diff --git a/commands/scripts/netconf.sh b/commands/scripts/netconf.sh index 29928c206..e4c6c53be 100755 --- a/commands/scripts/netconf.sh +++ b/commands/scripts/netconf.sh @@ -103,10 +103,14 @@ cards() "1186:1340" "11DB:1234" "1259:A117" "1259:A11E" "126C:1211" \ "13D1:AB06" "1432:9130" "14EA:AB06" "14EA:AB07" "1500:1360" \ "1743:8139" "4033:1360" - card 4 "Realtek 8029 based card (also emulated by Qemu)" "10EC:8029" - card 5 "NE2000, 3com 503 or WD based card (also emulated by Bochs)" - card 6 "AMD LANCE (also emulated by VMWare and VirtualBox)" "1022:2000" - card 7 "Different Ethernet card (no networking)" + card 4 "Realtek 8169 based card" \ + "10EC:8129" "10EC:8167" "10EC:8169" "1186:4300" "1259:C107" \ + "1385:8169" "16EC:0116" "1737:1032" + card 5 "Realtek 8029 based card (also emulated by Qemu)" "10EC:8029" + card 6 "NE2000, 3com 503 or WD based card (also emulated by Bochs)" + card 7 "AMD LANCE (also emulated by VMWare and VirtualBox)" "1022:2000" + card 8 "Intel PRO/1000 Gigabit" "8086:100E" "8086:107C" "8086:10CD" + card 9 "Different Ethernet card (no networking)" } warn() @@ -143,15 +147,17 @@ drv_params() test "$v" = 1 && echo "" test "$v" = 1 && echo "Note: After installing, edit $LOCALRC to the right configuration." ;; + 4) driver=rtl8169; ;; 3) driver=rtl8139; ;; - 4) driver=dp8390; driverargs="dp8390_arg='DPETH0=pci'"; ;; - 5) driver=dp8390; driverargs="dp8390_arg='DPETH0=240:9'"; + 5) driver=dp8390; driverargs="dp8390_arg='DPETH0=pci'"; ;; + 6) driver=dp8390; driverargs="dp8390_arg='DPETH0=240:9'"; test "$v" = 1 && echo "" test "$v" = 1 && echo "Note: After installing, edit $LOCALRC to the right configuration." test "$v" = 1 && echo " chose option 4, the defaults for emulation by Bochs have been set." ;; - 6) driver="lance"; ;; - 7) driver="psip0"; ;; + 7) driver="lance"; ;; + 8) driver="e1000"; ;; + 9) driver="psip0"; ;; *) warn "choose a number" esac } diff --git a/drivers/e1000/Makefile b/drivers/e1000/Makefile new file mode 100644 index 000000000..2d5506a3d --- /dev/null +++ b/drivers/e1000/Makefile @@ -0,0 +1,44 @@ +# +# Makefile for the Intel Pro/1000 driver. +# +DRIVER = e1000 + +# +# Directories. +# +u = /usr +i = $u/include +s = $i/sys +m = $i/minix +b = $i/ibm +d = .. + +# +# Build Programs, Flags and Variables. +# +CC = exec cc +CFLAGS = -I$i $(CPROFILE) +LDFLAGS = -i +LIBS = -lsys -ltimers +OBJ = e1000.o + +# build local binary +all build: $(DRIVER) +$(DRIVER): $(OBJ) + $(CC) -o $@ $(LDFLAGS) $(OBJ) $(LIBS) + install -S 128k $(DRIVER) + +# install with other drivers +install: /usr/sbin/$(DRIVER) +/usr/sbin/$(DRIVER): $(DRIVER) + install -o root -cs $? $@ + +# clean up local files +clean: + rm -f *.o $(DRIVER) + +depend: + mkdep "$(CC) -E $(CPPFLAGS)" *.c > .depend + +# Include generated dependencies. +include .depend diff --git a/drivers/e1000/e1000.c b/drivers/e1000/e1000.c new file mode 100644 index 000000000..3e9c887e2 --- /dev/null +++ b/drivers/e1000/e1000.c @@ -0,0 +1,1262 @@ +/** + * @file e1000.c + * + * @brief This file contains a device driver for Intel Pro/1000 + * Gigabit Ethernet Controllers. + */ + +#include "../drivers.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include "assert.h" +#include "e1000.h" +#include "e1000_hw.h" +#include "e1000_reg.h" +#include "e1000_pci.h" + +PRIVATE u16_t pcitab_e1000[] = +{ + E1000_DEV_ID_82540EM, + E1000_DEV_ID_82541GI_LF, + E1000_DEV_ID_ICH10_R_BM_LF, + 0, +}; + +PRIVATE char *progname; +PRIVATE e1000_t e1000_table[E1000_PORT_NR]; + +_PROTOTYPE( PRIVATE int e1000_init, (message *mp) ); +_PROTOTYPE( PRIVATE void e1000_init_pci, (void) ); +_PROTOTYPE( PRIVATE int e1000_probe, (e1000_t *e) ); +_PROTOTYPE( PRIVATE int e1000_init_hw, (e1000_t *e) ); +_PROTOTYPE( PRIVATE void e1000_init_addr, (e1000_t *e) ); +_PROTOTYPE( PRIVATE void e1000_init_buf, (e1000_t *e) ); +_PROTOTYPE( PRIVATE void e1000_reset_hw, (e1000_t *e) ); +_PROTOTYPE( PRIVATE void e1000_writev_s, (message *mp, int from_int) ); +_PROTOTYPE( PRIVATE void e1000_readv_s, (message *mp, int from_int) ); +_PROTOTYPE( PRIVATE void e1000_getstat_s, (message *mp) ); +_PROTOTYPE( PRIVATE void e1000_getname, (message *mp) ); +_PROTOTYPE( PRIVATE void e1000_interrupt, (message *mp) ); +_PROTOTYPE( PRIVATE void e1000_signal, (void) ); +_PROTOTYPE( PRIVATE int e1000_link_changed, (e1000_t *e) ); +_PROTOTYPE( PRIVATE void e1000_report_link, (e1000_t *e) ); +_PROTOTYPE( PRIVATE void e1000_stop, (void) ); +_PROTOTYPE( PRIVATE e1000_t * e1000_port, (int port) ); +_PROTOTYPE( PRIVATE uint32_t e1000_reg_read, (e1000_t *e, uint32_t reg) ); +_PROTOTYPE( PRIVATE void e1000_reg_write, (e1000_t *e, uint32_t reg, + uint32_t value) ); +_PROTOTYPE( PRIVATE void e1000_reg_set, (e1000_t *e, uint32_t reg, + uint32_t value) ); +_PROTOTYPE( PRIVATE void e1000_reg_unset, (e1000_t *e, uint32_t reg, + uint32_t value) ); +_PROTOTYPE( PRIVATE u16_t eeprom_eerd, (void *e, int reg) ); +_PROTOTYPE( PRIVATE u16_t eeprom_ich, (void *e, int reg) ); +_PROTOTYPE( PRIVATE int eeprom_ich_init, (e1000_t *e) ); +_PROTOTYPE( PRIVATE int eeprom_ich_cycle, (e1000_t *e, u32_t timeout) ); +_PROTOTYPE( PRIVATE void reply, (e1000_t *e, int err, int may_block) ); +_PROTOTYPE( PRIVATE void mess_reply, (message *req, message *reply) ); + +/*===========================================================================* + * main * + *===========================================================================*/ +int main(int argc, char *argv[]) +{ + message m; + int i, r; + u32_t tasknr; + e1000_t *e; + long v; + + /* Verify command-line arguments. */ + if (argc < 1) + { + panic("e1000", "no program name given in argc/argv", NO_NUM); + } + else + (progname = strrchr(argv[0],'/')) ? progname++ : (progname = argv[0]); + + /* Clear state. */ + memset(e1000_table, 0, sizeof(e1000_table)); + + /* Perform calibration. */ + if((r = micro_delay_calibrate()) != OK) + { + panic("e1000", "rmicro_delay_calibrate failed", r); + } + /* Try to notify inet that we are present (again) */ + if ((r = ds_retrieve_u32("inet", &tasknr)) == OK) + { + notify(tasknr); + } + else if (r != ESRCH) + { + printf("e1000: ds_retrieve_u32 failed for 'inet': %d\n", r); + } + + /* + * Enter the main driver loop. + */ + while (TRUE) + { + if ((r= receive(ANY, &m)) != OK) + { + panic("e1000", "receive failed", r); + } + if (is_notify(m.m_type)) + { + switch (_ENDPOINT_P(m.m_source)) + { + case RS_PROC_NR: + notify(m.m_source); + break; + + case HARDWARE: + e1000_interrupt(&m); + break; + + case PM_PROC_NR: + e1000_signal(); + break; + + case CLOCK: + break; + } + continue; + } + switch (m.m_type) + { + case DL_WRITEV_S: e1000_writev_s(&m, FALSE); break; + case DL_READV_S: e1000_readv_s(&m, FALSE); break; + case DL_CONF: e1000_init(&m); break; + case DL_STOP: e1000_stop(); break; + case DL_GETSTAT_S: e1000_getstat_s(&m); break; + case DL_GETNAME: e1000_getname(&m); break; + default: + panic("e1000", "illegal message", m.m_type); + } + } +} + +/*===========================================================================* + * e1000_init * + *===========================================================================*/ +PRIVATE int e1000_init(mp) +message *mp; +{ + static int first_time = 1; + message reply_mess; + e1000_t *e; + + E1000_DEBUG(3, ("e1000: init()\n")); + + /* Configure PCI devices, if needed. */ + if (first_time) + { + first_time = 0; + e1000_init_pci(); + } + /* Retrieve e1000 pointer. */ + e = e1000_port(mp->DL_PORT); + e->client = mp->DL_PROC; + + /* Initialize hardware, if needed. */ + if (!(e->status & E1000_ENABLED) && !(e1000_init_hw(e))) + { + reply_mess.m_type = DL_CONF_REPLY; + reply_mess.m3_i1 = ENXIO; + mess_reply(mp, &reply_mess); + return; + } + /* Reply back to INET. */ + reply_mess.m_type = DL_CONF_REPLY; + reply_mess.m3_i1 = mp->DL_PORT; + reply_mess.m3_i2 = E1000_PORT_NR; + *(ether_addr_t *) reply_mess.m3_ca1 = e->address; + mess_reply(mp, &reply_mess); +} + +/*===========================================================================* + * e1000_int_pci * + *===========================================================================*/ +PRIVATE void e1000_init_pci() +{ + e1000_t *e; + int i; + + /* Initialize the PCI bus. */ + pci_init(); + + /* Try to detect e1000's. */ + for (i = 0, e = &e1000_table[i]; i < E1000_PORT_NR; i++, e++) + { + strcpy(e->name, "e1000#0"); + e->name[6] += i; + e1000_probe(e); + } +} + +/*===========================================================================* + * e1000_probe * + *===========================================================================*/ +PRIVATE int e1000_probe(e) +e1000_t *e; +{ + int i, r, devind; + u16_t vid, did; + u32_t status[2]; + u32_t gfpreg, sector_base_addr, sector_end_addr; + char *dname, *str; + + E1000_DEBUG(3, ("%s: probe()\n", e->name)); + + /* + * Attempt to iterate the PCI bus. Start at the beginning. + */ + if ((r = pci_first_dev(&devind, &vid, &did)) == 0) + { + return FALSE; + } + /* Loop devices on the PCI bus. */ + for(;;) + { + for (i = 0; pcitab_e1000[i] != 0; i++) + { + if (vid != 0x8086) + continue; + + if (did != pcitab_e1000[i]) + continue; + else + break; + } + if (pcitab_e1000[i] != 0) + break; + + if (!(r = pci_next_dev(&devind, &vid, &did))) + { + return FALSE; + } + } + /* + * Successfully detected an Intel Pro/1000 on the PCI bus. + */ + e->status |= E1000_DETECTED; + e->eeprom_read = eeprom_eerd; + + /* + * Set card specific properties. + */ + switch (did) + { + case E1000_DEV_ID_ICH10_R_BM_LF: + e->eeprom_read = eeprom_ich; + break; + + case E1000_DEV_ID_82541GI_LF: + e->eeprom_done_bit = (1 << 1); + e->eeprom_addr_off = 2; + break; + + default: + e->eeprom_done_bit = (1 << 4); + e->eeprom_addr_off = 8; + break; + } + + /* Inform the user about the new card. */ + if (!(dname = pci_dev_name(vid, did))) + { + dname = "Intel Pro/1000 Gigabit Ethernet Card"; + } + E1000_DEBUG(1, ("%s: %s (%04x/%04x/%02x) at %s\n", + e->name, dname, vid, did, e->revision, + pci_slot_name(devind))); + + /* Reserve PCI resources found. */ + if ((r = pci_reserve_ok(devind)) != OK) + { + panic("e1000", "failed to reserve PCI device", r); + } + /* Read PCI configuration. */ + e->irq = pci_attr_r8(devind, PCI_ILR); + e->regs = vm_map_phys(SELF, (void *) pci_attr_r32(devind, PCI_BAR), + 0x20000); + + /* Verify mapped registers. */ + if (e->regs == (u8_t *) -1) + { + panic("e1000", "failed to map hardware registers from PCI\n", + NO_NUM); + } + /* Optionally map flash memory. */ + if (pci_attr_r32(devind, PCI_BAR_3)) + { + e->flash = vm_map_phys(SELF, (void *) pci_attr_r32(devind, PCI_BAR_2), + 0x10000); + + gfpreg = E1000_READ_FLASH_REG(e, ICH_FLASH_GFPREG); + /* + * sector_X_addr is a "sector"-aligned address (4096 bytes) + * Add 1 to sector_end_addr since this sector is included in + * the overall size. + */ + sector_base_addr = gfpreg & FLASH_GFPREG_BASE_MASK; + sector_end_addr = ((gfpreg >> 16) & FLASH_GFPREG_BASE_MASK) + 1; + + /* flash_base_addr is byte-aligned */ + e->flash_base_addr = sector_base_addr << FLASH_SECTOR_ADDR_SHIFT; + } + /* + * Output debug information. + */ + status[0] = e1000_reg_read(e, E1000_REG_STATUS); + E1000_DEBUG(3, ("%s: MEM at 0x%lx, IRQ %d\n", + e->name, e->regs, e->irq)); + E1000_DEBUG(3, ("%s: link %s, %s duplex\n", + e->name, status[0] & 3 ? "up" : "down", + status[0] & 1 ? "full" : "half")); + return TRUE; +} + +/*===========================================================================* + * e1000_init_hw * + *===========================================================================*/ +PRIVATE int e1000_init_hw(e) +e1000_t *e; +{ + int r, i; + u16_t word; + + e->status |= E1000_ENABLED; + e->irq_hook = e->irq; + + /* + * Set the interrupt handler and policy. Do not automatically + * re-enable interrupts. Return the IRQ line number on interrupts. + */ + if ((r = sys_irqsetpolicy(e->irq, 0, &e->irq_hook)) != OK) + { + panic(e->name, "sys_irqsetpolicy failed", r); + } + if ((r = sys_irqenable(&e->irq_hook)) != OK) + { + panic(e->name, "sys_irqenable failed", 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, 0); + } + /* Initialize statistics registers. */ + for (i = 0; i < 64; i++) + { + e1000_reg_write(e, E1000_REG_CRCERRS + (i * 4), 0); + } + /* + * Aquire MAC address and setup RX/TX buffers. + */ + e1000_init_addr(e); + 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); + return TRUE; +} + +/*===========================================================================* + * e1000_init_addr * + *===========================================================================*/ +PRIVATE void e1000_init_addr(e) +e1000_t *e; +{ + 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' + (e-e1000_table); + + for (i= 0; i < 6; i++) + { + if (env_parse(eakey, eafmt, i, &v, 0x00L, 0xFFL) != EP_SET) + break; + else + e->address.ea_addr[i]= v; + } + /* + * If that fails, read Ethernet Address from EEPROM. + */ + if ((i != 0 && i != 6) || i == 0) + { + for (i = 0; i < 3; i++) + { + word = e->eeprom_read(e, i); + e->address.ea_addr[(i * 2)] = (word & 0xff); + e->address.ea_addr[(i * 2) + 1] = (word & 0xff00) >> 8; + } + } + /* + * Set Receive Address. + */ + e1000_reg_write(e, E1000_REG_RAL, *(u32_t *)(&e->address.ea_addr[0])); + e1000_reg_write(e, E1000_REG_RAH, *(u16_t *)(&e->address.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, + e->address.ea_addr[0], e->address.ea_addr[1], + e->address.ea_addr[2], e->address.ea_addr[3], + e->address.ea_addr[4], e->address.ea_addr[5])); +} + +/*===========================================================================* + * e1000_init_buf * + *===========================================================================*/ +PRIVATE void e1000_init_buf(e) +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; + + /* + * First, allocate the receive descriptors. + */ + if (!e->rx_desc) + { + if ((e->rx_desc = alloc_contig(sizeof(e1000_rx_desc_t) * + e->rx_desc_count, AC_ALIGN4K, + &rx_desc_p)) == NULL) + { + panic(e->name, "failed to allocate RX descriptors", + NO_NUM); + } + memset(e->rx_desc, 0, sizeof(e1000_rx_desc_t) * e->rx_desc_count); + + /* + * Allocate 2048-byte buffers. + */ + e->rx_buffer_size = E1000_RXDESC_NR * E1000_IOBUF_SIZE; + + /* Attempt to allocate. */ + if ((e->rx_buffer = alloc_contig(e->rx_buffer_size, + AC_ALIGN4K, &rx_buff_p)) == NULL) + { + panic(e->name, "failed to allocate RX buffers", NO_NUM); + } + /* Setup receive descriptors. */ + for (i = 0; i < E1000_RXDESC_NR; i++) + { + e->rx_desc[i].buffer = rx_buff_p + (i * E1000_IOBUF_SIZE); + } + } + /* + * Then, allocate transmit descriptors. + */ + if (!e->tx_desc) + { + if ((e->tx_desc = alloc_contig(sizeof(e1000_tx_desc_t) * + e->tx_desc_count, AC_ALIGN4K, + &tx_desc_p)) == NULL) + { + panic(e->name, "failed to allocate TX descriptors", + NO_NUM); + } + memset(e->tx_desc, 0, sizeof(e1000_tx_desc_t) * e->tx_desc_count); + + /* + * Allocate 2048-byte buffers. + */ + e->tx_buffer_size = E1000_TXDESC_NR * E1000_IOBUF_SIZE; + + /* Attempt to allocate. */ + if ((e->tx_buffer = alloc_contig(e->tx_buffer_size, + AC_ALIGN4K, &tx_buff_p)) == NULL) + { + panic(e->name, "failed to allocate TX buffers", NO_NUM); + } + /* Setup transmit descriptors. */ + for (i = 0; i < E1000_RXDESC_NR; i++) + { + e->tx_desc[i].buffer = tx_buff_p + (i * E1000_IOBUF_SIZE); + } + } + /* + * Setup 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); + + /* + * Setup 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); +} + +/*===========================================================================* + * e1000_reset_hw * + *===========================================================================*/ +PRIVATE void e1000_reset_hw(e) +e1000_t *e; +{ + /* Assert a Device Reset signal. */ + e1000_reg_set(e, E1000_REG_CTRL, E1000_REG_CTRL_RST); + + /* Wait one microsecond. */ + tickdelay(1); +} + +/*===========================================================================* + * e1000_writev_s * + *===========================================================================*/ +PRIVATE void e1000_writev_s(mp, from_int) +message *mp; +int from_int; +{ + e1000_t *e = e1000_port(mp->DL_PORT); + e1000_tx_desc_t *desc; + iovec_s_t iovec[E1000_IOVEC_NR]; + int r, head, tail, i, bytes = 0, size; + + E1000_DEBUG(3, ("e1000: writev_s(%x,%d)\n", mp, from_int)); + + /* Are we called from the interrupt handler? */ + if (!from_int) + { + /* We cannot write twice simultaneously. + assert(!(e->status & E1000_WRITING)); */ + + /* Copy write message. */ + e->tx_message = *mp; + e->status |= E1000_WRITING; + + /* Must be a sane vector count. */ + assert(e->tx_message.DL_COUNT > 0); + assert(e->tx_message.DL_COUNT < E1000_IOVEC_NR); + + /* + * Copy the I/O vector table. + */ + if ((r = sys_safecopyfrom(e->client, e->tx_message.DL_GRANT, 0, + (vir_bytes) iovec, e->tx_message.DL_COUNT * + sizeof(iovec_s_t), D)) != OK) + { + panic(e->name, "sys_safecopyfrom() failed", r); + } + /* Find the head, tail and current descriptors. */ + head = e1000_reg_read(e, E1000_REG_TDH); + tail = e1000_reg_read(e, E1000_REG_TDT); + desc = &e->tx_desc[tail]; + + E1000_DEBUG(4, ("%s: head=%d, tail=%d\n", + e->name, head, tail)); + + /* Loop vector elements. */ + for (i = 0; i < e->tx_message.DL_COUNT; i++) + { + size = iovec[i].iov_size < (E1000_IOBUF_SIZE - bytes) ? + iovec[i].iov_size : (E1000_IOBUF_SIZE - bytes); + + E1000_DEBUG(4, ("iovec[%d] = %d\n", i, size)); + + /* Copy bytes to TX queue buffers. */ + if ((r = sys_safecopyfrom(e->client, iovec[i].iov_grant, 0, + (vir_bytes) e->tx_buffer + + (tail * E1000_IOBUF_SIZE), + size, D)) != OK) + { + panic(e->name, "sys_safecopyfrom() failed", r); + } + /* Mark this descriptor ready. */ + desc->status = 0; + desc->command = 0; + desc->length = size; + + /* Marks End-of-Packet. */ + if (i == e->tx_message.DL_COUNT - 1) + { + desc->command = E1000_TX_CMD_EOP | + E1000_TX_CMD_FCS | + E1000_TX_CMD_RS; + } + /* Move to next descriptor. */ + tail = (tail + 1) % e->tx_desc_count; + bytes += size; + desc = &e->tx_desc[tail]; + } + /* Increment tail. Start transmission. */ + e1000_reg_write(e, E1000_REG_TDT, tail); + + E1000_DEBUG(2, ("e1000: wrote %d byte packet\n", bytes)); + } + else + { + e->status |= E1000_TRANSMIT; + } + reply(e, OK, FALSE); +} + +/*===========================================================================* + * e1000_readv_s * + *===========================================================================*/ +PRIVATE void e1000_readv_s(mp, from_int) +message *mp; +int from_int; +{ + e1000_t *e = e1000_port(mp->DL_PORT); + e1000_rx_desc_t *desc; + iovec_s_t iovec[E1000_IOVEC_NR]; + int i, r, head, tail, cur, bytes = 0, size; + + E1000_DEBUG(3, ("e1000: readv_s(%x,%d)\n", mp, from_int)); + + /* Are we called from the interrupt handler? */ + if (!from_int) + { + e->rx_message = *mp; + e->status |= E1000_READING; + e->rx_size = 0; + + assert(e->rx_message.DL_COUNT > 0); + assert(e->rx_message.DL_COUNT < E1000_IOVEC_NR); + } + if (e->status & E1000_READING) + { + /* + * Copy the I/O vector table first. + */ + if ((r = sys_safecopyfrom(e->client, e->rx_message.DL_GRANT, 0, + (vir_bytes) iovec, e->rx_message.DL_COUNT * + sizeof(iovec_s_t), D)) != OK) + { + panic(e->name, "sys_safecopyfrom() failed", r); + } + /* Find the head, tail and current descriptors. */ + head = e1000_reg_read(e, E1000_REG_RDH); + tail = e1000_reg_read(e, E1000_REG_RDT); + cur = (tail + 1) % e->rx_desc_count; + desc = &e->rx_desc[cur]; + + /* + * Only handle one packet at a time. + */ + if (!(desc->status & E1000_RX_STATUS_EOP)) + { + reply(e, OK, FALSE); + return; + } + E1000_DEBUG(4, ("%s: head=%x, tail=%d\n", + e->name, head, tail)); + + /* + * Copy to vector elements. + */ + for (i = 0; i < e->rx_message.DL_COUNT && bytes < desc->length; i++) + { + size = iovec[i].iov_size < (desc->length - bytes) ? + iovec[i].iov_size : (desc->length - bytes); + + E1000_DEBUG(4, ("iovec[%d] = %d[%d]\n", + i, iovec[i].iov_size, size)); + + if ((r = sys_safecopyto(e->client, iovec[i].iov_grant, 0, + (vir_bytes) e->rx_buffer + bytes + + (cur * E1000_IOBUF_SIZE), + size, D)) != OK) + { + panic(e->name, "sys_safecopyto() failed", r); + } + bytes += size; + } + desc->status = 0; + + /* + * Update state. + */ + e->rx_size = bytes; + e->status |= E1000_RECEIVED; + E1000_DEBUG(2, ("e1000: got %d byte packet\n", e->rx_size)); + + /* Increment tail. */ + e1000_reg_write(e, E1000_REG_RDT, (tail + 1) % e->rx_desc_count); + } + reply(e, OK, FALSE); +} + +/*===========================================================================* + * e1000_getstat_s * + *===========================================================================*/ +PRIVATE void e1000_getstat_s(mp) +message *mp; +{ + int r; + eth_stat_t stats; + e1000_t *e = e1000_port(mp->DL_PORT); + + E1000_DEBUG(3, ("e1000: getstat_s()\n")); + + stats.ets_recvErr = e1000_reg_read(e, E1000_REG_RXERRC); + stats.ets_sendErr = 0; + stats.ets_OVW = 0; + stats.ets_CRCerr = e1000_reg_read(e, E1000_REG_CRCERRS); + stats.ets_frameAll = 0; + stats.ets_missedP = e1000_reg_read(e, E1000_REG_MPC); + stats.ets_packetR = e1000_reg_read(e, E1000_REG_TPR); + stats.ets_packetT = e1000_reg_read(e, E1000_REG_TPT); + stats.ets_collision = e1000_reg_read(e, E1000_REG_COLC); + stats.ets_transAb = 0; + stats.ets_carrSense = 0; + stats.ets_fifoUnder = 0; + stats.ets_fifoOver = 0; + stats.ets_CDheartbeat = 0; + stats.ets_OWC = 0; + + sys_safecopyto(mp->DL_PROC, mp->DL_GRANT, 0, (vir_bytes)&stats, + sizeof(stats), D); + mp->m_type = DL_STAT_REPLY; + mp->DL_PORT = mp->DL_PORT; + mp->DL_STAT = OK; + if((r=send(mp->m_source, mp)) != OK) + panic("e1000", "e1000_getstat: send() failed", r); +} + +/*===========================================================================* + * e1000_getname * + *===========================================================================*/ +PRIVATE void e1000_getname(mp) +message *mp; +{ + int r; + + E1000_DEBUG(3, ("e1000: getname()\n")); + + /* Copy our program name. */ + strncpy(mp->DL_NAME, progname, sizeof(mp->DL_NAME)); + mp->DL_NAME[ sizeof(mp->DL_NAME) - 1 ] = 0; + + /* Acknowledge the name request. */ + mp->m_type = DL_NAME_REPLY; + if ((r = send(mp->m_source, mp)) != OK) + { + panic("e1000", "e1000_getname: send() failed", r); + } +} + +/*===========================================================================* + * e1000_interrupt * + *===========================================================================*/ +PRIVATE void e1000_interrupt(mp) +message *mp; +{ + e1000_t *e; + u32_t cause; + unsigned int i; + + E1000_DEBUG(3, ("e1000: interrupt\n")); + + /* + * Loop all cards. Check for interrupt reason(s). + */ + for (i = 0; i < E1000_PORT_NR; i++) + { + e = e1000_port(i); + + /* Re-enable interrupts. */ + if (sys_irqenable(&e->irq_hook) != OK) + { + panic("e1000", "failed to re-enable IRQ", NO_NUM); + } + + /* Read the Interrupt Cause Read register. */ + if ((cause = e1000_reg_read(e, E1000_REG_ICR))) + { + if (cause & E1000_REG_ICR_LSC) + e1000_link_changed(e); + + if (cause & (E1000_REG_ICR_RXO | E1000_REG_ICR_RXT)) + e1000_readv_s(&e->rx_message, TRUE); + + if ((cause & E1000_REG_ICR_TXQE) || + (cause & E1000_REG_ICR_TXDW)) + e1000_writev_s(&e->tx_message, TRUE); + + } + } +} + +/*===========================================================================* + * e1000_signal * + *===========================================================================*/ +PRIVATE void e1000_signal(void) +{ + sigset_t sigset; + int sig; + + E1000_DEBUG(3, ("e1000: signal()\n")); + + /* Try to obtain signal set from PM. */ + if (getsigset(&sigset) != 0) + { + return; + } + /* Check for known signals. */ + if (sigismember(&sigset, SIGTERM)) + { + e1000_stop(); + } +} + +/*===========================================================================* + * e1000_link_changed * + *===========================================================================*/ +PRIVATE int e1000_link_changed(e) +e1000_t *e; +{ + E1000_DEBUG(4, ("%s: link_changed()\n", e->name)); + return FALSE; +} + +/*===========================================================================* + * e1000_report_link * + *===========================================================================*/ +PRIVATE void e1000_report_link(e) +e1000_t *e; +{ + E1000_DEBUG(4, ("%s: report_link()\n", e->name)); +} + +/*===========================================================================* + * e1000_stop * + *===========================================================================*/ +PRIVATE void e1000_stop() +{ + E1000_DEBUG(3, ("e1000: stop()\n")); + exit(EXIT_SUCCESS); +} + +/*===========================================================================* + * e1000_port * + *===========================================================================*/ +PRIVATE e1000_t * e1000_port(num) +int num; +{ + /* + * Is the given port number within the allowed range? + */ + if (num < 0 || num >= E1000_PORT_NR) + { + panic("e1000", "invalid port number given", num); + } + + /* + * The card must be active. + */ + if (!(e1000_table[num].status & E1000_DETECTED)) + { + panic("e1000", "inactive port number given", num); + } + return &e1000_table[num]; +} + + +/*===========================================================================* + * e1000_reg_read * + *===========================================================================*/ +PRIVATE uint32_t e1000_reg_read(e, reg) +e1000_t *e; +uint32_t reg; +{ + uint32_t value; + + /* Assume a sane register. */ + assert(reg < 0x1ffff); + + /* Read from memory mapped register. */ + value = *(u32_t *)(e->regs + reg); + + /* Return the result. */ + return value; +} + +/*===========================================================================* + * e1000_reg_write * + *===========================================================================*/ +PRIVATE void e1000_reg_write(e, reg, value) +e1000_t *e; +uint32_t reg; +uint32_t value; +{ + /* Assume a sane register. */ + assert(reg < 0x1ffff); + + /* Write to memory mapped register. */ + *(u32_t *)(e->regs + reg) = value; +} + +/*===========================================================================* + * e1000_reg_set * + *===========================================================================*/ +PRIVATE void e1000_reg_set(e, reg, value) +e1000_t *e; +uint32_t reg; +uint32_t value; +{ + uint32_t data; + + /* First read the current value. */ + data = e1000_reg_read(e, reg); + + /* Set value, and write back. */ + e1000_reg_write(e, reg, data | value); +} + +/*===========================================================================* + * e1000_reg_unset * + *===========================================================================*/ +PRIVATE void e1000_reg_unset(e, reg, value) +e1000_t *e; +uint32_t reg; +uint32_t value; +{ + uint32_t data; + + /* First read the current value. */ + data = e1000_reg_read(e, reg); + + /* Unset value, and write back. */ + e1000_reg_write(e, reg, data & ~value); +} + + +/*===========================================================================* + * eeprom_eerd * + *===========================================================================*/ +PRIVATE u16_t eeprom_eerd(v, reg) +void *v; +int reg; +{ + e1000_t *e = (e1000_t *) v; + u16_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 (!(e1000_reg_read(e, E1000_REG_EERD) & + e->eeprom_done_bit)); + + /* Fetch data. */ + data = (e1000_reg_read(e, E1000_REG_EERD) & + E1000_REG_EERD_DATA) >> 16; + return data; +} + +/*===========================================================================* + * eeprom_ich_init * + *===========================================================================*/ +PRIVATE int eeprom_ich_init(e) +e1000_t *e; +{ + union ich8_hws_flash_status hsfsts; + int ret_val = -1; + int i = 0; + + hsfsts.regval = E1000_READ_FLASH_REG16(e, ICH_FLASH_HSFSTS); + + /* Check if the flash descriptor is valid */ + if (hsfsts.hsf_status.fldesvalid == 0) + { + E1000_DEBUG(3, ("Flash descriptor invalid. " + "SW Sequencing must be used.")); + goto out; + } + /* Clear FCERR and DAEL in hw status by writing 1 */ + hsfsts.hsf_status.flcerr = 1; + hsfsts.hsf_status.dael = 1; + + E1000_WRITE_FLASH_REG16(e, ICH_FLASH_HSFSTS, hsfsts.regval); + + /* + * Either we should have a hardware SPI cycle in progress + * bit to check against, in order to start a new cycle or + * FDONE bit should be changed in the hardware so that it + * is 1 after hardware reset, which can then be used as an + * indication whether a cycle is in progress or has been + * completed. + */ + if (hsfsts.hsf_status.flcinprog == 0) + { + /* + * There is no cycle running at present, + * so we can start a cycle. + * Begin by setting Flash Cycle Done. + */ + hsfsts.hsf_status.flcdone = 1; + E1000_WRITE_FLASH_REG16(e, ICH_FLASH_HSFSTS, hsfsts.regval); + ret_val = 0; + } + else + { + /* + * Otherwise poll for sometime so the current + * cycle has a chance to end before giving up. + */ + for (i = 0; i < ICH_FLASH_READ_COMMAND_TIMEOUT; i++) + { + hsfsts.regval = E1000_READ_FLASH_REG16(e, ICH_FLASH_HSFSTS); + + if (hsfsts.hsf_status.flcinprog == 0) + { + ret_val = 0; + break; + } + tickdelay(1); + } + if (ret_val == 0) + { + /* + * Successful in waiting for previous cycle to timeout, + * now set the Flash Cycle Done. + */ + hsfsts.hsf_status.flcdone = 1; + E1000_WRITE_FLASH_REG16(e, ICH_FLASH_HSFSTS, + hsfsts.regval); + } + else + { + E1000_DEBUG(3, ("Flash controller busy, cannot get access")); + } + } +out: + return ret_val; +} + +/*===========================================================================* + * eeprom_ich_cycle * + *===========================================================================*/ +PRIVATE int eeprom_ich_cycle(e1000_t *e, u32_t timeout) +{ + union ich8_hws_flash_ctrl hsflctl; + union ich8_hws_flash_status hsfsts; + int ret_val = -1; + u32_t i = 0; + + E1000_DEBUG(3, ("e1000_flash_cycle_ich8lan")); + + /* Start a cycle by writing 1 in Flash Cycle Go in Hw Flash Control */ + hsflctl.regval = E1000_READ_FLASH_REG16(e, ICH_FLASH_HSFCTL); + hsflctl.hsf_ctrl.flcgo = 1; + E1000_WRITE_FLASH_REG16(e, ICH_FLASH_HSFCTL, hsflctl.regval); + + /* wait till FDONE bit is set to 1 */ + do + { + hsfsts.regval = E1000_READ_FLASH_REG16(e, ICH_FLASH_HSFSTS); + if (hsfsts.hsf_status.flcdone == 1) + break; + tickdelay(1); + } + while (i++ < timeout); + + if (hsfsts.hsf_status.flcdone == 1 && hsfsts.hsf_status.flcerr == 0) + ret_val = 0; + + return ret_val; +} + +/*===========================================================================* + * eeprom_ich * + *===========================================================================*/ +PRIVATE u16_t eeprom_ich(v, reg) +void *v; +int reg; +{ + union ich8_hws_flash_status hsfsts; + union ich8_hws_flash_ctrl hsflctl; + u32_t flash_linear_addr; + u32_t flash_data = 0; + int ret_val = -1; + u8_t count = 0; + e1000_t *e = (e1000_t *) v; + u16_t data; + + E1000_DEBUG(3, ("e1000_read_flash_data_ich8lan")); + + if (reg > ICH_FLASH_LINEAR_ADDR_MASK) + goto out; + + reg *= sizeof(u16_t); + flash_linear_addr = (ICH_FLASH_LINEAR_ADDR_MASK & reg) + + e->flash_base_addr; + + do { + tickdelay(1); + + /* Steps */ + ret_val = eeprom_ich_init(e); + if (ret_val != 0) + break; + + hsflctl.regval = E1000_READ_FLASH_REG16(e, ICH_FLASH_HSFCTL); + /* 0b/1b corresponds to 1 or 2 byte size, respectively. */ + hsflctl.hsf_ctrl.fldbcount = 1; + hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_READ; + E1000_WRITE_FLASH_REG16(e, ICH_FLASH_HSFCTL, hsflctl.regval); + E1000_WRITE_FLASH_REG(e, ICH_FLASH_FADDR, flash_linear_addr); + + ret_val = eeprom_ich_cycle(v, ICH_FLASH_READ_COMMAND_TIMEOUT); + + /* + * Check if FCERR is set to 1, if set to 1, clear it + * and try the whole sequence a few more times, else + * read in (shift in) the Flash Data0, the order is + * least significant byte first msb to lsb + */ + if (ret_val == 0) + { + flash_data = E1000_READ_FLASH_REG(e, ICH_FLASH_FDATA0); + data = (u16_t)(flash_data & 0x0000FFFF); + break; + } + else + { + /* + * If we've gotten here, then things are probably + * completely hosed, but if the error condition is + * detected, it won't hurt to give it another try... + * ICH_FLASH_CYCLE_REPEAT_COUNT times. + */ + hsfsts.regval = E1000_READ_FLASH_REG16(e, ICH_FLASH_HSFSTS); + + if (hsfsts.hsf_status.flcerr == 1) + { + /* Repeat for some time before giving up. */ + continue; + } + else if (hsfsts.hsf_status.flcdone == 0) + { + E1000_DEBUG(3, ("Timeout error - flash cycle " + "did not complete.")); + break; + } + } + } while (count++ < ICH_FLASH_CYCLE_REPEAT_COUNT); + +out: + return data; +} + +/*===========================================================================* + * reply * + *===========================================================================*/ +PRIVATE void reply(e, err, may_block) +e1000_t *e; +int err; +int may_block; +{ + message msg; + int r; + + /* Only reply to client for read/write request. */ + if (!(e->status & E1000_READING || + e->status & E1000_WRITING)) + { + return; + } + /* Construct reply message. */ + msg.m_type = DL_TASK_REPLY; + msg.DL_PORT = e - e1000_table; + msg.DL_PROC = e->client; + msg.DL_COUNT = 0; + msg.DL_STAT = 0; + msg.DL_CLCK = 0; + + /* Did we successfully receive packet(s)? */ + if (e->status & E1000_READING && + e->status & E1000_RECEIVED) + { + msg.DL_STAT = DL_PACK_RECV; + msg.DL_COUNT = e->rx_size >= ETH_MIN_PACK_SIZE ? + e->rx_size : ETH_MIN_PACK_SIZE; + + /* Clear flags. */ + e->status &= ~(E1000_READING | E1000_RECEIVED); + } + /* Did we successfully transmit packet(s)? */ + if (e->status & E1000_TRANSMIT && + e->status & E1000_WRITING) + { + msg.DL_STAT = DL_PACK_SEND; + msg.DL_COUNT = 0; + + /* Clear flags. */ + e->status &= ~(E1000_WRITING | E1000_TRANSMIT); + } + + /* Acknowledge to INET. */ + if ((r = send(e->client, &msg)) != OK) + { + panic("e1000", "send() failed", r); + } +} + +/*===========================================================================* + * mess_reply * + *===========================================================================*/ +PRIVATE void mess_reply(req, reply_mess) +message *req; +message *reply_mess; +{ + if (send(req->m_source, reply_mess) != OK) + { + panic("e1000", "unable to send reply message", NO_NUM); + } +} diff --git a/drivers/e1000/e1000.h b/drivers/e1000/e1000.h new file mode 100644 index 000000000..bf4da4b6d --- /dev/null +++ b/drivers/e1000/e1000.h @@ -0,0 +1,177 @@ +/** + * @file e1000.h + * + * @brief Device driver implementation declarations for the + * Intel Pro/1000 Gigabit Ethernet card(s). + * + * Parts of this code is based on the DragonflyBSD (FreeBSD) + * implementation, and the fxp driver for Minix 3. + * + * @see http://svn.freebsd.org/viewvc/base/head/sys/dev/e1000/ + * @see fxp.c + * + * @author Niek Linnenbank + * @date September 2009 + * + */ + +#ifndef __E1000_H +#define __E1000_H + +#include "../drivers.h" +#include +#include +#include +#include +#include +#include +#include "e1000_hw.h" + +/** + * @name Constants. + * @{ + */ + +/** Maximum number of cards supported. */ +#define E1000_PORT_NR 1 + +/** Number of receive descriptors per card. */ +#define E1000_RXDESC_NR 256 + +/** Number of transmit descriptors per card. */ +#define E1000_TXDESC_NR 256 + +/** Number of I/O vectors to use. */ +#define E1000_IOVEC_NR 16 + +/** Size of each I/O buffer per descriptor. */ +#define E1000_IOBUF_SIZE 2048 + +/** Debug verbosity. */ +#define E1000_VERBOSE 1 + +/** MAC address override variable. */ +#define E1000_ENVVAR "E1000ETH" + +/** + * @} + */ + +/** + * @name Status Flags. + * @{ + */ + +/** Card has been detected on the PCI bus. */ +#define E1000_DETECTED (1 << 0) + +/** Card is enabled. */ +#define E1000_ENABLED (1 << 1) + +/** Client has requested to receive packets. */ +#define E1000_READING (1 << 2) + +/** Client has requested to write packets. */ +#define E1000_WRITING (1 << 3) + +/** Received some packets on the card. */ +#define E1000_RECEIVED (1 << 4) + +/** Transmitted some packets on the card. */ +#define E1000_TRANSMIT (1 << 5) + +/** + * @} + */ + +/** + * @name Macros. + * @{ + */ + +/** + * @brief Print a debug message. + * @param level Debug verbosity level. + * @param args Arguments to printf(). + */ +#define E1000_DEBUG(level, args) \ + if ((level) <= E1000_VERBOSE) \ + { \ + printf args; \ + } \ + +/** + * Read a byte from flash memory. + * @param e e1000_t pointer. + * @param reg Register offset. + */ +#define E1000_READ_FLASH_REG(e,reg) \ + *(u32_t *) (((e)->flash) + (reg)) + +/** + * Read a 16-bit word from flash memory. + * @param e e1000_t pointer. + * @param reg Register offset. + */ +#define E1000_READ_FLASH_REG16(e,reg) \ + *(u16_t *) (((e)->flash) + (reg)) + +/** + * Write a 16-bit word to flash memory. + * @param e e1000_t pointer. + * @param reg Register offset. + * @param value New value. + */ +#define E1000_WRITE_FLASH_REG(e,reg,value) \ + *((u32_t *) (((e)->flash) + (reg))) = (value) + +/** + * Write a 16-bit word to flash memory. + * @param e e1000_t pointer. + * @param reg Register offset. + * @param value New value. + */ +#define E1000_WRITE_FLASH_REG16(e,reg,value) \ + *((u16_t *) (((e)->flash) + (reg))) = (value) + +/** + * @} + */ + +/** + * @brief Describes the state of an Intel Pro/1000 card. + */ +typedef struct e1000 +{ + char name[8]; /**< String containing the device name. */ + int status; /**< Describes the card's current state. */ + int irq; /**< Interrupt Request Vector. */ + int irq_hook; /**< Interrupt Request Vector Hook. */ + int revision; /**< Hardware Revision Number. */ + u8_t *regs; /**< Memory mapped hardware registers. */ + u8_t *flash; /**< Optional flash memory. */ + u32_t flash_base_addr; /**< Flash base address. */ + ether_addr_t address; /**< Ethernet MAC address. */ + u16_t (*eeprom_read)(void *, int reg); /**< Function to read + the EEPROM. */ + int eeprom_done_bit; /**< Offset of the EERD.DONE bit. */ + int eeprom_addr_off; /**< Offset of the EERD.ADDR field. */ + + e1000_rx_desc_t *rx_desc; /**< Receive Descriptor table. */ + int rx_desc_count; /**< Number of Receive Descriptors. */ + char *rx_buffer; /**< Receive buffer returned by malloc(). */ + int rx_buffer_size; /**< Size of the receive buffer. */ + + e1000_tx_desc_t *tx_desc; /**< Transmit Descriptor table. */ + int tx_desc_count; /**< Number of Transmit Descriptors. */ + char *tx_buffer; /**< Transmit buffer returned by malloc(). */ + int tx_buffer_size; /**< Size of the transmit buffer. */ + + int client; /**< Process ID being served by e1000. */ + message rx_message; /**< Read message received from client. */ + message tx_message; /**< Write message received from client. */ + size_t rx_size; /**< Size of one packet received. */ +} +e1000_t; + +#endif /* __E1000_H */ diff --git a/drivers/e1000/e1000_hw.h b/drivers/e1000/e1000_hw.h new file mode 100644 index 000000000..42740a34f --- /dev/null +++ b/drivers/e1000/e1000_hw.h @@ -0,0 +1,174 @@ +/** + * @file e1000.h + * + * @brief Hardware specific datastructures of the Intel + * Pro/1000 Gigabit Ethernet card(s). + * + * Parts of this code is based on the DragonflyBSD (FreeBSD) + * implementation, and the fxp driver for Minix 3. + * + * @see http://svn.freebsd.org/viewvc/base/head/sys/dev/e1000/ + * @see fxp.c + * + * @author Niek Linnenbank + * @date September 2009 + * + */ + +#ifndef __E1000_HW_H +#define __E1000_HW_H + +#include + +/** + * @name Datastructures. + * @{ + */ + +/** + * @brief Receive Descriptor Format. + */ +typedef struct e1000_rx_desc +{ + u32_t buffer; /**< Address of the receive data buffer (64-bit). */ + u32_t buffer_h; /**< High 32-bits of the receive data buffer (unused). */ + u16_t length; /**< Size of the receive buffer. */ + u16_t checksum; /**< Packet checksum. */ + u8_t status; /**< Descriptor status. */ + u8_t errors; /**< Descriptor errors. */ + u16_t special; /**< VLAN information. */ +} +e1000_rx_desc_t; + +/** + * @brief Transmit Descriptor Format. + */ +typedef struct e1000_tx_desc +{ + u32_t buffer; /**< Address of the transmit buffer (64-bit). */ + u32_t buffer_h; /**< High 32-bits of the transmit buffer (unused). */ + u16_t length; /**< Size of the transmit buffer contents. */ + u8_t checksum_off; /**< Checksum Offset. */ + u8_t command; /**< Command field. */ + u8_t status; /**< Status field. */ + u8_t checksum_st; /**< Checksum Start. */ + u16_t special; /**< Optional special bits. */ +} +e1000_tx_desc_t; + +/** + * @brief ICH GbE Flash Hardware Sequencing Flash Status Register bit breakdown. + * @see http://gitweb.dragonflybsd.org + */ +union ich8_hws_flash_status +{ + struct ich8_hsfsts + { + unsigned flcdone :1; /**< bit 0 Flash Cycle Done */ + unsigned flcerr :1; /**< bit 1 Flash Cycle Error */ + unsigned dael :1; /**< bit 2 Direct Access error Log */ + unsigned berasesz :2; /**< bit 4:3 Sector Erase Size */ + unsigned flcinprog :1; /**< bit 5 flash cycle in Progress */ + unsigned reserved1 :2; /**< bit 13:6 Reserved */ + unsigned reserved2 :6; /**< bit 13:6 Reserved */ + unsigned fldesvalid :1; /**< bit 14 Flash Descriptor Valid */ + unsigned flockdn :1; /**< bit 15 Flash Config Lock-Down */ + } hsf_status; + u16_t regval; +}; + +/** + * @brief ICH GbE Flash Hardware Sequencing Flash control Register bit breakdown. + * @see http://gitweb.dragonflybsd.org + */ +union ich8_hws_flash_ctrl +{ + struct ich8_hsflctl + { + unsigned flcgo :1; /**< 0 Flash Cycle Go */ + unsigned flcycle :2; /**< 2:1 Flash Cycle */ + unsigned reserved :5; /**< 7:3 Reserved */ + unsigned fldbcount :2; /**< 9:8 Flash Data Byte Count */ + unsigned flockdn :6; /**< 15:10 Reserved */ + } hsf_ctrl; + u16_t regval; +}; + +/** + * @brief ICH Flash Region Access Permissions. + * @see http://gitweb.dragonflybsd.org + */ +union ich8_hws_flash_regacc +{ + struct ich8_flracc + { + unsigned grra :8; /**< 0:7 GbE region Read Access */ + unsigned grwa :8; /**< 8:15 GbE region Write Access */ + unsigned gmrag :8; /**< 23:16 GbE Master Read Access Grant */ + unsigned gmwag :8; /**< 31:24 GbE Master Write Access Grant */ + } hsf_flregacc; + u16_t regval; +}; + +/** + * @} + */ + +/** + * @name Receive Status Field Bits. + * @{ + */ + +/** Passed In-exact Filter. */ +#define E1000_RX_STATUS_PIF (1 << 7) + +/** End of Packet. */ +#define E1000_RX_STATUS_EOP (1 << 1) + +/** Descriptor Done. */ +#define E1000_RX_STATUS_DONE (1 << 0) + +/** + * @} + */ + +/** + * @name Receive Errors Field Bits. + * @{ + */ + +/** RX Data Error. */ +#define E1000_RX_ERROR_RXE (1 << 7) + +/** Carrier Extension Error. */ +#define E1000_RX_ERROR_CXE (1 << 4) + +/** Sequence/Framing Error. */ +#define E1000_RX_ERROR_SEQ (1 << 2) + +/** CRC/Alignment Error. */ +#define E1000_RX_ERROR_CE (1 << 0) + +/** + * @} + */ + +/** + * @name Transmit Command Field Bits. + * @{ + */ + +/** End of Packet. */ +#define E1000_TX_CMD_EOP (1 << 0) + +/** Insert FCS/CRC. */ +#define E1000_TX_CMD_FCS (1 << 1) + +/** Report Status. */ +#define E1000_TX_CMD_RS (1 << 3) + +/** + * @} + */ + +#endif /* __E1000_HW_H */ diff --git a/drivers/e1000/e1000_pci.h b/drivers/e1000/e1000_pci.h new file mode 100644 index 000000000..0528aaa3a --- /dev/null +++ b/drivers/e1000/e1000_pci.h @@ -0,0 +1,137 @@ +/** + * @file e1000_pci.h + * + * @brief PCI Device Identity numbers of Intel Pro/1000 + * Gigabit Ethernet cards. + * + * Parts of this code is based on the DragonflyBSD (FreeBSD) + * implementation, and the fxp driver for Minix 3. + * + * @see http://svn.freebsd.org/viewvc/base/head/sys/dev/e1000/ + * @see fxp.c + * + * @author Niek Linnenbank + * @date September 2009 + * + */ + +#ifndef __E1000_PCI_H +#define __E1000_PCI_H + +/** + * @name PCI Device ID's. + * @{ + */ + +#define E1000_DEV_ID_82542 0x1000 +#define E1000_DEV_ID_82543GC_FIBER 0x1001 +#define E1000_DEV_ID_82543GC_COPPER 0x1004 +#define E1000_DEV_ID_82544EI_COPPER 0x1008 +#define E1000_DEV_ID_82544EI_FIBER 0x1009 +#define E1000_DEV_ID_82544GC_COPPER 0x100C +#define E1000_DEV_ID_82544GC_LOM 0x100D +#define E1000_DEV_ID_82540EM 0x100E +#define E1000_DEV_ID_82540EM_LOM 0x1015 +#define E1000_DEV_ID_82540EP_LOM 0x1016 +#define E1000_DEV_ID_82540EP 0x1017 +#define E1000_DEV_ID_82540EP_LP 0x101E +#define E1000_DEV_ID_82545EM_COPPER 0x100F +#define E1000_DEV_ID_82545EM_FIBER 0x1011 +#define E1000_DEV_ID_82545GM_COPPER 0x1026 +#define E1000_DEV_ID_82545GM_FIBER 0x1027 +#define E1000_DEV_ID_82545GM_SERDES 0x1028 +#define E1000_DEV_ID_82546EB_COPPER 0x1010 +#define E1000_DEV_ID_82546EB_FIBER 0x1012 +#define E1000_DEV_ID_82546EB_QUAD_COPPER 0x101D +#define E1000_DEV_ID_82546GB_COPPER 0x1079 +#define E1000_DEV_ID_82546GB_FIBER 0x107A +#define E1000_DEV_ID_82546GB_SERDES 0x107B +#define E1000_DEV_ID_82546GB_PCIE 0x108A +#define E1000_DEV_ID_82546GB_QUAD_COPPER 0x1099 +#define E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3 0x10B5 +#define E1000_DEV_ID_82541EI 0x1013 +#define E1000_DEV_ID_82541EI_MOBILE 0x1018 +#define E1000_DEV_ID_82541ER_LOM 0x1014 +#define E1000_DEV_ID_82541ER 0x1078 +#define E1000_DEV_ID_82541GI 0x1076 +#define E1000_DEV_ID_82541GI_LF 0x107C +#define E1000_DEV_ID_82541GI_MOBILE 0x1077 +#define E1000_DEV_ID_82547EI 0x1019 +#define E1000_DEV_ID_82547EI_MOBILE 0x101A +#define E1000_DEV_ID_82547GI 0x1075 +#define E1000_DEV_ID_82571EB_COPPER 0x105E +#define E1000_DEV_ID_82571EB_FIBER 0x105F +#define E1000_DEV_ID_82571EB_SERDES 0x1060 +#define E1000_DEV_ID_82571EB_SERDES_DUAL 0x10D9 +#define E1000_DEV_ID_82571EB_SERDES_QUAD 0x10DA +#define E1000_DEV_ID_82571EB_QUAD_COPPER 0x10A4 +#define E1000_DEV_ID_82571PT_QUAD_COPPER 0x10D5 +#define E1000_DEV_ID_82571EB_QUAD_FIBER 0x10A5 +#define E1000_DEV_ID_82571EB_QUAD_COPPER_LP 0x10BC +#define E1000_DEV_ID_82572EI_COPPER 0x107D +#define E1000_DEV_ID_82572EI_FIBER 0x107E +#define E1000_DEV_ID_82572EI_SERDES 0x107F +#define E1000_DEV_ID_82572EI 0x10B9 +#define E1000_DEV_ID_82573E 0x108B +#define E1000_DEV_ID_82573E_IAMT 0x108C +#define E1000_DEV_ID_82573L 0x109A +#define E1000_DEV_ID_82574L 0x10D3 +#define E1000_DEV_ID_82574LA 0x10F6 +#define E1000_DEV_ID_82583V 0x150C +#define E1000_DEV_ID_80003ES2LAN_COPPER_DPT 0x1096 +#define E1000_DEV_ID_80003ES2LAN_SERDES_DPT 0x1098 +#define E1000_DEV_ID_80003ES2LAN_COPPER_SPT 0x10BA +#define E1000_DEV_ID_80003ES2LAN_SERDES_SPT 0x10BB +#define E1000_DEV_ID_ICH8_IGP_M_AMT 0x1049 +#define E1000_DEV_ID_ICH8_IGP_AMT 0x104A +#define E1000_DEV_ID_ICH8_IGP_C 0x104B +#define E1000_DEV_ID_ICH8_IFE 0x104C +#define E1000_DEV_ID_ICH8_IFE_GT 0x10C4 +#define E1000_DEV_ID_ICH8_IFE_G 0x10C5 +#define E1000_DEV_ID_ICH8_IGP_M 0x104D +#define E1000_DEV_ID_ICH9_IGP_M 0x10BF +#define E1000_DEV_ID_ICH9_IGP_M_AMT 0x10F5 +#define E1000_DEV_ID_ICH9_IGP_M_V 0x10CB +#define E1000_DEV_ID_ICH9_IGP_AMT 0x10BD +#define E1000_DEV_ID_ICH9_BM 0x10E5 +#define E1000_DEV_ID_ICH9_IGP_C 0x294C +#define E1000_DEV_ID_ICH9_IFE 0x10C0 +#define E1000_DEV_ID_ICH9_IFE_GT 0x10C3 +#define E1000_DEV_ID_ICH9_IFE_G 0x10C2 +#define E1000_DEV_ID_ICH10_R_BM_LM 0x10CC +#define E1000_DEV_ID_ICH10_R_BM_LF 0x10CD +#define E1000_DEV_ID_ICH10_R_BM_V 0x10CE +#define E1000_DEV_ID_ICH10_D_BM_LM 0x10DE +#define E1000_DEV_ID_ICH10_D_BM_LF 0x10DF +#define E1000_DEV_ID_PCH_M_HV_LM 0x10EA +#define E1000_DEV_ID_PCH_M_HV_LC 0x10EB +#define E1000_DEV_ID_PCH_D_HV_DM 0x10EF +#define E1000_DEV_ID_PCH_D_HV_DC 0x10F0 +#define E1000_DEV_ID_82576 0x10C9 +#define E1000_DEV_ID_82576_FIBER 0x10E6 +#define E1000_DEV_ID_82576_SERDES 0x10E7 +#define E1000_DEV_ID_82576_QUAD_COPPER 0x10E8 +#define E1000_DEV_ID_82576_NS 0x150A +#define E1000_DEV_ID_82576_SERDES_QUAD 0x150D +#define E1000_DEV_ID_82575EB_COPPER 0x10A7 +#define E1000_DEV_ID_82575EB_FIBER_SERDES 0x10A9 +#define E1000_DEV_ID_82575GB_QUAD_COPPER 0x10D6 +#define E1000_DEV_ID_82575GB_QUAD_COPPER_PM 0x10E2 + +/** + * @} + */ + +/** + * @name Revision Numbers. + * @{ + */ + +#define E1000_DEV_RID_82540 0x03 +#define E1000_DEV_RID_82541 0x05 + +/** + * @} + */ + +#endif /* __E1000_PCI_H */ diff --git a/drivers/e1000/e1000_reg.h b/drivers/e1000/e1000_reg.h new file mode 100644 index 000000000..bcaefd114 --- /dev/null +++ b/drivers/e1000/e1000_reg.h @@ -0,0 +1,310 @@ +/** + * @file e1000_reg.h + * + * @brief Hardware specific registers and flags of the Intel + * Pro/1000 Gigabit Ethernet card(s). + * + * Parts of this code is based on the DragonflyBSD (FreeBSD) + * implementation, and the fxp driver for Minix 3. + * + * @see http://svn.freebsd.org/viewvc/base/head/sys/dev/e1000/ + * @see fxp.c + * + * @author Niek Linnenbank + * @date September 2009 + * + */ + +#ifndef __E1000_REG_H +#define __E1000_REG_H + +/** + * @name Controller Registers. + * @{ + */ + +/** Device Control. */ +#define E1000_REG_CTRL 0x00000 + +/** Device Status. */ +#define E1000_REG_STATUS 0x00008 + +/** EEPROM Read. */ +#define E1000_REG_EERD 0x00014 + +/** Flow Control Address Low. */ +#define E1000_REG_FCAL 0x00028 + +/** Flow Control Address High. */ +#define E1000_REG_FCAH 0x0002c + +/** Flow Control Type. */ +#define E1000_REG_FCT 0x00030 + +/** Interrupt Cause Read. */ +#define E1000_REG_ICR 0x000c0 + +/** Interrupt Mask Set/Read Register. */ +#define E1000_REG_IMS 0x000d0 + +/** Receive Control Register. */ +#define E1000_REG_RCTL 0x00100 + +/** Transmit Control Register. */ +#define E1000_REG_TCTL 0x00400 + +/** Flow Control Transmit Timer Value. */ +#define E1000_REG_FCTTV 0x00170 + +/** Receive Descriptor Base Address Low. */ +#define E1000_REG_RDBAL 0x02800 + +/** Receive Descriptor Base Address High. */ +#define E1000_REG_RDBAH 0x02804 + +/** Receive Descriptor Length. */ +#define E1000_REG_RDLEN 0x02808 + +/** Receive Descriptor Head. */ +#define E1000_REG_RDH 0x02810 + +/** Receive Descriptor Tail. */ +#define E1000_REG_RDT 0x02818 + +/** Transmit Descriptor Base Address Low. */ +#define E1000_REG_TDBAL 0x03800 + +/** Transmit Descriptor Base Address High. */ +#define E1000_REG_TDBAH 0x03804 + +/** Transmit Descriptor Length. */ +#define E1000_REG_TDLEN 0x03808 + +/** Transmit Descriptor Head. */ +#define E1000_REG_TDH 0x03810 + +/** Transmit Descriptor Tail. */ +#define E1000_REG_TDT 0x03818 + +/** CRC Error Count. */ +#define E1000_REG_CRCERRS 0x04000 + +/** RX Error Count. */ +#define E1000_REG_RXERRC 0x0400c + +/** Missed Packets Count. */ +#define E1000_REG_MPC 0x04010 + +/** Collision Count. */ +#define E1000_REG_COLC 0x04028 + +/** Total Packets Received. */ +#define E1000_REG_TPR 0x040D0 + +/** Total Packets Transmitted. */ +#define E1000_REG_TPT 0x040D4 + +/** Receive Address Low. */ +#define E1000_REG_RAL 0x05400 + +/** Receive Address High. */ +#define E1000_REG_RAH 0x05404 + +/** Multicast Table Array. */ +#define E1000_REG_MTA 0x05200 + +/** + * @} + */ + +/** + * @name Control Register Bits. + * @{ + */ + +/** Auto-Speed Detection Enable. */ +#define E1000_REG_CTRL_ASDE (1 << 5) + +/** Link Reset. */ +#define E1000_REG_CTRL_LRST (1 << 3) + +/** Set Link Up. */ +#define E1000_REG_CTRL_SLU (1 << 6) + +/** Invert Los Of Signal. */ +#define E1000_REG_CTRL_ILOS (1 << 7) + +/** Device Reset. */ +#define E1000_REG_CTRL_RST (1 << 26) + +/** VLAN Mode Enable. */ +#define E1000_REG_CTRL_VME (1 << 30) + +/** PHY Reset. */ +#define E1000_REG_CTRL_PHY_RST (1 << 31) + +/** + * @} + */ + +/** + * @name Status Register Bits. + * @{ + */ + +/** Link Full Duplex Configuration Indication. */ +#define E1000_REG_STATUS_FD (1 << 0) + +/** Link Up Indication. */ +#define E1000_REG_STATUS_LU (1 << 1) + +/** Transmission Paused. */ +#define E1000_REG_STATUS_TXOFF (1 << 4) + +/** Link Speed Setting. */ +#define E1000_REG_STATUS_SPEED ((1 << 6) | (1 << 7)) + +/** + * @} + */ + +/** + * @name EEPROM Read Register Bits. + * @{ + */ + +/** Start Read. */ +#define E1000_REG_EERD_START (1 << 0) + +/** Read Done. */ +#define E1000_REG_EERD_DONE (1 << 4) + +/** Read Address Bit Mask. */ +#define E1000_REG_EERD_ADDR (0xff << 8) + +/** Read Data Bit Mask. */ +#define E1000_REG_EERD_DATA (0xffff << 16) + +/** + * @} + */ + +/** + * @name Interrupt Cause Read. + * @{ + */ + +/** Transmit Descripts Written Back. */ +#define E1000_REG_ICR_TXDW (1 << 0) + +/** Transmit Queue Empty. */ +#define E1000_REG_ICR_TXQE (1 << 1) + +/** Link Status Change. */ +#define E1000_REG_ICR_LSC (1 << 2) + +/** Receiver Overrun. */ +#define E1000_REG_ICR_RXO (1 << 6) + +/** Receiver Timer Interrupt. */ +#define E1000_REG_ICR_RXT (1 << 7) + +/** + * @} + */ + +/** + * @name Interrupt Mask Set/Read Register Bits. + * @{ + */ + +/** Transmit Descripts Written Back. */ +#define E1000_REG_IMS_TXDW (1 << 0) + +/** Transmit Queue Empty. */ +#define E1000_REG_IMS_TXQE (1 << 1) + +/** Link Status Change. */ +#define E1000_REG_IMS_LSC (1 << 2) + +/** Receiver FIFO Overrun. */ +#define E1000_REG_IMS_RXO (1 << 6) + +/** Receiver Timer Interrupt. */ +#define E1000_REG_IMS_RXT (1 << 7) + +/** + * @} + */ + +/** + * @name Receive Control Register Bits. + * @{ + */ + +/** Receive Enable. */ +#define E1000_REG_RCTL_EN (1 << 1) + +/** Multicast Promiscious Enable. */ +#define E1000_REG_RCTL_MPE (1 << 4) + +/** Broadcast Accept Mode. */ +#define E1000_REG_RCTL_BAM (1 << 15) + +/** Receive Buffer Size. */ +#define E1000_REG_RCTL_BSIZE ((1 << 16) | (1 << 17)) + +/** + * @} + */ + +/** + * @name Transmit Control Register Bits. + * @{ + */ + +/** Transmit Enable. */ +#define E1000_REG_TCTL_EN (1 << 1) + +/** Pad Short Packets. */ +#define E1000_REG_TCTL_PSP (1 << 3) + +/** + * @} + */ + +/** + * @name Receive Address High Register Bits. + * @{ + */ + +/** Receive Address Valid. */ +#define E1000_REG_RAH_AV (1 << 31) + +/** + * @} + */ + +/** + * @name ICH Flash Registers. + * @see http://gitweb.dragonflybsd.org + * @{ + */ + +#define ICH_FLASH_GFPREG 0x0000 +#define ICH_FLASH_HSFSTS 0x0004 +#define ICH_FLASH_HSFCTL 0x0006 +#define ICH_FLASH_FADDR 0x0008 +#define ICH_FLASH_FDATA0 0x0010 +#define FLASH_GFPREG_BASE_MASK 0x1FFF +#define FLASH_SECTOR_ADDR_SHIFT 12 +#define ICH_FLASH_READ_COMMAND_TIMEOUT 500 +#define ICH_FLASH_LINEAR_ADDR_MASK 0x00FFFFFF +#define ICH_CYCLE_READ 0 +#define ICH_FLASH_CYCLE_REPEAT_COUNT 10 + +/** + * @} + */ + +#endif /* __E1000_REG_H */ diff --git a/drivers/pci/pci_table.c b/drivers/pci/pci_table.c index 3c401bab9..a49f16f6f 100644 --- a/drivers/pci/pci_table.c +++ b/drivers/pci/pci_table.c @@ -129,10 +129,13 @@ struct pci_device pci_device_table[]= { 0x5333, 0x88d0, "S3 Vision 964 vers 0" }, { 0x5333, 0x8a01, "S3 Virge/DX or /GX" }, { 0x8086, 0x1004, "Intel 82543GC Gigabit Ethernet Controller" }, + { 0x8086, 0x100E, "Intel PRO/1000 MT Desktop Adapter" }, { 0x8086, 0x1029, "Intel EtherExpressPro100 ID1029" }, { 0x8086, 0x1030, "Intel Corporation 82559 InBusiness 10/100" }, { 0x8086, 0x103d, "Intel Corporation 82801DB PRO/100 VE (MOB)" }, { 0x8086, 0x1064, "Intel Corporation 82562 PRO/100 VE" }, + { 0x8086, 0x107C, "Intel PRO/1000 GT Desktop Adapter" }, + { 0x8086, 0x10CD, "Intel PRO/1000 Gigabit Network Connection" }, { 0x8086, 0x1209, "Intel EtherExpressPro100 82559ER" }, { 0x8086, 0x1229, "Intel EtherExpressPro100 82557/8/9" }, { 0x8086, 0x122D, "Intel 82437FX" }, diff --git a/etc/drivers.conf b/etc/drivers.conf index d886cae7b..e8a2ba0a4 100644 --- a/etc/drivers.conf +++ b/etc/drivers.conf @@ -517,3 +517,25 @@ driver filter bios_wini ; }; + +driver e1000 +{ + system + UMAP # 14 + IRQCTL # 19 + DEVIO # 21 + SETALARM # 24 + TIMES # 25 + GETINFO # 26 + SAFECOPYFROM # 31 + SAFECOPYTO # 32 + SETGRANT # 34 + SYSCTL + ; + pci device 8086/100e; + pci device 8086/107c; + pci device 8086/10cd; + ipc + SYSTEM PM RS LOG TTY DS VM + pci inet ; +}; diff --git a/etc/usr/rc b/etc/usr/rc index 0430f46e5..295fe7ef0 100644 --- a/etc/usr/rc +++ b/etc/usr/rc @@ -91,7 +91,7 @@ start) fi # start only network drivers that are in use - for driver in lance rtl8139 rtl8169 fxp dpeth dp8390 orinoco + for driver in lance rtl8139 rtl8169 fxp e1000 dpeth dp8390 orinoco do if grep " $driver " /etc/inet.conf > /dev/null 2>&1 then