📄 eepro100.c
字号:
static struct enet_statistics *speedo_get_stats(struct device *dev);static int speedo_ioctl(struct device *dev, struct ifreq *rq, int cmd);static void set_rx_mode(struct device *dev);/* The parameters that may be passed in... *//* 'options' is used to pass a transceiver override or full-duplex flag e.g. "options=16" for FD, "options=32" for 100mbps-only. */static int full_duplex[] = {-1, -1, -1, -1, -1, -1, -1, -1};static int options[] = {-1, -1, -1, -1, -1, -1, -1, -1};#ifdef MODULEstatic int debug = -1; /* The debug level */#endif#ifdef honor_default_port/* Optional driver feature to allow forcing the transceiver setting. Not recommended. */static int mii_ctrl[8] = { 0x3300, 0x3100, 0x0000, 0x0100, 0x2000, 0x2100, 0x0400, 0x3100};#endif/* A list of all installed Speedo devices, for removing the driver module. */static struct device *root_speedo_dev = NULL;int eepro100_init(struct device *dev){ int cards_found = 0; static int pci_index = 0; if (! pcibios_present()) return cards_found; for (; pci_index < 8; pci_index++) { unsigned char pci_bus, pci_device_fn, pci_latency; long ioaddr; int irq; u16 pci_command, new_command; if (pcibios_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82557, pci_index, &pci_bus, &pci_device_fn)) break; { struct pci_dev *pdev = pci_find_slot(pci_bus, pci_device_fn); ioaddr = pdev->base_address[1]; /* Use [0] to mem-map */ irq = pdev->irq; } /* Remove I/O space marker in bit 0. */ ioaddr &= ~3; if (speedo_debug > 2) printk("Found Intel i82557 PCI Speedo at I/O %#lx, IRQ %d.\n", ioaddr, irq); /* Get and check the bus-master and latency values. */ pcibios_read_config_word(pci_bus, pci_device_fn, PCI_COMMAND, &pci_command); new_command = pci_command | PCI_COMMAND_MASTER|PCI_COMMAND_IO; if (pci_command != new_command) { printk(KERN_INFO " The PCI BIOS has not enabled this" " device! Updating PCI command %4.4x->%4.4x.\n", pci_command, new_command); pcibios_write_config_word(pci_bus, pci_device_fn, PCI_COMMAND, new_command); } pcibios_read_config_byte(pci_bus, pci_device_fn, PCI_LATENCY_TIMER, &pci_latency); if (pci_latency < 32) { printk(" PCI latency timer (CFLT) is unreasonably low at %d." " Setting to 32 clocks.\n", pci_latency); pcibios_write_config_byte(pci_bus, pci_device_fn, PCI_LATENCY_TIMER, 32); } else if (speedo_debug > 1) printk(" PCI latency timer (CFLT) is %#x.\n", pci_latency); speedo_found1(dev, ioaddr, irq, cards_found); dev = NULL; cards_found++; } return cards_found;}static void speedo_found1(struct device *dev, long ioaddr, int irq, int card_idx){ static int did_version = 0; /* Already printed version info. */ struct speedo_private *sp; char *product; int i, option; u16 eeprom[0x40]; if (speedo_debug > 0 && did_version++ == 0) printk(version); dev = init_etherdev(dev, sizeof(struct speedo_private)); if (dev->mem_start > 0) option = dev->mem_start; else if (card_idx >= 0 && options[card_idx] >= 0) option = options[card_idx]; else option = 0; /* Read the station address EEPROM before doing the reset. Perhaps this should even be done before accepting the device, then we wouldn't have a device name with which to report the error. */ { u16 sum = 0; int j; int addr_len = read_eeprom(ioaddr, 0, 6) == 0xffff ? 8 : 6; for (j = 0, i = 0; i < 0x40; i++) { u16 value = read_eeprom(ioaddr, i, addr_len); eeprom[i] = value; sum += value; if (i < 3) { dev->dev_addr[j++] = value; dev->dev_addr[j++] = value >> 8; } } if (sum != 0xBABA) printk(KERN_WARNING "%s: Invalid EEPROM checksum %#4.4x, " "check settings before activating this device!\n", dev->name, sum); /* Don't unregister_netdev(dev); as the EEPro may actually be usable, especially if the MAC address is set later. */ } /* Reset the chip: stop Tx and Rx processes and clear counters. This takes less than 10usec and will easily finish before the next action. */ outl(0, ioaddr + SCBPort); if (eeprom[3] & 0x0100) product = "OEM i82557/i82558 10/100 Ethernet"; else product = "Intel EtherExpress Pro 10/100"; printk(KERN_INFO "%s: %s at %#3lx, ", dev->name, product, ioaddr); for (i = 0; i < 5; i++) printk("%2.2X:", dev->dev_addr[i]); printk("%2.2X, IRQ %d.\n", dev->dev_addr[i], irq);#ifndef kernel_bloat /* OK, this is pure kernel bloat. I don't like it when other drivers waste non-pageable kernel space to emit similar messages, but I need them for bug reports. */ { const char *connectors[] = {" RJ45", " BNC", " AUI", " MII"}; /* The self-test results must be paragraph aligned. */ s32 str[6], *volatile self_test_results; int boguscnt = 16000; /* Timeout for set-test. */ if (eeprom[3] & 0x03) printk(KERN_INFO " Receiver lock-up bug exists -- enabling" " work-around.\n"); printk(KERN_INFO " Board assembly %4.4x%2.2x-%3.3d, Physical" " connectors present:", eeprom[8], eeprom[9]>>8, eeprom[9] & 0xff); for (i = 0; i < 4; i++) if (eeprom[5] & (1<<i)) printk(connectors[i]); printk("\n"KERN_INFO" Primary interface chip %s PHY #%d.\n", phys[(eeprom[6]>>8)&15], eeprom[6] & 0x1f); if (eeprom[7] & 0x0700) printk(KERN_INFO " Secondary interface chip %s.\n", phys[(eeprom[7]>>8)&7]); if (((eeprom[6]>>8) & 0x3f) == DP83840 || ((eeprom[6]>>8) & 0x3f) == DP83840A) { int mdi_reg23 = mdio_read(ioaddr, eeprom[6] & 0x1f, 23) | 0x0422; if (congenb) mdi_reg23 |= 0x0100; printk(KERN_INFO" DP83840 specific setup, setting register 23 to %4.4x.\n", mdi_reg23); mdio_write(ioaddr, eeprom[6] & 0x1f, 23, mdi_reg23); } if ((option >= 0) && (option & 0x70)) { printk(KERN_INFO " Forcing %dMbs %s-duplex operation.\n", (option & 0x20 ? 100 : 10), (option & 0x10 ? "full" : "half")); mdio_write(ioaddr, eeprom[6] & 0x1f, 0, ((option & 0x20) ? 0x2000 : 0) | /* 100mbps? */ ((option & 0x10) ? 0x0100 : 0)); /* Full duplex? */ } /* Perform a system self-test. */ self_test_results = (s32*) ((((long) str) + 15) & ~0xf); self_test_results[0] = 0; self_test_results[1] = -1; outl(virt_to_bus(self_test_results) | 1, ioaddr + SCBPort); do { udelay(10); } while (self_test_results[1] == -1 && --boguscnt >= 0); if (boguscnt < 0) { /* Test optimized out. */ printk(KERN_ERR "Self test failed, status %8.8x:\n" KERN_ERR " Failure to initialize the i82557.\n" KERN_ERR " Verify that the card is a bus-master" " capable slot.\n", self_test_results[1]); } else printk(KERN_INFO " General self-test: %s.\n" KERN_INFO " Serial sub-system self-test: %s.\n" KERN_INFO " Internal registers self-test: %s.\n" KERN_INFO " ROM checksum self-test: %s (%#8.8x).\n", self_test_results[1] & 0x1000 ? "failed" : "passed", self_test_results[1] & 0x0020 ? "failed" : "passed", self_test_results[1] & 0x0008 ? "failed" : "passed", self_test_results[1] & 0x0004 ? "failed" : "passed", self_test_results[0]); }#endif /* kernel_bloat */ /* We do a request_region() only to register /proc/ioports info. */ request_region(ioaddr, SPEEDO3_TOTAL_SIZE, "Intel Speedo3 Ethernet"); dev->base_addr = ioaddr; dev->irq = irq; if (dev->priv == NULL) dev->priv = kmalloc(sizeof(*sp), GFP_KERNEL); sp = dev->priv; memset(sp, 0, sizeof(*sp)); sp->next_module = root_speedo_dev; root_speedo_dev = dev; sp->full_duplex = option >= 0 && (option & 0x10) ? 1 : 0; if (card_idx >= 0) { if (full_duplex[card_idx] >= 0) sp->full_duplex = full_duplex[card_idx]; } sp->default_port = option >= 0 ? (option & 0x0f) : 0; sp->phy[0] = eeprom[6]; sp->phy[1] = eeprom[7]; sp->rx_bug = (eeprom[3] & 0x03) == 3 ? 0 : 1; if (sp->rx_bug) printk(KERN_INFO " Receiver lock-up workaround activated.\n"); /* The Speedo-specific entries in the device structure. */ dev->open = &speedo_open; dev->hard_start_xmit = &speedo_start_xmit; dev->stop = &speedo_close; dev->get_stats = &speedo_get_stats; dev->set_multicast_list = &set_rx_mode; dev->do_ioctl = &speedo_ioctl; return;}/* Serial EEPROM section. A "bit" grungy, but we work our way through bit-by-bit :->. *//* EEPROM_Ctrl bits. */#define EE_SHIFT_CLK 0x01 /* EEPROM shift clock. */#define EE_CS 0x02 /* EEPROM chip select. */#define EE_DATA_WRITE 0x04 /* EEPROM chip data in. */#define EE_WRITE_0 0x01#define EE_WRITE_1 0x05#define EE_DATA_READ 0x08 /* EEPROM chip data out. */#define EE_ENB (0x4800 | EE_CS)/* Delay between EEPROM clock transitions. This will actually work with no delay on 33Mhz PCI. */#define eeprom_delay(nanosec) udelay(1);/* The EEPROM commands include the alway-set leading bit. */#define EE_WRITE_CMD (5 << addr_len)#define EE_READ_CMD (6 << addr_len)#define EE_ERASE_CMD (7 << addr_len)static int read_eeprom(long ioaddr, int location, int addr_len){ unsigned short retval = 0; int ee_addr = ioaddr + SCBeeprom; int read_cmd = location | EE_READ_CMD; int i; outw(EE_ENB & ~EE_CS, ee_addr); outw(EE_ENB, ee_addr); /* Shift the read command bits out. */ for (i = 12; i >= 0; i--) { short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0; outw(EE_ENB | dataval, ee_addr); eeprom_delay(100); outw(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr); eeprom_delay(150); } outw(EE_ENB, ee_addr); for (i = 15; i >= 0; i--) { outw(EE_ENB | EE_SHIFT_CLK, ee_addr); eeprom_delay(100); retval = (retval << 1) | ((inw(ee_addr) & EE_DATA_READ) ? 1 : 0); outw(EE_ENB, ee_addr); eeprom_delay(100); } /* Terminate the EEPROM access. */ outw(EE_ENB & ~EE_CS, ee_addr); return retval;}static int mdio_read(long ioaddr, int phy_id, int location){ int val, boguscnt = 64*10; /* <64 usec. to complete, typ 27 ticks */ outl(0x08000000 | (location<<16) | (phy_id<<21), ioaddr + SCBCtrlMDI); do { val = inl(ioaddr + SCBCtrlMDI); if (--boguscnt < 0) { printk(KERN_ERR " mdio_read() timed out with val = %8.8x.\n", val); } } while (! (val & 0x10000000)); return val & 0xffff;}static int mdio_write(long ioaddr, int phy_id, int location, int value){ int val, boguscnt = 64*10; /* <64 usec. to complete, typ 27 ticks */ outl(0x04000000 | (location<<16) | (phy_id<<21) | value, ioaddr + SCBCtrlMDI); do { val = inl(ioaddr + SCBCtrlMDI); if (--boguscnt < 0) { printk(KERN_ERR" mdio_write() timed out with val = %8.8x.\n", val); } } while (! (val & 0x10000000)); return val & 0xffff;}static intspeedo_open(struct device *dev){ struct speedo_private *sp = (struct speedo_private *)dev->priv; long ioaddr = dev->base_addr;#ifdef notdef /* We could reset the chip, but should not need to. */ /* In fact we MUST NOT, unless we also re-do the init */ outl(0, ioaddr + SCBPort); udelay(10);#endif /* This had better be initialized before we initialize the interrupt! */ sp->lock = (spinlock_t) SPIN_LOCK_UNLOCKED; if (speedo_debug > 1) printk(KERN_DEBUG "%s: speedo_open() irq %d.\n", dev->name, dev->irq);#ifdef oh_no_you_dont_unless_you_honour_the_options_passed_in_to_us /* Retrigger negotiation to reset previous errors. */ if ((sp->phy[0] & 0x8000) == 0) { int phy_addr = sp->phy[0] & 0x1f ; /* Use 0x3300 for restarting NWay, other values to force xcvr: 0x0000 10-HD 0x0100 10-FD 0x2000 100-HD 0x2100 100-FD */#ifdef honor_default_port mdio_write(ioaddr, phy_addr, 0, mii_ctrl[dev->default_port & 7]);#else mdio_write(ioaddr, phy_addr, 0, 0x3300);#endif }#endif /* Load the statistics block address. */ wait_for_cmd_done(ioaddr + SCBCmd); outl(virt_to_bus(&sp->lstats), ioaddr + SCBPointer); outw(INT_MASK | CU_STATSADDR, ioaddr + SCBCmd); sp->lstats.done_marker = 0; speedo_init_rx_ring(dev); wait_for_cmd_done(ioaddr + SCBCmd); outl(0, ioaddr + SCBPointer); outw(INT_MASK | RX_ADDR_LOAD, ioaddr + SCBCmd); /* Todo: verify that we must wait for previous command completion. */ wait_for_cmd_done(ioaddr + SCBCmd); outl(virt_to_bus(sp->rx_ringp[0]), ioaddr + SCBPointer); outw(INT_MASK | RX_START, ioaddr + SCBCmd); /* Fill the first command with our physical address. */ { u16 *eaddrs = (u16 *)dev->dev_addr; u16 *setup_frm = (u16 *)&(sp->tx_ring[0].tx_desc_addr); /* Avoid a bug(?!) here by marking the command already completed. */ sp->tx_ring[0].status = ((CmdSuspend | CmdIASetup) << 16) | 0xa000; sp->tx_ring[0].link = virt_to_bus(&(sp->tx_ring[1])); *setup_frm++ = eaddrs[0]; *setup_frm++ = eaddrs[1]; *setup_frm++ = eaddrs[2]; } sp->last_cmd = (struct descriptor *)&sp->tx_ring[0]; sp->cur_tx = 1; sp->dirty_tx = 0; sp->tx_full = 0; wait_for_cmd_done(ioaddr + SCBCmd); outl(0, ioaddr + SCBPointer); outw(INT_MASK | CU_CMD_BASE, ioaddr + SCBCmd);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -