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.
This commit is contained in:
Chris Johns
2004-03-14 01:28:08 +00:00
parent 27192b8981
commit 00bf774547
2 changed files with 602 additions and 299 deletions

View File

@@ -1,23 +1,28 @@
/* /*
------------------------------------------------------------------------ ------------------------------------------------------------------------
$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 Copyright Cybertec Pty Ltd, 2000
All rights reserved 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. COPYRIGHT (c) 1989-1998.
On-Line Applications Research Corporation (OAR). On-Line Applications Research Corporation (OAR).
Copyright assigned to U.S. Government, 1994.
The license and distribution terms for this file may be The license and distribution terms for this file may be
found in the file LICENSE in this distribution or at 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.
*/ */
@@ -25,67 +30,8 @@
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
/* #include <target.h>
chris explain what this is to contain and provide a default one */
#include "cs8900.h" #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. * We expect to be able to read a complete packet into an mbuf.
*/ */
@@ -103,88 +49,124 @@ extern unsigned int bsp_cs8900_memory_base;
#define CS8900_TX_OK_EVENT RTEMS_EVENT_2 #define CS8900_TX_OK_EVENT RTEMS_EVENT_2
#define CS8900_TX_WAIT_EVENT RTEMS_EVENT_3 #define CS8900_TX_WAIT_EVENT RTEMS_EVENT_3
/*
* Our local data.
*/
static cs8900_device cs8900[CS8900_DEVICES];
/* /*
* IO Packet Page inteface. * IO Packet Page inteface.
*/ */
static inline unsigned short 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); 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 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); 0x3000 | CS8900_PPP_AUTO_INCREMENT | reg);
return ((cs8900_io_get_reg (dev, CS8900_IO_BASE + CS8900_IO_PP_DATA_PORT0) << 16) | data = ((cs8900_io_get_reg (cs, CS8900_IO_PP_DATA_PORT0) << 16) |
cs8900_io_get_reg (dev, CS8900_IO_BASE + CS8900_IO_PP_DATA_PORT1)); cs8900_io_get_reg (cs, CS8900_IO_PP_DATA_PORT1));
rtems_interrupt_enable (level);
return data;
} }
static inline void 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); 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 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); 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 (cs, 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_PORT1, data);
} }
static inline void 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 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. * Memory Mapped Packet Page interface.
*
* If the BSP does not configure mem_base use the I/O register accesses.
*/ */
static inline unsigned short 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 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 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 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);
}
} }
/* /*
@@ -239,6 +221,28 @@ cs8900_trace (cs8900_device *cs, unsigned short key, unsigned long var)
#define cs8900_trace(c, k, v) #define cs8900_trace(c, k, v)
#endif #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. * Bring the chip online.
*/ */
@@ -248,21 +252,20 @@ cs8900_hardware_init (cs8900_device *cs)
{ {
unsigned long prod_id; unsigned long prod_id;
unsigned short status; unsigned short status;
int dev = cs->dev;
/* /*
* Do nothing while the device is calibrating and checking the EEPROM. * Do nothing while the device is calibrating and checking the EEPROM.
* We must wait 20msecs. * 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)); 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) { if (status == 0) {
printf("Reading status register again\n"); 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) || if (((status & CS8900_SELF_STATUS_INITD) == 0) ||
@@ -277,19 +280,24 @@ cs8900_hardware_init (cs8900_device *cs)
return; 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 */ /* 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) 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; return;
} }
if ((prod_id & 0x000000ff) != 0) 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); prod_id);
return; return;
} }
@@ -304,18 +312,21 @@ cs8900_hardware_init (cs8900_device *cs)
* Switch to memory base accesses as they are faster. No indirect access. * 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); if (cs->mem_base)
io_pp_set_reg_16 (dev, CS8900_PP_MEM_BASE + 2, (CS8900_MEMORY_BASE >> 16) & 0xf); {
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 (dev, io_pp_set_reg_16 (cs,
CS8900_PP_BusCTL, CS8900_PP_BusCTL,
CS8900_BUS_CTRL_RESET_RX_DMA | CS8900_BUS_CTRL_RESET_RX_DMA |
CS8900_BUS_CTRL_USE_SA | CS8900_BUS_CTRL_USE_SA |
CS8900_BUS_CTRL_MEMORY_ENABLE); CS8900_BUS_CTRL_MEMORY_ENABLE);
io_pp_set_reg_16 (dev, io_pp_set_reg_16 (cs,
CS8900_PP_BusCTL, CS8900_PP_BusCTL,
CS8900_BUS_CTRL_USE_SA | CS8900_BUS_CTRL_USE_SA |
CS8900_BUS_CTRL_MEMORY_ENABLE); CS8900_BUS_CTRL_MEMORY_ENABLE);
}
/* /*
* We are now in memory mapped mode. * We are now in memory mapped mode.
@@ -327,7 +338,7 @@ cs8900_hardware_init (cs8900_device *cs)
* No auto detect support at the moment. Only 10BaseT. * 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. * Ask the user for the MAC address, the program into the device.
@@ -335,13 +346,13 @@ cs8900_hardware_init (cs8900_device *cs)
#define MACO(o) cs->arpcom.ac_enaddr[o] #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 (1)) << 8) |
((unsigned int) MACO (0))); ((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 (3)) << 8) |
((unsigned int) MACO (2))); ((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 (5)) << 8) |
((unsigned int) MACO (4))); ((unsigned int) MACO (4)));
@@ -349,7 +360,7 @@ cs8900_hardware_init (cs8900_device *cs)
* Set the Buffer configuration. * 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_RDY_FOR_TX |
CS8900_BUFFER_CONFIG_TX_UNDERRUN | CS8900_BUFFER_CONFIG_TX_UNDERRUN |
CS8900_BUFFER_CONFIG_TX_COL_OVF | CS8900_BUFFER_CONFIG_TX_COL_OVF |
@@ -359,7 +370,7 @@ cs8900_hardware_init (cs8900_device *cs)
* Set the Receiver configuration. * 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_RX_OK |
CS8900_RX_CONFIG_CRC_ERROR | CS8900_RX_CONFIG_CRC_ERROR |
CS8900_RX_CONFIG_RUNT| CS8900_RX_CONFIG_RUNT|
@@ -369,7 +380,7 @@ cs8900_hardware_init (cs8900_device *cs)
* Set the Receiver control. * 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_RX_OK |
CS8900_RX_CTRL_MULTICAST | CS8900_RX_CTRL_MULTICAST |
CS8900_RX_CTRL_INDIVIDUAL | CS8900_RX_CTRL_INDIVIDUAL |
@@ -379,7 +390,7 @@ cs8900_hardware_init (cs8900_device *cs)
* Set the Transmitter configuration. * 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_TX_OK |
CS8900_TX_CONFIG_OUT_OF_WINDOW | CS8900_TX_CONFIG_OUT_OF_WINDOW |
CS8900_TX_CONFIG_JABBER | CS8900_TX_CONFIG_JABBER |
@@ -389,15 +400,17 @@ cs8900_hardware_init (cs8900_device *cs)
* Attach the interrupt handler. * Attach the interrupt handler.
*/ */
cs8900_attach_interrupt (dev, cs); cs8900_attach_interrupt (cs);
/* /*
* Program the interrupt level we require then enable interrupts. * 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); CS8900_BUS_CTRL_ENABLE_INT);
} }
@@ -405,7 +418,6 @@ rtems_isr
cs8900_interrupt (rtems_vector_number v, void *csp) cs8900_interrupt (rtems_vector_number v, void *csp)
{ {
cs8900_device *cs = csp; cs8900_device *cs = csp;
int dev = cs->dev;
unsigned short isq = 0; unsigned short isq = 0;
struct mbuf *m; struct mbuf *m;
unsigned char *p; unsigned char *p;
@@ -414,12 +426,10 @@ cs8900_interrupt (rtems_vector_number v, void *csp)
while (1) 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); cs8900_trace (cs, CS8900_T_INT, isq);
WATCHDOG_TOGGLE ();
/* /*
* No more interrupts to service. * No more interrupts to service.
*/ */
@@ -450,7 +460,7 @@ cs8900_interrupt (rtems_vector_number v, void *csp)
p = mtod (m, unsigned char *); 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) if (cs->rx_loaded_tail == 0)
cs->rx_loaded_head = m; cs->rx_loaded_head = m;
@@ -540,7 +550,7 @@ cs8900_interrupt (rtems_vector_number v, void *csp)
*/ */
cs->eth_stats.rx_missed_errors += 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; break;
case 0x12: case 0x12:
@@ -550,7 +560,7 @@ cs8900_interrupt (rtems_vector_number v, void *csp)
*/ */
cs->eth_stats.tx_collisions += cs->eth_stats.tx_collisions +=
mem_pp_get_reg (dev, CS8900_PP_TxCol) >> 6; mem_pp_get_reg (cs, CS8900_PP_TxCol) >> 6;
break; break;
default: default:
@@ -561,9 +571,9 @@ cs8900_interrupt (rtems_vector_number v, void *csp)
} }
int 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); 1 : 0);
} }
@@ -579,7 +589,7 @@ cs8900_rx_refill_queue (cs8900_device *cs)
* will lower the latency of the driver. * 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); MGETHDR (m, M_DONTWAIT, MT_DATA);
@@ -619,7 +629,6 @@ static void
cs8900_rx_task (void *arg) cs8900_rx_task (void *arg)
{ {
cs8900_device *cs = arg; cs8900_device *cs = arg;
int dev = cs->dev;
struct ifnet *ifp = &cs->arpcom.ac_if; struct ifnet *ifp = &cs->arpcom.ac_if;
rtems_event_set events; rtems_event_set events;
struct mbuf *m; struct mbuf *m;
@@ -631,7 +640,7 @@ cs8900_rx_task (void *arg)
* Turn the receiver and transmitter on. * 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_RX_ON |
CS8900_LINE_CTRL_TX_ON); CS8900_LINE_CTRL_TX_ON);
@@ -639,11 +648,9 @@ cs8900_rx_task (void *arg)
* Start the software interrupt watchdog. * Start the software interrupt watchdog.
*/ */
rtems_interrupt_disable (level); mem_pp_bit_set_reg (cs, CS8900_PP_BufCFG,
mem_pp_bit_set_reg (dev, CS8900_PP_BufCFG,
CS8900_BUFFER_CONFIG_SW_INT); CS8900_BUFFER_CONFIG_SW_INT);
++cs->eth_stats.int_swint_req; ++cs->eth_stats.int_swint_req;
rtems_interrupt_enable (level);
/* /*
* Loop reading packets. * Loop reading packets.
@@ -675,23 +682,21 @@ cs8900_rx_task (void *arg)
{ {
printf ("cs8900: int lockup, isq flush\n"); 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); 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_swint_req = cs->eth_stats.int_swint_res = 0;
++cs->eth_stats.int_lockup; ++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); CS8900_BUS_CTRL_ENABLE_INT);
} }
rtems_interrupt_disable (level); mem_pp_bit_set_reg (cs, CS8900_PP_BufCFG,
mem_pp_bit_set_reg (dev, CS8900_PP_BufCFG,
CS8900_BUFFER_CONFIG_SW_INT); CS8900_BUFFER_CONFIG_SW_INT);
++cs->eth_stats.int_swint_req; ++cs->eth_stats.int_swint_req;
rtems_interrupt_enable (level);
} }
cs8900_trace (cs, CS8900_T_RX_BEGIN, cs->rx_loaded_len); cs8900_trace (cs, CS8900_T_RX_BEGIN, cs->rx_loaded_len);
@@ -737,7 +742,6 @@ static void
cs8900_tx_task (void *arg) cs8900_tx_task (void *arg)
{ {
cs8900_device *cs = arg; cs8900_device *cs = arg;
int dev = cs->dev;
struct ifnet *ifp = &cs->arpcom.ac_if; struct ifnet *ifp = &cs->arpcom.ac_if;
rtems_event_set events; rtems_event_set events;
struct mbuf *m; struct mbuf *m;
@@ -776,7 +780,7 @@ cs8900_tx_task (void *arg)
} }
else else
{ {
if (cs8900_link_active (dev)) if (cs8900_link_active (cs))
{ {
int resending; int resending;
@@ -788,12 +792,12 @@ cs8900_tx_task (void *arg)
cs->tx_active = 1; 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_TX_START_ENTIRE |
CS8900_TX_CMD_STATUS_FORCE); CS8900_TX_CMD_STATUS_FORCE);
mem_pp_set_reg (dev, CS8900_PP_TxLength, m->m_pkthdr.len); mem_pp_set_reg (cs, CS8900_PP_TxLength, m->m_pkthdr.len);
buf_status = mem_pp_get_reg (dev, CS8900_PP_BusST); buf_status = mem_pp_get_reg (cs, CS8900_PP_BusST);
/* /*
* If the bid for memory in the device fails trash the * If the bid for memory in the device fails trash the
@@ -830,7 +834,7 @@ cs8900_tx_task (void *arg)
if (!resending) if (!resending)
{ {
cs8900_tx_load (dev, m); cs8900_tx_load (cs, m);
cs->eth_stats.tx_packets++; cs->eth_stats.tx_packets++;
cs->eth_stats.tx_bytes += m->m_pkthdr.len; cs->eth_stats.tx_bytes += m->m_pkthdr.len;
} }
@@ -875,13 +879,11 @@ cs8900_start (struct ifnet *ifp)
static void static void
cs8900_stop (cs8900_device *cs) cs8900_stop (cs8900_device *cs)
{ {
int dev = cs->dev; mem_pp_bit_clear_reg (cs, CS8900_PP_LineCFG,
mem_pp_bit_clear_reg (dev, CS8900_PP_LineCFG,
CS8900_LINE_CTRL_RX_ON | CS8900_LINE_CTRL_RX_ON |
CS8900_LINE_CTRL_TX_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); CS8900_BUS_CTRL_ENABLE_INT);
} }
@@ -917,17 +919,16 @@ static const char *eth_statistics_labels[] =
static void static void
cs8900_stats (cs8900_device *cs) cs8900_stats (cs8900_device *cs)
{ {
int dev = cs->dev;
int i; int i;
int max_label = 0; int max_label = 0;
int len; int len;
unsigned long *value = (unsigned long*) &cs->eth_stats.rx_packets; unsigned long *value = (unsigned long*) &cs->eth_stats.rx_packets;
cs->eth_stats.rx_missed_errors += 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 += 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"); printf ("Network Driver Stats for CS8900 :\n");
@@ -1032,7 +1033,6 @@ static void
cs8900_init (void *arg) cs8900_init (void *arg)
{ {
cs8900_device *cs = arg; cs8900_device *cs = arg;
int dev = cs->dev;
struct ifnet *ifp = &cs->arpcom.ac_if; struct ifnet *ifp = &cs->arpcom.ac_if;
if (cs->rx_task == 0) if (cs->rx_task == 0)
@@ -1070,11 +1070,11 @@ cs8900_init (void *arg)
* 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_RX_ON |
CS8900_LINE_CTRL_TX_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); CS8900_BUS_CTRL_ENABLE_INT);
} }
@@ -1148,17 +1148,7 @@ cs8900_driver_attach (struct rtems_bsdnet_ifconfig *config, int attaching)
if ((unit = rtems_bsdnet_parse_driver_name (config, &name)) < 0) if ((unit = rtems_bsdnet_parse_driver_name (config, &name)) < 0)
return 0; return 0;
/* cs = config->drv_ctrl;
* Is driver free?
*/
if (unit >= CS8900_DEVICES)
{
printf ("Bad CS8900 unit number for device `%s'.\n", config->name);
return 0;
}
cs = &cs8900[unit];
cs->dev = unit; cs->dev = unit;
ifp = &cs->arpcom.ac_if; ifp = &cs->arpcom.ac_if;
@@ -1177,7 +1167,7 @@ cs8900_driver_attach (struct rtems_bsdnet_ifconfig *config, int attaching)
if (config->hardware_address) if (config->hardware_address)
memcpy (cs->arpcom.ac_enaddr, config->hardware_address, ETHER_ADDR_LEN); memcpy (cs->arpcom.ac_enaddr, config->hardware_address, ETHER_ADDR_LEN);
else else
cs8900_get_mac_addr (unit, cs->arpcom.ac_enaddr); cs8900_get_mac_addr (cs, cs->arpcom.ac_enaddr);
if (config->mtu) if (config->mtu)
mtu = config->mtu; mtu = config->mtu;
@@ -1219,9 +1209,8 @@ cs8900_driver_attach (struct rtems_bsdnet_ifconfig *config, int attaching)
} }
cs8900_stop (cs); cs8900_stop (cs);
cs8900_detach_interrupt (unit); cs8900_detach_interrupt (cs);
} }
return 1; return 1;
} }

View File

@@ -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 Copyright Cybertec Pty Ltd, 2000
All rights reserved 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. COPYRIGHT (c) 1989-1998.
On-Line Applications Research Corporation (OAR). On-Line Applications Research Corporation (OAR).
The license and distribution terms for this file may be The license and distribution terms for this file may be
found in the file LICENSE in this distribution or at 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 0
#define CS8900_TRACE_SIZE (400) #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. * Stats, more for debugging than anything else.
*/ */
@@ -380,6 +511,32 @@ typedef struct
int dev; 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. * The bsdnet information structure.
*/ */
@@ -399,6 +556,7 @@ typedef struct
/* /*
* The queues. FIXME : these should be changed to be mbuf lists. * The queues. FIXME : these should be changed to be mbuf lists.
*/ */
struct mbuf *rx_ready_head; struct mbuf *rx_ready_head;
struct mbuf *rx_ready_tail; struct mbuf *rx_ready_tail;
int rx_ready_len; int rx_ready_len;
@@ -407,6 +565,13 @@ typedef struct
struct mbuf *rx_loaded_tail; struct mbuf *rx_loaded_tail;
int rx_loaded_len; int rx_loaded_len;
/*
* Number of mbufs queued for the interrupt handler to
* loop reading.
*/
int rx_queue_size;
#if CS8900_TRACE #if CS8900_TRACE
unsigned short trace_key[CS8900_TRACE_SIZE]; unsigned short trace_key[CS8900_TRACE_SIZE];
unsigned long trace_var[CS8900_TRACE_SIZE]; unsigned long trace_var[CS8900_TRACE_SIZE];
@@ -414,7 +579,7 @@ typedef struct
int trace_in; int trace_in;
#endif #endif
/* /**
* Standard(!) ethernet statistics * Standard(!) ethernet statistics
*/ */
@@ -423,27 +588,176 @@ typedef struct
} cs8900_device; } cs8900_device;
/* /*
* Link is active, and RX count. * 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_link_active (int dev);
int cs8900_driver_attach (struct rtems_bsdnet_ifconfig *config, int cs8900_driver_attach (struct rtems_bsdnet_ifconfig *config,
int attaching); int attaching);
rtems_isr cs8900_interrupt (rtems_vector_number v, void *cs);
/* /**
* Functions Users Provide to implement the driver. * 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.
*/ */
void cs8900_attach_interrupt (int dev, cs8900_device *cs); rtems_isr cs8900_interrupt (rtems_vector_number v, void *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); * Get the MAC address for the interface.
unsigned short cs8900_io_get_reg (int dev, unsigned short reg); *
void cs8900_mem_set_reg (int dev, unsigned long reg, unsigned short data); * @param cs Pointer to the device structure.
unsigned short cs8900_mem_get_reg (int dev, unsigned long reg); *
void cs8900_put_data_block (int dev, int len, unsigned char *data); * @param mac_address Pointer to the memory to load the MAC address. This
unsigned short cs8900_get_data_block (int dev, unsigned char *data); * is a 6 byte buffer so do not exceeed the bounds.
void cs8900_tx_load (int dev, struct mbuf *m); */
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 #endif