📄 eepro100.c
字号:
txfd.count = 0x02208000; txfd.tx_desc_addr = virt_to_bus(&txfd.tx_buf_addr0); txfd.tx_buf_addr0 = virt_to_bus (&hdr); txfd.tx_buf_size0 = sizeof (hdr); txfd.tx_buf_addr1 = virt_to_bus (p); txfd.tx_buf_size1 = s;#ifdef DEBUG printf ("txfd: \n"); hd (&txfd, sizeof (txfd));#endif outl(virt_to_bus(&txfd), ioaddr + SCBPointer); outw(INT_MASK | CU_START, ioaddr + SCBCmd); wait_for_cmd_done(ioaddr + SCBCmd); s1 = inw (ioaddr + SCBStatus); load_timer2(10*TICKS_PER_MS); /* timeout 10 ms for transmit */ while (!txfd.status && timer2_running()) /* Wait */; s2 = inw (ioaddr + SCBStatus);#ifdef DEBUG printf ("s1 = %hX, s2 = %hX.\n", s1, s2);#endif}/* * Sometimes the receiver stops making progress. This routine knows how to * get it going again, without losing packets or being otherwise nasty like * a chip reset would be. Previously the driver had a whole sequence * of if RxSuspended, if it's no buffers do one thing, if it's no resources, * do another, etc. But those things don't really matter. Separate logic * in the ISR provides for allocating buffers--the other half of operation * is just making sure the receiver is active. speedo_rx_soft_reset does that. * This problem with the old, more involved algorithm is shown up under * ping floods on the order of 60K packets/second on a 100Mbps fdx network. */static voidspeedo_rx_soft_reset(void){ wait_for_cmd_done(ioaddr + SCBCmd); /* * Put the hardware into a known state. */ outb(RX_ABORT, ioaddr + SCBCmd); ACCESS(rxfd)rx_buf_addr = 0xffffffff; wait_for_cmd_done(ioaddr + SCBCmd); outb(RX_START, ioaddr + SCBCmd);}/* function: eepro100_poll / eth_poll * This recieves a packet from the network. * * Arguments: none * * returns: 1 if a packet was recieved. * 0 if no pacet was recieved. * side effects: * returns the packet in the array nic->packet. * returns the length of the packet in nic->packetlen. */static int eepro100_poll(struct nic *nic){ unsigned int status; status = inw(ioaddr + SCBStatus); if (!ACCESS(rxfd)status) return 0; /* * The chip may have suspended reception for various reasons. * Check for that, and re-prime it should this be the case. */ switch ((status >> 2) & 0xf) { case 0: /* Idle */ break; case 1: /* Suspended */ case 2: /* No resources (RxFDs) */ case 9: /* Suspended with no more RBDs */ case 10: /* No resources due to no RBDs */ case 12: /* Ready with no RBDs */ speedo_rx_soft_reset(); break; case 3: case 5: case 6: case 7: case 8: case 11: case 13: case 14: case 15: /* these are all reserved values */ break; } /* Ok. We got a packet. Now restart the reciever.... */ ACCESS(rxfd)status = 0; ACCESS(rxfd)command = 0xc000; outl(virt_to_bus(&(ACCESS(rxfd)status)), ioaddr + SCBPointer); outw(INT_MASK | RX_START, ioaddr + SCBCmd); wait_for_cmd_done(ioaddr + SCBCmd);#ifdef DEBUG printf ("Got a packet: Len = %d.\n", ACCESS(rxfd)count & 0x3fff);#endif nic->packetlen = ACCESS(rxfd)count & 0x3fff; memcpy (nic->packet, ACCESS(rxfd)packet, nic->packetlen);#ifdef DEBUG hd (nic->packet, 0x30);#endif return 1;}/* function: eepro100_disable * resets the card. This is used to allow Etherboot or Linux * to probe the card again from a "virginal" state.... * Arguments: none * * returns: void. */static void eepro100_disable(struct dev *dev __unused){/* from eepro100_reset */ outl(0, ioaddr + SCBPort);/* from eepro100_disable */ /* See if this PartialReset solves the problem with interfering with kernel operation after Etherboot hands over. - Ken 20001102 */ outl(2, ioaddr + SCBPort); /* The following is from the Intel e100 driver. * This hopefully solves the problem with hanging hard DOS images. */ /* wait for the reset to take effect */ udelay(20); /* Mask off our interrupt line -- it is unmasked after reset */ { u16 intr_status; /* Disable interrupts on our PCI board by setting the mask bit */ outw(INT_MASK, ioaddr + SCBCmd); intr_status = inw(ioaddr + SCBStatus); /* ack and clear intrs */ outw(intr_status, ioaddr + SCBStatus); inw(ioaddr + SCBStatus); }}/* exported function: eepro100_probe / eth_probe * initializes a card * * side effects: * leaves the ioaddress of the 82557 chip in the variable ioaddr. * leaves the 82557 initialized, and ready to recieve packets. */static int eepro100_probe(struct dev *dev, struct pci_device *p){ struct nic *nic = (struct nic *)dev; unsigned short sum = 0; int i; int read_cmd, ee_size; int options; int rx_mode; /* we cache only the first few words of the EEPROM data be careful not to access beyond this array */ unsigned short eeprom[16]; if (p->ioaddr == 0) return 0; ioaddr = p->ioaddr & ~3; /* Mask the bit that says "this is an io addr" */ adjust_pci_device(p); if ((do_eeprom_cmd(EE_READ_CMD << 24, 27) & 0xffe0000) == 0xffe0000) { ee_size = 0x100; read_cmd = EE_READ_CMD << 24; } else { ee_size = 0x40; read_cmd = EE_READ_CMD << 22; } for (i = 0, sum = 0; i < ee_size; i++) { unsigned short value = do_eeprom_cmd(read_cmd | (i << 16), 27); if (i < (int)(sizeof(eeprom)/sizeof(eeprom[0]))) eeprom[i] = value; sum += value; } for (i=0;i<ETH_ALEN;i++) { nic->node_addr[i] = (eeprom[i/2] >> (8*(i&1))) & 0xff; } printf ("Ethernet addr: %!\n", nic->node_addr); if (sum != 0xBABA) printf("eepro100: Invalid EEPROM checksum %#hX, " "check settings before activating this device!\n", sum); outl(0, ioaddr + SCBPort); udelay (10000); whereami ("Got eeprom."); /* Base = 0 */ outl(0, ioaddr + SCBPointer); outw(INT_MASK | RX_ADDR_LOAD, ioaddr + SCBCmd); wait_for_cmd_done(ioaddr + SCBCmd); whereami ("set rx base addr."); outl(virt_to_bus(&lstats), ioaddr + SCBPointer); outw(INT_MASK | CU_STATSADDR, ioaddr + SCBCmd); wait_for_cmd_done(ioaddr + SCBCmd); whereami ("set stats addr."); /* INIT RX stuff. */ ACCESS(rxfd)status = 0x0001; ACCESS(rxfd)command = 0x0000; ACCESS(rxfd)link = virt_to_bus(&(ACCESS(rxfd)status)); ACCESS(rxfd)rx_buf_addr = virt_to_bus(&nic->packet); ACCESS(rxfd)count = 0; ACCESS(rxfd)size = 1528; outl(virt_to_bus(&(ACCESS(rxfd)status)), ioaddr + SCBPointer); outw(INT_MASK | RX_START, ioaddr + SCBCmd); wait_for_cmd_done(ioaddr + SCBCmd); whereami ("started RX process."); /* Start the reciever.... */ ACCESS(rxfd)status = 0; ACCESS(rxfd)command = 0xc000; outl(virt_to_bus(&(ACCESS(rxfd)status)), ioaddr + SCBPointer); outw(INT_MASK | RX_START, ioaddr + SCBCmd); /* INIT TX stuff. */ /* Base = 0 */ outl(0, ioaddr + SCBPointer); outw(INT_MASK | CU_CMD_BASE, ioaddr + SCBCmd); wait_for_cmd_done(ioaddr + SCBCmd); whereami ("set TX base addr."); txfd.command = (CmdIASetup); txfd.status = 0x0000; txfd.link = virt_to_bus (&confcmd); { char *t = (char *)&txfd.tx_desc_addr; for (i=0;i<ETH_ALEN;i++) t[i] = nic->node_addr[i]; }#ifdef DEBUG printf ("Setup_eaddr:\n"); hd (&txfd, 0x20);#endif /* options = 0x40; */ /* 10mbps half duplex... */ options = 0x00; /* Autosense */#ifdef PROMISC rx_mode = 3;#elif ALLMULTI rx_mode = 1;#else rx_mode = 0;#endif if ( ((eeprom[6]>>8) & 0x3f) == DP83840 || ((eeprom[6]>>8) & 0x3f) == DP83840A) { int mdi_reg23 = mdio_read(eeprom[6] & 0x1f, 23) | 0x0422; if (congenb) mdi_reg23 |= 0x0100; printf(" DP83840 specific setup, setting register 23 to %hX.\n", mdi_reg23); mdio_write(eeprom[6] & 0x1f, 23, mdi_reg23); } whereami ("Done DP8340 special setup."); if (options != 0) { mdio_write(eeprom[6] & 0x1f, 0, ((options & 0x20) ? 0x2000 : 0) | /* 100mbps? */ ((options & 0x10) ? 0x0100 : 0)); /* Full duplex? */ whereami ("set mdio_register."); } confcmd.command = CmdSuspend | CmdConfigure; confcmd.status = 0x0000; confcmd.link = virt_to_bus (&txfd); confcmd.data[1] = (txfifo << 4) | rxfifo; confcmd.data[4] = rxdmacount; confcmd.data[5] = txdmacount + 0x80; confcmd.data[15] = (rx_mode & 2) ? 0x49: 0x48; confcmd.data[19] = (options & 0x10) ? 0xC0 : 0x80; confcmd.data[21] = (rx_mode & 1) ? 0x0D: 0x05; outl(virt_to_bus(&txfd), ioaddr + SCBPointer); outw(INT_MASK | CU_START, ioaddr + SCBCmd); wait_for_cmd_done(ioaddr + SCBCmd); whereami ("started TX thingy (config, iasetup)."); load_timer2(10*TICKS_PER_MS); while (!txfd.status && timer2_running()) /* Wait */; /* Read the status register once to disgard stale data */ mdio_read(eeprom[6] & 0x1f, 1); /* Check to see if the network cable is plugged in. * This allows for faster failure if there is nothing * we can do. */ if (!(mdio_read(eeprom[6] & 0x1f, 1) & (1 << 2))) { printf("Valid link not established\n"); eepro100_disable(dev); return 0; } dev->disable = eepro100_disable; nic->poll = eepro100_poll; nic->transmit = eepro100_transmit; return 1;}/*********************************************************************/#ifdef DEBUG/* Hexdump a number of bytes from memory... */void hd (void *where, int n){ int i; while (n > 0) { printf ("%X ", where); for (i=0;i < ( (n>16)?16:n);i++) printf (" %hhX", ((char *)where)[i]); printf ("\n"); n -= 16; where += 16; }}#endifstatic struct pci_id eepro100_nics[] = {PCI_ROM(0x8086, 0x1029, "id1029", "Intel EtherExpressPro100 ID1029"),PCI_ROM(0x8086, 0x1030, "id1030", "Intel EtherExpressPro100 ID1030"),PCI_ROM(0x8086, 0x1031, "82801cam", "Intel 82801CAM (ICH3) Chipset Ethernet Controller"),PCI_ROM(0x8086, 0x1032, "eepro100-1032", "Intel PRO/100 VE Network Connection"),PCI_ROM(0x8086, 0x1033, "eepro100-1033", "Intel PRO/100 VM Network Connection"),PCI_ROM(0x8086, 0x1034, "eepro100-1034", "Intel PRO/100 VM Network Connection"),PCI_ROM(0x8086, 0x1035, "eepro100-1035", "Intel 82801CAM (ICH3) Chipset Ethernet Controller"),PCI_ROM(0x8086, 0x1036, "eepro100-1036", "Intel 82801CAM (ICH3) Chipset Ethernet Controller"),PCI_ROM(0x8086, 0x1037, "eepro100-1037", "Intel 82801CAM (ICH3) Chipset Ethernet Controller"),PCI_ROM(0x8086, 0x1038, "id1038", "Intel PRO/100 VM Network Connection"),PCI_ROM(0x8086, 0x1039, "82562et", "Intel PRO100 VE 82562ET"),PCI_ROM(0x8086, 0x103a, "id103a", "Intel Corporation 82559 InBusiness 10/100"),PCI_ROM(0x8086, 0x103b, "82562etb", "Intel PRO100 VE 82562ETB"),PCI_ROM(0x8086, 0x103c, "eepro100-103c", "Intel PRO/100 VM Network Connection"),PCI_ROM(0x8086, 0x103d, "eepro100-103d", "Intel PRO/100 VE Network Connection"),PCI_ROM(0x8086, 0x103e, "eepro100-103e", "Intel PRO/100 VM Network Connection"),PCI_ROM(0x8086, 0x1059, "82551qm", "Intel PRO/100 M Mobile Connection"),PCI_ROM(0x8086, 0x1209, "82559er", "Intel EtherExpressPro100 82559ER"),PCI_ROM(0x8086, 0x1227, "82865", "Intel 82865 EtherExpress PRO/100A"),PCI_ROM(0x8086, 0x1228, "82556", "Intel 82556 EtherExpress PRO/100 Smart"),PCI_ROM(0x8086, 0x1229, "eepro100", "Intel EtherExpressPro100"),PCI_ROM(0x8086, 0x2449, "82562em", "Intel EtherExpressPro100 82562EM"),PCI_ROM(0x8086, 0x2459, "82562-1", "Intel 82562 based Fast Ethernet Connection"),PCI_ROM(0x8086, 0x245d, "82562-2", "Intel 82562 based Fast Ethernet Connection"),PCI_ROM(0x8086, 0x1050, "82562ez", "Intel 82562EZ Network Connection"),PCI_ROM(0x8086, 0x5200, "eepro100-5200", "Intel EtherExpress PRO/100 Intelligent Server"),PCI_ROM(0x8086, 0x5201, "eepro100-5201", "Intel EtherExpress PRO/100 Intelligent Server"),};/* Cards with device ids 0x1030 to 0x103F, 0x2449, 0x2459 or 0x245D might need * a workaround for hardware bug on 10 mbit half duplex (see linux driver eepro100.c) * 2003/03/17 gbaum */static struct pci_driver eepro100_driver __pci_driver = { .type = NIC_DRIVER, .name = "EEPRO100", .probe = eepro100_probe, .ids = eepro100_nics, .id_count = sizeof(eepro100_nics)/sizeof(eepro100_nics[0]), .class = 0};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -