summaryrefslogtreecommitdiffstats
path: root/c/src/lib/libbsp/m68k/mvme167/network
diff options
context:
space:
mode:
authorJoel Sherrill <joel.sherrill@OARcorp.com>2000-04-05 13:01:21 +0000
committerJoel Sherrill <joel.sherrill@OARcorp.com>2000-04-05 13:01:21 +0000
commit5a23ca846b0c8c22f30eac1251440648441b94b1 (patch)
treebd89f600364fb16503de76cc8abca249bde9a20c /c/src/lib/libbsp/m68k/mvme167/network
parentNew file from Ralf Corsepius <corsepiu@faw.uni-ulm.de> as part of (diff)
downloadrtems-5a23ca846b0c8c22f30eac1251440648441b94b1.tar.bz2
New files from John Cotton <John.Cotton@nrc.ca> and Charles-Antoine
Gauthier <charles.gauthier@nrc.ca>. The power supply in their VMEbus cage died so it was submitted at this point. It passes ttcp which is a really good sign but they would like to do more testing and cleanup once their hardware is functional again. Please contact them if you are interested in using or fixing this driver. As their comments indicate, the performance is actually quite good even at this point as indicated by the ttcp results. Please note that this is by no means a final version. The code is still fairly ugly, and will require some further fixing. On the bright side, what is attached works. I finally ran the test programs successfully with optimized code and data cache enabled: netdemos worked, but failed on the UDP transfer (runs out of buffers). ttcp worked, with something like 1036 KB/sec Rx, 952 KB/sec Tx. tftp worked
Diffstat (limited to 'c/src/lib/libbsp/m68k/mvme167/network')
-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 */