diff options
Diffstat (limited to 'bsps/shared/net/cs8900.c')
-rw-r--r-- | bsps/shared/net/cs8900.c | 1216 |
1 files changed, 0 insertions, 1216 deletions
diff --git a/bsps/shared/net/cs8900.c b/bsps/shared/net/cs8900.c deleted file mode 100644 index 452a33a372..0000000000 --- a/bsps/shared/net/cs8900.c +++ /dev/null @@ -1,1216 +0,0 @@ -/* - ------------------------------------------------------------------------ - - 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.org/license/LICENSE. - - ------------------------------------------------------------------------ - - CS8900 RTEMS driver. - - See the header file for details. - -*/ - -#include <machine/rtems-bsd-kernel-space.h> - -#include <errno.h> -#include <string.h> -#include <stdio.h> - -#include <libchip/cs8900.h> - -/* - * We expect to be able to read a complete packet into an mbuf. - */ - -#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 - -/* - * IO Packet Page inteface. - */ - -static inline unsigned short -io_pp_get_reg_16 (cs8900_device *cs, unsigned short reg) -{ - 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); - data = cs8900_io_get_reg (cs, CS8900_IO_PP_DATA_PORT0); - rtems_interrupt_enable (level); - return data; -} - -static inline uint32_t -io_pp_get_reg_32 (cs8900_device *cs, uint16_t reg) -{ - rtems_interrupt_level level; - uint32_t data; - rtems_interrupt_disable (level); - cs8900_io_set_reg (cs, CS8900_IO_PACKET_PAGE_PTR, - 0x3000 | CS8900_PPP_AUTO_INCREMENT | reg); - data = cs8900_io_get_reg (cs, CS8900_IO_PP_DATA_PORT0); - data <<= 16; - data |= cs8900_io_get_reg (cs, CS8900_IO_PP_DATA_PORT1); - rtems_interrupt_enable (level); - return data; -} - -static inline void -io_pp_set_reg_16 (cs8900_device *cs, unsigned short reg, unsigned short data) -{ - 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 (cs, CS8900_IO_PP_DATA_PORT0, data); - rtems_interrupt_enable (level); -} - -static inline void -io_pp_set_reg_32 (cs8900_device *cs, unsigned short reg, unsigned long data) -{ - cs8900_io_set_reg (cs, CS8900_IO_PACKET_PAGE_PTR, - 0x3000 | CS8900_PPP_AUTO_INCREMENT | reg); - 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 (cs8900_device *cs, unsigned short reg, unsigned short 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 (cs8900_device *cs, unsigned short reg, unsigned short 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 (cs8900_device *cs, unsigned short 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 (cs8900_device *cs, unsigned short reg, unsigned short 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 (cs8900_device *cs, unsigned short reg, unsigned short 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 (cs8900_device *cs, unsigned short reg, unsigned short 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) -#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[] = -{ - "int", - "rx ok", - "rx dropped", - "no mbuf", - "no clusters", - "rx begin", - "rx end" -}; - -/* - * Assumes a micro-second timer such as the Coldfire. - */ - -uint32_t rtems_read_timer (); - -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; - 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 - -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. - */ - -static void -cs8900_hardware_init (cs8900_device *cs) -{ - unsigned long prod_id; - unsigned short status; - - /* - * Do nothing while the device is calibrating and checking the EEPROM. - * We must wait 20msecs. - */ - - io_pp_bit_set_reg_16 (cs, CS8900_PP_SelfCTL, CS8900_SELF_CTRL_RESET); - - rtems_task_wake_after (RTEMS_MILLISECONDS_TO_TICKS (20)); - - 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 (cs, 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))) - { - printf ("CS8900: %s. Initialisation aborted.\n", - (status & CS8900_SELF_STATUS_INITD) ? - "EEPROM read/write failed to complete" : - "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 (cs, CS8900_PP_PROD_ID); - - if ((prod_id >> 16) != CS8900_ESIA_ID) - { - printf ("CS8900: Invalid EISA ID, read product code 0x%08lx\n", prod_id); - return; - } - - if ((prod_id & 0x000000ff) != 0) - { - printf ("CS8900: 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. - */ - - 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. - */ - - /* - * Program the Line Control register with the mode we want. - * - * No auto detect support at the moment. Only 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 (cs, CS8900_PP_IA, - (((unsigned int) MACO (1)) << 8) | - ((unsigned int) MACO (0))); - mem_pp_set_reg (cs, CS8900_PP_IA + 2, - (((unsigned int) MACO (3)) << 8) | - ((unsigned int) MACO (2))); - mem_pp_set_reg (cs, CS8900_PP_IA + 4, - (((unsigned int) MACO (5)) << 8) | - ((unsigned int) MACO (4))); - - /* - * Set the Buffer configuration. - */ - - 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 | - CS8900_BUFFER_CONFIG_RX_MISSED_OVF); - - /* - * Set the Receiver configuration. - */ - - mem_pp_set_reg (cs, 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 (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 (cs, 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 (cs); - - /* - * Program the interrupt level we require then enable interrupts. - * - * Note, this will need to change to support other levels. - */ - - mem_pp_set_reg (cs, CS8900_PP_INT, cs->irq_level & 3); - - mem_pp_bit_set_reg (cs, CS8900_PP_BusCTL, - CS8900_BUS_CTRL_ENABLE_INT); -} - -rtems_isr -cs8900_interrupt (rtems_vector_number v, void *csp) -{ - cs8900_device *cs = csp; - unsigned short isq = 0; - struct mbuf *m; - unsigned char *p; - - ++cs->eth_stats.interrupts; - - while (1) - { - isq = mem_pp_get_reg (cs, CS8900_PP_ISQ); - - cs8900_trace (cs, CS8900_T_INT, isq); - - /* - * 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 (cs, 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_bsdnet_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_bsdnet_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_bsdnet_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_bsdnet_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_bsdnet_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 (cs, CS8900_PP_RxMISS) >> 6; - break; - - case 0x12: - - /* - * TxCol. - */ - - cs->eth_stats.tx_collisions += - mem_pp_get_reg (cs, CS8900_PP_TxCol) >> 6; - break; - - default: - break; - } - } - -} - -int -cs8900_link_active (cs8900_device *cs) -{ - return ((mem_pp_get_reg (cs, 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; - - /* - * Hold a single queue of mbuf's at the interface. This - * will lower the latency of the driver. - */ - - 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); - 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; - 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 (cs, CS8900_PP_LineCFG, - CS8900_LINE_CTRL_RX_ON | - CS8900_LINE_CTRL_TX_ON); - - /* - * Start the software interrupt watchdog. - */ - - mem_pp_bit_set_reg (cs, CS8900_PP_BufCFG, - CS8900_BUFFER_CONFIG_SW_INT); - ++cs->eth_stats.int_swint_req; - - /* - * Loop reading packets. - */ - - while (1) - { - cs8900_rx_refill_queue (cs); - - sc = rtems_bsdnet_event_receive (CS8900_RX_OK_EVENT, - RTEMS_WAIT | RTEMS_EVENT_ANY, - RTEMS_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 (cs, CS8900_PP_BusCTL, - CS8900_BUS_CTRL_ENABLE_INT); - - 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 (cs, CS8900_PP_BusCTL, - CS8900_BUS_CTRL_ENABLE_INT); - } - - mem_pp_bit_set_reg (cs, CS8900_PP_BufCFG, - CS8900_BUFFER_CONFIG_SW_INT); - ++cs->eth_stats.int_swint_req; - } - - 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); - } -} - -static void -cs8900_tx_task (void *arg) -{ - cs8900_device *cs = arg; - 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 (RTEMS_MILLISECONDS_TO_TICKS (750)); - - /* - * Loop processing the tx queue. - */ - - while (1) - { - /* - * Fetch the mbuf list from the interface's queue. - */ - - IF_DEQUEUE (&ifp->if_snd, m); - - /* - * If something actually is present send it. - */ - - if (!m) - { - 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 (cs)) - { - int resending; - - do - { - unsigned short buf_status; - - resending = 0; - - cs->tx_active = 1; - - mem_pp_set_reg (cs, CS8900_PP_TxCMD, - CS8900_TX_CMD_STATUS_TX_START_ENTIRE | - CS8900_TX_CMD_STATUS_FORCE); - 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 - * transmit and try again next time. - */ - - 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, - RTEMS_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 (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, - RTEMS_WAIT | RTEMS_EVENT_ANY, - RTEMS_NO_TIMEOUT, - &events); - } - while (cs->tx_active); - } - else - { - ++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_bsdnet_event_send (cs->tx_task, CS8900_TX_START_EVENT); -} - -static void -cs8900_stop (cs8900_device *cs) -{ - mem_pp_bit_clear_reg (cs, CS8900_PP_LineCFG, - CS8900_LINE_CTRL_RX_ON | - CS8900_LINE_CTRL_TX_ON); - - mem_pp_bit_clear_reg (cs, 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 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 (cs, CS8900_PP_RxMISS) >> 6; - - cs->eth_stats.tx_collisions += - 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++) - { - 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]); - - i++; - - if (i < (sizeof (eth_statistics_labels) / sizeof (const char *))) - printf (" %*s - %10lu", - max_label, eth_statistics_labels[i], value[i]); - printf ("\n"); - } - -#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 - 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 -} - -static void -cs8900_init (void *arg) -{ - cs8900_device *cs = arg; - 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 (cs, CS8900_PP_LineCFG, - CS8900_LINE_CTRL_RX_ON | - CS8900_LINE_CTRL_TX_ON); - - mem_pp_bit_set_reg (cs, CS8900_PP_BusCTL, - CS8900_BUS_CTRL_ENABLE_INT); -} - -static int -cs8900_ioctl (struct ifnet *ifp, ioctl_command_t cmd, caddr_t data) -{ - 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; -} - -int -cs8900_driver_attach (struct rtems_bsdnet_ifconfig *config, int attaching) -{ - 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; - - cs = config->drv_ctrl; - 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 (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; - 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 (cs); - } - - return 1; -} |