📄 forcedeth.c
字号:
writel(0, base + NvRegTransmitterControl); writel(0, base + NvRegReceiverControl); writel(0, base + NvRegAdapterControl); /* 2) initialize descriptor rings */ oom = nv_init_ring(dev); writel(0, base + NvRegLinkSpeed); writel(0, base + NvRegUnknownTransmitterReg); nv_txrx_reset(dev); writel(0, base + NvRegUnknownSetupReg6); np->in_shutdown = 0; /* 3) set mac address */ { u32 mac[2]; mac[0] = (dev->dev_addr[0] << 0) + (dev->dev_addr[1] << 8) + (dev->dev_addr[2] << 16) + (dev->dev_addr[3] << 24); mac[1] = (dev->dev_addr[4] << 0) + (dev->dev_addr[5] << 8); writel(mac[0], base + NvRegMacAddrA); writel(mac[1], base + NvRegMacAddrB); } /* 4) give hw rings */ writel((u32) np->ring_addr, base + NvRegRxRingPhysAddr); writel((u32) (np->ring_addr + RX_RING*sizeof(struct ring_desc)), base + NvRegTxRingPhysAddr); writel( ((RX_RING-1) << NVREG_RINGSZ_RXSHIFT) + ((TX_RING-1) << NVREG_RINGSZ_TXSHIFT), base + NvRegRingSizes); /* 5) continue setup */ np->linkspeed = NVREG_LINKSPEED_FORCE|NVREG_LINKSPEED_10; np->duplex = 0; writel(np->linkspeed, base + NvRegLinkSpeed); writel(NVREG_UNKSETUP3_VAL1, base + NvRegUnknownSetupReg3); writel(np->desc_ver, base + NvRegTxRxControl); pci_push(base); writel(NVREG_TXRXCTL_BIT1|np->desc_ver, base + NvRegTxRxControl); reg_delay(dev, NvRegUnknownSetupReg5, NVREG_UNKSETUP5_BIT31, NVREG_UNKSETUP5_BIT31, NV_SETUP5_DELAY, NV_SETUP5_DELAYMAX, KERN_INFO "open: SetupReg5, Bit 31 remained off\n"); writel(0, base + NvRegUnknownSetupReg4); writel(NVREG_IRQSTAT_MASK, base + NvRegIrqStatus); writel(NVREG_MIISTAT_MASK2, base + NvRegMIIStatus); /* 6) continue setup */ writel(NVREG_MISC1_FORCE | NVREG_MISC1_HD, base + NvRegMisc1); writel(readl(base + NvRegTransmitterStatus), base + NvRegTransmitterStatus); writel(NVREG_PFF_ALWAYS, base + NvRegPacketFilterFlags); writel(NVREG_OFFLOAD_NORMAL, base + NvRegOffloadConfig); writel(readl(base + NvRegReceiverStatus), base + NvRegReceiverStatus); get_random_bytes(&i, sizeof(i)); writel(NVREG_RNDSEED_FORCE | (i&NVREG_RNDSEED_MASK), base + NvRegRandomSeed); writel(NVREG_UNKSETUP1_VAL, base + NvRegUnknownSetupReg1); writel(NVREG_UNKSETUP2_VAL, base + NvRegUnknownSetupReg2); writel(NVREG_POLL_DEFAULT, base + NvRegPollingInterval); writel(NVREG_UNKSETUP6_VAL, base + NvRegUnknownSetupReg6); writel((np->phyaddr << NVREG_ADAPTCTL_PHYSHIFT)|NVREG_ADAPTCTL_PHYVALID|NVREG_ADAPTCTL_RUNNING, base + NvRegAdapterControl); writel(NVREG_MIISPEED_BIT8|NVREG_MIIDELAY, base + NvRegMIISpeed); writel(NVREG_UNKSETUP4_VAL, base + NvRegUnknownSetupReg4); writel(NVREG_WAKEUPFLAGS_VAL, base + NvRegWakeUpFlags); i = readl(base + NvRegPowerState); if ( (i & NVREG_POWERSTATE_POWEREDUP) == 0) writel(NVREG_POWERSTATE_POWEREDUP|i, base + NvRegPowerState); pci_push(base); udelay(10); writel(readl(base + NvRegPowerState) | NVREG_POWERSTATE_VALID, base + NvRegPowerState); writel(0, base + NvRegIrqMask); pci_push(base); writel(NVREG_MIISTAT_MASK2, base + NvRegMIIStatus); writel(NVREG_IRQSTAT_MASK, base + NvRegIrqStatus); pci_push(base); ret = request_irq(dev->irq, &nv_nic_irq, SA_SHIRQ, dev->name, dev); if (ret) goto out_drain; /* ask for interrupts */ writel(np->irqmask, base + NvRegIrqMask); spin_lock_irq(&np->lock); writel(NVREG_MCASTADDRA_FORCE, base + NvRegMulticastAddrA); writel(0, base + NvRegMulticastAddrB); writel(0, base + NvRegMulticastMaskA); writel(0, base + NvRegMulticastMaskB); writel(NVREG_PFF_ALWAYS|NVREG_PFF_MYADDR, base + NvRegPacketFilterFlags); /* One manual link speed update: Interrupts are enabled, future link * speed changes cause interrupts and are handled by nv_link_irq(). */ { u32 miistat; miistat = readl(base + NvRegMIIStatus); writel(NVREG_MIISTAT_MASK, base + NvRegMIIStatus); dprintk(KERN_INFO "startup: got 0x%08x.\n", miistat); } ret = nv_update_linkspeed(dev); nv_start_rx(dev); nv_start_tx(dev); netif_start_queue(dev); if (ret) { netif_carrier_on(dev); } else { printk("%s: no link during initialization.\n", dev->name); netif_carrier_off(dev); } if (oom) mod_timer(&np->oom_kick, jiffies + OOM_REFILL); spin_unlock_irq(&np->lock); return 0;out_drain: drain_ring(dev); return ret;}static int nv_close(struct net_device *dev){ struct fe_priv *np = get_nvpriv(dev); u8 *base; spin_lock_irq(&np->lock); np->in_shutdown = 1; spin_unlock_irq(&np->lock); synchronize_irq(dev->irq); del_timer_sync(&np->oom_kick); del_timer_sync(&np->nic_poll); netif_stop_queue(dev); spin_lock_irq(&np->lock); nv_stop_tx(dev); nv_stop_rx(dev); base = get_hwbase(dev); /* disable interrupts on the nic or we will lock up */ writel(0, base + NvRegIrqMask); pci_push(base); dprintk(KERN_INFO "%s: Irqmask is zero again\n", dev->name); spin_unlock_irq(&np->lock); free_irq(dev->irq, dev); drain_ring(dev); if (np->wolenabled) nv_start_rx(dev); /* FIXME: power down nic */ return 0;}static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_id *id){ struct net_device *dev; struct fe_priv *np; unsigned long addr; u8 *base; int err, i; dev = alloc_etherdev(sizeof(struct fe_priv)); err = -ENOMEM; if (!dev) goto out; np = get_nvpriv(dev); np->pci_dev = pci_dev; spin_lock_init(&np->lock); SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pci_dev->dev); init_timer(&np->oom_kick); np->oom_kick.data = (unsigned long) dev; np->oom_kick.function = &nv_do_rx_refill; /* timer handler */ init_timer(&np->nic_poll); np->nic_poll.data = (unsigned long) dev; np->nic_poll.function = &nv_do_nic_poll; /* timer handler */ err = pci_enable_device(pci_dev); if (err) { printk(KERN_INFO "forcedeth: pci_enable_dev failed (%d) for device %s\n", err, pci_name(pci_dev)); goto out_free; } pci_set_master(pci_dev); err = pci_request_regions(pci_dev, DRV_NAME); if (err < 0) goto out_disable; err = -EINVAL; addr = 0; for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { dprintk(KERN_DEBUG "%s: resource %d start %p len %ld flags 0x%08lx.\n", pci_name(pci_dev), i, (void*)pci_resource_start(pci_dev, i), pci_resource_len(pci_dev, i), pci_resource_flags(pci_dev, i)); if (pci_resource_flags(pci_dev, i) & IORESOURCE_MEM && pci_resource_len(pci_dev, i) >= NV_PCI_REGSZ) { addr = pci_resource_start(pci_dev, i); break; } } if (i == DEVICE_COUNT_RESOURCE) { printk(KERN_INFO "forcedeth: Couldn't find register window for device %s.\n", pci_name(pci_dev)); goto out_relreg; } /* handle different descriptor versions */ if (pci_dev->device == PCI_DEVICE_ID_NVIDIA_NVENET_1 || pci_dev->device == PCI_DEVICE_ID_NVIDIA_NVENET_2 || pci_dev->device == PCI_DEVICE_ID_NVIDIA_NVENET_3) np->desc_ver = DESC_VER_1; else np->desc_ver = DESC_VER_2; err = -ENOMEM; dev->base_addr = (unsigned long) ioremap(addr, NV_PCI_REGSZ); if (!dev->base_addr) goto out_relreg; dev->irq = pci_dev->irq; np->rx_ring = pci_alloc_consistent(pci_dev, sizeof(struct ring_desc) * (RX_RING + TX_RING), &np->ring_addr); if (!np->rx_ring) goto out_unmap; np->tx_ring = &np->rx_ring[RX_RING]; dev->open = nv_open; dev->stop = nv_close; dev->hard_start_xmit = nv_start_xmit; dev->get_stats = nv_get_stats; dev->change_mtu = nv_change_mtu; dev->set_multicast_list = nv_set_multicast; dev->do_ioctl = nv_ioctl; dev->tx_timeout = nv_tx_timeout; dev->watchdog_timeo = NV_WATCHDOG_TIMEO; pci_set_drvdata(pci_dev, dev); /* read the mac address */ base = get_hwbase(dev); np->orig_mac[0] = readl(base + NvRegMacAddrA); np->orig_mac[1] = readl(base + NvRegMacAddrB); dev->dev_addr[0] = (np->orig_mac[1] >> 8) & 0xff; dev->dev_addr[1] = (np->orig_mac[1] >> 0) & 0xff; dev->dev_addr[2] = (np->orig_mac[0] >> 24) & 0xff; dev->dev_addr[3] = (np->orig_mac[0] >> 16) & 0xff; dev->dev_addr[4] = (np->orig_mac[0] >> 8) & 0xff; dev->dev_addr[5] = (np->orig_mac[0] >> 0) & 0xff; if (!is_valid_ether_addr(dev->dev_addr)) { /* * Bad mac address. At least one bios sets the mac address * to 01:23:45:67:89:ab */ printk(KERN_ERR "%s: Invalid Mac address detected: %02x:%02x:%02x:%02x:%02x:%02x\n", pci_name(pci_dev), dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); printk(KERN_ERR "Please complain to your hardware vendor. Switching to a random MAC.\n"); dev->dev_addr[0] = 0x00; dev->dev_addr[1] = 0x00; dev->dev_addr[2] = 0x6c; get_random_bytes(&dev->dev_addr[3], 3); } dprintk(KERN_DEBUG "%s: MAC Address %02x:%02x:%02x:%02x:%02x:%02x\n", pci_name(pci_dev), dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); /* disable WOL */ writel(0, base + NvRegWakeUpFlags); np->wolenabled = 0; if (np->desc_ver == DESC_VER_1) { np->tx_flags = NV_TX_LASTPACKET|NV_TX_VALID; if (id->driver_data & DEV_NEED_LASTPACKET1) np->tx_flags |= NV_TX_LASTPACKET1; } else { np->tx_flags = NV_TX2_LASTPACKET|NV_TX2_VALID; if (id->driver_data & DEV_NEED_LASTPACKET1) np->tx_flags |= NV_TX2_LASTPACKET1; } if (id->driver_data & DEV_IRQMASK_1) np->irqmask = NVREG_IRQMASK_WANTED_1; if (id->driver_data & DEV_IRQMASK_2) np->irqmask = NVREG_IRQMASK_WANTED_2; if (id->driver_data & DEV_NEED_TIMERIRQ) np->irqmask |= NVREG_IRQ_TIMER; if (id->driver_data & DEV_NEED_LINKTIMER) { dprintk(KERN_INFO "%s: link timer on.\n", pci_name(pci_dev)); np->need_linktimer = 1; np->link_timeout = jiffies + LINK_TIMEOUT; } else { dprintk(KERN_INFO "%s: link timer off.\n", pci_name(pci_dev)); np->need_linktimer = 0; } /* find a suitable phy */ for (i = 1; i < 32; i++) { int id1, id2; spin_lock_irq(&np->lock); id1 = mii_rw(dev, i, MII_PHYSID1, MII_READ); spin_unlock_irq(&np->lock); if (id1 < 0 || id1 == 0xffff) continue; spin_lock_irq(&np->lock); id2 = mii_rw(dev, i, MII_PHYSID2, MII_READ); spin_unlock_irq(&np->lock); if (id2 < 0 || id2 == 0xffff) continue; id1 = (id1 & PHYID1_OUI_MASK) << PHYID1_OUI_SHFT; id2 = (id2 & PHYID2_OUI_MASK) >> PHYID2_OUI_SHFT; dprintk(KERN_DEBUG "%s: open: Found PHY %04x:%04x at address %d.\n", pci_name(pci_dev), id1, id2, i); np->phyaddr = i; np->phy_oui = id1 | id2; break; } if (i == 32) { /* PHY in isolate mode? No phy attached and user wants to * test loopback? Very odd, but can be correct. */ printk(KERN_INFO "%s: open: Could not find a valid PHY.\n", pci_name(pci_dev)); } if (i != 32) { /* reset it */ phy_init(dev); } err = register_netdev(dev); if (err) { printk(KERN_INFO "forcedeth: unable to register netdev: %d\n", err); goto out_freering; } printk(KERN_INFO "%s: forcedeth.c: subsystem: %05x:%04x bound to %s\n", dev->name, pci_dev->subsystem_vendor, pci_dev->subsystem_device, pci_name(pci_dev)); return 0;out_freering: pci_free_consistent(np->pci_dev, sizeof(struct ring_desc) * (RX_RING + TX_RING), np->rx_ring, np->ring_addr); pci_set_drvdata(pci_dev, NULL);out_unmap: iounmap(get_hwbase(dev));out_relreg: pci_release_regions(pci_dev);out_disable: pci_disable_device(pci_dev);out_free: free_netdev(dev);out: return err;}static void __devexit nv_remove(struct pci_dev *pci_dev){ struct net_device *dev = pci_get_drvdata(pci_dev); struct fe_priv *np = get_nvpriv(dev); u8 *base = get_hwbase(dev); unregister_netdev(dev); /* special op: write back the misordered MAC address - otherwise * the next nv_probe would see a wrong address. */ writel(np->orig_mac[0], base + NvRegMacAddrA); writel(np->orig_mac[1], base + NvRegMacAddrB); /* free all structures */ pci_free_consistent(np->pci_dev, sizeof(struct ring_desc) * (RX_RING + TX_RING), np->rx_ring, np->ring_addr); iounmap(get_hwbase(dev)); pci_release_regions(pci_dev); pci_disable_device(pci_dev); free_netdev(dev); pci_set_drvdata(pci_dev, NULL);}static struct pci_device_id pci_tbl[] = { { /* nForce Ethernet Controller */ .vendor = PCI_VENDOR_ID_NVIDIA, .device = PCI_DEVICE_ID_NVIDIA_NVENET_1, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, .driver_data = DEV_IRQMASK_1|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER, }, { /* nForce2 Ethernet Controller */ .vendor = PCI_VENDOR_ID_NVIDIA, .device = PCI_DEVICE_ID_NVIDIA_NVENET_2, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER, }, { /* nForce3 Ethernet Controller */ .vendor = PCI_VENDOR_ID_NVIDIA, .device = PCI_DEVICE_ID_NVIDIA_NVENET_3, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER, }, { /* nForce3 Ethernet Controller */ .vendor = PCI_VENDOR_ID_NVIDIA, .device = PCI_DEVICE_ID_NVIDIA_NVENET_4, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ, }, { /* nForce3 Ethernet Controller */ .vendor = PCI_VENDOR_ID_NVIDIA, .device = PCI_DEVICE_ID_NVIDIA_NVENET_5, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ, }, { /* nForce3 Ethernet Controller */ .vendor = PCI_VENDOR_ID_NVIDIA, .device = PCI_DEVICE_ID_NVIDIA_NVENET_6, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ, }, { /* nForce3 Ethernet Controller */ .vendor = PCI_VENDOR_ID_NVIDIA, .device = PCI_DEVICE_ID_NVIDIA_NVENET_7, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ, }, { /* CK804 Ethernet Controller */ .vendor = PCI_VENDOR_ID_NVIDIA, .device = PCI_DEVICE_ID_NVIDIA_NVENET_8, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ, }, { /* CK804 Ethernet Controller */ .vendor = PCI_VENDOR_ID_NVIDIA, .device = PCI_DEVICE_ID_NVIDIA_NVENET_9, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ, }, { /* MCP04 Ethernet Controller */ .vendor = PCI_VENDOR_ID_NVIDIA, .device = PCI_DEVICE_ID_NVIDIA_NVENET_10, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ, }, { /* MCP04 Ethernet Controller */ .vendor = PCI_VENDOR_ID_NVIDIA, .device = PCI_DEVICE_ID_NVIDIA_NVENET_11, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ, }, {0,},};static struct pci_driver driver = { .name = "forcedeth", .id_table = pci_tbl, .probe = nv_probe, .remove = __devexit_p(nv_remove),};static int __init init_nic(void){ printk(KERN_INFO "forcedeth.c: Reverse Engineered nForce ethernet driver. Version %s.\n", FORCEDETH_VERSION); return pci_module_init(&driver);}static void __exit exit_nic(void){ pci_unregister_driver(&driver);}module_param(max_interrupt_work, int, 0);MODULE_PARM_DESC(max_interrupt_work, "forcedeth maximum events handled per interrupt");MODULE_AUTHOR("Manfred Spraul <manfred@colorfullife.com>");MODULE_DESCRIPTION("Reverse Engineered nForce ethernet driver");MODULE_LICENSE("GPL");MODULE_DEVICE_TABLE(pci, pci_tbl);module_init(init_nic);module_exit(exit_nic);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -