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

📄 epic100.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
	spin_unlock_irq(&ep->lock);	/* Trigger an immediate transmit demand. */	outl(TxQueued, dev->base_addr + COMMAND);	dev->trans_start = jiffies;	if (debug > 4)		printk(KERN_DEBUG "%s: Queued Tx packet size %d to slot %d, "			   "flag %2.2x Tx status %8.8x.\n",			   dev->name, (int)skb->len, entry, ctrl_word,			   (int)inl(dev->base_addr + TxSTAT));	return 0;}/* The interrupt handler does all of the Rx thread work and cleans up   after the Tx thread. */static void epic_interrupt(int irq, void *dev_instance, struct pt_regs *regs){	struct net_device *dev = (struct net_device *)dev_instance;	struct epic_private *ep = (struct epic_private *)dev->priv;	long ioaddr = dev->base_addr;	int status, boguscnt = max_interrupt_work;	spin_lock(&ep->lock);	do {		status = inl(ioaddr + INTSTAT);		/* Acknowledge all of the current interrupt sources ASAP. */		outl(status & 0x00007fff, ioaddr + INTSTAT);		if (debug > 4)			printk(KERN_DEBUG "%s: Interrupt, status=%#8.8x new "				   "intstat=%#8.8x.\n",				   dev->name, status, (int)inl(ioaddr + INTSTAT));		if ((status & IntrSummary) == 0)			break;		if (status & (RxDone | RxStarted | RxEarlyWarn | RxOverflow))			epic_rx(dev);		if (status & (TxEmpty | TxDone)) {			unsigned int dirty_tx, cur_tx;			/* Note: if this lock becomes a problem we can narrow the locked			   region at the cost of occasionally grabbing the lock more			   times. */			cur_tx = ep->cur_tx;			dirty_tx = ep->dirty_tx;			for (; cur_tx - dirty_tx > 0; dirty_tx++) {				int entry = dirty_tx % TX_RING_SIZE;				int txstatus = le32_to_cpu(ep->tx_ring[entry].txstatus);				if (txstatus & DescOwn)					break;			/* It still hasn't been Txed */				if ( ! (txstatus & 0x0001)) {					/* There was an major error, log it. */#ifndef final_version					if (debug > 1)						printk("%s: Transmit error, Tx status %8.8x.\n",							   dev->name, txstatus);#endif					ep->stats.tx_errors++;					if (txstatus & 0x1050) ep->stats.tx_aborted_errors++;					if (txstatus & 0x0008) ep->stats.tx_carrier_errors++;					if (txstatus & 0x0040) ep->stats.tx_window_errors++;					if (txstatus & 0x0010) ep->stats.tx_fifo_errors++;#ifdef ETHER_STATS					if (txstatus & 0x1000) ep->stats.collisions16++;#endif				} else {#ifdef ETHER_STATS					if ((txstatus & 0x0002) != 0) ep->stats.tx_deferred++;#endif					ep->stats.collisions += (txstatus >> 8) & 15;					ep->stats.tx_packets++;					ep->stats.tx_bytes += ep->tx_skbuff[entry]->len;				}				/* Free the original skb. */				dev_kfree_skb_irq(ep->tx_skbuff[entry]);				ep->tx_skbuff[entry] = 0;			}#ifndef final_version			if (cur_tx - dirty_tx > TX_RING_SIZE) {				printk("%s: Out-of-sync dirty pointer, %d vs. %d, full=%d.\n",					   dev->name, dirty_tx, cur_tx, ep->tx_full);				dirty_tx += TX_RING_SIZE;			}#endif			ep->dirty_tx = dirty_tx;			if (ep->tx_full				&& cur_tx - dirty_tx < TX_QUEUE_LEN - 4) {				/* The ring is no longer full, clear tbusy. */				ep->tx_full = 0;				netif_wake_queue(dev);			}		}		/* Check uncommon events all at once. */		if (status & (CntFull | TxUnderrun | RxOverflow | RxFull |					  PCIBusErr170 | PCIBusErr175)) {			if (status == 0xffffffff) /* Chip failed or removed (CardBus). */				break;			/* Always update the error counts to avoid overhead later. */			ep->stats.rx_missed_errors += inb(ioaddr + MPCNT);			ep->stats.rx_frame_errors += inb(ioaddr + ALICNT);			ep->stats.rx_crc_errors += inb(ioaddr + CRCCNT);			if (status & TxUnderrun) { /* Tx FIFO underflow. */				ep->stats.tx_fifo_errors++;				outl(ep->tx_threshold += 128, ioaddr + TxThresh);				/* Restart the transmit process. */				outl(RestartTx, ioaddr + COMMAND);			}			if (status & RxOverflow) {		/* Missed a Rx frame. */				ep->stats.rx_errors++;			}			if (status & (RxOverflow | RxFull))				outw(RxQueued, ioaddr + COMMAND);			if (status & PCIBusErr170) {				printk(KERN_ERR "%s: PCI Bus Error!  EPIC status %4.4x.\n",					   dev->name, status);				epic_pause(dev);				epic_restart(dev);			}			/* Clear all error sources. */			outl(status & 0x7f18, ioaddr + INTSTAT);		}		if (--boguscnt < 0) {			printk(KERN_ERR "%s: Too much work at interrupt, "				   "IntrStatus=0x%8.8x.\n",				   dev->name, status);			/* Clear all interrupt sources. */			outl(0x0001ffff, ioaddr + INTSTAT);			break;		}	} while (1);	if (debug > 3)		printk(KERN_DEBUG "%s: exiting interrupt, intr_status=%#4.4x.\n",			   dev->name, status);	spin_unlock(&ep->lock);}static int epic_rx(struct net_device *dev){	struct epic_private *ep = (struct epic_private *)dev->priv;	int entry = ep->cur_rx % RX_RING_SIZE;	int rx_work_limit = ep->dirty_rx + RX_RING_SIZE - ep->cur_rx;	int work_done = 0;	if (debug > 4)		printk(KERN_DEBUG " In epic_rx(), entry %d %8.8x.\n", entry,			   ep->rx_ring[entry].rxstatus);	/* If we own the next entry, it's a new packet. Send it up. */	while (!(le32_to_cpu(ep->rx_ring[entry].rxstatus) & DescOwn)) { 		int status = le32_to_cpu(ep->rx_ring[entry].rxstatus);		if (debug > 4)			printk(KERN_DEBUG "  epic_rx() status was %8.8x.\n", status);		if (--rx_work_limit < 0)			break;		if (status & 0x2006) {			if (debug > 2)				printk(KERN_DEBUG "%s: epic_rx() error status was %8.8x.\n",					   dev->name, status);			if (status & 0x2000) {				printk(KERN_WARNING "%s: Oversized Ethernet frame spanned "					   "multiple buffers, status %4.4x!\n", dev->name, status);				ep->stats.rx_length_errors++;			} else if (status & 0x0006)				/* Rx Frame errors are counted in hardware. */				ep->stats.rx_errors++;		} else {			/* Malloc up new buffer, compatible with net-2e. */			/* Omit the four octet CRC from the length. */			short pkt_len = (status >> 16) - 4;			struct sk_buff *skb;			if (pkt_len > PKT_BUF_SZ - 4) {				printk(KERN_ERR "%s: Oversized Ethernet frame, status %x "					   "%d bytes.\n",					   dev->name, pkt_len, status);				pkt_len = 1514;			}			/* 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 */#if 1 /* HAS_IP_COPYSUM */				eth_copy_and_sum(skb, ep->rx_skbuff[entry]->tail, pkt_len, 0);				skb_put(skb, pkt_len);#else				memcpy(skb_put(skb, pkt_len), ep->rx_skbuff[entry]->tail,					   pkt_len);#endif			} else {				skb_put(skb = ep->rx_skbuff[entry], pkt_len);				ep->rx_skbuff[entry] = NULL;			}			skb->protocol = eth_type_trans(skb, dev);			netif_rx(skb);			ep->stats.rx_packets++;			ep->stats.rx_bytes += pkt_len;		}		work_done++;		entry = (++ep->cur_rx) % RX_RING_SIZE;	}	/* Refill the Rx ring buffers. */	for (; ep->cur_rx - ep->dirty_rx > 0; ep->dirty_rx++) {		entry = ep->dirty_rx % RX_RING_SIZE;		if (ep->rx_skbuff[entry] == NULL) {			struct sk_buff *skb;			skb = ep->rx_skbuff[entry] = dev_alloc_skb(ep->rx_buf_sz);			if (skb == NULL)				break;			skb->dev = dev;			/* Mark as being used by this device. */			skb_reserve(skb, 2);	/* Align IP on 16 byte boundaries */			ep->rx_ring[entry].bufaddr = virt_to_le32desc(skb->tail);			work_done++;		}		ep->rx_ring[entry].rxstatus = cpu_to_le32(DescOwn);	}	return work_done;}static int epic_close(struct net_device *dev){	long ioaddr = dev->base_addr;	struct epic_private *ep = (struct epic_private *)dev->priv;	int i;	netif_stop_queue(dev);	if (debug > 1)		printk(KERN_DEBUG "%s: Shutting down ethercard, status was %2.2x.\n",			   dev->name, (int)inl(ioaddr + INTSTAT));	del_timer_sync(&ep->timer);	epic_pause(dev);	free_irq(dev->irq, dev);	/* Free all the skbuffs in the Rx queue. */	for (i = 0; i < RX_RING_SIZE; i++) {		struct sk_buff *skb = ep->rx_skbuff[i];		ep->rx_skbuff[i] = 0;		ep->rx_ring[i].rxstatus = 0;		/* Not owned by Epic chip. */		ep->rx_ring[i].buflength = 0;		ep->rx_ring[i].bufaddr = 0xBADF00D0; /* An invalid address. */		if (skb) {			dev_kfree_skb(skb);		}	}	for (i = 0; i < TX_RING_SIZE; i++) {		if (ep->tx_skbuff[i])			dev_kfree_skb(ep->tx_skbuff[i]);		ep->tx_skbuff[i] = 0;	}	/* Green! Leave the chip in low-power mode. */	outl(0x0008, ioaddr + GENCTL);	MOD_DEC_USE_COUNT;	return 0;}static struct net_device_stats *epic_get_stats(struct net_device *dev){	struct epic_private *ep = (struct epic_private *)dev->priv;	long ioaddr = dev->base_addr;	if (netif_running(dev)) {		/* Update the error counts. */		ep->stats.rx_missed_errors += inb(ioaddr + MPCNT);		ep->stats.rx_frame_errors += inb(ioaddr + ALICNT);		ep->stats.rx_crc_errors += inb(ioaddr + CRCCNT);	}	return &ep->stats;}/* Set or clear the multicast filter for this adaptor.   Note that we only use exclusion around actually queueing the   new frame, not around filling ep->setup_frame.  This is non-deterministic   when re-entered but still correct. *//* The little-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_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;	struct epic_private *ep = (struct epic_private *)dev->priv;	unsigned char mc_filter[8];		 /* Multicast hash filter */	int i;	if (dev->flags & IFF_PROMISC) {			/* Set promiscuous. */		outl(0x002C, ioaddr + RxCtrl);		/* Unconditionally log net taps. */		printk(KERN_INFO "%s: Promiscuous mode enabled.\n", dev->name);		memset(mc_filter, 0xff, sizeof(mc_filter));	} else if ((dev->mc_count > 0)  ||  (dev->flags & IFF_ALLMULTI)) {		/* There is apparently a chip bug, so the multicast filter		   is never enabled. */		/* Too many to filter perfectly -- accept all multicasts. */		memset(mc_filter, 0xff, sizeof(mc_filter));		outl(0x000C, ioaddr + RxCtrl);	} else if (dev->mc_count == 0) {		outl(0x0004, ioaddr + RxCtrl);		return;	} else {					/* Never executed, for now. */		struct dev_mc_list *mclist;		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) & 0x3f,					mc_filter);	}	/* ToDo: perhaps we need to stop the Tx and Rx process here? */	if (memcmp(mc_filter, ep->mc_filter, sizeof(mc_filter))) {		for (i = 0; i < 4; i++)			outw(((u16 *)mc_filter)[i], ioaddr + MC0 + i*4);		memcpy(ep->mc_filter, mc_filter, sizeof(mc_filter));	}	return;}static 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 epic_private *)dev->priv)->phys[0] & 0x1f;		/* Fall Through */	case SIOCDEVPRIVATE+1:		/* Read the specified MII register. */		if (! netif_running(dev)) {			outl(0x0200, ioaddr + GENCTL);			outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL);		}		data[3] = mdio_read(ioaddr, data[0] & 0x1f, data[1] & 0x1f);		if (! netif_running(dev)) {#ifdef notdef					/* Leave on if the ioctl() is used. */			outl(0x0008, ioaddr + GENCTL);			outl((inl(ioaddr + NVCTL) & ~0x483C) | 0x0000, ioaddr + NVCTL);#endif		}		return 0;	case SIOCDEVPRIVATE+2:		/* Write the specified MII register */		if (!capable(CAP_NET_ADMIN))			return -EPERM;		if (! netif_running(dev)) {			outl(0x0200, ioaddr + GENCTL);			outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL);		}		mdio_write(ioaddr, data[0] & 0x1f, data[1] & 0x1f, data[2]);		if (! netif_running(dev)) {#ifdef notdef					/* Leave on if the ioctl() is used. */			outl(0x0008, ioaddr + GENCTL);			outl((inl(ioaddr + NVCTL) & ~0x483C) | 0x0000, ioaddr + NVCTL);#endif		}		return 0;	default:		return -EOPNOTSUPP;	}}static void __devexit epic_remove_one (struct pci_dev *pdev){	struct net_device *dev = pdev->driver_data;		unregister_netdev(dev);#ifndef USE_IO_OPS	iounmap ((void*) dev->base_addr);#endif	release_mem_region (pci_resource_start (pdev, 1),			    pci_resource_len (pdev, 1));	release_region (pci_resource_start (pdev, 0),			pci_resource_len (pdev, 0));	kfree(dev);}static void epic_suspend (struct pci_dev *pdev){	struct net_device *dev = pdev->driver_data;	long ioaddr = dev->base_addr;	epic_pause(dev);	/* Put the chip into low-power mode. */	outl(0x0008, ioaddr + GENCTL);}static void epic_resume (struct pci_dev *pdev){	struct net_device *dev = pdev->driver_data;	epic_restart (dev);}static struct pci_driver epic_driver = {	name:		"epic100",	id_table:	epic_pci_tbl,	probe:		epic_init_one,	remove:		epic_remove_one,	suspend:	epic_suspend,	resume:		epic_resume,};static int __init epic_init (void){	return pci_module_init (&epic_driver);}static void __exit epic_cleanup (void){	pci_unregister_driver (&epic_driver);}module_init(epic_init);module_exit(epic_cleanup);

⌨️ 快捷键说明

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