summaryrefslogtreecommitdiffstats
path: root/c
diff options
context:
space:
mode:
authorTill Straumann <strauman@slac.stanford.edu>2009-09-11 22:53:25 +0000
committerTill Straumann <strauman@slac.stanford.edu>2009-09-11 22:53:25 +0000
commita1e516f2340560f2cb38ab95ec5f872a5c1ed7a8 (patch)
tree08b329266b6acef57a7d4f2d477693e439a8b0d1 /c
parent2009-09-11 Till Straumann <Till.Straumann@TU-Berlin.de> (diff)
downloadrtems-a1e516f2340560f2cb38ab95ec5f872a5c1ed7a8.tar.bz2
2009-09-11 Till Straumann <strauman@slac.stanford.edu>
* Makefile.am, bsp.h, network/if_sim.c, network/README: added driver for NIC emulation.
Diffstat (limited to 'c')
-rw-r--r--c/src/lib/libbsp/powerpc/psim/ChangeLog5
-rw-r--r--c/src/lib/libbsp/powerpc/psim/Makefile.am2
-rw-r--r--c/src/lib/libbsp/powerpc/psim/include/bsp.h8
-rw-r--r--c/src/lib/libbsp/powerpc/psim/network/README141
-rw-r--r--c/src/lib/libbsp/powerpc/psim/network/if_sim.c505
5 files changed, 661 insertions, 0 deletions
diff --git a/c/src/lib/libbsp/powerpc/psim/ChangeLog b/c/src/lib/libbsp/powerpc/psim/ChangeLog
index 863cbf180d..9f17670985 100644
--- a/c/src/lib/libbsp/powerpc/psim/ChangeLog
+++ b/c/src/lib/libbsp/powerpc/psim/ChangeLog
@@ -1,5 +1,10 @@
2009-09-11 Till Straumann <strauman@slac.stanford.edu>
+ * Makefile.am, bsp.h, network/if_sim.c, network/README:
+ added driver for NIC emulation.
+
+2009-09-11 Till Straumann <strauman@slac.stanford.edu>
+
* Makefile.am, preinstall.am, irq/no_pic.c (REMOVED),
irq/irq.h, irq/irq_init.c:
use openpic from 'shared' area instead of no_pic.
diff --git a/c/src/lib/libbsp/powerpc/psim/Makefile.am b/c/src/lib/libbsp/powerpc/psim/Makefile.am
index b2b97965d8..face282e53 100644
--- a/c/src/lib/libbsp/powerpc/psim/Makefile.am
+++ b/c/src/lib/libbsp/powerpc/psim/Makefile.am
@@ -69,6 +69,8 @@ libbsp_a_SOURCES += \
shmsupp/addrconv.c shmsupp/getcfg.c shmsupp/lock.c shmsupp/mpisr.c
endif
+libbsp_a_SOURCES += network/if_sim.c
+
libbsp_a_LIBADD = ../../../libcpu/@RTEMS_CPU@/shared/cpuIdent.rel \
../../../libcpu/@RTEMS_CPU@/shared/stack.rel \
../../../libcpu/@RTEMS_CPU@/@exceptions@/rtems-cpu.rel \
diff --git a/c/src/lib/libbsp/powerpc/psim/include/bsp.h b/c/src/lib/libbsp/powerpc/psim/include/bsp.h
index 3960df6c9a..0add0ebd2c 100644
--- a/c/src/lib/libbsp/powerpc/psim/include/bsp.h
+++ b/c/src/lib/libbsp/powerpc/psim/include/bsp.h
@@ -67,6 +67,14 @@ extern uint32_t BSP_mem_size;
#define Processor_Synchronize() \
asm(" eieio ")
+struct rtems_bsdnet_ifconfig;
+
+int
+rtems_ifsim_attach(struct rtems_bsdnet_ifconfig *ifcfg, int attaching);
+
+#define RTEMS_BSP_NETWORK_DRIVER_NAME "ifsim1"
+#define RTEMS_BSP_NETWORK_DRIVER_ATTACH rtems_ifsim_attach
+
#endif /* ASM */
#define BSP_HAS_NO_VME
diff --git a/c/src/lib/libbsp/powerpc/psim/network/README b/c/src/lib/libbsp/powerpc/psim/network/README
new file mode 100644
index 0000000000..4ca287788c
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/psim/network/README
@@ -0,0 +1,141 @@
+PSIM NETWORKING HOWTO
+=====================
+
+IMPLEMENTATION INFORMATION
+
+1) NIC hardware emulation.
+
+ In order to simulate networking the simulator (PSIM in our case)
+ has to emulate some networking hardware.
+ At the time of this writing (2009/09 - gdb-6.8) no such emulation
+ is available.
+ However, a patch has been created which adds this functionality
+ to PSIM (see diff in this directory). Unfortunately, implementing
+ a network chip (or some other sort of 'data-source') in PSIM is
+ not quite that simple since PSIM is at the end of the day a single-
+ threaded, monolithic application which has no built-in support for
+ external asynchronous events (e.g., NIC packet reception or a
+ character arriving at a UART [the PSIM BSP uses a polled console
+ driver]).
+ In order to add such asynchronous support, the 'async_io' module
+ was added to PSIM. 'async_io' uses OS-support in the form of
+ a signal (SIGIO) that the OS sends to the PSIM process when I/O
+ becomes possible. The signal handler then executes a callback
+ which e.g., may schedule a PSIM interrupt.
+ However, the use of SIGIO and the O_ASYNC fcntl-flag is not portable
+ (BSD and linux only).
+ The 'ethtap' NIC emulation uses another not quite portable OS
+ service -- the host OS' TUN/TAP device which is some sort of
+ pipe with a networking-interface on one end and a file-system
+ interface on the other. The 'ethtap' NIC reads/writes packets
+ to the file-system interface and they then become available
+ to the host OS' networking.
+ This ascii-art shows how a RTEMS application inside PSIM can
+ communicate with an application on the host with both using
+ sockets. (If the host sets up proper routing table entries
+ then the RTEMS APP can even communicate with the internet...)
+
+
+ RTEMS APP HOST APP
+ | |
+ ............. ............
+ . <socket> . .<socket> .
+ .RTEMS BSD . . HOST OS .
+ .networking . .networking.
+ ............. ............
+
+ ....................... .....................
+ .RTEMS BSD IF "ifsim1". . HOST OS IF: "tap0".
+ .e.g., 10.0.0.100 . . e.g., 10.0.0.1 .
+ ....................... .....................
+ o
+ ............. o
+ .RTEMS ifsim. o
+ . driver . o
+ ............. o
+ || o
+ || o
+ --------------- o
+ ethtap o
+ hw emulation o
+ --------------- o
+ ^ o
+ | o
+ -----> /dev/net/tun (special file on host OS) ooo
+
+
+2) Device-tree. Once PSIM supports the 'ethtap' device then it
+ must be added to the device tree. The following properties are
+ relevant (The register addresses must match with what the
+ BSP/if_sim expects):
+
+ #### ETHTAP @ 0x0c100020 for 0x40
+ #
+
+ /ethtap@0x0c100020/reg 0x0c100020 0x40
+ # route interrupt to open-pic
+ /ethtap@0x0c100020 > 0 irq0 /opic@0x0c130000
+ # 'tun' device on host
+ /ethtap@0x0c100020/tun-device "/dev/net/tun"
+ # name of 'tap' device to use
+ /ethtap@0x0c100020/tap-ifname "tap0"
+ # ethernet address of simulated IF
+ /ethtap@0x0c100020/hw-address "00:00:00:22:11:00"
+ # generate CRC and append to received packet before
+ # handing over to the simulation. This is mostly for
+ # debugging the rtems device driver. If unsure, leave 'false'.
+ /ethtap@0x0c100020/enable-crc false
+
+ The 'tun-device' and 'tap-ifname' properties allow you to
+ configure the name of the special-file and the 'tap' interface
+ on the host.
+
+3) RTEMS driver. The 'if_sim' driver implements a driver for
+ the 'ethtap' device.
+
+USAGE INFORMATION
+
+1) Configure application for networking; the
+ RTEMS_BSP_NETWORK_DRIVER_NAME is "ifsim1"
+ and
+ RTEMS_BSP_NETWORK_DRIVER_ATTACH is rtems_ifsim_attach
+
+2) Patch, configure (--target=powerpc-rtems) and build
+ gdb-6.8. As already mentioned, the NIC emulation only
+ is available if your host-os is linux.
+
+3) Create a 'device-tree' file. The BSP build process produces
+ a shell-script 'psim' residing in
+
+ <bsp_installdir>/powerpc-rtems/psim/tests/
+
+ which can be used for generating a device-tree file.
+
+ Call 'psim -d -n <application>'. The '-n' option adds the
+ emulated interface (the lines above) to the device tree.
+ The resulting file is saved as <application>.device.
+
+ The 'psim' script can also be used to launch an application
+ directly -- just omit the '-d' option.
+
+4) Linux host network configuration:
+ Create a 'permanent' 'tap' interface. This allows you
+ to use 'psim' w/o special privileges (the 'tunctl' command
+ still must be executed by the super-user).
+
+ sudo tunctl -u <uid-of-user-running-psim>
+
+ You now can configure the 'tap0' interface:
+
+ sudo ifconfig tap0 10.0.0.1 up
+
+ and e.g., run a BOOTP server to provide RTEMS with its
+ network configuration:
+
+ sudo dhcpd3 -d tap0
+
+ Assuming that BOOTP gives the RTEMS guest an IP address
+ e.g., '10.0.0.100' you can 'ping' the RTEMS guest
+ from the linux host:
+
+ ping 10.0.0.100
diff --git a/c/src/lib/libbsp/powerpc/psim/network/if_sim.c b/c/src/lib/libbsp/powerpc/psim/network/if_sim.c
new file mode 100644
index 0000000000..58f35396fc
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/psim/network/if_sim.c
@@ -0,0 +1,505 @@
+/* $Id$ */
+
+/* Trivial driver for PSIM's emulated ethernet device 'hw_ethtap'.
+ *
+ * NOTE: At the time of this writing (2009/1) 'hw_ethtap' requires
+ * a patched version of PSIM -- the vanilla version does not
+ * implement this device.
+ * Also, support for this device is currently only available
+ * on a linux host.
+ *
+ * Author/Copyright: Till Straumann <Till.Straumann@TU-Berlin.de>
+ *
+ * LICENSE
+ * 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.
+ *
+ */
+
+#include <bsp.h>
+#include <rtems.h>
+#include <bsp/irq.h>
+#include <psim.h>
+#include <libcpu/io.h>
+#include <inttypes.h>
+
+
+#ifndef KERNEL
+#define KERNEL
+#endif
+#ifndef _KERNEL
+#define _KERNEL
+#endif
+
+#include <rtems/rtems_bsdnet.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <net/ethernet.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+
+#include <stdio.h>
+
+#define IFSIM_SLOTS 1
+
+#define DRVNAME "if_sim"
+
+#define IFSIM_TX_BUF_REG 1
+#define IFSIM_TX_STA_REG 2
+
+#define IFSIM_RX_BUF_REG 4
+#define IFSIM_RX_STA_REG 5
+
+#define IFSIM_RX_CNT_MSK 0xffff
+#define IFSIM_RX_STA_DONE (1<<31)
+
+#define IFSIM_RX_ERR_NOSPC (1<<20) /* buffer too small */
+#define IFSIM_RX_ERR_DMA (1<<21) /* DMA error */
+#define IFSIM_RX_ERR_RD (1<<23) /* file read error */
+
+#define IFSIM_TX_STA_LST (1<<16)
+#define IFSIM_TX_STA_DONE (1<<31)
+
+#define IFSIM_IEN_REG 6
+#define IFSIM_IRQ_REG 7
+
+#define IFSIM_RX_IRQ (1<<0)
+
+#define IFSIM_MACA0_REG 8
+#define IFSIM_MACA1_REG 9
+
+#define IFSIM_CSR_REG 10
+#define IFSIM_CSR_PROM (1<<0)
+/* Enable CRC generation/checking */
+#define IFSIM_CSR_CRCEN (1<<1)
+
+
+#define RX_BUF_ALIGNMENT 1
+#define ETH_RX_OFFSET 0
+
+/*
+ * Align 'p' up to a multiple of 'a' which must be
+ * a power of two. Result is cast to (uintptr_t)
+ */
+#define ALIGNTO(p,a) ((((uintptr_t)(p)) + (a) - 1) & ~((a)-1))
+
+
+typedef volatile unsigned reg_t;
+
+struct ifsim_private {
+ reg_t *base;
+ void *rbuf;
+ unsigned rx_cserrs;
+ unsigned rx_err_nospc;
+ unsigned rx_err_dma;
+ unsigned rx_err_rd;
+ unsigned rx_nobufs;
+ unsigned rx_irqs;
+};
+
+struct ifsim_softc {
+ struct arpcom arpcom;
+ struct ifsim_private pvt;
+};
+
+struct ifsim_softc theIfSims[IFSIM_SLOTS] = {{{{0}}} };
+
+rtems_id ifsim_tid = 0;
+
+__inline__ uint32_t
+ifsim_in(struct ifsim_softc *sc, unsigned regno)
+{
+ return in_be32( sc->pvt.base + regno );
+}
+
+__inline__ void
+ifsim_out(struct ifsim_softc *sc, unsigned regno, uint32_t v)
+{
+ out_be32(sc->pvt.base + regno, v);
+}
+
+static void *
+alloc_mbuf_rx(int *psz, uintptr_t *paddr)
+{
+struct mbuf *m;
+unsigned long l,o;
+
+ MGETHDR(m, M_DONTWAIT, MT_DATA);
+ if ( !m )
+ return 0;
+ MCLGET(m, M_DONTWAIT);
+ if ( ! (m->m_flags & M_EXT) ) {
+ m_freem(m);
+ return 0;
+ }
+
+ o = mtod(m, unsigned long);
+ l = ALIGNTO(o, RX_BUF_ALIGNMENT) - o;
+
+ /* align start of buffer */
+ m->m_data += l;
+
+ /* reduced length */
+ l = MCLBYTES - l;
+
+ m->m_len = m->m_pkthdr.len = l;
+ *psz = m->m_len;
+ *paddr = mtod(m, unsigned long);
+
+ return (void*) m;
+}
+
+static int
+get_rxbuf(struct ifsim_softc *sc)
+{
+int sz;
+uintptr_t addr;
+void *nbuf;
+
+ nbuf = alloc_mbuf_rx(&sz, &addr);
+
+ if ( nbuf ) {
+ sc->pvt.rbuf = nbuf;
+ ifsim_out(sc, IFSIM_RX_BUF_REG, addr);
+ ifsim_out(sc, IFSIM_RX_STA_REG, sz);
+ return 0;
+ }
+ return -1;
+}
+
+/* set/clear promiscuous mode */
+static void
+ifsim_upd_promisc(struct ifsim_softc *sc)
+{
+uint32_t ncsr, csr;
+
+ ncsr = csr = ifsim_in(sc, IFSIM_CSR_REG);
+
+ if ( sc->arpcom.ac_if.if_flags & IFF_PROMISC )
+ ncsr |= IFSIM_CSR_PROM;
+ else
+ ncsr &= ~IFSIM_CSR_PROM;
+
+ if ( ncsr != csr )
+ ifsim_out(sc, IFSIM_CSR_REG, ncsr);
+}
+
+static void
+ifsim_init(void *arg)
+{
+struct ifsim_softc *sc = arg;
+struct ifnet *ifp = &sc->arpcom.ac_if;
+
+ if ( 0 == get_rxbuf(sc) ) {
+ ifsim_upd_promisc(sc);
+ ifp->if_flags |= IFF_RUNNING;
+ }
+}
+
+static void
+ifsim_start(struct ifnet *ifp)
+{
+struct ifsim_softc *sc = ifp->if_softc;
+struct mbuf *m, *mh, *m1;
+
+ while ( ifp->if_snd.ifq_head ) {
+ IF_DEQUEUE( &ifp->if_snd, mh );
+ for ( m=mh, m1 = m->m_next ; m1 ; m1 = m1->m_next ) {
+ ifsim_out(sc, IFSIM_TX_BUF_REG, mtod(m, uint32_t));
+ ifsim_out(sc, IFSIM_TX_STA_REG, m->m_len);
+ /* dummy-busywait; the emulated hardware DMAs our
+ * data away 'immediately' i.e., this loop is
+ * never executed
+ */
+ while ( ! (IFSIM_TX_STA_DONE & ifsim_in(sc, IFSIM_TX_STA_REG)) )
+ /* Loop */;
+ m = m1;
+ }
+ ifsim_out(sc, IFSIM_TX_BUF_REG, mtod(m, uint32_t));
+ ifsim_out(sc, IFSIM_TX_STA_REG, m->m_len | IFSIM_TX_STA_LST);
+
+ /* dummy-busywait; the emulated hardware DMAs our
+ * data away 'immediately' i.e., this loop is
+ * never executed
+ */
+ while ( ! (IFSIM_TX_STA_DONE & ifsim_in(sc, IFSIM_TX_STA_REG)) )
+ /* Loop */;
+
+ m_freem(mh);
+ }
+}
+
+static int
+ifsim_ioctl(struct ifnet *ifp, ioctl_command_t cmd, caddr_t data)
+{
+struct ifsim_softc *sc = ifp->if_softc;
+int rval = 0;
+int f;
+
+ switch (cmd) {
+
+ case SIOCSIFFLAGS:
+ f = ifp->if_flags;
+ if ( f & IFF_UP ) {
+ if ( ! (f & IFF_RUNNING) ) {
+ ifsim_init(sc);
+ } else {
+ ifsim_upd_promisc(sc);
+ }
+ /* FIXME: handle other flags here */
+ } else {
+ if ( f & IFF_RUNNING ) {
+ printk("WARNING: bringing "DRVNAME" down not really implemented\n");
+ ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
+ }
+ }
+
+ break;
+
+ case SIO_RTEMS_SHOW_STATS:
+ printf("RX bad chksum : %u\n", sc->pvt.rx_cserrs);
+ printf("RX no space : %u\n", sc->pvt.rx_err_nospc);
+ printf("RX bad DMA : %u\n", sc->pvt.rx_err_dma);
+ printf("RX read errors : %u\n", sc->pvt.rx_err_rd);
+ printf("rx_nobufs : %u\n", sc->pvt.rx_nobufs);
+ printf("rx_irqs : %u\n", sc->pvt.rx_irqs);
+ break;
+
+ default:
+ rval = ether_ioctl(ifp, cmd, data);
+ break;
+ }
+
+ return rval;
+}
+
+static void ifsim_irq_on(const rtems_irq_connect_data *pd)
+{
+struct ifsim_softc *sc = pd->handle;
+ ifsim_out(sc, IFSIM_IEN_REG, IFSIM_RX_IRQ);
+}
+
+static void ifsim_irq_off(const rtems_irq_connect_data *pd)
+{
+struct ifsim_softc *sc = pd->handle;
+ ifsim_out(sc, IFSIM_IEN_REG, 0);
+}
+
+static int ifsim_irq_ison(const rtems_irq_connect_data *pd)
+{
+struct ifsim_softc *sc = pd->handle;
+ return ifsim_in(sc, IFSIM_IEN_REG) & IFSIM_RX_IRQ ? 1 : 0;
+}
+
+static void
+ifsim_isr(void *arg)
+{
+struct ifsim_softc *sc = arg;
+
+ sc->pvt.rx_irqs++;
+#ifdef IRQ_DEBUG
+ printk("ISR happened\n");
+#endif
+
+ ifsim_out(sc, IFSIM_IEN_REG, 0);
+ rtems_event_send(ifsim_tid, (1<<(sc-theIfSims)));
+}
+
+static void
+ifsim_task(void *arg)
+{
+struct ifsim_softc *sc;
+uint32_t sta;
+struct ifnet *ifp;
+unsigned len;
+rtems_event_set evs;
+
+ while (1) {
+
+ rtems_bsdnet_event_receive(
+ ((1<<IFSIM_SLOTS)-1),
+ RTEMS_WAIT | RTEMS_EVENT_ANY,
+ RTEMS_NO_TIMEOUT,
+ &evs);
+
+ evs &= ((1<<IFSIM_SLOTS)-1);
+
+#ifdef IRQ_DEBUG
+ printf("Task got evs %u\n", evs);
+#endif
+
+ for ( sc = theIfSims; evs; evs>>=1, sc++ ) {
+
+ if ( ! ( evs & 1 ) )
+ continue;
+
+ ifp = &sc->arpcom.ac_if;
+
+ while ( ifsim_in(sc, IFSIM_IRQ_REG) & IFSIM_RX_IRQ ) {
+ struct mbuf *m = sc->pvt.rbuf;
+
+ sta = ifsim_in(sc, IFSIM_RX_STA_REG);
+
+
+ if ( (sta & IFSIM_RX_STA_DONE) ) {
+
+ if ( (ifp->if_flags & IFF_RUNNING) ) {
+ if ( 0 == get_rxbuf(sc) ) {
+ /* enqueue packet */
+ struct ether_header *eh;
+ uint32_t crc_net, crc;
+ int crc_len;
+
+ crc_len = (IFSIM_CSR_CRCEN & ifsim_in(sc, IFSIM_CSR_REG)) ? sizeof(crc_net) : 0;
+
+ len = (sta & IFSIM_RX_CNT_MSK) - crc_len;
+
+ eh = (struct ether_header*)(mtod(m,unsigned long) + ETH_RX_OFFSET);
+
+ m->m_len = m->m_pkthdr.len = len - sizeof(struct ether_header) - ETH_RX_OFFSET;
+ m->m_data += sizeof(struct ether_header) + ETH_RX_OFFSET;
+ m->m_pkthdr.rcvif = ifp;
+
+#ifdef DEBUG_WO_BSDNET
+ {
+ int i;
+ for ( i=0; i<len + crc_len; ) {
+ printf("%02X ",((char*)eh)[i]);
+ if ( 0 == (++i & 0xf) )
+ fputc('\n',stdout);
+ }
+ if ( i & 0xf )
+ fputc('\n', stdout);
+ printf("*****\n");
+ }
+#endif
+
+ if ( crc_len
+ && (memcpy(&crc_net, (char*)eh + len, crc_len),
+ (crc = (ether_crc32_le((uint8_t *)eh, len) ^ 0xffffffff)) != crc_net) ) {
+ printk("CSUM: me 0x%08X, them 0x%08x\n", crc, crc_net);
+ sc->pvt.rx_cserrs++;
+ } else {
+
+ ifp->if_ipackets++;
+ ifp->if_ibytes += len;
+
+#ifdef DEBUG_WO_BSDNET
+ m_freem(m);
+#else
+ ether_input(ifp, eh, m);
+#endif
+
+ m = 0;
+ }
+
+ } else {
+ /* throw away and reuse buffer */
+ sc->pvt.rx_nobufs++;
+ }
+ }
+ } else {
+ /* throw away and reuse buffer */
+ if ( (sta & IFSIM_RX_ERR_NOSPC) )
+ sc->pvt.rx_err_nospc++;
+ if ( (sta & IFSIM_RX_ERR_DMA) )
+ sc->pvt.rx_err_dma++;
+ if ( (sta & IFSIM_RX_ERR_RD) )
+ sc->pvt.rx_err_rd++;
+ }
+
+ if ( m ) {
+ /* reuse */
+ ifsim_out(sc, IFSIM_RX_STA_REG, m->m_pkthdr.len);
+ }
+ }
+ /* re-enable interrupt */
+ ifsim_out(sc, IFSIM_IEN_REG, IFSIM_RX_IRQ);
+ }
+ }
+}
+
+int
+rtems_ifsim_attach(struct rtems_bsdnet_ifconfig *ifcfg, int attaching)
+{
+char *unitName;
+int unit;
+struct ifsim_softc *sc;
+struct ifnet *ifp;
+uint32_t v;
+rtems_irq_connect_data ihdl;
+
+ if ( !attaching )
+ return -1;
+
+ unit = rtems_bsdnet_parse_driver_name(ifcfg, &unitName);
+
+ if ( unit <= 0 || unit > IFSIM_SLOTS ) {
+ printk(DRVNAME": Bad unit number %i; must be 1..%i\n", unit, IFSIM_SLOTS);
+ return 1;
+ }
+
+ sc = &theIfSims[unit-1];
+ ifp = &sc->arpcom.ac_if;
+
+ memset(&sc->pvt, 0, sizeof(sc->pvt));
+
+ sc->pvt.base = (reg_t*)ifcfg->port;
+
+ if ( 0 == sc->pvt.base )
+ sc->pvt.base = (reg_t*)PSIM.Ethtap;
+
+
+ sc->pvt.rbuf = 0;
+
+ if ( !ifsim_tid ) {
+ ifsim_tid = rtems_bsdnet_newproc("IFSM", 10000, ifsim_task, 0);
+ }
+
+ ihdl.name = ifcfg->irno;
+ ihdl.hdl = ifsim_isr;
+ ihdl.handle = sc;
+ ihdl.on = ifsim_irq_on;
+ ihdl.off = ifsim_irq_off;
+ ihdl.isOn = ifsim_irq_ison;
+
+ if ( ! BSP_install_rtems_irq_handler(&ihdl) ) {
+ printk(DRVNAME"_attach(): installing ISR failed!\n");
+ return -1;
+ }
+
+ if ( ifcfg->hardware_address ) {
+ memcpy(sc->arpcom.ac_enaddr, ifcfg->hardware_address, ETHER_ADDR_LEN);
+ } else {
+ v = ifsim_in(sc, IFSIM_MACA0_REG);
+ memcpy(sc->arpcom.ac_enaddr, &v, 4);
+ v = ifsim_in(sc, IFSIM_MACA1_REG);
+ memcpy(sc->arpcom.ac_enaddr+4, &v, 2);
+ }
+
+ ifp->if_softc = sc;
+ ifp->if_unit = unit;
+ ifp->if_name = unitName;
+
+ ifp->if_mtu = ifcfg->mtu ? ifcfg->mtu : ETHERMTU;
+
+ ifp->if_init = ifsim_init;
+ ifp->if_ioctl = ifsim_ioctl;
+ ifp->if_start = ifsim_start;
+ ifp->if_output = ether_output;
+
+ ifp->if_watchdog = 0;
+ ifp->if_timer = 0;
+
+ ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
+
+ ifp->if_snd.ifq_maxlen = ifqmaxlen;
+
+ if_attach(ifp);
+ ether_ifattach(ifp);
+
+ return 0;
+}