1*107df7c8SDavid 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 <stdlib.h> 6433d6423SLionel Sambuc #include <net/gen/ether.h> 7433d6423SLionel Sambuc #include <net/gen/eth_io.h> 8433d6423SLionel Sambuc #include <machine/pci.h> 9433d6423SLionel Sambuc #include <minix/ds.h> 10433d6423SLionel Sambuc #include <minix/vm.h> 11433d6423SLionel Sambuc #include <minix/timers.h> 12433d6423SLionel Sambuc #include <sys/mman.h> 13433d6423SLionel Sambuc #include "assert.h" 14433d6423SLionel Sambuc #include "e1000.h" 15433d6423SLionel Sambuc #include "e1000_hw.h" 16433d6423SLionel Sambuc #include "e1000_reg.h" 17433d6423SLionel Sambuc #include "e1000_pci.h" 18433d6423SLionel Sambuc 19433d6423SLionel Sambuc static int e1000_instance; 20433d6423SLionel Sambuc static e1000_t e1000_state; 21433d6423SLionel Sambuc 22433d6423SLionel Sambuc static void e1000_init(message *mp); 23433d6423SLionel Sambuc static void e1000_init_pci(void); 24433d6423SLionel Sambuc static int e1000_probe(e1000_t *e, int skip); 25433d6423SLionel Sambuc static int e1000_init_hw(e1000_t *e); 26433d6423SLionel Sambuc static void e1000_init_addr(e1000_t *e); 27433d6423SLionel Sambuc static void e1000_init_buf(e1000_t *e); 28433d6423SLionel Sambuc static void e1000_reset_hw(e1000_t *e); 29433d6423SLionel Sambuc static void e1000_writev_s(message *mp, int from_int); 30433d6423SLionel Sambuc static void e1000_readv_s(message *mp, int from_int); 31433d6423SLionel Sambuc static void e1000_getstat_s(message *mp); 32433d6423SLionel Sambuc static void e1000_interrupt(message *mp); 33433d6423SLionel Sambuc static int e1000_link_changed(e1000_t *e); 34433d6423SLionel Sambuc static void e1000_stop(e1000_t *e); 35433d6423SLionel Sambuc static uint32_t e1000_reg_read(e1000_t *e, uint32_t reg); 36433d6423SLionel Sambuc static void e1000_reg_write(e1000_t *e, uint32_t reg, uint32_t value); 37433d6423SLionel Sambuc static void e1000_reg_set(e1000_t *e, uint32_t reg, uint32_t value); 38433d6423SLionel Sambuc static void e1000_reg_unset(e1000_t *e, uint32_t reg, uint32_t value); 39433d6423SLionel Sambuc static u16_t eeprom_eerd(void *e, int reg); 40433d6423SLionel Sambuc static u16_t eeprom_ich(void *e, int reg); 41433d6423SLionel Sambuc static int eeprom_ich_init(e1000_t *e); 42*107df7c8SDavid van Moolenbroek static int eeprom_ich_cycle(e1000_t *e, u32_t timeout); 43433d6423SLionel Sambuc static void reply(e1000_t *e); 44433d6423SLionel Sambuc static void mess_reply(message *req, message *reply); 45433d6423SLionel Sambuc 46433d6423SLionel Sambuc /* SEF functions and variables. */ 47433d6423SLionel Sambuc static void sef_local_startup(void); 48433d6423SLionel Sambuc static int sef_cb_init_fresh(int type, sef_init_info_t *info); 49433d6423SLionel Sambuc static void sef_cb_signal_handler(int signo); 50433d6423SLionel Sambuc 51*107df7c8SDavid van Moolenbroek /* 52*107df7c8SDavid van Moolenbroek * The e1000 driver. 53*107df7c8SDavid van Moolenbroek */ 54*107df7c8SDavid van Moolenbroek int 55*107df7c8SDavid van Moolenbroek main(int argc, char * argv[]) 56433d6423SLionel Sambuc { 57433d6423SLionel Sambuc message m; 58433d6423SLionel Sambuc int ipc_status; 59433d6423SLionel Sambuc int r; 60433d6423SLionel Sambuc 61433d6423SLionel Sambuc /* SEF local startup. */ 62433d6423SLionel Sambuc env_setargs(argc, argv); 63433d6423SLionel Sambuc sef_local_startup(); 64433d6423SLionel Sambuc 65433d6423SLionel Sambuc /* 66433d6423SLionel Sambuc * Enter the main driver loop. 67433d6423SLionel Sambuc */ 68*107df7c8SDavid van Moolenbroek while (TRUE) { 69433d6423SLionel Sambuc if ((r = netdriver_receive(ANY, &m, &ipc_status)) != OK) 70433d6423SLionel Sambuc panic("netdriver_receive failed: %d", r); 71433d6423SLionel Sambuc 72*107df7c8SDavid van Moolenbroek if (is_ipc_notify(ipc_status)) { 73*107df7c8SDavid van Moolenbroek switch (_ENDPOINT_P(m.m_source)) { 74433d6423SLionel Sambuc case HARDWARE: 75433d6423SLionel Sambuc e1000_interrupt(&m); 76433d6423SLionel Sambuc break; 77433d6423SLionel Sambuc } 78*107df7c8SDavid van Moolenbroek 79433d6423SLionel Sambuc continue; 80433d6423SLionel Sambuc } 81*107df7c8SDavid van Moolenbroek 82*107df7c8SDavid van Moolenbroek switch (m.m_type) { 83433d6423SLionel Sambuc case DL_WRITEV_S: e1000_writev_s(&m, FALSE); break; 84433d6423SLionel Sambuc case DL_READV_S: e1000_readv_s(&m, FALSE); break; 85433d6423SLionel Sambuc case DL_CONF: e1000_init(&m); break; 86433d6423SLionel Sambuc case DL_GETSTAT_S: e1000_getstat_s(&m); break; 87*107df7c8SDavid van Moolenbroek default: panic("illegal message: %d", m.m_type); 88433d6423SLionel Sambuc } 89433d6423SLionel Sambuc } 90433d6423SLionel Sambuc } 91433d6423SLionel Sambuc 92*107df7c8SDavid van Moolenbroek /* 93*107df7c8SDavid van Moolenbroek * Perform SEF initialization. 94*107df7c8SDavid van Moolenbroek */ 95*107df7c8SDavid van Moolenbroek static void 96*107df7c8SDavid van Moolenbroek sef_local_startup(void) 97433d6423SLionel Sambuc { 98*107df7c8SDavid van Moolenbroek 99433d6423SLionel Sambuc /* Register init callbacks. */ 100433d6423SLionel Sambuc sef_setcb_init_fresh(sef_cb_init_fresh); 101433d6423SLionel Sambuc sef_setcb_init_lu(sef_cb_init_fresh); 102433d6423SLionel Sambuc sef_setcb_init_restart(sef_cb_init_fresh); 103433d6423SLionel Sambuc 104433d6423SLionel Sambuc /* Register live update callbacks. */ 105433d6423SLionel Sambuc sef_setcb_lu_prepare(sef_cb_lu_prepare_always_ready); 106433d6423SLionel Sambuc sef_setcb_lu_state_isvalid(sef_cb_lu_state_isvalid_workfree); 107433d6423SLionel Sambuc 108433d6423SLionel Sambuc /* Register signal callbacks. */ 109433d6423SLionel Sambuc sef_setcb_signal_handler(sef_cb_signal_handler); 110433d6423SLionel Sambuc 111433d6423SLionel Sambuc /* Let SEF perform startup. */ 112433d6423SLionel Sambuc sef_startup(); 113433d6423SLionel Sambuc } 114433d6423SLionel Sambuc 115*107df7c8SDavid van Moolenbroek /* 116*107df7c8SDavid van Moolenbroek * Initialize the e1000 driver. 117*107df7c8SDavid van Moolenbroek */ 118*107df7c8SDavid van Moolenbroek static int 119*107df7c8SDavid van Moolenbroek sef_cb_init_fresh(int __unused type, sef_init_info_t * __unused info) 120433d6423SLionel Sambuc { 121433d6423SLionel Sambuc long v; 122433d6423SLionel Sambuc int r; 123433d6423SLionel Sambuc 124433d6423SLionel Sambuc v = 0; 125433d6423SLionel Sambuc (void)env_parse("instance", "d", 0, &v, 0, 255); 126433d6423SLionel Sambuc e1000_instance = (int) v; 127433d6423SLionel Sambuc 128433d6423SLionel Sambuc /* Clear state. */ 129433d6423SLionel Sambuc memset(&e1000_state, 0, sizeof(e1000_state)); 130433d6423SLionel Sambuc 131433d6423SLionel Sambuc /* Perform calibration. */ 132433d6423SLionel Sambuc if ((r = tsc_calibrate()) != OK) 133433d6423SLionel Sambuc panic("tsc_calibrate failed: %d", r); 134433d6423SLionel Sambuc 135433d6423SLionel Sambuc /* Announce we are up! */ 136433d6423SLionel Sambuc netdriver_announce(); 137433d6423SLionel Sambuc 138*107df7c8SDavid van Moolenbroek return OK; 139433d6423SLionel Sambuc } 140433d6423SLionel Sambuc 141*107df7c8SDavid van Moolenbroek /* 142*107df7c8SDavid van Moolenbroek * Process a signal. 143*107df7c8SDavid van Moolenbroek */ 144*107df7c8SDavid van Moolenbroek static void 145*107df7c8SDavid van Moolenbroek sef_cb_signal_handler(int signo) 146433d6423SLionel Sambuc { 147433d6423SLionel Sambuc e1000_t *e; 148*107df7c8SDavid van Moolenbroek 149433d6423SLionel Sambuc e = &e1000_state; 150433d6423SLionel Sambuc 151433d6423SLionel Sambuc E1000_DEBUG(3, ("%s: got signal\n", e->name)); 152433d6423SLionel Sambuc 153433d6423SLionel Sambuc /* Only check for termination signal, ignore anything else. */ 154433d6423SLionel Sambuc if (signo != SIGTERM) return; 155433d6423SLionel Sambuc 156433d6423SLionel Sambuc e1000_stop(e); 157433d6423SLionel Sambuc } 158433d6423SLionel Sambuc 159*107df7c8SDavid van Moolenbroek /* 160*107df7c8SDavid van Moolenbroek * Process a configuration message from Inet. 161*107df7c8SDavid van Moolenbroek */ 162*107df7c8SDavid van Moolenbroek static void 163*107df7c8SDavid van Moolenbroek e1000_init(message * mp) 164433d6423SLionel Sambuc { 165433d6423SLionel Sambuc static int first_time = 1; 166433d6423SLionel Sambuc message reply_mess; 167433d6423SLionel Sambuc e1000_t *e; 168433d6423SLionel Sambuc 169433d6423SLionel Sambuc E1000_DEBUG(3, ("e1000: init()\n")); 170433d6423SLionel Sambuc 171433d6423SLionel Sambuc /* Configure PCI devices, if needed. */ 172*107df7c8SDavid van Moolenbroek if (first_time) { 173433d6423SLionel Sambuc first_time = 0; 174433d6423SLionel Sambuc e1000_init_pci(); 175433d6423SLionel Sambuc } 176*107df7c8SDavid van Moolenbroek 177433d6423SLionel Sambuc e = &e1000_state; 178433d6423SLionel Sambuc 179433d6423SLionel Sambuc /* Initialize hardware, if needed. */ 180*107df7c8SDavid van Moolenbroek if (!(e->status & E1000_ENABLED) && !(e1000_init_hw(e))) { 181433d6423SLionel Sambuc reply_mess.m_type = DL_CONF_REPLY; 182433d6423SLionel Sambuc reply_mess.m_netdrv_net_dl_conf.stat = ENXIO; 183433d6423SLionel Sambuc mess_reply(mp, &reply_mess); 184433d6423SLionel Sambuc return; 185433d6423SLionel Sambuc } 186*107df7c8SDavid van Moolenbroek 187433d6423SLionel Sambuc /* Reply back to INET. */ 188433d6423SLionel Sambuc reply_mess.m_type = DL_CONF_REPLY; 189433d6423SLionel Sambuc reply_mess.m_netdrv_net_dl_conf.stat = OK; 190433d6423SLionel Sambuc memcpy(reply_mess.m_netdrv_net_dl_conf.hw_addr, e->address.ea_addr, 191433d6423SLionel Sambuc sizeof(reply_mess.m_netdrv_net_dl_conf.hw_addr)); 192433d6423SLionel Sambuc mess_reply(mp, &reply_mess); 193433d6423SLionel Sambuc } 194433d6423SLionel Sambuc 195*107df7c8SDavid van Moolenbroek /* 196*107df7c8SDavid van Moolenbroek * Find a matching PCI device. 197*107df7c8SDavid van Moolenbroek */ 198*107df7c8SDavid van Moolenbroek static void 199*107df7c8SDavid van Moolenbroek e1000_init_pci(void) 200433d6423SLionel Sambuc { 201433d6423SLionel Sambuc e1000_t *e; 202433d6423SLionel Sambuc 203433d6423SLionel Sambuc /* Initialize the PCI bus. */ 204433d6423SLionel Sambuc pci_init(); 205433d6423SLionel Sambuc 206*107df7c8SDavid van Moolenbroek /* Try to detect e1000 cards. */ 207433d6423SLionel Sambuc e = &e1000_state; 208433d6423SLionel Sambuc strlcpy(e->name, "e1000#0", sizeof(e->name)); 209433d6423SLionel Sambuc e->name[6] += e1000_instance; 210*107df7c8SDavid van Moolenbroek 211433d6423SLionel Sambuc e1000_probe(e, e1000_instance); 212433d6423SLionel Sambuc } 213433d6423SLionel Sambuc 214*107df7c8SDavid van Moolenbroek /* 215*107df7c8SDavid van Moolenbroek * Find a matching device. Return TRUE on success. 216*107df7c8SDavid van Moolenbroek */ 217*107df7c8SDavid van Moolenbroek static int 218*107df7c8SDavid van Moolenbroek e1000_probe(e1000_t * e, int skip) 219433d6423SLionel Sambuc { 220433d6423SLionel Sambuc int r, devind, ioflag; 221433d6423SLionel Sambuc u16_t vid, did, cr; 222433d6423SLionel Sambuc u32_t status[2]; 223433d6423SLionel Sambuc u32_t base, size; 224*107df7c8SDavid van Moolenbroek size_t flash_size; 225433d6423SLionel Sambuc u32_t gfpreg, sector_base_addr; 226433d6423SLionel Sambuc char *dname; 227433d6423SLionel Sambuc 228433d6423SLionel Sambuc E1000_DEBUG(3, ("%s: probe()\n", e->name)); 229433d6423SLionel Sambuc 230*107df7c8SDavid van Moolenbroek /* Attempt to iterate the PCI bus. Start at the beginning. */ 231433d6423SLionel Sambuc if ((r = pci_first_dev(&devind, &vid, &did)) == 0) 232433d6423SLionel Sambuc return FALSE; 233*107df7c8SDavid van Moolenbroek 234433d6423SLionel Sambuc /* Loop devices on the PCI bus. */ 235*107df7c8SDavid van Moolenbroek while (skip--) { 236433d6423SLionel Sambuc E1000_DEBUG(3, ("%s: probe() devind %d vid 0x%x did 0x%x\n", 237433d6423SLionel Sambuc e->name, devind, vid, did)); 238433d6423SLionel Sambuc 239433d6423SLionel Sambuc if (!(r = pci_next_dev(&devind, &vid, &did))) 240433d6423SLionel Sambuc return FALSE; 241433d6423SLionel Sambuc } 242*107df7c8SDavid van Moolenbroek 243*107df7c8SDavid van Moolenbroek /* We found a matching card. Set card-specific properties. */ 244433d6423SLionel Sambuc e->status |= E1000_DETECTED; 245433d6423SLionel Sambuc e->eeprom_read = eeprom_eerd; 246433d6423SLionel Sambuc 247*107df7c8SDavid van Moolenbroek switch (did) { 248433d6423SLionel Sambuc case E1000_DEV_ID_ICH10_D_BM_LM: 249433d6423SLionel Sambuc case E1000_DEV_ID_ICH10_R_BM_LF: 250433d6423SLionel Sambuc e->eeprom_read = eeprom_ich; 251433d6423SLionel Sambuc break; 252433d6423SLionel Sambuc 253433d6423SLionel Sambuc case E1000_DEV_ID_82540EM: 254433d6423SLionel Sambuc case E1000_DEV_ID_82545EM: 255433d6423SLionel Sambuc e->eeprom_done_bit = (1 << 4); 256433d6423SLionel Sambuc e->eeprom_addr_off = 8; 257433d6423SLionel Sambuc break; 258433d6423SLionel Sambuc 259433d6423SLionel Sambuc default: 260433d6423SLionel Sambuc e->eeprom_done_bit = (1 << 1); 261433d6423SLionel Sambuc e->eeprom_addr_off = 2; 262433d6423SLionel Sambuc break; 263433d6423SLionel Sambuc } 264433d6423SLionel Sambuc 265433d6423SLionel Sambuc /* Inform the user about the new card. */ 266433d6423SLionel Sambuc if (!(dname = pci_dev_name(vid, did))) 267433d6423SLionel Sambuc dname = "Intel Pro/1000 Gigabit Ethernet Card"; 268433d6423SLionel Sambuc E1000_DEBUG(1, ("%s: %s (%04x/%04x/%02x) at %s\n", 269*107df7c8SDavid van Moolenbroek e->name, dname, vid, did, e->revision, pci_slot_name(devind))); 270433d6423SLionel Sambuc 271433d6423SLionel Sambuc /* Reserve PCI resources found. */ 272433d6423SLionel Sambuc if ((r = pci_reserve_ok(devind)) != OK) 273433d6423SLionel Sambuc panic("failed to reserve PCI device: %d", r); 274*107df7c8SDavid van Moolenbroek 275433d6423SLionel Sambuc /* Read PCI configuration. */ 276433d6423SLionel Sambuc e->irq = pci_attr_r8(devind, PCI_ILR); 277433d6423SLionel Sambuc 278433d6423SLionel Sambuc if ((r = pci_get_bar(devind, PCI_BAR, &base, &size, &ioflag)) != OK) 279*107df7c8SDavid van Moolenbroek panic("failed to get PCI BAR: %d", r); 280*107df7c8SDavid van Moolenbroek if (ioflag) 281*107df7c8SDavid van Moolenbroek panic("PCI BAR is not for memory"); 282433d6423SLionel Sambuc 283*107df7c8SDavid van Moolenbroek if ((e->regs = vm_map_phys(SELF, (void *)base, size)) == MAP_FAILED) 284433d6423SLionel Sambuc panic("failed to map hardware registers from PCI"); 285433d6423SLionel Sambuc 286*107df7c8SDavid van Moolenbroek /* Enable DMA bus mastering if necessary. */ 287433d6423SLionel Sambuc cr = pci_attr_r16(devind, PCI_CR); 288433d6423SLionel Sambuc if (!(cr & PCI_CR_MAST_EN)) 289433d6423SLionel Sambuc pci_attr_w16(devind, PCI_CR, cr | PCI_CR_MAST_EN); 290433d6423SLionel Sambuc 291433d6423SLionel Sambuc /* Optionally map flash memory. */ 292*107df7c8SDavid van Moolenbroek if (did != E1000_DEV_ID_82540EM && did != E1000_DEV_ID_82545EM && 293*107df7c8SDavid van Moolenbroek did != E1000_DEV_ID_82540EP && pci_attr_r32(devind, PCI_BAR_2)) { 294*107df7c8SDavid van Moolenbroek /* 295*107df7c8SDavid van Moolenbroek * 82566/82567/82562V series support mapping 4kB of flash 296*107df7c8SDavid van Moolenbroek * memory. 297*107df7c8SDavid van Moolenbroek */ 298*107df7c8SDavid van Moolenbroek switch (did) { 299433d6423SLionel Sambuc case E1000_DEV_ID_ICH10_D_BM_LM: 300433d6423SLionel Sambuc case E1000_DEV_ID_ICH10_R_BM_LF: 301433d6423SLionel Sambuc flash_size = 0x1000; 302433d6423SLionel Sambuc break; 303433d6423SLionel Sambuc default: 304433d6423SLionel Sambuc flash_size = 0x10000; 305433d6423SLionel Sambuc } 306433d6423SLionel Sambuc 307433d6423SLionel Sambuc if ((e->flash = vm_map_phys(SELF, 308433d6423SLionel Sambuc (void *)pci_attr_r32(devind, PCI_BAR_2), 309*107df7c8SDavid van Moolenbroek flash_size)) == MAP_FAILED) 310*107df7c8SDavid van Moolenbroek panic("e1000: couldn't map in flash"); 311433d6423SLionel Sambuc 312433d6423SLionel Sambuc /* 313433d6423SLionel Sambuc * sector_base_addr is a "sector"-aligned address (4096 bytes) 314433d6423SLionel Sambuc */ 315*107df7c8SDavid van Moolenbroek gfpreg = E1000_READ_FLASH_REG(e, ICH_FLASH_GFPREG); 316433d6423SLionel Sambuc sector_base_addr = gfpreg & FLASH_GFPREG_BASE_MASK; 317433d6423SLionel Sambuc 318433d6423SLionel Sambuc /* flash_base_addr is byte-aligned */ 319*107df7c8SDavid van Moolenbroek e->flash_base_addr = 320*107df7c8SDavid van Moolenbroek sector_base_addr << FLASH_SECTOR_ADDR_SHIFT; 321433d6423SLionel Sambuc } 322*107df7c8SDavid van Moolenbroek 323*107df7c8SDavid van Moolenbroek /* Output debug information. */ 324433d6423SLionel Sambuc status[0] = e1000_reg_read(e, E1000_REG_STATUS); 325*107df7c8SDavid van Moolenbroek E1000_DEBUG(3, ("%s: MEM at %p, IRQ %d\n", e->name, e->regs, e->irq)); 326*107df7c8SDavid van Moolenbroek E1000_DEBUG(3, ("%s: link %s, %s duplex\n", e->name, 327*107df7c8SDavid van Moolenbroek status[0] & 3 ? "up" : "down", status[0] & 1 ? "full" : "half")); 328*107df7c8SDavid van Moolenbroek 329433d6423SLionel Sambuc return TRUE; 330433d6423SLionel Sambuc } 331433d6423SLionel Sambuc 332*107df7c8SDavid van Moolenbroek /* 333*107df7c8SDavid van Moolenbroek * Initialize the hardware. 334*107df7c8SDavid van Moolenbroek */ 335*107df7c8SDavid van Moolenbroek static int 336*107df7c8SDavid van Moolenbroek e1000_init_hw(e1000_t * e) 337433d6423SLionel Sambuc { 338433d6423SLionel Sambuc int r, i; 339433d6423SLionel Sambuc 340433d6423SLionel Sambuc e->status |= E1000_ENABLED; 341433d6423SLionel Sambuc e->irq_hook = e->irq; 342433d6423SLionel Sambuc 343433d6423SLionel Sambuc /* 344433d6423SLionel Sambuc * Set the interrupt handler and policy. Do not automatically 345*107df7c8SDavid van Moolenbroek * reenable interrupts. Return the IRQ line number on interrupts. 346433d6423SLionel Sambuc */ 347433d6423SLionel Sambuc if ((r = sys_irqsetpolicy(e->irq, 0, &e->irq_hook)) != OK) 348433d6423SLionel Sambuc panic("sys_irqsetpolicy failed: %d", r); 349433d6423SLionel Sambuc if ((r = sys_irqenable(&e->irq_hook)) != OK) 350433d6423SLionel Sambuc panic("sys_irqenable failed: %d", r); 351*107df7c8SDavid van Moolenbroek 352433d6423SLionel Sambuc /* Reset hardware. */ 353433d6423SLionel Sambuc e1000_reset_hw(e); 354433d6423SLionel Sambuc 355433d6423SLionel Sambuc /* 356*107df7c8SDavid van Moolenbroek * Initialize appropriately, according to section 14.3 General 357*107df7c8SDavid van Moolenbroek * Configuration of Intel's Gigabit Ethernet Controllers Software 358*107df7c8SDavid van Moolenbroek * Developer's Manual. 359433d6423SLionel Sambuc */ 360*107df7c8SDavid van Moolenbroek e1000_reg_set(e, E1000_REG_CTRL, 361*107df7c8SDavid van Moolenbroek E1000_REG_CTRL_ASDE | E1000_REG_CTRL_SLU); 362433d6423SLionel Sambuc e1000_reg_unset(e, E1000_REG_CTRL, E1000_REG_CTRL_LRST); 363433d6423SLionel Sambuc e1000_reg_unset(e, E1000_REG_CTRL, E1000_REG_CTRL_PHY_RST); 364433d6423SLionel Sambuc e1000_reg_unset(e, E1000_REG_CTRL, E1000_REG_CTRL_ILOS); 365433d6423SLionel Sambuc e1000_reg_write(e, E1000_REG_FCAL, 0); 366433d6423SLionel Sambuc e1000_reg_write(e, E1000_REG_FCAH, 0); 367433d6423SLionel Sambuc e1000_reg_write(e, E1000_REG_FCT, 0); 368433d6423SLionel Sambuc e1000_reg_write(e, E1000_REG_FCTTV, 0); 369433d6423SLionel Sambuc e1000_reg_unset(e, E1000_REG_CTRL, E1000_REG_CTRL_VME); 370433d6423SLionel Sambuc 371433d6423SLionel Sambuc /* Clear Multicast Table Array (MTA). */ 372433d6423SLionel Sambuc for (i = 0; i < 128; i++) 373*107df7c8SDavid van Moolenbroek e1000_reg_write(e, E1000_REG_MTA + i, 0); 374*107df7c8SDavid van Moolenbroek 375433d6423SLionel Sambuc /* Initialize statistics registers. */ 376433d6423SLionel Sambuc for (i = 0; i < 64; i++) 377433d6423SLionel Sambuc e1000_reg_write(e, E1000_REG_CRCERRS + (i * 4), 0); 378*107df7c8SDavid van Moolenbroek 379*107df7c8SDavid van Moolenbroek /* Acquire MAC address and set up RX/TX buffers. */ 380433d6423SLionel Sambuc e1000_init_addr(e); 381433d6423SLionel Sambuc e1000_init_buf(e); 382433d6423SLionel Sambuc 383433d6423SLionel Sambuc /* Enable interrupts. */ 384*107df7c8SDavid van Moolenbroek e1000_reg_set(e, E1000_REG_IMS, E1000_REG_IMS_LSC | E1000_REG_IMS_RXO | 385*107df7c8SDavid van Moolenbroek E1000_REG_IMS_RXT | E1000_REG_IMS_TXQE | E1000_REG_IMS_TXDW); 386433d6423SLionel Sambuc return TRUE; 387433d6423SLionel Sambuc } 388433d6423SLionel Sambuc 389*107df7c8SDavid van Moolenbroek /* 390*107df7c8SDavid van Moolenbroek * Initialize the card's ethernet address. 391*107df7c8SDavid van Moolenbroek */ 392*107df7c8SDavid van Moolenbroek static void 393*107df7c8SDavid van Moolenbroek e1000_init_addr(e1000_t * e) 394433d6423SLionel Sambuc { 395433d6423SLionel Sambuc static char eakey[] = E1000_ENVVAR "#_EA"; 396433d6423SLionel Sambuc static char eafmt[] = "x:x:x:x:x:x"; 397433d6423SLionel Sambuc u16_t word; 398433d6423SLionel Sambuc int i; 399433d6423SLionel Sambuc long v; 400433d6423SLionel Sambuc 401*107df7c8SDavid van Moolenbroek /* Do we have a user defined ethernet address? */ 402433d6423SLionel Sambuc eakey[sizeof(E1000_ENVVAR)-1] = '0' + e1000_instance; 403433d6423SLionel Sambuc 404*107df7c8SDavid van Moolenbroek for (i = 0; i < 6; i++) { 405433d6423SLionel Sambuc if (env_parse(eakey, eafmt, i, &v, 0x00L, 0xFFL) != EP_SET) 406433d6423SLionel Sambuc break; 407433d6423SLionel Sambuc else 408433d6423SLionel Sambuc e->address.ea_addr[i] = v; 409433d6423SLionel Sambuc } 410*107df7c8SDavid van Moolenbroek 411*107df7c8SDavid van Moolenbroek /* If that fails, read Ethernet Address from EEPROM. */ 412*107df7c8SDavid van Moolenbroek if (i != 6) { 413*107df7c8SDavid van Moolenbroek for (i = 0; i < 3; i++) { 414433d6423SLionel Sambuc word = e->eeprom_read(e, i); 415*107df7c8SDavid van Moolenbroek e->address.ea_addr[(i * 2)] = (word & 0x00ff); 416433d6423SLionel Sambuc e->address.ea_addr[(i * 2) + 1] = (word & 0xff00) >> 8; 417433d6423SLionel Sambuc } 418433d6423SLionel Sambuc } 419*107df7c8SDavid van Moolenbroek 420*107df7c8SDavid van Moolenbroek /* Set Receive Address. */ 421433d6423SLionel Sambuc e1000_reg_write(e, E1000_REG_RAL, *(u32_t *)(&e->address.ea_addr[0])); 422433d6423SLionel Sambuc e1000_reg_write(e, E1000_REG_RAH, *(u16_t *)(&e->address.ea_addr[4])); 423433d6423SLionel Sambuc e1000_reg_set(e, E1000_REG_RAH, E1000_REG_RAH_AV); 424433d6423SLionel Sambuc e1000_reg_set(e, E1000_REG_RCTL, E1000_REG_RCTL_MPE); 425433d6423SLionel Sambuc 426433d6423SLionel Sambuc E1000_DEBUG(3, ("%s: Ethernet Address %x:%x:%x:%x:%x:%x\n", e->name, 427433d6423SLionel Sambuc e->address.ea_addr[0], e->address.ea_addr[1], 428433d6423SLionel Sambuc e->address.ea_addr[2], e->address.ea_addr[3], 429433d6423SLionel Sambuc e->address.ea_addr[4], e->address.ea_addr[5])); 430433d6423SLionel Sambuc } 431433d6423SLionel Sambuc 432*107df7c8SDavid van Moolenbroek /* 433*107df7c8SDavid van Moolenbroek * Initialize receive and transmit buffers. 434*107df7c8SDavid van Moolenbroek */ 435*107df7c8SDavid van Moolenbroek static void 436*107df7c8SDavid van Moolenbroek e1000_init_buf(e1000_t * e) 437433d6423SLionel Sambuc { 438433d6423SLionel Sambuc phys_bytes rx_buff_p; 439433d6423SLionel Sambuc phys_bytes tx_buff_p; 440433d6423SLionel Sambuc int i; 441433d6423SLionel Sambuc 442433d6423SLionel Sambuc /* Number of descriptors. */ 443433d6423SLionel Sambuc e->rx_desc_count = E1000_RXDESC_NR; 444433d6423SLionel Sambuc e->tx_desc_count = E1000_TXDESC_NR; 445433d6423SLionel Sambuc 446*107df7c8SDavid van Moolenbroek /* Allocate the receive descriptors. */ 447*107df7c8SDavid van Moolenbroek if (!e->rx_desc) { 448433d6423SLionel Sambuc if ((e->rx_desc = alloc_contig(sizeof(e1000_rx_desc_t) * 449*107df7c8SDavid van Moolenbroek e->rx_desc_count, AC_ALIGN4K, &e->rx_desc_p)) == NULL) 450433d6423SLionel Sambuc panic("failed to allocate RX descriptors"); 451433d6423SLionel Sambuc 452*107df7c8SDavid van Moolenbroek memset(e->rx_desc, 0, 453*107df7c8SDavid van Moolenbroek sizeof(e1000_rx_desc_t) * e->rx_desc_count); 454*107df7c8SDavid van Moolenbroek 455433d6423SLionel Sambuc e->rx_buffer_size = E1000_RXDESC_NR * E1000_IOBUF_SIZE; 456433d6423SLionel Sambuc 457*107df7c8SDavid van Moolenbroek /* Allocate receive buffers. */ 458*107df7c8SDavid van Moolenbroek if ((e->rx_buffer = alloc_contig(e->rx_buffer_size, AC_ALIGN4K, 459*107df7c8SDavid van Moolenbroek &rx_buff_p)) == NULL) 460433d6423SLionel Sambuc panic("failed to allocate RX buffers"); 461*107df7c8SDavid van Moolenbroek 462433d6423SLionel Sambuc /* Set up receive descriptors. */ 463433d6423SLionel Sambuc for (i = 0; i < E1000_RXDESC_NR; i++) 464*107df7c8SDavid van Moolenbroek e->rx_desc[i].buffer = rx_buff_p + 465*107df7c8SDavid van Moolenbroek (i * E1000_IOBUF_SIZE); 466433d6423SLionel Sambuc } 467433d6423SLionel Sambuc 468*107df7c8SDavid van Moolenbroek /* Allocate transmit descriptors. */ 469*107df7c8SDavid van Moolenbroek if (!e->tx_desc) { 470*107df7c8SDavid van Moolenbroek if ((e->tx_desc = alloc_contig(sizeof(e1000_tx_desc_t) * 471*107df7c8SDavid van Moolenbroek e->tx_desc_count, AC_ALIGN4K, &e->tx_desc_p)) == NULL) 472*107df7c8SDavid van Moolenbroek panic("failed to allocate TX descriptors"); 473*107df7c8SDavid van Moolenbroek 474*107df7c8SDavid van Moolenbroek memset(e->tx_desc, 0, 475*107df7c8SDavid van Moolenbroek sizeof(e1000_tx_desc_t) * e->tx_desc_count); 476*107df7c8SDavid van Moolenbroek 477*107df7c8SDavid van Moolenbroek /* Allocate transmit buffers. */ 478433d6423SLionel Sambuc e->tx_buffer_size = E1000_TXDESC_NR * E1000_IOBUF_SIZE; 479433d6423SLionel Sambuc 480433d6423SLionel Sambuc /* Attempt to allocate. */ 481*107df7c8SDavid van Moolenbroek if ((e->tx_buffer = alloc_contig(e->tx_buffer_size, AC_ALIGN4K, 482*107df7c8SDavid van Moolenbroek &tx_buff_p)) == NULL) 483433d6423SLionel Sambuc panic("failed to allocate TX buffers"); 484*107df7c8SDavid van Moolenbroek 485433d6423SLionel Sambuc /* Set up transmit descriptors. */ 486433d6423SLionel Sambuc for (i = 0; i < E1000_TXDESC_NR; i++) 487*107df7c8SDavid van Moolenbroek e->tx_desc[i].buffer = tx_buff_p + 488*107df7c8SDavid van Moolenbroek (i * E1000_IOBUF_SIZE); 489433d6423SLionel Sambuc } 490*107df7c8SDavid van Moolenbroek 491*107df7c8SDavid van Moolenbroek /* Set up the receive ring registers. */ 492433d6423SLionel Sambuc e1000_reg_write(e, E1000_REG_RDBAL, e->rx_desc_p); 493433d6423SLionel Sambuc e1000_reg_write(e, E1000_REG_RDBAH, 0); 494*107df7c8SDavid van Moolenbroek e1000_reg_write(e, E1000_REG_RDLEN, 495*107df7c8SDavid van Moolenbroek e->rx_desc_count * sizeof(e1000_rx_desc_t)); 496433d6423SLionel Sambuc e1000_reg_write(e, E1000_REG_RDH, 0); 497433d6423SLionel Sambuc e1000_reg_write(e, E1000_REG_RDT, e->rx_desc_count - 1); 498433d6423SLionel Sambuc e1000_reg_unset(e, E1000_REG_RCTL, E1000_REG_RCTL_BSIZE); 499433d6423SLionel Sambuc e1000_reg_set(e, E1000_REG_RCTL, E1000_REG_RCTL_EN); 500433d6423SLionel Sambuc 501*107df7c8SDavid van Moolenbroek /* Set up the transmit ring registers. */ 502433d6423SLionel Sambuc e1000_reg_write(e, E1000_REG_TDBAL, e->tx_desc_p); 503433d6423SLionel Sambuc e1000_reg_write(e, E1000_REG_TDBAH, 0); 504*107df7c8SDavid van Moolenbroek e1000_reg_write(e, E1000_REG_TDLEN, 505*107df7c8SDavid van Moolenbroek e->tx_desc_count * sizeof(e1000_tx_desc_t)); 506433d6423SLionel Sambuc e1000_reg_write(e, E1000_REG_TDH, 0); 507433d6423SLionel Sambuc e1000_reg_write(e, E1000_REG_TDT, 0); 508*107df7c8SDavid van Moolenbroek e1000_reg_set(e, E1000_REG_TCTL, 509*107df7c8SDavid van Moolenbroek E1000_REG_TCTL_EN | E1000_REG_TCTL_PSP); 510433d6423SLionel Sambuc } 511433d6423SLionel Sambuc 512*107df7c8SDavid van Moolenbroek /* 513*107df7c8SDavid van Moolenbroek * Reset the card. 514*107df7c8SDavid van Moolenbroek */ 515*107df7c8SDavid van Moolenbroek static void 516*107df7c8SDavid van Moolenbroek e1000_reset_hw(e1000_t * e) 517433d6423SLionel Sambuc { 518*107df7c8SDavid van Moolenbroek 519433d6423SLionel Sambuc /* Assert a Device Reset signal. */ 520433d6423SLionel Sambuc e1000_reg_set(e, E1000_REG_CTRL, E1000_REG_CTRL_RST); 521433d6423SLionel Sambuc 522433d6423SLionel Sambuc /* Wait one microsecond. */ 523433d6423SLionel Sambuc tickdelay(1); 524433d6423SLionel Sambuc } 525433d6423SLionel Sambuc 526*107df7c8SDavid van Moolenbroek /* 527*107df7c8SDavid van Moolenbroek * Try to send a packet. 528*107df7c8SDavid van Moolenbroek */ 529*107df7c8SDavid van Moolenbroek static void 530*107df7c8SDavid van Moolenbroek e1000_writev_s(message * mp, int from_int) 531433d6423SLionel Sambuc { 532433d6423SLionel Sambuc e1000_t *e = &e1000_state; 533433d6423SLionel Sambuc e1000_tx_desc_t *desc; 534433d6423SLionel Sambuc iovec_s_t iovec[E1000_IOVEC_NR]; 535433d6423SLionel Sambuc int r, head, tail, i, bytes = 0, size; 536433d6423SLionel Sambuc 537433d6423SLionel Sambuc E1000_DEBUG(3, ("e1000: writev_s(%p,%d)\n", mp, from_int)); 538433d6423SLionel Sambuc 539433d6423SLionel Sambuc /* Are we called from the interrupt handler? */ 540*107df7c8SDavid van Moolenbroek if (!from_int) { 541433d6423SLionel Sambuc /* We cannot write twice simultaneously. 542433d6423SLionel Sambuc assert(!(e->status & E1000_WRITING)); */ 543433d6423SLionel Sambuc 544433d6423SLionel Sambuc /* Copy write message. */ 545433d6423SLionel Sambuc e->tx_message = *mp; 546433d6423SLionel Sambuc e->client = mp->m_source; 547433d6423SLionel Sambuc e->status |= E1000_WRITING; 548433d6423SLionel Sambuc 549433d6423SLionel Sambuc /* Must be a sane vector count. */ 550433d6423SLionel Sambuc assert(e->tx_message.m_net_netdrv_dl_writev_s.count > 0); 551*107df7c8SDavid van Moolenbroek assert(e->tx_message.m_net_netdrv_dl_writev_s.count < 552*107df7c8SDavid van Moolenbroek E1000_IOVEC_NR); 553433d6423SLionel Sambuc 554433d6423SLionel Sambuc /* 555433d6423SLionel Sambuc * Copy the I/O vector table. 556433d6423SLionel Sambuc */ 557433d6423SLionel Sambuc if ((r = sys_safecopyfrom(e->tx_message.m_source, 558433d6423SLionel Sambuc e->tx_message.m_net_netdrv_dl_writev_s.grant, 0, 559433d6423SLionel Sambuc (vir_bytes)iovec, 560433d6423SLionel Sambuc e->tx_message.m_net_netdrv_dl_writev_s.count * 561433d6423SLionel Sambuc sizeof(iovec_s_t))) != OK) 562433d6423SLionel Sambuc panic("sys_safecopyfrom() failed: %d", r); 563*107df7c8SDavid van Moolenbroek 564433d6423SLionel Sambuc /* Find the head, tail and current descriptors. */ 565433d6423SLionel Sambuc head = e1000_reg_read(e, E1000_REG_TDH); 566433d6423SLionel Sambuc tail = e1000_reg_read(e, E1000_REG_TDT); 567433d6423SLionel Sambuc desc = &e->tx_desc[tail]; 568433d6423SLionel Sambuc 569433d6423SLionel Sambuc E1000_DEBUG(4, ("%s: head=%d, tail=%d\n", 570433d6423SLionel Sambuc e->name, head, tail)); 571433d6423SLionel Sambuc 572433d6423SLionel Sambuc /* Loop vector elements. */ 573*107df7c8SDavid van Moolenbroek for (i = 0; i < e->tx_message.m_net_netdrv_dl_writev_s.count; 574*107df7c8SDavid van Moolenbroek i++) 575433d6423SLionel Sambuc { 576433d6423SLionel Sambuc size = iovec[i].iov_size < (E1000_IOBUF_SIZE - bytes) ? 577433d6423SLionel Sambuc iovec[i].iov_size : (E1000_IOBUF_SIZE - bytes); 578433d6423SLionel Sambuc 579433d6423SLionel Sambuc E1000_DEBUG(4, ("iovec[%d] = %d\n", i, size)); 580433d6423SLionel Sambuc 581433d6423SLionel Sambuc /* Copy bytes to TX queue buffers. */ 582433d6423SLionel Sambuc if ((r = sys_safecopyfrom(e->tx_message.m_source, 583*107df7c8SDavid van Moolenbroek iovec[i].iov_grant, 0, (vir_bytes) e->tx_buffer + 584*107df7c8SDavid van Moolenbroek (tail * E1000_IOBUF_SIZE), size)) != OK) 585433d6423SLionel Sambuc panic("sys_safecopyfrom() failed: %d", r); 586*107df7c8SDavid van Moolenbroek 587433d6423SLionel Sambuc /* Mark this descriptor ready. */ 588433d6423SLionel Sambuc desc->status = 0; 589433d6423SLionel Sambuc desc->command = 0; 590433d6423SLionel Sambuc desc->length = size; 591433d6423SLionel Sambuc 592433d6423SLionel Sambuc /* Marks End-of-Packet. */ 593*107df7c8SDavid van Moolenbroek if (i == 594*107df7c8SDavid van Moolenbroek e->tx_message.m_net_netdrv_dl_writev_s.count - 1) { 595433d6423SLionel Sambuc desc->command = E1000_TX_CMD_EOP | 596*107df7c8SDavid van Moolenbroek E1000_TX_CMD_FCS | E1000_TX_CMD_RS; 597433d6423SLionel Sambuc } 598433d6423SLionel Sambuc /* Move to next descriptor. */ 599433d6423SLionel Sambuc tail = (tail + 1) % e->tx_desc_count; 600433d6423SLionel Sambuc bytes += size; 601433d6423SLionel Sambuc desc = &e->tx_desc[tail]; 602433d6423SLionel Sambuc } 603*107df7c8SDavid van Moolenbroek 604433d6423SLionel Sambuc /* Increment tail. Start transmission. */ 605433d6423SLionel Sambuc e1000_reg_write(e, E1000_REG_TDT, tail); 606433d6423SLionel Sambuc 607433d6423SLionel Sambuc E1000_DEBUG(2, ("e1000: wrote %d byte packet\n", bytes)); 608*107df7c8SDavid van Moolenbroek } else 609433d6423SLionel Sambuc e->status |= E1000_TRANSMIT; 610433d6423SLionel Sambuc reply(e); 611433d6423SLionel Sambuc } 612433d6423SLionel Sambuc 613*107df7c8SDavid van Moolenbroek /* 614*107df7c8SDavid van Moolenbroek * Try to receive a packet. 615*107df7c8SDavid van Moolenbroek */ 616*107df7c8SDavid van Moolenbroek static void 617*107df7c8SDavid van Moolenbroek e1000_readv_s(message * mp, int from_int) 618433d6423SLionel Sambuc { 619433d6423SLionel Sambuc e1000_t *e = &e1000_state; 620433d6423SLionel Sambuc e1000_rx_desc_t *desc; 621433d6423SLionel Sambuc iovec_s_t iovec[E1000_IOVEC_NR]; 622433d6423SLionel Sambuc int i, r, head, tail, cur, bytes = 0, size; 623433d6423SLionel Sambuc 624433d6423SLionel Sambuc E1000_DEBUG(3, ("e1000: readv_s(%p,%d)\n", mp, from_int)); 625433d6423SLionel Sambuc 626433d6423SLionel Sambuc /* Are we called from the interrupt handler? */ 627*107df7c8SDavid van Moolenbroek if (!from_int) { 628433d6423SLionel Sambuc e->rx_message = *mp; 629433d6423SLionel Sambuc e->client = mp->m_source; 630433d6423SLionel Sambuc e->status |= E1000_READING; 631433d6423SLionel Sambuc e->rx_size = 0; 632433d6423SLionel Sambuc 633433d6423SLionel Sambuc assert(e->rx_message.m_net_netdrv_dl_readv_s.count > 0); 634*107df7c8SDavid van Moolenbroek assert(e->rx_message.m_net_netdrv_dl_readv_s.count < 635*107df7c8SDavid van Moolenbroek E1000_IOVEC_NR); 636433d6423SLionel Sambuc } 637*107df7c8SDavid van Moolenbroek 638*107df7c8SDavid van Moolenbroek if (e->status & E1000_READING) { 639433d6423SLionel Sambuc /* 640433d6423SLionel Sambuc * Copy the I/O vector table first. 641433d6423SLionel Sambuc */ 642433d6423SLionel Sambuc if ((r = sys_safecopyfrom(e->rx_message.m_source, 643433d6423SLionel Sambuc e->rx_message.m_net_netdrv_dl_readv_s.grant, 0, 644433d6423SLionel Sambuc (vir_bytes)iovec, 645433d6423SLionel Sambuc e->rx_message.m_net_netdrv_dl_readv_s.count * 646433d6423SLionel Sambuc sizeof(iovec_s_t))) != OK) 647433d6423SLionel Sambuc panic("sys_safecopyfrom() failed: %d", r); 648*107df7c8SDavid van Moolenbroek 649433d6423SLionel Sambuc /* Find the head, tail and current descriptors. */ 650433d6423SLionel Sambuc head = e1000_reg_read(e, E1000_REG_RDH); 651433d6423SLionel Sambuc tail = e1000_reg_read(e, E1000_REG_RDT); 652433d6423SLionel Sambuc cur = (tail + 1) % e->rx_desc_count; 653433d6423SLionel Sambuc desc = &e->rx_desc[cur]; 654433d6423SLionel Sambuc 655433d6423SLionel Sambuc /* 656433d6423SLionel Sambuc * Only handle one packet at a time. 657433d6423SLionel Sambuc */ 658*107df7c8SDavid van Moolenbroek if (!(desc->status & E1000_RX_STATUS_EOP)) { 659433d6423SLionel Sambuc reply(e); 660433d6423SLionel Sambuc return; 661433d6423SLionel Sambuc } 662433d6423SLionel Sambuc E1000_DEBUG(4, ("%s: head=%x, tail=%d\n", 663433d6423SLionel Sambuc e->name, head, tail)); 664433d6423SLionel Sambuc 665433d6423SLionel Sambuc /* 666433d6423SLionel Sambuc * Copy to vector elements. 667433d6423SLionel Sambuc */ 668433d6423SLionel Sambuc for (i = 0; i < e->rx_message.m_net_netdrv_dl_readv_s.count && 669*107df7c8SDavid van Moolenbroek bytes < desc->length; i++) { 670433d6423SLionel Sambuc size = iovec[i].iov_size < (desc->length - bytes) ? 671433d6423SLionel Sambuc iovec[i].iov_size : (desc->length - bytes); 672433d6423SLionel Sambuc 673433d6423SLionel Sambuc E1000_DEBUG(4, ("iovec[%d] = %lu[%d]\n", 674433d6423SLionel Sambuc i, iovec[i].iov_size, size)); 675433d6423SLionel Sambuc 676*107df7c8SDavid van Moolenbroek if ((r = sys_safecopyto(e->rx_message.m_source, 677*107df7c8SDavid van Moolenbroek iovec[i].iov_grant, 0, (vir_bytes)e->rx_buffer + 678*107df7c8SDavid van Moolenbroek bytes + (cur * E1000_IOBUF_SIZE), size)) != OK) 679433d6423SLionel Sambuc panic("sys_safecopyto() failed: %d", r); 680433d6423SLionel Sambuc bytes += size; 681433d6423SLionel Sambuc } 682433d6423SLionel Sambuc desc->status = 0; 683433d6423SLionel Sambuc 684433d6423SLionel Sambuc /* 685433d6423SLionel Sambuc * Update state. 686433d6423SLionel Sambuc */ 687433d6423SLionel Sambuc e->rx_size = bytes; 688433d6423SLionel Sambuc e->status |= E1000_RECEIVED; 689433d6423SLionel Sambuc E1000_DEBUG(2, ("e1000: got %d byte packet\n", e->rx_size)); 690433d6423SLionel Sambuc 691433d6423SLionel Sambuc /* Increment tail. */ 692*107df7c8SDavid van Moolenbroek e1000_reg_write(e, E1000_REG_RDT, 693*107df7c8SDavid van Moolenbroek (tail + 1) % e->rx_desc_count); 694433d6423SLionel Sambuc } 695433d6423SLionel Sambuc reply(e); 696433d6423SLionel Sambuc } 697433d6423SLionel Sambuc 698*107df7c8SDavid van Moolenbroek /* 699*107df7c8SDavid van Moolenbroek * Return statistics. 700*107df7c8SDavid van Moolenbroek */ 701*107df7c8SDavid van Moolenbroek static void 702*107df7c8SDavid van Moolenbroek e1000_getstat_s(message * mp) 703433d6423SLionel Sambuc { 704433d6423SLionel Sambuc int r; 705433d6423SLionel Sambuc eth_stat_t stats; 706433d6423SLionel Sambuc e1000_t *e = &e1000_state; 707433d6423SLionel Sambuc 708433d6423SLionel Sambuc E1000_DEBUG(3, ("e1000: getstat_s()\n")); 709433d6423SLionel Sambuc 710433d6423SLionel Sambuc stats.ets_recvErr = e1000_reg_read(e, E1000_REG_RXERRC); 711433d6423SLionel Sambuc stats.ets_sendErr = 0; 712433d6423SLionel Sambuc stats.ets_OVW = 0; 713433d6423SLionel Sambuc stats.ets_CRCerr = e1000_reg_read(e, E1000_REG_CRCERRS); 714433d6423SLionel Sambuc stats.ets_frameAll = 0; 715433d6423SLionel Sambuc stats.ets_missedP = e1000_reg_read(e, E1000_REG_MPC); 716433d6423SLionel Sambuc stats.ets_packetR = e1000_reg_read(e, E1000_REG_TPR); 717433d6423SLionel Sambuc stats.ets_packetT = e1000_reg_read(e, E1000_REG_TPT); 718433d6423SLionel Sambuc stats.ets_collision = e1000_reg_read(e, E1000_REG_COLC); 719433d6423SLionel Sambuc stats.ets_transAb = 0; 720433d6423SLionel Sambuc stats.ets_carrSense = 0; 721433d6423SLionel Sambuc stats.ets_fifoUnder = 0; 722433d6423SLionel Sambuc stats.ets_fifoOver = 0; 723433d6423SLionel Sambuc stats.ets_CDheartbeat = 0; 724433d6423SLionel Sambuc stats.ets_OWC = 0; 725433d6423SLionel Sambuc 726433d6423SLionel Sambuc sys_safecopyto(mp->m_source, mp->m_net_netdrv_dl_getstat_s.grant, 0, 727433d6423SLionel Sambuc (vir_bytes)&stats, sizeof(stats)); 728433d6423SLionel Sambuc mp->m_type = DL_STAT_REPLY; 729433d6423SLionel Sambuc if ((r = ipc_send(mp->m_source, mp)) != OK) 730433d6423SLionel Sambuc panic("e1000_getstat: ipc_send() failed: %d", r); 731433d6423SLionel Sambuc } 732433d6423SLionel Sambuc 733*107df7c8SDavid van Moolenbroek /* 734*107df7c8SDavid van Moolenbroek * Handle an interrupt. 735*107df7c8SDavid van Moolenbroek */ 736*107df7c8SDavid van Moolenbroek static void 737*107df7c8SDavid van Moolenbroek e1000_interrupt(message * mp) 738433d6423SLionel Sambuc { 739433d6423SLionel Sambuc e1000_t *e; 740433d6423SLionel Sambuc u32_t cause; 741433d6423SLionel Sambuc 742433d6423SLionel Sambuc E1000_DEBUG(3, ("e1000: interrupt\n")); 743433d6423SLionel Sambuc 744433d6423SLionel Sambuc e = &e1000_state; 745433d6423SLionel Sambuc 746*107df7c8SDavid van Moolenbroek /* Reenable interrupts. */ 747433d6423SLionel Sambuc if (sys_irqenable(&e->irq_hook) != OK) 748433d6423SLionel Sambuc panic("failed to re-enable IRQ"); 749433d6423SLionel Sambuc 750433d6423SLionel Sambuc /* Read the Interrupt Cause Read register. */ 751*107df7c8SDavid van Moolenbroek if ((cause = e1000_reg_read(e, E1000_REG_ICR)) != 0) { 752433d6423SLionel Sambuc if (cause & E1000_REG_ICR_LSC) 753433d6423SLionel Sambuc e1000_link_changed(e); 754433d6423SLionel Sambuc 755433d6423SLionel Sambuc if (cause & (E1000_REG_ICR_RXO | E1000_REG_ICR_RXT)) 756433d6423SLionel Sambuc e1000_readv_s(&e->rx_message, TRUE); 757433d6423SLionel Sambuc 758*107df7c8SDavid van Moolenbroek if (cause & (E1000_REG_ICR_TXQE | E1000_REG_ICR_TXDW)) 759433d6423SLionel Sambuc e1000_writev_s(&e->tx_message, TRUE); 760433d6423SLionel Sambuc } 761433d6423SLionel Sambuc } 762433d6423SLionel Sambuc 763*107df7c8SDavid van Moolenbroek /* 764*107df7c8SDavid van Moolenbroek * Link status has changed. Nothing to do for now. 765*107df7c8SDavid van Moolenbroek */ 766*107df7c8SDavid van Moolenbroek static int 767*107df7c8SDavid van Moolenbroek e1000_link_changed(e1000_t * e) 768433d6423SLionel Sambuc { 769*107df7c8SDavid van Moolenbroek 770433d6423SLionel Sambuc E1000_DEBUG(4, ("%s: link_changed()\n", e->name)); 771433d6423SLionel Sambuc return FALSE; 772433d6423SLionel Sambuc } 773433d6423SLionel Sambuc 774*107df7c8SDavid van Moolenbroek /* 775*107df7c8SDavid van Moolenbroek * Stop the card. 776*107df7c8SDavid van Moolenbroek */ 777*107df7c8SDavid van Moolenbroek static void 778*107df7c8SDavid van Moolenbroek e1000_stop(e1000_t *e) 779433d6423SLionel Sambuc { 780*107df7c8SDavid van Moolenbroek 781433d6423SLionel Sambuc E1000_DEBUG(3, ("%s: stop()\n", e->name)); 782433d6423SLionel Sambuc 783433d6423SLionel Sambuc e1000_reset_hw(e); 784433d6423SLionel Sambuc 785433d6423SLionel Sambuc exit(EXIT_SUCCESS); 786433d6423SLionel Sambuc } 787433d6423SLionel Sambuc 788*107df7c8SDavid van Moolenbroek /* 789*107df7c8SDavid van Moolenbroek * Read from a register. 790*107df7c8SDavid van Moolenbroek */ 791*107df7c8SDavid van Moolenbroek static uint32_t 792*107df7c8SDavid van Moolenbroek e1000_reg_read(e1000_t * e, uint32_t reg) 793433d6423SLionel Sambuc { 794433d6423SLionel Sambuc uint32_t value; 795433d6423SLionel Sambuc 796433d6423SLionel Sambuc /* Assume a sane register. */ 797433d6423SLionel Sambuc assert(reg < 0x1ffff); 798433d6423SLionel Sambuc 799433d6423SLionel Sambuc /* Read from memory mapped register. */ 800*107df7c8SDavid van Moolenbroek value = *(volatile uint32_t *)(e->regs + reg); 801433d6423SLionel Sambuc 802433d6423SLionel Sambuc /* Return the result. */ 803433d6423SLionel Sambuc return value; 804433d6423SLionel Sambuc } 805433d6423SLionel Sambuc 806*107df7c8SDavid van Moolenbroek /* 807*107df7c8SDavid van Moolenbroek * Write to a register. 808*107df7c8SDavid van Moolenbroek */ 809*107df7c8SDavid van Moolenbroek static void 810*107df7c8SDavid van Moolenbroek e1000_reg_write(e1000_t * e, uint32_t reg, uint32_t value) 811433d6423SLionel Sambuc { 812*107df7c8SDavid van Moolenbroek 813433d6423SLionel Sambuc /* Assume a sane register. */ 814433d6423SLionel Sambuc assert(reg < 0x1ffff); 815433d6423SLionel Sambuc 816433d6423SLionel Sambuc /* Write to memory mapped register. */ 817433d6423SLionel Sambuc *(volatile u32_t *)(e->regs + reg) = value; 818433d6423SLionel Sambuc } 819433d6423SLionel Sambuc 820*107df7c8SDavid van Moolenbroek /* 821*107df7c8SDavid van Moolenbroek * Set bits in a register. 822*107df7c8SDavid van Moolenbroek */ 823*107df7c8SDavid van Moolenbroek static void 824*107df7c8SDavid van Moolenbroek e1000_reg_set(e1000_t * e, uint32_t reg, uint32_t value) 825433d6423SLionel Sambuc { 826433d6423SLionel Sambuc uint32_t data; 827433d6423SLionel Sambuc 828433d6423SLionel Sambuc /* First read the current value. */ 829433d6423SLionel Sambuc data = e1000_reg_read(e, reg); 830433d6423SLionel Sambuc 831*107df7c8SDavid van Moolenbroek /* Set bits, and write back. */ 832433d6423SLionel Sambuc e1000_reg_write(e, reg, data | value); 833433d6423SLionel Sambuc } 834433d6423SLionel Sambuc 835*107df7c8SDavid van Moolenbroek /* 836*107df7c8SDavid van Moolenbroek * Clear bits in a register. 837*107df7c8SDavid van Moolenbroek */ 838*107df7c8SDavid van Moolenbroek static void 839*107df7c8SDavid van Moolenbroek e1000_reg_unset(e1000_t * e, uint32_t reg, uint32_t value) 840433d6423SLionel Sambuc { 841433d6423SLionel Sambuc uint32_t data; 842433d6423SLionel Sambuc 843433d6423SLionel Sambuc /* First read the current value. */ 844433d6423SLionel Sambuc data = e1000_reg_read(e, reg); 845433d6423SLionel Sambuc 846*107df7c8SDavid van Moolenbroek /* Unset bits, and write back. */ 847433d6423SLionel Sambuc e1000_reg_write(e, reg, data & ~value); 848433d6423SLionel Sambuc } 849433d6423SLionel Sambuc 850*107df7c8SDavid van Moolenbroek /* 851*107df7c8SDavid van Moolenbroek * Read from EEPROM. 852*107df7c8SDavid van Moolenbroek */ 853*107df7c8SDavid van Moolenbroek static u16_t 854*107df7c8SDavid van Moolenbroek eeprom_eerd(void * v, int reg) 855433d6423SLionel Sambuc { 856433d6423SLionel Sambuc e1000_t *e = (e1000_t *)v; 857433d6423SLionel Sambuc u32_t data; 858433d6423SLionel Sambuc 859433d6423SLionel Sambuc /* Request EEPROM read. */ 860433d6423SLionel Sambuc e1000_reg_write(e, E1000_REG_EERD, 861433d6423SLionel Sambuc (reg << e->eeprom_addr_off) | (E1000_REG_EERD_START)); 862433d6423SLionel Sambuc 863433d6423SLionel Sambuc /* Wait until ready. */ 864*107df7c8SDavid van Moolenbroek while (!((data = (e1000_reg_read(e, E1000_REG_EERD))) & 865*107df7c8SDavid van Moolenbroek e->eeprom_done_bit)); 866433d6423SLionel Sambuc 867433d6423SLionel Sambuc return data >> 16; 868433d6423SLionel Sambuc } 869433d6423SLionel Sambuc 870*107df7c8SDavid van Moolenbroek /* 871*107df7c8SDavid van Moolenbroek * Initialize ICH8 flash. 872*107df7c8SDavid van Moolenbroek */ 873*107df7c8SDavid van Moolenbroek static int 874*107df7c8SDavid van Moolenbroek eeprom_ich_init(e1000_t * e) 875433d6423SLionel Sambuc { 876433d6423SLionel Sambuc union ich8_hws_flash_status hsfsts; 877433d6423SLionel Sambuc int ret_val = -1; 878433d6423SLionel Sambuc int i = 0; 879433d6423SLionel Sambuc 880433d6423SLionel Sambuc hsfsts.regval = E1000_READ_FLASH_REG16(e, ICH_FLASH_HSFSTS); 881433d6423SLionel Sambuc 882433d6423SLionel Sambuc /* Check if the flash descriptor is valid */ 883*107df7c8SDavid van Moolenbroek if (hsfsts.hsf_status.fldesvalid == 0) { 884433d6423SLionel Sambuc E1000_DEBUG(3, ("Flash descriptor invalid. " 885433d6423SLionel Sambuc "SW Sequencing must be used.")); 886433d6423SLionel Sambuc goto out; 887433d6423SLionel Sambuc } 888*107df7c8SDavid van Moolenbroek 889433d6423SLionel Sambuc /* Clear FCERR and DAEL in hw status by writing 1 */ 890433d6423SLionel Sambuc hsfsts.hsf_status.flcerr = 1; 891433d6423SLionel Sambuc hsfsts.hsf_status.dael = 1; 892433d6423SLionel Sambuc 893433d6423SLionel Sambuc E1000_WRITE_FLASH_REG16(e, ICH_FLASH_HSFSTS, hsfsts.regval); 894433d6423SLionel Sambuc 895433d6423SLionel Sambuc /* 896*107df7c8SDavid van Moolenbroek * Either we should have a hardware SPI cycle in progress bit to check 897*107df7c8SDavid van Moolenbroek * against, in order to start a new cycle or FDONE bit should be 898*107df7c8SDavid van Moolenbroek * changed in the hardware so that it is 1 after hardware reset, which 899*107df7c8SDavid van Moolenbroek * can then be used as an indication whether a cycle is in progress or 900*107df7c8SDavid van Moolenbroek * has been completed. 901433d6423SLionel Sambuc */ 902*107df7c8SDavid van Moolenbroek if (hsfsts.hsf_status.flcinprog == 0) { 903433d6423SLionel Sambuc /* 904*107df7c8SDavid van Moolenbroek * There is no cycle running at present, so we can start a 905*107df7c8SDavid van Moolenbroek * cycle. Begin by setting Flash Cycle Done. 906433d6423SLionel Sambuc */ 907433d6423SLionel Sambuc hsfsts.hsf_status.flcdone = 1; 908433d6423SLionel Sambuc E1000_WRITE_FLASH_REG16(e, ICH_FLASH_HSFSTS, hsfsts.regval); 909433d6423SLionel Sambuc ret_val = 0; 910*107df7c8SDavid van Moolenbroek } else { 911433d6423SLionel Sambuc /* 912*107df7c8SDavid van Moolenbroek * Otherwise poll for sometime so the current cycle has a 913*107df7c8SDavid van Moolenbroek * chance to end before giving up. 914433d6423SLionel Sambuc */ 915*107df7c8SDavid van Moolenbroek for (i = 0; i < ICH_FLASH_READ_COMMAND_TIMEOUT; i++) { 916*107df7c8SDavid van Moolenbroek hsfsts.regval = E1000_READ_FLASH_REG16(e, 917*107df7c8SDavid van Moolenbroek ICH_FLASH_HSFSTS); 918433d6423SLionel Sambuc 919*107df7c8SDavid van Moolenbroek if (hsfsts.hsf_status.flcinprog == 0) { 920433d6423SLionel Sambuc ret_val = 0; 921433d6423SLionel Sambuc break; 922433d6423SLionel Sambuc } 923433d6423SLionel Sambuc tickdelay(1); 924433d6423SLionel Sambuc } 925*107df7c8SDavid van Moolenbroek if (ret_val == 0) { 926433d6423SLionel Sambuc /* 927433d6423SLionel Sambuc * Successful in waiting for previous cycle to timeout, 928433d6423SLionel Sambuc * now set the Flash Cycle Done. 929433d6423SLionel Sambuc */ 930433d6423SLionel Sambuc hsfsts.hsf_status.flcdone = 1; 931433d6423SLionel Sambuc E1000_WRITE_FLASH_REG16(e, ICH_FLASH_HSFSTS, 932433d6423SLionel Sambuc hsfsts.regval); 933*107df7c8SDavid van Moolenbroek } else { 934*107df7c8SDavid van Moolenbroek E1000_DEBUG(3, 935*107df7c8SDavid van Moolenbroek ("Flash controller busy, cannot get access")); 936433d6423SLionel Sambuc } 937433d6423SLionel Sambuc } 938433d6423SLionel Sambuc out: 939433d6423SLionel Sambuc return ret_val; 940433d6423SLionel Sambuc } 941433d6423SLionel Sambuc 942*107df7c8SDavid van Moolenbroek /* 943*107df7c8SDavid van Moolenbroek * Start ICH8 flash cycle. 944*107df7c8SDavid van Moolenbroek */ 945*107df7c8SDavid van Moolenbroek static int 946*107df7c8SDavid van Moolenbroek eeprom_ich_cycle(e1000_t * e, u32_t timeout) 947433d6423SLionel Sambuc { 948433d6423SLionel Sambuc union ich8_hws_flash_ctrl hsflctl; 949433d6423SLionel Sambuc union ich8_hws_flash_status hsfsts; 950433d6423SLionel Sambuc int ret_val = -1; 951433d6423SLionel Sambuc u32_t i = 0; 952433d6423SLionel Sambuc 953433d6423SLionel Sambuc E1000_DEBUG(3, ("e1000_flash_cycle_ich8lan")); 954433d6423SLionel Sambuc 955433d6423SLionel Sambuc /* Start a cycle by writing 1 in Flash Cycle Go in Hw Flash Control */ 956433d6423SLionel Sambuc hsflctl.regval = E1000_READ_FLASH_REG16(e, ICH_FLASH_HSFCTL); 957433d6423SLionel Sambuc hsflctl.hsf_ctrl.flcgo = 1; 958433d6423SLionel Sambuc E1000_WRITE_FLASH_REG16(e, ICH_FLASH_HSFCTL, hsflctl.regval); 959433d6423SLionel Sambuc 960*107df7c8SDavid van Moolenbroek /* Wait till the FDONE bit is set to 1 */ 961*107df7c8SDavid van Moolenbroek do { 962433d6423SLionel Sambuc hsfsts.regval = E1000_READ_FLASH_REG16(e, ICH_FLASH_HSFSTS); 963433d6423SLionel Sambuc if (hsfsts.hsf_status.flcdone == 1) 964433d6423SLionel Sambuc break; 965433d6423SLionel Sambuc tickdelay(1); 966*107df7c8SDavid van Moolenbroek } while (i++ < timeout); 967433d6423SLionel Sambuc 968433d6423SLionel Sambuc if (hsfsts.hsf_status.flcdone == 1 && hsfsts.hsf_status.flcerr == 0) 969433d6423SLionel Sambuc ret_val = 0; 970433d6423SLionel Sambuc 971433d6423SLionel Sambuc return ret_val; 972433d6423SLionel Sambuc } 973433d6423SLionel Sambuc 974*107df7c8SDavid van Moolenbroek /* 975*107df7c8SDavid van Moolenbroek * Read from ICH8 flash. 976*107df7c8SDavid van Moolenbroek */ 977*107df7c8SDavid van Moolenbroek static u16_t 978*107df7c8SDavid van Moolenbroek eeprom_ich(void * v, int reg) 979433d6423SLionel Sambuc { 980433d6423SLionel Sambuc union ich8_hws_flash_status hsfsts; 981433d6423SLionel Sambuc union ich8_hws_flash_ctrl hsflctl; 982433d6423SLionel Sambuc u32_t flash_linear_addr; 983433d6423SLionel Sambuc u32_t flash_data = 0; 984433d6423SLionel Sambuc int ret_val = -1; 985433d6423SLionel Sambuc u8_t count = 0; 986433d6423SLionel Sambuc e1000_t *e = (e1000_t *)v; 987433d6423SLionel Sambuc u16_t data = 0; 988433d6423SLionel Sambuc 989433d6423SLionel Sambuc E1000_DEBUG(3, ("e1000_read_flash_data_ich8lan")); 990433d6423SLionel Sambuc 991433d6423SLionel Sambuc if (reg > ICH_FLASH_LINEAR_ADDR_MASK) 992433d6423SLionel Sambuc goto out; 993433d6423SLionel Sambuc 994433d6423SLionel Sambuc reg *= sizeof(u16_t); 995433d6423SLionel Sambuc flash_linear_addr = (ICH_FLASH_LINEAR_ADDR_MASK & reg) + 996433d6423SLionel Sambuc e->flash_base_addr; 997433d6423SLionel Sambuc 998433d6423SLionel Sambuc do { 999433d6423SLionel Sambuc tickdelay(1); 1000433d6423SLionel Sambuc 1001433d6423SLionel Sambuc /* Steps */ 1002433d6423SLionel Sambuc ret_val = eeprom_ich_init(e); 1003433d6423SLionel Sambuc if (ret_val != 0) 1004433d6423SLionel Sambuc break; 1005433d6423SLionel Sambuc 1006433d6423SLionel Sambuc hsflctl.regval = E1000_READ_FLASH_REG16(e, ICH_FLASH_HSFCTL); 1007433d6423SLionel Sambuc /* 0b/1b corresponds to 1 or 2 byte size, respectively. */ 1008433d6423SLionel Sambuc hsflctl.hsf_ctrl.fldbcount = 1; 1009433d6423SLionel Sambuc hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_READ; 1010433d6423SLionel Sambuc E1000_WRITE_FLASH_REG16(e, ICH_FLASH_HSFCTL, hsflctl.regval); 1011433d6423SLionel Sambuc E1000_WRITE_FLASH_REG(e, ICH_FLASH_FADDR, flash_linear_addr); 1012433d6423SLionel Sambuc 1013433d6423SLionel Sambuc ret_val = eeprom_ich_cycle(v, ICH_FLASH_READ_COMMAND_TIMEOUT); 1014433d6423SLionel Sambuc 1015433d6423SLionel Sambuc /* 1016*107df7c8SDavid van Moolenbroek * Check if FCERR is set to 1, if set to 1, clear it and try 1017*107df7c8SDavid van Moolenbroek * the whole sequence a few more times, else read in (shift in) 1018*107df7c8SDavid van Moolenbroek * the Flash Data0, the order is least significant byte first 1019*107df7c8SDavid van Moolenbroek * msb to lsb. 1020433d6423SLionel Sambuc */ 1021*107df7c8SDavid van Moolenbroek if (ret_val == 0) { 1022433d6423SLionel Sambuc flash_data = E1000_READ_FLASH_REG(e, ICH_FLASH_FDATA0); 1023433d6423SLionel Sambuc data = (u16_t)(flash_data & 0x0000FFFF); 1024433d6423SLionel Sambuc break; 1025*107df7c8SDavid van Moolenbroek } else { 1026433d6423SLionel Sambuc /* 1027433d6423SLionel Sambuc * If we've gotten here, then things are probably 1028433d6423SLionel Sambuc * completely hosed, but if the error condition is 1029433d6423SLionel Sambuc * detected, it won't hurt to give it another try... 1030433d6423SLionel Sambuc * ICH_FLASH_CYCLE_REPEAT_COUNT times. 1031433d6423SLionel Sambuc */ 1032*107df7c8SDavid van Moolenbroek hsfsts.regval = E1000_READ_FLASH_REG16(e, 1033*107df7c8SDavid van Moolenbroek ICH_FLASH_HSFSTS); 1034433d6423SLionel Sambuc 1035*107df7c8SDavid van Moolenbroek if (hsfsts.hsf_status.flcerr == 1) { 1036433d6423SLionel Sambuc /* Repeat for some time before giving up. */ 1037433d6423SLionel Sambuc continue; 1038*107df7c8SDavid van Moolenbroek } else if (hsfsts.hsf_status.flcdone == 0) { 1039433d6423SLionel Sambuc E1000_DEBUG(3, ("Timeout error - flash cycle " 1040433d6423SLionel Sambuc "did not complete.")); 1041433d6423SLionel Sambuc break; 1042433d6423SLionel Sambuc } 1043433d6423SLionel Sambuc } 1044433d6423SLionel Sambuc } while (count++ < ICH_FLASH_CYCLE_REPEAT_COUNT); 1045433d6423SLionel Sambuc 1046433d6423SLionel Sambuc out: 1047433d6423SLionel Sambuc return data; 1048433d6423SLionel Sambuc } 1049433d6423SLionel Sambuc 1050*107df7c8SDavid van Moolenbroek /* 1051*107df7c8SDavid van Moolenbroek * Reply to a task request from Inet. 1052*107df7c8SDavid van Moolenbroek */ 1053*107df7c8SDavid van Moolenbroek static void 1054*107df7c8SDavid van Moolenbroek reply(e1000_t *e) 1055433d6423SLionel Sambuc { 1056433d6423SLionel Sambuc message msg; 1057433d6423SLionel Sambuc int r; 1058433d6423SLionel Sambuc 1059433d6423SLionel Sambuc /* Only reply to client for read/write request. */ 1060*107df7c8SDavid van Moolenbroek if (!(e->status & E1000_READING || e->status & E1000_WRITING)) 1061433d6423SLionel Sambuc return; 1062*107df7c8SDavid van Moolenbroek 1063433d6423SLionel Sambuc /* Construct reply message. */ 1064433d6423SLionel Sambuc msg.m_type = DL_TASK_REPLY; 1065433d6423SLionel Sambuc msg.m_netdrv_net_dl_task.flags = DL_NOFLAGS; 1066433d6423SLionel Sambuc msg.m_netdrv_net_dl_task.count = 0; 1067433d6423SLionel Sambuc 1068433d6423SLionel Sambuc /* Did we successfully receive packet(s)? */ 1069*107df7c8SDavid van Moolenbroek if (e->status & E1000_READING && e->status & E1000_RECEIVED) { 1070433d6423SLionel Sambuc msg.m_netdrv_net_dl_task.flags |= DL_PACK_RECV; 1071433d6423SLionel Sambuc msg.m_netdrv_net_dl_task.count = 1072433d6423SLionel Sambuc e->rx_size >= ETH_MIN_PACK_SIZE ? 1073433d6423SLionel Sambuc e->rx_size : ETH_MIN_PACK_SIZE; 1074433d6423SLionel Sambuc 1075433d6423SLionel Sambuc /* Clear flags. */ 1076433d6423SLionel Sambuc e->status &= ~(E1000_READING | E1000_RECEIVED); 1077433d6423SLionel Sambuc } 1078*107df7c8SDavid van Moolenbroek 1079433d6423SLionel Sambuc /* Did we successfully transmit packet(s)? */ 1080*107df7c8SDavid van Moolenbroek if (e->status & E1000_TRANSMIT && e->status & E1000_WRITING) { 1081433d6423SLionel Sambuc msg.m_netdrv_net_dl_task.flags |= DL_PACK_SEND; 1082433d6423SLionel Sambuc 1083433d6423SLionel Sambuc /* Clear flags. */ 1084433d6423SLionel Sambuc e->status &= ~(E1000_WRITING | E1000_TRANSMIT); 1085433d6423SLionel Sambuc } 1086433d6423SLionel Sambuc 1087433d6423SLionel Sambuc /* Acknowledge to INET. */ 1088433d6423SLionel Sambuc if ((r = ipc_send(e->client, &msg)) != OK) 1089433d6423SLionel Sambuc panic("ipc_send() failed: %d", r); 1090433d6423SLionel Sambuc } 1091433d6423SLionel Sambuc 1092*107df7c8SDavid van Moolenbroek /* 1093*107df7c8SDavid van Moolenbroek * Send a reply to Inet. 1094*107df7c8SDavid van Moolenbroek */ 1095*107df7c8SDavid van Moolenbroek static void 1096*107df7c8SDavid van Moolenbroek mess_reply(message *req, message *reply_mess) 1097433d6423SLionel Sambuc { 1098*107df7c8SDavid van Moolenbroek 1099433d6423SLionel Sambuc if (ipc_send(req->m_source, reply_mess) != OK) 1100433d6423SLionel Sambuc panic("unable to send reply message"); 1101433d6423SLionel Sambuc } 1102