add first version of the network driver for Intel's E1000 NIC

This commit is contained in:
Stefan Lankes 2012-07-26 09:11:46 +02:00
parent ac20297df9
commit 947d77c775
3 changed files with 796 additions and 1 deletions

View file

@ -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

536
drivers/net/e1000.c Normal file
View file

@ -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 <metalsvm/stddef.h>
#include <metalsvm/stdio.h>
#include <metalsvm/string.h>
#include <metalsvm/processor.h>
#include <metalsvm/mailbox.h>
#include <metalsvm/page.h>
#include <asm/io.h>
#include <asm/irq.h>
#if defined(CONFIG_LWIP) && defined(CONFIG_PCI)
#include <asm/pci.h>
#include <lwip/sys.h>
#include <lwip/stats.h>
#include <lwip/netif.h>
#include <lwip/tcpip.h>
#include <netif/etharp.h>
#include <net/e1000.h>
#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

259
drivers/net/e1000.h Normal file
View file

@ -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 <metalsvm/stddef.h>
#include <metalsvm/spinlock.h>
#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