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
This commit is contained in:
parent
7ee2c8049c
commit
99e393eacc
@ -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
|
||||
;
|
||||
|
||||
|
@ -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 ) ;
|
||||
|
||||
|
@ -1,57 +0,0 @@
|
||||
#include "packetlist.h"
|
||||
#include <malloc.h>
|
||||
|
||||
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;
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
/* This file describes a netpacket kernel buffer */
|
||||
|
||||
#include <KernelExport.h>
|
||||
|
||||
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 );
|
Loading…
x
Reference in New Issue
Block a user