summaryrefslogtreecommitdiffstats
path: root/c
diff options
context:
space:
mode:
authorJoel Sherrill <joel.sherrill@OARcorp.com>2002-09-07 23:09:47 +0000
committerJoel Sherrill <joel.sherrill@OARcorp.com>2002-09-07 23:09:47 +0000
commita2117cd64a9d25926564e43ea2806f7eacde7343 (patch)
tree2f088b9c41fbff16b2ca11adca1b5ef4d871c3c9 /c
parent2002-09-07 Joel Sherrill <joel@OARcorp.com> (diff)
downloadrtems-a2117cd64a9d25926564e43ea2806f7eacde7343.tar.bz2
2002-09-07 Chris Johns <ccj@acm.org>
* network/Makefile.am, network/README.cs8900, network/cs8900.c, network/cs8900.h: Significant update which corrects the problem where the cs8900.c file was actually the BSP glue. Joel did some hacking so this file will compile. Previously it required providing a target.h file to compile. * network/cs8900.c.bsp: New file.
Diffstat (limited to 'c')
-rw-r--r--c/src/libchip/ChangeLog9
-rw-r--r--c/src/libchip/network/Makefile.am5
-rw-r--r--c/src/libchip/network/README.cs89008
-rw-r--r--c/src/libchip/network/cs8900.c1305
-rw-r--r--c/src/libchip/network/cs8900.c.bsp297
-rw-r--r--c/src/libchip/network/cs8900.h8
6 files changed, 1437 insertions, 195 deletions
diff --git a/c/src/libchip/ChangeLog b/c/src/libchip/ChangeLog
index c451f8f901..f97cf0cc0d 100644
--- a/c/src/libchip/ChangeLog
+++ b/c/src/libchip/ChangeLog
@@ -1,3 +1,12 @@
+2002-09-07 Chris Johns <ccj@acm.org>
+
+ * network/Makefile.am, network/README.cs8900, network/cs8900.c,
+ network/cs8900.h: Significant update which corrects the problem
+ where the cs8900.c file was actually the BSP glue. Joel did
+ some hacking so this file will compile. Previously it required
+ providing a target.h file to compile.
+ * network/cs8900.c.bsp: New file.
+
2002-08-11 Ralf Corsepius <corsepiu@faw.uni-ulm.de>
* network/Makefile.am: Use .$(OBJEXT) instead of .o.
diff --git a/c/src/libchip/network/Makefile.am b/c/src/libchip/network/Makefile.am
index c916be1abd..48a052ed6a 100644
--- a/c/src/libchip/network/Makefile.am
+++ b/c/src/libchip/network/Makefile.am
@@ -8,8 +8,7 @@ include_libchipdir = $(includedir)/libchip
LIBNAME = libnetchip
LIB = $(ARCH)/$(LIBNAME).a
-# add cs8900.c to work with it and make it compile
-C_FILES = dec21140.c i82586.c sonic.c if_fxp.c
+C_FILES = cs8900.c dec21140.c i82586.c sonic.c if_fxp.c
C_O_FILES = $(C_FILES:%.c=$(ARCH)/%.$(OBJEXT))
include_libchip_HEADERS = cs8900.h i82586var.h if_fxpvar.h sonic.h
@@ -52,6 +51,6 @@ endif
.PRECIOUS: $(LIB)
EXTRA_DIST = README README.cs8900 README.dec21140 README.i82586 README.sonic \
- cs8900.c dec21140.c i82586.c if_fxp.c sonic.c
+ cs8900.c cs8900.c.bsp dec21140.c i82586.c if_fxp.c sonic.c
include $(top_srcdir)/../../../automake/local.am
diff --git a/c/src/libchip/network/README.cs8900 b/c/src/libchip/network/README.cs8900
index 8cd31d91e4..8d677a23ce 100644
--- a/c/src/libchip/network/README.cs8900
+++ b/c/src/libchip/network/README.cs8900
@@ -2,6 +2,14 @@
# $Id$
#
+Target Support
+==============
+
+The target is required to provide the low level support routines as
+listed in the Configuration section of this file.
+
+The file cs8900.c.bsp is an example BSP file for a Coldfire processor.
+
Conditionals
============
CS8900_DATA_BUS_SWAPPED - XXX
diff --git a/c/src/libchip/network/cs8900.c b/c/src/libchip/network/cs8900.c
index f445617cd8..4a00853b1c 100644
--- a/c/src/libchip/network/cs8900.c
+++ b/c/src/libchip/network/cs8900.c
@@ -10,288 +10,1215 @@
COPYRIGHT (c) 1989-1998.
On-Line Applications Research Corporation (OAR).
+ Copyright assigned to U.S. Government, 1994.
The license and distribution terms for this file may be
found in the file LICENSE in this distribution or at
http://www.OARcorp.com/rtems/license.html.
-
+
------------------------------------------------------------------------
CS8900 net boot driver.
+*/
+
+#include <sys/errno.h>
+#include <string.h>
+#include <stdio.h>
+
+/* #include <target.h>
+ chris explain what this is to contain and provide a default one */
+#include "cs8900.h"
+
+/***********************************************************
+ ***********************************************************
+ BEGIN SECTION OF DEFAULT DEFINES
+ ***********************************************************
+ ***********************************************************/
+
+/*
+ * Number of devices supported by this driver
*/
+#ifndef CS8900_DEVICES
+#define CS8900_DEVICES 1
+#endif
-#include <rtems/bspIo.h>
-#include <rtems.h>
+/*
+ * This variable really should come from a per device configuration
+ * table so the base can vary by adapter.
+ */
-#include <libchip/cs8900.h>
+#ifndef CS8900_IO_BASE
+extern unsigned int bsp_cs8900_io_base;
+#define CS8900_IO_BASE bsp_cs8900_io_base
+#endif
/*
- * Our local data.
+ * This variable really should come from a per device configuration
+ * table so the base can vary by adapter.
+ */
+
+#ifndef CS8900_MEMORY_BASE
+extern unsigned int bsp_cs8900_memory_base;
+#define CS8900_MEMORY_BASE bsp_cs8900_memory_base
+#endif
+
+/*
+ * This could go to a BSP provided callout.
+ */
+#ifndef WATCHDOG_TOGGLE
+#define WATCHDOG_TOGGLE()
+#endif
+
+/*
+ * This variable really should come from a per device configuration
+ * table so the base can vary by adapter.
+ *
+ * chris this is probably not a good default --joel
*/
-#ifdef CS8900_VERBOSE
-static BOOLEAN cs8900_io_verbose;
+#ifndef CS8900_RX_QUEUE_SIZE
+#define CS8900_RX_QUEUE_SIZE 1
#endif
-static rtems_isr_void_entry old_handler[CS8900_DEVICES];
-static void *old_parameter[CS8900_DEVICES];
+/***********************************************************
+ ***********************************************************
+ END SECTION OF DEFAULT DEFINES
+ ***********************************************************
+ ***********************************************************/
/*
- * Tables of IO addresses and interrupt levels for each device attached.
+ * We expect to be able to read a complete packet into an mbuf.
*/
-static const unsigned long ethernet_io_base[CS8900_DEVICES] =
+#if (MCLBYTES < 1520)
+#error "CS8900 Driver must have MCLBYTES >= 1520"
+#endif
+
+/*
+ * Task event usage.
+ */
+
+#define CS8900_RX_OK_EVENT RTEMS_EVENT_1
+#define CS8900_TX_START_EVENT RTEMS_EVENT_1
+#define CS8900_TX_OK_EVENT RTEMS_EVENT_2
+#define CS8900_TX_WAIT_EVENT RTEMS_EVENT_3
+
+/*
+ * Our local data.
+ */
+
+static cs8900_device cs8900[CS8900_DEVICES];
+
+/*
+ * IO Packet Page inteface.
+ */
+
+static inline unsigned short
+io_pp_get_reg_16 (int dev, unsigned short reg)
{
- ETHERNET_BASE
-};
+ cs8900_io_set_reg (dev, CS8900_IO_BASE + CS8900_IO_PACKET_PAGE_PTR,
+ 0x3000 | CS8900_PPP_AUTO_INCREMENT | reg);
+ return cs8900_io_get_reg (dev, CS8900_IO_BASE + CS8900_IO_PP_DATA_PORT0);
+}
-static const unsigned long ethernet_mem_base[CS8900_DEVICES] =
+static inline unsigned long
+io_pp_get_reg_32 (int dev, unsigned short reg)
{
- ETHERNET_BASE + CS8900_MEMORY_BASE
-};
+ cs8900_io_set_reg (dev, CS8900_IO_BASE + CS8900_IO_PACKET_PAGE_PTR,
+ 0x3000 | CS8900_PPP_AUTO_INCREMENT | reg);
+ return ((cs8900_io_get_reg (dev, CS8900_IO_BASE + CS8900_IO_PP_DATA_PORT0) << 16) |
+ cs8900_io_get_reg (dev, CS8900_IO_BASE + CS8900_IO_PP_DATA_PORT1));
+}
-static const unsigned int ethernet_irq_level[CS8900_DEVICES] =
+static inline void
+io_pp_set_reg_16 (int dev, unsigned short reg, unsigned short data)
{
- ETHERNET_IRQ_LEVEL
-};
+ cs8900_io_set_reg (dev, CS8900_IO_BASE + CS8900_IO_PACKET_PAGE_PTR,
+ 0x3000 | CS8900_PPP_AUTO_INCREMENT | reg);
+ cs8900_io_set_reg (dev, CS8900_IO_BASE + CS8900_IO_PP_DATA_PORT0, data);
+}
-static const unsigned int ethernet_irq_priority[CS8900_DEVICES] =
+static inline void
+io_pp_set_reg_32 (int dev, unsigned short reg, unsigned long data)
{
- ETHERNET_IRQ_PRIORITY
-};
+ cs8900_io_set_reg (dev, CS8900_IO_BASE + CS8900_IO_PACKET_PAGE_PTR,
+ 0x3000 | CS8900_PPP_AUTO_INCREMENT | reg);
+ cs8900_io_set_reg (dev, CS8900_IO_BASE + CS8900_IO_PP_DATA_PORT0, data >> 16);
+ cs8900_io_set_reg (dev, CS8900_IO_BASE + CS8900_IO_PP_DATA_PORT1, data);
+}
-static const unsigned int ethernet_irq_vector[CS8900_DEVICES] =
+static inline void
+io_pp_bit_set_reg_16 (int dev, unsigned short reg, unsigned short mask)
{
- ETHERNET_IRQ_VECTOR,
-};
+ io_pp_set_reg_16 (dev, reg, io_pp_get_reg_16 (dev, reg) | mask);
+}
-void cs8900_io_set_reg (int dev, unsigned short reg, unsigned short data)
+static inline void
+io_pp_bit_clear_reg_16 (int dev, unsigned short reg, unsigned short mask)
{
-#ifdef CS8900_DATA_BUS_SWAPPED
- data = (data >> 8) | (data << 8);
-#endif
+ io_pp_set_reg_16 (dev, reg, io_pp_get_reg_16 (dev, reg) & ~mask);
+}
-#ifdef CS8900_VERBOSE
- if (cs8900_io_verbose)
- printf ("CS8900: io set reg=0x%04x, data=0x%04x\n", reg, data);
-#endif
-
- WRITE_REGISTER_16 (ethernet_io_base[dev] + reg, data);
+/*
+ * Memory Mapped Packet Page interface.
+ */
+
+static inline unsigned short
+mem_pp_get_reg (int dev, unsigned short reg)
+{
+ return cs8900_mem_get_reg (dev, CS8900_MEMORY_BASE + reg);
}
-unsigned short cs8900_io_get_reg (int dev, unsigned short reg)
+static inline void
+mem_pp_set_reg (int dev, unsigned short reg, unsigned short data)
{
- unsigned long data;
+ cs8900_mem_set_reg (dev, CS8900_MEMORY_BASE + reg, data);
+}
- READ_REGISTER_16 (ethernet_io_base[dev] + reg, data);
+static inline void
+mem_pp_bit_set_reg (int dev, unsigned short reg, unsigned short mask)
+{
+ mem_pp_set_reg (dev, reg, mem_pp_get_reg (dev, reg) | mask);
+}
-#ifdef CS8900_DATA_BUS_SWAPPED
- data = (data >> 8) | (data << 8);
-#endif
-
-#ifdef CS8900_VERBOSE
- if (cs8900_io_verbose)
- printk ("CS8900: io get reg=0x%04x, data=0x%04x\n", reg, data);
-#endif
-
- return data;
+static inline void
+mem_pp_bit_clear_reg (int dev, unsigned short reg, unsigned short mask)
+{
+ mem_pp_set_reg (dev, reg, mem_pp_get_reg (dev, reg) & ~mask);
}
-void cs8900_mem_set_reg (int dev, unsigned long reg, unsigned short data)
+/*
+ * Trace defines and control structures.
+ */
+
+#define CS8900_T_INT (0)
+#define CS8900_T_RX_OK (1)
+#define CS8900_T_RX_DROPPED (2)
+#define CS8900_T_NO_MBUF (3)
+#define CS8900_T_NO_CLUSTERS (4)
+#define CS8900_T_RX_BEGIN (5)
+#define CS8900_T_RX_END (6)
+
+#if CS8900_TRACE
+
+static const char *cs8900_trace_labels[] =
{
-#ifdef CS8900_DATA_BUS_SWAPPED
- data = (data >> 8) | (data << 8);
-#endif
+ "int",
+ "rx ok",
+ "rx dropped",
+ "no mbuf",
+ "no clusters",
+ "rx begin",
+ "rx end"
+};
-#ifdef CS8900_VERBOSE
- if (cs8900_io_verbose)
- printk ("CS8900: mem set reg=0x%04x, data=0x%04x\n", reg, data);
-#endif
+/*
+ * Assumes a micro-second timer such as the Coldfire.
+ */
- WRITE_REGISTER_16 (ethernet_io_base[dev] + reg, data);
-}
+rtems_unsigned32 rtems_read_timer ();
-unsigned short cs8900_mem_get_reg (int dev, unsigned long reg)
+static inline void
+cs8900_trace (cs8900_device *cs, unsigned short key, unsigned long var)
{
- unsigned short data;
- READ_REGISTER_16 (ethernet_io_base[dev] + reg, data);
+ rtems_interrupt_level level;
-#ifdef CS8900_DATA_BUS_SWAPPED
- data = (data >> 8) | (data << 8);
-#endif
-
-#ifdef CS8900_VERBOSE
- if (cs8900_io_verbose)
- printk ("CS8900: mem get reg=0x%04x, data=0x%04x\n", reg, data);
+ rtems_interrupt_disable (level);
+
+ if (cs->trace_in < CS8900_TRACE_SIZE)
+ {
+ cs->trace_key[cs->trace_in] = key;
+ cs->trace_var[cs->trace_in] = var;
+ cs->trace_time[cs->trace_in] = rtems_read_timer ();
+ cs->trace_in++;
+ }
+
+ rtems_interrupt_enable (level);
+}
+#else
+#define cs8900_trace(c, k, v)
#endif
- return data;
-}
+/*
+ * Bring the chip online.
+ */
-void cs8900_put_data_block (int dev, int len, unsigned char *data)
+static void
+cs8900_hardware_init (cs8900_device *cs)
{
-#ifndef CS8900_DATA_BUS_SWAPPED
- unsigned short swap_word;
-#endif
- unsigned short *src = (unsigned short *) ((unsigned long) data);
- unsigned short *dst = (unsigned short *) (ethernet_mem_base[dev] + CS8900_PP_TxFrameLoc);
+ unsigned long prod_id;
+ unsigned short status;
+ int dev = cs->dev;
+
+ /*
+ * Do nothing while the device is calibrating and checking the EEPROM.
+ * We must wait 20msecs.
+ */
+
+ io_pp_bit_set_reg_16 (dev, CS8900_PP_SelfCTL, CS8900_SELF_CTRL_RESET);
- while (len > 1)
+ rtems_task_wake_after (TOD_MILLISECONDS_TO_TICKS (20));
+
+ status = io_pp_get_reg_16 (dev, CS8900_PP_SelfST);
+
+ if (((status & CS8900_SELF_STATUS_INITD) == 0) ||
+ ((status & CS8900_SELF_STATUS_INITD) &&
+ (status & CS8900_SELF_STATUS_EEPROM_PRESENT) &&
+ (status & CS8900_SELF_STATUS_SIBUST)))
{
-#ifndef CS8900_DATA_BUS_SWAPPED
- swap_word = *src++;
- *dst++ = (swap_word >> 8) | (swap_word << 8);
-#else
- *dst++ = *src++;
-#endif
- len -= 2;
+ printf ("CS8900: %s. Initialisation aborted.\n",
+ (status & CS8900_SELF_STATUS_INITD) ?
+ "EEPROM read/write failed to complete" :
+ "Failed to complete to reset");
+ return;
}
+
+ /* Probe the device for its ID */
+
+ prod_id = io_pp_get_reg_32 (dev, CS8900_PP_PROD_ID);
- if (len)
+ if ((prod_id >> 16) != CS8900_ESIA_ID)
{
-#ifndef CS8900_DATA_BUS_SWAPPED
- swap_word = *src++;
- *dst++ = (swap_word >> 8) | (swap_word << 8);
-#else
- *dst++ = *src++;
-#endif
- }
+ printf ("CS9800: Invalid EISA ID, read product code 0x%08lx\n", prod_id);
+ return;
+ }
+
+ if ((prod_id & 0x000000ff) != 0)
+ {
+ printf ("CS9800: Unsupported product id, read product code 0x%08lx\n",
+ prod_id);
+ return;
+ }
+
+ printf ("CS8900 Rev %ld, %s, %s.\n",
+ (prod_id >> 8) & 0x1f,
+ status & CS8900_SELF_STATUS_3_3_V ? "3.3V" : "5.0V",
+ status & CS8900_SELF_STATUS_EEPROM_PRESENT ?
+ "EEPROM present" : "no EEPROM");
+
+ /*
+ * Switch to memory base accesses as they are faster. No indirect access.
+ */
+
+ io_pp_set_reg_16 (dev, CS8900_PP_MEM_BASE, CS8900_MEMORY_BASE);
+ io_pp_set_reg_16 (dev, CS8900_PP_MEM_BASE + 2, (CS8900_MEMORY_BASE >> 16) & 0xf);
+
+ io_pp_set_reg_16 (dev,
+ CS8900_PP_BusCTL,
+ CS8900_BUS_CTRL_RESET_RX_DMA |
+ CS8900_BUS_CTRL_USE_SA |
+ CS8900_BUS_CTRL_MEMORY_ENABLE);
+ io_pp_set_reg_16 (dev,
+ CS8900_PP_BusCTL,
+ CS8900_BUS_CTRL_USE_SA |
+ CS8900_BUS_CTRL_MEMORY_ENABLE);
+
+ /*
+ * We are now in memory mapped mode.
+ */
+
+ /*
+ * Program the Line Control register with the mode we want.
+ *
+ * No auto detect support at the moment. Only 10BaseT.
+ */
+
+ mem_pp_set_reg (dev, CS8900_PP_LineCFG, CS8900_LINE_CTRL_10BASET);
+
+ /*
+ * Ask the user for the MAC address, the program into the device.
+ */
+
+#define MACO(o) cs->arpcom.ac_enaddr[o]
+
+ mem_pp_set_reg (dev, CS8900_PP_IA,
+ (((unsigned int) MACO (1)) << 8) |
+ ((unsigned int) MACO (0)));
+ mem_pp_set_reg (dev, CS8900_PP_IA + 2,
+ (((unsigned int) MACO (3)) << 8) |
+ ((unsigned int) MACO (2)));
+ mem_pp_set_reg (dev, CS8900_PP_IA + 4,
+ (((unsigned int) MACO (5)) << 8) |
+ ((unsigned int) MACO (4)));
+
+ /*
+ * Set the Buffer configuration.
+ */
+
+ mem_pp_set_reg (dev, CS8900_PP_BufCFG,
+ CS8900_BUFFER_CONFIG_RDY_FOR_TX |
+ CS8900_BUFFER_CONFIG_TX_UNDERRUN |
+ CS8900_BUFFER_CONFIG_TX_COL_OVF |
+ CS8900_BUFFER_CONFIG_RX_MISSED_OVF);
+
+ /*
+ * Set the Receiver configuration.
+ */
+
+ mem_pp_set_reg (dev, CS8900_PP_RxCFG,
+ CS8900_RX_CONFIG_RX_OK |
+ CS8900_RX_CONFIG_CRC_ERROR |
+ CS8900_RX_CONFIG_RUNT|
+ CS8900_RX_CONFIG_EXTRA_DATA);
+
+ /*
+ * Set the Receiver control.
+ */
+
+ mem_pp_set_reg (dev, CS8900_PP_RxCTL,
+ CS8900_RX_CTRL_RX_OK |
+ CS8900_RX_CTRL_MULTICAST |
+ CS8900_RX_CTRL_INDIVIDUAL |
+ CS8900_RX_CTRL_BROADCAST);
+
+ /*
+ * Set the Transmitter configuration.
+ */
+
+ mem_pp_set_reg (dev, CS8900_PP_TxCFG,
+ CS8900_TX_CONFIG_TX_OK |
+ CS8900_TX_CONFIG_OUT_OF_WINDOW |
+ CS8900_TX_CONFIG_JABBER |
+ CS8900_TX_CONFIG_16_COLLISION);
+
+ /*
+ * Attach the interrupt handler.
+ */
+
+ cs8900_attach_interrupt (dev, cs);
+
+ /*
+ * Program the interrupt level we require then enable interrupts.
+ */
+
+ mem_pp_set_reg (dev, CS8900_PP_INT, 0);
+
+ mem_pp_bit_set_reg (dev, CS8900_PP_BusCTL,
+ CS8900_BUS_CTRL_ENABLE_INT);
}
-unsigned short cs8900_get_data_block (int dev, unsigned char *data)
+rtems_isr
+cs8900_interrupt (rtems_vector_number v, void *csp)
{
- unsigned short swap_word;
- volatile unsigned short *src = (unsigned short *) (ethernet_mem_base[dev] + CS8900_PP_RxLength);
- unsigned short *dst;
- unsigned short len;
- unsigned short rx_len;
- unsigned short len_odd;
-
-#ifdef CS8900_DATA_BUS_SWAPPED
- swap_word = *src++;
- len = (swap_word >> 8) | (swap_word << 8);
-#else
- len = *src++;
-#endif
+ cs8900_device *cs = csp;
+ int dev = cs->dev;
+ unsigned short isq = 0;
+ struct mbuf *m;
+ unsigned char *p;
+
+ ++cs->eth_stats.interrupts;
+
+ while (1)
+ {
+ isq = mem_pp_get_reg (dev, CS8900_PP_ISQ);
+
+ cs8900_trace (cs, CS8900_T_INT, isq);
+
+ WATCHDOG_TOGGLE ();
- dst = (unsigned short *) ((unsigned long) data);
+ /*
+ * No more interrupts to service.
+ */
+
+ if (isq == 0)
+ return;
+
+ switch (isq & 0x1f)
+ {
+ case 0x04:
+
+ /*
+ * RxEvent.
+ */
+
+ ++cs->eth_stats.rx_interrupts;
+
+ if (isq & CS8900_RX_EVENT_RX_OK)
+ {
+ m = cs->rx_ready_head;
+ if (m)
+ {
+ cs->rx_ready_head = m->m_nextpkt;
+ if (cs->rx_ready_head == 0)
+ cs->rx_ready_tail = 0;
+ m->m_nextpkt = 0;
+ cs->rx_ready_len--;
+
+ p = mtod (m, unsigned char *);
+
+ m->m_pkthdr.len = cs8900_get_data_block (dev, p);
+
+ if (cs->rx_loaded_tail == 0)
+ cs->rx_loaded_head = m;
+ else
+ cs->rx_loaded_tail->m_nextpkt = m;
+ cs->rx_loaded_tail = m;
+ cs->rx_loaded_len++;
+
+ if (cs->rx_loaded_len == 1)
+ {
+ cs8900_trace (cs, CS8900_T_RX_OK, cs->rx_loaded_len);
+ rtems_event_send (cs->rx_task, CS8900_RX_OK_EVENT);
+ }
+ }
+ else
+ {
+ ++cs->eth_stats.rx_dropped;
+
+ cs8900_trace (cs, CS8900_T_RX_DROPPED, cs->rx_loaded_len);
+
+ if (cs->rx_loaded_len == 0)
+ rtems_event_send (cs->rx_task, CS8900_RX_OK_EVENT);
+ }
+ }
+ else
+ {
+ if (isq & CS8900_RX_EVENT_CRC_ERROR)
+ ++cs->eth_stats.rx_crc_errors;
+
+ if (isq & CS8900_RX_EVENT_RUNT)
+ ++cs->eth_stats.rx_runt_errors;
+
+ if (isq & CS8900_RX_EVENT_EXTRA_DATA)
+ ++cs->eth_stats.rx_oversize_errors;
+ }
+ break;
+
+ case 0x08:
+
+ /*
+ * TxEvent.
+ */
+
+ ++cs->eth_stats.tx_interrupts;
+
+ if (cs->tx_active)
+ {
+ if (isq & CS8900_TX_EVENT_TX_OK)
+ ++cs->eth_stats.tx_ok;
+
+ cs->tx_active = 0;
+
+ rtems_event_send (cs->tx_task, CS8900_TX_OK_EVENT);
+ }
+ break;
+
+ case 0x0c:
+
+ /*
+ * BufEvent.
+ */
+
+ if (isq & CS8900_BUFFER_EVENT_RDY_FOR_TX)
+ {
+ if (cs->tx_active)
+ {
+ ++cs->eth_stats.tx_rdy4tx;
+ rtems_event_send (cs->tx_task, CS8900_TX_WAIT_EVENT);
+ }
+ }
+ else if (isq & CS8900_BUFFER_EVENT_TX_UNDERRUN)
+ {
+ ++cs->eth_stats.tx_underrun_errors;
+ if (cs->tx_active)
+ rtems_event_send (cs->tx_task, CS8900_TX_OK_EVENT);
+ }
+ else if (isq & CS8900_BUFFER_EVENT_SW_INT)
+ {
+ ++cs->eth_stats.int_swint_res;
+ }
+ break;
+
+ case 0x10:
+
+ /*
+ * RxMiss.
+ */
+
+ cs->eth_stats.rx_missed_errors +=
+ mem_pp_get_reg (dev, CS8900_PP_RxMISS) >> 6;
+ break;
- len_odd = len & 1;
- rx_len = len & ~1;
+ case 0x12:
+
+ /*
+ * TxCol.
+ */
+
+ cs->eth_stats.tx_collisions +=
+ mem_pp_get_reg (dev, CS8900_PP_TxCol) >> 6;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+}
+
+int
+cs8900_link_active (int dev)
+{
+ return ((mem_pp_get_reg (dev, CS8900_PP_LineST) & CS8900_LINE_STATUS_LINK_OK) ?
+ 1 : 0);
+}
+
+static inline void
+cs8900_rx_refill_queue (cs8900_device *cs)
+{
+ struct ifnet *ifp = &cs->arpcom.ac_if;
+ struct mbuf *m;
+ rtems_interrupt_level level;
- for (; rx_len; rx_len -= 2)
+ /*
+ * Hold a single queue of mbuf's at the interface. This
+ * will lower the latency of the driver.
+ */
+
+ while (cs->rx_ready_len < CS8900_RX_QUEUE_SIZE)
{
-#ifndef CS8900_DATA_BUS_SWAPPED
- swap_word = *src++;
- *dst++ = (swap_word >> 8) | (swap_word << 8);
-#else
- *dst++ = *src++;
-#endif
+ MGETHDR (m, M_DONTWAIT, MT_DATA);
+
+ if (!m)
+ {
+ ++cs->eth_stats.rx_no_mbufs;
+ cs8900_trace (cs, CS8900_T_NO_MBUF, cs->eth_stats.rx_no_mbufs);
+ return;
+ }
+
+ MCLGET (m, M_DONTWAIT);
+
+ if (!m->m_ext.ext_buf)
+ {
+ ++cs->eth_stats.rx_no_clusters;
+ cs8900_trace (cs, CS8900_T_NO_CLUSTERS, cs->eth_stats.rx_no_clusters);
+ m_free (m);
+ return;
+ }
+ m->m_pkthdr.rcvif = ifp;
+ m->m_nextpkt = 0;
+
+ rtems_interrupt_disable (level);
+
+ if (cs->rx_ready_tail == 0)
+ cs->rx_ready_head = m;
+ else
+ cs->rx_ready_tail->m_nextpkt = m;
+ cs->rx_ready_tail = m;
+ cs->rx_ready_len++;
+
+ rtems_interrupt_enable (level);
}
+}
+
+static void
+cs8900_rx_task (void *arg)
+{
+ cs8900_device *cs = arg;
+ int dev = cs->dev;
+ struct ifnet *ifp = &cs->arpcom.ac_if;
+ rtems_event_set events;
+ struct mbuf *m;
+ struct ether_header *eh;
+ rtems_status_code sc;
+ rtems_interrupt_level level;
+
+ /*
+ * Turn the receiver and transmitter on.
+ */
+
+ mem_pp_bit_set_reg (dev, CS8900_PP_LineCFG,
+ CS8900_LINE_CTRL_RX_ON |
+ CS8900_LINE_CTRL_TX_ON);
+
+ /*
+ * Start the software interrupt watchdog.
+ */
+
+ rtems_interrupt_disable (level);
+ mem_pp_bit_set_reg (dev, CS8900_PP_BufCFG,
+ CS8900_BUFFER_CONFIG_SW_INT);
+ ++cs->eth_stats.int_swint_req;
+ rtems_interrupt_enable (level);
+
+ /*
+ * Loop reading packets.
+ */
- if (len_odd)
+ while (1)
{
-#ifndef CS8900_DATA_BUS_SWAPPED
- swap_word = *src++;
- *dst++ = (swap_word >> 8) | (swap_word << 8);
-#else
- *dst++ = *src++;
-#endif
- }
+ cs8900_rx_refill_queue (cs);
+
+ sc = rtems_bsdnet_event_receive (CS8900_RX_OK_EVENT,
+ RTEMS_WAIT | RTEMS_EVENT_ANY,
+ TOD_MILLISECONDS_TO_TICKS (250),
+ &events);
+
+ cs8900_rx_refill_queue (cs);
+
+ if (sc == RTEMS_TIMEOUT)
+ {
+ /*
+ * We need to check the interrupt hardware in the cs8900a
+ * has not locked up. It seems this occurs if the ISQ
+ * queue fills up.
+ * To test we generate a software interrupt and watch
+ * a counter go up. If the counter does not go for 2
+ * software interrupts requests we flush the ISQ queue.
+ */
+
+ if ((cs->eth_stats.int_swint_req - cs->eth_stats.int_swint_res) > 1)
+ {
+ printf ("cs8900: int lockup, isq flush\n");
+
+ mem_pp_bit_clear_reg (dev, CS8900_PP_BusCTL,
+ CS8900_BUS_CTRL_ENABLE_INT);
+
+ while (mem_pp_get_reg (dev, CS8900_PP_ISQ) != 0);
+
+ cs->eth_stats.int_swint_req = cs->eth_stats.int_swint_res = 0;
+ ++cs->eth_stats.int_lockup;
+
+ mem_pp_bit_set_reg (dev, CS8900_PP_BusCTL,
+ CS8900_BUS_CTRL_ENABLE_INT);
+ }
+
+ rtems_interrupt_disable (level);
+ mem_pp_bit_set_reg (dev, CS8900_PP_BufCFG,
+ CS8900_BUFFER_CONFIG_SW_INT);
+ ++cs->eth_stats.int_swint_req;
+ rtems_interrupt_enable (level);
+ }
- return len;
+ cs8900_trace (cs, CS8900_T_RX_BEGIN, cs->rx_loaded_len);
+
+ while (cs->rx_loaded_len)
+ {
+ rtems_interrupt_disable (level);
+
+ m = cs->rx_loaded_head;
+ if (m)
+ {
+ cs->rx_loaded_head = m->m_nextpkt;
+ if (cs->rx_loaded_head == 0)
+ cs->rx_loaded_tail = 0;
+ m->m_nextpkt = 0;
+ cs->rx_loaded_len--;
+
+ rtems_interrupt_enable (level);
+
+ m->m_pkthdr.rcvif = ifp;
+
+ cs->eth_stats.rx_bytes += m->m_pkthdr.len;
+
+ m->m_len = m->m_pkthdr.len = m->m_pkthdr.len - sizeof (struct ether_header);
+
+ eh = mtod (m, struct ether_header *);
+ m->m_data += sizeof (struct ether_header);
+
+ ++cs->eth_stats.rx_packets;
+
+ ether_input (ifp, eh, m);
+ }
+ else
+ {
+ rtems_interrupt_enable (level);
+ }
+ }
+ cs8900_trace (cs, CS8900_T_RX_END, cs->rx_loaded_len);
+ }
}
-void
-cs8900_tx_load (int dev, struct mbuf *m)
+static void
+cs8900_tx_task (void *arg)
{
- volatile unsigned short *dst = (unsigned short *) (ethernet_mem_base[dev] + CS8900_PP_TxFrameLoc);
- unsigned int len;
- unsigned char *src;
- int remainder = 0;
- unsigned char remainder_data = '\0';
-
- while (m)
+ cs8900_device *cs = arg;
+ int dev = cs->dev;
+ struct ifnet *ifp = &cs->arpcom.ac_if;
+ rtems_event_set events;
+ struct mbuf *m;
+ rtems_status_code sc;
+
+ /*
+ * Wait for the link to come up.
+ */
+
+ rtems_task_wake_after (TOD_MILLISECONDS_TO_TICKS (750));
+
+ /*
+ * Loop processing the tx queue.
+ */
+
+ while (1)
{
/*
- * We can get empty mbufs from the stack.
+ * Fetch the mbuf list from the interface's queue.
*/
- len = m->m_len;
- src = mtod (m, unsigned char*);
+ IF_DEQUEUE (&ifp->if_snd, m);
- if (len)
+ /*
+ * If something actually is present send it.
+ */
+
+ if (!m)
{
- if (remainder)
+ ifp->if_flags &= ~IFF_OACTIVE;
+
+ rtems_bsdnet_event_receive (CS8900_TX_START_EVENT,
+ RTEMS_WAIT | RTEMS_EVENT_ANY,
+ RTEMS_NO_TIMEOUT,
+ &events);
+ }
+ else
+ {
+ if (cs8900_link_active (dev))
{
-#ifndef CS8900_DATA_BUS_SWAPPED
- *dst++ = remainder_data | (*src++ << 8);
-#else
- *dst++ = *src++ | (remainder_data << 8);
-#endif
- len--;
- remainder = 0;
- }
+ int resending;
+
+ do
+ {
+ unsigned short buf_status;
+
+ resending = 0;
+
+ cs->tx_active = 1;
+
+ mem_pp_set_reg (dev, CS8900_PP_TxCMD,
+ CS8900_TX_CMD_STATUS_TX_START_ENTIRE |
+ CS8900_TX_CMD_STATUS_FORCE);
+ mem_pp_set_reg (dev, CS8900_PP_TxLength, m->m_pkthdr.len);
+
+ buf_status = mem_pp_get_reg (dev, CS8900_PP_BusST);
+
+ /*
+ * If the bid for memory in the device fails trash the
+ * transmit and try again next time.
+ */
- if (len & 1)
+ if (buf_status & CS8900_BUS_STATUS_TX_BID_ERROR)
+ ++cs->eth_stats.tx_bid_errors;
+ else
+ {
+ /*
+ * If the buffer is not read enable the interrupt and then wait.
+ */
+
+ if ((buf_status & CS8900_BUS_STATUS_RDY_FOR_TX_NOW) == 0)
+ {
+ cs->eth_stats.tx_wait_for_rdy4tx++;
+ sc = rtems_bsdnet_event_receive (CS8900_TX_WAIT_EVENT,
+ RTEMS_WAIT | RTEMS_EVENT_ANY,
+ TOD_MILLISECONDS_TO_TICKS (750),
+ &events);
+ if (sc == RTEMS_TIMEOUT)
+ {
+ /*
+ * For some reason the wait request has been dropped,
+ * so lets resend from the start.
+ */
+
+ printf ("tx resend\n");
+ ++cs->eth_stats.tx_resends;
+ resending = 1;
+ }
+ }
+
+ if (!resending)
+ {
+ cs8900_tx_load (dev, m);
+ cs->eth_stats.tx_packets++;
+ cs->eth_stats.tx_bytes += m->m_pkthdr.len;
+ }
+ }
+ }
+ while (resending);
+
+ m_freem (m);
+
+ do
+ {
+ rtems_bsdnet_event_receive (CS8900_TX_OK_EVENT,
+ RTEMS_WAIT | RTEMS_EVENT_ANY,
+ RTEMS_NO_TIMEOUT,
+ &events);
+ }
+ while (cs->tx_active);
+ }
+ else
{
- remainder = 1;
- len--;
+ ++cs->eth_stats.tx_dropped;
+ m_freem (m);
}
+ }
+ }
+}
+
+static void
+cs8900_start (struct ifnet *ifp)
+{
+ cs8900_device *cs = ifp->if_softc;
+
+ /*
+ * Tell the transmit daemon to wake up and send a packet.
+ */
+
+ ifp->if_flags |= IFF_OACTIVE;
+
+ rtems_event_send (cs->tx_task, CS8900_TX_START_EVENT);
+}
+
+static void
+cs8900_stop (cs8900_device *cs)
+{
+ int dev = cs->dev;
+
+ mem_pp_bit_clear_reg (dev, CS8900_PP_LineCFG,
+ CS8900_LINE_CTRL_RX_ON |
+ CS8900_LINE_CTRL_TX_ON);
+
+ mem_pp_bit_clear_reg (dev, CS8900_PP_BusCTL,
+ CS8900_BUS_CTRL_ENABLE_INT);
+}
+
+static const char *eth_statistics_labels[] =
+{
+ "rx packets",
+ "tx packets",
+ "rx bytes",
+ "tx bytes",
+ "rx interrupts",
+ "tx interrupts",
+ "rx dropped",
+ "rx no mbuf",
+ "rx no custers",
+ "rx oversize errors",
+ "rx crc errors",
+ "rx runt errors",
+ "rx missed errors",
+ "tx ok",
+ "tx collisions",
+ "tx bid errors",
+ "tx wait for rdy4tx",
+ "tx rdy4tx",
+ "tx underrun errors",
+ "tx dropped",
+ "tx resends",
+ "int swint req",
+ "int swint res",
+ "int lockup",
+ "interrupts"
+};
+
+static void
+cs8900_stats (cs8900_device *cs)
+{
+ int dev = cs->dev;
+ int i;
+ int max_label = 0;
+ int len;
+ unsigned long *value = (unsigned long*) &cs->eth_stats.rx_packets;
+
+ cs->eth_stats.rx_missed_errors +=
+ mem_pp_get_reg (dev, CS8900_PP_RxMISS) >> 6;
- for (; len; len -= 2)
-#ifndef CS8900_DATA_BUS_SWAPPED
- *dst++ = (*src++) | (*(++src) << 8);
-#else
- *dst++ = (*src++ << 8) | *(++src);
-#endif
+ cs->eth_stats.tx_collisions +=
+ mem_pp_get_reg (dev, CS8900_PP_TxCol) >> 6;
+
+ printf ("Network Driver Stats for CS8900 :\n");
+
+ for (i = 0; i < (sizeof (eth_statistics_labels) / sizeof (const char *)); i++)
+ {
+ len = strlen (eth_statistics_labels[i]);
+ if (len > max_label)
+ max_label = len;
+ }
+
+ max_label += 2;
+
+ printf ("%*s - %10u %*s - %10u\n",
+ max_label, "rx ready len", cs->rx_ready_len,
+ max_label, "rx loaded len", cs->rx_loaded_len);
+
+ for (i = 0;
+ i < (sizeof (eth_statistics_labels) / sizeof (const char *));
+ i++)
+ {
+ printf ("%*s - %10lu",
+ max_label, eth_statistics_labels[i], value[i]);
- if (remainder)
- remainder_data = *src++;
- }
+ i++;
- m = m->m_next;
+ if (i < (sizeof (eth_statistics_labels) / sizeof (const char *)))
+ printf (" %*s - %10lu",
+ max_label, eth_statistics_labels[i], value[i]);
+ printf ("\n");
}
- if (remainder)
+#if CS8900_TRACE
+
+ for (i = 0; i < cs->trace_in; i++)
{
-#ifndef CS8900_DATA_BUS_SWAPPED
- *dst = (unsigned short) remainder_data;
-#else
- *dst = (unsigned short) (remainder_data << 8);
-#endif
+ printf ("%8ld.%03ld ", cs->trace_time[i] / 1000, cs->trace_time[i] % 1000);
+
+ if (cs->trace_key[i] < sizeof (cs8900_trace_labels) / sizeof (char*))
+ printf ("%s : ", cs8900_trace_labels[cs->trace_key[i]]);
+ else
+ printf ("unknown trace key, %d : ", cs->trace_key[i]);
+
+ if (cs->trace_key[i] == CS8900_T_INT)
+ {
+ printf ("0x%04lx ", cs->trace_var[i]);
+ if (cs->trace_var[i] == 0)
+ printf ("end");
+ else
+ {
+ switch (cs->trace_var[i] & 0x1f)
+ {
+ case 0x04:
+ printf ("rx event");
+ break;
+
+ case 0x08:
+ printf ("tx event");
+ break;
+
+ case 0x0c:
+ printf ("buffer event");
+ break;
+
+ case 0x10:
+ printf ("rx missed");
+ break;
+
+ case 0x12:
+ printf ("tx collisions");
+ break;
+
+ case 0x1f:
+ printf ("tx request");
+ break;
+
+ case 0x1e:
+ printf ("tx wait 4 tx");
+ break;
+
+ case 0x1d:
+ printf ("tx already active");
+ break;
+
+ default:
+ printf ("unknown event");
+ break;
+ }
+ }
+ }
+ else
+ printf ("0x%08lx", cs->trace_var[i]);
+
+ printf ("\n");
}
+
+ cs->trace_in = 0;
+
+#endif
}
-void cs8900_attach_interrupt (int dev, cs8900_device *cs)
+static void
+cs8900_init (void *arg)
{
- rtems_interrupt_catch_with_void (cs8900_interrupt,
- ethernet_irq_vector[dev],
- &old_handler[dev],
- cs,
- &old_parameter[dev]);
-
- CF_SIM_WRITE_ICR (CF_BASE,
- ethernet_irq_level[dev],
- CF_SIM_ICR_AVEC_AUTO,
- ethernet_irq_level[dev],
- ethernet_irq_priority[dev]);
- CF_SIM_IMR_ENABLE (CF_BASE, 1 << ethernet_irq_level[dev]);
+ cs8900_device *cs = arg;
+ int dev = cs->dev;
+ struct ifnet *ifp = &cs->arpcom.ac_if;
+
+ if (cs->rx_task == 0)
+ {
+
+ /*
+ * Set up the hardware.
+ */
+
+ cs8900_hardware_init (cs);
+
+ /*
+ * Start driver task. We have only one task.
+ */
+
+ cs->rx_task = rtems_bsdnet_newproc ("CSr0", 4096, cs8900_rx_task, cs);
+ cs->tx_task = rtems_bsdnet_newproc ("CSt0", 4096, cs8900_tx_task, cs);
+ }
+
+#ifdef todo
+ /*
+ * Set flags appropriately
+ */
+ if (ifp->if_flags & IFF_PROMISC)
+ else
+#endif
+
+ /*
+ * Tell the world that we're running.
+ */
+
+ ifp->if_flags |= IFF_RUNNING;
+
+ /*
+ * Set the Line Control to bring the receive and transmitter online.
+ */
+
+ mem_pp_bit_set_reg (dev, CS8900_PP_LineCFG,
+ CS8900_LINE_CTRL_RX_ON |
+ CS8900_LINE_CTRL_TX_ON);
+
+ mem_pp_bit_set_reg (dev, CS8900_PP_BusCTL,
+ CS8900_BUS_CTRL_ENABLE_INT);
}
-void cs8900_detach_interrupt (int dev)
+static int
+cs8900_ioctl (struct ifnet *ifp, int cmd, caddr_t data)
{
- CF_SIM_IMR_DISABLE (CF_BASE, 1 << ethernet_irq_level[dev]);
-
- rtems_interrupt_catch_with_void (old_handler,
- ethernet_irq_vector[dev],
- NULL,
- old_parameter[dev],
- NULL);
+ cs8900_device *cs = ifp->if_softc;
+ int error = 0;
+
+ switch (cmd)
+ {
+ case SIOCGIFADDR:
+ case SIOCSIFADDR:
+
+ error = ether_ioctl (ifp, cmd, data);
+ break;
+
+ case SIOCSIFFLAGS:
+
+ switch (ifp->if_flags & (IFF_UP | IFF_RUNNING))
+ {
+ case IFF_RUNNING:
+
+ cs8900_stop (cs);
+ break;
+
+ case IFF_UP:
+
+ cs8900_init (cs);
+ break;
+
+ case IFF_UP | IFF_RUNNING:
+
+ cs8900_stop (cs);
+ cs8900_init (cs);
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case SIO_RTEMS_SHOW_STATS:
+
+ cs8900_stats (cs);
+ break;
+
+ /* FIXME: Multicast commands must be added here. */
+
+ default:
+ error = EINVAL;
+ break;
+ }
+
+ return error;
}
-void cs8900_get_mac_addr (int dev, unsigned char *mac_address)
+int
+cs8900_driver_attach (struct rtems_bsdnet_ifconfig *config, int attaching)
{
- memcpy (mac_address, rct_get_mac_address (dev), 6);
+ cs8900_device *cs;
+ struct ifnet *ifp;
+ int mtu;
+ int unit;
+ char *name;
+
+ /*
+ * Parse driver name
+ */
+
+ if ((unit = rtems_bsdnet_parse_driver_name (config, &name)) < 0)
+ return 0;
+
+ /*
+ * Is driver free?
+ */
+
+ if (unit >= CS8900_DEVICES)
+ {
+ printf ("Bad CS8900 unit number for device `%s'.\n", config->name);
+ return 0;
+ }
+
+ cs = &cs8900[unit];
+ cs->dev = unit;
+ ifp = &cs->arpcom.ac_if;
+
+ if (attaching)
+ {
+ if (ifp->if_softc)
+ {
+ printf ("Driver `%s' already in use.\n", config->name);
+ return 0;
+ }
+
+ /*
+ * Process options
+ */
+
+ if (config->hardware_address)
+ memcpy (cs->arpcom.ac_enaddr, config->hardware_address, ETHER_ADDR_LEN);
+ else
+ cs8900_get_mac_addr (unit, cs->arpcom.ac_enaddr);
+
+ if (config->mtu)
+ mtu = config->mtu;
+ else
+ mtu = ETHERMTU;
+
+ cs->accept_bcast = !config->ignore_broadcast;
+
+ /*
+ * Set up network interface values.
+ */
+
+ ifp->if_softc = cs;
+ ifp->if_unit = unit;
+ ifp->if_name = name;
+ ifp->if_mtu = mtu;
+ ifp->if_init = cs8900_init;
+ ifp->if_ioctl = cs8900_ioctl;
+ ifp->if_start = cs8900_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 to the stack.
+ */
+
+ if_attach (ifp);
+ ether_ifattach (ifp);
+ }
+ else
+ {
+ if (!ifp->if_softc)
+ {
+ printf ("Driver `%s' not found.\n", config->name);
+ return 0;
+ }
+
+ cs8900_stop (cs);
+ cs8900_detach_interrupt (unit);
+ }
+
+ return 1;
+
}
diff --git a/c/src/libchip/network/cs8900.c.bsp b/c/src/libchip/network/cs8900.c.bsp
new file mode 100644
index 0000000000..f445617cd8
--- /dev/null
+++ b/c/src/libchip/network/cs8900.c.bsp
@@ -0,0 +1,297 @@
+/*
+ ------------------------------------------------------------------------
+ $Id$
+ ------------------------------------------------------------------------
+
+ My Right Boot, a boot ROM for embedded hardware.
+
+ Copyright Cybertec Pty Ltd, 2000
+ All rights reserved Cybertec Pty Ltd, 2000
+
+ COPYRIGHT (c) 1989-1998.
+ On-Line Applications Research Corporation (OAR).
+
+ The license and distribution terms for this file may be
+ found in the file LICENSE in this distribution or at
+ http://www.OARcorp.com/rtems/license.html.
+
+ ------------------------------------------------------------------------
+
+ CS8900 net boot driver.
+
+ */
+
+#include <rtems/bspIo.h>
+#include <rtems.h>
+
+#include <libchip/cs8900.h>
+
+/*
+ * Our local data.
+ */
+
+#ifdef CS8900_VERBOSE
+static BOOLEAN cs8900_io_verbose;
+#endif
+
+static rtems_isr_void_entry old_handler[CS8900_DEVICES];
+static void *old_parameter[CS8900_DEVICES];
+
+/*
+ * Tables of IO addresses and interrupt levels for each device attached.
+ */
+
+static const unsigned long ethernet_io_base[CS8900_DEVICES] =
+{
+ ETHERNET_BASE
+};
+
+static const unsigned long ethernet_mem_base[CS8900_DEVICES] =
+{
+ ETHERNET_BASE + CS8900_MEMORY_BASE
+};
+
+static const unsigned int ethernet_irq_level[CS8900_DEVICES] =
+{
+ ETHERNET_IRQ_LEVEL
+};
+
+static const unsigned int ethernet_irq_priority[CS8900_DEVICES] =
+{
+ ETHERNET_IRQ_PRIORITY
+};
+
+static const unsigned int ethernet_irq_vector[CS8900_DEVICES] =
+{
+ ETHERNET_IRQ_VECTOR,
+};
+
+void cs8900_io_set_reg (int dev, unsigned short reg, unsigned short data)
+{
+#ifdef CS8900_DATA_BUS_SWAPPED
+ data = (data >> 8) | (data << 8);
+#endif
+
+#ifdef CS8900_VERBOSE
+ if (cs8900_io_verbose)
+ printf ("CS8900: io set reg=0x%04x, data=0x%04x\n", reg, data);
+#endif
+
+ WRITE_REGISTER_16 (ethernet_io_base[dev] + reg, data);
+}
+
+unsigned short cs8900_io_get_reg (int dev, unsigned short reg)
+{
+ unsigned long data;
+
+ READ_REGISTER_16 (ethernet_io_base[dev] + reg, data);
+
+#ifdef CS8900_DATA_BUS_SWAPPED
+ data = (data >> 8) | (data << 8);
+#endif
+
+#ifdef CS8900_VERBOSE
+ if (cs8900_io_verbose)
+ printk ("CS8900: io get reg=0x%04x, data=0x%04x\n", reg, data);
+#endif
+
+ return data;
+}
+
+void cs8900_mem_set_reg (int dev, unsigned long reg, unsigned short data)
+{
+#ifdef CS8900_DATA_BUS_SWAPPED
+ data = (data >> 8) | (data << 8);
+#endif
+
+#ifdef CS8900_VERBOSE
+ if (cs8900_io_verbose)
+ printk ("CS8900: mem set reg=0x%04x, data=0x%04x\n", reg, data);
+#endif
+
+ WRITE_REGISTER_16 (ethernet_io_base[dev] + reg, data);
+}
+
+unsigned short cs8900_mem_get_reg (int dev, unsigned long reg)
+{
+ unsigned short data;
+ READ_REGISTER_16 (ethernet_io_base[dev] + reg, data);
+
+#ifdef CS8900_DATA_BUS_SWAPPED
+ data = (data >> 8) | (data << 8);
+#endif
+
+#ifdef CS8900_VERBOSE
+ if (cs8900_io_verbose)
+ printk ("CS8900: mem get reg=0x%04x, data=0x%04x\n", reg, data);
+#endif
+
+ return data;
+}
+
+void cs8900_put_data_block (int dev, int len, unsigned char *data)
+{
+#ifndef CS8900_DATA_BUS_SWAPPED
+ unsigned short swap_word;
+#endif
+ unsigned short *src = (unsigned short *) ((unsigned long) data);
+ unsigned short *dst = (unsigned short *) (ethernet_mem_base[dev] + CS8900_PP_TxFrameLoc);
+
+ while (len > 1)
+ {
+#ifndef CS8900_DATA_BUS_SWAPPED
+ swap_word = *src++;
+ *dst++ = (swap_word >> 8) | (swap_word << 8);
+#else
+ *dst++ = *src++;
+#endif
+ len -= 2;
+ }
+
+ if (len)
+ {
+#ifndef CS8900_DATA_BUS_SWAPPED
+ swap_word = *src++;
+ *dst++ = (swap_word >> 8) | (swap_word << 8);
+#else
+ *dst++ = *src++;
+#endif
+ }
+}
+
+unsigned short cs8900_get_data_block (int dev, unsigned char *data)
+{
+ unsigned short swap_word;
+ volatile unsigned short *src = (unsigned short *) (ethernet_mem_base[dev] + CS8900_PP_RxLength);
+ unsigned short *dst;
+ unsigned short len;
+ unsigned short rx_len;
+ unsigned short len_odd;
+
+#ifdef CS8900_DATA_BUS_SWAPPED
+ swap_word = *src++;
+ len = (swap_word >> 8) | (swap_word << 8);
+#else
+ len = *src++;
+#endif
+
+ dst = (unsigned short *) ((unsigned long) data);
+
+ len_odd = len & 1;
+ rx_len = len & ~1;
+
+ for (; rx_len; rx_len -= 2)
+ {
+#ifndef CS8900_DATA_BUS_SWAPPED
+ swap_word = *src++;
+ *dst++ = (swap_word >> 8) | (swap_word << 8);
+#else
+ *dst++ = *src++;
+#endif
+ }
+
+ if (len_odd)
+ {
+#ifndef CS8900_DATA_BUS_SWAPPED
+ swap_word = *src++;
+ *dst++ = (swap_word >> 8) | (swap_word << 8);
+#else
+ *dst++ = *src++;
+#endif
+ }
+
+ return len;
+}
+
+void
+cs8900_tx_load (int dev, struct mbuf *m)
+{
+ volatile unsigned short *dst = (unsigned short *) (ethernet_mem_base[dev] + CS8900_PP_TxFrameLoc);
+ unsigned int len;
+ unsigned char *src;
+ int remainder = 0;
+ unsigned char remainder_data = '\0';
+
+ while (m)
+ {
+ /*
+ * We can get empty mbufs from the stack.
+ */
+
+ len = m->m_len;
+ src = mtod (m, unsigned char*);
+
+ if (len)
+ {
+ if (remainder)
+ {
+#ifndef CS8900_DATA_BUS_SWAPPED
+ *dst++ = remainder_data | (*src++ << 8);
+#else
+ *dst++ = *src++ | (remainder_data << 8);
+#endif
+ len--;
+ remainder = 0;
+ }
+
+ if (len & 1)
+ {
+ remainder = 1;
+ len--;
+ }
+
+ for (; len; len -= 2)
+#ifndef CS8900_DATA_BUS_SWAPPED
+ *dst++ = (*src++) | (*(++src) << 8);
+#else
+ *dst++ = (*src++ << 8) | *(++src);
+#endif
+
+ if (remainder)
+ remainder_data = *src++;
+ }
+
+ m = m->m_next;
+ }
+
+ if (remainder)
+ {
+#ifndef CS8900_DATA_BUS_SWAPPED
+ *dst = (unsigned short) remainder_data;
+#else
+ *dst = (unsigned short) (remainder_data << 8);
+#endif
+ }
+}
+
+void cs8900_attach_interrupt (int dev, cs8900_device *cs)
+{
+ rtems_interrupt_catch_with_void (cs8900_interrupt,
+ ethernet_irq_vector[dev],
+ &old_handler[dev],
+ cs,
+ &old_parameter[dev]);
+
+ CF_SIM_WRITE_ICR (CF_BASE,
+ ethernet_irq_level[dev],
+ CF_SIM_ICR_AVEC_AUTO,
+ ethernet_irq_level[dev],
+ ethernet_irq_priority[dev]);
+ CF_SIM_IMR_ENABLE (CF_BASE, 1 << ethernet_irq_level[dev]);
+}
+
+void cs8900_detach_interrupt (int dev)
+{
+ CF_SIM_IMR_DISABLE (CF_BASE, 1 << ethernet_irq_level[dev]);
+
+ rtems_interrupt_catch_with_void (old_handler,
+ ethernet_irq_vector[dev],
+ NULL,
+ old_parameter[dev],
+ NULL);
+}
+
+void cs8900_get_mac_addr (int dev, unsigned char *mac_address)
+{
+ memcpy (mac_address, rct_get_mac_address (dev), 6);
+}
diff --git a/c/src/libchip/network/cs8900.h b/c/src/libchip/network/cs8900.h
index fc36e438a9..ba387681f2 100644
--- a/c/src/libchip/network/cs8900.h
+++ b/c/src/libchip/network/cs8900.h
@@ -2,7 +2,7 @@
------------------------------------------------------------------------
$Id$
------------------------------------------------------------------------
-
+
My Right Boot, a boot ROM for embedded hardware.
Copyright Cybertec Pty Ltd, 2000
@@ -38,6 +38,8 @@
#include <netinet/in.h>
#include <netinet/if_ether.h>
+/* #include <target.h> what does this provide? joel to chris */
+
#define ET_MINLEN 60
/*
@@ -382,7 +384,7 @@ typedef struct
* The bsdnet information structure.
*/
- struct arpcom arpcom;
+ struct arpcom arpcom;
/*
* Driver state and resources.
@@ -417,7 +419,7 @@ typedef struct
*/
eth_statistics eth_stats;
-
+
} cs8900_device;
/*