📄 cs8900.c
字号:
/* ------------------------------------------------------------------------ $Id: cs8900.c,v 1.5.2.2 2003/09/04 18:46:04 joel Exp $ ------------------------------------------------------------------------ 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.rtems.com/license/LICENSE. ------------------------------------------------------------------------ CS8900 net boot driver.*/#include <sys/errno.h>#include <string.h>#include <stdio.h>/* #include <target.h> chris explain what this is to contain and provide a default one */#include "cs8900.h"/*********************************************************** *********************************************************** BEGIN SECTION OF DEFAULT DEFINES *********************************************************** ***********************************************************//* * Number of devices supported by this driver */#ifndef CS8900_DEVICES#define CS8900_DEVICES 1#endif/* * 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. */#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 shortio_pp_get_reg_16 (int dev, unsigned short reg){ 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 inline unsigned longio_pp_get_reg_32 (int dev, unsigned short reg){ 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 inline voidio_pp_set_reg_16 (int dev, unsigned short reg, unsigned short data){ 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 inline voidio_pp_set_reg_32 (int dev, unsigned short reg, unsigned long data){ 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 inline voidio_pp_bit_set_reg_16 (int dev, unsigned short reg, unsigned short mask){ io_pp_set_reg_16 (dev, reg, io_pp_get_reg_16 (dev, reg) | mask);}static inline voidio_pp_bit_clear_reg_16 (int dev, unsigned short reg, unsigned short mask){ io_pp_set_reg_16 (dev, reg, io_pp_get_reg_16 (dev, reg) & ~mask);}/* * Memory Mapped Packet Page interface. */static inline unsigned shortmem_pp_get_reg (int dev, unsigned short reg){ return cs8900_mem_get_reg (dev, CS8900_MEMORY_BASE + reg);}static inline voidmem_pp_set_reg (int dev, unsigned short reg, unsigned short data){ cs8900_mem_set_reg (dev, CS8900_MEMORY_BASE + reg, data);}static inline voidmem_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);}static inline voidmem_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);}/* * 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_TRACEstatic 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. */rtems_unsigned32 rtems_read_timer ();static inline voidcs8900_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/* * Bring the chip online. */static voidcs8900_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); rtems_task_wake_after (TOD_MILLISECONDS_TO_TICKS (20)); status = io_pp_get_reg_16 (dev, CS8900_PP_SelfST); if (status == 0) { printf("Reading status register again\n"); 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))) { 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 ((prod_id >> 16) != CS8900_ESIA_ID) { 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);}rtems_isrcs8900_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; ++cs->eth_stats.interrupts; while (1) { isq = mem_pp_get_reg (dev, 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: /* * 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; case 0x12: /* * TxCol. */ cs->eth_stats.tx_collisions += mem_pp_get_reg (dev, CS8900_PP_TxCol) >> 6; break; default: break; } } }intcs8900_link_active (int dev){ return ((mem_pp_get_reg (dev, CS8900_PP_LineST) & CS8900_LINE_STATUS_LINK_OK) ? 1 : 0);}static inline voidcs8900_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) { 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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -