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

📄 starfire.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
			np->tx_full = 0;			netif_wake_queue(dev);		}		/* Abnormal error summary/uncommon events handlers. */		if (intr_status & IntrAbnormalSummary)			netdev_error(dev, intr_status);		if (--boguscnt < 0) {			printk(KERN_WARNING "%s: Too much work at interrupt, "				   "status=0x%4.4x.\n",				   dev->name, intr_status);			break;		}	} while (1);	if (debug > 4)		printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n",			   dev->name, (int)readl(ioaddr + IntrStatus));#ifndef final_version	/* Code that should never be run!  Remove after testing.. */	{		static int stopit = 10;		if (!netif_running(dev)  &&  --stopit < 0) {			printk(KERN_ERR "%s: Emergency stop, looping startup interrupt.\n",				   dev->name);			free_irq(irq, dev);		}	}#endif}/* This routine is logically part of the interrupt handler, but separated   for clarity and better register allocation. */static int netdev_rx(struct net_device *dev){	struct netdev_private *np = (struct netdev_private *)dev->priv;	int boguscnt = np->dirty_rx + RX_RING_SIZE - np->cur_rx;	u32 desc_status;	if (np->rx_done_q == 0) {		printk(KERN_ERR "%s:  rx_done_q is NULL!  rx_done is %d. %p.\n",			   dev->name, np->rx_done, np->tx_done_q);		return 0;	}	/* If EOP is set on the next entry, it's a new packet. Send it up. */	while ((desc_status = le32_to_cpu(np->rx_done_q[np->rx_done].status)) != 0) {		if (debug > 4)			printk(KERN_DEBUG "  netdev_rx() status of %d was %8.8x.\n",				   np->rx_done, desc_status);		if (--boguscnt < 0)			break;		if ( ! (desc_status & RxOK)) {			/* There was a error. */			if (debug > 2)				printk(KERN_DEBUG "  netdev_rx() Rx error was %8.8x.\n",					   desc_status);			np->stats.rx_errors++;			if (desc_status & RxFIFOErr)				np->stats.rx_fifo_errors++;		} else {			struct sk_buff *skb;			u16 pkt_len = desc_status;			/* Implicitly Truncate */			int entry = (desc_status >> 16) & 0x7ff;#ifndef final_version			if (debug > 4)				printk(KERN_DEBUG "  netdev_rx() normal Rx pkt length %d"					   ", bogus_cnt %d.\n",					   pkt_len, boguscnt);#endif			/* Check if the packet is long enough to accept without copying			   to a minimally-sized skbuff. */			if (pkt_len < rx_copybreak				&& (skb = dev_alloc_skb(pkt_len + 2)) != NULL) {				skb->dev = dev;				skb_reserve(skb, 2);	/* 16 byte align the IP header */				pci_dma_sync_single(np->pci_dev,						    np->rx_info[entry].mapping,						    pkt_len, PCI_DMA_FROMDEVICE);#if HAS_IP_COPYSUM			/* Call copy + cksum if available. */				eth_copy_and_sum(skb, np->rx_info[entry].skb->tail, pkt_len, 0);				skb_put(skb, pkt_len);#else				memcpy(skb_put(skb, pkt_len), np->rx_info[entry].skb->tail,					   pkt_len);#endif			} else {				char *temp;				pci_unmap_single(np->pci_dev, np->rx_info[entry].mapping, np->rx_buf_sz, PCI_DMA_FROMDEVICE);				skb = np->rx_info[entry].skb;				temp = skb_put(skb, pkt_len);				np->rx_info[entry].skb = NULL;				np->rx_info[entry].mapping = 0;#ifndef final_version				/* Remove after testing. */				if (le32_to_cpu(np->rx_ring[entry].rxaddr & ~3) != ((unsigned long) temp))					printk(KERN_ERR "%s: Internal fault: The skbuff addresses "						   "do not match in netdev_rx: %d vs. %p / %p.\n",						   dev->name,						   le32_to_cpu(np->rx_ring[entry].rxaddr),						   skb->head, temp);#endif			}#ifndef final_version				/* Remove after testing. */			/* You will want this info for the initial debug. */			if (debug > 5)				printk(KERN_DEBUG "  Rx data %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:"					   "%2.2x %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x %2.2x%2.2x "					   "%d.%d.%d.%d.\n",					   skb->data[0], skb->data[1], skb->data[2], skb->data[3],					   skb->data[4], skb->data[5], skb->data[6], skb->data[7],					   skb->data[8], skb->data[9], skb->data[10],					   skb->data[11], skb->data[12], skb->data[13],					   skb->data[14], skb->data[15], skb->data[16],					   skb->data[17]);#endif			skb->protocol = eth_type_trans(skb, dev);#ifdef full_rx_status			if (le32_to_cpu(np->rx_done_q[np->rx_done].status2) & 0x01000000)				skb->ip_summed = CHECKSUM_UNNECESSARY;#endif			netif_rx(skb);			dev->last_rx = jiffies;			np->stats.rx_packets++;		}		np->cur_rx++;		np->rx_done_q[np->rx_done].status = 0;		np->rx_done = (np->rx_done + 1) & (DONE_Q_SIZE-1);	}	writew(np->rx_done, dev->base_addr + CompletionQConsumerIdx);	/* Refill the Rx ring buffers. */	for (; np->cur_rx - np->dirty_rx > 0; np->dirty_rx++) {		struct sk_buff *skb;		int entry = np->dirty_rx % RX_RING_SIZE;		if (np->rx_info[entry].skb == NULL) {			skb = dev_alloc_skb(np->rx_buf_sz);			np->rx_info[entry].skb = skb;			if (skb == NULL)				break;			/* Better luck next round. */			np->rx_info[entry].mapping =				pci_map_single(np->pci_dev, skb->tail, np->rx_buf_sz, PCI_DMA_FROMDEVICE);			skb->dev = dev;			/* Mark as being used by this device. */			np->rx_ring[entry].rxaddr =				cpu_to_le32(np->rx_info[entry].mapping | RxDescValid);		}		if (entry == RX_RING_SIZE - 1)			np->rx_ring[entry].rxaddr |= cpu_to_le32(RxDescEndRing);		/* We could defer this until later... */		writew(entry, dev->base_addr + RxDescQIdx);	}	if (debug > 5		|| memcmp(np->pad0, np->pad0 + 1, sizeof(np->pad0) -1))		printk(KERN_DEBUG "  exiting netdev_rx() status of %d was %8.8x %d.\n",			   np->rx_done, desc_status,			   memcmp(np->pad0, np->pad0 + 1, sizeof(np->pad0) -1));	/* Restart Rx engine if stopped. */	return 0;}static void netdev_error(struct net_device *dev, int intr_status){	struct netdev_private *np = (struct netdev_private *)dev->priv;	if (intr_status & LinkChange) {		printk(KERN_NOTICE "%s: Link changed: Autonegotiation advertising"			   " %4.4x  partner %4.4x.\n", dev->name,			   mdio_read(dev, np->phys[0], 4),			   mdio_read(dev, np->phys[0], 5));		check_duplex(dev, 0);	}	if (intr_status & StatsMax) {		get_stats(dev);	}	/* Came close to underrunning the Tx FIFO, increase threshold. */	if (intr_status & IntrTxDataLow)		writel(++np->tx_threshold, dev->base_addr + TxThreshold);	if ((intr_status &		 ~(IntrAbnormalSummary|LinkChange|StatsMax|IntrTxDataLow|1)) && debug)		printk(KERN_ERR "%s: Something Wicked happened! %4.4x.\n",			   dev->name, intr_status);	/* Hmmmmm, it's not clear how to recover from PCI faults. */	if (intr_status & IntrTxPCIErr)		np->stats.tx_fifo_errors++;	if (intr_status & IntrRxPCIErr)		np->stats.rx_fifo_errors++;}static struct net_device_stats *get_stats(struct net_device *dev){	long ioaddr = dev->base_addr;	struct netdev_private *np = (struct netdev_private *)dev->priv;	/* This adapter architecture needs no SMP locks. */	np->stats.tx_bytes = readl(ioaddr + 0x57010);	np->stats.rx_bytes = readl(ioaddr + 0x57044);	np->stats.tx_packets = readl(ioaddr + 0x57000);	np->stats.tx_aborted_errors =		readl(ioaddr + 0x57024) + readl(ioaddr + 0x57028);	np->stats.tx_window_errors = readl(ioaddr + 0x57018);	np->stats.collisions = readl(ioaddr + 0x57004) + readl(ioaddr + 0x57008);	/* The chip only need report frame silently dropped. */	np->stats.rx_dropped	   += readw(ioaddr + RxDMAStatus);	writew(0, ioaddr + RxDMAStatus);	np->stats.rx_crc_errors	   = readl(ioaddr + 0x5703C);	np->stats.rx_frame_errors = readl(ioaddr + 0x57040);	np->stats.rx_length_errors = readl(ioaddr + 0x57058);	np->stats.rx_missed_errors = readl(ioaddr + 0x5707C);	return &np->stats;}/* The little-endian AUTODIN II ethernet CRC calculations.   A big-endian version is also available.   This is slow but compact code.  Do not use this routine for bulk data,   use a table-based routine instead.   This is common code and should be moved to net/core/crc.c.   Chips may use the upper or lower CRC bits, and may reverse and/or invert   them.  Select the endian-ness that results in minimal calculations.*/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){	long ioaddr = dev->base_addr;	u32 rx_mode;	struct dev_mc_list *mclist;	int i;	if (dev->flags & IFF_PROMISC) {			/* Set promiscuous. */		/* Unconditionally log net taps. */		printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n", dev->name);		rx_mode = AcceptBroadcast|AcceptAllMulticast|AcceptAll|AcceptMyPhys;	} else if ((dev->mc_count > multicast_filter_limit)			   ||  (dev->flags & IFF_ALLMULTI)) {		/* Too many to match, or accept all multicasts. */		rx_mode = AcceptBroadcast|AcceptAllMulticast|AcceptMyPhys;	} else if (dev->mc_count <= 15) {		/* Use the 16 element perfect filter. */		long filter_addr = ioaddr + 0x56000 + 1*16;		for (i = 1, mclist = dev->mc_list; mclist  &&  i <= dev->mc_count;			 i++, mclist = mclist->next) {			u16 *eaddrs = (u16 *)mclist->dmi_addr;			writew(cpu_to_be16(eaddrs[2]), filter_addr); filter_addr += 4;			writew(cpu_to_be16(eaddrs[1]), filter_addr); filter_addr += 4;			writew(cpu_to_be16(eaddrs[0]), filter_addr); filter_addr += 8;		}		while (i++ < 16) {			writew(0xffff, filter_addr); filter_addr += 4;			writew(0xffff, filter_addr); filter_addr += 4;			writew(0xffff, filter_addr); filter_addr += 8;		}		rx_mode = AcceptBroadcast | AcceptMyPhys;	} else {		/* Must use a multicast hash table. */		long filter_addr;		u16 mc_filter[32] __attribute__ ((aligned(sizeof(long))));	/* Multicast hash filter */		memset(mc_filter, 0, sizeof(mc_filter));		for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;			 i++, mclist = mclist->next) {			set_bit(ether_crc_le(ETH_ALEN, mclist->dmi_addr) >> 23, mc_filter);		}		/* Clear the perfect filter list. */		filter_addr = ioaddr + 0x56000 + 1*16;		for (i = 1; i < 16; i++) {			writew(0xffff, filter_addr); filter_addr += 4;			writew(0xffff, filter_addr); filter_addr += 4;			writew(0xffff, filter_addr); filter_addr += 8;		}		for (filter_addr=ioaddr + 0x56100, i=0; i < 32; filter_addr+= 16, i++)			writew(mc_filter[i], filter_addr);		rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;	}	writel(rx_mode, ioaddr + RxFilterMode);}static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd){	struct netdev_private *np = (struct netdev_private *)dev->priv;	u16 *data = (u16 *)&rq->ifr_data;	switch(cmd) {	case SIOCDEVPRIVATE:		/* Get the address of the PHY in use. */		data[0] = np->phys[0] & 0x1f;		/* Fall Through */	case SIOCDEVPRIVATE+1:		/* Read the specified MII register. */		data[3] = mdio_read(dev, data[0] & 0x1f, data[1] & 0x1f);		return 0;	case SIOCDEVPRIVATE+2:		/* Write the specified MII register */		if (!capable(CAP_NET_ADMIN))			return -EPERM;		if (data[0] == np->phys[0]) {			u16 value = data[2];			switch (data[1]) {			case 0:				if (value & 0x9000)	/* Autonegotiation. */					np->medialock = 0;				else {					np->full_duplex = (value & 0x0100) ? 1 : 0;					np->medialock = 1;				}				break;			case 4: np->advertising = value; break;			}			check_duplex(dev, 0);		}		mdio_write(dev, data[0] & 0x1f, data[1] & 0x1f, data[2]);		return 0;	default:		return -EOPNOTSUPP;	}}static int netdev_close(struct net_device *dev){	long ioaddr = dev->base_addr;	struct netdev_private *np = (struct netdev_private *)dev->priv;	int i;	netif_stop_queue(dev);	del_timer_sync(&np->timer);	if (debug > 1) {		printk(KERN_DEBUG "%s: Shutting down ethercard, Intr status %4.4x.\n",			   dev->name, (int)readl(ioaddr + IntrStatus));		printk(KERN_DEBUG "%s: Queue pointers were Tx %d / %d,  Rx %d / %d.\n",			   dev->name, np->cur_tx, np->dirty_tx, np->cur_rx, np->dirty_rx);	}	/* Disable interrupts by clearing the interrupt mask. */	writel(0, ioaddr + IntrEnable);	/* Stop the chip's Tx and Rx processes. */#ifdef __i386__	if (debug > 2) {		printk("\n"KERN_DEBUG"  Tx ring at %8.8x:\n",			   np->tx_ring_dma);		for (i = 0; i < 8 /* TX_RING_SIZE is huge! */; i++)			printk(KERN_DEBUG " #%d desc. %8.8x %8.8x -> %8.8x.\n",				   i, le32_to_cpu(np->tx_ring[i].status),				   le32_to_cpu(np->tx_ring[i].addr),				   le32_to_cpu(np->tx_done_q[i].status));		printk(KERN_DEBUG "  Rx ring at %8.8x -> %p:\n",			   np->rx_ring_dma, np->rx_done_q);		if (np->rx_done_q)			for (i = 0; i < 8 /* RX_RING_SIZE */; i++) {				printk(KERN_DEBUG " #%d desc. %8.8x -> %8.8x\n",					   i, le32_to_cpu(np->rx_ring[i].rxaddr), le32_to_cpu(np->rx_done_q[i].status));		}	}#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++) {		np->rx_ring[i].rxaddr = cpu_to_le32(0xBADF00D0); /* An invalid address. */		if (np->rx_info[i].skb != NULL) {			pci_unmap_single(np->pci_dev, np->rx_info[i].mapping, np->rx_buf_sz, PCI_DMA_FROMDEVICE);			dev_kfree_skb(np->rx_info[i].skb);		}		np->rx_info[i].skb = NULL;		np->rx_info[i].mapping = 0;	}	for (i = 0; i < TX_RING_SIZE; i++) {		struct sk_buff *skb = np->tx_info[i].skb;		if (skb != NULL) {			pci_unmap_single(np->pci_dev,					 np->tx_info[i].mapping,					 skb->len, PCI_DMA_TODEVICE);			dev_kfree_skb(skb);		}		np->tx_info[i].skb = NULL;		np->tx_info[i].mapping = 0;	}	MOD_DEC_USE_COUNT;	return 0;}static void __devexit starfire_remove_one (struct pci_dev *pdev){	struct net_device *dev = pdev->driver_data;	struct netdev_private *np;		if (!dev)		BUG();	np = dev->priv;	unregister_netdev(dev);	iounmap((char *)dev->base_addr);	if (np->tx_done_q)		pci_free_consistent(np->pci_dev, PAGE_SIZE,				    np->tx_done_q, np->tx_done_q_dma);	if (np->rx_done_q)		pci_free_consistent(np->pci_dev, PAGE_SIZE,				    np->rx_done_q, np->rx_done_q_dma);	if (np->tx_ring)		pci_free_consistent(np->pci_dev, PAGE_SIZE,				    np->tx_ring, np->tx_ring_dma);	if (np->rx_ring)		pci_free_consistent(np->pci_dev, PAGE_SIZE,				    np->rx_ring, np->rx_ring_dma);	kfree(dev);}static struct pci_driver starfire_driver = {	name:		"starfire",	probe:		starfire_init_one,	remove:		starfire_remove_one,	id_table:	starfire_pci_tbl,};static int __init starfire_init (void){	return pci_module_init (&starfire_driver);}static void __exit starfire_cleanup (void){	pci_unregister_driver (&starfire_driver);}module_init(starfire_init);module_exit(starfire_cleanup);/* * Local variables: *  compile-command: "gcc -DMODULE -Wall -Wstrict-prototypes -O6 -c starfire.c" *  simple-compile-command: "gcc -DMODULE -O6 -c starfire.c" *  c-indent-level: 4 *  c-basic-offset: 4 *  tab-width: 4 * End: */

⌨️ 快捷键说明

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