📄 xircom_tulip_cb.c
字号:
if (inl(ioaddr + CSR6) != 0xffffffff) tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff; dev->if_port = tp->saved_if_port;}static intxircom_close(struct net_device *dev){ long ioaddr = dev->base_addr; struct xircom_private *tp = netdev_priv(dev); int i; if (xircom_debug > 1) printk(KERN_DEBUG "%s: Shutting down ethercard, status was %2.2x.\n", dev->name, inl(ioaddr + CSR5)); netif_stop_queue(dev); if (netif_device_present(dev)) xircom_down(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 = tp->rx_skbuff[i]; tp->rx_skbuff[i] = NULL; tp->rx_ring[i].status = 0; /* Not owned by Xircom chip. */ tp->rx_ring[i].length = 0; tp->rx_ring[i].buffer1 = 0xBADF00D0; /* An invalid address. */ if (skb) { dev_kfree_skb(skb); } } for (i = 0; i < TX_RING_SIZE; i++) { if (tp->tx_skbuff[i]) dev_kfree_skb(tp->tx_skbuff[i]); tp->tx_skbuff[i] = NULL; } tp->open = 0; return 0;}static struct net_device_stats *xircom_get_stats(struct net_device *dev){ struct xircom_private *tp = netdev_priv(dev); 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_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd){ struct xircom_private *tp = netdev_priv(dev); 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; return 0;}static int xircom_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd){ struct xircom_private *tp = netdev_priv(dev); 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;}static void xircom_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info){ struct xircom_private *tp = netdev_priv(dev); strcpy(info->driver, DRV_NAME); strcpy(info->version, DRV_VERSION); strcpy(info->bus_info, pci_name(tp->pdev));}static struct ethtool_ops ops = { .get_settings = xircom_get_settings, .set_settings = xircom_set_settings, .get_drvinfo = xircom_get_drvinfo,};/* 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 = netdev_priv(dev); u16 *data = (u16 *)&rq->ifr_ifru; int phy = tp->phys[0] & 0x1f; unsigned long flags; switch(cmd) { /* Legacy mii-diag interface */ case SIOCGMIIPHY: /* Get address of MII PHY in use. */ if (tp->mii_cnt) data[0] = phy; else return -ENODEV; return 0; case SIOCGMIIREG: /* Read MII PHY register. */ 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. */ 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;}/* 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 = netdev_priv(dev); 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] = NULL; 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] = NULL; /* 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[] = { { 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, pm_message_t state){ struct net_device *dev = pci_get_drvdata(pdev); struct xircom_private *tp = netdev_priv(dev); printk(KERN_INFO "xircom_suspend(%s)\n", dev->name); if (tp->open) xircom_down(dev); pci_save_state(pdev); pci_disable_device(pdev); pci_set_power_state(pdev, 3); return 0;}static int xircom_resume(struct pci_dev *pdev){ struct net_device *dev = pci_get_drvdata(pdev); struct xircom_private *tp = netdev_priv(dev); printk(KERN_INFO "xircom_resume(%s)\n", dev->name); pci_set_power_state(pdev,0); pci_enable_device(pdev); pci_restore_state(pdev); /* 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); free_netdev(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 + -