summaryrefslogtreecommitdiffstats
path: root/bsps/m68k/mvme167/net/network.c
diff options
context:
space:
mode:
Diffstat (limited to 'bsps/m68k/mvme167/net/network.c')
-rw-r--r--bsps/m68k/mvme167/net/network.c3099
1 files changed, 3099 insertions, 0 deletions
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 <bsp.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <rtems/error.h>
+#include <rtems/bspIo.h>
+#include <rtems/rtems_bsdnet.h>
+#include <sys/param.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <sys/types.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+
+#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; i<sc->txBdCount; 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:
+ * <ethernet header, payload>.
+ * 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