📄 ns83820.c
字号:
/* enable output, set bit */ dev->MEAR_cache |= MEAR_MDDIR; if (bit) dev->MEAR_cache |= MEAR_MDIO; else dev->MEAR_cache &= ~MEAR_MDIO; /* set the output bit */ writel(dev->MEAR_cache, dev->base + MEAR); readl(dev->base + MEAR); /* Wait. Max clock rate is 2.5MHz, this way we come in under 1MHz */ udelay(1); /* drive MDC high causing the data bit to be latched */ dev->MEAR_cache |= MEAR_MDC; writel(dev->MEAR_cache, dev->base + MEAR); readl(dev->base + MEAR); /* Wait again... */ udelay(1);}static int ns83820_mii_read_bit(struct ns83820 *dev){ int bit; /* drive MDC low, disable output */ dev->MEAR_cache &= ~MEAR_MDC; dev->MEAR_cache &= ~MEAR_MDDIR; writel(dev->MEAR_cache, dev->base + MEAR); readl(dev->base + MEAR); /* Wait. Max clock rate is 2.5MHz, this way we come in under 1MHz */ udelay(1); /* drive MDC high causing the data bit to be latched */ bit = (readl(dev->base + MEAR) & MEAR_MDIO) ? 1 : 0; dev->MEAR_cache |= MEAR_MDC; writel(dev->MEAR_cache, dev->base + MEAR); /* Wait again... */ udelay(1); return bit;}static unsigned ns83820_mii_read_reg(struct ns83820 *dev, unsigned phy, unsigned reg){ unsigned data = 0; int i; /* read some garbage so that we eventually sync up */ for (i=0; i<64; i++) ns83820_mii_read_bit(dev); ns83820_mii_write_bit(dev, 0); /* start */ ns83820_mii_write_bit(dev, 1); ns83820_mii_write_bit(dev, 1); /* opcode read */ ns83820_mii_write_bit(dev, 0); /* 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++) { data <<= 1; data |= ns83820_mii_read_bit(dev); } return data;}static unsigned ns83820_mii_write_reg(struct ns83820 *dev, unsigned phy, unsigned reg, unsigned data){ int i; /* read some garbage so that we eventually sync up */ for (i=0; i<64; i++) 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; /* See if we can set the dma mask early on; failure is fatal. */ if (TRY_DAC && !pci_set_dma_mask(pci_dev, 0xffffffffffffffffULL)) { using_dac = 1; } else if (!pci_set_dma_mask(pci_dev, 0xffffffff)) { using_dac = 0; } else { printk(KERN_WARNING "ns83820.c: pci_set_dma_mask failed!\n"); return -ENODEV; } ndev = alloc_etherdev(sizeof(struct ns83820)); dev = PRIV(ndev); err = -ENOMEM; if (!dev) goto out; spin_lock_init(&dev->rx_info.lock); spin_lock_init(&dev->tx_lock); spin_lock_init(&dev->misc_lock); dev->pci_dev = pci_dev; dev->ee.cache = &dev->MEAR_cache; dev->ee.lock = &dev->misc_lock; SET_MODULE_OWNER(ndev); SET_NETDEV_DEV(ndev, &pci_dev->dev); INIT_WORK(&dev->tq_refill, queue_refill, ndev); tasklet_init(&dev->rx_tasklet, rx_action, (unsigned long)ndev); err = pci_enable_device(pci_dev); if (err) { printk(KERN_INFO "ns83820: 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; setup_ee_mem_bitbanger(&dev->ee, (long)dev->base + MEAR, 3, 2, 1, 0, 0); err = request_irq(pci_dev->irq, ns83820_irq, SA_SHIRQ, DRV_NAME, ndev); if (err) { printk(KERN_INFO "ns83820: unable to register irq %d\n", pci_dev->irq); 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) { printk(KERN_INFO "ns83820: 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; ndev->do_ioctl = ns83820_ioctl; 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. */#ifdef USE_64BIT_ADDR dev->CFG_cache |= CFG_M64ADDR;#endif 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); set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout((HZ+99)/100); 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...... */ writel(VRCR_IPEN | VRCR_VTDEN, dev->base + VRCR); /* Enable per-packet TCP/UDP/IP checksumming */ writel(VTCR_PPCHK, 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; 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: %02x:%02x:%02x:%02x:%02x:%02x io=0x%08lx irq=%d f=%s\n", ndev->name, (unsigned)readl(dev->base + SRR) >> 8, (unsigned)readl(dev->base + SRR) & 0xff, ndev->dev_addr[0], ndev->dev_addr[1], ndev->dev_addr[2], ndev->dev_addr[3], ndev->dev_addr[4], ndev->dev_addr[5], 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_module_init(&driver);}static void __exit ns83820_exit(void){ pci_unregister_driver(&driver);}MODULE_AUTHOR("Benjamin LaHaise <bcrl@redhat.com>");MODULE_DESCRIPTION("National Semiconductor DP83820 10/100/1000 driver");MODULE_LICENSE("GPL");MODULE_DEVICE_TABLE(pci, ns83820_pci_tbl);MODULE_PARM(lnksts, "i");MODULE_PARM_DESC(lnksts, "Polarity of LNKSTS bit");MODULE_PARM(ihr, "i");MODULE_PARM_DESC(ihr, "Time in 100 us increments to delay interrupts (range 0-127)");MODULE_PARM(reset_phy, "i");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 + -