summaryrefslogtreecommitdiffstats
path: root/c/src/libchip
diff options
context:
space:
mode:
authorJoel Sherrill <joel.sherrill@OARcorp.com>2003-06-13 17:43:11 +0000
committerJoel Sherrill <joel.sherrill@OARcorp.com>2003-06-13 17:43:11 +0000
commit01b6ca963c9be8447e7e0b9c5f0fe3c1b443bfad (patch)
tree8a36cd6c426360a9e79652d617d787b89c210c62 /c/src/libchip
parent2003-06-13 Greg Menke <gregory.menke@gsfc.nasa.gov> (diff)
downloadrtems-01b6ca963c9be8447e7e0b9c5f0fe3c1b443bfad.tar.bz2
2003-06-13 Greg Menke <gregory.menke@gsfc.nasa.gov>
PR 405/bsps PR 393/networking * network/dec21140.c: Fix leak also known as PR393. * network/elnk.c, network/if_media.h, network/mii.h: New files. * network/Makefile.am: Reflect new files.
Diffstat (limited to 'c/src/libchip')
-rw-r--r--c/src/libchip/ChangeLog8
-rw-r--r--c/src/libchip/network/Makefile.am4
-rw-r--r--c/src/libchip/network/dec21140.c1478
-rw-r--r--c/src/libchip/network/elnk.c3267
-rw-r--r--c/src/libchip/network/if_media.h436
-rw-r--r--c/src/libchip/network/mii.h206
6 files changed, 4818 insertions, 581 deletions
diff --git a/c/src/libchip/ChangeLog b/c/src/libchip/ChangeLog
index c9cd91d112..1a3c9dc4a4 100644
--- a/c/src/libchip/ChangeLog
+++ b/c/src/libchip/ChangeLog
@@ -6,6 +6,14 @@
* network/elnk.c, network/if_media.h, network/mii.h: New files.
* network/Makefile.am: Reflect new files.
+2003-06-13 Greg Menke <gregory.menke@gsfc.nasa.gov>
+
+ PR 405/bsps
+ PR 393/networking
+ * network/dec21140.c: Fix leak also known as PR393.
+ * network/elnk.c, network/if_media.h, network/mii.h: New files.
+ * network/Makefile.am: Reflect new files.
+
2003-04-15 Joel Sherrill <joel@OARcorp.com>
PR 387/rtems_misc
diff --git a/c/src/libchip/network/Makefile.am b/c/src/libchip/network/Makefile.am
index fd8aba74b2..926e4bba28 100644
--- a/c/src/libchip/network/Makefile.am
+++ b/c/src/libchip/network/Makefile.am
@@ -8,10 +8,10 @@ include_libchipdir = $(includedir)/libchip
LIBNAME = libnetchip
LIB = $(ARCH)/$(LIBNAME).a
-C_FILES = cs8900.c dec21140.c i82586.c sonic.c if_fxp.c
+C_FILES = cs8900.c dec21140.c i82586.c sonic.c if_fxp.c elnk.c
OBJS = $(C_FILES:%.c=$(ARCH)/%.$(OBJEXT))
-include_libchip_HEADERS = cs8900.h i82586var.h if_fxpvar.h sonic.h
+include_libchip_HEADERS = cs8900.h i82586var.h if_fxpvar.h sonic.h if_media.h mii.h
include $(top_srcdir)/../../../automake/compile.am
include $(top_srcdir)/../../../automake/lib.am
diff --git a/c/src/libchip/network/dec21140.c b/c/src/libchip/network/dec21140.c
index 7ec952f70e..fd37cfd2e1 100644
--- a/c/src/libchip/network/dec21140.c
+++ b/c/src/libchip/network/dec21140.c
@@ -25,6 +25,18 @@
* look for the 21140 first. If the 21140 is not found the driver will
* look for the 21143.
* ------------------------------------------------------------------------
+ *
+ * 2003-03-13, Greg Menke, gregory.menke@gsfc.nasa.gov
+ *
+ * Added support for up to 8 units (which is an arbitrary limit now),
+ * consolidating their support into a single pair of rx/tx daemons and a
+ * single ISR for all vectors servicing the DEC units. The driver now
+ * simply uses whatever INTERRUPT_LINE the card supplies, requiring it
+ * be configured either by the boot monitor or bspstart() hackery.
+ * Tested on a MCP750 PPC based system with 2 DEC21140 boards.
+ *
+ * Also fixed a few bugs related to board configuration, start and stop.
+ *
*/
#include <rtems.h>
@@ -39,7 +51,7 @@
#define DEC21140_SUPPORTED
#endif
-#if defined(__PPC__) && (defined(mpc604) || defined(mpc750))
+#if defined(__PPC__) && (defined(mpc604) || defined(mpc750) || defined(mpc603e))
#define DEC21140_SUPPORTED
#endif
@@ -57,6 +69,7 @@
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
+#include <string.h>
#include <rtems/error.h>
#include <rtems/bspIo.h>
#include <rtems/rtems_bsdnet.h>
@@ -88,9 +101,11 @@
/* note: the 21143 isn't really a DEC, it's an Intel chip */
#define PCI_INVALID_VENDORDEVICEID 0xffffffff
-#define PCI_VENDOR_ID_DEC 0x1011
-#define PCI_DEVICE_ID_DEC_21140 0x0009
-#define PCI_DEVICE_ID_DEC_21143 0x0019
+#define PCI_VENDOR_ID_DEC 0x1011
+#define PCI_DEVICE_ID_DEC_21140 0x0009
+#define PCI_DEVICE_ID_DEC_21143 0x0019
+
+#define DRIVER_PREFIX "dc"
#define IO_MASK 0x3
#define MEM_MASK 0xF
@@ -133,6 +148,9 @@
#define DEC_REGISTER_SIZE 0x100 /* to reserve virtual memory */
+
+
+
#define RESET_CHIP 0x00000001
#if defined(__PPC)
#define CSR0_MODE 0x0030e002 /* 01b08000 */
@@ -147,43 +165,72 @@
#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;
+ volatile unsigned32 buf1, buf2;
/* used by software */
volatile struct mbuf *m;
volatile struct MD *next;
-};
+} __attribute__ ((packed));
+
+
+
+
+/*
+** These buffers allocated for each unit, so ensure
+**
+** rtems_bsdnet_config.mbuf_bytecount
+** rtems_bsdnet_config.mbuf_cluster_bytecount
+**
+** are adequately sized to provide enough clusters and mbufs for all the
+** units. The default bsdnet configuration is sufficient for one dec
+** unit, but will be nearing exhaustion with 2 or more. Although a
+** little expensive in memory, the following configuration should
+** eliminate all mbuf/cluster issues;
+**
+** rtems_bsdnet_config.mbuf_bytecount = 128*1024;
+** rtems_bsdnet_config.mbuf_cluster_bytecount = 256*1024;
+*/
+
+#define NRXBUFS 16 /* number of receive buffers */
+#define NTXBUFS 16 /* number of transmit buffers */
+
/*
- * Number of DECs supported by this driver
+ * Number of DEC boards supported by this driver
*/
-#define NDECDRIVER 1
+#define NDECDRIVER 8
+
/*
* Receive buffer size -- Allow for a full ethernet packet including CRC
*/
#define RBUF_SIZE 1536
-#define ET_MINLEN 60 /* minimum message length */
+#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
+** Events, one per unit. The event is sent to the rx task from the isr
+** or from the stack to the tx task whenever a unit needs service. The
+** rx/tx tasks identify the requesting unit(s) by their particular
+** events so only requesting units are serviced.
+*/
+
+static rtems_event_set unit_signals[NDECDRIVER]= { RTEMS_EVENT_1,
+ RTEMS_EVENT_2,
+ RTEMS_EVENT_3,
+ RTEMS_EVENT_4,
+ RTEMS_EVENT_5,
+ RTEMS_EVENT_6,
+ RTEMS_EVENT_7,
+ RTEMS_EVENT_8 };
+
#if defined(__PPC)
#define phys_to_bus(address) ((unsigned int)((address)) + PCI_DRAM_OFFSET)
@@ -212,94 +259,75 @@ inline unsigned32 ld_le32(volatile unsigned32 *addr)
# error "Driver must have MCLBYTES > RBUF_SIZE"
#endif
+
+
+
+
/*
* Per-device data
*/
- struct dec21140_softc {
+struct dec21140_softc {
- struct arpcom arpcom;
+ struct arpcom arpcom;
- rtems_irq_connect_data irqInfo;
+ 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;
+ rtems_event_set ioevent;
- unsigned int port;
- volatile unsigned int *base;
+ volatile struct MD *MDbase;
+ volatile struct MD *nextRxMD;
+ volatile unsigned char *bufferBase;
+ int acceptBroadcast;
- /*
- * 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;
+ 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;
+ 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];
+static rtems_id rxDaemonTid;
+static rtems_id txDaemonTid;
+
+
+
+
+
+
+
+
+
+
+
+
-/*
- * 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);
-}
/*
@@ -321,352 +349,523 @@ static int dec21140IsOn(const rtems_irq_connect_data* irq)
static int eeget16(volatile unsigned int *ioaddr, int location)
{
- int i;
- unsigned short retval = 0;
- int read_cmd = location | EE_READ_CMD;
+ 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);
+ 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);
- rtems_bsp_delay_in_bus_cycles(200);
- st_le32(ioaddr, EE_ENB | dataval | EE_SHIFT_CLK);
- rtems_bsp_delay_in_bus_cycles(200);
- st_le32(ioaddr, EE_ENB | dataval); /* Finish EEPROM a clock tick. */
- rtems_bsp_delay_in_bus_cycles(200);
- }
- 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);
+ rtems_bsp_delay_in_bus_cycles(200);
+ st_le32(ioaddr, EE_ENB | dataval | EE_SHIFT_CLK);
+ rtems_bsp_delay_in_bus_cycles(200);
+ st_le32(ioaddr, EE_ENB | dataval); /* Finish EEPROM a clock tick. */
+ rtems_bsp_delay_in_bus_cycles(200);
+ }
+ st_le32(ioaddr, EE_ENB);
- for (i = 16; i > 0; i--) {
- st_le32(ioaddr, EE_ENB | EE_SHIFT_CLK);
- rtems_bsp_delay_in_bus_cycles(200);
- retval = (retval << 1) | ((ld_le32(ioaddr) & EE_DATA_READ) ? 1 : 0);
- st_le32(ioaddr, EE_ENB);
- rtems_bsp_delay_in_bus_cycles(200);
- }
-
- /* Terminate the EEPROM access. */
- st_le32(ioaddr, EE_ENB & ~EE_CS);
- return ( ((retval<<8)&0xff00) | ((retval>>8)&0xff) );
+ for (i = 16; i > 0; i--) {
+ st_le32(ioaddr, EE_ENB | EE_SHIFT_CLK);
+ rtems_bsp_delay_in_bus_cycles(200);
+ retval = (retval << 1) | ((ld_le32(ioaddr) & EE_DATA_READ) ? 1 : 0);
+ st_le32(ioaddr, EE_ENB);
+ rtems_bsp_delay_in_bus_cycles(200);
+ }
+
+ /* Terminate the EEPROM access. */
+ st_le32(ioaddr, EE_ENB & ~EE_CS);
+ return ( ((retval<<8)&0xff00) | ((retval>>8)&0xff) );
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+static void no_op(const rtems_irq_connect_data* irq)
+{
+ return;
+}
+
+
+
+
+static int dec21140IsOn(const rtems_irq_connect_data* irq)
+{
+ return BSP_irq_enabled_at_i8259s (irq->name);
}
+
+
+
/*
- * Initialize the ethernet hardware
+ * DEC21140 interrupt handler
*/
-static void
-dec21140Enet_initialize_hardware (struct dec21140_softc *sc)
+static rtems_isr
+dec21140Enet_interrupt_handler ( struct dec21140_softc *sc )
{
- rtems_status_code st;
- volatile unsigned int *tbase;
- int i;
- volatile unsigned char *cp, *setup_frm, *eaddrs;
- volatile unsigned char *buffer;
- volatile struct MD *rmd;
+ volatile unsigned32 *tbase;
+ unsigned32 status;
+
+ tbase = (unsigned32 *)(sc->base);
+
+ /*
+ * Read status
+ */
+ status = ld_le32(tbase+memCSR5);
+ st_le32((tbase+memCSR5), status);
+
+ /*
+ * Frame received?
+ */
+ if( status & 0x000000c0 )
+ {
+ sc->rxInterrupts++;
+ rtems_event_send(rxDaemonTid, sc->ioevent);
+ }
+}
- 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);
- rtems_bsp_delay_in_bus_cycles(200);
- /*
- * Init CSR0
+static rtems_isr
+dec21140Enet_interrupt_handler_entry()
+{
+ int i;
+
+ /*
+ ** Check all the initialized dec units for interrupt service
*/
- st_le32( (tbase+memCSR0), CSR0_MODE);
+
+ for(i=0; i< NDECDRIVER; i++ )
+ {
+ if( dec21140_softc[i].base )
+ dec21140Enet_interrupt_handler( &dec21140_softc[i] );
+ }
+}
+
+
+
+
+
+
+
+
+
+
+/*
+ * Initialize the ethernet hardware
+ */
+static void
+dec21140Enet_initialize_hardware (struct dec21140_softc *sc)
+{
+ int i,st;
+ volatile unsigned int *tbase;
+ volatile unsigned char *cp, *setup_frm, *eaddrs;
+ volatile unsigned char *buffer;
+ volatile struct MD *rmd;
+
#ifdef DEC_DEBUG
- printk("DC2114x %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);
+ printk("dec2114x : %02x:%02x:%02x:%02x:%02x:%02x name '%s%d', io %x, mem %x, int %d\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->arpcom.ac_if.if_name, sc->arpcom.ac_if.if_unit,
+ sc->port, (unsigned) sc->base, sc->irqInfo.name );
#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);
+
+
+
+ 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);
+ rtems_bsp_delay_in_bus_cycles(200);
+
+ st_le32( (tbase+memCSR7), NO_IT);
+
+ /*
+ * Init CSR0
+ */
+ st_le32( (tbase+memCSR0), CSR0_MODE);
+
+ /*
+ * 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);
+ 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;
+ rmd = (volatile struct MD*)cp;
+ sc->MDbase = rmd;
+ sc->nextRxMD = 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;
- }
+ buffer = cp + ((NRXBUFS+NTXBUFS)*sizeof(struct MD));
+ st_le32( (tbase+memCSR3), (long)(phys_to_bus((long)(sc->MDbase))));
- /*
- * 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);
+ 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;
- st_le32( (tbase+memCSR7), NO_IT);
+ rmd->buf2 = phys_to_bus(rmd+1);
+ rmd->buf1 = phys_to_bus(mtod(m, void *));
+ rmd->status = 0x80000000;
+ rmd->counts = 0xfdc00000 | (RBUF_SIZE);
+ rmd->next = rmd+1;
+ rmd++;
+ }
+ /*
+ * mark last RX buffer.
+ */
+ sc->MDbase [NRXBUFS-1].buf2 = 0;
+ 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;
+
+
+ /*
+ * 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;
+
+
+
+
+
+ sc->irqInfo.hdl = (rtems_irq_hdl)dec21140Enet_interrupt_handler_entry;
+ sc->irqInfo.on = no_op;
+ sc->irqInfo.off = no_op;
+ sc->irqInfo.isOn = dec21140IsOn;
+
+#ifdef BSP_SHARED_HANDLER_SUPPORT
+ st = BSP_install_rtems_shared_irq_handler( &sc->irqInfo );
+#else
+ st = BSP_install_rtems_irq_handler( &sc->irqInfo );
+#endif
- /*
- * 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);
+ if (!st)
+ rtems_panic ("dec2114x : Interrupt name %d already in use\n", sc->irqInfo.name );
}
+
+
+
+
+
+
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;
+ volatile unsigned int *tbase;
+ volatile struct MD *rmd;
+ struct dec21140_softc *sc;
+ volatile struct ifnet *ifp;
+ struct ether_header *eh;
+ struct mbuf *m;
+ unsigned int i,len;
+ rtems_event_set events;
+
+ for (;;)
+ {
+
+ rtems_bsdnet_event_receive( RTEMS_ALL_EVENTS,
+ RTEMS_WAIT|RTEMS_EVENT_ANY,
+ RTEMS_NO_TIMEOUT,
+ &events);
+
+ for(i=0; i< NDECDRIVER; i++ )
+ {
+ sc = &dec21140_softc[i];
+ if( sc->base )
+ {
+ if( events & sc->ioevent )
+ {
+ ifp = &sc->arpcom.ac_if;
+ tbase = sc->base;
+ rmd = sc->nextRxMD;
+
+ /*
+ ** Read off all the packets we've received on this unit
+ */
+ while((rmd->status & 0x80000000) == 0)
+ {
+ /* printk("unit %i rx\n", ifp->if_unit ); */
+
+ /* 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 *));
+
+ /* mark the descriptor as ready to receive */
+ rmd->status = 0x80000000;
+
+ rmd=rmd->next;
+ }
- for (;;){
+ sc->nextRxMD = rmd;
+ }
+ }
+ }
- 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;
+ 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 = dp->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;
+ }
- tbase = dp->base;
- /*
- * Waiting for Transmitter ready
- */
- tmd = dec21140_softc[0].TxMD;
- n = m;
+ if (len < ET_MINLEN) len = ET_MINLEN;
+ tmd->counts = 0xe1000000 | (len & 0x7ff);
+ tmd->status = 0x80000000;
- while ((tmd->status & 0x80000000) != 0){
- tmd=tmd->next;
- }
+ st_le32( (tbase+memCSR1), 0x1);
- 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;
+ m_freem(n);
+
+ dp->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 (;;) {
+ struct dec21140_softc *sc;
+ struct ifnet *ifp;
+ struct mbuf *m;
+ int i;
+ rtems_event_set events;
+
+ for (;;)
+ {
/*
- * Get the next mbuf chain to transmit.
+ * Wait for packets bound for any of the dec units
*/
- IF_DEQUEUE(&ifp->if_snd, m);
- if (!m)
- break;
- sendpacket (ifp, m);
- }
- ifp->if_flags &= ~IFF_OACTIVE;
- }
-}
+ rtems_bsdnet_event_receive( RTEMS_ALL_EVENTS,
+ RTEMS_EVENT_ANY | RTEMS_WAIT,
+ RTEMS_NO_TIMEOUT, &events);
+
+ for(i=0; i< NDECDRIVER; i++ )
+ {
+ sc = &dec21140_softc[i];
+ if( sc->base )
+ {
+ if( events & sc->ioevent )
+ {
+ ifp = &sc->arpcom.ac_if;
+
+ /*
+ * Send packets till queue is empty
+ */
+ for(;;)
+ {
+ IF_DEQUEUE(&ifp->if_snd, m);
+ if( !m ) break;
+ /* printk("unit %i tx\n", ifp->if_unit ); */
+ 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;
+ struct dec21140_softc *sc = ifp->if_softc;
+ rtems_event_send( txDaemonTid, sc->ioevent );
+ 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;
+ struct dec21140_softc *sc = arg;
+ struct ifnet *ifp = &sc->arpcom.ac_if;
+ volatile unsigned int *tbase;
+
+ /*
+ * Set up DEC21140 hardware if its not already been done
+ */
+ if( !sc->irqInfo.hdl )
+ {
+ dec21140Enet_initialize_hardware (sc);
+ }
+
+ /*
+ * Enable RX and TX
+ */
+ tbase = sc->base;
+ st_le32( (tbase+memCSR5), IT_SETUP);
+ st_le32( (tbase+memCSR7), IT_SETUP);
+ st_le32( (unsigned int*)(tbase+memCSR6), CSR6_INIT | CSR6_TXRX);
+
+ /*
+ * Tell the world that we're running.
+ */
+ ifp->if_flags |= IFF_RUNNING;
+}
+
+
+
- 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
@@ -682,10 +881,11 @@ dec21140_stop (struct dec21140_softc *sc)
/*
* Stop the transmitter
*/
- tbase=dec21140_softc[0].base ;
+ tbase = sc->base;
st_le32( (tbase+memCSR7), NO_IT);
st_le32( (tbase+memCSR6), CSR6_INIT);
- free((void*)sc->bufferBase);
+
+ /* free((void*)sc->bufferBase); */
}
@@ -715,55 +915,85 @@ dec21140_stats (struct dec21140_softc *sc)
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;
+ 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;
+ /*
+ * FIXME: All sorts of multicast commands need to be added here!
+ */
+ default:
+ error = EINVAL;
+ break;
+ }
+
+ return error;
+}
+
+
+
+
+
+
+
+/*
+int iftap(struct ifnet *ifp, struct ether_header *eh, struct mbuf *m )
+{
+ int i;
+
+ if( ifp->if_unit == 1 ) return 0;
+
+ printf("unit %i, src ", ifp->if_unit );
+ for(i=0; i< ETHER_ADDR_LEN; i++) printf("%02x", (char) eh->ether_shost[i] );
+ printf(" dest ");
+ for(i=0; i< ETHER_ADDR_LEN; i++) printf("%02x", (char) eh->ether_dhost[i] );
+ printf("\n");
+
+ return -1;
}
+*/
+
+
+
+
/*
* Attach an DEC21140 driver to the system
@@ -771,193 +1001,283 @@ dec21140_ioctl (struct ifnet *ifp, int command, caddr_t data)
int
rtems_dec21140_driver_attach (struct rtems_bsdnet_ifconfig *config, int attach)
{
- struct dec21140_softc *sc;
- struct ifnet *ifp;
- int mtu;
- int i;
+ struct dec21140_softc *sc;
+ struct ifnet *ifp;
+ char *unitName;
+ int unitNumber;
+ int mtu;
+ unsigned char cvalue;
#if defined(__i386__)
- int deviceId = PCI_DEVICE_ID_DEC_21140; /* network card device ID */
+ int signature;
+ int value;
+ char interrupt;
+ int diag;
+ unsigned int deviceId;
#endif
-
- /*
- * First, find a DEC board
- */
+#if defined(__PPC)
+ int pbus, pdev, pfun;
+ int tmp;
+ unsigned int lvalue;
+#endif
+
+
+ /*
+ * Get the instance number for the board we're going to configure
+ * from the user.
+ */
+ if( (unitNumber = rtems_bsdnet_parse_driver_name( config, &unitName)) == -1 )
+ {
+ return 0;
+ }
+ if( strcmp(unitName, DRIVER_PREFIX) )
+ {
+ printk("dec2114x : unit name '%s' not %s\n", unitName, DRIVER_PREFIX );
+ return 0;
+ }
+
+
#if defined(__i386__)
- int signature;
- int value;
- char interrupt;
- int diag;
+ /*
+ * First, find a DEC board
+ */
- if (pcib_init() == PCIB_ERR_NOTPRESENT)
- rtems_panic("PCI BIOS not found !!");
+ if (pcib_init() == PCIB_ERR_NOTPRESENT)
+ rtems_panic("PCI BIOS not found !!");
- /*
- * Try to find the network card on the PCI bus. Probe for a DEC 21140
- * card first. If not found probe the bus for a DEC/Intel 21143 card.
- */
- deviceId = PCI_DEVICE_ID_DEC_21140;
- diag = pcib_find_by_devid( PCI_VENDOR_ID_DEC, deviceId,
- 0, &signature);
- if ( diag == PCIB_ERR_SUCCESS)
+ /*
+ * Try to find the network card on the PCI bus. Probe for a DEC 21140
+ * card first. If not found probe the bus for a DEC/Intel 21143 card.
+ */
+ deviceId = PCI_DEVICE_ID_DEC_21140;
+ diag = pcib_find_by_devid( PCI_VENDOR_ID_DEC, deviceId, unitNumber-1, &signature);
+
+ if ( diag == PCIB_ERR_SUCCESS)
printk( "DEC 21140 PCI network card found\n" );
- else
- {
+ else
+ {
deviceId = PCI_DEVICE_ID_DEC_21143;
- diag = pcib_find_by_devid( PCI_VENDOR_ID_DEC, deviceId,
- 0, &signature);
+ diag = pcib_find_by_devid( PCI_VENDOR_ID_DEC, deviceId, unitNumber-1, &signature);
if ( diag == PCIB_ERR_SUCCESS)
- printk( "DEC/Intel 21143 PCI network card found\n" );
+ printk( "DEC/Intel 21143 PCI network card found\n" );
else
- rtems_panic("DEC PCI network card not found !!\n");
- }
+ rtems_panic("DEC PCI network card not 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_21140<<16) + PCI_VENDOR_ID_DEC))
- break;
- }
- if (ulDeviceID == ((PCI_DEVICE_ID_DEC_21140<<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
- */
+ /*
+ * Find the board
+ */
+ if( BSP_pciFindDevice( PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21140,
+ unitNumber-1, &pbus, &pdev, &pfun) == -1 )
+ {
+ if( BSP_pciFindDevice( PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21143,
+ unitNumber-1, &pbus, &pdev, &pfun) != -1 )
+ {
+ printk("dec21143 : found device '%s', PPC support has not been tested. Using it anyway.\n",
+ config->name );
+
+ pci_write_config_dword(pbus,
+ pdev,
+ pfun,
+ 0x40,
+ PCI_DEVICE_ID_DEC_21143 );
+
+ }
+ else
+ {
+ printk("dec2114x : device '%s' not found on PCI bus\n", config->name );
+ return 0;
+ }
+ }
+
+#ifdef DEC_DEBUG
+ else
+ {
+ printk("dec21140 : found device '%s', bus 0x%02x, dev 0x%02x, func 0x%02x\n",
+ config->name, pbus, pdev, pfun);
+ }
+#endif
+
+#endif
+
+
+
+
+ if ((unitNumber < 1) || (unitNumber > NDECDRIVER))
+ {
+ printk("dec2114x : unit %i is invalid, must be (1 <= n <= %d)\n", unitNumber);
+ return 0;
+ }
+
+ sc = &dec21140_softc[unitNumber - 1];
+ ifp = &sc->arpcom.ac_if;
+ if (ifp->if_softc != NULL)
+ {
+ printk("dec2114x : unit %i already in use.\n", unitNumber );
+ return 0;
+ }
+
+
+ /*
+ ** Get this unit's rx/tx event
+ */
+ sc->ioevent = unit_signals[unitNumber-1];
+
+
+ /*
+ * Get card address spaces & retrieve its isr vector
+ */
#if defined(__i386__)
- /* the 21143 chip must be enabled before it can be accessed */
- if ( deviceId == PCI_DEVICE_ID_DEC_21143 )
+ /* the 21143 chip must be enabled before it can be accessed */
+ if ( deviceId == PCI_DEVICE_ID_DEC_21143 )
pcib_conf_write32( signature, 0x40, 0 );
- pcib_conf_read32(signature, 16, &value);
- sc->port = value & ~IO_MASK;
+ 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((void **) &(sc->base),
- (void *)(value & ~MEM_MASK),
- DEC_REGISTER_SIZE ,
- PTE_CACHE_DISABLE | PTE_WRITABLE);
- else
- sc->base = (unsigned int *)(value & ~MEM_MASK);
+ pcib_conf_read32(signature, 20, &value);
+ if (_CPU_is_paging_enabled())
+ _CPU_map_phys_address((void **) &(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;
+ pcib_conf_read8(signature, 60, &interrupt);
+ cvalue = interrupt;
#endif
#if defined(__PPC)
- (void)pci_read_config_dword(0,
- ucSlotNumber,
- ucFnNumber,
- PCI_BASE_ADDRESS_0,
- &lvalue);
+ (void)pci_read_config_dword(pbus,
+ pdev,
+ pfun,
+ PCI_BASE_ADDRESS_0,
+ &lvalue);
- sc->port = lvalue & (unsigned int)(~IO_MASK);
+ 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)PCI_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;
+ (void)pci_read_config_dword(pbus,
+ pdev,
+ pfun,
+ PCI_BASE_ADDRESS_1,
+ &lvalue);
+
+ tmp = (unsigned int)(lvalue & (unsigned int)(~MEM_MASK))
+ + (unsigned int)PCI_MEM_BASE;
+
+ sc->base = (unsigned int *)(tmp);
+
+ pci_read_config_byte(pbus,
+ pdev,
+ pfun,
+ PCI_INTERRUPT_LINE,
+ &cvalue);
+
#endif
- if (config->hardware_address) {
- memcpy (sc->arpcom.ac_enaddr, config->hardware_address,
- ETHER_ADDR_LEN);
- }
- else {
- union {char c[64]; unsigned short s[32];} rombuf;
- int i;
-
- for (i=0; i<32; i++){
- rombuf.s[i] = eeget16(sc->base+memCSR9, i);
- }
+
+ /*
+ ** Prep the board
+ */
+ pci_write_config_word(pbus, pdev, pfun,
+ PCI_COMMAND,
+ (unsigned16)( PCI_COMMAND_MEMORY |
+ PCI_COMMAND_MASTER |
+ PCI_COMMAND_INVALIDATE |
+ PCI_COMMAND_WAIT |
+ PCI_COMMAND_FAST_BACK ) );
+
+ /*
+ ** Store the interrupt name, we'll use it later when we initialize
+ ** the board.
+ */
+ memset(&sc->irqInfo,0,sizeof(rtems_irq_connect_data));
+ sc->irqInfo.name = cvalue;
+
+
+ /* printk("dec2114x : unit %d base address %08x.\n", unitNumber, sc->base ); */
+
+
+ /*
+ ** Setup ethernet address
+ */
+ if (config->hardware_address) {
+ memcpy (sc->arpcom.ac_enaddr, config->hardware_address,
+ ETHER_ADDR_LEN);
+ }
+ else {
+ union {char c[64]; unsigned short s[32];} rombuf;
+ int i;
+
+ for (i=0; i<32; i++){
+ rombuf.s[i] = eeget16( sc->base + memCSR9, i);
+ }
#if defined(__i386__)
- for (i=0 ; i<(ETHER_ADDR_LEN/2); i++){
- sc->arpcom.ac_enaddr[2*i] = rombuf.c[20+2*i+1];
- sc->arpcom.ac_enaddr[2*i+1] = rombuf.c[20+2*i];
- }
+ for (i=0 ; i<(ETHER_ADDR_LEN/2); i++){
+ sc->arpcom.ac_enaddr[2*i] = rombuf.c[20+2*i+1];
+ sc->arpcom.ac_enaddr[2*i+1] = rombuf.c[20+2*i];
+ }
#endif
#if defined(__PPC)
- memcpy (sc->arpcom.ac_enaddr, rombuf.c+20, ETHER_ADDR_LEN);
+ memcpy (sc->arpcom.ac_enaddr, rombuf.c+20, ETHER_ADDR_LEN);
+#endif
+ }
+
+ if (config->mtu)
+ mtu = config->mtu;
+ else
+ mtu = ETHERMTU;
+
+ sc->acceptBroadcast = !config->ignore_broadcast;
+
+ /*
+ * Set up network interface values
+ */
+
+/* ifp->if_tap = iftap; */
+
+ ifp->if_softc = sc;
+ ifp->if_unit = unitNumber;
+ ifp->if_name = unitName;
+ 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);
+
+#ifdef DEC_DEBUG
+ printk( "dec2114x : driver attached\n" );
#endif
- }
-
- 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);
-
- printk( "DC2114x : driver has been attached\n" );
- return 1;
+
+
+ /*
+ * Start driver tasks if this is the first dec unit initialized
+ */
+ if (txDaemonTid == 0)
+ {
+ rxDaemonTid = rtems_bsdnet_newproc( "DCrx", 4096,
+ dec21140_rxDaemon, NULL);
+
+ txDaemonTid = rtems_bsdnet_newproc( "DCtx", 4096,
+ dec21140_txDaemon, NULL);
+#ifdef DEC_DEBUG
+ printk( "dec2114x : driver tasks created\n" );
+#endif
+ }
+
+ return 1;
};
+
#endif /* DEC21140_SUPPORTED */
+
+/* eof */
diff --git a/c/src/libchip/network/elnk.c b/c/src/libchip/network/elnk.c
new file mode 100644
index 0000000000..be4f69a128
--- /dev/null
+++ b/c/src/libchip/network/elnk.c
@@ -0,0 +1,3267 @@
+/*
+ * RTEMS driver for Etherlink based Ethernet Controllers
+ *
+ * Copyright (C) 2003, Gregory Menke, NASA/GSFC
+ *
+ * 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.
+ *
+ * elnk.c
+ *
+ *
+ */
+
+
+/*
+ * Portions of this driver are taken from the Freebsd if_xl.c driver,
+ * version "1.133 2003/03/19 01:48:14" and are covered by the license
+ * text included below that was taken verbatim from the original file.
+ * More particularly, all structures, variables, and #defines prefixed
+ * with XL_ or xl_, along with their associated comments were taken
+ * directly from the Freebsd driver and modified as required to suit the
+ * purposes of this one. Additionally, much of the device setup &
+ * manipulation logic was also copied and modified to suit. All types
+ * and functions beginning with elnk are either my own creations or were
+ * adapted from other RTEMS components, and regardless, are subject to
+ * the standard OAR licensing terms given in the comments at the top of
+ * this file.
+ *
+ * Greg Menke
+ */
+
+ /*
+ * Copyright (c) 1997, 1998, 1999
+ * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Bill Paul.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <rtems.h>
+
+/*
+ * This driver only supports architectures with the new style
+ * exception processing. The following checks try to keep this
+ * from being compiled on systems which can't support this driver.
+ */
+
+#if defined(__i386__)
+#define ELNK_SUPPORTED
+#endif
+
+#if defined(__PPC__) && (defined(mpc604) || defined(mpc750) || defined(mpc603e))
+#define ELNK_SUPPORTED
+#endif
+
+/* #undef ELNK_SUPPORTED */
+
+
+#if defined(ELNK_SUPPORTED)
+#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 <string.h>
+#include <rtems/error.h>
+#include <rtems/bspIo.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 "if_media.h"
+#include "mii.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 ELNK_DEBUG
+
+
+#define DRIVER_PREFIX "elnk"
+
+
+
+
+
+/*
+* These buffers allocated for each unit, so ensure
+*
+* rtems_bsdnet_config.mbuf_bytecount
+* rtems_bsdnet_config.mbuf_cluster_bytecount
+*
+* are adequately sized to provide enough clusters and mbufs for all the
+* units. The default bsdnet configuration is sufficient for one unit,
+* but will be nearing exhaustion with 2 or more. Although a little
+* expensive in memory, the following configuration should eliminate all
+* mbuf/cluster issues;
+*
+* rtems_bsdnet_config.mbuf_bytecount = 128*1024;
+* rtems_bsdnet_config.mbuf_cluster_bytecount = 256*1024;
+*
+* The default size in buffers of the rx & tx rings are given below.
+* This driver honors the rtems_bsdnet_ifconfig fields 'rbuf_count' and
+* 'xbuf_count', allowing the user to specify something else.
+*/
+
+#define RX_RING_SIZE 16 /* default number of receive buffers */
+#define TX_RING_SIZE 16 /* default number of transmit buffers */
+
+
+/*
+ * Number of boards supported by this driver
+ */
+#define NUM_UNITS 8
+
+/*
+ * Receive buffer size -- Allow for a full ethernet packet including CRC
+ */
+#define XL_PACKET_SIZE 1540
+
+
+/*
+** Events, one per unit. The event is sent to the rx task from the isr
+** or from the stack to the tx task whenever a unit needs service. The
+** rx/tx tasks identify the requesting unit(s) by their particular
+** events so only requesting units are serviced.
+*/
+
+static rtems_event_set unit_signals[NUM_UNITS]= { RTEMS_EVENT_1,
+ RTEMS_EVENT_2,
+ RTEMS_EVENT_3,
+ RTEMS_EVENT_4,
+ RTEMS_EVENT_5,
+ RTEMS_EVENT_6,
+ RTEMS_EVENT_7,
+ RTEMS_EVENT_8 };
+
+
+#if defined(__PPC)
+#define phys_to_bus(address) ((unsigned int)((address)) + PCI_DRAM_OFFSET)
+#define bus_to_phys(address) ((unsigned int)((address)) - PCI_DRAM_OFFSET)
+#define CPU_CACHE_ALIGNMENT_FOR_BUFFER PPC_CACHE_ALIGNMENT
+#else
+extern void Wait_X_ms( unsigned int timeToWait );
+#define phys_to_bus(address) ((unsigned int) ((address)))
+#define bus_to_phys(address) ((unsigned int) ((address)))
+#define rtems_bsp_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
+
+/* the actual duration waited in DELAY is not especially predictable,
+ * though it will be consistent. It should not be relied upon for
+ * specific timing given the vague per-bsp, per-architecture
+ * implementation of the actual delay function. It would probably be
+ * helpful to make this more accurate at some point...
+ */
+#define DELAY(n) rtems_bsp_delay_in_bus_cycles( n*20 )
+
+
+
+
+/*
+ * Register layouts.
+ */
+#define XL_COMMAND 0x0E
+#define XL_STATUS 0x0E
+
+#define XL_TX_STATUS 0x1B
+#define XL_TX_FREE 0x1C
+#define XL_DMACTL 0x20
+#define XL_DOWNLIST_PTR 0x24
+#define XL_DOWN_POLL 0x2D /* 3c90xB only */
+#define XL_TX_FREETHRESH 0x2F
+#define XL_UPLIST_PTR 0x38
+#define XL_UPLIST_STATUS 0x30
+#define XL_UP_POLL 0x3D /* 3c90xB only */
+
+#define XL_PKTSTAT_UP_STALLED 0x00002000
+#define XL_PKTSTAT_UP_ERROR 0x00004000
+#define XL_PKTSTAT_UP_CMPLT 0x00008000
+
+#define XL_DMACTL_DN_CMPLT_REQ 0x00000002
+#define XL_DMACTL_DOWN_STALLED 0x00000004
+#define XL_DMACTL_UP_CMPLT 0x00000008
+#define XL_DMACTL_DOWN_CMPLT 0x00000010
+#define XL_DMACTL_UP_RX_EARLY 0x00000020
+#define XL_DMACTL_ARM_COUNTDOWN 0x00000040
+#define XL_DMACTL_DOWN_INPROG 0x00000080
+#define XL_DMACTL_COUNTER_SPEED 0x00000100
+#define XL_DMACTL_DOWNDOWN_MODE 0x00000200
+#define XL_DMACTL_TARGET_ABORT 0x40000000
+#define XL_DMACTL_MASTER_ABORT 0x80000000
+
+/*
+ * Command codes. Some command codes require that we wait for
+ * the CMD_BUSY flag to clear. Those codes are marked as 'mustwait.'
+ */
+#define XL_CMD_RESET 0x0000 /* mustwait */
+#define XL_CMD_WINSEL 0x0800
+#define XL_CMD_COAX_START 0x1000
+#define XL_CMD_RX_DISABLE 0x1800
+#define XL_CMD_RX_ENABLE 0x2000
+#define XL_CMD_RX_RESET 0x2800 /* mustwait */
+#define XL_CMD_UP_STALL 0x3000 /* mustwait */
+#define XL_CMD_UP_UNSTALL 0x3001
+#define XL_CMD_DOWN_STALL 0x3002 /* mustwait */
+#define XL_CMD_DOWN_UNSTALL 0x3003
+#define XL_CMD_RX_DISCARD 0x4000
+#define XL_CMD_TX_ENABLE 0x4800
+#define XL_CMD_TX_DISABLE 0x5000
+#define XL_CMD_TX_RESET 0x5800 /* mustwait */
+#define XL_CMD_INTR_FAKE 0x6000
+#define XL_CMD_INTR_ACK 0x6800
+#define XL_CMD_INTR_ENB 0x7000
+#define XL_CMD_STAT_ENB 0x7800
+#define XL_CMD_RX_SET_FILT 0x8000
+#define XL_CMD_RX_SET_THRESH 0x8800
+#define XL_CMD_TX_SET_THRESH 0x9000
+#define XL_CMD_TX_SET_START 0x9800
+#define XL_CMD_DMA_UP 0xA000
+#define XL_CMD_DMA_STOP 0xA001
+#define XL_CMD_STATS_ENABLE 0xA800
+#define XL_CMD_STATS_DISABLE 0xB000
+#define XL_CMD_COAX_STOP 0xB800
+
+#define XL_CMD_SET_TX_RECLAIM 0xC000 /* 3c905B only */
+#define XL_CMD_RX_SET_HASH 0xC800 /* 3c905B only */
+
+#define XL_HASH_SET 0x0400
+#define XL_HASHFILT_SIZE 256
+
+/*
+ * status codes
+ * Note that bits 15 to 13 indicate the currently visible register window
+ * which may be anything from 0 to 7.
+ */
+#define XL_STAT_INTLATCH 0x0001 /* 0 */
+#define XL_STAT_ADFAIL 0x0002 /* 1 */
+#define XL_STAT_TX_COMPLETE 0x0004 /* 2 */
+#define XL_STAT_TX_AVAIL 0x0008 /* 3 first generation */
+#define XL_STAT_RX_COMPLETE 0x0010 /* 4 */
+#define XL_STAT_RX_EARLY 0x0020 /* 5 */
+#define XL_STAT_INTREQ 0x0040 /* 6 */
+#define XL_STAT_STATSOFLOW 0x0080 /* 7 */
+#define XL_STAT_DMADONE 0x0100 /* 8 first generation */
+#define XL_STAT_LINKSTAT 0x0100 /* 8 3c509B */
+#define XL_STAT_DOWN_COMPLETE 0x0200 /* 9 */
+#define XL_STAT_UP_COMPLETE 0x0400 /* 10 */
+#define XL_STAT_DMABUSY 0x0800 /* 11 first generation */
+#define XL_STAT_CMDBUSY 0x1000 /* 12 */
+
+/*
+ * Interrupts we normally want enabled.
+ */
+#define XL_INTRS \
+ (XL_STAT_UP_COMPLETE|XL_STAT_STATSOFLOW|XL_STAT_ADFAIL| \
+ XL_STAT_DOWN_COMPLETE|XL_STAT_TX_COMPLETE|XL_STAT_INTLATCH)
+
+
+
+/*
+ * General constants that are fun to know.
+ *
+ * 3Com PCI vendor ID
+ */
+#define TC_VENDORID 0x10B7
+
+/*
+ * 3Com chip device IDs.
+ */
+#define TC_DEVICEID_BOOMERANG_10BT 0x9000
+#define TC_DEVICEID_BOOMERANG_10BT_COMBO 0x9001
+#define TC_DEVICEID_BOOMERANG_10_100BT 0x9050
+#define TC_DEVICEID_BOOMERANG_100BT4 0x9051
+#define TC_DEVICEID_KRAKATOA_10BT 0x9004
+#define TC_DEVICEID_KRAKATOA_10BT_COMBO 0x9005
+#define TC_DEVICEID_KRAKATOA_10BT_TPC 0x9006
+#define TC_DEVICEID_CYCLONE_10FL 0x900A
+#define TC_DEVICEID_HURRICANE_10_100BT 0x9055
+#define TC_DEVICEID_CYCLONE_10_100BT4 0x9056
+#define TC_DEVICEID_CYCLONE_10_100_COMBO 0x9058
+#define TC_DEVICEID_CYCLONE_10_100FX 0x905A
+#define TC_DEVICEID_TORNADO_10_100BT 0x9200
+#define TC_DEVICEID_TORNADO_10_100BT_920B 0x9201
+#define TC_DEVICEID_HURRICANE_10_100BT_SERV 0x9800
+#define TC_DEVICEID_TORNADO_10_100BT_SERV 0x9805
+#define TC_DEVICEID_HURRICANE_SOHO100TX 0x7646
+#define TC_DEVICEID_TORNADO_HOMECONNECT 0x4500
+#define TC_DEVICEID_HURRICANE_555 0x5055
+#define TC_DEVICEID_HURRICANE_556 0x6055
+#define TC_DEVICEID_HURRICANE_556B 0x6056
+#define TC_DEVICEID_HURRICANE_575A 0x5057
+#define TC_DEVICEID_HURRICANE_575B 0x5157
+#define TC_DEVICEID_HURRICANE_575C 0x5257
+#define TC_DEVICEID_HURRICANE_656 0x6560
+#define TC_DEVICEID_HURRICANE_656B 0x6562
+#define TC_DEVICEID_TORNADO_656C 0x6564
+
+
+
+#define XL_RXSTAT_LENMASK 0x00001FFF
+#define XL_RXSTAT_UP_ERROR 0x00004000
+#define XL_RXSTAT_UP_CMPLT 0x00008000
+#define XL_RXSTAT_UP_OVERRUN 0x00010000
+#define XL_RXSTAT_RUNT 0x00020000
+#define XL_RXSTAT_ALIGN 0x00040000
+#define XL_RXSTAT_CRC 0x00080000
+#define XL_RXSTAT_OVERSIZE 0x00100000
+#define XL_RXSTAT_DRIBBLE 0x00800000
+#define XL_RXSTAT_UP_OFLOW 0x01000000
+#define XL_RXSTAT_IPCKERR 0x02000000 /* 3c905B only */
+#define XL_RXSTAT_TCPCKERR 0x04000000 /* 3c905B only */
+#define XL_RXSTAT_UDPCKERR 0x08000000 /* 3c905B only */
+#define XL_RXSTAT_BUFEN 0x10000000 /* 3c905B only */
+#define XL_RXSTAT_IPCKOK 0x20000000 /* 3c905B only */
+#define XL_RXSTAT_TCPCOK 0x40000000 /* 3c905B only */
+#define XL_RXSTAT_UDPCKOK 0x80000000 /* 3c905B only */
+
+#define XL_TXSTAT_LENMASK 0x00001FFF
+#define XL_TXSTAT_CRCDIS 0x00002000
+#define XL_TXSTAT_TX_INTR 0x00008000
+#define XL_TXSTAT_DL_COMPLETE 0x00010000
+#define XL_TXSTAT_IPCKSUM 0x02000000 /* 3c905B only */
+#define XL_TXSTAT_TCPCKSUM 0x04000000 /* 3c905B only */
+#define XL_TXSTAT_UDPCKSUM 0x08000000 /* 3c905B only */
+#define XL_TXSTAT_RND_DEFEAT 0x10000000 /* 3c905B only */
+#define XL_TXSTAT_EMPTY 0x20000000 /* 3c905B only */
+#define XL_TXSTAT_DL_INTR 0x80000000
+
+
+#define XL_FLAG_FUNCREG 0x0001
+#define XL_FLAG_PHYOK 0x0002
+#define XL_FLAG_EEPROM_OFFSET_30 0x0004
+#define XL_FLAG_WEIRDRESET 0x0008
+#define XL_FLAG_8BITROM 0x0010
+#define XL_FLAG_INVERT_LED_PWR 0x0020
+#define XL_FLAG_INVERT_MII_PWR 0x0040
+#define XL_FLAG_NO_XCVR_PWR 0x0080
+#define XL_FLAG_USE_MMIO 0x0100
+
+
+
+#define XL_EE_READ 0x0080 /* read, 5 bit address */
+#define XL_EE_WRITE 0x0040 /* write, 5 bit address */
+#define XL_EE_ERASE 0x00c0 /* erase, 5 bit address */
+#define XL_EE_EWEN 0x0030 /* erase, no data needed */
+#define XL_EE_8BIT_READ 0x0200 /* read, 8 bit address */
+#define XL_EE_BUSY 0x8000
+
+#define XL_EE_EADDR0 0x00 /* station address, first word */
+#define XL_EE_EADDR1 0x01 /* station address, next word, */
+#define XL_EE_EADDR2 0x02 /* station address, last word */
+#define XL_EE_PRODID 0x03 /* product ID code */
+#define XL_EE_MDATA_DATE 0x04 /* manufacturing data, date */
+#define XL_EE_MDATA_DIV 0x05 /* manufacturing data, division */
+#define XL_EE_MDATA_PCODE 0x06 /* manufacturing data, product code */
+#define XL_EE_MFG_ID 0x07
+#define XL_EE_PCI_PARM 0x08
+#define XL_EE_ROM_ONFO 0x09
+#define XL_EE_OEM_ADR0 0x0A
+#define XL_EE_OEM_ADR1 0x0B
+#define XL_EE_OEM_ADR2 0x0C
+#define XL_EE_SOFTINFO1 0x0D
+#define XL_EE_COMPAT 0x0E
+#define XL_EE_SOFTINFO2 0x0F
+#define XL_EE_CAPS 0x10 /* capabilities word */
+#define XL_EE_RSVD0 0x11
+#define XL_EE_ICFG_0 0x12
+#define XL_EE_ICFG_1 0x13
+#define XL_EE_RSVD1 0x14
+#define XL_EE_SOFTINFO3 0x15
+#define XL_EE_RSVD_2 0x16
+
+/*
+ * Bits in the capabilities word
+ */
+#define XL_CAPS_PNP 0x0001
+#define XL_CAPS_FULL_DUPLEX 0x0002
+#define XL_CAPS_LARGE_PKTS 0x0004
+#define XL_CAPS_SLAVE_DMA 0x0008
+#define XL_CAPS_SECOND_DMA 0x0010
+#define XL_CAPS_FULL_BM 0x0020
+#define XL_CAPS_FRAG_BM 0x0040
+#define XL_CAPS_CRC_PASSTHRU 0x0080
+#define XL_CAPS_TXDONE 0x0100
+#define XL_CAPS_NO_TXLENGTH 0x0200
+#define XL_CAPS_RX_REPEAT 0x0400
+#define XL_CAPS_SNOOPING 0x0800
+#define XL_CAPS_100MBPS 0x1000
+#define XL_CAPS_PWRMGMT 0x2000
+
+
+
+/*
+ * Window 0 registers
+ */
+#define XL_W0_EE_DATA 0x0C
+#define XL_W0_EE_CMD 0x0A
+#define XL_W0_RSRC_CFG 0x08
+#define XL_W0_ADDR_CFG 0x06
+#define XL_W0_CFG_CTRL 0x04
+
+#define XL_W0_PROD_ID 0x02
+#define XL_W0_MFG_ID 0x00
+
+/*
+ * Window 1
+ */
+
+#define XL_W1_TX_FIFO 0x10
+
+#define XL_W1_FREE_TX 0x0C
+#define XL_W1_TX_STATUS 0x0B
+#define XL_W1_TX_TIMER 0x0A
+#define XL_W1_RX_STATUS 0x08
+#define XL_W1_RX_FIFO 0x00
+
+/*
+ * RX status codes
+ */
+#define XL_RXSTATUS_OVERRUN 0x01
+#define XL_RXSTATUS_RUNT 0x02
+#define XL_RXSTATUS_ALIGN 0x04
+#define XL_RXSTATUS_CRC 0x08
+#define XL_RXSTATUS_OVERSIZE 0x10
+#define XL_RXSTATUS_DRIBBLE 0x20
+
+/*
+ * TX status codes
+ */
+#define XL_TXSTATUS_RECLAIM 0x02 /* 3c905B only */
+#define XL_TXSTATUS_OVERFLOW 0x04
+#define XL_TXSTATUS_MAXCOLS 0x08
+#define XL_TXSTATUS_UNDERRUN 0x10
+#define XL_TXSTATUS_JABBER 0x20
+#define XL_TXSTATUS_INTREQ 0x40
+#define XL_TXSTATUS_COMPLETE 0x80
+
+/*
+ * Window 2
+ */
+#define XL_W2_RESET_OPTIONS 0x0C /* 3c905B only */
+#define XL_W2_STATION_MASK_HI 0x0A
+#define XL_W2_STATION_MASK_MID 0x08
+#define XL_W2_STATION_MASK_LO 0x06
+#define XL_W2_STATION_ADDR_HI 0x04
+#define XL_W2_STATION_ADDR_MID 0x02
+#define XL_W2_STATION_ADDR_LO 0x00
+
+#define XL_RESETOPT_FEATUREMASK 0x0001|0x0002|0x004
+#define XL_RESETOPT_D3RESETDIS 0x0008
+#define XL_RESETOPT_DISADVFD 0x0010
+#define XL_RESETOPT_DISADV100 0x0020
+#define XL_RESETOPT_DISAUTONEG 0x0040
+#define XL_RESETOPT_DEBUGMODE 0x0080
+#define XL_RESETOPT_FASTAUTO 0x0100
+#define XL_RESETOPT_FASTEE 0x0200
+#define XL_RESETOPT_FORCEDCONF 0x0400
+#define XL_RESETOPT_TESTPDTPDR 0x0800
+#define XL_RESETOPT_TEST100TX 0x1000
+#define XL_RESETOPT_TEST100RX 0x2000
+
+#define XL_RESETOPT_INVERT_LED 0x0010
+#define XL_RESETOPT_INVERT_MII 0x4000
+
+/*
+ * Window 3 (fifo management)
+ */
+#define XL_W3_INTERNAL_CFG 0x00
+#define XL_W3_MAXPKTSIZE 0x04 /* 3c905B only */
+#define XL_W3_RESET_OPT 0x08
+#define XL_W3_FREE_TX 0x0C
+#define XL_W3_FREE_RX 0x0A
+#define XL_W3_MAC_CTRL 0x06
+
+#define XL_ICFG_CONNECTOR_MASK 0x00F00000
+#define XL_ICFG_CONNECTOR_BITS 20
+
+#define XL_ICFG_RAMSIZE_MASK 0x00000007
+#define XL_ICFG_RAMWIDTH 0x00000008
+#define XL_ICFG_ROMSIZE_MASK (0x00000040|0x00000080)
+#define XL_ICFG_DISABLE_BASSD 0x00000100
+#define XL_ICFG_RAMLOC 0x00000200
+#define XL_ICFG_RAMPART (0x00010000|0x00020000)
+#define XL_ICFG_XCVRSEL (0x00100000|0x00200000|0x00400000)
+#define XL_ICFG_AUTOSEL 0x01000000
+
+#define XL_XCVR_10BT 0x00
+#define XL_XCVR_AUI 0x01
+#define XL_XCVR_RSVD_0 0x02
+#define XL_XCVR_COAX 0x03
+#define XL_XCVR_100BTX 0x04
+#define XL_XCVR_100BFX 0x05
+#define XL_XCVR_MII 0x06
+#define XL_XCVR_RSVD_1 0x07
+#define XL_XCVR_AUTO 0x08 /* 3c905B only */
+
+#define XL_MACCTRL_DEFER_EXT_END 0x0001
+#define XL_MACCTRL_DEFER_0 0x0002
+#define XL_MACCTRL_DEFER_1 0x0004
+#define XL_MACCTRL_DEFER_2 0x0008
+#define XL_MACCTRL_DEFER_3 0x0010
+#define XL_MACCTRL_DUPLEX 0x0020
+#define XL_MACCTRL_ALLOW_LARGE_PACK 0x0040
+#define XL_MACCTRL_EXTEND_AFTER_COL 0x0080 (3c905B only)
+#define XL_MACCTRL_FLOW_CONTROL_ENB 0x0100 (3c905B only)
+#define XL_MACCTRL_VLT_END 0x0200 (3c905B only)
+
+/*
+ * The 'reset options' register contains power-on reset values
+ * loaded from the EEPROM. This includes the supported media
+ * types on the card. It is also known as the media options register.
+ */
+#define XL_W3_MEDIA_OPT 0x08
+
+#define XL_MEDIAOPT_BT4 0x0001 /* MII */
+#define XL_MEDIAOPT_BTX 0x0002 /* on-chip */
+#define XL_MEDIAOPT_BFX 0x0004 /* on-chip */
+#define XL_MEDIAOPT_BT 0x0008 /* on-chip */
+#define XL_MEDIAOPT_BNC 0x0010 /* on-chip */
+#define XL_MEDIAOPT_AUI 0x0020 /* on-chip */
+#define XL_MEDIAOPT_MII 0x0040 /* MII */
+#define XL_MEDIAOPT_VCO 0x0100 /* 1st gen chip only */
+
+#define XL_MEDIAOPT_10FL 0x0100 /* 3x905B only, on-chip */
+#define XL_MEDIAOPT_MASK 0x01FF
+
+/*
+ * Window 4 (diagnostics)
+ */
+#define XL_W4_UPPERBYTESOK 0x0D
+#define XL_W4_BADSSD 0x0C
+#define XL_W4_MEDIA_STATUS 0x0A
+#define XL_W4_PHY_MGMT 0x08
+#define XL_W4_NET_DIAG 0x06
+#define XL_W4_FIFO_DIAG 0x04
+#define XL_W4_VCO_DIAG 0x02
+
+#define XL_W4_CTRLR_STAT 0x08
+#define XL_W4_TX_DIAG 0x00
+
+#define XL_MII_CLK 0x01
+#define XL_MII_DATA 0x02
+#define XL_MII_DIR 0x04
+
+#define XL_MEDIA_SQE 0x0008
+#define XL_MEDIA_10TP 0x00C0
+#define XL_MEDIA_LNK 0x0080
+#define XL_MEDIA_LNKBEAT 0x0800
+
+#define XL_MEDIASTAT_CRCSTRIP 0x0004
+#define XL_MEDIASTAT_SQEENB 0x0008
+#define XL_MEDIASTAT_COLDET 0x0010
+#define XL_MEDIASTAT_CARRIER 0x0020
+#define XL_MEDIASTAT_JABGUARD 0x0040
+#define XL_MEDIASTAT_LINKBEAT 0x0080
+#define XL_MEDIASTAT_JABDETECT 0x0200
+#define XL_MEDIASTAT_POLREVERS 0x0400
+#define XL_MEDIASTAT_LINKDETECT 0x0800
+#define XL_MEDIASTAT_TXINPROG 0x1000
+#define XL_MEDIASTAT_DCENB 0x4000
+#define XL_MEDIASTAT_AUIDIS 0x8000
+
+#define XL_NETDIAG_TEST_LOWVOLT 0x0001
+#define XL_NETDIAG_ASIC_REVMASK (0x0002|0x0004|0x0008|0x0010|0x0020)
+#define XL_NETDIAG_UPPER_BYTES_ENABLE 0x0040
+#define XL_NETDIAG_STATS_ENABLED 0x0080
+#define XL_NETDIAG_TX_FATALERR 0x0100
+#define XL_NETDIAG_TRANSMITTING 0x0200
+#define XL_NETDIAG_RX_ENABLED 0x0400
+#define XL_NETDIAG_TX_ENABLED 0x0800
+#define XL_NETDIAG_FIFO_LOOPBACK 0x1000
+#define XL_NETDIAG_MAC_LOOPBACK 0x2000
+#define XL_NETDIAG_ENDEC_LOOPBACK 0x4000
+#define XL_NETDIAG_EXTERNAL_LOOP 0x8000
+
+/*
+ * Window 5
+ */
+#define XL_W5_STAT_ENB 0x0C
+#define XL_W5_INTR_ENB 0x0A
+#define XL_W5_RECLAIM_THRESH 0x09 /* 3c905B only */
+#define XL_W5_RX_FILTER 0x08
+#define XL_W5_RX_EARLYTHRESH 0x06
+#define XL_W5_TX_AVAILTHRESH 0x02
+#define XL_W5_TX_STARTTHRESH 0x00
+
+/*
+ * RX filter bits
+ */
+#define XL_RXFILTER_INDIVIDUAL 0x01
+#define XL_RXFILTER_ALLMULTI 0x02
+#define XL_RXFILTER_BROADCAST 0x04
+#define XL_RXFILTER_ALLFRAMES 0x08
+#define XL_RXFILTER_MULTIHASH 0x10 /* 3c905B only */
+
+/*
+ * Window 6 (stats)
+ */
+#define XL_W6_TX_BYTES_OK 0x0C
+#define XL_W6_RX_BYTES_OK 0x0A
+#define XL_W6_UPPER_FRAMES_OK 0x09
+#define XL_W6_DEFERRED 0x08
+#define XL_W6_RX_OK 0x07
+#define XL_W6_TX_OK 0x06
+#define XL_W6_RX_OVERRUN 0x05
+#define XL_W6_COL_LATE 0x04
+#define XL_W6_COL_SINGLE 0x03
+#define XL_W6_COL_MULTIPLE 0x02
+#define XL_W6_SQE_ERRORS 0x01
+#define XL_W6_CARRIER_LOST 0x00
+
+/*
+ * Window 7 (bus master control)
+ */
+#define XL_W7_BM_ADDR 0x00
+#define XL_W7_BM_LEN 0x06
+#define XL_W7_BM_STATUS 0x0B
+#define XL_W7_BM_TIMEr 0x0A
+
+/*
+ * bus master control registers
+ */
+#define XL_BM_PKTSTAT 0x20
+#define XL_BM_DOWNLISTPTR 0x24
+#define XL_BM_FRAGADDR 0x28
+#define XL_BM_FRAGLEN 0x2C
+#define XL_BM_TXFREETHRESH 0x2F
+#define XL_BM_UPPKTSTAT 0x30
+#define XL_BM_UPLISTPTR 0x38
+
+
+
+
+
+
+
+
+struct xl_mii_frame {
+ u_int8_t mii_stdelim;
+ u_int8_t mii_opcode;
+ u_int8_t mii_phyaddr;
+ u_int8_t mii_regaddr;
+ u_int8_t mii_turnaround;
+ u_int16_t mii_data;
+};
+
+/*
+ * MII constants
+ */
+#define XL_MII_STARTDELIM 0x01
+#define XL_MII_READOP 0x02
+#define XL_MII_WRITEOP 0x01
+#define XL_MII_TURNAROUND 0x02
+
+
+
+/*
+ * The 3C905B adapters implement a few features that we want to
+ * take advantage of, namely the multicast hash filter. With older
+ * chips, you only have the option of turning on reception of all
+ * multicast frames, which is kind of lame.
+ *
+ * We also use this to decide on a transmit strategy. For the 3c90xB
+ * cards, we can use polled descriptor mode, which reduces CPU overhead.
+ */
+#define XL_TYPE_905B 1
+#define XL_TYPE_90X 2
+
+#define XL_FLAG_FUNCREG 0x0001
+#define XL_FLAG_PHYOK 0x0002
+#define XL_FLAG_EEPROM_OFFSET_30 0x0004
+#define XL_FLAG_WEIRDRESET 0x0008
+#define XL_FLAG_8BITROM 0x0010
+#define XL_FLAG_INVERT_LED_PWR 0x0020
+#define XL_FLAG_INVERT_MII_PWR 0x0040
+#define XL_FLAG_NO_XCVR_PWR 0x0080
+#define XL_FLAG_USE_MMIO 0x0100
+
+#define XL_NO_XCVR_PWR_MAGICBITS 0x0900
+
+
+#define XL_MIN_FRAMELEN 60
+
+#define XL_LAST_FRAG 0x80000000
+
+
+
+
+
+
+
+struct xl_stats
+{
+ u_int8_t xl_carrier_lost;
+ u_int8_t xl_sqe_errs;
+ u_int8_t xl_tx_multi_collision;
+ u_int8_t xl_tx_single_collision;
+ u_int8_t xl_tx_late_collision;
+ u_int8_t xl_rx_overrun;
+ u_int8_t xl_tx_frames_ok;
+ u_int8_t xl_rx_frames_ok;
+ u_int8_t xl_tx_deferred;
+ u_int8_t xl_upper_frames_ok;
+ u_int16_t xl_rx_bytes_ok;
+ u_int16_t xl_tx_bytes_ok;
+
+ u_int8_t xl_upper_bytes_ok;
+ u_int8_t xl_badssd;
+
+ u_int16_t intstatus;
+ u_int16_t rxstatus;
+ u_int8_t txstatus;
+ u_int16_t mediastatus;
+
+ u_int16_t miianr, miipar, miistatus, miicmd;
+
+ u_int32_t device_interrupts;
+
+ u_int16_t smbstatus;
+};
+
+
+
+struct xl_type
+{
+ u_int16_t xl_vid;
+ u_int16_t xl_did;
+ char *xl_name;
+};
+
+
+
+/*
+ * Various supported device vendors/types and their names.
+ */
+static struct xl_type xl_devs[] = {
+ { TC_VENDORID, TC_DEVICEID_BOOMERANG_10BT,
+ "3Com 3c900-TPO Etherlink XL" },
+ { TC_VENDORID, TC_DEVICEID_BOOMERANG_10BT_COMBO,
+ "3Com 3c900-COMBO Etherlink XL" },
+ { TC_VENDORID, TC_DEVICEID_BOOMERANG_10_100BT,
+ "3Com 3c905-TX Fast Etherlink XL" },
+ { TC_VENDORID, TC_DEVICEID_BOOMERANG_100BT4,
+ "3Com 3c905-T4 Fast Etherlink XL" },
+ { TC_VENDORID, TC_DEVICEID_KRAKATOA_10BT,
+ "3Com 3c900B-TPO Etherlink XL" },
+ { TC_VENDORID, TC_DEVICEID_KRAKATOA_10BT_COMBO,
+ "3Com 3c900B-COMBO Etherlink XL" },
+ { TC_VENDORID, TC_DEVICEID_KRAKATOA_10BT_TPC,
+ "3Com 3c900B-TPC Etherlink XL" },
+ { TC_VENDORID, TC_DEVICEID_CYCLONE_10FL,
+ "3Com 3c900B-FL Etherlink XL" },
+ { TC_VENDORID, TC_DEVICEID_HURRICANE_10_100BT,
+ "3Com 3c905B-TX Fast Etherlink XL" },
+ { TC_VENDORID, TC_DEVICEID_CYCLONE_10_100BT4,
+ "3Com 3c905B-T4 Fast Etherlink XL" },
+ { TC_VENDORID, TC_DEVICEID_CYCLONE_10_100FX,
+ "3Com 3c905B-FX/SC Fast Etherlink XL" },
+ { TC_VENDORID, TC_DEVICEID_CYCLONE_10_100_COMBO,
+ "3Com 3c905B-COMBO Fast Etherlink XL" },
+ { TC_VENDORID, TC_DEVICEID_TORNADO_10_100BT,
+ "3Com 3c905C-TX Fast Etherlink XL" },
+ { TC_VENDORID, TC_DEVICEID_TORNADO_10_100BT_920B,
+ "3Com 3c920B-EMB Integrated Fast Etherlink XL" },
+ { TC_VENDORID, TC_DEVICEID_HURRICANE_10_100BT_SERV,
+ "3Com 3c980 Fast Etherlink XL" },
+ { TC_VENDORID, TC_DEVICEID_TORNADO_10_100BT_SERV,
+ "3Com 3c980C Fast Etherlink XL" },
+ { TC_VENDORID, TC_DEVICEID_HURRICANE_SOHO100TX,
+ "3Com 3cSOHO100-TX OfficeConnect" },
+ { TC_VENDORID, TC_DEVICEID_TORNADO_HOMECONNECT,
+ "3Com 3c450-TX HomeConnect" },
+ { TC_VENDORID, TC_DEVICEID_HURRICANE_555,
+ "3Com 3c555 Fast Etherlink XL" },
+ { TC_VENDORID, TC_DEVICEID_HURRICANE_556,
+ "3Com 3c556 Fast Etherlink XL" },
+ { TC_VENDORID, TC_DEVICEID_HURRICANE_556B,
+ "3Com 3c556B Fast Etherlink XL" },
+ { TC_VENDORID, TC_DEVICEID_HURRICANE_575A,
+ "3Com 3c575TX Fast Etherlink XL" },
+ { TC_VENDORID, TC_DEVICEID_HURRICANE_575B,
+ "3Com 3c575B Fast Etherlink XL" },
+ { TC_VENDORID, TC_DEVICEID_HURRICANE_575C,
+ "3Com 3c575C Fast Etherlink XL" },
+ { TC_VENDORID, TC_DEVICEID_HURRICANE_656,
+ "3Com 3c656 Fast Etherlink XL" },
+ { TC_VENDORID, TC_DEVICEID_HURRICANE_656B,
+ "3Com 3c656B Fast Etherlink XL" },
+ { TC_VENDORID, TC_DEVICEID_TORNADO_656C,
+ "3Com 3c656C Fast Etherlink XL" },
+ { 0, 0, NULL }
+};
+
+
+
+
+
+
+#define CSR_WRITE_4(sc, reg, val) outl( val, sc->ioaddr + reg)
+#define CSR_WRITE_2(sc, reg, val) outw( val, sc->ioaddr + reg)
+#define CSR_WRITE_1(sc, reg, val) outb( val, sc->ioaddr + reg)
+
+#define CSR_READ_4(sc, reg) inl(sc->ioaddr + reg)
+#define CSR_READ_2(sc, reg) inw(sc->ioaddr + reg)
+#define CSR_READ_1(sc, reg) inb(sc->ioaddr + reg)
+
+#define XL_SEL_WIN(x) CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_WINSEL | x)
+
+#define XL_TIMEOUT 1000
+
+
+
+
+
+/* message descriptor entry, ensure this struct is aligned to 8 bytes */
+struct MD
+{
+ /* used by hardware */
+ volatile unsigned32 next;
+ volatile unsigned32 status;
+ volatile unsigned32 addr;
+ volatile unsigned32 length;
+ /* used by software */
+ struct mbuf *mbuf; /* scratch variable used in the tx ring */
+ struct MD *next_md;
+} __attribute__ ((packed));
+
+
+
+
+
+
+
+/*
+ * Per-device data
+ */
+struct elnk_softc
+{
+ struct arpcom arpcom;
+
+ rtems_irq_connect_data irqInfo;
+ rtems_event_set ioevent;
+ unsigned int ioaddr;
+
+ volatile unsigned char *bufferBase, *ringBase;
+
+ struct MD *curr_rx_md, *last_tx_md, *last_txchain_head;
+
+ rtems_id stat_timer_id;
+ unsigned32 stats_update_ticks;
+
+ struct xl_stats xl_stats;
+
+ u_int8_t xl_unit; /* interface number */
+ u_int8_t xl_type;
+ int xl_flags;
+ u_int16_t xl_media;
+ u_int16_t xl_caps;
+ u_int32_t xl_xcvr;
+ u_int8_t xl_stats_no_timeout;
+ u_int16_t xl_tx_thresh;
+
+ int tx_idle;
+
+ unsigned short vendorID, deviceID;
+ int acceptBroadcast;
+ int numTxbuffers, numRxbuffers;
+};
+
+static struct elnk_softc elnk_softc[NUM_UNITS];
+static rtems_id rxDaemonTid;
+static rtems_id txDaemonTid;
+
+
+
+
+
+
+
+
+
+
+
+
+/*
+ * Murphy's law says that it's possible the chip can wedge and
+ * the 'command in progress' bit may never clear. Hence, we wait
+ * only a finite amount of time to avoid getting caught in an
+ * infinite loop. Normally this delay routine would be a macro,
+ * but it isn't called during normal operation so we can afford
+ * to make it a function.
+ */
+static void
+xl_wait(sc)
+ struct elnk_softc *sc;
+{
+ register int i;
+
+ for (i = 0; i < XL_TIMEOUT; i++) {
+ if (!(CSR_READ_2(sc, XL_STATUS) & XL_STAT_CMDBUSY))
+ break;
+ }
+
+ if (i == XL_TIMEOUT)
+ printk("ek%d: command never completed!\n", sc->xl_unit);
+
+ return;
+}
+
+
+
+
+
+
+/*
+ * MII access routines are provided for adapters with external
+ * PHYs (3c905-TX, 3c905-T4, 3c905B-T4) and those with built-in
+ * autoneg logic that's faked up to look like a PHY (3c905B-TX).
+ * Note: if you don't perform the MDIO operations just right,
+ * it's possible to end up with code that works correctly with
+ * some chips/CPUs/processor speeds/bus speeds/etc but not
+ * with others.
+ */
+#define MII_SET(x) \
+ CSR_WRITE_2(sc, XL_W4_PHY_MGMT, \
+ CSR_READ_2(sc, XL_W4_PHY_MGMT) | (x))
+
+#define MII_CLR(x) \
+ CSR_WRITE_2(sc, XL_W4_PHY_MGMT, \
+ CSR_READ_2(sc, XL_W4_PHY_MGMT) & ~(x))
+
+/*
+ * Sync the PHYs by setting data bit and strobing the clock 32 times.
+ */
+static void
+xl_mii_sync(sc)
+ struct elnk_softc *sc;
+{
+ register int i;
+
+ XL_SEL_WIN(4);
+ MII_SET(XL_MII_DIR|XL_MII_DATA);
+
+ for (i = 0; i < 32; i++) {
+ MII_SET(XL_MII_CLK);
+ MII_SET(XL_MII_DATA);
+ MII_CLR(XL_MII_CLK);
+ MII_SET(XL_MII_DATA);
+ }
+
+ return;
+}
+
+/*
+ * Clock a series of bits through the MII.
+ */
+static void
+xl_mii_send(sc, bits, cnt)
+ struct elnk_softc *sc;
+ u_int32_t bits;
+ int cnt;
+{
+ int i;
+
+ XL_SEL_WIN(4);
+ MII_CLR(XL_MII_CLK);
+
+ for (i = (0x1 << (cnt - 1)); i; i >>= 1) {
+ if (bits & i) {
+ MII_SET(XL_MII_DATA);
+ } else {
+ MII_CLR(XL_MII_DATA);
+ }
+ MII_CLR(XL_MII_CLK);
+ MII_SET(XL_MII_CLK);
+ }
+}
+
+/*
+ * Read an PHY register through the MII.
+ */
+static int
+xl_mii_readreg(sc, frame)
+ struct elnk_softc *sc;
+ struct xl_mii_frame *frame;
+
+{
+ int i, ack;
+
+ /*
+ * Set up frame for RX.
+ */
+ frame->mii_stdelim = XL_MII_STARTDELIM;
+ frame->mii_opcode = XL_MII_READOP;
+ frame->mii_turnaround = 0;
+ frame->mii_data = 0;
+
+ /*
+ * Select register window 4.
+ */
+
+ XL_SEL_WIN(4);
+
+ CSR_WRITE_2(sc, XL_W4_PHY_MGMT, 0);
+ /*
+ * Turn on data xmit.
+ */
+ MII_SET(XL_MII_DIR);
+
+ xl_mii_sync(sc);
+
+ /*
+ * Send command/address info.
+ */
+ xl_mii_send(sc, frame->mii_stdelim, 2);
+ xl_mii_send(sc, frame->mii_opcode, 2);
+ xl_mii_send(sc, frame->mii_phyaddr, 5);
+ xl_mii_send(sc, frame->mii_regaddr, 5);
+
+ /* Idle bit */
+ MII_CLR((XL_MII_CLK|XL_MII_DATA));
+ MII_SET(XL_MII_CLK);
+
+ /* Turn off xmit. */
+ MII_CLR(XL_MII_DIR);
+
+ /* Check for ack */
+ MII_CLR(XL_MII_CLK);
+ ack = CSR_READ_2(sc, XL_W4_PHY_MGMT) & XL_MII_DATA;
+ MII_SET(XL_MII_CLK);
+
+ /*
+ * Now try reading data bits. If the ack failed, we still
+ * need to clock through 16 cycles to keep the PHY(s) in sync.
+ */
+ if (ack) {
+ for(i = 0; i < 16; i++) {
+ MII_CLR(XL_MII_CLK);
+ MII_SET(XL_MII_CLK);
+ }
+ goto fail;
+ }
+
+ for (i = 0x8000; i; i >>= 1) {
+ MII_CLR(XL_MII_CLK);
+ if (!ack) {
+ if (CSR_READ_2(sc, XL_W4_PHY_MGMT) & XL_MII_DATA)
+ frame->mii_data |= i;
+ }
+ MII_SET(XL_MII_CLK);
+ }
+
+ fail:
+
+ MII_CLR(XL_MII_CLK);
+ MII_SET(XL_MII_CLK);
+
+ if (ack)
+ return(1);
+ return(0);
+}
+
+/*
+ * Write to a PHY register through the MII.
+ */
+static int
+xl_mii_writereg(sc, frame)
+ struct elnk_softc *sc;
+ struct xl_mii_frame *frame;
+
+{
+ /*
+ * Set up frame for TX.
+ */
+
+ frame->mii_stdelim = XL_MII_STARTDELIM;
+ frame->mii_opcode = XL_MII_WRITEOP;
+ frame->mii_turnaround = XL_MII_TURNAROUND;
+
+ /*
+ * Select the window 4.
+ */
+ XL_SEL_WIN(4);
+
+ /*
+ * Turn on data output.
+ */
+ MII_SET(XL_MII_DIR);
+
+ xl_mii_sync(sc);
+
+ xl_mii_send(sc, frame->mii_stdelim, 2);
+ xl_mii_send(sc, frame->mii_opcode, 2);
+ xl_mii_send(sc, frame->mii_phyaddr, 5);
+ xl_mii_send(sc, frame->mii_regaddr, 5);
+ xl_mii_send(sc, frame->mii_turnaround, 2);
+ xl_mii_send(sc, frame->mii_data, 16);
+
+ /* Idle bit. */
+ MII_SET(XL_MII_CLK);
+ MII_CLR(XL_MII_CLK);
+
+ /*
+ * Turn off xmit.
+ */
+ MII_CLR(XL_MII_DIR);
+
+ return(0);
+}
+
+static int
+xl_miibus_readreg(sc, phy, reg)
+ struct elnk_softc *sc;
+ int phy, reg;
+{
+ struct xl_mii_frame frame;
+
+ /*
+ * Pretend that PHYs are only available at MII address 24.
+ * This is to guard against problems with certain 3Com ASIC
+ * revisions that incorrectly map the internal transceiver
+ * control registers at all MII addresses. This can cause
+ * the miibus code to attach the same PHY several times over.
+ */
+ if ((!(sc->xl_flags & XL_FLAG_PHYOK)) && phy != 24)
+ {
+ printk("etherlink : unit elnk%d xl_miibus_readreg returned\n", sc->xl_unit);
+ return(0);
+ }
+
+ bzero((char *)&frame, sizeof(frame));
+
+ frame.mii_phyaddr = phy;
+ frame.mii_regaddr = reg;
+ xl_mii_readreg(sc, &frame);
+
+ return(frame.mii_data);
+}
+
+static int
+xl_miibus_writereg(sc, phy, reg, data)
+ struct elnk_softc *sc;
+ int phy, reg, data;
+{
+ struct xl_mii_frame frame;
+
+ if ((!(sc->xl_flags & XL_FLAG_PHYOK)) && phy != 24)
+ {
+ printk("etherlink : unit elnk%d xl_miibus_writereg returned\n", sc->xl_unit);
+ return(0);
+ }
+
+ bzero((char *)&frame, sizeof(frame));
+
+ frame.mii_phyaddr = phy;
+ frame.mii_regaddr = reg;
+ frame.mii_data = data;
+
+ xl_mii_writereg(sc, &frame);
+
+ return(0);
+}
+
+
+
+
+
+
+
+
+
+/*
+ * The EEPROM is slow: give it time to come ready after issuing
+ * it a command.
+ */
+static int
+xl_eeprom_wait(sc)
+ struct elnk_softc *sc;
+{
+ int i;
+
+ for (i = 0; i < 100; i++) {
+ if (CSR_READ_2(sc, XL_W0_EE_CMD) & XL_EE_BUSY)
+ DELAY(162);
+ else
+ break;
+ }
+
+ if (i == 100) {
+ printk("etherlink : unit elnk%d eeprom failed to come ready\n", sc->xl_unit);
+ return(1);
+ }
+
+ return(0);
+}
+
+/*
+ * Read a sequence of words from the EEPROM. Note that ethernet address
+ * data is stored in the EEPROM in network byte order.
+ */
+static int
+xl_read_eeprom(sc, dest, off, cnt, swap)
+ struct elnk_softc *sc;
+ caddr_t dest;
+ int off;
+ int cnt;
+ int swap;
+{
+ int err = 0, i;
+ u_int16_t word = 0, *ptr;
+#define EEPROM_5BIT_OFFSET(A) ((((A) << 2) & 0x7F00) | ((A) & 0x003F))
+#define EEPROM_8BIT_OFFSET(A) ((A) & 0x003F)
+ /* WARNING! DANGER!
+ * It's easy to accidentally overwrite the rom content!
+ * Note: the 3c575 uses 8bit EEPROM offsets.
+ */
+ XL_SEL_WIN(0);
+
+ if (xl_eeprom_wait(sc))
+ return(1);
+
+ if (sc->xl_flags & XL_FLAG_EEPROM_OFFSET_30)
+ off += 0x30;
+
+ for (i = 0; i < cnt; i++) {
+ if (sc->xl_flags & XL_FLAG_8BITROM)
+ CSR_WRITE_2(sc, XL_W0_EE_CMD,
+ XL_EE_8BIT_READ | EEPROM_8BIT_OFFSET(off + i));
+ else
+ CSR_WRITE_2(sc, XL_W0_EE_CMD,
+ XL_EE_READ | EEPROM_5BIT_OFFSET(off + i));
+ err = xl_eeprom_wait(sc);
+ if (err)
+ break;
+ word = CSR_READ_2(sc, XL_W0_EE_DATA);
+ ptr = (u_int16_t *)(dest + (i * 2));
+ if (swap)
+ *ptr = ntohs(word);
+ else
+ *ptr = word;
+ }
+
+ return(err ? 1 : 0);
+}
+
+
+
+
+static void
+xl_stats_update(timerid,xsc)
+ rtems_id timerid;
+ void *xsc;
+{
+ volatile struct elnk_softc *sc = (struct elnk_softc *)xsc;
+ volatile struct ifnet *ifp = &sc->arpcom.ac_if;
+
+ int i;
+
+ sc->xl_stats.intstatus = CSR_READ_2(sc, XL_STATUS);
+
+ sc->xl_stats.miianr = xl_miibus_readreg(sc, 0x18, MII_ANAR );
+ sc->xl_stats.miipar = xl_miibus_readreg(sc, 0x18, MII_ANLPAR );
+ sc->xl_stats.miistatus = xl_miibus_readreg(sc, 0x18, MII_BMSR );
+ sc->xl_stats.miicmd = xl_miibus_readreg(sc, 0x18, MII_BMCR );
+
+ XL_SEL_WIN(1);
+ sc->xl_stats.rxstatus = CSR_READ_2(sc, XL_W1_RX_STATUS );
+ sc->xl_stats.txstatus = CSR_READ_1(sc, XL_W1_TX_STATUS );
+ sc->xl_stats.smbstatus = CSR_READ_2(sc, 2 );
+
+ /* Read all the stats registers. */
+ XL_SEL_WIN(6);
+
+ sc->xl_stats.xl_carrier_lost += CSR_READ_1(sc, XL_W6_CARRIER_LOST);
+ sc->xl_stats.xl_sqe_errs += CSR_READ_1(sc, XL_W6_SQE_ERRORS);
+ sc->xl_stats.xl_tx_multi_collision += CSR_READ_1(sc, XL_W6_COL_MULTIPLE);
+ sc->xl_stats.xl_tx_single_collision += CSR_READ_1(sc, XL_W6_COL_SINGLE);
+ sc->xl_stats.xl_tx_late_collision += CSR_READ_1(sc, XL_W6_COL_LATE);
+ sc->xl_stats.xl_rx_overrun += CSR_READ_1(sc, XL_W6_RX_OVERRUN);
+ sc->xl_stats.xl_tx_frames_ok += CSR_READ_1(sc, XL_W6_TX_OK);
+ sc->xl_stats.xl_rx_frames_ok += CSR_READ_1(sc, XL_W6_RX_OK);
+ sc->xl_stats.xl_tx_deferred += CSR_READ_1(sc, XL_W6_DEFERRED);
+ sc->xl_stats.xl_upper_frames_ok += CSR_READ_1(sc, XL_W6_UPPER_FRAMES_OK);
+
+ sc->xl_stats.xl_rx_bytes_ok += CSR_READ_2(sc, XL_W6_TX_BYTES_OK );
+ sc->xl_stats.xl_tx_bytes_ok += CSR_READ_2(sc, XL_W6_RX_BYTES_OK );
+
+/*
+ for (i = 0; i < 16; i++)
+ *p++ = CSR_READ_1(sc, XL_W6_CARRIER_LOST + i);
+*/
+
+ ifp->if_ierrors += sc->xl_stats.xl_rx_overrun;
+
+ ifp->if_collisions += sc->xl_stats.xl_tx_multi_collision +
+ sc->xl_stats.xl_tx_single_collision +
+ sc->xl_stats.xl_tx_late_collision;
+
+ /*
+ * Boomerang and cyclone chips have an extra stats counter
+ * in window 4 (BadSSD). We have to read this too in order
+ * to clear out all the stats registers and avoid a statsoflow
+ * interrupt.
+ */
+ XL_SEL_WIN(4);
+ sc->xl_stats.xl_upper_bytes_ok += CSR_READ_1(sc, XL_W4_UPPERBYTESOK);
+ sc->xl_stats.xl_badssd += CSR_READ_1(sc, XL_W4_BADSSD);
+ sc->xl_stats.mediastatus = CSR_READ_2(sc, XL_W4_MEDIA_STATUS );
+
+ XL_SEL_WIN(7);
+
+ if (!sc->xl_stats_no_timeout)
+ rtems_timer_fire_after( sc->stat_timer_id, sc->stats_update_ticks, xl_stats_update, (void *)sc );
+ return;
+}
+
+
+
+
+
+
+
+static void
+xl_reset(sc)
+ struct elnk_softc *sc;
+{
+ register int i;
+
+ XL_SEL_WIN(0);
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RESET |
+ ((sc->xl_flags & XL_FLAG_WEIRDRESET) ?
+ XL_RESETOPT_DISADVFD:0));
+
+ for (i = 0; i < XL_TIMEOUT; i++) {
+ DELAY(10);
+ if (!(CSR_READ_2(sc, XL_STATUS) & XL_STAT_CMDBUSY))
+ break;
+ }
+
+ if (i == XL_TIMEOUT)
+ printk("etherlink : unit elnk%d reset didn't complete\n", sc->xl_unit);
+
+ /* Reset TX and RX. */
+ /* Note: the RX reset takes an absurd amount of time
+ * on newer versions of the Tornado chips such as those
+ * on the 3c905CX and newer 3c908C cards. We wait an
+ * extra amount of time so that xl_wait() doesn't complain
+ * and annoy the users.
+ */
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_RESET);
+ DELAY(100000);
+ xl_wait(sc);
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_TX_RESET);
+ xl_wait(sc);
+
+ if (sc->xl_flags & XL_FLAG_INVERT_LED_PWR ||
+ sc->xl_flags & XL_FLAG_INVERT_MII_PWR) {
+ XL_SEL_WIN(2);
+ CSR_WRITE_2(sc, XL_W2_RESET_OPTIONS, CSR_READ_2(sc,
+ XL_W2_RESET_OPTIONS)
+ | ((sc->xl_flags & XL_FLAG_INVERT_LED_PWR)?XL_RESETOPT_INVERT_LED:0)
+ | ((sc->xl_flags & XL_FLAG_INVERT_MII_PWR)?XL_RESETOPT_INVERT_MII:0)
+ );
+ }
+
+ /* Wait a little while for the chip to get its brains in order. */
+ DELAY(100000);
+ return;
+}
+
+
+
+
+static void
+xl_stop(sc)
+ struct elnk_softc *sc;
+{
+ register int i;
+ struct ifnet *ifp;
+
+ ifp = &sc->arpcom.ac_if;
+ ifp->if_timer = 0;
+
+ rtems_timer_cancel( sc->stat_timer_id );
+
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_DISABLE);
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_STATS_DISABLE);
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_INTR_ENB);
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_DISCARD);
+ xl_wait(sc);
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_TX_DISABLE);
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_COAX_STOP);
+ DELAY(800);
+
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_INTR_ACK|XL_STAT_INTLATCH);
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_STAT_ENB|0);
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_INTR_ENB|0);
+
+ return;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+static void
+xl_setcfg(sc)
+ struct elnk_softc *sc;
+{
+ u_int32_t icfg;
+
+ XL_SEL_WIN(3);
+ icfg = CSR_READ_4(sc, XL_W3_INTERNAL_CFG);
+ icfg &= ~XL_ICFG_CONNECTOR_MASK;
+ if (sc->xl_media & XL_MEDIAOPT_MII ||
+ sc->xl_media & XL_MEDIAOPT_BT4)
+ icfg |= (XL_XCVR_MII << XL_ICFG_CONNECTOR_BITS);
+ if (sc->xl_media & XL_MEDIAOPT_BTX)
+ icfg |= (XL_XCVR_AUTO << XL_ICFG_CONNECTOR_BITS);
+
+ CSR_WRITE_4(sc, XL_W3_INTERNAL_CFG, icfg);
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_COAX_STOP);
+
+ XL_SEL_WIN(7);
+ return;
+}
+
+static void
+xl_setmode(sc, media)
+ struct elnk_softc *sc;
+ int media;
+{
+ u_int32_t icfg;
+ u_int16_t mediastat;
+
+ printk("etherlink : unit elnk%d selecting ", sc->xl_unit);
+
+ XL_SEL_WIN(4);
+ mediastat = CSR_READ_2(sc, XL_W4_MEDIA_STATUS);
+ XL_SEL_WIN(3);
+ icfg = CSR_READ_4(sc, XL_W3_INTERNAL_CFG);
+
+ if (sc->xl_media & XL_MEDIAOPT_BT) {
+ if (IFM_SUBTYPE(media) == IFM_10_T) {
+ printk("10baseT transceiver, ");
+ sc->xl_xcvr = XL_XCVR_10BT;
+ icfg &= ~XL_ICFG_CONNECTOR_MASK;
+ icfg |= (XL_XCVR_10BT << XL_ICFG_CONNECTOR_BITS);
+ mediastat |= XL_MEDIASTAT_LINKBEAT|
+ XL_MEDIASTAT_JABGUARD;
+ mediastat &= ~XL_MEDIASTAT_SQEENB;
+ }
+ }
+
+ if (sc->xl_media & XL_MEDIAOPT_BFX) {
+ if (IFM_SUBTYPE(media) == IFM_100_FX) {
+ printk("100baseFX port, ");
+ sc->xl_xcvr = XL_XCVR_100BFX;
+ icfg &= ~XL_ICFG_CONNECTOR_MASK;
+ icfg |= (XL_XCVR_100BFX << XL_ICFG_CONNECTOR_BITS);
+ mediastat |= XL_MEDIASTAT_LINKBEAT;
+ mediastat &= ~XL_MEDIASTAT_SQEENB;
+ }
+ }
+
+ if (sc->xl_media & (XL_MEDIAOPT_AUI|XL_MEDIAOPT_10FL)) {
+ if (IFM_SUBTYPE(media) == IFM_10_5) {
+ printk("AUI port, ");
+ sc->xl_xcvr = XL_XCVR_AUI;
+ icfg &= ~XL_ICFG_CONNECTOR_MASK;
+ icfg |= (XL_XCVR_AUI << XL_ICFG_CONNECTOR_BITS);
+ mediastat &= ~(XL_MEDIASTAT_LINKBEAT|
+ XL_MEDIASTAT_JABGUARD);
+ mediastat |= ~XL_MEDIASTAT_SQEENB;
+ }
+ if (IFM_SUBTYPE(media) == IFM_10_FL) {
+ printk("10baseFL transceiver, ");
+ sc->xl_xcvr = XL_XCVR_AUI;
+ icfg &= ~XL_ICFG_CONNECTOR_MASK;
+ icfg |= (XL_XCVR_AUI << XL_ICFG_CONNECTOR_BITS);
+ mediastat &= ~(XL_MEDIASTAT_LINKBEAT|
+ XL_MEDIASTAT_JABGUARD);
+ mediastat |= ~XL_MEDIASTAT_SQEENB;
+ }
+ }
+
+ if (sc->xl_media & XL_MEDIAOPT_BNC) {
+ if (IFM_SUBTYPE(media) == IFM_10_2) {
+ printk("BNC port, ");
+ sc->xl_xcvr = XL_XCVR_COAX;
+ icfg &= ~XL_ICFG_CONNECTOR_MASK;
+ icfg |= (XL_XCVR_COAX << XL_ICFG_CONNECTOR_BITS);
+ mediastat &= ~(XL_MEDIASTAT_LINKBEAT|
+ XL_MEDIASTAT_JABGUARD|
+ XL_MEDIASTAT_SQEENB);
+ }
+ }
+
+ if ((media & IFM_GMASK) == IFM_FDX ||
+ IFM_SUBTYPE(media) == IFM_100_FX) {
+ printk("full duplex\n");
+ XL_SEL_WIN(3);
+ CSR_WRITE_1(sc, XL_W3_MAC_CTRL, XL_MACCTRL_DUPLEX);
+ } else {
+ printk("half duplex\n");
+ XL_SEL_WIN(3);
+ CSR_WRITE_1(sc, XL_W3_MAC_CTRL,
+ (CSR_READ_1(sc, XL_W3_MAC_CTRL) & ~XL_MACCTRL_DUPLEX));
+ }
+
+ if (IFM_SUBTYPE(media) == IFM_10_2)
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_COAX_START);
+ else
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_COAX_STOP);
+ CSR_WRITE_4(sc, XL_W3_INTERNAL_CFG, icfg);
+ XL_SEL_WIN(4);
+ CSR_WRITE_2(sc, XL_W4_MEDIA_STATUS, mediastat);
+ DELAY(800);
+ XL_SEL_WIN(7);
+
+ return;
+}
+
+
+
+
+
+
+
+static void
+xl_choose_xcvr(sc, verbose)
+ struct elnk_softc *sc;
+ int verbose;
+{
+ u_int16_t devid;
+
+ /*
+ * Read the device ID from the EEPROM.
+ * This is what's loaded into the PCI device ID register, so it has
+ * to be correct otherwise we wouldn't have gotten this far.
+ */
+ xl_read_eeprom(sc, (caddr_t)&devid, XL_EE_PRODID, 1, 0);
+
+ switch(devid) {
+ case TC_DEVICEID_BOOMERANG_10BT: /* 3c900-TPO */
+ case TC_DEVICEID_KRAKATOA_10BT: /* 3c900B-TPO */
+ sc->xl_media = XL_MEDIAOPT_BT;
+ sc->xl_xcvr = XL_XCVR_10BT;
+ if (verbose)
+ printk("etherlink : unit elnk%d guessing 10BaseT "
+ "transceiver\n", sc->xl_unit);
+ break;
+ case TC_DEVICEID_BOOMERANG_10BT_COMBO: /* 3c900-COMBO */
+ case TC_DEVICEID_KRAKATOA_10BT_COMBO: /* 3c900B-COMBO */
+ sc->xl_media = XL_MEDIAOPT_BT|XL_MEDIAOPT_BNC|XL_MEDIAOPT_AUI;
+ sc->xl_xcvr = XL_XCVR_10BT;
+ if (verbose)
+ printk("etherlink : unit elnk%d guessing COMBO "
+ "(AUI/BNC/TP)\n", sc->xl_unit);
+ break;
+ case TC_DEVICEID_KRAKATOA_10BT_TPC: /* 3c900B-TPC */
+ sc->xl_media = XL_MEDIAOPT_BT|XL_MEDIAOPT_BNC;
+ sc->xl_xcvr = XL_XCVR_10BT;
+ if (verbose)
+ printk("etherlink : unit elnk%d guessing TPC (BNC/TP)\n", sc->xl_unit);
+ break;
+ case TC_DEVICEID_CYCLONE_10FL: /* 3c900B-FL */
+ sc->xl_media = XL_MEDIAOPT_10FL;
+ sc->xl_xcvr = XL_XCVR_AUI;
+ if (verbose)
+ printk("etherlink : unit elnk%d guessing 10baseFL\n", sc->xl_unit);
+ break;
+ case TC_DEVICEID_BOOMERANG_10_100BT: /* 3c905-TX */
+ case TC_DEVICEID_HURRICANE_555: /* 3c555 */
+ case TC_DEVICEID_HURRICANE_556: /* 3c556 */
+ case TC_DEVICEID_HURRICANE_556B: /* 3c556B */
+ case TC_DEVICEID_HURRICANE_575A: /* 3c575TX */
+ case TC_DEVICEID_HURRICANE_575B: /* 3c575B */
+ case TC_DEVICEID_HURRICANE_575C: /* 3c575C */
+ case TC_DEVICEID_HURRICANE_656: /* 3c656 */
+ case TC_DEVICEID_HURRICANE_656B: /* 3c656B */
+ case TC_DEVICEID_TORNADO_656C: /* 3c656C */
+ case TC_DEVICEID_TORNADO_10_100BT_920B: /* 3c920B-EMB */
+ sc->xl_media = XL_MEDIAOPT_MII;
+ sc->xl_xcvr = XL_XCVR_MII;
+ if (verbose)
+ printk("etherlink : unit elnk%d guessing MII\n", sc->xl_unit);
+ break;
+ case TC_DEVICEID_BOOMERANG_100BT4: /* 3c905-T4 */
+ case TC_DEVICEID_CYCLONE_10_100BT4: /* 3c905B-T4 */
+ sc->xl_media = XL_MEDIAOPT_BT4;
+ sc->xl_xcvr = XL_XCVR_MII;
+ if (verbose)
+ printk("etherlink : unit elnk%d guessing 100BaseT4/MII\n", sc->xl_unit);
+ break;
+ case TC_DEVICEID_HURRICANE_10_100BT: /* 3c905B-TX */
+ case TC_DEVICEID_HURRICANE_10_100BT_SERV:/*3c980-TX */
+ case TC_DEVICEID_TORNADO_10_100BT_SERV: /* 3c980C-TX */
+ case TC_DEVICEID_HURRICANE_SOHO100TX: /* 3cSOHO100-TX */
+ case TC_DEVICEID_TORNADO_10_100BT: /* 3c905C-TX */
+ case TC_DEVICEID_TORNADO_HOMECONNECT: /* 3c450-TX */
+ sc->xl_media = XL_MEDIAOPT_BTX;
+ sc->xl_xcvr = XL_XCVR_AUTO;
+ if (verbose)
+ printk("etherlink : unit elnk%d guessing 10/100 internal\n", sc->xl_unit);
+ break;
+ case TC_DEVICEID_CYCLONE_10_100_COMBO: /* 3c905B-COMBO */
+ sc->xl_media = XL_MEDIAOPT_BTX|XL_MEDIAOPT_BNC|XL_MEDIAOPT_AUI;
+ sc->xl_xcvr = XL_XCVR_AUTO;
+ if (verbose)
+ printk("etherlink : unit elnk%d guessing 10/100 "
+ "plus BNC/AUI\n", sc->xl_unit);
+ break;
+ default:
+ printk("etherlink : unit elnk%d unknown device ID: %x -- "
+ "defaulting to 10baseT\n", sc->xl_unit, devid);
+ sc->xl_media = XL_MEDIAOPT_BT;
+ break;
+ }
+
+ return;
+}
+
+
+
+
+
+
+
+/*
+ * This routine is a kludge to work around possible hardware faults
+ * or manufacturing defects that can cause the media options register
+ * (or reset options register, as it's called for the first generation
+ * 3c90x adapters) to return an incorrect result. I have encountered
+ * one Dell Latitude laptop docking station with an integrated 3c905-TX
+ * which doesn't have any of the 'mediaopt' bits set. This screws up
+ * the attach routine pretty badly because it doesn't know what media
+ * to look for. If we find ourselves in this predicament, this routine
+ * will try to guess the media options values and warn the user of a
+ * possible manufacturing defect with his adapter/system/whatever.
+ */
+static void
+xl_mediacheck(sc)
+ struct elnk_softc *sc;
+{
+
+ /*
+ * If some of the media options bits are set, assume they are
+ * correct. If not, try to figure it out down below.
+ * XXX I should check for 10baseFL, but I don't have an adapter
+ * to test with.
+ */
+ if (sc->xl_media & (XL_MEDIAOPT_MASK & ~XL_MEDIAOPT_VCO)) {
+ /*
+ * Check the XCVR value. If it's not in the normal range
+ * of values, we need to fake it up here.
+ */
+ if (sc->xl_xcvr <= XL_XCVR_AUTO)
+ return;
+ else {
+ printk("etherlink : unit elnk%d bogus xcvr value "
+ "in EEPROM (%x)\n", sc->xl_unit, sc->xl_xcvr);
+ printk("etherlink : unit elnk%d choosing new default based "
+ "on card type\n", sc->xl_unit);
+ }
+ } else {
+ if (sc->xl_type == XL_TYPE_905B &&
+ sc->xl_media & XL_MEDIAOPT_10FL)
+ return;
+ printk("etherlink : unit elnk%d WARNING: no media options bits set in "
+ "the media options register!!\n", sc->xl_unit);
+ printk("etherlink : unit elnk%d this could be a manufacturing defect in "
+ "your adapter or system\n", sc->xl_unit);
+ printk("etherlink : unit elnk%d attempting to guess media type; you "
+ "should probably consult your vendor\n", sc->xl_unit);
+ }
+
+ xl_choose_xcvr(sc, 1);
+ return;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+static void no_op(const rtems_irq_connect_data* irq)
+{
+ return;
+}
+
+
+
+
+static int elnkIsOn(const rtems_irq_connect_data* irq)
+{
+ return BSP_irq_enabled_at_i8259s (irq->name);
+}
+
+
+
+
+
+
+static void
+elnk_start_txchain( struct elnk_softc *sc, struct MD *chaintop )
+{
+ printk("unit elnk%d tx start\n", sc->xl_unit );
+
+ sc->tx_idle = 0;
+
+ /* save the address of the TX list */
+ sc->last_txchain_head = chaintop;
+
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_DOWN_STALL);
+ xl_wait(sc);
+ CSR_WRITE_4(sc, XL_DOWNLIST_PTR, phys_to_bus( sc->last_txchain_head ));
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_DOWN_UNSTALL);
+}
+
+
+
+
+
+/*
+ * ELNK interrupt handler
+ */
+static rtems_isr
+elnk_interrupt_handler ( struct elnk_softc *sc )
+{
+ struct ifnet *ifp = &sc->arpcom.ac_if;
+ u_int16_t status;
+
+ while( (status = CSR_READ_2(sc, XL_STATUS)) & XL_INTRS && status != 0xFFFF)
+ {
+ sc->xl_stats.device_interrupts++;
+
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_INTR_ACK|(status & XL_INTRS));
+
+#if 0
+ printk("etherlink : unit elnk%d intstatus %04x\n", sc->xl_unit, status );
+#endif
+
+ if (status & XL_STAT_UP_COMPLETE)
+ {
+#if 0
+ printk("etherlink : unit elnk%d rx\n", sc->xl_unit );
+#endif
+ /* received packets */
+ rtems_event_send(rxDaemonTid, sc->ioevent);
+ }
+
+ if (status & XL_STAT_DOWN_COMPLETE)
+ {
+ struct MD *chaintailmd = NULL;
+
+ /* all packets uploaded to the device */
+
+ if( sc->last_txchain_head->mbuf )
+ {
+ /* either this is a chain of 2 or more packets, or its a
+ * single packet chain and another chain is also ready to send
+ */
+ if( (int)sc->last_txchain_head->mbuf == -1 )
+ {
+ /* single packet was sent, no indirection to the last entry
+ in the chain. since mbuf is != 0, then another chain
+ is ready */
+ chaintailmd = sc->last_txchain_head;
+ }
+ else
+ {
+ /* otherwise, this is a pointer to the last packet in the
+ chain */
+ chaintailmd = (struct MD *)sc->last_txchain_head->mbuf;
+ if( !chaintailmd->mbuf ) chaintailmd = NULL;
+ }
+ }
+
+ if( chaintailmd )
+ {
+ /* the next MD is the start of another chain */
+ elnk_start_txchain(sc, chaintailmd->next_md );
+ }
+ else
+ {
+ /* otherwise, we have nothing else to send */
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_DOWN_STALL);
+ sc->tx_idle = -1;
+ printk("unit elnk%d tx done\n", sc->xl_unit );
+ }
+ }
+
+ if (status & XL_STAT_TX_COMPLETE)
+ {
+ ifp->if_oerrors++;
+ printk("etherlink : unit elnk%d transmission error\n", sc->xl_unit );
+ }
+ if (status & XL_STAT_ADFAIL)
+ {
+ printk("etherlink : unit elnk%d Catastrophic bus failure\n", sc->xl_unit );
+ }
+ if (status & XL_STAT_STATSOFLOW)
+ {
+ sc->xl_stats_no_timeout = 1;
+ xl_stats_update(sc->stat_timer_id,sc);
+ sc->xl_stats_no_timeout = 0;
+ }
+ }
+
+
+#if 0
+ {
+ unsigned16 intstatus, intenable, indenable;
+
+ intstatus = CSR_READ_2(sc, XL_STATUS );
+
+ XL_SEL_WIN(5);
+ intenable = CSR_READ_2(sc, XL_W5_INTR_ENB );
+ indenable = CSR_READ_2(sc, XL_W5_STAT_ENB );
+ XL_SEL_WIN(7);
+ printk("etherlink : unit elnk%d istat %04x, ien %04x, ind %04x\n", sc->xl_unit, intstatus, intenable, indenable );
+ }
+#endif
+}
+
+
+
+
+
+static rtems_isr
+elnk_interrupt_handler_entry()
+{
+ int i;
+
+ /*
+ ** Check all the initialized units for interrupt service
+ */
+
+ for(i=0; i< NUM_UNITS; i++ )
+ {
+ if( elnk_softc[i].ioaddr )
+ elnk_interrupt_handler( &elnk_softc[i] );
+ }
+}
+
+
+
+
+
+
+
+
+
+
+
+/*
+ * Initialize the ethernet hardware
+ */
+static void
+elnk_initialize_hardware (struct elnk_softc *sc)
+{
+ volatile unsigned char *cp;
+ int nb, i, rxsize, txsize, ringsize;
+
+ /*
+ * Init RX ring
+ */
+ cp = (volatile unsigned char *)malloc( (nb =
+ (ringsize = ((rxsize = (sc->numRxbuffers * sizeof(struct MD))) +
+ (txsize = (sc->numTxbuffers * sizeof(struct MD))))) +
+ (sc->numTxbuffers * XL_PACKET_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, nb, PTE_CACHE_DISABLE | PTE_WRITABLE);
+#endif
+#endif
+ sc->ringBase = cp;
+
+ {
+ volatile unsigned char *txpackets;
+ struct MD *rx_ring, *tx_ring, *nxtmd, *thismd;
+ struct mbuf *m;
+
+ /* rebuild tx and rx rings */
+
+ rx_ring = (struct MD *)sc->ringBase;
+ tx_ring = (struct MD *)&sc->ringBase[ rxsize ];
+ txpackets = &sc->ringBase[ringsize];
+
+ /*
+ * The rx ring is easy as its just an array of MD structs, the mbuf
+ * data is dynamically requested from the ip stack.
+ */
+ for(i=0 ; i<sc->numRxbuffers; i++)
+ {
+ /* 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;
+
+ if( i == sc->numRxbuffers-1 )
+ nxtmd = &rx_ring[0];
+ else
+ nxtmd = &rx_ring[i+1];
+
+ rx_ring[i].next_md = nxtmd;
+ rx_ring[i].mbuf = m;
+
+ rx_ring[i].status = 0;
+ st_le32( &rx_ring[i].addr, (unsigned32)phys_to_bus( mtod(m, void *) ));
+ st_le32( &rx_ring[i].length, XL_LAST_FRAG | XL_PACKET_SIZE );
+ st_le32( &rx_ring[i].next, (unsigned32)phys_to_bus( nxtmd ));
+ }
+ sc->curr_rx_md = &rx_ring[0];
+
+
+ /*
+ * The tx ring is more complex. Each MD has a packet buffer
+ * permanently assigned to it. Although the next_md fields form a
+ * ring, the DPD next is filled only when packets are added to the
+ * tx chain. mbuf is a scratch register used to form chains of tx
+ * packets.
+ */
+
+ for(i=0 ; i<sc->numTxbuffers; i++)
+ {
+ if( i == sc->numTxbuffers-1 )
+ nxtmd = &tx_ring[0];
+ else
+ nxtmd = &tx_ring[i+1];
+
+ thismd = &tx_ring[i];
+
+ thismd->next_md = nxtmd;
+ thismd->mbuf = NULL;
+
+ st_le32( &thismd->status, XL_TXSTAT_DL_COMPLETE );
+ st_le32( &thismd->addr, (unsigned32)phys_to_bus( &txpackets[ i * XL_PACKET_SIZE ] ));
+ st_le32( &thismd->length, XL_LAST_FRAG );
+ thismd->next = 0;
+ }
+ sc->last_tx_md = &tx_ring[0];
+
+ }
+
+
+
+
+#ifdef ELNK_DEBUG
+ printk("etherlink : %02x:%02x:%02x:%02x:%02x:%02x name 'elnk%d', io %x, int %d\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->xl_unit,
+ (unsigned)sc->ioaddr, sc->irqInfo.name );
+#endif
+
+
+ sc->irqInfo.hdl = (rtems_irq_hdl)elnk_interrupt_handler_entry;
+ sc->irqInfo.on = no_op;
+ sc->irqInfo.off = no_op;
+ sc->irqInfo.isOn = elnkIsOn;
+
+ if( sc->irqInfo.name != 255 )
+ {
+ int st;
+
+#ifdef BSP_SHARED_HANDLER_SUPPORT
+ st = BSP_install_rtems_shared_irq_handler( &sc->irqInfo );
+#else
+ st = BSP_install_rtems_irq_handler( &sc->irqInfo );
+#endif
+ if (!st)
+ rtems_panic ("etherlink : unit elnk%d Interrupt name %d already in use\n", sc->xl_unit, sc->irqInfo.name );
+ }
+ else
+ {
+ printk("etherlink : unit elnk%d Interrupt not specified by device\n", sc->xl_unit );
+ }
+}
+
+
+
+
+
+
+
+
+
+
+
+static void
+elnk_rxDaemon (void *arg)
+{
+ struct elnk_softc *sc;
+ volatile struct ifnet *ifp;
+ struct ether_header *eh;
+ struct mbuf *m;
+ volatile struct MD *rmd;
+ unsigned int i,len, rxstat;
+ rtems_event_set events;
+
+ for (;;)
+ {
+
+ rtems_bsdnet_event_receive( RTEMS_ALL_EVENTS,
+ RTEMS_WAIT|RTEMS_EVENT_ANY,
+ RTEMS_NO_TIMEOUT,
+ &events);
+
+ for(;;)
+ {
+ for(i=0; i< NUM_UNITS; i++ )
+ {
+ sc = &elnk_softc[i];
+ if( sc->ioaddr )
+ {
+ if( events & sc->ioevent )
+ {
+ struct ifnet *ifp = &sc->arpcom.ac_if;
+
+ rmd = sc->curr_rx_md;
+
+ /*
+ ** Read off all the packets we've received on this unit
+ */
+ while( (rxstat = ld_le32(&rmd->status)) )
+ {
+ if (rxstat & XL_RXSTAT_UP_ERROR)
+ {
+ printk("unit %i up error\n", sc->xl_unit );
+ ifp->if_ierrors++;
+ }
+
+ if( (rxstat & XL_RXSTAT_UP_CMPLT) )
+ {
+
+#if 0
+ {
+ char *pkt, *delim;
+ int i;
+ pkt = mtod(rmd->mbuf, char *);
+ printk("unit %i rx pkt (%08x) ", sc->xl_unit, pkt );
+ for(delim="", i=0; i < sizeof(struct ether_header)+8; i++, delim=":")
+ printk("%s%02x", delim, (char) pkt[i] );
+ printk("\n");
+ }
+#endif
+
+ /* pass on the packet in the mbuf */
+ len = ( ld_le32(&rmd->status) & XL_RXSTAT_LENMASK);
+ m = rmd->mbuf;
+ 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 */
+ MGETHDR (m, M_WAIT, MT_DATA);
+ MCLGET (m, M_WAIT);
+ m->m_pkthdr.rcvif = ifp;
+ rmd->mbuf = m;
+ rmd->status = 0;
+ st_le32( &rmd->addr, (unsigned32)phys_to_bus(mtod(m, void *)) );
+ }
+ else
+ {
+ /* some kind of packet failure */
+ printk("etherlink : unit elnk%d bad receive status -- packet dropped\n", sc->xl_unit);
+ ifp->if_ierrors++;
+ }
+ /* clear descriptor status */
+ rmd->status = 0;
+
+ rmd = rmd->next_md;
+ }
+
+ sc->curr_rx_md = rmd;
+ }
+ }
+ }
+
+ /*
+ ** If more events are pending, service them before we go back to sleep
+ */
+ if( rtems_event_receive( RTEMS_ALL_EVENTS,
+ RTEMS_NO_WAIT | RTEMS_EVENT_ANY,
+ 0,
+ &events ) == RTEMS_UNSATISFIED ) break;
+ }
+ }
+}
+
+
+
+
+
+
+
+
+
+
+
+
+/*
+ * Driver transmit daemon
+ */
+void
+elnk_txDaemon (void *arg)
+{
+ struct elnk_softc *sc;
+ struct ifnet *ifp;
+ struct mbuf *m;
+ struct mbuf *hold;
+ volatile struct MD *lastmd, *nextmd, *firstmd;
+ unsigned char *pktbuff, *buffer;
+ unsigned int len;
+ int chainCount,i;
+ rtems_event_set events;
+
+ for (;;)
+ {
+ /*
+ * Wait for packets bound for any of the units
+ */
+ rtems_bsdnet_event_receive( RTEMS_ALL_EVENTS,
+ RTEMS_EVENT_ANY | RTEMS_WAIT,
+ RTEMS_NO_TIMEOUT, &events);
+
+ for(i=0; i< NUM_UNITS; i++ )
+ {
+ sc = &elnk_softc[i];
+ if( sc->ioaddr )
+ {
+ if( events & sc->ioevent )
+ {
+ ifp = &sc->arpcom.ac_if;
+
+ /*
+ * Send packets till queue is empty or tx ring is full
+ */
+ chainCount = 0;
+ firstmd = NULL;
+
+ lastmd = sc->last_tx_md;
+
+ for(;;)
+ {
+ nextmd = lastmd->next_md;
+
+ /* stop when ring is full */
+ if( ! (ld_le32(&nextmd->status) & XL_TXSTAT_DL_COMPLETE) )
+ {
+ printk("etherlink : unit elnk%d tx ring full!\n", sc->xl_unit);
+ break;
+ }
+
+ IF_DEQUEUE(&ifp->if_snd, m);
+ if( !m ) break;
+
+
+
+ hold = m;
+ len = 0;
+
+ buffer = pktbuff = (char *)bus_to_phys( ld_le32(&nextmd->addr) );
+ for(;;)
+ {
+ len += m->m_len;
+ memcpy((void*) buffer, (char *)m->m_data, m->m_len);
+ buffer += m->m_len ;
+ if ((m = m->m_next) == NULL)
+ break;
+ }
+ m_freem( hold );
+
+
+ {
+ char *pkt = pktbuff, *delim;
+ int i;
+ printk("unit %i queued pkt (%08x) ", sc->xl_unit, (unsigned32)pkt );
+ for(delim="", i=0; i < sizeof(struct ether_header)+8; i++, delim=":")
+ printk("%s%02x", delim, (char) pkt[i] );
+ printk("\n");
+ }
+
+
+ if (len < XL_MIN_FRAMELEN ) len = XL_MIN_FRAMELEN;
+ st_le32( &nextmd->length, XL_LAST_FRAG | (len & XL_TXSTAT_LENMASK) );
+
+ /* this packet will be the new end of the list */
+ nextmd->next = 0;
+ nextmd->status = 0;
+
+ if( !firstmd )
+ {
+ /* keep track of the first packet we add to the chain */
+ firstmd = nextmd;
+
+ /* use the mbuf pointer of the last packet of the
+ * previous chain as a flag so when a dnComplete
+ * interrupt indicates the card is finished, the
+ * isr can immediately start the next chain. Note
+ * several chains of packets may be assembled this
+ * way- but this assignment won't have any effect
+ * if a chain isn't already being transmitted.
+ */
+ lastmd->mbuf = (struct mbuf *)-1;
+ }
+ else
+ {
+ /* hook this packet to the previous one */
+ st_le32( &lastmd->next, (unsigned32)phys_to_bus( nextmd ));
+ }
+
+ ++chainCount;
+ lastmd = nextmd;
+ }
+
+
+
+ if( firstmd )
+ {
+ /* save the last descriptor we set up in the chain */
+ sc->last_tx_md = lastmd;
+
+ /*
+ * We've added one or more packets to a chain, flag
+ * the last packet so we get an dnComplete interrupt
+ * when the card finishes accepting the chain
+ */
+ st_le32(&lastmd->status, XL_TXSTAT_DL_INTR );
+
+ /*
+ * point the chain head's mbuf to the tail so we can
+ * locate the next chain to send inside the isr. If
+ * we're only sending one packet, then don't bother
+ * with the link, as the mbuf value will either be 0
+ * if theres no next chain or -1 if there is.
+ */
+ if( chainCount > 1 )
+ firstmd->mbuf = (struct mbuf *)lastmd;
+
+ /* clear our "next chain present" flag. If another
+ * chain is added later, this flag will be set to -1
+ */
+ lastmd->mbuf = NULL;
+
+
+ if( sc->tx_idle == 0 && CSR_READ_4(sc, XL_DOWNLIST_PTR) == 0 )
+ {
+ printk("etherlink : unit elnk%d tx forced!\n", sc->xl_unit);
+ sc->tx_idle = -1;
+ }
+
+ /* start sending this chain of packets if tx isn't busy */
+ if( sc->tx_idle )
+ {
+ elnk_start_txchain(sc, firstmd);
+ }
+ }
+
+ ifp->if_flags &= ~IFF_OACTIVE;
+ }
+ }
+ }
+ }
+}
+
+
+
+
+
+
+
+
+
+
+
+static void
+elnk_start (struct ifnet *ifp)
+{
+ struct elnk_softc *sc = ifp->if_softc;
+#if 0
+ printk("unit %i tx signaled\n", sc->xl_unit );
+#endif
+ ifp->if_flags |= IFF_OACTIVE;
+ rtems_event_send( txDaemonTid, sc->ioevent );
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/*
+ * Initialize and start the device
+ */
+static void
+elnk_init (void *arg)
+{
+ int i;
+ struct elnk_softc *sc = arg;
+ struct ifnet *ifp = &sc->arpcom.ac_if;
+
+ xl_stop(sc);
+
+ XL_SEL_WIN(3);
+ CSR_WRITE_1(sc, XL_W3_MAC_CTRL, XL_MACCTRL_DUPLEX);
+
+ {
+ unsigned32 cr,sr;
+
+ xl_miibus_writereg(sc, 0x18, MII_BMCR, BMCR_RESET );
+
+ while( (cr = xl_miibus_readreg(sc, 0x18, MII_BMCR )) & BMCR_RESET )
+ {
+ DELAY(100000);
+ }
+
+ xl_miibus_writereg(sc, 0x18, MII_ANAR, ANAR_10 | ANAR_10_FD | ANAR_TX | ANAR_TX_FD | ANAR_T4);
+ xl_miibus_writereg(sc, 0x18, MII_BMCR, BMCR_AUTOEN );
+
+ /* while( ((sr = xl_miibus_readreg(sc, 0x18, MII_BMSR)) & BMSR_ACOMP) == 0 ); */
+ }
+
+
+ XL_SEL_WIN(7);
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_RESET);
+ xl_wait(sc);
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_TX_RESET);
+ xl_wait(sc);
+ DELAY(10000);
+
+ sc->tx_idle = -1;
+
+ /*
+ * Set up hardware if its not already been done
+ */
+ if( !sc->irqInfo.hdl )
+ {
+ elnk_initialize_hardware(sc);
+ }
+
+ /*
+ * Enable the card
+ */
+ {
+ u_int8_t rxfilt;
+
+ /*
+ * Cancel pending I/O
+ */
+
+ /* Init our MAC address */
+ XL_SEL_WIN(2);
+ for (i = 0; i < ETHER_ADDR_LEN; i++)
+ {
+ CSR_WRITE_1(sc, XL_W2_STATION_ADDR_LO + i, sc->arpcom.ac_enaddr[i]);
+ }
+
+ /* Clear the station mask. */
+ for (i = 0; i < 3; i++)
+ CSR_WRITE_2(sc, XL_W2_STATION_MASK_LO + (i * 2), 0);
+
+ /*
+ * Set the TX freethresh value.
+ * Note that this has no effect on 3c905B "cyclone"
+ * cards but is required for 3c900/3c905 "boomerang"
+ * cards in order to enable the download engine.
+ */
+ CSR_WRITE_1(sc, XL_TX_FREETHRESH, XL_PACKET_SIZE >> 8);
+
+ /* Set the TX start threshold for best performance. */
+ sc->xl_tx_thresh = XL_MIN_FRAMELEN;
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_TX_SET_START|sc->xl_tx_thresh);
+
+ /*
+ * If this is a 3c905B, also set the tx reclaim threshold.
+ * This helps cut down on the number of tx reclaim errors
+ * that could happen on a busy network. The chip multiplies
+ * the register value by 16 to obtain the actual threshold
+ * in bytes, so we divide by 16 when setting the value here.
+ * The existing threshold value can be examined by reading
+ * the register at offset 9 in window 5.
+ */
+ if (sc->xl_type == XL_TYPE_905B) {
+ CSR_WRITE_2(sc, XL_COMMAND,
+ XL_CMD_SET_TX_RECLAIM|(XL_PACKET_SIZE >> 4));
+ }
+
+ /* Set RX filter bits. */
+ XL_SEL_WIN(5);
+ rxfilt = CSR_READ_1(sc, XL_W5_RX_FILTER);
+
+ /* Set the individual bit to receive frames for this host only. */
+ rxfilt |= XL_RXFILTER_INDIVIDUAL;
+
+ /* If we want promiscuous mode, set the allframes bit. */
+ if (ifp->if_flags & IFF_PROMISC) {
+ rxfilt |= XL_RXFILTER_ALLFRAMES;
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_SET_FILT|rxfilt);
+ } else {
+ rxfilt &= ~XL_RXFILTER_ALLFRAMES;
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_SET_FILT|rxfilt);
+ }
+
+ /*
+ * Set capture broadcast bit to capture broadcast frames.
+ */
+ if (ifp->if_flags & IFF_BROADCAST) {
+ rxfilt |= XL_RXFILTER_BROADCAST;
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_SET_FILT|rxfilt);
+ } else {
+ rxfilt &= ~XL_RXFILTER_BROADCAST;
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_SET_FILT|rxfilt);
+ }
+
+#if 0
+ /*
+ * Program the multicast filter, if necessary.
+ */
+ if (sc->xl_type == XL_TYPE_905B)
+ xl_setmulti_hash(sc);
+ else
+ xl_setmulti(sc);
+#endif
+ /*
+ * Load the address of the RX list. We have to
+ * stall the upload engine before we can manipulate
+ * the uplist pointer register, then unstall it when
+ * we're finished. We also have to wait for the
+ * stall command to complete before proceeding.
+ * Note that we have to do this after any RX resets
+ * have completed since the uplist register is cleared
+ * by a reset.
+ */
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_UP_STALL);
+ xl_wait(sc);
+ CSR_WRITE_4(sc, XL_UPLIST_PTR, phys_to_bus( sc->curr_rx_md ));
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_UP_UNSTALL);
+ xl_wait(sc);
+
+
+ if (sc->xl_type == XL_TYPE_905B) {
+ /* Set polling interval */
+ CSR_WRITE_1(sc, XL_DOWN_POLL, 64);
+ xl_wait(sc);
+ }
+
+ /*
+ * If the coax transceiver is on, make sure to enable
+ * the DC-DC converter.
+ */
+ XL_SEL_WIN(3);
+ if (sc->xl_xcvr == XL_XCVR_COAX)
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_COAX_START);
+ else
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_COAX_STOP);
+
+ /* increase packet size to allow reception of 802.1q or ISL packets */
+ if (sc->xl_type == XL_TYPE_905B)
+ CSR_WRITE_2(sc, XL_W3_MAXPKTSIZE, XL_PACKET_SIZE);
+ /* Clear out the stats counters. */
+
+ memset( &sc->xl_stats, 0, sizeof(struct xl_stats));
+
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_STATS_DISABLE);
+ sc->xl_stats_no_timeout = 1;
+ xl_stats_update(sc->stat_timer_id,sc);
+ sc->xl_stats_no_timeout = 0;
+ XL_SEL_WIN(4);
+ CSR_WRITE_2(sc, XL_W4_NET_DIAG, XL_NETDIAG_UPPER_BYTES_ENABLE);
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_STATS_ENABLE);
+
+
+ /*
+ * Enable interrupts.
+ */
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_INTR_ACK|0xFF);
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_STAT_ENB|XL_INTRS);
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_INTR_ENB|XL_INTRS);
+
+ /* Set the RX early threshold */
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_SET_THRESH|(XL_PACKET_SIZE >>2));
+ CSR_WRITE_2(sc, XL_DMACTL, XL_DMACTL_UP_RX_EARLY );
+
+#if 0
+ {
+ unsigned32 icfg;
+ unsigned16 mctl;
+
+ XL_SEL_WIN(3);
+ icfg = CSR_READ_4( sc, XL_W3_INTERNAL_CFG );
+ mctl = CSR_READ_2( sc, XL_W3_MAC_CTRL );
+
+ printk("etherlink : unit elnk%d intcfg %08x, macctl %04x\n", sc->xl_unit, icfg, mctl);
+ }
+#endif
+
+ /* Enable receiver and transmitter. */
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_TX_ENABLE);
+ xl_wait(sc);
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_ENABLE);
+ xl_wait(sc);
+
+ /* Select window 7 for normal operations. */
+ XL_SEL_WIN(7);
+
+ /* schedule the stats update timer */
+ rtems_timer_fire_after( sc->stat_timer_id, sc->stats_update_ticks, xl_stats_update, (void *)sc );
+ }
+
+ /*
+ * Tell the world that we're running.
+ */
+ ifp->if_flags |= IFF_RUNNING;
+}
+
+
+
+
+
+
+
+/*
+ * Stop the device
+ */
+static void
+elnk_stop (struct elnk_softc *sc)
+{
+ struct ifnet *ifp = &sc->arpcom.ac_if;
+
+ /*
+ * Stop the transmitter
+ */
+ xl_stop(sc);
+
+ ifp->if_flags &= ~IFF_RUNNING;
+}
+
+
+
+
+/*
+ * Show interface statistics
+ */
+static void
+elnk_stats (struct elnk_softc *sc)
+{
+ printf(" MII PHY data { anr:%04x lpar:%04x stat:%04x ctl:%04x }\n",
+ sc->xl_unit,
+ sc->xl_stats.miianr,
+ sc->xl_stats.miipar,
+ sc->xl_stats.miistatus,
+ sc->xl_stats.miicmd);
+
+ printf(" interrupts:%-5d intstatus:%04x mediastat:%04x\n",
+ sc->xl_stats.device_interrupts,
+ sc->xl_stats.intstatus,
+ sc->xl_stats.mediastatus);
+
+ printf(" rxstatus:%04x txstatus:%02x smbstat:%04x\n",
+ sc->xl_stats.rxstatus,
+ sc->xl_stats.txstatus,
+ sc->xl_stats.smbstatus);
+
+ printf(" carrier_lost:%-5d sqe_errs:%-5d\n",
+ sc->xl_stats.xl_carrier_lost,
+ sc->xl_stats.xl_sqe_errs);
+
+ printf(" tx_multi_collision:%-5d tx_single_collision:%-5d\n",
+ sc->xl_stats.xl_tx_multi_collision,
+ sc->xl_stats.xl_tx_single_collision);
+
+ printf(" tx_late_collision:%-5d rx_overrun:%-5d\n",
+ sc->xl_stats.xl_tx_late_collision,
+ sc->xl_stats.xl_rx_overrun);
+
+ printf(" tx_deferred:%-5d badssd:%-5d\n",
+ sc->xl_stats.xl_tx_deferred,
+ sc->xl_stats.xl_badssd);
+
+ printf(" rx_frames_ok:%-5d tx_frames_ok:%-5d\n",
+ sc->xl_stats.xl_rx_frames_ok + ((sc->xl_stats.xl_upper_frames_ok & 3) << 16),
+ sc->xl_stats.xl_tx_frames_ok + (((sc->xl_stats.xl_upper_frames_ok >> 4) & 3) << 16) );
+
+ printf(" rx_bytes_ok:%-5d tx_bytes_ok:%-5d\n",
+ sc->xl_stats.xl_rx_bytes_ok + ((sc->xl_stats.xl_upper_bytes_ok & 7) << 16),
+ sc->xl_stats.xl_tx_bytes_ok + (((sc->xl_stats.xl_upper_bytes_ok >> 4) & 7) << 16) );
+}
+
+
+
+
+
+
+
+/*
+ * Driver ioctl handler
+ */
+static int
+elnk_ioctl (struct ifnet *ifp, int command, caddr_t data)
+{
+ struct elnk_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:
+ elnk_stop (sc);
+ break;
+
+ case IFF_UP:
+ elnk_init (sc);
+ break;
+
+ case IFF_UP | IFF_RUNNING:
+ elnk_stop (sc);
+ elnk_init (sc);
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case SIO_RTEMS_SHOW_STATS:
+ elnk_stats (sc);
+ break;
+
+ /*
+ * FIXME: All sorts of multicast commands need to be added here!
+ */
+ default:
+ error = EINVAL;
+ break;
+ }
+
+ return error;
+}
+
+
+
+
+
+
+
+
+#if 0
+static int iftap(struct ifnet *ifp, struct ether_header *eh, struct mbuf *m )
+{
+ int i;
+ char *delim, *pkt;
+
+ printk("unit %i, src ", ifp->if_unit );
+ for(delim= "", i=0; i< ETHER_ADDR_LEN; i++, delim=":")
+ printk("%s%02x", delim, (char) eh->ether_shost[i] );
+
+ printk(" dest ");
+
+ for(delim= "", i=0; i< ETHER_ADDR_LEN; i++, delim=":")
+ printk("%s%02x", delim, (char) eh->ether_dhost[i] );
+ printk(" pkt ");
+
+ pkt = (char *)eh;
+ for(delim="", i=0; i < sizeof(struct ether_header); i++, delim=":")
+ printk("%s%02x", delim, (char) pkt[i] );
+
+ printk("\n");
+ return 0;
+}
+#endif
+
+
+
+struct el_boards
+{
+ int pbus,pdev,pfun, vid, did, tindex;
+};
+
+
+
+/*
+ * Attach an ELNK driver to the system
+ */
+int
+rtems_elnk_driver_attach (struct rtems_bsdnet_ifconfig *config, int attach)
+{
+ struct elnk_softc *sc;
+ struct ifnet *ifp;
+ char *unitName;
+ int unitNumber;
+ int mtu, i;
+ unsigned char cvalue;
+ int pbus, pdev, pfun;
+ unsigned int lvalue;
+ struct el_boards sysboards[NUM_UNITS];
+ int numFound = 0;
+
+
+ /*
+ * Get the instance number for the board we're going to configure
+ * from the user.
+ */
+ if( (unitNumber = rtems_bsdnet_parse_driver_name( config, &unitName)) == -1 )
+ {
+ return 0;
+ }
+
+ if( strcmp(unitName, DRIVER_PREFIX) )
+ {
+ printk("etherlink : invalid unit name '%s'\n", unitName );
+ return 0;
+ }
+
+ if ((unitNumber < 1) || (unitNumber > NUM_UNITS))
+ {
+ printk("etherlink : unit %i is invalid, must be (1 <= n <= %d)\n", unitNumber, NUM_UNITS);
+ return 0;
+ }
+
+
+ {
+ int done= 0, unum;
+
+ /*
+ * Run thru the list of boards, finding all that are present in
+ * the system. Sort by slot,dev - and then use the unitNumber-1
+ * to index the list and select the device. Yucky.
+ */
+ for( i=0; !done && xl_devs[i].xl_vid; i++)
+ {
+ for(unum= 1;
+ !done && BSP_pciFindDevice( xl_devs[i].xl_vid, xl_devs[i].xl_did, unum-1,
+ &sysboards[numFound].pbus,
+ &sysboards[numFound].pdev,
+ &sysboards[numFound].pfun)==0;
+ unum++)
+ {
+ if( numFound == NUM_UNITS )
+ {
+ printk("etherlink : Maximum of %d units found, extra devices ignored.\n", NUM_UNITS );
+ done=-1;
+ }
+ else
+ {
+ sysboards[numFound].vid = xl_devs[i].xl_vid;
+ sysboards[numFound].did = xl_devs[i].xl_did;
+ sysboards[numFound].tindex = i;
+ ++numFound;
+ }
+ }
+ }
+
+ if( ! numFound )
+ {
+ printk("etherlink : No Etherlink devices found\n");
+ return 0;
+ }
+
+ if( unitNumber-1 >= numFound )
+ {
+ printk("etherlink : device '%s' not found\n", config->name );
+ return 0;
+ }
+
+ /*
+ * Got the list of etherlink boards in the system, now sort by
+ * slot,device. bubble sorts aren't all that wonderful, but this
+ * is a short & infrequently sorted list.
+ */
+ if( numFound > 1 )
+ {
+ struct el_boards tboard;
+ int didsort;
+
+ do
+ {
+ didsort = 0;
+
+ for(i=1; i<numFound; i++)
+ {
+ if( sysboards[i-1].pbus > sysboards[i].pbus ||
+ (sysboards[i-1].pbus == sysboards[i].pbus && sysboards[i-1].pdev > sysboards[i].pdev) )
+ {
+ memcpy(&tboard, &sysboards[i-1], sizeof(struct el_boards));
+ memcpy(&sysboards[i-1], &sysboards[i], sizeof(struct el_boards));
+ memcpy(&sysboards[i], &tboard, sizeof(struct el_boards));
+ didsort++;
+ }
+ }
+ }
+ while( didsort );
+ }
+
+ /*
+ ** board list is sorted, now select the unit
+ */
+
+ pbus = sysboards[unitNumber-1].pbus;
+ pdev = sysboards[unitNumber-1].pdev;
+ pfun = sysboards[unitNumber-1].pfun;
+ }
+
+ sc = &elnk_softc[unitNumber - 1];
+ ifp = &sc->arpcom.ac_if;
+ if (ifp->if_softc != NULL)
+ {
+ printk("etherlink : unit %i already in use.\n", unitNumber );
+ return 0;
+ }
+
+ /*
+ ** Save various things
+ */
+ sc->xl_unit = unitNumber;
+ sc->xl_type = sysboards[ unitNumber-1 ].tindex;
+
+ sc->vendorID = sysboards[numFound].vid;
+ sc->deviceID = sysboards[numFound].did;
+
+ sc->numRxbuffers = (config->rbuf_count) ? config->rbuf_count : RX_RING_SIZE;
+ sc->numTxbuffers = (config->xbuf_count) ? config->xbuf_count : TX_RING_SIZE;
+
+ if (config->mtu)
+ mtu = config->mtu;
+ else
+ mtu = ETHERMTU;
+
+ sc->acceptBroadcast = !config->ignore_broadcast;
+
+
+
+#ifdef ELNK_DEBUG
+ printk("etherlink : device '%s', name 'elnk%d', pci %02x:%02x.%02x, %d rx/%d tx buffers\n",
+ xl_devs[sc->xl_type].xl_name, sc->xl_unit,
+ pbus, pdev, pfun,
+ sc->numRxbuffers, sc->numTxbuffers);
+#endif
+
+
+ /*
+ ** Create this unit's stats timer
+ */
+ if( rtems_timer_create( rtems_build_name( 'X', 'L', 't', (char)(sc->xl_unit & 255)),
+ &sc->stat_timer_id ) != RTEMS_SUCCESSFUL )
+ {
+ printk("etherlink : unit elnk%d unable to create stats timer\n", sc->xl_unit );
+ return 0;
+ }
+
+ /* update stats 1 times/second if things aren't incrementing fast
+ * enough to trigger stats interrupts
+ */
+ rtems_clock_get( RTEMS_CLOCK_GET_TICKS_PER_SECOND, &sc->stats_update_ticks );
+
+
+ /*
+ ** Get this unit's rx/tx event
+ */
+ sc->ioevent = unit_signals[unitNumber-1];
+
+
+ /*
+ ** Prep the board
+ */
+ pci_write_config_word(pbus, pdev, pfun,
+ PCI_COMMAND,
+ (unsigned16)( PCI_COMMAND_IO |
+ PCI_COMMAND_MASTER |
+ PCI_COMMAND_INVALIDATE |
+ PCI_COMMAND_WAIT |
+ PCI_COMMAND_FAST_BACK ) );
+
+ /*
+ * Get the devices base address
+ */
+ pci_read_config_dword(pbus, pdev, pfun,
+ PCI_BASE_ADDRESS_0,
+ &lvalue);
+
+ sc->ioaddr = (unsigned32)lvalue & PCI_BASE_ADDRESS_IO_MASK;
+
+
+ /*
+ ** Store the interrupt name, we'll use it later when we initialize
+ ** the board.
+ */
+ pci_read_config_byte(pbus, pdev, pfun,
+ PCI_INTERRUPT_LINE,
+ &cvalue);
+
+ memset(&sc->irqInfo,0,sizeof(rtems_irq_connect_data));
+ sc->irqInfo.name = cvalue;
+
+
+ /*
+ ** Establish basic board config, set node address from config or
+ ** board eeprom, do stuff with additional device properties
+ */
+
+#if 0
+ {
+ unsigned8 pci_latency;
+ unsigned8 new_latency = 248;
+
+ /* Check the PCI latency value. On the 3c590 series the latency timer
+ must be set to the maximum value to avoid data corruption that occurs
+ when the timer expires during a transfer. This bug exists the Vortex
+ chip only. */
+ pci_read_config_byte(pbus,pdev,pfun, PCI_LATENCY_TIMER, &pci_latency);
+ if (pci_latency < new_latency)
+ {
+ printk("etherlink : unit elnk%d Overriding PCI latency, timer (CFLT) setting of %d, new value is %d.\n", sc->xl_unit, pci_latency, new_latency );
+ pci_write_config_byte(pbus,pdev,pfun, PCI_LATENCY_TIMER, new_latency);
+ }
+ }
+#endif
+
+
+ /* Reset the adapter. */
+ xl_reset(sc);
+
+
+ {
+ u_int16_t xcvr[2];
+ u_char eaddr[ETHER_ADDR_LEN];
+ int media = IFM_ETHER|IFM_100_TX|IFM_FDX;
+
+ sc->xl_flags = 0;
+ if (sc->deviceID == TC_DEVICEID_HURRICANE_555)
+ sc->xl_flags |= XL_FLAG_EEPROM_OFFSET_30 | XL_FLAG_PHYOK;
+ if (sc->deviceID == TC_DEVICEID_HURRICANE_556 ||
+ sc->deviceID == TC_DEVICEID_HURRICANE_556B)
+ sc->xl_flags |= XL_FLAG_FUNCREG | XL_FLAG_PHYOK |
+ XL_FLAG_EEPROM_OFFSET_30 | XL_FLAG_WEIRDRESET |
+ XL_FLAG_INVERT_LED_PWR | XL_FLAG_INVERT_MII_PWR;
+ if (sc->deviceID == TC_DEVICEID_HURRICANE_555 ||
+ sc->deviceID == TC_DEVICEID_HURRICANE_556)
+ sc->xl_flags |= XL_FLAG_8BITROM;
+ if (sc->deviceID == TC_DEVICEID_HURRICANE_556B)
+ sc->xl_flags |= XL_FLAG_NO_XCVR_PWR;
+
+ if (sc->deviceID == TC_DEVICEID_HURRICANE_575A ||
+ sc->deviceID == TC_DEVICEID_HURRICANE_575B ||
+ sc->deviceID == TC_DEVICEID_HURRICANE_575C ||
+ sc->deviceID == TC_DEVICEID_HURRICANE_656B ||
+ sc->deviceID == TC_DEVICEID_TORNADO_656C)
+ sc->xl_flags |= XL_FLAG_FUNCREG | XL_FLAG_PHYOK |
+ XL_FLAG_EEPROM_OFFSET_30 | XL_FLAG_8BITROM;
+ if (sc->deviceID == TC_DEVICEID_HURRICANE_656)
+ sc->xl_flags |= XL_FLAG_FUNCREG | XL_FLAG_PHYOK;
+ if (sc->deviceID == TC_DEVICEID_HURRICANE_575B)
+ sc->xl_flags |= XL_FLAG_INVERT_LED_PWR;
+ if (sc->deviceID == TC_DEVICEID_HURRICANE_575C)
+ sc->xl_flags |= XL_FLAG_INVERT_MII_PWR;
+ if (sc->deviceID == TC_DEVICEID_TORNADO_656C)
+ sc->xl_flags |= XL_FLAG_INVERT_MII_PWR;
+ if (sc->deviceID == TC_DEVICEID_HURRICANE_656 ||
+ sc->deviceID == TC_DEVICEID_HURRICANE_656B)
+ sc->xl_flags |= XL_FLAG_INVERT_MII_PWR |
+ XL_FLAG_INVERT_LED_PWR;
+ if (sc->deviceID == TC_DEVICEID_TORNADO_10_100BT_920B)
+ sc->xl_flags |= XL_FLAG_PHYOK;
+
+
+ if (config->hardware_address)
+ {
+ memcpy(sc->arpcom.ac_enaddr, config->hardware_address, ETHER_ADDR_LEN);
+ }
+ else
+ {
+ if (xl_read_eeprom(sc, (caddr_t)&eaddr, XL_EE_OEM_ADR0, 3, 1))
+ {
+ printk("etherlink : unit elnk%d Failed to read station address\n", sc->xl_unit );
+ return 0;
+ }
+ memcpy((char *)&sc->arpcom.ac_enaddr, eaddr, ETHER_ADDR_LEN);
+ }
+
+ /*
+ * Figure out the card type. 3c905B adapters have the
+ * 'supportsNoTxLength' bit set in the capabilities
+ * word in the EEPROM.
+ */
+ xl_read_eeprom(sc, (caddr_t)&sc->xl_caps, XL_EE_CAPS, 1, 0);
+ if (sc->xl_caps & XL_CAPS_NO_TXLENGTH)
+ sc->xl_type = XL_TYPE_905B;
+ else
+ sc->xl_type = XL_TYPE_90X;
+
+
+ /*
+ * Now we have to see what sort of media we have.
+ * This includes probing for an MII interace and a
+ * possible PHY.
+ */
+ XL_SEL_WIN(3);
+ sc->xl_media = CSR_READ_2(sc, XL_W3_MEDIA_OPT);
+
+ xl_read_eeprom(sc, (char *)&xcvr, XL_EE_ICFG_0, 2, 0);
+ sc->xl_xcvr = xcvr[0] | xcvr[1] << 16;
+ sc->xl_xcvr &= XL_ICFG_CONNECTOR_MASK;
+ sc->xl_xcvr >>= XL_ICFG_CONNECTOR_BITS;
+
+#if 0
+ printk("etherlink : unit elnk%d EEPROM set xcvr to 0x%x\n", sc->xl_unit, sc->xl_xcvr);
+#endif
+
+ {
+ char msg[255];
+ int i;
+
+ struct _availmedia
+ {
+ int bit;
+ char *name;
+ } _am[]= {{ XL_MEDIAOPT_BT4, "100BaseT4" },
+ { XL_MEDIAOPT_BTX, "100BaseTX" },
+ { XL_MEDIAOPT_BFX, "100BaseFX" },
+ { XL_MEDIAOPT_BT, "10BaseT" },
+ { XL_MEDIAOPT_BNC, "10Base2" },
+ { XL_MEDIAOPT_AUI, "10mbps AUI"},
+ { XL_MEDIAOPT_MII, "MII"},
+ { 0, NULL }};
+
+ msg[0]= 0;
+ for( i=0; _am[i].bit; i++)
+ {
+ if( sc->xl_media & _am[i].bit )
+ sprintf( &msg[strlen(msg)], ",%s", _am[i].name );
+ }
+ if( !strlen(msg) ) strcpy( &msg[1], "<no media bits>");
+
+ printk("etherlink : unit elnk%d available media : %s\n", sc->xl_unit, &msg[1]);
+ }
+
+ xl_mediacheck(sc);
+
+#if 0
+/* this has already been called by xl_mediacheck()- hopefully
+ I've not messed something up here */
+ /*
+ * Sanity check. If the user has selected "auto" and this isn't
+ * a 10/100 card of some kind, we need to force the transceiver
+ * type to something sane.
+ */
+ if (sc->xl_xcvr == XL_XCVR_AUTO)
+ xl_choose_xcvr(sc, 1);
+#endif
+
+
+ /* Choose a default media. */
+ switch(sc->xl_xcvr) {
+ case XL_XCVR_10BT:
+ media = IFM_ETHER|IFM_10_T;
+ xl_setmode(sc, media);
+ break;
+ case XL_XCVR_AUI:
+ if (sc->xl_type == XL_TYPE_905B &&
+ sc->xl_media == XL_MEDIAOPT_10FL) {
+ media = IFM_ETHER|IFM_10_FL;
+ xl_setmode(sc, media);
+ } else {
+ media = IFM_ETHER|IFM_10_5;
+ xl_setmode(sc, media);
+ }
+ break;
+ case XL_XCVR_COAX:
+ media = IFM_ETHER|IFM_10_2;
+ xl_setmode(sc, media);
+ break;
+ case XL_XCVR_AUTO:
+ case XL_XCVR_100BTX:
+ xl_setcfg(sc);
+ break;
+ case XL_XCVR_MII:
+ printk("etherlink : unit elnk%d MII media not supported!\n", sc->xl_unit);
+ break;
+ case XL_XCVR_100BFX:
+ media = IFM_ETHER|IFM_100_FX;
+ break;
+ default:
+ printk("etherlink : unit elnk%d unknown XCVR type: %d\n", sc->xl_unit, sc->xl_xcvr);
+ /*
+ * This will probably be wrong, but it prevents
+ * the ifmedia code from panicking.
+ */
+ media = IFM_ETHER|IFM_10_T;
+ break;
+ }
+
+
+ if (sc->xl_flags & XL_FLAG_NO_XCVR_PWR) {
+ XL_SEL_WIN(0);
+ CSR_WRITE_2(sc, XL_W0_MFG_ID, XL_NO_XCVR_PWR_MAGICBITS);
+ }
+
+ XL_SEL_WIN(7);
+ }
+
+
+
+ /*
+ * Set up network interface
+ */
+ ifp->if_softc = sc;
+ ifp->if_name = unitName;
+ ifp->if_unit = sc->xl_unit;
+ ifp->if_mtu = mtu;
+ ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
+ if (ifp->if_snd.ifq_maxlen == 0)
+ ifp->if_snd.ifq_maxlen = ifqmaxlen;
+ ifp->if_init = elnk_init;
+ ifp->if_start = elnk_start;
+ ifp->if_ioctl = elnk_ioctl;
+ ifp->if_output = ether_output;
+
+#if 0
+ ifp->if_tap = iftap;
+#endif
+
+ /*
+ * Attach the interface
+ */
+ if_attach (ifp);
+ ether_ifattach (ifp);
+
+#ifdef ELNK_DEBUG
+ printk( "etherlink : unit elnk%d driver attached\n", sc->xl_unit );
+#endif
+
+ /*
+ * Start driver tasks if this is the first unit initialized
+ */
+ if (txDaemonTid == 0)
+ {
+ rxDaemonTid = rtems_bsdnet_newproc( "XLrx", 4096,
+ elnk_rxDaemon, NULL);
+
+ txDaemonTid = rtems_bsdnet_newproc( "XLtx", 4096,
+ elnk_txDaemon, NULL);
+#ifdef ELNK_DEBUG
+ printk( "etherlink : driver tasks created\n" );
+#endif
+ }
+
+ return 1;
+};
+
+#endif /* ELNK_SUPPORTED */
+
+/* eof */
diff --git a/c/src/libchip/network/if_media.h b/c/src/libchip/network/if_media.h
new file mode 100644
index 0000000000..926a803ddb
--- /dev/null
+++ b/c/src/libchip/network/if_media.h
@@ -0,0 +1,436 @@
+/* $NetBSD: if_media.h,v 1.3 1997/03/26 01:19:27 thorpej Exp $ */
+/* $FreeBSD: /repoman/r/ncvs/src/sys/net/if_media.h,v 1.18 2002/07/14 21:58:19 kbyanc Exp $ */
+
+/*
+ * Copyright (c) 1997
+ * Jonathan Stone and Jason R. Thorpe. All rights reserved.
+ *
+ * This software is derived from information provided by Matt Thomas.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Jonathan Stone
+ * and Jason R. Thorpe for the NetBSD Project.
+ * 4. The names of the authors may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _NET_IF_MEDIA_H_
+#define _NET_IF_MEDIA_H_
+
+/*
+ * Prototypes and definitions for BSD/OS-compatible network interface
+ * media selection.
+ *
+ * Where it is safe to do so, this code strays slightly from the BSD/OS
+ * design. Software which uses the API (device drivers, basically)
+ * shouldn't notice any difference.
+ *
+ * Many thanks to Matt Thomas for providing the information necessary
+ * to implement this interface.
+ */
+
+#ifdef _KERNEL
+
+#include <sys/queue.h>
+
+/*
+ * Driver callbacks for media status and change requests.
+ */
+typedef int (*ifm_change_cb_t)(struct ifnet *ifp);
+typedef void (*ifm_stat_cb_t)(struct ifnet *ifp, struct ifmediareq *req);
+
+/*
+ * In-kernel representation of a single supported media type.
+ */
+struct ifmedia_entry {
+ LIST_ENTRY(ifmedia_entry) ifm_list;
+ int ifm_media; /* description of this media attachment */
+ int ifm_data; /* for driver-specific use */
+ void *ifm_aux; /* for driver-specific use */
+};
+
+/*
+ * One of these goes into a network interface's softc structure.
+ * It is used to keep general media state.
+ */
+struct ifmedia {
+ int ifm_mask; /* mask of changes we don't care about */
+ int ifm_media; /* current user-set media word */
+ struct ifmedia_entry *ifm_cur; /* currently selected media */
+ LIST_HEAD(, ifmedia_entry) ifm_list; /* list of all supported media */
+ ifm_change_cb_t ifm_change; /* media change driver callback */
+ ifm_stat_cb_t ifm_status; /* media status driver callback */
+};
+
+/* Initialize an interface's struct if_media field. */
+void ifmedia_init(struct ifmedia *ifm, int dontcare_mask,
+ ifm_change_cb_t change_callback, ifm_stat_cb_t status_callback);
+
+/* Remove all mediums from a struct ifmedia. */
+void ifmedia_removeall( struct ifmedia *ifm);
+
+/* Add one supported medium to a struct ifmedia. */
+void ifmedia_add(struct ifmedia *ifm, int mword, int data, void *aux);
+
+/* Add an array (of ifmedia_entry) media to a struct ifmedia. */
+void ifmedia_list_add(struct ifmedia *mp, struct ifmedia_entry *lp,
+ int count);
+
+/* Set default media type on initialization. */
+void ifmedia_set(struct ifmedia *ifm, int mword);
+
+/* Common ioctl function for getting/setting media, called by driver. */
+int ifmedia_ioctl(struct ifnet *ifp, struct ifreq *ifr,
+ struct ifmedia *ifm, u_long cmd);
+
+#endif /*_KERNEL */
+
+/*
+ * if_media Options word:
+ * Bits Use
+ * ---- -------
+ * 0-4 Media variant
+ * 5-7 Media type
+ * 8-15 Type specific options
+ * 16-19 RFU
+ * 20-27 Shared (global) options
+ * 28-31 Instance
+ */
+
+/*
+ * Ethernet
+ */
+#define IFM_ETHER 0x00000020
+#define IFM_10_T 3 /* 10BaseT - RJ45 */
+#define IFM_10_2 4 /* 10Base2 - Thinnet */
+#define IFM_10_5 5 /* 10Base5 - AUI */
+#define IFM_100_TX 6 /* 100BaseTX - RJ45 */
+#define IFM_100_FX 7 /* 100BaseFX - Fiber */
+#define IFM_100_T4 8 /* 100BaseT4 - 4 pair cat 3 */
+#define IFM_100_VG 9 /* 100VG-AnyLAN */
+#define IFM_100_T2 10 /* 100BaseT2 */
+#define IFM_1000_SX 11 /* 1000BaseSX - multi-mode fiber */
+#define IFM_10_STP 12 /* 10BaseT over shielded TP */
+#define IFM_10_FL 13 /* 10BaseFL - Fiber */
+#define IFM_1000_LX 14 /* 1000baseLX - single-mode fiber */
+#define IFM_1000_CX 15 /* 1000baseCX - 150ohm STP */
+#define IFM_1000_T 16 /* 1000baseT - 4 pair cat 5 */
+#define IFM_HPNA_1 17 /* HomePNA 1.0 (1Mb/s) */
+/* note 31 is the max! */
+
+#define IFM_ETH_MASTER 0x00000100 /* master mode (1000baseT) */
+
+/*
+ * Token ring
+ */
+#define IFM_TOKEN 0x00000040
+#define IFM_TOK_STP4 3 /* Shielded twisted pair 4m - DB9 */
+#define IFM_TOK_STP16 4 /* Shielded twisted pair 16m - DB9 */
+#define IFM_TOK_UTP4 5 /* Unshielded twisted pair 4m - RJ45 */
+#define IFM_TOK_UTP16 6 /* Unshielded twisted pair 16m - RJ45 */
+#define IFM_TOK_STP100 7 /* Shielded twisted pair 100m - DB9 */
+#define IFM_TOK_UTP100 8 /* Unshielded twisted pair 100m - RJ45 */
+#define IFM_TOK_ETR 0x00000200 /* Early token release */
+#define IFM_TOK_SRCRT 0x00000400 /* Enable source routing features */
+#define IFM_TOK_ALLR 0x00000800 /* All routes / Single route bcast */
+#define IFM_TOK_DTR 0x00002000 /* Dedicated token ring */
+#define IFM_TOK_CLASSIC 0x00004000 /* Classic token ring */
+#define IFM_TOK_AUTO 0x00008000 /* Automatic Dedicate/Classic token ring */
+
+/*
+ * FDDI
+ */
+#define IFM_FDDI 0x00000060
+#define IFM_FDDI_SMF 3 /* Single-mode fiber */
+#define IFM_FDDI_MMF 4 /* Multi-mode fiber */
+#define IFM_FDDI_UTP 5 /* CDDI / UTP */
+#define IFM_FDDI_DA 0x00000100 /* Dual attach / single attach */
+
+/*
+ * IEEE 802.11 Wireless
+ */
+#define IFM_IEEE80211 0x00000080
+#define IFM_IEEE80211_FH1 3 /* Frequency Hopping 1Mbps */
+#define IFM_IEEE80211_FH2 4 /* Frequency Hopping 2Mbps */
+#define IFM_IEEE80211_DS1 5 /* Direct Sequence 1Mbps */
+#define IFM_IEEE80211_DS2 6 /* Direct Sequence 2Mbps */
+#define IFM_IEEE80211_DS5 7 /* Direct Sequence 5.5Mbps */
+#define IFM_IEEE80211_DS11 8 /* Direct Sequence 11Mbps */
+#define IFM_IEEE80211_DS22 9 /* Direct Sequence 22Mbps */
+#define IFM_IEEE80211_ODFM6 10 /* ODFM 6Mbps */
+#define IFM_IEEE80211_ODFM9 11 /* ODFM 9Mbps */
+#define IFM_IEEE80211_ODFM12 12 /* ODFM 12Mbps */
+#define IFM_IEEE80211_ODFM18 13 /* ODFM 18Mbps */
+#define IFM_IEEE80211_ODFM24 14 /* ODFM 24Mbps */
+#define IFM_IEEE80211_ODFM36 15 /* ODFM 36Mbps */
+#define IFM_IEEE80211_ODFM48 16 /* ODFM 48Mbps */
+#define IFM_IEEE80211_ODFM54 17 /* ODFM 54Mbps */
+#define IFM_IEEE80211_ODFM72 18 /* ODFM 72Mbps */
+#define IFM_IEEE80211_ADHOC 0x00000100 /* Operate in Adhoc mode */
+#define IFM_IEEE80211_HOSTAP 0x00000200 /* Operate in Host AP mode */
+#define IFM_IEEE80211_IBSS 0x00000400 /* Operate in IBSS mode */
+#define IFM_IEEE80211_IBSSMASTER 0x00000800 /* Operate as an IBSS master */
+
+/*
+ * Shared media sub-types
+ */
+#define IFM_AUTO 0 /* Autoselect best media */
+#define IFM_MANUAL 1 /* Jumper/dipswitch selects media */
+#define IFM_NONE 2 /* Deselect all media */
+
+/*
+ * Shared options
+ */
+#define IFM_FDX 0x00100000 /* Force full duplex */
+#define IFM_HDX 0x00200000 /* Force half duplex */
+#define IFM_FLAG0 0x01000000 /* Driver defined flag */
+#define IFM_FLAG1 0x02000000 /* Driver defined flag */
+#define IFM_FLAG2 0x04000000 /* Driver defined flag */
+#define IFM_LOOP 0x08000000 /* Put hardware in loopback */
+
+/*
+ * Masks
+ */
+#define IFM_NMASK 0x000000e0 /* Network type */
+#define IFM_TMASK 0x0000001f /* Media sub-type */
+#define IFM_IMASK 0xf0000000 /* Instance */
+#define IFM_ISHIFT 28 /* Instance shift */
+#define IFM_OMASK 0x0000ff00 /* Type specific options */
+#define IFM_GMASK 0x0ff00000 /* Global options */
+
+/*
+ * Status bits
+ */
+#define IFM_AVALID 0x00000001 /* Active bit valid */
+#define IFM_ACTIVE 0x00000002 /* Interface attached to working net */
+
+/*
+ * Macros to extract various bits of information from the media word.
+ */
+#define IFM_TYPE(x) ((x) & IFM_NMASK)
+#define IFM_SUBTYPE(x) ((x) & IFM_TMASK)
+#define IFM_TYPE_OPTIONS(x) ((x) & IFM_OMASK)
+#define IFM_INST(x) (((x) & IFM_IMASK) >> IFM_ISHIFT)
+#define IFM_OPTIONS(x) ((x) & (IFM_OMASK|IFM_GMASK))
+
+#define IFM_INST_MAX IFM_INST(IFM_IMASK)
+
+/*
+ * Macro to create a media word.
+ */
+#define IFM_MAKEWORD(type, subtype, options, instance) \
+ ((type) | (subtype) | (options) | ((instance) << IFM_ISHIFT))
+
+/*
+ * NetBSD extension not defined in the BSDI API. This is used in various
+ * places to get the canonical description for a given type/subtype.
+ *
+ * NOTE: all but the top-level type descriptions must contain NO whitespace!
+ * Otherwise, parsing these in ifconfig(8) would be a nightmare.
+ */
+struct ifmedia_description {
+ int ifmt_word; /* word value; may be masked */
+ const char *ifmt_string; /* description */
+};
+
+#define IFM_TYPE_DESCRIPTIONS { \
+ { IFM_ETHER, "Ethernet" }, \
+ { IFM_TOKEN, "Token ring" }, \
+ { IFM_FDDI, "FDDI" }, \
+ { IFM_IEEE80211, "IEEE 802.11 Wireless Ethernet" }, \
+ { 0, NULL }, \
+}
+
+#define IFM_SUBTYPE_ETHERNET_DESCRIPTIONS { \
+ { IFM_10_T, "10baseT/UTP" }, \
+ { IFM_10_2, "10base2/BNC" }, \
+ { IFM_10_5, "10base5/AUI" }, \
+ { IFM_100_TX, "100baseTX" }, \
+ { IFM_100_FX, "100baseFX" }, \
+ { IFM_100_T4, "100baseT4" }, \
+ { IFM_100_VG, "100baseVG" }, \
+ { IFM_100_T2, "100baseT2" }, \
+ { IFM_10_STP, "10baseSTP" }, \
+ { IFM_10_FL, "10baseFL" }, \
+ { IFM_1000_SX, "1000baseSX" }, \
+ { IFM_1000_LX, "1000baseLX" }, \
+ { IFM_1000_CX, "1000baseCX" }, \
+ { IFM_1000_T, "1000baseTX" }, \
+ { IFM_1000_T, "1000baseT" }, \
+ { IFM_HPNA_1, "homePNA" }, \
+ { 0, NULL }, \
+}
+
+#define IFM_SUBTYPE_ETHERNET_ALIASES { \
+ { IFM_10_T, "UTP" }, \
+ { IFM_10_T, "10UTP" }, \
+ { IFM_10_2, "BNC" }, \
+ { IFM_10_2, "10BNC" }, \
+ { IFM_10_5, "AUI" }, \
+ { IFM_10_5, "10AUI" }, \
+ { IFM_100_TX, "100TX" }, \
+ { IFM_100_T4, "100T4" }, \
+ { IFM_100_VG, "100VG" }, \
+ { IFM_100_T2, "100T2" }, \
+ { IFM_10_STP, "10STP" }, \
+ { IFM_10_FL, "10FL" }, \
+ { IFM_1000_SX, "1000SX" }, \
+ { IFM_1000_LX, "1000LX" }, \
+ { IFM_1000_CX, "1000CX" }, \
+ { IFM_1000_T, "1000TX" }, \
+ { IFM_1000_T, "1000T" }, \
+ { 0, NULL }, \
+}
+
+#define IFM_SUBTYPE_ETHERNET_OPTION_DESCRIPTIONS { \
+ { 0, NULL }, \
+}
+
+#define IFM_SUBTYPE_TOKENRING_DESCRIPTIONS { \
+ { IFM_TOK_STP4, "DB9/4Mbit" }, \
+ { IFM_TOK_STP16, "DB9/16Mbit" }, \
+ { IFM_TOK_UTP4, "UTP/4Mbit" }, \
+ { IFM_TOK_UTP16, "UTP/16Mbit" }, \
+ { IFM_TOK_STP100, "STP/100Mbit" }, \
+ { IFM_TOK_UTP100, "UTP/100Mbit" }, \
+ { 0, NULL }, \
+}
+
+#define IFM_SUBTYPE_TOKENRING_ALIASES { \
+ { IFM_TOK_STP4, "4STP" }, \
+ { IFM_TOK_STP16, "16STP" }, \
+ { IFM_TOK_UTP4, "4UTP" }, \
+ { IFM_TOK_UTP16, "16UTP" }, \
+ { IFM_TOK_STP100, "100STP" }, \
+ { IFM_TOK_UTP100, "100UTP" }, \
+ { 0, NULL }, \
+}
+
+#define IFM_SUBTYPE_TOKENRING_OPTION_DESCRIPTIONS { \
+ { IFM_TOK_ETR, "EarlyTokenRelease" }, \
+ { IFM_TOK_SRCRT, "SourceRouting" }, \
+ { IFM_TOK_ALLR, "AllRoutes" }, \
+ { IFM_TOK_DTR, "Dedicated" }, \
+ { IFM_TOK_CLASSIC,"Classic" }, \
+ { IFM_TOK_AUTO, " " }, \
+ { 0, NULL }, \
+}
+
+#define IFM_SUBTYPE_FDDI_DESCRIPTIONS { \
+ { IFM_FDDI_SMF, "Single-mode" }, \
+ { IFM_FDDI_MMF, "Multi-mode" }, \
+ { IFM_FDDI_UTP, "UTP" }, \
+ { 0, NULL }, \
+}
+
+#define IFM_SUBTYPE_FDDI_ALIASES { \
+ { IFM_FDDI_SMF, "SMF" }, \
+ { IFM_FDDI_MMF, "MMF" }, \
+ { IFM_FDDI_UTP, "CDDI" }, \
+ { 0, NULL }, \
+}
+
+#define IFM_SUBTYPE_FDDI_OPTION_DESCRIPTIONS { \
+ { IFM_FDDI_DA, "Dual-attach" }, \
+ { 0, NULL }, \
+}
+
+#define IFM_SUBTYPE_IEEE80211_DESCRIPTIONS { \
+ { IFM_IEEE80211_FH1, "FH/1Mbps" }, \
+ { IFM_IEEE80211_FH2, "FH/2Mbps" }, \
+ { IFM_IEEE80211_DS1, "DS/1Mbps" }, \
+ { IFM_IEEE80211_DS2, "DS/2Mbps" }, \
+ { IFM_IEEE80211_DS5, "DS/5.5Mbps" }, \
+ { IFM_IEEE80211_DS11, "DS/11Mbps" }, \
+ { IFM_IEEE80211_DS22, "DS/22Mbps" }, \
+ { IFM_IEEE80211_ODFM6, "ODFM/6Mbps" }, \
+ { IFM_IEEE80211_ODFM9, "ODFM/9Mbps" }, \
+ { IFM_IEEE80211_ODFM12, "ODFM/12Mbps" }, \
+ { IFM_IEEE80211_ODFM18, "ODFM/18Mbps" }, \
+ { IFM_IEEE80211_ODFM24, "ODFM/24Mbps" }, \
+ { IFM_IEEE80211_ODFM36, "ODFM/36Mbps" }, \
+ { IFM_IEEE80211_ODFM48, "ODFM/48Mbps" }, \
+ { IFM_IEEE80211_ODFM54, "ODFM/54Mbps" }, \
+ { IFM_IEEE80211_ODFM72, "ODFM/72Mbps" }, \
+ { 0, NULL }, \
+}
+
+#define IFM_SUBTYPE_IEEE80211_ALIASES { \
+ { IFM_IEEE80211_FH1, "FH1" }, \
+ { IFM_IEEE80211_FH2, "FH2" }, \
+ { IFM_IEEE80211_FH1, "FrequencyHopping/1Mbps" }, \
+ { IFM_IEEE80211_FH2, "FrequencyHopping/2Mbps" }, \
+ { IFM_IEEE80211_DS1, "DS1" }, \
+ { IFM_IEEE80211_DS2, "DS2" }, \
+ { IFM_IEEE80211_DS5, "DS5.5" }, \
+ { IFM_IEEE80211_DS11, "DS11" }, \
+ { IFM_IEEE80211_DS22, "DS22" }, \
+ { IFM_IEEE80211_DS1, "DirectSequence/1Mbps" }, \
+ { IFM_IEEE80211_DS2, "DirectSequence/2Mbps" }, \
+ { IFM_IEEE80211_DS5, "DirectSequence/5.5Mbps" }, \
+ { IFM_IEEE80211_DS11, "DirectSequence/11Mbps" }, \
+ { IFM_IEEE80211_DS22, "DirectSequence/22Mbps" }, \
+ { IFM_IEEE80211_ODFM6, "ODFM6" }, \
+ { IFM_IEEE80211_ODFM9, "ODFM9" }, \
+ { IFM_IEEE80211_ODFM12, "ODFM12" }, \
+ { IFM_IEEE80211_ODFM18, "ODFM18" }, \
+ { IFM_IEEE80211_ODFM24, "ODFM24" }, \
+ { IFM_IEEE80211_ODFM36, "ODFM36" }, \
+ { IFM_IEEE80211_ODFM48, "ODFM48" }, \
+ { IFM_IEEE80211_ODFM54, "ODFM54" }, \
+ { IFM_IEEE80211_ODFM72, "ODFM72" }, \
+ { 0, NULL }, \
+}
+
+#define IFM_SUBTYPE_IEEE80211_OPTION_DESCRIPTIONS { \
+ { IFM_IEEE80211_ADHOC, "adhoc" }, \
+ { IFM_IEEE80211_HOSTAP, "hostap" }, \
+ { IFM_IEEE80211_IBSS, "ibss" }, \
+ { IFM_IEEE80211_IBSSMASTER, "ibss-master" }, \
+ { 0, NULL }, \
+}
+
+#define IFM_SUBTYPE_SHARED_DESCRIPTIONS { \
+ { IFM_AUTO, "autoselect" }, \
+ { IFM_MANUAL, "manual" }, \
+ { IFM_NONE, "none" }, \
+ { 0, NULL }, \
+}
+
+#define IFM_SUBTYPE_SHARED_ALIASES { \
+ { IFM_AUTO, "auto" }, \
+ { 0, NULL }, \
+}
+
+#define IFM_SHARED_OPTION_DESCRIPTIONS { \
+ { IFM_FDX, "full-duplex" }, \
+ { IFM_HDX, "half-duplex" }, \
+ { IFM_FLAG0, "flag0" }, \
+ { IFM_FLAG1, "flag1" }, \
+ { IFM_FLAG2, "flag2" }, \
+ { IFM_LOOP, "hw-loopback" }, \
+ { 0, NULL }, \
+}
+
+#endif /* _NET_IF_MEDIA_H_ */
diff --git a/c/src/libchip/network/mii.h b/c/src/libchip/network/mii.h
new file mode 100644
index 0000000000..dca3ff4ed5
--- /dev/null
+++ b/c/src/libchip/network/mii.h
@@ -0,0 +1,206 @@
+/* $NetBSD: mii.h,v 1.9 2001/05/31 03:07:14 thorpej Exp $ */
+
+/*
+ * Copyright (c) 1997 Manuel Bouyer. All rights reserved.
+ *
+ * Modification to match BSD/OS 3.0 MII interface by Jason R. Thorpe,
+ * Numerical Aerospace Simulation Facility, NASA Ames Research Center.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Manuel Bouyer.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD: /repoman/r/ncvs/src/sys/dev/mii/mii.h,v 1.4 2002/04/29 11:57:28 phk Exp $
+ */
+
+#ifndef _DEV_MII_MII_H_
+#define _DEV_MII_MII_H_
+
+/*
+ * Registers common to all PHYs.
+ */
+
+#define MII_NPHY 32 /* max # of PHYs per MII */
+
+/*
+ * MII commands, used if a device must drive the MII lines
+ * manually.
+ */
+#define MII_COMMAND_START 0x01
+#define MII_COMMAND_READ 0x02
+#define MII_COMMAND_WRITE 0x01
+#define MII_COMMAND_ACK 0x02
+
+#define MII_BMCR 0x00 /* Basic mode control register (rw) */
+#define BMCR_RESET 0x8000 /* reset */
+#define BMCR_LOOP 0x4000 /* loopback */
+#define BMCR_SPEED0 0x2000 /* speed selection (LSB) */
+#define BMCR_AUTOEN 0x1000 /* autonegotiation enable */
+#define BMCR_PDOWN 0x0800 /* power down */
+#define BMCR_ISO 0x0400 /* isolate */
+#define BMCR_STARTNEG 0x0200 /* restart autonegotiation */
+#define BMCR_FDX 0x0100 /* Set duplex mode */
+#define BMCR_CTEST 0x0080 /* collision test */
+#define BMCR_SPEED1 0x0040 /* speed selection (MSB) */
+
+#define BMCR_S10 0x0000 /* 10 Mb/s */
+#define BMCR_S100 BMCR_SPEED0 /* 100 Mb/s */
+#define BMCR_S1000 BMCR_SPEED1 /* 1000 Mb/s */
+
+#define BMCR_SPEED(x) ((x) & (BMCR_SPEED0|BMCR_SPEED1))
+
+#define MII_BMSR 0x01 /* Basic mode status register (ro) */
+#define BMSR_100T4 0x8000 /* 100 base T4 capable */
+#define BMSR_100TXFDX 0x4000 /* 100 base Tx full duplex capable */
+#define BMSR_100TXHDX 0x2000 /* 100 base Tx half duplex capable */
+#define BMSR_10TFDX 0x1000 /* 10 base T full duplex capable */
+#define BMSR_10THDX 0x0800 /* 10 base T half duplex capable */
+#define BMSR_100T2FDX 0x0400 /* 100 base T2 full duplex capable */
+#define BMSR_100T2HDX 0x0200 /* 100 base T2 half duplex capable */
+#define BMSR_EXTSTAT 0x0100 /* Extended status in register 15 */
+#define BMSR_MFPS 0x0040 /* MII Frame Preamble Suppression */
+#define BMSR_ACOMP 0x0020 /* Autonegotiation complete */
+#define BMSR_RFAULT 0x0010 /* Link partner fault */
+#define BMSR_ANEG 0x0008 /* Autonegotiation capable */
+#define BMSR_LINK 0x0004 /* Link status */
+#define BMSR_JABBER 0x0002 /* Jabber detected */
+#define BMSR_EXTCAP 0x0001 /* Extended capability */
+
+/*
+ * Note that the EXTSTAT bit indicates that there is extended status
+ * info available in register 15, but 802.3 section 22.2.4.3 also
+ * states that that all 1000 Mb/s capable PHYs will set this bit to 1.
+ */
+#if 0
+#define BMSR_MEDIAMASK (BMSR_100T4|BMSR_100TXFDX|BMSR_100TXHDX|BMSR_10TFDX| \
+ BMSR_10THDX|BMSR_ANEG)
+
+#else
+/* NetBSD uses: */
+#define BMSR_MEDIAMASK (BMSR_100T4|BMSR_100TXFDX|BMSR_100TXHDX| \
+ BMSR_10TFDX|BMSR_10THDX|BMSR_100T2FDX|BMSR_100T2HDX)
+#endif
+
+/*
+ * Convert BMSR media capabilities to ANAR bits for autonegotiation.
+ * Note the shift chopps off the BMSR_ANEG bit.
+ */
+#define BMSR_MEDIA_TO_ANAR(x) (((x) & BMSR_MEDIAMASK) >> 6)
+
+#define MII_PHYIDR1 0x02 /* ID register 1 (ro) */
+
+#define MII_PHYIDR2 0x03 /* ID register 2 (ro) */
+#define IDR2_OUILSB 0xfc00 /* OUI LSB */
+#define IDR2_MODEL 0x03f0 /* vendor model */
+#define IDR2_REV 0x000f /* vendor revision */
+
+#define MII_OUI(id1, id2) (((id1) << 6) | ((id2) >> 10))
+#define MII_MODEL(id2) (((id2) & IDR2_MODEL) >> 4)
+#define MII_REV(id2) ((id2) & IDR2_REV)
+
+#define MII_ANAR 0x04 /* Autonegotiation advertisement (rw) */
+ /* section 28.2.4.1 and 37.2.6.1 */
+#define ANAR_NP 0x8000 /* Next page (ro) */
+#define ANAR_ACK 0x4000 /* link partner abilities acknowledged (ro) */
+#define ANAR_RF 0x2000 /* remote fault (ro) */
+#define ANAR_FC 0x0400 /* local device supports PAUSE */
+#define ANAR_T4 0x0200 /* local device supports 100bT4 */
+#define ANAR_TX_FD 0x0100 /* local device supports 100bTx FD */
+#define ANAR_TX 0x0080 /* local device supports 100bTx */
+#define ANAR_10_FD 0x0040 /* local device supports 10bT FD */
+#define ANAR_10 0x0020 /* local device supports 10bT */
+#define ANAR_CSMA 0x0001 /* protocol selector CSMA/CD */
+
+#define ANAR_X_FD 0x0020 /* local device supports 1000BASE-X FD */
+#define ANAR_X_HD 0x0040 /* local device supports 1000BASE-X HD */
+#define ANAR_X_PAUSE_NONE (0 << 7)
+#define ANAR_X_PAUSE_SYM (1 << 7)
+#define ANAR_X_PAUSE_ASYM (2 << 7)
+#define ANAR_X_PAUSE_TOWARDS (3 << 7)
+
+#define MII_ANLPAR 0x05 /* Autonegotiation lnk partner abilities (rw) */
+ /* section 28.2.4.1 and 37.2.6.1 */
+#define ANLPAR_NP 0x8000 /* Next page (ro) */
+#define ANLPAR_ACK 0x4000 /* link partner accepted ACK (ro) */
+#define ANLPAR_RF 0x2000 /* remote fault (ro) */
+#define ANLPAR_FC 0x0400 /* link partner supports PAUSE */
+#define ANLPAR_T4 0x0200 /* link partner supports 100bT4 */
+#define ANLPAR_TX_FD 0x0100 /* link partner supports 100bTx FD */
+#define ANLPAR_TX 0x0080 /* link partner supports 100bTx */
+#define ANLPAR_10_FD 0x0040 /* link partner supports 10bT FD */
+#define ANLPAR_10 0x0020 /* link partner supports 10bT */
+#define ANLPAR_CSMA 0x0001 /* protocol selector CSMA/CD */
+
+#define ANLPAR_X_FD 0x0020 /* local device supports 1000BASE-X FD */
+#define ANLPAR_X_HD 0x0040 /* local device supports 1000BASE-X HD */
+#define ANLPAR_X_PAUSE_MASK (3 << 7)
+#define ANLPAR_X_PAUSE_NONE (0 << 7)
+#define ANLPAR_X_PAUSE_SYM (1 << 7)
+#define ANLPAR_X_PAUSE_ASYM (2 << 7)
+#define ANLPAR_X_PAUSE_TOWARDS (3 << 7)
+
+#define MII_ANER 0x06 /* Autonegotiation expansion (ro) */
+ /* section 28.2.4.1 and 37.2.6.1 */
+#define ANER_MLF 0x0010 /* multiple link detection fault */
+#define ANER_LPNP 0x0008 /* link parter next page-able */
+#define ANER_NP 0x0004 /* next page-able */
+#define ANER_PAGE_RX 0x0002 /* Page received */
+#define ANER_LPAN 0x0001 /* link parter autoneg-able */
+
+#define MII_ANNP 0x07 /* Autonegotiation next page */
+ /* section 28.2.4.1 and 37.2.6.1 */
+
+#define MII_ANLPRNP 0x08 /* Autonegotiation link partner rx next page */
+ /* section 32.5.1 and 37.2.6.1 */
+
+ /* This is also the 1000baseT control register */
+#define MII_100T2CR 0x09 /* 100base-T2 control register */
+#define GTCR_TEST_MASK 0xe000 /* see 802.3ab ss. 40.6.1.1.2 */
+#define GTCR_MAN_MS 0x1000 /* enable manual master/slave control */
+#define GTCR_ADV_MS 0x0800 /* 1 = adv. master, 0 = adv. slave */
+#define GTCR_PORT_TYPE 0x0400 /* 1 = DCE, 0 = DTE (NIC) */
+#define GTCR_ADV_1000TFDX 0x0200 /* adv. 1000baseT FDX */
+#define GTCR_ADV_1000THDX 0x0100 /* adv. 1000baseT HDX */
+
+ /* This is also the 1000baseT status register */
+#define MII_100T2SR 0x0a /* 100base-T2 status register */
+#define GTSR_MAN_MS_FLT 0x8000 /* master/slave config fault */
+#define GTSR_MS_RES 0x4000 /* result: 1 = master, 0 = slave */
+#define GTSR_LRS 0x2000 /* local rx status, 1 = ok */
+#define GTSR_RRS 0x1000 /* remove rx status, 1 = ok */
+#define GTSR_LP_1000TFDX 0x0800 /* link partner 1000baseT FDX capable */
+#define GTSR_LP_1000THDX 0x0400 /* link partner 1000baseT HDX capable */
+#define GTSR_LP_ASM_DIR 0x0200 /* link partner asym. pause dir. capable */
+#define GTSR_IDLE_ERR 0x00ff /* IDLE error count */
+
+#define MII_EXTSR 0x0f /* Extended status register */
+#define EXTSR_1000XFDX 0x8000 /* 1000X full-duplex capable */
+#define EXTSR_1000XHDX 0x4000 /* 1000X half-duplex capable */
+#define EXTSR_1000TFDX 0x2000 /* 1000T full-duplex capable */
+#define EXTSR_1000THDX 0x1000 /* 1000T half-duplex capable */
+
+#define EXTSR_MEDIAMASK (EXTSR_1000XFDX|EXTSR_1000XHDX| \
+ EXTSR_1000TFDX|EXTSR_1000THDX)
+
+#endif /* _DEV_MII_MII_H_ */