summaryrefslogtreecommitdiff
path: root/src/drivers/net/rtl8139.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/drivers/net/rtl8139.c')
-rw-r--r--src/drivers/net/rtl8139.c200
1 files changed, 185 insertions, 15 deletions
diff --git a/src/drivers/net/rtl8139.c b/src/drivers/net/rtl8139.c
index 78a552a..e6898d4 100644
--- a/src/drivers/net/rtl8139.c
+++ b/src/drivers/net/rtl8139.c
@@ -8,27 +8,34 @@
static rtl8139_vtable_t const rtl8139_vtable = {
{
- rtl8139_activate,
- rtl8139_deactivate,
- rtl8139_deinit,
- rtl8139_print_name,
- rtl8139_print_info
+ {
+ rtl8139_activate,
+ rtl8139_deactivate,
+ rtl8139_deinit,
+ rtl8139_print_name,
+ rtl8139_print_info
+ },
+ network_register_handler
}
};
// 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
#define REG_ISR 0x3E
#define REG_TCR 0x40
#define REG_RCR 0x44
+#define REG_MPC 0x4C
// commands for REG_CMD (command register)
#define CMD_RESET 0x10
#define CMD_RECEIVER_ENABLE 0x08
#define CMD_TRANSMITTER_ENABLE 0x04
+#define CMD_BUFFER_EMPTY 0x01
// mask for reading the version in from the REG_TCR (transmit configuration register)
#define TCR_MODEL_VERSION_AM 0x7C000000
@@ -52,7 +59,10 @@ static rtl8139_vtable_t const rtl8139_vtable = {
// values for REG_RCR (receive configuration register)
#define RCR_MXDMA_UNLIMITED 0x00000700
+#define RCR_RECEIVE_BUFFER_8K_16 0x00000000
+#define RCR_WRAP 0x00000080
#define RCR_ACCEPT_BROADCAST 0x00000008
+#define RCR_ACCEPT_MULTICAST 0x00000004
#define RCR_ACCEPT_PHYS_MATCH 0x00000002
// values for REG_IMR/REG_ISR (interrupt mask/status registers)
@@ -73,8 +83,11 @@ static rtl8139_vtable_t const rtl8139_vtable = {
ISR_RECEIVE_BUFFER_OVERFLOW | ISR_TRANSMIT_ERROR | ISR_TRANSMIT_OK | \
ISR_RECEIVE_ERROR | ISR_RECEIVE_OK
-// for now we follow the guide line on OSDEV on the size of the receive buffer
-#define RECEIVE_BUFFER_SIZE 8192 + 16
+// header
+#define PACKET_HEADER_ROK 0x0001
+
+// receive buffer, set to 8k + header (16) + wrap (2k)
+#define RECEIVE_BUFFER_SIZE 8192 + 16 + 2048
void rtl8139_init( rtl8139_t *rtl8139, pci_device_descriptor_t *descriptor, interrupt_t *interrupt, void *context )
{
@@ -90,11 +103,14 @@ void rtl8139_init( rtl8139_t *rtl8139, pci_device_descriptor_t *descriptor, inte
port8_init( &rtl8139->MAC_port[i], descriptor->port_base + REG_MAC0 + i );
}
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 );
port32_init( &rtl8139->RCR_port, descriptor->port_base + REG_RCR );
+ port32_init( &rtl8139->MPC_port, descriptor->port_base + REG_MPC );
// software reset, the CR_RESET bit remains high till the
// reset is finished
@@ -106,7 +122,8 @@ void rtl8139_init( rtl8139_t *rtl8139, pci_device_descriptor_t *descriptor, inte
rtl8139->base.mac_address.byte[i] = port8_read( &rtl8139->MAC_port[i] );
}
- // enable receiver and transmitter early
+ // enable receiver and transmitter early (TODO: lowlevel says as later as
+ // possible, Osdev and others say as early as possible)
port8_write( &rtl8139->CMD_port, CMD_RECEIVER_ENABLE | CMD_TRANSMITTER_ENABLE );
// get model
@@ -154,20 +171,27 @@ void rtl8139_init( rtl8139_t *rtl8139, pci_device_descriptor_t *descriptor, inte
// initialize TCR/RCR (take Lowlevel suggestions: TCR = 0x03000700, RCR = 0x0000070a)
port32_write( &rtl8139->TCR_port, TCR_IFG_STANDARD | TCR_MXDMA_2048 );
- port32_write( &rtl8139->RCR_port, RCR_MXDMA_UNLIMITED | RCR_ACCEPT_BROADCAST | RCR_ACCEPT_PHYS_MATCH );
+ 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 *)malloc( RECEIVE_BUFFER_SIZE );
+ rtl8139->receive_buffer = (uint8_t *)aligned_alloc( 16, RECEIVE_BUFFER_SIZE + 16 );
+ memset( rtl8139->receive_buffer, 0xFE, RECEIVE_BUFFER_SIZE + 16 );
port32_write( &rtl8139->RBSTART_port, (uint32_t)rtl8139->receive_buffer );
+ rtl8139->receive_buffer_pos = 0;
+
+ // reset missed packet counter
+ port32_write( &rtl8139->MPC_port, 0 );
+
+ interrupt_handler_init( &rtl8139->interrupt_handler, IRQ_BASE + descriptor->interrupt, interrupt, rtl8139_handle_interrupt, rtl8139 );
+ interrupts_register_interrupt_handler( rtl8139->interrupt_handler );
// register interrupts we are interested in (we want all and
// filter them in the interrupt handler), read ISR to clear
// the current values (if there are bits set)
port16_write( &rtl8139->IMR_port, ISR_ALL );
(void)port16_read( &rtl8139->ISR_port );
-
- interrupt_handler_init( &rtl8139->interrupt_handler, IRQ_BASE + descriptor->interrupt, interrupt, rtl8139_handle_interrupt, rtl8139 );
- interrupts_register_interrupt_handler( rtl8139->interrupt_handler );
rtl8139_print_info( rtl8139 );
@@ -195,14 +219,158 @@ void rtl8139_deinit( void *obj )
free( rtl8139->receive_buffer );
}
+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 );
+
+ // still data in the buffer
+ if( data & CMD_BUFFER_EMPTY ) {
+ break;
+ }
+
+ 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;
+ }
+ buffer += sizeof( uint16_t );
+
+ // buffer is 16-bit alligned
+ uint16_t len = *( (uint16_t *)buffer );
+ buffer += sizeof( uint16_t );
+#ifdef DEBUG
+ printf( "rtl8139: rcv len: %d\n", len );
+#endif
+
+ for( int i = 0; i < len; i++ ) {
+ }
+
+ }
+
+#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))
+ {
+ uint8_t data[length - 4];
+ if ((netcard->rx_buffer_offset + length - 4) >= RX_BUFFER_SIZE) {
+ // FIXME Beim Umbruch gehen Daten kaputt
+ memcpy(data, buffer, RX_BUFFER_SIZE - netcard->rx_buffer_offset);
+ memcpy(
+ data + RX_BUFFER_SIZE - netcard->rx_buffer_offset,
+ netcard->rx_buffer,
+ (length - 4) - (RX_BUFFER_SIZE - netcard->rx_buffer_offset)
+ );
+ } else {
+ memcpy(data, buffer, length - 4);
+ }
+
+ cdi_net_receive(
+ (struct cdi_net_device*) netcard,
+ data,
+ 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;
+
+ write_register_word(netcard, REG_CUR_READ_ADDR,
+ netcard->rx_buffer_offset - 0x10);
+
+
+
+ }
+#endif
+}
+
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;
+
+ port16_write( &rtl8139->ISR_port, isr );
+
#ifdef DEBUG
- printf( "RTL8139 INTERRUPT\n" );
+ printf( "rtl8139: INTERRUPT: %X\n", isr );
#endif
+
+ if( isr & ISR_RECEIVE_OK ) {
+ // 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 );
+
return esp;
}
@@ -217,7 +385,9 @@ void rtl8139_print_info( void *obj )
char buf[20];
char buf2[30];
- snprintf( buf2, 30, "unknown submodel 0x%X", rtl8139->model_id );
+ if( rtl8139->model == NULL ) {
+ snprintf( buf2, 30, "unknown submodel 0x%X", rtl8139->model_id );
+ }
network_mac_to_string( rtl8139->base.mac_address, buf, 20 );
printf( "rtl8139 NIC type %s\n at I/O base 0x%X, interrupt 0x%X, MAC: %s\n",
( rtl8139->model != NULL ) ? rtl8139->model : buf2,