📄 starfire.c
字号:
} else crc >>= 1; } } return crc;}static void set_rx_mode(struct net_device *dev){ long ioaddr = dev->base_addr; u32 rx_mode; struct dev_mc_list *mclist; int i; if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ rx_mode = AcceptBroadcast|AcceptAllMulticast|AcceptAll|AcceptMyPhys; } else if ((dev->mc_count > multicast_filter_limit) || (dev->flags & IFF_ALLMULTI)) { /* Too many to match, or accept all multicasts. */ rx_mode = AcceptBroadcast|AcceptAllMulticast|AcceptMyPhys; } else if (dev->mc_count <= 15) { /* Use the 16 element perfect filter, skip first entry. */ long filter_addr = ioaddr + PerfFilterTable + 1 * 16; for (i = 1, mclist = dev->mc_list; mclist && i <= dev->mc_count; i++, mclist = mclist->next) { u16 *eaddrs = (u16 *)mclist->dmi_addr; writew(cpu_to_be16(eaddrs[2]), filter_addr); filter_addr += 4; writew(cpu_to_be16(eaddrs[1]), filter_addr); filter_addr += 4; writew(cpu_to_be16(eaddrs[0]), filter_addr); filter_addr += 8; } while (i++ < 16) { writew(0xffff, filter_addr); filter_addr += 4; writew(0xffff, filter_addr); filter_addr += 4; writew(0xffff, filter_addr); filter_addr += 8; } rx_mode = AcceptBroadcast | AcceptMyPhys; } else { /* Must use a multicast hash table. */ long filter_addr; u16 mc_filter[32] __attribute__ ((aligned(sizeof(long)))); /* Multicast hash filter */ memset(mc_filter, 0, sizeof(mc_filter)); for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; i++, mclist = mclist->next) { int bit_nr = ether_crc_le(ETH_ALEN, mclist->dmi_addr) >> 23; __u32 *fptr = (__u32 *) &mc_filter[(bit_nr >> 4) & ~1]; *fptr |= cpu_to_le32(1 << (bit_nr & 31)); } /* Clear the perfect filter list, skip first entry. */ filter_addr = ioaddr + PerfFilterTable + 1 * 16; for (i = 1; i < 16; i++) { writew(0xffff, filter_addr); filter_addr += 4; writew(0xffff, filter_addr); filter_addr += 4; writew(0xffff, filter_addr); filter_addr += 8; } for (filter_addr = ioaddr + HashTable, i=0; i < 32; filter_addr+= 16, i++) writew(mc_filter[i], filter_addr); rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys; } writel(rx_mode, ioaddr + RxFilterMode);}static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr){ struct ethtool_cmd ecmd; struct netdev_private *np = 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 (np->advertising & ADVERTISE_10HALF) ecmd.advertising |= ADVERTISED_10baseT_Half; if (np->advertising & ADVERTISE_10FULL) ecmd.advertising |= ADVERTISED_10baseT_Full; if (np->advertising & ADVERTISE_100HALF) ecmd.advertising |= ADVERTISED_100baseT_Half; if (np->advertising & ADVERTISE_100FULL) ecmd.advertising |= ADVERTISED_100baseT_Full; if (np->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 = np->phys[0]; ecmd.speed = np->speed100 ? SPEED_100 : SPEED_10; ecmd.duplex = np->full_duplex ? DUPLEX_FULL : DUPLEX_HALF; ecmd.maxtxpkt = TX_RING_SIZE; ecmd.maxrxpkt = np->intr_mitigation; /* not 100% accurate */ 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); np->autoneg = autoneg; if (speed100 != np->speed100 || full_duplex != np->full_duplex) { np->speed100 = speed100; np->full_duplex = full_duplex; /* change advertising bits */ np->advertising &= ~(ADVERTISE_10HALF | ADVERTISE_10FULL | ADVERTISE_100HALF | ADVERTISE_100FULL | ADVERTISE_100BASE4); if (speed100) { if (full_duplex) np->advertising |= ADVERTISE_100FULL; else np->advertising |= ADVERTISE_100HALF; } else { if (full_duplex) np->advertising |= ADVERTISE_10FULL; else np->advertising |= 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, PCI_SLOT_NAME(np->pci_dev)); if (copy_to_user(useraddr, &info, sizeof(info))) return -EFAULT; return 0; } /* restart autonegotiation */ case ETHTOOL_NWAY_RST: { int tmp; int r = -EINVAL; /* if autoneg is off, it's an error */ tmp = mdio_read(dev, np->phys[0], MII_BMCR); if (tmp & BMCR_ANENABLE) { tmp |= (BMCR_ANRESTART); mdio_write(dev, np->phys[0], MII_BMCR, tmp); r = 0; } return r; } /* get link status */ case ETHTOOL_GLINK: { struct ethtool_value edata = {ETHTOOL_GLINK}; if (mdio_read(dev, np->phys[0], MII_BMSR) & BMSR_LSTATUS) edata.data = 1; else edata.data = 0; 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: return -EOPNOTSUPP; }}static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd){ struct netdev_private *np = dev->priv; 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); /* Legacy mii-diag interface */ case SIOCGMIIPHY: /* Get address of MII PHY in use. */ case SIOCDEVPRIVATE: /* for binary compat, remove in 2.5 */ data->phy_id = np->phys[0] & 0x1f; /* Fall Through */ case SIOCGMIIREG: /* Read MII PHY register. */ case SIOCDEVPRIVATE+1: /* for binary compat, remove in 2.5 */ data->val_out = mdio_read(dev, data->phy_id & 0x1f, data->reg_num & 0x1f); 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 (data->phy_id == np->phys[0]) { u16 value = data->val_in; switch (data->reg_num) { case 0: if (value & (BMCR_RESET | BMCR_ANENABLE)) /* Autonegotiation. */ np->autoneg = 1; else { np->full_duplex = (value & BMCR_FULLDPLX) ? 1 : 0; np->autoneg = 0; } break; case 4: np->advertising = value; break; } check_duplex(dev); } mdio_write(dev, data->phy_id & 0x1f, data->reg_num & 0x1f, data->val_in); return 0; default: return -EOPNOTSUPP; }}static int netdev_close(struct net_device *dev){ long ioaddr = dev->base_addr; struct netdev_private *np = dev->priv; int i; netif_stop_queue(dev); netif_stop_if(dev); if (debug > 1) { printk(KERN_DEBUG "%s: Shutting down ethercard, Intr status %4.4x.\n", dev->name, (int)readl(ioaddr + IntrStatus)); printk(KERN_DEBUG "%s: Queue pointers were Tx %d / %d, Rx %d / %d.\n", dev->name, np->cur_tx, np->dirty_tx, np->cur_rx, np->dirty_rx); } /* Disable interrupts by clearing the interrupt mask. */ writel(0, ioaddr + IntrEnable); /* Stop the chip's Tx and Rx processes. */#ifdef __i386__ if (debug > 2) { printk("\n"KERN_DEBUG" Tx ring at %8.8x:\n", np->tx_ring_dma); for (i = 0; i < 8 /* TX_RING_SIZE is huge! */; i++) printk(KERN_DEBUG " #%d desc. %8.8x %8.8x -> %8.8x.\n", i, le32_to_cpu(np->tx_ring[i].status), le32_to_cpu(np->tx_ring[i].first_addr), le32_to_cpu(np->tx_done_q[i].status)); printk(KERN_DEBUG " Rx ring at %8.8x -> %p:\n", np->rx_ring_dma, np->rx_done_q); if (np->rx_done_q) for (i = 0; i < 8 /* RX_RING_SIZE */; i++) { printk(KERN_DEBUG " #%d desc. %8.8x -> %8.8x\n", i, le32_to_cpu(np->rx_ring[i].rxaddr), le32_to_cpu(np->rx_done_q[i].status)); } }#endif /* __i386__ debugging only */ free_irq(dev->irq, dev); /* Free all the skbuffs in the Rx queue. */ for (i = 0; i < RX_RING_SIZE; i++) { np->rx_ring[i].rxaddr = cpu_to_le32(0xBADF00D0); /* An invalid address. */ if (np->rx_info[i].skb != NULL) { pci_unmap_single(np->pci_dev, np->rx_info[i].mapping, np->rx_buf_sz, PCI_DMA_FROMDEVICE); dev_kfree_skb(np->rx_info[i].skb); } np->rx_info[i].skb = NULL; np->rx_info[i].mapping = 0; } for (i = 0; i < TX_RING_SIZE; i++) { struct sk_buff *skb = np->tx_info[i].skb;#ifdef ZEROCOPY int j;#endif /* ZEROCOPY */ if (skb == NULL) continue; pci_unmap_single(np->pci_dev, np->tx_info[i].first_mapping, skb_first_frag_len(skb), PCI_DMA_TODEVICE); np->tx_info[i].first_mapping = 0; dev_kfree_skb(skb); np->tx_info[i].skb = NULL;#ifdef ZEROCOPY for (j = 0; j < MAX_STARFIRE_FRAGS; j++) if (np->tx_info[i].frag_mapping[j]) { pci_unmap_single(np->pci_dev, np->tx_info[i].frag_mapping[j], skb_shinfo(skb)->frags[j].size, PCI_DMA_TODEVICE); np->tx_info[i].frag_mapping[j] = 0; } else break;#endif /* ZEROCOPY */ } COMPAT_MOD_DEC_USE_COUNT; return 0;}static void __devexit starfire_remove_one (struct pci_dev *pdev){ struct net_device *dev = pci_get_drvdata(pdev); struct netdev_private *np; if (!dev) BUG(); np = dev->priv; if (np->tx_done_q) pci_free_consistent(pdev, PAGE_SIZE, np->tx_done_q, np->tx_done_q_dma); if (np->rx_done_q) pci_free_consistent(pdev, sizeof(struct rx_done_desc) * DONE_Q_SIZE, np->rx_done_q, np->rx_done_q_dma); if (np->tx_ring) pci_free_consistent(pdev, PAGE_SIZE, np->tx_ring, np->tx_ring_dma); if (np->rx_ring) pci_free_consistent(pdev, PAGE_SIZE, np->rx_ring, np->rx_ring_dma); unregister_netdev(dev); iounmap((char *)dev->base_addr); pci_release_regions(pdev); pci_set_drvdata(pdev, NULL); kfree(dev); /* Will also free np!! */}static struct pci_driver starfire_driver = { name: DRV_NAME, probe: starfire_init_one, remove: __devexit_p(starfire_remove_one), id_table: starfire_pci_tbl,};static int __init starfire_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 (&starfire_driver);}static void __exit starfire_cleanup (void){ pci_unregister_driver (&starfire_driver);}module_init(starfire_init);module_exit(starfire_cleanup);/* * Local variables: * compile-command: "gcc -DMODULE -Wall -Wstrict-prototypes -O2 -c starfire.c" * simple-compile-command: "gcc -DMODULE -O2 -c starfire.c" * c-basic-offset: 8 * tab-width: 8 * End: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -