summaryrefslogtreecommitdiffstats
path: root/c/src/libchip
diff options
context:
space:
mode:
authorJoel Sherrill <joel.sherrill@OARcorp.com>1999-12-03 13:42:34 +0000
committerJoel Sherrill <joel.sherrill@OARcorp.com>1999-12-03 13:42:34 +0000
commit5a8203085e5855198949dc289ba8acd3a11e68cc (patch)
tree14b02b925f9bad752aea22d008bdce86b699e34b /c/src/libchip
parentPatch rtems-rc-19991123-rc-3.diff from Ralf Corsepius (diff)
downloadrtems-5a8203085e5855198949dc289ba8acd3a11e68cc.tar.bz2
Modification from Emmanuel Raguet <raguet@crf.canon.fr> to merge the
dec21140 drivers from the i386/pc386 and powerpc/mcp750 (all Motorola PowerPC boards) and move the network driver to libchip. This driver should work on all PCI based uses of this chip.
Diffstat (limited to 'c/src/libchip')
-rw-r--r--c/src/libchip/network/README.dec21140117
-rw-r--r--c/src/libchip/network/dec21140.c904
2 files changed, 1021 insertions, 0 deletions
diff --git a/c/src/libchip/network/README.dec21140 b/c/src/libchip/network/README.dec21140
new file mode 100644
index 0000000000..516bb5fca7
--- /dev/null
+++ b/c/src/libchip/network/README.dec21140
@@ -0,0 +1,117 @@
+#
+# $Id$
+#
+
+This TULIP driver can be used on BSPs that support PCI bus.
+
+It can handle any DEC21140 based Ethernet controller.
+
+It works on big or little endian target.
+
+It has been tested with powerpc/mcp750 BSP (OnBoard Ethernet
+controller) and i386/pc386 BSP (D-Link DFE-500TX Ethernet board).
+
+
+*****************************************************************
+******** ***************
+******** tests with ttcp benchmark for DEC driver ***************
+******** optimization ***************
+******** ***************
+*****************************************************************
+
+
+LINUX -> LINUX-ix86
+
+Transmitter :
+
+ttcp-t: buflen=8192, nbuf=2048, align=16384/0, port=5001 tcp -> genesis
+ttcp-t: 16777216 bytes in 1.87 real seconds = 8775.25 KB/sec +++
+ttcp-t: 2048 I/O calls, msec/call = 0.93, calls/sec = 1096.91
+ttcp-t: 0.0user 0.9sys 0:01real 51% 0i+0d 0maxrss 0+2pf 0+0csw
+
+Receiver :
+
+ttcp-r: buflen=8192, nbuf=2048, align=16384/0, port=5001 tcp
+ttcp-r: 16777216 bytes in 1.88 real seconds = 8706.53 KB/sec +++
+ttcp-r: 10802 I/O calls, msec/call = 0.18, calls/sec = 5740.23
+ttcp-r: 0.0user 0.2sys 0:01real 13% 0i+0d 0maxrss 0+2pf 0+0csw
+
+==============================================================
+==============================================================
+==============================================================
+
+LINUX -> RTEMS-ix86 with tulip driver from pc386 bsp
+
+Transmitter :
+
+ttcp-t: buflen=8192, nbuf=2048, align=16384/0, port=5001 tcp -> neil-young-100
+ttcp-t: 16777216 bytes in 1.98 real seconds = 8294.76 KB/sec +++
+ttcp-t: 2048 I/O calls, msec/call = 0.99, calls/sec = 1036.85
+ttcp-t: 0.0user 0.1sys 0:01real 9% 0i+0d 0maxrss 0+2pf 0+0csw
+
+Receiver :
+
+ttcp-r: buflen=8192, nbuf=2048, align=16384/0, port=5001 tcp
+ttcp-r: 16777216 bytes in 2.03 real seconds = 8065.14 KB/sec +++
+ttcp-r: 3088 I/O calls, msec/call = 0.67, calls/sec = 1520.09
+ttcp-r: 0.0user 2.0sys 0:02real 100% 0i+0d 0maxrss 0+0pf 0+0csw
+
+==============================================================
+==============================================================
+==============================================================
+
+RTEMS-ix86 with tulip driver from pc386 bsp -> LINUX
+
+Transmitter :
+
+ttcp-t: buflen=8192, nbuf=2048, align=16384/0, port=5001 tcp -> 194.2.81.126
+ttcp-t: 16777216 bytes in 2.76 real seconds = 5938.77 KB/sec +++
+ttcp-t: 2048 I/O calls, msec/call = 1.38, calls/sec = 742.35
+ttcp-t: 0.0user 2.5sys 0:02real 100% 0i+0d 0maxrss 0+0pf 0+0csw
+
+Receiver :
+
+ttcp-r: buflen=8192, nbuf=2048, align=16384/0, port=5001 tcp
+ttcp-r: 16777216 bytes in 2.75 real seconds = 5948.53 KB/sec +++
+ttcp-r: 11349 I/O calls, msec/call = 0.25, calls/sec = 4120.48
+ttcp-r: 0.0user 0.1sys 0:02real 6% 0i+0d 0maxrss 0+2pf 0+0csw
+
+==============================================================
+==============================================================
+==============================================================
+
+LINUX -> RTEMS-ix86 with optimized tulip driver
+
+Transmitter :
+
+ttcp-t: buflen=8192, nbuf=2048, align=16384/0, port=5001 tcp -> neil-young-100
+ttcp-t: 16777216 bytes in 1.73 real seconds = 9470.13 KB/sec +++
+ttcp-t: 2048 I/O calls, msec/call = 0.87, calls/sec = 1183.77
+ttcp-t: 0.0user 0.1sys 0:01real 6% 0i+0d 0maxrss 0+2pf 0+0csw
+
+Receiver :
+
+ttcp-r: buflen=8192, nbuf=2048, align=16384/0, port=5001 tcp
+ttcp-r: 16777216 bytes in 1.76 real seconds = 9315.33 KB/sec +++
+ttcp-r: 4558 I/O calls, msec/call = 0.40, calls/sec = 2591.51
+ttcp-r: 0.0user 1.7sys 0:01real 100% 0i+0d 0maxrss 0+0pf 0+0csw
+
+==============================================================
+==============================================================
+==============================================================
+
+RTEMS-ix86 with optimized tulip driver -> LINUX
+
+Transmitter :
+
+ttcp-t: buflen=8192, nbuf=2048, align=16384/0, port=5001 tcp -> 194.2.81.126
+ttcp-t: 16777216 bytes in 2.09 real seconds = 7847.80 KB/sec +++
+ttcp-t: 2048 I/O calls, msec/call = 1.04, calls/sec = 980.98
+ttcp-t: 0.0user 2.0sys 0:02real 100% 0i+0d 0maxrss 0+0pf 0+0csw
+
+Receiver :
+
+ttcp-r: buflen=8192, nbuf=2048, align=16384/0, port=5001 tcp
+ttcp-r: 16777216 bytes in 2.08 real seconds = 7874.23 KB/sec +++
+ttcp-r: 11404 I/O calls, msec/call = 0.19, calls/sec = 5480.82
+ttcp-r: 0.0user 0.1sys 0:02real 8% 0i+0d 0maxrss 0+2pf 0+0csw
diff --git a/c/src/libchip/network/dec21140.c b/c/src/libchip/network/dec21140.c
new file mode 100644
index 0000000000..4b3dbd3c24
--- /dev/null
+++ b/c/src/libchip/network/dec21140.c
@@ -0,0 +1,904 @@
+/*
+ * RTEMS driver for TULIP based Ethernet Controller
+ *
+ * Copyright (C) 1999 Emmanuel Raguet. raguet@crf.canon.fr
+ *
+ * The license and distribution terms for this file may be
+ * found in found in the file LICENSE in this distribution or at
+ * http://www.OARcorp.com/rtems/license.html.
+ *
+ * $Id$
+ */
+
+#include <bsp.h>
+#if defined(i386)
+#include <pcibios.h>
+#endif
+#if defined(__PPC)
+#include <bsp/pci.h>
+#include <libcpu/byteorder.h>
+#include <libcpu/io.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <rtems/error.h>
+#include <rtems/rtems_bsdnet.h>
+
+#include <libcpu/cpu.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>
+
+#if defined(i386)
+#include <irq.h>
+#endif
+#if defined(__PPC)
+#include <bsp/irq.h>
+#endif
+
+#ifdef malloc
+#undef malloc
+#endif
+#ifdef free
+#undef free
+#endif
+
+#define DEC_DEBUG
+
+#define PCI_INVALID_VENDORDEVICEID 0xffffffff
+#define PCI_VENDOR_ID_DEC 0x1011
+#define PCI_DEVICE_ID_DEC_TULIP_FAST 0x0009
+
+#define IO_MASK 0x3
+#define MEM_MASK 0xF
+#define MASK_OFFSET 0xF
+
+/* command and status registers, 32-bit access, only if IO-ACCESS */
+#define ioCSR0 0x00 /* bus mode register */
+#define ioCSR1 0x08 /* transmit poll demand */
+#define ioCSR2 0x10 /* receive poll demand */
+#define ioCSR3 0x18 /* receive list base address */
+#define ioCSR4 0x20 /* transmit list base address */
+#define ioCSR5 0x28 /* status register */
+#define ioCSR6 0x30 /* operation mode register */
+#define ioCSR7 0x38 /* interrupt mask register */
+#define ioCSR8 0x40 /* missed frame counter */
+#define ioCSR9 0x48 /* Ethernet ROM register */
+#define ioCSR10 0x50 /* reserved */
+#define ioCSR11 0x58 /* full-duplex register */
+#define ioCSR12 0x60 /* SIA status register */
+#define ioCSR13 0x68
+#define ioCSR14 0x70
+#define ioCSR15 0x78 /* SIA general register */
+
+/* command and status registers, 32-bit access, only if MEMORY-ACCESS */
+#define memCSR0 0x00 /* bus mode register */
+#define memCSR1 0x02 /* transmit poll demand */
+#define memCSR2 0x04 /* receive poll demand */
+#define memCSR3 0x06 /* receive list base address */
+#define memCSR4 0x08 /* transmit list base address */
+#define memCSR5 0x0A /* status register */
+#define memCSR6 0x0C /* operation mode register */
+#define memCSR7 0x0E /* interrupt mask register */
+#define memCSR8 0x10 /* missed frame counter */
+#define memCSR9 0x12 /* Ethernet ROM register */
+#define memCSR10 0x14 /* reserved */
+#define memCSR11 0x16 /* full-duplex register */
+#define memCSR12 0x18 /* SIA status register */
+#define memCSR13 0x1A
+#define memCSR14 0x1C
+#define memCSR15 0x1E /* SIA general register */
+
+#define DEC_REGISTER_SIZE 0x100 /* to reserve virtual memory */
+
+#define RESET_CHIP 0x00000001
+#if defined(__PPC)
+#define CSR0_MODE 0x0030e002 /* 01b08000 */
+#else
+#define CSR0_MODE 0x0020e002 /* 01b08000 */
+#endif
+#define ROM_ADDRESS 0x00004800
+#define CSR6_INIT 0x022cc000 /* 022c0000 020c0000 */
+#define CSR6_TX 0x00002000
+#define CSR6_TXRX 0x00002002
+#define IT_SETUP 0x000100c0 /* 000100e0 */
+#define CLEAR_IT 0xFFFFFFFF
+#define NO_IT 0x00000000
+
+#define NRXBUFS 32 /* number of receive buffers */
+#define NTXBUFS 16 /* number of transmit buffers */
+
+/* message descriptor entry */
+struct MD {
+ /* used by hardware */
+ volatile unsigned32 status;
+ volatile unsigned32 counts;
+ unsigned32 buf1, buf2;
+ /* used by software */
+ volatile struct mbuf *m;
+ volatile struct MD *next;
+};
+
+/*
+ * Number of DECs supported by this driver
+ */
+#define NDECDRIVER 1
+
+/*
+ * Receive buffer size -- Allow for a full ethernet packet including CRC
+ */
+#define RBUF_SIZE 1536
+
+#define ET_MINLEN 60 /* minimum message length */
+
+/*
+ * 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
+
+#if defined(__PPC)
+#define phys_to_bus(address) ((unsigned int)(address) + PREP_PCI_DRAM_OFFSET)
+#define bus_to_phys(address) ((unsigned int)(address) - PREP_PCI_DRAM_OFFSET)
+#define CPU_CACHE_ALIGNMENT_FOR_BUFFER PPC_CACHE_ALIGNMENT
+#else
+#define phys_to_bus(address) address
+#define bus_to_phys(address) address
+#define delay_in_bus_cycles(cycle) Wait_X_ms( cycle/100 )
+#define CPU_CACHE_ALIGNMENT_FOR_BUFFER PG_SIZE
+
+inline void st_le32(volatile unsigned32 *addr, unsigned32 value)
+{
+ *(addr)=value ;
+}
+
+inline unsigned32 ld_le32(volatile unsigned32 *addr)
+{
+ return(*addr);
+}
+
+#endif
+
+#if (MCLBYTES < RBUF_SIZE)
+# error "Driver must have MCLBYTES > RBUF_SIZE"
+#endif
+
+/*
+ * Per-device data
+ */
+ struct dec21140_softc {
+
+ struct arpcom arpcom;
+
+ rtems_irq_connect_data irqInfo;
+
+ volatile struct MD *MDbase;
+ volatile unsigned char *bufferBase;
+ int acceptBroadcast;
+ rtems_id rxDaemonTid;
+ rtems_id txDaemonTid;
+
+ volatile struct MD *TxMD;
+ volatile struct MD *SentTxMD;
+ int PendingTxCount;
+ int TxSuspended;
+
+ unsigned int port;
+ volatile unsigned int *base;
+
+ /*
+ * 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 dec21140_softc dec21140_softc[NDECDRIVER];
+
+/*
+ * DEC21140 interrupt handler
+ */
+static rtems_isr
+dec21140Enet_interrupt_handler (rtems_vector_number v)
+{
+ volatile unsigned32 *tbase;
+ unsigned32 status;
+ struct dec21140_softc *sc;
+
+ sc = &dec21140_softc[0];
+ tbase = (unsigned32 *)(sc->base) ;
+
+ /*
+ * Read status
+ */
+ status = ld_le32(tbase+memCSR5);
+ st_le32((tbase+memCSR5), status); /* clear the bits we've read */
+
+ /*
+ * Frame received?
+ */
+ if (status & 0x000000c0){
+ sc->rxInterrupts++;
+ rtems_event_send (sc->rxDaemonTid, INTERRUPT_EVENT);
+ }
+}
+
+static void nopOn(const rtems_irq_connect_data* notUsed)
+{
+ /*
+ * code should be moved from dec21140Enet_initialize_hardware
+ * to this location
+ */
+}
+
+static int dec21140IsOn(const rtems_irq_connect_data* irq)
+{
+ return BSP_irq_enabled_at_i8259s (irq->name);
+}
+
+
+/*
+ * This routine reads a word (16 bits) from the serial EEPROM.
+ */
+/* EEPROM_Ctrl bits. */
+#define EE_SHIFT_CLK 0x02 /* EEPROM shift clock. */
+#define EE_CS 0x01 /* EEPROM chip select. */
+#define EE_DATA_WRITE 0x04 /* EEPROM chip data in. */
+#define EE_WRITE_0 0x01
+#define EE_WRITE_1 0x05
+#define EE_DATA_READ 0x08 /* EEPROM chip data out. */
+#define EE_ENB (0x4800 | EE_CS)
+
+/* The EEPROM commands include the alway-set leading bit. */
+#define EE_WRITE_CMD (5 << 6)
+#define EE_READ_CMD (6 << 6)
+#define EE_ERASE_CMD (7 << 6)
+
+static int eeget16(volatile unsigned int *ioaddr, int location)
+{
+ int i;
+ unsigned short retval = 0;
+ int read_cmd = location | EE_READ_CMD;
+
+ st_le32(ioaddr, EE_ENB & ~EE_CS);
+ st_le32(ioaddr, EE_ENB);
+
+ /* Shift the read command bits out. */
+ for (i = 10; i >= 0; i--) {
+ short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0;
+ st_le32(ioaddr, EE_ENB | dataval);
+ delay_in_bus_cycles(200);
+ st_le32(ioaddr, EE_ENB | dataval | EE_SHIFT_CLK);
+ delay_in_bus_cycles(200);
+ st_le32(ioaddr, EE_ENB | dataval); /* Finish EEPROM a clock tick. */
+ delay_in_bus_cycles(200);
+ }
+ st_le32(ioaddr, EE_ENB);
+
+ for (i = 16; i > 0; i--) {
+ st_le32(ioaddr, EE_ENB | EE_SHIFT_CLK);
+ delay_in_bus_cycles(200);
+ retval = (retval << 1) | ((ld_le32(ioaddr) & EE_DATA_READ) ? 1 : 0);
+ st_le32(ioaddr, EE_ENB);
+ delay_in_bus_cycles(200);
+ }
+
+ /* Terminate the EEPROM access. */
+ st_le32(ioaddr, EE_ENB & ~EE_CS);
+ return ( ((retval<<8)&0xff00) | ((retval>>8)&0xff) );
+}
+
+/*
+ * Initialize the ethernet hardware
+ */
+static void
+dec21140Enet_initialize_hardware (struct dec21140_softc *sc)
+{
+ rtems_status_code st;
+ volatile unsigned int *tbase;
+ union {char c[64]; unsigned short s[32];} rombuf;
+ int i;
+ volatile unsigned char *cp, *setup_frm, *eaddrs;
+ volatile unsigned char *buffer;
+ volatile struct MD *rmd;
+
+ tbase = sc->base;
+
+ /*
+ * WARNING : First write in CSR6
+ * Then Reset the chip ( 1 in CSR0)
+ */
+ st_le32( (tbase+memCSR6), CSR6_INIT);
+ st_le32( (tbase+memCSR0), RESET_CHIP);
+ delay_in_bus_cycles(200);
+
+ /*
+ * Init CSR0
+ */
+ st_le32( (tbase+memCSR0), CSR0_MODE);
+
+ /* csr12_val = ld_le32( (tbase+memCSR8) );*/
+
+ for (i=0; i<32; i++){
+ rombuf.s[i] = eeget16(tbase+memCSR9, i);
+ }
+ memcpy (sc->arpcom.ac_enaddr, rombuf.c+20, ETHER_ADDR_LEN);
+
+#ifdef DEC_DEBUG
+ printk("DC21140 %x:%x:%x:%x:%x:%x IRQ %d IO %x M %x .........\n",
+ sc->arpcom.ac_enaddr[0], sc->arpcom.ac_enaddr[1],
+ sc->arpcom.ac_enaddr[2], sc->arpcom.ac_enaddr[3],
+ sc->arpcom.ac_enaddr[4], sc->arpcom.ac_enaddr[5],
+ sc->irqInfo.name, sc->port, (unsigned) sc->base);
+#endif
+
+ /*
+ * Init RX ring
+ */
+ cp = (volatile unsigned char *)malloc(((NRXBUFS+NTXBUFS)*sizeof(struct MD))
+ + (NTXBUFS*RBUF_SIZE)
+ + CPU_CACHE_ALIGNMENT_FOR_BUFFER);
+ sc->bufferBase = cp;
+ cp += (CPU_CACHE_ALIGNMENT_FOR_BUFFER - (int)cp)
+ & (CPU_CACHE_ALIGNMENT_FOR_BUFFER - 1);
+#if defined(__i386)
+#ifdef PCI_BRIDGE_DOES_NOT_ENSURE_CACHE_COHERENCY_FOR_DMA
+ if (_CPU_is_paging_enabled())
+ _CPU_change_memory_mapping_attribute
+ (NULL, cp,
+ ((NRXBUFS+NTXBUFS)*sizeof(struct MD))
+ + (NTXBUFS*RBUF_SIZE),
+ PTE_CACHE_DISABLE | PTE_WRITABLE);
+#endif
+#endif
+ rmd = (volatile struct MD*)cp;
+ sc->MDbase = rmd;
+ buffer = cp + ((NRXBUFS+NTXBUFS)*sizeof(struct MD));
+ st_le32( (tbase+memCSR3), (long)(phys_to_bus((long)(sc->MDbase))));
+ for (i=0 ; i<NRXBUFS; i++){
+ struct mbuf *m;
+
+ /* allocate an mbuf for each receive descriptor */
+ MGETHDR (m, M_WAIT, MT_DATA);
+ MCLGET (m, M_WAIT);
+ m->m_pkthdr.rcvif = &sc->arpcom.ac_if;
+ rmd->m = m;
+
+ rmd->buf2 = phys_to_bus(rmd+1);
+ rmd->buf1 = phys_to_bus(mtod(m, void *));
+ rmd->counts = 0xfdc00000 | (RBUF_SIZE);
+ rmd->status = 0x80000000;
+ rmd->next = rmd + 1;
+ rmd++;
+ }
+ /*
+ * mark last RX buffer.
+ */
+ sc->MDbase [NRXBUFS-1].counts = 0xfec00000 | (RBUF_SIZE);
+ sc->MDbase [NRXBUFS-1].next = sc->MDbase;
+
+ /*
+ * Init TX ring
+ */
+ st_le32( (tbase+memCSR4), (long)(phys_to_bus((long)(rmd))) );
+ for (i=0 ; i<NTXBUFS; i++){
+ (rmd+i)->buf2 = phys_to_bus(rmd+i+1);
+ (rmd+i)->buf1 = phys_to_bus(buffer + (i*RBUF_SIZE));
+ (rmd+i)->counts = 0x01000000;
+ (rmd+i)->status = 0x0;
+ (rmd+i)->next = rmd+i+1;
+ (rmd+i)->m = 0;
+ }
+
+ /*
+ * mark last TX buffer.
+ */
+ (rmd+NTXBUFS-1)->buf2 = phys_to_bus(rmd);
+ (rmd+NTXBUFS-1)->next = rmd;
+
+ /*
+ * Set up interrupts
+ */
+ sc->irqInfo.hdl = (rtems_irq_hdl)dec21140Enet_interrupt_handler;
+ sc->irqInfo.on = nopOn;
+ sc->irqInfo.off = nopOn;
+ sc->irqInfo.isOn = dec21140IsOn;
+ st = BSP_install_rtems_irq_handler (&sc->irqInfo);
+ if (!st)
+ rtems_panic ("Can't attach DEC21140 interrupt handler for irq %d\n",
+ sc->irqInfo.name);
+
+ st_le32( (tbase+memCSR7), NO_IT);
+
+ /*
+ * Build setup frame
+ */
+ setup_frm = (volatile unsigned char *)(bus_to_phys(rmd->buf1));
+ eaddrs = (char *)(sc->arpcom.ac_enaddr);
+ /* Fill the buffer with our physical address. */
+ for (i = 1; i < 16; i++) {
+ *setup_frm++ = eaddrs[0];
+ *setup_frm++ = eaddrs[1];
+ *setup_frm++ = eaddrs[0];
+ *setup_frm++ = eaddrs[1];
+ *setup_frm++ = eaddrs[2];
+ *setup_frm++ = eaddrs[3];
+ *setup_frm++ = eaddrs[2];
+ *setup_frm++ = eaddrs[3];
+ *setup_frm++ = eaddrs[4];
+ *setup_frm++ = eaddrs[5];
+ *setup_frm++ = eaddrs[4];
+ *setup_frm++ = eaddrs[5];
+ }
+ /* Add the broadcast address when doing perfect filtering */
+ memset((void*) setup_frm, 0xff, 12);
+ rmd->counts = 0x09000000 | 192 ;
+ rmd->status = 0x80000000;
+ st_le32( (tbase+memCSR6), CSR6_INIT | CSR6_TX);
+ st_le32( (tbase+memCSR1), 1);
+ while (rmd->status != 0x7fffffff);
+ rmd->counts = 0x01000000;
+ sc->TxMD = rmd+1;
+
+ /*
+ * Enable RX and TX
+ */
+ st_le32( (tbase+memCSR5), IT_SETUP);
+ st_le32( (tbase+memCSR7), IT_SETUP);
+ st_le32( (unsigned int*)(tbase+memCSR6), CSR6_INIT | CSR6_TXRX);
+
+}
+
+static void
+dec21140_rxDaemon (void *arg)
+{
+ volatile unsigned int *tbase;
+ struct ether_header *eh;
+ struct dec21140_softc *dp = (struct dec21140_softc *)&dec21140_softc[0];
+ struct ifnet *ifp = &dp->arpcom.ac_if;
+ struct mbuf *m;
+ volatile struct MD *rmd;
+ unsigned int len;
+ rtems_event_set events;
+
+ tbase = dec21140_softc[0].base ;
+ rmd = dec21140_softc[0].MDbase;
+
+ for (;;){
+
+ rtems_bsdnet_event_receive (INTERRUPT_EVENT,
+ RTEMS_WAIT|RTEMS_EVENT_ANY,
+ RTEMS_NO_TIMEOUT,
+ &events);
+
+ while((rmd->status & 0x80000000) == 0){
+ /* pass on the packet in the mbuf */
+ len = (rmd->status >> 16) & 0x7ff;
+ m = (struct mbuf *)(rmd->m);
+ m->m_len = m->m_pkthdr.len = len - sizeof(struct ether_header);
+ eh = mtod (m, struct ether_header *);
+ m->m_data += sizeof(struct ether_header);
+ ether_input (ifp, eh, m);
+
+ /* get a new mbuf for the 21140 */
+ MGETHDR (m, M_WAIT, MT_DATA);
+ MCLGET (m, M_WAIT);
+ m->m_pkthdr.rcvif = ifp;
+ rmd->m = m;
+ rmd->buf1 = phys_to_bus(mtod(m, void *));
+
+ rmd->status = 0x80000000;
+
+ rmd=rmd->next;
+ }
+ }
+}
+
+static void
+sendpacket (struct ifnet *ifp, struct mbuf *m)
+{
+ struct dec21140_softc *dp = ifp->if_softc;
+ volatile struct MD *tmd;
+ volatile unsigned char *temp;
+ struct mbuf *n;
+ unsigned int len;
+ volatile unsigned int *tbase;
+
+ tbase = dp->base;
+ /*
+ * Waiting for Transmitter ready
+ */
+ tmd = dec21140_softc[0].TxMD;
+ n = m;
+
+ while ((tmd->status & 0x80000000) != 0){
+ tmd=tmd->next;
+ }
+
+ len = 0;
+ temp = (volatile unsigned char *)(bus_to_phys(tmd->buf1));
+
+ for (;;){
+ len += m->m_len;
+ memcpy((void*) temp, (char *)m->m_data, m->m_len);
+ temp += m->m_len ;
+ if ((m = m->m_next) == NULL)
+ break;
+ }
+
+ if (len < ET_MINLEN) len = ET_MINLEN;
+ tmd->counts = 0xe1000000 | (len & 0x7ff);
+ tmd->status = 0x80000000;
+
+ st_le32( (tbase+memCSR1), 0x1);
+
+ m_freem(n);
+ dec21140_softc[0].TxMD = tmd->next;
+}
+
+/*
+ * Driver transmit daemon
+ */
+void
+dec21140_txDaemon (void *arg)
+{
+ struct dec21140_softc *sc = (struct dec21140_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;
+ }
+}
+
+
+static void
+dec21140_start (struct ifnet *ifp)
+{
+ struct dec21140_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
+dec21140_init (void *arg)
+{
+ struct dec21140_softc *sc = arg;
+ struct ifnet *ifp = &sc->arpcom.ac_if;
+
+ if (sc->txDaemonTid == 0) {
+
+ /*
+ * Set up DEC21140 hardware
+ */
+ dec21140Enet_initialize_hardware (sc);
+
+ /*
+ * Start driver tasks
+ */
+ sc->rxDaemonTid = rtems_bsdnet_newproc ("DCrx", 4096,
+ dec21140_rxDaemon, sc);
+ sc->txDaemonTid = rtems_bsdnet_newproc ("DCtx", 4096,
+ dec21140_txDaemon, sc);
+ }
+
+ /*
+ * Tell the world that we're running.
+ */
+ ifp->if_flags |= IFF_RUNNING;
+
+}
+
+/*
+ * Stop the device
+ */
+static void
+dec21140_stop (struct dec21140_softc *sc)
+{
+ volatile unsigned int *tbase;
+ struct ifnet *ifp = &sc->arpcom.ac_if;
+
+ ifp->if_flags &= ~IFF_RUNNING;
+
+ /*
+ * Stop the transmitter
+ */
+ tbase=dec21140_softc[0].base ;
+ st_le32( (tbase+memCSR7), NO_IT);
+ st_le32( (tbase+memCSR6), CSR6_INIT);
+ free((void*)sc->bufferBase);
+}
+
+
+/*
+ * Show interface statistics
+ */
+static void
+dec21140_stats (struct dec21140_softc *sc)
+{
+ printf (" Rx Interrupts:%-8lu", sc->rxInterrupts);
+ printf (" Not First:%-8lu", sc->rxNotFirst);
+ printf (" Not Last:%-8lu\n", sc->rxNotLast);
+ printf (" Giant:%-8lu", sc->rxGiant);
+ printf (" Runt:%-8lu", sc->rxRunt);
+ printf (" Non-octet:%-8lu\n", sc->rxNonOctet);
+ printf (" Bad CRC:%-8lu", sc->rxBadCRC);
+ printf (" Overrun:%-8lu", sc->rxOverrun);
+ printf (" Collision:%-8lu\n", sc->rxCollision);
+
+ printf (" Tx Interrupts:%-8lu", sc->txInterrupts);
+ printf (" Deferred:%-8lu", sc->txDeferred);
+ printf (" Missed Hearbeat:%-8lu\n", sc->txHeartbeat);
+ printf (" No Carrier:%-8lu", sc->txLostCarrier);
+ printf ("Retransmit Limit:%-8lu", sc->txRetryLimit);
+ printf (" Late Collision:%-8lu\n", sc->txLateCollision);
+ printf (" Underrun:%-8lu", sc->txUnderrun);
+ printf (" Raw output wait:%-8lu\n", sc->txRawWait);
+}
+
+/*
+ * Driver ioctl handler
+ */
+static int
+dec21140_ioctl (struct ifnet *ifp, int command, caddr_t data)
+{
+ struct dec21140_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:
+ dec21140_stop (sc);
+ break;
+
+ case IFF_UP:
+ dec21140_init (sc);
+ break;
+
+ case IFF_UP | IFF_RUNNING:
+ dec21140_stop (sc);
+ dec21140_init (sc);
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case SIO_RTEMS_SHOW_STATS:
+ dec21140_stats (sc);
+ break;
+
+ /*
+ * FIXME: All sorts of multicast commands need to be added here!
+ */
+ default:
+ error = EINVAL;
+ break;
+ }
+
+ return error;
+}
+
+/*
+ * Attach an DEC21140 driver to the system
+ */
+int
+rtems_dec21140_driver_attach (struct rtems_bsdnet_ifconfig *config)
+{
+ struct dec21140_softc *sc;
+ struct ifnet *ifp;
+ int mtu;
+ int i;
+
+ /*
+ * First, find a DEC board
+ */
+#if defined(__i386)
+ int signature;
+ int value;
+ char interrupt;
+ int diag;
+
+ if (pcib_init() == PCIB_ERR_NOTPRESENT)
+ rtems_panic("PCI BIOS not found !!");
+
+ /*
+ * First, find a DEC board
+ */
+ if ((diag = pcib_find_by_devid(PCI_VENDOR_ID_DEC,
+ PCI_DEVICE_ID_DEC_TULIP_FAST,
+ 0,
+ &signature)) != PCIB_ERR_SUCCESS)
+ rtems_panic("DEC PCI board not found !! (%d)\n", diag);
+ else {
+ printk("DEC PCI Device found\n");
+ }
+#endif
+#if defined(__PPC)
+ unsigned char ucSlotNumber, ucFnNumber;
+ unsigned int ulDeviceID, lvalue, tmp;
+ unsigned char cvalue;
+
+ for(ucSlotNumber=0;ucSlotNumber<PCI_MAX_DEVICES;ucSlotNumber++) {
+ for(ucFnNumber=0;ucFnNumber<PCI_MAX_FUNCTIONS;ucFnNumber++) {
+ (void)pci_read_config_dword(0,
+ ucSlotNumber,
+ ucFnNumber,
+ PCI_VENDOR_ID,
+ &ulDeviceID);
+ if(ulDeviceID==PCI_INVALID_VENDORDEVICEID) {
+ /*
+ * This slot is empty
+ */
+ continue;
+ }
+ if (ulDeviceID == ((PCI_DEVICE_ID_DEC_TULIP_FAST<<16) + PCI_VENDOR_ID_DEC))
+ break;
+ }
+ if (ulDeviceID == ((PCI_DEVICE_ID_DEC_TULIP_FAST<<16) + PCI_VENDOR_ID_DEC)){
+ printk("DEC Adapter found !!\n");
+ break;
+ }
+ }
+
+ if(ulDeviceID==PCI_INVALID_VENDORDEVICEID)
+ rtems_panic("DEC PCI board not found !!\n");
+#endif
+ /*
+ * Find a free driver
+ */
+ for (i = 0 ; i < NDECDRIVER ; i++) {
+ sc = &dec21140_softc[i];
+ ifp = &sc->arpcom.ac_if;
+ if (ifp->if_softc == NULL)
+ break;
+ }
+ if (i >= NDECDRIVER) {
+ printk ("Too many DEC drivers.\n");
+ return 0;
+ }
+
+ /*
+ * Process options
+ */
+#if defined(__i386)
+ pcib_conf_read32(signature, 16, &value);
+ sc->port = value & ~IO_MASK;
+
+ pcib_conf_read32(signature, 20, &value);
+ if (_CPU_is_paging_enabled())
+ _CPU_map_phys_address(&(sc->base),
+ (void *)(value & ~MEM_MASK),
+ DEC_REGISTER_SIZE ,
+ PTE_CACHE_DISABLE | PTE_WRITABLE);
+ else
+ sc->base = (unsigned int *)(value & ~MEM_MASK);
+
+ pcib_conf_read8(signature, 60, &interrupt);
+ sc->irqInfo.name = (rtems_irq_symbolic_name)interrupt;
+#endif
+#if defined(__PPC)
+ (void)pci_read_config_dword(0,
+ ucSlotNumber,
+ ucFnNumber,
+ PCI_BASE_ADDRESS_0,
+ &lvalue);
+
+ sc->port = lvalue & (unsigned int)(~IO_MASK);
+
+ (void)pci_read_config_dword(0,
+ ucSlotNumber,
+ ucFnNumber,
+ PCI_BASE_ADDRESS_1 ,
+ &lvalue);
+
+
+ tmp = (unsigned int)(lvalue & (unsigned int)(~MEM_MASK))
+ + (unsigned int)PREP_ISA_MEM_BASE;
+ sc->base = (unsigned int *)(tmp);
+
+ (void)pci_read_config_byte(0,
+ ucSlotNumber,
+ ucFnNumber,
+ PCI_INTERRUPT_LINE,
+ &cvalue);
+ sc->irqInfo.name = (rtems_irq_symbolic_name)cvalue;
+#endif
+ if (config->hardware_address) {
+ memcpy (sc->arpcom.ac_enaddr, config->hardware_address,
+ ETHER_ADDR_LEN);
+ }
+ else {
+ memset (sc->arpcom.ac_enaddr, 0x08,ETHER_ADDR_LEN);
+ }
+ if (config->mtu)
+ mtu = config->mtu;
+ else
+ mtu = ETHERMTU;
+
+ sc->acceptBroadcast = !config->ignore_broadcast;
+
+ /*
+ * Set up network interface values
+ */
+ ifp->if_softc = sc;
+ ifp->if_unit = i + 1;
+ ifp->if_name = "dc";
+ ifp->if_mtu = mtu;
+ ifp->if_init = dec21140_init;
+ ifp->if_ioctl = dec21140_ioctl;
+ ifp->if_start = dec21140_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;
+};
+