1107df7c8SDavid van Moolenbroek /* A device driver for Intel Pro/1000 Gigabit Ethernet Controllers. */ 2433d6423SLionel Sambuc 3433d6423SLionel Sambuc #include <minix/drivers.h> 4433d6423SLionel Sambuc #include <minix/netdriver.h> 5433d6423SLionel Sambuc #include <machine/pci.h> 6433d6423SLionel Sambuc #include <sys/mman.h> 7433d6423SLionel Sambuc #include "assert.h" 8433d6423SLionel Sambuc #include "e1000.h" 9433d6423SLionel Sambuc #include "e1000_hw.h" 10433d6423SLionel Sambuc #include "e1000_reg.h" 11433d6423SLionel Sambuc #include "e1000_pci.h" 12433d6423SLionel Sambuc 13*f7df02e7SDavid van Moolenbroek static int e1000_init(unsigned int instance, netdriver_addr_t *addr, 14*f7df02e7SDavid van Moolenbroek uint32_t *caps, unsigned int *ticks); 151ad10e3aSDavid van Moolenbroek static void e1000_stop(void); 16*f7df02e7SDavid van Moolenbroek static void e1000_set_mode(unsigned int, const netdriver_addr_t *, 17*f7df02e7SDavid van Moolenbroek unsigned int); 18*f7df02e7SDavid van Moolenbroek static void e1000_set_hwaddr(const netdriver_addr_t *); 191ad10e3aSDavid van Moolenbroek static int e1000_send(struct netdriver_data *data, size_t size); 201ad10e3aSDavid van Moolenbroek static ssize_t e1000_recv(struct netdriver_data *data, size_t max); 21*f7df02e7SDavid van Moolenbroek static unsigned int e1000_get_link(uint32_t *); 221ad10e3aSDavid van Moolenbroek static void e1000_intr(unsigned int mask); 23*f7df02e7SDavid van Moolenbroek static void e1000_tick(void); 24433d6423SLionel Sambuc static int e1000_probe(e1000_t *e, int skip); 25*f7df02e7SDavid van Moolenbroek static void e1000_init_hw(e1000_t *e, netdriver_addr_t *addr); 26433d6423SLionel Sambuc static uint32_t e1000_reg_read(e1000_t *e, uint32_t reg); 27433d6423SLionel Sambuc static void e1000_reg_write(e1000_t *e, uint32_t reg, uint32_t value); 28433d6423SLionel Sambuc static void e1000_reg_set(e1000_t *e, uint32_t reg, uint32_t value); 29433d6423SLionel Sambuc static void e1000_reg_unset(e1000_t *e, uint32_t reg, uint32_t value); 301ad10e3aSDavid van Moolenbroek static u16_t eeprom_eerd(e1000_t *e, int reg); 311ad10e3aSDavid van Moolenbroek static u16_t eeprom_ich(e1000_t *e, int reg); 32433d6423SLionel Sambuc static int eeprom_ich_init(e1000_t *e); 33107df7c8SDavid van Moolenbroek static int eeprom_ich_cycle(e1000_t *e, u32_t timeout); 34433d6423SLionel Sambuc 351ad10e3aSDavid van Moolenbroek static int e1000_instance; 361ad10e3aSDavid van Moolenbroek static e1000_t e1000_state; 371ad10e3aSDavid van Moolenbroek 381ad10e3aSDavid van Moolenbroek static const struct netdriver e1000_table = { 39*f7df02e7SDavid van Moolenbroek .ndr_name = "em", 401ad10e3aSDavid van Moolenbroek .ndr_init = e1000_init, 411ad10e3aSDavid van Moolenbroek .ndr_stop = e1000_stop, 42*f7df02e7SDavid van Moolenbroek .ndr_set_mode = e1000_set_mode, 43*f7df02e7SDavid van Moolenbroek .ndr_set_hwaddr = e1000_set_hwaddr, 441ad10e3aSDavid van Moolenbroek .ndr_recv = e1000_recv, 451ad10e3aSDavid van Moolenbroek .ndr_send = e1000_send, 46*f7df02e7SDavid van Moolenbroek .ndr_get_link = e1000_get_link, 471ad10e3aSDavid van Moolenbroek .ndr_intr = e1000_intr, 48*f7df02e7SDavid van Moolenbroek .ndr_tick = e1000_tick 491ad10e3aSDavid van Moolenbroek }; 50433d6423SLionel Sambuc 51107df7c8SDavid van Moolenbroek /* 52107df7c8SDavid van Moolenbroek * The e1000 driver. 53107df7c8SDavid van Moolenbroek */ 54107df7c8SDavid van Moolenbroek int 55107df7c8SDavid van Moolenbroek main(int argc, char * argv[]) 56433d6423SLionel Sambuc { 57433d6423SLionel Sambuc 58433d6423SLionel Sambuc env_setargs(argc, argv); 59433d6423SLionel Sambuc 601ad10e3aSDavid van Moolenbroek /* Let the netdriver library take control. */ 611ad10e3aSDavid van Moolenbroek netdriver_task(&e1000_table); 62433d6423SLionel Sambuc 631ad10e3aSDavid van Moolenbroek return 0; 64433d6423SLionel Sambuc } 65433d6423SLionel Sambuc 66107df7c8SDavid van Moolenbroek /* 671ad10e3aSDavid van Moolenbroek * Initialize the e1000 driver and device. 68107df7c8SDavid van Moolenbroek */ 69107df7c8SDavid van Moolenbroek static int 70*f7df02e7SDavid van Moolenbroek e1000_init(unsigned int instance, netdriver_addr_t * addr, uint32_t * caps, 71*f7df02e7SDavid van Moolenbroek unsigned int * ticks) 72433d6423SLionel Sambuc { 731ad10e3aSDavid van Moolenbroek e1000_t *e; 74433d6423SLionel Sambuc int r; 75433d6423SLionel Sambuc 761ad10e3aSDavid van Moolenbroek e1000_instance = instance; 77433d6423SLionel Sambuc 78433d6423SLionel Sambuc /* Clear state. */ 79433d6423SLionel Sambuc memset(&e1000_state, 0, sizeof(e1000_state)); 80433d6423SLionel Sambuc 811ad10e3aSDavid van Moolenbroek e = &e1000_state; 821ad10e3aSDavid van Moolenbroek 83433d6423SLionel Sambuc /* Perform calibration. */ 84433d6423SLionel Sambuc if ((r = tsc_calibrate()) != OK) 85433d6423SLionel Sambuc panic("tsc_calibrate failed: %d", r); 86433d6423SLionel Sambuc 871ad10e3aSDavid van Moolenbroek /* See if we can find a matching device. */ 881ad10e3aSDavid van Moolenbroek if (!e1000_probe(e, instance)) 891ad10e3aSDavid van Moolenbroek return ENXIO; 901ad10e3aSDavid van Moolenbroek 911ad10e3aSDavid van Moolenbroek /* Initialize the hardware, and return its ethernet address. */ 921ad10e3aSDavid van Moolenbroek e1000_init_hw(e, addr); 93433d6423SLionel Sambuc 94*f7df02e7SDavid van Moolenbroek *caps = NDEV_CAP_MCAST | NDEV_CAP_BCAST | NDEV_CAP_HWADDR; 95*f7df02e7SDavid van Moolenbroek *ticks = sys_hz() / 10; /* update statistics 10x/sec */ 96107df7c8SDavid van Moolenbroek return OK; 97433d6423SLionel Sambuc } 98433d6423SLionel Sambuc 99107df7c8SDavid van Moolenbroek /* 1001ad10e3aSDavid van Moolenbroek * Map flash memory. This step is optional. 101107df7c8SDavid van Moolenbroek */ 102107df7c8SDavid van Moolenbroek static void 1031ad10e3aSDavid van Moolenbroek e1000_map_flash(e1000_t * e, int devind, int did) 104433d6423SLionel Sambuc { 1051ad10e3aSDavid van Moolenbroek u32_t flash_addr, gfpreg, sector_base_addr; 1061ad10e3aSDavid van Moolenbroek size_t flash_size; 107107df7c8SDavid van Moolenbroek 1081ad10e3aSDavid van Moolenbroek /* The flash memory is pointed to by BAR2. It may not be present. */ 1091ad10e3aSDavid van Moolenbroek if ((flash_addr = pci_attr_r32(devind, PCI_BAR_2)) == 0) 110433d6423SLionel Sambuc return; 1111ad10e3aSDavid van Moolenbroek 1121ad10e3aSDavid van Moolenbroek /* The default flash size. */ 1131ad10e3aSDavid van Moolenbroek flash_size = 0x10000; 1141ad10e3aSDavid van Moolenbroek 1151ad10e3aSDavid van Moolenbroek switch (did) { 1161ad10e3aSDavid van Moolenbroek case E1000_DEV_ID_82540EM: 1171ad10e3aSDavid van Moolenbroek case E1000_DEV_ID_82545EM: 1181ad10e3aSDavid van Moolenbroek case E1000_DEV_ID_82540EP: 119e1131d9cSThomas Goering case E1000_DEV_ID_82540EP_LP: 1201ad10e3aSDavid van Moolenbroek return; /* don't even try */ 1211ad10e3aSDavid van Moolenbroek 1221ad10e3aSDavid van Moolenbroek /* 82566/82567/82562V series support mapping 4kB of flash memory. */ 1231ad10e3aSDavid van Moolenbroek case E1000_DEV_ID_ICH10_D_BM_LM: 1241ad10e3aSDavid van Moolenbroek case E1000_DEV_ID_ICH10_R_BM_LF: 1251ad10e3aSDavid van Moolenbroek flash_size = 0x1000; 1261ad10e3aSDavid van Moolenbroek break; 127433d6423SLionel Sambuc } 128107df7c8SDavid van Moolenbroek 1291ad10e3aSDavid van Moolenbroek e->flash = vm_map_phys(SELF, (void *)flash_addr, flash_size); 1301ad10e3aSDavid van Moolenbroek if (e->flash == MAP_FAILED) 1311ad10e3aSDavid van Moolenbroek panic("e1000: couldn't map in flash"); 132433d6423SLionel Sambuc 1331ad10e3aSDavid van Moolenbroek /* sector_base_addr is a "sector"-aligned address (4096 bytes). */ 1341ad10e3aSDavid van Moolenbroek gfpreg = E1000_READ_FLASH_REG(e, ICH_FLASH_GFPREG); 1351ad10e3aSDavid van Moolenbroek sector_base_addr = gfpreg & FLASH_GFPREG_BASE_MASK; 136433d6423SLionel Sambuc 1371ad10e3aSDavid van Moolenbroek /* flash_base_addr is byte-aligned. */ 1381ad10e3aSDavid van Moolenbroek e->flash_base_addr = sector_base_addr << FLASH_SECTOR_ADDR_SHIFT; 139433d6423SLionel Sambuc } 140433d6423SLionel Sambuc 141107df7c8SDavid van Moolenbroek /* 142107df7c8SDavid van Moolenbroek * Find a matching device. Return TRUE on success. 143107df7c8SDavid van Moolenbroek */ 144107df7c8SDavid van Moolenbroek static int 145107df7c8SDavid van Moolenbroek e1000_probe(e1000_t * e, int skip) 146433d6423SLionel Sambuc { 147433d6423SLionel Sambuc int r, devind, ioflag; 148433d6423SLionel Sambuc u16_t vid, did, cr; 1491ad10e3aSDavid van Moolenbroek u32_t status; 150433d6423SLionel Sambuc u32_t base, size; 151*f7df02e7SDavid van Moolenbroek const char *dname; 152433d6423SLionel Sambuc 153*f7df02e7SDavid van Moolenbroek E1000_DEBUG(3, ("%s: probe()\n", netdriver_name())); 154433d6423SLionel Sambuc 1551ad10e3aSDavid van Moolenbroek /* Initialize communication to the PCI driver. */ 1561ad10e3aSDavid van Moolenbroek pci_init(); 1571ad10e3aSDavid van Moolenbroek 158107df7c8SDavid van Moolenbroek /* Attempt to iterate the PCI bus. Start at the beginning. */ 159433d6423SLionel Sambuc if ((r = pci_first_dev(&devind, &vid, &did)) == 0) 160433d6423SLionel Sambuc return FALSE; 161107df7c8SDavid van Moolenbroek 162433d6423SLionel Sambuc /* Loop devices on the PCI bus. */ 163107df7c8SDavid van Moolenbroek while (skip--) { 164433d6423SLionel Sambuc E1000_DEBUG(3, ("%s: probe() devind %d vid 0x%x did 0x%x\n", 165*f7df02e7SDavid van Moolenbroek netdriver_name(), devind, vid, did)); 166433d6423SLionel Sambuc 167433d6423SLionel Sambuc if (!(r = pci_next_dev(&devind, &vid, &did))) 168433d6423SLionel Sambuc return FALSE; 169433d6423SLionel Sambuc } 170107df7c8SDavid van Moolenbroek 171107df7c8SDavid van Moolenbroek /* We found a matching card. Set card-specific properties. */ 172433d6423SLionel Sambuc e->eeprom_read = eeprom_eerd; 173433d6423SLionel Sambuc 174107df7c8SDavid van Moolenbroek switch (did) { 175433d6423SLionel Sambuc case E1000_DEV_ID_ICH10_D_BM_LM: 176433d6423SLionel Sambuc case E1000_DEV_ID_ICH10_R_BM_LF: 177433d6423SLionel Sambuc e->eeprom_read = eeprom_ich; 178433d6423SLionel Sambuc break; 179433d6423SLionel Sambuc 180433d6423SLionel Sambuc case E1000_DEV_ID_82540EM: 181433d6423SLionel Sambuc case E1000_DEV_ID_82545EM: 182e1131d9cSThomas Goering case E1000_DEV_ID_82540EP_LP: 183433d6423SLionel Sambuc e->eeprom_done_bit = (1 << 4); 184433d6423SLionel Sambuc e->eeprom_addr_off = 8; 185433d6423SLionel Sambuc break; 186433d6423SLionel Sambuc 187433d6423SLionel Sambuc default: 188433d6423SLionel Sambuc e->eeprom_done_bit = (1 << 1); 189433d6423SLionel Sambuc e->eeprom_addr_off = 2; 190433d6423SLionel Sambuc break; 191433d6423SLionel Sambuc } 192433d6423SLionel Sambuc 193433d6423SLionel Sambuc /* Inform the user about the new card. */ 194433d6423SLionel Sambuc if (!(dname = pci_dev_name(vid, did))) 195433d6423SLionel Sambuc dname = "Intel Pro/1000 Gigabit Ethernet Card"; 1961ad10e3aSDavid van Moolenbroek E1000_DEBUG(1, ("%s: %s (%04x/%04x) at %s\n", 197*f7df02e7SDavid van Moolenbroek netdriver_name(), dname, vid, did, pci_slot_name(devind))); 198433d6423SLionel Sambuc 199433d6423SLionel Sambuc /* Reserve PCI resources found. */ 2001ad10e3aSDavid van Moolenbroek pci_reserve(devind); 201107df7c8SDavid van Moolenbroek 202433d6423SLionel Sambuc /* Read PCI configuration. */ 203433d6423SLionel Sambuc e->irq = pci_attr_r8(devind, PCI_ILR); 204433d6423SLionel Sambuc 205433d6423SLionel Sambuc if ((r = pci_get_bar(devind, PCI_BAR, &base, &size, &ioflag)) != OK) 206107df7c8SDavid van Moolenbroek panic("failed to get PCI BAR: %d", r); 207107df7c8SDavid van Moolenbroek if (ioflag) 208107df7c8SDavid van Moolenbroek panic("PCI BAR is not for memory"); 209433d6423SLionel Sambuc 210107df7c8SDavid van Moolenbroek if ((e->regs = vm_map_phys(SELF, (void *)base, size)) == MAP_FAILED) 211433d6423SLionel Sambuc panic("failed to map hardware registers from PCI"); 212433d6423SLionel Sambuc 213107df7c8SDavid van Moolenbroek /* Enable DMA bus mastering if necessary. */ 214433d6423SLionel Sambuc cr = pci_attr_r16(devind, PCI_CR); 215433d6423SLionel Sambuc if (!(cr & PCI_CR_MAST_EN)) 216433d6423SLionel Sambuc pci_attr_w16(devind, PCI_CR, cr | PCI_CR_MAST_EN); 217433d6423SLionel Sambuc 218433d6423SLionel Sambuc /* Optionally map flash memory. */ 2191ad10e3aSDavid van Moolenbroek e1000_map_flash(e, devind, did); 220107df7c8SDavid van Moolenbroek 221107df7c8SDavid van Moolenbroek /* Output debug information. */ 2221ad10e3aSDavid van Moolenbroek status = e1000_reg_read(e, E1000_REG_STATUS); 223*f7df02e7SDavid van Moolenbroek E1000_DEBUG(3, ("%s: MEM at %p, IRQ %d\n", netdriver_name(), 224*f7df02e7SDavid van Moolenbroek e->regs, e->irq)); 225*f7df02e7SDavid van Moolenbroek E1000_DEBUG(3, ("%s: link %s, %s duplex\n", netdriver_name(), 2261ad10e3aSDavid van Moolenbroek status & 3 ? "up" : "down", status & 1 ? "full" : "half")); 227107df7c8SDavid van Moolenbroek 228433d6423SLionel Sambuc return TRUE; 229433d6423SLionel Sambuc } 230433d6423SLionel Sambuc 231107df7c8SDavid van Moolenbroek /* 2321ad10e3aSDavid van Moolenbroek * Reset the card. 233107df7c8SDavid van Moolenbroek */ 2341ad10e3aSDavid van Moolenbroek static void 2351ad10e3aSDavid van Moolenbroek e1000_reset_hw(e1000_t * e) 2361ad10e3aSDavid van Moolenbroek { 2371ad10e3aSDavid van Moolenbroek 2381ad10e3aSDavid van Moolenbroek /* Assert a Device Reset signal. */ 2391ad10e3aSDavid van Moolenbroek e1000_reg_set(e, E1000_REG_CTRL, E1000_REG_CTRL_RST); 2401ad10e3aSDavid van Moolenbroek 2411ad10e3aSDavid van Moolenbroek /* Wait one microsecond. */ 2421ad10e3aSDavid van Moolenbroek tickdelay(1); 2431ad10e3aSDavid van Moolenbroek } 2441ad10e3aSDavid van Moolenbroek 2451ad10e3aSDavid van Moolenbroek /* 2461ad10e3aSDavid van Moolenbroek * Initialize and return the card's ethernet address. 2471ad10e3aSDavid van Moolenbroek */ 2481ad10e3aSDavid van Moolenbroek static void 249*f7df02e7SDavid van Moolenbroek e1000_init_addr(e1000_t * e, netdriver_addr_t * addr) 2501ad10e3aSDavid van Moolenbroek { 2511ad10e3aSDavid van Moolenbroek static char eakey[] = E1000_ENVVAR "#_EA"; 2521ad10e3aSDavid van Moolenbroek static char eafmt[] = "x:x:x:x:x:x"; 2531ad10e3aSDavid van Moolenbroek u16_t word; 2541ad10e3aSDavid van Moolenbroek int i; 2551ad10e3aSDavid van Moolenbroek long v; 2561ad10e3aSDavid van Moolenbroek 2571ad10e3aSDavid van Moolenbroek /* Do we have a user defined ethernet address? */ 2581ad10e3aSDavid van Moolenbroek eakey[sizeof(E1000_ENVVAR)-1] = '0' + e1000_instance; 2591ad10e3aSDavid van Moolenbroek 2601ad10e3aSDavid van Moolenbroek for (i = 0; i < 6; i++) { 2611ad10e3aSDavid van Moolenbroek if (env_parse(eakey, eafmt, i, &v, 0x00L, 0xFFL) != EP_SET) 2621ad10e3aSDavid van Moolenbroek break; 2631ad10e3aSDavid van Moolenbroek else 264*f7df02e7SDavid van Moolenbroek addr->na_addr[i] = v; 2651ad10e3aSDavid van Moolenbroek } 2661ad10e3aSDavid van Moolenbroek 2671ad10e3aSDavid van Moolenbroek /* If that fails, read Ethernet Address from EEPROM. */ 2681ad10e3aSDavid van Moolenbroek if (i != 6) { 2691ad10e3aSDavid van Moolenbroek for (i = 0; i < 3; i++) { 2701ad10e3aSDavid van Moolenbroek word = e->eeprom_read(e, i); 271*f7df02e7SDavid van Moolenbroek addr->na_addr[i * 2] = (word & 0x00ff); 272*f7df02e7SDavid van Moolenbroek addr->na_addr[i * 2 + 1] = (word & 0xff00) >> 8; 2731ad10e3aSDavid van Moolenbroek } 2741ad10e3aSDavid van Moolenbroek } 2751ad10e3aSDavid van Moolenbroek 2761ad10e3aSDavid van Moolenbroek /* Set Receive Address. */ 277*f7df02e7SDavid van Moolenbroek e1000_set_hwaddr(addr); 2781ad10e3aSDavid van Moolenbroek 279*f7df02e7SDavid van Moolenbroek E1000_DEBUG(3, ("%s: Ethernet Address %x:%x:%x:%x:%x:%x\n", 280*f7df02e7SDavid van Moolenbroek netdriver_name(), 281*f7df02e7SDavid van Moolenbroek addr->na_addr[0], addr->na_addr[1], addr->na_addr[2], 282*f7df02e7SDavid van Moolenbroek addr->na_addr[3], addr->na_addr[4], addr->na_addr[5])); 2831ad10e3aSDavid van Moolenbroek } 2841ad10e3aSDavid van Moolenbroek 2851ad10e3aSDavid van Moolenbroek /* 2861ad10e3aSDavid van Moolenbroek * Initialize receive and transmit buffers. 2871ad10e3aSDavid van Moolenbroek */ 2881ad10e3aSDavid van Moolenbroek static void 2891ad10e3aSDavid van Moolenbroek e1000_init_buf(e1000_t * e) 2901ad10e3aSDavid van Moolenbroek { 2911ad10e3aSDavid van Moolenbroek phys_bytes rx_desc_p, rx_buff_p; 2921ad10e3aSDavid van Moolenbroek phys_bytes tx_desc_p, tx_buff_p; 2931ad10e3aSDavid van Moolenbroek int i; 2941ad10e3aSDavid van Moolenbroek 2951ad10e3aSDavid van Moolenbroek /* Number of descriptors. */ 2961ad10e3aSDavid van Moolenbroek e->rx_desc_count = E1000_RXDESC_NR; 2971ad10e3aSDavid van Moolenbroek e->tx_desc_count = E1000_TXDESC_NR; 2981ad10e3aSDavid van Moolenbroek 2991ad10e3aSDavid van Moolenbroek /* Allocate receive descriptors. */ 3001ad10e3aSDavid van Moolenbroek if ((e->rx_desc = alloc_contig(sizeof(e1000_rx_desc_t) * 3011ad10e3aSDavid van Moolenbroek e->rx_desc_count, AC_ALIGN4K, &rx_desc_p)) == NULL) 3021ad10e3aSDavid van Moolenbroek panic("failed to allocate RX descriptors"); 3031ad10e3aSDavid van Moolenbroek 3041ad10e3aSDavid van Moolenbroek memset(e->rx_desc, 0, sizeof(e1000_rx_desc_t) * e->rx_desc_count); 3051ad10e3aSDavid van Moolenbroek 3061ad10e3aSDavid van Moolenbroek /* Allocate receive buffers. */ 3071ad10e3aSDavid van Moolenbroek e->rx_buffer_size = E1000_RXDESC_NR * E1000_IOBUF_SIZE; 3081ad10e3aSDavid van Moolenbroek 3091ad10e3aSDavid van Moolenbroek if ((e->rx_buffer = alloc_contig(e->rx_buffer_size, AC_ALIGN4K, 3101ad10e3aSDavid van Moolenbroek &rx_buff_p)) == NULL) 3111ad10e3aSDavid van Moolenbroek panic("failed to allocate RX buffers"); 3121ad10e3aSDavid van Moolenbroek 3131ad10e3aSDavid van Moolenbroek /* Set up receive descriptors. */ 3141ad10e3aSDavid van Moolenbroek for (i = 0; i < E1000_RXDESC_NR; i++) 3151ad10e3aSDavid van Moolenbroek e->rx_desc[i].buffer = rx_buff_p + i * E1000_IOBUF_SIZE; 3161ad10e3aSDavid van Moolenbroek 3171ad10e3aSDavid van Moolenbroek /* Allocate transmit descriptors. */ 3181ad10e3aSDavid van Moolenbroek if ((e->tx_desc = alloc_contig(sizeof(e1000_tx_desc_t) * 3191ad10e3aSDavid van Moolenbroek e->tx_desc_count, AC_ALIGN4K, &tx_desc_p)) == NULL) 3201ad10e3aSDavid van Moolenbroek panic("failed to allocate TX descriptors"); 3211ad10e3aSDavid van Moolenbroek 3221ad10e3aSDavid van Moolenbroek memset(e->tx_desc, 0, sizeof(e1000_tx_desc_t) * e->tx_desc_count); 3231ad10e3aSDavid van Moolenbroek 3241ad10e3aSDavid van Moolenbroek /* Allocate transmit buffers. */ 3251ad10e3aSDavid van Moolenbroek e->tx_buffer_size = E1000_TXDESC_NR * E1000_IOBUF_SIZE; 3261ad10e3aSDavid van Moolenbroek 3271ad10e3aSDavid van Moolenbroek if ((e->tx_buffer = alloc_contig(e->tx_buffer_size, AC_ALIGN4K, 3281ad10e3aSDavid van Moolenbroek &tx_buff_p)) == NULL) 3291ad10e3aSDavid van Moolenbroek panic("failed to allocate TX buffers"); 3301ad10e3aSDavid van Moolenbroek 3311ad10e3aSDavid van Moolenbroek /* Set up transmit descriptors. */ 3321ad10e3aSDavid van Moolenbroek for (i = 0; i < E1000_TXDESC_NR; i++) 3331ad10e3aSDavid van Moolenbroek e->tx_desc[i].buffer = tx_buff_p + i * E1000_IOBUF_SIZE; 3341ad10e3aSDavid van Moolenbroek 3351ad10e3aSDavid van Moolenbroek /* Set up the receive ring registers. */ 3361ad10e3aSDavid van Moolenbroek e1000_reg_write(e, E1000_REG_RDBAL, rx_desc_p); 3371ad10e3aSDavid van Moolenbroek e1000_reg_write(e, E1000_REG_RDBAH, 0); 3381ad10e3aSDavid van Moolenbroek e1000_reg_write(e, E1000_REG_RDLEN, 3391ad10e3aSDavid van Moolenbroek e->rx_desc_count * sizeof(e1000_rx_desc_t)); 3401ad10e3aSDavid van Moolenbroek e1000_reg_write(e, E1000_REG_RDH, 0); 3411ad10e3aSDavid van Moolenbroek e1000_reg_write(e, E1000_REG_RDT, e->rx_desc_count - 1); 3421ad10e3aSDavid van Moolenbroek e1000_reg_unset(e, E1000_REG_RCTL, E1000_REG_RCTL_BSIZE); 3431ad10e3aSDavid van Moolenbroek e1000_reg_set(e, E1000_REG_RCTL, E1000_REG_RCTL_EN); 3441ad10e3aSDavid van Moolenbroek 3451ad10e3aSDavid van Moolenbroek /* Set up the transmit ring registers. */ 3461ad10e3aSDavid van Moolenbroek e1000_reg_write(e, E1000_REG_TDBAL, tx_desc_p); 3471ad10e3aSDavid van Moolenbroek e1000_reg_write(e, E1000_REG_TDBAH, 0); 3481ad10e3aSDavid van Moolenbroek e1000_reg_write(e, E1000_REG_TDLEN, 3491ad10e3aSDavid van Moolenbroek e->tx_desc_count * sizeof(e1000_tx_desc_t)); 3501ad10e3aSDavid van Moolenbroek e1000_reg_write(e, E1000_REG_TDH, 0); 3511ad10e3aSDavid van Moolenbroek e1000_reg_write(e, E1000_REG_TDT, 0); 3521ad10e3aSDavid van Moolenbroek e1000_reg_set(e, E1000_REG_TCTL, 3531ad10e3aSDavid van Moolenbroek E1000_REG_TCTL_EN | E1000_REG_TCTL_PSP); 3541ad10e3aSDavid van Moolenbroek } 3551ad10e3aSDavid van Moolenbroek 3561ad10e3aSDavid van Moolenbroek /* 3571ad10e3aSDavid van Moolenbroek * Initialize the hardware. Return the ethernet address. 3581ad10e3aSDavid van Moolenbroek */ 3591ad10e3aSDavid van Moolenbroek static void 360*f7df02e7SDavid van Moolenbroek e1000_init_hw(e1000_t * e, netdriver_addr_t * addr) 361433d6423SLionel Sambuc { 362433d6423SLionel Sambuc int r, i; 363433d6423SLionel Sambuc 364433d6423SLionel Sambuc e->irq_hook = e->irq; 365433d6423SLionel Sambuc 366433d6423SLionel Sambuc /* 367433d6423SLionel Sambuc * Set the interrupt handler and policy. Do not automatically 368107df7c8SDavid van Moolenbroek * reenable interrupts. Return the IRQ line number on interrupts. 369433d6423SLionel Sambuc */ 370433d6423SLionel Sambuc if ((r = sys_irqsetpolicy(e->irq, 0, &e->irq_hook)) != OK) 371433d6423SLionel Sambuc panic("sys_irqsetpolicy failed: %d", r); 372433d6423SLionel Sambuc if ((r = sys_irqenable(&e->irq_hook)) != OK) 373433d6423SLionel Sambuc panic("sys_irqenable failed: %d", r); 374107df7c8SDavid van Moolenbroek 375433d6423SLionel Sambuc /* Reset hardware. */ 376433d6423SLionel Sambuc e1000_reset_hw(e); 377433d6423SLionel Sambuc 378433d6423SLionel Sambuc /* 379107df7c8SDavid van Moolenbroek * Initialize appropriately, according to section 14.3 General 380107df7c8SDavid van Moolenbroek * Configuration of Intel's Gigabit Ethernet Controllers Software 381107df7c8SDavid van Moolenbroek * Developer's Manual. 382433d6423SLionel Sambuc */ 383107df7c8SDavid van Moolenbroek e1000_reg_set(e, E1000_REG_CTRL, 384107df7c8SDavid van Moolenbroek E1000_REG_CTRL_ASDE | E1000_REG_CTRL_SLU); 385433d6423SLionel Sambuc e1000_reg_unset(e, E1000_REG_CTRL, E1000_REG_CTRL_LRST); 386433d6423SLionel Sambuc e1000_reg_unset(e, E1000_REG_CTRL, E1000_REG_CTRL_PHY_RST); 387433d6423SLionel Sambuc e1000_reg_unset(e, E1000_REG_CTRL, E1000_REG_CTRL_ILOS); 388433d6423SLionel Sambuc e1000_reg_write(e, E1000_REG_FCAL, 0); 389433d6423SLionel Sambuc e1000_reg_write(e, E1000_REG_FCAH, 0); 390433d6423SLionel Sambuc e1000_reg_write(e, E1000_REG_FCT, 0); 391433d6423SLionel Sambuc e1000_reg_write(e, E1000_REG_FCTTV, 0); 392433d6423SLionel Sambuc e1000_reg_unset(e, E1000_REG_CTRL, E1000_REG_CTRL_VME); 393433d6423SLionel Sambuc 394433d6423SLionel Sambuc /* Clear Multicast Table Array (MTA). */ 395433d6423SLionel Sambuc for (i = 0; i < 128; i++) 3961ad10e3aSDavid van Moolenbroek e1000_reg_write(e, E1000_REG_MTA + i * 4, 0); 397107df7c8SDavid van Moolenbroek 398433d6423SLionel Sambuc /* Initialize statistics registers. */ 399433d6423SLionel Sambuc for (i = 0; i < 64; i++) 4001ad10e3aSDavid van Moolenbroek e1000_reg_write(e, E1000_REG_CRCERRS + i * 4, 0); 401107df7c8SDavid van Moolenbroek 402107df7c8SDavid van Moolenbroek /* Acquire MAC address and set up RX/TX buffers. */ 4031ad10e3aSDavid van Moolenbroek e1000_init_addr(e, addr); 404433d6423SLionel Sambuc e1000_init_buf(e); 405433d6423SLionel Sambuc 406433d6423SLionel Sambuc /* Enable interrupts. */ 407107df7c8SDavid van Moolenbroek e1000_reg_set(e, E1000_REG_IMS, E1000_REG_IMS_LSC | E1000_REG_IMS_RXO | 408107df7c8SDavid van Moolenbroek E1000_REG_IMS_RXT | E1000_REG_IMS_TXQE | E1000_REG_IMS_TXDW); 409433d6423SLionel Sambuc } 410433d6423SLionel Sambuc 411107df7c8SDavid van Moolenbroek /* 412*f7df02e7SDavid van Moolenbroek * Set receive mode. 413*f7df02e7SDavid van Moolenbroek */ 414*f7df02e7SDavid van Moolenbroek static void 415*f7df02e7SDavid van Moolenbroek e1000_set_mode(unsigned int mode, const netdriver_addr_t * mcast_list __unused, 416*f7df02e7SDavid van Moolenbroek unsigned int mcast_count __unused) 417*f7df02e7SDavid van Moolenbroek { 418*f7df02e7SDavid van Moolenbroek e1000_t *e; 419*f7df02e7SDavid van Moolenbroek uint32_t rctl; 420*f7df02e7SDavid van Moolenbroek 421*f7df02e7SDavid van Moolenbroek e = &e1000_state; 422*f7df02e7SDavid van Moolenbroek 423*f7df02e7SDavid van Moolenbroek rctl = e1000_reg_read(e, E1000_REG_RCTL); 424*f7df02e7SDavid van Moolenbroek 425*f7df02e7SDavid van Moolenbroek rctl &= ~(E1000_REG_RCTL_BAM | E1000_REG_RCTL_MPE | 426*f7df02e7SDavid van Moolenbroek E1000_REG_RCTL_UPE); 427*f7df02e7SDavid van Moolenbroek 428*f7df02e7SDavid van Moolenbroek /* TODO: support for NDEV_MODE_DOWN and multicast lists */ 429*f7df02e7SDavid van Moolenbroek if (mode & NDEV_MODE_BCAST) 430*f7df02e7SDavid van Moolenbroek rctl |= E1000_REG_RCTL_BAM; 431*f7df02e7SDavid van Moolenbroek if (mode & (NDEV_MODE_MCAST_LIST | NDEV_MODE_MCAST_ALL)) 432*f7df02e7SDavid van Moolenbroek rctl |= E1000_REG_RCTL_MPE; 433*f7df02e7SDavid van Moolenbroek if (mode & NDEV_MODE_PROMISC) 434*f7df02e7SDavid van Moolenbroek rctl |= E1000_REG_RCTL_BAM | E1000_REG_RCTL_MPE | 435*f7df02e7SDavid van Moolenbroek E1000_REG_RCTL_UPE; 436*f7df02e7SDavid van Moolenbroek 437*f7df02e7SDavid van Moolenbroek e1000_reg_write(e, E1000_REG_RCTL, rctl); 438*f7df02e7SDavid van Moolenbroek } 439*f7df02e7SDavid van Moolenbroek 440*f7df02e7SDavid van Moolenbroek /* 441*f7df02e7SDavid van Moolenbroek * Set hardware address. 442*f7df02e7SDavid van Moolenbroek */ 443*f7df02e7SDavid van Moolenbroek static void 444*f7df02e7SDavid van Moolenbroek e1000_set_hwaddr(const netdriver_addr_t * hwaddr) 445*f7df02e7SDavid van Moolenbroek { 446*f7df02e7SDavid van Moolenbroek e1000_t *e; 447*f7df02e7SDavid van Moolenbroek 448*f7df02e7SDavid van Moolenbroek e = &e1000_state; 449*f7df02e7SDavid van Moolenbroek 450*f7df02e7SDavid van Moolenbroek e1000_reg_write(e, E1000_REG_RAL, 451*f7df02e7SDavid van Moolenbroek *(const u32_t *)(&hwaddr->na_addr[0])); 452*f7df02e7SDavid van Moolenbroek e1000_reg_write(e, E1000_REG_RAH, 453*f7df02e7SDavid van Moolenbroek *(const u16_t *)(&hwaddr->na_addr[4])); 454*f7df02e7SDavid van Moolenbroek e1000_reg_set(e, E1000_REG_RAH, E1000_REG_RAH_AV); 455*f7df02e7SDavid van Moolenbroek } 456*f7df02e7SDavid van Moolenbroek 457*f7df02e7SDavid van Moolenbroek /* 458107df7c8SDavid van Moolenbroek * Try to send a packet. 459107df7c8SDavid van Moolenbroek */ 4601ad10e3aSDavid van Moolenbroek static int 4611ad10e3aSDavid van Moolenbroek e1000_send(struct netdriver_data * data, size_t size) 462433d6423SLionel Sambuc { 4631ad10e3aSDavid van Moolenbroek e1000_t *e; 464433d6423SLionel Sambuc e1000_tx_desc_t *desc; 4651ad10e3aSDavid van Moolenbroek unsigned int head, tail, next; 4661ad10e3aSDavid van Moolenbroek char *ptr; 467433d6423SLionel Sambuc 4681ad10e3aSDavid van Moolenbroek e = &e1000_state; 469433d6423SLionel Sambuc 4701ad10e3aSDavid van Moolenbroek if (size > E1000_IOBUF_SIZE) 4711ad10e3aSDavid van Moolenbroek panic("packet too large to send"); 472433d6423SLionel Sambuc 473433d6423SLionel Sambuc /* 4741ad10e3aSDavid van Moolenbroek * The queue tail must not advance to the point that it is equal to the 4751ad10e3aSDavid van Moolenbroek * queue head, since this condition indicates that the queue is empty. 476433d6423SLionel Sambuc */ 477433d6423SLionel Sambuc head = e1000_reg_read(e, E1000_REG_TDH); 478433d6423SLionel Sambuc tail = e1000_reg_read(e, E1000_REG_TDT); 4791ad10e3aSDavid van Moolenbroek next = (tail + 1) % e->tx_desc_count; 4801ad10e3aSDavid van Moolenbroek 4811ad10e3aSDavid van Moolenbroek if (next == head) 4821ad10e3aSDavid van Moolenbroek return SUSPEND; 4831ad10e3aSDavid van Moolenbroek 4841ad10e3aSDavid van Moolenbroek /* The descriptor to use is the one pointed to by the current tail. */ 485433d6423SLionel Sambuc desc = &e->tx_desc[tail]; 486433d6423SLionel Sambuc 4871ad10e3aSDavid van Moolenbroek /* Copy the packet from the caller. */ 4881ad10e3aSDavid van Moolenbroek ptr = e->tx_buffer + tail * E1000_IOBUF_SIZE; 489433d6423SLionel Sambuc 4901ad10e3aSDavid van Moolenbroek netdriver_copyin(data, 0, ptr, size); 491107df7c8SDavid van Moolenbroek 492433d6423SLionel Sambuc /* Mark this descriptor ready. */ 493433d6423SLionel Sambuc desc->status = 0; 494433d6423SLionel Sambuc desc->length = size; 4951ad10e3aSDavid van Moolenbroek desc->command = E1000_TX_CMD_EOP | E1000_TX_CMD_FCS | E1000_TX_CMD_RS; 496107df7c8SDavid van Moolenbroek 497433d6423SLionel Sambuc /* Increment tail. Start transmission. */ 4981ad10e3aSDavid van Moolenbroek e1000_reg_write(e, E1000_REG_TDT, next); 499433d6423SLionel Sambuc 5001ad10e3aSDavid van Moolenbroek return OK; 501433d6423SLionel Sambuc } 502433d6423SLionel Sambuc 503107df7c8SDavid van Moolenbroek /* 504107df7c8SDavid van Moolenbroek * Try to receive a packet. 505107df7c8SDavid van Moolenbroek */ 5061ad10e3aSDavid van Moolenbroek static ssize_t 5071ad10e3aSDavid van Moolenbroek e1000_recv(struct netdriver_data * data, size_t max) 508433d6423SLionel Sambuc { 5091ad10e3aSDavid van Moolenbroek e1000_t *e; 510433d6423SLionel Sambuc e1000_rx_desc_t *desc; 5111ad10e3aSDavid van Moolenbroek unsigned int head, tail, cur; 5121ad10e3aSDavid van Moolenbroek char *ptr; 5131ad10e3aSDavid van Moolenbroek size_t size; 514433d6423SLionel Sambuc 5151ad10e3aSDavid van Moolenbroek e = &e1000_state; 516433d6423SLionel Sambuc 5171ad10e3aSDavid van Moolenbroek /* If the queue head and tail are equal, the queue is empty. */ 518433d6423SLionel Sambuc head = e1000_reg_read(e, E1000_REG_RDH); 519433d6423SLionel Sambuc tail = e1000_reg_read(e, E1000_REG_RDT); 5201ad10e3aSDavid van Moolenbroek 521*f7df02e7SDavid van Moolenbroek E1000_DEBUG(4, ("%s: head=%u, tail=%u\n", 522*f7df02e7SDavid van Moolenbroek netdriver_name(), head, tail)); 5231ad10e3aSDavid van Moolenbroek 5241ad10e3aSDavid van Moolenbroek if (head == tail) 5251ad10e3aSDavid van Moolenbroek return SUSPEND; 5261ad10e3aSDavid van Moolenbroek 5271ad10e3aSDavid van Moolenbroek /* Has a packet been received? */ 528433d6423SLionel Sambuc cur = (tail + 1) % e->rx_desc_count; 529433d6423SLionel Sambuc desc = &e->rx_desc[cur]; 530433d6423SLionel Sambuc 5311ad10e3aSDavid van Moolenbroek if (!(desc->status & E1000_RX_STATUS_DONE)) 5321ad10e3aSDavid van Moolenbroek return SUSPEND; 533433d6423SLionel Sambuc 534433d6423SLionel Sambuc /* 5351ad10e3aSDavid van Moolenbroek * HACK: we expect all packets to fit in a single receive buffer. 5361ad10e3aSDavid van Moolenbroek * Eventually, some sort of support to deal with packets spanning 5371ad10e3aSDavid van Moolenbroek * multiple receive descriptors should be added. For now, we panic, 5381ad10e3aSDavid van Moolenbroek * so that we can continue after the restart; this is already an 5391ad10e3aSDavid van Moolenbroek * improvement over freezing (the old behavior of this driver). 540433d6423SLionel Sambuc */ 5411ad10e3aSDavid van Moolenbroek size = desc->length; 542433d6423SLionel Sambuc 5431ad10e3aSDavid van Moolenbroek if (!(desc->status & E1000_RX_STATUS_EOP)) 5441ad10e3aSDavid van Moolenbroek panic("received packet too large"); 545433d6423SLionel Sambuc 5461ad10e3aSDavid van Moolenbroek /* Copy the packet to the caller. */ 5471ad10e3aSDavid van Moolenbroek ptr = e->rx_buffer + cur * E1000_IOBUF_SIZE; 5481ad10e3aSDavid van Moolenbroek 5491ad10e3aSDavid van Moolenbroek if (size > max) 5501ad10e3aSDavid van Moolenbroek size = max; 5511ad10e3aSDavid van Moolenbroek 5521ad10e3aSDavid van Moolenbroek netdriver_copyout(data, 0, ptr, size); 5531ad10e3aSDavid van Moolenbroek 5541ad10e3aSDavid van Moolenbroek /* Reset the descriptor. */ 555433d6423SLionel Sambuc desc->status = 0; 556433d6423SLionel Sambuc 557433d6423SLionel Sambuc /* Increment tail. */ 5581ad10e3aSDavid van Moolenbroek e1000_reg_write(e, E1000_REG_RDT, cur); 5591ad10e3aSDavid van Moolenbroek 5601ad10e3aSDavid van Moolenbroek /* Return the size of the received packet. */ 5611ad10e3aSDavid van Moolenbroek return size; 562433d6423SLionel Sambuc } 563433d6423SLionel Sambuc 564107df7c8SDavid van Moolenbroek /* 565*f7df02e7SDavid van Moolenbroek * Return the link and media status. 566107df7c8SDavid van Moolenbroek */ 567*f7df02e7SDavid van Moolenbroek static unsigned int 568*f7df02e7SDavid van Moolenbroek e1000_get_link(uint32_t * media) 569433d6423SLionel Sambuc { 570*f7df02e7SDavid van Moolenbroek uint32_t status, type; 571433d6423SLionel Sambuc 572*f7df02e7SDavid van Moolenbroek status = e1000_reg_read(&e1000_state, E1000_REG_STATUS); 573433d6423SLionel Sambuc 574*f7df02e7SDavid van Moolenbroek if (!(status & E1000_REG_STATUS_LU)) 575*f7df02e7SDavid van Moolenbroek return NDEV_LINK_DOWN; 576*f7df02e7SDavid van Moolenbroek 577*f7df02e7SDavid van Moolenbroek if (status & E1000_REG_STATUS_FD) 578*f7df02e7SDavid van Moolenbroek type = IFM_ETHER | IFM_FDX; 579*f7df02e7SDavid van Moolenbroek else 580*f7df02e7SDavid van Moolenbroek type = IFM_ETHER | IFM_HDX; 581*f7df02e7SDavid van Moolenbroek 582*f7df02e7SDavid van Moolenbroek switch (status & E1000_REG_STATUS_SPEED) { 583*f7df02e7SDavid van Moolenbroek case E1000_REG_STATUS_SPEED_10: 584*f7df02e7SDavid van Moolenbroek type |= IFM_10_T; 585*f7df02e7SDavid van Moolenbroek break; 586*f7df02e7SDavid van Moolenbroek case E1000_REG_STATUS_SPEED_100: 587*f7df02e7SDavid van Moolenbroek type |= IFM_100_TX; 588*f7df02e7SDavid van Moolenbroek break; 589*f7df02e7SDavid van Moolenbroek case E1000_REG_STATUS_SPEED_1000_A: 590*f7df02e7SDavid van Moolenbroek case E1000_REG_STATUS_SPEED_1000_B: 591*f7df02e7SDavid van Moolenbroek type |= IFM_1000_T; 592*f7df02e7SDavid van Moolenbroek break; 5931ad10e3aSDavid van Moolenbroek } 594433d6423SLionel Sambuc 595*f7df02e7SDavid van Moolenbroek *media = type; 596*f7df02e7SDavid van Moolenbroek return NDEV_LINK_UP; 597433d6423SLionel Sambuc } 598433d6423SLionel Sambuc 599107df7c8SDavid van Moolenbroek /* 600107df7c8SDavid van Moolenbroek * Handle an interrupt. 601107df7c8SDavid van Moolenbroek */ 602107df7c8SDavid van Moolenbroek static void 6031ad10e3aSDavid van Moolenbroek e1000_intr(unsigned int __unused mask) 604433d6423SLionel Sambuc { 605433d6423SLionel Sambuc e1000_t *e; 606433d6423SLionel Sambuc u32_t cause; 607433d6423SLionel Sambuc 608433d6423SLionel Sambuc E1000_DEBUG(3, ("e1000: interrupt\n")); 609433d6423SLionel Sambuc 610433d6423SLionel Sambuc e = &e1000_state; 611433d6423SLionel Sambuc 612107df7c8SDavid van Moolenbroek /* Reenable interrupts. */ 613433d6423SLionel Sambuc if (sys_irqenable(&e->irq_hook) != OK) 614433d6423SLionel Sambuc panic("failed to re-enable IRQ"); 615433d6423SLionel Sambuc 616433d6423SLionel Sambuc /* Read the Interrupt Cause Read register. */ 617107df7c8SDavid van Moolenbroek if ((cause = e1000_reg_read(e, E1000_REG_ICR)) != 0) { 618433d6423SLionel Sambuc if (cause & E1000_REG_ICR_LSC) 619*f7df02e7SDavid van Moolenbroek netdriver_link(); 620433d6423SLionel Sambuc 621433d6423SLionel Sambuc if (cause & (E1000_REG_ICR_RXO | E1000_REG_ICR_RXT)) 6221ad10e3aSDavid van Moolenbroek netdriver_recv(); 623433d6423SLionel Sambuc 624107df7c8SDavid van Moolenbroek if (cause & (E1000_REG_ICR_TXQE | E1000_REG_ICR_TXDW)) 6251ad10e3aSDavid van Moolenbroek netdriver_send(); 626433d6423SLionel Sambuc } 627433d6423SLionel Sambuc } 628433d6423SLionel Sambuc 629107df7c8SDavid van Moolenbroek /* 630*f7df02e7SDavid van Moolenbroek * Do regular processing. 631*f7df02e7SDavid van Moolenbroek */ 632*f7df02e7SDavid van Moolenbroek static void 633*f7df02e7SDavid van Moolenbroek e1000_tick(void) 634*f7df02e7SDavid van Moolenbroek { 635*f7df02e7SDavid van Moolenbroek e1000_t *e; 636*f7df02e7SDavid van Moolenbroek 637*f7df02e7SDavid van Moolenbroek e = &e1000_state; 638*f7df02e7SDavid van Moolenbroek 639*f7df02e7SDavid van Moolenbroek /* Update statistics. */ 640*f7df02e7SDavid van Moolenbroek netdriver_stat_ierror(e1000_reg_read(e, E1000_REG_RXERRC)); 641*f7df02e7SDavid van Moolenbroek netdriver_stat_ierror(e1000_reg_read(e, E1000_REG_CRCERRS)); 642*f7df02e7SDavid van Moolenbroek netdriver_stat_ierror(e1000_reg_read(e, E1000_REG_MPC)); 643*f7df02e7SDavid van Moolenbroek netdriver_stat_coll(e1000_reg_read(e, E1000_REG_COLC)); 644*f7df02e7SDavid van Moolenbroek } 645*f7df02e7SDavid van Moolenbroek 646*f7df02e7SDavid van Moolenbroek /* 647107df7c8SDavid van Moolenbroek * Stop the card. 648107df7c8SDavid van Moolenbroek */ 649107df7c8SDavid van Moolenbroek static void 6501ad10e3aSDavid van Moolenbroek e1000_stop(void) 651433d6423SLionel Sambuc { 6521ad10e3aSDavid van Moolenbroek e1000_t *e; 6531ad10e3aSDavid van Moolenbroek 6541ad10e3aSDavid van Moolenbroek e = &e1000_state; 655107df7c8SDavid van Moolenbroek 656*f7df02e7SDavid van Moolenbroek E1000_DEBUG(3, ("%s: stop()\n", netdriver_name())); 657433d6423SLionel Sambuc 658433d6423SLionel Sambuc e1000_reset_hw(e); 659433d6423SLionel Sambuc } 660433d6423SLionel Sambuc 661107df7c8SDavid van Moolenbroek /* 662107df7c8SDavid van Moolenbroek * Read from a register. 663107df7c8SDavid van Moolenbroek */ 664107df7c8SDavid van Moolenbroek static uint32_t 665107df7c8SDavid van Moolenbroek e1000_reg_read(e1000_t * e, uint32_t reg) 666433d6423SLionel Sambuc { 667433d6423SLionel Sambuc uint32_t value; 668433d6423SLionel Sambuc 669433d6423SLionel Sambuc /* Assume a sane register. */ 670433d6423SLionel Sambuc assert(reg < 0x1ffff); 671433d6423SLionel Sambuc 672433d6423SLionel Sambuc /* Read from memory mapped register. */ 673107df7c8SDavid van Moolenbroek value = *(volatile uint32_t *)(e->regs + reg); 674433d6423SLionel Sambuc 675433d6423SLionel Sambuc /* Return the result. */ 676433d6423SLionel Sambuc return value; 677433d6423SLionel Sambuc } 678433d6423SLionel Sambuc 679107df7c8SDavid van Moolenbroek /* 680107df7c8SDavid van Moolenbroek * Write to a register. 681107df7c8SDavid van Moolenbroek */ 682107df7c8SDavid van Moolenbroek static void 683107df7c8SDavid van Moolenbroek e1000_reg_write(e1000_t * e, uint32_t reg, uint32_t value) 684433d6423SLionel Sambuc { 685107df7c8SDavid van Moolenbroek 686433d6423SLionel Sambuc /* Assume a sane register. */ 687433d6423SLionel Sambuc assert(reg < 0x1ffff); 688433d6423SLionel Sambuc 689433d6423SLionel Sambuc /* Write to memory mapped register. */ 690433d6423SLionel Sambuc *(volatile u32_t *)(e->regs + reg) = value; 691433d6423SLionel Sambuc } 692433d6423SLionel Sambuc 693107df7c8SDavid van Moolenbroek /* 694107df7c8SDavid van Moolenbroek * Set bits in a register. 695107df7c8SDavid van Moolenbroek */ 696107df7c8SDavid van Moolenbroek static void 697107df7c8SDavid van Moolenbroek e1000_reg_set(e1000_t * e, uint32_t reg, uint32_t value) 698433d6423SLionel Sambuc { 699433d6423SLionel Sambuc uint32_t data; 700433d6423SLionel Sambuc 701433d6423SLionel Sambuc /* First read the current value. */ 702433d6423SLionel Sambuc data = e1000_reg_read(e, reg); 703433d6423SLionel Sambuc 704107df7c8SDavid van Moolenbroek /* Set bits, and write back. */ 705433d6423SLionel Sambuc e1000_reg_write(e, reg, data | value); 706433d6423SLionel Sambuc } 707433d6423SLionel Sambuc 708107df7c8SDavid van Moolenbroek /* 709107df7c8SDavid van Moolenbroek * Clear bits in a register. 710107df7c8SDavid van Moolenbroek */ 711107df7c8SDavid van Moolenbroek static void 712107df7c8SDavid van Moolenbroek e1000_reg_unset(e1000_t * e, uint32_t reg, uint32_t value) 713433d6423SLionel Sambuc { 714433d6423SLionel Sambuc uint32_t data; 715433d6423SLionel Sambuc 716433d6423SLionel Sambuc /* First read the current value. */ 717433d6423SLionel Sambuc data = e1000_reg_read(e, reg); 718433d6423SLionel Sambuc 719107df7c8SDavid van Moolenbroek /* Unset bits, and write back. */ 720433d6423SLionel Sambuc e1000_reg_write(e, reg, data & ~value); 721433d6423SLionel Sambuc } 722433d6423SLionel Sambuc 723107df7c8SDavid van Moolenbroek /* 724107df7c8SDavid van Moolenbroek * Read from EEPROM. 725107df7c8SDavid van Moolenbroek */ 726107df7c8SDavid van Moolenbroek static u16_t 7271ad10e3aSDavid van Moolenbroek eeprom_eerd(e1000_t * e, int reg) 728433d6423SLionel Sambuc { 729433d6423SLionel Sambuc u32_t data; 730433d6423SLionel Sambuc 731433d6423SLionel Sambuc /* Request EEPROM read. */ 732433d6423SLionel Sambuc e1000_reg_write(e, E1000_REG_EERD, 733433d6423SLionel Sambuc (reg << e->eeprom_addr_off) | (E1000_REG_EERD_START)); 734433d6423SLionel Sambuc 735433d6423SLionel Sambuc /* Wait until ready. */ 736107df7c8SDavid van Moolenbroek while (!((data = (e1000_reg_read(e, E1000_REG_EERD))) & 737107df7c8SDavid van Moolenbroek e->eeprom_done_bit)); 738433d6423SLionel Sambuc 739433d6423SLionel Sambuc return data >> 16; 740433d6423SLionel Sambuc } 741433d6423SLionel Sambuc 742107df7c8SDavid van Moolenbroek /* 743107df7c8SDavid van Moolenbroek * Initialize ICH8 flash. 744107df7c8SDavid van Moolenbroek */ 745107df7c8SDavid van Moolenbroek static int 746107df7c8SDavid van Moolenbroek eeprom_ich_init(e1000_t * e) 747433d6423SLionel Sambuc { 748433d6423SLionel Sambuc union ich8_hws_flash_status hsfsts; 749433d6423SLionel Sambuc int ret_val = -1; 750433d6423SLionel Sambuc int i = 0; 751433d6423SLionel Sambuc 752433d6423SLionel Sambuc hsfsts.regval = E1000_READ_FLASH_REG16(e, ICH_FLASH_HSFSTS); 753433d6423SLionel Sambuc 754433d6423SLionel Sambuc /* Check if the flash descriptor is valid */ 755107df7c8SDavid van Moolenbroek if (hsfsts.hsf_status.fldesvalid == 0) { 756433d6423SLionel Sambuc E1000_DEBUG(3, ("Flash descriptor invalid. " 757433d6423SLionel Sambuc "SW Sequencing must be used.")); 7581ad10e3aSDavid van Moolenbroek return ret_val; 759433d6423SLionel Sambuc } 760107df7c8SDavid van Moolenbroek 761433d6423SLionel Sambuc /* Clear FCERR and DAEL in hw status by writing 1 */ 762433d6423SLionel Sambuc hsfsts.hsf_status.flcerr = 1; 763433d6423SLionel Sambuc hsfsts.hsf_status.dael = 1; 764433d6423SLionel Sambuc 765433d6423SLionel Sambuc E1000_WRITE_FLASH_REG16(e, ICH_FLASH_HSFSTS, hsfsts.regval); 766433d6423SLionel Sambuc 767433d6423SLionel Sambuc /* 768107df7c8SDavid van Moolenbroek * Either we should have a hardware SPI cycle in progress bit to check 769107df7c8SDavid van Moolenbroek * against, in order to start a new cycle or FDONE bit should be 770107df7c8SDavid van Moolenbroek * changed in the hardware so that it is 1 after hardware reset, which 771107df7c8SDavid van Moolenbroek * can then be used as an indication whether a cycle is in progress or 772107df7c8SDavid van Moolenbroek * has been completed. 773433d6423SLionel Sambuc */ 774107df7c8SDavid van Moolenbroek if (hsfsts.hsf_status.flcinprog == 0) { 775433d6423SLionel Sambuc /* 776107df7c8SDavid van Moolenbroek * There is no cycle running at present, so we can start a 777107df7c8SDavid van Moolenbroek * cycle. Begin by setting Flash Cycle Done. 778433d6423SLionel Sambuc */ 779433d6423SLionel Sambuc hsfsts.hsf_status.flcdone = 1; 780433d6423SLionel Sambuc E1000_WRITE_FLASH_REG16(e, ICH_FLASH_HSFSTS, hsfsts.regval); 781433d6423SLionel Sambuc ret_val = 0; 782107df7c8SDavid van Moolenbroek } else { 783433d6423SLionel Sambuc /* 784107df7c8SDavid van Moolenbroek * Otherwise poll for sometime so the current cycle has a 785107df7c8SDavid van Moolenbroek * chance to end before giving up. 786433d6423SLionel Sambuc */ 787107df7c8SDavid van Moolenbroek for (i = 0; i < ICH_FLASH_READ_COMMAND_TIMEOUT; i++) { 788107df7c8SDavid van Moolenbroek hsfsts.regval = E1000_READ_FLASH_REG16(e, 789107df7c8SDavid van Moolenbroek ICH_FLASH_HSFSTS); 790433d6423SLionel Sambuc 791107df7c8SDavid van Moolenbroek if (hsfsts.hsf_status.flcinprog == 0) { 792433d6423SLionel Sambuc ret_val = 0; 793433d6423SLionel Sambuc break; 794433d6423SLionel Sambuc } 795433d6423SLionel Sambuc tickdelay(1); 796433d6423SLionel Sambuc } 797107df7c8SDavid van Moolenbroek if (ret_val == 0) { 798433d6423SLionel Sambuc /* 799433d6423SLionel Sambuc * Successful in waiting for previous cycle to timeout, 800433d6423SLionel Sambuc * now set the Flash Cycle Done. 801433d6423SLionel Sambuc */ 802433d6423SLionel Sambuc hsfsts.hsf_status.flcdone = 1; 803433d6423SLionel Sambuc E1000_WRITE_FLASH_REG16(e, ICH_FLASH_HSFSTS, 804433d6423SLionel Sambuc hsfsts.regval); 805107df7c8SDavid van Moolenbroek } else { 806107df7c8SDavid van Moolenbroek E1000_DEBUG(3, 807107df7c8SDavid van Moolenbroek ("Flash controller busy, cannot get access")); 808433d6423SLionel Sambuc } 809433d6423SLionel Sambuc } 8101ad10e3aSDavid van Moolenbroek 811433d6423SLionel Sambuc return ret_val; 812433d6423SLionel Sambuc } 813433d6423SLionel Sambuc 814107df7c8SDavid van Moolenbroek /* 815107df7c8SDavid van Moolenbroek * Start ICH8 flash cycle. 816107df7c8SDavid van Moolenbroek */ 817107df7c8SDavid van Moolenbroek static int 818107df7c8SDavid van Moolenbroek eeprom_ich_cycle(e1000_t * e, u32_t timeout) 819433d6423SLionel Sambuc { 820433d6423SLionel Sambuc union ich8_hws_flash_ctrl hsflctl; 821433d6423SLionel Sambuc union ich8_hws_flash_status hsfsts; 822433d6423SLionel Sambuc int ret_val = -1; 823433d6423SLionel Sambuc u32_t i = 0; 824433d6423SLionel Sambuc 825433d6423SLionel Sambuc E1000_DEBUG(3, ("e1000_flash_cycle_ich8lan")); 826433d6423SLionel Sambuc 827433d6423SLionel Sambuc /* Start a cycle by writing 1 in Flash Cycle Go in Hw Flash Control */ 828433d6423SLionel Sambuc hsflctl.regval = E1000_READ_FLASH_REG16(e, ICH_FLASH_HSFCTL); 829433d6423SLionel Sambuc hsflctl.hsf_ctrl.flcgo = 1; 830433d6423SLionel Sambuc E1000_WRITE_FLASH_REG16(e, ICH_FLASH_HSFCTL, hsflctl.regval); 831433d6423SLionel Sambuc 832107df7c8SDavid van Moolenbroek /* Wait till the FDONE bit is set to 1 */ 833107df7c8SDavid van Moolenbroek do { 834433d6423SLionel Sambuc hsfsts.regval = E1000_READ_FLASH_REG16(e, ICH_FLASH_HSFSTS); 835433d6423SLionel Sambuc if (hsfsts.hsf_status.flcdone == 1) 836433d6423SLionel Sambuc break; 837433d6423SLionel Sambuc tickdelay(1); 838107df7c8SDavid van Moolenbroek } while (i++ < timeout); 839433d6423SLionel Sambuc 840433d6423SLionel Sambuc if (hsfsts.hsf_status.flcdone == 1 && hsfsts.hsf_status.flcerr == 0) 841433d6423SLionel Sambuc ret_val = 0; 842433d6423SLionel Sambuc 843433d6423SLionel Sambuc return ret_val; 844433d6423SLionel Sambuc } 845433d6423SLionel Sambuc 846107df7c8SDavid van Moolenbroek /* 847107df7c8SDavid van Moolenbroek * Read from ICH8 flash. 848107df7c8SDavid van Moolenbroek */ 849107df7c8SDavid van Moolenbroek static u16_t 8501ad10e3aSDavid van Moolenbroek eeprom_ich(e1000_t * e, int reg) 851433d6423SLionel Sambuc { 852433d6423SLionel Sambuc union ich8_hws_flash_status hsfsts; 853433d6423SLionel Sambuc union ich8_hws_flash_ctrl hsflctl; 854433d6423SLionel Sambuc u32_t flash_linear_addr; 855433d6423SLionel Sambuc u32_t flash_data = 0; 856433d6423SLionel Sambuc int ret_val = -1; 857433d6423SLionel Sambuc u8_t count = 0; 858433d6423SLionel Sambuc u16_t data = 0; 859433d6423SLionel Sambuc 860433d6423SLionel Sambuc E1000_DEBUG(3, ("e1000_read_flash_data_ich8lan")); 861433d6423SLionel Sambuc 862433d6423SLionel Sambuc if (reg > ICH_FLASH_LINEAR_ADDR_MASK) 8631ad10e3aSDavid van Moolenbroek return data; 864433d6423SLionel Sambuc 865433d6423SLionel Sambuc reg *= sizeof(u16_t); 866433d6423SLionel Sambuc flash_linear_addr = (ICH_FLASH_LINEAR_ADDR_MASK & reg) + 867433d6423SLionel Sambuc e->flash_base_addr; 868433d6423SLionel Sambuc 869433d6423SLionel Sambuc do { 870433d6423SLionel Sambuc tickdelay(1); 871433d6423SLionel Sambuc 872433d6423SLionel Sambuc /* Steps */ 873433d6423SLionel Sambuc ret_val = eeprom_ich_init(e); 874433d6423SLionel Sambuc if (ret_val != 0) 875433d6423SLionel Sambuc break; 876433d6423SLionel Sambuc 877433d6423SLionel Sambuc hsflctl.regval = E1000_READ_FLASH_REG16(e, ICH_FLASH_HSFCTL); 878433d6423SLionel Sambuc /* 0b/1b corresponds to 1 or 2 byte size, respectively. */ 879433d6423SLionel Sambuc hsflctl.hsf_ctrl.fldbcount = 1; 880433d6423SLionel Sambuc hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_READ; 881433d6423SLionel Sambuc E1000_WRITE_FLASH_REG16(e, ICH_FLASH_HSFCTL, hsflctl.regval); 882433d6423SLionel Sambuc E1000_WRITE_FLASH_REG(e, ICH_FLASH_FADDR, flash_linear_addr); 883433d6423SLionel Sambuc 8841ad10e3aSDavid van Moolenbroek ret_val = eeprom_ich_cycle(e, ICH_FLASH_READ_COMMAND_TIMEOUT); 885433d6423SLionel Sambuc 886433d6423SLionel Sambuc /* 887107df7c8SDavid van Moolenbroek * Check if FCERR is set to 1, if set to 1, clear it and try 888107df7c8SDavid van Moolenbroek * the whole sequence a few more times, else read in (shift in) 889107df7c8SDavid van Moolenbroek * the Flash Data0, the order is least significant byte first 890107df7c8SDavid van Moolenbroek * msb to lsb. 891433d6423SLionel Sambuc */ 892107df7c8SDavid van Moolenbroek if (ret_val == 0) { 893433d6423SLionel Sambuc flash_data = E1000_READ_FLASH_REG(e, ICH_FLASH_FDATA0); 894433d6423SLionel Sambuc data = (u16_t)(flash_data & 0x0000FFFF); 895433d6423SLionel Sambuc break; 896107df7c8SDavid van Moolenbroek } else { 897433d6423SLionel Sambuc /* 898433d6423SLionel Sambuc * If we've gotten here, then things are probably 899433d6423SLionel Sambuc * completely hosed, but if the error condition is 900433d6423SLionel Sambuc * detected, it won't hurt to give it another try... 901433d6423SLionel Sambuc * ICH_FLASH_CYCLE_REPEAT_COUNT times. 902433d6423SLionel Sambuc */ 903107df7c8SDavid van Moolenbroek hsfsts.regval = E1000_READ_FLASH_REG16(e, 904107df7c8SDavid van Moolenbroek ICH_FLASH_HSFSTS); 905433d6423SLionel Sambuc 906107df7c8SDavid van Moolenbroek if (hsfsts.hsf_status.flcerr == 1) { 907433d6423SLionel Sambuc /* Repeat for some time before giving up. */ 908433d6423SLionel Sambuc continue; 909107df7c8SDavid van Moolenbroek } else if (hsfsts.hsf_status.flcdone == 0) { 910433d6423SLionel Sambuc E1000_DEBUG(3, ("Timeout error - flash cycle " 911433d6423SLionel Sambuc "did not complete.")); 912433d6423SLionel Sambuc break; 913433d6423SLionel Sambuc } 914433d6423SLionel Sambuc } 915433d6423SLionel Sambuc } while (count++ < ICH_FLASH_CYCLE_REPEAT_COUNT); 916433d6423SLionel Sambuc 917433d6423SLionel Sambuc return data; 918433d6423SLionel Sambuc } 919