📄 ns83820.c
字号:
ns83820_mii_read_bit(dev); ns83820_mii_write_bit(dev, 0); /* start */ ns83820_mii_write_bit(dev, 1); ns83820_mii_write_bit(dev, 0); /* opcode read */ ns83820_mii_write_bit(dev, 1); /* write out the phy address: 5 bits, msb first */ for (i=0; i<5; i++) ns83820_mii_write_bit(dev, phy & (0x10 >> i)); /* write out the register address, 5 bits, msb first */ for (i=0; i<5; i++) ns83820_mii_write_bit(dev, reg & (0x10 >> i)); ns83820_mii_read_bit(dev); /* turn around cycles */ ns83820_mii_read_bit(dev); /* read in the register data, 16 bits msb first */ for (i=0; i<16; i++) ns83820_mii_write_bit(dev, (data >> (15 - i)) & 1); return data;}static void ns83820_probe_phy(struct net_device *ndev){ struct ns83820 *dev = PRIV(ndev); static int first; int i;#define MII_PHYIDR1 0x02#define MII_PHYIDR2 0x03#if 0 if (!first) { unsigned tmp; ns83820_mii_read_reg(dev, 1, 0x09); ns83820_mii_write_reg(dev, 1, 0x10, 0x0d3e); tmp = ns83820_mii_read_reg(dev, 1, 0x00); ns83820_mii_write_reg(dev, 1, 0x00, tmp | 0x8000); udelay(1300); ns83820_mii_read_reg(dev, 1, 0x09); }#endif first = 1; for (i=1; i<2; i++) { int j; unsigned a, b; a = ns83820_mii_read_reg(dev, i, MII_PHYIDR1); b = ns83820_mii_read_reg(dev, i, MII_PHYIDR2); //printk("%s: phy %d: 0x%04x 0x%04x\n", // ndev->name, i, a, b); for (j=0; j<0x16; j+=4) { dprintk("%s: [0x%02x] %04x %04x %04x %04x\n", ndev->name, j, ns83820_mii_read_reg(dev, i, 0 + j), ns83820_mii_read_reg(dev, i, 1 + j), ns83820_mii_read_reg(dev, i, 2 + j), ns83820_mii_read_reg(dev, i, 3 + j) ); } } { unsigned a, b; /* read firmware version: memory addr is 0x8402 and 0x8403 */ ns83820_mii_write_reg(dev, 1, 0x16, 0x000d); ns83820_mii_write_reg(dev, 1, 0x1e, 0x810e); a = ns83820_mii_read_reg(dev, 1, 0x1d); ns83820_mii_write_reg(dev, 1, 0x16, 0x000d); ns83820_mii_write_reg(dev, 1, 0x1e, 0x810e); b = ns83820_mii_read_reg(dev, 1, 0x1d); dprintk("version: 0x%04x 0x%04x\n", a, b); }}#endifstatic int __devinit ns83820_init_one(struct pci_dev *pci_dev, const struct pci_device_id *id){ struct net_device *ndev; struct ns83820 *dev; long addr; int err; int using_dac = 0; DECLARE_MAC_BUF(mac); /* See if we can set the dma mask early on; failure is fatal. */ if (sizeof(dma_addr_t) == 8 && !pci_set_dma_mask(pci_dev, DMA_64BIT_MASK)) { using_dac = 1; } else if (!pci_set_dma_mask(pci_dev, DMA_32BIT_MASK)) { using_dac = 0; } else { dev_warn(&pci_dev->dev, "pci_set_dma_mask failed!\n"); return -ENODEV; } ndev = alloc_etherdev(sizeof(struct ns83820)); dev = PRIV(ndev); err = -ENOMEM; if (!dev) goto out; dev->ndev = ndev; spin_lock_init(&dev->rx_info.lock); spin_lock_init(&dev->tx_lock); spin_lock_init(&dev->misc_lock); dev->pci_dev = pci_dev; SET_NETDEV_DEV(ndev, &pci_dev->dev); INIT_WORK(&dev->tq_refill, queue_refill); tasklet_init(&dev->rx_tasklet, rx_action, (unsigned long)ndev); err = pci_enable_device(pci_dev); if (err) { dev_info(&pci_dev->dev, "pci_enable_dev failed: %d\n", err); goto out_free; } pci_set_master(pci_dev); addr = pci_resource_start(pci_dev, 1); dev->base = ioremap_nocache(addr, PAGE_SIZE); dev->tx_descs = pci_alloc_consistent(pci_dev, 4 * DESC_SIZE * NR_TX_DESC, &dev->tx_phy_descs); dev->rx_info.descs = pci_alloc_consistent(pci_dev, 4 * DESC_SIZE * NR_RX_DESC, &dev->rx_info.phy_descs); err = -ENOMEM; if (!dev->base || !dev->tx_descs || !dev->rx_info.descs) goto out_disable; dprintk("%p: %08lx %p: %08lx\n", dev->tx_descs, (long)dev->tx_phy_descs, dev->rx_info.descs, (long)dev->rx_info.phy_descs); /* disable interrupts */ writel(0, dev->base + IMR); writel(0, dev->base + IER); readl(dev->base + IER); dev->IMR_cache = 0; err = request_irq(pci_dev->irq, ns83820_irq, IRQF_SHARED, DRV_NAME, ndev); if (err) { dev_info(&pci_dev->dev, "unable to register irq %d, err %d\n", pci_dev->irq, err); goto out_disable; } /* * FIXME: we are holding rtnl_lock() over obscenely long area only * because some of the setup code uses dev->name. It's Wrong(tm) - * we should be using driver-specific names for all that stuff. * For now that will do, but we really need to come back and kill * most of the dev_alloc_name() users later. */ rtnl_lock(); err = dev_alloc_name(ndev, ndev->name); if (err < 0) { dev_info(&pci_dev->dev, "unable to get netdev name: %d\n", err); goto out_free_irq; } printk("%s: ns83820.c: 0x22c: %08x, subsystem: %04x:%04x\n", ndev->name, le32_to_cpu(readl(dev->base + 0x22c)), pci_dev->subsystem_vendor, pci_dev->subsystem_device); ndev->open = ns83820_open; ndev->stop = ns83820_stop; ndev->hard_start_xmit = ns83820_hard_start_xmit; ndev->get_stats = ns83820_get_stats; ndev->change_mtu = ns83820_change_mtu; ndev->set_multicast_list = ns83820_set_multicast; SET_ETHTOOL_OPS(ndev, &ops); ndev->tx_timeout = ns83820_tx_timeout; ndev->watchdog_timeo = 5 * HZ; pci_set_drvdata(pci_dev, ndev); ns83820_do_reset(dev, CR_RST); /* Must reset the ram bist before running it */ writel(PTSCR_RBIST_RST, dev->base + PTSCR); ns83820_run_bist(ndev, "sram bist", PTSCR_RBIST_EN, PTSCR_RBIST_DONE, PTSCR_RBIST_FAIL); ns83820_run_bist(ndev, "eeprom bist", PTSCR_EEBIST_EN, 0, PTSCR_EEBIST_FAIL); ns83820_run_bist(ndev, "eeprom load", PTSCR_EELOAD_EN, 0, 0); /* I love config registers */ dev->CFG_cache = readl(dev->base + CFG); if ((dev->CFG_cache & CFG_PCI64_DET)) { printk(KERN_INFO "%s: detected 64 bit PCI data bus.\n", ndev->name); /*dev->CFG_cache |= CFG_DATA64_EN;*/ if (!(dev->CFG_cache & CFG_DATA64_EN)) printk(KERN_INFO "%s: EEPROM did not enable 64 bit bus. Disabled.\n", ndev->name); } else dev->CFG_cache &= ~(CFG_DATA64_EN); dev->CFG_cache &= (CFG_TBI_EN | CFG_MRM_DIS | CFG_MWI_DIS | CFG_T64ADDR | CFG_DATA64_EN | CFG_EXT_125 | CFG_M64ADDR); dev->CFG_cache |= CFG_PINT_DUPSTS | CFG_PINT_LNKSTS | CFG_PINT_SPDSTS | CFG_EXTSTS_EN | CFG_EXD | CFG_PESEL; dev->CFG_cache |= CFG_REQALG; dev->CFG_cache |= CFG_POW; dev->CFG_cache |= CFG_TMRTEST; /* When compiled with 64 bit addressing, we must always enable * the 64 bit descriptor format. */ if (sizeof(dma_addr_t) == 8) dev->CFG_cache |= CFG_M64ADDR; if (using_dac) dev->CFG_cache |= CFG_T64ADDR; /* Big endian mode does not seem to do what the docs suggest */ dev->CFG_cache &= ~CFG_BEM; /* setup optical transceiver if we have one */ if (dev->CFG_cache & CFG_TBI_EN) { printk(KERN_INFO "%s: enabling optical transceiver\n", ndev->name); writel(readl(dev->base + GPIOR) | 0x3e8, dev->base + GPIOR); /* setup auto negotiation feature advertisement */ writel(readl(dev->base + TANAR) | TANAR_HALF_DUP | TANAR_FULL_DUP, dev->base + TANAR); /* start auto negotiation */ writel(TBICR_MR_AN_ENABLE | TBICR_MR_RESTART_AN, dev->base + TBICR); writel(TBICR_MR_AN_ENABLE, dev->base + TBICR); dev->linkstate = LINK_AUTONEGOTIATE; dev->CFG_cache |= CFG_MODE_1000; } writel(dev->CFG_cache, dev->base + CFG); dprintk("CFG: %08x\n", dev->CFG_cache); if (reset_phy) { printk(KERN_INFO "%s: resetting phy\n", ndev->name); writel(dev->CFG_cache | CFG_PHY_RST, dev->base + CFG); msleep(10); writel(dev->CFG_cache, dev->base + CFG); }#if 0 /* Huh? This sets the PCI latency register. Should be done via * the PCI layer. FIXME. */ if (readl(dev->base + SRR)) writel(readl(dev->base+0x20c) | 0xfe00, dev->base + 0x20c);#endif /* Note! The DMA burst size interacts with packet * transmission, such that the largest packet that * can be transmitted is 8192 - FLTH - burst size. * If only the transmit fifo was larger... */ /* Ramit : 1024 DMA is not a good idea, it ends up banging * some DELL and COMPAQ SMP systems */ writel(TXCFG_CSI | TXCFG_HBI | TXCFG_ATP | TXCFG_MXDMA512 | ((1600 / 32) * 0x100), dev->base + TXCFG); /* Flush the interrupt holdoff timer */ writel(0x000, dev->base + IHR); writel(0x100, dev->base + IHR); writel(0x000, dev->base + IHR); /* Set Rx to full duplex, don't accept runt, errored, long or length * range errored packets. Use 512 byte DMA. */ /* Ramit : 1024 DMA is not a good idea, it ends up banging * some DELL and COMPAQ SMP systems * Turn on ALP, only we are accpeting Jumbo Packets */ writel(RXCFG_AEP | RXCFG_ARP | RXCFG_AIRL | RXCFG_RX_FD | RXCFG_STRIPCRC //| RXCFG_ALP | (RXCFG_MXDMA512) | 0, dev->base + RXCFG); /* Disable priority queueing */ writel(0, dev->base + PQCR); /* Enable IP checksum validation and detetion of VLAN headers. * Note: do not set the reject options as at least the 0x102 * revision of the chip does not properly accept IP fragments * at least for UDP. */ /* Ramit : Be sure to turn on RXCFG_ARP if VLAN's are enabled, since * the MAC it calculates the packetsize AFTER stripping the VLAN * header, and if a VLAN Tagged packet of 64 bytes is received (like * a ping with a VLAN header) then the card, strips the 4 byte VLAN * tag and then checks the packet size, so if RXCFG_ARP is not enabled, * it discrards it!. These guys...... * also turn on tag stripping if hardware acceleration is enabled */#ifdef NS83820_VLAN_ACCEL_SUPPORT#define VRCR_INIT_VALUE (VRCR_IPEN|VRCR_VTDEN|VRCR_VTREN)#else#define VRCR_INIT_VALUE (VRCR_IPEN|VRCR_VTDEN)#endif writel(VRCR_INIT_VALUE, dev->base + VRCR); /* Enable per-packet TCP/UDP/IP checksumming * and per packet vlan tag insertion if * vlan hardware acceleration is enabled */#ifdef NS83820_VLAN_ACCEL_SUPPORT#define VTCR_INIT_VALUE (VTCR_PPCHK|VTCR_VPPTI)#else#define VTCR_INIT_VALUE VTCR_PPCHK#endif writel(VTCR_INIT_VALUE, dev->base + VTCR); /* Ramit : Enable async and sync pause frames */ /* writel(0, dev->base + PCR); */ writel((PCR_PS_MCAST | PCR_PS_DA | PCR_PSEN | PCR_FFLO_4K | PCR_FFHI_8K | PCR_STLO_4 | PCR_STHI_8 | PCR_PAUSE_CNT), dev->base + PCR); /* Disable Wake On Lan */ writel(0, dev->base + WCSR); ns83820_getmac(dev, ndev->dev_addr); /* Yes, we support dumb IP checksum on transmit */ ndev->features |= NETIF_F_SG; ndev->features |= NETIF_F_IP_CSUM;#ifdef NS83820_VLAN_ACCEL_SUPPORT /* We also support hardware vlan acceleration */ ndev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; ndev->vlan_rx_register = ns83820_vlan_rx_register;#endif if (using_dac) { printk(KERN_INFO "%s: using 64 bit addressing.\n", ndev->name); ndev->features |= NETIF_F_HIGHDMA; } printk(KERN_INFO "%s: ns83820 v" VERSION ": DP83820 v%u.%u: %s io=0x%08lx irq=%d f=%s\n", ndev->name, (unsigned)readl(dev->base + SRR) >> 8, (unsigned)readl(dev->base + SRR) & 0xff, print_mac(mac, ndev->dev_addr), addr, pci_dev->irq, (ndev->features & NETIF_F_HIGHDMA) ? "h,sg" : "sg" );#ifdef PHY_CODE_IS_FINISHED ns83820_probe_phy(ndev);#endif err = register_netdevice(ndev); if (err) { printk(KERN_INFO "ns83820: unable to register netdev: %d\n", err); goto out_cleanup; } rtnl_unlock(); return 0;out_cleanup: writel(0, dev->base + IMR); /* paranoia */ writel(0, dev->base + IER); readl(dev->base + IER);out_free_irq: rtnl_unlock(); free_irq(pci_dev->irq, ndev);out_disable: if (dev->base) iounmap(dev->base); pci_free_consistent(pci_dev, 4 * DESC_SIZE * NR_TX_DESC, dev->tx_descs, dev->tx_phy_descs); pci_free_consistent(pci_dev, 4 * DESC_SIZE * NR_RX_DESC, dev->rx_info.descs, dev->rx_info.phy_descs); pci_disable_device(pci_dev);out_free: free_netdev(ndev); pci_set_drvdata(pci_dev, NULL);out: return err;}static void __devexit ns83820_remove_one(struct pci_dev *pci_dev){ struct net_device *ndev = pci_get_drvdata(pci_dev); struct ns83820 *dev = PRIV(ndev); /* ok even if NULL */ if (!ndev) /* paranoia */ return; writel(0, dev->base + IMR); /* paranoia */ writel(0, dev->base + IER); readl(dev->base + IER); unregister_netdev(ndev); free_irq(dev->pci_dev->irq, ndev); iounmap(dev->base); pci_free_consistent(dev->pci_dev, 4 * DESC_SIZE * NR_TX_DESC, dev->tx_descs, dev->tx_phy_descs); pci_free_consistent(dev->pci_dev, 4 * DESC_SIZE * NR_RX_DESC, dev->rx_info.descs, dev->rx_info.phy_descs); pci_disable_device(dev->pci_dev); free_netdev(ndev); pci_set_drvdata(pci_dev, NULL);}static struct pci_device_id ns83820_pci_tbl[] = { { 0x100b, 0x0022, PCI_ANY_ID, PCI_ANY_ID, 0, .driver_data = 0, }, { 0, },};static struct pci_driver driver = { .name = "ns83820", .id_table = ns83820_pci_tbl, .probe = ns83820_init_one, .remove = __devexit_p(ns83820_remove_one),#if 0 /* FIXME: implement */ .suspend = , .resume = ,#endif};static int __init ns83820_init(void){ printk(KERN_INFO "ns83820.c: National Semiconductor DP83820 10/100/1000 driver.\n"); return pci_register_driver(&driver);}static void __exit ns83820_exit(void){ pci_unregister_driver(&driver);}MODULE_AUTHOR("Benjamin LaHaise <bcrl@kvack.org>");MODULE_DESCRIPTION("National Semiconductor DP83820 10/100/1000 driver");MODULE_LICENSE("GPL");MODULE_DEVICE_TABLE(pci, ns83820_pci_tbl);module_param(lnksts, int, 0);MODULE_PARM_DESC(lnksts, "Polarity of LNKSTS bit");module_param(ihr, int, 0);MODULE_PARM_DESC(ihr, "Time in 100 us increments to delay interrupts (range 0-127)");module_param(reset_phy, int, 0);MODULE_PARM_DESC(reset_phy, "Set to 1 to reset the PHY on startup");module_init(ns83820_init);module_exit(ns83820_exit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -