📄 pcnet32.c
字号:
} lp->a.write_bcr(ioaddr, 9, val); } /* set/reset GPSI bit in test register */ val = lp->a.read_csr(ioaddr, 124) & ~0x10; if ((lp->options & PCNET32_PORT_PORTSEL) == PCNET32_PORT_GPSI) val |= 0x10; lp->a.write_csr(ioaddr, 124, val); if (lp->mii && !(lp->options & PCNET32_PORT_ASEL)) { val = lp->a.read_bcr(ioaddr, 32) & ~0x38; /* disable Auto Negotiation, set 10Mpbs, HD */ if (lp->options & PCNET32_PORT_FD) val |= 0x10; if (lp->options & PCNET32_PORT_100) val |= 0x08; lp->a.write_bcr(ioaddr, 32, val); } else { if (lp->options & PCNET32_PORT_ASEL) { /* enable auto negotiate, setup, disable fd */ val = lp->a.read_bcr(ioaddr, 32) & ~0x98; val |= 0x20; lp->a.write_bcr(ioaddr, 32, val); } }#ifdef DO_DXSUFLO if (lp->dxsuflo) { /* Disable transmit stop on underflow */ val = lp->a.read_csr(ioaddr, 3); val |= 0x40; lp->a.write_csr(ioaddr, 3, val); }#endif if (lp->ltint) { /* Enable TxDone-intr inhibitor */ val = lp->a.read_csr(ioaddr, 5); val |= (1 << 14); lp->a.write_csr(ioaddr, 5, val); } lp->init_block.mode = le16_to_cpu((lp->options & PCNET32_PORT_PORTSEL) << 7); lp->init_block.filter[0] = 0xffffffff; lp->init_block.filter[1] = 0xffffffff; pcnet32_init_ring(nic); /* Re-initialize the PCNET32, and start it when done. */ lp->a.write_csr(ioaddr, 1, (virt_to_bus(&lp->init_block)) & 0xffff); lp->a.write_csr(ioaddr, 2, (virt_to_bus(&lp->init_block)) >> 16); lp->a.write_csr(ioaddr, 4, 0x0915); lp->a.write_csr(ioaddr, 0, 0x0001); i = 0; while (i++ < 100) if (lp->a.read_csr(ioaddr, 0) & 0x0100) break; /* * We used to clear the InitDone bit, 0x0100, here but Mark Stockton * reports that doing so triggers a bug in the '974. */ lp->a.write_csr(ioaddr, 0, 0x0042); printf("pcnet32 open, csr0 %hX.\n", lp->a.read_csr(ioaddr, 0));}/**************************************************************************POLL - Wait for a frame***************************************************************************/static int pcnet32_poll(struct nic *nic __unused){ /* return true if there's an ethernet packet ready to read */ /* nic->packet should contain data on return */ /* nic->packetlen should contain length of data */ int status; int entry; entry = lp->cur_rx & RX_RING_MOD_MASK; status = ((short) le16_to_cpu(rx_ring[entry].status) >> 8); if (status < 0) return 0; if (status == 0x03) { nic->packetlen = (le32_to_cpu(rx_ring[entry].msg_length) & 0xfff) - 4; memcpy(nic->packet, &rxb[entry], nic->packetlen); /* Andrew Boyd of QNX reports that some revs of the 79C765 * clear the buffer length */ rx_ring[entry].buf_length = le16_to_cpu(-PKT_BUF_SZ); rx_ring[entry].status |= le16_to_cpu(0x8000); /* prime for next receive */ /* Switch to the next Rx ring buffer */ lp->cur_rx++; } else { return 0; } return 1;}/**************************************************************************TRANSMIT - Transmit a frame***************************************************************************/static void pcnet32_transmit(struct nic *nic __unused, const char *d, /* Destination */ unsigned int t, /* Type */ unsigned int s, /* size */ const char *p){ /* Packet */ /* send the packet to destination */ unsigned long time; u8 *ptxb; u16 nstype; u16 status; int entry = 0; /*lp->cur_tx & TX_RING_MOD_MASK; */ status = 0x8300; /* point to the current txb incase multiple tx_rings are used */ ptxb = txb + (lp->cur_tx * PKT_BUF_SZ); /* copy the packet to ring buffer */ memcpy(ptxb, d, ETH_ALEN); /* dst */ memcpy(ptxb + ETH_ALEN, nic->node_addr, ETH_ALEN); /* src */ nstype = htons((u16) t); /* type */ memcpy(ptxb + 2 * ETH_ALEN, (u8 *) & nstype, 2); /* type */ memcpy(ptxb + ETH_HLEN, p, s); s += ETH_HLEN; while (s < ETH_ZLEN) /* pad to min length */ ptxb[s++] = '\0'; tx_ring[entry].length = le16_to_cpu(-s); tx_ring[entry].misc = 0x00000000; tx_ring[entry].base = (u32) virt_to_le32desc(ptxb); /* we set the top byte as the very last thing */ tx_ring[entry].status = le16_to_cpu(status); /* Trigger an immediate send poll */ lp->a.write_csr(ioaddr, 0, 0x0048); /* wait for transmit complete */ lp->cur_tx = 0; /* (lp->cur_tx + 1); */ time = currticks() + TICKS_PER_SEC; /* wait one second */ while (currticks() < time && ((short) le16_to_cpu(tx_ring[entry].status) < 0)); if ((short) le16_to_cpu(tx_ring[entry].status) < 0) printf("PCNET32 timed out on transmit\n"); /* Stop pointing at the current txb * otherwise the card continues to send the packet */ tx_ring[entry].base = 0;}/**************************************************************************DISABLE - Turn off ethernet interface***************************************************************************/#ifdef EB50static void pcnet32_disable(struct nic *nic __unused)#elsestatic void pcnet32_disable(struct dev *dev __unused)#endif{ /* Stop the PCNET32 here -- it ocassionally polls memory if we don't */ lp->a.write_csr(ioaddr, 0, 0x0004); /* * Switch back to 16-bit mode to avoid problesm with dumb * DOS packet driver after a warm reboot */ lp->a.write_bcr(ioaddr, 20, 4);}/**************************************************************************PROBE - Look for an adapter, this routine's visible to the outsideYou should omit the last argument struct pci_device * for a non-PCI NIC***************************************************************************/#ifdef EB50struct nic *pcnet32_probe(struct nic *nic, unsigned short *io_addr, struct pci_device *pci){#elsestatic int pcnet32_probe(struct dev *dev, struct pci_device *pci){ struct nic *nic = (struct nic *) dev;#endif int i, media; int fdx, mii, fset, dxsuflo, ltint; int chip_version; char *chipname; /* struct net_device *dev; */ struct pcnet32_access *a = NULL; u8 promaddr[6]; int shared = 1; if (pci->ioaddr == 0) return 0; /* BASE is used throughout to address the card */ ioaddr = pci->ioaddr; printf("\n"); printf("pcnet32.c: %s, %s\n", drv_version, drv_date); printf("%s: Probing for Vendor=%hX Device=%hX\n", pci->name, pci->vendor, pci->dev_id); /* 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 /* return -ENODEV; */ return 0; } chip_version = a->read_csr(ioaddr, 88) | (a->read_csr(ioaddr, 89) << 16); printf("PCnet chip version is %#x.\n", chip_version); if ((chip_version & 0xfff) != 0x003) /*return -ENODEV; */ return 0; /* initialize variables */ fdx = mii = fset = dxsuflo = ltint = 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; 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); printf("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: printf("PCnet version %#x, no PCnet32 chip.\n", chip_version); /* return -ENODEV; */ return 0; } /* * 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); dxsuflo = 1; ltint = 1; } printf("%s at %hX,", chipname, ioaddr); /* read PROM address */ for (i = 0; i < 6; i++) promaddr[i] = inb(ioaddr + i); /* Update the nic structure with the MAC Address */ for (i = 0; i < ETH_ALEN; i++) { nic->node_addr[i] = promaddr[i]; } /* Print out some hardware info */ printf("%s: %! at ioaddr %hX\n", pci->name, nic->node_addr, ioaddr); /* I really must find out what this does */ adjust_pci_device(pci); /* point to private storage */ lp = &lpx; if (((chip_version + 1) & 0xfffe) == 0x2624) { /* Version 0x2623 or 0x2624 */ i = a->read_csr(ioaddr, 80) & 0x0C00; /* Check tx_start_pt */ printf(" tx_start_pt(0x%hX):", i); switch (i >> 10) { case 0: printf(" 20 bytes,"); break; case 1: printf(" 64 bytes,"); break; case 2: printf(" 128 bytes,"); break; case 3: printf("~220 bytes,"); break; } i = a->read_bcr(ioaddr, 18); /* Check Burst/Bus control */ printf(" BCR18(%hX):", i & 0xffff); if (i & (1 << 5)) printf("BurstWrEn "); if (i & (1 << 6)) printf("BurstRdEn "); if (i & (1 << 7)) printf("DWordIO "); if (i & (1 << 11)) printf("NoUFlow "); i = a->read_bcr(ioaddr, 25); printf(" SRAMSIZE=0x%hX,", i << 8); i = a->read_bcr(ioaddr, 26); printf(" SRAM_BND=0x%hX,", i << 8); i = a->read_bcr(ioaddr, 27); if (i & (1 << 14)) printf("LowLatRx"); } lp = &lpx; lp->name = chipname; lp->shared_irq = shared; lp->full_duplex = fdx; lp->dxsuflo = dxsuflo; lp->ltint = ltint; lp->mii = mii; if ((cards_found >= MAX_UNITS) || (options[cards_found] > sizeof(options_mapping))) lp->options = PCNET32_PORT_ASEL; else lp->options = options_mapping[options[cards_found]]; if (fdx && !(lp->options & PCNET32_PORT_ASEL) && ((cards_found >= MAX_UNITS) || full_duplex[cards_found])) lp->options |= PCNET32_PORT_FD; if (!a) { printf("No access methods\n"); return 0; } lp->a = *a; /* detect special T1/E1 WAN card by checking for MAC address */ if (nic->node_addr[0] == 0x00 && nic->node_addr[1] == 0xe0 && nic->node_addr[2] == 0x75) lp->options = PCNET32_PORT_FD | PCNET32_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] = nic->node_addr[i]; lp->init_block.filter[0] = 0xffffffff; lp->init_block.filter[1] = 0xffffffff; lp->init_block.rx_ring = virt_to_bus(&rx_ring); lp->init_block.tx_ring = virt_to_bus(&tx_ring); /* switch pcnet32 to 32bit mode */ a->write_bcr(ioaddr, 20, 2); a->write_csr(ioaddr, 1, (virt_to_bus(&lp->init_block)) & 0xffff); a->write_csr(ioaddr, 2, (virt_to_bus(&lp->init_block)) >> 16); /* * 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); cards_found++; /* point to NIC specific routines */ pcnet32_reset(nic);#ifdef EB50 nic->poll = pcnet32_poll; nic->transmit = pcnet32_transmit; nic->disable = pcnet32_disable; return nic;#else nic->poll = pcnet32_poll; nic->transmit = pcnet32_transmit; dev->disable = pcnet32_disable; return 1;#endif}#ifndef EB50static struct pci_id pcnet32_nics[] = { PCI_ROM(0x1022, 0x2000, "lancepci", "AMD Lance/PCI"), PCI_ROM(0x1022, 0x2625, "pcnetfastiii", "AMD Lance/PCI PCNet/32"), PCI_ROM(0x1022, 0x2001, "amdhomepna", "AMD Lance/HomePNA"),};static struct pci_driver pcnet32_driver __pci_driver = { .type = NIC_DRIVER, .name = "PCNET32/PCI", .probe = pcnet32_probe, .ids = pcnet32_nics, .id_count = sizeof(pcnet32_nics) / sizeof(pcnet32_nics[0]), .class = 0,};#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -