summaryrefslogtreecommitdiffstats
path: root/bsps/shared/net/cs8900.c
diff options
context:
space:
mode:
Diffstat (limited to 'bsps/shared/net/cs8900.c')
-rw-r--r--bsps/shared/net/cs8900.c1216
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;
-}