Updated the BSP example code.

This commit is contained in:
Chris Johns
2004-03-14 01:28:34 +00:00
parent 00bf774547
commit 528da1cb9f
2 changed files with 452 additions and 196 deletions

View File

@@ -1,217 +1,283 @@
/*
------------------------------------------------------------------------
$Id$
------------------------------------------------------------------------
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.
* $Id$
*
* RTEMS CS8900 Driver Setup for the DIMM-PC/i386 made by Kontron.
*
* 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.
*
* Port performed by Chris Johns, Cybertec Pty Ltd, Jan 2004.
* Based on the Cybertec CS8900 driver setup for the SFP-101.
*
*/
#include <rtems/bspIo.h>
#define CS8900_VERBOSE 0
#define HAVE_MRB_CS8900_DATA_BUS_SWAPPED 1
#include <bsp.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#include <rtems.h>
#include <rtems/monitor.h>
#include <rtems/rtems_bsdnet.h>
#include <irq.h>
#include <libchip/cs8900.h>
#include "cs8900.h"
#include <net/route.h>
/*
* Our local data.
* Loopback interface.
*/
#ifdef CS8900_VERBOSE
static BOOLEAN cs8900_io_verbose;
#endif
extern int rtems_bsdnet_loopattach (struct rtems_bsdnet_ifconfig *, int);
static rtems_isr_void_entry old_handler[CS8900_DEVICES];
static void *old_parameter[CS8900_DEVICES];
static struct rtems_bsdnet_ifconfig loopback_config =
{
"lo0", /* name */
rtems_bsdnet_loopattach, /* attach function */
NULL, /* link to next interface */
"127.0.0.1", /* IP address */
"255.0.0.0", /* IP net mask */
};
/*
* Tables of IO addresses and interrupt levels for each device attached.
* Network configuration
*/
static const unsigned long ethernet_io_base[CS8900_DEVICES] =
struct rtems_bsdnet_config rtems_bsdnet_config =
{
ETHERNET_BASE
&loopback_config,
NULL,
20, /* Network task priority */
32 * 1024, /* Mbuf capacity */
96 * 1024, /* Mbuf cluster capacity */
};
static const unsigned long ethernet_mem_base[CS8900_DEVICES] =
static void cs8900_isr ();
static void cs8900_int_off (const rtems_irq_connect_data* unused);
static void cs8900_int_on (const rtems_irq_connect_data* unused);
static int cs8900_int_is_on (const rtems_irq_connect_data *irq);
/**
* The device's data.
*/
static cs8900_device cs8900;
static rtems_irq_connect_data cs8900_irq =
{
ETHERNET_BASE + CS8900_MEMORY_BASE
0,
cs8900_isr,
cs8900_int_on,
cs8900_int_off,
cs8900_int_is_on
};
static const unsigned int ethernet_irq_level[CS8900_DEVICES] =
{
ETHERNET_IRQ_LEVEL
};
static const unsigned int ethernet_irq_priority[CS8900_DEVICES] =
{
ETHERNET_IRQ_PRIORITY
};
static const unsigned int ethernet_irq_vector[CS8900_DEVICES] =
{
ETHERNET_IRQ_VECTOR,
};
void cs8900_io_set_reg (int dev, unsigned short reg, unsigned short data)
{
#ifdef CS8900_DATA_BUS_SWAPPED
data = (data >> 8) | (data << 8);
#if CS8900_VERBOSE
static int cs8900_io_verbose = 1;
#endif
#ifdef CS8900_VERBOSE
if (cs8900_io_verbose)
printf ("CS8900: io set reg=0x%04x, data=0x%04x\n", reg, data);
#endif
WRITE_REGISTER_16 (ethernet_io_base[dev] + reg, data);
/**
* Device structure for attaching to the BSD stack.
*/
static struct rtems_bsdnet_ifconfig cs8900_ifconfig =
{
"cs0", /* name */
cs8900_driver_attach, /* attach funtion */
NULL, /* next interface */
NULL, /* ip address */
NULL, /* ip netmask */
NULL, /* hardware address */
0, /* ignore broadcast */
0, /* mtu */
0, /* rbuf count */
0, /* xbuf count */
0, /* port */
0, /* irno */
0, /* bpar */
0 /* drv ctrl */
};
/*
* Commands to register.
*/
rtems_monitor_command_entry_t rtems_bsdnet_commands[] =
{
{
"ifstats",
"Show the interface stats.\n",
0,
(void*) rtems_bsdnet_show_if_stats,
0,
0,
},
{
"ipstats",
"Show the IP stats.\n",
0,
(void*) rtems_bsdnet_show_ip_stats,
0,
0,
},
{
"routes",
"Show the inet routes.\n",
0,
(void*) rtems_bsdnet_show_inet_routes,
0,
0,
},
{
"mbufs",
"Show the mbuf stats.\n",
0,
(void*) rtems_bsdnet_show_mbuf_stats,
0,
0,
},
{
"icmp",
"Show the ICMP stats.\n",
0,
(void*) rtems_bsdnet_show_icmp_stats,
0,
0,
},
{
"udp",
"Show the UDP stats.\n",
0,
(void*) rtems_bsdnet_show_udp_stats,
0,
0,
},
{
"tcp",
"Show the TCP stats.\n",
0,
(void*) rtems_bsdnet_show_tcp_stats,
0,
0,
}
};
static void
cs8900_isr ()
{
/*
* Note: we could have a high priority task here to call the
* drivers handler. The would lower the interrupt latancy
* we aother wise have.
*/
cs8900_interrupt (cs8900_irq.name, &cs8900);
}
unsigned short cs8900_io_get_reg (int dev, unsigned short reg)
static void
cs8900_int_on (const rtems_irq_connect_data *unused)
{
unsigned long data;
}
READ_REGISTER_16 (ethernet_io_base[dev] + reg, data);
static void
cs8900_int_off (const rtems_irq_connect_data *unused)
{
}
#ifdef CS8900_DATA_BUS_SWAPPED
data = (data >> 8) | (data << 8);
static int
cs8900_int_is_on (const rtems_irq_connect_data *irq)
{
return BSP_irq_enabled_at_i8259s (irq->name);
}
void cs8900_io_set_reg (cs8900_device *cs, unsigned short reg, unsigned short data)
{
#if CS8900_VERBOSE
if (cs8900_io_verbose)
printk ("CS8900: io set reg=0x%04x, data=0x%04x\n", reg, data);
#endif
#ifdef CS8900_VERBOSE
outport_word (cs->io_base + reg, data);
}
unsigned short cs8900_io_get_reg (cs8900_device *cs, unsigned short reg)
{
unsigned short data;
inport_word (cs->io_base + reg, data);
#if CS8900_VERBOSE
if (cs8900_io_verbose)
printk ("CS8900: io get reg=0x%04x, data=0x%04x\n", reg, data);
#endif
return data;
}
void cs8900_mem_set_reg (int dev, unsigned long reg, unsigned short data)
void cs8900_mem_set_reg (cs8900_device *cs, unsigned long reg, unsigned short data)
{
#ifdef CS8900_DATA_BUS_SWAPPED
data = (data >> 8) | (data << 8);
#endif
#ifdef CS8900_VERBOSE
if (cs8900_io_verbose)
printk ("CS8900: mem set reg=0x%04x, data=0x%04x\n", reg, data);
#endif
WRITE_REGISTER_16 (ethernet_io_base[dev] + reg, data);
printk ("CS8900: mem_set_reg register access called. Only IO supported.\n");
while (1);
}
unsigned short cs8900_mem_get_reg (int dev, unsigned long reg)
unsigned short cs8900_mem_get_reg (cs8900_device *cs, unsigned long reg)
{
unsigned short data;
READ_REGISTER_16 (ethernet_io_base[dev] + reg, data);
#ifdef CS8900_DATA_BUS_SWAPPED
data = (data >> 8) | (data << 8);
#endif
#ifdef CS8900_VERBOSE
if (cs8900_io_verbose)
printk ("CS8900: mem get reg=0x%04x, data=0x%04x\n", reg, data);
#endif
return data;
printk ("CS8900: mem_get_reg register access called. Only IO supported.\n");
while (1);
return 0;
}
void cs8900_put_data_block (int dev, int len, unsigned char *data)
void cs8900_put_data_block (cs8900_device *cs, int len, unsigned char *data)
{
#ifndef CS8900_DATA_BUS_SWAPPED
unsigned short swap_word;
#endif
unsigned short *src = (unsigned short *) ((unsigned long) data);
unsigned short *dst = (unsigned short *) (ethernet_mem_base[dev] + CS8900_PP_TxFrameLoc);
while (len > 1)
{
#ifndef CS8900_DATA_BUS_SWAPPED
swap_word = *src++;
*dst++ = (swap_word >> 8) | (swap_word << 8);
#else
*dst++ = *src++;
#endif
len -= 2;
}
for (; len > 1; len -= 2)
outport_word (cs->io_base, *src++);
if (len)
{
#ifndef CS8900_DATA_BUS_SWAPPED
swap_word = *src++;
*dst++ = (swap_word >> 8) | (swap_word << 8);
#else
*dst++ = *src++;
#endif
}
outport_word (cs->io_base, *src++);
}
unsigned short cs8900_get_data_block (int dev, unsigned char *data)
unsigned short cs8900_get_data_block (cs8900_device *cs, unsigned char *data)
{
unsigned short swap_word;
volatile unsigned short *src = (unsigned short *) (ethernet_mem_base[dev] + CS8900_PP_RxLength);
unsigned short *dst;
unsigned short len;
unsigned short rx_len;
unsigned short len_odd;
#ifdef CS8900_DATA_BUS_SWAPPED
swap_word = *src++;
len = (swap_word >> 8) | (swap_word << 8);
#else
len = *src++;
#endif
unsigned short *dst;
int cnt;
int len;
/*
* Drop the Rx status first.
*/
inport_word (cs->io_base, len);
/*
* Now the length.
*/
inport_word (cs->io_base, len);
dst = (unsigned short *) ((unsigned long) data);
cnt = len >> 1;
len_odd = len & 1;
rx_len = len & ~1;
for (; rx_len; rx_len -= 2)
{
#ifndef CS8900_DATA_BUS_SWAPPED
swap_word = *src++;
*dst++ = (swap_word >> 8) | (swap_word << 8);
#else
*dst++ = *src++;
#endif
}
while (cnt--)
inport_word (cs->io_base, *dst++);
if (len_odd)
{
#ifndef CS8900_DATA_BUS_SWAPPED
swap_word = *src++;
*dst++ = (swap_word >> 8) | (swap_word << 8);
#else
*dst++ = *src++;
#endif
}
if (len & 1)
inport_word (cs->io_base, *dst++);
return len;
}
void
cs8900_tx_load (int dev, struct mbuf *m)
cs8900_tx_load (cs8900_device *cs, struct mbuf *m)
{
volatile unsigned short *dst = (unsigned short *) (ethernet_mem_base[dev] + CS8900_PP_TxFrameLoc);
unsigned int len;
unsigned char *src;
int remainder = 0;
unsigned char remainder_data = '\0';
unsigned int len;
unsigned char *src = 0;
unsigned short *wsrc = 0;
unsigned char remainder = 0;
unsigned char word[2];
while (m)
{
/*
@@ -225,11 +291,12 @@ cs8900_tx_load (int dev, struct mbuf *m)
{
if (remainder)
{
#ifndef CS8900_DATA_BUS_SWAPPED
*dst++ = remainder_data | (*src++ << 8);
#if HAVE_MRB_CS8900_DATA_BUS_SWAPPED
word[1] = *src++;
#else
*dst++ = *src++ | (remainder_data << 8);
word[0] = *src++;
#endif
outport_word (cs->io_base, *((unsigned short*) (unsigned long) &word));
len--;
remainder = 0;
}
@@ -239,59 +306,207 @@ cs8900_tx_load (int dev, struct mbuf *m)
remainder = 1;
len--;
}
for (; len; len -= 2)
#ifndef CS8900_DATA_BUS_SWAPPED
*dst++ = (*src++) | (*(++src) << 8);
#else
*dst++ = (*src++ << 8) | *(++src);
#endif
wsrc = (unsigned short*) src;
for (; len; len -= 2, src += 2)
outport_word (cs->io_base, *wsrc++);
if (remainder)
remainder_data = *src++;
#if HAVE_MRB_CS8900_DATA_BUS_SWAPPED
word[0] = *src++;
#else
word[1] = *src++;
#endif
}
m = m->m_next;
}
if (remainder)
{
#ifndef CS8900_DATA_BUS_SWAPPED
*dst = (unsigned short) remainder_data;
#if HAVE_MRB_CS8900_DATA_BUS_SWAPPED
word[1] = *src++;
#else
*dst = (unsigned short) (remainder_data << 8);
word[0] = *src++;
#endif
outport_word (cs->io_base, *((unsigned short*) (unsigned long) &word));
}
}
void cs8900_attach_interrupt (int dev, cs8900_device *cs)
void cs8900_attach_interrupt (cs8900_device *cs)
{
rtems_interrupt_catch_with_void (cs8900_interrupt,
ethernet_irq_vector[dev],
&old_handler[dev],
cs,
&old_parameter[dev]);
CF_SIM_WRITE_ICR (CF_BASE,
ethernet_irq_level[dev],
CF_SIM_ICR_AVEC_AUTO,
ethernet_irq_level[dev],
ethernet_irq_priority[dev]);
CF_SIM_IMR_ENABLE (CF_BASE, 1 << ethernet_irq_level[dev]);
BSP_install_rtems_irq_handler (&cs8900_irq);
}
void cs8900_detach_interrupt (int dev)
void cs8900_detach_interrupt (cs8900_device *cs)
{
CF_SIM_IMR_DISABLE (CF_BASE, 1 << ethernet_irq_level[dev]);
rtems_interrupt_catch_with_void (old_handler,
ethernet_irq_vector[dev],
NULL,
old_parameter[dev],
NULL);
BSP_remove_rtems_irq_handler (&cs8900_irq);
}
void cs8900_get_mac_addr (int dev, unsigned char *mac_address)
void
BSP_cs8900_attach (unsigned long io_base, unsigned long mem_base, int intrp,
const char* ip, const char* nm, const char* gw)
{
memcpy (mac_address, rct_get_mac_address (dev), 6);
cs8900_device *cs = &cs8900;
int flags;
struct sockaddr_in address;
struct sockaddr_in netmask;
struct sockaddr_in broadcast;
struct sockaddr_in gateway;
int cmd;
printf ("cso: io=0x%0lx mem=0 irq=%d\n", io_base, intrp);
memset (cs, 0, sizeof (cs8900));
cs->dev = 0;
cs->rx_queue_size = 30;
cs->io_base = io_base;
if (mem_base)
printf ("cs8900: memory mode is currently not supported.\n");
cs->mem_base = 0;
switch (intrp)
{
case 5:
cs->irq_level = 3;
break;
case 10:
cs->irq_level = 0;
break;
case 11:
cs->irq_level = 1;
break;
case 12:
cs->irq_level = 2;
break;
default:
printf ("cs8900: unsupported IRQ level\n");
return;
}
cs8900_irq.name = intrp;
/*
* Get the MAC adress from the CS8900.
*/
cs8900_get_mac_addr (cs, cs->mac_address);
/*
* Setup the BSD interface configure structure.
*/
cs8900_ifconfig.drv_ctrl = cs;
cs8900_ifconfig.hardware_address = cs->mac_address;
printf ("CS8900 initialisation\n");
rtems_bsdnet_attach (&cs8900_ifconfig);
/*
* Configure the interface using the boot configuration.
*/
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;
}
if (ip && strlen (ip) && nm && strlen (nm))
{
printf ("%s: addr: %s netmask: %s gateway: %s\n",
cs8900_ifconfig.name, ip, nm, gw ? gw : "none");
memset (&netmask, '\0', sizeof netmask);
netmask.sin_len = sizeof netmask;
netmask.sin_family = AF_INET;
if (!inet_aton (nm, &netmask.sin_addr))
{
printf ("error: cannot parse the network mask: %s\n", nm);
return;
}
memset (&address, '\0', sizeof address);
address.sin_len = sizeof address;
address.sin_family = AF_INET;
if (!inet_aton (ip, &address.sin_addr))
{
printf ("error: cannot parse the ip address: %s\n", ip);
return;
}
if (rtems_bsdnet_ifconfig (cs8900_ifconfig.name,
SIOCSIFNETMASK,
&netmask) < 0)
{
printf ("error: can't set %s netmask: %s\n",
cs8900_ifconfig.name, strerror (errno));
return;
}
if (rtems_bsdnet_ifconfig (cs8900_ifconfig.name,
SIOCSIFADDR,
&address) < 0)
{
printf ("error: can't set %s address: %s\n",
cs8900_ifconfig.name, strerror (errno));
return;
}
memset (&broadcast, '\0', sizeof broadcast);
broadcast.sin_len = sizeof broadcast;
broadcast.sin_family = AF_INET;
broadcast.sin_addr.s_addr =
(address.sin_addr.s_addr & netmask.sin_addr.s_addr) | ~netmask.sin_addr.s_addr;
if (rtems_bsdnet_ifconfig (cs8900_ifconfig.name,
SIOCSIFBRDADDR,
&broadcast) < 0)
{
printf ("error: can't set %s broadcast address: %s\n",
cs8900_ifconfig.name, strerror (errno));
return;
}
if (gw && strlen (gw))
{
address.sin_addr.s_addr = INADDR_ANY;
netmask.sin_addr.s_addr = INADDR_ANY;
memset (&gateway, '\0', sizeof gateway);
gateway.sin_len = sizeof gateway;
gateway.sin_family = AF_INET;
if (!inet_aton (gw, &gateway.sin_addr))
printf ("warning: cannot parse the gateway address: %s\n", ip);
else
{
if (rtems_bsdnet_rtrequest (RTM_ADD,
(struct sockaddr *) &address,
(struct sockaddr *) &gateway,
(struct sockaddr *) &netmask,
(RTF_UP | RTF_GATEWAY | RTF_STATIC), NULL) < 0)
printf ("error: can't set default route: %s\n", strerror (errno));
}
}
}
else
{
rtems_bsdnet_do_bootp_and_rootfs ();
}
for (cmd = 0;
cmd < sizeof (rtems_bsdnet_commands) / sizeof (rtems_monitor_command_entry_t);
cmd++)
rtems_monitor_insert_cmd (&rtems_bsdnet_commands[cmd]);
}

View File

@@ -0,0 +1,41 @@
/*
* $Id$
*
* RTEMS CS8900 Driver Setup for the DIMM-PC/i386 made by Kontron.
*
* 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.
*
* Port performed by Chris Johns, Cybertec Pty Ltd, Jan 2004.
* Based on the Cybertec CS8900 driver setup for the SFP-101.
*
*/
#if !defined (__BSP_CS8900_H__)
#define __BSP_CS8900_H__
/**
* BSP CS8900 Device initialisation and interface attach.
*
* @param io_base The I/O base address of the device.
*
* @param mem_base The memory base address. Currently not used.
*
* @param intrp The ISA bus IRQ. These are currently limited to
* 5, 10, 11, and 12 as documented in the CS8900
* manual.
*
* @param ip IP address in ASCII. For example 10.10.10.10. If the
* pointer is a NULL (0) the interface will BOOTP.
*
* @param nm Network Mask in ASCII. For example 10.10.10.255.
*
* @param gw Address of the gateway machine. For example
* 10.10.10.1.
*/
void BSP_cs8900_attach (unsigned long io_base, unsigned long mem_base, int intrp,
const char* ip, const char* nm, const char* gw);
#endif