static void e1000_write_eeprom_bits(struct e1000_device *device, uint16_t data, uint16_t bitcount) { uint32_t eecd, mask; mask = 0x1 << (bitcount - 1); eecd = e1000_reg_read(device, REG_EECD); eecd &= ~(E1000_EECD_DO | E1000_EECD_DI); do { eecd &= ~E1000_EECD_DI; if(data & mask) eecd |= E1000_EECD_DI; e1000_reg_write(device, REG_EECD, eecd); e1000_write_flush(device); cdi_sleep_ms(5); e1000_raise_eeprom_clock(device, &eecd); e1000_lower_eeprom_clock(device, &eecd); mask >>= 1; } while(mask); eecd &= ~E1000_EECD_DI; e1000_reg_write(device, REG_EECD, eecd); }
static void e1000_prep_eeprom(struct e1000_device *device) { uint32_t eecd = e1000_reg_read(device, REG_EECD); eecd &= ~(E1000_EECD_SK | E1000_EECD_DI); e1000_reg_write(device, REG_EECD, eecd); eecd |= E1000_EECD_CS; e1000_reg_write(device, REG_EECD, eecd); }
static void e1000_lower_eeprom_clock(struct e1000_device *device, uint32_t *eecd) { *eecd &= ~E1000_EECD_SK; e1000_reg_write(device, REG_EECD, *eecd); e1000_write_flush(device); cdi_sleep_ms(5); }
/* * Try to receive a packet. */ static ssize_t e1000_recv(struct netdriver_data * data, size_t max) { e1000_t *e; e1000_rx_desc_t *desc; unsigned int head, tail, cur; char *ptr; size_t size; e = &e1000_state; /* If the queue head and tail are equal, the queue is empty. */ head = e1000_reg_read(e, E1000_REG_RDH); tail = e1000_reg_read(e, E1000_REG_RDT); E1000_DEBUG(4, ("%s: head=%u, tail=%u\n", e->name, head, tail)); if (head == tail) return SUSPEND; /* Has a packet been received? */ cur = (tail + 1) % e->rx_desc_count; desc = &e->rx_desc[cur]; if (!(desc->status & E1000_RX_STATUS_DONE)) return SUSPEND; /* * HACK: we expect all packets to fit in a single receive buffer. * Eventually, some sort of support to deal with packets spanning * multiple receive descriptors should be added. For now, we panic, * so that we can continue after the restart; this is already an * improvement over freezing (the old behavior of this driver). */ size = desc->length; if (!(desc->status & E1000_RX_STATUS_EOP)) panic("received packet too large"); /* Copy the packet to the caller. */ ptr = e->rx_buffer + cur * E1000_IOBUF_SIZE; if (size > max) size = max; netdriver_copyout(data, 0, ptr, size); /* Reset the descriptor. */ desc->status = 0; /* Increment tail. */ e1000_reg_write(e, E1000_REG_RDT, cur); /* Return the size of the received packet. */ return size; }
static uint32_t e1000_read_uwire(struct e1000_device *device, uint16_t offset) { uint32_t eecd, i = 0; int large_eeprom = 0; // TODO: check for post-82544 chip, only run this handling if so eecd = e1000_reg_read(device, REG_EECD); if(eecd & E1000_EECD_SIZE) large_eeprom = 1; eecd |= E1000_EECD_REQ; e1000_reg_write(device, REG_EECD, eecd); eecd = e1000_reg_read(device, REG_EECD); while((!(eecd & E1000_EECD_GNT)) && (i++ < 100)) { cdi_sleep_ms(1); eecd = e1000_reg_read(device, REG_EECD); } if(!(eecd & E1000_EECD_GNT)) { eecd &= ~E1000_EECD_REQ; e1000_reg_write(device, REG_EECD, eecd); return (uint32_t) -1; } e1000_prep_eeprom(device); e1000_write_eeprom_bits(device, EEPROM_READ_OPCODE, 3); if(large_eeprom) e1000_write_eeprom_bits(device, offset, 8); else e1000_write_eeprom_bits(device, offset, 6); uint32_t data = e1000_read_eeprom_bits(device); e1000_standby_eeprom(device); // TODO: check for post-82544 chip eecd = e1000_reg_read(device, REG_EECD); eecd &= ~E1000_EECD_REQ; e1000_reg_write(device, REG_EECD, eecd); return data; }
/* * Clear bits in a register. */ static void e1000_reg_unset(e1000_t * e, uint32_t reg, uint32_t value) { uint32_t data; /* First read the current value. */ data = e1000_reg_read(e, reg); /* Unset bits, and write back. */ e1000_reg_write(e, reg, data & ~value); }
/* * Initialize and return the card's ethernet address. */ static void e1000_init_addr(e1000_t * e, ether_addr_t * addr) { static char eakey[] = E1000_ENVVAR "#_EA"; static char eafmt[] = "x:x:x:x:x:x"; u16_t word; int i; long v; /* Do we have a user defined ethernet address? */ eakey[sizeof(E1000_ENVVAR)-1] = '0' + e1000_instance; for (i = 0; i < 6; i++) { if (env_parse(eakey, eafmt, i, &v, 0x00L, 0xFFL) != EP_SET) break; else addr->ea_addr[i] = v; } /* If that fails, read Ethernet Address from EEPROM. */ if (i != 6) { for (i = 0; i < 3; i++) { word = e->eeprom_read(e, i); addr->ea_addr[i * 2] = (word & 0x00ff); addr->ea_addr[i * 2 + 1] = (word & 0xff00) >> 8; } } /* Set Receive Address. */ e1000_reg_write(e, E1000_REG_RAL, *(u32_t *)(&addr->ea_addr[0])); e1000_reg_write(e, E1000_REG_RAH, *(u16_t *)(&addr->ea_addr[4])); e1000_reg_set(e, E1000_REG_RAH, E1000_REG_RAH_AV); e1000_reg_set(e, E1000_REG_RCTL, E1000_REG_RCTL_MPE); E1000_DEBUG(3, ("%s: Ethernet Address %x:%x:%x:%x:%x:%x\n", e->name, addr->ea_addr[0], addr->ea_addr[1], addr->ea_addr[2], addr->ea_addr[3], addr->ea_addr[4], addr->ea_addr[5])); }
/* * Read from EEPROM. */ static u16_t eeprom_eerd(e1000_t * e, int reg) { u32_t data; /* Request EEPROM read. */ e1000_reg_write(e, E1000_REG_EERD, (reg << e->eeprom_addr_off) | (E1000_REG_EERD_START)); /* Wait until ready. */ while (!((data = (e1000_reg_read(e, E1000_REG_EERD))) & e->eeprom_done_bit)); return data >> 16; }
static void e1000_standby_eeprom(struct e1000_device *device) { uint32_t eecd = e1000_reg_read(device, REG_EECD); eecd &= ~(E1000_EECD_CS | E1000_EECD_SK); e1000_reg_write(device, REG_EECD, eecd); e1000_write_flush(device); cdi_sleep_ms(5); eecd |= E1000_EECD_SK; e1000_reg_write(device, REG_EECD, eecd); e1000_write_flush(device); cdi_sleep_ms(5); eecd |= E1000_EECD_CS; e1000_reg_write(device, REG_EECD, eecd); e1000_write_flush(device); cdi_sleep_ms(5); eecd &= ~(E1000_EECD_SK); e1000_reg_write(device, REG_EECD, eecd); e1000_write_flush(device); cdi_sleep_ms(5); }
/* * Initialize the hardware. Return the ethernet address. */ static void e1000_init_hw(e1000_t * e, ether_addr_t * addr) { int r, i; e->irq_hook = e->irq; /* * Set the interrupt handler and policy. Do not automatically * reenable interrupts. Return the IRQ line number on interrupts. */ if ((r = sys_irqsetpolicy(e->irq, 0, &e->irq_hook)) != OK) panic("sys_irqsetpolicy failed: %d", r); if ((r = sys_irqenable(&e->irq_hook)) != OK) panic("sys_irqenable failed: %d", r); /* Reset hardware. */ e1000_reset_hw(e); /* * Initialize appropriately, according to section 14.3 General * Configuration of Intel's Gigabit Ethernet Controllers Software * Developer's Manual. */ e1000_reg_set(e, E1000_REG_CTRL, E1000_REG_CTRL_ASDE | E1000_REG_CTRL_SLU); e1000_reg_unset(e, E1000_REG_CTRL, E1000_REG_CTRL_LRST); e1000_reg_unset(e, E1000_REG_CTRL, E1000_REG_CTRL_PHY_RST); e1000_reg_unset(e, E1000_REG_CTRL, E1000_REG_CTRL_ILOS); e1000_reg_write(e, E1000_REG_FCAL, 0); e1000_reg_write(e, E1000_REG_FCAH, 0); e1000_reg_write(e, E1000_REG_FCT, 0); e1000_reg_write(e, E1000_REG_FCTTV, 0); e1000_reg_unset(e, E1000_REG_CTRL, E1000_REG_CTRL_VME); /* Clear Multicast Table Array (MTA). */ for (i = 0; i < 128; i++) e1000_reg_write(e, E1000_REG_MTA + i * 4, 0); /* Initialize statistics registers. */ for (i = 0; i < 64; i++) e1000_reg_write(e, E1000_REG_CRCERRS + i * 4, 0); /* Acquire MAC address and set up RX/TX buffers. */ e1000_init_addr(e, addr); e1000_init_buf(e); /* Enable interrupts. */ e1000_reg_set(e, E1000_REG_IMS, E1000_REG_IMS_LSC | E1000_REG_IMS_RXO | E1000_REG_IMS_RXT | E1000_REG_IMS_TXQE | E1000_REG_IMS_TXDW); }
/* * Try to send a packet. */ static int e1000_send(struct netdriver_data * data, size_t size) { e1000_t *e; e1000_tx_desc_t *desc; unsigned int head, tail, next; char *ptr; e = &e1000_state; if (size > E1000_IOBUF_SIZE) panic("packet too large to send"); /* * The queue tail must not advance to the point that it is equal to the * queue head, since this condition indicates that the queue is empty. */ head = e1000_reg_read(e, E1000_REG_TDH); tail = e1000_reg_read(e, E1000_REG_TDT); next = (tail + 1) % e->tx_desc_count; if (next == head) return SUSPEND; /* The descriptor to use is the one pointed to by the current tail. */ desc = &e->tx_desc[tail]; /* Copy the packet from the caller. */ ptr = e->tx_buffer + tail * E1000_IOBUF_SIZE; netdriver_copyin(data, 0, ptr, size); /* Mark this descriptor ready. */ desc->status = 0; desc->length = size; desc->command = E1000_TX_CMD_EOP | E1000_TX_CMD_FCS | E1000_TX_CMD_RS; /* Increment tail. Start transmission. */ e1000_reg_write(e, E1000_REG_TDT, next); return OK; }
/* * Initialize receive and transmit buffers. */ static void e1000_init_buf(e1000_t * e) { phys_bytes rx_desc_p, rx_buff_p; phys_bytes tx_desc_p, tx_buff_p; int i; /* Number of descriptors. */ e->rx_desc_count = E1000_RXDESC_NR; e->tx_desc_count = E1000_TXDESC_NR; /* Allocate receive descriptors. */ if ((e->rx_desc = alloc_contig(sizeof(e1000_rx_desc_t) * e->rx_desc_count, AC_ALIGN4K, &rx_desc_p)) == NULL) panic("failed to allocate RX descriptors"); memset(e->rx_desc, 0, sizeof(e1000_rx_desc_t) * e->rx_desc_count); /* Allocate receive buffers. */ e->rx_buffer_size = E1000_RXDESC_NR * E1000_IOBUF_SIZE; if ((e->rx_buffer = alloc_contig(e->rx_buffer_size, AC_ALIGN4K, &rx_buff_p)) == NULL) panic("failed to allocate RX buffers"); /* Set up receive descriptors. */ for (i = 0; i < E1000_RXDESC_NR; i++) e->rx_desc[i].buffer = rx_buff_p + i * E1000_IOBUF_SIZE; /* Allocate transmit descriptors. */ if ((e->tx_desc = alloc_contig(sizeof(e1000_tx_desc_t) * e->tx_desc_count, AC_ALIGN4K, &tx_desc_p)) == NULL) panic("failed to allocate TX descriptors"); memset(e->tx_desc, 0, sizeof(e1000_tx_desc_t) * e->tx_desc_count); /* Allocate transmit buffers. */ e->tx_buffer_size = E1000_TXDESC_NR * E1000_IOBUF_SIZE; if ((e->tx_buffer = alloc_contig(e->tx_buffer_size, AC_ALIGN4K, &tx_buff_p)) == NULL) panic("failed to allocate TX buffers"); /* Set up transmit descriptors. */ for (i = 0; i < E1000_TXDESC_NR; i++) e->tx_desc[i].buffer = tx_buff_p + i * E1000_IOBUF_SIZE; /* Set up the receive ring registers. */ e1000_reg_write(e, E1000_REG_RDBAL, rx_desc_p); e1000_reg_write(e, E1000_REG_RDBAH, 0); e1000_reg_write(e, E1000_REG_RDLEN, e->rx_desc_count * sizeof(e1000_rx_desc_t)); e1000_reg_write(e, E1000_REG_RDH, 0); e1000_reg_write(e, E1000_REG_RDT, e->rx_desc_count - 1); e1000_reg_unset(e, E1000_REG_RCTL, E1000_REG_RCTL_BSIZE); e1000_reg_set(e, E1000_REG_RCTL, E1000_REG_RCTL_EN); /* Set up the transmit ring registers. */ e1000_reg_write(e, E1000_REG_TDBAL, tx_desc_p); e1000_reg_write(e, E1000_REG_TDBAH, 0); e1000_reg_write(e, E1000_REG_TDLEN, e->tx_desc_count * sizeof(e1000_tx_desc_t)); e1000_reg_write(e, E1000_REG_TDH, 0); e1000_reg_write(e, E1000_REG_TDT, 0); e1000_reg_set(e, E1000_REG_TCTL, E1000_REG_TCTL_EN | E1000_REG_TCTL_PSP); }