⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 yellowfin.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
			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) {				char *temp = skb_put(skb = yp->rx_skbuff[entry], pkt_len);#ifndef final_verison				/* Remove after testing. */				if (le32desc_to_virt(yp->rx_ring[entry].addr) != temp)					printk(KERN_WARNING "%s: Warning -- the skbuff addresses "						   "do not match in yellowfin_rx: %p vs. %p / %p.\n",						   dev->name, le32desc_to_virt(yp->rx_ring[entry].addr),						   skb->head, temp);#endif				yp->rx_skbuff[entry] = NULL;			} else {				skb = dev_alloc_skb(pkt_len + 2);				if (skb == NULL)					break;				skb->dev = dev;				skb_reserve(skb, 2);	/* 16 byte align the data fields */#if 1 || USE_IP_CSUM				eth_copy_and_sum(skb, yp->rx_skbuff[entry]->tail, pkt_len, 0);				skb_put(skb, pkt_len);#else				memcpy(skb_put(skb, pkt_len), yp->rx_skbuff[entry]->tail,					   pkt_len);#endif			}			skb->protocol = eth_type_trans(skb, dev);			netif_rx(skb);			dev->last_rx = jiffies;			yp->stats.rx_packets++;			yp->stats.rx_bytes += pkt_len;		}		entry = (++yp->cur_rx) % RX_RING_SIZE;		yp->rx_head_desc = &yp->rx_ring[entry];	}	/* 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 = virt_to_le32desc(skb->tail);		}		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){	struct yellowfin_private *yp = (struct yellowfin_private *)dev->priv;	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))		yp->stats.tx_errors++;	if (intr_status & (IntrRxPCIErr | IntrRxPCIFault))		yp->stats.rx_errors++;}static int yellowfin_close(struct net_device *dev){	long ioaddr = dev->base_addr;	struct yellowfin_private *yp = (struct yellowfin_private *)dev->priv;	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, YF_INW(ioaddr + TxStatus),			   YF_INW(ioaddr + RxStatus),			   YF_INW(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. */	YF_OUTW(0x0000, ioaddr + IntrEnb);	/* Stop the chip's Tx and Rx processes. */	YF_OUTL(0x80000000, ioaddr + RxCtrl);	YF_OUTL(0x80000000, ioaddr + TxCtrl);	del_timer(&yp->timer);#if !defined(final_version) && defined(__i386__)	if (yellowfin_debug > 2) {		printk("\n"KERN_DEBUG"  Tx ring at %8.8x:\n", (int)virt_to_bus(yp->tx_ring));		for (i = 0; i < TX_RING_SIZE*2; i++)			printk(" %c #%d desc. %8.8x %8.8x %8.8x %8.8x.\n",				   YF_INL(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.8x:\n", (int)virt_to_bus(yp->rx_ring));		for (i = 0; i < RX_RING_SIZE; i++) {			printk(KERN_DEBUG " %c #%d desc. %8.8x %8.8x %8.8x\n",				   YF_INL(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 = 0xBADF00D0; /* An invalid address. */		if (yp->rx_skbuff[i]) {			dev_kfree_skb(yp->rx_skbuff[i]);		}		yp->rx_skbuff[i] = 0;	}	for (i = 0; i < TX_RING_SIZE; i++) {		if (yp->tx_skbuff[i])			dev_kfree_skb(yp->tx_skbuff[i]);		yp->tx_skbuff[i] = 0;	}#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;}static struct net_device_stats *yellowfin_get_stats(struct net_device *dev){	struct yellowfin_private *yp = (struct yellowfin_private *)dev->priv;	return &yp->stats;}/* Set or clear the multicast filter for this adaptor. *//* The little-endian AUTODIN32 ethernet CRC calculation.   N.B. Do not use for bulk data, use a table-based routine instead.   This is common code and should be moved to net/core/crc.c */static unsigned const ethernet_polynomial_le = 0xedb88320U;static inline unsigned ether_crc_le(int length, unsigned char *data){	unsigned int crc = 0xffffffff;	/* Initial value. */	while(--length >= 0) {		unsigned char current_octet = *data++;		int bit;		for (bit = 8; --bit >= 0; current_octet >>= 1) {			if ((crc ^ current_octet) & 1) {				crc >>= 1;				crc ^= ethernet_polynomial_le;			} else				crc >>= 1;		}	}	return crc;}static void set_rx_mode(struct net_device *dev){	struct yellowfin_private *yp = (struct yellowfin_private *)dev->priv;	long ioaddr = dev->base_addr;	u16 cfg_value = YF_INW(ioaddr + Cnfg);	/* Stop the Rx process to change any value. */	YF_OUTW(cfg_value & ~0x1000, ioaddr + Cnfg);	if (dev->flags & IFF_PROMISC) {			/* Set promiscuous. */		/* Unconditionally log net taps. */		printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n", dev->name);		YF_OUTW(0x000F, ioaddr + AddrMode);	} else if ((dev->mc_count > 64)  ||  (dev->flags & IFF_ALLMULTI)) {		/* Too many to filter well, or accept all multicasts. */		YF_OUTW(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) {			/* Due to a bug in the early chip versions, multiple filter			   slots must be set for each address. */			if (yp->flags & HasMulticastBug) {				set_bit((ether_crc_le(3, mclist->dmi_addr) >> 3) & 0x3f,						hash_table);				set_bit((ether_crc_le(4, mclist->dmi_addr) >> 3) & 0x3f,						hash_table);				set_bit((ether_crc_le(5, mclist->dmi_addr) >> 3) & 0x3f,						hash_table);			}			set_bit((ether_crc_le(6, mclist->dmi_addr) >> 3) & 0x3f,					hash_table);		}		/* Copy the hash table to the chip. */		for (i = 0; i < 4; i++)			YF_OUTW(hash_table[i], ioaddr + HashTbl + i*2);		YF_OUTW(0x0003, ioaddr + AddrMode);	} else {					/* Normal, unicast/broadcast-only mode. */		YF_OUTW(0x0001, ioaddr + AddrMode);	}	/* Restart the Rx process. */	YF_OUTW(cfg_value | 0x1000, ioaddr + Cnfg);}#ifdef HAVE_PRIVATE_IOCTLstatic int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd){	long ioaddr = dev->base_addr;	u16 *data = (u16 *)&rq->ifr_data;	switch(cmd) {	case SIOCDEVPRIVATE:		/* Get the address of the PHY in use. */		data[0] = ((struct yellowfin_private *)dev->priv)->phys[0] & 0x1f;		/* Fall Through */	case SIOCDEVPRIVATE+1:		/* Read the specified MII register. */		data[3] = mdio_read(ioaddr, data[0] & 0x1f, data[1] & 0x1f);		return 0;	case SIOCDEVPRIVATE+2:		/* Write the specified MII register */		if (!capable(CAP_NET_ADMIN))			return -EPERM;		mdio_write(ioaddr, data[0] & 0x1f, data[1] & 0x1f, data[2]);		return 0;	default:		return -EOPNOTSUPP;	}}#endif  /* HAVE_PRIVATE_IOCTL */static int __devinit yellowfin_init_one(struct pci_dev *pdev,					const struct pci_device_id *ent){	struct net_device *dev;	struct yellowfin_private *yp;	int option, i, irq;	int flags, chip_idx;	static int find_cnt = 0;	long ioaddr, real_ioaddr;		chip_idx = ent->driver_data;	flags = chip_info[chip_idx].flags;	dev = init_etherdev(NULL, sizeof(*yp));	if (!dev) {		printk (KERN_ERR PFX "cannot allocate ethernet device\n");		return -ENOMEM;	}	SET_MODULE_OWNER(dev);	yp = dev->priv;	if (!request_region (pci_resource_start (pdev, 0),			     YELLOWFIN_SIZE, YELLOWFIN_MODULE_NAME)) {		printk (KERN_ERR PFX "cannot obtain I/O port region\n");		goto err_out_free_netdev;	}	if (!request_mem_region (pci_resource_start (pdev, 1),			         YELLOWFIN_SIZE, YELLOWFIN_MODULE_NAME)) {		printk (KERN_ERR PFX "cannot obtain MMIO region\n");		goto err_out_free_pio_region;	}		if (pci_enable_device (pdev))		goto err_out_free_mmio_region;	pci_set_master (pdev);#ifdef USE_IO_OPS	real_ioaddr = ioaddr = pci_resource_start (pdev, 0);#else	real_ioaddr = ioaddr = pci_resource_start (pdev, 1);	ioaddr = (long) ioremap(ioaddr, YELLOWFIN_SIZE);	if (!ioaddr)		goto err_out_free_mmio_region;#endif	irq = pdev->irq;	printk(KERN_INFO "%s: %s type %8x at 0x%lx, ",	       dev->name, chip_info[chip_idx].name,	       YF_INL(ioaddr + ChipRev), real_ioaddr);	if (flags & IsGigabit)		for (i = 0; i < 6; i++)			dev->dev_addr[i] = YF_INB(ioaddr + StnAddr + i);	else {		int ee_offset = (read_eeprom(ioaddr, 6) == 0xff ? 0x100 : 0);		for (i = 0; i < 6; i++)			dev->dev_addr[i] = read_eeprom(ioaddr, ee_offset + i);	}	for (i = 0; i < 5; i++)			printk("%2.2x:", dev->dev_addr[i]);	printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq);	/* Reset the chip. */	YF_OUTL(0x80000000, ioaddr + DMACtrl);	dev->base_addr = ioaddr;	dev->irq = irq;	pdev->driver_data = dev;	yp->chip_id = chip_idx;	yp->flags = flags;	yp->lock = SPIN_LOCK_UNLOCKED;	option = find_cnt < MAX_UNITS ? options[find_cnt] : 0;	if (dev->mem_start)		option = dev->mem_start;	/* The lower four bits are the media type. */	if (option > 0) {		if (option & 0x200)			yp->full_duplex = 1;		yp->default_port = option & 15;		if (yp->default_port)			yp->medialock = 1;	}	if (find_cnt < MAX_UNITS  &&  full_duplex[find_cnt] > 0)		yp->full_duplex = 1;	if (yp->full_duplex)		yp->duplex_lock = 1;	/* The Yellowfin-specific entries in the device structure. */	dev->open = &yellowfin_open;	dev->hard_start_xmit = &yellowfin_start_xmit;	dev->stop = &yellowfin_close;	dev->get_stats = &yellowfin_get_stats;	dev->set_multicast_list = &set_rx_mode;#ifdef HAVE_PRIVATE_IOCTL	dev->do_ioctl = &mii_ioctl;#endif	dev->tx_timeout = yellowfin_tx_timeout;	dev->watchdog_timeo = TX_TIMEOUT;	if (mtu)		dev->mtu = mtu;	if (yp->flags & HasMII) {		int phy, phy_idx = 0;		for (phy = 0; phy < 32 && phy_idx < 4; phy++) {			int mii_status = mdio_read(ioaddr, phy, 1);			if (mii_status != 0xffff  &&				mii_status != 0x0000) {				yp->phys[phy_idx++] = phy;				yp->advertising = mdio_read(ioaddr, phy, 4);				printk(KERN_INFO "%s: MII PHY found at address %d, status "					   "0x%4.4x advertising %4.4x.\n",					   dev->name, phy, mii_status, yp->advertising);			}		}		yp->mii_cnt = phy_idx;	}	find_cnt++;		return 0;err_out_free_mmio_region:	release_mem_region (pci_resource_start (pdev, 1), YELLOWFIN_SIZE);err_out_free_pio_region:	release_region (pci_resource_start (pdev, 0), YELLOWFIN_SIZE);err_out_free_netdev:	unregister_netdev (dev);	kfree (dev);	return -ENODEV;}static void __devexit yellowfin_remove_one (struct pci_dev *pdev){	struct net_device *dev = pdev->driver_data;	struct yellowfin_private *np;	if (!dev)		BUG();	np = dev->priv;	unregister_netdev (dev);	release_region (dev->base_addr, YELLOWFIN_SIZE);	release_mem_region (dev->base_addr, YELLOWFIN_SIZE);#ifndef USE_IO_OPS	iounmap ((void *) dev->base_addr);#endif	kfree (dev);}static struct pci_driver yellowfin_driver = {	name:		YELLOWFIN_MODULE_NAME,	id_table:	yellowfin_pci_tbl,	probe:		yellowfin_init_one,	remove:		yellowfin_remove_one,};static int __init yellowfin_init (void){	if (debug)					/* Emit version even if no cards detected. */		printk(KERN_INFO "%s", version);	return pci_module_init (&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 -D__KERNEL__  -Wall -Wstrict-prototypes -O6 -c yellowfin.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`" *  compile-command-alphaLX: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O2 -c yellowfin.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`  -fomit-frame-pointer -fno-strength-reduce -mno-fp-regs -Wa,-m21164a -DBWX_USABLE -DBWIO_ENABLED" *  c-indent-level: 4 *  c-basic-offset: 4 *  tab-width: 4 * End: */

⌨️ 快捷键说明

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