summaryrefslogtreecommitdiffstats
path: root/c/src/lib/libbsp/m68k/gen68302/network/network.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--c/src/lib/libbsp/m68k/gen68302/network/network.c985
1 files changed, 985 insertions, 0 deletions
diff --git a/c/src/lib/libbsp/m68k/gen68302/network/network.c b/c/src/lib/libbsp/m68k/gen68302/network/network.c
new file mode 100644
index 0000000000..9a058d8003
--- /dev/null
+++ b/c/src/lib/libbsp/m68k/gen68302/network/network.c
@@ -0,0 +1,985 @@
+/*
+ * RTEMS driver for M68360 SCC1 Ethernet
+ * W. Eric Norum
+ * Saskatchewan Accelerator Laboratory
+ * University of Saskatchewan
+ * Saskatoon, Saskatchewan, CANADA
+ * eric@skatter.usask.ca
+ *
+ * $Id$
+ *
+ * Modify for Motorola 68en320 Ethernet Controller
+ * CXR S.A. France - 2000/09/14 - franckj@cxr.fr
+ */
+#include <bsp.h>
+#include <stdio.h>
+#include <rtems/error.h>
+#include <m302_int.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 <m68302.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_BUF_COUNT 64
+#define TX_BUF_COUNT 64
+
+/*
+ * RTEMS event used by interrupt handler to signal driver tasks.
+ * This must not be any of the events used by the network task synchronization.
+ */
+#define INTERRUPT_EVENT RTEMS_EVENT_1
+
+/*
+ * RTEMS event used to start transmit daemon.
+ * This must not be the same as INTERRUPT_EVENT.
+ */
+#define START_TRANSMIT_EVENT RTEMS_EVENT_2
+
+/*
+ * Receive buffer size -- Allow for a full ethernet packet including CRC
+ */
+#define RBUF_SIZE 1520
+
+#if (MCLBYTES < RBUF_SIZE)
+# error "Driver must have MCLBYTES > RBUF_SIZE"
+#endif
+
+static struct m68302_imp * a_m68302_imp;
+
+#define M302_ETHER_IVECTOR 0x40
+
+/*
+ * Per-device data
+ */
+struct scc_softc {
+ struct arpcom arpcom;
+ struct mbuf **rxMbuf;
+ struct mbuf **txMbuf;
+ int acceptBroadcast;
+ int rxBdCount;
+ int txBdCount;
+ int txBdHead;
+ int txBdTail;
+ int txBdActiveCount;
+
+ struct m68302_scc_bd *rxBdBase;
+ struct m68302_scc_bd *txBdBase;
+
+ rtems_id rxDaemonTid;
+ rtems_id txDaemonTid;
+
+ /*
+ * 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;
+ unsigned long txCoalesced;
+ unsigned long txCoalesceFailed;
+ unsigned long txRetry;
+};
+static struct scc_softc scc_softc[NSCCDRIVER];
+
+/*
+ * interrupt handler
+ */
+static rtems_isr
+m302Enet_interrupt_handler (rtems_vector_number v)
+{
+
+ /*
+ * Frame received?
+ */
+ if (M68en302imp_intr_event & INTR_EVENT_BIT_RFINT) {
+ M68en302imp_intr_event = INTR_EVENT_BIT_RFINT;
+ M68en302imp_intr_mask &= ~INTR_MASK_BIT_RFIEN;
+ scc_softc[0].rxInterrupts++;
+ rtems_event_send (scc_softc[0].rxDaemonTid, INTERRUPT_EVENT);
+ }
+
+ /*
+ * Buffer transmitted or transmitter error?
+ */
+ if ((M68en302imp_intr_event & INTR_EVENT_BIT_TFINT) ||
+ ((M68en302imp_intr_event & INTR_EVENT_BIT_TXB))){
+ M68en302imp_intr_event = INTR_EVENT_BIT_TFINT | INTR_EVENT_BIT_TXB;
+ M68en302imp_intr_mask &= ~(INTR_MASK_BIT_TFIEN | INTR_MASK_BIT_TXIEN);
+ scc_softc[0].txInterrupts++;
+ rtems_event_send (scc_softc[0].txDaemonTid, INTERRUPT_EVENT);
+ }
+}
+
+/*
+ * Initialize the ethernet hardware
+ */
+static void
+m302Enet_initialize_hardware (struct scc_softc *sc)
+{
+ int i;
+ unsigned char *hwaddr;
+ rtems_status_code status;
+ rtems_isr_entry old_handler;
+ struct m68302_scc_bd *a_bd; /* Buffer Descriptor pointer */
+ ushort *cam;
+ void **p;
+ ushort tmp;
+#define LBK 0x0008
+#define DSQE 0x0010
+#define FDE 0x0020
+
+
+
+ /*
+ * standard loopback
+ */
+ M68302imp_port_data (1) &= ~(LBK);
+ M68302imp_port_data (1) |= (FDE);
+
+
+ M68en302imp_ecntrl=0x0001;
+ /*
+ * Set dma configuration status register EDMA
+ */
+ i = (sc->txBdCount == 16) ? EDMA_BDSIZE_16T_112R :
+ (sc->txBdCount == 32) ? EDMA_BDSIZE_32T_96R :
+ (sc->txBdCount == 64) ? EDMA_BDSIZE_64T_64R :
+ EDMA_BDSIZE_8T_120R;
+
+ M68en302imp_edma = EDMA_BLIM_8ACCESS | EDMA_WMRK_16FIFO | EDMA_BIT_TSRLY | (ushort)i;
+
+ /*
+ * Set maximum receive buffer length
+ */
+
+ M68en302imp_emrblr = RBUF_SIZE; /* 1520 */
+
+ /*
+ * Set interrupt vector
+ */
+ M68en302imp_intr_vect = M302_ETHER_IVECTOR;
+
+
+ M68en302imp_intr_mask=0x0;
+
+ /*
+ * Set ethernet Configuration
+ */
+ M68en302imp_ecnfig=0x0000;
+
+ /*
+ * Set ETHER_TEST
+ */
+ M68en302imp_ether_test=0x0000;
+
+ /*
+ * Set AR control Register
+ * Ignore/accept broadcast packets as specified
+ */
+ M68en302imp_ar_cntrl = ((sc->acceptBroadcast) ? 0 : AR_CNTRL_BIT_NO_BROADCAST) ;
+
+ /*
+ * Allocate mbuf pointers
+ */
+ sc->rxMbuf = malloc (sc->rxBdCount * sizeof *sc->rxMbuf, M_MBUF, M_NOWAIT);
+ sc->txMbuf = malloc (sc->txBdCount * sizeof *sc->txMbuf, M_MBUF, M_NOWAIT);
+ if (!sc->rxMbuf || !sc->txMbuf)
+ rtems_panic ("No memory for mbuf pointers");
+
+ /*
+ * Set our physical address
+ */
+ hwaddr = sc->arpcom.ac_enaddr;
+
+ cam=(ushort *)(M68en302imp_cet);
+ for (i=0;i<64;i++){
+ cam[(4*i)]=0x00ff;
+ cam[(4*i)+1]=0x00ff;
+ cam[(4*i)+2]=0x00ff;
+ }
+
+ cam[4] = (hwaddr[0] << 8) | hwaddr[1];
+ cam[5] = (hwaddr[2] << 8) | hwaddr[3];
+ cam[6] = (hwaddr[4] << 8) | hwaddr[5];
+
+
+ /*
+ * Set receiver and transmitter buffer descriptor bases
+ */
+ a_bd = M68302imp_a_eth_bd (0); /* point to first BD */
+
+
+ for (i=0;i<128;i++){
+
+ M68302_scc_bd_stat_ctrl (a_bd + i) = 0;
+ M68302_scc_bd_data_lgth (a_bd + i) = 0;
+ M68302_scc_bd_p_buffer (a_bd + i) = NULL;
+ }
+
+
+ sc->txBdBase = M68302imp_a_eth_bd ( 0 ); /* point to first BD */
+ sc->rxBdBase = M68302imp_a_eth_bd ( sc->txBdCount); /* point to first RX BD atfer all TX*/
+
+ /*
+ * Set up transmit buffer descriptors
+ */
+ for (i = 0 ; i < sc->txBdCount ; i++) {
+ sc->txMbuf[i] = NULL;
+ }
+ sc->txBdHead = sc->txBdTail = 0;
+ sc->txBdActiveCount = 0;
+
+ /*
+ * Clear any outstanding events
+ */
+ M68en302imp_intr_event = 0x07FF;
+ /*
+ * Set up interrupts
+ */
+
+ status = rtems_interrupt_catch (m302Enet_interrupt_handler,
+ M302_ETHER_IVECTOR,
+ &old_handler);
+ if (status != RTEMS_SUCCESSFUL)
+ rtems_panic ("Can't attach M302 ether interrupt handler: %s\r\n",
+ rtems_status_text (status));
+}
+
+/*
+ * 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
+m302Enet_retire_tx_bd (struct scc_softc *sc)
+{
+
+ rtems_unsigned16 status;
+ int i;
+ int nRetired;
+ struct mbuf *m, *n;
+ int retries = 0;
+ int saveStatus = 0;
+
+ i = sc->txBdTail;
+ nRetired = 0;
+ while ((sc->txBdActiveCount != 0)
+ && (((status = (sc->txBdBase + i)->stat_ctrl) & BUF_STAT_READY) == 0)) {
+ /*
+ * Check for errors which stop the transmitter.
+ */
+ if (status & (BUF_STAT_LATE_COLLISION |
+ BUF_STAT_RETRY_LIMIT |
+ BUF_STAT_UNDERRUN)) {
+ int j;
+
+
+ if (status & BUF_STAT_LATE_COLLISION)
+ sc->txLateCollision++;
+ if (status & BUF_STAT_RETRY_LIMIT)
+ sc->txRetryLimit++;
+ if (status & BUF_STAT_UNDERRUN)
+ sc->txUnderrun++;
+
+ /*
+ * Reenable buffer descriptors
+ */
+ j = sc->txBdTail;
+ for (;;) {
+ status = (sc->txBdBase + j)->stat_ctrl;
+ if (status & BUF_STAT_READY)
+ break;
+ (sc->txBdBase + j)->stat_ctrl = BUF_STAT_READY |
+ (status & ( BUF_STAT_WRAP |
+ BUF_STAT_INTERRUPT |
+ BUF_STAT_LAST |
+ BUF_STAT_TX_CRC));
+ if (status & BUF_STAT_LAST)
+ break;
+ if (++j == sc->txBdCount)
+ j = 0;
+ }
+
+ /*
+ * Move transmitter back to the first
+ * buffer descriptor in the frame.
+ */
+/* m360.scc1p._tbptr = m360.scc1p.tbase +
+ sc->txBdTail * sizeof (m360BufferDescriptor_t);
+*/
+ /*
+ * Restart the transmitter
+ */
+/* M360ExecuteRISC (M360_CR_OP_RESTART_TX | M360_CR_CHAN_SCC1);*/
+ continue;
+ }
+ saveStatus |= status;
+ retries += (status >> 2) & 0xF;
+ nRetired++;
+ if (status & BUF_STAT_LAST) {
+ /*
+ * A full frame has been transmitted.
+ * Free all the associated buffer descriptors.
+ */
+ if (saveStatus & BUF_STAT_DEFER)
+ sc->txDeferred++;
+ if (saveStatus & BUF_STAT_HEARTBIT)
+ sc->txHeartbeat++;
+ if (saveStatus & BUF_STAT_CARRIER_LOST)
+ sc->txLostCarrier++;
+ saveStatus = 0;
+ sc->txRetry += retries;
+ retries = 0;
+ sc->txBdActiveCount -= nRetired;
+ while (nRetired) {
+ nRetired--;
+ m = sc->txMbuf[sc->txBdTail];
+ MFREE (m, n);
+ if (++sc->txBdTail == sc->txBdCount)
+ sc->txBdTail = 0;
+ }
+ }
+ if (++i == sc->txBdCount)
+ i = 0;
+ }
+
+}
+
+/*
+ * SCC reader task
+ */
+static void
+scc_rxDaemon (void *arg)
+{
+
+ struct scc_softc *sc = (struct scc_softc *)arg;
+ struct ifnet *ifp = &sc->arpcom.ac_if;
+ struct mbuf *m;
+ rtems_unsigned16 status;
+ volatile struct m68302_scc_bd *rxBd;
+ int rxBdIndex;
+
+ /*
+ * Allocate space for incoming packets and start reception
+ */
+ for (rxBdIndex = 0 ; ;) {
+ rxBd = sc->rxBdBase + rxBdIndex;
+ MGETHDR (m, M_WAIT, MT_DATA);
+ MCLGET (m, M_WAIT);
+ m->m_pkthdr.rcvif = ifp;
+ sc->rxMbuf[rxBdIndex] = m;
+ rxBd->p_buffer = mtod (m, void *);
+
+
+ if (++rxBdIndex == sc->rxBdCount) {
+ rxBd->stat_ctrl = BUF_STAT_EMPTY | BUF_STAT_INTERRUPT | BUF_STAT_WRAP;
+ break;
+ }
+ rxBd->stat_ctrl = BUF_STAT_EMPTY | BUF_STAT_INTERRUPT;
+ }
+
+ /*
+ * Input packet handling loop
+ */
+ rxBdIndex = 0;
+ for (;;) {
+ rxBd = sc->rxBdBase + rxBdIndex;
+
+ /*
+ * Wait for packet if there's not one ready
+ */
+ if ((status = rxBd->stat_ctrl) & BUF_STAT_EMPTY) {
+ /*
+ * Clear old events
+ */
+ M68en302imp_intr_event = INTR_EVENT_BIT_RFINT;
+
+ /*
+ * 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->stat_ctrl) & BUF_STAT_EMPTY) {
+ rtems_interrupt_level level;
+ rtems_event_set events;
+
+ /*
+ * Unmask RXF (Full frame received) event
+ */
+ rtems_interrupt_disable (level);
+ M68en302imp_intr_mask |= INTR_MASK_BIT_RFIEN;
+
+ rtems_interrupt_enable (level);
+ rtems_bsdnet_event_receive (INTERRUPT_EVENT,
+ RTEMS_WAIT|RTEMS_EVENT_ANY,
+ RTEMS_NO_TIMEOUT,
+ &events);
+ }
+ }
+
+
+ /*
+ * Check that packet is valid
+ */
+ if ((status & (BUF_STAT_LAST |
+ BUF_STAT_FIRST_IN_FRAME |
+ BUF_STAT_LONG |
+ BUF_STAT_NONALIGNED |
+ BUF_STAT_SHORT |
+ BUF_STAT_CRC_ERROR |
+ BUF_STAT_OVERRUN |
+ BUF_STAT_COLLISION)) ==
+ (BUF_STAT_LAST |
+ BUF_STAT_FIRST_IN_FRAME)) {
+ /*
+ * Pass the packet up the chain.
+ * FIXME: Packet filtering hook could be done here.
+ */
+ struct ether_header *eh;
+
+ m = sc->rxMbuf[rxBdIndex];
+ m->m_len = m->m_pkthdr.len = rxBd->data_lgth -
+ sizeof(rtems_unsigned32) -
+ sizeof(struct ether_header);
+ eh = mtod (m, struct ether_header *);
+ m->m_data += sizeof(struct ether_header);
+
+ ether_input (ifp, eh, m);
+
+ /*
+ * Allocate a new mbuf
+ */
+ MGETHDR (m, M_WAIT, MT_DATA);
+ MCLGET (m, M_WAIT);
+ m->m_pkthdr.rcvif = ifp;
+ sc->rxMbuf[rxBdIndex] = m;
+ rxBd->p_buffer = mtod (m, void *);
+ }
+ else {
+ /*
+ * Something went wrong with the reception
+ */
+ if (!(status & BUF_STAT_LAST))
+ sc->rxNotLast++;
+ if (!(status & BUF_STAT_FIRST_IN_FRAME))
+ sc->rxNotFirst++;
+ if (status & BUF_STAT_LONG)
+ sc->rxGiant++;
+ if (status & BUF_STAT_NONALIGNED)
+ sc->rxNonOctet++;
+ if (status & BUF_STAT_SHORT)
+ sc->rxRunt++;
+ if (status & BUF_STAT_CRC_ERROR)
+ sc->rxBadCRC++;
+ if (status & BUF_STAT_OVERRUN)
+ sc->rxOverrun++;
+ if (status & BUF_STAT_COLLISION)
+ sc->rxCollision++;
+ }
+
+ /*
+ * Reenable the buffer descriptor
+ */
+ rxBd->stat_ctrl = (status & (BUF_STAT_WRAP | BUF_STAT_INTERRUPT)) | BUF_STAT_EMPTY;
+
+ /*
+ * Move to next buffer descriptor
+ */
+ if (++rxBdIndex == sc->rxBdCount)
+ rxBdIndex = 0;
+ }
+
+}
+
+static void
+sendpacket (struct ifnet *ifp, struct mbuf *m)
+{
+
+ struct scc_softc *sc = ifp->if_softc;
+ volatile struct m68302_scc_bd *firstTxBd, *txBd;
+ struct mbuf *l = NULL;
+ rtems_unsigned16 status;
+ int nAdded;
+ char buf[20];
+
+ /*
+ * Free up buffer descriptors
+ */
+ m302Enet_retire_tx_bd (sc);
+ /*
+ * 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.
+ */
+ status = 0;
+ nAdded = 0;
+ txBd = firstTxBd = sc->txBdBase + sc->txBdHead;
+ while (m) {
+ /*
+ * There are more mbufs in the packet than there
+ * are transmit buffer descriptors.
+ * Coalesce into a single buffer.
+ */
+ if (nAdded == sc->txBdCount) {
+ struct mbuf *nm;
+ int j;
+ char *dest;
+
+ /*
+ * Get the pointer to the first mbuf of the packet
+ */
+ if (sc->txBdTail != sc->txBdHead)
+ rtems_panic ("sendpacket coalesce");
+ m = sc->txMbuf[sc->txBdTail];
+
+ /*
+ * Rescind the buffer descriptor READY bits
+ */
+ for (j = 0 ; j < sc->txBdCount ; j++)
+ (sc->txBdBase + j)->stat_ctrl = 0;
+
+ /*
+ * Allocate an mbuf cluster
+ * Toss the packet if allocation fails
+ */
+ MGETHDR (nm, M_DONTWAIT, MT_DATA);
+ if (nm == NULL) {
+ sc->txCoalesceFailed++;
+ m_freem (m);
+
+ return;
+ }
+ MCLGET (nm, M_DONTWAIT);
+ if (nm->m_ext.ext_buf == NULL) {
+ sc->txCoalesceFailed++;
+ m_freem (m);
+ m_free (nm);
+
+ return;
+ }
+ nm->m_pkthdr = m->m_pkthdr;
+ nm->m_len = nm->m_pkthdr.len;
+
+ /*
+ * Copy data from packet chain to mbuf cluster
+ */
+ sc->txCoalesced++;
+ dest = nm->m_ext.ext_buf;
+ while (m) {
+ struct mbuf *n;
+
+ if (m->m_len) {
+ memcpy (dest, mtod(m, caddr_t), m->m_len);
+ dest += m->m_len;
+ }
+ MFREE (m, n);
+ m = n;
+ }
+
+ /*
+ * Redo the send with the new mbuf cluster
+ */
+ m = nm;
+ nAdded = 0;
+ status = 0;
+
+ continue;
+ }
+
+ /*
+ * Wait for buffer descriptor to become available.
+ */
+ if ((sc->txBdActiveCount + nAdded) == sc->txBdCount) {
+ /*
+ * Clear old events
+ */
+ M68en302imp_intr_event = INTR_EVENT_BIT_TFINT | INTR_EVENT_BIT_TXB;
+
+ /*
+ * 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.
+ * 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.
+ */
+ m302Enet_retire_tx_bd (sc);
+ while ((sc->txBdActiveCount + nAdded) == sc->txBdCount) {
+ rtems_interrupt_level level;
+ rtems_event_set events;
+
+ /*
+ * Unmask TXB (buffer transmitted) and
+ * TXE (transmitter error) events.
+ */
+ rtems_interrupt_disable (level);
+ M68en302imp_intr_mask |= INTR_MASK_BIT_TFIEN | INTR_MASK_BIT_TXIEN;
+ rtems_interrupt_enable (level);
+
+ rtems_bsdnet_event_receive (INTERRUPT_EVENT,
+ RTEMS_WAIT|RTEMS_EVENT_ANY,
+ RTEMS_NO_TIMEOUT,
+ &events);
+ m302Enet_retire_tx_bd (sc);
+ }
+ }
+
+ /*
+ * The IP fragmentation routine in ip_output
+ * can produce packet fragments with zero length.
+ */
+ if (m->m_len) {
+ /*
+ * Fill in the buffer descriptor.
+ * Don't set the READY flag in the first buffer
+ * descriptor till the whole packet has been readied.
+ */
+ txBd = sc->txBdBase + sc->txBdHead;
+ txBd->p_buffer = mtod (m, void *);
+ txBd->data_lgth = m->m_len;
+
+ sc->txMbuf[sc->txBdHead] = m;
+ status = nAdded ? BUF_STAT_READY : 0;
+ if (++sc->txBdHead == sc->txBdCount) {
+ status |= BUF_STAT_WRAP;
+ sc->txBdHead = 0;
+ }
+ txBd->stat_ctrl = status;
+ l = m;
+ m = m->m_next;
+ nAdded++;
+
+ }
+ else {
+ /*
+ * Just toss empty mbufs
+ */
+ struct mbuf *n;
+ MFREE (m, n);
+ m = n;
+ if (l != NULL)
+ l->m_next = m;
+
+ }
+ }
+ if (nAdded) {
+ /*
+ * Send the packet
+ */
+ txBd->stat_ctrl = status | BUF_STAT_LAST | BUF_STAT_TX_CRC | BUF_STAT_INTERRUPT;
+ firstTxBd->stat_ctrl |= BUF_STAT_READY;
+ sc->txBdActiveCount += nAdded;
+
+ }
+
+}
+
+/*
+ * Driver transmit daemon
+ */
+void
+scc_txDaemon (void *arg)
+{
+
+ struct scc_softc *sc = (struct scc_softc *)arg;
+ struct ifnet *ifp = &sc->arpcom.ac_if;
+ struct mbuf *m;
+ rtems_event_set events;
+
+ for (;;) {
+ /*
+ * Wait for packet
+ */
+ rtems_bsdnet_event_receive (START_TRANSMIT_EVENT, RTEMS_EVENT_ANY | RTEMS_WAIT, RTEMS_NO_TIMEOUT, &events);
+
+ /*
+ * Send packets till queue is empty
+ */
+ for (;;) {
+ /*
+ * Get the next mbuf chain to transmit.
+ */
+ IF_DEQUEUE(&ifp->if_snd, m);
+ if (!m)
+ break;
+ sendpacket (ifp, m);
+ }
+ ifp->if_flags &= ~IFF_OACTIVE;
+ }
+
+}
+
+/*
+ * Send packet (caller provides header).
+ */
+static void
+scc_start (struct ifnet *ifp)
+{
+ struct scc_softc *sc = ifp->if_softc;
+
+ rtems_event_send (sc->txDaemonTid, START_TRANSMIT_EVENT);
+ ifp->if_flags |= IFF_OACTIVE;
+}
+
+/*
+ * Initialize and start the device
+ */
+static void
+scc_init (void *arg)
+{
+ struct scc_softc *sc = arg;
+ struct ifnet *ifp = &sc->arpcom.ac_if;
+
+ if (sc->txDaemonTid == 0) {
+
+ /*
+ * Set up SCC hardware
+ */
+ m302Enet_initialize_hardware (sc);
+
+
+ sc->txDaemonTid = rtems_bsdnet_newproc ("SCtx", 4096, scc_txDaemon, sc);
+ sc->rxDaemonTid = rtems_bsdnet_newproc ("SCrx", 4096, scc_rxDaemon, sc);
+
+ }
+
+ /*
+ * Set flags appropriately
+ */
+/* if (ifp->if_flags & IFF_PROMISC)
+ m360.scc1.psmr |= 0x200;
+ else
+ m360.scc1.psmr &= ~0x200;
+*/
+ /*
+ * Tell the world that we're running.
+ */
+ ifp->if_flags |= IFF_RUNNING;
+
+ /*
+ * Enable receiver and transmitter
+ */
+ M68en302imp_ecntrl = ECNTRL_BIT_RESET | ECNTRL_BIT_ETHER_EN;
+
+}
+
+/*
+ * Stop the device
+ */
+static void
+scc_stop (struct scc_softc *sc)
+{
+
+ struct ifnet *ifp = &sc->arpcom.ac_if;
+
+ ifp->if_flags &= ~IFF_RUNNING;
+
+ /*
+ * Shut down receiver and transmitter
+ */
+ M68en302imp_ecntrl &= ~(ECNTRL_BIT_RESET | ECNTRL_BIT_ETHER_EN);
+
+}
+
+
+/*
+ * Show interface statistics
+ */
+static void
+scc_stats (struct scc_softc *sc)
+{
+ printf (" Rx Interrupts:%-8lu", sc->rxInterrupts);
+ printf (" Not First:%-8lu", sc->rxNotFirst);
+ printf (" Not Last:%-8lu\r\n", sc->rxNotLast);
+ printf (" Giant:%-8lu", sc->rxGiant);
+ printf (" Runt:%-8lu", sc->rxRunt);
+ printf (" Non-octet:%-8lu\r\n", sc->rxNonOctet);
+ printf (" Bad CRC:%-8lu", sc->rxBadCRC);
+ printf (" Overrun:%-8lu", sc->rxOverrun);
+ printf (" Collision:%-8lu\r\n", sc->rxCollision);
+/* printf (" Discarded:%-8lu\r\n", (unsigned long)m360.scc1p.un.ethernet.disfc);
+*/
+ printf (" Tx Interrupts:%-8lu", sc->txInterrupts);
+ printf (" Deferred:%-8lu", sc->txDeferred);
+ printf (" Missed Hearbeat:%-8lu\r\n", sc->txHeartbeat);
+ printf (" No Carrier:%-8lu", sc->txLostCarrier);
+ printf ("Retransmit Limit:%-8lu", sc->txRetryLimit);
+ printf (" Late Collision:%-8lu\r\n", sc->txLateCollision);
+ printf (" Underrun:%-8lu", sc->txUnderrun);
+ printf (" Raw output wait:%-8lu", sc->txRawWait);
+ printf (" Coalesced:%-8lu\r\n", sc->txCoalesced);
+ printf (" Coalesce failed:%-8lu", sc->txCoalesceFailed);
+ printf (" Retries:%-8lu\r\n", sc->txRetry);
+}
+
+/*
+ * Driver ioctl handler
+ */
+static int
+scc_ioctl (struct ifnet *ifp, int command, caddr_t data)
+{
+
+ struct scc_softc *sc = ifp->if_softc;
+ int error = 0;
+
+ switch (command) {
+ case SIOCGIFADDR:
+ case SIOCSIFADDR:
+ ether_ioctl (ifp, command, data);
+ break;
+
+ case SIOCSIFFLAGS:
+ switch (ifp->if_flags & (IFF_UP | IFF_RUNNING)) {
+ case IFF_RUNNING:
+ scc_stop (sc);
+ break;
+
+ case IFF_UP:
+ scc_init (sc);
+ break;
+
+ case IFF_UP | IFF_RUNNING:
+ scc_stop (sc);
+ scc_init (sc);
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case SIO_RTEMS_SHOW_STATS:
+ scc_stats (sc);
+ break;
+
+ /*
+ * FIXME: All sorts of multicast commands need to be added here!
+ */
+ default:
+ error = EINVAL;
+ break;
+ }
+ return error;
+
+}
+
+
+/*
+ * Attach an SCC driver to the system
+ */
+int
+rtems_ether1_driver_attach (struct rtems_bsdnet_ifconfig *config)
+{
+ struct scc_softc *sc;
+ struct ifnet *ifp;
+ int mtu;
+ int unitNumber;
+ char *unitName;
+
+ a_m68302_imp = (struct m68302_imp *)0x700000L;
+ /*
+ * Parse driver name
+ */
+ if ((unitNumber = rtems_bsdnet_parse_driver_name (config, &unitName)) < 0)
+ return 0;
+
+ /*
+ * Is driver free?
+ */
+ if ((unitNumber <= 0) || (unitNumber > NSCCDRIVER)) {
+ printf ("Bad SCC unit number.\r\n");
+ return 0;
+ }
+ sc = &scc_softc[unitNumber - 1];
+ ifp = &sc->arpcom.ac_if;
+ if (ifp->if_softc != NULL) {
+ printf ("Driver already in use.\r\n");
+ return 0;
+ }
+
+ /*
+ * Process options
+ */
+ if (config->hardware_address) {
+ memcpy (sc->arpcom.ac_enaddr, config->hardware_address, ETHER_ADDR_LEN);
+ }
+
+ if (config->mtu)
+ mtu = config->mtu;
+ else
+ mtu = ETHERMTU;
+ if (config->rbuf_count)
+ sc->rxBdCount = config->rbuf_count;
+ else
+ sc->rxBdCount = RX_BUF_COUNT;
+ if (config->xbuf_count)
+ sc->txBdCount = config->xbuf_count;
+ else
+ sc->txBdCount = TX_BUF_COUNT;
+ sc->acceptBroadcast = !config->ignore_broadcast;
+
+ /*
+ * Set up network interface values
+ */
+ ifp->if_softc = sc;
+ ifp->if_unit = unitNumber;
+ ifp->if_name = unitName;
+ ifp->if_mtu = mtu;
+ ifp->if_init = scc_init;
+ ifp->if_ioctl = scc_ioctl;
+ ifp->if_start = scc_start;
+ ifp->if_output = ether_output;
+ ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
+ if (ifp->if_snd.ifq_maxlen == 0)
+ ifp->if_snd.ifq_maxlen = ifqmaxlen;
+
+ /*
+ * Attach the interface
+ */
+ if_attach (ifp);
+ ether_ifattach (ifp);
+ return 1;
+};