summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTill Straumann <strauman@slac.stanford.edu>2007-12-14 06:30:15 +0000
committerTill Straumann <strauman@slac.stanford.edu>2007-12-14 06:30:15 +0000
commitb599faa1bb56dd5909be179ca56ad74937906823 (patch)
treebe9038b9e1e8775e2b73fd254a5b62ac1891ee71
- imported MVME3100 BSP (from SLAC repository)R_rtems_mvme3100_bsp_slacB_rtems_mvme3100_bsp_slac
-rw-r--r--c/src/lib/libbsp/powerpc/mvme3100/.cvsignore8
-rw-r--r--c/src/lib/libbsp/powerpc/mvme3100/ChangeLog1
-rw-r--r--c/src/lib/libbsp/powerpc/mvme3100/KNOWN_PROBLEMS77
-rw-r--r--c/src/lib/libbsp/powerpc/mvme3100/LICENSE49
-rw-r--r--c/src/lib/libbsp/powerpc/mvme3100/Makefile.am184
-rw-r--r--c/src/lib/libbsp/powerpc/mvme3100/README129
-rw-r--r--c/src/lib/libbsp/powerpc/mvme3100/bsp_specs15
-rw-r--r--c/src/lib/libbsp/powerpc/mvme3100/configure.ac43
-rw-r--r--c/src/lib/libbsp/powerpc/mvme3100/flash/flashcfg.c118
-rw-r--r--c/src/lib/libbsp/powerpc/mvme3100/i2c/i2c_init.c187
-rw-r--r--c/src/lib/libbsp/powerpc/mvme3100/i2c/mpc8540_i2c.c452
-rw-r--r--c/src/lib/libbsp/powerpc/mvme3100/i2c/mpc8540_i2c_busdrv.h64
-rw-r--r--c/src/lib/libbsp/powerpc/mvme3100/include/bsp.h329
-rw-r--r--c/src/lib/libbsp/powerpc/mvme3100/include/bspopts.h.in23
-rw-r--r--c/src/lib/libbsp/powerpc/mvme3100/irq/irq.h126
-rw-r--r--c/src/lib/libbsp/powerpc/mvme3100/irq/irq_init.c140
-rw-r--r--c/src/lib/libbsp/powerpc/mvme3100/network/if_tsec_pub.h346
-rw-r--r--c/src/lib/libbsp/powerpc/mvme3100/network/tsec.c2920
-rw-r--r--c/src/lib/libbsp/powerpc/mvme3100/pci/detect_host_bridge.c115
-rw-r--r--c/src/lib/libbsp/powerpc/mvme3100/preinstall.am143
-rw-r--r--c/src/lib/libbsp/powerpc/mvme3100/start/start.S67
-rw-r--r--c/src/lib/libbsp/powerpc/mvme3100/startup/bspstart.c480
-rw-r--r--c/src/lib/libbsp/powerpc/mvme3100/startup/misc.c133
-rw-r--r--c/src/lib/libbsp/powerpc/mvme3100/tod/todcfg.c28
-rw-r--r--c/src/lib/libbsp/powerpc/mvme3100/vme/VMEConfig.h116
25 files changed, 6293 insertions, 0 deletions
diff --git a/c/src/lib/libbsp/powerpc/mvme3100/.cvsignore b/c/src/lib/libbsp/powerpc/mvme3100/.cvsignore
new file mode 100644
index 0000000000..849c802af6
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/mvme3100/.cvsignore
@@ -0,0 +1,8 @@
+Makefile
+Makefile.in
+aclocal.m4
+autom4te.cache
+config.cache
+config.log
+config.status
+configure
diff --git a/c/src/lib/libbsp/powerpc/mvme3100/ChangeLog b/c/src/lib/libbsp/powerpc/mvme3100/ChangeLog
new file mode 100644
index 0000000000..8b13789179
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/mvme3100/ChangeLog
@@ -0,0 +1 @@
+
diff --git a/c/src/lib/libbsp/powerpc/mvme3100/KNOWN_PROBLEMS b/c/src/lib/libbsp/powerpc/mvme3100/KNOWN_PROBLEMS
new file mode 100644
index 0000000000..2178c43206
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/mvme3100/KNOWN_PROBLEMS
@@ -0,0 +1,77 @@
+I have observed what seem to be strange
+initialization problems with the ethernet
+driver:
+
+I usually configure RTEMS networking by
+BOOTP (the problem has nothing to do with
+BOOTP but I just want to describe my
+environment). Sometimes (it can actually
+happen quite frequently, like 1 out of 4
+attempts but since yesterday when I decided
+to hunt this down more systematically
+the problem seems to have gone - typical!)
+networking fails to initialize properly:
+
+BOOTP requests are sent (to the MAC),
+TX interrupts occur and the TX MIB
+counters increment - i.e., everything
+seems normal but no data can be seen on
+the wire. Also, even though we are on
+a quite busy network, the receiver
+doesn't see anything, i.e., 0 RX
+interrupts, RX MIB counters for broadcast
+packets remain steady at zero etc.
+In brief, everyting seems normal at the
+MAC and higher layers but no connection
+to the wire seems to be established.
+
+Some further tests reveal (system under
+test is in the 'bad' state):
+ 1 communication with the BCM5461 PHY
+ is normal. Registers can be read/written
+ and everything seems normal. In particular,
+ the link status is reported OK: disconnect
+ the cable and MII - BMSR bit 1<<2 is clear,
+ reconnect the cable and BMSR[2] is set.
+ Restart autoneg, the link goes and comes
+ back after a short while.
+ 2 setting the loopback bit in the TSEC's
+ MACCFG1 register correctly feeds packets
+ back into the RX, RX MIB counters now
+ increment and indicate data flow.
+ There are RX interrupts and all indicates
+ (I haven't actually looked at RX packet
+ data) that the RX would work normally.
+ After switching MACCFG1[LOOP_BACK] off
+ no RX traffic can be seen anymore.
+ 3 resetting the PHY (BMCR = 0x8000) and/or
+ restarting autoneg (BMCR = 0x1200) seems
+ to perform the desired action (registers
+ take on expected values) but still no luck
+ with communication all the way through
+ to the wire.
+
+Especially point 2 seems to indicate that
+the problem is likely to be between the
+wire and the MAC somewhere but re-setting
+the PHY doesn't change things. Analysis is
+much complicated by the fact that there
+is no documentation on the BCM5461 chip
+available.
+
+Noteworthy is also that if the system
+initializes OK then it continues to work
+normally; if initialization fails then
+only resetting the board and restarting
+helps.
+
+I wanted to test if it makes a difference
+if MotLoad used the chip prior to RTEMS
+being booted (in case MotLoad did some
+magic step during initialization) but
+before I could really test this the
+problem went away.
+
+Big Mystery...
+
+12/12/2007, T.S.
diff --git a/c/src/lib/libbsp/powerpc/mvme3100/LICENSE b/c/src/lib/libbsp/powerpc/mvme3100/LICENSE
new file mode 100644
index 0000000000..25a6abc81c
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/mvme3100/LICENSE
@@ -0,0 +1,49 @@
+/* NOTE: The terms described in this LICENSE file apply only to the
+ * files created by the author (see below). Consult individual
+ * file headers for more details.
+ */
+
+/*
+ * Authorship
+ * ----------
+ * This software ('mvme3100' RTEMS BSP) was
+ * created by Till Straumann <strauman@slac.stanford.edu>, 2007,
+ * Stanford Linear Accelerator Center, Stanford University.
+ *
+ * Acknowledgement of sponsorship
+ * ------------------------------
+ * The 'mvme3100' BSP was produced by
+ * the Stanford Linear Accelerator Center, Stanford University,
+ * under Contract DE-AC03-76SFO0515 with the Department of Energy.
+ *
+ * Government disclaimer of liability
+ * ----------------------------------
+ * Neither the United States nor the United States Department of Energy,
+ * nor any of their employees, makes any warranty, express or implied, or
+ * assumes any legal liability or responsibility for the accuracy,
+ * completeness, or usefulness of any data, apparatus, product, or process
+ * disclosed, or represents that its use would not infringe privately owned
+ * rights.
+ *
+ * Stanford disclaimer of liability
+ * --------------------------------
+ * Stanford University makes no representations or warranties, express or
+ * implied, nor assumes any liability for the use of this software.
+ *
+ * Stanford disclaimer of copyright
+ * --------------------------------
+ * Stanford University, owner of the copyright, hereby disclaims its
+ * copyright and all other rights in this software. Hence, anyone may
+ * freely use it for any purpose without restriction.
+ *
+ * Maintenance of notices
+ * ----------------------
+ * In the interest of clarity regarding the origin and status of this
+ * SLAC software, this and all the preceding Stanford University notices
+ * are to remain affixed to any copy or derivative of this software made
+ * or distributed by the recipient and are to be affixed to any copy of
+ * software made or distributed by the recipient that contains a copy or
+ * derivative of this software.
+ *
+ * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03
+ */
diff --git a/c/src/lib/libbsp/powerpc/mvme3100/Makefile.am b/c/src/lib/libbsp/powerpc/mvme3100/Makefile.am
new file mode 100644
index 0000000000..8f4035a5b9
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/mvme3100/Makefile.am
@@ -0,0 +1,184 @@
+##
+## $Id$
+##
+
+ACLOCAL_AMFLAGS = -I ../../../../aclocal
+
+# wrapup is the one that actually builds and installs the library
+# from the individual .rel files built in other directories
+SUBDIRS = .
+
+include $(top_srcdir)/../../../../automake/compile.am
+include $(top_srcdir)/../../bsp.am
+
+dist_project_lib_DATA = bsp_specs
+
+include_HEADERS = include/bsp.h
+
+nodist_include_HEADERS = include/bspopts.h
+DISTCLEANFILES = include/bspopts.h
+
+noinst_PROGRAMS =
+
+include_bspdir = $(includedir)/bsp
+
+include_HEADERS += ../../shared/include/coverhd.h
+include_HEADERS += ../../shared/tod.h
+
+project_lib_DATA =
+
+EXTRA_DIST = ./start/start.S
+start.$(OBJEXT): ./start/start.S
+ $(CPPASCOMPILE) -o $@ -c $<
+
+EXTRA_DIST += ../beatnik/start/ssrl/preload.S
+preload.$(OBJEXT): ../beatnik/start/ssrl/preload.S
+ $(CPPASCOMPILE) -DASM -o $@ -c $<
+
+motld_start.$(OBJEXT): preload.$(OBJEXT) start.$(OBJEXT)
+ $(LD) -o $@ -r $^
+
+project_lib_DATA += motld_start.$(OBJEXT)
+
+EXTRA_DIST += ../../powerpc/shared/start/rtems_crti.S
+rtems_crti.$(OBJEXT): ../../powerpc/shared/start/rtems_crti.S
+ $(CPPASCOMPILE) -o $@ -c $<
+project_lib_DATA += rtems_crti.$(OBJEXT)
+
+dist_project_lib_DATA += ../shared/startup/linkcmds
+
+build_date.c::
+ echo 'const char *BSP_build_date="'`date`'";' > $@
+
+noinst_PROGRAMS += startup.rel
+startup_rel_SOURCES = ./startup/bspstart.c build_date.c \
+ ./startup/misc.c \
+ ../../powerpc/shared/startup/pretaskinghook.c \
+ ../../powerpc/shared/startup/zerobss.c \
+ ../../powerpc/shared/startup/sbrk.c ../../shared/bootcard.c \
+ ../../shared/bspclean.c ../../shared/bsplibc.c ../../shared/bsppost.c \
+ ../../shared/gnatinstallhandler.c
+startup_rel_CPPFLAGS = $(AM_CPPFLAGS)
+startup_rel_LDFLAGS = $(RTEMS_RELLDFLAGS)
+
+noinst_PROGRAMS += tod.rel
+tod_rel_SOURCES = ../../shared/tod.c tod/todcfg.c
+tod_rel_CPPFLAGS = $(AM_CPPFLAGS)
+tod_rel_LDFLAGS = $(RTEMS_RELLDFLAGS)
+
+noinst_PROGRAMS += pclock.rel
+pclock_rel_SOURCES = ../../powerpc/shared/clock/p_clock.c
+pclock_rel_CPPFLAGS = $(AM_CPPFLAGS)
+pclock_rel_LDFLAGS = $(RTEMS_RELLDFLAGS)
+
+include_bsp_HEADERS = ../../powerpc/shared/console/uart.h
+noinst_PROGRAMS += console.rel
+console_rel_SOURCES = ../../powerpc/shared/console/uart.c \
+ ../../powerpc/shared/console/console.c \
+ ../../powerpc/shared/console/consoleIo.h \
+ ../../powerpc/shared/console/uart.h
+console_rel_CPPFLAGS = $(AM_CPPFLAGS) $(console_CPPFLAGS)
+console_rel_LDFLAGS = $(RTEMS_RELLDFLAGS)
+
+include_bsp_HEADERS += ./irq/irq.h
+
+noinst_PROGRAMS += irq.rel
+irq_rel_SOURCES = ./irq/irq_init.c ../../powerpc/shared/irq/openpic_i8259_irq.c \
+ ../../powerpc/shared/irq/irq.h
+irq_rel_CPPFLAGS = $(AM_CPPFLAGS)
+irq_rel_LDFLAGS = $(RTEMS_RELLDFLAGS)
+
+
+include_bsp_HEADERS += ../../powerpc/shared/openpic/openpic.h
+
+noinst_PROGRAMS += openpic.rel
+openpic_rel_SOURCES = ../../powerpc/shared/openpic/openpic.h \
+ ../../powerpc/shared/openpic/openpic.c \
+ ../../powerpc/shared/openpic/openpic.h
+
+openpic_rel_CPPFLAGS = $(AM_CPPFLAGS)
+openpic_rel_LDFLAGS = $(RTEMS_RELLDFLAGS)
+
+include_bsp_HEADERS += ../../powerpc/shared/pci/pci.h
+
+noinst_PROGRAMS += pci.rel
+pci_rel_SOURCES = ../../powerpc/shared/pci/pci.c \
+ ./pci/detect_host_bridge.c \
+ ../../powerpc/shared/pci/generic_clear_hberrs.c \
+ ../../powerpc/shared/pci/pcifinddevice.c ../../powerpc/shared/pci/pci.h
+pci_rel_CPPFLAGS = $(AM_CPPFLAGS)
+pci_rel_LDFLAGS = $(RTEMS_RELLDFLAGS)
+
+include_bsp_HEADERS += ../../../libcpu/@RTEMS_CPU@/@exceptions@/bspsupport/vectors.h
+include_bsp_HEADERS += ../../../libcpu/@RTEMS_CPU@/@exceptions@/bspsupport/ppc_exc_bspsupp.h
+include_bsp_HEADERS += ../../../libcpu/@RTEMS_CPU@/@exceptions@/bspsupport/irq_supp.h
+
+include_bsp_HEADERS += ./vme/VMEConfig.h \
+ ../../shared/vmeUniverse/vmeTsi148.h \
+ ../../shared/vmeUniverse/vme_am_defs.h \
+ ../../shared/vmeUniverse/VME.h \
+ ../../shared/vmeUniverse/vmeTsi148DMA.h\
+ ../../shared/vmeUniverse/bspVmeDmaList.h\
+ ../../shared/vmeUniverse/VMEDMA.h
+
+noinst_PROGRAMS += vme.rel
+vme_rel_SOURCES = ../../shared/vmeUniverse/vmeTsi148.c \
+ ../../shared/vmeUniverse/bspVmeDmaList.c \
+ ../../shared/vmeUniverse/vmeTsi148.h \
+ ../../shared/vmeUniverse/vme_am_defs.h \
+ ../../shared/vmeUniverse/VME.h \
+ ../../powerpc/shared/vme/vmeconfig.c \
+ ../../powerpc/shared/vme/vme_universe.c
+
+vme_rel_CPPFLAGS = $(AM_CPPFLAGS)
+vme_rel_LDFLAGS = $(RTEMS_RELLDFLAGS)
+
+include_bsp_HEADERS += ../shared/flash/flashPgm.h \
+ ../shared/flash/flashPgmPvt.h
+
+noinst_PROGRAMS += flash.rel
+flash_rel_SOURCES = ../shared/flash/flash.c \
+ ../shared/flash/spansionFlash.c \
+ ./flash/flashcfg.c
+
+flash_rel_CPPFLAGS = $(AM_CPPFLAGS)
+flash_rel_LDFLAGS = $(RTEMS_RELLDFLAGS)
+
+
+include_bsp_HEADERS += i2c/mpc8540_i2c_busdrv.h
+noinst_PROGRAMS += i2c.rel
+i2c_rel_SOURCES = i2c/mpc8540_i2c.c i2c/i2c_init.c
+i2c_rel_CPPFLAGS = $(AM_CPPFLAGS)
+i2c_rel_LDFLAGS = $(RTEMS_RELLDFLAGS)
+
+include_bsp_HEADERS += ../shared/motorola/vpd.h
+noinst_PROGRAMS += vpd.rel
+vpd_rel_SOURCES = ../shared/motorola/vpd.c
+vpd_rel_CPPFLAGS = $(AM_CPPFLAGS)
+vpd_rel_LDFLAGS = $(RTEMS_RELLDFLAGS)
+
+include_bsp_HEADERS += network/if_tsec_pub.h
+noinst_PROGRAMS += network.rel
+network_rel_SOURCES = network/tsec.c
+network_rel_CPPFLAGS = $(AM_CPPFLAGS)
+network_rel_LDFLAGS = $(RTEMS_RELLDFLAGS)
+
+
+noinst_LIBRARIES = libbsp.a
+libbsp_a_SOURCES =
+libbsp_a_LIBADD = startup.rel pclock.rel console.rel openpic.rel \
+ pci.rel irq.rel i2c.rel tod.rel vpd.rel network.rel vme.rel flash.rel
+
+libbsp_a_LIBADD += ../../../libcpu/@RTEMS_CPU@/shared/cpuIdent.rel \
+ ../../../libcpu/@RTEMS_CPU@/shared/stack.rel \
+ ../../../libcpu/@RTEMS_CPU@/e500/clock.rel \
+ ../../../libcpu/@RTEMS_CPU@/e500/timer.rel \
+ ../../../libcpu/@RTEMS_CPU@/@exceptions@/rtems-cpu.rel \
+ ../../../libcpu/@RTEMS_CPU@/@exceptions@/raw_exception.rel \
+ ../../../libcpu/@RTEMS_CPU@/@exceptions@/exc_bspsupport.rel \
+ ../../../libcpu/@RTEMS_CPU@/@exceptions@/irq_bspsupport.rel
+
+EXTRA_DIST += LICENSE ChangeLog README KNOWN_PROBLEMS
+
+include $(srcdir)/preinstall.am
+include $(top_srcdir)/../../../../automake/local.am
diff --git a/c/src/lib/libbsp/powerpc/mvme3100/README b/c/src/lib/libbsp/powerpc/mvme3100/README
new file mode 100644
index 0000000000..5fff588ea9
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/mvme3100/README
@@ -0,0 +1,129 @@
+Some information about this BSP
+================================
+
+ACKNOWLEDGEMENTS
+----------------
+Acknowledgements:
+
+ Valuable information was obtained from the following drivers
+
+ linux: (BCM54xx) Maciej W. Rozycki, Amy Fong.
+
+ This BSP also builds on top of the work of others who have contributed
+ to similar RTEMS (powerpc) BSPs, most notably Eric Valette, Eric Norum
+ and others.
+
+ This BSP was produced by the Stanford Linear Accelerator Center,
+ Stanford University under contract with the US Department of Energy.
+
+LICENSE
+-------
+See ./LICENSE file.
+
+Note that not all files that are part of this BSP were written by
+myself. Consult individual file headers for copyright
+and authorship information.
+
+HARDWARE SUPPORT
+===============
+(some of the headers mentioned below contain more
+detailed information)
+
+NOTE: The BSP supports the mvme3100 board.
+
+CONSOLE: 2 serial devices, UART driver from 'shared' - no surprises
+ ("/dev/ttyS0", [="/dev/console"], "/dev/ttyS1"). (Only
+ /dev/ttyS0 is accessible from the front panel.)
+
+CLOCK: Decrementer, same as other PPC BSPs. (FIXME: a openpic timer
+ could be used.) The bookE decrementer is slightly different
+ from the classic PPC decrementer but the differences are
+ hidden from the user.
+
+PIC (interrupt controller) (bsp/irq.h): OpenPIC integrated with
+ the MPC8540. (see also: bsp/openpic.h).
+
+PCI (bsp/pci.h):
+ In addition to rtems' PCI API, a call is available to scan
+ all devices executing a user callback on each device.
+ BSP_pciConfigDump() is a convenience wrapper dumping essential
+ information (IDs, BAs, IRQ pin/line) to the console or a file.
+
+MEMORY MAP: MotLoad; all addresses (MEM + I/O) read from PCI config. space
+ are CPU addresses. For sake of portability, drivers should still
+ use the _IO_BASE, PCI_MEM_BASE, PCI_DRAM_OFFSET constants.
+
+NVRAM: No NVRAM.
+
+FLASH (bsp/flashPgm.h): Routines to write flash. Highest level
+ wrapper writes a file to flash.
+ NOTE: Writing to flash is disabled by default;
+ call BSP_flashWriteEnable().
+
+I2C (bsp.h, rtems/libi2c.h, libchip/i2c-xxx.h): temp. sensor, eeprom
+ and real-time clock (RTC) are available as device files (bsp.h);
+ lower-level interface is provided by libi2c.h.
+
+ Available i2c devices are:
+
+ /dev/i2c0.vpd-eeprom
+ /dev/i2c0.usr-eeprom
+ /dev/i2c0.usr1-eeprom
+ /dev/i2c0.ds1621
+ /dev/i2c0.ds1621-raw
+ /dev/i2c0.ds1375-raw
+
+ You can e.g., read the board temperature:
+ fd = open("/dev/i2c0.ds1621",O_RDONLY)
+ read(fd,&temp,1)
+ close(fd);
+ printf("Board Temp. is %idegC\n",(int)temp);
+
+VME: (bsp/VME.h, bsp/vme_am_defs.h, bsp/VMEDMA.h).
+ *always* use VME.h API, if possible; do *not* use chip driver
+ (vmeTsi148.h) directly unless you know what you are
+ doing (i.e., if you need specific features provided by the particular
+ chip)
+
+ VMEConfig.h should not be used by applications as it makes them
+ dependent on BSP internals. VMEConfig.h is intended to be used
+ by BSP designers only.
+
+ VME interrupt priorities: the VME bridge(s) do not implement
+ priorities in hardware.
+ However, on the 3100 multiple physical interrupt
+ lines/wires connect the VME bridge to the PIC. Hence, it is possible
+ to assign the different wires different priorities at the PIC
+ (see bsp/openpic.h) and to route VME interrupts to different
+ wires according to their priority.
+ You need to call driver specific routines
+ for this (vmeXXXIntRoute()), however (for driver-specific API
+ consult bsp/vmeTsi148.h).
+
+ For VME DMA *always* use the bsp/VMEDMA.h API. DO NOT use
+ chip-specific features. Applications written using the bsp/VMEDMA.h
+ API are portable between the UniverseII and the Tsi148.
+
+HARDWARE TIMERS: (bsp/openpic.h). Programmable general-purpose
+ timers. Routines are provided to setup, start and stop
+ GPTs. The setup routine allows for specifying single-shot or periodic
+ mode and dispatches a user ISR when the GPT expires.
+
+NETWORK: (bsp/if_tsec_pub.h). In addition to the standard bsdnet
+ 'attach' function the driver offers a low-level API that
+ can be used to implement alternate communication links
+ which are totally decoupled from BSDNET.
+
+ Consult 'KNOWN_PROBLEMS'.
+
+VPD: (bsp/vpd.h). The board's VPD (vital-product-data such as S/N,
+ MAC addresses and so forth) can be retrieved.
+
+BOOTING: BSP has a relocator-header. Clear MSR and jump to the first
+ instruction in the binary. R3 and R4, if non-null, point to the
+ start/end of an optional command line string that is copied into
+ BSP_commandline_string. The BSP is compatible with 'netboot'.
+
+Have fun.
+
+-- Till Straumann <strauman@slac.stanford.edu>, 2007.
diff --git a/c/src/lib/libbsp/powerpc/mvme3100/bsp_specs b/c/src/lib/libbsp/powerpc/mvme3100/bsp_specs
new file mode 100644
index 0000000000..0fff686076
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/mvme3100/bsp_specs
@@ -0,0 +1,15 @@
+%rename endfile old_endfile
+%rename startfile old_startfile
+%rename link old_link
+
+*startfile:
+%{!qrtems: %(old_startfile)} \
+%{!nostdlib: %{qrtems: ecrti%O%s rtems_crti%O%s crtbegin.o%s \
+%{!qrtems_debug: motld_start.o%s} \
+%{qrtems_debug: motld_start_g.o%s}}}
+
+*link:
+%{!qrtems: %(old_link)} %{qrtems: -Qy -dp -Bstatic -e __rtems_entry_point -u __vectors}
+
+*endfile:
+%{!qrtems: %(old_endfile)} %{qrtems: crtend.o%s ecrtn.o%s}
diff --git a/c/src/lib/libbsp/powerpc/mvme3100/configure.ac b/c/src/lib/libbsp/powerpc/mvme3100/configure.ac
new file mode 100644
index 0000000000..f62e62f1bd
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/mvme3100/configure.ac
@@ -0,0 +1,43 @@
+## Process this file with autoconf to produce a configure script.
+##
+## $Id$
+
+AC_PREREQ(2.60)
+AC_INIT([rtems-c-src-lib-libbsp-powerpc-mvme3100],[_RTEMS_VERSION],[http://www.rtems.org/bugzilla])
+AC_CONFIG_SRCDIR([bsp_specs])
+RTEMS_TOP(../../../../../..)
+
+RTEMS_CANONICAL_TARGET_CPU
+AM_INIT_AUTOMAKE([no-define nostdinc foreign 1.10])
+RTEMS_BSP_CONFIGURE
+
+RTEMS_PROG_CC_FOR_TARGET([-ansi -fasm])
+RTEMS_CANONICALIZE_TOOLS
+RTEMS_CHECK_TOOL(NM,nm,no)
+RTEMS_PROG_CCAS
+
+RTEMS_CHECK_NETWORKING
+AM_CONDITIONAL(HAS_NETWORKING,test "$HAS_NETWORKING" = "yes")
+
+AS=$CC
+AM_PROG_AS
+
+dnl AC_PATH_PROG([AMPOLISH3],[ampolish3],[])
+dnl AM_CONDITIONAL([AMPOLISH3],[test x"$USE_MAINTAINER_MODE" = x"yes" \
+dnl && test -n "$AMPOLISH3"])
+
+RTEMS_BSPOPTS_SET([PPC_USE_DATA_CACHE],[*],[1])
+RTEMS_BSPOPTS_HELP([PPC_USE_DATA_CACHE],
+[If defined, then the PowerPC specific code in RTEMS will use
+ data cache instructions to optimize the context switch code.
+ This code can conflict with debuggers or emulators. It is known
+ to break the Corelis PowerPC emulator with at least some combinations
+ of PowerPC 603e revisions and emulator versions.
+ The BSP actually contains the call that enables this.])
+
+# Explicitly list all Makefiles here
+AC_CONFIG_FILES([Makefile])
+
+RTEMS_PPC_EXCEPTIONS
+
+AC_OUTPUT
diff --git a/c/src/lib/libbsp/powerpc/mvme3100/flash/flashcfg.c b/c/src/lib/libbsp/powerpc/mvme3100/flash/flashcfg.c
new file mode 100644
index 0000000000..217282d026
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/mvme3100/flash/flashcfg.c
@@ -0,0 +1,118 @@
+/* $Id$ */
+
+/* BSP-specific bits of flash programmer support */
+
+/*
+ * Authorship
+ * ----------
+ * This software ('mvme3100' RTEMS BSP) was created by
+ *
+ * Till Straumann <strauman@slac.stanford.edu>, 2005-2007,
+ * Stanford Linear Accelerator Center, Stanford University.
+ *
+ * Acknowledgement of sponsorship
+ * ------------------------------
+ * The 'mvme3100' BSP was produced by
+ * the Stanford Linear Accelerator Center, Stanford University,
+ * under Contract DE-AC03-76SFO0515 with the Department of Energy.
+ *
+ * Government disclaimer of liability
+ * ----------------------------------
+ * Neither the United States nor the United States Department of Energy,
+ * nor any of their employees, makes any warranty, express or implied, or
+ * assumes any legal liability or responsibility for the accuracy,
+ * completeness, or usefulness of any data, apparatus, product, or process
+ * disclosed, or represents that its use would not infringe privately owned
+ * rights.
+ *
+ * Stanford disclaimer of liability
+ * --------------------------------
+ * Stanford University makes no representations or warranties, express or
+ * implied, nor assumes any liability for the use of this software.
+ *
+ * Stanford disclaimer of copyright
+ * --------------------------------
+ * Stanford University, owner of the copyright, hereby disclaims its
+ * copyright and all other rights in this software. Hence, anyone may
+ * freely use it for any purpose without restriction.
+ *
+ * Maintenance of notices
+ * ----------------------
+ * In the interest of clarity regarding the origin and status of this
+ * SLAC software, this and all the preceding Stanford University notices
+ * are to remain affixed to any copy or derivative of this software made
+ * or distributed by the recipient and are to be affixed to any copy of
+ * software made or distributed by the recipient that contains a copy or
+ * derivative of this software.
+ *
+ * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03
+ */
+#include <rtems.h>
+#include <bsp.h>
+#include <libcpu/spr.h>
+#include <stdio.h>
+
+#include <bsp/flashPgmPvt.h>
+
+SPR_RO(TBRL)
+
+#define STATIC static
+
+static struct bankdesc mvme3100Flash[] = {
+ /*
+ * Bank is populated from the top; make max_size negative to
+ * indicate this
+ */
+ { 0xf8000000, 0, - 0x08000000, 2, BSP_flash_vendor_spansion, 0, 0, 0 },
+};
+
+STATIC struct bankdesc *
+bankcheck(int bank, int quiet)
+{
+ if ( bank ) {
+ if ( !quiet )
+ fprintf(stderr,"Invalid flash bank #%i\n",bank);
+ return 0;
+ }
+ return &mvme3100Flash[bank];
+}
+
+STATIC int
+flash_wp(int bank, int enbl)
+{
+uint8_t mask = enbl < 0 ? 0 : BSP_MVME3100_FLASH_CSR_F_WP_SW;
+uint8_t val;
+
+ if ( bank != 0 ) {
+ fprintf(stderr,"Invalid flash bank #%i\n",bank);
+ return -1;
+ }
+
+ if ( enbl )
+ val = BSP_setSysReg( BSP_MVME3100_FLASH_CSR, mask );
+ else
+ val = BSP_clrSysReg( BSP_MVME3100_FLASH_CSR, mask );
+
+ if ( BSP_MVME3100_FLASH_CSR_F_WP_HW & val ) {
+ fprintf(stderr,"Flash: hardware write-protection engaged (switch)\n");
+ return -1;
+ }
+ if ( enbl < 0 )
+ return val & (BSP_MVME3100_FLASH_CSR_F_WP_HW | BSP_MVME3100_FLASH_CSR_F_WP_SW );
+ return 0;
+}
+
+STATIC uint32_t
+read_us_timer()
+{
+uint32_t mhz = BSP_bus_frequency/BSP_time_base_divisor/1000;
+
+ return _read_TBRL()/mhz;
+}
+
+/* BSP ops (detect banks, handle write-protection on board) */
+struct flash_bsp_ops BSP_flashBspOps = {
+ bankcheck: bankcheck,
+ flash_wp: flash_wp,
+ read_us_timer: read_us_timer,
+};
diff --git a/c/src/lib/libbsp/powerpc/mvme3100/i2c/i2c_init.c b/c/src/lib/libbsp/powerpc/mvme3100/i2c/i2c_init.c
new file mode 100644
index 0000000000..61eae8b1b7
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/mvme3100/i2c/i2c_init.c
@@ -0,0 +1,187 @@
+/* $Id$ */
+
+/* Register i2c bus driver & devices */
+
+/*
+ * Authorship
+ * ----------
+ * This software ('mvme3100' RTEMS BSP) was created by
+ *
+ * Till Straumann <strauman@slac.stanford.edu>, 2005-2007,
+ * Stanford Linear Accelerator Center, Stanford University.
+ *
+ * Acknowledgement of sponsorship
+ * ------------------------------
+ * The 'mvme3100' BSP was produced by
+ * the Stanford Linear Accelerator Center, Stanford University,
+ * under Contract DE-AC03-76SFO0515 with the Department of Energy.
+ *
+ * Government disclaimer of liability
+ * ----------------------------------
+ * Neither the United States nor the United States Department of Energy,
+ * nor any of their employees, makes any warranty, express or implied, or
+ * assumes any legal liability or responsibility for the accuracy,
+ * completeness, or usefulness of any data, apparatus, product, or process
+ * disclosed, or represents that its use would not infringe privately owned
+ * rights.
+ *
+ * Stanford disclaimer of liability
+ * --------------------------------
+ * Stanford University makes no representations or warranties, express or
+ * implied, nor assumes any liability for the use of this software.
+ *
+ * Stanford disclaimer of copyright
+ * --------------------------------
+ * Stanford University, owner of the copyright, hereby disclaims its
+ * copyright and all other rights in this software. Hence, anyone may
+ * freely use it for any purpose without restriction.
+ *
+ * Maintenance of notices
+ * ----------------------
+ * In the interest of clarity regarding the origin and status of this
+ * SLAC software, this and all the preceding Stanford University notices
+ * are to remain affixed to any copy or derivative of this software made
+ * or distributed by the recipient and are to be affixed to any copy of
+ * software made or distributed by the recipient that contains a copy or
+ * derivative of this software.
+ *
+ * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03
+ */
+
+#include <rtems.h>
+#include <bsp.h>
+#include <rtems/bspIo.h>
+#include <rtems/libi2c.h>
+#include <libchip/i2c-2b-eeprom.h>
+#include <libchip/i2c-ds1621.h>
+#include <bsp/mpc8540_i2c_busdrv.h>
+#include <rtems/libio.h>
+
+#include <stdio.h>
+#include <sys/stat.h>
+#include <sys/errno.h>
+#include <stdarg.h>
+
+static void
+safe_printf (const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ if ( _System_state_Is_up( _System_state_Get() ) )
+ vfprintf( stderr, fmt, ap );
+ else
+ vprintk( fmt, ap );
+ va_end(ap);
+}
+
+static void
+safe_perror(const char *s)
+{
+ safe_printf("%s :%s\n", s, strerror(errno));
+}
+
+
+int
+BSP_i2c_initialize()
+{
+int busno, succ = 0;
+
+ /* Initialize the library */
+ if ( rtems_libi2c_initialize() ) {
+ safe_printf("Initializing I2C library failed\n");
+ return -1;
+ }
+
+ /* Register our bus driver */
+ if ( (busno=rtems_libi2c_register_bus(
+ BSP_I2C_BUS0_NAME,
+ BSP_I2C_BUS_DESCRIPTOR) ) < 0 ) {
+ safe_perror("Registering mpc8540 i2c bus driver");
+ return -1;
+ }
+
+ /* Now register higher level drivers; note that
+ * the i2c address in the manual is actually left-shifted
+ * by one bit, i.e., as it would go on the bus.
+ */
+
+ /* Use read-only driver for VPD */
+ if ( rtems_libi2c_register_drv(
+ BSP_I2C_VPD_EEPROM_NAME,
+ i2c_2b_eeprom_ro_driver_descriptor,
+ busno,
+ BSP_VPD_I2C_ADDR) < 0 ) {
+ safe_perror("Registering i2c VPD eeprom driver failed");
+ } else {
+ succ++;
+ }
+
+ /* Use read-write driver for user eeprom -- you still might
+ * have to disable HW write-protection on your board.
+ */
+ if ( rtems_libi2c_register_drv(
+ BSP_I2C_USR_EEPROM_NAME,
+ i2c_2b_eeprom_driver_descriptor,
+ busno,
+ BSP_USR0_I2C_ADDR) < 0 ) {
+ safe_perror("Registering i2c 1st USR eeprom driver failed");
+ } else {
+ succ++;
+ }
+
+ /* Use read-write driver for user eeprom -- you still might
+ * have to disable HW write-protection on your board.
+ */
+ if ( rtems_libi2c_register_drv(
+ BSP_I2C_USR1_EEPROM_NAME,
+ i2c_2b_eeprom_driver_descriptor,
+ busno,
+ BSP_USR1_I2C_ADDR) < 0 ) {
+ safe_perror("Registering i2c 2nd USR eeprom driver failed");
+ } else {
+ succ++;
+ }
+
+ /* The thermostat */
+ if ( rtems_libi2c_register_drv(
+ BSP_I2C_DS1621_NAME,
+ i2c_ds1621_driver_descriptor,
+ busno,
+ BSP_THM_I2C_ADDR) < 0 ) {
+ safe_perror("Registering i2c ds1621 temp sensor. driver failed");
+ } else {
+ succ++;
+ }
+
+ /* Finally, as an example, register raw access to the
+ * ds1621. The driver above just reads the 8 msb of the
+ * temperature but doesn't support anything else. Using
+ * the raw device node you can write/read individual
+ * control bytes yourself and e.g., program the thermostat...
+ */
+
+ if ( mknod(
+ BSP_I2C_DS1621_RAW_DEV_NAME,
+ 0666 | S_IFCHR,
+ rtems_filesystem_make_dev_t(rtems_libi2c_major,
+ RTEMS_LIBI2C_MAKE_MINOR(busno,BSP_THM_I2C_ADDR))) ) {
+ safe_perror("Creating device node for raw ds1621 (temp. sensor) access failed");
+ } else {
+ succ++;
+ }
+
+ /* Raw access to RTC */
+ if ( mknod(
+ BSP_I2C_DS1375_RAW_DEV_NAME,
+ 0666 | S_IFCHR,
+ rtems_filesystem_make_dev_t(rtems_libi2c_major,
+ RTEMS_LIBI2C_MAKE_MINOR(busno,BSP_RTC_I2C_ADDR))) ) {
+ safe_perror("Creating device node for raw ds1375 (rtc) access failed");
+ } else {
+ succ++;
+ }
+
+ safe_printf("%i I2C devices registered\n", succ);
+ return 0;
+}
diff --git a/c/src/lib/libbsp/powerpc/mvme3100/i2c/mpc8540_i2c.c b/c/src/lib/libbsp/powerpc/mvme3100/i2c/mpc8540_i2c.c
new file mode 100644
index 0000000000..7512ef5354
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/mvme3100/i2c/mpc8540_i2c.c
@@ -0,0 +1,452 @@
+/* I2C bus driver for mpc8540-based boards */
+
+/*
+ * Authorship
+ * ----------
+ * This software ('mvme3100' RTEMS BSP) was created by
+ *
+ * Till Straumann <strauman@slac.stanford.edu>, 2005-2007,
+ * Stanford Linear Accelerator Center, Stanford University.
+ *
+ * Acknowledgement of sponsorship
+ * ------------------------------
+ * The 'mvme3100' BSP was produced by
+ * the Stanford Linear Accelerator Center, Stanford University,
+ * under Contract DE-AC03-76SFO0515 with the Department of Energy.
+ *
+ * Government disclaimer of liability
+ * ----------------------------------
+ * Neither the United States nor the United States Department of Energy,
+ * nor any of their employees, makes any warranty, express or implied, or
+ * assumes any legal liability or responsibility for the accuracy,
+ * completeness, or usefulness of any data, apparatus, product, or process
+ * disclosed, or represents that its use would not infringe privately owned
+ * rights.
+ *
+ * Stanford disclaimer of liability
+ * --------------------------------
+ * Stanford University makes no representations or warranties, express or
+ * implied, nor assumes any liability for the use of this software.
+ *
+ * Stanford disclaimer of copyright
+ * --------------------------------
+ * Stanford University, owner of the copyright, hereby disclaims its
+ * copyright and all other rights in this software. Hence, anyone may
+ * freely use it for any purpose without restriction.
+ *
+ * Maintenance of notices
+ * ----------------------
+ * In the interest of clarity regarding the origin and status of this
+ * SLAC software, this and all the preceding Stanford University notices
+ * are to remain affixed to any copy or derivative of this software made
+ * or distributed by the recipient and are to be affixed to any copy of
+ * software made or distributed by the recipient that contains a copy or
+ * derivative of this software.
+ *
+ * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03
+ */
+
+/* Note: We maintain base address, IRQ etc. statically and
+ * globally. We don't bother creating driver-specific
+ * data or using the bus handle but simply assume
+ * this is the only 8540/i2c bus in the system.
+ * Proper support for multiple instances would not
+ * be very hard to add but I don't see the point...
+ */
+
+#include <rtems.h>
+#include <bsp.h>
+#include <rtems/libi2c.h>
+#include <bsp/irq.h>
+#include <libcpu/spr.h>
+#include <libcpu/io.h>
+#include <rtems/bspIo.h>
+
+#include "mpc8540_i2c_busdrv.h"
+
+#define STATIC
+
+/* I2C controller register definitions */
+#define I2CADR 0x3000
+#define I2CFDR 0x3004
+#define I2CCR 0x3008
+#define I2CCR_MEN (1<<(7-0))
+#define I2CCR_MIEN (1<<(7-1))
+#define I2CCR_MSTA (1<<(7-2))
+#define I2CCR_MTX (1<<(7-3))
+#define I2CCR_TXAK (1<<(7-4))
+#define I2CCR_RSTA (1<<(7-5))
+#define I2CCR_BCST (1<<(7-7))
+#define I2CSR 0x300c
+#define I2CSR_MCF (1<<(7-0))
+#define I2CSR_MAAS (1<<(7-1))
+#define I2CSR_MBB (1<<(7-2))
+#define I2CSR_MAL (1<<(7-3))
+#define I2CSR_BCSTM (1<<(7-4))
+#define I2CSR_SRW (1<<(7-5))
+#define I2CSR_MIF (1<<(7-6))
+#define I2CSR_RXAK (1<<(7-7))
+#define I2CDR 0x3010
+#define I2CDFSRR 0x3014
+
+SPR_RO(TBRL)
+
+/********* Global Variables **********/
+
+/*
+ * Semaphore for synchronizing accessing task
+ * with the (slow) hardware operation.
+ * Task takes semaphore and blocks, ISR releases.
+ */
+static rtems_id syncsem = 0;
+
+static inline int ok_to_block()
+{
+ return syncsem && _System_state_Is_up( _System_state_Get() );
+}
+
+/*
+ * Wild guess for 0.2 s; this timeout is effective
+ * in polling mode; during early init we don't know
+ * the system clock rate yet - it's one of the things
+ * we have to read from VPD -- via i2c.
+ */
+
+static uint32_t poll_timeout = 333333333/8/5;
+
+/********* Primitives ****************/
+
+static inline uint8_t
+i2c_rd(unsigned reg)
+{
+ return in_8( (volatile uint8_t *)(BSP_8540_CCSR_BASE + reg) );
+}
+
+static inline void
+i2c_wr(unsigned reg, uint8_t val)
+{
+ out_8( (volatile uint8_t *)(BSP_8540_CCSR_BASE + reg), val );
+}
+
+static inline void
+i2c_set(unsigned reg, uint8_t val)
+{
+ i2c_wr( reg, i2c_rd( reg ) | val );
+}
+
+static inline void
+i2c_clr(unsigned reg, uint8_t val)
+{
+ i2c_wr( reg, i2c_rd( reg ) & ~val );
+}
+
+/********* Helper Routines ***********/
+
+/* Synchronize (wait) for a condition on the
+ * i2c bus. Wait for START or STOP to be complete
+ * or wait for a byte-transfer.
+ * The latter is much slower (9 bit times vs. 1/2
+ * in the former cases).
+ *
+ * If the system is up (and we may block) then
+ * this routine attempts to block the current
+ * task rather than busy-waiting.
+ *
+ * NOTE: waiting for START/STOP always requires
+ * polling.
+ */
+
+/* wait until i2c status reg AND mask == cond */
+static rtems_status_code
+i2c_wait( uint8_t msk, uint8_t cond )
+{
+uint32_t then;
+rtems_status_code sc;
+static int warn = 0;
+
+ if ( I2CSR_MIF == msk && ok_to_block() ) {
+ /* block on semaphore only if system is up and sema initialized */
+ sc = rtems_semaphore_obtain( syncsem, RTEMS_WAIT, 100 );
+ if ( RTEMS_SUCCESSFUL != sc )
+ return sc;
+ } else {
+ /* system not up (no SEMA yet ) or waiting on something other
+ * than MIF
+ */
+ if ( I2CSR_MIF == msk && _System_state_Is_up( _System_state_Get() ) ) {
+ if ( warn < 8 || ! (warn & 0x1f) )
+ printk("WARNING: i2c bus driver running in polled mode -- should initialize properly!\n");
+ warn++;
+ }
+
+ then = _read_TBRL();
+ do {
+ /* poll for .2 seconds */
+ if ( (_read_TBRL() - then) > poll_timeout )
+ return RTEMS_TIMEOUT;
+ } while ( (msk & i2c_rd( I2CSR )) != cond );
+ }
+
+ return RTEMS_SUCCESSFUL;
+}
+
+/*
+ * multi-byte transfer
+ * - set transfer direction (master read or master write)
+ * - transfer byte
+ * - wait/synchronize
+ * - check for ACK
+ *
+ * RETURNS: number of bytes transferred or negative error code.
+ */
+
+STATIC int
+i2c_xfer(int rw, uint8_t *buf, int len)
+{
+int i;
+rtems_status_code sc;
+
+ if ( rw ) {
+ i2c_clr( I2CCR, I2CCR_MTX );
+ } else {
+ i2c_set( I2CCR, I2CCR_MTX );
+ }
+
+ for ( i = 0; i< len; i++ ) {
+ i2c_clr( I2CSR, I2CSR_MIF );
+ /* Enable interrupts if necessary */
+ if ( ok_to_block() )
+ i2c_set( I2CCR, I2CCR_MIEN );
+ if ( rw ) {
+ buf[i] = i2c_rd( I2CDR );
+ } else {
+ i2c_wr( I2CDR, buf[i] );
+ }
+ if ( RTEMS_SUCCESSFUL != (sc = i2c_wait( I2CSR_MIF, I2CSR_MIF )) )
+ return -sc;
+ if ( (I2CSR_RXAK & i2c_rd( I2CSR )) ) {
+ /* NO ACK */
+ return -RTEMS_IO_ERROR;
+ }
+ }
+
+ return i;
+}
+
+/*
+ * This bus controller gives us lagging data, i.e.,
+ * when we read a byte from the data reg then that
+ * issues a read cycle on the bus and gives us the
+ * byte from the *previous* read cycle :-(
+ *
+ * This makes it impossible to properly terminate
+ * a read transaction w/o knowing ahead of time
+ * how many bytes are going to be read (API decouples
+ * 'START'/'STOP' from 'READ') since we would have to
+ * set TXAK when reading the next-to-last byte
+ * (i.e., when the last byte is read on the i2c bus).
+ *
+ * Hence, (if we are reading) we must do a dummy
+ * read-cycle here -- hopefully
+ * that has no side-effects! (i.e., EEPROM drivers should
+ * reposition file pointers after issuing STOP)
+ *
+ */
+
+static void
+rd1byte_noack()
+{
+uint8_t dum;
+uint8_t ccr;
+
+ /* If we are in reading state then read one more
+ * byte w/o acknowledge
+ */
+
+ ccr = i2c_rd (I2CCR );
+
+ if ( ! ( I2CCR_MTX & ccr ) ) {
+ i2c_wr( I2CCR, ccr | I2CCR_TXAK );
+ i2c_xfer(1, &dum, 1);
+ /* restore original TXAK bit setting */
+ i2c_clr( I2CCR, (I2CCR_TXAK & ccr) );
+ }
+}
+
+
+/********* ISR ***********************/
+
+static void i2c_isr(rtems_irq_hdl_param arg)
+{
+ /* disable irq */
+ i2c_clr( I2CCR, I2CCR_MIEN );
+ /* release task */
+ rtems_semaphore_release( syncsem );
+}
+
+/********* IIC Bus Driver Ops ********/
+
+STATIC rtems_status_code
+i2c_init(rtems_libi2c_bus_t *bh)
+{
+rtems_status_code sc;
+
+ /* compute more accurate timeout */
+ if ( BSP_bus_frequency && BSP_time_base_divisor )
+ poll_timeout = BSP_bus_frequency/BSP_time_base_divisor*1000/5;
+
+ i2c_clr( I2CCR, I2CCR_MEN );
+ i2c_set( I2CCR, I2CCR_MEN );
+
+ i2c_wr( I2CADR, 0 );
+
+ /* leave motload settings for divisor and filter registers */
+
+ if ( SYSTEM_STATE_BEFORE_MULTITASKING <= _System_state_Get() && !syncsem ) {
+ sc = rtems_semaphore_create(
+ rtems_build_name('i','2','c','b'),
+ 0,
+ RTEMS_SIMPLE_BINARY_SEMAPHORE | RTEMS_LOCAL,
+ 0,
+ &syncsem);
+ if ( RTEMS_SUCCESSFUL == sc ) {
+ rtems_irq_connect_data xxx;
+ xxx.name = BSP_I2C_IRQ;
+ xxx.on = 0;
+ xxx.off = 0;
+ xxx.isOn = 0;
+ xxx.hdl = i2c_isr;
+ xxx.handle = 0;
+ if ( ! BSP_install_rtems_irq_handler( &xxx ) ) {
+ printk("Unable to install i2c ISR -- falling back to polling mode\n");
+ rtems_semaphore_delete( syncsem );
+ /* fall back to polling mode */
+ syncsem = 0;
+ }
+ } else {
+ syncsem = 0;
+ }
+ }
+
+ return RTEMS_SUCCESSFUL;
+}
+
+STATIC rtems_status_code
+i2c_start(rtems_libi2c_bus_t *bh)
+{
+uint8_t v;
+rtems_status_code sc = RTEMS_SUCCESSFUL;
+
+ v = i2c_rd( I2CCR );
+ if ( I2CCR_MSTA & v ) {
+ /* RESTART */
+ rd1byte_noack();
+ v |= I2CCR_RSTA;
+ } else {
+ v |= I2CCR_MSTA;
+ }
+ i2c_wr( I2CCR, v );
+
+ /* On MBB we can only poll-wait (no IRQ is generated)
+ * and this is also much faster than reading a byte
+ * (1/2-bit time) so the overhead of an IRQ may not
+ * be justified.
+ * OTOH, we can put this off into the 'send_addr' routine
+ *
+
+ sc = i2c_wait( I2CSR_MBB, I2CSR_MBB );
+ */
+
+ return sc;
+}
+
+STATIC rtems_status_code
+i2c_stop(rtems_libi2c_bus_t *bh)
+{
+ rd1byte_noack();
+
+ /* STOP */
+ i2c_clr( I2CCR, I2CCR_TXAK | I2CCR_MSTA );
+
+ /* FIXME: should we really spend 1/2 bit-time polling
+ * or should we just go ahead and hope noone
+ * else will get a chance to do something to
+ * the bus until the STOP completes?
+ */
+ return i2c_wait( I2CSR_MBB, 0 );
+}
+
+STATIC rtems_status_code
+i2c_send_addr(rtems_libi2c_bus_t *bh, uint32_t addr, int rw)
+{
+uint8_t buf[2];
+int l = 0;
+uint8_t read_mask = rw ? 1 : 0;
+rtems_status_code sc;
+
+ /* Make sure we are started; (i2c_start() didn't bother to wait
+ * so we do it here - some time already has expired.
+ */
+ sc = i2c_wait( I2CSR_MBB, I2CSR_MBB );
+
+ if ( RTEMS_SUCCESSFUL != sc )
+ return sc;
+
+ if ( addr > 0x7f ) {
+ /* 10-bit request; 1st address byte is 0b11110<b9><b8><r/w> */
+ buf[l] = 0xf0 | ((addr >> 7) & 0x06) | read_mask;
+ read_mask = 0;
+ l++;
+ buf[l] = addr & 0xff;
+ } else {
+ buf[l] = (addr << 1) | read_mask;
+ l++;
+ }
+
+ /*
+ * After sending a an address for reading we must
+ * read a dummy byte (this actually clocks the first real
+ * byte on the i2c bus and makes it available in the
+ * data register so that the first 'read_bytes' operation
+ * obtains the byte we clock in here [and starts clocking
+ * the second byte]) to overcome the pipeline
+ * delay in the hardware (I don't like this design) :-(.
+ */
+ sc = i2c_xfer( 0, buf, l );
+ if ( rw && l == sc ) {
+ sc = i2c_xfer( 1, buf, 1 );
+ }
+ return sc >=0 ? RTEMS_SUCCESSFUL : -sc;
+}
+
+STATIC int
+i2c_read_bytes(rtems_libi2c_bus_t *bh, unsigned char *buf, int len)
+{
+ return i2c_xfer( 1, buf, len );
+}
+
+STATIC int
+i2c_write_bytes(rtems_libi2c_bus_t *bh, unsigned char *buf, int len)
+{
+ return i2c_xfer( 0, buf, len );
+}
+
+/********* Driver Glue Vars **********/
+
+static rtems_libi2c_bus_ops_t myops = {
+ init: i2c_init,
+ send_start: i2c_start,
+ send_stop: i2c_stop,
+ send_addr: i2c_send_addr,
+ read_bytes: i2c_read_bytes,
+ write_bytes: i2c_write_bytes,
+};
+
+static rtems_libi2c_bus_t my_bus_tbl = {
+ ops: &myops,
+ size: sizeof(my_bus_tbl),
+};
+
+/********* Global Driver Handle ******/
+
+rtems_libi2c_bus_t *mpc8540_i2c_bus_descriptor = &my_bus_tbl;
diff --git a/c/src/lib/libbsp/powerpc/mvme3100/i2c/mpc8540_i2c_busdrv.h b/c/src/lib/libbsp/powerpc/mvme3100/i2c/mpc8540_i2c_busdrv.h
new file mode 100644
index 0000000000..96921c19d8
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/mvme3100/i2c/mpc8540_i2c_busdrv.h
@@ -0,0 +1,64 @@
+#ifndef MPC8540_I2C_BUS_DRIVER_H
+#define MPC8540_I2C_BUS_DRIVER_H
+
+/*
+ * Authorship
+ * ----------
+ * This software ('mvme3100' RTEMS BSP) was created by
+ *
+ * Till Straumann <strauman@slac.stanford.edu>, 2005-2007,
+ * Stanford Linear Accelerator Center, Stanford University.
+ *
+ * Acknowledgement of sponsorship
+ * ------------------------------
+ * The 'mvme3100' BSP was produced by
+ * the Stanford Linear Accelerator Center, Stanford University,
+ * under Contract DE-AC03-76SFO0515 with the Department of Energy.
+ *
+ * Government disclaimer of liability
+ * ----------------------------------
+ * Neither the United States nor the United States Department of Energy,
+ * nor any of their employees, makes any warranty, express or implied, or
+ * assumes any legal liability or responsibility for the accuracy,
+ * completeness, or usefulness of any data, apparatus, product, or process
+ * disclosed, or represents that its use would not infringe privately owned
+ * rights.
+ *
+ * Stanford disclaimer of liability
+ * --------------------------------
+ * Stanford University makes no representations or warranties, express or
+ * implied, nor assumes any liability for the use of this software.
+ *
+ * Stanford disclaimer of copyright
+ * --------------------------------
+ * Stanford University, owner of the copyright, hereby disclaims its
+ * copyright and all other rights in this software. Hence, anyone may
+ * freely use it for any purpose without restriction.
+ *
+ * Maintenance of notices
+ * ----------------------
+ * In the interest of clarity regarding the origin and status of this
+ * SLAC software, this and all the preceding Stanford University notices
+ * are to remain affixed to any copy or derivative of this software made
+ * or distributed by the recipient and are to be affixed to any copy of
+ * software made or distributed by the recipient that contains a copy or
+ * derivative of this software.
+ *
+ * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03
+ */
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+#include <rtems.h>
+#include <rtems/libi2c.h>
+
+/* for registration with libi2c */
+extern rtems_libi2c_bus_t *mpc8540_i2c_bus_descriptor;
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif
diff --git a/c/src/lib/libbsp/powerpc/mvme3100/include/bsp.h b/c/src/lib/libbsp/powerpc/mvme3100/include/bsp.h
new file mode 100644
index 0000000000..e36d307e59
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/mvme3100/include/bsp.h
@@ -0,0 +1,329 @@
+/*
+ * bsp.h -- contain BSP API definition.
+ *
+ * Copyright (C) 1999 Eric Valette. valette@crf.canon.fr
+ *
+ * The license and distribution terms for this file may be
+ * found in found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * Adapted for the mvme3100 BSP by T. Straumann, 2007.
+ *
+ * $Id$
+ */
+#ifndef _BSP_H
+#define _BSP_H
+
+#include <bspopts.h>
+
+#include <rtems.h>
+#include <rtems/console.h>
+#include <libcpu/io.h>
+#include <rtems/clockdrv.h>
+
+/*
+ * confdefs.h overrides for this BSP:
+ * - termios serial ports (defaults to 1)
+ * - Interrupt stack space is not minimum if defined.
+ */
+#define CONFIGURE_NUMBER_OF_TERMIOS_PORTS 2
+
+#define CONFIGURE_INTERRUPT_STACK_MEMORY (16 * 1024)
+
+/*
+ * diagram illustrating the role of the configuration
+ * constants
+ * PCI_MEM_WIN0: CPU starting addr where PCI memory space is visible
+ * PCI_MEM_BASE: CPU address of PCI mem addr. zero. (regardless of this
+ * address being 'visible' or not!).
+ * _VME_A32_WIN0_ON_PCI: PCI starting addr of the 1st window to VME
+ * _VME_A32_WIN0_ON_VME: VME address of that same window
+ *
+ * AFAIK, only PreP boards have a non-zero PCI_MEM_BASE (i.e., an offset between
+ * CPU and PCI addresses). The mvme2300 'ppcbug' firmware configures the PCI
+ * bus using PCI base addresses! I.e., drivers need to add PCI_MEM_BASE to
+ * the base address read from PCI config.space in order to translate that
+ * into a CPU address.
+ *
+ * NOTE: VME addresses should NEVER be translated using these constants!
+ * they are strictly for BSP internal use. Drivers etc. should use
+ * the translation routines int VME.h (BSP_vme2local_adrs/BSP_local2vme_adrs).
+ *
+ * CPU ADDR PCI_ADDR VME ADDR
+ *
+ * 00000000 XXXXXXXX XXXXXXXX
+ * ^ ^ ........
+ * | |
+ * | | e.g., RAM XXXXXXXX
+ * | | 00000000
+ * | | ......... ^
+ * | | (possible offset |
+ * | | between pci and XXXXXXXX | ......
+ * | | cpu addresses) |
+ * | v |
+ * | PCI_MEM_BASE -------------> 00000000 --------------- |
+ * | ........ ........ ^ |
+ * | invisible | |
+ * | ........ from CPU | |
+ * v | |
+ * PCI_MEM_WIN0 ============= first visible PCI addr | |
+ * | |
+ * pci devices pci window | |
+ * visible here v v
+ * mapped by ========== _VME_A32_WIN0_ON_PCI ======= _VME_A32_WIN0_ON_VME
+ * vme window
+ * VME devices hostbridge mapped by
+ * visible here universe
+ * =====================================================
+ *
+ */
+
+/* fundamental addresses for BSP (CHRPxxx and PREPxxx are from libcpu/io.h) */
+#define _IO_BASE 0xe0000000 /* Motload's PCI IO base */
+#define _ISA_MEM_BASE CHRP_ISA_MEM_BASE
+/* address of our ram on the PCI bus */
+#define PCI_DRAM_OFFSET CHRP_PCI_DRAM_OFFSET
+/* offset of pci memory as seen from the CPU */
+#define PCI_MEM_BASE 0
+/* where (in CPU addr. space) does the PCI window start */
+#define PCI_MEM_WIN0 0x80000000
+
+/*
+ * Base address definitions for several devices
+ */
+
+#define BSP_OPEN_PIC_BASE_OFFSET 0x40000
+#define BSP_OPEN_PIC_BIG_ENDIAN
+
+#define BSP_8540_CCSR_BASE (0xe1000000)
+
+#define BSP_UART_IOBASE_COM1 (BSP_8540_CCSR_BASE+0x4500)
+#define BSP_UART_IOBASE_COM2 (BSP_8540_CCSR_BASE+0x4600)
+#define PCI_CONFIG_ADDR (BSP_8540_CCSR_BASE+0x8000)
+#define PCI_CONFIG_DATA (BSP_8540_CCSR_BASE+0x8004)
+#define PCI_CONFIG_WR_ADDR( addr, val ) out_be32((unsigned int*)(addr), (val))
+
+#define BSP_CONSOLE_PORT BSP_UART_COM1
+#define BSP_UART_BAUD_BASE (-9600) /* use existing divisor to determine clock rate */
+#define BSP_UART_USE_SHARED_IRQS
+
+#define BSP_MVME3100_IRQ_DETECT_REG ((volatile uint8_t *)0xe2000007)
+
+/* I2C Devices */
+/* Note that the i2c addresses stated in the manual are
+ * left-shifted by one bit.
+ */
+#define BSP_VPD_I2C_ADDR (0xA8>>1) /* the VPD EEPROM */
+#define BSP_USR0_I2C_ADDR (0xA4>>1) /* the 1st user EEPROM */
+#define BSP_USR1_I2C_ADDR (0xA6>>1) /* the 2nd user EEPROM */
+#define BSP_THM_I2C_ADDR (0x90>>1) /* the DS1621 temperature sensor & thermostat */
+#define BSP_RTC_I2C_ADDR (0xD0>>1) /* the DS1375 wall-clock */
+
+#define BSP_I2C_BUS_DESCRIPTOR mpc8540_i2c_bus_descriptor
+
+#define BSP_I2C_BUS0_NAME "/dev/i2c0"
+
+#define BSP_I2C_VPD_EEPROM_NAME "vpd-eeprom"
+#define BSP_I2C_USR_EEPROM_NAME "usr-eeprom"
+#define BSP_I2C_USR1_EEPROM_NAME "usr1-eeprom"
+#define BSP_I2C_DS1621_NAME "ds1621"
+#define BSP_I2C_THM_NAME BSP_I2C_DS1621_NAME
+#define BSP_I2C_DS1621_RAW_NAME "ds1621-raw"
+#define BSP_I2C_DS1375_RAW_NAME "ds1375-raw"
+#define BSP_I2C_RTC_RAW_NAME BSP_I2C_DS1375_RAW_NAME
+
+#define BSP_I2C_VPD_EEPROM_DEV_NAME (BSP_I2C_BUS0_NAME"."BSP_I2C_VPD_EEPROM_NAME)
+#define BSP_I2C_USR_EEPROM_DEV_NAME (BSP_I2C_BUS0_NAME"."BSP_I2C_USR_EEPROM_NAME)
+#define BSP_I2C_USR1_EEPROM_DEV_NAME (BSP_I2C_BUS0_NAME"."BSP_I2C_USR1_EEPROM_NAME)
+#define BSP_I2C_DS1621_DEV_NAME (BSP_I2C_BUS0_NAME"."BSP_I2C_DS1621_NAME)
+#define BSP_I2C_THM_DEV_NAME BSP_I2C_DS1621_DEV_NAME
+#define BSP_I2C_DS1621_RAW_DEV_NAME (BSP_I2C_BUS0_NAME"."BSP_I2C_DS1621_RAW_NAME)
+#define BSP_I2C_DS1375_RAW_DEV_NAME (BSP_I2C_BUS0_NAME"."BSP_I2C_DS1375_RAW_NAME)
+
+/* Definitions useful for bootloader (netboot); where to find
+ * boot/'environment' parameters.
+ */
+#define BSP_EEPROM_BOOTPARMS_NAME BSP_I2C_USR1_EEPROM_DEV_NAME
+#define BSP_EEPROM_BOOTPARMS_SIZE 1024
+#define BSP_EEPROM_BOOTPARMS_OFFSET 0
+#define BSP_BOOTPARMS_WRITE_ENABLE() do { BSP_eeprom_write_enable(); } while (0)
+#define BSP_BOOTPARMS_WRITE_DISABLE() do { BSP_eeprom_write_protect();} while (0)
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+/* Initialize the I2C driver and register all devices
+ * RETURNS 0 on success, -1 on error.
+ *
+ * Access to the VPD and user EEPROMS as well
+ * as the ds1621 temperature sensor is possible
+ * by means of file nodes
+ *
+ * /dev/i2c0.vpd-eeprom (read-only)
+ * /dev/i2c0.usr-eeprom (read-write)
+ * /dev/i2c0.usr1-eeprom (read-write)
+ * /dev/i2c0.ds1621 (read-only; one byte: board-temp in degC)
+ * /dev/i2c0.ds1621-raw (read-write; transfer bytes to/from the ds1621)
+ * /dev/i2c0.ds1375-raw (read-write; transfer bytes to/from the ds1375)
+ *
+ */
+int
+BSP_i2c_initialize();
+
+/* Misc utility definitions and routines */
+
+void
+rtemsReboot();
+
+/* System Control Register */
+#define BSP_MVME3100_SYS_CR ((volatile uint8_t *)0xe2000001)
+#define BSP_MVME3100_SYS_CR_RESET_MSK (7<<5)
+#define BSP_MVME3100_SYS_CR_RESET (5<<5)
+#define BSP_MVME3100_SYS_CR_EEPROM_WP (1<<1)
+#define BSP_MVME3100_SYS_CR_TSTAT_MSK (1<<0)
+
+/* LED support */
+#define BSP_MVME3100_SYS_IND_REG ((volatile uint8_t *)0xe2000002)
+#define BSP_LED_BRD_FAIL (1<<0)
+#define BSP_LED_USR1 (1<<1)
+#define BSP_LED_USR2 (1<<2)
+#define BSP_LED_USR3 (1<<3)
+
+/* Flash CSR */
+#define BSP_MVME3100_FLASH_CSR ((volatile uint8_t *)0xe2000003)
+#define BSP_MVME3100_FLASH_CSR_FLASH_RDY (1<<0)
+#define BSP_MVME3100_FLASH_CSR_FBT_BLK_SEL (1<<1)
+#define BSP_MVME3100_FLASH_CSR_F_WP_HW (1<<2)
+#define BSP_MVME3100_FLASH_CSR_F_WP_SW (1<<3)
+#define BSP_MVME3100_FLASH_CSR_MAP_SEL (1<<4)
+
+/* Phy interrupt detect */
+#define BSP_MVME3100_IRQ_DETECT_REG ((volatile uint8_t *)0xe2000007)
+
+/* Atomically set bits in a sys-register; The bits set in 'mask'
+ * are set in the register others; are left unmodified.
+ *
+ * RETURNS: old state.
+ *
+ * NOTE : since BSP_setSysReg( reg, 0 ) does not make
+ * any changes this call may be used
+ * to read the current status w/o modifying it.
+ */
+uint8_t
+BSP_setSysReg(volatile uint8_t *r, uint8_t mask);
+
+/* Atomically clear bits in a sys-register; The bits set in 'mask'
+ * are cleared in the register; others are left unmodified.
+ *
+ * RETURNS: old state.
+ *
+ * NOTE : since BSP_clrSysReg( reg, 0 ) does not make
+ * any changes this call may be used
+ * to read the current status w/o modifying it.
+ */
+
+uint8_t
+BSP_clrSysReg(volatile uint8_t *r, uint8_t mask);
+
+/* Convenience wrappers around BSP_setSysReg()/BSP_clrSysReg() */
+
+/* Set write-protection for all EEPROM devices
+ * RETURNS: old status
+ */
+uint8_t
+BSP_eeprom_write_protect();
+
+/* Disengage write-protection for all EEPROM devices
+ * RETURNS: old status
+ */
+uint8_t
+BSP_eeprom_write_enable();
+
+/* Set LEDs that have their bit set in the mask
+ *
+ * RETURNS: old status.
+ *
+ * NOTE : since BSP_setLEDs( 0 ) does not make
+ * any changes this call may be used
+ * to read the current status w/o modifying it.
+ */
+uint8_t
+BSP_setLEDs(uint8_t mask);
+
+/* Clear LEDs that have their bit set in the mask
+ *
+ * RETURNS: old status
+ *
+ * NOTE: : see above (BSP_setLEDs)
+ */
+uint8_t
+BSP_clrLEDs(uint8_t mask);
+
+#if 0
+#define outport_byte(port,value) outb(value,port)
+#define outport_word(port,value) outw(value,port)
+#define outport_long(port,value) outl(value,port)
+
+#define inport_byte(port,value) (value = inb(port))
+#define inport_word(port,value) (value = inw(port))
+#define inport_long(port,value) (value = inl(port))
+#endif
+
+/*
+ * Total memory using RESIDUAL DATA
+ */
+extern unsigned int BSP_mem_size;
+/*
+ * Start of the heap
+ */
+extern unsigned int BSP_heap_start;
+/*
+ * PCI Bus Frequency
+ */
+extern unsigned int BSP_bus_frequency;
+/*
+ * processor clock frequency
+ */
+extern unsigned int BSP_processor_frequency;
+/*
+ * Time base divisior (how many tick for 1 second).
+ */
+extern unsigned int BSP_time_base_divisor;
+
+#define BSP_Convert_decrementer( _value ) \
+ ((unsigned long long) ((((unsigned long long)BSP_time_base_divisor) * 1000000ULL) /((unsigned long long) BSP_bus_frequency)) * ((unsigned long long) (_value)))
+
+extern rtems_configuration_table BSP_Configuration;
+extern void BSP_panic(char *s);
+extern void rtemsReboot(void);
+/* extern int printk(const char *, ...) __attribute__((format(printf, 1, 2))); */
+extern int BSP_disconnect_clock_handler (void);
+extern int BSP_connect_clock_handler (void);
+
+/* clear hostbridge errors
+ *
+ * NOTE: The routine returns always (-1) if 'enableMCP==1'
+ * [semantics needed by libbspExt] if the MCP input is not wired.
+ * It returns and clears the error bits of the PCI status register.
+ * MCP support is disabled because:
+ * a) the 2100 has no raven chip
+ * b) the raven (2300) would raise machine check interrupts
+ * on PCI config space access to empty slots.
+ */
+extern unsigned long _BSP_clear_hostbridge_errors(int enableMCP, int quiet);
+extern void BSP_motload_pci_fixup();
+
+struct rtems_bsdnet_ifconfig;
+
+int
+rtems_tsec_attach(struct rtems_bsdnet_ifconfig *ifcfg, int attaching);
+
+#define RTEMS_BSP_NETWORK_DRIVER_NAME "tse1"
+#define RTEMS_BSP_NETWORK_DRIVER_ATTACH rtems_tsec_attach
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/c/src/lib/libbsp/powerpc/mvme3100/include/bspopts.h.in b/c/src/lib/libbsp/powerpc/mvme3100/include/bspopts.h.in
new file mode 100644
index 0000000000..2678efef45
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/mvme3100/include/bspopts.h.in
@@ -0,0 +1,23 @@
+/* include/bspopts.h.in. Generated from configure.ac by autoheader. */
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* If defined, then the PowerPC specific code in RTEMS will use data cache
+ instructions to optimize the context switch code. This code can conflict
+ with debuggers or emulators. It is known to break the Corelis PowerPC
+ emulator with at least some combinations of PowerPC 603e revisions and
+ emulator versions. The BSP actually contains the call that enables this. */
+#undef PPC_USE_DATA_CACHE
diff --git a/c/src/lib/libbsp/powerpc/mvme3100/irq/irq.h b/c/src/lib/libbsp/powerpc/mvme3100/irq/irq.h
new file mode 100644
index 0000000000..d7002527e9
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/mvme3100/irq/irq.h
@@ -0,0 +1,126 @@
+/* irq.h
+ *
+ * This include file describe the data structure and the functions implemented
+ * by RTEMS to write interrupt handlers.
+ *
+ * Copyright (C) 1999 valette@crf.canon.fr
+ *
+ * This code is heavilly inspired by the public specification of STREAM V2
+ * that can be found at :
+ *
+ * <http://www.chorus.com/Documentation/index.html> by following
+ * the STREAM API Specification Document link.
+ *
+ * The license and distribution terms for this file may be
+ * found in found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * Adapted for the mvme3100 BSP by T. Straumann, 2007.
+ *
+ * $Id$
+ */
+
+#ifndef BSP_POWERPC_IRQ_H
+#define BSP_POWERPC_IRQ_H
+
+#define BSP_SHARED_HANDLER_SUPPORT 1
+#include <rtems/irq.h>
+
+#ifndef ASM
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * rtems_irq_number Definitions
+ */
+
+/* Must pad number of external sources to 16 because
+ * of the layout of vector/priority registers in the
+ * 8540's openpic where there is a gap between
+ * registers corresponding to external and core sources.
+ */
+#define BSP_EXT_IRQ_NUMBER (16)
+#define BSP_CORE_IRQ_NUMBER (32)
+
+/* openpic glue code from shared/irq assigns priorities and configures
+ * initial ISRs for BSP_PCI_IRQ_NUMBER entries (plus ISA stuff on legacy
+ * boards). Hence PCI_IRQ_NUMBER must also cover the internal sources
+ * even though they have nothing to do with PCI.
+ */
+#define BSP_PCI_IRQ_NUMBER (BSP_EXT_IRQ_NUMBER + BSP_CORE_IRQ_NUMBER)
+#define BSP_PCI_IRQ_LOWEST_OFFSET (0)
+#define BSP_PCI_IRQ_MAX_OFFSET (BSP_PCI_IRQ_LOWEST_OFFSET + BSP_PCI_IRQ_NUMBER - 1)
+
+#define BSP_CORE_IRQ_LOWEST_OFFSET (BSP_PCI_IRQ_LOWEST_OFFSET + BSP_EXT_IRQ_NUMBER)
+#define BSP_CORE_IRQ_MAX_OFFSET (BSP_CORE_IRQ_LOWEST_OFFSET + BSP_CORE_IRQ_NUMBER - 1)
+
+/*
+ * PowerPC exceptions handled as interrupt where an RTEMS managed interrupt
+ * handler might be connected
+ */
+#define BSP_PROCESSOR_IRQ_NUMBER (1)
+#define BSP_PROCESSOR_IRQ_LOWEST_OFFSET (BSP_CORE_IRQ_MAX_OFFSET + 1)
+#define BSP_PROCESSOR_IRQ_MAX_OFFSET (BSP_PROCESSOR_IRQ_LOWEST_OFFSET + BSP_PROCESSOR_IRQ_NUMBER - 1)
+/* Misc vectors for OPENPIC irqs (IPI, timers)
+ */
+#define BSP_MISC_IRQ_NUMBER (8)
+#define BSP_MISC_IRQ_LOWEST_OFFSET (BSP_PROCESSOR_IRQ_MAX_OFFSET + 1)
+#define BSP_MISC_IRQ_MAX_OFFSET (BSP_MISC_IRQ_LOWEST_OFFSET + BSP_MISC_IRQ_NUMBER - 1)
+/*
+ * Summary
+ */
+#define BSP_IRQ_NUMBER (BSP_MISC_IRQ_MAX_OFFSET + 1)
+#define BSP_LOWEST_OFFSET (BSP_PCI_IRQ_LOWEST_OFFSET)
+#define BSP_MAX_OFFSET (BSP_MISC_IRQ_MAX_OFFSET)
+
+/*
+ * Some PCI IRQ symbolic name definition
+ */
+#define BSP_PCI_IRQ0 (BSP_PCI_IRQ_LOWEST_OFFSET)
+
+#define BSP_VME0_IRQ (BSP_PCI_IRQ_LOWEST_OFFSET + 0)
+#define BSP_VME1_IRQ (BSP_PCI_IRQ_LOWEST_OFFSET + 1)
+#define BSP_VME2_IRQ (BSP_PCI_IRQ_LOWEST_OFFSET + 2)
+#define BSP_VME3_IRQ (BSP_PCI_IRQ_LOWEST_OFFSET + 3)
+
+#define BSP_ABORT_IRQ (BSP_PCI_IRQ_LOWEST_OFFSET + 8)
+#define BSP_TEMP_IRQ (BSP_PCI_IRQ_LOWEST_OFFSET + 9)
+#define BSP_PHY_IRQ (BSP_PCI_IRQ_LOWEST_OFFSET + 10)
+#define BSP_RTC_IRQ (BSP_PCI_IRQ_LOWEST_OFFSET + 11)
+
+/* Weird - they provide 3 different IRQ lines per ethernet controller
+ * but only one shared line for 2 UARTs ???
+ */
+#define BSP_UART_COM1_IRQ (BSP_CORE_IRQ_LOWEST_OFFSET + 26)
+#define BSP_UART_COM2_IRQ (BSP_CORE_IRQ_LOWEST_OFFSET + 26)
+#define BSP_I2C_IRQ (BSP_CORE_IRQ_LOWEST_OFFSET + 27)
+
+/*
+ * Some internal (CORE) name definitions
+ */
+/* Ethernet (FEC) */
+#define BSP_CORE_IRQ_FEC (BSP_CORE_IRQ_LOWEST_OFFSET + 25)
+/* i2c controller */
+#define BSP_CORE_IRQ_I2C (BSP_CORE_IRQ_LOWEST_OFFSET + 27)
+
+/*
+ * Some Processor execption handled as RTEMS IRQ symbolic name definition
+ */
+#define BSP_DECREMENTER (BSP_PROCESSOR_IRQ_LOWEST_OFFSET)
+
+/*-------------------------------------------------------------------------+
+| Function Prototypes.
++--------------------------------------------------------------------------*/
+
+extern void BSP_rtems_irq_mng_init(unsigned cpuId);
+
+#include <bsp/irq_supp.h>
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif
+#endif
diff --git a/c/src/lib/libbsp/powerpc/mvme3100/irq/irq_init.c b/c/src/lib/libbsp/powerpc/mvme3100/irq/irq_init.c
new file mode 100644
index 0000000000..9b474899b7
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/mvme3100/irq/irq_init.c
@@ -0,0 +1,140 @@
+/* irq_init.c
+ *
+ * This file contains the implementation of rtems initialization
+ * related to interrupt handling.
+ *
+ * CopyRight (C) 1999 valette@crf.canon.fr
+ *
+ * Enhanced by Jay Kulpinski <jskulpin@eng01.gdds.com>
+ * to make it valid for MVME2300 Motorola boards.
+ *
+ * Till Straumann <strauman@slac.stanford.edu>, 12/20/2001:
+ * Use the new interface to openpic_init
+ *
+ * Adapted for the mvme3100 BSP by T. Straumann, 2007.
+ *
+ * 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.
+ *
+ * $Id$
+ */
+
+#include <libcpu/io.h>
+#include <bsp/pci.h>
+#include <bsp/openpic.h>
+#include <bsp/irq.h>
+#include <bsp.h>
+#include <libcpu/raw_exception.h>
+#include <rtems/bspIo.h>
+
+static void nop_func()
+{
+ printk("Unhandled IRQ\n");
+}
+
+static rtems_irq_connect_data rtemsIrq[BSP_IRQ_NUMBER];
+static rtems_irq_global_settings initial_config;
+static rtems_irq_connect_data defaultIrq = {
+ /* vectorIdex, hdl , handle , on , off , isOn */
+ 0, nop_func , NULL , 0 , 0 , 0
+};
+
+static rtems_irq_prio irqPrioTable[BSP_IRQ_NUMBER]={
+ /*
+ * actual priorities for interrupt :
+ * 0 means that only current interrupt is masked
+ * 255 means all other interrupts are masked
+ */
+ /*
+ * PCI Interrupts
+ */
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, /* for raven prio 0 means unactive... */
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, /* for raven prio 0 means unactive... */
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, /* for raven prio 0 means unactive... */
+ /*
+ * Processor exceptions handled as interrupts
+ */
+ 0
+};
+
+ /*
+ * This code assumes the exceptions management setup has already
+ * been done. We just need to replace the exceptions that will
+ * be handled like interrupt. On mcp750/mpc750 and many PPC processors
+ * this means the decrementer exception and the external exception.
+ */
+void BSP_rtems_irq_mng_init(unsigned cpuId)
+{
+ /* We should really have a way to find the number of sources
+ * the driver will use so that the size of the polarity-array
+ * matches the driver's idea of it.
+ */
+ unsigned char pol[56];
+ int i;
+
+ /* Note: The openpic driver initializes only as many
+ * 'pic-external' interrupt sources as reported
+ * by the feature register.
+ * The 8540's openpic supports 12 core-external
+ * and 23 core-internal (both of these groups
+ * are external to the PIC, i.e., 'pic-external')
+ * interrupts but between the corresponding
+ * banks of vector/priority registers there is
+ * a gap leaving space for 4 (unsupported) irqs.
+ * The driver, not knowing of this gap, would
+ * initialize the 12 core-external sources
+ * followed by 4 unsupported sources and 19
+ * core-internal sources thus leaving the last
+ * four core-internal sources uninitialized.
+ * Luckily, the feature register reports
+ * too many sources:
+ * - the 4 IPI plus 4 timer plus 4 messaging
+ * sources are included with the count
+ * - there are unused core-internal sources 24..32
+ * which are also supported by the pic
+ * bringing the reported number of sources to
+ * a count of 56 (12+32+4+4+4) which is enough
+ * so that all pic-external sources are covered
+ * and initialized.
+ *
+ * NOTE: All core-internal sources are active-high.
+ * The manual says that setting the polarity
+ * to 'low/0' will disable the interrupt but
+ * I found this not to be true: on the device
+ * I tested the interrupt was asserted hard.
+ */
+
+ /* core-external sources on the mvme3100 are active-low,
+ * core-internal sources are active high.
+ */
+ for (i=0; i<BSP_EXT_IRQ_NUMBER; i++)
+ pol[i]=0;
+ for (i=BSP_EXT_IRQ_NUMBER; i< BSP_EXT_IRQ_NUMBER + BSP_CORE_IRQ_NUMBER; i++)
+ pol[i]=1;
+
+ openpic_init(1, pol, 0, 0, 0, 0);
+
+ /*
+ * re-init the rtemsIrq table
+ */
+ for (i = 0; i < BSP_IRQ_NUMBER; i++) {
+ rtemsIrq[i] = defaultIrq;
+ rtemsIrq[i].name = i;
+ }
+ /*
+ * Init initial Interrupt management config
+ */
+ initial_config.irqNb = BSP_IRQ_NUMBER;
+ initial_config.defaultEntry = defaultIrq;
+ initial_config.irqHdlTbl = rtemsIrq;
+ initial_config.irqBase = BSP_LOWEST_OFFSET;
+ initial_config.irqPrioTbl = irqPrioTable;
+
+ if (!BSP_rtems_irq_mngt_set(&initial_config)) {
+ /*
+ * put something here that will show the failure...
+ */
+ BSP_panic("Unable to initialize RTEMS interrupt Management!!! System locked\n");
+ }
+}
diff --git a/c/src/lib/libbsp/powerpc/mvme3100/network/if_tsec_pub.h b/c/src/lib/libbsp/powerpc/mvme3100/network/if_tsec_pub.h
new file mode 100644
index 0000000000..da3f2bc1a7
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/mvme3100/network/if_tsec_pub.h
@@ -0,0 +1,346 @@
+#ifndef IF_TSEC_PUBLIC_INTERFACE_H
+#define IF_TSEC_PUBLIC_INTERFACE_H
+
+/*
+ * Authorship
+ * ----------
+ * This software ('mvme3100' RTEMS BSP) was created by
+ *
+ * Till Straumann <strauman@slac.stanford.edu>, 2005-2007,
+ * Stanford Linear Accelerator Center, Stanford University.
+ *
+ * Acknowledgement of sponsorship
+ * ------------------------------
+ * The 'mvme3100' BSP was produced by
+ * the Stanford Linear Accelerator Center, Stanford University,
+ * under Contract DE-AC03-76SFO0515 with the Department of Energy.
+ *
+ * Government disclaimer of liability
+ * ----------------------------------
+ * Neither the United States nor the United States Department of Energy,
+ * nor any of their employees, makes any warranty, express or implied, or
+ * assumes any legal liability or responsibility for the accuracy,
+ * completeness, or usefulness of any data, apparatus, product, or process
+ * disclosed, or represents that its use would not infringe privately owned
+ * rights.
+ *
+ * Stanford disclaimer of liability
+ * --------------------------------
+ * Stanford University makes no representations or warranties, express or
+ * implied, nor assumes any liability for the use of this software.
+ *
+ * Stanford disclaimer of copyright
+ * --------------------------------
+ * Stanford University, owner of the copyright, hereby disclaims its
+ * copyright and all other rights in this software. Hence, anyone may
+ * freely use it for any purpose without restriction.
+ *
+ * Maintenance of notices
+ * ----------------------
+ * In the interest of clarity regarding the origin and status of this
+ * SLAC software, this and all the preceding Stanford University notices
+ * are to remain affixed to any copy or derivative of this software made
+ * or distributed by the recipient and are to be affixed to any copy of
+ * software made or distributed by the recipient that contains a copy or
+ * derivative of this software.
+ *
+ * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03
+ */
+
+#include <rtems.h>
+#include <stdio.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Opaque driver handle */
+struct tsec_private;
+
+/********** Low-level Driver API ****************/
+
+/*
+ * This API provides driver access to applications that
+ * want to use e.g., the second ethernet interface
+ * independently from the BSD TCP/IP stack. E.g., for
+ * raw ethernet packet communication...
+ */
+
+/*
+ * Setup an interface.
+ * Allocates resources for descriptor rings and sets up the driver software structure.
+ *
+ * Arguments:
+ * unit:
+ * interface # (1..2). The interface must not be attached to BSD already.
+ *
+ * driver_tid:
+ * ISR posts RTEMS event # ('unit' - 1) to task with ID 'driver_tid' and disables interrupts
+ * from this interface.
+ *
+ * void (*cleanup_txbuf)(void *user_buf, void *cleanup_txbuf_arg, int error_on_tx_occurred):
+ * Pointer to user-supplied callback to release a buffer that had been sent
+ * by BSP_tsec_send_buf() earlier. The callback is passed 'cleanup_txbuf_arg'
+ * and a flag indicating whether the send had been successful.
+ * The driver no longer accesses 'user_buf' after invoking this callback.
+ * CONTEXT: This callback is executed either by BSP_tsec_swipe_tx() or
+ * BSP_tsec_send_buf(), BSP_tsec_init_hw(), BSP_tsec_stop_hw() (the latter
+ * ones calling BSP_tsec_swipe_tx()).
+ * void *cleanup_txbuf_arg:
+ * Closure argument that is passed on to 'cleanup_txbuf()' callback;
+ *
+ * void *(*alloc_rxbuf)(int *p_size, uintptr_t *p_data_addr),
+ * Pointer to user-supplied callback to allocate a buffer for subsequent
+ * insertion into the RX ring by the driver.
+ * RETURNS: opaque handle to the buffer (which may be a more complex object
+ * such as an 'mbuf'). The handle is not used by the driver directly
+ * but passed back to the 'consume_rxbuf()' callback.
+ * Size of the available data area and pointer to buffer's data area
+ * in '*psize' and '*p_data_area', respectively.
+ * If no buffer is available, this routine should return NULL in which
+ * case the driver drops the last packet and re-uses the last buffer
+ * instead of handing it out to 'consume_rxbuf()'.
+ * CONTEXT: Called when initializing the RX ring (BSP_tsec_init_hw()) or when
+ * swiping it (BSP_tsec_swipe_rx()).
+ *
+ *
+ * void (*consume_rxbuf)(void *user_buf, void *consume_rxbuf_arg, int len);
+ * Pointer to user-supplied callback to pass a received buffer back to
+ * the user. The driver no longer accesses the buffer after invoking this
+ * callback (with 'len'>0, see below). 'user_buf' is the buffer handle
+ * previously generated by 'alloc_rxbuf()'.
+ * The callback is passed 'cleanup_rxbuf_arg' and a 'len'
+ * argument giving the number of bytes that were received.
+ * 'len' may be <=0 in which case the 'user_buf' argument is NULL.
+ * 'len' == 0 means that the last 'alloc_rxbuf()' had failed,
+ * 'len' < 0 indicates a receiver error. In both cases, the last packet
+ * was dropped/missed and the last buffer will be re-used by the driver.
+ * NOTE: the data are 'prefixed' with two bytes, i.e., the ethernet packet header
+ * is stored at offset 2 in the buffer's data area. Also, the FCS (4 bytes)
+ * is appended. 'len' accounts for both.
+ * CONTEXT: Called from BSP_tsec_swipe_rx().
+ * void *cleanup_rxbuf_arg:
+ * Closure argument that is passed on to 'consume_rxbuf()' callback;
+ *
+ * rx_ring_size, tx_ring_size:
+ * How many big to make the RX and TX descriptor rings. Note that the sizes
+ * may be 0 in which case a reasonable default will be used.
+ * If either ring size is < 0 then the RX or TX will be disabled.
+ * Note that it is illegal in this case to use BSP_tsec_swipe_rx() or
+ * BSP_tsec_swipe_tx(), respectively.
+ *
+ * irq_mask:
+ * Interrupts to enable. OR of flags from above.
+ *
+ */
+struct tsec_private *
+BSP_tsec_setup(
+ int unit,
+ rtems_id driver_tid,
+ void (*cleanup_txbuf)(void *user_buf, void *cleanup_txbuf_arg, int error_on_tx_occurred),
+ void *cleanup_txbuf_arg,
+ void *(*alloc_rxbuf)(int *p_size, uintptr_t *p_data_addr),
+ void (*consume_rxbuf)(void *user_buf, void *consume_rxbuf_arg, int len),
+ void *consume_rxbuf_arg,
+ int rx_ring_size,
+ int tx_ring_size,
+ int irq_mask
+);
+
+/*
+ * Descriptor scavenger; cleanup the TX ring, passing all buffers
+ * that have been sent to the cleanup_tx() callback.
+ * This routine is called from BSP_tsec_send_buf(), BSP_tsec_init_hw(),
+ * BSP_tsec_stop_hw().
+ *
+ * RETURNS: number of buffers processed.
+ */
+
+int
+BSP_tsec_swipe_tx(struct tsec_private *mp);
+
+
+/*
+ * Reset statistics counters.
+ */
+void
+BSP_tsec_reset_stats(struct tsec_private *mp);
+
+/*
+ * Initialize interface hardware
+ *
+ * 'mp' handle obtained by from BSP_tsec_setup().
+ * 'promisc' whether to set promiscuous flag.
+ * 'enaddr' pointer to six bytes with MAC address. Read
+ * from the device if NULL.
+ */
+void
+BSP_tsec_init_hw(struct tsec_private *mp, int promisc, unsigned char *enaddr);
+
+/*
+ * Dump statistics to FILE 'f'. If NULL, stdout is used.
+ */
+void
+BSP_tsec_dump_stats(struct tsec_private *mp, FILE *f);
+
+/*
+ * Shutdown hardware and clean out the rings
+ */
+void
+BSP_tsec_stop_hw(struct tsec_private *mp);
+
+/*
+ * calls BSP_tsec_stop_hw(), releases all resources and marks the interface
+ * as unused.
+ * RETURNS 0 on success, nonzero on failure.
+ * NOTE: the handle MUST NOT be used after successful execution of this
+ * routine.
+ */
+int
+BSP_tsec_detach(struct tsec_private *mp);
+
+/*
+ * Enqueue a mbuf chain or a raw data buffer for transmission;
+ * RETURN: #bytes sent or -1 if there are not enough free descriptors
+ *
+ * If 'len' is <=0 then 'm_head' is assumed to point to a mbuf chain.
+ * OTOH, a raw data packet (or a different type of buffer)
+ * may be sent (non-BSD driver) by pointing data_p to the start of
+ * the data and passing 'len' > 0.
+ * 'm_head' is passed back to the 'cleanup_txbuf()' callback.
+ *
+ * Comments: software cache-flushing incurs a penalty if the
+ * packet cannot be queued since it is flushed anyways.
+ * The algorithm is slightly more efficient in the normal
+ * case, though.
+ *
+ * RETURNS: # bytes enqueued to device for transmission or -1 if no
+ * space in the TX ring was available.
+ */
+
+int
+BSP_tsec_send_buf(struct tsec_private *mp, void *m_head, void *data_p, int len);
+
+/*
+ * Retrieve all received buffers from the RX ring, replacing them
+ * by fresh ones (obtained from the alloc_rxbuf() callback). The
+ * received buffers are passed to consume_rxbuf().
+ *
+ * RETURNS: number of buffers processed.
+ */
+int
+BSP_tsec_swipe_rx(struct tsec_private *mp);
+
+/* read ethernet address from hw to buffer */
+void
+BSP_tsec_read_eaddr(struct tsec_private *mp, unsigned char *eaddr);
+
+/* Read MII register */
+uint32_t
+BSP_tsec_mdio_rd(struct tsec_private *mp, unsigned reg);
+
+/* Write MII register */
+int
+BSP_tsec_mdio_wr(struct tsec_private *mp, unsigned reg, uint32_t val);
+
+/*
+ * read/write media word.
+ * 'cmd': can be SIOCGIFMEDIA, SIOCSIFMEDIA, 0 or 1. The latter
+ * are aliased to the former for convenience.
+ * 'parg': pointer to media word.
+ *
+ * RETURNS: 0 on success, nonzero on error
+ */
+int
+BSP_tsec_media_ioctl(struct tsec_private *mp, int cmd, int *parg);
+
+/* Interrupt related routines */
+
+/*
+ * When it comes to interrupts the chip has two rather
+ * annoying features:
+ * 1 once an IRQ is pending, clearing the IMASK does not
+ * de-assert the interrupt line.
+ * 2 the chip has three physical interrupt lines even though
+ * all events are reported in a single register. Rather
+ * useless; we must hook 3 ISRs w/o any real benefit.
+ * In fact, it makes our life a bit more difficult:
+ *
+ * Hence, for (1) we would have to mask interrupts at the PIC
+ * but to re-enable them we would have to do that three times
+ * because of (2).
+ *
+ * Therefore, we take the following approach:
+ *
+ * ISR masks all interrupts on the TSEC, acks/clears them
+ * and stores the acked irqs in the device struct where
+ * it is picked up by BSP_tsec_ack_irqs().
+ * Since all interrupts are disabled until the daemon
+ * re-enables them after calling BSP_tsec_ack_irqs()
+ * no interrupts are lost.
+ *
+ * BUT: NO isr (including PHY isrs) MUST INTERRUPT ANY
+ * OTHER ONE, i.e., they all must have the same
+ * priority. Otherwise, integrity of the cached
+ * irq_pending variable may be compromised.
+ */
+
+/* Enable interrupts at device */
+void
+BSP_tsec_enable_irqs(struct tsec_private *mp);
+
+/* Disable interrupts at device */
+void
+BSP_tsec_disable_irqs(struct tsec_private *mp);
+
+/*
+ * Acknowledge (and clear) interrupts.
+ * RETURNS: interrupts that were raised.
+ */
+uint32_t
+BSP_tsec_ack_irqs(struct tsec_private *mp);
+
+/* Retrieve the driver daemon TID that was passed to
+ * BSP_tsec_setup().
+ */
+
+rtems_id
+BSP_tsec_get_tid(struct tsec_private *mp);
+
+struct tsec_private *
+BSP_tsec_getp(unsigned index);
+
+/*
+ *
+ * Example driver task loop (note: no synchronization of
+ * buffer access shown!).
+ * RTEMS_EVENTx = 0,1 or 2 depending on IF unit.
+ *
+ * / * setup (obtain handle) and initialize hw here * /
+ *
+ * do {
+ * / * ISR disables IRQs and posts event * /
+ * rtems_event_receive( RTEMS_EVENTx, RTEMS_WAIT | RTEMS_EVENT_ANY, RTEMS_NO_TIMEOUT, &evs );
+ * irqs = BSP_tsec_ack_irqs(handle);
+ * if ( irqs & BSP_TSEC_IRQ_TX ) {
+ * BSP_tsec_swipe_tx(handle); / * cleanup_txbuf() callback executed * /
+ * }
+ * if ( irqs & BSP_TSEC_IRQ_RX ) {
+ * BSP_tsec_swipe_rx(handle); / * alloc_rxbuf() and consume_rxbuf() executed * /
+ * }
+ * BSP_tsec_enable_irqs(handle);
+ * } while (1);
+ *
+ */
+
+/* PUBLIC RTEMS BSDNET ATTACH FUNCTION */
+struct rtems_bsdnet_ifconfig;
+
+int
+rtems_tsec_attach(struct rtems_bsdnet_ifconfig *ifcfg, int attaching);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/c/src/lib/libbsp/powerpc/mvme3100/network/tsec.c b/c/src/lib/libbsp/powerpc/mvme3100/network/tsec.c
new file mode 100644
index 0000000000..ffff01c850
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/mvme3100/network/tsec.c
@@ -0,0 +1,2920 @@
+/*
+ * Authorship
+ * ----------
+ * This software ('mvme3100' RTEMS BSP) was created by
+ *
+ * Till Straumann <strauman@slac.stanford.edu>, 2005-2007,
+ * Stanford Linear Accelerator Center, Stanford University.
+ *
+ * Acknowledgement of sponsorship
+ * ------------------------------
+ * The 'mvme3100' BSP was produced by
+ * the Stanford Linear Accelerator Center, Stanford University,
+ * under Contract DE-AC03-76SFO0515 with the Department of Energy.
+ *
+ * Government disclaimer of liability
+ * ----------------------------------
+ * Neither the United States nor the United States Department of Energy,
+ * nor any of their employees, makes any warranty, express or implied, or
+ * assumes any legal liability or responsibility for the accuracy,
+ * completeness, or usefulness of any data, apparatus, product, or process
+ * disclosed, or represents that its use would not infringe privately owned
+ * rights.
+ *
+ * Stanford disclaimer of liability
+ * --------------------------------
+ * Stanford University makes no representations or warranties, express or
+ * implied, nor assumes any liability for the use of this software.
+ *
+ * Stanford disclaimer of copyright
+ * --------------------------------
+ * Stanford University, owner of the copyright, hereby disclaims its
+ * copyright and all other rights in this software. Hence, anyone may
+ * freely use it for any purpose without restriction.
+ *
+ * Maintenance of notices
+ * ----------------------
+ * In the interest of clarity regarding the origin and status of this
+ * SLAC software, this and all the preceding Stanford University notices
+ * are to remain affixed to any copy or derivative of this software made
+ * or distributed by the recipient and are to be affixed to any copy of
+ * software made or distributed by the recipient that contains a copy or
+ * derivative of this software.
+ *
+ * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03
+ */
+
+#include <rtems.h>
+#include <rtems/error.h>
+#include <bsp/irq.h>
+#include <libcpu/byteorder.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <assert.h>
+#include <bsp.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 <rtems/rtems_mii_ioctl.h>
+
+#include <bsp/if_tsec_pub.h>
+
+#define STATIC
+#define PARANOIA
+#undef DEBUG
+
+
+#ifdef TEST_MII_TIMING
+
+#include <libcpu/spr.h>
+
+SPR_RO(TBRL)
+
+static inline uint32_t tb_rd()
+{
+ return _read_TBRL();
+}
+#endif
+
+struct tsec_private;
+
+/* Forward declarations */
+static void
+phy_init_irq( int install, struct tsec_private *mp, void (*tsec_lisr)(rtems_irq_hdl_param) );
+
+static void
+phy_en_irq(struct tsec_private *mp);
+
+static void
+phy_en_irq_at_phy(struct tsec_private *mp);
+
+static void
+phy_dis_irq(struct tsec_private *mp);
+
+static void
+phy_dis_irq_at_phy(struct tsec_private *mp);
+
+static int
+phy_irq_pending(struct tsec_private *mp);
+
+static uint32_t
+phy_ack_irq(struct tsec_private *mp);
+
+#if defined(PARANOIA) || defined(DEBUG)
+void tsec_dump_tring(struct tsec_private *mp);
+void tsec_dump_rring(struct tsec_private *mp);
+#endif
+
+#ifdef DEBUG
+#ifdef TSEC_RX_RING_SIZE
+#undef TSEC_RX_RING_SIZE
+#endif
+#define TSEC_RX_RING_SIZE 4
+
+#ifdef TSEC_TX_RING_SIZE
+#undef TSEC_TX_RING_SIZE
+#endif
+#define TSEC_TX_RING_SIZE 2
+#else
+#ifndef TSEC_RX_RING_SIZE
+#define TSEC_RX_RING_SIZE 40
+#endif
+#ifndef TSEC_TX_RING_SIZE
+#define TSEC_TX_RING_SIZE 200
+#endif
+#endif
+
+/********** Helper Macros and Definitions ******/
+
+/*
+ * 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))
+
+
+/*
+ * Not obvious from the doc: RX buffers apparently must be 32-byte
+ * aligned :-(; TX buffers have no alignment requirement.
+ * I found this by testing, T.S, 11/2007
+ */
+#define RX_BUF_ALIGNMENT 32
+
+/*
+ * Alignment req. for buffer descriptors (BDs)
+ */
+#define BD_ALIGNMENT 8
+
+
+#define ETH_RX_OFFSET 0
+#define ETH_CRC_LEN 0
+
+#define CPU2BUS_ADDR(x) (x)
+#define BUS2CPU_ADDR(x) (x)
+
+/*
+ * Whether to automatically try to reclaim descriptors
+ * when enqueueing new packets
+ */
+#if 1
+#define TSEC_CLEAN_ON_SEND(mp) (BSP_tsec_swipe_tx(mp))
+#else
+#define TSEC_CLEAN_ON_SEND(mp) (-1)
+#endif
+
+#define TX_AVAILABLE_RING_SIZE(mp) (mp)->tx_ring_size
+
+#define DRVNAME "tsec"
+
+/*
+ * Event(s) posted by ISRs to driver task
+ */
+#define EV_PER_UNIT 1
+
+#define TSEC_ETH_EVENT( unit ) ( 1 << (EV_PER_UNIT * (unit) ))
+#if EV_PER_UNIT > 1
+#define TSEC_PHY_EVENT( unit ) ( 1 << (EV_PER_UNIT * (unit) + 1))
+#endif
+
+#define EV_IS_ETH(ev) ( (ev) & 1 )
+#if EV_PER_UNIT > 1
+#define EV_IS_PHY(ev) ( (ev) & 2 )
+#endif
+
+#define EV_IS_ANY(ev) ( (ev) & ((1<<EV_PER_UNIT) - 1) )
+
+#define EV_MSK ( ( 1 << (EV_PER_UNIT * TSEC_NUM_DRIVER_SLOTS) ) - 1)
+
+
+/********** Register Definitions ****************/
+
+/*
+ * Most registers/bits apply to the FEC also;
+ * things that are not supported by the FEC
+ * are commented 'TSEC only'
+ */
+
+#define TSEC_IEVENT 0x010
+#define TSEC_IEVENT_BABR (1<<(31- 0))
+#define TSEC_IEVENT_RXC (1<<(31- 1))
+#define TSEC_IEVENT_BSY (1<<(31- 2))
+#define TSEC_IEVENT_EBERR (1<<(31- 3))
+/*
+ * Misuse reserved bit 4 to flag link interrupts
+ * (which are totally external to the TSEC).
+ * Because reading the MII is so slow we don't
+ * want to poll MII unnecessarily from RX/TX ISRs
+ */
+#define TSEC_LINK_INTR (1<<(31- 4))
+#define TSEC_IEVENT_MSRO (1<<(31- 5))
+#define TSEC_IEVENT_GTSC (1<<(31- 6))
+#define TSEC_IEVENT_BABT (1<<(31- 7))
+#define TSEC_IEVENT_TXC (1<<(31- 8))
+#define TSEC_IEVENT_TXE (1<<(31- 9))
+#define TSEC_IEVENT_TXB (1<<(31-10))
+#define TSEC_IEVENT_TXF (1<<(31-11))
+#define TSEC_IEVENT_LC (1<<(31-13))
+#define TSEC_IEVENT_CRLXDA (1<<(31-14))
+#define TSEC_IEVENT_XFUN (1<<(31-15))
+#define TSEC_IEVENT_RXB (1<<(31-16))
+#define TSEC_IEVENT_GRSC (1<<(31-23))
+#define TSEC_IEVENT_RXF (1<<(31-24))
+#define TSEC_IEVENT_ALL (-1)
+
+#define TSEC_TXIRQ ( TSEC_IEVENT_TXE | TSEC_IEVENT_TXF )
+#define TSEC_RXIRQ ( TSEC_IEVENT_RXF | TSEC_IEVENT_BABR | TSEC_IEVENT_EBERR )
+
+#define TSEC_IMASK 0x014
+#define TSEC_IMASK_BABREN (1<<(31- 0))
+#define TSEC_IMASK_RXCEN (1<<(31- 1))
+#define TSEC_IMASK_BSYEN (1<<(31- 2))
+#define TSEC_IMASK_EBERREN (1<<(31- 3))
+#define TSEC_IMASK_MSROEN (1<<(31- 5))
+#define TSEC_IMASK_GTSCEN (1<<(31- 6))
+#define TSEC_IMASK_BABTEN (1<<(31- 7))
+#define TSEC_IMASK_TXCEN (1<<(31- 8))
+#define TSEC_IMASK_TXEEN (1<<(31- 9))
+#define TSEC_IMASK_TXBEN (1<<(31-10))
+#define TSEC_IMASK_TXFEN (1<<(31-11))
+#define TSEC_IMASK_LCEN (1<<(31-13))
+#define TSEC_IMASK_CRLXDAEN (1<<(31-14))
+#define TSEC_IMASK_XFUNEN (1<<(31-15))
+#define TSEC_IMASK_RXBEN (1<<(31-16))
+#define TSEC_IMASK_GRSCEN (1<<(31-23))
+#define TSEC_IMASK_RXFEN (1<<(31-24))
+#define TSEC_IMASK_NONE (0)
+#define TSEC_EDIS 0x018
+#define TSEC_ECNTRL 0x020 /* TSEC only */
+#define TSEC_ECNTRL_CLRCNT (1<<(31-17))
+#define TSEC_ECNTRL_AUTOZ (1<<(31-18))
+#define TSEC_ECNTRL_STEN (1<<(31-19))
+#define TSEC_ECNTRL_TBIM (1<<(31-26))
+#define TSEC_ECNTRL_RPM (1<<(31-27))
+#define TSEC_ECNTRL_R100M (1<<(31-28))
+#define TSEC_MINFLR 0x024
+#define TSEC_PTV 0x028
+#define TSEC_DMACTRL 0x02c
+#define TSEC_DMACTRL_TDSEN (1<<(31-24))
+#define TSEC_DMACTRL_TBDSEN (1<<(31-25))
+#define TSEC_DMACTRL_GRS (1<<(31-27))
+#define TSEC_DMACTRL_GTS (1<<(31-28))
+#define TSEC_DMACTRL_WWR (1<<(31-30))
+#define TSEC_DMACTRL_WOP (1<<(31-31))
+#define TSEC_TBIPA 0x030 /* TSEC only */
+#define TSEC_FIFO_PAUSE_CTRL 0x04c
+#define TSEC_FIFO_TX_THR 0x08c
+#define TSEC_FIFO_TX_STARVE 0x098
+#define TSEC_FIFO_TX_STARVE_SHUTOFF 0x09c
+#define TSEC_TCTRL 0x100
+#define TSEC_TCTRL_THDR (1<<(31-20))
+#define TSEC_TCTRL_RFC_PAUSE (1<<(31-27))
+#define TSEC_TCTRL_TFC_PAUSE (1<<(31-28))
+#define TSEC_TSTAT 0x104
+#define TSEC_TSTAT_THLT (1<<(31- 0))
+#define TSEC_TBDLEN 0x10c
+#define TSEC_TXIC 0x110 /* TSEC only */
+#define TSEC_IC_ICEN (1<<(31- 0))
+#define TSEC_IC_ICFCT(x) (((x)&0xff)<<(31-10))
+#define TSEC_IC_ICTT(x) (((x)&0xffff)<<(31-31))
+#define TSEC_CTBPTR 0x124
+#define TSEC_TBPTR 0x184
+#define TSEC_TBASE 0x204
+#define TSEC_OSTBD 0x2b0
+#define TSEC_OSTBDP 0x2b4
+#define TSEC_RCTRL 0x300
+#define TSEC_RCTRL_BC_REJ (1<<(31-27))
+#define TSEC_RCTRL_PROM (1<<(31-28))
+#define TSEC_RCTRL_RSF (1<<(31-29))
+#define TSEC_RSTAT 0x304
+#define TSEC_RSTAT_QHLT (1<<(31- 8))
+#define TSEC_RBDLEN 0x30c
+#define TSEC_RXIC 0x310 /* TSEC only */
+#define TSEC_CRBPTR 0x324
+#define TSEC_MRBLR 0x340
+#define TSEC_RBPTR 0x384
+#define TSEC_RBASE 0x404
+#define TSEC_MACCFG1 0x500
+#define TSEC_MACCFG1_SOFT_RESET (1<<(31- 0))
+#define TSEC_MACCFG1_LOOP_BACK (1<<(31-23))
+#define TSEC_MACCFG1_RX_FLOW (1<<(31-26))
+#define TSEC_MACCFG1_TX_FLOW (1<<(31-27))
+#define TSEC_MACCFG1_SYNCD_RX_EN (1<<(31-28))
+#define TSEC_MACCFG1_RX_EN (1<<(31-29))
+#define TSEC_MACCFG1_SYNCD_TX_EN (1<<(31-30))
+#define TSEC_MACCFG1_TX_EN (1<<(31-31))
+#define TSEC_MACCFG2 0x504
+#define TSEC_MACCFG2_PREAMBLE_7 (7<<(31-19))
+#define TSEC_MACCFG2_PREAMBLE_15 (15<<(31-19))
+#define TSEC_MACCFG2_IF_MODE_MII (1<<(31-23))
+#define TSEC_MACCFG2_IF_MODE_GMII (2<<(31-23))
+#define TSEC_MACCFG2_HUGE_FRAME (1<<(31-26))
+#define TSEC_MACCFG2_LENGTH_CHECK (1<<(31-27))
+#define TSEC_MACCFG2_PAD_CRC (1<<(31-29))
+#define TSEC_MACCFG2_CRC_EN (1<<(31-30))
+#define TSEC_MACCFG2_FD (1<<(31-31))
+#define TSEC_IPGIFG 0x508
+#define TSEC_HAFDUP 0x50c
+#define TSEC_MAXFRM 0x510
+#define TSEC_MIIMCFG 0x520 /* TSEC only */
+#define TSEC_MIIMCOM 0x524 /* TSEC only */
+#define TSEC_MIIMCOM_SCAN (1<<(31-30))
+#define TSEC_MIIMCOM_READ (1<<(31-31))
+#define TSEC_MIIMADD 0x528 /* TSEC only */
+#define TSEC_MIIMADD_ADDR(phy, reg) ((((phy)&0x1f)<<8) | ((reg) & 0x1f))
+#define TSEC_MIIMCON 0x52c /* TSEC only */
+#define TSEC_MIIMSTAT 0x530 /* TSEC only */
+#define TSEC_MIIMIND 0x534 /* TSEC only */
+#define TSEC_MIIMIND_NV (1<<(31-29))
+#define TSEC_MIIMIND_SCAN (1<<(31-30))
+#define TSEC_MIIMIND_BUSY (1<<(31-31))
+#define TSEC_IFSTAT 0x53c
+#define TSEC_MACSTNADDR1 0x540
+#define TSEC_MACSTNADDR2 0x544
+#define TSEC_TR64 0x680 /* TSEC only */
+#define TSEC_TR127 0x684 /* TSEC only */
+#define TSEC_TR255 0x688 /* TSEC only */
+#define TSEC_TR511 0x68c /* TSEC only */
+#define TSEC_TR1K 0x690 /* TSEC only */
+#define TSEC_TRMAX 0x694 /* TSEC only */
+#define TSEC_TRMGV 0x698 /* TSEC only */
+#define TSEC_RBYT 0x69c /* TSEC only */
+#define TSEC_RPKT 0x6a0 /* TSEC only */
+#define TSEC_RFCS 0x6a4 /* TSEC only */
+#define TSEC_RMCA 0x6a8 /* TSEC only */
+#define TSEC_RBCA 0x6ac /* TSEC only */
+#define TSEC_RXCF 0x6b0 /* TSEC only */
+#define TSEC_RXPF 0x6b4 /* TSEC only */
+#define TSEC_RXUO 0x6b8 /* TSEC only */
+#define TSEC_RALN 0x6bc /* TSEC only */
+#define TSEC_RFLR 0x6c0 /* TSEC only */
+#define TSEC_RCDE 0x6c4 /* TSEC only */
+#define TSEC_RCSE 0x6c8 /* TSEC only */
+#define TSEC_RUND 0x6cc /* TSEC only */
+#define TSEC_ROVR 0x6d0 /* TSEC only */
+#define TSEC_RFRG 0x6d4 /* TSEC only */
+#define TSEC_RJBR 0x6d8 /* TSEC only */
+#define TSEC_RDRP 0x6dc /* TSEC only */
+#define TSEC_TBYT 0x6e0 /* TSEC only */
+#define TSEC_TPKT 0x6e4 /* TSEC only */
+#define TSEC_TMCA 0x6e8 /* TSEC only */
+#define TSEC_TBCA 0x6ec /* TSEC only */
+#define TSEC_TXPF 0x6f0 /* TSEC only */
+#define TSEC_TDFR 0x6f4 /* TSEC only */
+#define TSEC_TEDF 0x6f8 /* TSEC only */
+#define TSEC_TSCL 0x6fc /* TSEC only */
+#define TSEC_TMCL 0x700 /* TSEC only */
+#define TSEC_TLCL 0x704 /* TSEC only */
+#define TSEC_TXCL 0x708 /* TSEC only */
+#define TSEC_TNCL 0x70c /* TSEC only */
+#define TSEC_TDRP 0x714 /* TSEC only */
+#define TSEC_TJBR 0x718 /* TSEC only */
+#define TSEC_TFCS 0x71c /* TSEC only */
+#define TSEC_TXCF 0x720 /* TSEC only */
+#define TSEC_TOVR 0x724 /* TSEC only */
+#define TSEC_TUND 0x728 /* TSEC only */
+#define TSEC_TFRG 0x72c /* TSEC only */
+#define TSEC_CAR1 0x730 /* TSEC only */
+#define TSEC_CAR2 0x734 /* TSEC only */
+#define TSEC_CAM1 0x738 /* TSEC only */
+#define TSEC_CAM2 0x73c /* TSEC only */
+#define TSEC_IADDR0 0x800
+#define TSEC_IADDR1 0x804
+#define TSEC_IADDR2 0x808
+#define TSEC_IADDR3 0x80c
+#define TSEC_IADDR4 0x810
+#define TSEC_IADDR5 0x814
+#define TSEC_IADDR6 0x818
+#define TSEC_IADDR7 0x81c
+#define TSEC_GADDR0 0x880
+#define TSEC_GADDR1 0x884
+#define TSEC_GADDR2 0x888
+#define TSEC_GADDR3 0x88c
+#define TSEC_GADDR4 0x890
+#define TSEC_GADDR5 0x894
+#define TSEC_GADDR6 0x898
+#define TSEC_GADDR7 0x89c
+#define TSEC_ATTR 0xbf8
+#define TSEC_ATTR_ELCWT_NONE (0<<(31-18))
+#define TSEC_ATTR_ELCWT_ALLOC (2<<(31-18))
+#define TSEC_ATTR_ELCWT_ALLOC_LOCK (3<<(31-18))
+#define TSEC_ATTR_BDLWT_NONE (0<<(31-21))
+#define TSEC_ATTR_BDLWT_ALLOC (2<<(31-21))
+#define TSEC_ATTR_BDLWT_ALLOC_LOCK (3<<(31-21))
+#define TSEC_ATTR_RDSEN (1<<(31-24))
+#define TSEC_ATTR_RBDSEN (1<<(31-25))
+#define TSEC_ATTRELI 0xbfc
+
+/********** Memory Barriers *********************/
+
+#ifdef __PPC__
+static inline void membarrier()
+{
+ asm volatile("sync":::"memory");
+}
+
+#define EIEIO(mem) do { asm volatile("eieio":"=m"(mem):"m"(mem)); } while (0)
+
+#else
+#error "memory barrier not implemented for your CPU architecture"
+#endif
+
+/********** Register Access Primitives **********/
+
+/*
+ * Typedef for base address (uint8_t *) so that
+ * we can do easy pointer arithmetic.
+ */
+typedef volatile uint8_t *FEC_Enet_Base;
+
+/*
+ * All TSEC/FEC registers are 32-bit only.
+ */
+typedef volatile uint32_t FEC_Reg __attribute__((may_alias));
+
+static inline uint32_t
+fec_rd(FEC_Enet_Base b, uint32_t reg)
+{
+#ifdef __BIG_ENDIAN__
+uint32_t rval = *(FEC_Reg *)(b + reg);
+ EIEIO(*(FEC_Reg*)(b+reg));
+ return rval;
+#else
+ return in_be32( (volatile uint32_t*) (b+reg) );
+#endif
+}
+
+static inline void
+fec_wr(FEC_Enet_Base b, uint32_t reg, uint32_t val)
+{
+#ifdef __BIG_ENDIAN__
+ *(FEC_Reg *)(b + reg) = val;
+ EIEIO(*(FEC_Reg*)(b+reg));
+#else
+ out_be32( (volatile uint32_t*) (b+reg), val );
+#endif
+}
+
+/* Set bits in a register */
+static inline void
+fec_set(FEC_Enet_Base b, uint32_t reg, uint32_t val)
+{
+ fec_wr(b, reg, fec_rd(b, reg) | val );
+}
+
+/* Clear bits in a register */
+static inline void
+fec_clr(FEC_Enet_Base b, uint32_t reg, uint32_t val)
+{
+ fec_wr(b, reg, fec_rd(b, reg) & ~val );
+}
+
+/* Clear and set bits in a register */
+static inline void
+fec_csl(FEC_Enet_Base b, uint32_t reg, uint32_t clr, uint32_t set)
+{
+ fec_wr(b, reg, (fec_rd(b, reg) & ~clr) | set);
+}
+
+
+/********** Memory Access Primitives ************/
+
+#ifdef __BIG_ENDIAN__
+static inline uint16_t ld_be16(volatile uint16_t *a)
+{
+ return *a;
+}
+
+static inline uint32_t ld_be32(volatile uint32_t *a)
+{
+ return *a;
+}
+
+static inline void st_be16(volatile uint16_t *a, uint16_t v)
+{
+ *a = v;
+}
+
+static inline void st_be32(volatile uint32_t *a, uint32_t v)
+{
+ *a = v;
+}
+#else
+#error "ld_be32 & friends not implemented"
+#endif
+
+/********** Note About Coherency ****************/
+
+#ifdef SW_COHERENCY
+#error "SW_COHERENCY not implemented"
+/* Note: maintaining BD coherency in software is not trivial
+ * because BDs are smaller than a cache line;
+ * we cannot pad a BD to the length of a cache line because
+ * the TSEC assumes BDs layed out sequentially in memory.
+ * We cannot use zero-length BDs to pad to a full cache
+ * line either because the manual says that the length
+ * field of a TX BD must not be zero.
+ *
+ * We probably would need MMU resources to map BDs
+ * as non-cachable.
+ *
+ * Maintaining buffer coherency would be easier:
+ * - make RX buffers cache aligned so we can
+ * invalidate them w/o overlapping other data.
+ * - TX buffers may be flushed to memory. If cache
+ * lines overlap anything else (besides TX buffers)
+ * then that would only be harmful if (part of) a
+ * TX buffer would share a cache line with another
+ * type of DMA buffer that is written by another
+ * master. Note that BDs have exactly this problem;
+ * we may not flush one BD because the TSEC could
+ * have written another BD to memory covered by
+ * the same cache line.
+ * This second BD could be lost by a DBCF operation:
+ * - writes 1st BD to memory OK
+ * - overwrites 2nd BD with stale data from cache
+ */
+#else
+#define FLUSH_BUF(addr, len) do {} while(0)
+#endif
+
+/********** Driver Data Structures **************/
+
+/* Buffer descriptor layout (defined by hardware) */
+struct tsec_bd {
+ volatile uint16_t flags;
+ volatile uint16_t len;
+ volatile uint32_t buf;
+};
+
+typedef struct tsec_bd TSEC_BD __attribute__((aligned(BD_ALIGNMENT)));
+
+/* BD access primitives */
+
+static inline uint16_t bd_rdfl(TSEC_BD *bd)
+{
+ return ld_be16( & bd->flags );
+}
+
+static inline void bd_wrfl(TSEC_BD *bd, uint16_t v)
+{
+ st_be16( &bd->flags, v );
+}
+
+static inline void bd_setfl(TSEC_BD *bd, uint16_t v)
+{
+ bd_wrfl(bd, bd_rdfl(bd) | v );
+}
+
+static inline void bd_clrfl(TSEC_BD *bd, uint16_t v)
+{
+ bd_wrfl(bd, bd_rdfl(bd) & ~v );
+}
+
+static inline void bd_cslfl(TSEC_BD *bd, uint16_t s, uint16_t c)
+{
+ bd_wrfl( bd, ( bd_rdfl(bd) & ~c ) | s );
+}
+
+static inline uint32_t bd_rdbuf(TSEC_BD *bd)
+{
+ return BUS2CPU_ADDR( ld_be32( &bd->buf ) );
+}
+
+static inline void bd_wrbuf(TSEC_BD *bd, uint32_t addr)
+{
+ st_be32( &bd->buf, CPU2BUS_ADDR(addr) );
+}
+
+/* BD bit definitions */
+
+#define TSEC_TXBD_R ((uint16_t)(1<<(15- 0)))
+#define TSEC_TXBD_PAD_CRC ((uint16_t)(1<<(15- 1)))
+#define TSEC_TXBD_W ((uint16_t)(1<<(15- 2)))
+#define TSEC_TXBD_I ((uint16_t)(1<<(15- 3)))
+#define TSEC_TXBD_L ((uint16_t)(1<<(15- 4)))
+#define TSEC_TXBD_TC ((uint16_t)(1<<(15- 5)))
+#define TSEC_TXBD_DEF ((uint16_t)(1<<(15- 6)))
+#define TSEC_TXBD_TO1 ((uint16_t)(1<<(15- 7)))
+#define TSEC_TXBD_HFE_LC ((uint16_t)(1<<(15- 8)))
+#define TSEC_TXBD_RL ((uint16_t)(1<<(15- 9)))
+#define TSEC_TXBD_RC(x) ((uint16_t)(((x)>>2)&0xf))
+#define TSEC_TXBD_UN ((uint16_t)(1<<(15-14)))
+#define TSEC_TXBD_TXTRUNC ((uint16_t)(1<<(15-15)))
+#define TSEC_TXBD_ERRS (TSEC_TXBD_RL | TSEC_TXBD_UN | TSEC_TXBD_TXTRUNC)
+
+#define TSEC_RXBD_E ((uint16_t)(1<<(15- 0)))
+#define TSEC_RXBD_RO1 ((uint16_t)(1<<(15- 1)))
+#define TSEC_RXBD_W ((uint16_t)(1<<(15- 2)))
+#define TSEC_RXBD_I ((uint16_t)(1<<(15- 3)))
+#define TSEC_RXBD_L ((uint16_t)(1<<(15- 4)))
+#define TSEC_RXBD_F ((uint16_t)(1<<(15- 5)))
+#define TSEC_RXBD_M ((uint16_t)(1<<(15- 7)))
+#define TSEC_RXBD_BC ((uint16_t)(1<<(15- 8)))
+#define TSEC_RXBD_MC ((uint16_t)(1<<(15- 9)))
+#define TSEC_RXBD_LG ((uint16_t)(1<<(15-10)))
+#define TSEC_RXBD_NO ((uint16_t)(1<<(15-11)))
+#define TSEC_RXBD_SH ((uint16_t)(1<<(15-12)))
+#define TSEC_RXBD_CR ((uint16_t)(1<<(15-13)))
+#define TSEC_RXBD_OV ((uint16_t)(1<<(15-14)))
+#define TSEC_RXBD_TR ((uint16_t)(1<<(15-15)))
+
+#define TSEC_RXBD_ERROR \
+ (TSEC_RXBD_LG | TSEC_RXBD_NO | TSEC_RXBD_SH | TSEC_RXBD_CR | TSEC_RXBD_OV | TSEC_RXBD_TR )
+
+/* Driver 'private' data */
+
+struct tsec_private {
+ FEC_Enet_Base base; /* Controller base address */
+ FEC_Enet_Base phy_base; /* Phy base address (not necessarily identical
+ * with controller base address);
+ * e.g., phy attached to 2nd controller may be
+ * connected to mii bus of 1st controller.
+ */
+ unsigned phy; /* Phy address on mii bus */
+ unsigned unit; /* Driver instance (one-based */
+ int isfec; /* Set if a FEC (not TSEC) controller */
+ struct tsec_softc *sc; /* Pointer to BSD driver struct */
+ TSEC_BD *ring_area; /* Not necessarily aligned */
+ TSEC_BD *tx_ring; /* Aligned array of TX BDs */
+ void **tx_ring_user; /* Array of user pointers (1 per BD) */
+ unsigned tx_ring_size;
+ unsigned tx_head; /* first 'dirty' BD; chip is working on */
+ unsigned tx_tail; /* BDs between head and tail */
+ unsigned tx_avail; /* Number of available/free TX BDs */
+ TSEC_BD *rx_ring; /* Aligned array of RX BDs */
+ void **rx_ring_user; /* Array of user pointers (1 per BD) */
+ unsigned rx_tail; /* Where we left off scanning for full bufs */
+ unsigned rx_ring_size;
+ void (*cleanup_txbuf) /* Callback to cleanup TX ring */
+ (void*, void*, int);
+ void *cleanup_txbuf_arg;
+ void *(*alloc_rxbuf) /* Callback for allocating RX buffer */
+ (int *psize, uintptr_t *paddr);
+ void (*consume_rxbuf) /* callback to consume RX buffer */
+ (void*, void*, int);
+ void *consume_rxbuf_arg;
+ rtems_id tid; /* driver task ID */
+ uint32_t irq_mask;
+ uint32_t irq_pending;
+ rtems_event_set event; /* Task synchronization events */
+ struct { /* Statistics */
+ unsigned xirqs;
+ unsigned rirqs;
+ unsigned eirqs;
+ unsigned lirqs;
+ unsigned maxchain;
+ unsigned packet;
+ unsigned odrops;
+ unsigned repack;
+ } stats;
+};
+
+#define NEXT_TXI(mp, i) (((i)+1) < (mp)->tx_ring_size ? (i)+1 : 0 )
+#define NEXT_RXI(mp, i) (((i)+1) < (mp)->rx_ring_size ? (i)+1 : 0 )
+
+/* Stuff needed for bsdnet support */
+struct tsec_bsdsupp {
+ int oif_flags; /* old / cached if_flags */
+};
+
+/* bsdnet driver data */
+struct tsec_softc {
+ struct arpcom arpcom;
+ struct tsec_bsdsupp bsd;
+ struct tsec_private pvt;
+};
+
+/* BSP glue information */
+typedef struct tsec_bsp_config {
+ uint32_t base;
+ int xirq, rirq, eirq;
+ uint32_t phy_base;
+ int phy_addr;
+} TsecBspConfig;
+
+/********** Global Variables ********************/
+
+/* You may override base addresses
+ * externally - but you must
+ * then also define TSEC_NUM_DRIVER_SLOTS.
+ */
+#ifndef TSEC_CONFIG
+
+static TsecBspConfig tsec_config[] =
+{
+ {
+ base: BSP_8540_CCSR_BASE + 0x24000,
+ xirq: BSP_CORE_IRQ_LOWEST_OFFSET + 13,
+ rirq: BSP_CORE_IRQ_LOWEST_OFFSET + 14,
+ eirq: BSP_CORE_IRQ_LOWEST_OFFSET + 18,
+ phy_base: BSP_8540_CCSR_BASE + 0x24000,
+ phy_addr: 1,
+ },
+ {
+ base: BSP_8540_CCSR_BASE + 0x25000,
+ xirq: BSP_CORE_IRQ_LOWEST_OFFSET + 19,
+ rirq: BSP_CORE_IRQ_LOWEST_OFFSET + 20,
+ eirq: BSP_CORE_IRQ_LOWEST_OFFSET + 23,
+ /* all PHYs are on the 1st adapter's mii bus */
+ phy_base: BSP_8540_CCSR_BASE + 0x24000,
+ phy_addr: 2,
+ },
+};
+
+#define TSEC_CONFIG tsec_config
+
+#endif
+
+#ifndef TSEC_NUM_DRIVER_SLOTS
+#define TSEC_NUM_DRIVER_SLOTS (sizeof(TSEC_CONFIG)/sizeof(TSEC_CONFIG[0]))
+#endif
+
+/* Driver data structs */
+STATIC struct tsec_softc theTsecEths[TSEC_NUM_DRIVER_SLOTS] = { {{{0}}} };
+
+/* Bsdnet driver task ID; since the BSD stack is single-threaded
+ * there is no point having multiple tasks. A single
+ * task handling all adapters (attached to BSD stack)
+ * is good enough.
+ * Note that an adapter might well be used independently
+ * from the BSD stack (use the low-level driver interface)
+ * and be serviced by a separate task.
+ */
+STATIC rtems_id tsec_tid = 0;
+
+/* If we anticipate using adapters independently
+ * from the BSD stack AND if all PHYs are on a single
+ * adapter's MII bus THEN we must mutex-protect
+ * that MII bus.
+ * If not all of these conditions hold then you
+ * may define TSEC_CONFIG_NO_PHY_REGLOCK and
+ * avoid the creation and use of a mutex.
+ */
+#ifndef TSEC_CONFIG_NO_PHY_REGLOCK
+/*
+ * PHY register access protection mutex;
+ * multiple instances of tsec hardware
+ * may share e.g., the first tsec's registers
+ * for accessing the mii bus where all PHYs
+ * may be connected. If we would only deal
+ * with BSD networking then using the normal
+ * networking semaphore would be OK. However,
+ * we want to support standalone drivers and
+ * therefore might require a separate lock.
+ */
+STATIC rtems_id tsec_mtx = 0;
+#define REGLOCK() do { \
+ if ( RTEMS_SUCCESSFUL != rtems_semaphore_obtain(tsec_mtx, RTEMS_WAIT, RTEMS_NO_TIMEOUT) ) \
+ rtems_panic(DRVNAME": unable to lock phy register protection mutex"); \
+ } while (0)
+#define REGUNLOCK() rtems_semaphore_release(tsec_mtx)
+#else
+#define REGLOCK() do { } while (0)
+#define REGUNLOCK() do { } while (0)
+#endif
+
+static void tsec_xisr(rtems_irq_hdl_param arg);
+static void tsec_risr(rtems_irq_hdl_param arg);
+static void tsec_eisr(rtems_irq_hdl_param arg);
+static void tsec_lisr(rtems_irq_hdl_param arg);
+
+static void noop(const rtems_irq_connect_data *unused) { }
+static int nopf(const rtems_irq_connect_data *unused) { return -1; }
+
+/********** Low-level Driver API ****************/
+
+/*
+ * This API provides driver access to applications that
+ * want to use e.g., the second ethernet interface
+ * independently from the BSD TCP/IP stack. E.g., for
+ * raw ethernet packet communication...
+ */
+
+/*
+ * Descriptor scavenger; cleanup the TX ring, passing all buffers
+ * that have been sent to the cleanup_tx() callback.
+ * This routine is called from BSP_tsec_send_buf(), BSP_tsec_init_hw(),
+ * BSP_tsec_stop_hw().
+ *
+ * RETURNS: number of buffers processed.
+ */
+
+int
+BSP_tsec_swipe_tx(struct tsec_private *mp)
+{
+int rval = 0;
+int i;
+TSEC_BD *bd;
+uint16_t flags;
+void *u;
+
+#if DEBUG > 2
+printf("Swipe TX entering:\n");
+tsec_dump_tring(mp);
+#endif
+
+ for ( i = mp->tx_head; bd_rdbuf( (bd = &mp->tx_ring[i]) ); i = NEXT_TXI(mp, i) ) {
+
+ flags = bd_rdfl( bd );
+ if ( (TSEC_TXBD_R & flags) ) {
+ /* nothing more to clean */
+ break;
+ }
+
+ /* tx_ring_user[i] is only set on the last descriptor in a chain;
+ * we only count errors in the last descriptor;
+ */
+ if ( (u=mp->tx_ring_user[i]) ) {
+ mp->cleanup_txbuf(u, mp->cleanup_txbuf_arg, (flags & TSEC_TXBD_ERRS));
+ mp->tx_ring_user[i] = 0;
+ }
+
+ bd_wrbuf( bd, 0 );
+
+ mp->tx_avail++;
+
+ rval++;
+ }
+ mp->tx_head = i;
+
+#if DEBUG > 2
+tsec_dump_tring(mp);
+printf("Swipe TX leaving\n");
+#endif
+
+ return rval;
+}
+
+
+/*
+ * Reset the controller and bring into a known state;
+ * all interrupts are off
+ */
+STATIC void
+tsec_reset_hw(struct tsec_private *mp)
+{
+FEC_Enet_Base b = mp->base;
+
+ /* Make sure all interrupts are off */
+ fec_wr(b, TSEC_IMASK, TSEC_IMASK_NONE);
+
+#ifndef TSEC_CONFIG_NO_PHY_REGLOCK
+ /* don't bother disabling irqs in the PHY if this is
+ * called before the mutex is created;
+ * the PHY ISR is not hooked yet and there can be no
+ * interrupts...
+ */
+ if ( tsec_mtx )
+#endif
+ phy_dis_irq_at_phy( mp );
+
+ /* Follow the manual resetting the chip */
+
+ /* Do graceful stop (if not in stop condition already) */
+ if ( ! (TSEC_DMACTRL_GTS & fec_rd(b, TSEC_DMACTRL)) ) {
+ /* Make sure GTSC is clear */
+ fec_wr(b, TSEC_IEVENT, TSEC_IEVENT_GTSC);
+ fec_set(b, TSEC_DMACTRL, TSEC_DMACTRL_GTS);
+ while ( ! (TSEC_IEVENT_GTSC & fec_rd(b, TSEC_IEVENT)) )
+ /* wait */;
+ }
+
+ /* Clear RX/TX enable in MAC */
+ fec_clr(b, TSEC_MACCFG1, TSEC_MACCFG1_RX_EN | TSEC_MACCFG1_TX_EN);
+
+ /* wait for > 8ms */
+ rtems_task_wake_after(1);
+
+ /* set GRS if not already stopped */
+ if ( ! (TSEC_DMACTRL_GRS & fec_rd(b, TSEC_DMACTRL)) ) {
+ /* Make sure GRSC is clear */
+ fec_wr(b, TSEC_IEVENT, TSEC_IEVENT_GRSC);
+ fec_set(b, TSEC_DMACTRL, TSEC_DMACTRL_GRS);
+ while ( ! (TSEC_IEVENT_GRSC & fec_rd(b, TSEC_IEVENT)) )
+ /* wait */;
+ }
+
+ fec_set(b, TSEC_MACCFG1, TSEC_MACCFG1_SOFT_RESET);
+ fec_clr(b, TSEC_MACCFG1, TSEC_MACCFG1_SOFT_RESET);
+
+ /* clear all irqs */
+ fec_wr (b, TSEC_IEVENT, TSEC_IEVENT_ALL);
+}
+
+/* Helper to hook/unhook interrupts */
+
+static void
+install_remove_isrs(int install, struct tsec_private *mp, uint32_t irq_mask)
+{
+ rtems_irq_connect_data xxx;
+ int installed = 0;
+ int line;
+ int unit = mp->unit;
+
+ xxx.on = noop;
+ xxx.off = noop;
+ xxx.isOn = nopf;
+ xxx.handle = mp;
+
+ if ( irq_mask & TSEC_TXIRQ ) {
+ xxx.name = TSEC_CONFIG[unit-1].xirq;
+ xxx.hdl = tsec_xisr;
+ if ( ! (install ?
+ BSP_install_rtems_irq_handler( &xxx ) :
+ BSP_remove_rtems_irq_handler( &xxx ) ) ) {
+ rtems_panic(DRVNAME": Unable to install TX ISR\n");
+ }
+ installed++;
+ }
+
+ if ( (irq_mask & TSEC_RXIRQ) ) {
+ if ( (line = TSEC_CONFIG[unit-1].rirq) < 0 && ! installed ) {
+ /* have no dedicated RX IRQ line; install TX ISR if not already done */
+ line = TSEC_CONFIG[unit-1].xirq;
+ }
+ xxx.name = line;
+ xxx.hdl = tsec_risr;
+ if ( ! (install ?
+ BSP_install_rtems_irq_handler( &xxx ) :
+ BSP_remove_rtems_irq_handler( &xxx ) ) ) {
+ rtems_panic(DRVNAME": Unable to install RX ISR\n");
+ }
+ installed++;
+ }
+
+ if ( (line = TSEC_CONFIG[unit-1].eirq) < 0 && ! installed ) {
+ /* have no dedicated RX IRQ line; install TX ISR if not already done */
+ line = TSEC_CONFIG[unit-1].xirq;
+ }
+ xxx.name = line;
+ xxx.hdl = tsec_eisr;
+ if ( ! (install ?
+ BSP_install_rtems_irq_handler( &xxx ) :
+ BSP_remove_rtems_irq_handler( &xxx ) ) ) {
+ rtems_panic(DRVNAME": Unable to install ERR ISR\n");
+ }
+
+ if ( irq_mask & TSEC_LINK_INTR ) {
+ phy_init_irq( install, mp, tsec_lisr );
+ }
+}
+
+/*
+ * Setup an interface.
+ * Allocates resources for descriptor rings and sets up the driver software structure.
+ *
+ * Arguments:
+ * unit:
+ * interface # (1..2). The interface must not be attached to BSD already.
+ *
+ * driver_tid:
+ * ISR posts RTEMS event # ('unit' - 1) to task with ID 'driver_tid' and disables interrupts
+ * from this interface.
+ *
+ * void (*cleanup_txbuf)(void *user_buf, void *cleanup_txbuf_arg, int error_on_tx_occurred):
+ * Pointer to user-supplied callback to release a buffer that had been sent
+ * by BSP_tsec_send_buf() earlier. The callback is passed 'cleanup_txbuf_arg'
+ * and a flag indicating whether the send had been successful.
+ * The driver no longer accesses 'user_buf' after invoking this callback.
+ * CONTEXT: This callback is executed either by BSP_tsec_swipe_tx() or
+ * BSP_tsec_send_buf(), BSP_tsec_init_hw(), BSP_tsec_stop_hw() (the latter
+ * ones calling BSP_tsec_swipe_tx()).
+ * void *cleanup_txbuf_arg:
+ * Closure argument that is passed on to 'cleanup_txbuf()' callback;
+ *
+ * void *(*alloc_rxbuf)(int *p_size, uintptr_t *p_data_addr),
+ * Pointer to user-supplied callback to allocate a buffer for subsequent
+ * insertion into the RX ring by the driver.
+ * RETURNS: opaque handle to the buffer (which may be a more complex object
+ * such as an 'mbuf'). The handle is not used by the driver directly
+ * but passed back to the 'consume_rxbuf()' callback.
+ * Size of the available data area and pointer to buffer's data area
+ * in '*psize' and '*p_data_area', respectively.
+ * If no buffer is available, this routine should return NULL in which
+ * case the driver drops the last packet and re-uses the last buffer
+ * instead of handing it out to 'consume_rxbuf()'.
+ * CONTEXT: Called when initializing the RX ring (BSP_tsec_init_hw()) or when
+ * swiping it (BSP_tsec_swipe_rx()).
+ *
+ *
+ * void (*consume_rxbuf)(void *user_buf, void *consume_rxbuf_arg, int len);
+ * Pointer to user-supplied callback to pass a received buffer back to
+ * the user. The driver no longer accesses the buffer after invoking this
+ * callback (with 'len'>0, see below). 'user_buf' is the buffer handle
+ * previously generated by 'alloc_rxbuf()'.
+ * The callback is passed 'cleanup_rxbuf_arg' and a 'len'
+ * argument giving the number of bytes that were received.
+ * 'len' may be <=0 in which case the 'user_buf' argument is NULL.
+ * 'len' == 0 means that the last 'alloc_rxbuf()' had failed,
+ * 'len' < 0 indicates a receiver error. In both cases, the last packet
+ * was dropped/missed and the last buffer will be re-used by the driver.
+ * NOTE: the data are 'prefixed' with two bytes, i.e., the ethernet packet header
+ * is stored at offset 2 in the buffer's data area. Also, the FCS (4 bytes)
+ * is appended. 'len' accounts for both.
+ * CONTEXT: Called from BSP_tsec_swipe_rx().
+ * void *cleanup_rxbuf_arg:
+ * Closure argument that is passed on to 'consume_rxbuf()' callback;
+ *
+ * rx_ring_size, tx_ring_size:
+ * How many big to make the RX and TX descriptor rings. Note that the sizes
+ * may be 0 in which case a reasonable default will be used.
+ * If either ring size is < 0 then the RX or TX will be disabled.
+ * Note that it is illegal in this case to use BSP_tsec_swipe_rx() or
+ * BSP_tsec_swipe_tx(), respectively.
+ *
+ * irq_mask:
+ * Interrupts to enable. OR of flags from above.
+ *
+ */
+struct tsec_private *
+BSP_tsec_setup(
+ int unit,
+ rtems_id driver_tid,
+ void (*cleanup_txbuf)(void *user_buf, void *cleanup_txbuf_arg, int error_on_tx_occurred),
+ void *cleanup_txbuf_arg,
+ void *(*alloc_rxbuf)(int *p_size, uintptr_t *p_data_addr),
+ void (*consume_rxbuf)(void *user_buf, void *consume_rxbuf_arg, int len),
+ void *consume_rxbuf_arg,
+ int rx_ring_size,
+ int tx_ring_size,
+ int irq_mask
+)
+{
+struct tsec_private *mp;
+int i;
+struct ifnet *ifp;
+
+ if ( unit <= 0 || unit > TSEC_NUM_DRIVER_SLOTS ) {
+ printk(DRVNAME": Bad unit number %i; must be 1..%i\n", unit, TSEC_NUM_DRIVER_SLOTS);
+ return 0;
+ }
+
+ ifp = &theTsecEths[unit-1].arpcom.ac_if;
+ if ( ifp->if_init ) {
+ if ( ifp->if_init ) {
+ printk(DRVNAME": instance %i already attached.\n", unit);
+ return 0;
+ }
+ }
+
+
+ if ( rx_ring_size < 0 && tx_ring_size < 0 )
+ return 0;
+
+ mp = &theTsecEths[unit - 1].pvt;
+
+ memset(mp, 0, sizeof(*mp));
+
+ mp->sc = &theTsecEths[unit - 1];
+ mp->unit = unit;
+
+ mp->base = (FEC_Enet_Base)TSEC_CONFIG[unit-1].base;
+ mp->phy_base = (FEC_Enet_Base)TSEC_CONFIG[unit-1].phy_base;
+ mp->phy = TSEC_CONFIG[unit-1].phy_addr;
+ mp->tid = driver_tid;
+ /* use odd event flags for link status IRQ */
+ mp->event = TSEC_ETH_EVENT((unit-1));
+
+ mp->cleanup_txbuf = cleanup_txbuf;
+ mp->cleanup_txbuf_arg = cleanup_txbuf_arg;
+ mp->alloc_rxbuf = alloc_rxbuf;
+ mp->consume_rxbuf = consume_rxbuf;
+ mp->consume_rxbuf_arg = consume_rxbuf_arg;
+
+ /* stop hw prior to setting ring-size to anything nonzero
+ * so that the rings are not swept.
+ */
+ BSP_tsec_stop_hw(mp);
+
+ if ( 0 == rx_ring_size )
+ rx_ring_size = TSEC_RX_RING_SIZE;
+ if ( 0 == tx_ring_size )
+ tx_ring_size = TSEC_TX_RING_SIZE;
+
+ mp->rx_ring_size = rx_ring_size < 0 ? 0 : rx_ring_size;
+ mp->tx_ring_size = tx_ring_size < 0 ? 0 : tx_ring_size;
+
+ /* allocate ring area; add 1 entry -- room for alignment */
+ assert( !mp->ring_area );
+ mp->ring_area = malloc(
+ sizeof(*mp->ring_area) *
+ (mp->rx_ring_size + mp->tx_ring_size + 1),
+ M_DEVBUF,
+ M_WAIT );
+ assert( mp->ring_area );
+
+ mp->tx_ring_user = malloc( sizeof(*mp->tx_ring_user) *
+ (mp->rx_ring_size + mp->tx_ring_size),
+ M_DEVBUF,
+ M_WAIT );
+ assert( mp->tx_ring_user );
+
+ mp->rx_ring_user = mp->tx_ring_user + mp->tx_ring_size;
+
+ /* Initialize TX ring */
+ mp->tx_ring = (TSEC_BD *) ALIGNTO(mp->ring_area,BD_ALIGNMENT);
+
+ mp->rx_ring = mp->tx_ring + mp->tx_ring_size;
+
+ for ( i=0; i<mp->tx_ring_size; i++ ) {
+ bd_wrbuf( &mp->tx_ring[i], 0 );
+ bd_wrfl( &mp->tx_ring[i], TSEC_TXBD_I );
+ mp->tx_ring_user[i] = 0;
+ }
+ /* set wrap-around flag on last BD */
+ if ( mp->tx_ring_size )
+ bd_setfl( &mp->tx_ring[i-1], TSEC_TXBD_W );
+
+ mp->tx_tail = mp->tx_head = 0;
+ mp->tx_avail = mp->tx_ring_size;
+
+ /* Initialize RX ring (buffers are allocated later) */
+ for ( i=0; i<mp->rx_ring_size; i++ ) {
+ bd_wrbuf( &mp->rx_ring[i], 0 );
+ bd_wrfl( &mp->rx_ring[i], TSEC_RXBD_I );
+ mp->rx_ring_user[i] = 0;
+ }
+ /* set wrap-around flag on last BD */
+ if ( mp->rx_ring_size )
+ bd_setfl( &mp->rx_ring[i-1], TSEC_RXBD_W );
+
+ if ( irq_mask ) {
+ if ( rx_ring_size == 0 )
+ irq_mask &= ~ TSEC_RXIRQ;
+ if ( tx_ring_size == 0 )
+ irq_mask &= ~ TSEC_TXIRQ;
+ }
+
+#ifndef TSEC_CONFIG_NO_PHY_REGLOCK
+ /* lazy init of mutex (non thread-safe! - we assume initialization
+ * of 1st IF is single-threaded)
+ */
+ if ( ! tsec_mtx ) {
+ rtems_status_code sc;
+ sc = rtems_semaphore_create(
+ rtems_build_name('t','s','e','X'),
+ 1,
+ RTEMS_SIMPLE_BINARY_SEMAPHORE | RTEMS_PRIORITY | RTEMS_INHERIT_PRIORITY | RTEMS_DEFAULT_ATTRIBUTES,
+ 0,
+ &tsec_mtx);
+ if ( RTEMS_SUCCESSFUL != sc ) {
+ rtems_error(sc,DRVNAME": creating mutex\n");
+ rtems_panic("unable to proceed\n");
+ }
+ }
+#endif
+
+ if ( irq_mask ) {
+ install_remove_isrs( 1, mp, irq_mask );
+ }
+
+ mp->irq_mask = irq_mask;
+
+ /* mark as used */
+ ifp->if_init = (void*)(-1);
+
+ return mp;
+}
+
+void
+BSP_tsec_reset_stats(struct tsec_private *mp)
+{
+FEC_Enet_Base b = mp->base;
+int i;
+ memset( &mp->stats, 0, sizeof( mp->stats ) );
+ if ( mp->isfec )
+ return;
+ for ( i=TSEC_TR64; i<=TSEC_TFRG; i+=4 )
+ fec_wr( b, i, 0 );
+
+}
+
+/*
+ * retrieve media status from the PHY
+ * and set duplex mode in MACCFG2 based
+ * on the result.
+ *
+ * RETURNS: media word (or -1 if BSP_tsec_media_ioctl() fails)
+ */
+static int
+mac_set_duplex(struct tsec_private *mp)
+{
+int media = 0;
+
+ if ( 0 == BSP_tsec_media_ioctl(mp, SIOCGIFMEDIA, &media)) {
+ if ( IFM_LINK_OK & media ) {
+ /* update duplex setting in MACCFG2 */
+ if ( IFM_FDX & media ) {
+ fec_set( mp->base, TSEC_MACCFG2, TSEC_MACCFG2_FD );
+ } else {
+ fec_clr( mp->base, TSEC_MACCFG2, TSEC_MACCFG2_FD );
+ }
+ }
+ return media;
+ }
+ return -1;
+}
+
+/*
+ * Initialize interface hardware
+ *
+ * 'mp' handle obtained by from BSP_tsec_setup().
+ * 'promisc' whether to set promiscuous flag.
+ * 'enaddr' pointer to six bytes with MAC address. Read
+ * from the device if NULL.
+ */
+void
+BSP_tsec_init_hw(struct tsec_private *mp, int promisc, unsigned char *enaddr)
+{
+FEC_Enet_Base b = mp->base;
+unsigned i;
+uint32_t v;
+int sz;
+rtems_interrupt_level l;
+
+ BSP_tsec_stop_hw(mp);
+
+#ifdef PARANOIA
+ assert( mp->tx_avail == mp->tx_ring_size );
+ assert( mp->tx_head == mp->tx_tail );
+ for ( i=0; i<mp->tx_ring_size; i++ ) {
+ assert( mp->tx_ring_user[i] == 0 );
+ }
+#endif
+
+ /* make sure RX ring is filled */
+ for ( i=0; i<mp->rx_ring_size; i++ ) {
+ uintptr_t data_area;
+ if ( ! (mp->rx_ring_user[i] = mp->alloc_rxbuf( &sz, &data_area)) ) {
+ rtems_panic(DRVNAME": unable to fill RX ring");
+ }
+ if ( data_area & (RX_BUF_ALIGNMENT-1) )
+ rtems_panic(DRVNAME": RX buffers must be %i-byte aligned", RX_BUF_ALIGNMENT);
+
+ bd_wrbuf( &mp->rx_ring[i], data_area );
+ st_be16 ( &mp->rx_ring[i].len, sz );
+ bd_setfl( &mp->rx_ring[i], TSEC_RXBD_E | TSEC_RXBD_I );
+ }
+
+ mp->tx_tail = mp->tx_head = 0;
+
+ mp->rx_tail = 0;
+
+ /* tell chip what the ring areas are */
+ fec_wr( b, TSEC_TBASE, (uint32_t)mp->tx_ring );
+ fec_wr( b, TSEC_RBASE, (uint32_t)mp->rx_ring );
+
+ /* clear and disable IRQs */
+ fec_wr( b, TSEC_IEVENT, TSEC_IEVENT_ALL );
+ fec_wr( b, TSEC_IMASK, TSEC_IMASK_NONE );
+
+ /* bring other regs. into a known state */
+ fec_wr( b, TSEC_EDIS, 0 );
+
+ if ( !mp->isfec )
+ fec_wr( b, TSEC_ECNTRL, TSEC_ECNTRL_CLRCNT | TSEC_ECNTRL_STEN );
+
+ fec_wr( b, TSEC_MINFLR, 64 );
+ fec_wr( b, TSEC_PTV, 0 );
+
+ v = TSEC_DMACTRL_WWR;
+
+ if ( mp->tx_ring_size )
+ v |= TSEC_DMACTRL_TDSEN | TSEC_DMACTRL_TBDSEN | TSEC_DMACTRL_WOP;
+
+ fec_wr( b, TSEC_DMACTRL, v );
+
+ fec_wr( b, TSEC_FIFO_PAUSE_CTRL, 0 );
+ fec_wr( b, TSEC_FIFO_TX_THR, 256 );
+ fec_wr( b, TSEC_FIFO_TX_STARVE, 128 );
+ fec_wr( b, TSEC_FIFO_TX_STARVE_SHUTOFF, 256 );
+ fec_wr( b, TSEC_TCTRL, 0 );
+ if ( !mp->isfec ) {
+ /* FIXME: use IRQ coalescing ? not sure how to
+ * set the timer (bad if it depends on the speed
+ * setting).
+ */
+ fec_wr( b, TSEC_TXIC, 0);
+ }
+ fec_wr( b, TSEC_OSTBD, 0 );
+ fec_wr( b, TSEC_RCTRL, (promisc ? TSEC_RCTRL_PROM : 0) );
+ fec_wr( b, TSEC_RSTAT, TSEC_RSTAT_QHLT );
+ if ( !mp->isfec ) {
+ /* FIXME: use IRQ coalescing ? not sure how to
+ * set the timer (bad if it depends on the speed
+ * setting).
+ */
+ fec_wr( b, TSEC_RXIC, 0 );
+ }
+ fec_wr( b, TSEC_MRBLR, sz & ~63 );
+
+ /* Reset config. as per manual */
+ fec_wr( b, TSEC_IPGIFG, 0x40605060 );
+ fec_wr( b, TSEC_HAFDUP, 0x00a1f037 );
+ fec_wr( b, TSEC_MAXFRM, 1536 );
+
+ if ( enaddr ) {
+ union {
+ uint32_t u;
+ uint16_t s[2];
+ uint8_t c[4];
+ } x;
+ fec_wr( b, TSEC_MACSTNADDR1, ld_le32( (volatile uint32_t*)(enaddr + 2) ) );
+ x.s[0] = ld_le16( (volatile uint16_t *)(enaddr) );
+ fec_wr( b, TSEC_MACSTNADDR2, x.u );
+ }
+
+ for ( i=0; i<8*4; i+=4 ) {
+ fec_wr( b, TSEC_IADDR0 + i, 0 );
+ fec_wr( b, TSEC_GADDR0 + i, 0 );
+ }
+
+ BSP_tsec_reset_stats(mp);
+
+ fec_wr( b, TSEC_ATTR, (TSEC_ATTR_RDSEN | TSEC_ATTR_RBDSEN) );
+ fec_wr( b, TSEC_ATTRELI, 0 );
+
+ /* The interface type is probably board dependent; leave alone...
+ v = mp->isfec ? TSEC_MACCFG2_IF_MODE_MII : TSEC_MACCFG2_IF_MODE_GMII;
+ */
+
+ fec_clr( b, TSEC_MACCFG2,
+ TSEC_MACCFG2_PREAMBLE_15
+ | TSEC_MACCFG2_HUGE_FRAME
+ | TSEC_MACCFG2_LENGTH_CHECK );
+
+ fec_set( b, TSEC_MACCFG2,
+ TSEC_MACCFG2_PREAMBLE_7
+ | TSEC_MACCFG2_PAD_CRC );
+
+ mac_set_duplex( mp );
+
+ v = 0;
+ if ( mp->rx_ring_size ) {
+ v |= TSEC_MACCFG1_RX_EN;
+ }
+ if ( mp->tx_ring_size ) {
+ v |= TSEC_MACCFG1_TX_EN;
+ }
+
+ fec_wr( b, TSEC_MACCFG1, v);
+
+ /* The following sequency (FWIW) ensures that
+ *
+ * - PHY and TSEC interrupts are enabled atomically
+ * - IRQS are not globally off while accessing the PHY
+ * (slow MII)
+ */
+
+ /* disable PHY irq at PIC (fast) */
+ phy_dis_irq( mp );
+ /* enable PHY irq (MII operation, slow) */
+ phy_en_irq_at_phy (mp );
+
+ /* globally disable */
+ rtems_interrupt_disable( l );
+
+ /* enable TSEC IRQs */
+ fec_wr( mp->base, TSEC_IMASK, mp->irq_mask );
+ /* enable PHY irq at PIC */
+ phy_en_irq( mp );
+
+ /* globally reenable */
+ rtems_interrupt_enable( l );
+}
+
+void
+BSP_tsec_dump_stats(struct tsec_private *mp, FILE *f)
+{
+FEC_Enet_Base b;
+
+ if ( !mp )
+ mp = &theTsecEths[0].pvt;
+
+ if ( ! f )
+ f = stdout;
+
+ fprintf(f, DRVNAME"%i Statistics:\n", mp->unit);
+
+ b = mp->base;
+
+ fprintf(f, "TX IRQS: %u\n", mp->stats.xirqs);
+ fprintf(f, "RX IRQS: %u\n", mp->stats.rirqs);
+ fprintf(f, "ERR IRQS: %u\n", mp->stats.eirqs);
+ fprintf(f, "LNK IRQS: %u\n", mp->stats.lirqs);
+ fprintf(f, "maxchain: %u\n", mp->stats.maxchain);
+ fprintf(f, "xpackets: %u\n", mp->stats.packet);
+ fprintf(f, "odrops: %u\n", mp->stats.odrops);
+ fprintf(f, "repack: %u\n", mp->stats.repack);
+
+ if ( mp->isfec ) {
+ fprintf(f,"FEC has no HW counters\n");
+ return;
+ }
+
+ fprintf(f,"TSEC MIB counters (modulo 2^32):\n");
+
+ fprintf(f,"RX bytes %"PRIu32"\n", fec_rd( b, TSEC_RBYT ));
+ fprintf(f,"RX pkts %"PRIu32"\n", fec_rd( b, TSEC_RPKT ));
+ fprintf(f,"RX FCS errs %"PRIu32"\n", fec_rd( b, TSEC_RFCS ));
+ fprintf(f,"RX mcst pkts %"PRIu32"\n", fec_rd( b, TSEC_RMCA ));
+ fprintf(f,"RX bcst pkts %"PRIu32"\n", fec_rd( b, TSEC_RBCA ));
+ fprintf(f,"RX pse frms %"PRIu32"\n", fec_rd( b, TSEC_RXPF ));
+ fprintf(f,"RX drop %"PRIu32"\n", fec_rd( b, TSEC_RDRP ));
+ fprintf(f,"TX bytes %"PRIu32"\n", fec_rd( b, TSEC_TBYT ));
+ fprintf(f,"TX pkts %"PRIu32"\n", fec_rd( b, TSEC_TPKT ));
+ fprintf(f,"TX FCS errs %"PRIu32"\n", fec_rd( b, TSEC_TFCS ));
+ fprintf(f,"TX mcst pkts %"PRIu32"\n", fec_rd( b, TSEC_TMCA ));
+ fprintf(f,"TX bcst pkts %"PRIu32"\n", fec_rd( b, TSEC_TBCA ));
+ fprintf(f,"TX pse frms %"PRIu32"\n", fec_rd( b, TSEC_TXPF ));
+ fprintf(f,"TX drop %"PRIu32"\n", fec_rd( b, TSEC_TDRP ));
+ fprintf(f,"TX coll %"PRIu32"\n", fec_rd( b, TSEC_TSCL ));
+ fprintf(f,"TX mcoll %"PRIu32"\n", fec_rd( b, TSEC_TMCL ));
+ fprintf(f,"TX late coll %"PRIu32"\n", fec_rd( b, TSEC_TLCL ));
+ fprintf(f,"TX exc coll %"PRIu32"\n", fec_rd( b, TSEC_TXCL ));
+ fprintf(f,"TX defer %"PRIu32"\n", fec_rd( b, TSEC_TDFR ));
+ fprintf(f,"TX exc defer %"PRIu32"\n", fec_rd( b, TSEC_TEDF ));
+ fprintf(f,"TX oversz %"PRIu32"\n", fec_rd( b, TSEC_TOVR ));
+ fprintf(f,"TX undersz %"PRIu32"\n", fec_rd( b, TSEC_TUND ));
+}
+
+/*
+ * Shutdown hardware and clean out the rings
+ */
+void
+BSP_tsec_stop_hw(struct tsec_private *mp)
+{
+unsigned i;
+ /* stop and reset hardware */
+ tsec_reset_hw( mp );
+
+ if ( mp->tx_ring_size ) {
+ /* should be OK to clear all ownership flags */
+ for ( i=0; i<mp->tx_ring_size; i++ ) {
+ bd_clrfl( &mp->tx_ring[i], TSEC_TXBD_R );
+ }
+ BSP_tsec_swipe_tx(mp);
+#if DEBUG > 0
+ tsec_dump_tring(mp);
+ fflush(stderr); fflush(stdout);
+#endif
+#ifdef PARANOIA
+ assert( mp->tx_avail == mp->tx_ring_size );
+ assert( mp->tx_head == mp->tx_tail );
+ for ( i=0; i<mp->tx_ring_size; i++ ) {
+ assert( !bd_rdbuf( & mp->tx_ring[i] ) );
+ assert( !mp->tx_ring_user[i] );
+ }
+#endif
+ }
+
+ if ( mp->rx_ring_size ) {
+ for ( i=0; i<mp->rx_ring_size; i++ ) {
+ bd_clrfl( &mp->rx_ring[i], TSEC_RXBD_E );
+ bd_wrbuf( &mp->rx_ring[i], 0 );
+ if ( mp->rx_ring_user[i] )
+ mp->consume_rxbuf( mp->rx_ring_user[i], mp->consume_rxbuf_arg, 0 );
+ mp->rx_ring_user[i] = 0;
+ }
+ }
+}
+
+/*
+ * calls BSP_tsec_stop_hw(), releases all resources and marks the interface
+ * as unused.
+ * RETURNS 0 on success, nonzero on failure.
+ * NOTE: the handle MUST NOT be used after successful execution of this
+ * routine.
+ */
+int
+BSP_tsec_detach(struct tsec_private *mp)
+{
+
+ if ( ! mp || !mp->sc || ! mp->sc->arpcom.ac_if.if_init ) {
+ fprintf(stderr,"Unit not setup -- programming error!\n");
+ return -1;
+ }
+
+ BSP_tsec_stop_hw(mp);
+
+ install_remove_isrs( 0, mp, mp->irq_mask );
+
+ free( (void*)mp->ring_area, M_DEVBUF );
+ free( (void*)mp->tx_ring_user, M_DEVBUF );
+ memset(mp, 0, sizeof(*mp));
+ __asm__ __volatile__("":::"memory");
+
+ /* mark as unused */
+ mp->sc->arpcom.ac_if.if_init = 0;
+
+ return 0;
+}
+
+/*
+ * Enqueue a mbuf chain or a raw data buffer for transmission;
+ * RETURN: #bytes sent or -1 if there are not enough free descriptors
+ *
+ * If 'len' is <=0 then 'm_head' is assumed to point to a mbuf chain.
+ * OTOH, a raw data packet (or a different type of buffer)
+ * may be sent (non-BSD driver) by pointing data_p to the start of
+ * the data and passing 'len' > 0.
+ * 'm_head' is passed back to the 'cleanup_txbuf()' callback.
+ *
+ * Comments: software cache-flushing incurs a penalty if the
+ * packet cannot be queued since it is flushed anyways.
+ * The algorithm is slightly more efficient in the normal
+ * case, though.
+ *
+ * RETURNS: # bytes enqueued to device for transmission or -1 if no
+ * space in the TX ring was available.
+ */
+
+#if 0
+#define NEXT_TXD(mp, bd) ((bd_rdfl( bd ) & TSEC_TXBD_W) ? mp->tx_ring : (bd + 1))
+#endif
+
+/*
+ * allocate a new cluster and copy an existing chain there;
+ * old chain is released...
+ */
+static struct mbuf *
+repackage_chain(struct mbuf *m_head)
+{
+struct mbuf *m;
+ MGETHDR(m, M_DONTWAIT, MT_DATA);
+
+ if ( !m ) {
+ goto bail;
+ }
+
+ MCLGET(m, M_DONTWAIT);
+
+ if ( !(M_EXT & m->m_flags) ) {
+ m_freem(m);
+ m = 0;
+ goto bail;
+ }
+
+ m_copydata(m_head, 0, MCLBYTES, mtod(m, caddr_t));
+ m->m_pkthdr.len = m->m_len = m_head->m_pkthdr.len;
+
+bail:
+ m_freem(m_head);
+ return m;
+}
+
+static inline unsigned
+tsec_assign_desc( TSEC_BD *bd, uint32_t buf, unsigned len, uint32_t flags)
+{
+ st_be16 ( &bd->len, (uint16_t)len );
+ bd_wrbuf( bd, buf );
+ bd_cslfl( bd, flags, TSEC_TXBD_R | TSEC_TXBD_L );
+ return len;
+}
+
+
+int
+BSP_tsec_send_buf(struct tsec_private *mp, void *m_head, void *data_p, int len)
+{
+int rval;
+register TSEC_BD *bd;
+register unsigned l,d,t;
+register struct mbuf *m1;
+int nmbs;
+int ismbuf = (len <= 0);
+
+#if DEBUG > 2
+ printf("send entering...\n");
+ tsec_dump_tring(mp);
+#endif
+/* Only way to get here is when we discover that the mbuf chain
+ * is too long for the tx ring
+ */
+startover:
+
+ rval = 0;
+
+#ifdef PARANOIA
+ assert(m_head);
+#endif
+
+ /* if no descriptor is available; try to wipe the queue */
+ if ( (mp->tx_avail < 1) && TSEC_CLEAN_ON_SEND(mp)<=0 ) {
+ return -1;
+ }
+
+ t = mp->tx_tail;
+
+#ifdef PARANOIA
+ assert( ! bd_rdbuf( &mp->tx_ring[t] ) );
+ assert( ! mp->tx_ring_user[t] );
+#endif
+
+ if ( ! (m1 = m_head) )
+ return 0;
+
+ if ( ismbuf ) {
+ /* find first mbuf with actual data */
+ while ( 0 == m1->m_len ) {
+ if ( ! (m1 = m1->m_next) ) {
+ /* end reached and still no data to send ?? */
+ m_freem(m_head);
+ return 0;
+ }
+ }
+ }
+
+ /* Don't use the first descriptor yet because BSP_tsec_swipe_tx()
+ * needs bd->buf == NULL as a marker. Hence, we
+ * start with the second mbuf and fill the first descriptor
+ * last.
+ */
+
+ l = t;
+ d = NEXT_TXI(mp,t);
+
+ mp->tx_avail--;
+
+ nmbs = 1;
+ if ( ismbuf ) {
+ register struct mbuf *m;
+ for ( m=m1->m_next; m; m=m->m_next ) {
+ if ( 0 == m->m_len )
+ continue; /* skip empty mbufs */
+
+ nmbs++;
+
+ if ( mp->tx_avail < 1 && TSEC_CLEAN_ON_SEND(mp)<=0 ) {
+ /* not enough descriptors; cleanup...
+ * the first slot was never used, so we start
+ * at mp->d_tx_h->next;
+ */
+ for ( l = NEXT_TXI(mp, t); l!=d; l=NEXT_TXI(mp, l) ) {
+ bd = & mp->tx_ring[l];
+#ifdef PARANOIA
+ assert( mp->tx_ring_user[l] == 0 );
+#endif
+ bd_wrbuf( bd, 0 );
+ bd_clrfl( bd, TSEC_TXBD_R | TSEC_TXBD_L );
+
+ mp->tx_avail++;
+ }
+ mp->tx_avail++;
+ if ( nmbs > TX_AVAILABLE_RING_SIZE(mp) ) {
+ /* this chain will never fit into the ring */
+ if ( nmbs > mp->stats.maxchain )
+ mp->stats.maxchain = nmbs;
+ mp->stats.repack++;
+ if ( ! (m_head = repackage_chain(m_head)) ) {
+ /* no cluster available */
+ mp->stats.odrops++;
+#ifdef PARANOIA
+ printf("send return 0\n");
+ tsec_dump_tring(mp);
+#endif
+ return 0;
+ }
+#ifdef PARANOIA
+ printf("repackaged; start over\n");
+#endif
+ goto startover;
+ }
+#ifdef PARANOIA
+ printf("send return -1\n");
+ tsec_dump_tring(mp);
+#endif
+ return -1;
+ }
+
+ mp->tx_avail--;
+
+#ifdef PARANOIA
+ assert( ! mp->tx_ring_user[d] );
+ if ( d == t ) {
+ tsec_dump_tring(mp);
+ printf("l %i, d %i, t %i, nmbs %i\n", l,d,t, nmbs);
+ } else
+ assert( d != t );
+ assert( ! bd_rdbuf( &mp->tx_ring[d] ) );
+#endif
+
+ /* fill this slot */
+ rval += tsec_assign_desc( &mp->tx_ring[d], mtod(m, uint32_t), m->m_len, TSEC_TXBD_R);
+
+ FLUSH_BUF(mtod(m, uint32_t), m->m_len);
+
+ l = d;
+ d = NEXT_TXI(mp, d);
+ }
+
+ /* fill first slot - don't release to DMA yet */
+ rval += tsec_assign_desc( &mp->tx_ring[t], mtod(m1, uint32_t), m1->m_len, 0);
+
+
+ FLUSH_BUF(mtod(m1, uint32_t), m1->m_len);
+
+ } else {
+ /* fill first slot with raw buffer - don't release to DMA yet */
+ rval += tsec_assign_desc( &mp->tx_ring[t], (uint32_t)data_p, len, 0);
+
+ FLUSH_BUF( (uint32_t)data_p, len);
+ }
+
+ /* tag last slot; this covers the case where 1st==last */
+ bd_setfl( &mp->tx_ring[l], TSEC_TXBD_L );
+
+ /* mbuf goes into last desc */
+ mp->tx_ring_user[l] = m_head;
+
+ membarrier();
+
+ /* turn over the whole chain by flipping ownership of the first desc */
+ bd_setfl( &mp->tx_ring[t], TSEC_TXBD_R );
+
+ membarrier();
+
+#if DEBUG > 2
+ printf("send return (l=%i, t=%i, d=%i) %i\n", l, t, d, rval);
+ tsec_dump_tring(mp);
+#endif
+
+ /* notify the device */
+ fec_wr( mp->base, TSEC_TSTAT, TSEC_TSTAT_THLT );
+
+ /* Update softc */
+ mp->stats.packet++;
+ if ( nmbs > mp->stats.maxchain )
+ mp->stats.maxchain = nmbs;
+
+ /* remember new tail */
+ mp->tx_tail = d;
+
+ return rval; /* #bytes sent */
+}
+
+/*
+ * Retrieve all received buffers from the RX ring, replacing them
+ * by fresh ones (obtained from the alloc_rxbuf() callback). The
+ * received buffers are passed to consume_rxbuf().
+ *
+ * RETURNS: number of buffers processed.
+ */
+int
+BSP_tsec_swipe_rx(struct tsec_private *mp)
+{
+int rval = 0, err;
+unsigned i;
+uint16_t flags;
+TSEC_BD *bd;
+void *newbuf;
+int sz;
+uint16_t len;
+uintptr_t baddr;
+
+ i = mp->rx_tail;
+ bd = mp->rx_ring + i;
+ flags = bd_rdfl( bd );
+
+ while ( ! (TSEC_RXBD_E & flags) ) {
+
+ /* err is not valid if not qualified by TSEC_RXBD_L */
+ if ( ( err = (TSEC_RXBD_ERROR & flags) ) ) {
+ /* make sure error is < 0 */
+ err |= 0xffff0000;
+ /* pass 'L' flag out so they can verify... */
+ err |= (flags & TSEC_RXBD_L);
+ }
+
+#ifdef PARANOIA
+ assert( flags & TSEC_RXBD_L );
+ assert( mp->rx_ring_user[i] );
+#endif
+
+ if ( err || !(newbuf = mp->alloc_rxbuf(&sz, &baddr)) ) {
+ /* drop packet and recycle buffer */
+ newbuf = mp->rx_ring_user[i];
+ mp->consume_rxbuf( 0, mp->consume_rxbuf_arg, err );
+ } else {
+ len = ld_be16( &bd->len );
+
+#ifdef PARANOIA
+ assert( 0 == (baddr & (RX_BUF_ALIGNMENT-1)) );
+ assert( len > 0 );
+#endif
+
+ mp->consume_rxbuf( mp->rx_ring_user[i], mp->consume_rxbuf_arg, len );
+
+ mp->rx_ring_user[i] = newbuf;
+ st_be16( &bd->len, sz );
+ bd_wrbuf( bd, baddr );
+ }
+
+ RTEMS_COMPILER_MEMORY_BARRIER();
+
+ bd_wrfl( &mp->rx_ring[i], (flags & ~TSEC_RXBD_ERROR) | TSEC_RXBD_E );
+
+ rval++;
+
+ i = NEXT_RXI( mp, i );
+ bd = mp->rx_ring + i;
+ flags = bd_rdfl( bd );
+ }
+
+ fec_wr( mp->base, TSEC_RSTAT, TSEC_RSTAT_QHLT );
+
+ mp->rx_tail = i;
+ return rval;
+}
+
+/* read ethernet address from hw to buffer */
+void
+BSP_tsec_read_eaddr(struct tsec_private *mp, unsigned char *eaddr)
+{
+union {
+ uint32_t u;
+ uint16_t s[2];
+ uint8_t c[4];
+} x;
+ st_le32( (volatile uint32_t *)(eaddr+2), fec_rd(mp->base, TSEC_MACSTNADDR1) );
+ x.u = fec_rd(mp->base, TSEC_MACSTNADDR2);
+ st_le16( (volatile uint16_t *)(eaddr), x.s[0]);
+}
+
+/* mdio / mii interface wrappers for rtems_mii_ioctl API */
+
+/*
+ * Busy-wait -- this can take a while: I measured ~550 timebase-ticks
+ * @333333333Hz, TB divisor is 8 -> 13us
+ */
+static inline void mii_wait(FEC_Enet_Base b)
+{
+ while ( (TSEC_MIIMIND_BUSY & fec_rd( b, TSEC_MIIMIND )) )
+ ;
+}
+
+/* MII operations are rather slow :-( */
+static int
+tsec_mdio_rd(int phyidx, void *uarg, unsigned reg, uint32_t *pval)
+{
+uint32_t v;
+#ifdef TEST_MII_TIMING
+uint32_t t;
+#endif
+struct tsec_private *mp = uarg;
+FEC_Enet_Base b = mp->phy_base;
+
+ if ( phyidx != 0 )
+ return -1; /* only one phy supported for now */
+
+ /* write phy and register address */
+ fec_wr( b, TSEC_MIIMADD, TSEC_MIIMADD_ADDR(mp->phy,reg) );
+
+ /* clear READ bit */
+ v = fec_rd( b, TSEC_MIIMCOM );
+ fec_wr( b, TSEC_MIIMCOM, v & ~TSEC_MIIMCOM_READ );
+
+#ifdef TEST_MII_TIMING
+ t = tb_rd();
+#endif
+
+ /* trigger READ operation by READ-bit 0-->1 transition */
+ fec_wr( b, TSEC_MIIMCOM, v | TSEC_MIIMCOM_READ );
+
+ /* (busy) wait for completion */
+
+ mii_wait( b );
+
+ /* Ugly workaround: I observed that the link status
+ * is not correctly reported when the link changes to
+ * a good status - a failed link is reported until
+ * we read twice :-(
+ */
+ if ( MII_BMSR == reg ) {
+ /* trigger a second read operation */
+ fec_wr( b, TSEC_MIIMCOM, v & ~TSEC_MIIMCOM_READ );
+ fec_wr( b, TSEC_MIIMCOM, v | TSEC_MIIMCOM_READ );
+ mii_wait( b );
+ }
+
+#ifdef TEST_MII_TIMING
+ t = tb_rd() - t;
+ printf("Reading MII took %"PRIi32"\n", t);
+#endif
+ /* return result */
+ *pval = fec_rd( b, TSEC_MIIMSTAT ) & 0xffff;
+ return 0;
+}
+
+STATIC int
+tsec_mdio_wr(int phyidx, void *uarg, unsigned reg, uint32_t val)
+{
+#ifdef TEST_MII_TIMING
+uint32_t t;
+#endif
+struct tsec_private *mp = uarg;
+FEC_Enet_Base b = mp->phy_base;
+
+ if ( phyidx != 0 )
+ return -1; /* only one phy supported for now */
+
+#ifdef TEST_MII_TIMING
+ t = tb_rd();
+#endif
+
+ fec_wr( b, TSEC_MIIMADD, TSEC_MIIMADD_ADDR(mp->phy,reg) );
+ fec_wr( b, TSEC_MIIMCON, val & 0xffff );
+
+ mii_wait( b );
+
+#ifdef TEST_MII_TIMING
+ t = tb_rd() - t;
+ printf("Writing MII took %"PRIi32"\n", t);
+#endif
+
+ return 0;
+}
+
+/* Public, locked versions */
+uint32_t
+BSP_tsec_mdio_rd(struct tsec_private *mp, unsigned reg)
+{
+uint32_t val, rval;
+
+ REGLOCK();
+ rval = tsec_mdio_rd(0, mp, reg, &val ) ? -1 : val;
+ REGUNLOCK();
+
+ return rval;
+}
+
+int
+BSP_tsec_mdio_wr(struct tsec_private *mp, unsigned reg, uint32_t val)
+{
+int rval;
+
+ REGLOCK();
+ rval = tsec_mdio_wr(0, mp, reg, val);
+ REGUNLOCK();
+
+ return rval;
+}
+
+static struct rtems_mdio_info tsec_mdio = {
+ mdio_r: tsec_mdio_rd,
+ mdio_w: tsec_mdio_wr,
+ has_gmii: 1,
+};
+
+
+/*
+ * read/write media word.
+ * 'cmd': can be SIOCGIFMEDIA, SIOCSIFMEDIA, 0 or 1. The latter
+ * are aliased to the former for convenience.
+ * 'parg': pointer to media word.
+ *
+ * RETURNS: 0 on success, nonzero on error
+ */
+int
+BSP_tsec_media_ioctl(struct tsec_private *mp, int cmd, int *parg)
+{
+int rval;
+ /* alias cmd == 0,1 for convenience when calling from shell */
+ switch ( cmd ) {
+ case 0: cmd = SIOCGIFMEDIA;
+ break;
+ case 1: cmd = SIOCSIFMEDIA;
+ case SIOCGIFMEDIA:
+ case SIOCSIFMEDIA:
+ break;
+ default: return -1;
+ }
+ REGLOCK();
+ tsec_mdio.has_gmii = mp->isfec ? 0 : 1;
+ rval = rtems_mii_ioctl(&tsec_mdio, mp, cmd, parg);
+ REGUNLOCK();
+ return rval;
+}
+
+/* Interrupt related routines */
+
+/*
+ * When it comes to interrupts the chip has two rather
+ * annoying features:
+ * 1 once an IRQ is pending, clearing the IMASK does not
+ * de-assert the interrupt line.
+ * 2 the chip has three physical interrupt lines even though
+ * all events are reported in a single register. Rather
+ * useless; we must hook 3 ISRs w/o any real benefit.
+ * In fact, it makes our life a bit more difficult:
+ *
+ * Hence, for (1) we would have to mask interrupts at the PIC
+ * but to re-enable them we would have to do that three times
+ * because of (2).
+ *
+ * Therefore, we take the following approach:
+ *
+ * ISR masks all interrupts on the TSEC, acks/clears them
+ * and stores the acked irqs in the device struct where
+ * it is picked up by BSP_tsec_ack_irqs().
+ * Since all interrupts are disabled until the daemon
+ * re-enables them after calling BSP_tsec_ack_irqs()
+ * no interrupts are lost.
+ *
+ * BUT: NO isr (including PHY isrs) MUST INTERRUPT ANY
+ * OTHER ONE, i.e., they all must have the same
+ * priority. Otherwise, integrity of the cached
+ * irq_pending variable may be compromised.
+ */
+
+static inline void
+tsec_dis_irqs( struct tsec_private *mp)
+{
+ phy_dis_irq( mp );
+ fec_wr( mp->base, TSEC_IMASK, TSEC_IMASK_NONE );
+}
+
+static inline uint32_t
+tsec_dis_clr_irqs(struct tsec_private *mp)
+{
+uint32_t rval;
+FEC_Enet_Base b = mp->base;
+ tsec_dis_irqs( mp );
+ rval = fec_rd( b, TSEC_IEVENT);
+ fec_wr( b, TSEC_IEVENT, rval );
+ /* Make sure we mask out the link intr */
+ return rval & ~TSEC_LINK_INTR;
+}
+
+/*
+ * We have 3 different ISRs just so we can count
+ * interrupt types independently...
+ */
+
+static void tsec_xisr(rtems_irq_hdl_param arg)
+{
+struct tsec_private *mp = (struct tsec_private *)arg;
+
+ mp->irq_pending |= tsec_dis_clr_irqs( mp );
+
+ mp->stats.xirqs++;
+
+ rtems_event_send( mp->tid, mp->event );
+}
+
+static void tsec_risr(rtems_irq_hdl_param arg)
+{
+struct tsec_private *mp = (struct tsec_private *)arg;
+
+ mp->irq_pending |= tsec_dis_clr_irqs( mp );
+
+ mp->stats.rirqs++;
+
+ rtems_event_send( mp->tid, mp->event );
+}
+
+static void tsec_eisr(rtems_irq_hdl_param arg)
+{
+struct tsec_private *mp = (struct tsec_private *)arg;
+
+ mp->irq_pending |= tsec_dis_clr_irqs( mp );
+
+ mp->stats.eirqs++;
+
+ rtems_event_send( mp->tid, mp->event );
+}
+
+static void tsec_lisr(rtems_irq_hdl_param arg)
+{
+struct tsec_private *mp = (struct tsec_private *)arg;
+
+ if ( phy_irq_pending( mp ) ) {
+
+ tsec_dis_irqs( mp );
+
+ mp->irq_pending |= TSEC_LINK_INTR;
+
+ mp->stats.lirqs++;
+
+ rtems_event_send( mp->tid, mp->event );
+ }
+}
+
+/* Enable interrupts at device */
+void
+BSP_tsec_enable_irqs(struct tsec_private *mp)
+{
+rtems_interrupt_level l;
+ rtems_interrupt_disable( l );
+ fec_wr( mp->base, TSEC_IMASK, mp->irq_mask );
+ phy_en_irq( mp );
+ rtems_interrupt_enable( l );
+}
+
+/* Disable interrupts at device */
+void
+BSP_tsec_disable_irqs(struct tsec_private *mp)
+{
+rtems_interrupt_level l;
+ rtems_interrupt_disable( l );
+ tsec_dis_irqs( mp );
+ rtems_interrupt_enable( l );
+}
+
+/*
+ * Acknowledge (and clear) interrupts.
+ * RETURNS: interrupts that were raised.
+ */
+uint32_t
+BSP_tsec_ack_irqs(struct tsec_private *mp)
+{
+uint32_t rval;
+
+ /* no need to disable interrupts because
+ * this should only be called after receiving
+ * a RTEMS event posted by the ISR which
+ * already shut off interrupts.
+ */
+ rval = mp->irq_pending;
+ mp->irq_pending = 0;
+
+ if ( (rval & TSEC_LINK_INTR) ) {
+ /* interacting with the PHY is slow so
+ * we do it only if we have to...
+ */
+ phy_ack_irq( mp );
+ }
+
+ return rval & mp->irq_mask;
+}
+
+/* Retrieve the driver daemon TID that was passed to
+ * BSP_tsec_setup().
+ */
+
+rtems_id
+BSP_tsec_get_tid(struct tsec_private *mp)
+{
+ return mp->tid;
+}
+
+struct tsec_private *
+BSP_tsec_getp(unsigned index)
+{
+ if ( index >= TSEC_NUM_DRIVER_SLOTS )
+ return 0;
+ return & theTsecEths[index].pvt;
+}
+
+/*
+ *
+ * Example driver task loop (note: no synchronization of
+ * buffer access shown!).
+ * RTEMS_EVENTx = 0,1 or 2 depending on IF unit.
+ *
+ * / * setup (obtain handle) and initialize hw here * /
+ *
+ * do {
+ * / * ISR disables IRQs and posts event * /
+ * rtems_event_receive( RTEMS_EVENTx, RTEMS_WAIT | RTEMS_EVENT_ANY, RTEMS_NO_TIMEOUT, &evs );
+ * irqs = BSP_tsec_ack_irqs(handle);
+ * if ( irqs & BSP_TSEC_IRQ_TX ) {
+ * BSP_tsec_swipe_tx(handle); / * cleanup_txbuf() callback executed * /
+ * }
+ * if ( irqs & BSP_TSEC_IRQ_RX ) {
+ * BSP_tsec_swipe_rx(handle); / * alloc_rxbuf() and consume_rxbuf() executed * /
+ * }
+ * BSP_tsec_enable_irqs(handle);
+ * } while (1);
+ *
+ */
+
+/* BSDNET SUPPORT/GLUE ROUTINES */
+
+STATIC void
+tsec_stop(struct tsec_softc *sc)
+{
+ BSP_tsec_stop_hw(&sc->pvt);
+ sc->arpcom.ac_if.if_timer = 0;
+}
+
+/* allocate a mbuf for RX with a properly aligned data buffer
+ * RETURNS 0 if allocation fails
+ */
+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 void consume_rx_mbuf(void *buf, void *arg, int len)
+{
+struct ifnet *ifp = arg;
+ if ( len <= 0 ) {
+ ifp->if_iqdrops++;
+ if ( len < 0 ) {
+ ifp->if_ierrors++;
+ }
+ /* caller recycles mbuf */
+ } else {
+ struct ether_header *eh;
+ struct mbuf *m = buf;
+
+ 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 - ETH_CRC_LEN;
+ m->m_data += sizeof(struct ether_header) + ETH_RX_OFFSET;
+ m->m_pkthdr.rcvif = ifp;
+
+ ifp->if_ipackets++;
+ ifp->if_ibytes += m->m_pkthdr.len;
+
+ /* send buffer upwards */
+ if (0) {
+ /* Low-level debugging */
+ int i;
+ for (i=0; i<13; i++) {
+ printf("%02X:",((char*)eh)[i]);
+ }
+ printf("%02X\n",((char*)eh)[i]);
+ for (i=0; i<m->m_len; i++) {
+ if ( !(i&15) )
+ printf("\n");
+ printf("0x%02x ",mtod(m,char*)[i]);
+ }
+ printf("\n");
+ }
+
+ if (0) /* Low-level debugging/testing without bsd stack */
+ m_freem(m);
+ else
+ ether_input(ifp, eh, m);
+ }
+}
+
+static void release_tx_mbuf(void *buf, void *arg, int err)
+{
+struct ifnet *ifp = arg;
+struct mbuf *mb = buf;
+
+ if ( err ) {
+ ifp->if_oerrors++;
+ } else {
+ ifp->if_opackets++;
+ }
+ ifp->if_obytes += mb->m_pkthdr.len;
+ m_freem(mb);
+}
+
+/* BSDNET DRIVER CALLBACKS */
+
+static void
+tsec_init(void *arg)
+{
+struct tsec_softc *sc = arg;
+struct ifnet *ifp = &sc->arpcom.ac_if;
+ BSP_tsec_init_hw(&sc->pvt, ifp->if_flags & IFF_PROMISC, sc->arpcom.ac_enaddr);
+ ifp->if_flags |= IFF_RUNNING;
+ sc->arpcom.ac_if.if_timer = 0;
+}
+
+/* bsdnet driver entry to start transmission */
+static void
+tsec_start(struct ifnet *ifp)
+{
+struct tsec_softc *sc = ifp->if_softc;
+struct mbuf *m = 0;
+
+ while ( ifp->if_snd.ifq_head ) {
+ IF_DEQUEUE( &ifp->if_snd, m );
+ if ( BSP_tsec_send_buf(&sc->pvt, m, 0, 0) < 0 ) {
+ IF_PREPEND( &ifp->if_snd, m);
+ ifp->if_flags |= IFF_OACTIVE;
+ break;
+ }
+ /* need to do this really only once
+ * but it's cheaper this way.
+ */
+ ifp->if_timer = 2*IFNET_SLOWHZ;
+ }
+}
+
+/* bsdnet driver entry; */
+static void
+tsec_watchdog(struct ifnet *ifp)
+{
+struct tsec_softc *sc = ifp->if_softc;
+
+ ifp->if_oerrors++;
+ printk(DRVNAME"%i: watchdog timeout; resetting\n", ifp->if_unit);
+
+ tsec_init(sc);
+ tsec_start(ifp);
+}
+
+/* bsdnet driver ioctl entry */
+static int
+tsec_ioctl(struct ifnet *ifp, ioctl_command_t cmd, caddr_t data)
+{
+struct tsec_softc *sc = ifp->if_softc;
+struct ifreq *ifr = (struct ifreq *)data;
+#if 0
+uint32_t v;
+#endif
+int error = 0;
+int f;
+
+ switch ( cmd ) {
+ case SIOCSIFFLAGS:
+ f = ifp->if_flags;
+ if ( f & IFF_UP ) {
+ if ( ! ( f & IFF_RUNNING ) ) {
+ tsec_init(sc);
+ } else {
+ if ( (f & IFF_PROMISC) != (sc->bsd.oif_flags & IFF_PROMISC) ) {
+ /* Hmm - the manual says we must change the RCTRL
+ * register only after a reset or if DMACTRL[GRS]
+ * is cleared which is the normal operating
+ * condition. I hope this is legal ??
+ */
+ if ( (f & IFF_PROMISC) ) {
+ fec_set( sc->pvt.base, TSEC_RCTRL, TSEC_RCTRL_PROM );
+ } else {
+ fec_clr( sc->pvt.base, TSEC_RCTRL, TSEC_RCTRL_PROM );
+ }
+ }
+ /* FIXME: other flag changes are ignored/unimplemented */
+ }
+ } else {
+ if ( f & IFF_RUNNING ) {
+ tsec_stop(sc);
+ ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
+ }
+ }
+ sc->bsd.oif_flags = ifp->if_flags;
+ break;
+
+ case SIOCGIFMEDIA:
+ case SIOCSIFMEDIA:
+ error = BSP_tsec_media_ioctl(&sc->pvt, cmd, &ifr->ifr_media);
+ break;
+
+/*
+ * TODO
+ *
+ * case SIOCADDMULTI:
+ * case SIOCDELMULTI:
+ *
+ * break;
+ */
+
+
+ case SIO_RTEMS_SHOW_STATS:
+ BSP_tsec_dump_stats( &sc->pvt, stdout );
+ break;
+
+ default:
+ error = ether_ioctl(ifp, cmd, data);
+ break;
+ }
+
+ return error;
+}
+
+/* DRIVER TASK */
+
+/* Daemon task does all the 'interrupt' work */
+static void tsec_daemon(void *arg)
+{
+struct tsec_softc *sc;
+struct ifnet *ifp;
+rtems_event_set evs;
+ for (;;) {
+ rtems_bsdnet_event_receive( EV_MSK, RTEMS_WAIT | RTEMS_EVENT_ANY, RTEMS_NO_TIMEOUT, &evs );
+ evs &= EV_MSK;
+ for ( sc = theTsecEths; evs; evs>>=EV_PER_UNIT, sc++ ) {
+ if ( EV_IS_ANY(evs) ) {
+
+ register uint32_t x;
+
+ ifp = &sc->arpcom.ac_if;
+
+ if ( !(ifp->if_flags & IFF_UP) ) {
+ tsec_stop(sc);
+ ifp->if_flags &= ~(IFF_UP|IFF_RUNNING);
+ continue;
+ }
+
+ if ( !(ifp->if_flags & IFF_RUNNING) ) {
+ /* event could have been pending at the time hw was stopped;
+ * just ignore...
+ */
+ continue;
+ }
+
+ x = BSP_tsec_ack_irqs(&sc->pvt);
+
+ if ( TSEC_LINK_INTR & x ) {
+ /* phy status changed */
+ int media;
+
+#ifdef DEBUG
+ printf("LINK INTR\n");
+#endif
+ if ( -1 != (media = mac_set_duplex( &sc->pvt )) ) {
+#ifdef DEBUG
+ rtems_ifmedia2str( media, 0, 0 );
+ printf("\n");
+#endif
+ if ( IFM_LINK_OK & media ) {
+ ifp->if_flags &= ~IFF_OACTIVE;
+ tsec_start(ifp);
+ } else {
+ /* stop sending */
+ ifp->if_flags |= IFF_OACTIVE;
+ }
+ }
+ }
+
+ /* free tx chain */
+ if ( (TSEC_TXIRQ & x) && BSP_tsec_swipe_tx(&sc->pvt) ) {
+ ifp->if_flags &= ~IFF_OACTIVE;
+ if ( TX_AVAILABLE_RING_SIZE(&sc->pvt) == sc->pvt.tx_avail )
+ ifp->if_timer = 0;
+ tsec_start(ifp);
+ }
+ if ( (TSEC_RXIRQ & x) )
+ BSP_tsec_swipe_rx(&sc->pvt);
+
+ BSP_tsec_enable_irqs(&sc->pvt);
+ }
+ }
+ }
+}
+
+/* PUBLIC RTEMS BSDNET ATTACH FUNCTION */
+int
+rtems_tsec_attach(struct rtems_bsdnet_ifconfig *ifcfg, int attaching)
+{
+char *unitName;
+int unit,i,cfgUnits;
+struct tsec_softc *sc;
+struct ifnet *ifp;
+
+ unit = rtems_bsdnet_parse_driver_name(ifcfg, &unitName);
+ if ( unit <= 0 || unit > TSEC_NUM_DRIVER_SLOTS ) {
+ printk(DRVNAME": Bad unit number %i; must be 1..%i\n", unit, TSEC_NUM_DRIVER_SLOTS);
+ return 1;
+ }
+
+ sc = &theTsecEths[unit-1];
+ ifp = &sc->arpcom.ac_if;
+
+ if ( attaching ) {
+ if ( ifp->if_init ) {
+ printk(DRVNAME": instance %i already attached.\n", unit);
+ return -1;
+ }
+
+ for ( i=cfgUnits = 0; i<TSEC_NUM_DRIVER_SLOTS; i++ ) {
+ if ( theTsecEths[i].arpcom.ac_if.if_init )
+ cfgUnits++;
+ }
+ cfgUnits++; /* this new one */
+
+ /* lazy init of TID should still be thread-safe because we are protected
+ * by the global networking semaphore..
+ */
+ if ( !tsec_tid ) {
+ /* newproc uses the 1st 4 chars of name string to build an rtems name */
+ tsec_tid = rtems_bsdnet_newproc("FECd", 4096, tsec_daemon, 0);
+ }
+
+ if ( !BSP_tsec_setup( unit,
+ tsec_tid,
+ release_tx_mbuf, ifp,
+ alloc_mbuf_rx,
+ consume_rx_mbuf, ifp,
+ ifcfg->rbuf_count,
+ ifcfg->xbuf_count,
+ TSEC_RXIRQ | TSEC_TXIRQ | TSEC_LINK_INTR) ) {
+ return -1;
+ }
+
+ if ( nmbclusters < sc->pvt.rx_ring_size * cfgUnits + 60 /* arbitrary */ ) {
+ printk(DRVNAME"%i: (tsec ethernet) Your application has not enough mbuf clusters\n", unit);
+ printk( " configured for this driver.\n");
+ return -1;
+ }
+
+ if ( ifcfg->hardware_address ) {
+ memcpy(sc->arpcom.ac_enaddr, ifcfg->hardware_address, ETHER_ADDR_LEN);
+ } else {
+ /* read back from hardware assuming that MotLoad already had set it up */
+ BSP_tsec_read_eaddr(&sc->pvt, sc->arpcom.ac_enaddr);
+ }
+
+ ifp->if_softc = sc;
+ ifp->if_unit = unit;
+ ifp->if_name = unitName;
+
+ ifp->if_mtu = ifcfg->mtu ? ifcfg->mtu : ETHERMTU;
+
+ ifp->if_init = tsec_init;
+ ifp->if_ioctl = tsec_ioctl;
+ ifp->if_start = tsec_start;
+ ifp->if_output = ether_output;
+ /*
+ * While nonzero, the 'if->if_timer' is decremented
+ * (by the networking code) at a rate of IFNET_SLOWHZ (1hz) and 'if_watchdog'
+ * is called when it expires.
+ * If either of those fields is 0 the feature is disabled.
+ */
+ ifp->if_watchdog = tsec_watchdog;
+ ifp->if_timer = 0;
+
+ sc->bsd.oif_flags = /* ... */
+ ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
+
+ /*
+ * if unset, this set to 10Mbps by ether_ifattach; seems to be unused by bsdnet stack;
+ * could be updated along with phy speed, though...
+ ifp->if_baudrate = 10000000;
+ */
+
+ /* NOTE: ether_output drops packets if ifq_len >= ifq_maxlen
+ * but this is the packet count, not the fragment count!
+ ifp->if_snd.ifq_maxlen = sc->pvt.tx_ring_size;
+ */
+ ifp->if_snd.ifq_maxlen = ifqmaxlen;
+
+#ifdef TSEC_DETACH_HACK
+ if ( !ifp->if_addrlist ) /* do only the first time [reattach hack] */
+#endif
+ {
+ if_attach(ifp);
+ ether_ifattach(ifp);
+ }
+
+ } else {
+#ifdef TSEC_DETACH_HACK
+ if ( !ifp->if_init ) {
+ printk(DRVNAME": instance %i not attached.\n", unit);
+ return -1;
+ }
+ return tsec_detach(sc);
+#else
+ printk(DRVNAME": interface detaching not implemented\n");
+ return -1;
+#endif
+ }
+
+ return 0;
+}
+
+/* PHY stuff should really not be in this driver but separate :-(
+ * However, I don't have time right now to implement clean
+ * boundaries:
+ * - PHY driver should only know about the PHY
+ * - TSEC driver only provides MII access and knows
+ * how to deal with a PHY interrupt.
+ * - BSP knows how interrupts are routed. E.g., the MVME3100
+ * shares a single IRQ line among 3 PHYs (for the three ports)
+ * and provides a special 'on-board' register for determining
+ * what PHY raised an interrupt w/o the need to do any MII IO.
+ * Integrating all these bits in a clean way is not as easy as
+ * just hacking away, sorry...
+ */
+
+/*
+ * Broadcom 54xx PHY register definitions. Unfriendly Broadcom doesn't
+ * release specs for their products :-( -- valuable info comes from
+ * the linux driver by
+ * Maciej W. Rozycki <macro@linux-mips.org>
+ * Amy Fong
+ */
+
+#define BCM54xx_GBCR 0x09 /* gigabit control */
+#define BCM54xx_GBCR_FD (1<<9) /* full-duplex cap. */
+
+#define BCM54xx_ECR 0x10 /* extended control */
+#define BCM54xx_ECR_IM (1<<12) /* IRQ mask */
+#define BCM54xx_ECR_IF (1<<12) /* IRQ force */
+
+#define BCM54xx_ESR 0x11 /* extended status */
+#define BCM54xx_ESR_IRQ (1<<12) /* IRQ pending */
+
+#define BCM54xx_AUXCR 0x18 /* AUX control */
+#define BCM54xx_AUXCR_PWR10BASET (1<<2)
+
+#define BCM54xx_AUXST 0x19 /* AUX status */
+#define BCM54xx_AUXST_LNKMM (7<<8) /* link mode mask */
+
+/* link mode (linux' syngem_phy.c helped here...)
+ *
+ * 0: no link
+ * 1: 10BT half
+ * 2: 10BT full
+ * 3: 100BT half
+ * 4: 100BT half
+ * 5: 100BT full
+ * 6: 1000BT full
+ * 7: 1000BT full
+ */
+
+#define BCM54xx_ISR 0x1a /* IRQ status */
+#define BCM54xx_IMR 0x1b /* IRQ mask */
+#define BCM54xx_IRQ_CRC (1<< 0) /* CRC error */
+#define BCM54xx_IRQ_LNK (1<< 1) /* LINK status chg. */
+#define BCM54xx_IRQ_SPD (1<< 2) /* SPEED change */
+#define BCM54xx_IRQ_DUP (1<< 3) /* LINK status chg. */
+#define BCM54xx_IRQ_LRS (1<< 4) /* Lcl. RX status chg.*/
+#define BCM54xx_IRQ_RRS (1<< 5) /* Rem. RX status chg.*/
+#define BCM54xx_IRQ_SSE (1<< 6) /* Scrambler sync err */
+#define BCM54xx_IRQ_UHCD (1<< 7) /* Unsupp. HCD neg. */
+#define BCM54xx_IRQ_NHCD (1<< 8) /* No HCD */
+#define BCM54xx_IRQ_HCDL (1<< 9) /* No HCD Link */
+#define BCM54xx_IRQ_ANPR (1<<10) /* Aneg. pg. req. */
+#define BCM54xx_IRQ_LC (1<<11) /* All ctrs. < 128 */
+#define BCM54xx_IRQ_HC (1<<12) /* Ctr > 32768 */
+#define BCM54xx_IRQ_MDIX (1<<13) /* MDIX status chg. */
+#define BCM54xx_IRQ_PSERR (1<<14) /* Pair swap error */
+
+#define PHY_IRQS ( BCM54xx_IRQ_LNK | BCM54xx_IRQ_SPD | BCM54xx_IRQ_DUP )
+
+
+static void
+phy_en_irq_at_phy( struct tsec_private *mp )
+{
+uint32_t ecr;
+
+ REGLOCK();
+ tsec_mdio_rd( 0, mp, BCM54xx_ECR, &ecr );
+ ecr &= ~BCM54xx_ECR_IM;
+ tsec_mdio_wr( 0, mp, BCM54xx_ECR, ecr );
+ REGUNLOCK();
+}
+
+static void
+phy_dis_irq_at_phy( struct tsec_private *mp )
+{
+uint32_t ecr;
+
+ REGLOCK();
+ tsec_mdio_rd( 0, mp, BCM54xx_ECR, &ecr );
+ ecr |= BCM54xx_ECR_IM;
+ tsec_mdio_wr( 0, mp, BCM54xx_ECR, ecr );
+ REGUNLOCK();
+}
+
+static void
+phy_init_irq( int install, struct tsec_private *mp, void (*isr)(rtems_irq_hdl_param) )
+{
+uint32_t v;
+rtems_irq_connect_data xxx;
+
+ xxx.on = noop;
+ xxx.off = noop;
+ xxx.isOn = nopf;
+ xxx.name = BSP_PHY_IRQ;
+ xxx.handle = mp;
+ xxx.hdl = isr;
+
+ phy_dis_irq_at_phy( mp );
+
+ REGLOCK();
+ /* Select IRQs we want */
+ tsec_mdio_wr( 0, mp, BCM54xx_IMR, ~ PHY_IRQS );
+ /* clear pending irqs */
+ tsec_mdio_rd( 0, mp, BCM54xx_ISR, &v );
+ REGUNLOCK();
+
+ /* install shared ISR */
+ if ( ! (install ?
+ BSP_install_rtems_shared_irq_handler( &xxx ) :
+ BSP_remove_rtems_irq_handler( &xxx )) ) {
+ rtems_panic( "Unable to %s shared irq handler (PHY)\n", install ? "install" : "remove" );
+ }
+}
+
+/* Because on the MVME3100 multiple PHYs (belonging to different
+ * TSEC instances) share a single interrupt line and we want
+ * to disable interrupts at the PIC rather than in the individual
+ * PHYs (because access to those is slow) we must implement
+ * nesting...
+ */
+STATIC int phy_irq_dis_level = 0;
+
+/* assume 'en_irq' / 'dis_irq' cannot be interrupted.
+ * Either because they are called from an ISR (all
+ * tsec + phy isrs must have the same priority) or
+ * from a IRQ-protected section of code
+ */
+static void
+phy_en_irq(struct tsec_private *mp)
+{
+ if ( ! ( --phy_irq_dis_level ) ) {
+ BSP_enable_irq_at_pic( BSP_PHY_IRQ );
+ }
+}
+
+
+static void
+phy_dis_irq(struct tsec_private *mp)
+{
+ if ( !(phy_irq_dis_level++) ) {
+ BSP_disable_irq_at_pic( BSP_PHY_IRQ );
+ }
+}
+
+static int
+phy_irq_pending(struct tsec_private *mp)
+{
+ /* MVME3100 speciality: we can check for a pending
+ * PHY IRQ w/o having to access the MII bus :-)
+ */
+ return in_8( BSP_MVME3100_IRQ_DETECT_REG ) & (1 << (mp->unit - 1));
+}
+
+static uint32_t
+phy_ack_irq(struct tsec_private *mp)
+{
+uint32_t v;
+
+ REGLOCK();
+ tsec_mdio_rd( 0, mp, BCM54xx_ISR, &v );
+ REGUNLOCK();
+
+#ifdef DEBUG
+ printf("phy_ack_irq: 0x%08"PRIx32"\n", v);
+#endif
+
+ return v;
+}
+
+#if defined(PARANOIA) || defined(DEBUG)
+
+static void dumpbd(TSEC_BD *bd)
+{
+ printf("Flags 0x%04"PRIx16", len 0x%04"PRIx16", buf 0x%08"PRIx32"\n",
+ bd_rdfl( bd ), ld_be16( &bd->len ), bd_rdbuf( bd ) );
+}
+
+void tsec_dump_rring(struct tsec_private *mp)
+{
+int i;
+TSEC_BD *bd;
+ if ( !mp ) {
+ printf("Neet tsec_private * arg\n");
+ return;
+ }
+ for ( i=0; i<mp->rx_ring_size; i++ ) {
+ bd = &mp->rx_ring[i];
+ printf("[%i]: ", i);
+ dumpbd(bd);
+ }
+}
+
+void tsec_dump_tring(struct tsec_private *mp)
+{
+int i;
+TSEC_BD *bd;
+ if ( !mp ) {
+ printf("Neet tsec_private * arg\n");
+ return;
+ }
+ for ( i=0; i<mp->tx_ring_size; i++ ) {
+ bd = &mp->tx_ring[i];
+ printf("[%i]: ", i);
+ dumpbd(bd);
+ }
+ printf("Avail: %i; Head %i; Tail %i\n", mp->tx_avail, mp->tx_head, mp->tx_tail);
+}
+#endif
+
+
+#ifdef DEBUG
+
+#undef free
+#undef malloc
+
+#include <stdlib.h>
+
+void cleanup_txbuf_test(void *u, void *a, int err)
+{
+ printf("cleanup_txbuf_test (releasing buf 0x%8p)\n", u);
+ free(u);
+ if ( err )
+ printf("cleanup_txbuf_test: an error was detected\n");
+}
+
+void *alloc_rxbuf_test(int *p_size, uintptr_t *p_data_addr)
+{
+void *rval;
+
+ *p_size = 1600;
+ rval = malloc( *p_size + RX_BUF_ALIGNMENT );
+ *p_data_addr = (uintptr_t)ALIGNTO(rval,RX_BUF_ALIGNMENT);
+
+ /* PRIxPTR is still broken :-( */
+ printf("alloc_rxxbuf_test: allocated %i bytes @0x%8p/0x%08"PRIx32"\n",
+ *p_size, rval, (uint32_t)*p_data_addr);
+
+ return rval;
+}
+
+void consume_rxbuf_test(void *user_buf, void *consume_rxbuf_arg, int len)
+{
+int i;
+uintptr_t d = (uintptr_t)ALIGNTO(user_buf,RX_BUF_ALIGNMENT);
+
+ /* PRIxPTR is still broken */
+ printf("consuming rx buf 0x%8p (data@ 0x%08"PRIx32")\n",user_buf, (uint32_t)d);
+ if ( len > 32 )
+ len = 32;
+ if ( len < 0 )
+ printf("consume_rxbuf_test: ERROR occurred: 0x%x\n", len);
+ else {
+ printf("RX:");
+ for ( i=0; i<len; i++ ) {
+ if ( 0 == (i&0xf) )
+ printf("\n ");
+ printf("0x%02x ", ((char*)d)[i]);
+ }
+ printf("\n");
+ free(user_buf);
+ }
+}
+
+unsigned char pkt[100];
+
+void * tsec_up()
+{
+struct tsec_private *tsec =
+ BSP_tsec_setup( 1, 0,
+ cleanup_txbuf_test, 0,
+ alloc_rxbuf_test,
+ consume_rxbuf_test, 0,
+ 2,
+ 2,
+ 0);
+ BSP_tsec_init_hw(tsec, 0, 0);
+ memset(pkt,0,100);
+ memset(pkt,0xff,6);
+ BSP_tsec_read_eaddr(tsec, pkt+6);
+ pkt[12] = 0;
+ pkt[13] = 64;
+ return tsec;
+}
+
+#ifdef DEBUG_MODULAR
+int
+_cexpModuleInitialize(void*u)
+{
+extern int ifattach();
+extern int ifconf();
+extern int rtconf();
+ ifattach("ts1",rtems_tsec_attach,0);
+ ifconf("ts1","134.79.33.137","255.255.252.0");
+ ifconf("pcn1",0,0);
+ rtconf(0, "134.79.33.86",0,0);
+ return 0;
+}
+#endif
+#endif
diff --git a/c/src/lib/libbsp/powerpc/mvme3100/pci/detect_host_bridge.c b/c/src/lib/libbsp/powerpc/mvme3100/pci/detect_host_bridge.c
new file mode 100644
index 0000000000..a200d41019
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/mvme3100/pci/detect_host_bridge.c
@@ -0,0 +1,115 @@
+/* $Id$ */
+
+/* PCI Initialization */
+
+/*
+ * Authorship
+ * ----------
+ * This software ('mvme3100' RTEMS BSP) was created by
+ *
+ * Till Straumann <strauman@slac.stanford.edu>, 2005-2007,
+ * Stanford Linear Accelerator Center, Stanford University.
+ *
+ * Acknowledgement of sponsorship
+ * ------------------------------
+ * The 'mvme3100' BSP was produced by
+ * the Stanford Linear Accelerator Center, Stanford University,
+ * under Contract DE-AC03-76SFO0515 with the Department of Energy.
+ *
+ * Government disclaimer of liability
+ * ----------------------------------
+ * Neither the United States nor the United States Department of Energy,
+ * nor any of their employees, makes any warranty, express or implied, or
+ * assumes any legal liability or responsibility for the accuracy,
+ * completeness, or usefulness of any data, apparatus, product, or process
+ * disclosed, or represents that its use would not infringe privately owned
+ * rights.
+ *
+ * Stanford disclaimer of liability
+ * --------------------------------
+ * Stanford University makes no representations or warranties, express or
+ * implied, nor assumes any liability for the use of this software.
+ *
+ * Stanford disclaimer of copyright
+ * --------------------------------
+ * Stanford University, owner of the copyright, hereby disclaims its
+ * copyright and all other rights in this software. Hence, anyone may
+ * freely use it for any purpose without restriction.
+ *
+ * Maintenance of notices
+ * ----------------------
+ * In the interest of clarity regarding the origin and status of this
+ * SLAC software, this and all the preceding Stanford University notices
+ * are to remain affixed to any copy or derivative of this software made
+ * or distributed by the recipient and are to be affixed to any copy of
+ * software made or distributed by the recipient that contains a copy or
+ * derivative of this software.
+ *
+ * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03
+ */
+
+#include <bsp.h>
+#include <bsp/pci.h>
+#include <bsp/irq.h>
+#include <bsp/openpic.h>
+#include <inttypes.h>
+
+/* Motload configures PCI interrupts to start at 16 and up but
+ * we'd rather have them starting at 0.
+ * Use this callback to fix them up.
+ */
+static int
+fixup_irq_line(int bus, int slot, int fun, void *uarg)
+{
+unsigned char line;
+ pci_read_config_byte( bus, slot, fun, PCI_INTERRUPT_LINE, &line);
+ if ( line >= BSP_EXT_IRQ_NUMBER ) {
+ pci_write_config_byte( bus, slot, fun, PCI_INTERRUPT_LINE, line - BSP_EXT_IRQ_NUMBER );
+ }
+
+ return 0;
+}
+
+void BSP_motload_pci_fixup()
+{
+ BSP_pciScan(0, fixup_irq_line, 0);
+}
+
+void detect_host_bridge()
+{
+ OpenPIC = (volatile struct OpenPIC *) (BSP_8540_CCSR_BASE + BSP_OPEN_PIC_BASE_OFFSET);
+}
+
+static int
+dump_dev_cb(
+ int bus,
+ int dev,
+ int fun,
+ void *uarg
+)
+{
+ uint16_t vi,di;
+ uint16_t cd,st;
+ uint32_t b1,b2;
+ uint8_t il,ip;
+
+ pci_read_config_word (bus, dev, fun, PCI_VENDOR_ID, &vi);
+ pci_read_config_word (bus, dev, fun, PCI_DEVICE_ID, &di);
+ pci_read_config_word (bus, dev, fun, PCI_COMMAND, &cd);
+ pci_read_config_word (bus, dev, fun, PCI_STATUS, &st);
+ pci_read_config_dword(bus, dev, fun, PCI_BASE_ADDRESS_0, &b1);
+ pci_read_config_dword(bus, dev, fun, PCI_BASE_ADDRESS_1, &b2);
+ pci_read_config_byte (bus, dev, fun, PCI_INTERRUPT_LINE, &il);
+ pci_read_config_byte (bus, dev, fun, PCI_INTERRUPT_PIN, &ip);
+
+ printk("%3d:0x%02x:%d 0x%04x-0x%04x: 0x%04x 0x%04x 0x%08x 0x%08x %d -> %3d (=0x%02x)\n",
+ bus, dev, fun, vi, di, cd, st, b1, b2, ip, il, il);
+ return 0;
+}
+
+void
+BSP_pciConfigDump_early()
+{
+ printk("BUS:SLOT:FUN VENDOR-DEV_ID: COMMAND STATUS BASE_ADDR0 BASE_ADDR1 IRQ_PIN -> IRQ_LINE\n");
+ BSP_pciScan(0, dump_dev_cb, 0);
+}
diff --git a/c/src/lib/libbsp/powerpc/mvme3100/preinstall.am b/c/src/lib/libbsp/powerpc/mvme3100/preinstall.am
new file mode 100644
index 0000000000..76a8db09dd
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/mvme3100/preinstall.am
@@ -0,0 +1,143 @@
+## Automatically generated by ampolish3 - Do not edit
+
+if AMPOLISH3
+$(srcdir)/preinstall.am: Makefile.am
+ $(AMPOLISH3) $(srcdir)/Makefile.am > $(srcdir)/preinstall.am
+endif
+
+PREINSTALL_DIRS =
+DISTCLEANFILES += $(PREINSTALL_DIRS)
+
+all-local: $(TMPINSTALL_FILES)
+
+TMPINSTALL_FILES =
+CLEANFILES = $(TMPINSTALL_FILES)
+
+all-am: $(PREINSTALL_FILES)
+
+PREINSTALL_FILES =
+CLEANFILES += $(PREINSTALL_FILES)
+
+$(PROJECT_LIB)/$(dirstamp):
+ @$(MKDIR_P) $(PROJECT_LIB)
+ @: > $(PROJECT_LIB)/$(dirstamp)
+PREINSTALL_DIRS += $(PROJECT_LIB)/$(dirstamp)
+
+$(PROJECT_INCLUDE)/$(dirstamp):
+ @$(MKDIR_P) $(PROJECT_INCLUDE)
+ @: > $(PROJECT_INCLUDE)/$(dirstamp)
+PREINSTALL_DIRS += $(PROJECT_INCLUDE)/$(dirstamp)
+
+$(PROJECT_LIB)/bsp_specs: bsp_specs $(PROJECT_LIB)/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_LIB)/bsp_specs
+PREINSTALL_FILES += $(PROJECT_LIB)/bsp_specs
+
+$(PROJECT_INCLUDE)/bsp.h: include/bsp.h $(PROJECT_INCLUDE)/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp.h
+
+$(PROJECT_INCLUDE)/bspopts.h: include/bspopts.h $(PROJECT_INCLUDE)/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bspopts.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/bspopts.h
+
+$(PROJECT_INCLUDE)/bsp/$(dirstamp):
+ @$(MKDIR_P) $(PROJECT_INCLUDE)/bsp
+ @: > $(PROJECT_INCLUDE)/bsp/$(dirstamp)
+PREINSTALL_DIRS += $(PROJECT_INCLUDE)/bsp/$(dirstamp)
+
+$(PROJECT_INCLUDE)/coverhd.h: ../../shared/include/coverhd.h $(PROJECT_INCLUDE)/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/coverhd.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/coverhd.h
+
+$(PROJECT_INCLUDE)/tod.h: ../../shared/tod.h $(PROJECT_INCLUDE)/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/tod.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/tod.h
+
+$(PROJECT_LIB)/motld_start.$(OBJEXT): motld_start.$(OBJEXT) $(PROJECT_LIB)/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_LIB)/motld_start.$(OBJEXT)
+TMPINSTALL_FILES += $(PROJECT_LIB)/motld_start.$(OBJEXT)
+
+$(PROJECT_LIB)/rtems_crti.$(OBJEXT): rtems_crti.$(OBJEXT) $(PROJECT_LIB)/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_LIB)/rtems_crti.$(OBJEXT)
+TMPINSTALL_FILES += $(PROJECT_LIB)/rtems_crti.$(OBJEXT)
+
+$(PROJECT_LIB)/linkcmds: ../shared/startup/linkcmds $(PROJECT_LIB)/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_LIB)/linkcmds
+PREINSTALL_FILES += $(PROJECT_LIB)/linkcmds
+
+$(PROJECT_INCLUDE)/bsp/uart.h: ../../powerpc/shared/console/uart.h $(PROJECT_INCLUDE)/bsp/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/uart.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/uart.h
+
+$(PROJECT_INCLUDE)/bsp/irq.h: ./irq/irq.h $(PROJECT_INCLUDE)/bsp/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/irq.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/irq.h
+
+$(PROJECT_INCLUDE)/bsp/openpic.h: ../../powerpc/shared/openpic/openpic.h $(PROJECT_INCLUDE)/bsp/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/openpic.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/openpic.h
+
+$(PROJECT_INCLUDE)/bsp/pci.h: ../../powerpc/shared/pci/pci.h $(PROJECT_INCLUDE)/bsp/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/pci.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/pci.h
+
+$(PROJECT_INCLUDE)/bsp/vectors.h: ../../../libcpu/@RTEMS_CPU@/@exceptions@/bspsupport/vectors.h $(PROJECT_INCLUDE)/bsp/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/vectors.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/vectors.h
+
+$(PROJECT_INCLUDE)/bsp/ppc_exc_bspsupp.h: ../../../libcpu/@RTEMS_CPU@/@exceptions@/bspsupport/ppc_exc_bspsupp.h $(PROJECT_INCLUDE)/bsp/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/ppc_exc_bspsupp.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/ppc_exc_bspsupp.h
+
+$(PROJECT_INCLUDE)/bsp/irq_supp.h: ../../../libcpu/@RTEMS_CPU@/@exceptions@/bspsupport/irq_supp.h $(PROJECT_INCLUDE)/bsp/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/irq_supp.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/irq_supp.h
+
+$(PROJECT_INCLUDE)/bsp/VMEConfig.h: ./vme/VMEConfig.h $(PROJECT_INCLUDE)/bsp/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/VMEConfig.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/VMEConfig.h
+
+$(PROJECT_INCLUDE)/bsp/vmeTsi148.h: ../../shared/vmeUniverse/vmeTsi148.h $(PROJECT_INCLUDE)/bsp/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/vmeTsi148.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/vmeTsi148.h
+
+$(PROJECT_INCLUDE)/bsp/vme_am_defs.h: ../../shared/vmeUniverse/vme_am_defs.h $(PROJECT_INCLUDE)/bsp/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/vme_am_defs.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/vme_am_defs.h
+
+$(PROJECT_INCLUDE)/bsp/VME.h: ../../shared/vmeUniverse/VME.h $(PROJECT_INCLUDE)/bsp/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/VME.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/VME.h
+
+$(PROJECT_INCLUDE)/bsp/vmeTsi148DMA.h: ../../shared/vmeUniverse/vmeTsi148DMA.h $(PROJECT_INCLUDE)/bsp/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/vmeTsi148DMA.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/vmeTsi148DMA.h
+
+$(PROJECT_INCLUDE)/bsp/bspVmeDmaList.h: ../../shared/vmeUniverse/bspVmeDmaList.h $(PROJECT_INCLUDE)/bsp/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/bspVmeDmaList.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/bspVmeDmaList.h
+
+$(PROJECT_INCLUDE)/bsp/VMEDMA.h: ../../shared/vmeUniverse/VMEDMA.h $(PROJECT_INCLUDE)/bsp/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/VMEDMA.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/VMEDMA.h
+
+$(PROJECT_INCLUDE)/bsp/flashPgm.h: ../shared/flash/flashPgm.h $(PROJECT_INCLUDE)/bsp/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/flashPgm.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/flashPgm.h
+
+$(PROJECT_INCLUDE)/bsp/flashPgmPvt.h: ../shared/flash/flashPgmPvt.h $(PROJECT_INCLUDE)/bsp/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/flashPgmPvt.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/flashPgmPvt.h
+
+$(PROJECT_INCLUDE)/bsp/mpc8540_i2c_busdrv.h: i2c/mpc8540_i2c_busdrv.h $(PROJECT_INCLUDE)/bsp/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/mpc8540_i2c_busdrv.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/mpc8540_i2c_busdrv.h
+
+$(PROJECT_INCLUDE)/bsp/vpd.h: ../shared/motorola/vpd.h $(PROJECT_INCLUDE)/bsp/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/vpd.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/vpd.h
+
+$(PROJECT_INCLUDE)/bsp/if_tsec_pub.h: network/if_tsec_pub.h $(PROJECT_INCLUDE)/bsp/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/if_tsec_pub.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/if_tsec_pub.h
+
diff --git a/c/src/lib/libbsp/powerpc/mvme3100/start/start.S b/c/src/lib/libbsp/powerpc/mvme3100/start/start.S
new file mode 100644
index 0000000000..cab9261c0a
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/mvme3100/start/start.S
@@ -0,0 +1,67 @@
+/*
+ * start.S : RTEMS entry point
+ *
+ * Copyright (C) 1999 Eric Valette. valette@crf.canon.fr
+ *
+ * The license and distribution terms for this file may be
+ * found in found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * Modified for mvme3100 by T. Straumann, 2007.
+ *
+ * $Id$
+ *
+ */
+
+#include <rtems/asm.h>
+#include <rtems/score/cpu.h>
+#include <rtems/powerpc/powerpc.h>
+
+#include <bspopts.h>
+
+#define SYNC \
+ sync; \
+ isync
+
+#define KERNELBASE 0x0
+
+ .text
+ .globl __rtems_entry_point
+ .type __rtems_entry_point,@function
+__rtems_entry_point:
+ mr r31,r3
+ mr r30,r4
+ mr r29,r5
+ mr r28,r6
+ mr r27,r7
+
+ /* Use MotLoad's TLB setup for now; caches are on already */
+ bl __eabi /* setup EABI and SYSV environment */
+ bl zero_bss
+ /*
+ * restore original args
+ */
+ mr r3,r31
+ mr r4,r30
+ mr r5,r29
+ mr r6,r28
+ mr r7,r27
+ bl save_boot_params
+ /*
+ * stack = &__rtems_end + 4096
+ */
+ addis r9,r0, __rtems_end+(4096-PPC_MINIMUM_STACK_FRAME_SIZE)@ha
+ addi r9,r9, __rtems_end+(4096-PPC_MINIMUM_STACK_FRAME_SIZE)@l
+ /* align down to 16-bytes */
+ li r5, (CPU_STACK_ALIGNMENT - 1)
+ andc r1, r9, r5
+ /*
+ * We are now in a environment that is totally independent from
+ * bootloader setup.
+ */
+ lis r5,environ@ha
+ la r5,environ@l(r5) /* environp */
+ li r4, 0 /* argv */
+ li r3, 0 /* argc */
+ bl boot_card
+ /* point of no return: reset board here ? */
diff --git a/c/src/lib/libbsp/powerpc/mvme3100/startup/bspstart.c b/c/src/lib/libbsp/powerpc/mvme3100/startup/bspstart.c
new file mode 100644
index 0000000000..5fb1481715
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/mvme3100/startup/bspstart.c
@@ -0,0 +1,480 @@
+/*
+ * This routine starts the application. It includes application,
+ * board, and monitor specific initialization and configuration.
+ * The generic CPU dependent initialization has been performed
+ * before this routine is invoked.
+ *
+ * COPYRIGHT (c) 1989-1998.
+ * On-Line Applications Research Corporation (OAR).
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * Modified to support the MCP750.
+ * Modifications Copyright (C) 1999 Eric Valette. valette@crf.canon.fr
+ *
+ * Modified for mvme3100 by T. Straumann
+ *
+ * $Id$
+ */
+
+#include <string.h>
+#include <stdlib.h>
+
+#include <rtems.h>
+#include <bsp.h>
+#include <rtems/bspIo.h>
+#include <libcpu/spr.h>
+#include <libcpu/io.h>
+#include <bsp/uart.h>
+#include <bsp/irq.h>
+#include <bsp/pci.h>
+#include <bsp/vpd.h>
+#include <libcpu/cpuIdent.h>
+#include <bsp/vectors.h>
+#include <rtems/powerpc/powerpc.h>
+
+#define SHOW_MORE_INIT_SETTINGS
+#undef DEBUG
+
+#ifdef DEBUG
+#define STATIC
+#else
+#define STATIC static
+#endif
+
+extern unsigned long __rtems_end[];
+extern void bsp_cleanup(void);
+extern void BSP_vme_config();
+
+SPR_RW(SPRG0)
+SPR_RW(SPRG1)
+
+/*
+ * Copy Additional boot param passed by boot loader
+ */
+#define CMDLINE_BUF_SIZE 2048
+
+static char cmdline_buf[CMDLINE_BUF_SIZE] = {0};
+char *BSP_commandline_string = cmdline_buf;
+
+extern const char *BSP_build_date;
+
+/*
+ * Vital Board data Start using DATA RESIDUAL
+ */
+uint32_t bsp_clicks_per_usec = 0;
+/*
+ * Total memory using RESIDUAL DATA
+ */
+unsigned int BSP_mem_size = 0;
+/*
+ * Where the heap starts; is used by bsp_pretasking_hook;
+ */
+unsigned int BSP_heap_start = 0;
+/*
+ * PCI Bus Frequency
+ */
+unsigned int BSP_pci_bus_frequency = 0xdeadbeef;
+/*
+ * PPC Bus Frequency
+ */
+unsigned int BSP_bus_frequency = 0;
+/*
+ * processor clock frequency
+ */
+unsigned int BSP_processor_frequency = 0;
+/*
+ * Time base divisior (how many tick for 1 second).
+ */
+unsigned int BSP_time_base_divisor = 8000; /* if external RTC clock unused (HID0) */
+
+/* Board identification string */
+char BSP_productIdent[20] = {0};
+char BSP_serialNumber[20] = {0};
+
+/* VPD appends an extra char -- what for ? */
+char BSP_enetAddr0[7] = {0};
+char BSP_enetAddr1[7] = {0};
+char BSP_enetAddr2[7] = {0};
+
+static void
+prether(char *b, int idx)
+{
+int i;
+ printk("Ethernet %i %02X", idx, *b++);
+ for ( i=0; i<5; i++ )
+ printk(":%02X",*b++);
+ printk("\n");
+}
+
+/*
+ * system init stack and soft ir stack size
+ */
+#define INIT_STACK_SIZE 0x1000
+#define INTR_STACK_SIZE rtems_configuration_get_interrupt_stack_size()
+
+BSP_output_char_function_type BSP_output_char = BSP_output_char_via_serial;
+
+void BSP_panic(char *s)
+{
+ printk("\n%s PANIC %s\n",_RTEMS_version, s);
+ __asm__ __volatile ("sc");
+}
+
+void _BSP_Fatal_error(unsigned int v)
+{
+ printk("\n%s PANIC ERROR %x\n",_RTEMS_version, v);
+ __asm__ __volatile ("sc");
+}
+
+/*
+ * The original table from the application and our copy of it with
+ * some changes.
+ */
+
+extern rtems_configuration_table Configuration;
+
+char *rtems_progname;
+
+/*
+ * Use the shared implementations of the following routines
+ */
+
+void save_boot_params(void* r3, void *r4, void* r5, char *additional_boot_options)
+{
+
+ strncpy(cmdline_buf, additional_boot_options, CMDLINE_BUF_SIZE);
+ cmdline_buf[CMDLINE_BUF_SIZE - 1] ='\0';
+}
+
+#define CS_CONFIG_CS_EN (1<<31)
+#define CS_BNDS_SA(x) ((((uint32_t)(x))>>(31-15)) & 0xff)
+#define CS_BNDS_EA(x) ((((uint32_t)(x))>>(31-31)) & 0xff)
+
+static inline uint32_t
+_ccsr_rd32(uint32_t off)
+{
+ return in_be32( (volatile unsigned *)(BSP_8540_CCSR_BASE + off) );
+}
+
+static inline void
+_ccsr_wr32(uint32_t off, uint32_t val)
+{
+ out_be32( (volatile unsigned *)(BSP_8540_CCSR_BASE + off), val );
+}
+
+
+STATIC uint32_t
+BSP_get_mem_size()
+{
+int i;
+uint32_t cs_bnds, cs_config;
+uint32_t memsz=0;
+uint32_t v;
+
+ for ( cs_bnds = 0x2000, cs_config=0x2080, i=0; i<4; i++, cs_bnds+=8, cs_config+=4 ) {
+ if ( CS_CONFIG_CS_EN & _ccsr_rd32( cs_config ) ) {
+ v = _ccsr_rd32( cs_bnds );
+
+ memsz += CS_BNDS_EA(v) - CS_BNDS_SA(v) + 1;
+ }
+ }
+ return memsz << 24;
+}
+
+STATIC void
+BSP_calc_freqs()
+{
+uint32_t porpllsr = _ccsr_rd32( 0xe0000 );
+unsigned plat_ratio = (porpllsr >> (31-30)) & 0x1f;
+unsigned e500_ratio = (porpllsr >> (31-15)) & 0x3f;
+
+ switch ( plat_ratio ) {
+ case 2: case 3: case 4: case 5: case 6:
+ case 8: case 9: case 10: case 12: case 16:
+ /* supported ratios */
+ BSP_bus_frequency = BSP_pci_bus_frequency * plat_ratio;
+ break;
+
+ default:
+ BSP_panic("Unknown PLL sys-clock ratio; something's wrong here");
+ }
+
+ switch ( e500_ratio ) {
+ case 4: case 5: case 6: case 7:
+ BSP_processor_frequency = (BSP_pci_bus_frequency * e500_ratio) >> 1;
+ break;
+
+ default:
+ BSP_panic("Unknown PLL e500-clock ratio; something's wrong here");
+ }
+
+ printk("Core Complex Bus (CCB) Clock Freq: %10u Hz\n", BSP_bus_frequency);
+ printk("CPU Clock Freq: %10u Hz\n", BSP_processor_frequency);
+}
+
+void
+bsp_predriver_hook(void)
+{
+ /* Some drivers (RTC) may need i2c */
+ BSP_i2c_initialize();
+}
+
+/*
+ * bsp_start
+ *
+ * This routine does the bulk of the system initialization.
+ */
+
+void bsp_start( void )
+{
+unsigned char *stack;
+register uint32_t intrStack;
+register uint32_t *intrStackPtr;
+unsigned char *work_space_start;
+char *chpt;
+ppc_cpu_id_t myCpu;
+ppc_cpu_revision_t myCpuRevision;
+
+VpdBufRec vpdData [] = {
+ { key: ProductIdent, instance: 0, buf: BSP_productIdent, buflen: sizeof(BSP_productIdent) - 1 },
+ { key: SerialNumber, instance: 0, buf: BSP_serialNumber, buflen: sizeof(BSP_serialNumber) - 1 },
+ { key: BusClockHz, instance: 0, buf: &BSP_pci_bus_frequency, buflen: sizeof(BSP_pci_bus_frequency) },
+ { key: EthernetAddr, instance: 0, buf: BSP_enetAddr0, buflen: sizeof(BSP_enetAddr0) },
+ { key: EthernetAddr, instance: 1, buf: BSP_enetAddr1, buflen: sizeof(BSP_enetAddr1) },
+ { key: EthernetAddr, instance: 2, buf: BSP_enetAddr2, buflen: sizeof(BSP_enetAddr2) },
+ VPD_END
+};
+
+ /* Intersperse messages with actions to help locate problems */
+ printk("-----------------------------------------\n");
+
+ /*
+ * Get CPU identification dynamically. Note that the get_ppc_cpu_type()
+ * function store the result in global variables so that it can be used
+ * later...
+ */
+ myCpu = get_ppc_cpu_type();
+ myCpuRevision = get_ppc_cpu_revision();
+
+ printk("Welcome to %s\n", _RTEMS_version);
+ printk("BSP: %s, CVS Release ($Name$)\n", "mvme3100");
+
+ /*
+ * the initial stack has aready been set to this value in start.S
+ * so there is no need to set it in r1 again... It is just for info
+ * so that It can be printed without accessing R1.
+ */
+ asm volatile("mr %0, 1":"=r"(stack));
+#if 0
+ stack = ((unsigned char*) __rtems_end) +
+ INIT_STACK_SIZE - PPC_MINIMUM_STACK_FRAME_SIZE;
+#endif
+
+ /* tag the bottom */
+ *((uint32_t*)stack) = 0;
+
+ /*
+ * Initialize the interrupt related settings
+ * SPRG1 = software managed IRQ stack
+ *
+ * This could be done later (e.g in IRQ_INIT) but it helps to understand
+ * some settings below...
+ */
+ BSP_heap_start = ((uint32_t) __rtems_end) + INIT_STACK_SIZE + INTR_STACK_SIZE;
+
+ /* reserve space for the marker/tag frame */
+ intrStack = BSP_heap_start - PPC_MINIMUM_STACK_FRAME_SIZE;
+
+ /* make sure it's properly aligned */
+ intrStack &= ~(CPU_STACK_ALIGNMENT-1);
+
+ /* tag the bottom (T. Straumann 6/36/2001 <strauman@slac.stanford.edu>) */
+ intrStackPtr = (uint32_t*) intrStack;
+ *intrStackPtr = 0;
+
+ _write_SPRG1(intrStack);
+
+ /* signal them that we have fixed PR288 - eventually, this should go away */
+ _write_SPRG0(PPC_BSP_HAS_FIXED_PR288);
+
+ /*
+ * Initialize default raw exception handlers. See vectors/vectors_init.c
+ */
+ initialize_exceptions();
+
+ printk("CPU 0x%x - rev 0x%x\n", myCpu, myCpuRevision);
+
+#ifdef SHOW_MORE_INIT_SETTINGS
+ printk("Additionnal boot options are %s\n", BSP_commandline_string);
+ printk("Initial system stack at %x\n", stack);
+ printk("Software IRQ stack at %x\n", intrStack);
+#endif
+
+#ifdef SHOW_MORE_INIT_SETTINGS
+ printk("Going to start PCI buses scanning and initialization\n");
+#endif
+
+ printk("Build Date: %s\n",BSP_build_date);
+
+ BSP_vpdRetrieveFields( vpdData );
+
+ printk("Board Type: %s (S/N %s)\n",
+ BSP_productIdent[0] ? BSP_productIdent : "n/a",
+ BSP_serialNumber[0] ? BSP_serialNumber : "n/a");
+
+ printk("External (=PCI Bus) Clock Freq ");
+ if ( 0xdeadbeef == BSP_pci_bus_frequency ) {
+ BSP_pci_bus_frequency = 66666666;
+ printk(" NOT FOUND in VPD; using %10u Hz\n",
+ BSP_pci_bus_frequency);
+ } else {
+ printk(": %10u Hz\n",
+ BSP_pci_bus_frequency);
+ }
+
+ /* Calculate CPU and CCB bus freqs */
+ BSP_calc_freqs();
+
+ pci_initialize();
+
+ prether(BSP_enetAddr0, 0);
+ prether(BSP_enetAddr1, 1);
+ prether(BSP_enetAddr2, 2);
+
+ /* need to tweak the motload setup */
+ BSP_motload_pci_fixup();
+
+#ifdef SHOW_MORE_INIT_SETTINGS
+ printk("Number of PCI buses found is : %d\n", pci_bus_count());
+ {
+ void BSP_pciConfigDump_early();
+ BSP_pciConfigDump_early();
+ }
+#endif
+
+#ifdef TEST_RAW_EXCEPTION_CODE
+ printk("Testing exception handling Part 1\n");
+ /*
+ * Cause a software exception
+ */
+ __asm__ __volatile ("sc");
+ /*
+ * Check we can still catch exceptions and return coorectly.
+ */
+ printk("Testing exception handling Part 2\n");
+ __asm__ __volatile ("sc");
+
+ /*
+ * Somehow doing the above seems to clobber SPRG0 on the mvme2100. It
+ * is probably a not so subtle hint that you do not want to use PPCBug
+ * once RTEMS is up and running. Anyway, we still needs to indicate
+ * that we have fixed PR288. Eventually, this should go away.
+ */
+ _write_SPRG0(PPC_BSP_HAS_FIXED_PR288);
+#endif
+
+ BSP_mem_size = BSP_get_mem_size();
+
+ if ( (chpt = strstr(BSP_commandline_string,"MEMSZ=")) ) {
+ char *endp;
+ uint32_t sz;
+ chpt+=6 /* strlen("MEMSZ=") */;
+ sz = strtoul(chpt, &endp, 0);
+ if ( endp != chpt )
+ BSP_mem_size = sz;
+ }
+
+ printk("Memory: %10u bytes\n", BSP_mem_size);
+
+ BSP_bus_frequency = 333333333;
+ BSP_processor_frequency = 833333333;
+ BSP_time_base_divisor = 8000; /* if external RTC clock unused (HID0) */
+
+ /* clear hostbridge errors but leave MCP disabled -
+ * PCI config space scanning code will trip otherwise :-(
+ */
+ _BSP_clear_hostbridge_errors(0 /* enableMCP */, 0/*quiet*/);
+
+ /*
+ * Set up our hooks
+ * Make sure libc_init is done before drivers initialized so that
+ * they can use atexit()
+ */
+
+#if 0
+ Cpu_table.interrupt_stack_size = CONFIGURE_INTERRUPT_STACK_MEMORY;
+/* FIXME */
+#endif
+ bsp_clicks_per_usec = BSP_bus_frequency/(BSP_time_base_divisor * 1000);
+
+#ifdef SHOW_MORE_INIT_SETTINGS
+ printk("Configuration.work_space_size = %x\n",
+ Configuration.work_space_size);
+#endif
+
+ work_space_start =
+ (unsigned char *)BSP_mem_size - Configuration.work_space_size;
+
+ if ( work_space_start <=
+ ((unsigned char *)__rtems_end) + INIT_STACK_SIZE + INTR_STACK_SIZE) {
+ printk( "bspstart: Not enough RAM!!!\n" );
+ bsp_cleanup();
+ }
+
+ Configuration.work_space_start = work_space_start;
+
+ /*
+ * Initalize RTEMS IRQ system
+ */
+ BSP_rtems_irq_mng_init(0);
+
+ if (1) {
+ int i;
+ unsigned msr,tcr;
+ asm volatile("mfmsr %0":"=r"(msr));
+ asm volatile("mftcr %0":"=r"(tcr));
+ printk("MSR is 0x%08x, TCR 0x%08x\n",msr,tcr);
+ asm volatile("mttcr %0"::"r"(0));
+ if (0) {
+ asm volatile("mtmsr %0"::"r"(msr|0x8000));
+ for (i=0; i<12; i++)
+ BSP_enable_irq_at_pic(i);
+ printk("IRQS enabled\n");
+ }
+ }
+
+ if (0) {
+ extern unsigned ppc_exc_lock_std, ppc_exc_gpr3_std;
+ unsigned x;
+ asm volatile("mfivpr %0":"=r"(x));
+ printk("IVPR: 0x%08x\n",x);
+ asm volatile("mfivor8 %0":"=r"(x));
+ printk("IVOR8: 0x%08x\n",x);
+ printk("0x%08x\n",*(unsigned *)0xc00);
+ printk("0x%08x\n",*(unsigned *)0xc04);
+ printk("0x%08x\n",*(unsigned *)0xc08);
+ printk("0x%08x\n\n\n",*(unsigned *)0xc0c);
+ if (0) {
+ *(unsigned *)0xc08 = 0x4c000064;
+ asm volatile("dcbf 0, %0; icbi 0, %0; sync; isync"::"r"(0xc00));
+ }
+
+ printk("0x%08x\n", ppc_exc_lock_std);
+ printk("0x%08x\n", ppc_exc_gpr3_std);
+
+ asm volatile("sc");
+
+ printk("0x%08x\n", ppc_exc_lock_std);
+ printk("0x%08x\n", ppc_exc_gpr3_std);
+ }
+
+ printk("-----------------------------------------\n");
+
+#ifdef SHOW_MORE_INIT_SETTINGS
+ printk("Exit from bspstart\n");
+#endif
+
+}
diff --git a/c/src/lib/libbsp/powerpc/mvme3100/startup/misc.c b/c/src/lib/libbsp/powerpc/mvme3100/startup/misc.c
new file mode 100644
index 0000000000..98ab3eb07b
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/mvme3100/startup/misc.c
@@ -0,0 +1,133 @@
+/* $Id$ */
+
+/* Miscellaneous small BSP routines; reboot, board CSR, ... */
+
+/*
+ * Authorship
+ * ----------
+ * This software ('mvme3100' RTEMS BSP) was created by
+ *
+ * Till Straumann <strauman@slac.stanford.edu>, 2005-2007,
+ * Stanford Linear Accelerator Center, Stanford University.
+ *
+ * Acknowledgement of sponsorship
+ * ------------------------------
+ * The 'mvme3100' BSP was produced by
+ * the Stanford Linear Accelerator Center, Stanford University,
+ * under Contract DE-AC03-76SFO0515 with the Department of Energy.
+ *
+ * Government disclaimer of liability
+ * ----------------------------------
+ * Neither the United States nor the United States Department of Energy,
+ * nor any of their employees, makes any warranty, express or implied, or
+ * assumes any legal liability or responsibility for the accuracy,
+ * completeness, or usefulness of any data, apparatus, product, or process
+ * disclosed, or represents that its use would not infringe privately owned
+ * rights.
+ *
+ * Stanford disclaimer of liability
+ * --------------------------------
+ * Stanford University makes no representations or warranties, express or
+ * implied, nor assumes any liability for the use of this software.
+ *
+ * Stanford disclaimer of copyright
+ * --------------------------------
+ * Stanford University, owner of the copyright, hereby disclaims its
+ * copyright and all other rights in this software. Hence, anyone may
+ * freely use it for any purpose without restriction.
+ *
+ * Maintenance of notices
+ * ----------------------
+ * In the interest of clarity regarding the origin and status of this
+ * SLAC software, this and all the preceding Stanford University notices
+ * are to remain affixed to any copy or derivative of this software made
+ * or distributed by the recipient and are to be affixed to any copy of
+ * software made or distributed by the recipient that contains a copy or
+ * derivative of this software.
+ *
+ * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03
+ */
+
+#include <rtems.h>
+#include <bsp.h>
+
+void
+rtemsReboot()
+{
+uint8_t v;
+ /*
+ * AFAIK, the hardest reset available; cleared
+ * some errors a VME-bus reset wouldn't (hung
+ * i2c bus)...
+ */
+ v = in_8( BSP_MVME3100_SYS_CR );
+ v &= ~BSP_MVME3100_SYS_CR_RESET_MSK;
+ v |= BSP_MVME3100_SYS_CR_RESET;
+ out_8( BSP_MVME3100_SYS_CR, v );
+}
+
+uint8_t
+BSP_setSysReg(volatile uint8_t *r, uint8_t mask)
+{
+uint8_t v;
+rtems_interrupt_level l;
+
+ if ( !mask )
+ return in_8( r );
+
+ rtems_interrupt_disable(l);
+ v = in_8( r );
+ if ( mask ) {
+ out_8( r, v | mask );
+ }
+ rtems_interrupt_enable(l);
+ return v;
+}
+
+uint8_t
+BSP_clrSysReg(volatile uint8_t *r, uint8_t mask)
+{
+uint8_t v;
+rtems_interrupt_level l;
+
+ if ( !mask )
+ return in_8( r );
+
+ rtems_interrupt_disable(l);
+ v = in_8( r );
+ if ( mask ) {
+ out_8( r, v & ~mask );
+ }
+ rtems_interrupt_enable(l);
+ return v;
+}
+
+uint8_t
+BSP_setLEDs(uint8_t mask)
+{
+ return BSP_setSysReg( BSP_MVME3100_SYS_IND_REG, mask );
+}
+
+uint8_t
+BSP_clrLEDs(uint8_t mask)
+{
+ return BSP_clrSysReg( BSP_MVME3100_SYS_IND_REG, mask );
+}
+
+uint8_t
+BSP_eeprom_write_protect()
+{
+uint8_t m = BSP_MVME3100_SYS_CR_EEPROM_WP;
+volatile uint8_t *r = BSP_MVME3100_SYS_CR;
+
+ return m & BSP_setSysReg( r, m );
+}
+
+uint8_t
+BSP_eeprom_write_enable()
+{
+uint8_t m = BSP_MVME3100_SYS_CR_EEPROM_WP;
+volatile uint8_t *r = BSP_MVME3100_SYS_CR;
+
+ return m & BSP_clrSysReg( r, m );
+}
diff --git a/c/src/lib/libbsp/powerpc/mvme3100/tod/todcfg.c b/c/src/lib/libbsp/powerpc/mvme3100/tod/todcfg.c
new file mode 100644
index 0000000000..7d29377c21
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/mvme3100/tod/todcfg.c
@@ -0,0 +1,28 @@
+/*
+ * This file contains the RTC driver table for the MVME3100 BSP
+ *
+ * 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.
+ *
+ * Modified for mvme3100 by T. Straumann, 2007
+ *
+ * $Id$
+ */
+
+#include <bsp.h>
+#include <libchip/rtc.h>
+#include <libchip/ds1375-rtc.h>
+
+/* The following table configures the RTC drivers used in this BSP */
+rtc_tbl RTC_Table[] = {
+ DS1375_RTC_TBL_ENTRY(BSP_I2C_DS1375_RAW_DEV_NAME),
+};
+
+/* Some information used by the RTC driver */
+
+#define NUM_RTCS (sizeof(RTC_Table)/sizeof(rtc_tbl))
+
+size_t RTC_Count = NUM_RTCS;
+
+rtems_device_minor_number RTC_Minor;
diff --git a/c/src/lib/libbsp/powerpc/mvme3100/vme/VMEConfig.h b/c/src/lib/libbsp/powerpc/mvme3100/vme/VMEConfig.h
new file mode 100644
index 0000000000..3366efab41
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/mvme3100/vme/VMEConfig.h
@@ -0,0 +1,116 @@
+#ifndef RTEMS_BSP_VME_CONFIG_H
+#define RTEMS_BSP_VME_CONFIG_H
+/* $Id$ */
+
+/* mvme3100 BSP specific address space configuration parameters */
+
+/*
+ * Authorship
+ * ----------
+ * This software was created by
+ * Till Straumann <strauman@slac.stanford.edu>, 2002..2007,
+ * Stanford Linear Accelerator Center, Stanford University.
+ *
+ * Acknowledgement of sponsorship
+ * ------------------------------
+ * This software was produced by
+ * the Stanford Linear Accelerator Center, Stanford University,
+ * under Contract DE-AC03-76SFO0515 with the Department of Energy.
+ *
+ * Government disclaimer of liability
+ * ----------------------------------
+ * Neither the United States nor the United States Department of Energy,
+ * nor any of their employees, makes any warranty, express or implied, or
+ * assumes any legal liability or responsibility for the accuracy,
+ * completeness, or usefulness of any data, apparatus, product, or process
+ * disclosed, or represents that its use would not infringe privately owned
+ * rights.
+ *
+ * Stanford disclaimer of liability
+ * --------------------------------
+ * Stanford University makes no representations or warranties, express or
+ * implied, nor assumes any liability for the use of this software.
+ *
+ * Stanford disclaimer of copyright
+ * --------------------------------
+ * Stanford University, owner of the copyright, hereby disclaims its
+ * copyright and all other rights in this software. Hence, anyone may
+ * freely use it for any purpose without restriction.
+ *
+ * Maintenance of notices
+ * ----------------------
+ * In the interest of clarity regarding the origin and status of this
+ * SLAC software, this and all the preceding Stanford University notices
+ * are to remain affixed to any copy or derivative of this software made
+ * or distributed by the recipient and are to be affixed to any copy of
+ * software made or distributed by the recipient that contains a copy or
+ * derivative of this software.
+ *
+ * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03
+ */
+
+/*
+ * NOTE: the BSP (startup/bspstart.c) uses
+ * hardcoded window lengths that match this
+ * layout:
+ */
+
+#define _VME_A32_WIN0_ON_PCI 0xc0000000
+#define _VME_CSR_ON_PCI 0xce000000
+#define _VME_A24_ON_PCI 0xcf000000
+#define _VME_A16_ON_PCI 0xcfff0000
+
+/* start of the A32 window on the VME bus
+ * TODO: this should perhaps be a run-time configuration option
+ */
+#define _VME_A32_WIN0_ON_VME 0x20000000
+
+/* if _VME_DRAM_OFFSET is defined, the BSP
+ * will map the board RAM onto the VME bus, starting
+ * at _VME_DRAM_OFFSET
+ */
+#define _VME_DRAM_OFFSET 0xc0000000
+
+/* If your BSP requires a non-standard way to configure
+ * the VME interrupt manager then define the symbol
+ *
+ * BSP_VME_INSTALL_IRQ_MGR
+ *
+ * to a proper instruction sequence that installs the
+ * universe interrupt manager. This requires knowledge
+ * of the wiring between the universe and the PIC (main
+ * interrupt controller), i.e., which IRQ 'pins' of the
+ * universe are wired to which 'lines'/inputs at the PIC.
+ * (consult vmeUniverse.h for more information).
+ *
+ * When installing the universe IRQ manager it is also
+ * possible to specify whether it should try to share
+ * PIC interrupts with other sources. This might not
+ * be supported by all BSPs (but the unverse driver
+ * recognizes that).
+ *
+ * If BSP_VME_INSTALL_IRQ_MGR is undefined then
+ * the default algorithm is used (vme_universe.c):
+ *
+ * This default setup uses only a single wire. It reads
+ * the PIC 'line' from PCI configuration space and assumes
+ * this to be wired to the first (LIRQ0) IRQ input at the
+ * universe. The default setup tries to use interrupt
+ * sharing.
+ */
+#define BSP_VME_INSTALL_IRQ_MGR(err) \
+ do { \
+ err = vmeTsi148InstallIrqMgrAlt(\
+ VMETSI148_IRQ_MGR_FLAG_SHARED, /* use shared IRQs */ \
+ 0, BSP_VME0_IRQ, \
+ 1, BSP_VME1_IRQ, \
+ 2, BSP_VME2_IRQ, \
+ 3, BSP_VME3_IRQ, \
+ -1 /* terminate list */ \
+ ); \
+ } while (0)
+
+/* This BSP uses the Tsi148 Driver */
+#define _VME_DRIVER_TSI148
+
+#endif