Sync with local repository:

1.23: fix some compile errors on PPC
1.24: Finalising some PPC changes. In theory it should work
1.25: Second round of PPC fixes. I hope it works now.
1.26: Adding the reset function when there are rx problems
1.27: Added the chip id for the 8101L
1.28: Minor code cleanup
1.29: Implemented multipe card support
1.30: drop some debug output
1.31: FINALLY fixed the receive problem (where large packets slow down
      everything)
What remains to be done is to fix the transmit bug, where the card
suddenly stops to send packets (after it gets behind by one).


git-svn-id: file:///srv/svn/repos/haiku/trunk/current@3993 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Niels Sascha Reedijk 2003-07-16 18:55:26 +00:00
parent e793a55e78
commit 5767925f0e
2 changed files with 349 additions and 227 deletions

View File

@ -31,23 +31,30 @@
#include <Errors.h>
#include <PCI.h>
#include <malloc.h>
#include <stdio.h>
#include <string.h>
#include "ether_driver.h"
#include "util.h"
#define RTL_MAX_CARDS 4
//#define RTL_NODEBUG
#define RTL_NODEBUG
#ifdef RTL_NODEBUG
#define dprintf no_printf
#define TRACE no_printf
void no_printf( const char *useless , ... ) {};
#else
#define TRACE TRACE
#endif
/* ----------
global data
----- */
static pci_info *m_device = 0;
static pci_info *m_devices[RTL_MAX_CARDS];
static pci_module_info *m_pcimodule = 0; //To call methods of pci
static int16 m_isopen = 0; //Is the thing already opened?
static char *rtl8139_names[RTL_MAX_CARDS +1];
static int32 m_openmask = 0; //Is the thing already opened?
int32 api_version = B_CUR_DRIVER_API_VERSION; //Procedure
@ -116,7 +123,11 @@ enum Receiver_actions {
enum TransmitDescription {
OWN = 0x2000 ,
TOK = 0x8000
TUN = 0x4000 ,
TOK = 0x8000 ,
OWC = 0x20000000 ,
TABT = 0x40000000 ,
CRS = 0x80000000
};
@ -138,7 +149,7 @@ enum BMCR_Commands {
Restart_Auto_Negotiation = 0x400
};
typedef enum chiptype { RTL_8139_C , RTL_8139_D } chiptype;
typedef enum chiptype { RTL_8139_C , RTL_8139_D , RTL_8101_L } chiptype;
/* ----------
structure that stores internal data
@ -148,7 +159,9 @@ typedef struct rtl8139_properties
{
pci_info *pcii; /* Pointer to PCI Info for the device */
uint32 reg_base; /* Base address for registers */
area_id ioarea; /* PPC: Area where the mmaped registers are */
chiptype chip_type; /* Storage for the chip type */
uint8 device_id; /* Which device id this is... */
area_id receivebuffer; /* Memoryaddress for the receive buffer */
void *receivebufferlog; /* Logical address */
@ -160,13 +173,14 @@ typedef struct rtl8139_properties
void *transmitbufferlog[4]; /* Logical addresses of the transmit buffer */
void *transmitbufferphy[4]; /* Physical addresses of the transmit buffer */
uint8 transmitstatus[4]; /* Transmitstatus: 0 means empty and 1 means in use */
uint8 nexttransmitstatus;
uint32 queued_packets; /* Number of queued tx that have been written */
uint32 finished_packets; /* Number of finished transfers */
uint8 multiset; /* determines if multicast address is set */
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 */
uint8 nonblocking; /* determines if the card blocks on read requests */
} rtl8139_properties_t;
typedef struct packetheader
@ -192,17 +206,40 @@ static status_t close_hook( void * );
void rtl8139_init_registers( rtl8139_properties_t *data )
{
data->reg_base = data->pcii->u.h0.base_registers[0];
//TRACE( "NIELX@@: registers %lu\n" , data->reg_base );
}
#else /* PPC */
#include <ByteOrder.h>
#define WRITE_8( offset , value) (*((volatile uint8 *)(data->reg_base + (offset))) = (value))
#define WRITE_16( offset , value) (*((volatile uint8 *)(data->reg_base + (offset))) = B_HOST_TO_LENDIAN_INT16(value))
#define WRITE_32( offset , value) (*((volatile uint8 *)(data->reg_base + (offset))) = B_HOST_TO_LENDIAN_INT32(value))
#define READ_8( offset ) (*((volatile uint8*)(data->reg_base + (offset))))
#define READ_16( offset ) B_LENDIAN_TO_HOST_INT16(*((volatile uint16*)(data->reg_base + (offset))))
#define READ_32( offset ) B_LENDIAN_TO_HOST_INT32(*((volatile uint32*)(data->reg_base + (offset))))
void rtl8139_init_registers( rtl8139_properties_t *data )
{
int32 base, size, offset;
base = data->pcii->u.h0.base_registers[0];
size = data->pcii->u.h0.base_register_sizes[0];
/* Round down to nearest page boundary */
base = base & ~(B_PAGE_SIZE-1);
/* Adjust the size */
offset = data->pcii->u.h0.base_registers[0] - base;
size += offset;
size = (size +(B_PAGE_SIZE-1)) & ~(B_PAGE_SIZE-1);
TRACE("rtl8139_nielx _open_hook(): PCI base=%lx size=%lx offset=%lx\n", base, size, offset);
data->ioarea = map_physical_memory("rtl8139_regs", (void *)base, size, B_ANY_KERNEL_ADDRESS, B_READ_AREA | B_WRITE_AREA, (void **)&data->reg_base);
data->reg_base = data->reg_base + offset;
}
#endif
/* -----
null-terminated array of device names supported by this driver
----- */
static const char *rtl8139_name[] = {
"net/rtl8139/0",
NULL
};
/* ----------
init_hardware - called once the first time the driver is loaded
@ -211,7 +248,7 @@ status_t
init_hardware (void)
{
// Nielx: no special requirements here...
dprintf( "rtl8139_nielx: init_hardware\n" );
TRACE( "rtl8139_nielx: init_hardware\n" );
return B_OK;
}
@ -225,55 +262,60 @@ init_driver (void)
{
status_t status; //Storage for statuses
pci_info *item; //Storage used while looking through pci
int32 i; //Counter
m_device = 0; //...
/*
Nielx: Some notes
- I will implement multiple cards later
- For now this thing just searches for the card and use it.
*/
dprintf( "rtl8139_nielx: init_driver()\n" );
int32 i, found; //Counter
TRACE( "rtl8139_nielx: init_driver()\n" );
// 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! %lu \n", status);
TRACE( "rtl8139_nielx init_driver(): Get PCI module failed! %lu \n", status);
return status;
}
//
i = 0;
item = (pci_info *)malloc(sizeof(pci_info));
while( true )
for ( i = found = 0 ; m_pcimodule->get_nth_pci_info(i, item) == B_OK ; i++ )
{
if ((status = m_pcimodule->get_nth_pci_info(i, item)) != B_OK)
break;
// Vendorid = 0x10ec and device_id = 0x8139
if ( ( item->vendor_id == 0x10ec ) && ( item->device_id == 0x8139 ) )
{
//Also done in etherpci sample code
if ((item->u.h0.interrupt_line == 0) || (item->u.h0.interrupt_line == 0xFF)) {
dprintf( "rtl8139_nielx init_driver(): found with invalid IRQ - check IRQ assignement\n");
if ((item->u.h0.interrupt_line == 0) || (item->u.h0.interrupt_line == 0xFF))
{
TRACE( "rtl8139_nielx init_driver(): found with invalid IRQ - check IRQ assignement\n");
i++; //next
continue;
}
dprintf("rtl8139_nielx init_driver(): found at IRQ %u \n", item->u.h0.interrupt_line);
m_device = item;
break;
TRACE("rtl8139_nielx init_driver(): found at IRQ %u \n", item->u.h0.interrupt_line);
m_devices[found] = item;
item = (pci_info *)malloc(sizeof(pci_info));
found++;
}
i++; //Look for the next one
}
free( item );
//Check if we have found any devices:
if ( m_device == 0 )
if ( found == 0 )
{
dprintf( "rtl8139_nielx init_driver(): no device found\n" );
TRACE( "rtl8139_nielx init_driver(): no device found\n" );
put_module(B_PCI_MODULE_NAME ); //dereference module
return ENODEV;
}
//Create the devices list
{
char name[32];
for (i = 0; i < found; i++)
{
sprintf(name, "net/rtl8139/%ld", i);
rtl8139_names[i] = strdup(name);
}
rtl8139_names[i] = NULL;
}
return B_OK;
}
@ -285,7 +327,16 @@ init_driver (void)
void
uninit_driver (void)
{
free ( m_device );
int index;
void *item;
TRACE( "rtl8139_nielx: uninit_driver()\n" );
for (index = 0; (item = rtl8139_names[index]) != NULL; index++)
{
free(item);
free(m_devices[index]);
}
put_module( B_PCI_MODULE_NAME );
}
@ -294,6 +345,9 @@ uninit_driver (void)
open_hook - handle open() calls
----- */
//FWD declaration:
static status_t free_hook( void *cookie );
static status_t
open_hook(const char *name, uint32 flags, void** cookie)
{
@ -304,32 +358,43 @@ open_hook(const char *name, uint32 flags, void** cookie)
uint32 temp32;
unsigned char cmd;
dprintf( "rtl8139_nielx open_hook()\n" );
// Check if the device name is ours
if ( strcmp( name , rtl8139_name[0] ) != 0 )
return EINVAL;
if ( m_isopen == 1 )
{
dprintf( "rtl8139_nielx open_hook(): Device already in use\n" );
return B_BUSY;
}
TRACE( "rtl8139_nielx open_hook()\n" );
//We are now officially opening (don't know if it is possible that there
//are multiple calls, however, this could prevent some ugly bugs)
m_isopen = 1;
// verify device access
{
char *thisName;
int32 mask;
// search for device name
for (temp8 = 0; (thisName = rtl8139_names[temp8]) != NULL; temp8++) {
if (!strcmp(name, thisName))
break;
}
if (!thisName)
return EINVAL;
// check if device is already open
mask = 1L << temp8;
if (atomic_or(&m_openmask, mask) & mask)
return B_BUSY;
}
//Create a structure that contains the internals
if (!(*cookie = data = (rtl8139_properties_t *)malloc(sizeof(rtl8139_properties_t))))
{
dprintf( "rtl8139_nielx open_hook(): Out of memory\n" );
m_isopen = 0;
TRACE( "rtl8139_nielx open_hook(): Out of memory\n" );
return B_NO_MEMORY;
}
//Set status to open:
m_openmask &= ~( 1L << temp8 );
//Clear memory
memset( data , 0 , sizeof( rtl8139_properties_t ) );
//Set the ID
data->device_id = temp8;
// Create lock
data->lock = create_sem( 1 , "rtl8139_nielx data protect" );
set_sem_owner( data->lock , B_SYSTEM_TEAM );
@ -337,7 +402,7 @@ open_hook(const char *name, uint32 flags, void** cookie)
set_sem_owner( data->input_wait , B_SYSTEM_TEAM );
//Set up the cookie
data->pcii = m_device;
data->pcii = m_devices[data->device_id];
//Enable the registers
rtl8139_init_registers( data );
@ -352,8 +417,8 @@ open_hook(const char *name, uint32 flags, void** cookie)
if ( temp32 == 0xFFFFFF )
{
dprintf( "rtl8139_nielx open_hook(): Faulty chip\n" );
m_isopen = 0;
TRACE( "rtl8139_nielx open_hook(): Faulty chip\n" );
free_hook( cookie );
put_module( B_PCI_MODULE_NAME );
return EIO;
}
@ -363,17 +428,22 @@ open_hook(const char *name, uint32 flags, void** cookie)
switch( temp32 )
{
case 0x74000000:
dprintf( "rtl8139_nielx open_hook(): Chip is the 8139 C\n" );
TRACE( "rtl8139_nielx open_hook(): Chip is the 8139 C\n" );
data->chip_type = RTL_8139_C;
break;
case 0x74400000:
dprintf( "rtl8139_niels open_hook(): Chip is the 8139 D\n" );
TRACE( "rtl8139_niels open_hook(): Chip is the 8139 D\n" );
data->chip_type = RTL_8139_D;
break;
case 0x74C00000:
TRACE( "rtl8139_nielx open_hook(): Chip is the 8101L\n" );
data->chip_type = RTL_8101_L;
break;
default:
dprintf( "rtl8139_nielx open_hook(): Unknown chip, assuming 8139 C\n" );
TRACE( "rtl8139_nielx open_hook(): Unknown chip, assuming 8139 C\n" );
data->chip_type = RTL_8139_C;
}
@ -387,12 +457,11 @@ open_hook(const char *name, uint32 flags, void** cookie)
if ( temp16 == 0 )
{
dprintf( "rtl8139_nielx open_hook(): Reset failed... Bailing out\n" );
m_isopen = 0;
free( data );
TRACE( "rtl8139_nielx open_hook(): Reset failed... Bailing out\n" );
free_hook( cookie );
return EIO;
}
dprintf( "rtl8139_nielx open_hook(): Chip reset: %u \n" , temp16 );
TRACE( "rtl8139_nielx open_hook(): Chip reset: %u \n" , temp16 );
/* Enable writing to the configuration registers */
WRITE_8( _9346CR , 0xc0 );
@ -419,7 +488,7 @@ open_hook(const char *name, uint32 flags, void** cookie)
//settings: Max DMA burst size per Tx DMA burst is 1024 ( = 110 )
//settings: Interframe GAP time according to IEEE standard ( = 11 )
WRITE_32( TxConfig ,
READ_32( TxConfig ) | MXDMA_2 | MXDMA_1 );
IFG_1 | IFG_0 | MXDMA_1 );
/* Configure the Receive Register */
//settings: Early Rx Treshold is 1024 kB ( = 110 ) DISABLED
@ -436,7 +505,7 @@ open_hook(const char *name, uint32 flags, void** cookie)
data->receivebuffer = alloc_mem( &(data->receivebufferlog) , &(data->receivebufferphy) , 1024 * 64 + 16 , "rx buffer" );
if( data->receivebuffer == B_ERROR )
{
dprintf( "rtl8139_nielx open_hook(): memory allocation for ringbuffer failed\n" );
TRACE( "rtl8139_nielx open_hook(): memory allocation for ringbuffer failed\n" );
return B_ERROR;
}
WRITE_32( RBSTART , (int32) data->receivebufferphy );
@ -449,35 +518,31 @@ open_hook(const char *name, uint32 flags, void** cookie)
data->transmitbuffer[0] = alloc_mem( &(data->transmitbufferlog[0]) , &(data->transmitbufferphy[0]) , 4096 , "txbuffer01" );
WRITE_32( TSAD0 , (int32)data->transmitbufferphy[0] );
data->transmitbuffer[1] = data->transmitbuffer[0];
data->transmitbufferlog[1] = data->transmitbufferlog[0] + 2048;
data->transmitbufferphy[1] = data->transmitbufferphy[0] + 2048;
data->transmitbufferlog[1] = (void *)( (uint32)data->transmitbufferlog[0] + 2048 );
data->transmitbufferphy[1] = (void *)( (uint32)data->transmitbufferphy[0] + 2048 );
WRITE_32( TSAD1 , (int32)data->transmitbufferphy[1] );
data->transmitbuffer[2] = alloc_mem( &(data->transmitbufferlog[2]) , &(data->transmitbufferphy[2]) , 4096 , "txbuffer23" );
WRITE_32( TSAD2 , (int32)data->transmitbufferphy[2] );
data->transmitbuffer[3] = data->transmitbuffer[2];
data->transmitbufferlog[3] = data->transmitbufferlog[2] + 2048;
data->transmitbufferphy[3] = data->transmitbufferphy[2] + 2048;
data->transmitbufferlog[3] = (void *)( (uint32)data->transmitbufferlog[2] + 2048 );
data->transmitbufferphy[3] = (void *)( (uint32)data->transmitbufferphy[2] + 2048 );
WRITE_32( TSAD3 , (int32)data->transmitbufferphy[3] );
if( data->transmitbuffer[0] == B_ERROR || data->transmitbuffer[2] == B_ERROR )
{
dprintf( "rtl8139_nielx open_hook(): memory allocation for transmitbuffer failed\n" );
TRACE( "rtl8139_nielx open_hook(): memory allocation for transmitbuffer failed\n" );
return B_ERROR;
}
data->nexttransmitstatus = 0;
data->queued_packets = 0;
data->finished_packets = 0;
// Receive hardware MAC address
// Suggestion by Marcus Overhagen: Make it a nice for loop...
temp8 = 0;
do
{
for( temp8 = 0 ; temp8 < 6; temp8++ )
data->address.ebyte[ temp8 ] = READ_8( IDR0 + temp8 );
temp8++;
} while ( temp8 < 6 );
dprintf( "rlt8139_nielx open_hook(): MAC address: %x:%x:%x:%x:%x:%x\n",
TRACE( "rlt8139_nielx open_hook(): MAC address: %x:%x:%x:%x:%x:%x\n",
data->address.ebyte[0] , data->address.ebyte[1] , data->address.ebyte[2] ,
data->address.ebyte[3] , data->address.ebyte[4] , data->address.ebyte[5] );
@ -493,7 +558,7 @@ open_hook(const char *name, uint32 flags, void** cookie)
/* We want interrupts! */
if ( install_io_interrupt_handler( data->pcii->u.h0.interrupt_line , rtl8139_interrupt , data , 0 ) != B_OK )
{
dprintf( "rtl8139_nielx open_hook(): Error installing interrupt handler\n" );
TRACE( "rtl8139_nielx open_hook(): Error installing interrupt handler\n" );
return B_ERROR;
}
@ -508,11 +573,11 @@ open_hook(const char *name, uint32 flags, void** cookie)
//Check if Tx and Rx are enabled
if( !( READ_8( Command ) & EnableReceive ) || !( READ_8( Command ) & EnableTransmit ) )
dprintf( "TRANSMIT AND RECEIVE NOT ENABLED!!!\n" );
TRACE( "TRANSMIT AND RECEIVE NOT ENABLED!!!\n" );
else
dprintf( "TRANSMIT AND RECEIVE ENABLED!!!\n" );
TRACE( "TRANSMIT AND RECEIVE ENABLED!!!\n" );
dprintf( "rtl8139_nielx open_hook(): Basic Mode Status Register: 0x%x ESRS: 0x%x\n" ,
TRACE( "rtl8139_nielx open_hook(): Basic Mode Status Register: 0x%x ESRS: 0x%x\n" ,
READ_16( BMSR ) ,
READ_8( ESRS ) );
@ -520,6 +585,31 @@ open_hook(const char *name, uint32 flags, void** cookie)
}
/* --------------
rtl8139_reset - resets the card
----- */
static void rtl8139_reset( rtl8139_properties_t *data )
{
// Stop everything and disable interrupts
WRITE_8( Command , Reset );
WRITE_16( IMR , 0 );
//Reset the buffer pointers
WRITE_16( CBR , 0 );
WRITE_16( CAPR , 0 - 16 );
data->receivebufferoffset = 0;
//Re-enable interrupts
WRITE_16( IMR ,
ReceiveOk | ReceiveError | TransmitOk | TransmitError |
ReceiveOverflow | ReceiveUnderflow | ReceiveFIFOOverrun |
TimeOut | SystemError );
//Start rx/tx
WRITE_8( Command , EnableReceive | EnableTransmit );
}
/* ----------
read_hook - handle read() calls
----- */
@ -529,16 +619,21 @@ read_hook (void* cookie, off_t position, void *buf, size_t* num_bytes)
{
rtl8139_properties_t *data =/* (rtl8139_properties_t *)*/cookie;
packetheader_t *packet_header;
cpu_status former;
dprintf( "rtl8139_nielx: read_hook()\n" );
TRACE( "rtl8139_nielx: read_hook()\n" );
//if( !data->nonblocking )
acquire_sem_etc( data->input_wait , 1 , B_CAN_INTERRUPT , 0 );
restart:
former = lock();
//Next: check in command register if there's actually anything to be read
if ( READ_8( Command ) & BUFE )
{
dprintf( "rtl8139_nielx read_hook: Nothing to read!!!\n" );
TRACE( "rtl8139_nielx read_hook: Nothing to read!!!\n" );
unlock( former );
return B_IO_ERROR;
}
@ -548,45 +643,43 @@ read_hook (void* cookie, off_t position, void *buf, size_t* num_bytes)
// 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;
TRACE( "rtl8139_nielx read_hook: The transfer is not yet finished!!!\n" );
unlock( former );
goto restart;
}
//Check for an error: if needed: resetrx, length may not be bigger than 1514 + 4 CRC
if ( !( packet_header->bits & 0x1 ) || packet_header->length > 1518 )
{
dprintf( "rtl8139_nielx read_hook: Error in package reception: bits: %u length %u!!!\n" , packet_header->bits , packet_header->length);
return B_IO_ERROR;
TRACE( "rtl8139_nielx read_hook: Error in package reception: bits: %u length %u!!!\n" , packet_header->bits , packet_header->length);
unlock ( former );
rtl8139_reset( data );
goto restart;
}
dprintf( "rtl8139_nielx read_hook(): Packet size: %u Receiveheader: %u Buffer size: %lu\n" , packet_header->length , packet_header->bits , *num_bytes );
TRACE( "rtl8139_nielx read_hook(): Packet size: %u Receiveheader: %u Buffer size: %lu\n" , packet_header->length , packet_header->bits , *num_bytes );
//Copy the packet
*num_bytes = packet_header->length - 4;
if ( data->receivebufferoffset + *num_bytes > 65536 )
{
//Packet wraps around , copy last bits except header ( = +4 )
memcpy( buf , data->receivebufferlog + data->receivebufferoffset + 4 , 0x10000 - ( data->receivebufferoffset + 4 ) );
memcpy( buf , (void *)( (uint32)data->receivebufferlog + data->receivebufferoffset + 4 ) , 0x10000 - ( data->receivebufferoffset + 4 ) );
//copy remaining bytes from the beginning
memcpy( buf + 0x10000 - ( data->receivebufferoffset + 4 ) , data->receivebufferlog , *num_bytes - (0x10000 - ( data->receivebufferoffset + 4 ) ) );
dprintf( "rtl8139_nielx read_hook: Wrapping around end of buffer\n" );
memcpy( (void *) ( (uint32)buf + 0x10000 - ( data->receivebufferoffset + 4 ) ) , data->receivebufferlog , *num_bytes - (0x10000 - ( data->receivebufferoffset + 4 ) ) );
TRACE( "rtl8139_nielx read_hook: Wrapping around end of buffer\n" );
}
else
memcpy( buf , data->receivebufferlog + data->receivebufferoffset + 4 , packet_header->length - 4); //length-4 because we don't want to copy the 4 bytes CRC
memcpy( buf , (void *) ( (uint32)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;
WRITE_16( CAPR , data->receivebufferoffset - 16 ); //-16, avoid overflow
TRACE( "rtl8139_nielx read_hook(): CBP %u CAPR %u \n" , READ_16( CBR ) , READ_16( CAPR ) );
dprintf( "rtl8139_nielx read_hook(): CBP %u CAPR %u \n" , READ_16( CBR ) , READ_16( CAPR ) );
unlock( former );
// Re-enable interrupts
WRITE_16( ISR , ReceiveOk );
WRITE_16( IMR ,
ReceiveOk | ReceiveError | TransmitOk | TransmitError |
ReceiveOverflow | ReceiveUnderflow | ReceiveFIFOOverrun |
TimeOut | SystemError );
return packet_header->length - 4;
}
@ -602,54 +695,48 @@ write_hook (void* cookie, off_t position, const void* buffer, size_t* num_bytes)
int buflen = *num_bytes;
int transmitid = 0;
uint32 transmitdescription = 0;
cpu_status former;
dprintf( "rtl8139_nielx write_hook()\n" );
TRACE( "rtl8139_nielx write_hook()\n" );
acquire_sem_etc( data->lock , 1 , B_CAN_INTERRUPT, 0);
acquire_sem( data->lock );
//Get spinlock
WRITE_16( IMR , 0 );
former = lock();
if ( data->writes == 4 )
{
dprintf( "rtl8139_nielx write_hook(): already doing four writes\n" );
unlock( former );
release_sem_etc( data->lock , 1 , B_DO_NOT_RESCHEDULE );
return B_INTERRUPTED;
}
if ( buflen > 1792 ) //Maximum of 1792 bytes
{
dprintf( "rtl8139_nielx write_hook(): packet is too long\n" );
TRACE( "rtl8139_nielx write_hook(): packet is too long\n" );
unlock( former );
release_sem_etc( data->lock , 1 , B_DO_NOT_RESCHEDULE );
return B_IO_ERROR;
}
// We need to determine a free transmit descriptor
if ( data->transmitstatus[ data->nexttransmitstatus ] == 1 )
transmitid = data->queued_packets % 4;
if ( data->transmitstatus[ transmitid ] == 1 )
{
//No free descriptor]
unlock( former );
release_sem_etc( data->lock , 1 , B_DO_NOT_RESCHEDULE );
return B_IO_ERROR;
}
//Update our current transmit id
transmitid = data->nexttransmitstatus;
if ( data->nexttransmitstatus == 3 )
data->nexttransmitstatus = 0;
else
data->nexttransmitstatus++;
dprintf( "rtl8139_nielx write_hook(): TransmitID: %u Packagelen: %u Register: %lx\n" , transmitid , buflen , TSD0 + (sizeof(uint32) * transmitid ) );
if ( transmitid == -1 )
{
dprintf( "rtl8139_nielx_write_hook(): no free buffer ?!?\n" );
return B_IO_ERROR;
}
data->writes++;
// Set the buffer as used
data->transmitstatus[transmitid] = 1;
release_sem_etc( data->lock , 1 , B_DO_NOT_RESCHEDULE );
//Copy the packet into the buffer
memcpy( data->transmitbufferlog[transmitid] , buffer , buflen );
@ -658,10 +745,18 @@ 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 = %lu\n" , transmitdescription );
TRACE( "rtl8139_nielx write: transmitdescription = %lu\n" , transmitdescription );
WRITE_32( TSD0 + (sizeof(uint32) * transmitid ) , transmitdescription );
dprintf( "rtl8139_nielx write: TSAD: %u\n" , READ_16( TSAD ) );
TRACE( "rtl8139_nielx write: TSAD: %u\n" , READ_16( TSAD ) );
data->queued_packets++;
unlock( former );
WRITE_16( IMR ,
ReceiveOk | ReceiveError | TransmitOk | TransmitError |
ReceiveOverflow | ReceiveUnderflow | ReceiveFIFOOverrun |
TimeOut | SystemError );
release_sem_etc( data->lock , 1 , B_DO_NOT_RESCHEDULE );
//Done
return B_OK;
@ -677,20 +772,20 @@ 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" );
TRACE( "rtl8139_nielx control_hook()\n" );
switch ( op )
{
case ETHER_INIT:
dprintf( "rtl8139_nielx control_hook(): Wants us to init... ;-)\n" );
TRACE( "rtl8139_nielx control_hook(): Wants us to init... ;-)\n" );
return B_NO_ERROR;
case ETHER_GETADDR:
if ( data == NULL )
return B_ERROR;
dprintf( "rtl8139_nielx control_hook(): Wants our address...\n" );
TRACE( "rtl8139_nielx control_hook(): Wants our address...\n" );
memcpy( arg , (void *) &(data->address) , sizeof( ether_address_t ) );
return B_OK;
@ -701,9 +796,9 @@ control_hook (void* cookie, uint32 op, void* arg, size_t len)
if ( data->multiset == 8 )
return B_ERROR;
dprintf( "rtl8139_nielx control_hook(): Add multicast...\n" );
TRACE( "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] ,
TRACE( "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;
@ -712,20 +807,20 @@ control_hook (void* cookie, uint32 op, void* arg, size_t len)
if ( data == NULL )
return B_ERROR;
dprintf( "rtl8139_nielx control_hook(): Wants to set block/nonblock\n" );
TRACE( "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" );
TRACE( "rtl8139_nielx control_hook(): Wants REMMULTI\n" );
return B_OK;
case ETHER_SETPROMISC:
dprintf("rtl8139_nielx control_hook(): Wants PROMISC\n" );
TRACE("rtl8139_nielx control_hook(): Wants PROMISC\n" );
return B_OK;
case ETHER_GETFRAMESIZE:
dprintf("rtl8139_nielx control_hook(): Wants GETFRAMESIZE\n" ) ;
TRACE("rtl8139_nielx control_hook(): Wants GETFRAMESIZE\n" ) ;
*( (unsigned int *)arg ) = 1514;
return B_OK;
}
@ -742,100 +837,127 @@ rtl8139_interrupt( void *cookie )
rtl8139_properties_t *data = (rtl8139_properties_t *)cookie;
uint8 temp8;
uint16 isr_contents;
uint16 isr_write = 0;
uint32 txstatus;
int32 retval = B_UNHANDLED_INTERRUPT;
cpu_status status;
status = lock();
WRITE_16( IMR , 0 ); //Disable interrupts
isr_contents = READ_16( ISR );
dprintf( "NIELX INTERRUPT: %u \n" , isr_contents );
if( isr_contents & ReceiveOk )
for (;;)
{
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.
WRITE_16( IMR , 0 );
retval = B_INVOKE_SCHEDULER;
}
if (isr_contents & ReceiveError )
{
//Do something
;
}
if (isr_contents & TransmitOk )
{
// Check each status descriptor
for (temp8 = 0 ; temp8 < 4 ; temp8++)
{
// If a register isn't used, continue next run
if ( data->transmitstatus[temp8] != 1 )
continue;
txstatus = READ_32( TSD0 + temp8 * sizeof( int32 ) );
dprintf( "run: %u txstatus: %lu Register: %lx\n" , temp8 , txstatus , TSD0 + temp8 * sizeof( int32 ) );
isr_contents = READ_16( ISR );
if ( isr_contents == 0 )
break;
else
WRITE_16( ISR , isr_contents );
if ( ( txstatus & TOK ) )
{
//this one is the one!
dprintf( "NIELX INTERRUPT: TXOK, clearing register %u\n" , temp8 );
data->transmitstatus[temp8] = 0; //That's all there is to it
data->writes--;
//update next transmitid
continue;
}
TRACE( "NIELX INTERRUPT: %u \n" , isr_contents );
if( isr_contents & ReceiveOk )
{
TRACE( "rtl8139_nielx interrupt ReceiveOk\n" );
release_sem_etc( data->input_wait , 1 , B_DO_NOT_RESCHEDULE );
retval = B_INVOKE_SCHEDULER;
}
isr_write |= TransmitOk;
retval = B_HANDLED_INTERRUPT;
}
if( isr_contents & TransmitError )
{
//
;
}
if (isr_contents & ReceiveError )
{
//Do something
;
}
if( isr_contents & ReceiveOverflow )
{
// Discard all the current packages to be processed -- newos driver
WRITE_16( CAPR , ( READ_16( CBR ) + 16 ) % 0x1000 );
isr_write |= ReceiveOverflow;
retval = B_HANDLED_INTERRUPT;
}
if( isr_contents & ReceiveUnderflow )
{
// Most probably a link change -> TODO CHECK!
isr_write |= ReceiveUnderflow;
dprintf( "rtl8139_nielx interrupt(): BMCR: 0x%x BMSR: 0x%x\n" ,
READ_16( BMCR ) ,
READ_16( BMSR ) );
retval = B_HANDLED_INTERRUPT;
}
if ( isr_contents & ReceiveFIFOOverrun )
{
//
;
}
if ( isr_contents & TimeOut )
{
//
;
}
if ( isr_contents & SystemError )
{
//
;
}
WRITE_16( ISR , isr_write );
if (isr_contents & TransmitOk )
{
uint32 checks = data->queued_packets - data->finished_packets;
uint32 txstatus;
// Check each status descriptor
while( checks > 0 )
{
// If a register isn't used, continue next run
temp8 = data->finished_packets % 4 ;
txstatus = READ_32( TSD0 + temp8 * sizeof( int32 ) );
dprintf( "run: %u txstatus: %lu Register: %lx\n" , temp8 , txstatus , TSD0 + temp8 * sizeof( int32 ) );
if ( !( txstatus & ( TOK | TUN | TABT ) ) )
{
dprintf( "NOT FINISHED\n" );
break;
}
if ( txstatus & ( TABT | OWC ) )
{
dprintf( "MAJOR ERROR\n" );
continue;
}
if ( txstatus &( TUN ) )
{
dprintf( "TRANSMIT UNDERRUN\n" );
continue;
}
if ( ( txstatus & TOK ) )
{
//this one is the one!
dprintf( "NIELX INTERRUPT: TXOK, clearing register %u\n" , temp8 );
data->transmitstatus[temp8] = 0; //That's all there is to it
data->writes--;
data->finished_packets++;
checks--;
//update next transmitid
continue;
}
}
retval = B_HANDLED_INTERRUPT;
}
if( isr_contents & TransmitError )
{
//
;
}
if( isr_contents & ReceiveOverflow )
{
// Discard all the current packages to be processed -- newos driver
WRITE_16( CAPR , ( READ_16( CBR ) + 16 ) % 0x1000 );
retval = B_HANDLED_INTERRUPT;
}
if( isr_contents & ReceiveUnderflow )
{
// Most probably a link change -> TODO CHECK!
TRACE( "rtl8139_nielx interrupt(): BMCR: 0x%x BMSR: 0x%x\n" ,
READ_16( BMCR ) ,
READ_16( BMSR ) );
retval = B_HANDLED_INTERRUPT;
}
if ( isr_contents & ReceiveFIFOOverrun )
{
//
;
}
if ( isr_contents & TimeOut )
{
//
;
}
if ( isr_contents & SystemError )
{
//
;
}
}
//Re-enable interrupts
WRITE_16( IMR ,
ReceiveOk | ReceiveError | TransmitOk | TransmitError |
ReceiveOverflow | ReceiveUnderflow | ReceiveFIFOOverrun |
TimeOut | SystemError );
unlock( status );
return retval;
@ -857,15 +979,15 @@ close_hook (void* cookie)
/* -----
rtl8139_free - called after the last device is closed, and after
free_hook - called after the last device is closed, and after
all i/o is complete.
----- */
static status_t
rtl8139_free (void* cookie)
free_hook (void* cookie)
{
rtl8139_properties_t *data = (rtl8139_properties_t *) cookie;
dprintf( "rtl8139_nielx free_hook()\n" );
TRACE( "rtl8139_nielx free_hook()\n" );
//Remove interrupt handler
remove_io_interrupt_handler( data->pcii->u.h0.interrupt_line ,
@ -875,6 +997,9 @@ rtl8139_free (void* cookie)
delete_area( data->receivebuffer );
delete_area( data->transmitbuffer[0] );
delete_area( data->transmitbuffer[2] );
delete_area( data->ioarea ); //Only does something on ppc
m_openmask &= ~(1L << data->device_id);
//Finally, free the cookie
free( data );
@ -882,9 +1007,6 @@ rtl8139_free (void* cookie)
//Put the pci module
put_module( B_PCI_MODULE_NAME );
//To conclude: set the status of the device to closed
m_isopen = 0;
return B_OK;
}
@ -896,7 +1018,7 @@ rtl8139_free (void* cookie)
device_hooks rtl8139_hooks = {
open_hook, /* -> open entry point */
close_hook, /* -> close entry point */
rtl8139_free, /* -> free cookie */
free_hook, /* -> free cookie */
control_hook, /* -> control entry point */
read_hook, /* -> read entry point */
write_hook /* -> write entry point */
@ -910,7 +1032,7 @@ device_hooks rtl8139_hooks = {
const char**
publish_devices()
{
return rtl8139_name;
return (const char **)rtl8139_names;
}
/* ----------

View File

@ -101,10 +101,10 @@ area_id map_mem(void **log, void *phy, size_t size, const char *name)
dprintf("mapping physical address %p with %#lx bytes for %s\n",phy,size,name);
offset = (uint32)phy & (B_PAGE_SIZE - 1);
phyadr = phy - offset;
phyadr = (void *) ( (uint32)phy - offset );
size = round_to_pagesize(size + offset);
area = map_physical_memory(name, phyadr, size, B_ANY_KERNEL_BLOCK_ADDRESS, B_READ_AREA | B_WRITE_AREA, &mapadr);
*log = mapadr + offset;
*log = (void *) ( (uint32)mapadr + offset );
dprintf("physical = %p, logical = %p, offset = %#lx, phyadr = %p, mapadr = %p, size = %#lx, area = %#lx\n",
phy, *log, offset, phyadr, mapadr, size, area);