summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--c/src/lib/libbsp/m68k/mvme167/network/Makefile.am36
-rw-r--r--c/src/lib/libbsp/m68k/mvme167/network/network.c2889
-rw-r--r--c/src/lib/libbsp/m68k/mvme167/network/uti596.h298
3 files changed, 3223 insertions, 0 deletions
diff --git a/c/src/lib/libbsp/m68k/mvme167/network/Makefile.am b/c/src/lib/libbsp/m68k/mvme167/network/Makefile.am
new file mode 100644
index 0000000000..601d7cd3e2
--- /dev/null
+++ b/c/src/lib/libbsp/m68k/mvme167/network/Makefile.am
@@ -0,0 +1,36 @@
+##
+## $Id$
+##
+
+AUTOMAKE_OPTIONS = foreign 1.4
+
+PGM = $(ARCH)/network.rel
+
+C_FILES = network.c
+C_O_FILES = $(C_FILES:%.c=$(ARCH)/%.o)
+
+H_FILES = uti596.h
+
+OBJS = $(C_O_FILES)
+
+include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP@.cfg
+include $(top_srcdir)/../../../../../../automake/lib.am
+
+#
+# (OPTIONAL) Add local stuff here using +=
+#
+
+$(PGM): $(OBJS)
+ $(make-rel)
+
+# the .rel file built here will be put into libbsp.a by ../wrapup/Makefile
+
+if HAS_NETWORKING
+all-local: $(ARCH) $(OBJS) $(PGM)
+endif
+
+.PRECIOUS: $(PGM)
+
+EXTRA_DIST = network.c uti596.h
+
+include $(top_srcdir)/../../../../../../automake/local.am
diff --git a/c/src/lib/libbsp/m68k/mvme167/network/network.c b/c/src/lib/libbsp/m68k/mvme167/network/network.c
new file mode 100644
index 0000000000..bcfc07ef00
--- /dev/null
+++ b/c/src/lib/libbsp/m68k/mvme167/network/network.c
@@ -0,0 +1,2889 @@
+/* uti596.c: An 82596 ethernet driver for rtems-bsd.
+ *
+ * $Id$
+ */
+
+#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_596
+#define DBG_596_RFA
+#define DBG_START
+#define DBG_INIT
+#define DBG_INIT_2
+/*#define DBG_INIT_3*/
+#define DBG_RESET
+#define DBG_VERSION
+#define DBG_ISR
+#define DBG_RAW_ISR
+#define DBG_596_RFD
+#define DBG_FR
+#define DBG_RAW
+#define DBG_ATTACH
+#define DBG_POLLED_CMD
+#define DBG_ADD
+#define DBG_SUPPLY_FD
+
+
+/*
+ * 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
+
+/*
+ * 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 <stdio.h>
+
+#include <rtems/error.h>
+#include <rtems/rtems_bsdnet.h>
+#include <sys/param.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+
+#include "uti596.h"
+#include "netexterns.h"
+
+#if CD2401_POLLED_IO == 1
+ #define printk(arglist) printk arglist;
+#else
+ #define printk(arglist)
+#endif
+
+#define UTI_596_ASSERT( condition, str ) if (!( condition ) ) { printk((str)) }
+
+int count_rx = 0;
+i596_rfd *pISR_Rfd;
+
+static uti596_softc_ uti596_softc;
+
+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 */
+ 0x0E, /* Byte 8: not promisc, disable 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 */
+};
+
+
+/* Required RTEMS network driver functions and tasks (reset daemon extra) */
+
+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 *, int, caddr_t );
+void uti596_stats( uti596_softc_ * );
+
+/* Local Routines */
+
+void uti596_initialize_hardware( uti596_softc_ * );
+void uti596_initMem( uti596_softc_ * );
+int uti596_initRFA( int );
+void uti596addPolledCmd( i596_cmd * );
+void uti596Diagnose( int );
+i596_rfd * uti596dequeue( i596_rfd ** );
+void uti596reset( void );
+void uti596_reset_hardware( uti596_softc_ *);
+void uti596clearListStatus( i596_rfd * );
+void send_packet( struct ifnet *, struct mbuf * );
+void uti596addCmd( i596_cmd *pCmd );
+void uti596supplyFD( i596_rfd * );
+void uti596append( i596_rfd ** , i596_rfd * );
+
+void printk_time( void );
+void dump_scb( void );
+
+#ifdef DBG_INIT_3
+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
+
+int uti596dump( char * );
+void dumpQ( void );
+void show_buffers( void );
+void show_queues( void );
+
+/* Helper function for reading/writing big endian memory structures */
+unsigned long word_swap(unsigned long);
+
+
+/* Waits for the command word to clear. The command word is cleared AFTER the interrupt is
+ * generated. This allows the CPU to issue the next command
+ */
+#define UTI_WAIT_COMMAND_ACCEPTED(duration,function) \
+{ rtems_interval ticks_per_second, start_ticks, end_ticks; \
+ rtems_clock_get(RTEMS_CLOCK_GET_TICKS_PER_SECOND, &ticks_per_second); \
+ rtems_clock_get(RTEMS_CLOCK_GET_TICKS_SINCE_BOOT, &start_ticks); \
+ end_ticks = start_ticks + ticks_per_second; \
+ do { \
+ if (uti596_softc.scb.command == 0) \
+ break; \
+ else { \
+ rtems_clock_get(RTEMS_CLOCK_GET_TICKS_SINCE_BOOT, &start_ticks); \
+ } \
+ } while (start_ticks <= end_ticks); \
+ if ((uti596_softc.scb.command != 0) || (start_ticks > end_ticks)) \
+ printf("%s: i82596 timed out with status %x, cmd %x.\n", function, \
+ uti596_softc.scb.status, uti596_softc.scb.command); \
+}
+
+#define UTI_WAIT_TICKS \
+{ rtems_interval ticks_per_second, start_ticks, end_ticks; \
+ rtems_clock_get(RTEMS_CLOCK_GET_TICKS_PER_SECOND, &ticks_per_second); \
+ rtems_clock_get(RTEMS_CLOCK_GET_TICKS_SINCE_BOOT, &start_ticks); \
+ end_ticks = start_ticks + ticks_per_second; \
+ do { \
+ rtems_clock_get(RTEMS_CLOCK_GET_TICKS_SINCE_BOOT, &start_ticks); \
+ } while (start_ticks <= end_ticks); \
+}
+/************************************************************************/
+
+
+ /***********************************************************************
+ * 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
+)
+{
+ uti596_softc_ *sc = &uti596_softc; /* device dependent data structure */
+ struct ifnet * ifp = &sc->arpcom.ac_if; /* ifnet structure */
+
+ int unitNumber;
+ char *unitName;
+
+#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 = 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;
+
+ /* For now the ethernet address must be specified in the ifconfig structure,
+ * else FIXME so it can be read in from BBRAM at $FFFC1F2C (6 bytes)
+ * mvme167 manual p. 1-47
+ */
+ if ( pConfig->hardware_address) {
+ memcpy (sc->arpcom.ac_enaddr, pConfig->hardware_address, ETHER_ADDR_LEN);
+ }
+
+ /* 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_INIT
+ printk(("uti596_start: begins\n"))
+#endif
+ rtems_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 = &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, sc);
+ sc->rxDaemonTid = rtems_bsdnet_newproc ("UTrx", 2*4096, uti596_rxDaemon, sc);
+ sc->resetDaemonTid = rtems_bsdnet_newproc ("UTrt", 2*4096, uti596_resetDaemon, sc);
+
+#ifdef DBG_INIT
+ printk(("uti596_init: After attach, status of board = 0x%x\n", sc->scb.status ))
+#endif
+ }
+
+ /*
+ * Enable receiver
+ */
+#ifdef DBG_INIT
+ printk(("uti596_init: enabling the reciever...\n" ))
+#endif
+ sc->scb.command = RX_START;
+ i82596->chan_attn = 0x00000000;
+ UTI_WAIT_COMMAND_ACCEPTED(4000,"uti596_init: RX_START");
+
+ /*
+ * 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 = &sc->arpcom.ac_if;
+
+ ifp->if_flags &= ~IFF_RUNNING;
+ sc->started = 0;
+
+#ifdef DBG_596
+ 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 = &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 = &sc->arpcom.ac_if;
+ struct mbuf *m;
+
+ i596_rfd *pRfd;
+ ISR_Level level;
+ int tid;
+ rtems_event_set events;
+ struct ether_header *eh;
+
+ int frames = 0;
+#ifdef DBG_INIT_3
+ int i;
+#endif
+
+#ifdef DBG_596
+ printk(("uti596_rxDaemon: begin\n"))
+ printk(("&scb = %p, pRfd = %p\n", &sc->scb,sc->scb.pRfd))
+#endif
+
+ rtems_task_ident (0, 0, &tid);
+
+#ifdef DBG_596
+ printk(("uti596_rxDaemon: RX tid = 0x%x\n", tid))
+#endif
+
+ for(;;) {
+ /*
+ * Wait for packet.
+ */
+#ifdef DBG_596
+ printk(("uti596_rxDaemon: Receiver sleeps\n"))
+#endif
+
+ rtems_bsdnet_event_receive (INTERRUPT_EVENT,
+ RTEMS_WAIT|RTEMS_EVENT_ANY,
+ RTEMS_NO_TIMEOUT,
+ &events);
+
+#ifdef DBG_596
+ 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 = uti596dequeue( &sc->pInboundFrameQueue);
+ while ( pRfd &&
+ pRfd != I596_NULL &&
+ pRfd -> stat & STAT_C )
+ {
+
+#ifdef DBG_INIT_3
+ printk(("\nuti596_rxDaemon: Received packet:\n"))
+ print_eth( pRfd->data);
+#endif
+ if ( pRfd->stat & STAT_OK) { /* a good frame */
+ int pkt_len = pRfd->count & 0x3fff; /* the actual # of bytes received */
+
+#ifdef DBG_596
+ 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,
+ 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_596
+ printk(("uti596_rxDaemon: m->m_ext: %p pRfd -> data: %p\n",
+ m->m_ext, pRfd->data))
+#endif
+#ifdef DBG_INIT_3
+ 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_596
+ 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")
+
+#ifdef DBG_SUPPLY_FD
+ printk(("uti596_rxDaemon: Supply FD Starting\n"))
+#endif
+ _ISR_Disable(level);
+ uti596supplyFD ( pRfd ); /* Return RFD to RFA. */
+ _ISR_Enable(level);
+#ifdef DBG_SUPPLY_FD
+ printk(("uti596_rxDaemon: Supply FD Complete\n"))
+#endif
+ pRfd = uti596dequeue( &sc->pInboundFrameQueue); /* grab next frame */
+
+ } /* end while */
+ } /* end for(;;) */
+
+#ifdef DBG_596
+ 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(RTEMS_CLOCK_GET_TOD, &tm_struct);
+ printk(("reset daemon: Resetting NIC @ %d:%d:%d \n",
+ tm_struct.hour, tm_struct.minute, tm_struct.second))
+
+ sc->stats.nic_reset_count++;
+ /* Reinitialize the LANC */
+ rtems_bsdnet_semaphore_obtain ();
+ uti596reset();
+ rtems_bsdnet_semaphore_release ();
+ }
+}
+
+
+ /***********************************************************************
+ * Function: uti596_DynamicInterruptHandler
+ *
+ * Description:
+ * This is the interrupt handler for the uti596 board
+ *
+ * Algorithm:
+ *
+ ***********************************************************************/
+
+/* static */ rtems_isr uti596_DynamicInterruptHandler(
+ rtems_vector_number irq
+)
+{
+#ifdef DEBUG_ISR
+ printk(("uti596_DynamicInterruptHandler: begins"))
+#endif
+
+ UTI_WAIT_COMMAND_ACCEPTED(20000,"****ERROR:on ISR entry");
+
+ scbStatus = 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;
+ i82596->chan_attn = 0x00000000;
+
+ if( uti596_softc.resetDone ) {
+ /* stack is attached */
+ UTI_WAIT_COMMAND_ACCEPTED(20000,"****ERROR:ACK");
+ }
+ else {
+ /* printk(("***INFO: ACK'd w/o processing. status = %x\n", scbStatus)) */
+ return;
+ }
+ }
+ else {
+ printk(("\n***ERROR: Spurious interrupt. Resetting...\n"))
+ uti596_softc.nic_reset = 1;
+ }
+
+
+ if ( (scbStatus & SCB_STAT_CX) && !(scbStatus & SCB_STAT_CNA) ){
+ printk_time();
+ 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_time();
+ printk(("\n*****ERROR: CNA, NO CX:0x%x\nResetting...",scbStatus))
+ uti596_softc.nic_reset = 1;
+ return;
+ }
+
+ if ( scbStatus & SCB_CUS_SUSPENDED ) {
+ printk_time();
+ printk(("\n*****ERROR: Command unit suspended!:0x%x\nResetting...",scbStatus))
+ uti596_softc.nic_reset = 1;
+ return;
+ }
+
+ if ( scbStatus & RU_SUSPENDED ) {
+ printk_time();
+ printk(("\n*****ERROR: Receive unit suspended!:0x%x\nResetting...",scbStatus))
+ uti596_softc.nic_reset = 1;
+ return;
+ }
+
+ if ( scbStatus & SCB_STAT_RNR ) {
+ printk_time();
+ 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_FR
+ printk(("uti596_DynamicInterruptHandler: Frame received\n"))
+#endif
+ if ( uti596_softc.pBeginRFA == I596_NULL ||
+ !( uti596_softc.pBeginRFA -> stat & STAT_C)) {
+ dump_scb();
+ uti596_softc.nic_reset = 1;
+ }
+ 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 ++;
+ if ( count_rx > 1) {
+ printk(("****WARNING: Received 2 frames on 1 interrupt \n"))
+ }
+ /* 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 */
+ uti596append( &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_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_RAW_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_RAW_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:
+
+ /* printk(("****INFO:Configure OK\n")) */
+ 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_event_send (uti596_softc.txDaemonTid,
+ INTERRUPT_EVENT);
+
+ if ( sc != RTEMS_SUCCESSFUL ) {
+ printk(("****ERROR:Could NOT send event to tid 0x%x : %s\n",
+ uti596_softc.txDaemonTid, rtems_status_text (sc) ))
+ }
+#ifdef DBG_RAW_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_time();
+ printk(("****INFO: Request board reset ( tx )\n"))
+ uti596_softc.nic_reset = 1;
+ if ( uti596_softc.txDaemonTid) {
+ /* Ensure that a transmitter is present */
+ sc = rtems_event_send (uti596_softc.txDaemonTid,
+ INTERRUPT_EVENT);
+ if ( sc != RTEMS_SUCCESSFUL ) {
+ printk(("****ERROR:Could NOT send event to tid 0x%x : %s\n",uti596_softc.txDaemonTid, rtems_status_text (sc) ))
+ }
+#ifdef DBG_RAW_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 DEBUG_RFA
+ 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 */
+ }
+ uti596append( &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 DEBUG_RFA
+ 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 DEBUG_RFA
+ 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 DEBUG_RFA
+ 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 DEBUG_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_596_RFD
+ printk(("uti596_DynamicInterruptHandler: The list starts here %p\n",uti596_softc.pBeginRFA ))
+#endif
+
+ if ( uti596_softc.countRFD > 1) {
+ printk_time();
+ 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_val = 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_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
+ *
+ * Algorithm:
+ *
+ ***********************************************************************/
+
+static int uti596_ioctl(
+ struct ifnet *ifp,
+ int command, caddr_t data
+)
+{
+ uti596_softc_ *sc = ifp->if_softc;
+ int error = 0;
+
+#ifdef DBG_INIT
+ 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 (sc);
+ break;
+
+ case IFF_UP | IFF_RUNNING:
+ printk(("IFF_UP and RUNNING\n"))
+ uti596_stop (sc);
+ uti596_init (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");
+
+ dump_scb();
+}
+
+
+/***********************************************************************
+ *************************** LOCAL ROUTINES ****************************
+ ***********************************************************************/
+
+
+/***********************************************************************
+ * Function: void uti596_initialize_hardware
+ *
+ * Description:
+ ***********************************************************************/
+void uti596_initialize_hardware(
+ uti596_softc_ *sc
+)
+{
+ int boguscnt = 1000;
+ rtems_isr_entry dummy;
+
+ printk(("uti596_initialize_hardware: begins\n"))
+
+ pccchip2->LANC_berr_ctl = 0x40; /* Enable snooping */
+
+ /* reset the board */
+ i82596->port_lower = 0x0000; /* Each Port access must consist of two 16-bit writes */
+ i82596->port_upper = 0x0000;
+
+ /* allocate enough memory for the Scp block to be aligned on 16 bit boundary */
+ uti596_softc.pScp = (i596_scp *) calloc(1,sizeof(struct i596_scp) + 0xf);
+
+#ifdef DBG_INIT
+ printk(("uti596_initialize_hardware: Scp address initially %p\n", sc->pScp))
+#endif
+
+ /* align the block */
+ sc->pScp = (i596_scp *)
+ ((((int)uti596_softc.pScp) + 0xf) & 0xfffffff0);
+
+#ifdef DBG_INIT
+ printk(("uti596_initialize_hardware: change scp address to : %p\n",sc->pScp))
+#endif
+
+ /* change the scp address */
+#ifdef DBG_INIT
+ printk(("uti596_initialize_hardware: Change the SCP address\n"))
+#endif
+
+ /* reset the board */
+ i82596->port_lower = 0x0000;
+ i82596->port_upper = 0x0000;
+
+ /* supply the Scp address
+ * Lower Command Word D31-D16; Upper Command Word D15-D0
+ */
+ i82596->port_lower = (((int)sc->pScp) & 0xfff0) | 0x0002;
+ i82596->port_upper = (((int)sc->pScp) >> 16 ) & 0xffff;
+
+
+ /* write the SYSBUS: interrupt pin active high, LOCK disabled,
+ * internal triggering, linear mode
+ */
+ sc->pScp->sysbus = word_swap(0x00540000);
+
+ /* provide the iscp to the scp, keep a pointer for our use */
+ sc->pScp->iscp_val = 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_val = word_swap((unsigned long)&sc->scb);
+ sc->iscp.scb = &sc->scb;
+
+ /* set the busy flag in the iscp */
+ sc->iscp.stat = word_swap(0x00000001);
+
+ /* the command block list (CBL) is empty */
+ sc->scb.Cmd_val = (unsigned long) I596_NULL; /* all 1's */
+ sc->pCmdHead = sc->scb.pCmd = I596_NULL; /* all 1's */
+
+#ifdef DBG_596
+ printk(("uti596_initialize_hardware: Starting i82596.\n"))
+#endif
+
+ /* Issue CA: pass the scb address to the 596 */
+ i82596->chan_attn = 0x00000000;
+
+ UTI_WAIT_TICKS
+
+ /* Wait for the 596 to read the SCB address and clear 'stat' */
+ while (sc->iscp.stat) {
+ if (--boguscnt == 0) {
+ printk(("initialize_hardware: timed out with status %4.4lx\n",
+ sc->iscp.stat ))
+ break;
+ }
+ } /* end while */
+
+ /* clear the scb command word */
+ sc->scb.command = 0;
+
+ /*
+ * 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
+ */
+ dummy = (rtems_isr_entry) 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
+}
+
+/***********************************************************************
+ * Function: uti596_initMem
+ *
+ * Description:
+ * creates the necessary descriptors for the
+ * uti596 board, hooks the interrupt, and starts the board.
+ * Assumes that interrupts are hooked.
+ *
+ * Algorithm:
+ *
+ ***********************************************************************/
+
+void uti596_initMem(
+ uti596_softc_ * sc
+)
+{
+ int i,count;
+ i596_tbd *pTbd, *pPrev;
+
+#ifdef DBG_INIT
+ printk(("uti596_initMem: begins\n"))
+#endif
+
+ sc->resetDone = 0;
+
+ /*
+ * Set up receive frame area (RFA)
+ */
+#ifdef DBG_INIT
+ printk(("uti596_initMem: Initializing the RFA...\n"))
+#endif
+ i = uti596_initRFA( sc->rxBdCount );
+ if ( i < sc->rxBdCount ) {
+ printk(("init_rfd: only able to allocate %d receive frame descriptors\n", i))
+ }
+
+ sc->scb.Rfd_val = word_swap((unsigned long)sc->pBeginRFA);
+ sc->scb.pRfd = sc->pBeginRFA;
+
+ /*
+ * Diagnose the health of the board
+ * send the CU a diagnostic command
+ */
+#ifdef DBG_INIT
+ printk(("uti596_initMem: Running diagnostics...\n"))
+#endif
+ uti596Diagnose(1);
+
+ /*
+ * Configure the 82596
+ * send the CU a configure command with our initial setup
+ */
+#ifdef DBG_INIT
+ printk(("uti596_initMem: Configuring...\n"))
+#endif
+ sc->set_conf.cmd.command = CmdConfigure;
+ memcpy (sc->set_conf.data, uti596initSetup, 14);
+ uti596addPolledCmd( (i596_cmd *) &sc->set_conf);
+
+ /* Poll for successful command completion */
+ count = 2000;
+ while( !( sc->set_conf.cmd.status & STAT_C ) && --count ) {
+ printk(("."))
+ }
+
+ if ( count ) {
+ printk(("Configure OK, count = %d\n",count))
+ }
+ else {
+ printk(("***Configure failed\n"))
+ }
+ /*
+ * Set up the Internet Address
+ * send the CU an IA-setup command
+ */
+#ifdef DBG_INIT
+ printk(("uti596_initMem: Setting Address...\n"))
+#endif
+ sc->set_add.cmd.command = CmdSASetup;
+ for ( i=0; i<6; i++) {
+ sc->set_add.data[i]=sc->arpcom.ac_enaddr[i];
+#ifdef DBG_INIT
+ printk(("uti596_initMem: copying byte %d: 0x%x\n", i, sc->set_add.data[i]))
+#endif
+ }
+ sc->cmdOk = 0;
+ uti596addPolledCmd((i596_cmd *)&sc->set_add);
+
+ /* Poll for successful command completion */
+ count = 2000;
+ while( !(sc->set_add.cmd.status & STAT_C ) && --count) {
+ printk(("."))
+ }
+
+ if ( count ) {
+ printk(("Set Address OK, count= %d\n",count))
+ }
+ else {
+ printk(("Set Address Failed\n"))
+ }
+#ifdef DBG_INIT
+ printk(( "uti596_initMem: After initialization, status and command: 0x%x, 0x%x\n",
+ sc->scb.status, sc->scb.status))
+#endif
+
+ /*
+ *Initialize transmit buffer descriptors
+ */
+#ifdef DBG_INIT
+ printk(( "uti596_initMem:Initializing TBDs...\n"))
+#endif
+ sc->pLastUnkRFD = I596_NULL;
+ sc->pTxCmd = (i596_tx *) calloc (1,sizeof (struct i596_tx) );
+ sc->pTbd = (i596_tbd *) calloc (1,sizeof (struct i596_tbd) );
+ 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++) {
+ pTbd = (i596_tbd *) calloc (1,sizeof (struct i596_tbd) );
+ pPrev->next = (i596_tbd *) word_swap ((unsigned long) pTbd);
+ pPrev = pTbd;
+ }
+ pTbd->next = I596_NULL;
+
+ /* Padding used to fill short tx frames */
+ memset ( &sc->zeroes, 0, 64);
+
+#ifdef DBG_596
+ printk(( "uti596_initMem: After receiver start, status and command: 0x%x, 0x%x\n",
+ sc->scb.status, sc->scb.status))
+#endif
+
+#ifdef DBG_596
+ printk(("uti596_initMem allows ISR's\n"))
+#endif
+ sc->resetDone = 1; /* now need ISR */
+}
+
+/***********************************************************************
+ * Function: uti596initRFA(int num)
+ *
+ * Description:
+ * attempts to allocate and initialize ( chain together )
+ * the requested number of FD's
+ *
+ * Algorithm:
+ *
+ ***********************************************************************/
+
+int uti596_initRFA( int num )
+{
+ i596_rfd *pRfd;
+ int i = 0;
+
+#ifdef DBG_596
+ 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;
+ printk(("First Rfd allocated @: %p\n",
+ uti596_softc.pBeginRFA))
+ }
+
+ /* Create remaining RFAs */
+ 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 */
+#ifdef DBG_596_RFA
+ printk(("uti596_initRFA: Allocated RFD @ %p\n", pRfd))
+#endif
+ }
+ 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 == RX_BUF_COUNT,"INIT:WRONG RFD COUNT\n" )
+
+#ifdef DBG_596_RFA
+ 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
+ /* 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 ) */
+ if ( pRfd -> data == NULL ) {
+ printk(("Can't allocate the RFD data buffer\n"))
+ }
+ }
+
+ /* 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 */
+}
+
+ /***********************************************************************
+ * Function: uti596addPolledCmd
+ *
+ * Description:
+ * This routine issues a single command then polls for it's
+ * completion.
+ *
+ * Algorithm:
+ * Give the command to the driver. ( CUC_START is ALWAYS required )
+ * Poll for completion.
+ *
+ ***********************************************************************/
+
+void uti596addPolledCmd(
+ i596_cmd *pCmd
+)
+{
+
+ #ifdef DBG_596
+ printk(("uti596addPolledCmd: Adding command 0x%x\n", pCmd -> command ))
+ #endif
+
+#ifdef DBG_POLLED_CMD
+
+ switch ( pCmd -> command & 0x7 ) { /* check bottom 3 bits */
+ case CmdConfigure:
+ printk(("uti596addPolledCmd: Configure Command 0x%x\n", pCmd->command))
+ break;
+ case CmdSASetup:
+ printk(("uti596addPolledCmd: Set CMDress Command 0x%x\n", pCmd->command))
+ break;
+ case CmdMulticastList:
+ printk(("uti596addPolledCmd: Multi-cast list 0x%x\n", pCmd->command))
+ break;
+ case CmdNOp:
+ printk(("uti596addPolledCmd: NO op 0x%x\n", pCmd->command))
+ break;
+ case CmdTDR:
+ printk(("uti596addPolledCmd: TDR 0x%x\n", pCmd->command))
+ break;
+ case CmdDump:
+ printk(("uti596addPolledCmd: Dump 0x%x\n", pCmd->command))
+ break;
+ case CmdDiagnose:
+ printk(("uti596addPolledCmd: Diagnose 0x%x\n", pCmd->command))
+ break;
+ case CmdTx:
+ break;
+ default:
+ printk(("PolledCMD: ****Unknown Command encountered 0x%x\n", pCmd->command))
+ break;
+ } /* end switch */
+
+#endif
+
+ pCmd->status = 0;
+ pCmd->command |= CMD_EOL ; /* only command in list*/
+
+ pCmd->next = I596_NULL;
+
+ UTI_WAIT_COMMAND_ACCEPTED(10000,"Add Polled command: wait prev");
+
+ uti596_softc.pCmdHead = uti596_softc.pCmdTail = uti596_softc.scb.pCmd = pCmd;
+ uti596_softc.scb.Cmd_val = word_swap((unsigned long)pCmd);
+ uti596_softc.scb.command = CUC_START;
+ i82596->chan_attn = 0x00000000;
+
+ UTI_WAIT_COMMAND_ACCEPTED(10000,"Add Polled command: start");
+ uti596_softc.pCmdHead = uti596_softc.pCmdTail = uti596_softc.scb.pCmd = I596_NULL;
+ uti596_softc.scb.Cmd_val = (unsigned long) I596_NULL;
+
+#ifdef DBG_POLLED_CMD
+ printk(("uti596addPolledCmd: Scb status & command 0x%x 0x%x\n",
+ uti596_softc.scb.status,
+ uti596_softc.scb.command ))
+#endif
+}
+
+
+/***********************************************************************
+ * Function: void uti596Diagnose
+ *
+ * Description:
+ *
+ ***********************************************************************/
+void uti596Diagnose(
+ int verbose
+)
+{
+ i596_cmd diagnose;
+ int count=10000;
+
+ diagnose.command = CmdDiagnose;
+ diagnose.status = 0;
+ uti596addPolledCmd(&diagnose);
+ while( !( diagnose.status & STAT_C ) && count ) {
+ if(verbose) {
+ printk(("."))
+ }
+ count --;
+ }
+ if(verbose) {
+ printk(("Status diagnostic: 0xa000 is a success ... 0x%2.2x\n", diagnose.status))
+ }
+}
+
+/***********************************************************************
+ * Function: void uti596dequeue
+ *
+ * Description:
+ * removes an RFD from the received frame queue,
+ *
+ * Algorithm:
+ *
+ ***********************************************************************/
+i596_rfd * uti596dequeue(
+ i596_rfd ** ppQ
+)
+{
+ ISR_Level level;
+
+ i596_rfd * pRfd;
+ _ISR_Disable(level);
+
+ /* invalid address, or empty queue or emptied queue */
+ if( ppQ == NULL || *ppQ == NULL || *ppQ == I596_NULL) {
+ _ISR_Enable(level);
+ return I596_NULL;
+ }
+
+ pRfd = *ppQ; /* The dequeued buffer */
+ *ppQ = (i596_rfd *) \
+ word_swap ((unsigned long) pRfd->next); /* advance the queue pointer */
+ pRfd->next = I596_NULL; /* unlink the rfd being returned */
+
+ _ISR_Enable(level);
+ return pRfd;
+}
+
+/***********************************************************************
+ * Function: void uti596reset
+ *
+ * Description:
+ ***********************************************************************/
+void uti596reset( void )
+{
+ int i,count;
+ uti596_softc_ *sc = &uti596_softc;
+ /* i596_rfd * pRfd; */
+
+#ifdef DBG_RESET
+ printk(("uti596reset: begin\n"))
+#endif
+
+ sc->resetDone = 0;
+ UTI_WAIT_COMMAND_ACCEPTED(10000, "reset: wait for previous command complete");
+ uti596_reset_hardware(&uti596_softc); /* reset the ethernet hardware. must re-config */
+
+#ifdef DBG_RESET
+ uti596Diagnose(1);
+#endif
+
+ sc->set_conf.cmd.command = CmdConfigure;
+ memcpy (sc->set_conf.data, uti596initSetup, 14);
+ uti596addPolledCmd( (i596_cmd *) &sc->set_conf);
+
+ /* POLL */
+ count = 2000;
+ while( !( sc->set_conf.cmd.status & STAT_C ) && --count ) {
+ printk(("."))
+ }
+
+ if ( count ) {
+ printk(("Configure OK, count = %d\n",count))
+ }
+ else {
+ printk(("reset: Configure failed\n"))
+ }
+
+ /*
+ * Create the IA setup command
+ */
+
+#ifdef DBG_RESET
+ printk(("uti596reset: Setting Address\n"))
+#endif
+ 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;
+ uti596addPolledCmd((i596_cmd *)&sc->set_add);
+
+ count = 2000;
+ while( !(sc->set_add.cmd.status & STAT_C ) && --count) {
+ printk(("."))
+ }
+ if ( count ) {
+ printk(("Reset Set Address OK, count= %d\n",count))
+ }
+ else {
+ printk(("Reset Set Address Failed\n"))
+ }
+
+ sc->pCmdHead = sc->pCmdTail = sc->scb.pCmd = I596_NULL;
+
+#ifdef DBG_RESET
+ printk(( "uti596reset: After reset, status and command: 0x%x, 0x%x\n",
+ sc->scb.status, sc->scb.status))
+#endif
+
+ /* restore the RFA */
+
+ /* dumpQ(); */
+
+ if ( sc->pLastUnkRFD != I596_NULL ) {
+ sc-> pEndRFA = sc->pLastUnkRFD; /* The end position can be updated */
+ sc-> pLastUnkRFD = I596_NULL;
+ }
+
+ sc->pEndRFA->next = sc->pSavedRfdQueue;
+ if ( sc->pSavedRfdQueue != I596_NULL ) {
+ sc->pEndRFA = sc->pEndSavedQueue;
+ sc->pSavedRfdQueue = sc->pEndSavedQueue = I596_NULL;
+ sc -> countRFD = sc->rxBdCount ;
+ }
+
+ sc->scb.pRfd = sc->pBeginRFA; /* readdress the head of the RFA in the SCB */
+ sc->scb.Rfd_val = word_swap((unsigned long)sc->pBeginRFA);
+
+ uti596clearListStatus(sc->pBeginRFA );
+
+ /* dumpQ(); */
+
+ printk(("Reset:Starting NIC\n"))
+ sc->scb.command = RX_START;
+ sc->started = 1; /* we assume that the start works */
+ sc->resetDone = 1;
+ i82596->chan_attn = 0x00000000;
+ UTI_WAIT_COMMAND_ACCEPTED(4000, "reset");
+ printk(("Reset:Start complete \n"))
+ UTI_596_ASSERT(sc->pCmdHead == I596_NULL, "Reset: CMD not cleared\n")
+
+#ifdef DBG_RESET
+ printk(("uti596reset: completed\n"))
+#endif
+}
+
+
+/***********************************************************************
+ * Function: void uti596_reset_hardware
+ *
+ * Description:
+ ***********************************************************************/
+void uti596_reset_hardware(
+ uti596_softc_ *sc
+)
+{
+ int boguscnt = 1000;
+ rtems_status_code status_code;
+ i596_cmd *pCmd;
+
+
+ printk(("uti596_reset_hardware\n"))
+ pCmd = sc->pCmdHead; /* This is a tx command for sure (99.99999%) */
+
+ /* reset the board */
+ i82596->port_lower = 0x0000;
+ i82596->port_upper = 0x0000;
+
+ if ( sc->pScp == NULL ) {
+ printk(("Calloc scp\n"))
+ uti596_softc.pScp = (i596_scp *) calloc(1,sizeof(struct i596_scp) + 0xf);
+ }
+
+#ifdef DBG_RESET
+ printk(("uti596_reset_hardware: Scp address %p\n", sc->pScp))
+#endif
+
+ /* align the block */
+ sc->pScp = (i596_scp *)
+ ((((int)uti596_softc.pScp) + 0xf) & 0xfffffff0);
+
+#ifdef DBG_RESET
+ printk(("uti596_reset_hardware: change scp address to : %p\n",sc->pScp))
+#endif
+
+ /* change the scp address */
+#ifdef DBG_RESET
+ printk(("uti596_reset_hardware: Change the SCP address\n"))
+#endif
+
+ /* reset the board */
+ i82596->port_lower = 0x0000;
+ i82596->port_upper = 0x0000;
+
+ /* supply the Scp address
+ * Lower Command Word D31-D16; Upper Command Word D15-D0
+ */
+ i82596->port_lower = (((int)sc->pScp) & 0xfff0) | 0x0002;
+ i82596->port_upper = (((int)sc->pScp) >> 16 ) & 0xffff;
+
+ /* write the SYSBUS: interrupt pin active high, LOCK disabled,
+ * internal triggering, linear mode
+ */
+ sc->pScp->sysbus = word_swap(0x00540000);
+
+ /* provide the iscp to the scp, keep a pointer for our use */
+ sc->pScp->iscp_val = 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_val = word_swap((unsigned long)&sc->scb);
+ sc->iscp.scb = &sc->scb;
+
+ /* set the busy flag in the iscp */
+ sc->iscp.stat = word_swap(0x00000001);
+
+ /* the command block list (CBL) is empty */
+ sc->scb.Cmd_val = (unsigned long) I596_NULL; /* all 1's */
+ sc->pCmdHead = sc->scb.pCmd = I596_NULL; /* all 1's */
+
+ /*
+ * Wake the transmitter if needed.
+ */
+ if ( uti596_softc.txDaemonTid && pCmd != I596_NULL ) {
+ printk(("****RESET: wakes transmitter!\n"))
+ status_code = rtems_event_send (uti596_softc.txDaemonTid,
+ INTERRUPT_EVENT);
+
+ if ( status_code != RTEMS_SUCCESSFUL ) {
+ printk(("****ERROR:Could NOT send event to tid 0x%x : %s\n",
+ uti596_softc.txDaemonTid, rtems_status_text (status_code) ))
+ }
+ }
+
+#ifdef DBG_596
+ printk(("uti596_reset_hardware: starting i82596.\n"))
+#endif
+
+ /* Pass the scb address to the 596 */
+ i82596->chan_attn = 0x00000000;
+
+ while (sc->iscp.stat)
+ if (--boguscnt == 0)
+ {
+ printk(("reset_hardware: timed out with status %4.4lx\n",
+ sc->iscp.stat ))
+ break;
+ }
+
+ /* clear the command word */
+ sc->scb.command = 0;
+
+#ifdef DBG_RESET
+ printk(("uti596_reset_hardware: After reset_hardware, status of board = 0x%x\n", sc->scb.status ))
+#endif
+}
+
+ /***********************************************************************
+ * Function: uti596clearListStatus
+ *
+ * Description:
+ * Clear the stat fields for all rfd's
+ * Algorithm:
+ *
+ ***********************************************************************/
+
+void uti596clearListStatus(
+ i596_rfd *pRfd
+)
+{
+ while ( pRfd != I596_NULL ) {
+ pRfd -> stat = 0;
+ pRfd = (i596_rfd *) word_swap((unsigned long)pRfd-> next);
+ }
+}
+
+ /***********************************************************************
+ * Function: send_packet
+ *
+ * Description: Send a raw ethernet packet
+ *
+ * Algorithm:
+ * increment some stats counters,
+ * create the transmit command,
+ * add the command to the CBL,
+ * wait for event
+ *
+ ***********************************************************************/
+
+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 );
+
+ /* This should never happen */
+ if ( bd_count == 16 ) {
+ printk(("TX ERROR:Too many mbufs in the packet!!!\n"))
+ printk(("Must coalesce!\n"))
+ }
+
+ 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
+ pTbd = pPrev; /* Don't use pTbd in the send routine */
+
+ /* 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;
+
+#ifdef DBG_RAW
+ printk(("send_packet: RAW - Add cmd and sleep\n"))
+#endif
+
+ sc->rawsndcnt++;
+
+#ifdef DBG_RAW
+ printk(("send_packet: RAW - sending packet\n"))
+#endif
+
+ /* Sending Zero length packet: shouldn't happen */
+ if (pTbd->size <= 0) return ;
+
+#ifdef DBG_INIT_3
+ 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 */
+ uti596addCmd ( (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_RAW
+ printk(("send_packet: RAW - wake\n"))
+#endif
+
+ sc->txInterrupts++;
+
+#ifdef DBG_INIT_3
+ printk(("\nsend_packet: Transmitter issued packet\n"))
+ print_hdr ( sc->pTxCmd->pTbd -> data ); /* print the first part */
+ print_pkt ( sc->pTxCmd->pTbd ->next-> data ); /* print the first part */
+#endif
+
+ if ( sc->pTxCmd -> cmd.status & STAT_OK ) {
+ sc->stats.tx_packets++;
+ }
+ else {
+#ifdef DBG_RAW
+ printk(("******send_packet: Driver Error 0x%x\n", sc->pTxCmd -> cmd.status ))
+#endif
+ 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 transmited 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: uti596addCmd
+ *
+ * Description:
+ * This routine adds a command onto the end of the
+ * command chain
+ *
+ * Algorithm:
+ * Add the command to the end of an existing chain,
+ * or start the chain and issue a CUC_START
+ *
+ *
+ ***********************************************************************/
+
+/* static */ void uti596addCmd(
+ i596_cmd *pCmd
+)
+{
+ ISR_Level level;
+
+ #ifdef DBG_596
+ printk(("uti596addCmd: Adding command 0x%x\n", pCmd -> command ))
+ #endif
+
+#ifdef DBG_ADD
+
+ switch ( pCmd -> command & 0x7 ){ /* check bottom 3 bits */
+ case CmdConfigure:
+ printk(("uti596addCmd: Configure Command 0x%x\n", pCmd->command))
+ break;
+ case CmdSASetup:
+ printk(("uti596addCmd: Set Address Command 0x%x\n", pCmd->command))
+ break;
+ case CmdMulticastList:
+ printk(("uti596addCmd: Multi-cast list 0x%x\n", pCmd->command))
+ break;
+ case CmdNOp:
+ printk(("uti596addCmd: NO op 0x%x\n", pCmd->command))
+ break;
+ case CmdTDR:
+ printk(("uti596addCmd: TDR 0x%x\n", pCmd->command))
+ break;
+ case CmdDump:
+ printk(("uti596addCmd: Dump 0x%x\n", pCmd->command))
+ break;
+ case CmdDiagnose:
+ printk(("uti596addCmd: Diagnose 0x%x\n", pCmd->command))
+ break;
+ case CmdTx:
+ break;
+ default:
+ printk(("****Unknown Command encountered 0x%x\n", pCmd->command))
+ break;
+ } /* end switch */
+#endif
+
+ pCmd->status = 0;
+ pCmd->command |= (CMD_EOL | CMD_INTR ); /* all commands last in list & return an interrupt */
+
+ pCmd->next = I596_NULL;
+
+ _ISR_Disable(level);
+ if (uti596_softc.pCmdHead == I596_NULL)
+ {
+ uti596_softc.pCmdHead =
+ uti596_softc.pCmdTail =
+ uti596_softc.scb.pCmd = pCmd;
+ uti596_softc.scb.Cmd_val = word_swap ((unsigned long)pCmd);
+#ifdef DBG_596
+ printk(("uti596addCmd: First Cmd\n"))
+#endif
+ UTI_WAIT_COMMAND_ACCEPTED(10000,"add command"); /* wait for acceptance of previous command */
+ uti596_softc.scb.command = CUC_START;
+ i82596->chan_attn = 0x00000000;
+ _ISR_Enable(level);
+ }
+ else
+ {
+#ifdef DBG_596
+ printk(("uti596addCmd: Chained Cmd\n"))
+#endif
+ uti596_softc.pCmdTail->next = (i596_cmd *) word_swap ((unsigned long)pCmd);
+ uti596_softc.pCmdTail = pCmd;
+ _ISR_Enable(level);
+ }
+
+#ifdef DBG_596
+ printk(("uti596addCmd: Scb status & command 0x%x 0x%x\n",
+ uti596_softc.scb.status,
+ uti596_softc.scb.command ))
+#endif
+}
+
+
+/***********************************************************************
+ * Function: uti596supplyFD
+ *
+ * Description: returns a buffer to the receive frame pool.
+ * call this with Inetrrupts disabled!
+ *
+ * Algorithm:
+ *
+ ***********************************************************************/
+
+void uti596supplyFD(
+ 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 ) {
+ /* Init a list w/ 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;
+
+ if ( pLastRfd != I596_NULL &&
+ ! (pLastRfd -> stat & ( STAT_C | STAT_B ) )) { /* C = complete, B = busy (prefetched) */
+
+ /*
+ * 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 is 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 ) {
+
+ uti596append(&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 ) {
+ uti596_softc.pBeginRFA -> cmd &= ~CMD_EOL; /* Ensure that beginRFA is not 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_START
+ printk(("uti596supplyFD: 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_val = word_swap ((unsigned long) uti596_softc.pBeginRFA);
+ uti596_softc.scb.command = RX_START | SCB_STAT_RNR; /* Don't ack RNR! The receiver
+ * should be stopped in this case */
+ UTI_596_ASSERT( !(uti596_softc.scb.status & SCB_STAT_FR),"FRAME RECEIVED INT COMING!\n")
+ i82596->chan_attn = 0x00000000; /* send CA signal */
+ }
+ }
+ return;
+
+ }
+ }
+ else {
+ /*
+ * too late , pLastRfd in use ( or NULL ),
+ * in either case, EL bit has been read, and RNR condition will occur
+ */
+ uti596append( &uti596_softc.pSavedRfdQueue, pRfd); /* save it for RNR */
+
+ uti596_softc.pEndSavedQueue = pRfd; /* reset end of saved queue */
+ uti596_softc.savedCount++;
+
+ return;
+ }
+}
+
+/***********************************************************************
+ * Function: void uti596append
+ *
+ * Description:
+ * adds an RFD to the end of the received frame queue,
+ * for processing by the rxproc.
+ * Also removes this RFD from the RFA
+ *
+ * Algorithm:
+ *
+ ***********************************************************************/
+void uti596append(
+ 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))
+ }
+}
+
+/***********************************************************************
+ * Function: void printk_time
+ *
+ * Description:
+ ***********************************************************************/
+void printk_time( void )
+{
+ rtems_time_of_day tm_struct;
+
+ rtems_clock_get(RTEMS_CLOCK_GET_TOD, &tm_struct);
+ printk(("Current time: %d:%d:%d \n",
+ tm_struct.hour,
+ tm_struct.minute,
+ tm_struct.second))
+}
+
+/***********************************************************************
+ * Function: void dump_scb
+ *
+ * Description:
+ ***********************************************************************/
+void 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%x\n",uti596_softc.scb.crc_err))
+ printk(("align_err 0x%x\n",uti596_softc.scb.align_err))
+ printk(("resource_err 0x%x\n",uti596_softc.scb.resource_err ))
+ printk(("over_err 0x%x\n",uti596_softc.scb.over_err))
+ printk(("rcvdt_err 0x%x\n",uti596_softc.scb.rcvdt_err))
+ printk(("short_err 0x%x\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))
+}
+
+
+#ifdef DBG_INIT_3
+
+ /***********************************************************************
+ **
+ ** Debugging Functions
+ **
+ ***********************************************************************/
+
+
+ /***********************************************************************
+ * Function: print_eth
+ *
+ * Description:
+ * Print the contents of an ethernet packet header
+ * CANNOT BE CALLED FROM ISR
+ *
+ * Algorithm:
+ * Print Destination, Src, and type of packet
+ *
+ ***********************************************************************/
+
+/* 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]))
+ /* 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]))
+ */
+ }
+}
+
+ /***********************************************************************
+ * Function: print_hdr
+ *
+ * Description:
+ * Print the contents of an ethernet packet header
+ * CANNOT BE CALLED FROM ISR
+ *
+ * Algorithm:
+ * Print Destination, Src, and type of packet
+ *
+ ***********************************************************************/
+
+/* 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
+ *
+ * Description:
+ * Print the contents of an ethernet packet header
+ * CANNOT BE CALLED FROM ISR
+ *
+ * Algorithm:
+ * Print Destination, Src, and type of packet
+ *
+ ***********************************************************************/
+
+/* 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"))
+ }
+}
+
+ /***********************************************************************
+ * Function: print_echo
+ *
+ * Description:
+ * Print the contents of an ethernet packet header
+ * CANNOT BE CALLED FROM ISR
+ *
+ * Algorithm:
+ * Prints only echo packets
+ *
+ ***********************************************************************/
+
+/* 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
+
+/***********************************************************************
+ * Function: uti596dump
+ *
+ * Description: Dump 596 registers
+ *
+ * Algorithm:
+ ***********************************************************************/
+/* static */ int uti596dump(
+ char * pDumpArea
+)
+{
+ i596_dump dumpCmd;
+ int boguscnt = 25000000; /* over a second! */
+
+#ifdef DBG_596
+ printk(("uti596dump: begin\n"))
+#endif
+
+ dumpCmd.cmd.command = CmdDump;
+ dumpCmd.cmd.next = I596_NULL;
+ dumpCmd.pData = pDumpArea;
+ uti596_softc.cmdOk = 0;
+ uti596addCmd ( (i596_cmd *)&dumpCmd);
+ while (1) {
+ if ( --boguscnt == 0) {
+ printk(("Dump command was not processed within spin loop delay\n"))
+ return 0;
+ }
+ else {
+ if ( uti596_softc.cmdOk ) {
+ return 1; /* successful completion */
+ }
+ }
+ }
+}
+
+/***********************************************************************
+ * Function: void dumpQ
+ *
+ * Description:
+ ***********************************************************************/
+void dumpQ( void )
+{
+ i596_rfd *pRfd;
+
+ printk(("savedQ:\n"))
+
+ for( pRfd = uti596_softc.pSavedRfdQueue;
+ pRfd != I596_NULL;
+ pRfd = 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 = 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 = pRfd -> next) {
+ printk(("pRfd: %p, stat: 0x%x cmd: 0x%x\n",pRfd,pRfd -> stat,pRfd -> cmd))
+ }
+}
+
+
+/***********************************************************************
+ * Function: void show_buffers
+ *
+ * Description:
+ ***********************************************************************/
+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 = 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 = 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 = pRfd->next) {
+ printk(("Frame @ %p, status: %2.2x, cmd: %2.2x\n",
+ pRfd, pRfd->stat, pRfd->cmd))
+ }
+
+ printk(("\nUnknown: %p\n",uti596_softc.pLastUnkRFD))
+}
+
+/***********************************************************************
+ * Function: void show_queues
+ *
+ * Description:
+ ***********************************************************************/
+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 = 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 = pRfd->next) {
+ printk(("0x%p\n", pRfd))
+ }
+
+ printk(("uti596_softc.pEndRFA: %p\n",uti596_softc.pEndRFA))
+}
+
+ /***********************************************************************
+ * Function: word_swap
+ *
+ * Description:
+ * Return a 32 bit value, swapping the upper
+ * and lower words first.
+ *
+ ***********************************************************************/
+unsigned long word_swap (unsigned long val)
+{
+ return (((val >> 16)&(0x0000ffff)) | ((val << 16)&(0xffff0000)));
+}
+
+
diff --git a/c/src/lib/libbsp/m68k/mvme167/network/uti596.h b/c/src/lib/libbsp/m68k/mvme167/network/uti596.h
new file mode 100644
index 0000000000..5757767526
--- /dev/null
+++ b/c/src/lib/libbsp/m68k/mvme167/network/uti596.h
@@ -0,0 +1,298 @@
+
+/* uti596.h: Contains the defines and structures used by the uti596 driver */
+
+/*
+ * EII: March 11: Created v. 0.0
+ * Jan 12/98 Added STAT bits, s11-=s5 and max_colls.
+ *
+ * $Id$
+ */
+
+#ifndef UTI596_H
+#define UTI596_H
+#include <rtems/error.h>
+#include <rtems/rtems_bsdnet.h>
+
+#include <sys/param.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+
+#include <net/if.h>
+
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+
+/* 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 UTI596_MUTEX 1
+
+
+#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 IO_ADDR 0x360
+#define PORT_ADDR IO_ADDR
+#define CHAN_ATTN PORT_ADDR + 4
+#define NIC_ADDR PORT_ADDR + 8
+
+#define I596_NULL ( ( void * ) 0xffffffff)
+#define UTI_596_END_OF_FRAME 0x8000
+#define SIZE_MASK 0x3fff
+
+struct i596_tbd;
+
+enum commands {
+ CmdNOp = 0,
+ CmdSASetup = 1,
+ CmdConfigure = 2,
+ CmdMulticastList = 3,
+ CmdTx = 4,
+ CmdTDR = 5,
+ CmdDump = 6,
+ CmdDiagnose = 7
+};
+
+/*
+ * Action commands
+ * (big endian, linear mode)
+ */
+typedef volatile struct i596_cmd {
+ volatile unsigned short status;
+ volatile 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 {
+ volatile unsigned short stat;
+ volatile unsigned short cmd;
+ volatile struct i596_rfd *next;
+ i596_rbd *pRbd;
+ unsigned short count;
+ unsigned short size;
+ char data [1532];
+} i596_rfd;
+
+#define RX_RING_SIZE 8
+
+/*
+ * System Control Block
+ */
+typedef volatile struct i596_scb {
+ volatile unsigned short status;
+ volatile unsigned short command;
+ volatile unsigned long Cmd_val;
+ volatile unsigned long Rfd_val;
+ volatile unsigned long crc_err;
+ volatile unsigned long align_err;
+ volatile unsigned long resource_err;
+ volatile unsigned long over_err;
+ volatile unsigned long rcvdt_err;
+ volatile unsigned long short_err;
+ volatile unsigned short t_off;
+ volatile unsigned short t_on;
+ i596_cmd *pCmd;
+ i596_rfd *pRfd;
+} i596_scb;
+
+/*
+ * Intermediate System Configuration Pointer
+ */
+typedef volatile struct i596_iscp {
+ volatile unsigned long stat;
+ volatile unsigned long scb_val;
+ i596_scb *scb;
+} i596_iscp;
+
+/*
+ * System Configuration Pointer
+ */
+typedef volatile struct i596_scp {
+ unsigned long sysbus;
+ unsigned long pad;
+ unsigned long iscp_val;
+ i596_iscp *iscp;
+} i596_scp;
+
+typedef volatile struct uti596_softc {
+ struct arpcom arpcom;
+ i596_scp *pScp;
+ i596_iscp iscp;
+ i596_scb scb;
+ i596_set_add set_add;
+ i596_configure set_conf;
+ i596_tdr tdr;
+ i596_nop nop;
+ unsigned long stat;
+ i596_tx *pTxCmd;
+ i596_tbd *pTbd;
+
+ int ioAddr;
+
+ 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;
+ 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 is for requesting that ISR issue a reset quest */
+} uti596_softc_;
+
+#endif /* UTI596_H */