From 99e393eaccf2e07e6b89df3fe96d89b521da1997 Mon Sep 17 00:00:00 2001 From: Niels Sascha Reedijk Date: Sun, 15 Jun 2003 20:10:09 +0000 Subject: [PATCH] I have changed the way packet reception is handled. Instead of managing it at the interrupt handler, now it is done in the read_hook itself. This means that less memory is used because the packet reception isn't double-buffered anymore. It also wasn't the performance it I'd expect it to be (probably thanks to BeOS scheduling!). The problem with the strange loss of around 50% of the packets remains. git-svn-id: file:///srv/svn/repos/haiku/trunk/current@3526 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../kernel/drivers/network/rtl8139/Jamfile | 1 - .../kernel/drivers/network/rtl8139/driver.c | 166 ++++++++++++------ .../drivers/network/rtl8139/packetlist.c | 57 ------ .../drivers/network/rtl8139/packetlist.h | 21 --- 4 files changed, 109 insertions(+), 136 deletions(-) delete mode 100644 src/add-ons/kernel/drivers/network/rtl8139/packetlist.c delete mode 100644 src/add-ons/kernel/drivers/network/rtl8139/packetlist.h diff --git a/src/add-ons/kernel/drivers/network/rtl8139/Jamfile b/src/add-ons/kernel/drivers/network/rtl8139/Jamfile index 9648813b19..fc58b43450 100644 --- a/src/add-ons/kernel/drivers/network/rtl8139/Jamfile +++ b/src/add-ons/kernel/drivers/network/rtl8139/Jamfile @@ -14,7 +14,6 @@ SubDir OBOS_TOP src add-ons kernel drivers network rtl8139 ; R5KernelAddon rtl8139 : [ FDirName kernel drivers network ] : driver.c - packetlist.c util.c ; diff --git a/src/add-ons/kernel/drivers/network/rtl8139/driver.c b/src/add-ons/kernel/drivers/network/rtl8139/driver.c index 2f33b28671..b0cb89847f 100644 --- a/src/add-ons/kernel/drivers/network/rtl8139/driver.c +++ b/src/add-ons/kernel/drivers/network/rtl8139/driver.c @@ -34,7 +34,6 @@ #include "ether_driver.h" #include "util.h" -#include "packetlist.h" /* ---------- global data @@ -161,6 +160,7 @@ typedef struct rtl8139_properties ether_address_t address; /* holds the MAC address */ sem_id lock; /* lock this structure: still interrupt */ sem_id input_wait; /* locked until there is a packet to be read */ + uint8 nonblocking; /* determines if the card blocks on read requests */ } rtl8139_properties_t; typedef struct packetheader @@ -216,7 +216,7 @@ init_driver (void) // Try if the PCI module is loaded (it would be weird if it wouldn't, but alas) if( ( status = get_module( B_PCI_MODULE_NAME, (module_info **)&m_pcimodule )) != B_OK) { - dprintf( "rtl8139_nielx init_driver(): Get PCI module failed! %u\n", status); + dprintf( "rtl8139_nielx init_driver(): Get PCI module failed! %lu \n", status); return status; } @@ -311,7 +311,6 @@ open_hook(const char *name, uint32 flags, void** cookie) set_sem_owner( data->lock , B_SYSTEM_TEAM ); data->input_wait = create_sem( 0 , "rtl8139_nielx read wait" ); set_sem_owner( data->input_wait , B_SYSTEM_TEAM ); - set_sem( data->input_wait ); //give the packet list the sem //Set up the cookie data->pcii = m_device; @@ -403,6 +402,8 @@ open_hook(const char *name, uint32 flags, void** cookie) m_pcimodule->write_io_32( data->reg_base + RxConfig , /*RXFTH2 | RXFTH1 | */ RBLEN_1 | RBLEN_0 | WRAP | MXDMA_2 | MXDMA_1 | APM | AB); + //Disable blocking + data->nonblocking = 0; //Allocate the ring buffer for the receiver. // Size is set above: as 16k + 16 bytes + 1.5 kB--- 16 bytes for last CRC (a data->receivebuffer = alloc_mem( &(data->receivebufferlog) , &(data->receivebufferphy) , 1024 * 64 + 16 , "rx buffer" ); @@ -500,32 +501,67 @@ static status_t read_hook (void* cookie, off_t position, void *buf, size_t* num_bytes) { rtl8139_properties_t *data =/* (rtl8139_properties_t *)*/cookie; - uint16 length; - net_packet_t *packet; + packetheader_t *packet_header; dprintf( "rtl8139_nielx: read_hook()\n" ); - acquire_sem_etc( data->input_wait , 1 , B_CAN_INTERRUPT , 0 ); - - packet = get_packet(); - if ( packet == 0 ) //No packets in queue - return B_ERROR; - - if ( packet->len > *num_bytes ) + //if( !data->nonblocking ) + acquire_sem_etc( data->input_wait , 1 , B_CAN_INTERRUPT , 0 ); + + //Next: check in command register if there's actually anything to be read + if ( m_pcimodule->read_io_8( data->reg_base + Command ) & BUFE ) { - free( packet->buffer ); - free ( packet ); + dprintf( "rtl8139_nielx read_hook: Nothing to read!!!\n" ); return B_IO_ERROR; - } + } - length = packet->len; + // Retrieve the packet header + packet_header = (packetheader_t *) ( ( uint8 *)data->receivebufferlog + data->receivebufferoffset ); - memcpy( buf , packet->buffer , length ); + // Check if the transfer is already done: EarlyRX + if ( packet_header->length == 0xfff0 ) + { + dprintf( "rtl8139_nielx read_hook: The transfer is not yet finished!!!\n" ); + return B_IO_ERROR; + } - free( packet->buffer ); - free( packet ); + //Check for an error: if needed: resetrx + if ( !( packet_header->bits & 0x1 ) || packet_header->length > 1500 ) + { + dprintf( "rtl8139_nielx read_hook: Error in package reception!!!\n" ); + return B_IO_ERROR; + } - return length; + dprintf( "rtl8139_nielx read_hook(): Packet size: %u Receiveheader: %u Buffer size: %lu\n" , packet_header->length , packet_header->bits , *num_bytes ); + + // Check if the packet goes beyond the buffer + /* + if ( bufferoffset + packet_header.length > 1024 * 16 + 16 ) + { + dprintf( "rtl8139_nielx read_hook(): Packet goes beyond end of buffer!\n" ); + //Taken from sample code, I have no idea whether it works + memcpy( data->receivebufferlog + 1024 * 16 + 16 , data->receivebufferlog , (bufferoffset + packet_header.length - 1024 * 16 + 16 ) ); + } + */ + + //Copy the packet + *num_bytes = packet_header->length - 4; + memcpy( buf , data->receivebufferlog + data->receivebufferoffset + 4 , packet_header->length - 4); //length-4 because we don't want to copy the 4 bytes CRC + + //Update the buffer -- 4 for the header length, plus 3 for the dword allignment + data->receivebufferoffset = ( data->receivebufferoffset + packet_header->length + 4 + 3 ) & ~3; + + m_pcimodule->write_io_16( data->reg_base + CAPR , data->receivebufferoffset - 16 ); //-16, avoid overflow + + dprintf( "rtl8139_nielx read_hook(): CBP %u CAPR %u \n" , m_pcimodule->read_io_16( data->reg_base + CBR ) , m_pcimodule->read_io_16( data->reg_base + CAPR ) ); + + // Re-enable interrupts + m_pcimodule->write_io_16( data->reg_base + ISR , ReceiveOk ); + m_pcimodule->write_io_16( data->reg_base + IMR , + ReceiveOk | ReceiveError | TransmitOk | TransmitError | + ReceiveOverflow | ReceiveUnderflow | ReceiveFIFOOverrun | + TimeOut | SystemError ); + return packet_header->length - 4; } @@ -574,7 +610,7 @@ write_hook (void* cookie, off_t position, const void* buffer, size_t* num_bytes) else data->nexttransmitstatus++; - dprintf( "rtl8139_nielx write_hook(): TransmitID: %u Packagelen: %u Register: %x\n" , transmitid , buflen , TSD0 + (sizeof(uint32) * transmitid ) ); + dprintf( "rtl8139_nielx write_hook(): TransmitID: %u Packagelen: %u Register: %lx\n" , transmitid , buflen , TSD0 + (sizeof(uint32) * transmitid ) ); if ( transmitid == -1 ) { @@ -596,7 +632,7 @@ write_hook (void* cookie, off_t position, const void* buffer, size_t* num_bytes) //Clear OWN and start transfer Create transmit description with early Tx FIFO, size transmitdescription = ( buflen | 0x80000 | transmitdescription ) ^OWN; //0x80000 = early tx treshold - dprintf( "rtl8139_nielx write: transmitdescription = %u\n" , transmitdescription ); + dprintf( "rtl8139_nielx write: transmitdescription = %lu\n" , transmitdescription ); m_pcimodule->write_io_32( data->reg_base + TSD0 + (sizeof(uint32) * transmitid ) , transmitdescription ); dprintf( "rtl8139_nielx write: TSAD: %u\n" , m_pcimodule->read_io_16( data->reg_base + TSAD ) ); @@ -614,12 +650,16 @@ static status_t control_hook (void* cookie, uint32 op, void* arg, size_t len) { rtl8139_properties_t *data = (rtl8139_properties_t *)cookie; - + ether_address_t address; dprintf( "rtl8139_nielx control_hook()\n" ); switch ( op ) { + case ETHER_INIT: + dprintf( "rtl8139_nielx control_hook(): Wants us to init... ;-)\n" ); + return B_NO_ERROR; + case ETHER_GETADDR: if ( data == NULL ) return B_ERROR; @@ -627,6 +667,46 @@ control_hook (void* cookie, uint32 op, void* arg, size_t len) dprintf( "rtl8139_nielx control_hook(): Wants our address...\n" ); memcpy( arg , (void *) &(data->address) , sizeof( ether_address_t ) ); return B_OK; + + case ETHER_ADDMULTI: + if (data == NULL ) + return B_ERROR; + //Check if the maximum of multicast addresses isn't reached + if ( data->multiset == 8 ) + return B_ERROR; + + dprintf( "rtl8139_nielx control_hook(): Add multicast...\n" ); + memcpy( &address , arg , sizeof( address ) ); + dprintf( "Multicast address: %i %i %i %i %i %i \n" , address.ebyte[0] , + address.ebyte[1] , address.ebyte[2] , address.ebyte[3] , address.ebyte[4] , + address.ebyte[5] ); + return B_OK; + + /*data->multiset; + m_pcimodule->write_io_32( MAR0 , address[0] ); //First 32 bits + m_pcimodule->write_io_32( MAR0 + 0x4 , address + */ + + case ETHER_NONBLOCK: + if ( data == NULL ) + return B_ERROR; + + dprintf( "rtl8139_nielx control_hook(): Wants to set block/nonblock\n" ); + memcpy( &data->nonblocking , arg , sizeof( data->nonblocking ) ); + return B_NO_ERROR; + + case ETHER_REMMULTI: + dprintf( "rtl8139_nielx control_hook(): Wants REMMULTI\n" ); + return B_OK; + + case ETHER_SETPROMISC: + dprintf("rtl8139_nielx control_hook(): Wants PROMISC\n" ); + return B_OK; + + case ETHER_GETFRAMESIZE: + dprintf("rtl8139_nielx control_hook(): Wants GETFRAMESIZE\n" ) ; + *( (unsigned int *)arg ) = 1514; + return B_OK; } return B_BAD_VALUE; } @@ -652,39 +732,11 @@ rtl8139_interrupt( void *cookie ) dprintf( "NIELX INTERRUPT: %u \n" , isr_contents ); if( isr_contents & ReceiveOk ) { - dprintf( "rtl8139_nielx interrupt ReceiveOk: %x\n" , m_pcimodule->read_io_16( data->reg_base + CBR ) ); - isr_write |= ReceiveOk; - retval = B_HANDLED_INTERRUPT; - //Next: check in command register if there's actually anything to be read - while ( !( m_pcimodule->read_io_8( data->reg_base + Command ) & BUFE ) ) - { - packetheader_t *packet_header; - - // Retrieve the packet header - packet_header = (packetheader_t *) ( ( uint8 *)data->receivebufferlog + data->receivebufferoffset ); - - // Check if the transfer is already done: EarlyRX THIS SHOULD NEVER HAPPEN - if ( packet_header->length == 0xfff0 ) - { - dprintf( "rtl8139_nielx interrupt: The transfer is not yet finished!!!\n" ); - break; - } - - //Check for an error: if needed: resetrx - if ( !( packet_header->bits & 0x1 ) || packet_header->length > 1500 ) - { - dprintf( "rtl8139_nielx Interrupt: Error in package reception!!!\n" ); - break; - } - - //Append the packet to the list - append_packet( data->receivebufferlog + data->receivebufferoffset + 4 , packet_header->length - 4 ); //-4 -- we don't want CRC - - //Update read pointer - data->receivebufferoffset = ( data->receivebufferoffset + packet_header->length + 4 + 3 ) & ~3; - m_pcimodule->write_io_16( data->reg_base + CAPR , data->receivebufferoffset - 16 ); //-16, avoid overflow - dprintf( "rtl8139_nielx interrupt: Packet received ok!!!\n" ); - } + dprintf( "rtl8139_nielx interrupt ReceiveOk\n" ); + release_sem_etc( data->input_wait , 1 , B_DO_NOT_RESCHEDULE ); + // First, disable all interrupts until the read hook is finished. It will re-enable them. + m_pcimodule->write_io_16( data->reg_base + IMR , 0 ); + retval = B_INVOKE_SCHEDULER; } if (isr_contents & ReceiveError ) @@ -702,7 +754,7 @@ rtl8139_interrupt( void *cookie ) if ( data->transmitstatus[temp8] != 1 ) continue; txstatus = m_pcimodule->read_io_32( data->reg_base + TSD0 + temp8 * sizeof( int32 ) ); - dprintf( "run: %u txstatus: %u Register: %x\n" , temp8 , txstatus , TSD0 + temp8 * sizeof( int32 ) ); + dprintf( "run: %u txstatus: %lu Register: %lx\n" , temp8 , txstatus , TSD0 + temp8 * sizeof( int32 ) ); //m_pcimodule->write_io_32( data->reg_base + TSAD0 + temp8 * sizeof( int32) , (m_pcimodule->read_io_32( data->reg_base + TSAD0 + temp8 * sizeof( int32 ) ) ) | OWN ) ; diff --git a/src/add-ons/kernel/drivers/network/rtl8139/packetlist.c b/src/add-ons/kernel/drivers/network/rtl8139/packetlist.c deleted file mode 100644 index d6a79b0a44..0000000000 --- a/src/add-ons/kernel/drivers/network/rtl8139/packetlist.c +++ /dev/null @@ -1,57 +0,0 @@ -#include "packetlist.h" -#include - -static net_packet_list_t *firstpacketlist = 0; -static net_packet_list_t *lastpacketlist = 0; -static sem_id mysem; - -void append_packet( void *pointer , int16 size ) -{ - net_packet_list_t *temp; - - temp = (net_packet_list_t *) malloc( sizeof( net_packet_list_t ) ); - temp->packet = (net_packet_t *) malloc( sizeof( net_packet_t ) ); - temp->next = 0; - temp->packet->len = size; - temp->packet->buffer = (void *) malloc( size ); - memcpy( temp->packet->buffer , pointer , size ); - - //This is the first packet - if (firstpacketlist == 0 ) - firstpacketlist = temp; - - if ( lastpacketlist == 0 ) - lastpacketlist = temp; - else - { - lastpacketlist->next = temp; - lastpacketlist = temp; - } - //Release the semaphore with 1, so with each packet read can do a run - release_sem_etc( mysem , 1 , B_DO_NOT_RESCHEDULE ); -} - -net_packet_t *get_packet() -{ - net_packet_list_t *temp; - net_packet_t *retval; - - if ( firstpacketlist == 0 ) - return 0; - - temp = firstpacketlist->next; - retval = firstpacketlist->packet; - free( firstpacketlist ); - - if ( temp == 0 ) //There are no more packets in teh queue - { - firstpacketlist = 0; - lastpacketlist = 0; - } - return retval; -} - -void set_sem( sem_id sem ) -{ - mysem = sem; -} diff --git a/src/add-ons/kernel/drivers/network/rtl8139/packetlist.h b/src/add-ons/kernel/drivers/network/rtl8139/packetlist.h deleted file mode 100644 index e532d396a4..0000000000 --- a/src/add-ons/kernel/drivers/network/rtl8139/packetlist.h +++ /dev/null @@ -1,21 +0,0 @@ -/* This file describes a netpacket kernel buffer */ - -#include - -typedef struct net_packet -{ - void *buffer; /* Contains the packet without CRC */ - uint16 len; /* Contains the length of the packet */ -} net_packet_t; - -struct net_packet_list; - -typedef struct net_packet_list { - net_packet_t *packet; /* Contains a pointer to the current packet */ - struct net_packet_list *next; /* Contains a pointer to the next packet -- if 0, then ther is none */ -} net_packet_list_t; - - -net_packet_t *get_packet(); -void append_packet( void *pointer , int16 size ); -void set_sem( sem_id sem );