📄 winbond-840.c
字号:
skb->data[17]);#endif skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); dev->last_rx = jiffies; np->stats.rx_packets++; np->stats.rx_bytes += pkt_len; } entry = (++np->cur_rx) % RX_RING_SIZE; np->rx_head_desc = &np->rx_ring[entry]; } /* Refill the Rx ring buffers. */ for (; np->cur_rx - np->dirty_rx > 0; np->dirty_rx++) { struct sk_buff *skb; entry = np->dirty_rx % RX_RING_SIZE; if (np->rx_skbuff[entry] == NULL) { skb = dev_alloc_skb(np->rx_buf_sz); np->rx_skbuff[entry] = skb; if (skb == NULL) break; /* Better luck next round. */ skb->dev = dev; /* Mark as being used by this device. */ np->rx_addr[entry] = pci_map_single(np->pci_dev, skb->tail, skb->len, PCI_DMA_FROMDEVICE); np->rx_ring[entry].buffer1 = np->rx_addr[entry]; } wmb(); np->rx_ring[entry].status = DescOwn; } return 0;}static void netdev_error(struct net_device *dev, int intr_status){ long ioaddr = dev->base_addr; struct netdev_private *np = dev->priv; if (debug > 2) printk(KERN_DEBUG "%s: Abnormal event, %8.8x.\n", dev->name, intr_status); if (intr_status == 0xffffffff) return; spin_lock(&np->lock); if (intr_status & TxFIFOUnderflow) { int new; /* Bump up the Tx threshold */#if 0 /* This causes lots of dropped packets, * and under high load even tx_timeouts */ new = np->csr6 + 0x4000;#else new = (np->csr6 >> 14)&0x7f; if (new < 64) new *= 2; else new = 127; /* load full packet before starting */ new = (np->csr6 & ~(0x7F << 14)) | (new<<14);#endif printk(KERN_DEBUG "%s: Tx underflow, new csr6 %8.8x.\n", dev->name, new); update_csr6(dev, new); } if (intr_status & IntrRxDied) { /* Missed a Rx frame. */ np->stats.rx_errors++; } if (intr_status & TimerInt) { /* Re-enable other interrupts. */ if (netif_device_present(dev)) writel(0x1A0F5, ioaddr + IntrEnable); } np->stats.rx_missed_errors += readl(ioaddr + RxMissed) & 0xffff; writel(0, ioaddr + RxStartDemand); spin_unlock(&np->lock);}static struct net_device_stats *get_stats(struct net_device *dev){ long ioaddr = dev->base_addr; struct netdev_private *np = dev->priv; /* The chip only need report frame silently dropped. */ spin_lock_irq(&np->lock); if (netif_running(dev) && netif_device_present(dev)) np->stats.rx_missed_errors += readl(ioaddr + RxMissed) & 0xffff; spin_unlock_irq(&np->lock); return &np->stats;}static u32 __set_rx_mode(struct net_device *dev){ long ioaddr = dev->base_addr; u32 mc_filter[2]; /* Multicast hash filter */ u32 rx_mode; if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ /* Unconditionally log net taps. */ printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n", dev->name); memset(mc_filter, 0xff, sizeof(mc_filter)); rx_mode = AcceptBroadcast | AcceptMulticast | AcceptAllPhys | AcceptMyPhys; } else if ((dev->mc_count > multicast_filter_limit) || (dev->flags & IFF_ALLMULTI)) { /* Too many to match, or accept all multicasts. */ memset(mc_filter, 0xff, sizeof(mc_filter)); rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys; } else { struct dev_mc_list *mclist; int i; 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(ETH_ALEN, mclist->dmi_addr) >> 26) ^ 0x3F, mc_filter); } rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys; } writel(mc_filter[0], ioaddr + MulticastFilter0); writel(mc_filter[1], ioaddr + MulticastFilter1); return rx_mode;}static void set_rx_mode(struct net_device *dev){ struct netdev_private *np = dev->priv; u32 rx_mode = __set_rx_mode(dev); spin_lock_irq(&np->lock); update_csr6(dev, (np->csr6 & ~0x00F8) | rx_mode); spin_unlock_irq(&np->lock);}static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr){ struct netdev_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_if, &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_if, &ecmd); spin_unlock_irq(&np->lock); return r; } /* restart autonegotiation */ case ETHTOOL_NWAY_RST: { return mii_nway_restart(&np->mii_if); } /* get link status */ case ETHTOOL_GLINK: { struct ethtool_value edata = {ETHTOOL_GLINK}; edata.data = mii_link_ok(&np->mii_if); 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; } } return -EOPNOTSUPP;}static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd){ struct mii_ioctl_data *data = (struct mii_ioctl_data *)&rq->ifr_data; struct netdev_private *np = dev->priv; switch(cmd) { case SIOCETHTOOL: return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data); case SIOCGMIIPHY: /* Get address of MII PHY in use. */ data->phy_id = ((struct netdev_private *)dev->priv)->phys[0] & 0x1f; /* Fall Through */ case SIOCGMIIREG: /* Read MII PHY register. */ spin_lock_irq(&np->lock); data->val_out = mdio_read(dev, data->phy_id & 0x1f, data->reg_num & 0x1f); spin_unlock_irq(&np->lock); return 0; case SIOCSMIIREG: /* Write MII PHY register. */ if (!capable(CAP_NET_ADMIN)) return -EPERM; spin_lock_irq(&np->lock); mdio_write(dev, data->phy_id & 0x1f, data->reg_num & 0x1f, data->val_in); spin_unlock_irq(&np->lock); return 0; default: return -EOPNOTSUPP; }}static int netdev_close(struct net_device *dev){ long ioaddr = dev->base_addr; struct netdev_private *np = dev->priv; netif_stop_queue(dev); if (debug > 1) { printk(KERN_DEBUG "%s: Shutting down ethercard, status was %8.8x " "Config %8.8x.\n", dev->name, (int)readl(ioaddr + IntrStatus), (int)readl(ioaddr + NetworkConfig)); 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); } /* Stop the chip's Tx and Rx processes. */ spin_lock_irq(&np->lock); netif_device_detach(dev); update_csr6(dev, 0); writel(0x0000, ioaddr + IntrEnable); spin_unlock_irq(&np->lock); free_irq(dev->irq, dev); wmb(); netif_device_attach(dev); if (readl(ioaddr + NetworkConfig) != 0xffffffff) np->stats.rx_missed_errors += readl(ioaddr + RxMissed) & 0xffff;#ifdef __i386__ if (debug > 2) { int i; printk("\n"KERN_DEBUG" Tx ring at %8.8x:\n", (int)np->tx_ring); for (i = 0; i < TX_RING_SIZE; i++) printk(" #%d desc. %4.4x %4.4x %8.8x.\n", i, np->tx_ring[i].length, np->tx_ring[i].status, np->tx_ring[i].buffer1); printk("\n"KERN_DEBUG " Rx ring %8.8x:\n", (int)np->rx_ring); for (i = 0; i < RX_RING_SIZE; i++) { printk(KERN_DEBUG " #%d desc. %4.4x %4.4x %8.8x\n", i, np->rx_ring[i].length, np->rx_ring[i].status, np->rx_ring[i].buffer1); } }#endif /* __i386__ debugging only */ del_timer_sync(&np->timer); free_rxtx_rings(np); free_ringdesc(np); return 0;}static void __devexit w840_remove1 (struct pci_dev *pdev){ struct net_device *dev = pci_get_drvdata(pdev); /* No need to check MOD_IN_USE, as sys_delete_module() checks. */ if (dev) { unregister_netdev(dev); pci_release_regions(pdev);#ifndef USE_IO_OPS iounmap((char *)(dev->base_addr));#endif kfree(dev); } pci_set_drvdata(pdev, NULL);}#ifdef CONFIG_PM/* * suspend/resume synchronization: * - open, close, do_ioctl: * rtnl_lock, & netif_device_detach after the rtnl_unlock. * - get_stats: * spin_lock_irq(np->lock), doesn't touch hw if not present * - hard_start_xmit: * netif_stop_queue + spin_unlock_wait(&dev->xmit_lock); * - tx_timeout: * netif_device_detach + spin_unlock_wait(&dev->xmit_lock); * - set_multicast_list * netif_device_detach + spin_unlock_wait(&dev->xmit_lock); * - interrupt handler * doesn't touch hw if not present, synchronize_irq waits for * running instances of the interrupt handler. * * Disabling hw requires clearing csr6 & IntrEnable. * update_csr6 & all function that write IntrEnable check netif_device_present * before settings any bits. * * Detach must occur under spin_unlock_irq(), interrupts from a detached * device would cause an irq storm. */static int w840_suspend (struct pci_dev *pdev, u32 state){ struct net_device *dev = pci_get_drvdata (pdev); struct netdev_private *np = dev->priv; long ioaddr = dev->base_addr; rtnl_lock(); if (netif_running (dev)) { del_timer_sync(&np->timer); spin_lock_irq(&np->lock); netif_device_detach(dev); update_csr6(dev, 0); writel(0, ioaddr + IntrEnable); netif_stop_queue(dev); spin_unlock_irq(&np->lock); spin_unlock_wait(&dev->xmit_lock); synchronize_irq(); np->stats.rx_missed_errors += readl(ioaddr + RxMissed) & 0xffff; /* no more hardware accesses behind this line. */ if (np->csr6) BUG(); if (readl(ioaddr + IntrEnable)) BUG(); /* pci_power_off(pdev, -1); */ free_rxtx_rings(np); } else { netif_device_detach(dev); } rtnl_unlock(); return 0;}static int w840_resume (struct pci_dev *pdev){ struct net_device *dev = pci_get_drvdata (pdev); struct netdev_private *np = dev->priv; rtnl_lock(); if (netif_device_present(dev)) goto out; /* device not suspended */ if (netif_running(dev)) { pci_enable_device(pdev); /* pci_power_on(pdev); */ spin_lock_irq(&np->lock); writel(1, dev->base_addr+PCIBusCfg); readl(dev->base_addr+PCIBusCfg); udelay(1); netif_device_attach(dev); init_rxtx_rings(dev); init_registers(dev); spin_unlock_irq(&np->lock); netif_wake_queue(dev); np->timer.expires = jiffies + 1*HZ; add_timer(&np->timer); } else { netif_device_attach(dev); }out: rtnl_unlock(); return 0;}#endifstatic struct pci_driver w840_driver = { name: DRV_NAME, id_table: w840_pci_tbl, probe: w840_probe1, remove: __devexit_p(w840_remove1),#ifdef CONFIG_PM suspend: w840_suspend, resume: w840_resume,#endif};static int __init w840_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(&w840_driver);}static void __exit w840_exit(void){ pci_unregister_driver(&w840_driver);}module_init(w840_init);module_exit(w840_exit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -