yellowfin.c

来自「linux 内核源代码」· C语言 代码 · 共 1,437 行 · 第 1/4 页

C
1,437
字号
			dev->stats.rx_errors++;			if (frame_status & 0x0060) dev->stats.rx_length_errors++;			if (frame_status & 0x0008) dev->stats.rx_frame_errors++;			if (frame_status & 0x0010) dev->stats.rx_crc_errors++;			if (frame_status < 0) dev->stats.rx_dropped++;		} else if ( !(yp->drv_flags & IsGigabit)  &&				   ((buf_addr[data_size-1] & 0x85) || buf_addr[data_size-2] & 0xC0)) {			u8 status1 = buf_addr[data_size-2];			u8 status2 = buf_addr[data_size-1];			dev->stats.rx_errors++;			if (status1 & 0xC0) dev->stats.rx_length_errors++;			if (status2 & 0x03) dev->stats.rx_frame_errors++;			if (status2 & 0x04) dev->stats.rx_crc_errors++;			if (status2 & 0x80) dev->stats.rx_dropped++;#ifdef YF_PROTOTYPE		/* Support for prototype hardware errata. */		} else if ((yp->flags & HasMACAddrBug)  &&			memcmp(le32_to_cpu(yp->rx_ring_dma +				entry*sizeof(struct yellowfin_desc)),				dev->dev_addr, 6) != 0 &&			memcmp(le32_to_cpu(yp->rx_ring_dma +				entry*sizeof(struct yellowfin_desc)),				"\377\377\377\377\377\377", 6) != 0) {			if (bogus_rx++ == 0) {				DECLARE_MAC_BUF(mac);				printk(KERN_WARNING "%s: Bad frame to %s\n",					   dev->name, print_mac(mac, buf_addr));			}#endif		} else {			struct sk_buff *skb;			int pkt_len = data_size -				(yp->chip_id ? 7 : 8 + buf_addr[data_size - 8]);			/* To verify: Yellowfin Length should omit the CRC! */#ifndef final_version			if (yellowfin_debug > 4)				printk(KERN_DEBUG "  yellowfin_rx() normal Rx pkt length %d"					   " of %d, bogus_cnt %d.\n",					   pkt_len, data_size, boguscnt);#endif			/* Check if the packet is long enough to just pass up the skbuff			   without copying to a properly sized skbuff. */			if (pkt_len > rx_copybreak) {				skb_put(skb = rx_skb, pkt_len);				pci_unmap_single(yp->pci_dev,					le32_to_cpu(yp->rx_ring[entry].addr),					yp->rx_buf_sz,					PCI_DMA_FROMDEVICE);				yp->rx_skbuff[entry] = NULL;			} else {				skb = dev_alloc_skb(pkt_len + 2);				if (skb == NULL)					break;				skb_reserve(skb, 2);	/* 16 byte align the IP header */				skb_copy_to_linear_data(skb, rx_skb->data, pkt_len);				skb_put(skb, pkt_len);				pci_dma_sync_single_for_device(yp->pci_dev,								le32_to_cpu(desc->addr),								yp->rx_buf_sz,								PCI_DMA_FROMDEVICE);			}			skb->protocol = eth_type_trans(skb, dev);			netif_rx(skb);			dev->last_rx = jiffies;			dev->stats.rx_packets++;			dev->stats.rx_bytes += pkt_len;		}		entry = (++yp->cur_rx) % RX_RING_SIZE;	}	/* Refill the Rx ring buffers. */	for (; yp->cur_rx - yp->dirty_rx > 0; yp->dirty_rx++) {		entry = yp->dirty_rx % RX_RING_SIZE;		if (yp->rx_skbuff[entry] == NULL) {			struct sk_buff *skb = dev_alloc_skb(yp->rx_buf_sz);			if (skb == NULL)				break;				/* Better luck next round. */			yp->rx_skbuff[entry] = skb;			skb->dev = dev;	/* Mark as being used by this device. */			skb_reserve(skb, 2);	/* Align IP on 16 byte boundaries */			yp->rx_ring[entry].addr = cpu_to_le32(pci_map_single(yp->pci_dev,				skb->data, yp->rx_buf_sz, PCI_DMA_FROMDEVICE));		}		yp->rx_ring[entry].dbdma_cmd = cpu_to_le32(CMD_STOP);		yp->rx_ring[entry].result_status = 0;	/* Clear complete bit. */		if (entry != 0)			yp->rx_ring[entry - 1].dbdma_cmd =				cpu_to_le32(CMD_RX_BUF | INTR_ALWAYS | yp->rx_buf_sz);		else			yp->rx_ring[RX_RING_SIZE - 1].dbdma_cmd =				cpu_to_le32(CMD_RX_BUF | INTR_ALWAYS | BRANCH_ALWAYS							| yp->rx_buf_sz);	}	return 0;}static void yellowfin_error(struct net_device *dev, int intr_status){	printk(KERN_ERR "%s: Something Wicked happened! %4.4x.\n",		   dev->name, intr_status);	/* Hmmmmm, it's not clear what to do here. */	if (intr_status & (IntrTxPCIErr | IntrTxPCIFault))		dev->stats.tx_errors++;	if (intr_status & (IntrRxPCIErr | IntrRxPCIFault))		dev->stats.rx_errors++;}static int yellowfin_close(struct net_device *dev){	struct yellowfin_private *yp = netdev_priv(dev);	void __iomem *ioaddr = yp->base;	int i;	netif_stop_queue (dev);	if (yellowfin_debug > 1) {		printk(KERN_DEBUG "%s: Shutting down ethercard, status was Tx %4.4x "			   "Rx %4.4x Int %2.2x.\n",			   dev->name, ioread16(ioaddr + TxStatus),			   ioread16(ioaddr + RxStatus),			   ioread16(ioaddr + IntrStatus));		printk(KERN_DEBUG "%s: Queue pointers were Tx %d / %d,  Rx %d / %d.\n",			   dev->name, yp->cur_tx, yp->dirty_tx, yp->cur_rx, yp->dirty_rx);	}	/* Disable interrupts by clearing the interrupt mask. */	iowrite16(0x0000, ioaddr + IntrEnb);	/* Stop the chip's Tx and Rx processes. */	iowrite32(0x80000000, ioaddr + RxCtrl);	iowrite32(0x80000000, ioaddr + TxCtrl);	del_timer(&yp->timer);#if defined(__i386__)	if (yellowfin_debug > 2) {		printk("\n"KERN_DEBUG"  Tx ring at %8.8llx:\n",				(unsigned long long)yp->tx_ring_dma);		for (i = 0; i < TX_RING_SIZE*2; i++)			printk(" %c #%d desc. %8.8x %8.8x %8.8x %8.8x.\n",				   ioread32(ioaddr + TxPtr) == (long)&yp->tx_ring[i] ? '>' : ' ',				   i, yp->tx_ring[i].dbdma_cmd, yp->tx_ring[i].addr,				   yp->tx_ring[i].branch_addr, yp->tx_ring[i].result_status);		printk(KERN_DEBUG "  Tx status %p:\n", yp->tx_status);		for (i = 0; i < TX_RING_SIZE; i++)			printk("   #%d status %4.4x %4.4x %4.4x %4.4x.\n",				   i, yp->tx_status[i].tx_cnt, yp->tx_status[i].tx_errs,				   yp->tx_status[i].total_tx_cnt, yp->tx_status[i].paused);		printk("\n"KERN_DEBUG "  Rx ring %8.8llx:\n",				(unsigned long long)yp->rx_ring_dma);		for (i = 0; i < RX_RING_SIZE; i++) {			printk(KERN_DEBUG " %c #%d desc. %8.8x %8.8x %8.8x\n",				   ioread32(ioaddr + RxPtr) == (long)&yp->rx_ring[i] ? '>' : ' ',				   i, yp->rx_ring[i].dbdma_cmd, yp->rx_ring[i].addr,				   yp->rx_ring[i].result_status);			if (yellowfin_debug > 6) {				if (get_unaligned((u8*)yp->rx_ring[i].addr) != 0x69) {					int j;					for (j = 0; j < 0x50; j++)						printk(" %4.4x",							   get_unaligned(((u16*)yp->rx_ring[i].addr) + j));					printk("\n");				}			}		}	}#endif /* __i386__ debugging only */	free_irq(dev->irq, dev);	/* Free all the skbuffs in the Rx queue. */	for (i = 0; i < RX_RING_SIZE; i++) {		yp->rx_ring[i].dbdma_cmd = cpu_to_le32(CMD_STOP);		yp->rx_ring[i].addr = cpu_to_le32(0xBADF00D0); /* An invalid address. */		if (yp->rx_skbuff[i]) {			dev_kfree_skb(yp->rx_skbuff[i]);		}		yp->rx_skbuff[i] = NULL;	}	for (i = 0; i < TX_RING_SIZE; i++) {		if (yp->tx_skbuff[i])			dev_kfree_skb(yp->tx_skbuff[i]);		yp->tx_skbuff[i] = NULL;	}#ifdef YF_PROTOTYPE			/* Support for prototype hardware errata. */	if (yellowfin_debug > 0) {		printk(KERN_DEBUG "%s: Received %d frames that we should not have.\n",			   dev->name, bogus_rx);	}#endif	return 0;}/* Set or clear the multicast filter for this adaptor. */static void set_rx_mode(struct net_device *dev){	struct yellowfin_private *yp = netdev_priv(dev);	void __iomem *ioaddr = yp->base;	u16 cfg_value = ioread16(ioaddr + Cnfg);	/* Stop the Rx process to change any value. */	iowrite16(cfg_value & ~0x1000, ioaddr + Cnfg);	if (dev->flags & IFF_PROMISC) {			/* Set promiscuous. */		iowrite16(0x000F, ioaddr + AddrMode);	} else if ((dev->mc_count > 64)  ||  (dev->flags & IFF_ALLMULTI)) {		/* Too many to filter well, or accept all multicasts. */		iowrite16(0x000B, ioaddr + AddrMode);	} else if (dev->mc_count > 0) { /* Must use the multicast hash table. */		struct dev_mc_list *mclist;		u16 hash_table[4];		int i;		memset(hash_table, 0, sizeof(hash_table));		for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;			 i++, mclist = mclist->next) {			unsigned int bit;			/* Due to a bug in the early chip versions, multiple filter			   slots must be set for each address. */			if (yp->drv_flags & HasMulticastBug) {				bit = (ether_crc_le(3, mclist->dmi_addr) >> 3) & 0x3f;				hash_table[bit >> 4] |= (1 << bit);				bit = (ether_crc_le(4, mclist->dmi_addr) >> 3) & 0x3f;				hash_table[bit >> 4] |= (1 << bit);				bit = (ether_crc_le(5, mclist->dmi_addr) >> 3) & 0x3f;				hash_table[bit >> 4] |= (1 << bit);			}			bit = (ether_crc_le(6, mclist->dmi_addr) >> 3) & 0x3f;			hash_table[bit >> 4] |= (1 << bit);		}		/* Copy the hash table to the chip. */		for (i = 0; i < 4; i++)			iowrite16(hash_table[i], ioaddr + HashTbl + i*2);		iowrite16(0x0003, ioaddr + AddrMode);	} else {					/* Normal, unicast/broadcast-only mode. */		iowrite16(0x0001, ioaddr + AddrMode);	}	/* Restart the Rx process. */	iowrite16(cfg_value | 0x1000, ioaddr + Cnfg);}static void yellowfin_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info){	struct yellowfin_private *np = netdev_priv(dev);	strcpy(info->driver, DRV_NAME);	strcpy(info->version, DRV_VERSION);	strcpy(info->bus_info, pci_name(np->pci_dev));}static const struct ethtool_ops ethtool_ops = {	.get_drvinfo = yellowfin_get_drvinfo};static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd){	struct yellowfin_private *np = netdev_priv(dev);	void __iomem *ioaddr = np->base;	struct mii_ioctl_data *data = if_mii(rq);	switch(cmd) {	case SIOCGMIIPHY:		/* Get address of MII PHY in use. */		data->phy_id = np->phys[0] & 0x1f;		/* Fall Through */	case SIOCGMIIREG:		/* Read MII PHY register. */		data->val_out = mdio_read(ioaddr, data->phy_id & 0x1f, data->reg_num & 0x1f);		return 0;	case SIOCSMIIREG:		/* Write MII PHY register. */		if (!capable(CAP_NET_ADMIN))			return -EPERM;		if (data->phy_id == np->phys[0]) {			u16 value = data->val_in;			switch (data->reg_num) {			case 0:				/* Check for autonegotiation on or reset. */				np->medialock = (value & 0x9000) ? 0 : 1;				if (np->medialock)					np->full_duplex = (value & 0x0100) ? 1 : 0;				break;			case 4: np->advertising = value; break;			}			/* Perhaps check_duplex(dev), depending on chip semantics. */		}		mdio_write(ioaddr, data->phy_id & 0x1f, data->reg_num & 0x1f, data->val_in);		return 0;	default:		return -EOPNOTSUPP;	}}static void __devexit yellowfin_remove_one (struct pci_dev *pdev){	struct net_device *dev = pci_get_drvdata(pdev);	struct yellowfin_private *np;	BUG_ON(!dev);	np = netdev_priv(dev);        pci_free_consistent(pdev, STATUS_TOTAL_SIZE, np->tx_status,		np->tx_status_dma);	pci_free_consistent(pdev, RX_TOTAL_SIZE, np->rx_ring, np->rx_ring_dma);	pci_free_consistent(pdev, TX_TOTAL_SIZE, np->tx_ring, np->tx_ring_dma);	unregister_netdev (dev);	pci_iounmap(pdev, np->base);	pci_release_regions (pdev);	free_netdev (dev);	pci_set_drvdata(pdev, NULL);}static struct pci_driver yellowfin_driver = {	.name		= DRV_NAME,	.id_table	= yellowfin_pci_tbl,	.probe		= yellowfin_init_one,	.remove		= __devexit_p(yellowfin_remove_one),};static int __init yellowfin_init (void){/* when a module, this is printed whether or not devices are found in probe */#ifdef MODULE	printk(version);#endif	return pci_register_driver(&yellowfin_driver);}static void __exit yellowfin_cleanup (void){	pci_unregister_driver (&yellowfin_driver);}module_init(yellowfin_init);module_exit(yellowfin_cleanup);/* * Local variables: *  compile-command: "gcc -DMODULE -Wall -Wstrict-prototypes -O6 -c yellowfin.c" *  compile-command-alphaLX: "gcc -DMODULE -Wall -Wstrict-prototypes -O2 -c yellowfin.c -fomit-frame-pointer -fno-strength-reduce -mno-fp-regs -Wa,-m21164a -DBWX_USABLE -DBWIO_ENABLED" *  simple-compile-command: "gcc -DMODULE -O6 -c yellowfin.c" *  c-indent-level: 4 *  c-basic-offset: 4 *  tab-width: 4 * End: */

⌨️ 快捷键说明

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