From a2117cd64a9d25926564e43ea2806f7eacde7343 Mon Sep 17 00:00:00 2001 From: Joel Sherrill Date: Sat, 7 Sep 2002 23:09:47 +0000 Subject: 2002-09-07 Chris Johns * 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. --- c/src/libchip/ChangeLog | 9 + c/src/libchip/network/Makefile.am | 5 +- c/src/libchip/network/README.cs8900 | 8 + c/src/libchip/network/cs8900.c | 1305 ++++++++++++++++++++++++++++++----- c/src/libchip/network/cs8900.c.bsp | 297 ++++++++ c/src/libchip/network/cs8900.h | 8 +- 6 files changed, 1437 insertions(+), 195 deletions(-) create mode 100644 c/src/libchip/network/cs8900.c.bsp (limited to 'c') 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 + + * 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 * 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 +#include +#include + +/* #include + 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 -#include +/* + * This variable really should come from a per device configuration + * table so the base can vary by adapter. + */ -#include +#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 +#include + +#include + +/* + * 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 #include +/* #include 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; /* -- cgit v1.2.3