📄 epic100.c
字号:
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 { 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_rx(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 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_pause(dev); free_irq(dev->irq, 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] = 0; 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] = 0; 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. *//* 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 = 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 netdev_ethtool_ioctl (struct net_device *dev, void *useraddr){ struct epic_private *np = dev->priv; u32 ethcmd; if (copy_from_user (ðcmd, useraddr, sizeof (ethcmd))) return -EFAULT; switch (ethcmd) { case ETHTOOL_GDRVINFO: { struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO }; strcpy (info.driver, DRV_NAME); strcpy (info.version, DRV_VERSION); strcpy (info.bus_info, np->pci_dev->slot_name); if (copy_to_user (useraddr, &info, sizeof (info))) return -EFAULT; return 0; } /* get settings */ case ETHTOOL_GSET: { struct ethtool_cmd ecmd = { ETHTOOL_GSET }; spin_lock_irq(&np->lock); mii_ethtool_gset(&np->mii, &ecmd); spin_unlock_irq(&np->lock); if (copy_to_user(useraddr, &ecmd, sizeof(ecmd))) return -EFAULT; return 0; } /* set settings */ case ETHTOOL_SSET: { int r; struct ethtool_cmd ecmd; if (copy_from_user(&ecmd, useraddr, sizeof(ecmd))) return -EFAULT; spin_lock_irq(&np->lock); r = mii_ethtool_sset(&np->mii, &ecmd); spin_unlock_irq(&np->lock); return r; } /* restart autonegotiation */ case ETHTOOL_NWAY_RST: { return mii_nway_restart(&np->mii); } /* get link status */ case ETHTOOL_GLINK: { struct ethtool_value edata = {ETHTOOL_GLINK}; edata.data = mii_link_ok(&np->mii); if (copy_to_user(useraddr, &edata, sizeof(edata))) return -EFAULT; return 0; } /* get message-level */ case ETHTOOL_GMSGLVL: { struct ethtool_value edata = {ETHTOOL_GMSGLVL}; edata.data = debug; if (copy_to_user(useraddr, &edata, sizeof(edata))) return -EFAULT; return 0; } /* set message-level */ case ETHTOOL_SMSGLVL: { struct ethtool_value edata; if (copy_from_user(&edata, useraddr, sizeof(edata))) return -EFAULT; debug = edata.data; return 0; } default: break; } return -EOPNOTSUPP;}static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd){ struct epic_private *ep = dev->priv; long ioaddr = dev->base_addr; struct mii_ioctl_data *data = (struct mii_ioctl_data *)&rq->ifr_data; switch(cmd) { case SIOCETHTOOL: return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data); case SIOCGMIIPHY: /* Get address of MII PHY in use. */ case SIOCDEVPRIVATE: /* for binary compat, remove in 2.5 */ data->phy_id = ep->phys[0] & 0x1f; /* Fall Through */ case SIOCGMIIREG: /* Read MII PHY register. */ case SIOCDEVPRIVATE+1: /* for binary compat, remove in 2.5 */ if (! netif_running(dev)) { outl(0x0200, ioaddr + GENCTL); outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL); } data->val_out = mdio_read(dev, data->phy_id & 0x1f, data->reg_num & 0x1f);#if 0 /* Just leave on if the ioctl() is ever used. */ if (! netif_running(dev)) { outl(0x0008, ioaddr + GENCTL); outl((inl(ioaddr + NVCTL) & ~0x483C) | 0x0000, ioaddr + NVCTL); }#endif return 0; case SIOCSMIIREG: /* Write MII PHY register. */ case SIOCDEVPRIVATE+2: /* for binary compat, remove in 2.5 */ if (!capable(CAP_NET_ADMIN)) return -EPERM; if (! netif_running(dev)) { outl(0x0200, ioaddr + GENCTL); outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL); } if (data->phy_id == ep->phys[0]) { u16 value = data->val_in; switch (data->reg_num) { case 0: /* Check for autonegotiation on or reset. */ ep->mii.duplex_lock = (value & 0x9000) ? 0 : 1; if (ep->mii.duplex_lock) ep->mii.full_duplex = (value & 0x0100) ? 1 : 0; break; case 4: ep->mii.advertising = value; break; } /* Perhaps check_duplex(dev), depending on chip semantics. */ } mdio_write(dev, data->phy_id & 0x1f, data->reg_num & 0x1f, data->val_in);#if 0 /* Leave on if the ioctl() is used. */ if (! netif_running(dev)) { 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 = 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); kfree(dev); 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 + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -