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

📄 via-rhine.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
	u32 intr_status;	int boguscnt = max_interrupt_work;	ioaddr = dev->base_addr;		while ((intr_status = readw(ioaddr + IntrStatus))) {		/* Acknowledge all of the current interrupt sources ASAP. */		writew(intr_status & 0xffff, ioaddr + IntrStatus);		if (debug > 4)			printk(KERN_DEBUG "%s: Interrupt, status %4.4x.\n",				   dev->name, intr_status);		if (intr_status & (IntrRxDone | IntrRxErr | IntrRxDropped |						   IntrRxWakeUp | IntrRxEmpty | IntrRxNoBuf))			via_rhine_rx(dev);		if (intr_status & (IntrTxDone | IntrTxAbort | IntrTxUnderrun |						   IntrTxAborted))			via_rhine_tx(dev);		/* Abnormal error summary/uncommon events handlers. */		if (intr_status & (IntrPCIErr | IntrLinkChange | IntrMIIChange |						   IntrStatsMax | IntrTxAbort | IntrTxUnderrun))			via_rhine_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;		}	}	if (debug > 3)		printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n",			   dev->name, readw(ioaddr + IntrStatus));}/* This routine is logically part of the interrupt handler, but isolated   for clarity. */static void via_rhine_tx(struct net_device *dev){	struct netdev_private *np = (struct netdev_private *)dev->priv;	int txstatus = 0, entry = np->dirty_tx % TX_RING_SIZE;	spin_lock (&np->lock);	/* find and cleanup dirty tx descriptors */	while (np->dirty_tx != np->cur_tx) {		txstatus = le32_to_cpu(np->tx_ring[entry].tx_status);		if (txstatus & DescOwn)			break;		if (debug > 6)			printk(KERN_DEBUG " Tx scavenge %d status %8.8x.\n",				   entry, txstatus);		if (txstatus & 0x8000) {			if (debug > 1)				printk(KERN_DEBUG "%s: Transmit error, Tx status %8.8x.\n",					   dev->name, txstatus);			np->stats.tx_errors++;			if (txstatus & 0x0400) np->stats.tx_carrier_errors++;			if (txstatus & 0x0200) np->stats.tx_window_errors++;			if (txstatus & 0x0100) np->stats.tx_aborted_errors++;			if (txstatus & 0x0080) np->stats.tx_heartbeat_errors++;			if (txstatus & 0x0002) np->stats.tx_fifo_errors++;			/* Transmitter restarted in 'abnormal' handler. */		} else {			np->stats.collisions += (txstatus >> 3) & 15;			np->stats.tx_bytes += np->tx_skbuff[entry]->len;			np->stats.tx_packets++;		}		/* Free the original skb. */		if (np->tx_skbuff_dma[entry]) {			pci_unmap_single(np->pdev,							 np->tx_skbuff_dma[entry],							 np->tx_skbuff[entry]->len, PCI_DMA_TODEVICE);		}		dev_kfree_skb_irq(np->tx_skbuff[entry]);		np->tx_skbuff[entry] = NULL;		entry = (++np->dirty_tx) % TX_RING_SIZE;	}	if ((np->cur_tx - np->dirty_tx) < TX_QUEUE_LEN - 4)		netif_wake_queue (dev);	spin_unlock (&np->lock);}/* This routine is logically part of the interrupt handler, but isolated   for clarity and better register allocation. */static void via_rhine_rx(struct net_device *dev){	struct netdev_private *np = (struct netdev_private *)dev->priv;	int entry = np->cur_rx % RX_RING_SIZE;	int boguscnt = np->dirty_rx + RX_RING_SIZE - np->cur_rx;	if (debug > 4) {		printk(KERN_DEBUG " In via_rhine_rx(), entry %d status %8.8x.\n",			   entry, le32_to_cpu(np->rx_head_desc->rx_status));	}	/* If EOP is set on the next entry, it's a new packet. Send it up. */	while ( ! (np->rx_head_desc->rx_status & cpu_to_le32(DescOwn))) {		struct rx_desc *desc = np->rx_head_desc;		u32 desc_status = le32_to_cpu(desc->rx_status);		int data_size = desc_status >> 16;		if (debug > 4)			printk(KERN_DEBUG "  via_rhine_rx() status is %8.8x.\n",				   desc_status);		if (--boguscnt < 0)			break;		if ( (desc_status & (RxWholePkt | RxErr)) !=  RxWholePkt) {			if ((desc_status & RxWholePkt) !=  RxWholePkt) {				printk(KERN_WARNING "%s: Oversized Ethernet frame spanned "					   "multiple buffers, entry %#x length %d status %8.8x!\n",					   dev->name, entry, data_size, desc_status);				printk(KERN_WARNING "%s: Oversized Ethernet frame %p vs %p.\n",					   dev->name, np->rx_head_desc, &np->rx_ring[entry]);				np->stats.rx_length_errors++;			} else if (desc_status & RxErr) {				/* There was a error. */				if (debug > 2)					printk(KERN_DEBUG "  via_rhine_rx() Rx error was %8.8x.\n",						   desc_status);				np->stats.rx_errors++;				if (desc_status & 0x0030) np->stats.rx_length_errors++;				if (desc_status & 0x0048) np->stats.rx_fifo_errors++;				if (desc_status & 0x0004) np->stats.rx_frame_errors++;				if (desc_status & 0x0002) {					/* this can also be updated outside the interrupt handler */					spin_lock (&np->lock);					np->stats.rx_crc_errors++;					spin_unlock (&np->lock);				}			}		} else {			struct sk_buff *skb;			/* Length should omit the CRC */			int pkt_len = data_size - 4;			/* 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->pdev, np->rx_skbuff_dma[entry],						    np->rx_buf_sz, PCI_DMA_FROMDEVICE);				/* *_IP_COPYSUM isn't defined anywhere and eth_copy_and_sum				   is memcpy for all archs so this is kind of pointless right				   now ... or? */#if HAS_IP_COPYSUM                     /* Call copy + cksum if available. */				eth_copy_and_sum(skb, np->rx_skbuff[entry]->tail, pkt_len, 0);				skb_put(skb, pkt_len);#else				memcpy(skb_put(skb, pkt_len), np->rx_skbuff[entry]->tail,					   pkt_len);#endif			} else {				skb = np->rx_skbuff[entry];				if (skb == NULL) {					printk(KERN_ERR "%s: Inconsistent Rx descriptor chain.\n",						   dev->name);					break;				}				np->rx_skbuff[entry] = NULL;				skb_put(skb, pkt_len);				pci_unmap_single(np->pdev, np->rx_skbuff_dma[entry],								 np->rx_buf_sz, PCI_DMA_FROMDEVICE);			}			skb->protocol = eth_type_trans(skb, dev);			netif_rx(skb);			dev->last_rx = jiffies;			np->stats.rx_bytes += skb->len;			np->stats.rx_packets++;		}		entry = (++np->cur_rx) % RX_RING_SIZE;		np->rx_head_desc = &np->rx_ring[entry];	}	/* Refill the Rx ring buffers. */	for (; np->cur_rx - np->dirty_rx > 0; np->dirty_rx++) {		struct sk_buff *skb;		entry = np->dirty_rx % RX_RING_SIZE;		if (np->rx_skbuff[entry] == NULL) {			skb = dev_alloc_skb(np->rx_buf_sz);			np->rx_skbuff[entry] = skb;			if (skb == NULL)				break;			/* Better luck next round. */			skb->dev = dev;			/* Mark as being used by this device. */			np->rx_skbuff_dma[entry] =				pci_map_single(np->pdev, skb->tail, np->rx_buf_sz, 							   PCI_DMA_FROMDEVICE);			np->rx_ring[entry].addr = cpu_to_le32(np->rx_skbuff_dma[entry]);		}		np->rx_ring[entry].rx_status = cpu_to_le32(DescOwn);	}	/* Pre-emptively restart Rx engine. */	writew(CmdRxDemand | np->chip_cmd, dev->base_addr + ChipCmd);}static void via_rhine_error(struct net_device *dev, int intr_status){	struct netdev_private *np = (struct netdev_private *)dev->priv;	long ioaddr = dev->base_addr;	spin_lock (&np->lock);	if (intr_status & (IntrMIIChange | IntrLinkChange)) {		if (readb(ioaddr + MIIStatus) & 0x02) {			/* Link failed, restart autonegotiation. */			if (np->drv_flags & HasDavicomPhy)				mdio_write(dev, np->phys[0], 0, 0x3300);		} else			via_rhine_check_duplex(dev);		if (debug)			printk(KERN_ERR "%s: MII status 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));	}	if (intr_status & IntrStatsMax) {		np->stats.rx_crc_errors	+= readw(ioaddr + RxCRCErrs);		np->stats.rx_missed_errors	+= readw(ioaddr + RxMissed);		clear_tally_counters(ioaddr);	}	if (intr_status & IntrTxAbort) {		/* Stats counted in Tx-done handler, just restart Tx. */		writew(CmdTxDemand | np->chip_cmd, dev->base_addr + ChipCmd);	}	if (intr_status & IntrTxUnderrun) {		if (np->tx_thresh < 0xE0)			writeb(np->tx_thresh += 0x20, ioaddr + TxConfig);		if (debug > 1)			printk(KERN_INFO "%s: Transmitter underrun, increasing Tx "				   "threshold setting to %2.2x.\n", dev->name, np->tx_thresh);	}	if ((intr_status & ~( IntrLinkChange | IntrStatsMax |						  IntrTxAbort | IntrTxAborted)) && debug > 1) {		printk(KERN_ERR "%s: Something Wicked happened! %4.4x.\n",			   dev->name, intr_status);		/* Recovery for other fault sources not known. */		writew(CmdTxDemand | np->chip_cmd, dev->base_addr + ChipCmd);	}	spin_unlock (&np->lock);}static struct net_device_stats *via_rhine_get_stats(struct net_device *dev){	struct netdev_private *np = (struct netdev_private *)dev->priv;	long ioaddr = dev->base_addr;	unsigned long flags;	spin_lock_irqsave(&np->lock, flags);	np->stats.rx_crc_errors	+= readw(ioaddr + RxCRCErrs);	np->stats.rx_missed_errors	+= readw(ioaddr + RxMissed);	clear_tally_counters(ioaddr);	spin_unlock_irqrestore(&np->lock, flags);	return &np->stats;}/* Clears the "tally counters" for CRC errors and missed frames(?).   It has been reported that some chips need a write of 0 to clear   these, for others the counters are set to 1 when written to and   instead cleared when read. So we clear them both ways ... */static inline void clear_tally_counters(const long ioaddr){	writel(0, ioaddr + RxMissed);	readw(ioaddr + RxCRCErrs);	readw(ioaddr + RxMissed);}/* The big-endian AUTODIN II 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 = 0x04c11db7U;static inline u32 ether_crc(int length, unsigned char *data){    int crc = -1;    while(--length >= 0) {		unsigned char current_octet = *data++;		int bit;		for (bit = 0; bit < 8; bit++, current_octet >>= 1) {			crc = (crc << 1) ^				((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0);		}    }    return crc;}static void via_rhine_set_rx_mode(struct net_device *dev){	struct netdev_private *np = (struct netdev_private *)dev->priv;	long ioaddr = dev->base_addr;	u32 mc_filter[2];			/* Multicast hash filter */	u8 rx_mode;					/* Note: 0x02=accept runt, 0x01=accept errs */	if (dev->flags & IFF_PROMISC) {			/* Set promiscuous. */		/* Unconditionally log net taps. */		printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n", dev->name);		rx_mode = 0x1C;	} else if ((dev->mc_count > multicast_filter_limit)			   ||  (dev->flags & IFF_ALLMULTI)) {		/* Too many to match, or accept all multicasts. */		writel(0xffffffff, ioaddr + MulticastFilter0);		writel(0xffffffff, ioaddr + MulticastFilter1);		rx_mode = 0x0C;	} else {		struct dev_mc_list *mclist;		int i;		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(ETH_ALEN, mclist->dmi_addr) >> 26, mc_filter);		}		writel(mc_filter[0], ioaddr + MulticastFilter0);		writel(mc_filter[1], ioaddr + MulticastFilter1);		rx_mode = 0x0C;	}	writeb(np->rx_thresh | rx_mode, ioaddr + RxConfig);}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;	unsigned long flags;	int retval;	spin_lock_irqsave(&np->lock, flags);	retval = 0;	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);		break;	case SIOCDEVPRIVATE+2:		/* Write the specified MII register */		if (!capable(CAP_NET_ADMIN)) {			retval = -EPERM;			break;		}		mdio_write(dev, data[0] & 0x1f, data[1] & 0x1f, data[2]);		break;	default:		retval = -EOPNOTSUPP;	}	spin_unlock_irqrestore(&np->lock, flags);	return retval;}static int via_rhine_close(struct net_device *dev){	long ioaddr = dev->base_addr;	struct netdev_private *np = (struct netdev_private *)dev->priv;	int i;	unsigned long flags;	del_timer_sync(&np->timer);	spin_lock_irqsave(&np->lock, flags);	netif_stop_queue(dev);	if (debug > 1)		printk(KERN_DEBUG "%s: Shutting down ethercard, status was %4.4x.\n",			   dev->name, readw(ioaddr + ChipCmd));	/* Switch to loopback mode to avoid hardware races. */	writeb(np->tx_thresh | 0x01, ioaddr + TxConfig);	/* Disable interrupts by clearing the interrupt mask. */	writew(0x0000, ioaddr + IntrEnable);	/* Stop the chip's Tx and Rx processes. */	writew(CmdStop, ioaddr + ChipCmd);	spin_unlock_irqrestore(&np->lock, flags);	/* Make sure there is no irq-handler running on a different CPU. */	synchronize_irq();	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].rx_status = 0;		np->rx_ring[i].addr = cpu_to_le32(0xBADF00D0); /* An invalid address. */		if (np->rx_skbuff[i]) {			pci_unmap_single(np->pdev,							 np->rx_skbuff_dma[i],							 np->rx_buf_sz, PCI_DMA_FROMDEVICE);			dev_kfree_skb(np->rx_skbuff[i]);		}		np->rx_skbuff[i] = 0;	}	/* Free all the skbuffs in the Tx queue, and also any bounce buffers. */	for (i = 0; i < TX_RING_SIZE; i++) {		np->tx_ring[i].tx_status = 0;		np->tx_ring[i].desc_length = cpu_to_le32(0x00e08000);		np->tx_ring[i].addr = cpu_to_le32(0xBADF00D0); /* An invalid address. */		if (np->tx_skbuff[i]) {			if (np->tx_skbuff_dma[i]) {				pci_unmap_single(np->pdev,								 np->tx_skbuff_dma[i],								 np->tx_skbuff[i]->len, PCI_DMA_TODEVICE);			}			dev_kfree_skb(np->tx_skbuff[i]);		}		np->tx_skbuff[i] = 0;		np->tx_buf[i] = 0;	}	pci_free_consistent(np->pdev, PKT_BUF_SZ * TX_RING_SIZE,						np->tx_bufs, np->tx_bufs_dma);	return 0;}static void __devexit via_rhine_remove_one (struct pci_dev *pdev){	struct net_device *dev = pdev->driver_data;	struct netdev_private *np = (struct netdev_private *)(dev->priv);		unregister_netdev(dev);	release_region(pci_resource_start (pdev, 0),		       pci_resource_len (pdev, 0));	release_mem_region(pci_resource_start (pdev, 1),		           pci_resource_len (pdev, 1));#ifndef USE_IO	iounmap((char *)(dev->base_addr));#endif	pci_free_consistent(pdev, 			    RX_RING_SIZE * sizeof(struct rx_desc) +			    TX_RING_SIZE * sizeof(struct tx_desc),			    np->rx_ring, np->rx_ring_dma);	kfree(dev);}static struct pci_driver via_rhine_driver = {	name:		"via-rhine",	id_table:	via_rhine_pci_tbl,	probe:		via_rhine_init_one,	remove:		via_rhine_remove_one,};static int __init via_rhine_init (void){	return pci_module_init (&via_rhine_driver);}static void __exit via_rhine_cleanup (void){	pci_unregister_driver (&via_rhine_driver);}module_init(via_rhine_init);module_exit(via_rhine_cleanup);/* * Local variables: *  compile-command: "gcc -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c via-rhine.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`" *  c-indent-level: 4 *  c-basic-offset: 4 *  tab-width: 4 * End: */

⌨️ 快捷键说明

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