epic100.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,688 行 · 第 1/4 页

C
1,688
字号
			/* 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_for_cpu(ep->pci_dev,							    ep->rx_ring[entry].bufaddr,							    ep->rx_buf_sz,							    PCI_DMA_FROMDEVICE);				eth_copy_and_sum(skb, ep->rx_skbuff[entry]->tail, pkt_len, 0);				skb_put(skb, pkt_len);				pci_dma_sync_single_for_device(ep->pci_dev,							       ep->rx_ring[entry].bufaddr,							       ep->rx_buf_sz,							       PCI_DMA_FROMDEVICE);			} else {				pci_unmap_single(ep->pci_dev, 					ep->rx_ring[entry].bufaddr, 					ep->rx_buf_sz, PCI_DMA_FROMDEVICE);				skb_put(skb = ep->rx_skbuff[entry], pkt_len);				ep->rx_skbuff[entry] = NULL;			}			skb->protocol = eth_type_trans(skb, dev);			netif_receive_skb(skb);			dev->last_rx = jiffies;			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 = pci_map_single(ep->pci_dev, 				skb->tail, ep->rx_buf_sz, PCI_DMA_FROMDEVICE);			work_done++;		}		ep->rx_ring[entry].rxstatus = cpu_to_le32(DescOwn);	}	return work_done;}static void epic_rx_err(struct net_device *dev, struct epic_private *ep){	long ioaddr = dev->base_addr;	int status;	status = inl(ioaddr + INTSTAT);	if (status == EpicRemoved)		return;	if (status & RxOverflow) 	/* Missed a Rx frame. */		ep->stats.rx_errors++;	if (status & (RxOverflow | RxFull))		outw(RxQueued, ioaddr + COMMAND);}static int epic_poll(struct net_device *dev, int *budget){	struct epic_private *ep = dev->priv;	int work_done, orig_budget;	long ioaddr = dev->base_addr;	orig_budget = (*budget > dev->quota) ? dev->quota : *budget;rx_action:	epic_tx(dev, ep);	work_done = epic_rx(dev, *budget);	epic_rx_err(dev, ep);	*budget -= work_done;	dev->quota -= work_done;	if (netif_running(dev) && (work_done < orig_budget)) {		unsigned long flags;		int more;		/* A bit baroque but it avoids a (space hungry) spin_unlock */		spin_lock_irqsave(&ep->napi_lock, flags);		more = ep->reschedule_in_poll;		if (!more) {			__netif_rx_complete(dev);			outl(EpicNapiEvent, ioaddr + INTSTAT);			epic_napi_irq_on(dev, ep);		} else			ep->reschedule_in_poll--;		spin_unlock_irqrestore(&ep->napi_lock, flags);		if (more)			goto rx_action;	}	return (work_done >= orig_budget);}static int epic_close(struct net_device *dev){	long ioaddr = dev->base_addr;	struct epic_private *ep = dev->priv;	struct sk_buff *skb;	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_disable_int(dev, ep);	free_irq(dev->irq, dev);	epic_pause(dev);	/* Free all the skbuffs in the Rx queue. */	for (i = 0; i < RX_RING_SIZE; i++) {		skb = ep->rx_skbuff[i];		ep->rx_skbuff[i] = NULL;		ep->rx_ring[i].rxstatus = 0;		/* Not owned by Epic chip. */		ep->rx_ring[i].buflength = 0;		if (skb) {			pci_unmap_single(ep->pci_dev, ep->rx_ring[i].bufaddr, 				 	 ep->rx_buf_sz, PCI_DMA_FROMDEVICE);			dev_kfree_skb(skb);		}		ep->rx_ring[i].bufaddr = 0xBADF00D0; /* An invalid address. */	}	for (i = 0; i < TX_RING_SIZE; i++) {		skb = ep->tx_skbuff[i];		ep->tx_skbuff[i] = NULL;		if (!skb)			continue;		pci_unmap_single(ep->pci_dev, ep->tx_ring[i].bufaddr, 				 skb->len, PCI_DMA_TODEVICE);		dev_kfree_skb(skb);	}	/* Green! Leave the chip in low-power mode. */	outl(0x0008, ioaddr + GENCTL);	return 0;}static struct net_device_stats *epic_get_stats(struct net_device *dev){	struct epic_private *ep = 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. */static void set_rx_mode(struct net_device *dev){	long ioaddr = dev->base_addr;	struct epic_private *ep = 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) {			unsigned int bit_nr =				ether_crc_le(ETH_ALEN, mclist->dmi_addr) & 0x3f;			mc_filter[bit_nr >> 3] |= (1 << bit_nr);		}	}	/* 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 void netdev_get_drvinfo (struct net_device *dev, struct ethtool_drvinfo *info){	struct epic_private *np = dev->priv;	strcpy (info->driver, DRV_NAME);	strcpy (info->version, DRV_VERSION);	strcpy (info->bus_info, pci_name(np->pci_dev));}static int netdev_get_settings(struct net_device *dev, struct ethtool_cmd *cmd){	struct epic_private *np = dev->priv;	int rc;	spin_lock_irq(&np->lock);	rc = mii_ethtool_gset(&np->mii, cmd);	spin_unlock_irq(&np->lock);	return rc;}static int netdev_set_settings(struct net_device *dev, struct ethtool_cmd *cmd){	struct epic_private *np = dev->priv;	int rc;	spin_lock_irq(&np->lock);	rc = mii_ethtool_sset(&np->mii, cmd);	spin_unlock_irq(&np->lock);	return rc;}static int netdev_nway_reset(struct net_device *dev){	struct epic_private *np = dev->priv;	return mii_nway_restart(&np->mii);}static u32 netdev_get_link(struct net_device *dev){	struct epic_private *np = dev->priv;	return mii_link_ok(&np->mii);}static u32 netdev_get_msglevel(struct net_device *dev){	return debug;}static void netdev_set_msglevel(struct net_device *dev, u32 value){	debug = value;}static int ethtool_begin(struct net_device *dev){	unsigned long ioaddr = dev->base_addr;	/* power-up, if interface is down */	if (! netif_running(dev)) {		outl(0x0200, ioaddr + GENCTL);		outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL);	}	return 0;}static void ethtool_complete(struct net_device *dev){	unsigned long ioaddr = dev->base_addr;	/* power-down, if interface is down */	if (! netif_running(dev)) {		outl(0x0008, ioaddr + GENCTL);		outl((inl(ioaddr + NVCTL) & ~0x483C) | 0x0000, ioaddr + NVCTL);	}}static struct ethtool_ops netdev_ethtool_ops = {	.get_drvinfo		= netdev_get_drvinfo,	.get_settings		= netdev_get_settings,	.set_settings		= netdev_set_settings,	.nway_reset		= netdev_nway_reset,	.get_link		= netdev_get_link,	.get_msglevel		= netdev_get_msglevel,	.set_msglevel		= netdev_set_msglevel,	.get_sg			= ethtool_op_get_sg,	.get_tx_csum		= ethtool_op_get_tx_csum,	.begin			= ethtool_begin,	.complete		= ethtool_complete};static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd){	struct epic_private *np = dev->priv;	long ioaddr = dev->base_addr;	struct mii_ioctl_data *data = if_mii(rq);	int rc;	/* power-up, if interface is down */	if (! netif_running(dev)) {		outl(0x0200, ioaddr + GENCTL);		outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL);	}	/* all non-ethtool ioctls (the SIOC[GS]MIIxxx ioctls) */	spin_lock_irq(&np->lock);	rc = generic_mii_ioctl(&np->mii, data, cmd, NULL);	spin_unlock_irq(&np->lock);	/* power-down, if interface is down */	if (! netif_running(dev)) {		outl(0x0008, ioaddr + GENCTL);		outl((inl(ioaddr + NVCTL) & ~0x483C) | 0x0000, ioaddr + NVCTL);	}	return rc;}static void __devexit epic_remove_one (struct pci_dev *pdev){	struct net_device *dev = pci_get_drvdata(pdev);	struct epic_private *ep = dev->priv;		pci_free_consistent(pdev, TX_TOTAL_SIZE, ep->tx_ring, ep->tx_ring_dma);	pci_free_consistent(pdev, RX_TOTAL_SIZE, ep->rx_ring, ep->rx_ring_dma);	unregister_netdev(dev);#ifndef USE_IO_OPS	iounmap((void*) dev->base_addr);#endif	pci_release_regions(pdev);	free_netdev(dev);	pci_disable_device(pdev);	pci_set_drvdata(pdev, NULL);	/* pci_power_off(pdev, -1); */}#ifdef CONFIG_PMstatic int epic_suspend (struct pci_dev *pdev, u32 state){	struct net_device *dev = pci_get_drvdata(pdev);	long ioaddr = dev->base_addr;	if (!netif_running(dev))		return 0;	epic_pause(dev);	/* Put the chip into low-power mode. */	outl(0x0008, ioaddr + GENCTL);	/* pci_power_off(pdev, -1); */	return 0;}static int epic_resume (struct pci_dev *pdev){	struct net_device *dev = pci_get_drvdata(pdev);	if (!netif_running(dev))		return 0;	epic_restart(dev);	/* pci_power_on(pdev); */	return 0;}#endif /* CONFIG_PM */static struct pci_driver epic_driver = {	.name		= DRV_NAME,	.id_table	= epic_pci_tbl,	.probe		= epic_init_one,	.remove		= __devexit_p(epic_remove_one),#ifdef CONFIG_PM	.suspend	= epic_suspend,	.resume		= epic_resume,#endif /* CONFIG_PM */};static int __init epic_init (void){/* when a module, this is printed whether or not devices are found in probe */#ifdef MODULE	printk (KERN_INFO "%s" KERN_INFO "%s" KERN_INFO "%s",		version, version2, version3);#endif	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 + =
减小字号Ctrl + -
显示快捷键?