summaryrefslogtreecommitdiff
path: root/src/drivers/net/rtl8139.c
diff options
context:
space:
mode:
authorAndreas Baumann <mail@andreasbaumann.cc>2017-08-01 21:06:18 +0200
committerAndreas Baumann <mail@andreasbaumann.cc>2017-08-01 21:06:18 +0200
commita132fee060fcc849fe59c622ef8010c83f8c041b (patch)
tree9d3b859a679a33c03efba04fc3cbddc2bf69ee98 /src/drivers/net/rtl8139.c
parentd4c0eb036034288bab5202a8f0c6242cb1e5325b (diff)
downloadabaos-a132fee060fcc849fe59c622ef8010c83f8c041b.tar.gz
abaos-a132fee060fcc849fe59c622ef8010c83f8c041b.tar.bz2
correctly receiving data in the rtl8139 driver and passing it to the network
handler, in Qemu user network we see complete ARP requests now (sent by Qemu itself presumably to update it's 'router' table (an external telnet localhost 8080 is needed to trigger that)
Diffstat (limited to 'src/drivers/net/rtl8139.c')
-rw-r--r--src/drivers/net/rtl8139.c117
1 files changed, 51 insertions, 66 deletions
diff --git a/src/drivers/net/rtl8139.c b/src/drivers/net/rtl8139.c
index 4f32815..34f273c 100644
--- a/src/drivers/net/rtl8139.c
+++ b/src/drivers/net/rtl8139.c
@@ -22,7 +22,6 @@ static rtl8139_vtable_t const rtl8139_vtable = {
// registers
#define REG_MAC0 0x00
#define REG_RBSTART 0x30
-#define REG_ERSR 0x36
#define REG_CMD 0x37
#define REG_CAPR 0x38
#define REG_IMR 0x3C
@@ -56,6 +55,7 @@ static rtl8139_vtable_t const rtl8139_vtable = {
// values for REG_TCR (transmit configuration register)
#define TCR_IFG_STANDARD 0x03000000
#define TCR_MXDMA_2048 0x00000700
+#define TCR_APPEND_CRC 0x00010000
// values for REG_RCR (receive configuration register)
#define RCR_MXDMA_UNLIMITED 0x00000700
@@ -87,7 +87,8 @@ static rtl8139_vtable_t const rtl8139_vtable = {
#define PACKET_HEADER_ROK 0x0001
// receive buffer, set to 8k + header (16) + wrap (2k)
-#define RECEIVE_BUFFER_SIZE 8192 + 16 + 2048
+#define RECEIVE_BUFFER_SIZE 8192
+#define RECEIVE_TOTAL_BUFFER_SIZE RECEIVE_BUFFER_SIZE + 16 + 2048
void rtl8139_init( rtl8139_t *rtl8139, pci_controller_t *pci, pci_device_descriptor_t *descriptor, interrupt_t *interrupt, void *context )
{
@@ -106,7 +107,6 @@ void rtl8139_init( rtl8139_t *rtl8139, pci_controller_t *pci, pci_device_descrip
port8_init( &rtl8139->CMD_port, descriptor->port_base + REG_CMD );
port16_init( &rtl8139->CAPR_port, descriptor->port_base + REG_CAPR );
port32_init( &rtl8139->RBSTART_port, descriptor->port_base + REG_RBSTART );
- port8_init( &rtl8139->ERSR_port, descriptor->port_base + REG_ERSR );
port16_init( &rtl8139->IMR_port, descriptor->port_base + REG_IMR );
port16_init( &rtl8139->ISR_port, descriptor->port_base + REG_ISR );
port32_init( &rtl8139->TCR_port, descriptor->port_base + REG_TCR );
@@ -171,14 +171,14 @@ void rtl8139_init( rtl8139_t *rtl8139, pci_controller_t *pci, pci_device_descrip
}
// initialize TCR/RCR (take Lowlevel suggestions: TCR = 0x03000700, RCR = 0x0000070a)
- port32_write( &rtl8139->TCR_port, TCR_IFG_STANDARD | TCR_MXDMA_2048 );
+ port32_write( &rtl8139->TCR_port, TCR_IFG_STANDARD | TCR_APPEND_CRC | TCR_MXDMA_2048 );
port32_write( &rtl8139->RCR_port, RCR_MXDMA_UNLIMITED |
RCR_RECEIVE_BUFFER_8K_16 | RCR_WRAP |
RCR_ACCEPT_BROADCAST | RCR_ACCEPT_MULTICAST | RCR_ACCEPT_PHYS_MATCH );
// allocate receive buffer and register it
- rtl8139->receive_buffer = (uint8_t *)aligned_alloc( 16, RECEIVE_BUFFER_SIZE + 16 );
- memset( rtl8139->receive_buffer, 0xFE, RECEIVE_BUFFER_SIZE + 16 );
+ rtl8139->receive_buffer = (uint8_t *)aligned_alloc( 16, RECEIVE_TOTAL_BUFFER_SIZE );
+ memset( rtl8139->receive_buffer, 0, RECEIVE_TOTAL_BUFFER_SIZE );
port32_write( &rtl8139->RBSTART_port, (uint32_t)rtl8139->receive_buffer );
rtl8139->receive_buffer_pos = 0;
@@ -226,9 +226,6 @@ void rtl8139_deinit( void *obj )
static void handle_receive_packet( rtl8139_t *rtl8139 )
{
- network_event_t event;
- rtl8139->base.handler( &event, rtl8139 );
-
while( true ) {
uint8_t data = port8_read( &rtl8139->CMD_port );
@@ -238,31 +235,13 @@ static void handle_receive_packet( rtl8139_t *rtl8139 )
}
uint8_t *buffer = rtl8139->receive_buffer + rtl8139->receive_buffer_pos;
-
-#ifdef DEBUG
- uint16_t capr = port16_read( &rtl8139->CAPR_port );
- uint32_t rbstart = port32_read( &rtl8139->RBSTART_port );
- uint32_t mpc = port32_read( &rtl8139->MPC_port );
- uint8_t ersr = port8_read( &rtl8139->ERSR_port );
- printf( "rtl8139: ERSR: %X, RBSTART: %X, CAPR: %X, RBPOS: %X, MPC: %X\n",
- ersr, rbstart, capr, rtl8139->receive_buffer_pos, mpc );
- printf( "rtl8139: " );
- for( int i = 0; i < 80; i++ ) {
- printf( "%X ", rtl8139->receive_buffer[rtl8139->receive_buffer_pos+i] );
- }
- puts( "" );
-#endif
-
- // kprintf("%s: rtl8139_rx() status %4.4x, size %4.4x, cur %4.4x\n", dev->name, rx_status, rx_size, cur_rx);
- // kprintf("%s: Frame contents ", dev->name);
- // for (i = 0; i < 70; i++) kprintf(" %2.2x", rx_ring[ring_offset + i]);
-
// packet header
uint16_t header = *( (uint16_t *)buffer );
#ifdef DEBUG
printf( "rtl8139: rcv header %X\n", header );
#endif
+
if( ( header & PACKET_HEADER_ROK ) == 0 ) {
printf( "rtl8139: illegal packet header, no ROK\n", header );
break;
@@ -276,41 +255,46 @@ static void handle_receive_packet( rtl8139_t *rtl8139 )
printf( "rtl8139: rcv len: %d\n", len );
#endif
+#ifdef DEBUG
+ uint16_t capr = port16_read( &rtl8139->CAPR_port );
+ uint32_t rbstart = port32_read( &rtl8139->RBSTART_port );
+ uint32_t mpc = port32_read( &rtl8139->MPC_port );
+ printf( "rtl8139: RBSTART: %X, CAPR: %X, RBPOS: %X, MPC: %X\n",
+ rbstart, capr, rtl8139->receive_buffer_pos, mpc );
+ printf( "rtl8139: " );
for( int i = 0; i < len; i++ ) {
+ printf( "%X ", rtl8139->receive_buffer[rtl8139->receive_buffer_pos+i] );
+ }
+ puts( "" );
+#endif
+
+ // copy data for the handler of the network event
+ network_event_t event;
+ event.length = len;
+ event.data = (uint8_t *)malloc( len );
+ memcpy( event.data, buffer, len );
+ memset( rtl8139->receive_buffer, 0, len + 2 * sizeof( uint16_t ) );
+
+ // adjust buffer pos
+ rtl8139->receive_buffer_pos += 2 * sizeof( uint16_t );
+ rtl8139->receive_buffer_pos += len;
+ rtl8139->receive_buffer_pos = ( rtl8139->receive_buffer_pos + 3 ) & ~0x3;
+ if( rtl8139->receive_buffer_pos >= RECEIVE_TOTAL_BUFFER_SIZE ) {
+ rtl8139->receive_buffer_pos = 0;
}
+ // initial CAPS is set to FFF0, we deduce from this that we have
+ // to subtract 16 from the actual buffer offset (not mentioned in
+ // documentation of the card!)
+ port16_write( &rtl8139->CAPR_port, rtl8139->receive_buffer_pos - 16 );
+
+ rtl8139->base.handler( &event, rtl8139 );
}
#if 0
while (1)
{
-
- void* buffer = netcard->rx_buffer + netcard->rx_buffer_offset;
-
- uint16_t packet_header = *((uint16_t*) buffer);
- buffer += 2;
-
- if ((packet_header & 1) == 0) {
- DEBUG_MSG("Paketheader: Kein ROK.\n");
- break;
- }
-
- // Die L�nge enth�lt die CRC-Pr�fsumme, nicht aber den Paketheader
- uint16_t length = *((uint16_t*) buffer);
- buffer += 2;
-
- /*
- * RECEIVE_BUFFER_SIZE
- printf("Empfangen: %d Bytes\n", length);
- printf("netcard->rx_buffer_offset = %08x\n", netcard->rx_buffer_offset);
- */
- /*int i;
- for (i = 0; i < length; i++) {
- printf("%02x ", ((char*) buffer)[i]);
- }
- printf("\n");*/
-
netcard->rx_buffer_offset += 4;
if (length >= sizeof(struct eth_packet_header))
@@ -334,16 +318,18 @@ static void handle_receive_packet( rtl8139_t *rtl8139 )
length - 4);
}
- // Den aktuellen Offset im Lesepuffer anpassen. Jedes Paket ist
- // uint32_t-aligned, daher anschlie�end Aufrundung.
- netcard->rx_buffer_offset += length;
- netcard->rx_buffer_offset = (netcard->rx_buffer_offset + 3) & ~0x3;
+--
- // �berl�ufe abfangen
- netcard->rx_buffer_offset %= RX_BUFFER_SIZE;
+ // Den aktuellen Offset im Lesepuffer anpassen. Jedes Paket ist
+ // dword-aligned, daher anschließend Aufrundung.
+ netcard->rx_buffer_offset += length + 4;
+ netcard->rx_buffer_offset = (netcard->rx_buffer_offset + 3) & ~0x3;
- write_register_word(netcard, REG_CUR_READ_ADDR,
- netcard->rx_buffer_offset - 0x10);
+ // Überläufe abfangen
+ netcard->rx_buffer_offset %= 0x2000;
+
+ write_register_word(netcard, REG_CUR_READ_ADDR,
+ netcard->rx_buffer_offset - 0x10);
@@ -356,8 +342,9 @@ uint32_t rtl8139_handle_interrupt( interrupt_handler_t *handler, uint32_t esp )
rtl8139_t *rtl8139 = (rtl8139_t *)handler->driver;
uint16_t isr = port16_read( &rtl8139->ISR_port );
- //~ uint16_t reset_isr = 0;
+ uint16_t reset_isr = 0;
+ // TODO: early interrupt line cleaning or later?
port16_write( &rtl8139->ISR_port, isr );
#ifdef DEBUG
@@ -369,12 +356,10 @@ uint32_t rtl8139_handle_interrupt( interrupt_handler_t *handler, uint32_t esp )
// TODO: manual says, we should reset the ISR bit first,
// then go into a read loop?
handle_receive_packet( rtl8139 );
-
- //~ reset_isr |= ISR_RECEIVE_OK;
}
// reset interrupt lines when consumed
- //~ port16_write( &rtl8139->ISR_port, reset_isr );
+ //~ port16_write( &rtl8139->ISR_port, isr );
return esp;
}