summaryrefslogtreecommitdiffstats
path: root/c
diff options
context:
space:
mode:
Diffstat (limited to 'c')
-rw-r--r--c/ACKNOWLEDGEMENTS4
-rw-r--r--c/Makefile.in5
-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
-rw-r--r--c/src/wrapup/Makefile.in1
10 files changed, 1037 insertions, 5 deletions
diff --git a/c/ACKNOWLEDGEMENTS b/c/ACKNOWLEDGEMENTS
index 153cf1b1fe..535b913ab8 100644
--- a/c/ACKNOWLEDGEMENTS
+++ b/c/ACKNOWLEDGEMENTS
@@ -97,6 +97,10 @@ The following persons/organizations have made contributions:
mode with a m68040 and a port of the Motorola MC68040 Floating Point
Support Package (FPSP) to RTEMS.
++ Eric Norum (eric@skatter.usask.ca) of the Saskatchewan Accelerator
+ Laboratory submitted a port of the KA9Q TCP/IP stack to RTEMS as
+ well as a network device driver for the gen68360 BSP.
+
Finally, the RTEMS project would like to thank those who have contributed
to the other free software efforts which RTEMS utilizes. The primary RTEMS
development environment is from the Free Software Foundation (the GNU
diff --git a/c/Makefile.in b/c/Makefile.in
index 2892073027..8bb19c7fc1 100644
--- a/c/Makefile.in
+++ b/c/Makefile.in
@@ -27,10 +27,15 @@ export PROJECT_HOME
SUB_DIRS=build-tools src
+# We only make the install point for the KA9Q header files if it is enabled.
+LIBKA9Q_yes_V = include/ka9q
+LIBKA9Q = $(LIBKA9Q_$(HAS_KA9Q)_V)
+
# directories to be created in install point
CREATE_DIRS = include include/sys \
include/rtems include/rtems/score include/rtems/rtems include/rtems/posix \
include/netinet include/libc include/libc/sys \
+ $(LIBKA9Q) \
lib bin samples \
tests tests/screens tests/screens/sptests \
tests/screens/psxtests tests/screens/mptests \
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)
diff --git a/c/src/wrapup/Makefile.in b/c/src/wrapup/Makefile.in
index 0316d5c56b..2446f24015 100644
--- a/c/src/wrapup/Makefile.in
+++ b/c/src/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)