📄 winbond-840.c
字号:
if (debug > 5) printk(KERN_DEBUG " Rx data %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:" "%2.2x %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x %2.2x%2.2x " "%d.%d.%d.%d.\n", skb->data[0], skb->data[1], skb->data[2], skb->data[3], skb->data[4], skb->data[5], skb->data[6], skb->data[7], skb->data[8], skb->data[9], skb->data[10], skb->data[11], skb->data[12], skb->data[13], skb->data[14], skb->data[15], skb->data[16], 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) { int filterbit = (ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26) ^ 0x3F; filterbit &= 0x3f; mc_filter[filterbit >> 5] |= cpu_to_le32(1 << (filterbit & 31)); } 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 void netdev_get_drvinfo (struct net_device *dev, struct ethtool_drvinfo *info){ struct netdev_private *np = dev->priv; strcpy (info->driver, DRV_NAME); strcpy (info->version, DRV_VERSION); strcpy (info->bus_info, pci_name(np->pci_dev));}static int netdev_get_settings(struct net_device *dev, struct ethtool_cmd *cmd){ struct netdev_private *np = dev->priv; int rc; spin_lock_irq(&np->lock); rc = mii_ethtool_gset(&np->mii_if, cmd); spin_unlock_irq(&np->lock); return rc;}static int netdev_set_settings(struct net_device *dev, struct ethtool_cmd *cmd){ struct netdev_private *np = dev->priv; int rc; spin_lock_irq(&np->lock); rc = mii_ethtool_sset(&np->mii_if, cmd); spin_unlock_irq(&np->lock); return rc;}static int netdev_nway_reset(struct net_device *dev){ struct netdev_private *np = dev->priv; return mii_nway_restart(&np->mii_if);}static u32 netdev_get_link(struct net_device *dev){ struct netdev_private *np = dev->priv; return mii_link_ok(&np->mii_if);}static u32 netdev_get_msglevel(struct net_device *dev){ return debug;}static void netdev_set_msglevel(struct net_device *dev, u32 value){ debug = value;}static struct ethtool_ops netdev_ethtool_ops = { .get_drvinfo = netdev_get_drvinfo, .get_settings = netdev_get_settings, .set_settings = netdev_set_settings, .nway_reset = netdev_nway_reset, .get_link = netdev_get_link, .get_msglevel = netdev_get_msglevel, .set_msglevel = netdev_set_msglevel, .get_sg = ethtool_op_get_sg, .get_tx_csum = ethtool_op_get_tx_csum,};static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd){ struct mii_ioctl_data *data = if_mii(rq); struct netdev_private *np = netdev_priv(dev); switch(cmd) { 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(KERN_DEBUG" Tx ring at %8.8x:\n", (int)np->tx_ring); for (i = 0; i < TX_RING_SIZE; i++) printk(KERN_DEBUG " #%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); if (dev) { unregister_netdev(dev); pci_release_regions(pdev);#ifndef USE_IO_OPS iounmap((char *)(dev->base_addr));#endif free_netdev(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(dev->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); mod_timer(&np->timer, jiffies + 1*HZ); } 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){ printk(version); 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 + -