summaryrefslogtreecommitdiffstats
path: root/c/src/lib
diff options
context:
space:
mode:
Diffstat (limited to 'c/src/lib')
-rw-r--r--c/src/lib/include/Makefile.in10
-rw-r--r--c/src/lib/libbsp/m68k/gen68360/Makefile.in6
-rw-r--r--c/src/lib/libbsp/m68k/gen68360/README9
-rw-r--r--c/src/lib/libbsp/m68k/gen68360/network/Makefile.in53
-rw-r--r--c/src/lib/libbsp/m68k/gen68360/network/network.c947
-rw-r--r--c/src/lib/libbsp/m68k/gen68360/wrapup/Makefile.in6
-rw-r--r--c/src/lib/wrapup/Makefile.in1
7 files changed, 1027 insertions, 5 deletions
diff --git a/c/src/lib/include/Makefile.in b/c/src/lib/include/Makefile.in
index c15472cbc0..092b7c9766 100644
--- a/c/src/lib/include/Makefile.in
+++ b/c/src/lib/include/Makefile.in
@@ -11,6 +11,13 @@ H_PIECES=console clockdrv iosupp ringbuf \
spurious timerdrv vmeintr z8036 z8530 z8536
H_FILES=$(H_PIECES:%=$(srcdir)/%.h)
+KA9Q_H_PIECES= arp asy ax25 ax25mail bootp cmdparse commands config \
+ daemon dialer domain enet ftp ftpcli global hardware icmp iface \
+ internet ip kiss lapb lzw mailbox mbuf netuser nospc nr4 nr4mail \
+ nrs ping pktdrvr ppp proc rip rtems_ka9q sb session slhc slip smtp \
+ sockaddr socket tcp telnet tftp timer tipmail trace udp usock
+KA9Q_H_FILES=$(KA9Q_H_PIECES:%=$(srcdir)/ka9q/%.h)
+
SYS_H_FILES=
SRCS=$(H_FILES) $(SYS_H_FILES)
@@ -24,3 +31,6 @@ CLOBBER_ADDITIONS +=
all: $(SRCS)
$(INSTALL) -m 444 $(H_FILES) ${PROJECT_RELEASE}/include
$(INSTALL) -m 444 $(SYS_H_FILES) ${PROJECT_RELEASE}/include/sys
+ifeq ($(HAS_KA9Q),yes)
+ $(INSTALL) -m 444 $(KA9Q_H_FILES) ${PROJECT_RELEASE}/include/ka9q
+endif
diff --git a/c/src/lib/libbsp/m68k/gen68360/Makefile.in b/c/src/lib/libbsp/m68k/gen68360/Makefile.in
index 9581a49c3b..83c9fe4822 100644
--- a/c/src/lib/libbsp/m68k/gen68360/Makefile.in
+++ b/c/src/lib/libbsp/m68k/gen68360/Makefile.in
@@ -12,8 +12,12 @@ include $(PROJECT_ROOT)/make/directory.cfg
SRCS=README
+# We only build the ka9q device driver if HAS_KA9Q was defined
+KA9Q_DRIVER_yes_V = network
+KA9Q_DRIVER = $(KA9Q_DRIVER_$(HAS_KA9Q)_V)
+
all: $(SRCS)
# wrapup is the one that actually builds and installs the library
# from the individual .rel files built in other directories
-SUB_DIRS=include start360 startup clock console timer wrapup
+SUB_DIRS=include start360 startup clock console timer $(KA9Q_DRIVER) wrapup
diff --git a/c/src/lib/libbsp/m68k/gen68360/README b/c/src/lib/libbsp/m68k/gen68360/README
index f0dd2a1bf0..ce3aa09cef 100644
--- a/c/src/lib/libbsp/m68k/gen68360/README
+++ b/c/src/lib/libbsp/m68k/gen68360/README
@@ -39,9 +39,12 @@
# The default value is 4 Mbytes. To specify 16 Mbytes of memory,
# --defsym RamSize=0x1000000
#
-# - The size of the memory allocator heap. The default value is
-# 64 kbytes. To choose a heap size of 256 kbytes,
-# --defsym HeapSize=0x40000
+# - The size of the memory allocator heap. The default value is
+# 64 kbytes. If the KA9Q network package is used the heap
+# should be at least 256 kbytes. If your network is large, or
+# busy, the heap should be even larger.
+# To choose a heap size of 256 kbytes,
+# --defsym HeapSize=0x40000
#
# - The Ethernet address for network boot proms.
diff --git a/c/src/lib/libbsp/m68k/gen68360/network/Makefile.in b/c/src/lib/libbsp/m68k/gen68360/network/Makefile.in
new file mode 100644
index 0000000000..f733f80d7d
--- /dev/null
+++ b/c/src/lib/libbsp/m68k/gen68360/network/Makefile.in
@@ -0,0 +1,53 @@
+#
+# $Id$
+#
+
+@SET_MAKE@
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH=@srcdir@
+
+PGM=${ARCH}/network.rel
+
+# C source names, if any, go here -- minus the .c
+C_PIECES=network
+C_FILES=$(C_PIECES:%=%.c)
+C_O_FILES=$(C_PIECES:%=${ARCH}/%.o)
+
+H_FILES=
+
+SRCS=$(C_FILES) $(H_FILES)
+OBJS=$(C_O_FILES)
+
+include $(RTEMS_CUSTOM)
+include $(PROJECT_ROOT)/make/leaf.cfg
+
+#
+# (OPTIONAL) Add local stuff here using +=
+#
+
+DEFINES +=
+CPPFLAGS +=
+CFLAGS +=
+
+LD_PATHS +=
+LD_LIBS +=
+LDFLAGS +=
+
+#
+# Add your list of files to delete here. The config files
+# already know how to delete some stuff, so you may want
+# to just run 'make clean' first to see what gets missed.
+# 'make clobber' already includes 'make clean'
+#
+
+CLEAN_ADDITIONS +=
+CLOBBER_ADDITIONS +=
+
+${PGM}: ${SRCS} ${OBJS}
+ $(make-rel)
+
+all: ${ARCH} $(SRCS) $(PGM)
+
+# the .rel file built here will be put into libbsp.a by ../wrapup/Makefile
+install: all
diff --git a/c/src/lib/libbsp/m68k/gen68360/network/network.c b/c/src/lib/libbsp/m68k/gen68360/network/network.c
new file mode 100644
index 0000000000..f8e54e2a78
--- /dev/null
+++ b/c/src/lib/libbsp/m68k/gen68360/network/network.c
@@ -0,0 +1,947 @@
+/*
+ * RTEMS/KA9Q driver for M68360 SCC1 Ethernet
+ *
+ * W. Eric Norum
+ * Saskatchewan Accelerator Laboratory
+ * University of Saskatchewan
+ * Saskatoon, Saskatchewan, CANADA
+ * eric@skatter.usask.ca
+ *
+ * $Id$
+ */
+#include <bsp.h>
+#include <m68360.h>
+#include <rtems/error.h>
+#include <ka9q/rtems_ka9q.h>
+#include <ka9q/global.h>
+#include <ka9q/enet.h>
+#include <ka9q/iface.h>
+#include <ka9q/netuser.h>
+#include <ka9q/trace.h>
+#include <ka9q/commands.h>
+
+/*
+ * Number of SCCs supported by this driver
+ */
+#define NSCCDRIVER 1
+
+/*
+ * Default number of buffer descriptors set aside for this driver.
+ * The number of transmit buffer descriptors has to be quite large
+ * since a single frame often uses four or more buffer descriptors.
+ */
+#define RX_BD_COUNT 15
+#define TX_BD_COUNT 12
+
+/*
+ * RTEMS event used by interrupt handler to signal daemons.
+ * This must *not* be the same event used by the KA9Q task synchronization.
+ */
+#define INTERRUPT_EVENT RTEMS_EVENT_1
+
+/*
+ * Receive buffer size -- Allow for a full ethernet packet plus a pointer
+ */
+#define RBUF_SIZE (1520 + sizeof (struct iface *))
+
+/*
+ * Hardware-specific storage
+ */
+struct m360EnetDriver {
+ struct mbuf **rxMbuf;
+ struct mbuf **txMbuf;
+ int rxBdCount;
+ int txBdCount;
+ int txBdHead;
+ int txBdTail;
+ int txBdActiveCount;
+ m360BufferDescriptor_t *rxBdBase;
+ m360BufferDescriptor_t *txBdBase;
+ struct iface *iface;
+ rtems_id txWaitTid;
+
+ /*
+ * Statistics
+ */
+ unsigned long rxInterrupts;
+ unsigned long rxNotFirst;
+ unsigned long rxNotLast;
+ unsigned long rxGiant;
+ unsigned long rxNonOctet;
+ unsigned long rxRunt;
+ unsigned long rxBadCRC;
+ unsigned long rxOverrun;
+ unsigned long rxCollision;
+
+ unsigned long txInterrupts;
+ unsigned long txDeferred;
+ unsigned long txHeartbeat;
+ unsigned long txLateCollision;
+ unsigned long txRetryLimit;
+ unsigned long txUnderrun;
+ unsigned long txLostCarrier;
+ unsigned long txRawWait;
+};
+static struct m360EnetDriver m360EnetDriver[NSCCDRIVER];
+
+/*
+ * SCC1 interrupt handler
+ */
+static rtems_isr
+m360Enet_interrupt_handler (rtems_vector_number v)
+{
+ /*
+ * Frame received?
+ */
+ if ((m360.scc1.sccm & 0x8) && (m360.scc1.scce & 0x8)) {
+ m360.scc1.scce = 0x8;
+ m360EnetDriver[0].rxInterrupts++;
+ rtems_event_send (m360EnetDriver[0].iface->rxproc, INTERRUPT_EVENT);
+ }
+
+ /*
+ * Buffer transmitted or transmitter error?
+ */
+ if ((m360.scc1.sccm & 0x12) && (m360.scc1.scce & 0x12)) {
+ m360.scc1.scce = 0x12;
+ m360EnetDriver[0].txInterrupts++;
+ rtems_event_send (m360EnetDriver[0].txWaitTid, INTERRUPT_EVENT);
+ }
+ m360.cisr = 1UL << 30; /* Clear SCC1 interrupt-in-service bit */
+}
+
+/*
+ * Initialize the ethernet hardware
+ */
+static void
+m360Enet_initialize_hardware (struct m360EnetDriver *dp, int broadcastFlag)
+{
+ int i;
+ unsigned char *hwaddr;
+ rtems_status_code sc;
+ rtems_isr_entry old_handler;
+
+ /*
+ * Configure port A CLK1, CLK2, TXD1 and RXD1 pins
+ */
+ m360.papar |= 0x303;
+ m360.padir &= ~0x303;
+ m360.paodr &= ~0x303;
+
+ /*
+ * Configure port C CTS1* and CD1* pins
+ */
+ m360.pcpar &= ~0x30;
+ m360.pcdir &= ~0x30;
+ m360.pcso |= 0x30;
+
+ /*
+ * Connect CLK1 and CLK2 to SCC1
+ */
+ m360.sicr &= ~0xFF;
+ m360.sicr |= (5 << 3) | 4;
+
+ /*
+ * Allocate mbuf pointers
+ */
+ dp->rxMbuf = mallocw (dp->rxBdCount * sizeof *dp->rxMbuf);
+ dp->txMbuf = mallocw (dp->txBdCount * sizeof *dp->txMbuf);
+
+ /*
+ * Set receiver and transmitter buffer descriptor bases
+ */
+ dp->rxBdBase = M360AllocateBufferDescriptors(dp->rxBdCount);
+ dp->txBdBase = M360AllocateBufferDescriptors(dp->txBdCount);
+ m360.scc1p.rbase = (char *)dp->rxBdBase - (char *)&m360;
+ m360.scc1p.tbase = (char *)dp->txBdBase - (char *)&m360;
+
+ /*
+ * Send "Init parameters" command
+ */
+ M360ExecuteRISC (M360_CR_OP_INIT_RX_TX | M360_CR_CHAN_SCC1);
+
+ /*
+ * Set receive and transmit function codes
+ */
+ m360.scc1p.rfcr = M360_RFCR_MOT | M360_RFCR_DMA_SPACE;
+ m360.scc1p.tfcr = M360_TFCR_MOT | M360_TFCR_DMA_SPACE;
+
+ /*
+ * Set maximum receive buffer length
+ */
+ m360.scc1p.mrblr = 1520;
+
+ /*
+ * Set CRC parameters
+ */
+ m360.scc1p.un.ethernet.c_pres = 0xFFFFFFFF;
+ m360.scc1p.un.ethernet.c_mask = 0xDEBB20E3;
+
+ /*
+ * Clear diagnostic counters
+ */
+ m360.scc1p.un.ethernet.crcec = 0;
+ m360.scc1p.un.ethernet.alec = 0;
+ m360.scc1p.un.ethernet.disfc = 0;
+
+ /*
+ * Set pad value
+ */
+ m360.scc1p.un.ethernet.pads = 0x8888;
+
+ /*
+ * Set retry limit
+ */
+ m360.scc1p.un.ethernet.ret_lim = 15;
+
+ /*
+ * Set maximum and minimum frame length
+ */
+ m360.scc1p.un.ethernet.mflr = 1518;
+ m360.scc1p.un.ethernet.minflr = 64;
+ m360.scc1p.un.ethernet.maxd1 = 1520;
+ m360.scc1p.un.ethernet.maxd2 = 1520;
+
+ /*
+ * Clear group address hash table
+ */
+ m360.scc1p.un.ethernet.gaddr1 = 0;
+ m360.scc1p.un.ethernet.gaddr2 = 0;
+ m360.scc1p.un.ethernet.gaddr3 = 0;
+ m360.scc1p.un.ethernet.gaddr4 = 0;
+
+ /*
+ * Set our physical address
+ */
+ hwaddr = dp->iface->hwaddr;
+ m360.scc1p.un.ethernet.paddr_h = (hwaddr[5] << 8) | hwaddr[4];
+ m360.scc1p.un.ethernet.paddr_m = (hwaddr[3] << 8) | hwaddr[2];
+ m360.scc1p.un.ethernet.paddr_l = (hwaddr[1] << 8) | hwaddr[0];
+
+ /*
+ * Aggressive retry
+ */
+ m360.scc1p.un.ethernet.p_per = 0;
+
+ /*
+ * Clear individual address hash table
+ */
+ m360.scc1p.un.ethernet.iaddr1 = 0;
+ m360.scc1p.un.ethernet.iaddr2 = 0;
+ m360.scc1p.un.ethernet.iaddr3 = 0;
+ m360.scc1p.un.ethernet.iaddr4 = 0;
+
+ /*
+ * Set up receive buffer descriptors
+ */
+ for (i = 0 ; i < dp->rxBdCount ; i++)
+ (dp->rxBdBase + i)->status = 0;
+
+ /*
+ * Set up transmit buffer descriptors
+ */
+ for (i = 0 ; i < dp->txBdCount ; i++) {
+ (dp->txBdBase + i)->status = 0;
+ dp->txMbuf[i] = NULL;
+ }
+ dp->txBdHead = dp->txBdTail = 0;
+ dp->txBdActiveCount = 0;
+
+ /*
+ * Clear any outstanding events
+ */
+ m360.scc1.scce = 0xFFFF;
+
+ /*
+ * Set up interrupts
+ */
+ sc = rtems_interrupt_catch (m360Enet_interrupt_handler,
+ (m360.cicr & 0xE0) | 0x1E,
+ &old_handler);
+ if (sc != RTEMS_SUCCESSFUL)
+ rtems_panic ("Can't attach M360 SCC1 interrupt handler: %s\n",
+ rtems_status_text (sc));
+ m360.scc1.sccm = 0; /* No interrupts unmasked till necessary */
+ m360.cimr |= (1UL << 30); /* Enable SCC1 interrupt */
+
+ /*
+ * Set up General SCC Mode Register
+ * Ethernet configuration
+ */
+ m360.scc1.gsmr_h = 0x0;
+ m360.scc1.gsmr_l = 0x1088000c;
+
+ /*
+ * Set up data synchronization register
+ * Ethernet synchronization pattern
+ */
+ m360.scc1.dsr = 0xd555;
+
+ /*
+ * Set up protocol-specific mode register
+ * Heartbeat check
+ * No force collision
+ * Discard short frames
+ * Individual address mode
+ * Ethernet CRC
+ * Not promisuous
+ * Ignore/accept broadcast packets as specified
+ * Normal backoff timer
+ * No loopback
+ * No input sample at end of frame
+ * 64-byte limit for late collision
+ * Wait 22 bits before looking for start of frame delimiter
+ * Disable full-duplex operation
+ */
+ m360.scc1.psmr = 0x880A | (broadcastFlag ? 0 : 0x100);
+
+ /*
+ * Enable the TENA (RTS1*) pin
+ */
+#if (defined (M68360_ATLAS_HSB))
+ m360.pbpar |= 0x1000;
+ m360.pbdir |= 0x1000;
+#else
+ m360.pcpar |= 0x1;
+ m360.pcdir &= ~0x1;
+#endif
+
+ /*
+ * Enable receiver and transmitter
+ */
+ m360.scc1.gsmr_l = 0x1088003c;
+}
+
+/*
+ * Soak up buffer descriptors that have been sent
+ * Note that a buffer descriptor can't be retired as soon as it becomes
+ * ready. The MC68360 Errata (May 96) says that, "If an Ethernet frame is
+ * made up of multiple buffers, the user should not reuse the first buffer
+ * descriptor until the last buffer descriptor of the frame has had its
+ * ready bit cleared by the CPM".
+ */
+static void
+m360Enet_retire_tx_bd (struct m360EnetDriver *dp)
+{
+ rtems_unsigned16 status;
+ int i;
+ int nRetired;
+
+ i = dp->txBdTail;
+ nRetired = 0;
+ while ((dp->txBdActiveCount != 0)
+ && (((status = (dp->txBdBase + i)->status) & M360_BD_READY) == 0)) {
+ /*
+ * See if anything went wrong
+ */
+ if (status & (M360_BD_DEFER |
+ M360_BD_HEARTBEAT |
+ M360_BD_LATE_COLLISION |
+ M360_BD_RETRY_LIMIT |
+ M360_BD_UNDERRUN |
+ M360_BD_CARRIER_LOST)) {
+ /*
+ * Check for errors which stop the transmitter.
+ */
+ if (status & (M360_BD_LATE_COLLISION |
+ M360_BD_RETRY_LIMIT |
+ M360_BD_UNDERRUN)) {
+ if (status & M360_BD_LATE_COLLISION)
+ m360EnetDriver[0].txLateCollision++;
+ if (status & M360_BD_RETRY_LIMIT)
+ m360EnetDriver[0].txRetryLimit++;
+ if (status & M360_BD_UNDERRUN)
+ m360EnetDriver[0].txUnderrun++;
+
+ /*
+ * Restart the transmitter
+ */
+ M360ExecuteRISC (M360_CR_OP_RESTART_TX | M360_CR_CHAN_SCC1);
+ }
+ if (status & M360_BD_DEFER)
+ m360EnetDriver[0].txDeferred++;
+ if (status & M360_BD_HEARTBEAT)
+ m360EnetDriver[0].txHeartbeat++;
+ if (status & M360_BD_CARRIER_LOST)
+ m360EnetDriver[0].txLostCarrier++;
+ }
+ nRetired++;
+ if (status & M360_BD_LAST) {
+ /*
+ * A full frame has been transmitted.
+ * Free all the associated buffer descriptors.
+ */
+ dp->txBdActiveCount -= nRetired;
+ while (nRetired) {
+ nRetired--;
+ free_mbuf (&dp->txMbuf[dp->txBdTail]);
+ if (++dp->txBdTail == dp->txBdCount)
+ dp->txBdTail = 0;
+ }
+ }
+ if (++i == dp->txBdCount)
+ i = 0;
+ }
+}
+
+/*
+ * Send raw packet (caller provides header).
+ * This code runs in the context of the interface transmit
+ * task or in the context of the network task.
+ */
+static int
+m360Enet_raw (struct iface *iface, struct mbuf **bpp)
+{
+ struct m360EnetDriver *dp = &m360EnetDriver[iface->dev];
+ struct mbuf *bp;
+ volatile m360BufferDescriptor_t *firstTxBd, *txBd;
+ rtems_unsigned16 status;
+ int nAdded;
+
+ /*
+ * Fill in some logging data
+ */
+ iface->rawsndcnt++;
+ iface->lastsent = secclock ();
+ dump (iface, IF_TRACE_OUT, *bpp);
+
+ /*
+ * It would not do to have two tasks active in the transmit
+ * loop at the same time.
+ * The blocking is simple-minded since the odds of two tasks
+ * simultaneously attempting to use this code are low. The only
+ * way that two tasks can try to run here is:
+ * 1) Task A enters this code and ends up having to
+ * wait for a transmit buffer descriptor.
+ * 2) Task B gains control and tries to transmit a packet.
+ * The RTEMS/KA9Q scheduling semaphore ensures that there
+ * are no race conditions associated with manipulating the
+ * txWaitTid variable.
+ */
+ if (dp->txWaitTid) {
+ dp->txRawWait++;
+ while (dp->txWaitTid)
+ rtems_ka9q_ppause (10);
+ }
+
+ /*
+ * Free up buffer descriptors
+ */
+ m360Enet_retire_tx_bd (dp);
+
+ /*
+ * Set up the transmit buffer descriptors.
+ * No need to pad out short packets since the
+ * hardware takes care of that automatically.
+ * No need to copy the packet to a contiguous buffer
+ * since the hardware is capable of scatter/gather DMA.
+ */
+ bp = *bpp;
+ nAdded = 0;
+ txBd = firstTxBd = dp->txBdBase + dp->txBdHead;
+ for (;;) {
+ /*
+ * Wait for buffer descriptor to become available.
+ */
+ if ((dp->txBdActiveCount + nAdded) == dp->txBdCount) {
+ /*
+ * Find out who we are
+ */
+ if (dp->txWaitTid == 0)
+ rtems_task_ident (0, 0, &dp->txWaitTid);
+
+ /*
+ * Clear old events
+ */
+ m360.scc1.scce = 0x12;
+
+ /*
+ * Unmask TXB (buffer transmitted) and
+ * TXE (transmitter error) events.
+ */
+ m360.scc1.sccm |= 0x12;
+
+ /*
+ * Wait for buffer descriptor to become available.
+ * Note that the buffer descriptors are checked
+ * *before* * entering the wait loop -- this catches
+ * the possibility that a buffer descriptor became
+ * available between the `if' above, and the clearing
+ * of the event register.
+ * Also, the event receive doesn't wait forever.
+ * This is to catch the case where the transmitter
+ * stops in the middle of a frame -- and only the
+ * last buffer descriptor in a frame can generate
+ * an interrupt.
+ */
+ m360Enet_retire_tx_bd (dp);
+ while ((dp->txBdActiveCount + nAdded) == dp->txBdCount) {
+ rtems_ka9q_event_receive (INTERRUPT_EVENT,
+ RTEMS_WAIT|RTEMS_EVENT_ANY,
+ 1 + 1000000/BSP_Configuration.microseconds_per_tick);
+ m360Enet_retire_tx_bd (dp);
+ }
+
+ /*
+ * Mask TXB and TXE events.
+ * This eliminates the load of interupts happening
+ * when the daemon is not interested.
+ */
+ {
+ ISR_Level level;
+ _ISR_Disable (level);
+ m360.scc1.sccm &= ~0x12;
+ m360.scc1.scce = 0x12;
+ _ISR_Enable (level);
+ }
+ }
+
+ /*
+ * Fill in the buffer descriptor
+ */
+ txBd->buffer = bp->data;
+ txBd->length = bp->cnt;
+ dp->txMbuf[dp->txBdHead] = bp;
+
+ /*
+ * Don't set the READY flag till the whole packet has been readied.
+ */
+ status = nAdded ? M360_BD_READY : 0;
+ nAdded++;
+ if (++dp->txBdHead == dp->txBdCount) {
+ status |= M360_BD_WRAP;
+ dp->txBdHead = 0;
+ }
+
+ /*
+ * Set the transmit buffer status.
+ * Break out of the loop if this mbuf is the last in the frame.
+ */
+ if ((bp = bp->next) == NULL) {
+ status |= M360_BD_PAD | M360_BD_LAST | M360_BD_TX_CRC | M360_BD_INTERRUPT;
+ txBd->status = status;
+ firstTxBd->status |= M360_BD_READY;
+ dp->txBdActiveCount += nAdded;
+ break;
+ }
+ txBd->status = status;
+ txBd = dp->txBdBase + dp->txBdHead;
+ }
+
+ /*
+ * Show that we've finished with the packet
+ */
+ dp->txWaitTid = 0;
+ *bpp = NULL;
+ return 0;
+}
+
+/*
+ * SCC reader task
+ */
+static void
+m360Enet_rx (int dev, void *p1, void *p2)
+{
+ struct iface *iface = (struct iface *)p1;
+ struct m360EnetDriver *dp = (struct m360EnetDriver *)p2;
+ struct mbuf *bp;
+ rtems_unsigned16 status;
+ m360BufferDescriptor_t *rxBd;
+ int rxBdIndex;
+ int continuousCount;
+
+ /*
+ * Allocate space for incoming packets and start reception
+ */
+ for (rxBdIndex = 0 ; ;) {
+ rxBd = dp->rxBdBase + rxBdIndex;
+ dp->rxMbuf[rxBdIndex] = bp = ambufw (RBUF_SIZE);
+ bp->data += sizeof (struct iface *);
+ rxBd->buffer = bp->data;
+ rxBd->status = M360_BD_EMPTY | M360_BD_INTERRUPT;
+ if (++rxBdIndex == dp->rxBdCount) {
+ rxBd->status |= M360_BD_WRAP;
+ break;
+ }
+ }
+
+ /*
+ * Input packet handling loop
+ */
+ continuousCount = 0;
+ rxBdIndex = 0;
+ for (;;) {
+ rxBd = dp->rxBdBase + rxBdIndex;
+
+ /*
+ * Wait for packet if there's not one ready
+ */
+ if ((status = rxBd->status) & M360_BD_EMPTY) {
+ /*
+ * Reset `continuous-packet' count
+ */
+ continuousCount = 0;
+
+ /*
+ * Clear old events
+ */
+ m360.scc1.scce = 0x8;
+
+ /*
+ * Unmask RXF (Full frame received) event
+ */
+ m360.scc1.sccm |= 0x8;
+
+ /*
+ * Wait for packet
+ * Note that the buffer descriptor is checked
+ * *before* the event wait -- this catches the
+ * possibility that a packet arrived between the
+ * `if' above, and the clearing of the event register.
+ */
+ while ((status = rxBd->status) & M360_BD_EMPTY) {
+ rtems_ka9q_event_receive (INTERRUPT_EVENT,
+ RTEMS_WAIT|RTEMS_EVENT_ANY,
+ RTEMS_NO_TIMEOUT);
+ }
+
+ /*
+ * Mask RXF (Full frame received) event
+ * By doing so, we avoid the overhead of
+ * receive interupts happening while the receive
+ * daemon is busy elsewhere
+ */
+ {
+ ISR_Level level;
+ _ISR_Disable (level);
+ m360.scc1.sccm &= ~0x8;
+ m360.scc1.scce = 0x8;
+ _ISR_Enable (level);
+ }
+ }
+
+ /*
+ * Check that packet is valid
+ */
+ if ((status & (M360_BD_LAST |
+ M360_BD_FIRST_IN_FRAME |
+ M360_BD_LONG |
+ M360_BD_NONALIGNED |
+ M360_BD_SHORT |
+ M360_BD_CRC_ERROR |
+ M360_BD_OVERRUN |
+ M360_BD_COLLISION)) ==
+ (M360_BD_LAST |
+ M360_BD_FIRST_IN_FRAME)) {
+ /*
+ * Pass the packet up the chain
+ * The mbuf count is reduced to remove
+ * the frame check sequence at the end
+ * of the packet.
+ */
+ bp = dp->rxMbuf[rxBdIndex];
+ bp->cnt = rxBd->length - sizeof (uint32);
+ net_route (iface, &bp);
+
+ /*
+ * Give the network code a chance to digest the
+ * packet. This guards against a flurry of
+ * incoming packets (usually an ARP storm) from
+ * using up all the available memory.
+ */
+ if (++continuousCount >= dp->rxBdCount)
+ kwait_null ();
+
+ /*
+ * Allocate a new mbuf
+ * FIXME: It seems to me that it would be better
+ * if there were some way to limit number of mbufs
+ * in use by this interface, but I don't see any
+ * way of determining when the mbuf we pass up
+ * is freed.
+ */
+ dp->rxMbuf[rxBdIndex] = bp = ambufw (RBUF_SIZE);
+ bp->data += sizeof (struct iface *);
+ rxBd->buffer = bp->data;
+ }
+ else {
+ /*
+ * Something went wrong with the reception
+ */
+ if (!(status & M360_BD_LAST))
+ dp->rxNotLast++;
+ if (!(status & M360_BD_FIRST_IN_FRAME))
+ dp->rxNotFirst++;
+ if (status & M360_BD_LONG)
+ dp->rxGiant++;
+ if (status & M360_BD_NONALIGNED)
+ dp->rxNonOctet++;
+ if (status & M360_BD_SHORT)
+ dp->rxRunt++;
+ if (status & M360_BD_CRC_ERROR)
+ dp->rxBadCRC++;
+ if (status & M360_BD_OVERRUN)
+ dp->rxOverrun++;
+ if (status & M360_BD_COLLISION)
+ dp->rxCollision++;
+ }
+
+ /*
+ * Reenable the buffer descriptor
+ */
+ rxBd->status = (status & (M360_BD_WRAP | M360_BD_INTERRUPT)) | M360_BD_EMPTY;
+
+ /*
+ * Move to next buffer descriptor
+ */
+ if (++rxBdIndex == dp->rxBdCount)
+ rxBdIndex = 0;
+ }
+}
+
+/*
+ * Shut down the interface
+ * FIXME: This is a pretty simple-minded routine. It doesn't worry
+ * about cleaning up mbufs, shutting down daemons, etc.
+ */
+static int
+m360Enet_stop (struct iface *iface)
+{
+ /*
+ * Stop the transmitter
+ */
+ M360ExecuteRISC (M360_CR_OP_GR_STOP_TX | M360_CR_CHAN_SCC1);
+
+ /*
+ * Wait for graceful stop
+ * FIXME: Maybe there should be a watchdog loop around this....
+ */
+ while ((m360.scc1.scce & 0x80) == 0)
+ continue;
+
+ /*
+ * Shut down receiver and transmitter
+ */
+ m360.scc1.gsmr_l &= ~0x30;
+ return 0;
+}
+
+/*
+ * Show interface statistics
+ */
+static void
+m360Enet_show (struct iface *iface)
+{
+ printf (" Rx Interrupts:%-8lu", m360EnetDriver[0].rxInterrupts);
+ printf (" Not First:%-8lu", m360EnetDriver[0].rxNotFirst);
+ printf (" Not Last:%-8lu\n", m360EnetDriver[0].rxNotLast);
+ printf (" Giant:%-8lu", m360EnetDriver[0].rxGiant);
+ printf (" Runt:%-8lu", m360EnetDriver[0].rxRunt);
+ printf (" Non-octet:%-8lu\n", m360EnetDriver[0].rxNonOctet);
+ printf (" Bad CRC:%-8lu", m360EnetDriver[0].rxBadCRC);
+ printf (" Overrun:%-8lu", m360EnetDriver[0].rxOverrun);
+ printf (" Collision:%-8lu\n", m360EnetDriver[0].rxCollision);
+ printf (" Discarded:%-8lu\n", (unsigned long)m360.scc1p.un.ethernet.disfc);
+
+ printf (" Tx Interrupts:%-8lu", m360EnetDriver[0].txInterrupts);
+ printf (" Deferred:%-8lu", m360EnetDriver[0].txDeferred);
+ printf (" Missed Hearbeat:%-8lu\n", m360EnetDriver[0].txHeartbeat);
+ printf (" No Carrier:%-8lu", m360EnetDriver[0].txLostCarrier);
+ printf ("Retransmit Limit:%-8lu", m360EnetDriver[0].txRetryLimit);
+ printf (" Late Collision:%-8lu\n", m360EnetDriver[0].txLateCollision);
+ printf (" Underrun:%-8lu", m360EnetDriver[0].txUnderrun);
+ printf (" Raw output wait:%-8lu\n", m360EnetDriver[0].txRawWait);
+}
+
+/*
+ * Attach an SCC driver to the system
+ * This is the only `extern' function in the driver.
+ *
+ * argv[0]: interface label, e.g., "m360scc1"
+ * argv[1]: maximum transmission unit, bytes, e.g., "1500"
+ * argv[2]: accept ("broadcast") or ignore ("nobroadcast") broadcast packets
+ * Following arguments are optional, but if present, must appear in
+ * the following order:
+ * rxbdcount ## -- Set number of receive buffer descriptors
+ * txbdcount ## -- Set number of transmit buffer descriptors
+ * Following arguments are optional, but if Ethernet address is
+ * specified, Internet address must also be specified.
+ * ###.###.###.### -- IP address
+ * ##:##:##:##:##:## -- Ethernet address
+ */
+int
+m360Enet_attach (int argc, char *argv[], void *p)
+{
+ struct iface *iface;
+ struct m360EnetDriver *dp;
+ char *cp;
+ int i;
+ int argIndex;
+ int broadcastFlag;
+
+ /*
+ * Find a free driver
+ */
+ for (i = 0 ; i < NSCCDRIVER ; i++) {
+ if (m360EnetDriver[i].iface == NULL)
+ break;
+ }
+ if (i >= NSCCDRIVER) {
+ printf ("Too many SCC drivers.\n");
+ return -1;
+ }
+ if (if_lookup (argv[0]) != NULL) {
+ printf ("Interface %s already exists\n", argv[0]);
+ return -1;
+ }
+ dp = &m360EnetDriver[i];
+
+ /*
+ * Create an inteface descriptor
+ */
+ iface = callocw (1, sizeof *iface);
+ iface->name = strdup (argv[0]);
+ iface->mtu = atoi (argv[1]);
+
+ /*
+ * Select broadcast packet handling
+ */
+ cp = argv[2];
+ if (strnicmp (cp, "broadcast", strlen (cp)) == 0) {
+ broadcastFlag = 1;
+ }
+ else if (strnicmp (cp, "nobroadcast", strlen (cp)) == 0) {
+ broadcastFlag = 0;
+ }
+ else {
+ printf ("Argument `%s' is neither `broadcast' nor `nobroadcast'.\n", cp);
+ return -1;
+ }
+ argIndex = 3;
+
+ /*
+ * Set receive buffer descriptor count
+ */
+ dp->rxBdCount = RX_BD_COUNT;
+ if (argIndex < (argc - 1)) {
+ cp = argv[argIndex];
+ if (strnicmp (argv[argIndex], "rxbdcount", strlen (cp)) == 0) {
+ dp->rxBdCount = atoi (argv[argIndex + 1]);
+ argIndex += 2;
+ }
+ }
+
+ /*
+ * Set transmit buffer descriptor count
+ */
+ dp->txWaitTid = 0;
+ dp->txBdCount = TX_BD_COUNT;
+ if (argIndex < (argc - 1)) {
+ cp = argv[argIndex];
+ if (strnicmp (argv[argIndex], "txbdcount", strlen (cp)) == 0) {
+ dp->txBdCount = atoi (argv[argIndex + 1]);
+ argIndex += 2;
+ }
+ }
+
+ /*
+ * Set Internet address
+ */
+ if (argIndex < argc)
+ iface->addr = resolve (argv[argIndex++]);
+ else
+ iface->addr = Ip_addr;
+
+ /*
+ * Set Ethernet address
+ */
+ iface->hwaddr = mallocw (EADDR_LEN);
+ if (argIndex < argc) {
+ gether (iface->hwaddr, argv[argIndex++]);
+ }
+ else {
+ /*
+ * The first 4 bytes of the bootstrap prom contain
+ * the value loaded into the stack pointer as part
+ * of the CPU32's hardware reset exception handler.
+ * The following 4 bytes contain the value loaded
+ * into the program counter.
+ * The low order three octets of the boards' Ethernet
+ * address are stored in the three bytes immediately
+ * preceding this initial program counter value.
+ *
+ * See startup/linkcmds and start360/start360.s for
+ * details on how this is done.
+ *
+ * The high order three octets of the Ethernet address
+ * are fixed and indicate that the address is that
+ * of a Motorola device.
+ */
+ {
+ extern void *_RomBase; /* Value provided by linkcmds script */
+ const unsigned long *ExceptionVectors;
+ const unsigned char *entryPoint;
+ char cbuf[30];
+
+ /*
+ * Set up the fixed portion of the hardware address
+ */
+ iface->hwaddr[0] = 0x08;
+ iface->hwaddr[1] = 0x00;
+ iface->hwaddr[2] = 0x3e;
+
+ /*
+ * Sanity check -- assume entry point must be
+ * within 1 MByte of beginning of boot ROM.
+ */
+ ExceptionVectors = (const unsigned long *)&_RomBase;
+ entryPoint = (const unsigned char *)ExceptionVectors[1];
+ if (((unsigned long)entryPoint - (unsigned long)ExceptionVectors)
+ >= (1 * 1024 * 1024)) {
+ printf ("Warning -- Ethernet address can not be found in bootstrap PROM.\n");
+ iface->hwaddr[3] = 0x12;
+ iface->hwaddr[4] = 0xE2;
+ iface->hwaddr[5] = 0x05;
+ }
+ else {
+ iface->hwaddr[3] = entryPoint[-3];
+ iface->hwaddr[4] = entryPoint[-2];
+ iface->hwaddr[5] = entryPoint[-1];
+ }
+ printf ("Ethernet address: %s\n", pether (cbuf, iface->hwaddr));
+ }
+ }
+ iface->dev = i;
+ iface->raw = m360Enet_raw;
+ iface->stop = m360Enet_stop;
+ iface->show = m360Enet_show;
+ dp->iface = iface;
+ setencap (iface, "Ethernet");
+
+ /*
+ * Set up SCC hardware
+ */
+ m360Enet_initialize_hardware (dp, broadcastFlag);
+
+ /*
+ * Chain onto list of interfaces
+ */
+ iface->next = Ifaces;
+ Ifaces = iface;
+
+ /*
+ * Start I/O daemons
+ */
+ cp = if_name (iface, " tx");
+ iface->txproc = newproc (cp, 1024, if_tx, iface->dev, iface, NULL, 0);
+ free (cp);
+ cp = if_name (iface, " rx");
+ iface->rxproc = newproc (cp, 1024, m360Enet_rx, iface->dev, iface, dp, 0);
+ free (cp);
+ return 0;
+}
+
+/*
+ * FIXME: There should be an ioctl routine to allow things like
+ * enabling/disabling reception of broadcast packets.
+ */
diff --git a/c/src/lib/libbsp/m68k/gen68360/wrapup/Makefile.in b/c/src/lib/libbsp/m68k/gen68360/wrapup/Makefile.in
index 4893e89c5d..211d8619d7 100644
--- a/c/src/lib/libbsp/m68k/gen68360/wrapup/Makefile.in
+++ b/c/src/lib/libbsp/m68k/gen68360/wrapup/Makefile.in
@@ -7,7 +7,11 @@ srcdir = @srcdir@
top_srcdir = @top_srcdir@
VPATH=@srcdir@
-BSP_PIECES=startup clock console timer
+# We only build the ka9q device driver if HAS_KA9Q was defined
+KA9Q_DRIVER_yes_V = network
+KA9Q_DRIVER = $(KA9Q_DRIVER_$(HAS_KA9Q)_V)
+
+BSP_PIECES=startup clock console timer $(KA9Q_DRIVER)
CPU_PIECES=
GENERIC_PIECES=
diff --git a/c/src/lib/wrapup/Makefile.in b/c/src/lib/wrapup/Makefile.in
index 0316d5c56b..2446f24015 100644
--- a/c/src/lib/wrapup/Makefile.in
+++ b/c/src/lib/wrapup/Makefile.in
@@ -17,6 +17,7 @@ LIB=$(PROJECT_HOME)/lib/librtemsall.a
SRCS=$(wildcard $(PROJECT_HOME)/lib/libbsp$(LIB_VARIANT).a) \
$(PROJECT_HOME)/lib/librtems$(LIB_VARIANT).a \
$(wildcard $(PROJECT_HOME)/lib/libposix$(LIB_VARIANT).a) \
+ $(wildcard $(PROJECT_HOME)/lib/libka9q$(LIB_VARIANT).a) \
$(PROJECT_HOME)/lib/libcsupport$(LIB_VARIANT).a \
$(wildcard $(PROJECT_HOME)/lib/rtems-ctor$(LIB_VARIANT).o) \
$(wildcard $(PROJECT_HOME)/lib/libno-ctor$(LIB_VARIANT).a)