📄 8139cp.c
字号:
pci_unmap_single(cp->pdev, cp->rx_skb[i].mapping, cp->rx_buf_sz, PCI_DMA_FROMDEVICE); dev_kfree_skb(cp->rx_skb[i].skb); } } for (i = 0; i < CP_TX_RING_SIZE; i++) { if (cp->tx_skb[i].skb) { struct sk_buff *skb = cp->tx_skb[i].skb; pci_unmap_single(cp->pdev, cp->tx_skb[i].mapping, skb->len, PCI_DMA_TODEVICE); dev_kfree_skb(skb); cp->net_stats.tx_dropped++; } } memset(&cp->rx_skb, 0, sizeof(struct ring_info) * CP_RX_RING_SIZE); memset(&cp->tx_skb, 0, sizeof(struct ring_info) * CP_TX_RING_SIZE);}static void cp_free_rings (struct cp_private *cp){ cp_clean_rings(cp); pci_free_consistent(cp->pdev, CP_RING_BYTES, cp->rx_ring, cp->ring_dma); cp->rx_ring = NULL; cp->tx_ring = NULL;}static int cp_open (struct net_device *dev){ struct cp_private *cp = dev->priv; int rc; if (netif_msg_ifup(cp)) printk(KERN_DEBUG "%s: enabling interface\n", dev->name); cp->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32); rc = cp_alloc_rings(cp); if (rc) return rc; cp_init_hw(cp); rc = request_irq(dev->irq, cp_interrupt, SA_SHIRQ, dev->name, dev); if (rc) goto err_out_hw; netif_start_queue(dev); return 0;err_out_hw: cp_stop_hw(cp); cp_free_rings(cp); return rc;}static int cp_close (struct net_device *dev){ struct cp_private *cp = dev->priv; if (netif_msg_ifdown(cp)) printk(KERN_DEBUG "%s: disabling interface\n", dev->name); netif_stop_queue(dev); cp_stop_hw(cp); free_irq(dev->irq, dev); cp_free_rings(cp); return 0;}static char mii_2_8139_map[8] = { BasicModeCtrl, BasicModeStatus, 0, 0, NWayAdvert, NWayLPAR, NWayExpansion, 0};static int mdio_read(struct net_device *dev, int phy_id, int location){ struct cp_private *cp = dev->priv; return location < 8 && mii_2_8139_map[location] ? readw(cp->regs + mii_2_8139_map[location]) : 0;}static void mdio_write(struct net_device *dev, int phy_id, int location, int value){ struct cp_private *cp = dev->priv; if (location == 0) { cpw8(Cfg9346, Cfg9346_Unlock); cpw16(BasicModeCtrl, value); cpw8(Cfg9346, Cfg9346_Lock); } else if (location < 8 && mii_2_8139_map[location]) cpw16(mii_2_8139_map[location], value);}static int cp_ethtool_ioctl (struct cp_private *cp, void *useraddr){ u32 ethcmd; /* dev_ioctl() in ../../net/core/dev.c has already checked capable(CAP_NET_ADMIN), so don't bother with that here. */ if (get_user(ethcmd, (u32 *)useraddr)) 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, cp->pdev->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(&cp->lock); mii_ethtool_gset(&cp->mii_if, &ecmd); spin_unlock_irq(&cp->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(&cp->lock); r = mii_ethtool_sset(&cp->mii_if, &ecmd); spin_unlock_irq(&cp->lock); return r; } /* restart autonegotiation */ case ETHTOOL_NWAY_RST: { return mii_nway_restart(&cp->mii_if); } /* get link status */ case ETHTOOL_GLINK: { struct ethtool_value edata = {ETHTOOL_GLINK}; edata.data = mii_link_ok(&cp->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 = cp->msg_enable; 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; cp->msg_enable = edata.data; return 0; } default: break; } return -EOPNOTSUPP;}static int cp_ioctl (struct net_device *dev, struct ifreq *rq, int cmd){ struct cp_private *cp = dev->priv; int rc = 0; if (!netif_running(dev)) return -EINVAL; switch (cmd) { case SIOCETHTOOL: return cp_ethtool_ioctl(cp, (void *) rq->ifr_data); default: rc = -EOPNOTSUPP; break; } return rc;}/* Serial EEPROM section. *//* EEPROM_Ctrl bits. */#define EE_SHIFT_CLK 0x04 /* EEPROM shift clock. */#define EE_CS 0x08 /* EEPROM chip select. */#define EE_DATA_WRITE 0x02 /* EEPROM chip data in. */#define EE_WRITE_0 0x00#define EE_WRITE_1 0x02#define EE_DATA_READ 0x01 /* EEPROM chip data out. */#define EE_ENB (0x80 | EE_CS)/* Delay between EEPROM clock transitions. No extra delay is needed with 33Mhz PCI, but 66Mhz may change this. */#define eeprom_delay() readl(ee_addr)/* The EEPROM commands include the alway-set leading bit. */#define EE_WRITE_CMD (5)#define EE_READ_CMD (6)#define EE_ERASE_CMD (7)static int __devinit read_eeprom (void *ioaddr, int location, int addr_len){ int i; unsigned retval = 0; void *ee_addr = ioaddr + Cfg9346; int read_cmd = location | (EE_READ_CMD << addr_len); writeb (EE_ENB & ~EE_CS, ee_addr); writeb (EE_ENB, ee_addr); eeprom_delay (); /* Shift the read command bits out. */ for (i = 4 + addr_len; i >= 0; i--) { int dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0; writeb (EE_ENB | dataval, ee_addr); eeprom_delay (); writeb (EE_ENB | dataval | EE_SHIFT_CLK, ee_addr); eeprom_delay (); } writeb (EE_ENB, ee_addr); eeprom_delay (); for (i = 16; i > 0; i--) { writeb (EE_ENB | EE_SHIFT_CLK, ee_addr); eeprom_delay (); retval = (retval << 1) | ((readb (ee_addr) & EE_DATA_READ) ? 1 : 0); writeb (EE_ENB, ee_addr); eeprom_delay (); } /* Terminate the EEPROM access. */ writeb (~EE_CS, ee_addr); eeprom_delay (); return retval;}static int __devinit cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent){ struct net_device *dev; struct cp_private *cp; int rc; void *regs; long pciaddr; unsigned addr_len, i; u8 pci_rev, cache_size; u16 pci_command;#ifndef MODULE static int version_printed; if (version_printed++ == 0) printk("%s", version);#endif pci_read_config_byte(pdev, PCI_REVISION_ID, &pci_rev); if (pdev->vendor == PCI_VENDOR_ID_REALTEK && pdev->device == PCI_DEVICE_ID_REALTEK_8139 && pci_rev < 0x20) { printk(KERN_ERR PFX "pci dev %s (id %04x:%04x rev %02x) is not an 8139C+ compatible chip\n", pdev->slot_name, pdev->vendor, pdev->device, pci_rev); printk(KERN_ERR PFX "Try the \"8139too\" driver instead.\n"); return -ENODEV; } dev = alloc_etherdev(sizeof(struct cp_private)); if (!dev) return -ENOMEM; SET_MODULE_OWNER(dev); cp = dev->priv; cp->pdev = pdev; cp->dev = dev; cp->msg_enable = (debug < 0 ? CP_DEF_MSG_ENABLE : debug); spin_lock_init (&cp->lock); cp->mii_if.dev = dev; cp->mii_if.mdio_read = mdio_read; cp->mii_if.mdio_write = mdio_write; cp->mii_if.phy_id = CP_INTERNAL_PHY; rc = pci_enable_device(pdev); if (rc) goto err_out_free; rc = pci_request_regions(pdev, DRV_NAME); if (rc) goto err_out_disable; if (pdev->irq < 2) { rc = -EIO; printk(KERN_ERR PFX "invalid irq (%d) for pci dev %s\n", pdev->irq, pdev->slot_name); goto err_out_res; } pciaddr = pci_resource_start(pdev, 1); if (!pciaddr) { rc = -EIO; printk(KERN_ERR PFX "no MMIO resource for pci dev %s\n", pdev->slot_name); goto err_out_res; } if (pci_resource_len(pdev, 1) < CP_REGS_SIZE) { rc = -EIO; printk(KERN_ERR PFX "MMIO resource (%lx) too small on pci dev %s\n", pci_resource_len(pdev, 1), pdev->slot_name); goto err_out_res; } regs = ioremap_nocache(pciaddr, CP_REGS_SIZE); if (!regs) { rc = -EIO; printk(KERN_ERR PFX "Cannot map PCI MMIO (%lx@%lx) on pci dev %s\n", pci_resource_len(pdev, 1), pciaddr, pdev->slot_name); goto err_out_res; } dev->base_addr = (unsigned long) regs; cp->regs = regs; cp_stop_hw(cp); /* read MAC address from EEPROM */ addr_len = read_eeprom (regs, 0, 8) == 0x8129 ? 8 : 6; for (i = 0; i < 3; i++) ((u16 *) (dev->dev_addr))[i] = le16_to_cpu (read_eeprom (regs, i + 7, addr_len)); dev->open = cp_open; dev->stop = cp_close; dev->set_multicast_list = cp_set_rx_mode; dev->hard_start_xmit = cp_start_xmit; dev->get_stats = cp_get_stats; dev->do_ioctl = cp_ioctl;#if 0 dev->tx_timeout = cp_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT;#endif#ifdef CP_TX_CHECKSUM dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM;#endif dev->irq = pdev->irq; rc = register_netdev(dev); if (rc) goto err_out_iomap; printk (KERN_INFO "%s: %s at 0x%lx, " "%02x:%02x:%02x:%02x:%02x:%02x, " "IRQ %d\n", dev->name, "RTL-8139C+", dev->base_addr, dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5], dev->irq); pci_set_drvdata(pdev, dev); /* * Looks like this is necessary to deal with on all architectures, * even this %$#%$# N440BX Intel based thing doesn't get it right. * Ie. having two NICs in the machine, one will have the cache * line set at boot time, the other will not. */ pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &cache_size); cache_size <<= 2; if (cache_size != SMP_CACHE_BYTES) { printk(KERN_INFO "%s: PCI cache line size set incorrectly " "(%i bytes) by BIOS/FW, ", dev->name, cache_size); if (cache_size > SMP_CACHE_BYTES) printk("expecting %i\n", SMP_CACHE_BYTES); else { printk("correcting to %i\n", SMP_CACHE_BYTES); pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, SMP_CACHE_BYTES >> 2); } } /* enable busmastering and memory-write-invalidate */ pci_read_config_word(pdev, PCI_COMMAND, &pci_command); if (!(pci_command & PCI_COMMAND_INVALIDATE)) { pci_command |= PCI_COMMAND_INVALIDATE; pci_write_config_word(pdev, PCI_COMMAND, pci_command); } pci_set_master(pdev); return 0;err_out_iomap: iounmap(regs);err_out_res: pci_release_regions(pdev);err_out_disable: pci_disable_device(pdev);err_out_free: kfree(dev); return rc;}static void __devexit cp_remove_one (struct pci_dev *pdev){ struct net_device *dev = pci_get_drvdata(pdev); struct cp_private *cp = dev->priv; if (!dev) BUG(); unregister_netdev(dev); iounmap(cp->regs); pci_release_regions(pdev); pci_disable_device(pdev); pci_set_drvdata(pdev, NULL); kfree(dev);}static struct pci_driver cp_driver = { name: DRV_NAME, id_table: cp_pci_tbl, probe: cp_init_one, remove: __devexit_p(cp_remove_one),};static int __init cp_init (void){#ifdef MODULE printk("%s", version);#endif return pci_module_init (&cp_driver);}static void __exit cp_exit (void){ pci_unregister_driver (&cp_driver);}module_init(cp_init);module_exit(cp_exit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -