- Add a quick and dirty driver for the RTL8139 network adapters
- Currently, the driver detects only one adapter card. But the driver is already prepared to support several adapters. git-svn-id: http://svn.lfbs.rwth-aachen.de/svn/scc/trunk/MetalSVM@296 315a16e6-25f9-4109-90ae-ca3045a26c18
This commit is contained in:
parent
55bec7a933
commit
6dc323dd6e
3 changed files with 705 additions and 1 deletions
|
@ -1,4 +1,4 @@
|
|||
C_source = sccpc.c
|
||||
C_source = rtl8139.c
|
||||
|
||||
OBJS += $(patsubst %.c, %.o, $(filter %.c, $(C_source)))
|
||||
ALLOBJS += $(patsubst %.c, %.o, $(filter %.c, $(C_source)))
|
||||
|
|
467
drivers/net/rtl8139.c
Normal file
467
drivers/net/rtl8139.c
Normal file
|
@ -0,0 +1,467 @@
|
|||
/*
|
||||
* Copyright 2010 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.
|
||||
*
|
||||
* This code based mostly on the online manual http://www.lowlevel.eu/wiki/RTL8139
|
||||
*/
|
||||
|
||||
#include <metalsvm/stddef.h>
|
||||
#include <metalsvm/stdio.h>
|
||||
#include <metalsvm/string.h>
|
||||
#include <metalsvm/processor.h>
|
||||
#include <metalsvm/mailbox.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 <netif/etharp.h>
|
||||
#include <net/rtl8139.h>
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
#if 0
|
||||
void rtl8139if_input(struct netif* netif, struct pbuf* p)
|
||||
{
|
||||
struct eth_hdr *ethhdr;
|
||||
|
||||
/* 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 */
|
||||
/* full packet send to tcpip_thread to process */
|
||||
if (mynetif->input(p, mynetif) != ERR_OK) {
|
||||
LWIP_DEBUGF(NETIF_DEBUG, ("rtl8139if_input: IP input error\n"));
|
||||
pbuf_free(p);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
pbuf_free(p);
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
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) % (8192+16);
|
||||
|
||||
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) % (8192+16);
|
||||
#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) {
|
||||
for(i=0; i<q->len; i++) {
|
||||
((uint8_t*) q->payload)[i] = rtl8139if->rx_buffer[rtl8139if->rx_pos];
|
||||
rtl8139if->rx_pos = (rtl8139if->rx_pos + 1) % (8192+16);
|
||||
}
|
||||
}
|
||||
#if ETH_PAD_SIZE
|
||||
pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */
|
||||
#endif
|
||||
mailbox_ptr_post(&rtl8139if->mbox, (void*)p);
|
||||
//rtl8139if_input(netif, p);
|
||||
LINK_STATS_INC(link.recv);
|
||||
} else {
|
||||
LWIP_DEBUGF(NETIF_DEBUG, ("rtl8139if_rx_inthandler: not enough memory!\n"));
|
||||
rtl8139if->rx_pos += (rtl8139if->rx_pos + length) % (8192+16);
|
||||
LINK_STATS_INC(link.memerr);
|
||||
LINK_STATS_INC(link.drop);
|
||||
}
|
||||
|
||||
// packets are dword aligned
|
||||
rtl8139if->rx_pos = ((rtl8139if->rx_pos + 4 + 3) & ~0x3) % (8192+16);
|
||||
outportw(rtl8139if->iobase + CAPR, rtl8139if->rx_pos - 0x10);
|
||||
} else {
|
||||
LWIP_DEBUGF(NETIF_DEBUG, ("rtl8139if_rx_inthandler: invalid header!\n"));
|
||||
LINK_STATS_INC(link.memerr);
|
||||
LINK_STATS_INC(link.drop);
|
||||
break;
|
||||
}
|
||||
|
||||
cmd = inportb(rtl8139if->iobase + CR);
|
||||
}
|
||||
}
|
||||
|
||||
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--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void rtl8139if_handler(struct state* s)
|
||||
{
|
||||
rtl1839if_t* rtl8139if = mynetif->state;
|
||||
uint16_t isr_contents;
|
||||
|
||||
while (1) {
|
||||
isr_contents = inportw(rtl8139if->iobase + ISR);
|
||||
if (isr_contents == 0)
|
||||
break;
|
||||
|
||||
if (isr_contents & ISR_ROK) {
|
||||
rtl_rx_inthandler(mynetif);
|
||||
outportw(rtl8139if->iobase + ISR, ISR_ROK);
|
||||
}
|
||||
|
||||
if (isr_contents & ISR_TOK) {
|
||||
rtl_tx_inthandler(mynetif);
|
||||
outportw(rtl8139if->iobase + ISR, ISR_TOK);
|
||||
}
|
||||
|
||||
if (isr_contents & ISR_RER) {
|
||||
LWIP_DEBUGF(NETIF_DEBUG, ("rtl8139if_handler: RX error detected!\n"));
|
||||
outportw(rtl8139if->iobase + ISR, ISR_RER);
|
||||
}
|
||||
|
||||
if (isr_contents & ISR_TER) {
|
||||
LWIP_DEBUGF(NETIF_DEBUG, ("rtl8139if_handler: TX error detected!\n"));
|
||||
outportw(rtl8139if->iobase + ISR, ISR_TER);
|
||||
}
|
||||
|
||||
if (isr_contents & ISR_RXOVW) {
|
||||
LWIP_DEBUGF(NETIF_DEBUG, ("rtl8139if_handler: RX overflow detected!\n"));
|
||||
outportw(rtl8139if->iobase + ISR, ISR_RXOVW);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Can be called in a polling manner, or only after the RTL8139 has raised
|
||||
* an interrupt request.
|
||||
*/
|
||||
err_t rtl8139if_poll(struct netif* netif)
|
||||
{
|
||||
rtl1839if_t* rtl8139if = netif->state;
|
||||
struct eth_hdr *ethhdr;
|
||||
struct pbuf *p = NULL;
|
||||
err_t err = ERR_OK;
|
||||
|
||||
mailbox_ptr_fetch(&(rtl8139if->mbox), (void**) &p);
|
||||
|
||||
/* 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 */
|
||||
/* full packet send to tcpip_thread to process */
|
||||
if ((err = mynetif->input(p, mynetif)) != ERR_OK) {
|
||||
LWIP_DEBUGF(NETIF_DEBUG, ("rtl8139if_poll: IP input error\n"));
|
||||
pbuf_free(p);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
pbuf_free(p);
|
||||
break;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
LWIP_ASSERT("netif != NULL", (netif != NULL));
|
||||
|
||||
rtl8139if = kmalloc(sizeof(rtl1839if_t)); //mem_malloc(sizeof(rtl1839if_t));
|
||||
if (rtl8139if == NULL) {
|
||||
LWIP_DEBUGF(NETIF_DEBUG, ("rtl8139if_init: out of memory\n"));
|
||||
return ERR_MEM;
|
||||
}
|
||||
memset(rtl8139if, 0, sizeof(rtl1839if_t));
|
||||
mailbox_ptr_init(&rtl8139if->mbox);
|
||||
netif->state = rtl8139if;
|
||||
mynetif = netif;
|
||||
|
||||
tmp8 = 0;
|
||||
while (board_tbl[tmp8].vendor_str) {
|
||||
if (pci_get_device_info(board_tbl[tmp8].vendor, board_tbl[tmp8].device,
|
||||
&rtl8139if->iobase, &rtl8139if->irq) == 0)
|
||||
break;
|
||||
tmp8++;
|
||||
}
|
||||
|
||||
if (!board_tbl[tmp8].vendor_str)
|
||||
return ERR_ARG;
|
||||
|
||||
tmp32 = inportl(rtl8139if->iobase + TCR);
|
||||
if (tmp32 == 0xFFFFFF) {
|
||||
LWIP_DEBUGF(NETIF_DEBUG, ("rtl8139if_init: ERROR\n"));
|
||||
return ERR_ARG;
|
||||
}
|
||||
|
||||
// determine the hardware revision
|
||||
//tmp32 = (tmp32 & TCR_HWVERID) >> TCR_HWOFFSET;
|
||||
|
||||
irq_install_handler(rtl8139if->irq, rtl8139if_handler);
|
||||
|
||||
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<6; tmp8++) {
|
||||
mynetif->hwaddr[tmp8] = inportb(rtl8139if->iobase + IDR0 + tmp8);
|
||||
LWIP_DEBUGF(NETIF_DEBUG, ("%02x ", mynetif->hwaddr[tmp8]));
|
||||
}
|
||||
LWIP_DEBUGF(NETIF_DEBUG, ("\n"));
|
||||
|
||||
// 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");
|
||||
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, (uint32_t) rtl8139if->rx_buffer);
|
||||
|
||||
// set each of the transmitter start address descriptors
|
||||
outportl(rtl8139if->iobase + TSAD0, (uint32_t) rtl8139if->tx_buffer[0]);
|
||||
outportl(rtl8139if->iobase + TSAD1, (uint32_t) rtl8139if->tx_buffer[1]);
|
||||
outportl(rtl8139if->iobase + TSAD2, (uint32_t) rtl8139if->tx_buffer[2]);
|
||||
outportl(rtl8139if->iobase + TSAD3, (uint32_t) rtl8139if->tx_buffer[3]);
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
outportw(rtl8139if->iobase + IMR, ISR_ROK|ISR_TOK|ISR_RXOVW|ISR_TER|ISR_RER);
|
||||
|
||||
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_LINK_UP;
|
||||
/* hardware address length */
|
||||
netif->hwaddr_len = 6;
|
||||
|
||||
rtl8139if->ethaddr = (struct eth_addr *)netif->hwaddr;
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
#endif
|
237
drivers/net/rtl8139.h
Normal file
237
drivers/net/rtl8139.h
Normal file
|
@ -0,0 +1,237 @@
|
|||
/*
|
||||
* Copyright 2010 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.
|
||||
*
|
||||
* This code based mostly on the online manual http://www.lowlevel.eu/wiki/RTL8139
|
||||
*/
|
||||
|
||||
#ifndef __HAVE_RTL839_H__
|
||||
#define __HAVE_RL8139_H__
|
||||
|
||||
#include <metalsvm/stddef.h>
|
||||
#include <metalsvm/mailbox.h>
|
||||
#if defined(CONFIG_LWIP) && defined(CONFIG_PCI)
|
||||
|
||||
// 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)
|
||||
|
||||
typedef struct {
|
||||
char *vendor_str;
|
||||
char *device_str;
|
||||
uint32_t vendor;
|
||||
uint32_t device;
|
||||
} board_t;
|
||||
|
||||
/*
|
||||
* 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 rx_buffer[8192+16] __attribute__((aligned (8)));
|
||||
uint8_t tx_buffer[4][4096] __attribute__((aligned (8)));
|
||||
uint32_t iobase;
|
||||
uint32_t irq;
|
||||
uint32_t tx_queue;
|
||||
uint32_t tx_complete;
|
||||
uint16_t rx_pos;
|
||||
uint8_t tx_inuse[4];
|
||||
mailbox_ptr_t mbox;
|
||||
} rtl1839if_t;
|
||||
|
||||
err_t rtl8139if_poll(struct netif* netif);
|
||||
err_t rtl8139if_init(struct netif* netif);
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
Loading…
Add table
Reference in a new issue