📄 pcnet32.c
字号:
rc = 1; break; } } x++; } if (!rc) { *data1 = 0; }clean_up: pcnet32_purge_tx_ring(dev); x = a->read_csr(ioaddr, 15) & 0xFFFF; a->write_csr(ioaddr, 15, (x & ~0x0044)); /* reset bits 6 and 2 */ x = a->read_bcr(ioaddr, 32); /* reset internal loopback */ x = x & ~0x0002; a->write_bcr(ioaddr, 32, x); spin_unlock_irqrestore(&lp->lock, flags); if (netif_running(dev)) { pcnet32_open(dev); } else { lp->a.write_bcr (ioaddr, 20, 4); /* return to 16bit mode */ } return(rc);} /* end pcnet32_loopback_test */static void pcnet32_led_blink_callback(struct net_device *dev){ struct pcnet32_private *lp = dev->priv; struct pcnet32_access *a = &lp->a; ulong ioaddr = dev->base_addr; unsigned long flags; int i; spin_lock_irqsave(&lp->lock, flags); for (i=4; i<8; i++) { a->write_bcr(ioaddr, i, a->read_bcr(ioaddr, i) ^ 0x4000); } spin_unlock_irqrestore(&lp->lock, flags); mod_timer(&lp->blink_timer, PCNET32_BLINK_TIMEOUT);}static int pcnet32_phys_id(struct net_device *dev, u32 data){ struct pcnet32_private *lp = dev->priv; struct pcnet32_access *a = &lp->a; ulong ioaddr = dev->base_addr; unsigned long flags; int i, regs[4]; if (!lp->blink_timer.function) { init_timer(&lp->blink_timer); lp->blink_timer.function = (void *) pcnet32_led_blink_callback; lp->blink_timer.data = (unsigned long) dev; } /* Save the current value of the bcrs */ spin_lock_irqsave(&lp->lock, flags); for (i=4; i<8; i++) { regs[i-4] = a->read_bcr(ioaddr, i); } spin_unlock_irqrestore(&lp->lock, flags); mod_timer(&lp->blink_timer, jiffies); set_current_state(TASK_INTERRUPTIBLE); if ((!data) || (data > (u32)(MAX_SCHEDULE_TIMEOUT / HZ))) data = (u32)(MAX_SCHEDULE_TIMEOUT / HZ); msleep_interruptible(data * 1000); del_timer_sync(&lp->blink_timer); /* Restore the original value of the bcrs */ spin_lock_irqsave(&lp->lock, flags); for (i=4; i<8; i++) { a->write_bcr(ioaddr, i, regs[i-4]); } spin_unlock_irqrestore(&lp->lock, flags); return 0;}static int pcnet32_get_regs_len(struct net_device *dev){ return(PCNET32_NUM_REGS * sizeof(u16));}static void pcnet32_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *ptr){ int i, csr0; u16 *buff = ptr; struct pcnet32_private *lp = dev->priv; struct pcnet32_access *a = &lp->a; ulong ioaddr = dev->base_addr; int ticks; unsigned long flags; spin_lock_irqsave(&lp->lock, flags); csr0 = a->read_csr(ioaddr, 0); if (!(csr0 & 0x0004)) { /* If not stopped */ /* set SUSPEND (SPND) - CSR5 bit 0 */ a->write_csr(ioaddr, 5, 0x0001); /* poll waiting for bit to be set */ ticks = 0; while (!(a->read_csr(ioaddr, 5) & 0x0001)) { spin_unlock_irqrestore(&lp->lock, flags); mdelay(1); spin_lock_irqsave(&lp->lock, flags); ticks++; if (ticks > 200) { if (netif_msg_hw(lp)) printk(KERN_DEBUG "%s: Error getting into suspend!\n", dev->name); break; } } } /* read address PROM */ for (i=0; i<16; i += 2) *buff++ = inw(ioaddr + i); /* read control and status registers */ for (i=0; i<90; i++) { *buff++ = a->read_csr(ioaddr, i); } *buff++ = a->read_csr(ioaddr, 112); *buff++ = a->read_csr(ioaddr, 114); /* read bus configuration registers */ for (i=0; i<30; i++) { *buff++ = a->read_bcr(ioaddr, i); } *buff++ = 0; /* skip bcr30 so as not to hang 79C976 */ for (i=31; i<36; i++) { *buff++ = a->read_bcr(ioaddr, i); } /* read mii phy registers */ if (lp->mii) { for (i=0; i<32; i++) { lp->a.write_bcr(ioaddr, 33, ((lp->mii_if.phy_id) << 5) | i); *buff++ = lp->a.read_bcr(ioaddr, 34); } } if (!(csr0 & 0x0004)) { /* If not stopped */ /* clear SUSPEND (SPND) - CSR5 bit 0 */ a->write_csr(ioaddr, 5, 0x0000); } i = buff - (u16 *)ptr; for (; i < PCNET32_NUM_REGS; i++) *buff++ = 0; spin_unlock_irqrestore(&lp->lock, flags);}static struct ethtool_ops pcnet32_ethtool_ops = { .get_settings = pcnet32_get_settings, .set_settings = pcnet32_set_settings, .get_drvinfo = pcnet32_get_drvinfo, .get_msglevel = pcnet32_get_msglevel, .set_msglevel = pcnet32_set_msglevel, .nway_reset = pcnet32_nway_reset, .get_link = pcnet32_get_link, .get_ringparam = pcnet32_get_ringparam, .set_ringparam = pcnet32_set_ringparam, .get_tx_csum = ethtool_op_get_tx_csum, .get_sg = ethtool_op_get_sg, .get_tso = ethtool_op_get_tso, .get_strings = pcnet32_get_strings, .self_test_count = pcnet32_self_test_count, .self_test = pcnet32_ethtool_test, .phys_id = pcnet32_phys_id, .get_regs_len = pcnet32_get_regs_len, .get_regs = pcnet32_get_regs, .get_perm_addr = ethtool_op_get_perm_addr,};/* only probes for non-PCI devices, the rest are handled by * pci_register_driver via pcnet32_probe_pci */static void __devinitpcnet32_probe_vlbus(void){ unsigned int *port, ioaddr; /* search for PCnet32 VLB cards at known addresses */ for (port = pcnet32_portlist; (ioaddr = *port); port++) { if (request_region(ioaddr, PCNET32_TOTAL_SIZE, "pcnet32_probe_vlbus")) { /* check if there is really a pcnet chip on that ioaddr */ if ((inb(ioaddr + 14) == 0x57) && (inb(ioaddr + 15) == 0x57)) { pcnet32_probe1(ioaddr, 0, NULL); } else { release_region(ioaddr, PCNET32_TOTAL_SIZE); } } }}static int __devinitpcnet32_probe_pci(struct pci_dev *pdev, const struct pci_device_id *ent){ unsigned long ioaddr; int err; err = pci_enable_device(pdev); if (err < 0) { if (pcnet32_debug & NETIF_MSG_PROBE) printk(KERN_ERR PFX "failed to enable device -- err=%d\n", err); return err; } pci_set_master(pdev); ioaddr = pci_resource_start (pdev, 0); if (!ioaddr) { if (pcnet32_debug & NETIF_MSG_PROBE) printk (KERN_ERR PFX "card has no PCI IO resources, aborting\n"); return -ENODEV; } if (!pci_dma_supported(pdev, PCNET32_DMA_MASK)) { if (pcnet32_debug & NETIF_MSG_PROBE) printk(KERN_ERR PFX "architecture does not support 32bit PCI busmaster DMA\n"); return -ENODEV; } if (request_region(ioaddr, PCNET32_TOTAL_SIZE, "pcnet32_probe_pci") == NULL) { if (pcnet32_debug & NETIF_MSG_PROBE) printk(KERN_ERR PFX "io address range already allocated\n"); return -EBUSY; } err = pcnet32_probe1(ioaddr, 1, pdev); if (err < 0) { pci_disable_device(pdev); } return err;}/* pcnet32_probe1 * Called from both pcnet32_probe_vlbus and pcnet_probe_pci. * pdev will be NULL when called from pcnet32_probe_vlbus. */static int __devinitpcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev){ struct pcnet32_private *lp; dma_addr_t lp_dma_addr; int i, media; int fdx, mii, fset, dxsuflo; int chip_version; char *chipname; struct net_device *dev; struct pcnet32_access *a = NULL; u8 promaddr[6]; int ret = -ENODEV; /* reset the chip */ pcnet32_wio_reset(ioaddr); /* NOTE: 16-bit check is first, otherwise some older PCnet chips fail */ if (pcnet32_wio_read_csr(ioaddr, 0) == 4 && pcnet32_wio_check(ioaddr)) { a = &pcnet32_wio; } else { pcnet32_dwio_reset(ioaddr); if (pcnet32_dwio_read_csr(ioaddr, 0) == 4 && pcnet32_dwio_check(ioaddr)) { a = &pcnet32_dwio; } else goto err_release_region; } chip_version = a->read_csr(ioaddr, 88) | (a->read_csr(ioaddr,89) << 16); if ((pcnet32_debug & NETIF_MSG_PROBE) && (pcnet32_debug & NETIF_MSG_HW)) printk(KERN_INFO " PCnet chip version is %#x.\n", chip_version); if ((chip_version & 0xfff) != 0x003) { if (pcnet32_debug & NETIF_MSG_PROBE) printk(KERN_INFO PFX "Unsupported chip version.\n"); goto err_release_region; } /* initialize variables */ fdx = mii = fset = dxsuflo = 0; chip_version = (chip_version >> 12) & 0xffff; switch (chip_version) { case 0x2420: chipname = "PCnet/PCI 79C970"; /* PCI */ break; case 0x2430: if (shared) chipname = "PCnet/PCI 79C970"; /* 970 gives the wrong chip id back */ else chipname = "PCnet/32 79C965"; /* 486/VL bus */ break; case 0x2621: chipname = "PCnet/PCI II 79C970A"; /* PCI */ fdx = 1; break; case 0x2623: chipname = "PCnet/FAST 79C971"; /* PCI */ fdx = 1; mii = 1; fset = 1; break; case 0x2624: chipname = "PCnet/FAST+ 79C972"; /* PCI */ fdx = 1; mii = 1; fset = 1; break; case 0x2625: chipname = "PCnet/FAST III 79C973"; /* PCI */ fdx = 1; mii = 1; break; case 0x2626: chipname = "PCnet/Home 79C978"; /* PCI */ fdx = 1; /* * This is based on specs published at www.amd.com. This section * assumes that a card with a 79C978 wants to go into standard * ethernet mode. The 79C978 can also go into 1Mb HomePNA mode, * and the module option homepna=1 can select this instead. */ media = a->read_bcr(ioaddr, 49); media &= ~3; /* default to 10Mb ethernet */ if (cards_found < MAX_UNITS && homepna[cards_found]) media |= 1; /* switch to home wiring mode */ if (pcnet32_debug & NETIF_MSG_PROBE) printk(KERN_DEBUG PFX "media set to %sMbit mode.\n", (media & 1) ? "1" : "10"); a->write_bcr(ioaddr, 49, media); break; case 0x2627: chipname = "PCnet/FAST III 79C975"; /* PCI */ fdx = 1; mii = 1; break; case 0x2628: chipname = "PCnet/PRO 79C976"; fdx = 1; mii = 1; break; default: if (pcnet32_debug & NETIF_MSG_PROBE) printk(KERN_INFO PFX "PCnet version %#x, no PCnet32 chip.\n", chip_version); goto err_release_region; } /* * On selected chips turn on the BCR18:NOUFLO bit. This stops transmit * starting until the packet is loaded. Strike one for reliability, lose * one for latency - although on PCI this isnt a big loss. Older chips * have FIFO's smaller than a packet, so you can't do this. * Turn on BCR18:BurstRdEn and BCR18:BurstWrEn. */ if (fset) { a->write_bcr(ioaddr, 18, (a->read_bcr(ioaddr, 18) | 0x0860)); a->write_csr(ioaddr, 80, (a->read_csr(ioaddr, 80) & 0x0C00) | 0x0c00); dxsuflo = 1; } dev = alloc_etherdev(0); if (!dev) { if( pcnet32_debug & NETIF_MSG_PROBE ) printk(KERN_ERR PFX "Memory allocation failed.\n"); ret = -ENOMEM; goto err_release_region; } strcpy( dev->name, "myeth0" ); SET_NETDEV_DEV(dev, &pdev->dev); if (pcnet32_debug & NETIF_MSG_PROBE) printk(KERN_INFO PFX "%s at %#3lx,", chipname, ioaddr); /* In most chips, after a chip reset, the ethernet address is read from the * station address PROM at the base address and programmed into the * "Physical Address Registers" CSR12-14. * As a precautionary measure, we read the PROM values and complain if * they disagree with the CSRs. Either way, we use the CSR values, and * double check that they are valid. */ for (i = 0; i < 3; i++) { unsigned int val; val = a->read_csr(ioaddr, i+12) & 0x0ffff; /* There may be endianness issues here. */ dev->dev_addr[2*i] = val & 0x0ff; dev->dev_addr[2*i+1] = (val >> 8) & 0x0ff; } /* read PROM address and compare with CSR address */ for (i = 0; i < 6; i++) promaddr[i] = inb(ioaddr + i); if (memcmp(promaddr, dev->dev_addr, 6) || !is_valid_ether_addr(dev->dev_addr)) { if (is_valid_ether_addr(promaddr)) { if (pcnet32_debug & NETIF_MSG_PROBE) { printk(" warning: CSR address invalid,\n"); printk(KERN_INFO " using instead PROM address of"); } memcpy(dev->dev_addr, promaddr, 6); } } memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); /* if the ethernet address is not valid, force to 00:00:00:00:00:00 */ if (!is_valid_ether_addr(dev->perm_addr)) memset(dev->dev_addr, 0, sizeof(dev->dev_addr));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -