📄 xircom_tulip_cb.c
字号:
for (i = 0; i < TX_RING_SIZE; i++) { if (tp->tx_skbuff[i]) dev_kfree_skb(tp->tx_skbuff[i]); tp->tx_skbuff[i] = 0; } tp->open = 0; return 0;}static struct net_device_stats *xircom_get_stats(struct net_device *dev){ struct xircom_private *tp = dev->priv; long ioaddr = dev->base_addr; if (netif_device_present(dev)) tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff; return &tp->stats;}static int xircom_ethtool_ioctl(struct net_device *dev, void *useraddr){ struct ethtool_cmd ecmd; struct xircom_private *tp = dev->priv; if (copy_from_user(&ecmd, useraddr, sizeof(ecmd))) return -EFAULT; switch (ecmd.cmd) { case ETHTOOL_GSET: ecmd.supported = SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | SUPPORTED_Autoneg | SUPPORTED_MII; ecmd.advertising = ADVERTISED_MII; if (tp->advertising[0] & ADVERTISE_10HALF) ecmd.advertising |= ADVERTISED_10baseT_Half; if (tp->advertising[0] & ADVERTISE_10FULL) ecmd.advertising |= ADVERTISED_10baseT_Full; if (tp->advertising[0] & ADVERTISE_100HALF) ecmd.advertising |= ADVERTISED_100baseT_Half; if (tp->advertising[0] & ADVERTISE_100FULL) ecmd.advertising |= ADVERTISED_100baseT_Full; if (tp->autoneg) { ecmd.advertising |= ADVERTISED_Autoneg; ecmd.autoneg = AUTONEG_ENABLE; } else ecmd.autoneg = AUTONEG_DISABLE; ecmd.port = PORT_MII; ecmd.transceiver = XCVR_INTERNAL; ecmd.phy_address = tp->phys[0]; ecmd.speed = tp->speed100 ? SPEED_100 : SPEED_10; ecmd.duplex = tp->full_duplex ? DUPLEX_FULL : DUPLEX_HALF; ecmd.maxtxpkt = TX_RING_SIZE / 2; ecmd.maxrxpkt = 0; if (copy_to_user(useraddr, &ecmd, sizeof(ecmd))) return -EFAULT; return 0; case ETHTOOL_SSET: { u16 autoneg, speed100, full_duplex; autoneg = (ecmd.autoneg == AUTONEG_ENABLE); speed100 = (ecmd.speed == SPEED_100); full_duplex = (ecmd.duplex == DUPLEX_FULL); tp->autoneg = autoneg; if (speed100 != tp->speed100 || full_duplex != tp->full_duplex) { tp->speed100 = speed100; tp->full_duplex = full_duplex; /* change advertising bits */ tp->advertising[0] &= ~(ADVERTISE_10HALF | ADVERTISE_10FULL | ADVERTISE_100HALF | ADVERTISE_100FULL | ADVERTISE_100BASE4); if (speed100) { if (full_duplex) tp->advertising[0] |= ADVERTISE_100FULL; else tp->advertising[0] |= ADVERTISE_100HALF; } else { if (full_duplex) tp->advertising[0] |= ADVERTISE_10FULL; else tp->advertising[0] |= ADVERTISE_10HALF; } } check_duplex(dev); return 0; } case ETHTOOL_GDRVINFO: { struct ethtool_drvinfo info; memset(&info, 0, sizeof(info)); info.cmd = ecmd.cmd; strcpy(info.driver, DRV_NAME); strcpy(info.version, DRV_VERSION); *info.fw_version = 0; strcpy(info.bus_info, tp->pdev->slot_name); if (copy_to_user(useraddr, &info, sizeof(info))) return -EFAULT; return 0; } default: return -EOPNOTSUPP; }}/* Provide ioctl() calls to examine the MII xcvr state. */static int xircom_ioctl(struct net_device *dev, struct ifreq *rq, int cmd){ struct xircom_private *tp = dev->priv; u16 *data = (u16 *)&rq->ifr_data; int phy = tp->phys[0] & 0x1f; long flags; switch(cmd) { case SIOCETHTOOL: return xircom_ethtool_ioctl(dev, (void *) rq->ifr_data); /* Legacy mii-diag interface */ case SIOCGMIIPHY: /* Get address of MII PHY in use. */ case SIOCDEVPRIVATE: /* for binary compat, remove in 2.5 */ if (tp->mii_cnt) data[0] = phy; else return -ENODEV; return 0; case SIOCGMIIREG: /* Read MII PHY register. */ case SIOCDEVPRIVATE+1: /* for binary compat, remove in 2.5 */ save_flags(flags); cli(); data[3] = mdio_read(dev, data[0] & 0x1f, data[1] & 0x1f); restore_flags(flags); 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; save_flags(flags); cli(); if (data[0] == tp->phys[0]) { u16 value = data[2]; switch (data[1]) { case 0: if (value & (BMCR_RESET | BMCR_ANENABLE)) /* Autonegotiation. */ tp->autoneg = 1; else { tp->full_duplex = (value & BMCR_FULLDPLX) ? 1 : 0; tp->autoneg = 0; } break; case 4: tp->advertising[0] = value; break; } check_duplex(dev); } mdio_write(dev, data[0] & 0x1f, data[1] & 0x1f, data[2]); restore_flags(flags); return 0; default: return -EOPNOTSUPP; } return -EOPNOTSUPP;}/* The little-endian AUTODIN32 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 u32 ether_crc_le(int length, unsigned char *data){ u32 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 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;}/* Set or clear the multicast filter for this adaptor. Note that we only use exclusion around actually queueing the new frame, not around filling tp->setup_frame. This is non-deterministic when re-entered but still correct. */static void set_rx_mode(struct net_device *dev){ struct xircom_private *tp = dev->priv; struct dev_mc_list *mclist; long ioaddr = dev->base_addr; int csr6 = inl(ioaddr + CSR6); u16 *eaddrs, *setup_frm; u32 tx_flags; int i; tp->csr6 &= ~(AllMultiBit | PromiscBit | HashFilterBit); csr6 &= ~(AllMultiBit | PromiscBit | HashFilterBit); if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ tp->csr6 |= PromiscBit; csr6 |= PromiscBit; goto out; } if ((dev->mc_count > 1000) || (dev->flags & IFF_ALLMULTI)) { /* Too many to filter well -- accept all multicasts. */ tp->csr6 |= AllMultiBit; csr6 |= AllMultiBit; goto out; } tx_flags = Tx1WholePkt | Tx1SetupPkt | PKT_SETUP_SZ; /* Note that only the low-address shortword of setup_frame is valid! */ setup_frm = tp->setup_frame; mclist = dev->mc_list; /* Fill the first entry with our physical address. */ eaddrs = (u16 *)dev->dev_addr; *setup_frm = cpu_to_le16(eaddrs[0]); setup_frm += 2; *setup_frm = cpu_to_le16(eaddrs[1]); setup_frm += 2; *setup_frm = cpu_to_le16(eaddrs[2]); setup_frm += 2; if (dev->mc_count > 14) { /* Must use a multicast hash table. */ u32 *hash_table = (u32 *)(tp->setup_frame + 4 * 12); u32 hash, hash2; tx_flags |= Tx1HashSetup; tp->csr6 |= HashFilterBit; csr6 |= HashFilterBit; /* Fill the unused 3 entries with the broadcast address. At least one entry *must* contain the broadcast address!!!*/ for (i = 0; i < 3; i++) { *setup_frm = 0xffff; setup_frm += 2; *setup_frm = 0xffff; setup_frm += 2; *setup_frm = 0xffff; setup_frm += 2; } /* Truly brain-damaged hash filter layout */ /* XXX: not sure if I should take the last or the first 9 bits */ for (i = 0; i < dev->mc_count; i++, mclist = mclist->next) { u32 *hptr; hash = ether_crc(ETH_ALEN, mclist->dmi_addr) & 0x1ff; if (hash < 384) { hash2 = hash + ((hash >> 4) << 4) + ((hash >> 5) << 5); } else { hash -= 384; hash2 = 64 + hash + (hash >> 4) * 80; } hptr = &hash_table[hash2 & ~0x1f]; *hptr |= cpu_to_le32(1 << (hash2 & 0x1f)); } } else { /* We have <= 14 mcast addresses so we can use Xircom's wonderful 16-address perfect filter. */ for (i = 0; i < dev->mc_count; i++, mclist = mclist->next) { eaddrs = (u16 *)mclist->dmi_addr; *setup_frm = cpu_to_le16(eaddrs[0]); setup_frm += 2; *setup_frm = cpu_to_le16(eaddrs[1]); setup_frm += 2; *setup_frm = cpu_to_le16(eaddrs[2]); setup_frm += 2; } /* Fill the unused entries with the broadcast address. At least one entry *must* contain the broadcast address!!!*/ for (; i < 15; i++) { *setup_frm = 0xffff; setup_frm += 2; *setup_frm = 0xffff; setup_frm += 2; *setup_frm = 0xffff; setup_frm += 2; } } /* Now add this frame to the Tx list. */ if (tp->cur_tx - tp->dirty_tx > TX_RING_SIZE - 2) { /* Same setup recently queued, we need not add it. */ /* XXX: Huh? All it means is that the Tx list is full...*/ } else { unsigned long flags; unsigned int entry; int dummy = -1; save_flags(flags); cli(); entry = tp->cur_tx++ % TX_RING_SIZE; if (entry != 0) { /* Avoid a chip errata by prefixing a dummy entry. */ tp->tx_skbuff[entry] = 0; tp->tx_ring[entry].length = (entry == TX_RING_SIZE - 1) ? Tx1RingWrap : 0; tp->tx_ring[entry].buffer1 = 0; /* race with chip, set Tx0DescOwned later */ dummy = entry; entry = tp->cur_tx++ % TX_RING_SIZE; } tp->tx_skbuff[entry] = 0; /* Put the setup frame on the Tx list. */ if (entry == TX_RING_SIZE - 1) tx_flags |= Tx1RingWrap; /* Wrap ring. */ tp->tx_ring[entry].length = tx_flags; tp->tx_ring[entry].buffer1 = virt_to_bus(tp->setup_frame); tp->tx_ring[entry].status = Tx0DescOwned; if (tp->cur_tx - tp->dirty_tx >= TX_RING_SIZE - 2) { tp->tx_full = 1; netif_stop_queue (dev); } if (dummy >= 0) tp->tx_ring[dummy].status = Tx0DescOwned; restore_flags(flags); /* Trigger an immediate transmit demand. */ outl(0, ioaddr + CSR1); }out: outl_CSR6(csr6, ioaddr);}static struct pci_device_id xircom_pci_table[] __devinitdata = { { 0x115D, 0x0003, PCI_ANY_ID, PCI_ANY_ID, 0, 0, X3201_3 }, {0},};MODULE_DEVICE_TABLE(pci, xircom_pci_table);#ifdef CONFIG_PMstatic int xircom_suspend(struct pci_dev *pdev, u32 state){ struct net_device *dev = pci_get_drvdata(pdev); struct xircom_private *tp = dev->priv; printk(KERN_INFO "xircom_suspend(%s)\n", dev->name); if (tp->open) xircom_down(dev); return 0;}static int xircom_resume(struct pci_dev *pdev){ struct net_device *dev = pci_get_drvdata(pdev); struct xircom_private *tp = dev->priv; printk(KERN_INFO "xircom_resume(%s)\n", dev->name); /* Bring the chip out of sleep mode. Caution: Snooze mode does not work with some boards! */ if (xircom_tbl[tp->chip_id].flags & HAS_ACPI) pci_write_config_dword(tp->pdev, PCI_POWERMGMT, 0); transceiver_voodoo(dev); if (xircom_tbl[tp->chip_id].flags & HAS_MII) check_duplex(dev); if (tp->open) xircom_up(dev); return 0;}#endif /* CONFIG_PM */static void __devexit xircom_remove_one(struct pci_dev *pdev){ struct net_device *dev = pci_get_drvdata(pdev); printk(KERN_INFO "xircom_remove_one(%s)\n", dev->name); unregister_netdev(dev); pci_release_regions(pdev); kfree(dev); pci_set_drvdata(pdev, NULL);}static struct pci_driver xircom_driver = { name: DRV_NAME, id_table: xircom_pci_table, probe: xircom_init_one, remove: __devexit_p(xircom_remove_one),#ifdef CONFIG_PM suspend: xircom_suspend, resume: xircom_resume#endif /* CONFIG_PM */};static int __init xircom_init(void){/* when a module, this is printed whether or not devices are found in probe */#ifdef MODULE printk(version);#endif return pci_module_init(&xircom_driver);}static void __exit xircom_exit(void){ pci_unregister_driver(&xircom_driver);}module_init(xircom_init)module_exit(xircom_exit)/* * Local variables: * c-indent-level: 4 * c-basic-offset: 4 * tab-width: 4 * End: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -