From 031df3914990db0336a0d386fb53558b05de467e Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Mon, 23 Apr 2018 09:53:31 +0200 Subject: bsps: Move legacy network drivers to bsps This patch is a part of the BSP source reorganization. Update #3285. --- bsps/m68k/mvme167/net/network.c | 3099 +++++++++++++++++++++++++++++++++++++++ bsps/m68k/mvme167/net/uti596.h | 369 +++++ 2 files changed, 3468 insertions(+) create mode 100644 bsps/m68k/mvme167/net/network.c create mode 100644 bsps/m68k/mvme167/net/uti596.h (limited to 'bsps/m68k/mvme167') diff --git a/bsps/m68k/mvme167/net/network.c b/bsps/m68k/mvme167/net/network.c new file mode 100644 index 0000000000..06bcbfa84a --- /dev/null +++ b/bsps/m68k/mvme167/net/network.c @@ -0,0 +1,3099 @@ +/* network.c: An 82596 ethernet driver for rtems-bsd. + */ + +#define __INSIDE_RTEMS_BSD_TCPIP_STACK__ +#define KERNEL + +/* + * Selectively define to debug the network driver. If you define any of these + * you must run with polled console I/O. + */ + +/* +#define DBG_ADD_CMD +#define DBG_WAIT +#define DBG_SEND +#define DBG_MEM +#define DBG_SELFTEST_CMD +#define DBG_DUMP_CMD +#define DBG_RESET +#define DBG_ATTACH +#define DBG_START +#define DBG_INIT +#define DBG_STOP +#define DBG_RX +#define DBG_ISR +#define DBG_IOCTL +#define DBG_STAT +#define DBG_PACKETS +*/ + +#define IGNORE_SPURIOUS_IRQ +#define IGNORE_NO_RFA +#define IGNORE_MULTIPLE_RF + +/* + * Default number of buffer descriptors and buffer sizes. + */ +#define RX_BUF_COUNT 15 +#define TX_BUF_COUNT 4 +#define TX_BD_PER_BUF 4 + +#define RBUF_SIZE 1520 + +#define UTI_596_ETH_MIN_SIZE 60 + +#define INET_ADDR_MAX_BUF_SIZE (sizeof "255.255.255.255") + +/* + * RTEMS events + */ +#define INTERRUPT_EVENT RTEMS_EVENT_1 +#define START_TRANSMIT_EVENT RTEMS_EVENT_2 +#define NIC_RESET_EVENT RTEMS_EVENT_3 + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "uti596.h" + +/* If we are running interrupt driven I/O no debug output is printed */ +#if CD2401_IO_MODE == 0 + #define printk(arglist) do { printk arglist; printk("\r"); } while (0); +#else + #define printk(arglist) +#endif + +#define UTI_596_ASSERT( condition, str ) if (!( condition ) ) { printk((str)) } + +/* Types of PORT commands */ +#define UTI596_RESET_PORT_FUNCTION 0 +#define UTI596_SELFTEST_PORT_FUNCTION 1 +#define UTI596_SCP_PORT_FUNCTION 2 +#define UTI596_DUMP_PORT_FUNCTION 3 + +/* Types of waiting for commands */ +#define UTI596_NO_WAIT 0 +#define UTI596_WAIT_FOR_CU_ACCEPT 1 +#define UTI596_WAIT_FOR_INITIALIZATION 2 +#define UTI596_WAIT_FOR_STAT_C 3 + +/* Device dependent data structure */ +static uti596_softc_ uti596_softc; + +/* Globals */ +int count_rx = 0; +static int scbStatus; +static rtems_status_code sc; +static i596_cmd *pIsrCmd; +static i596_rfd *pIsrRfd; + +/* + * Initial 596 configuration + */ +char uti596initSetup[] = { + 0x0E, /* Byte 0: length, prefetch off ( no RBD's ) */ + 0xC8, /* Byte 1: fifo to 8, monitor off */ + 0x40, /* Byte 2: don't save bad frames ( was save= 80, use intel's 40 )*/ + 0x2E, /* Byte 3: No source address insertion, 8 byte preamble */ + 0x00, /* Byte 4: priority and backoff defaults */ + 0x60, /* Byte 5: interframe spacing */ + 0x00, /* Byte 6: slot time LSB */ + 0xf2, /* Byte 7: slot time and retries */ + 0x0C, /* Byte 8: not promisc, enable bcast, tx no crs, crc inserted 32bit, 802.3 framing */ + 0x08, /* Byte 9: collision detect */ + 0x40, /* Byte 10: minimum frame length */ + 0xfb, /* Byte 11: tried C8 same as byte 1 in bits 6-7, else ignored*/ + 0x00, /* Byte 12: disable full duplex */ + 0x3f /* Byte 13: no multi IA, backoff enabled */ +}; + +/* Local Routines */ + +static unsigned long word_swap ( unsigned long ); +static void * malloc_16byte_aligned ( void **, void ** adjusted_pointer, size_t ); +RTEMS_INLINE_ROUTINE void uti596_writePortFunction ( volatile void *, unsigned long ); +/* currently unused by RTEMS */ +#if 0 +RTEMS_INLINE_ROUTINE void uti596_portReset( void ); +static unsigned long uti596_portSelfTest( i596_selftest * ); +static int uti596_portDump ( i596_dump_result * ); +static void uti596_CU_dump ( i596_dump_result * ); +#endif +static int uti596_wait ( uti596_softc_ *, uint8_t); +static int uti596_issueCA ( uti596_softc_ *, uint8_t); +static void uti596_addCmd ( i596_cmd * ); +static void uti596_addPolledCmd ( i596_cmd * ); +static int uti596_setScpAndScb ( uti596_softc_ * ); +static int uti596_diagnose ( void ); +static int uti596_configure ( uti596_softc_ * ); +static int uti596_IAsetup ( uti596_softc_ * ); +static int uti596_initTBD ( uti596_softc_ * ); +static int uti596_initRFA ( int ); +static void uti596_initMem ( uti596_softc_ * ); +static void uti596_initialize ( uti596_softc_ * ); +static void uti596_initialize_hardware ( uti596_softc_ * ); +static void uti596_reset_hardware ( uti596_softc_ *); +static void uti596_reset ( void ); +static void uti596_clearListStatus ( i596_rfd * ); +static i596_rfd * uti596_dequeue ( i596_rfd ** ); +static void uti596_append ( i596_rfd ** , i596_rfd * ); +static void uti596_supplyFD ( i596_rfd * ); +static void send_packet ( struct ifnet *, struct mbuf * ); + +/* Required RTEMS network driver functions and tasks (plus reset daemon) */ + +static void uti596_start ( struct ifnet * ); +void uti596_init ( void * ); +void uti596_stop ( uti596_softc_ * ); +void uti596_txDaemon ( void * ); +void uti596_rxDaemon ( void * ); +void uti596_resetDaemon( void * ); +rtems_isr uti596_DynamicInterruptHandler ( rtems_vector_number ); +static int uti596_ioctl ( struct ifnet *, u_long, caddr_t ); +void uti596_stats ( uti596_softc_ * ); + +#ifdef DBG_PACKETS +static void dumpQ( void ); +static void show_buffers( void ); +static void show_queues( void ); +static void print_eth ( unsigned char * ); +static void print_hdr ( unsigned char * ); +static void print_pkt ( unsigned char * ); +static void print_echo ( unsigned char * ); +#endif + +/* + * word_swap + * + * Return a 32 bit value, swapping the upper and lower words first. + * + * Input parameters: + * val - 32 bit value to swap + * + * Output parameters: NONE + * + * Return value: + * Input value with upper and lower 16-bit words swapped + */ +static unsigned long word_swap( + unsigned long val +) +{ + return (((val >> 16)&(0x0000ffff)) | ((val << 16)&(0xffff0000))); +} + +/* + * malloc_16byte_aligned + * + * Allocate a block of a least nbytes aligned on a 16-byte boundary. + * Clients are responsible to store both the real address and the adjusted + * address. The real address must be used to free the block. + * + * Input parameters: + * real_pointer - pointer to a void * pointer in which to store the starting + * address of the block. Required for free. + * adjusted_pointer - pointer to a void * pointer in which to store the + * starting address of the block rounded up to the next + * 16 byte boundary. + * nbytes - number of bytes of storage requested + * + * Output parameters: + * real_pointer - starting address of the block. + * adjusted_pointer - starting address of the block rounded up to the next + * 16 byte boundary. + * + * Return value: + * starting address of the block rounded up to the next 16 byte boundary. + * NULL if no storage was allocated. + */ +static void * malloc_16byte_aligned( + void ** real_pointer, + void ** adjusted_pointer, + size_t nbytes +) +{ + *real_pointer = malloc( nbytes + 0xF, 0, M_NOWAIT ); + *adjusted_pointer = (void *)(((unsigned long)*real_pointer + 0xF ) & 0xFFFFFFF0 ); + return *adjusted_pointer; +} + +/* + * uti596_scp_alloc + * + * Allocate a new scp, possibly freeing a previously allocated one. + * + * Input parameters: + * sc - pointer to the global uti596_softc in which to store pointers + * to the newly allocated block. + * + * Output parameters: NONE + * + * Return value: + * Pointer to the newly allocated, 16-byte aligned scp. + */ +static i596_scp * uti596_scp_alloc( + uti596_softc_ * sc +) +{ + if( sc->base_scp != NULL ) { + #ifdef DBG_MEM + printk(("uti596_scp_alloc: Already have an SCP at %p\n", sc->base_scp)) + #endif + return sc->pScp; + } + + /* allocate enough memory for the Scp block to be aligned on 16 byte boundary */ + malloc_16byte_aligned( (void *)&(sc->base_scp), (void *)&(sc->pScp), sizeof( i596_scp ) ); + + #ifdef DBG_MEM + printk(("uti596_scp_alloc: Scp base address is %p\n", sc->base_scp)) + printk(("uti596_scp_alloc: Scp aligned address is : %p\n",sc->pScp)) + #endif + + return sc->pScp; +} + +/* + * uti596_writePortFunction + * + * Write the command into the PORT. + * + * Input parameters: + * addr - 16-byte aligned address to write into the PORT. + * cmd - 4-bit cmd to write into the PORT + * + * Output parameters: NONE + * + * Return value: NONE + * + * The Motorola manual swapped the high and low registers. + */ +RTEMS_INLINE_ROUTINE void uti596_writePortFunction( + volatile void * addr, + unsigned long cmd +) +{ + i82596->port_lower = (unsigned short)(((unsigned long)addr & 0xFFF0) | cmd); + i82596->port_upper = (unsigned short)(((unsigned long)addr >> 16 ) & 0xFFFF); +} + +/* + * uti596_portReset + * + * Issue a port Reset to the uti596 + * + * Input parameters: NONE + * + * Output parameters: NONE + * + * Return value: NONE + */ +RTEMS_INLINE_ROUTINE void uti596_portReset( void ) +{ + uti596_writePortFunction( NULL, UTI596_RESET_PORT_FUNCTION ); +} + +/* currently unused by RTEMS */ +#if 0 +/* + * uti596_portSelfTest + * + * Perform a self-test. Wait for up to 1 second for the test to + * complete. Normally, the test should complete in a very short time, + * so busy waiting is not an issue. + * + * Input parameters: + * stp - pointer to a 16-byte aligned uti596_selftest structure. + * + * Output parameters: NONE + * + * Return value: + * 32-bit result field if successful, -1 otherwise. + */ +static unsigned long uti596_portSelfTest( + i596_selftest * stp +) +{ + rtems_interval ticks_per_second, start_ticks, end_ticks; + + stp->results = 0xFFFFFFFF; + uti596_writePortFunction( stp, UTI596_SELFTEST_PORT_FUNCTION ); + + ticks_per_second = rtems_clock_get_ticks_per_second(); + + start_ticks = rtems_clock_get_ticks_since_boot(); + end_ticks = start_ticks + ticks_per_second; + + do { + if( stp->results != 0xFFFFFFFF ) + break; + else + start_ticks = rtems_clock_get_ticks_since_boot(); + } while (start_ticks <= end_ticks); + + if (start_ticks > end_ticks ) { + #ifdef DBG_SELFTEST_CMD + printk(("uti596_selftest: Timed out\n" )) + #endif + return -1; + } + else { + #ifdef DBG_SELFTEST_CMD + printk(("uti596_selftest: Succeeded with signature = 0x%08x, result = 0x%08x\n", + stp->signature, + stp->results)) + #endif + return stp->results; + } +} +#endif + +/* currently unused by RTEMS */ +#if 0 +/* + * uti596_portDump + * + * Perform a dump Wait for up to 1 second for the test to + * complete. Normally, the test should complete in a very short time, + * so busy waiting is not an issue. + * + * Input parameters: + * dp - pointer to a 16-byte aligned uti596_dump structure. + * + * Output parameters: NONE + * + * Return value: + * 16-bit dump_status field if successful, -1 otherwise. + */ +static int uti596_portDump( + i596_dump_result * dp +) +{ + rtems_interval ticks_per_second, start_ticks, end_ticks; + + dp->dump_status = 0; + uti596_writePortFunction( dp, UTI596_DUMP_PORT_FUNCTION ); + + ticks_per_second = rtems_clock_get_ticks_per_second(); + start_ticks = rtems_clock_get_ticks_since_boot(); + end_ticks = start_ticks + ticks_per_second; + + do { + if( dp->dump_status != 0xA006 ) + break; + else + start_ticks = rtems_clock_get_ticks_since_boot(); + } while (start_ticks <= end_ticks); + + if (start_ticks > end_ticks ) { + #ifdef DBG_DUMP_CMD + printk(("uti596_dump: Timed out with dump at 0x%08x\n", (unsigned long)dp )) + #endif + return -1; + } + else { + #ifdef DBG_DUMP_CMD + printk(("uti596_dump: Succeeded with dump at = 0x%08x\n", (unsigned long)dp )) + #endif + return dp->dump_status; + } +} +#endif + +/* + * uti596_wait + * + * Wait for a certain condition. + * + * Input parameters: + * sc - pointer to the uti596_softc struct + * wait_type - UTI596_NO_WAIT + * UTI596_WAIT + * UTI596_WAIT_FOR_CU_ACCEPT + * UTI596_WAIT_FOR_INITIALIZATION + * UTI596_WAIT_FOR_STAT_C + * + * Output parameters: NONE + * + * Return value: + * 0 if successful, -1 otherwise. + */ +static int uti596_wait( + uti596_softc_ *sc, + uint8_t waitType +) +{ + rtems_interval ticks_per_second, start_ticks, end_ticks; + + ticks_per_second = rtems_clock_get_ticks_per_second(); + start_ticks = rtems_clock_get_ticks_since_boot(); + end_ticks = start_ticks + ticks_per_second; + + switch( waitType ) { + + case UTI596_NO_WAIT: + return 0; + + case UTI596_WAIT_FOR_CU_ACCEPT: + do { + if (sc->scb.command == 0) + break; + else + + start_ticks = rtems_clock_get_ticks_since_boot(); + + } while (start_ticks <= end_ticks); + + if( (sc->scb.command != 0) || (start_ticks > end_ticks) ) { + printf("i82596 timed out with status %x, cmd %x.\n", + sc->scb.status, sc->scb.command); + return -1; + } + else + return 0; + + case UTI596_WAIT_FOR_INITIALIZATION: + do { + if( !sc->iscp.busy ) + break; + else + start_ticks = rtems_clock_get_ticks_since_boot(); + } while (start_ticks <= end_ticks); + + if (start_ticks > end_ticks ) { + #ifdef DBG_WAIT + printk(("uti596_setScpAndScb: Timed out\n" )) + #endif + return -1; + } + else { + #ifdef DBG_WAIT + printk(("uti596_setScpAndScb: Succeeded\n" )) + #endif + return 0; + } + + case UTI596_WAIT_FOR_STAT_C: + do { + if( *sc->pCurrent_command_status & STAT_C ) + break; + else + start_ticks = rtems_clock_get_ticks_since_boot(); + } while (start_ticks <= end_ticks); + + if (start_ticks > end_ticks ) { + #ifdef DBG_WAIT + printk(("uti596_initMem: timed out - STAT_C not obtained\n" )) + #endif + return -1; + } + else { + #ifdef DBG_WAIT + printk(("uti596_initMem: STAT_C obtained OK\n" )) + #endif + return 0; + } + } + return -1; +} + +/* + * uti596_issueCA + * + * Issue a Channel Attention command. Possibly wait for the + * command to start or complete. + * + * Input parameters: + * sc - pointer to the uti596_softc + * wait_type - UTI596_NO_WAIT + * UTI596_WAIT_BEGIN + * UTI596_WAIT_COMPLETION + * + * Output parameters: NONE + * + * Return value: + * 0 if successful, -1 otherwise. + */ +static int uti596_issueCA( + uti596_softc_ *sc, + uint8_t waitType +) +{ + /* Issue Channel Attention */ + i82596->chan_attn = 0x00000000; + + return (uti596_wait ( sc, waitType )); +} + +/* + * uti596_addCmd + * + * Add a uti596_cmd onto the end of the CBL command chain, + * or to the start if the chain is empty. + * + * Input parameters: + * pCmd - a pointer to the command to be added. + * + * Output parameters: NONE + * + * Return value: NONE + */ +static void uti596_addCmd( + i596_cmd *pCmd +) +{ + ISR_Level level; + + #ifdef DBG_ADD_CMD + printk(("uti596_addCmd: Adding command 0x%x\n", pCmd -> command )) + #endif + + /* Mark command as last in list, to return an interrupt */ + pCmd->command |= (CMD_EOL | CMD_INTR ); + pCmd->status = 0; + pCmd->next = I596_NULL; + + _ISR_Local_disable(level); + + if (uti596_softc.pCmdHead == I596_NULL) { + uti596_softc.pCmdHead = uti596_softc.pCmdTail = uti596_softc.scb.pCmd = pCmd; + uti596_softc.scb.cmd_pointer = word_swap ((unsigned long)pCmd); + + uti596_wait ( &uti596_softc, UTI596_WAIT_FOR_CU_ACCEPT ); + uti596_softc.scb.command = CUC_START; + uti596_issueCA ( &uti596_softc, UTI596_NO_WAIT ); + + _ISR_Local_enable(level); + } + else { + uti596_softc.pCmdTail->next = (i596_cmd *) word_swap ((unsigned long)pCmd); + uti596_softc.pCmdTail = pCmd; + _ISR_Local_enable(level); + } + + #ifdef DBG_ADD_CMD + printk(("uti596_addCmd: Scb status & command 0x%x 0x%x\n", + uti596_softc.scb.status, + uti596_softc.scb.command )) + #endif +} + +/* + * uti596_addPolledCmd + * + * Add a single uti596_cmd to the end of the command block list + * for processing, send a CU_START and wait for its acceptance + * + * Input parameters: + * sc - a pointer to the uti596_softc struct + * + * Output parameters: NONE + * + * Return value: NONE + */ +void uti596_addPolledCmd( + i596_cmd *pCmd +) +{ + + #ifdef DBG_ADD_CMD + printk(("uti596_addPolledCmd: Adding command 0x%x\n", pCmd -> command )) + #endif + + pCmd->status = 0; + pCmd->command |= CMD_EOL ; /* only command in list*/ + pCmd->next = I596_NULL; + + uti596_wait ( &uti596_softc, UTI596_WAIT_FOR_CU_ACCEPT ); + + uti596_softc.pCmdHead = uti596_softc.pCmdTail = uti596_softc.scb.pCmd = pCmd; + uti596_softc.scb.cmd_pointer = word_swap((unsigned long)pCmd); + uti596_softc.scb.command = CUC_START; + uti596_issueCA ( &uti596_softc, UTI596_WAIT_FOR_CU_ACCEPT ); + + uti596_softc.pCmdHead = uti596_softc.pCmdTail = uti596_softc.scb.pCmd = I596_NULL; + uti596_softc.scb.cmd_pointer = (unsigned long) I596_NULL; + + #ifdef DBG_ADD_CMD + printk(("uti596_addPolledCmd: Scb status & command 0x%x 0x%x\n", + uti596_softc.scb.status, + uti596_softc.scb.command )) + #endif +} + +/* currently unused by RTEMS */ +#if 0 +/* + * uti596_CU_dump + * + * Dump the LANC 82596 registers + * The outcome is the same as the portDump() but executed + * via the CU instead of via a PORT access. + * + * Input parameters: + * drp - a pointer to a i596_dump_result structure. + * + * Output parameters: NONE + * + * Return value: NONE + */ +static void uti596_CU_dump ( i596_dump_result * drp) +{ + i596_dump dumpCmd; + + dumpCmd.cmd.command = CmdDump; + dumpCmd.cmd.next = I596_NULL; + dumpCmd.pData = (char *) drp; + uti596_softc.cmdOk = 0; + uti596_addCmd ( (i596_cmd *) &dumpCmd ); + +} +#endif + +#if defined(DBG_STAT) || !defined(IGNORE_NO_RFA) +/* + * uti596_dump_scb + * + * Dump the system control block + * This function expands to nothing when using interrupt driven I/O + * + * Input parameters: NONE + * + * Output parameters: NONE + * + * Return value: NONE + */ +static void uti596_dump_scb ( void ) +{ + printk(("status 0x%x\n",uti596_softc.scb.status)) + printk(("command 0x%x\n",uti596_softc.scb.command)) + printk(("cmd 0x%x\n",(int)uti596_softc.scb.pCmd)) + printk(("rfd 0x%x\n",(int)uti596_softc.scb.pRfd)) + printk(("crc_err 0x%" PRIx32 "\n",uti596_softc.scb.crc_err)) + printk(("align_err 0x%" PRIx32 "\n",uti596_softc.scb.align_err)) + printk(("resource_err 0x%" PRIx32 "\n",uti596_softc.scb.resource_err )) + printk(("over_err 0x%" PRIx32 "\n",uti596_softc.scb.over_err)) + printk(("rcvdt_err 0x%" PRIx32 "\n",uti596_softc.scb.rcvdt_err)) + printk(("short_err 0x%" PRIx32 "\n",uti596_softc.scb.short_err)) + printk(("t_on 0x%x\n",uti596_softc.scb.t_on)) + printk(("t_off 0x%x\n",uti596_softc.scb.t_off)) +} +#endif + +/* + * uti596_setScpAndScb + * + * Issue the first channel attention after reset and wait for the busy + * field to clear in the iscp. + * + * Input parameters: + * sc - pointer to the global uti596_softc + * + * Output parameters: NONE + * + * Return value: + * 0 if successful, -1 otherwise. + */ +static int uti596_setScpAndScb( + uti596_softc_ * sc +) +{ + /* set the busy flag in the iscp */ + sc->iscp.busy = 1; + + /* the command block list (CBL) is empty */ + sc->scb.command = 0; + sc->scb.cmd_pointer = (unsigned long) I596_NULL; /* all 1's */ + sc->pCmdHead = sc->scb.pCmd = I596_NULL; /* all 1's */ + + uti596_writePortFunction( sc->pScp, UTI596_SCP_PORT_FUNCTION ); + + /* Issue CA: pass the scb address to the 596 */ + return ( uti596_issueCA ( sc, UTI596_WAIT_FOR_INITIALIZATION ) ); +} + +/* + * uti596_diagnose + * + * Send a diagnose command to the CU + * + * Input parameters: NONE + * + * Output parameters: NONE + * + * Return value: + * 0 if successful, -1 otherwise + */ +static int uti596_diagnose( void ) +{ + i596_cmd diagnose; + + diagnose.command = CmdDiagnose; + diagnose.status = 0; + uti596_softc.pCurrent_command_status = (unsigned short *)&diagnose.status; + uti596_addPolledCmd(&diagnose); + return (uti596_wait ( &uti596_softc, UTI596_WAIT_FOR_STAT_C )); + + #ifdef DBG_INIT + printk(("Status diagnostic: 0xa000 is a success ... 0x%2.2x\n", diagnose.status)) + #endif +} + +/* + * uti596_configure + * + * Send the CU a configure command with the desired + * configuration structure + * + * Input parameters: + * sc - a pointer to the uti596_softc struct + * + * Output parameters: NONE + * + * Return value: + * 0 if successful, -1 otherwise + */ +static int uti596_configure ( + uti596_softc_ * sc +) +{ + sc->set_conf.cmd.command = CmdConfigure; + memcpy ( (void *)sc->set_conf.data, uti596initSetup, 14); + uti596_addPolledCmd( (i596_cmd *) &sc->set_conf); + + /* Poll for successful command completion */ + sc->pCurrent_command_status = (unsigned short *)&(sc->set_conf.cmd.status); + return ( uti596_wait ( sc, UTI596_WAIT_FOR_STAT_C ) ); +} + +/* + * uti596_IAsetup + * + * Send the CU an Individual Address setup command with + * the ethernet hardware address + * + * Input parameters: + * sc - a pointer to the uti596_softc struct + * + * Output parameters: NONE + * + * Return value: + * 0 if successful, -1 otherwise + */ +static int uti596_IAsetup ( + uti596_softc_ * sc +) +{ + int i; + + sc->set_add.cmd.command = CmdSASetup; + for ( i=0; i<6; i++) { + sc->set_add.data[i]=sc->arpcom.ac_enaddr[i]; + } + sc->cmdOk = 0; + uti596_addPolledCmd((i596_cmd *)&sc->set_add); + + /* Poll for successful command completion */ + sc->pCurrent_command_status = (unsigned short *)&(sc->set_add.cmd.status); + return ( uti596_wait ( sc, UTI596_WAIT_FOR_STAT_C ) ); +} + +/* + * uti596_initTBD + * + * Initialize transmit buffer descriptors + * dynamically allocate mem for the number of tbd's required + * + * Input parameters: + * sc - a pointer to the uti596_softc struct + * + * Output parameters: NONE + * + * Return value: + * 0 if successful, -1 otherwise + */ +static int uti596_initTBD ( uti596_softc_ * sc ) +{ + int i; + i596_tbd *pTbd, *pPrev; + + /* Set up a transmit command with a tbd ready */ + sc->pLastUnkRFD = I596_NULL; + sc->pTxCmd = (i596_tx *) calloc (1,sizeof (struct i596_tx) ); + sc->pTbd = (i596_tbd *) calloc (1,sizeof (struct i596_tbd) ); + if ((sc->pTxCmd == NULL) || (sc->pTbd == NULL)) { + return -1; + } + sc->pTxCmd->pTbd = (i596_tbd *) word_swap ((unsigned long) sc->pTbd); + sc->pTxCmd->cmd.command = CMD_FLEX|CmdTx; + sc->pTxCmd->pad = 0; + sc->pTxCmd->count = 0; /* all bytes are in list of TBD's */ + + pPrev = pTbd = sc->pTbd; + + /* Allocate a linked list of tbd's each with it's 'next' field written + * with upper and lower words swapped (for big endian), and mark the end. + */ + for ( i=0; itxBdCount; i++) { + if ( (pTbd = (i596_tbd *) calloc (1,sizeof (struct i596_tbd) )) == NULL ) { + return -1; + } + pPrev->next = (i596_tbd *) word_swap ((unsigned long) pTbd); + pPrev = pTbd; + } + pTbd->next = I596_NULL; + return 0; +} + +/* + * uti596_initRFA + * + * Initialize the Receive Frame Area + * dynamically allocate mem for the number of rfd's required + * + * Input parameters: + * sc - a pointer to the uti596_softc struct + * + * Output parameters: NONE + * + * Return value: + * # of buffer descriptors successfully allocated + */ +static int uti596_initRFA( int num ) +{ + i596_rfd *pRfd; + int i = 0; + + #ifdef DBG_INIT + printk(("uti596_initRFA: begins\n Requested frame descriptors ... %d.\n", num)) + #endif + + /* + * Create the first RFD in the RFA + */ + pRfd = (i596_rfd *) calloc (1, sizeof (struct i596_rfd)); + if ( !pRfd ) { + printk(("Can't allocate first buffer.\n")) + return 0; + } + else { + uti596_softc.countRFD = 1; + uti596_softc.pBeginRFA = uti596_softc.pEndRFA = pRfd; + } + + /* Create remaining RFDs */ + for (i = 1; i < num; i++) { + pRfd = (i596_rfd *) calloc (1, sizeof (struct i596_rfd) ); + if ( pRfd != NULL ) { + uti596_softc.countRFD++; /* update count */ + uti596_softc.pEndRFA->next = + (i596_rfd *) word_swap ((unsigned long) pRfd); /* write the link */ + uti596_softc.pEndRFA = pRfd; /* move the end */ + } + else { + printk(("Can't allocate all buffers: only %d allocated\n", i)) + break; + } + } /* end for */ + + uti596_softc.pEndRFA->next = I596_NULL; + UTI_596_ASSERT(uti596_softc.countRFD == num,"INIT:WRONG RFD COUNT\n" ) + + #ifdef DBG_INIT + printk (("uti596_initRFA: Head of RFA is buffer %p \n\ + uti596_initRFA: End of RFA is buffer %p \n", + uti596_softc.pBeginRFA, uti596_softc.pEndRFA )) + #endif + + /* Walk and initialize the RFD's */ + for ( pRfd = uti596_softc.pBeginRFA; + pRfd != I596_NULL; + pRfd = (i596_rfd *) word_swap ((unsigned long)pRfd->next) ) + { + pRfd->cmd = 0x0000; + pRfd->stat = 0x0000; + pRfd->pRbd = I596_NULL; + pRfd->count = 0; /* number of bytes in buffer: usually less than size */ + pRfd->size = 1532; /* was 1532; buffer size ( All RBD ) */ + } /* end for */ + + /* mark the last RFD as the last one in the RDL */ + uti596_softc.pEndRFA -> cmd = CMD_EOL; + uti596_softc.pSavedRfdQueue = + uti596_softc.pEndSavedQueue = I596_NULL; /* initially empty */ + + uti596_softc.savedCount = 0; + uti596_softc.nop.cmd.command = CmdNOp; /* initialize the nop command */ + + return (i); /* the number of allocated buffers */ +} + +/* + * uti596_initMem + * + * Initialize the 82596 memory structures for Tx and Rx + * dynamically allocate mem for the number of tbd's required + * + * Input parameters: + * sc - a pointer to the uti596_softc struct + * + * Output parameters: NONE + * + * Return value: NONE + */ +void uti596_initMem( + uti596_softc_ * sc +) +{ + int i; + + #ifdef DBG_INIT + printk(("uti596_initMem: begins\n")) + #endif + + sc->resetDone = 0; + + /* + * Set up receive frame area (RFA) + */ + i = uti596_initRFA( sc->rxBdCount ); + if ( i < sc->rxBdCount ) { + printk(("init_rfd: only able to allocate %d receive frame descriptors\n", i)) + } + + /* + * Write the SCB with a pointer to the receive frame area + * and keep a pointer for our use. + */ + sc->scb.rfd_pointer = word_swap((unsigned long)sc->pBeginRFA); + sc->scb.pRfd = sc->pBeginRFA; + + /* + * Diagnose the health of the board + */ + uti596_diagnose(); + + /* + * Configure the 82596 + */ + uti596_configure( sc ); + + /* + * Set up the Individual (hardware) Address + */ + uti596_IAsetup ( sc ); + + /* + * Initialize the transmit buffer descriptors + */ + uti596_initTBD( sc ); + + /* Padding used to fill short tx frames */ + memset ( RTEMS_DEVOLATILE( char *, sc->zeroes ), 0, 64); + + /* now need ISR */ + sc->resetDone = 1; +} + +/* + * uti596_initialize + * + * Reset the 82596 and initialize it with a new SCP. + * + * Input parameters: + * sc - pointer to the uti596_softc + * + * Output parameters: NONE + * + * Return value: NONE + */ +void uti596_initialize( + uti596_softc_ *sc +) +{ + /* Reset the device. Stops it from doing whatever it might be doing. */ + uti596_portReset(); + + /* Get a new System Configuration Pointer */ + uti596_scp_alloc( sc ); + + /* write the SYSBUS: interrupt pin active high, LOCK disabled, + * internal triggering, linear mode + */ + sc->pScp->sysbus = 0x44; + + /* provide the iscp to the scp, keep a pointer for our use */ + sc->pScp->iscp_pointer = word_swap((unsigned long)&sc->iscp); + sc->pScp->iscp = &sc->iscp; + + /* provide the scb to the iscp, keep a pointer for our use */ + sc->iscp.scb_pointer = word_swap((unsigned long)&sc->scb); + sc->iscp.scb = &sc->scb; + + #ifdef DBG_INIT + printk(("uti596_initialize: Starting i82596.\n")) + #endif + + /* Set up the 82596 */ + uti596_setScpAndScb( sc ); + + /* clear the scb command word */ + sc->scb.command = 0; +} + +/* + * uti596_initialize_hardware + * + * Reset the 82596 and initialize it with a new SCP. Enable bus snooping. + * Install the interrupt handlers. + * + * Input parameters: + * sc - pointer to the uti596_softc + * + * Output parameters: NONE + * + * Return value: NONE + */ +void uti596_initialize_hardware( + uti596_softc_ *sc +) +{ + printk(("uti596_initialize_hardware: begins\n")) + + /* Get the PCCChip2 to assert bus snooping signals on behalf of the i82596 */ + pccchip2->LANC_berr_ctl = 0x40; + + uti596_initialize( sc ); + + /* + * Configure interrupt control in PCCchip2 + */ + pccchip2->LANC_error = 0xff; /* clear status register */ + pccchip2->LANC_int_ctl = 0x5d; /* lvl 5, enabled, edge-sensitive rising */ + pccchip2->LANC_berr_ctl = 0x5d; /* bus error: lvl 5, enabled, snoop control + * will supply dirty data and leave dirty data + * on read access and sink any data on write + */ + /* + * Install the interrupt handler + * calls rtems_interrupt_catch + */ + set_vector( uti596_DynamicInterruptHandler, 0x57, 1 ); + + /* Initialize the 82596 memory */ + uti596_initMem(sc); + + #ifdef DBG_INIT + printk(("uti596_initialize_hardware: After attach, status of board = 0x%x\n", sc->scb.status )) + #endif +} + +/* + * uti596_reset_hardware + * + * Reset the 82596 and initialize it with an SCP. + * + * Input parameters: + * sc - pointer to the uti596_softc + * + * Output parameters: NONE + * + * Return value: NONE + */ +void uti596_reset_hardware( + uti596_softc_ *sc +) +{ + rtems_status_code status_code; + i596_cmd *pCmd; + + pCmd = sc->pCmdHead; /* This is a tx command for sure (99.99999%) */ + + /* the command block list (CBL) is empty */ + sc->scb.cmd_pointer = (unsigned long) I596_NULL; /* all 1's */ + sc->pCmdHead = sc->scb.pCmd = I596_NULL; /* all 1's */ + + #ifdef DBG_RESET + printk(("uti596_reset_hardware\n")) + #endif + uti596_initialize( sc ); + + /* + * Wake the transmitter if needed. + */ + if ( sc->txDaemonTid && pCmd != I596_NULL ) { + printk(("****RESET: wakes transmitter!\n")) + status_code = rtems_bsdnet_event_send (sc->txDaemonTid, + INTERRUPT_EVENT); + + if ( status_code != RTEMS_SUCCESSFUL ) { + printk(("****ERROR:Could NOT send event to tid 0x%" PRIx32 " : %s\n", + sc->txDaemonTid, rtems_status_text (status_code) )) + } + } + + #ifdef DBG_RESET + printk(("uti596_reset_hardware: After reset_hardware, status of board = 0x%x\n", sc->scb.status )) + #endif +} + +/* + * uti596_clearListStatus + * + * Clear the stat fields for all RFDs + * + * Input parameters: + * pRfd - a pointer to the head of the RFA + * + * Output parameters: NONE + * + * Return value: NONE + */ +void uti596_clearListStatus( + i596_rfd *pRfd +) +{ + while ( pRfd != I596_NULL ) { + pRfd -> stat = 0; + pRfd = (i596_rfd *) word_swap((unsigned long)pRfd-> next); + } +} + +/* + * uti596_reset + * + * Reset the 82596 and reconfigure + * + * Input parameters: NONE + * + * Output parameters: NONE + * + * Return value: NONE + */ +void uti596_reset( void ) +{ + uti596_softc_ *sc = &uti596_softc; + + #ifdef DBG_RESET + printk(("uti596_reset: begin\n")) + #endif + + /* Wait for the CU to be available, then + * reset the ethernet hardware. Must re-config. + */ + sc->resetDone = 0; + uti596_wait ( sc, UTI596_WAIT_FOR_CU_ACCEPT ); + uti596_reset_hardware ( &uti596_softc ); + + #ifdef DBG_RESET + uti596_diagnose(); + #endif + + /* + * Configure the 82596 + */ + uti596_configure( sc ); + + /* + * Set up the Individual (hardware) Address + */ + uti596_IAsetup ( sc ); + + sc->pCmdHead = sc->pCmdTail = sc->scb.pCmd = I596_NULL; + + /* restore the RFA */ + + if ( sc->pLastUnkRFD != I596_NULL ) { + sc-> pEndRFA = sc->pLastUnkRFD; /* The end position can be updated */ + sc-> pLastUnkRFD = I596_NULL; + } + + sc->pEndRFA->next = (i596_rfd*)word_swap((uint32_t)sc->pSavedRfdQueue); + if ( sc->pSavedRfdQueue != I596_NULL ) { + sc->pEndRFA = sc->pEndSavedQueue; + sc->pSavedRfdQueue = sc->pEndSavedQueue = I596_NULL; + sc -> countRFD = sc->rxBdCount ; + } + + /* Re-address the head of the RFA in the SCB */ + sc->scb.pRfd = sc->pBeginRFA; + sc->scb.rfd_pointer = word_swap((unsigned long)sc->pBeginRFA); + + /* Clear the status of all RFDs */ + uti596_clearListStatus( sc->pBeginRFA ); + + printk(("uti596_reset: Starting NIC\n")) + + /* Start the receiver */ + sc->scb.command = RX_START; + sc->started = 1; /* assume that the start is accepted */ + sc->resetDone = 1; + uti596_issueCA ( sc, UTI596_WAIT_FOR_CU_ACCEPT ); + + UTI_596_ASSERT(sc->pCmdHead == I596_NULL, "Reset: CMD not cleared\n") + + #ifdef DBG_RESET + printk(("uti596_reset: completed\n")) + #endif +} + +/* + * uti596_dequeue + * + * Remove an RFD from the received fram queue + * + * Input parameters: + * ppQ - a pointer to a i596_rfd pointer + * + * Output parameters: NONE + * + * Return value: + * pRfd - a pointer to the dequeued RFD + */ +i596_rfd * uti596_dequeue( + i596_rfd ** ppQ +) +{ + ISR_Level level; + i596_rfd * pRfd; + + _ISR_Local_disable(level); + + /* invalid address, or empty queue or emptied queue */ + if( ppQ == NULL || *ppQ == NULL || *ppQ == I596_NULL) { + _ISR_Local_enable(level); + return I596_NULL; + } + + /* + * Point to the dequeued buffer, then + * adjust the queue pointer and detach the buffer + */ + pRfd = *ppQ; + *ppQ = (i596_rfd *) word_swap ((unsigned long) pRfd->next); + pRfd->next = I596_NULL; /* unlink the rfd being returned */ + + _ISR_Local_enable(level); + return pRfd; +} + +/* + * uti596_append + * + * Remove an RFD buffer from the RFA and tack it on to + * the received frame queue for processing. + * + * Input parameters: + * ppQ - a pointer to the queue pointer + * pRfd - a pointer to the buffer to be returned + * + * Output parameters: NONE + * + * Return value: NONE + */ + +void uti596_append( + i596_rfd ** ppQ, + i596_rfd * pRfd +) +{ + + i596_rfd *p; + + if ( pRfd != NULL && pRfd != I596_NULL) { + pRfd -> next = I596_NULL; + pRfd -> cmd |= CMD_EOL; /* set EL bit */ + + if ( *ppQ == NULL || *ppQ == I596_NULL ) { + /* empty list */ + *ppQ = pRfd; + } + else { + /* walk to the end of the list */ + for ( p=*ppQ; + p->next != I596_NULL; + p=(i596_rfd *) word_swap ((unsigned long)p->next) ); + + /* append the rfd */ + p->cmd &= ~CMD_EOL; /* Clear EL bit at end */ + p->next = (i596_rfd *) word_swap ((unsigned long)pRfd); + } + } + else { + printk(("Illegal attempt to append: %p\n", pRfd)) + } +} + +/* + * uti596_supplyFD + * + * Return a buffer (RFD) to the receive frame area (RFA). + * Call with interrupts disabled. + * + * Input parameters: + * pRfd - a pointer to the buffer to be returned + * + * Output parameters: NONE + * + * Return value: NONE + */ +void uti596_supplyFD ( + i596_rfd * pRfd +) +{ + i596_rfd *pLastRfd; + + UTI_596_ASSERT(pRfd != I596_NULL, "Supplying NULL RFD!\n") + + pRfd -> cmd = CMD_EOL; + pRfd -> pRbd = I596_NULL; + pRfd -> next = I596_NULL; + pRfd -> stat = 0x0000; /* clear STAT_C and STAT_B bits */ + + /* + * Check if the list is empty: + */ + if ( uti596_softc.pBeginRFA == I596_NULL ) { + + /* Start a list with one entry */ + uti596_softc.pBeginRFA = uti596_softc.pEndRFA = pRfd; + UTI_596_ASSERT(uti596_softc.countRFD == 0, "Null begin, but non-zero count\n") + if ( uti596_softc.pLastUnkRFD != I596_NULL ) { + printk(("LastUnkRFD is NOT NULL!!\n")) + } + uti596_softc.countRFD = 1; + return; + } + + /* + * Check if the last RFD is used/read by the 596. + */ + pLastRfd = uti596_softc.pEndRFA; + + /* C = complete, B = busy (prefetched) */ + if ( pLastRfd != I596_NULL && ! (pLastRfd -> stat & ( STAT_C | STAT_B ) )) { + + /* + * Not yet too late to add it + */ + pLastRfd -> next = (i596_rfd *) word_swap ((unsigned long)pRfd); + pLastRfd -> cmd &= ~CMD_EOL; /* RESET_EL : reset EL bit to 0 */ + uti596_softc.countRFD++; /* Lets assume we add it successfully + If not, the RFD may be used, and may + decrement countRFD < 0 !! */ + /* + * Check if the last RFD was used while appending. + */ + if ( pLastRfd -> stat & ( STAT_C | STAT_B ) ) { /* completed or was prefetched */ + /* + * Either the EL bit of the last rfd has been read by the 82596, + * and it will stop after reception,( true when RESET_EL not reached ) or + * the EL bit was NOT read by the 82596 and it will use the linked + * RFD for the next reception. ( true when RESET_EL was reached ) + * So, it is unknown whether or not the linked rfd will be used. + * Therefore, the end of list CANNOT be updated. + */ + UTI_596_ASSERT ( uti596_softc.pLastUnkRFD == I596_NULL, "Too many Unk RFD's\n" ) + uti596_softc.pLastUnkRFD = pRfd; + return; + } + else { + /* + * The RFD being added was not touched by the 82596 + */ + if (uti596_softc.pLastUnkRFD != I596_NULL ) { + + uti596_append((i596_rfd **)&uti596_softc.pSavedRfdQueue, pRfd); /* Only here! saved Q */ + uti596_softc.pEndSavedQueue = pRfd; + uti596_softc.savedCount++; + uti596_softc.countRFD--; + + } + else { + + uti596_softc.pEndRFA = pRfd; /* the RFA has been extended */ + + if ( ( uti596_softc.scb.status & SCB_STAT_RNR || + uti596_softc.scb.status & RU_NO_RESOURCES ) && + uti596_softc.countRFD > 1 ) { + + /* Ensure that beginRFA is not EOL */ + uti596_softc.pBeginRFA -> cmd &= ~CMD_EOL; + + UTI_596_ASSERT(uti596_softc.pEndRFA -> next == I596_NULL, "supply: List buggered\n") + UTI_596_ASSERT(uti596_softc.pEndRFA -> cmd & CMD_EOL, "supply: No EOL at end.\n") + UTI_596_ASSERT(uti596_softc.scb.command == 0, "Supply: scb command must be zero\n") + + #ifdef DBG_MEM + printk(("uti596_supplyFD: starting receiver")) + #endif + + /* start the receiver */ + UTI_596_ASSERT(uti596_softc.pBeginRFA != I596_NULL, "rx start w/ NULL begin! \n") + uti596_softc.scb.pRfd = uti596_softc.pBeginRFA; + uti596_softc.scb.rfd_pointer = word_swap ((unsigned long) uti596_softc.pBeginRFA); + + /* Don't ack RNR! The receiver should be stopped in this case */ + uti596_softc.scb.command = RX_START | SCB_STAT_RNR; + + UTI_596_ASSERT( !(uti596_softc.scb.status & SCB_STAT_FR),"FRAME RECEIVED INT COMING!\n") + + /* send CA signal */ + uti596_issueCA ( &uti596_softc, UTI596_NO_WAIT ); + } + } + return; + } + } + else { + /* + * too late , pLastRfd in use ( or NULL ), + * in either case, EL bit has been read, and RNR condition will occur + */ + uti596_append( (i596_rfd **)&uti596_softc.pSavedRfdQueue, pRfd); /* save it for RNR */ + + uti596_softc.pEndSavedQueue = pRfd; /* reset end of saved queue */ + uti596_softc.savedCount++; + + return; + } +} + +/* + * send_packet + * + * Send a raw ethernet packet, add a + * transmit command to the CBL + * + * Input parameters: + * ifp - a pointer to the ifnet structure + * m - a pointer to the mbuf being sent + * + * Output parameters: NONE + * + * Return value: NONE + */ +void send_packet( + struct ifnet *ifp, struct mbuf *m +) +{ + i596_tbd *pPrev = I596_NULL; + i596_tbd *pRemainingTbdList; + i596_tbd *pTbd; + struct mbuf *n, *input_m = m; + uti596_softc_ *sc = ifp->if_softc; + struct mbuf *l = NULL; + unsigned int length = 0; + rtems_status_code status; + int bd_count = 0; + rtems_event_set events; + + /* + * For all mbufs in the chain, + * fill a transmit buffer descriptor for each + */ + pTbd = (i596_tbd*) word_swap ((unsigned long)sc->pTxCmd->pTbd); + + do { + if (m->m_len) { + /* + * Fill in the buffer descriptor + */ + length += m->m_len; + pTbd->data = (char *) word_swap ((unsigned long) mtod (m, void *)); + pTbd->size = m->m_len; + pPrev = pTbd; + pTbd = (i596_tbd *) word_swap ((unsigned long) pTbd->next); + l = m; + m = m->m_next; + } + else { + /* + * Just toss empty mbufs + */ + MFREE (m, n); + m = n; + if (l != NULL) + l->m_next = m; + } + } while( m != NULL && ++bd_count < 16 ); + + if ( length < UTI_596_ETH_MIN_SIZE ) { + pTbd->data = (char *) word_swap ((unsigned long) sc->zeroes); /* add padding to pTbd */ + pTbd->size = UTI_596_ETH_MIN_SIZE - length; /* zeroes have no effect on the CRC */ + } + else /* Don't use pTbd in the send routine */ + pTbd = pPrev; + + /* Disconnect the packet from the list of Tbd's */ + pRemainingTbdList = (i596_tbd *) word_swap ((unsigned long)pTbd->next); + pTbd->next = I596_NULL; + pTbd->size |= UTI_596_END_OF_FRAME; + + sc->rawsndcnt++; + + #ifdef DBG_SEND + printk(("send_packet: sending packet\n")) + #endif + + /* Sending Zero length packet: shouldn't happen */ + if (pTbd->size <= 0) return; + + #ifdef DBG_PACKETS + printk (("\nsend_packet: Transmitter adds packet\n")) + print_hdr ( sc->pTxCmd->pTbd->data ); /* print the first part */ + print_pkt ( sc->pTxCmd->pTbd->next->data ); /* print the first part */ + print_echo (sc->pTxCmd->pTbd->data); + #endif + + /* add the command to the output command queue */ + uti596_addCmd ( (i596_cmd *) sc->pTxCmd ); + + /* sleep until the command has been processed or Timeout encountered. */ + status= rtems_bsdnet_event_receive (INTERRUPT_EVENT, + RTEMS_WAIT|RTEMS_EVENT_ANY, + RTEMS_NO_TIMEOUT, + &events); + + if ( status != RTEMS_SUCCESSFUL ) { + printk(("Could not sleep %s\n", rtems_status_text(status))) + } + + #ifdef DBG_SEND + printk(("send_packet: RAW - wake\n")) + #endif + + sc->txInterrupts++; + + if ( sc->pTxCmd -> cmd.status & STAT_OK ) { + sc->stats.tx_packets++; + } + else { + + printk(("*** send_packet: Driver Error 0x%x\n", sc->pTxCmd -> cmd.status )) + + sc->stats.tx_errors++; + if ( sc->pTxCmd->cmd.status & 0x0020 ) + sc->stats.tx_retries_exceeded++; + if (!(sc->pTxCmd->cmd.status & 0x0040)) + sc->stats.tx_heartbeat_errors++; + if ( sc->pTxCmd->cmd.status & 0x0400 ) + sc->stats.tx_carrier_errors++; + if ( sc->pTxCmd->cmd.status & 0x0800 ) + sc->stats.collisions++; + if ( sc->pTxCmd->cmd.status & 0x1000 ) + sc->stats.tx_aborted_errors++; + } /* end if stat_ok */ + + /* + * Restore the transmitted buffer descriptor chain. + */ + pTbd -> next = (i596_tbd *) word_swap ((unsigned long)pRemainingTbdList); + + /* + * Free the mbufs used by the sender. + */ + m = input_m; + while ( m != NULL ) { + MFREE(m,n); + m = n; + } +} + +/*********************************************************************** + * Function: uti596_attach + * + * Description: + * Configure the driver, and connect to the network stack + * + * Algorithm: + * + * Check parameters in the ifconfig structure, and + * set driver parameters accordingly. + * Initialize required rx and tx buffers. + * Link driver data structure onto device list. + * Return 1 on successful completion. + * + ***********************************************************************/ + +int uti596_attach( + struct rtems_bsdnet_ifconfig * pConfig, + int attaching +) +{ + uti596_softc_ *sc = &uti596_softc; /* device dependent data structure */ + struct ifnet * ifp = (struct ifnet *)&sc->arpcom.ac_if; /* ifnet structure */ + int unitNumber; + char *unitName; +#if defined(mvme167) + unsigned char j1; /* State of J1 jumpers */ + char *pAddr; + int addr; +#endif + + #ifdef DBG_ATTACH + printk(("uti596_attach: begins\n")) + #endif + + /* The NIC is not started yet */ + sc->started = 0; + + /* Indicate to ULCS that this is initialized */ + ifp->if_softc = (void *)sc; + sc->pScp = NULL; + + /* Parse driver name */ + if ((unitNumber = rtems_bsdnet_parse_driver_name (pConfig, &unitName)) < 0) + return 0; + + ifp->if_name = unitName; + ifp->if_unit = unitNumber; + + /* Assign mtu */ + if ( pConfig -> mtu ) + ifp->if_mtu = pConfig -> mtu; + else + ifp->if_mtu = ETHERMTU; + + /* + * Check whether parameters should be obtained from NVRAM. If + * yes, and if an IP address, netmask, or ethernet address are + * provided in NVRAM, cheat, and stuff them into the ifconfig + * structure, OVERRIDING and existing or NULL values. + * + * Warning: If values are provided in NVRAM, the ifconfig entries + * must be NULL because buffer memory allocated to hold the + * structure values is unrecoverable and would be lost here. + */ + +#if defined(mvme167) + /* Read the J1 header */ + j1 = (unsigned char)(lcsr->vector_base & 0xFF); + + if ( !(j1 & 0x10) ) { + /* Jumper J1-4 is on, configure from NVRAM */ + + if ( (addr = nvram->ipaddr) ) { + /* We have a non-zero entry, copy the value */ + if ( (pAddr = malloc ( INET_ADDR_MAX_BUF_SIZE, 0, M_NOWAIT )) ) + pConfig->ip_address = (char *)inet_ntop(AF_INET, &addr, pAddr, INET_ADDR_MAX_BUF_SIZE -1 ); + else + rtems_panic("Can't allocate ip_address buffer!\n"); + } + + if ( (addr = nvram->netmask) ) { + /* We have a non-zero entry, copy the value */ + if ( (pAddr = malloc ( INET_ADDR_MAX_BUF_SIZE, 0, M_NOWAIT )) ) + pConfig->ip_netmask = (char *)inet_ntop(AF_INET, &addr, pAddr, INET_ADDR_MAX_BUF_SIZE -1 ); + else + rtems_panic("Can't allocate ip_netmask buffer!\n"); + } + + /* Ethernet address requires special handling -- it must be copied into + * the arpcom struct. The following if construct serves only to give the + * NVRAM parameter the highest priority if J1-4 indicates we are configuring + * from NVRAM. + * + * If the ethernet address is specified in NVRAM, go ahead and copy it. + * (ETHER_ADDR_LEN = 6 bytes). + */ + if ( nvram->enaddr[0] || nvram->enaddr[1] || nvram->enaddr[2] ) { + /* Anything in the first three bytes indicates a non-zero entry, copy value */ + memcpy ((void *)sc->arpcom.ac_enaddr, &nvram->enaddr, ETHER_ADDR_LEN); + } + else if ( pConfig->hardware_address) { + /* There is no entry in NVRAM, but there is in the ifconfig struct, so use it. */ + memcpy ((void *)sc->arpcom.ac_enaddr, pConfig->hardware_address, ETHER_ADDR_LEN); + } + else { + /* There is no ethernet address provided, so it will be read + * from BBRAM at $FFFC1F2C by default. [mvme167 manual p. 1-47] + */ + memcpy ((void *)sc->arpcom.ac_enaddr, (char *)0xFFFC1F2C, ETHER_ADDR_LEN); + } + } + else if ( pConfig->hardware_address) { + /* We are not configuring from NVRAM (J1-4 is off), and the ethernet address + * is given in the ifconfig structure. Copy it. + */ + memcpy ((void *)sc->arpcom.ac_enaddr, pConfig->hardware_address, ETHER_ADDR_LEN); + } + else +#endif + { + /* We are not configuring from NVRAM (J1-4 is off), and there is no ethernet + * address provided in the ifconfig struct, so it will be read from BBRAM at + * $FFFC1F2C by default. [mvme167 manual p. 1-47] + */ + memcpy ((void *)sc->arpcom.ac_enaddr, (char *)0xFFFC1F2C, ETHER_ADDR_LEN); + } + + /* Possibly override default acceptance of broadcast packets */ + if (pConfig->ignore_broadcast) + uti596initSetup[8] |= 0x02; + + /* Assign requested receive buffer descriptor count */ + if (pConfig->rbuf_count) + sc->rxBdCount = pConfig->rbuf_count; + else + sc->rxBdCount = RX_BUF_COUNT; + + /* Assign requested tx buffer descriptor count */ + if (pConfig->xbuf_count) + sc->txBdCount = pConfig->xbuf_count; + else + sc->txBdCount = TX_BUF_COUNT * TX_BD_PER_BUF; + + /* Set up fields in the ifnet structure*/ + ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX; + ifp->if_snd.ifq_maxlen = ifqmaxlen; + ifp->if_init = uti596_init; + ifp->if_ioctl = uti596_ioctl; + ifp->if_start = uti596_start; + ifp->if_output = ether_output; + + /* uti596_softc housekeeping */ + sc->started = 1; + sc->pInboundFrameQueue = I596_NULL; + sc->scb.command = 0; + + /* + * Attach the interface + */ + if_attach (ifp); + ether_ifattach (ifp); + return 1; +} + +/*********************************************************************** + * Function: uti596_start + * + * Description: + * start the driver + * + * Algorithm: + * send an event to the tx task + * set the if_flags + * + ***********************************************************************/ +static void uti596_start( + struct ifnet *ifp +) +{ + uti596_softc_ *sc = ifp->if_softc; + + #ifdef DBG_START + printk(("uti596_start: begins\n")) + #endif + + rtems_bsdnet_event_send (sc->txDaemonTid, START_TRANSMIT_EVENT); + ifp->if_flags |= IFF_OACTIVE; +} + +/*********************************************************************** + * Function: uti596_init + * + * Description: + * driver initialization + * + * Algorithm: + * initialize the 82596 + * start driver tx and rx tasks, and reset task + * send the RX_START command the the RU + * set if_flags + * + * + ***********************************************************************/ +void uti596_init( + void * arg +) +{ + uti596_softc_ *sc = arg; + struct ifnet *ifp = (struct ifnet *)&sc->arpcom.ac_if; + + if (sc->txDaemonTid == 0) { + + /* + * Initialize the 82596 + */ + #ifdef DBG_INIT + printk(("uti596_init: begins\nuti596_init: initializing the 82596...\n")) + #endif + uti596_initialize_hardware(sc); + + /* + * Start driver tasks + */ + #ifdef DBG_INIT + printk(("uti596_init: starting driver tasks...\n")) + #endif + sc->txDaemonTid = rtems_bsdnet_newproc ("UTtx", 2*4096, uti596_txDaemon, (void *)sc); + sc->rxDaemonTid = rtems_bsdnet_newproc ("UTrx", 2*4096, uti596_rxDaemon, (void *)sc); + sc->resetDaemonTid = rtems_bsdnet_newproc ("UTrt", 2*4096, uti596_resetDaemon, (void *)sc); + + #ifdef DBG_INIT + printk(("uti596_init: After attach, status of board = 0x%x\n", sc->scb.status )) + #endif + } + + /* + * In case the ISR discovers there are no resources it reclaims + * them and restarts + */ + sc->started = 1; + + /* + * Enable receiver + */ + #ifdef DBG_INIT + printk(("uti596_init: enabling the reciever...\n" )) + #endif + sc->scb.command = RX_START; + uti596_issueCA ( sc, UTI596_WAIT_FOR_CU_ACCEPT ); + + /* + * Tell the world that we're running. + */ + ifp->if_flags |= IFF_RUNNING; + #ifdef DBG_INIT + printk(("uti596_init: completed.\n")) + #endif +} + +/*********************************************************************** + * Function: uti596stop + * + * Description: + * stop the driver + * + * Algorithm: + * mark driver as not started, + * mark transmitter as busy + * abort any transmissions/receptions + * clean-up all buffers ( RFD's et. al. ) + * + * + ***********************************************************************/ + +/* static */ void uti596_stop( + uti596_softc_ *sc +) +{ + struct ifnet *ifp = (struct ifnet *)&sc->arpcom.ac_if; + + ifp->if_flags &= ~IFF_RUNNING; + sc->started = 0; + + #ifdef DBG_STOP + printk(("uti596stop: %s: Shutting down ethercard, status was %4.4x.\n", + uti596_softc.arpcom.ac_if.if_name, uti596_softc.scb.status)) + #endif + + printk(("Stopping interface\n")) + sc->scb.command = CUC_ABORT | RX_ABORT; + i82596->chan_attn = 0x00000000; +} + +/*********************************************************************** + * Function: void uti596_txDaemon + * + * Description: Transmit task + * + * Algorithm: Get mbufs to be transmitted, stuff into RFDs, send + * + ***********************************************************************/ + +void uti596_txDaemon( + void *arg +) +{ + uti596_softc_ *sc = (uti596_softc_ *)arg; + struct ifnet *ifp = (struct ifnet *)&sc->arpcom.ac_if; + struct mbuf *m; + rtems_event_set events; + + for (;;) { + /* + * Wait for packet from stack + */ + rtems_bsdnet_event_receive (START_TRANSMIT_EVENT, + RTEMS_EVENT_ANY | RTEMS_WAIT, + RTEMS_NO_TIMEOUT, &events); + + /* + * Send packets till queue is empty. + * Ensure that irq is on before sending. + */ + for (;;) { + /* Get the next mbuf chain to transmit. */ + IF_DEQUEUE(&ifp->if_snd, m); + if (!m) + break; + + send_packet (ifp, m); /* blocks */ + } + ifp->if_flags &= ~IFF_OACTIVE; /* no more to send, mark output inactive */ + } +} + +/*********************************************************************** + * Function: uti596_rxDaemon + * + * Description: Receiver task + * + * Algorithm: Extract the packet from an RFD, and place into an + * mbuf chain. Place the mbuf chain in the network task + * queue. Assumes that the frame check sequence is removed + * by the 82596. + * + ***********************************************************************/ + +/* static */ void uti596_rxDaemon( + void *arg +) +{ + uti596_softc_ *sc = (uti596_softc_ *)arg; + struct ifnet *ifp = (struct ifnet *)&sc->arpcom.ac_if; + struct mbuf *m; + + i596_rfd *pRfd; + ISR_Level level; + rtems_id tid; + rtems_event_set events; + struct ether_header *eh; + + int frames = 0; + + #ifdef DBG_RX + printk(("uti596_rxDaemon: begin\n")) + printk(("&scb = %p, pRfd = %p\n", &sc->scb,sc->scb.pRfd)) + #endif + + rtems_task_ident (0, 0, &tid); + + for(;;) { + /* + * Wait for packet. + */ + #ifdef DBG_RX + printk(("uti596_rxDaemon: Receiver sleeps\n")) + #endif + + rtems_bsdnet_event_receive (INTERRUPT_EVENT, + RTEMS_WAIT|RTEMS_EVENT_ANY, + RTEMS_NO_TIMEOUT, + &events); + + #ifdef DBG_RX + printk(("uti596_rxDaemon: Receiver wakes\n")) + #endif + /* + * While received frames are available. Note that the frame may be + * a fragment, so it is NOT a complete packet. + */ + pRfd = uti596_dequeue( (i596_rfd **)&sc->pInboundFrameQueue); + while ( pRfd && + pRfd != I596_NULL && + pRfd -> stat & STAT_C ) + { + + if ( pRfd->stat & STAT_OK) { /* a good frame */ + int pkt_len = pRfd->count & 0x3fff; /* the actual # of bytes received */ + + #ifdef DBG_RX + printk(("uti596_rxDaemon: Good frame, @%p, data @%p length %d\n", pRfd, pRfd -> data , pkt_len)) + #endif + frames++; + + /* + * Allocate an mbuf to give to the stack + * The format of the data portion of the RFD is: + * . + * The FRAME CHECK SEQUENCE / CRC is stripped by the uti596. + * This is to be optimized later.... should not have to memcopy! + */ + MGETHDR(m, M_WAIT, MT_DATA); + MCLGET(m, M_WAIT); + + m->m_pkthdr.rcvif = ifp; + /* move everything into an mbuf */ + memcpy(m->m_data, (const char *)pRfd->data, pkt_len); + m->m_len = m->m_pkthdr.len = pkt_len - sizeof(struct ether_header) - 4; + + /* move the header to an mbuf */ + eh = mtod (m, struct ether_header *); + m->m_data += sizeof(struct ether_header); + + #ifdef DBG_PACKETS + { + int i; + printk(("uti596_rxDaemon: mbuf contains:\n")) + print_eth( (char *) (((int)m->m_data)-sizeof(struct ether_header))); + for ( i = 0; i<20; i++) { + printk((".")) + } + } + #endif + + ether_input (ifp, eh, m); + + } /* end if STAT_OK */ + + else { + /* + * A bad frame is present: Note that this could be the last RFD! + */ + #ifdef DBG_RX + printk(("uti596_rxDaemon: Bad frame\n")) + #endif + /* + * FIX ME: use the statistics from the SCB + */ + sc->stats.rx_errors++; + if ((sc->scb.pRfd->stat) & 0x0001) + sc->stats.collisions++; + if ((sc->scb.pRfd->stat) & 0x0080) + sc->stats.rx_length_errors++; + if ((sc->scb.pRfd->stat) & 0x0100) + sc->stats.rx_over_errors++; + if ((sc->scb.pRfd->stat) & 0x0200) + sc->stats.rx_fifo_errors++; + if ((sc->scb.pRfd->stat) & 0x0400) + sc->stats.rx_frame_errors++; + if ((sc->scb.pRfd->stat) & 0x0800) + sc->stats.rx_crc_errors++; + if ((sc->scb.pRfd->stat) & 0x1000) + sc->stats.rx_length_errors++; + } + + UTI_596_ASSERT(pRfd != I596_NULL, "Supplying NULL RFD\n") + + _ISR_Local_disable(level); + uti596_supplyFD ( pRfd ); /* Return RFD to RFA. */ + _ISR_Local_enable(level); + + pRfd = uti596_dequeue( (i596_rfd **)&sc->pInboundFrameQueue); /* grab next frame */ + + } /* end while */ + } /* end for() */ + + #ifdef DBG_RX + printk (("uti596_rxDaemon: frames ... %d\n", frames)) + #endif +} + +/*********************************************************************** + * Function: void uti596_resetDaemon + * + * Description: + ***********************************************************************/ +void uti596_resetDaemon( + void *arg +) +{ + uti596_softc_ *sc = (uti596_softc_ *)arg; + rtems_event_set events; + rtems_time_of_day tm_struct; + + /* struct ifnet *ifp = &sc->arpcom.ac_if; */ + + for (;;) { + /* Wait for reset event from ISR */ + rtems_bsdnet_event_receive (NIC_RESET_EVENT, + RTEMS_EVENT_ANY | RTEMS_WAIT, + RTEMS_NO_TIMEOUT, &events); + + rtems_clock_get_tod(&tm_struct); + printk(("reset daemon: Resetting NIC @ %" PRIu32 ":%" PRIu32 ":%" PRIu32 " \n", + tm_struct.hour, tm_struct.minute, tm_struct.second)) + + sc->stats.nic_reset_count++; + /* Reinitialize the LANC */ + rtems_bsdnet_semaphore_obtain (); + uti596_reset(); + rtems_bsdnet_semaphore_release (); + } +} + +/*********************************************************************** + * Function: uti596_DynamicInterruptHandler + * + * Description: + * This is the interrupt handler for the uti596 board + * + ***********************************************************************/ + +/* static */ rtems_isr uti596_DynamicInterruptHandler( + rtems_vector_number irq +) +{ +int fullStatus; + + #ifdef DBG_ISR + printk(("uti596_DynamicInterruptHandler: begins")) + #endif + + uti596_wait (&uti596_softc, UTI596_WAIT_FOR_CU_ACCEPT); + + scbStatus = (fullStatus = uti596_softc.scb.status) & 0xf000; + + if ( scbStatus ) { + /* acknowledge interrupts */ + + /* Write to the ICLR bit in the PCCchip2 control registers to clear + * the INT status bit. Clearing INT here *before* sending the CA signal + * to the 82596 should ensure that interrupts won't be lost. + */ + pccchip2->LANC_int_ctl |=0x08; + pccchip2->LANC_berr_ctl |=0x08; + + /* printk(("***INFO: ACK %x\n", scbStatus))*/ + + /* Send the CA signal to acknowledge interrupt */ + uti596_softc.scb.command = scbStatus; + uti596_issueCA ( &uti596_softc, UTI596_NO_WAIT ); + + if( uti596_softc.resetDone ) { + /* stack is attached */ + uti596_wait ( &uti596_softc, UTI596_WAIT_FOR_CU_ACCEPT ); + } + else { + printk(("***INFO: ACK'd w/o processing. status = %x\n", scbStatus)) + return; + } + } + else { +#ifndef IGNORE_SPURIOUS_IRQ + printk(("\n***ERROR: Spurious interrupt (full status 0x%x). Resetting...\n", fullStatus)) + uti596_softc.nic_reset = 1; +#endif + } + + if ( (scbStatus & SCB_STAT_CX) && !(scbStatus & SCB_STAT_CNA) ) { + printk(("\n*****ERROR: Command Complete, and CNA available: 0x%x\nResetting...", scbStatus)) + uti596_softc.nic_reset = 1; + return; + } + + if ( !(scbStatus & SCB_STAT_CX) && (scbStatus & SCB_STAT_CNA) ) { + printk(("\n*****ERROR: CNA, NO CX:0x%x\nResetting...",scbStatus)) + uti596_softc.nic_reset = 1; + return; + } + + if ( scbStatus & SCB_CUS_SUSPENDED ) { + printk(("\n*****ERROR: Command unit suspended!:0x%x\nResetting...",scbStatus)) + uti596_softc.nic_reset = 1; + return; + } + + if ( scbStatus & RU_SUSPENDED ) { + printk(("\n*****ERROR: Receive unit suspended!:0x%x\nResetting...",scbStatus)) + uti596_softc.nic_reset = 1; + return; + } + + if ( scbStatus & SCB_STAT_RNR ) { + printk(("\n*****WARNING: RNR %x\n",scbStatus)) + if (uti596_softc.pBeginRFA != I596_NULL) { + printk(("*****INFO: RFD cmd: %x status:%x\n", uti596_softc.pBeginRFA->cmd, + uti596_softc.pBeginRFA->stat)) + } + else { + printk(("*****WARNING: RNR condition with NULL BeginRFA\n")) + } + } + + /* + * Receive Unit Control + * a frame is received + */ + if ( scbStatus & SCB_STAT_FR ) { + uti596_softc.rxInterrupts++; + + #ifdef DBG_ISR + printk(("uti596_DynamicInterruptHandler: Frame received\n")) + #endif + if ( uti596_softc.pBeginRFA == I596_NULL || + !( uti596_softc.pBeginRFA -> stat & STAT_C)) { +#ifndef IGNORE_NO_RFA + uti596_dump_scb(); + uti596_softc.nic_reset = 1; +#endif + } + else { + while ( uti596_softc.pBeginRFA != I596_NULL && + ( uti596_softc.pBeginRFA -> stat & STAT_C)) { + + #ifdef DBG_ISR + printk(("uti596_DynamicInterruptHandler: pBeginRFA != NULL\n")) + #endif + count_rx ++; +#ifndef IGNORE_MULTIPLE_RF + if ( count_rx > 1) { + printk(("****WARNING: Received %i frames on 1 interrupt \n", count_rx)) + } +#endif + /* Give Received Frame to the ULCS */ + uti596_softc.countRFD--; + + if ( uti596_softc.countRFD < 0 ) { + printk(("ISR: Count < 0 !!! count == %d, beginRFA = %p\n", + uti596_softc.countRFD, uti596_softc.pBeginRFA)) + } + uti596_softc.stats.rx_packets++; + /* the rfd next link is stored with upper and lower words swapped so read it that way */ + pIsrRfd = (i596_rfd *) word_swap ((unsigned long)uti596_softc.pBeginRFA->next); + /* the append destroys the link */ + uti596_append( (i596_rfd **)&uti596_softc.pInboundFrameQueue , uti596_softc.pBeginRFA ); + + /* + * if we have just received the a frame in the last unknown RFD, + * then it is certain that the RFA is empty. + */ + if ( uti596_softc.pLastUnkRFD == uti596_softc.pBeginRFA ) { + UTI_596_ASSERT(uti596_softc.pLastUnkRFD != I596_NULL,"****ERROR:LastUnk is NULL, begin ptr @ end!\n") + uti596_softc.pEndRFA = uti596_softc.pLastUnkRFD = I596_NULL; + } + + #ifdef DBG_ISR + printk(("uti596_DynamicInterruptHandler: Wake %#x\n",uti596_softc.rxDaemonTid)) + #endif + sc = rtems_bsdnet_event_send(uti596_softc.rxDaemonTid, INTERRUPT_EVENT); + if ( sc != RTEMS_SUCCESSFUL ) { + rtems_panic("Can't notify rxDaemon: %s\n", + rtems_status_text (sc)); + } + #ifdef DBG_ISR + else { + printk(("uti596_DynamicInterruptHandler: Rx Wake: %#x\n",uti596_softc.rxDaemonTid)) + } + #endif + + uti596_softc.pBeginRFA = pIsrRfd; + } /* end while */ + } /* end if */ + + if ( uti596_softc.pBeginRFA == I596_NULL ) { + /* adjust the pEndRFA to reflect an empty list */ + if ( uti596_softc.pLastUnkRFD == I596_NULL && uti596_softc.countRFD != 0 ) { + printk(("Last Unk is NULL, BeginRFA is null, and count == %d\n", + uti596_softc.countRFD)) + } + uti596_softc.pEndRFA = I596_NULL; + if ( uti596_softc.countRFD != 0 ) { + printk(("****ERROR:Count is %d, but begin ptr is NULL\n", + uti596_softc.countRFD )) + } + } + } /* end if ( scbStatus & SCB_STAT_FR ) */ + + /* + * Command Unit Control + * a command is completed + */ + if ( scbStatus & SCB_STAT_CX ) { + #ifdef DBG_ISR + printk(("uti596_DynamicInterruptHandler: CU\n")) + #endif + + pIsrCmd = uti596_softc.pCmdHead; + + /* For ALL completed commands */ + if ( pIsrCmd != I596_NULL && pIsrCmd->status & STAT_C ) { + + #ifdef DBG_ISR + printk(("uti596_DynamicInterruptHandler: pIsrCmd != NULL\n")) + #endif + + /* Adjust the command block list */ + uti596_softc.pCmdHead = (i596_cmd *) word_swap ((unsigned long)pIsrCmd->next); + + /* + * If there are MORE commands to process, + * the serialization in the raw routine has failed. + * ( Perhaps AddCmd is bad? ) + */ + UTI_596_ASSERT(uti596_softc.pCmdHead == I596_NULL, "****ERROR: command serialization failed\n") + + /* What if the command did not complete OK? */ + switch ( pIsrCmd->command & 0x7) { + case CmdConfigure: + + uti596_softc.cmdOk = 1; + break; + + case CmdDump: + #ifdef DBG_ISR + printk(("uti596_DynamicInterruptHandler: dump!\n")) + #endif + uti596_softc.cmdOk = 1; + break; + + case CmdDiagnose: + #ifdef DBG_ISR + printk(("uti596_DynamicInterruptHandler: diagnose!\n")) + #endif + uti596_softc.cmdOk = 1; + break; + + case CmdSASetup: + /* printk(("****INFO:Set address interrupt\n")) */ + if ( pIsrCmd -> status & STAT_OK ) { + uti596_softc.cmdOk = 1; + } + else { + printk(("****ERROR:SET ADD FAILED\n")) + } + break; + + case CmdTx: + UTI_596_ASSERT(uti596_softc.txDaemonTid, "****ERROR:Null txDaemonTid\n") + #ifdef DBG_ISR + printk(("uti596_DynamicInterruptHandler: wake TX:0x%x\n",uti596_softc.txDaemonTid)) + #endif + if ( uti596_softc.txDaemonTid ) { + /* Ensure that the transmitter is present */ + sc = rtems_bsdnet_event_send (uti596_softc.txDaemonTid, + INTERRUPT_EVENT); + + if ( sc != RTEMS_SUCCESSFUL ) { + printk(("****ERROR:Could NOT send event to tid 0x%" PRIu32 " : %s\n", + uti596_softc.txDaemonTid, rtems_status_text (sc) )) + } + #ifdef DBG_ISR + else { + printk(("****INFO:Tx wake: %#x\n",uti596_softc.txDaemonTid)) + } + #endif + } + break; + + case CmdMulticastList: + printk(("***ERROR:Multicast?!\n")) + pIsrCmd->next = I596_NULL; + break; + + case CmdTDR: { + unsigned long status = *( (unsigned long *)pIsrCmd)+1; + printk(("****ERROR:TDR?!\n")) + + if (status & STAT_C) { + /* mark the TDR command successful */ + uti596_softc.cmdOk = 1; + } + else { + if (status & 0x4000) { + printk(("****WARNING:Transceiver problem.\n")) + } + if (status & 0x2000) { + printk(("****WARNING:Termination problem.\n")) + } + if (status & 0x1000) { + printk(("****WARNING:Short circuit.\n")) + /* printk(("****INFO:Time %ld.\n", status & 0x07ff)) */ + } + } + } + break; + + default: { + /* + * This should never be reached + */ + printk(("CX but NO known command\n")) + } + } /* end switch */ + + pIsrCmd = uti596_softc.pCmdHead; /* next command */ + if ( pIsrCmd != I596_NULL ) { + printk(("****WARNING: more commands in list, but no start to NIC\n")) + } + } /* end if pIsrCmd != NULL && pIsrCmd->stat & STAT_C */ + + else { + if ( pIsrCmd != I596_NULL ) { + /* The command MAY be NULL from a RESET */ + /* Reset the ethernet card, and wake the transmitter (if necessary) */ + printk(("****INFO: Request board reset ( tx )\n")) + uti596_softc.nic_reset = 1; + if ( uti596_softc.txDaemonTid) { + /* Ensure that a transmitter is present */ + sc = rtems_bsdnet_event_send (uti596_softc.txDaemonTid, + INTERRUPT_EVENT); + if ( sc != RTEMS_SUCCESSFUL ) { + printk(("****ERROR:Could NOT send event to tid 0x%" PRIu32 " : %s\n", + uti596_softc.txDaemonTid, rtems_status_text (sc) )) + } + #ifdef DBG_ISR + else { + printk(("uti596_DynamicInterruptHandler: ****INFO:Tx wake: %#x\n", + uti596_softc.txDaemonTid)) + } + #endif + } + } + } + } /* end if command complete */ + + /* + * If the receiver has stopped, + * check if this is a No Resources scenario, + * Try to add more RFD's ( no RBDs are used ) + */ + if ( uti596_softc.started ) { + if ( scbStatus & SCB_STAT_RNR ) { + #ifdef DBG_ISR + printk(("uti596_DynamicInterruptHandler: INFO:RNR: status %#x \n", + uti596_softc.scb.status )) + #endif + /* + * THE RECEIVER IS OFF! + */ + if ( uti596_softc.pLastUnkRFD != I596_NULL ) { + /* We have an unknown RFD, it is not inbound */ + if ( uti596_softc.pLastUnkRFD -> stat & (STAT_C | STAT_B )) { /* in use */ + uti596_softc.pEndRFA = uti596_softc.pLastUnkRFD; /* update end */ + } + else { + /* + * It is NOT in use, and since RNR, we know EL bit of pEndRFA was read! + * So, unlink it from the RFA and move it to the saved queue. + * But pBegin can equal LastUnk! + */ + + if ( uti596_softc.pEndRFA != I596_NULL ) { + /* check added feb24. */ + #ifdef DBG_ISR + if ((i596_rfd *)word_swap((unsigned long)uti596_softc.pEndRFA->next) != uti596_softc.pLastUnkRFD) { + printk(("***ERROR:UNK: %p not end->next: %p, end: %p\n", + uti596_softc.pLastUnkRFD, + uti596_softc.pEndRFA -> next, + uti596_softc.pEndRFA)) + printk(("***INFO:countRFD now %d\n", + uti596_softc.countRFD)) + printk(("\n\n")) + } + #endif + uti596_softc.pEndRFA -> next = I596_NULL; /* added feb 16 */ + } + uti596_append( (i596_rfd **)&uti596_softc.pSavedRfdQueue, uti596_softc.pLastUnkRFD ); + uti596_softc.savedCount++; + uti596_softc.pEndSavedQueue = uti596_softc.pLastUnkRFD; + uti596_softc.countRFD--; /* It was not in the RFA */ + /* + * The Begin pointer CAN advance this far. We must resynch the CPU side + * with the chip. + */ + if ( uti596_softc.pBeginRFA == uti596_softc.pLastUnkRFD ) { + #ifdef DBG_ISR + if ( uti596_softc.countRFD != 0 ) { + printk(("****INFO:About to set begin to NULL, with count == %d\n\n", + uti596_softc.countRFD )) + } + #endif + uti596_softc.pBeginRFA = I596_NULL; + UTI_596_ASSERT(uti596_softc.countRFD == 0, "****ERROR:Count must be zero here!\n") + } + } + uti596_softc.pLastUnkRFD = I596_NULL; + } /* end if exists UnkRFD */ + + /* + * Append the saved queue to the RFA. + * Any further RFD's being supplied will be added to + * this new list. + */ + if ( uti596_softc.pSavedRfdQueue != I596_NULL ) { + /* entries to add */ + if ( uti596_softc.pBeginRFA == I596_NULL ) { + /* add at beginning to list */ + #ifdef DBG_ISR + if(uti596_softc.countRFD != 0) { + printk(("****ERROR:Begin pointer is NULL, but count == %d\n", + uti596_softc.countRFD)) + } + #endif + uti596_softc.pBeginRFA = uti596_softc.pSavedRfdQueue; + uti596_softc.pEndRFA = uti596_softc.pEndSavedQueue; + uti596_softc.pSavedRfdQueue = uti596_softc.pEndSavedQueue = I596_NULL; /* Reset the End */ + } + else { + #ifdef DBG_ISR + if ( uti596_softc.countRFD <= 0) { + printk(("****ERROR:Begin pointer is not NULL, but count == %d\n", + uti596_softc.countRFD)) + } + #endif + UTI_596_ASSERT( uti596_softc.pEndRFA != I596_NULL, "****WARNING: END RFA IS NULL\n") + UTI_596_ASSERT( uti596_softc.pEndRFA->next == I596_NULL, "****ERROR:END RFA -> next must be NULL\n") + + uti596_softc.pEndRFA->next = (i596_rfd *)word_swap((unsigned long)uti596_softc.pSavedRfdQueue); + uti596_softc.pEndRFA->cmd &= ~CMD_EOL; /* clear the end of list */ + uti596_softc.pEndRFA = uti596_softc.pEndSavedQueue; + uti596_softc.pSavedRfdQueue = uti596_softc.pEndSavedQueue = I596_NULL; /* Reset the End */ + #ifdef DBG_ISR + printk(("uti596_DynamicInterruptHandler: count... %d, saved ... %d \n", + uti596_softc.countRFD, + uti596_softc.savedCount)) + #endif + } + /* printk(("Isr: countRFD = %d\n",uti596_softc.countRFD)) */ + uti596_softc.countRFD += uti596_softc.savedCount; + /* printk(("Isr: after countRFD = %d\n",uti596_softc.countRFD)) */ + uti596_softc.savedCount = 0; + } + + #ifdef DBG_ISR + printk(("uti596_DynamicInterruptHandler: The list starts here %p\n",uti596_softc.pBeginRFA )) + #endif + + if ( uti596_softc.countRFD > 1) { + printk(("****INFO: pBeginRFA -> stat = 0x%x\n",uti596_softc.pBeginRFA -> stat)) + printk(("****INFO: pBeginRFA -> cmd = 0x%x\n",uti596_softc.pBeginRFA -> cmd)) + uti596_softc.pBeginRFA -> stat = 0; + UTI_596_ASSERT(uti596_softc.scb.command == 0, "****ERROR:scb command must be zero\n") + uti596_softc.scb.pRfd = uti596_softc.pBeginRFA; + uti596_softc.scb.rfd_pointer = word_swap((unsigned long)uti596_softc.pBeginRFA); + /* start RX here */ + printk(("****INFO: ISR Starting receiver\n")) + uti596_softc.scb.command = RX_START; /* should this also be CU start? */ + i82596->chan_attn = 0x00000000; + } + } /* end stat_rnr */ + } /* end if receiver started */ + + #ifdef DBG_ISR + printk(("uti596_DynamicInterruptHandler: X\n")) + #endif + count_rx=0; + + /* Do this last, to ensure that the reset is called at the right time. */ + if ( uti596_softc.nic_reset ) { + uti596_softc.nic_reset = 0; + sc = rtems_bsdnet_event_send(uti596_softc.resetDaemonTid, NIC_RESET_EVENT); + if ( sc != RTEMS_SUCCESSFUL ) + rtems_panic ("Can't notify resetDaemon: %s\n", rtems_status_text (sc)); + } + return; +} + +/*********************************************************************** + * Function: uti596_ioctl + * + * Description: + * driver ioctl function + * handles SIOCGIFADDR, SIOCSIFADDR, SIOCSIFFLAGS + * + ***********************************************************************/ + +static int uti596_ioctl( + struct ifnet *ifp, + u_long command, + caddr_t data +) +{ + uti596_softc_ *sc = ifp->if_softc; + int error = 0; + + #ifdef DBG_IOCTL + printk(("uti596_ioctl: begins\n", sc->pScp)) + #endif + + switch (command) { + case SIOCGIFADDR: + case SIOCSIFADDR: + printk(("SIOCSIFADDR\n")) + ether_ioctl (ifp, command, data); + break; + + case SIOCSIFFLAGS: + printk(("SIOCSIFFLAGS\n")) + switch (ifp->if_flags & (IFF_UP | IFF_RUNNING)) { + case IFF_RUNNING: + printk(("IFF_RUNNING\n")) + uti596_stop (sc); + break; + + case IFF_UP: + printk(("IFF_UP\n")) + uti596_init ( (void *)sc); + break; + + case IFF_UP | IFF_RUNNING: + printk(("IFF_UP and RUNNING\n")) + uti596_stop (sc); + uti596_init ( (void *)sc); + break; + + default: + printk(("default\n")) + break; + } + break; + + case SIO_RTEMS_SHOW_STATS: + printk(("show stats\n")) + uti596_stats (sc); + break; + + /* FIXME: All sorts of multicast commands need to be added here! */ + default: + printk(("default: EINVAL\n")) + error = EINVAL; + break; + } + + return error; +} + +/*********************************************************************** + * Function: uti596_stats + * + * Description: + * print out the collected data + * + * Algorithm: + * use printf + * + ***********************************************************************/ + +void uti596_stats( + uti596_softc_ *sc +) +{ + printf ("CPU Reports:\n"); + printf (" Tx raw send count:%-8lu", sc->rawsndcnt); + printf (" Rx Interrupts:%-8lu", sc->rxInterrupts); + printf (" Tx Interrupts:%-8lu\n", sc->txInterrupts); + printf (" Rx Packets:%-8u", sc->stats.rx_packets); + printf (" Tx Attempts:%-u\n", sc->stats.tx_packets); + + printf (" Rx Dropped:%-8u", sc->stats.rx_dropped); + printf (" Rx IP Packets:%-8u", sc->stats.rx_packets); + printf (" Tx Errors:%-8u\n", sc->stats.tx_errors); + printf (" Tx aborted:%-8u", sc->stats.tx_aborted_errors); + printf (" Tx Dropped:%-8u\n", sc->stats.tx_dropped); + printf (" Tx IP packets:%-8u", sc->stats.tx_packets); + + printf (" Collisions Detected:%-8u\n", sc->stats.collisions); + printf (" Tx Heartbeat Errors:%-8u", sc->stats.tx_heartbeat_errors); + printf (" Tx Carrier Errors:%-8u\n", sc->stats.tx_carrier_errors); + printf (" Tx Aborted Errors:%-8u", sc->stats.tx_aborted_errors); + printf (" Rx Length Errors:%-8u\n", sc->stats.rx_length_errors); + printf (" Rx Overrun Errors:%-8u", sc->stats.rx_over_errors); + printf (" Rx Fifo Errors:%-8u\n", sc->stats.rx_fifo_errors); + printf (" Rx Framing Errors:%-8u", sc->stats.rx_frame_errors); + printf (" Rx crc errors:%-8u\n", sc->stats.rx_crc_errors); + + printf (" TX WAITS: %-8lu\n", sc->txRawWait); + + printf (" NIC resets: %-8u\n", sc->stats.nic_reset_count); + + printf (" NIC reports\n"); + + #ifdef DBG_STAT + uti596_dump_scb(); + #endif +} + +/************************ PACKET DEBUG ROUTINES ************************/ + +#ifdef DBG_PACKETS + +/* + * dumpQ + * + * Dumps frame queues for debugging + */ +static void dumpQ( void ) +{ + i596_rfd *pRfd; + + printk(("savedQ:\n")) + + for( pRfd = uti596_softc.pSavedRfdQueue; + pRfd != I596_NULL; + pRfd = (i596_rfd*)word_swap((uint32_t)pRfd -> next)) { + printk(("pRfd: %p, stat: 0x%x cmd: 0x%x\n",pRfd,pRfd -> stat,pRfd -> cmd)) + } + + printk(("Inbound:\n")) + + for( pRfd = uti596_softc.pInboundFrameQueue; + pRfd != I596_NULL; + pRfd = (i596_rfd*)word_swap((uint32_t)pRfd -> next)) { + printk(("pRfd: %p, stat: 0x%x cmd: 0x%x\n",pRfd,pRfd -> stat,pRfd -> cmd)) + } + + printk(("Last Unk: %p\n", uti596_softc.pLastUnkRFD )) + printk(("RFA:\n")) + + for( pRfd = uti596_softc.pBeginRFA; + pRfd != I596_NULL; + pRfd = (i596_rfd*)word_swap((uint32_t)pRfd -> next)) { + printk(("pRfd: %p, stat: 0x%x cmd: 0x%x\n",pRfd,pRfd -> stat,pRfd -> cmd)) + } +} + +/* + * show_buffers + * + * Print out the RFA and frame queues + */ +static void show_buffers (void) +{ + i596_rfd *pRfd; + + printk(("82596 cmd: 0x%x, status: 0x%x RFA len: %d\n", + uti596_softc.scb.command, + uti596_softc.scb.status, + uti596_softc.countRFD)) + + printk(("\nRFA: \n")) + + for ( pRfd = uti596_softc.pBeginRFA; + pRfd != I596_NULL; + pRfd = (i596_rfd *)word_swap((uint32_t)pRfd->next) ) { + printk(("Frame @ %p, status: %2.2x, cmd: %2.2x\n", + pRfd, pRfd->stat, pRfd->cmd)) + } + printk(("\nInbound: \n")) + + for ( pRfd = uti596_softc.pInboundFrameQueue; + pRfd != I596_NULL; + pRfd = (i596_rfd *)word_swap((uint32_t)pRfd->next) ) { + printk(("Frame @ %p, status: %2.2x, cmd: %2.2x\n", + pRfd, pRfd->stat, pRfd->cmd)) + } + + printk(("\nSaved: \n")) + + for ( pRfd = uti596_softc.pSavedRfdQueue; + pRfd != I596_NULL; + pRfd = (i596_rfd *)word_swap((uint32_t)pRfd->next) ) { + printk(("Frame @ %p, status: %2.2x, cmd: %2.2x\n", + pRfd, pRfd->stat, pRfd->cmd)) + } + + printk(("\nUnknown: %p\n",uti596_softc.pLastUnkRFD)) +} + +/* + * show_queues + * + * Print out the saved frame queue and the RFA + */ +static void show_queues(void) +{ + i596_rfd *pRfd; + + printk(("CMD: 0x%x, Status: 0x%x\n", + uti596_softc.scb.command, + uti596_softc.scb.status)) + printk(("saved Q\n")) + + for ( pRfd = uti596_softc.pSavedRfdQueue; + pRfd != I596_NULL && + pRfd != NULL; + pRfd = (i596_rfd *)word_swap((uint32_t)pRfd->next) ) { + printk(("0x%p\n", pRfd)) + } + + printk(("End saved Q 0x%p\n", uti596_softc.pEndSavedQueue)) + + printk(("\nRFA:\n")) + + for ( pRfd = uti596_softc.pBeginRFA; + pRfd != I596_NULL && + pRfd != NULL; + pRfd = (i596_rfd *)word_swap((uint32_t)pRfd->next) ) { + printk(("0x%p\n", pRfd)) + } + + printk(("uti596_softc.pEndRFA: %p\n",uti596_softc.pEndRFA)) +} + +/* + * print_eth + * + * Print the contents of an ethernet packet + * CANNOT BE CALLED FROM ISR + */ +static void print_eth( + unsigned char *add +) +{ + int i; + short int length; + + printk (("Packet Location %p\n", add)) + printk (("Dest ")) + + for (i = 0; i < 6; i++) { + printk ((" %2.2X", add[i])) + } + printk (("\n")) + printk (("Source")) + + for (i = 6; i < 12; i++) { + printk ((" %2.2X", add[i])) + } + + printk (("\n")) + printk (("frame type %2.2X%2.2X\n", add[12], add[13])) + + if ( add[12] == 0x08 && add[13] == 0x06 ) { + /* an ARP */ + printk (("Hardware type : %2.2X%2.2X\n", add[14],add[15])) + printk (("Protocol type : %2.2X%2.2X\n", add[16],add[17])) + printk (("Hardware size : %2.2X\n", add[18])) + printk (("Protocol size : %2.2X\n", add[19])) + printk (("op : %2.2X%2.2X\n", add[20],add[21])) + printk (("Sender Enet addr: ")) + + for ( i=0; i< 5 ; i++) { + printk (("%x:", add[22 + i])) + } + printk (("%x\n", add[27])) + printk (("Sender IP addr: ")) + + for ( i=0; i< 3 ; i++) { + printk (("%u.", add[28 + i])) + } + printk (("%u\n", add[31])) + printk (("Target Enet addr: ")) + + for ( i=0; i< 5 ; i++) { + printk (( "%x:", add[32 + i])) + } + printk (("%x\n", add[37])) + printk (("Target IP addr: ")) + + for ( i=0; i< 3 ; i++) { + printk (( "%u.", add[38 + i])) + } + printk (("%u\n", add[41])) + } + + if ( add[12] == 0x08 && add[13] == 0x00 ) { + /* an IP packet */ + printk (("*********************IP HEADER******************\n")) + printk (("IP version/IPhdr length: %2.2X TOS: %2.2X\n", add[14] , add[15])) + printk (("IP total length: %2.2X %2.2X, decimal %d\n", add[16], add[17], length = (add[16]<<8 | add[17] ))) + printk (("IP identification: %2.2X %2.2X, 3-bit flags and offset %2.2X %2.2X\n", + add[18],add[19], add[20], add[21])) + printk (("IP TTL: %2.2X, protocol: %2.2X, checksum: %2.2X %2.2X \n", + add[22],add[23],add[24],add[25])) + printk (("IP packet type: %2.2X code %2.2X\n", add[34],add[35])) + printk (("Source IP address: ")) + + for ( i=0; i< 3 ; i++) { + printk (("%u.", add[26 + i])) + } + printk (("%u\n", add[29])) + printk (("Destination IP address: ")) + + for ( i=0; i< 3 ; i++) { + printk (("%u.", add[30 + i])) + } + printk (("%u\n", add[33])) + } +} + +/* + * print_hdr + * + * Print the contents of an ethernet packet header + * CANNOT BE CALLED FROM ISR + */ +static void print_hdr( + unsigned char *add +) +{ + int i; + + printk (("print_hdr: begins\n")) + printk (("Header Location %p\n", add)) + printk (("Dest ")) + + for (i = 0; i < 6; i++) { + printk ((" %2.2X", add[i])) + } + printk (("\nSource")) + + for (i = 6; i < 12; i++) { + printk ((" %2.2X", add[i])) + } + printk (("\nframe type %2.2X%2.2X\n", add[12], add[13])) + printk (("print_hdr: completed")) +} + +/* + * Function: print_pkt + * + * Print the contents of an ethernet packet & data + * CANNOT BE CALLED FROM ISR + */ +static void print_pkt( + unsigned char *add +) +{ + int i; + short int length; + + printk (("print_pkt: begins")) + printk (("Data Location %p\n", add)) + + if ( add[0] == 0x08 && add[1] == 0x06 ) { + /* an ARP */ + printk (("Hardware type : %2.2X%2.2X\n", add[14],add[15])) + printk (("Protocol type : %2.2X%2.2X\n", add[16],add[17])) + printk (("Hardware size : %2.2X\n", add[18])) + printk (("Protocol size : %2.2X\n", add[19])) + printk (("op : %2.2X%2.2X\n", add[20],add[21])) + printk (("Sender Enet addr: ")) + + for ( i=0; i< 5 ; i++) { + printk (( "%x:", add[22 + i])) + } + printk (("%x\n", add[27])) + printk (("Sender IP addr: ")) + + for ( i=0; i< 3 ; i++) { + printk (("%u.", add[28 + i])) + } + printk (("%u\n", add[31])) + printk (("Target Enet addr: ")) + + for ( i=0; i< 5 ; i++) { + printk (( "%x:", add[32 + i])) + } + printk (("%x\n", add[37])) + printk (("Target IP addr: ")) + + for ( i=0; i< 3 ; i++) { + printk (( "%u.", add[38 + i])) + } + printk (("%u\n", add[41])) + } + + if ( add[0] == 0x08 && add[1] == 0x00 ) { + /* an IP packet */ + printk (("*********************IP HEADER******************\n")) + printk (("IP version/IPhdr length: %2.2X TOS: %2.2X\n", add[14] , add[15])) + printk (("IP total length: %2.2X %2.2X, decimal %d\n", add[16], add[17], length = (add[16]<<8 | add[17] ))) + printk (("IP identification: %2.2X %2.2X, 3-bit flags and offset %2.2X %2.2X\n", + add[18],add[19], add[20], add[21])) + printk (("IP TTL: %2.2X, protocol: %2.2X, checksum: %2.2X %2.2X \n", + add[22],add[23],add[24],add[25])) + printk (("IP packet type: %2.2X code %2.2X\n", add[34],add[35])) + printk (("Source IP address: ")) + + for ( i=0; i< 3 ; i++) { + printk(( "%u.", add[26 + i])) + } + printk(("%u\n", add[29])) + printk(("Destination IP address: ")) + + for ( i=0; i< 3 ; i++) { + printk(( "%u.", add[30 + i])) + } + printk(("%u\n", add[33])) + printk(("********************IP Packet Data*******************\n")) + length -=20; + + for ( i=0; i < length ; i++) { + printk(("0x%2.2x ", add[34+i])) + } + printk(("\n")) + printk(("ICMP checksum: %2.2x %2.2x\n", add[36], add[37])) + printk(("ICMP identifier: %2.2x %2.2x\n", add[38], add[39])) + printk(("ICMP sequence nbr: %2.2x %2.2x\n", add[40], add[41])) + printk(("print_pkt: completed")) + } +} + +/* + * print_echo + * + * Print the contents of an echo packet + * CANNOT BE CALLED FROM ISR + */ +static void print_echo( + unsigned char *add +) +{ + int i; + short int length; + + printk (("print_echo: begins")) + + if ( add[12] == 0x08 && add[13] == 0x00 ) { + /* an IP packet */ + printk (("Packet Location %p\n", add)) + printk (("Dest ")) + + for (i = 0; i < 6; i++) { + printk ((" %2.2X", add[i])) + } + printk (("\n")) + printk (("Source")) + + for (i = 6; i < 12; i++) { + printk ((" %2.2X", add[i])) + } + printk (("\n")) + printk (("frame type %2.2X%2.2X\n", add[12], add[13])) + + printk (("*********************IP HEADER******************\n")) + printk (("IP version/IPhdr length: %2.2X TOS: %2.2X\n", add[14] , add[15])) + printk (("IP total length: %2.2X %2.2X, decimal %d\n", add[16], add[17], length = (add[16]<<8 | add[17] ))) + printk (("IP identification: %2.2X %2.2X, 3-bit flags and offset %2.2X %2.2X\n", + add[18],add[19], add[20], add[21])) + printk (("IP TTL: %2.2X, protocol: %2.2X, checksum: %2.2X %2.2X \n", + add[22],add[23],add[24],add[25])) + printk (("IP packet type: %2.2X code %2.2X\n", add[34],add[35])) + printk (("Source IP address: ")) + + for ( i=0; i< 3 ; i++) { + printk (("%u.", add[26 + i])) + } + printk (("%u\n", add[29])) + printk (("Destination IP address: ")) + + for ( i=0; i< 3 ; i++) { + printk (("%u.", add[30 + i])) + } + printk (("%u\n", add[33])) + printk(("********************IP Packet Data*******************\n")) + length -=20; + + for ( i=0; i < length ; i++) { + printk(("0x%2.2x ", add[34+i])) + } + printk(("\n")) + printk(("ICMP checksum: %2.2x %2.2x\n", add[36], add[37])) + printk(("ICMP identifier: %2.2x %2.2x\n", add[38], add[39])) + printk(("ICMP sequence nbr: %2.2x %2.2x\n", add[40], add[41])) + printk(("print_echo: completed")) + } +} + +#endif diff --git a/bsps/m68k/mvme167/net/uti596.h b/bsps/m68k/mvme167/net/uti596.h new file mode 100644 index 0000000000..29e4fed299 --- /dev/null +++ b/bsps/m68k/mvme167/net/uti596.h @@ -0,0 +1,369 @@ +/* uti596.h: Contains the defines and structures used by the uti596 driver */ + +/* + * EII: March 11: Created v. 0.0 + */ + +#ifndef UTI596_H +#define UTI596_H +#include +#include + +#include +#include +#include +#include + +#include + +#include +#include + +/* Ethernet statistics */ + +struct enet_statistics{ + int rx_packets; /* total packets received */ + int tx_packets; /* total packets transmitted */ + int rx_errors; /* bad packets received */ + int tx_errors; /* packet transmit problems */ + int rx_dropped; /* no space in buffers */ + int tx_dropped; + int tx_retries_exceeded; /* excessive retries */ + int multicast; /* multicast packets received */ + int collisions; + + /* detailed rx_errors: */ + int rx_length_errors; + int rx_over_errors; /* receiver ring buff overflow */ + int rx_crc_errors; /* recved pkt with crc error */ + int rx_frame_errors; /* recv'd frame alignment error */ + int rx_fifo_errors; /* recv'r fifo overrun */ + int rx_missed_errors; /* receiver missed packet */ + + /* detailed tx_errors */ + int tx_aborted_errors; + int tx_carrier_errors; + int tx_fifo_errors; + int tx_heartbeat_errors; + int tx_window_errors; + + /* NIC reset errors */ + int nic_reset_count; /* The number of times uti596reset() has been called. */ +}; + +#define CMD_EOL 0x8000 /* The last command of the list, stop. */ +#define CMD_SUSP 0x4000 /* Suspend after doing cmd. */ +#define CMD_INTR 0x2000 /* Interrupt after doing cmd. */ + +#define CMD_FLEX 0x0008 /* Enable flexible memory model */ + +#define SCB_STAT_CX 0x8000 /* Cmd completes with 'I' bit set */ +#define SCB_STAT_FR 0x4000 /* Frame Received */ +#define SCB_STAT_CNA 0x2000 /* Cmd unit Not Active */ +#define SCB_STAT_RNR 0x1000 /* Receiver Not Ready */ + +#define SCB_CUS_SUSPENDED 0x0100 +#define SCB_CUS_ACTIVE 0x0200 + +#define STAT_C 0x8000 /* Set to 1 after execution */ +#define STAT_B 0x4000 /* 1 : Cmd being executed, 0 : Cmd done. */ +#define STAT_OK 0x2000 /* 1: Command executed ok 0 : Error */ +#define STAT_A 0x1000 /* command has been aborted */ + +#define STAT_S11 0x0800 +#define STAT_S10 0x0400 +#define STAT_S9 0x0200 +#define STAT_S8 0x0100 +#define STAT_S7 0x0080 +#define STAT_S6 0x0040 +#define STAT_S5 0x0020 +#define STAT_MAX_COLLS 0x000F + +#define RBD_STAT_P 0x4000 /* prefetch */ +#define RBD_STAT_F 0x4000 /* used */ + +#define CUC_START 0x0100 +#define CUC_RESUME 0x0200 +#define CUC_SUSPEND 0x0300 +#define CUC_ABORT 0x0400 +#define RX_START 0x0010 +#define RX_RESUME 0x0020 +#define RX_SUSPEND 0x0030 +#define RX_ABORT 0x0040 + +#define RU_SUSPENDED 0x0010 +#define RU_NO_RESOURCES 0x0020 +#define RU_READY 0x0040 + +#define I596_NULL ( ( void * ) 0xffffffff) +#define UTI_596_END_OF_FRAME 0x8000 + +struct i596_tbd; /* necessary forward declaration */ + +enum commands { + CmdNOp = 0, + CmdSASetup = 1, + CmdConfigure = 2, + CmdMulticastList = 3, + CmdTx = 4, + CmdTDR = 5, + CmdDump = 6, + CmdDiagnose = 7 +}; + +/* + * 82596 Dump Command Result + */ +typedef volatile struct i596_dump_result { + unsigned char bf; + unsigned char config_bytes[11]; + unsigned char reserved1[2]; + unsigned char ia_bytes[6]; + unsigned short last_tx_status; + unsigned short tx_crc_byte01; + unsigned short tx_crc_byte23; + unsigned short rx_crc_byte01; + unsigned short rx_crc_byte23; + unsigned short rx_temp_mem01; + unsigned short rx_temp_mem23; + unsigned short rx_temp_mem45; + unsigned short last_rx_status; + unsigned short hash_reg01; + unsigned short hash_reg23; + unsigned short hash_reg45; + unsigned short hash_reg67; + unsigned short slot_time_counter; + unsigned short wait_time_counter; + unsigned short rx_frame_length; + unsigned long reserved2; + unsigned long cb_in3; + unsigned long cb_in2; + unsigned long cb_in1; + unsigned long la_cb_addr; + unsigned long rdb_pointer; + unsigned long int_memory; + unsigned long rfd_size; + unsigned long tbd_pointer; + unsigned long base_addr; + unsigned long ru_temp_reg; + unsigned long tcb_count; + unsigned long next_rb_size; + unsigned long next_rb_addr; + unsigned long curr_rb_size; + unsigned long la_rbd_addr; + unsigned long next_rbd_addr; + unsigned long curr_rbd_addr; + unsigned long curr_rb_count; + unsigned long next_fd_addr; + unsigned long curr_fd_add; + unsigned long temp_cu_reg; + unsigned long next_tb_count; + unsigned long buffer_addr; + unsigned long la_tbd_addr; + unsigned long next_tbd_addr; + unsigned long cb_command; + unsigned long next_cb_addr; + unsigned long curr_cb_addr; + unsigned long scb_cmd_word; + unsigned long scb_pointer; + unsigned long cb_stat_word; + unsigned long mm_lfsr; + unsigned char micro_machine_bit_array[28]; + unsigned char cu_port[16]; + unsigned long mm_alu; + unsigned long reserved3; + unsigned long mm_temp_a_rr; + unsigned long mm_temp_a; + unsigned long tx_dma_b_cnt; + unsigned long mm_input_port_addr_reg; + unsigned long tx_dma_addr; + unsigned long mm_port_reg1; + unsigned long rx_dma_b_cnt; + unsigned long mm_port_reg2; + unsigned long rx_dma_addr; + unsigned long reserved4; + unsigned long bus_t_timers; + unsigned long diu_cntrl_reg; + unsigned long reserved5; + unsigned long sysbus; + unsigned long biu_cntrl_reg; + unsigned long mm_disp_reg; + unsigned long mm_status_reg; + unsigned short dump_status; +} i596_dump_result; + +typedef volatile struct i596_selftest { + unsigned long rom_signature; + unsigned long results; +} i596_selftest; + +/* + * Action commands + * (big endian, linear mode) + */ +typedef volatile struct i596_cmd { + unsigned short status; + unsigned short command; + volatile struct i596_cmd *next; +} i596_cmd; + +typedef volatile struct i596_nop { + i596_cmd cmd; +} i596_nop; + +typedef volatile struct i596_set_add { + i596_cmd cmd; + char data[8]; +} i596_set_add; + +typedef volatile struct i596_configure { + i596_cmd cmd; + char data[16]; +} i596_configure; + +typedef volatile struct i596_tx { + i596_cmd cmd; + volatile struct i596_tbd *pTbd; + unsigned short count; + unsigned short pad; + char data[6]; + unsigned short length; +} i596_tx; + +typedef volatile struct i596_tdr { + i596_cmd cmd; + unsigned long data; +} i596_tdr; + +typedef volatile struct i596_dump { + i596_cmd cmd; + char *pData; +} i596_dump; + +/* + * Transmit buffer descriptor + */ +typedef volatile struct i596_tbd { + unsigned short size; + unsigned short pad; + volatile struct i596_tbd *next; + char *data; +} i596_tbd; + +/* + * Receive buffer descriptor + * (flexible memory structure) + */ +typedef volatile struct i596_rbd { + unsigned short count; + unsigned short offset; + volatile struct i596_rbd *next; + char *data; + unsigned short size; + unsigned short pad; +} i596_rbd; + +/* + * Receive Frame Descriptor + */ +typedef volatile struct i596_rfd { + unsigned short stat; + unsigned short cmd; + volatile struct i596_rfd *next; + i596_rbd *pRbd; + unsigned short count; + unsigned short size; + char data [1532]; +} i596_rfd; + +/* + * System Control Block + */ +typedef volatile struct i596_scb { + unsigned short status; + unsigned short command; + unsigned long cmd_pointer; + unsigned long rfd_pointer; + unsigned long crc_err; + unsigned long align_err; + unsigned long resource_err; + unsigned long over_err; + unsigned long rcvdt_err; + unsigned long short_err; + unsigned short t_off; + unsigned short t_on; + i596_cmd *pCmd; + i596_rfd *pRfd; +} i596_scb; + +/* + * Intermediate System Configuration Pointer + */ +typedef volatile struct i596_iscp { + uint8_t null1; /* Always zero */ + uint8_t busy; /* Busy byte */ + unsigned short scb_offset; /* Not used in linear mode */ + unsigned long scb_pointer; /* Swapped pointer to scb */ + i596_scb *scb; /* Real pointer to scb */ +} i596_iscp; + +/* + * System Configuration Pointer + */ +typedef volatile struct i596_scp { + unsigned long sysbus; /* Only low 8 bits are used */ + unsigned long pad; /* Must be zero */ + unsigned long iscp_pointer; /* Swapped pointer to iscp */ + i596_iscp *iscp; /* Real pointer to iscp */ +} i596_scp; + +/* + * Device Dependent Data Structure + */ +typedef volatile struct uti596_softc { + struct arpcom arpcom; + i596_scp *pScp; /* Block aligned on 16 byte boundary */ + i596_scp *base_scp; /* Unaligned block. Need for free() */ + i596_iscp iscp; + i596_scb scb; + i596_set_add set_add; + i596_configure set_conf; + i596_tdr tdr; + i596_nop nop; + i596_tx *pTxCmd; + i596_tbd *pTbd; + + i596_rfd *pBeginRFA; + i596_rfd *pEndRFA; + i596_rfd *pLastUnkRFD; + i596_rbd *pLastUnkRBD; + i596_rfd *pEndSavedQueue; + i596_cmd *pCmdHead; + i596_cmd *pCmdTail; /* unneeded, as chaining not used, but implemented */ + + rtems_id rxDaemonTid; + rtems_id txDaemonTid; + rtems_id resetDaemonTid; + + struct enet_statistics stats; + int started; + unsigned long rxInterrupts; + unsigned long txInterrupts; + volatile int cmdOk; + unsigned short * pCurrent_command_status; + int resetDone; + unsigned long txRawWait; + i596_rfd *pInboundFrameQueue; + short int rxBdCount; + short int txBdCount; + short int countRFD; + short int savedCount; + i596_rfd *pSavedRfdQueue; + rtems_name semaphore_name; + rtems_id semaphore_id; + char zeroes[64]; + unsigned long rawsndcnt; + int nic_reset; /* flag for requesting that ISR issue a reset quest */ +} uti596_softc_; + +#endif /* UTI596_H */ -- cgit v1.2.3