/*===========================================================================* * e1000_init * *===========================================================================*/ PRIVATE void e1000_init(message *mp) { static int first_time = 1; message reply_mess; e1000_t *e; E1000_DEBUG(3, ("e1000: init()\n")); /* Configure PCI devices, if needed. */ if (first_time) { first_time = 0; e1000_init_pci(); } e = &e1000_state; /* Initialize hardware, if needed. */ if (!(e->status & E1000_ENABLED) && !(e1000_init_hw(e))) { reply_mess.m_type = DL_CONF_REPLY; reply_mess.DL_STAT = ENXIO; mess_reply(mp, &reply_mess); return; } /* Reply back to INET. */ reply_mess.m_type = DL_CONF_REPLY; reply_mess.DL_STAT = OK; *(ether_addr_t *) reply_mess.DL_HWADDR = e->address; mess_reply(mp, &reply_mess); }
/* * Handle an interrupt. */ static void e1000_intr(unsigned int __unused mask) { e1000_t *e; u32_t cause; E1000_DEBUG(3, ("e1000: interrupt\n")); e = &e1000_state; /* Reenable interrupts. */ if (sys_irqenable(&e->irq_hook) != OK) panic("failed to re-enable IRQ"); /* Read the Interrupt Cause Read register. */ if ((cause = e1000_reg_read(e, E1000_REG_ICR)) != 0) { if (cause & E1000_REG_ICR_LSC) e1000_link_changed(e); if (cause & (E1000_REG_ICR_RXO | E1000_REG_ICR_RXT)) netdriver_recv(); if (cause & (E1000_REG_ICR_TXQE | E1000_REG_ICR_TXDW)) netdriver_send(); } }
/* * Start ICH8 flash cycle. */ static int eeprom_ich_cycle(e1000_t * e, u32_t timeout) { union ich8_hws_flash_ctrl hsflctl; union ich8_hws_flash_status hsfsts; int ret_val = -1; u32_t i = 0; E1000_DEBUG(3, ("e1000_flash_cycle_ich8lan")); /* Start a cycle by writing 1 in Flash Cycle Go in Hw Flash Control */ hsflctl.regval = E1000_READ_FLASH_REG16(e, ICH_FLASH_HSFCTL); hsflctl.hsf_ctrl.flcgo = 1; E1000_WRITE_FLASH_REG16(e, ICH_FLASH_HSFCTL, hsflctl.regval); /* Wait till the FDONE bit is set to 1 */ do { hsfsts.regval = E1000_READ_FLASH_REG16(e, ICH_FLASH_HSFSTS); if (hsfsts.hsf_status.flcdone == 1) break; tickdelay(1); } while (i++ < timeout); if (hsfsts.hsf_status.flcdone == 1 && hsfsts.hsf_status.flcerr == 0) ret_val = 0; return ret_val; }
/*===========================================================================* * sef_cb_signal_handler * *===========================================================================*/ PRIVATE void sef_cb_signal_handler(int signo) { E1000_DEBUG(3, ("e1000: got signal\n")); /* Only check for termination signal, ignore anything else. */ if (signo != SIGTERM) return; e1000_stop(); }
/* * Try to receive a packet. */ static ssize_t e1000_recv(struct netdriver_data * data, size_t max) { e1000_t *e; e1000_rx_desc_t *desc; unsigned int head, tail, cur; char *ptr; size_t size; e = &e1000_state; /* If the queue head and tail are equal, the queue is empty. */ head = e1000_reg_read(e, E1000_REG_RDH); tail = e1000_reg_read(e, E1000_REG_RDT); E1000_DEBUG(4, ("%s: head=%u, tail=%u\n", e->name, head, tail)); if (head == tail) return SUSPEND; /* Has a packet been received? */ cur = (tail + 1) % e->rx_desc_count; desc = &e->rx_desc[cur]; if (!(desc->status & E1000_RX_STATUS_DONE)) return SUSPEND; /* * HACK: we expect all packets to fit in a single receive buffer. * Eventually, some sort of support to deal with packets spanning * multiple receive descriptors should be added. For now, we panic, * so that we can continue after the restart; this is already an * improvement over freezing (the old behavior of this driver). */ size = desc->length; if (!(desc->status & E1000_RX_STATUS_EOP)) panic("received packet too large"); /* Copy the packet to the caller. */ ptr = e->rx_buffer + cur * E1000_IOBUF_SIZE; if (size > max) size = max; netdriver_copyout(data, 0, ptr, size); /* Reset the descriptor. */ desc->status = 0; /* Increment tail. */ e1000_reg_write(e, E1000_REG_RDT, cur); /* Return the size of the received packet. */ return size; }
/* * Stop the card. */ static void e1000_stop(void) { e1000_t *e; e = &e1000_state; E1000_DEBUG(3, ("%s: stop()\n", e->name)); e1000_reset_hw(e); }
/* * Initialize and return the card's ethernet address. */ static void e1000_init_addr(e1000_t * e, ether_addr_t * addr) { static char eakey[] = E1000_ENVVAR "#_EA"; static char eafmt[] = "x:x:x:x:x:x"; u16_t word; int i; long v; /* Do we have a user defined ethernet address? */ eakey[sizeof(E1000_ENVVAR)-1] = '0' + e1000_instance; for (i = 0; i < 6; i++) { if (env_parse(eakey, eafmt, i, &v, 0x00L, 0xFFL) != EP_SET) break; else addr->ea_addr[i] = v; } /* If that fails, read Ethernet Address from EEPROM. */ if (i != 6) { for (i = 0; i < 3; i++) { word = e->eeprom_read(e, i); addr->ea_addr[i * 2] = (word & 0x00ff); addr->ea_addr[i * 2 + 1] = (word & 0xff00) >> 8; } } /* Set Receive Address. */ e1000_reg_write(e, E1000_REG_RAL, *(u32_t *)(&addr->ea_addr[0])); e1000_reg_write(e, E1000_REG_RAH, *(u16_t *)(&addr->ea_addr[4])); e1000_reg_set(e, E1000_REG_RAH, E1000_REG_RAH_AV); e1000_reg_set(e, E1000_REG_RCTL, E1000_REG_RCTL_MPE); E1000_DEBUG(3, ("%s: Ethernet Address %x:%x:%x:%x:%x:%x\n", e->name, addr->ea_addr[0], addr->ea_addr[1], addr->ea_addr[2], addr->ea_addr[3], addr->ea_addr[4], addr->ea_addr[5])); }
/* * Return statistics. */ static void e1000_stat(eth_stat_t * stat) { e1000_t *e = &e1000_state; E1000_DEBUG(3, ("e1000: stat()\n")); stat->ets_recvErr = e1000_reg_read(e, E1000_REG_RXERRC); stat->ets_sendErr = 0; stat->ets_OVW = 0; stat->ets_CRCerr = e1000_reg_read(e, E1000_REG_CRCERRS); stat->ets_frameAll = 0; stat->ets_missedP = e1000_reg_read(e, E1000_REG_MPC); stat->ets_packetR = e1000_reg_read(e, E1000_REG_TPR); stat->ets_packetT = e1000_reg_read(e, E1000_REG_TPT); stat->ets_collision = e1000_reg_read(e, E1000_REG_COLC); stat->ets_transAb = 0; stat->ets_carrSense = 0; stat->ets_fifoUnder = 0; stat->ets_fifoOver = 0; stat->ets_CDheartbeat = 0; stat->ets_OWC = 0; }
/*===========================================================================* * e1000_probe * *===========================================================================*/ PRIVATE int e1000_probe(e1000_t *e, int skip) { int i, r, devind; u16_t vid, did; u32_t status[2]; u32_t gfpreg, sector_base_addr; char *dname; E1000_DEBUG(3, ("%s: probe()\n", e->name)); /* * Attempt to iterate the PCI bus. Start at the beginning. */ if ((r = pci_first_dev(&devind, &vid, &did)) == 0) { return FALSE; } /* Loop devices on the PCI bus. */ for(;;) { for (i = 0; pcitab_e1000[i] != 0; i++) { if (vid != 0x8086) continue; if (did != pcitab_e1000[i]) continue; else break; } if (pcitab_e1000[i] != 0) { if (!skip) break; skip--; } if (!(r = pci_next_dev(&devind, &vid, &did))) { return FALSE; } } /* * Successfully detected an Intel Pro/1000 on the PCI bus. */ e->status |= E1000_DETECTED; e->eeprom_read = eeprom_eerd; /* * Set card specific properties. */ switch (did) { case E1000_DEV_ID_ICH10_R_BM_LF: e->eeprom_read = eeprom_ich; break; case E1000_DEV_ID_82574L: case E1000_DEV_ID_82541GI_LF: e->eeprom_done_bit = (1 << 1); e->eeprom_addr_off = 2; break; default: e->eeprom_done_bit = (1 << 4); e->eeprom_addr_off = 8; break; } /* Inform the user about the new card. */ if (!(dname = pci_dev_name(vid, did))) { dname = "Intel Pro/1000 Gigabit Ethernet Card"; } E1000_DEBUG(1, ("%s: %s (%04x/%04x/%02x) at %s\n", e->name, dname, vid, did, e->revision, pci_slot_name(devind))); /* Reserve PCI resources found. */ if ((r = pci_reserve_ok(devind)) != OK) { panic("failed to reserve PCI device: %d", r); } /* Read PCI configuration. */ e->irq = pci_attr_r8(devind, PCI_ILR); e->regs = vm_map_phys(SELF, (void *) pci_attr_r32(devind, PCI_BAR), 0x20000); /* Verify mapped registers. */ if (e->regs == (u8_t *) -1) { panic("failed to map hardware registers from PCI"); } /* Optionally map flash memory. */ if (did != E1000_DEV_ID_82540EM && did != E1000_DEV_ID_82540EP && pci_attr_r32(devind, PCI_BAR_2)) { if((e->flash = vm_map_phys(SELF, (void *) pci_attr_r32(devind, PCI_BAR_2), 0x10000)) == MAP_FAILED) { if((e->flash = vm_map_phys(SELF, (void *) pci_attr_r32(devind, PCI_BAR_2), 0x1000)) == MAP_FAILED) { panic("e1000: couldn't map in flash."); } } gfpreg = E1000_READ_FLASH_REG(e, ICH_FLASH_GFPREG); /* * sector_base_addr is a "sector"-aligned address (4096 bytes) */ sector_base_addr = gfpreg & FLASH_GFPREG_BASE_MASK; /* flash_base_addr is byte-aligned */ e->flash_base_addr = sector_base_addr << FLASH_SECTOR_ADDR_SHIFT; } /* * Output debug information. */ status[0] = e1000_reg_read(e, E1000_REG_STATUS); E1000_DEBUG(3, ("%s: MEM at %p, IRQ %d\n", e->name, e->regs, e->irq)); E1000_DEBUG(3, ("%s: link %s, %s duplex\n", e->name, status[0] & 3 ? "up" : "down", status[0] & 1 ? "full" : "half")); return TRUE; }
/* * Read from ICH8 flash. */ static u16_t eeprom_ich(e1000_t * e, int reg) { union ich8_hws_flash_status hsfsts; union ich8_hws_flash_ctrl hsflctl; u32_t flash_linear_addr; u32_t flash_data = 0; int ret_val = -1; u8_t count = 0; u16_t data = 0; E1000_DEBUG(3, ("e1000_read_flash_data_ich8lan")); if (reg > ICH_FLASH_LINEAR_ADDR_MASK) return data; reg *= sizeof(u16_t); flash_linear_addr = (ICH_FLASH_LINEAR_ADDR_MASK & reg) + e->flash_base_addr; do { tickdelay(1); /* Steps */ ret_val = eeprom_ich_init(e); if (ret_val != 0) break; hsflctl.regval = E1000_READ_FLASH_REG16(e, ICH_FLASH_HSFCTL); /* 0b/1b corresponds to 1 or 2 byte size, respectively. */ hsflctl.hsf_ctrl.fldbcount = 1; hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_READ; E1000_WRITE_FLASH_REG16(e, ICH_FLASH_HSFCTL, hsflctl.regval); E1000_WRITE_FLASH_REG(e, ICH_FLASH_FADDR, flash_linear_addr); ret_val = eeprom_ich_cycle(e, ICH_FLASH_READ_COMMAND_TIMEOUT); /* * Check if FCERR is set to 1, if set to 1, clear it and try * the whole sequence a few more times, else read in (shift in) * the Flash Data0, the order is least significant byte first * msb to lsb. */ if (ret_val == 0) { flash_data = E1000_READ_FLASH_REG(e, ICH_FLASH_FDATA0); data = (u16_t)(flash_data & 0x0000FFFF); break; } else { /* * If we've gotten here, then things are probably * completely hosed, but if the error condition is * detected, it won't hurt to give it another try... * ICH_FLASH_CYCLE_REPEAT_COUNT times. */ hsfsts.regval = E1000_READ_FLASH_REG16(e, ICH_FLASH_HSFSTS); if (hsfsts.hsf_status.flcerr == 1) { /* Repeat for some time before giving up. */ continue; } else if (hsfsts.hsf_status.flcdone == 0) { E1000_DEBUG(3, ("Timeout error - flash cycle " "did not complete.")); break; } } } while (count++ < ICH_FLASH_CYCLE_REPEAT_COUNT); return data; }
/* * Initialize ICH8 flash. */ static int eeprom_ich_init(e1000_t * e) { union ich8_hws_flash_status hsfsts; int ret_val = -1; int i = 0; hsfsts.regval = E1000_READ_FLASH_REG16(e, ICH_FLASH_HSFSTS); /* Check if the flash descriptor is valid */ if (hsfsts.hsf_status.fldesvalid == 0) { E1000_DEBUG(3, ("Flash descriptor invalid. " "SW Sequencing must be used.")); return ret_val; } /* Clear FCERR and DAEL in hw status by writing 1 */ hsfsts.hsf_status.flcerr = 1; hsfsts.hsf_status.dael = 1; E1000_WRITE_FLASH_REG16(e, ICH_FLASH_HSFSTS, hsfsts.regval); /* * Either we should have a hardware SPI cycle in progress bit to check * against, in order to start a new cycle or FDONE bit should be * changed in the hardware so that it is 1 after hardware reset, which * can then be used as an indication whether a cycle is in progress or * has been completed. */ if (hsfsts.hsf_status.flcinprog == 0) { /* * There is no cycle running at present, so we can start a * cycle. Begin by setting Flash Cycle Done. */ hsfsts.hsf_status.flcdone = 1; E1000_WRITE_FLASH_REG16(e, ICH_FLASH_HSFSTS, hsfsts.regval); ret_val = 0; } else { /* * Otherwise poll for sometime so the current cycle has a * chance to end before giving up. */ for (i = 0; i < ICH_FLASH_READ_COMMAND_TIMEOUT; i++) { hsfsts.regval = E1000_READ_FLASH_REG16(e, ICH_FLASH_HSFSTS); if (hsfsts.hsf_status.flcinprog == 0) { ret_val = 0; break; } tickdelay(1); } if (ret_val == 0) { /* * Successful in waiting for previous cycle to timeout, * now set the Flash Cycle Done. */ hsfsts.hsf_status.flcdone = 1; E1000_WRITE_FLASH_REG16(e, ICH_FLASH_HSFSTS, hsfsts.regval); } else { E1000_DEBUG(3, ("Flash controller busy, cannot get access")); } } return ret_val; }
/* * Link status has changed. Nothing to do for now. */ static void e1000_link_changed(e1000_t * e) { E1000_DEBUG(4, ("%s: link_changed()\n", e->name)); }
/* * Find a matching device. Return TRUE on success. */ static int e1000_probe(e1000_t * e, int skip) { int r, devind, ioflag; u16_t vid, did, cr; u32_t status; u32_t base, size; char *dname; E1000_DEBUG(3, ("%s: probe()\n", e->name)); /* Initialize communication to the PCI driver. */ pci_init(); /* Attempt to iterate the PCI bus. Start at the beginning. */ if ((r = pci_first_dev(&devind, &vid, &did)) == 0) return FALSE; /* Loop devices on the PCI bus. */ while (skip--) { E1000_DEBUG(3, ("%s: probe() devind %d vid 0x%x did 0x%x\n", e->name, devind, vid, did)); if (!(r = pci_next_dev(&devind, &vid, &did))) return FALSE; } /* We found a matching card. Set card-specific properties. */ e->eeprom_read = eeprom_eerd; switch (did) { case E1000_DEV_ID_ICH10_D_BM_LM: case E1000_DEV_ID_ICH10_R_BM_LF: e->eeprom_read = eeprom_ich; break; case E1000_DEV_ID_82540EM: case E1000_DEV_ID_82545EM: case E1000_DEV_ID_82540EP_LP: e->eeprom_done_bit = (1 << 4); e->eeprom_addr_off = 8; break; default: e->eeprom_done_bit = (1 << 1); e->eeprom_addr_off = 2; break; } /* Inform the user about the new card. */ if (!(dname = pci_dev_name(vid, did))) dname = "Intel Pro/1000 Gigabit Ethernet Card"; E1000_DEBUG(1, ("%s: %s (%04x/%04x) at %s\n", e->name, dname, vid, did, pci_slot_name(devind))); /* Reserve PCI resources found. */ pci_reserve(devind); /* Read PCI configuration. */ e->irq = pci_attr_r8(devind, PCI_ILR); if ((r = pci_get_bar(devind, PCI_BAR, &base, &size, &ioflag)) != OK) panic("failed to get PCI BAR: %d", r); if (ioflag) panic("PCI BAR is not for memory"); if ((e->regs = vm_map_phys(SELF, (void *)base, size)) == MAP_FAILED) panic("failed to map hardware registers from PCI"); /* Enable DMA bus mastering if necessary. */ cr = pci_attr_r16(devind, PCI_CR); if (!(cr & PCI_CR_MAST_EN)) pci_attr_w16(devind, PCI_CR, cr | PCI_CR_MAST_EN); /* Optionally map flash memory. */ e1000_map_flash(e, devind, did); /* Output debug information. */ status = e1000_reg_read(e, E1000_REG_STATUS); E1000_DEBUG(3, ("%s: MEM at %p, IRQ %d\n", e->name, e->regs, e->irq)); E1000_DEBUG(3, ("%s: link %s, %s duplex\n", e->name, status & 3 ? "up" : "down", status & 1 ? "full" : "half")); return TRUE; }