From 947d77c775c04b2b6edb9bd532e899df5611f31b Mon Sep 17 00:00:00 2001 From: Stefan Lankes Date: Thu, 26 Jul 2012 09:11:46 +0200 Subject: [PATCH] add first version of the network driver for Intel's E1000 NIC --- drivers/net/Makefile | 2 +- drivers/net/e1000.c | 536 +++++++++++++++++++++++++++++++++++++++++++ drivers/net/e1000.h | 259 +++++++++++++++++++++ 3 files changed, 796 insertions(+), 1 deletion(-) create mode 100644 drivers/net/e1000.c create mode 100644 drivers/net/e1000.h diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 0c5c9997..ffe7312f 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -1,4 +1,4 @@ -C_source := rtl8139.c rckemac.c mmnif.c util.c +C_source := e1000.c rtl8139.c rckemac.c mmnif.c util.c MODULE := drivers_net include $(TOPDIR)/Makefile.inc diff --git a/drivers/net/e1000.c b/drivers/net/e1000.c new file mode 100644 index 00000000..c7439828 --- /dev/null +++ b/drivers/net/e1000.c @@ -0,0 +1,536 @@ +/* + * Copyright 2012 Stefan Lankes, Chair for Operating Systems, + * RWTH Aachen University + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of MetalSVM. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#if defined(CONFIG_LWIP) && defined(CONFIG_PCI) +#include +#include +#include +#include +#include +#include +#include + +#define RX_BUF_LEN (8192+16) +#define TX_BUF_LEN (1792+16) + +#define INT_MASK (E1000_IMS_RXO|E1000_IMS_RXT0|E1000_IMS_RXDMT0|E1000_IMS_RXSEQ|E1000_IMS_LSC) +#define INT_MASK_NO_RXT0 (E1000_IMS_RXO|E1000_IMS_RXDMT0|E1000_IMS_RXSEQ|E1000_IMS_LSC) + +typedef struct { + char *vendor_str; + char *device_str; + uint32_t vendor; + uint32_t device; +} board_t; + +static board_t board_tbl[] = +{ + {"Intel", "Intel E1000 (82542)", 0x8086, 0x1000}, + {"Intel", "Intel E1000 (82543GC FIBER)", 0x8086, 0x1001}, + {"Intel", "Intel E1000 (82543GC COPPER)", 0x8086, 0x1004}, + {"Intel", "Intel E1000 (82544EI COPPER)", 0x8086, 0x1008}, + {"Intel", "Intel E1000 (82544EI FIBER)", 0x8086, 0x1009}, + {"Intel", "Intel E1000 (82544GC COPPER)", 0x8086, 0x100C}, + {"Intel", "Intel E1000 (82544GC LOM)", 0x8086, 0x100D}, + {"Intel", "Intel E1000 (82540EM)", 0x8086, 0x100E}, + {"Intel", "Intel E1000 (82540EM LOM)", 0x8086, 0x1015}, + {"Intel", "Intel E1000 (82540EP LOM)", 0x8086, 0x1016}, + {"Intel", "Intel E1000 (82540EP)", 0x8086, 0x1017}, + {"Intel", "Intel E1000 (82540EP LP)", 0x8086, 0x101E}, + {"Intel", "Intel E1000 (82545EM COPPER)", 0x8086, 0x100F}, + {"Intel", "Intel E1000 (82545EM FIBER)", 0x8086, 0x1011}, + {"Intel", "Intel E1000 (82545GM COPPER)", 0x8086, 0x1026}, + {"Intel", "Intel E1000 (82545GM FIBER)", 0x8086, 0x1027}, + {"Intel", "Intel E1000 (82545GM SERDES)", 0x8086, 0x1028}, + {"Intel", "Intel E1000 (82546EB COPPER)", 0x8086, 0x1010}, + {"Intel", "Intel E1000 (82546EB FIBER)", 0x8086, 0x1012}, + {"Intel", "Intel E1000 (82546EB QUAD COPPER)", 0x8086, 0x101D}, + {"Intel", "Intel E1000 (82541EI)", 0x8086, 0x1013}, + {"Intel", "Intel E1000 (82541EI MOBILE)", 0x8086, 0x1018}, + {"Intel", "Intel E1000 (82541ER LOM)", 0x8086, 0x1014}, + {"Intel", "Intel E1000 (82541ER)", 0x8086, 0x1078}, + {"Intel", "Intel E1000 (82547GI)", 0x8086, 0x1075}, + {"Intel", "Intel E1000 (82541GI)", 0x8086, 0x1076}, + {"Intel", "Intel E1000 (82541GI MOBILE)", 0x8086, 0x1077}, + {"Intel", "Intel E1000 (82541GI LF)", 0x8086, 0x107C}, + {"Intel", "Intel E1000 (82546GB COPPER)", 0x8086, 0x1079}, + {"Intel", "Intel E1000 (82546GB FIBER)", 0x8086, 0x107A}, + {"Intel", "Intel E1000 (82546GB SERDES)", 0x8086, 0x107B}, + {"Intel", "Intel E1000 (82546GB PCIE)", 0x8086, 0x108A}, + {"Intel", "Intel E1000 (82546GB QUAD COPPER)", 0x8086, 0x1099}, + {"Intel", "Intel E1000 (82547EI)", 0x8086, 0x1019}, + {"Intel", "Intel E1000 (82547EI_MOBILE)", 0x8086, 0x101A}, + {"Intel", "Intel E1000 (82546GB QUAD COPPER KSP3)", 0x8086, 0x10B5}, + {NULL,}, +}; + +static struct netif* mynetif = NULL; + +static inline uint32_t e1000_read(uint8_t* base, uint32_t off) +{ + return *((volatile uint32_t*) (base+off)); +} + +static inline void e1000_write(uint8_t* base, uint32_t off, uint32_t value) +{ + *((volatile uint32_t*) (base+off)) = value; +} + +#if 1 +static uint16_t eeprom_read(uint8_t* base, uint8_t addr) +{ + uint16_t data; + uint32_t tmp; + + e1000_write(base, E1000_EERD, 1 | ((uint32_t)(addr) << 8)); + + while(!((tmp = e1000_read(base, E1000_EERD)) & (1 << 4))) + udelay(1); + + data = (uint16_t)((tmp >> 16) & 0xFFFF); + + return data; +} +#else +// Only for 82541xx and 82547GI/EI +static uint16_t eeprom_read(uint8_t* base, uint8_t addr) +{ + uint16_t data; + uint32_t tmp; + + e1000_write(base, E1000_EERD, 1 | ((uint32_t)(addr) << 2)); + + while(!((tmp = e1000_read(base, E1000_EERD)) & (1 << 1))) + udelay(1); + + data = (uint16_t)((tmp >> 16) & 0xFFFF); + + return data; +} +#endif + +/* + * @return error code + * - ERR_OK: packet transferred to hardware + * - ERR_CONN: no link or link failure + * - ERR_IF: could not transfer to link (hardware buffer full?) + */ +static err_t e1000if_output(struct netif* netif, struct pbuf* p) +{ + e1000if_t* e1000if = netif->state; + uint32_t i; + struct pbuf *q; + + if (BUILTIN_EXPECT((p->tot_len > 1792) || (p->tot_len > TX_BUF_LEN), 0)) { + LWIP_DEBUGF(NETIF_DEBUG, ("e1000if_output: packet is longer than 1792 bytes\n")); + return ERR_IF; + } + + if (!(e1000if->tx_desc[e1000if->tx_tail].status & 0xF)) { + LWIP_DEBUGF(NETIF_DEBUG, ("e1000if_output: %i already inuse\n", e1000if->tx_tail)); + return ERR_IF; + } + +#if ETH_PAD_SIZE + pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */ +#endif + + /* + * q traverses through linked list of pbuf's + * This list MUST consist of a single packet ONLY + */ + for (q = p, i = 0; q != 0; q = q->next) { + memcpy((void*) ((size_t) e1000if->tx_buffers + e1000if->tx_tail*TX_BUF_LEN + i), q->payload, q->len); + i += q->len; + } + + e1000if->tx_desc[e1000if->tx_tail].length = p->tot_len; + e1000if->tx_desc[e1000if->tx_tail].status = 0; + e1000if->tx_desc[e1000if->tx_tail].cmd = (1 << 3) | 3; + + // update the tail so the hardware knows it's ready + e1000if->tx_tail = (e1000if->tx_tail + 1) % NUM_TX_DESCRIPTORS; + e1000_write(e1000if->bar0, E1000_TDT, e1000if->tx_tail); + +#if ETH_PAD_SIZE + pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */ +#endif + + LINK_STATS_INC(link.xmit); + + return ERR_OK; +} + +static void e1000if_input(struct netif* netif, struct pbuf* p) +{ + struct eth_hdr *ethhdr; + err_t err; + + /* points to packet payload, which starts with an Ethernet header */ + ethhdr = p->payload; + + switch (htons(ethhdr->type)) { + /* IP or ARP packet? */ + case ETHTYPE_ARP: + case ETHTYPE_IP: +#if PPPOE_SUPPORT + /* PPPoE packet? */ + case ETHTYPE_PPPOEDISC: + case ETHTYPE_PPPOE: +#endif /* PPPOE_SUPPORT */ + /* + * This function is called in the context of the tcpip thread. + * Therefore, we are able to call directly the input functions. + */ + err = ethernet_input(p, netif); + if (err != ERR_OK) { + LWIP_DEBUGF(NETIF_DEBUG, ("e1000if_input: ethernet_input failed %d\n", err)); + } + break; + default: + LWIP_DEBUGF(NETIF_DEBUG, ("e1000if_input: invalid ethernet header 0x%x\n", htons(ethhdr->type))); + pbuf_free(p); + break; + } +} + +static void e1000_rx_inthandler(struct netif* netif) +{ + e1000if_t* e1000if = netif->state; + struct pbuf *p = NULL; + struct pbuf* q; + uint16_t length, i; + + while(e1000if->rx_desc[e1000if->rx_tail].status & (1 << 0)) + { + if (!(e1000if->rx_desc[e1000if->rx_tail].status & (1 << 1))) { + LINK_STATS_INC(link.drop); + goto no_eop; // currently, we ignore packets without EOP flag + } + + length = e1000if->rx_desc[e1000if->rx_tail].length; + + if (!e1000if->rx_desc[e1000if->rx_tail].errors) { +#if ETH_PAD_SIZE + length += ETH_PAD_SIZE; /* allow room for Ethernet padding */ +#endif + + p = pbuf_alloc(PBUF_RAW, length, PBUF_POOL); + if (p) { +#if ETH_PAD_SIZE + pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */ +#endif + for (q=p, i=0; q!=NULL; q=q->next) { + memcpy((uint8_t*) q->payload, (void*) ((size_t) e1000if->rx_buffers + e1000if->rx_tail*RX_BUF_LEN + i), q->len); + i += q->len; + } +#if ETH_PAD_SIZE + pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */ +#endif + LINK_STATS_INC(link.recv); + + // forward packet to LwIP + e1000if_input(netif, p); + } else { + LWIP_DEBUGF(NETIF_DEBUG, ("e1000if_rx_inthandler: not enough memory!\n")); + LINK_STATS_INC(link.memerr); + LINK_STATS_INC(link.drop); + } + } else { + LWIP_DEBUGF(NETIF_DEBUG, ("e1000if_rx_inthandler: RX errors (0x%x)\n", e1000if->rx_desc[e1000if->rx_tail].errors)); + LINK_STATS_INC(link.memerr); + LINK_STATS_INC(link.drop); + break; + } + +no_eop: + e1000if->rx_desc[e1000if->rx_tail].status = 0; + + // update tail and write the value to the device + e1000if->rx_tail = (e1000if->rx_tail + 1) % NUM_RX_DESCRIPTORS; + e1000_write(e1000if->bar0, E1000_RDT, e1000if->rx_tail); + } + + e1000if->polling = 0; + // enable all known interrupts + e1000_write(e1000if->bar0, E1000_IMS, INT_MASK); +} + +/* this function is called in the context of the tcpip thread or the irq handler (by using NO_SYS) */ +static void e1000if_poll(void* ctx) +{ + e1000_rx_inthandler(mynetif); +} + +static void e1000if_handler(struct state* s) +{ + e1000if_t* e1000if = mynetif->state; + uint32_t icr; + + // disable all interrupts + e1000_write(e1000if->bar0, E1000_IMS, 0); + + // read the pending interrupt status + icr = e1000_read(e1000if->bar0, E1000_ICR); + + kprintf("INT icr %u\n", icr); + + // ignore tx success stuff + icr &= ~3; + + // LINK STATUS CHANGE + if (icr & E1000_ICR_LSC) + { + icr &= ~E1000_ICR_LSC; + LWIP_DEBUGF(NETIF_DEBUG, ("e1000if: Link status change (TODO)\n")); + } + + if (icr & (E1000_ICR_RXT0|E1000_ICR_RXDMT0|E1000_ICR_RXO)) { + icr &= ~(E1000_ICR_RXT0|E1000_ICR_RXDMT0|E1000_ICR_RXO); + + if (!e1000if->polling) { +#if NO_SYS + e1000if_poll(NULL); +#else + if (tcpip_callback_with_block(e1000if_poll, NULL, 0) == ERR_OK) { + e1000if->polling = 1; + } else { + LWIP_DEBUGF(NETIF_DEBUG, ("e1000if_handler: unable to send a poll request to the tcpip thread\n")); + } +#endif + } + } + + if (e1000if->polling) // now, the tcpip thread will check for incoming messages + e1000_write(e1000if->bar0, E1000_IMS, INT_MASK_NO_RXT0); + else + e1000_write(e1000if->bar0, E1000_IMS, INT_MASK); // enable interrupts + + if (icr & 0x1FFFF) { + LWIP_DEBUGF(NETIF_DEBUG, ("e1000if_handler: unhandled interrupt #%u received! (0x%x)\n", e1000if->irq, icr)); + } +} + +err_t e1000if_init(struct netif* netif) +{ + pci_info_t pci_info; + e1000if_t* e1000if; + uint32_t tmp32; + uint16_t tmp16, speed; + uint8_t tmp8, is64bit, mem_type, prefetch; + static uint8_t num = 0; + + LWIP_ASSERT("netif != NULL", (netif != NULL)); + + tmp8 = 0; + while (board_tbl[tmp8].vendor_str) { + if (pci_get_device_info(board_tbl[tmp8].vendor, board_tbl[tmp8].device, &pci_info) == 0) + break; + tmp8++; + } + + if (!board_tbl[tmp8].vendor_str) + return ERR_ARG; + + mem_type = pci_info.base[0] & 0x1; + is64bit = pci_info.base[0] & 0x6 ? 1 : 0; + prefetch = pci_info.base[0] & 0x8 ? 1 : 0; + + if (mem_type) { + LWIP_DEBUGF(NETIF_DEBUG, ("e1000if_init: IO space is currently not supported!\n")); + return ERR_ARG; + } + + e1000if = kmalloc(sizeof(e1000if_t)); + if (!e1000if) { + LWIP_DEBUGF(NETIF_DEBUG, ("e1000if_init: out of memory\n")); + return ERR_MEM; + } + memset(e1000if, 0x00, sizeof(e1000if_t)); + + netif->state = e1000if; + mynetif = netif; + + e1000if->bar0 = (uint8_t*) map_region(0, pci_info.base[0] & ~0xF, pci_info.size[0], MAP_KERNEL_SPACE|MAP_NO_CACHE); + + // reset device + e1000_write(e1000if->bar0, E1000_CTRL, E1000_CTRL_RST); + + e1000if->irq = pci_info.irq; + e1000if->rx_desc = mem_allocation(NUM_RX_DESCRIPTORS*sizeof(rx_desc_t), MAP_KERNEL_SPACE|MAP_NO_CACHE); + memset((void*) e1000if->rx_desc, 0x00, NUM_RX_DESCRIPTORS*sizeof(rx_desc_t)); + e1000if->tx_desc = mem_allocation(NUM_TX_DESCRIPTORS*sizeof(tx_desc_t), MAP_KERNEL_SPACE|MAP_NO_CACHE); + memset((void*) e1000if->tx_desc, 0x00, NUM_TX_DESCRIPTORS*sizeof(tx_desc_t)); + + LWIP_DEBUGF(NETIF_DEBUG, ("e1000if_init: Found %s at iobase 0x%x (size 0x%x), irq %u\n", board_tbl[tmp8].device_str, + pci_info.base[0] & ~0xF, pci_info.size[0], e1000if->irq)); + //LWIP_DEBUGF(NETIF_DEBUG, ("e1000if_init: Map iobase to %p\n", e1000if->bar0)); + LWIP_DEBUGF(NETIF_DEBUG, ("e1000if_init: is64bit %u, prefetch %u\n", is64bit, prefetch)); + + // determine the mac address of this card + for (tmp8=0; tmp8<6; tmp8+=2) { + tmp16 = eeprom_read(e1000if->bar0, tmp8 / 2); + mynetif->hwaddr[tmp8] = (tmp16 & 0xFF); + mynetif->hwaddr[tmp8+1] = (tmp16 >> 8) & 0xFF; + } + + e1000if->tx_buffers = mem_allocation(NUM_TX_DESCRIPTORS*TX_BUF_LEN, MAP_KERNEL_SPACE|MAP_NO_CACHE); + memset((void*) e1000if->tx_buffers, 0x00, NUM_TX_DESCRIPTORS*TX_BUF_LEN); + for(tmp32=0; tmp32 < NUM_TX_DESCRIPTORS; tmp32++) { + e1000if->tx_desc[tmp32].addr = virt_to_phys((size_t)e1000if->tx_buffers + tmp32*TX_BUF_LEN); + e1000if->tx_desc[tmp32].status = 1; + } + + //LWIP_DEBUGF(NETIF_DEBUG, ("e1000if_init: add TX ring buffer %p (viraddr %p)\n", virt_to_phys((size_t)e1000if->tx_desc), e1000if->tx_desc)); + + // setup the transmit descriptor ring buffer + e1000_write(e1000if->bar0, E1000_TDBAL, (uint32_t)((uint64_t)virt_to_phys((size_t)e1000if->tx_desc) & 0xFFFFFFFF)); + e1000_write(e1000if->bar0, E1000_TDBAH, (uint32_t)((uint64_t)virt_to_phys((size_t)e1000if->tx_desc) >> 32)); + //LWIP_DEBUGF(NETIF_DEBUG, ("e1000if_init: TDBAH/TDBAL = 0x%x:0x%x\n", e1000_read(e1000if->bar0, E1000_TDBAH), e1000_read(e1000if->bar0, E1000_TDBAL))); + + // transmit buffer length; NUM_TX_DESCRIPTORS 16-byte descriptors + e1000_write(e1000if->bar0, E1000_TDLEN , (uint32_t)(NUM_TX_DESCRIPTORS * sizeof(tx_desc_t))); + + // setup head and tail pointers + e1000_write(e1000if->bar0, E1000_TDH, 0); + e1000_write(e1000if->bar0, E1000_TDT, 0); + e1000if->tx_tail = 0; + + // set the transmit control register (padshortpackets) + e1000_write(e1000if->bar0, E1000_TCTL, (E1000_TCTL_EN | E1000_TCTL_PSP | (0x40 << 12) | (0x10 << 4))); + + // set IEEE 802.3 standard IPG value + e1000_write(e1000if->bar0, E1000_TIPG, (6 << 20) | (8 << 10) | 10); + +#if 1 + LWIP_DEBUGF(NETIF_DEBUG, ("e1000if_init: MAC address ")); + for(tmp8=0; tmp8<6; tmp8++) { + LWIP_DEBUGF(NETIF_DEBUG, ("%02x ", mynetif->hwaddr[tmp8])); + } + LWIP_DEBUGF(NETIF_DEBUG, ("\n")); +#else + // set MAC address + for(tmp8=0; tmp8<4; tmp8++) + ((uint8_t*) &tmp32)[tmp8] = mynetif->hwaddr[tmp8]; + e1000_write(e1000if->bar0, E1000_RA, tmp32); + tmp32 = 0; + for(tmp8=0; tmp8<2; tmp8++) + ((uint8_t*) &tmp32)[tmp8] = mynetif->hwaddr[tmp8+4]; + e1000_write(e1000if->bar0, E1000_RA+4, tmp32 | (1 << 31)); // set also AV bit to check incoming packets + + LWIP_DEBUGF(NETIF_DEBUG, ("e1000if_init: MAC address ")); + tmp32 = e1000_read(e1000if->bar0, E1000_RA); + for(tmp8=0; tmp8<4; tmp8++) { + LWIP_DEBUGF(NETIF_DEBUG, ("%02x ", ((uint8_t*) &tmp32)[tmp8])); + } + tmp32 = e1000_read(e1000if->bar0, E1000_RA+4); + for(tmp8=0; tmp8<2; tmp8++) { + LWIP_DEBUGF(NETIF_DEBUG, ("%02x ", ((uint8_t*) &tmp32)[tmp8])); + } + LWIP_DEBUGF(NETIF_DEBUG, ("\n")); +#endif + + // set multicast table to 0 + for(tmp8=0; tmp8<128; tmp8++ ) + e1000_write(e1000if->bar0, E1000_MTA + (tmp8 * 4), 0); + + // set IRQ handler + irq_install_handler(e1000if->irq+32, e1000if_handler); + + // enable all interrupts (and clear existing pending ones) + e1000_write(e1000if->bar0, E1000_IMS, INT_MASK); + e1000_read(e1000if->bar0, E1000_ICR); + + //LWIP_DEBUGF(NETIF_DEBUG, ("e1000if_init: add RX ring buffer %p (viraddr %p)\n", virt_to_phys((size_t)e1000if->rx_desc), e1000if->rx_desc)); + + e1000if->rx_buffers = mem_allocation(NUM_RX_DESCRIPTORS*RX_BUF_LEN, MAP_KERNEL_SPACE|MAP_NO_CACHE); + memset(e1000if->rx_buffers, 0x00, NUM_RX_DESCRIPTORS*RX_BUF_LEN); + for(tmp32=0; tmp32 < NUM_RX_DESCRIPTORS; tmp32++) + e1000if->rx_desc[tmp32].addr = virt_to_phys((size_t)e1000if->rx_buffers + tmp32*RX_BUF_LEN); + + // setup the receive descriptor ring buffer + e1000_write(e1000if->bar0, E1000_RDBAH, (uint32_t)((uint64_t)virt_to_phys((size_t)e1000if->rx_desc) >> 32)); + e1000_write(e1000if->bar0, E1000_RDBAL, (uint32_t)((uint64_t)virt_to_phys((size_t)e1000if->rx_desc) & 0xFFFFFFFF)); + + // receive buffer length; NUM_RX_DESCRIPTORS 16-byte descriptors + e1000_write(e1000if->bar0, E1000_RDLEN , (uint32_t)(NUM_RX_DESCRIPTORS * sizeof(rx_desc_t))); + + // setup head and tail pointers + e1000_write(e1000if->bar0, E1000_RDH, 0); + e1000_write(e1000if->bar0, E1000_RDT, 0); + e1000if->rx_tail = 0; + + // set the receieve control register +#if 1 + e1000_write(e1000if->bar0, E1000_RCTL, (E1000_RCTL_EN|E1000_RCTL_LPE|E1000_RCTL_BAM|E1000_RCTL_SZ_8192|E1000_RCTL_BSEX| + E1000_RCTL_SECRC|E1000_RCTL_RDMTS_HALF|E1000_RCTL_MO_0|E1000_RCTL_UPE|E1000_RCTL_MPE)); +#else + e1000_write(e1000if->bar0, E1000_RCTL, (E1000_RCTL_EN|E1000_RCTL_LPE|E1000_RCTL_BAM|E1000_RCTL_SZ_8192|E1000_RCTL_BSEX| + E1000_RCTL_SECRC|E1000_RCTL_RDMTS_HALF|E1000_RCTL_MO_0)); +#endif + + // set the LINK UP + e1000_write(e1000if->bar0, E1000_CTRL, (e1000_read(e1000if->bar0, E1000_CTRL) | E1000_CTRL_SLU)); + + tmp32 = e1000_read(e1000if->bar0, E1000_CTRL); + if (tmp32 & E1000_CTRL_SPD_1000) + speed = 1000; + else if (tmp32 & E1000_CTRL_SPD_100) + speed = 100; + else + speed = 10; + + LWIP_DEBUGF(NETIF_DEBUG, ("e1000if_init: speed = %u mbps\n", speed)); + + /* + * Initialize the snmp variables and counters inside the struct netif. + * The last argument should be replaced with your link speed, in units + * of bits per second. + */ + NETIF_INIT_SNMP(netif, snmp_ifType_ethernet_csmacd, speed); + + /* administrative details */ + netif->name[0] = 'e'; + netif->name[1] = 'n'; + netif->num = num; + num++; + /* downward functions */ + netif->output = etharp_output; + netif->linkoutput = e1000if_output; + /* maximum transfer unit */ + netif->mtu = 1500; + /* broadcast capability */ + netif->flags |= NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_IGMP; + /* hardware address length */ + netif->hwaddr_len = 6; + + e1000if->ethaddr = (struct eth_addr *)netif->hwaddr; + + return ERR_OK; +} +#endif diff --git a/drivers/net/e1000.h b/drivers/net/e1000.h new file mode 100644 index 00000000..154ef19e --- /dev/null +++ b/drivers/net/e1000.h @@ -0,0 +1,259 @@ +/* + * Copyright 2012 Stefan Lankes, Chair for Operating Systems, + * RWTH Aachen University + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of MetalSVM. + * + */ + +#ifndef __HAVE_E1000_H__ +#define __HAVE_E1000_H__ + +#include +#include + +#if defined(CONFIG_LWIP) && defined(CONFIG_PCI) + + +#define NUM_RX_DESCRIPTORS 64 +#define NUM_TX_DESCRIPTORS 64 + +#define E1000_CTRL 0x00000 /* Device Control - RW */ +#define E1000_CTRL_DUP 0x00004 /* Device Control Duplicate (Shadow) - RW */ +#define E1000_STATUS 0x00008 /* Device Status - RO */ +#define E1000_EECD 0x00010 /* EEPROM/Flash Control - RW */ +#define E1000_EERD 0x00014 /* EEPROM Read - RW */ +#define E1000_ICR 0x000C0 /* Interrupt Cause Read - R/clr */ +#define E1000_ITR 0x000C4 /* Interrupt Throttling Rate - RW */ +#define E1000_ICS 0x000C8 /* Interrupt Cause Set - WO */ +#define E1000_IMS 0x000D0 /* Interrupt Mask Set - RW */ +#define E1000_IMC 0x000D8 /* Interrupt Mask Clear - WO */ +#define E1000_IAM 0x000E0 /* Interrupt Acknowledge Auto Mask */ +#define E1000_RCTL 0x00100 /* RX Control - RW */ +#define E1000_TCTL 0x00400 /* TX Control - RW */ +#define E1000_TIPG 0x00410 /* TX Inter-packet gap -RW */ +#define E1000_RDBAL 0x02800 /* RX Descriptor Base Address Low - RW */ +#define E1000_RDBAH 0x02804 /* RX Descriptor Base Address High - RW */ +#define E1000_RDLEN 0x02808 /* RX Descriptor Length - RW */ +#define E1000_RDH 0x02810 /* RX Descriptor Head - RW */ +#define E1000_RDT 0x02818 /* RX Descriptor Tail - RW */ +#define E1000_TDBAL 0x03800 /* TX Descriptor Base Address Low - RW */ +#define E1000_TDBAH 0x03804 /* TX Descriptor Base Address High - RW */ +#define E1000_TDLEN 0x03808 /* TX Descriptor Length - RW */ +#define E1000_TDH 0x03810 /* TX Descriptor Head - RW */ +#define E1000_TDT 0x03818 /* TX Descripotr Tail - RW */ +#define E1000_MTA 0x05200 /* Multicast Table Array - RW Array */ +#define E1000_RA 0x05400 /* Receive Address - RW Array */ + +/* Device Control */ +#define E1000_CTRL_FD 0x00000001 /* Full duplex.0=half; 1=full */ +#define E1000_CTRL_BEM 0x00000002 /* Endian Mode.0=little,1=big */ +#define E1000_CTRL_PRIOR 0x00000004 /* Priority on PCI. 0=rx,1=fair */ +#define E1000_CTRL_GIO_MASTER_DISABLE 0x00000004 /*Blocks new Master requests */ +#define E1000_CTRL_LRST 0x00000008 /* Link reset. 0=normal,1=reset */ +#define E1000_CTRL_TME 0x00000010 /* Test mode. 0=normal,1=test */ +#define E1000_CTRL_SLE 0x00000020 /* Serial Link on 0=dis,1=en */ +#define E1000_CTRL_ASDE 0x00000020 /* Auto-speed detect enable */ +#define E1000_CTRL_SLU 0x00000040 /* Set link up (Force Link) */ +#define E1000_CTRL_ILOS 0x00000080 /* Invert Loss-Of Signal */ +#define E1000_CTRL_SPD_SEL 0x00000300 /* Speed Select Mask */ +#define E1000_CTRL_SPD_10 0x00000000 /* Force 10Mb */ +#define E1000_CTRL_SPD_100 0x00000100 /* Force 100Mb */ +#define E1000_CTRL_SPD_1000 0x00000200 /* Force 1Gb */ +#define E1000_CTRL_BEM32 0x00000400 /* Big Endian 32 mode */ +#define E1000_CTRL_FRCSPD 0x00000800 /* Force Speed */ +#define E1000_CTRL_FRCDPX 0x00001000 /* Force Duplex */ +#define E1000_CTRL_D_UD_EN 0x00002000 /* Dock/Undock enable */ +#define E1000_CTRL_D_UD_POLARITY 0x00004000 /* Defined polarity of Dock/Undock indication in SDP[0] */ +#define E1000_CTRL_FORCE_PHY_RESET 0x00008000 /* Reset both PHY ports, through PHYRST_N pin */ +#define E1000_CTRL_EXT_LINK_EN 0x00010000 /* enable link status from external LINK_0 and LINK_1 pins */ +#define E1000_CTRL_SWDPIN0 0x00040000 /* SWDPIN 0 value */ +#define E1000_CTRL_SWDPIN1 0x00080000 /* SWDPIN 1 value */ +#define E1000_CTRL_SWDPIN2 0x00100000 /* SWDPIN 2 value */ +#define E1000_CTRL_SWDPIN3 0x00200000 /* SWDPIN 3 value */ +#define E1000_CTRL_SWDPIO0 0x00400000 /* SWDPIN 0 Input or output */ +#define E1000_CTRL_SWDPIO1 0x00800000 /* SWDPIN 1 input or output */ +#define E1000_CTRL_SWDPIO2 0x01000000 /* SWDPIN 2 input or output */ +#define E1000_CTRL_SWDPIO3 0x02000000 /* SWDPIN 3 input or output */ +#define E1000_CTRL_RST 0x04000000 /* Global reset */ +#define E1000_CTRL_RFCE 0x08000000 /* Receive Flow Control enable */ +#define E1000_CTRL_TFCE 0x10000000 /* Transmit flow control enable */ +#define E1000_CTRL_RTE 0x20000000 /* Routing tag enable */ +#define E1000_CTRL_VME 0x40000000 /* IEEE VLAN mode enable */ +#define E1000_CTRL_PHY_RST 0x80000000 /* PHY Reset */ +#define E1000_CTRL_SW2FW_INT 0x02000000 /* Initiate an interrupt to manageability engine */ + +/* Transmit Control */ +#define E1000_TCTL_RST 0x00000001 /* software reset */ +#define E1000_TCTL_EN 0x00000002 /* enable tx */ +#define E1000_TCTL_BCE 0x00000004 /* busy check enable */ +#define E1000_TCTL_PSP 0x00000008 /* pad short packets */ +#define E1000_TCTL_CT 0x00000ff0 /* collision threshold */ +#define E1000_TCTL_COLD 0x003ff000 /* collision distance */ +#define E1000_TCTL_SWXOFF 0x00400000 /* SW Xoff transmission */ +#define E1000_TCTL_PBE 0x00800000 /* Packet Burst Enable */ +#define E1000_TCTL_RTLC 0x01000000 /* Re-transmit on late collision */ +#define E1000_TCTL_NRTU 0x02000000 /* No Re-transmit on underrun */ +#define E1000_TCTL_MULR 0x10000000 /* Multiple request support */ + +/* Receive Control */ +#define E1000_RCTL_RST 0x00000001 /* Software reset */ +#define E1000_RCTL_EN 0x00000002 /* enable */ +#define E1000_RCTL_SBP 0x00000004 /* store bad packet */ +#define E1000_RCTL_UPE 0x00000008 /* unicast promiscuous enable */ +#define E1000_RCTL_MPE 0x00000010 /* multicast promiscuous enable */ +#define E1000_RCTL_LPE 0x00000020 /* long packet enable */ +#define E1000_RCTL_LBM_NO 0x00000000 /* no loopback mode */ +#define E1000_RCTL_LBM_MAC 0x00000040 /* MAC loopback mode */ +#define E1000_RCTL_LBM_SLP 0x00000080 /* serial link loopback mode */ +#define E1000_RCTL_LBM_TCVR 0x000000C0 /* tcvr loopback mode */ +#define E1000_RCTL_DTYP_MASK 0x00000C00 /* Descriptor type mask */ +#define E1000_RCTL_DTYP_PS 0x00000400 /* Packet Split descriptor */ +#define E1000_RCTL_RDMTS_HALF 0x00000000 /* rx desc min threshold size */ +#define E1000_RCTL_RDMTS_QUAT 0x00000100 /* rx desc min threshold size */ +#define E1000_RCTL_RDMTS_EIGTH 0x00000200 /* rx desc min threshold size */ +#define E1000_RCTL_MO_SHIFT 12 /* multicast offset shift */ +#define E1000_RCTL_MO_0 0x00000000 /* multicast offset 11:0 */ +#define E1000_RCTL_MO_1 0x00001000 /* multicast offset 12:1 */ +#define E1000_RCTL_MO_2 0x00002000 /* multicast offset 13:2 */ +#define E1000_RCTL_MO_3 0x00003000 /* multicast offset 15:4 */ +#define E1000_RCTL_MDR 0x00004000 /* multicast desc ring 0 */ +#define E1000_RCTL_BAM 0x00008000 /* broadcast enable */ +/* these buffer sizes are valid if E1000_RCTL_BSEX is 0 */ +#define E1000_RCTL_SZ_2048 0x00000000 /* rx buffer size 2048 */ +#define E1000_RCTL_SZ_1024 0x00010000 /* rx buffer size 1024 */ +#define E1000_RCTL_SZ_512 0x00020000 /* rx buffer size 512 */ +#define E1000_RCTL_SZ_256 0x00030000 /* rx buffer size 256 */ +/* these buffer sizes are valid if E1000_RCTL_BSEX is 1 */ +#define E1000_RCTL_SZ_16384 0x00010000 /* rx buffer size 16384 */ +#define E1000_RCTL_SZ_8192 0x00020000 /* rx buffer size 8192 */ +#define E1000_RCTL_SZ_4096 0x00030000 /* rx buffer size 4096 */ +#define E1000_RCTL_VFE 0x00040000 /* vlan filter enable */ +#define E1000_RCTL_CFIEN 0x00080000 /* canonical form enable */ +#define E1000_RCTL_CFI 0x00100000 /* canonical form indicator */ +#define E1000_RCTL_DPF 0x00400000 /* discard pause frames */ +#define E1000_RCTL_PMCF 0x00800000 /* pass MAC control frames */ +#define E1000_RCTL_BSEX 0x02000000 /* Buffer size extension */ +#define E1000_RCTL_SECRC 0x04000000 /* Strip Ethernet CRC */ +#define E1000_RCTL_FLXBUF_MASK 0x78000000 /* Flexible buffer size */ +#define E1000_RCTL_FLXBUF_SHIFT 27 /* Flexible buffer shift */ + +/* Interrupt Cause Read */ +#define E1000_ICR_TXDW 0x00000001 /* Transmit desc written back */ +#define E1000_ICR_TXQE 0x00000002 /* Transmit Queue empty */ +#define E1000_ICR_LSC 0x00000004 /* Link Status Change */ +#define E1000_ICR_RXSEQ 0x00000008 /* rx sequence error */ +#define E1000_ICR_RXDMT0 0x00000010 /* rx desc min. threshold (0) */ +#define E1000_ICR_RXO 0x00000040 /* rx overrun */ +#define E1000_ICR_RXT0 0x00000080 /* rx timer intr (ring 0) */ +#define E1000_ICR_MDAC 0x00000200 /* MDIO access complete */ +#define E1000_ICR_RXCFG 0x00000400 /* RX /c/ ordered set */ +#define E1000_ICR_GPI_EN0 0x00000800 /* GP Int 0 */ +#define E1000_ICR_GPI_EN1 0x00001000 /* GP Int 1 */ +#define E1000_ICR_GPI_EN2 0x00002000 /* GP Int 2 */ +#define E1000_ICR_GPI_EN3 0x00004000 /* GP Int 3 */ +#define E1000_ICR_TXD_LOW 0x00008000 +#define E1000_ICR_SRPD 0x00010000 +#define E1000_ICR_ACK 0x00020000 /* Receive Ack frame */ +#define E1000_ICR_MNG 0x00040000 /* Manageability event */ +#define E1000_ICR_DOCK 0x00080000 /* Dock/Undock */ +#define E1000_ICR_INT_ASSERTED 0x80000000 /* If this bit asserted, the driver should claim the interrupt */ +#define E1000_ICR_RXD_FIFO_PAR0 0x00100000 /* queue 0 Rx descriptor FIFO parity error */ +#define E1000_ICR_TXD_FIFO_PAR0 0x00200000 /* queue 0 Tx descriptor FIFO parity error */ +#define E1000_ICR_HOST_ARB_PAR 0x00400000 /* host arb read buffer parity error */ +#define E1000_ICR_PB_PAR 0x00800000 /* packet buffer parity error */ +#define E1000_ICR_RXD_FIFO_PAR1 0x01000000 /* queue 1 Rx descriptor FIFO parity error */ +#define E1000_ICR_TXD_FIFO_PAR1 0x02000000 /* queue 1 Tx descriptor FIFO parity error */ +#define E1000_ICR_ALL_PARITY 0x03F00000 /* all parity error bits */ +#define E1000_ICR_DSW 0x00000020 /* FW changed the status of DISSW bit in the FWSM */ +#define E1000_ICR_PHYINT 0x00001000 /* LAN connected device generates an interrupt */ +#define E1000_ICR_EPRST 0x00100000 /* ME handware reset occurs */ + +/* Interrupt Mask Set */ +#define E1000_IMS_TXDW E1000_ICR_TXDW /* Transmit desc written back */ +#define E1000_IMS_TXQE E1000_ICR_TXQE /* Transmit Queue empty */ +#define E1000_IMS_LSC E1000_ICR_LSC /* Link Status Change */ +#define E1000_IMS_RXSEQ E1000_ICR_RXSEQ /* rx sequence error */ +#define E1000_IMS_RXDMT0 E1000_ICR_RXDMT0 /* rx desc min. threshold */ +#define E1000_IMS_RXO E1000_ICR_RXO /* rx overrun */ +#define E1000_IMS_RXT0 E1000_ICR_RXT0 /* rx timer intr */ +#define E1000_IMS_MDAC E1000_ICR_MDAC /* MDIO access complete */ +#define E1000_IMS_RXCFG E1000_ICR_RXCFG /* RX /c/ ordered set */ +#define E1000_IMS_GPI_EN0 E1000_ICR_GPI_EN0 /* GP Int 0 */ +#define E1000_IMS_GPI_EN1 E1000_ICR_GPI_EN1 /* GP Int 1 */ +#define E1000_IMS_GPI_EN2 E1000_ICR_GPI_EN2 /* GP Int 2 */ +#define E1000_IMS_GPI_EN3 E1000_ICR_GPI_EN3 /* GP Int 3 */ +#define E1000_IMS_TXD_LOW E1000_ICR_TXD_LOW +#define E1000_IMS_SRPD E1000_ICR_SRPD +#define E1000_IMS_ACK E1000_ICR_ACK /* Receive Ack frame */ +#define E1000_IMS_MNG E1000_ICR_MNG /* Manageability event */ +#define E1000_IMS_DOCK E1000_ICR_DOCK /* Dock/Undock */ +#define E1000_IMS_RXD_FIFO_PAR0 E1000_ICR_RXD_FIFO_PAR0 /* queue 0 Rx descriptor FIFO parity error */ +#define E1000_IMS_TXD_FIFO_PAR0 E1000_ICR_TXD_FIFO_PAR0 /* queue 0 Tx descriptor FIFO parity error */ +#define E1000_IMS_HOST_ARB_PAR E1000_ICR_HOST_ARB_PAR /* host arb read buffer parity error */ +#define E1000_IMS_PB_PAR E1000_ICR_PB_PAR /* packet buffer parity error */ +#define E1000_IMS_RXD_FIFO_PAR1 E1000_ICR_RXD_FIFO_PAR1 /* queue 1 Rx descriptor FIFO parity error */ +#define E1000_IMS_TXD_FIFO_PAR1 E1000_ICR_TXD_FIFO_PAR1 /* queue 1 Tx descriptor FIFO parity error */ +#define E1000_IMS_DSW E1000_ICR_DSW +#define E1000_IMS_PHYINT E1000_ICR_PHYINT +#define E1000_IMS_EPRST E1000_ICR_EPRST + +// TX and RX descriptor +typedef struct __attribute__((packed)) +{ + uint64_t addr; + uint16_t length; + uint8_t cso; + uint8_t cmd; + uint8_t status; + uint8_t css; + uint16_t special; +} tx_desc_t; + +typedef struct __attribute__((packed)) +{ + uint64_t addr; + uint16_t length; + uint16_t checksum; + uint8_t status; + uint8_t errors; + uint16_t special; +} rx_desc_t; + +/* + * Helper struct to hold private data used to operate your ethernet interface. + */ +typedef struct e1000if { + struct eth_addr *ethaddr; + /* Add whatever per-interface state that is needed here. */ + uint8_t* bar0; + uint8_t* tx_buffers; + uint8_t* rx_buffers; + volatile tx_desc_t* tx_desc; // transmit descriptor buffer + uint16_t tx_tail; + volatile rx_desc_t* rx_desc; // receive descriptor buffer + uint16_t rx_tail; + uint8_t irq; + volatile uint8_t polling; +} e1000if_t; + +/* + * Initialize the network driver for the RealTek RTL8139 family + */ +err_t e1000if_init(struct netif* netif); + +#endif + +#endif