From 00bf77454744fe75694db20ecc6902d2d403d961 Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Sun, 14 Mar 2004 01:28:08 +0000 Subject: Changes made to support the DIMMPC. This is a pc396 target with IO port support. Minor formating clean up. Add documentation to the header file. --- c/src/libchip/network/cs8900.c | 541 ++++++++++++++++++++--------------------- c/src/libchip/network/cs8900.h | 370 +++++++++++++++++++++++++--- 2 files changed, 607 insertions(+), 304 deletions(-) diff --git a/c/src/libchip/network/cs8900.c b/c/src/libchip/network/cs8900.c index 341042d5ee..3e7d219cd3 100644 --- a/c/src/libchip/network/cs8900.c +++ b/c/src/libchip/network/cs8900.c @@ -1,91 +1,37 @@ /* ------------------------------------------------------------------------ - $Id$ + cs8900.c,v 1.5 2002/11/13 15:34:39 joel Exp ------------------------------------------------------------------------ - - My Right Boot, a boot ROM for embedded hardware. - + Copyright Cybertec Pty Ltd, 2000 All rights reserved Cybertec Pty Ltd, 2000 - + + Port to the DIMM PC copyright (c) 2004 Angelo Fraietta + This project has been assisted by the Commonwealth Government + through the Australia Council, its arts funding and advisory body. + 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.rtems.com/license/LICENSE. + http://www.OARcorp.com/rtems/license.html. ------------------------------------------------------------------------ - CS8900 net boot driver. + CS8900 RTEMS driver. + See the header file for details. + */ #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 - -/* - * This variable really should come from a per device configuration - * table so the base can vary by adapter. - */ - -#ifndef CS8900_IO_BASE -extern unsigned int bsp_cs8900_io_base; -#define CS8900_IO_BASE bsp_cs8900_io_base -#endif - -/* - * 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 - */ - -#ifndef CS8900_RX_QUEUE_SIZE -#define CS8900_RX_QUEUE_SIZE 1 -#endif - -/*********************************************************** - *********************************************************** - END SECTION OF DEFAULT DEFINES - *********************************************************** - ***********************************************************/ - /* * We expect to be able to read a complete packet into an mbuf. */ @@ -103,94 +49,130 @@ extern unsigned int bsp_cs8900_memory_base; #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) +io_pp_get_reg_16 (cs8900_device *cs, unsigned short reg) { - cs8900_io_set_reg (dev, CS8900_IO_BASE + CS8900_IO_PACKET_PAGE_PTR, + rtems_interrupt_level level; + unsigned short data; + rtems_interrupt_disable (level); + cs8900_io_set_reg (cs, 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); + data = cs8900_io_get_reg (cs, CS8900_IO_PP_DATA_PORT0); + rtems_interrupt_enable (level); + return data; } static inline unsigned long -io_pp_get_reg_32 (int dev, unsigned short reg) +io_pp_get_reg_32 (cs8900_device *cs, unsigned short reg) { - cs8900_io_set_reg (dev, CS8900_IO_BASE + CS8900_IO_PACKET_PAGE_PTR, + rtems_interrupt_level level; + unsigned long data; + rtems_interrupt_disable (level); + cs8900_io_set_reg (cs, 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)); + data = ((cs8900_io_get_reg (cs, CS8900_IO_PP_DATA_PORT0) << 16) | + cs8900_io_get_reg (cs, CS8900_IO_PP_DATA_PORT1)); + rtems_interrupt_enable (level); + return data; } static inline void -io_pp_set_reg_16 (int dev, unsigned short reg, unsigned short data) +io_pp_set_reg_16 (cs8900_device *cs, unsigned short reg, unsigned short data) { - cs8900_io_set_reg (dev, CS8900_IO_BASE + CS8900_IO_PACKET_PAGE_PTR, + rtems_interrupt_level level; + rtems_interrupt_disable (level); + cs8900_io_set_reg (cs, 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); + cs8900_io_set_reg (cs, CS8900_IO_PP_DATA_PORT0, data); + rtems_interrupt_enable (level); } static inline void -io_pp_set_reg_32 (int dev, unsigned short reg, unsigned long data) +io_pp_set_reg_32 (cs8900_device *cs, unsigned short reg, unsigned long data) { - cs8900_io_set_reg (dev, CS8900_IO_BASE + CS8900_IO_PACKET_PAGE_PTR, + cs8900_io_set_reg (cs, 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); + cs8900_io_set_reg (cs, CS8900_IO_PP_DATA_PORT0, data >> 16); + cs8900_io_set_reg (cs, CS8900_IO_PP_DATA_PORT1, data); } static inline void -io_pp_bit_set_reg_16 (int dev, unsigned short reg, unsigned short mask) +io_pp_bit_set_reg_16 (cs8900_device *cs, unsigned short reg, unsigned short mask) { - io_pp_set_reg_16 (dev, reg, io_pp_get_reg_16 (dev, reg) | mask); + rtems_interrupt_level level; + rtems_interrupt_disable (level); + io_pp_set_reg_16 (cs, reg, io_pp_get_reg_16 (cs, reg) | mask); + rtems_interrupt_enable (level); } static inline void -io_pp_bit_clear_reg_16 (int dev, unsigned short reg, unsigned short mask) +io_pp_bit_clear_reg_16 (cs8900_device *cs, unsigned short reg, unsigned short mask) { - io_pp_set_reg_16 (dev, reg, io_pp_get_reg_16 (dev, reg) & ~mask); + rtems_interrupt_level level; + rtems_interrupt_disable (level); + io_pp_set_reg_16 (cs, reg, io_pp_get_reg_16 (cs, reg) & ~mask); + rtems_interrupt_enable (level); } /* * Memory Mapped Packet Page interface. + * + * If the BSP does not configure mem_base use the I/O register accesses. */ static inline unsigned short -mem_pp_get_reg (int dev, unsigned short reg) +mem_pp_get_reg (cs8900_device *cs, unsigned short reg) { - return cs8900_mem_get_reg (dev, CS8900_MEMORY_BASE + reg); + if (!cs->mem_base) + return io_pp_get_reg_16 (cs, reg); + return cs8900_mem_get_reg (cs, reg); } static inline void -mem_pp_set_reg (int dev, unsigned short reg, unsigned short data) +mem_pp_set_reg (cs8900_device *cs, unsigned short reg, unsigned short data) { - cs8900_mem_set_reg (dev, CS8900_MEMORY_BASE + reg, data); + if (!cs->mem_base) + io_pp_set_reg_16 (cs, reg, data); + else + cs8900_mem_set_reg (cs, reg, data); } static inline void -mem_pp_bit_set_reg (int dev, unsigned short reg, unsigned short mask) +mem_pp_bit_set_reg (cs8900_device *cs, unsigned short reg, unsigned short mask) { - mem_pp_set_reg (dev, reg, mem_pp_get_reg (dev, reg) | mask); + if (!cs->mem_base) + io_pp_bit_set_reg_16 (cs, reg, mask); + else + { + rtems_interrupt_level level; + rtems_interrupt_disable (level); + mem_pp_set_reg (cs, reg, mem_pp_get_reg (cs, reg) | mask); + rtems_interrupt_enable (level); + } } static inline void -mem_pp_bit_clear_reg (int dev, unsigned short reg, unsigned short mask) +mem_pp_bit_clear_reg (cs8900_device *cs, unsigned short reg, unsigned short mask) { - mem_pp_set_reg (dev, reg, mem_pp_get_reg (dev, reg) & ~mask); + if (!cs->mem_base) + io_pp_bit_clear_reg_16 (cs, reg, mask); + else + { + rtems_interrupt_level level; + rtems_interrupt_disable (level); + mem_pp_set_reg (cs, reg, mem_pp_get_reg (cs, reg) & ~mask); + rtems_interrupt_enable (level); + } } /* * Trace defines and control structures. */ - + #define CS8900_T_INT (0) #define CS8900_T_RX_OK (1) #define CS8900_T_RX_DROPPED (2) @@ -222,9 +204,9 @@ static inline void cs8900_trace (cs8900_device *cs, unsigned short key, unsigned long var) { rtems_interrupt_level level; - + rtems_interrupt_disable (level); - + if (cs->trace_in < CS8900_TRACE_SIZE) { cs->trace_key[cs->trace_in] = key; @@ -232,13 +214,35 @@ cs8900_trace (cs8900_device *cs, unsigned short key, unsigned long 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 +void cs8900_get_mac_addr (cs8900_device *cs, unsigned char *mac_address) +{ + unsigned short ma; + + /* + * Only ever use IO calls for this function as it can be + * called before memory mode has been enabled. + */ + + ma = io_pp_get_reg_16 (cs, CS8900_PP_IA); + mac_address[0] = ma >> 8; + mac_address[1] = ma; + + ma = io_pp_get_reg_16 (cs, CS8900_PP_IA + 2); + mac_address[2] = ma >> 8; + mac_address[3] = ma; + + ma = io_pp_get_reg_16 (cs, CS8900_PP_IA + 4); + mac_address[4] = ma >> 8; + mac_address[5] = ma; +} + /* * Bring the chip online. */ @@ -248,23 +252,22 @@ cs8900_hardware_init (cs8900_device *cs) { 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); + + io_pp_bit_set_reg_16 (cs, CS8900_PP_SelfCTL, CS8900_SELF_CTRL_RESET); rtems_task_wake_after (TOD_MILLISECONDS_TO_TICKS (20)); - - status = io_pp_get_reg_16 (dev, CS8900_PP_SelfST); + + status = io_pp_get_reg_16 (cs, CS8900_PP_SelfST); if (status == 0) { printf("Reading status register again\n"); - status = io_pp_get_reg_16 (dev, CS8900_PP_SelfST); + status = io_pp_get_reg_16 (cs, CS8900_PP_SelfST); } - + if (((status & CS8900_SELF_STATUS_INITD) == 0) || ((status & CS8900_SELF_STATUS_INITD) && (status & CS8900_SELF_STATUS_EEPROM_PRESENT) && @@ -273,23 +276,28 @@ cs8900_hardware_init (cs8900_device *cs) printf ("CS8900: %s. Initialisation aborted.\n", (status & CS8900_SELF_STATUS_INITD) ? "EEPROM read/write failed to complete" : - "Failed to complete to reset"); + "Failed to complete to reset"); return; } - + + /* Set the RX queue size if not set by the BSP. */ + + if (cs->rx_queue_size == 0) + cs->rx_queue_size = 10; + /* Probe the device for its ID */ - prod_id = io_pp_get_reg_32 (dev, CS8900_PP_PROD_ID); + prod_id = io_pp_get_reg_32 (cs, CS8900_PP_PROD_ID); if ((prod_id >> 16) != CS8900_ESIA_ID) { - printf ("CS9800: Invalid EISA ID, read product code 0x%08lx\n", prod_id); + printf ("CS8900: 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", + printf ("CS8900: Unsupported product id, read product code 0x%08lx\n", prod_id); return; } @@ -303,19 +311,22 @@ cs8900_hardware_init (cs8900_device *cs) /* * 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); + + if (cs->mem_base) + { + io_pp_set_reg_16 (cs, CS8900_PP_MEM_BASE, cs->mem_base); + io_pp_set_reg_16 (cs, CS8900_PP_MEM_BASE + 2, (cs->mem_base >> 16) & 0xf); + + io_pp_set_reg_16 (cs, + CS8900_PP_BusCTL, + CS8900_BUS_CTRL_RESET_RX_DMA | + CS8900_BUS_CTRL_USE_SA | + CS8900_BUS_CTRL_MEMORY_ENABLE); + io_pp_set_reg_16 (cs, + CS8900_PP_BusCTL, + CS8900_BUS_CTRL_USE_SA | + CS8900_BUS_CTRL_MEMORY_ENABLE); + } /* * We are now in memory mapped mode. @@ -327,21 +338,21 @@ cs8900_hardware_init (cs8900_device *cs) * No auto detect support at the moment. Only 10BaseT. */ - mem_pp_set_reg (dev, CS8900_PP_LineCFG, CS8900_LINE_CTRL_10BASET); - + mem_pp_set_reg (cs, 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, + + mem_pp_set_reg (cs, CS8900_PP_IA, (((unsigned int) MACO (1)) << 8) | ((unsigned int) MACO (0))); - mem_pp_set_reg (dev, CS8900_PP_IA + 2, + mem_pp_set_reg (cs, CS8900_PP_IA + 2, (((unsigned int) MACO (3)) << 8) | ((unsigned int) MACO (2))); - mem_pp_set_reg (dev, CS8900_PP_IA + 4, + mem_pp_set_reg (cs, CS8900_PP_IA + 4, (((unsigned int) MACO (5)) << 8) | ((unsigned int) MACO (4))); @@ -349,7 +360,7 @@ cs8900_hardware_init (cs8900_device *cs) * Set the Buffer configuration. */ - mem_pp_set_reg (dev, CS8900_PP_BufCFG, + mem_pp_set_reg (cs, CS8900_PP_BufCFG, CS8900_BUFFER_CONFIG_RDY_FOR_TX | CS8900_BUFFER_CONFIG_TX_UNDERRUN | CS8900_BUFFER_CONFIG_TX_COL_OVF | @@ -359,7 +370,7 @@ cs8900_hardware_init (cs8900_device *cs) * Set the Receiver configuration. */ - mem_pp_set_reg (dev, CS8900_PP_RxCFG, + mem_pp_set_reg (cs, CS8900_PP_RxCFG, CS8900_RX_CONFIG_RX_OK | CS8900_RX_CONFIG_CRC_ERROR | CS8900_RX_CONFIG_RUNT| @@ -369,17 +380,17 @@ cs8900_hardware_init (cs8900_device *cs) * Set the Receiver control. */ - mem_pp_set_reg (dev, CS8900_PP_RxCTL, + mem_pp_set_reg (cs, 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, + mem_pp_set_reg (cs, CS8900_PP_TxCFG, CS8900_TX_CONFIG_TX_OK | CS8900_TX_CONFIG_OUT_OF_WINDOW | CS8900_TX_CONFIG_JABBER | @@ -389,15 +400,17 @@ cs8900_hardware_init (cs8900_device *cs) * Attach the interrupt handler. */ - cs8900_attach_interrupt (dev, cs); - + cs8900_attach_interrupt (cs); + /* * Program the interrupt level we require then enable interrupts. + * + * Note, this will need to change to support other levels. */ - mem_pp_set_reg (dev, CS8900_PP_INT, 0); + mem_pp_set_reg (cs, CS8900_PP_INT, cs->irq_level & 3); - mem_pp_bit_set_reg (dev, CS8900_PP_BusCTL, + mem_pp_bit_set_reg (cs, CS8900_PP_BusCTL, CS8900_BUS_CTRL_ENABLE_INT); } @@ -405,7 +418,6 @@ rtems_isr cs8900_interrupt (rtems_vector_number v, void *csp) { cs8900_device *cs = csp; - int dev = cs->dev; unsigned short isq = 0; struct mbuf *m; unsigned char *p; @@ -414,19 +426,17 @@ cs8900_interrupt (rtems_vector_number v, void *csp) while (1) { - isq = mem_pp_get_reg (dev, CS8900_PP_ISQ); + isq = mem_pp_get_reg (cs, CS8900_PP_ISQ); cs8900_trace (cs, CS8900_T_INT, isq); - WATCHDOG_TOGGLE (); - /* * No more interrupts to service. */ if (isq == 0) return; - + switch (isq & 0x1f) { case 0x04: @@ -447,10 +457,10 @@ cs8900_interrupt (rtems_vector_number v, void *csp) 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); + + m->m_pkthdr.len = cs8900_get_data_block (cs, p); if (cs->rx_loaded_tail == 0) cs->rx_loaded_head = m; @@ -461,15 +471,15 @@ cs8900_interrupt (rtems_vector_number v, void *csp) if (cs->rx_loaded_len == 1) { - cs8900_trace (cs, CS8900_T_RX_OK, cs->rx_loaded_len); + 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); + + 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); @@ -482,14 +492,14 @@ cs8900_interrupt (rtems_vector_number v, void *csp) 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. */ @@ -502,17 +512,17 @@ cs8900_interrupt (rtems_vector_number v, void *csp) ++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) @@ -534,36 +544,36 @@ cs8900_interrupt (rtems_vector_number v, void *csp) break; case 0x10: - + /* * RxMiss. */ - + cs->eth_stats.rx_missed_errors += - mem_pp_get_reg (dev, CS8900_PP_RxMISS) >> 6; + mem_pp_get_reg (cs, CS8900_PP_RxMISS) >> 6; break; case 0x12: - + /* * TxCol. */ cs->eth_stats.tx_collisions += - mem_pp_get_reg (dev, CS8900_PP_TxCol) >> 6; + mem_pp_get_reg (cs, CS8900_PP_TxCol) >> 6; break; default: break; } } - + } int -cs8900_link_active (int dev) +cs8900_link_active (cs8900_device *cs) { - return ((mem_pp_get_reg (dev, CS8900_PP_LineST) & CS8900_LINE_STATUS_LINK_OK) ? + return ((mem_pp_get_reg (cs, CS8900_PP_LineST) & CS8900_LINE_STATUS_LINK_OK) ? 1 : 0); } @@ -573,29 +583,29 @@ cs8900_rx_refill_queue (cs8900_device *cs) struct ifnet *ifp = &cs->arpcom.ac_if; struct mbuf *m; rtems_interrupt_level level; - + /* * 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) + while (cs->rx_ready_len < cs->rx_queue_size) { 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); + 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); + cs8900_trace (cs, CS8900_T_NO_CLUSTERS, cs->eth_stats.rx_no_clusters); m_free (m); return; } @@ -603,7 +613,7 @@ cs8900_rx_refill_queue (cs8900_device *cs) m->m_nextpkt = 0; rtems_interrupt_disable (level); - + if (cs->rx_ready_tail == 0) cs->rx_ready_head = m; else @@ -619,7 +629,6 @@ 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; @@ -630,21 +639,19 @@ cs8900_rx_task (void *arg) /* * Turn the receiver and transmitter on. */ - - mem_pp_bit_set_reg (dev, CS8900_PP_LineCFG, + + mem_pp_bit_set_reg (cs, 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, + + mem_pp_bit_set_reg (cs, CS8900_PP_BufCFG, CS8900_BUFFER_CONFIG_SW_INT); ++cs->eth_stats.int_swint_req; - rtems_interrupt_enable (level); - + /* * Loop reading packets. */ @@ -652,14 +659,14 @@ cs8900_rx_task (void *arg) while (1) { 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) { /* @@ -675,31 +682,29 @@ cs8900_rx_task (void *arg) { printf ("cs8900: int lockup, isq flush\n"); - mem_pp_bit_clear_reg (dev, CS8900_PP_BusCTL, + mem_pp_bit_clear_reg (cs, CS8900_PP_BusCTL, CS8900_BUS_CTRL_ENABLE_INT); - - while (mem_pp_get_reg (dev, CS8900_PP_ISQ) != 0); - + + while (mem_pp_get_reg (cs, 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, + + mem_pp_bit_set_reg (cs, CS8900_PP_BusCTL, CS8900_BUS_CTRL_ENABLE_INT); } - - rtems_interrupt_disable (level); - mem_pp_bit_set_reg (dev, CS8900_PP_BufCFG, + + mem_pp_bit_set_reg (cs, CS8900_PP_BufCFG, CS8900_BUFFER_CONFIG_SW_INT); ++cs->eth_stats.int_swint_req; - rtems_interrupt_enable (level); } 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) { @@ -708,20 +713,20 @@ cs8900_rx_task (void *arg) 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 @@ -737,7 +742,6 @@ static void cs8900_tx_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; @@ -776,24 +780,24 @@ cs8900_tx_task (void *arg) } else { - if (cs8900_link_active (dev)) + if (cs8900_link_active (cs)) { int resending; - + do { unsigned short buf_status; resending = 0; - + cs->tx_active = 1; - - mem_pp_set_reg (dev, CS8900_PP_TxCMD, + + mem_pp_set_reg (cs, 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); + mem_pp_set_reg (cs, CS8900_PP_TxLength, m->m_pkthdr.len); + + buf_status = mem_pp_get_reg (cs, CS8900_PP_BusST); /* * If the bid for memory in the device fails trash the @@ -807,7 +811,7 @@ cs8900_tx_task (void *arg) /* * 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++; @@ -830,16 +834,16 @@ cs8900_tx_task (void *arg) if (!resending) { - cs8900_tx_load (dev, m); + cs8900_tx_load (cs, 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, @@ -875,13 +879,11 @@ cs8900_start (struct ifnet *ifp) static void cs8900_stop (cs8900_device *cs) { - int dev = cs->dev; - - mem_pp_bit_clear_reg (dev, CS8900_PP_LineCFG, + mem_pp_bit_clear_reg (cs, CS8900_PP_LineCFG, CS8900_LINE_CTRL_RX_ON | CS8900_LINE_CTRL_TX_ON); - - mem_pp_bit_clear_reg (dev, CS8900_PP_BusCTL, + + mem_pp_bit_clear_reg (cs, CS8900_PP_BusCTL, CS8900_BUS_CTRL_ENABLE_INT); } @@ -917,18 +919,17 @@ static const char *eth_statistics_labels[] = 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; - + mem_pp_get_reg (cs, CS8900_PP_RxMISS) >> 6; + cs->eth_stats.tx_collisions += - mem_pp_get_reg (dev, CS8900_PP_TxCol) >> 6; - + mem_pp_get_reg (cs, CS8900_PP_TxCol) >> 6; + printf ("Network Driver Stats for CS8900 :\n"); for (i = 0; i < (sizeof (eth_statistics_labels) / sizeof (const char *)); i++) @@ -943,16 +944,16 @@ cs8900_stats (cs8900_device *cs) 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]); - + i++; - + if (i < (sizeof (eth_statistics_labels) / sizeof (const char *))) printf (" %*s - %10lu", max_label, eth_statistics_labels[i], value[i]); @@ -960,11 +961,11 @@ cs8900_stats (cs8900_device *cs) } #if CS8900_TRACE - + for (i = 0; i < cs->trace_in; i++) { 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 @@ -1002,15 +1003,15 @@ cs8900_stats (cs8900_device *cs) 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; @@ -1019,12 +1020,12 @@ cs8900_stats (cs8900_device *cs) } else printf ("0x%08lx", cs->trace_var[i]); - + printf ("\n"); } cs->trace_in = 0; - + #endif } @@ -1032,7 +1033,6 @@ static void cs8900_init (void *arg) { cs8900_device *cs = arg; - int dev = cs->dev; struct ifnet *ifp = &cs->arpcom.ac_if; if (cs->rx_task == 0) @@ -1041,13 +1041,13 @@ cs8900_init (void *arg) /* * 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); } @@ -1059,22 +1059,22 @@ cs8900_init (void *arg) 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. + * Set the Line Control to bring the receive and transmitter online. */ - mem_pp_bit_set_reg (dev, CS8900_PP_LineCFG, + mem_pp_bit_set_reg (cs, CS8900_PP_LineCFG, CS8900_LINE_CTRL_RX_ON | CS8900_LINE_CTRL_TX_ON); - mem_pp_bit_set_reg (dev, CS8900_PP_BusCTL, + mem_pp_bit_set_reg (cs, CS8900_PP_BusCTL, CS8900_BUS_CTRL_ENABLE_INT); } @@ -1088,26 +1088,26 @@ cs8900_ioctl (struct ifnet *ifp, int cmd, caddr_t data) { 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; @@ -1118,7 +1118,7 @@ cs8900_ioctl (struct ifnet *ifp, int cmd, caddr_t data) break; case SIO_RTEMS_SHOW_STATS: - + cs8900_stats (cs); break; @@ -1144,21 +1144,11 @@ cs8900_driver_attach (struct rtems_bsdnet_ifconfig *config, int attaching) /* * 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 = config->drv_ctrl; cs->dev = unit; ifp = &cs->arpcom.ac_if; @@ -1173,23 +1163,23 @@ cs8900_driver_attach (struct rtems_bsdnet_ifconfig *config, int attaching) /* * 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); - + cs8900_get_mac_addr (cs, 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; @@ -1199,14 +1189,14 @@ cs8900_driver_attach (struct rtems_bsdnet_ifconfig *config, int attaching) 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); } @@ -1219,9 +1209,8 @@ cs8900_driver_attach (struct rtems_bsdnet_ifconfig *config, int attaching) } cs8900_stop (cs); - cs8900_detach_interrupt (unit); + cs8900_detach_interrupt (cs); } - + return 1; - } diff --git a/c/src/libchip/network/cs8900.h b/c/src/libchip/network/cs8900.h index 00082a557f..036b6d6ced 100644 --- a/c/src/libchip/network/cs8900.h +++ b/c/src/libchip/network/cs8900.h @@ -1,23 +1,148 @@ /* ------------------------------------------------------------------------ - $Id$ + cs8900.h,v 1.3 2002/09/07 23:09:47 joel Exp ------------------------------------------------------------------------ - My Right Boot, a boot ROM for embedded hardware. - Copyright Cybertec Pty Ltd, 2000 All rights reserved Cybertec Pty Ltd, 2000 + Port to the DIMM PC copyright (c) 2004 Angelo Fraietta + This project has been assisted by the Commonwealth Government + through the Australia Council, its arts funding and advisory body. + 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.rtems.com/license/LICENSE. + http://www.OARcorp.com/rtems/license.html. ------------------------------------------------------------------------ - CS8900 net boot driver. + CS8900 RTEMS driver. + + This is a generic driver that requires a BSP backend. The BSP backend + provides the glue to the specific bus for the target hardware. It has + been tested with Coldfire processors, and the PC. These targets have + completely different bus, byte order and interrupt structures. + + An example BSP backend is provided in the pci386 BSP. + + The BSP provides the following functions: + + cs8900_io_set_reg + cs8900_io_get_reg + cs8900_mem_set_reg + cs8900_mem_get_reg + cs8900_put_data_block + cs8900_get_data_block + cs8900_tx_load + cs8900_attach_interrupt + cs8900_detach_interrupt + + The header file provides documentation for these functions. There + are four types of functions. + + The I/O set/get functions access the CS8900 I/O registers via the + I/O Mode. For example on a PC with an ISA bus you would use the + IA32 in/out port instructions. The cs8900_device structure passed + to these functions provide these functions with the I/O base + address. The BSP must provide these functions. + + The Memory set/get functions access the CS8900 internal registers + and frame buffers directly from a 4K byte block of host memory. + Memory mode provides a faster access to the CS8900. The cs8900_device + structure passed to these functions provides the memory base + address. The BSP needs to provide these functions but they do not + need to be implemented if the mem_base field is set to 0. The + driver will use I/O mode only. + + The Block transfer functions are used to read or write a block + of memory from the CS8900. This saves the driver making a number + of small calls. The BSP driver must know if I/O or Memory mode + can be used. + + The final group of functions is to handle interrupts. The BSP + must take care of save and restoring any interrupt state + information. + + The BSP declares a 'cs8900_device' structure for each device being + attached to the networking stack. It also creates a + 'struct rtems_bsdnet_ifconfig' which is used to attach the interface + to the networking stack. The following code declares the BSD config: + + static cs8900_device cs8900; + + static struct rtems_bsdnet_ifconfig cs8900_ifconfig = + { + "cs0", + cs8900_driver_attach, + NULL, + NULL, + NULL, + NULL, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + }; + + The device linked to the BSD config structure with: + + cs8900_ifconfig.drv_ctrl = &cs8900; + + If you have a specific hardware address you should point the BSD + config structure to that address. If you do not the driver will read + the MAC address from the CS8900. This assumes the CS8900 has read + the address from an external EEPROM or has been setup by a BIOS or + boot monitor. For EEPROM less you need to supply the MAC address. + + Set the I/O and Memory base addresses. If the Memory base address + is 0 the driver will use I/O mode only. A typical initialisation + looks like: + + printf ("RTEMS BSD Network initialisation.\n"); + rtems_bsdnet_initialize_network (); + + #define ETHERNET_IO_BASE 0x300 + #define ETHERNET_MEM_BASE 0 + #define ETHERNET_IRQ_LEVEL 0 + + cs8900_device *cs = &cs8900; + + memset (cs, 0, sizeof (cs8900_device)); + + cs->dev = 0; + cs->io_base = ETHERNET_IO_BASE; + cs->mem_base = ETHERNET_MEM_BASE; + cs->irq_level = ETHERNET_IRQ_LEVEL; + cs->rx_queue_size = 30; + + cs8900_ifconfig.drv_ctrl = &cs8900; + + printf ("CS8900 initialisation\n"); + + rtems_bsdnet_attach (&cs8900_ifconfig); + + flags = IFF_UP; + if (rtems_bsdnet_ifconfig (cs8900_ifconfig.name, + SIOCSIFFLAGS, + &flags) < 0) + { + printf ("error: can't bring up %s: %s\n", + cs8900_ifconfig.name, strerror (errno)); + return; + } + + rtems_bsdnet_do_bootp_and_rootfs (); + + The IRQ level is the one documented in the CS8900 datasheet and below + in the CS8900 device structure. You need to map your target IRQ to the + CS8900 in the BSP driver. */ @@ -327,6 +452,12 @@ #define CS8900_TRACE 0 #define CS8900_TRACE_SIZE (400) +/* + * The default receive queue size. If the BSP sets this field to + * 0 this default is used. + */ +#define CS8900_RX_QUEUE_SIZE (30) + /* * Stats, more for debugging than anything else. */ @@ -380,6 +511,32 @@ typedef struct int dev; + /* + * Memory base addresses. Making mem_base 0 forces the + * driver to perform only I/O space accesses. + */ + + unsigned long io_base; + unsigned long mem_base; + + /* + * The IRQ level as defined in the datasheet for the CS8900. + * + * ISA BUS Pin Value + * IRQ10 INTRQ0 0 + * IRQ11 INTRQ1 1 + * IRQ12 INTRQ2 2 + * IRQ5 INTRQ3 3 + */ + + int irq_level; + + /* + * The MAC address. + */ + + unsigned char mac_address[6]; + /* * The bsdnet information structure. */ @@ -399,6 +556,7 @@ typedef struct /* * The queues. FIXME : these should be changed to be mbuf lists. */ + struct mbuf *rx_ready_head; struct mbuf *rx_ready_tail; int rx_ready_len; @@ -407,6 +565,13 @@ typedef struct struct mbuf *rx_loaded_tail; int rx_loaded_len; + /* + * Number of mbufs queued for the interrupt handler to + * loop reading. + */ + + int rx_queue_size; + #if CS8900_TRACE unsigned short trace_key[CS8900_TRACE_SIZE]; unsigned long trace_var[CS8900_TRACE_SIZE]; @@ -414,7 +579,7 @@ typedef struct int trace_in; #endif - /* + /** * Standard(!) ethernet statistics */ @@ -423,27 +588,176 @@ typedef struct } cs8900_device; /* - * Link is active, and RX count. - */ - -int cs8900_link_active (int dev); -int cs8900_driver_attach (struct rtems_bsdnet_ifconfig *config, - int attaching); -rtems_isr cs8900_interrupt (rtems_vector_number v, void *cs); - -/* - * Functions Users Provide to implement the driver. - */ - -void cs8900_attach_interrupt (int dev, cs8900_device *cs); -void cs8900_detach_interrupt (int dev); -void cs8900_get_mac_addr (int dev, unsigned char *mac_address); -void cs8900_io_set_reg (int dev, unsigned short reg, unsigned short data); -unsigned short cs8900_io_get_reg (int dev, unsigned short reg); -void cs8900_mem_set_reg (int dev, unsigned long reg, unsigned short data); -unsigned short cs8900_mem_get_reg (int dev, unsigned long reg); -void cs8900_put_data_block (int dev, int len, unsigned char *data); -unsigned short cs8900_get_data_block (int dev, unsigned char *data); -void cs8900_tx_load (int dev, struct mbuf *m); + * Link active returns the state of the PHY. + * + * @param cs Pointer to the device structure. + */ + +int cs8900_link_active (cs8900_device *cs); + +/** + * The RTEMS network stack driver attach function that is loaded into the + * the rtems_bsdnet_ifconfig struct. The network stack will call this + * function when attaching the driver. The BSP must load the 'drv_ctrl' + * field of the structure before calling the 'rtems_bsdnet_attach' + * function. + * + * @param config The RTEMS BSD config structure. + * + * @param attaching True is the stack is attaching the interface. + * + * @retval int Set to 1 if the device has attached. + */ + +int cs8900_driver_attach (struct rtems_bsdnet_ifconfig *config, + int attaching); + +/** + * The BSP specific interrupt wrapper calls this function when a device + * interrupt occurs. + * + * @param v The RTEMS vector number that generated the interrupt. + * + * @param cs Pointer to the device structure passed to the interrupt + * catch function provided by the BSP. + * + * @retval rtems_isr The standard ISR return type. + */ + +rtems_isr cs8900_interrupt (rtems_vector_number v, void *cs); + +/** + * Get the MAC address for the interface. + * + * @param cs Pointer to the device structure. + * + * @param mac_address Pointer to the memory to load the MAC address. This + * is a 6 byte buffer so do not exceeed the bounds. + */ + +void cs8900_get_mac_addr (cs8900_device *cs, unsigned char *mac_address); + +/** + * Catch the device interrupt. When the interrupt is called call the + * function 'cs8900_interrupt'. + * + * BSP to provide this function. + * + * @param cs Pointer to the device structure. + */ + +void cs8900_attach_interrupt (cs8900_device *cs); + +/** + * Detach the device interrupt. + * + * BSP to provide this function. + * + * @param cs Pointer to the device structure. + */ + +void cs8900_detach_interrupt (cs8900_device *cs); + +/** + * Write to an IO space register. + * + * BSP to provide this function. + * + * @param cs Pointer to the device structure. + * + * @param reg Register offset from the IO base. + * + * @param data The data to be written to the register. + */ + +void cs8900_io_set_reg (cs8900_device *cs, + unsigned short reg, unsigned short data); + +/** + * Read an IO space register. + * + * BSP to provide this function. + * + * @param cs Pointer to the device structure. + * + * @param reg Register offset from the IO base. + * + * @retval unsigned short The register data. + */ + +unsigned short cs8900_io_get_reg (cs8900_device *cs, unsigned short reg); + +/** + * Write to a memory space register. Will only be called is the mem_base + * field of the 'cs' struct is not 0. + * + * BSP to provide this function. + * + * @param cs Pointer to the device structure. + * + * @param reg Register offset from the memory base. + * + * @param data The data to be written to the register. + */ + +void cs8900_mem_set_reg (cs8900_device *cs, + unsigned long reg, unsigned short data); + +/** + * Read a memory space register. Will only be called is the mem_base + * field of the 'cs' struct is not 0. + * + * BSP to provide this function. + * + * @param cs Pointer to the device structure. + * + * @param reg Register offset from the IO base. + * + * @retval unsigned short The register data. + */ + +unsigned short cs8900_mem_get_reg (cs8900_device *cs, unsigned long reg); + +/** + * Write a block of data to the interface. The BSP codes if this is an IO or + * memory space write. + * + * BSP to provide this function. + * + * @param cs Pointer to the device structure. + * + * @param len The length of data to write. + * + * @param data Pointer to the data to be written. + */ + +void cs8900_put_data_block (cs8900_device *cs, int len, unsigned char *data); + +/** + * Read a block of data from the interface. The BSP codes if this is an IO or + * memory space write. The read must not be longer than the MTU size. + * + * BSP to provide this function. + * + * @param cs Pointer to the device structure. + * + * @param data Pointer to the buffer where the data is to be written. + * + * @retval unsigned short The number of bytes read from the device. + */ + +unsigned short cs8900_get_data_block (cs8900_device *cs, unsigned char *data); + +/** + * Load a mbuf chain to the device ready for tranmission. + * + * BSP to provide this function. + * + * @param cs Pointer to the device structure. + * + * @param m Pointer to the head of an mbuf chain. + */ + +void cs8900_tx_load (cs8900_device *cs, struct mbuf *m); #endif -- cgit v1.2.3