mirror of
https://github.com/hermitcore/libhermit.git
synced 2025-03-09 00:00:03 +01:00
add prototype of basic ethernet support
- add devices driver for Intel's E1000 and Realtek's 8139 - currently, work in progress and not initialized at boot time
This commit is contained in:
parent
f00773ce8b
commit
c10ab74d67
7 changed files with 1695 additions and 12 deletions
|
@ -1,4 +1,4 @@
|
|||
C_source := mmnif.c util.c
|
||||
C_source := mmnif.c util.c e1000.c rtl8139.c
|
||||
MODULE := drivers_net
|
||||
|
||||
include $(TOPDIR)/Makefile.inc
|
||||
|
|
596
hermit/drivers/net/e1000.c
Normal file
596
hermit/drivers/net/e1000.c
Normal file
|
@ -0,0 +1,596 @@
|
|||
/*
|
||||
* Copyright 2012 Stefan Lankes, Chair for Operating Systems,
|
||||
* RWTH Aachen University
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <hermit/stddef.h>
|
||||
#include <hermit/stdio.h>
|
||||
#include <hermit/string.h>
|
||||
#include <hermit/processor.h>
|
||||
#include <hermit/mailbox.h>
|
||||
#include <asm/page.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/irq.h>
|
||||
#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 (2048)
|
||||
#define TX_BUF_LEN (1792)
|
||||
|
||||
#define INT_MASK (E1000_IMS_RXO|E1000_IMS_RXT0|E1000_IMS_RXDMT0|E1000_IMS_RXSEQ|E1000_IMS_LSC)
|
||||
#define INT_MASK_NO_RX (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(volatile uint8_t* base, uint32_t off)
|
||||
{
|
||||
#if 1
|
||||
uint32_t ret;
|
||||
|
||||
asm volatile ("movl (%1), %0" : "=r"(ret) : "r"(base+off));
|
||||
|
||||
return ret;
|
||||
#else
|
||||
return *((volatile uint32_t*) (base+off));
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void e1000_write(volatile uint8_t* base, uint32_t off, uint32_t value)
|
||||
{
|
||||
*((volatile uint32_t*) (base+off)) = value;
|
||||
}
|
||||
|
||||
static inline void e1000_flush(volatile uint8_t* base)
|
||||
{
|
||||
e1000_read(base, E1000_STATUS);
|
||||
}
|
||||
|
||||
#if 1
|
||||
static uint16_t eeprom_read(volatile 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 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
|
||||
netif->input(p, netif);
|
||||
} 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.drop);
|
||||
}
|
||||
|
||||
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);
|
||||
e1000_flush(e1000if->bar0);
|
||||
}
|
||||
|
||||
/* 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_IMC, INT_MASK|0xFFFE0000);
|
||||
e1000_flush(e1000if->bar0);
|
||||
|
||||
// read the pending interrupt status
|
||||
icr = e1000_read(e1000if->bar0, E1000_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_RX);
|
||||
else
|
||||
e1000_write(e1000if->bar0, E1000_IMS, INT_MASK); // enable interrupts
|
||||
e1000_flush(e1000if->bar0);
|
||||
|
||||
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 = NULL;
|
||||
uint32_t tmp32;
|
||||
uint16_t tmp16, speed, cold = 0x40;
|
||||
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;
|
||||
}
|
||||
|
||||
if (is64bit) {
|
||||
LWIP_DEBUGF(NETIF_DEBUG, ("e1000if_init: 64bit mode 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*) vma_alloc(PAGE_FLOOR(pci_info.size[0]), VMA_READ|VMA_WRITE);
|
||||
if (BUILTIN_EXPECT(!e1000if->bar0, 0))
|
||||
goto oom;
|
||||
|
||||
int ret = page_map((size_t)e1000if->bar0, PAGE_CEIL(pci_info.base[0]), PAGE_FLOOR(pci_info.size[0]) >> PAGE_BITS, PG_GLOBAL|PG_RW|PG_PCD);
|
||||
if (BUILTIN_EXPECT(ret, 0))
|
||||
goto oom;
|
||||
|
||||
// reset device
|
||||
e1000_write(e1000if->bar0, E1000_CTRL, E1000_CTRL_RST);
|
||||
e1000_flush(e1000if->bar0);
|
||||
/* Wait for reset to complete */
|
||||
udelay(10);
|
||||
|
||||
e1000if->irq = pci_info.irq;
|
||||
e1000if->rx_desc = page_alloc(NUM_RX_DESCRIPTORS*sizeof(rx_desc_t), VMA_READ|VMA_WRITE);
|
||||
if (BUILTIN_EXPECT(!e1000if->rx_desc, 0))
|
||||
goto oom;
|
||||
memset((void*) e1000if->rx_desc, 0x00, NUM_RX_DESCRIPTORS*sizeof(rx_desc_t));
|
||||
e1000if->tx_desc = page_alloc(NUM_TX_DESCRIPTORS*sizeof(tx_desc_t), VMA_READ|VMA_WRITE);
|
||||
if (BUILTIN_EXPECT(!e1000if->tx_desc, 0))
|
||||
goto oom;
|
||||
memset((void*) e1000if->tx_desc, 0x00, NUM_TX_DESCRIPTORS*sizeof(tx_desc_t));
|
||||
|
||||
LWIP_DEBUGF(NETIF_DEBUG, ("e1000if_init: Found %s at mmio 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));
|
||||
|
||||
/* hardware address length */
|
||||
netif->hwaddr_len = ETHARP_HWADDR_LEN;
|
||||
|
||||
// determine the mac address of this card
|
||||
for (tmp8=0; tmp8<ETHARP_HWADDR_LEN; tmp8+=2) {
|
||||
tmp16 = eeprom_read(e1000if->bar0, tmp8 / 2);
|
||||
netif->hwaddr[tmp8] = (tmp16 & 0xFF);
|
||||
netif->hwaddr[tmp8+1] = (tmp16 >> 8) & 0xFF;
|
||||
}
|
||||
|
||||
e1000if->tx_buffers = page_alloc(NUM_TX_DESCRIPTORS*TX_BUF_LEN, VMA_READ|VMA_WRITE);
|
||||
if (BUILTIN_EXPECT(!e1000if->tx_buffers, 0))
|
||||
goto oom;
|
||||
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));
|
||||
|
||||
/* General configuration */
|
||||
tmp32 = e1000_read(e1000if->bar0, E1000_CTRL);
|
||||
tmp32 &= ~(E1000_CTRL_VME|E1000_CTRL_FD|E1000_CTRL_ILOS|E1000_CTRL_PHY_RST|E1000_CTRL_LRST|E1000_CTRL_FRCSPD);
|
||||
e1000_write(e1000if->bar0, E1000_CTRL, tmp32 | E1000_CTRL_SLU | E1000_CTRL_ASDE);
|
||||
e1000_flush(e1000if->bar0);
|
||||
kprintf("e1000if_init: Device Control Register 0x%x\n", e1000_read(e1000if->bar0, E1000_CTRL));
|
||||
|
||||
/* make sure transmits are disabled while setting up the descriptors */
|
||||
tmp32 = e1000_read(e1000if->bar0, E1000_TCTL);
|
||||
e1000_write(e1000if->bar0, E1000_TCTL, tmp32 & ~E1000_TCTL_EN);
|
||||
e1000_flush(e1000if->bar0);
|
||||
|
||||
// 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;
|
||||
|
||||
tmp32 = e1000_read(e1000if->bar0, E1000_STATUS);
|
||||
if (tmp32 & E1000_STATUS_SPEED_1000)
|
||||
speed = 1000;
|
||||
else if (tmp32 & E1000_STATUS_SPEED_100)
|
||||
speed = 100;
|
||||
else
|
||||
speed = 10;
|
||||
|
||||
if ((!(tmp32 & E1000_STATUS_FD)) && (speed == 1000))
|
||||
cold = 0x200;
|
||||
LWIP_DEBUGF(NETIF_DEBUG, ("e1000if_init: speed = %u mbps\n", speed));
|
||||
LWIP_DEBUGF(NETIF_DEBUG, ("e1000if_init: Full-Duplex %u\n", tmp32 & E1000_STATUS_FD));
|
||||
|
||||
// set the transmit control register (padshortpackets)
|
||||
e1000_write(e1000if->bar0, E1000_TCTL, (E1000_TCTL_EN | E1000_TCTL_PSP | (cold << 12) | (0x10 << 4)));
|
||||
e1000_flush(e1000if->bar0);
|
||||
|
||||
// set IEEE 802.3 standard IPG value
|
||||
e1000_write(e1000if->bar0, E1000_TIPG, (6 << 20) | (8 << 10) | 10);
|
||||
|
||||
// set MAC address
|
||||
for(tmp8=0; tmp8<4; tmp8++)
|
||||
((uint8_t*) &tmp32)[tmp8] = netif->hwaddr[tmp8];
|
||||
e1000_write(e1000if->bar0, E1000_RA, tmp32);
|
||||
tmp32 = 0;
|
||||
for(tmp8=0; tmp8<2; tmp8++)
|
||||
((uint8_t*) &tmp32)[tmp8] = netif->hwaddr[tmp8+4];
|
||||
e1000_write(e1000if->bar0, E1000_RA+4, tmp32 | (1 << 31)); // set also AV bit to check incoming packets
|
||||
|
||||
/* Zero out the other receive addresses. */
|
||||
for (tmp8=1; tmp8<16; tmp8++) {
|
||||
e1000_write(e1000if->bar0, E1000_RA+8*tmp8, 0);
|
||||
e1000_write(e1000if->bar0, E1000_RA+8*tmp8+4, 0);
|
||||
}
|
||||
|
||||
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"));
|
||||
e1000_flush(e1000if->bar0);
|
||||
|
||||
// set multicast table to 0
|
||||
for(tmp8=0; tmp8<128; tmp8++ )
|
||||
e1000_write(e1000if->bar0, E1000_MTA + (tmp8 * 4), 0);
|
||||
e1000_flush(e1000if->bar0);
|
||||
|
||||
// set IRQ handler
|
||||
irq_install_handler(e1000if->irq+32, e1000if_handler);
|
||||
|
||||
/* make sure receives are disabled while setting up the descriptors */
|
||||
tmp32 = e1000_read(e1000if->bar0, E1000_RCTL);
|
||||
e1000_write(e1000if->bar0, E1000_RCTL, tmp32 & ~E1000_RCTL_EN);
|
||||
e1000_flush(e1000if->bar0);
|
||||
|
||||
// clear IMS & IMC registers
|
||||
e1000_write(e1000if->bar0, E1000_IMS, 0xFFFF);
|
||||
e1000_flush(e1000if->bar0);
|
||||
e1000_write(e1000if->bar0, E1000_IMC, 0xFFFF);
|
||||
e1000_flush(e1000if->bar0);
|
||||
|
||||
// enable all interrupts (and clear existing pending ones)
|
||||
e1000_write(e1000if->bar0, E1000_IMS, INT_MASK);
|
||||
e1000_flush(e1000if->bar0);
|
||||
e1000_read(e1000if->bar0, E1000_ICR);
|
||||
|
||||
LWIP_DEBUGF(NETIF_DEBUG, ("e1000if_init: Interrupt Mask is set to 0x%x\n", e1000_read(e1000if->bar0, E1000_IMS)));
|
||||
|
||||
//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 = page_alloc(NUM_RX_DESCRIPTORS*RX_BUF_LEN, VMA_READ|VMA_WRITE);
|
||||
if (BUILTIN_EXPECT(!e1000if->rx_buffers, 0))
|
||||
goto oom;
|
||||
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
|
||||
e1000_write(e1000if->bar0, E1000_RCTL, (E1000_RCTL_EN|/*E1000_RCTL_LPE|*/E1000_RCTL_LBM_NO|E1000_RCTL_BAM|E1000_RCTL_SZ_2048|
|
||||
E1000_RCTL_SECRC|E1000_RCTL_RDMTS_HALF|E1000_RCTL_MO_0/*|E1000_RCTL_UPE|E1000_RCTL_MPE*/));
|
||||
e1000_flush(e1000if->bar0);
|
||||
|
||||
LWIP_DEBUGF(NETIF_DEBUG, ("e1000if_init: status = 0x%x\n", e1000_read(e1000if->bar0, E1000_STATUS)));
|
||||
|
||||
/*
|
||||
* 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;
|
||||
|
||||
e1000if->ethaddr = (struct eth_addr *)netif->hwaddr;
|
||||
|
||||
return ERR_OK;
|
||||
|
||||
oom:
|
||||
if (e1000if)
|
||||
{
|
||||
if (e1000if->rx_desc)
|
||||
page_free((void*) e1000if->rx_desc, NUM_RX_DESCRIPTORS*sizeof(rx_desc_t));
|
||||
if (e1000if->tx_desc)
|
||||
page_free((void*) e1000if->tx_desc, NUM_TX_DESCRIPTORS*sizeof(tx_desc_t));
|
||||
if (e1000if->tx_buffers)
|
||||
page_free(e1000if->tx_buffers, NUM_TX_DESCRIPTORS*TX_BUF_LEN);
|
||||
if (e1000if->rx_buffers)
|
||||
page_free(e1000if->rx_buffers, NUM_RX_DESCRIPTORS*RX_BUF_LEN);
|
||||
if (e1000if->bar0) {
|
||||
e1000_write(e1000if->bar0, E1000_CTRL, E1000_CTRL_RST);
|
||||
|
||||
// TODO: unmap e1000if->bar0
|
||||
}
|
||||
|
||||
irq_uninstall_handler(e1000if->irq+32);
|
||||
|
||||
kfree(e1000if);
|
||||
}
|
||||
|
||||
memset(netif, 0x00, sizeof(struct netif));
|
||||
mynetif = NULL;
|
||||
|
||||
return ERR_MEM;
|
||||
}
|
326
hermit/drivers/net/e1000.h
Normal file
326
hermit/drivers/net/e1000.h
Normal file
|
@ -0,0 +1,326 @@
|
|||
/*
|
||||
* Copyright 2012 Stefan Lankes, Chair for Operating Systems,
|
||||
* RWTH Aachen University
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __NET_E1000_H__
|
||||
#define __NET_E1000_H__
|
||||
|
||||
#include <hermit/stddef.h>
|
||||
#include <hermit/spinlock.h>
|
||||
|
||||
#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_CTRL_EXT 0x00018 /* Extended Device Control - 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 */
|
||||
|
||||
/* Device Status */
|
||||
#define E1000_STATUS_FD 0x00000001 /* Full duplex.0=half,1=full */
|
||||
#define E1000_STATUS_LU 0x00000002 /* Link up.0=no,1=link */
|
||||
#define E1000_STATUS_FUNC_MASK 0x0000000C /* PCI Function Mask */
|
||||
#define E1000_STATUS_FUNC_SHIFT 2
|
||||
#define E1000_STATUS_FUNC_0 0x00000000 /* Function 0 */
|
||||
#define E1000_STATUS_FUNC_1 0x00000004 /* Function 1 */
|
||||
#define E1000_STATUS_TXOFF 0x00000010 /* transmission paused */
|
||||
#define E1000_STATUS_TBIMODE 0x00000020 /* TBI mode */
|
||||
#define E1000_STATUS_SPEED_MASK 0x000000C0
|
||||
#define E1000_STATUS_SPEED_10 0x00000000 /* Speed 10Mb/s */
|
||||
#define E1000_STATUS_SPEED_100 0x00000040 /* Speed 100Mb/s */
|
||||
#define E1000_STATUS_SPEED_1000 0x00000080 /* Speed 1000Mb/s */
|
||||
#define E1000_STATUS_LAN_INIT_DONE 0x00000200 /* Lan Init Completion
|
||||
by EEPROM/Flash */
|
||||
#define E1000_STATUS_ASDV 0x00000300 /* Auto speed detect value */
|
||||
#define E1000_STATUS_DOCK_CI 0x00000800 /* Change in Dock/Undock state. Clear on write '0'. */
|
||||
#define E1000_STATUS_GIO_MASTER_ENABLE 0x00080000 /* Status of Master requests. */
|
||||
#define E1000_STATUS_MTXCKOK 0x00000400 /* MTX clock running OK */
|
||||
#define E1000_STATUS_PCI66 0x00000800 /* In 66Mhz slot */
|
||||
#define E1000_STATUS_BUS64 0x00001000 /* In 64 bit slot */
|
||||
#define E1000_STATUS_PCIX_MODE 0x00002000 /* PCI-X mode */
|
||||
#define E1000_STATUS_PCIX_SPEED 0x0000C000 /* PCI-X bus speed */
|
||||
#define E1000_STATUS_BMC_SKU_0 0x00100000 /* BMC USB redirect disabled */
|
||||
#define E1000_STATUS_BMC_SKU_1 0x00200000 /* BMC SRAM disabled */
|
||||
#define E1000_STATUS_BMC_SKU_2 0x00400000 /* BMC SDRAM disabled */
|
||||
#define E1000_STATUS_BMC_CRYPTO 0x00800000 /* BMC crypto disabled */
|
||||
#define E1000_STATUS_BMC_LITE 0x01000000 /* BMC external code execution disabled */
|
||||
#define E1000_STATUS_RGMII_ENABLE 0x02000000 /* RGMII disabled */
|
||||
#define E1000_STATUS_FUSE_8 0x04000000
|
||||
#define E1000_STATUS_FUSE_9 0x08000000
|
||||
#define E1000_STATUS_SERDES0_DIS 0x10000000 /* SERDES disabled on port 0 */
|
||||
#define E1000_STATUS_SERDES1_DIS 0x20000000 /* SERDES disabled on port 1 */
|
||||
|
||||
/* 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
|
||||
|
||||
/* Interrupt Mask Clear */
|
||||
#define E1000_IMC_TXDW E1000_ICR_TXDW /* Transmit desc written back */
|
||||
#define E1000_IMC_TXQE E1000_ICR_TXQE /* Transmit Queue empty */
|
||||
#define E1000_IMC_LSC E1000_ICR_LSC /* Link Status Change */
|
||||
#define E1000_IMC_RXSEQ E1000_ICR_RXSEQ /* rx sequence error */
|
||||
#define E1000_IMC_RXDMT0 E1000_ICR_RXDMT0 /* rx desc min. threshold */
|
||||
#define E1000_IMC_RXO E1000_ICR_RXO /* rx overrun */
|
||||
#define E1000_IMC_RXT0 E1000_ICR_RXT0 /* rx timer intr */
|
||||
#define E1000_IMC_MDAC E1000_ICR_MDAC /* MDIO access complete */
|
||||
#define E1000_IMC_RXCFG E1000_ICR_RXCFG /* RX /c/ ordered set */
|
||||
#define E1000_IMC_GPI_EN0 E1000_ICR_GPI_EN0 /* GP Int 0 */
|
||||
#define E1000_IMC_GPI_EN1 E1000_ICR_GPI_EN1 /* GP Int 1 */
|
||||
#define E1000_IMC_GPI_EN2 E1000_ICR_GPI_EN2 /* GP Int 2 */
|
||||
#define E1000_IMC_GPI_EN3 E1000_ICR_GPI_EN3 /* GP Int 3 */
|
||||
#define E1000_IMC_TXD_LOW E1000_ICR_TXD_LOW
|
||||
#define E1000_IMC_SRPD E1000_ICR_SRPD
|
||||
#define E1000_IMC_ACK E1000_ICR_ACK /* Receive Ack frame */
|
||||
#define E1000_IMC_MNG E1000_ICR_MNG /* Manageability event */
|
||||
#define E1000_IMC_DOCK E1000_ICR_DOCK /* Dock/Undock */
|
||||
#define E1000_IMC_RXD_FIFO_PAR0 E1000_ICR_RXD_FIFO_PAR0 /* queue 0 Rx descriptor FIFO parity error */
|
||||
#define E1000_IMC_TXD_FIFO_PAR0 E1000_ICR_TXD_FIFO_PAR0 /* queue 0 Tx descriptor FIFO parity error */
|
||||
#define E1000_IMC_HOST_ARB_PAR E1000_ICR_HOST_ARB_PAR /* host arb read buffer parity error */
|
||||
#define E1000_IMC_PB_PAR E1000_ICR_PB_PAR /* packet buffer parity error */
|
||||
#define E1000_IMC_RXD_FIFO_PAR1 E1000_ICR_RXD_FIFO_PAR1 /* queue 1 Rx descriptor FIFO parity error */
|
||||
#define E1000_IMC_TXD_FIFO_PAR1 E1000_ICR_TXD_FIFO_PAR1 /* queue 1 Tx descriptor FIFO parity error */
|
||||
#define E1000_IMC_DSW E1000_ICR_DSW
|
||||
#define E1000_IMC_PHYINT E1000_ICR_PHYINT
|
||||
#define E1000_IMC_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. */
|
||||
volatile 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
|
484
hermit/drivers/net/rtl8139.c
Normal file
484
hermit/drivers/net/rtl8139.c
Normal file
|
@ -0,0 +1,484 @@
|
|||
/*
|
||||
* Copyright 2010 Stefan Lankes, Chair for Operating Systems,
|
||||
* RWTH Aachen University
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This code based mostly on the online manual http://www.lowlevel.eu/wiki/RTL8139
|
||||
*/
|
||||
|
||||
#include <hermit/stddef.h>
|
||||
#include <hermit/stdio.h>
|
||||
#include <hermit/string.h>
|
||||
#include <hermit/processor.h>
|
||||
#include <hermit/mailbox.h>
|
||||
#include <asm/page.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/irq.h>
|
||||
#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/rtl8139.h>
|
||||
|
||||
#define RX_BUF_LEN 8192
|
||||
#define TX_BUF_LEN 4096
|
||||
#define MIN(a, b) (a) < (b) ? (a) : (b)
|
||||
|
||||
/*
|
||||
* To set the RTL8139 to accept only the Transmit OK (TOK) and Receive OK (ROK)
|
||||
* interrupts, we would have the TOK and ROK bits of the IMR high and leave the
|
||||
* rest low. That way when a TOK or ROK IRQ happens, it actually will go through
|
||||
* and fire up an IRQ.
|
||||
*/
|
||||
#define INT_MASK (ISR_ROK|ISR_TOK|ISR_RXOVW|ISR_TER|ISR_RER)
|
||||
|
||||
// Beside Receive OK (ROK) interrupt, this mask enable all other interrupts
|
||||
#define INT_MASK_NO_ROK (ISR_TOK|ISR_RXOVW|ISR_TER|ISR_RER)
|
||||
|
||||
typedef struct {
|
||||
char *vendor_str;
|
||||
char *device_str;
|
||||
uint32_t vendor;
|
||||
uint32_t device;
|
||||
} board_t;
|
||||
|
||||
static board_t board_tbl[] =
|
||||
{
|
||||
{"RealTek", "RealTek RTL8139", 0x10ec, 0x8139},
|
||||
{"RealTek", "RealTek RTL8129 Fast Ethernet", 0x10ec, 0x8129},
|
||||
{"RealTek", "RealTek RTL8139B PCI", 0x10ec, 0x8138},
|
||||
{"SMC", "SMC1211TX EZCard 10/100 (RealTek RTL8139)", 0x1113, 0x1211},
|
||||
{"D-Link", "D-Link DFE-538TX (RTL8139)", 0x1186, 0x1300},
|
||||
{"LevelOne", "LevelOne FPC-0106Tx (RTL8139)", 0x018a, 0x0106},
|
||||
{"Compaq", "Compaq HNE-300 (RTL8139c)", 0x021b, 0x8139},
|
||||
{NULL,},
|
||||
};
|
||||
|
||||
static struct netif* mynetif = NULL;
|
||||
|
||||
/*
|
||||
* @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 rtl8139if_output(struct netif* netif, struct pbuf* p)
|
||||
{
|
||||
rtl1839if_t* rtl8139if = netif->state;
|
||||
uint8_t transmitid = rtl8139if->tx_queue % 4;
|
||||
uint32_t i;
|
||||
struct pbuf *q;
|
||||
|
||||
if (BUILTIN_EXPECT((rtl8139if->tx_queue - rtl8139if->tx_complete) > 3, 0)) {
|
||||
LWIP_DEBUGF(NETIF_DEBUG, ("rtl8139if_output: too many packets at once\n"));
|
||||
return ERR_IF;
|
||||
}
|
||||
|
||||
if (BUILTIN_EXPECT(p->tot_len > 1792, 0)) {
|
||||
LWIP_DEBUGF(NETIF_DEBUG, ("rtl8139if_output: packet is longer than 1792 bytes\n"));
|
||||
return ERR_IF;
|
||||
}
|
||||
|
||||
if (rtl8139if->tx_inuse[transmitid] == 1) {
|
||||
LWIP_DEBUGF(NETIF_DEBUG, ("rtl8139if_output: %i already inuse\n", transmitid));
|
||||
return ERR_IF;
|
||||
}
|
||||
|
||||
if (inportb(rtl8139if->iobase + MSR) & MSR_LINKB) {
|
||||
LWIP_DEBUGF(NETIF_DEBUG, ("rtl8139if_output: link failure\n"));
|
||||
return ERR_CONN;
|
||||
}
|
||||
|
||||
rtl8139if->tx_queue++;
|
||||
rtl8139if->tx_inuse[transmitid] = 1;
|
||||
|
||||
#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(rtl8139if->tx_buffer[transmitid] + i, q->payload, q->len);
|
||||
i += q->len;
|
||||
}
|
||||
|
||||
// send the packet
|
||||
outportl(rtl8139if->iobase + TSD0 + (4 * transmitid), p->tot_len); //|0x3A0000);
|
||||
|
||||
#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 rtl_rx_inthandler(struct netif* netif)
|
||||
{
|
||||
rtl1839if_t* rtl8139if = netif->state;
|
||||
uint16_t header;
|
||||
uint16_t length, i;
|
||||
uint8_t cmd;
|
||||
struct pbuf *p = NULL;
|
||||
struct pbuf* q;
|
||||
|
||||
cmd = inportb(rtl8139if->iobase + CR);
|
||||
while(!(cmd & CR_BUFE)) {
|
||||
header = *((uint16_t*) (rtl8139if->rx_buffer+rtl8139if->rx_pos));
|
||||
rtl8139if->rx_pos = (rtl8139if->rx_pos + 2) % RX_BUF_LEN;
|
||||
|
||||
if (header & ISR_ROK) {
|
||||
length = *((uint16_t*) (rtl8139if->rx_buffer+rtl8139if->rx_pos)) - 4; // copy packet (but not the CRC)
|
||||
rtl8139if->rx_pos = (rtl8139if->rx_pos + 2) % RX_BUF_LEN;
|
||||
#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; q!=NULL; q=q->next) {
|
||||
i = MIN(q->len, RX_BUF_LEN - rtl8139if->rx_pos);
|
||||
memcpy((uint8_t*) q->payload, rtl8139if->rx_buffer + rtl8139if->rx_pos, i);
|
||||
if (i < q->len) // wrap around to end of RxBuffer
|
||||
memcpy((uint8_t*) q->payload + i, rtl8139if->rx_buffer, q->len - i);
|
||||
rtl8139if->rx_pos = (rtl8139if->rx_pos + q->len) % RX_BUF_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
|
||||
netif->input(p, netif);
|
||||
} else {
|
||||
LWIP_DEBUGF(NETIF_DEBUG, ("rtl8139if_rx_inthandler: not enough memory!\n"));
|
||||
rtl8139if->rx_pos += (rtl8139if->rx_pos + length) % RX_BUF_LEN;
|
||||
LINK_STATS_INC(link.memerr);
|
||||
LINK_STATS_INC(link.drop);
|
||||
}
|
||||
|
||||
// packets are dword aligned
|
||||
rtl8139if->rx_pos = ((rtl8139if->rx_pos + 4 + 3) & ~0x3) % RX_BUF_LEN;
|
||||
outportw(rtl8139if->iobase + CAPR, rtl8139if->rx_pos - 0x10);
|
||||
} else {
|
||||
LWIP_DEBUGF(NETIF_DEBUG, ("rtl8139if_rx_inthandler: invalid header 0x%x, rx_pos %d\n", (uint32_t) header, rtl8139if->rx_pos));
|
||||
LINK_STATS_INC(link.drop);
|
||||
break;
|
||||
}
|
||||
|
||||
cmd = inportb(rtl8139if->iobase + CR);
|
||||
}
|
||||
|
||||
rtl8139if->polling = 0;
|
||||
// enable all known interrupts
|
||||
outportw(rtl8139if->iobase + IMR, INT_MASK);
|
||||
}
|
||||
|
||||
static void rtl_tx_inthandler(struct netif* netif)
|
||||
{
|
||||
rtl1839if_t* rtl8139if = netif->state;
|
||||
uint32_t checks = rtl8139if->tx_queue - rtl8139if->tx_complete;
|
||||
uint32_t txstatus;
|
||||
uint8_t tmp8;
|
||||
|
||||
while(checks > 0)
|
||||
{
|
||||
tmp8 = rtl8139if->tx_complete % 4;
|
||||
txstatus = inportl(rtl8139if->iobase + TSD0 + tmp8 * 4);
|
||||
|
||||
if (!(txstatus & (TSD_TOK|TSD_TUN|TSD_TABT)))
|
||||
return;
|
||||
|
||||
if (txstatus & (TSD_TABT | TSD_OWC)) {
|
||||
LWIP_DEBUGF(NETIF_DEBUG, ("rtl8139_tx_inthandler: major error\n"));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (txstatus & TSD_TUN) {
|
||||
LWIP_DEBUGF(NETIF_DEBUG, ("rtl8139_tx_inthandler: transmit underrun\n"));
|
||||
}
|
||||
|
||||
if (txstatus & TSD_TOK) {
|
||||
rtl8139if->tx_inuse[tmp8] = 0;
|
||||
rtl8139if->tx_complete++;
|
||||
checks--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* this function is called in the context of the tcpip thread or the irq handler (by using NO_SYS) */
|
||||
static void rtl8139if_poll(void* ctx)
|
||||
{
|
||||
rtl_rx_inthandler(mynetif);
|
||||
}
|
||||
|
||||
static void rtl8139if_handler(struct state* s)
|
||||
{
|
||||
rtl1839if_t* rtl8139if = mynetif->state;
|
||||
uint16_t isr_contents;
|
||||
|
||||
// disable all interrupts
|
||||
outportw(rtl8139if->iobase + IMR, 0x00);
|
||||
|
||||
while (1) {
|
||||
isr_contents = inportw(rtl8139if->iobase + ISR);
|
||||
if (isr_contents == 0)
|
||||
break;
|
||||
|
||||
if ((isr_contents & ISR_ROK) && !rtl8139if->polling) {
|
||||
#if NO_SYS
|
||||
rtl8139if_poll(NULL);
|
||||
#else
|
||||
if (tcpip_callback_with_block(rtl8139if_poll, NULL, 0) == ERR_OK) {
|
||||
rtl8139if->polling = 1;
|
||||
} else {
|
||||
LWIP_DEBUGF(NETIF_DEBUG, ("rtl8139if_handler: unable to send a poll request to the tcpip thread\n"));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (isr_contents & ISR_TOK)
|
||||
rtl_tx_inthandler(mynetif);
|
||||
|
||||
if (isr_contents & ISR_RER) {
|
||||
LWIP_DEBUGF(NETIF_DEBUG, ("rtl8139if_handler: RX error detected!\n"));
|
||||
}
|
||||
|
||||
if (isr_contents & ISR_TER) {
|
||||
LWIP_DEBUGF(NETIF_DEBUG, ("rtl8139if_handler: TX error detected!\n"));
|
||||
}
|
||||
|
||||
if (isr_contents & ISR_RXOVW) {
|
||||
LWIP_DEBUGF(NETIF_DEBUG, ("rtl8139if_handler: RX overflow detected!\n"));
|
||||
}
|
||||
|
||||
outportw(rtl8139if->iobase + ISR, isr_contents & (ISR_RXOVW|ISR_TER|ISR_RER|ISR_TOK|ISR_ROK));
|
||||
}
|
||||
|
||||
if (rtl8139if->polling) // now, the tcpip thread will check for incoming messages
|
||||
outportw(rtl8139if->iobase + IMR, INT_MASK_NO_ROK);
|
||||
else
|
||||
outportw(rtl8139if->iobase + IMR, INT_MASK); // enable interrupts
|
||||
}
|
||||
|
||||
err_t rtl8139if_init(struct netif* netif)
|
||||
{
|
||||
rtl1839if_t* rtl8139if;
|
||||
uint32_t tmp32;
|
||||
uint16_t tmp16, speed;
|
||||
uint8_t tmp8;
|
||||
static uint8_t num = 0;
|
||||
pci_info_t pci_info;
|
||||
|
||||
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;
|
||||
|
||||
rtl8139if = kmalloc(sizeof(rtl1839if_t));
|
||||
if (!rtl8139if) {
|
||||
LWIP_DEBUGF(NETIF_DEBUG, ("rtl8139if_init: out of memory\n"));
|
||||
return ERR_MEM;
|
||||
}
|
||||
memset(rtl8139if, 0x00, sizeof(rtl1839if_t));
|
||||
|
||||
rtl8139if->iobase = pci_info.base[0];
|
||||
rtl8139if->irq = pci_info.irq;
|
||||
|
||||
/* allocate the receive buffer */
|
||||
rtl8139if->rx_buffer = page_alloc(RX_BUF_LEN + 16 /* header size */, VMA_READ|VMA_WRITE);
|
||||
if (!(rtl8139if->rx_buffer)) {
|
||||
LWIP_DEBUGF(NETIF_DEBUG, ("rtl8139if_init: out of memory\n"));
|
||||
kfree(rtl8139if);
|
||||
return ERR_MEM;
|
||||
}
|
||||
memset(rtl8139if->rx_buffer, 0x00, RX_BUF_LEN + 16);
|
||||
|
||||
/* allocate the send buffers */
|
||||
rtl8139if->tx_buffer[0] = page_alloc(4*TX_BUF_LEN, VMA_READ|VMA_WRITE);
|
||||
if (!(rtl8139if->tx_buffer[0])) {
|
||||
LWIP_DEBUGF(NETIF_DEBUG, ("rtl8139if_init: out of memory\n"));
|
||||
page_free(rtl8139if->rx_buffer, RX_BUF_LEN + 16);
|
||||
kfree(rtl8139if);
|
||||
return ERR_MEM;
|
||||
}
|
||||
memset(rtl8139if->tx_buffer[0], 0x00, 4*TX_BUF_LEN);
|
||||
rtl8139if->tx_buffer[1] = rtl8139if->tx_buffer[0] + TX_BUF_LEN;
|
||||
rtl8139if->tx_buffer[2] = rtl8139if->tx_buffer[1] + TX_BUF_LEN;
|
||||
rtl8139if->tx_buffer[3] = rtl8139if->tx_buffer[2] + TX_BUF_LEN;
|
||||
|
||||
netif->state = rtl8139if;
|
||||
mynetif = netif;
|
||||
|
||||
tmp32 = inportl(rtl8139if->iobase + TCR);
|
||||
if (tmp32 == 0xFFFFFF) {
|
||||
LWIP_DEBUGF(NETIF_DEBUG, ("rtl8139if_init: ERROR\n"));
|
||||
page_free(rtl8139if->rx_buffer, RX_BUF_LEN + 16);
|
||||
page_free(rtl8139if->tx_buffer[0], 4*TX_BUF_LEN);
|
||||
kfree(rtl8139if);
|
||||
memset(netif, 0x00, sizeof(struct netif));
|
||||
mynetif = NULL;
|
||||
|
||||
return ERR_ARG;
|
||||
}
|
||||
|
||||
// determine the hardware revision
|
||||
//tmp32 = (tmp32 & TCR_HWVERID) >> TCR_HWOFFSET;
|
||||
|
||||
irq_install_handler(rtl8139if->irq+32, rtl8139if_handler);
|
||||
|
||||
/* hardware address length */
|
||||
netif->hwaddr_len = ETHARP_HWADDR_LEN;
|
||||
|
||||
LWIP_DEBUGF(NETIF_DEBUG, ("rtl8139if_init: Found %s at iobase 0x%x (irq %u)\n", board_tbl[tmp8].device_str,
|
||||
rtl8139if->iobase, rtl8139if->irq));
|
||||
// determine the mac address of this card
|
||||
LWIP_DEBUGF(NETIF_DEBUG, ("rtl8139if_init: MAC address "));
|
||||
for (tmp8=0; tmp8<ETHARP_HWADDR_LEN; tmp8++) {
|
||||
netif->hwaddr[tmp8] = inportb(rtl8139if->iobase + IDR0 + tmp8);
|
||||
LWIP_DEBUGF(NETIF_DEBUG, ("%02x ", netif->hwaddr[tmp8]));
|
||||
}
|
||||
LWIP_DEBUGF(NETIF_DEBUG, ("\n"));
|
||||
|
||||
rtl8139if->ethaddr = (struct eth_addr *) netif->hwaddr;
|
||||
|
||||
// Software reset
|
||||
outportb(rtl8139if->iobase + CR, CR_RST);
|
||||
|
||||
/*
|
||||
* The RST bit must be checked to make sure that the chip has finished the reset.
|
||||
* If the RST bit is high (1), then the reset is still in operation.
|
||||
*/
|
||||
udelay(10000);
|
||||
tmp16 = 10000;
|
||||
while ((inportb(rtl8139if->iobase + CR) & CR_RST) && tmp16 > 0) {
|
||||
tmp16--;
|
||||
}
|
||||
|
||||
if (!tmp16) {
|
||||
// it seems not to work
|
||||
kprintf("RTL8139 reset failed\n");
|
||||
page_free(rtl8139if->rx_buffer, RX_BUF_LEN + 16);
|
||||
page_free(rtl8139if->tx_buffer[0], 4*TX_BUF_LEN);
|
||||
kfree(rtl8139if);
|
||||
memset(netif, 0x00, sizeof(struct netif));
|
||||
mynetif = NULL;
|
||||
|
||||
return ERR_ARG;
|
||||
}
|
||||
|
||||
// Enable Receive and Transmitter
|
||||
outportb(rtl8139if->iobase + CR, CR_TE|CR_RE); // Sets the RE and TE bits high
|
||||
|
||||
// lock config register
|
||||
outportb(rtl8139if->iobase + CR9346, CR9346_EEM1 | CR9346_EEM0);
|
||||
|
||||
// clear all of CONFIG1
|
||||
outportb(rtl8139if->iobase + CONFIG1, 0);
|
||||
|
||||
// disable driver loaded and lanwake bits, turn driver loaded bit back on
|
||||
outportb(rtl8139if->iobase + CONFIG1,
|
||||
(inportb(rtl8139if->iobase + CONFIG1) & ~(CONFIG1_DVRLOAD | CONFIG1_LWACT)) | CONFIG1_DVRLOAD);
|
||||
|
||||
// unlock config register
|
||||
outportb(rtl8139if->iobase + CR9346, 0);
|
||||
|
||||
/*
|
||||
* configure receive buffer
|
||||
* AB - Accept Broadcast: Accept broadcast packets sent to mac ff:ff:ff:ff:ff:ff
|
||||
* AM - Accept Multicast: Accept multicast packets.
|
||||
* APM - Accept Physical Match: Accept packets send to NIC's MAC address.
|
||||
* AAP - Accept All Packets. Accept all packets (run in promiscuous mode).
|
||||
*/
|
||||
outportl(rtl8139if->iobase + RCR, RCR_MXDMA2|RCR_MXDMA1|RCR_MXDMA0|RCR_AB|RCR_AM|RCR_APM|RCR_AAP); // The WRAP bit isn't set!
|
||||
|
||||
// set the transmit config register to
|
||||
// be the normal interframe gap time
|
||||
// set DMA max burst to 64bytes
|
||||
outportl(rtl8139if->iobase + TCR, TCR_IFG|TCR_MXDMA0|TCR_MXDMA1|TCR_MXDMA2);
|
||||
|
||||
// register the receive buffer
|
||||
outportl(rtl8139if->iobase + RBSTART, virt_to_phys((size_t) rtl8139if->rx_buffer));
|
||||
|
||||
// set each of the transmitter start address descriptors
|
||||
outportl(rtl8139if->iobase + TSAD0, virt_to_phys((size_t) rtl8139if->tx_buffer[0]));
|
||||
outportl(rtl8139if->iobase + TSAD1, virt_to_phys((size_t) rtl8139if->tx_buffer[1]));
|
||||
outportl(rtl8139if->iobase + TSAD2, virt_to_phys((size_t) rtl8139if->tx_buffer[2]));
|
||||
outportl(rtl8139if->iobase + TSAD3, virt_to_phys((size_t) rtl8139if->tx_buffer[3]));
|
||||
|
||||
// Enable all known interrupts by setting the interrupt mask.
|
||||
outportw(rtl8139if->iobase + IMR, INT_MASK);
|
||||
|
||||
outportw(rtl8139if->iobase + BMCR, BMCR_ANE);
|
||||
tmp16 = inportw(rtl8139if->iobase + BMCR);
|
||||
if (tmp16 & BMCR_SPD1000)
|
||||
speed = 1000;
|
||||
else if (tmp16 & BMCR_SPD100)
|
||||
speed = 100;
|
||||
else
|
||||
speed = 10;
|
||||
// Enable Receive and Transmitter
|
||||
outportb(rtl8139if->iobase + CR, CR_TE|CR_RE); // Sets the RE and TE bits high
|
||||
|
||||
kprintf("RTL8139: CR = 0x%x, ISR = 0x%x, speed = %u mbps\n",
|
||||
inportb(rtl8139if->iobase + CR), inportw(rtl8139if->iobase + ISR), 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 = rtl8139if_output;
|
||||
/* maximum transfer unit */
|
||||
netif->mtu = 1500;
|
||||
/* broadcast capability */
|
||||
netif->flags |= NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_IGMP;
|
||||
|
||||
return ERR_OK;
|
||||
}
|
237
hermit/drivers/net/rtl8139.h
Normal file
237
hermit/drivers/net/rtl8139.h
Normal file
|
@ -0,0 +1,237 @@
|
|||
/*
|
||||
* Copyright 2010 Stefan Lankes, Chair for Operating Systems,
|
||||
* RWTH Aachen University
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This code based mostly on the online manual http://www.lowlevel.eu/wiki/RTL8139
|
||||
*/
|
||||
|
||||
#ifndef __NET_RTL8139_H__
|
||||
#define __NET_RTL8139_H__
|
||||
|
||||
#include <hermit/stddef.h>
|
||||
#include <hermit/spinlock.h>
|
||||
|
||||
// the registers are at the following places
|
||||
#define IDR0 0x0 // the ethernet ID (6bytes)
|
||||
#define MAR0 0x8 // Multicast (8 bytes)
|
||||
#define TSD0 0x10 // transmit status of each descriptor (4bytes/descriptor) (C mode)
|
||||
#define DTCCR 0x10 // Dump Tally Counter Command Register (C+ mode)
|
||||
#define TSAD0 0x20 // transmit start address of descriptor 0 (4byte, C mode, 4 byte alignment)
|
||||
#define TSAD1 0x24 // transmit start address of descriptor 1 (4byte, C mode, 4 byte alignment)
|
||||
#define TNPDS 0x20 // transmit normal priority descriptors start address (8bytes, C+ mode, 256 byte-align)
|
||||
#define TSAD2 0x28 // transmit start address of descriptor 2 (4byte, C mode, 4 byte alignment)
|
||||
#define TSAD3 0x2c // transmit start address of descriptor 3 (4byte, C mode, 4 byte alignment)
|
||||
#define THPDS 0x28 // transmit high priority descriptors start address (8byte, C+ mode, 256 byte-align)
|
||||
#define RBSTART 0x30 // recieve buffer start address (C mode, 4 byte alignment)
|
||||
#define ERBCR 0x34 // early recieve byte count (2byte)
|
||||
#define ERSR 0x36 // early recieve state register (1byte)
|
||||
#define CR 0x37 // command register (1byte)
|
||||
#define CAPR 0x38 // current address of packet read (2byte, C mode, initial value 0xFFF0)
|
||||
#define CBR 0x3a // current buffer address , total recieved byte-count in the Rx buffer (2byte, C mode, initial value 0x0000)
|
||||
#define IMR 0x3c // interrupt mask register (2byte)
|
||||
#define ISR 0x3e // interrupt status register (2byte)
|
||||
#define TCR 0x40 // transmit config register (4byte)
|
||||
#define RCR 0x44 // receive config register (4byte)
|
||||
#define TCTR 0x48 // timer count register, write any value and it will reset the count, and count from zero (4byte)
|
||||
#define MPC 0x4C // missed packet count , number of packets ignored due to RX overflow, 24-bit, write a value to reset (4byte, top is void)
|
||||
#define CR9346 0x50 // command register for 93C46 (93C56) (1byte)
|
||||
#define CONFIG0 0x51 // config register 0 (1byte)
|
||||
#define CONFIG1 0x52 // config register 1 (1byte)
|
||||
#define TIMINT 0x54 // timer interrupt register , the timeout bit will be set when the value of this == value of TCTR (4byte, when 0 does nothing)
|
||||
#define MSR 0x58 // media status register (1byte)
|
||||
#define CONFIG3 0x59 // config register 3 (1byte)
|
||||
#define CONFIG4 0x5a // config register 4 (1byte)
|
||||
#define MULINT 0x5c // multiple interrupt select (4byte)
|
||||
#define RERID 0x5e // revision ID (C+ = 0x10)
|
||||
#define TSAD 0x60 // transmit status of ALL descriptors (2byte, C mode)
|
||||
#define BMCR 0x62 // basic mode control register (2byte)
|
||||
#define BMSR 0x64 // basic mode status register (2byte)
|
||||
#define ANAR 0x66 // Auto-negotiation advertisement register (2byte)
|
||||
#define ANLPAR 0x68 // Auto-negotiation link partner register (2byte)
|
||||
#define ANER 0x6a // Auto-negotiation expansion register (2byte)
|
||||
#define DIS 0x6c // disconnected counter (2byte)
|
||||
#define FCSC 0x6e // false carrier sense counter (2byte)
|
||||
#define NWAYTR 0x70 // N-way test register (2byte)
|
||||
#define REC 0x72 // RX_ER (counts valid packets) counter (2byte)
|
||||
#define CSCR 0x74 // CS config register (2byte)
|
||||
#define PHYS1P 0x78 // PHY parameter 1 (2byte)
|
||||
#define TWP 0x7c // twister parameter (2byte)
|
||||
#define PHYS2P 0x80 // PHY parameter 2
|
||||
// some power managment registers are here
|
||||
#define FLASH 0xD4 // flash memory read/write (4byte)
|
||||
#define CONFIG5 0xD8 // config register 5 (1byte)
|
||||
#define TPPoll 0xD9 // transmit priority polling (1byte, C+ mode)
|
||||
#define CPCR 0xE0 // C+ command register (2byte, C+ mode)
|
||||
#define RDSAR 0xE4 // C+ receive descriptor start address (4byte, C+ mode, 256 byte alignment)
|
||||
#define ETTR 0xEC // C+ early transmit threshold (1byte, C+ mode)
|
||||
// some cardbus only stuff goes here
|
||||
#define MIIR 0xFC // MII register (Auto-detect or MII mode only)
|
||||
|
||||
// Command Register
|
||||
#define CR_RST 0x10 // Reset, set to 1 to invoke S/W reset, held to 1 while resetting
|
||||
#define CR_RE 0x08 // Reciever Enable, enables receiving
|
||||
#define CR_TE 0x04 // Transmitter Enable, enables transmitting
|
||||
#define CR_BUFE 0x01 // Rx buffer is empty
|
||||
|
||||
// Transmit Configuration Register
|
||||
#define TCR_HWVERID 0x7CC00000 // mask for hw version ID's
|
||||
#define TCR_HWOFFSET 22
|
||||
#define TCR_IFG 0x3000000 // interframe gap time
|
||||
#define TCR_LBK1 0x40000 // loopback test
|
||||
#define TCR_LBK0 0x20000 // loopback test
|
||||
#define TCR_CRC 0x10000 // append CRC (card adds CRC if 1)
|
||||
#define TCR_MXDMA2 0x400 // max dma burst
|
||||
#define TCR_MXDMA1 0x200 // max dma burst
|
||||
#define TCR_MXDMA0 0x100 // max dma burst
|
||||
#define TCR_TXRR 0xF0 // Tx retry count, 0 = 16 else retries TXRR * 16 + 16 times
|
||||
#define TCR_CLRABT 0x01 // Clear abort, attempt retransmit (when in abort state)
|
||||
|
||||
// Media Status Register
|
||||
#define MSR_TXFCE 0x80 // Tx Flow Control enabled
|
||||
#define MSR_RXFCE 0x40 // Rx Flow Control enabled
|
||||
#define MSR_AS 0x10 // Auxilary status
|
||||
#define MSR_SPEED 0x8 // set if currently talking on 10mbps network, clear if 100mbps
|
||||
#define MSR_LINKB 0x4 // Link Bad ?
|
||||
#define MSR_TXPF 0x2 // Transmit Pause flag
|
||||
#define MSR_RXPF 0x1 // Recieve Pause flag
|
||||
|
||||
// Basic mode control register
|
||||
#define BMCR_RESET 0x8000 // set the status and control of PHY to default
|
||||
#define BMCR_SPD100 (1 << 13) // 100 MBit
|
||||
#define BMCR_SPD1000 (1 << 6) // 1000 MBit
|
||||
#define BMCR_ANE 0x1000 // enable N-way autonegotiation (ignore above if set)
|
||||
#define BMCR_RAN 0x400 // restart auto-negotiation
|
||||
#define BMCR_DUPLEX 0x200 // Duplex mode, generally a value of 1 means full-duplex
|
||||
|
||||
// Receive Configuration Register
|
||||
#define RCR_ERTH3 0x8000000 // early Rx Threshold 0
|
||||
#define RCR_ERTH2 0x4000000 // early Rx Threshold 1
|
||||
#define RCR_ERTH1 0x2000000 // early Rx Threshold 2
|
||||
#define RCR_ERTH0 0x1000000 // early Rx Threshold 3
|
||||
#define RCR_MRINT 0x20000 // Multiple Early interrupt, (enable to make interrupts happen early, yuk)
|
||||
#define RCR_RER8 0x10000 // Receive Error Packets larger than 8 bytes
|
||||
#define RCR_RXFTH2 0x8000 // Rx Fifo threshold 0
|
||||
#define RCR_RXFTH1 0x4000 // Rx Fifo threshold 1 (set to 110 and it will send to system when 1024bytes have been gathered)
|
||||
#define RCR_RXFTH0 0x2000 // Rx Fifo threshold 2 (set all these to 1, and it wont FIFO till the full packet is ready)
|
||||
#define RCR_RBLEN1 0x1000 // Rx Buffer length 0
|
||||
#define RCR_RBLEN0 0x800 // Rx Buffer length 1 (C mode, 11 = 64kb, 10 = 32k, 01 = 16k, 00 = 8k)
|
||||
#define RCR_MXDMA2 0x400 // Max DMA burst size 0
|
||||
#define RCR_MXDMA1 0x200 // Max DMA burst size 1
|
||||
#define RCR_MXDMA0 0x100 // Max DMA burst size 2
|
||||
#define RCR_WRAP 0x80 // (void if buffer size = 64k, C mode, wrap to beginning of Rx buffer if we hit the end)
|
||||
#define RCR_EEPROMSEL 0x40 // EEPROM type (0 = 9346, 1 = 9356)
|
||||
#define RCR_AER 0x20 // Accept Error Packets (do we accept bad packets ?)
|
||||
#define RCR_AR 0x10 // Accept runt packets (accept packets that are too small ?)
|
||||
#define RCR_AB 0x08 // Accept Broadcast packets (accept broadcasts ?)
|
||||
#define RCR_AM 0x04 // Accept multicast ?
|
||||
#define RCR_APM 0x02 // Accept Physical matches (accept packets sent to our mac ?)
|
||||
#define RCR_AAP 0x01 // Accept packets with a physical address ?
|
||||
|
||||
// Interrupt Status/Mask Register
|
||||
// Bits in IMR enable/disable interrupts for specific events
|
||||
// Bits in ISR indicate the status of the card
|
||||
#define ISR_SERR 0x8000 // System error interrupt
|
||||
#define ISR_TUN 0x4000 // time out interrupt
|
||||
#define ISR_SWInt 0x100 // Software interrupt
|
||||
#define ISR_TDU 0x80 // Tx Descriptor unavailable
|
||||
#define ISR_FIFOOVW 0x40 // Rx Fifo overflow
|
||||
#define ISR_PUN 0x20 // Packet underrun/link change
|
||||
#define ISR_RXOVW 0x10 // Rx overflow/Rx Descriptor unavailable
|
||||
#define ISR_TER 0x08 // Tx Error
|
||||
#define ISR_TOK 0x04 // Tx OK
|
||||
#define ISR_RER 0x02 // Rx Error
|
||||
#define ISR_ROK 0x01 // Rx OK
|
||||
#define R39_INTERRUPT_MASK 0x7f
|
||||
|
||||
// CR9346 Command register
|
||||
#define CR9346_EEM1 0x80 // determine the operating mode
|
||||
#define CR9346_EEM0 0x40 // 00 = Normal, 01 = Auto-load, 10 = Programming, 11 = Config, Register write enabled
|
||||
#define CR9346_EECS 0x8 // status of EECS
|
||||
#define CR9346_EESK 0x4 // status of EESK
|
||||
#define CR9346_EEDI 0x2 // status of EEDI
|
||||
#define CR9346_EEDO 0x1 // status of EEDO
|
||||
|
||||
// CONFIG1 stuff
|
||||
#define CONFIG1_LEDS 0xC0 // leds status
|
||||
#define CONFIG1_DVRLOAD 0x20 // is the driver loaded ?
|
||||
#define CONFIG1_LWACT 0x10 // lanwake mode
|
||||
#define CONFIG1_MEMMAP 0x8 // Memory mapping enabled ?
|
||||
#define CONFIG1_IOMAP 0x4 // IO map enabled ?
|
||||
#define CONFIG1_VPD 0x2 // enable the virtal product data
|
||||
#define CONFIG1_PMEn 0x1 // Power Managment Enable
|
||||
|
||||
// CONFIG3 stuff
|
||||
#define CONFIG3_GNT 0x80 // Grant Select enable
|
||||
#define CONFIG3_PARM 0x40 // Parameter auto-load enabled ?
|
||||
#define CONFIG3_MAGIC 0x20 // Magic packet ?
|
||||
#define CONFIG3_LINKUP 0x10 // wake computer when link goes up ?
|
||||
#define CONFIG3_CardB 0x08 // Card Bus stuff enabled ?
|
||||
#define CONFIG3_CLKRUN 0x04 // enable CLKRUN ?
|
||||
#define CONFIG3_FRE 0x02 // Function registers enabled ? (cardbus only)
|
||||
#define CONFIG3_FBBE 0x01 // fast back to back enabled ?
|
||||
|
||||
// CONFIG4 stuff ?
|
||||
#define CONFIG4_RXFAC 0x80 // Clear Rx Fifo overflow, when enabled the card will clear FIFO overflow automatically
|
||||
#define CONFIG4_AnaOff 0x40 // Analogue power off ?
|
||||
#define CONFIG4_LWF 0x20 // Long wake-up frame
|
||||
#define CONFIG4_LWPME 0x10 // LANWAKE vs PMEB
|
||||
#define CONFIG4_LWPTN 0x04 // Lan wake pattern ?
|
||||
#define CONFIG4_PBWAKE 0x01 // pre-boot wakeup
|
||||
|
||||
//Transmit Status of Descriptor0-3 (C mode only)
|
||||
#define TSD_CRS (1 << 31) // carrier sense lost (during packet transmission)
|
||||
#define TSD_TABT (1 << 30) // transmission abort
|
||||
#define TSD_OWC (1 << 29) // out of window collision
|
||||
#define TSD_CDH (1 << 28) // CD Heart beat (Cleared in 100Mb mode)
|
||||
#define TSD_NCC 0xF000000 // Number of collisions counted (during transmission)
|
||||
#define TSD_EARTH 0x3F0000 // threshold to begin transmission (0 = 8bytes, 1->2^6 = * 32bytes)
|
||||
#define TSD_TOK (1 << 15) // Transmission OK, successful
|
||||
#define TSD_TUN (1 << 14) // Transmission FIFO underrun
|
||||
#define TSD_OWN (1 << 13) // Tx DMA operation finished (driver must set to 0 when TBC is written)
|
||||
#define TSD_SIZE 0x1fff // Descriptor size, the total size in bytes of data to send (max 1792)
|
||||
|
||||
/*
|
||||
* Helper struct to hold private data used to operate your ethernet interface.
|
||||
*/
|
||||
typedef struct rtl1839if {
|
||||
struct eth_addr *ethaddr;
|
||||
/* Add whatever per-interface state that is needed here. */
|
||||
uint8_t* tx_buffer[4];
|
||||
uint8_t* rx_buffer;
|
||||
uint32_t iobase;
|
||||
uint32_t tx_queue;
|
||||
uint32_t tx_complete;
|
||||
uint16_t rx_pos;
|
||||
uint8_t tx_inuse[4];
|
||||
uint8_t irq;
|
||||
volatile uint8_t polling;
|
||||
} rtl1839if_t;
|
||||
|
||||
/*
|
||||
* Initialize the network driver for the RealTek RTL8139 family
|
||||
*/
|
||||
err_t rtl8139if_init(struct netif* netif);
|
||||
|
||||
#endif
|
|
@ -53,11 +53,13 @@
|
|||
#include <lwip/stats.h>
|
||||
#include <netif/etharp.h>
|
||||
#include <net/mmnif.h>
|
||||
#include <net/rtl8139.h>
|
||||
#include <net/e1000.h>
|
||||
|
||||
#define HERMIT_PORT 0x494E
|
||||
#define HEMRIT_MAGIC 0x7E317
|
||||
|
||||
static struct netif mmnif_netif;
|
||||
static struct netif default_netif;
|
||||
static const int sobufsize = 131072;
|
||||
|
||||
/*
|
||||
|
@ -148,11 +150,17 @@ static void tcpip_init_done(void* arg)
|
|||
|
||||
static int init_netifs(void)
|
||||
{
|
||||
struct ip_addr ipaddr;
|
||||
struct ip_addr netmask;
|
||||
struct ip_addr gw;
|
||||
sys_sem_t sem;
|
||||
err_t err;
|
||||
|
||||
if(sys_sem_new(&sem, 0) != ERR_OK)
|
||||
LWIP_ASSERT("Failed to create semaphore", 0);
|
||||
|
||||
memset(&default_netif, 0x00, sizeof(struct netif));
|
||||
|
||||
tcpip_init(tcpip_init_done, &sem);
|
||||
sys_sem_wait(&sem);
|
||||
kprintf("TCP/IP initialized.\n");
|
||||
|
@ -160,11 +168,6 @@ static int init_netifs(void)
|
|||
|
||||
if (!is_single_kernel())
|
||||
{
|
||||
struct ip_addr ipaddr;
|
||||
struct ip_addr netmask;
|
||||
struct ip_addr gw;
|
||||
err_t err;
|
||||
|
||||
/* Set network address variables */
|
||||
IP4_ADDR(&gw, 192,168,28,1);
|
||||
IP4_ADDR(&ipaddr, 192,168,28,isle+2);
|
||||
|
@ -179,13 +182,13 @@ static int init_netifs(void)
|
|||
* - ip_input : tells him that he should use ip_input
|
||||
*/
|
||||
#if LWIP_TCPIP_CORE_LOCKING_INPUT
|
||||
if ((err = netifapi_netif_add(&mmnif_netif, &ipaddr, &netmask, &gw, NULL, mmnif_init, tcpip_input)) != ERR_OK)
|
||||
if ((err = netifapi_netif_add(&default_netif, &ipaddr, &netmask, &gw, NULL, mmnif_init, ip_input)) != ERR_OK)
|
||||
#else
|
||||
/*
|
||||
* Note: Our drivers guarantee that the input function will be called in the context of the tcpip thread.
|
||||
* => Therefore, we are able to use ip_input instead of tcpip_input
|
||||
*/
|
||||
if ((err = netifapi_netif_add(&mmnif_netif, &ipaddr, &netmask, &gw, NULL, mmnif_init, ip_input)) != ERR_OK)
|
||||
if ((err = netifapi_netif_add(&default_netif, &ipaddr, &netmask, &gw, NULL, mmnif_init, ip_input)) != ERR_OK)
|
||||
#endif
|
||||
{
|
||||
kprintf("Unable to add the intra network interface: err = %d\n", err);
|
||||
|
@ -193,10 +196,47 @@ static int init_netifs(void)
|
|||
}
|
||||
|
||||
/* tell lwip all initialization is done and we want to set it up */
|
||||
netifapi_netif_set_default(&mmnif_netif);
|
||||
netifapi_netif_set_up(&mmnif_netif);
|
||||
netifapi_netif_set_default(&default_netif);
|
||||
netifapi_netif_set_up(&default_netif);
|
||||
} else {
|
||||
/* Clear network address because we use DHCP to get an ip address */
|
||||
IP4_ADDR(&gw, 0,0,0,0);
|
||||
IP4_ADDR(&ipaddr, 0,0,0,0);
|
||||
IP4_ADDR(&netmask, 0,0,0,0);
|
||||
|
||||
#if 0
|
||||
/* Note: Our drivers guarantee that the input function will be called in the context of the tcpip thread.
|
||||
* => Therefore, we are able to use ethernet_input instead of tcpip_input */
|
||||
if ((err = netifapi_netif_add(&default_netif, &ipaddr, &netmask, &gw, NULL, rtl8139if_init, ethernet_input)) == ERR_OK)
|
||||
goto success;
|
||||
if ((err = netifapi_netif_add(&default_netif, &ipaddr, &netmask, &gw, NULL, e1000if_init, ethernet_input)) == ERR_OK)
|
||||
goto success;
|
||||
#endif
|
||||
|
||||
kprintf("Unable to add the network interface: err = %d\n", err);
|
||||
|
||||
return -ENODEV;
|
||||
|
||||
success:
|
||||
netifapi_netif_set_default(&default_netif);
|
||||
|
||||
kprintf("Starting DHCPD...\n");
|
||||
netifapi_dhcp_start(&default_netif);
|
||||
|
||||
int mscnt = 0;
|
||||
/* wait for ip address */
|
||||
while(!default_netif.ip_addr.addr) {
|
||||
sys_msleep(DHCP_FINE_TIMER_MSECS);
|
||||
dhcp_fine_tmr();
|
||||
mscnt += DHCP_FINE_TIMER_MSECS;
|
||||
if (mscnt >= DHCP_COARSE_TIMER_SECS*1000) {
|
||||
dhcp_coarse_tmr();
|
||||
mscnt = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 4042efff160d0006d002109c1b9e423c782bd9e3
|
||||
Subproject commit cae72f3218c5c523b4ede3b38a16163e6520ee49
|
Loading…
Add table
Reference in a new issue