summaryrefslogtreecommitdiffstats
path: root/bsd_eth_drivers/libbsdport
diff options
context:
space:
mode:
authorJoel Sherrill <joel.sherrill@OARcorp.com>2009-02-19 19:55:40 +0000
committerJoel Sherrill <joel.sherrill@OARcorp.com>2009-02-19 19:55:40 +0000
commit89376b7141edb6f927fb940c27391cda6e67c785 (patch)
tree57dd01fd9328b879289493ba848ae5c34c607b91 /bsd_eth_drivers/libbsdport
downloadlibbsdport-89376b7141edb6f927fb940c27391cda6e67c785.tar.bz2
Initial import.initial
Diffstat (limited to 'bsd_eth_drivers/libbsdport')
-rw-r--r--bsd_eth_drivers/libbsdport/Makefile.am75
-rw-r--r--bsd_eth_drivers/libbsdport/README29
-rw-r--r--bsd_eth_drivers/libbsdport/alldrv.c16
-rw-r--r--bsd_eth_drivers/libbsdport/bus.h324
-rw-r--r--bsd_eth_drivers/libbsdport/callout.h43
-rw-r--r--bsd_eth_drivers/libbsdport/contigmalloc.c33
-rw-r--r--bsd_eth_drivers/libbsdport/devicet.c374
-rw-r--r--bsd_eth_drivers/libbsdport/devicet.h125
-rw-r--r--bsd_eth_drivers/libbsdport/ifmedia.c91
-rw-r--r--bsd_eth_drivers/libbsdport/ifstuff.c79
-rw-r--r--bsd_eth_drivers/libbsdport/libbsdport.h380
-rw-r--r--bsd_eth_drivers/libbsdport/libbsdport_api.h84
-rw-r--r--bsd_eth_drivers/libbsdport/libbsdport_post.h95
-rw-r--r--bsd_eth_drivers/libbsdport/malloc.c17
-rw-r--r--bsd_eth_drivers/libbsdport/mutex.h55
-rw-r--r--bsd_eth_drivers/libbsdport/rtems_callout.c250
-rw-r--r--bsd_eth_drivers/libbsdport/rtems_taskqueue.c308
-rw-r--r--bsd_eth_drivers/libbsdport/rtems_udelay.c192
-rw-r--r--bsd_eth_drivers/libbsdport/rtems_udelay.h22
-rw-r--r--bsd_eth_drivers/libbsdport/rtems_verscheck.h29
-rw-r--r--bsd_eth_drivers/libbsdport/sysbus.c267
-rw-r--r--bsd_eth_drivers/libbsdport/taskqueue.h69
22 files changed, 2957 insertions, 0 deletions
diff --git a/bsd_eth_drivers/libbsdport/Makefile.am b/bsd_eth_drivers/libbsdport/Makefile.am
new file mode 100644
index 0000000..44096b5
--- /dev/null
+++ b/bsd_eth_drivers/libbsdport/Makefile.am
@@ -0,0 +1,75 @@
+# $Id$
+AUTOMAKE_OPTIONS=foreign
+
+include $(top_srcdir)/rtems-pre.am
+
+libbsdport_a_SOURCES = rtems_callout.c rtems_taskqueue.c rtems_udelay.c
+libbsdport_a_SOURCES += ifstuff.c devicet.c alldrv.c contigmalloc.c
+libbsdport_a_SOURCES += sysbus.c malloc.c ifmedia.c
+
+libbsdport_a_SOURCES += rtems_verscheck.h bus.h callout.h devicet.h
+libbsdport_a_SOURCES += libbsdport.h libbsdport_post.h mutex.h
+libbsdport_a_SOURCES += rtems_udelay.h rtems_verscheck.h taskqueue.h
+
+include_bsp_HEADERS = libbsdport_api.h
+
+lib_LIBRARIES = libbsdport.a
+
+include $(top_srcdir)/rtems.am
+
+LINKS =
+LINKS+=sys/taskqueue.h
+LINKS+=sys/bus.h
+LINKS+=sys/mutex.h
+LINKS+=bsp/rtems_verscheck.h
+
+DUMMYHEADERS =
+DUMMYHEADERS+=dummyheaders/machine/bus.h
+DUMMYHEADERS+=dummyheaders/machine/resource.h
+DUMMYHEADERS+=dummyheaders/dev/pci/pcivar.h
+DUMMYHEADERS+=dummyheaders/dev/pci/pcireg.h
+DUMMYHEADERS+=dummyheaders/dev/mii/miivar.h
+DUMMYHEADERS+=dummyheaders/sys/module.h
+DUMMYHEADERS+=dummyheaders/sys/rman.h
+DUMMYHEADERS+=dummyheaders/sys/kthread.h
+DUMMYHEADERS+=dummyheaders/sys/endian.h
+DUMMYHEADERS+=dummyheaders/net/if_vlan_var.h
+DUMMYHEADERS+=dummyheaders/netinet/ip6.h
+DUMMYHEADERS+=dummyheaders/vm/pmap.h
+DUMMYHEADERS+=dummyheaders/miibus_if.h
+
+DUMMYHEADERS+=dummyheaders/miidevs.h
+DUMMYHEADERS+=dummyheaders/dev/mii/brgphyreg.h
+
+BUILT_SOURCES=
+
+include ../links.am
+
+#
+# I found no good way to have something made first thing.
+# all-local is made after 'all' and xxx_DEPENDENCIES are
+# after OBJECTS are made :-(
+$(libbsdport_a_OBJECTS): $(DUMMYHEADERS) $(LINKS)
+
+if FALSE
+CLOBBER_ADDITIONS =
+CLOBBER_ADDITIONS += $(srcdir)/dummyheaders
+CLOBBER_ADDITIONS += $(addprefix $(srcdir)/,$(sort $(foreach n,$(LINKS),$(firstword $(subst /, ,$(n))))))
+
+dummyheaders/%:
+ @if [ ! -d $(srcdir)/`dirname $@` ] ; then mkdir -p $(srcdir)/`dirname $@`; fi
+ @touch $(srcdir)/$@
+
+# for each name listed in LINKS, create parent directories (if needed)
+# and a symlink to file in .
+# E.g., LINKS=a/b/c.h
+# creates a/b/c.h -> ../../c.h
+$(LINKS):
+ @if [ ! -d $(srcdir)/$(dir $@) ] ; then mkdir -p $(srcdir)/$(dir $@); fi
+ @ln -s `echo $@ | sed -e 's%[^/]\+[/]\+%../%g'` $(srcdir)/$@
+
+
+distclean-local:
+ $(RM) -r $(CLOBBER_ADDITIONS)
+endif
+
diff --git a/bsd_eth_drivers/libbsdport/README b/bsd_eth_drivers/libbsdport/README
new file mode 100644
index 0000000..14fd4a5
--- /dev/null
+++ b/bsd_eth_drivers/libbsdport/README
@@ -0,0 +1,29 @@
+This is a library and collection of header files
+intended to ease porting recent FreeBSD (as of 7/2007)
+drivers to RTEMS. Currently, only the PCI bus is supported.
+
+A lot of macro-magic is used in the 'libbsdport.h'
+and 'libbsdport_post.h' headers which are te be included
+from the driver source file prior and after the driver
+includes the normal headers it uses:
+
+At the top of if_xxx.c add:
+
+#ifdef __rtems__
+#include <libbsdport.h>
+#endif
+
+... leave all normal include statements in place...
+#include <sys/yyy.h>
+
+lastly, add:
+
+#ifdef __rtems__
+#include <libbsdport_post.h>
+#endif
+
+Note that libbsdport does not provide the full freebsd
+kernel API but only a subset.
+
+<< MORE TO COME >>
+
diff --git a/bsd_eth_drivers/libbsdport/alldrv.c b/bsd_eth_drivers/libbsdport/alldrv.c
new file mode 100644
index 0000000..0738179
--- /dev/null
+++ b/bsd_eth_drivers/libbsdport/alldrv.c
@@ -0,0 +1,16 @@
+#include <stdio.h>
+#include "libbsdport_api.h"
+
+driver_t *libbsdport_netdriver_table_all[] = {
+ &libbsdport_em_driver,
+ &libbsdport_pcn_driver,
+ &libbsdport_le_pci_driver,
+ &libbsdport_re_driver,
+ 0
+};
+
+/* weak alias defaults to a table that includes all currently supported drivers */
+extern driver_t *libbsdport_netdriver_table
+ [
+ sizeof(libbsdport_netdriver_table_all)/sizeof(libbsdport_netdriver_table_all[0])
+ ] __attribute__((weak,alias("libbsdport_netdriver_table_all")));
diff --git a/bsd_eth_drivers/libbsdport/bus.h b/bsd_eth_drivers/libbsdport/bus.h
new file mode 100644
index 0000000..76d78a8
--- /dev/null
+++ b/bsd_eth_drivers/libbsdport/bus.h
@@ -0,0 +1,324 @@
+#ifndef LIBBSDPORT_SYS_BUS_H
+#define LIBBSDPORT_SYS_BUS_H
+
+#include <rtems.h>
+#include <sys/errno.h>
+#include <bsp.h>
+#include <devicet.h>
+#include <sys/mbuf.h>
+
+typedef uint32_t bus_addr_t;
+typedef size_t bus_size_t;
+
+typedef enum {
+ bus_space_mem = 0,
+ bus_space_io = 1
+} bus_space_tag_t;
+
+struct resource;
+
+typedef bus_addr_t bus_space_handle_t;
+
+/* The 'bus_space_xxx()' inlines can be helped if the
+ * tag is hardcoded in the driver so that the compiler
+ * can optimize part of the implementation away.
+ */
+
+#define BUS_SPACE_BARRIER_WRITE 1
+#define BUS_SPACE_BARRIER_READ 2
+
+#if defined(__i386__)
+
+#include <rtems/score/cpu.h>
+
+static inline void
+bus_space_barrier(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o, int width, int type)
+{
+}
+
+#define BUS_SPACE_DECL(type, width, nwidth) \
+static inline type \
+bus_space_read_##nwidth(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o) \
+{ \
+type v; \
+ if ( bus_space_io == t ) { \
+ /* this is a macro setting the second argument */ \
+ inport_##width( h+o, v ); \
+ } else { \
+ v = *(volatile type __attribute__((may_alias)) *)(h+o); \
+ } \
+ return v; \
+} \
+ \
+static inline void \
+bus_space_write_##nwidth(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o, type v) \
+{ \
+ if ( bus_space_io == t ) { \
+ outport_##width( h+o, v ); \
+ } else { \
+ *(volatile type __attribute__((may_alias)) *)(h+o) = v; \
+ }\
+}
+
+BUS_SPACE_DECL(u_int32_t, long, 4)
+BUS_SPACE_DECL(u_int16_t, word, 2)
+BUS_SPACE_DECL(u_int8_t, byte, 1)
+
+#elif defined(__PPC__)
+
+#include <libcpu/io.h>
+
+#if defined(_IO_BASE) && _IO_BASE == 0
+#define BUS_SPACE_ALWAYS_MEM 1
+#else
+#define BUS_SPACE_ALWAYS_MEM 0
+#endif
+
+static inline void
+bus_space_barrier(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o, int width, int type)
+{
+ asm volatile("eieio");
+}
+
+
+#define BUS_SPACE_DECL(type, width, nwidth, op) \
+static inline type \
+bus_space_read_##nwidth(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o) \
+{ \
+type v; \
+ if ( !BUS_SPACE_ALWAYS_MEM && bus_space_io == t ) { \
+ /* this is a macro setting the second argument */ \
+ v = in_##op((volatile type *)(_IO_BASE+h+o)); \
+ } else { \
+ v = in_##op((volatile type *)(h+o)); \
+ } \
+ return v; \
+} \
+ \
+static inline void \
+bus_space_write_##nwidth(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o, type v) \
+{ \
+ if ( !BUS_SPACE_ALWAYS_MEM && bus_space_io == t ) { \
+ out_##op((volatile type *)(_IO_BASE+h+o), v); \
+ } else { \
+ out_##op((volatile type *)(h+o), v); \
+ }\
+}
+
+BUS_SPACE_DECL(u_int32_t, long, 4, le32)
+BUS_SPACE_DECL(u_int16_t, word, 2, le16)
+BUS_SPACE_DECL(u_int8_t, byte, 1, 8)
+
+#undef BUS_SPACE_ALWAYS_MEM
+
+#else
+#error "Missing definitions of bus_space_XXX() for this CPU architecture"
+#endif
+
+
+#undef BUS_SPACE_DECL
+
+#ifndef BUS_PROBE_DEFAULT
+#define BUS_PROBE_DEFAULT 0
+#endif
+
+/* error codes are > 0 ; low priority says that probe
+ * was successful but another driver returning BUS_PROBE_DEFAULT
+ * is to be preferred...
+ */
+#ifndef BUS_PROBE_LOW_PRIORITY
+#define BUS_PROBE_LOW_PRIORITY (-1)
+#endif
+
+
+
+/* types -> -1 means unsupported */
+#define SYS_RES_IOPORT 1
+#define SYS_RES_MEMORY 2
+#define SYS_RES_IRQ 3
+
+/* flags (1<<31) means unsupported */
+#define RF_ACTIVE (1<<1)
+#define RF_SHAREABLE (1<<2)
+
+struct resource *
+bus_alloc_resource_any(device_t dev, int type, int *prid, unsigned flags);
+
+#define FILTER_STRAY 1
+#define FILTER_HANDLED 0
+
+typedef void (*driver_intr_t)(void *);
+typedef int (*driver_filter_t)(void *);
+
+int
+bus_setup_intr(device_t dev, struct resource *r, int flags, driver_filter_t filter, driver_intr_t handler, void *arg, void **cookiep);
+
+/* Flags currently ignored... */
+#define INTR_MPSAFE 0
+#define INTR_TYPE_NET 0
+/* INTR_FAST indicates that a 'handler' is actually
+ * a 'fast' handler which already uses taskqueues
+ */
+#define INTR_FAST 1
+
+int
+bus_teardown_intr(device_t dev, struct resource *r, void *cookiep);
+
+static inline int
+bus_release_resource(device_t dev, int type, int rid, struct resource *r)
+{
+ return 0;
+}
+
+#define bus_generic_detach(dev) do {} while (0)
+
+#define bus_generic_suspend(dev) (0)
+#define bus_generic_resume(dev) (0)
+
+bus_space_handle_t
+rman_get_bushandle(struct resource *r);
+
+bus_space_tag_t
+rman_get_bustag(struct resource *r);
+
+#ifndef BUS_DMA_NOWAIT
+/* ignored anyways */
+#define BUS_DMA_NOWAIT 0
+#endif
+
+#ifndef BUS_DMA_WAITOK
+/* ignored anyways */
+#define BUS_DMA_WAITOK 0
+#endif
+
+#ifndef BUS_DMA_COHERENT
+/* ignored anyways */
+#define BUS_DMA_COHERENT 0
+#endif
+
+#ifndef BUS_DMA_ZERO
+/* ignored anyways */
+#define BUS_DMA_ZERO 0
+#endif
+
+#ifndef BUS_DMA_ALLOCNOW
+/* ignored anyways */
+#define BUS_DMA_ALLOCNOW 0
+#endif
+
+/* unused */
+#ifndef BUS_SPACE_MAXADDR
+#define BUS_SPACE_MAXADDR 0xdeadbeef
+#endif
+
+/* unused */
+#ifndef BUS_SPACE_MAXADDR_32BIT
+#define BUS_SPACE_MAXADDR_32BIT 0xdeadbeef
+#endif
+
+/* unused */
+#ifndef BUS_SPACE_MAXSIZE_32BIT
+#define BUS_SPACE_MAXSIZE_32BIT 0x10000000
+#endif
+
+typedef struct _bus_dma_tag_t {
+ unsigned alignment;
+ unsigned maxsize;
+ unsigned maxsegs;
+} * bus_dma_tag_t;
+
+typedef struct _bus_dma_segment_t {
+ bus_addr_t ds_addr;
+ bus_size_t ds_len;
+} bus_dma_segment_t;
+
+typedef void *bus_dmamap_t;
+
+int
+bus_dma_tag_create(void *parent, unsigned alignment, unsigned bounds, uint32_t lowadd, uint32_t hiaddr, void (*filter)(void*), void *filterarg, unsigned maxsize, int nsegs, unsigned maxsegsize, unsigned flags, void (*lockfunc)(void*), void *lockarg, bus_dma_tag_t *ptag);
+
+void
+bus_dma_tag_destroy(bus_dma_tag_t tag);
+
+int
+bus_dmamem_alloc(bus_dma_tag_t tag, void **p_vaddr, unsigned flags, bus_dmamap_t *p_map);
+
+void
+bus_dmamem_free(bus_dma_tag_t tag, void *vaddr, bus_dmamap_t map);
+
+#ifndef CPU2BUSADDR
+#ifndef PCI_DRAM_OFFSET
+#define PCI_DRAM_OFFSET 0
+#endif
+#define CPU2BUSADDR(x) ((uint32_t)(x) + (PCI_DRAM_OFFSET))
+#endif
+
+#define kvtop(a) CPU2BUSADDR((bus_addr_t)(a))
+#define vtophys(a) CPU2BUSADDR((bus_addr_t)(a))
+
+
+static inline int
+bus_dmamap_load_mbuf_sg(bus_dma_tag_t tag, bus_dmamap_t map, struct mbuf *m_head, bus_dma_segment_t *segs, int *pnsegs, unsigned flags)
+{
+struct mbuf *m;
+int n;
+ for ( m=m_head, n=0; m; m=m->m_next, n++ ) {
+ if ( n >= tag->maxsegs ) {
+ return EFBIG;
+ }
+ segs[n].ds_addr = CPU2BUSADDR(mtod(m, unsigned));
+ segs[n].ds_len = m->m_len;
+ }
+ *pnsegs = n;
+ return 0;
+}
+
+static inline bus_dma_tag_t
+bus_get_dma_tag(device_t dev)
+{
+ return 0;
+}
+
+typedef void bus_dmamap_callback_t (void *arg, bus_dma_segment_t *segs, int nseg, int error);
+
+static inline int
+bus_dmamap_load(bus_dma_tag_t tag, bus_dmamap_t map, caddr_t vaddr, bus_size_t size, bus_dmamap_callback_t cb, void *arg, unsigned flags)
+{
+bus_dma_segment_t segs[1];
+ segs[0].ds_addr = CPU2BUSADDR(vaddr);
+ segs[0].ds_len = size;
+ cb(arg, segs, 1, 0);
+ return 0;
+}
+
+typedef void bus_dmamap_callback2_t (void *arg, bus_dma_segment_t *segs, int nsegs, bus_size_t mapsize, int error);
+
+static inline int
+bus_dmamap_load_mbuf(bus_dma_tag_t tag, bus_dmamap_t map, struct mbuf *m_head, bus_dmamap_callback2_t cb, void *arg, unsigned flags)
+{
+/* hopefully there's enough stack ... */
+bus_dma_segment_t segs[tag->maxsegs];
+struct mbuf *m;
+int n;
+bus_size_t sz;
+ for ( m=m_head, sz=0, n=0; m; m=m->m_next, n++ ) {
+ if ( n >= tag->maxsegs ) {
+ cb(arg, segs, n, sz, EFBIG);
+ return EFBIG;
+ }
+ segs[n].ds_addr = CPU2BUSADDR(mtod(m, unsigned));
+ sz += (segs[n].ds_len = m->m_len);
+ }
+ cb(arg, segs, n, sz, 0);
+ return 0;
+}
+
+#define bus_dmamap_unload(tag, map) do {} while (0)
+
+/* should we do something if we have no HW snooping ? */
+#define bus_dmamap_sync(tag, map, flags) do { membarrier_rw(); } while (0)
+
+#define bus_dmamap_create(tag, flags, pmap) ( *(pmap) = 0, 0 )
+#define bus_dmamap_destroy(tag, map) do {} while (0)
+
+#endif
diff --git a/bsd_eth_drivers/libbsdport/callout.h b/bsd_eth_drivers/libbsdport/callout.h
new file mode 100644
index 0000000..3f586bf
--- /dev/null
+++ b/bsd_eth_drivers/libbsdport/callout.h
@@ -0,0 +1,43 @@
+#ifndef _SYS_CALLOUT_H
+#define _SYS_CALLOUT_H /* include this to override rtems stack's */
+
+/* RTEMS systm.h still declares old timout stuff which is not
+ * fully compatible with more recent 'callout' functionality.
+ *
+ * Also: our struct callout it incompatible with the one
+ * declared in rtems' sys/callout.h.
+ * Make sure to include the proper header (first).
+ */
+
+typedef unsigned callout_time_t;
+
+struct callout {
+ struct callout *c_next;
+ struct callout **c_pprev;
+ void (*c_func)(void*);
+ void *c_arg;
+ struct mtx *c_mtx;
+ callout_time_t c_time;
+};
+
+/* We cannot stop a callout that's in progress */
+
+void
+callout_stop(struct callout *c);
+
+#define callout_drain callout_stop
+
+void
+callout_reset(struct callout *c, int ticks, void (*fn)(void*), void *arg);
+
+void
+callout_init(struct callout *c, int mpsafe);
+
+void
+callout_init_mtx(struct callout *c, struct mtx *m, unsigned flags);
+
+/* Initialize callout facility [networking must have been initialized already] */
+rtems_id
+rtems_callout_initialize();
+
+#endif
diff --git a/bsd_eth_drivers/libbsdport/contigmalloc.c b/bsd_eth_drivers/libbsdport/contigmalloc.c
new file mode 100644
index 0000000..7c9f1b7
--- /dev/null
+++ b/bsd_eth_drivers/libbsdport/contigmalloc.c
@@ -0,0 +1,33 @@
+#include <rtems.h>
+
+#define _KERNEL
+#include <rtems/rtems_bsdnet_internal.h>
+#include <sys/malloc.h>
+
+void *
+contigmalloc(
+ unsigned long size,
+ int type,
+ int flags,
+ unsigned long lo,
+ unsigned long hi,
+ unsigned long align,
+ unsigned long bound)
+{
+void *ptr = rtems_bsdnet_malloc(size + sizeof(ptr) + align-1, type, flags);
+char *rval = 0;
+ if ( ptr ) {
+ unsigned tmp = (unsigned)ptr + align - 1;
+ tmp -= tmp % align;
+ rval = (char*)tmp;
+ /* save backlink */
+ *(void**)(rval+size) = ptr;
+ }
+ return rval;
+}
+
+void
+contigfree(void *ptr, size_t size, int type)
+{
+ rtems_bsdnet_free( *(void**)((unsigned)ptr + size), type);
+}
diff --git a/bsd_eth_drivers/libbsdport/devicet.c b/bsd_eth_drivers/libbsdport/devicet.c
new file mode 100644
index 0000000..48ddd9a
--- /dev/null
+++ b/bsd_eth_drivers/libbsdport/devicet.c
@@ -0,0 +1,374 @@
+#define DEVICET_EXTERN_INLINE
+
+#include "devicet.h"
+#include <rtems/rtems_bsdnet.h>
+#include <sys/malloc.h>
+#include <assert.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdio.h>
+#include <rtems/pci.h>
+#include <rtems/error.h>
+#include <sys/bus.h>
+#include "libbsdport_api.h"
+
+#define DEBUG
+
+extern void real_libc_free(void*);
+
+static STAILQ_HEAD(devq_t, device) devq = STAILQ_HEAD_INITIALIZER(devq);
+
+static device_t
+devalloc(driver_t *dr)
+{
+void *m;
+device_t rval;
+int l = sizeof(*rval) + dr->softc_size + DEVICE_SOFTC_ALIGNMENT -1;
+
+ if ( !(m = malloc( l, M_DEVBUF, M_NOWAIT )) )
+ return 0;
+
+ memset(m, 0, l);
+
+ rval = (device_t)(((uintptr_t)m + (DEVICE_SOFTC_ALIGNMENT-1)) & ~(DEVICE_SOFTC_ALIGNMENT-1));
+ rval->rawmem = m;
+ rval->type = dr->type;
+ rval->name = dr->name;
+ rval->drv = dr;
+
+ return rval;
+}
+
+static void
+devclean(device_t dev)
+{
+ assert( !dev->attached );
+ memset(device_get_softc(dev), 0, dev->drv->softc_size);
+ real_libc_free(dev->desc);
+ dev->desc = 0;
+ dev->unit = 0;
+ dev->nameunit[0]=0;
+ memset( &dev->bushdr, 0, sizeof(dev->bushdr));
+}
+
+static void
+devfree(device_t dev)
+{
+ /* paranoia */
+ devclean(dev);
+ dev->drv = 0;
+ free(dev->rawmem, M_DEVBUF);
+}
+
+static int
+devattach(device_t dev, int unit, struct rtems_bsdnet_ifconfig *cfg)
+{
+int error;
+
+#ifdef DEBUG
+ printf("Now attaching %s%d: (0x%x:%x.%x)\n",
+ dev->name, unit,
+ dev->bushdr.pci.bus, dev->bushdr.pci.dev, dev->bushdr.pci.fun);
+#endif
+
+ dev->unit = unit;
+ dev->ifconfig = cfg;
+ sprintf(dev->nameunit,"%s%d",dev->drv->name,unit);
+
+ /* Try to attach */
+ if ( (error = dev->drv->methods->attach(dev)) ) {
+ fprintf(stderr,"Attaching '%s%d' failed: %s", dev->drv->name, unit, strerror(error));
+ return error;
+ }
+ /* Successfully attached new device */
+ dev->attached = 1;
+ cfg->name = (char*)device_get_nameunit(dev);
+ STAILQ_INSERT_TAIL(&devq, dev, list);
+ return 0;
+}
+
+static int
+devequal(device_t a, device_t b)
+{
+ if ( a->type != b->type )
+ return 0;
+ switch ( a->type ) {
+ case DEV_TYPE_PCI:
+ return a->bushdr.pci.bus == b->bushdr.pci.bus
+ && a->bushdr.pci.dev == b->bushdr.pci.dev
+ && a->bushdr.pci.fun == b->bushdr.pci.fun;
+
+ default:
+ rtems_panic("devequal: Unsupported device type %i\n", a->type);
+ }
+ return 0;
+}
+
+/* Check if a particular device is already listed */
+static device_t
+devattached(device_t dev)
+{
+struct device *ldev;
+ STAILQ_FOREACH(ldev, &devq, list) {
+ if ( devequal(ldev, dev) )
+ return ldev;
+ }
+ return 0;
+}
+
+
+int
+device_printf(device_t dev, const char *fmt, ...)
+{
+int rval;
+va_list ap;
+ rval = fprintf(stdout,"%s:",device_get_nameunit(dev));
+ va_start(ap, fmt);
+ rval += vfprintf(stdout,fmt,ap);
+ va_end(ap);
+ return rval;
+}
+
+static uint32_t
+get_pci_triple(const char *drvnam)
+{
+unsigned b,d,f;
+ if ( drvnam && 3 == sscanf(drvnam,"%i:%i.%i",&b,&d,&f) )
+ return (b<<8) | PCI_DEVFN(d,f);
+ return -1;
+}
+
+static void
+get_name_unit(const char *drvnam, char *nm, int *punit)
+{
+int l = strlen(drvnam);
+int i;
+ if ( l > 0 ) {
+ for ( i=l-1; i>=0 && isdigit(drvnam[i]); i-- )
+ /* nothing else to do */;
+ if ( 1 != sscanf(drvnam+i,"%d",punit) )
+ *punit = 0; /* wildcard */
+ strncpy(nm, drvnam, i+1);
+ nm[i+1]=0;
+ } else {
+ /* wildcards */
+ *nm = 0;
+ *punit = 0;
+ }
+}
+
+static int
+matches(driver_t *dr, const char *pat)
+{
+ if ( 0 == *pat || '*' == *pat )
+ return 1;
+ return !strcmp(pat, dr->name);
+}
+
+static int
+pci_slot_empty(int b, int d, int f)
+{
+uint16_t id;
+ pci_read_config_word(b,d,f,PCI_VENDOR_ID,&id);
+ return ( 0xffff == id );
+}
+
+static int
+pci_is_ether(int b, int d, int f)
+{
+uint16_t dclass;
+ if ( pci_slot_empty(b,d,f) )
+ return 0;
+ pci_read_config_word(b,d,f,PCI_CLASS_DEVICE, &dclass);
+ return PCI_CLASS_NETWORK_ETHERNET == dclass;
+}
+
+/* this catches the case of an unpopulated slot (returning 0) */
+static int
+pci_num_functions(int b, int d)
+{
+uint8_t h;
+ if ( pci_slot_empty(b,d,0) )
+ return 0;
+ pci_read_config_byte(b,d,0,PCI_HEADER_TYPE,&h);
+ return (h & 0x80) ? PCI_MAX_FUNCTIONS : 1; /* multifunction device ? */
+}
+
+int
+libbsdport_netdriver_dump(FILE *f)
+{
+struct device *ldev;
+int ndevs;
+unsigned w;
+
+ if ( !f )
+ f = stdout;
+
+ ndevs = 0;
+ fprintf(f, "PCI Network device information:\n");
+ rtems_bsdnet_semaphore_obtain();
+ STAILQ_FOREACH(ldev, &devq, list) {
+ /* ASSUME LIST ELEMENTS DO NOT DISAPPEAR
+ * so we can release the lock while printing...
+ */
+ rtems_bsdnet_semaphore_release();
+ w=fprintf(f,"%-6s -- (0x%x:%x.%x)",
+ device_get_nameunit(ldev),
+ ldev->bushdr.pci.bus,
+ ldev->bushdr.pci.dev,
+ ldev->bushdr.pci.fun);
+ for ( ; w < 24 ; w++)
+ fputc(' ',f);
+ if ( ldev->desc )
+ fprintf(f," %s",ldev->desc);
+ fputc('\n',f);
+
+
+ ndevs++;
+ rtems_bsdnet_semaphore_obtain();
+ }
+ rtems_bsdnet_semaphore_release();
+ return ndevs;
+}
+
+#define UNITMATCH(wanted, unit, bdfunit) \
+ ((wanted) < 0 ? ((wanted) & 0xffff) == (bdfunit) : (wanted) == (unit))
+
+int
+libbsdport_netdriver_attach(struct rtems_bsdnet_ifconfig *cfg, int attaching)
+{
+char nm[20]; /* copy of the name */
+int unit,thisunit,wantedunit;
+int i,b,d,f;
+int prob;
+driver_t *dr;
+device_t dev = 0;
+device_t tmpdev;
+int error = 0;
+int bdfunit;
+
+ if ( !attaching )
+ return ENOTSUP;
+
+ if ( (wantedunit = get_pci_triple(cfg->name)) < 0 ) {
+ get_name_unit(cfg->name, nm, &wantedunit);
+ } else {
+ wantedunit |= 1<<31;
+ nm[0]=0;
+ }
+#ifdef DEBUG
+ printf("Wanted unit is 0x%x, pattern '%s'\n", wantedunit, nm);
+#endif
+
+ unit = 0;
+ for ( i=0; (dr=libbsdport_netdriver_table[i]); i++ ) {
+ /* Find matching driver */
+#ifdef DEBUG
+ printf("Trying driver '%s' ...", dr->name);
+#endif
+ if ( matches(dr, nm) ) {
+#ifdef DEBUG
+ printf("MATCH\n");
+#endif
+
+ assert( dr->methods );
+
+ thisunit = 0;
+
+ if ( DEV_TYPE_PCI != dr->type ) {
+ fprintf(stderr,"Non-PCI driver '%s' not supported; skipping\n", dr->name);
+ continue;
+ }
+
+ dev = devalloc(dr);
+ for ( b=0; b<pci_bus_count(); b++)
+ for ( d=0; d<PCI_MAX_DEVICES; d++ ) {
+ for ( f=0; f<pci_num_functions(b,d); f++ ) {
+ if ( ! pci_is_ether(b,d,f) )
+ continue;
+
+ dev->bushdr.pci.bus = b;
+ dev->bushdr.pci.dev = d;
+ dev->bushdr.pci.fun = f;
+
+ bdfunit = (b<<8) | PCI_DEVFN(d,f);
+
+#ifdef DEBUG
+ printf("Probing PCI 0x%x:%x.%x\n",
+ bdfunit>>8, PCI_SLOT(bdfunit), PCI_FUNC(bdfunit));
+#endif
+
+ /* has this device been attached already ? */
+ if ( (tmpdev = devattached(dev)) ) {
+ if ( dev->drv == tmpdev->drv )
+ thisunit++;
+ unit++;
+ if ( UNITMATCH(wantedunit, unit, bdfunit) ) {
+ fprintf(stderr,"Device '%s' has already been attached\n", device_get_nameunit(dev));
+ error = EBUSY;
+ goto bail;
+ }
+ } else {
+ switch ( ( prob = dr->methods->probe(dev) ) ) {
+ /* LOW_PRIORITY currently unsupported; list preferred drivers first */
+ case BUS_PROBE_LOW_PRIORITY:
+ case BUS_PROBE_DEFAULT:
+ /* accepted */
+ thisunit++;
+ unit++;
+ /* wanted unit == 0 means next avail.
+ * unit is acceptable.
+ */
+#ifdef DEBUG
+ printf("->SUCCESS\n");
+#endif
+ if ( 0 == wantedunit || UNITMATCH(wantedunit, unit, bdfunit) ) {
+ error = devattach(dev, thisunit, cfg);
+ if ( !error )
+ dev = 0; /* is now on list */
+ goto bail;
+ }
+ break;
+
+ default:
+#ifdef DEBUG
+ printf("->FAILED\n");
+#endif
+ /* probe failed */
+ break;
+ }
+ }
+ devclean(dev);
+ } /* for all functions */
+ } /* for all busses + slots */
+ devfree(dev); dev = 0;
+ } /* matching driver */
+#ifdef DEBUG
+ else printf("NO MATCH\n");
+#endif
+ } /* for all drivers */
+
+ /* Nothing found */
+ error = ENODEV;
+bail:
+ if (dev)
+ devfree(dev);
+ return error;
+}
+
+device_t
+libbsdport_netdriver_get_dev(const char *name)
+{
+struct device *ldev;
+
+ if ( !name )
+ return 0;
+
+ rtems_bsdnet_semaphore_obtain();
+ STAILQ_FOREACH(ldev, &devq, list) {
+ if ( !strcmp(name, device_get_nameunit(ldev)) )
+ break;
+ }
+ rtems_bsdnet_semaphore_release();
+ return ldev;
+}
diff --git a/bsd_eth_drivers/libbsdport/devicet.h b/bsd_eth_drivers/libbsdport/devicet.h
new file mode 100644
index 0000000..bbb4e71
--- /dev/null
+++ b/bsd_eth_drivers/libbsdport/devicet.h
@@ -0,0 +1,125 @@
+#ifndef RTEMS_NETDEV_T_DECL_H
+#define RTEMS_NETDEV_T_DECL_H
+
+#include <rtems.h>
+#include <rtems/bspIo.h>
+#include <stdarg.h>
+#include <stdio.h>
+
+#include <bsp/rtems_verscheck.h>
+
+#if RTEMS_REV_AT_LEAST(4,8,99)
+#include <rtems/bsd/sys/queue.h>
+#else
+#include <sys/queue.h>
+#endif
+
+#include <libbsdport_api.h>
+
+/* se we can generate a non-inlined version somewhere */
+#ifndef DEVICET_EXTERN_INLINE
+#define DEVICET_EXTERN_INLINE extern inline
+#endif
+
+/* unused for now: */
+typedef int devclass_t;
+
+typedef struct device *device_t;
+
+typedef struct _pcidev_t {
+ unsigned short bus;
+ unsigned char dev;
+ unsigned char fun;
+} pcidev_t;
+
+#define DEV_TYPE_PCI 1
+
+typedef int device_probe_t (device_t);
+typedef int device_attach_t (device_t);
+typedef int device_detach_t (device_t);
+typedef int device_resume_t (device_t);
+typedef int device_suspend_t (device_t);
+
+typedef struct device_methods {
+ int (*probe ) (device_t);
+ int (*attach) (device_t);
+ void (*shutdown) (device_t);
+ int (*detach) (device_t);
+ int (*irq_check_dis) (device_t);
+ void (*irq_en) (device_t);
+} device_method_t;
+
+struct driver {
+ const char *name;
+ device_method_t *methods;
+ int type;
+ int softc_size;
+};
+
+#define DEVICE_SOFTC_ALIGNMENT 16
+
+struct device {
+ union {
+ pcidev_t pci;
+ } bushdr;
+ int type;
+ STAILQ_ENTRY(device) list;
+ const char *name;
+ char nameunit[16]; /* NEVER use knowledge about the size of this -- we may change it */
+ int unit;
+ char *desc;
+ driver_t *drv;
+ int attached;
+ void *rawmem; /* back pointer */
+ struct rtems_bsdnet_ifconfig *ifconfig;
+ char softc[] __attribute__ ((aligned(DEVICE_SOFTC_ALIGNMENT), may_alias));
+ /* a pointer to back to the device is installed past the 'softc' */
+};
+
+static inline device_t
+rtems_softc2dev(void *softc)
+{
+uintptr_t diff = (uintptr_t)&((device_t)(0))->softc - (uintptr_t)(device_t)(0);
+ return (device_t)((uintptr_t)softc - diff);
+}
+
+#define device_set_desc_copy(dev, nm) \
+ do { real_libc_free((dev)->desc); (dev)->desc = strdup((nm)); } while (0)
+
+#define device_set_desc(dev, nm) device_set_desc_copy(dev, nm)
+
+static inline const char *
+device_get_nameunit(device_t dev)
+{
+ return dev->nameunit;
+}
+
+static inline const char *
+device_get_name(device_t dev)
+{
+ return dev->name;
+}
+
+static inline int
+device_get_unit(device_t dev)
+{
+ return dev->unit;
+}
+
+DEVICET_EXTERN_INLINE void *
+device_get_softc(device_t dev)
+{
+ return dev->softc;
+}
+
+#define device_delete_child(dev,bus) do {} while (0)
+
+static inline int
+device_is_attached(device_t dev)
+{
+ return dev->attached;
+}
+
+int device_printf(device_t dev, const char *fmt, ...);
+
+#endif
diff --git a/bsd_eth_drivers/libbsdport/ifmedia.c b/bsd_eth_drivers/libbsdport/ifmedia.c
new file mode 100644
index 0000000..77c3bd3
--- /dev/null
+++ b/bsd_eth_drivers/libbsdport/ifmedia.c
@@ -0,0 +1,91 @@
+#include <rtems.h>
+#define _KERNEL
+#include <rtems/rtems_bsdnet.h>
+#include <rtems/rtems_bsdnet_internal.h>
+
+#include <bsp/rtems_verscheck.h>
+
+#if RTEMS_REV_AT_LEAST(4,8,99)
+#include <rtems/bsd/sys/queue.h>
+#else
+#include <sys/queue.h>
+#endif
+
+#include <sys/malloc.h>
+#include <sys/errno.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <net/if.h>
+#include <net/if_media.h>
+#include <rtems/rtems_mii_ioctl.h>
+
+void
+ifmedia_init(struct ifmedia *ifm, int dontcare_mask,
+ ifm_change_cb_t change_callback, ifm_stat_cb_t status_callback)
+{
+ ifm->ifm_mask = dontcare_mask;
+ ifm->ifm_media = 0;
+ ifm->ifm_cur = 0;
+ ifm->ifm_list.lh_first = NULL;
+ ifm->ifm_change = change_callback;
+ ifm->ifm_status = status_callback;
+}
+
+void
+ifmedia_add(struct ifmedia *ifm, int mword, int data, void *aux)
+{
+struct ifmedia_entry *ifmen, *ifmep, *ifme;
+ if ( ( ifme = malloc(sizeof(*ifme), M_DEVBUF, M_NOWAIT) ) ) {
+ ifme->ifm_media = mword;
+ ifme->ifm_data = data;
+ ifme->ifm_aux = aux;
+ for ( ifmep = LIST_FIRST(&ifm->ifm_list); ifmep; ifmep = ifmen ) {
+ if ( !(ifmen = LIST_NEXT(ifmep, ifm_list)) )
+ break;
+ }
+ if ( ifmep )
+ LIST_INSERT_AFTER(ifmep, ifme, ifm_list);
+ else
+ LIST_INSERT_HEAD( &ifm->ifm_list, ifme, ifm_list);
+ }
+}
+
+int
+ifmedia_ioctl(struct ifnet *ifp, struct ifreq *ifr, struct ifmedia *ifm, u_long cmd)
+{
+int rval = 0;
+struct ifmediareq ifmr;
+ if ( SIOCGIFMEDIA == cmd ) {
+ if ( !ifm->ifm_status )
+ return ENOTSUP;
+ ifm->ifm_status(ifp, &ifmr);
+ if ( ! (IFM_AVALID & ifmr.ifm_status) )
+ return EINVAL;
+ /* translate */
+ ifr->ifr_media = ifmr.ifm_active;
+ if ( IFM_ACTIVE & ifmr.ifm_status )
+ ifr->ifr_media |= IFM_LINK_OK;
+ /* no way to determine if autoneg is forcefully disabled
+ * from ifmr :-(
+ * Look at current ifm_media for now.
+ */
+ if ( IFM_SUBTYPE(ifm->ifm_media) != IFM_AUTO )
+ ifr->ifr_media |= IFM_ANEG_DIS;
+ } else {
+ if ( !ifm->ifm_change )
+ return ENOTSUP;
+ ifm->ifm_media = ifr->ifr_media;
+ rval = ifm->ifm_change(ifp);
+ }
+ return rval;
+}
+
+void
+ifmedia_set(struct ifmedia *ifm, int mword)
+{
+ ifm->ifm_media = mword;
+ /* cannot invoke the ifm_change callback because we have
+ * no ifp here.
+ */
+}
+
diff --git a/bsd_eth_drivers/libbsdport/ifstuff.c b/bsd_eth_drivers/libbsdport/ifstuff.c
new file mode 100644
index 0000000..40e525e
--- /dev/null
+++ b/bsd_eth_drivers/libbsdport/ifstuff.c
@@ -0,0 +1,79 @@
+
+#include "libbsdport.h"
+
+#define _KERNEL
+#include <rtems/rtems_bsdnet.h>
+#include <rtems/rtems_bsdnet_internal.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <net/if_types.h>
+#include <net/ethernet.h>
+
+static struct ifnet *rtems_bsdnet_if_freelist = 0;
+
+struct ifnet *
+if_alloc(int type)
+{
+struct ifnet *rval = 0;
+ if ( IFT_ETHER == type ) {
+ /* Hack with freelist allows for debugging drivers as modules */
+ if ( (rval = rtems_bsdnet_if_freelist) ) {
+ /* use softc pointer to link free list */
+ rtems_bsdnet_if_freelist = rtems_bsdnet_if_freelist->if_softc;
+ }
+ if ( (rval = malloc(sizeof(struct arpcom), M_DEVBUF, M_WAIT)) )
+ memset(rval, 0, sizeof(struct arpcom));
+ }
+ return rval;
+}
+
+void
+if_free(struct ifnet *ifp)
+{
+ /* save on free-list so subsequent alloc gets old
+ * interface back (which is still on the bsdnet stack's list
+ * of known interfaces. The old rtems stack doesn't provide
+ * means to remove an interface once it has been attached.
+ * This hack allows for detaching a *driver* and reattaching
+ * it to the same interface later (good for development/debugging).
+ */
+ ifp->if_softc = rtems_bsdnet_if_freelist;
+ rtems_bsdnet_if_freelist = ifp;
+}
+
+/* Ugly hack to allow unloading/reloading the driver core.
+ * Needed because rtems' bsdnet release doesn't implement
+ * if_detach(). Therefore, we bring the interface down but
+ * keep the device record alive...
+ */
+void
+ether_ifdetach(struct ifnet *ifp)
+{
+ (ifp)->if_flags = 0;
+ (ifp)->if_ioctl = 0;
+ (ifp)->if_start = 0;
+ (ifp)->if_watchdog = 0;
+ (ifp)->if_init = 0;
+}
+
+
+/* copy ethernet addr into arpcom if nothing is set yet */
+void
+ether_setaddr(struct ifnet *ifp, u_int8_t *eaddr)
+{
+int i;
+device_t dev = rtems_softc2dev(ifp->if_softc);
+ /* If LLADDR has already been set, then use it */
+ for ( i=0; i< ETHER_ADDR_LEN; i++ ) {
+ if ( IF_LLADDR(ifp)[i] )
+ break;
+ }
+ if ( i >= ETHER_ADDR_LEN ) {
+ /* not set; see if the ifconfig struct provides one */
+ if ( dev->ifconfig && dev->ifconfig->hardware_address )
+ memcpy(IF_LLADDR(ifp), dev->ifconfig->hardware_address, ETHER_ADDR_LEN);
+ else
+ memcpy(IF_LLADDR(ifp), eaddr, ETHER_ADDR_LEN);
+ }
+}
diff --git a/bsd_eth_drivers/libbsdport/libbsdport.h b/bsd_eth_drivers/libbsdport/libbsdport.h
new file mode 100644
index 0000000..8b88784
--- /dev/null
+++ b/bsd_eth_drivers/libbsdport/libbsdport.h
@@ -0,0 +1,380 @@
+#ifndef RTEMS_COMPAT_DEFS_H
+#define RTEMS_COMPAT_DEFS_H
+
+#include <rtems.h>
+#include <sys/param.h>
+
+#define _KERNEL
+#include <rtems/rtems_bsdnet.h>
+#include <rtems/rtems_bsdnet_internal.h>
+
+#include <inttypes.h>
+#include <string.h>
+
+#include <sys/systm.h>
+#include <sys/errno.h>
+#include <sys/mbuf.h>
+
+#include <rtems/bspIo.h>
+#include <rtems/pci.h>
+#include <rtems/irq.h>
+
+#include <devicet.h>
+
+#include <bsp/rtems_verscheck.h>
+
+/*
+#include <rtems/rtems_mii_ioctl.h>
+*/
+
+
+
+#include <rtems_udelay.h>
+
+#ifndef bswap32
+#define bswap32(_x) CPU_swap_u32(_x)
+#endif
+
+#if defined(__LITTLE_ENDIAN__) || defined(__i386__)
+static inline uint16_t htole16(uint16_t v) { return v; }
+static inline uint32_t htole32(uint32_t v) { return v; }
+static inline uint64_t htole64(uint64_t v) { return v; }
+static inline uint16_t le16toh(uint16_t v) { return v; }
+static inline uint32_t le32toh(uint32_t v) { return v; }
+static inline uint64_t le64toh(uint64_t v) { return v; }
+
+#ifdef __i386__
+
+#ifdef __SSE__
+static inline void membarrier_r() { asm volatile("lfence":::"memory"); }
+static inline void membarrier_rw() { asm volatile("mfence":::"memory"); }
+/* Current x86 CPUs always do in-order stores - prevent the compiler from reordering, neverthelesss */
+static inline void membarrier_w() { asm volatile(/*"sfence"*/"":::"memory"); }
+#else
+static inline void membarrier_r() { asm volatile("lock; addl $0,0(%%esp)":::"memory"); }
+static inline void membarrier_rw() { asm volatile("lock; addl $0,0(%%esp)":::"memory"); }
+/* Current x86 CPUs always do in-order stores - prevent the compiler from reordering, neverthelesss */
+static inline void membarrier_w() { asm volatile(/*"lock; addl $0,0(%%esp)"*/"":::"memory"); }
+#endif
+
+#endif
+
+#elif defined(__BIG_ENDIAN__)
+#ifdef __PPC__
+#include <libcpu/byteorder.h>
+
+/* Note the 'may_alias' constructs. They are
+ * a safeguard agains the alias rule should the
+ * pointer argument of st_leXX change (again) in
+ * the future (and it should be safe to use older
+ * versions of 'byteorder.h'
+ */
+
+static inline uint16_t
+htole16(uint16_t v)
+{
+uint16_t rval __attribute__((may_alias));
+ st_le16((volatile uint16_t*)&rval,v);
+ return rval;
+}
+
+static inline uint16_t
+le16toh(uint16_t v)
+{
+uint16_t vv __attribute__((may_alias)) = v;
+ return ld_le16((volatile uint16_t*)&vv);
+}
+
+static inline uint32_t
+htole32(uint32_t v)
+{
+uint32_t rval __attribute__((may_alias));
+ st_le32((volatile libbsdport_u32_t*)&rval,v);
+ return rval;
+}
+
+static inline uint32_t
+le32toh(uint32_t v)
+{
+uint32_t vv __attribute__((may_alias)) = v;
+ return ld_le32((volatile libbsdport_u32_t*)&vv);
+}
+
+/* Compiler generated floating point instructions for this
+ * and rtems_bsdnet_newproc()-generated tasks are non-FP
+ * :-(
+ */
+static inline uint64_t
+htole64(uint64_t v)
+{
+union {
+ libbsdport_u32_t tmp[2] __attribute__((may_alias));
+ uint64_t rval __attribute__((may_alias));
+} u;
+
+ st_le32( &u.tmp[0], (unsigned)(v&0xffffffff) );
+ st_le32( &u.tmp[1], (unsigned)((v>>32)&0xffffffff) );
+
+ return u.rval;
+}
+
+static inline void membarrier_r() { asm volatile("sync":::"memory"); }
+
+static inline void membarrier_rw() { asm volatile("sync":::"memory"); }
+
+static inline void membarrier_w() { asm volatile("eieio":::"memory"); }
+
+#else
+#error "need htoleXX() implementation for this CPU arch"
+#endif
+
+#else
+#error "Unknown CPU endianness"
+#endif
+
+#include <mutex.h>
+#include <callout.h>
+
+#ifndef PCIR_BAR
+#define PCIR_BAR(x) (0x10+4*(x))
+#endif
+
+#ifndef PCIR_COMMAND
+#define PCIR_COMMAND PCI_COMMAND
+#endif
+
+#ifndef PCIR_REVID
+#define PCIR_REVID PCI_REVISION_ID
+#endif
+
+#ifndef PCIR_SUBVEND_0
+#define PCIR_SUBVEND_0 PCI_SUBSYSTEM_VENDOR_ID
+#endif
+
+#ifndef PCIR_SUBDEV_0
+#define PCIR_SUBDEV_0 PCI_SUBSYSTEM_ID
+#endif
+
+#ifndef PCIR_CIS
+#define PCIR_CIS PCI_CARDBUS_CIS
+#endif
+
+#ifndef PCIM_CMD_BUSMASTEREN
+#define PCIM_CMD_BUSMASTEREN PCI_COMMAND_MASTER
+#endif
+
+#ifndef PCIM_CMD_MEMEN
+#define PCIM_CMD_MEMEN PCI_COMMAND_MEMORY
+#endif
+
+#ifndef PCIM_CMD_PORTEN
+#define PCIM_CMD_PORTEN PCI_COMMAND_IO
+#endif
+
+#ifndef PCIR_CAP_PTR
+#define PCIR_CAP_PTR 0x34
+#endif
+
+#ifndef PCIR_POWER_STATUS
+#define PCIR_POWER_STATUS 0x4
+#endif
+
+#ifndef PCIM_PSTAT_PME
+#define PCIM_PSTAT_PME 0x8000
+#endif
+
+#ifndef PCIM_PSTAT_PMEENABLE
+#define PCIM_PSTAT_PMEENABLE 0x0100
+#endif
+
+#ifndef PCIY_PMG
+#define PCIY_PMG 0x01
+#endif
+
+#ifndef PCI_RF_DENSE
+#define PCI_RF_DENSE 0
+#endif
+
+static inline uint32_t
+pci_read_config(device_t dev, unsigned reg, int width)
+{
+ switch ( width ) {
+ default:
+ case 4:
+ {
+ libbsdport_u32_t v;
+ pci_read_config_dword(dev->bushdr.pci.bus, dev->bushdr.pci.dev, dev->bushdr.pci.fun, reg, &v);
+ return v;
+ }
+ case 2:
+ {
+ uint16_t v;
+ pci_read_config_word(dev->bushdr.pci.bus, dev->bushdr.pci.dev, dev->bushdr.pci.fun, reg, &v);
+ return (uint32_t)v;
+ }
+ case 1:
+ {
+ uint8_t v;
+ pci_read_config_byte(dev->bushdr.pci.bus, dev->bushdr.pci.dev, dev->bushdr.pci.fun, reg, &v);
+ return (uint32_t)v;
+ }
+ }
+}
+
+static inline void
+pci_write_config(device_t dev, unsigned reg, uint32_t val, int width)
+{
+ switch ( width ) {
+ default:
+ case 4:
+ {
+ pci_write_config_dword(dev->bushdr.pci.bus, dev->bushdr.pci.dev, dev->bushdr.pci.fun, reg, val);
+ }
+ case 2:
+ {
+ pci_write_config_word(dev->bushdr.pci.bus, dev->bushdr.pci.dev, dev->bushdr.pci.fun, reg, val);
+ }
+ case 1:
+ {
+ pci_write_config_byte(dev->bushdr.pci.bus, dev->bushdr.pci.dev, dev->bushdr.pci.fun, reg, val);
+ }
+ }
+}
+
+
+static inline uint16_t
+pci_get_vendor(device_t dev)
+{
+ return pci_read_config(dev, PCI_VENDOR_ID, 2);
+}
+
+static inline uint16_t
+pci_get_device(device_t dev)
+{
+ return pci_read_config(dev, PCI_DEVICE_ID, 2);
+}
+
+static inline uint16_t
+pci_get_subvendor(device_t dev)
+{
+ return pci_read_config(dev, PCIR_SUBVEND_0, 2);
+}
+
+static inline uint16_t
+pci_get_subdevice(device_t dev)
+{
+ return pci_read_config(dev, PCIR_SUBDEV_0, 2);
+}
+
+static inline void
+pci_enable_busmaster(device_t dev)
+{
+ pci_write_config(
+ dev,
+ PCI_COMMAND,
+ pci_read_config(dev, PCI_COMMAND, 2) | PCI_COMMAND_MASTER,
+ 2
+ );
+}
+
+static inline void
+pci_enable_io(device_t dev, int space)
+{
+ pci_write_config(
+ dev,
+ PCI_COMMAND,
+ pci_read_config(dev, PCI_COMMAND, 2) | space,
+ 2
+ );
+}
+
+static inline void
+pci_disable_io(device_t dev, int space)
+{
+ pci_write_config(
+ dev,
+ PCI_COMMAND,
+ pci_read_config(dev, PCI_COMMAND, 2) & ~space,
+ 2
+ );
+}
+
+
+
+/* MSI / MSIX not supported */
+static inline int
+pci_msi_count(device_t dev) { return 0; }
+
+static inline int
+pci_alloc_msi(device_t dev, int *pval) { return -1; }
+
+static inline int
+pci_alloc_msix(device_t dev, int *pval) { return -1; }
+
+static inline void
+pci_release_msi(device_t dev) { }
+
+
+
+
+#define IFQ_DRV_IS_EMPTY(q) (0 == (q)->ifq_head)
+#define IFQ_DRV_DEQUEUE(q,m) IF_DEQUEUE((q),(m))
+#define IFQ_DRV_PREPEND(q,m) IF_PREPEND((q),(m))
+
+#define ifq_drv_maxlen ifq_maxlen
+#define IFQ_SET_MAXLEN(q, len) do {} while (0)
+#define IFQ_SET_READY(q) do {} while (0)
+
+#define ETHER_BPF_MTAP(ifp, m) do {} while (0)
+#define BPF_MTAP(ifp, m) do {} while (0)
+
+#define IF_LLADDR(ifp) (((struct arpcom *)(ifp))->ac_enaddr)
+
+#define if_link_state_change(ifp, state) do {} while (0)
+
+/* if_name should probably be const char * but isn't */
+#define if_initname(ifp, name, unit) \
+ do { (ifp)->if_name = (char*)(name); (ifp)->if_unit = (unit); } while (0)
+
+struct ifnet * if_alloc(int type);
+
+void if_free(struct ifnet *ifp);
+
+#define if_printf(ifp,args...) do { printf("%s: ",(ifp)->if_name); printf(args); } while (0)
+
+void *
+contigmalloc(
+ unsigned long size,
+ int type,
+ int flags,
+ unsigned long lo,
+ unsigned long hi,
+ unsigned long align,
+ unsigned long bound);
+
+void
+contigfree(void *ptr, size_t size, int type);
+
+/* locking is handled by 'super-lock' outside driver; watch for link intr task, though */
+#define NET_LOCK_GIANT() do {} while (0)
+#define NET_UNLOCK_GIANT() do {} while (0)
+
+#define KASSERT(cond, msg...) \
+ do { \
+ if ( ! (cond) ) { \
+ rtems_panic msg; \
+ } \
+ } while (0)
+
+#define __FBSDID(x)
+#define MODULE_DEPEND(x1,x2,x3,x4,x5)
+
+#define mii_mediachg(mii) do {} while (0)
+
+void *
+real_libc_malloc(size_t);
+
+void
+real_libc_free(void*);
+
+#endif
diff --git a/bsd_eth_drivers/libbsdport/libbsdport_api.h b/bsd_eth_drivers/libbsdport/libbsdport_api.h
new file mode 100644
index 0000000..ba3e54e
--- /dev/null
+++ b/bsd_eth_drivers/libbsdport/libbsdport_api.h
@@ -0,0 +1,84 @@
+#ifndef LIBBSDPORT_API_H
+#define LIBBSDPORT_API_H
+
+#include <rtems.h>
+#include <rtems/rtems_bsdnet.h>
+
+/* $Id$ */
+
+/* User API to libbsdport driver attach function, driver table etc. */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct driver driver_t;
+
+/* NULL terminated list of all drivers configured into the system.
+ * To be defined by the application.
+ */
+extern driver_t *libbsdport_netdriver_table[];
+
+/* Drivers ported so far: */
+/* Intel E1000 chips */
+extern driver_t libbsdport_em_driver;
+/* AMD 79C971..976 pcnet PCI */
+extern driver_t libbsdport_pcn_driver;
+/* RealTek RTL8139, 8168, 8169, 8169S, 8110, 8101E, and 8111 PCI */
+extern driver_t libbsdport_re_driver;
+/* AMD/Lance older (and later) chips; this driver also supports what 'pcn'
+ * does but might not be as efficient.
+ * NOTE: The 'le_pci' driver works with the pcnet32 (79C970A) emulation
+ * of qemu.
+ */
+extern driver_t libbsdport_le_pci_driver;
+
+
+/* Generic driver attach function (can be used in rtems_bsdnet_ifconfig).
+ * This routine selects a driver/device combination based on
+ * - drivers available / listed in libbsdport_netdriver_table[];
+ * - devices detected in PCI config space compatible with a listed
+ * driver.
+ * - name and unit specified in the rtems_bsdnet_ifconfig.name field
+ * (empty name: "" is a wildcard).
+ *
+ * E.g. assume that
+ * 1) the 'em' and 'pcn' drivers are listed in the table.
+ * 2) a AMD Am79C973 chip is somewhere on the PCI bus
+ * 3) ifconfig name is ""
+ * -> the 'pcn' driver is selected and the only AMD chip present
+ * is used as 'pcn1'.
+ * -> If the name was 'em' or 'pcn2' no device would be found
+ * (no em device found; no 2nd pcn device found).
+ *
+ * Now assume that you have a 82544 and two AMD 79C973 devices:
+ *
+ * name: "" picks the first of the three chips found in PCI space
+ * name: "pcn" picks the first AMD chip found
+ * name: "em" picks the first (and only) 82544
+ * name: "pcn2" picks the second AMD chip
+ *
+ * Also, it is possible to specify a PCI-triple: <busno>:<slotno>.<fnno>
+ * i.e., name: "2:3.0" tries to find a driver that supports the device
+ * at bus #2, slot #2.
+ *
+ * NOTE: detaching a driver is not supported (since rtems bsdnet cannot detach
+ * an interface).
+ */
+int
+libbsdport_netdriver_attach(struct rtems_bsdnet_ifconfig *cfg, int attaching);
+
+/* Print information about all attached drivers to FILE (stdout if NULL)
+ *
+ * RETURNS: number of devices attached so far.
+ *
+ * BUGS: more info should be printed.
+ */
+int
+libbsdport_netdriver_dump(FILE *f);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/bsd_eth_drivers/libbsdport/libbsdport_post.h b/bsd_eth_drivers/libbsdport/libbsdport_post.h
new file mode 100644
index 0000000..fcf7e2d
--- /dev/null
+++ b/bsd_eth_drivers/libbsdport/libbsdport_post.h
@@ -0,0 +1,95 @@
+/* This file is to be included from 'if_xxx.c' AFTER all other
+ * includes so we can override some rtems-bsdnet things...
+ */
+#if 1
+/* These are defined in sys/sysctl.h and we
+ * could one day add support ...
+ */
+#undef SYSCTL_ADD_PROC
+#define SYSCTL_ADD_PROC(unused...) do { } while (0)
+
+#undef SYSCTL_ADD_INT
+#define SYSCTL_ADD_INT(unused...) do { } while (0)
+#endif
+
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+
+/* include after <net/if.h> & friends */
+#include <rtems/rtems_mii_ioctl.h>
+
+#define if_drv_flags if_flags
+#define IFF_DRV_RUNNING IFF_RUNNING
+#define IFF_DRV_OACTIVE IFF_OACTIVE
+
+/* FIXME: should implement m_defrag() */
+#define m_defrag(m_headp, opt) NULL
+
+static inline struct mbuf *
+m_getcl(int how, int type, unsigned flags)
+{
+struct mbuf *mp = 0;
+ if ( ! (flags & M_PKTHDR) ) {
+ printk("m_getcl: DUNNO WHAT TO DO HERE\n");
+ return 0;
+ }
+ MGETHDR(mp, M_DONTWAIT, MT_DATA);
+ if ( mp ) {
+ MCLGET( mp, M_DONTWAIT );
+ if ( !(mp->m_flags & M_EXT) ) {
+ m_freem(mp);
+ mp = 0;
+ }
+ }
+ return mp;
+}
+
+static inline void
+ether_input_skipping(struct ifnet *ifp, struct mbuf *m)
+{ struct ether_header *eh;
+ eh = mtod(m, struct ether_header*);
+#if 1
+ m_adj(m, sizeof(struct ether_header));
+#else
+ /* faster hack */
+ m->m_data += sizeof(struct ether_header);
+ m->m_len -= sizeof(struct ether_header);
+ m->m_pkthdr.len -= sizeof(struct ether_header);
+#endif
+ /* some drivers don't set this */
+ m->m_pkthdr.rcvif = ifp;
+ ether_input(ifp, eh, m);
+}
+
+void
+ether_setaddr(struct ifnet *ifp, u_int8_t *eaddr);
+
+#define ether_ifattach(ifp, eaddr) \
+ do { \
+ (ifp)->if_output = ether_output; \
+ if ( !(ifp)->if_addrlist ) { \
+ /* reattach hack; do this only the first time -- detaching is not implemented, however!! */ \
+ ether_setaddr(ifp, eaddr); \
+ if_attach(ifp); \
+ ether_ifattach(ifp); \
+ } \
+ } while (0)
+
+
+/* Not 100% sure this is correct */
+#define M_MOVE_PKTHDR(to, from) \
+ do { \
+ (to)->m_flags = ((from)->m_flags & M_COPYFLAGS) | ((to)->m_flags & M_EXT); \
+ if (((to)->m_flags & M_EXT) == 0) \
+ (to)->m_data = (to)->m_pktdat; \
+ (to)->m_pkthdr = (from)->m_pkthdr; \
+ (from)->m_flags &= ~M_PKTHDR; \
+ } while (0)
+
+#define ETHER_SIOCMULTIFRAG(e, c, ifr, ifp) \
+ ( ENETRESET != (e = (SIOCADDMULTI == (c) ? \
+ ether_addmulti((ifr), (struct arpcom*)(ifp)) : \
+ ether_delmulti((ifr), (struct arpcom*)(ifp)) ))) \
+
+#define arp_ifinit(ifp, ifa) arp_ifinit((struct arpcom *)ifp, ifa)
+
diff --git a/bsd_eth_drivers/libbsdport/malloc.c b/bsd_eth_drivers/libbsdport/malloc.c
new file mode 100644
index 0000000..116b0e5
--- /dev/null
+++ b/bsd_eth_drivers/libbsdport/malloc.c
@@ -0,0 +1,17 @@
+#include <stdlib.h>
+
+/* sometimes we want the original versions,
+ * not malloc/free shadowed by rtems' bsdnet port
+ */
+
+void *
+real_libc_malloc(size_t s)
+{
+ return malloc(s);
+}
+
+void
+real_libc_free(void *p)
+{
+ free(p);
+}
diff --git a/bsd_eth_drivers/libbsdport/mutex.h b/bsd_eth_drivers/libbsdport/mutex.h
new file mode 100644
index 0000000..5476e37
--- /dev/null
+++ b/bsd_eth_drivers/libbsdport/mutex.h
@@ -0,0 +1,55 @@
+#ifndef _RTEMS_BSDNET_MUTEX_H
+#define _RTEMS_BSDNET_MUTEX_H
+
+/* NOTE: mutexes should never be necessary since
+ * the RTEMS BSD code protects everything with a
+ * big fat lock
+ */
+
+struct mtx {
+ rtems_id mtx_id;
+};
+
+#define MTX_DEF 0 /* default sleeping lock */
+#define MTX_RECURSE 4 /* nesting */
+
+#define MTX_NETWORK_LOCK "xxx"
+
+static inline void
+mtx_init(struct mtx *m, const char *name, const char *type, int opts)
+{
+ /* Set ID to zero in case they want to submit this mutex
+ * to callout_init_mtx()
+ */
+ m->mtx_id = 0;
+}
+
+static inline int
+mtx_initialized(struct mtx *m)
+{
+ return m->mtx_id == 0;
+}
+
+static inline void
+mtx_lock(struct mtx *m)
+{
+}
+
+static inline void
+mtx_unlock(struct mtx *m)
+{
+}
+
+static inline void
+mtx_destroy(struct mtx *m)
+{
+}
+
+/* what ? */
+#define MA_OWNED 1
+static inline void
+mtx_assert(struct mtx *m, int what)
+{
+}
+
+#endif
diff --git a/bsd_eth_drivers/libbsdport/rtems_callout.c b/bsd_eth_drivers/libbsdport/rtems_callout.c
new file mode 100644
index 0000000..ce9a477
--- /dev/null
+++ b/bsd_eth_drivers/libbsdport/rtems_callout.c
@@ -0,0 +1,250 @@
+#include <rtems.h>
+#include <rtems/error.h>
+#include <string.h>
+
+#include <rtems/rtems_bsdnet.h>
+#include <rtems/rtems_bsdnet_internal.h>
+
+#include "mutex.h"
+#include "callout.h"
+
+#define STATIC static
+
+/* Implementation modelled after
+ *
+ * "Redesign the BSD Callout and Timer Facilities"
+ * Adam M. Costello, George Varghese
+ * Dpt. of Computer Science, Washington University, 1995.
+ */
+
+#include <assert.h>
+
+/* rely on networking semaphore for now */
+#define LIST_KEY_DECL(k)
+#define LIST_LOCK(k) do {} while (0)
+#define LIST_UNLOCK(k) do {} while (0)
+
+#define WHEELBITS 5
+
+#define WHEELMASK ((1<<(WHEELBITS))-1)
+
+#define CALLOUT_EVENT RTEMS_EVENT_1
+#define KILL_EVENT RTEMS_EVENT_2
+
+
+typedef void (*timeout_t)(void*);
+
+STATIC volatile callout_time_t hard_ticks = 0;
+STATIC volatile callout_time_t soft_ticks = 0;
+
+STATIC struct callout *c_wheel[1<<WHEELBITS] = {0};
+
+static inline void
+c_enq(struct callout **where, struct callout *c)
+{
+ assert( c->c_pprev == 0 && c->c_next == 0 );
+ if ( (c->c_next = *where) )
+ (*where)->c_pprev = &c->c_next;
+ c->c_pprev = where;
+ *where = c;
+}
+
+static inline void
+c_deq(struct callout *c)
+{
+struct callout *n;
+ assert( c->c_pprev );
+ if ( (n = *c->c_pprev = c->c_next) )
+ n->c_pprev = c->c_pprev;
+ c->c_next = 0;
+ c->c_pprev = 0;
+}
+
+static inline void
+softclock()
+{
+struct callout *c, *n;
+rtems_interrupt_level k1;
+callout_time_t st,ht;
+LIST_KEY_DECL(k);
+
+ /* I believe this is free of a race condition (softclock
+ * and hardclock both update volatile 'soft_ticks' variable):
+ * a) 'hardclock' runs at IRQ level and is atomic
+ * b) inside while loop 'soft_ticks' is != 'hard_ticks'
+ * c) hardclock only modifies soft_ticks if 'soft_ticks'=='hard_ticks'
+ * hence this could only happen just after the update of 'soft_ticks'
+ * at the end of the while loop completes.
+ */
+
+ while ( 1 ) {
+ /* Must atomically read 'soft_ticks' and 'hard_ticks' -- otherwise,
+ * hardclock might update both but we get one old and one new value
+ */
+ rtems_interrupt_disable(k1);
+ st = soft_ticks;
+ ht = hard_ticks;
+ rtems_interrupt_enable(k1);
+ if ( st == ht )
+ break; /* caught up */
+
+ /* at this point, we know that st != ht and therefore,
+ * hardclock will only increment hard_ticks but leave
+ * soft_ticks alone.
+ */
+
+ st++;
+
+ LIST_LOCK(k);
+ for ( c = c_wheel[ st & WHEELMASK ]; c; c=n ) {
+ n = c->c_next;
+ if ( c->c_time <= 0 ) {
+ /* this one expired */
+ c_deq(c);
+ if ( c->c_func )
+ c->c_func(c->c_arg);
+ } else {
+ c->c_time--;
+ }
+ }
+ LIST_UNLOCK(k);
+ soft_ticks = st;
+ /* here, soft_ticks could have caught up and
+ * a hardclock occurring here could also
+ * update soft_ticks.
+ */
+ }
+}
+
+static inline void
+hardclock(rtems_id tid)
+{
+ if ( hard_ticks++ == soft_ticks && !c_wheel[hard_ticks & WHEELMASK] ) {
+ /* nothing to do */
+ soft_ticks++;
+ } else {
+ rtems_event_send(tid, CALLOUT_EVENT);
+ }
+}
+
+static void
+calloutTick(rtems_id myself, void *arg)
+{
+rtems_id tid = (rtems_id)arg;
+
+ hardclock(tid);
+
+ rtems_timer_fire_after(myself, 1, calloutTick, arg);
+}
+
+static void
+calloutTask(void *arg)
+{
+rtems_event_set ev;
+rtems_status_code sc;
+rtems_id ticker = 0;
+rtems_id me;
+
+ sc = rtems_timer_create(rtems_build_name('b','s','d','c'), &ticker);
+ if ( RTEMS_SUCCESSFUL != sc ) {
+ rtems_error(sc, "Creation of timer failed\n");
+ goto bail;
+ }
+ rtems_task_ident(RTEMS_SELF, RTEMS_LOCAL, &me);
+
+ rtems_timer_fire_after(ticker, 1, calloutTick, (void*)me);
+
+ while ( 1 ) {
+ sc = rtems_bsdnet_event_receive (CALLOUT_EVENT | KILL_EVENT, RTEMS_EVENT_ANY | RTEMS_WAIT, RTEMS_NO_TIMEOUT, &ev);
+ if ( RTEMS_SUCCESSFUL != sc ) {
+ rtems_error(sc, "calloutTask: unable to receive event; terminating\n");
+ break;
+ }
+ if ( ev & KILL_EVENT ) {
+ break;
+ }
+ softclock();
+ }
+bail:
+ rtems_timer_delete(ticker);
+ rtems_task_delete(RTEMS_SELF);
+}
+
+
+/* We cannot stop a callout that's in progress */
+
+void
+callout_stop(struct callout *c)
+{
+LIST_KEY_DECL(k);
+
+ if ( !c->c_pprev )
+ return; /* not currently on a list */
+
+ LIST_LOCK(k);
+ /* remove from list */
+ c_deq(c);
+ LIST_UNLOCK(k);
+}
+
+
+void
+callout_reset(struct callout *c, int ticks, timeout_t fn, void *arg)
+{
+LIST_KEY_DECL(k);
+int i;
+
+ if ( ticks <= 0 )
+ ticks = 1;
+
+ callout_stop(c);
+
+ c->c_func = fn;
+ c->c_arg = arg;
+
+ LIST_LOCK(k);
+ i = (hard_ticks + ticks) & WHEELMASK;
+ c->c_time = ticks >> WHEELBITS;
+
+ /* enqueue */
+ c_enq(&c_wheel[i], c);
+
+ LIST_UNLOCK(k);
+}
+
+static rtems_id callout_tid = 0;
+
+void
+callout_init(struct callout *c, int mpsafe)
+{
+ /* non thread-safe lazy init in case nobody cared to do it ... */
+ if ( !callout_tid )
+ rtems_callout_initialize();
+ memset(c,0,sizeof(*c));
+}
+
+void
+callout_init_mtx(struct callout *c, struct mtx *m, unsigned flags)
+{
+ if ( m->mtx_id )
+ rtems_panic("callout_init_mtx: using mutex not supported\n");
+ callout_init(c,0);
+ c->c_mtx = m;
+}
+
+rtems_id
+rtems_callout_initialize()
+{
+ if ( !callout_tid )
+ callout_tid=rtems_bsdnet_newproc ("cout", 4096, calloutTask, NULL);
+ return callout_tid;
+}
+
+#ifdef DEBUG
+void
+_cexpModuleInitialize(void*u)
+{
+ rtems_bsdnet_initialize_network();
+ rtems_callout_initialize();
+}
+#endif
diff --git a/bsd_eth_drivers/libbsdport/rtems_taskqueue.c b/bsd_eth_drivers/libbsdport/rtems_taskqueue.c
new file mode 100644
index 0000000..97153ca
--- /dev/null
+++ b/bsd_eth_drivers/libbsdport/rtems_taskqueue.c
@@ -0,0 +1,308 @@
+#include <rtems.h>
+#include <rtems/error.h>
+
+#include <rtems/rtems_bsdnet.h>
+#include <rtems/rtems_bsdnet_internal.h>
+
+#include "taskqueue.h"
+
+/*
+#define STATIC static
+*/
+#undef DEBUG
+
+#ifdef DEBUG
+#include <stdio.h>
+#ifndef STATIC
+#define STATIC
+#endif
+#else
+#ifndef STATIC
+#define STATIC static
+#endif
+#endif
+
+#define TQ_WAKE_EVENT RTEMS_EVENT_0
+
+/* This implementation is extremely simple; we assume
+ * that all taskqueues (and as a matter of fact there is
+ * only a single one) are manipulated with the rtems
+ * bsdnet semaphore held. I.e.,
+ * taskqueue_enqueue()
+ * taskqueue_drain()
+ * etc.
+ * are called from an environment that holds the
+ * bsdnet semaphore.
+ * Likewise, the thread that works the taskqueue
+ * holds the semaphore while doing so.
+ *
+ */
+
+/* use single-linked list; 'drain' which would benefit from
+ * double-linked list is seldom used and performance doesn't
+ * matter much there. OTOH, the frequent case of working
+ * the list + enqueueing is more efficient for the single-linked
+ * list.
+struct task {
+ struct task *ta_next;
+ int ta_pending;
+ int ta_priority;
+ task_fn ta_fn;
+ void *ta_fn_arg;
+};
+ */
+
+struct taskqueue {
+ struct task anchor;
+ struct task *tail;
+ tq_enq_fn enq_fn;
+ void *enq_fn_arg;
+ rtems_id tid;
+};
+
+
+STATIC struct taskqueue the_taskqueue = {
+ { 0, 0, 0, 0, 0 },
+ &the_taskqueue.anchor,
+ taskqueue_thread_enqueue,
+ &taskqueue_fast,
+ 0
+};
+
+struct taskqueue *taskqueue_fast = &the_taskqueue;
+
+struct taskqueue *
+taskqueue_create(const char *name, int mflags, tq_enq_fn enq_fn, void *arg)
+{
+ if ( enq_fn != taskqueue_thread_enqueue )
+ rtems_panic("rtems_taskqueue: attempt to create non-standard TQ; implementation needs to be modified\n");
+ return &the_taskqueue;
+}
+
+struct taskqueue *
+taskqueue_create_fast(const char *name, int mflags, tq_enq_fn enq_fn, void *arg)
+{
+ return taskqueue_create(name, mflags, enq_fn, arg);
+}
+
+/* taskqueue_enqueue must be allowed from an ISR;
+ * hence, all critical list manipulation must lock out
+ * interrupts...
+ */
+int
+taskqueue_enqueue(struct taskqueue *tq, struct task *ta)
+{
+rtems_interrupt_level l;
+
+rtems_interrupt_disable(l);
+ if ( 0 == ta->ta_pending ++ ) {
+ /* hook into list */
+ ta->ta_next = 0;
+ tq->tail->ta_next = ta;
+ tq->tail = ta;
+ }
+ tq->enq_fn(tq->enq_fn_arg);
+rtems_interrupt_enable(l);
+ return 0;
+}
+
+void
+taskqueue_thread_enqueue(void *ctxt)
+{
+int dopost;
+/* pointer-to-pointer is what bsd provides; we currently
+ * follow the scheme even we don't directly use the argument
+ * passed to taskqueue_create...
+ */
+struct taskqueue *tq = *(struct taskqueue **)ctxt;
+ /* If this is the first entry on the list then the
+ * task needs to be notified...
+ */
+ dopost = ( tq->anchor.ta_next == tq->tail && 1 == tq->tail->ta_pending );
+
+ if ( dopost )
+ rtems_event_send(tq->tid, TQ_WAKE_EVENT);
+}
+
+/* Returns 0 on success */
+int
+taskqueue_start_threads(struct taskqueue **ptq, int count, int prio, const char *fmt, ...)
+{
+ if ( count != 1 )
+ rtems_panic("rtems_taskqueue: taskqueue_start_threads cannot currently deal with count != 1\n");
+
+ /* Do (non thread-safe) lazy init as a fallback */
+ if ( ! the_taskqueue.tid )
+ rtems_taskqueue_initialize();
+ return 0;
+}
+
+void
+taskqueue_drain(struct taskqueue *tq, struct task *ta)
+{
+rtems_interrupt_level l;
+struct task *p, *q;
+int i;
+
+ /* find predecessor; searching the list should be
+ * safe; an ISR might append a new record to the tail
+ * while we are working but that should be OK.
+ */
+ for ( p = &tq->anchor; (q = p->ta_next); p=q ) {
+ if ( q == ta ) {
+ rtems_interrupt_disable(l);
+ /* found; do work */
+ /* remember 'pending' count and extract */
+ i = ta->ta_pending;
+ ta->ta_pending = 0;
+ p->ta_next = ta->ta_next;
+ ta->ta_next = 0;
+ /* adjust tail */
+ if ( tq->tail == q )
+ tq->tail = p;
+ rtems_interrupt_enable(l);
+ for ( ; i>0; i-- ) {
+ ta->ta_fn(ta->ta_fn_arg, i);
+ }
+ return;
+ }
+ }
+}
+
+/* work the task queue and return
+ * nonzero if the list is not empty
+ * (which means that some callback has
+ * rescheduled itself)
+ */
+static void *
+taskqueue_work(struct taskqueue *tq)
+{
+rtems_interrupt_level l;
+struct task *p, *q;
+task_fn f;
+void *arg;
+int i;
+
+/* work off a temporary list in case any callback reschedules
+ * itself or if new tasks are queued from an ISR.
+ */
+rtems_interrupt_disable(l);
+ p = tq->anchor.ta_next;
+
+ tq->anchor.ta_next = 0;
+ tq->tail = &tq->anchor;
+rtems_interrupt_enable(l);
+
+ while ( (q=p) ) {
+ rtems_interrupt_disable(l);
+ i = q->ta_pending;
+ q->ta_pending = 0;
+ /* extract */
+ p = q->ta_next;
+ q->ta_next = 0;
+ f = q->ta_fn;
+ arg = q->ta_fn_arg;
+ rtems_interrupt_enable(l);
+ for ( ; i>0; i-- ) {
+ f(arg, i);
+ }
+ }
+ return tq->anchor.ta_next;
+}
+
+void
+taskqueue_free(struct taskqueue *tq)
+{
+ taskqueue_work(tq);
+}
+
+static void
+taskqueueDoWork(void *arg)
+{
+struct taskqueue *tq = arg;
+rtems_event_set evs;
+rtems_status_code sc;
+ while ( 1 ) {
+ sc = rtems_bsdnet_event_receive(TQ_WAKE_EVENT, RTEMS_EVENT_ANY | RTEMS_WAIT, RTEMS_NO_TIMEOUT, &evs);
+ if ( RTEMS_SUCCESSFUL != sc ) {
+ rtems_error(sc,"rtems_taskqueue: taskqueueDoWork() unable to receive wakup event\n");
+ rtems_panic("Can't proceed\n");
+ }
+ if ( taskqueue_work(tq) ) {
+#if 0
+ /* chance to reschedule */
+ rtems_bsdnet_semaphore_release();
+ rtems_task_wake_after(0);
+ rtems_bsdnet_semaphore_obtain();
+#else
+ /* hopefully, releasing the semaphore (as part of bsdnet_event_receive)
+ * and obtaining the event (which has been posted already)
+ * yields the CPU if necessary...
+ */
+#endif
+ }
+ }
+}
+
+#ifdef DEBUG
+struct task_dbg {
+ struct task t;
+ char *nm;
+};
+
+struct task_dbg taskA = {
+ {0},
+ "taskA"
+};
+
+struct task_dbg taskB = {
+ {0},
+ "taskB"
+};
+
+struct task_dbg taskC = {
+ {0},
+ "taskC"
+};
+
+static void the_task_fn(void *arg, int pending)
+{
+struct task_dbg *td = arg;
+ printf("%s (pending: %i)\n", td->nm, pending);
+ /* Test rescheduling */
+ if ( pending > 3 )
+ taskqueue_enqueue(&the_taskqueue,&td->t);
+}
+
+void taskqueue_dump()
+{
+struct task *p;
+ printf("Anchor %p, Tail %p\n", &the_taskqueue.anchor, the_taskqueue.tail);
+ for ( p = the_taskqueue.anchor.ta_next; p; p=p->ta_next ) {
+ printf("%p: (pending %2i, next %p)\n",
+ p, p->ta_pending, p->ta_next);
+ }
+}
+#endif
+
+rtems_id
+rtems_taskqueue_initialize()
+{
+#ifdef DEBUG
+ TASK_INIT( &taskA.t, 0, the_task_fn, &taskA );
+ TASK_INIT( &taskB.t, 0, the_task_fn, &taskB );
+ TASK_INIT( &taskC.t, 0, the_task_fn, &taskC );
+#endif
+ if ( ! the_taskqueue.tid )
+ the_taskqueue.tid = rtems_bsdnet_newproc("tskq", 10000, taskqueueDoWork, &the_taskqueue);
+ return the_taskqueue.tid;
+}
+
+#ifdef DEBUG
+void
+_cexpModuleInitialize(void *u)
+{
+ rtems_bsdnet_initialize_network();
+ the_taskqueue.tid = rtems_taskqueue_initialize();
+}
+#endif
diff --git a/bsd_eth_drivers/libbsdport/rtems_udelay.c b/bsd_eth_drivers/libbsdport/rtems_udelay.c
new file mode 100644
index 0000000..d8f80f4
--- /dev/null
+++ b/bsd_eth_drivers/libbsdport/rtems_udelay.c
@@ -0,0 +1,192 @@
+#include <rtems.h>
+#include <rtems/error.h>
+#include <bsp.h>
+
+#include "rtems_udelay.h"
+
+#if defined(__PPC__)
+
+#include <rtems/powerpc/registers.h>
+
+/* Ouch. stupid bookE doesn't implement mftb so we must
+ * use mfspr (which wouldn't work on classic ppc if we
+ * were in user mode but luckily we're not.
+ */
+static inline uint64_t __read_hires_clicks()
+{
+uint32_t tbl, tbu1, tbu2;
+ asm volatile(
+ " mfspr %0, %4 \n"
+ " mfspr %1, %3 \n"
+ " mfspr %2, %4 \n"
+ :"=r"(tbu1),"=r"(tbl),"=r"(tbu2)
+ :"i"(TBRL), "i"(TBRU)
+ );
+ if ( tbu1 != tbu2 )
+ asm volatile("mfspr %0, %1":"=r"(tbl):"i"(TBRL));
+ return ((uint64_t)tbu2<<32) | tbl;
+}
+
+#define __rtems_hires_kHz (BSP_bus_frequency/BSP_time_base_divisor)
+
+#elif defined(__i386__)
+
+static inline uint64_t __read_hires_clicks()
+{
+uint32_t lo,hi;
+ asm volatile("rdtsc":"=a"(lo),"=d"(hi));
+ return ( (uint64_t)hi << 32 ) | lo;
+}
+
+#else
+#error "rtems_udelay.c not ported to this CPU yet"
+#endif
+
+#ifndef __rtems_hires_kHz
+/* Clock frequency of high-resolution timer */
+uint32_t __rtems_hires_kHz = 0;
+uint32_t rtems_udelay_calibrate();
+#endif
+
+
+void rtems_usec_delay(uint32_t usecs)
+{
+uint64_t clicks = __read_hires_clicks();
+int ticks;
+ if (usecs > 10) {
+ if ( _ISR_Is_in_progress() ) {
+ rtems_panic("rtems_usec_delay for more than 10us in ISR!!");
+ }
+ if ( _ISR_Get_level() > 0 ) {
+ rtems_panic("rtems_usec_delay for more than 10us with IRQs disabled!!");
+ }
+ }
+ ticks = usecs/rtems_configuration_get_microseconds_per_tick();
+#ifndef __rtems_hires_kHz
+ /* If it's not a macro; do lazy init */
+ if ( 0 == __rtems_hires_kHz ) {
+ uint64_t clicks = rtems_udelay_calibrate();
+ __rtems_hires_kHz = (clicks * 1000) / rtems_configuration_get_microseconds_per_tick();
+ ticks--;
+ }
+#endif
+ clicks += (usecs * __rtems_hires_kHz)/1000;
+ if ( ticks > 0 )
+ rtems_task_wake_after(ticks);
+
+ while ( clicks > __read_hires_clicks() )
+ /* busy wait */;
+}
+
+/* This doesn't belong here; also, the RTEMS timeout() implementation is buggy:
+ * if a timeout is added when the networking task is asleep then I believe 'timeout()'
+ * is unable to schedule a wakeup. Therefore, I implemented the 'callout' facility.
+ */
+#ifdef UNTESTED
+/* Must be executed with the network semaphore held */
+void
+rtems_bsdnet_untimeout(timeout_func_t fn, void *arg)
+{
+register struct callout *l, *p;
+
+ for ( l = &calltodo; (p=l->c_next); l=p ) {
+ if ( p->c_func == fn && p->c_arg == arg ) {
+ register struct callout *n
+ /* found it */
+ if ( (n = p->c_next) && p->c_time > 0 ) {
+ /* adjust time of following entry */
+ n->c_time += p->c_time;
+ }
+ /* extract */
+ l->c_next = n;
+ /* return to extract first occurrence; continue
+ * to extract all
+ */
+#if 0
+ return;
+#else
+ p = l;
+#endif
+ }
+ }
+}
+#endif
+
+struct caldat {
+ uint64_t t0,t1,t2,t3;
+ rtems_id thetid;
+};
+
+#ifndef __rtems_hires_kHz
+static void
+tickmeas1(rtems_id myself, void *arg)
+{
+struct caldat *p = arg;
+ p->t2 = __read_hires_clicks();
+ rtems_event_send(p->thetid, RTEMS_EVENT_0);
+}
+
+static void
+tickmeas0(rtems_id myself, void *arg)
+{
+struct caldat *p = arg;
+ p->t1 = __read_hires_clicks();
+ rtems_timer_fire_after( myself, 1, tickmeas1, arg );
+}
+
+/* Calibrate high-resolution timer */
+uint32_t
+rtems_udelay_calibrate()
+{
+rtems_id timer;
+rtems_status_code sc;
+rtems_event_set ev;
+struct caldat d;
+
+ /* measure a clock tick with the hires timer;
+ * note that we can't just sleep for 1 tick because
+ * that results in sleeping for an unknown fraction
+ * of a tick...
+ */
+ sc = rtems_timer_create( rtems_build_name('h','r','e','s'), &timer );
+ if ( RTEMS_SUCCESSFUL != sc ) {
+ rtems_panic("Unable to create timer:%i\n", sc);
+ }
+ sc = rtems_task_ident(RTEMS_SELF, RTEMS_LOCAL, &d.thetid);
+ if ( RTEMS_SUCCESSFUL != sc ) {
+ rtems_panic("Unable to read my own TID:%i\n", sc);
+ }
+#ifdef DEBUG
+ d.t0 = __read_hires_clicks();
+#endif
+ sc = rtems_timer_fire_after(timer, 1, tickmeas0, &d);
+ if ( RTEMS_SUCCESSFUL != sc ) {
+ rtems_panic("Unable to fire timer:%i\n", sc);
+ }
+ sc = rtems_event_receive( RTEMS_EVENT_0, RTEMS_EVENT_ANY | RTEMS_WAIT , RTEMS_NO_TIMEOUT, &ev);
+#ifdef DEBUG
+ d.t3 = __read_hires_clicks();
+#endif
+ if ( RTEMS_SUCCESSFUL != sc ) {
+ rtems_panic("Unable to synchronize with timer:%i\n", sc);
+ }
+ rtems_timer_delete(timer);
+#ifdef DEBUG
+ printf("Diffs: %llu %llu %llu\n",
+ d.t3-d.t2, d.t2-d.t1, d.t1-d.t0);
+#endif
+ return d.t2-d.t1;
+}
+#endif
+
+#ifdef DEBUG
+unsigned
+hdiff(unsigned s)
+{
+uint64_t now = __read_hires_clicks();
+ rtems_task_wake_after(s);
+ now = __read_hires_clicks() - now;
+ printf("Diff was %llu clicks\n",now);
+ return (unsigned)now;
+}
+#endif
diff --git a/bsd_eth_drivers/libbsdport/rtems_udelay.h b/bsd_eth_drivers/libbsdport/rtems_udelay.h
new file mode 100644
index 0000000..32a3b62
--- /dev/null
+++ b/bsd_eth_drivers/libbsdport/rtems_udelay.h
@@ -0,0 +1,22 @@
+#ifndef RTEMS_UDELAY_Y
+#define RTEMS_UDELAY_Y
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Delay execution for n microseconds. The current task
+ * is suspended for multiples of OS 'ticks' and busy-waits
+ * for fractions thereof.
+ * The routine panics if requested to delay for more than
+ * 10us in an ISR or IRQ-disabled section of code.
+ */
+void rtems_usec_delay(uint32_t usecs);
+
+#define DELAY(usecs) rtems_usec_delay(usecs)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/bsd_eth_drivers/libbsdport/rtems_verscheck.h b/bsd_eth_drivers/libbsdport/rtems_verscheck.h
new file mode 100644
index 0000000..519f817
--- /dev/null
+++ b/bsd_eth_drivers/libbsdport/rtems_verscheck.h
@@ -0,0 +1,29 @@
+#ifndef RTEMS_VERSION_CHECKER_H
+#define RTEMS_VERSION_CHECKER_H
+/* $Id$ Macros to check rtems version dependent API features :-( */
+
+#include <rtems.h>
+
+#define RTEMS_REV_LATER_THAN(ma,mi,re) \
+ ( __RTEMS_MAJOR__ > (ma) \
+ || (__RTEMS_MAJOR__ == (ma) && __RTEMS_MINOR__ > (mi)) \
+ || (__RTEMS_MAJOR__ == (ma) && __RTEMS_MINOR__ == (mi) && __RTEMS_REVISION__ > (re)) \
+ )
+
+#define RTEMS_REV_AT_LEAST(ma,mi,re) \
+ ( __RTEMS_MAJOR__ > (ma) \
+ || (__RTEMS_MAJOR__ == (ma) && __RTEMS_MINOR__ > (mi)) \
+ || (__RTEMS_MAJOR__ == (ma) && __RTEMS_MINOR__ == (mi) && __RTEMS_REVISION__ >= (re)) \
+ )
+
+/*
+ * unfortunately, (powerpc) libcpu/io.h didn't follow the change from
+ * unsigned -> uin32_t :--(
+ */
+#if RTEMS_REV_AT_LEAST(4,8,0)
+typedef uint32_t libbsdport_u32_t;
+#else
+typedef unsigned libbsdport_u32_t;
+#endif
+
+#endif
diff --git a/bsd_eth_drivers/libbsdport/sysbus.c b/bsd_eth_drivers/libbsdport/sysbus.c
new file mode 100644
index 0000000..fc0ae0b
--- /dev/null
+++ b/bsd_eth_drivers/libbsdport/sysbus.c
@@ -0,0 +1,267 @@
+#include <rtems.h>
+#include <rtems/pci.h>
+#include <rtems/error.h>
+#include <sys/errno.h>
+#include <bsp.h>
+#include <devicet.h>
+#include <bsp/irq.h>
+#include <rtems/irq.h>
+
+#include <sys/taskqueue.h>
+
+#include <sys/bus.h>
+#include <sys/malloc.h>
+
+#include <bsp/rtems_verscheck.h>
+
+#if !RTEMS_REV_AT_LEAST(4,6,99) || !defined(BSP_SHARED_HANDLER_SUPPORT)
+
+#include <bsp/bspExt.h>
+
+#else
+
+static void noop(const rtems_irq_connect_data *unused) {};
+static int noop1(const rtems_irq_connect_data *unused) { return 0;};
+
+/* Finally have an ISR arg but the API still sucks.. */
+static int
+bspExtInstallSharedISR(int irqLine, void (*isr)(void *), void * uarg, int flags)
+{
+rtems_irq_connect_data suck = {0};
+ suck.name = irqLine;
+ suck.hdl = isr;
+ suck.handle = uarg;
+ suck.on = noop;
+ suck.off = noop;
+ suck.isOn = noop1;
+ return ! BSP_install_rtems_shared_irq_handler(&suck);
+}
+
+static int
+bspExtRemoveSharedISR(int irqLine, void (*isr)(void *), void *uarg)
+{
+rtems_irq_connect_data suck = {0};
+ suck.name = irqLine;
+ suck.hdl = isr;
+ suck.handle = uarg;
+ suck.on = noop;
+ suck.off = noop;
+ suck.isOn = noop1;
+ return ! BSP_remove_rtems_irq_handler(&suck);
+}
+#endif
+
+
+struct resource *
+bus_alloc_resource_any(device_t dev, int type, int *prid, unsigned flags)
+{
+bus_addr_t ba;
+int isio;
+ switch ( type ) {
+ default:
+ break;
+ case SYS_RES_IOPORT:
+ case SYS_RES_MEMORY:
+ {
+ libbsdport_u32_t d;
+ pci_read_config_dword(
+ dev->bushdr.pci.bus,
+ dev->bushdr.pci.dev,
+ dev->bushdr.pci.fun,
+ *prid,
+ &d);
+ ba = d;
+ isio = (ba & PCI_BASE_ADDRESS_SPACE_IO) ? 1 : 0;
+ if ( (type == SYS_RES_IOPORT) != (isio != 0) )
+ return 0; /* wrong type */
+
+ return (struct resource *) ba;
+ }
+ case SYS_RES_IRQ:
+ {
+ uint8_t line;
+ pci_read_config_byte(
+ dev->bushdr.pci.bus,
+ dev->bushdr.pci.dev,
+ dev->bushdr.pci.fun,
+ PCI_INTERRUPT_LINE,
+ &line);
+ ba = line;
+ /* MSI not implemented */
+ return (struct resource*) ba;
+ }
+ }
+ rtems_panic("bus_alloc_resource_any: unknown/unimplemented resource type %i\n", type);
+ /* never get here */
+ return (struct resource*)0;
+}
+
+struct irq_cookie {
+ device_t dev;
+ driver_filter_t handler;
+ void (*work)(void*);
+ void *arg;
+ /* cache methods */
+ int (*irq_check_dis)(device_t d);
+ void (*irq_en) (device_t d);
+ struct task task;
+};
+
+static int
+sysbus_isr(void *arg)
+{
+struct irq_cookie *info = arg;
+int rval;
+#ifdef DEBUG
+ printk("Sysbus IRQ\n");
+#endif
+ /* Check if we have an IRQ pending and disable further interrupts */
+ rval = info->irq_check_dis(info->dev);
+ if ( FILTER_HANDLED == rval ) {
+ /* enqueue work */
+ taskqueue_enqueue(taskqueue_fast, &info->task);
+ }
+ return rval;
+}
+
+static void
+sysbus_taskfn(void *arg, int pending)
+{
+struct irq_cookie *info = arg;
+
+ /* do work */
+ info->work(info->arg);
+
+ /* reenable interrupts */
+ if ( info->irq_en )
+ info->irq_en(info->dev);
+}
+
+int
+bus_setup_intr(device_t dev, struct resource *r, int flags, driver_filter_t filter, driver_intr_t handler, void *arg, void **cookiep)
+{
+int rval;
+struct irq_cookie *info = 0;
+
+ if ( filter && handler ) {
+ rtems_panic("bus_setup_intr for both: filter & handler not implemented\n");
+ }
+
+ if ( (flags & INTR_FAST) && filter ) {
+ rtems_panic("bus_setup_intr for both: filter & INTR_FAST not implemented\n");
+ /* handler is a fast handler already */
+ filter = (driver_filter_t) handler;
+ handler = 0;
+ }
+
+ if ( handler ) {
+ if ( !dev->drv ) {
+ device_printf(dev, "bus_setup_intr: device has no driver attached\n");
+ return EINVAL;
+ } else if ( !dev->drv->methods->irq_check_dis ) {
+ device_printf(dev, "bus_setup_intr: driver has no 'irq_dis' method\n");
+ return EINVAL;
+ }
+ }
+
+ if ( ! (info = malloc(sizeof(*info), M_DEVBUF, M_NOWAIT)) )
+ return ENOMEM;
+
+ info->dev = dev;
+ info->handler = filter;
+ info->work = handler;
+ info->arg = arg;
+
+ if ( handler ) {
+ TASK_INIT(&info->task, 0, sysbus_taskfn, info);
+ /* make sure taskqueue facility is initialized */
+ rtems_taskqueue_initialize();
+ /* install our own filter */
+ filter = sysbus_isr;
+ arg = info;
+ info->irq_check_dis = dev->drv->methods->irq_check_dis;
+ info->irq_en = dev->drv->methods->irq_en;
+ } else {
+ TASK_INIT(&info->task, 0, 0, 0);
+ }
+
+ rval = bspExtInstallSharedISR((int)r, (void (*)(void*))filter, arg, 0);
+
+ if ( rval ) {
+ free(info, M_DEVBUF);
+ return rval;
+ }
+
+ if ( cookiep )
+ *cookiep = info;
+ return rval;
+}
+
+int
+bus_teardown_intr(device_t dev, struct resource *r, void *cookiep)
+{
+int rval;
+struct irq_cookie *info = cookiep;
+ rval = bspExtRemoveSharedISR((int)r, (void (*)(void*))info->handler, info->arg);
+ if ( 0 == rval ) {
+ if ( info->task.ta_fn ) {
+ taskqueue_drain(taskqueue_fast, &info->task);
+ }
+ free(info, M_DEVBUF);
+ }
+ return rval;
+}
+
+bus_space_handle_t
+rman_get_bushandle(struct resource *r)
+{
+bus_space_handle_t h = (bus_space_handle_t)r;
+bus_space_handle_t msk = (PCI_BASE_ADDRESS_SPACE_IO & h) ? PCI_BASE_ADDRESS_IO_MASK : PCI_BASE_ADDRESS_MEM_MASK;
+ return h & msk;
+}
+
+bus_space_tag_t
+rman_get_bustag(struct resource *r)
+{
+bus_space_handle_t h = (bus_space_handle_t)r;
+ return (PCI_BASE_ADDRESS_SPACE_IO & h) ? bus_space_io : bus_space_mem;
+}
+
+int
+bus_dma_tag_create(void *parent, unsigned alignment, unsigned bounds, uint32_t lowadd, uint32_t hiaddr, void (*filter)(void*), void *filterarg, unsigned maxsize, int nsegs, unsigned maxsegsize, unsigned flags, void (*lockfunc)(void*), void *lockarg, bus_dma_tag_t *ptag)
+{
+bus_dma_tag_t tag;
+ if ( filter || lockfunc )
+ return ENOTSUP;
+ if ( ! (tag = malloc(sizeof(*tag), M_DEVBUF, M_NOWAIT)) )
+ return ENOMEM;
+ /* save some information */
+ tag->alignment = alignment;
+ tag->maxsize = maxsize;
+ tag->maxsegs = nsegs;
+ *ptag = tag;
+ return 0;
+}
+
+void
+bus_dma_tag_destroy(bus_dma_tag_t tag)
+{
+ free(tag, M_DEVBUF);
+}
+
+int
+bus_dmamem_alloc(bus_dma_tag_t tag, void **p_vaddr, unsigned flags, bus_dmamap_t *p_map)
+{
+uintptr_t a;
+ if ( ! (*p_map = malloc(tag->maxsize + tag->alignment, M_DEVBUF, M_NOWAIT)) )
+ return ENOMEM;
+ a = ((uintptr_t)*p_map + tag->alignment - 1 ) & ~(tag->alignment - 1);
+ *p_vaddr = (void*)a;
+ return 0;
+}
+
+void
+bus_dmamem_free(bus_dma_tag_t tag, void *vaddr, bus_dmamap_t map)
+{
+ free(map, M_DEVBUF);
+}
diff --git a/bsd_eth_drivers/libbsdport/taskqueue.h b/bsd_eth_drivers/libbsdport/taskqueue.h
new file mode 100644
index 0000000..d700edf
--- /dev/null
+++ b/bsd_eth_drivers/libbsdport/taskqueue.h
@@ -0,0 +1,69 @@
+#ifndef RTEMS_TASKQUEUE_H
+#define RTEMS_TASKQUEUE_H
+
+#include <stdarg.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct taskqueue;
+
+typedef void (*task_fn)(void *ctxt, int pending);
+
+/* forwarded 'ctxt' that was passed to taskqueue_create() */
+typedef void (*tq_enq_fn)(void *ctxt);
+
+struct task {
+ struct task *ta_next;
+ int ta_pending;
+ int ta_priority;
+ task_fn ta_fn;
+ void *ta_fn_arg;
+};
+
+struct taskqueue *
+taskqueue_create(const char *name, int mflags, tq_enq_fn, void *ctxt);
+
+struct taskqueue *
+taskqueue_create_fast(const char *name, int mflags, tq_enq_fn, void *ctxt);
+
+int
+taskqueue_enqueue(struct taskqueue *tq, struct task *ta);
+
+#define taskqueue_enqueue_fast(_q,_t) taskqueue_enqueue(_q,_t)
+
+void
+taskqueue_thread_enqueue(void *ctxt);
+
+#define PI_NET 150
+/* Returns 0 on success */
+int
+taskqueue_start_threads(struct taskqueue **ptq, int count, int prio, const char *fmt, ...);
+
+void
+taskqueue_drain(struct taskqueue *tq, struct task *ta);
+
+void
+taskqueue_free(struct taskqueue *tq);
+
+#define TASK_INIT(task, pri, fn, arg) \
+ do { \
+ (task)->ta_next = 0; \
+ (task)->ta_priority = (pri); \
+ (task)->ta_pending = 0; \
+ (task)->ta_fn = (fn); \
+ (task)->ta_fn_arg = (arg); \
+ } while (0)
+
+extern struct taskqueue *taskqueue_fast;
+
+/* Initialize taskqueue facility [networking must have been initialized already] */
+rtems_id
+rtems_taskqueue_initialize();
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif