diff --git a/drivers/net/Makefile b/drivers/net/Makefile index dd7c72f2..1dc0003d 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -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))) diff --git a/drivers/net/rtl8139.c b/drivers/net/rtl8139.c new file mode 100644 index 00000000..ec71b447 --- /dev/null +++ b/drivers/net/rtl8139.c @@ -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 +#include +#include +#include +#include +#include +#include +#if defined(CONFIG_LWIP) && defined(CONFIG_PCI) +#include +#include +#include +#include +#include +#include + +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; ilen; 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 diff --git a/drivers/net/rtl8139.h b/drivers/net/rtl8139.h new file mode 100644 index 00000000..f8e4ef7e --- /dev/null +++ b/drivers/net/rtl8139.h @@ -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 +#include +#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