📄 pcnet32.c
字号:
outl (val, addr+PCNET32_DWIO_RDP);}static u16 pcnet32_dwio_read_bcr (unsigned long addr, int index){ outl (index, addr+PCNET32_DWIO_RAP); return (inl (addr+PCNET32_DWIO_BDP) & 0xffff);}static void pcnet32_dwio_write_bcr (unsigned long addr, int index, u16 val){ outl (index, addr+PCNET32_DWIO_RAP); outl (val, addr+PCNET32_DWIO_BDP);}static u16 pcnet32_dwio_read_rap (unsigned long addr){ return (inl (addr+PCNET32_DWIO_RAP) & 0xffff);}static void pcnet32_dwio_write_rap (unsigned long addr, u16 val){ outl (val, addr+PCNET32_DWIO_RAP);}static void pcnet32_dwio_reset (unsigned long addr){ inl (addr+PCNET32_DWIO_RESET);}static int pcnet32_dwio_check (unsigned long addr){ outl (88, addr+PCNET32_DWIO_RAP); return (inl (addr+PCNET32_DWIO_RAP) == 88);}static struct pcnet32_access pcnet32_dwio = { pcnet32_dwio_read_csr, pcnet32_dwio_write_csr, pcnet32_dwio_read_bcr, pcnet32_dwio_write_bcr, pcnet32_dwio_read_rap, pcnet32_dwio_write_rap, pcnet32_dwio_reset};/* only probes for non-PCI devices, the rest are handled by pci_register_driver via pcnet32_probe_pci*/static int __init pcnet32_probe_vlbus(int cards_found){ unsigned long ioaddr = 0; // FIXME dev ? dev->base_addr: 0; unsigned int irq_line = 0; // FIXME dev ? dev->irq : 0; int *port; printk(KERN_INFO "pcnet32_probe_vlbus: cards_found=%d\n", cards_found);#ifndef __powerpc__ if (ioaddr > 0x1ff) { if (check_region(ioaddr, PCNET32_TOTAL_SIZE) == 0) return pcnet32_probe1(ioaddr, irq_line, 0, 0, NULL); else return -ENODEV; } else#endif if (ioaddr != 0) return -ENXIO; /* now look for PCnet32 VLB cards */ for (port = pcnet32_portlist; *port; port++) { unsigned long ioaddr = *port; if ( check_region(ioaddr, PCNET32_TOTAL_SIZE) == 0) { /* check if there is really a pcnet chip on that ioaddr */ if ((inb(ioaddr + 14) == 0x57) && (inb(ioaddr + 15) == 0x57) && (pcnet32_probe1(ioaddr, 0, 0, 0, NULL) == 0)) cards_found++; } } return cards_found ? 0: -ENODEV;}static int __initpcnet32_probe_pci(struct pci_dev *pdev, const struct pci_device_id *ent){ static int card_idx; long ioaddr; int err = 0; printk(KERN_INFO "pcnet32_probe_pci: found device %#08x.%#08x\n", ent->vendor, ent->device); ioaddr = pci_resource_start (pdev, 0); printk(KERN_INFO " ioaddr=%#08lx resource_flags=%#08lx\n", ioaddr, pci_resource_flags (pdev, 0)); if (!ioaddr) { printk (KERN_ERR "no PCI IO resources, aborting\n"); return -ENODEV; } if (!pci_dma_supported(pdev, PCNET32_DMA_MASK)) { printk(KERN_ERR "pcnet32.c: architecture does not support 32bit PCI busmaster DMA\n"); return -ENODEV; } if ((err = pci_enable_device(pdev)) < 0) { printk(KERN_ERR "pcnet32.c: failed to enable device -- err=%d\n", err); return err; } pci_set_master(pdev); return pcnet32_probe1(ioaddr, pdev->irq, 1, card_idx, pdev);}/* pcnet32_probe1 * Called from both pcnet32_probe_vlbus and pcnet_probe_pci. * pdev will be NULL when called from pcnet32_probe_vlbus. */static int __initpcnet32_probe1(unsigned long ioaddr, unsigned char irq_line, int shared, int card_idx, struct pci_dev *pdev){ struct pcnet32_private *lp; dma_addr_t lp_dma_addr; int i,media,fdx = 0, mii = 0, fset = 0;#ifdef DO_DXSUFLO int dxsuflo = 0;#endif int ltint = 0; int chip_version; char *chipname; struct net_device *dev; struct pcnet32_access *a = NULL; /* reset the chip */ pcnet32_dwio_reset(ioaddr); pcnet32_wio_reset(ioaddr); if (pcnet32_wio_read_csr (ioaddr, 0) == 4 && pcnet32_wio_check (ioaddr)) { a = &pcnet32_wio; } else { if (pcnet32_dwio_read_csr (ioaddr, 0) == 4 && pcnet32_dwio_check(ioaddr)) { a = &pcnet32_dwio; } else return -ENODEV; } chip_version = a->read_csr (ioaddr, 88) | (a->read_csr (ioaddr,89) << 16); if (pcnet32_debug > 2) printk(KERN_INFO " PCnet chip version is %#x.\n", chip_version); if ((chip_version & 0xfff) != 0x003) return -ENODEV; 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; ltint = 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 1Mb HomePNA * mode. The 79C978 can also go into standard ethernet, and there * probably should be some sort of module option to select the * mode by which the card should operate */ /* switch to home wiring mode */ media = a->read_bcr (ioaddr, 49);#if 0 if (pcnet32_debug > 2) printk(KERN_DEBUG "pcnet32: pcnet32 media value %#x.\n", media); media &= ~3; media |= 1;#endif if (pcnet32_debug > 2) printk(KERN_DEBUG "pcnet32: pcnet32 media reset to %#x.\n", media); a->write_bcr (ioaddr, 49, media); break; case 0x2627: chipname = "PCnet/FAST III 79C975"; /* PCI */ fdx = 1; mii = 1; break; default: printk(KERN_INFO "pcnet32: PCnet version %#x, no PCnet32 chip.\n",chip_version); return -ENODEV; } /* * 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. */ if(fset) { a->write_bcr(ioaddr, 18, (a->read_bcr(ioaddr, 18) | 0x0800)); a->write_csr(ioaddr, 80, (a->read_csr(ioaddr, 80) & 0x0C00) | 0x0c00);#ifdef DO_DXSUFLO dxsuflo = 1;#endif ltint = 1; } dev = init_etherdev(NULL, 0); if(dev==NULL) return -ENOMEM; printk(KERN_INFO "%s: %s at %#3lx,", dev->name, chipname, ioaddr); /* There is a 16 byte station address PROM at the base address. The first six bytes are the station address. */ for (i = 0; i < 6; i++) printk(" %2.2x", dev->dev_addr[i] = inb(ioaddr + i)); if (((chip_version + 1) & 0xfffe) == 0x2624) { /* Version 0x2623 or 0x2624 */ i = a->read_csr(ioaddr, 80) & 0x0C00; /* Check tx_start_pt */ printk("\n" KERN_INFO " tx_start_pt(0x%04x):",i); switch(i>>10) { case 0: printk(" 20 bytes,"); break; case 1: printk(" 64 bytes,"); break; case 2: printk(" 128 bytes,"); break; case 3: printk("~220 bytes,"); break; } i = a->read_bcr(ioaddr, 18); /* Check Burst/Bus control */ printk(" BCR18(%x):",i&0xffff); if (i & (1<<5)) printk("BurstWrEn "); if (i & (1<<6)) printk("BurstRdEn "); if (i & (1<<7)) printk("DWordIO "); if (i & (1<<11)) printk("NoUFlow "); i = a->read_bcr(ioaddr, 25); printk("\n" KERN_INFO " SRAMSIZE=0x%04x,",i<<8); i = a->read_bcr(ioaddr, 26); printk(" SRAM_BND=0x%04x,",i<<8); i = a->read_bcr(ioaddr, 27); if (i & (1<<14)) printk("LowLatRx"); } dev->base_addr = ioaddr; request_region(ioaddr, PCNET32_TOTAL_SIZE, chipname); /* pci_alloc_consistent returns page-aligned memory, so we do not have to check the alignment */ if ((lp = (struct pcnet32_private *)pci_alloc_consistent(pdev, sizeof(*lp), &lp_dma_addr)) == NULL) return -ENOMEM; memset(lp, 0, sizeof(*lp)); lp->dma_addr = lp_dma_addr; lp->pci_dev = pdev; printk("\n" KERN_INFO "pcnet32: pcnet32_private lp=%p lp_dma_addr=%#08x", lp, lp_dma_addr); spin_lock_init(&lp->lock); dev->priv = lp; lp->name = chipname; lp->shared_irq = shared; lp->full_duplex = fdx;#ifdef DO_DXSUFLO lp->dxsuflo = dxsuflo;#endif lp->ltint = ltint; lp->mii = mii; if (options[card_idx] > sizeof (options_mapping)) lp->options = PORT_ASEL; else lp->options = options_mapping[options[card_idx]]; if (fdx && !(lp->options & PORT_ASEL) && full_duplex[card_idx]) lp->options |= PORT_FD; if (a == NULL) { printk(KERN_ERR "pcnet32: No access methods\n"); return -ENODEV; } lp->a = *a; /* detect special T1/E1 WAN card by checking for MAC address */ if (dev->dev_addr[0] == 0x00 && dev->dev_addr[1] == 0xe0 && dev->dev_addr[2] == 0x75) lp->options = PORT_FD | PORT_GPSI; lp->init_block.mode = le16_to_cpu(0x0003); /* Disable Rx and Tx. */ lp->init_block.tlen_rlen = le16_to_cpu(TX_RING_LEN_BITS | RX_RING_LEN_BITS); for (i = 0; i < 6; i++) lp->init_block.phys_addr[i] = dev->dev_addr[i]; lp->init_block.filter[0] = 0x00000000; lp->init_block.filter[1] = 0x00000000; lp->init_block.rx_ring = (u32)le32_to_cpu(lp->dma_addr + offsetof(struct pcnet32_private, rx_ring)); lp->init_block.tx_ring = (u32)le32_to_cpu(lp->dma_addr + offsetof(struct pcnet32_private, tx_ring)); /* switch pcnet32 to 32bit mode */ a->write_bcr (ioaddr, 20, 2); a->write_csr (ioaddr, 1, (lp->dma_addr + offsetof(struct pcnet32_private, init_block)) & 0xffff); a->write_csr (ioaddr, 2, (lp->dma_addr + offsetof(struct pcnet32_private, init_block)) >> 16); if (irq_line) { dev->irq = irq_line; } if (dev->irq >= 2) printk(" assigned IRQ %d.\n", dev->irq); else { unsigned long irq_mask = probe_irq_on(); /* * To auto-IRQ we enable the initialization-done and DMA error * interrupts. For ISA boards we get a DMA error, but VLB and PCI * boards will work. */ /* Trigger an initialization just for the interrupt. */ a->write_csr (ioaddr, 0, 0x41); mdelay (1); dev->irq = probe_irq_off (irq_mask); if (dev->irq) printk(", probed IRQ %d.\n", dev->irq); else { printk(", failed to detect IRQ line.\n"); return -ENODEV; } } if (pcnet32_debug > 0) printk(KERN_INFO "%s", version); /* The PCNET32-specific entries in the device structure. */ dev->open = &pcnet32_open; dev->hard_start_xmit = &pcnet32_start_xmit; dev->stop = &pcnet32_close; dev->get_stats = &pcnet32_get_stats; dev->set_multicast_list = &pcnet32_set_multicast_list;#ifdef HAVE_PRIVATE_IOCTL dev->do_ioctl = &pcnet32_mii_ioctl;#endif dev->tx_timeout = pcnet32_tx_timeout; dev->watchdog_timeo = (HZ >> 1); lp->next = pcnet32_dev; pcnet32_dev = dev; /* Fill in the generic fields of the device structure. */ ether_setup(dev); return 0;}static intpcnet32_open(struct net_device *dev){ struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv; unsigned long ioaddr = dev->base_addr; u16 val; int i; if (dev->irq == 0 || request_irq(dev->irq, &pcnet32_interrupt, lp->shared_irq ? SA_SHIRQ : 0, lp->name, (void *)dev)) { return -EAGAIN; } /* Reset the PCNET32 */ lp->a.reset (ioaddr); /* switch pcnet32 to 32bit mode */ lp->a.write_bcr (ioaddr, 20, 2);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -