r6040.c

来自「Linux Home Server 是专门为家庭和SOHO/SMB 设计的高性价」· C语言 代码 · 共 1,405 行 · 第 1/3 页

C
1,405
字号
	if (lp->rx_ring) {		for(i=0, ptr=lp->rx_ring; i < RX_DCNT; i++, ptr++) {			printk(KERN_INFO "%s: %d. descr: status x%x len x%x "			       "ndesc %08x vbufp %p vndescp %p skb_ptr %p\n", 			       DRV_NAME, i, ptr->status, ptr->len,			       ptr->ndesc, ptr->vbufp, ptr->vndescp, ptr->skb_ptr);		}	}}#endif /* #if (DEBUG & DBG_TX_RING_DUMP) */int r6040_alloc_rxbufs(struct net_device *dev){	struct r6040_private *lp = netdev_priv(dev);	struct r6040_descriptor *desc;	struct sk_buff *skb;	int rc;	lp->rx_remove_ptr = lp->rx_insert_ptr = lp->rx_ring;	r6040_init_ring_desc(lp->rx_ring, lp->rx_ring_dma, RX_DCNT);	/* alloc skbs for the rx descriptors */	desc = lp->rx_ring;	do {		if (!(skb=netdev_alloc_skb(dev, MAX_BUF_SIZE))) {			err("failed to alloc skb for rx\n");			rc = -ENOMEM;			goto err_exit;		}		desc->skb_ptr = skb;		desc->buf = cpu_to_le32(pci_map_single(lp->pdev,						       desc->skb_ptr->data,						       MAX_BUF_SIZE, PCI_DMA_FROMDEVICE));		desc->status = DESC_STATUS_OWNER_MAC;		desc = desc->vndescp;	} while (desc != lp->rx_ring);#if (DEBUG & DBG_RX_RING_DUMP)	if (debug & DBG_RX_RING_DUMP) {		dump_rx_ring(lp);	}#endif	return 0;err_exit:	/* dealloc all previously allocated skb */	r6040_free_rxbufs(dev);	return rc;}/*! reset MAC and set all registers */void r6040_init_mac_regs(struct r6040_private *lp){	void __iomem *ioaddr = lp->base;	int limit;	char obuf[3*ETH_ALEN] __attribute__ ((unused));	/* Mask Off Interrupt */	iowrite16(MSK_INT, ioaddr + MIER);	/* reset MAC */	iowrite16(MAC_RST, ioaddr + MCR1);	udelay(100);	limit=2048;	while ((ioread16(ioaddr + MCR1) & MAC_RST) && limit-- > 0);	/* Reset internal state machine */	iowrite16(2, ioaddr + MAC_SM);	iowrite16(0, ioaddr + MAC_SM);	udelay(5000);	/* Restore MAC Addresses */	r6040_multicast_list(lp->dev);	/* TODO: restore multcast and hash table */	/* MAC Bus Control Register */	iowrite16(MBCR_DEFAULT, ioaddr + MBCR);	/* Buffer Size Register */	iowrite16(MAX_BUF_SIZE, ioaddr + MR_BSR);	/* write tx ring start address */	iowrite16(lp->tx_ring_dma, ioaddr + MTD_SA0);	iowrite16(lp->tx_ring_dma >> 16, ioaddr + MTD_SA1);	/* write rx ring start address */	iowrite16(lp->rx_ring_dma, ioaddr + MRD_SA0);	iowrite16(lp->rx_ring_dma >> 16, ioaddr + MRD_SA1);	/* set interrupt waiting time and packet numbers */	iowrite16(0, ioaddr + MT_ICR);	iowrite16(0, ioaddr + MR_ICR);	/* enable interrupts */	iowrite16(INT_MASK, ioaddr + MIER);	/* enable tx and rx */	iowrite16(lp->mcr0 | 0x0002, ioaddr);	/* let TX poll the descriptors - we may got called by r6040_tx_timeout which has left	   some unsent tx buffers */	iowrite16(0x01, ioaddr + MTPR);}void r6040_tx_timeout(struct net_device *dev){	struct r6040_private *priv = netdev_priv(dev);	void __iomem *ioaddr = priv->base;	/* we read MISR, which clears on read (i.e. we may loose an RX interupt,	   but this is an error anyhow ... */	printk(KERN_WARNING "%s: transmit timed out, int enable %4.4x "	       "status %4.4x, PHY status %4.4x\n",	       dev->name, ioread16(ioaddr + MIER),	       ioread16(ioaddr + MISR),	       mdio_read(dev, priv->mii_if.phy_id, MII_BMSR));	dev->stats.tx_errors++;	/* Reset MAC and re-init all registers */	r6040_init_mac_regs(priv);}struct net_device_stats *r6040_get_stats(struct net_device *dev){	struct r6040_private *priv = netdev_priv(dev);	void __iomem *ioaddr = priv->base;	unsigned long flags;	spin_lock_irqsave(&priv->lock, flags);	dev->stats.rx_crc_errors += ioread8(ioaddr + ME_CNT1);	dev->stats.multicast += ioread8(ioaddr + ME_CNT0);	spin_unlock_irqrestore(&priv->lock, flags);	return &dev->stats;}/* Stop RDC MAC and Free the allocated resource */void r6040_down(struct net_device *dev){	struct r6040_private *lp = netdev_priv(dev);	void __iomem *ioaddr = lp->base;	struct pci_dev *pdev = lp->pdev;	int limit = 2048;	dbg(DBG_EXIT, "ENTER\n");	/* Stop MAC */	iowrite16(MSK_INT, ioaddr + MIER);	/* Mask Off Interrupt */	iowrite16(MAC_RST, ioaddr + MCR1);	/* Reset RDC MAC */	udelay(100);	while ((ioread16(ioaddr+MCR1) & 1) && limit-- > 0);	if (limit <= 0)		err("timeout while waiting for reset done.\n");	free_irq(dev->irq, dev);	/* Free RX buffer */	r6040_free_rxbufs(dev);	/* Free TX buffer */	r6040_free_txbufs(dev);	/* Free Descriptor memory */	pci_free_consistent(pdev, RX_DESC_SIZE, lp->rx_ring, lp->rx_ring_dma);	pci_free_consistent(pdev, TX_DESC_SIZE, lp->tx_ring, lp->tx_ring_dma);	dbg(DBG_EXIT, "EXIT\n");}int r6040_close(struct net_device *dev){	struct r6040_private *lp = netdev_priv(dev);	dbg(DBG_EXIT, "ENTER\n");	/* deleted timer */	del_timer_sync(&lp->timer);	spin_lock_irq(&lp->lock);	napi_disable(&lp->napi);	netif_stop_queue(dev);	r6040_down(dev);	spin_unlock_irq(&lp->lock);	dbg(DBG_EXIT, "EXIT\n");	return 0;}/* Status of PHY CHIP. Returns 0x8000 for full duplex, 0 for half duplex */STATIC int phy_mode_chk(struct net_device *dev){	struct r6040_private *lp = netdev_priv(dev);	void __iomem *ioaddr = lp->base;	int phy_dat;	/* PHY Link Status Check */	phy_dat = phy_read(ioaddr, lp->phy_addr, 1);	if (!(phy_dat & 0x4))		phy_dat = 0x8000;	/* Link Failed, full duplex */	/* PHY Chip Auto-Negotiation Status */	phy_dat = phy_read(ioaddr, lp->phy_addr, 1);	if (phy_dat & 0x0020) {		/* Auto Negotiation Mode */		phy_dat = phy_read(ioaddr, lp->phy_addr, 5);		phy_dat &= phy_read(ioaddr, lp->phy_addr, 4);		if (phy_dat & 0x140)			/* Force full duplex */			phy_dat = 0x8000;		else			phy_dat = 0;	} else {		/* Force Mode */		phy_dat = phy_read(ioaddr, lp->phy_addr, 0);		if (phy_dat & 0x100)			phy_dat = 0x8000;		else			phy_dat = 0x0000;	}	dbg(DBG_PHY, "RETURN x%x\n", phy_dat);	return phy_dat;};void r6040_set_carrier(struct mii_if_info *mii){	if (phy_mode_chk(mii->dev)) {		/* autoneg is off: Link is always assumed to be up */		if (!netif_carrier_ok(mii->dev))			netif_carrier_on(mii->dev);	} else		phy_mode_chk(mii->dev);}int r6040_ioctl(struct net_device *dev, struct ifreq *rq, int cmd){	struct r6040_private *lp = netdev_priv(dev);	struct mii_ioctl_data *data = if_mii(rq);	int rc;	if (!netif_running(dev))		return -EINVAL;	spin_lock_irq(&lp->lock);	rc = generic_mii_ioctl(&lp->mii_if, data, cmd, NULL);	spin_unlock_irq(&lp->lock);	r6040_set_carrier(&lp->mii_if);	return rc;}int r6040_rx(struct net_device *dev, int limit){	struct r6040_private *priv = netdev_priv(dev);	int count=0;	struct r6040_descriptor *descptr = priv->rx_remove_ptr;	struct sk_buff *skb_ptr, *new_skb;	char obuf[2*32+1] __attribute__ ((unused)); /* for debugging */	while (count < limit && !(descptr->status & DESC_STATUS_OWNER_MAC)) {		/* limit not reached and the descriptor belongs to the CPU */		dbg(DBG_RX_DESCR, "descptr %p status x%x data len x%x\n",		    descptr, descptr->status, descptr->len);				/* Check for errors */		if (descptr->status & DESC_STATUS_RX_ERR) {					dev->stats.rx_errors++;						if (descptr->status & (DESC_STATUS_RX_ERR_DRIBBLE|					       DESC_STATUS_RX_ERR_BUFLEN|					       DESC_STATUS_RX_ERR_LONG|					       DESC_STATUS_RX_ERR_RUNT)) {				/* packet too long or too short*/				dev->stats.rx_length_errors++;			}			if (descptr->status & DESC_STATUS_RX_ERR_CRC) {				dev->stats.rx_crc_errors++;			}			goto next_descr;		}				/* successful received packet */				/* first try to allocate new skb. If this fails		   we drop the packet and leave the old skb there.*/		new_skb = netdev_alloc_skb(dev, MAX_BUF_SIZE);		if (!new_skb) {			dev->stats.rx_dropped++;			goto next_descr;		}		skb_ptr = descptr->skb_ptr;		skb_ptr->dev = priv->dev;		/* Do not count the CRC */		skb_put(skb_ptr, descptr->len - 4);		pci_unmap_single(priv->pdev, le32_to_cpu(descptr->buf),				 MAX_BUF_SIZE, PCI_DMA_FROMDEVICE);		skb_ptr->protocol = eth_type_trans(skb_ptr, priv->dev);		dbg(DBG_RX_DATA, "rx len x%x: %s...\n",		    descptr->len, 		    hex2str(skb_ptr->data, obuf, sizeof(obuf)/2, '\0'));		/* Send to upper layer */		netif_receive_skb(skb_ptr);		dev->last_rx = jiffies;		dev->stats.rx_packets++;		dev->stats.rx_bytes += (descptr->len-4);		/* put new skb into descriptor */		descptr->skb_ptr = new_skb;		descptr->buf = cpu_to_le32(pci_map_single(priv->pdev,			descptr->skb_ptr->data,			MAX_BUF_SIZE, PCI_DMA_FROMDEVICE));next_descr:				/* put the descriptor back to the MAC */		descptr->status = DESC_STATUS_OWNER_MAC;		descptr = descptr->vndescp;		count++; /* shall we count errors and dropped packets as well? */	} /* while (limit && !(descptr->status & DESC_STATUS_OWNER_MAC)) */	/* remember next descriptor to check for rx */	priv->rx_remove_ptr = descptr;	return count;}void r6040_tx(struct net_device *dev){	struct r6040_private *priv = netdev_priv(dev);	struct r6040_descriptor *descptr;	void __iomem *ioaddr = priv->base;	struct sk_buff *skb_ptr;	u16 err;	spin_lock(&priv->lock);	descptr = priv->tx_remove_ptr;	while (priv->tx_free_desc < TX_DCNT) {		/* Check for errors */		err = ioread16(ioaddr + MLSR);		if (err & 0x0200)			dev->stats.rx_fifo_errors++;		if (err & (0x2000 | 0x4000))			dev->stats.tx_carrier_errors++;		dbg(DBG_TX_DONE, "descptr %p status x%x err x%x jiffies %lu\n",		    descptr, descptr->status, err, jiffies);		if (descptr->status & 0x8000)			break; /* Not complete */		skb_ptr = descptr->skb_ptr;		pci_unmap_single(priv->pdev, le32_to_cpu(descptr->buf),			skb_ptr->len, PCI_DMA_TODEVICE);		/* Free buffer */		dev_kfree_skb_irq(skb_ptr);		descptr->skb_ptr = NULL;		/* To next descriptor */		descptr = descptr->vndescp;		priv->tx_free_desc++;	}	priv->tx_remove_ptr = descptr;	if (priv->tx_free_desc)		netif_wake_queue(dev);	spin_unlock(&priv->lock);}int r6040_poll(struct napi_struct *napi, int budget){	struct r6040_private *priv =		container_of(napi, struct r6040_private, napi);	struct net_device *dev = priv->dev;	void __iomem *ioaddr = priv->base;	int work_done;	work_done = r6040_rx(dev, budget);	dbg(DBG_POLL, "budget x%x done x%x\n", budget, work_done);	if (work_done < budget) {		netif_rx_complete(dev, napi);		/* Enable RX interrupt */		iowrite16(ioread16(ioaddr + MIER) | RX_INTS, ioaddr + MIER);	}	return work_done;}/* The RDC interrupt handler. */irqreturn_t r6040_interrupt(int irq, void *dev_id){	struct net_device *dev = dev_id;	struct r6040_private *lp = netdev_priv(dev);	void __iomem *ioaddr = lp->base;	u16 status;	/* Read MISR status and clear */	status = ioread16(ioaddr + MISR);	dbg(DBG_IRQ, "status x%x jiffies %lu\n", status, jiffies);	if (status == 0x0000 || status == 0xffff)		return IRQ_NONE;	/* rx early / rx finish interrupt	   or rx descriptor unavail. */	if (status & RX_INTS) {		if (status & RX_NO_DESC) {			/* rx descriptor unavail. */			dev->stats.rx_dropped++;			dev->stats.rx_missed_errors++;		}		/* Mask off RX interrupts */		iowrite16(ioread16(ioaddr + MIER) & ~RX_INTS, ioaddr + MIER);		netif_rx_schedule(dev, &lp->napi);	}	/* rx FIFO full */	if (status & RX_FIFO_FULL) {		dev->stats.rx_fifo_errors++;	}		/* TX interrupt request */	if (status & 0x10)		r6040_tx(dev);	return IRQ_HANDLED;}#ifdef CONFIG_NET_POLL_CONTROLLERvoid r6040_poll_controller(struct net_device *dev){	disable_irq(dev->irq);	r6040_interrupt(dev->irq, dev);	enable_irq(dev->irq);}#endif/* Init RDC MAC */int r6040_up(struct net_device *dev){	struct r6040_private *lp = netdev_priv(dev);	void __iomem *ioaddr = lp->base;	int rc;	dbg(DBG_INIT, "ENTER\n");	/* Initialise and alloc RX/TX buffers */	r6040_init_txbufs(dev);	if ((rc=r6040_alloc_rxbufs(dev)))		return rc;	/* Read the PHY ID */	lp->switch_sig = phy_read(ioaddr, 0, 2);	if (lp->switch_sig  == ICPLUS_PHY_ID) {		phy_write(ioaddr, 29, 31, 0x175C); /* Enable registers */		lp->phy_mode = 0x8000;	} else {		/* PHY Mode Check */		phy_write(ioaddr, lp->phy_addr, 4, PHY_CAP);		phy_write(ioaddr, lp->phy_addr, 0, PHY_MODE);		if (PHY_MODE == 0x3100)			lp->phy_mode = phy_mode_chk(dev);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?