summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTill Straumann <strauman@slac.stanford.edu>2009-12-03 16:56:50 +0000
committerTill Straumann <strauman@slac.stanford.edu>2009-12-03 16:56:50 +0000
commitb7a6d23a0d8d855fe92d573658405e1eedc2356b (patch)
tree71efd676a12343e1268e25c9214f44312e8d554e
- importing 'beatnik' BSP from SLAC repository.R_beatnik_import_1_0_from_SLACB_beatnik_import_from_SLAC
-rw-r--r--c/src/lib/libbsp/powerpc/beatnik/.cvsignore8
-rw-r--r--c/src/lib/libbsp/powerpc/beatnik/ChangeLog197
-rw-r--r--c/src/lib/libbsp/powerpc/beatnik/LICENSE52
-rw-r--r--c/src/lib/libbsp/powerpc/beatnik/Makefile.am245
-rw-r--r--c/src/lib/libbsp/powerpc/beatnik/README178
-rw-r--r--c/src/lib/libbsp/powerpc/beatnik/bsp_specs13
-rw-r--r--c/src/lib/libbsp/powerpc/beatnik/configure.ac40
-rw-r--r--c/src/lib/libbsp/powerpc/beatnik/flash/flashcfg.c182
-rw-r--r--c/src/lib/libbsp/powerpc/beatnik/include/.cvsignore4
-rw-r--r--c/src/lib/libbsp/powerpc/beatnik/include/bsp.h273
-rw-r--r--c/src/lib/libbsp/powerpc/beatnik/irq/discovery_pic.c995
-rw-r--r--c/src/lib/libbsp/powerpc/beatnik/irq/irq.h133
-rw-r--r--c/src/lib/libbsp/powerpc/beatnik/irq/irq_init.c112
-rw-r--r--c/src/lib/libbsp/powerpc/beatnik/irq/irq_test_app.c167
-rw-r--r--c/src/lib/libbsp/powerpc/beatnik/make/custom/beatnik.cfg37
-rw-r--r--c/src/lib/libbsp/powerpc/beatnik/marvell/discovery.c151
-rw-r--r--c/src/lib/libbsp/powerpc/beatnik/marvell/gt.c1010
-rw-r--r--c/src/lib/libbsp/powerpc/beatnik/marvell/gt_timer.c412
-rw-r--r--c/src/lib/libbsp/powerpc/beatnik/marvell/gt_timer.h134
-rw-r--r--c/src/lib/libbsp/powerpc/beatnik/marvell/gti2c.c447
-rw-r--r--c/src/lib/libbsp/powerpc/beatnik/marvell/gti2c_busdrv.h62
-rw-r--r--c/src/lib/libbsp/powerpc/beatnik/marvell/gti2creg.h83
-rw-r--r--c/src/lib/libbsp/powerpc/beatnik/marvell/gtintrreg.h257
-rw-r--r--c/src/lib/libbsp/powerpc/beatnik/marvell/gtpcireg.h964
-rw-r--r--c/src/lib/libbsp/powerpc/beatnik/marvell/gtreg.h854
-rw-r--r--c/src/lib/libbsp/powerpc/beatnik/network/if_em/LICENSE31
-rw-r--r--c/src/lib/libbsp/powerpc/beatnik/network/if_em/Makefile92
-rw-r--r--c/src/lib/libbsp/powerpc/beatnik/network/if_em/README332
-rw-r--r--c/src/lib/libbsp/powerpc/beatnik/network/if_em/if_em.c3846
-rw-r--r--c/src/lib/libbsp/powerpc/beatnik/network/if_em/if_em.h493
-rw-r--r--c/src/lib/libbsp/powerpc/beatnik/network/if_em/if_em_hw.c6635
-rw-r--r--c/src/lib/libbsp/powerpc/beatnik/network/if_em/if_em_hw.h2678
-rw-r--r--c/src/lib/libbsp/powerpc/beatnik/network/if_em/if_em_osdep.h146
-rw-r--r--c/src/lib/libbsp/powerpc/beatnik/network/if_em/if_em_pub.h23
-rw-r--r--c/src/lib/libbsp/powerpc/beatnik/network/if_em/if_em_rtems.c106
-rw-r--r--c/src/lib/libbsp/powerpc/beatnik/network/if_em/rtemscompat_defs.h110
-rw-r--r--c/src/lib/libbsp/powerpc/beatnik/network/if_gfe/Makefile90
-rw-r--r--c/src/lib/libbsp/powerpc/beatnik/network/if_gfe/gtethreg.h854
-rw-r--r--c/src/lib/libbsp/powerpc/beatnik/network/if_gfe/gtvar.h170
-rw-r--r--c/src/lib/libbsp/powerpc/beatnik/network/if_gfe/if_gfe.c2641
-rw-r--r--c/src/lib/libbsp/powerpc/beatnik/network/if_gfe/if_gfe_pub.h31
-rw-r--r--c/src/lib/libbsp/powerpc/beatnik/network/if_gfe/if_gfe_rtems.c130
-rw-r--r--c/src/lib/libbsp/powerpc/beatnik/network/if_gfe/if_gfevar.h225
-rw-r--r--c/src/lib/libbsp/powerpc/beatnik/network/if_gfe/rtemscompat_defs.h122
-rw-r--r--c/src/lib/libbsp/powerpc/beatnik/network/if_mve/if_mve_pub.h423
-rw-r--r--c/src/lib/libbsp/powerpc/beatnik/network/if_mve/mv643xx_eth.c3297
-rw-r--r--c/src/lib/libbsp/powerpc/beatnik/network/if_mve/mve_smallbuf_tst.c144
-rw-r--r--c/src/lib/libbsp/powerpc/beatnik/network/if_mve/testing.c323
-rw-r--r--c/src/lib/libbsp/powerpc/beatnik/network/porting/LICENSE51
-rw-r--r--c/src/lib/libbsp/powerpc/beatnik/network/porting/Makefile.template84
-rw-r--r--c/src/lib/libbsp/powerpc/beatnik/network/porting/README106
-rw-r--r--c/src/lib/libbsp/powerpc/beatnik/network/porting/if_xxx.modini.c34
-rw-r--r--c/src/lib/libbsp/powerpc/beatnik/network/porting/if_xxx_rtems.c504
-rw-r--r--c/src/lib/libbsp/powerpc/beatnik/network/porting/pcireg.h405
-rw-r--r--c/src/lib/libbsp/powerpc/beatnik/network/porting/rtemscompat.h459
-rw-r--r--c/src/lib/libbsp/powerpc/beatnik/network/porting/rtemscompat1.h219
-rw-r--r--c/src/lib/libbsp/powerpc/beatnik/network/porting/rtemscompat_defs.h.template97
-rw-r--r--c/src/lib/libbsp/powerpc/beatnik/network/support/bsp_attach.c468
-rw-r--r--c/src/lib/libbsp/powerpc/beatnik/network/support/bsp_bsdnet_attach.h80
-rw-r--r--c/src/lib/libbsp/powerpc/beatnik/network/support/early_enet_link_status.h31
-rw-r--r--c/src/lib/libbsp/powerpc/beatnik/network/support/early_link_status.c41
-rw-r--r--c/src/lib/libbsp/powerpc/beatnik/pci/gt_pci_init.c274
-rw-r--r--c/src/lib/libbsp/powerpc/beatnik/pci/motload_fixup.c182
-rw-r--r--c/src/lib/libbsp/powerpc/beatnik/pci/pci_io_remap.c207
-rw-r--r--c/src/lib/libbsp/powerpc/beatnik/pci/pci_io_remap.h66
-rw-r--r--c/src/lib/libbsp/powerpc/beatnik/preinstall.am188
-rw-r--r--c/src/lib/libbsp/powerpc/beatnik/startup/bspclean.c11
-rw-r--r--c/src/lib/libbsp/powerpc/beatnik/startup/bspstart.c397
-rw-r--r--c/src/lib/libbsp/powerpc/beatnik/startup/i2c_init.c132
-rw-r--r--c/src/lib/libbsp/powerpc/beatnik/startup/linkcmds261
-rw-r--r--c/src/lib/libbsp/powerpc/beatnik/startup/reboot.c16
-rw-r--r--c/src/lib/libbsp/powerpc/beatnik/tod/todcfg.c36
-rw-r--r--c/src/lib/libbsp/powerpc/beatnik/vme/VMEConfig.h112
-rw-r--r--c/src/lib/libbsp/powerpc/beatnik/vme/vme_dma.c217
-rw-r--r--c/src/lib/libbsp/powerpc/beatnik/vme/vmeconfig.c305
75 files changed, 34935 insertions, 0 deletions
diff --git a/c/src/lib/libbsp/powerpc/beatnik/.cvsignore b/c/src/lib/libbsp/powerpc/beatnik/.cvsignore
new file mode 100644
index 0000000000..baba64eafa
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/beatnik/.cvsignore
@@ -0,0 +1,8 @@
+aclocal.m4
+autom4te*.cache
+config.cache
+config.log
+config.status
+configure
+Makefile
+Makefile.in
diff --git a/c/src/lib/libbsp/powerpc/beatnik/ChangeLog b/c/src/lib/libbsp/powerpc/beatnik/ChangeLog
new file mode 100644
index 0000000000..f102855023
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/beatnik/ChangeLog
@@ -0,0 +1,197 @@
+2009-11-06 Till Straumann <strauman@slac.stanford.edu>
+
+ * Makefile.am, irq/discovery_pic.c, irq/irq_init.c:
+ dump raw_exceptions.rel, raw_exception.h; these have
+ disappeared. <bsp/vectors.h> must now be included
+ instead.
+
+ * Makefile.am: Add 'altivec.rel'.
+
+ * make/custom/beatnik.cfg: Use -mcpu=7400; this enables
+ AltiVec!
+
+2009-11-06 Till Straumann <strauman@slac.stanford.edu>
+
+ * beatnik.cfg, make/custom/beatnik.cfg: moved beatnik.cfg
+ to new make/custom subdir.
+
+2009-10-20 Till Straumann <strauman@slac.stanford.edu>
+
+ * startup/bspstart.c: leave 'work-space start' and initial
+ stack alone. These are now handled by the shared framework
+ and linker script etc. Locate interrupt stack after __rtems_end
+ and obtain its size from the configuration.
+
+2009-10-20 Till Straumann <strauman@slac.stanford.edu>
+
+ * network/if_mve/mv643xx_eth.c: made mutex a binary semphore;
+ simple binary semaphore doesn't support priority inheritance.
+ This was silently ignored under previous releases but is an
+ error under 4.10.
+
+2009-10-20 Till Straumann <strauman@slac.stanford.edu>
+
+ * Makefile.am, bsp_specs, preinstall.am, flash/flashcfg.c,
+ include/bspopts.h.in, irq/discovery_pic.c, irq/irq_init.c,
+ marvell/gt_timer.c, marvell/gt_timer.h, marvel/gti2c.c,
+ network/if_gfe/if_gfe.c, network/if_gfe/if_gfe_rtems.c,
+ network/if_mve/mv643xx_eth.c, network/support/bsp_attach.c,
+ pci/gt_pci_init.c, pci/motload_fixup.c, startup/bspstart.c,
+ startup/i2c_init.c:
+ Ported to rtems HEAD (to become rtems-4.10). This consisted
+ mainly of fixing compiler warnings (mostly: adding prototypes
+ to function declarations and moving extern declarations to
+ global scope).
+
+ A pecularity: if_gfe.c had to remove 'queue.h' inclusion.
+ we have two versions of queue.h: one in newlib another one in
+ rtems - don't know how this is supposed to work...
+
+2009-10-17 Till Straumann <strauman@slac.stanford.edu>
+
+ * Makefile.am, network/if_mve_mv643xx_eth.c,
+ network/if_mve_pub.h: Enhanced low-level API allowing
+ the user to selectively enable/disable/acknowledge
+ interrupts and to install their own ISR (rather than having
+ the driver posting an event to a single task).
+
+2009-10-03 Till Straumann <strauman@slac.stanford.edu>
+ * network/if_mve/mv643xx_eth.c:
+ BUGFIX: mbuf leak; consume_rx_mbuf() must release mbuf
+ if 'len'<=0.
+
+ BUGFIX: Must initialize 'media-word' argument before
+ calling BSP_mve_media_ioctl() (defines PHY instance).
+
+2009-06-05 Till Straumann <strauman@slac.stanford.edu>
+ * network/if_mve/mv643xx_eth.c, network/if_mve/if_mve_pub.h,
+ Makefile.am: Added MC address reference count and
+ BSP_mve_mcast_filter_accept_del() to remove a single
+ entry from the filter.
+
+2009-06-05 Till Straumann <strauman@slac.stanford.edu>
+ * network/if_mve/mv643xx_eth.c, network/if_mve/if_mve_pub.h,
+ Makefile.am: first stab at adding multicast support.
+
+2009-06-05 Till Straumann <strauman@slac.stanford.edu>
+ * network/if_gfe/if_gfe.c:
+ o propagate PROMISC flag to hardware (SIOCSIFFLAGS)
+ o handle case where IFF_PROMISC is set (and wasn't before)
+ in gfe_hash_fill() routine.
+
+2009-06-02 Till Straumann <strauman@slac.stanford.edu>
+ * network/if_gfe/if_gfe.c: activated and fixed multicast
+ support.
+
+2009-06-01 Till Straumann <strauman@slac.stanford.edu>
+ * network/if_em/if_em.c: activated multicast support.
+
+2008-10-30 Till Straumann <strauman@slac.stanford.edu>
+
+ MERGED from rtems-4-7-branch:
+ * Makefile.am, network/if_mve/mv643xx.c, network/if_mve/if_mve_pub.h:
+ o Exported new low-level driver entry points:
+ - BSP_mve_ack_link_chg() so that changes in PHY link status can be
+ propagated to the serial port when handling link-change interrupts.
+ - BSP_mve_dump_stats() for printing statistics.
+ o FIXED reading of statistics counters.
+ o Count interrupts (statistics) in ISR rather than network daemon
+ (which is only used by the BSD driver).
+
+2008-10-04 Till Straumann <strauman@slac.stanford.edu>
+
+ * beatnik.cfg: updated to 4.9; removed make-exe
+ make-cxx-exe commands. Replaced CPU cflags to use
+ -mpowerpc -D__ppc_generic.
+
+2008-10-04 Till Straumann <strauman@slac.stanford.edu>
+
+ * startup/linkcmds: increased size of CODE memory
+ area to 32M.
+
+2008-05-10 Till Straumann <strauman@slac.stanford.edu>
+
+ * pci/gt_pci_init.c, pci/pci_io_remap.c: fixed 32-bit
+ types. RTEMS' pci_config access functions now use uint32_t,
+ earlier versions used unsigned. Both are incompatible,
+ unfortunately (gcc regards unsigned and unsigned long different
+ beasts leading to warnings and alias-issues :-()
+
+2008-05-10 Till Straumann <strauman@slac.stanford.edu>
+
+ * network/porting/rtemscompat1.h, network/porting/rtemscompat.h,
+ network/porting/if_xxx_rtems.c, network/if_gfe/if_gfe_rtems.c:
+ Fixed 32-bit types (pci config access, byteorder macros differ
+ depending on RTEMS version :-(). We now check for version and
+ use appropriate types (unsigned vs. uint32_t).
+ Silenced more warnings (ifndef DEBUG_MODULAR the METHODSPTR
+ is always non-zero; hence I ifdef'ed the affected code snippet).
+
+2008-03-20 Till Straumann <strauman@slac.stanford.edu>
+
+ * include/bsp.h, startup/bspstart.c: confdefs.h now wants
+ us to use BSP_INTERRUPT_STACK_SIZE instead of
+ CONFIGURE_INTERRUPT_STACK_MEMORY.
+
+2008-03-19 Till Straumann <strauman@slac.stanford.edu>
+
+ * irq/discovery_pic.c: must spare GPP7_0 etc. summary
+ interrupts in BSP_enable_irq_at_pic() etc.
+ New 'new-exceptions/bspsupport' code scans all IRQS
+ and enables or disables depending on the initial config
+ having a handler connected. This initial disable operation
+ switched-off the summaries and I had no GPP interrupts...
+
+2008-01-04 Till Straumann <strauman@slac.stanford.edu>
+
+ * startup/bspstart.c: changed Kate's copyright note
+ again as requested by her email 1/04/2008.
+
+2008-01-04 Till Straumann <strauman@slac.stanford.edu>
+
+ * startup/bspstart.c: changed Kate's copyright note
+ as requested by her email 8/16/2007.
+
+2007-12-11 Till Straumann <strauman@slac.stanford.edu>
+
+ * irq/discovery_pic.c: don't print warnings if an
+ invalid irq number is passed to BSP_disable_irq_at_pic(),
+ BSP_enable_irq_at_pic(). irq_supp.h says we must
+ silently ignore.
+
+2007-12-11 Till Straumann <strauman@slac.stanford.edu>
+
+ * Makefile.am: use new irq_bspsupport.rel which was
+ split out of exc_bspsupport.rel to provide finer-grained
+ control over what BSPs want to use.
+
+2007-12-10 Till Straumann <strauman@slac.stanford.edu>
+
+ * Makefile.am, startup/vpd.c, startup/vpd.h:
+ moved VPD support to ../shared/motorola.
+
+2007-12-08 Till Straumann <strauman@slac.stanford.edu>
+
+ * Makefile.am: merged shared/vme/vme_universe.c and
+ shared/vme/vme_universe_dma.c into one file.
+ Use vme_universe.c, vmeconfig.c from shared area.
+
+2007-11-30 Till Straumann <strauman@slac.stanford.edu>
+
+ * startup/bspstart: removed _Cpu_table.exceptions_in_RAM.
+
+2007/11/27 (TS):
+ - Generalized flash support and moved to shared area (libchip would probably
+ more appropriate).
+2007/10/22 (TS):
+ - DECREMENTER interrupt is now handled the same way external interrupts are.
+ It can also be assigned a priority and the handler is executed in priority
+ order, i.e., it can be preempted by higher-priority interrupts and
+ is protected from being preempted by lower-priority irqs.
+2007/10/08 (TS):
+ - ChangeLog added
+ - (Makefile.am) MUST NOT use -msoft-float because this also prevents CR7
+ to be set/cleared when calling vararg routines (which may then save/restore
+ FP args on the stack or do other bad things) :-(
+ Still don't know how to deal with implicit usage of the FPU by GCC
+ (problem in ISRs and integer-only tasks).
diff --git a/c/src/lib/libbsp/powerpc/beatnik/LICENSE b/c/src/lib/libbsp/powerpc/beatnik/LICENSE
new file mode 100644
index 0000000000..2ac95733bd
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/beatnik/LICENSE
@@ -0,0 +1,52 @@
+/* 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. Some files were ported from
+ * netbsd and/or freebsd and are covered by the respective
+ * file header copyright notices. E.g., the if_em driver is
+ * covered by it's own network/if_em/LICENSE.
+ */
+
+/*
+ * Authorship
+ * ----------
+ * This software ('beatnik' RTEMS BSP for MVME6100 and MVME5500) was
+ * created by Till Straumann <strauman@slac.stanford.edu>, 2005-2007,
+ * Stanford Linear Accelerator Center, Stanford University.
+ *
+ * Acknowledgement of sponsorship
+ * ------------------------------
+ * The 'beatnik' 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/beatnik/Makefile.am b/c/src/lib/libbsp/powerpc/beatnik/Makefile.am
new file mode 100644
index 0000000000..5433e2fca5
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/beatnik/Makefile.am
@@ -0,0 +1,245 @@
+##
+## $Id$
+##
+
+ACLOCAL_AMFLAGS = -I ../../../../aclocal
+
+SUBDIRS = .
+CLEANFILES =
+DISTCLEANFILES =
+noinst_PROGRAMS =
+EXTRA_DIST =
+
+
+include $(top_srcdir)/../../../../automake/compile.am
+include $(top_srcdir)/../../bsp.am
+
+include_bspdir = $(includedir)/bsp
+
+dist_project_lib_DATA = bsp_specs
+project_lib_DATA =
+
+#include
+include_HEADERS = include/bsp.h
+
+nodist_include_HEADERS = include/bspopts.h
+nodist_include_bsp_HEADERS = ../../shared/include/bootcard.h
+DISTCLEANFILES += include/bspopts.h
+
+include_bsp_HEADERS =
+
+#start
+EXTRA_DIST += ../../powerpc/shared/start/rtems_crti.S
+rtems_crti.$(OBJEXT): ../../powerpc/shared/start/rtems_crti.S
+ $(CPPASCOMPILE) -DASM -o $@ -c $<
+project_lib_DATA += rtems_crti.$(OBJEXT)
+
+
+EXTRA_DIST += ../../powerpc/shared/start/preload.S
+preload.$(OBJEXT): ../../powerpc/shared/start/preload.S
+ $(CPPASCOMPILE) -DASM -o $@ -c $<
+
+EXTRA_DIST += ../../powerpc/shared/start/vectors_entry.S
+vectors_entry.$(OBJEXT): ../../powerpc/shared/start/vectors_entry.S
+ $(CPPASCOMPILE) -DASM -o $@ -c $<
+
+EXTRA_DIST += ../../powerpc/shared/start/start.S
+start.$(OBJEXT): ../../powerpc/shared/start/start.S
+ $(CPPASCOMPILE) -DASM -o $@ -c $<
+
+motld_start.$(OBJEXT): preload.$(OBJEXT) vectors_entry.$(OBJEXT) start.$(OBJEXT)
+ $(LD) -o $@ -r $^
+
+project_lib_DATA += motld_start.$(OBJEXT)
+
+
+#startup
+
+dist_project_lib_DATA += ../shared/startup/linkcmds
+
+build_date.c::
+ echo 'const char *BSP_build_date="'`date`'";' > $@
+
+noinst_LIBRARIES = libbsp.a
+libbsp_a_SOURCES =
+
+libbsp_a_SOURCES += startup/bspstart.c \
+ ../shared/motorola/vpd.c startup/reboot.c startup/i2c_init.c build_date.c \
+ ../../powerpc/shared/startup/panic.c \
+ ../../powerpc/shared/startup/bspgetworkarea.c \
+ ../../powerpc/shared/startup/probeMemEnd.c \
+ ../../powerpc/shared/startup/pretaskinghook.c \
+ ../../powerpc/shared/startup/zerobss.c \
+ ../../powerpc/shared/startup/pgtbl_setup.c \
+ ../../powerpc/shared/startup/pgtbl_activate.c \
+ ../../powerpc/shared/startup/sbrk.c ../../shared/bootcard.c \
+ startup/bspclean.c ../../shared/bsplibc.c ../../shared/bsppost.c \
+ ../../shared/bsppredriverhook.c \
+ ../../shared/gnatinstallhandler.c
+
+include_bsp_HEADERS += ../shared/motorola/vpd.h
+
+#pclock
+libbsp_a_SOURCES += ../../powerpc/shared/clock/p_clock.c
+
+#console
+include_bsp_HEADERS += ../../powerpc/shared/console/consoleIo.h
+include_bsp_HEADERS += ../../powerpc/shared/console/uart.h
+
+libbsp_a_SOURCES += \
+ ../../powerpc/shared/console/uart.c \
+ ../../powerpc/shared/console/console.c \
+ ../../powerpc/shared/console/consoleIo.h \
+ ../../powerpc/shared/console/uart.h
+
+#irq
+include_bsp_HEADERS += irq/irq.h
+
+libbsp_a_SOURCES += irq/irq_init.c irq/discovery_pic.c
+
+#marvell
+include_bsp_HEADERS += marvell/gtreg.h marvell/gtintrreg.h \
+ marvell/gti2creg.h marvell/gti2c_busdrv.h marvell/gt_timer.h \
+ marvell/gtpcireg.h
+
+libbsp_a_SOURCES += marvell/discovery.c marvell/gti2c.c marvell/gt_timer.c
+
+#flash
+include_bsp_HEADERS += ../shared/flash/flashPgm.h
+include_bsp_HEADERS += ../shared/flash/flashPgmPvt.h
+
+libbsp_a_SOURCES += ../shared/flash/flash.c \
+ ../shared/flash/intelFlash.c \
+ flash/flashcfg.c
+
+#pci
+include_bsp_HEADERS += ../../powerpc/shared/pci/pci.h
+
+libbsp_a_SOURCES += ../../powerpc/shared/pci/pci.c \
+ pci/gt_pci_init.c pci/pci_io_remap.c pci/motload_fixup.c \
+ ../../powerpc/shared/pci/pcifinddevice.c
+
+#vectors
+include_bsp_HEADERS += ../../../libcpu/@RTEMS_CPU@/@exceptions@/bspsupport/vectors.h
+include_bsp_HEADERS += ../../../libcpu/@RTEMS_CPU@/@exceptions@/bspsupport/irq_supp.h
+include_bsp_HEADERS += ../../../libcpu/@RTEMS_CPU@/@exceptions@/bspsupport/ppc_exc_bspsupp.h
+
+#vme
+include_bsp_HEADERS += vme/VMEConfig.h \
+ ../../shared/vmeUniverse/vmeUniverse.h \
+ ../../shared/vmeUniverse/vmeUniverseDMA.h \
+ ../../shared/vmeUniverse/vme_am_defs.h \
+ ../../shared/vmeUniverse/vmeTsi148.h \
+ ../../shared/vmeUniverse/vmeTsi148DMA.h \
+ ../../shared/vmeUniverse/bspVmeDmaList.h \
+ ../../shared/vmeUniverse/VME.h \
+ ../../shared/vmeUniverse/VMEDMA.h
+
+libbsp_a_SOURCES += ../shared/vme/vmeconfig.c \
+ ../shared/vme/vme_universe.c \
+ ../../shared/vmeUniverse/vmeUniverse.c \
+ ../../shared/vmeUniverse/vmeTsi148.c \
+ ../../shared/vmeUniverse/bspVmeDmaList.c
+
+#network
+if HAS_NETWORKING
+include_bsp_HEADERS += network/support/early_enet_link_status.h \
+ network/support/bsp_bsdnet_attach.h
+
+noinst_PROGRAMS += network_support.rel
+network_support_rel_SOURCES = network/support/early_link_status.c \
+ network/support/bsp_attach.c
+network_support_rel_CPPFLAGS = $(AM_CPPFLAGS)
+network_support_rel_LDFLAGS = $(RTEMS_RELLDFLAGS)
+
+include_bsp_HEADERS += network/if_mve/if_mve_pub.h
+
+noinst_PROGRAMS += network_if_mve_tmp.rel
+network_if_mve_tmp_rel_SOURCES = network/if_mve/mv643xx_eth.c
+network_if_mve_tmp_rel_CPPFLAGS = $(AM_CPPFLAGS) -DDISABLE_DETACHING
+network_if_mve_tmp_rel_CFLAGS = $(AM_CFLAGS)
+network_if_mve_tmp_rel_LDFLAGS = $(RTEMS_RELLDFLAGS)
+
+# remove all unneccessary global symbols to avoid name clashes
+# with BSD stuff;
+network_if_mve.rel: network_if_mve_tmp.rel
+ $(OBJCOPY) -G rtems_mve_attach -G rtems_mve_early_link_check_ops \
+ -G BSP_mve_ack_irqs -G BSP_mve_disable_irqs \
+ -G BSP_mve_enable_irqs -G BSP_mve_init_hw \
+ -G BSP_mve_ack_irq_mask -G BSP_mve_disable_irq_mask \
+ -G BSP_mve_enable_irq_mask -G BSP_mve_setup_1 \
+ -G BSP_mve_read_eaddr -G BSP_mve_send_buf \
+ -G BSP_mve_send_buf_raw \
+ -G BSP_mve_setup -G BSP_mve_stop_hw \
+ -G BSP_mve_swipe_rx -G BSP_mve_swipe_tx \
+ -G BSP_mve_detach -G BSP_mve_media_ioctl \
+ -G BSP_mve_get_tid \
+ -G BSP_mve_dump_stats -G BSP_mve_ack_link_chg \
+ -G BSP_mve_mcast_filter_clear \
+ -G BSP_mve_mcast_filter_accept_all \
+ -G BSP_mve_mcast_filter_accept_add \
+ -G BSP_mve_mcast_filter_accept_del \
+ -G mveth_serial_ctrl_config_val \
+ $^ $@
+
+include_bsp_HEADERS += network/if_gfe/if_gfe_pub.h
+
+noinst_PROGRAMS += network_if_gfe_tmp.rel
+network_if_gfe_tmp_rel_SOURCES = network/if_gfe/if_gfe.c network/if_gfe/if_gfe_rtems.c
+network_if_gfe_tmp_rel_CPPFLAGS = $(AM_CPPFLAGS) \
+ -I$(srcdir)/network/porting -I$(srcdir)/network/if_gfe
+network_if_gfe_tmp_rel_CFLAGS = -Wno-unused-variable $(AM_CFLAGS)
+network_if_gfe_tmp_rel_LDFLAGS = $(RTEMS_RELLDFLAGS)
+
+# remove all unneccessary global symbols to avoid name clashes
+# with BSD stuff;
+network_if_gfe.rel: network_if_gfe_tmp.rel
+ $(OBJCOPY) -G rtems_gfe_attach -G net_driver_ticks_per_sec \
+ -G rtems_gfe_setup -G rtems_gfe_early_link_check_ops \
+ $^ $@
+
+
+include_bsp_HEADERS += network/if_em/if_em_pub.h
+
+noinst_PROGRAMS += network_if_em_tmp.rel
+network_if_em_tmp_rel_SOURCES = network/if_em/if_em.c \
+ network/if_em/if_em_hw.c \
+ network/if_em/if_em_rtems.c
+network_if_em_tmp_rel_CPPFLAGS = $(AM_CPPFLAGS) \
+ -I$(srcdir)/network/porting -I$(srcdir)/network/if_em
+network_if_em_tmp_rel_CFLAGS = -Wno-unused-variable $(AM_CFLAGS)
+network_if_em_tmp_rel_LDFLAGS = $(RTEMS_RELLDFLAGS)
+
+network_if_em.rel: network_if_em_tmp.rel
+ $(OBJCOPY) -G rtems_em_attach -G net_driver_ticks_per_sec \
+ -G rtems_em_pci_setup -G rtems_em_early_link_check_ops \
+ $^ $@
+endif
+
+# tod
+nodist_include_HEADERS += ../../shared/tod.h
+
+libbsp_a_SOURCES += ../../shared/tod.c tod/todcfg.c
+
+libbsp_a_LIBADD = ../../../libcpu/@RTEMS_CPU@/shared/cpuIdent.rel \
+ ../../../libcpu/@RTEMS_CPU@/shared/cache.rel \
+ ../../../libcpu/@RTEMS_CPU@/shared/stack.rel \
+ ../../../libcpu/@RTEMS_CPU@/@exceptions@/rtems-cpu.rel \
+ ../../../libcpu/@RTEMS_CPU@/@exceptions@/exc_bspsupport.rel \
+ ../../../libcpu/@RTEMS_CPU@/@exceptions@/irq_bspsupport.rel \
+ ../../../libcpu/@RTEMS_CPU@/mpc6xx/clock.rel \
+ ../../../libcpu/@RTEMS_CPU@/mpc6xx/mmu.rel \
+ ../../../libcpu/@RTEMS_CPU@/mpc6xx/timer.rel \
+ ../../../libcpu/@RTEMS_CPU@/mpc6xx/altivec.rel
+
+if HAS_NETWORKING
+libbsp_a_LIBADD += network_support.rel \
+ network_if_mve.rel network_if_gfe.rel network_if_em.rel
+endif
+
+all-local: $(PREINSTALL_FILES) $(TMPINSTALL_FILES)
+
+EXTRA_DIST += README LICENSE ChangeLog
+
+include $(srcdir)/preinstall.am
+include $(top_srcdir)/../../../../automake/local.am
diff --git a/c/src/lib/libbsp/powerpc/beatnik/README b/c/src/lib/libbsp/powerpc/beatnik/README
new file mode 100644
index 0000000000..699f9a5e9d
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/beatnik/README
@@ -0,0 +1,178 @@
+Some information about this BSP
+================================
+
+ACKNOWLEDGEMENTS
+----------------
+Acknowledgements:
+ Valuable information was obtained from the following drivers
+ netbsd: Allegro Networks Inc; Wasabi Systems Inc.
+ linux: MontaVista, Software, Inc; Chris Zankel, Mark A. Greer.
+ Matthew Dharm, rabeeh, Manish Lachwani, Ralf Baechle.
+ rtems: Brookhaven National Laboratory; Shuchen Kate Feng
+ 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.
+
+ In particular, the Author wishes to thank Shuchen Kate Feng (BNL) for many
+ inspiring discussions and Dayle Kotturi (SLAC) for her contributions, support
+ and extensive testing.
+
+LICENSE
+-------
+See ./LICENSE file.
+
+Note that not all files that are part of this BSP were written by
+me (most notably, the ethernet drivers if_gfe [netbsd port] and
+if_em [freebsd port]). Consult individual file headers for copyright
+and authorship information.
+
+BUILD INFO
+----------
+(relevant only if you received this BSP unbundled from the RTEMS distribution)
+
+ prepare:
+ - get up-to date RTEMS release
+ - untar beatnik.tgz into c/src/lib/libbsp/powerpc
+ - copy beatnik.cfg into make/custom
+ - patch c/src/lib/libsp/powerpc/acinclude.ac
+ - run 'bootstrap' from top directory; make sure RTEMS
+ autoXXX are found first in your PATH
+ configure:
+ - configure with your favorite options. BSP name is 'beatnik'
+ I recommend passing RTEMS_CFLAGS=-g to 'configure'
+
+TARGET
+------
+Even though this BSP is binary compatible with the MVME5500 it's primary
+target was and is the MVME6100 board which in some respects is quite different.
+In particular, the discovery chip and the VME bridge exhibit significant
+differences.
+I am sometimes asked why this BSP provides yet another port of the gfe
+and em BSD drivers (which had previously been ported for the mvme5500
+BSP by Shuchen Kate Feng [BNL]). The answer is simply a matter of time:
+Once support for the 6100 board was completed I found it easier to use
+the set of 'quick-and-dirty' wrappers (found in network/porting) that I had
+developed for other projects and to do a new port from scratch using that
+framework rather than modifying the mvme5500 BSP's drivers. mvme5500 support was
+added to this BSP because we own a few of those boards we occasionally
+play with but we don't want to build and support an additional BSP for them.
+An important detail -- hardware cache snooping -- was borrowed from
+Shuchen Kate Feng's gfe driver port, though.
+
+HARDWARE SUPPORT
+===============
+(some of the headers mentioned below contain more
+detailed information)
+
+NOTE: The BSP supports both, the mvme6100 and the mvme5500 boards.
+ It detects relevant hardware at run-time.
+
+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 discovery timer
+ could be used.)
+
+PIC (interrupt controller) (bsp/irq.h): Marvell hostbridge
+ does not implement interrupt priorities. The driver supports
+ priorities in software (masking lower priority lines during
+ execution of higher priority ISR). I believe the design of the
+ IRQ subsystem is as efficient as possible with focus on low
+ latencies.
+ In addition to the rtems IRQ API, calls are available to
+ change IRQ priority and to enable/disable interrupts at the PIC.
+
+EXCEPTIONS: (bspException.h) Routines to install a user callback
+ for (PPC) exception handling.
+
+PCI (bsp/pci.h): The BSP hides the fact that there are effectively
+ two 'root' busses (AKA 'hoses') behind the discovery bridge.
+ Devices are addressed by bus/slot/function-triples and the PCI
+ subsystem transparently figures out what hose to use.
+ 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: CHRP; 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: Address constants are defined in bsp.h
+
+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 and eeprom
+ are available as device files (bsp.h); lower-level interface is
+ provided by libi2c.h.
+ NOTE: The I2C devices are not registered and the driver is not
+ initialized by default. Call BSP_i2c_initialize() to do that;
+ this will create
+ /dev/i2c0.vpd-eeprom
+ /dev/i2c0.usr-eeprom
+ /dev/i2c0.ds1621
+ You can then 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 drivers
+ (vmeUniverse.h, vmeTsi148.h) directly unless you know what you are
+ doing (i.e., if you need specific features provided by the particular
+ chip; currently, both of the mentioned chip drivers expose entry points
+ that are designed to be compatible).
+
+ 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 5500/6100 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 above) 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/vmeUniverse.h, 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/gt_timer.h). Programmable general-purpose (GPT) and
+ watchdog 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.
+
+ The watchdog timer - when started - issues a hard-reset of the
+ board if not 'petted' within a configurable timeout period.
+
+NETWORK: (bsp/bsp_bsdnet_attach.h). The BSP offers a call to list
+ all available interfaces (name, description, 'attach'-method)
+ for the application to make a selection.
+ Alternatively, there are BSP_auto_network_driver_name and
+ BSP_auto_enet_attach(), the latter with the capability to configure
+ the first NIC with a 'live' link status.
+ All drivers (rewritten 'mve' for the mv64360 NIC (6100) and BSD ports
+ 'gfe'/'em' (5500)) support the SIOCSIFMEDIA/SIOCGIFMEDIA ioctls
+ (rtems/rtems_mii_ioctl.h provides helpers to convert strings from/to
+ control words).
+
+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>, 2005-2007.
diff --git a/c/src/lib/libbsp/powerpc/beatnik/bsp_specs b/c/src/lib/libbsp/powerpc/beatnik/bsp_specs
new file mode 100644
index 0000000000..3c859d1d66
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/beatnik/bsp_specs
@@ -0,0 +1,13 @@
+%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 -e __rtems_entry_point -u __vectors motld_start.o%s}}
+
+*link:
+%{!qrtems: %(old_link)} %{qrtems: -dp -Bstatic}
+
+*endfile:
+%{!qrtems: %(old_endfile)} %{qrtems: crtend.o%s ecrtn.o%s}
diff --git a/c/src/lib/libbsp/powerpc/beatnik/configure.ac b/c/src/lib/libbsp/powerpc/beatnik/configure.ac
new file mode 100644
index 0000000000..d8f6a3f83c
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/beatnik/configure.ac
@@ -0,0 +1,40 @@
+## Process this file with autoconf to produce a configure script.
+##
+## configure.ac,v 1.9.2.3 2003/08/11 14:37:22 ralf Exp
+
+AC_PREREQ(2.59)
+AC_INIT([rtems-c-src-lib-libbsp-powerpc-beatnik],[_RTEMS_VERSION],[rtems-bugs@rtems.com])
+AC_CONFIG_SRCDIR([bsp_specs])
+RTEMS_TOP(../../../../../..)
+
+RTEMS_CANONICAL_TARGET_CPU
+AM_INIT_AUTOMAKE([no-define nostdinc foreign 1.9])
+RTEMS_BSP_CONFIGURE
+
+RTEMS_PROG_CC_FOR_TARGET([-ansi -fasm])
+RTEMS_CANONICALIZE_TOOLS
+RTEMS_PROG_CCAS
+
+RTEMS_CHECK_TOOL([OBJCOPY],[objcopy])
+
+RTEMS_CHECK_NETWORKING
+AM_CONDITIONAL(HAS_NETWORKING,test "$HAS_NETWORKING" = "yes")
+
+AS=$CC
+AM_PROG_AS
+
+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/beatnik/flash/flashcfg.c b/c/src/lib/libbsp/powerpc/beatnik/flash/flashcfg.c
new file mode 100644
index 0000000000..3dc76c504d
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/beatnik/flash/flashcfg.c
@@ -0,0 +1,182 @@
+/*
+ * Authorship
+ * ----------
+ * This software ('beatnik' RTEMS BSP for MVME6100 and MVME5500) was
+ * created by Till Straumann <strauman@slac.stanford.edu>, 2005-2007,
+ * Stanford Linear Accelerator Center, Stanford University.
+ *
+ * Acknowledgement of sponsorship
+ * ------------------------------
+ * The 'beatnik' 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 <stdio.h>
+#include <inttypes.h>
+
+#define STATIC static
+
+#include <bsp/flashPgmPvt.h>
+
+/* MVME Board Specifica; board status reg. 2 where write-enable is controlled... */
+
+#define SYS_FLASHA_WP (1<<5)
+#define SYS_FBOOTB_WP (1<<3)
+#define SYS_FBA_WP_HDR (1<<2)
+#define SYS_FBOOTB_WP_HDR (1<<1)
+
+#define SYS_STATUS_2_REG (1)
+
+/* Forward Declarations */
+STATIC struct bankdesc *
+bankcheck(int bank, int quiet);
+
+static int
+flash_wp(int bank, int enbl);
+
+STATIC uint32_t
+read_us_timer(void);
+
+/* Global Variables */
+
+/* motload memory map */
+static struct bankdesc mvme5500Flash[] = {
+ { 0, 2 }, /* first entry gives number of entries */
+ { 0xf2000000, 0x08000000, 0x20000*2, 2, BSP_flash_vendor_intel, 0, 0, 0, },
+ { 0xff800000, 0x00800000, 0x20000*2, 2, BSP_flash_vendor_intel, 0, 0, 0, },
+};
+
+/* motload memory map */
+static struct bankdesc mvme6100Flash[] = {
+ { 0, 2 }, /* first entry gives number of entries */
+ { 0xf4000000, 0x04000000, 0x20000*2, 2, BSP_flash_vendor_intel, 0, 0, 0, },
+ { 0xf8000000, 0x04000000, 0x20000*2, 2, BSP_flash_vendor_intel, 0, 0, 0, },
+};
+
+struct flash_bsp_ops BSP_flashBspOps = {
+ bankcheck : bankcheck,
+ flash_wp : flash_wp,
+ read_us_timer: read_us_timer,
+};
+
+/* set (enbl:1), clear (enbl:0) or query (enbl:-1) write protection
+ *
+ * RETURNS 0 on success, nonzero on error.
+ */
+static int
+flash_wp(int bank, int enbl)
+{
+BSP_BoardType b;
+A8 p;
+unsigned char hwp = 0, swp;
+
+ /* validate 'bank' argument */
+ if ( !bankcheck( bank, 0 ) )
+ return -1;
+
+ switch ( (b=BSP_getBoardType()) ) {
+ default:
+ fprintf(stderr,"Unknown board type %i\n",b);
+ return -1;
+
+ case MVME5500:
+ /* bit enables both banks; no readback of jumper available */
+ p = (A8)(BSP_MV64x60_DEV1_BASE + SYS_STATUS_2_REG);
+ swp = SYS_FLASHA_WP;
+ break;
+
+ case MVME6100:
+ {
+
+ p = (A8)(BSP_MV64x60_DEV1_BASE + SYS_STATUS_2_REG);
+ if ( 0 == bank ) {
+ hwp = SYS_FBA_WP_HDR;
+ swp = SYS_FLASHA_WP;
+ } else {
+ hwp = SYS_FBOOTB_WP_HDR;
+ swp = SYS_FBOOTB_WP;
+ }
+ if ( enbl && (*p & hwp) ) {
+ fprintf(stderr,"HW write protection enabled (jumper)\n");
+ return -1;
+ }
+ }
+ break;
+ }
+ if ( -1 == enbl ) {
+ /* query */
+ return *p & (swp | hwp);
+ } else {
+ if ( enbl ) {
+ *p |= swp;
+ } else {
+ *p &= ~swp;;
+ }
+ }
+ return 0;
+}
+
+/* Lookup bank description in table */
+STATIC struct bankdesc *
+bankcheck(int bank, int quiet)
+{
+struct bankdesc *b;
+ switch ( BSP_getBoardType() ) {
+ case MVME5500: b = mvme5500Flash; break;
+ case MVME6100: b = mvme6100Flash; break;
+ default:
+ fprintf(stderr,"Unknown/unsupported board type\n");
+ return 0;
+ }
+ if ( bank >= b->size || bank < 0 ) {
+ if ( !quiet )
+ fprintf(stderr,"Invalid flash bank #: %i; (too big)\n", bank);
+ return 0;
+ }
+ return b + bank + 1;
+}
+
+STATIC uint32_t read_us_timer(void)
+{
+uint32_t now, mhz;
+
+ /* we burn cycles anyways... */
+ mhz = BSP_bus_frequency/BSP_time_base_divisor/1000;
+
+ asm volatile("mftb %0":"=r"(now));
+
+ return now/mhz;
+}
diff --git a/c/src/lib/libbsp/powerpc/beatnik/include/.cvsignore b/c/src/lib/libbsp/powerpc/beatnik/include/.cvsignore
new file mode 100644
index 0000000000..5f1077556d
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/beatnik/include/.cvsignore
@@ -0,0 +1,4 @@
+bspopts.h
+bspopts.h.in
+stamp-h
+stamp-h.in
diff --git a/c/src/lib/libbsp/powerpc/beatnik/include/bsp.h b/c/src/lib/libbsp/powerpc/beatnik/include/bsp.h
new file mode 100644
index 0000000000..84a3cfce00
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/beatnik/include/bsp.h
@@ -0,0 +1,273 @@
+/*
+ * 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.
+ *
+ * S. Kate Feng 2003-2007 : Modified it to support the mvme5500 BSP.
+ *
+ * Modified for the 'beatnik' BSP by T. Straumann, 2005-2007.
+ *
+ * bsp.h,v 1.9.4.2 2003/09/04 18:45:20 joel Exp
+ */
+#ifndef LIBBSP_BEATNIK_BSP_H
+#define LIBBSP_BEATNIK_BSP_H
+
+#include <bspopts.h>
+
+#include <rtems.h>
+#include <rtems/console.h>
+#include <libcpu/io.h>
+#include <rtems/clockdrv.h>
+#include <bsp/vectors.h>
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/* Board type */
+typedef enum {
+ Unknown = 0,
+ MVME5500,
+ MVME6100
+} BSP_BoardType;
+
+BSP_BoardType
+BSP_getBoardType();
+
+/* Discovery Version */
+
+typedef enum {
+ unknown = 0,
+ GT_64260_A, /* Revision 0x10 */
+ GT_64260_B, /* Revision 0x20 */
+ MV_64360,
+} DiscoveryVersion;
+
+/* Determine the type of discovery chip on this board; info
+ * is cached and repeated calls just return the cached value.
+ *
+ * If a non-zero argument is passed, the routine panics
+ * (BSP_panic) if no recognized bridge is found;
+ */
+
+DiscoveryVersion
+BSP_getDiscoveryVersion(int assertion);
+
+/*
+ * 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 BSP_INTERRUPT_STACK_SIZE (16 * 1024)
+
+/*
+ * base address definitions for several devices
+ *
+ */
+#define BSP_MV64x60_BASE (0xf1000000)
+#define BSP_MV64x60_DEV1_BASE (0xf1100000)
+#define BSP_UART_IOBASE_COM1 ((BSP_MV64x60_DEV1_BASE)+0x20000)
+#define BSP_UART_IOBASE_COM2 ((BSP_MV64x60_DEV1_BASE)+0x21000)
+#define BSP_UART_USE_SHARED_IRQS
+
+#define BSP_NVRAM_BASE_ADDR (0xf1110000)
+#define BSP_NVRAM_END_ADDR (0xf1117fff)
+#define BSP_NVRAM_RTC_START (0xf1117ff8)
+
+#define BSP_NVRAM_BOOTPARMS_START (0xf1111000)
+#define BSP_NVRAM_BOOTPARMS_END (0xf1111fff)
+
+
+/* This is only active/used during early init. It defines
+ * the hose0 base for the shared/generic pci code.
+ * Our own BSP specific pci initialization will then
+ * override the PCI configuration (see gt_pci_init.c:BSP_pci_initialize)
+ */
+
+#define PCI_CONFIG_ADDR (BSP_MV64x60_BASE + 0xcf8)
+#define PCI_CONFIG_DATA (BSP_MV64x60_BASE + 0xcfc)
+
+/* our wonderful PCI initialization remaps everything to CPU addresses
+ * - before calling BSP_pci_initialize() this is NOT VALID, however
+ * and the deprecated inl()/outl() etc won't work!
+ */
+#define _IO_BASE 0x00000000
+/* wonderful MotLoad has the base address as seen from the CPU programmed into config space :-) */
+#define PCI_MEM_BASE 0
+#define PCI_MEM_BASE_ADJUSTMENT 0
+#define PCI_DRAM_OFFSET 0
+
+/* PCI <-> local address mapping - no sophisticated windows
+ * (i.e., no support for cached regions etc. you read a BAR
+ * from config space and that's 1:1 where the CPU sees it).
+ * Our memory is mapped 1:1 to PCI also.
+ */
+#define BSP_PCI2LOCAL_ADDR(a) ((uint32_t)(a))
+#define BSP_LOCAL2PCI_ADDR(a) ((uint32_t)(a))
+
+#define BSP_CONFIG_NUM_PCI_CACHE_SLOTS 32
+
+#define BSP_CONSOLE_PORT BSP_UART_COM1
+#define BSP_UART_BAUD_BASE 115200
+
+/* 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_USR_I2C_ADDR (0xAA>>1) /* the user EEPROM */
+#define BSP_THM_I2C_ADDR (0x90>>1) /* the DS1621 temperature sensor & thermostat */
+
+#define BSP_I2C_BUS_DESCRIPTOR gt64260_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_DS1621_NAME "ds1621"
+#define BSP_I2C_THM_NAME BSP_I2C_DS1621_NAME
+#define BSP_I2C_DS1621_RAW_NAME "ds1621-raw"
+
+#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_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)
+
+
+/* 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.ds1621 (read-only; one byte: board-temp in degC)
+ * /dev/i2c0.ds1621-raw (read-write; transfer bytes to/from the ds1621)
+ */
+int
+BSP_i2c_initialize();
+
+/* Networking; */
+#include <bsp/bsp_bsdnet_attach.h>
+
+/* NOT FOR PUBLIC USE BELOW HERE */
+#define BSP_PCI_HOSE0_MEM_BASE 0x80000000 /* must be aligned to size */
+#define BSP_PCI_HOSE0_MEM_SIZE 0x20000000
+
+#define BSP_PCI_HOSE1_MEM_BASE 0xe0000000
+
+#define BSP_DEV_AND_PCI_IO_BASE 0xf0000000
+#define BSP_DEV_AND_PCI_IO_SIZE 0x10000000
+
+/* maintain coherency between CPU and GT64340 ethernet (& possibly other discovery components) */
+#define BSP_RW_PAGE_ATTRIBUTES TRIV121_ATTR_M
+
+extern unsigned BSP_pci_hose1_bus_base;
+
+void BSP_pci_initialize();
+
+/* Exception Handling */
+
+/* Use a task notepad to attach user exception handler info;
+ * may be changed by application startup code (EPICS uses 11)
+ */
+#define BSP_EXCEPTION_NOTEPAD 14
+
+#ifndef ASM
+
+#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))
+/*
+ * Vital Board data Start using DATA RESIDUAL
+ */
+/*
+ * 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;
+
+extern char BSP_productIdent[20];
+extern char BSP_serialNumber[20];
+
+extern char BSP_enetAddr0[7];
+extern char BSP_enetAddr1[7];
+
+/*
+ * The commandline as passed from the bootloader.
+ */
+extern char *BSP_commandline_string;
+
+
+#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 bsp_reset(void);
+extern int BSP_disconnect_clock_handler (void);
+extern int BSP_connect_clock_handler (void);
+
+/* clear hostbridge errors
+ *
+ * enableMCP: whether to enable MCP checkstop / machine check interrupts
+ * on the hostbridge and in HID0.
+ *
+ * NOTE: The 5500 and 6100 boards have NO PHYSICAL CONNECTION
+ * to MCP so 'enableMCP' will always fail!
+ *
+ * quiet : be silent
+ *
+ * RETURNS : PCI status (hose 0 in byte 0, host 1 in byte 1) and
+ * VME bridge status (upper 16 bits).
+ * Zero if no errors were found.
+ */
+extern unsigned long _BSP_clear_hostbridge_errors(int enableMCP, int quiet);
+
+/* clear vme bridge errors and return (bridge-dependent) 16-bit status
+ *
+ * quiet : be silent
+ *
+ * RETURNS : 0 if there were no errors, non-zero, bridge-dependent
+ * 16-bit error status on error.
+ *
+ */
+extern unsigned short
+(*_BSP_clear_vmebridge_errors)(int);
+
+
+#endif
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif
diff --git a/c/src/lib/libbsp/powerpc/beatnik/irq/discovery_pic.c b/c/src/lib/libbsp/powerpc/beatnik/irq/discovery_pic.c
new file mode 100644
index 0000000000..8b0eba27fc
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/beatnik/irq/discovery_pic.c
@@ -0,0 +1,995 @@
+/* $Id$ */
+
+/* Interrupt driver + dispatcher for the discovery host controller */
+
+/* Author: T. Straumann, 2005-2007
+ *
+ * Acknowledgements:
+ * Valuable information was obtained from the following drivers
+ * netbsd: (C) Allegro Networks Inc; Wasabi Systems Inc.
+ * linux: (C) MontaVista, Software, Inc; Chris Zankel, Mark A. Greer.
+ * rtems: (C) Brookhaven National Laboratory; K. Feng
+ * but this implementation is original work by the author.
+ */
+
+/*
+ * Authorship
+ * ----------
+ * This software ('beatnik' RTEMS BSP for MVME6100 and MVME5500) was
+ * created by Till Straumann <strauman@slac.stanford.edu>, 2005-2007,
+ * Stanford Linear Accelerator Center, Stanford University.
+ *
+ * Acknowledgement of sponsorship
+ * ------------------------------
+ * The 'beatnik' 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 <bsp/irq.h>
+#include <bsp/gtreg.h>
+#include <bsp/gtintrreg.h>
+#include <rtems/bspIo.h>
+#include <bsp/vectors.h>
+#include <libcpu/byteorder.h>
+#include <libcpu/spr.h>
+
+/* dont change the order (main_lo, main_hi, gpp) which
+ * matches the interrupt numbers!
+ */
+#define MAIN_LO_IDX 0
+#define MAIN_HI_IDX 1
+#define GPP_IDX 2
+#define NUM_INTR_REGS 3
+
+
+#define SYNC() asm volatile("sync")
+
+/* How many times should the ISR dispatcher check for
+ * pending interrupts until it decides that something's
+ * fishy (i.e., a user ISR fails to clear the interrupt
+ * source)
+ */
+#define MAX_SPIN_LOOPS 100
+
+/* If FASTER is defined, a few obscure I/O statements found in the linux
+ * driver are removed
+ */
+#define FASTER
+
+/* Array helper */
+#define NumberOf(arr) (sizeof(arr)/sizeof((arr)[0]))
+
+
+/* MVME6100 specific; re-define watchdog NMI pin to be a normal output
+ * so we have a way to raise an interrupt in software (GPP[26] is wired to
+ * GPP[6] on the MVME6100).
+ */
+#define MVME6100_IRQ_DEBUG 4
+
+#define GPP_WIRED_OUT_BIT_6100 26 /* CAVEAT: this is bit 26 on the 6100 */
+#define GPP_WIRED_OUT_BIT_5500 24 /* CAVEAT: this is bit 24 on the 5500 */
+#define GPP_WIRED_IN_BIT 6
+
+/* Ored mask of debugging features to enable */
+#define IRQ_DEBUG_BASIC 1
+/* This is _very_ lowlevel */
+#define IRQ_DEBUG_DISPATCHER 2
+/* Record maximal dispatching latency */
+#define IRQ_DEBUG_MAXLAT 8 /* PPC only */
+
+#define IRQ_DEBUG (0 /*|(IRQ_DEBUG_BASIC)*/|(MVME6100_IRQ_DEBUG)|(IRQ_DEBUG_MAXLAT))
+
+/**********
+ * Typedefs
+ **********/
+
+/* Set of the three relevant cause registers */
+typedef volatile unsigned IrqMask[NUM_INTR_REGS];
+
+#define REGP(x) ((volatile uint32_t *)(x))
+
+/* Information we keep about the PIC */
+typedef struct _Mv64x60PicRec {
+ /* base address as seen from CPU */
+ uintptr_t reg_base;
+
+ /* addresses of 'cause' registers */
+ volatile uint32_t *causes[NUM_INTR_REGS];
+
+ /* addresses of 'mask' registers */
+ volatile uint32_t *masks[NUM_INTR_REGS];
+
+ /* masks for all priorities. If an
+ * interrupt source has priority X,
+ * its corresponding bit is set
+ * (enabled) in mcache[i] for all
+ * i < X and cleared for i >= X
+ */
+ volatile IrqMask mcache[BSP_IRQ_MAX_PRIO+1];
+
+ /* Priority we're executing at.
+ * Thread-level is priority 0,
+ * ISRs range from 1..MAX_PRIO
+ */
+ volatile rtems_irq_prio current_priority;
+} Mv64x60PicRec, *Mv64x60Pic;
+
+/**********
+ * Globals
+ **********/
+
+
+/* Copy of the configuration */
+static rtems_irq_global_settings theConfig;
+/* PIC description */
+static Mv64x60PicRec thePic;
+
+#if (IRQ_DEBUG) & MVME6100_IRQ_DEBUG
+static unsigned long gpp_out_bit = 0;
+#endif
+
+#if (IRQ_DEBUG) & IRQ_DEBUG_MAXLAT
+unsigned long discovery_pic_max_dispatching_latency = 0;
+#ifdef __PPC__
+static inline unsigned long mftb(void)
+{
+unsigned long rval;
+ asm volatile("mftb %0":"=r"(rval));
+ return rval;
+}
+#else
+#define mftb() 0
+#endif
+#endif
+
+/**********
+ * Functions
+ **********/
+
+/* Debugging helper routines */
+static void pregs(volatile uint32_t **p)
+{
+int i;
+ for (i=NUM_INTR_REGS-1; i>=0; i--) {
+ printk(" 0x%08x", ld_le32(p[i]));
+ printk( i ? " --":"\n");
+ }
+}
+
+static void pmsks(volatile IrqMask p)
+{
+int i;
+ for (i=NUM_INTR_REGS-1; i>=0; i--) {
+ printk(" 0x%08x", p[i]);
+ printk( i ? " --":"\n");
+ }
+}
+
+void discovery_dump_picregs(void)
+{
+ printk(" ..GPP_IRQ. -- ..MAIN_HI. -- ..MAIN_LO.\n");
+ printk("Cause:"); pregs(thePic.causes);
+ printk("Mask: "); pregs(thePic.masks);
+}
+
+/* Small inline helpers */
+
+/* return 0 if this PIC is not 'responsible' for a given irq number
+ * we also 'ignore' the GPP summary bits - these must always remain
+ * enabled.
+ */
+static inline int
+validIrqNo(rtems_irq_number irq)
+{
+ return
+ irq >= BSP_PCI_IRQ_LOWEST_OFFSET
+ && irq <= BSP_PCI_IRQ_MAX_OFFSET
+ && ! (IMH_GPP_SUM & (1<<(irq-32)));
+}
+
+/* return 0 if a given priority is outside the valid range */
+static inline int
+validPri(rtems_irq_prio pri)
+{
+ /* silence compiler warning about limited range of type;
+ * hope it never changes...
+ */
+ return /* pri>=0 && */ pri <=BSP_IRQ_MAX_PRIO;
+}
+
+/* Return position of the most significant bit that is set in 'x' */
+static inline int
+__ilog2(unsigned x)
+{
+ asm volatile("cntlzw %0, %0":"=&r"(x):"0"(x));
+ return 31-x;
+}
+
+/* Convert irq number to cause register index
+ * (array of handles in the PicRec).
+ * ASSUMES: 'irq' within valid range.
+ */
+static inline unsigned
+irqDiv32(unsigned irq)
+{
+ return (irq-BSP_PCI_IRQ_LOWEST_OFFSET)>>5;
+}
+
+/* Convert irq number to cause/mask bit number.
+ * ASSUMES: 'irq' within valid range.
+ */
+
+static inline unsigned
+irqMod32(unsigned irq)
+{
+ return (irq-BSP_PCI_IRQ_LOWEST_OFFSET)&31;
+}
+
+/* NON-ATOMICALLY set/clear bits in a MV64x60 register
+ *
+ * register contents at offset 'off' are ANDed with
+ * complement of the 'clr' mask and ORed with 'set' mask:
+ *
+ * *off = (*off & ~clr) | set
+ *
+ * ASSUMES: executed from IRQ-disabled section
+ */
+static inline void
+gt_bitmod(unsigned off, unsigned set, unsigned clr)
+{
+ st_le32(REGP(thePic.reg_base + off),
+ (ld_le32(REGP(thePic.reg_base+off)) & ~clr) | set);
+}
+
+static inline unsigned
+gt_read(unsigned off)
+{
+ return ld_le32(REGP(thePic.reg_base + off));
+}
+
+static inline void
+gt_write(unsigned off, unsigned val)
+{
+ st_le32(REGP(thePic.reg_base + off), val);
+}
+
+/* Enable interrupt number 'irq' at the PIC.
+ *
+ * Checks for valid arguments but has no way of
+ * communicating violation; prints to console
+ * if illegal arguments are given.
+ *
+ * This routine may be called from ISR level.
+ *
+ * Algorithm: set corresponding bit in masks
+ * for all priorities lower than the
+ * target irq's priority and push
+ * mask for the currently executing
+ * priority out to the PIC.
+ */
+
+void
+BSP_enable_irq_at_pic(rtems_irq_number irq)
+{
+unsigned i,j;
+unsigned long flags;
+volatile uint32_t *p;
+uint32_t v,m;
+
+ if ( !validIrqNo(irq) ) {
+/* API change - must silently ignore...
+ printk("BSP_enable_irq_at_pic: Invalid argument (irq #%i)\n",irq);
+ */
+ return;
+ }
+
+#if (IRQ_DEBUG) & IRQ_DEBUG_BASIC
+ printk("IRQ: Enable #%i;",irq);
+#endif
+
+ if ( (i=irqDiv32(irq)) > NUM_INTR_REGS ) {
+ /* This is probably a more serious error; don't ignore silently */
+ printk("BSP_enable_irq_at_pic: illegal argument\n");
+ return;
+ }
+ /* compute register pointer and bit mask */
+ p = thePic.masks[i];
+ m = 1<<irqMod32(irq);
+
+ rtems_interrupt_disable(flags);
+ {
+ /* access table from protected section to be thread-safe */
+ rtems_irq_prio pri = theConfig.irqPrioTbl[irq];
+ for ( j=0; j<pri; j++ ) {
+ thePic.mcache[j][i] |= m;
+ }
+ st_le32(p, (v=thePic.mcache[thePic.current_priority][i]));
+ /* linux driver reads back GPP mask; maybe it's wise to do the same */
+ (void)ld_le32(thePic.masks[GPP_IDX]);
+ }
+ SYNC();
+ rtems_interrupt_enable(flags);
+
+#if (IRQ_DEBUG) & IRQ_DEBUG_BASIC
+ printk(" Mask[%i]: 0x%08x -> 0x%08x\n",i,v,ld_le32(p));
+
+#endif
+}
+
+/* Disable interrupt number 'irq' at the PIC.
+ *
+ * Checks for valid arguments but has no way of
+ * communicating violation; prints to console
+ * if illegal arguments are given.
+ *
+ * This routine may be called from ISR level.
+ *
+ * Algorithm: clear corresponding bit in masks
+ * for all priorities and push the
+ * mask for the currently executing
+ * priority out to the PIC.
+ */
+
+int
+BSP_disable_irq_at_pic(rtems_irq_number irq)
+{
+unsigned i,j;
+unsigned long flags;
+volatile uint32_t *p;
+uint32_t v,m;
+int rval;
+
+ if ( !validIrqNo(irq) ) {
+/* API change - must silently ignore...
+ printk("BSP_disable_irq_at_pic: Invalid argument (irq #%i)\n",irq);
+ */
+ return -1;
+ }
+
+#if (IRQ_DEBUG) & IRQ_DEBUG_BASIC
+ printk("IRQ: Disable #%i;",irq);
+#endif
+
+ if ( (i=irqDiv32(irq)) > NUM_INTR_REGS ) {
+ /* This is probably a more serious error; don't ignore silently */
+ printk("BSP_enable_irq_at_pic: illegal argument\n");
+ return -1;
+ }
+
+ /* compute register pointer and bit mask */
+ p = thePic.masks[i];
+ m = (1<<irqMod32(irq));
+
+ rtems_interrupt_disable(flags);
+ {
+ rval = thePic.mcache[thePic.current_priority][i] & m;
+ for (j=0; j<=BSP_IRQ_MAX_PRIO; j++)
+ thePic.mcache[j][i] &= ~m;
+ st_le32(p, (v=thePic.mcache[thePic.current_priority][i]));
+ /* linux driver reads back GPP mask; maybe it's wise to do the same */
+ (void)ld_le32(thePic.masks[GPP_IDX]);
+ }
+ SYNC();
+ rtems_interrupt_enable(flags);
+
+#if (IRQ_DEBUG) & IRQ_DEBUG_BASIC
+ printk(" Mask[%i]: 0x%08x -> 0x%08x\n",i,v,ld_le32(p));
+#endif
+
+ return rval ? 1 : 0;
+}
+
+int
+BSP_irq_is_enabled_at_pic(rtems_irq_number irq)
+{
+unsigned i;
+ if ( !validIrqNo(irq) ) {
+ printk("BSP_irq_is_enabled_at_pic: Invalid argument (irq #%i)\n",irq);
+ return -1;
+ }
+
+ if ( (i=irqDiv32(irq)) > NUM_INTR_REGS ) {
+ printk("BSP_enable_irq_at_pic: illegal argument\n");
+ return -1;
+ }
+ return ld_le32(thePic.masks[i]) & (1<<irqMod32(irq)) ? 1 : 0;
+}
+
+
+/* Change priority of interrupt number 'irq' to 'pri'
+ *
+ * RETURNS: 0 on success, nonzero on failure (illegal args)
+ *
+ * NOTE: This routine must not be called from ISR level.
+ *
+ * Algorithm: Set bit corresponding to 'irq' in the masks for
+ * all priorities < pri and clear in all masks
+ * for priorities >=pri
+ */
+int
+BSP_irq_set_priority(rtems_irq_number irq, rtems_irq_prio pri)
+{
+unsigned long flags;
+volatile uint32_t *p;
+uint32_t v,m;
+unsigned i,j;
+
+ if ( thePic.current_priority > 0 ) {
+ printk("BSP_irq_set_priority: must not be called from ISR level\n");
+ return -1;
+ }
+
+ if ( !validPri(pri) ) {
+ printk("BSP_irq_set_priority: invalid argument (pri #%i)\n",pri);
+ return -1;
+ }
+
+ if ( BSP_DECREMENTER != irq ) {
+ if ( !validIrqNo(irq) ) {
+ printk("BSP_irq_set_priority: invalid argument (irq #%i)\n",irq);
+ return -1;
+ }
+
+ if ( (i=irqDiv32(irq)) > NUM_INTR_REGS ) {
+ printk("BSP_irq_set_priority: illegal argument (irq #%i not PCI?)\n", irq);
+ return -1;
+ }
+ }
+
+#if (IRQ_DEBUG) & IRQ_DEBUG_BASIC
+ printk("IRQ: Set Priority #%i -> %i;",irq,pri);
+#endif
+
+ if ( BSP_DECREMENTER == irq ) {
+ theConfig.irqPrioTbl[irq] = pri;
+ return 0;
+ }
+
+ /* compute register pointer and bit mask */
+ p = thePic.masks[i];
+ m = 1<<irqMod32(irq);
+
+ rtems_interrupt_disable(flags);
+ {
+ for (j=0; j<=BSP_IRQ_MAX_PRIO; j++) {
+ if ( j<pri )
+ thePic.mcache[j][i] |= m;
+ else
+ thePic.mcache[j][i] &= ~m;
+ }
+ theConfig.irqPrioTbl[irq] = pri;
+ st_le32(p, (v=thePic.mcache[thePic.current_priority][i]));
+ /* linux driver reads back GPP mask; maybe it's wise to do the same */
+ (void)ld_le32(thePic.masks[GPP_IDX]);
+ }
+ SYNC();
+ rtems_interrupt_enable(flags);
+
+#if (IRQ_DEBUG) & IRQ_DEBUG_BASIC
+ printk(" Mask[%i]: 0x%08x -> 0x%08x\n",i,v,ld_le32(p));
+#endif
+
+ return 0;
+}
+
+/* Initialize the PIC; routine needed by BSP framework
+ *
+ * RETURNS: NONZERO on SUCCESS, 0 on error!
+ */
+int
+BSP_setup_the_pic(rtems_irq_global_settings* config)
+{
+int i;
+ /*
+ * Store copy of configuration
+ */
+ theConfig = *config;
+
+ /* check config */
+ if ( theConfig.irqNb <= BSP_PCI_IRQ_MAX_OFFSET ) {
+ printk("BSP_setup_the_pic: FATAL ERROR: configured IRQ table too small???\n");
+ return 0;
+ }
+
+ for ( i=0; i<theConfig.irqNb; i++ ) {
+ if ( !validPri(theConfig.irqPrioTbl[i]) ) {
+ printk("BSP_setup_the_pic: invalid priority (%i) for irg #%i; setting to 1\n", theConfig.irqPrioTbl[i], i);
+ theConfig.irqPrioTbl[i]=1;
+ }
+ }
+
+ /* TODO: Detect; Switch wired-out bit; */
+ thePic.reg_base = BSP_MV64x60_BASE;
+
+ thePic.current_priority = 0;
+
+#if (IRQ_DEBUG) & MVME6100_IRQ_DEBUG
+#endif
+
+ switch ( BSP_getDiscoveryVersion(/* assert */ 1) ) {
+ case MV_64360:
+ thePic.causes[MAIN_LO_IDX] = REGP(thePic.reg_base + ICR_360_MIC_LO);
+ thePic.causes[MAIN_HI_IDX] = REGP(thePic.reg_base + ICR_360_MIC_HI);
+ thePic.masks[MAIN_LO_IDX] = REGP(thePic.reg_base + ICR_360_C0IM_LO);
+ thePic.masks[MAIN_HI_IDX] = REGP(thePic.reg_base + ICR_360_C0IM_HI);
+ break;
+
+ case GT_64260_A:
+ case GT_64260_B:
+ thePic.causes[MAIN_LO_IDX] = REGP(thePic.reg_base + ICR_260_MIC_LO);
+ thePic.causes[MAIN_HI_IDX] = REGP(thePic.reg_base + ICR_260_MIC_HI);
+ thePic.masks[MAIN_LO_IDX] = REGP(thePic.reg_base + ICR_260_CIM_LO);
+ thePic.masks[MAIN_HI_IDX] = REGP(thePic.reg_base + ICR_260_CIM_HI);
+ break;
+
+ default:
+ BSP_panic("Unable to initialize interrupt controller; unknown chip");
+ break;
+ }
+
+ thePic.causes[GPP_IDX] = REGP(thePic.reg_base + GT_GPP_Interrupt_Cause);
+ thePic.masks[GPP_IDX] = REGP(thePic.reg_base + GT_GPP_Interrupt_Mask);
+
+ /* Initialize mask cache */
+ for ( i=0; i<=BSP_IRQ_MAX_PRIO; i++ ) {
+ thePic.mcache[i][MAIN_LO_IDX] = 0;
+ /* Always enable the summary bits. Otherwise, GPP interrupts dont
+ * make it 'through' to the GPP cause
+ */
+ thePic.mcache[i][MAIN_HI_IDX] = IMH_GPP_SUM;
+ thePic.mcache[i][GPP_IDX] = 0;
+ }
+
+ /* mask and clear everything */
+ for ( i=0; i<NUM_INTR_REGS; i++ ) {
+ st_le32(thePic.causes[i], 0);
+ st_le32(thePic.masks[i], 0);
+ }
+
+ /* make sure GPP Irqs are level sensitive */
+ gt_bitmod(
+ GT_CommUnitArb_Ctrl, /* reg */
+ GT_CommUnitArb_Ctrl_GPP_Ints_Level_Sensitive, /* set */
+ 0); /* clr */
+
+ /* enable summaries */
+ st_le32(thePic.masks[MAIN_LO_IDX], thePic.mcache[thePic.current_priority][MAIN_LO_IDX]);
+ st_le32(thePic.masks[MAIN_HI_IDX], thePic.mcache[thePic.current_priority][MAIN_HI_IDX]);
+ st_le32(thePic.masks[GPP_IDX ], thePic.mcache[thePic.current_priority][GPP_IDX ]);
+
+ /* believe the interrupts are all level sensitive (which is good); we leave all the
+ * inputs configured they way the are by MotLoad...
+ */
+
+ /* Finally, enable all interrupts for which the configuration table has already
+ * a handler installed.
+ */
+ for ( i=BSP_PCI_IRQ_LOWEST_OFFSET; i<=BSP_PCI_IRQ_MAX_OFFSET; i++ ) {
+ if ( theConfig.irqHdlTbl[i].hdl != theConfig.defaultEntry.hdl ) {
+ BSP_enable_irq_at_pic(i);
+ }
+ }
+
+ return 1;
+}
+
+int discovery_pic_max_loops = 0;
+
+
+/* Change the priority level we're executing at and mask all interrupts of
+ * the same and lower priorities
+ *
+ * RETURNS old priority;
+ */
+
+static inline rtems_irq_prio
+change_executing_prio_level(rtems_irq_prio pri)
+{
+register rtems_irq_prio rval = thePic.current_priority;
+ thePic.current_priority = pri;
+ st_le32(thePic.masks[MAIN_LO_IDX], thePic.mcache[pri][MAIN_LO_IDX]);
+ st_le32(thePic.masks[MAIN_HI_IDX], thePic.mcache[pri][MAIN_HI_IDX]);
+ st_le32(thePic.masks[GPP_IDX ], thePic.mcache[pri][GPP_IDX ]);
+ /* this DOES seem to be necessary */
+ (void)ld_le32(thePic.masks[GPP_IDX]);
+ return rval;
+}
+
+/* Scan the three cause register and find the pending interrupt with
+ * the highest priority.
+ *
+ * Two facts make this quite efficient
+ * a) the PPC has an opcode for finding the number of leading zero-bits
+ * in a register (__ilog2()).
+ * b) as we proceed we mask all sources of equal or lower priorites; they won't be
+ * seen while scanning:
+ *
+ * maxpri = 0;
+ * bits = in_le32(cause);
+ * while ( bits &= mask[maxpri] ) {
+ * irq_no = __ilog2(bits);
+ * maxpri = priority[irq_no];
+ * }
+ *
+ * a) __ilog() is 1-2 machine instructions
+ * b) while loop is only executed as many times as interrupts of different
+ * priorities are pending at the same time (and only if lower-priority
+ * ones are found first; otherwise, the iteration terminates quicker).
+ *
+ * ==> highest priority source is found quickly. It takes at most
+ *
+ * BSP_IRQ_MAX_PRIO * ( ~3 reg-only instructions + 2 memory access )
+ * + 2 reg-only instructions + 1 I/O + 1 memory access.
+ *
+ *
+ */
+
+static unsigned mlc, mhc, gpc;
+
+static int decrementerPending = 0;
+#if (IRQ_DEBUG) & IRQ_DEBUG_DISPATCHER
+int decrementerIrqs = 0;
+#endif
+
+static inline unsigned
+find_highest_priority_pending_irq(rtems_irq_prio *ppri)
+{
+register int rval = -1;
+register rtems_irq_prio *pt = theConfig.irqPrioTbl + BSP_PCI_IRQ_LOWEST_OFFSET;
+register rtems_irq_prio pmax = *ppri;
+register unsigned cse,ocse;
+
+#if (IRQ_DEBUG) & IRQ_DEBUG_DISPATCHER
+ discovery_dump_picregs();
+#endif
+
+ if ( decrementerPending ) {
+/* Don't flood
+#if (IRQ_DEBUG) & IRQ_DEBUG_DISPATCHER
+ printk("Decrementer IRQ pending\n");
+#endif
+*/
+ if ( theConfig.irqPrioTbl[BSP_DECREMENTER] > pmax ) {
+ pmax = theConfig.irqPrioTbl[BSP_DECREMENTER];
+ rval = BSP_DECREMENTER;
+ }
+ }
+
+ mlc = cse = ld_le32(thePic.causes[MAIN_LO_IDX]);
+#if (IRQ_DEBUG) & IRQ_DEBUG_DISPATCHER
+ printk("MAIN_LO; cse: 0x%08x, msk 0x%08x\n", cse ,thePic.mcache[pmax][MAIN_LO_IDX]);
+#endif
+ while ( cse &= thePic.mcache[pmax][MAIN_LO_IDX] ) {
+ rval = __ilog2(cse);
+ pmax = pt[rval];
+#if (IRQ_DEBUG) & IRQ_DEBUG_DISPATCHER
+ printk("Max pri IRQ now %i\n",rval);
+#endif
+ }
+ mhc = cse = ocse = ld_le32(thePic.causes[MAIN_HI_IDX]);
+#if (IRQ_DEBUG) & IRQ_DEBUG_DISPATCHER
+ printk("MAIN_HI; cse: 0x%08x, msk 0x%08x\n", cse, thePic.mcache[pmax][MAIN_HI_IDX]);
+#endif
+ /* don't look at the GPP summary; only check for 'real' MAIN_HI sources */
+ cse &= ~IMH_GPP_SUM;
+ while ( cse &= thePic.mcache[pmax][MAIN_HI_IDX] ) {
+ rval = __ilog2(cse) + 32;
+ pmax = pt[rval];
+#if (IRQ_DEBUG) & IRQ_DEBUG_DISPATCHER
+ printk("Max pri IRQ now %i\n",rval);
+#endif
+ }
+ gpc = cse = ld_le32(thePic.causes[GPP_IDX ]);
+ /* if there were GPP ints, scan the GPP cause now */
+ if ( ocse & IMH_GPP_SUM ) {
+#if (IRQ_DEBUG) & IRQ_DEBUG_DISPATCHER
+ printk("GPP; cse: 0x%08x, msk 0x%08x\n", cse, thePic.mcache[pmax][GPP_IDX ]);
+#endif
+ cse &= thePic.mcache[pmax][GPP_IDX ];
+ ocse = cse;
+ while ( cse ) {
+ rval = __ilog2(cse) + 64;
+ pmax = pt[rval];
+ cse &= thePic.mcache[pmax][GPP_IDX ];
+#if (IRQ_DEBUG) & IRQ_DEBUG_DISPATCHER
+ printk("Max pri IRQ now %i\n",rval);
+#endif
+ }
+#ifndef FASTER
+ /* this doesn't seem to be necessary -- however, the linux people do it... */
+ out_le32(thePic.causes[GPP_IDX], ~ocse);
+#endif
+ }
+#ifndef FASTER
+ /* this doesn't seem to be necessary -- however, the linux people do it... */
+ (void)in_le32(thePic.causes[GPP_IDX]);
+#endif
+
+ *ppri = pmax;
+
+ if ( BSP_DECREMENTER == rval ) {
+#if (IRQ_DEBUG) & IRQ_DEBUG_DISPATCHER
+ decrementerIrqs++;
+#endif
+ decrementerPending = 0;
+ }
+
+ return rval;
+}
+
+#if 0 /* TODO: should this be cleaned up ? */
+#define _IRQ_DEBUG IRQ_DEBUG_DISPATCHER
+static inline unsigned
+ffind_highest_priority_pending_irq(rtems_irq_prio *ppri)
+{
+register int rval = -1;
+register rtems_irq_prio *pt = theConfig.irqPrioTbl + BSP_PCI_IRQ_LOWEST_OFFSET;
+register rtems_irq_prio pmax = *ppri;
+register unsigned cse,ocse;
+
+#if (_IRQ_DEBUG) & IRQ_DEBUG_DISPATCHER
+ discovery_dump_picregs();
+#endif
+
+ cse = in_le32(thePic.causes[MAIN_LO_IDX]);
+#if (_IRQ_DEBUG) & IRQ_DEBUG_DISPATCHER
+ printk("MAIN_LO; cse: 0x%08x, msk 0x%08x\n", cse ,thePic.mcache[pmax][MAIN_LO_IDX]);
+#endif
+ while ( cse &= thePic.mcache[pmax][MAIN_LO_IDX] ) {
+ rval = __ilog2(cse);
+ pmax = pt[rval];
+#if (_IRQ_DEBUG) & IRQ_DEBUG_DISPATCHER
+ printk("Max pri IRQ now %i\n",rval);
+#endif
+ }
+ cse = ocse = in_le32(thePic.causes[MAIN_HI_IDX]);
+#if (_IRQ_DEBUG) & IRQ_DEBUG_DISPATCHER
+ printk("MAIN_HI; cse: 0x%08x, msk 0x%08x\n", cse, thePic.mcache[pmax][MAIN_HI_IDX]);
+#endif
+ /* don't look at the GPP summary; only check for 'real' MAIN_HI sources */
+ cse &= ~IMH_GPP_SUM;
+ while ( cse &= thePic.mcache[pmax][MAIN_HI_IDX] ) {
+ rval = __ilog2(cse) + 32;
+ pmax = pt[rval];
+#if (_IRQ_DEBUG) & IRQ_DEBUG_DISPATCHER
+ printk("Max pri IRQ now %i\n",rval);
+#endif
+ }
+ /* if there were GPP ints, scan the GPP cause now */
+ if ( ocse & IMH_GPP_SUM ) {
+ cse = in_le32(thePic.causes[GPP_IDX ]);
+#if (_IRQ_DEBUG) & IRQ_DEBUG_DISPATCHER
+ printk("GPP; cse: 0x%08x, msk 0x%08x\n", cse, thePic.mcache[pmax][GPP_IDX ]);
+#endif
+ cse &= thePic.mcache[pmax][GPP_IDX ];
+ ocse = cse;
+ while ( cse ) {
+ rval = __ilog2(cse) + 64;
+ pmax = pt[rval];
+ cse &= thePic.mcache[pmax][GPP_IDX ];
+#if (_IRQ_DEBUG) & IRQ_DEBUG_DISPATCHER
+ printk("Max pri IRQ now %i\n",rval);
+#endif
+ }
+ /* this doesn't seem to be necessary -- however, the linux people do it... */
+ out_le32(thePic.causes[GPP_IDX], ~ocse);
+ }
+ /* this doesn't seem to be necessary -- however, the linux people do it... */
+ (void)in_le32(thePic.causes[GPP_IDX]);
+
+ *ppri = pmax;
+ return rval;
+}
+#endif
+
+
+/* Here's our dispatcher; the BSP framework uses the same one for EE and decrementer
+ * exceptions...
+ */
+int C_dispatch_irq_handler (BSP_Exception_frame *frame, unsigned int excNum)
+{
+register int irq;
+int loop, last_irq;
+rtems_irq_prio pri;
+#if (IRQ_DEBUG) & IRQ_DEBUG_MAXLAT
+unsigned long diff;
+#endif
+
+#if (IRQ_DEBUG) & IRQ_DEBUG_MAXLAT
+ diff = mftb();
+#endif
+
+ if (excNum == ASM_DEC_VECTOR) {
+ decrementerPending = 1;
+ }
+
+ /* Tradeoff: EITHER we loop as long as interrupts are pending
+ * incurring the overhead of one extra run of the 'find_pending_irq' routine.
+ * OR we do rely on the handler just being invoked again if multiple
+ * interrupts are pending.
+ *
+ * The first solution gives better worst-case behavior
+ * the second slightly better average performance.
+ * --> we go for the first solution. This also enables us to catch
+ * runaway interrupts, i.e., bad drivers that don't clear interrupts
+ * at the device. Can be very handy during driver development...
+ */
+ for ( loop=0, last_irq=-1, pri = thePic.current_priority;
+ (irq=find_highest_priority_pending_irq(&pri)) >=0;
+ loop++, last_irq = irq ) {
+
+ /* raise priority level and remember current one */
+ pri = change_executing_prio_level(pri);
+
+ SYNC();
+
+#if (IRQ_DEBUG) & IRQ_DEBUG_MAXLAT
+ if ( 0 == loop ) {
+ diff = mftb()-diff;
+ if ( diff > discovery_pic_max_dispatching_latency )
+ discovery_pic_max_dispatching_latency = diff;
+ }
+#endif
+
+#if (IRQ_DEBUG) & IRQ_DEBUG_DISPATCHER
+ if ( BSP_DECREMENTER == irq ) {
+ printk("IRQ: dispatching DECREMENTER\n");
+ } else {
+ int idx = irqDiv32(irq);
+ printk("IRQ: dispatching #%i; causes[%i]=0x%08x\n", irq, idx, ld_le32(thePic.causes[idx]));
+ }
+#endif
+
+ bsp_irq_dispatch_list( theConfig.irqHdlTbl, irq, theConfig.defaultEntry.hdl );
+
+ /* restore executing priority level */
+ (void)change_executing_prio_level(pri);
+
+ if ( (loop > MAX_SPIN_LOOPS) && (last_irq == irq) ) {
+ /* try to catch run-away interrupts without disabling a 'legal' one;
+ * this should never happen with the decrementer (and
+ * BSP_disable_irq_at_pic(BSP_DECREMENTER) would fail)
+ */
+ printk("Runaway IRQ #%i; disabling\n", irq);
+ BSP_disable_irq_at_pic(irq);
+ loop = 0;
+ }
+ }
+
+ if (!loop) {
+ if ( decrementerPending && pri >= theConfig.irqPrioTbl[BSP_DECREMENTER] ) {
+ /* we cannot mask the decrementer interrupt so it is possible that it
+ * gets delivered even though it has a lower priority than what we're
+ * currently executing at.
+ * In this case, we ignore the zero loop count and return;
+ * the interrupted instance of C_dispatch_irq_handler() will eventually
+ * lower the executing priority and catch the 'decrementerPending' flag
+ * we just set.
+ */
+ } else {
+ printk("Discovery: Spurious interrupt; causes were gpp: 0x%x, mhc: 0x%x, mlc: 0x%x\n", gpc, mhc, mlc);
+ printk("Current priority level %i, decrementerPending %i\n", pri, decrementerPending);
+ {
+ rtems_irq_prio p=pri;
+ printk("PIC register dump:\n");
+ discovery_dump_picregs();
+ printk("Current Priority: %i, found %i\n",pri,find_highest_priority_pending_irq(&p));
+ discovery_dump_picregs();
+ for (p=0; p<=BSP_IRQ_MAX_PRIO; p++) {
+ printk("M[%i] :",p);pmsks(thePic.mcache[p]);
+ }
+ }
+ }
+ }
+ else if (loop>discovery_pic_max_loops)
+ discovery_pic_max_loops = loop;
+
+ return 0;
+}
+
+
+#if (IRQ_DEBUG) & MVME6100_IRQ_DEBUG
+void
+discovery_pic_install_debug_irq(void)
+{
+ switch ( BSP_getBoardType() ) {
+ case MVME6100: gpp_out_bit = GPP_WIRED_OUT_BIT_6100; break;
+ case MVME5500: gpp_out_bit = GPP_WIRED_OUT_BIT_5500; break;
+ default:
+ gpp_out_bit = 0; break;
+ break;
+ }
+ if ( gpp_out_bit ) {
+ unsigned mppoff;
+ switch (gpp_out_bit / 8) {
+ default: /* silence warning; this is never reached */
+ case 0: mppoff = GT_MPP_Control0; break;
+ case 1: mppoff = GT_MPP_Control1; break;
+ case 2: mppoff = GT_MPP_Control2; break;
+ case 3: mppoff = GT_MPP_Control3; break;
+ }
+
+ /* switch GPP pin allocated to watchdog (value 4) to
+ * GPP I/O (value 0 ??; have no doc, found out by experimenting)
+ */
+ gt_bitmod(mppoff, 0, (0xf<<(4*(gpp_out_bit % 8))));
+
+ /* make it an output */
+ gt_bitmod(GT_GPP_IO_Control, (1<<gpp_out_bit), 0);
+
+ /* don't invert levels */
+ gt_bitmod(GT_GPP_Level_Control, 0, (1<<GPP_WIRED_IN_BIT) | (1<<gpp_out_bit));
+
+ /* clear output */
+ gt_bitmod(GT_GPP_Value, 0, 1<<gpp_out_bit);
+
+ printk("GPP levelctl now 0x%08x\n", gt_read(GT_GPP_Level_Control));
+ printk("GPP value now 0x%08x\n", gt_read(GT_GPP_Value));
+ printk("MPP ctl 0 now 0x%08x\n", gt_read(GT_MPP_Control0));
+ printk("MPP ctl 1 now 0x%08x\n", gt_read(GT_MPP_Control1));
+ printk("MPP ctl 2 now 0x%08x\n", gt_read(GT_MPP_Control2));
+ printk("MPP ctl 3 now 0x%08x\n", gt_read(GT_MPP_Control3));
+
+ }
+}
+
+/* Control the state of the external 'wire' that connects the
+ * GPP_WIRED_OUT --> GPP_WIRED_IN pins
+ */
+void
+discovery_pic_set_debug_irq(int on)
+{
+unsigned long flags, clr;
+ if ( !gpp_out_bit ) {
+ printk("discovery_pic_set_debug_irq(): unknown wire output\n");
+ return;
+ }
+ if (on) {
+ on = 1<<gpp_out_bit;
+ clr = 0;
+ } else {
+ clr = 1<<gpp_out_bit;
+ on = 0;
+ }
+ rtems_interrupt_disable(flags);
+ gt_bitmod(GT_GPP_Value, on, clr);
+ rtems_interrupt_enable(flags);
+}
+#endif
+
+#if 0
+/* Here's some code for testing */
+#endif
diff --git a/c/src/lib/libbsp/powerpc/beatnik/irq/irq.h b/c/src/lib/libbsp/powerpc/beatnik/irq/irq.h
new file mode 100644
index 0000000000..895d66c7da
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/beatnik/irq/irq.h
@@ -0,0 +1,133 @@
+/* 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.
+ *
+ * Modified by T. Straumann for the beatnik BSP, 2005-2007
+ * Some information may be based on mvme5500/irq/irq.h by K. Feng.
+ */
+
+#ifndef LIBBSP_POWERPC_MOT_PPC_NEW_IRQ_IRQ_H
+#define LIBBSP_POWERPC_MOT_PPC_NEW_IRQ_IRQ_H
+
+#define BSP_SHARED_HANDLER_SUPPORT 1
+#include <rtems/irq.h>
+#include <bsp/vectors.h>
+
+/* This BSP also passes a pointer to the interrupt frame to the handler.
+ * The PPC ABI guarantees that this will not mess up handlers written
+ * without knowledge of this feature.
+ */
+
+typedef void (*BSP_rtems_irq_hdl)(rtems_irq_hdl_param,BSP_Exception_frame*);
+
+
+/* legal priorities are 0 <= priority <= MAX_PRIO; 0 effectively disables the interrupt */
+#define BSP_IRQ_MAX_PRIO 4
+#define BSP_IRQ_MIN_PRIO 1
+
+/* Note that priorites are only honoured for 'PCI' interrupt numbers.
+ * The discovery pic has no support for hardware priorites; hence they
+ * are handled in software
+ */
+#define BSP_IRQ_DEFAULT_PRIORITY 2
+
+
+#define BSP_PCI_IRQ_LOWEST_OFFSET 0 /* IMPLEMENTATION RELIES ON discovery pic INTERRUPTS HAVING NUMBERS 0..95 */
+#define BSP_IRQ_DEV 1 /* device interface interrupt */
+#define BSP_IRQ_DMA 2 /* DMA addres error interrupt (260) */
+#define BSP_IRQ_CPU 3 /* CPU interface interrupt */
+#define BSP_IRQ_IDMA0_1 4 /* IDMA ch. 0..1 complete interrupt (260) */
+#define BSP_IRQ_IDMA2_3 5 /* IDMA ch. 2..3 complete interrupt (260) */
+#define BSP_IRQ_IDMA4_5 6 /* IDMA ch. 4..5 complete interrupt (260) */
+#define BSP_IRQ_IDMA6_7 7 /* IDMA ch. 6..7 complete interrupt (260) */
+#define BSP_IRQ_TIME0_1 8 /* Timer 0..1 interrupt; Timer 0 on 64360 */
+#define BSP_IRQ_TIME2_3 9 /* Timer 2..3 interrupt; Timer 1 on 64360 */
+#define BSP_IRQ_TIME4_5 10 /* Timer 4..5 interrupt; Timer 2 on 64360 */
+#define BSP_IRQ_TIME6_7 11 /* Timer 6..7 interrupt; Timer 3 on 64360 */
+#define BSP_IRQ_PCI0_0 12 /* PCI 0 interrupt 0 summary (PCI 0 interrupt summary on 64360) */
+#define BSP_IRQ_PCI0_1 13 /* PCI 0 interrupt 1 summary (SRAM PAR ERROR on 64360) */
+#define BSP_IRQ_PCI0_2 14 /* PCI 0 interrupt 2 summary */
+#define BSP_IRQ_PCI0_3 15 /* PCI 0 interrupt 3 summary */
+#define BSP_IRQ_PCI1_0 16 /* PCI 1 interrupt 0 summary (PCI 1 interrupt summary on 64360) */
+#define BSP_IRQ_ECC 17 /* ECC error interrupt */
+#define BSP_IRQ_PCI1_1 18 /* PCI 1 interrupt 1 summary */
+#define BSP_IRQ_PCI1_2 19 /* PCI 1 interrupt 2 summary */
+#define BSP_IRQ_PCI1_3 20 /* PCI 1 interrupt 3 summary */
+#define BSP_IRQ_PCI0OUT_LO 21 /* PCI 0 outbound interrupt summary */
+#define BSP_IRQ_PCI0OUT_HI 22 /* PCI 0 outbound interrupt summary */
+#define BSP_IRQ_PCI1OUT_LO 23 /* PCI 1 outbound interrupt summary */
+#define BSP_IRQ_PCI1OUT_HI 24 /* PCI 1 outbound interrupt summary */
+#define BSP_IRQ_PCI0IN_LO 26 /* PCI 0 inbound interrupt summary */
+#define BSP_IRQ_PCI0IN_HI 27 /* PCI 0 inbound interrupt summary */
+#define BSP_IRQ_PCI1IN_LO 28 /* PCI 1 inbound interrupt summary */
+#define BSP_IRQ_PCI1IN_HI 29 /* PCI 1 inbound interrupt summary */
+#define BSP_IRQ_ETH0 (32+0) /* Ethernet controller 0 interrupt */
+#define BSP_IRQ_ETH1 (32+1) /* Ethernet controller 1 interrupt */
+#define BSP_IRQ_ETH2 (32+2) /* Ethernet controller 2 interrupt */
+#define BSP_IRQ_SDMA (32+4) /* SDMA interrupt */
+#define BSP_IRQ_I2C (32+5) /* I2C interrupt */
+#define BSP_IRQ_BRG (32+7) /* Baud Rate Generator interrupt */
+#define BSP_IRQ_MPSC0 (32+8) /* MPSC 0 interrupt */
+#define BSP_IRQ_MPSC1 (32+10) /* MPSC 1 interrupt */
+#define BSP_IRQ_COMM (32+11) /* Comm unit interrupt */
+#define BSP_IRQ_GPP7_0 (32+24) /* GPP[7..0] interrupt summary */
+#define BSP_IRQ_GPP15_8 (32+25) /* GPP[15..8] interrupt summary */
+#define BSP_IRQ_GPP23_16 (32+26) /* GPP[23..16] interrupt summary */
+#define BSP_IRQ_GPP31_24 (32+27) /* GPP[31..24] interrupt summary */
+#define BSP_IRQ_GPP_0 64
+
+#define BSP_PCI_IRQ_NUMBER (64+32)
+#define BSP_PCI_IRQ_MAX_OFFSET (BSP_PCI_IRQ_LOWEST_OFFSET + BSP_PCI_IRQ_NUMBER - 1)
+
+#define BSP_PROCESSOR_IRQ_NUMBER 1
+#define BSP_PROCESSOR_IRQ_LOWEST_OFFSET (BSP_PCI_IRQ_MAX_OFFSET+1)
+#define BSP_PROCESSOR_IRQ_MAX_OFFSET (BSP_PROCESSOR_IRQ_LOWEST_OFFSET + BSP_PROCESSOR_IRQ_NUMBER - 1)
+
+/* summary */
+
+#define BSP_IRQ_NUMBER (BSP_PCI_IRQ_NUMBER + BSP_PROCESSOR_IRQ_NUMBER)
+#define BSP_LOWEST_OFFSET 0
+#define BSP_MAX_OFFSET (BSP_LOWEST_OFFSET + BSP_IRQ_NUMBER - 1)
+#define BSP_DECREMENTER BSP_PROCESSOR_IRQ_LOWEST_OFFSET
+
+#define BSP_UART_COM1_IRQ BSP_IRQ_GPP_0
+#define BSP_UART_COM2_IRQ BSP_IRQ_GPP_0
+
+#ifndef ASM
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#include <bsp/irq_supp.h>
+
+int BSP_irq_is_enabled_at_pic(rtems_irq_number irq);
+
+/* set priority of an interrupt; must not be called from ISR level */
+int BSP_irq_set_priority(rtems_irq_number irq, rtems_irq_prio pri);
+
+/* Not for public use */
+void BSP_rtems_irq_mng_init(unsigned cpuId);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif
+
+#endif
diff --git a/c/src/lib/libbsp/powerpc/beatnik/irq/irq_init.c b/c/src/lib/libbsp/powerpc/beatnik/irq/irq_init.c
new file mode 100644
index 0000000000..29499597f8
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/beatnik/irq/irq_init.c
@@ -0,0 +1,112 @@
+/* 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.
+ *
+ * Modified by T. Straumann for the 'beatnik' 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.
+ *
+ * $Id$
+ */
+
+#include <rtems.h>
+#include <bsp.h>
+#include <bsp/irq.h>
+#include <bsp/vectors.h>
+#include <rtems/bspIo.h>
+
+#if 0
+#include <libcpu/io.h>
+#include <libcpu/spr.h>
+#include <bsp/pci.h>
+#include <bsp/residual.h>
+#include <bsp/openpic.h>
+#include <bsp/irq.h>
+#include <bsp.h>
+#include <bsp/motorola.h>
+#endif
+
+/*
+#define SHOW_ISA_PCI_BRIDGE_SETTINGS
+*/
+
+extern unsigned int external_exception_vector_prolog_code_size[];
+extern void external_exception_vector_prolog_code(void);
+extern unsigned int decrementer_exception_vector_prolog_code_size[];
+extern void decrementer_exception_vector_prolog_code(void);
+
+/*
+ * default handler
+ */
+static void nop_func(void *arg){}
+
+static rtems_irq_connect_data rtemsIrq[BSP_IRQ_NUMBER];
+static rtems_irq_global_settings initial_config;
+static rtems_irq_prio rtemsPrioTbl[BSP_IRQ_NUMBER];
+static rtems_irq_connect_data defaultIrq = {
+ name: 0,
+ hdl: nop_func,
+ handle: 0,
+ on: 0,
+ off: 0,
+ isOn: 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)
+{
+int i;
+
+ /*
+ * First initialize the Interrupt management hardware
+ */
+
+ /*
+ * Initialize Rtems management interrupt table
+ */
+
+ /*
+ * re-init the rtemsIrq table
+ */
+ for (i = BSP_LOWEST_OFFSET; i <= BSP_MAX_OFFSET; i++) {
+ rtemsIrq[i] = defaultIrq;
+ rtemsIrq[i].name = i;
+ rtemsPrioTbl[i] = BSP_IRQ_DEFAULT_PRIORITY;
+ }
+
+ /*
+ * 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 = rtemsPrioTbl;
+
+ 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");
+ }
+
+#ifdef TRACE_IRQ_INIT
+ printk("RTEMS IRQ management is now operationnal\n");
+#endif
+}
+
diff --git a/c/src/lib/libbsp/powerpc/beatnik/irq/irq_test_app.c b/c/src/lib/libbsp/powerpc/beatnik/irq/irq_test_app.c
new file mode 100644
index 0000000000..2a2bfdfb8a
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/beatnik/irq/irq_test_app.c
@@ -0,0 +1,167 @@
+/* Init
+ *
+ * This routine is the initialization task for this test program.
+ * It is called from init_exec and has the responsibility for creating
+ * and starting the tasks that make up the test. If the time of day
+ * clock is required for the test, it should also be set to a known
+ * value by this function.
+ *
+ * Input parameters: NONE
+ *
+ * Output parameters: NONE
+ *
+ * COPYRIGHT (c) 1989-1999.
+ * 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.
+ *
+ * OAR init.c Template modified by T. Straumann who provided
+ * the implementation of this application.
+ *
+ * init.c,v 1.12.4.1 2003/09/04 18:46:30 joel Exp
+ */
+
+#define CONFIGURE_INIT
+
+#include <rtems.h>
+
+/* functions */
+rtems_task Init(
+ rtems_task_argument argument
+);
+
+/* configuration information */
+#include <bsp.h> /* for device driver prototypes */
+#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER
+#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
+#define CONFIGURE_MAXIMUM_TASKS 1
+#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
+#define CONFIGURE_USE_MINIIMFS_AS_BASE_FILESYSTEM
+#include <confdefs.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <bsp/irq.h>
+#include <rtems/bspIo.h>
+
+
+void noop(){}
+int connected() {return 1;}
+
+rtems_irq_connect_data blah = { 0, 0, noop, noop, connected };
+extern void discovery_pic_set_debug_irq();
+
+#define WIRE_IRQ (BSP_IRQ_GPP_0 + 6)
+#define ABRT_IRQ (BSP_IRQ_GPP_0 + 2)
+
+static volatile int testno=0;
+static volatile int wloops =0;
+static volatile int aloops =0;
+
+void wire_hdl()
+{
+ if ( 1 == testno ) {
+ BSP_disable_irq_at_pic(WIRE_IRQ);
+ }
+
+ if ( 2 == testno || 3 == testno ) {
+ discovery_pic_set_debug_irq(0);
+ printk("WIRE -- this message should be printed %s\n", 3==testno ? "FIRST":"SECOND");
+ } else {
+ }
+
+ /* assume the driver checks for less than 1000 loops */
+ if ( ++wloops > 1000) {
+ printk("wire IRQ. FAILURE -- driver couldn't catch runaway ISR. Disabling IRQ source.\n");
+ discovery_pic_set_debug_irq(0);
+ BSP_disable_irq_at_pic(WIRE_IRQ);
+ }
+ /*
+ */
+}
+
+void abrt_hdl()
+{
+ aloops++;
+ if ( 2 == testno || 3 == testno ) {
+ discovery_pic_set_debug_irq(1);
+ printk("ABRT -- this message should be printed %s\n", 2==testno ? "FIRST":"SECOND");
+ } else
+ printk("ABRT IRQ\n");
+
+ if ( 1== testno ) {
+ BSP_enable_irq_at_pic(WIRE_IRQ);
+ }
+ BSP_disable_irq_at_pic(ABRT_IRQ);
+}
+
+
+rtems_task Init(
+ rtems_task_argument ignored
+)
+{
+ blah.name = WIRE_IRQ;
+ blah.hdl = wire_hdl;
+ if (!BSP_install_rtems_irq_handler(&blah)) {
+ fprintf(stderr,"installing handler 1 failed\n");
+ }
+ blah.name = ABRT_IRQ;
+ blah.hdl = abrt_hdl;
+ if (!BSP_install_rtems_irq_handler(&blah)) {
+ fprintf(stderr,"installing handler 2 failed\n");
+ }
+ printf("Hello, testing the ISR dispatcher...\n");
+ printf(" 1. Trying to catch runaway interrupt\n");
+ printf(" If the system freezes, the test failed!\n");
+ fflush(stdout); sleep(1);
+ aloops = wloops = 0;
+ discovery_pic_set_debug_irq(1);
+ printf(" >>> %s\n", wloops<1000 ? "SUCCESS" : "FAILED");
+ discovery_pic_set_debug_irq(0);
+
+ testno++;
+ printf(" 2. Testing enabling / disabling interrupt from ISR\n");
+ printf(" Hit the ABORT key for this test\n");
+ fflush(stdout); sleep(1);
+ aloops = wloops = 0;
+ BSP_disable_irq_at_pic(WIRE_IRQ);
+ BSP_irq_set_priority(ABRT_IRQ,1);
+ BSP_enable_irq_at_pic(ABRT_IRQ);
+ discovery_pic_set_debug_irq(1);
+ while (!aloops)
+ ;
+ discovery_pic_set_debug_irq(0);
+ sleep(2);
+ printf(" >>> disabling ABRT IRQ from isr %s\n", 1==aloops ? "SUCCESS":"FAILURE");
+ printf(" flashing WIRE IRQ from isr %s\n", 1==wloops ? "SUCCESS":"FAILURE");
+
+
+ testno++;
+ printf(" 3. Testing interrupt priorities\n");
+ BSP_irq_set_priority(ABRT_IRQ,2);
+ BSP_irq_set_priority(WIRE_IRQ,2);
+ BSP_enable_irq_at_pic(ABRT_IRQ);
+ BSP_enable_irq_at_pic(WIRE_IRQ);
+ printf(" Hit the ABORT key for this test\n");
+ fflush(stdout); sleep(1);
+ aloops = wloops = 0;
+ while (!aloops)
+ ;
+ sleep(2);
+ testno++;
+ printf(" Now we are raising the priority of the wire interrupt\n");
+ BSP_irq_set_priority(WIRE_IRQ,3);
+ BSP_enable_irq_at_pic(ABRT_IRQ);
+ printf(" Hit the ABORT key for this test\n");
+ fflush(stdout); sleep(1);
+ aloops = wloops = 0;
+ while (!aloops)
+ ;
+
+ sleep(2);
+ printf( "That's it; we're done...\n" );
+ exit( 0 );
+}
diff --git a/c/src/lib/libbsp/powerpc/beatnik/make/custom/beatnik.cfg b/c/src/lib/libbsp/powerpc/beatnik/make/custom/beatnik.cfg
new file mode 100644
index 0000000000..2729aefc5d
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/beatnik/make/custom/beatnik.cfg
@@ -0,0 +1,37 @@
+#
+# Config file for the PowerPC 745x based mvmexxxx
+#
+#
+
+include $(RTEMS_ROOT)/make/custom/default.cfg
+
+RTEMS_CPU=powerpc
+RTEMS_CPU_MODEL=mpc7455
+RTEMS_PPC_EXCEPTION_PROCESSING_MODEL=new
+
+# This is the actual bsp directory used during the build process.
+RTEMS_BSP_FAMILY=beatnik
+
+# This contains the compiler options necessary to select the CPU model
+# and (hopefully) optimize for it.
+#
+CPU_CFLAGS = -mcpu=7400 -D__ppc_generic
+#T. Straumann; disable sdata=eabi for now until CEXP supports it -meabi -msdata=eabi
+
+# optimize flag: typically -0, could use -O4 or -fast
+# -O4 is ok for RTEMS
+# NOTE: some level of -O may be actually required by inline assembler
+#CFLAGS_OPTIMIZE_V=-O4 -fno-keep-inline-functions
+CFLAGS_OPTIMIZE_V = -O2 -g
+
+# debug flags: typically none, but at least -O1 is required due to this
+# BSP using inlined code
+CFLAGS_DEBUG_V = -O1 -g
+
+define bsp-post-link
+ $(default-bsp-post-link)
+ $(OBJCOPY) -Obinary $@ $(basename $@)$(DOWNEXT)
+endef
+
+# Miscellaneous additions go here
+START_BASE = motld_start
diff --git a/c/src/lib/libbsp/powerpc/beatnik/marvell/discovery.c b/c/src/lib/libbsp/powerpc/beatnik/marvell/discovery.c
new file mode 100644
index 0000000000..81bbf7b4e0
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/beatnik/marvell/discovery.c
@@ -0,0 +1,151 @@
+/* $Id$ */
+
+/*
+ * Acknowledgements:
+ * Valuable information was obtained from the following drivers
+ * netbsd: (C) Allegro Networks Inc; Wasabi Systems Inc.
+ * linux: (C) MontaVista, Software, Inc; Chris Zankel, Mark A. Greer.
+ * rtems: (C) Brookhaven National Laboratory; K. Feng
+ * but this implementation is original work by the author.
+ */
+
+/*
+ * Authorship
+ * ----------
+ * This software ('beatnik' RTEMS BSP for MVME6100 and MVME5500) was
+ * created by Till Straumann <strauman@slac.stanford.edu>, 2005-2007,
+ * Stanford Linear Accelerator Center, Stanford University.
+ *
+ * Acknowledgement of sponsorship
+ * ------------------------------
+ * The 'beatnik' 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/bspIo.h>
+#include <bsp.h>
+#include <bsp/gtreg.h>
+#include <bsp/pci.h>
+
+#ifndef PCI_VENDOR_ID_MARVELL
+#define PCI_VENDOR_ID_MARVELL 0x11ab
+#endif
+
+#ifndef PCI_DEVICE_ID_MARVELL_GT64260
+#define PCI_DEVICE_ID_MARVELL_GT64260 0x6430
+#endif
+
+#ifndef PCI_DEVICE_ID_MARVELL_MV64360
+#define PCI_DEVICE_ID_MARVELL_MV64360 0x6460
+#endif
+
+#if 0
+#define MV64x60_PCI0_CONFIG_ADDR (BSP_MV64x60_BASE + 0xcf8)
+#define MV64x60_PCI0_CONFIG_DATA (BSP_MV64x60_BASE + 0xcfc)
+
+/* read from bus/slot/fn 0/0/0 */
+static unsigned long
+pci_early_config_read(int offset, int width)
+{
+ out_be32((unsigned int*) pci.pci_config_addr,
+ 0x80|(0<<8)|(PCI_DEVFN(0,0)<<16)|((offset&~3)<<24));
+ switch (width) {
+ default:
+ case 1:
+ return in_8((unsigned char*)pci.pci_config_data + (offset&3));
+ case 2:
+ return in_le16((unsigned short*)pci.pci_config_data + (offset&3));
+ case 4:
+ return in_le32((unsigned long *)pci.pci_config_data + (offset&3));
+ }
+}
+#endif
+
+DiscoveryVersion
+BSP_getDiscoveryVersion(int assertion)
+{
+static DiscoveryVersion rval = unknown;
+
+ if ( unknown ==rval ) {
+ unsigned char dc;
+ unsigned short ds;
+ /* this must work before and after the call to BSP_pciInitialize() --
+ * since the host bridge is at 0,0,0 it doesn't matter if the hosed
+ * access methods are installed or not (as a matter of fact this shouldn't
+ * matter for any device on hose 0)
+ */
+printk("config addr is 0x%08x\n", BSP_pci_configuration.pci_config_addr);
+printk("config data is 0x%08x\n", BSP_pci_configuration.pci_config_data);
+ pci_read_config_word(0,0,0,PCI_VENDOR_ID, &ds);
+ if ( PCI_VENDOR_ID_MARVELL != ds ) {
+ if ( assertion ) {
+ printk("Host bridge vendor id: 0x%04x\n",ds);
+ BSP_panic("Host bridge vendor @ pci(0,0,0) is not MARVELL");
+ }
+ else return unknown;
+ }
+ pci_read_config_word(0,0,0,PCI_DEVICE_ID, &ds);
+ pci_read_config_byte(0,0,0,PCI_REVISION_ID, &dc);
+ switch (ds) {
+ case PCI_DEVICE_ID_MARVELL_MV64360:
+ rval = MV_64360;
+ break;
+
+ case PCI_DEVICE_ID_MARVELL_GT64260:
+ switch (dc) {
+ default:
+ break;
+
+ case 0x10:
+ return (rval = GT_64260_A);
+
+ case 0x20:
+ return (rval = GT_64260_B);
+ }
+
+ default:
+ if ( assertion ) {
+ printk("Marvell device id 0x%04x, revision 0x%02x; check %s:%u\n",
+ ds, dc,
+ __FILE__,__LINE__);
+ BSP_panic("Unknown Marvell bridge or revision@ pci(0,0,0) is not MARVELL");
+ }
+ break;
+ }
+ }
+
+ return rval;
+}
diff --git a/c/src/lib/libbsp/powerpc/beatnik/marvell/gt.c b/c/src/lib/libbsp/powerpc/beatnik/marvell/gt.c
new file mode 100644
index 0000000000..c71b7cbdb3
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/beatnik/marvell/gt.c
@@ -0,0 +1,1010 @@
+/* $NetBSD: gt.c,v 1.5 2003/07/14 15:47:16 lukem Exp $ */
+
+/*
+ * Copyright (c) 2002 Allegro Networks, Inc., Wasabi Systems, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed for the NetBSD Project by
+ * Allegro Networks, Inc., and Wasabi Systems, Inc.
+ * 4. The name of Allegro Networks, Inc. may not be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ * 5. The name of Wasabi Systems, Inc. may not be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ALLEGRO NETWORKS, INC. AND
+ * WASABI SYSTEMS, INC. ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL EITHER ALLEGRO NETWORKS, INC. OR WASABI SYSTEMS, INC.
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * gt.c -- GT system controller driver
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: gt.c,v 1.5 2003/07/14 15:47:16 lukem Exp $");
+
+#include "opt_marvell.h"
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/cdefs.h>
+#include <sys/extent.h>
+#include <sys/device.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+
+#define _BUS_SPACE_PRIVATE
+#define _BUS_DMA_PRIVATE
+#include <machine/bus.h>
+
+#include <powerpc/spr.h>
+#include <powerpc/oea/hid.h>
+
+#include <dev/marvell/gtreg.h>
+#include <dev/marvell/gtintrreg.h>
+#include <dev/marvell/gtvar.h>
+#include <dev/marvell/gtethreg.h>
+
+#ifdef DEBUG
+#include <sys/systm.h> /* for Debugger() */
+#endif
+
+#if ((GT_MPP_WATCHDOG & 0xf0f0f0f0) != 0)
+# error /* unqualified: configuration botch! */
+#endif
+#if ((GT_MPP_WATCHDOG & GT_MPP_INTERRUPTS) != 0)
+# error /* conflict: configuration botch! */
+#endif
+
+static void gt_comm_intr_enb(struct gt_softc *);
+static void gt_devbus_intr_enb(struct gt_softc *);
+#ifdef GT_ECC
+static void gt_ecc_intr_enb(struct gt_softc *);
+#endif
+
+void gt_init_hostid (struct gt_softc *);
+void gt_init_interrupt (struct gt_softc *);
+static int gt_comm_intr (void *);
+
+void gt_watchdog_init(struct gt_softc *);
+void gt_watchdog_enable(void);
+void gt_watchdog_disable(void);
+void gt_watchdog_reset(void);
+
+extern struct cfdriver gt_cd;
+
+static int gtfound = 0;
+
+static struct gt_softc *gt_watchdog_sc = 0;
+static int gt_watchdog_state = 0;
+
+int
+gt_cfprint (void *aux, const char *pnp)
+{
+ struct gt_attach_args *ga = aux;
+
+ if (pnp) {
+ aprint_normal("%s at %s", ga->ga_name, pnp);
+ }
+
+ aprint_normal(" unit %d", ga->ga_unit);
+ return (UNCONF);
+}
+
+
+static int
+gt_cfsearch(struct device *parent, struct cfdata *cf, void *aux)
+{
+ struct gt_softc *gt = (struct gt_softc *) parent;
+ struct gt_attach_args ga;
+
+ ga.ga_name = cf->cf_name;
+ ga.ga_dmat = gt->gt_dmat;
+ ga.ga_memt = gt->gt_memt;
+ ga.ga_memh = gt->gt_memh;
+ ga.ga_unit = cf->cf_loc[GTCF_UNIT];
+
+ if (config_match(parent, cf, &ga) > 0)
+ config_attach(parent, cf, &ga, gt_cfprint);
+
+ return (0);
+}
+
+void
+gt_attach_common(struct gt_softc *gt)
+{
+ uint32_t cpucfg, cpumode, cpumstr;
+#ifdef DEBUG
+ uint32_t loaddr, hiaddr;
+#endif
+
+ gtfound = 1;
+
+ cpumode = gt_read(gt, GT_CPU_Mode);
+ aprint_normal(": id %d", GT_CPUMode_MultiGTID_GET(cpumode));
+ if (cpumode & GT_CPUMode_MultiGT)
+ aprint_normal (" (multi)");
+ switch (GT_CPUMode_CPUType_GET(cpumode)) {
+ case 4: aprint_normal(", 60x bus"); break;
+ case 5: aprint_normal(", MPX bus"); break;
+ default: aprint_normal(", %#x(?) bus", GT_CPUMode_CPUType_GET(cpumode)); break;
+ }
+
+ cpumstr = gt_read(gt, GT_CPU_Master_Ctl);
+ cpumstr &= ~(GT_CPUMstrCtl_CleanBlock|GT_CPUMstrCtl_FlushBlock);
+#if 0
+ cpumstr |= GT_CPUMstrCtl_CleanBlock|GT_CPUMstrCtl_FlushBlock;
+#endif
+ gt_write(gt, GT_CPU_Master_Ctl, cpumstr);
+
+ switch (cpumstr & (GT_CPUMstrCtl_CleanBlock|GT_CPUMstrCtl_FlushBlock)) {
+ case 0: break;
+ case GT_CPUMstrCtl_CleanBlock: aprint_normal(", snoop=clean"); break;
+ case GT_CPUMstrCtl_FlushBlock: aprint_normal(", snoop=flush"); break;
+ case GT_CPUMstrCtl_CleanBlock|GT_CPUMstrCtl_FlushBlock:
+ aprint_normal(", snoop=clean&flush"); break;
+ }
+ aprint_normal(" wdog=%#x,%#x\n",
+ gt_read(gt, GT_WDOG_Config),
+ gt_read(gt, GT_WDOG_Value));
+
+#if DEBUG
+ loaddr = GT_LowAddr_GET(gt_read(gt, GT_SCS0_Low_Decode));
+ hiaddr = GT_HighAddr_GET(gt_read(gt, GT_SCS0_High_Decode));
+ aprint_normal("%s: scs[0]=%#10x-%#10x\n", gt->gt_dev.dv_xname, loaddr, hiaddr);
+
+ loaddr = GT_LowAddr_GET(gt_read(gt, GT_SCS1_Low_Decode));
+ hiaddr = GT_HighAddr_GET(gt_read(gt, GT_SCS1_High_Decode));
+ aprint_normal("%s: scs[1]=%#10x-%#10x\n", gt->gt_dev.dv_xname, loaddr, hiaddr);
+
+ loaddr = GT_LowAddr_GET(gt_read(gt, GT_SCS2_Low_Decode));
+ hiaddr = GT_HighAddr_GET(gt_read(gt, GT_SCS2_High_Decode));
+ aprint_normal("%s: scs[2]=%#10x-%#10x\n", gt->gt_dev.dv_xname, loaddr, hiaddr);
+
+ loaddr = GT_LowAddr_GET(gt_read(gt, GT_SCS3_Low_Decode));
+ hiaddr = GT_HighAddr_GET(gt_read(gt, GT_SCS3_High_Decode));
+ aprint_normal("%s: scs[3]=%#10x-%#10x\n", gt->gt_dev.dv_xname, loaddr, hiaddr);
+
+ loaddr = GT_LowAddr_GET(gt_read(gt, GT_CS0_Low_Decode));
+ hiaddr = GT_HighAddr_GET(gt_read(gt, GT_CS0_High_Decode));
+ aprint_normal("%s: cs[0]=%#10x-%#10x\n", gt->gt_dev.dv_xname, loaddr, hiaddr);
+
+ loaddr = GT_LowAddr_GET(gt_read(gt, GT_CS1_Low_Decode));
+ hiaddr = GT_HighAddr_GET(gt_read(gt, GT_CS1_High_Decode));
+ aprint_normal("%s: cs[1]=%#10x-%#10x\n", gt->gt_dev.dv_xname, loaddr, hiaddr);
+
+ loaddr = GT_LowAddr_GET(gt_read(gt, GT_CS2_Low_Decode));
+ hiaddr = GT_HighAddr_GET(gt_read(gt, GT_CS2_High_Decode));
+ aprint_normal("%s: cs[2]=%#10x-%#10x\n", gt->gt_dev.dv_xname, loaddr, hiaddr);
+
+ loaddr = GT_LowAddr_GET(gt_read(gt, GT_CS3_Low_Decode));
+ hiaddr = GT_HighAddr_GET(gt_read(gt, GT_CS3_High_Decode));
+ aprint_normal("%s: cs[3]=%#10x-%#10x\n", gt->gt_dev.dv_xname, loaddr, hiaddr);
+
+ loaddr = GT_LowAddr_GET(gt_read(gt, GT_BootCS_Low_Decode));
+ hiaddr = GT_HighAddr_GET(gt_read(gt, GT_BootCS_High_Decode));
+ aprint_normal("%s: bootcs=%#10x-%#10x\n", gt->gt_dev.dv_xname, loaddr, hiaddr);
+
+ loaddr = GT_LowAddr_GET(gt_read(gt, GT_PCI0_IO_Low_Decode));
+ hiaddr = GT_HighAddr_GET(gt_read(gt, GT_PCI0_IO_High_Decode));
+ aprint_normal("%s: pci0io=%#10x-%#10x ", gt->gt_dev.dv_xname, loaddr, hiaddr);
+
+ loaddr = gt_read(gt, GT_PCI0_IO_Remap);
+ aprint_normal("remap=%#010x\n", loaddr);
+
+ loaddr = GT_LowAddr_GET(gt_read(gt, GT_PCI0_Mem0_Low_Decode));
+ hiaddr = GT_HighAddr_GET(gt_read(gt, GT_PCI0_Mem0_High_Decode));
+ aprint_normal("%s: pci0mem[0]=%#10x-%#10x ", gt->gt_dev.dv_xname, loaddr, hiaddr);
+
+ loaddr = gt_read(gt, GT_PCI0_Mem0_Remap_Low);
+ hiaddr = gt_read(gt, GT_PCI0_Mem0_Remap_High);
+ aprint_normal("remap=%#010x.%#010x\n", hiaddr, loaddr);
+
+ loaddr = GT_LowAddr_GET(gt_read(gt, GT_PCI0_Mem1_Low_Decode));
+ hiaddr = GT_HighAddr_GET(gt_read(gt, GT_PCI0_Mem1_High_Decode));
+ aprint_normal("%s: pci0mem[1]=%#10x-%#10x ", gt->gt_dev.dv_xname, loaddr, hiaddr);
+
+ loaddr = gt_read(gt, GT_PCI0_Mem1_Remap_Low);
+ hiaddr = gt_read(gt, GT_PCI0_Mem1_Remap_High);
+ aprint_normal("remap=%#010x.%#010x\n", hiaddr, loaddr);
+
+ loaddr = GT_LowAddr_GET(gt_read(gt, GT_PCI0_Mem2_Low_Decode));
+ hiaddr = GT_HighAddr_GET(gt_read(gt, GT_PCI0_Mem2_High_Decode));
+ aprint_normal("%s: pci0mem[2]=%#10x-%#10x ", gt->gt_dev.dv_xname, loaddr, hiaddr);
+
+ loaddr = gt_read(gt, GT_PCI0_Mem2_Remap_Low);
+ hiaddr = gt_read(gt, GT_PCI0_Mem2_Remap_High);
+ aprint_normal("remap=%#010x.%#010x\n", hiaddr, loaddr);
+
+ loaddr = GT_LowAddr_GET(gt_read(gt, GT_PCI0_Mem3_Low_Decode));
+ hiaddr = GT_HighAddr_GET(gt_read(gt, GT_PCI0_Mem3_High_Decode));
+ aprint_normal("%s: pci0mem[3]=%#10x-%#10x ", gt->gt_dev.dv_xname, loaddr, hiaddr);
+
+ loaddr = gt_read(gt, GT_PCI0_Mem3_Remap_Low);
+ hiaddr = gt_read(gt, GT_PCI0_Mem3_Remap_High);
+ aprint_normal("remap=%#010x.%#010x\n", hiaddr, loaddr);
+
+ loaddr = GT_LowAddr_GET(gt_read(gt, GT_PCI1_IO_Low_Decode));
+ hiaddr = GT_HighAddr_GET(gt_read(gt, GT_PCI1_IO_High_Decode));
+ aprint_normal("%s: pci1io=%#10x-%#10x ", gt->gt_dev.dv_xname, loaddr, hiaddr);
+
+ loaddr = gt_read(gt, GT_PCI1_IO_Remap);
+ aprint_normal("remap=%#010x\n", loaddr);
+
+ loaddr = GT_LowAddr_GET(gt_read(gt, GT_PCI1_Mem0_Low_Decode));
+ hiaddr = GT_HighAddr_GET(gt_read(gt, GT_PCI1_Mem0_High_Decode));
+ aprint_normal("%s: pci1mem[0]=%#10x-%#10x ", gt->gt_dev.dv_xname, loaddr, hiaddr);
+
+ loaddr = gt_read(gt, GT_PCI1_Mem0_Remap_Low);
+ hiaddr = gt_read(gt, GT_PCI1_Mem0_Remap_High);
+ aprint_normal("remap=%#010x.%#010x\n", hiaddr, loaddr);
+
+ loaddr = GT_LowAddr_GET(gt_read(gt, GT_PCI1_Mem1_Low_Decode));
+ hiaddr = GT_HighAddr_GET(gt_read(gt, GT_PCI1_Mem1_High_Decode));
+ aprint_normal("%s: pci1mem[1]=%#10x-%#10x ", gt->gt_dev.dv_xname, loaddr, hiaddr);
+
+ loaddr = gt_read(gt, GT_PCI1_Mem1_Remap_Low);
+ hiaddr = gt_read(gt, GT_PCI1_Mem1_Remap_High);
+ aprint_normal("remap=%#010x.%#010x\n", hiaddr, loaddr);
+
+ loaddr = GT_LowAddr_GET(gt_read(gt, GT_PCI1_Mem2_Low_Decode));
+ hiaddr = GT_HighAddr_GET(gt_read(gt, GT_PCI1_Mem2_High_Decode));
+ aprint_normal("%s: pci1mem[2]=%#10x-%#10x ", gt->gt_dev.dv_xname, loaddr, hiaddr);
+
+ loaddr = gt_read(gt, GT_PCI1_Mem2_Remap_Low);
+ hiaddr = gt_read(gt, GT_PCI1_Mem2_Remap_High);
+ aprint_normal("remap=%#010x.%#010x\n", hiaddr, loaddr);
+
+ loaddr = GT_LowAddr_GET(gt_read(gt, GT_PCI1_Mem3_Low_Decode));
+ hiaddr = GT_HighAddr_GET(gt_read(gt, GT_PCI1_Mem3_High_Decode));
+ aprint_normal("%s: pci1mem[3]=%#10x-%#10x ", gt->gt_dev.dv_xname, loaddr, hiaddr);
+
+ loaddr = gt_read(gt, GT_PCI1_Mem3_Remap_Low);
+ hiaddr = gt_read(gt, GT_PCI1_Mem3_Remap_High);
+ aprint_normal("remap=%#010x.%#010x\n", hiaddr, loaddr);
+
+ loaddr = GT_LowAddr_GET(gt_read(gt, GT_Internal_Decode));
+ aprint_normal("%s: internal=%#10x-%#10x\n", gt->gt_dev.dv_xname,
+ loaddr, loaddr+256*1024);
+
+ loaddr = GT_LowAddr_GET(gt_read(gt, GT_CPU0_Low_Decode));
+ hiaddr = GT_HighAddr_GET(gt_read(gt, GT_CPU0_High_Decode));
+ aprint_normal("%s: cpu0=%#10x-%#10x\n", gt->gt_dev.dv_xname, loaddr, hiaddr);
+
+ loaddr = GT_LowAddr_GET(gt_read(gt, GT_CPU1_Low_Decode));
+ hiaddr = GT_HighAddr_GET(gt_read(gt, GT_CPU1_High_Decode));
+ aprint_normal("%s: cpu1=%#10x-%#10x", gt->gt_dev.dv_xname, loaddr, hiaddr);
+#endif
+
+ aprint_normal("%s:", gt->gt_dev.dv_xname);
+
+ cpucfg = gt_read(gt, GT_CPU_Cfg);
+ cpucfg |= GT_CPUCfg_ConfSBDis; /* per errata #46 */
+ cpucfg |= GT_CPUCfg_AACKDelay; /* per restriction #18 */
+ gt_write(gt, GT_CPU_Cfg, cpucfg);
+ if (cpucfg & GT_CPUCfg_Pipeline)
+ aprint_normal(" pipeline");
+ if (cpucfg & GT_CPUCfg_AACKDelay)
+ aprint_normal(" aack-delay");
+ if (cpucfg & GT_CPUCfg_RdOOO)
+ aprint_normal(" read-ooo");
+ if (cpucfg & GT_CPUCfg_IOSBDis)
+ aprint_normal(" io-sb-dis");
+ if (cpucfg & GT_CPUCfg_ConfSBDis)
+ aprint_normal(" conf-sb-dis");
+ if (cpucfg & GT_CPUCfg_ClkSync)
+ aprint_normal(" clk-sync");
+ aprint_normal("\n");
+
+ gt_init_hostid(gt);
+
+ gt_watchdog_init(gt);
+
+ gt_init_interrupt(gt);
+
+#ifdef GT_ECC
+ gt_ecc_intr_enb(gt);
+#endif
+
+ gt_comm_intr_enb(gt);
+ gt_devbus_intr_enb(gt);
+
+ gt_watchdog_disable();
+ config_search(gt_cfsearch, &gt->gt_dev, NULL);
+ gt_watchdog_service();
+ gt_watchdog_enable();
+}
+
+void
+gt_init_hostid(struct gt_softc *gt)
+{
+
+ hostid = 1; /* XXX: Used by i2c; needs work -- AKB */
+}
+
+void
+gt_init_interrupt(struct gt_softc *gt)
+{
+ u_int32_t mppirpts = GT_MPP_INTERRUPTS; /* from config */
+ u_int32_t r;
+ u_int32_t mppbit;
+ u_int32_t mask;
+ u_int32_t mppsel;
+ u_int32_t regoff;
+
+ gt_write(gt, ICR_CIM_LO, 0);
+ gt_write(gt, ICR_CIM_HI, 0);
+
+ /*
+ * configure the GPP interrupts:
+ * - set the configured MPP pins in GPP mode
+ * - set the configured GPP pins to input, active low, interrupt enbl
+ */
+#ifdef DEBUG
+ printf("%s: mpp cfg ", gt->gt_dev.dv_xname);
+ for (regoff = GT_MPP_Control0; regoff <= GT_MPP_Control3; regoff += 4)
+ printf("%#x ", gt_read(gt, regoff));
+ printf(", mppirpts 0x%x\n", mppirpts);
+#endif
+ mppbit = 0x1;
+ for (regoff = GT_MPP_Control0; regoff <= GT_MPP_Control3; regoff += 4) {
+ mask = 0;
+ for (mppsel = 0xf; mppsel; mppsel <<= 4) {
+ if (mppirpts & mppbit)
+ mask |= mppsel;
+ mppbit <<= 1;
+ }
+ if (mask) {
+ r = gt_read(gt, regoff);
+ r &= ~mask;
+ gt_write(gt, regoff, r);
+ }
+ }
+
+ r = gt_read(gt, GT_GPP_IO_Control);
+ r &= ~mppirpts;
+ gt_write(gt, GT_GPP_IO_Control, r);
+
+ r = gt_read(gt, GT_GPP_Level_Control);
+ r |= mppirpts;
+ gt_write(gt, GT_GPP_Level_Control, r);
+
+ r = gt_read(gt, GT_GPP_Interrupt_Mask);
+ r |= mppirpts;
+ gt_write(gt, GT_GPP_Interrupt_Mask, r);
+}
+
+uint32_t
+gt_read_mpp (void)
+{
+ return gt_read((struct gt_softc *)gt_cd.cd_devs[0], GT_GPP_Value);
+}
+
+#if 0
+int
+gt_bs_extent_init(struct discovery_bus_space *bs, char *name)
+{
+ u_long start, end;
+ int i, j, error;
+
+ if (bs->bs_nregion == 0) {
+ bs->bs_extent = extent_create(name, 0xffffffffUL, 0xffffffffUL,
+ M_DEVBUF, NULL, 0, EX_NOCOALESCE|EX_WAITOK);
+ KASSERT(bs->bs_extent != NULL);
+ return 0;
+ }
+ /*
+ * Find the top and bottoms of this bus space.
+ */
+ start = bs->bs_regions[0].br_start;
+ end = bs->bs_regions[0].br_end;
+#ifdef DEBUG
+ if (gtpci_debug > 1)
+ printf("gtpci_bs_extent_init: %s: region %d: %#lx-%#lx\n",
+ name, 0, bs->bs_regions[0].br_start,
+ bs->bs_regions[0].br_end);
+#endif
+ for (i = 1; i < bs->bs_nregion; i++) {
+ if (bs->bs_regions[i].br_start < start)
+ start = bs->bs_regions[i].br_start;
+ if (bs->bs_regions[i].br_end > end)
+ end = bs->bs_regions[i].br_end;
+#ifdef DEBUG
+ if (gtpci_debug > 1)
+ printf("gtpci_bs_extent_init: %s: region %d:"
+ " %#lx-%#lx\n",
+ name, i, bs->bs_regions[i].br_start,
+ bs->bs_regions[i].br_end);
+#endif
+ }
+ /*
+ * Now that we have the top and bottom limits of this
+ * bus space, create the extent map that will manage this
+ * space for us.
+ */
+#ifdef DEBUG
+ if (gtpci_debug > 1)
+ printf("gtpci_bs_extent_init: %s: create: %#lx-%#lx\n",
+ name, start, end);
+#endif
+ bs->bs_extent = extent_create(name, start, end, M_DEVBUF,
+ NULL, 0, EX_NOCOALESCE|EX_WAITOK);
+ KASSERT(bs->bs_extent != NULL);
+
+ /* If there was more than one bus space region, then there
+ * might gaps in between them. Allocate the gap so that
+ * they will not be legal addresses in the extent.
+ */
+ for (i = 0; i < bs->bs_nregion && bs->bs_nregion > 1; i++) {
+ /* Initial start is "infinity" and the inital end is
+ * is the end of this bus region.
+ */
+ start = ~0UL;
+ end = bs->bs_regions[i].br_end;
+ /* For each region, if it starts after this region but less
+ * than the saved start, use its start address. If the start
+ * address is one past the end address, then we're done
+ */
+ for (j = 0; j < bs->bs_nregion && start > end + 1; j++) {
+ if (i == j)
+ continue;
+ if (bs->bs_regions[j].br_start > end &&
+ bs->bs_regions[j].br_start < start)
+ start = bs->bs_regions[j].br_start;
+ }
+ /*
+ * If we found a gap, allocate it away.
+ */
+ if (start != ~0UL && start != end + 1) {
+#ifdef DEBUG
+ if (gtpci_debug > 1)
+ printf("gtpci_bs_extent_init: %s: alloc(hole): %#lx-%#lx\n",
+ name, end + 1, start - 1);
+#endif
+ error = extent_alloc_region(bs->bs_extent, end + 1,
+ start - (end + 1), EX_NOWAIT);
+ KASSERT(error == 0);
+ }
+ }
+ return 1;
+}
+#endif
+
+/*
+ * unknown board, enable everything
+ */
+# define GT_CommUnitIntr_DFLT GT_CommUnitIntr_S0|GT_CommUnitIntr_S1 \
+ |GT_CommUnitIntr_E0|GT_CommUnitIntr_E1 \
+ |GT_CommUnitIntr_E2
+
+static const char * const gt_comm_subunit_name[8] = {
+ "ethernet 0",
+ "ethernet 1",
+ "ethernet 2",
+ "(reserved)",
+ "MPSC 0",
+ "MPSC 1",
+ "(reserved)",
+ "(sel)",
+};
+
+static int
+gt_comm_intr(void *arg)
+{
+ struct gt_softc *gt = (struct gt_softc *)arg;
+ u_int32_t cause;
+ u_int32_t addr;
+ unsigned int mask;
+ int i;
+
+ cause = gt_read(gt, GT_CommUnitIntr_Cause);
+ gt_write(gt, GT_CommUnitIntr_Cause, ~cause);
+ addr = gt_read(gt, GT_CommUnitIntr_ErrAddr);
+
+ printf("%s: Comm Unit irpt, cause %#x addr %#x\n",
+ gt->gt_dev.dv_xname, cause, addr);
+
+ cause &= GT_CommUnitIntr_DFLT;
+ if (cause == 0)
+ return 0;
+
+ mask = 0x7;
+ for (i=0; i<7; i++) {
+ if (cause & mask) {
+ printf("%s: Comm Unit %s:", gt->gt_dev.dv_xname,
+ gt_comm_subunit_name[i]);
+ if (cause & 1)
+ printf(" AddrMiss");
+ if (cause & 2)
+ printf(" AccProt");
+ if (cause & 4)
+ printf(" WrProt");
+ printf("\n");
+ }
+ cause >>= 4;
+ }
+ return 1;
+}
+
+/*
+ * gt_comm_intr_init - enable GT-64260 Comm Unit interrupts
+ */
+static void
+gt_comm_intr_enb(struct gt_softc *gt)
+{
+ u_int32_t cause;
+
+ cause = gt_read(gt, GT_CommUnitIntr_Cause);
+ if (cause)
+ gt_write(gt, GT_CommUnitIntr_Cause, ~cause);
+ gt_write(gt, GT_CommUnitIntr_Mask, GT_CommUnitIntr_DFLT);
+ (void)gt_read(gt, GT_CommUnitIntr_ErrAddr);
+
+ intr_establish(IRQ_COMM, IST_LEVEL, IPL_GTERR, gt_comm_intr, gt);
+ printf("%s: Comm Unit irpt at %d\n", gt->gt_dev.dv_xname, IRQ_COMM);
+}
+
+#ifdef GT_ECC
+static char *gt_ecc_intr_str[4] = {
+ "(none)",
+ "single bit",
+ "double bit",
+ "(reserved)"
+};
+
+static int
+gt_ecc_intr(void *arg)
+{
+ struct gt_softc *gt = (struct gt_softc *)arg;
+ u_int32_t addr;
+ u_int32_t dlo;
+ u_int32_t dhi;
+ u_int32_t rec;
+ u_int32_t calc;
+ u_int32_t count;
+ int err;
+
+ count = gt_read(gt, GT_ECC_Count);
+ dlo = gt_read(gt, GT_ECC_Data_Lo);
+ dhi = gt_read(gt, GT_ECC_Data_Hi);
+ rec = gt_read(gt, GT_ECC_Rec);
+ calc = gt_read(gt, GT_ECC_Calc);
+ addr = gt_read(gt, GT_ECC_Addr); /* read last! */
+ gt_write(gt, GT_ECC_Addr, 0); /* clear irpt */
+
+ err = addr & 0x3;
+
+ printf("%s: ECC error: %s: "
+ "addr %#x data %#x.%#x rec %#x calc %#x cnt %#x\n",
+ gt->gt_dev.dv_xname, gt_ecc_intr_str[err],
+ addr, dhi, dlo, rec, calc, count);
+
+ if (err == 2)
+ panic("ecc");
+
+ return (err == 1);
+}
+
+/*
+ * gt_ecc_intr_enb - enable GT-64260 ECC interrupts
+ */
+static void
+gt_ecc_intr_enb(struct gt_softc *gt)
+{
+ u_int32_t ctl;
+
+ ctl = gt_read(gt, GT_ECC_Ctl);
+ ctl |= 1 << 16; /* XXX 1-bit threshold == 1 */
+ gt_write(gt, GT_ECC_Ctl, ctl);
+ (void)gt_read(gt, GT_ECC_Data_Lo);
+ (void)gt_read(gt, GT_ECC_Data_Hi);
+ (void)gt_read(gt, GT_ECC_Rec);
+ (void)gt_read(gt, GT_ECC_Calc);
+ (void)gt_read(gt, GT_ECC_Addr); /* read last! */
+ gt_write(gt, GT_ECC_Addr, 0); /* clear irpt */
+
+ intr_establish(IRQ_ECC, IST_LEVEL, IPL_GTERR, gt_ecc_intr, gt);
+ printf("%s: ECC irpt at %d\n", gt->gt_dev.dv_xname, IRQ_ECC);
+}
+#endif /* GT_ECC */
+
+
+#ifndef GT_MPP_WATCHDOG
+void
+gt_watchdog_init(struct gt_softc *gt)
+{
+ u_int32_t r;
+ unsigned int omsr;
+
+ omsr = extintr_disable();
+
+ printf("%s: watchdog", gt->gt_dev.dv_xname);
+
+ /*
+ * handle case where firmware started watchdog
+ */
+ r = gt_read(gt, GT_WDOG_Config);
+ printf(" status %#x,%#x:",
+ r, gt_read(gt, GT_WDOG_Value));
+ if ((r & 0x80000000) != 0) {
+ gt_watchdog_sc = gt; /* enabled */
+ gt_watchdog_state = 1;
+ printf(" firmware-enabled\n");
+ gt_watchdog_service();
+ return;
+ } else {
+ printf(" firmware-disabled\n");
+ }
+
+ extintr_restore(omsr);
+}
+
+#else /* GT_MPP_WATCHDOG */
+
+void
+gt_watchdog_init(struct gt_softc *gt)
+{
+ u_int32_t mpp_watchdog = GT_MPP_WATCHDOG; /* from config */
+ u_int32_t r;
+ u_int32_t cfgbits;
+ u_int32_t mppbits;
+ u_int32_t mppmask=0;
+ u_int32_t regoff;
+ unsigned int omsr;
+
+ printf("%s: watchdog", gt->gt_dev.dv_xname);
+
+ if (mpp_watchdog == 0) {
+ printf(" not configured\n");
+ return;
+ }
+
+#if 0
+ if (afw_wdog_ctl == 1) {
+ printf(" admin disabled\n");
+ return;
+ }
+#endif
+
+ omsr = extintr_disable();
+
+ /*
+ * if firmware started watchdog, we disable and start
+ * from scratch to get it in a known state.
+ *
+ * on GT-64260A we always see 0xffffffff
+ * in both the GT_WDOG_Config_Enb and GT_WDOG_Value regsiters.
+ * Use AFW-supplied flag to determine run state.
+ */
+ r = gt_read(gt, GT_WDOG_Config);
+ if (r != ~0) {
+ if ((r & GT_WDOG_Config_Enb) != 0) {
+ gt_write(gt, GT_WDOG_Config,
+ (GT_WDOG_Config_Ctl1a | GT_WDOG_Preset_DFLT));
+ gt_write(gt, GT_WDOG_Config,
+ (GT_WDOG_Config_Ctl1b | GT_WDOG_Preset_DFLT));
+ }
+ } else {
+#if 0
+ if (afw_wdog_state == 1) {
+ gt_write(gt, GT_WDOG_Config,
+ (GT_WDOG_Config_Ctl1a | GT_WDOG_Preset_DFLT));
+ gt_write(gt, GT_WDOG_Config,
+ (GT_WDOG_Config_Ctl1b | GT_WDOG_Preset_DFLT));
+ }
+#endif
+ }
+
+ /*
+ * "the watchdog timer can be activated only after
+ * configuring two MPP pins to act as WDE and WDNMI"
+ */
+ mppbits = 0;
+ cfgbits = 0x3;
+ for (regoff = GT_MPP_Control0; regoff <= GT_MPP_Control3; regoff += 4) {
+ if ((mpp_watchdog & cfgbits) == cfgbits) {
+ mppbits = 0x99;
+ mppmask = 0xff;
+ break;
+ }
+ cfgbits <<= 2;
+ if ((mpp_watchdog & cfgbits) == cfgbits) {
+ mppbits = 0x9900;
+ mppmask = 0xff00;
+ break;
+ }
+ cfgbits <<= 6; /* skip unqualified bits */
+ }
+ if (mppbits == 0) {
+ printf(" config error\n");
+ extintr_restore(omsr);
+ return;
+ }
+
+ r = gt_read(gt, regoff);
+ r &= ~mppmask;
+ r |= mppbits;
+ gt_write(gt, regoff, r);
+ printf(" mpp %#x %#x", regoff, mppbits);
+
+ gt_write(gt, GT_WDOG_Value, GT_WDOG_NMI_DFLT);
+
+ gt_write(gt, GT_WDOG_Config,
+ (GT_WDOG_Config_Ctl1a | GT_WDOG_Preset_DFLT));
+ gt_write(gt, GT_WDOG_Config,
+ (GT_WDOG_Config_Ctl1b | GT_WDOG_Preset_DFLT));
+
+
+ r = gt_read(gt, GT_WDOG_Config),
+ printf(" status %#x,%#x: %s",
+ r, gt_read(gt, GT_WDOG_Value),
+ ((r & GT_WDOG_Config_Enb) != 0) ? "enabled" : "botch");
+
+ if ((r & GT_WDOG_Config_Enb) != 0) {
+ register_t hid0;
+
+ gt_watchdog_sc = gt; /* enabled */
+ gt_watchdog_state = 1;
+
+ /*
+ * configure EMCP in HID0 in case it's not already set
+ */
+ __asm __volatile("sync":::"memory");
+ hid0 = mfspr(SPR_HID0);
+ if ((hid0 & HID0_EMCP) == 0) {
+ hid0 |= HID0_EMCP;
+ __asm __volatile("sync":::"memory"); mtspr(SPR_HID0, hid0);
+ __asm __volatile("sync":::"memory"); hid0 = mfspr(SPR_HID0);
+ printf(", EMCP set");
+ }
+ }
+ printf("\n");
+
+ extintr_restore(omsr);
+}
+#endif /* GT_MPP_WATCHDOG */
+
+#ifdef DEBUG
+u_int32_t hid0_print(void);
+u_int32_t
+hid0_print()
+{
+ u_int32_t hid0;
+ __asm __volatile("sync; mfspr %0,1008;" : "=r"(hid0)::"memory");
+ printf("hid0: %#x\n", hid0);
+ return hid0;
+}
+#endif
+
+void
+gt_watchdog_enable(void)
+{
+ struct gt_softc *gt;
+ unsigned int omsr;
+
+ omsr = extintr_disable();
+ gt = gt_watchdog_sc;
+ if ((gt != NULL) && (gt_watchdog_state == 0)) {
+ gt_watchdog_state = 1;
+
+ gt_write(gt, GT_WDOG_Config,
+ (GT_WDOG_Config_Ctl1a | GT_WDOG_Preset_DFLT));
+ gt_write(gt, GT_WDOG_Config,
+ (GT_WDOG_Config_Ctl1b | GT_WDOG_Preset_DFLT));
+ }
+ extintr_restore(omsr);
+}
+
+void
+gt_watchdog_disable(void)
+{
+ struct gt_softc *gt;
+ unsigned int omsr;
+
+ omsr = extintr_disable();
+ gt = gt_watchdog_sc;
+ if ((gt != NULL) && (gt_watchdog_state != 0)) {
+ gt_watchdog_state = 0;
+
+ gt_write(gt, GT_WDOG_Config,
+ (GT_WDOG_Config_Ctl1a | GT_WDOG_Preset_DFLT));
+ gt_write(gt, GT_WDOG_Config,
+ (GT_WDOG_Config_Ctl1b | GT_WDOG_Preset_DFLT));
+ }
+ extintr_restore(omsr);
+}
+
+#ifdef DEBUG
+int inhibit_watchdog_service = 0;
+#endif
+void
+gt_watchdog_service(void)
+{
+ struct gt_softc *gt = gt_watchdog_sc;
+
+ if ((gt == NULL) || (gt_watchdog_state == 0))
+ return; /* not enabled */
+#ifdef DEBUG
+ if (inhibit_watchdog_service)
+ return;
+#endif
+
+ gt_write(gt, GT_WDOG_Config,
+ (GT_WDOG_Config_Ctl2a | GT_WDOG_Preset_DFLT));
+ gt_write(gt, GT_WDOG_Config,
+ (GT_WDOG_Config_Ctl2b | GT_WDOG_Preset_DFLT));
+}
+
+/*
+ * gt_watchdog_reset - force a watchdog reset using Preset_VAL=0
+ */
+void
+gt_watchdog_reset()
+{
+ struct gt_softc *gt = gt_watchdog_sc;
+ u_int32_t r;
+
+ (void)extintr_disable();
+ r = gt_read(gt, GT_WDOG_Config);
+ gt_write(gt, GT_WDOG_Config, (GT_WDOG_Config_Ctl1a | 0));
+ gt_write(gt, GT_WDOG_Config, (GT_WDOG_Config_Ctl1b | 0));
+ if ((r & GT_WDOG_Config_Enb) != 0) {
+ /*
+ * was enabled, we just toggled it off, toggle on again
+ */
+ gt_write(gt, GT_WDOG_Config,
+ (GT_WDOG_Config_Ctl1a | 0));
+ gt_write(gt, GT_WDOG_Config,
+ (GT_WDOG_Config_Ctl1b | 0));
+ }
+ for(;;);
+}
+
+static int
+gt_devbus_intr(void *arg)
+{
+ struct gt_softc *gt = (struct gt_softc *)arg;
+ u_int32_t cause;
+ u_int32_t addr;
+
+ cause = gt_read(gt, GT_DEVBUS_ICAUSE);
+ addr = gt_read(gt, GT_DEVBUS_ERR_ADDR);
+ gt_write(gt, GT_DEVBUS_ICAUSE, 0); /* clear irpt */
+
+ if (cause & GT_DEVBUS_DBurstErr) {
+ printf("%s: Device Bus error: burst violation",
+ gt->gt_dev.dv_xname);
+ if ((cause & GT_DEVBUS_Sel) == 0)
+ printf(", addr %#x", addr);
+ printf("\n");
+ }
+ if (cause & GT_DEVBUS_DRdyErr) {
+ printf("%s: Device Bus error: ready timer expired",
+ gt->gt_dev.dv_xname);
+ if ((cause & GT_DEVBUS_Sel) != 0)
+ printf(", addr %#x\n", addr);
+ printf("\n");
+ }
+
+ return (cause != 0);
+}
+
+/*
+ * gt_ecc_intr_enb - enable GT-64260 ECC interrupts
+ */
+static void
+gt_devbus_intr_enb(struct gt_softc *gt)
+{
+ gt_write(gt, GT_DEVBUS_IMASK,
+ GT_DEVBUS_DBurstErr|GT_DEVBUS_DRdyErr);
+ (void)gt_read(gt, GT_DEVBUS_ERR_ADDR); /* clear addr */
+ gt_write(gt, GT_ECC_Addr, 0); /* clear irpt */
+
+ intr_establish(IRQ_DEV, IST_LEVEL, IPL_GTERR, gt_devbus_intr, gt);
+ printf("%s: Device Bus Error irpt at %d\n",
+ gt->gt_dev.dv_xname, IRQ_DEV);
+}
+
+
+int
+gt_mii_read(
+ struct device *child,
+ struct device *parent,
+ int phy,
+ int reg)
+{
+ struct gt_softc * const gt = (struct gt_softc *) parent;
+ uint32_t data;
+ int count = 10000;
+
+ do {
+ DELAY(10);
+ data = gt_read(gt, ETH_ESMIR);
+ } while ((data & ETH_ESMIR_Busy) && count-- > 0);
+
+ if (count == 0) {
+ printf("%s: mii read for phy %d reg %d busied out\n",
+ child->dv_xname, phy, reg);
+ return ETH_ESMIR_Value_GET(data);
+ }
+
+ gt_write(gt, ETH_ESMIR, ETH_ESMIR_READ(phy, reg));
+
+ count = 10000;
+ do {
+ DELAY(10);
+ data = gt_read(gt, ETH_ESMIR);
+ } while ((data & ETH_ESMIR_ReadValid) == 0 && count-- > 0);
+
+ if (count == 0)
+ printf("%s: mii read for phy %d reg %d timed out\n",
+ child->dv_xname, phy, reg);
+#if defined(GTMIIDEBUG)
+ printf("%s: mii_read(%d, %d): %#x data %#x\n",
+ child->dv_xname, phy, reg,
+ data, ETH_ESMIR_Value_GET(data));
+#endif
+ return ETH_ESMIR_Value_GET(data);
+}
+
+void
+gt_mii_write (
+ struct device *child,
+ struct device *parent,
+ int phy, int reg,
+ int value)
+{
+ struct gt_softc * const gt = (struct gt_softc *) parent;
+ uint32_t data;
+ int count = 10000;
+
+ do {
+ DELAY(10);
+ data = gt_read(gt, ETH_ESMIR);
+ } while ((data & ETH_ESMIR_Busy) && count-- > 0);
+
+ if (count == 0) {
+ printf("%s: mii write for phy %d reg %d busied out (busy)\n",
+ child->dv_xname, phy, reg);
+ return;
+ }
+
+ gt_write(gt, ETH_ESMIR,
+ ETH_ESMIR_WRITE(phy, reg, value));
+
+ count = 10000;
+ do {
+ DELAY(10);
+ data = gt_read(gt, ETH_ESMIR);
+ } while ((data & ETH_ESMIR_Busy) && count-- > 0);
+
+ if (count == 0)
+ printf("%s: mii write for phy %d reg %d timed out\n",
+ child->dv_xname, phy, reg);
+#if defined(GTMIIDEBUG)
+ printf("%s: mii_write(%d, %d, %#x)\n",
+ child->dv_xname, phy, reg, value);
+#endif
+}
+
diff --git a/c/src/lib/libbsp/powerpc/beatnik/marvell/gt_timer.c b/c/src/lib/libbsp/powerpc/beatnik/marvell/gt_timer.c
new file mode 100644
index 0000000000..8cafdebf03
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/beatnik/marvell/gt_timer.c
@@ -0,0 +1,412 @@
+/* $Id$ */
+
+/* Driver for discovery timers and watchdog */
+
+/*
+ * Acknowledgements:
+ * Valuable information was obtained from the following drivers
+ * netbsd: (C) Allegro Networks Inc; Wasabi Systems Inc.
+ * linux: (C) MontaVista, Software, Inc; Mark A. Greer.
+ * rtems: (C) Brookhaven National Laboratory; K. Feng
+ * but this implementation is original work by the author.
+ */
+
+/*
+ * Authorship
+ * ----------
+ * This software ('beatnik' RTEMS BSP for MVME6100 and MVME5500) was
+ * created by Till Straumann <strauman@slac.stanford.edu>, 2005-2007,
+ * Stanford Linear Accelerator Center, Stanford University.
+ *
+ * Acknowledgement of sponsorship
+ * ------------------------------
+ * The 'beatnik' 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/gtreg.h>
+#include <libcpu/io.h>
+#include <bsp.h>
+#include <bsp/irq.h>
+#include <rtems/bspIo.h>
+
+#include <stdint.h>
+
+#include "gt_timer.h"
+
+#define DEBUG
+
+static inline uint32_t gt_rd(uint32_t off)
+{
+ return in_le32( (volatile unsigned *)(BSP_MV64x60_BASE+off) );
+}
+
+static inline void gt_wr(uint32_t off, uint32_t val)
+{
+ out_le32( (volatile unsigned *)(BSP_MV64x60_BASE+off), val);
+}
+
+static inline uint32_t gt_timer_bitmod(uint32_t off, uint32_t clr, uint32_t set)
+{
+ unsigned flags;
+ uint32_t rval;
+ rtems_interrupt_disable(flags);
+ rval = gt_rd( off );
+ gt_wr( off, (rval & ~clr) | set );
+ rtems_interrupt_enable(flags);
+ return rval;
+}
+
+#define GT_TIMER_MAX 3
+#define TIMER_ARGCHECK(t) do { if ((t)<0 || (t)>GT_TIMER_MAX) return -1; } while (0)
+
+static struct {
+ void (*isr)(void *);
+ void *arg;
+} gt_timer_isrs[GT_TIMER_MAX+1] = {{0},};
+
+uint32_t BSP_timer_read(uint32_t timer)
+{
+ TIMER_ARGCHECK(timer);
+ return gt_rd(GT_TIMER_0 + (timer<<2));
+}
+
+int
+BSP_timer_start(uint32_t timer, uint32_t period)
+{
+ TIMER_ARGCHECK(timer);
+ gt_wr(GT_TIMER_0 + (timer<<2), period);
+ return 0;
+}
+
+int
+BSP_timer_stop(uint32_t timer)
+{
+ TIMER_ARGCHECK(timer);
+ /* disable, clear period, re-enable */
+ gt_timer_bitmod(GT_TIMER_0_3_Ctl, GT_TIMER_0_Ctl_Enb << (timer<<3), 0);
+ gt_wr(GT_TIMER_0 + (timer<<2), 0);
+ gt_timer_bitmod(GT_TIMER_0_3_Ctl, 0, GT_TIMER_0_Ctl_Enb << (timer<<3));
+ return 0;
+}
+
+int
+BSP_timer_setup(uint32_t timer, void (*isr)(void *arg), void *arg, int reload)
+{
+ TIMER_ARGCHECK(timer);
+ if ( isr && gt_timer_isrs[timer].isr )
+ return -1;
+ BSP_timer_stop(timer);
+ /* mask and clear */
+ gt_timer_bitmod(GT_TIMER_0_3_Intr_Msk, GT_TIMER_0_Intr<<timer, 0);
+ gt_timer_bitmod(GT_TIMER_0_3_Intr_Cse, GT_TIMER_0_Intr<<timer, 0);
+
+ /* set reload bit */
+ if ( reload )
+ gt_timer_bitmod(GT_TIMER_0_3_Ctl, 0, GT_TIMER_0_Ctl_Rld << (timer<<3));
+ else
+ gt_timer_bitmod(GT_TIMER_0_3_Ctl, GT_TIMER_0_Ctl_Rld << (timer<<3), 0);
+
+ asm volatile("":::"memory");
+
+ if ( isr ) {
+ gt_timer_isrs[timer].isr = isr;
+ gt_timer_isrs[timer].arg = arg;
+ asm volatile("":::"memory");
+ gt_timer_bitmod(GT_TIMER_0_3_Intr_Msk, 0, GT_TIMER_0_Intr<<timer);
+ } else {
+ gt_timer_isrs[timer].isr = 0;
+ gt_timer_isrs[timer].arg = 0;
+ }
+ return 0;
+}
+
+static void
+gt_timer_hdl(rtems_irq_hdl_param arg)
+{
+int iarg = (int)arg;
+int timer;
+uint32_t bit;
+
+ for ( ; iarg; iarg >>= 4 ) {
+ timer = (iarg & 0xf)-1;
+ bit = GT_TIMER_0_Intr<<timer;
+ if ( gt_timer_bitmod(GT_TIMER_0_3_Intr_Cse, bit, 0) & bit ) {
+ /* cause was set */
+ if ( ! gt_timer_isrs[timer].isr ) {
+ printk("gt_timer: warning; no ISR connected but and IRQ happened (timer # %i)\n", timer);
+ /* mask */
+ gt_timer_bitmod(GT_TIMER_0_3_Intr_Msk, bit, 0);
+ } else {
+ gt_timer_isrs[timer].isr(gt_timer_isrs[timer].arg);
+ }
+ }
+ }
+}
+
+int
+BSP_timers_initialize(void)
+{
+rtems_irq_connect_data xx = {0};
+int i, ainc, arg;
+
+ xx.hdl = gt_timer_hdl;
+ xx.on = 0;
+ xx.off = 0;
+ xx.isOn = 0;
+
+ switch (BSP_getDiscoveryVersion(0)) {
+ case MV_64360:
+ i = 3;
+ ainc = 1;
+ arg = 4;
+ break;
+ default:
+ i = 1;
+ ainc = 0x0202;
+ arg = 0x0403;
+ break;
+ }
+
+ for ( ; i>=0; i--, arg-=ainc ) {
+ xx.name = BSP_IRQ_TIME0_1 + i;
+ xx.handle = (rtems_irq_hdl_param)arg;
+ if ( !BSP_install_rtems_irq_handler(&xx) )
+ return -1;
+ }
+
+ return 0;
+}
+
+int
+BSP_timers_uninstall(void)
+{
+rtems_irq_connect_data xx = {0};
+int i;
+
+ xx.hdl = gt_timer_hdl;
+ xx.on = 0;
+ xx.off = 0;
+ xx.isOn = 0;
+
+ for ( i=0; i<= GT_TIMER_MAX; i++ ) {
+ if ( BSP_timer_setup(i, 0, 0, 0) )
+ return -1;
+ }
+
+ switch (BSP_getDiscoveryVersion(0)) {
+ case MV_64360:
+ i = 3;
+ break;
+ default:
+ i = 1;
+ break;
+ }
+
+ for ( ; i >= 0; i-- ) {
+ xx.name = BSP_IRQ_TIME0_1 + i;
+ BSP_get_current_rtems_irq_handler(&xx);
+ if ( !BSP_remove_rtems_irq_handler(&xx) )
+ return -1;
+ }
+
+ return 0;
+}
+
+uint32_t
+BSP_timer_clock_get(uint32_t timer)
+{
+ return BSP_bus_frequency;
+}
+
+int BSP_timer_instances(void)
+{
+ return GT_TIMER_MAX + 1;
+}
+
+#ifdef DEBUG
+void BSP_timer_test_isr(void *arg)
+{
+ printk("TIMER IRQ (user arg 0x%x)\n",arg);
+}
+#endif
+
+/* On a 64260A we can't read the status (on/off), apparently
+ * so we maintain it locally and assume the firmware has
+ * not enabled the dog initially...
+ */
+static uint32_t wdog_on = 0x00ffffff;
+
+static uint32_t rd_wdcnf(void)
+{
+ uint32_t cnf = gt_rd(GT_WDOG_Config);
+ /* BSD driver says that on the 64260A we always
+ * read 0xffffffff so we have to maintain the
+ * status locally (and hope we get the initial
+ * value right).
+ */
+ if ( ~0 == cnf )
+ cnf = wdog_on;
+ return cnf;
+}
+
+/* change on/off state assume caller has IRQs disabled */
+static void dog_toggle(uint32_t ctl)
+{
+ ctl &= ~( GT_WDOG_Config_Ctl1a | GT_WDOG_Config_Ctl1b \
+ | GT_WDOG_Config_Ctl2a | GT_WDOG_Config_Ctl2b);
+ gt_wr(GT_WDOG_Config, ctl | GT_WDOG_Config_Ctl1a);
+ gt_wr(GT_WDOG_Config, ctl | GT_WDOG_Config_Ctl1b);
+}
+
+static void dog_pet(uint32_t ctl)
+{
+ ctl &= ~( GT_WDOG_Config_Ctl1a | GT_WDOG_Config_Ctl1b \
+ | GT_WDOG_Config_Ctl2a | GT_WDOG_Config_Ctl2b);
+ gt_wr(GT_WDOG_Config, ctl | GT_WDOG_Config_Ctl2a);
+ gt_wr(GT_WDOG_Config, ctl | GT_WDOG_Config_Ctl2b);
+}
+
+
+/* Enable watchdog and set a timeout (in us)
+ * a timeout of 0xffffffff selects the old/existing
+ * timeout.
+ *
+ * RETURNS 0 on success
+ */
+int
+BSP_watchdog_enable(uint32_t timeout_us)
+{
+unsigned long long x = timeout_us;
+unsigned flags;
+uint32_t ctl;
+
+ x *= BSP_bus_frequency;
+ x /= 256; /* there seems to be a prescaler */
+ x /= 1000000; /* us/s */
+
+ if ( x > (1<<24)-1 )
+ x = (1<<24)-1;
+
+ if ( 0xffffffff != timeout_us )
+ timeout_us = x;
+
+ rtems_interrupt_disable(flags);
+
+ ctl = rd_wdcnf();
+
+ /* if enabled, disable first */
+ if ( GT_WDOG_Config_Enb & ctl ) {
+ dog_toggle(ctl);
+ }
+ if ( 0xffffffff == timeout_us ) {
+ timeout_us = ctl & ((1<<24)-1);
+ dog_toggle(ctl);
+ dog_pet(ctl);
+ } else {
+ gt_wr(GT_WDOG_Config, timeout_us | GT_WDOG_Config_Ctl1a);
+ gt_wr(GT_WDOG_Config, timeout_us | GT_WDOG_Config_Ctl1b);
+ }
+
+ wdog_on = GT_WDOG_Config_Enb | timeout_us;
+
+ rtems_interrupt_enable(flags);
+ return 0;
+}
+
+/* Disable watchdog
+ * RETURNS 0 on success
+ */
+int BSP_watchdog_disable(void)
+{
+unsigned long flags;
+uint32_t ctl;
+
+ rtems_interrupt_disable(flags);
+
+ ctl = rd_wdcnf();
+
+ if ( (GT_WDOG_Config_Enb & ctl) ) {
+ dog_toggle(ctl);
+ wdog_on = ctl & ~(GT_WDOG_Config_Enb);
+ }
+
+ rtems_interrupt_enable(flags);
+ return 0;
+}
+
+/* Check status -- unfortunately there seems to be no way
+ * to read the running value...
+ *
+ * RETURNS nonzero if enabled/running, zero if disabled/stopped
+ */
+int BSP_watchdog_status(void)
+{
+uint32_t ctl = rd_wdcnf();
+
+ /* report also the current period */
+ return GT_WDOG_Config_Enb & ctl ? ctl : 0;
+}
+
+/* Pet the watchdog (rearm to configured timeout)
+ * RETURNS: 0 on success, nonzero on failure (watchdog
+ * currently not running).
+ */
+int BSP_watchdog_pet(void)
+{
+unsigned long flags;
+ if ( !wdog_on )
+ return -1;
+ rtems_interrupt_disable(flags);
+ dog_pet(rd_wdcnf());
+ rtems_interrupt_enable(flags);
+ return 0;
+}
+
+
+#ifdef DEBUG_MODULAR
+int
+_cexpModuleFinalize(void *unused)
+{
+ BSP_watchdog_disable();
+ return BSP_timers_uninstall();
+}
+
+void
+_cexpModuleInitialize(void *unused)
+{
+ BSP_timers_initialize();
+}
+#endif
diff --git a/c/src/lib/libbsp/powerpc/beatnik/marvell/gt_timer.h b/c/src/lib/libbsp/powerpc/beatnik/marvell/gt_timer.h
new file mode 100644
index 0000000000..f1a83d6bc1
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/beatnik/marvell/gt_timer.h
@@ -0,0 +1,134 @@
+#ifndef BSP_GT_TIMER_H
+#define BSP_GT_TIMER_H
+/* $Id$ */
+
+/* Support for hardware timers in the discovery bridge */
+
+/*
+ * Authorship
+ * ----------
+ * This software ('beatnik' RTEMS BSP for MVME6100 and MVME5500) was
+ * created by Till Straumann <strauman@slac.stanford.edu>, 2005-2007,
+ * Stanford Linear Accelerator Center, Stanford University.
+ *
+ * Acknowledgement of sponsorship
+ * ------------------------------
+ * The 'beatnik' 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 <stdint.h>
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/* Obtain the number of hardware timers present
+ * The 'timer' argument in the routines below addresses
+ * one of 0..(BSP_timer_instances()-1)
+ */
+int BSP_timer_instances(void);
+
+/* Setup timer but don't start yet; interrupts are enabled if an isr argument is passed
+ * no interrupts are generated otherwise.
+ *
+ * If 'reload' is nonzero then the period is automatically restarted.
+ *
+ * RETURNS: 0 on success, nonzero on error (argument error)
+ *
+ * NOTE: If an ISR is already connected, it must be removed by passing a NULL isr first.
+ */
+int BSP_timer_setup(uint32_t timer, void (*isr)(void *arg), void *arg, int reload);
+
+/* Stop timer;
+ *
+ * RETURNS: 0 on success, nonzero on argument error
+ */
+int BSP_timer_stop(uint32_t timer);
+
+/* Start timer with 'period' (in ticks)
+ *
+ * RETURNS: 0 on success, nonzero on argument error
+ */
+int BSP_timer_start(uint32_t timer, uint32_t period);
+
+/* read decrementing timer on the fly
+ *
+ * RETURNS: current count in ticks
+ */
+uint32_t BSP_timer_read(uint32_t timer);
+
+/* get clock rate in Hz */
+uint32_t BSP_timer_clock_get(uint32_t timer);
+
+/* Initialize timer facility -- to be used by BSP implementors only
+ *
+ * RETURNS: 0 on success, nonzero if ISR wrapper couldn't be installed
+ */
+int BSP_timers_initialize(void);
+
+/* WATCHDOG TIMER (resets board if enabled and not 'petted' for
+ * some time).
+ */
+
+/* Enable watchdog and set a timeout (in us)
+ * RETURNS 0 on success
+ */
+int BSP_watchdog_enable(uint32_t timeout_us);
+
+/* Disable watchdog
+ * RETURNS 0 on success
+ */
+int BSP_watchdog_disable(void);
+
+/* Check status -- unfortunately there seems to be no way
+ * to read the running value...
+ *
+ * RETURNS nonzero if enabled/running, zero if disabled/stopped
+ */
+int BSP_watchdog_status(void);
+
+/* Pet the watchdog (rearm to configured timeout)
+ * RETURNS: 0 on success, nonzero on failure (watchdog
+ * currently not running).
+ */
+int BSP_watchdog_pet(void);
+
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif
diff --git a/c/src/lib/libbsp/powerpc/beatnik/marvell/gti2c.c b/c/src/lib/libbsp/powerpc/beatnik/marvell/gti2c.c
new file mode 100644
index 0000000000..2cc67f3258
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/beatnik/marvell/gti2c.c
@@ -0,0 +1,447 @@
+/* $NetBSD: gti2c.c,v 1.2 2005/02/27 00:27:21 perry Exp $ */
+
+/*
+ * Copyright (c) 2005 Brocade Communcations, inc.
+ * All rights reserved.
+ *
+ * Written by Matt Thomas for Brocade Communcations, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of Brocade Communications, Inc. may not be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY BROCADE COMMUNICATIONS, INC. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL EITHER BROCADE COMMUNICATIONS, INC. BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* Fixed many things + ported to RTEMS by Till Straumann, 2005 */
+
+#include <stdio.h>
+#include <rtems.h>
+#include <libcpu/io.h>
+#include <sys/errno.h>
+#include <rtems/bspIo.h>
+#include <rtems/score/sysstate.h>
+#include <bsp/irq.h>
+#include <rtems/libi2c.h>
+
+#include <sys/cdefs.h>
+
+#include <bsp/gtintrreg.h>
+#include <bsp/gti2creg.h>
+#include <bsp/gti2c_busdrv.h>
+
+#define ENABLE_IRQ_AT_PIC_HACK /* workaround for a bad HW bug */
+#undef DEBUG
+
+#ifndef BSP_IRQ_MIN_PRIO
+#define BSP_IRQ_MIN_PRIO 1
+#endif
+
+struct gti2c_softc {
+ uint32_t sc_gt;
+ uint32_t sc_cntl;
+ int sc_inited;
+ rtems_id sc_sync;
+ int sc_irqs; /* statistics */
+};
+
+#ifdef DEBUG
+#define STATIC
+#else
+#define STATIC static
+#endif
+
+typedef struct {
+ rtems_libi2c_bus_t bus_desc;
+ struct gti2c_softc pvt;
+} gti2c_desc_rec, *gti2c_desc;
+
+STATIC rtems_status_code
+gt_i2c_init(rtems_libi2c_bus_t *bh);
+STATIC rtems_status_code
+gt_i2c_send_start(rtems_libi2c_bus_t *bh);
+STATIC rtems_status_code
+gt_i2c_send_stop(rtems_libi2c_bus_t *bh);
+STATIC rtems_status_code
+gt_i2c_send_addr(rtems_libi2c_bus_t *bh, uint32_t addr, int rw);
+STATIC int
+gt_i2c_read_bytes(rtems_libi2c_bus_t *bh, unsigned char *buf, int len);
+STATIC int
+gt_i2c_write_bytes(rtems_libi2c_bus_t *bh, unsigned char *buf, int len);
+
+static rtems_libi2c_bus_ops_t myops = {
+ init: gt_i2c_init,
+ send_start: gt_i2c_send_start,
+ send_stop: gt_i2c_send_stop,
+ send_addr: gt_i2c_send_addr,
+ read_bytes: gt_i2c_read_bytes,
+ write_bytes: gt_i2c_write_bytes,
+};
+
+static gti2c_desc_rec my_bus_tbl = {
+ {
+ ops: &myops,
+ size: sizeof(my_bus_tbl),
+ },/* public fields */
+ {
+ sc_gt: BSP_MV64x60_BASE,
+ sc_cntl: I2C_Control_TWSIEn,
+ sc_inited: 0,
+ sc_sync: 0
+ } /* our private fields */
+};
+
+
+static inline uint32_t
+gt_read(uint32_t base, uint32_t off)
+{
+ return in_le32((volatile unsigned*)(base+off));
+}
+
+static inline void
+gt_write(uint32_t base, uint32_t off, uint32_t val)
+{
+ out_le32((volatile unsigned*)(base+off), val);
+}
+
+
+static inline void
+disable_irq(struct gti2c_softc *sc)
+{
+uint32_t v = gt_read(sc->sc_gt, I2C_REG_Control);
+ gt_write(sc->sc_gt, I2C_REG_Control, v & ~I2C_Control_IntEn);
+}
+
+
+static rtems_status_code
+gt_i2c_wait(struct gti2c_softc *sc, uint32_t control, uint32_t desired_status)
+{
+ uint32_t status;
+ rtems_status_code rval;
+
+ control |= I2C_Control_IntEn;
+
+ gt_write(sc->sc_gt, I2C_REG_Control, control | sc->sc_cntl);
+
+ if ( sc->sc_inited ) {
+
+#ifdef ENABLE_IRQ_AT_PIC_HACK
+ BSP_enable_irq_at_pic(BSP_IRQ_I2C);
+#endif
+
+ rval = rtems_semaphore_obtain(sc->sc_sync, RTEMS_WAIT, 100);
+
+ if ( RTEMS_SUCCESSFUL != rval )
+ return rval;
+ } else {
+ uint32_t then, now;
+
+ /* run in polling mode - useful during init */
+ if ( _System_state_Is_up(_System_state_Get()) ) {
+ printk("WARNING: gti2c running in polled mode -- should initialize properly!\n");
+ }
+
+ asm volatile("mftb %0":"=r"(then));
+
+ do {
+ asm volatile("mftb %0":"=r"(now));
+ /* poll timebase for .2 seconds assuming a bus clock of 100MHz */
+ if ( now - then > (uint32_t)100000000/4/5 )
+ return RTEMS_TIMEOUT;
+ } while ( ! (I2C_Control_IFlg & gt_read(sc->sc_gt, I2C_REG_Control)) );
+ }
+
+ status = gt_read(sc->sc_gt, I2C_REG_Status);
+
+ if ( status != desired_status && (status!=I2C_Status_ReStarted || desired_status!=I2C_Status_Started) )
+ return RTEMS_IO_ERROR;
+
+ return RTEMS_SUCCESSFUL;
+}
+
+static void
+gt_i2c_intr(void *arg)
+{
+struct gti2c_softc * const sc = &my_bus_tbl.pvt;
+ uint32_t v;
+
+ v = gt_read(sc->sc_gt, I2C_REG_Control);
+ if ((v & I2C_Control_IFlg) == 0) {
+ printk("gt_i2c_intr: IRQ but IFlg not set??\n");
+ return;
+ }
+ gt_write(sc->sc_gt, I2C_REG_Control, v & ~(I2C_Control_IntEn));
+#if 0
+ gt_read(sc->sc_gt, I2C_REG_Control);
+ asm volatile("sync");
+/* This is how bad it is: after turning off the IntEn bit, the line
+ * still remains asserted! (shame on you.)
+ *
+ * The test below (on MVME6100; the MVME5500 has the same problem
+ * but the main cause register address is different; substitute
+ * 0xf100000c for 0xf1000c68 on a 5500).
+ *
+ * The skew was 101 TB ticks or ~3us (bus freq 133MHz) which
+ * really sucks.
+ *
+ * Therefore, we must disable the interrupt at the PIC
+ */
+{unsigned from,to;
+ asm volatile("mftb %0":"=r"(from));
+ while ( in_le32((volatile unsigned*)0xf100000c) & 0x20 )
+ ;
+ asm volatile("mftb %0":"=r"(to));
+ printk("I2C IRQ remained asserted for %i TB ticks!\n",to-from);
+}
+#endif
+#ifdef ENABLE_IRQ_AT_PIC_HACK
+ BSP_disable_irq_at_pic(BSP_IRQ_I2C);
+#endif
+
+ sc->sc_irqs++;
+
+ rtems_semaphore_release(sc->sc_sync);
+}
+
+STATIC rtems_status_code
+gt_i2c_init(rtems_libi2c_bus_t *bh)
+{
+struct gti2c_softc * const sc = &((gti2c_desc)bh)->pvt;
+unsigned m,n,N;
+
+ disable_irq(sc);
+
+ /* reset */
+ gt_write(sc->sc_gt, I2C_REG_SoftReset, 0);
+ gt_write(sc->sc_gt, I2C_REG_SlaveAddr, 0);
+ gt_write(sc->sc_gt, I2C_REG_ExtSlaveAddr, 0);
+
+ /* Set baud rate; I don't know the details
+ * but have to assume that it has to fit into 7 bits
+ * (as indicated by some experiment)
+ */
+ n = 0, N=1<<n;
+ do {
+ n++, N<<=1;
+ /* increase 2^n until m becomes small enough */
+ m = BSP_bus_frequency / 10 / 62500 / N;
+ } while ( m > 16 );
+
+ /* n is at least 1 */
+ if ( n > 8 ) {
+ n = 8; m = 16; /* nothing else we can do */
+ }
+ if ( 0 == m )
+ m = 1; /* nothing we can do */
+
+ gt_write(sc->sc_gt, I2C_REG_BaudRate, I2C_BaudRate(m-1, n-1));
+
+ if ( !sc->sc_inited ) {
+
+ if ( _System_state_Is_up(_System_state_Get()) ) {
+ rtems_irq_connect_data ii = {
+ name: BSP_IRQ_I2C,
+ hdl: gt_i2c_intr,
+ on: 0,
+ off: 0,
+ isOn: 0
+ };
+ rtems_status_code err;
+ /* synchronization semaphore */
+ err = rtems_semaphore_create(
+ rtems_build_name('g','i','2','c'),
+ 0,
+ RTEMS_SIMPLE_BINARY_SEMAPHORE | RTEMS_LOCAL,
+ 0,
+ &sc->sc_sync);
+ if ( err ) {
+ sc->sc_sync = 0;
+ return err;
+ }
+ if ( !BSP_install_rtems_irq_handler(&ii) ) {
+ fprintf(stderr,"Unable to install interrupt handler\n");
+ rtems_semaphore_delete(sc->sc_sync);
+ return RTEMS_INTERNAL_ERROR;
+ }
+ BSP_irq_set_priority(BSP_IRQ_I2C, BSP_IRQ_MIN_PRIO);
+ sc->sc_inited = 1;
+ } else {
+ }
+ } else {
+ rtems_semaphore_flush(sc->sc_sync);
+ }
+ return RTEMS_SUCCESSFUL;
+}
+
+STATIC rtems_status_code
+gt_i2c_send_start(rtems_libi2c_bus_t *bh)
+{
+struct gti2c_softc * const sc = &((gti2c_desc)bh)->pvt;
+
+ return gt_i2c_wait(sc, I2C_Control_Start, I2C_Status_Started);
+}
+
+STATIC rtems_status_code
+gt_i2c_send_stop(rtems_libi2c_bus_t *bh)
+{
+struct gti2c_softc * const sc = &((gti2c_desc)bh)->pvt;
+uint32_t data;
+
+ data = gt_read(sc->sc_gt, I2C_REG_Status);
+ if ( I2C_Status_Started == data || I2C_Status_ReStarted == data ) {
+ /* According to the spec, a void message (start - stop sequence)
+ * is illegal and indeed, the chip plays bad tricks with us, i.e.,
+ * sometimes it hangs the bus so that it remains idle forever.
+ * so we have to address someone...
+ */
+ gt_i2c_send_addr(bh, /*just something... */ 8, 1);
+ data = gt_read(sc->sc_gt, I2C_REG_Status);
+ }
+
+ if ( I2C_Status_AddrReadAck == data ) {
+ /* Another thing: spec says that the master generates stop only after
+ * not acknowledging the last byte. Again, the chip doesn't like
+ * to be stopped in this condition - hence we just do it the favor
+ * and read a single byte...
+ */
+ gt_i2c_read_bytes(bh, (unsigned char *)&data, 1);
+ }
+
+ gt_write(sc->sc_gt, I2C_REG_Control, I2C_Control_Stop | sc->sc_cntl);
+
+ /* should we poll for idle? There seems to be in IRQ when this completes */
+ return RTEMS_SUCCESSFUL;
+}
+
+STATIC rtems_status_code
+gt_i2c_send_addr(rtems_libi2c_bus_t *bh, uint32_t addr, int rw)
+{
+struct gti2c_softc * const sc = &((gti2c_desc)bh)->pvt;
+uint32_t data, wanted_status;
+uint8_t read_mask = rw ? 1 : 0;
+rtems_status_code error;
+
+ if (read_mask) {
+ wanted_status = I2C_Status_AddrReadAck;
+ } else {
+ wanted_status = I2C_Status_AddrWriteAck;
+ }
+ /*
+ * First byte contains whether this xfer is a read or write.
+ */
+ data = read_mask;
+ if (addr > 0x7f) {
+ /*
+ * If this is a 10bit request, the first address byte is
+ * 0b11110<b9><b8><r/w>.
+ */
+ data |= 0xf0 | ((addr & 0x300) >> 7);
+ gt_write(sc->sc_gt, I2C_REG_Data, data);
+ error = gt_i2c_wait(sc, 0, wanted_status);
+ if (error)
+ return error;
+ /*
+ * The first address byte has been sent, now to send
+ * the second one.
+ */
+ if (read_mask) {
+ wanted_status = I2C_Status_2ndAddrReadAck;
+ } else {
+ wanted_status = I2C_Status_2ndAddrWriteAck;
+ }
+ data = (uint8_t) addr;
+ } else {
+ data |= (addr << 1);
+ }
+
+ gt_write(sc->sc_gt, I2C_REG_Data, data);
+ return gt_i2c_wait(sc, 0, wanted_status);
+}
+
+STATIC int
+gt_i2c_read_bytes(rtems_libi2c_bus_t *bh, unsigned char *buf, int len)
+{
+struct gti2c_softc * const sc = &((gti2c_desc)bh)->pvt;
+rtems_status_code error;
+register unsigned char *p=buf;
+
+ while ( len-- > 0 ) {
+ error = gt_i2c_wait(
+ sc,
+ len ? I2C_Control_ACK : 0,
+ len ? I2C_Status_MasterReadAck : I2C_Status_MasterReadNoAck);
+ if ( error ) {
+ return -error;
+ }
+ *p++ = gt_read(sc->sc_gt, I2C_REG_Data);
+ }
+
+ return p-buf;
+}
+
+STATIC int
+gt_i2c_write_bytes(rtems_libi2c_bus_t *bh, unsigned char *buf, int len)
+{
+struct gti2c_softc * const sc = &((gti2c_desc)bh)->pvt;
+int rval = 0;
+rtems_status_code error;
+
+ while ( len-- > 0 ) {
+ gt_write(sc->sc_gt, I2C_REG_Data, buf[rval]);
+ error = gt_i2c_wait(sc, 0, I2C_Status_MasterWriteAck);
+ if ( error ) {
+ return -error;
+ }
+ rval++;
+ }
+
+ return rval;
+}
+
+rtems_libi2c_bus_t *gt64260_i2c_bus_descriptor = &my_bus_tbl.bus_desc;
+
+#ifdef DEBUG_MODULAR
+
+void
+_cexpModuleInitialize(void *arg)
+{
+ gt_i2c_init(&gt64260_i2c_bus_descriptor->bus_desc);
+}
+
+int
+_cexpModuleFinalize(void * arg)
+{
+struct gti2c_softc * const sc = &gt64260_i2c_bus_descriptor->pvt;
+
+ rtems_irq_connect_data ii = {
+ name: BSP_IRQ_I2C,
+ hdl: gt_i2c_intr,
+ on: noop,
+ off: noop,
+ isOn: inoop
+ };
+
+ rtems_semaphore_delete(sc->sc_sync);
+
+ return !BSP_remove_rtems_irq_handler(&ii);
+}
+
+#endif
diff --git a/c/src/lib/libbsp/powerpc/beatnik/marvell/gti2c_busdrv.h b/c/src/lib/libbsp/powerpc/beatnik/marvell/gti2c_busdrv.h
new file mode 100644
index 0000000000..b75e16cdf8
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/beatnik/marvell/gti2c_busdrv.h
@@ -0,0 +1,62 @@
+#ifndef GT_64260_BUS_DRIVER_H
+#define GT_64260_BUS_DRIVER_H
+/*
+ * Authorship
+ * ----------
+ * This software ('beatnik' RTEMS BSP for MVME6100 and MVME5500) was
+ * created by Till Straumann <strauman@slac.stanford.edu>, 2005-2007,
+ * Stanford Linear Accelerator Center, Stanford University.
+ *
+ * Acknowledgement of sponsorship
+ * ------------------------------
+ * The 'beatnik' 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 *gt64260_i2c_bus_descriptor;
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif
diff --git a/c/src/lib/libbsp/powerpc/beatnik/marvell/gti2creg.h b/c/src/lib/libbsp/powerpc/beatnik/marvell/gti2creg.h
new file mode 100644
index 0000000000..33e566f5bc
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/beatnik/marvell/gti2creg.h
@@ -0,0 +1,83 @@
+/* $NetBSD: gti2creg.h,v 1.2 2005/02/27 00:27:21 perry Exp $ */
+
+/*
+ * Copyright (c) 2005 Brocade Communcations, inc.
+ * All rights reserved.
+ *
+ * Written by Matt Thomas for Brocade Communcations, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of Brocade Communications, Inc. may not be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY BROCADE COMMUNICATIONS, INC. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL EITHER BROCADE COMMUNICATIONS, INC. BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _DEV_MARVELL_GTI2CREG_H_
+#define _DEV_MARVELL_GTI2CREG_H_
+
+#define I2C_REG_SlaveAddr 0xc000
+#define I2C_REG_ExtSlaveAddr 0xc010
+#define I2C_REG_Data 0xc004
+#define I2C_REG_Control 0xc008
+#define I2C_REG_Status 0xc00c
+#define I2C_REG_BaudRate 0xc00c
+#define I2C_REG_SoftReset 0xc01c
+
+#define I2C_SlaveAddr_GCE 0x0001 /* Act as Slave */
+#define I2C_SlaveAddr_SAddr 0x7E
+
+#define I2C_Control_ACK 0x04
+#define I2C_Control_IFlg 0x08
+#define I2C_Control_Stop 0x10
+#define I2C_Control_Start 0x20
+#define I2C_Control_TWSIEn 0x40
+#define I2C_Control_IntEn 0x80
+
+/*
+ * F(I2C) = F(Tclk) / ( 10 * (M + 1) * (2^(N+1)))
+ * For Tclk = 100MHz, M = 4, N = 4: F = 62.5KHz
+ * For Tclk = 100MHz, M = 13, N = 3: F = 96.2KHz
+ */
+#define I2C_BaudRate(M, N) (((M) << 3) | (N))
+#define I2C_BaudRate_62_5K I2C_BaudRate(4, 4)
+#define I2C_BaudRate_96_2K I2C_BaudRate(13, 3)
+
+#define I2C_Status_BusError 0x00 /* Bus error */
+#define I2C_Status_Started 0x08 /* Start condition xmitted */
+#define I2C_Status_ReStarted 0x10 /* Repeated start condition xmitted */
+#define I2C_Status_AddrWriteAck 0x18 /* Adr + wr bit xmtd, ack rcvd */
+#define I2C_Status_AddrWriteNoAck 0x20 /* Adr + wr bit xmtd, NO ack rcvd */
+#define I2C_Status_MasterWriteAck 0x28 /* Master xmtd data byte, ack rcvd */
+#define I2C_Status_MasterWriteNoAck 0x30 /* Master xmtd data byte, NO ack rcvd*/
+#define I2C_Status_MasterLostArb 0x38 /* Master lost arbitration during
+ address or data transfer */
+#define I2C_Status_AddrReadAck 0x40 /* Adr + rd bit xmtd, ack rcvd */
+#define I2C_Status_AddrReadNoAck 0x48 /* Adr + rd bit xmtd, NO ack rcvd */
+#define I2C_Status_MasterReadAck 0x50 /* Master rcvd data bye, ack rcvd */
+#define I2C_Status_MasterReadNoAck 0x58 /* Master rcvd data bye, NO ack rcvd */
+#define I2C_Status_2ndAddrWriteAck 0xd0 /* 2nd adr + wr bit xmid, ack rcvd */
+#define I2C_Status_2ndAddrWriteNoAck 0xd8 /* 2nd adr + wr bit xmid, NO ack rcvd */
+#define I2C_Status_2ndAddrReadAck 0xe0 /* 2nd adr + rd bit xmid, ack rcvd */
+#define I2C_Status_2ndAddrReadNoAck 0xe8 /* 2nd adr + rd bit xmtd, NO ack rcvd */
+#define I2C_Status_Idle 0xf8 /* Idle */
+
+#endif /* _DEV_MARVELL_GTI2CREG_H_ */
diff --git a/c/src/lib/libbsp/powerpc/beatnik/marvell/gtintrreg.h b/c/src/lib/libbsp/powerpc/beatnik/marvell/gtintrreg.h
new file mode 100644
index 0000000000..bd3f69514e
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/beatnik/marvell/gtintrreg.h
@@ -0,0 +1,257 @@
+/* $NetBSD: gtintrreg.h,v 1.3 2005/02/27 00:27:21 perry Exp $ */
+
+/*
+ * Copyright (c) 2002 Allegro Networks, Inc., Wasabi Systems, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed for the NetBSD Project by
+ * Allegro Networks, Inc., and Wasabi Systems, Inc.
+ * 4. The name of Allegro Networks, Inc. may not be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ * 5. The name of Wasabi Systems, Inc. may not be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ALLEGRO NETWORKS, INC. AND
+ * WASABI SYSTEMS, INC. ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL EITHER ALLEGRO NETWORKS, INC. OR WASABI SYSTEMS, INC.
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * gt64260intr.h: defines for GT-64260 system controller interrupts
+ *
+ * creation Sun Jan 7 18:05:59 PST 2001 cliff
+ *
+ * NOTE:
+ * Galileo GT-64260 manual bit defines assume Little Endian
+ * ordering of bits within bytes, i.e.
+ * bit #0 --> 0x01
+ * vs. Motorola Big Endian bit numbering where
+ * bit #0 --> 0x80
+ * Consequently we define bits in Little Endian format and plan
+ * to swizzle bytes during programmed I/O by using lwbrx/swbrx
+ * to load/store GT-64260 registers.
+ */
+
+
+#ifndef _DISCOVERY_GT64260INTR_H
+#define _DISCOVERY_GT64260INTR_H
+
+#define BIT(n) (1<<(n))
+
+
+/*
+ * GT-64260 Interrupt Controller Register Map
+ */
+#define ICR_260_MIC_LO 0xc18 /* main interrupt cause low */
+#define ICR_260_MIC_HI 0xc68 /* main interrupt cause high */
+#define ICR_260_CIM_LO 0xc1c /* CPU interrupt mask low */
+#define ICR_260_CIM_HI 0xc6c /* CPU interrupt mask high */
+#define ICR_260_CSC 0xc70 /* CPU select cause */
+#define ICR_260_P0IM_LO 0xc24 /* PCI_0 interrupt mask low */
+#define ICR_260_P0IM_HI 0xc64 /* PCI_0 interrupt mask high */
+#define ICR_260_P0SC 0xc74 /* PCI_0 select cause */
+#define ICR_260_P1IM_LO 0xca4 /* PCI_1 interrupt mask low */
+#define ICR_260_P1IM_HI 0xce4 /* PCI_1 interrupt mask high */
+#define ICR_260_P1SC 0xcf4 /* PCI_1 select cause */
+#define ICR_260_CI0M 0xe60 /* CPU int[0] mask */
+#define ICR_260_CI1M 0xe64 /* CPU int[1] mask */
+#define ICR_260_CI2M 0xe68 /* CPU int[2] mask */
+#define ICR_260_CI3M 0xe6c /* CPU int[3] mask */
+
+/*
+ * MV64360 Interrupt Controller Register Map
+ */
+#define ICR_360_MIC_LO 0x004 /* main interrupt cause low */
+#define ICR_360_MIC_HI 0x00c /* main interrupt cause high */
+#define ICR_360_C0IM_LO 0x014 /* CPU 0 interrupt mask low */
+#define ICR_360_C0IM_HI 0x01c /* CPU 0 interrupt mask high */
+#define ICR_360_C0SC 0x024 /* CPU 0 select cause */
+#define ICR_360_C1IM_LO 0x034 /* CPU 1 interrupt mask low */
+#define ICR_360_C1IM_HI 0x03c /* CPU 1 interrupt mask high */
+#define ICR_360_C1SC 0x044 /* CPU 1 select cause */
+#define ICR_360_I0M_LO 0x014 /* Int 0 mask low */
+#define ICR_360_I0M_HI 0x01c /* Int 0 mask high */
+#define ICR_360_I0SC 0x024 /* Int 0 select cause */
+#define ICR_360_I1M_LO 0x034 /* Int 1 mask low */
+#define ICR_360_I1M_HI 0x03c /* Int 1 mask high */
+#define ICR_360_C1SC 0x044 /* Int 1 select cause */
+
+
+/*
+ * IRQs:
+ * we define IRQs based on bit number in the
+ * ICU_LEN dimensioned hardware portion of the imask_t bit vector
+ * which consists of 64 bits of Main Cause and Mask register pairs
+ * (ICR_MIC_LO, ICR_MIC_HI and ICR_CIM_LO, ICR_CIM_HI)
+ * as well as 32 bits in GPP registers (see intr.h):
+ *
+ * IRQs:
+ * 31.............................0 63.............................32
+ * | | |
+ * imask_t index: | | |
+ * | | | |
+ * ^--------- IM_PIC_LO ----------^ ^------ IM_PIC_HI ------------^
+ * | | |
+ * Bitmasks: | | |
+ * | | | |
+ * ^--------- IML_* --------------^ ^------ IMH_* ----------------^
+ * | | |
+ * Registers: | | |
+ * | | | |
+ * ^--------- ICR_MIC_LO ---------^ ^------ ICR_MIC_HI -----------^
+ * ^--------- ICR_CIM_LO ---------^ ^------ ICR_CIM_HI -----------^
+ *
+ * IRQs:
+ * 95............................64 127............................96
+ * | | |
+ * imask_t index: | | |
+ * | | | |
+ * ^-------- IMASK_GPP ----------^ ^----- IMASK_SOFTINT --------^
+ * | | |
+ * Bitmasks: | | |
+ * | | | |
+ * ^--------- GPP_* --------------^ ^------ SIBIT(irq) -----------^
+ * | | |
+ * Registers: | | |
+ * | | | |
+ * ^--- GT_GPP_Interrupt_Cause ---^ ^------- (none) -----------^
+ * ^--- GT_GPP_Interrupt_Mask ---^
+ *
+ *
+ * Note that GPP interrupts are summarized in the Main Cause Register.
+ *
+ * Some IRQs are "resvered" undefined due to gaps in HW register utilization.
+ */
+#define IRQ_DEV 1 /* device interface interrupt */
+#define IRQ_DMA 2 /* DMA addres error interrupt */
+#define IRQ_CPU 3 /* CPU interface interrupt */
+#define IRQ_IDMA0_1 4 /* IDMA ch. 0..1 complete interrupt */
+#define IRQ_IDMA2_3 5 /* IDMA ch. 2..3 complete interrupt */
+#define IRQ_IDMA4_5 6 /* IDMA ch. 4..5 complete interrupt */
+#define IRQ_IDMA6_7 7 /* IDMA ch. 6..7 complete interrupt */
+#define IRQ_TIME0_1 8 /* Timer 0..1 interrupt */
+#define IRQ_TIME2_3 9 /* Timer 2..3 interrupt */
+#define IRQ_TIME4_5 10 /* Timer 4..5 interrupt */
+#define IRQ_TIME6_7 11 /* Timer 6..7 interrupt */
+#define IRQ_PCI0_0 12 /* PCI 0 interrupt 0 summary */
+#define IRQ_PCI0_1 13 /* PCI 0 interrupt 1 summary */
+#define IRQ_PCI0_2 14 /* PCI 0 interrupt 2 summary */
+#define IRQ_PCI0_3 15 /* PCI 0 interrupt 3 summary */
+#define IRQ_PCI1_0 16 /* PCI 1 interrupt 0 summary */
+#define IRQ_ECC 17 /* ECC error interrupt */
+#define IRQ_PCI1_1 18 /* PCI 1 interrupt 1 summary */
+#define IRQ_PCI1_2 19 /* PCI 1 interrupt 2 summary */
+#define IRQ_PCI1_3 20 /* PCI 1 interrupt 3 summary */
+#define IRQ_PCI0OUT_LO 21 /* PCI 0 outbound interrupt summary */
+#define IRQ_PCI0OUT_HI 22 /* PCI 0 outbound interrupt summary */
+#define IRQ_PCI1OUT_LO 23 /* PCI 1 outbound interrupt summary */
+#define IRQ_PCI1OUT_HI 24 /* PCI 1 outbound interrupt summary */
+#define IRQ_PCI0IN_LO 26 /* PCI 0 inbound interrupt summary */
+#define IRQ_PCI0IN_HI 27 /* PCI 0 inbound interrupt summary */
+#define IRQ_PCI1IN_LO 28 /* PCI 1 inbound interrupt summary */
+#define IRQ_PCI1IN_HI 29 /* PCI 1 inbound interrupt summary */
+#define IRQ_ETH0 (32+0) /* Ethernet controller 0 interrupt */
+#define IRQ_ETH1 (32+1) /* Ethernet controller 1 interrupt */
+#define IRQ_ETH2 (32+2) /* Ethernet controller 2 interrupt */
+#define IRQ_SDMA (32+4) /* SDMA interrupt */
+#define IRQ_I2C (32+5) /* I2C interrupt */
+#define IRQ_BRG (32+7) /* Baud Rate Generator interrupt */
+#define IRQ_MPSC0 (32+8) /* MPSC 0 interrupt */
+#define IRQ_MPSC1 (32+10) /* MPSC 1 interrupt */
+#define IRQ_COMM (32+11) /* Comm unit interrupt */
+#define IRQ_GPP7_0 (32+24) /* GPP[7..0] interrupt */
+#define IRQ_GPP15_8 (32+25) /* GPP[15..8] interrupt */
+#define IRQ_GPP23_16 (32+26) /* GPP[23..16] interrupt */
+#define IRQ_GPP31_24 (32+27) /* GPP[31..24] interrupt */
+
+/*
+ * low word interrupt mask register bits
+ */
+#define IML_SUM BIT(0)
+#define IML_DEV BIT(IRQ_DEV)
+#define IML_DMA BIT(IRQ_DMA)
+#define IML_CPU BIT(IRQ_CPU)
+#define IML_IDMA0_1 BIT(IRQ_IDMA0_1)
+#define IML_IDMA2_3 BIT(IRQ_IDMA2_3)
+#define IML_IDMA4_5 BIT(IRQ_IDMA4_5)
+#define IML_IDMA6_7 BIT(IRQ_IDMA6_7)
+#define IML_TIME0_1 BIT(IRQ_TIME0_1)
+#define IML_TIME2_3 BIT(IRQ_TIME2_3)
+#define IML_TIME4_5 BIT(IRQ_TIME4_5)
+#define IML_TIME6_7 BIT(IRQ_TIME6_7)
+#define IML_PCI0_0 BIT(IRQ_PCI0_0)
+#define IML_PCI0_1 BIT(IRQ_PCI0_1)
+#define IML_PCI0_2 BIT(IRQ_PCI0_2)
+#define IML_PCI0_3 BIT(IRQ_PCI0_3)
+#define IML_PCI1_0 BIT(IRQ_PCI1_0)
+#define IML_ECC BIT(IRQ_ECC)
+#define IML_PCI1_1 BIT(IRQ_PCI1_1)
+#define IML_PCI1_2 BIT(IRQ_PCI1_2)
+#define IML_PCI1_3 BIT(IRQ_PCI1_3)
+#define IML_PCI0OUT_LO BIT(IRQ_PCI0OUT_LO)
+#define IML_PCI0OUT_HI BIT(IRQ_PCI0OUT_HI)
+#define IML_PCI1OUT_LO BIT(IRQ_PCI1OUT_LO)
+#define IML_PCI1OUT_HI BIT(IRQ_PCI1OUT_HI)
+#define IML_PCI0IN_LO BIT(IRQ_PCI0IN_LO)
+#define IML_PCI0IN_HI BIT(IRQ_PCI0IN_HI)
+#define IML_PCI1IN_LO BIT(IRQ_PCI1IN_LO)
+#define IML_PCI1IN_HI BIT(IRQ_PCI1IN_HI)
+#define IML_RES (BIT(25)|BIT(30)|BIT(31))
+
+/*
+ * high word interrupt mask register bits
+ */
+#define IMH_ETH0 BIT(IRQ_ETH0-32)
+#define IMH_ETH1 BIT(IRQ_ETH1-32)
+#define IMH_ETH2 BIT(IRQ_ETH2-32)
+#define IMH_SDMA BIT(IRQ_SDMA-32)
+#define IMH_I2C BIT(IRQ_I2C-32)
+#define IMH_BRG BIT(IRQ_BRG-32)
+#define IMH_MPSC0 BIT(IRQ_MPSC0-32)
+#define IMH_MPSC1 BIT(IRQ_MPSC1-32)
+#define IMH_COMM BIT(IRQ_COMM-32)
+#define IMH_GPP7_0 BIT(IRQ_GPP7_0-32)
+#define IMH_GPP15_8 BIT(IRQ_GPP15_8-32)
+#define IMH_GPP23_16 BIT(IRQ_GPP23_16-32)
+#define IMH_GPP31_24 BIT(IRQ_GPP31_24-32)
+#define IMH_GPP_SUM (IMH_GPP7_0|IMH_GPP15_8|IMH_GPP23_16|IMH_GPP31_24)
+#define IMH_RES (BIT(3) |BIT(6) |BIT(9) |BIT(12)|BIT(13)|BIT(14) \
+ |BIT(15)|BIT(16)|BIT(17)|BIT(18)|BIT(19)|BIT(20) \
+ |BIT(21)|BIT(22)|BIT(23)|BIT(28)|BIT(29)|BIT(30) \
+ |BIT(31))
+
+/*
+ * ICR_CSC "Select Cause" register bits
+ */
+#define CSC_SEL BIT(30) /* HI/LO select */
+#define CSC_STAT BIT(31) /* ? "irq active" : "irq none" */
+#define CSC_CAUSE ~(CSC_SEL|CSC_STAT)
+
+
+/*
+ * CPU Int[n] Mask bit(s)
+ */
+#define CPUINT_SEL 0x80000000 /* HI/LO select */
+
+#endif /* _DISCOVERY_GT64260INTR_H */
diff --git a/c/src/lib/libbsp/powerpc/beatnik/marvell/gtpcireg.h b/c/src/lib/libbsp/powerpc/beatnik/marvell/gtpcireg.h
new file mode 100644
index 0000000000..d01fc702ac
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/beatnik/marvell/gtpcireg.h
@@ -0,0 +1,964 @@
+/* $NetBSD: gtpcireg.h,v 1.4 2005/12/11 12:22:16 christos Exp $ */
+
+/*
+ * Copyright (c) 2002 Allegro Networks, Inc., Wasabi Systems, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed for the NetBSD Project by
+ * Allegro Networks, Inc., and Wasabi Systems, Inc.
+ * 4. The name of Allegro Networks, Inc. may not be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ * 5. The name of Wasabi Systems, Inc. may not be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ALLEGRO NETWORKS, INC. AND
+ * WASABI SYSTEMS, INC. ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL EITHER ALLEGRO NETWORKS, INC. OR WASABI SYSTEMS, INC.
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _DEV_GTPCIREG_H
+#define _DEV_GTPCIREG_H
+
+#define PCI__BIT(bit) (1U << (bit))
+#define PCI__MASK(bit) (PCI__BIT(bit) - 1)
+#define PCI__GEN(bus, off, num) (((off)^((bus) << 7))+((num) << 4))
+#define PCI__EXT(data, bit, len) (((data) >> (bit)) & PCI__MASK(len))
+#define PCI__CLR(data, bit, len) ((data) &= ~(PCI__MASK(len) << (bit)))
+#define PCI__INS(bit, new) ((new) << (bit))
+
+#define PCI_SYNC_REG(bus) (0xc0 | ((bus) << 3))
+
+/*
+ * Table 185: PCI Slave ADDRess Decoding Register Map
+ */
+#define PCI_SCS0_BAR_SIZE(bus) PCI__GEN(bus, 0x0c08, 0)
+#define PCI_SCS2_BAR_SIZE(bus) PCI__GEN(bus, 0x0c0c, 0)
+#define PCI_CS0_BAR_SIZE(bus) PCI__GEN(bus, 0x0c10, 0)
+#define PCI_CS3_BAR_SIZE(bus) PCI__GEN(bus, 0x0c14, 0)
+#define PCI_SCS1_BAR_SIZE(bus) PCI__GEN(bus, 0x0d08, 0)
+#define PCI_SCS3_BAR_SIZE(bus) PCI__GEN(bus, 0x0d0c, 0)
+#define PCI_CS1_BAR_SIZE(bus) PCI__GEN(bus, 0x0d10, 0)
+#define PCI_BOOTCS_BAR_SIZE(bus) PCI__GEN(bus, 0x0d14, 0)
+#define PCI_CS2_BAR_SIZE(bus) PCI__GEN(bus, 0x0d18, 0)
+#define PCI_P2P_MEM0_BAR_SIZE(bus) PCI__GEN(bus, 0x0d1c, 0)
+#define PCI_P2P_MEM1_BAR_SIZE(bus) PCI__GEN(bus, 0x0d20, 0)
+#define PCI_P2P_IO_BAR_SIZE(bus) PCI__GEN(bus, 0x0d24, 0)
+#define PCI_CPU_BAR_SIZE(bus) PCI__GEN(bus, 0x0d28, 0)
+#define PCI_EXPANSION_ROM_BAR_SIZE(bus) PCI__GEN(bus, 0x0d2c, 0)
+#define PCI_DAC_SCS0_BAR_SIZE(bus) PCI__GEN(bus, 0x0e00, 0)
+#define PCI_DAC_SCS1_BAR_SIZE(bus) PCI__GEN(bus, 0x0e04, 0)
+#define PCI_DAC_SCS2_BAR_SIZE(bus) PCI__GEN(bus, 0x0e08, 0)
+#define PCI_DAC_SCS3_BAR_SIZE(bus) PCI__GEN(bus, 0x0e0c, 0)
+#define PCI_DAC_CS0_BAR_SIZE(bus) PCI__GEN(bus, 0x0e10, 0)
+#define PCI_DAC_CS1_BAR_SIZE(bus) PCI__GEN(bus, 0x0e14, 0)
+#define PCI_DAC_CS2_BAR_SIZE(bus) PCI__GEN(bus, 0x0e18, 0)
+#define PCI_DAC_CS3_BAR_SIZE(bus) PCI__GEN(bus, 0x0e1c, 0)
+#define PCI_DAC_BOOTCS_BAR_SIZE(bus) PCI__GEN(bus, 0x0e20, 0)
+#define PCI_DAC_P2P_MEM0_BAR_SIZE(bus) PCI__GEN(bus, 0x0e24, 0)
+#define PCI_DAC_P2P_MEM1_BAR_SIZE(bus) PCI__GEN(bus, 0x0e28, 0)
+#define PCI_DAC_CPU_BAR_SIZE(bus) PCI__GEN(bus, 0x0e2c, 0)
+#define PCI_BASE_ADDR_REGISTERS_ENABLE(bus) PCI__GEN(bus, 0x0c3c, 0)
+#define PCI_SCS0_BASE_ADDR_REMAP(bus) PCI__GEN(bus, 0x0c48, 0)
+#define PCI_SCS1_BASE_ADDR_REMAP(bus) PCI__GEN(bus, 0x0d48, 0)
+#define PCI_SCS2_BASE_ADDR_REMAP(bus) PCI__GEN(bus, 0x0c4c, 0)
+#define PCI_SCS3_BASE_ADDR_REMAP(bus) PCI__GEN(bus, 0x0d4c, 0)
+#define PCI_CS0_BASE_ADDR_REMAP(bus) PCI__GEN(bus, 0x0c50, 0)
+#define PCI_CS1_BASE_ADDR_REMAP(bus) PCI__GEN(bus, 0x0d50, 0)
+#define PCI_CS2_BASE_ADDR_REMAP(bus) PCI__GEN(bus, 0x0d58, 0)
+#define PCI_CS3_BASE_ADDR_REMAP(bus) PCI__GEN(bus, 0x0c54, 0)
+#define PCI_ADDR_DECODE_CONTROL(bus) PCI__GEN(bus, 0x0d3c, 0)
+#define PCI_BOOTCS_ADDR_REMAP(bus) PCI__GEN(bus, 0x0d54, 0)
+#define PCI_P2P_MEM0_BASE_ADDR_REMAP_LOW(bus) PCI__GEN(bus, 0x0d5c, 0)
+#define PCI_P2P_MEM0_BASE_ADDR_REMAP_HIGH(bus) PCI__GEN(bus, 0x0d60, 0)
+#define PCI_P2P_MEM1_BASE_ADDR_REMAP_LOW(bus) PCI__GEN(bus, 0x0d64, 0)
+#define PCI_P2P_MEM1_BASE_ADDR_REMAP_HIGH(bus) PCI__GEN(bus, 0x0d68, 0)
+#define PCI_P2P_IO_BASE_ADDR_REMAP(bus) PCI__GEN(bus, 0x0d6c, 0)
+#define PCI_CPU_BASE_ADDR_REMAP(bus) PCI__GEN(bus, 0x0d70, 0)
+#define PCI_DAC_SCS0_BASE_ADDR_REMAP(bus) PCI__GEN(bus, 0x0f00, 0)
+#define PCI_DAC_SCS1_BASE_ADDR_REMAP(bus) PCI__GEN(bus, 0x0f04, 0)
+#define PCI_DAC_SCS2_BASE_ADDR_REMAP(bus) PCI__GEN(bus, 0x0f08, 0)
+#define PCI_DAC_SCS3_BASE_ADDR_REMAP(bus) PCI__GEN(bus, 0x0f0c, 0)
+#define PCI_DAC_CS0_BASE_ADDR_REMAP(bus) PCI__GEN(bus, 0x0f10, 0)
+#define PCI_DAC_CS1_BASE_ADDR_REMAP(bus) PCI__GEN(bus, 0x0f14, 0)
+#define PCI_DAC_CS2_BASE_ADDR_REMAP(bus) PCI__GEN(bus, 0x0f18, 0)
+#define PCI_DAC_CS3_BASE_ADDR_REMAP(bus) PCI__GEN(bus, 0x0f1c, 0)
+#define PCI_DAC_BOOTCS_BASE_ADDR_REMAP(bus) PCI__GEN(bus, 0x0f20, 0)
+#define PCI_DAC_P2P_MEM0_BASE_ADDR_REMAP_LOW(bus) PCI__GEN(bus, 0x0f24, 0)
+#define PCI_DAC_P2P_MEM0_BASE_ADDR_REMAP_HIGH(bus) PCI__GEN(bus, 0x0f28, 0)
+#define PCI_DAC_P2P_MEM1_BASE_ADDR_REMAP_LOW(bus) PCI__GEN(bus, 0x0f2c, 0)
+#define PCI_DAC_P2P_MEM1_BASE_ADDR_REMAP_HIGH(bus) PCI__GEN(bus, 0x0f30, 0)
+#define PCI_DAC_CPU_BASE_ADDR_REMAP(bus) PCI__GEN(bus, 0x0f34, 0)
+#define PCI_EXPANSION_ROM_BASE_ADDR_REMAP(bus) PCI__GEN(bus, 0x0f38, 0)
+
+/*
+ * Table 186: PCI Control Register Map
+ */
+#define PCI_COMMAND(bus) PCI__GEN(bus, 0x0c00, 0)
+#define PCI_MODE(bus) PCI__GEN(bus, 0x0d00, 0)
+#define PCI_TIMEOUT_RETRY(bus) PCI__GEN(bus, 0x0c04, 0)
+#define PCI_READ_BUFFER_DISCARD_TIMER(bus) PCI__GEN(bus, 0x0d04, 0)
+#define PCI_MSI_TRIGGER_TIMER(bus) PCI__GEN(bus, 0x0c38, 0)
+#define PCI_ARBITER_CONTROL(bus) PCI__GEN(bus, 0x1d00, 0)
+#define PCI_INTERFACE_XBAR_CONTROL_LOW(bus) PCI__GEN(bus, 0x1d08, 0)
+#define PCI_INTERFACE_XBAR_CONTROL_HIGH(bus) PCI__GEN(bus, 0x1d0c, 0)
+#define PCI_INTERFACE_XBAR_TIMEOUT(bus) PCI__GEN(bus, 0x1d04, 0)
+#define PCI_READ_RESPONSE_XBAR_CONTROL_LOW(bus) PCI__GEN(bus, 0x1d18, 0)
+#define PCI_READ_RESPONSE_XBAR_CONTROL_HIGH(bus) PCI__GEN(bus, 0x1d1c, 0)
+#define PCI_SYNC_BARRIER(bus) PCI__GEN(bus, 0x1d10, 0)
+#define PCI_P2P_CONFIGURATION(bus) PCI__GEN(bus, 0x1d14, 0)
+#define PCI_P2P_SWAP_CONTROL(bus) PCI__GEN(bus, 0x1d54, 0)
+#define PCI_ACCESS_CONTROL_BASE_LOW(bus, n) PCI__GEN(bus, 0x1e00, n)
+#define PCI_ACCESS_CONTROL_BASE_HIGH(bus, n) PCI__GEN(bus, 0x1e04, n)
+#define PCI_ACCESS_CONTROL_TOP(bus, n) PCI__GEN(bus, 0x1e08, n)
+
+
+/*
+ * Table 187: PCI Snoop Control Register Map
+ */
+#define PCI_SNOOP_CONTROL_BASE_LOW(bus, n) PCI__GEN(bus, 0x1f00, n)
+#define PCI_SNOOP_CONTROL_BASE_HIGH(bus, n) PCI__GEN(bus, 0x1f04, n)
+#define PCI_SNOOP_CONTROL_TOP(bus, n) PCI__GEN(bus, 0x1f08, n)
+
+/*
+ * Table 188: PCI Configuration ACCESS_Register Map
+ */
+#define PCI_CONFIG_ADDR(bus) PCI__GEN(bus, 0x0cf8, 0)
+#define PCI_CONFIG_DATA(bus) PCI__GEN(bus, 0x0cfc, 0)
+#define PCI_INTR_ACK(bus) PCI__GEN(bus, 0x0c34, 0)
+
+/*
+ * Table 189: PCI ERROR Report Register Map
+ */
+#define PCI_SERR_MASK(bus) PCI__GEN(bus, 0x0c28, 0)
+#define PCI_ERROR_ADDRESS_LOW(bus) PCI__GEN(bus, 0x1d40, 0)
+#define PCI_ERROR_ADDRESS_HIGH(bus) PCI__GEN(bus, 0x1d44, 0)
+#define PCI_ERROR_DATA_LOW(bus) PCI__GEN(bus, 0x1d48, 0)
+#define PCI_ERROR_DATA_HIGH(bus) PCI__GEN(bus, 0x1d4c, 0)
+#define PCI_ERROR_COMMAND(bus) PCI__GEN(bus, 0x1d50, 0)
+#define PCI_ERROR_CAUSE(bus) PCI__GEN(bus, 0x1d58, 0)
+#define PCI_ERROR_MASK(bus) PCI__GEN(bus, 0x1d5c, 0)
+
+
+
+/*
+ * Table 223: PCI Base Address Registers Enable
+ * If a bit is clear, the BAR is enabled. If set, disabled. The GT64260]
+ * prevents disabling both memory mapped and I/O mapped BARs (bits 9 and 10
+ * cannot simultaneously be set to 1).
+ */
+#define PCI_BARE_SCS0En PCI__BIT(0) /* SCS[0]* BAR Enable */
+#define PCI_BARE_SCS1En PCI__BIT(1) /* SCS[1]* BAR Enable */
+#define PCI_BARE_SCS2En PCI__BIT(2) /* SCS[2]* BAR Enable */
+#define PCI_BARE_SCS3En PCI__BIT(3) /* SCS[3]* BAR Enable */
+#define PCI_BARE_CS0En PCI__BIT(4) /* CS[0]* BAR Enable */
+#define PCI_BARE_CS1En PCI__BIT(5) /* CS[1]* BAR Enable */
+#define PCI_BARE_CS2En PCI__BIT(6) /* CS[2]* BAR Enable */
+#define PCI_BARE_CS3En PCI__BIT(7) /* CS[3]* BAR Enable */
+#define PCI_BARE_BootCSEn PCI__BIT(8) /* BootCS* BAR Enable */
+#define PCI_BARE_IntMemEn PCI__BIT(9) /* Memory Mapped Internal
+ * Registers BAR Enable */
+#define PCI_BARE_IntIOEn PCI__BIT(10) /* I/O Mapped Internal
+ * Registers BAR Enable */
+#define PCI_BARE_P2PMem0En PCI__BIT(11) /* P2P Mem0 BAR Enable */
+#define PCI_BARE_P2PMem1En PCI__BIT(12) /* P2P Mem1 BAR Enable */
+#define PCI_BARE_P2PIOEn PCI__BIT(13) /* P2P IO BAR Enable */
+#define PCI_BARE_CPUEn PCI__BIT(14) /* CPU BAR Enable */
+#define PCI_BARE_DSCS0En PCI__BIT(15) /* DAC SCS[0]* BAR Enable */
+#define PCI_BARE_DSCS1En PCI__BIT(16) /* DAC SCS[1]* BAR Enable */
+#define PCI_BARE_DSCS2En PCI__BIT(17) /* DAC SCS[2]* BAR Enable */
+#define PCI_BARE_DSCS3En PCI__BIT(18) /* DAC SCS[3]* BAR Enable */
+#define PCI_BARE_DCS0En PCI__BIT(19) /* DAC CS[0]* BAR Enable */
+#define PCI_BARE_DCS1En PCI__BIT(20) /* DAC CS[1]* BAR Enable */
+#define PCI_BARE_DCS2En PCI__BIT(21) /* DAC CS[2]* BAR Enable */
+#define PCI_BARE_DCS3En PCI__BIT(22) /* DAC CS[3]* BAR Enable */
+#define PCI_BARE_DBootCSEn PCI__BIT(23) /* DAC BootCS* BAR Enable */
+#define PCI_BARE_DP2PMem0En PCI__BIT(24) /* DAC P2P Mem0 BAR Enable */
+#define PCI_BARE_DP2PMem1En PCI__BIT(25) /* DAC P2P Mem1 BAR Enable */
+#define PCI_BARE_DCPUEn PCI__BIT(26) /* DAC CPU BAR Enable */
+
+/*
+ * Table 254: PCI Address Decode Control
+ * Bits 7:4 and 31:25 are reserved
+ * 00:00 RemapWrDis Address Remap Registers Write Disable
+ * 0: Writes to a BAR result in updating the
+ * corresponding remap register with the BAR's
+ * new value.
+ * 1: Writes to a BAR have no affect on the
+ * corresponding Remap register value.
+ * 01:01 ExpRomDev Expansion ROM Device (0: CS[3]; 1: BootCS)
+ * 02:02 VPDDev VPD Device (0: CS[3]; 1: BootCS)
+ * 03:03 MsgAcc Messaging registers access
+ * 0: Messaging unit registers are accessible on
+ * lowest 4Kbyte of SCS[0] BAR space.
+ * 1: Messaging unit registers are only accessible
+ * as part of the GT64260 internal space.
+ * 07:04 Reserved
+ * 24:08 VPDHighAddr VPD High Address bits
+ * [31:15] of VPD the address.
+ * 31:25 Reserved
+ */
+#define PCI_ADC_RemapWrDis PCI__BIT(0)
+#define PCI_ADC_ExpRomDev PCI__BIT(1)
+#define PCI_ADC_VPDDev PCI__BIT(2)
+#define PCI_ADC_MsgAcc PCI__BIT(3)
+#define PCI_ADC_VPDHighAddr_GET(v) PCI__EXT(v, 8, 16)
+
+
+/*
+ * Table 255: PCI Command
+ * 00:00 MByteSwap PCI Master Byte Swap
+ * NOTE: GT-64120 and GT-64130 compatible.
+ * When set to 0, the GTO64260 PCI master swaps the bytes
+ * of the incoming and outgoing PCI data (swap the 8 bytes
+ * of a longword).
+ * 01:01 Reserved
+ * 02:02 Reserved Must be 0.
+ * 03:03 Reserved
+ * 04:04 MWrCom PCI Master Write Combine Enable
+ * When set to 1, write combining is enabled.
+ * 05:05 MRdCom PCI Master Read Combine Enable
+ * When set to 1, read combining is enabled.
+ * 06:06 MWrTrig PCI Master Write Trigger
+ * 0: Accesses the PCI bus only when the whole burst is
+ * written into the master write buffer.
+ * 1: Accesses the PCI bus when the first data is written
+ * into the master write buffer.
+ * 07:07 MRdTrig PCI Master Read Trigger
+ * 0: Returns read data to the initiating unit only when
+ * the whole burst is written into master read buffer.
+ * 1: Returns read data to the initiating unit when the
+ * first read data is written into master read buffer.
+ * 08:08 MRdLine PCI Master Memory Read Line Enable
+ * (0: Disable; 1: Enable)
+ * 09:09 MRdMul PCI Master Memory Read Multiple Enable
+ * (0: Disable; 1: Enable)
+ * 10:10 MWordSwap PCI Master Word Swap
+ * NOTE: GT-64120 and GT-64130 compatible.
+ * When set to 1, the GT64260 PCI master swaps the 32-bit
+ * words of the incoming and outgoing PCI data.
+ * 11:11 SWordSwap PCI Slave Word Swap
+ * NOTE: GT-64120 and GT-64130 compatible.
+ * When set to 1, the GT64260 PCI slave swaps the 32-bit
+ * words of the incoming and outgoing PCI data.
+ * 12:12 IntBusCtl PCI Interface Unit Internal Bus Control
+ * NOTE: Reserved for Galileo Technology usage
+ * 0: Enable internal bus sharing between master and
+ * slave interfaces.
+ * 1: Disable internal bus sharing between master and
+ * slave interfaces.
+ * 13:13 SBDis PCI Slave Sync Barrier Disable
+ * When set to 1, the PCI configuration read transaction
+ * will stop act as sync barrier transaction.
+ * 14:14 Reserved Must be 0
+ * 15:15 MReq64 PCI Master REQ64* Enable (0: Disable; 1: Enable)
+ * 16:16 SByteSwap PCI Slave Byte Swap
+ * NOTE: GT-64120 and GT-64130 compatible.
+ * When set to 0, the GT64260 PCI slave swaps the bytes of
+ * the incoming and outgoing PCI data (swap the 8 bytes of
+ * a long-word).
+ * 17:17 MDACEn PCI Master DAC Enable
+ * 0: Disable (The PCI master never drives the DAC cycle)
+ * 1: Enable (In case the upper 32-bit address is not 0,
+ * the PCI master drives the DAC cycle)
+ * 18:18 M64Allign PCI Master REQ64* assertion on non-aligned
+ * 0: Disable (The master asserts REQ64* only if
+ * the address is 64-bit aligned)
+ * 1: Enable (The master asserts REQ64* even if
+ * the address is not 64-bit aligned)
+ * 19:19 PErrProp Parity/ECC Errors Propagation Enable
+ * 0: Disable (The PCI interface always drives
+ * correct parity on the PAR signal)
+ * 1: Enable (In case of slave read bad ECC from
+ * SDRAM, or master write with bad parity/ECC
+ * indication from the initiator, the PCI interface
+ * drives bad parity on the PAR signal)
+ * 20:20 SSwapEn PCI Slave Swap Enable
+ * NOTE: Even if the SSwapEn bit is set to 1 and
+ * the PCI address does not match any of the
+ * Access Control registers, slave data swapping
+ * works according to SByteSwap and SWordSwap bits.
+ * 0: PCI slave data swapping is determined via
+ * SByteSwap and SWordSwap bits (bits 16 and 11),
+ * as in the GT-64120/130.
+ * 1: PCI slave data swapping is determined via PCISwap
+ * bits [25:24] in the PCI Access Control registers.
+ * 21:21 MSwapEn PCI Master Swap Enable
+ * 0: PCI master data swapping is determined via
+ * MByteSwap and MWordSwap bits (bits 0 and 10),
+ * as in the GT-64120/130.
+ * 1: PCI master data swapping is determined via
+ * PCISwap bits in CPU to PCI Address Decoding
+ * registers.
+ * 22:22 MIntSwapEn PCI Master Configuration Transactions Data Swap Enable
+ * NOTE: Reserved for Galileo Technology usage.
+ * 0: Disable (The PCI master configuration transaction
+ * to the PCI bus is always in Little Endian convention)
+ * 1: Enable (The PCI master configuration transaction to
+ * the PCI bus is determined according to the setting
+ * of MSwapEn bit)
+ * 23:23 LBEn PCI Loop Back Enable
+ * NOTE: Reserved for Galileo Technology usage.
+ * 0: Disable (The PCI slave does not respond to
+ * transactions initiated by the PCI master)
+ * 1: Enable (The PCI slave does respond to
+ * transactions initiated by the PCI master,
+ * if targeted to the slave (address match)
+ * 26:24 SIntSwap PCI Slave data swap control on PCI accesses to the
+ * GT64260 internal and configuration registers.
+ * Bits encoding are the same as bits[26:24] in PCI Access
+ * Control registers.
+ * 27:27 Reserved Must be 0.
+ * 31:28 Reserved Read only.
+ */
+#define PCI_CMD_MByteSwap PCI__BIT(0)
+#define PCI_CMD_MBZ0_2 PCI__BIT(2)
+#define PCI_CMD_MWrCom PCI__BIT(4)
+#define PCI_CMD_MRdCom PCI__BIT(5)
+#define PCI_CMD_MWrTrig PCI__BIT(6)
+#define PCI_CMD_MRdTrig PCI__BIT(7)
+#define PCI_CMD_MRdLine PCI__BIT(8)
+#define PCI_CMD_MRdMul PCI__BIT(9)
+#define PCI_CMD_MWordSwap PCI__BIT(10)
+#define PCI_CMD_SWordSwap PCI__BIT(11)
+#define PCI_CMD_IntBusCtl PCI__BIT(12)
+#define PCI_CMD_SBDis PCI__BIT(13)
+#define PCI_CMD_MBZ0_14 PCI__BIT(14)
+#define PCI_CMD_MReq64 PCI__BIT(15)
+#define PCI_CMD_SByteSwap PCI__BIT(16)
+#define PCI_CMD_MDCAEn PCI__BIT(17)
+#define PCI_CMD_M64Allign PCI__BIT(18)
+#define PCI_CMD_PErrProp PCI__BIT(19)
+#define PCI_CMD_SSwapEn PCI__BIT(20)
+#define PCI_CMD_MSwapEn PCI__BIT(21)
+#define PCI_CMD_MIntSwapEn PCI__BIT(22)
+#define PCI_CMD_LBEn PCI__BIT(23)
+#define PCI_CMD_SIntSwap_GET(v) PCI__EXT(v, 24, 3)
+#define PCI_CMD_MBZ0_27 PCI__BIT(27)
+
+
+/*
+ * Table 256: PCI Mode
+ * 00:00 PciID PCI Interface ID -- Read Only (PCI_0: 0x0; PCI_1: 0x1)
+ * 01:01 Reserved
+ * 02:02 Pci64 64-bit PCI Interface -- Read Only
+ * When set to 1, the PCI interface is configured to a
+ * 64 bit interface.
+ * 07:03 Reserved
+ * 08:08 ExpRom Expansion ROM Enable -- Read Only from PCI
+ * When set to 1, the expansion ROM BAR is enabled.
+ * 09:09 VPD VPD Enable -- Read Only from PCI
+ * When set to 1, VPD is supported.
+ * 10:10 MSI MSI Enable -- Read Only from PCI
+ * When set to 1, MSI is supported.
+ * 11:11 PMG Power Management Enable -- Read Only from PCI
+ * When set to 1, PMG is supported.
+ * 12:12 HotSwap CompactPCI Hot Swap Enable -- Read Only from PCI
+ * When set to 1, HotSwap is supported.
+ * 13:13 BIST BIST Enable -- Read only from PCI
+ * If set to 1, BIST is enabled.
+ * 30:14 Reserved
+ * 31:31 PRst PCI Interface Reset Indication -- Read Only
+ * Set to 0 as long as the RST* pin is asserted.
+ */
+#define PCI_MODE_PciID_GET(v) PCI__EXT(v, 0, 1)
+#define PCI_MODE_Pci64 PCI__BIT(2)
+#define PCI_MODE_ExpRom PCI__BIT(8)
+#define PCI_MODE_VPD PCI__BIT(9)
+#define PCI_MODE_MSI PCI__BIT(10)
+#define PCI_MODE_PMG PCI__BIT(11)
+#define PCI_MODE_HotSwap PCI__BIT(12)
+#define PCI_MODE_BIST PCI__BIT(13)
+#define PCI_MODE_PRst PCI__BIT(31)
+
+/*
+ * Table 257: PCI Timeout and Retry
+ * 07:00 Timeout0 Specifies the number of PClk cycles the GT64260 slave
+ * holds the PCI bus before terminating a transaction
+ * with RETRY.
+ * 15:08 Timeout1 Specifies the number of PClk cycles the GT64260 slave
+ * holds the PCI bus before terminating a transaction
+ * with DISCONNECT.
+ * 23:16 RetryCtr Retry Counter
+ * Specifies the number of retries of the GT64260 Master.
+ * The GT64260 generates an interrupt when this timer
+ * expires. A 0x00 value means a retry forever.
+ * 31:24 Reserved
+ */
+#define PCI_TMORTRY_Timeout0_GET(v) PCI__EXT(v, 0, 8)
+#define PCI_TMORTRY_Timeout1_GET(v) PCI__EXT(v, 8, 8)
+#define PCI_TMORTRY_RetryCtr_GET(v) PCI__EXT(v, 16, 8)
+
+
+/*
+ * Table 258: PCI Read Buffer Discard Timer
+ * 15:00 Timer Specifies the number of PClk cycles the GT64260
+ * slave keeps an non-accessed read buffers (non com-
+ * pleted delayed read) before invalidating the buffer.
+ * 23:16 RdBufEn Slave Read Buffers Enable
+ * Each bit corresponds to one of the eight read buffers.
+ * If set to 1, buffer is enabled.
+ * 31:24 Reserved
+ */
+#define PCI_RdBufDisTmr_Timer_GET(v) PCI__EXT(v, 0, 16)
+#define PCI_RdBufDisTmr_RdBufEn_GET(v) PCI__EXT(v, 16, 8)
+#define PCI_RdBufDisTmr_RdBufEn0(v) PCI__BIT(16)
+#define PCI_RdBufDisTmr_RdBufEn1(v) PCI__BIT(17)
+#define PCI_RdBufDisTmr_RdBufEn2(v) PCI__BIT(18)
+#define PCI_RdBufDisTmr_RdBufEn3(v) PCI__BIT(19)
+#define PCI_RdBufDisTmr_RdBufEn4(v) PCI__BIT(20)
+#define PCI_RdBufDisTmr_RdBufEn5(v) PCI__BIT(21)
+#define PCI_RdBufDisTmr_RdBufEn6(v) PCI__BIT(22)
+#define PCI_RdBufDisTmr_RdBufEn7(v) PCI__BIT(23)
+
+/*
+ * Table 259: MSI Trigger Timer
+ * 15:00 Timer Specifies the number of TClk cycles between consecutive
+ * MSI requests.
+ * 31:16 Reserved
+ */
+#define PCI_MSITrigger_Timer_GET(v) PCI__EXT(v, 0, 16)
+
+/*
+ * Table 260: PCI Arbiter Control
+ * NOTE: If HPPV (bits [28:21]) is set to 0 and PAEn is set to 1,
+ * priority scheme is reversed. This means that high priority
+ * requests are granted if no low priority request is pending.
+ * 00:00 Reserved Must be 0. 0x0
+ * 01:01 BDEn Broken Detection Enable
+ * If set to 1, broken master detection is enabled. A mas-
+ * ter is said to be broken if it fails to respond to grant
+ * assertion within a window specified in BV (bits [6:3]).
+ * 02:02 PAEn Priority Arbitration Enable
+ * 0: Low priority requests are granted only when no high
+ * priority request is pending
+ * 1: Weighted round robin arbitration is performed
+ * between high priority and low priority groups.
+ * 06:03 BV Broken Value
+ * This value sets the maximum number of cycles that the
+ * arbiter waits for a PCI master to respond to its grant
+ * assertion. If a PCI master fails to assert FRAME* within
+ * this time, the PCI arbiter aborts the transaction and
+ * performs a new arbitration cycle and a maskable
+ * interrupt is generated. Must be greater than 0.
+ * NOTE: The PCI arbiter waits for the current
+ * transaction to end before starting to
+ * count the wait-for-broken cycles.
+ * Must be greater than 1 for masters that performs address
+ * stepping (such as the GTO 64260 PCI master), since they
+ * require GNT* assertion for two cycles.
+ * 13:07 P[6:0] Priority
+ * These bits assign priority levels to the requests
+ * connected to the PCI arbiter. When a PM bit is set to
+ * 1, priority of the associated request is high. The
+ * mapping between P[6:0] bits and the request/grant pairs
+ * are as follows:
+ * P[0]: internal PCI master P[1]: external REQ0/GNT0
+ * P[2]: external REQ1/GNT1 P[3]: external REQ2/GNT2
+ * P[4]: external REQ3/GNT3 P[5]: external REQ4/GNT4
+ * P[6]: external REQ5/GNT5
+ * 20:14 PD[6:0] Parking Disable
+ * Use these bits to disable parking on any of the PCI
+ * masters. When a PD bit is set to 1, parking on the
+ * associated PCI master is disabled.
+ * NOTE: The arbiter parks on the last master granted
+ * unless disabled through the PD bit. Also, if
+ * PD bits are all 1, the PCI arbiter parks on
+ * the internal PCI master.
+ * 28:21 HPPV High Priority Preset Value
+ * This is the preset value of the high priority counter
+ * (High_cnt). This counter decrements each time a high
+ * priority request is granted. When the counter reaches
+ * zero, it reloads with this preset value. The counter
+ * reloads when a low priority request is granted.
+ * 30:29 Reserved
+ * 31:31 EN Enable
+ * Setting this bit to 1 enables operation of the arbiter.
+ */
+#define PCI_ARBCTL_MBZ0_0 PCI__BIT(0)
+#define PCI_ARBCTL_BDEn PCI__BIT(1)
+#define PCI_ARBCTL_PAEn PCI__BIT(2)
+#define PCI_ARBCTL_BV_GET(v) PCI__EXT(v, 3, 4)
+#define PCI_ARBCTL_P_GET(v) PCI__EXT(v, 7, 7)
+#define PCI_ARBCTL_PD_GET(v) PCI__EXT(v, 14, 7)
+#define PCI_ARBCTL_HPPV_GET(v) PCI__EXT(v, 21, 7)
+#define PCI_ARBCTL_EN PCI__BIT(31)
+
+#define PCI_ARBPRI_IntPci PCI__BIT(0)
+#define PCI_ARBPRI_ExtReqGnt0 PCI__BIT(1)
+#define PCI_ARBPRI_ExtReqGnt1 PCI__BIT(2)
+#define PCI_ARBPRI_EXtReqGnt2 PCI__BIT(3)
+#define PCI_ARBPRI_EXtReqGnt3 PCI__BIT(4)
+#define PCI_ARBPRI_EXtReqGnt4 PCI__BIT(5)
+#define PCI_ARBPRI_EXtReqGnt5 PCI__BIT(6)
+
+/*
+ * Table 261: PCI Interface Crossbar Control (Low)
+ * 03:00 Arb0 Slice 0 of PCI master pizza arbiter.
+ * 07:04 Arb1 Slice 1 of PCI master pizza arbiter.
+ * 11:08 Arb2 Slice 2 of PCI master pizza arbiter.
+ * 15:12 Arb3 Slice 3 of PCI master pizza arbiter.
+ * 19:16 Arb4 Slice 4 of PCI master pizza arbiter.
+ * 23:20 Arb5 Slice 5 of PCI master pizza arbiter.
+ * 27:24 Arb6 Slice 6 of PCI master pizza arbiter.
+ * 31:28 Arb7 Slice 7 of PCI master pizza arbiter.
+ */
+#define PCI_IFXBRCTL_GET_SLICE(v, n) PCI__EXT(v, (n) * 4, 4)
+#define PCI_IFXBRCTL_SET_SLICE(v, n, s) ((void)(PCI__CLR(v, (n)*4, 4),\
+ (v) |= PCI__INS((n)*4, s)))
+
+/*
+ * Table 262: PCI Interface Crossbar Control (High)
+ * 03:00 Arb8 Slice 8 of PCI master pizza arbiter.
+ * 07:04 Arb9 Slice 9 of PCI master pizza arbiter.
+ * 11:08 Arb10 Slice 10 of PCI master pizza arbiter.
+ * 15:12 Arb11 Slice 11 of PCI master pizza arbiter.
+ * 19:16 Arb12 Slice 12 of PCI master pizza arbiter.
+ * 23:20 Arb13 Slice 13 of PCI master pizza arbiter.
+ * 27:24 Arb14 Slice 14 of PCI master pizza arbiter.
+ * 31:28 Arb15 Slice 15 of PCI master pizza arbiter.
+ */
+#define PCI_IFXBRCH_GET_SLICE(v, n) PCI__EXT(v, ((n) - 8) * 4, 4)
+#define PCI_IFXBRCH_SET_SLICE(v, n, s) ((void)(PCI__CLR(v, ((n)*-8)4, 4),\
+ (v) |= PCI__INS(((n)-8)*4, s)))
+
+/*
+ * Table 263: PCI Interface Crossbar Timeout
+ (NOTE: Reserved for Galileo Technology usage.)
+ * 07:00 Timeout Crossbar Arbiter Timeout Preset Value
+ * 15:08 Reserved
+ * 16:16 TimeoutEn Crossbar Arbiter Timer Enable (1: Disable)
+ * 31:17 Reserved
+ */
+#define PCI_IFXBRTMO_Timeout_GET(v) PCI__EXT(v, 0, 8)
+#define PCI_IFXBRTMO_TimeoutEn PCI__BIT(16)
+
+/*
+ * Table 264: PCI Read Response Crossbar Control (Low)
+ * 03:00 Arb0 Slice 0 of PCI slave pizza arbiter.
+ * 07:04 Arb1 Slice 1 of PCI slave pizza arbiter.
+ * 11:08 Arb2 Slice 2 of PCI slave pizza arbiter.
+ * 15:12 Arb3 Slice 3 of PCI slave pizza arbiter.
+ * 19:16 Arb4 Slice 4 of PCI slave pizza arbiter.
+ * 23:20 Arb5 Slice 5 of PCI slave pizza arbiter.
+ * 27:24 Arb6 Slice 6 of PCI slave pizza arbiter.
+ * 31:28 Arb7 Slice 7 of PCI slave pizza arbiter.
+ */
+#define PCI_RRXBRCL_GET_SLICE(v, n) PCI__EXT(v, (n) * 4, 4)
+#define PCI_RRXBRCL_SET_SLICE(v, n, s) ((void)(PCI__CLR(v, (n)*4, 4),\
+ (v) |= PCI__INS((n)*4, s)))
+
+
+/*
+ * Table 265: PCI Read Response Crossbar Control (High)
+ * 03:00 Arb8 Slice 8 of PCI slave pizza arbiter.
+ * 07:04 Arb9 Slice 9 of PCI slave pizza arbiter.
+ * 11:08 Arb10 Slice 10 of PCI slave pizza arbiter.
+ * 15:12 Arb11 Slice 11 of PCI slave pizza arbiter.
+ * 19:16 Arb12 Slice 12 of PCI slave pizza arbiter.
+ * 23:20 Arb13 Slice 13 of PCI slave pizza arbiter.
+ * 27:24 Arb14 Slice 14 of PCI slave pizza arbiter.
+ * 31:28 Arb15 Slice 15 of PCI slave pizza arbiter.
+ */
+#define PCI_RRXBRCH_GET_SLICE(v, n) PCI__EXT(v, ((n) - 8) * 4, 4)
+#define PCI_RRXBRCH_SET_SLICE(v, n, s) ((void)(PCI__CLR(v, ((n)*-8)4, 4),\
+ (v) |= PCI__INS(((n)-8)*4, s)))
+
+/*
+ * Table 266: PCI Sync Barrier Virtual Register
+ * 31:0 SyncReg Sync Barrier Virtual Register
+ * PCI read from this register results in PCI slave sync barrier
+ * action. The returned data is un-deterministic. Read Only.
+ */
+
+/*
+ * Table 267: PCI P2P Configuration
+ * 07:00 2ndBusL Secondary PCI Interface Bus Range Lower Boundary
+ * 15:08 2ndBusH Secondary PCI Interface Bus Range Upper Boundary
+ * 23:16 BusNum The PCI bus number to which the PCI interface
+ * is connected.
+ * 28:24 DevNum The PCI interface's device number.
+ * 31:29 Reserved Reserved.
+ */
+#define PCI_P2PCFG_2ndBusL_GET(v) PCI__EXT(v, 0, 8)
+#define PCI_P2PCFG_2ndBusH_GET(v) PCI__EXT(v, 8, 8)
+#define PCI_P2PCFG_BusNum_GET(v) PCI__EXT(v, 16, 8)
+#define PCI_P2PCFG_DevNum_GET(v) PCI__EXT(v, 24, 5)
+
+/*
+ * Table 268: PCI P2P Swap Control
+ * 02:00 M0Sw P2P Mem0 BAR Swap Control
+ * 03:03 M0Req64 P2P Mem0 BAR Force REQ64
+ * 06:04 M1Sw P2P Mem1 BAR Swap Control
+ * 07:07 M1Req64 P2P Mem1 BAR Force REQ64
+ * 10:08 DM0Sw P2P DAC Mem0 BAR Swap Control
+ * 11:11 DM0Req64 P2P DAC Mem0 BAR Force REQ64
+ * 14:12 DM1Sw P2P DAC Mem1 BAR Swap Control
+ * 15:15 DM1Req64 P2P DAC Mem1 BAR Force REQ64
+ * 18:16 IOSw P2P I/O BAR Swap Control
+ * 19:19 Reserved
+ * 22:20 CfgSw P2P Configuration Swap Control
+ * 31:19 Reserved
+ */
+#define PCI_P2PSWAP_M0Sw_GET(v) PCI__EXT(v, 0, 3)
+#define PCI_P2PSWAP_M0Req64 PCI__BIT(3)
+#define PCI_P2PSWAP_M1Sw_GET(v) PCI__EXT(v, 4, 3)
+#define PCI_P2PSWAP_M1Req64 PCI__BIT(7)
+#define PCI_P2PSWAP_DM0Sw_GET(v) PCI__EXT(v, 8, 3)
+#define PCI_P2PSWAP_DM0Req64 PCI__BIT(11)
+#define PCI_P2PSWAP_DM1Sw_GET(v) PCI__EXT(v, 12, 3)
+#define PCI_P2PSWAP_DM1Req64 PCI__BIT(15)
+#define PCI_P2PSWAP_CfgSw_GET(v) PCI__EXT(v, 20, 3)
+
+
+
+/*
+ * Table 269: PCI Access Control Base (Low)
+ * 11:00 Addr Base Address Corresponds to address bits[31:20].
+ * 12:12 PrefetchEn Read Prefetch Enable
+ * 0: Prefetch disabled (The PCI slave reads single words)
+ * 1: Prefetch enabled.
+ * 14:14 Reserved Must be 0
+ * 15:15 Reserved
+ * 16:16 RdPrefetch PCI Read Aggressive Prefetch Enable; 0: Disable;
+ * 1: Enable (The PCI slave prefetches two
+ * bursts in advance)
+ * 17:17 RdLinePrefetch PCI Read Line Aggressive Prefetch Enable; 0: Disable;
+ * 1: Enable (PCI slave prefetch two bursts in advance)
+ * 18:18 RdMulPrefetch PCI Read Multiple Aggressive Prefetch Enable
+ * 0: Disable; 1: Enable (PCI slave prefetch two bursts in
+ * advance)
+ * 19:19 Reserved
+ * 21:20 MBurst PCI Max Burst
+ * Specifies the maximum burst size for a single transac-
+ * tion between a PCI slave and the other interfaces
+ * 00 - 4 64-bit words
+ * 01 - 8 64-bit words
+ * 10 - 16 64-bit words
+ * 11 - Reserved
+ * 23:22 Reserved
+ * 25:24 PCISwap Data Swap Control
+ * 00 - Byte Swap
+ * 01 - No swapping
+ * 10 - Both byte and word swap
+ * 11 - Word swap
+ * 26:26 Reserved Must be 0
+ * 27:27 Reserved
+ * 28:28 AccProt Access Protect (0: PCI access is allowed; 1; Region is
+ not accessible from PCI)
+ * 29:29 WrProt Write Protect (0: PCI write is allowed; 1: Region is
+ * not writeable from PCI)
+ * 31:30 Reserved
+ */
+#define PCI_ACCCTLBASEL_Addr_GET(v) PCI__EXT(v, 0, 12)
+#define PCI_ACCCTLBASEL_PrefetchEn PCI__BIT(12)
+#define PCI_ACCCTLBASEL_MBZ0_14 PCI__BIT(14)
+#define PCI_ACCCTLBASEL_RdPrefetch PCI__BIT(16)
+#define PCI_ACCCTLBASEL_RdLinePrefetch PCI__BIT(17)
+#define PCI_ACCCTLBASEL_RdMulPrefetch PCI__BIT(18)
+#define PCI_ACCCTLBASEL_WBurst PCI__EXT(v, 20, 2)
+#define PCI_ACCCTLBASEL_WBurst_8_QW PCI__INS(20, PCI_WBURST_8_QW)
+#define PCI_ACCCTLBASEL_PCISwap PCI__EXT(v, 24, 2)
+#define PCI_ACCCTLBASEL_PCISwap_NoSwap PCI__INS(24, PCI_PCISWAP_NoSwap)
+#define PCI_ACCCTLBASEL_MBZ0_26 PCI__BIT(26)
+#define PCI_ACCCTLBASEL_AccProt PCI__BIT(28)
+#define PCI_ACCCTLBASEL_WrProt PCI__BIT(29)
+
+#define PCI_WBURST_4_QW 0x00
+#define PCI_WBURST_8_QW 0x01
+#define PCI_WBURST_16_QW 0x02
+#define PCI_WBURST_Reserved 0x04
+
+#define PCI_PCISWAP_ByteSwap 0x00
+#define PCI_PCISWAP_NoSwap 0x01
+#define PCI_PCISWAP_ByteWordSwap 0x02
+#define PCI_PCISWAP_WordSwap 0x04
+
+/*
+ * Table 293: PCI Snoop Control Base (Low)
+ * 11:00 Addr Base Address Corresponds to address bits[31:20].
+ * 13:12 Snoop Snoop Type
+ * 31:14 Reserved
+ */
+#define PCI_SNOOPCTL_ADDR(v) PCI__EXT(v, 0, 12)
+#define PCI_SNOOPCTL_TYPE(v) PCI__EXT(v, 12, 2)
+
+#define PCI_SNOOP_None 0 /* no snoop */
+#define PCI_SNOOP_WT 1 /* Snoop to WT region */
+#define PCI_SNOOP_WB 2 /* Snoop to WB region */
+
+
+/*
+ * Table 305: PCI Configuration Address
+ *
+ * 07:02 RegNum Register number.
+ * 10:08 FunctNum Function number.
+ * 15:11 DevNum Device number.
+ * 23:16 BusNum Bus number.
+ * 31:31 ConfigEn When set, an access to the Configuration Data
+ * register is translated into a Configuration
+ * or Special cycle on the PCI bus.
+ */
+#define PCI_CFG_MAKE_TAG(bus, dev, fun, reg) (PCI__BIT(31)|\
+ PCI__INS(16, (bus))|\
+ PCI__INS(11, (dev))|\
+ PCI__INS( 8, (fun))|\
+ PCI__INS( 0, (reg)))
+#define PCI_CFG_GET_BUSNO(tag) PCI__EXT(tag, 16, 8)
+#define PCI_CFG_GET_DEVNO(tag) PCI__EXT(tag, 11, 5)
+#define PCI_CFG_GET_FUNCNO(tag) PCI__EXT(tag, 8, 3)
+#define PCI_CFG_GET_REGNO(tag) PCI__EXT(tag, 0, 8)
+
+/*
+ * Table 306: PCI Configuration Data
+ *
+ * 31:00 ConfigData The data is transferred to/from the PCI bus when
+ * the CPU accesses this register and the ConfigEn
+ * bit in the Configuration Address register is set
+ *
+ * A CPU access to this register causes the GT64260 to perform a Configuration
+ * or Special cycle on the PCI bus.
+ */
+
+
+/*
+ * Table 307: PCI Interrupt Acknowledge (This register is READ ONLY)
+ * 31:00 IntAck A CPU read access to this register forces an
+ * interrupt acknowledge cycle on the PCI bus.
+ */
+
+
+/*
+ * Table 308: PCI SERR* Mask
+ *
+ * NOTE: The GT64260 asserts SERR* only if SERR* is enabled via the PCI Status
+ * and Command register.
+ * If the corresponding bit is set, then asserts SERR* upon ...
+ */
+#define PCI_SERRMSK_SAPerr PCI__BIT(0) /* PCI slave detection of bad
+ * address parity. */
+#define PCI_SERRMSK_SWrPerr PCI__BIT(1) /* PCI slave detection of bad
+ * write data parity. */
+#define PCI_SERRMSK_SRdPerr PCI__BIT(2) /* a PERR* response to read
+ * data driven by the PCI
+ * slave. */
+#define PCI_SERRMSK_MAPerr PCI__BIT(4) /* a PERR* response to an
+ * address driven by the PCI
+ * master. */
+#define PCI_SERRMSK_MWrPerr PCI__BIT(5) /* a PERR* response to write
+ * data driven by the PCI
+ * master. */
+#define PCI_SERRMSK_MRdPerr PCI__BIT(6) /* bad data parity detection
+ * during a PCI master read
+ * transaction. */
+#define PCI_SERRMSK_MMabort PCI__BIT(8) /* a PCI master generation of
+ * master abort. */
+#define PCI_SERRMSK_MTabort PCI__BIT(9) /* a PCI master detection of
+ * target abort. */
+#define PCI_SERRMSK_MRetry PCI__BIT(11) /* a PCI master reaching retry
+ * counter limit. */
+#define PCI_SERRMSK_SMabort PCI__BIT(16) /* a PCI slave detection of
+ * master abort. */
+#define PCI_SERRMSK_STabort PCI__BIT(17) /* a PCI slave termination of
+ * a transaction with Target
+ * Abort. */
+#define PCI_SERRMSK_SAccProt PCI__BIT(18) /* a PCI slave access protect
+ * violation. */
+#define PCI_SERRMSK_SWrProt PCI__BIT(19) /* a PCI slave write protect
+ * violation. */
+#define PCI_SERRMSK_SRdBuf PCI__BIT(20) /* the PCI slave's read buffer,
+ * discard timer expires */
+#define PCI_SERRMSK_Arb PCI__BIT(21) /* the internal PCI arbiter
+ * detection of a broken PCI
+ * master. */
+
+#define PCI_SERRMSK_ALL_ERRS \
+ (PCI_SERRMSK_SAPerr|PCI_SERRMSK_SWrPerr|PCI_SERRMSK_SRdPerr \
+ |PCI_SERRMSK_MAPerr|PCI_SERRMSK_MWrPerr|PCI_SERRMSK_MRdPerr \
+ |PCI_SERRMSK_MMabort|PCI_SERRMSK_MTabort|PCI_SERRMSK_MRetry \
+ |PCI_SERRMSK_SMabort|PCI_SERRMSK_STabort|PCI_SERRMSK_SAccProt \
+ |PCI_SERRMSK_SWrProt|PCI_SERRMSK_SRdBuf|PCI_SERRMSK_Arb)
+
+
+
+/*
+ * Table 309: PCI Error Address (Low) -- Read Only.
+ * 31:00 ErrAddr PCI address bits [31:0] are latched upon an error
+ * condition. Upon address latch, no new addresses can
+ * be registered (due to additional error condition) until
+ * the register is being read.
+ */
+
+
+
+/*
+ * Table 310: PCI Error Address (High) Applicable only when running DAC cycles.
+ * 31:00 ErrAddr PCI address bits [63:32] are latched upon
+ * error condition.
+ *
+ * NOTE: Upon data sample, no new data is latched until the PCI Error Low
+ * Address register is read. This means that PCI Error Low Address
+ * register must bethe last register read by the interrupt handler.
+ */
+
+/*
+ * Table 311: PCI Error Data (Low)
+ * 31:00 ErrData PCI data bits [31:00] are latched upon error condition.
+ */
+
+/*
+ * Table 312: PCI Error Data (High) Applicable only when running
+ * 64-bit cycles.
+ * 31:00 ErrData PCI data bits [63:32] are latched upon error condition.
+ */
+
+/*
+ * Table 313: PCI Error Command
+ * 03:00 ErrCmd PCI command is latched upon error condition.
+ * 07:04 Reserved
+ * 15:08 ErrBE PCI byte enable is latched upon error condition.
+ * 16:16 ErrPAR PCI PAR is latched upon error condition.
+ * 17:17 ErrPAR64 PCI PAR64 is latched upon error condition.
+ * Applicable only when running 64-bit cycles.
+ * 31:18 Reserved
+ * NOTE: Upon data sample, no new data is latched until the PCI Error Low
+ * Address register is read. This means that PCI Error Low Address register
+ * must be the last register read by the interrupt handler.
+ */
+#define PCI_ERRCMD_Cmd_GET(v) PCI__EXT(v, 0, 4)
+#define PCI_ERRCMD_ByteEn_GET(v) PCI__EXT(v, 8, 8)
+#define PCI_ERRCMD_PAR PCI__BIT(16)
+#define PCI_ERRCMD_PAR64 PCI__BIT(17)
+
+/*
+ * Table 314: PCI Interrupt Cause
+ * 1. All bits are Clear Only. A cause bit set upon error event occurrence.
+ * A write of 0 clears the bit. A write of 1 has no affect.
+ * 2. PCI Interrupt bits are organized in four groups:
+ * bits[ 7: 0] for address and data parity errors,
+ * bits[15: 8] for PCI master transaction failure (possible external
+ * target problem),
+ * bits[23:16] for slave response failure (possible external master problem),
+ * bits[26:24] for external PCI events that require CPU handle.
+ */
+#define PCI_IC_SAPerr PCI__BIT(0) /* The PCI slave detected
+ * bad address parity. */
+#define PCI_IC_SWrPerr PCI__BIT(1) /* The PCI slave detected
+ * bad write data parity. */
+#define PCI_IC_SRdPerr PCI__BIT(2) /* PERR* response to read
+ * data driven by PCI slave. */
+#define PCI_IC_MAPerr PCI__BIT(4) /* PERR* response to address
+ * driven by the PCI master. */
+#define PCI_IC_MWrPerr PCI__BIT(5) /* PERR* response to write data
+ * driven by the PCI master. */
+#define PCI_IC_MRdPerr PCI__BIT(6) /* Bad data parity detected
+ * during the PCI master read
+ * transaction. */
+#define PCI_IC_MMabort PCI__BIT(8) /* The PCI master generated
+ * master abort. */
+#define PCI_IC_MTabort PCI__BIT(9) /* The PCI master detected
+ * target abort. */
+#define PCI_IC_MMasterEn PCI__BIT(10) /* An attempt to generate a PCI
+ * transaction while master is
+ * not enabled. */
+#define PCI_IC_MRetry PCI__BIT(11) /* The PCI master reached
+ * retry counter limit. */
+#define PCI_IC_SMabort PCI__BIT(16) /* The PCI slave detects an il-
+ * legal master termination. */
+#define PCI_IC_STabort PCI__BIT(17) /* The PCI slave terminates a
+ * transaction with Target
+ * Abort. */
+#define PCI_IC_SAccProt PCI__BIT(18) /* A PCI slave access protect
+ * violation. */
+#define PCI_IC_SWrProt PCI__BIT(19) /* A PCI slave write protect
+ * violation. */
+#define PCI_IC_SRdBuf PCI__BIT(20) /* A PCI slave read buffer
+ * discard timer expired. */
+#define PCI_IC_Arb PCI__BIT(21) /* Internal PCI arbiter detec-
+ * tion of a broken master. */
+#define PCI_IC_BIST PCI__BIT(24) /* PCI BIST Interrupt */
+#define PCI_IC_PMG PCI__BIT(25) /* PCI Power Management
+ * Interrupt */
+#define PCI_IC_PRST PCI__BIT(26) /* PCI Reset Assert */
+
+/*
+31:27 Sel Specifies the error event currently being reported in the
+Error Address, Error Data, and Error Command registers.
+*/
+#define PCI_IC_SEL_GET(v) PCI__EXT((v), 27, 5)
+#define PCI_IC_SEL_SAPerr 0x00
+#define PCI_IC_SEL_SWrPerr 0x01
+#define PCI_IC_SEL_SRdPerr 0x02
+#define PCI_IC_SEL_MAPerr 0x04
+#define PCI_IC_SEL_MWrPerr 0x05
+#define PCI_IC_SEL_MRdPerr 0x06
+#define PCI_IC_SEL_MMabort 0x08
+#define PCI_IC_SEL_MTabort 0x09
+#define PCI_IC_SEL_MMasterEn 0x0a
+#define PCI_IC_SEL_MRetry 0x0b
+#define PCI_IC_SEL_SMabort 0x10
+#define PCI_IC_SEL_STabort 0x11
+#define PCI_IC_SEL_SAccProt 0x12
+#define PCI_IC_SEL_SWrProt 0x13
+#define PCI_IC_SEL_SRdBuf 0x14
+#define PCI_IC_SEL_Arb 0x15
+#define PCI_IC_SEL_BIST 0x18
+#define PCI_IC_SEL_PMG 0x19
+#define PCI_IC_SEL_PRST 0x1a
+
+#define PCI_IC_SEL_Strings { \
+ "SAPerr", "SWrPerr", "SRdPerr", "Rsvd#03", \
+ "MAPerr", "MWrPerr", "MRdPerr", "Rsvd#07", \
+ "MMabort", "MTabort", "MMasterEn", "MRetry", \
+ "Rsvd#0c", "Rsvd#0d", "Rsvd#0e", "Rsvd#0f", \
+ "SMabort", "STabort", "SAccProt", "SWrProt", \
+ "SRdBuf", "Arb", "Rsvd#16", "Rsvd#17", \
+ "BIST", "PMG", "PRST", "Rsvd#1b", \
+ "Rsvd#1c", "Rsvd#1d", "Rsvd#1e", "Rsvd#1f" }
+
+/*
+ * Table 315: PCI Error Mask
+ * If the corresponding bit is 1, that interrupt is enabled
+ * Bits 3, 7, 12:15, 22:23, 27:31 are reserved.
+ */
+#define PCI_ERRMASK_SAPErr PCI__BIT(0)
+#define PCI_ERRMASK_SWrPErr PCI__BIT(1)
+#define PCI_ERRMASK_SRdPErr PCI__BIT(2)
+#define PCI_ERRMASK_MAPErr PCI__BIT(4)
+#define PCI_ERRMASK_MWRPErr PCI__BIT(5)
+#define PCI_ERRMASK_MRDPErr PCI__BIT(6)
+#define PCI_ERRMASK_MMAbort PCI__BIT(8)
+#define PCI_ERRMASK_MTAbort PCI__BIT(9)
+#define PCI_ERRMASK_MMasterEn PCI__BIT(10)
+#define PCI_ERRMASK_MRetry PCI__BIT(11)
+#define PCI_ERRMASK_SMAbort PCI__BIT(16)
+#define PCI_ERRMASK_STAbort PCI__BIT(17)
+#define PCI_ERRMASK_SAccProt PCI__BIT(18)
+#define PCI_ERRMASK_SWrProt PCI__BIT(19)
+#define PCI_ERRMASK_SRdBuf PCI__BIT(20)
+#define PCI_ERRMASK_Arb PCI__BIT(21)
+#define PCI_ERRMASK_BIST PCI__BIT(24)
+#define PCI_ERRMASK_PMG PCI__BIT(25)
+#define PCI_ERRMASK_PRST PCI__BIT(26)
+
+#endif /* _DEV_GTPCIREG_H_ */
diff --git a/c/src/lib/libbsp/powerpc/beatnik/marvell/gtreg.h b/c/src/lib/libbsp/powerpc/beatnik/marvell/gtreg.h
new file mode 100644
index 0000000000..a6c87e2047
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/beatnik/marvell/gtreg.h
@@ -0,0 +1,854 @@
+/* $NetBSD: gtreg.h,v 1.2 2005/02/27 00:27:21 perry Exp $ */
+
+/*
+ * Copyright (c) 2002 Allegro Networks, Inc., Wasabi Systems, Inc.
+ * All rights reserved. *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed for the NetBSD Project by
+ * Allegro Networks, Inc., and Wasabi Systems, Inc.
+ * 4. The name of Allegro Networks, Inc. may not be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ * 5. The name of Wasabi Systems, Inc. may not be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ALLEGRO NETWORKS, INC. AND
+ * WASABI SYSTEMS, INC. ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL EITHER ALLEGRO NETWORKS, INC. OR WASABI SYSTEMS, INC.
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _DISCOVERY_DEV_GTREG_H_
+#define _DISCOVERY_DEV_GTREG_H_
+
+
+#define GT__BIT(bit) (1U << (bit))
+#define GT__MASK(bit) (GT__BIT(bit) - 1)
+#define GT__EXT(data, bit, len) (((data) >> (bit)) & GT__MASK(len))
+#define GT__CLR(data, bit, len) ((data) &= ~(GT__MASK(len) << (bit)))
+#define GT__INS(new, bit) ((new) << (bit))
+
+
+/*
+ * Table 30: CPU Address Decode Register Map
+ */
+#define GT_SCS0_Low_Decode 0x0008
+#define GT_SCS0_High_Decode 0x0010
+#define GT_SCS1_Low_Decode 0x0208
+#define GT_SCS1_High_Decode 0x0210
+#define GT_SCS2_Low_Decode 0x0018
+#define GT_SCS2_High_Decode 0x0020
+#define GT_SCS3_Low_Decode 0x0218
+#define GT_SCS3_High_Decode 0x0220
+#define GT_CS0_Low_Decode 0x0028
+#define GT_CS0_High_Decode 0x0030
+#define GT_CS1_Low_Decode 0x0228
+#define GT_CS1_High_Decode 0x0230
+#define GT_CS2_Low_Decode 0x0248
+#define GT_CS2_High_Decode 0x0250
+#define GT_CS3_Low_Decode 0x0038
+#define GT_CS3_High_Decode 0x0040
+#define GT_BootCS_Low_Decode 0x0238
+#define GT_BootCS_High_Decode 0x0240
+#define GT_PCI0_IO_Low_Decode 0x0048
+#define GT_PCI0_IO_High_Decode 0x0050
+#define GT_PCI0_Mem0_Low_Decode 0x0058
+#define GT_PCI0_Mem0_High_Decode 0x0060
+#define GT_PCI0_Mem1_Low_Decode 0x0080
+#define GT_PCI0_Mem1_High_Decode 0x0088
+#define GT_PCI0_Mem2_Low_Decode 0x0258
+#define GT_PCI0_Mem2_High_Decode 0x0260
+#define GT_PCI0_Mem3_Low_Decode 0x0280
+#define GT_PCI0_Mem3_High_Decode 0x0288
+#define GT_PCI1_IO_Low_Decode 0x0090
+#define GT_PCI1_IO_High_Decode 0x0098
+#define GT_PCI1_Mem0_Low_Decode 0x00a0
+#define GT_PCI1_Mem0_High_Decode 0x00a8
+#define GT_PCI1_Mem1_Low_Decode 0x00b0
+#define GT_PCI1_Mem1_High_Decode 0x00b8
+#define GT_PCI1_Mem2_Low_Decode 0x02a0
+#define GT_PCI1_Mem2_High_Decode 0x02a8
+#define GT_PCI1_Mem3_Low_Decode 0x02b0
+#define GT_PCI1_Mem3_High_Decode 0x02b8
+#define GT_Internal_Decode 0x0068
+#define GT_CPU0_Low_Decode 0x0290
+#define GT_CPU0_High_Decode 0x0298
+#define GT_CPU1_Low_Decode 0x02c0
+#define GT_CPU1_High_Decode 0x02c8
+/* ts, 2005/8: it seems that these are implicitely written
+ * when setting the 'Low_Decode' regs...
+ */
+#define GT_PCI0_IO_Remap 0x00f0
+#define GT_PCI0_Mem0_Remap_Low 0x00f8
+#define GT_PCI0_Mem0_Remap_High 0x0320
+#define GT_PCI0_Mem1_Remap_Low 0x0100
+#define GT_PCI0_Mem1_Remap_High 0x0328
+#define GT_PCI0_Mem2_Remap_Low 0x02f8
+#define GT_PCI0_Mem2_Remap_High 0x0330
+#define GT_PCI0_Mem3_Remap_Low 0x0300
+#define GT_PCI0_Mem3_Remap_High 0x0338
+#define GT_PCI1_IO_Remap 0x0108
+#define GT_PCI1_Mem0_Remap_Low 0x0110
+#define GT_PCI1_Mem0_Remap_High 0x0340
+#define GT_PCI1_Mem1_Remap_Low 0x0118
+#define GT_PCI1_Mem1_Remap_High 0x0348
+#define GT_PCI1_Mem2_Remap_Low 0x0310
+#define GT_PCI1_Mem2_Remap_High 0x0350
+#define GT_PCI1_Mem3_Remap_Low 0x0318
+#define GT_PCI1_Mem3_Remap_High 0x0358
+
+
+/*
+ * Table 31: CPU Control Register Map
+ */
+#define GT_CPU_Cfg 0x0000
+#define GT_CPU_Mode 0x0120
+#define GT_CPU_Master_Ctl 0x0160
+#define GT_CPU_If_Xbar_Ctl_Low 0x0150
+#define GT_CPU_If_Xbar_Ctl_High 0x0158
+#define GT_CPU_If_Xbar_Timeout 0x0168
+#define GT_260_CPU_Rd_Rsp_Xbar_Ctl_Low 0x0170
+#define GT_260_CPU_Rd_Rsp_Xbar_Ctl_High 0x0178
+
+/*
+ * Table 32: CPU Sync Barrier Register Map
+ */
+#define GT_260_PCI_Sync_Barrier(bus) (0x00c0 | ((bus) << 3))
+#define GT_260_PCI0_Sync_Barrier 0x00c0
+#define GT_260_PCI1_Sync_Barrier 0x00c8
+
+/*
+ * Table 33: CPU Access Protection Register Map
+ */
+#define GT_Protect_Low_0 0x0180
+#define GT_Protect_High_0 0x0188
+#define GT_Protect_Low_1 0x0190
+#define GT_Protect_High_1 0x0198
+#define GT_Protect_Low_2 0x01a0
+#define GT_Protect_High_2 0x01a8
+#define GT_Protect_Low_3 0x01b0
+#define GT_Protect_High_3 0x01b8
+#define GT_260_Protect_Low_4 0x01c0
+#define GT_260_Protect_High_4 0x01c8
+#define GT_260_Protect_Low_5 0x01d0
+#define GT_260_Protect_High_5 0x01d8
+#define GT_260_Protect_Low_6 0x01e0
+#define GT_260_Protect_High_6 0x01e8
+#define GT_260_Protect_Low_7 0x01f0
+#define GT_260_Protect_High_7 0x01f8
+
+/*
+ * Table 34: Snoop Control Register Map
+ */
+#define GT_260_Snoop_Base_0 0x0380
+#define GT_260_Snoop_Top_0 0x0388
+#define GT_260_Snoop_Base_1 0x0390
+#define GT_260_Snoop_Top_1 0x0398
+#define GT_260_Snoop_Base_2 0x03a0
+#define GT_260_Snoop_Top_2 0x03a8
+#define GT_260_Snoop_Base_3 0x03b0
+#define GT_260_Snoop_Top_3 0x03b8
+
+/*
+ * Table 35: CPU Error Report Register Map
+ */
+#define GT_CPU_Error_Address_Low 0x0070
+#define GT_CPU_Error_Address_High 0x0078
+#define GT_CPU_Error_Data_Low 0x0128
+#define GT_CPU_Error_Data_High 0x0130
+#define GT_CPU_Error_Parity 0x0138
+#define GT_CPU_Error_Cause 0x0140
+#define GT_CPU_Error_Mask 0x0148
+
+#define GT_DecodeAddr_SET(g, r, v) \
+ do { \
+ gt_read((g), GT_Internal_Decode); \
+ gt_write((g), (r), ((v) & 0xfff00000) >> 20); \
+ while ((gt_read((g), (r)) & 0xfff) != ((v) >> 20)); \
+ } while (0)
+
+#define GT_LowAddr_GET(v) (GT__EXT((v), 0, 12) << 20)
+#define GT_HighAddr_GET(v) ((GT__EXT((v), 0, 12) << 20) | 0xfffff)
+
+#define GT_MPP_Control0 0xf000
+#define GT_MPP_Control1 0xf004
+#define GT_MPP_Control2 0xf008
+#define GT_MPP_Control3 0xf00c
+
+#define GT_GPP_IO_Control 0xf100
+#define GT_GPP_Level_Control 0xf110
+#define GT_GPP_Value 0xf104
+#define GT_GPP_Interrupt_Cause 0xf108
+#define GT_GPP_Interrupt_Mask 0xf10c
+/*
+ * Table 36: SCS[0]* Low Decode Address, Offset: 0x008
+ * Table 38: SCS[1]* Low Decode Address, Offset: 0x208
+ * Table 40: SCS[2]* Low Decode Address, Offset: 0x018
+ * Table 42: SCS[3]* Low Decode Address, Offset: 0x218
+ * Table 44: CS[0]* Low Decode Address, Offset: 0x028
+ * Table 46: CS[1]* Low Decode Address, Offset: 0x228
+ * Table 48: CS[2]* Low Decode Address, Offset: 0x248
+ * Table 50: CS[3]* Low Decode Address, Offset: 0x038
+ * Table 52: BootCS* Low Decode Address, Offset: 0x238
+ * Table 75: CPU 0 Low Decode Address, Offset: 0x290
+ * Table 77: CPU 1 Low Decode Address, Offset: 0x2c0
+ *
+ * 11:00 LowAddr SCS[0] Base Address
+ * 31:12 Reserved Must be 0.
+ */
+
+/*
+ * Table 37: SCS[0]* High Decode Address, Offset: 0x010
+ * Table 39: SCS[1]* High Decode Address, Offset: 0x210
+ * Table 41: SCS[2]* High Decode Address, Offset: 0x020
+ * Table 43: SCS[3]* High Decode Address, Offset: 0x220
+ * Table 45: CS[0]* High Decode Address, Offset: 0x030
+ * Table 47: CS[1]* High Decode Address, Offset: 0x230
+ * Table 49: CS[2]* High Decode Address, Offset: 0x250
+ * Table 51: CS[3]* High Decode Address, Offset: 0x040
+ * Table 53: BootCS* High Decode Address, Offset: 0x240
+ * Table 76: CPU 0 High Decode Address, Offset: 0x298
+ * Table 78: CPU 1 High Decode Address, Offset: 0x2c8
+ *
+ * 11:00 HighAddr SCS[0] Top Address
+ * 31:12 Reserved
+ */
+
+/*
+ * Table 54: PCI_0 I/O Low Decode Address, Offset: 0x048
+ * Table 56: PCI_0 Memory 0 Low Decode Address, Offset: 0x058
+ * Table 58: PCI_0 Memory 1 Low Decode Address, Offset: 0x080
+ * Table 60: PCI_0 Memory 2 Low Decode Address, Offset: 0x258
+ * Table 62: PCI_0 Memory 3 Low Decode Address, Offset: 0x280
+ * Table 64: PCI_1 I/O Low Decode Address, Offset: 0x090
+ * Table 66: PCI_1 Memory 0 Low Decode Address, Offset: 0x0a0
+ * Table 68: PCI_1 Memory 1 Low Decode Address, Offset: 0x0b0
+ * Table 70: PCI_1 Memory 2 Low Decode Address, Offset: 0x2a0
+ * Table 72: PCI_1 Memory 3 Low Decode Address, Offset: 0x2b0
+ *
+ * 11:00 LowAddr PCI IO/Memory Space Base Address
+ * 23:12 Reserved
+ * 26:24 PCISwap PCI Master Data Swap Control (0: Byte Swap;
+ * 1: No swapping; 2: Both byte and word swap;
+ * 3: Word swap; 4..7: Reserved)
+ * 27:27 PCIReq64 PCI master REQ64* policy (Relevant only when
+ * configured to 64-bit PCI bus and not I/O)
+ * 0: Assert s REQ64* only when transaction
+ * is longer than 64-bits.
+ * 1: Always assert REQ64*.
+ * 31:28 Reserved
+ */
+#define GT_PCISwap_GET(v) GT__EXT((v), 24, 3)
+#define GT_PCISwap_ByteSwap 0
+#define GT_PCISwap_NoSwap 1
+#define GT_PCISwap_ByteWordSwap 2
+#define GT_PCISwap_WordSwap 3
+#define GT_PCI_LowDecode_PCIReq64 GT__BIT(27)
+
+/*
+ * Table 55: PCI_0 I/O High Decode Address, Offset: 0x050
+ * Table 57: PCI_0 Memory 0 High Decode Address, Offset: 0x060
+ * Table 59: PCI_0 Memory 1 High Decode Address, Offset: 0x088
+ * Table 61: PCI_0 Memory 2 High Decode Address, Offset: 0x260
+ * Table 63: PCI_0 Memory 3 High Decode Address, Offset: 0x288
+ * Table 65: PCI_1 I/O High Decode Address, Offset: 0x098
+ * Table 67: PCI_1 Memory 0 High Decode Address, Offset: 0x0a8
+ * Table 69: PCI_1 Memory 1 High Decode Address, Offset: 0x0b8
+ * Table 71: PCI_1 Memory 2 High Decode Address, Offset: 0x2a8
+ * Table 73: PCI_1 Memory 3 High Decode Address, Offset: 0x2b8
+ *
+ * 11:00 HighAddr PCI_0 I/O Space Top Address
+ * 31:12 Reserved
+ */
+
+/*
+ * Table 74: Internal Space Decode, Offset: 0x068
+ * 15:00 IntDecode GT64260 Internal Space Base Address
+ * 23:16 Reserved
+ * 26:24 PCISwap Same as PCI_0 Memory 0 Low Decode Address.
+ * NOTE: Reserved for Galileo Technology usage.
+ * Relevant only for PCI master configuration
+ * transactions on the PCI bus.
+ * 31:27 Reserved
+ */
+
+/*
+ * Table 79: PCI_0 I/O Address Remap, Offset: 0x0f0
+ * Table 80: PCI_0 Memory 0 Address Remap Low, Offset: 0x0f8
+ * Table 82: PCI_0 Memory 1 Address Remap Low, Offset: 0x100
+ * Table 84: PCI_0 Memory 2 Address Remap Low, Offset: 0x2f8
+ * Table 86: PCI_0 Memory 3 Address Remap Low, Offset: 0x300
+ * Table 88: PCI_1 I/O Address Remap, Offset: 0x108
+ * Table 89: PCI_1 Memory 0 Address Remap Low, Offset: 0x110
+ * Table 91: PCI_1 Memory 1 Address Remap Low, Offset: 0x118
+ * Table 93: PCI_1 Memory 2 Address Remap Low, Offset: 0x310
+ * Table 95: PCI_1 Memory 3 Address Remap Low, Offset: 0x318
+ *
+ * 11:00 Remap PCI IO/Memory Space Address Remap (31:20)
+ * 31:12 Reserved
+ */
+
+/*
+ * Table 81: PCI_0 Memory 0 Address Remap High, Offset: 0x320
+ * Table 83: PCI_0 Memory 1 Address Remap High, Offset: 0x328
+ * Table 85: PCI_0 Memory 2 Address Remap High, Offset: 0x330
+ * Table 87: PCI_0 Memory 3 Address Remap High, Offset: 0x338
+ * Table 90: PCI_1 Memory 0 Address Remap High, Offset: 0x340
+ * Table 92: PCI_1 Memory 1 Address Remap High, Offset: 0x348
+ * Table 94: PCI_1 Memory 2 Address Remap High, Offset: 0x350
+ * Table 96: PCI_1 Memory 3 Address Remap High, Offset: 0x358
+ *
+ * 31:00 Remap PCI Memory Address Remap (high 32 bits)
+ */
+
+/*
+ * Table 97: CPU Configuration, Offset: 0x000
+ * 07:00 NoMatchCnt CPU Address Miss Counter
+ * 08:08 NoMatchCntEn CPU Address Miss Counter Enable
+ * NOTE: Relevant only if multi-GT is enabled.
+ * (0: Disabled; 1: Enabled)
+ * 09:09 NoMatchCntExt CPU address miss counter MSB
+ * 10:10 Reserved
+ * 11:11 AACKDelay Address Acknowledge Delay
+ * 0: AACK* is asserted one cycle after TS*.
+ * 1: AACK* is asserted two cycles after TS*.
+ * 12:12 Endianess Must be 0
+ * NOTE: The GT64260 does not support the PowerPC
+ * Little Endian convention
+ * 13:13 Pipeline Pipeline Enable
+ * 0: Disabled. The GT64260 will not respond with
+ * AACK* to a new CPU transaction, before the
+ * previous transaction data phase completes.
+ * 1: Enabled.
+ * 14:14 Reserved
+ * 15:15 TADelay Transfer Acknowledge Delay
+ * 0: TA* is asserted one cycle after AACK*
+ * 1: TA* is asserted two cycles after AACK*
+ * 16:16 RdOOO Read Out of Order Completion
+ * 0: Not Supported, Data is always returned in
+ * order (DTI[0-2] is always driven
+ * 1: Supported
+ * 17:17 StopRetry Relevant only if PCI Retry is enabled
+ * 0: Keep Retry all PCI transactions targeted
+ * to the GT64260.
+ * 1: Stop Retry of PCI transactions.
+ * 18:18 MultiGTDec Multi-GT Address Decode
+ * 0: Normal address decoding
+ * 1: Multi-GT address decoding
+ * 19:19 DPValid CPU DP[0-7] Connection. CPU write parity ...
+ * 0: is not checked. (Not connected)
+ * 1: is checked (Connected)
+ * 21:20 Reserved
+ * 22:22 PErrProp Parity Error Propagation
+ * 0: GT64260 always drives good parity on
+ * DP[0-7] during CPU reads.
+ * 1: GT64260 drives bad parity on DP[0-7] in case
+ * the read response from the target interface
+ * comes with erroneous data indication
+ * (e.g. ECC error from SDRAM interface).
+ * 25:23 Reserved
+ * 26:26 APValid CPU AP[0-3] Connection. CPU address parity ...
+ * 0: is not checked. (Not connected)
+ * 1: is checked (Connected)
+ * 27:27 RemapWrDis Address Remap Registers Write Control
+ * 0: Write to Low Address decode register.
+ * Results in writing of the corresponding
+ * Remap register.
+ * 1: Write to Low Address decode register. No
+ * affect on the corresponding Remap register.
+ * 28:28 ConfSBDis Configuration Read Sync Barrier Disable
+ * 0: enabled; 1: disabled
+ * 29:29 IOSBDis I/O Read Sync Barrier Disable
+ * 0: enabled; 1: disabled
+ * 30:30 ClkSync Clocks Synchronization
+ * 0: The CPU interface is running with SysClk,
+ * which is asynchronous to TClk.
+ * 1: The CPU interface is running with TClk.
+ * 31:31 Reserved
+ */
+#define GT_CPUCfg_NoMatchCnt_GET(v) GT__EXT((v), 0, 8)
+#define GT_CPUCfg_NoMatchCntEn GT__BIT( 9)
+#define GT_CPUCfg_NoMatchCntExt GT__BIT(10)
+#define GT_CPUCfg_AACKDelay GT__BIT(11)
+#define GT_CPUCfg_Endianess GT__BIT(12)
+#define GT_CPUCfg_Pipeline GT__BIT(13)
+#define GT_CPUCfg_TADelay GT__BIT(15)
+#define GT_CPUCfg_RdOOO GT__BIT(16)
+#define GT_CPUCfg_StopRetry GT__BIT(17)
+#define GT_CPUCfg_MultiGTDec GT__BIT(18)
+#define GT_CPUCfg_DPValid GT__BIT(19)
+#define GT_CPUCfg_PErrProp GT__BIT(22)
+#define GT_CPUCfg_APValid GT__BIT(26)
+#define GT_CPUCfg_RemapWrDis GT__BIT(27)
+#define GT_CPUCfg_ConfSBDis GT__BIT(28)
+#define GT_CPUCfg_IOSBDis GT__BIT(29)
+#define GT_CPUCfg_ClkSync GT__BIT(30)
+
+/*
+ * Table 98: CPU Mode, Offset: 0x120, Read only
+ * 01:00 MultiGTID Multi-GT ID
+ * Represents the ID to which the GT64260 responds
+ * to during a multi-GT address decoding period.
+ * 02:02 MultiGT (0: Single; 1: Multiple) GT configuration
+ * 03:03 RetryEn (0: Don't; 1: Do) Retry PCI transactions
+ * 07:04 CPUType
+ * 0x0-0x3: Reserved
+ * 0x4: 64-bit PowerPC CPU, 60x bus
+ * 0x5: 64-bit PowerPC CPU, MPX bus
+ * 0x6-0xf: Reserved
+ * 31:08 Reserved
+ */
+#define GT_CPUMode_MultiGTID_GET(v) GT__EXT(v, 0, 2)
+#define GT_CPUMode_MultiGT GT__BIT(2)
+#define GT_CPUMode_RetryEn GT__BIT(3)
+#define GT_CPUMode_CPUType_GET(v) GT__EXT(v, 4, 4)
+
+/*
+ * Table 99: CPU Master Control, Offset: 0x160
+ * 07:00 Reserved
+ * 08:08 IntArb CPU Bus Internal Arbiter Enable
+ * NOTE: Only relevant to 60x bus mode. When
+ * running MPX bus, the GT64260 internal
+ * arbiter must be used.
+ * 0: Disabled. External arbiter is required.
+ * 1: Enabled. Use the GT64260 CPU bus arbiter.
+ * 09:09 IntBusCtl CPU Interface Unit Internal Bus Control
+ * NOTE: This bit must be set to 1. It is reserved
+ * for Galileo Technology usage.
+ * 0: Enable internal bus sharing between master
+ * and slave interfaces.
+ * 1: Disable internal bus sharing between master
+ * and slave interfaces.
+ * 10:10 MWrTrig Master Write Transaction Trigger
+ * 0: With first valid write data
+ * 1: With last valid write data
+ * 11:11 MRdTrig Master Read Response Trigger
+ * 0: With first valid read data
+ * 1: With last valid read data
+ * 12:12 CleanBlock Clean Block Snoop Transaction Support
+ * 0: CPU does not support clean block (603e,750)
+ * 1: CPU supports clean block (604e,G4)
+ * 13:13 FlushBlock Flush Block Snoop Transaction Support
+ * 0: CPU does not support flush block (603e,750)
+ * 1: CPU supports flush block (604e,G4)
+ * 31:14 Reserved
+ */
+#define GT_CPUMstrCtl_IntArb GT__BIT(8)
+#define GT_CPUMstrCtl_IntBusCtl GT__BIT(9)
+#define GT_CPUMstrCtl_MWrTrig GT__BIT(10)
+#define GT_CPUMstrCtl_MRdTrig GT__BIT(11)
+#define GT_CPUMstrCtl_CleanBlock GT__BIT(12)
+#define GT_CPUMstrCtl_FlushBlock GT__BIT(13)
+
+#define GT_ArbSlice_SDRAM 0x0 /* SDRAM interface snoop request */
+#define GT_ArbSlice_DEVICE 0x1 /* Device request */
+#define GT_ArbSlice_NULL 0x2 /* NULL request */
+#define GT_ArbSlice_PCI0 0x3 /* PCI_0 access */
+#define GT_ArbSlice_PCI1 0x4 /* PCI_1 access */
+#define GT_ArbSlice_COMM 0x5 /* Comm unit access */
+#define GT_ArbSlice_IDMA0123 0x6 /* IDMA channels 0/1/2/3 access */
+#define GT_ArbSlice_IDMA4567 0x7 /* IDMA channels 4/5/6/7 access */
+ /* 0x8-0xf: Reserved */
+
+/* Pass in the slice number (from 0..16) as 'n'
+ */
+#define GT_XbarCtl_GET_ArbSlice(v, n) GT__EXT((v), (((n) & 7)*4, 4)
+
+/*
+ * Table 100: CPU Interface Crossbar Control Low, Offset: 0x150
+ * 03:00 Arb0 Slice 0 of CPU Master pizza Arbiter
+ * 07:04 Arb1 Slice 1 of CPU Master pizza Arbiter
+ * 11:08 Arb2 Slice 2 of CPU Master pizza Arbiter
+ * 15:12 Arb3 Slice 3 of CPU Master pizza Arbiter
+ * 19:16 Arb4 Slice 4 of CPU Master pizza Arbiter
+ * 23:20 Arb5 Slice 5 of CPU Master pizza Arbiter
+ * 27:24 Arb6 Slice 6 of CPU Master pizza Arbiter
+ * 31:28 Arb7 Slice 7 of CPU Master pizza Arbiter
+ */
+
+/*
+ * Table 101: CPU Interface Crossbar Control High, Offset: 0x158
+ * 03:00 Arb8 Slice 8 of CPU Master pizza Arbiter
+ * 07:04 Arb9 Slice 9 of CPU Master pizza Arbiter
+ * 11:08 Arb10 Slice 10 of CPU Master pizza Arbiter
+ * 15:12 Arb11 Slice 11 of CPU Master pizza Arbiter
+ * 19:16 Arb12 Slice 12 of CPU Master pizza Arbiter
+ * 23:20 Arb13 Slice 13 of CPU Master pizza Arbiter
+ * 27:24 Arb14 Slice 14 of CPU Master pizza Arbiter
+ * 31:28 Arb15 Slice 15 of CPU Master pizza Arbiter
+ */
+
+/*
+ * Table 102: CPU Interface Crossbar Timeout, Offset: 0x168
+ * NOTE: Reserved for Galileo Technology usage.
+ * 07:00 Timeout Crossbar Arbiter Timeout Preset Value
+ * 15:08 Reserved
+ * 16:16 TimeoutEn Crossbar Arbiter Timer Enable
+ * (0: Enable; 1: Disable)
+ * 31:17 Reserved
+ */
+
+/*
+ * Table 103: CPU Read Response Crossbar Control Low, Offset: 0x170
+ * 03:00 Arb0 Slice 0 of CPU Slave pizza Arbiter
+ * 07:04 Arb1 Slice 1 of CPU Slave pizza Arbiter
+ * 11:08 Arb2 Slice 2 of CPU Slave pizza Arbiter
+ * 15:12 Arb3 Slice 3 of CPU Slave pizza Arbiter
+ * 19:16 Arb4 Slice 4 of CPU Slave pizza Arbiter
+ * 23:20 Arb5 Slice 5 of CPU Slave pizza Arbiter
+ * 27:24 Arb6 Slice 6 of CPU Slave pizza Arbiter
+ * 31:28 Arb7 Slice 7 of CPU Slave pizza Arbiter
+ */
+/*
+ * Table 104: CPU Read Response Crossbar Control High, Offset: 0x178
+ * 03:00 Arb8 Slice 8 of CPU Slave pizza Arbiter
+ * 07:04 Arb9 Slice 9 of CPU Slave pizza Arbiter
+ * 11:08 Arb10 Slice 10 of CPU Slave pizza Arbiter
+ * 15:12 Arb11 Slice 11 of CPU Slave pizza Arbiter
+ * 19:16 Arb12 Slice 12 of CPU Slave pizza Arbiter
+ * 23:20 Arb13 Slice 13 of CPU Slave pizza Arbiter
+ * 27:24 Arb14 Slice 14 of CPU Slave pizza Arbiter
+ * 31:28 Arb15 Slice 15 of CPU Slave pizza Arbiter
+ */
+
+/*
+ * Table 105: PCI_0 Sync Barrier Virtual Register, Offset: 0x0c0
+ * Table 106: PCI_1 Sync Barrier Virtual Register, Offset: 0x0c8
+ * NOTE: The read data is random and should be ignored.
+ * 31:00 SyncBarrier A CPU read from this register creates a
+ * synchronization barrier cycle.
+ */
+
+/*
+ * Table 107: CPU Protect Address 0 Low, Offset: 0x180
+ * Table 109: CPU Protect Address 1 Low, Offset: 0x190
+ * Table 111: CPU Protect Address 2 Low, Offset: 0x1a0
+ * Table 113: CPU Protect Address 3 Low, Offset: 0x1b0
+ * Table 115: CPU Protect Address 4 Low, Offset: 0x1c0
+ * Table 117: CPU Protect Address 5 Low, Offset: 0x1d0
+ * Table 119: CPU Protect Address 6 Low, Offset: 0x1e0
+ * Table 121: CPU Protect Address 7 Low, Offset: 0x1f0
+ *
+ * 11:00 LowAddr CPU Protect Region Base Address
+ * Corresponds to address bits[31:20].
+ * 15:12 Reserved. Must be 0
+ * 16:16 AccProtect CPU Access Protect
+ * Access is (0: allowed; 1: forbidden)
+ * 17:17 WrProtect CPU Write Protect
+ * Writes are (0: allowed; 1: forbidden)
+ * 18:18 CacheProtect CPU caching protect. Caching (block read)
+ * is (0: allowed; 1: forbidden)
+ * 31:19 Reserved
+ */
+#define GT_CPU_AccProtect GT__BIT(16)
+#define GT_CPU_WrProtect GT__BIT(17)
+#define GT_CPU_CacheProtect GT__BIT(18)
+
+/*
+ * Table 108: CPU Protect Address 0 High, Offset: 0x188
+ * Table 110: CPU Protect Address 1 High, Offset: 0x198
+ * Table 112: CPU Protect Address 2 High, Offset: 0x1a8
+ * Table 114: CPU Protect Address 3 High, Offset: 0x1b8
+ * Table 116: CPU Protect Address 4 High, Offset: 0x1c8
+ * Table 118: CPU Protect Address 5 High, Offset: 0x1d8
+ * Table 120: CPU Protect Address 6 High, Offset: 0x1e8
+ * Table 122: CPU Protect Address 7 High, Offset: 0x1f8
+ *
+ * 11:00 HighAddr CPU Protect Region Top Address
+ * Corresponds to address bits[31:20]
+ * 31:12 Reserved
+ */
+
+/*
+ * Table 123: Snoop Base Address 0, Offset: 0x380
+ * Table 125: Snoop Base Address 1, Offset: 0x390
+ * Table 127: Snoop Base Address 2, Offset: 0x3a0
+ * Table 129: Snoop Base Address 3, Offset: 0x3b0
+ *
+ * 11:00 LowAddr Snoop Region Base Address [31:20]
+ * 15:12 Reserved Must be 0.
+ * 17:16 Snoop Snoop Type
+ * 0x0: No Snoop
+ * 0x1: Snoop to WT region
+ * 0x2: Snoop to WB region
+ * 0x3: Reserved
+ * 31:18 Reserved
+ */
+#define GT_Snoop_GET(v) GT__EXT((v), 16, 2)
+#define GT_Snoop_INS(v) GT__INS((v), 16)
+#define GT_Snoop_None 0
+#define GT_Snoop_WT 1
+#define GT_Snoop_WB 2
+
+
+/*
+ * Table 124: Snoop Top Address 0, Offset: 0x388
+ * Table 126: Snoop Top Address 1, Offset: 0x398
+ * Table 128: Snoop Top Address 2, Offset: 0x3a8
+ * Table 130: Snoop Top Address 3, Offset: 0x3b8
+ * 11:00 HighAddr Snoop Region Top Address [31:20]
+ * 31:12 Reserved
+ */
+
+
+/*
+ * Table 131: CPU Error Address Low, Offset: 0x070, Read Only.
+ * In case of multiple errors, only the first one is latched. New error
+ * report latching is enabled only after the CPU Error Address Low register
+ * is being read.
+ * 31:00 ErrAddr Latched address bits [31:0] of a CPU
+ * transaction in case of:
+ * o illegal address (failed address decoding)
+ * o access protection violation
+ * o bad data parity
+ * o bad address parity
+ * Upon address latch, no new address are
+ * registered (due to additional error condition),
+ * until the register is being read.
+ */
+
+/*
+ * Table 132: CPU Error Address High, Offset: 0x078, Read Only.
+ * Once data is latched, no new data can be registered (due to additional
+ * error condition), until CPU Error Low Address is being read (which
+ * implies, it should be the last being read by the interrupt handler).
+ * 03:00 Reserved
+ * 07:04 ErrPar Latched address parity bits in case
+ * of bad CPU address parity detection.
+ * 31:08 Reserved
+ */
+#define GT_CPUErrorAddrHigh_ErrPar_GET(v) GT__EXT((v), 4, 4)
+
+/*
+ * Table 133: CPU Error Data Low, Offset: 0x128, Read only.
+ * 31:00 PErrData Latched data bits [31:0] in case of bad data
+ * parity sampled on write transactions or on
+ * master read transactions.
+ */
+
+/*
+ * Table 134: CPU Error Data High, Offset: 0x130, Read only.
+ * 31:00 PErrData Latched data bits [63:32] in case of bad data
+ * parity sampled on write transactions or on
+ * master read transactions.
+ */
+
+/*
+ * Table 135: CPU Error Parity, Offset: 0x138, Read only.
+ * 07:00 PErrPar Latched data parity bus in case of bad data
+ * parity sampled on write transactions or on
+ * master read transactions.
+ * 31:10 Reserved
+ */
+#define GT_CPUErrorParity_PErrPar_GET(v) GT__EXT((v), 0, 8)
+
+/*
+ * Table 136: CPU Error Cause, Offset: 0x140
+ * Bits[7:0] are clear only. A cause bit is set upon an error condition
+ * occurrence. Write a 0 value to clear the bit. Writing a 1 value has
+ * no affect.
+ * 00:00 AddrOut CPU Address Out of Range
+ * 01:01 AddrPErr Bad Address Parity Detected
+ * 02:02 TTErr Transfer Type Violation.
+ * The CPU attempts to burst (read or write) to an
+ * internal register.
+ * 03:03 AccErr Access to a Protected Region
+ * 04:04 WrErr Write to a Write Protected Region
+ * 05:05 CacheErr Read from a Caching protected region
+ * 06:06 WrDataPErr Bad Write Data Parity Detected
+ * 07:07 RdDataPErr Bad Read Data Parity Detected
+ * 26:08 Reserved
+ * 31:27 Sel Specifies the error event currently being
+ * reported in Error Address, Error Data, and
+ * Error Parity registers.
+ * 0x0: AddrOut
+ * 0x1: AddrPErr
+ * 0x2: TTErr
+ * 0x3: AccErr
+ * 0x4: WrErr
+ * 0x5: CacheErr
+ * 0x6: WrDataPErr
+ * 0x7: RdDataPErr
+ * 0x8-0x1f: Reserved
+ */
+#define GT_CPUError_AddrOut GT__BIT(GT_CPUError_Sel_AddrOut)
+#define GT_CPUError_AddrPErr GT__BIT(GT_CPUError_Sel_AddrPErr)
+#define GT_CPUError_TTErr GT__BIT(GT_CPUError_Sel_TTErr)
+#define GT_CPUError_AccErr GT__BIT(GT_CPUError_Sel_AccErr)
+#define GT_CPUError_WrErr GT__BIT(GT_CPUError_Sel_WrPErr)
+#define GT_CPUError_CacheErr GT__BIT(GT_CPUError_Sel_CachePErr)
+#define GT_CPUError_WrDataPErr GT__BIT(GT_CPUError_Sel_WrDataPErr)
+#define GT_CPUError_RdDataPErr GT__BIT(GT_CPUError_Sel_RdDataPErr)
+
+#define GT_CPUError_Sel_AddrOut 0
+#define GT_CPUError_Sel_AddrPErr 1
+#define GT_CPUError_Sel_TTErr 2
+#define GT_CPUError_Sel_AccErr 3
+#define GT_CPUError_Sel_WrErr 4
+#define GT_CPUError_Sel_CacheErr 5
+#define GT_CPUError_Sel_WrDataPErr 6
+#define GT_CPUError_Sel_RdDataPErr 7
+
+#define GT_CPUError_Sel_GET(v) GT__EXT((v), 27, 5)
+
+/*
+ * Table 137: CPU Error Mask, Offset: 0x148
+ * 00:00 AddrOut If set to 1, enables AddrOut interrupt.
+ * 01:01 AddrPErr If set to 1, enables AddrPErr interrupt.
+ * 02:02 TTErr If set to 1, enables TTErr interrupt.
+ * 03:03 AccErr If set to 1, enables AccErr interrupt.
+ * 04:04 WrErr If set to 1, enables WrErr interrupt.
+ * 05:05 CacheErr If set to 1, enables CacheErr interrupt.
+ * 06:06 WrDataPErr If set to 1, enables WrDataPErr interrupt.
+ * 07:07 RdDataPErr If set to 1, enables RdDataPErr interrupt.
+ * 31:08 Reserved
+ */
+
+/*
+ * Comm Unit Interrupt registers
+ */
+
+/* Comm Unit Arbiter Control */
+#define GT_CommUnitArb_Ctrl 0xf300
+/* GPP IRQs level vs. edge sensitivity */
+#define GT_CommUnitArb_Ctrl_GPP_Ints_Level_Sensitive (1<<10)
+
+#define GT_CommUnitIntr_Cause 0xf310
+#define GT_CommUnitIntr_Mask 0xf314
+#define GT_CommUnitIntr_ErrAddr 0xf318
+
+#define GT_CommUnitIntr_E0 0x00000007
+#define GT_CommUnitIntr_E1 0x00000070
+#define GT_CommUnitIntr_E2 0x00000700
+#define GT_CommUnitIntr_S0 0x00070000
+#define GT_CommUnitIntr_S1 0x00700000
+#define GT_CommUnitIntr_Sel 0x70000000
+
+/*
+ * SDRAM Error Report (ECC) Registers
+ */
+#define GT_260_ECC_Data_Lo 0x484 /* latched Error Data (low) */
+#define GT_260_ECC_Data_Hi 0x480 /* latched Error Data (high) */
+#define GT_260_ECC_Addr 0x490 /* latched Error Address */
+#define GT_260_ECC_Rec 0x488 /* latched ECC code from SDRAM */
+#define GT_260_ECC_Calc 0x48c /* latched ECC code from SDRAM */
+#define GT_260_ECC_Ctl 0x494 /* ECC Control */
+#define GT_260_ECC_Count 0x498 /* ECC 1-bit error count */
+
+/* Timer/Counter Registers (t. straumann)
+ */
+#define GT_TIMER_0 0x0850 /* preset / running value */
+#define GT_TIMER_1 0x0854
+#define GT_TIMER_2 0x0858
+#define GT_TIMER_3 0x085c
+
+#define GT_TIMER_0_3_Ctl 0x0864
+
+#define GT_TIMER_0_Ctl_Enb 0x00000001 /* enable timer */
+#define GT_TIMER_0_Ctl_Rld 0x00000002 /* reload after expiration */
+#define GT_TIMER_1_Ctl_Enb 0x00000100 /* enable timer */
+#define GT_TIMER_1_Ctl_Rld 0x00000200 /* reload after expiration */
+#define GT_TIMER_2_Ctl_Enb 0x00010000 /* enable timer */
+#define GT_TIMER_2_Ctl_Rld 0x00020000 /* reload after expiration */
+#define GT_TIMER_3_Ctl_Enb 0x01000000 /* enable timer */
+#define GT_TIMER_3_Ctl_Rld 0x02000000 /* reload after expiration */
+
+#define GT_TIMER_0_3_Intr_Cse 0x0868
+#define GT_TIMER_0_Intr 0x00000001
+#define GT_TIMER_1_Intr 0x00000002
+#define GT_TIMER_2_Intr 0x00000004
+#define GT_TIMER_3_Intr 0x00000008
+#define GT_TIMER_Intr_Smry 0x80000000 /* Interrupt Summary */
+
+#define GT_TIMER_0_3_Intr_Msk 0x086c
+
+/*
+ * Watchdog Registers
+ */
+#define GT_WDOG_Config 0xb410
+#define GT_WDOG_Value 0xb414
+#define GT_WDOG_Value_NMI GT__MASK(24)
+#define GT_WDOG_Config_Preset GT__MASK(24)
+#define GT_WDOG_Config_Ctl1a GT__BIT(24)
+#define GT_WDOG_Config_Ctl1b GT__BIT(25)
+#define GT_WDOG_Config_Ctl2a GT__BIT(26)
+#define GT_WDOG_Config_Ctl2b GT__BIT(27)
+#define GT_WDOG_Config_Enb GT__BIT(31)
+
+#define GT_WDOG_NMI_DFLT (GT__MASK(24) & GT_WDOG_Value_NMI)
+#define GT_WDOG_Preset_DFLT (GT__MASK(22) & GT_WDOG_Config_Preset)
+
+/*
+ * Device Bus Interrupts
+ */
+#define GT_DEVBUS_ICAUSE 0x4d0 /* Device Interrupt Cause */
+#define GT_DEVBUS_IMASK 0x4d4 /* Device Interrupt Mask */
+#define GT_DEVBUS_ERR_ADDR 0x4d8 /* Device Error Address */
+
+/*
+ * bit defines for GT_DEVBUS_ICAUSE, GT_DEVBUS_IMASK
+ */
+#define GT_DEVBUS_DBurstErr GT__BIT(0)
+#define GT_DEVBUS_DRdyErr GT__BIT(1)
+#define GT_DEVBUS_Sel GT__BIT(27)
+#define GT_DEVBUS_RES ~(GT_DEVBUS_DBurstErr|GT_DEVBUS_DRdyErr|GT_DEVBUS_Sel)
+
+/* MV64360 */
+/* Enable individual CPU windows by *clearing* respective bits
+ * in MV_64360_BASE_ADDR_DISBL
+ *
+ * Bit ordering is:
+ *
+ * SDRAM_CS_0..3 (1<<0..3)
+ * DEV_CS_0..3 (1<<4..7)
+ * BOOT_CS_0..3 (1<<8)
+ * PCI_0_IO (1<<9)
+ * PCI_0_MEM_0..3 (1<<10..13)
+ * PCI_1_IO (1<<14)
+ * PCI_1_MEM_0..3 (1<<15..18)
+ * INTERNAL_SRAM (1<<19)
+ * MV64x60_REGS (1<<20)
+ */
+#define MV_64360_BASE_ADDR_DISBL (0x278)
+
+/* Internal SRAM */
+#define MV_64360_SRAM_BASE (0x268)
+#define MV_64360_SRAM_CTRL (0x380)
+/* Control register bits */
+#define MV_64360_SRAM_CacheWb GT__BIT(1)
+/* default setup used by linux, motload (uses 90 instead of b0), ...
+ * Comments say:
+ * - parity enabled,
+ * - parity error propagation
+ * - arbitration not parked for CPU only
+ * - other bits are reserved
+ */
+#define MV_64360_SRAM_Ctl_Setup (0x001600b0)
+
+#define MV_64360_SRAM_TEST_MODE (0x3f4)
+#define MV_64340_SRAM_ERR_CAUSE (0x388)
+#define MV_64340_SRAM_ERR_ADDR (0x390)
+#define MV_64340_SRAM_ERR_ADDR_HI (0X3f8)
+#define MV_64340_SRAM_ERR_DATA_LO (0x398)
+#define MV_64340_SRAM_ERR_DATA_HI (0x3a0)
+#define MV_64340_SRAM_ERR_DATA_PARITY (0x3a8)
+
+#endif /* !_DISCOVERY_DEV_GTREG_H */
diff --git a/c/src/lib/libbsp/powerpc/beatnik/network/if_em/LICENSE b/c/src/lib/libbsp/powerpc/beatnik/network/if_em/LICENSE
new file mode 100644
index 0000000000..ba90c4a817
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/beatnik/network/if_em/LICENSE
@@ -0,0 +1,31 @@
+$FreeBSD: /repoman/r/ncvs/src/sys/dev/em/LICENSE,v 1.3 2005/01/06 01:42:38 imp Exp $
+/*-
+Copyright (c) 2001-2003, Intel Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+*/
diff --git a/c/src/lib/libbsp/powerpc/beatnik/network/if_em/Makefile b/c/src/lib/libbsp/powerpc/beatnik/network/if_em/Makefile
new file mode 100644
index 0000000000..af3d788b53
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/beatnik/network/if_em/Makefile
@@ -0,0 +1,92 @@
+#
+# Makefile.lib,v 1.5 2000/06/12 15:00:14 joel Exp
+#
+# Templates/Makefile.lib
+# Template library Makefile
+#
+
+LIBNAME=libif_em.a # xxx- your library names goes here
+#PGMS=${ARCH}/if_em.obj
+LIB=${ARCH}/${LIBNAME}
+
+# C and C++ source names, if any, go here -- minus the .c or .cc
+C_PIECES=if_em_hw if_em if_em_rtems
+#C_PIECES=if_em_hw if_em if_em_rtems if_em.modini
+MODOBJS=$(ARCH)/if_em.o $(ARCH)/if_em_hw.o $(ARCH)/if_em.modini.o
+C_FILES=$(C_PIECES:%=%.c)
+C_O_FILES=$(C_PIECES:%=${ARCH}/%.o)
+
+CC_PIECES=
+CC_FILES=$(CC_PIECES:%=%.cc)
+CC_O_FILES=$(CC_PIECES:%=${ARCH}/%.o)
+
+H_FILES=
+
+# Assembly source names, if any, go here -- minus the .S
+S_PIECES=
+S_FILES=$(S_PIECES:%=%.S)
+S_O_FILES=$(S_FILES:%.S=${ARCH}/%.o)
+
+SRCS=$(C_FILES) $(CC_FILES) $(H_FILES) $(S_FILES)
+OBJS=$(C_O_FILES) $(CC_O_FILES) $(S_O_FILES)
+
+include $(RTEMS_MAKEFILE_PATH)/Makefile.inc
+
+include $(RTEMS_CUSTOM)
+include $(RTEMS_ROOT)/make/lib.cfg
+
+#
+# Add local stuff here using +=
+#
+
+DEFINES += -DHAVE_LIBBSPEXT
+CPPFLAGS += -I. -Ilibchip -Iporting
+CFLAGS += -Wno-unused-variable -msoft-float
+
+#
+# Add your list of files to delete here. The config files
+# already know how to delete some stuff, so you may want
+# to just run 'make clean' first to see what gets missed.
+# 'make clobber' already includes 'make clean'
+#
+
+CLEAN_ADDITIONS +=
+CLOBBER_ADDITIONS +=
+
+all: ${ARCH} $(SRCS) $(LIB) ${PGMS}
+
+# doesn't work if we define this just after OBJS= :-(
+
+# must be after inclusion of RTEMS_CUSTOM
+
+$(LIB): OBJS=$(filter-out %.modini.o,$(OBJS))
+
+$(LIB): ${OBJS}
+ $(make-library)
+
+#How to make a relocatable object
+$(filter %.obj, $(PGMS)): $(MODOBJS)
+ $(make-obj)
+
+ifndef RTEMS_SITE_INSTALLDIR
+RTEMS_SITE_INSTALLDIR = $(PROJECT_RELEASE)
+endif
+
+${RTEMS_SITE_INSTALLDIR}/include \
+${RTEMS_SITE_INSTALLDIR}/lib \
+${RTEMS_SITE_INSTALLDIR}/bin \
+${RTEMS_SITE_INSTALLDIR}/$(RTEMS_BSP)/include \
+${RTEMS_SITE_INSTALLDIR}/$(RTEMS_BSP)/lib \
+${RTEMS_SITE_INSTALLDIR}/$(RTEMS_BSP)/bin :
+ test -d $@ || mkdir -p $@
+
+# Install the library, appending _g or _p as appropriate.
+# for include files, just use $(INSTALL_CHANGE)
+#
+# NOTES:
+# - BSP specific libraries, headers etc. should be installed to
+# $RTEMS_SITE_INSTALLDIR)/$(RTEMS_BSP)/lib
+#
+
+install: all $(RTEMS_SITE_INSTALLDIR)/lib
+ $(INSTALL_VARIANT) -m 644 ${LIB} ${RTEMS_SITE_INSTALLDIR}/lib
diff --git a/c/src/lib/libbsp/powerpc/beatnik/network/if_em/README b/c/src/lib/libbsp/powerpc/beatnik/network/if_em/README
new file mode 100644
index 0000000000..b4eef8dbb7
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/beatnik/network/if_em/README
@@ -0,0 +1,332 @@
+$FreeBSD: /repoman/r/ncvs/src/sys/dev/em/README,v 1.10 2005/07/11 02:33:25 delphij Exp $
+FreeBSD* Driver for the Intel(R) PRO/1000 Family of Adapters
+============================================================
+
+March 18, 2005
+
+
+Contents
+========
+
+- Overview
+- Identifying Your Adapter
+- Building and Installation
+- Speed and Duplex Configuration
+- Additional Configurations
+- Known Limitations
+- Support
+- License
+
+
+Overview
+========
+
+This file describes the FreeBSD* driver, version 2.1.x, for the Intel(R)
+PRO/1000 Family of Adapters. This driver has been developed for use with
+FreeBSD, version 5.x.
+
+For questions related to hardware requirements, refer to the documentation
+supplied with your Intel PRO/1000 adapter. All hardware requirements listed
+apply to use with FreeBSD.
+
+
+Identifying Your Adapter
+========================
+
+For information on how to identify your adapter, go to the Adapter &
+Driver ID Guide at:
+
+http://support.intel.com/support/network/adapter/pro100/21397.htm
+
+
+For the latest Intel network drivers for FreeBSD, see:
+
+http://appsr.intel.com/scripts-df/support_intel.asp
+
+
+NOTE: Mobile adapters are not fully supported.
+
+
+Building and Installation
+=========================
+
+NOTE: The driver can be installed as a dynamic loadable kernel module or
+ compiled into the kernel. You must have kernel sources installed in
+ order to compile the driver module.
+
+In the instructions below, x.x.x is the driver version as indicated in the
+name of the driver tar file.
+
+1. Move the base driver tar file to the directory of your choice. For
+ example, use /home/username/em or /usr/local/src/em.
+
+2. Untar/unzip the archive:
+
+ tar xvfz em-x.x.x.tar.gz
+
+ This will create an em-x.x.x directory.
+
+3. To create a loadable module, perform the following steps.
+ NOTE: To compile the driver into the kernel, go directly to step 4.
+
+ a. To compile the module
+
+ cd em-x.x.x
+ make
+
+ b. To install the compiled module in system directory:
+
+ make install
+
+ c. If you want the driver to load automatically when the system is booted:
+
+ 1. Edit /boot/loader.conf, and add the following line:
+
+ if_em_load="YES"
+
+4. To compile the driver into the kernel:
+
+ cd em-x.x.x/src
+
+ cp if_em* /usr/src/sys/dev/em
+
+ cp Makefile.kernel /usr/src/sys/modules/em/Makefile
+
+ Edit the /usr/src/sys/conf/files.i386 file, and add the following lines only if
+ they don't already exist:
+
+ dev/em/if_em.c optional em
+
+ dev/em/if_em_hw.c optional em
+
+ Remove the following lines from the /usr/src/sys/conf/files.i386 file,
+ if they exist:
+
+ dev/em/if_em_fxhw.c optional em
+ dev/em/if_em_phy.c optional em
+
+ Edit the kernel configuration file (i.e., GENERIC or MYKERNEL) in
+ /usr/src/sys/i386/conf, and ensure the following line is present:
+
+ device em
+
+ Compile and install the kernel. The system must be rebooted for the kernel
+ updates to take effect. For additional information on compiling the
+ kernel, consult the FreeBSD operating system documentation.
+
+5. To assign an IP address to the interface, enter the following:
+
+ ifconfig em<interface_num> <IP_address>
+
+6. Verify that the interface works. Enter the following, where <IP_address>
+ is the IP address for another machine on the same subnet as the interface
+ that is being tested:
+
+ ping <IP_address>
+
+7. To configure the IP address to remain after reboot, edit /etc/rc.conf,
+ and create the appropriate ifconfig_em<interface_num>entry:
+
+ ifconfig_em<interface_num>="<ifconfig_settings>"
+
+ Example usage:
+
+ ifconfig_em0="inet 192.168.10.1 netmask 255.255.255.0"
+
+ NOTE: For assistance, see the ifconfig man page.
+
+
+Speed and Duplex Configuration
+==============================
+
+By default, the adapter auto-negotiates the speed and duplex of the
+connection. If there is a specific need, the ifconfig utility can be used to
+configure the speed and duplex settings on the adapter. Example usage:
+
+ ifconfig em<interface_num> <IP_address> media 100baseTX mediaopt
+ full-duplex
+
+ NOTE: Only use mediaopt to set the driver to full-duplex. If mediaopt is
+ not specified and you are not running at gigabit speed, the driver
+ defaults to half-duplex.
+
+
+This driver supports the following media type options:
+
+ autoselect - Enables auto-negotiation for speed and duplex.
+
+ 10baseT/UTP - Sets speed to 10 Mbps. Use the ifconfig mediaopt
+ option to select full-duplex mode.
+
+ 100baseTX - Sets speed to 100 Mbps. Use the ifconfig mediaopt
+ option to select full-duplex mode.
+
+ 1000baseTX - Sets speed to 1000 Mbps. In this case, the driver
+ supports only full-duplex mode.
+
+ 1000baseSX - Sets speed to 1000 Mbps. In this case, the driver
+ supports only full-duplex mode.
+
+For more information on the ifconfig utility, see the ifconfig man page.
+
+
+Additional Configurations
+=========================
+
+The driver supports Transmit/Receive Checksum Offload and Jumbo Frames on
+all but the 82542-based adapters. For specific adapters, refer to the
+Identifying Your Adapter section.
+
+ Jumbo Frames
+ ------------
+ To enable Jumbo Frames, use the ifconfig utility to increase the MTU
+ beyond 1500 bytes.
+
+ NOTES: Only enable Jumbo Frames if your network infrastructure supports
+ them.
+
+ The Jumbo Frames setting on the switch must be set to at least
+ 22 bytes larger than that of the MTU.
+
+ The Intel PRO/1000 PM Network Connection does not support jumbo
+ frames.
+
+
+ The Jumbo Frames MTU range for Intel Adapters is 1500 to 16114. The default
+ MTU range is 1500. To modify the setting, enter the following:
+
+ ifconfig em<interface_num> <hostname or IP address> mtu 9000
+
+ To confirm the MTU used between two specific devices, use:
+
+ route get <destination_IP_address>
+
+ VLANs
+ -----
+ To create a new VLAN interface:
+
+ ifconfig <vlan_name> create
+
+ To associate the VLAN interface with a physical interface and
+ assign a VLAN ID, IP address, and netmask:
+
+ ifconfig <vlan_name> <ip_address> netmask <subnet_mask> vlan
+ <vlan_id> vlandev <physical_interface>
+
+ Example:
+
+ ifconfig vlan10 10.0.0.1 netmask 255.255.255.0 vlan10 vlandev em0
+
+ In this example, all packets will be marked on egress with 802.1Q VLAN
+ tags, specifying a VLAN ID of 10.
+
+ To remove a VLAN interface:
+
+ ifconfig <vlan_name> destroy
+
+ Polling
+ -------
+ NOTES: DEVICE POLLING is only valid for non-SMP kernels.
+
+ The driver has to be compiled into the kernel for DEVICE POLLING to be
+ enabled in the driver.
+
+ To enable polling in the driver, add the following options to the kernel
+ configuration, and then recompile the kernel:
+
+ options DEVICE_POLLING
+ options HZ=1000
+
+ At runtime use:
+ sysctl kern.polling.enable=1 to turn polling on
+ Use:
+ sysctl kern.polling.enable=0 to turn polling off
+
+ Checksum Offload
+ ----------------
+ Checksum offloading is not supported on 82542 Gigabit adapters.
+
+ Checksum offloading supports both TCP and UDP packets and is
+ supported for both transmit and receive.
+
+ Checksum offloading can be enabled or disabled using ifconfig.
+ Both transmit and receive offloading will be either enabled or
+ disabled together. You cannot enable/disable one without the other.
+
+ To enable checksum offloading:
+
+ ifconfig <interface_num> rxcsum
+
+ To disable checksum offloading:
+
+ ifconfig <interface_num> -rxcsum
+
+ To confirm the current setting:
+
+ ifconfig <interface_num>
+
+ Look for the presence or absence of the following line:
+
+ options=3 <RXCSUM,TXCSUM>
+
+ See the ifconfig man page for further information.
+
+Known Limitations
+=================
+
+ There are known performance issues with this driver when running UDP traffic
+ with Jumbo Frames.
+
+ There is a known compatibility issue where time to link is slow or link is not
+ established between 82541/82547 controllers and some switches. Known switches
+ include:
+ Planex FXG-08TE
+ I-O Data ETG-SH8
+
+ The driver can be compiled with the following changes:
+
+ Edit ./em.x.x.x/src/if_em.h to uncomment the #define EM_MASTER_SLAVE
+ from within the comments. For example, change from:
+
+ /* #define EM_MASTER_SLAVE 2 */
+ to:
+ #define EM_MASTER_SLAVE 2
+
+ Use one of the following options:
+ 1 = Master mode
+ 2 = Slave mode
+ 3 = Auto master/slave
+ Setting 2 is recommended.
+
+ Recompile the module:
+ a. To compile the module
+ cd em-x.x.x
+ make clean
+ make
+
+ b. To install the compiled module in system directory:
+ make install
+
+
+Support
+=======
+
+For general information and support, go to the Intel support website at:
+
+ http://support.intel.com
+
+If an issue is identified, support is through email only at:
+freebsdnic@mailbox.intel.com
+
+License
+=======
+
+This software program is released under the terms of a license agreement
+between you ('Licensee') and Intel. Do not use or load this software or any
+associated materials (collectively, the 'Software') until you have carefully
+read the full terms and conditions of the LICENSE located in this software
+package. By loading or using the Software, you agree to the terms of this
+Agreement. If you do not agree with the terms of this Agreement, do not
+install or use the Software.
+
+* Other names and brands may be claimed as the property of others.
diff --git a/c/src/lib/libbsp/powerpc/beatnik/network/if_em/if_em.c b/c/src/lib/libbsp/powerpc/beatnik/network/if_em/if_em.c
new file mode 100644
index 0000000000..749a4877a4
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/beatnik/network/if_em/if_em.c
@@ -0,0 +1,3846 @@
+/**************************************************************************
+
+Copyright (c) 2001-2005, Intel Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+
+/*$FreeBSD: /repoman/r/ncvs/src/sys/dev/em/if_em.c,v 1.67 2005/08/03 00:18:29 rwatson Exp $*/
+#ifndef __rtems__
+#include <dev/em/if_em.h>
+#else
+#include <rtems.h>
+#include <rtemscompat.h>
+#include <if_em.h>
+#include <rtemscompat1.h>
+#endif
+
+/*********************************************************************
+ * Set this to one to display debug statistics
+ *********************************************************************/
+int em_display_debug_stats = 0;
+
+/*********************************************************************
+ * Linked list of board private structures for all NICs found
+ *********************************************************************/
+
+struct adapter *em_adapter_list = NULL;
+
+
+/*********************************************************************
+ * Driver version
+ *********************************************************************/
+
+char em_driver_version[] = "2.1.7";
+
+
+/*********************************************************************
+ * PCI Device ID Table
+ *
+ * Used by probe to select devices to load on
+ * Last field stores an index into em_strings
+ * Last entry must be all 0s
+ *
+ * { Vendor ID, Device ID, SubVendor ID, SubDevice ID, String Index }
+ *********************************************************************/
+
+static em_vendor_info_t em_vendor_info_array[] =
+{
+ /* Intel(R) PRO/1000 Network Connection */
+ { 0x8086, E1000_DEV_ID_82540EM, PCI_ANY_ID, PCI_ANY_ID, 0},
+ { 0x8086, E1000_DEV_ID_82540EM_LOM, PCI_ANY_ID, PCI_ANY_ID, 0},
+ { 0x8086, E1000_DEV_ID_82540EP, PCI_ANY_ID, PCI_ANY_ID, 0},
+ { 0x8086, E1000_DEV_ID_82540EP_LOM, PCI_ANY_ID, PCI_ANY_ID, 0},
+ { 0x8086, E1000_DEV_ID_82540EP_LP, PCI_ANY_ID, PCI_ANY_ID, 0},
+
+ { 0x8086, E1000_DEV_ID_82541EI, PCI_ANY_ID, PCI_ANY_ID, 0},
+ { 0x8086, E1000_DEV_ID_82541ER, PCI_ANY_ID, PCI_ANY_ID, 0},
+ { 0x8086, E1000_DEV_ID_82541ER_LOM, PCI_ANY_ID, PCI_ANY_ID, 0},
+ { 0x8086, E1000_DEV_ID_82541EI_MOBILE, PCI_ANY_ID, PCI_ANY_ID, 0},
+ { 0x8086, E1000_DEV_ID_82541GI, PCI_ANY_ID, PCI_ANY_ID, 0},
+ { 0x8086, E1000_DEV_ID_82541GI_LF, PCI_ANY_ID, PCI_ANY_ID, 0},
+ { 0x8086, E1000_DEV_ID_82541GI_MOBILE, PCI_ANY_ID, PCI_ANY_ID, 0},
+
+ { 0x8086, E1000_DEV_ID_82542, PCI_ANY_ID, PCI_ANY_ID, 0},
+
+ { 0x8086, E1000_DEV_ID_82543GC_FIBER, PCI_ANY_ID, PCI_ANY_ID, 0},
+ { 0x8086, E1000_DEV_ID_82543GC_COPPER, PCI_ANY_ID, PCI_ANY_ID, 0},
+
+ { 0x8086, E1000_DEV_ID_82544EI_COPPER, PCI_ANY_ID, PCI_ANY_ID, 0},
+ { 0x8086, E1000_DEV_ID_82544EI_FIBER, PCI_ANY_ID, PCI_ANY_ID, 0},
+ { 0x8086, E1000_DEV_ID_82544GC_COPPER, PCI_ANY_ID, PCI_ANY_ID, 0},
+ { 0x8086, E1000_DEV_ID_82544GC_LOM, PCI_ANY_ID, PCI_ANY_ID, 0},
+
+ { 0x8086, E1000_DEV_ID_82545EM_COPPER, PCI_ANY_ID, PCI_ANY_ID, 0},
+ { 0x8086, E1000_DEV_ID_82545EM_FIBER, PCI_ANY_ID, PCI_ANY_ID, 0},
+ { 0x8086, E1000_DEV_ID_82545GM_COPPER, PCI_ANY_ID, PCI_ANY_ID, 0},
+ { 0x8086, E1000_DEV_ID_82545GM_FIBER, PCI_ANY_ID, PCI_ANY_ID, 0},
+ { 0x8086, E1000_DEV_ID_82545GM_SERDES, PCI_ANY_ID, PCI_ANY_ID, 0},
+
+ { 0x8086, E1000_DEV_ID_82546EB_COPPER, PCI_ANY_ID, PCI_ANY_ID, 0},
+ { 0x8086, E1000_DEV_ID_82546EB_FIBER, PCI_ANY_ID, PCI_ANY_ID, 0},
+ { 0x8086, E1000_DEV_ID_82546EB_QUAD_COPPER, PCI_ANY_ID, PCI_ANY_ID, 0},
+ { 0x8086, E1000_DEV_ID_82546GB_COPPER, PCI_ANY_ID, PCI_ANY_ID, 0},
+ { 0x8086, E1000_DEV_ID_82546GB_FIBER, PCI_ANY_ID, PCI_ANY_ID, 0},
+ { 0x8086, E1000_DEV_ID_82546GB_SERDES, PCI_ANY_ID, PCI_ANY_ID, 0},
+ { 0x8086, E1000_DEV_ID_82546GB_PCIE, PCI_ANY_ID, PCI_ANY_ID, 0},
+ { 0x8086, E1000_DEV_ID_82546GB_QUAD_COPPER, PCI_ANY_ID, PCI_ANY_ID, 0},
+
+ { 0x8086, E1000_DEV_ID_82547EI, PCI_ANY_ID, PCI_ANY_ID, 0},
+ { 0x8086, E1000_DEV_ID_82547EI_MOBILE, PCI_ANY_ID, PCI_ANY_ID, 0},
+ { 0x8086, E1000_DEV_ID_82547GI, PCI_ANY_ID, PCI_ANY_ID, 0},
+
+ { 0x8086, E1000_DEV_ID_82573E, PCI_ANY_ID, PCI_ANY_ID, 0},
+ { 0x8086, E1000_DEV_ID_82573E_IAMT, PCI_ANY_ID, PCI_ANY_ID, 0},
+
+ /* required last entry */
+ { 0, 0, 0, 0, 0}
+};
+
+/*********************************************************************
+ * Table of branding strings for all supported NICs.
+ *********************************************************************/
+
+static char *em_strings[] = {
+ "Intel(R) PRO/1000 Network Connection"
+};
+
+/*********************************************************************
+ * Function prototypes
+ *********************************************************************/
+static int em_probe(device_t);
+static int em_attach(device_t);
+#if !defined(__rtems__) || defined(DEBUG_MODULAR)
+static int em_detach(device_t);
+#endif
+#ifndef __rtems__
+static int em_shutdown(device_t);
+#endif
+static void em_intr(void *);
+static void em_start(struct ifnet *);
+#ifndef __rtems__
+static int em_ioctl(struct ifnet *, u_long, caddr_t);
+#else
+static int em_ioctl(struct ifnet *, ioctl_command_t, caddr_t);
+#endif
+static void em_watchdog(struct ifnet *);
+static void em_init(void *);
+static void em_init_locked(struct adapter *);
+static void em_stop(void *);
+static void em_media_status(struct ifnet *, struct ifmediareq *);
+#ifndef __rtems__
+static int em_media_change(struct ifnet *);
+#else
+static int em_media_change(struct ifnet *ifp, struct rtems_ifmedia *ifm);
+#endif
+static void em_identify_hardware(struct adapter *);
+static int em_allocate_pci_resources(struct adapter *);
+#ifndef __rtems__
+static void em_free_pci_resources(struct adapter *);
+static void em_local_timer(void *);
+#endif
+static int em_hardware_init(struct adapter *);
+static void em_setup_interface(device_t, struct adapter *);
+static int em_setup_transmit_structures(struct adapter *);
+static void em_initialize_transmit_unit(struct adapter *);
+static int em_setup_receive_structures(struct adapter *);
+static void em_initialize_receive_unit(struct adapter *);
+static void em_enable_intr(struct adapter *);
+static void em_disable_intr(struct adapter *);
+static void em_free_transmit_structures(struct adapter *);
+static void em_free_receive_structures(struct adapter *);
+static void em_update_stats_counters(struct adapter *);
+static void em_clean_transmit_interrupts(struct adapter *);
+static int em_allocate_receive_structures(struct adapter *);
+static int em_allocate_transmit_structures(struct adapter *);
+static void em_process_receive_interrupts(struct adapter *, int);
+#ifndef __rtems__
+static void em_receive_checksum(struct adapter *,
+ struct em_rx_desc *,
+ struct mbuf *);
+static void em_transmit_checksum_setup(struct adapter *,
+ struct mbuf *,
+ u_int32_t *,
+ u_int32_t *);
+#endif
+static void em_set_promisc(struct adapter *);
+static void em_disable_promisc(struct adapter *);
+static void em_set_multi(struct adapter *);
+static void em_print_hw_stats(struct adapter *);
+static void em_print_link_status(struct adapter *);
+static int em_get_buf(int i, struct adapter *,
+ struct mbuf *);
+#ifndef __rtems__
+static void em_enable_vlans(struct adapter *);
+static void em_disable_vlans(struct adapter *);
+#endif
+static int em_encap(struct adapter *, struct mbuf **);
+#ifndef __rtems__
+static void em_smartspeed(struct adapter *);
+#endif
+static int em_82547_fifo_workaround(struct adapter *, int);
+static void em_82547_update_fifo_head(struct adapter *, int);
+static int em_82547_tx_fifo_reset(struct adapter *);
+#ifndef __rtems__
+static void em_82547_move_tail(void *arg);
+#endif
+static void em_82547_move_tail_locked(struct adapter *);
+static int em_dma_malloc(struct adapter *, bus_size_t,
+ struct em_dma_alloc *, int);
+static void em_dma_free(struct adapter *, struct em_dma_alloc *);
+#ifndef __rtems__
+static void em_print_debug_info(struct adapter *);
+#endif
+static int em_is_valid_ether_addr(u_int8_t *);
+#ifndef __rtems__
+static int em_sysctl_stats(SYSCTL_HANDLER_ARGS);
+static int em_sysctl_debug_info(SYSCTL_HANDLER_ARGS);
+#endif
+static u_int32_t em_fill_descriptors (u_int64_t address,
+ u_int32_t length,
+ PDESC_ARRAY desc_array);
+#ifndef __rtems__
+static int em_sysctl_int_delay(SYSCTL_HANDLER_ARGS);
+static void em_add_int_delay_sysctl(struct adapter *, const char *,
+ const char *, struct em_int_delay_info *,
+ int, int);
+#endif
+
+/*********************************************************************
+ * FreeBSD Device Interface Entry Points
+ *********************************************************************/
+
+#ifndef __rtems__
+static device_method_t em_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, em_probe),
+ DEVMETHOD(device_attach, em_attach),
+ DEVMETHOD(device_detach, em_detach),
+ DEVMETHOD(device_shutdown, em_shutdown),
+ {0, 0}
+};
+
+static driver_t em_driver = {
+ "em", em_methods, sizeof(struct adapter ),
+};
+
+static devclass_t em_devclass;
+DRIVER_MODULE(em, pci, em_driver, em_devclass, 0, 0);
+MODULE_DEPEND(em, pci, 1, 1, 1);
+MODULE_DEPEND(em, ether, 1, 1, 1);
+#else
+net_drv_tbl_t METHODS = {
+ n_probe : em_probe,
+ n_attach : em_attach,
+#ifdef DEBUG_MODULAR
+ n_detach : em_detach,
+#else
+ n_detach: 0,
+#endif
+ n_intr : em_intr,
+};
+#endif
+
+/*********************************************************************
+ * Tunable default values.
+ *********************************************************************/
+
+#define E1000_TICKS_TO_USECS(ticks) ((1024 * (ticks) + 500) / 1000)
+#define E1000_USECS_TO_TICKS(usecs) ((1000 * (usecs) + 512) / 1024)
+
+#ifndef __rtems__
+static int em_tx_int_delay_dflt = E1000_TICKS_TO_USECS(EM_TIDV);
+static int em_rx_int_delay_dflt = E1000_TICKS_TO_USECS(EM_RDTR);
+static int em_tx_abs_int_delay_dflt = E1000_TICKS_TO_USECS(EM_TADV);
+static int em_rx_abs_int_delay_dflt = E1000_TICKS_TO_USECS(EM_RADV);
+
+TUNABLE_INT("hw.em.tx_int_delay", &em_tx_int_delay_dflt);
+TUNABLE_INT("hw.em.rx_int_delay", &em_rx_int_delay_dflt);
+TUNABLE_INT("hw.em.tx_abs_int_delay", &em_tx_abs_int_delay_dflt);
+TUNABLE_INT("hw.em.rx_abs_int_delay", &em_rx_abs_int_delay_dflt);
+#endif
+
+/*********************************************************************
+ * Device identification routine
+ *
+ * em_probe determines if the driver should be loaded on
+ * adapter based on PCI vendor/device id of the adapter.
+ *
+ * return BUS_PROBE_DEFAULT on success, positive on failure
+ *********************************************************************/
+
+static int
+em_probe(device_t dev)
+{
+ em_vendor_info_t *ent;
+
+ u_int16_t pci_vendor_id = 0;
+ u_int16_t pci_device_id = 0;
+ u_int16_t pci_subvendor_id = 0;
+ u_int16_t pci_subdevice_id = 0;
+ char adapter_name[60];
+
+ INIT_DEBUGOUT("em_probe: begin");
+
+ pci_vendor_id = pci_get_vendor(dev);
+ if (pci_vendor_id != EM_VENDOR_ID)
+ return(ENXIO);
+
+ pci_device_id = pci_get_device(dev);
+ pci_subvendor_id = pci_get_subvendor(dev);
+ pci_subdevice_id = pci_get_subdevice(dev);
+
+ ent = em_vendor_info_array;
+ while (ent->vendor_id != 0) {
+ if ((pci_vendor_id == ent->vendor_id) &&
+ (pci_device_id == ent->device_id) &&
+
+ ((pci_subvendor_id == ent->subvendor_id) ||
+ (ent->subvendor_id == PCI_ANY_ID)) &&
+
+ ((pci_subdevice_id == ent->subdevice_id) ||
+ (ent->subdevice_id == PCI_ANY_ID))) {
+ sprintf(adapter_name, "%s, Version - %s",
+ em_strings[ent->index],
+ em_driver_version);
+ device_set_desc_copy(dev, adapter_name);
+ return(BUS_PROBE_DEFAULT);
+ }
+ ent++;
+ }
+
+ return(ENXIO);
+}
+
+/*********************************************************************
+ * Device initialization routine
+ *
+ * The attach entry point is called when the driver is being loaded.
+ * This routine identifies the type of hardware, allocates all resources
+ * and initializes the hardware.
+ *
+ * return 0 on success, positive on failure
+ *********************************************************************/
+
+static int
+em_attach(device_t dev)
+{
+ struct adapter * adapter;
+ int tsize, rsize;
+ int error = 0;
+
+ INIT_DEBUGOUT("em_attach: begin");
+
+ /* Allocate, clear, and link in our adapter structure */
+ if (!(adapter = device_get_softc(dev))) {
+ printf("em: adapter structure allocation failed\n");
+ return(ENOMEM);
+ }
+#ifndef __rtems__
+ bzero(adapter, sizeof(struct adapter ));
+#else
+ /* softc structure is maintained outside of this
+ * and the osdep already contains vital fields (memory address)
+ */
+#endif
+ adapter->dev = dev;
+ adapter->osdep.dev = dev;
+ adapter->unit = device_get_unit(dev);
+ EM_LOCK_INIT(adapter, device_get_nameunit(dev));
+
+ if (em_adapter_list != NULL)
+ em_adapter_list->prev = adapter;
+ adapter->next = em_adapter_list;
+ em_adapter_list = adapter;
+
+#ifndef __rtems__
+ /* SYSCTL stuff */
+ SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
+ SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
+ OID_AUTO, "debug_info", CTLTYPE_INT|CTLFLAG_RW,
+ (void *)adapter, 0,
+ em_sysctl_debug_info, "I", "Debug Information");
+
+ SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
+ SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
+ OID_AUTO, "stats", CTLTYPE_INT|CTLFLAG_RW,
+ (void *)adapter, 0,
+ em_sysctl_stats, "I", "Statistics");
+#endif
+
+ callout_init(&adapter->timer, CALLOUT_MPSAFE);
+ callout_init(&adapter->tx_fifo_timer, CALLOUT_MPSAFE);
+
+ /* Determine hardware revision */
+ em_identify_hardware(adapter);
+
+#ifndef __rtems__
+ /* Set up some sysctls for the tunable interrupt delays */
+ em_add_int_delay_sysctl(adapter, "rx_int_delay",
+ "receive interrupt delay in usecs", &adapter->rx_int_delay,
+ E1000_REG_OFFSET(&adapter->hw, RDTR), em_rx_int_delay_dflt);
+ em_add_int_delay_sysctl(adapter, "tx_int_delay",
+ "transmit interrupt delay in usecs", &adapter->tx_int_delay,
+ E1000_REG_OFFSET(&adapter->hw, TIDV), em_tx_int_delay_dflt);
+ if (adapter->hw.mac_type >= em_82540) {
+ em_add_int_delay_sysctl(adapter, "rx_abs_int_delay",
+ "receive interrupt delay limit in usecs",
+ &adapter->rx_abs_int_delay,
+ E1000_REG_OFFSET(&adapter->hw, RADV),
+ em_rx_abs_int_delay_dflt);
+ em_add_int_delay_sysctl(adapter, "tx_abs_int_delay",
+ "transmit interrupt delay limit in usecs",
+ &adapter->tx_abs_int_delay,
+ E1000_REG_OFFSET(&adapter->hw, TADV),
+ em_tx_abs_int_delay_dflt);
+ }
+#endif
+
+ /* Parameters (to be read from user) */
+ adapter->num_tx_desc = EM_MAX_TXD;
+ adapter->num_rx_desc = EM_MAX_RXD;
+#ifdef __rtems__
+ if ( dev->d_ifconfig->rbuf_count > 0 ) {
+ adapter->num_rx_desc = dev->d_ifconfig->rbuf_count;
+ }
+ if ( adapter->num_rx_desc < 80 )
+ adapter->num_rx_desc = 80;
+ if ( adapter->num_rx_desc > 256 )
+ adapter->num_rx_desc = 256;
+ if ( dev->d_ifconfig->xbuf_count > 0 ) {
+ adapter->num_tx_desc = dev->d_ifconfig->xbuf_count;
+ }
+ if ( adapter->num_tx_desc < 80 )
+ adapter->num_tx_desc = 80;
+ if ( adapter->num_tx_desc > 256 )
+ adapter->num_tx_desc = 256;
+ adapter->tx_cleanup_threshold = adapter->num_tx_desc/8;
+#endif
+ adapter->hw.autoneg = DO_AUTO_NEG;
+ adapter->hw.wait_autoneg_complete = WAIT_FOR_AUTO_NEG_DEFAULT;
+ adapter->hw.autoneg_advertised = AUTONEG_ADV_DEFAULT;
+ adapter->hw.tbi_compatibility_en = TRUE;
+ adapter->rx_buffer_len = EM_RXBUFFER_2048;
+
+ /*
+ * These parameters control the automatic generation(Tx) and
+ * response(Rx) to Ethernet PAUSE frames.
+ */
+ adapter->hw.fc_high_water = FC_DEFAULT_HI_THRESH;
+ adapter->hw.fc_low_water = FC_DEFAULT_LO_THRESH;
+ adapter->hw.fc_pause_time = FC_DEFAULT_TX_TIMER;
+ adapter->hw.fc_send_xon = TRUE;
+ adapter->hw.fc = em_fc_full;
+
+ adapter->hw.phy_init_script = 1;
+ adapter->hw.phy_reset_disable = FALSE;
+
+#ifndef EM_MASTER_SLAVE
+ adapter->hw.master_slave = em_ms_hw_default;
+#else
+ adapter->hw.master_slave = EM_MASTER_SLAVE;
+#endif
+ /*
+ * Set the max frame size assuming standard ethernet
+ * sized frames
+ */
+ adapter->hw.max_frame_size =
+ ETHERMTU + ETHER_HDR_LEN + ETHER_CRC_LEN;
+
+ adapter->hw.min_frame_size =
+ MINIMUM_ETHERNET_PACKET_SIZE + ETHER_CRC_LEN;
+
+ /*
+ * This controls when hardware reports transmit completion
+ * status.
+ */
+ adapter->hw.report_tx_early = 1;
+
+
+ if (em_allocate_pci_resources(adapter)) {
+ printf("em%d: Allocation of PCI resources failed\n",
+ adapter->unit);
+ error = ENXIO;
+ goto err_pci;
+ }
+
+
+ /* Initialize eeprom parameters */
+ em_init_eeprom_params(&adapter->hw);
+
+ tsize = EM_ROUNDUP(adapter->num_tx_desc *
+ sizeof(struct em_tx_desc), 4096);
+
+ /* Allocate Transmit Descriptor ring */
+ if (em_dma_malloc(adapter, tsize, &adapter->txdma, BUS_DMA_NOWAIT)) {
+ printf("em%d: Unable to allocate tx_desc memory\n",
+ adapter->unit);
+ error = ENOMEM;
+ goto err_tx_desc;
+ }
+ adapter->tx_desc_base = (struct em_tx_desc *) adapter->txdma.dma_vaddr;
+
+ rsize = EM_ROUNDUP(adapter->num_rx_desc *
+ sizeof(struct em_rx_desc), 4096);
+
+ /* Allocate Receive Descriptor ring */
+ if (em_dma_malloc(adapter, rsize, &adapter->rxdma, BUS_DMA_NOWAIT)) {
+ printf("em%d: Unable to allocate rx_desc memory\n",
+ adapter->unit);
+ error = ENOMEM;
+ goto err_rx_desc;
+ }
+ adapter->rx_desc_base = (struct em_rx_desc *) adapter->rxdma.dma_vaddr;
+
+ /* Initialize the hardware */
+ if (em_hardware_init(adapter)) {
+ printf("em%d: Unable to initialize the hardware\n",
+ adapter->unit);
+ error = EIO;
+ goto err_hw_init;
+ }
+
+ /* Copy the permanent MAC address out of the EEPROM */
+ if (em_read_mac_addr(&adapter->hw) < 0) {
+ printf("em%d: EEPROM read error while reading mac address\n",
+ adapter->unit);
+ error = EIO;
+ goto err_mac_addr;
+ }
+
+#ifdef __rtems__
+ /* if the configuration has not set a mac address, copy the permanent
+ * address from the device to the arpcom struct.
+ */
+ {
+ int i;
+ for ( i=0; i<ETHER_ADDR_LEN; i++ ) {
+ if ( adapter->arpcom.ac_enaddr[i] )
+ break;
+ }
+ if ( i >= ETHER_ADDR_LEN ) {
+ /* all nulls */
+ bcopy(adapter->hw.mac_addr, adapter->arpcom.ac_enaddr,
+ ETHER_ADDR_LEN);
+ }
+ }
+#endif
+
+ if (!em_is_valid_ether_addr(adapter->hw.mac_addr)) {
+ printf("em%d: Invalid mac address\n", adapter->unit);
+ error = EIO;
+ goto err_mac_addr;
+ }
+
+ /* Setup OS specific network interface */
+ em_setup_interface(dev, adapter);
+
+ /* Initialize statistics */
+ em_clear_hw_cntrs(&adapter->hw);
+ em_update_stats_counters(adapter);
+ adapter->hw.get_link_status = 1;
+#ifndef __rtems__
+ em_check_for_link(&adapter->hw);
+#else
+ /* first check during hw init usually fails - probably we need to wait longer;
+ * could take a while till the link is up, depends on the partner?
+ * in any case, rather than waiting here we just proceed...
+ */
+ em_check_for_link(&adapter->hw);
+ /* em_check_for_link doesn't update 'link_active'
+ * -- they usually call em_print_link_status() right
+ * after check_for_link, so let's repeat this
+ * algorithm here.
+ */
+ em_print_link_status(adapter);
+#endif
+
+ /* Print the link status */
+ if (adapter->link_active == 1) {
+ em_get_speed_and_duplex(&adapter->hw, &adapter->link_speed,
+ &adapter->link_duplex);
+ printf("em%d: Speed:%d Mbps Duplex:%s\n",
+ adapter->unit,
+ adapter->link_speed,
+ adapter->link_duplex == FULL_DUPLEX ? "Full" : "Half");
+ } else
+ printf("em%d: Speed:N/A Duplex:N/A\n", adapter->unit);
+
+ /* Identify 82544 on PCIX */
+ em_get_bus_info(&adapter->hw);
+ if(adapter->hw.bus_type == em_bus_type_pcix &&
+ adapter->hw.mac_type == em_82544) {
+ adapter->pcix_82544 = TRUE;
+ }
+ else {
+ adapter->pcix_82544 = FALSE;
+ }
+ INIT_DEBUGOUT("em_attach: end");
+ return(0);
+
+err_mac_addr:
+err_hw_init:
+ em_dma_free(adapter, &adapter->rxdma);
+err_rx_desc:
+ em_dma_free(adapter, &adapter->txdma);
+err_tx_desc:
+err_pci:
+#ifndef __rtems__
+ em_free_pci_resources(adapter);
+#endif
+ return(error);
+
+}
+
+/*********************************************************************
+ * Device removal routine
+ *
+ * The detach entry point is called when the driver is being removed.
+ * This routine stops the adapter and deallocates all the resources
+ * that were allocated for driver operation.
+ *
+ * return 0 on success, positive on failure
+ *********************************************************************/
+
+#if !defined(__rtems__) || defined(DEBUG_MODULAR)
+
+static int
+em_detach(device_t dev)
+{
+ struct adapter * adapter = device_get_softc(dev);
+ struct ifnet *ifp = &adapter->arpcom.ac_if;
+
+ INIT_DEBUGOUT("em_detach: begin");
+
+ EM_LOCK(adapter);
+ adapter->in_detach = 1;
+ em_stop(adapter);
+ em_phy_hw_reset(&adapter->hw);
+ EM_UNLOCK(adapter);
+#ifndef __rtems__
+#if __FreeBSD_version < 500000
+ ether_ifdetach(adapter->ifp, ETHER_BPF_SUPPORTED);
+#else
+ ether_ifdetach(adapter->ifp);
+ if_free(ifp);
+#endif
+ em_free_pci_resources(adapter);
+ bus_generic_detach(dev);
+#else
+ ether_ifdetach(ifp);
+#endif
+
+ /* Free Transmit Descriptor ring */
+ if (adapter->tx_desc_base) {
+ em_dma_free(adapter, &adapter->txdma);
+ adapter->tx_desc_base = NULL;
+ }
+
+ /* Free Receive Descriptor ring */
+ if (adapter->rx_desc_base) {
+ em_dma_free(adapter, &adapter->rxdma);
+ adapter->rx_desc_base = NULL;
+ }
+
+ /* Remove from the adapter list */
+ if (em_adapter_list == adapter)
+ em_adapter_list = adapter->next;
+ if (adapter->next != NULL)
+ adapter->next->prev = adapter->prev;
+ if (adapter->prev != NULL)
+ adapter->prev->next = adapter->next;
+
+ EM_LOCK_DESTROY(adapter);
+
+ ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
+ ifp->if_timer = 0;
+
+ return(0);
+}
+
+#endif
+
+#ifndef __rtems__
+/*********************************************************************
+ *
+ * Shutdown entry point
+ *
+ **********************************************************************/
+
+static int
+em_shutdown(device_t dev)
+{
+ struct adapter *adapter = device_get_softc(dev);
+ EM_LOCK(adapter);
+ em_stop(adapter);
+ EM_UNLOCK(adapter);
+ return(0);
+}
+#endif
+
+/*********************************************************************
+ * Transmit entry point
+ *
+ * em_start is called by the stack to initiate a transmit.
+ * The driver will remain in this routine as long as there are
+ * packets to transmit and transmit resources are available.
+ * In case resources are not available stack is notified and
+ * the packet is requeued.
+ **********************************************************************/
+
+static void
+em_start_locked(struct ifnet *ifp)
+{
+ struct mbuf *m_head;
+ struct adapter *adapter = ifp->if_softc;
+
+ mtx_assert(&adapter->mtx, MA_OWNED);
+
+ if (!adapter->link_active)
+ return;
+
+ while (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) {
+
+ IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head);
+
+ if (m_head == NULL) break;
+
+ /*
+ * em_encap() can modify our pointer, and or make it NULL on
+ * failure. In that event, we can't requeue.
+ */
+ if (em_encap(adapter, &m_head)) {
+ if (m_head == NULL)
+ break;
+ ifp->if_flags |= IFF_OACTIVE;
+ IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
+ break;
+ }
+
+ /* Send a copy of the frame to the BPF listener */
+#if __FreeBSD_version < 500000 && !defined(__rtems__)
+ if (ifp->if_bpf)
+ bpf_mtap(ifp, m_head);
+#else
+ BPF_MTAP(ifp, m_head);
+#endif
+
+ /* Set timeout in case hardware has problems transmitting */
+ ifp->if_timer = EM_TX_TIMEOUT;
+
+ }
+ return;
+}
+
+static void
+em_start(struct ifnet *ifp)
+{
+ struct adapter *adapter __attribute__((unused)) = ifp->if_softc;
+
+ EM_LOCK(adapter);
+ em_start_locked(ifp);
+ EM_UNLOCK(adapter);
+ return;
+}
+
+/*********************************************************************
+ * Ioctl entry point
+ *
+ * em_ioctl is called when the user wants to configure the
+ * interface.
+ *
+ * return 0 on success, positive on failure
+ **********************************************************************/
+
+#ifndef __rtems__
+static int
+em_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
+#else
+static int
+em_ioctl(struct ifnet *ifp, ioctl_command_t command, caddr_t data)
+#endif
+{
+#ifndef __rtems__
+ int mask, reinit, error = 0;
+#else
+ int error = 0;
+#endif
+ struct ifreq *ifr = (struct ifreq *) data;
+ struct adapter * adapter = ifp->if_softc;
+
+ if (adapter->in_detach) return(error);
+
+ switch (command) {
+ case SIOCSIFADDR:
+ case SIOCGIFADDR:
+ IOCTL_DEBUGOUT("ioctl rcv'd: SIOCxIFADDR (Get/Set Interface Addr)");
+ ether_ioctl(ifp, command, data);
+ break;
+ case SIOCSIFMTU:
+ IOCTL_DEBUGOUT("ioctl rcv'd: SIOCSIFMTU (Set Interface MTU)");
+ if (ifr->ifr_mtu > MAX_JUMBO_FRAME_SIZE - ETHER_HDR_LEN || \
+ /* 82573 does not support jumbo frames */
+ (adapter->hw.mac_type == em_82573 && ifr->ifr_mtu > ETHERMTU) ) {
+ error = EINVAL;
+ } else {
+ EM_LOCK(adapter);
+ ifp->if_mtu = ifr->ifr_mtu;
+ adapter->hw.max_frame_size =
+ ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN;
+ em_init_locked(adapter);
+ EM_UNLOCK(adapter);
+ }
+ break;
+ case SIOCSIFFLAGS:
+ IOCTL_DEBUGOUT("ioctl rcv'd: SIOCSIFFLAGS (Set Interface Flags)");
+ EM_LOCK(adapter);
+ if (ifp->if_flags & IFF_UP) {
+ if (!(ifp->if_flags & IFF_RUNNING)) {
+ em_init_locked(adapter);
+ }
+
+ em_disable_promisc(adapter);
+ em_set_promisc(adapter);
+ } else {
+ if (ifp->if_flags & IFF_RUNNING) {
+ em_stop(adapter);
+ }
+ }
+ EM_UNLOCK(adapter);
+ break;
+ case SIOCADDMULTI:
+ case SIOCDELMULTI:
+#ifdef __rtems__
+ if ( (error = ( SIOCADDMULTI == command ?
+ ether_addmulti( ifr, (struct arpcom*)ifp ) :
+ ether_delmulti( ifr, (struct arpcom*)ifp ) ) ) ) {
+ if ( ENETRESET == error )
+ error = 0;
+ else
+ break;
+ }
+#endif
+ IOCTL_DEBUGOUT("ioctl rcv'd: SIOC(ADD|DEL)MULTI");
+ if (ifp->if_flags & IFF_RUNNING) {
+ EM_LOCK(adapter);
+ em_disable_intr(adapter);
+ em_set_multi(adapter);
+ if (adapter->hw.mac_type == em_82542_rev2_0) {
+ em_initialize_receive_unit(adapter);
+ }
+#ifdef DEVICE_POLLING
+ if (!(ifp->if_flags & IFF_POLLING))
+#endif
+ em_enable_intr(adapter);
+ EM_UNLOCK(adapter);
+ }
+ break;
+#ifndef __rtems__
+ case SIOCSIFMEDIA:
+ case SIOCGIFMEDIA:
+ IOCTL_DEBUGOUT("ioctl rcv'd: SIOCxIFMEDIA (Get/Set Interface Media)");
+ error = ifmedia_ioctl(ifp, ifr, &adapter->media, command);
+ break;
+#else
+ case SIOCSIFMEDIA:
+ {
+ struct rtems_ifmedia mhack;
+ mhack.ifm_media = ifr->ifr_media;
+ error = em_media_change(ifp, &mhack);
+ }
+ break;
+ case SIOCGIFMEDIA:
+ {
+ struct ifmediareq ifmr;
+ em_media_status(ifp, &ifmr);
+ ifr->ifr_media = ifmr.ifm_active;
+ /* add-in rtems flags */
+ if ( adapter->link_active )
+ ifr->ifr_media |= IFM_LINK_OK;
+ if ( !adapter->hw.autoneg )
+ ifr->ifr_media |= IFM_ANEG_DIS;
+ error = 0;
+ }
+ break;
+#endif
+#ifndef __rtems__
+ case SIOCSIFCAP:
+ IOCTL_DEBUGOUT("ioctl rcv'd: SIOCSIFCAP (Set Capabilities)");
+ reinit = 0;
+ mask = ifr->ifr_reqcap ^ ifp->if_capenable;
+ if (mask & IFCAP_POLLING)
+ ifp->if_capenable ^= IFCAP_POLLING;
+ if (mask & IFCAP_HWCSUM) {
+ ifp->if_capenable ^= IFCAP_HWCSUM;
+ reinit = 1;
+ }
+ if (mask & IFCAP_VLAN_HWTAGGING) {
+ ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING;
+ reinit = 1;
+ }
+ if (reinit && (ifp->if_flags & IFF_RUNNING))
+ em_init(adapter);
+ break;
+#endif
+
+#ifdef __rtems__
+ case SIO_RTEMS_SHOW_STATS:
+ em_print_hw_stats(adapter);
+ error = 0;
+ break;
+#endif
+
+ default:
+ IOCTL_DEBUGOUT1("ioctl received: UNKNOWN (0x%x)", (int)command);
+ error = EINVAL;
+ }
+
+ return(error);
+}
+
+/*********************************************************************
+ * Watchdog entry point
+ *
+ * This routine is called whenever hardware quits transmitting.
+ *
+ **********************************************************************/
+
+static void
+em_watchdog(struct ifnet *ifp)
+{
+ struct adapter * adapter;
+ adapter = ifp->if_softc;
+
+ /* If we are in this routine because of pause frames, then
+ * don't reset the hardware.
+ */
+ if (E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_TXOFF) {
+ ifp->if_timer = EM_TX_TIMEOUT;
+ return;
+ }
+
+ if (em_check_for_link(&adapter->hw))
+ printf("em%d: watchdog timeout -- resetting\n", adapter->unit);
+
+ ifp->if_flags &= ~IFF_RUNNING;
+
+ em_init(adapter);
+
+ ifp->if_oerrors++;
+ return;
+}
+
+/*********************************************************************
+ * Init entry point
+ *
+ * This routine is used in two ways. It is used by the stack as
+ * init entry point in network interface structure. It is also used
+ * by the driver as a hw/sw initialization routine to get to a
+ * consistent state.
+ *
+ * return 0 on success, positive on failure
+ **********************************************************************/
+
+static void
+em_init_locked(struct adapter * adapter)
+{
+ struct ifnet *ifp;
+
+ uint32_t pba;
+ ifp = &adapter->arpcom.ac_if;
+
+ INIT_DEBUGOUT("em_init: begin");
+
+ mtx_assert(&adapter->mtx, MA_OWNED);
+
+ em_stop(adapter);
+
+ /* Packet Buffer Allocation (PBA)
+ * Writing PBA sets the receive portion of the buffer
+ * the remainder is used for the transmit buffer.
+ *
+ * Devices before the 82547 had a Packet Buffer of 64K.
+ * Default allocation: PBA=48K for Rx, leaving 16K for Tx.
+ * After the 82547 the buffer was reduced to 40K.
+ * Default allocation: PBA=30K for Rx, leaving 10K for Tx.
+ * Note: default does not leave enough room for Jumbo Frame >10k.
+ */
+ if(adapter->hw.mac_type < em_82547) {
+ /* Total FIFO is 64K */
+ if(adapter->rx_buffer_len > EM_RXBUFFER_8192)
+ pba = E1000_PBA_40K; /* 40K for Rx, 24K for Tx */
+ else
+ pba = E1000_PBA_48K; /* 48K for Rx, 16K for Tx */
+ } else {
+ /* Total FIFO is 40K */
+ if(adapter->hw.max_frame_size > EM_RXBUFFER_8192) {
+ pba = E1000_PBA_22K; /* 22K for Rx, 18K for Tx */
+ } else {
+ pba = E1000_PBA_30K; /* 30K for Rx, 10K for Tx */
+ }
+ adapter->tx_fifo_head = 0;
+ adapter->tx_head_addr = pba << EM_TX_HEAD_ADDR_SHIFT;
+ adapter->tx_fifo_size = (E1000_PBA_40K - pba) << EM_PBA_BYTES_SHIFT;
+ }
+ INIT_DEBUGOUT1("em_init: pba=%" PRId32 "K",pba);
+ E1000_WRITE_REG(&adapter->hw, PBA, pba);
+
+ /* Get the latest mac address, User can use a LAA */
+ bcopy(adapter->arpcom.ac_enaddr, adapter->hw.mac_addr,
+ ETHER_ADDR_LEN);
+
+ /* Initialize the hardware */
+ if (em_hardware_init(adapter)) {
+ printf("em%d: Unable to initialize the hardware\n",
+ adapter->unit);
+ return;
+ }
+
+#ifndef __rtems__
+ if (ifp->if_capenable & IFCAP_VLAN_HWTAGGING)
+ em_enable_vlans(adapter);
+#endif
+
+ /* Prepare transmit descriptors and buffers */
+ if (em_setup_transmit_structures(adapter)) {
+ printf("em%d: Could not setup transmit structures\n",
+ adapter->unit);
+ em_stop(adapter);
+ return;
+ }
+ em_initialize_transmit_unit(adapter);
+
+ /* Setup Multicast table */
+ em_set_multi(adapter);
+
+ /* Prepare receive descriptors and buffers */
+ if (em_setup_receive_structures(adapter)) {
+ printf("em%d: Could not setup receive structures\n",
+ adapter->unit);
+ em_stop(adapter);
+ return;
+ }
+ em_initialize_receive_unit(adapter);
+
+ /* Don't loose promiscuous settings */
+ em_set_promisc(adapter);
+
+ ifp->if_flags |= IFF_RUNNING;
+ ifp->if_flags &= ~IFF_OACTIVE;
+
+#ifndef __rtems__
+ if (adapter->hw.mac_type >= em_82543) {
+ if (ifp->if_capenable & IFCAP_TXCSUM)
+ ifp->if_hwassist = EM_CHECKSUM_FEATURES;
+ else
+ ifp->if_hwassist = 0;
+ }
+#endif
+
+ callout_reset(&adapter->timer, hz, em_local_timer, adapter);
+ em_clear_hw_cntrs(&adapter->hw);
+#ifdef DEVICE_POLLING
+ /*
+ * Only enable interrupts if we are not polling, make sure
+ * they are off otherwise.
+ */
+ if (ifp->if_flags & IFF_POLLING)
+ em_disable_intr(adapter);
+ else
+#endif /* DEVICE_POLLING */
+ em_enable_intr(adapter);
+
+ /* Don't reset the phy next time init gets called */
+ adapter->hw.phy_reset_disable = TRUE;
+
+ return;
+}
+
+static void
+em_init(void *arg)
+{
+ struct adapter * adapter = arg;
+
+ EM_LOCK(adapter);
+ em_init_locked(adapter);
+ EM_UNLOCK(adapter);
+ return;
+}
+
+
+#ifdef DEVICE_POLLING
+static poll_handler_t em_poll;
+
+static void
+em_poll_locked(struct ifnet *ifp, enum poll_cmd cmd, int count)
+{
+ struct adapter *adapter = ifp->if_softc;
+ u_int32_t reg_icr;
+
+ mtx_assert(&adapter->mtx, MA_OWNED);
+
+ if (!(ifp->if_capenable & IFCAP_POLLING)) {
+ ether_poll_deregister(ifp);
+ cmd = POLL_DEREGISTER;
+ }
+ if (cmd == POLL_DEREGISTER) { /* final call, enable interrupts */
+ em_enable_intr(adapter);
+ return;
+ }
+ if (cmd == POLL_AND_CHECK_STATUS) {
+ reg_icr = E1000_READ_REG(&adapter->hw, ICR);
+ if (reg_icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) {
+ callout_stop(&adapter->timer);
+ adapter->hw.get_link_status = 1;
+ em_check_for_link(&adapter->hw);
+ em_print_link_status(adapter);
+ callout_reset(&adapter->timer, hz, em_local_timer, adapter);
+ }
+ }
+ if (ifp->if_flags & IFF_RUNNING) {
+ em_process_receive_interrupts(adapter, count);
+ em_clean_transmit_interrupts(adapter);
+ }
+
+ if (ifp->if_flags & IFF_RUNNING && !IFQ_DRV_IS_EMPTY(&ifp->if_snd))
+ em_start_locked(ifp);
+}
+
+static void
+em_poll(struct ifnet *ifp, enum poll_cmd cmd, int count)
+{
+ struct adapter *adapter = ifp->if_softc;
+
+ EM_LOCK(adapter);
+ em_poll_locked(ifp, cmd, count);
+ EM_UNLOCK(adapter);
+}
+#endif /* DEVICE_POLLING */
+
+/*********************************************************************
+ *
+ * Interrupt Service routine
+ *
+ **********************************************************************/
+static void
+em_intr(void *arg)
+{
+ u_int32_t loop_cnt = EM_MAX_INTR;
+ u_int32_t reg_icr;
+ struct ifnet *ifp;
+ struct adapter *adapter = arg;
+
+ EM_LOCK(adapter);
+
+ ifp = &adapter->arpcom.ac_if;
+
+#ifdef DEVICE_POLLING
+ if (ifp->if_flags & IFF_POLLING) {
+ EM_UNLOCK(adapter);
+ return;
+ }
+
+ if ((ifp->if_capenable & IFCAP_POLLING) &&
+ ether_poll_register(em_poll, ifp)) {
+ em_disable_intr(adapter);
+ em_poll_locked(ifp, 0, 1);
+ EM_UNLOCK(adapter);
+ return;
+ }
+#endif /* DEVICE_POLLING */
+
+ reg_icr = E1000_READ_REG(&adapter->hw, ICR);
+ if (!reg_icr) {
+ EM_UNLOCK(adapter);
+ return;
+ }
+
+ /* Link status change */
+ if (reg_icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) {
+ callout_stop(&adapter->timer);
+ adapter->hw.get_link_status = 1;
+ em_check_for_link(&adapter->hw);
+ em_print_link_status(adapter);
+ callout_reset(&adapter->timer, hz, em_local_timer, adapter);
+ }
+
+ while (loop_cnt > 0) {
+ if (ifp->if_flags & IFF_RUNNING) {
+ em_process_receive_interrupts(adapter, -1);
+ em_clean_transmit_interrupts(adapter);
+ }
+ loop_cnt--;
+ }
+
+ if (ifp->if_flags & IFF_RUNNING && !IFQ_DRV_IS_EMPTY(&ifp->if_snd))
+ em_start_locked(ifp);
+
+ EM_UNLOCK(adapter);
+ return;
+}
+
+
+
+/*********************************************************************
+ *
+ * Media Ioctl callback
+ *
+ * This routine is called whenever the user queries the status of
+ * the interface using ifconfig.
+ *
+ **********************************************************************/
+static void
+em_media_status(struct ifnet *ifp, struct ifmediareq *ifmr)
+{
+ struct adapter * adapter = ifp->if_softc;
+
+ INIT_DEBUGOUT("em_media_status: begin");
+
+ em_check_for_link(&adapter->hw);
+ if (E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_LU) {
+ if (adapter->link_active == 0) {
+ em_get_speed_and_duplex(&adapter->hw,
+ &adapter->link_speed,
+ &adapter->link_duplex);
+ adapter->link_active = 1;
+ }
+ } else {
+ if (adapter->link_active == 1) {
+ adapter->link_speed = 0;
+ adapter->link_duplex = 0;
+ adapter->link_active = 0;
+ }
+ }
+
+ ifmr->ifm_status = IFM_AVALID;
+ ifmr->ifm_active = IFM_ETHER;
+
+ if (!adapter->link_active)
+ return;
+
+ ifmr->ifm_status |= IFM_ACTIVE;
+
+ if (adapter->hw.media_type == em_media_type_fiber) {
+ ifmr->ifm_active |= IFM_1000_SX | IFM_FDX;
+ } else {
+ switch (adapter->link_speed) {
+ case 10:
+ ifmr->ifm_active |= IFM_10_T;
+ break;
+ case 100:
+ ifmr->ifm_active |= IFM_100_TX;
+ break;
+ case 1000:
+#if __FreeBSD_version < 500000 && !defined(__rtems__)
+ ifmr->ifm_active |= IFM_1000_TX;
+#else
+ ifmr->ifm_active |= IFM_1000_T;
+#endif
+ break;
+ }
+ if (adapter->link_duplex == FULL_DUPLEX)
+ ifmr->ifm_active |= IFM_FDX;
+ else
+ ifmr->ifm_active |= IFM_HDX;
+ }
+ return;
+}
+
+/*********************************************************************
+ *
+ * Media Ioctl callback
+ *
+ * This routine is called when the user changes speed/duplex using
+ * media/mediopt option with ifconfig.
+ *
+ **********************************************************************/
+static int
+#ifndef __rtems__
+em_media_change(struct ifnet *ifp)
+#else
+em_media_change(struct ifnet *ifp, struct rtems_ifmedia *ifm)
+#endif
+{
+ struct adapter * adapter = ifp->if_softc;
+#ifndef __rtems__
+ struct ifmedia *ifm = &adapter->media;
+#endif
+
+ INIT_DEBUGOUT("em_media_change: begin");
+
+ if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER)
+ return(EINVAL);
+
+ switch (IFM_SUBTYPE(ifm->ifm_media)) {
+ case IFM_AUTO:
+ adapter->hw.autoneg = DO_AUTO_NEG;
+ adapter->hw.autoneg_advertised = AUTONEG_ADV_DEFAULT;
+ break;
+ case IFM_1000_SX:
+#if __FreeBSD_version < 500000 && !defined(__rtems__)
+ case IFM_1000_TX:
+#else
+ case IFM_1000_T:
+#endif
+ adapter->hw.autoneg = DO_AUTO_NEG;
+ adapter->hw.autoneg_advertised = ADVERTISE_1000_FULL;
+ break;
+ case IFM_100_TX:
+ adapter->hw.autoneg = FALSE;
+ adapter->hw.autoneg_advertised = 0;
+ if ((ifm->ifm_media & IFM_GMASK) == IFM_FDX)
+ adapter->hw.forced_speed_duplex = em_100_full;
+ else
+ adapter->hw.forced_speed_duplex = em_100_half;
+ break;
+ case IFM_10_T:
+ adapter->hw.autoneg = FALSE;
+ adapter->hw.autoneg_advertised = 0;
+ if ((ifm->ifm_media & IFM_GMASK) == IFM_FDX)
+ adapter->hw.forced_speed_duplex = em_10_full;
+ else
+ adapter->hw.forced_speed_duplex = em_10_half;
+ break;
+ default:
+ printf("em%d: Unsupported media type\n", adapter->unit);
+ }
+
+ /* As the speed/duplex settings my have changed we need to
+ * reset the PHY.
+ */
+ adapter->hw.phy_reset_disable = FALSE;
+
+ em_init(adapter);
+
+ return(0);
+}
+
+/*********************************************************************
+ *
+ * This routine maps the mbufs to tx descriptors.
+ *
+ * return 0 on success, positive on failure
+ **********************************************************************/
+static int
+em_encap(struct adapter *adapter, struct mbuf **m_headp)
+{
+ u_int32_t txd_upper;
+ u_int32_t txd_lower, txd_used = 0, txd_saved = 0;
+ int i, j, error;
+ u_int64_t address;
+
+ struct mbuf *m_head;
+
+ /* For 82544 Workaround */
+ DESC_ARRAY desc_array;
+ u_int32_t array_elements;
+ u_int32_t counter;
+
+#ifndef __rtems__
+#if __FreeBSD_version < 500000
+ struct ifvlan *ifv = NULL;
+#else
+ struct m_tag *mtag;
+#endif
+#endif
+ bus_dma_segment_t segs[EM_MAX_SCATTER];
+#ifndef __rtems__
+ bus_dmamap_t map;
+#endif
+ int nsegs;
+ struct em_buffer *tx_buffer = NULL;
+ struct em_tx_desc *current_tx_desc = NULL;
+#ifndef __rtems__
+ struct ifnet *ifp = &adapter->arpcom.ac_if;
+#endif
+
+ m_head = *m_headp;
+
+ /*
+ * Force a cleanup if number of TX descriptors
+ * available hits the threshold
+ */
+ if (adapter->num_tx_desc_avail <= EM_TX_CLEANUP_THRESHOLD) {
+ em_clean_transmit_interrupts(adapter);
+ if (adapter->num_tx_desc_avail <= EM_TX_CLEANUP_THRESHOLD) {
+ adapter->no_tx_desc_avail1++;
+ return(ENOBUFS);
+ }
+ }
+
+#ifndef __rtems__
+ /*
+ * Map the packet for DMA.
+ */
+ if (bus_dmamap_create(adapter->txtag, BUS_DMA_NOWAIT, &map)) {
+ adapter->no_tx_map_avail++;
+ return (ENOMEM);
+ }
+ error = bus_dmamap_load_mbuf_sg(adapter->txtag, map, m_head, segs,
+ &nsegs, BUS_DMA_NOWAIT);
+ if (error != 0) {
+ adapter->no_tx_dma_setup++;
+ bus_dmamap_destroy(adapter->txtag, map);
+ return (error);
+ }
+#else
+ error = 0;
+ {
+ struct mbuf *m;
+ for ( m=m_head, nsegs=0; m; m=m->m_next, nsegs++ ) {
+ if ( nsegs >= sizeof(segs)/sizeof(segs[0]) ) {
+ error = -1;
+ break;
+ }
+ segs[nsegs].ds_addr = mtod(m, unsigned);
+ segs[nsegs].ds_len = m->m_len;
+ }
+ }
+#endif
+ KASSERT(nsegs != 0, ("em_encap: empty packet"));
+
+ if (nsegs > adapter->num_tx_desc_avail) {
+ adapter->no_tx_desc_avail2++;
+ bus_dmamap_destroy(adapter->txtag, map);
+ return (ENOBUFS);
+ }
+
+
+#ifndef __rtems__
+ if (ifp->if_hwassist > 0) {
+ em_transmit_checksum_setup(adapter, m_head,
+ &txd_upper, &txd_lower);
+ } else
+#endif
+ txd_upper = txd_lower = 0;
+
+
+#ifndef __rtems__
+ /* Find out if we are in vlan mode */
+#if __FreeBSD_version < 500000
+ if ((m_head->m_flags & (M_PROTO1|M_PKTHDR)) == (M_PROTO1|M_PKTHDR) &&
+ m_head->m_pkthdr.rcvif != NULL &&
+ m_head->m_pkthdr.rcvif->if_type == IFT_L2VLAN)
+ ifv = m_head->m_pkthdr.rcvif->if_softc;
+#else
+ mtag = VLAN_OUTPUT_TAG(ifp, m_head);
+#endif
+
+ /*
+ * When operating in promiscuous mode, hardware encapsulation for
+ * packets is disabled. This means we have to add the vlan
+ * encapsulation in the driver, since it will have come down from the
+ * VLAN layer with a tag instead of a VLAN header.
+ */
+ if (mtag != NULL && adapter->em_insert_vlan_header) {
+ struct ether_vlan_header *evl;
+ struct ether_header eh;
+
+ m_head = m_pullup(m_head, sizeof(eh));
+ if (m_head == NULL) {
+ *m_headp = NULL;
+ bus_dmamap_destroy(adapter->txtag, map);
+ return (ENOBUFS);
+ }
+ eh = *mtod(m_head, struct ether_header *);
+ M_PREPEND(m_head, sizeof(*evl), M_DONTWAIT);
+ if (m_head == NULL) {
+ *m_headp = NULL;
+ bus_dmamap_destroy(adapter->txtag, map);
+ return (ENOBUFS);
+ }
+ m_head = m_pullup(m_head, sizeof(*evl));
+ if (m_head == NULL) {
+ *m_headp = NULL;
+ bus_dmamap_destroy(adapter->txtag, map);
+ return (ENOBUFS);
+ }
+ evl = mtod(m_head, struct ether_vlan_header *);
+ bcopy(&eh, evl, sizeof(*evl));
+ evl->evl_proto = evl->evl_encap_proto;
+ evl->evl_encap_proto = htons(ETHERTYPE_VLAN);
+ evl->evl_tag = htons(VLAN_TAG_VALUE(mtag));
+ m_tag_delete(m_head, mtag);
+ mtag = NULL;
+ *m_headp = m_head;
+ }
+#endif
+
+ i = adapter->next_avail_tx_desc;
+ if (adapter->pcix_82544) {
+ txd_saved = i;
+ txd_used = 0;
+ }
+ for (j = 0; j < nsegs; j++) {
+ /* If adapter is 82544 and on PCIX bus */
+ if(adapter->pcix_82544) {
+ array_elements = 0;
+ address = htole64(segs[j].ds_addr);
+ /*
+ * Check the Address and Length combination and
+ * split the data accordingly
+ */
+ array_elements = em_fill_descriptors(address,
+ htole32(segs[j].ds_len),
+ &desc_array);
+ for (counter = 0; counter < array_elements; counter++) {
+ if (txd_used == adapter->num_tx_desc_avail) {
+ adapter->next_avail_tx_desc = txd_saved;
+ adapter->no_tx_desc_avail2++;
+ bus_dmamap_destroy(adapter->txtag, map);
+ return (ENOBUFS);
+ }
+ tx_buffer = &adapter->tx_buffer_area[i];
+ current_tx_desc = &adapter->tx_desc_base[i];
+ current_tx_desc->buffer_addr = htole64(
+ desc_array.descriptor[counter].address);
+ current_tx_desc->lower.data = htole32(
+ (adapter->txd_cmd | txd_lower |
+ (u_int16_t)desc_array.descriptor[counter].length));
+ current_tx_desc->upper.data = htole32((txd_upper));
+ if (++i == adapter->num_tx_desc)
+ i = 0;
+
+ tx_buffer->m_head = NULL;
+ txd_used++;
+ }
+ } else {
+ tx_buffer = &adapter->tx_buffer_area[i];
+ current_tx_desc = &adapter->tx_desc_base[i];
+
+ current_tx_desc->buffer_addr = htole64(segs[j].ds_addr);
+ current_tx_desc->lower.data = htole32(
+ adapter->txd_cmd | txd_lower | segs[j].ds_len);
+ current_tx_desc->upper.data = htole32(txd_upper);
+
+ if (++i == adapter->num_tx_desc)
+ i = 0;
+
+ tx_buffer->m_head = NULL;
+ }
+ }
+
+ adapter->next_avail_tx_desc = i;
+ if (adapter->pcix_82544) {
+ adapter->num_tx_desc_avail -= txd_used;
+ }
+ else {
+ adapter->num_tx_desc_avail -= nsegs;
+ }
+
+#ifndef __rtems__
+#if __FreeBSD_version < 500000
+ if (ifv != NULL) {
+ /* Set the vlan id */
+ current_tx_desc->upper.fields.special = htole16(ifv->ifv_tag);
+#else
+ if (mtag != NULL) {
+ /* Set the vlan id */
+ current_tx_desc->upper.fields.special = htole16(VLAN_TAG_VALUE(mtag));
+#endif
+
+ /* Tell hardware to add tag */
+ current_tx_desc->lower.data |= htole32(E1000_TXD_CMD_VLE);
+ }
+#endif
+
+ tx_buffer->m_head = m_head;
+#ifndef __rtems__
+ tx_buffer->map = map;
+#endif
+ bus_dmamap_sync(adapter->txtag, map, BUS_DMASYNC_PREWRITE);
+
+ /*
+ * Last Descriptor of Packet needs End Of Packet (EOP)
+ */
+ current_tx_desc->lower.data |= htole32(E1000_TXD_CMD_EOP);
+
+ /*
+ * Advance the Transmit Descriptor Tail (Tdt), this tells the E1000
+ * that this frame is available to transmit.
+ */
+ bus_dmamap_sync(adapter->txdma.dma_tag, adapter->txdma.dma_map,
+ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+ if (adapter->hw.mac_type == em_82547 &&
+ adapter->link_duplex == HALF_DUPLEX) {
+ em_82547_move_tail_locked(adapter);
+ } else {
+ E1000_WRITE_REG(&adapter->hw, TDT, i);
+ if (adapter->hw.mac_type == em_82547) {
+ em_82547_update_fifo_head(adapter, m_head->m_pkthdr.len);
+ }
+ }
+
+ return(0);
+}
+
+/*********************************************************************
+ *
+ * 82547 workaround to avoid controller hang in half-duplex environment.
+ * The workaround is to avoid queuing a large packet that would span
+ * the internal Tx FIFO ring boundary. We need to reset the FIFO pointers
+ * in this case. We do that only when FIFO is quiescent.
+ *
+ **********************************************************************/
+static void
+em_82547_move_tail_locked(struct adapter *adapter)
+{
+ uint16_t hw_tdt;
+ uint16_t sw_tdt;
+ struct em_tx_desc *tx_desc;
+ uint16_t length = 0;
+ boolean_t eop = 0;
+
+ EM_LOCK_ASSERT(adapter);
+
+ hw_tdt = E1000_READ_REG(&adapter->hw, TDT);
+ sw_tdt = adapter->next_avail_tx_desc;
+
+ while (hw_tdt != sw_tdt) {
+ tx_desc = &adapter->tx_desc_base[hw_tdt];
+ length += tx_desc->lower.flags.length;
+ eop = tx_desc->lower.data & E1000_TXD_CMD_EOP;
+ if(++hw_tdt == adapter->num_tx_desc)
+ hw_tdt = 0;
+
+ if(eop) {
+ if (em_82547_fifo_workaround(adapter, length)) {
+ adapter->tx_fifo_wrk_cnt++;
+ callout_reset(&adapter->tx_fifo_timer, 1,
+ em_82547_move_tail, adapter);
+ break;
+ }
+ E1000_WRITE_REG(&adapter->hw, TDT, hw_tdt);
+ em_82547_update_fifo_head(adapter, length);
+ length = 0;
+ }
+ }
+ return;
+}
+
+#ifndef __rtems__
+static void
+em_82547_move_tail(void *arg)
+{
+ struct adapter *adapter = arg;
+
+ EM_LOCK(adapter);
+ em_82547_move_tail_locked(adapter);
+ EM_UNLOCK(adapter);
+}
+#endif
+
+static int
+em_82547_fifo_workaround(struct adapter *adapter, int len)
+{
+ int fifo_space, fifo_pkt_len;
+
+ fifo_pkt_len = EM_ROUNDUP(len + EM_FIFO_HDR, EM_FIFO_HDR);
+
+ if (adapter->link_duplex == HALF_DUPLEX) {
+ fifo_space = adapter->tx_fifo_size - adapter->tx_fifo_head;
+
+ if (fifo_pkt_len >= (EM_82547_PKT_THRESH + fifo_space)) {
+ if (em_82547_tx_fifo_reset(adapter)) {
+ return(0);
+ }
+ else {
+ return(1);
+ }
+ }
+ }
+
+ return(0);
+}
+
+static void
+em_82547_update_fifo_head(struct adapter *adapter, int len)
+{
+ int fifo_pkt_len = EM_ROUNDUP(len + EM_FIFO_HDR, EM_FIFO_HDR);
+
+ /* tx_fifo_head is always 16 byte aligned */
+ adapter->tx_fifo_head += fifo_pkt_len;
+ if (adapter->tx_fifo_head >= adapter->tx_fifo_size) {
+ adapter->tx_fifo_head -= adapter->tx_fifo_size;
+ }
+
+ return;
+}
+
+
+static int
+em_82547_tx_fifo_reset(struct adapter *adapter)
+{
+ uint32_t tctl;
+
+ if ( (E1000_READ_REG(&adapter->hw, TDT) ==
+ E1000_READ_REG(&adapter->hw, TDH)) &&
+ (E1000_READ_REG(&adapter->hw, TDFT) ==
+ E1000_READ_REG(&adapter->hw, TDFH)) &&
+ (E1000_READ_REG(&adapter->hw, TDFTS) ==
+ E1000_READ_REG(&adapter->hw, TDFHS)) &&
+ (E1000_READ_REG(&adapter->hw, TDFPC) == 0)) {
+
+ /* Disable TX unit */
+ tctl = E1000_READ_REG(&adapter->hw, TCTL);
+ E1000_WRITE_REG(&adapter->hw, TCTL, tctl & ~E1000_TCTL_EN);
+
+ /* Reset FIFO pointers */
+ E1000_WRITE_REG(&adapter->hw, TDFT, adapter->tx_head_addr);
+ E1000_WRITE_REG(&adapter->hw, TDFH, adapter->tx_head_addr);
+ E1000_WRITE_REG(&adapter->hw, TDFTS, adapter->tx_head_addr);
+ E1000_WRITE_REG(&adapter->hw, TDFHS, adapter->tx_head_addr);
+
+ /* Re-enable TX unit */
+ E1000_WRITE_REG(&adapter->hw, TCTL, tctl);
+ E1000_WRITE_FLUSH(&adapter->hw);
+
+ adapter->tx_fifo_head = 0;
+ adapter->tx_fifo_reset_cnt++;
+
+ return(TRUE);
+ }
+ else {
+ return(FALSE);
+ }
+}
+
+static void
+em_set_promisc(struct adapter * adapter)
+{
+
+ u_int32_t reg_rctl;
+ struct ifnet *ifp = &adapter->arpcom.ac_if;
+
+ reg_rctl = E1000_READ_REG(&adapter->hw, RCTL);
+
+ if (ifp->if_flags & IFF_PROMISC) {
+ reg_rctl |= (E1000_RCTL_UPE | E1000_RCTL_MPE);
+ E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl);
+#ifndef __rtems__
+ /* Disable VLAN stripping in promiscous mode
+ * This enables bridging of vlan tagged frames to occur
+ * and also allows vlan tags to be seen in tcpdump
+ */
+ if (ifp->if_capenable & IFCAP_VLAN_HWTAGGING)
+ em_disable_vlans(adapter);
+ adapter->em_insert_vlan_header = 1;
+#endif
+ } else if (ifp->if_flags & IFF_ALLMULTI) {
+ reg_rctl |= E1000_RCTL_MPE;
+ reg_rctl &= ~E1000_RCTL_UPE;
+ E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl);
+#ifndef __rtems__
+ adapter->em_insert_vlan_header = 0;
+ } else
+ adapter->em_insert_vlan_header = 0;
+#else
+ }
+#endif
+
+ return;
+}
+
+static void
+em_disable_promisc(struct adapter * adapter)
+{
+ u_int32_t reg_rctl;
+#ifndef __rtems__
+ struct ifnet *ifp = adapter->ifp;
+#endif
+
+ reg_rctl = E1000_READ_REG(&adapter->hw, RCTL);
+
+ reg_rctl &= (~E1000_RCTL_UPE);
+ reg_rctl &= (~E1000_RCTL_MPE);
+ E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl);
+
+#ifndef __rtems__
+ if (ifp->if_capenable & IFCAP_VLAN_HWTAGGING)
+ em_enable_vlans(adapter);
+ adapter->em_insert_vlan_header = 0;
+#endif
+
+ return;
+}
+
+
+/*********************************************************************
+ * Multicast Update
+ *
+ * This routine is called whenever multicast address list is updated.
+ *
+ **********************************************************************/
+
+static void
+em_set_multi(struct adapter * adapter)
+{
+ u_int32_t reg_rctl = 0;
+ u_int8_t mta[MAX_NUM_MULTICAST_ADDRESSES * ETH_LENGTH_OF_ADDRESS];
+#ifndef __rtems__
+ struct ifmultiaddr *ifma;
+#endif
+ int mcnt = 0;
+ struct ifnet *ifp = &adapter->arpcom.ac_if;
+
+ IOCTL_DEBUGOUT("em_set_multi: begin");
+
+ if (adapter->hw.mac_type == em_82542_rev2_0) {
+ reg_rctl = E1000_READ_REG(&adapter->hw, RCTL);
+ if (adapter->hw.pci_cmd_word & CMD_MEM_WRT_INVALIDATE) {
+ em_pci_clear_mwi(&adapter->hw);
+ }
+ reg_rctl |= E1000_RCTL_RST;
+ E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl);
+ msec_delay(5);
+ }
+
+#ifndef __rtems__
+ IF_ADDR_LOCK(ifp);
+#if __FreeBSD_version < 500000
+ LIST_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
+#else
+ TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
+#endif
+ if (ifma->ifma_addr->sa_family != AF_LINK)
+ continue;
+
+ if (mcnt == MAX_NUM_MULTICAST_ADDRESSES) break;
+
+ bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr),
+ &mta[mcnt*ETH_LENGTH_OF_ADDRESS], ETH_LENGTH_OF_ADDRESS);
+ mcnt++;
+ }
+ IF_ADDR_UNLOCK(ifp);
+#else
+ {
+ /* Don't know how to handle address ranges - we warn and ignore
+ * for now...
+ */
+ struct ether_multi *enm;
+ struct ether_multistep step;
+
+ ETHER_FIRST_MULTI(step, (struct arpcom*)ifp, enm);
+ while ( enm != NULL ) {
+ if ( mcnt == MAX_NUM_MULTICAST_ADDRESSES )
+ break;
+ if ( memcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN) ) {
+ printk("if_em: Unable to handle multicast wildcard (not ported yet); skipping/ignoring\n");
+ goto skiptonext;
+ } else {
+ bcopy(enm->enm_addrlo, &mta[mcnt * ETHER_ADDR_LEN], ETHER_ADDR_LEN);
+ }
+ mcnt++;
+skiptonext:
+ ETHER_NEXT_MULTI( step, enm );
+ }
+ }
+#endif
+
+ if (mcnt >= MAX_NUM_MULTICAST_ADDRESSES) {
+ reg_rctl = E1000_READ_REG(&adapter->hw, RCTL);
+ reg_rctl |= E1000_RCTL_MPE;
+ E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl);
+ } else
+ em_mc_addr_list_update(&adapter->hw, mta, mcnt, 0, 1);
+
+ if (adapter->hw.mac_type == em_82542_rev2_0) {
+ reg_rctl = E1000_READ_REG(&adapter->hw, RCTL);
+ reg_rctl &= ~E1000_RCTL_RST;
+ E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl);
+ msec_delay(5);
+ if (adapter->hw.pci_cmd_word & CMD_MEM_WRT_INVALIDATE) {
+ em_pci_set_mwi(&adapter->hw);
+ }
+ }
+
+ return;
+}
+
+#ifndef __rtems__
+/*********************************************************************
+ * Timer routine
+ *
+ * This routine checks for link status and updates statistics.
+ *
+ **********************************************************************/
+
+static void
+em_local_timer(void *arg)
+{
+ struct ifnet *ifp;
+ struct adapter * adapter = arg;
+ ifp = &adapter->arpcom.ac_if;
+
+ EM_LOCK(adapter);
+
+ em_check_for_link(&adapter->hw);
+ em_print_link_status(adapter);
+ em_update_stats_counters(adapter);
+ if (em_display_debug_stats && ifp->if_flags & IFF_RUNNING) {
+ em_print_hw_stats(adapter);
+ }
+ em_smartspeed(adapter);
+
+ callout_reset(&adapter->timer, hz, em_local_timer, adapter);
+
+ EM_UNLOCK(adapter);
+ return;
+}
+#endif
+
+static void
+em_print_link_status(struct adapter * adapter)
+{
+#ifndef __rtems__
+ struct ifnet *ifp = &adapter->arpcom.ac_if;
+#endif
+
+ if (E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_LU) {
+ if (adapter->link_active == 0) {
+ em_get_speed_and_duplex(&adapter->hw,
+ &adapter->link_speed,
+ &adapter->link_duplex);
+ if (bootverbose)
+ printf("em%d: Link is up %d Mbps %s\n",
+ adapter->unit,
+ adapter->link_speed,
+ ((adapter->link_duplex == FULL_DUPLEX) ?
+ "Full Duplex" : "Half Duplex"));
+ adapter->link_active = 1;
+ adapter->smartspeed = 0;
+#ifndef __rtems__
+ if_link_state_change(ifp, LINK_STATE_UP);
+#endif
+ }
+ } else {
+ if (adapter->link_active == 1) {
+ adapter->link_speed = 0;
+ adapter->link_duplex = 0;
+ if (bootverbose)
+ printf("em%d: Link is Down\n", adapter->unit);
+ adapter->link_active = 0;
+#ifndef __rtems__
+ if_link_state_change(ifp, LINK_STATE_UP);
+ if_link_state_change(ifp, LINK_STATE_DOWN);
+#endif
+ }
+ }
+
+ return;
+}
+
+/*********************************************************************
+ *
+ * This routine disables all traffic on the adapter by issuing a
+ * global reset on the MAC and deallocates TX/RX buffers.
+ *
+ **********************************************************************/
+
+static void
+em_stop(void *arg)
+{
+ struct ifnet *ifp;
+ struct adapter * adapter = arg;
+ ifp = &adapter->arpcom.ac_if;
+
+ mtx_assert(&adapter->mtx, MA_OWNED);
+
+ INIT_DEBUGOUT("em_stop: begin");
+#ifdef DEVICE_POLLING
+ ether_poll_deregister(ifp);
+#endif
+ em_disable_intr(adapter);
+ em_reset_hw(&adapter->hw);
+ callout_stop(&adapter->timer);
+ callout_stop(&adapter->tx_fifo_timer);
+ em_free_transmit_structures(adapter);
+ em_free_receive_structures(adapter);
+
+
+ /* Tell the stack that the interface is no longer active */
+ ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
+
+ return;
+}
+
+
+/*********************************************************************
+ *
+ * Determine hardware revision.
+ *
+ **********************************************************************/
+static void
+em_identify_hardware(struct adapter * adapter)
+{
+ device_t dev = adapter->dev;
+
+ /* Make sure our PCI config space has the necessary stuff set */
+ adapter->hw.pci_cmd_word = pci_read_config(dev, PCIR_COMMAND, 2);
+ if (!((adapter->hw.pci_cmd_word & PCIM_CMD_BUSMASTEREN) &&
+ (adapter->hw.pci_cmd_word & PCIM_CMD_MEMEN))) {
+ printf("em%d: Memory Access and/or Bus Master bits were not set!\n",
+ adapter->unit);
+ adapter->hw.pci_cmd_word |=
+ (PCIM_CMD_BUSMASTEREN | PCIM_CMD_MEMEN);
+ pci_write_config(dev, PCIR_COMMAND, adapter->hw.pci_cmd_word, 2);
+ }
+
+ /* Save off the information about this board */
+ adapter->hw.vendor_id = pci_get_vendor(dev);
+ adapter->hw.device_id = pci_get_device(dev);
+ adapter->hw.revision_id = pci_read_config(dev, PCIR_REVID, 1);
+ adapter->hw.subsystem_vendor_id = pci_read_config(dev, PCIR_SUBVEND_0, 2);
+ adapter->hw.subsystem_id = pci_read_config(dev, PCIR_SUBDEV_0, 2);
+
+ /* Identify the MAC */
+ if (em_set_mac_type(&adapter->hw))
+ printf("em%d: Unknown MAC Type\n", adapter->unit);
+
+ if(adapter->hw.mac_type == em_82541 ||
+ adapter->hw.mac_type == em_82541_rev_2 ||
+ adapter->hw.mac_type == em_82547 ||
+ adapter->hw.mac_type == em_82547_rev_2)
+ adapter->hw.phy_init_script = TRUE;
+
+ return;
+}
+
+static int
+em_allocate_pci_resources(struct adapter * adapter)
+{
+ int i, val, rid;
+ device_t dev = adapter->dev;
+
+ rid = EM_MMBA;
+
+#ifndef __rtems__
+ adapter->res_memory = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
+ &rid, RF_ACTIVE);
+ if (!(adapter->res_memory)) {
+ printf("em%d: Unable to allocate bus resource: memory\n",
+ adapter->unit);
+ return(ENXIO);
+ }
+ adapter->osdep.mem_bus_space_tag =
+ rman_get_bustag(adapter->res_memory);
+ adapter->osdep.mem_bus_space_handle =
+ rman_get_bushandle(adapter->res_memory);
+#endif
+
+ adapter->hw.hw_addr = (uint8_t *)&adapter->osdep.mem_bus_space_handle;
+
+
+ if (adapter->hw.mac_type > em_82543) {
+ /* Figure our where our IO BAR is ? */
+ rid = EM_MMBA;
+ for (i = 0; i < 5; i++) {
+ val = pci_read_config(dev, rid, 4);
+ if (val & 0x00000001) {
+#ifndef __rtems__
+ adapter->io_rid = rid;
+#endif
+ break;
+ }
+ rid += 4;
+ }
+
+#ifndef __rtems__
+ adapter->res_ioport = bus_alloc_resource_any(dev,
+ SYS_RES_IOPORT,
+ &adapter->io_rid,
+ RF_ACTIVE);
+ if (!(adapter->res_ioport)) {
+ printf("em%d: Unable to allocate bus resource: ioport\n",
+ adapter->unit);
+ return(ENXIO);
+ }
+
+ adapter->hw.io_base =
+ rman_get_start(adapter->res_ioport);
+#else
+ adapter->hw.io_base = val & PCI_BASE_ADDRESS_IO_MASK;
+#endif
+ }
+
+#ifndef __rtems__
+ rid = 0x0;
+ adapter->res_interrupt = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
+ RF_SHAREABLE |
+ RF_ACTIVE);
+ if (!(adapter->res_interrupt)) {
+ printf("em%d: Unable to allocate bus resource: interrupt\n",
+ adapter->unit);
+ return(ENXIO);
+ }
+ if (bus_setup_intr(dev, adapter->res_interrupt,
+ INTR_TYPE_NET | INTR_MPSAFE,
+ (void (*)(void *)) em_intr, adapter,
+ &adapter->int_handler_tag)) {
+ printf("em%d: Error registering interrupt handler!\n",
+ adapter->unit);
+ return(ENXIO);
+ }
+#endif
+
+ adapter->hw.back = &adapter->osdep;
+
+ return(0);
+}
+
+#ifndef __rtems__
+static void
+em_free_pci_resources(struct adapter * adapter)
+{
+ device_t dev = adapter->dev;
+
+ if (adapter->res_interrupt != NULL) {
+ bus_teardown_intr(dev, adapter->res_interrupt,
+ adapter->int_handler_tag);
+ bus_release_resource(dev, SYS_RES_IRQ, 0,
+ adapter->res_interrupt);
+ }
+ if (adapter->res_memory != NULL) {
+ bus_release_resource(dev, SYS_RES_MEMORY, EM_MMBA,
+ adapter->res_memory);
+ }
+
+ if (adapter->res_ioport != NULL) {
+ bus_release_resource(dev, SYS_RES_IOPORT, adapter->io_rid,
+ adapter->res_ioport);
+ }
+ return;
+}
+#endif
+
+/*********************************************************************
+ *
+ * Initialize the hardware to a configuration as specified by the
+ * adapter structure. The controller is reset, the EEPROM is
+ * verified, the MAC address is set, then the shared initialization
+ * routines are called.
+ *
+ **********************************************************************/
+static int
+em_hardware_init(struct adapter * adapter)
+{
+ INIT_DEBUGOUT("em_hardware_init: begin");
+ /* Issue a global reset */
+ em_reset_hw(&adapter->hw);
+
+ /* When hardware is reset, fifo_head is also reset */
+ adapter->tx_fifo_head = 0;
+
+ /* Make sure we have a good EEPROM before we read from it */
+ if (em_validate_eeprom_checksum(&adapter->hw) < 0) {
+ printf("em%d: The EEPROM Checksum Is Not Valid\n",
+ adapter->unit);
+ return(EIO);
+ }
+
+ if (em_read_part_num(&adapter->hw, &(adapter->part_num)) < 0) {
+ printf("em%d: EEPROM read error while reading part number\n",
+ adapter->unit);
+ return(EIO);
+ }
+
+ if (em_init_hw(&adapter->hw) < 0) {
+ printf("em%d: Hardware Initialization Failed",
+ adapter->unit);
+ return(EIO);
+ }
+
+ em_check_for_link(&adapter->hw);
+ if (E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_LU)
+ adapter->link_active = 1;
+ else
+ adapter->link_active = 0;
+
+ if (adapter->link_active) {
+ em_get_speed_and_duplex(&adapter->hw,
+ &adapter->link_speed,
+ &adapter->link_duplex);
+ } else {
+ adapter->link_speed = 0;
+ adapter->link_duplex = 0;
+ }
+
+ return(0);
+}
+
+/*********************************************************************
+ *
+ * Setup networking device structure and register an interface.
+ *
+ **********************************************************************/
+static void
+em_setup_interface(device_t dev, struct adapter * adapter)
+{
+ struct ifnet *ifp = &device_get_softc(dev)->arpcom.ac_if;
+ INIT_DEBUGOUT("em_setup_interface: begin");
+
+ if_initname(ifp, device_get_name(dev), device_get_unit(dev));
+ ifp->if_mtu = ETHERMTU;
+ ifp->if_baudrate = 1000000000;
+ ifp->if_init = em_init;
+ ifp->if_softc = adapter;
+ ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+#ifdef __rtems__
+ ifp->if_output = ether_output;
+#endif
+ ifp->if_ioctl = em_ioctl;
+ ifp->if_start = em_start;
+ ifp->if_watchdog = em_watchdog;
+#ifndef __rtems__
+ IFQ_SET_MAXLEN(&ifp->if_snd, adapter->num_tx_desc - 1);
+ ifp->if_snd.ifq_drv_maxlen = adapter->num_tx_desc - 1;
+ IFQ_SET_READY(&ifp->if_snd);
+#else
+ ifp->if_snd.ifq_maxlen = adapter->num_tx_desc - 1;
+#endif
+
+#ifndef __rtems__
+#if __FreeBSD_version < 500000
+ ether_ifattach(ifp, ETHER_BPF_SUPPORTED);
+#else
+ ether_ifattach(ifp, adapter->hw.mac_addr);
+#endif
+#else
+ if ( !ifp->if_addrlist ) /* reattach hack */
+ {
+ if_attach(ifp);
+ ether_ifattach(ifp);
+ }
+#endif
+
+#ifndef __rtems__
+ ifp->if_capabilities = ifp->if_capenable = 0;
+
+ if (adapter->hw.mac_type >= em_82543) {
+ ifp->if_capabilities |= IFCAP_HWCSUM;
+ ifp->if_capenable |= IFCAP_HWCSUM;
+ }
+
+ /*
+ * Tell the upper layer(s) we support long frames.
+ */
+ ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header);
+#if __FreeBSD_version >= 500000
+ ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU;
+ ifp->if_capenable |= IFCAP_VLAN_MTU;
+#endif
+
+#ifdef DEVICE_POLLING
+ ifp->if_capabilities |= IFCAP_POLLING;
+ ifp->if_capenable |= IFCAP_POLLING;
+#endif
+
+ /*
+ * Specify the media types supported by this adapter and register
+ * callbacks to update media and link information
+ */
+ ifmedia_init(&adapter->media, IFM_IMASK, em_media_change,
+ em_media_status);
+ if (adapter->hw.media_type == em_media_type_fiber) {
+ ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_SX | IFM_FDX,
+ 0, NULL);
+ ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_SX,
+ 0, NULL);
+ } else {
+ ifmedia_add(&adapter->media, IFM_ETHER | IFM_10_T, 0, NULL);
+ ifmedia_add(&adapter->media, IFM_ETHER | IFM_10_T | IFM_FDX,
+ 0, NULL);
+ ifmedia_add(&adapter->media, IFM_ETHER | IFM_100_TX,
+ 0, NULL);
+ ifmedia_add(&adapter->media, IFM_ETHER | IFM_100_TX | IFM_FDX,
+ 0, NULL);
+#if __FreeBSD_version < 500000
+ ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_TX | IFM_FDX,
+ 0, NULL);
+ ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_TX, 0, NULL);
+#else
+ ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_T | IFM_FDX,
+ 0, NULL);
+ ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_T, 0, NULL);
+#endif
+ }
+ ifmedia_add(&adapter->media, IFM_ETHER | IFM_AUTO, 0, NULL);
+ ifmedia_set(&adapter->media, IFM_ETHER | IFM_AUTO);
+#endif
+
+ return;
+}
+
+#ifndef __rtems__
+/*********************************************************************
+ *
+ * Workaround for SmartSpeed on 82541 and 82547 controllers
+ *
+ **********************************************************************/
+static void
+em_smartspeed(struct adapter *adapter)
+{
+ uint16_t phy_tmp;
+
+ if(adapter->link_active || (adapter->hw.phy_type != em_phy_igp) ||
+ !adapter->hw.autoneg || !(adapter->hw.autoneg_advertised & ADVERTISE_1000_FULL))
+ return;
+
+ if(adapter->smartspeed == 0) {
+ /* If Master/Slave config fault is asserted twice,
+ * we assume back-to-back */
+ em_read_phy_reg(&adapter->hw, PHY_1000T_STATUS, &phy_tmp);
+ if(!(phy_tmp & SR_1000T_MS_CONFIG_FAULT)) return;
+ em_read_phy_reg(&adapter->hw, PHY_1000T_STATUS, &phy_tmp);
+ if(phy_tmp & SR_1000T_MS_CONFIG_FAULT) {
+ em_read_phy_reg(&adapter->hw, PHY_1000T_CTRL,
+ &phy_tmp);
+ if(phy_tmp & CR_1000T_MS_ENABLE) {
+ phy_tmp &= ~CR_1000T_MS_ENABLE;
+ em_write_phy_reg(&adapter->hw,
+ PHY_1000T_CTRL, phy_tmp);
+ adapter->smartspeed++;
+ if(adapter->hw.autoneg &&
+ !em_phy_setup_autoneg(&adapter->hw) &&
+ !em_read_phy_reg(&adapter->hw, PHY_CTRL,
+ &phy_tmp)) {
+ phy_tmp |= (MII_CR_AUTO_NEG_EN |
+ MII_CR_RESTART_AUTO_NEG);
+ em_write_phy_reg(&adapter->hw,
+ PHY_CTRL, phy_tmp);
+ }
+ }
+ }
+ return;
+ } else if(adapter->smartspeed == EM_SMARTSPEED_DOWNSHIFT) {
+ /* If still no link, perhaps using 2/3 pair cable */
+ em_read_phy_reg(&adapter->hw, PHY_1000T_CTRL, &phy_tmp);
+ phy_tmp |= CR_1000T_MS_ENABLE;
+ em_write_phy_reg(&adapter->hw, PHY_1000T_CTRL, phy_tmp);
+ if(adapter->hw.autoneg &&
+ !em_phy_setup_autoneg(&adapter->hw) &&
+ !em_read_phy_reg(&adapter->hw, PHY_CTRL, &phy_tmp)) {
+ phy_tmp |= (MII_CR_AUTO_NEG_EN |
+ MII_CR_RESTART_AUTO_NEG);
+ em_write_phy_reg(&adapter->hw, PHY_CTRL, phy_tmp);
+ }
+ }
+ /* Restart process after EM_SMARTSPEED_MAX iterations */
+ if(adapter->smartspeed++ == EM_SMARTSPEED_MAX)
+ adapter->smartspeed = 0;
+
+ return;
+}
+
+
+/*
+ * Manage DMA'able memory.
+ */
+static void
+em_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error)
+{
+ if (error)
+ return;
+ *(bus_addr_t*) arg = segs->ds_addr;
+ return;
+}
+#endif
+
+static int
+em_dma_malloc(struct adapter *adapter, bus_size_t size,
+ struct em_dma_alloc *dma, int mapflags)
+{
+ int r;
+
+#ifndef __rtems__
+ r = bus_dma_tag_create(NULL, /* parent */
+ PAGE_SIZE, 0, /* alignment, bounds */
+ BUS_SPACE_MAXADDR, /* lowaddr */
+ BUS_SPACE_MAXADDR, /* highaddr */
+ NULL, NULL, /* filter, filterarg */
+ size, /* maxsize */
+ 1, /* nsegments */
+ size, /* maxsegsize */
+ BUS_DMA_ALLOCNOW, /* flags */
+ NULL, /* lockfunc */
+ NULL, /* lockarg */
+ &dma->dma_tag);
+ if (r != 0) {
+ printf("em%d: em_dma_malloc: bus_dma_tag_create failed; "
+ "error %u\n", adapter->unit, r);
+ goto fail_0;
+ }
+
+ r = bus_dmamem_alloc(dma->dma_tag, (void**) &dma->dma_vaddr,
+ BUS_DMA_NOWAIT, &dma->dma_map);
+#else
+ if ( (dma->malloc_base = malloc( size + PAGE_SIZE, M_DEVBUF, M_NOWAIT )) ) {
+ r = 0;
+ dma->dma_vaddr = (caddr_t)_DO_ALIGN(dma->malloc_base, PAGE_SIZE);
+ } else {
+ r = -1;
+ }
+#endif
+ if (r != 0) {
+#ifndef __rtems__
+ printf("em%d: em_dma_malloc: bus_dmammem_alloc failed; "
+ "size %ju, error %d\n", adapter->unit,
+ (uintmax_t)size, r);
+#else
+ printf("em%d: em_dma_malloc: bus_dmammem_alloc failed; "
+ "size %u, error %d\n", adapter->unit,
+ size, r);
+#endif
+ goto fail_2;
+ }
+
+#ifndef __rtems__
+ r = bus_dmamap_load(dma->dma_tag, dma->dma_map, dma->dma_vaddr,
+ size,
+ em_dmamap_cb,
+ &dma->dma_paddr,
+ mapflags | BUS_DMA_NOWAIT);
+#else
+ dma->dma_paddr = kvtop(dma->dma_vaddr);
+#endif
+ if (r != 0) {
+ printf("em%d: em_dma_malloc: bus_dmamap_load failed; "
+ "error %u\n", adapter->unit, r);
+ goto fail_3;
+ }
+
+#ifndef __rtems__
+ dma->dma_size = size;
+#endif
+ return (0);
+
+fail_3:
+ bus_dmamap_unload(dma->dma_tag, dma->dma_map);
+fail_2:
+#ifndef __rtems__
+ bus_dmamem_free(dma->dma_tag, dma->dma_vaddr, dma->dma_map);
+#else
+ free(dma->malloc_base, M_DEVBUF);
+ dma->dma_vaddr = dma->malloc_base = 0;
+ dma->dma_paddr = 0;
+#endif
+ bus_dma_tag_destroy(dma->dma_tag);
+#ifndef __rtems__
+fail_0:
+ dma->dma_map = NULL;
+ dma->dma_tag = NULL;
+#endif
+ return (r);
+}
+
+static void
+em_dma_free(struct adapter *adapter, struct em_dma_alloc *dma)
+{
+ bus_dmamap_unload(dma->dma_tag, dma->dma_map);
+#ifndef __rtems__
+ bus_dmamem_free(dma->dma_tag, dma->dma_vaddr, dma->dma_map);
+#else
+ free(dma->malloc_base, M_DEVBUF);
+ dma->dma_vaddr = dma->malloc_base = 0;
+ dma->dma_paddr = 0;
+#endif
+ bus_dma_tag_destroy(dma->dma_tag);
+}
+
+
+/*********************************************************************
+ *
+ * Allocate memory for tx_buffer structures. The tx_buffer stores all
+ * the information needed to transmit a packet on the wire.
+ *
+ **********************************************************************/
+static int
+em_allocate_transmit_structures(struct adapter * adapter)
+{
+ if (!(adapter->tx_buffer_area =
+ (struct em_buffer *) malloc(sizeof(struct em_buffer) *
+ adapter->num_tx_desc, M_DEVBUF,
+ M_NOWAIT))) {
+ printf("em%d: Unable to allocate tx_buffer memory\n",
+ adapter->unit);
+ return ENOMEM;
+ }
+
+ bzero(adapter->tx_buffer_area,
+ sizeof(struct em_buffer) * adapter->num_tx_desc);
+
+ return 0;
+}
+
+/*********************************************************************
+ *
+ * Allocate and initialize transmit structures.
+ *
+ **********************************************************************/
+static int
+em_setup_transmit_structures(struct adapter * adapter)
+{
+#ifndef __rtems__
+ /*
+ * Setup DMA descriptor areas.
+ */
+ if (bus_dma_tag_create(NULL, /* parent */
+ 1, 0, /* alignment, bounds */
+ BUS_SPACE_MAXADDR, /* lowaddr */
+ BUS_SPACE_MAXADDR, /* highaddr */
+ NULL, NULL, /* filter, filterarg */
+ MCLBYTES * 8, /* maxsize */
+ EM_MAX_SCATTER, /* nsegments */
+ MCLBYTES * 8, /* maxsegsize */
+ BUS_DMA_ALLOCNOW, /* flags */
+ NULL, /* lockfunc */
+ NULL, /* lockarg */
+ &adapter->txtag)) {
+ printf("em%d: Unable to allocate TX DMA tag\n", adapter->unit);
+ return (ENOMEM);
+ }
+#endif
+
+ if (em_allocate_transmit_structures(adapter))
+ return (ENOMEM);
+
+ bzero((void *) adapter->tx_desc_base,
+ (sizeof(struct em_tx_desc)) * adapter->num_tx_desc);
+
+ adapter->next_avail_tx_desc = 0;
+ adapter->oldest_used_tx_desc = 0;
+
+ /* Set number of descriptors available */
+ adapter->num_tx_desc_avail = adapter->num_tx_desc;
+
+ /* Set checksum context */
+ adapter->active_checksum_context = OFFLOAD_NONE;
+
+ return (0);
+}
+
+/*********************************************************************
+ *
+ * Enable transmit unit.
+ *
+ **********************************************************************/
+static void
+em_initialize_transmit_unit(struct adapter * adapter)
+{
+ u_int32_t reg_tctl;
+ u_int32_t reg_tipg = 0;
+ u_int64_t bus_addr;
+
+ INIT_DEBUGOUT("em_initialize_transmit_unit: begin");
+ /* Setup the Base and Length of the Tx Descriptor Ring */
+ bus_addr = adapter->txdma.dma_paddr;
+ E1000_WRITE_REG(&adapter->hw, TDBAL, (u_int32_t)bus_addr);
+ E1000_WRITE_REG(&adapter->hw, TDBAH, (u_int32_t)(bus_addr >> 32));
+ E1000_WRITE_REG(&adapter->hw, TDLEN,
+ adapter->num_tx_desc *
+ sizeof(struct em_tx_desc));
+
+ /* Setup the HW Tx Head and Tail descriptor pointers */
+ E1000_WRITE_REG(&adapter->hw, TDH, 0);
+ E1000_WRITE_REG(&adapter->hw, TDT, 0);
+
+
+ HW_DEBUGOUT2("Base = %x, Length = %x\n",
+ E1000_READ_REG(&adapter->hw, TDBAL),
+ E1000_READ_REG(&adapter->hw, TDLEN));
+
+ /* Set the default values for the Tx Inter Packet Gap timer */
+ switch (adapter->hw.mac_type) {
+ case em_82542_rev2_0:
+ case em_82542_rev2_1:
+ reg_tipg = DEFAULT_82542_TIPG_IPGT;
+ reg_tipg |= DEFAULT_82542_TIPG_IPGR1 << E1000_TIPG_IPGR1_SHIFT;
+ reg_tipg |= DEFAULT_82542_TIPG_IPGR2 << E1000_TIPG_IPGR2_SHIFT;
+ break;
+ default:
+ if (adapter->hw.media_type == em_media_type_fiber)
+ reg_tipg = DEFAULT_82543_TIPG_IPGT_FIBER;
+ else
+ reg_tipg = DEFAULT_82543_TIPG_IPGT_COPPER;
+ reg_tipg |= DEFAULT_82543_TIPG_IPGR1 << E1000_TIPG_IPGR1_SHIFT;
+ reg_tipg |= DEFAULT_82543_TIPG_IPGR2 << E1000_TIPG_IPGR2_SHIFT;
+ }
+
+ E1000_WRITE_REG(&adapter->hw, TIPG, reg_tipg);
+ E1000_WRITE_REG(&adapter->hw, TIDV, adapter->tx_int_delay.value);
+ if(adapter->hw.mac_type >= em_82540)
+ E1000_WRITE_REG(&adapter->hw, TADV,
+ adapter->tx_abs_int_delay.value);
+
+ /* Program the Transmit Control Register */
+ reg_tctl = E1000_TCTL_PSP | E1000_TCTL_EN |
+ (E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT);
+ if (adapter->hw.mac_type >= em_82573)
+ reg_tctl |= E1000_TCTL_MULR;
+ if (adapter->link_duplex == 1) {
+ reg_tctl |= E1000_FDX_COLLISION_DISTANCE << E1000_COLD_SHIFT;
+ } else {
+ reg_tctl |= E1000_HDX_COLLISION_DISTANCE << E1000_COLD_SHIFT;
+ }
+ E1000_WRITE_REG(&adapter->hw, TCTL, reg_tctl);
+
+ /* Setup Transmit Descriptor Settings for this adapter */
+ adapter->txd_cmd = E1000_TXD_CMD_IFCS | E1000_TXD_CMD_RS;
+
+ if (adapter->tx_int_delay.value > 0)
+ adapter->txd_cmd |= E1000_TXD_CMD_IDE;
+
+ return;
+}
+
+/*********************************************************************
+ *
+ * Free all transmit related data structures.
+ *
+ **********************************************************************/
+static void
+em_free_transmit_structures(struct adapter * adapter)
+{
+ struct em_buffer *tx_buffer;
+ int i;
+
+ INIT_DEBUGOUT("free_transmit_structures: begin");
+
+ if (adapter->tx_buffer_area != NULL) {
+ tx_buffer = adapter->tx_buffer_area;
+ for (i = 0; i < adapter->num_tx_desc; i++, tx_buffer++) {
+ if (tx_buffer->m_head != NULL) {
+ bus_dmamap_unload(adapter->txtag, tx_buffer->map);
+ bus_dmamap_destroy(adapter->txtag, tx_buffer->map);
+ m_freem(tx_buffer->m_head);
+ }
+ tx_buffer->m_head = NULL;
+ }
+ }
+ if (adapter->tx_buffer_area != NULL) {
+ free(adapter->tx_buffer_area, M_DEVBUF);
+ adapter->tx_buffer_area = NULL;
+ }
+#ifndef __rtems__
+ if (adapter->txtag != NULL) {
+ bus_dma_tag_destroy(adapter->txtag);
+ adapter->txtag = NULL;
+ }
+#endif
+ return;
+}
+
+#ifndef __rtems__
+/*********************************************************************
+ *
+ * The offload context needs to be set when we transfer the first
+ * packet of a particular protocol (TCP/UDP). We change the
+ * context only if the protocol type changes.
+ *
+ **********************************************************************/
+static void
+em_transmit_checksum_setup(struct adapter * adapter,
+ struct mbuf *mp,
+ u_int32_t *txd_upper,
+ u_int32_t *txd_lower)
+{
+ struct em_context_desc *TXD;
+ struct em_buffer *tx_buffer;
+ int curr_txd;
+
+ if (mp->m_pkthdr.csum_flags) {
+
+ if (mp->m_pkthdr.csum_flags & CSUM_TCP) {
+ *txd_upper = E1000_TXD_POPTS_TXSM << 8;
+ *txd_lower = E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D;
+ if (adapter->active_checksum_context == OFFLOAD_TCP_IP)
+ return;
+ else
+ adapter->active_checksum_context = OFFLOAD_TCP_IP;
+
+ } else if (mp->m_pkthdr.csum_flags & CSUM_UDP) {
+ *txd_upper = E1000_TXD_POPTS_TXSM << 8;
+ *txd_lower = E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D;
+ if (adapter->active_checksum_context == OFFLOAD_UDP_IP)
+ return;
+ else
+ adapter->active_checksum_context = OFFLOAD_UDP_IP;
+ } else {
+ *txd_upper = 0;
+ *txd_lower = 0;
+ return;
+ }
+ } else {
+ *txd_upper = 0;
+ *txd_lower = 0;
+ return;
+ }
+
+ /* If we reach this point, the checksum offload context
+ * needs to be reset.
+ */
+ curr_txd = adapter->next_avail_tx_desc;
+ tx_buffer = &adapter->tx_buffer_area[curr_txd];
+ TXD = (struct em_context_desc *) &adapter->tx_desc_base[curr_txd];
+
+ TXD->lower_setup.ip_fields.ipcss = ETHER_HDR_LEN;
+ TXD->lower_setup.ip_fields.ipcso =
+ ETHER_HDR_LEN + offsetof(struct ip, ip_sum);
+ TXD->lower_setup.ip_fields.ipcse =
+ htole16(ETHER_HDR_LEN + sizeof(struct ip) - 1);
+
+ TXD->upper_setup.tcp_fields.tucss =
+ ETHER_HDR_LEN + sizeof(struct ip);
+ TXD->upper_setup.tcp_fields.tucse = htole16(0);
+
+ if (adapter->active_checksum_context == OFFLOAD_TCP_IP) {
+ TXD->upper_setup.tcp_fields.tucso =
+ ETHER_HDR_LEN + sizeof(struct ip) +
+ offsetof(struct tcphdr, th_sum);
+ } else if (adapter->active_checksum_context == OFFLOAD_UDP_IP) {
+ TXD->upper_setup.tcp_fields.tucso =
+ ETHER_HDR_LEN + sizeof(struct ip) +
+ offsetof(struct udphdr, uh_sum);
+ }
+
+ TXD->tcp_seg_setup.data = htole32(0);
+ TXD->cmd_and_length = htole32(adapter->txd_cmd | E1000_TXD_CMD_DEXT);
+
+ tx_buffer->m_head = NULL;
+
+ if (++curr_txd == adapter->num_tx_desc)
+ curr_txd = 0;
+
+ adapter->num_tx_desc_avail--;
+ adapter->next_avail_tx_desc = curr_txd;
+
+ return;
+}
+#endif
+
+/**********************************************************************
+ *
+ * Examine each tx_buffer in the used queue. If the hardware is done
+ * processing the packet then free associated resources. The
+ * tx_buffer is put back on the free queue.
+ *
+ **********************************************************************/
+static void
+em_clean_transmit_interrupts(struct adapter * adapter)
+{
+ int i, num_avail;
+ struct em_buffer *tx_buffer;
+ struct em_tx_desc *tx_desc;
+ struct ifnet *ifp = &adapter->arpcom.ac_if;
+
+ mtx_assert(&adapter->mtx, MA_OWNED);
+
+ if (adapter->num_tx_desc_avail == adapter->num_tx_desc)
+ return;
+
+ num_avail = adapter->num_tx_desc_avail;
+ i = adapter->oldest_used_tx_desc;
+
+ tx_buffer = &adapter->tx_buffer_area[i];
+ tx_desc = &adapter->tx_desc_base[i];
+
+ bus_dmamap_sync(adapter->txdma.dma_tag, adapter->txdma.dma_map,
+ BUS_DMASYNC_POSTREAD);
+ while (tx_desc->upper.fields.status & E1000_TXD_STAT_DD) {
+
+ tx_desc->upper.data = 0;
+ num_avail++;
+
+ if (tx_buffer->m_head) {
+ ifp->if_opackets++;
+ bus_dmamap_unload(adapter->txtag, tx_buffer->map);
+ bus_dmamap_destroy(adapter->txtag, tx_buffer->map);
+
+ m_freem(tx_buffer->m_head);
+ tx_buffer->m_head = NULL;
+ }
+
+ if (++i == adapter->num_tx_desc)
+ i = 0;
+
+ tx_buffer = &adapter->tx_buffer_area[i];
+ tx_desc = &adapter->tx_desc_base[i];
+ }
+ bus_dmamap_sync(adapter->txdma.dma_tag, adapter->txdma.dma_map,
+ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+
+ adapter->oldest_used_tx_desc = i;
+
+ /*
+ * If we have enough room, clear IFF_OACTIVE to tell the stack
+ * that it is OK to send packets.
+ * If there are no pending descriptors, clear the timeout. Otherwise,
+ * if some descriptors have been freed, restart the timeout.
+ */
+ if (num_avail > EM_TX_CLEANUP_THRESHOLD) {
+ ifp->if_flags &= ~IFF_OACTIVE;
+ if (num_avail == adapter->num_tx_desc)
+ ifp->if_timer = 0;
+ else if (num_avail == adapter->num_tx_desc_avail)
+ ifp->if_timer = EM_TX_TIMEOUT;
+ }
+ adapter->num_tx_desc_avail = num_avail;
+ return;
+}
+
+/*********************************************************************
+ *
+ * Get a buffer from system mbuf buffer pool.
+ *
+ **********************************************************************/
+static int
+em_get_buf(int i, struct adapter *adapter,
+ struct mbuf *nmp)
+{
+ register struct mbuf *mp = nmp;
+ struct em_buffer *rx_buffer;
+ struct ifnet *ifp;
+ bus_addr_t paddr;
+#ifndef __rtems__
+ int error;
+#endif
+
+ ifp = &adapter->arpcom.ac_if;
+
+ if (mp == NULL) {
+#ifndef __rtems__
+ mp = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
+#else
+ MGETHDR(mp, M_DONTWAIT, MT_DATA);
+ if ( mp ) {
+ MCLGET( mp, M_DONTWAIT );
+ if ( !(mp->m_flags & M_EXT) ) {
+ m_freem(mp);
+ mp = 0;
+ }
+ }
+#endif
+ if (mp == NULL) {
+ adapter->mbuf_cluster_failed++;
+ return(ENOBUFS);
+ }
+ mp->m_len = mp->m_pkthdr.len = MCLBYTES;
+ } else {
+ mp->m_len = mp->m_pkthdr.len = MCLBYTES;
+ mp->m_data = mp->m_ext.ext_buf;
+ mp->m_next = NULL;
+ }
+
+ if (ifp->if_mtu <= ETHERMTU) {
+ m_adj(mp, ETHER_ALIGN);
+ }
+
+ rx_buffer = &adapter->rx_buffer_area[i];
+
+#ifndef __rtems__
+ /*
+ * Using memory from the mbuf cluster pool, invoke the
+ * bus_dma machinery to arrange the memory mapping.
+ */
+ error = bus_dmamap_load(adapter->rxtag, rx_buffer->map,
+ mtod(mp, void *), mp->m_len,
+ em_dmamap_cb, &paddr, 0);
+ if (error) {
+ m_free(mp);
+ return(error);
+ }
+#else
+ paddr = kvtop(mtod(mp, void*));
+#endif
+
+ rx_buffer->m_head = mp;
+ adapter->rx_desc_base[i].buffer_addr = htole64(paddr);
+ bus_dmamap_sync(adapter->rxtag, rx_buffer->map, BUS_DMASYNC_PREREAD);
+
+ return(0);
+}
+
+/*********************************************************************
+ *
+ * Allocate memory for rx_buffer structures. Since we use one
+ * rx_buffer per received packet, the maximum number of rx_buffer's
+ * that we'll need is equal to the number of receive descriptors
+ * that we've allocated.
+ *
+ **********************************************************************/
+static int
+em_allocate_receive_structures(struct adapter * adapter)
+{
+ int i, error;
+#ifndef __rtems__
+ struct em_buffer *rx_buffer;
+#endif
+
+ if (!(adapter->rx_buffer_area =
+ (struct em_buffer *) malloc(sizeof(struct em_buffer) *
+ adapter->num_rx_desc, M_DEVBUF,
+ M_NOWAIT))) {
+ printf("em%d: Unable to allocate rx_buffer memory\n",
+ adapter->unit);
+ return(ENOMEM);
+ }
+
+ bzero(adapter->rx_buffer_area,
+ sizeof(struct em_buffer) * adapter->num_rx_desc);
+
+#ifndef __rtems__
+ error = bus_dma_tag_create(NULL, /* parent */
+ 1, 0, /* alignment, bounds */
+ BUS_SPACE_MAXADDR, /* lowaddr */
+ BUS_SPACE_MAXADDR, /* highaddr */
+ NULL, NULL, /* filter, filterarg */
+ MCLBYTES, /* maxsize */
+ 1, /* nsegments */
+ MCLBYTES, /* maxsegsize */
+ BUS_DMA_ALLOCNOW, /* flags */
+ NULL, /* lockfunc */
+ NULL, /* lockarg */
+ &adapter->rxtag);
+ if (error != 0) {
+ printf("em%d: em_allocate_receive_structures: "
+ "bus_dma_tag_create failed; error %u\n",
+ adapter->unit, error);
+ goto fail_0;
+ }
+ rx_buffer = adapter->rx_buffer_area;
+ for (i = 0; i < adapter->num_rx_desc; i++, rx_buffer++) {
+ error = bus_dmamap_create(adapter->rxtag, BUS_DMA_NOWAIT,
+ &rx_buffer->map);
+ if (error != 0) {
+ printf("em%d: em_allocate_receive_structures: "
+ "bus_dmamap_create failed; error %u\n",
+ adapter->unit, error);
+ goto fail_1;
+ }
+ }
+
+#else
+ error = 0;
+#endif
+
+ for (i = 0; i < adapter->num_rx_desc; i++) {
+ error = em_get_buf(i, adapter, NULL);
+ if (error != 0) {
+ adapter->rx_buffer_area[i].m_head = NULL;
+ adapter->rx_desc_base[i].buffer_addr = 0;
+ return(error);
+ }
+ }
+ bus_dmamap_sync(adapter->rxdma.dma_tag, adapter->rxdma.dma_map,
+ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+
+ return(0);
+
+#ifndef __rtems__
+fail_1:
+ bus_dma_tag_destroy(adapter->rxtag);
+fail_0:
+ adapter->rxtag = NULL;
+#endif
+ free(adapter->rx_buffer_area, M_DEVBUF);
+ adapter->rx_buffer_area = NULL;
+ return (error);
+}
+
+/*********************************************************************
+ *
+ * Allocate and initialize receive structures.
+ *
+ **********************************************************************/
+static int
+em_setup_receive_structures(struct adapter * adapter)
+{
+ bzero((void *) adapter->rx_desc_base,
+ (sizeof(struct em_rx_desc)) * adapter->num_rx_desc);
+
+ if (em_allocate_receive_structures(adapter))
+ return ENOMEM;
+
+ /* Setup our descriptor pointers */
+ adapter->next_rx_desc_to_check = 0;
+ return(0);
+}
+
+/*********************************************************************
+ *
+ * Enable receive unit.
+ *
+ **********************************************************************/
+static void
+em_initialize_receive_unit(struct adapter * adapter)
+{
+ u_int32_t reg_rctl;
+#ifndef __rtems__
+ u_int32_t reg_rxcsum;
+#endif
+ struct ifnet *ifp;
+ u_int64_t bus_addr;
+
+ INIT_DEBUGOUT("em_initialize_receive_unit: begin");
+ ifp = &adapter->arpcom.ac_if;
+
+ /* Make sure receives are disabled while setting up the descriptor ring */
+ E1000_WRITE_REG(&adapter->hw, RCTL, 0);
+
+ /* Set the Receive Delay Timer Register */
+ E1000_WRITE_REG(&adapter->hw, RDTR,
+ adapter->rx_int_delay.value | E1000_RDT_FPDB);
+
+ if(adapter->hw.mac_type >= em_82540) {
+ E1000_WRITE_REG(&adapter->hw, RADV,
+ adapter->rx_abs_int_delay.value);
+
+ /* Set the interrupt throttling rate. Value is calculated
+ * as DEFAULT_ITR = 1/(MAX_INTS_PER_SEC * 256ns) */
+#define MAX_INTS_PER_SEC 8000
+#define DEFAULT_ITR 1000000000/(MAX_INTS_PER_SEC * 256)
+ E1000_WRITE_REG(&adapter->hw, ITR, DEFAULT_ITR);
+ }
+
+ /* Setup the Base and Length of the Rx Descriptor Ring */
+ bus_addr = adapter->rxdma.dma_paddr;
+ E1000_WRITE_REG(&adapter->hw, RDBAL, (u_int32_t)bus_addr);
+ E1000_WRITE_REG(&adapter->hw, RDBAH, (u_int32_t)(bus_addr >> 32));
+ E1000_WRITE_REG(&adapter->hw, RDLEN, adapter->num_rx_desc *
+ sizeof(struct em_rx_desc));
+
+ /* Setup the HW Rx Head and Tail Descriptor Pointers */
+ E1000_WRITE_REG(&adapter->hw, RDH, 0);
+ E1000_WRITE_REG(&adapter->hw, RDT, adapter->num_rx_desc - 1);
+
+ /* Setup the Receive Control Register */
+ reg_rctl = E1000_RCTL_EN | E1000_RCTL_BAM | E1000_RCTL_LBM_NO |
+ E1000_RCTL_RDMTS_HALF |
+ (adapter->hw.mc_filter_type << E1000_RCTL_MO_SHIFT);
+
+ if (adapter->hw.tbi_compatibility_on == TRUE)
+ reg_rctl |= E1000_RCTL_SBP;
+
+
+ switch (adapter->rx_buffer_len) {
+ default:
+ case EM_RXBUFFER_2048:
+ reg_rctl |= E1000_RCTL_SZ_2048;
+ break;
+ case EM_RXBUFFER_4096:
+ reg_rctl |= E1000_RCTL_SZ_4096 | E1000_RCTL_BSEX | E1000_RCTL_LPE;
+ break;
+ case EM_RXBUFFER_8192:
+ reg_rctl |= E1000_RCTL_SZ_8192 | E1000_RCTL_BSEX | E1000_RCTL_LPE;
+ break;
+ case EM_RXBUFFER_16384:
+ reg_rctl |= E1000_RCTL_SZ_16384 | E1000_RCTL_BSEX | E1000_RCTL_LPE;
+ break;
+ }
+
+ if (ifp->if_mtu > ETHERMTU)
+ reg_rctl |= E1000_RCTL_LPE;
+
+#ifndef __rtems__
+ /* Enable 82543 Receive Checksum Offload for TCP and UDP */
+ if ((adapter->hw.mac_type >= em_82543) &&
+ (ifp->if_capenable & IFCAP_RXCSUM)) {
+ reg_rxcsum = E1000_READ_REG(&adapter->hw, RXCSUM);
+ reg_rxcsum |= (E1000_RXCSUM_IPOFL | E1000_RXCSUM_TUOFL);
+ E1000_WRITE_REG(&adapter->hw, RXCSUM, reg_rxcsum);
+ }
+#endif
+
+ /* Enable Receives */
+ E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl);
+
+ return;
+}
+
+/*********************************************************************
+ *
+ * Free receive related data structures.
+ *
+ **********************************************************************/
+static void
+em_free_receive_structures(struct adapter *adapter)
+{
+ struct em_buffer *rx_buffer;
+ int i;
+
+ INIT_DEBUGOUT("free_receive_structures: begin");
+
+ if (adapter->rx_buffer_area != NULL) {
+ rx_buffer = adapter->rx_buffer_area;
+ for (i = 0; i < adapter->num_rx_desc; i++, rx_buffer++) {
+#ifndef __rtems__
+ if (rx_buffer->map != NULL) {
+ bus_dmamap_unload(adapter->rxtag, rx_buffer->map);
+ bus_dmamap_destroy(adapter->rxtag, rx_buffer->map);
+ }
+#endif
+ if (rx_buffer->m_head != NULL)
+ m_freem(rx_buffer->m_head);
+ rx_buffer->m_head = NULL;
+ }
+ }
+ if (adapter->rx_buffer_area != NULL) {
+ free(adapter->rx_buffer_area, M_DEVBUF);
+ adapter->rx_buffer_area = NULL;
+ }
+#ifndef __rtems__
+ if (adapter->rxtag != NULL) {
+ bus_dma_tag_destroy(adapter->rxtag);
+ adapter->rxtag = NULL;
+ }
+#endif
+ return;
+}
+
+/*********************************************************************
+ *
+ * This routine executes in interrupt context. It replenishes
+ * the mbufs in the descriptor and sends data which has been
+ * dma'ed into host memory to upper layer.
+ *
+ * We loop at most count times if count is > 0, or until done if
+ * count < 0.
+ *
+ *********************************************************************/
+static void
+em_process_receive_interrupts(struct adapter * adapter, int count)
+{
+ struct ifnet *ifp;
+ struct mbuf *mp;
+#if __FreeBSD_version < 500000
+ struct ether_header *eh;
+#endif
+ u_int8_t accept_frame = 0;
+ u_int8_t eop = 0;
+ u_int16_t len, desc_len, prev_len_adj;
+ int i;
+
+ /* Pointer to the receive descriptor being examined. */
+ struct em_rx_desc *current_desc;
+
+ mtx_assert(&adapter->mtx, MA_OWNED);
+
+ ifp = &adapter->arpcom.ac_if;
+ i = adapter->next_rx_desc_to_check;
+ current_desc = &adapter->rx_desc_base[i];
+ bus_dmamap_sync(adapter->rxdma.dma_tag, adapter->rxdma.dma_map,
+ BUS_DMASYNC_POSTREAD);
+
+ if (!((current_desc->status) & E1000_RXD_STAT_DD)) {
+ return;
+ }
+
+ while ((current_desc->status & E1000_RXD_STAT_DD) && (count != 0)) {
+
+ mp = adapter->rx_buffer_area[i].m_head;
+ bus_dmamap_sync(adapter->rxtag, adapter->rx_buffer_area[i].map,
+ BUS_DMASYNC_POSTREAD);
+
+ accept_frame = 1;
+ prev_len_adj = 0;
+ desc_len = le16toh(current_desc->length);
+ if (current_desc->status & E1000_RXD_STAT_EOP) {
+ count--;
+ eop = 1;
+ if (desc_len < ETHER_CRC_LEN) {
+ len = 0;
+ prev_len_adj = ETHER_CRC_LEN - desc_len;
+ }
+ else {
+ len = desc_len - ETHER_CRC_LEN;
+ }
+ } else {
+ eop = 0;
+ len = desc_len;
+ }
+
+ if (current_desc->errors & E1000_RXD_ERR_FRAME_ERR_MASK) {
+ u_int8_t last_byte;
+ u_int32_t pkt_len = desc_len;
+
+ if (adapter->fmp != NULL)
+ pkt_len += adapter->fmp->m_pkthdr.len;
+
+ last_byte = *(mtod(mp, caddr_t) + desc_len - 1);
+
+ if (TBI_ACCEPT(&adapter->hw, current_desc->status,
+ current_desc->errors,
+ pkt_len, last_byte)) {
+ em_tbi_adjust_stats(&adapter->hw,
+ &adapter->stats,
+ pkt_len,
+ adapter->hw.mac_addr);
+ if (len > 0) len--;
+ }
+ else {
+ accept_frame = 0;
+ }
+ }
+
+ if (accept_frame) {
+
+ if (em_get_buf(i, adapter, NULL) == ENOBUFS) {
+ adapter->dropped_pkts++;
+ em_get_buf(i, adapter, mp);
+ if (adapter->fmp != NULL)
+ m_freem(adapter->fmp);
+ adapter->fmp = NULL;
+ adapter->lmp = NULL;
+ break;
+ }
+
+ /* Assign correct length to the current fragment */
+ mp->m_len = len;
+
+ if (adapter->fmp == NULL) {
+ mp->m_pkthdr.len = len;
+ adapter->fmp = mp; /* Store the first mbuf */
+ adapter->lmp = mp;
+ } else {
+ /* Chain mbuf's together */
+ mp->m_flags &= ~M_PKTHDR;
+ /*
+ * Adjust length of previous mbuf in chain if we
+ * received less than 4 bytes in the last descriptor.
+ */
+ if (prev_len_adj > 0) {
+ adapter->lmp->m_len -= prev_len_adj;
+ adapter->fmp->m_pkthdr.len -= prev_len_adj;
+ }
+ adapter->lmp->m_next = mp;
+ adapter->lmp = adapter->lmp->m_next;
+ adapter->fmp->m_pkthdr.len += len;
+ }
+
+ if (eop) {
+ adapter->fmp->m_pkthdr.rcvif = ifp;
+ ifp->if_ipackets++;
+
+#if __FreeBSD_version < 500000
+ eh = mtod(adapter->fmp, struct ether_header *);
+ /* Remove ethernet header from mbuf */
+ m_adj(adapter->fmp, sizeof(struct ether_header));
+#ifndef __rtems__
+ em_receive_checksum(adapter, current_desc,
+ adapter->fmp);
+ if (current_desc->status & E1000_RXD_STAT_VP)
+ VLAN_INPUT_TAG(eh, adapter->fmp,
+ (current_desc->special &
+ E1000_RXD_SPC_VLAN_MASK));
+ else
+#endif
+ ether_input(ifp, eh, adapter->fmp);
+#else
+
+ em_receive_checksum(adapter, current_desc,
+ adapter->fmp);
+ if (current_desc->status & E1000_RXD_STAT_VP)
+ VLAN_INPUT_TAG(ifp, adapter->fmp,
+ (current_desc->special &
+ E1000_RXD_SPC_VLAN_MASK),
+ adapter->fmp = NULL);
+
+ if (adapter->fmp != NULL) {
+ EM_UNLOCK(adapter);
+ (*ifp->if_input)(ifp, adapter->fmp);
+ EM_LOCK(adapter);
+ }
+#endif
+ adapter->fmp = NULL;
+ adapter->lmp = NULL;
+ }
+ } else {
+ adapter->dropped_pkts++;
+ em_get_buf(i, adapter, mp);
+ if (adapter->fmp != NULL)
+ m_freem(adapter->fmp);
+ adapter->fmp = NULL;
+ adapter->lmp = NULL;
+ }
+
+ /* Zero out the receive descriptors status */
+ current_desc->status = 0;
+
+ /* Advance the E1000's Receive Queue #0 "Tail Pointer". */
+ E1000_WRITE_REG(&adapter->hw, RDT, i);
+
+ /* Advance our pointers to the next descriptor */
+ if (++i == adapter->num_rx_desc) {
+ i = 0;
+ current_desc = adapter->rx_desc_base;
+ } else
+ current_desc++;
+ }
+ bus_dmamap_sync(adapter->rxdma.dma_tag, adapter->rxdma.dma_map,
+ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+ adapter->next_rx_desc_to_check = i;
+ return;
+}
+
+#ifndef __rtems__
+/*********************************************************************
+ *
+ * Verify that the hardware indicated that the checksum is valid.
+ * Inform the stack about the status of checksum so that stack
+ * doesn't spend time verifying the checksum.
+ *
+ *********************************************************************/
+static void
+em_receive_checksum(struct adapter *adapter,
+ struct em_rx_desc *rx_desc,
+ struct mbuf *mp)
+{
+ /* 82543 or newer only */
+ if ((adapter->hw.mac_type < em_82543) ||
+ /* Ignore Checksum bit is set */
+ (rx_desc->status & E1000_RXD_STAT_IXSM)) {
+ mp->m_pkthdr.csum_flags = 0;
+ return;
+ }
+
+ if (rx_desc->status & E1000_RXD_STAT_IPCS) {
+ /* Did it pass? */
+ if (!(rx_desc->errors & E1000_RXD_ERR_IPE)) {
+ /* IP Checksum Good */
+ mp->m_pkthdr.csum_flags = CSUM_IP_CHECKED;
+ mp->m_pkthdr.csum_flags |= CSUM_IP_VALID;
+
+ } else {
+ mp->m_pkthdr.csum_flags = 0;
+ }
+ }
+
+ if (rx_desc->status & E1000_RXD_STAT_TCPCS) {
+ /* Did it pass? */
+ if (!(rx_desc->errors & E1000_RXD_ERR_TCPE)) {
+ mp->m_pkthdr.csum_flags |=
+ (CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
+ mp->m_pkthdr.csum_data = htons(0xffff);
+ }
+ }
+
+ return;
+}
+
+
+static void
+em_enable_vlans(struct adapter *adapter)
+{
+ uint32_t ctrl;
+
+ E1000_WRITE_REG(&adapter->hw, VET, ETHERTYPE_VLAN);
+
+ ctrl = E1000_READ_REG(&adapter->hw, CTRL);
+ ctrl |= E1000_CTRL_VME;
+ E1000_WRITE_REG(&adapter->hw, CTRL, ctrl);
+
+ return;
+}
+
+static void
+em_disable_vlans(struct adapter *adapter)
+{
+ uint32_t ctrl;
+
+ ctrl = E1000_READ_REG(&adapter->hw, CTRL);
+ ctrl &= ~E1000_CTRL_VME;
+ E1000_WRITE_REG(&adapter->hw, CTRL, ctrl);
+
+ return;
+}
+#endif
+
+static void
+em_enable_intr(struct adapter * adapter)
+{
+ E1000_WRITE_REG(&adapter->hw, IMS, (IMS_ENABLE_MASK));
+ return;
+}
+
+static void
+em_disable_intr(struct adapter *adapter)
+{
+ /*
+ * The first version of 82542 had an errata where when link was forced it
+ * would stay up even up even if the cable was disconnected. Sequence errors
+ * were used to detect the disconnect and then the driver would unforce the link.
+ * This code in the in the ISR. For this to work correctly the Sequence error
+ * interrupt had to be enabled all the time.
+ */
+
+ if (adapter->hw.mac_type == em_82542_rev2_0)
+ E1000_WRITE_REG(&adapter->hw, IMC,
+ (0xffffffff & ~E1000_IMC_RXSEQ));
+ else
+ E1000_WRITE_REG(&adapter->hw, IMC,
+ 0xffffffff);
+ return;
+}
+
+static int
+em_is_valid_ether_addr(u_int8_t *addr)
+{
+ char zero_addr[6] = { 0, 0, 0, 0, 0, 0 };
+
+ if ((addr[0] & 1) || (!bcmp(addr, zero_addr, ETHER_ADDR_LEN))) {
+ return (FALSE);
+ }
+
+ return(TRUE);
+}
+
+void
+em_write_pci_cfg(struct em_hw *hw,
+ uint32_t reg,
+ uint16_t *value)
+{
+ pci_write_config(((struct em_osdep *)hw->back)->dev, reg,
+ *value, 2);
+}
+
+void
+em_read_pci_cfg(struct em_hw *hw, uint32_t reg,
+ uint16_t *value)
+{
+ *value = pci_read_config(((struct em_osdep *)hw->back)->dev,
+ reg, 2);
+ return;
+}
+
+void
+em_pci_set_mwi(struct em_hw *hw)
+{
+ pci_write_config(((struct em_osdep *)hw->back)->dev,
+ PCIR_COMMAND,
+ (hw->pci_cmd_word | CMD_MEM_WRT_INVALIDATE), 2);
+ return;
+}
+
+void
+em_pci_clear_mwi(struct em_hw *hw)
+{
+ pci_write_config(((struct em_osdep *)hw->back)->dev,
+ PCIR_COMMAND,
+ (hw->pci_cmd_word & ~CMD_MEM_WRT_INVALIDATE), 2);
+ return;
+}
+
+uint32_t
+em_io_read(struct em_hw *hw, unsigned long port)
+{
+ return(inl(port));
+}
+
+void
+em_io_write(struct em_hw *hw, unsigned long port, uint32_t value)
+{
+#ifndef __rtems__
+ outl(port, value);
+#else
+ /* everybody else has this the other way round! */
+ outl(value, port);
+#endif
+ return;
+}
+
+/*********************************************************************
+* 82544 Coexistence issue workaround.
+* There are 2 issues.
+* 1. Transmit Hang issue.
+* To detect this issue, following equation can be used...
+* SIZE[3:0] + ADDR[2:0] = SUM[3:0].
+* If SUM[3:0] is in between 1 to 4, we will have this issue.
+*
+* 2. DAC issue.
+* To detect this issue, following equation can be used...
+* SIZE[3:0] + ADDR[2:0] = SUM[3:0].
+* If SUM[3:0] is in between 9 to c, we will have this issue.
+*
+*
+* WORKAROUND:
+* Make sure we do not have ending address as 1,2,3,4(Hang) or 9,a,b,c (DAC)
+*
+*** *********************************************************************/
+static u_int32_t
+em_fill_descriptors (u_int64_t address,
+ u_int32_t length,
+ PDESC_ARRAY desc_array)
+{
+ /* Since issue is sensitive to length and address.*/
+ /* Let us first check the address...*/
+ u_int32_t safe_terminator;
+ if (length <= 4) {
+ desc_array->descriptor[0].address = address;
+ desc_array->descriptor[0].length = length;
+ desc_array->elements = 1;
+ return desc_array->elements;
+ }
+ safe_terminator = (u_int32_t)((((u_int32_t)address & 0x7) + (length & 0xF)) & 0xF);
+ /* if it does not fall between 0x1 to 0x4 and 0x9 to 0xC then return */
+ if (safe_terminator == 0 ||
+ (safe_terminator > 4 &&
+ safe_terminator < 9) ||
+ (safe_terminator > 0xC &&
+ safe_terminator <= 0xF)) {
+ desc_array->descriptor[0].address = address;
+ desc_array->descriptor[0].length = length;
+ desc_array->elements = 1;
+ return desc_array->elements;
+ }
+
+ desc_array->descriptor[0].address = address;
+ desc_array->descriptor[0].length = length - 4;
+ desc_array->descriptor[1].address = address + (length - 4);
+ desc_array->descriptor[1].length = 4;
+ desc_array->elements = 2;
+ return desc_array->elements;
+}
+
+/**********************************************************************
+ *
+ * Update the board statistics counters.
+ *
+ **********************************************************************/
+static void
+em_update_stats_counters(struct adapter *adapter)
+{
+ struct ifnet *ifp;
+
+ if(adapter->hw.media_type == em_media_type_copper ||
+ (E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_LU)) {
+ adapter->stats.symerrs += E1000_READ_REG(&adapter->hw, SYMERRS);
+ adapter->stats.sec += E1000_READ_REG(&adapter->hw, SEC);
+ }
+ adapter->stats.crcerrs += E1000_READ_REG(&adapter->hw, CRCERRS);
+ adapter->stats.mpc += E1000_READ_REG(&adapter->hw, MPC);
+ adapter->stats.scc += E1000_READ_REG(&adapter->hw, SCC);
+ adapter->stats.ecol += E1000_READ_REG(&adapter->hw, ECOL);
+
+ adapter->stats.mcc += E1000_READ_REG(&adapter->hw, MCC);
+ adapter->stats.latecol += E1000_READ_REG(&adapter->hw, LATECOL);
+ adapter->stats.colc += E1000_READ_REG(&adapter->hw, COLC);
+ adapter->stats.dc += E1000_READ_REG(&adapter->hw, DC);
+ adapter->stats.rlec += E1000_READ_REG(&adapter->hw, RLEC);
+ adapter->stats.xonrxc += E1000_READ_REG(&adapter->hw, XONRXC);
+ adapter->stats.xontxc += E1000_READ_REG(&adapter->hw, XONTXC);
+ adapter->stats.xoffrxc += E1000_READ_REG(&adapter->hw, XOFFRXC);
+ adapter->stats.xofftxc += E1000_READ_REG(&adapter->hw, XOFFTXC);
+ adapter->stats.fcruc += E1000_READ_REG(&adapter->hw, FCRUC);
+ adapter->stats.prc64 += E1000_READ_REG(&adapter->hw, PRC64);
+ adapter->stats.prc127 += E1000_READ_REG(&adapter->hw, PRC127);
+ adapter->stats.prc255 += E1000_READ_REG(&adapter->hw, PRC255);
+ adapter->stats.prc511 += E1000_READ_REG(&adapter->hw, PRC511);
+ adapter->stats.prc1023 += E1000_READ_REG(&adapter->hw, PRC1023);
+ adapter->stats.prc1522 += E1000_READ_REG(&adapter->hw, PRC1522);
+ adapter->stats.gprc += E1000_READ_REG(&adapter->hw, GPRC);
+ adapter->stats.bprc += E1000_READ_REG(&adapter->hw, BPRC);
+ adapter->stats.mprc += E1000_READ_REG(&adapter->hw, MPRC);
+ adapter->stats.gptc += E1000_READ_REG(&adapter->hw, GPTC);
+
+ /* For the 64-bit byte counters the low dword must be read first. */
+ /* Both registers clear on the read of the high dword */
+
+ adapter->stats.gorcl += E1000_READ_REG(&adapter->hw, GORCL);
+ adapter->stats.gorch += E1000_READ_REG(&adapter->hw, GORCH);
+ adapter->stats.gotcl += E1000_READ_REG(&adapter->hw, GOTCL);
+ adapter->stats.gotch += E1000_READ_REG(&adapter->hw, GOTCH);
+
+ adapter->stats.rnbc += E1000_READ_REG(&adapter->hw, RNBC);
+ adapter->stats.ruc += E1000_READ_REG(&adapter->hw, RUC);
+ adapter->stats.rfc += E1000_READ_REG(&adapter->hw, RFC);
+ adapter->stats.roc += E1000_READ_REG(&adapter->hw, ROC);
+ adapter->stats.rjc += E1000_READ_REG(&adapter->hw, RJC);
+
+ adapter->stats.torl += E1000_READ_REG(&adapter->hw, TORL);
+ adapter->stats.torh += E1000_READ_REG(&adapter->hw, TORH);
+ adapter->stats.totl += E1000_READ_REG(&adapter->hw, TOTL);
+ adapter->stats.toth += E1000_READ_REG(&adapter->hw, TOTH);
+
+ adapter->stats.tpr += E1000_READ_REG(&adapter->hw, TPR);
+ adapter->stats.tpt += E1000_READ_REG(&adapter->hw, TPT);
+ adapter->stats.ptc64 += E1000_READ_REG(&adapter->hw, PTC64);
+ adapter->stats.ptc127 += E1000_READ_REG(&adapter->hw, PTC127);
+ adapter->stats.ptc255 += E1000_READ_REG(&adapter->hw, PTC255);
+ adapter->stats.ptc511 += E1000_READ_REG(&adapter->hw, PTC511);
+ adapter->stats.ptc1023 += E1000_READ_REG(&adapter->hw, PTC1023);
+ adapter->stats.ptc1522 += E1000_READ_REG(&adapter->hw, PTC1522);
+ adapter->stats.mptc += E1000_READ_REG(&adapter->hw, MPTC);
+ adapter->stats.bptc += E1000_READ_REG(&adapter->hw, BPTC);
+
+ if (adapter->hw.mac_type >= em_82543) {
+ adapter->stats.algnerrc +=
+ E1000_READ_REG(&adapter->hw, ALGNERRC);
+ adapter->stats.rxerrc +=
+ E1000_READ_REG(&adapter->hw, RXERRC);
+ adapter->stats.tncrs +=
+ E1000_READ_REG(&adapter->hw, TNCRS);
+ adapter->stats.cexterr +=
+ E1000_READ_REG(&adapter->hw, CEXTERR);
+ adapter->stats.tsctc +=
+ E1000_READ_REG(&adapter->hw, TSCTC);
+ adapter->stats.tsctfc +=
+ E1000_READ_REG(&adapter->hw, TSCTFC);
+ }
+ ifp = &adapter->arpcom.ac_if;
+
+ /* Fill out the OS statistics structure */
+ ifp->if_ibytes = adapter->stats.gorcl;
+ ifp->if_obytes = adapter->stats.gotcl;
+ ifp->if_imcasts = adapter->stats.mprc;
+ ifp->if_collisions = adapter->stats.colc;
+
+ /* Rx Errors */
+ ifp->if_ierrors =
+ adapter->dropped_pkts +
+ adapter->stats.rxerrc +
+ adapter->stats.crcerrs +
+ adapter->stats.algnerrc +
+ adapter->stats.rlec +
+ adapter->stats.mpc + adapter->stats.cexterr;
+
+ /* Tx Errors */
+ ifp->if_oerrors = adapter->stats.ecol + adapter->stats.latecol;
+
+}
+
+#ifndef __rtems__
+/**********************************************************************
+ *
+ * This routine is called only when em_display_debug_stats is enabled.
+ * This routine provides a way to take a look at important statistics
+ * maintained by the driver and hardware.
+ *
+ **********************************************************************/
+static void
+em_print_debug_info(struct adapter *adapter)
+{
+ int unit = adapter->unit;
+ uint8_t *hw_addr = adapter->hw.hw_addr;
+
+ printf("em%d: Adapter hardware address = %p \n", unit, hw_addr);
+ printf("em%d:CTRL = 0x%x\n", unit,
+ E1000_READ_REG(&adapter->hw, CTRL));
+ printf("em%d:RCTL = 0x%x PS=(0x8402)\n", unit,
+ E1000_READ_REG(&adapter->hw, RCTL));
+ printf("em%d:tx_int_delay = %d, tx_abs_int_delay = %d\n", unit,
+ E1000_READ_REG(&adapter->hw, TIDV),
+ E1000_READ_REG(&adapter->hw, TADV));
+ printf("em%d:rx_int_delay = %d, rx_abs_int_delay = %d\n", unit,
+ E1000_READ_REG(&adapter->hw, RDTR),
+ E1000_READ_REG(&adapter->hw, RADV));
+ printf("em%d: fifo workaround = %lld, fifo_reset = %lld\n", unit,
+ (long long)adapter->tx_fifo_wrk_cnt,
+ (long long)adapter->tx_fifo_reset_cnt);
+ printf("em%d: hw tdh = %d, hw tdt = %d\n", unit,
+ E1000_READ_REG(&adapter->hw, TDH),
+ E1000_READ_REG(&adapter->hw, TDT));
+ printf("em%d: Num Tx descriptors avail = %d\n", unit,
+ adapter->num_tx_desc_avail);
+ printf("em%d: Tx Descriptors not avail1 = %ld\n", unit,
+ adapter->no_tx_desc_avail1);
+ printf("em%d: Tx Descriptors not avail2 = %ld\n", unit,
+ adapter->no_tx_desc_avail2);
+ printf("em%d: Std mbuf failed = %ld\n", unit,
+ adapter->mbuf_alloc_failed);
+ printf("em%d: Std mbuf cluster failed = %ld\n", unit,
+ adapter->mbuf_cluster_failed);
+ printf("em%d: Driver dropped packets = %ld\n", unit,
+ adapter->dropped_pkts);
+
+ return;
+}
+#endif
+
+static void
+em_print_hw_stats(struct adapter *adapter)
+{
+ int unit = adapter->unit;
+
+ printf("em%d: Excessive collisions = %lld\n", unit,
+ (long long)adapter->stats.ecol);
+ printf("em%d: Symbol errors = %lld\n", unit,
+ (long long)adapter->stats.symerrs);
+ printf("em%d: Sequence errors = %lld\n", unit,
+ (long long)adapter->stats.sec);
+ printf("em%d: Defer count = %lld\n", unit,
+ (long long)adapter->stats.dc);
+
+ printf("em%d: Missed Packets = %lld\n", unit,
+ (long long)adapter->stats.mpc);
+ printf("em%d: Receive No Buffers = %lld\n", unit,
+ (long long)adapter->stats.rnbc);
+ printf("em%d: Receive length errors = %lld\n", unit,
+ (long long)adapter->stats.rlec);
+ printf("em%d: Receive errors = %lld\n", unit,
+ (long long)adapter->stats.rxerrc);
+ printf("em%d: Crc errors = %lld\n", unit,
+ (long long)adapter->stats.crcerrs);
+ printf("em%d: Alignment errors = %lld\n", unit,
+ (long long)adapter->stats.algnerrc);
+ printf("em%d: Carrier extension errors = %lld\n", unit,
+ (long long)adapter->stats.cexterr);
+
+ printf("em%d: XON Rcvd = %lld\n", unit,
+ (long long)adapter->stats.xonrxc);
+ printf("em%d: XON Xmtd = %lld\n", unit,
+ (long long)adapter->stats.xontxc);
+ printf("em%d: XOFF Rcvd = %lld\n", unit,
+ (long long)adapter->stats.xoffrxc);
+ printf("em%d: XOFF Xmtd = %lld\n", unit,
+ (long long)adapter->stats.xofftxc);
+
+ printf("em%d: Good Packets Rcvd = %lld\n", unit,
+ (long long)adapter->stats.gprc);
+ printf("em%d: Good Packets Xmtd = %lld\n", unit,
+ (long long)adapter->stats.gptc);
+
+ return;
+}
+
+#ifndef __rtems__
+static int
+em_sysctl_debug_info(SYSCTL_HANDLER_ARGS)
+{
+ int error;
+ int result;
+ struct adapter *adapter;
+
+ result = -1;
+ error = sysctl_handle_int(oidp, &result, 0, req);
+
+ if (error || !req->newptr)
+ return (error);
+
+ if (result == 1) {
+ adapter = (struct adapter *)arg1;
+ em_print_debug_info(adapter);
+ }
+
+ return error;
+}
+
+static int
+em_sysctl_stats(SYSCTL_HANDLER_ARGS)
+{
+ int error;
+ int result;
+ struct adapter *adapter;
+
+ result = -1;
+ error = sysctl_handle_int(oidp, &result, 0, req);
+
+ if (error || !req->newptr)
+ return (error);
+
+ if (result == 1) {
+ adapter = (struct adapter *)arg1;
+ em_print_hw_stats(adapter);
+ }
+
+ return error;
+}
+
+static int
+em_sysctl_int_delay(SYSCTL_HANDLER_ARGS)
+{
+ struct em_int_delay_info *info;
+ struct adapter *adapter;
+ u_int32_t regval;
+ int error;
+ int usecs;
+ int ticks;
+ int s;
+
+ info = (struct em_int_delay_info *)arg1;
+ adapter = info->adapter;
+ usecs = info->value;
+ error = sysctl_handle_int(oidp, &usecs, 0, req);
+ if (error != 0 || req->newptr == NULL)
+ return error;
+ if (usecs < 0 || usecs > E1000_TICKS_TO_USECS(65535))
+ return EINVAL;
+ info->value = usecs;
+ ticks = E1000_USECS_TO_TICKS(usecs);
+
+ s = splimp();
+ regval = E1000_READ_OFFSET(&adapter->hw, info->offset);
+ regval = (regval & ~0xffff) | (ticks & 0xffff);
+ /* Handle a few special cases. */
+ switch (info->offset) {
+ case E1000_RDTR:
+ case E1000_82542_RDTR:
+ regval |= E1000_RDT_FPDB;
+ break;
+ case E1000_TIDV:
+ case E1000_82542_TIDV:
+ if (ticks == 0) {
+ adapter->txd_cmd &= ~E1000_TXD_CMD_IDE;
+ /* Don't write 0 into the TIDV register. */
+ regval++;
+ } else
+ adapter->txd_cmd |= E1000_TXD_CMD_IDE;
+ break;
+ }
+ E1000_WRITE_OFFSET(&adapter->hw, info->offset, regval);
+ splx(s);
+ return 0;
+}
+
+static void
+em_add_int_delay_sysctl(struct adapter *adapter, const char *name,
+ const char *description, struct em_int_delay_info *info,
+ int offset, int value)
+{
+ info->adapter = adapter;
+ info->offset = offset;
+ info->value = value;
+ SYSCTL_ADD_PROC(device_get_sysctl_ctx(adapter->dev),
+ SYSCTL_CHILDREN(device_get_sysctl_tree(adapter->dev)),
+ OID_AUTO, name, CTLTYPE_INT|CTLFLAG_RW,
+ info, 0, em_sysctl_int_delay, "I", description);
+}
+#endif
+
+#ifdef __rtems__
+/* Initialize bare minimals so we can check the phy link status */
+int
+em_hw_early_init(device_t dev)
+{
+struct adapter *adapter = device_get_softc(dev);
+ adapter->dev = dev;
+ adapter->osdep.dev = dev;
+ em_identify_hardware(adapter);
+ return em_allocate_pci_resources(adapter);
+}
+#endif
diff --git a/c/src/lib/libbsp/powerpc/beatnik/network/if_em/if_em.h b/c/src/lib/libbsp/powerpc/beatnik/network/if_em/if_em.h
new file mode 100644
index 0000000000..560c682581
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/beatnik/network/if_em/if_em.h
@@ -0,0 +1,493 @@
+/**************************************************************************
+
+Copyright (c) 2001-2005, Intel Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+
+/*$FreeBSD: /repoman/r/ncvs/src/sys/dev/em/if_em.h,v 1.31 2005/05/26 23:32:02 tackerman Exp $*/
+
+#ifndef _EM_H_DEFINED_
+#define _EM_H_DEFINED_
+
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/mbuf.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <sys/malloc.h>
+#include <sys/kernel.h>
+#ifndef __rtems__
+#include <sys/module.h>
+#endif
+#include <sys/sockio.h>
+#include <sys/sysctl.h>
+
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <net/ethernet.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+#ifndef __rtems__
+
+#include <net/bpf.h>
+#include <net/if_types.h>
+#include <net/if_vlan_var.h>
+#else
+#include <net/if_types.h>
+#endif
+
+#include <netinet/in_systm.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <netinet/tcp.h>
+#include <netinet/udp.h>
+
+#ifndef __rtems__
+#include <sys/bus.h>
+#include <machine/bus.h>
+#include <sys/rman.h>
+#include <machine/resource.h>
+#include <vm/vm.h>
+#include <vm/pmap.h>
+#include <machine/clock.h>
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcireg.h>
+#else
+#include <netinet/if_ether.h>
+#include <bsp/pci.h>
+#endif
+
+#ifndef __rtems__
+#include <sys/endian.h>
+#include <sys/proc.h>
+#include "opt_bdg.h"
+
+
+#include <dev/em/if_em_hw.h>
+#else
+#include <if_em_hw.h>
+#endif
+
+/* Tunables */
+
+/*
+ * EM_MAX_TXD: Maximum number of Transmit Descriptors
+ * Valid Range: 80-256 for 82542 and 82543-based adapters
+ * 80-4096 for others
+ * Default Value: 256
+ * This value is the number of transmit descriptors allocated by the driver.
+ * Increasing this value allows the driver to queue more transmits. Each
+ * descriptor is 16 bytes.
+ */
+#define EM_MAX_TXD 256
+
+/*
+ * EM_MAX_RXD - Maximum number of receive Descriptors
+ * Valid Range: 80-256 for 82542 and 82543-based adapters
+ * 80-4096 for others
+ * Default Value: 256
+ * This value is the number of receive descriptors allocated by the driver.
+ * Increasing this value allows the driver to buffer more incoming packets.
+ * Each descriptor is 16 bytes. A receive buffer is also allocated for each
+ * descriptor. The maximum MTU size is 16110.
+ *
+ */
+#define EM_MAX_RXD 80
+
+/*
+ * EM_TIDV - Transmit Interrupt Delay Value
+ * Valid Range: 0-65535 (0=off)
+ * Default Value: 64
+ * This value delays the generation of transmit interrupts in units of
+ * 1.024 microseconds. Transmit interrupt reduction can improve CPU
+ * efficiency if properly tuned for specific network traffic. If the
+ * system is reporting dropped transmits, this value may be set too high
+ * causing the driver to run out of available transmit descriptors.
+ */
+#define EM_TIDV 64
+
+/*
+ * EM_TADV - Transmit Absolute Interrupt Delay Value (Not valid for 82542/82543/82544)
+ * Valid Range: 0-65535 (0=off)
+ * Default Value: 64
+ * This value, in units of 1.024 microseconds, limits the delay in which a
+ * transmit interrupt is generated. Useful only if EM_TIDV is non-zero,
+ * this value ensures that an interrupt is generated after the initial
+ * packet is sent on the wire within the set amount of time. Proper tuning,
+ * along with EM_TIDV, may improve traffic throughput in specific
+ * network conditions.
+ */
+#define EM_TADV 64
+
+/*
+ * EM_RDTR - Receive Interrupt Delay Timer (Packet Timer)
+ * Valid Range: 0-65535 (0=off)
+ * Default Value: 0
+ * This value delays the generation of receive interrupts in units of 1.024
+ * microseconds. Receive interrupt reduction can improve CPU efficiency if
+ * properly tuned for specific network traffic. Increasing this value adds
+ * extra latency to frame reception and can end up decreasing the throughput
+ * of TCP traffic. If the system is reporting dropped receives, this value
+ * may be set too high, causing the driver to run out of available receive
+ * descriptors.
+ *
+ * CAUTION: When setting EM_RDTR to a value other than 0, adapters
+ * may hang (stop transmitting) under certain network conditions.
+ * If this occurs a WATCHDOG message is logged in the system event log.
+ * In addition, the controller is automatically reset, restoring the
+ * network connection. To eliminate the potential for the hang
+ * ensure that EM_RDTR is set to 0.
+ */
+#define EM_RDTR 0
+
+/*
+ * Receive Interrupt Absolute Delay Timer (Not valid for 82542/82543/82544)
+ * Valid Range: 0-65535 (0=off)
+ * Default Value: 64
+ * This value, in units of 1.024 microseconds, limits the delay in which a
+ * receive interrupt is generated. Useful only if EM_RDTR is non-zero,
+ * this value ensures that an interrupt is generated after the initial
+ * packet is received within the set amount of time. Proper tuning,
+ * along with EM_RDTR, may improve traffic throughput in specific network
+ * conditions.
+ */
+#define EM_RADV 64
+
+
+/*
+ * This parameter controls the maximum no of times the driver will loop
+ * in the isr.
+ * Minimum Value = 1
+ */
+#define EM_MAX_INTR 3
+
+/*
+ * Inform the stack about transmit checksum offload capabilities.
+ */
+#define EM_CHECKSUM_FEATURES (CSUM_TCP | CSUM_UDP)
+
+/*
+ * This parameter controls the duration of transmit watchdog timer.
+ */
+#define EM_TX_TIMEOUT 5 /* set to 5 seconds */
+
+/*
+ * This parameter controls when the driver calls the routine to reclaim
+ * transmit descriptors.
+ */
+#ifndef __rtems__
+#define EM_TX_CLEANUP_THRESHOLD EM_MAX_TXD / 8
+#else
+#define EM_TX_CLEANUP_THRESHOLD (adapter->tx_cleanup_threshold)
+#endif
+
+/*
+ * This parameter controls whether or not autonegotation is enabled.
+ * 0 - Disable autonegotiation
+ * 1 - Enable autonegotiation
+ */
+#define DO_AUTO_NEG 1
+
+/*
+ * This parameter control whether or not the driver will wait for
+ * autonegotiation to complete.
+ * 1 - Wait for autonegotiation to complete
+ * 0 - Don't wait for autonegotiation to complete
+ */
+#define WAIT_FOR_AUTO_NEG_DEFAULT 0
+
+/*
+ * EM_MASTER_SLAVE is only defined to enable a workaround for a known compatibility issue
+ * with 82541/82547 devices and some switches. See the "Known Limitations" section of
+ * the README file for a complete description and a list of affected switches.
+ *
+ * 0 = Hardware default
+ * 1 = Master mode
+ * 2 = Slave mode
+ * 3 = Auto master/slave
+ */
+/* #define EM_MASTER_SLAVE 2 */
+
+/* Tunables -- End */
+
+#define AUTONEG_ADV_DEFAULT (ADVERTISE_10_HALF | ADVERTISE_10_FULL | \
+ ADVERTISE_100_HALF | ADVERTISE_100_FULL | \
+ ADVERTISE_1000_FULL)
+
+#define EM_VENDOR_ID 0x8086
+#define EM_MMBA 0x0010 /* Mem base address */
+#define EM_ROUNDUP(size, unit) (((size) + (unit) - 1) & ~((unit) - 1))
+
+#define EM_JUMBO_PBA 0x00000028
+#define EM_DEFAULT_PBA 0x00000030
+#define EM_SMARTSPEED_DOWNSHIFT 3
+#define EM_SMARTSPEED_MAX 15
+
+
+#define MAX_NUM_MULTICAST_ADDRESSES 128
+#define PCI_ANY_ID (~0U)
+#define ETHER_ALIGN 2
+
+/* Defines for printing debug information */
+#define DEBUG_INIT 0
+#define DEBUG_IOCTL 0
+#define DEBUG_HW 0
+
+#define INIT_DEBUGOUT(S) if (DEBUG_INIT) printf(S "\n")
+#define INIT_DEBUGOUT1(S, A) if (DEBUG_INIT) printf(S "\n", A)
+#define INIT_DEBUGOUT2(S, A, B) if (DEBUG_INIT) printf(S "\n", A, B)
+#define IOCTL_DEBUGOUT(S) if (DEBUG_IOCTL) printf(S "\n")
+#define IOCTL_DEBUGOUT1(S, A) if (DEBUG_IOCTL) printf(S "\n", A)
+#define IOCTL_DEBUGOUT2(S, A, B) if (DEBUG_IOCTL) printf(S "\n", A, B)
+#define HW_DEBUGOUT(S) if (DEBUG_HW) printf(S "\n")
+#define HW_DEBUGOUT1(S, A) if (DEBUG_HW) printf(S "\n", A)
+#define HW_DEBUGOUT2(S, A, B) if (DEBUG_HW) printf(S "\n", A, B)
+
+
+/* Supported RX Buffer Sizes */
+#define EM_RXBUFFER_2048 2048
+#define EM_RXBUFFER_4096 4096
+#define EM_RXBUFFER_8192 8192
+#define EM_RXBUFFER_16384 16384
+
+#define EM_MAX_SCATTER 64
+
+/* ******************************************************************************
+ * vendor_info_array
+ *
+ * This array contains the list of Subvendor/Subdevice IDs on which the driver
+ * should load.
+ *
+ * ******************************************************************************/
+typedef struct _em_vendor_info_t {
+ unsigned int vendor_id;
+ unsigned int device_id;
+ unsigned int subvendor_id;
+ unsigned int subdevice_id;
+ unsigned int index;
+} em_vendor_info_t;
+
+
+struct em_buffer {
+ struct mbuf *m_head;
+#ifndef __rtems__
+ bus_dmamap_t map; /* bus_dma map for packet */
+#endif
+};
+
+/*
+ * Bus dma allocation structure used by
+ * em_dma_malloc and em_dma_free.
+ */
+struct em_dma_alloc {
+ bus_addr_t dma_paddr; /* 64bit in descriptors */
+#ifndef __rtems__
+ caddr_t dma_vaddr;
+ bus_dma_tag_t dma_tag;
+ bus_dmamap_t dma_map;
+ bus_dma_segment_t dma_seg;
+ bus_size_t dma_size;
+ int dma_nseg;
+#else
+ caddr_t dma_vaddr;
+ caddr_t malloc_base;
+#endif
+};
+
+typedef enum _XSUM_CONTEXT_T {
+ OFFLOAD_NONE,
+ OFFLOAD_TCP_IP,
+ OFFLOAD_UDP_IP
+} XSUM_CONTEXT_T;
+
+struct adapter;
+struct em_int_delay_info {
+ struct adapter *adapter; /* Back-pointer to the adapter struct */
+ int offset; /* Register offset to read/write */
+ int value; /* Current value in usecs */
+};
+
+/* For 82544 PCIX Workaround */
+typedef struct _ADDRESS_LENGTH_PAIR
+{
+ u_int64_t address;
+ u_int32_t length;
+} ADDRESS_LENGTH_PAIR, *PADDRESS_LENGTH_PAIR;
+
+typedef struct _DESCRIPTOR_PAIR
+{
+ ADDRESS_LENGTH_PAIR descriptor[4];
+ u_int32_t elements;
+} DESC_ARRAY, *PDESC_ARRAY;
+
+/* Our adapter structure */
+struct adapter {
+ struct arpcom interface_data;
+ struct adapter *next;
+ struct adapter *prev;
+ struct em_hw hw;
+
+ /* FreeBSD operating-system-specific structures */
+ struct em_osdep osdep;
+#ifndef __rtems__
+ struct device *dev;
+ struct resource *res_memory;
+ struct resource *res_ioport;
+ struct resource *res_interrupt;
+ void *int_handler_tag;
+ struct ifmedia media;
+ struct callout timer;
+ struct callout tx_fifo_timer;
+ int io_rid;
+ struct ifmedia media;
+#endif
+ u_int8_t unit;
+#ifndef __rtems__
+ struct mtx mtx;
+ int em_insert_vlan_header;
+#else
+ device_t dev;
+ unsigned char irq_no;
+ unsigned char b,d,f;
+ rtems_id tid;
+#endif
+
+ /* Info about the board itself */
+#ifndef __rtems__
+ u_int32_t part_num;
+#else
+ uint32_t part_num;
+#endif
+ u_int8_t link_active;
+ u_int16_t link_speed;
+ u_int16_t link_duplex;
+ u_int32_t smartspeed;
+ struct em_int_delay_info tx_int_delay;
+ struct em_int_delay_info tx_abs_int_delay;
+ struct em_int_delay_info rx_int_delay;
+ struct em_int_delay_info rx_abs_int_delay;
+
+ XSUM_CONTEXT_T active_checksum_context;
+
+ /*
+ * Transmit definitions
+ *
+ * We have an array of num_tx_desc descriptors (handled
+ * by the controller) paired with an array of tx_buffers
+ * (at tx_buffer_area).
+ * The index of the next available descriptor is next_avail_tx_desc.
+ * The number of remaining tx_desc is num_tx_desc_avail.
+ */
+ struct em_dma_alloc txdma; /* bus_dma glue for tx desc */
+ struct em_tx_desc *tx_desc_base;
+ u_int32_t next_avail_tx_desc;
+ u_int32_t oldest_used_tx_desc;
+ volatile u_int16_t num_tx_desc_avail;
+ u_int16_t num_tx_desc;
+ u_int32_t txd_cmd;
+ struct em_buffer *tx_buffer_area;
+#ifndef __rtems__
+ bus_dma_tag_t txtag; /* dma tag for tx */
+#endif
+#ifdef __rtems__
+ u_int16_t tx_cleanup_threshold;
+#endif
+
+ /*
+ * Receive definitions
+ *
+ * we have an array of num_rx_desc rx_desc (handled by the
+ * controller), and paired with an array of rx_buffers
+ * (at rx_buffer_area).
+ * The next pair to check on receive is at offset next_rx_desc_to_check
+ */
+ struct em_dma_alloc rxdma; /* bus_dma glue for rx desc */
+ struct em_rx_desc *rx_desc_base;
+ u_int32_t next_rx_desc_to_check;
+ u_int16_t num_rx_desc;
+ u_int32_t rx_buffer_len;
+ struct em_buffer *rx_buffer_area;
+#ifndef __rtems__
+ bus_dma_tag_t rxtag;
+#endif
+
+ /* Jumbo frame */
+ struct mbuf *fmp;
+ struct mbuf *lmp;
+
+ /* Misc stats maintained by the driver */
+ unsigned long dropped_pkts;
+ unsigned long mbuf_alloc_failed;
+ unsigned long mbuf_cluster_failed;
+ unsigned long no_tx_desc_avail1;
+ unsigned long no_tx_desc_avail2;
+ unsigned long no_tx_map_avail;
+ unsigned long no_tx_dma_setup;
+
+ /* Used in for 82547 10Mb Half workaround */
+ #define EM_PBA_BYTES_SHIFT 0xA
+ #define EM_TX_HEAD_ADDR_SHIFT 7
+ #define EM_PBA_TX_MASK 0xFFFF0000
+ #define EM_FIFO_HDR 0x10
+
+ #define EM_82547_PKT_THRESH 0x3e0
+
+ u_int32_t tx_fifo_size;
+ u_int32_t tx_fifo_head;
+ u_int32_t tx_fifo_head_addr;
+ u_int64_t tx_fifo_reset_cnt;
+ u_int64_t tx_fifo_wrk_cnt;
+ u_int32_t tx_head_addr;
+
+ /* For 82544 PCIX Workaround */
+ boolean_t pcix_82544;
+ boolean_t in_detach;
+
+ struct em_hw_stats stats;
+};
+
+#define EM_LOCK_INIT(_sc, _name) \
+ mtx_init(&(_sc)->mtx, _name, MTX_NETWORK_LOCK, MTX_DEF)
+#define EM_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->mtx)
+#define EM_LOCK(_sc) mtx_lock(&(_sc)->mtx)
+#define EM_UNLOCK(_sc) mtx_unlock(&(_sc)->mtx)
+#define EM_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->mtx, MA_OWNED)
+
+#ifdef __rtems__
+/* Initialize bare minimals so we can check the phy link status;
+ * 'rtems_em_pci_setup()' must have been run on the device already!
+ */
+int
+em_hw_early_init(device_t dev);
+#endif
+
+
+#endif /* _EM_H_DEFINED_ */
diff --git a/c/src/lib/libbsp/powerpc/beatnik/network/if_em/if_em_hw.c b/c/src/lib/libbsp/powerpc/beatnik/network/if_em/if_em_hw.c
new file mode 100644
index 0000000000..56f7224055
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/beatnik/network/if_em/if_em_hw.c
@@ -0,0 +1,6635 @@
+/*******************************************************************************
+
+ Copyright (c) 2001-2005, Intel Corporation
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+
+*******************************************************************************/
+
+/* if_em_hw.c
+ * Shared functions for accessing and configuring the MAC
+ */
+
+#include <sys/cdefs.h>
+#ifdef __rtems__
+#include <rtemscompat.h>
+#include <if_em_hw.h>
+#else
+__FBSDID("$FreeBSD: /repoman/r/ncvs/src/sys/dev/em/if_em_hw.c,v 1.16 2005/05/26 23:32:02 tackerman Exp $");
+
+#include <dev/em/if_em_hw.h>
+#endif
+
+static int32_t em_set_phy_type(struct em_hw *hw);
+static void em_phy_init_script(struct em_hw *hw);
+static int32_t em_setup_copper_link(struct em_hw *hw);
+static int32_t em_setup_fiber_serdes_link(struct em_hw *hw);
+static int32_t em_adjust_serdes_amplitude(struct em_hw *hw);
+static int32_t em_phy_force_speed_duplex(struct em_hw *hw);
+static int32_t em_config_mac_to_phy(struct em_hw *hw);
+static void em_raise_mdi_clk(struct em_hw *hw, uint32_t *ctrl);
+static void em_lower_mdi_clk(struct em_hw *hw, uint32_t *ctrl);
+static void em_shift_out_mdi_bits(struct em_hw *hw, uint32_t data,
+ uint16_t count);
+static uint16_t em_shift_in_mdi_bits(struct em_hw *hw);
+static int32_t em_phy_reset_dsp(struct em_hw *hw);
+static int32_t em_write_eeprom_spi(struct em_hw *hw, uint16_t offset,
+ uint16_t words, uint16_t *data);
+static int32_t em_write_eeprom_microwire(struct em_hw *hw,
+ uint16_t offset, uint16_t words,
+ uint16_t *data);
+static int32_t em_spi_eeprom_ready(struct em_hw *hw);
+static void em_raise_ee_clk(struct em_hw *hw, uint32_t *eecd);
+static void em_lower_ee_clk(struct em_hw *hw, uint32_t *eecd);
+static void em_shift_out_ee_bits(struct em_hw *hw, uint16_t data,
+ uint16_t count);
+static int32_t em_write_phy_reg_ex(struct em_hw *hw, uint32_t reg_addr,
+ uint16_t phy_data);
+static int32_t em_read_phy_reg_ex(struct em_hw *hw,uint32_t reg_addr,
+ uint16_t *phy_data);
+static uint16_t em_shift_in_ee_bits(struct em_hw *hw, uint16_t count);
+static int32_t em_acquire_eeprom(struct em_hw *hw);
+static void em_release_eeprom(struct em_hw *hw);
+static void em_standby_eeprom(struct em_hw *hw);
+static int32_t em_set_vco_speed(struct em_hw *hw);
+static int32_t em_polarity_reversal_workaround(struct em_hw *hw);
+static int32_t em_set_phy_mode(struct em_hw *hw);
+static int32_t em_host_if_read_cookie(struct em_hw *hw, uint8_t *buffer);
+static uint8_t em_calculate_mng_checksum(char *buffer, uint32_t length);
+
+/* IGP cable length table */
+static const
+uint16_t em_igp_cable_length_table[IGP01E1000_AGC_LENGTH_TABLE_SIZE] =
+ { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 10, 10, 10, 10, 10, 10, 10, 20, 20, 20, 20, 20, 25, 25, 25,
+ 25, 25, 25, 25, 30, 30, 30, 30, 40, 40, 40, 40, 40, 40, 40, 40,
+ 40, 50, 50, 50, 50, 50, 50, 50, 60, 60, 60, 60, 60, 60, 60, 60,
+ 60, 70, 70, 70, 70, 70, 70, 80, 80, 80, 80, 80, 80, 90, 90, 90,
+ 90, 90, 90, 90, 90, 90, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100,
+ 100, 100, 100, 100, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110,
+ 110, 110, 110, 110, 110, 110, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120};
+
+static const
+uint16_t em_igp_2_cable_length_table[IGP02E1000_AGC_LENGTH_TABLE_SIZE] =
+ { 8, 13, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41, 43,
+ 22, 24, 27, 30, 32, 35, 37, 40, 42, 44, 47, 49, 51, 54, 56, 58,
+ 32, 35, 38, 41, 44, 47, 50, 53, 55, 58, 61, 63, 66, 69, 71, 74,
+ 43, 47, 51, 54, 58, 61, 64, 67, 71, 74, 77, 80, 82, 85, 88, 90,
+ 57, 62, 66, 70, 74, 77, 81, 85, 88, 91, 94, 97, 100, 103, 106, 108,
+ 73, 78, 82, 87, 91, 95, 98, 102, 105, 109, 112, 114, 117, 119, 122, 124,
+ 91, 96, 101, 105, 109, 113, 116, 119, 122, 125, 127, 128, 128, 128, 128, 128,
+ 108, 113, 117, 121, 124, 127, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128};
+
+
+/******************************************************************************
+ * Set the phy type member in the hw struct.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+int32_t
+em_set_phy_type(struct em_hw *hw)
+{
+ DEBUGFUNC("em_set_phy_type");
+
+ if(hw->mac_type == em_undefined)
+ return -E1000_ERR_PHY_TYPE;
+
+ switch(hw->phy_id) {
+ case M88E1000_E_PHY_ID:
+ case M88E1000_I_PHY_ID:
+ case M88E1011_I_PHY_ID:
+ case M88E1111_I_PHY_ID:
+ hw->phy_type = em_phy_m88;
+ break;
+ case IGP01E1000_I_PHY_ID:
+ if(hw->mac_type == em_82541 ||
+ hw->mac_type == em_82541_rev_2 ||
+ hw->mac_type == em_82547 ||
+ hw->mac_type == em_82547_rev_2) {
+ hw->phy_type = em_phy_igp;
+ break;
+ }
+ /* Fall Through */
+ default:
+ /* Should never have loaded on this device */
+ hw->phy_type = em_phy_undefined;
+ return -E1000_ERR_PHY_TYPE;
+ }
+
+ return E1000_SUCCESS;
+}
+
+/******************************************************************************
+ * IGP phy init script - initializes the GbE PHY
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+static void
+em_phy_init_script(struct em_hw *hw)
+{
+ uint32_t ret_val;
+ uint16_t phy_saved_data;
+
+ DEBUGFUNC("em_phy_init_script");
+
+ if(hw->phy_init_script) {
+ msec_delay(20);
+
+ /* Save off the current value of register 0x2F5B to be restored at
+ * the end of this routine. */
+ ret_val = em_read_phy_reg(hw, 0x2F5B, &phy_saved_data);
+
+ /* Disabled the PHY transmitter */
+ em_write_phy_reg(hw, 0x2F5B, 0x0003);
+
+ msec_delay(20);
+
+ em_write_phy_reg(hw,0x0000,0x0140);
+
+ msec_delay(5);
+
+ switch(hw->mac_type) {
+ case em_82541:
+ case em_82547:
+ em_write_phy_reg(hw, 0x1F95, 0x0001);
+
+ em_write_phy_reg(hw, 0x1F71, 0xBD21);
+
+ em_write_phy_reg(hw, 0x1F79, 0x0018);
+
+ em_write_phy_reg(hw, 0x1F30, 0x1600);
+
+ em_write_phy_reg(hw, 0x1F31, 0x0014);
+
+ em_write_phy_reg(hw, 0x1F32, 0x161C);
+
+ em_write_phy_reg(hw, 0x1F94, 0x0003);
+
+ em_write_phy_reg(hw, 0x1F96, 0x003F);
+
+ em_write_phy_reg(hw, 0x2010, 0x0008);
+ break;
+
+ case em_82541_rev_2:
+ case em_82547_rev_2:
+ em_write_phy_reg(hw, 0x1F73, 0x0099);
+ break;
+ default:
+ break;
+ }
+
+ em_write_phy_reg(hw, 0x0000, 0x3300);
+
+ msec_delay(20);
+
+ /* Now enable the transmitter */
+ em_write_phy_reg(hw, 0x2F5B, phy_saved_data);
+
+ if(hw->mac_type == em_82547) {
+ uint16_t fused, fine, coarse;
+
+ /* Move to analog registers page */
+ em_read_phy_reg(hw, IGP01E1000_ANALOG_SPARE_FUSE_STATUS, &fused);
+
+ if(!(fused & IGP01E1000_ANALOG_SPARE_FUSE_ENABLED)) {
+ em_read_phy_reg(hw, IGP01E1000_ANALOG_FUSE_STATUS, &fused);
+
+ fine = fused & IGP01E1000_ANALOG_FUSE_FINE_MASK;
+ coarse = fused & IGP01E1000_ANALOG_FUSE_COARSE_MASK;
+
+ if(coarse > IGP01E1000_ANALOG_FUSE_COARSE_THRESH) {
+ coarse -= IGP01E1000_ANALOG_FUSE_COARSE_10;
+ fine -= IGP01E1000_ANALOG_FUSE_FINE_1;
+ } else if(coarse == IGP01E1000_ANALOG_FUSE_COARSE_THRESH)
+ fine -= IGP01E1000_ANALOG_FUSE_FINE_10;
+
+ fused = (fused & IGP01E1000_ANALOG_FUSE_POLY_MASK) |
+ (fine & IGP01E1000_ANALOG_FUSE_FINE_MASK) |
+ (coarse & IGP01E1000_ANALOG_FUSE_COARSE_MASK);
+
+ em_write_phy_reg(hw, IGP01E1000_ANALOG_FUSE_CONTROL, fused);
+ em_write_phy_reg(hw, IGP01E1000_ANALOG_FUSE_BYPASS,
+ IGP01E1000_ANALOG_FUSE_ENABLE_SW_CONTROL);
+ }
+ }
+ }
+}
+
+/******************************************************************************
+ * Set the mac type member in the hw struct.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+int32_t
+em_set_mac_type(struct em_hw *hw)
+{
+ DEBUGFUNC("em_set_mac_type");
+
+ switch (hw->device_id) {
+ case E1000_DEV_ID_82542:
+ switch (hw->revision_id) {
+ case E1000_82542_2_0_REV_ID:
+ hw->mac_type = em_82542_rev2_0;
+ break;
+ case E1000_82542_2_1_REV_ID:
+ hw->mac_type = em_82542_rev2_1;
+ break;
+ default:
+ /* Invalid 82542 revision ID */
+ return -E1000_ERR_MAC_TYPE;
+ }
+ break;
+ case E1000_DEV_ID_82543GC_FIBER:
+ case E1000_DEV_ID_82543GC_COPPER:
+ hw->mac_type = em_82543;
+ break;
+ case E1000_DEV_ID_82544EI_COPPER:
+ case E1000_DEV_ID_82544EI_FIBER:
+ case E1000_DEV_ID_82544GC_COPPER:
+ case E1000_DEV_ID_82544GC_LOM:
+ hw->mac_type = em_82544;
+ break;
+ case E1000_DEV_ID_82540EM:
+ case E1000_DEV_ID_82540EM_LOM:
+ case E1000_DEV_ID_82540EP:
+ case E1000_DEV_ID_82540EP_LOM:
+ case E1000_DEV_ID_82540EP_LP:
+ hw->mac_type = em_82540;
+ break;
+ case E1000_DEV_ID_82545EM_COPPER:
+ case E1000_DEV_ID_82545EM_FIBER:
+ hw->mac_type = em_82545;
+ break;
+ case E1000_DEV_ID_82545GM_COPPER:
+ case E1000_DEV_ID_82545GM_FIBER:
+ case E1000_DEV_ID_82545GM_SERDES:
+ hw->mac_type = em_82545_rev_3;
+ break;
+ case E1000_DEV_ID_82546EB_COPPER:
+ case E1000_DEV_ID_82546EB_FIBER:
+ case E1000_DEV_ID_82546EB_QUAD_COPPER:
+ hw->mac_type = em_82546;
+ break;
+ case E1000_DEV_ID_82546GB_COPPER:
+ case E1000_DEV_ID_82546GB_FIBER:
+ case E1000_DEV_ID_82546GB_SERDES:
+ case E1000_DEV_ID_82546GB_PCIE:
+ case E1000_DEV_ID_82546GB_QUAD_COPPER:
+ hw->mac_type = em_82546_rev_3;
+ break;
+ case E1000_DEV_ID_82541EI:
+ case E1000_DEV_ID_82541ER_LOM:
+ case E1000_DEV_ID_82541EI_MOBILE:
+ hw->mac_type = em_82541;
+ break;
+ case E1000_DEV_ID_82541ER:
+ case E1000_DEV_ID_82541GI:
+ case E1000_DEV_ID_82541GI_LF:
+ case E1000_DEV_ID_82541GI_MOBILE:
+ hw->mac_type = em_82541_rev_2;
+ break;
+ case E1000_DEV_ID_82547EI:
+ case E1000_DEV_ID_82547EI_MOBILE:
+ hw->mac_type = em_82547;
+ break;
+ case E1000_DEV_ID_82547GI:
+ hw->mac_type = em_82547_rev_2;
+ break;
+ case E1000_DEV_ID_82573E:
+ case E1000_DEV_ID_82573E_IAMT:
+ hw->mac_type = em_82573;
+ break;
+ default:
+ /* Should never have loaded on this device */
+ return -E1000_ERR_MAC_TYPE;
+ }
+
+ switch(hw->mac_type) {
+ case em_82573:
+ hw->eeprom_semaphore_present = TRUE;
+ /* fall through */
+ case em_82541:
+ case em_82547:
+ case em_82541_rev_2:
+ case em_82547_rev_2:
+ hw->asf_firmware_present = TRUE;
+ break;
+ default:
+ break;
+ }
+
+ return E1000_SUCCESS;
+}
+
+/*****************************************************************************
+ * Set media type and TBI compatibility.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * **************************************************************************/
+void
+em_set_media_type(struct em_hw *hw)
+{
+ uint32_t status;
+
+ DEBUGFUNC("em_set_media_type");
+
+ if(hw->mac_type != em_82543) {
+ /* tbi_compatibility is only valid on 82543 */
+ hw->tbi_compatibility_en = FALSE;
+ }
+
+ switch (hw->device_id) {
+ case E1000_DEV_ID_82545GM_SERDES:
+ case E1000_DEV_ID_82546GB_SERDES:
+ hw->media_type = em_media_type_internal_serdes;
+ break;
+ default:
+ if(hw->mac_type >= em_82543) {
+ status = E1000_READ_REG(hw, STATUS);
+ if(status & E1000_STATUS_TBIMODE) {
+ hw->media_type = em_media_type_fiber;
+ /* tbi_compatibility not valid on fiber */
+ hw->tbi_compatibility_en = FALSE;
+ } else {
+ hw->media_type = em_media_type_copper;
+ }
+ } else {
+ /* This is an 82542 (fiber only) */
+ hw->media_type = em_media_type_fiber;
+ }
+ }
+}
+
+/******************************************************************************
+ * Reset the transmit and receive units; mask and clear all interrupts.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+int32_t
+em_reset_hw(struct em_hw *hw)
+{
+ uint32_t ctrl;
+ uint32_t ctrl_ext;
+ uint32_t icr;
+ uint32_t manc;
+ uint32_t led_ctrl;
+ uint32_t timeout;
+ uint32_t extcnf_ctrl;
+ int32_t ret_val;
+
+ DEBUGFUNC("em_reset_hw");
+
+ /* For 82542 (rev 2.0), disable MWI before issuing a device reset */
+ if(hw->mac_type == em_82542_rev2_0) {
+ DEBUGOUT("Disabling MWI on 82542 rev 2.0\n");
+ em_pci_clear_mwi(hw);
+ }
+
+ if(hw->bus_type == em_bus_type_pci_express) {
+ /* Prevent the PCI-E bus from sticking if there is no TLP connection
+ * on the last TLP read/write transaction when MAC is reset.
+ */
+ if(em_disable_pciex_master(hw) != E1000_SUCCESS) {
+ DEBUGOUT("PCI-E Master disable polling has failed.\n");
+ }
+ }
+
+ /* Clear interrupt mask to stop board from generating interrupts */
+ DEBUGOUT("Masking off all interrupts\n");
+ E1000_WRITE_REG(hw, IMC, 0xffffffff);
+
+ /* Disable the Transmit and Receive units. Then delay to allow
+ * any pending transactions to complete before we hit the MAC with
+ * the global reset.
+ */
+ E1000_WRITE_REG(hw, RCTL, 0);
+ E1000_WRITE_REG(hw, TCTL, E1000_TCTL_PSP);
+ E1000_WRITE_FLUSH(hw);
+
+ /* The tbi_compatibility_on Flag must be cleared when Rctl is cleared. */
+ hw->tbi_compatibility_on = FALSE;
+
+ /* Delay to allow any outstanding PCI transactions to complete before
+ * resetting the device
+ */
+ msec_delay(10);
+
+ ctrl = E1000_READ_REG(hw, CTRL);
+
+ /* Must reset the PHY before resetting the MAC */
+ if((hw->mac_type == em_82541) || (hw->mac_type == em_82547)) {
+ E1000_WRITE_REG(hw, CTRL, (ctrl | E1000_CTRL_PHY_RST));
+ msec_delay(5);
+ }
+
+ /* Must acquire the MDIO ownership before MAC reset.
+ * Ownership defaults to firmware after a reset. */
+ if(hw->mac_type == em_82573) {
+ timeout = 10;
+
+ extcnf_ctrl = E1000_READ_REG(hw, EXTCNF_CTRL);
+ extcnf_ctrl |= E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP;
+
+ do {
+ E1000_WRITE_REG(hw, EXTCNF_CTRL, extcnf_ctrl);
+ extcnf_ctrl = E1000_READ_REG(hw, EXTCNF_CTRL);
+
+ if(extcnf_ctrl & E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP)
+ break;
+ else
+ extcnf_ctrl |= E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP;
+
+ msec_delay(2);
+ timeout--;
+ } while(timeout);
+ }
+
+ /* Issue a global reset to the MAC. This will reset the chip's
+ * transmit, receive, DMA, and link units. It will not effect
+ * the current PCI configuration. The global reset bit is self-
+ * clearing, and should clear within a microsecond.
+ */
+ DEBUGOUT("Issuing a global reset to MAC\n");
+
+ switch(hw->mac_type) {
+ case em_82544:
+ case em_82540:
+ case em_82545:
+#ifndef __arm__
+ case em_82546:
+#endif
+ case em_82541:
+ case em_82541_rev_2:
+ /* These controllers can't ack the 64-bit write when issuing the
+ * reset, so use IO-mapping as a workaround to issue the reset */
+ E1000_WRITE_REG_IO(hw, CTRL, (ctrl | E1000_CTRL_RST));
+ break;
+ case em_82545_rev_3:
+ case em_82546_rev_3:
+ /* Reset is performed on a shadow of the control register */
+ E1000_WRITE_REG(hw, CTRL_DUP, (ctrl | E1000_CTRL_RST));
+ break;
+ default:
+ E1000_WRITE_REG(hw, CTRL, (ctrl | E1000_CTRL_RST));
+ break;
+ }
+
+ /* After MAC reset, force reload of EEPROM to restore power-on settings to
+ * device. Later controllers reload the EEPROM automatically, so just wait
+ * for reload to complete.
+ */
+ switch(hw->mac_type) {
+ case em_82542_rev2_0:
+ case em_82542_rev2_1:
+ case em_82543:
+ case em_82544:
+ /* Wait for reset to complete */
+ usec_delay(10);
+ ctrl_ext = E1000_READ_REG(hw, CTRL_EXT);
+ ctrl_ext |= E1000_CTRL_EXT_EE_RST;
+ E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext);
+ E1000_WRITE_FLUSH(hw);
+ /* Wait for EEPROM reload */
+ msec_delay(2);
+ break;
+ case em_82541:
+ case em_82541_rev_2:
+ case em_82547:
+ case em_82547_rev_2:
+ /* Wait for EEPROM reload */
+ msec_delay(20);
+ break;
+ case em_82573:
+ usec_delay(10);
+ ctrl_ext = E1000_READ_REG(hw, CTRL_EXT);
+ ctrl_ext |= E1000_CTRL_EXT_EE_RST;
+ E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext);
+ E1000_WRITE_FLUSH(hw);
+ /* fall through */
+ ret_val = em_get_auto_rd_done(hw);
+ if(ret_val)
+ /* We don't want to continue accessing MAC registers. */
+ return ret_val;
+ break;
+ default:
+ /* Wait for EEPROM reload (it happens automatically) */
+ msec_delay(5);
+ break;
+ }
+
+ /* Disable HW ARPs on ASF enabled adapters */
+ if(hw->mac_type >= em_82540 && hw->mac_type <= em_82547_rev_2) {
+ manc = E1000_READ_REG(hw, MANC);
+ manc &= ~(E1000_MANC_ARP_EN);
+ E1000_WRITE_REG(hw, MANC, manc);
+ }
+
+ if((hw->mac_type == em_82541) || (hw->mac_type == em_82547)) {
+ em_phy_init_script(hw);
+
+ /* Configure activity LED after PHY reset */
+ led_ctrl = E1000_READ_REG(hw, LEDCTL);
+ led_ctrl &= IGP_ACTIVITY_LED_MASK;
+ led_ctrl |= (IGP_ACTIVITY_LED_ENABLE | IGP_LED3_MODE);
+ E1000_WRITE_REG(hw, LEDCTL, led_ctrl);
+ }
+
+ /* Clear interrupt mask to stop board from generating interrupts */
+ DEBUGOUT("Masking off all interrupts\n");
+ E1000_WRITE_REG(hw, IMC, 0xffffffff);
+
+ /* Clear any pending interrupt events. */
+ icr = E1000_READ_REG(hw, ICR);
+
+ /* If MWI was previously enabled, reenable it. */
+ if(hw->mac_type == em_82542_rev2_0) {
+ if(hw->pci_cmd_word & CMD_MEM_WRT_INVALIDATE)
+ em_pci_set_mwi(hw);
+ }
+#ifdef __rtems__
+ msec_delay(100);
+#endif
+
+ return E1000_SUCCESS;
+}
+
+/******************************************************************************
+ * Performs basic configuration of the adapter.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *
+ * Assumes that the controller has previously been reset and is in a
+ * post-reset uninitialized state. Initializes the receive address registers,
+ * multicast table, and VLAN filter table. Calls routines to setup link
+ * configuration and flow control settings. Clears all on-chip counters. Leaves
+ * the transmit and receive units disabled and uninitialized.
+ *****************************************************************************/
+int32_t
+em_init_hw(struct em_hw *hw)
+{
+ uint32_t ctrl;
+ uint32_t i;
+ int32_t ret_val;
+ uint16_t pcix_cmd_word;
+ uint16_t pcix_stat_hi_word;
+ uint16_t cmd_mmrbc;
+ uint16_t stat_mmrbc;
+ uint32_t mta_size;
+
+ DEBUGFUNC("em_init_hw");
+
+ /* Initialize Identification LED */
+ ret_val = em_id_led_init(hw);
+ if(ret_val) {
+ DEBUGOUT("Error Initializing Identification LED\n");
+ return ret_val;
+ }
+
+ /* Set the media type and TBI compatibility */
+ em_set_media_type(hw);
+
+ /* Disabling VLAN filtering. */
+ DEBUGOUT("Initializing the IEEE VLAN\n");
+ if (hw->mac_type < em_82545_rev_3)
+ E1000_WRITE_REG(hw, VET, 0);
+ em_clear_vfta(hw);
+
+ /* For 82542 (rev 2.0), disable MWI and put the receiver into reset */
+ if(hw->mac_type == em_82542_rev2_0) {
+ DEBUGOUT("Disabling MWI on 82542 rev 2.0\n");
+ em_pci_clear_mwi(hw);
+ E1000_WRITE_REG(hw, RCTL, E1000_RCTL_RST);
+ E1000_WRITE_FLUSH(hw);
+ msec_delay(5);
+ }
+
+ /* Setup the receive address. This involves initializing all of the Receive
+ * Address Registers (RARs 0 - 15).
+ */
+ em_init_rx_addrs(hw);
+
+ /* For 82542 (rev 2.0), take the receiver out of reset and enable MWI */
+ if(hw->mac_type == em_82542_rev2_0) {
+ E1000_WRITE_REG(hw, RCTL, 0);
+ E1000_WRITE_FLUSH(hw);
+ msec_delay(1);
+ if(hw->pci_cmd_word & CMD_MEM_WRT_INVALIDATE)
+ em_pci_set_mwi(hw);
+ }
+
+ /* Zero out the Multicast HASH table */
+ DEBUGOUT("Zeroing the MTA\n");
+ mta_size = E1000_MC_TBL_SIZE;
+ for(i = 0; i < mta_size; i++)
+ E1000_WRITE_REG_ARRAY(hw, MTA, i, 0);
+
+ /* Set the PCI priority bit correctly in the CTRL register. This
+ * determines if the adapter gives priority to receives, or if it
+ * gives equal priority to transmits and receives. Valid only on
+ * 82542 and 82543 silicon.
+ */
+ if(hw->dma_fairness && hw->mac_type <= em_82543) {
+ ctrl = E1000_READ_REG(hw, CTRL);
+ E1000_WRITE_REG(hw, CTRL, ctrl | E1000_CTRL_PRIOR);
+ }
+
+ switch(hw->mac_type) {
+ case em_82545_rev_3:
+ case em_82546_rev_3:
+ break;
+ default:
+ /* Workaround for PCI-X problem when BIOS sets MMRBC incorrectly. */
+ if(hw->bus_type == em_bus_type_pcix) {
+ em_read_pci_cfg(hw, PCIX_COMMAND_REGISTER, &pcix_cmd_word);
+ em_read_pci_cfg(hw, PCIX_STATUS_REGISTER_HI,
+ &pcix_stat_hi_word);
+ cmd_mmrbc = (pcix_cmd_word & PCIX_COMMAND_MMRBC_MASK) >>
+ PCIX_COMMAND_MMRBC_SHIFT;
+ stat_mmrbc = (pcix_stat_hi_word & PCIX_STATUS_HI_MMRBC_MASK) >>
+ PCIX_STATUS_HI_MMRBC_SHIFT;
+ if(stat_mmrbc == PCIX_STATUS_HI_MMRBC_4K)
+ stat_mmrbc = PCIX_STATUS_HI_MMRBC_2K;
+ if(cmd_mmrbc > stat_mmrbc) {
+ pcix_cmd_word &= ~PCIX_COMMAND_MMRBC_MASK;
+ pcix_cmd_word |= stat_mmrbc << PCIX_COMMAND_MMRBC_SHIFT;
+ em_write_pci_cfg(hw, PCIX_COMMAND_REGISTER,
+ &pcix_cmd_word);
+ }
+ }
+ break;
+ }
+
+ /* Call a subroutine to configure the link and setup flow control. */
+ ret_val = em_setup_link(hw);
+
+ /* Set the transmit descriptor write-back policy */
+ if(hw->mac_type > em_82544) {
+ ctrl = E1000_READ_REG(hw, TXDCTL);
+ ctrl = (ctrl & ~E1000_TXDCTL_WTHRESH) | E1000_TXDCTL_FULL_TX_DESC_WB;
+ switch (hw->mac_type) {
+ default:
+ break;
+ case em_82573:
+ ctrl |= E1000_TXDCTL_COUNT_DESC;
+ break;
+ }
+ E1000_WRITE_REG(hw, TXDCTL, ctrl);
+ }
+
+ if (hw->mac_type == em_82573) {
+ em_enable_tx_pkt_filtering(hw);
+ }
+
+
+ /* Clear all of the statistics registers (clear on read). It is
+ * important that we do this after we have tried to establish link
+ * because the symbol error count will increment wildly if there
+ * is no link.
+ */
+ em_clear_hw_cntrs(hw);
+
+ return ret_val;
+}
+
+/******************************************************************************
+ * Adjust SERDES output amplitude based on EEPROM setting.
+ *
+ * hw - Struct containing variables accessed by shared code.
+ *****************************************************************************/
+static int32_t
+em_adjust_serdes_amplitude(struct em_hw *hw)
+{
+ uint16_t eeprom_data;
+ int32_t ret_val;
+
+ DEBUGFUNC("em_adjust_serdes_amplitude");
+
+ if(hw->media_type != em_media_type_internal_serdes)
+ return E1000_SUCCESS;
+
+ switch(hw->mac_type) {
+ case em_82545_rev_3:
+ case em_82546_rev_3:
+ break;
+ default:
+ return E1000_SUCCESS;
+ }
+
+ ret_val = em_read_eeprom(hw, EEPROM_SERDES_AMPLITUDE, 1, &eeprom_data);
+ if (ret_val) {
+ return ret_val;
+ }
+
+ if(eeprom_data != EEPROM_RESERVED_WORD) {
+ /* Adjust SERDES output amplitude only. */
+ eeprom_data &= EEPROM_SERDES_AMPLITUDE_MASK;
+ ret_val = em_write_phy_reg(hw, M88E1000_PHY_EXT_CTRL, eeprom_data);
+ if(ret_val)
+ return ret_val;
+ }
+
+ return E1000_SUCCESS;
+}
+
+/******************************************************************************
+ * Configures flow control and link settings.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *
+ * Determines which flow control settings to use. Calls the apropriate media-
+ * specific link configuration function. Configures the flow control settings.
+ * Assuming the adapter has a valid link partner, a valid link should be
+ * established. Assumes the hardware has previously been reset and the
+ * transmitter and receiver are not enabled.
+ *****************************************************************************/
+int32_t
+em_setup_link(struct em_hw *hw)
+{
+ uint32_t ctrl_ext;
+ int32_t ret_val;
+ uint16_t eeprom_data;
+
+ DEBUGFUNC("em_setup_link");
+
+ /* Read and store word 0x0F of the EEPROM. This word contains bits
+ * that determine the hardware's default PAUSE (flow control) mode,
+ * a bit that determines whether the HW defaults to enabling or
+ * disabling auto-negotiation, and the direction of the
+ * SW defined pins. If there is no SW over-ride of the flow
+ * control setting, then the variable hw->fc will
+ * be initialized based on a value in the EEPROM.
+ */
+ if(em_read_eeprom(hw, EEPROM_INIT_CONTROL2_REG, 1, &eeprom_data)) {
+ DEBUGOUT("EEPROM Read Error\n");
+ return -E1000_ERR_EEPROM;
+ }
+
+ if(hw->fc == em_fc_default) {
+ if((eeprom_data & EEPROM_WORD0F_PAUSE_MASK) == 0)
+ hw->fc = em_fc_none;
+ else if((eeprom_data & EEPROM_WORD0F_PAUSE_MASK) ==
+ EEPROM_WORD0F_ASM_DIR)
+ hw->fc = em_fc_tx_pause;
+ else
+ hw->fc = em_fc_full;
+ }
+
+ /* We want to save off the original Flow Control configuration just
+ * in case we get disconnected and then reconnected into a different
+ * hub or switch with different Flow Control capabilities.
+ */
+ if(hw->mac_type == em_82542_rev2_0)
+ hw->fc &= (~em_fc_tx_pause);
+
+ if((hw->mac_type < em_82543) && (hw->report_tx_early == 1))
+ hw->fc &= (~em_fc_rx_pause);
+
+ hw->original_fc = hw->fc;
+
+ DEBUGOUT1("After fix-ups FlowControl is now = %x\n", hw->fc);
+
+ /* Take the 4 bits from EEPROM word 0x0F that determine the initial
+ * polarity value for the SW controlled pins, and setup the
+ * Extended Device Control reg with that info.
+ * This is needed because one of the SW controlled pins is used for
+ * signal detection. So this should be done before em_setup_pcs_link()
+ * or em_phy_setup() is called.
+ */
+ if(hw->mac_type == em_82543) {
+ ctrl_ext = ((eeprom_data & EEPROM_WORD0F_SWPDIO_EXT) <<
+ SWDPIO__EXT_SHIFT);
+ E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext);
+ }
+
+ /* Call the necessary subroutine to configure the link. */
+ ret_val = (hw->media_type == em_media_type_copper) ?
+ em_setup_copper_link(hw) :
+ em_setup_fiber_serdes_link(hw);
+
+ /* Initialize the flow control address, type, and PAUSE timer
+ * registers to their default values. This is done even if flow
+ * control is disabled, because it does not hurt anything to
+ * initialize these registers.
+ */
+ DEBUGOUT("Initializing the Flow Control address, type and timer regs\n");
+
+ E1000_WRITE_REG(hw, FCAL, FLOW_CONTROL_ADDRESS_LOW);
+ E1000_WRITE_REG(hw, FCAH, FLOW_CONTROL_ADDRESS_HIGH);
+ E1000_WRITE_REG(hw, FCT, FLOW_CONTROL_TYPE);
+
+ E1000_WRITE_REG(hw, FCTTV, hw->fc_pause_time);
+
+ /* Set the flow control receive threshold registers. Normally,
+ * these registers will be set to a default threshold that may be
+ * adjusted later by the driver's runtime code. However, if the
+ * ability to transmit pause frames in not enabled, then these
+ * registers will be set to 0.
+ */
+ if(!(hw->fc & em_fc_tx_pause)) {
+ E1000_WRITE_REG(hw, FCRTL, 0);
+ E1000_WRITE_REG(hw, FCRTH, 0);
+ } else {
+ /* We need to set up the Receive Threshold high and low water marks
+ * as well as (optionally) enabling the transmission of XON frames.
+ */
+ if(hw->fc_send_xon) {
+ E1000_WRITE_REG(hw, FCRTL, (hw->fc_low_water | E1000_FCRTL_XONE));
+ E1000_WRITE_REG(hw, FCRTH, hw->fc_high_water);
+ } else {
+ E1000_WRITE_REG(hw, FCRTL, hw->fc_low_water);
+ E1000_WRITE_REG(hw, FCRTH, hw->fc_high_water);
+ }
+ }
+ return ret_val;
+}
+
+/******************************************************************************
+ * Sets up link for a fiber based or serdes based adapter
+ *
+ * hw - Struct containing variables accessed by shared code
+ *
+ * Manipulates Physical Coding Sublayer functions in order to configure
+ * link. Assumes the hardware has been previously reset and the transmitter
+ * and receiver are not enabled.
+ *****************************************************************************/
+static int32_t
+em_setup_fiber_serdes_link(struct em_hw *hw)
+{
+ uint32_t ctrl;
+ uint32_t status;
+ uint32_t txcw = 0;
+ uint32_t i;
+ uint32_t signal = 0;
+ int32_t ret_val;
+
+ DEBUGFUNC("em_setup_fiber_serdes_link");
+
+ /* On adapters with a MAC newer than 82544, SW Defineable pin 1 will be
+ * set when the optics detect a signal. On older adapters, it will be
+ * cleared when there is a signal. This applies to fiber media only.
+ * If we're on serdes media, adjust the output amplitude to value set in
+ * the EEPROM.
+ */
+ ctrl = E1000_READ_REG(hw, CTRL);
+ if(hw->media_type == em_media_type_fiber)
+ signal = (hw->mac_type > em_82544) ? E1000_CTRL_SWDPIN1 : 0;
+
+ ret_val = em_adjust_serdes_amplitude(hw);
+ if(ret_val)
+ return ret_val;
+
+ /* Take the link out of reset */
+ ctrl &= ~(E1000_CTRL_LRST);
+
+ /* Adjust VCO speed to improve BER performance */
+ ret_val = em_set_vco_speed(hw);
+ if(ret_val)
+ return ret_val;
+
+ em_config_collision_dist(hw);
+
+ /* Check for a software override of the flow control settings, and setup
+ * the device accordingly. If auto-negotiation is enabled, then software
+ * will have to set the "PAUSE" bits to the correct value in the Tranmsit
+ * Config Word Register (TXCW) and re-start auto-negotiation. However, if
+ * auto-negotiation is disabled, then software will have to manually
+ * configure the two flow control enable bits in the CTRL register.
+ *
+ * The possible values of the "fc" parameter are:
+ * 0: Flow control is completely disabled
+ * 1: Rx flow control is enabled (we can receive pause frames, but
+ * not send pause frames).
+ * 2: Tx flow control is enabled (we can send pause frames but we do
+ * not support receiving pause frames).
+ * 3: Both Rx and TX flow control (symmetric) are enabled.
+ */
+ switch (hw->fc) {
+ case em_fc_none:
+ /* Flow control is completely disabled by a software over-ride. */
+ txcw = (E1000_TXCW_ANE | E1000_TXCW_FD);
+ break;
+ case em_fc_rx_pause:
+ /* RX Flow control is enabled and TX Flow control is disabled by a
+ * software over-ride. Since there really isn't a way to advertise
+ * that we are capable of RX Pause ONLY, we will advertise that we
+ * support both symmetric and asymmetric RX PAUSE. Later, we will
+ * disable the adapter's ability to send PAUSE frames.
+ */
+ txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK);
+ break;
+ case em_fc_tx_pause:
+ /* TX Flow control is enabled, and RX Flow control is disabled, by a
+ * software over-ride.
+ */
+ txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_ASM_DIR);
+ break;
+ case em_fc_full:
+ /* Flow control (both RX and TX) is enabled by a software over-ride. */
+ txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK);
+ break;
+ default:
+ DEBUGOUT("Flow control param set incorrectly\n");
+ return -E1000_ERR_CONFIG;
+ break;
+ }
+
+ /* Since auto-negotiation is enabled, take the link out of reset (the link
+ * will be in reset, because we previously reset the chip). This will
+ * restart auto-negotiation. If auto-neogtiation is successful then the
+ * link-up status bit will be set and the flow control enable bits (RFCE
+ * and TFCE) will be set according to their negotiated value.
+ */
+ DEBUGOUT("Auto-negotiation enabled\n");
+
+ E1000_WRITE_REG(hw, TXCW, txcw);
+ E1000_WRITE_REG(hw, CTRL, ctrl);
+ E1000_WRITE_FLUSH(hw);
+
+ hw->txcw = txcw;
+ msec_delay(1);
+
+ /* If we have a signal (the cable is plugged in) then poll for a "Link-Up"
+ * indication in the Device Status Register. Time-out if a link isn't
+ * seen in 500 milliseconds seconds (Auto-negotiation should complete in
+ * less than 500 milliseconds even if the other end is doing it in SW).
+ * For internal serdes, we just assume a signal is present, then poll.
+ */
+ if(hw->media_type == em_media_type_internal_serdes ||
+ (E1000_READ_REG(hw, CTRL) & E1000_CTRL_SWDPIN1) == signal) {
+ DEBUGOUT("Looking for Link\n");
+ for(i = 0; i < (LINK_UP_TIMEOUT / 10); i++) {
+ msec_delay(10);
+ status = E1000_READ_REG(hw, STATUS);
+ if(status & E1000_STATUS_LU) break;
+ }
+ if(i == (LINK_UP_TIMEOUT / 10)) {
+ DEBUGOUT("Never got a valid link from auto-neg!!!\n");
+ hw->autoneg_failed = 1;
+ /* AutoNeg failed to achieve a link, so we'll call
+ * em_check_for_link. This routine will force the link up if
+ * we detect a signal. This will allow us to communicate with
+ * non-autonegotiating link partners.
+ */
+ ret_val = em_check_for_link(hw);
+ if(ret_val) {
+ DEBUGOUT("Error while checking for link\n");
+ return ret_val;
+ }
+ hw->autoneg_failed = 0;
+ } else {
+ hw->autoneg_failed = 0;
+ DEBUGOUT("Valid Link Found\n");
+ }
+ } else {
+ DEBUGOUT("No Signal Detected\n");
+ }
+ return E1000_SUCCESS;
+}
+
+/******************************************************************************
+* Make sure we have a valid PHY and change PHY mode before link setup.
+*
+* hw - Struct containing variables accessed by shared code
+******************************************************************************/
+static int32_t
+em_copper_link_preconfig(struct em_hw *hw)
+{
+ uint32_t ctrl;
+ int32_t ret_val;
+ uint16_t phy_data;
+
+ DEBUGFUNC("em_copper_link_preconfig");
+
+ ctrl = E1000_READ_REG(hw, CTRL);
+ /* With 82543, we need to force speed and duplex on the MAC equal to what
+ * the PHY speed and duplex configuration is. In addition, we need to
+ * perform a hardware reset on the PHY to take it out of reset.
+ */
+ if(hw->mac_type > em_82543) {
+ ctrl |= E1000_CTRL_SLU;
+ ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
+ E1000_WRITE_REG(hw, CTRL, ctrl);
+ } else {
+ ctrl |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX | E1000_CTRL_SLU);
+ E1000_WRITE_REG(hw, CTRL, ctrl);
+ ret_val = em_phy_hw_reset(hw);
+ if(ret_val)
+ return ret_val;
+ }
+
+ /* Make sure we have a valid PHY */
+ ret_val = em_detect_gig_phy(hw);
+ if(ret_val) {
+ DEBUGOUT("Error, did not detect valid phy.\n");
+ return ret_val;
+ }
+ DEBUGOUT1("Phy ID = %x \n", hw->phy_id);
+
+ /* Set PHY to class A mode (if necessary) */
+ ret_val = em_set_phy_mode(hw);
+ if(ret_val)
+ return ret_val;
+
+ if((hw->mac_type == em_82545_rev_3) ||
+ (hw->mac_type == em_82546_rev_3)) {
+ ret_val = em_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
+ phy_data |= 0x00000008;
+ ret_val = em_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
+ }
+
+ if(hw->mac_type <= em_82543 ||
+ hw->mac_type == em_82541 || hw->mac_type == em_82547 ||
+ hw->mac_type == em_82541_rev_2 || hw->mac_type == em_82547_rev_2)
+ hw->phy_reset_disable = FALSE;
+
+ return E1000_SUCCESS;
+}
+
+
+/********************************************************************
+* Copper link setup for em_phy_igp series.
+*
+* hw - Struct containing variables accessed by shared code
+*********************************************************************/
+static int32_t
+em_copper_link_igp_setup(struct em_hw *hw)
+{
+ uint32_t led_ctrl;
+ int32_t ret_val;
+ uint16_t phy_data;
+
+ DEBUGFUNC("em_copper_link_igp_setup");
+
+ if (hw->phy_reset_disable)
+ return E1000_SUCCESS;
+
+ ret_val = em_phy_reset(hw);
+ if (ret_val) {
+ DEBUGOUT("Error Resetting the PHY\n");
+ return ret_val;
+ }
+
+ /* Wait 10ms for MAC to configure PHY from eeprom settings */
+ msec_delay(15);
+
+ /* Configure activity LED after PHY reset */
+ led_ctrl = E1000_READ_REG(hw, LEDCTL);
+ led_ctrl &= IGP_ACTIVITY_LED_MASK;
+ led_ctrl |= (IGP_ACTIVITY_LED_ENABLE | IGP_LED3_MODE);
+ E1000_WRITE_REG(hw, LEDCTL, led_ctrl);
+
+ /* disable lplu d3 during driver init */
+ ret_val = em_set_d3_lplu_state(hw, FALSE);
+ if (ret_val) {
+ DEBUGOUT("Error Disabling LPLU D3\n");
+ return ret_val;
+ }
+
+ /* disable lplu d0 during driver init */
+ ret_val = em_set_d0_lplu_state(hw, FALSE);
+ if (ret_val) {
+ DEBUGOUT("Error Disabling LPLU D0\n");
+ return ret_val;
+ }
+ /* Configure mdi-mdix settings */
+ ret_val = em_read_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL, &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ if ((hw->mac_type == em_82541) || (hw->mac_type == em_82547)) {
+ hw->dsp_config_state = em_dsp_config_disabled;
+ /* Force MDI for earlier revs of the IGP PHY */
+ phy_data &= ~(IGP01E1000_PSCR_AUTO_MDIX | IGP01E1000_PSCR_FORCE_MDI_MDIX);
+ hw->mdix = 1;
+
+ } else {
+ hw->dsp_config_state = em_dsp_config_enabled;
+ phy_data &= ~IGP01E1000_PSCR_AUTO_MDIX;
+
+ switch (hw->mdix) {
+ case 1:
+ phy_data &= ~IGP01E1000_PSCR_FORCE_MDI_MDIX;
+ break;
+ case 2:
+ phy_data |= IGP01E1000_PSCR_FORCE_MDI_MDIX;
+ break;
+ case 0:
+ default:
+ phy_data |= IGP01E1000_PSCR_AUTO_MDIX;
+ break;
+ }
+ }
+ ret_val = em_write_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL, phy_data);
+ if(ret_val)
+ return ret_val;
+
+ /* set auto-master slave resolution settings */
+ if(hw->autoneg) {
+ em_ms_type phy_ms_setting = hw->master_slave;
+
+ if(hw->ffe_config_state == em_ffe_config_active)
+ hw->ffe_config_state = em_ffe_config_enabled;
+
+ if(hw->dsp_config_state == em_dsp_config_activated)
+ hw->dsp_config_state = em_dsp_config_enabled;
+
+ /* when autonegotiation advertisment is only 1000Mbps then we
+ * should disable SmartSpeed and enable Auto MasterSlave
+ * resolution as hardware default. */
+ if(hw->autoneg_advertised == ADVERTISE_1000_FULL) {
+ /* Disable SmartSpeed */
+ ret_val = em_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG, &phy_data);
+ if(ret_val)
+ return ret_val;
+ phy_data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+ ret_val = em_write_phy_reg(hw,
+ IGP01E1000_PHY_PORT_CONFIG,
+ phy_data);
+ if(ret_val)
+ return ret_val;
+ /* Set auto Master/Slave resolution process */
+ ret_val = em_read_phy_reg(hw, PHY_1000T_CTRL, &phy_data);
+ if(ret_val)
+ return ret_val;
+ phy_data &= ~CR_1000T_MS_ENABLE;
+ ret_val = em_write_phy_reg(hw, PHY_1000T_CTRL, phy_data);
+ if(ret_val)
+ return ret_val;
+ }
+
+ ret_val = em_read_phy_reg(hw, PHY_1000T_CTRL, &phy_data);
+ if(ret_val)
+ return ret_val;
+
+ /* load defaults for future use */
+ hw->original_master_slave = (phy_data & CR_1000T_MS_ENABLE) ?
+ ((phy_data & CR_1000T_MS_VALUE) ?
+ em_ms_force_master :
+ em_ms_force_slave) :
+ em_ms_auto;
+
+ switch (phy_ms_setting) {
+ case em_ms_force_master:
+ phy_data |= (CR_1000T_MS_ENABLE | CR_1000T_MS_VALUE);
+ break;
+ case em_ms_force_slave:
+ phy_data |= CR_1000T_MS_ENABLE;
+ phy_data &= ~(CR_1000T_MS_VALUE);
+ break;
+ case em_ms_auto:
+ phy_data &= ~CR_1000T_MS_ENABLE;
+ default:
+ break;
+ }
+ ret_val = em_write_phy_reg(hw, PHY_1000T_CTRL, phy_data);
+ if(ret_val)
+ return ret_val;
+ }
+
+ return E1000_SUCCESS;
+}
+
+
+/********************************************************************
+* Copper link setup for em_phy_m88 series.
+*
+* hw - Struct containing variables accessed by shared code
+*********************************************************************/
+static int32_t
+em_copper_link_mgp_setup(struct em_hw *hw)
+{
+ int32_t ret_val;
+ uint16_t phy_data;
+
+ DEBUGFUNC("em_copper_link_mgp_setup");
+
+ if(hw->phy_reset_disable)
+ return E1000_SUCCESS;
+
+ /* Enable CRS on TX. This must be set for half-duplex operation. */
+ ret_val = em_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
+ if(ret_val)
+ return ret_val;
+
+ phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
+
+ /* Options:
+ * MDI/MDI-X = 0 (default)
+ * 0 - Auto for all speeds
+ * 1 - MDI mode
+ * 2 - MDI-X mode
+ * 3 - Auto for 1000Base-T only (MDI-X for 10/100Base-T modes)
+ */
+ phy_data &= ~M88E1000_PSCR_AUTO_X_MODE;
+
+ switch (hw->mdix) {
+ case 1:
+ phy_data |= M88E1000_PSCR_MDI_MANUAL_MODE;
+ break;
+ case 2:
+ phy_data |= M88E1000_PSCR_MDIX_MANUAL_MODE;
+ break;
+ case 3:
+ phy_data |= M88E1000_PSCR_AUTO_X_1000T;
+ break;
+ case 0:
+ default:
+ phy_data |= M88E1000_PSCR_AUTO_X_MODE;
+ break;
+ }
+
+ /* Options:
+ * disable_polarity_correction = 0 (default)
+ * Automatic Correction for Reversed Cable Polarity
+ * 0 - Disabled
+ * 1 - Enabled
+ */
+ phy_data &= ~M88E1000_PSCR_POLARITY_REVERSAL;
+ if(hw->disable_polarity_correction == 1)
+ phy_data |= M88E1000_PSCR_POLARITY_REVERSAL;
+ ret_val = em_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
+ if(ret_val)
+ return ret_val;
+
+ /* Force TX_CLK in the Extended PHY Specific Control Register
+ * to 25MHz clock.
+ */
+ ret_val = em_read_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data);
+ if(ret_val)
+ return ret_val;
+
+ phy_data |= M88E1000_EPSCR_TX_CLK_25;
+
+ if (hw->phy_revision < M88E1011_I_REV_4) {
+ /* Configure Master and Slave downshift values */
+ phy_data &= ~(M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK |
+ M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK);
+ phy_data |= (M88E1000_EPSCR_MASTER_DOWNSHIFT_1X |
+ M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X);
+ ret_val = em_write_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, phy_data);
+ if(ret_val)
+ return ret_val;
+ }
+
+ /* SW Reset the PHY so all changes take effect */
+ ret_val = em_phy_reset(hw);
+ if(ret_val) {
+ DEBUGOUT("Error Resetting the PHY\n");
+ return ret_val;
+ }
+
+ return E1000_SUCCESS;
+}
+
+/********************************************************************
+* Setup auto-negotiation and flow control advertisements,
+* and then perform auto-negotiation.
+*
+* hw - Struct containing variables accessed by shared code
+*********************************************************************/
+static int32_t
+em_copper_link_autoneg(struct em_hw *hw)
+{
+ int32_t ret_val;
+ uint16_t phy_data;
+
+ DEBUGFUNC("em_copper_link_autoneg");
+
+ /* Perform some bounds checking on the hw->autoneg_advertised
+ * parameter. If this variable is zero, then set it to the default.
+ */
+ hw->autoneg_advertised &= AUTONEG_ADVERTISE_SPEED_DEFAULT;
+
+ /* If autoneg_advertised is zero, we assume it was not defaulted
+ * by the calling code so we set to advertise full capability.
+ */
+ if(hw->autoneg_advertised == 0)
+ hw->autoneg_advertised = AUTONEG_ADVERTISE_SPEED_DEFAULT;
+
+ DEBUGOUT("Reconfiguring auto-neg advertisement params\n");
+ ret_val = em_phy_setup_autoneg(hw);
+ if(ret_val) {
+ DEBUGOUT("Error Setting up Auto-Negotiation\n");
+ return ret_val;
+ }
+ DEBUGOUT("Restarting Auto-Neg\n");
+
+ /* Restart auto-negotiation by setting the Auto Neg Enable bit and
+ * the Auto Neg Restart bit in the PHY control register.
+ */
+ ret_val = em_read_phy_reg(hw, PHY_CTRL, &phy_data);
+ if(ret_val)
+ return ret_val;
+
+ phy_data |= (MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG);
+ ret_val = em_write_phy_reg(hw, PHY_CTRL, phy_data);
+ if(ret_val)
+ return ret_val;
+
+ /* Does the user want to wait for Auto-Neg to complete here, or
+ * check at a later time (for example, callback routine).
+ */
+ if(hw->wait_autoneg_complete) {
+ ret_val = em_wait_autoneg(hw);
+ if(ret_val) {
+ DEBUGOUT("Error while waiting for autoneg to complete\n");
+ return ret_val;
+ }
+ }
+
+ hw->get_link_status = TRUE;
+
+ return E1000_SUCCESS;
+}
+
+
+/******************************************************************************
+* Config the MAC and the PHY after link is up.
+* 1) Set up the MAC to the current PHY speed/duplex
+* if we are on 82543. If we
+* are on newer silicon, we only need to configure
+* collision distance in the Transmit Control Register.
+* 2) Set up flow control on the MAC to that established with
+* the link partner.
+* 3) Config DSP to improve Gigabit link quality for some PHY revisions.
+*
+* hw - Struct containing variables accessed by shared code
+******************************************************************************/
+static int32_t
+em_copper_link_postconfig(struct em_hw *hw)
+{
+ int32_t ret_val;
+ DEBUGFUNC("em_copper_link_postconfig");
+
+ if(hw->mac_type >= em_82544) {
+ em_config_collision_dist(hw);
+ } else {
+ ret_val = em_config_mac_to_phy(hw);
+ if(ret_val) {
+ DEBUGOUT("Error configuring MAC to PHY settings\n");
+ return ret_val;
+ }
+ }
+ ret_val = em_config_fc_after_link_up(hw);
+ if(ret_val) {
+ DEBUGOUT("Error Configuring Flow Control\n");
+ return ret_val;
+ }
+
+ /* Config DSP to improve Giga link quality */
+ if(hw->phy_type == em_phy_igp) {
+ ret_val = em_config_dsp_after_link_change(hw, TRUE);
+ if(ret_val) {
+ DEBUGOUT("Error Configuring DSP after link up\n");
+ return ret_val;
+ }
+ }
+
+ return E1000_SUCCESS;
+}
+
+/******************************************************************************
+* Detects which PHY is present and setup the speed and duplex
+*
+* hw - Struct containing variables accessed by shared code
+******************************************************************************/
+static int32_t
+em_setup_copper_link(struct em_hw *hw)
+{
+ int32_t ret_val;
+ uint16_t i;
+ uint16_t phy_data;
+
+ DEBUGFUNC("em_setup_copper_link");
+
+ /* Check if it is a valid PHY and set PHY mode if necessary. */
+ ret_val = em_copper_link_preconfig(hw);
+ if(ret_val)
+ return ret_val;
+
+ if (hw->phy_type == em_phy_igp ||
+ hw->phy_type == em_phy_igp_2) {
+ ret_val = em_copper_link_igp_setup(hw);
+ if(ret_val)
+ return ret_val;
+ } else if (hw->phy_type == em_phy_m88) {
+ ret_val = em_copper_link_mgp_setup(hw);
+ if(ret_val)
+ return ret_val;
+ }
+
+ if(hw->autoneg) {
+ /* Setup autoneg and flow control advertisement
+ * and perform autonegotiation */
+ ret_val = em_copper_link_autoneg(hw);
+ if(ret_val)
+ return ret_val;
+ } else {
+ /* PHY will be set to 10H, 10F, 100H,or 100F
+ * depending on value from forced_speed_duplex. */
+ DEBUGOUT("Forcing speed and duplex\n");
+ ret_val = em_phy_force_speed_duplex(hw);
+ if(ret_val) {
+ DEBUGOUT("Error Forcing Speed and Duplex\n");
+ return ret_val;
+ }
+ }
+
+ /* Check link status. Wait up to 100 microseconds for link to become
+ * valid.
+ */
+ for(i = 0; i < 10; i++) {
+ ret_val = em_read_phy_reg(hw, PHY_STATUS, &phy_data);
+ if(ret_val)
+ return ret_val;
+ ret_val = em_read_phy_reg(hw, PHY_STATUS, &phy_data);
+ if(ret_val)
+ return ret_val;
+
+ if(phy_data & MII_SR_LINK_STATUS) {
+ /* Config the MAC and PHY after link is up */
+ ret_val = em_copper_link_postconfig(hw);
+ if(ret_val)
+ return ret_val;
+
+ DEBUGOUT("Valid link established!!!\n");
+ return E1000_SUCCESS;
+ }
+ usec_delay(10);
+ }
+
+ DEBUGOUT("Unable to establish link!!!\n");
+ return E1000_SUCCESS;
+}
+
+/******************************************************************************
+* Configures PHY autoneg and flow control advertisement settings
+*
+* hw - Struct containing variables accessed by shared code
+******************************************************************************/
+int32_t
+em_phy_setup_autoneg(struct em_hw *hw)
+{
+ int32_t ret_val;
+ uint16_t mii_autoneg_adv_reg;
+ uint16_t mii_1000t_ctrl_reg;
+
+ DEBUGFUNC("em_phy_setup_autoneg");
+
+ /* Read the MII Auto-Neg Advertisement Register (Address 4). */
+ ret_val = em_read_phy_reg(hw, PHY_AUTONEG_ADV, &mii_autoneg_adv_reg);
+ if(ret_val)
+ return ret_val;
+
+ /* Read the MII 1000Base-T Control Register (Address 9). */
+ ret_val = em_read_phy_reg(hw, PHY_1000T_CTRL, &mii_1000t_ctrl_reg);
+ if(ret_val)
+ return ret_val;
+
+ /* Need to parse both autoneg_advertised and fc and set up
+ * the appropriate PHY registers. First we will parse for
+ * autoneg_advertised software override. Since we can advertise
+ * a plethora of combinations, we need to check each bit
+ * individually.
+ */
+
+ /* First we clear all the 10/100 mb speed bits in the Auto-Neg
+ * Advertisement Register (Address 4) and the 1000 mb speed bits in
+ * the 1000Base-T Control Register (Address 9).
+ */
+ mii_autoneg_adv_reg &= ~REG4_SPEED_MASK;
+ mii_1000t_ctrl_reg &= ~REG9_SPEED_MASK;
+
+ DEBUGOUT1("autoneg_advertised %x\n", hw->autoneg_advertised);
+
+ /* Do we want to advertise 10 Mb Half Duplex? */
+ if(hw->autoneg_advertised & ADVERTISE_10_HALF) {
+ DEBUGOUT("Advertise 10mb Half duplex\n");
+ mii_autoneg_adv_reg |= NWAY_AR_10T_HD_CAPS;
+ }
+
+ /* Do we want to advertise 10 Mb Full Duplex? */
+ if(hw->autoneg_advertised & ADVERTISE_10_FULL) {
+ DEBUGOUT("Advertise 10mb Full duplex\n");
+ mii_autoneg_adv_reg |= NWAY_AR_10T_FD_CAPS;
+ }
+
+ /* Do we want to advertise 100 Mb Half Duplex? */
+ if(hw->autoneg_advertised & ADVERTISE_100_HALF) {
+ DEBUGOUT("Advertise 100mb Half duplex\n");
+ mii_autoneg_adv_reg |= NWAY_AR_100TX_HD_CAPS;
+ }
+
+ /* Do we want to advertise 100 Mb Full Duplex? */
+ if(hw->autoneg_advertised & ADVERTISE_100_FULL) {
+ DEBUGOUT("Advertise 100mb Full duplex\n");
+ mii_autoneg_adv_reg |= NWAY_AR_100TX_FD_CAPS;
+ }
+
+ /* We do not allow the Phy to advertise 1000 Mb Half Duplex */
+ if(hw->autoneg_advertised & ADVERTISE_1000_HALF) {
+ DEBUGOUT("Advertise 1000mb Half duplex requested, request denied!\n");
+ }
+
+ /* Do we want to advertise 1000 Mb Full Duplex? */
+ if(hw->autoneg_advertised & ADVERTISE_1000_FULL) {
+ DEBUGOUT("Advertise 1000mb Full duplex\n");
+ mii_1000t_ctrl_reg |= CR_1000T_FD_CAPS;
+ }
+
+ /* Check for a software override of the flow control settings, and
+ * setup the PHY advertisement registers accordingly. If
+ * auto-negotiation is enabled, then software will have to set the
+ * "PAUSE" bits to the correct value in the Auto-Negotiation
+ * Advertisement Register (PHY_AUTONEG_ADV) and re-start auto-negotiation.
+ *
+ * The possible values of the "fc" parameter are:
+ * 0: Flow control is completely disabled
+ * 1: Rx flow control is enabled (we can receive pause frames
+ * but not send pause frames).
+ * 2: Tx flow control is enabled (we can send pause frames
+ * but we do not support receiving pause frames).
+ * 3: Both Rx and TX flow control (symmetric) are enabled.
+ * other: No software override. The flow control configuration
+ * in the EEPROM is used.
+ */
+ switch (hw->fc) {
+ case em_fc_none: /* 0 */
+ /* Flow control (RX & TX) is completely disabled by a
+ * software over-ride.
+ */
+ mii_autoneg_adv_reg &= ~(NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
+ break;
+ case em_fc_rx_pause: /* 1 */
+ /* RX Flow control is enabled, and TX Flow control is
+ * disabled, by a software over-ride.
+ */
+ /* Since there really isn't a way to advertise that we are
+ * capable of RX Pause ONLY, we will advertise that we
+ * support both symmetric and asymmetric RX PAUSE. Later
+ * (in em_config_fc_after_link_up) we will disable the
+ *hw's ability to send PAUSE frames.
+ */
+ mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
+ break;
+ case em_fc_tx_pause: /* 2 */
+ /* TX Flow control is enabled, and RX Flow control is
+ * disabled, by a software over-ride.
+ */
+ mii_autoneg_adv_reg |= NWAY_AR_ASM_DIR;
+ mii_autoneg_adv_reg &= ~NWAY_AR_PAUSE;
+ break;
+ case em_fc_full: /* 3 */
+ /* Flow control (both RX and TX) is enabled by a software
+ * over-ride.
+ */
+ mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
+ break;
+ default:
+ DEBUGOUT("Flow control param set incorrectly\n");
+ return -E1000_ERR_CONFIG;
+ }
+
+ ret_val = em_write_phy_reg(hw, PHY_AUTONEG_ADV, mii_autoneg_adv_reg);
+ if(ret_val)
+ return ret_val;
+
+ DEBUGOUT1("Auto-Neg Advertising %x\n", mii_autoneg_adv_reg);
+
+ ret_val = em_write_phy_reg(hw, PHY_1000T_CTRL, mii_1000t_ctrl_reg);
+ if(ret_val)
+ return ret_val;
+
+ return E1000_SUCCESS;
+}
+
+/******************************************************************************
+* Force PHY speed and duplex settings to hw->forced_speed_duplex
+*
+* hw - Struct containing variables accessed by shared code
+******************************************************************************/
+static int32_t
+em_phy_force_speed_duplex(struct em_hw *hw)
+{
+ uint32_t ctrl;
+ int32_t ret_val;
+ uint16_t mii_ctrl_reg;
+ uint16_t mii_status_reg;
+ uint16_t phy_data;
+ uint16_t i;
+
+ DEBUGFUNC("em_phy_force_speed_duplex");
+
+ /* Turn off Flow control if we are forcing speed and duplex. */
+ hw->fc = em_fc_none;
+
+ DEBUGOUT1("hw->fc = %d\n", hw->fc);
+
+ /* Read the Device Control Register. */
+ ctrl = E1000_READ_REG(hw, CTRL);
+
+ /* Set the bits to Force Speed and Duplex in the Device Ctrl Reg. */
+ ctrl |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
+ ctrl &= ~(DEVICE_SPEED_MASK);
+
+ /* Clear the Auto Speed Detect Enable bit. */
+ ctrl &= ~E1000_CTRL_ASDE;
+
+ /* Read the MII Control Register. */
+ ret_val = em_read_phy_reg(hw, PHY_CTRL, &mii_ctrl_reg);
+ if(ret_val)
+ return ret_val;
+
+ /* We need to disable autoneg in order to force link and duplex. */
+
+ mii_ctrl_reg &= ~MII_CR_AUTO_NEG_EN;
+
+ /* Are we forcing Full or Half Duplex? */
+ if(hw->forced_speed_duplex == em_100_full ||
+ hw->forced_speed_duplex == em_10_full) {
+ /* We want to force full duplex so we SET the full duplex bits in the
+ * Device and MII Control Registers.
+ */
+ ctrl |= E1000_CTRL_FD;
+ mii_ctrl_reg |= MII_CR_FULL_DUPLEX;
+ DEBUGOUT("Full Duplex\n");
+ } else {
+ /* We want to force half duplex so we CLEAR the full duplex bits in
+ * the Device and MII Control Registers.
+ */
+ ctrl &= ~E1000_CTRL_FD;
+ mii_ctrl_reg &= ~MII_CR_FULL_DUPLEX;
+ DEBUGOUT("Half Duplex\n");
+ }
+
+ /* Are we forcing 100Mbps??? */
+ if(hw->forced_speed_duplex == em_100_full ||
+ hw->forced_speed_duplex == em_100_half) {
+ /* Set the 100Mb bit and turn off the 1000Mb and 10Mb bits. */
+ ctrl |= E1000_CTRL_SPD_100;
+ mii_ctrl_reg |= MII_CR_SPEED_100;
+ mii_ctrl_reg &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_10);
+ DEBUGOUT("Forcing 100mb ");
+ } else {
+ /* Set the 10Mb bit and turn off the 1000Mb and 100Mb bits. */
+ ctrl &= ~(E1000_CTRL_SPD_1000 | E1000_CTRL_SPD_100);
+ mii_ctrl_reg |= MII_CR_SPEED_10;
+ mii_ctrl_reg &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_100);
+ DEBUGOUT("Forcing 10mb ");
+ }
+
+ em_config_collision_dist(hw);
+
+ /* Write the configured values back to the Device Control Reg. */
+ E1000_WRITE_REG(hw, CTRL, ctrl);
+
+ if (hw->phy_type == em_phy_m88) {
+ ret_val = em_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
+ if(ret_val)
+ return ret_val;
+
+ /* Clear Auto-Crossover to force MDI manually. M88E1000 requires MDI
+ * forced whenever speed are duplex are forced.
+ */
+ phy_data &= ~M88E1000_PSCR_AUTO_X_MODE;
+ ret_val = em_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
+ if(ret_val)
+ return ret_val;
+
+ DEBUGOUT1("M88E1000 PSCR: %x \n", phy_data);
+
+ /* Need to reset the PHY or these changes will be ignored */
+ mii_ctrl_reg |= MII_CR_RESET;
+ } else {
+ /* Clear Auto-Crossover to force MDI manually. IGP requires MDI
+ * forced whenever speed or duplex are forced.
+ */
+ ret_val = em_read_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL, &phy_data);
+ if(ret_val)
+ return ret_val;
+
+ phy_data &= ~IGP01E1000_PSCR_AUTO_MDIX;
+ phy_data &= ~IGP01E1000_PSCR_FORCE_MDI_MDIX;
+
+ ret_val = em_write_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL, phy_data);
+ if(ret_val)
+ return ret_val;
+ }
+
+ /* Write back the modified PHY MII control register. */
+ ret_val = em_write_phy_reg(hw, PHY_CTRL, mii_ctrl_reg);
+ if(ret_val)
+ return ret_val;
+
+ usec_delay(1);
+
+ /* The wait_autoneg_complete flag may be a little misleading here.
+ * Since we are forcing speed and duplex, Auto-Neg is not enabled.
+ * But we do want to delay for a period while forcing only so we
+ * don't generate false No Link messages. So we will wait here
+ * only if the user has set wait_autoneg_complete to 1, which is
+ * the default.
+ */
+ if(hw->wait_autoneg_complete) {
+ /* We will wait for autoneg to complete. */
+ DEBUGOUT("Waiting for forced speed/duplex link.\n");
+ mii_status_reg = 0;
+
+ /* We will wait for autoneg to complete or 4.5 seconds to expire. */
+ for(i = PHY_FORCE_TIME; i > 0; i--) {
+ /* Read the MII Status Register and wait for Auto-Neg Complete bit
+ * to be set.
+ */
+ ret_val = em_read_phy_reg(hw, PHY_STATUS, &mii_status_reg);
+ if(ret_val)
+ return ret_val;
+
+ ret_val = em_read_phy_reg(hw, PHY_STATUS, &mii_status_reg);
+ if(ret_val)
+ return ret_val;
+
+ if(mii_status_reg & MII_SR_LINK_STATUS) break;
+ msec_delay(100);
+ }
+ if((i == 0) &&
+ (hw->phy_type == em_phy_m88)) {
+ /* We didn't get link. Reset the DSP and wait again for link. */
+ ret_val = em_phy_reset_dsp(hw);
+ if(ret_val) {
+ DEBUGOUT("Error Resetting PHY DSP\n");
+ return ret_val;
+ }
+ }
+ /* This loop will early-out if the link condition has been met. */
+ for(i = PHY_FORCE_TIME; i > 0; i--) {
+ if(mii_status_reg & MII_SR_LINK_STATUS) break;
+ msec_delay(100);
+ /* Read the MII Status Register and wait for Auto-Neg Complete bit
+ * to be set.
+ */
+ ret_val = em_read_phy_reg(hw, PHY_STATUS, &mii_status_reg);
+ if(ret_val)
+ return ret_val;
+
+ ret_val = em_read_phy_reg(hw, PHY_STATUS, &mii_status_reg);
+ if(ret_val)
+ return ret_val;
+ }
+ }
+
+ if (hw->phy_type == em_phy_m88) {
+ /* Because we reset the PHY above, we need to re-force TX_CLK in the
+ * Extended PHY Specific Control Register to 25MHz clock. This value
+ * defaults back to a 2.5MHz clock when the PHY is reset.
+ */
+ ret_val = em_read_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data);
+ if(ret_val)
+ return ret_val;
+
+ phy_data |= M88E1000_EPSCR_TX_CLK_25;
+ ret_val = em_write_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, phy_data);
+ if(ret_val)
+ return ret_val;
+
+ /* In addition, because of the s/w reset above, we need to enable CRS on
+ * TX. This must be set for both full and half duplex operation.
+ */
+ ret_val = em_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
+ if(ret_val)
+ return ret_val;
+
+ phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
+ ret_val = em_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
+ if(ret_val)
+ return ret_val;
+
+ if((hw->mac_type == em_82544 || hw->mac_type == em_82543) &&
+ (!hw->autoneg) &&
+ (hw->forced_speed_duplex == em_10_full ||
+ hw->forced_speed_duplex == em_10_half)) {
+ ret_val = em_polarity_reversal_workaround(hw);
+ if(ret_val)
+ return ret_val;
+ }
+ }
+ return E1000_SUCCESS;
+}
+
+/******************************************************************************
+* Sets the collision distance in the Transmit Control register
+*
+* hw - Struct containing variables accessed by shared code
+*
+* Link should have been established previously. Reads the speed and duplex
+* information from the Device Status register.
+******************************************************************************/
+void
+em_config_collision_dist(struct em_hw *hw)
+{
+ uint32_t tctl;
+
+ DEBUGFUNC("em_config_collision_dist");
+
+ tctl = E1000_READ_REG(hw, TCTL);
+
+ tctl &= ~E1000_TCTL_COLD;
+ tctl |= E1000_COLLISION_DISTANCE << E1000_COLD_SHIFT;
+
+ E1000_WRITE_REG(hw, TCTL, tctl);
+ E1000_WRITE_FLUSH(hw);
+}
+
+/******************************************************************************
+* Sets MAC speed and duplex settings to reflect the those in the PHY
+*
+* hw - Struct containing variables accessed by shared code
+* mii_reg - data to write to the MII control register
+*
+* The contents of the PHY register containing the needed information need to
+* be passed in.
+******************************************************************************/
+static int32_t
+em_config_mac_to_phy(struct em_hw *hw)
+{
+ uint32_t ctrl;
+ int32_t ret_val;
+ uint16_t phy_data;
+
+ DEBUGFUNC("em_config_mac_to_phy");
+
+ /* 82544 or newer MAC, Auto Speed Detection takes care of
+ * MAC speed/duplex configuration.*/
+ if (hw->mac_type >= em_82544)
+ return E1000_SUCCESS;
+
+ /* Read the Device Control Register and set the bits to Force Speed
+ * and Duplex.
+ */
+ ctrl = E1000_READ_REG(hw, CTRL);
+ ctrl |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
+ ctrl &= ~(E1000_CTRL_SPD_SEL | E1000_CTRL_ILOS);
+
+ /* Set up duplex in the Device Control and Transmit Control
+ * registers depending on negotiated values.
+ */
+ ret_val = em_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data);
+ if(ret_val)
+ return ret_val;
+
+ if(phy_data & M88E1000_PSSR_DPLX)
+ ctrl |= E1000_CTRL_FD;
+ else
+ ctrl &= ~E1000_CTRL_FD;
+
+ em_config_collision_dist(hw);
+
+ /* Set up speed in the Device Control register depending on
+ * negotiated values.
+ */
+ if((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS)
+ ctrl |= E1000_CTRL_SPD_1000;
+ else if((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_100MBS)
+ ctrl |= E1000_CTRL_SPD_100;
+
+ /* Write the configured values back to the Device Control Reg. */
+ E1000_WRITE_REG(hw, CTRL, ctrl);
+ return E1000_SUCCESS;
+}
+
+/******************************************************************************
+ * Forces the MAC's flow control settings.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *
+ * Sets the TFCE and RFCE bits in the device control register to reflect
+ * the adapter settings. TFCE and RFCE need to be explicitly set by
+ * software when a Copper PHY is used because autonegotiation is managed
+ * by the PHY rather than the MAC. Software must also configure these
+ * bits when link is forced on a fiber connection.
+ *****************************************************************************/
+int32_t
+em_force_mac_fc(struct em_hw *hw)
+{
+ uint32_t ctrl;
+
+ DEBUGFUNC("em_force_mac_fc");
+
+ /* Get the current configuration of the Device Control Register */
+ ctrl = E1000_READ_REG(hw, CTRL);
+
+ /* Because we didn't get link via the internal auto-negotiation
+ * mechanism (we either forced link or we got link via PHY
+ * auto-neg), we have to manually enable/disable transmit an
+ * receive flow control.
+ *
+ * The "Case" statement below enables/disable flow control
+ * according to the "hw->fc" parameter.
+ *
+ * The possible values of the "fc" parameter are:
+ * 0: Flow control is completely disabled
+ * 1: Rx flow control is enabled (we can receive pause
+ * frames but not send pause frames).
+ * 2: Tx flow control is enabled (we can send pause frames
+ * frames but we do not receive pause frames).
+ * 3: Both Rx and TX flow control (symmetric) is enabled.
+ * other: No other values should be possible at this point.
+ */
+
+ switch (hw->fc) {
+ case em_fc_none:
+ ctrl &= (~(E1000_CTRL_TFCE | E1000_CTRL_RFCE));
+ break;
+ case em_fc_rx_pause:
+ ctrl &= (~E1000_CTRL_TFCE);
+ ctrl |= E1000_CTRL_RFCE;
+ break;
+ case em_fc_tx_pause:
+ ctrl &= (~E1000_CTRL_RFCE);
+ ctrl |= E1000_CTRL_TFCE;
+ break;
+ case em_fc_full:
+ ctrl |= (E1000_CTRL_TFCE | E1000_CTRL_RFCE);
+ break;
+ default:
+ DEBUGOUT("Flow control param set incorrectly\n");
+ return -E1000_ERR_CONFIG;
+ }
+
+ /* Disable TX Flow Control for 82542 (rev 2.0) */
+ if(hw->mac_type == em_82542_rev2_0)
+ ctrl &= (~E1000_CTRL_TFCE);
+
+ E1000_WRITE_REG(hw, CTRL, ctrl);
+ return E1000_SUCCESS;
+}
+
+/******************************************************************************
+ * Configures flow control settings after link is established
+ *
+ * hw - Struct containing variables accessed by shared code
+ *
+ * Should be called immediately after a valid link has been established.
+ * Forces MAC flow control settings if link was forced. When in MII/GMII mode
+ * and autonegotiation is enabled, the MAC flow control settings will be set
+ * based on the flow control negotiated by the PHY. In TBI mode, the TFCE
+ * and RFCE bits will be automaticaly set to the negotiated flow control mode.
+ *****************************************************************************/
+int32_t
+em_config_fc_after_link_up(struct em_hw *hw)
+{
+ int32_t ret_val;
+ uint16_t mii_status_reg;
+ uint16_t mii_nway_adv_reg;
+ uint16_t mii_nway_lp_ability_reg;
+ uint16_t speed;
+ uint16_t duplex;
+
+ DEBUGFUNC("em_config_fc_after_link_up");
+
+ /* Check for the case where we have fiber media and auto-neg failed
+ * so we had to force link. In this case, we need to force the
+ * configuration of the MAC to match the "fc" parameter.
+ */
+ if(((hw->media_type == em_media_type_fiber) && (hw->autoneg_failed)) ||
+ ((hw->media_type == em_media_type_internal_serdes) && (hw->autoneg_failed)) ||
+ ((hw->media_type == em_media_type_copper) && (!hw->autoneg))) {
+ ret_val = em_force_mac_fc(hw);
+ if(ret_val) {
+ DEBUGOUT("Error forcing flow control settings\n");
+ return ret_val;
+ }
+ }
+
+ /* Check for the case where we have copper media and auto-neg is
+ * enabled. In this case, we need to check and see if Auto-Neg
+ * has completed, and if so, how the PHY and link partner has
+ * flow control configured.
+ */
+ if((hw->media_type == em_media_type_copper) && hw->autoneg) {
+ /* Read the MII Status Register and check to see if AutoNeg
+ * has completed. We read this twice because this reg has
+ * some "sticky" (latched) bits.
+ */
+ ret_val = em_read_phy_reg(hw, PHY_STATUS, &mii_status_reg);
+ if(ret_val)
+ return ret_val;
+ ret_val = em_read_phy_reg(hw, PHY_STATUS, &mii_status_reg);
+ if(ret_val)
+ return ret_val;
+
+ if(mii_status_reg & MII_SR_AUTONEG_COMPLETE) {
+ /* The AutoNeg process has completed, so we now need to
+ * read both the Auto Negotiation Advertisement Register
+ * (Address 4) and the Auto_Negotiation Base Page Ability
+ * Register (Address 5) to determine how flow control was
+ * negotiated.
+ */
+ ret_val = em_read_phy_reg(hw, PHY_AUTONEG_ADV,
+ &mii_nway_adv_reg);
+ if(ret_val)
+ return ret_val;
+ ret_val = em_read_phy_reg(hw, PHY_LP_ABILITY,
+ &mii_nway_lp_ability_reg);
+ if(ret_val)
+ return ret_val;
+
+ /* Two bits in the Auto Negotiation Advertisement Register
+ * (Address 4) and two bits in the Auto Negotiation Base
+ * Page Ability Register (Address 5) determine flow control
+ * for both the PHY and the link partner. The following
+ * table, taken out of the IEEE 802.3ab/D6.0 dated March 25,
+ * 1999, describes these PAUSE resolution bits and how flow
+ * control is determined based upon these settings.
+ * NOTE: DC = Don't Care
+ *
+ * LOCAL DEVICE | LINK PARTNER
+ * PAUSE | ASM_DIR | PAUSE | ASM_DIR | NIC Resolution
+ *-------|---------|-------|---------|--------------------
+ * 0 | 0 | DC | DC | em_fc_none
+ * 0 | 1 | 0 | DC | em_fc_none
+ * 0 | 1 | 1 | 0 | em_fc_none
+ * 0 | 1 | 1 | 1 | em_fc_tx_pause
+ * 1 | 0 | 0 | DC | em_fc_none
+ * 1 | DC | 1 | DC | em_fc_full
+ * 1 | 1 | 0 | 0 | em_fc_none
+ * 1 | 1 | 0 | 1 | em_fc_rx_pause
+ *
+ */
+ /* Are both PAUSE bits set to 1? If so, this implies
+ * Symmetric Flow Control is enabled at both ends. The
+ * ASM_DIR bits are irrelevant per the spec.
+ *
+ * For Symmetric Flow Control:
+ *
+ * LOCAL DEVICE | LINK PARTNER
+ * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
+ *-------|---------|-------|---------|--------------------
+ * 1 | DC | 1 | DC | em_fc_full
+ *
+ */
+ if((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
+ (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE)) {
+ /* Now we need to check if the user selected RX ONLY
+ * of pause frames. In this case, we had to advertise
+ * FULL flow control because we could not advertise RX
+ * ONLY. Hence, we must now check to see if we need to
+ * turn OFF the TRANSMISSION of PAUSE frames.
+ */
+ if(hw->original_fc == em_fc_full) {
+ hw->fc = em_fc_full;
+ DEBUGOUT("Flow Control = FULL.\r\n");
+ } else {
+ hw->fc = em_fc_rx_pause;
+ DEBUGOUT("Flow Control = RX PAUSE frames only.\r\n");
+ }
+ }
+ /* For receiving PAUSE frames ONLY.
+ *
+ * LOCAL DEVICE | LINK PARTNER
+ * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
+ *-------|---------|-------|---------|--------------------
+ * 0 | 1 | 1 | 1 | em_fc_tx_pause
+ *
+ */
+ else if(!(mii_nway_adv_reg & NWAY_AR_PAUSE) &&
+ (mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
+ (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
+ (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
+ hw->fc = em_fc_tx_pause;
+ DEBUGOUT("Flow Control = TX PAUSE frames only.\r\n");
+ }
+ /* For transmitting PAUSE frames ONLY.
+ *
+ * LOCAL DEVICE | LINK PARTNER
+ * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
+ *-------|---------|-------|---------|--------------------
+ * 1 | 1 | 0 | 1 | em_fc_rx_pause
+ *
+ */
+ else if((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
+ (mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
+ !(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
+ (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
+ hw->fc = em_fc_rx_pause;
+ DEBUGOUT("Flow Control = RX PAUSE frames only.\r\n");
+ }
+ /* Per the IEEE spec, at this point flow control should be
+ * disabled. However, we want to consider that we could
+ * be connected to a legacy switch that doesn't advertise
+ * desired flow control, but can be forced on the link
+ * partner. So if we advertised no flow control, that is
+ * what we will resolve to. If we advertised some kind of
+ * receive capability (Rx Pause Only or Full Flow Control)
+ * and the link partner advertised none, we will configure
+ * ourselves to enable Rx Flow Control only. We can do
+ * this safely for two reasons: If the link partner really
+ * didn't want flow control enabled, and we enable Rx, no
+ * harm done since we won't be receiving any PAUSE frames
+ * anyway. If the intent on the link partner was to have
+ * flow control enabled, then by us enabling RX only, we
+ * can at least receive pause frames and process them.
+ * This is a good idea because in most cases, since we are
+ * predominantly a server NIC, more times than not we will
+ * be asked to delay transmission of packets than asking
+ * our link partner to pause transmission of frames.
+ */
+ else if((hw->original_fc == em_fc_none ||
+ hw->original_fc == em_fc_tx_pause) ||
+ hw->fc_strict_ieee) {
+ hw->fc = em_fc_none;
+ DEBUGOUT("Flow Control = NONE.\r\n");
+ } else {
+ hw->fc = em_fc_rx_pause;
+ DEBUGOUT("Flow Control = RX PAUSE frames only.\r\n");
+ }
+
+ /* Now we need to do one last check... If we auto-
+ * negotiated to HALF DUPLEX, flow control should not be
+ * enabled per IEEE 802.3 spec.
+ */
+ ret_val = em_get_speed_and_duplex(hw, &speed, &duplex);
+ if(ret_val) {
+ DEBUGOUT("Error getting link speed and duplex\n");
+ return ret_val;
+ }
+
+ if(duplex == HALF_DUPLEX)
+ hw->fc = em_fc_none;
+
+ /* Now we call a subroutine to actually force the MAC
+ * controller to use the correct flow control settings.
+ */
+ ret_val = em_force_mac_fc(hw);
+ if(ret_val) {
+ DEBUGOUT("Error forcing flow control settings\n");
+ return ret_val;
+ }
+ } else {
+ DEBUGOUT("Copper PHY and Auto Neg has not completed.\r\n");
+ }
+ }
+ return E1000_SUCCESS;
+}
+
+/******************************************************************************
+ * Checks to see if the link status of the hardware has changed.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *
+ * Called by any function that needs to check the link status of the adapter.
+ *****************************************************************************/
+int32_t
+em_check_for_link(struct em_hw *hw)
+{
+ uint32_t rxcw = 0;
+ uint32_t ctrl;
+ uint32_t status;
+ uint32_t rctl;
+ uint32_t icr;
+ uint32_t signal = 0;
+ int32_t ret_val;
+ uint16_t phy_data;
+
+ DEBUGFUNC("em_check_for_link");
+
+ ctrl = E1000_READ_REG(hw, CTRL);
+ status = E1000_READ_REG(hw, STATUS);
+
+ /* On adapters with a MAC newer than 82544, SW Defineable pin 1 will be
+ * set when the optics detect a signal. On older adapters, it will be
+ * cleared when there is a signal. This applies to fiber media only.
+ */
+ if((hw->media_type == em_media_type_fiber) ||
+ (hw->media_type == em_media_type_internal_serdes)) {
+ rxcw = E1000_READ_REG(hw, RXCW);
+
+ if(hw->media_type == em_media_type_fiber) {
+ signal = (hw->mac_type > em_82544) ? E1000_CTRL_SWDPIN1 : 0;
+ if(status & E1000_STATUS_LU)
+ hw->get_link_status = FALSE;
+ }
+ }
+
+ /* If we have a copper PHY then we only want to go out to the PHY
+ * registers to see if Auto-Neg has completed and/or if our link
+ * status has changed. The get_link_status flag will be set if we
+ * receive a Link Status Change interrupt or we have Rx Sequence
+ * Errors.
+ */
+ if((hw->media_type == em_media_type_copper) && hw->get_link_status) {
+ /* First we want to see if the MII Status Register reports
+ * link. If so, then we want to get the current speed/duplex
+ * of the PHY.
+ * Read the register twice since the link bit is sticky.
+ */
+ ret_val = em_read_phy_reg(hw, PHY_STATUS, &phy_data);
+ if(ret_val)
+ return ret_val;
+ ret_val = em_read_phy_reg(hw, PHY_STATUS, &phy_data);
+ if(ret_val)
+ return ret_val;
+
+ if(phy_data & MII_SR_LINK_STATUS) {
+ hw->get_link_status = FALSE;
+ /* Check if there was DownShift, must be checked immediately after
+ * link-up */
+ em_check_downshift(hw);
+
+ /* If we are on 82544 or 82543 silicon and speed/duplex
+ * are forced to 10H or 10F, then we will implement the polarity
+ * reversal workaround. We disable interrupts first, and upon
+ * returning, place the devices interrupt state to its previous
+ * value except for the link status change interrupt which will
+ * happen due to the execution of this workaround.
+ */
+
+ if((hw->mac_type == em_82544 || hw->mac_type == em_82543) &&
+ (!hw->autoneg) &&
+ (hw->forced_speed_duplex == em_10_full ||
+ hw->forced_speed_duplex == em_10_half)) {
+ E1000_WRITE_REG(hw, IMC, 0xffffffff);
+ ret_val = em_polarity_reversal_workaround(hw);
+ icr = E1000_READ_REG(hw, ICR);
+ E1000_WRITE_REG(hw, ICS, (icr & ~E1000_ICS_LSC));
+ E1000_WRITE_REG(hw, IMS, IMS_ENABLE_MASK);
+ }
+
+ } else {
+ /* No link detected */
+ em_config_dsp_after_link_change(hw, FALSE);
+ return 0;
+ }
+
+ /* If we are forcing speed/duplex, then we simply return since
+ * we have already determined whether we have link or not.
+ */
+ if(!hw->autoneg) return -E1000_ERR_CONFIG;
+
+ /* optimize the dsp settings for the igp phy */
+ em_config_dsp_after_link_change(hw, TRUE);
+
+ /* We have a M88E1000 PHY and Auto-Neg is enabled. If we
+ * have Si on board that is 82544 or newer, Auto
+ * Speed Detection takes care of MAC speed/duplex
+ * configuration. So we only need to configure Collision
+ * Distance in the MAC. Otherwise, we need to force
+ * speed/duplex on the MAC to the current PHY speed/duplex
+ * settings.
+ */
+ if(hw->mac_type >= em_82544)
+ em_config_collision_dist(hw);
+ else {
+ ret_val = em_config_mac_to_phy(hw);
+ if(ret_val) {
+ DEBUGOUT("Error configuring MAC to PHY settings\n");
+ return ret_val;
+ }
+ }
+
+ /* Configure Flow Control now that Auto-Neg has completed. First, we
+ * need to restore the desired flow control settings because we may
+ * have had to re-autoneg with a different link partner.
+ */
+ ret_val = em_config_fc_after_link_up(hw);
+ if(ret_val) {
+ DEBUGOUT("Error configuring flow control\n");
+ return ret_val;
+ }
+
+ /* At this point we know that we are on copper and we have
+ * auto-negotiated link. These are conditions for checking the link
+ * partner capability register. We use the link speed to determine if
+ * TBI compatibility needs to be turned on or off. If the link is not
+ * at gigabit speed, then TBI compatibility is not needed. If we are
+ * at gigabit speed, we turn on TBI compatibility.
+ */
+ if(hw->tbi_compatibility_en) {
+ uint16_t speed, duplex;
+ em_get_speed_and_duplex(hw, &speed, &duplex);
+ if(speed != SPEED_1000) {
+ /* If link speed is not set to gigabit speed, we do not need
+ * to enable TBI compatibility.
+ */
+ if(hw->tbi_compatibility_on) {
+ /* If we previously were in the mode, turn it off. */
+ rctl = E1000_READ_REG(hw, RCTL);
+ rctl &= ~E1000_RCTL_SBP;
+ E1000_WRITE_REG(hw, RCTL, rctl);
+ hw->tbi_compatibility_on = FALSE;
+ }
+ } else {
+ /* If TBI compatibility is was previously off, turn it on. For
+ * compatibility with a TBI link partner, we will store bad
+ * packets. Some frames have an additional byte on the end and
+ * will look like CRC errors to to the hardware.
+ */
+ if(!hw->tbi_compatibility_on) {
+ hw->tbi_compatibility_on = TRUE;
+ rctl = E1000_READ_REG(hw, RCTL);
+ rctl |= E1000_RCTL_SBP;
+ E1000_WRITE_REG(hw, RCTL, rctl);
+ }
+ }
+ }
+ }
+ /* If we don't have link (auto-negotiation failed or link partner cannot
+ * auto-negotiate), the cable is plugged in (we have signal), and our
+ * link partner is not trying to auto-negotiate with us (we are receiving
+ * idles or data), we need to force link up. We also need to give
+ * auto-negotiation time to complete, in case the cable was just plugged
+ * in. The autoneg_failed flag does this.
+ */
+ else if((((hw->media_type == em_media_type_fiber) &&
+ ((ctrl & E1000_CTRL_SWDPIN1) == signal)) ||
+ (hw->media_type == em_media_type_internal_serdes)) &&
+ (!(status & E1000_STATUS_LU)) &&
+ (!(rxcw & E1000_RXCW_C))) {
+ if(hw->autoneg_failed == 0) {
+ hw->autoneg_failed = 1;
+ return 0;
+ }
+ DEBUGOUT("NOT RXing /C/, disable AutoNeg and force link.\r\n");
+
+ /* Disable auto-negotiation in the TXCW register */
+ E1000_WRITE_REG(hw, TXCW, (hw->txcw & ~E1000_TXCW_ANE));
+
+ /* Force link-up and also force full-duplex. */
+ ctrl = E1000_READ_REG(hw, CTRL);
+ ctrl |= (E1000_CTRL_SLU | E1000_CTRL_FD);
+ E1000_WRITE_REG(hw, CTRL, ctrl);
+
+ /* Configure Flow Control after forcing link up. */
+ ret_val = em_config_fc_after_link_up(hw);
+ if(ret_val) {
+ DEBUGOUT("Error configuring flow control\n");
+ return ret_val;
+ }
+ }
+ /* If we are forcing link and we are receiving /C/ ordered sets, re-enable
+ * auto-negotiation in the TXCW register and disable forced link in the
+ * Device Control register in an attempt to auto-negotiate with our link
+ * partner.
+ */
+ else if(((hw->media_type == em_media_type_fiber) ||
+ (hw->media_type == em_media_type_internal_serdes)) &&
+ (ctrl & E1000_CTRL_SLU) && (rxcw & E1000_RXCW_C)) {
+ DEBUGOUT("RXing /C/, enable AutoNeg and stop forcing link.\r\n");
+ E1000_WRITE_REG(hw, TXCW, hw->txcw);
+ E1000_WRITE_REG(hw, CTRL, (ctrl & ~E1000_CTRL_SLU));
+
+ hw->serdes_link_down = FALSE;
+ }
+ /* If we force link for non-auto-negotiation switch, check link status
+ * based on MAC synchronization for internal serdes media type.
+ */
+ else if((hw->media_type == em_media_type_internal_serdes) &&
+ !(E1000_TXCW_ANE & E1000_READ_REG(hw, TXCW))) {
+ /* SYNCH bit and IV bit are sticky. */
+ usec_delay(10);
+ if(E1000_RXCW_SYNCH & E1000_READ_REG(hw, RXCW)) {
+ if(!(rxcw & E1000_RXCW_IV)) {
+ hw->serdes_link_down = FALSE;
+ DEBUGOUT("SERDES: Link is up.\n");
+ }
+ } else {
+ hw->serdes_link_down = TRUE;
+ DEBUGOUT("SERDES: Link is down.\n");
+ }
+ }
+ if((hw->media_type == em_media_type_internal_serdes) &&
+ (E1000_TXCW_ANE & E1000_READ_REG(hw, TXCW))) {
+ hw->serdes_link_down = !(E1000_STATUS_LU & E1000_READ_REG(hw, STATUS));
+ }
+ return E1000_SUCCESS;
+}
+
+/******************************************************************************
+ * Detects the current speed and duplex settings of the hardware.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * speed - Speed of the connection
+ * duplex - Duplex setting of the connection
+ *****************************************************************************/
+int32_t
+em_get_speed_and_duplex(struct em_hw *hw,
+ uint16_t *speed,
+ uint16_t *duplex)
+{
+ uint32_t status;
+ int32_t ret_val;
+ uint16_t phy_data;
+
+ DEBUGFUNC("em_get_speed_and_duplex");
+
+ if(hw->mac_type >= em_82543) {
+ status = E1000_READ_REG(hw, STATUS);
+ if(status & E1000_STATUS_SPEED_1000) {
+ *speed = SPEED_1000;
+ DEBUGOUT("1000 Mbs, ");
+ } else if(status & E1000_STATUS_SPEED_100) {
+ *speed = SPEED_100;
+ DEBUGOUT("100 Mbs, ");
+ } else {
+ *speed = SPEED_10;
+ DEBUGOUT("10 Mbs, ");
+ }
+
+ if(status & E1000_STATUS_FD) {
+ *duplex = FULL_DUPLEX;
+ DEBUGOUT("Full Duplex\r\n");
+ } else {
+ *duplex = HALF_DUPLEX;
+ DEBUGOUT(" Half Duplex\r\n");
+ }
+ } else {
+ DEBUGOUT("1000 Mbs, Full Duplex\r\n");
+ *speed = SPEED_1000;
+ *duplex = FULL_DUPLEX;
+ }
+
+ /* IGP01 PHY may advertise full duplex operation after speed downgrade even
+ * if it is operating at half duplex. Here we set the duplex settings to
+ * match the duplex in the link partner's capabilities.
+ */
+ if(hw->phy_type == em_phy_igp && hw->speed_downgraded) {
+ ret_val = em_read_phy_reg(hw, PHY_AUTONEG_EXP, &phy_data);
+ if(ret_val)
+ return ret_val;
+
+ if(!(phy_data & NWAY_ER_LP_NWAY_CAPS))
+ *duplex = HALF_DUPLEX;
+ else {
+ ret_val = em_read_phy_reg(hw, PHY_LP_ABILITY, &phy_data);
+ if(ret_val)
+ return ret_val;
+ if((*speed == SPEED_100 && !(phy_data & NWAY_LPAR_100TX_FD_CAPS)) ||
+ (*speed == SPEED_10 && !(phy_data & NWAY_LPAR_10T_FD_CAPS)))
+ *duplex = HALF_DUPLEX;
+ }
+ }
+
+ return E1000_SUCCESS;
+}
+
+/******************************************************************************
+* Blocks until autoneg completes or times out (~4.5 seconds)
+*
+* hw - Struct containing variables accessed by shared code
+******************************************************************************/
+int32_t
+em_wait_autoneg(struct em_hw *hw)
+{
+ int32_t ret_val;
+ uint16_t i;
+ uint16_t phy_data;
+
+ DEBUGFUNC("em_wait_autoneg");
+ DEBUGOUT("Waiting for Auto-Neg to complete.\n");
+
+ /* We will wait for autoneg to complete or 4.5 seconds to expire. */
+ for(i = PHY_AUTO_NEG_TIME; i > 0; i--) {
+ /* Read the MII Status Register and wait for Auto-Neg
+ * Complete bit to be set.
+ */
+ ret_val = em_read_phy_reg(hw, PHY_STATUS, &phy_data);
+ if(ret_val)
+ return ret_val;
+ ret_val = em_read_phy_reg(hw, PHY_STATUS, &phy_data);
+ if(ret_val)
+ return ret_val;
+ if(phy_data & MII_SR_AUTONEG_COMPLETE) {
+ return E1000_SUCCESS;
+ }
+ msec_delay(100);
+ }
+ return E1000_SUCCESS;
+}
+
+/******************************************************************************
+* Raises the Management Data Clock
+*
+* hw - Struct containing variables accessed by shared code
+* ctrl - Device control register's current value
+******************************************************************************/
+static void
+em_raise_mdi_clk(struct em_hw *hw,
+ uint32_t *ctrl)
+{
+ /* Raise the clock input to the Management Data Clock (by setting the MDC
+ * bit), and then delay 10 microseconds.
+ */
+ E1000_WRITE_REG(hw, CTRL, (*ctrl | E1000_CTRL_MDC));
+ E1000_WRITE_FLUSH(hw);
+ usec_delay(10);
+}
+
+/******************************************************************************
+* Lowers the Management Data Clock
+*
+* hw - Struct containing variables accessed by shared code
+* ctrl - Device control register's current value
+******************************************************************************/
+static void
+em_lower_mdi_clk(struct em_hw *hw,
+ uint32_t *ctrl)
+{
+ /* Lower the clock input to the Management Data Clock (by clearing the MDC
+ * bit), and then delay 10 microseconds.
+ */
+ E1000_WRITE_REG(hw, CTRL, (*ctrl & ~E1000_CTRL_MDC));
+ E1000_WRITE_FLUSH(hw);
+ usec_delay(10);
+}
+
+/******************************************************************************
+* Shifts data bits out to the PHY
+*
+* hw - Struct containing variables accessed by shared code
+* data - Data to send out to the PHY
+* count - Number of bits to shift out
+*
+* Bits are shifted out in MSB to LSB order.
+******************************************************************************/
+static void
+em_shift_out_mdi_bits(struct em_hw *hw,
+ uint32_t data,
+ uint16_t count)
+{
+ uint32_t ctrl;
+ uint32_t mask;
+
+ /* We need to shift "count" number of bits out to the PHY. So, the value
+ * in the "data" parameter will be shifted out to the PHY one bit at a
+ * time. In order to do this, "data" must be broken down into bits.
+ */
+ mask = 0x01;
+ mask <<= (count - 1);
+
+ ctrl = E1000_READ_REG(hw, CTRL);
+
+ /* Set MDIO_DIR and MDC_DIR direction bits to be used as output pins. */
+ ctrl |= (E1000_CTRL_MDIO_DIR | E1000_CTRL_MDC_DIR);
+
+ while(mask) {
+ /* A "1" is shifted out to the PHY by setting the MDIO bit to "1" and
+ * then raising and lowering the Management Data Clock. A "0" is
+ * shifted out to the PHY by setting the MDIO bit to "0" and then
+ * raising and lowering the clock.
+ */
+ if(data & mask) ctrl |= E1000_CTRL_MDIO;
+ else ctrl &= ~E1000_CTRL_MDIO;
+
+ E1000_WRITE_REG(hw, CTRL, ctrl);
+ E1000_WRITE_FLUSH(hw);
+
+ usec_delay(10);
+
+ em_raise_mdi_clk(hw, &ctrl);
+ em_lower_mdi_clk(hw, &ctrl);
+
+ mask = mask >> 1;
+ }
+}
+
+/******************************************************************************
+* Shifts data bits in from the PHY
+*
+* hw - Struct containing variables accessed by shared code
+*
+* Bits are shifted in in MSB to LSB order.
+******************************************************************************/
+static uint16_t
+em_shift_in_mdi_bits(struct em_hw *hw)
+{
+ uint32_t ctrl;
+ uint16_t data = 0;
+ uint8_t i;
+
+ /* In order to read a register from the PHY, we need to shift in a total
+ * of 18 bits from the PHY. The first two bit (turnaround) times are used
+ * to avoid contention on the MDIO pin when a read operation is performed.
+ * These two bits are ignored by us and thrown away. Bits are "shifted in"
+ * by raising the input to the Management Data Clock (setting the MDC bit),
+ * and then reading the value of the MDIO bit.
+ */
+ ctrl = E1000_READ_REG(hw, CTRL);
+
+ /* Clear MDIO_DIR (SWDPIO1) to indicate this bit is to be used as input. */
+ ctrl &= ~E1000_CTRL_MDIO_DIR;
+ ctrl &= ~E1000_CTRL_MDIO;
+
+ E1000_WRITE_REG(hw, CTRL, ctrl);
+ E1000_WRITE_FLUSH(hw);
+
+ /* Raise and Lower the clock before reading in the data. This accounts for
+ * the turnaround bits. The first clock occurred when we clocked out the
+ * last bit of the Register Address.
+ */
+ em_raise_mdi_clk(hw, &ctrl);
+ em_lower_mdi_clk(hw, &ctrl);
+
+ for(data = 0, i = 0; i < 16; i++) {
+ data = data << 1;
+ em_raise_mdi_clk(hw, &ctrl);
+ ctrl = E1000_READ_REG(hw, CTRL);
+ /* Check to see if we shifted in a "1". */
+ if(ctrl & E1000_CTRL_MDIO) data |= 1;
+ em_lower_mdi_clk(hw, &ctrl);
+ }
+
+ em_raise_mdi_clk(hw, &ctrl);
+ em_lower_mdi_clk(hw, &ctrl);
+
+ return data;
+}
+
+/*****************************************************************************
+* Reads the value from a PHY register, if the value is on a specific non zero
+* page, sets the page first.
+* hw - Struct containing variables accessed by shared code
+* reg_addr - address of the PHY register to read
+******************************************************************************/
+int32_t
+em_read_phy_reg(struct em_hw *hw,
+ uint32_t reg_addr,
+ uint16_t *phy_data)
+{
+ uint32_t ret_val;
+
+ DEBUGFUNC("em_read_phy_reg");
+
+ if((hw->phy_type == em_phy_igp ||
+ hw->phy_type == em_phy_igp_2) &&
+ (reg_addr > MAX_PHY_MULTI_PAGE_REG)) {
+ ret_val = em_write_phy_reg_ex(hw, IGP01E1000_PHY_PAGE_SELECT,
+ (uint16_t)reg_addr);
+ if(ret_val) {
+ return ret_val;
+ }
+ }
+
+ ret_val = em_read_phy_reg_ex(hw, MAX_PHY_REG_ADDRESS & reg_addr,
+ phy_data);
+
+ return ret_val;
+}
+
+int32_t
+em_read_phy_reg_ex(struct em_hw *hw,
+ uint32_t reg_addr,
+ uint16_t *phy_data)
+{
+ uint32_t i;
+ uint32_t mdic = 0;
+ const uint32_t phy_addr = 1;
+
+ DEBUGFUNC("em_read_phy_reg_ex");
+
+ if(reg_addr > MAX_PHY_REG_ADDRESS) {
+ DEBUGOUT1("PHY Address %d is out of range\n", reg_addr);
+ return -E1000_ERR_PARAM;
+ }
+
+ if(hw->mac_type > em_82543) {
+ /* Set up Op-code, Phy Address, and register address in the MDI
+ * Control register. The MAC will take care of interfacing with the
+ * PHY to retrieve the desired data.
+ */
+ mdic = ((reg_addr << E1000_MDIC_REG_SHIFT) |
+ (phy_addr << E1000_MDIC_PHY_SHIFT) |
+ (E1000_MDIC_OP_READ));
+
+ E1000_WRITE_REG(hw, MDIC, mdic);
+
+ /* Poll the ready bit to see if the MDI read completed */
+ for(i = 0; i < 64; i++) {
+ usec_delay(50);
+ mdic = E1000_READ_REG(hw, MDIC);
+ if(mdic & E1000_MDIC_READY) break;
+ }
+ if(!(mdic & E1000_MDIC_READY)) {
+ DEBUGOUT("MDI Read did not complete\n");
+ return -E1000_ERR_PHY;
+ }
+ if(mdic & E1000_MDIC_ERROR) {
+ DEBUGOUT("MDI Error\n");
+ return -E1000_ERR_PHY;
+ }
+ *phy_data = (uint16_t) mdic;
+ } else {
+ /* We must first send a preamble through the MDIO pin to signal the
+ * beginning of an MII instruction. This is done by sending 32
+ * consecutive "1" bits.
+ */
+ em_shift_out_mdi_bits(hw, PHY_PREAMBLE, PHY_PREAMBLE_SIZE);
+
+ /* Now combine the next few fields that are required for a read
+ * operation. We use this method instead of calling the
+ * em_shift_out_mdi_bits routine five different times. The format of
+ * a MII read instruction consists of a shift out of 14 bits and is
+ * defined as follows:
+ * <Preamble><SOF><Op Code><Phy Addr><Reg Addr>
+ * followed by a shift in of 18 bits. This first two bits shifted in
+ * are TurnAround bits used to avoid contention on the MDIO pin when a
+ * READ operation is performed. These two bits are thrown away
+ * followed by a shift in of 16 bits which contains the desired data.
+ */
+ mdic = ((reg_addr) | (phy_addr << 5) |
+ (PHY_OP_READ << 10) | (PHY_SOF << 12));
+
+ em_shift_out_mdi_bits(hw, mdic, 14);
+
+ /* Now that we've shifted out the read command to the MII, we need to
+ * "shift in" the 16-bit value (18 total bits) of the requested PHY
+ * register address.
+ */
+ *phy_data = em_shift_in_mdi_bits(hw);
+ }
+ return E1000_SUCCESS;
+}
+
+/******************************************************************************
+* Writes a value to a PHY register
+*
+* hw - Struct containing variables accessed by shared code
+* reg_addr - address of the PHY register to write
+* data - data to write to the PHY
+******************************************************************************/
+int32_t
+em_write_phy_reg(struct em_hw *hw,
+ uint32_t reg_addr,
+ uint16_t phy_data)
+{
+ uint32_t ret_val;
+
+ DEBUGFUNC("em_write_phy_reg");
+
+ if((hw->phy_type == em_phy_igp ||
+ hw->phy_type == em_phy_igp_2) &&
+ (reg_addr > MAX_PHY_MULTI_PAGE_REG)) {
+ ret_val = em_write_phy_reg_ex(hw, IGP01E1000_PHY_PAGE_SELECT,
+ (uint16_t)reg_addr);
+ if(ret_val) {
+ return ret_val;
+ }
+ }
+
+ ret_val = em_write_phy_reg_ex(hw, MAX_PHY_REG_ADDRESS & reg_addr,
+ phy_data);
+
+ return ret_val;
+}
+
+int32_t
+em_write_phy_reg_ex(struct em_hw *hw,
+ uint32_t reg_addr,
+ uint16_t phy_data)
+{
+ uint32_t i;
+ uint32_t mdic = 0;
+ const uint32_t phy_addr = 1;
+
+ DEBUGFUNC("em_write_phy_reg_ex");
+
+ if(reg_addr > MAX_PHY_REG_ADDRESS) {
+ DEBUGOUT1("PHY Address %d is out of range\n", reg_addr);
+ return -E1000_ERR_PARAM;
+ }
+
+ if(hw->mac_type > em_82543) {
+ /* Set up Op-code, Phy Address, register address, and data intended
+ * for the PHY register in the MDI Control register. The MAC will take
+ * care of interfacing with the PHY to send the desired data.
+ */
+ mdic = (((uint32_t) phy_data) |
+ (reg_addr << E1000_MDIC_REG_SHIFT) |
+ (phy_addr << E1000_MDIC_PHY_SHIFT) |
+ (E1000_MDIC_OP_WRITE));
+
+ E1000_WRITE_REG(hw, MDIC, mdic);
+
+ /* Poll the ready bit to see if the MDI read completed */
+ for(i = 0; i < 640; i++) {
+ usec_delay(5);
+ mdic = E1000_READ_REG(hw, MDIC);
+ if(mdic & E1000_MDIC_READY) break;
+ }
+ if(!(mdic & E1000_MDIC_READY)) {
+ DEBUGOUT("MDI Write did not complete\n");
+ return -E1000_ERR_PHY;
+ }
+ } else {
+ /* We'll need to use the SW defined pins to shift the write command
+ * out to the PHY. We first send a preamble to the PHY to signal the
+ * beginning of the MII instruction. This is done by sending 32
+ * consecutive "1" bits.
+ */
+ em_shift_out_mdi_bits(hw, PHY_PREAMBLE, PHY_PREAMBLE_SIZE);
+
+ /* Now combine the remaining required fields that will indicate a
+ * write operation. We use this method instead of calling the
+ * em_shift_out_mdi_bits routine for each field in the command. The
+ * format of a MII write instruction is as follows:
+ * <Preamble><SOF><Op Code><Phy Addr><Reg Addr><Turnaround><Data>.
+ */
+ mdic = ((PHY_TURNAROUND) | (reg_addr << 2) | (phy_addr << 7) |
+ (PHY_OP_WRITE << 12) | (PHY_SOF << 14));
+ mdic <<= 16;
+ mdic |= (uint32_t) phy_data;
+
+ em_shift_out_mdi_bits(hw, mdic, 32);
+ }
+
+ return E1000_SUCCESS;
+}
+
+
+/******************************************************************************
+* Returns the PHY to the power-on reset state
+*
+* hw - Struct containing variables accessed by shared code
+******************************************************************************/
+int32_t
+em_phy_hw_reset(struct em_hw *hw)
+{
+ uint32_t ctrl, ctrl_ext;
+ uint32_t led_ctrl;
+ int32_t ret_val;
+
+ DEBUGFUNC("em_phy_hw_reset");
+
+ /* In the case of the phy reset being blocked, it's not an error, we
+ * simply return success without performing the reset. */
+ ret_val = em_check_phy_reset_block(hw);
+ if (ret_val)
+ return E1000_SUCCESS;
+
+ DEBUGOUT("Resetting Phy...\n");
+
+ if(hw->mac_type > em_82543) {
+ /* Read the device control register and assert the E1000_CTRL_PHY_RST
+ * bit. Then, take it out of reset.
+ */
+ ctrl = E1000_READ_REG(hw, CTRL);
+ E1000_WRITE_REG(hw, CTRL, ctrl | E1000_CTRL_PHY_RST);
+ E1000_WRITE_FLUSH(hw);
+ msec_delay(10);
+ E1000_WRITE_REG(hw, CTRL, ctrl);
+ E1000_WRITE_FLUSH(hw);
+ } else {
+ /* Read the Extended Device Control Register, assert the PHY_RESET_DIR
+ * bit to put the PHY into reset. Then, take it out of reset.
+ */
+ ctrl_ext = E1000_READ_REG(hw, CTRL_EXT);
+ ctrl_ext |= E1000_CTRL_EXT_SDP4_DIR;
+ ctrl_ext &= ~E1000_CTRL_EXT_SDP4_DATA;
+ E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext);
+ E1000_WRITE_FLUSH(hw);
+ msec_delay(10);
+ ctrl_ext |= E1000_CTRL_EXT_SDP4_DATA;
+ E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext);
+ E1000_WRITE_FLUSH(hw);
+ }
+ usec_delay(150);
+
+ if((hw->mac_type == em_82541) || (hw->mac_type == em_82547)) {
+ /* Configure activity LED after PHY reset */
+ led_ctrl = E1000_READ_REG(hw, LEDCTL);
+ led_ctrl &= IGP_ACTIVITY_LED_MASK;
+ led_ctrl |= (IGP_ACTIVITY_LED_ENABLE | IGP_LED3_MODE);
+ E1000_WRITE_REG(hw, LEDCTL, led_ctrl);
+ }
+
+ /* Wait for FW to finish PHY configuration. */
+ ret_val = em_get_phy_cfg_done(hw);
+
+ return ret_val;
+}
+
+/******************************************************************************
+* Resets the PHY
+*
+* hw - Struct containing variables accessed by shared code
+*
+* Sets bit 15 of the MII Control regiser
+******************************************************************************/
+int32_t
+em_phy_reset(struct em_hw *hw)
+{
+ int32_t ret_val;
+ uint16_t phy_data;
+
+ DEBUGFUNC("em_phy_reset");
+
+ /* In the case of the phy reset being blocked, it's not an error, we
+ * simply return success without performing the reset. */
+ ret_val = em_check_phy_reset_block(hw);
+ if (ret_val)
+ return E1000_SUCCESS;
+
+ switch (hw->mac_type) {
+ case em_82541_rev_2:
+ ret_val = em_phy_hw_reset(hw);
+ if(ret_val)
+ return ret_val;
+ break;
+ default:
+ ret_val = em_read_phy_reg(hw, PHY_CTRL, &phy_data);
+ if(ret_val)
+ return ret_val;
+
+ phy_data |= MII_CR_RESET;
+ ret_val = em_write_phy_reg(hw, PHY_CTRL, phy_data);
+ if(ret_val)
+ return ret_val;
+
+ usec_delay(1);
+ break;
+ }
+
+ if(hw->phy_type == em_phy_igp || hw->phy_type == em_phy_igp_2)
+ em_phy_init_script(hw);
+
+ return E1000_SUCCESS;
+}
+
+/******************************************************************************
+* Probes the expected PHY address for known PHY IDs
+*
+* hw - Struct containing variables accessed by shared code
+******************************************************************************/
+int32_t
+em_detect_gig_phy(struct em_hw *hw)
+{
+ int32_t phy_init_status, ret_val;
+ uint16_t phy_id_high, phy_id_low;
+ boolean_t match = FALSE;
+
+ DEBUGFUNC("em_detect_gig_phy");
+
+ /* Read the PHY ID Registers to identify which PHY is onboard. */
+ ret_val = em_read_phy_reg(hw, PHY_ID1, &phy_id_high);
+ if(ret_val)
+ return ret_val;
+
+ hw->phy_id = (uint32_t) (phy_id_high << 16);
+ usec_delay(20);
+ ret_val = em_read_phy_reg(hw, PHY_ID2, &phy_id_low);
+ if(ret_val)
+ return ret_val;
+
+ hw->phy_id |= (uint32_t) (phy_id_low & PHY_REVISION_MASK);
+ hw->phy_revision = (uint32_t) phy_id_low & ~PHY_REVISION_MASK;
+
+ switch(hw->mac_type) {
+ case em_82543:
+ if(hw->phy_id == M88E1000_E_PHY_ID) match = TRUE;
+ break;
+ case em_82544:
+ if(hw->phy_id == M88E1000_I_PHY_ID) match = TRUE;
+ break;
+ case em_82540:
+ case em_82545:
+ case em_82545_rev_3:
+ case em_82546:
+ case em_82546_rev_3:
+ if(hw->phy_id == M88E1011_I_PHY_ID) match = TRUE;
+ break;
+ case em_82541:
+ case em_82541_rev_2:
+ case em_82547:
+ case em_82547_rev_2:
+ if(hw->phy_id == IGP01E1000_I_PHY_ID) match = TRUE;
+ break;
+ case em_82573:
+ if(hw->phy_id == M88E1111_I_PHY_ID) match = TRUE;
+ break;
+ default:
+ DEBUGOUT1("Invalid MAC type %d\n", hw->mac_type);
+ return -E1000_ERR_CONFIG;
+ }
+ phy_init_status = em_set_phy_type(hw);
+
+ if ((match) && (phy_init_status == E1000_SUCCESS)) {
+ DEBUGOUT1("PHY ID 0x%X detected\n", hw->phy_id);
+ return E1000_SUCCESS;
+ }
+ DEBUGOUT1("Invalid PHY ID 0x%X\n", hw->phy_id);
+ return -E1000_ERR_PHY;
+}
+
+/******************************************************************************
+* Resets the PHY's DSP
+*
+* hw - Struct containing variables accessed by shared code
+******************************************************************************/
+static int32_t
+em_phy_reset_dsp(struct em_hw *hw)
+{
+ int32_t ret_val;
+ DEBUGFUNC("em_phy_reset_dsp");
+
+ do {
+ ret_val = em_write_phy_reg(hw, 29, 0x001d);
+ if(ret_val) break;
+ ret_val = em_write_phy_reg(hw, 30, 0x00c1);
+ if(ret_val) break;
+ ret_val = em_write_phy_reg(hw, 30, 0x0000);
+ if(ret_val) break;
+ ret_val = E1000_SUCCESS;
+ } while(0);
+
+ return ret_val;
+}
+
+/******************************************************************************
+* Get PHY information from various PHY registers for igp PHY only.
+*
+* hw - Struct containing variables accessed by shared code
+* phy_info - PHY information structure
+******************************************************************************/
+int32_t
+em_phy_igp_get_info(struct em_hw *hw,
+ struct em_phy_info *phy_info)
+{
+ int32_t ret_val;
+ uint16_t phy_data, polarity, min_length, max_length, average;
+
+ DEBUGFUNC("em_phy_igp_get_info");
+
+ /* The downshift status is checked only once, after link is established,
+ * and it stored in the hw->speed_downgraded parameter. */
+ phy_info->downshift = (em_downshift)hw->speed_downgraded;
+
+ /* IGP01E1000 does not need to support it. */
+ phy_info->extended_10bt_distance = em_10bt_ext_dist_enable_normal;
+
+ /* IGP01E1000 always correct polarity reversal */
+ phy_info->polarity_correction = em_polarity_reversal_enabled;
+
+ /* Check polarity status */
+ ret_val = em_check_polarity(hw, &polarity);
+ if(ret_val)
+ return ret_val;
+
+ phy_info->cable_polarity = polarity;
+
+ ret_val = em_read_phy_reg(hw, IGP01E1000_PHY_PORT_STATUS, &phy_data);
+ if(ret_val)
+ return ret_val;
+
+ phy_info->mdix_mode = (phy_data & IGP01E1000_PSSR_MDIX) >>
+ IGP01E1000_PSSR_MDIX_SHIFT;
+
+ if((phy_data & IGP01E1000_PSSR_SPEED_MASK) ==
+ IGP01E1000_PSSR_SPEED_1000MBPS) {
+ /* Local/Remote Receiver Information are only valid at 1000 Mbps */
+ ret_val = em_read_phy_reg(hw, PHY_1000T_STATUS, &phy_data);
+ if(ret_val)
+ return ret_val;
+
+ phy_info->local_rx = (phy_data & SR_1000T_LOCAL_RX_STATUS) >>
+ SR_1000T_LOCAL_RX_STATUS_SHIFT;
+ phy_info->remote_rx = (phy_data & SR_1000T_REMOTE_RX_STATUS) >>
+ SR_1000T_REMOTE_RX_STATUS_SHIFT;
+
+ /* Get cable length */
+ ret_val = em_get_cable_length(hw, &min_length, &max_length);
+ if(ret_val)
+ return ret_val;
+
+ /* Translate to old method */
+ average = (max_length + min_length) / 2;
+
+ if(average <= em_igp_cable_length_50)
+ phy_info->cable_length = em_cable_length_50;
+ else if(average <= em_igp_cable_length_80)
+ phy_info->cable_length = em_cable_length_50_80;
+ else if(average <= em_igp_cable_length_110)
+ phy_info->cable_length = em_cable_length_80_110;
+ else if(average <= em_igp_cable_length_140)
+ phy_info->cable_length = em_cable_length_110_140;
+ else
+ phy_info->cable_length = em_cable_length_140;
+ }
+
+ return E1000_SUCCESS;
+}
+
+/******************************************************************************
+* Get PHY information from various PHY registers fot m88 PHY only.
+*
+* hw - Struct containing variables accessed by shared code
+* phy_info - PHY information structure
+******************************************************************************/
+int32_t
+em_phy_m88_get_info(struct em_hw *hw,
+ struct em_phy_info *phy_info)
+{
+ int32_t ret_val;
+ uint16_t phy_data, polarity;
+
+ DEBUGFUNC("em_phy_m88_get_info");
+
+ /* The downshift status is checked only once, after link is established,
+ * and it stored in the hw->speed_downgraded parameter. */
+ phy_info->downshift = (em_downshift)hw->speed_downgraded;
+
+ ret_val = em_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
+ if(ret_val)
+ return ret_val;
+
+ phy_info->extended_10bt_distance =
+ (phy_data & M88E1000_PSCR_10BT_EXT_DIST_ENABLE) >>
+ M88E1000_PSCR_10BT_EXT_DIST_ENABLE_SHIFT;
+ phy_info->polarity_correction =
+ (phy_data & M88E1000_PSCR_POLARITY_REVERSAL) >>
+ M88E1000_PSCR_POLARITY_REVERSAL_SHIFT;
+
+ /* Check polarity status */
+ ret_val = em_check_polarity(hw, &polarity);
+ if(ret_val)
+ return ret_val;
+ phy_info->cable_polarity = polarity;
+
+ ret_val = em_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data);
+ if(ret_val)
+ return ret_val;
+
+ phy_info->mdix_mode = (phy_data & M88E1000_PSSR_MDIX) >>
+ M88E1000_PSSR_MDIX_SHIFT;
+
+ if ((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS) {
+ /* Cable Length Estimation and Local/Remote Receiver Information
+ * are only valid at 1000 Mbps.
+ */
+ phy_info->cable_length = ((phy_data & M88E1000_PSSR_CABLE_LENGTH) >>
+ M88E1000_PSSR_CABLE_LENGTH_SHIFT);
+
+ ret_val = em_read_phy_reg(hw, PHY_1000T_STATUS, &phy_data);
+ if(ret_val)
+ return ret_val;
+
+ phy_info->local_rx = (phy_data & SR_1000T_LOCAL_RX_STATUS) >>
+ SR_1000T_LOCAL_RX_STATUS_SHIFT;
+
+ phy_info->remote_rx = (phy_data & SR_1000T_REMOTE_RX_STATUS) >>
+ SR_1000T_REMOTE_RX_STATUS_SHIFT;
+ }
+
+ return E1000_SUCCESS;
+}
+
+/******************************************************************************
+* Get PHY information from various PHY registers
+*
+* hw - Struct containing variables accessed by shared code
+* phy_info - PHY information structure
+******************************************************************************/
+int32_t
+em_phy_get_info(struct em_hw *hw,
+ struct em_phy_info *phy_info)
+{
+ int32_t ret_val;
+ uint16_t phy_data;
+
+ DEBUGFUNC("em_phy_get_info");
+
+ phy_info->cable_length = em_cable_length_undefined;
+ phy_info->extended_10bt_distance = em_10bt_ext_dist_enable_undefined;
+ phy_info->cable_polarity = em_rev_polarity_undefined;
+ phy_info->downshift = em_downshift_undefined;
+ phy_info->polarity_correction = em_polarity_reversal_undefined;
+ phy_info->mdix_mode = em_auto_x_mode_undefined;
+ phy_info->local_rx = em_1000t_rx_status_undefined;
+ phy_info->remote_rx = em_1000t_rx_status_undefined;
+
+ if(hw->media_type != em_media_type_copper) {
+ DEBUGOUT("PHY info is only valid for copper media\n");
+ return -E1000_ERR_CONFIG;
+ }
+
+ ret_val = em_read_phy_reg(hw, PHY_STATUS, &phy_data);
+ if(ret_val)
+ return ret_val;
+
+ ret_val = em_read_phy_reg(hw, PHY_STATUS, &phy_data);
+ if(ret_val)
+ return ret_val;
+
+ if((phy_data & MII_SR_LINK_STATUS) != MII_SR_LINK_STATUS) {
+ DEBUGOUT("PHY info is only valid if link is up\n");
+ return -E1000_ERR_CONFIG;
+ }
+
+ if(hw->phy_type == em_phy_igp ||
+ hw->phy_type == em_phy_igp_2)
+ return em_phy_igp_get_info(hw, phy_info);
+ else
+ return em_phy_m88_get_info(hw, phy_info);
+}
+
+int32_t
+em_validate_mdi_setting(struct em_hw *hw)
+{
+ DEBUGFUNC("em_validate_mdi_settings");
+
+ if(!hw->autoneg && (hw->mdix == 0 || hw->mdix == 3)) {
+ DEBUGOUT("Invalid MDI setting detected\n");
+ hw->mdix = 1;
+ return -E1000_ERR_CONFIG;
+ }
+ return E1000_SUCCESS;
+}
+
+
+/******************************************************************************
+ * Sets up eeprom variables in the hw struct. Must be called after mac_type
+ * is configured.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+int32_t
+em_init_eeprom_params(struct em_hw *hw)
+{
+ struct em_eeprom_info *eeprom = &hw->eeprom;
+ uint32_t eecd = E1000_READ_REG(hw, EECD);
+ int32_t ret_val = E1000_SUCCESS;
+ uint16_t eeprom_size;
+
+ DEBUGFUNC("em_init_eeprom_params");
+
+ switch (hw->mac_type) {
+ case em_82542_rev2_0:
+ case em_82542_rev2_1:
+ case em_82543:
+ case em_82544:
+ eeprom->type = em_eeprom_microwire;
+ eeprom->word_size = 64;
+ eeprom->opcode_bits = 3;
+ eeprom->address_bits = 6;
+ eeprom->delay_usec = 50;
+ eeprom->use_eerd = FALSE;
+ eeprom->use_eewr = FALSE;
+ break;
+ case em_82540:
+ case em_82545:
+ case em_82545_rev_3:
+ case em_82546:
+ case em_82546_rev_3:
+ eeprom->type = em_eeprom_microwire;
+ eeprom->opcode_bits = 3;
+ eeprom->delay_usec = 50;
+ if(eecd & E1000_EECD_SIZE) {
+ eeprom->word_size = 256;
+ eeprom->address_bits = 8;
+ } else {
+ eeprom->word_size = 64;
+ eeprom->address_bits = 6;
+ }
+ eeprom->use_eerd = FALSE;
+ eeprom->use_eewr = FALSE;
+ break;
+ case em_82541:
+ case em_82541_rev_2:
+ case em_82547:
+ case em_82547_rev_2:
+ if (eecd & E1000_EECD_TYPE) {
+ eeprom->type = em_eeprom_spi;
+ eeprom->opcode_bits = 8;
+ eeprom->delay_usec = 1;
+ if (eecd & E1000_EECD_ADDR_BITS) {
+ eeprom->page_size = 32;
+ eeprom->address_bits = 16;
+ } else {
+ eeprom->page_size = 8;
+ eeprom->address_bits = 8;
+ }
+ } else {
+ eeprom->type = em_eeprom_microwire;
+ eeprom->opcode_bits = 3;
+ eeprom->delay_usec = 50;
+ if (eecd & E1000_EECD_ADDR_BITS) {
+ eeprom->word_size = 256;
+ eeprom->address_bits = 8;
+ } else {
+ eeprom->word_size = 64;
+ eeprom->address_bits = 6;
+ }
+ }
+ eeprom->use_eerd = FALSE;
+ eeprom->use_eewr = FALSE;
+ break;
+ case em_82573:
+ eeprom->type = em_eeprom_spi;
+ eeprom->opcode_bits = 8;
+ eeprom->delay_usec = 1;
+ if (eecd & E1000_EECD_ADDR_BITS) {
+ eeprom->page_size = 32;
+ eeprom->address_bits = 16;
+ } else {
+ eeprom->page_size = 8;
+ eeprom->address_bits = 8;
+ }
+ eeprom->use_eerd = TRUE;
+ eeprom->use_eewr = TRUE;
+ if(em_is_onboard_nvm_eeprom(hw) == FALSE) {
+ eeprom->type = em_eeprom_flash;
+ eeprom->word_size = 2048;
+
+ /* Ensure that the Autonomous FLASH update bit is cleared due to
+ * Flash update issue on parts which use a FLASH for NVM. */
+ eecd &= ~E1000_EECD_AUPDEN;
+ E1000_WRITE_REG(hw, EECD, eecd);
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (eeprom->type == em_eeprom_spi) {
+ /* eeprom_size will be an enum [0..8] that maps to eeprom sizes 128B to
+ * 32KB (incremented by powers of 2).
+ */
+ if(hw->mac_type <= em_82547_rev_2) {
+ /* Set to default value for initial eeprom read. */
+ eeprom->word_size = 64;
+ ret_val = em_read_eeprom(hw, EEPROM_CFG, 1, &eeprom_size);
+ if(ret_val)
+ return ret_val;
+ eeprom_size = (eeprom_size & EEPROM_SIZE_MASK) >> EEPROM_SIZE_SHIFT;
+ /* 256B eeprom size was not supported in earlier hardware, so we
+ * bump eeprom_size up one to ensure that "1" (which maps to 256B)
+ * is never the result used in the shifting logic below. */
+ if(eeprom_size)
+ eeprom_size++;
+ } else {
+ eeprom_size = (uint16_t)((eecd & E1000_EECD_SIZE_EX_MASK) >>
+ E1000_EECD_SIZE_EX_SHIFT);
+ }
+
+ eeprom->word_size = 1 << (eeprom_size + EEPROM_WORD_SIZE_SHIFT);
+ }
+ return ret_val;
+}
+
+/******************************************************************************
+ * Raises the EEPROM's clock input.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * eecd - EECD's current value
+ *****************************************************************************/
+static void
+em_raise_ee_clk(struct em_hw *hw,
+ uint32_t *eecd)
+{
+ /* Raise the clock input to the EEPROM (by setting the SK bit), and then
+ * wait <delay> microseconds.
+ */
+ *eecd = *eecd | E1000_EECD_SK;
+ E1000_WRITE_REG(hw, EECD, *eecd);
+ E1000_WRITE_FLUSH(hw);
+ usec_delay(hw->eeprom.delay_usec);
+}
+
+/******************************************************************************
+ * Lowers the EEPROM's clock input.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * eecd - EECD's current value
+ *****************************************************************************/
+static void
+em_lower_ee_clk(struct em_hw *hw,
+ uint32_t *eecd)
+{
+ /* Lower the clock input to the EEPROM (by clearing the SK bit), and then
+ * wait 50 microseconds.
+ */
+ *eecd = *eecd & ~E1000_EECD_SK;
+ E1000_WRITE_REG(hw, EECD, *eecd);
+ E1000_WRITE_FLUSH(hw);
+ usec_delay(hw->eeprom.delay_usec);
+}
+
+/******************************************************************************
+ * Shift data bits out to the EEPROM.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * data - data to send to the EEPROM
+ * count - number of bits to shift out
+ *****************************************************************************/
+static void
+em_shift_out_ee_bits(struct em_hw *hw,
+ uint16_t data,
+ uint16_t count)
+{
+ struct em_eeprom_info *eeprom = &hw->eeprom;
+ uint32_t eecd;
+ uint32_t mask;
+
+ /* We need to shift "count" bits out to the EEPROM. So, value in the
+ * "data" parameter will be shifted out to the EEPROM one bit at a time.
+ * In order to do this, "data" must be broken down into bits.
+ */
+ mask = 0x01 << (count - 1);
+ eecd = E1000_READ_REG(hw, EECD);
+ if (eeprom->type == em_eeprom_microwire) {
+ eecd &= ~E1000_EECD_DO;
+ } else if (eeprom->type == em_eeprom_spi) {
+ eecd |= E1000_EECD_DO;
+ }
+ do {
+ /* A "1" is shifted out to the EEPROM by setting bit "DI" to a "1",
+ * and then raising and then lowering the clock (the SK bit controls
+ * the clock input to the EEPROM). A "0" is shifted out to the EEPROM
+ * by setting "DI" to "0" and then raising and then lowering the clock.
+ */
+ eecd &= ~E1000_EECD_DI;
+
+ if(data & mask)
+ eecd |= E1000_EECD_DI;
+
+ E1000_WRITE_REG(hw, EECD, eecd);
+ E1000_WRITE_FLUSH(hw);
+
+ usec_delay(eeprom->delay_usec);
+
+ em_raise_ee_clk(hw, &eecd);
+ em_lower_ee_clk(hw, &eecd);
+
+ mask = mask >> 1;
+
+ } while(mask);
+
+ /* We leave the "DI" bit set to "0" when we leave this routine. */
+ eecd &= ~E1000_EECD_DI;
+ E1000_WRITE_REG(hw, EECD, eecd);
+}
+
+/******************************************************************************
+ * Shift data bits in from the EEPROM
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+static uint16_t
+em_shift_in_ee_bits(struct em_hw *hw,
+ uint16_t count)
+{
+ uint32_t eecd;
+ uint32_t i;
+ uint16_t data;
+
+ /* In order to read a register from the EEPROM, we need to shift 'count'
+ * bits in from the EEPROM. Bits are "shifted in" by raising the clock
+ * input to the EEPROM (setting the SK bit), and then reading the value of
+ * the "DO" bit. During this "shifting in" process the "DI" bit should
+ * always be clear.
+ */
+
+ eecd = E1000_READ_REG(hw, EECD);
+
+ eecd &= ~(E1000_EECD_DO | E1000_EECD_DI);
+ data = 0;
+
+ for(i = 0; i < count; i++) {
+ data = data << 1;
+ em_raise_ee_clk(hw, &eecd);
+
+ eecd = E1000_READ_REG(hw, EECD);
+
+ eecd &= ~(E1000_EECD_DI);
+ if(eecd & E1000_EECD_DO)
+ data |= 1;
+
+ em_lower_ee_clk(hw, &eecd);
+ }
+
+ return data;
+}
+
+/******************************************************************************
+ * Prepares EEPROM for access
+ *
+ * hw - Struct containing variables accessed by shared code
+ *
+ * Lowers EEPROM clock. Clears input pin. Sets the chip select pin. This
+ * function should be called before issuing a command to the EEPROM.
+ *****************************************************************************/
+static int32_t
+em_acquire_eeprom(struct em_hw *hw)
+{
+ struct em_eeprom_info *eeprom = &hw->eeprom;
+ uint32_t eecd, i=0;
+
+ DEBUGFUNC("em_acquire_eeprom");
+
+ if(em_get_hw_eeprom_semaphore(hw))
+ return -E1000_ERR_EEPROM;
+
+ eecd = E1000_READ_REG(hw, EECD);
+
+ if (hw->mac_type != em_82573) {
+ /* Request EEPROM Access */
+ if(hw->mac_type > em_82544) {
+ eecd |= E1000_EECD_REQ;
+ E1000_WRITE_REG(hw, EECD, eecd);
+ eecd = E1000_READ_REG(hw, EECD);
+ while((!(eecd & E1000_EECD_GNT)) &&
+ (i < E1000_EEPROM_GRANT_ATTEMPTS)) {
+ i++;
+ usec_delay(5);
+ eecd = E1000_READ_REG(hw, EECD);
+ }
+ if(!(eecd & E1000_EECD_GNT)) {
+ eecd &= ~E1000_EECD_REQ;
+ E1000_WRITE_REG(hw, EECD, eecd);
+ DEBUGOUT("Could not acquire EEPROM grant\n");
+ return -E1000_ERR_EEPROM;
+ }
+ }
+ }
+
+ /* Setup EEPROM for Read/Write */
+
+ if (eeprom->type == em_eeprom_microwire) {
+ /* Clear SK and DI */
+ eecd &= ~(E1000_EECD_DI | E1000_EECD_SK);
+ E1000_WRITE_REG(hw, EECD, eecd);
+
+ /* Set CS */
+ eecd |= E1000_EECD_CS;
+ E1000_WRITE_REG(hw, EECD, eecd);
+ } else if (eeprom->type == em_eeprom_spi) {
+ /* Clear SK and CS */
+ eecd &= ~(E1000_EECD_CS | E1000_EECD_SK);
+ E1000_WRITE_REG(hw, EECD, eecd);
+ usec_delay(1);
+ }
+
+ return E1000_SUCCESS;
+}
+
+/******************************************************************************
+ * Returns EEPROM to a "standby" state
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+static void
+em_standby_eeprom(struct em_hw *hw)
+{
+ struct em_eeprom_info *eeprom = &hw->eeprom;
+ uint32_t eecd;
+
+ eecd = E1000_READ_REG(hw, EECD);
+
+ if(eeprom->type == em_eeprom_microwire) {
+ eecd &= ~(E1000_EECD_CS | E1000_EECD_SK);
+ E1000_WRITE_REG(hw, EECD, eecd);
+ E1000_WRITE_FLUSH(hw);
+ usec_delay(eeprom->delay_usec);
+
+ /* Clock high */
+ eecd |= E1000_EECD_SK;
+ E1000_WRITE_REG(hw, EECD, eecd);
+ E1000_WRITE_FLUSH(hw);
+ usec_delay(eeprom->delay_usec);
+
+ /* Select EEPROM */
+ eecd |= E1000_EECD_CS;
+ E1000_WRITE_REG(hw, EECD, eecd);
+ E1000_WRITE_FLUSH(hw);
+ usec_delay(eeprom->delay_usec);
+
+ /* Clock low */
+ eecd &= ~E1000_EECD_SK;
+ E1000_WRITE_REG(hw, EECD, eecd);
+ E1000_WRITE_FLUSH(hw);
+ usec_delay(eeprom->delay_usec);
+ } else if(eeprom->type == em_eeprom_spi) {
+ /* Toggle CS to flush commands */
+ eecd |= E1000_EECD_CS;
+ E1000_WRITE_REG(hw, EECD, eecd);
+ E1000_WRITE_FLUSH(hw);
+ usec_delay(eeprom->delay_usec);
+ eecd &= ~E1000_EECD_CS;
+ E1000_WRITE_REG(hw, EECD, eecd);
+ E1000_WRITE_FLUSH(hw);
+ usec_delay(eeprom->delay_usec);
+ }
+}
+
+/******************************************************************************
+ * Terminates a command by inverting the EEPROM's chip select pin
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+static void
+em_release_eeprom(struct em_hw *hw)
+{
+ uint32_t eecd;
+
+ DEBUGFUNC("em_release_eeprom");
+
+ eecd = E1000_READ_REG(hw, EECD);
+
+ if (hw->eeprom.type == em_eeprom_spi) {
+ eecd |= E1000_EECD_CS; /* Pull CS high */
+ eecd &= ~E1000_EECD_SK; /* Lower SCK */
+
+ E1000_WRITE_REG(hw, EECD, eecd);
+
+ usec_delay(hw->eeprom.delay_usec);
+ } else if(hw->eeprom.type == em_eeprom_microwire) {
+ /* cleanup eeprom */
+
+ /* CS on Microwire is active-high */
+ eecd &= ~(E1000_EECD_CS | E1000_EECD_DI);
+
+ E1000_WRITE_REG(hw, EECD, eecd);
+
+ /* Rising edge of clock */
+ eecd |= E1000_EECD_SK;
+ E1000_WRITE_REG(hw, EECD, eecd);
+ E1000_WRITE_FLUSH(hw);
+ usec_delay(hw->eeprom.delay_usec);
+
+ /* Falling edge of clock */
+ eecd &= ~E1000_EECD_SK;
+ E1000_WRITE_REG(hw, EECD, eecd);
+ E1000_WRITE_FLUSH(hw);
+ usec_delay(hw->eeprom.delay_usec);
+ }
+
+ /* Stop requesting EEPROM access */
+ if(hw->mac_type > em_82544) {
+ eecd &= ~E1000_EECD_REQ;
+ E1000_WRITE_REG(hw, EECD, eecd);
+ }
+
+ em_put_hw_eeprom_semaphore(hw);
+}
+
+/******************************************************************************
+ * Reads a 16 bit word from the EEPROM.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+int32_t
+em_spi_eeprom_ready(struct em_hw *hw)
+{
+ uint16_t retry_count = 0;
+ uint8_t spi_stat_reg;
+
+ DEBUGFUNC("em_spi_eeprom_ready");
+
+ /* Read "Status Register" repeatedly until the LSB is cleared. The
+ * EEPROM will signal that the command has been completed by clearing
+ * bit 0 of the internal status register. If it's not cleared within
+ * 5 milliseconds, then error out.
+ */
+ retry_count = 0;
+ do {
+ em_shift_out_ee_bits(hw, EEPROM_RDSR_OPCODE_SPI,
+ hw->eeprom.opcode_bits);
+ spi_stat_reg = (uint8_t)em_shift_in_ee_bits(hw, 8);
+ if (!(spi_stat_reg & EEPROM_STATUS_RDY_SPI))
+ break;
+
+ usec_delay(5);
+ retry_count += 5;
+
+ em_standby_eeprom(hw);
+ } while(retry_count < EEPROM_MAX_RETRY_SPI);
+
+ /* ATMEL SPI write time could vary from 0-20mSec on 3.3V devices (and
+ * only 0-5mSec on 5V devices)
+ */
+ if(retry_count >= EEPROM_MAX_RETRY_SPI) {
+ DEBUGOUT("SPI EEPROM Status error\n");
+ return -E1000_ERR_EEPROM;
+ }
+
+ return E1000_SUCCESS;
+}
+
+/******************************************************************************
+ * Reads a 16 bit word from the EEPROM.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * offset - offset of word in the EEPROM to read
+ * data - word read from the EEPROM
+ * words - number of words to read
+ *****************************************************************************/
+int32_t
+em_read_eeprom(struct em_hw *hw,
+ uint16_t offset,
+ uint16_t words,
+ uint16_t *data)
+{
+ struct em_eeprom_info *eeprom = &hw->eeprom;
+ uint32_t i = 0;
+ int32_t ret_val;
+
+ DEBUGFUNC("em_read_eeprom");
+
+ /* A check for invalid values: offset too large, too many words, and not
+ * enough words.
+ */
+ if((offset >= eeprom->word_size) || (words > eeprom->word_size - offset) ||
+ (words == 0)) {
+ DEBUGOUT("\"words\" parameter out of bounds\n");
+ return -E1000_ERR_EEPROM;
+ }
+
+ /* FLASH reads without acquiring the semaphore are safe in 82573-based
+ * controllers.
+ */
+ if ((em_is_onboard_nvm_eeprom(hw) == TRUE) ||
+ (hw->mac_type != em_82573)) {
+ /* Prepare the EEPROM for reading */
+ if(em_acquire_eeprom(hw) != E1000_SUCCESS)
+ return -E1000_ERR_EEPROM;
+ }
+
+ if(eeprom->use_eerd == TRUE) {
+ ret_val = em_read_eeprom_eerd(hw, offset, words, data);
+ if ((em_is_onboard_nvm_eeprom(hw) == TRUE) ||
+ (hw->mac_type != em_82573))
+ em_release_eeprom(hw);
+ return ret_val;
+ }
+
+ if(eeprom->type == em_eeprom_spi) {
+ uint16_t word_in;
+ uint8_t read_opcode = EEPROM_READ_OPCODE_SPI;
+
+ if(em_spi_eeprom_ready(hw)) {
+ em_release_eeprom(hw);
+ return -E1000_ERR_EEPROM;
+ }
+
+ em_standby_eeprom(hw);
+
+ /* Some SPI eeproms use the 8th address bit embedded in the opcode */
+ if((eeprom->address_bits == 8) && (offset >= 128))
+ read_opcode |= EEPROM_A8_OPCODE_SPI;
+
+ /* Send the READ command (opcode + addr) */
+ em_shift_out_ee_bits(hw, read_opcode, eeprom->opcode_bits);
+ em_shift_out_ee_bits(hw, (uint16_t)(offset*2), eeprom->address_bits);
+
+ /* Read the data. The address of the eeprom internally increments with
+ * each byte (spi) being read, saving on the overhead of eeprom setup
+ * and tear-down. The address counter will roll over if reading beyond
+ * the size of the eeprom, thus allowing the entire memory to be read
+ * starting from any offset. */
+ for (i = 0; i < words; i++) {
+ word_in = em_shift_in_ee_bits(hw, 16);
+ data[i] = (word_in >> 8) | (word_in << 8);
+ }
+ } else if(eeprom->type == em_eeprom_microwire) {
+ for (i = 0; i < words; i++) {
+ /* Send the READ command (opcode + addr) */
+ em_shift_out_ee_bits(hw, EEPROM_READ_OPCODE_MICROWIRE,
+ eeprom->opcode_bits);
+ em_shift_out_ee_bits(hw, (uint16_t)(offset + i),
+ eeprom->address_bits);
+
+ /* Read the data. For microwire, each word requires the overhead
+ * of eeprom setup and tear-down. */
+ data[i] = em_shift_in_ee_bits(hw, 16);
+ em_standby_eeprom(hw);
+ }
+ }
+
+ /* End this read operation */
+ em_release_eeprom(hw);
+
+ return E1000_SUCCESS;
+}
+
+/******************************************************************************
+ * Reads a 16 bit word from the EEPROM using the EERD register.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * offset - offset of word in the EEPROM to read
+ * data - word read from the EEPROM
+ * words - number of words to read
+ *****************************************************************************/
+int32_t
+em_read_eeprom_eerd(struct em_hw *hw,
+ uint16_t offset,
+ uint16_t words,
+ uint16_t *data)
+{
+ uint32_t i, eerd = 0;
+ int32_t error = 0;
+
+ for (i = 0; i < words; i++) {
+ eerd = ((offset+i) << E1000_EEPROM_RW_ADDR_SHIFT) +
+ E1000_EEPROM_RW_REG_START;
+
+ E1000_WRITE_REG(hw, EERD, eerd);
+ error = em_poll_eerd_eewr_done(hw, E1000_EEPROM_POLL_READ);
+
+ if(error) {
+ break;
+ }
+ data[i] = (E1000_READ_REG(hw, EERD) >> E1000_EEPROM_RW_REG_DATA);
+
+ }
+
+ return error;
+}
+
+/******************************************************************************
+ * Writes a 16 bit word from the EEPROM using the EEWR register.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * offset - offset of word in the EEPROM to read
+ * data - word read from the EEPROM
+ * words - number of words to read
+ *****************************************************************************/
+int32_t
+em_write_eeprom_eewr(struct em_hw *hw,
+ uint16_t offset,
+ uint16_t words,
+ uint16_t *data)
+{
+ uint32_t register_value = 0;
+ uint32_t i = 0;
+ int32_t error = 0;
+
+ for (i = 0; i < words; i++) {
+ register_value = (data[i] << E1000_EEPROM_RW_REG_DATA) |
+ ((offset+i) << E1000_EEPROM_RW_ADDR_SHIFT) |
+ E1000_EEPROM_RW_REG_START;
+
+ error = em_poll_eerd_eewr_done(hw, E1000_EEPROM_POLL_WRITE);
+ if(error) {
+ break;
+ }
+
+ E1000_WRITE_REG(hw, EEWR, register_value);
+
+ error = em_poll_eerd_eewr_done(hw, E1000_EEPROM_POLL_WRITE);
+
+ if(error) {
+ break;
+ }
+ }
+
+ return error;
+}
+
+/******************************************************************************
+ * Polls the status bit (bit 1) of the EERD to determine when the read is done.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+int32_t
+em_poll_eerd_eewr_done(struct em_hw *hw, int eerd)
+{
+ uint32_t attempts = 100000;
+ uint32_t i, reg = 0;
+ int32_t done = E1000_ERR_EEPROM;
+
+ for(i = 0; i < attempts; i++) {
+ if(eerd == E1000_EEPROM_POLL_READ)
+ reg = E1000_READ_REG(hw, EERD);
+ else
+ reg = E1000_READ_REG(hw, EEWR);
+
+ if(reg & E1000_EEPROM_RW_REG_DONE) {
+ done = E1000_SUCCESS;
+ break;
+ }
+ usec_delay(5);
+ }
+
+ return done;
+}
+
+/***************************************************************************
+* Description: Determines if the onboard NVM is FLASH or EEPROM.
+*
+* hw - Struct containing variables accessed by shared code
+****************************************************************************/
+boolean_t
+em_is_onboard_nvm_eeprom(struct em_hw *hw)
+{
+ uint32_t eecd = 0;
+
+ if(hw->mac_type == em_82573) {
+ eecd = E1000_READ_REG(hw, EECD);
+
+ /* Isolate bits 15 & 16 */
+ eecd = ((eecd >> 15) & 0x03);
+
+ /* If both bits are set, device is Flash type */
+ if(eecd == 0x03) {
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+/******************************************************************************
+ * Verifies that the EEPROM has a valid checksum
+ *
+ * hw - Struct containing variables accessed by shared code
+ *
+ * Reads the first 64 16 bit words of the EEPROM and sums the values read.
+ * If the the sum of the 64 16 bit words is 0xBABA, the EEPROM's checksum is
+ * valid.
+ *****************************************************************************/
+int32_t
+em_validate_eeprom_checksum(struct em_hw *hw)
+{
+ uint16_t checksum = 0;
+ uint16_t i, eeprom_data;
+
+ DEBUGFUNC("em_validate_eeprom_checksum");
+
+ if ((hw->mac_type == em_82573) &&
+ (em_is_onboard_nvm_eeprom(hw) == FALSE)) {
+ /* Check bit 4 of word 10h. If it is 0, firmware is done updating
+ * 10h-12h. Checksum may need to be fixed. */
+ em_read_eeprom(hw, 0x10, 1, &eeprom_data);
+ if ((eeprom_data & 0x10) == 0) {
+ /* Read 0x23 and check bit 15. This bit is a 1 when the checksum
+ * has already been fixed. If the checksum is still wrong and this
+ * bit is a 1, we need to return bad checksum. Otherwise, we need
+ * to set this bit to a 1 and update the checksum. */
+ em_read_eeprom(hw, 0x23, 1, &eeprom_data);
+ if ((eeprom_data & 0x8000) == 0) {
+ eeprom_data |= 0x8000;
+ em_write_eeprom(hw, 0x23, 1, &eeprom_data);
+ em_update_eeprom_checksum(hw);
+ }
+ }
+ }
+
+ for(i = 0; i < (EEPROM_CHECKSUM_REG + 1); i++) {
+ if(em_read_eeprom(hw, i, 1, &eeprom_data) < 0) {
+ DEBUGOUT("EEPROM Read Error\n");
+ return -E1000_ERR_EEPROM;
+ }
+ checksum += eeprom_data;
+ }
+
+ if(checksum == (uint16_t) EEPROM_SUM)
+ return E1000_SUCCESS;
+ else {
+ DEBUGOUT("EEPROM Checksum Invalid\n");
+ return -E1000_ERR_EEPROM;
+ }
+}
+
+/******************************************************************************
+ * Calculates the EEPROM checksum and writes it to the EEPROM
+ *
+ * hw - Struct containing variables accessed by shared code
+ *
+ * Sums the first 63 16 bit words of the EEPROM. Subtracts the sum from 0xBABA.
+ * Writes the difference to word offset 63 of the EEPROM.
+ *****************************************************************************/
+int32_t
+em_update_eeprom_checksum(struct em_hw *hw)
+{
+ uint16_t checksum = 0;
+ uint16_t i, eeprom_data;
+
+ DEBUGFUNC("em_update_eeprom_checksum");
+
+ for(i = 0; i < EEPROM_CHECKSUM_REG; i++) {
+ if(em_read_eeprom(hw, i, 1, &eeprom_data) < 0) {
+ DEBUGOUT("EEPROM Read Error\n");
+ return -E1000_ERR_EEPROM;
+ }
+ checksum += eeprom_data;
+ }
+ checksum = (uint16_t) EEPROM_SUM - checksum;
+ if(em_write_eeprom(hw, EEPROM_CHECKSUM_REG, 1, &checksum) < 0) {
+ DEBUGOUT("EEPROM Write Error\n");
+ return -E1000_ERR_EEPROM;
+ } else if (hw->eeprom.type == em_eeprom_flash) {
+ em_commit_shadow_ram(hw);
+ }
+ return E1000_SUCCESS;
+}
+
+/******************************************************************************
+ * Parent function for writing words to the different EEPROM types.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * offset - offset within the EEPROM to be written to
+ * words - number of words to write
+ * data - 16 bit word to be written to the EEPROM
+ *
+ * If em_update_eeprom_checksum is not called after this function, the
+ * EEPROM will most likely contain an invalid checksum.
+ *****************************************************************************/
+int32_t
+em_write_eeprom(struct em_hw *hw,
+ uint16_t offset,
+ uint16_t words,
+ uint16_t *data)
+{
+ struct em_eeprom_info *eeprom = &hw->eeprom;
+ int32_t status = 0;
+
+ DEBUGFUNC("em_write_eeprom");
+
+ /* A check for invalid values: offset too large, too many words, and not
+ * enough words.
+ */
+ if((offset >= eeprom->word_size) || (words > eeprom->word_size - offset) ||
+ (words == 0)) {
+ DEBUGOUT("\"words\" parameter out of bounds\n");
+ return -E1000_ERR_EEPROM;
+ }
+
+ /* 82573 reads only through eerd */
+ if(eeprom->use_eewr == TRUE)
+ return em_write_eeprom_eewr(hw, offset, words, data);
+
+ /* Prepare the EEPROM for writing */
+ if (em_acquire_eeprom(hw) != E1000_SUCCESS)
+ return -E1000_ERR_EEPROM;
+
+ if(eeprom->type == em_eeprom_microwire) {
+ status = em_write_eeprom_microwire(hw, offset, words, data);
+ } else {
+ status = em_write_eeprom_spi(hw, offset, words, data);
+ msec_delay(10);
+ }
+
+ /* Done with writing */
+ em_release_eeprom(hw);
+
+ return status;
+}
+
+/******************************************************************************
+ * Writes a 16 bit word to a given offset in an SPI EEPROM.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * offset - offset within the EEPROM to be written to
+ * words - number of words to write
+ * data - pointer to array of 8 bit words to be written to the EEPROM
+ *
+ *****************************************************************************/
+int32_t
+em_write_eeprom_spi(struct em_hw *hw,
+ uint16_t offset,
+ uint16_t words,
+ uint16_t *data)
+{
+ struct em_eeprom_info *eeprom = &hw->eeprom;
+ uint16_t widx = 0;
+
+ DEBUGFUNC("em_write_eeprom_spi");
+
+ while (widx < words) {
+ uint8_t write_opcode = EEPROM_WRITE_OPCODE_SPI;
+
+ if(em_spi_eeprom_ready(hw)) return -E1000_ERR_EEPROM;
+
+ em_standby_eeprom(hw);
+
+ /* Send the WRITE ENABLE command (8 bit opcode ) */
+ em_shift_out_ee_bits(hw, EEPROM_WREN_OPCODE_SPI,
+ eeprom->opcode_bits);
+
+ em_standby_eeprom(hw);
+
+ /* Some SPI eeproms use the 8th address bit embedded in the opcode */
+ if((eeprom->address_bits == 8) && (offset >= 128))
+ write_opcode |= EEPROM_A8_OPCODE_SPI;
+
+ /* Send the Write command (8-bit opcode + addr) */
+ em_shift_out_ee_bits(hw, write_opcode, eeprom->opcode_bits);
+
+ em_shift_out_ee_bits(hw, (uint16_t)((offset + widx)*2),
+ eeprom->address_bits);
+
+ /* Send the data */
+
+ /* Loop to allow for up to whole page write (32 bytes) of eeprom */
+ while (widx < words) {
+ uint16_t word_out = data[widx];
+ word_out = (word_out >> 8) | (word_out << 8);
+ em_shift_out_ee_bits(hw, word_out, 16);
+ widx++;
+
+ /* Some larger eeprom sizes are capable of a 32-byte PAGE WRITE
+ * operation, while the smaller eeproms are capable of an 8-byte
+ * PAGE WRITE operation. Break the inner loop to pass new address
+ */
+ if((((offset + widx)*2) % eeprom->page_size) == 0) {
+ em_standby_eeprom(hw);
+ break;
+ }
+ }
+ }
+
+ return E1000_SUCCESS;
+}
+
+/******************************************************************************
+ * Writes a 16 bit word to a given offset in a Microwire EEPROM.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * offset - offset within the EEPROM to be written to
+ * words - number of words to write
+ * data - pointer to array of 16 bit words to be written to the EEPROM
+ *
+ *****************************************************************************/
+int32_t
+em_write_eeprom_microwire(struct em_hw *hw,
+ uint16_t offset,
+ uint16_t words,
+ uint16_t *data)
+{
+ struct em_eeprom_info *eeprom = &hw->eeprom;
+ uint32_t eecd;
+ uint16_t words_written = 0;
+ uint16_t i = 0;
+
+ DEBUGFUNC("em_write_eeprom_microwire");
+
+ /* Send the write enable command to the EEPROM (3-bit opcode plus
+ * 6/8-bit dummy address beginning with 11). It's less work to include
+ * the 11 of the dummy address as part of the opcode than it is to shift
+ * it over the correct number of bits for the address. This puts the
+ * EEPROM into write/erase mode.
+ */
+ em_shift_out_ee_bits(hw, EEPROM_EWEN_OPCODE_MICROWIRE,
+ (uint16_t)(eeprom->opcode_bits + 2));
+
+ em_shift_out_ee_bits(hw, 0, (uint16_t)(eeprom->address_bits - 2));
+
+ /* Prepare the EEPROM */
+ em_standby_eeprom(hw);
+
+ while (words_written < words) {
+ /* Send the Write command (3-bit opcode + addr) */
+ em_shift_out_ee_bits(hw, EEPROM_WRITE_OPCODE_MICROWIRE,
+ eeprom->opcode_bits);
+
+ em_shift_out_ee_bits(hw, (uint16_t)(offset + words_written),
+ eeprom->address_bits);
+
+ /* Send the data */
+ em_shift_out_ee_bits(hw, data[words_written], 16);
+
+ /* Toggle the CS line. This in effect tells the EEPROM to execute
+ * the previous command.
+ */
+ em_standby_eeprom(hw);
+
+ /* Read DO repeatedly until it is high (equal to '1'). The EEPROM will
+ * signal that the command has been completed by raising the DO signal.
+ * If DO does not go high in 10 milliseconds, then error out.
+ */
+ for(i = 0; i < 200; i++) {
+ eecd = E1000_READ_REG(hw, EECD);
+ if(eecd & E1000_EECD_DO) break;
+ usec_delay(50);
+ }
+ if(i == 200) {
+ DEBUGOUT("EEPROM Write did not complete\n");
+ return -E1000_ERR_EEPROM;
+ }
+
+ /* Recover from write */
+ em_standby_eeprom(hw);
+
+ words_written++;
+ }
+
+ /* Send the write disable command to the EEPROM (3-bit opcode plus
+ * 6/8-bit dummy address beginning with 10). It's less work to include
+ * the 10 of the dummy address as part of the opcode than it is to shift
+ * it over the correct number of bits for the address. This takes the
+ * EEPROM out of write/erase mode.
+ */
+ em_shift_out_ee_bits(hw, EEPROM_EWDS_OPCODE_MICROWIRE,
+ (uint16_t)(eeprom->opcode_bits + 2));
+
+ em_shift_out_ee_bits(hw, 0, (uint16_t)(eeprom->address_bits - 2));
+
+ return E1000_SUCCESS;
+}
+
+/******************************************************************************
+ * Flushes the cached eeprom to NVM. This is done by saving the modified values
+ * in the eeprom cache and the non modified values in the currently active bank
+ * to the new bank.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * offset - offset of word in the EEPROM to read
+ * data - word read from the EEPROM
+ * words - number of words to read
+ *****************************************************************************/
+int32_t
+em_commit_shadow_ram(struct em_hw *hw)
+{
+ uint32_t attempts = 100000;
+ uint32_t eecd = 0;
+ uint32_t flop = 0;
+ uint32_t i = 0;
+ int32_t error = E1000_SUCCESS;
+
+ /* The flop register will be used to determine if flash type is STM */
+ flop = E1000_READ_REG(hw, FLOP);
+
+ if (hw->mac_type == em_82573) {
+ for (i=0; i < attempts; i++) {
+ eecd = E1000_READ_REG(hw, EECD);
+ if ((eecd & E1000_EECD_FLUPD) == 0) {
+ break;
+ }
+ usec_delay(5);
+ }
+
+ if (i == attempts) {
+ return -E1000_ERR_EEPROM;
+ }
+
+ /* If STM opcode located in bits 15:8 of flop, reset firmware */
+ if ((flop & 0xFF00) == E1000_STM_OPCODE) {
+ E1000_WRITE_REG(hw, HICR, E1000_HICR_FW_RESET);
+ }
+
+ /* Perform the flash update */
+ E1000_WRITE_REG(hw, EECD, eecd | E1000_EECD_FLUPD);
+
+ for (i=0; i < attempts; i++) {
+ eecd = E1000_READ_REG(hw, EECD);
+ if ((eecd & E1000_EECD_FLUPD) == 0) {
+ break;
+ }
+ usec_delay(5);
+ }
+
+ if (i == attempts) {
+ return -E1000_ERR_EEPROM;
+ }
+ }
+
+ return error;
+}
+
+/******************************************************************************
+ * Reads the adapter's part number from the EEPROM
+ *
+ * hw - Struct containing variables accessed by shared code
+ * part_num - Adapter's part number
+ *****************************************************************************/
+int32_t
+em_read_part_num(struct em_hw *hw,
+ uint32_t *part_num)
+{
+ uint16_t offset = EEPROM_PBA_BYTE_1;
+ uint16_t eeprom_data;
+
+ DEBUGFUNC("em_read_part_num");
+
+ /* Get word 0 from EEPROM */
+ if(em_read_eeprom(hw, offset, 1, &eeprom_data) < 0) {
+ DEBUGOUT("EEPROM Read Error\n");
+ return -E1000_ERR_EEPROM;
+ }
+ /* Save word 0 in upper half of part_num */
+ *part_num = (uint32_t) (eeprom_data << 16);
+
+ /* Get word 1 from EEPROM */
+ if(em_read_eeprom(hw, ++offset, 1, &eeprom_data) < 0) {
+ DEBUGOUT("EEPROM Read Error\n");
+ return -E1000_ERR_EEPROM;
+ }
+ /* Save word 1 in lower half of part_num */
+ *part_num |= eeprom_data;
+
+ return E1000_SUCCESS;
+}
+
+/******************************************************************************
+ * Reads the adapter's MAC address from the EEPROM and inverts the LSB for the
+ * second function of dual function devices
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+int32_t
+em_read_mac_addr(struct em_hw * hw)
+{
+ uint16_t offset;
+ uint16_t eeprom_data, i;
+
+ DEBUGFUNC("em_read_mac_addr");
+
+ for(i = 0; i < NODE_ADDRESS_SIZE; i += 2) {
+ offset = i >> 1;
+ if(em_read_eeprom(hw, offset, 1, &eeprom_data) < 0) {
+ DEBUGOUT("EEPROM Read Error\n");
+ return -E1000_ERR_EEPROM;
+ }
+ hw->perm_mac_addr[i] = (uint8_t) (eeprom_data & 0x00FF);
+ hw->perm_mac_addr[i+1] = (uint8_t) (eeprom_data >> 8);
+ }
+ if(((hw->mac_type == em_82546) || (hw->mac_type == em_82546_rev_3)) &&
+ (E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1))
+ hw->perm_mac_addr[5] ^= 0x01;
+
+ for(i = 0; i < NODE_ADDRESS_SIZE; i++)
+ hw->mac_addr[i] = hw->perm_mac_addr[i];
+ return E1000_SUCCESS;
+}
+
+/******************************************************************************
+ * Initializes receive address filters.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *
+ * Places the MAC address in receive address register 0 and clears the rest
+ * of the receive addresss registers. Clears the multicast table. Assumes
+ * the receiver is in reset when the routine is called.
+ *****************************************************************************/
+void
+em_init_rx_addrs(struct em_hw *hw)
+{
+ uint32_t i;
+ uint32_t rar_num;
+
+ DEBUGFUNC("em_init_rx_addrs");
+
+ /* Setup the receive address. */
+ DEBUGOUT("Programming MAC Address into RAR[0]\n");
+
+ em_rar_set(hw, hw->mac_addr, 0);
+
+ rar_num = E1000_RAR_ENTRIES;
+ /* Zero out the other 15 receive addresses. */
+ DEBUGOUT("Clearing RAR[1-15]\n");
+ for(i = 1; i < rar_num; i++) {
+ E1000_WRITE_REG_ARRAY(hw, RA, (i << 1), 0);
+ E1000_WRITE_REG_ARRAY(hw, RA, ((i << 1) + 1), 0);
+ }
+}
+
+/******************************************************************************
+ * Updates the MAC's list of multicast addresses.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * mc_addr_list - the list of new multicast addresses
+ * mc_addr_count - number of addresses
+ * pad - number of bytes between addresses in the list
+ * rar_used_count - offset where to start adding mc addresses into the RAR's
+ *
+ * The given list replaces any existing list. Clears the last 15 receive
+ * address registers and the multicast table. Uses receive address registers
+ * for the first 15 multicast addresses, and hashes the rest into the
+ * multicast table.
+ *****************************************************************************/
+void
+em_mc_addr_list_update(struct em_hw *hw,
+ uint8_t *mc_addr_list,
+ uint32_t mc_addr_count,
+ uint32_t pad,
+ uint32_t rar_used_count)
+{
+ uint32_t hash_value;
+ uint32_t i;
+ uint32_t num_rar_entry;
+ uint32_t num_mta_entry;
+
+ DEBUGFUNC("em_mc_addr_list_update");
+
+ /* Set the new number of MC addresses that we are being requested to use. */
+ hw->num_mc_addrs = mc_addr_count;
+
+ /* Clear RAR[1-15] */
+ DEBUGOUT(" Clearing RAR[1-15]\n");
+ num_rar_entry = E1000_RAR_ENTRIES;
+ for(i = rar_used_count; i < num_rar_entry; i++) {
+ E1000_WRITE_REG_ARRAY(hw, RA, (i << 1), 0);
+ E1000_WRITE_REG_ARRAY(hw, RA, ((i << 1) + 1), 0);
+ }
+
+ /* Clear the MTA */
+ DEBUGOUT(" Clearing MTA\n");
+ num_mta_entry = E1000_NUM_MTA_REGISTERS;
+ for(i = 0; i < num_mta_entry; i++) {
+ E1000_WRITE_REG_ARRAY(hw, MTA, i, 0);
+ }
+
+ /* Add the new addresses */
+ for(i = 0; i < mc_addr_count; i++) {
+ DEBUGOUT(" Adding the multicast addresses:\n");
+ DEBUGOUT7(" MC Addr #%d =%.2X %.2X %.2X %.2X %.2X %.2X\n", i,
+ mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad)],
+ mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad) + 1],
+ mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad) + 2],
+ mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad) + 3],
+ mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad) + 4],
+ mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad) + 5]);
+
+ hash_value = em_hash_mc_addr(hw,
+ mc_addr_list +
+ (i * (ETH_LENGTH_OF_ADDRESS + pad)));
+
+ DEBUGOUT1(" Hash value = 0x%03X\n", hash_value);
+
+ /* Place this multicast address in the RAR if there is room, *
+ * else put it in the MTA
+ */
+ if (rar_used_count < num_rar_entry) {
+ em_rar_set(hw,
+ mc_addr_list + (i * (ETH_LENGTH_OF_ADDRESS + pad)),
+ rar_used_count);
+ rar_used_count++;
+ } else {
+ em_mta_set(hw, hash_value);
+ }
+ }
+ DEBUGOUT("MC Update Complete\n");
+}
+
+/******************************************************************************
+ * Hashes an address to determine its location in the multicast table
+ *
+ * hw - Struct containing variables accessed by shared code
+ * mc_addr - the multicast address to hash
+ *****************************************************************************/
+uint32_t
+em_hash_mc_addr(struct em_hw *hw,
+ uint8_t *mc_addr)
+{
+ uint32_t hash_value = 0;
+
+ /* The portion of the address that is used for the hash table is
+ * determined by the mc_filter_type setting.
+ */
+ switch (hw->mc_filter_type) {
+ /* [0] [1] [2] [3] [4] [5]
+ * 01 AA 00 12 34 56
+ * LSB MSB
+ */
+ case 0:
+ /* [47:36] i.e. 0x563 for above example address */
+ hash_value = ((mc_addr[4] >> 4) | (((uint16_t) mc_addr[5]) << 4));
+ break;
+ case 1:
+ /* [46:35] i.e. 0xAC6 for above example address */
+ hash_value = ((mc_addr[4] >> 3) | (((uint16_t) mc_addr[5]) << 5));
+ break;
+ case 2:
+ /* [45:34] i.e. 0x5D8 for above example address */
+ hash_value = ((mc_addr[4] >> 2) | (((uint16_t) mc_addr[5]) << 6));
+ break;
+ case 3:
+ /* [43:32] i.e. 0x634 for above example address */
+ hash_value = ((mc_addr[4]) | (((uint16_t) mc_addr[5]) << 8));
+ break;
+ }
+
+ hash_value &= 0xFFF;
+
+ return hash_value;
+}
+
+/******************************************************************************
+ * Sets the bit in the multicast table corresponding to the hash value.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * hash_value - Multicast address hash value
+ *****************************************************************************/
+void
+em_mta_set(struct em_hw *hw,
+ uint32_t hash_value)
+{
+ uint32_t hash_bit, hash_reg;
+ uint32_t mta;
+ uint32_t temp;
+
+ /* The MTA is a register array of 128 32-bit registers.
+ * It is treated like an array of 4096 bits. We want to set
+ * bit BitArray[hash_value]. So we figure out what register
+ * the bit is in, read it, OR in the new bit, then write
+ * back the new value. The register is determined by the
+ * upper 7 bits of the hash value and the bit within that
+ * register are determined by the lower 5 bits of the value.
+ */
+ hash_reg = (hash_value >> 5) & 0x7F;
+ hash_bit = hash_value & 0x1F;
+
+ mta = E1000_READ_REG_ARRAY(hw, MTA, hash_reg);
+
+ mta |= (1 << hash_bit);
+
+ /* If we are on an 82544 and we are trying to write an odd offset
+ * in the MTA, save off the previous entry before writing and
+ * restore the old value after writing.
+ */
+ if((hw->mac_type == em_82544) && ((hash_reg & 0x1) == 1)) {
+ temp = E1000_READ_REG_ARRAY(hw, MTA, (hash_reg - 1));
+ E1000_WRITE_REG_ARRAY(hw, MTA, hash_reg, mta);
+ E1000_WRITE_REG_ARRAY(hw, MTA, (hash_reg - 1), temp);
+ } else {
+ E1000_WRITE_REG_ARRAY(hw, MTA, hash_reg, mta);
+ }
+}
+
+/******************************************************************************
+ * Puts an ethernet address into a receive address register.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * addr - Address to put into receive address register
+ * index - Receive address register to write
+ *****************************************************************************/
+void
+em_rar_set(struct em_hw *hw,
+ uint8_t *addr,
+ uint32_t index)
+{
+ uint32_t rar_low, rar_high;
+
+ /* HW expects these in little endian so we reverse the byte order
+ * from network order (big endian) to little endian
+ */
+ rar_low = ((uint32_t) addr[0] |
+ ((uint32_t) addr[1] << 8) |
+ ((uint32_t) addr[2] << 16) | ((uint32_t) addr[3] << 24));
+
+ rar_high = ((uint32_t) addr[4] | ((uint32_t) addr[5] << 8) | E1000_RAH_AV);
+
+ E1000_WRITE_REG_ARRAY(hw, RA, (index << 1), rar_low);
+ E1000_WRITE_REG_ARRAY(hw, RA, ((index << 1) + 1), rar_high);
+}
+
+/******************************************************************************
+ * Writes a value to the specified offset in the VLAN filter table.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * offset - Offset in VLAN filer table to write
+ * value - Value to write into VLAN filter table
+ *****************************************************************************/
+void
+em_write_vfta(struct em_hw *hw,
+ uint32_t offset,
+ uint32_t value)
+{
+ uint32_t temp;
+
+ if((hw->mac_type == em_82544) && ((offset & 0x1) == 1)) {
+ temp = E1000_READ_REG_ARRAY(hw, VFTA, (offset - 1));
+ E1000_WRITE_REG_ARRAY(hw, VFTA, offset, value);
+ E1000_WRITE_REG_ARRAY(hw, VFTA, (offset - 1), temp);
+ } else {
+ E1000_WRITE_REG_ARRAY(hw, VFTA, offset, value);
+ }
+}
+
+/******************************************************************************
+ * Clears the VLAN filer table
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+void
+em_clear_vfta(struct em_hw *hw)
+{
+ uint32_t offset;
+ uint32_t vfta_value = 0;
+ uint32_t vfta_offset = 0;
+ uint32_t vfta_bit_in_reg = 0;
+
+ if (hw->mac_type == em_82573) {
+ if (hw->mng_cookie.vlan_id != 0) {
+ /* The VFTA is a 4096b bit-field, each identifying a single VLAN
+ * ID. The following operations determine which 32b entry
+ * (i.e. offset) into the array we want to set the VLAN ID
+ * (i.e. bit) of the manageability unit. */
+ vfta_offset = (hw->mng_cookie.vlan_id >>
+ E1000_VFTA_ENTRY_SHIFT) &
+ E1000_VFTA_ENTRY_MASK;
+ vfta_bit_in_reg = 1 << (hw->mng_cookie.vlan_id &
+ E1000_VFTA_ENTRY_BIT_SHIFT_MASK);
+ }
+ }
+ for (offset = 0; offset < E1000_VLAN_FILTER_TBL_SIZE; offset++) {
+ /* If the offset we want to clear is the same offset of the
+ * manageability VLAN ID, then clear all bits except that of the
+ * manageability unit */
+ vfta_value = (offset == vfta_offset) ? vfta_bit_in_reg : 0;
+ E1000_WRITE_REG_ARRAY(hw, VFTA, offset, vfta_value);
+ }
+}
+
+int32_t
+em_id_led_init(struct em_hw * hw)
+{
+ uint32_t ledctl;
+ const uint32_t ledctl_mask = 0x000000FF;
+ const uint32_t ledctl_on = E1000_LEDCTL_MODE_LED_ON;
+ const uint32_t ledctl_off = E1000_LEDCTL_MODE_LED_OFF;
+ uint16_t eeprom_data, i, temp;
+ const uint16_t led_mask = 0x0F;
+
+ DEBUGFUNC("em_id_led_init");
+
+ if(hw->mac_type < em_82540) {
+ /* Nothing to do */
+ return E1000_SUCCESS;
+ }
+
+ ledctl = E1000_READ_REG(hw, LEDCTL);
+ hw->ledctl_default = ledctl;
+ hw->ledctl_mode1 = hw->ledctl_default;
+ hw->ledctl_mode2 = hw->ledctl_default;
+
+ if(em_read_eeprom(hw, EEPROM_ID_LED_SETTINGS, 1, &eeprom_data) < 0) {
+ DEBUGOUT("EEPROM Read Error\n");
+ return -E1000_ERR_EEPROM;
+ }
+ if((eeprom_data== ID_LED_RESERVED_0000) ||
+ (eeprom_data == ID_LED_RESERVED_FFFF)) eeprom_data = ID_LED_DEFAULT;
+ for(i = 0; i < 4; i++) {
+ temp = (eeprom_data >> (i << 2)) & led_mask;
+ switch(temp) {
+ case ID_LED_ON1_DEF2:
+ case ID_LED_ON1_ON2:
+ case ID_LED_ON1_OFF2:
+ hw->ledctl_mode1 &= ~(ledctl_mask << (i << 3));
+ hw->ledctl_mode1 |= ledctl_on << (i << 3);
+ break;
+ case ID_LED_OFF1_DEF2:
+ case ID_LED_OFF1_ON2:
+ case ID_LED_OFF1_OFF2:
+ hw->ledctl_mode1 &= ~(ledctl_mask << (i << 3));
+ hw->ledctl_mode1 |= ledctl_off << (i << 3);
+ break;
+ default:
+ /* Do nothing */
+ break;
+ }
+ switch(temp) {
+ case ID_LED_DEF1_ON2:
+ case ID_LED_ON1_ON2:
+ case ID_LED_OFF1_ON2:
+ hw->ledctl_mode2 &= ~(ledctl_mask << (i << 3));
+ hw->ledctl_mode2 |= ledctl_on << (i << 3);
+ break;
+ case ID_LED_DEF1_OFF2:
+ case ID_LED_ON1_OFF2:
+ case ID_LED_OFF1_OFF2:
+ hw->ledctl_mode2 &= ~(ledctl_mask << (i << 3));
+ hw->ledctl_mode2 |= ledctl_off << (i << 3);
+ break;
+ default:
+ /* Do nothing */
+ break;
+ }
+ }
+ return E1000_SUCCESS;
+}
+
+/******************************************************************************
+ * Prepares SW controlable LED for use and saves the current state of the LED.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+int32_t
+em_setup_led(struct em_hw *hw)
+{
+ uint32_t ledctl;
+ int32_t ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("em_setup_led");
+
+ switch(hw->mac_type) {
+ case em_82542_rev2_0:
+ case em_82542_rev2_1:
+ case em_82543:
+ case em_82544:
+ /* No setup necessary */
+ break;
+ case em_82541:
+ case em_82547:
+ case em_82541_rev_2:
+ case em_82547_rev_2:
+ /* Turn off PHY Smart Power Down (if enabled) */
+ ret_val = em_read_phy_reg(hw, IGP01E1000_GMII_FIFO,
+ &hw->phy_spd_default);
+ if(ret_val)
+ return ret_val;
+ ret_val = em_write_phy_reg(hw, IGP01E1000_GMII_FIFO,
+ (uint16_t)(hw->phy_spd_default &
+ ~IGP01E1000_GMII_SPD));
+ if(ret_val)
+ return ret_val;
+ /* Fall Through */
+ default:
+ if(hw->media_type == em_media_type_fiber) {
+ ledctl = E1000_READ_REG(hw, LEDCTL);
+ /* Save current LEDCTL settings */
+ hw->ledctl_default = ledctl;
+ /* Turn off LED0 */
+ ledctl &= ~(E1000_LEDCTL_LED0_IVRT |
+ E1000_LEDCTL_LED0_BLINK |
+ E1000_LEDCTL_LED0_MODE_MASK);
+ ledctl |= (E1000_LEDCTL_MODE_LED_OFF <<
+ E1000_LEDCTL_LED0_MODE_SHIFT);
+ E1000_WRITE_REG(hw, LEDCTL, ledctl);
+ } else if(hw->media_type == em_media_type_copper)
+ E1000_WRITE_REG(hw, LEDCTL, hw->ledctl_mode1);
+ break;
+ }
+
+ return E1000_SUCCESS;
+}
+
+/******************************************************************************
+ * Restores the saved state of the SW controlable LED.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+int32_t
+em_cleanup_led(struct em_hw *hw)
+{
+ int32_t ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("em_cleanup_led");
+
+ switch(hw->mac_type) {
+ case em_82542_rev2_0:
+ case em_82542_rev2_1:
+ case em_82543:
+ case em_82544:
+ /* No cleanup necessary */
+ break;
+ case em_82541:
+ case em_82547:
+ case em_82541_rev_2:
+ case em_82547_rev_2:
+ /* Turn on PHY Smart Power Down (if previously enabled) */
+ ret_val = em_write_phy_reg(hw, IGP01E1000_GMII_FIFO,
+ hw->phy_spd_default);
+ if(ret_val)
+ return ret_val;
+ /* Fall Through */
+ default:
+ /* Restore LEDCTL settings */
+ E1000_WRITE_REG(hw, LEDCTL, hw->ledctl_default);
+ break;
+ }
+
+ return E1000_SUCCESS;
+}
+
+/******************************************************************************
+ * Turns on the software controllable LED
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+int32_t
+em_led_on(struct em_hw *hw)
+{
+ uint32_t ctrl = E1000_READ_REG(hw, CTRL);
+
+ DEBUGFUNC("em_led_on");
+
+ switch(hw->mac_type) {
+ case em_82542_rev2_0:
+ case em_82542_rev2_1:
+ case em_82543:
+ /* Set SW Defineable Pin 0 to turn on the LED */
+ ctrl |= E1000_CTRL_SWDPIN0;
+ ctrl |= E1000_CTRL_SWDPIO0;
+ break;
+ case em_82544:
+ if(hw->media_type == em_media_type_fiber) {
+ /* Set SW Defineable Pin 0 to turn on the LED */
+ ctrl |= E1000_CTRL_SWDPIN0;
+ ctrl |= E1000_CTRL_SWDPIO0;
+ } else {
+ /* Clear SW Defineable Pin 0 to turn on the LED */
+ ctrl &= ~E1000_CTRL_SWDPIN0;
+ ctrl |= E1000_CTRL_SWDPIO0;
+ }
+ break;
+ default:
+ if(hw->media_type == em_media_type_fiber) {
+ /* Clear SW Defineable Pin 0 to turn on the LED */
+ ctrl &= ~E1000_CTRL_SWDPIN0;
+ ctrl |= E1000_CTRL_SWDPIO0;
+ } else if(hw->media_type == em_media_type_copper) {
+ E1000_WRITE_REG(hw, LEDCTL, hw->ledctl_mode2);
+ return E1000_SUCCESS;
+ }
+ break;
+ }
+
+ E1000_WRITE_REG(hw, CTRL, ctrl);
+
+ return E1000_SUCCESS;
+}
+
+/******************************************************************************
+ * Turns off the software controllable LED
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+int32_t
+em_led_off(struct em_hw *hw)
+{
+ uint32_t ctrl = E1000_READ_REG(hw, CTRL);
+
+ DEBUGFUNC("em_led_off");
+
+ switch(hw->mac_type) {
+ case em_82542_rev2_0:
+ case em_82542_rev2_1:
+ case em_82543:
+ /* Clear SW Defineable Pin 0 to turn off the LED */
+ ctrl &= ~E1000_CTRL_SWDPIN0;
+ ctrl |= E1000_CTRL_SWDPIO0;
+ break;
+ case em_82544:
+ if(hw->media_type == em_media_type_fiber) {
+ /* Clear SW Defineable Pin 0 to turn off the LED */
+ ctrl &= ~E1000_CTRL_SWDPIN0;
+ ctrl |= E1000_CTRL_SWDPIO0;
+ } else {
+ /* Set SW Defineable Pin 0 to turn off the LED */
+ ctrl |= E1000_CTRL_SWDPIN0;
+ ctrl |= E1000_CTRL_SWDPIO0;
+ }
+ break;
+ default:
+ if(hw->media_type == em_media_type_fiber) {
+ /* Set SW Defineable Pin 0 to turn off the LED */
+ ctrl |= E1000_CTRL_SWDPIN0;
+ ctrl |= E1000_CTRL_SWDPIO0;
+ } else if(hw->media_type == em_media_type_copper) {
+ E1000_WRITE_REG(hw, LEDCTL, hw->ledctl_mode1);
+ return E1000_SUCCESS;
+ }
+ break;
+ }
+
+ E1000_WRITE_REG(hw, CTRL, ctrl);
+
+ return E1000_SUCCESS;
+}
+
+/******************************************************************************
+ * Clears all hardware statistics counters.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+void
+em_clear_hw_cntrs(struct em_hw *hw)
+{
+ volatile uint32_t temp;
+
+ temp = E1000_READ_REG(hw, CRCERRS);
+ temp = E1000_READ_REG(hw, SYMERRS);
+ temp = E1000_READ_REG(hw, MPC);
+ temp = E1000_READ_REG(hw, SCC);
+ temp = E1000_READ_REG(hw, ECOL);
+ temp = E1000_READ_REG(hw, MCC);
+ temp = E1000_READ_REG(hw, LATECOL);
+ temp = E1000_READ_REG(hw, COLC);
+ temp = E1000_READ_REG(hw, DC);
+ temp = E1000_READ_REG(hw, SEC);
+ temp = E1000_READ_REG(hw, RLEC);
+ temp = E1000_READ_REG(hw, XONRXC);
+ temp = E1000_READ_REG(hw, XONTXC);
+ temp = E1000_READ_REG(hw, XOFFRXC);
+ temp = E1000_READ_REG(hw, XOFFTXC);
+ temp = E1000_READ_REG(hw, FCRUC);
+ temp = E1000_READ_REG(hw, PRC64);
+ temp = E1000_READ_REG(hw, PRC127);
+ temp = E1000_READ_REG(hw, PRC255);
+ temp = E1000_READ_REG(hw, PRC511);
+ temp = E1000_READ_REG(hw, PRC1023);
+ temp = E1000_READ_REG(hw, PRC1522);
+ temp = E1000_READ_REG(hw, GPRC);
+ temp = E1000_READ_REG(hw, BPRC);
+ temp = E1000_READ_REG(hw, MPRC);
+ temp = E1000_READ_REG(hw, GPTC);
+ temp = E1000_READ_REG(hw, GORCL);
+ temp = E1000_READ_REG(hw, GORCH);
+ temp = E1000_READ_REG(hw, GOTCL);
+ temp = E1000_READ_REG(hw, GOTCH);
+ temp = E1000_READ_REG(hw, RNBC);
+ temp = E1000_READ_REG(hw, RUC);
+ temp = E1000_READ_REG(hw, RFC);
+ temp = E1000_READ_REG(hw, ROC);
+ temp = E1000_READ_REG(hw, RJC);
+ temp = E1000_READ_REG(hw, TORL);
+ temp = E1000_READ_REG(hw, TORH);
+ temp = E1000_READ_REG(hw, TOTL);
+ temp = E1000_READ_REG(hw, TOTH);
+ temp = E1000_READ_REG(hw, TPR);
+ temp = E1000_READ_REG(hw, TPT);
+ temp = E1000_READ_REG(hw, PTC64);
+ temp = E1000_READ_REG(hw, PTC127);
+ temp = E1000_READ_REG(hw, PTC255);
+ temp = E1000_READ_REG(hw, PTC511);
+ temp = E1000_READ_REG(hw, PTC1023);
+ temp = E1000_READ_REG(hw, PTC1522);
+ temp = E1000_READ_REG(hw, MPTC);
+ temp = E1000_READ_REG(hw, BPTC);
+
+ if(hw->mac_type < em_82543) return;
+
+ temp = E1000_READ_REG(hw, ALGNERRC);
+ temp = E1000_READ_REG(hw, RXERRC);
+ temp = E1000_READ_REG(hw, TNCRS);
+ temp = E1000_READ_REG(hw, CEXTERR);
+ temp = E1000_READ_REG(hw, TSCTC);
+ temp = E1000_READ_REG(hw, TSCTFC);
+
+ if(hw->mac_type <= em_82544) return;
+
+ temp = E1000_READ_REG(hw, MGTPRC);
+ temp = E1000_READ_REG(hw, MGTPDC);
+ temp = E1000_READ_REG(hw, MGTPTC);
+
+ if(hw->mac_type <= em_82547_rev_2) return;
+
+ temp = E1000_READ_REG(hw, IAC);
+ temp = E1000_READ_REG(hw, ICRXOC);
+ temp = E1000_READ_REG(hw, ICRXPTC);
+ temp = E1000_READ_REG(hw, ICRXATC);
+ temp = E1000_READ_REG(hw, ICTXPTC);
+ temp = E1000_READ_REG(hw, ICTXATC);
+ temp = E1000_READ_REG(hw, ICTXQEC);
+ temp = E1000_READ_REG(hw, ICTXQMTC);
+ temp = E1000_READ_REG(hw, ICRXDMTC);
+
+}
+
+/******************************************************************************
+ * Resets Adaptive IFS to its default state.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *
+ * Call this after em_init_hw. You may override the IFS defaults by setting
+ * hw->ifs_params_forced to TRUE. However, you must initialize hw->
+ * current_ifs_val, ifs_min_val, ifs_max_val, ifs_step_size, and ifs_ratio
+ * before calling this function.
+ *****************************************************************************/
+void
+em_reset_adaptive(struct em_hw *hw)
+{
+ DEBUGFUNC("em_reset_adaptive");
+
+ if(hw->adaptive_ifs) {
+ if(!hw->ifs_params_forced) {
+ hw->current_ifs_val = 0;
+ hw->ifs_min_val = IFS_MIN;
+ hw->ifs_max_val = IFS_MAX;
+ hw->ifs_step_size = IFS_STEP;
+ hw->ifs_ratio = IFS_RATIO;
+ }
+ hw->in_ifs_mode = FALSE;
+ E1000_WRITE_REG(hw, AIT, 0);
+ } else {
+ DEBUGOUT("Not in Adaptive IFS mode!\n");
+ }
+}
+
+/******************************************************************************
+ * Called during the callback/watchdog routine to update IFS value based on
+ * the ratio of transmits to collisions.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * tx_packets - Number of transmits since last callback
+ * total_collisions - Number of collisions since last callback
+ *****************************************************************************/
+void
+em_update_adaptive(struct em_hw *hw)
+{
+ DEBUGFUNC("em_update_adaptive");
+
+ if(hw->adaptive_ifs) {
+ if((hw->collision_delta * hw->ifs_ratio) > hw->tx_packet_delta) {
+ if(hw->tx_packet_delta > MIN_NUM_XMITS) {
+ hw->in_ifs_mode = TRUE;
+ if(hw->current_ifs_val < hw->ifs_max_val) {
+ if(hw->current_ifs_val == 0)
+ hw->current_ifs_val = hw->ifs_min_val;
+ else
+ hw->current_ifs_val += hw->ifs_step_size;
+ E1000_WRITE_REG(hw, AIT, hw->current_ifs_val);
+ }
+ }
+ } else {
+ if(hw->in_ifs_mode && (hw->tx_packet_delta <= MIN_NUM_XMITS)) {
+ hw->current_ifs_val = 0;
+ hw->in_ifs_mode = FALSE;
+ E1000_WRITE_REG(hw, AIT, 0);
+ }
+ }
+ } else {
+ DEBUGOUT("Not in Adaptive IFS mode!\n");
+ }
+}
+
+/******************************************************************************
+ * Adjusts the statistic counters when a frame is accepted by TBI_ACCEPT
+ *
+ * hw - Struct containing variables accessed by shared code
+ * frame_len - The length of the frame in question
+ * mac_addr - The Ethernet destination address of the frame in question
+ *****************************************************************************/
+void
+em_tbi_adjust_stats(struct em_hw *hw,
+ struct em_hw_stats *stats,
+ uint32_t frame_len,
+ uint8_t *mac_addr)
+{
+ uint64_t carry_bit;
+
+ /* First adjust the frame length. */
+ frame_len--;
+ /* We need to adjust the statistics counters, since the hardware
+ * counters overcount this packet as a CRC error and undercount
+ * the packet as a good packet
+ */
+ /* This packet should not be counted as a CRC error. */
+ stats->crcerrs--;
+ /* This packet does count as a Good Packet Received. */
+ stats->gprc++;
+
+ /* Adjust the Good Octets received counters */
+ carry_bit = 0x80000000 & stats->gorcl;
+ stats->gorcl += frame_len;
+ /* If the high bit of Gorcl (the low 32 bits of the Good Octets
+ * Received Count) was one before the addition,
+ * AND it is zero after, then we lost the carry out,
+ * need to add one to Gorch (Good Octets Received Count High).
+ * This could be simplified if all environments supported
+ * 64-bit integers.
+ */
+ if(carry_bit && ((stats->gorcl & 0x80000000) == 0))
+ stats->gorch++;
+ /* Is this a broadcast or multicast? Check broadcast first,
+ * since the test for a multicast frame will test positive on
+ * a broadcast frame.
+ */
+ if((mac_addr[0] == (uint8_t) 0xff) && (mac_addr[1] == (uint8_t) 0xff))
+ /* Broadcast packet */
+ stats->bprc++;
+ else if(*mac_addr & 0x01)
+ /* Multicast packet */
+ stats->mprc++;
+
+ if(frame_len == hw->max_frame_size) {
+ /* In this case, the hardware has overcounted the number of
+ * oversize frames.
+ */
+ if(stats->roc > 0)
+ stats->roc--;
+ }
+
+ /* Adjust the bin counters when the extra byte put the frame in the
+ * wrong bin. Remember that the frame_len was adjusted above.
+ */
+ if(frame_len == 64) {
+ stats->prc64++;
+ stats->prc127--;
+ } else if(frame_len == 127) {
+ stats->prc127++;
+ stats->prc255--;
+ } else if(frame_len == 255) {
+ stats->prc255++;
+ stats->prc511--;
+ } else if(frame_len == 511) {
+ stats->prc511++;
+ stats->prc1023--;
+ } else if(frame_len == 1023) {
+ stats->prc1023++;
+ stats->prc1522--;
+ } else if(frame_len == 1522) {
+ stats->prc1522++;
+ }
+}
+
+/******************************************************************************
+ * Gets the current PCI bus type, speed, and width of the hardware
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+void
+em_get_bus_info(struct em_hw *hw)
+{
+ uint32_t status;
+
+ switch (hw->mac_type) {
+ case em_82542_rev2_0:
+ case em_82542_rev2_1:
+ hw->bus_type = em_bus_type_unknown;
+ hw->bus_speed = em_bus_speed_unknown;
+ hw->bus_width = em_bus_width_unknown;
+ break;
+ case em_82573:
+ hw->bus_type = em_bus_type_pci_express;
+ hw->bus_speed = em_bus_speed_2500;
+ hw->bus_width = em_bus_width_pciex_4;
+ break;
+ default:
+ status = E1000_READ_REG(hw, STATUS);
+ hw->bus_type = (status & E1000_STATUS_PCIX_MODE) ?
+ em_bus_type_pcix : em_bus_type_pci;
+
+ if(hw->device_id == E1000_DEV_ID_82546EB_QUAD_COPPER) {
+ hw->bus_speed = (hw->bus_type == em_bus_type_pci) ?
+ em_bus_speed_66 : em_bus_speed_120;
+ } else if(hw->bus_type == em_bus_type_pci) {
+ hw->bus_speed = (status & E1000_STATUS_PCI66) ?
+ em_bus_speed_66 : em_bus_speed_33;
+ } else {
+ switch (status & E1000_STATUS_PCIX_SPEED) {
+ case E1000_STATUS_PCIX_SPEED_66:
+ hw->bus_speed = em_bus_speed_66;
+ break;
+ case E1000_STATUS_PCIX_SPEED_100:
+ hw->bus_speed = em_bus_speed_100;
+ break;
+ case E1000_STATUS_PCIX_SPEED_133:
+ hw->bus_speed = em_bus_speed_133;
+ break;
+ default:
+ hw->bus_speed = em_bus_speed_reserved;
+ break;
+ }
+ }
+ hw->bus_width = (status & E1000_STATUS_BUS64) ?
+ em_bus_width_64 : em_bus_width_32;
+ break;
+ }
+}
+/******************************************************************************
+ * Reads a value from one of the devices registers using port I/O (as opposed
+ * memory mapped I/O). Only 82544 and newer devices support port I/O.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * offset - offset to read from
+ *****************************************************************************/
+uint32_t
+em_read_reg_io(struct em_hw *hw,
+ uint32_t offset)
+{
+ unsigned long io_addr = hw->io_base;
+ unsigned long io_data = hw->io_base + 4;
+
+ em_io_write(hw, io_addr, offset);
+ return em_io_read(hw, io_data);
+}
+
+/******************************************************************************
+ * Writes a value to one of the devices registers using port I/O (as opposed to
+ * memory mapped I/O). Only 82544 and newer devices support port I/O.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * offset - offset to write to
+ * value - value to write
+ *****************************************************************************/
+void
+em_write_reg_io(struct em_hw *hw,
+ uint32_t offset,
+ uint32_t value)
+{
+ unsigned long io_addr = hw->io_base;
+ unsigned long io_data = hw->io_base + 4;
+
+ em_io_write(hw, io_addr, offset);
+ em_io_write(hw, io_data, value);
+}
+
+
+/******************************************************************************
+ * Estimates the cable length.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * min_length - The estimated minimum length
+ * max_length - The estimated maximum length
+ *
+ * returns: - E1000_ERR_XXX
+ * E1000_SUCCESS
+ *
+ * This function always returns a ranged length (minimum & maximum).
+ * So for M88 phy's, this function interprets the one value returned from the
+ * register to the minimum and maximum range.
+ * For IGP phy's, the function calculates the range by the AGC registers.
+ *****************************************************************************/
+int32_t
+em_get_cable_length(struct em_hw *hw,
+ uint16_t *min_length,
+ uint16_t *max_length)
+{
+ int32_t ret_val;
+ uint16_t agc_value = 0;
+ uint16_t cur_agc, min_agc = IGP01E1000_AGC_LENGTH_TABLE_SIZE;
+ uint16_t i, phy_data;
+ uint16_t cable_length;
+
+ DEBUGFUNC("em_get_cable_length");
+
+ *min_length = *max_length = 0;
+
+ /* Use old method for Phy older than IGP */
+ if(hw->phy_type == em_phy_m88) {
+
+ ret_val = em_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS,
+ &phy_data);
+ if(ret_val)
+ return ret_val;
+ cable_length = (phy_data & M88E1000_PSSR_CABLE_LENGTH) >>
+ M88E1000_PSSR_CABLE_LENGTH_SHIFT;
+
+ /* Convert the enum value to ranged values */
+ switch (cable_length) {
+ case em_cable_length_50:
+ *min_length = 0;
+ *max_length = em_igp_cable_length_50;
+ break;
+ case em_cable_length_50_80:
+ *min_length = em_igp_cable_length_50;
+ *max_length = em_igp_cable_length_80;
+ break;
+ case em_cable_length_80_110:
+ *min_length = em_igp_cable_length_80;
+ *max_length = em_igp_cable_length_110;
+ break;
+ case em_cable_length_110_140:
+ *min_length = em_igp_cable_length_110;
+ *max_length = em_igp_cable_length_140;
+ break;
+ case em_cable_length_140:
+ *min_length = em_igp_cable_length_140;
+ *max_length = em_igp_cable_length_170;
+ break;
+ default:
+ return -E1000_ERR_PHY;
+ break;
+ }
+ } else if(hw->phy_type == em_phy_igp) { /* For IGP PHY */
+ uint16_t agc_reg_array[IGP01E1000_PHY_CHANNEL_NUM] =
+ {IGP01E1000_PHY_AGC_A,
+ IGP01E1000_PHY_AGC_B,
+ IGP01E1000_PHY_AGC_C,
+ IGP01E1000_PHY_AGC_D};
+ /* Read the AGC registers for all channels */
+ for(i = 0; i < IGP01E1000_PHY_CHANNEL_NUM; i++) {
+
+ ret_val = em_read_phy_reg(hw, agc_reg_array[i], &phy_data);
+ if(ret_val)
+ return ret_val;
+
+ cur_agc = phy_data >> IGP01E1000_AGC_LENGTH_SHIFT;
+
+ /* Array bound check. */
+ if((cur_agc >= IGP01E1000_AGC_LENGTH_TABLE_SIZE - 1) ||
+ (cur_agc == 0))
+ return -E1000_ERR_PHY;
+
+ agc_value += cur_agc;
+
+ /* Update minimal AGC value. */
+ if(min_agc > cur_agc)
+ min_agc = cur_agc;
+ }
+
+ /* Remove the minimal AGC result for length < 50m */
+ if(agc_value < IGP01E1000_PHY_CHANNEL_NUM * em_igp_cable_length_50) {
+ agc_value -= min_agc;
+
+ /* Get the average length of the remaining 3 channels */
+ agc_value /= (IGP01E1000_PHY_CHANNEL_NUM - 1);
+ } else {
+ /* Get the average length of all the 4 channels. */
+ agc_value /= IGP01E1000_PHY_CHANNEL_NUM;
+ }
+
+ /* Set the range of the calculated length. */
+ *min_length = ((em_igp_cable_length_table[agc_value] -
+ IGP01E1000_AGC_RANGE) > 0) ?
+ (em_igp_cable_length_table[agc_value] -
+ IGP01E1000_AGC_RANGE) : 0;
+ *max_length = em_igp_cable_length_table[agc_value] +
+ IGP01E1000_AGC_RANGE;
+ }
+
+ return E1000_SUCCESS;
+}
+
+/******************************************************************************
+ * Check the cable polarity
+ *
+ * hw - Struct containing variables accessed by shared code
+ * polarity - output parameter : 0 - Polarity is not reversed
+ * 1 - Polarity is reversed.
+ *
+ * returns: - E1000_ERR_XXX
+ * E1000_SUCCESS
+ *
+ * For phy's older then IGP, this function simply reads the polarity bit in the
+ * Phy Status register. For IGP phy's, this bit is valid only if link speed is
+ * 10 Mbps. If the link speed is 100 Mbps there is no polarity so this bit will
+ * return 0. If the link speed is 1000 Mbps the polarity status is in the
+ * IGP01E1000_PHY_PCS_INIT_REG.
+ *****************************************************************************/
+int32_t
+em_check_polarity(struct em_hw *hw,
+ uint16_t *polarity)
+{
+ int32_t ret_val;
+ uint16_t phy_data;
+#ifdef __rtems__
+ *polarity = 0; /* keep compiler happy */
+#endif
+
+ DEBUGFUNC("em_check_polarity");
+
+ if(hw->phy_type == em_phy_m88) {
+ /* return the Polarity bit in the Status register. */
+ ret_val = em_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS,
+ &phy_data);
+ if(ret_val)
+ return ret_val;
+ *polarity = (phy_data & M88E1000_PSSR_REV_POLARITY) >>
+ M88E1000_PSSR_REV_POLARITY_SHIFT;
+ } else if(hw->phy_type == em_phy_igp ||
+ hw->phy_type == em_phy_igp_2) {
+ /* Read the Status register to check the speed */
+ ret_val = em_read_phy_reg(hw, IGP01E1000_PHY_PORT_STATUS,
+ &phy_data);
+ if(ret_val)
+ return ret_val;
+
+ /* If speed is 1000 Mbps, must read the IGP01E1000_PHY_PCS_INIT_REG to
+ * find the polarity status */
+ if((phy_data & IGP01E1000_PSSR_SPEED_MASK) ==
+ IGP01E1000_PSSR_SPEED_1000MBPS) {
+
+ /* Read the GIG initialization PCS register (0x00B4) */
+ ret_val = em_read_phy_reg(hw, IGP01E1000_PHY_PCS_INIT_REG,
+ &phy_data);
+ if(ret_val)
+ return ret_val;
+
+ /* Check the polarity bits */
+ *polarity = (phy_data & IGP01E1000_PHY_POLARITY_MASK) ? 1 : 0;
+ } else {
+ /* For 10 Mbps, read the polarity bit in the status register. (for
+ * 100 Mbps this bit is always 0) */
+ *polarity = phy_data & IGP01E1000_PSSR_POLARITY_REVERSED;
+ }
+ }
+ return E1000_SUCCESS;
+}
+
+/******************************************************************************
+ * Check if Downshift occured
+ *
+ * hw - Struct containing variables accessed by shared code
+ * downshift - output parameter : 0 - No Downshift ocured.
+ * 1 - Downshift ocured.
+ *
+ * returns: - E1000_ERR_XXX
+ * E1000_SUCCESS
+ *
+ * For phy's older then IGP, this function reads the Downshift bit in the Phy
+ * Specific Status register. For IGP phy's, it reads the Downgrade bit in the
+ * Link Health register. In IGP this bit is latched high, so the driver must
+ * read it immediately after link is established.
+ *****************************************************************************/
+int32_t
+em_check_downshift(struct em_hw *hw)
+{
+ int32_t ret_val;
+ uint16_t phy_data;
+
+ DEBUGFUNC("em_check_downshift");
+
+ if(hw->phy_type == em_phy_igp ||
+ hw->phy_type == em_phy_igp_2) {
+ ret_val = em_read_phy_reg(hw, IGP01E1000_PHY_LINK_HEALTH,
+ &phy_data);
+ if(ret_val)
+ return ret_val;
+
+ hw->speed_downgraded = (phy_data & IGP01E1000_PLHR_SS_DOWNGRADE) ? 1 : 0;
+ } else if(hw->phy_type == em_phy_m88) {
+ ret_val = em_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS,
+ &phy_data);
+ if(ret_val)
+ return ret_val;
+
+ hw->speed_downgraded = (phy_data & M88E1000_PSSR_DOWNSHIFT) >>
+ M88E1000_PSSR_DOWNSHIFT_SHIFT;
+ }
+
+ return E1000_SUCCESS;
+}
+
+/*****************************************************************************
+ *
+ * 82541_rev_2 & 82547_rev_2 have the capability to configure the DSP when a
+ * gigabit link is achieved to improve link quality.
+ *
+ * hw: Struct containing variables accessed by shared code
+ *
+ * returns: - E1000_ERR_PHY if fail to read/write the PHY
+ * E1000_SUCCESS at any other case.
+ *
+ ****************************************************************************/
+
+int32_t
+em_config_dsp_after_link_change(struct em_hw *hw,
+ boolean_t link_up)
+{
+ int32_t ret_val;
+ uint16_t phy_data, phy_saved_data, speed, duplex, i;
+ uint16_t dsp_reg_array[IGP01E1000_PHY_CHANNEL_NUM] =
+ {IGP01E1000_PHY_AGC_PARAM_A,
+ IGP01E1000_PHY_AGC_PARAM_B,
+ IGP01E1000_PHY_AGC_PARAM_C,
+ IGP01E1000_PHY_AGC_PARAM_D};
+ uint16_t min_length, max_length;
+
+ DEBUGFUNC("em_config_dsp_after_link_change");
+
+ if(hw->phy_type != em_phy_igp)
+ return E1000_SUCCESS;
+
+ if(link_up) {
+ ret_val = em_get_speed_and_duplex(hw, &speed, &duplex);
+ if(ret_val) {
+ DEBUGOUT("Error getting link speed and duplex\n");
+ return ret_val;
+ }
+
+ if(speed == SPEED_1000) {
+
+ em_get_cable_length(hw, &min_length, &max_length);
+
+ if((hw->dsp_config_state == em_dsp_config_enabled) &&
+ min_length >= em_igp_cable_length_50) {
+
+ for(i = 0; i < IGP01E1000_PHY_CHANNEL_NUM; i++) {
+ ret_val = em_read_phy_reg(hw, dsp_reg_array[i],
+ &phy_data);
+ if(ret_val)
+ return ret_val;
+
+ phy_data &= ~IGP01E1000_PHY_EDAC_MU_INDEX;
+
+ ret_val = em_write_phy_reg(hw, dsp_reg_array[i],
+ phy_data);
+ if(ret_val)
+ return ret_val;
+ }
+ hw->dsp_config_state = em_dsp_config_activated;
+ }
+
+ if((hw->ffe_config_state == em_ffe_config_enabled) &&
+ (min_length < em_igp_cable_length_50)) {
+
+ uint16_t ffe_idle_err_timeout = FFE_IDLE_ERR_COUNT_TIMEOUT_20;
+ uint32_t idle_errs = 0;
+
+ /* clear previous idle error counts */
+ ret_val = em_read_phy_reg(hw, PHY_1000T_STATUS,
+ &phy_data);
+ if(ret_val)
+ return ret_val;
+
+ for(i = 0; i < ffe_idle_err_timeout; i++) {
+ usec_delay(1000);
+ ret_val = em_read_phy_reg(hw, PHY_1000T_STATUS,
+ &phy_data);
+ if(ret_val)
+ return ret_val;
+
+ idle_errs += (phy_data & SR_1000T_IDLE_ERROR_CNT);
+ if(idle_errs > SR_1000T_PHY_EXCESSIVE_IDLE_ERR_COUNT) {
+ hw->ffe_config_state = em_ffe_config_active;
+
+ ret_val = em_write_phy_reg(hw,
+ IGP01E1000_PHY_DSP_FFE,
+ IGP01E1000_PHY_DSP_FFE_CM_CP);
+ if(ret_val)
+ return ret_val;
+ break;
+ }
+
+ if(idle_errs)
+ ffe_idle_err_timeout = FFE_IDLE_ERR_COUNT_TIMEOUT_100;
+ }
+ }
+ }
+ } else {
+ if(hw->dsp_config_state == em_dsp_config_activated) {
+ /* Save off the current value of register 0x2F5B to be restored at
+ * the end of the routines. */
+ ret_val = em_read_phy_reg(hw, 0x2F5B, &phy_saved_data);
+
+ if(ret_val)
+ return ret_val;
+
+ /* Disable the PHY transmitter */
+ ret_val = em_write_phy_reg(hw, 0x2F5B, 0x0003);
+
+ if(ret_val)
+ return ret_val;
+
+ msec_delay_irq(20);
+
+ ret_val = em_write_phy_reg(hw, 0x0000,
+ IGP01E1000_IEEE_FORCE_GIGA);
+ if(ret_val)
+ return ret_val;
+ for(i = 0; i < IGP01E1000_PHY_CHANNEL_NUM; i++) {
+ ret_val = em_read_phy_reg(hw, dsp_reg_array[i], &phy_data);
+ if(ret_val)
+ return ret_val;
+
+ phy_data &= ~IGP01E1000_PHY_EDAC_MU_INDEX;
+ phy_data |= IGP01E1000_PHY_EDAC_SIGN_EXT_9_BITS;
+
+ ret_val = em_write_phy_reg(hw,dsp_reg_array[i], phy_data);
+ if(ret_val)
+ return ret_val;
+ }
+
+ ret_val = em_write_phy_reg(hw, 0x0000,
+ IGP01E1000_IEEE_RESTART_AUTONEG);
+ if(ret_val)
+ return ret_val;
+
+ msec_delay_irq(20);
+
+ /* Now enable the transmitter */
+ ret_val = em_write_phy_reg(hw, 0x2F5B, phy_saved_data);
+
+ if(ret_val)
+ return ret_val;
+
+ hw->dsp_config_state = em_dsp_config_enabled;
+ }
+
+ if(hw->ffe_config_state == em_ffe_config_active) {
+ /* Save off the current value of register 0x2F5B to be restored at
+ * the end of the routines. */
+ ret_val = em_read_phy_reg(hw, 0x2F5B, &phy_saved_data);
+
+ if(ret_val)
+ return ret_val;
+
+ /* Disable the PHY transmitter */
+ ret_val = em_write_phy_reg(hw, 0x2F5B, 0x0003);
+
+ if(ret_val)
+ return ret_val;
+
+ msec_delay_irq(20);
+
+ ret_val = em_write_phy_reg(hw, 0x0000,
+ IGP01E1000_IEEE_FORCE_GIGA);
+ if(ret_val)
+ return ret_val;
+ ret_val = em_write_phy_reg(hw, IGP01E1000_PHY_DSP_FFE,
+ IGP01E1000_PHY_DSP_FFE_DEFAULT);
+ if(ret_val)
+ return ret_val;
+
+ ret_val = em_write_phy_reg(hw, 0x0000,
+ IGP01E1000_IEEE_RESTART_AUTONEG);
+ if(ret_val)
+ return ret_val;
+
+ msec_delay_irq(20);
+
+ /* Now enable the transmitter */
+ ret_val = em_write_phy_reg(hw, 0x2F5B, phy_saved_data);
+
+ if(ret_val)
+ return ret_val;
+
+ hw->ffe_config_state = em_ffe_config_enabled;
+ }
+ }
+ return E1000_SUCCESS;
+}
+
+/*****************************************************************************
+ * Set PHY to class A mode
+ * Assumes the following operations will follow to enable the new class mode.
+ * 1. Do a PHY soft reset
+ * 2. Restart auto-negotiation or force link.
+ *
+ * hw - Struct containing variables accessed by shared code
+ ****************************************************************************/
+static int32_t
+em_set_phy_mode(struct em_hw *hw)
+{
+ int32_t ret_val;
+ uint16_t eeprom_data;
+
+ DEBUGFUNC("em_set_phy_mode");
+
+ if((hw->mac_type == em_82545_rev_3) &&
+ (hw->media_type == em_media_type_copper)) {
+ ret_val = em_read_eeprom(hw, EEPROM_PHY_CLASS_WORD, 1, &eeprom_data);
+ if(ret_val) {
+ return ret_val;
+ }
+
+ if((eeprom_data != EEPROM_RESERVED_WORD) &&
+ (eeprom_data & EEPROM_PHY_CLASS_A)) {
+ ret_val = em_write_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x000B);
+ if(ret_val)
+ return ret_val;
+ ret_val = em_write_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, 0x8104);
+ if(ret_val)
+ return ret_val;
+
+ hw->phy_reset_disable = FALSE;
+ }
+ }
+
+ return E1000_SUCCESS;
+}
+
+/*****************************************************************************
+ *
+ * This function sets the lplu state according to the active flag. When
+ * activating lplu this function also disables smart speed and vise versa.
+ * lplu will not be activated unless the device autonegotiation advertisment
+ * meets standards of either 10 or 10/100 or 10/100/1000 at all duplexes.
+ * hw: Struct containing variables accessed by shared code
+ * active - true to enable lplu false to disable lplu.
+ *
+ * returns: - E1000_ERR_PHY if fail to read/write the PHY
+ * E1000_SUCCESS at any other case.
+ *
+ ****************************************************************************/
+
+int32_t
+em_set_d3_lplu_state(struct em_hw *hw,
+ boolean_t active)
+{
+ int32_t ret_val;
+ uint16_t phy_data;
+ DEBUGFUNC("em_set_d3_lplu_state");
+
+ if(hw->phy_type != em_phy_igp && hw->phy_type != em_phy_igp_2)
+ return E1000_SUCCESS;
+
+ /* During driver activity LPLU should not be used or it will attain link
+ * from the lowest speeds starting from 10Mbps. The capability is used for
+ * Dx transitions and states */
+ if(hw->mac_type == em_82541_rev_2 || hw->mac_type == em_82547_rev_2) {
+ ret_val = em_read_phy_reg(hw, IGP01E1000_GMII_FIFO, &phy_data);
+ if(ret_val)
+ return ret_val;
+ } else {
+ ret_val = em_read_phy_reg(hw, IGP02E1000_PHY_POWER_MGMT, &phy_data);
+ if(ret_val)
+ return ret_val;
+ }
+
+ if(!active) {
+ if(hw->mac_type == em_82541_rev_2 ||
+ hw->mac_type == em_82547_rev_2) {
+ phy_data &= ~IGP01E1000_GMII_FLEX_SPD;
+ ret_val = em_write_phy_reg(hw, IGP01E1000_GMII_FIFO, phy_data);
+ if(ret_val)
+ return ret_val;
+ } else {
+ phy_data &= ~IGP02E1000_PM_D3_LPLU;
+ ret_val = em_write_phy_reg(hw, IGP02E1000_PHY_POWER_MGMT,
+ phy_data);
+ if (ret_val)
+ return ret_val;
+ }
+
+ /* LPLU and SmartSpeed are mutually exclusive. LPLU is used during
+ * Dx states where the power conservation is most important. During
+ * driver activity we should enable SmartSpeed, so performance is
+ * maintained. */
+ if (hw->smart_speed == em_smart_speed_on) {
+ ret_val = em_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
+ &phy_data);
+ if(ret_val)
+ return ret_val;
+
+ phy_data |= IGP01E1000_PSCFR_SMART_SPEED;
+ ret_val = em_write_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
+ phy_data);
+ if(ret_val)
+ return ret_val;
+ } else if (hw->smart_speed == em_smart_speed_off) {
+ ret_val = em_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
+ &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ phy_data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+ ret_val = em_write_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
+ phy_data);
+ if(ret_val)
+ return ret_val;
+ }
+
+ } else if((hw->autoneg_advertised == AUTONEG_ADVERTISE_SPEED_DEFAULT) ||
+ (hw->autoneg_advertised == AUTONEG_ADVERTISE_10_ALL ) ||
+ (hw->autoneg_advertised == AUTONEG_ADVERTISE_10_100_ALL)) {
+
+ if(hw->mac_type == em_82541_rev_2 ||
+ hw->mac_type == em_82547_rev_2) {
+ phy_data |= IGP01E1000_GMII_FLEX_SPD;
+ ret_val = em_write_phy_reg(hw, IGP01E1000_GMII_FIFO, phy_data);
+ if(ret_val)
+ return ret_val;
+ } else {
+ phy_data |= IGP02E1000_PM_D3_LPLU;
+ ret_val = em_write_phy_reg(hw, IGP02E1000_PHY_POWER_MGMT,
+ phy_data);
+ if (ret_val)
+ return ret_val;
+ }
+
+ /* When LPLU is enabled we should disable SmartSpeed */
+ ret_val = em_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG, &phy_data);
+ if(ret_val)
+ return ret_val;
+
+ phy_data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+ ret_val = em_write_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG, phy_data);
+ if(ret_val)
+ return ret_val;
+
+ }
+ return E1000_SUCCESS;
+}
+
+/*****************************************************************************
+ *
+ * This function sets the lplu d0 state according to the active flag. When
+ * activating lplu this function also disables smart speed and vise versa.
+ * lplu will not be activated unless the device autonegotiation advertisment
+ * meets standards of either 10 or 10/100 or 10/100/1000 at all duplexes.
+ * hw: Struct containing variables accessed by shared code
+ * active - true to enable lplu false to disable lplu.
+ *
+ * returns: - E1000_ERR_PHY if fail to read/write the PHY
+ * E1000_SUCCESS at any other case.
+ *
+ ****************************************************************************/
+
+int32_t
+em_set_d0_lplu_state(struct em_hw *hw,
+ boolean_t active)
+{
+ int32_t ret_val;
+ uint16_t phy_data;
+ DEBUGFUNC("em_set_d0_lplu_state");
+
+ if(hw->mac_type <= em_82547_rev_2)
+ return E1000_SUCCESS;
+
+ ret_val = em_read_phy_reg(hw, IGP02E1000_PHY_POWER_MGMT, &phy_data);
+ if(ret_val)
+ return ret_val;
+
+ if (!active) {
+ phy_data &= ~IGP02E1000_PM_D0_LPLU;
+ ret_val = em_write_phy_reg(hw, IGP02E1000_PHY_POWER_MGMT, phy_data);
+ if (ret_val)
+ return ret_val;
+
+ /* LPLU and SmartSpeed are mutually exclusive. LPLU is used during
+ * Dx states where the power conservation is most important. During
+ * driver activity we should enable SmartSpeed, so performance is
+ * maintained. */
+ if (hw->smart_speed == em_smart_speed_on) {
+ ret_val = em_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
+ &phy_data);
+ if(ret_val)
+ return ret_val;
+
+ phy_data |= IGP01E1000_PSCFR_SMART_SPEED;
+ ret_val = em_write_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
+ phy_data);
+ if(ret_val)
+ return ret_val;
+ } else if (hw->smart_speed == em_smart_speed_off) {
+ ret_val = em_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
+ &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ phy_data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+ ret_val = em_write_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
+ phy_data);
+ if(ret_val)
+ return ret_val;
+ }
+
+
+ } else {
+
+ phy_data |= IGP02E1000_PM_D0_LPLU;
+ ret_val = em_write_phy_reg(hw, IGP02E1000_PHY_POWER_MGMT, phy_data);
+ if (ret_val)
+ return ret_val;
+
+ /* When LPLU is enabled we should disable SmartSpeed */
+ ret_val = em_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG, &phy_data);
+ if(ret_val)
+ return ret_val;
+
+ phy_data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+ ret_val = em_write_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG, phy_data);
+ if(ret_val)
+ return ret_val;
+
+ }
+ return E1000_SUCCESS;
+}
+
+/******************************************************************************
+ * Change VCO speed register to improve Bit Error Rate performance of SERDES.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+static int32_t
+em_set_vco_speed(struct em_hw *hw)
+{
+ int32_t ret_val;
+ uint16_t default_page = 0;
+ uint16_t phy_data;
+
+ DEBUGFUNC("em_set_vco_speed");
+
+ switch(hw->mac_type) {
+ case em_82545_rev_3:
+ case em_82546_rev_3:
+ break;
+ default:
+ return E1000_SUCCESS;
+ }
+
+ /* Set PHY register 30, page 5, bit 8 to 0 */
+
+ ret_val = em_read_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, &default_page);
+ if(ret_val)
+ return ret_val;
+
+ ret_val = em_write_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x0005);
+ if(ret_val)
+ return ret_val;
+
+ ret_val = em_read_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, &phy_data);
+ if(ret_val)
+ return ret_val;
+
+ phy_data &= ~M88E1000_PHY_VCO_REG_BIT8;
+ ret_val = em_write_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, phy_data);
+ if(ret_val)
+ return ret_val;
+
+ /* Set PHY register 30, page 4, bit 11 to 1 */
+
+ ret_val = em_write_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x0004);
+ if(ret_val)
+ return ret_val;
+
+ ret_val = em_read_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, &phy_data);
+ if(ret_val)
+ return ret_val;
+
+ phy_data |= M88E1000_PHY_VCO_REG_BIT11;
+ ret_val = em_write_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, phy_data);
+ if(ret_val)
+ return ret_val;
+
+ ret_val = em_write_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, default_page);
+ if(ret_val)
+ return ret_val;
+
+ return E1000_SUCCESS;
+}
+
+
+/*****************************************************************************
+ * This function reads the cookie from ARC ram.
+ *
+ * returns: - E1000_SUCCESS .
+ ****************************************************************************/
+int32_t
+em_host_if_read_cookie(struct em_hw * hw, uint8_t *buffer)
+{
+ uint8_t i;
+ uint32_t offset = E1000_MNG_DHCP_COOKIE_OFFSET;
+ uint8_t length = E1000_MNG_DHCP_COOKIE_LENGTH;
+
+ length = (length >> 2);
+ offset = (offset >> 2);
+
+ for (i = 0; i < length; i++) {
+ *((uint32_t *) buffer + i) =
+ E1000_READ_REG_ARRAY_DWORD(hw, HOST_IF, offset + i);
+ }
+ return E1000_SUCCESS;
+}
+
+
+/*****************************************************************************
+ * This function checks whether the HOST IF is enabled for command operaton
+ * and also checks whether the previous command is completed.
+ * It busy waits in case of previous command is not completed.
+ *
+ * returns: - E1000_ERR_HOST_INTERFACE_COMMAND in case if is not ready or
+ * timeout
+ * - E1000_SUCCESS for success.
+ ****************************************************************************/
+int32_t
+em_mng_enable_host_if(struct em_hw * hw)
+{
+ uint32_t hicr;
+ uint8_t i;
+
+ /* Check that the host interface is enabled. */
+ hicr = E1000_READ_REG(hw, HICR);
+ if ((hicr & E1000_HICR_EN) == 0) {
+ DEBUGOUT("E1000_HOST_EN bit disabled.\n");
+ return -E1000_ERR_HOST_INTERFACE_COMMAND;
+ }
+ /* check the previous command is completed */
+ for (i = 0; i < E1000_MNG_DHCP_COMMAND_TIMEOUT; i++) {
+ hicr = E1000_READ_REG(hw, HICR);
+ if (!(hicr & E1000_HICR_C))
+ break;
+ msec_delay_irq(1);
+ }
+
+ if (i == E1000_MNG_DHCP_COMMAND_TIMEOUT) {
+ DEBUGOUT("Previous command timeout failed .\n");
+ return -E1000_ERR_HOST_INTERFACE_COMMAND;
+ }
+ return E1000_SUCCESS;
+}
+
+/*****************************************************************************
+ * This function writes the buffer content at the offset given on the host if.
+ * It also does alignment considerations to do the writes in most efficient way.
+ * Also fills up the sum of the buffer in *buffer parameter.
+ *
+ * returns - E1000_SUCCESS for success.
+ ****************************************************************************/
+int32_t
+em_mng_host_if_write(struct em_hw * hw, uint8_t *buffer,
+ uint16_t length, uint16_t offset, uint8_t *sum)
+{
+ uint8_t *tmp;
+ uint8_t *bufptr = buffer;
+ uint32_t data;
+ uint16_t remaining, i, j, prev_bytes;
+
+ /* sum = only sum of the data and it is not checksum */
+
+ if (length == 0 || offset + length > E1000_HI_MAX_MNG_DATA_LENGTH) {
+ return -E1000_ERR_PARAM;
+ }
+
+ tmp = (uint8_t *)&data;
+ prev_bytes = offset & 0x3;
+ offset &= 0xFFFC;
+ offset >>= 2;
+
+ if (prev_bytes) {
+ data = E1000_READ_REG_ARRAY_DWORD(hw, HOST_IF, offset);
+ for (j = prev_bytes; j < sizeof(uint32_t); j++) {
+ *(tmp + j) = *bufptr++;
+ *sum += *(tmp + j);
+ }
+ E1000_WRITE_REG_ARRAY_DWORD(hw, HOST_IF, offset, data);
+ length -= j - prev_bytes;
+ offset++;
+ }
+
+ remaining = length & 0x3;
+ length -= remaining;
+
+ /* Calculate length in DWORDs */
+ length >>= 2;
+
+ /* The device driver writes the relevant command block into the
+ * ram area. */
+ for (i = 0; i < length; i++) {
+ for (j = 0; j < sizeof(uint32_t); j++) {
+ *(tmp + j) = *bufptr++;
+ *sum += *(tmp + j);
+ }
+
+ E1000_WRITE_REG_ARRAY_DWORD(hw, HOST_IF, offset + i, data);
+ }
+ if (remaining) {
+ for (j = 0; j < sizeof(uint32_t); j++) {
+ if (j < remaining)
+ *(tmp + j) = *bufptr++;
+ else
+ *(tmp + j) = 0;
+
+ *sum += *(tmp + j);
+ }
+ E1000_WRITE_REG_ARRAY_DWORD(hw, HOST_IF, offset + i, data);
+ }
+
+ return E1000_SUCCESS;
+}
+
+
+/*****************************************************************************
+ * This function writes the command header after does the checksum calculation.
+ *
+ * returns - E1000_SUCCESS for success.
+ ****************************************************************************/
+int32_t
+em_mng_write_cmd_header(struct em_hw * hw,
+ struct em_host_mng_command_header * hdr)
+{
+ uint16_t i;
+ uint8_t sum;
+ uint8_t *buffer;
+
+ /* Write the whole command header structure which includes sum of
+ * the buffer */
+
+ uint16_t length = sizeof(struct em_host_mng_command_header);
+
+ sum = hdr->checksum;
+ hdr->checksum = 0;
+
+ buffer = (uint8_t *) hdr;
+ i = length;
+ while(i--)
+ sum += buffer[i];
+
+ hdr->checksum = 0 - sum;
+
+ length >>= 2;
+ /* The device driver writes the relevant command block into the ram area. */
+ for (i = 0; i < length; i++)
+ E1000_WRITE_REG_ARRAY_DWORD(hw, HOST_IF, i, *((uint32_t *) hdr + i));
+
+ return E1000_SUCCESS;
+}
+
+
+/*****************************************************************************
+ * This function indicates to ARC that a new command is pending which completes
+ * one write operation by the driver.
+ *
+ * returns - E1000_SUCCESS for success.
+ ****************************************************************************/
+int32_t
+em_mng_write_commit(
+ struct em_hw * hw)
+{
+ uint32_t hicr;
+
+ hicr = E1000_READ_REG(hw, HICR);
+ /* Setting this bit tells the ARC that a new command is pending. */
+ E1000_WRITE_REG(hw, HICR, hicr | E1000_HICR_C);
+
+ return E1000_SUCCESS;
+}
+
+
+/*****************************************************************************
+ * This function checks the mode of the firmware.
+ *
+ * returns - TRUE when the mode is IAMT or FALSE.
+ ****************************************************************************/
+boolean_t
+em_check_mng_mode(
+ struct em_hw *hw)
+{
+ uint32_t fwsm;
+
+ fwsm = E1000_READ_REG(hw, FWSM);
+
+ if((fwsm & E1000_FWSM_MODE_MASK) ==
+ (E1000_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT))
+ return TRUE;
+
+ return FALSE;
+}
+
+
+/*****************************************************************************
+ * This function writes the dhcp info .
+ ****************************************************************************/
+int32_t
+em_mng_write_dhcp_info(struct em_hw * hw, uint8_t *buffer,
+ uint16_t length)
+{
+ int32_t ret_val;
+ struct em_host_mng_command_header hdr;
+
+ hdr.command_id = E1000_MNG_DHCP_TX_PAYLOAD_CMD;
+ hdr.command_length = length;
+ hdr.reserved1 = 0;
+ hdr.reserved2 = 0;
+ hdr.checksum = 0;
+
+ ret_val = em_mng_enable_host_if(hw);
+ if (ret_val == E1000_SUCCESS) {
+ ret_val = em_mng_host_if_write(hw, buffer, length, sizeof(hdr),
+ &(hdr.checksum));
+ if (ret_val == E1000_SUCCESS) {
+ ret_val = em_mng_write_cmd_header(hw, &hdr);
+ if (ret_val == E1000_SUCCESS)
+ ret_val = em_mng_write_commit(hw);
+ }
+ }
+ return ret_val;
+}
+
+
+/*****************************************************************************
+ * This function calculates the checksum.
+ *
+ * returns - checksum of buffer contents.
+ ****************************************************************************/
+uint8_t
+em_calculate_mng_checksum(char *buffer, uint32_t length)
+{
+ uint8_t sum = 0;
+ uint32_t i;
+
+ if (!buffer)
+ return 0;
+
+ for (i=0; i < length; i++)
+ sum += buffer[i];
+
+ return (uint8_t) (0 - sum);
+}
+
+/*****************************************************************************
+ * This function checks whether tx pkt filtering needs to be enabled or not.
+ *
+ * returns - TRUE for packet filtering or FALSE.
+ ****************************************************************************/
+boolean_t
+em_enable_tx_pkt_filtering(struct em_hw *hw)
+{
+ /* called in init as well as watchdog timer functions */
+
+ int32_t ret_val, checksum;
+ boolean_t tx_filter = FALSE;
+ struct em_host_mng_dhcp_cookie *hdr = &(hw->mng_cookie);
+ uint8_t *buffer = (uint8_t *) &(hw->mng_cookie);
+
+ if (em_check_mng_mode(hw)) {
+ ret_val = em_mng_enable_host_if(hw);
+ if (ret_val == E1000_SUCCESS) {
+ ret_val = em_host_if_read_cookie(hw, buffer);
+ if (ret_val == E1000_SUCCESS) {
+ checksum = hdr->checksum;
+ hdr->checksum = 0;
+ if ((hdr->signature == E1000_IAMT_SIGNATURE) &&
+ checksum == em_calculate_mng_checksum((char *)buffer,
+ E1000_MNG_DHCP_COOKIE_LENGTH)) {
+ if (hdr->status &
+ E1000_MNG_DHCP_COOKIE_STATUS_PARSING_SUPPORT)
+ tx_filter = TRUE;
+ } else
+ tx_filter = TRUE;
+ } else
+ tx_filter = TRUE;
+ }
+ }
+
+ hw->tx_pkt_filtering = tx_filter;
+ return tx_filter;
+}
+
+/******************************************************************************
+ * Verifies the hardware needs to allow ARPs to be processed by the host
+ *
+ * hw - Struct containing variables accessed by shared code
+ *
+ * returns: - TRUE/FALSE
+ *
+ *****************************************************************************/
+uint32_t
+em_enable_mng_pass_thru(struct em_hw *hw)
+{
+ uint32_t manc;
+ uint32_t fwsm, factps;
+
+ if (hw->asf_firmware_present) {
+ manc = E1000_READ_REG(hw, MANC);
+
+ if (!(manc & E1000_MANC_RCV_TCO_EN) ||
+ !(manc & E1000_MANC_EN_MAC_ADDR_FILTER))
+ return FALSE;
+ if (em_arc_subsystem_valid(hw) == TRUE) {
+ fwsm = E1000_READ_REG(hw, FWSM);
+ factps = E1000_READ_REG(hw, FACTPS);
+
+ if (((fwsm & E1000_FWSM_MODE_MASK) ==
+ (em_mng_mode_pt << E1000_FWSM_MODE_SHIFT)) &&
+ (factps & E1000_FACTPS_MNGCG))
+ return TRUE;
+ } else
+ if ((manc & E1000_MANC_SMBUS_EN) && !(manc & E1000_MANC_ASF_EN))
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static int32_t
+em_polarity_reversal_workaround(struct em_hw *hw)
+{
+ int32_t ret_val;
+ uint16_t mii_status_reg;
+ uint16_t i;
+
+ /* Polarity reversal workaround for forced 10F/10H links. */
+
+ /* Disable the transmitter on the PHY */
+
+ ret_val = em_write_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x0019);
+ if(ret_val)
+ return ret_val;
+ ret_val = em_write_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, 0xFFFF);
+ if(ret_val)
+ return ret_val;
+
+ ret_val = em_write_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x0000);
+ if(ret_val)
+ return ret_val;
+
+ /* This loop will early-out if the NO link condition has been met. */
+ for(i = PHY_FORCE_TIME; i > 0; i--) {
+ /* Read the MII Status Register and wait for Link Status bit
+ * to be clear.
+ */
+
+ ret_val = em_read_phy_reg(hw, PHY_STATUS, &mii_status_reg);
+ if(ret_val)
+ return ret_val;
+
+ ret_val = em_read_phy_reg(hw, PHY_STATUS, &mii_status_reg);
+ if(ret_val)
+ return ret_val;
+
+ if((mii_status_reg & ~MII_SR_LINK_STATUS) == 0) break;
+ msec_delay_irq(100);
+ }
+
+ /* Recommended delay time after link has been lost */
+ msec_delay_irq(1000);
+
+ /* Now we will re-enable th transmitter on the PHY */
+
+ ret_val = em_write_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x0019);
+ if(ret_val)
+ return ret_val;
+ msec_delay_irq(50);
+ ret_val = em_write_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, 0xFFF0);
+ if(ret_val)
+ return ret_val;
+ msec_delay_irq(50);
+ ret_val = em_write_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, 0xFF00);
+ if(ret_val)
+ return ret_val;
+ msec_delay_irq(50);
+ ret_val = em_write_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, 0x0000);
+ if(ret_val)
+ return ret_val;
+
+ ret_val = em_write_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x0000);
+ if(ret_val)
+ return ret_val;
+
+ /* This loop will early-out if the link condition has been met. */
+ for(i = PHY_FORCE_TIME; i > 0; i--) {
+ /* Read the MII Status Register and wait for Link Status bit
+ * to be set.
+ */
+
+ ret_val = em_read_phy_reg(hw, PHY_STATUS, &mii_status_reg);
+ if(ret_val)
+ return ret_val;
+
+ ret_val = em_read_phy_reg(hw, PHY_STATUS, &mii_status_reg);
+ if(ret_val)
+ return ret_val;
+
+ if(mii_status_reg & MII_SR_LINK_STATUS) break;
+ msec_delay_irq(100);
+ }
+ return E1000_SUCCESS;
+}
+
+/***************************************************************************
+ *
+ * Disables PCI-Express master access.
+ *
+ * hw: Struct containing variables accessed by shared code
+ *
+ * returns: - none.
+ *
+ ***************************************************************************/
+void
+em_set_pci_express_master_disable(struct em_hw *hw)
+{
+ uint32_t ctrl;
+
+ DEBUGFUNC("em_set_pci_express_master_disable");
+
+ if (hw->bus_type != em_bus_type_pci_express)
+ return;
+
+ ctrl = E1000_READ_REG(hw, CTRL);
+ ctrl |= E1000_CTRL_GIO_MASTER_DISABLE;
+ E1000_WRITE_REG(hw, CTRL, ctrl);
+}
+
+/***************************************************************************
+ *
+ * Enables PCI-Express master access.
+ *
+ * hw: Struct containing variables accessed by shared code
+ *
+ * returns: - none.
+ *
+ ***************************************************************************/
+void
+em_enable_pciex_master(struct em_hw *hw)
+{
+ uint32_t ctrl;
+
+ DEBUGFUNC("em_enable_pciex_master");
+
+ if (hw->bus_type != em_bus_type_pci_express)
+ return;
+
+ ctrl = E1000_READ_REG(hw, CTRL);
+ ctrl &= ~E1000_CTRL_GIO_MASTER_DISABLE;
+ E1000_WRITE_REG(hw, CTRL, ctrl);
+}
+
+/*******************************************************************************
+ *
+ * Disables PCI-Express master access and verifies there are no pending requests
+ *
+ * hw: Struct containing variables accessed by shared code
+ *
+ * returns: - E1000_ERR_MASTER_REQUESTS_PENDING if master disable bit hasn't
+ * caused the master requests to be disabled.
+ * E1000_SUCCESS master requests disabled.
+ *
+ ******************************************************************************/
+int32_t
+em_disable_pciex_master(struct em_hw *hw)
+{
+ int32_t timeout = MASTER_DISABLE_TIMEOUT; /* 80ms */
+
+ DEBUGFUNC("em_disable_pciex_master");
+
+ if (hw->bus_type != em_bus_type_pci_express)
+ return E1000_SUCCESS;
+
+ em_set_pci_express_master_disable(hw);
+
+ while(timeout) {
+ if(!(E1000_READ_REG(hw, STATUS) & E1000_STATUS_GIO_MASTER_ENABLE))
+ break;
+ else
+ usec_delay(100);
+ timeout--;
+ }
+
+ if(!timeout) {
+ DEBUGOUT("Master requests are pending.\n");
+ return -E1000_ERR_MASTER_REQUESTS_PENDING;
+ }
+
+ return E1000_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Check for EEPROM Auto Read bit done.
+ *
+ * hw: Struct containing variables accessed by shared code
+ *
+ * returns: - E1000_ERR_RESET if fail to reset MAC
+ * E1000_SUCCESS at any other case.
+ *
+ ******************************************************************************/
+int32_t
+em_get_auto_rd_done(struct em_hw *hw)
+{
+ int32_t timeout = AUTO_READ_DONE_TIMEOUT;
+
+ DEBUGFUNC("em_get_auto_rd_done");
+
+ switch (hw->mac_type) {
+ default:
+ msec_delay(5);
+ break;
+ case em_82573:
+ while(timeout) {
+ if (E1000_READ_REG(hw, EECD) & E1000_EECD_AUTO_RD) break;
+ else msec_delay(1);
+ timeout--;
+ }
+
+ if(!timeout) {
+ DEBUGOUT("Auto read by HW from EEPROM has not completed.\n");
+ return -E1000_ERR_RESET;
+ }
+ break;
+ }
+
+ return E1000_SUCCESS;
+}
+
+/***************************************************************************
+ * Checks if the PHY configuration is done
+ *
+ * hw: Struct containing variables accessed by shared code
+ *
+ * returns: - E1000_ERR_RESET if fail to reset MAC
+ * E1000_SUCCESS at any other case.
+ *
+ ***************************************************************************/
+int32_t
+em_get_phy_cfg_done(struct em_hw *hw)
+{
+ DEBUGFUNC("em_get_phy_cfg_done");
+
+ /* Simply wait for 10ms */
+ msec_delay(10);
+
+ return E1000_SUCCESS;
+}
+
+/***************************************************************************
+ *
+ * Using the combination of SMBI and SWESMBI semaphore bits when resetting
+ * adapter or Eeprom access.
+ *
+ * hw: Struct containing variables accessed by shared code
+ *
+ * returns: - E1000_ERR_EEPROM if fail to access EEPROM.
+ * E1000_SUCCESS at any other case.
+ *
+ ***************************************************************************/
+int32_t
+em_get_hw_eeprom_semaphore(struct em_hw *hw)
+{
+ int32_t timeout;
+ uint32_t swsm;
+
+ DEBUGFUNC("em_get_hw_eeprom_semaphore");
+
+ if(!hw->eeprom_semaphore_present)
+ return E1000_SUCCESS;
+
+
+ /* Get the FW semaphore. */
+ timeout = hw->eeprom.word_size + 1;
+ while(timeout) {
+ swsm = E1000_READ_REG(hw, SWSM);
+ swsm |= E1000_SWSM_SWESMBI;
+ E1000_WRITE_REG(hw, SWSM, swsm);
+ /* if we managed to set the bit we got the semaphore. */
+ swsm = E1000_READ_REG(hw, SWSM);
+ if(swsm & E1000_SWSM_SWESMBI)
+ break;
+
+ usec_delay(50);
+ timeout--;
+ }
+
+ if(!timeout) {
+ /* Release semaphores */
+ em_put_hw_eeprom_semaphore(hw);
+ DEBUGOUT("Driver can't access the Eeprom - SWESMBI bit is set.\n");
+ return -E1000_ERR_EEPROM;
+ }
+
+ return E1000_SUCCESS;
+}
+
+/***************************************************************************
+ * This function clears HW semaphore bits.
+ *
+ * hw: Struct containing variables accessed by shared code
+ *
+ * returns: - None.
+ *
+ ***************************************************************************/
+void
+em_put_hw_eeprom_semaphore(struct em_hw *hw)
+{
+ uint32_t swsm;
+
+ DEBUGFUNC("em_put_hw_eeprom_semaphore");
+
+ if(!hw->eeprom_semaphore_present)
+ return;
+
+ swsm = E1000_READ_REG(hw, SWSM);
+ /* Release both semaphores. */
+ swsm &= ~(E1000_SWSM_SMBI | E1000_SWSM_SWESMBI);
+ E1000_WRITE_REG(hw, SWSM, swsm);
+}
+
+/******************************************************************************
+ * Checks if PHY reset is blocked due to SOL/IDER session, for example.
+ * Returning E1000_BLK_PHY_RESET isn't necessarily an error. But it's up to
+ * the caller to figure out how to deal with it.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *
+ * returns: - E1000_BLK_PHY_RESET
+ * E1000_SUCCESS
+ *
+ *****************************************************************************/
+int32_t
+em_check_phy_reset_block(struct em_hw *hw)
+{
+ uint32_t manc = 0;
+ if(hw->mac_type > em_82547_rev_2)
+ manc = E1000_READ_REG(hw, MANC);
+ return (manc & E1000_MANC_BLK_PHY_RST_ON_IDE) ?
+ E1000_BLK_PHY_RESET : E1000_SUCCESS;
+}
+
+uint8_t
+em_arc_subsystem_valid(struct em_hw *hw)
+{
+ uint32_t fwsm;
+
+ /* On 8257x silicon, registers in the range of 0x8800 - 0x8FFC
+ * may not be provided a DMA clock when no manageability features are
+ * enabled. We do not want to perform any reads/writes to these registers
+ * if this is the case. We read FWSM to determine the manageability mode.
+ */
+ switch (hw->mac_type) {
+ case em_82573:
+ fwsm = E1000_READ_REG(hw, FWSM);
+ if((fwsm & E1000_FWSM_MODE_MASK) != 0)
+ return TRUE;
+ break;
+ default:
+ break;
+ }
+ return FALSE;
+}
+
+
+
diff --git a/c/src/lib/libbsp/powerpc/beatnik/network/if_em/if_em_hw.h b/c/src/lib/libbsp/powerpc/beatnik/network/if_em/if_em_hw.h
new file mode 100644
index 0000000000..b043bcba67
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/beatnik/network/if_em/if_em_hw.h
@@ -0,0 +1,2678 @@
+/*******************************************************************************
+
+ Copyright (c) 2001-2005, Intel Corporation
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+
+*******************************************************************************/
+
+/*$FreeBSD: /repoman/r/ncvs/src/sys/dev/em/if_em_hw.h,v 1.15 2005/05/26 23:32:02 tackerman Exp $*/
+/* if_em_hw.h
+ * Structures, enums, and macros for the MAC
+ */
+
+#ifndef _EM_HW_H_
+#define _EM_HW_H_
+
+#ifndef __rtems__
+#include <dev/em/if_em_osdep.h>
+#else
+#include <if_em_osdep.h>
+#endif
+
+
+/* Forward declarations of structures used by the shared code */
+struct em_hw;
+struct em_hw_stats;
+
+/* Enumerated types specific to the e1000 hardware */
+/* Media Access Controlers */
+typedef enum {
+ em_undefined = 0,
+ em_82542_rev2_0,
+ em_82542_rev2_1,
+ em_82543,
+ em_82544,
+ em_82540,
+ em_82545,
+ em_82545_rev_3,
+ em_82546,
+ em_82546_rev_3,
+ em_82541,
+ em_82541_rev_2,
+ em_82547,
+ em_82547_rev_2,
+ em_82573,
+ em_num_macs
+} em_mac_type;
+
+typedef enum {
+ em_eeprom_uninitialized = 0,
+ em_eeprom_spi,
+ em_eeprom_microwire,
+ em_eeprom_flash,
+ em_num_eeprom_types
+} em_eeprom_type;
+
+/* Media Types */
+typedef enum {
+ em_media_type_copper = 0,
+ em_media_type_fiber = 1,
+ em_media_type_internal_serdes = 2,
+ em_num_media_types
+} em_media_type;
+
+typedef enum {
+ em_10_half = 0,
+ em_10_full = 1,
+ em_100_half = 2,
+ em_100_full = 3
+} em_speed_duplex_type;
+
+/* Flow Control Settings */
+typedef enum {
+ em_fc_none = 0,
+ em_fc_rx_pause = 1,
+ em_fc_tx_pause = 2,
+ em_fc_full = 3,
+ em_fc_default = 0xFF
+} em_fc_type;
+
+/* PCI bus types */
+typedef enum {
+ em_bus_type_unknown = 0,
+ em_bus_type_pci,
+ em_bus_type_pcix,
+ em_bus_type_pci_express,
+ em_bus_type_reserved
+} em_bus_type;
+
+/* PCI bus speeds */
+typedef enum {
+ em_bus_speed_unknown = 0,
+ em_bus_speed_33,
+ em_bus_speed_66,
+ em_bus_speed_100,
+ em_bus_speed_120,
+ em_bus_speed_133,
+ em_bus_speed_2500,
+ em_bus_speed_reserved
+} em_bus_speed;
+
+/* PCI bus widths */
+typedef enum {
+ em_bus_width_unknown = 0,
+ em_bus_width_32,
+ em_bus_width_64,
+ em_bus_width_pciex_1,
+ em_bus_width_pciex_4,
+ em_bus_width_reserved
+} em_bus_width;
+
+/* PHY status info structure and supporting enums */
+typedef enum {
+ em_cable_length_50 = 0,
+ em_cable_length_50_80,
+ em_cable_length_80_110,
+ em_cable_length_110_140,
+ em_cable_length_140,
+ em_cable_length_undefined = 0xFF
+} em_cable_length;
+
+typedef enum {
+ em_igp_cable_length_10 = 10,
+ em_igp_cable_length_20 = 20,
+ em_igp_cable_length_30 = 30,
+ em_igp_cable_length_40 = 40,
+ em_igp_cable_length_50 = 50,
+ em_igp_cable_length_60 = 60,
+ em_igp_cable_length_70 = 70,
+ em_igp_cable_length_80 = 80,
+ em_igp_cable_length_90 = 90,
+ em_igp_cable_length_100 = 100,
+ em_igp_cable_length_110 = 110,
+ em_igp_cable_length_120 = 120,
+ em_igp_cable_length_130 = 130,
+ em_igp_cable_length_140 = 140,
+ em_igp_cable_length_150 = 150,
+ em_igp_cable_length_160 = 160,
+ em_igp_cable_length_170 = 170,
+ em_igp_cable_length_180 = 180
+} em_igp_cable_length;
+
+typedef enum {
+ em_10bt_ext_dist_enable_normal = 0,
+ em_10bt_ext_dist_enable_lower,
+ em_10bt_ext_dist_enable_undefined = 0xFF
+} em_10bt_ext_dist_enable;
+
+typedef enum {
+ em_rev_polarity_normal = 0,
+ em_rev_polarity_reversed,
+ em_rev_polarity_undefined = 0xFF
+} em_rev_polarity;
+
+typedef enum {
+ em_downshift_normal = 0,
+ em_downshift_activated,
+ em_downshift_undefined = 0xFF
+} em_downshift;
+
+typedef enum {
+ em_smart_speed_default = 0,
+ em_smart_speed_on,
+ em_smart_speed_off
+} em_smart_speed;
+
+typedef enum {
+ em_polarity_reversal_enabled = 0,
+ em_polarity_reversal_disabled,
+ em_polarity_reversal_undefined = 0xFF
+} em_polarity_reversal;
+
+typedef enum {
+ em_auto_x_mode_manual_mdi = 0,
+ em_auto_x_mode_manual_mdix,
+ em_auto_x_mode_auto1,
+ em_auto_x_mode_auto2,
+ em_auto_x_mode_undefined = 0xFF
+} em_auto_x_mode;
+
+typedef enum {
+ em_1000t_rx_status_not_ok = 0,
+ em_1000t_rx_status_ok,
+ em_1000t_rx_status_undefined = 0xFF
+} em_1000t_rx_status;
+
+typedef enum {
+ em_phy_m88 = 0,
+ em_phy_igp,
+ em_phy_igp_2,
+ em_phy_undefined = 0xFF
+} em_phy_type;
+
+typedef enum {
+ em_ms_hw_default = 0,
+ em_ms_force_master,
+ em_ms_force_slave,
+ em_ms_auto
+} em_ms_type;
+
+typedef enum {
+ em_ffe_config_enabled = 0,
+ em_ffe_config_active,
+ em_ffe_config_blocked
+} em_ffe_config;
+
+typedef enum {
+ em_dsp_config_disabled = 0,
+ em_dsp_config_enabled,
+ em_dsp_config_activated,
+ em_dsp_config_undefined = 0xFF
+} em_dsp_config;
+
+struct em_phy_info {
+ em_cable_length cable_length;
+ em_10bt_ext_dist_enable extended_10bt_distance;
+ em_rev_polarity cable_polarity;
+ em_downshift downshift;
+ em_polarity_reversal polarity_correction;
+ em_auto_x_mode mdix_mode;
+ em_1000t_rx_status local_rx;
+ em_1000t_rx_status remote_rx;
+};
+
+struct em_phy_stats {
+ uint32_t idle_errors;
+ uint32_t receive_errors;
+};
+
+struct em_eeprom_info {
+ em_eeprom_type type;
+ uint16_t word_size;
+ uint16_t opcode_bits;
+ uint16_t address_bits;
+ uint16_t delay_usec;
+ uint16_t page_size;
+ boolean_t use_eerd;
+ boolean_t use_eewr;
+};
+
+/* Flex ASF Information */
+#define E1000_HOST_IF_MAX_SIZE 2048
+
+typedef enum {
+ em_byte_align = 0,
+ em_word_align = 1,
+ em_dword_align = 2
+} em_align_type;
+
+
+
+/* Error Codes */
+#define E1000_SUCCESS 0
+#define E1000_ERR_EEPROM 1
+#define E1000_ERR_PHY 2
+#define E1000_ERR_CONFIG 3
+#define E1000_ERR_PARAM 4
+#define E1000_ERR_MAC_TYPE 5
+#define E1000_ERR_PHY_TYPE 6
+#define E1000_ERR_RESET 9
+#define E1000_ERR_MASTER_REQUESTS_PENDING 10
+#define E1000_ERR_HOST_INTERFACE_COMMAND 11
+#define E1000_BLK_PHY_RESET 12
+
+/* Function prototypes */
+/* Initialization */
+int32_t em_reset_hw(struct em_hw *hw);
+int32_t em_init_hw(struct em_hw *hw);
+int32_t em_id_led_init(struct em_hw * hw);
+int32_t em_set_mac_type(struct em_hw *hw);
+void em_set_media_type(struct em_hw *hw);
+
+/* Link Configuration */
+int32_t em_setup_link(struct em_hw *hw);
+int32_t em_phy_setup_autoneg(struct em_hw *hw);
+void em_config_collision_dist(struct em_hw *hw);
+int32_t em_config_fc_after_link_up(struct em_hw *hw);
+int32_t em_check_for_link(struct em_hw *hw);
+int32_t em_get_speed_and_duplex(struct em_hw *hw, uint16_t * speed, uint16_t * duplex);
+int32_t em_wait_autoneg(struct em_hw *hw);
+int32_t em_force_mac_fc(struct em_hw *hw);
+
+/* PHY */
+int32_t em_read_phy_reg(struct em_hw *hw, uint32_t reg_addr, uint16_t *phy_data);
+int32_t em_write_phy_reg(struct em_hw *hw, uint32_t reg_addr, uint16_t data);
+int32_t em_phy_hw_reset(struct em_hw *hw);
+int32_t em_phy_reset(struct em_hw *hw);
+int32_t em_detect_gig_phy(struct em_hw *hw);
+int32_t em_phy_get_info(struct em_hw *hw, struct em_phy_info *phy_info);
+int32_t em_phy_m88_get_info(struct em_hw *hw, struct em_phy_info *phy_info);
+int32_t em_phy_igp_get_info(struct em_hw *hw, struct em_phy_info *phy_info);
+int32_t em_get_cable_length(struct em_hw *hw, uint16_t *min_length, uint16_t *max_length);
+int32_t em_check_polarity(struct em_hw *hw, uint16_t *polarity);
+int32_t em_check_downshift(struct em_hw *hw);
+int32_t em_validate_mdi_setting(struct em_hw *hw);
+
+/* EEPROM Functions */
+int32_t em_init_eeprom_params(struct em_hw *hw);
+boolean_t em_is_onboard_nvm_eeprom(struct em_hw *hw);
+int32_t em_read_eeprom_eerd(struct em_hw *hw, uint16_t offset, uint16_t words, uint16_t *data);
+int32_t em_write_eeprom_eewr(struct em_hw *hw, uint16_t offset, uint16_t words, uint16_t *data);
+int32_t em_poll_eerd_eewr_done(struct em_hw *hw, int eerd);
+
+/* MNG HOST IF functions */
+uint32_t em_enable_mng_pass_thru(struct em_hw *hw);
+
+#define E1000_MNG_DHCP_TX_PAYLOAD_CMD 64
+#define E1000_HI_MAX_MNG_DATA_LENGTH 0x6F8 /* Host Interface data length */
+
+#define E1000_MNG_DHCP_COMMAND_TIMEOUT 10 /* Time in ms to process MNG command */
+#define E1000_MNG_DHCP_COOKIE_OFFSET 0x6F0 /* Cookie offset */
+#define E1000_MNG_DHCP_COOKIE_LENGTH 0x10 /* Cookie length */
+#define E1000_MNG_IAMT_MODE 0x3
+#define E1000_IAMT_SIGNATURE 0x544D4149 /* Intel(R) Active Management Technology signature */
+
+#define E1000_MNG_DHCP_COOKIE_STATUS_PARSING_SUPPORT 0x1 /* DHCP parsing enabled */
+#define E1000_MNG_DHCP_COOKIE_STATUS_VLAN_SUPPORT 0x2 /* DHCP parsing enabled */
+#define E1000_VFTA_ENTRY_SHIFT 0x5
+#define E1000_VFTA_ENTRY_MASK 0x7F
+#define E1000_VFTA_ENTRY_BIT_SHIFT_MASK 0x1F
+
+struct em_host_mng_command_header {
+ uint8_t command_id;
+ uint8_t checksum;
+ uint16_t reserved1;
+ uint16_t reserved2;
+ uint16_t command_length;
+};
+
+struct em_host_mng_command_info {
+ struct em_host_mng_command_header command_header; /* Command Head/Command Result Head has 4 bytes */
+ uint8_t command_data[E1000_HI_MAX_MNG_DATA_LENGTH]; /* Command data can length 0..0x658*/
+};
+#ifdef __BIG_ENDIAN
+struct em_host_mng_dhcp_cookie{
+ uint32_t signature;
+ uint16_t vlan_id;
+ uint8_t reserved0;
+ uint8_t status;
+ uint32_t reserved1;
+ uint8_t checksum;
+ uint8_t reserved3;
+ uint16_t reserved2;
+};
+#else
+struct em_host_mng_dhcp_cookie{
+ uint32_t signature;
+ uint8_t status;
+ uint8_t reserved0;
+ uint16_t vlan_id;
+ uint32_t reserved1;
+ uint16_t reserved2;
+ uint8_t reserved3;
+ uint8_t checksum;
+};
+#endif
+
+int32_t em_mng_write_dhcp_info(struct em_hw *hw, uint8_t *buffer,
+ uint16_t length);
+boolean_t em_check_mng_mode(struct em_hw *hw);
+boolean_t em_enable_tx_pkt_filtering(struct em_hw *hw);
+int32_t em_mng_enable_host_if(struct em_hw *hw);
+int32_t em_mng_host_if_write(struct em_hw *hw, uint8_t *buffer,
+ uint16_t length, uint16_t offset, uint8_t *sum);
+int32_t em_mng_write_cmd_header(struct em_hw* hw,
+ struct em_host_mng_command_header* hdr);
+
+int32_t em_mng_write_commit(struct em_hw *hw);
+
+int32_t em_read_eeprom(struct em_hw *hw, uint16_t reg, uint16_t words, uint16_t *data);
+int32_t em_validate_eeprom_checksum(struct em_hw *hw);
+int32_t em_update_eeprom_checksum(struct em_hw *hw);
+int32_t em_write_eeprom(struct em_hw *hw, uint16_t reg, uint16_t words, uint16_t *data);
+int32_t em_read_part_num(struct em_hw *hw, uint32_t * part_num);
+int32_t em_read_mac_addr(struct em_hw * hw);
+int32_t em_swfw_sync_acquire(struct em_hw *hw, uint16_t mask);
+void em_swfw_sync_release(struct em_hw *hw, uint16_t mask);
+
+/* Filters (multicast, vlan, receive) */
+void em_init_rx_addrs(struct em_hw *hw);
+void em_mc_addr_list_update(struct em_hw *hw, uint8_t * mc_addr_list, uint32_t mc_addr_count, uint32_t pad, uint32_t rar_used_count);
+uint32_t em_hash_mc_addr(struct em_hw *hw, uint8_t * mc_addr);
+void em_mta_set(struct em_hw *hw, uint32_t hash_value);
+void em_rar_set(struct em_hw *hw, uint8_t * mc_addr, uint32_t rar_index);
+void em_write_vfta(struct em_hw *hw, uint32_t offset, uint32_t value);
+void em_clear_vfta(struct em_hw *hw);
+
+/* LED functions */
+int32_t em_setup_led(struct em_hw *hw);
+int32_t em_cleanup_led(struct em_hw *hw);
+int32_t em_led_on(struct em_hw *hw);
+int32_t em_led_off(struct em_hw *hw);
+
+/* Adaptive IFS Functions */
+
+/* Everything else */
+void em_clear_hw_cntrs(struct em_hw *hw);
+void em_reset_adaptive(struct em_hw *hw);
+void em_update_adaptive(struct em_hw *hw);
+void em_tbi_adjust_stats(struct em_hw *hw, struct em_hw_stats *stats, uint32_t frame_len, uint8_t * mac_addr);
+void em_get_bus_info(struct em_hw *hw);
+void em_pci_set_mwi(struct em_hw *hw);
+void em_pci_clear_mwi(struct em_hw *hw);
+void em_read_pci_cfg(struct em_hw *hw, uint32_t reg, uint16_t * value);
+void em_write_pci_cfg(struct em_hw *hw, uint32_t reg, uint16_t * value);
+/* Port I/O is only supported on 82544 and newer */
+uint32_t em_io_read(struct em_hw *hw, unsigned long port);
+uint32_t em_read_reg_io(struct em_hw *hw, uint32_t offset);
+void em_io_write(struct em_hw *hw, unsigned long port, uint32_t value);
+void em_write_reg_io(struct em_hw *hw, uint32_t offset, uint32_t value);
+int32_t em_config_dsp_after_link_change(struct em_hw *hw, boolean_t link_up);
+int32_t em_set_d3_lplu_state(struct em_hw *hw, boolean_t active);
+int32_t em_set_d0_lplu_state(struct em_hw *hw, boolean_t active);
+void em_set_pci_express_master_disable(struct em_hw *hw);
+void em_enable_pciex_master(struct em_hw *hw);
+int32_t em_disable_pciex_master(struct em_hw *hw);
+int32_t em_get_auto_rd_done(struct em_hw *hw);
+int32_t em_get_phy_cfg_done(struct em_hw *hw);
+int32_t em_get_software_semaphore(struct em_hw *hw);
+void em_release_software_semaphore(struct em_hw *hw);
+int32_t em_check_phy_reset_block(struct em_hw *hw);
+int32_t em_get_hw_eeprom_semaphore(struct em_hw *hw);
+void em_put_hw_eeprom_semaphore(struct em_hw *hw);
+int32_t em_commit_shadow_ram(struct em_hw *hw);
+uint8_t em_arc_subsystem_valid(struct em_hw *hw);
+
+#define E1000_READ_REG_IO(a, reg) \
+ em_read_reg_io((a), E1000_##reg)
+#define E1000_WRITE_REG_IO(a, reg, val) \
+ em_write_reg_io((a), E1000_##reg, val)
+
+/* PCI Device IDs */
+#define E1000_DEV_ID_82542 0x1000
+#define E1000_DEV_ID_82543GC_FIBER 0x1001
+#define E1000_DEV_ID_82543GC_COPPER 0x1004
+#define E1000_DEV_ID_82544EI_COPPER 0x1008
+#define E1000_DEV_ID_82544EI_FIBER 0x1009
+#define E1000_DEV_ID_82544GC_COPPER 0x100C
+#define E1000_DEV_ID_82544GC_LOM 0x100D
+#define E1000_DEV_ID_82540EM 0x100E
+#define E1000_DEV_ID_82541ER_LOM 0x1014
+#define E1000_DEV_ID_82540EM_LOM 0x1015
+#define E1000_DEV_ID_82540EP_LOM 0x1016
+#define E1000_DEV_ID_82540EP 0x1017
+#define E1000_DEV_ID_82540EP_LP 0x101E
+#define E1000_DEV_ID_82545EM_COPPER 0x100F
+#define E1000_DEV_ID_82545EM_FIBER 0x1011
+#define E1000_DEV_ID_82545GM_COPPER 0x1026
+#define E1000_DEV_ID_82545GM_FIBER 0x1027
+#define E1000_DEV_ID_82545GM_SERDES 0x1028
+#define E1000_DEV_ID_82546EB_COPPER 0x1010
+#define E1000_DEV_ID_82546EB_FIBER 0x1012
+#define E1000_DEV_ID_82546EB_QUAD_COPPER 0x101D
+#define E1000_DEV_ID_82541EI 0x1013
+#define E1000_DEV_ID_82541EI_MOBILE 0x1018
+#define E1000_DEV_ID_82541ER 0x1078
+#define E1000_DEV_ID_82547GI 0x1075
+#define E1000_DEV_ID_82541GI 0x1076
+#define E1000_DEV_ID_82541GI_MOBILE 0x1077
+#define E1000_DEV_ID_82541GI_LF 0x107C
+#define E1000_DEV_ID_82546GB_COPPER 0x1079
+#define E1000_DEV_ID_82546GB_FIBER 0x107A
+#define E1000_DEV_ID_82546GB_SERDES 0x107B
+#define E1000_DEV_ID_82546GB_PCIE 0x108A
+#define E1000_DEV_ID_82547EI 0x1019
+#define E1000_DEV_ID_82547EI_MOBILE 0x101A
+#define E1000_DEV_ID_82573E 0x108B
+#define E1000_DEV_ID_82573E_IAMT 0x108C
+
+#define E1000_DEV_ID_82546GB_QUAD_COPPER 0x1099
+
+#define NODE_ADDRESS_SIZE 6
+#define ETH_LENGTH_OF_ADDRESS 6
+
+/* MAC decode size is 128K - This is the size of BAR0 */
+#define MAC_DECODE_SIZE (128 * 1024)
+
+#define E1000_82542_2_0_REV_ID 2
+#define E1000_82542_2_1_REV_ID 3
+#define E1000_REVISION_0 0
+#define E1000_REVISION_1 1
+#define E1000_REVISION_2 2
+#define E1000_REVISION_3 3
+
+#define SPEED_10 10
+#define SPEED_100 100
+#define SPEED_1000 1000
+#define HALF_DUPLEX 1
+#define FULL_DUPLEX 2
+
+/* The sizes (in bytes) of a ethernet packet */
+#define ENET_HEADER_SIZE 14
+#define MAXIMUM_ETHERNET_FRAME_SIZE 1518 /* With FCS */
+#define MINIMUM_ETHERNET_FRAME_SIZE 64 /* With FCS */
+#define ETHERNET_FCS_SIZE 4
+#define MAXIMUM_ETHERNET_PACKET_SIZE \
+ (MAXIMUM_ETHERNET_FRAME_SIZE - ETHERNET_FCS_SIZE)
+#define MINIMUM_ETHERNET_PACKET_SIZE \
+ (MINIMUM_ETHERNET_FRAME_SIZE - ETHERNET_FCS_SIZE)
+#define CRC_LENGTH ETHERNET_FCS_SIZE
+#define MAX_JUMBO_FRAME_SIZE 0x3F00
+
+
+/* 802.1q VLAN Packet Sizes */
+#define VLAN_TAG_SIZE 4 /* 802.3ac tag (not DMAed) */
+
+/* Ethertype field values */
+#define ETHERNET_IEEE_VLAN_TYPE 0x8100 /* 802.3ac packet */
+#define ETHERNET_IP_TYPE 0x0800 /* IP packets */
+#define ETHERNET_ARP_TYPE 0x0806 /* Address Resolution Protocol (ARP) */
+
+/* Packet Header defines */
+#define IP_PROTOCOL_TCP 6
+#define IP_PROTOCOL_UDP 0x11
+
+/* This defines the bits that are set in the Interrupt Mask
+ * Set/Read Register. Each bit is documented below:
+ * o RXDMT0 = Receive Descriptor Minimum Threshold hit (ring 0)
+ * o RXSEQ = Receive Sequence Error
+ */
+#define POLL_IMS_ENABLE_MASK ( \
+ E1000_IMS_RXDMT0 | \
+ E1000_IMS_RXSEQ)
+
+/* This defines the bits that are set in the Interrupt Mask
+ * Set/Read Register. Each bit is documented below:
+ * o RXT0 = Receiver Timer Interrupt (ring 0)
+ * o TXDW = Transmit Descriptor Written Back
+ * o RXDMT0 = Receive Descriptor Minimum Threshold hit (ring 0)
+ * o RXSEQ = Receive Sequence Error
+ * o LSC = Link Status Change
+ */
+#define IMS_ENABLE_MASK ( \
+ E1000_IMS_RXT0 | \
+ E1000_IMS_TXDW | \
+ E1000_IMS_RXDMT0 | \
+ E1000_IMS_RXSEQ | \
+ E1000_IMS_LSC)
+
+
+/* Number of high/low register pairs in the RAR. The RAR (Receive Address
+ * Registers) holds the directed and multicast addresses that we monitor. We
+ * reserve one of these spots for our directed address, allowing us room for
+ * E1000_RAR_ENTRIES - 1 multicast addresses.
+ */
+#define E1000_RAR_ENTRIES 15
+
+#define MIN_NUMBER_OF_DESCRIPTORS 8
+#define MAX_NUMBER_OF_DESCRIPTORS 0xFFF8
+
+/* Receive Descriptor */
+struct em_rx_desc {
+ uint64_t buffer_addr; /* Address of the descriptor's data buffer */
+ uint16_t length; /* Length of data DMAed into data buffer */
+ uint16_t csum; /* Packet checksum */
+ uint8_t status; /* Descriptor status */
+ uint8_t errors; /* Descriptor Errors */
+ uint16_t special;
+};
+
+/* Receive Descriptor - Extended */
+union em_rx_desc_extended {
+ struct {
+ uint64_t buffer_addr;
+ uint64_t reserved;
+ } read;
+ struct {
+ struct {
+ uint32_t mrq; /* Multiple Rx Queues */
+ union {
+ uint32_t rss; /* RSS Hash */
+ struct {
+ uint16_t ip_id; /* IP id */
+ uint16_t csum; /* Packet Checksum */
+ } csum_ip;
+ } hi_dword;
+ } lower;
+ struct {
+ uint32_t status_error; /* ext status/error */
+ uint16_t length;
+ uint16_t vlan; /* VLAN tag */
+ } upper;
+ } wb; /* writeback */
+};
+
+#define MAX_PS_BUFFERS 4
+/* Receive Descriptor - Packet Split */
+union em_rx_desc_packet_split {
+ struct {
+ /* one buffer for protocol header(s), three data buffers */
+ uint64_t buffer_addr[MAX_PS_BUFFERS];
+ } read;
+ struct {
+ struct {
+ uint32_t mrq; /* Multiple Rx Queues */
+ union {
+ uint32_t rss; /* RSS Hash */
+ struct {
+ uint16_t ip_id; /* IP id */
+ uint16_t csum; /* Packet Checksum */
+ } csum_ip;
+ } hi_dword;
+ } lower;
+ struct {
+ uint32_t status_error; /* ext status/error */
+ uint16_t length0; /* length of buffer 0 */
+ uint16_t vlan; /* VLAN tag */
+ } middle;
+ struct {
+ uint16_t header_status;
+ uint16_t length[3]; /* length of buffers 1-3 */
+ } upper;
+ uint64_t reserved;
+ } wb; /* writeback */
+};
+
+/* Receive Decriptor bit definitions */
+#define E1000_RXD_STAT_DD 0x01 /* Descriptor Done */
+#define E1000_RXD_STAT_EOP 0x02 /* End of Packet */
+#define E1000_RXD_STAT_IXSM 0x04 /* Ignore checksum */
+#define E1000_RXD_STAT_VP 0x08 /* IEEE VLAN Packet */
+#define E1000_RXD_STAT_UDPCS 0x10 /* UDP xsum caculated */
+#define E1000_RXD_STAT_TCPCS 0x20 /* TCP xsum calculated */
+#define E1000_RXD_STAT_IPCS 0x40 /* IP xsum calculated */
+#define E1000_RXD_STAT_PIF 0x80 /* passed in-exact filter */
+#define E1000_RXD_STAT_IPIDV 0x200 /* IP identification valid */
+#define E1000_RXD_STAT_UDPV 0x400 /* Valid UDP checksum */
+#define E1000_RXD_STAT_ACK 0x8000 /* ACK Packet indication */
+#define E1000_RXD_ERR_CE 0x01 /* CRC Error */
+#define E1000_RXD_ERR_SE 0x02 /* Symbol Error */
+#define E1000_RXD_ERR_SEQ 0x04 /* Sequence Error */
+#define E1000_RXD_ERR_CXE 0x10 /* Carrier Extension Error */
+#define E1000_RXD_ERR_TCPE 0x20 /* TCP/UDP Checksum Error */
+#define E1000_RXD_ERR_IPE 0x40 /* IP Checksum Error */
+#define E1000_RXD_ERR_RXE 0x80 /* Rx Data Error */
+#define E1000_RXD_SPC_VLAN_MASK 0x0FFF /* VLAN ID is in lower 12 bits */
+#define E1000_RXD_SPC_PRI_MASK 0xE000 /* Priority is in upper 3 bits */
+#define E1000_RXD_SPC_PRI_SHIFT 13
+#define E1000_RXD_SPC_CFI_MASK 0x1000 /* CFI is bit 12 */
+#define E1000_RXD_SPC_CFI_SHIFT 12
+
+#define E1000_RXDEXT_STATERR_CE 0x01000000
+#define E1000_RXDEXT_STATERR_SE 0x02000000
+#define E1000_RXDEXT_STATERR_SEQ 0x04000000
+#define E1000_RXDEXT_STATERR_CXE 0x10000000
+#define E1000_RXDEXT_STATERR_TCPE 0x20000000
+#define E1000_RXDEXT_STATERR_IPE 0x40000000
+#define E1000_RXDEXT_STATERR_RXE 0x80000000
+
+#define E1000_RXDPS_HDRSTAT_HDRSP 0x00008000
+#define E1000_RXDPS_HDRSTAT_HDRLEN_MASK 0x000003FF
+
+/* mask to determine if packets should be dropped due to frame errors */
+#define E1000_RXD_ERR_FRAME_ERR_MASK ( \
+ E1000_RXD_ERR_CE | \
+ E1000_RXD_ERR_SE | \
+ E1000_RXD_ERR_SEQ | \
+ E1000_RXD_ERR_CXE | \
+ E1000_RXD_ERR_RXE)
+
+
+/* Same mask, but for extended and packet split descriptors */
+#define E1000_RXDEXT_ERR_FRAME_ERR_MASK ( \
+ E1000_RXDEXT_STATERR_CE | \
+ E1000_RXDEXT_STATERR_SE | \
+ E1000_RXDEXT_STATERR_SEQ | \
+ E1000_RXDEXT_STATERR_CXE | \
+ E1000_RXDEXT_STATERR_RXE)
+
+/* Transmit Descriptor */
+struct em_tx_desc {
+ uint64_t buffer_addr; /* Address of the descriptor's data buffer */
+ union {
+ uint32_t data;
+ struct {
+ uint16_t length; /* Data buffer length */
+ uint8_t cso; /* Checksum offset */
+ uint8_t cmd; /* Descriptor control */
+ } flags;
+ } lower;
+ union {
+ uint32_t data;
+ struct {
+ uint8_t status; /* Descriptor status */
+ uint8_t css; /* Checksum start */
+ uint16_t special;
+ } fields;
+ } upper;
+};
+
+/* Transmit Descriptor bit definitions */
+#define E1000_TXD_DTYP_D 0x00100000 /* Data Descriptor */
+#define E1000_TXD_DTYP_C 0x00000000 /* Context Descriptor */
+#define E1000_TXD_POPTS_IXSM 0x01 /* Insert IP checksum */
+#define E1000_TXD_POPTS_TXSM 0x02 /* Insert TCP/UDP checksum */
+#define E1000_TXD_CMD_EOP 0x01000000 /* End of Packet */
+#define E1000_TXD_CMD_IFCS 0x02000000 /* Insert FCS (Ethernet CRC) */
+#define E1000_TXD_CMD_IC 0x04000000 /* Insert Checksum */
+#define E1000_TXD_CMD_RS 0x08000000 /* Report Status */
+#define E1000_TXD_CMD_RPS 0x10000000 /* Report Packet Sent */
+#define E1000_TXD_CMD_DEXT 0x20000000 /* Descriptor extension (0 = legacy) */
+#define E1000_TXD_CMD_VLE 0x40000000 /* Add VLAN tag */
+#define E1000_TXD_CMD_IDE 0x80000000 /* Enable Tidv register */
+#define E1000_TXD_STAT_DD 0x00000001 /* Descriptor Done */
+#define E1000_TXD_STAT_EC 0x00000002 /* Excess Collisions */
+#define E1000_TXD_STAT_LC 0x00000004 /* Late Collisions */
+#define E1000_TXD_STAT_TU 0x00000008 /* Transmit underrun */
+#define E1000_TXD_CMD_TCP 0x01000000 /* TCP packet */
+#define E1000_TXD_CMD_IP 0x02000000 /* IP packet */
+#define E1000_TXD_CMD_TSE 0x04000000 /* TCP Seg enable */
+#define E1000_TXD_STAT_TC 0x00000004 /* Tx Underrun */
+
+/* Offload Context Descriptor */
+struct em_context_desc {
+ union {
+ uint32_t ip_config;
+ struct {
+ uint8_t ipcss; /* IP checksum start */
+ uint8_t ipcso; /* IP checksum offset */
+ uint16_t ipcse; /* IP checksum end */
+ } ip_fields;
+ } lower_setup;
+ union {
+ uint32_t tcp_config;
+ struct {
+ uint8_t tucss; /* TCP checksum start */
+ uint8_t tucso; /* TCP checksum offset */
+ uint16_t tucse; /* TCP checksum end */
+ } tcp_fields;
+ } upper_setup;
+ uint32_t cmd_and_length; /* */
+ union {
+ uint32_t data;
+ struct {
+ uint8_t status; /* Descriptor status */
+ uint8_t hdr_len; /* Header length */
+ uint16_t mss; /* Maximum segment size */
+ } fields;
+ } tcp_seg_setup;
+};
+
+/* Offload data descriptor */
+struct em_data_desc {
+ uint64_t buffer_addr; /* Address of the descriptor's buffer address */
+ union {
+ uint32_t data;
+ struct {
+ uint16_t length; /* Data buffer length */
+ uint8_t typ_len_ext; /* */
+ uint8_t cmd; /* */
+ } flags;
+ } lower;
+ union {
+ uint32_t data;
+ struct {
+ uint8_t status; /* Descriptor status */
+ uint8_t popts; /* Packet Options */
+ uint16_t special; /* */
+ } fields;
+ } upper;
+};
+
+/* Filters */
+#define E1000_NUM_UNICAST 16 /* Unicast filter entries */
+#define E1000_MC_TBL_SIZE 128 /* Multicast Filter Table (4096 bits) */
+#define E1000_VLAN_FILTER_TBL_SIZE 128 /* VLAN Filter Table (4096 bits) */
+
+
+/* Receive Address Register */
+struct em_rar {
+ volatile uint32_t low; /* receive address low */
+ volatile uint32_t high; /* receive address high */
+};
+
+/* Number of entries in the Multicast Table Array (MTA). */
+#define E1000_NUM_MTA_REGISTERS 128
+
+/* IPv4 Address Table Entry */
+struct em_ipv4_at_entry {
+ volatile uint32_t ipv4_addr; /* IP Address (RW) */
+ volatile uint32_t reserved;
+};
+
+/* Four wakeup IP addresses are supported */
+#define E1000_WAKEUP_IP_ADDRESS_COUNT_MAX 4
+#define E1000_IP4AT_SIZE E1000_WAKEUP_IP_ADDRESS_COUNT_MAX
+#define E1000_IP6AT_SIZE 1
+
+/* IPv6 Address Table Entry */
+struct em_ipv6_at_entry {
+ volatile uint8_t ipv6_addr[16];
+};
+
+/* Flexible Filter Length Table Entry */
+struct em_fflt_entry {
+ volatile uint32_t length; /* Flexible Filter Length (RW) */
+ volatile uint32_t reserved;
+};
+
+/* Flexible Filter Mask Table Entry */
+struct em_ffmt_entry {
+ volatile uint32_t mask; /* Flexible Filter Mask (RW) */
+ volatile uint32_t reserved;
+};
+
+/* Flexible Filter Value Table Entry */
+struct em_ffvt_entry {
+ volatile uint32_t value; /* Flexible Filter Value (RW) */
+ volatile uint32_t reserved;
+};
+
+/* Four Flexible Filters are supported */
+#define E1000_FLEXIBLE_FILTER_COUNT_MAX 4
+
+/* Each Flexible Filter is at most 128 (0x80) bytes in length */
+#define E1000_FLEXIBLE_FILTER_SIZE_MAX 128
+
+#define E1000_FFLT_SIZE E1000_FLEXIBLE_FILTER_COUNT_MAX
+#define E1000_FFMT_SIZE E1000_FLEXIBLE_FILTER_SIZE_MAX
+#define E1000_FFVT_SIZE E1000_FLEXIBLE_FILTER_SIZE_MAX
+
+/* Register Set. (82543, 82544)
+ *
+ * Registers are defined to be 32 bits and should be accessed as 32 bit values.
+ * These registers are physically located on the NIC, but are mapped into the
+ * host memory address space.
+ *
+ * RW - register is both readable and writable
+ * RO - register is read only
+ * WO - register is write only
+ * R/clr - register is read only and is cleared when read
+ * A - register array
+ */
+#define E1000_CTRL 0x00000 /* Device Control - RW */
+#define E1000_CTRL_DUP 0x00004 /* Device Control Duplicate (Shadow) - RW */
+#define E1000_STATUS 0x00008 /* Device Status - RO */
+#define E1000_EECD 0x00010 /* EEPROM/Flash Control - RW */
+#define E1000_EERD 0x00014 /* EEPROM Read - RW */
+#define E1000_CTRL_EXT 0x00018 /* Extended Device Control - RW */
+#define E1000_FLA 0x0001C /* Flash Access - RW */
+#define E1000_MDIC 0x00020 /* MDI Control - RW */
+#define E1000_FCAL 0x00028 /* Flow Control Address Low - RW */
+#define E1000_FCAH 0x0002C /* Flow Control Address High -RW */
+#define E1000_FCT 0x00030 /* Flow Control Type - RW */
+#define E1000_VET 0x00038 /* VLAN Ether Type - RW */
+#define E1000_ICR 0x000C0 /* Interrupt Cause Read - R/clr */
+#define E1000_ITR 0x000C4 /* Interrupt Throttling Rate - RW */
+#define E1000_ICS 0x000C8 /* Interrupt Cause Set - WO */
+#define E1000_IMS 0x000D0 /* Interrupt Mask Set - RW */
+#define E1000_IMC 0x000D8 /* Interrupt Mask Clear - WO */
+#define E1000_IAM 0x000E0 /* Interrupt Acknowledge Auto Mask */
+#define E1000_RCTL 0x00100 /* RX Control - RW */
+#define E1000_FCTTV 0x00170 /* Flow Control Transmit Timer Value - RW */
+#define E1000_TXCW 0x00178 /* TX Configuration Word - RW */
+#define E1000_RXCW 0x00180 /* RX Configuration Word - RO */
+#define E1000_TCTL 0x00400 /* TX Control - RW */
+#define E1000_TIPG 0x00410 /* TX Inter-packet gap -RW */
+#define E1000_TBT 0x00448 /* TX Burst Timer - RW */
+#define E1000_AIT 0x00458 /* Adaptive Interframe Spacing Throttle - RW */
+#define E1000_LEDCTL 0x00E00 /* LED Control - RW */
+#define E1000_EXTCNF_CTRL 0x00F00 /* Extended Configuration Control */
+#define E1000_EXTCNF_SIZE 0x00F08 /* Extended Configuration Size */
+#define E1000_PBA 0x01000 /* Packet Buffer Allocation - RW */
+#define E1000_PBS 0x01008 /* Packet Buffer Size */
+#define E1000_EEMNGCTL 0x01010 /* MNG EEprom Control */
+#define E1000_FLASH_UPDATES 1000
+#define E1000_EEARBC 0x01024 /* EEPROM Auto Read Bus Control */
+#define E1000_FLASHT 0x01028 /* FLASH Timer Register */
+#define E1000_EEWR 0x0102C /* EEPROM Write Register - RW */
+#define E1000_FLSWCTL 0x01030 /* FLASH control register */
+#define E1000_FLSWDATA 0x01034 /* FLASH data register */
+#define E1000_FLSWCNT 0x01038 /* FLASH Access Counter */
+#define E1000_FLOP 0x0103C /* FLASH Opcode Register */
+#define E1000_ERT 0x02008 /* Early Rx Threshold - RW */
+#define E1000_FCRTL 0x02160 /* Flow Control Receive Threshold Low - RW */
+#define E1000_FCRTH 0x02168 /* Flow Control Receive Threshold High - RW */
+#define E1000_PSRCTL 0x02170 /* Packet Split Receive Control - RW */
+#define E1000_RDBAL 0x02800 /* RX Descriptor Base Address Low - RW */
+#define E1000_RDBAH 0x02804 /* RX Descriptor Base Address High - RW */
+#define E1000_RDLEN 0x02808 /* RX Descriptor Length - RW */
+#define E1000_RDH 0x02810 /* RX Descriptor Head - RW */
+#define E1000_RDT 0x02818 /* RX Descriptor Tail - RW */
+#define E1000_RDTR 0x02820 /* RX Delay Timer - RW */
+#define E1000_RXDCTL 0x02828 /* RX Descriptor Control - RW */
+#define E1000_RADV 0x0282C /* RX Interrupt Absolute Delay Timer - RW */
+#define E1000_RSRPD 0x02C00 /* RX Small Packet Detect - RW */
+#define E1000_RAID 0x02C08 /* Receive Ack Interrupt Delay - RW */
+#define E1000_TXDMAC 0x03000 /* TX DMA Control - RW */
+#define E1000_TDFH 0x03410 /* TX Data FIFO Head - RW */
+#define E1000_TDFT 0x03418 /* TX Data FIFO Tail - RW */
+#define E1000_TDFHS 0x03420 /* TX Data FIFO Head Saved - RW */
+#define E1000_TDFTS 0x03428 /* TX Data FIFO Tail Saved - RW */
+#define E1000_TDFPC 0x03430 /* TX Data FIFO Packet Count - RW */
+#define E1000_TDBAL 0x03800 /* TX Descriptor Base Address Low - RW */
+#define E1000_TDBAH 0x03804 /* TX Descriptor Base Address High - RW */
+#define E1000_TDLEN 0x03808 /* TX Descriptor Length - RW */
+#define E1000_TDH 0x03810 /* TX Descriptor Head - RW */
+#define E1000_TDT 0x03818 /* TX Descripotr Tail - RW */
+#define E1000_TIDV 0x03820 /* TX Interrupt Delay Value - RW */
+#define E1000_TXDCTL 0x03828 /* TX Descriptor Control - RW */
+#define E1000_TADV 0x0382C /* TX Interrupt Absolute Delay Val - RW */
+#define E1000_TSPMT 0x03830 /* TCP Segmentation PAD & Min Threshold - RW */
+#define E1000_TARC0 0x03840 /* TX Arbitration Count (0) */
+#define E1000_TDBAL1 0x03900 /* TX Desc Base Address Low (1) - RW */
+#define E1000_TDBAH1 0x03904 /* TX Desc Base Address High (1) - RW */
+#define E1000_TDLEN1 0x03908 /* TX Desc Length (1) - RW */
+#define E1000_TDH1 0x03910 /* TX Desc Head (1) - RW */
+#define E1000_TDT1 0x03918 /* TX Desc Tail (1) - RW */
+#define E1000_TXDCTL1 0x03928 /* TX Descriptor Control (1) - RW */
+#define E1000_TARC1 0x03940 /* TX Arbitration Count (1) */
+#define E1000_CRCERRS 0x04000 /* CRC Error Count - R/clr */
+#define E1000_ALGNERRC 0x04004 /* Alignment Error Count - R/clr */
+#define E1000_SYMERRS 0x04008 /* Symbol Error Count - R/clr */
+#define E1000_RXERRC 0x0400C /* Receive Error Count - R/clr */
+#define E1000_MPC 0x04010 /* Missed Packet Count - R/clr */
+#define E1000_SCC 0x04014 /* Single Collision Count - R/clr */
+#define E1000_ECOL 0x04018 /* Excessive Collision Count - R/clr */
+#define E1000_MCC 0x0401C /* Multiple Collision Count - R/clr */
+#define E1000_LATECOL 0x04020 /* Late Collision Count - R/clr */
+#define E1000_COLC 0x04028 /* Collision Count - R/clr */
+#define E1000_DC 0x04030 /* Defer Count - R/clr */
+#define E1000_TNCRS 0x04034 /* TX-No CRS - R/clr */
+#define E1000_SEC 0x04038 /* Sequence Error Count - R/clr */
+#define E1000_CEXTERR 0x0403C /* Carrier Extension Error Count - R/clr */
+#define E1000_RLEC 0x04040 /* Receive Length Error Count - R/clr */
+#define E1000_XONRXC 0x04048 /* XON RX Count - R/clr */
+#define E1000_XONTXC 0x0404C /* XON TX Count - R/clr */
+#define E1000_XOFFRXC 0x04050 /* XOFF RX Count - R/clr */
+#define E1000_XOFFTXC 0x04054 /* XOFF TX Count - R/clr */
+#define E1000_FCRUC 0x04058 /* Flow Control RX Unsupported Count- R/clr */
+#define E1000_PRC64 0x0405C /* Packets RX (64 bytes) - R/clr */
+#define E1000_PRC127 0x04060 /* Packets RX (65-127 bytes) - R/clr */
+#define E1000_PRC255 0x04064 /* Packets RX (128-255 bytes) - R/clr */
+#define E1000_PRC511 0x04068 /* Packets RX (255-511 bytes) - R/clr */
+#define E1000_PRC1023 0x0406C /* Packets RX (512-1023 bytes) - R/clr */
+#define E1000_PRC1522 0x04070 /* Packets RX (1024-1522 bytes) - R/clr */
+#define E1000_GPRC 0x04074 /* Good Packets RX Count - R/clr */
+#define E1000_BPRC 0x04078 /* Broadcast Packets RX Count - R/clr */
+#define E1000_MPRC 0x0407C /* Multicast Packets RX Count - R/clr */
+#define E1000_GPTC 0x04080 /* Good Packets TX Count - R/clr */
+#define E1000_GORCL 0x04088 /* Good Octets RX Count Low - R/clr */
+#define E1000_GORCH 0x0408C /* Good Octets RX Count High - R/clr */
+#define E1000_GOTCL 0x04090 /* Good Octets TX Count Low - R/clr */
+#define E1000_GOTCH 0x04094 /* Good Octets TX Count High - R/clr */
+#define E1000_RNBC 0x040A0 /* RX No Buffers Count - R/clr */
+#define E1000_RUC 0x040A4 /* RX Undersize Count - R/clr */
+#define E1000_RFC 0x040A8 /* RX Fragment Count - R/clr */
+#define E1000_ROC 0x040AC /* RX Oversize Count - R/clr */
+#define E1000_RJC 0x040B0 /* RX Jabber Count - R/clr */
+#define E1000_MGTPRC 0x040B4 /* Management Packets RX Count - R/clr */
+#define E1000_MGTPDC 0x040B8 /* Management Packets Dropped Count - R/clr */
+#define E1000_MGTPTC 0x040BC /* Management Packets TX Count - R/clr */
+#define E1000_TORL 0x040C0 /* Total Octets RX Low - R/clr */
+#define E1000_TORH 0x040C4 /* Total Octets RX High - R/clr */
+#define E1000_TOTL 0x040C8 /* Total Octets TX Low - R/clr */
+#define E1000_TOTH 0x040CC /* Total Octets TX High - R/clr */
+#define E1000_TPR 0x040D0 /* Total Packets RX - R/clr */
+#define E1000_TPT 0x040D4 /* Total Packets TX - R/clr */
+#define E1000_PTC64 0x040D8 /* Packets TX (64 bytes) - R/clr */
+#define E1000_PTC127 0x040DC /* Packets TX (65-127 bytes) - R/clr */
+#define E1000_PTC255 0x040E0 /* Packets TX (128-255 bytes) - R/clr */
+#define E1000_PTC511 0x040E4 /* Packets TX (256-511 bytes) - R/clr */
+#define E1000_PTC1023 0x040E8 /* Packets TX (512-1023 bytes) - R/clr */
+#define E1000_PTC1522 0x040EC /* Packets TX (1024-1522 Bytes) - R/clr */
+#define E1000_MPTC 0x040F0 /* Multicast Packets TX Count - R/clr */
+#define E1000_BPTC 0x040F4 /* Broadcast Packets TX Count - R/clr */
+#define E1000_TSCTC 0x040F8 /* TCP Segmentation Context TX - R/clr */
+#define E1000_TSCTFC 0x040FC /* TCP Segmentation Context TX Fail - R/clr */
+#define E1000_IAC 0x4100 /* Interrupt Assertion Count */
+#define E1000_ICRXPTC 0x4104 /* Interrupt Cause Rx Packet Timer Expire Count */
+#define E1000_ICRXATC 0x4108 /* Interrupt Cause Rx Absolute Timer Expire Count */
+#define E1000_ICTXPTC 0x410C /* Interrupt Cause Tx Packet Timer Expire Count */
+#define E1000_ICTXATC 0x4110 /* Interrupt Cause Tx Absolute Timer Expire Count */
+#define E1000_ICTXQEC 0x4118 /* Interrupt Cause Tx Queue Empty Count */
+#define E1000_ICTXQMTC 0x411C /* Interrupt Cause Tx Queue Minimum Threshold Count */
+#define E1000_ICRXDMTC 0x4120 /* Interrupt Cause Rx Descriptor Minimum Threshold Count */
+#define E1000_ICRXOC 0x4124 /* Interrupt Cause Receiver Overrun Count */
+#define E1000_RXCSUM 0x05000 /* RX Checksum Control - RW */
+#define E1000_RFCTL 0x05008 /* Receive Filter Control*/
+#define E1000_MTA 0x05200 /* Multicast Table Array - RW Array */
+#define E1000_RA 0x05400 /* Receive Address - RW Array */
+#define E1000_VFTA 0x05600 /* VLAN Filter Table Array - RW Array */
+#define E1000_WUC 0x05800 /* Wakeup Control - RW */
+#define E1000_WUFC 0x05808 /* Wakeup Filter Control - RW */
+#define E1000_WUS 0x05810 /* Wakeup Status - RO */
+#define E1000_MANC 0x05820 /* Management Control - RW */
+#define E1000_IPAV 0x05838 /* IP Address Valid - RW */
+#define E1000_IP4AT 0x05840 /* IPv4 Address Table - RW Array */
+#define E1000_IP6AT 0x05880 /* IPv6 Address Table - RW Array */
+#define E1000_WUPL 0x05900 /* Wakeup Packet Length - RW */
+#define E1000_WUPM 0x05A00 /* Wakeup Packet Memory - RO A */
+#define E1000_FFLT 0x05F00 /* Flexible Filter Length Table - RW Array */
+#define E1000_HOST_IF 0x08800 /* Host Interface */
+#define E1000_FFMT 0x09000 /* Flexible Filter Mask Table - RW Array */
+#define E1000_FFVT 0x09800 /* Flexible Filter Value Table - RW Array */
+
+#define E1000_GCR 0x05B00 /* PCI-Ex Control */
+#define E1000_GSCL_1 0x05B10 /* PCI-Ex Statistic Control #1 */
+#define E1000_GSCL_2 0x05B14 /* PCI-Ex Statistic Control #2 */
+#define E1000_GSCL_3 0x05B18 /* PCI-Ex Statistic Control #3 */
+#define E1000_GSCL_4 0x05B1C /* PCI-Ex Statistic Control #4 */
+#define E1000_FACTPS 0x05B30 /* Function Active and Power State to MNG */
+#define E1000_SWSM 0x05B50 /* SW Semaphore */
+#define E1000_FWSM 0x05B54 /* FW Semaphore */
+#define E1000_FFLT_DBG 0x05F04 /* Debug Register */
+#define E1000_HICR 0x08F00 /* Host Inteface Control */
+/* Register Set (82542)
+ *
+ * Some of the 82542 registers are located at different offsets than they are
+ * in more current versions of the 8254x. Despite the difference in location,
+ * the registers function in the same manner.
+ */
+#define E1000_82542_CTRL E1000_CTRL
+#define E1000_82542_CTRL_DUP E1000_CTRL_DUP
+#define E1000_82542_STATUS E1000_STATUS
+#define E1000_82542_EECD E1000_EECD
+#define E1000_82542_EERD E1000_EERD
+#define E1000_82542_CTRL_EXT E1000_CTRL_EXT
+#define E1000_82542_FLA E1000_FLA
+#define E1000_82542_MDIC E1000_MDIC
+#define E1000_82542_FCAL E1000_FCAL
+#define E1000_82542_FCAH E1000_FCAH
+#define E1000_82542_FCT E1000_FCT
+#define E1000_82542_VET E1000_VET
+#define E1000_82542_RA 0x00040
+#define E1000_82542_ICR E1000_ICR
+#define E1000_82542_ITR E1000_ITR
+#define E1000_82542_ICS E1000_ICS
+#define E1000_82542_IMS E1000_IMS
+#define E1000_82542_IMC E1000_IMC
+#define E1000_82542_RCTL E1000_RCTL
+#define E1000_82542_RDTR 0x00108
+#define E1000_82542_RDBAL 0x00110
+#define E1000_82542_RDBAH 0x00114
+#define E1000_82542_RDLEN 0x00118
+#define E1000_82542_RDH 0x00120
+#define E1000_82542_RDT 0x00128
+#define E1000_82542_FCRTH 0x00160
+#define E1000_82542_FCRTL 0x00168
+#define E1000_82542_FCTTV E1000_FCTTV
+#define E1000_82542_TXCW E1000_TXCW
+#define E1000_82542_RXCW E1000_RXCW
+#define E1000_82542_MTA 0x00200
+#define E1000_82542_TCTL E1000_TCTL
+#define E1000_82542_TIPG E1000_TIPG
+#define E1000_82542_TDBAL 0x00420
+#define E1000_82542_TDBAH 0x00424
+#define E1000_82542_TDLEN 0x00428
+#define E1000_82542_TDH 0x00430
+#define E1000_82542_TDT 0x00438
+#define E1000_82542_TIDV 0x00440
+#define E1000_82542_TBT E1000_TBT
+#define E1000_82542_AIT E1000_AIT
+#define E1000_82542_VFTA 0x00600
+#define E1000_82542_LEDCTL E1000_LEDCTL
+#define E1000_82542_PBA E1000_PBA
+#define E1000_82542_PBS E1000_PBS
+#define E1000_82542_EEMNGCTL E1000_EEMNGCTL
+#define E1000_82542_EEARBC E1000_EEARBC
+#define E1000_82542_FLASHT E1000_FLASHT
+#define E1000_82542_EEWR E1000_EEWR
+#define E1000_82542_FLSWCTL E1000_FLSWCTL
+#define E1000_82542_FLSWDATA E1000_FLSWDATA
+#define E1000_82542_FLSWCNT E1000_FLSWCNT
+#define E1000_82542_FLOP E1000_FLOP
+#define E1000_82542_EXTCNF_CTRL E1000_EXTCNF_CTRL
+#define E1000_82542_EXTCNF_SIZE E1000_EXTCNF_SIZE
+#define E1000_82542_ERT E1000_ERT
+#define E1000_82542_RXDCTL E1000_RXDCTL
+#define E1000_82542_RADV E1000_RADV
+#define E1000_82542_RSRPD E1000_RSRPD
+#define E1000_82542_TXDMAC E1000_TXDMAC
+#define E1000_82542_TDFHS E1000_TDFHS
+#define E1000_82542_TDFTS E1000_TDFTS
+#define E1000_82542_TDFPC E1000_TDFPC
+#define E1000_82542_TXDCTL E1000_TXDCTL
+#define E1000_82542_TADV E1000_TADV
+#define E1000_82542_TSPMT E1000_TSPMT
+#define E1000_82542_CRCERRS E1000_CRCERRS
+#define E1000_82542_ALGNERRC E1000_ALGNERRC
+#define E1000_82542_SYMERRS E1000_SYMERRS
+#define E1000_82542_RXERRC E1000_RXERRC
+#define E1000_82542_MPC E1000_MPC
+#define E1000_82542_SCC E1000_SCC
+#define E1000_82542_ECOL E1000_ECOL
+#define E1000_82542_MCC E1000_MCC
+#define E1000_82542_LATECOL E1000_LATECOL
+#define E1000_82542_COLC E1000_COLC
+#define E1000_82542_DC E1000_DC
+#define E1000_82542_TNCRS E1000_TNCRS
+#define E1000_82542_SEC E1000_SEC
+#define E1000_82542_CEXTERR E1000_CEXTERR
+#define E1000_82542_RLEC E1000_RLEC
+#define E1000_82542_XONRXC E1000_XONRXC
+#define E1000_82542_XONTXC E1000_XONTXC
+#define E1000_82542_XOFFRXC E1000_XOFFRXC
+#define E1000_82542_XOFFTXC E1000_XOFFTXC
+#define E1000_82542_FCRUC E1000_FCRUC
+#define E1000_82542_PRC64 E1000_PRC64
+#define E1000_82542_PRC127 E1000_PRC127
+#define E1000_82542_PRC255 E1000_PRC255
+#define E1000_82542_PRC511 E1000_PRC511
+#define E1000_82542_PRC1023 E1000_PRC1023
+#define E1000_82542_PRC1522 E1000_PRC1522
+#define E1000_82542_GPRC E1000_GPRC
+#define E1000_82542_BPRC E1000_BPRC
+#define E1000_82542_MPRC E1000_MPRC
+#define E1000_82542_GPTC E1000_GPTC
+#define E1000_82542_GORCL E1000_GORCL
+#define E1000_82542_GORCH E1000_GORCH
+#define E1000_82542_GOTCL E1000_GOTCL
+#define E1000_82542_GOTCH E1000_GOTCH
+#define E1000_82542_RNBC E1000_RNBC
+#define E1000_82542_RUC E1000_RUC
+#define E1000_82542_RFC E1000_RFC
+#define E1000_82542_ROC E1000_ROC
+#define E1000_82542_RJC E1000_RJC
+#define E1000_82542_MGTPRC E1000_MGTPRC
+#define E1000_82542_MGTPDC E1000_MGTPDC
+#define E1000_82542_MGTPTC E1000_MGTPTC
+#define E1000_82542_TORL E1000_TORL
+#define E1000_82542_TORH E1000_TORH
+#define E1000_82542_TOTL E1000_TOTL
+#define E1000_82542_TOTH E1000_TOTH
+#define E1000_82542_TPR E1000_TPR
+#define E1000_82542_TPT E1000_TPT
+#define E1000_82542_PTC64 E1000_PTC64
+#define E1000_82542_PTC127 E1000_PTC127
+#define E1000_82542_PTC255 E1000_PTC255
+#define E1000_82542_PTC511 E1000_PTC511
+#define E1000_82542_PTC1023 E1000_PTC1023
+#define E1000_82542_PTC1522 E1000_PTC1522
+#define E1000_82542_MPTC E1000_MPTC
+#define E1000_82542_BPTC E1000_BPTC
+#define E1000_82542_TSCTC E1000_TSCTC
+#define E1000_82542_TSCTFC E1000_TSCTFC
+#define E1000_82542_RXCSUM E1000_RXCSUM
+#define E1000_82542_WUC E1000_WUC
+#define E1000_82542_WUFC E1000_WUFC
+#define E1000_82542_WUS E1000_WUS
+#define E1000_82542_MANC E1000_MANC
+#define E1000_82542_IPAV E1000_IPAV
+#define E1000_82542_IP4AT E1000_IP4AT
+#define E1000_82542_IP6AT E1000_IP6AT
+#define E1000_82542_WUPL E1000_WUPL
+#define E1000_82542_WUPM E1000_WUPM
+#define E1000_82542_FFLT E1000_FFLT
+#define E1000_82542_TDFH 0x08010
+#define E1000_82542_TDFT 0x08018
+#define E1000_82542_FFMT E1000_FFMT
+#define E1000_82542_FFVT E1000_FFVT
+#define E1000_82542_HOST_IF E1000_HOST_IF
+#define E1000_82542_IAM E1000_IAM
+#define E1000_82542_EEMNGCTL E1000_EEMNGCTL
+#define E1000_82542_PSRCTL E1000_PSRCTL
+#define E1000_82542_RAID E1000_RAID
+#define E1000_82542_TARC0 E1000_TARC0
+#define E1000_82542_TDBAL1 E1000_TDBAL1
+#define E1000_82542_TDBAH1 E1000_TDBAH1
+#define E1000_82542_TDLEN1 E1000_TDLEN1
+#define E1000_82542_TDH1 E1000_TDH1
+#define E1000_82542_TDT1 E1000_TDT1
+#define E1000_82542_TXDCTL1 E1000_TXDCTL1
+#define E1000_82542_TARC1 E1000_TARC1
+#define E1000_82542_RFCTL E1000_RFCTL
+#define E1000_82542_GCR E1000_GCR
+#define E1000_82542_GSCL_1 E1000_GSCL_1
+#define E1000_82542_GSCL_2 E1000_GSCL_2
+#define E1000_82542_GSCL_3 E1000_GSCL_3
+#define E1000_82542_GSCL_4 E1000_GSCL_4
+#define E1000_82542_FACTPS E1000_FACTPS
+#define E1000_82542_SWSM E1000_SWSM
+#define E1000_82542_FWSM E1000_FWSM
+#define E1000_82542_FFLT_DBG E1000_FFLT_DBG
+#define E1000_82542_IAC E1000_IAC
+#define E1000_82542_ICRXPTC E1000_ICRXPTC
+#define E1000_82542_ICRXATC E1000_ICRXATC
+#define E1000_82542_ICTXPTC E1000_ICTXPTC
+#define E1000_82542_ICTXATC E1000_ICTXATC
+#define E1000_82542_ICTXQEC E1000_ICTXQEC
+#define E1000_82542_ICTXQMTC E1000_ICTXQMTC
+#define E1000_82542_ICRXDMTC E1000_ICRXDMTC
+#define E1000_82542_ICRXOC E1000_ICRXOC
+#define E1000_82542_HICR E1000_HICR
+
+/* Statistics counters collected by the MAC */
+struct em_hw_stats {
+ uint64_t crcerrs;
+ uint64_t algnerrc;
+ uint64_t symerrs;
+ uint64_t rxerrc;
+ uint64_t mpc;
+ uint64_t scc;
+ uint64_t ecol;
+ uint64_t mcc;
+ uint64_t latecol;
+ uint64_t colc;
+ uint64_t dc;
+ uint64_t tncrs;
+ uint64_t sec;
+ uint64_t cexterr;
+ uint64_t rlec;
+ uint64_t xonrxc;
+ uint64_t xontxc;
+ uint64_t xoffrxc;
+ uint64_t xofftxc;
+ uint64_t fcruc;
+ uint64_t prc64;
+ uint64_t prc127;
+ uint64_t prc255;
+ uint64_t prc511;
+ uint64_t prc1023;
+ uint64_t prc1522;
+ uint64_t gprc;
+ uint64_t bprc;
+ uint64_t mprc;
+ uint64_t gptc;
+ uint64_t gorcl;
+ uint64_t gorch;
+ uint64_t gotcl;
+ uint64_t gotch;
+ uint64_t rnbc;
+ uint64_t ruc;
+ uint64_t rfc;
+ uint64_t roc;
+ uint64_t rjc;
+ uint64_t mgprc;
+ uint64_t mgpdc;
+ uint64_t mgptc;
+ uint64_t torl;
+ uint64_t torh;
+ uint64_t totl;
+ uint64_t toth;
+ uint64_t tpr;
+ uint64_t tpt;
+ uint64_t ptc64;
+ uint64_t ptc127;
+ uint64_t ptc255;
+ uint64_t ptc511;
+ uint64_t ptc1023;
+ uint64_t ptc1522;
+ uint64_t mptc;
+ uint64_t bptc;
+ uint64_t tsctc;
+ uint64_t tsctfc;
+ uint64_t iac;
+ uint64_t icrxptc;
+ uint64_t icrxatc;
+ uint64_t ictxptc;
+ uint64_t ictxatc;
+ uint64_t ictxqec;
+ uint64_t ictxqmtc;
+ uint64_t icrxdmtc;
+ uint64_t icrxoc;
+};
+
+/* Structure containing variables used by the shared code (em_hw.c) */
+struct em_hw {
+ uint8_t *hw_addr;
+ uint8_t *flash_address;
+ em_mac_type mac_type;
+ em_phy_type phy_type;
+ uint32_t phy_init_script;
+ em_media_type media_type;
+ void *back;
+ em_fc_type fc;
+ em_bus_speed bus_speed;
+ em_bus_width bus_width;
+ em_bus_type bus_type;
+ struct em_eeprom_info eeprom;
+ em_ms_type master_slave;
+ em_ms_type original_master_slave;
+ em_ffe_config ffe_config_state;
+ uint32_t asf_firmware_present;
+ uint32_t eeprom_semaphore_present;
+ unsigned long io_base;
+ uint32_t phy_id;
+ uint32_t phy_revision;
+ uint32_t phy_addr;
+ uint32_t original_fc;
+ uint32_t txcw;
+ uint32_t autoneg_failed;
+ uint32_t max_frame_size;
+ uint32_t min_frame_size;
+ uint32_t mc_filter_type;
+ uint32_t num_mc_addrs;
+ uint32_t collision_delta;
+ uint32_t tx_packet_delta;
+ uint32_t ledctl_default;
+ uint32_t ledctl_mode1;
+ uint32_t ledctl_mode2;
+ boolean_t tx_pkt_filtering;
+ struct em_host_mng_dhcp_cookie mng_cookie;
+ uint16_t phy_spd_default;
+ uint16_t autoneg_advertised;
+ uint16_t pci_cmd_word;
+ uint16_t fc_high_water;
+ uint16_t fc_low_water;
+ uint16_t fc_pause_time;
+ uint16_t current_ifs_val;
+ uint16_t ifs_min_val;
+ uint16_t ifs_max_val;
+ uint16_t ifs_step_size;
+ uint16_t ifs_ratio;
+ uint16_t device_id;
+ uint16_t vendor_id;
+ uint16_t subsystem_id;
+ uint16_t subsystem_vendor_id;
+ uint8_t revision_id;
+ uint8_t autoneg;
+ uint8_t mdix;
+ uint8_t forced_speed_duplex;
+ uint8_t wait_autoneg_complete;
+ uint8_t dma_fairness;
+ uint8_t mac_addr[NODE_ADDRESS_SIZE];
+ uint8_t perm_mac_addr[NODE_ADDRESS_SIZE];
+ boolean_t disable_polarity_correction;
+ boolean_t speed_downgraded;
+ em_smart_speed smart_speed;
+ em_dsp_config dsp_config_state;
+ boolean_t get_link_status;
+ boolean_t serdes_link_down;
+ boolean_t tbi_compatibility_en;
+ boolean_t tbi_compatibility_on;
+ boolean_t phy_reset_disable;
+ boolean_t fc_send_xon;
+ boolean_t fc_strict_ieee;
+ boolean_t report_tx_early;
+ boolean_t adaptive_ifs;
+ boolean_t ifs_params_forced;
+ boolean_t in_ifs_mode;
+ boolean_t mng_reg_access_disabled;
+};
+
+
+#define E1000_EEPROM_SWDPIN0 0x0001 /* SWDPIN 0 EEPROM Value */
+#define E1000_EEPROM_LED_LOGIC 0x0020 /* Led Logic Word */
+#define E1000_EEPROM_RW_REG_DATA 16 /* Offset to data in EEPROM read/write registers */
+#define E1000_EEPROM_RW_REG_DONE 2 /* Offset to READ/WRITE done bit */
+#define E1000_EEPROM_RW_REG_START 1 /* First bit for telling part to start operation */
+#define E1000_EEPROM_RW_ADDR_SHIFT 2 /* Shift to the address bits */
+#define E1000_EEPROM_POLL_WRITE 1 /* Flag for polling for write complete */
+#define E1000_EEPROM_POLL_READ 0 /* Flag for polling for read complete */
+/* Register Bit Masks */
+/* Device Control */
+#define E1000_CTRL_FD 0x00000001 /* Full duplex.0=half; 1=full */
+#define E1000_CTRL_BEM 0x00000002 /* Endian Mode.0=little,1=big */
+#define E1000_CTRL_PRIOR 0x00000004 /* Priority on PCI. 0=rx,1=fair */
+#define E1000_CTRL_GIO_MASTER_DISABLE 0x00000004 /*Blocks new Master requests */
+#define E1000_CTRL_LRST 0x00000008 /* Link reset. 0=normal,1=reset */
+#define E1000_CTRL_TME 0x00000010 /* Test mode. 0=normal,1=test */
+#define E1000_CTRL_SLE 0x00000020 /* Serial Link on 0=dis,1=en */
+#define E1000_CTRL_ASDE 0x00000020 /* Auto-speed detect enable */
+#define E1000_CTRL_SLU 0x00000040 /* Set link up (Force Link) */
+#define E1000_CTRL_ILOS 0x00000080 /* Invert Loss-Of Signal */
+#define E1000_CTRL_SPD_SEL 0x00000300 /* Speed Select Mask */
+#define E1000_CTRL_SPD_10 0x00000000 /* Force 10Mb */
+#define E1000_CTRL_SPD_100 0x00000100 /* Force 100Mb */
+#define E1000_CTRL_SPD_1000 0x00000200 /* Force 1Gb */
+#define E1000_CTRL_BEM32 0x00000400 /* Big Endian 32 mode */
+#define E1000_CTRL_FRCSPD 0x00000800 /* Force Speed */
+#define E1000_CTRL_FRCDPX 0x00001000 /* Force Duplex */
+#define E1000_CTRL_D_UD_POLARITY 0x00004000 /* Defined polarity of Dock/Undock indication in SDP[0] */
+#define E1000_CTRL_SWDPIN0 0x00040000 /* SWDPIN 0 value */
+#define E1000_CTRL_SWDPIN1 0x00080000 /* SWDPIN 1 value */
+#define E1000_CTRL_SWDPIN2 0x00100000 /* SWDPIN 2 value */
+#define E1000_CTRL_SWDPIN3 0x00200000 /* SWDPIN 3 value */
+#define E1000_CTRL_SWDPIO0 0x00400000 /* SWDPIN 0 Input or output */
+#define E1000_CTRL_SWDPIO1 0x00800000 /* SWDPIN 1 input or output */
+#define E1000_CTRL_SWDPIO2 0x01000000 /* SWDPIN 2 input or output */
+#define E1000_CTRL_SWDPIO3 0x02000000 /* SWDPIN 3 input or output */
+#define E1000_CTRL_RST 0x04000000 /* Global reset */
+#define E1000_CTRL_RFCE 0x08000000 /* Receive Flow Control enable */
+#define E1000_CTRL_TFCE 0x10000000 /* Transmit flow control enable */
+#define E1000_CTRL_RTE 0x20000000 /* Routing tag enable */
+#define E1000_CTRL_VME 0x40000000 /* IEEE VLAN mode enable */
+#define E1000_CTRL_PHY_RST 0x80000000 /* PHY Reset */
+
+/* Device Status */
+#define E1000_STATUS_FD 0x00000001 /* Full duplex.0=half,1=full */
+#define E1000_STATUS_LU 0x00000002 /* Link up.0=no,1=link */
+#define E1000_STATUS_FUNC_MASK 0x0000000C /* PCI Function Mask */
+#define E1000_STATUS_FUNC_SHIFT 2
+#define E1000_STATUS_FUNC_0 0x00000000 /* Function 0 */
+#define E1000_STATUS_FUNC_1 0x00000004 /* Function 1 */
+#define E1000_STATUS_TXOFF 0x00000010 /* transmission paused */
+#define E1000_STATUS_TBIMODE 0x00000020 /* TBI mode */
+#define E1000_STATUS_SPEED_MASK 0x000000C0
+#define E1000_STATUS_SPEED_10 0x00000000 /* Speed 10Mb/s */
+#define E1000_STATUS_SPEED_100 0x00000040 /* Speed 100Mb/s */
+#define E1000_STATUS_SPEED_1000 0x00000080 /* Speed 1000Mb/s */
+#define E1000_STATUS_ASDV 0x00000300 /* Auto speed detect value */
+#define E1000_STATUS_DOCK_CI 0x00000800 /* Change in Dock/Undock state. Clear on write '0'. */
+#define E1000_STATUS_GIO_MASTER_ENABLE 0x00080000 /* Status of Master requests. */
+#define E1000_STATUS_MTXCKOK 0x00000400 /* MTX clock running OK */
+#define E1000_STATUS_PCI66 0x00000800 /* In 66Mhz slot */
+#define E1000_STATUS_BUS64 0x00001000 /* In 64 bit slot */
+#define E1000_STATUS_PCIX_MODE 0x00002000 /* PCI-X mode */
+#define E1000_STATUS_PCIX_SPEED 0x0000C000 /* PCI-X bus speed */
+
+/* Constants used to intrepret the masked PCI-X bus speed. */
+#define E1000_STATUS_PCIX_SPEED_66 0x00000000 /* PCI-X bus speed 50-66 MHz */
+#define E1000_STATUS_PCIX_SPEED_100 0x00004000 /* PCI-X bus speed 66-100 MHz */
+#define E1000_STATUS_PCIX_SPEED_133 0x00008000 /* PCI-X bus speed 100-133 MHz */
+
+/* EEPROM/Flash Control */
+#define E1000_EECD_SK 0x00000001 /* EEPROM Clock */
+#define E1000_EECD_CS 0x00000002 /* EEPROM Chip Select */
+#define E1000_EECD_DI 0x00000004 /* EEPROM Data In */
+#define E1000_EECD_DO 0x00000008 /* EEPROM Data Out */
+#define E1000_EECD_FWE_MASK 0x00000030
+#define E1000_EECD_FWE_DIS 0x00000010 /* Disable FLASH writes */
+#define E1000_EECD_FWE_EN 0x00000020 /* Enable FLASH writes */
+#define E1000_EECD_FWE_SHIFT 4
+#define E1000_EECD_REQ 0x00000040 /* EEPROM Access Request */
+#define E1000_EECD_GNT 0x00000080 /* EEPROM Access Grant */
+#define E1000_EECD_PRES 0x00000100 /* EEPROM Present */
+#define E1000_EECD_SIZE 0x00000200 /* EEPROM Size (0=64 word 1=256 word) */
+#define E1000_EECD_ADDR_BITS 0x00000400 /* EEPROM Addressing bits based on type
+ * (0-small, 1-large) */
+#define E1000_EECD_TYPE 0x00002000 /* EEPROM Type (1-SPI, 0-Microwire) */
+#ifndef E1000_EEPROM_GRANT_ATTEMPTS
+#define E1000_EEPROM_GRANT_ATTEMPTS 1000 /* EEPROM # attempts to gain grant */
+#endif
+#define E1000_EECD_AUTO_RD 0x00000200 /* EEPROM Auto Read done */
+#define E1000_EECD_SIZE_EX_MASK 0x00007800 /* EEprom Size */
+#define E1000_EECD_SIZE_EX_SHIFT 11
+#define E1000_EECD_NVADDS 0x00018000 /* NVM Address Size */
+#define E1000_EECD_SELSHAD 0x00020000 /* Select Shadow RAM */
+#define E1000_EECD_INITSRAM 0x00040000 /* Initialize Shadow RAM */
+#define E1000_EECD_FLUPD 0x00080000 /* Update FLASH */
+#define E1000_EECD_AUPDEN 0x00100000 /* Enable Autonomous FLASH update */
+#define E1000_EECD_SHADV 0x00200000 /* Shadow RAM Data Valid */
+#define E1000_EECD_SEC1VAL 0x00400000 /* Sector One Valid */
+#define E1000_STM_OPCODE 0xDB00
+#define E1000_HICR_FW_RESET 0xC0
+
+/* EEPROM Read */
+#define E1000_EERD_START 0x00000001 /* Start Read */
+#define E1000_EERD_DONE 0x00000010 /* Read Done */
+#define E1000_EERD_ADDR_SHIFT 8
+#define E1000_EERD_ADDR_MASK 0x0000FF00 /* Read Address */
+#define E1000_EERD_DATA_SHIFT 16
+#define E1000_EERD_DATA_MASK 0xFFFF0000 /* Read Data */
+
+/* SPI EEPROM Status Register */
+#define EEPROM_STATUS_RDY_SPI 0x01
+#define EEPROM_STATUS_WEN_SPI 0x02
+#define EEPROM_STATUS_BP0_SPI 0x04
+#define EEPROM_STATUS_BP1_SPI 0x08
+#define EEPROM_STATUS_WPEN_SPI 0x80
+
+/* Extended Device Control */
+#define E1000_CTRL_EXT_GPI0_EN 0x00000001 /* Maps SDP4 to GPI0 */
+#define E1000_CTRL_EXT_GPI1_EN 0x00000002 /* Maps SDP5 to GPI1 */
+#define E1000_CTRL_EXT_PHYINT_EN E1000_CTRL_EXT_GPI1_EN
+#define E1000_CTRL_EXT_GPI2_EN 0x00000004 /* Maps SDP6 to GPI2 */
+#define E1000_CTRL_EXT_GPI3_EN 0x00000008 /* Maps SDP7 to GPI3 */
+#define E1000_CTRL_EXT_SDP4_DATA 0x00000010 /* Value of SW Defineable Pin 4 */
+#define E1000_CTRL_EXT_SDP5_DATA 0x00000020 /* Value of SW Defineable Pin 5 */
+#define E1000_CTRL_EXT_PHY_INT E1000_CTRL_EXT_SDP5_DATA
+#define E1000_CTRL_EXT_SDP6_DATA 0x00000040 /* Value of SW Defineable Pin 6 */
+#define E1000_CTRL_EXT_SDP7_DATA 0x00000080 /* Value of SW Defineable Pin 7 */
+#define E1000_CTRL_EXT_SDP4_DIR 0x00000100 /* Direction of SDP4 0=in 1=out */
+#define E1000_CTRL_EXT_SDP5_DIR 0x00000200 /* Direction of SDP5 0=in 1=out */
+#define E1000_CTRL_EXT_SDP6_DIR 0x00000400 /* Direction of SDP6 0=in 1=out */
+#define E1000_CTRL_EXT_SDP7_DIR 0x00000800 /* Direction of SDP7 0=in 1=out */
+#define E1000_CTRL_EXT_ASDCHK 0x00001000 /* Initiate an ASD sequence */
+#define E1000_CTRL_EXT_EE_RST 0x00002000 /* Reinitialize from EEPROM */
+#define E1000_CTRL_EXT_IPS 0x00004000 /* Invert Power State */
+#define E1000_CTRL_EXT_SPD_BYPS 0x00008000 /* Speed Select Bypass */
+#define E1000_CTRL_EXT_LINK_MODE_MASK 0x00C00000
+#define E1000_CTRL_EXT_LINK_MODE_GMII 0x00000000
+#define E1000_CTRL_EXT_LINK_MODE_TBI 0x00C00000
+#define E1000_CTRL_EXT_WR_WMARK_MASK 0x03000000
+#define E1000_CTRL_EXT_WR_WMARK_256 0x00000000
+#define E1000_CTRL_EXT_WR_WMARK_320 0x01000000
+#define E1000_CTRL_EXT_WR_WMARK_384 0x02000000
+#define E1000_CTRL_EXT_WR_WMARK_448 0x03000000
+#define E1000_CTRL_EXT_IAME 0x08000000 /* Interrupt acknowledge Auto-mask */
+#define E1000_CTRL_EXT_INT_TIMER_CLR 0x20000000 /* Clear Interrupt timers after IMS clear */
+
+/* MDI Control */
+#define E1000_MDIC_DATA_MASK 0x0000FFFF
+#define E1000_MDIC_REG_MASK 0x001F0000
+#define E1000_MDIC_REG_SHIFT 16
+#define E1000_MDIC_PHY_MASK 0x03E00000
+#define E1000_MDIC_PHY_SHIFT 21
+#define E1000_MDIC_OP_WRITE 0x04000000
+#define E1000_MDIC_OP_READ 0x08000000
+#define E1000_MDIC_READY 0x10000000
+#define E1000_MDIC_INT_EN 0x20000000
+#define E1000_MDIC_ERROR 0x40000000
+
+/* LED Control */
+#define E1000_LEDCTL_LED0_MODE_MASK 0x0000000F
+#define E1000_LEDCTL_LED0_MODE_SHIFT 0
+#define E1000_LEDCTL_LED0_BLINK_RATE 0x0000020
+#define E1000_LEDCTL_LED0_IVRT 0x00000040
+#define E1000_LEDCTL_LED0_BLINK 0x00000080
+#define E1000_LEDCTL_LED1_MODE_MASK 0x00000F00
+#define E1000_LEDCTL_LED1_MODE_SHIFT 8
+#define E1000_LEDCTL_LED1_BLINK_RATE 0x0002000
+#define E1000_LEDCTL_LED1_IVRT 0x00004000
+#define E1000_LEDCTL_LED1_BLINK 0x00008000
+#define E1000_LEDCTL_LED2_MODE_MASK 0x000F0000
+#define E1000_LEDCTL_LED2_MODE_SHIFT 16
+#define E1000_LEDCTL_LED2_BLINK_RATE 0x00200000
+#define E1000_LEDCTL_LED2_IVRT 0x00400000
+#define E1000_LEDCTL_LED2_BLINK 0x00800000
+#define E1000_LEDCTL_LED3_MODE_MASK 0x0F000000
+#define E1000_LEDCTL_LED3_MODE_SHIFT 24
+#define E1000_LEDCTL_LED3_IVRT 0x40000000
+#define E1000_LEDCTL_LED3_BLINK 0x80000000
+
+#define E1000_LEDCTL_MODE_LINK_10_1000 0x0
+#define E1000_LEDCTL_MODE_LINK_100_1000 0x1
+#define E1000_LEDCTL_MODE_LINK_UP 0x2
+#define E1000_LEDCTL_MODE_ACTIVITY 0x3
+#define E1000_LEDCTL_MODE_LINK_ACTIVITY 0x4
+#define E1000_LEDCTL_MODE_LINK_10 0x5
+#define E1000_LEDCTL_MODE_LINK_100 0x6
+#define E1000_LEDCTL_MODE_LINK_1000 0x7
+#define E1000_LEDCTL_MODE_PCIX_MODE 0x8
+#define E1000_LEDCTL_MODE_FULL_DUPLEX 0x9
+#define E1000_LEDCTL_MODE_COLLISION 0xA
+#define E1000_LEDCTL_MODE_BUS_SPEED 0xB
+#define E1000_LEDCTL_MODE_BUS_SIZE 0xC
+#define E1000_LEDCTL_MODE_PAUSED 0xD
+#define E1000_LEDCTL_MODE_LED_ON 0xE
+#define E1000_LEDCTL_MODE_LED_OFF 0xF
+
+/* Receive Address */
+#define E1000_RAH_AV 0x80000000 /* Receive descriptor valid */
+
+/* Interrupt Cause Read */
+#define E1000_ICR_TXDW 0x00000001 /* Transmit desc written back */
+#define E1000_ICR_TXQE 0x00000002 /* Transmit Queue empty */
+#define E1000_ICR_LSC 0x00000004 /* Link Status Change */
+#define E1000_ICR_RXSEQ 0x00000008 /* rx sequence error */
+#define E1000_ICR_RXDMT0 0x00000010 /* rx desc min. threshold (0) */
+#define E1000_ICR_RXO 0x00000040 /* rx overrun */
+#define E1000_ICR_RXT0 0x00000080 /* rx timer intr (ring 0) */
+#define E1000_ICR_MDAC 0x00000200 /* MDIO access complete */
+#define E1000_ICR_RXCFG 0x00000400 /* RX /c/ ordered set */
+#define E1000_ICR_GPI_EN0 0x00000800 /* GP Int 0 */
+#define E1000_ICR_GPI_EN1 0x00001000 /* GP Int 1 */
+#define E1000_ICR_GPI_EN2 0x00002000 /* GP Int 2 */
+#define E1000_ICR_GPI_EN3 0x00004000 /* GP Int 3 */
+#define E1000_ICR_TXD_LOW 0x00008000
+#define E1000_ICR_SRPD 0x00010000
+#define E1000_ICR_ACK 0x00020000 /* Receive Ack frame */
+#define E1000_ICR_MNG 0x00040000 /* Manageability event */
+#define E1000_ICR_DOCK 0x00080000 /* Dock/Undock */
+#define E1000_ICR_INT_ASSERTED 0x80000000 /* If this bit asserted, the driver should claim the interrupt */
+
+/* Interrupt Cause Set */
+#define E1000_ICS_TXDW E1000_ICR_TXDW /* Transmit desc written back */
+#define E1000_ICS_TXQE E1000_ICR_TXQE /* Transmit Queue empty */
+#define E1000_ICS_LSC E1000_ICR_LSC /* Link Status Change */
+#define E1000_ICS_RXSEQ E1000_ICR_RXSEQ /* rx sequence error */
+#define E1000_ICS_RXDMT0 E1000_ICR_RXDMT0 /* rx desc min. threshold */
+#define E1000_ICS_RXO E1000_ICR_RXO /* rx overrun */
+#define E1000_ICS_RXT0 E1000_ICR_RXT0 /* rx timer intr */
+#define E1000_ICS_MDAC E1000_ICR_MDAC /* MDIO access complete */
+#define E1000_ICS_RXCFG E1000_ICR_RXCFG /* RX /c/ ordered set */
+#define E1000_ICS_GPI_EN0 E1000_ICR_GPI_EN0 /* GP Int 0 */
+#define E1000_ICS_GPI_EN1 E1000_ICR_GPI_EN1 /* GP Int 1 */
+#define E1000_ICS_GPI_EN2 E1000_ICR_GPI_EN2 /* GP Int 2 */
+#define E1000_ICS_GPI_EN3 E1000_ICR_GPI_EN3 /* GP Int 3 */
+#define E1000_ICS_TXD_LOW E1000_ICR_TXD_LOW
+#define E1000_ICS_SRPD E1000_ICR_SRPD
+#define E1000_ICS_ACK E1000_ICR_ACK /* Receive Ack frame */
+#define E1000_ICS_MNG E1000_ICR_MNG /* Manageability event */
+#define E1000_ICS_DOCK E1000_ICR_DOCK /* Dock/Undock */
+
+/* Interrupt Mask Set */
+#define E1000_IMS_TXDW E1000_ICR_TXDW /* Transmit desc written back */
+#define E1000_IMS_TXQE E1000_ICR_TXQE /* Transmit Queue empty */
+#define E1000_IMS_LSC E1000_ICR_LSC /* Link Status Change */
+#define E1000_IMS_RXSEQ E1000_ICR_RXSEQ /* rx sequence error */
+#define E1000_IMS_RXDMT0 E1000_ICR_RXDMT0 /* rx desc min. threshold */
+#define E1000_IMS_RXO E1000_ICR_RXO /* rx overrun */
+#define E1000_IMS_RXT0 E1000_ICR_RXT0 /* rx timer intr */
+#define E1000_IMS_MDAC E1000_ICR_MDAC /* MDIO access complete */
+#define E1000_IMS_RXCFG E1000_ICR_RXCFG /* RX /c/ ordered set */
+#define E1000_IMS_GPI_EN0 E1000_ICR_GPI_EN0 /* GP Int 0 */
+#define E1000_IMS_GPI_EN1 E1000_ICR_GPI_EN1 /* GP Int 1 */
+#define E1000_IMS_GPI_EN2 E1000_ICR_GPI_EN2 /* GP Int 2 */
+#define E1000_IMS_GPI_EN3 E1000_ICR_GPI_EN3 /* GP Int 3 */
+#define E1000_IMS_TXD_LOW E1000_ICR_TXD_LOW
+#define E1000_IMS_SRPD E1000_ICR_SRPD
+#define E1000_IMS_ACK E1000_ICR_ACK /* Receive Ack frame */
+#define E1000_IMS_MNG E1000_ICR_MNG /* Manageability event */
+#define E1000_IMS_DOCK E1000_ICR_DOCK /* Dock/Undock */
+
+/* Interrupt Mask Clear */
+#define E1000_IMC_TXDW E1000_ICR_TXDW /* Transmit desc written back */
+#define E1000_IMC_TXQE E1000_ICR_TXQE /* Transmit Queue empty */
+#define E1000_IMC_LSC E1000_ICR_LSC /* Link Status Change */
+#define E1000_IMC_RXSEQ E1000_ICR_RXSEQ /* rx sequence error */
+#define E1000_IMC_RXDMT0 E1000_ICR_RXDMT0 /* rx desc min. threshold */
+#define E1000_IMC_RXO E1000_ICR_RXO /* rx overrun */
+#define E1000_IMC_RXT0 E1000_ICR_RXT0 /* rx timer intr */
+#define E1000_IMC_MDAC E1000_ICR_MDAC /* MDIO access complete */
+#define E1000_IMC_RXCFG E1000_ICR_RXCFG /* RX /c/ ordered set */
+#define E1000_IMC_GPI_EN0 E1000_ICR_GPI_EN0 /* GP Int 0 */
+#define E1000_IMC_GPI_EN1 E1000_ICR_GPI_EN1 /* GP Int 1 */
+#define E1000_IMC_GPI_EN2 E1000_ICR_GPI_EN2 /* GP Int 2 */
+#define E1000_IMC_GPI_EN3 E1000_ICR_GPI_EN3 /* GP Int 3 */
+#define E1000_IMC_TXD_LOW E1000_ICR_TXD_LOW
+#define E1000_IMC_SRPD E1000_ICR_SRPD
+#define E1000_IMC_ACK E1000_ICR_ACK /* Receive Ack frame */
+#define E1000_IMC_MNG E1000_ICR_MNG /* Manageability event */
+#define E1000_IMC_DOCK E1000_ICR_DOCK /* Dock/Undock */
+
+/* Receive Control */
+#define E1000_RCTL_RST 0x00000001 /* Software reset */
+#define E1000_RCTL_EN 0x00000002 /* enable */
+#define E1000_RCTL_SBP 0x00000004 /* store bad packet */
+#define E1000_RCTL_UPE 0x00000008 /* unicast promiscuous enable */
+#define E1000_RCTL_MPE 0x00000010 /* multicast promiscuous enab */
+#define E1000_RCTL_LPE 0x00000020 /* long packet enable */
+#define E1000_RCTL_LBM_NO 0x00000000 /* no loopback mode */
+#define E1000_RCTL_LBM_MAC 0x00000040 /* MAC loopback mode */
+#define E1000_RCTL_LBM_SLP 0x00000080 /* serial link loopback mode */
+#define E1000_RCTL_LBM_TCVR 0x000000C0 /* tcvr loopback mode */
+#define E1000_RCTL_DTYP_MASK 0x00000C00 /* Descriptor type mask */
+#define E1000_RCTL_DTYP_PS 0x00000400 /* Packet Split descriptor */
+#define E1000_RCTL_RDMTS_HALF 0x00000000 /* rx desc min threshold size */
+#define E1000_RCTL_RDMTS_QUAT 0x00000100 /* rx desc min threshold size */
+#define E1000_RCTL_RDMTS_EIGTH 0x00000200 /* rx desc min threshold size */
+#define E1000_RCTL_MO_SHIFT 12 /* multicast offset shift */
+#define E1000_RCTL_MO_0 0x00000000 /* multicast offset 11:0 */
+#define E1000_RCTL_MO_1 0x00001000 /* multicast offset 12:1 */
+#define E1000_RCTL_MO_2 0x00002000 /* multicast offset 13:2 */
+#define E1000_RCTL_MO_3 0x00003000 /* multicast offset 15:4 */
+#define E1000_RCTL_MDR 0x00004000 /* multicast desc ring 0 */
+#define E1000_RCTL_BAM 0x00008000 /* broadcast enable */
+/* these buffer sizes are valid if E1000_RCTL_BSEX is 0 */
+#define E1000_RCTL_SZ_2048 0x00000000 /* rx buffer size 2048 */
+#define E1000_RCTL_SZ_1024 0x00010000 /* rx buffer size 1024 */
+#define E1000_RCTL_SZ_512 0x00020000 /* rx buffer size 512 */
+#define E1000_RCTL_SZ_256 0x00030000 /* rx buffer size 256 */
+/* these buffer sizes are valid if E1000_RCTL_BSEX is 1 */
+#define E1000_RCTL_SZ_16384 0x00010000 /* rx buffer size 16384 */
+#define E1000_RCTL_SZ_8192 0x00020000 /* rx buffer size 8192 */
+#define E1000_RCTL_SZ_4096 0x00030000 /* rx buffer size 4096 */
+#define E1000_RCTL_VFE 0x00040000 /* vlan filter enable */
+#define E1000_RCTL_CFIEN 0x00080000 /* canonical form enable */
+#define E1000_RCTL_CFI 0x00100000 /* canonical form indicator */
+#define E1000_RCTL_DPF 0x00400000 /* discard pause frames */
+#define E1000_RCTL_PMCF 0x00800000 /* pass MAC control frames */
+#define E1000_RCTL_BSEX 0x02000000 /* Buffer size extension */
+#define E1000_RCTL_SECRC 0x04000000 /* Strip Ethernet CRC */
+#define E1000_RCTL_FLXBUF_MASK 0x78000000 /* Flexible buffer size */
+#define E1000_RCTL_FLXBUF_SHIFT 27 /* Flexible buffer shift */
+
+/* Use byte values for the following shift parameters
+ * Usage:
+ * psrctl |= (((ROUNDUP(value0, 128) >> E1000_PSRCTL_BSIZE0_SHIFT) &
+ * E1000_PSRCTL_BSIZE0_MASK) |
+ * ((ROUNDUP(value1, 1024) >> E1000_PSRCTL_BSIZE1_SHIFT) &
+ * E1000_PSRCTL_BSIZE1_MASK) |
+ * ((ROUNDUP(value2, 1024) << E1000_PSRCTL_BSIZE2_SHIFT) &
+ * E1000_PSRCTL_BSIZE2_MASK) |
+ * ((ROUNDUP(value3, 1024) << E1000_PSRCTL_BSIZE3_SHIFT) |;
+ * E1000_PSRCTL_BSIZE3_MASK))
+ * where value0 = [128..16256], default=256
+ * value1 = [1024..64512], default=4096
+ * value2 = [0..64512], default=4096
+ * value3 = [0..64512], default=0
+ */
+
+#define E1000_PSRCTL_BSIZE0_MASK 0x0000007F
+#define E1000_PSRCTL_BSIZE1_MASK 0x00003F00
+#define E1000_PSRCTL_BSIZE2_MASK 0x003F0000
+#define E1000_PSRCTL_BSIZE3_MASK 0x3F000000
+
+#define E1000_PSRCTL_BSIZE0_SHIFT 7 /* Shift _right_ 7 */
+#define E1000_PSRCTL_BSIZE1_SHIFT 2 /* Shift _right_ 2 */
+#define E1000_PSRCTL_BSIZE2_SHIFT 6 /* Shift _left_ 6 */
+#define E1000_PSRCTL_BSIZE3_SHIFT 14 /* Shift _left_ 14 */
+
+/* Receive Descriptor */
+#define E1000_RDT_DELAY 0x0000ffff /* Delay timer (1=1024us) */
+#define E1000_RDT_FPDB 0x80000000 /* Flush descriptor block */
+#define E1000_RDLEN_LEN 0x0007ff80 /* descriptor length */
+#define E1000_RDH_RDH 0x0000ffff /* receive descriptor head */
+#define E1000_RDT_RDT 0x0000ffff /* receive descriptor tail */
+
+/* Flow Control */
+#define E1000_FCRTH_RTH 0x0000FFF8 /* Mask Bits[15:3] for RTH */
+#define E1000_FCRTH_XFCE 0x80000000 /* External Flow Control Enable */
+#define E1000_FCRTL_RTL 0x0000FFF8 /* Mask Bits[15:3] for RTL */
+#define E1000_FCRTL_XONE 0x80000000 /* Enable XON frame transmission */
+
+/* Header split receive */
+#define E1000_RFCTL_ISCSI_DIS 0x00000001
+#define E1000_RFCTL_ISCSI_DWC_MASK 0x0000003E
+#define E1000_RFCTL_ISCSI_DWC_SHIFT 1
+#define E1000_RFCTL_NFSW_DIS 0x00000040
+#define E1000_RFCTL_NFSR_DIS 0x00000080
+#define E1000_RFCTL_NFS_VER_MASK 0x00000300
+#define E1000_RFCTL_NFS_VER_SHIFT 8
+#define E1000_RFCTL_IPV6_DIS 0x00000400
+#define E1000_RFCTL_IPV6_XSUM_DIS 0x00000800
+#define E1000_RFCTL_ACK_DIS 0x00001000
+#define E1000_RFCTL_ACKD_DIS 0x00002000
+#define E1000_RFCTL_IPFRSP_DIS 0x00004000
+#define E1000_RFCTL_EXTEN 0x00008000
+#define E1000_RFCTL_IPV6_EX_DIS 0x00010000
+#define E1000_RFCTL_NEW_IPV6_EXT_DIS 0x00020000
+
+/* Receive Descriptor Control */
+#define E1000_RXDCTL_PTHRESH 0x0000003F /* RXDCTL Prefetch Threshold */
+#define E1000_RXDCTL_HTHRESH 0x00003F00 /* RXDCTL Host Threshold */
+#define E1000_RXDCTL_WTHRESH 0x003F0000 /* RXDCTL Writeback Threshold */
+#define E1000_RXDCTL_GRAN 0x01000000 /* RXDCTL Granularity */
+
+/* Transmit Descriptor Control */
+#define E1000_TXDCTL_PTHRESH 0x000000FF /* TXDCTL Prefetch Threshold */
+#define E1000_TXDCTL_HTHRESH 0x0000FF00 /* TXDCTL Host Threshold */
+#define E1000_TXDCTL_WTHRESH 0x00FF0000 /* TXDCTL Writeback Threshold */
+#define E1000_TXDCTL_GRAN 0x01000000 /* TXDCTL Granularity */
+#define E1000_TXDCTL_LWTHRESH 0xFE000000 /* TXDCTL Low Threshold */
+#define E1000_TXDCTL_FULL_TX_DESC_WB 0x01010000 /* GRAN=1, WTHRESH=1 */
+#define E1000_TXDCTL_COUNT_DESC 0x00400000 /* Enable the counting of desc.
+ still to be processed. */
+
+/* Transmit Configuration Word */
+#define E1000_TXCW_FD 0x00000020 /* TXCW full duplex */
+#define E1000_TXCW_HD 0x00000040 /* TXCW half duplex */
+#define E1000_TXCW_PAUSE 0x00000080 /* TXCW sym pause request */
+#define E1000_TXCW_ASM_DIR 0x00000100 /* TXCW astm pause direction */
+#define E1000_TXCW_PAUSE_MASK 0x00000180 /* TXCW pause request mask */
+#define E1000_TXCW_RF 0x00003000 /* TXCW remote fault */
+#define E1000_TXCW_NP 0x00008000 /* TXCW next page */
+#define E1000_TXCW_CW 0x0000ffff /* TxConfigWord mask */
+#define E1000_TXCW_TXC 0x40000000 /* Transmit Config control */
+#define E1000_TXCW_ANE 0x80000000 /* Auto-neg enable */
+
+/* Receive Configuration Word */
+#define E1000_RXCW_CW 0x0000ffff /* RxConfigWord mask */
+#define E1000_RXCW_NC 0x04000000 /* Receive config no carrier */
+#define E1000_RXCW_IV 0x08000000 /* Receive config invalid */
+#define E1000_RXCW_CC 0x10000000 /* Receive config change */
+#define E1000_RXCW_C 0x20000000 /* Receive config */
+#define E1000_RXCW_SYNCH 0x40000000 /* Receive config synch */
+#define E1000_RXCW_ANC 0x80000000 /* Auto-neg complete */
+
+/* Transmit Control */
+#define E1000_TCTL_RST 0x00000001 /* software reset */
+#define E1000_TCTL_EN 0x00000002 /* enable tx */
+#define E1000_TCTL_BCE 0x00000004 /* busy check enable */
+#define E1000_TCTL_PSP 0x00000008 /* pad short packets */
+#define E1000_TCTL_CT 0x00000ff0 /* collision threshold */
+#define E1000_TCTL_COLD 0x003ff000 /* collision distance */
+#define E1000_TCTL_SWXOFF 0x00400000 /* SW Xoff transmission */
+#define E1000_TCTL_PBE 0x00800000 /* Packet Burst Enable */
+#define E1000_TCTL_RTLC 0x01000000 /* Re-transmit on late collision */
+#define E1000_TCTL_NRTU 0x02000000 /* No Re-transmit on underrun */
+#define E1000_TCTL_MULR 0x10000000 /* Multiple request support */
+
+/* Receive Checksum Control */
+#define E1000_RXCSUM_PCSS_MASK 0x000000FF /* Packet Checksum Start */
+#define E1000_RXCSUM_IPOFL 0x00000100 /* IPv4 checksum offload */
+#define E1000_RXCSUM_TUOFL 0x00000200 /* TCP / UDP checksum offload */
+#define E1000_RXCSUM_IPV6OFL 0x00000400 /* IPv6 checksum offload */
+#define E1000_RXCSUM_IPPCSE 0x00001000 /* IP payload checksum enable */
+#define E1000_RXCSUM_PCSD 0x00002000 /* packet checksum disabled */
+
+
+/* Definitions for power management and wakeup registers */
+/* Wake Up Control */
+#define E1000_WUC_APME 0x00000001 /* APM Enable */
+#define E1000_WUC_PME_EN 0x00000002 /* PME Enable */
+#define E1000_WUC_PME_STATUS 0x00000004 /* PME Status */
+#define E1000_WUC_APMPME 0x00000008 /* Assert PME on APM Wakeup */
+#define E1000_WUC_SPM 0x80000000 /* Enable SPM */
+
+/* Wake Up Filter Control */
+#define E1000_WUFC_LNKC 0x00000001 /* Link Status Change Wakeup Enable */
+#define E1000_WUFC_MAG 0x00000002 /* Magic Packet Wakeup Enable */
+#define E1000_WUFC_EX 0x00000004 /* Directed Exact Wakeup Enable */
+#define E1000_WUFC_MC 0x00000008 /* Directed Multicast Wakeup Enable */
+#define E1000_WUFC_BC 0x00000010 /* Broadcast Wakeup Enable */
+#define E1000_WUFC_ARP 0x00000020 /* ARP Request Packet Wakeup Enable */
+#define E1000_WUFC_IPV4 0x00000040 /* Directed IPv4 Packet Wakeup Enable */
+#define E1000_WUFC_IPV6 0x00000080 /* Directed IPv6 Packet Wakeup Enable */
+#define E1000_WUFC_IGNORE_TCO 0x00008000 /* Ignore WakeOn TCO packets */
+#define E1000_WUFC_FLX0 0x00010000 /* Flexible Filter 0 Enable */
+#define E1000_WUFC_FLX1 0x00020000 /* Flexible Filter 1 Enable */
+#define E1000_WUFC_FLX2 0x00040000 /* Flexible Filter 2 Enable */
+#define E1000_WUFC_FLX3 0x00080000 /* Flexible Filter 3 Enable */
+#define E1000_WUFC_ALL_FILTERS 0x000F00FF /* Mask for all wakeup filters */
+#define E1000_WUFC_FLX_OFFSET 16 /* Offset to the Flexible Filters bits */
+#define E1000_WUFC_FLX_FILTERS 0x000F0000 /* Mask for the 4 flexible filters */
+
+/* Wake Up Status */
+#define E1000_WUS_LNKC 0x00000001 /* Link Status Changed */
+#define E1000_WUS_MAG 0x00000002 /* Magic Packet Received */
+#define E1000_WUS_EX 0x00000004 /* Directed Exact Received */
+#define E1000_WUS_MC 0x00000008 /* Directed Multicast Received */
+#define E1000_WUS_BC 0x00000010 /* Broadcast Received */
+#define E1000_WUS_ARP 0x00000020 /* ARP Request Packet Received */
+#define E1000_WUS_IPV4 0x00000040 /* Directed IPv4 Packet Wakeup Received */
+#define E1000_WUS_IPV6 0x00000080 /* Directed IPv6 Packet Wakeup Received */
+#define E1000_WUS_FLX0 0x00010000 /* Flexible Filter 0 Match */
+#define E1000_WUS_FLX1 0x00020000 /* Flexible Filter 1 Match */
+#define E1000_WUS_FLX2 0x00040000 /* Flexible Filter 2 Match */
+#define E1000_WUS_FLX3 0x00080000 /* Flexible Filter 3 Match */
+#define E1000_WUS_FLX_FILTERS 0x000F0000 /* Mask for the 4 flexible filters */
+
+/* Management Control */
+#define E1000_MANC_SMBUS_EN 0x00000001 /* SMBus Enabled - RO */
+#define E1000_MANC_ASF_EN 0x00000002 /* ASF Enabled - RO */
+#define E1000_MANC_R_ON_FORCE 0x00000004 /* Reset on Force TCO - RO */
+#define E1000_MANC_RMCP_EN 0x00000100 /* Enable RCMP 026Fh Filtering */
+#define E1000_MANC_0298_EN 0x00000200 /* Enable RCMP 0298h Filtering */
+#define E1000_MANC_IPV4_EN 0x00000400 /* Enable IPv4 */
+#define E1000_MANC_IPV6_EN 0x00000800 /* Enable IPv6 */
+#define E1000_MANC_SNAP_EN 0x00001000 /* Accept LLC/SNAP */
+#define E1000_MANC_ARP_EN 0x00002000 /* Enable ARP Request Filtering */
+#define E1000_MANC_NEIGHBOR_EN 0x00004000 /* Enable Neighbor Discovery
+ * Filtering */
+#define E1000_MANC_ARP_RES_EN 0x00008000 /* Enable ARP response Filtering */
+#define E1000_MANC_TCO_RESET 0x00010000 /* TCO Reset Occurred */
+#define E1000_MANC_RCV_TCO_EN 0x00020000 /* Receive TCO Packets Enabled */
+#define E1000_MANC_REPORT_STATUS 0x00040000 /* Status Reporting Enabled */
+#define E1000_MANC_BLK_PHY_RST_ON_IDE 0x00040000 /* Block phy resets */
+#define E1000_MANC_EN_MAC_ADDR_FILTER 0x00100000 /* Enable MAC address
+ * filtering */
+#define E1000_MANC_EN_MNG2HOST 0x00200000 /* Enable MNG packets to host
+ * memory */
+#define E1000_MANC_EN_IP_ADDR_FILTER 0x00400000 /* Enable IP address
+ * filtering */
+#define E1000_MANC_EN_XSUM_FILTER 0x00800000 /* Enable checksum filtering */
+#define E1000_MANC_BR_EN 0x01000000 /* Enable broadcast filtering */
+#define E1000_MANC_SMB_REQ 0x01000000 /* SMBus Request */
+#define E1000_MANC_SMB_GNT 0x02000000 /* SMBus Grant */
+#define E1000_MANC_SMB_CLK_IN 0x04000000 /* SMBus Clock In */
+#define E1000_MANC_SMB_DATA_IN 0x08000000 /* SMBus Data In */
+#define E1000_MANC_SMB_DATA_OUT 0x10000000 /* SMBus Data Out */
+#define E1000_MANC_SMB_CLK_OUT 0x20000000 /* SMBus Clock Out */
+
+#define E1000_MANC_SMB_DATA_OUT_SHIFT 28 /* SMBus Data Out Shift */
+#define E1000_MANC_SMB_CLK_OUT_SHIFT 29 /* SMBus Clock Out Shift */
+
+/* SW Semaphore Register */
+#define E1000_SWSM_SMBI 0x00000001 /* Driver Semaphore bit */
+#define E1000_SWSM_SWESMBI 0x00000002 /* FW Semaphore bit */
+#define E1000_SWSM_WMNG 0x00000004 /* Wake MNG Clock */
+#define E1000_SWSM_DRV_LOAD 0x00000008 /* Driver Loaded Bit */
+
+/* FW Semaphore Register */
+#define E1000_FWSM_MODE_MASK 0x0000000E /* FW mode */
+#define E1000_FWSM_MODE_SHIFT 1
+#define E1000_FWSM_FW_VALID 0x00008000 /* FW established a valid mode */
+
+/* FFLT Debug Register */
+#define E1000_FFLT_DBG_INVC 0x00100000 /* Invalid /C/ code handling */
+
+typedef enum {
+ em_mng_mode_none = 0,
+ em_mng_mode_asf,
+ em_mng_mode_pt,
+ em_mng_mode_ipmi,
+ em_mng_mode_host_interface_only
+} em_mng_mode;
+
+/* Host Inteface Control Register */
+#define E1000_HICR_EN 0x00000001 /* Enable Bit - RO */
+#define E1000_HICR_C 0x00000002 /* Driver sets this bit when done
+ * to put command in RAM */
+#define E1000_HICR_SV 0x00000004 /* Status Validity */
+#define E1000_HICR_FWR 0x00000080 /* FW reset. Set by the Host */
+
+/* Host Interface Command Interface - Address range 0x8800-0x8EFF */
+#define E1000_HI_MAX_DATA_LENGTH 252 /* Host Interface data length */
+#define E1000_HI_MAX_BLOCK_BYTE_LENGTH 1792 /* Number of bytes in range */
+#define E1000_HI_MAX_BLOCK_DWORD_LENGTH 448 /* Number of dwords in range */
+#define E1000_HI_COMMAND_TIMEOUT 500 /* Time in ms to process HI command */
+
+struct em_host_command_header {
+ uint8_t command_id;
+ uint8_t command_length;
+ uint8_t command_options; /* I/F bits for command, status for return */
+ uint8_t checksum;
+};
+struct em_host_command_info {
+ struct em_host_command_header command_header; /* Command Head/Command Result Head has 4 bytes */
+ uint8_t command_data[E1000_HI_MAX_DATA_LENGTH]; /* Command data can length 0..252 */
+};
+
+/* Host SMB register #0 */
+#define E1000_HSMC0R_CLKIN 0x00000001 /* SMB Clock in */
+#define E1000_HSMC0R_DATAIN 0x00000002 /* SMB Data in */
+#define E1000_HSMC0R_DATAOUT 0x00000004 /* SMB Data out */
+#define E1000_HSMC0R_CLKOUT 0x00000008 /* SMB Clock out */
+
+/* Host SMB register #1 */
+#define E1000_HSMC1R_CLKIN E1000_HSMC0R_CLKIN
+#define E1000_HSMC1R_DATAIN E1000_HSMC0R_DATAIN
+#define E1000_HSMC1R_DATAOUT E1000_HSMC0R_DATAOUT
+#define E1000_HSMC1R_CLKOUT E1000_HSMC0R_CLKOUT
+
+/* FW Status Register */
+#define E1000_FWSTS_FWS_MASK 0x000000FF /* FW Status */
+
+/* Wake Up Packet Length */
+#define E1000_WUPL_LENGTH_MASK 0x0FFF /* Only the lower 12 bits are valid */
+
+#define E1000_MDALIGN 4096
+
+#define E1000_GCR_BEM32 0x00400000
+/* Function Active and Power State to MNG */
+#define E1000_FACTPS_FUNC0_POWER_STATE_MASK 0x00000003
+#define E1000_FACTPS_LAN0_VALID 0x00000004
+#define E1000_FACTPS_FUNC0_AUX_EN 0x00000008
+#define E1000_FACTPS_FUNC1_POWER_STATE_MASK 0x000000C0
+#define E1000_FACTPS_FUNC1_POWER_STATE_SHIFT 6
+#define E1000_FACTPS_LAN1_VALID 0x00000100
+#define E1000_FACTPS_FUNC1_AUX_EN 0x00000200
+#define E1000_FACTPS_FUNC2_POWER_STATE_MASK 0x00003000
+#define E1000_FACTPS_FUNC2_POWER_STATE_SHIFT 12
+#define E1000_FACTPS_IDE_ENABLE 0x00004000
+#define E1000_FACTPS_FUNC2_AUX_EN 0x00008000
+#define E1000_FACTPS_FUNC3_POWER_STATE_MASK 0x000C0000
+#define E1000_FACTPS_FUNC3_POWER_STATE_SHIFT 18
+#define E1000_FACTPS_SP_ENABLE 0x00100000
+#define E1000_FACTPS_FUNC3_AUX_EN 0x00200000
+#define E1000_FACTPS_FUNC4_POWER_STATE_MASK 0x03000000
+#define E1000_FACTPS_FUNC4_POWER_STATE_SHIFT 24
+#define E1000_FACTPS_IPMI_ENABLE 0x04000000
+#define E1000_FACTPS_FUNC4_AUX_EN 0x08000000
+#define E1000_FACTPS_MNGCG 0x20000000
+#define E1000_FACTPS_LAN_FUNC_SEL 0x40000000
+#define E1000_FACTPS_PM_STATE_CHANGED 0x80000000
+
+/* EEPROM Commands - Microwire */
+#define EEPROM_READ_OPCODE_MICROWIRE 0x6 /* EEPROM read opcode */
+#define EEPROM_WRITE_OPCODE_MICROWIRE 0x5 /* EEPROM write opcode */
+#define EEPROM_ERASE_OPCODE_MICROWIRE 0x7 /* EEPROM erase opcode */
+#define EEPROM_EWEN_OPCODE_MICROWIRE 0x13 /* EEPROM erase/write enable */
+#define EEPROM_EWDS_OPCODE_MICROWIRE 0x10 /* EEPROM erast/write disable */
+
+/* EEPROM Commands - SPI */
+#define EEPROM_MAX_RETRY_SPI 5000 /* Max wait of 5ms, for RDY signal */
+#define EEPROM_READ_OPCODE_SPI 0x03 /* EEPROM read opcode */
+#define EEPROM_WRITE_OPCODE_SPI 0x02 /* EEPROM write opcode */
+#define EEPROM_A8_OPCODE_SPI 0x08 /* opcode bit-3 = address bit-8 */
+#define EEPROM_WREN_OPCODE_SPI 0x06 /* EEPROM set Write Enable latch */
+#define EEPROM_WRDI_OPCODE_SPI 0x04 /* EEPROM reset Write Enable latch */
+#define EEPROM_RDSR_OPCODE_SPI 0x05 /* EEPROM read Status register */
+#define EEPROM_WRSR_OPCODE_SPI 0x01 /* EEPROM write Status register */
+#define EEPROM_ERASE4K_OPCODE_SPI 0x20 /* EEPROM ERASE 4KB */
+#define EEPROM_ERASE64K_OPCODE_SPI 0xD8 /* EEPROM ERASE 64KB */
+#define EEPROM_ERASE256_OPCODE_SPI 0xDB /* EEPROM ERASE 256B */
+
+/* EEPROM Size definitions */
+#define EEPROM_WORD_SIZE_SHIFT 6
+#define EEPROM_SIZE_SHIFT 10
+#define EEPROM_SIZE_MASK 0x1C00
+
+/* EEPROM Word Offsets */
+#define EEPROM_COMPAT 0x0003
+#define EEPROM_ID_LED_SETTINGS 0x0004
+#define EEPROM_SERDES_AMPLITUDE 0x0006 /* For SERDES output amplitude adjustment. */
+#define EEPROM_PHY_CLASS_WORD 0x0007
+#define EEPROM_INIT_CONTROL1_REG 0x000A
+#define EEPROM_INIT_CONTROL2_REG 0x000F
+#define EEPROM_INIT_CONTROL3_PORT_B 0x0014
+#define EEPROM_INIT_CONTROL3_PORT_A 0x0024
+#define EEPROM_CFG 0x0012
+#define EEPROM_FLASH_VERSION 0x0032
+#define EEPROM_CHECKSUM_REG 0x003F
+
+/* Word definitions for ID LED Settings */
+#define ID_LED_RESERVED_0000 0x0000
+#define ID_LED_RESERVED_FFFF 0xFFFF
+#define ID_LED_DEFAULT ((ID_LED_OFF1_ON2 << 12) | \
+ (ID_LED_OFF1_OFF2 << 8) | \
+ (ID_LED_DEF1_DEF2 << 4) | \
+ (ID_LED_DEF1_DEF2))
+#define ID_LED_DEF1_DEF2 0x1
+#define ID_LED_DEF1_ON2 0x2
+#define ID_LED_DEF1_OFF2 0x3
+#define ID_LED_ON1_DEF2 0x4
+#define ID_LED_ON1_ON2 0x5
+#define ID_LED_ON1_OFF2 0x6
+#define ID_LED_OFF1_DEF2 0x7
+#define ID_LED_OFF1_ON2 0x8
+#define ID_LED_OFF1_OFF2 0x9
+
+#define IGP_ACTIVITY_LED_MASK 0xFFFFF0FF
+#define IGP_ACTIVITY_LED_ENABLE 0x0300
+#define IGP_LED3_MODE 0x07000000
+
+
+/* Mask bits for SERDES amplitude adjustment in Word 6 of the EEPROM */
+#define EEPROM_SERDES_AMPLITUDE_MASK 0x000F
+
+/* Mask bit for PHY class in Word 7 of the EEPROM */
+#define EEPROM_PHY_CLASS_A 0x8000
+
+/* Mask bits for fields in Word 0x0a of the EEPROM */
+#define EEPROM_WORD0A_ILOS 0x0010
+#define EEPROM_WORD0A_SWDPIO 0x01E0
+#define EEPROM_WORD0A_LRST 0x0200
+#define EEPROM_WORD0A_FD 0x0400
+#define EEPROM_WORD0A_66MHZ 0x0800
+
+/* Mask bits for fields in Word 0x0f of the EEPROM */
+#define EEPROM_WORD0F_PAUSE_MASK 0x3000
+#define EEPROM_WORD0F_PAUSE 0x1000
+#define EEPROM_WORD0F_ASM_DIR 0x2000
+#define EEPROM_WORD0F_ANE 0x0800
+#define EEPROM_WORD0F_SWPDIO_EXT 0x00F0
+
+/* For checksumming, the sum of all words in the EEPROM should equal 0xBABA. */
+#define EEPROM_SUM 0xBABA
+
+/* EEPROM Map defines (WORD OFFSETS)*/
+#define EEPROM_NODE_ADDRESS_BYTE_0 0
+#define EEPROM_PBA_BYTE_1 8
+
+#define EEPROM_RESERVED_WORD 0xFFFF
+
+/* EEPROM Map Sizes (Byte Counts) */
+#define PBA_SIZE 4
+
+/* Collision related configuration parameters */
+#define E1000_COLLISION_THRESHOLD 15
+#define E1000_CT_SHIFT 4
+#define E1000_COLLISION_DISTANCE 64
+#define E1000_FDX_COLLISION_DISTANCE E1000_COLLISION_DISTANCE
+#define E1000_HDX_COLLISION_DISTANCE E1000_COLLISION_DISTANCE
+#define E1000_COLD_SHIFT 12
+
+/* Number of Transmit and Receive Descriptors must be a multiple of 8 */
+#define REQ_TX_DESCRIPTOR_MULTIPLE 8
+#define REQ_RX_DESCRIPTOR_MULTIPLE 8
+
+/* Default values for the transmit IPG register */
+#define DEFAULT_82542_TIPG_IPGT 10
+#define DEFAULT_82543_TIPG_IPGT_FIBER 9
+#define DEFAULT_82543_TIPG_IPGT_COPPER 8
+
+#define E1000_TIPG_IPGT_MASK 0x000003FF
+#define E1000_TIPG_IPGR1_MASK 0x000FFC00
+#define E1000_TIPG_IPGR2_MASK 0x3FF00000
+
+#define DEFAULT_82542_TIPG_IPGR1 2
+#define DEFAULT_82543_TIPG_IPGR1 8
+#define E1000_TIPG_IPGR1_SHIFT 10
+
+#define DEFAULT_82542_TIPG_IPGR2 10
+#define DEFAULT_82543_TIPG_IPGR2 6
+#define E1000_TIPG_IPGR2_SHIFT 20
+
+#define E1000_TXDMAC_DPP 0x00000001
+
+/* Adaptive IFS defines */
+#define TX_THRESHOLD_START 8
+#define TX_THRESHOLD_INCREMENT 10
+#define TX_THRESHOLD_DECREMENT 1
+#define TX_THRESHOLD_STOP 190
+#define TX_THRESHOLD_DISABLE 0
+#define TX_THRESHOLD_TIMER_MS 10000
+#define MIN_NUM_XMITS 1000
+#define IFS_MAX 80
+#define IFS_STEP 10
+#define IFS_MIN 40
+#define IFS_RATIO 4
+
+/* Extended Configuration Control and Size */
+#define E1000_EXTCNF_CTRL_PCIE_WRITE_ENABLE 0x00000001
+#define E1000_EXTCNF_CTRL_PHY_WRITE_ENABLE 0x00000002
+#define E1000_EXTCNF_CTRL_D_UD_ENABLE 0x00000004
+#define E1000_EXTCNF_CTRL_D_UD_LATENCY 0x00000008
+#define E1000_EXTCNF_CTRL_D_UD_OWNER 0x00000010
+#define E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP 0x00000020
+#define E1000_EXTCNF_CTRL_MDIO_HW_OWNERSHIP 0x00000040
+#define E1000_EXTCNF_CTRL_EXT_CNF_POINTER 0x1FFF0000
+
+#define E1000_EXTCNF_SIZE_EXT_PHY_LENGTH 0x000000FF
+#define E1000_EXTCNF_SIZE_EXT_DOCK_LENGTH 0x0000FF00
+#define E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH 0x00FF0000
+
+/* PBA constants */
+#define E1000_PBA_12K 0x000C /* 12KB, default Rx allocation */
+#define E1000_PBA_16K 0x0010 /* 16KB, default TX allocation */
+#define E1000_PBA_22K 0x0016
+#define E1000_PBA_24K 0x0018
+#define E1000_PBA_30K 0x001E
+#define E1000_PBA_40K 0x0028
+#define E1000_PBA_48K 0x0030 /* 48KB, default RX allocation */
+
+/* Flow Control Constants */
+#define FLOW_CONTROL_ADDRESS_LOW 0x00C28001
+#define FLOW_CONTROL_ADDRESS_HIGH 0x00000100
+#define FLOW_CONTROL_TYPE 0x8808
+
+/* The historical defaults for the flow control values are given below. */
+#define FC_DEFAULT_HI_THRESH (0x8000) /* 32KB */
+#define FC_DEFAULT_LO_THRESH (0x4000) /* 16KB */
+#define FC_DEFAULT_TX_TIMER (0x100) /* ~130 us */
+
+/* PCIX Config space */
+#define PCIX_COMMAND_REGISTER 0xE6
+#define PCIX_STATUS_REGISTER_LO 0xE8
+#define PCIX_STATUS_REGISTER_HI 0xEA
+
+#define PCIX_COMMAND_MMRBC_MASK 0x000C
+#define PCIX_COMMAND_MMRBC_SHIFT 0x2
+#define PCIX_STATUS_HI_MMRBC_MASK 0x0060
+#define PCIX_STATUS_HI_MMRBC_SHIFT 0x5
+#define PCIX_STATUS_HI_MMRBC_4K 0x3
+#define PCIX_STATUS_HI_MMRBC_2K 0x2
+
+
+/* Number of bits required to shift right the "pause" bits from the
+ * EEPROM (bits 13:12) to the "pause" (bits 8:7) field in the TXCW register.
+ */
+#define PAUSE_SHIFT 5
+
+/* Number of bits required to shift left the "SWDPIO" bits from the
+ * EEPROM (bits 8:5) to the "SWDPIO" (bits 25:22) field in the CTRL register.
+ */
+#define SWDPIO_SHIFT 17
+
+/* Number of bits required to shift left the "SWDPIO_EXT" bits from the
+ * EEPROM word F (bits 7:4) to the bits 11:8 of The Extended CTRL register.
+ */
+#define SWDPIO__EXT_SHIFT 4
+
+/* Number of bits required to shift left the "ILOS" bit from the EEPROM
+ * (bit 4) to the "ILOS" (bit 7) field in the CTRL register.
+ */
+#define ILOS_SHIFT 3
+
+
+#define RECEIVE_BUFFER_ALIGN_SIZE (256)
+
+/* Number of milliseconds we wait for auto-negotiation to complete */
+#define LINK_UP_TIMEOUT 500
+
+/* Number of 100 microseconds we wait for PCI Express master disable */
+#define MASTER_DISABLE_TIMEOUT 800
+/* Number of milliseconds we wait for Eeprom auto read bit done after MAC reset */
+#define AUTO_READ_DONE_TIMEOUT 10
+/* Number of milliseconds we wait for PHY configuration done after MAC reset */
+#define PHY_CFG_TIMEOUT 40
+
+#define E1000_TX_BUFFER_SIZE ((uint32_t)1514)
+
+/* The carrier extension symbol, as received by the NIC. */
+#define CARRIER_EXTENSION 0x0F
+
+/* TBI_ACCEPT macro definition:
+ *
+ * This macro requires:
+ * adapter = a pointer to struct em_hw
+ * status = the 8 bit status field of the RX descriptor with EOP set
+ * error = the 8 bit error field of the RX descriptor with EOP set
+ * length = the sum of all the length fields of the RX descriptors that
+ * make up the current frame
+ * last_byte = the last byte of the frame DMAed by the hardware
+ * max_frame_length = the maximum frame length we want to accept.
+ * min_frame_length = the minimum frame length we want to accept.
+ *
+ * This macro is a conditional that should be used in the interrupt
+ * handler's Rx processing routine when RxErrors have been detected.
+ *
+ * Typical use:
+ * ...
+ * if (TBI_ACCEPT) {
+ * accept_frame = TRUE;
+ * em_tbi_adjust_stats(adapter, MacAddress);
+ * frame_length--;
+ * } else {
+ * accept_frame = FALSE;
+ * }
+ * ...
+ */
+
+#define TBI_ACCEPT(adapter, status, errors, length, last_byte) \
+ ((adapter)->tbi_compatibility_on && \
+ (((errors) & E1000_RXD_ERR_FRAME_ERR_MASK) == E1000_RXD_ERR_CE) && \
+ ((last_byte) == CARRIER_EXTENSION) && \
+ (((status) & E1000_RXD_STAT_VP) ? \
+ (((length) > ((adapter)->min_frame_size - VLAN_TAG_SIZE)) && \
+ ((length) <= ((adapter)->max_frame_size + 1))) : \
+ (((length) > (adapter)->min_frame_size) && \
+ ((length) <= ((adapter)->max_frame_size + VLAN_TAG_SIZE + 1)))))
+
+
+/* Structures, enums, and macros for the PHY */
+
+/* Bit definitions for the Management Data IO (MDIO) and Management Data
+ * Clock (MDC) pins in the Device Control Register.
+ */
+#define E1000_CTRL_PHY_RESET_DIR E1000_CTRL_SWDPIO0
+#define E1000_CTRL_PHY_RESET E1000_CTRL_SWDPIN0
+#define E1000_CTRL_MDIO_DIR E1000_CTRL_SWDPIO2
+#define E1000_CTRL_MDIO E1000_CTRL_SWDPIN2
+#define E1000_CTRL_MDC_DIR E1000_CTRL_SWDPIO3
+#define E1000_CTRL_MDC E1000_CTRL_SWDPIN3
+#define E1000_CTRL_PHY_RESET_DIR4 E1000_CTRL_EXT_SDP4_DIR
+#define E1000_CTRL_PHY_RESET4 E1000_CTRL_EXT_SDP4_DATA
+
+/* PHY 1000 MII Register/Bit Definitions */
+/* PHY Registers defined by IEEE */
+#define PHY_CTRL 0x00 /* Control Register */
+#define PHY_STATUS 0x01 /* Status Regiser */
+#define PHY_ID1 0x02 /* Phy Id Reg (word 1) */
+#define PHY_ID2 0x03 /* Phy Id Reg (word 2) */
+#define PHY_AUTONEG_ADV 0x04 /* Autoneg Advertisement */
+#define PHY_LP_ABILITY 0x05 /* Link Partner Ability (Base Page) */
+#define PHY_AUTONEG_EXP 0x06 /* Autoneg Expansion Reg */
+#define PHY_NEXT_PAGE_TX 0x07 /* Next Page TX */
+#define PHY_LP_NEXT_PAGE 0x08 /* Link Partner Next Page */
+#define PHY_1000T_CTRL 0x09 /* 1000Base-T Control Reg */
+#define PHY_1000T_STATUS 0x0A /* 1000Base-T Status Reg */
+#define PHY_EXT_STATUS 0x0F /* Extended Status Reg */
+
+/* M88E1000 Specific Registers */
+#define M88E1000_PHY_SPEC_CTRL 0x10 /* PHY Specific Control Register */
+#define M88E1000_PHY_SPEC_STATUS 0x11 /* PHY Specific Status Register */
+#define M88E1000_INT_ENABLE 0x12 /* Interrupt Enable Register */
+#define M88E1000_INT_STATUS 0x13 /* Interrupt Status Register */
+#define M88E1000_EXT_PHY_SPEC_CTRL 0x14 /* Extended PHY Specific Control */
+#define M88E1000_RX_ERR_CNTR 0x15 /* Receive Error Counter */
+
+#define M88E1000_PHY_EXT_CTRL 0x1A /* PHY extend control register */
+#define M88E1000_PHY_PAGE_SELECT 0x1D /* Reg 29 for page number setting */
+#define M88E1000_PHY_GEN_CONTROL 0x1E /* Its meaning depends on reg 29 */
+#define M88E1000_PHY_VCO_REG_BIT8 0x100 /* Bits 8 & 11 are adjusted for */
+#define M88E1000_PHY_VCO_REG_BIT11 0x800 /* improved BER performance */
+
+#define IGP01E1000_IEEE_REGS_PAGE 0x0000
+#define IGP01E1000_IEEE_RESTART_AUTONEG 0x3300
+#define IGP01E1000_IEEE_FORCE_GIGA 0x0140
+
+/* IGP01E1000 Specific Registers */
+#define IGP01E1000_PHY_PORT_CONFIG 0x10 /* PHY Specific Port Config Register */
+#define IGP01E1000_PHY_PORT_STATUS 0x11 /* PHY Specific Status Register */
+#define IGP01E1000_PHY_PORT_CTRL 0x12 /* PHY Specific Control Register */
+#define IGP01E1000_PHY_LINK_HEALTH 0x13 /* PHY Link Health Register */
+#define IGP01E1000_GMII_FIFO 0x14 /* GMII FIFO Register */
+#define IGP01E1000_PHY_CHANNEL_QUALITY 0x15 /* PHY Channel Quality Register */
+#define IGP02E1000_PHY_POWER_MGMT 0x19
+#define IGP01E1000_PHY_PAGE_SELECT 0x1F /* PHY Page Select Core Register */
+
+/* IGP01E1000 AGC Registers - stores the cable length values*/
+#define IGP01E1000_PHY_AGC_A 0x1172
+#define IGP01E1000_PHY_AGC_B 0x1272
+#define IGP01E1000_PHY_AGC_C 0x1472
+#define IGP01E1000_PHY_AGC_D 0x1872
+
+/* IGP02E1000 AGC Registers for cable length values */
+#define IGP02E1000_PHY_AGC_A 0x11B1
+#define IGP02E1000_PHY_AGC_B 0x12B1
+#define IGP02E1000_PHY_AGC_C 0x14B1
+#define IGP02E1000_PHY_AGC_D 0x18B1
+
+/* IGP01E1000 DSP Reset Register */
+#define IGP01E1000_PHY_DSP_RESET 0x1F33
+#define IGP01E1000_PHY_DSP_SET 0x1F71
+#define IGP01E1000_PHY_DSP_FFE 0x1F35
+
+#define IGP01E1000_PHY_CHANNEL_NUM 4
+#define IGP02E1000_PHY_CHANNEL_NUM 4
+
+#define IGP01E1000_PHY_AGC_PARAM_A 0x1171
+#define IGP01E1000_PHY_AGC_PARAM_B 0x1271
+#define IGP01E1000_PHY_AGC_PARAM_C 0x1471
+#define IGP01E1000_PHY_AGC_PARAM_D 0x1871
+
+#define IGP01E1000_PHY_EDAC_MU_INDEX 0xC000
+#define IGP01E1000_PHY_EDAC_SIGN_EXT_9_BITS 0x8000
+
+#define IGP01E1000_PHY_ANALOG_TX_STATE 0x2890
+#define IGP01E1000_PHY_ANALOG_CLASS_A 0x2000
+#define IGP01E1000_PHY_FORCE_ANALOG_ENABLE 0x0004
+#define IGP01E1000_PHY_DSP_FFE_CM_CP 0x0069
+
+#define IGP01E1000_PHY_DSP_FFE_DEFAULT 0x002A
+/* IGP01E1000 PCS Initialization register - stores the polarity status when
+ * speed = 1000 Mbps. */
+#define IGP01E1000_PHY_PCS_INIT_REG 0x00B4
+#define IGP01E1000_PHY_PCS_CTRL_REG 0x00B5
+
+#define IGP01E1000_ANALOG_REGS_PAGE 0x20C0
+
+#define MAX_PHY_REG_ADDRESS 0x1F /* 5 bit address bus (0-0x1F) */
+#define MAX_PHY_MULTI_PAGE_REG 0xF /*Registers that are equal on all pages*/
+/* PHY Control Register */
+#define MII_CR_SPEED_SELECT_MSB 0x0040 /* bits 6,13: 10=1000, 01=100, 00=10 */
+#define MII_CR_COLL_TEST_ENABLE 0x0080 /* Collision test enable */
+#define MII_CR_FULL_DUPLEX 0x0100 /* FDX =1, half duplex =0 */
+#define MII_CR_RESTART_AUTO_NEG 0x0200 /* Restart auto negotiation */
+#define MII_CR_ISOLATE 0x0400 /* Isolate PHY from MII */
+#define MII_CR_POWER_DOWN 0x0800 /* Power down */
+#define MII_CR_AUTO_NEG_EN 0x1000 /* Auto Neg Enable */
+#define MII_CR_SPEED_SELECT_LSB 0x2000 /* bits 6,13: 10=1000, 01=100, 00=10 */
+#define MII_CR_LOOPBACK 0x4000 /* 0 = normal, 1 = loopback */
+#define MII_CR_RESET 0x8000 /* 0 = normal, 1 = PHY reset */
+
+/* PHY Status Register */
+#define MII_SR_EXTENDED_CAPS 0x0001 /* Extended register capabilities */
+#define MII_SR_JABBER_DETECT 0x0002 /* Jabber Detected */
+#define MII_SR_LINK_STATUS 0x0004 /* Link Status 1 = link */
+#define MII_SR_AUTONEG_CAPS 0x0008 /* Auto Neg Capable */
+#define MII_SR_REMOTE_FAULT 0x0010 /* Remote Fault Detect */
+#define MII_SR_AUTONEG_COMPLETE 0x0020 /* Auto Neg Complete */
+#define MII_SR_PREAMBLE_SUPPRESS 0x0040 /* Preamble may be suppressed */
+#define MII_SR_EXTENDED_STATUS 0x0100 /* Ext. status info in Reg 0x0F */
+#define MII_SR_100T2_HD_CAPS 0x0200 /* 100T2 Half Duplex Capable */
+#define MII_SR_100T2_FD_CAPS 0x0400 /* 100T2 Full Duplex Capable */
+#define MII_SR_10T_HD_CAPS 0x0800 /* 10T Half Duplex Capable */
+#define MII_SR_10T_FD_CAPS 0x1000 /* 10T Full Duplex Capable */
+#define MII_SR_100X_HD_CAPS 0x2000 /* 100X Half Duplex Capable */
+#define MII_SR_100X_FD_CAPS 0x4000 /* 100X Full Duplex Capable */
+#define MII_SR_100T4_CAPS 0x8000 /* 100T4 Capable */
+
+/* Autoneg Advertisement Register */
+#define NWAY_AR_SELECTOR_FIELD 0x0001 /* indicates IEEE 802.3 CSMA/CD */
+#define NWAY_AR_10T_HD_CAPS 0x0020 /* 10T Half Duplex Capable */
+#define NWAY_AR_10T_FD_CAPS 0x0040 /* 10T Full Duplex Capable */
+#define NWAY_AR_100TX_HD_CAPS 0x0080 /* 100TX Half Duplex Capable */
+#define NWAY_AR_100TX_FD_CAPS 0x0100 /* 100TX Full Duplex Capable */
+#define NWAY_AR_100T4_CAPS 0x0200 /* 100T4 Capable */
+#define NWAY_AR_PAUSE 0x0400 /* Pause operation desired */
+#define NWAY_AR_ASM_DIR 0x0800 /* Asymmetric Pause Direction bit */
+#define NWAY_AR_REMOTE_FAULT 0x2000 /* Remote Fault detected */
+#define NWAY_AR_NEXT_PAGE 0x8000 /* Next Page ability supported */
+
+/* Link Partner Ability Register (Base Page) */
+#define NWAY_LPAR_SELECTOR_FIELD 0x0000 /* LP protocol selector field */
+#define NWAY_LPAR_10T_HD_CAPS 0x0020 /* LP is 10T Half Duplex Capable */
+#define NWAY_LPAR_10T_FD_CAPS 0x0040 /* LP is 10T Full Duplex Capable */
+#define NWAY_LPAR_100TX_HD_CAPS 0x0080 /* LP is 100TX Half Duplex Capable */
+#define NWAY_LPAR_100TX_FD_CAPS 0x0100 /* LP is 100TX Full Duplex Capable */
+#define NWAY_LPAR_100T4_CAPS 0x0200 /* LP is 100T4 Capable */
+#define NWAY_LPAR_PAUSE 0x0400 /* LP Pause operation desired */
+#define NWAY_LPAR_ASM_DIR 0x0800 /* LP Asymmetric Pause Direction bit */
+#define NWAY_LPAR_REMOTE_FAULT 0x2000 /* LP has detected Remote Fault */
+#define NWAY_LPAR_ACKNOWLEDGE 0x4000 /* LP has rx'd link code word */
+#define NWAY_LPAR_NEXT_PAGE 0x8000 /* Next Page ability supported */
+
+/* Autoneg Expansion Register */
+#define NWAY_ER_LP_NWAY_CAPS 0x0001 /* LP has Auto Neg Capability */
+#define NWAY_ER_PAGE_RXD 0x0002 /* LP is 10T Half Duplex Capable */
+#define NWAY_ER_NEXT_PAGE_CAPS 0x0004 /* LP is 10T Full Duplex Capable */
+#define NWAY_ER_LP_NEXT_PAGE_CAPS 0x0008 /* LP is 100TX Half Duplex Capable */
+#define NWAY_ER_PAR_DETECT_FAULT 0x0010 /* LP is 100TX Full Duplex Capable */
+
+/* Next Page TX Register */
+#define NPTX_MSG_CODE_FIELD 0x0001 /* NP msg code or unformatted data */
+#define NPTX_TOGGLE 0x0800 /* Toggles between exchanges
+ * of different NP
+ */
+#define NPTX_ACKNOWLDGE2 0x1000 /* 1 = will comply with msg
+ * 0 = cannot comply with msg
+ */
+#define NPTX_MSG_PAGE 0x2000 /* formatted(1)/unformatted(0) pg */
+#define NPTX_NEXT_PAGE 0x8000 /* 1 = addition NP will follow
+ * 0 = sending last NP
+ */
+
+/* Link Partner Next Page Register */
+#define LP_RNPR_MSG_CODE_FIELD 0x0001 /* NP msg code or unformatted data */
+#define LP_RNPR_TOGGLE 0x0800 /* Toggles between exchanges
+ * of different NP
+ */
+#define LP_RNPR_ACKNOWLDGE2 0x1000 /* 1 = will comply with msg
+ * 0 = cannot comply with msg
+ */
+#define LP_RNPR_MSG_PAGE 0x2000 /* formatted(1)/unformatted(0) pg */
+#define LP_RNPR_ACKNOWLDGE 0x4000 /* 1 = ACK / 0 = NO ACK */
+#define LP_RNPR_NEXT_PAGE 0x8000 /* 1 = addition NP will follow
+ * 0 = sending last NP
+ */
+
+/* 1000BASE-T Control Register */
+#define CR_1000T_ASYM_PAUSE 0x0080 /* Advertise asymmetric pause bit */
+#define CR_1000T_HD_CAPS 0x0100 /* Advertise 1000T HD capability */
+#define CR_1000T_FD_CAPS 0x0200 /* Advertise 1000T FD capability */
+#define CR_1000T_REPEATER_DTE 0x0400 /* 1=Repeater/switch device port */
+ /* 0=DTE device */
+#define CR_1000T_MS_VALUE 0x0800 /* 1=Configure PHY as Master */
+ /* 0=Configure PHY as Slave */
+#define CR_1000T_MS_ENABLE 0x1000 /* 1=Master/Slave manual config value */
+ /* 0=Automatic Master/Slave config */
+#define CR_1000T_TEST_MODE_NORMAL 0x0000 /* Normal Operation */
+#define CR_1000T_TEST_MODE_1 0x2000 /* Transmit Waveform test */
+#define CR_1000T_TEST_MODE_2 0x4000 /* Master Transmit Jitter test */
+#define CR_1000T_TEST_MODE_3 0x6000 /* Slave Transmit Jitter test */
+#define CR_1000T_TEST_MODE_4 0x8000 /* Transmitter Distortion test */
+
+/* 1000BASE-T Status Register */
+#define SR_1000T_IDLE_ERROR_CNT 0x00FF /* Num idle errors since last read */
+#define SR_1000T_ASYM_PAUSE_DIR 0x0100 /* LP asymmetric pause direction bit */
+#define SR_1000T_LP_HD_CAPS 0x0400 /* LP is 1000T HD capable */
+#define SR_1000T_LP_FD_CAPS 0x0800 /* LP is 1000T FD capable */
+#define SR_1000T_REMOTE_RX_STATUS 0x1000 /* Remote receiver OK */
+#define SR_1000T_LOCAL_RX_STATUS 0x2000 /* Local receiver OK */
+#define SR_1000T_MS_CONFIG_RES 0x4000 /* 1=Local TX is Master, 0=Slave */
+#define SR_1000T_MS_CONFIG_FAULT 0x8000 /* Master/Slave config fault */
+#define SR_1000T_REMOTE_RX_STATUS_SHIFT 12
+#define SR_1000T_LOCAL_RX_STATUS_SHIFT 13
+#define SR_1000T_PHY_EXCESSIVE_IDLE_ERR_COUNT 5
+#define FFE_IDLE_ERR_COUNT_TIMEOUT_20 20
+#define FFE_IDLE_ERR_COUNT_TIMEOUT_100 100
+
+/* Extended Status Register */
+#define IEEE_ESR_1000T_HD_CAPS 0x1000 /* 1000T HD capable */
+#define IEEE_ESR_1000T_FD_CAPS 0x2000 /* 1000T FD capable */
+#define IEEE_ESR_1000X_HD_CAPS 0x4000 /* 1000X HD capable */
+#define IEEE_ESR_1000X_FD_CAPS 0x8000 /* 1000X FD capable */
+
+#define PHY_TX_POLARITY_MASK 0x0100 /* register 10h bit 8 (polarity bit) */
+#define PHY_TX_NORMAL_POLARITY 0 /* register 10h bit 8 (normal polarity) */
+
+#define AUTO_POLARITY_DISABLE 0x0010 /* register 11h bit 4 */
+ /* (0=enable, 1=disable) */
+
+/* M88E1000 PHY Specific Control Register */
+#define M88E1000_PSCR_JABBER_DISABLE 0x0001 /* 1=Jabber Function disabled */
+#define M88E1000_PSCR_POLARITY_REVERSAL 0x0002 /* 1=Polarity Reversal enabled */
+#define M88E1000_PSCR_SQE_TEST 0x0004 /* 1=SQE Test enabled */
+#define M88E1000_PSCR_CLK125_DISABLE 0x0010 /* 1=CLK125 low,
+ * 0=CLK125 toggling
+ */
+#define M88E1000_PSCR_MDI_MANUAL_MODE 0x0000 /* MDI Crossover Mode bits 6:5 */
+ /* Manual MDI configuration */
+#define M88E1000_PSCR_MDIX_MANUAL_MODE 0x0020 /* Manual MDIX configuration */
+#define M88E1000_PSCR_AUTO_X_1000T 0x0040 /* 1000BASE-T: Auto crossover,
+ * 100BASE-TX/10BASE-T:
+ * MDI Mode
+ */
+#define M88E1000_PSCR_AUTO_X_MODE 0x0060 /* Auto crossover enabled
+ * all speeds.
+ */
+#define M88E1000_PSCR_10BT_EXT_DIST_ENABLE 0x0080
+ /* 1=Enable Extended 10BASE-T distance
+ * (Lower 10BASE-T RX Threshold)
+ * 0=Normal 10BASE-T RX Threshold */
+#define M88E1000_PSCR_MII_5BIT_ENABLE 0x0100
+ /* 1=5-Bit interface in 100BASE-TX
+ * 0=MII interface in 100BASE-TX */
+#define M88E1000_PSCR_SCRAMBLER_DISABLE 0x0200 /* 1=Scrambler disable */
+#define M88E1000_PSCR_FORCE_LINK_GOOD 0x0400 /* 1=Force link good */
+#define M88E1000_PSCR_ASSERT_CRS_ON_TX 0x0800 /* 1=Assert CRS on Transmit */
+
+#define M88E1000_PSCR_POLARITY_REVERSAL_SHIFT 1
+#define M88E1000_PSCR_AUTO_X_MODE_SHIFT 5
+#define M88E1000_PSCR_10BT_EXT_DIST_ENABLE_SHIFT 7
+
+/* M88E1000 PHY Specific Status Register */
+#define M88E1000_PSSR_JABBER 0x0001 /* 1=Jabber */
+#define M88E1000_PSSR_REV_POLARITY 0x0002 /* 1=Polarity reversed */
+#define M88E1000_PSSR_DOWNSHIFT 0x0020 /* 1=Downshifted */
+#define M88E1000_PSSR_MDIX 0x0040 /* 1=MDIX; 0=MDI */
+#define M88E1000_PSSR_CABLE_LENGTH 0x0380 /* 0=<50M;1=50-80M;2=80-110M;
+ * 3=110-140M;4=>140M */
+#define M88E1000_PSSR_LINK 0x0400 /* 1=Link up, 0=Link down */
+#define M88E1000_PSSR_SPD_DPLX_RESOLVED 0x0800 /* 1=Speed & Duplex resolved */
+#define M88E1000_PSSR_PAGE_RCVD 0x1000 /* 1=Page received */
+#define M88E1000_PSSR_DPLX 0x2000 /* 1=Duplex 0=Half Duplex */
+#define M88E1000_PSSR_SPEED 0xC000 /* Speed, bits 14:15 */
+#define M88E1000_PSSR_10MBS 0x0000 /* 00=10Mbs */
+#define M88E1000_PSSR_100MBS 0x4000 /* 01=100Mbs */
+#define M88E1000_PSSR_1000MBS 0x8000 /* 10=1000Mbs */
+
+#define M88E1000_PSSR_REV_POLARITY_SHIFT 1
+#define M88E1000_PSSR_DOWNSHIFT_SHIFT 5
+#define M88E1000_PSSR_MDIX_SHIFT 6
+#define M88E1000_PSSR_CABLE_LENGTH_SHIFT 7
+
+/* M88E1000 Extended PHY Specific Control Register */
+#define M88E1000_EPSCR_FIBER_LOOPBACK 0x4000 /* 1=Fiber loopback */
+#define M88E1000_EPSCR_DOWN_NO_IDLE 0x8000 /* 1=Lost lock detect enabled.
+ * Will assert lost lock and bring
+ * link down if idle not seen
+ * within 1ms in 1000BASE-T
+ */
+/* Number of times we will attempt to autonegotiate before downshifting if we
+ * are the master */
+#define M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK 0x0C00
+#define M88E1000_EPSCR_MASTER_DOWNSHIFT_1X 0x0000
+#define M88E1000_EPSCR_MASTER_DOWNSHIFT_2X 0x0400
+#define M88E1000_EPSCR_MASTER_DOWNSHIFT_3X 0x0800
+#define M88E1000_EPSCR_MASTER_DOWNSHIFT_4X 0x0C00
+/* Number of times we will attempt to autonegotiate before downshifting if we
+ * are the slave */
+#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK 0x0300
+#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_DIS 0x0000
+#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X 0x0100
+#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_2X 0x0200
+#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_3X 0x0300
+#define M88E1000_EPSCR_TX_CLK_2_5 0x0060 /* 2.5 MHz TX_CLK */
+#define M88E1000_EPSCR_TX_CLK_25 0x0070 /* 25 MHz TX_CLK */
+#define M88E1000_EPSCR_TX_CLK_0 0x0000 /* NO TX_CLK */
+
+/* IGP01E1000 Specific Port Config Register - R/W */
+#define IGP01E1000_PSCFR_AUTO_MDIX_PAR_DETECT 0x0010
+#define IGP01E1000_PSCFR_PRE_EN 0x0020
+#define IGP01E1000_PSCFR_SMART_SPEED 0x0080
+#define IGP01E1000_PSCFR_DISABLE_TPLOOPBACK 0x0100
+#define IGP01E1000_PSCFR_DISABLE_JABBER 0x0400
+#define IGP01E1000_PSCFR_DISABLE_TRANSMIT 0x2000
+
+/* IGP01E1000 Specific Port Status Register - R/O */
+#define IGP01E1000_PSSR_AUTONEG_FAILED 0x0001 /* RO LH SC */
+#define IGP01E1000_PSSR_POLARITY_REVERSED 0x0002
+#define IGP01E1000_PSSR_CABLE_LENGTH 0x007C
+#define IGP01E1000_PSSR_FULL_DUPLEX 0x0200
+#define IGP01E1000_PSSR_LINK_UP 0x0400
+#define IGP01E1000_PSSR_MDIX 0x0800
+#define IGP01E1000_PSSR_SPEED_MASK 0xC000 /* speed bits mask */
+#define IGP01E1000_PSSR_SPEED_10MBPS 0x4000
+#define IGP01E1000_PSSR_SPEED_100MBPS 0x8000
+#define IGP01E1000_PSSR_SPEED_1000MBPS 0xC000
+#define IGP01E1000_PSSR_CABLE_LENGTH_SHIFT 0x0002 /* shift right 2 */
+#define IGP01E1000_PSSR_MDIX_SHIFT 0x000B /* shift right 11 */
+
+/* IGP01E1000 Specific Port Control Register - R/W */
+#define IGP01E1000_PSCR_TP_LOOPBACK 0x0010
+#define IGP01E1000_PSCR_CORRECT_NC_SCMBLR 0x0200
+#define IGP01E1000_PSCR_TEN_CRS_SELECT 0x0400
+#define IGP01E1000_PSCR_FLIP_CHIP 0x0800
+#define IGP01E1000_PSCR_AUTO_MDIX 0x1000
+#define IGP01E1000_PSCR_FORCE_MDI_MDIX 0x2000 /* 0-MDI, 1-MDIX */
+
+/* IGP01E1000 Specific Port Link Health Register */
+#define IGP01E1000_PLHR_SS_DOWNGRADE 0x8000
+#define IGP01E1000_PLHR_GIG_SCRAMBLER_ERROR 0x4000
+#define IGP01E1000_PLHR_MASTER_FAULT 0x2000
+#define IGP01E1000_PLHR_MASTER_RESOLUTION 0x1000
+#define IGP01E1000_PLHR_GIG_REM_RCVR_NOK 0x0800 /* LH */
+#define IGP01E1000_PLHR_IDLE_ERROR_CNT_OFLOW 0x0400 /* LH */
+#define IGP01E1000_PLHR_DATA_ERR_1 0x0200 /* LH */
+#define IGP01E1000_PLHR_DATA_ERR_0 0x0100
+#define IGP01E1000_PLHR_AUTONEG_FAULT 0x0040
+#define IGP01E1000_PLHR_AUTONEG_ACTIVE 0x0010
+#define IGP01E1000_PLHR_VALID_CHANNEL_D 0x0008
+#define IGP01E1000_PLHR_VALID_CHANNEL_C 0x0004
+#define IGP01E1000_PLHR_VALID_CHANNEL_B 0x0002
+#define IGP01E1000_PLHR_VALID_CHANNEL_A 0x0001
+
+/* IGP01E1000 Channel Quality Register */
+#define IGP01E1000_MSE_CHANNEL_D 0x000F
+#define IGP01E1000_MSE_CHANNEL_C 0x00F0
+#define IGP01E1000_MSE_CHANNEL_B 0x0F00
+#define IGP01E1000_MSE_CHANNEL_A 0xF000
+
+#define IGP02E1000_PM_SPD 0x0001 /* Smart Power Down */
+#define IGP02E1000_PM_D3_LPLU 0x0004 /* Enable LPLU in non-D0a modes */
+#define IGP02E1000_PM_D0_LPLU 0x0002 /* Enable LPLU in D0a mode */
+
+/* IGP01E1000 DSP reset macros */
+#define DSP_RESET_ENABLE 0x0
+#define DSP_RESET_DISABLE 0x2
+#define E1000_MAX_DSP_RESETS 10
+
+/* IGP01E1000 & IGP02E1000 AGC Registers */
+
+#define IGP01E1000_AGC_LENGTH_SHIFT 7 /* Coarse - 13:11, Fine - 10:7 */
+#define IGP02E1000_AGC_LENGTH_SHIFT 9 /* Coarse - 15:13, Fine - 12:9 */
+
+/* IGP02E1000 AGC Register Length 9-bit mask */
+#define IGP02E1000_AGC_LENGTH_MASK 0x7F
+
+/* 7 bits (3 Coarse + 4 Fine) --> 128 optional values */
+#define IGP01E1000_AGC_LENGTH_TABLE_SIZE 128
+#define IGP02E1000_AGC_LENGTH_TABLE_SIZE 128
+
+/* The precision error of the cable length is +/- 10 meters */
+#define IGP01E1000_AGC_RANGE 10
+#define IGP02E1000_AGC_RANGE 10
+
+/* IGP01E1000 PCS Initialization register */
+/* bits 3:6 in the PCS registers stores the channels polarity */
+#define IGP01E1000_PHY_POLARITY_MASK 0x0078
+
+/* IGP01E1000 GMII FIFO Register */
+#define IGP01E1000_GMII_FLEX_SPD 0x10 /* Enable flexible speed
+ * on Link-Up */
+#define IGP01E1000_GMII_SPD 0x20 /* Enable SPD */
+
+/* IGP01E1000 Analog Register */
+#define IGP01E1000_ANALOG_SPARE_FUSE_STATUS 0x20D1
+#define IGP01E1000_ANALOG_FUSE_STATUS 0x20D0
+#define IGP01E1000_ANALOG_FUSE_CONTROL 0x20DC
+#define IGP01E1000_ANALOG_FUSE_BYPASS 0x20DE
+
+#define IGP01E1000_ANALOG_FUSE_POLY_MASK 0xF000
+#define IGP01E1000_ANALOG_FUSE_FINE_MASK 0x0F80
+#define IGP01E1000_ANALOG_FUSE_COARSE_MASK 0x0070
+#define IGP01E1000_ANALOG_SPARE_FUSE_ENABLED 0x0100
+#define IGP01E1000_ANALOG_FUSE_ENABLE_SW_CONTROL 0x0002
+
+#define IGP01E1000_ANALOG_FUSE_COARSE_THRESH 0x0040
+#define IGP01E1000_ANALOG_FUSE_COARSE_10 0x0010
+#define IGP01E1000_ANALOG_FUSE_FINE_1 0x0080
+#define IGP01E1000_ANALOG_FUSE_FINE_10 0x0500
+
+
+/* Bit definitions for valid PHY IDs. */
+/* I = Integrated
+ * E = External
+ */
+#define M88E1000_E_PHY_ID 0x01410C50
+#define M88E1000_I_PHY_ID 0x01410C30
+#define M88E1011_I_PHY_ID 0x01410C20
+#define IGP01E1000_I_PHY_ID 0x02A80380
+#define M88E1000_12_PHY_ID M88E1000_E_PHY_ID
+#define M88E1000_14_PHY_ID M88E1000_E_PHY_ID
+#define M88E1011_I_REV_4 0x04
+#define M88E1111_I_PHY_ID 0x01410CC0
+#define L1LXT971A_PHY_ID 0x001378E0
+
+/* Miscellaneous PHY bit definitions. */
+#define PHY_PREAMBLE 0xFFFFFFFF
+#define PHY_SOF 0x01
+#define PHY_OP_READ 0x02
+#define PHY_OP_WRITE 0x01
+#define PHY_TURNAROUND 0x02
+#define PHY_PREAMBLE_SIZE 32
+#define MII_CR_SPEED_1000 0x0040
+#define MII_CR_SPEED_100 0x2000
+#define MII_CR_SPEED_10 0x0000
+#define E1000_PHY_ADDRESS 0x01
+#define PHY_AUTO_NEG_TIME 45 /* 4.5 Seconds */
+#define PHY_FORCE_TIME 20 /* 2.0 Seconds */
+#define PHY_REVISION_MASK 0xFFFFFFF0
+#define DEVICE_SPEED_MASK 0x00000300 /* Device Ctrl Reg Speed Mask */
+#define REG4_SPEED_MASK 0x01E0
+#define REG9_SPEED_MASK 0x0300
+#define ADVERTISE_10_HALF 0x0001
+#define ADVERTISE_10_FULL 0x0002
+#define ADVERTISE_100_HALF 0x0004
+#define ADVERTISE_100_FULL 0x0008
+#define ADVERTISE_1000_HALF 0x0010
+#define ADVERTISE_1000_FULL 0x0020
+#define AUTONEG_ADVERTISE_SPEED_DEFAULT 0x002F /* Everything but 1000-Half */
+#define AUTONEG_ADVERTISE_10_100_ALL 0x000F /* All 10/100 speeds*/
+#define AUTONEG_ADVERTISE_10_ALL 0x0003 /* 10Mbps Full & Half speeds*/
+
+#endif /* _EM_HW_H_ */
diff --git a/c/src/lib/libbsp/powerpc/beatnik/network/if_em/if_em_osdep.h b/c/src/lib/libbsp/powerpc/beatnik/network/if_em/if_em_osdep.h
new file mode 100644
index 0000000000..0b62e8bed3
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/beatnik/network/if_em/if_em_osdep.h
@@ -0,0 +1,146 @@
+/**************************************************************************
+
+Copyright (c) 2001-2005, Intel Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+
+/*$FreeBSD: /repoman/r/ncvs/src/sys/dev/em/if_em_osdep.h,v 1.14 2005/05/26 23:32:02 tackerman Exp $*/
+
+#ifndef _RTEMS_OS_H_
+#define _RTEMS_OS_H_
+
+#include <rtems.h>
+#include <rtemscompat.h>
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/mbuf.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <sys/malloc.h>
+#include <sys/kernel.h>
+#include <bsp/pci.h>
+
+/* Eventually, we should include this
+#include <rtems/rtems-mii-ioctl.h>
+*/
+#define IFM_LINK_OK IFM_FLAG0
+#define IFM_ANEG_DIS IFM_FLAG1
+
+#define ASSERT(x) if(!(x)) panic("EM: x")
+
+/* The happy-fun DELAY macro is defined in /usr/src/sys/i386/include/clock.h */
+#define usec_delay(x) DELAY(x)
+#define msec_delay(x) DELAY(1000*(x))
+/* TODO: Should we be paranoid about delaying in interrupt context? */
+#define msec_delay_irq(x) DELAY(1000*(x))
+
+#define MSGOUT(S, A, B) printf(S "\n", A, B)
+#define DEBUGFUNC(F) DEBUGOUT(F);
+#if DBG
+ #define DEBUGOUT(S) printf(S "\n")
+ #define DEBUGOUT1(S,A) printf(S "\n",A)
+ #define DEBUGOUT2(S,A,B) printf(S "\n",A,B)
+ #define DEBUGOUT3(S,A,B,C) printf(S "\n",A,B,C)
+ #define bootverbose (1)
+ #define DEBUGOUT7(S,A,B,C,D,E,F,G) printf(S "\n",A,B,C,D,E,F,G)
+#else
+ #define DEBUGOUT(S)
+ #define DEBUGOUT1(S,A)
+ #define DEBUGOUT2(S,A,B)
+ #define DEBUGOUT3(S,A,B,C)
+ #define bootverbose (0)
+ #define DEBUGOUT7(S,A,B,C,D,E,F,G)
+#endif
+
+#define CMD_MEM_WRT_INVALIDATE 0x0010 /* BIT_4 */
+#define PCI_COMMAND_REGISTER PCIR_COMMAND
+
+struct em_osdep
+{
+ unsigned mem_bus_space_handle;
+ device_t dev;
+};
+
+struct rtems_ifmedia {
+ int ifm_media;
+};
+
+#define E1000_WRITE_FLUSH(hw) E1000_READ_REG(hw, STATUS)
+
+/* Read from an absolute offset in the adapter's memory space */
+#define E1000_READ_OFFSET(hw, offset) \
+ bus_space_read_4( ((struct em_osdep *)(hw)->back)->mem_bus_space_tag, \
+ ((struct em_osdep *)(hw)->back)->mem_bus_space_handle, \
+ offset)
+
+/* Write to an absolute offset in the adapter's memory space */
+#define E1000_WRITE_OFFSET(hw, offset, value) \
+ bus_space_write_4( ((struct em_osdep *)(hw)->back)->mem_bus_space_tag, \
+ ((struct em_osdep *)(hw)->back)->mem_bus_space_handle, \
+ offset, \
+ value)
+
+/* Convert a register name to its offset in the adapter's memory space */
+#define E1000_REG_OFFSET(hw, reg) \
+ ((hw)->mac_type >= em_82543 ? E1000_##reg : E1000_82542_##reg)
+
+#define E1000_READ_REG(hw, reg) \
+ E1000_READ_OFFSET(hw, E1000_REG_OFFSET(hw, reg))
+
+#define E1000_WRITE_REG(hw, reg, value) \
+ E1000_WRITE_OFFSET(hw, E1000_REG_OFFSET(hw, reg), value)
+
+#define E1000_READ_REG_ARRAY(hw, reg, index) \
+ E1000_READ_OFFSET(hw, E1000_REG_OFFSET(hw, reg) + ((index) << 2))
+
+#define E1000_READ_REG_ARRAY_DWORD E1000_READ_REG_ARRAY
+
+#define E1000_WRITE_REG_ARRAY(hw, reg, index, value) \
+ E1000_WRITE_OFFSET(hw, E1000_REG_OFFSET(hw, reg) + ((index) << 2), value)
+
+#define E1000_WRITE_REG_ARRAY_BYTE(hw, reg, index, value) \
+ bus_space_write_1( ((struct em_osdep *)(hw)->back)->mem_bus_space_tag, \
+ ((struct em_osdep *)(hw)->back)->mem_bus_space_handle, \
+ E1000_REG_OFFSET(hw, reg) + (index), \
+ value)
+
+#define E1000_WRITE_REG_ARRAY_WORD(hw, reg, index, value) \
+ bus_space_write_2( ((struct em_osdep *)(hw)->back)->mem_bus_space_tag, \
+ ((struct em_osdep *)(hw)->back)->mem_bus_space_handle, \
+ E1000_REG_OFFSET(hw, reg) + (index), \
+ value)
+
+#define E1000_WRITE_REG_ARRAY_DWORD(hw, reg, index, value) \
+ E1000_WRITE_OFFSET(hw, E1000_REG_OFFSET(hw, reg) + ((index) << 2), value)
+
+#endif /* _FREEBSD_OS_H_ */
+
diff --git a/c/src/lib/libbsp/powerpc/beatnik/network/if_em/if_em_pub.h b/c/src/lib/libbsp/powerpc/beatnik/network/if_em/if_em_pub.h
new file mode 100644
index 0000000000..66c9d3d3d2
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/beatnik/network/if_em/if_em_pub.h
@@ -0,0 +1,23 @@
+/* $Id$ */
+#ifndef RTEMS_BSDNET_IF_EM_PUBLIC_SYMBOLS_H
+#define RTEMS_BSDNET_IF_EM_PUBLIC_SYMBOLS_H
+
+#include <rtems.h>
+#include <rtems/rtems_bsdnet.h>
+#include <bsp/early_enet_link_status.h>
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+extern int rtems_em_attach(struct rtems_bsdnet_ifconfig *, int);
+extern int rtems_em_pci_setup(int);
+extern rtems_bsdnet_early_link_check_ops rtems_em_early_link_check_ops;
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif
+
+
diff --git a/c/src/lib/libbsp/powerpc/beatnik/network/if_em/if_em_rtems.c b/c/src/lib/libbsp/powerpc/beatnik/network/if_em/if_em_rtems.c
new file mode 100644
index 0000000000..306c2abc05
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/beatnik/network/if_em/if_em_rtems.c
@@ -0,0 +1,106 @@
+/* $Id$ */
+#include "if_xxx_rtems.c"
+#include <bsp/early_enet_link_status.h>
+#include <bsp/if_em_pub.h>
+
+/* Provide a routine to check link status early,
+ * i.e., before the network is really running.
+ * In case someone wants to decide whether to use/configure
+ * this interface at all :-)
+ *
+ * NOTE: this routine tries to enable autonegotiation!
+ *
+ * unit: unit number starting with 1 (usual BSDNET convention)
+ *
+ * RETURNS: Phy status register contents (1<<2 means link up).
+ * or -1 on error.
+ */
+
+/*
+ * Authorship
+ * ----------
+ * This software ('beatnik' RTEMS BSP for MVME6100 and MVME5500) was
+ * created by Till Straumann <strauman@slac.stanford.edu>, 2005-2007,
+ * Stanford Linear Accelerator Center, Stanford University.
+ *
+ * Acknowledgement of sponsorship
+ * ------------------------------
+ * The 'beatnik' 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
+ */
+
+static int
+em_early_init(int idx)
+{
+ if ( idx < 0 || idx >= NETDRIVER_SLOTS )
+ return -1;
+ return em_hw_early_init(&the_em_devs[idx]);
+}
+
+static int
+em_early_read_phy(int idx, unsigned reg)
+{
+unsigned short data;
+ if ( idx < 0 || idx >= NETDRIVER_SLOTS )
+ return -1;
+ /* Bizarre - I always have to read PHY_STATUS twice until a good link
+ * status is read
+ */
+ if ( em_read_phy_reg(&the_em_devs[idx].d_softc.hw, reg, &data) )
+ return -1;
+ if ( PHY_STATUS == reg ) {
+ /* read again */
+ if ( em_read_phy_reg(&the_em_devs[idx].d_softc.hw, PHY_STATUS, &data) )
+ return -1;
+ }
+ return data;
+}
+
+static int
+em_early_write_phy(int idx, unsigned reg, unsigned val)
+{
+ if ( idx < 0 || idx >= NETDRIVER_SLOTS )
+ return -1;
+ return em_write_phy_reg(&the_em_devs[idx].d_softc.hw, reg, val);
+}
+
+rtems_bsdnet_early_link_check_ops
+rtems_em_early_link_check_ops = {
+ init: em_early_init,
+ read_phy: em_early_read_phy,
+ write_phy: em_early_write_phy,
+ name: NETDRIVER,
+ num_slots: NETDRIVER_SLOTS
+};
diff --git a/c/src/lib/libbsp/powerpc/beatnik/network/if_em/rtemscompat_defs.h b/c/src/lib/libbsp/powerpc/beatnik/network/if_em/rtemscompat_defs.h
new file mode 100644
index 0000000000..50b51e6d40
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/beatnik/network/if_em/rtemscompat_defs.h
@@ -0,0 +1,110 @@
+#ifndef RTEMS_COMPAT_DEFS_H
+#define RTEMS_COMPAT_DEFS_H
+
+/* Number of device instances the driver should support
+ * - may be limited to 1 depending on IRQ API
+ * (braindamaged PC586 and powerpc)
+ */
+#define NETDRIVER_SLOTS 1
+
+/* String name to print with error messages */
+#define NETDRIVER "em"
+/* Name snippet used to make global symbols unique to this driver */
+#define NETDRIVER_PREFIX em
+
+#define adapter em_softc
+#define interface_data arpcom
+
+/* Define according to endianness of the *ethernet*chip*
+ * (not the CPU - most probably are LE)
+ * This must be either NET_CHIP_LE or NET_CHIP_BE
+ */
+
+#define NET_CHIP_LE
+#undef NET_CHIP_BE
+
+/* Define either NET_CHIP_MEM_IO or NET_CHIP_PORT_IO,
+ * depending whether the CPU sees it in memory address space
+ * or (e.g. x86) uses special I/O instructions.
+ */
+#define NET_CHIP_MEM_IO
+#undef NET_CHIP_PORT_IO
+
+/* The name of the hijacked 'bus handle' field in the softc
+ * structure. We use this field to store the chip's base address.
+ */
+#define NET_SOFTC_BHANDLE_FIELD osdep.mem_bus_space_handle
+
+/* define the names of the 'if_XXXreg.h' and 'if_XXXvar.h' headers
+ * (only if present, i.e., if the BSDNET driver has no respective
+ * header, leave this undefined).
+ *
+ */
+#define IF_REG_HEADER <if_em.h>
+#undef IF_VAR_HEADER
+
+/* define if a pci device */
+#define NETDRIVER_PCI <bsp/pci.h>
+
+/* Macros to disable and enable interrupts, respectively.
+ * The 'disable' macro is expanded in the ISR, the 'enable'
+ * macro is expanded in the driver task.
+ * The global network semaphore usually provides mutex
+ * protection of the device registers.
+ * Special care must be taken when coding the 'disable' macro,
+ * however to MAKE SURE THERE ARE NO OTHER SIDE EFFECTS such
+ * as:
+ * - macro must not clear any status flags
+ * - macro must save/restore any context information
+ * (e.g., a address register pointer or a bank switch register)
+ *
+ * ARGUMENT: the macro arg is a pointer to the driver's 'softc' structure
+ */
+
+#define NET_ENABLE_IRQS(sc) do { \
+ E1000_WRITE_REG(&sc->hw, IMS, (IMS_ENABLE_MASK)); \
+ } while (0)
+
+#define NET_DISABLE_IRQS(sc) do { \
+ E1000_WRITE_REG(&sc->hw, IMC, 0xffffffff); \
+ } while (0)
+
+#define KASSERT(a...) do {} while (0)
+
+/* dmamap stuff; these are defined just to work with the current version
+ * of this driver and the implementation must be carefully checked if
+ * a newer version is merged.!
+ *
+ * The more cumbersome routines have been commented in the source, the
+ * simpler ones are defined to be NOOPs here so the source gets less
+ * cluttered...
+ *
+ * ASSUMPTIONS:
+ *
+ * -> dmamap_sync cannot sync caches; assume we have HW snooping
+ *
+ */
+
+typedef unsigned bus_size_t;
+typedef unsigned bus_addr_t;
+
+typedef struct {
+ unsigned ds_addr;
+ unsigned ds_len;
+} bus_dma_segment_t;
+
+#define bus_dma_tag_destroy(args...) do {} while(0)
+
+#define bus_dmamap_destroy(args...) do {} while(0)
+
+#define bus_dmamap_unload(args...) do {} while (0)
+
+#ifdef __PPC__
+#define bus_dmamap_sync(args...) do { asm volatile("sync":::"memory"); } while (0)
+#else
+#define bus_dmamap_sync(args...) do {} while (0)
+#endif
+
+#define BUS_DMA_NOWAIT 0xdeadbeef /* unused */
+
+#endif
diff --git a/c/src/lib/libbsp/powerpc/beatnik/network/if_gfe/Makefile b/c/src/lib/libbsp/powerpc/beatnik/network/if_gfe/Makefile
new file mode 100644
index 0000000000..a2329f5e98
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/beatnik/network/if_gfe/Makefile
@@ -0,0 +1,90 @@
+#
+# Makefile.lib,v 1.5 2000/06/12 15:00:14 joel Exp
+#
+# Templates/Makefile.lib
+# Template library Makefile
+#
+
+LIBNAME=libif_gfe.a
+LIB=${ARCH}/${LIBNAME}
+
+# C and C++ source names, if any, go here -- minus the .c or .cc
+C_PIECES=if_gfe if_gfe_rtems if_gfe.modini
+PGMS = $(ARCH)/if_gfe.obj
+MODOBJS = $(OBJS)
+C_FILES=$(C_PIECES:%=%.c)
+C_O_FILES=$(C_PIECES:%=${ARCH}/%.o)
+
+CC_PIECES=
+CC_FILES=$(CC_PIECES:%=%.cc)
+CC_O_FILES=$(CC_PIECES:%=${ARCH}/%.o)
+
+H_FILES=
+
+# Assembly source names, if any, go here -- minus the .S
+S_PIECES=
+S_FILES=$(S_PIECES:%=%.S)
+S_O_FILES=$(S_FILES:%.S=${ARCH}/%.o)
+
+SRCS=$(C_FILES) $(CC_FILES) $(H_FILES) $(S_FILES)
+OBJS=$(C_O_FILES) $(CC_O_FILES) $(S_O_FILES)
+
+include $(RTEMS_MAKEFILE_PATH)/Makefile.inc
+
+include $(RTEMS_CUSTOM)
+include $(RTEMS_ROOT)/make/lib.cfg
+
+#
+# Add local stuff here using +=
+#
+
+DEFINES += -DDEBUG_MODULAR
+#-DDEBUG
+
+CPPFLAGS += -I. -Ilibchip -Iporting
+# bsdnet newproc generated daemon is non-FP;
+# prevent optimizer from generating FP instructions
+CFLAGS += -Wno-unused-variable -msoft-float
+
+#
+# Add your list of files to delete here. The config files
+# already know how to delete some stuff, so you may want
+# to just run 'make clean' first to see what gets missed.
+# 'make clobber' already includes 'make clean'
+#
+
+CLEAN_ADDITIONS +=
+CLOBBER_ADDITIONS +=
+
+all: ${ARCH} $(SRCS) $(LIB) $(PGMS)
+
+$(LIB): ${OBJS}
+ $(make-library)
+
+#How to make a relocatable object
+$(filter %.obj, $(PGMS)): $(MODOBJS)
+ $(make-obj)
+
+ifndef RTEMS_SITE_INSTALLDIR
+RTEMS_SITE_INSTALLDIR = $(PROJECT_RELEASE)
+endif
+
+${RTEMS_SITE_INSTALLDIR}/include \
+${RTEMS_SITE_INSTALLDIR}/lib \
+${RTEMS_SITE_INSTALLDIR}/bin \
+${RTEMS_SITE_INSTALLDIR}/$(RTEMS_BSP)/include \
+${RTEMS_SITE_INSTALLDIR}/$(RTEMS_BSP)/lib \
+${RTEMS_SITE_INSTALLDIR}/$(RTEMS_BSP)/bin :
+ test -d $@ || mkdir -p $@
+
+# Install the library, appending _g or _p as appropriate.
+# for include files, just use $(INSTALL_CHANGE)
+#
+# NOTES:
+# - BSP specific libraries, headers etc. should be installed to
+# $RTEMS_SITE_INSTALLDIR)/$(RTEMS_BSP)/lib
+#
+
+install: all $(RTEMS_SITE_INSTALLDIR)/lib
+ $(INSTALL_VARIANT) -m 644 ${LIB} ${RTEMS_SITE_INSTALLDIR}/lib
+ $(INSTALL_VARIANT) -m 644 ${PGMS} ${RTEMS_SITE_INSTALLDIR}/bin
diff --git a/c/src/lib/libbsp/powerpc/beatnik/network/if_gfe/gtethreg.h b/c/src/lib/libbsp/powerpc/beatnik/network/if_gfe/gtethreg.h
new file mode 100644
index 0000000000..d571eecd34
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/beatnik/network/if_gfe/gtethreg.h
@@ -0,0 +1,854 @@
+/* $NetBSD: gtethreg.h,v 1.2.10.1 2005/04/29 11:28:55 kent Exp $ */
+
+/*
+ * Copyright (c) 2002 Allegro Networks, Inc., Wasabi Systems, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed for the NetBSD Project by
+ * Allegro Networks, Inc., and Wasabi Systems, Inc.
+ * 4. The name of Allegro Networks, Inc. may not be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ * 5. The name of Wasabi Systems, Inc. may not be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ALLEGRO NETWORKS, INC. AND
+ * WASABI SYSTEMS, INC. ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL EITHER ALLEGRO NETWORKS, INC. OR WASABI SYSTEMS, INC.
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _DEV_GTETHREG_H_
+#define _DEV_GTETHREG_H_
+
+#define ETH__BIT(bit) (1U << (bit))
+#define ETH__LLBIT(bit) (1LLU << (bit))
+#define ETH__MASK(bit) (ETH__BIT(bit) - 1)
+#define ETH__LLMASK(bit) (ETH__LLBIT(bit) - 1)
+#define ETH__GEN(n, off) (0x2400+((n) << 10)+(ETH__ ## off))
+#define ETH__EXT(data, bit, len) (((data) >> (bit)) & ETH__MASK(len))
+#define ETH__LLEXT(data, bit, len) (((data) >> (bit)) & ETH__LLMASK(len))
+#define ETH__CLR(data, bit, len) ((data) &= ~(ETH__MASK(len) << (bit)))
+#define ETH__INS(new, bit) ((new) << (bit))
+#define ETH__LLINS(new, bit) ((uint64_t)(new) << (bit))
+
+/*
+ * Descriptors used for both receive & transmit data. Note that the descriptor
+ * must start on a 4LW boundary. Since the GT accesses the descriptor as
+ * two 64-bit quantities, we must present them 32bit quantities in the right
+ * order based on endianess.
+ */
+
+struct gt_eth_desc {
+#if defined(BYTE_ORDER) && BYTE_ORDER == BIG_ENDIAN
+ u_int32_t ed_lencnt; /* length is hi 16 bits; count (rx) is lo 16 */
+ u_int32_t ed_cmdsts; /* command (hi16)/status (lo16) bits */
+ u_int32_t ed_nxtptr; /* next descriptor (must be 4LW aligned) */
+ u_int32_t ed_bufptr; /* pointer to packet buffer */
+#endif
+#if defined(BYTE_ORDER) && BYTE_ORDER == LITTLE_ENDIAN
+ u_int32_t ed_cmdsts; /* command (hi16)/status (lo16) bits */
+ u_int32_t ed_lencnt; /* length is hi 16 bits; count (rx) is lo 16 */
+ u_int32_t ed_bufptr; /* pointer to packet buffer */
+ u_int32_t ed_nxtptr; /* next descriptor (must be 4LW aligned) */
+#endif
+};
+
+/* Table 578: Ethernet TX Descriptor - Command/Status word
+ * All bits except F, EI, AM, O are only valid if TX_CMD_L is also set,
+ * otherwise should be 0 (tx).
+ */
+#define TX_STS_LC ETH__BIT(5) /* Late Collision */
+#define TX_STS_UR ETH__BIT(6) /* Underrun error */
+#define TX_STS_RL ETH__BIT(8) /* Retransmit Limit (excession coll) */
+#define TX_STS_COL ETH__BIT(9) /* Collision Occurred */
+#define TX_STS_RC(v) ETH__GETBITS(v, 10, 4) /* Retransmit Count */
+#define TX_STS_ES ETH__BIT(15) /* Error Summary (LC|UR|RL) */
+#define TX_CMD_L ETH__BIT(16) /* Last - End Of Packet */
+#define TX_CMD_F ETH__BIT(17) /* First - Start Of Packet */
+#define TX_CMD_P ETH__BIT(18) /* Pad Packet */
+#define TX_CMD_GC ETH__BIT(22) /* Generate CRC */
+#define TX_CMD_EI ETH__BIT(23) /* Enable Interrupt */
+#define TX_CMD_AM ETH__BIT(30) /* Auto Mode */
+#define TX_CMD_O ETH__BIT(31) /* Ownership (1=GT 0=CPU) */
+
+#define TX_CMD_FIRST (TX_CMD_F|TX_CMD_O)
+#define TX_CMD_LAST (TX_CMD_L|TX_CMD_GC|TX_CMD_P|TX_CMD_O)
+
+/* Table 582: Ethernet RX Descriptor - Command/Status Word
+ * All bits except F, EI, AM, O are only valid if RX_CMD_L is also set,
+ * otherwise should be ignored (rx).
+ */
+#define RX_STS_CE ETH__BIT(0) /* CRC Error */
+#define RX_STS_COL ETH__BIT(1) /* Collision sensed during reception */
+#define RX_STS_LC ETH__BIT(5) /* Late Collision (Reserved) */
+#define RX_STS_OR ETH__BIT(6) /* Overrun Error */
+#define RX_STS_MFL ETH__BIT(7) /* Max Frame Len Error */
+#define RX_STS_SF ETH__BIT(8) /* Short Frame Error (< 64 bytes) */
+#define RX_STS_FT ETH__BIT(11) /* Frame Type (1 = 802.3) */
+#define RX_STS_M ETH__BIT(12) /* Missed Frame */
+#define RX_STS_HE ETH__BIT(13) /* Hash Expired (manual match) */
+#define RX_STS_IGMP ETH__BIT(14) /* IGMP Packet */
+#define RX_STS_ES ETH__BIT(15) /* Error Summary (CE|COL|LC|OR|MFL|SF) */
+#define RX_CMD_L ETH__BIT(16) /* Last - End Of Packet */
+#define RX_CMD_F ETH__BIT(17) /* First - Start Of Packet */
+#define RX_CMD_EI ETH__BIT(23) /* Enable Interrupt */
+#define RX_CMD_AM ETH__BIT(30) /* Auto Mode */
+#define RX_CMD_O ETH__BIT(31) /* Ownership (1=GT 0=CPU) */
+
+/* Table 586: Hash Table Entry Fields
+ */
+#define HSH_V ETH__LLBIT(0) /* Entry is valid */
+#define HSH_S ETH__LLBIT(1) /* Skip this entry */
+#define HSH_RD ETH__LLBIT(2) /* Receive(1) / Discard (0) */
+#define HSH_R ETH__LLBIT(2) /* Receive(1) */
+#define HSH_PRIO_GET(v) ETH__LLEXT(v, 51, 2)
+#define HSH_PRIO_INS(v) ETH__LLINS(v, 51)
+#define HSH_ADDR_MASK 0x7fffff8LLU
+#define HSH_LIMIT 12
+
+
+#define ETH_EPAR 0x2000 /* PHY Address Register */
+#define ETH_ESMIR 0x2010 /* SMI Register */
+
+#define ETH_BASE_ETH0 0x2400 /* Ethernet0 Register Base */
+#define ETH_BASE_ETH1 0x2800 /* Ethernet1 Register Base */
+#define ETH_BASE_ETH2 0x2c00 /* Ethernet2 Register Base */
+#define ETH_SIZE 0x0400 /* Register Space */
+
+#define ETH__EBASE 0x0000 /* Base of Registers */
+#define ETH__EPCR 0x0000 /* Port Config. Register */
+#define ETH__EPCXR 0x0008 /* Port Config. Extend Reg */
+#define ETH__EPCMR 0x0010 /* Port Command Register */
+#define ETH__EPSR 0x0018 /* Port Status Register */
+#define ETH__ESPR 0x0020 /* Port Serial Parameters Reg */
+#define ETH__EHTPR 0x0028 /* Port Hash Table Pointer Reg*/
+#define ETH__EFCSAL 0x0030 /* Flow Control Src Addr Low */
+#define ETH__EFCSAH 0x0038 /* Flow Control Src Addr High */
+#define ETH__ESDCR 0x0040 /* SDMA Configuration Reg */
+#define ETH__ESDCMR 0x0048 /* SDMA Command Register */
+#define ETH__EICR 0x0050 /* Interrupt Cause Register */
+#define ETH__EIMR 0x0058 /* Interrupt Mask Register */
+#define ETH__EFRDP0 0x0080 /* First Rx Desc Pointer 0 */
+#define ETH__EFRDP1 0x0084 /* First Rx Desc Pointer 1 */
+#define ETH__EFRDP2 0x0088 /* First Rx Desc Pointer 2 */
+#define ETH__EFRDP3 0x008c /* First Rx Desc Pointer 3 */
+#define ETH__ECRDP0 0x00a0 /* Current Rx Desc Pointer 0 */
+#define ETH__ECRDP1 0x00a4 /* Current Rx Desc Pointer 1 */
+#define ETH__ECRDP2 0x00a8 /* Current Rx Desc Pointer 2 */
+#define ETH__ECRDP3 0x00ac /* Current Rx Desc Pointer 3 */
+#define ETH__ECTDP0 0x00e0 /* Current Tx Desc Pointer 0 */
+#define ETH__ECTDP1 0x00e4 /* Current Tx Desc Pointer 1 */
+#define ETH__EDSCP2P0L 0x0060 /* IP Differentiated Services
+ CodePoint to Priority0 low */
+#define ETH__EDSCP2P0H 0x0064 /* IP Differentiated Services
+ CodePoint to Priority0 high*/
+#define ETH__EDSCP2P1L 0x0068 /* IP Differentiated Services
+ CodePoint to Priority1 low */
+#define ETH__EDSCP2P1H 0x006c /* IP Differentiated Services
+ CodePoint to Priority1 high*/
+#define ETH__EVPT2P 0x0068 /* VLAN Prio. Tag to Priority */
+#define ETH__EMIBCTRS 0x0100 /* MIB Counters */
+
+#define ETH_BASE(n) ETH__GEN(n, EBASE)
+#define ETH_EPCR(n) ETH__GEN(n, EPCR) /* Port Config. Register */
+#define ETH_EPCXR(n) ETH__GEN(n, EPCXR) /* Port Config. Extend Reg */
+#define ETH_EPCMR(n) ETH__GEN(n, EPCMR) /* Port Command Register */
+#define ETH_EPSR(n) ETH__GEN(n, EPSR) /* Port Status Register */
+#define ETH_ESPR(n) ETH__GEN(n, ESPR) /* Port Serial Parameters Reg */
+#define ETH_EHTPR(n) ETH__GEN(n, EHPTR) /* Port Hash Table Pointer Reg*/
+#define ETH_EFCSAL(n) ETH__GEN(n, EFCSAL) /* Flow Control Src Addr Low */
+#define ETH_EFCSAH(n) ETH__GEN(n, EFCSAH) /* Flow Control Src Addr High */
+#define ETH_ESDCR(n) ETH__GEN(n, ESDCR) /* SDMA Configuration Reg */
+#define ETH_ESDCMR(n) ETH__GEN(n, ESDCMR) /* SDMA Command Register */
+#define ETH_EICR(n) ETH__GEN(n, EICR) /* Interrupt Cause Register */
+#define ETH_EIMR(n) ETH__GEN(n, EIMR) /* Interrupt Mask Register */
+#define ETH_EFRDP0(n) ETH__GEN(n, EFRDP0) /* First Rx Desc Pointer 0 */
+#define ETH_EFRDP1(n) ETH__GEN(n, EFRDP1) /* First Rx Desc Pointer 1 */
+#define ETH_EFRDP2(n) ETH__GEN(n, EFRDP2) /* First Rx Desc Pointer 2 */
+#define ETH_EFRDP3(n) ETH__GEN(n, EFRDP3) /* First Rx Desc Pointer 3 */
+#define ETH_ECRDP0(n) ETH__GEN(n, ECRDP0) /* Current Rx Desc Pointer 0 */
+#define ETH_ECRDP1(n) ETH__GEN(n, ECRDP1) /* Current Rx Desc Pointer 1 */
+#define ETH_ECRDP2(n) ETH__GEN(n, ECRDP2) /* Current Rx Desc Pointer 2 */
+#define ETH_ECRDP3(n) ETH__GEN(n, ECRDP3) /* Current Rx Desc Pointer 3 */
+#define ETH_ECTDP0(n) ETH__GEN(n, ECTDP0) /* Current Tx Desc Pointer 0 */
+#define ETH_ECTDP1(n) ETH__GEN(n, ECTDP1) /* Current Tx Desc Pointer 1 */
+#define ETH_EDSCP2P0L(n) ETH__GEN(n, EDSCP2P0L) /* IP Differentiated Services
+ CodePoint to Priority0 low */
+#define ETH_EDSCP2P0H(n) ETH__GEN(n, EDSCP2P0H) /* IP Differentiated Services
+ CodePoint to Priority0 high*/
+#define ETH_EDSCP2P1L(n) ETH__GEN(n, EDSCP2P1L) /* IP Differentiated Services
+ CodePoint to Priority1 low */
+#define ETH_EDSCP2P1H(n) ETH__GEN(n, EDSCP1P1H) /* IP Differentiated Services
+ CodePoint to Priority1 high*/
+#define ETH_EVPT2P(n) ETH__GEN(n, EVPT2P) /* VLAN Prio. Tag to Priority */
+#define ETH_EMIBCTRS(n) ETH__GEN(n, EMIBCTRS) /* MIB Counters */
+
+#define ETH_EPAR_PhyAD_GET(v, n) (((v) >> ((n) * 5)) & 0x1f)
+
+#define ETH_ESMIR_READ(phy, reg) (ETH__INS(phy, 16)|\
+ ETH__INS(reg, 21)|\
+ ETH_ESMIR_ReadOpcode)
+#define ETH_ESMIR_WRITE(phy, reg, val) (ETH__INS(phy, 16)|\
+ ETH__INS(reg, 21)|\
+ ETH__INS(val, 0)|\
+ ETH_ESMIR_WriteOpcode)
+#define ETH_ESMIR_Value_GET(v) ETH__EXT(v, 0, 16)
+#define ETH_ESMIR_WriteOpcode 0
+#define ETH_ESMIR_ReadOpcode ETH__BIT(26)
+#define ETH_ESMIR_ReadValid ETH__BIT(27)
+#define ETH_ESMIR_Busy ETH__BIT(28)
+
+/*
+ * Table 597: Port Configuration Register (PCR)
+ * 00:00 PM Promiscuous mode
+ * 0: Normal mode (Frames are only received if the
+ * destination address is found in the hash
+ * table)
+ * 1: Promiscuous mode (Frames are received
+ * regardless of their destination address.
+ * Errored frames are discarded unless the Port
+ * Configuration register's PBF bit is set)
+ * 01:01 RBM Reject Broadcast Mode
+ * 0: Receive broadcast address
+ * 1: Reject frames with broadcast address
+ * Overridden by the promiscuous mode.
+ * 02:02 PBF Pass Bad Frames
+ * (0: Normal mode, 1: Pass bad Frames)
+ * The Ethernet receiver passes to the CPU errored
+ * frames (like fragments and collided packets)
+ * that are normally rejected.
+ * NOTE: Frames are only passed if they
+ * successfully pass address filtering.
+ * 06:03 Reserved
+ * 07:07 EN Enable (0: Disabled, 1: Enable)
+ * When enabled, the ethernet port is ready to
+ * transmit/receive.
+ * 09:08 LPBK Loop Back Mode
+ * 00: Normal mode
+ * 01: Internal loop back mode (TX data is looped
+ * back to the RX lines. No transition is seen
+ * on the interface pins)
+ * 10: External loop back mode (TX data is looped
+ * back to the RX lines and also transmitted
+ * out to the MII interface pins)
+ * 11: Reserved
+ * 10:10 FC Force Collision
+ * 0: Normal mode.
+ * 1: Force Collision on any TX frame.
+ * For RXM test (in Loopback mode).
+ * 11:11 Reserved.
+ * 12:12 HS Hash Size
+ * 0: 8K address filtering
+ * (256KB of memory space required).
+ * 1: 512 address filtering
+ * ( 16KB of memory space required).
+ * 13:13 HM Hash Mode (0: Hash Func. 0; 1: Hash Func. 1)
+ * 14:14 HDM Hash Default Mode
+ * 0: Discard addresses not found in address table
+ * 1: Pass addresses not found in address table
+ * 15:15 HD Duplex Mode (0: Half Duplex, 1: Full Duplex)
+ * NOTE: Valid only when auto-negotiation for
+ * duplex mode is disabled.
+ * 30:16 Reserved
+ * 31:31 ACCS Accelerate Slot Time
+ * (0: Normal mode, 1: Reserved)
+ */
+#define ETH_EPCR_PM ETH__BIT(0)
+#define ETH_EPCR_RBM ETH__BIT(1)
+#define ETH_EPCR_PBF ETH__BIT(2)
+#define ETH_EPCR_EN ETH__BIT(7)
+#define ETH_EPCR_LPBK_GET(v) ETH__BIT(v, 8, 2)
+#define ETH_EPCR_LPBK_Normal 0
+#define ETH_EPCR_LPBK_Internal 1
+#define ETH_EPCR_LPBK_External 2
+#define ETH_EPCR_FC ETH__BIT(10)
+
+#define ETH_EPCR_HS ETH__BIT(12)
+#define ETH_EPCR_HS_8K 0
+#define ETH_EPCR_HS_512 ETH_EPCR_HS
+
+#define ETH_EPCR_HM ETH__BIT(13)
+#define ETH_EPCR_HM_0 0
+#define ETH_EPCR_HM_1 ETH_EPCR_HM
+
+#define ETH_EPCR_HDM ETH__BIT(14)
+#define ETH_EPCR_HDM_Discard 0
+#define ETH_EPCR_HDM_Pass ETH_EPCR_HDM
+
+#define ETH_EPCR_HD_Half 0
+#define ETH_EPCR_HD_Full ETH_EPCR_HD_Full
+
+#define ETH_EPCR_ACCS ETH__BIT(31)
+
+
+
+/*
+ * Table 598: Port Configuration Extend Register (PCXR)
+ * 00:00 IGMP IGMP Packets Capture Enable
+ * 0: IGMP packets are treated as normal Multicast
+ * packets.
+ * 1: IGMP packets on IPv4/Ipv6 over Ethernet/802.3
+ * are trapped and sent to high priority RX
+ * queue.
+ * 01:01 SPAN Spanning Tree Packets Capture Enable
+ * 0: BPDU (Bridge Protocol Data Unit) packets are
+ * treated as normal Multicast packets.
+ * 1: BPDU packets are trapped and sent to high
+ * priority RX queue.
+ * 02:02 PAR Partition Enable (0: Normal, 1: Partition)
+ * When more than 61 collisions occur while
+ * transmitting, the port enters Partition mode.
+ * It waits for the first good packet from the
+ * wire and then goes back to Normal mode. Under
+ * Partition mode it continues transmitting, but
+ * it does not receive.
+ * 05:03 PRIOtx Priority weight in the round-robin between high
+ * and low priority TX queues.
+ * 000: 1 pkt from HIGH, 1 pkt from LOW.
+ * 001: 2 pkt from HIGH, 1 pkt from LOW.
+ * 010: 4 pkt from HIGH, 1 pkt from LOW.
+ * 011: 6 pkt from HIGH, 1 pkt from LOW.
+ * 100: 8 pkt from HIGH, 1 pkt from LOW.
+ * 101: 10 pkt from HIGH, 1 pkt from LOW.
+ * 110: 12 pkt from HIGH, 1 pkt from LOW.
+ * 111: All pkt from HIGH, 0 pkt from LOW. LOW is
+ * served only if HIGH is empty.
+ * NOTE: If the HIGH queue is emptied before
+ * finishing the count, the count is reset
+ * until the next first HIGH comes in.
+ * 07:06 PRIOrx Default Priority for Packets Received on this
+ * Port (00: Lowest priority, 11: Highest priority)
+ * 08:08 PRIOrx_Override Override Priority for Packets Received on this
+ * Port (0: Do not override, 1: Override with
+ * <PRIOrx> field)
+ * 09:09 DPLXen Enable Auto-negotiation for Duplex Mode
+ * (0: Enable, 1: Disable)
+ * 11:10 FCTLen Enable Auto-negotiation for 802.3x Flow-control
+ * 0: Enable; When enabled, 1 is written (through
+ * SMI access) to the PHY's register 4 bit 10
+ * to advertise flow-control capability.
+ * 1: Disable; Only enables flow control after the
+ * PHY address is set by the CPU. When changing
+ * the PHY address the flow control
+ * auto-negotiation must be disabled.
+ * 11:11 FLP Force Link Pass
+ * (0: Force Link Pass, 1: Do NOT Force Link pass)
+ * 12:12 FCTL 802.3x Flow-Control Mode (0: Enable, 1: Disable)
+ * NOTE: Only valid when auto negotiation for flow
+ * control is disabled.
+ * 13:13 Reserved
+ * 15:14 MFL Max Frame Length
+ * Maximum packet allowed for reception (including
+ * CRC): 00: 1518 bytes, 01: 1536 bytes,
+ * 10: 2048 bytes, 11: 64K bytes
+ * 16:16 MIBclrMode MIB Counters Clear Mode (0: Clear, 1: No effect)
+ * 17:17 MIBctrMode Reserved. (MBZ)
+ * 18:18 Speed Port Speed (0: 10Mbit/Sec, 1: 100Mbit/Sec)
+ * NOTE: Only valid if SpeedEn bit is set.
+ * 19:19 SpeedEn Enable Auto-negotiation for Speed
+ * (0: Enable, 1: Disable)
+ * 20:20 RMIIen RMII enable
+ * 0: Port functions as MII port
+ * 1: Port functions as RMII port
+ * 21:21 DSCPen DSCP enable
+ * 0: IP DSCP field decoding is disabled.
+ * 1: IP DSCP field decoding is enabled.
+ * 31:22 Reserved
+ */
+#define ETH_EPCXR_IGMP ETH__BIT(0)
+#define ETH_EPCXR_SPAN ETH__BIT(1)
+#define ETH_EPCXR_PAR ETH__BIT(2)
+#define ETH_EPCXR_PRIOtx_GET(v) ETH__EXT(v, 3, 3)
+#define ETH_EPCXR_PRIOrx_GET(v) ETH__EXT(v, 3, 3)
+#define ETH_EPCXR_PRIOrx_Override ETH__BIT(8)
+#define ETH_EPCXR_DLPXen ETH__BIT(9)
+#define ETH_EPCXR_FCTLen ETH__BIT(10)
+#define ETH_EPCXR_FLP ETH__BIT(11)
+#define ETH_EPCXR_FCTL ETH__BIT(12)
+#define ETH_EPCXR_MFL_GET(v) ETH__EXT(v, 14, 2)
+#define ETH_EPCXR_MFL_1518 0
+#define ETH_EPCXR_MFL_1536 1
+#define ETH_EPCXR_MFL_2084 2
+#define ETH_EPCXR_MFL_64K 3
+#define ETH_EPCXR_MIBclrMode ETH__BIT(16)
+#define ETH_EPCXR_MIBctrMode ETH__BIT(17)
+#define ETH_EPCXR_Speed ETH__BIT(18)
+#define ETH_EPCXR_SpeedEn ETH__BIT(19)
+#define ETH_EPCXR_RMIIEn ETH__BIT(20)
+#define ETH_EPCXR_DSCPEn ETH__BIT(21)
+
+
+
+/*
+ * Table 599: Port Command Register (PCMR)
+ * 14:00 Reserved
+ * 15:15 FJ Force Jam / Flow Control
+ * When in half-duplex mode, the CPU uses this bit
+ * to force collisions on the Ethernet segment.
+ * When the CPU recognizes that it is going to run
+ * out of receive buffers, it can force the
+ * transmitter to send jam frames, forcing
+ * collisions on the wire. To allow transmission
+ * on the Ethernet segment, the CPU must clear the
+ * FJ bit when more resources are available. When
+ * in full-duplex and flow-control is enabled, this
+ * bit causes the port's transmitter to send
+ * flow-control PAUSE packets. The CPU must reset
+ * this bit when more resources are available.
+ * 31:16 Reserved
+ */
+
+#define ETH_EPCMR_FJ ETH__BIT(15)
+
+
+/*
+ * Table 600: Port Status Register (PSR) -- Read Only
+ * 00:00 Speed Indicates Port Speed (0: 10Mbs, 1: 100Mbs)
+ * 01:01 Duplex Indicates Port Duplex Mode (0: Half, 1: Full)
+ * 02:02 Fctl Indicates Flow-control Mode
+ * (0: enabled, 1: disabled)
+ * 03:03 Link Indicates Link Status (0: down, 1: up)
+ * 04:04 Pause Indicates that the port is in flow-control
+ * disabled state. This bit is set when an IEEE
+ * 802.3x flow-control PAUSE (XOFF) packet is
+ * received (assuming that flow-control is
+ * enabled and the port is in full-duplex mode).
+ * Reset when XON is received, or when the XOFF
+ * timer has expired.
+ * 05:05 TxLow Tx Low Priority Status
+ * Indicates the status of the low priority
+ * transmit queue: (0: Stopped, 1: Running)
+ * 06:06 TxHigh Tx High Priority Status
+ * Indicates the status of the high priority
+ * transmit queue: (0: Stopped, 1: Running)
+ * 07:07 TXinProg TX in Progress
+ * Indicates that the port's transmitter is in an
+ * active transmission state.
+ * 31:08 Reserved
+ */
+#define ETH_EPSR_Speed ETH__BIT(0)
+#define ETH_EPSR_Duplex ETH__BIT(1)
+#define ETH_EPSR_Fctl ETH__BIT(2)
+#define ETH_EPSR_Link ETH__BIT(3)
+#define ETH_EPSR_Pause ETH__BIT(4)
+#define ETH_EPSR_TxLow ETH__BIT(5)
+#define ETH_EPSR_TxHigh ETH__BIT(6)
+#define ETH_EPSR_TXinProg ETH__BIT(7)
+
+
+/*
+ * Table 601: Serial Parameters Register (SPR)
+ * 01:00 JAM_LENGTH Two bits to determine the JAM Length
+ * (in Backpressure) as follows:
+ * 00 = 12K bit-times
+ * 01 = 24K bit-times
+ * 10 = 32K bit-times
+ * 11 = 48K bit-times
+ * 06:02 JAM_IPG Five bits to determine the JAM IPG.
+ * The step is four bit-times. The value may vary
+ * between 4 bit time to 124.
+ * 11:07 IPG_JAM_TO_DATA Five bits to determine the IPG JAM to DATA.
+ * The step is four bit-times. The value may vary
+ * between 4 bit time to 124.
+ * 16:12 IPG_DATA Inter-Packet Gap (IPG)
+ * The step is four bit-times. The value may vary
+ * between 12 bit time to 124.
+ * NOTE: These bits may be changed only when the
+ * Ethernet ports is disabled.
+ * 21:17 Data_Blind Data Blinder
+ * The number of nibbles from the beginning of the
+ * IPG, in which the IPG counter is restarted when
+ * detecting a carrier activity. Following this
+ * value, the port enters the Data Blinder zone and
+ * does not reset the IPG counter. This ensures
+ * fair access to the medium.
+ * The default is 10 hex (64 bit times - 2/3 of the
+ * default IPG). The step is 4 bit-times. Valid
+ * range is 3 to 1F hex nibbles.
+ * NOTE: These bits may be only changed when the
+ * Ethernet port is disabled.
+ * 22:22 Limit4 The number of consecutive packet collisions that
+ * occur before the collision counter is reset.
+ * 0: The port resets its collision counter after
+ * 16 consecutive retransmit trials and
+ * restarts the Backoff algorithm.
+ * 1: The port resets its collision counter and
+ * restarts the Backoff algorithm after 4
+ * consecutive transmit trials.
+ * 31:23 Reserved
+ */
+#define ETH_ESPR_JAM_LENGTH_GET(v) ETH__EXT(v, 0, 2)
+#define ETH_ESPR_JAM_IPG_GET(v) ETH__EXT(v, 2, 5)
+#define ETH_ESPR_IPG_JAM_TO_DATA_GET(v) ETH__EXT(v, 7, 5)
+#define ETH_ESPR_IPG_DATA_GET(v) ETH__EXT(v, 12, 5)
+#define ETH_ESPR_Data_Bilnd_GET(v) ETH__EXT(v, 17, 5)
+#define ETH_ESPR_Limit4(v) ETH__BIT(22)
+
+/*
+ * Table 602: Hash Table Pointer Register (HTPR)
+ * 31:00 HTP 32-bit pointer to the address table.
+ * Bits [2:0] must be set to zero.
+ */
+
+/*
+ * Table 603: Flow Control Source Address Low (FCSAL)
+ * 15:0 SA[15:0] Source Address
+ * The least significant bits of the source
+ * address for the port. This address is used for
+ * Flow Control.
+ * 31:16 Reserved
+ */
+
+/*
+ * Table 604: Flow Control Source Address High (FCSAH)
+ * 31:0 SA[47:16] Source Address
+ * The most significant bits of the source address
+ * for the port. This address is used for Flow
+ * Control.
+ */
+
+
+/*
+ * Table 605: SDMA Configuration Register (SDCR)
+ * 01:00 Reserved
+ * 05:02 RC Retransmit Count
+ * Sets the maximum number of retransmits per
+ * packet. After executing retransmit for RC
+ * times, the TX SDMA closes the descriptor with a
+ * Retransmit Limit error indication and processes
+ * the next packet. When RC is set to 0, the
+ * number of retransmits is unlimited. In this
+ * case, the retransmit process is only terminated
+ * if CPU issues an Abort command.
+ * 06:06 BLMR Big/Little Endian Receive Mode
+ * The DMA supports Big or Little Endian
+ * configurations on a per channel basis. The BLMR
+ * bit only affects data transfer to memory.
+ * 0: Big Endian
+ * 1: Little Endian
+ * 07:07 BLMT Big/Little Endian Transmit Mode
+ * The DMA supports Big or Little Endian
+ * configurations on a per channel basis. The BLMT
+ * bit only affects data transfer from memory.
+ * 0: Big Endian
+ * 1: Little Endian
+ * 08:08 POVR PCI Override
+ * When set, causes the SDMA to direct all its
+ * accesses in PCI_0 direction and overrides
+ * normal address decoding process.
+ * 09:09 RIFB Receive Interrupt on Frame Boundaries
+ * When set, the SDMA Rx generates interrupts only
+ * on frame boundaries (i.e. after writing the
+ * frame status to the descriptor).
+ * 11:10 Reserved
+ * 13:12 BSZ Burst Size
+ * Sets the maximum burst size for SDMA
+ * transactions:
+ * 00: Burst is limited to 1 64bit words.
+ * 01: Burst is limited to 2 64bit words.
+ * 10: Burst is limited to 4 64bit words.
+ * 11: Burst is limited to 8 64bit words.
+ * 31:14 Reserved
+ */
+#define ETH_ESDCR_RC_GET(v) ETH__EXT(v, 2, 4)
+#define ETH_ESDCR_BLMR ETH__BIT(6)
+#define ETH_ESDCR_BLMT ETH__BIT(7)
+#define ETH_ESDCR_POVR ETH__BIT(8)
+#define ETH_ESDCR_RIFB ETH__BIT(9)
+#define ETH_ESDCR_BSZ_GET(v) ETH__EXT(v, 12, 2)
+#define ETH_ESDCR_BSZ_SET(v, n) (ETH__CLR(v, 12, 2),\
+ (v) |= ETH__INS(n, 12))
+#define ETH_ESDCR_BSZ_1 0
+#define ETH_ESDCR_BSZ_2 1
+#define ETH_ESDCR_BSZ_4 2
+#define ETH_ESDCR_BSZ_8 3
+
+#define ETH_ESDCR_BSZ_Strings { "1 64-bit word", "2 64-bit words", \
+ "4 64-bit words", "8 64-bit words" }
+
+/*
+ * Table 606: SDMA Command Register (SDCMR)
+ * 06:00 Reserved
+ * 07:07 ERD Enable RX DMA.
+ * Set to 1 by the CPU to cause the SDMA to start
+ * a receive process. Cleared when the CPU issues
+ * an Abort Receive command.
+ * 14:08 Reserved
+ * 15:15 AR Abort Receive
+ * Set to 1 by the CPU to abort a receive SDMA
+ * operation. When the AR bit is set, the SDMA
+ * aborts its current operation and moves to IDLE.
+ * No descriptor is closed. The AR bit is cleared
+ * upon entering IDLE. After setting the AR bit,
+ * the CPU must poll the bit to verify that the
+ * abort sequence is completed.
+ * 16:16 STDH Stop TX High
+ * Set to 1 by the CPU to stop the transmission
+ * process from the high priority queue at the end
+ * of the current frame. An interrupt is generated
+ * when the stop command has been executed.
+ * Writing 1 to STDH resets TXDH bit.
+ * Writing 0 to this bit has no effect.
+ * 17:17 STDL Stop TX Low
+ * Set to 1 by the CPU to stop the transmission
+ * process from the low priority queue at the end
+ * of the current frame. An interrupt is generated
+ * when the stop command has been executed.
+ * Writing 1 to STDL resets TXDL bit.
+ * Writing 0 to this bit has no effect.
+ * 22:18 Reserved
+ * 23:23 TXDH Start Tx High
+ * Set to 1 by the CPU to cause the SDMA to fetch
+ * the first descriptor and start a transmit
+ * process from the high priority Tx queue.
+ * Writing 1 to TXDH resets STDH bit.
+ * Writing 0 to this bit has no effect.
+ * 24:24 TXDL Start Tx Low
+ * Set to 1 by the CPU to cause the SDMA to fetch
+ * the first descriptor and start a transmit
+ * process from the low priority Tx queue.
+ * Writing 1 to TXDL resets STDL bit.
+ * Writing 0 to this bit has no effect.
+ * 30:25 Reserved
+ * 31:31 AT Abort Transmit
+ * Set to 1 by the CPU to abort a transmit DMA
+ * operation. When the AT bit is set, the SDMA
+ * aborts its current operation and moves to IDLE.
+ * No descriptor is closed. Cleared upon entering
+ * IDLE. After setting AT bit, the CPU must poll
+ * it in order to verify that the abort sequence
+ * is completed.
+ */
+#define ETH_ESDCMR_ERD ETH__BIT(7)
+#define ETH_ESDCMR_AR ETH__BIT(15)
+#define ETH_ESDCMR_STDH ETH__BIT(16)
+#define ETH_ESDCMR_STDL ETH__BIT(17)
+#define ETH_ESDCMR_TXDH ETH__BIT(23)
+#define ETH_ESDCMR_TXDL ETH__BIT(24)
+#define ETH_ESDCMR_AT ETH__BIT(31)
+
+/*
+ * Table 607: Interrupt Cause Register (ICR)
+ * 00:00 RxBuffer Rx Buffer Return
+ * Indicates an Rx buffer returned to CPU ownership
+ * or that the port finished reception of a Rx
+ * frame in either priority queues.
+ * NOTE: In order to get a Rx Buffer return per
+ * priority queue, use bit 19:16. This bit is
+ * set upon closing any Rx descriptor which
+ * has its EI bit set. To limit the
+ * interrupts to frame (rather than buffer)
+ * boundaries, the user must set SDMA
+ * Configuration register's RIFB bit. When
+ * the RIFB bit is set, an interrupt
+ * generates only upon closing the first
+ * descriptor of a received packet, if this
+ * descriptor has it EI bit set.
+ * 01:01 Reserved
+ * 02:02 TxBufferHigh Tx Buffer for High priority Queue
+ * Indicates a Tx buffer returned to CPU ownership
+ * or that the port finished transmission of a Tx
+ * frame.
+ * NOTE: This bit is set upon closing any Tx
+ * descriptor which has its EI bit set. To
+ * limit the interrupts to frame (rather than
+ * buffer) boundaries, the user must set EI
+ * only in the last descriptor.
+ * 03:03 TxBufferLow Tx Buffer for Low Priority Queue
+ * Indicates a Tx buffer returned to CPU ownership
+ * or that the port finished transmission of a Tx
+ * frame.
+ * NOTE: This bit is set upon closing any Tx
+ * descriptor which has its EI bit set. To
+ * limit the interrupts to frame (rather than
+ * buffer) boundaries, the user must set EI
+ * only in the last descriptor.
+ * 05:04 Reserved
+ * 06:06 TxEndHigh Tx End for High Priority Queue
+ * Indicates that the Tx DMA stopped processing the
+ * high priority queue after stop command, or that
+ * it reached the end of the high priority
+ * descriptor chain.
+ * 07:07 TxEndLow Tx End for Low Priority Queue
+ * Indicates that the Tx DMA stopped processing the
+ * low priority queue after stop command, or that
+ * it reached the end of the low priority
+ * descriptor chain.
+ * 08:08 RxError Rx Resource Error
+ * Indicates a Rx resource error event in one of
+ * the priority queues.
+ * NOTE: To get a Rx Resource Error Indication per
+ * priority queue, use bit 23:20.
+ * 09:09 Reserved
+ * 10:10 TxErrorHigh Tx Resource Error for High Priority Queue
+ * Indicates a Tx resource error event during
+ * packet transmission from the high priority queue
+ * 11:11 TxErrorLow Tx Resource Error for Low Priority Queue
+ * Indicates a Tx resource error event during
+ * packet transmission from the low priority queue
+ * 12:12 RxOVR Rx Overrun
+ * Indicates an overrun event that occurred during
+ * reception of a packet.
+ * 13:13 TxUdr Tx Underrun
+ * Indicates an underrun event that occurred during
+ * transmission of packet from either queue.
+ * 15:14 Reserved
+ * 16:16 RxBuffer-Queue[0] Rx Buffer Return in Priority Queue[0]
+ * Indicates a Rx buffer returned to CPU ownership
+ * or that the port completed reception of a Rx
+ * frame in a receive priority queue[0]
+ * 17:17 RxBuffer-Queue[1] Rx Buffer Return in Priority Queue[1]
+ * Indicates a Rx buffer returned to CPU ownership
+ * or that the port completed reception of a Rx
+ * frame in a receive priority queue[1].
+ * 18:18 RxBuffer-Queue[2] Rx Buffer Return in Priority Queue[2]
+ * Indicates a Rx buffer returned to CPU ownership
+ * or that the port completed reception of a Rx
+ * frame in a receive priority queue[2].
+ * 19:19 RxBuffer-Queue[3] Rx Buffer Return in Priority Queue[3]
+ * Indicates a Rx buffer returned to CPU ownership
+ * or that the port completed reception of a Rx
+ * frame in a receive priority queue[3].
+ * 20:20 RxError-Queue[0] Rx Resource Error in Priority Queue[0]
+ * Indicates a Rx resource error event in receive
+ * priority queue[0].
+ * 21:21 RxError-Queue[1] Rx Resource Error in Priority Queue[1]
+ * Indicates a Rx resource error event in receive
+ * priority queue[1].
+ * 22:22 RxError-Queue[2] Rx Resource Error in Priority Queue[2]
+ * Indicates a Rx resource error event in receive
+ * priority queue[2].
+ * 23:23 RxError-Queue[3] Rx Resource Error in Priority Queue[3]
+ * Indicates a Rx resource error event in receive
+ * priority queue[3].
+ * 27:24 Reserved
+ * 28:29 MIIPhySTC MII PHY Status Change
+ * Indicates a status change reported by the PHY
+ * connected to this port. Set when the MII
+ * management interface block identifies a change
+ * in PHY's register 1.
+ * 29:29 SMIdone SMI Command Done
+ * Indicates that the SMI completed a MII
+ * management command (either read or write) that
+ * was initiated by the CPU writing to the SMI
+ * register.
+ * 30:30 Reserved
+ * 31:31 EtherIntSum Ethernet Interrupt Summary
+ * This bit is a logical OR of the (unmasked) bits
+ * [30:04] in the Interrupt Cause register.
+ */
+
+#define ETH_IR_RxBuffer ETH__BIT(0)
+#define ETH_IR_TxBufferHigh ETH__BIT(2)
+#define ETH_IR_TxBufferLow ETH__BIT(3)
+#define ETH_IR_TxEndHigh ETH__BIT(6)
+#define ETH_IR_TxEndLow ETH__BIT(7)
+#define ETH_IR_RxError ETH__BIT(8)
+#define ETH_IR_TxErrorHigh ETH__BIT(10)
+#define ETH_IR_TxErrorLow ETH__BIT(11)
+#define ETH_IR_RxOVR ETH__BIT(12)
+#define ETH_IR_TxUdr ETH__BIT(13)
+#define ETH_IR_RxBuffer_0 ETH__BIT(16)
+#define ETH_IR_RxBuffer_1 ETH__BIT(17)
+#define ETH_IR_RxBuffer_2 ETH__BIT(18)
+#define ETH_IR_RxBuffer_3 ETH__BIT(19)
+#define ETH_IR_RxBuffer_GET(v) ETH__EXT(v, 16, 4)
+#define ETH_IR_RxError_0 ETH__BIT(20)
+#define ETH_IR_RxError_1 ETH__BIT(21)
+#define ETH_IR_RxError_2 ETH__BIT(22)
+#define ETH_IR_RxError_3 ETH__BIT(23)
+#define ETH_IR_RxError_GET(v) ETH__EXT(v, 20, 4)
+#define ETH_IR_RxBits (ETH_IR_RxBuffer_0|\
+ ETH_IR_RxBuffer_1|\
+ ETH_IR_RxBuffer_2|\
+ ETH_IR_RxBuffer_3|\
+ ETH_IR_RxError_0|\
+ ETH_IR_RxError_1|\
+ ETH_IR_RxError_2|\
+ ETH_IR_RxError_3)
+#define ETH_IR_MIIPhySTC ETH__BIT(28)
+#define ETH_IR_SMIdone ETH__BIT(29)
+#define ETH_IR_EtherIntSum ETH__BIT(31)
+#define ETH_IR_Summary ETH__BIT(31)
+
+/*
+ * Table 608: Interrupt Mask Register (IMR)
+ * 31:00 Various Mask bits for the Interrupt Cause register.
+ */
+
+/*
+ * Table 609: IP Differentiated Services CodePoint to Priority0 low (DSCP2P0L),
+ * 31:00 Priority0_low The LSB priority bits for DSCP[31:0] entries.
+ */
+
+/*
+ * Table 610: IP Differentiated Services CodePoint to Priority0 high (DSCP2P0H)
+ * 31:00 Priority0_high The LSB priority bits for DSCP[63:32] entries.
+ */
+
+/*
+ * Table 611: IP Differentiated Services CodePoint to Priority1 low (DSCP2P1L)
+ * 31:00 Priority1_low The MSB priority bits for DSCP[31:0] entries.
+ */
+
+/*
+ * Table 612: IP Differentiated Services CodePoint to Priority1 high (DSCP2P1H)
+ * 31:00 Priority1_high The MSB priority bit for DSCP[63:32] entries.
+ */
+
+/*
+ * Table 613: VLAN Priority Tag to Priority (VPT2P)
+ * 07:00 Priority0 The LSB priority bits for VLAN Priority[7:0]
+ * entries.
+ * 15:08 Priority1 The MSB priority bits for VLAN Priority[7:0]
+ * entries.
+ * 31:16 Reserved
+ */
+
+/* Address control registers -- these are offsets from the GT base
+ * and NOT from the ethernet port base. <tss>
+ */
+#define ETH_ACTL_0_LO 0xf200
+
+/* Enable hardware cache snooping;
+ * Copyright Shuchen K. Feng <feng1@bnl.gov>, 2004
+ */
+
+/* Ethernet address control (Low) snoop bits */
+#define RxBSnoopEn ETH__BIT(6) /* Rx buffer snoop enable,1=enable*/
+#define TxBSnoopEn ETH__BIT(14) /* Tx buffer snoop enable */
+#define RxDSnoopEn ETH__BIT(22) /* Rx descriptor snoop enable */
+#define TxDSnoopEn ETH__BIT(30) /* Tx descriptor snoop enable */
+
+#define ETH_ACTL_0_HI 0xf204
+/* Ethernet address control (High), snoop bits */
+#define HashSnoopEn ETH__BIT(6) /* Hash Table snoop enable */
+
+
+#define ETH_ACTL_1_LO 0xf220
+#define ETH_ACTL_1_HI 0xf224
+#define ETH_ACTL_2_LO 0xf240
+#define ETH_ACTL_2_HI 0xf244
+
+
+#endif /* _DEV_GTETHREG_H_ */
diff --git a/c/src/lib/libbsp/powerpc/beatnik/network/if_gfe/gtvar.h b/c/src/lib/libbsp/powerpc/beatnik/network/if_gfe/gtvar.h
new file mode 100644
index 0000000000..00d72bfa3a
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/beatnik/network/if_gfe/gtvar.h
@@ -0,0 +1,170 @@
+/* $NetBSD: gtvar.h,v 1.7.4.1 2005/04/29 11:28:56 kent Exp $ */
+
+/*
+ * Copyright (c) 2002 Allegro Networks, Inc., Wasabi Systems, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed for the NetBSD Project by
+ * Allegro Networks, Inc., and Wasabi Systems, Inc.
+ * 4. The name of Allegro Networks, Inc. may not be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ * 5. The name of Wasabi Systems, Inc. may not be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ALLEGRO NETWORKS, INC. AND
+ * WASABI SYSTEMS, INC. ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL EITHER ALLEGRO NETWORKS, INC. OR WASABI SYSTEMS, INC.
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * gtvar.h -- placeholder for GT system controller driver
+ */
+#ifndef _DISCOVERY_DEV_GTVAR_H_
+#define _DISCOVERY_DEV_GTVAR_H_
+
+#include <sys/systm.h>
+
+struct gt_softc {
+#ifndef __rtems__
+ struct device gt_dev;
+ bus_dma_tag_t gt_dmat;
+ bus_space_tag_t gt_memt; /* the GT itself */
+ bus_space_tag_t gt_pci0_memt; /* PCI0 mem space */
+ bus_space_tag_t gt_pci0_iot; /* PCI0 i/o space */
+ boolean_t gt_pci0_host; /* We're host on PCI0 if TRUE */
+ bus_space_tag_t gt_pci1_memt; /* PCI1 mem space */
+ bus_space_tag_t gt_pci1_iot; /* PCI1 i/o space */
+ boolean_t gt_pci1_host; /* We're host on PCI1 if TRUE */
+
+ bus_space_handle_t gt_memh; /* to access the GT registers */
+#else
+ unsigned gt_memh;
+#endif
+ int gt_childmask; /* what children are present */
+};
+
+#define GT_CHILDOK(gt, ga, cd, pos, max) \
+ (((ga)->ga_unit) < (max) && \
+ !((gt)->gt_childmask & (1 << (((ga)->ga_unit) + (pos)))) && \
+ !strcmp((ga)->ga_name, (cd)->cd_name))
+
+#define GT_MPSCOK(gt, ga, cd) GT_CHILDOK((gt), (ga), (cd), 0, 2)
+#define GT_PCIOK(gt, ga, cd) GT_CHILDOK((gt), (ga), (cd), 2, 2)
+#define GT_ETHEROK(gt, ga, cd) GT_CHILDOK((gt), (ga), (cd), 4, 3)
+#define GT_OBIOOK(gt, ga, cd) GT_CHILDOK((gt), (ga), (cd), 7, 5)
+#define GT_I2COK(gt, ga, cd) GT_CHILDOK((gt), (ga), (cd), 12, 1)
+
+#define GT_CHILDFOUND(gt, ga, pos) \
+ ((void)(((gt)->gt_childmask |= (1 << (((ga)->ga_unit) + (pos))))))
+
+#define GT_MPSCFOUND(gt, ga) GT_CHILDFOUND((gt), (ga), 0)
+#define GT_PCIFOUND(gt, ga) GT_CHILDFOUND((gt), (ga), 2)
+#define GT_ETHERFOUND(gt, ga) GT_CHILDFOUND((gt), (ga), 4)
+#define GT_OBIOFOUND(gt, ga) GT_CHILDFOUND((gt), (ga), 7)
+#define GT_I2CFOUND(gt, ga) GT_CHILDFOUND((gt), (ga), 12)
+
+#ifndef __rtems__
+struct gt_attach_args {
+ const char *ga_name; /* class name of device */
+ bus_dma_tag_t ga_dmat; /* dma tag */
+ bus_space_tag_t ga_memt; /* GT bus space tag */
+ bus_space_handle_t ga_memh; /* GT bus space handle */
+ int ga_unit; /* instance of ga_name */
+};
+
+struct obio_attach_args {
+ const char *oa_name; /* call name of device */
+ bus_space_tag_t oa_memt; /* bus space tag */
+ bus_addr_t oa_offset; /* offset (absolute) to device */
+ bus_size_t oa_size; /* size (strided) of device */
+ int oa_irq; /* irq */
+};
+#endif
+
+#ifdef _KERNEL
+#ifndef __rtems__
+#include "locators.h"
+#endif
+
+#ifdef DEBUG
+extern int gtpci_debug;
+#endif
+
+/*
+ * Locators for GT private devices, as specified to config.
+ */
+#define GT_UNK_UNIT GTCF_UNIT_DEFAULT /* wcarded 'function' */
+
+#define OBIO_UNK_OFFSET OBIOCF_OFFSET_DEFAULT /* wcarded 'offset' */
+
+#define OBIO_UNK_SIZE OBIOCF_SIZE_DEFAULT /* wcarded 'size' */
+
+#define OBIO_UNK_IRQ OBIOCF_IRQ_DEFAULT /* wcarded 'irq' */
+
+void gt_attach_common(struct gt_softc *);
+uint32_t gt_read_mpp(void);
+int gt_cfprint(void *, const char *);
+
+#ifndef __rtems__
+/* int gt_bs_extent_init(struct discovery_bus_space *, char *); AKB */
+int gt_mii_read(struct device *, struct device *, int, int);
+void gt_mii_write(struct device *, struct device *, int, int, int);
+int gtget_macaddr(struct gt_softc *,int, char *);
+
+void gt_watchdog_service(void);
+bus_addr_t gt_dma_phys_to_bus_mem(bus_dma_tag_t, bus_addr_t);
+bus_addr_t gt_dma_bus_mem_to_phys(bus_dma_tag_t, bus_addr_t);
+
+#define gt_read(gt,o) \
+ bus_space_read_4((gt)->gt_memt, (gt)->gt_memh, (o))
+#define gt_write(gt,o,v) \
+ bus_space_write_4((gt)->gt_memt, (gt)->gt_memh, (o), (v))
+#else
+#endif
+
+#if defined(__powerpc__)
+static __inline volatile int
+atomic_add(volatile int *p, int v)
+{
+ int rv;
+ int rtmp;
+
+ __asm __volatile(
+ "1: lwarx %0,0,%3\n"
+ " add %1,%4,%0\n"
+ " stwcx. %1,0,%3\n"
+ " bne- 1b\n"
+ " sync"
+ : "=&r"(rv), "=&r"(rtmp), "=m"(*p)
+ : "r"(p), "r"(v), "m"(*p)
+ : "cc");
+
+ return rv;
+}
+
+#endif /* __powerpc__ */
+
+#endif /* _KERNEL */
+
+#endif /* _DISCOVERY_DEV_GTVAR_H_ */
diff --git a/c/src/lib/libbsp/powerpc/beatnik/network/if_gfe/if_gfe.c b/c/src/lib/libbsp/powerpc/beatnik/network/if_gfe/if_gfe.c
new file mode 100644
index 0000000000..47ceb98182
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/beatnik/network/if_gfe/if_gfe.c
@@ -0,0 +1,2641 @@
+/* $NetBSD: if_gfe.c,v 1.13.8.1 2005/04/29 11:28:56 kent Exp $ */
+
+/*
+ * Copyright (c) 2002 Allegro Networks, Inc., Wasabi Systems, Inc.
+ * All rights reserved.
+ *
+ * Copyright 2004: Enable hardware cache snooping. Kate Feng <feng1@bnl.gov>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed for the NetBSD Project by
+ * Allegro Networks, Inc., and Wasabi Systems, Inc.
+ * 4. The name of Allegro Networks, Inc. may not be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ * 5. The name of Wasabi Systems, Inc. may not be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ALLEGRO NETWORKS, INC. AND
+ * WASABI SYSTEMS, INC. ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL EITHER ALLEGRO NETWORKS, INC. OR WASABI SYSTEMS, INC.
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * if_gfe.c -- GT ethernet MAC driver
+ */
+
+/* Enable hardware cache snooping;
+ * Copyright Shuchen K. Feng <feng1@bnl.gov>, 2004
+ */
+
+#ifdef __rtems__
+#include <rtemscompat.h>
+#include <string.h>
+#include <stdio.h>
+#include <inttypes.h>
+#endif
+
+#include <sys/cdefs.h>
+#ifndef __rtems__
+__KERNEL_RCSID(0, "$NetBSD: if_gfe.c,v 1.13.8.1 2005/04/29 11:28:56 kent Exp $");
+
+#include "opt_inet.h"
+#include "bpfilter.h"
+#endif
+
+#include <sys/param.h>
+#include <sys/types.h>
+#ifndef __rtems__
+#include <sys/inttypes.h>
+#include <sys/queue.h>
+#endif
+
+#ifndef __rtems__
+#include <uvm/uvm_extern.h>
+
+#include <sys/callout.h>
+#include <sys/device.h>
+#endif
+#include <sys/errno.h>
+#include <sys/ioctl.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+
+#ifndef __rtems__
+#include <machine/bus.h>
+#endif
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+#ifndef __rtems__
+#include <net/if_ether.h>
+#else
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+#include <net/ethernet.h>
+#include <rtems/rtems_mii_ioctl.h>
+#endif
+
+#ifdef INET
+#include <netinet/in.h>
+#ifndef __rtems__
+#include <netinet/if_inarp.h>
+#endif
+#endif
+#if NBPFILTER > 0
+#include <net/bpf.h>
+#endif
+
+#ifndef __rtems__
+#include <dev/mii/miivar.h>
+
+#include <dev/marvell/gtintrreg.h>
+#include <dev/marvell/gtethreg.h>
+
+#include <dev/marvell/gtvar.h>
+#include <dev/marvell/if_gfevar.h>
+#else
+#include <bsp/gtintrreg.h>
+#include <bsp/gtreg.h>
+#include "gtethreg.h"
+
+#include "gtvar.h"
+#include "if_gfevar.h"
+#include <rtemscompat1.h>
+#define ether_sprintf ether_sprintf_macro
+#endif
+
+#define GE_READ(sc, reg) \
+ bus_space_read_4((sc)->sc_gt_memt, (sc)->sc_memh, ETH__ ## reg)
+#define GE_WRITE(sc, reg, v) \
+ bus_space_write_4((sc)->sc_gt_memt, (sc)->sc_memh, ETH__ ## reg, (v))
+
+#define GT_READ(sc, reg) \
+ bus_space_read_4((sc)->sc_gt_memt, (sc)->sc_gt_memh, reg)
+#define GT_WRITE(sc, reg, v) \
+ bus_space_write_4((sc)->sc_gt_memt, (sc)->sc_gt_memh, reg, (v))
+
+#define GE_DEBUG
+#if 0
+#define GE_NOHASH
+#define GE_NORX
+#endif
+
+#ifdef GE_DEBUG
+#define GE_DPRINTF(sc, a) do \
+ if ((sc)->sc_ec.ec_if.if_flags & IFF_DEBUG) \
+ printf a; \
+ while (0)
+#define GE_FUNC_ENTER(sc, func) GE_DPRINTF(sc, ("[" func))
+#define GE_FUNC_EXIT(sc, str) GE_DPRINTF(sc, (str "]"))
+#else
+#define GE_DPRINTF(sc, a) do { } while (0)
+#define GE_FUNC_ENTER(sc, func) do { } while (0)
+#define GE_FUNC_EXIT(sc, str) do { } while (0)
+#endif
+enum gfe_whack_op {
+ GE_WHACK_START, GE_WHACK_RESTART,
+ GE_WHACK_CHANGE, GE_WHACK_STOP
+};
+
+enum gfe_hash_op {
+ GE_HASH_ADD, GE_HASH_REMOVE,
+};
+
+
+#if 1
+#define htogt32(a) htobe32(a)
+#define gt32toh(a) be32toh(a)
+#else
+#define htogt32(a) htole32(a)
+#define gt32toh(a) le32toh(a)
+#endif
+
+#ifdef __rtems__
+#define htobe32 htonl
+#define be32toh ntohl
+#endif
+
+#define GE_RXDSYNC(sc, rxq, n, ops) \
+ bus_dmamap_sync((sc)->sc_dmat, (rxq)->rxq_desc_mem.gdm_map, \
+ (n) * sizeof((rxq)->rxq_descs[0]), sizeof((rxq)->rxq_descs[0]), \
+ (ops))
+#define GE_RXDPRESYNC(sc, rxq, n) \
+ GE_RXDSYNC(sc, rxq, n, BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE)
+#define GE_RXDPOSTSYNC(sc, rxq, n) \
+ GE_RXDSYNC(sc, rxq, n, BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE)
+
+#define GE_TXDSYNC(sc, txq, n, ops) \
+ bus_dmamap_sync((sc)->sc_dmat, (txq)->txq_desc_mem.gdm_map, \
+ (n) * sizeof((txq)->txq_descs[0]), sizeof((txq)->txq_descs[0]), \
+ (ops))
+#define GE_TXDPRESYNC(sc, txq, n) \
+ GE_TXDSYNC(sc, txq, n, BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE)
+#define GE_TXDPOSTSYNC(sc, txq, n) \
+ GE_TXDSYNC(sc, txq, n, BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE)
+
+#define STATIC
+
+#ifndef __rtems__
+STATIC int gfe_match (struct device *, struct cfdata *, void *);
+STATIC void gfe_attach (struct device *, struct device *, void *);
+#else
+STATIC int gfe_probe (device_t);
+STATIC int gfe_attach (device_t);
+STATIC void gfe_init (void*);
+#endif
+
+STATIC int gfe_dmamem_alloc(struct gfe_softc *, struct gfe_dmamem *, int,
+ size_t, int);
+STATIC void gfe_dmamem_free(struct gfe_softc *, struct gfe_dmamem *);
+
+#ifndef __rtems__
+STATIC int gfe_ifioctl (struct ifnet *, u_long, caddr_t);
+#else
+STATIC int gfe_ifioctl (struct ifnet *, ioctl_command_t, caddr_t);
+#endif
+STATIC void gfe_ifstart (struct ifnet *);
+STATIC void gfe_ifwatchdog (struct ifnet *);
+
+#ifndef __rtems__
+STATIC int gfe_mii_mediachange (struct ifnet *);
+STATIC void gfe_mii_mediastatus (struct ifnet *, struct ifmediareq *);
+STATIC int gfe_mii_read (struct device *, int, int);
+STATIC void gfe_mii_write (struct device *, int, int, int);
+STATIC void gfe_mii_statchg (struct device *);
+#endif
+
+STATIC void gfe_tick(void *arg);
+
+STATIC void gfe_tx_restart(void *);
+STATIC int gfe_tx_enqueue(struct gfe_softc *, enum gfe_txprio);
+STATIC uint32_t gfe_tx_done(struct gfe_softc *, enum gfe_txprio, uint32_t);
+STATIC void gfe_tx_cleanup(struct gfe_softc *, enum gfe_txprio, int);
+STATIC int gfe_tx_txqalloc(struct gfe_softc *, enum gfe_txprio);
+STATIC int gfe_tx_start(struct gfe_softc *, enum gfe_txprio);
+STATIC void gfe_tx_stop(struct gfe_softc *, enum gfe_whack_op);
+
+STATIC void gfe_rx_cleanup(struct gfe_softc *, enum gfe_rxprio);
+STATIC void gfe_rx_get(struct gfe_softc *, enum gfe_rxprio);
+STATIC int gfe_rx_prime(struct gfe_softc *);
+STATIC uint32_t gfe_rx_process(struct gfe_softc *, uint32_t, uint32_t);
+STATIC int gfe_rx_rxqalloc(struct gfe_softc *, enum gfe_rxprio);
+STATIC int gfe_rx_rxqinit(struct gfe_softc *, enum gfe_rxprio);
+STATIC void gfe_rx_stop(struct gfe_softc *, enum gfe_whack_op);
+
+STATIC int gfe_intr(void *);
+
+STATIC int gfe_whack(struct gfe_softc *, enum gfe_whack_op);
+
+STATIC int gfe_hash_compute(struct gfe_softc *, const uint8_t [ETHER_ADDR_LEN]);
+STATIC int gfe_hash_entry_op(struct gfe_softc *, enum gfe_hash_op,
+ enum gfe_rxprio, const uint8_t [ETHER_ADDR_LEN]);
+#ifndef __rtems__
+STATIC int gfe_hash_multichg(struct ethercom *, const struct ether_multi *,
+ u_long);
+#endif
+STATIC int gfe_hash_fill(struct gfe_softc *);
+STATIC int gfe_hash_alloc(struct gfe_softc *);
+
+#ifndef __rtems__
+/* Linkup to the rest of the kernel */
+CFATTACH_DECL(gfe, sizeof(struct gfe_softc),
+ gfe_match, gfe_attach, NULL, NULL);
+#else
+net_drv_tbl_t METHODS = {
+ n_probe : gfe_probe,
+ n_attach : gfe_attach,
+ n_detach : 0,
+ n_intr : (void (*)(void*))gfe_intr,
+};
+
+int
+gfe_mii_read(int phy, void *arg, unsigned reg, uint32_t *pval);
+int
+gfe_mii_write(int phy, void *arg, unsigned reg, uint32_t val);
+
+struct rtems_mdio_info
+gfe_mdio_access = {
+ mdio_r: gfe_mii_read,
+ mdio_w: gfe_mii_write,
+ has_gmii: 0
+};
+
+#endif
+
+extern struct cfdriver gfe_cd;
+
+#ifndef __rtems__
+int
+gfe_match(struct device *parent, struct cfdata *cf, void *aux)
+{
+ struct gt_softc *gt = (struct gt_softc *) parent;
+ struct gt_attach_args *ga = aux;
+ uint8_t enaddr[6];
+
+ if (!GT_ETHEROK(gt, ga, &gfe_cd))
+ return 0;
+
+ if (gtget_macaddr(gt, ga->ga_unit, enaddr) < 0)
+ return 0;
+
+ if (enaddr[0] == 0 && enaddr[1] == 0 && enaddr[2] == 0 &&
+ enaddr[3] == 0 && enaddr[4] == 0 && enaddr[5] == 0)
+ return 0;
+
+ return 1;
+}
+#else
+int
+gfe_probe(device_t dev)
+{
+ switch ( BSP_getDiscoveryVersion(0) ) {
+ case GT_64260_A:
+ case GT_64260_B:
+ return 0;
+ default:
+ break;
+ }
+ return -1;
+}
+
+void
+gfe_init(void *arg)
+{
+struct gfe_softc *sc = arg;
+ if ( sc->sc_ec.ec_if.if_flags & IFF_RUNNING )
+ gfe_whack(sc, GE_WHACK_RESTART);
+ else
+ gfe_whack(sc, GE_WHACK_START);
+}
+#endif
+
+/*
+ * Attach this instance, and then all the sub-devices
+ */
+#ifndef __rtems__
+void
+gfe_attach(struct device *parent, struct device *self, void *aux)
+#else
+int
+gfe_attach(device_t dev)
+#endif
+{
+#ifndef __rtems__
+ struct gt_attach_args * const ga = aux;
+ struct gt_softc * const gt = (struct gt_softc *) parent;
+ struct gfe_softc * const sc = (struct gfe_softc *) self;
+#else
+ struct gfe_softc * const sc = device_get_softc(dev);
+#endif
+ struct ifnet * const ifp = &sc->sc_ec.ec_if;
+ uint32_t data;
+ uint8_t enaddr[6];
+ int phyaddr;
+ uint32_t sdcr;
+ int error;
+#ifdef __rtems__
+ SPRINTFVARDECL;
+#endif
+
+#ifndef __rtems__
+ GT_ETHERFOUND(gt, ga);
+
+ sc->sc_gt_memt = ga->ga_memt;
+ sc->sc_gt_memh = ga->ga_memh;
+ sc->sc_dmat = ga->ga_dmat;
+ sc->sc_macno = ga->ga_unit;
+
+ if (bus_space_subregion(sc->sc_gt_memt, sc->sc_gt_memh,
+ ETH_BASE(sc->sc_macno), ETH_SIZE, &sc->sc_memh)) {
+ aprint_error(": failed to map registers\n");
+ }
+
+ callout_init(&sc->sc_co);
+#else
+ /* sc_macno, irq_no and sc_gt_memh must be filled in by 'setup' */
+
+ /* make ring sizes even numbers so that we have always multiple
+ * cache lines (paranoia)
+ */
+ if ( (sc->num_rxdesc = dev->d_ifconfig->rbuf_count) & 1 )
+ sc->num_rxdesc++;
+ if ( 0 == sc->num_rxdesc )
+ sc->num_rxdesc = 64;
+
+ if ( (sc->num_txdesc = dev->d_ifconfig->xbuf_count) & 1 )
+ sc->num_txdesc++;
+ if ( 0 == sc->num_txdesc )
+ sc->num_txdesc = 256;
+
+ /* Enable hardware cache snooping;
+ * Copyright Shuchen K. Feng <feng1@bnl.gov>, 2004
+ */
+ /* regs are eth0: 0xf200/0xf204, eth1 0xf220/0xf224, eth2: 0xf240/0xf244 */
+ {
+ uint32_t v;
+ v = GT_READ(sc, ETH_ACTL_0_LO + (sc->sc_macno<<5));
+ v |= RxBSnoopEn|TxBSnoopEn|RxDSnoopEn|TxDSnoopEn;
+ GT_WRITE(sc, ETH_ACTL_0_LO + (sc->sc_macno<<5), v);
+
+ v = GT_READ(sc, ETH_ACTL_0_HI + (sc->sc_macno<<5));
+ v |= HashSnoopEn;
+ GT_WRITE(sc, ETH_ACTL_0_HI + (sc->sc_macno<<5), v);
+ }
+
+#endif
+
+ data = bus_space_read_4(sc->sc_gt_memt, sc->sc_gt_memh, ETH_EPAR);
+#ifdef __rtems__
+ sc->sc_phyaddr =
+#endif
+ phyaddr = ETH_EPAR_PhyAD_GET(data, sc->sc_macno);
+
+#ifndef __rtems__
+ gtget_macaddr(gt, sc->sc_macno, enaddr);
+#else
+ memset( enaddr, 0, ETHER_ADDR_LEN );
+ if ( !memcmp(enaddr, sc->arpcom.ac_enaddr, ETHER_ADDR_LEN) ) {
+ aprint_error(": MAC address not set (pass to rtems_gfe_setup())\n");
+ return -1;
+ }
+ /* mac address needs to be provided by 'setup' */
+ memcpy(enaddr, sc->arpcom.ac_enaddr, ETHER_ADDR_LEN);
+#endif
+
+ sc->sc_pcr = GE_READ(sc, EPCR);
+ sc->sc_pcxr = GE_READ(sc, EPCXR);
+ sc->sc_intrmask = GE_READ(sc, EIMR) | ETH_IR_MIIPhySTC;
+
+ aprint_normal(": address %s", ether_sprintf(enaddr));
+
+#if defined(DEBUG)
+ aprint_normal(", pcr %#x, pcxr %#x", sc->sc_pcr, sc->sc_pcxr);
+#endif
+
+ sc->sc_pcxr &= ~ETH_EPCXR_PRIOrx_Override;
+#ifndef __rtems__
+ if (sc->sc_dev.dv_cfdata->cf_flags & 1) {
+ aprint_normal(", phy %d (rmii)", phyaddr);
+ sc->sc_pcxr |= ETH_EPCXR_RMIIEn;
+ } else
+#endif
+ {
+ aprint_normal(", phy %d (mii)", phyaddr);
+ sc->sc_pcxr &= ~ETH_EPCXR_RMIIEn;
+ }
+#ifndef __rtems__
+ if (sc->sc_dev.dv_cfdata->cf_flags & 2)
+ sc->sc_flags |= GE_NOFREE;
+#endif
+ sc->sc_pcxr &= ~(3 << 14);
+ sc->sc_pcxr |= (ETH_EPCXR_MFL_1536 << 14);
+
+ if (sc->sc_pcr & ETH_EPCR_EN) {
+ int tries = 1000;
+ /*
+ * Abort transmitter and receiver and wait for them to quiese
+ */
+ GE_WRITE(sc, ESDCMR, ETH_ESDCMR_AR|ETH_ESDCMR_AT);
+ do {
+ delay(100);
+ } while (tries-- > 0 && (GE_READ(sc, ESDCMR) & (ETH_ESDCMR_AR|ETH_ESDCMR_AT)));
+ }
+
+ sc->sc_pcr &= ~(ETH_EPCR_EN | ETH_EPCR_RBM | ETH_EPCR_PM | ETH_EPCR_PBF);
+
+#if defined(DEBUG)
+ aprint_normal(", pcr %#x, pcxr %#x", sc->sc_pcr, sc->sc_pcxr);
+#endif
+
+ /*
+ * Now turn off the GT. If it didn't quiese, too ***ing bad.
+ */
+ GE_WRITE(sc, EPCR, sc->sc_pcr);
+#ifndef __rtems__
+ GE_WRITE(sc, EIMR, sc->sc_intrmask);
+#else
+ GE_WRITE(sc, EICR, 0);
+ GE_WRITE(sc, EIMR, 0);
+#endif
+ sdcr = GE_READ(sc, ESDCR);
+ ETH_ESDCR_BSZ_SET(sdcr, ETH_ESDCR_BSZ_4);
+ sdcr |= ETH_ESDCR_RIFB;
+ GE_WRITE(sc, ESDCR, sdcr);
+ sc->sc_max_frame_length = 1536;
+
+ aprint_normal("\n");
+#ifndef __rtems__
+ sc->sc_mii.mii_ifp = ifp;
+ sc->sc_mii.mii_readreg = gfe_mii_read;
+ sc->sc_mii.mii_writereg = gfe_mii_write;
+ sc->sc_mii.mii_statchg = gfe_mii_statchg;
+
+ ifmedia_init(&sc->sc_mii.mii_media, 0, gfe_mii_mediachange,
+ gfe_mii_mediastatus);
+
+ mii_attach(&sc->sc_dev, &sc->sc_mii, 0xffffffff, phyaddr,
+ MII_OFFSET_ANY, MIIF_NOISOLATE);
+ if (LIST_FIRST(&sc->sc_mii.mii_phys) == NULL) {
+ ifmedia_add(&sc->sc_mii.mii_media, IFM_ETHER|IFM_NONE, 0, NULL);
+ ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER|IFM_NONE);
+ } else {
+ ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER|IFM_AUTO);
+ }
+
+ strcpy(ifp->if_xname, sc->sc_dev.dv_xname);
+#else
+ if_initname(ifp, device_get_name(dev), device_get_unit(dev));
+ ifp->if_mtu = ETHERMTU;
+ ifp->if_output = ether_output;
+ ifp->if_init = gfe_init;
+ ifp->if_snd.ifq_maxlen = GE_TXDESC_MAX - 1;
+ ifp->if_baudrate = 10000000;
+#endif
+ ifp->if_softc = sc;
+ /* ifp->if_mowner = &sc->sc_mowner; */
+ ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+#if 0
+ ifp->if_flags |= IFF_DEBUG;
+#endif
+ ifp->if_ioctl = gfe_ifioctl;
+ ifp->if_start = gfe_ifstart;
+ ifp->if_watchdog = gfe_ifwatchdog;
+
+ if (sc->sc_flags & GE_NOFREE) {
+ error = gfe_rx_rxqalloc(sc, GE_RXPRIO_HI);
+ if (!error)
+ error = gfe_rx_rxqalloc(sc, GE_RXPRIO_MEDHI);
+ if (!error)
+ error = gfe_rx_rxqalloc(sc, GE_RXPRIO_MEDLO);
+ if (!error)
+ error = gfe_rx_rxqalloc(sc, GE_RXPRIO_LO);
+ if (!error)
+ error = gfe_tx_txqalloc(sc, GE_TXPRIO_HI);
+ if (!error)
+ error = gfe_hash_alloc(sc);
+ if (error)
+ aprint_error(
+ "%s: failed to allocate resources: %d\n",
+ ifp->if_xname, error);
+ }
+
+ if_attach(ifp);
+#ifndef __rtems__
+ ether_ifattach(ifp, enaddr);
+#else
+ ether_ifattach(ifp);
+#endif
+#if NBPFILTER > 0
+ bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header));
+#endif
+#if NRND > 0
+ rnd_attach_source(&sc->sc_rnd_source, self->dv_xname, RND_TYPE_NET, 0);
+#endif
+#ifndef __rtems__
+ intr_establish(IRQ_ETH0 + sc->sc_macno, IST_LEVEL, IPL_NET,
+ gfe_intr, sc);
+#else
+ return 0;
+#endif
+}
+
+int
+gfe_dmamem_alloc(struct gfe_softc *sc, struct gfe_dmamem *gdm, int maxsegs,
+ size_t size, int flags)
+{
+ int error = 0;
+ GE_FUNC_ENTER(sc, "gfe_dmamem_alloc");
+
+ KASSERT(gdm->gdm_kva == NULL);
+ gdm->gdm_size = size;
+ gdm->gdm_maxsegs = maxsegs;
+
+#ifndef __rtems__
+ error = bus_dmamem_alloc(sc->sc_dmat, gdm->gdm_size, PAGE_SIZE,
+ gdm->gdm_size, gdm->gdm_segs, gdm->gdm_maxsegs, &gdm->gdm_nsegs,
+ BUS_DMA_NOWAIT);
+ if (error)
+ goto fail;
+
+ error = bus_dmamem_map(sc->sc_dmat, gdm->gdm_segs, gdm->gdm_nsegs,
+ gdm->gdm_size, &gdm->gdm_kva, flags | BUS_DMA_NOWAIT);
+ if (error)
+ goto fail;
+
+ error = bus_dmamap_create(sc->sc_dmat, gdm->gdm_size, gdm->gdm_nsegs,
+ gdm->gdm_size, 0, BUS_DMA_ALLOCNOW|BUS_DMA_NOWAIT, &gdm->gdm_map);
+ if (error)
+ goto fail;
+
+ error = bus_dmamap_load(sc->sc_dmat, gdm->gdm_map, gdm->gdm_kva,
+ gdm->gdm_size, NULL, BUS_DMA_NOWAIT);
+ if (error)
+ goto fail;
+#else
+ gdm->gdm_segs[0].ds_len = size;
+
+ /* FIXME: probably we can relax the alignment */
+ if ( ! ( gdm->gdm_unaligned_buf = malloc( size + PAGE_SIZE - 1, M_DEVBUF, M_NOWAIT ) ) )
+ goto fail;
+
+ gdm->gdm_map = gdm;
+ gdm->gdm_nsegs = 1;
+ gdm->gdm_kva = (caddr_t)(gdm->gdm_segs[0].ds_addr = _DO_ALIGN(gdm->gdm_unaligned_buf, PAGE_SIZE));
+#endif
+
+ /* invalidate from cache */
+ bus_dmamap_sync(sc->sc_dmat, gdm->gdm_map, 0, gdm->gdm_size,
+ BUS_DMASYNC_PREREAD);
+fail:
+ if (error) {
+ gfe_dmamem_free(sc, gdm);
+ GE_DPRINTF(sc, (":err=%d", error));
+ }
+ GE_DPRINTF(sc, (":kva=%p/%#x,map=%p,nsegs=%d,pa=%" PRIx32 "/%" PRIx32,
+ gdm->gdm_kva, gdm->gdm_size, gdm->gdm_map, gdm->gdm_map->dm_nsegs,
+ gdm->gdm_map->dm_segs->ds_addr, gdm->gdm_map->dm_segs->ds_len));
+ GE_FUNC_EXIT(sc, "");
+ return error;
+}
+
+void
+gfe_dmamem_free(struct gfe_softc *sc, struct gfe_dmamem *gdm)
+{
+ GE_FUNC_ENTER(sc, "gfe_dmamem_free");
+#ifndef __rtems__
+ if (gdm->gdm_map)
+ bus_dmamap_destroy(sc->sc_dmat, gdm->gdm_map);
+ if (gdm->gdm_kva)
+ bus_dmamem_unmap(sc->sc_dmat, gdm->gdm_kva, gdm->gdm_size);
+ if (gdm->gdm_nsegs > 0)
+ bus_dmamem_free(sc->sc_dmat, gdm->gdm_segs, gdm->gdm_nsegs);
+#else
+ if (gdm->gdm_nsegs > 0)
+ free(gdm->gdm_unaligned_buf, M_DEVBUF);
+#endif
+ gdm->gdm_map = NULL;
+ gdm->gdm_kva = NULL;
+ gdm->gdm_nsegs = 0;
+ GE_FUNC_EXIT(sc, "");
+}
+
+#ifndef __rtems__
+int
+gfe_ifioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
+#else
+int
+gfe_ifioctl(struct ifnet *ifp, ioctl_command_t cmd, caddr_t data)
+#endif
+{
+ struct gfe_softc * const sc = ifp->if_softc;
+ struct ifreq *ifr = (struct ifreq *) data;
+#ifndef __rtems__
+ struct ifaddr *ifa = (struct ifaddr *) data;
+#endif
+ int s, error = 0;
+
+ GE_FUNC_ENTER(sc, "gfe_ifioctl");
+ s = splnet();
+
+ switch (cmd) {
+#ifndef __rtems__
+ case SIOCSIFADDR:
+ ifp->if_flags |= IFF_UP;
+ switch (ifa->ifa_addr->sa_family) {
+#ifdef INET
+ case AF_INET:
+ error = gfe_whack(sc, GE_WHACK_START);
+ if (error == 0)
+ arp_ifinit(ifp, ifa);
+ break;
+#endif
+ default:
+ error = gfe_whack(sc, GE_WHACK_START);
+ break;
+ }
+ break;
+#endif
+
+ case SIOCSIFFLAGS:
+ if ((sc->sc_ec.ec_if.if_flags & IFF_PROMISC) == 0)
+ sc->sc_pcr &= ~ETH_EPCR_PM;
+ else
+ sc->sc_pcr |= ETH_EPCR_PM;
+ switch (ifp->if_flags & (IFF_UP|IFF_RUNNING)) {
+ case IFF_UP|IFF_RUNNING:/* active->active, update */
+ error = gfe_whack(sc, GE_WHACK_CHANGE);
+ break;
+ case IFF_RUNNING: /* not up, so we stop */
+ error = gfe_whack(sc, GE_WHACK_STOP);
+ break;
+ case IFF_UP: /* not running, so we start */
+ error = gfe_whack(sc, GE_WHACK_START);
+ break;
+ case 0: /* idle->idle: do nothing */
+ break;
+ }
+ break;
+
+ case SIOCADDMULTI:
+ case SIOCDELMULTI:
+ error = (cmd == SIOCADDMULTI)
+ ? ether_addmulti(ifr, &sc->sc_ec)
+ : ether_delmulti(ifr, &sc->sc_ec);
+ if (error == ENETRESET) {
+ if (ifp->if_flags & IFF_RUNNING)
+#if !defined(__rtems__)
+ error = gfe_whack(sc, GE_WHACK_CHANGE);
+#else
+ /* doing GE_WHACK_CHANGE seems wrong - that
+ * doesn't do anything to the hash table.
+ * Therefore we perform a stop/start sequence.
+ */
+ {
+ error = gfe_whack(sc, GE_WHACK_STOP);
+ if ( error )
+ break;
+ error = gfe_whack(sc, GE_WHACK_START);
+ }
+#endif
+ else
+ error = 0;
+ }
+ break;
+
+ case SIOCSIFMTU:
+ if (ifr->ifr_mtu > ETHERMTU || ifr->ifr_mtu < ETHERMIN) {
+ error = EINVAL;
+ break;
+ }
+ ifp->if_mtu = ifr->ifr_mtu;
+ break;
+
+ case SIOCSIFMEDIA:
+ case SIOCGIFMEDIA:
+#ifndef __rtems__
+ error = ifmedia_ioctl(ifp, ifr, &sc->sc_mii.mii_media, cmd);
+#else
+ error = rtems_mii_ioctl(&gfe_mdio_access, sc, cmd, &ifr->ifr_media);
+#endif
+ break;
+
+ default:
+#ifndef __rtems__
+ error = EINVAL;
+#else
+ error = ether_ioctl(ifp, cmd, data);
+#endif
+ break;
+ }
+ splx(s);
+ GE_FUNC_EXIT(sc, "");
+ return error;
+}
+
+void
+gfe_ifstart(struct ifnet *ifp)
+{
+ struct gfe_softc * const sc = ifp->if_softc;
+ struct mbuf *m;
+
+ GE_FUNC_ENTER(sc, "gfe_ifstart");
+
+ if ((ifp->if_flags & IFF_RUNNING) == 0) {
+ GE_FUNC_EXIT(sc, "$");
+ return;
+ }
+
+ for (;;) {
+ IF_DEQUEUE(&ifp->if_snd, m);
+ if (m == NULL) {
+ ifp->if_flags &= ~IFF_OACTIVE;
+ GE_FUNC_EXIT(sc, "");
+ return;
+ }
+
+ /*
+ * No space in the pending queue? try later.
+ */
+ if (IF_QFULL(&sc->sc_txq[GE_TXPRIO_HI].txq_pendq))
+ break;
+
+ /*
+ * Try to enqueue a mbuf to the device. If that fails, we
+ * can always try to map the next mbuf.
+ */
+ IF_ENQUEUE(&sc->sc_txq[GE_TXPRIO_HI].txq_pendq, m);
+ GE_DPRINTF(sc, (">"));
+#ifndef GE_NOTX
+ (void) gfe_tx_enqueue(sc, GE_TXPRIO_HI);
+#endif
+ }
+
+ /*
+ * Attempt to queue the mbuf for send failed.
+ */
+ IF_PREPEND(&ifp->if_snd, m);
+ ifp->if_flags |= IFF_OACTIVE;
+ GE_FUNC_EXIT(sc, "%%");
+}
+
+void
+gfe_ifwatchdog(struct ifnet *ifp)
+{
+ struct gfe_softc * const sc = ifp->if_softc;
+ struct gfe_txqueue * const txq = &sc->sc_txq[GE_TXPRIO_HI];
+
+ GE_FUNC_ENTER(sc, "gfe_ifwatchdog");
+ printf("%s: device timeout", sc->sc_dev.dv_xname);
+ if (ifp->if_flags & IFF_RUNNING) {
+ uint32_t curtxdnum = (bus_space_read_4(sc->sc_gt_memt, sc->sc_gt_memh, txq->txq_ectdp) - txq->txq_desc_busaddr) / sizeof(txq->txq_descs[0]);
+ GE_TXDPOSTSYNC(sc, txq, txq->txq_fi);
+ GE_TXDPOSTSYNC(sc, txq, curtxdnum);
+ printf(" (fi=%d(%#x),lo=%d,cur=%" PRId32 "(%#x),icm=%#x) ",
+ txq->txq_fi, txq->txq_descs[txq->txq_fi].ed_cmdsts,
+ txq->txq_lo, curtxdnum, txq->txq_descs[curtxdnum].ed_cmdsts,
+ GE_READ(sc, EICR));
+ GE_TXDPRESYNC(sc, txq, txq->txq_fi);
+ GE_TXDPRESYNC(sc, txq, curtxdnum);
+ }
+ printf("\n");
+ ifp->if_oerrors++;
+ (void) gfe_whack(sc, GE_WHACK_RESTART);
+ GE_FUNC_EXIT(sc, "");
+}
+
+#ifdef __rtems__
+static struct mbuf *
+gfe_newbuf(struct mbuf *m)
+{
+ if ( !m ) {
+ MGETHDR(m, M_DONTWAIT, MT_DATA);
+ if ( !m )
+ return 0;
+ MCLGET(m, M_DONTWAIT);
+ if ( !(M_EXT & m->m_flags) ) {
+ m_freem(m);
+ return 0;
+ }
+ } else {
+ m->m_data = m->m_ext.ext_buf;
+ }
+ m->m_len = m->m_pkthdr.len = MCLBYTES;
+#if 0
+ m_adj(m, 2); /* so payload is 16-byte aligned */
+#endif
+ return m;
+}
+#endif
+
+int
+gfe_rx_rxqalloc(struct gfe_softc *sc, enum gfe_rxprio rxprio)
+{
+ struct gfe_rxqueue * const rxq = &sc->sc_rxq[rxprio];
+ int error;
+
+ GE_FUNC_ENTER(sc, "gfe_rx_rxqalloc");
+ GE_DPRINTF(sc, ("(%d)", rxprio));
+
+ error = gfe_dmamem_alloc(sc, &rxq->rxq_desc_mem, 1,
+ GE_RXDESC_MEMSIZE, BUS_DMA_NOCACHE);
+ if (error) {
+ GE_FUNC_EXIT(sc, "!!");
+ return error;
+ }
+
+#ifndef __rtems__
+ error = gfe_dmamem_alloc(sc, &rxq->rxq_buf_mem, GE_RXBUF_NSEGS,
+ GE_RXBUF_MEMSIZE, 0);
+#else
+ if ( ! (rxq->rxq_bufs = malloc( sizeof(*rxq->rxq_bufs) * GE_RXDESC_MAX, M_DEVBUF, M_NOWAIT ) ) ) {
+ error = -1;
+ } else {
+ int i;
+ for ( i = 0; i<GE_RXDESC_MAX; i++ ) {
+ if ( !(rxq->rxq_bufs[i] = gfe_newbuf(0)) ) {
+ fprintf(stderr,"gfe: Not enough mbuf clusters to initialize RX ring!\n");
+ while (--i >=0 ) {
+ m_freem(rxq->rxq_bufs[i]);
+ }
+ free(rxq->rxq_bufs, M_DEVBUF);
+ rxq->rxq_bufs = 0;
+ error = -1;
+ break;
+ }
+ }
+ }
+#endif
+ if (error) {
+ GE_FUNC_EXIT(sc, "!!!");
+ return error;
+ }
+ GE_FUNC_EXIT(sc, "");
+ return error;
+}
+
+int
+gfe_rx_rxqinit(struct gfe_softc *sc, enum gfe_rxprio rxprio)
+{
+ struct gfe_rxqueue * const rxq = &sc->sc_rxq[rxprio];
+ volatile struct gt_eth_desc *rxd;
+#ifndef __rtems__
+ const bus_dma_segment_t *ds;
+#endif
+ int idx;
+ bus_addr_t nxtaddr;
+#ifndef __rtems__
+ bus_size_t boff;
+#endif
+
+ GE_FUNC_ENTER(sc, "gfe_rx_rxqinit");
+ GE_DPRINTF(sc, ("(%d)", rxprio));
+
+ if ((sc->sc_flags & GE_NOFREE) == 0) {
+ int error = gfe_rx_rxqalloc(sc, rxprio);
+ if (error) {
+ GE_FUNC_EXIT(sc, "!");
+ return error;
+ }
+ } else {
+ KASSERT(rxq->rxq_desc_mem.gdm_kva != NULL);
+#ifndef __rtems__
+ KASSERT(rxq->rxq_buf_mem.gdm_kva != NULL);
+#else
+ KASSERT(rxq->rxq_bufs != NULL);
+#endif
+ }
+
+ memset(rxq->rxq_desc_mem.gdm_kva, 0, GE_RXDESC_MEMSIZE);
+
+ rxq->rxq_descs =
+ (volatile struct gt_eth_desc *) rxq->rxq_desc_mem.gdm_kva;
+ rxq->rxq_desc_busaddr = rxq->rxq_desc_mem.gdm_map->dm_segs[0].ds_addr;
+#ifndef __rtems__
+ rxq->rxq_bufs = (struct gfe_rxbuf *) rxq->rxq_buf_mem.gdm_kva;
+#endif
+ rxq->rxq_fi = 0;
+ rxq->rxq_active = GE_RXDESC_MAX;
+ for (idx = 0, rxd = rxq->rxq_descs,
+#ifndef __rtems__
+ boff = 0, ds = rxq->rxq_buf_mem.gdm_map->dm_segs,
+#endif
+ nxtaddr = rxq->rxq_desc_busaddr + sizeof(*rxd);
+ idx < GE_RXDESC_MAX;
+ idx++, rxd++, nxtaddr += sizeof(*rxd)) {
+#ifndef __rtems__
+ rxd->ed_lencnt = htogt32(GE_RXBUF_SIZE << 16);
+#else
+ rxd->ed_lencnt = htogt32(MCLBYTES << 16);
+#endif
+ rxd->ed_cmdsts = htogt32(RX_CMD_F|RX_CMD_L|RX_CMD_O|RX_CMD_EI);
+#ifndef __rtems__
+ rxd->ed_bufptr = htogt32(ds->ds_addr + boff);
+#else
+ rxd->ed_bufptr = htogt32(mtod(rxq->rxq_bufs[idx], uint32_t));
+#endif
+ /*
+ * update the nxtptr to point to the next txd.
+ */
+ if (idx == GE_RXDESC_MAX - 1)
+ nxtaddr = rxq->rxq_desc_busaddr;
+ rxd->ed_nxtptr = htogt32(nxtaddr);
+#ifndef __rtems__
+ boff += GE_RXBUF_SIZE;
+ if (boff == ds->ds_len) {
+ ds++;
+ boff = 0;
+ }
+#endif
+ }
+ bus_dmamap_sync(sc->sc_dmat, rxq->rxq_desc_mem.gdm_map, 0,
+ rxq->rxq_desc_mem.gdm_map->dm_mapsize,
+ BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
+#ifndef __rtems__
+ bus_dmamap_sync(sc->sc_dmat, rxq->rxq_buf_mem.gdm_map, 0,
+ rxq->rxq_buf_mem.gdm_map->dm_mapsize,
+ BUS_DMASYNC_PREREAD);
+#else
+ /* FIXME: we leave this call in here so compilation fails
+ * if bus_dmamap_sync() is ever fleshed-out to implement
+ * software cache coherency...
+ */
+ bus_dmamap_sync(sc->sc_dmat, rxq->rxq_buf_mem.gdm_map, 0,
+ rxq->rxq_buf_mem.gdm_map->dm_mapsize,
+ BUS_DMASYNC_PREREAD);
+#endif
+
+ rxq->rxq_intrbits = ETH_IR_RxBuffer|ETH_IR_RxError;
+ switch (rxprio) {
+ case GE_RXPRIO_HI:
+ rxq->rxq_intrbits |= ETH_IR_RxBuffer_3|ETH_IR_RxError_3;
+ rxq->rxq_efrdp = ETH_EFRDP3(sc->sc_macno);
+ rxq->rxq_ecrdp = ETH_ECRDP3(sc->sc_macno);
+ break;
+ case GE_RXPRIO_MEDHI:
+ rxq->rxq_intrbits |= ETH_IR_RxBuffer_2|ETH_IR_RxError_2;
+ rxq->rxq_efrdp = ETH_EFRDP2(sc->sc_macno);
+ rxq->rxq_ecrdp = ETH_ECRDP2(sc->sc_macno);
+ break;
+ case GE_RXPRIO_MEDLO:
+ rxq->rxq_intrbits |= ETH_IR_RxBuffer_1|ETH_IR_RxError_1;
+ rxq->rxq_efrdp = ETH_EFRDP1(sc->sc_macno);
+ rxq->rxq_ecrdp = ETH_ECRDP1(sc->sc_macno);
+ break;
+ case GE_RXPRIO_LO:
+ rxq->rxq_intrbits |= ETH_IR_RxBuffer_0|ETH_IR_RxError_0;
+ rxq->rxq_efrdp = ETH_EFRDP0(sc->sc_macno);
+ rxq->rxq_ecrdp = ETH_ECRDP0(sc->sc_macno);
+ break;
+ }
+ GE_FUNC_EXIT(sc, "");
+ return 0;
+}
+
+void
+gfe_rx_get(struct gfe_softc *sc, enum gfe_rxprio rxprio)
+{
+ struct ifnet * const ifp = &sc->sc_ec.ec_if;
+ struct gfe_rxqueue * const rxq = &sc->sc_rxq[rxprio];
+#ifndef __rtems__
+ struct mbuf *m = rxq->rxq_curpkt;
+#else
+ struct mbuf *m;
+#endif
+
+ GE_FUNC_ENTER(sc, "gfe_rx_get");
+ GE_DPRINTF(sc, ("(%d)", rxprio));
+
+ while (rxq->rxq_active > 0) {
+ volatile struct gt_eth_desc *rxd = &rxq->rxq_descs[rxq->rxq_fi];
+#ifndef __rtems__
+ struct gfe_rxbuf *rxb = &rxq->rxq_bufs[rxq->rxq_fi];
+#else
+ struct mbuf **rxb = &rxq->rxq_bufs[rxq->rxq_fi];
+#endif
+ const struct ether_header *eh;
+ unsigned int cmdsts;
+ size_t buflen;
+
+ GE_RXDPOSTSYNC(sc, rxq, rxq->rxq_fi);
+ cmdsts = gt32toh(rxd->ed_cmdsts);
+ GE_DPRINTF(sc, (":%d=%#x", rxq->rxq_fi, cmdsts));
+ rxq->rxq_cmdsts = cmdsts;
+ /*
+ * Sometimes the GE "forgets" to reset the ownership bit.
+ * But if the length has been rewritten, the packet is ours
+ * so pretend the O bit is set.
+ */
+ buflen = gt32toh(rxd->ed_lencnt) & 0xffff;
+ if ((cmdsts & RX_CMD_O) && buflen == 0) {
+ GE_RXDPRESYNC(sc, rxq, rxq->rxq_fi);
+ break;
+ }
+
+ /*
+ * If this is not a single buffer packet with no errors
+ * or for some reason it's bigger than our frame size,
+ * ignore it and go to the next packet.
+ */
+ if ((cmdsts & (RX_CMD_F|RX_CMD_L|RX_STS_ES)) !=
+ (RX_CMD_F|RX_CMD_L) ||
+ buflen > sc->sc_max_frame_length) {
+ GE_DPRINTF(sc, ("!"));
+ --rxq->rxq_active;
+ ifp->if_ipackets++;
+ ifp->if_ierrors++;
+
+ *rxb = gfe_newbuf(*rxb);
+ goto give_it_back;
+ }
+
+ /* CRC is included with the packet; trim it off. */
+ buflen -= ETHER_CRC_LEN;
+
+#ifndef __rtems__
+ if (m == NULL) {
+ MGETHDR(m, M_DONTWAIT, MT_DATA);
+ if (m == NULL) {
+ GE_DPRINTF(sc, ("?"));
+ break;
+ }
+ }
+ if ((m->m_flags & M_EXT) == 0 && buflen > MHLEN - 2) {
+ MCLGET(m, M_DONTWAIT);
+ if ((m->m_flags & M_EXT) == 0) {
+ GE_DPRINTF(sc, ("?"));
+ break;
+ }
+ }
+ m->m_data += 2;
+ m->m_len = 0;
+ m->m_pkthdr.len = 0;
+ m->m_pkthdr.rcvif = ifp;
+#else
+ if ( ! (m=gfe_newbuf(0)) ) {
+ /* recycle old buffer */
+ *rxb = gfe_newbuf(*rxb);
+ goto give_it_back;
+ }
+ /* swap mbufs */
+ {
+ struct mbuf *tmp = *rxb;
+ *rxb = m;
+ m = tmp;
+ rxd->ed_bufptr = htogt32(mtod(*rxb, uint32_t));
+ }
+#endif
+ rxq->rxq_cmdsts = cmdsts;
+ --rxq->rxq_active;
+
+#ifdef __rtems__
+ /* FIXME: we leave this call in here so compilation fails
+ * if bus_dmamap_sync() is ever fleshed-out to implement
+ * software cache coherency...
+ */
+ bus_dmamap_sync(sc->sc_dmat, rxq->rxq_buf_mem.gdm_map,
+ rxq->rxq_fi * sizeof(*rxb), buflen, BUS_DMASYNC_POSTREAD);
+#else
+ bus_dmamap_sync(sc->sc_dmat, rxq->rxq_buf_mem.gdm_map,
+ rxq->rxq_fi * sizeof(*rxb), buflen, BUS_DMASYNC_POSTREAD);
+
+ KASSERT(m->m_len == 0 && m->m_pkthdr.len == 0);
+ memcpy(m->m_data + m->m_len, rxb->rb_data, buflen);
+#endif
+
+ m->m_len = buflen;
+ m->m_pkthdr.len = buflen;
+
+ ifp->if_ipackets++;
+#if NBPFILTER > 0
+ if (ifp->if_bpf != NULL)
+ bpf_mtap(ifp->if_bpf, m);
+#endif
+
+ eh = (const struct ether_header *) m->m_data;
+ if ((ifp->if_flags & IFF_PROMISC) ||
+ (rxq->rxq_cmdsts & RX_STS_M) == 0 ||
+ (rxq->rxq_cmdsts & RX_STS_HE) ||
+ (eh->ether_dhost[0] & 1) != 0 ||
+ memcmp(eh->ether_dhost,
+#ifndef __rtems__
+ LLADDR(ifp->if_sadl),
+#else
+ sc->sc_ec.ac_enaddr,
+#endif
+ ETHER_ADDR_LEN) == 0) {
+#ifndef __rtems__
+ (*ifp->if_input)(ifp, m);
+ m = NULL;
+#else
+ DO_ETHER_INPUT_SKIPPING_ETHER_HEADER(ifp,m);
+#endif
+ GE_DPRINTF(sc, (">"));
+ } else {
+#ifndef __rtems__
+ m->m_len = 0;
+ m->m_pkthdr.len = 0;
+#else
+ m_freem(m);
+#endif
+ GE_DPRINTF(sc, ("+"));
+ }
+ rxq->rxq_cmdsts = 0;
+
+ give_it_back:
+ rxd->ed_lencnt &= ~0xffff; /* zero out length */
+ rxd->ed_cmdsts = htogt32(RX_CMD_F|RX_CMD_L|RX_CMD_O|RX_CMD_EI);
+#if 0
+ GE_DPRINTF(sc, ("([%d]->%08lx.%08lx.%08lx.%08lx)",
+ rxq->rxq_fi,
+ ((unsigned long *)rxd)[0], ((unsigned long *)rxd)[1],
+ ((unsigned long *)rxd)[2], ((unsigned long *)rxd)[3]));
+#endif
+ GE_RXDPRESYNC(sc, rxq, rxq->rxq_fi);
+ if (++rxq->rxq_fi == GE_RXDESC_MAX)
+ rxq->rxq_fi = 0;
+ rxq->rxq_active++;
+ }
+#ifndef __rtems__
+ rxq->rxq_curpkt = m;
+#endif
+ GE_FUNC_EXIT(sc, "");
+}
+
+uint32_t
+gfe_rx_process(struct gfe_softc *sc, uint32_t cause, uint32_t intrmask)
+{
+ struct ifnet * const ifp = &sc->sc_ec.ec_if;
+ struct gfe_rxqueue *rxq;
+ uint32_t rxbits;
+#define RXPRIO_DECODER 0xffffaa50
+ GE_FUNC_ENTER(sc, "gfe_rx_process");
+
+ rxbits = ETH_IR_RxBuffer_GET(cause);
+ while (rxbits) {
+ enum gfe_rxprio rxprio = (RXPRIO_DECODER >> (rxbits * 2)) & 3;
+ GE_DPRINTF(sc, ("%1" PRIx32, rxbits));
+ rxbits &= ~(1 << rxprio);
+ gfe_rx_get(sc, rxprio);
+ }
+
+ rxbits = ETH_IR_RxError_GET(cause);
+ while (rxbits) {
+ enum gfe_rxprio rxprio = (RXPRIO_DECODER >> (rxbits * 2)) & 3;
+ uint32_t masks[(GE_RXDESC_MAX + 31) / 32];
+ int idx;
+ rxbits &= ~(1 << rxprio);
+ rxq = &sc->sc_rxq[rxprio];
+ sc->sc_idlemask |= (rxq->rxq_intrbits & ETH_IR_RxBits);
+ intrmask &= ~(rxq->rxq_intrbits & ETH_IR_RxBits);
+ if ((sc->sc_tickflags & GE_TICK_RX_RESTART) == 0) {
+ sc->sc_tickflags |= GE_TICK_RX_RESTART;
+ callout_reset(&sc->sc_co, 1, gfe_tick, sc);
+ }
+ ifp->if_ierrors++;
+ GE_DPRINTF(sc, ("%s: rx queue %d filled at %u\n",
+ sc->sc_dev.dv_xname, rxprio, rxq->rxq_fi));
+ memset(masks, 0, sizeof(masks));
+ bus_dmamap_sync(sc->sc_dmat, rxq->rxq_desc_mem.gdm_map,
+ 0, rxq->rxq_desc_mem.gdm_size,
+ BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
+ for (idx = 0; idx < GE_RXDESC_MAX; idx++) {
+ volatile struct gt_eth_desc *rxd = &rxq->rxq_descs[idx];
+
+ if (RX_CMD_O & gt32toh(rxd->ed_cmdsts))
+ masks[idx/32] |= 1 << (idx & 31);
+ }
+ bus_dmamap_sync(sc->sc_dmat, rxq->rxq_desc_mem.gdm_map,
+ 0, rxq->rxq_desc_mem.gdm_size,
+ BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
+#if defined(DEBUG)
+ printf("%s: rx queue %d filled at %u=%#x(%#x/%#x)\n",
+ sc->sc_dev.dv_xname, rxprio, rxq->rxq_fi,
+ rxq->rxq_cmdsts, masks[0], masks[1]);
+#endif
+ }
+ if ((intrmask & ETH_IR_RxBits) == 0)
+ intrmask &= ~(ETH_IR_RxBuffer|ETH_IR_RxError);
+
+ GE_FUNC_EXIT(sc, "");
+ return intrmask;
+}
+
+int
+gfe_rx_prime(struct gfe_softc *sc)
+{
+ struct gfe_rxqueue *rxq;
+ int error;
+
+ GE_FUNC_ENTER(sc, "gfe_rx_prime");
+
+ error = gfe_rx_rxqinit(sc, GE_RXPRIO_HI);
+ if (error)
+ goto bail;
+ rxq = &sc->sc_rxq[GE_RXPRIO_HI];
+ if ((sc->sc_flags & GE_RXACTIVE) == 0) {
+ GE_WRITE(sc, EFRDP3, rxq->rxq_desc_busaddr);
+ GE_WRITE(sc, ECRDP3, rxq->rxq_desc_busaddr);
+ }
+ sc->sc_intrmask |= rxq->rxq_intrbits;
+
+ error = gfe_rx_rxqinit(sc, GE_RXPRIO_MEDHI);
+ if (error)
+ goto bail;
+ if ((sc->sc_flags & GE_RXACTIVE) == 0) {
+ rxq = &sc->sc_rxq[GE_RXPRIO_MEDHI];
+ GE_WRITE(sc, EFRDP2, rxq->rxq_desc_busaddr);
+ GE_WRITE(sc, ECRDP2, rxq->rxq_desc_busaddr);
+ sc->sc_intrmask |= rxq->rxq_intrbits;
+ }
+
+ error = gfe_rx_rxqinit(sc, GE_RXPRIO_MEDLO);
+ if (error)
+ goto bail;
+ if ((sc->sc_flags & GE_RXACTIVE) == 0) {
+ rxq = &sc->sc_rxq[GE_RXPRIO_MEDLO];
+ GE_WRITE(sc, EFRDP1, rxq->rxq_desc_busaddr);
+ GE_WRITE(sc, ECRDP1, rxq->rxq_desc_busaddr);
+ sc->sc_intrmask |= rxq->rxq_intrbits;
+ }
+
+ error = gfe_rx_rxqinit(sc, GE_RXPRIO_LO);
+ if (error)
+ goto bail;
+ if ((sc->sc_flags & GE_RXACTIVE) == 0) {
+ rxq = &sc->sc_rxq[GE_RXPRIO_LO];
+ GE_WRITE(sc, EFRDP0, rxq->rxq_desc_busaddr);
+ GE_WRITE(sc, ECRDP0, rxq->rxq_desc_busaddr);
+ sc->sc_intrmask |= rxq->rxq_intrbits;
+ }
+
+ bail:
+ GE_FUNC_EXIT(sc, "");
+ return error;
+}
+
+void
+gfe_rx_cleanup(struct gfe_softc *sc, enum gfe_rxprio rxprio)
+{
+ struct gfe_rxqueue *rxq = &sc->sc_rxq[rxprio];
+ GE_FUNC_ENTER(sc, "gfe_rx_cleanup");
+ if (rxq == NULL) {
+ GE_FUNC_EXIT(sc, "");
+ return;
+ }
+
+#ifndef __rtems__
+ if (rxq->rxq_curpkt)
+ m_freem(rxq->rxq_curpkt);
+#endif
+ if ((sc->sc_flags & GE_NOFREE) == 0) {
+ gfe_dmamem_free(sc, &rxq->rxq_desc_mem);
+#ifndef __rtems__
+ gfe_dmamem_free(sc, &rxq->rxq_buf_mem);
+#else
+ if ( rxq->rxq_bufs ) {
+ int i;
+ for ( i=0; i<GE_RXDESC_MAX; i++ ) {
+ if ( rxq->rxq_bufs[i] ) {
+ m_freem(rxq->rxq_bufs[i]);
+ }
+ }
+ free(rxq->rxq_bufs, M_DEVBUF);
+ }
+#endif
+ }
+ GE_FUNC_EXIT(sc, "");
+}
+
+void
+gfe_rx_stop(struct gfe_softc *sc, enum gfe_whack_op op)
+{
+ GE_FUNC_ENTER(sc, "gfe_rx_stop");
+ sc->sc_flags &= ~GE_RXACTIVE;
+ sc->sc_idlemask &= ~(ETH_IR_RxBits|ETH_IR_RxBuffer|ETH_IR_RxError);
+ sc->sc_intrmask &= ~(ETH_IR_RxBits|ETH_IR_RxBuffer|ETH_IR_RxError);
+ GE_WRITE(sc, EIMR, sc->sc_intrmask);
+ GE_WRITE(sc, ESDCMR, ETH_ESDCMR_AR);
+ do {
+ delay(10);
+ } while (GE_READ(sc, ESDCMR) & ETH_ESDCMR_AR);
+ gfe_rx_cleanup(sc, GE_RXPRIO_HI);
+ gfe_rx_cleanup(sc, GE_RXPRIO_MEDHI);
+ gfe_rx_cleanup(sc, GE_RXPRIO_MEDLO);
+ gfe_rx_cleanup(sc, GE_RXPRIO_LO);
+ GE_FUNC_EXIT(sc, "");
+}
+
+void
+gfe_tick(void *arg)
+{
+ struct gfe_softc * const sc = arg;
+ uint32_t intrmask;
+ unsigned int tickflags;
+ int s;
+
+ GE_FUNC_ENTER(sc, "gfe_tick");
+
+ s = splnet();
+
+ tickflags = sc->sc_tickflags;
+ sc->sc_tickflags = 0;
+ intrmask = sc->sc_intrmask;
+ if (tickflags & GE_TICK_TX_IFSTART)
+ gfe_ifstart(&sc->sc_ec.ec_if);
+ if (tickflags & GE_TICK_RX_RESTART) {
+ intrmask |= sc->sc_idlemask;
+ if (sc->sc_idlemask & (ETH_IR_RxBuffer_3|ETH_IR_RxError_3)) {
+ struct gfe_rxqueue *rxq = &sc->sc_rxq[GE_RXPRIO_HI];
+ rxq->rxq_fi = 0;
+ GE_WRITE(sc, EFRDP3, rxq->rxq_desc_busaddr);
+ GE_WRITE(sc, ECRDP3, rxq->rxq_desc_busaddr);
+ }
+ if (sc->sc_idlemask & (ETH_IR_RxBuffer_2|ETH_IR_RxError_2)) {
+ struct gfe_rxqueue *rxq = &sc->sc_rxq[GE_RXPRIO_MEDHI];
+ rxq->rxq_fi = 0;
+ GE_WRITE(sc, EFRDP2, rxq->rxq_desc_busaddr);
+ GE_WRITE(sc, ECRDP2, rxq->rxq_desc_busaddr);
+ }
+ if (sc->sc_idlemask & (ETH_IR_RxBuffer_1|ETH_IR_RxError_1)) {
+ struct gfe_rxqueue *rxq = &sc->sc_rxq[GE_RXPRIO_MEDLO];
+ rxq->rxq_fi = 0;
+ GE_WRITE(sc, EFRDP1, rxq->rxq_desc_busaddr);
+ GE_WRITE(sc, ECRDP1, rxq->rxq_desc_busaddr);
+ }
+ if (sc->sc_idlemask & (ETH_IR_RxBuffer_0|ETH_IR_RxError_0)) {
+ struct gfe_rxqueue *rxq = &sc->sc_rxq[GE_RXPRIO_LO];
+ rxq->rxq_fi = 0;
+ GE_WRITE(sc, EFRDP0, rxq->rxq_desc_busaddr);
+ GE_WRITE(sc, ECRDP0, rxq->rxq_desc_busaddr);
+ }
+ sc->sc_idlemask = 0;
+ }
+ if (intrmask != sc->sc_intrmask) {
+ sc->sc_intrmask = intrmask;
+ GE_WRITE(sc, EIMR, sc->sc_intrmask);
+ }
+ gfe_intr(sc);
+ splx(s);
+
+ GE_FUNC_EXIT(sc, "");
+}
+
+static int
+gfe_free_slots(struct gfe_softc *sc, struct gfe_txqueue *const txq)
+{
+ struct ifnet * const ifp = &sc->sc_ec.ec_if;
+#ifndef __rtems__
+ const int dcache_line_size = curcpu()->ci_ci.dcache_line_size;
+#endif
+ int got = 0;
+ int fi = txq->txq_fi;
+ volatile struct gt_eth_desc *txd = &txq->txq_descs[fi];
+ uint32_t cmdsts;
+#ifndef __rtems__
+ size_t pktlen;
+#endif
+
+ GE_FUNC_ENTER(sc, "gfe_free_slots");
+
+#ifdef __rtems__
+ do {
+#endif
+ GE_TXDPOSTSYNC(sc, txq, fi);
+ if ((cmdsts = gt32toh(txd->ed_cmdsts)) & TX_CMD_O) {
+ int nextin;
+
+ if (txq->txq_nactive == 1) {
+ GE_TXDPRESYNC(sc, txq, fi);
+ GE_FUNC_EXIT(sc, "");
+ return -1;
+ }
+ /*
+ * Sometimes the Discovery forgets to update the
+ * ownership bit in the descriptor. See if we own the
+ * descriptor after it (since we know we've turned
+ * that to the Discovery and if we own it now then the
+ * Discovery gave it back). If we do, we know the
+ * Discovery gave back this one but forgot to mark it
+ * as ours.
+ */
+ nextin = fi + 1;
+ if (nextin == GE_TXDESC_MAX)
+ nextin = 0;
+ GE_TXDPOSTSYNC(sc, txq, nextin);
+ if (gt32toh(txq->txq_descs[nextin].ed_cmdsts) & TX_CMD_O) {
+ GE_TXDPRESYNC(sc, txq, fi);
+ GE_TXDPRESYNC(sc, txq, nextin);
+ GE_FUNC_EXIT(sc, "");
+ return -1;
+ }
+#ifdef DEBUG
+ printf("%s: gfe_free_slots: transmitter resynced at %d\n",
+ sc->sc_dev.dv_xname, fi);
+#endif
+ }
+ got++;
+#ifdef __rtems__
+ txd++;
+ fi++;
+ } while ( ! ( TX_CMD_LAST & cmdsts ) );
+
+ { struct mbuf *m;
+ IF_DEQUEUE(&txq->txq_sentq, m);
+ m_freem(m);
+ }
+#endif
+#if 0
+ GE_DPRINTF(sc, ("([%d]<-%08lx.%08lx.%08lx.%08lx)",
+ txq->txq_lo,
+ ((unsigned long *)txd)[0], ((unsigned long *)txd)[1],
+ ((unsigned long *)txd)[2], ((unsigned long *)txd)[3]));
+#endif
+ GE_DPRINTF(sc, ("(%d)", fi));
+ txq->txq_fi = fi;
+ if ( txq->txq_fi >= GE_TXDESC_MAX)
+ txq->txq_fi -= GE_TXDESC_MAX;
+#ifndef __rtems__
+ txq->txq_inptr = gt32toh(txd->ed_bufptr) - txq->txq_buf_busaddr;
+ pktlen = (gt32toh(txd->ed_lencnt) >> 16) & 0xffff;
+ bus_dmamap_sync(sc->sc_dmat, txq->txq_buf_mem.gdm_map,
+ txq->txq_inptr, pktlen, BUS_DMASYNC_POSTWRITE);
+ txq->txq_inptr += roundup(pktlen, dcache_line_size);
+#endif
+
+ /* statistics */
+ ifp->if_opackets++;
+#ifdef __rtems__
+ /* FIXME: should we check errors on every fragment? */
+#endif
+ if (cmdsts & TX_STS_ES)
+ ifp->if_oerrors++;
+
+ /* txd->ed_bufptr = 0; */
+
+ txq->txq_nactive -= got;
+
+ GE_FUNC_EXIT(sc, "");
+
+ return got;
+}
+
+#ifndef __rtems__
+int
+gfe_tx_enqueue(struct gfe_softc *sc, enum gfe_txprio txprio)
+{
+#ifndef __rtems__
+ const int dcache_line_size = curcpu()->ci_ci.dcache_line_size;
+#else
+#ifndef PPC_CACHE_ALIGNMENT
+#error "Unknown cache alignment for your CPU"
+#endif
+ const int dcache_line_size = PPC_CACHE_ALIGNMENT;
+#endif
+ struct ifnet * const ifp = &sc->sc_ec.ec_if;
+ struct gfe_txqueue * const txq = &sc->sc_txq[txprio];
+ volatile struct gt_eth_desc * const txd = &txq->txq_descs[txq->txq_lo];
+ uint32_t intrmask = sc->sc_intrmask;
+ size_t buflen;
+ struct mbuf *m;
+
+ GE_FUNC_ENTER(sc, "gfe_tx_enqueue");
+
+ /*
+ * Anything in the pending queue to enqueue? if not, punt. Likewise
+ * if the txq is not yet created.
+ * otherwise grab its dmamap.
+ */
+ if (txq == NULL || (m = txq->txq_pendq.ifq_head) == NULL) {
+ GE_FUNC_EXIT(sc, "-");
+ return 0;
+ }
+
+ /*
+ * Have we [over]consumed our limit of descriptors?
+ * Do we have enough free descriptors?
+ */
+ if (GE_TXDESC_MAX == txq->txq_nactive + 2) {
+ if ( gfe_free_slots(sc, txq) <= 0 )
+ return 0;
+ }
+
+ buflen = roundup(m->m_pkthdr.len, dcache_line_size);
+
+ /*
+ * If this packet would wrap around the end of the buffer, reset back
+ * to the beginning.
+ */
+ if (txq->txq_outptr + buflen > GE_TXBUF_SIZE) {
+ txq->txq_ei_gapcount += GE_TXBUF_SIZE - txq->txq_outptr;
+ txq->txq_outptr = 0;
+ }
+
+ /*
+ * Make sure the output packet doesn't run over the beginning of
+ * what we've already given the GT.
+ */
+ if (txq->txq_nactive > 0 && txq->txq_outptr <= txq->txq_inptr &&
+ txq->txq_outptr + buflen > txq->txq_inptr) {
+ intrmask |= txq->txq_intrbits &
+ (ETH_IR_TxBufferHigh|ETH_IR_TxBufferLow);
+ if (sc->sc_intrmask != intrmask) {
+ sc->sc_intrmask = intrmask;
+ GE_WRITE(sc, EIMR, sc->sc_intrmask);
+ }
+ GE_FUNC_EXIT(sc, "#");
+ return 0;
+ }
+
+ /*
+ * The end-of-list descriptor we put on last time is the starting point
+ * for this packet. The GT is supposed to terminate list processing on
+ * a NULL nxtptr but that currently is broken so a CPU-owned descriptor
+ * must terminate the list.
+ */
+ intrmask = sc->sc_intrmask;
+
+ m_copydata(m, 0, m->m_pkthdr.len,
+ txq->txq_buf_mem.gdm_kva + txq->txq_outptr);
+ bus_dmamap_sync(sc->sc_dmat, txq->txq_buf_mem.gdm_map,
+ txq->txq_outptr, buflen, BUS_DMASYNC_PREWRITE);
+ txd->ed_bufptr = htogt32(txq->txq_buf_busaddr + txq->txq_outptr);
+ txd->ed_lencnt = htogt32(m->m_pkthdr.len << 16);
+ GE_TXDPRESYNC(sc, txq, txq->txq_lo);
+
+ /*
+ * Request a buffer interrupt every 2/3 of the way thru the transmit
+ * buffer.
+ */
+ txq->txq_ei_gapcount += buflen;
+ if (txq->txq_ei_gapcount > 2 * GE_TXBUF_SIZE / 3) {
+ txd->ed_cmdsts = htogt32(TX_CMD_FIRST|TX_CMD_LAST|TX_CMD_EI);
+ txq->txq_ei_gapcount = 0;
+ } else {
+ txd->ed_cmdsts = htogt32(TX_CMD_FIRST|TX_CMD_LAST);
+ }
+#if 0
+ GE_DPRINTF(sc, ("([%d]->%08lx.%08lx.%08lx.%08lx)", txq->txq_lo,
+ ((unsigned long *)txd)[0], ((unsigned long *)txd)[1],
+ ((unsigned long *)txd)[2], ((unsigned long *)txd)[3]));
+#endif
+ GE_TXDPRESYNC(sc, txq, txq->txq_lo);
+
+ txq->txq_outptr += buflen;
+ /*
+ * Tell the SDMA engine to "Fetch!"
+ */
+ GE_WRITE(sc, ESDCMR,
+ txq->txq_esdcmrbits & (ETH_ESDCMR_TXDH|ETH_ESDCMR_TXDL));
+
+ GE_DPRINTF(sc, ("(%d)", txq->txq_lo));
+
+ /*
+ * Update the last out appropriately.
+ */
+ txq->txq_nactive++;
+ if (++txq->txq_lo == GE_TXDESC_MAX)
+ txq->txq_lo = 0;
+
+ /*
+ * Move mbuf from the pending queue to the snd queue.
+ */
+ IF_DEQUEUE(&txq->txq_pendq, m);
+#if NBPFILTER > 0
+ if (ifp->if_bpf != NULL)
+ bpf_mtap(ifp->if_bpf, m);
+#endif
+ m_freem(m);
+ ifp->if_flags &= ~IFF_OACTIVE;
+
+ /*
+ * Since we have put an item into the packet queue, we now want
+ * an interrupt when the transmit queue finishes processing the
+ * list. But only update the mask if needs changing.
+ */
+ intrmask |= txq->txq_intrbits & (ETH_IR_TxEndHigh|ETH_IR_TxEndLow);
+ if (sc->sc_intrmask != intrmask) {
+ sc->sc_intrmask = intrmask;
+ GE_WRITE(sc, EIMR, sc->sc_intrmask);
+ }
+ if (ifp->if_timer == 0)
+ ifp->if_timer = 5;
+ GE_FUNC_EXIT(sc, "*");
+ return 1;
+}
+
+#else
+
+#ifdef __PPC__
+static inline void membarrier(void)
+{
+ asm volatile("sync":::"memory");
+}
+#else
+#error "memory synchronization for your CPU not implemented"
+#endif
+
+
+void
+gfe_assign_desc(volatile struct gt_eth_desc *const d, struct mbuf *m, uint32_t flags)
+{
+ d->ed_cmdsts = htogt32(flags | TX_CMD_GC | TX_CMD_P);
+ d->ed_bufptr = htogt32(mtod(m, uint32_t));
+ d->ed_lencnt = htogt32(m->m_len << 16);
+}
+
+int
+gfe_tx_enqueue(struct gfe_softc *sc, enum gfe_txprio txprio)
+{
+ struct ifnet * const ifp = &sc->sc_ec.ec_if;
+ struct gfe_txqueue * const txq = &sc->sc_txq[txprio];
+ volatile struct gt_eth_desc * const txd = &txq->txq_descs[txq->txq_lo];
+#define NEXT_TXD(d) ((d)+1 < &txq->txq_descs[GE_TXDESC_MAX] ? (d)+1 : txq->txq_descs)
+ volatile struct gt_eth_desc *l,*d;
+ uint32_t intrmask = sc->sc_intrmask;
+ struct mbuf *m_head,*m,*m1;
+ int avail, used;
+
+ GE_FUNC_ENTER(sc, "gfe_tx_enqueue");
+
+ /*
+ * Anything in the pending queue to enqueue? if not, punt. Likewise
+ * if the txq is not yet created.
+ * otherwise grab its dmamap.
+ */
+ if (txq == NULL || (m_head = txq->txq_pendq.ifq_head) == NULL) {
+ GE_FUNC_EXIT(sc, "-");
+ return 0;
+ }
+
+ /* find 1st mbuf with actual data; m_head is not NULL at this point */
+ for ( m1=m_head; 0 == m1->m_len; ) {
+ if ( ! (m1=m1->m_next) ) {
+ /* nothing to send */
+ IF_DEQUEUE(&txq->txq_pendq, m_head);
+ m_freem(m_head);
+ return 0;
+ }
+ }
+
+ avail = GE_TXDESC_MAX - 1 - txq->txq_nactive;
+
+ if ( avail < 1 && (avail += gfe_free_slots(sc, txq)) < 1 )
+ return 0;
+
+ avail--;
+
+ l = txd;
+ d = NEXT_TXD(txd);
+
+ for ( m=m1->m_next, used = 1; m; m=m->m_next ) {
+ if ( 0 == m->m_len )
+ continue; /* skip empty mbufs */
+
+ if ( avail < 1 && (avail += gfe_free_slots(sc, txq)) < 1 ) {
+ /* not enough descriptors; cleanup */
+ for ( l = NEXT_TXD(txd); l!=d; l = NEXT_TXD(l) ) {
+ l->ed_cmdsts = 0;
+ avail++;
+ }
+ avail++;
+ if ( used >= GE_TXDESC_MAX-1 )
+ panic("mbuf chain (#%i) longer than TX ring (#%i); configuration error!",
+ used, GE_TXDESC_MAX-1);
+ return 0;
+ }
+ used++;
+ avail--;
+
+ /* fill this slot */
+ gfe_assign_desc(d, m, TX_CMD_O);
+
+ bus_dmamap_sync(sc->sc_dmat, /* TODO */,
+ mtod(m, uint32_t), m->m_len, BUS_DMASYNC_PREWRITE);
+
+ l = d;
+ d = NEXT_TXD(d);
+
+ GE_TXDPRESYNC(sc, txq, l - txq->txq_descs);
+ }
+
+ /* fill first slot */
+ gfe_assign_desc(txd, m1, TX_CMD_F);
+
+ bus_dmamap_sync(sc->sc_dmat, /* TODO */,
+ mtod(m1, uint32_t), m1->m_len, BUS_DMASYNC_PREWRITE);
+
+ /* tag last slot; this covers where 1st = last */
+ l->ed_cmdsts |= htonl(TX_CMD_L | TX_CMD_EI);
+
+ GE_TXDPRESYNC(sc, txq, l - txq->txq_descs);
+
+ /*
+ * The end-of-list descriptor we put on last time is the starting point
+ * for this packet. The GT is supposed to terminate list processing on
+ * a NULL nxtptr but that currently is broken so a CPU-owned descriptor
+ * must terminate the list.
+ */
+ d = NEXT_TXD(l);
+
+ out_be32(&d->ed_cmdsts,0);
+
+ GE_TXDPRESYNC(sc, txq, d - txq->txq_descs);
+
+ membarrier();
+
+ /* turn over the whole chain by flipping the ownership of the first desc */
+ txd->ed_cmdsts |= htonl(TX_CMD_O);
+
+ GE_TXDPRESYNC(sc, txq, txq->txq_lo);
+
+
+ intrmask = sc->sc_intrmask;
+
+#if 0
+ GE_DPRINTF(sc, ("([%d]->%08lx.%08lx.%08lx.%08lx)", txq->txq_lo,
+ ((unsigned long *)txd)[0], ((unsigned long *)txd)[1],
+ ((unsigned long *)txd)[2], ((unsigned long *)txd)[3]));
+#endif
+
+ membarrier();
+
+ /*
+ * Tell the SDMA engine to "Fetch!"
+ */
+ GE_WRITE(sc, ESDCMR,
+ txq->txq_esdcmrbits & (ETH_ESDCMR_TXDH|ETH_ESDCMR_TXDL));
+
+ GE_DPRINTF(sc, ("(%d)", txq->txq_lo));
+
+ /*
+ * Update the last out appropriately.
+ */
+ txq->txq_nactive += used;
+ txq->txq_lo += used;
+ if ( txq->txq_lo >= GE_TXDESC_MAX )
+ txq->txq_lo -= GE_TXDESC_MAX;
+
+ /*
+ * Move mbuf from the pending queue to the snd queue.
+ */
+ IF_DEQUEUE(&txq->txq_pendq, m_head);
+
+ IF_ENQUEUE(&txq->txq_sentq, m_head);
+
+#if NBPFILTER > 0
+ if (ifp->if_bpf != NULL)
+ bpf_mtap(ifp->if_bpf, m_head);
+#endif
+ ifp->if_flags &= ~IFF_OACTIVE;
+
+ /*
+ * Since we have put an item into the packet queue, we now want
+ * an interrupt when the transmit queue finishes processing the
+ * list. But only update the mask if needs changing.
+ */
+ intrmask |= txq->txq_intrbits & (ETH_IR_TxEndHigh|ETH_IR_TxEndLow);
+ if (sc->sc_intrmask != intrmask) {
+ sc->sc_intrmask = intrmask;
+ GE_WRITE(sc, EIMR, sc->sc_intrmask);
+ }
+ if (ifp->if_timer == 0)
+ ifp->if_timer = 5;
+ GE_FUNC_EXIT(sc, "*");
+ return 1;
+}
+#endif
+
+uint32_t
+gfe_tx_done(struct gfe_softc *sc, enum gfe_txprio txprio, uint32_t intrmask)
+{
+ struct gfe_txqueue * const txq = &sc->sc_txq[txprio];
+ struct ifnet * const ifp = &sc->sc_ec.ec_if;
+
+ GE_FUNC_ENTER(sc, "gfe_tx_done");
+
+ if (txq == NULL) {
+ GE_FUNC_EXIT(sc, "");
+ return intrmask;
+ }
+
+ while (txq->txq_nactive > 0) {
+ if ( gfe_free_slots(sc, txq) < 0 )
+ return intrmask;
+ ifp->if_timer = 5;
+ }
+ if (txq->txq_nactive != 0)
+ panic("%s: transmit fifo%d empty but active count (%d) not 0!",
+ sc->sc_dev.dv_xname, txprio, txq->txq_nactive);
+ ifp->if_timer = 0;
+ intrmask &= ~(txq->txq_intrbits & (ETH_IR_TxEndHigh|ETH_IR_TxEndLow));
+ intrmask &= ~(txq->txq_intrbits & (ETH_IR_TxBufferHigh|ETH_IR_TxBufferLow));
+ GE_FUNC_EXIT(sc, "");
+ return intrmask;
+}
+
+int
+gfe_tx_txqalloc(struct gfe_softc *sc, enum gfe_txprio txprio)
+{
+ struct gfe_txqueue * const txq = &sc->sc_txq[txprio];
+ int error;
+
+ GE_FUNC_ENTER(sc, "gfe_tx_txqalloc");
+
+ error = gfe_dmamem_alloc(sc, &txq->txq_desc_mem, 1,
+ GE_TXDESC_MEMSIZE, BUS_DMA_NOCACHE);
+ if (error) {
+ GE_FUNC_EXIT(sc, "");
+ return error;
+ }
+#ifndef __rtems__
+ error = gfe_dmamem_alloc(sc, &txq->txq_buf_mem, 1, GE_TXBUF_SIZE, 0);
+ if (error) {
+ gfe_dmamem_free(sc, &txq->txq_desc_mem);
+ GE_FUNC_EXIT(sc, "");
+ return error;
+ }
+#endif
+ GE_FUNC_EXIT(sc, "");
+ return 0;
+}
+
+int
+gfe_tx_start(struct gfe_softc *sc, enum gfe_txprio txprio)
+{
+ struct gfe_txqueue * const txq = &sc->sc_txq[txprio];
+ volatile struct gt_eth_desc *txd;
+ unsigned int i;
+ bus_addr_t addr;
+
+ GE_FUNC_ENTER(sc, "gfe_tx_start");
+
+ sc->sc_intrmask &= ~(ETH_IR_TxEndHigh|ETH_IR_TxBufferHigh|
+ ETH_IR_TxEndLow |ETH_IR_TxBufferLow);
+
+ if (sc->sc_flags & GE_NOFREE) {
+ KASSERT(txq->txq_desc_mem.gdm_kva != NULL);
+#ifndef __rtems__
+ KASSERT(txq->txq_buf_mem.gdm_kva != NULL);
+#endif
+ } else {
+ int error = gfe_tx_txqalloc(sc, txprio);
+ if (error) {
+ GE_FUNC_EXIT(sc, "!");
+ return error;
+ }
+ }
+
+ txq->txq_descs =
+ (volatile struct gt_eth_desc *) txq->txq_desc_mem.gdm_kva;
+ txq->txq_desc_busaddr = txq->txq_desc_mem.gdm_map->dm_segs[0].ds_addr;
+#ifndef __rtems__
+ txq->txq_buf_busaddr = txq->txq_buf_mem.gdm_map->dm_segs[0].ds_addr;
+#else
+ /* never used */
+ memset(&txq->txq_pendq,0,sizeof(txq->txq_pendq));
+ memset(&txq->txq_sentq,0,sizeof(txq->txq_sentq));
+ txq->txq_sentq.ifq_maxlen = 100000;
+#endif
+
+ txq->txq_pendq.ifq_maxlen = 10;
+#ifndef __rtems__
+ txq->txq_ei_gapcount = 0;
+#endif
+ txq->txq_nactive = 0;
+ txq->txq_fi = 0;
+ txq->txq_lo = 0;
+#ifndef __rtems__
+ txq->txq_ei_gapcount = 0;
+ txq->txq_inptr = GE_TXBUF_SIZE;
+ txq->txq_outptr = 0;
+#endif
+ for (i = 0, txd = txq->txq_descs,
+ addr = txq->txq_desc_busaddr + sizeof(*txd);
+ i < GE_TXDESC_MAX - 1;
+ i++, txd++, addr += sizeof(*txd)) {
+ /*
+ * update the nxtptr to point to the next txd.
+ */
+ txd->ed_cmdsts = 0;
+ txd->ed_nxtptr = htogt32(addr);
+ }
+ txq->txq_descs[GE_TXDESC_MAX-1].ed_nxtptr =
+ htogt32(txq->txq_desc_busaddr);
+ bus_dmamap_sync(sc->sc_dmat, txq->txq_desc_mem.gdm_map, 0,
+ GE_TXDESC_MEMSIZE, BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
+
+ switch (txprio) {
+ case GE_TXPRIO_HI:
+ txq->txq_intrbits = ETH_IR_TxEndHigh|ETH_IR_TxBufferHigh;
+ txq->txq_esdcmrbits = ETH_ESDCMR_TXDH;
+ txq->txq_epsrbits = ETH_EPSR_TxHigh;
+ txq->txq_ectdp = ETH_ECTDP1(sc->sc_macno);
+ GE_WRITE(sc, ECTDP1, txq->txq_desc_busaddr);
+ break;
+
+ case GE_TXPRIO_LO:
+ txq->txq_intrbits = ETH_IR_TxEndLow|ETH_IR_TxBufferLow;
+ txq->txq_esdcmrbits = ETH_ESDCMR_TXDL;
+ txq->txq_epsrbits = ETH_EPSR_TxLow;
+ txq->txq_ectdp = ETH_ECTDP0(sc->sc_macno);
+ GE_WRITE(sc, ECTDP0, txq->txq_desc_busaddr);
+ break;
+
+ case GE_TXPRIO_NONE:
+ break;
+ }
+#if 0
+ GE_DPRINTF(sc, ("(ectdp=%#x", txq->txq_ectdp));
+ gt_write(sc->sc_dev.dv_parent, txq->txq_ectdp, txq->txq_desc_busaddr);
+ GE_DPRINTF(sc, (")"));
+#endif
+
+ /*
+ * If we are restarting, there may be packets in the pending queue
+ * waiting to be enqueued. Try enqueuing packets from both priority
+ * queues until the pending queue is empty or there no room for them
+ * on the device.
+ */
+ while (gfe_tx_enqueue(sc, txprio))
+ continue;
+
+ GE_FUNC_EXIT(sc, "");
+ return 0;
+}
+
+void
+gfe_tx_cleanup(struct gfe_softc *sc, enum gfe_txprio txprio, int flush)
+{
+ struct gfe_txqueue * const txq = &sc->sc_txq[txprio];
+
+ GE_FUNC_ENTER(sc, "gfe_tx_cleanup");
+ if (txq == NULL) {
+ GE_FUNC_EXIT(sc, "");
+ return;
+ }
+
+ if (!flush) {
+ GE_FUNC_EXIT(sc, "");
+ return;
+ }
+
+#ifdef __rtems__
+ /* reclaim mbufs that were never sent */
+ {
+ struct mbuf *m;
+ while ( txq->txq_sentq.ifq_head ) {
+ IF_DEQUEUE(&txq->txq_sentq, m);
+ m_freem(m);
+ }
+ }
+#endif
+
+ if ((sc->sc_flags & GE_NOFREE) == 0) {
+ gfe_dmamem_free(sc, &txq->txq_desc_mem);
+#ifndef __rtems__
+ gfe_dmamem_free(sc, &txq->txq_buf_mem);
+#endif
+ }
+ GE_FUNC_EXIT(sc, "-F");
+}
+
+void
+gfe_tx_stop(struct gfe_softc *sc, enum gfe_whack_op op)
+{
+ GE_FUNC_ENTER(sc, "gfe_tx_stop");
+
+ GE_WRITE(sc, ESDCMR, ETH_ESDCMR_STDH|ETH_ESDCMR_STDL);
+
+ sc->sc_intrmask = gfe_tx_done(sc, GE_TXPRIO_HI, sc->sc_intrmask);
+ sc->sc_intrmask = gfe_tx_done(sc, GE_TXPRIO_LO, sc->sc_intrmask);
+ sc->sc_intrmask &= ~(ETH_IR_TxEndHigh|ETH_IR_TxBufferHigh|
+ ETH_IR_TxEndLow |ETH_IR_TxBufferLow);
+
+ gfe_tx_cleanup(sc, GE_TXPRIO_HI, op == GE_WHACK_STOP);
+ gfe_tx_cleanup(sc, GE_TXPRIO_LO, op == GE_WHACK_STOP);
+
+ sc->sc_ec.ec_if.if_timer = 0;
+ GE_FUNC_EXIT(sc, "");
+}
+
+int
+gfe_intr(void *arg)
+{
+ struct gfe_softc * const sc = arg;
+ uint32_t cause;
+ uint32_t intrmask = sc->sc_intrmask;
+ int claim = 0;
+ int cnt;
+
+ GE_FUNC_ENTER(sc, "gfe_intr");
+
+ for (cnt = 0; cnt < 4; cnt++) {
+ if (sc->sc_intrmask != intrmask) {
+ sc->sc_intrmask = intrmask;
+ GE_WRITE(sc, EIMR, sc->sc_intrmask);
+ }
+ cause = GE_READ(sc, EICR);
+ cause &= sc->sc_intrmask;
+ GE_DPRINTF(sc, (".%#" PRIx32, cause));
+ if (cause == 0)
+ break;
+
+ claim = 1;
+
+ GE_WRITE(sc, EICR, ~cause);
+#ifndef GE_NORX
+ if (cause & (ETH_IR_RxBuffer|ETH_IR_RxError))
+ intrmask = gfe_rx_process(sc, cause, intrmask);
+#endif
+
+#ifndef GE_NOTX
+ if (cause & (ETH_IR_TxBufferHigh|ETH_IR_TxEndHigh))
+ intrmask = gfe_tx_done(sc, GE_TXPRIO_HI, intrmask);
+ if (cause & (ETH_IR_TxBufferLow|ETH_IR_TxEndLow))
+ intrmask = gfe_tx_done(sc, GE_TXPRIO_LO, intrmask);
+#endif
+ if (cause & ETH_IR_MIIPhySTC) {
+ sc->sc_flags |= GE_PHYSTSCHG;
+ /* intrmask &= ~ETH_IR_MIIPhySTC; */
+ }
+ }
+
+ while (gfe_tx_enqueue(sc, GE_TXPRIO_HI))
+ continue;
+ while (gfe_tx_enqueue(sc, GE_TXPRIO_LO))
+ continue;
+
+ GE_FUNC_EXIT(sc, "");
+ return claim;
+}
+
+#ifndef __rtems__
+int
+gfe_mii_mediachange (struct ifnet *ifp)
+{
+ struct gfe_softc *sc = ifp->if_softc;
+
+ if (ifp->if_flags & IFF_UP)
+ mii_mediachg(&sc->sc_mii);
+
+ return (0);
+}
+void
+gfe_mii_mediastatus (struct ifnet *ifp, struct ifmediareq *ifmr)
+{
+ struct gfe_softc *sc = ifp->if_softc;
+
+ if (sc->sc_flags & GE_PHYSTSCHG) {
+ sc->sc_flags &= ~GE_PHYSTSCHG;
+ mii_pollstat(&sc->sc_mii);
+ }
+ ifmr->ifm_status = sc->sc_mii.mii_media_status;
+ ifmr->ifm_active = sc->sc_mii.mii_media_active;
+}
+
+int
+gfe_mii_read (struct device *self, int phy, int reg)
+{
+ return gt_mii_read(self, self->dv_parent, phy, reg);
+}
+
+void
+gfe_mii_write (struct device *self, int phy, int reg, int value)
+{
+ gt_mii_write(self, self->dv_parent, phy, reg, value);
+}
+
+void
+gfe_mii_statchg (struct device *self)
+{
+ /* struct gfe_softc *sc = (struct gfe_softc *) self; */
+ /* do nothing? */
+}
+
+#else
+int
+gfe_mii_read(int phy, void *arg, unsigned reg, uint32_t *pval)
+{
+ struct gfe_softc *sc = arg;
+ uint32_t data;
+ int count = 10000;
+
+ if ( 0 != phy )
+ return -1; /* invalid index */
+
+ phy = sc->sc_phyaddr;
+
+ do {
+ DELAY(10);
+ data = GT_READ(sc, ETH_ESMIR);
+ } while ((data & ETH_ESMIR_Busy) && count-- > 0);
+
+ if (count == 0) {
+ fprintf(stderr,"%s: mii read for phy %d reg %d busied out\n",
+ sc->sc_dev.dv_xname, phy, reg);
+ *pval = ETH_ESMIR_Value_GET(data);
+ return -1;
+ }
+
+ GT_WRITE(sc, ETH_ESMIR, ETH_ESMIR_READ(phy, reg));
+
+ count = 10000;
+ do {
+ DELAY(10);
+ data = GT_READ(sc, ETH_ESMIR);
+ } while ((data & ETH_ESMIR_ReadValid) == 0 && count-- > 0);
+
+ if (count == 0)
+ printf("%s: mii read for phy %d reg %d timed out\n",
+ sc->sc_dev.dv_xname, phy, reg);
+#if defined(GTMIIDEBUG)
+ printf("%s: mii_read(%d, %d): %#x data %#x\n",
+ sc->sc_dev.dv_xname, phy, reg,
+ data, ETH_ESMIR_Value_GET(data));
+#endif
+ *pval = ETH_ESMIR_Value_GET(data);
+ return 0;
+}
+
+int
+gfe_mii_write(int phy, void *arg, unsigned reg, uint32_t value)
+{
+ struct gfe_softc *sc = arg;
+ uint32_t data;
+ int count = 10000;
+
+ if ( 0 != phy )
+ return -1; /* invalid index */
+
+ phy = sc->sc_phyaddr;
+
+ do {
+ DELAY(10);
+ data = GT_READ(sc, ETH_ESMIR);
+ } while ((data & ETH_ESMIR_Busy) && count-- > 0);
+
+ if (count == 0) {
+ fprintf(stderr, "%s: mii write for phy %d reg %d busied out (busy)\n",
+ sc->sc_dev.dv_xname, phy, reg);
+ return -1;
+ }
+
+ GT_WRITE(sc, ETH_ESMIR,
+ ETH_ESMIR_WRITE(phy, reg, value));
+
+ count = 10000;
+ do {
+ DELAY(10);
+ data = GT_READ(sc, ETH_ESMIR);
+ } while ((data & ETH_ESMIR_Busy) && count-- > 0);
+
+ if (count == 0)
+ printf("%s: mii write for phy %d reg %d timed out\n",
+ sc->sc_dev.dv_xname, phy, reg);
+#if defined(GTMIIDEBUG)
+ printf("%s: mii_write(%d, %d, %#x)\n",
+ sc->sc_dev.dv_xname, phy, reg, value);
+#endif
+ return 0;
+}
+
+#endif
+int
+gfe_whack(struct gfe_softc *sc, enum gfe_whack_op op)
+{
+ int error = 0;
+ GE_FUNC_ENTER(sc, "gfe_whack");
+
+ switch (op) {
+ case GE_WHACK_RESTART:
+#ifndef GE_NOTX
+ gfe_tx_stop(sc, op);
+#endif
+ /* sc->sc_ec.ec_if.if_flags &= ~IFF_RUNNING; */
+ /* FALLTHROUGH */
+ case GE_WHACK_START:
+#ifndef GE_NOHASH
+ if (error == 0 && sc->sc_hashtable == NULL) {
+ error = gfe_hash_alloc(sc);
+ if (error)
+ break;
+ }
+ if (op != GE_WHACK_RESTART)
+ gfe_hash_fill(sc);
+#endif
+#ifndef GE_NORX
+ if (op != GE_WHACK_RESTART) {
+ error = gfe_rx_prime(sc);
+ if (error)
+ break;
+ }
+#endif
+#ifndef GE_NOTX
+ error = gfe_tx_start(sc, GE_TXPRIO_HI);
+ if (error)
+ break;
+#endif
+ sc->sc_ec.ec_if.if_flags |= IFF_RUNNING;
+ GE_WRITE(sc, EPCR, sc->sc_pcr | ETH_EPCR_EN);
+ GE_WRITE(sc, EPCXR, sc->sc_pcxr);
+ GE_WRITE(sc, EICR, 0);
+ GE_WRITE(sc, EIMR, sc->sc_intrmask);
+#ifndef GE_NOHASH
+ GE_WRITE(sc, EHTPR, sc->sc_hash_mem.gdm_map->dm_segs->ds_addr);
+#endif
+#ifndef GE_NORX
+ GE_WRITE(sc, ESDCMR, ETH_ESDCMR_ERD);
+ sc->sc_flags |= GE_RXACTIVE;
+#endif
+ /* FALLTHROUGH */
+ case GE_WHACK_CHANGE:
+ GE_DPRINTF(sc, ("(pcr=%#x,imr=%#x)",
+ GE_READ(sc, EPCR), GE_READ(sc, EIMR)));
+ GE_WRITE(sc, EPCR, sc->sc_pcr | ETH_EPCR_EN);
+ GE_WRITE(sc, EIMR, sc->sc_intrmask);
+ gfe_ifstart(&sc->sc_ec.ec_if);
+ GE_DPRINTF(sc, ("(ectdp0=%#x, ectdp1=%#x)",
+ GE_READ(sc, ECTDP0), GE_READ(sc, ECTDP1)));
+ GE_FUNC_EXIT(sc, "");
+ return error;
+ case GE_WHACK_STOP:
+ break;
+ }
+
+#ifdef GE_DEBUG
+ if (error)
+ GE_DPRINTF(sc, (" failed: %d\n", error));
+#endif
+ GE_WRITE(sc, EPCR, sc->sc_pcr);
+ GE_WRITE(sc, EIMR, 0);
+ sc->sc_ec.ec_if.if_flags &= ~IFF_RUNNING;
+#ifndef GE_NOTX
+ gfe_tx_stop(sc, GE_WHACK_STOP);
+#endif
+#ifndef GE_NORX
+ gfe_rx_stop(sc, GE_WHACK_STOP);
+#endif
+#ifndef GE_NOHASH
+ if ((sc->sc_flags & GE_NOFREE) == 0) {
+ gfe_dmamem_free(sc, &sc->sc_hash_mem);
+ sc->sc_hashtable = NULL;
+ }
+#endif
+
+ GE_FUNC_EXIT(sc, "");
+ return error;
+}
+
+int
+gfe_hash_compute(struct gfe_softc *sc, const uint8_t eaddr[ETHER_ADDR_LEN])
+{
+ uint32_t w0, add0, add1;
+ uint32_t result;
+#ifdef __rtems__
+ SPRINTFVARDECL;
+#endif
+
+ GE_FUNC_ENTER(sc, "gfe_hash_compute");
+ add0 = ((uint32_t) eaddr[5] << 0) |
+ ((uint32_t) eaddr[4] << 8) |
+ ((uint32_t) eaddr[3] << 16);
+
+ add0 = ((add0 & 0x00f0f0f0) >> 4) | ((add0 & 0x000f0f0f) << 4);
+ add0 = ((add0 & 0x00cccccc) >> 2) | ((add0 & 0x00333333) << 2);
+ add0 = ((add0 & 0x00aaaaaa) >> 1) | ((add0 & 0x00555555) << 1);
+
+ add1 = ((uint32_t) eaddr[2] << 0) |
+ ((uint32_t) eaddr[1] << 8) |
+ ((uint32_t) eaddr[0] << 16);
+
+ add1 = ((add1 & 0x00f0f0f0) >> 4) | ((add1 & 0x000f0f0f) << 4);
+ add1 = ((add1 & 0x00cccccc) >> 2) | ((add1 & 0x00333333) << 2);
+ add1 = ((add1 & 0x00aaaaaa) >> 1) | ((add1 & 0x00555555) << 1);
+
+ GE_DPRINTF(sc, ("%s=", ether_sprintf(eaddr)));
+ /*
+ * hashResult is the 15 bits Hash entry address.
+ * ethernetADD is a 48 bit number, which is derived from the Ethernet
+ * MAC address, by nibble swapping in every byte (i.e MAC address
+ * of 0x123456789abc translates to ethernetADD of 0x21436587a9cb).
+ */
+
+ if ((sc->sc_pcr & ETH_EPCR_HM) == 0) {
+ /*
+ * hashResult[14:0] = hashFunc0(ethernetADD[47:0])
+ *
+ * hashFunc0 calculates the hashResult in the following manner:
+ * hashResult[ 8:0] = ethernetADD[14:8,1,0]
+ * XOR ethernetADD[23:15] XOR ethernetADD[32:24]
+ */
+ result = (add0 & 3) | ((add0 >> 6) & ~3);
+ result ^= (add0 >> 15) ^ (add1 >> 0);
+ result &= 0x1ff;
+ /*
+ * hashResult[14:9] = ethernetADD[7:2]
+ */
+ result |= (add0 & ~3) << 7; /* excess bits will be masked */
+ GE_DPRINTF(sc, ("0(%#"PRIx32")", result & 0x7fff));
+ } else {
+#define TRIBITFLIP 073516240 /* yes its in octal */
+ /*
+ * hashResult[14:0] = hashFunc1(ethernetADD[47:0])
+ *
+ * hashFunc1 calculates the hashResult in the following manner:
+ * hashResult[08:00] = ethernetADD[06:14]
+ * XOR ethernetADD[15:23] XOR ethernetADD[24:32]
+ */
+ w0 = ((add0 >> 6) ^ (add0 >> 15) ^ (add1)) & 0x1ff;
+ /*
+ * Now bitswap those 9 bits
+ */
+ result = 0;
+ result |= ((TRIBITFLIP >> (((w0 >> 0) & 7) * 3)) & 7) << 6;
+ result |= ((TRIBITFLIP >> (((w0 >> 3) & 7) * 3)) & 7) << 3;
+ result |= ((TRIBITFLIP >> (((w0 >> 6) & 7) * 3)) & 7) << 0;
+
+ /*
+ * hashResult[14:09] = ethernetADD[00:05]
+ */
+ result |= ((TRIBITFLIP >> (((add0 >> 0) & 7) * 3)) & 7) << 12;
+ result |= ((TRIBITFLIP >> (((add0 >> 3) & 7) * 3)) & 7) << 9;
+ GE_DPRINTF(sc, ("1(%#"PRIx32")", result));
+ }
+ GE_FUNC_EXIT(sc, "");
+ return result & ((sc->sc_pcr & ETH_EPCR_HS_512) ? 0x7ff : 0x7fff);
+}
+
+int
+gfe_hash_entry_op(struct gfe_softc *sc, enum gfe_hash_op op,
+ enum gfe_rxprio prio, const uint8_t eaddr[ETHER_ADDR_LEN])
+{
+ uint64_t he;
+ uint64_t *maybe_he_p = NULL;
+ int limit;
+ int hash;
+ int maybe_hash = 0;
+
+ GE_FUNC_ENTER(sc, "gfe_hash_entry_op");
+
+ hash = gfe_hash_compute(sc, eaddr);
+
+ if (sc->sc_hashtable == NULL) {
+ panic("%s:%d: hashtable == NULL!", sc->sc_dev.dv_xname,
+ __LINE__);
+ }
+
+ /*
+ * Assume we are going to insert so create the hash entry we
+ * are going to insert. We also use it to match entries we
+ * will be removing.
+ */
+ he = ((uint64_t) eaddr[5] << 43) |
+ ((uint64_t) eaddr[4] << 35) |
+ ((uint64_t) eaddr[3] << 27) |
+ ((uint64_t) eaddr[2] << 19) |
+ ((uint64_t) eaddr[1] << 11) |
+ ((uint64_t) eaddr[0] << 3) |
+ HSH_PRIO_INS(prio) | HSH_V | HSH_R;
+
+ /*
+ * The GT will search upto 12 entries for a hit, so we must mimic that.
+ */
+ hash &= sc->sc_hashmask / sizeof(he);
+ for (limit = HSH_LIMIT; limit > 0 ; --limit) {
+ /*
+ * Does the GT wrap at the end, stop at the, or overrun the
+ * end? Assume it wraps for now. Stash a copy of the
+ * current hash entry.
+ */
+ uint64_t *he_p = &sc->sc_hashtable[hash];
+ uint64_t thishe = *he_p;
+
+ /*
+ * If the hash entry isn't valid, that break the chain. And
+ * this entry a good candidate for reuse.
+ */
+ if ((thishe & HSH_V) == 0) {
+ maybe_he_p = he_p;
+ break;
+ }
+
+ /*
+ * If the hash entry has the same address we are looking for
+ * then ... if we are removing and the skip bit is set, its
+ * already been removed. if are adding and the skip bit is
+ * clear, then its already added. In either return EBUSY
+ * indicating the op has already been done. Otherwise flip
+ * the skip bit and return 0.
+ */
+ if (((he ^ thishe) & HSH_ADDR_MASK) == 0) {
+ if (((op == GE_HASH_REMOVE) && (thishe & HSH_S)) ||
+ ((op == GE_HASH_ADD) && (thishe & HSH_S) == 0))
+ return EBUSY;
+ *he_p = thishe ^ HSH_S;
+ bus_dmamap_sync(sc->sc_dmat, sc->sc_hash_mem.gdm_map,
+ hash * sizeof(he), sizeof(he),
+ BUS_DMASYNC_PREWRITE);
+ GE_FUNC_EXIT(sc, "^");
+ return 0;
+ }
+
+ /*
+ * If we haven't found a slot for the entry and this entry
+ * is currently being skipped, return this entry.
+ */
+ if (maybe_he_p == NULL && (thishe & HSH_S)) {
+ maybe_he_p = he_p;
+ maybe_hash = hash;
+ }
+
+ hash = (hash + 1) & (sc->sc_hashmask / sizeof(he));
+ }
+
+ /*
+ * If we got here, then there was no entry to remove.
+ */
+ if (op == GE_HASH_REMOVE) {
+ GE_FUNC_EXIT(sc, "?");
+ return ENOENT;
+ }
+
+ /*
+ * If we couldn't find a slot, return an error.
+ */
+ if (maybe_he_p == NULL) {
+ GE_FUNC_EXIT(sc, "!");
+ return ENOSPC;
+ }
+
+ /* Update the entry.
+ */
+ *maybe_he_p = he;
+ bus_dmamap_sync(sc->sc_dmat, sc->sc_hash_mem.gdm_map,
+ maybe_hash * sizeof(he), sizeof(he), BUS_DMASYNC_PREWRITE);
+ GE_FUNC_EXIT(sc, "+");
+ return 0;
+}
+
+#ifndef __rtems__
+int
+gfe_hash_multichg(struct ethercom *ec, const struct ether_multi *enm, u_long cmd)
+{
+ struct gfe_softc * const sc = ec->ec_if.if_softc;
+ int error;
+ enum gfe_hash_op op;
+ enum gfe_rxprio prio;
+#ifdef __rtems__
+ SPRINTFVARDECL;
+#endif
+
+ GE_FUNC_ENTER(sc, "hash_multichg");
+ /*
+ * Is this a wildcard entry? If so and its being removed, recompute.
+ */
+ if (memcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN) != 0) {
+ if (cmd == SIOCDELMULTI) {
+ GE_FUNC_EXIT(sc, "");
+ return ENETRESET;
+ }
+
+ /*
+ * Switch in
+ */
+ sc->sc_flags |= GE_ALLMULTI;
+ if ((sc->sc_pcr & ETH_EPCR_PM) == 0) {
+ sc->sc_pcr |= ETH_EPCR_PM;
+ GE_WRITE(sc, EPCR, sc->sc_pcr);
+ GE_FUNC_EXIT(sc, "");
+ return 0;
+ }
+ GE_FUNC_EXIT(sc, "");
+ return ENETRESET;
+ }
+
+ prio = GE_RXPRIO_MEDLO;
+ op = (cmd == SIOCDELMULTI ? GE_HASH_REMOVE : GE_HASH_ADD);
+
+ if (sc->sc_hashtable == NULL) {
+ GE_FUNC_EXIT(sc, "");
+ return 0;
+ }
+
+ error = gfe_hash_entry_op(sc, op, prio, enm->enm_addrlo);
+ if (error == EBUSY) {
+ printf("%s: multichg: tried to %s %s again\n",
+ sc->sc_dev.dv_xname,
+ cmd == SIOCDELMULTI ? "remove" : "add",
+ ether_sprintf(enm->enm_addrlo));
+ GE_FUNC_EXIT(sc, "");
+ return 0;
+ }
+
+ if (error == ENOENT) {
+ printf("%s: multichg: failed to remove %s: not in table\n",
+ sc->sc_dev.dv_xname,
+ ether_sprintf(enm->enm_addrlo));
+ GE_FUNC_EXIT(sc, "");
+ return 0;
+ }
+
+ if (error == ENOSPC) {
+ printf("%s: multichg: failed to add %s: no space; regenerating table\n",
+ sc->sc_dev.dv_xname,
+ ether_sprintf(enm->enm_addrlo));
+ GE_FUNC_EXIT(sc, "");
+ return ENETRESET;
+ }
+ GE_DPRINTF(sc, ("%s: multichg: %s: %s succeeded\n",
+ sc->sc_dev.dv_xname,
+ cmd == SIOCDELMULTI ? "remove" : "add",
+ ether_sprintf(enm->enm_addrlo)));
+ GE_FUNC_EXIT(sc, "");
+ return 0;
+}
+#endif
+
+int
+gfe_hash_fill(struct gfe_softc *sc)
+{
+ struct ether_multistep step;
+ struct ether_multi *enm;
+ int error;
+
+ GE_FUNC_ENTER(sc, "gfe_hash_fill");
+
+#ifndef __rtems__
+ error = gfe_hash_entry_op(sc, GE_HASH_ADD, GE_RXPRIO_HI,
+ LLADDR(sc->sc_ec.ec_if.if_sadl));
+#else
+ error = gfe_hash_entry_op(sc, GE_HASH_ADD, GE_RXPRIO_HI, sc->sc_ec.ac_enaddr);
+#endif
+ if (error) {
+ GE_FUNC_EXIT(sc, "!");
+ return error;
+ }
+
+ sc->sc_flags &= ~GE_ALLMULTI;
+ if ((sc->sc_ec.ec_if.if_flags & IFF_PROMISC) == 0)
+ sc->sc_pcr &= ~ETH_EPCR_PM;
+ else
+ sc->sc_pcr |= ETH_EPCR_PM;
+ ETHER_FIRST_MULTI(step, &sc->sc_ec, enm);
+ while (enm != NULL) {
+ if (memcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) {
+ sc->sc_flags |= GE_ALLMULTI;
+ sc->sc_pcr |= ETH_EPCR_PM;
+ } else {
+ error = gfe_hash_entry_op(sc, GE_HASH_ADD,
+ GE_RXPRIO_MEDLO, enm->enm_addrlo);
+ if (error == ENOSPC)
+ break;
+ }
+ ETHER_NEXT_MULTI(step, enm);
+ }
+
+ GE_FUNC_EXIT(sc, "");
+ return error;
+}
+
+int
+gfe_hash_alloc(struct gfe_softc *sc)
+{
+ int error;
+ GE_FUNC_ENTER(sc, "gfe_hash_alloc");
+ sc->sc_hashmask = (sc->sc_pcr & ETH_EPCR_HS_512 ? 16 : 256)*1024 - 1;
+ error = gfe_dmamem_alloc(sc, &sc->sc_hash_mem, 1, sc->sc_hashmask + 1,
+ BUS_DMA_NOCACHE);
+ if (error) {
+ printf("%s: failed to allocate %d bytes for hash table: %d\n",
+ sc->sc_dev.dv_xname, sc->sc_hashmask + 1, error);
+ GE_FUNC_EXIT(sc, "");
+ return error;
+ }
+ sc->sc_hashtable = (uint64_t *) sc->sc_hash_mem.gdm_kva;
+ memset(sc->sc_hashtable, 0, sc->sc_hashmask + 1);
+ bus_dmamap_sync(sc->sc_dmat, sc->sc_hash_mem.gdm_map,
+ 0, sc->sc_hashmask + 1, BUS_DMASYNC_PREWRITE);
+ GE_FUNC_EXIT(sc, "");
+ return 0;
+}
diff --git a/c/src/lib/libbsp/powerpc/beatnik/network/if_gfe/if_gfe_pub.h b/c/src/lib/libbsp/powerpc/beatnik/network/if_gfe/if_gfe_pub.h
new file mode 100644
index 0000000000..8988f88a5c
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/beatnik/network/if_gfe/if_gfe_pub.h
@@ -0,0 +1,31 @@
+/* $Id$ */
+#ifndef RTEMS_BSDNET_IF_GFE_PUBLIC_SYMBOLS_H
+#define RTEMS_BSDNET_IF_GFE_PUBLIC_SYMBOLS_H
+
+#include <rtems.h>
+#include <rtems/rtems_bsdnet.h>
+#include <bsp/early_enet_link_status.h>
+#include <net/ethernet.h>
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+extern int
+rtems_gfe_attach(struct rtems_bsdnet_ifconfig *, int);
+
+
+/* enet_addr must be 6 bytes long */
+int
+rtems_gfe_setup(int unit, char *enet_addr, uint32_t base_addr);
+
+extern rtems_bsdnet_early_link_check_ops
+rtems_gfe_early_link_check_ops;
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif
+
+
diff --git a/c/src/lib/libbsp/powerpc/beatnik/network/if_gfe/if_gfe_rtems.c b/c/src/lib/libbsp/powerpc/beatnik/network/if_gfe/if_gfe_rtems.c
new file mode 100644
index 0000000000..069e0d9a89
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/beatnik/network/if_gfe/if_gfe_rtems.c
@@ -0,0 +1,130 @@
+/* $Id$ */
+
+/* Author: T. Straumann <strauman@slac.stanford.edu>; see ../../LICENSE */
+#include "rtemscompat.h"
+#include "gtethreg.h"
+
+#include <bsp/early_enet_link_status.h>
+#include <bsp/if_gfe_pub.h>
+#include <bsp/irq.h>
+
+/* from if_gfe.c */
+#define GE_READ(sc, reg) \
+ bus_space_read_4((sc)->sc_gt_memt, (sc)->sc_memh, ETH__ ## reg)
+#define GE_WRITE(sc, reg, v) \
+ bus_space_write_4((sc)->sc_gt_memt, (sc)->sc_memh, ETH__ ## reg, (v))
+
+#define GT_READ(sc, reg) \
+ bus_space_read_4((sc)->sc_gt_memt, (sc)->sc_gt_memh, reg)
+#define GT_WRITE(sc, reg, v) \
+ bus_space_write_4((sc)->sc_gt_memt, (sc)->sc_gt_memh, reg, (v))
+
+#include "if_xxx_rtems.c"
+
+#include <bsp.h>
+#include <libcpu/io.h>
+
+int
+NET_EMBEMB(rtems_,NETDRIVER_PREFIX,_setup)(
+ int unit,
+ char *ea,
+ uint32_t base_addr)
+{
+struct NET_SOFTC *sc;
+
+ if ( !ea ) {
+ fprintf(stderr,"Station address argument missing\n");
+ return 0;
+ }
+
+ if ( !(sc=net_drv_check_unit(unit)) ) {
+ fprintf(stderr,"Bad unit number -- (not enought driver slots?)\n");
+ return 0;
+ }
+
+ unit--;
+
+#ifdef DEBUG_MODULAR
+ if ( !METHODSPTR ) {
+ fprintf(stderr,"Methods not set -- module not loaded?\n");
+ return 0;
+ }
+#endif
+
+ if ( !base_addr ) {
+#ifdef BSP_MV64x60_BASE
+ base_addr = BSP_MV64x60_BASE;
+#else
+ fprintf(stderr,"Missing GT64260 base address\n");
+ return 0;
+#endif
+ }
+ sc->sc_gt_memh = base_addr;
+ /* must set this as well to indicate that the device is set up */
+ sc->NET_SOFTC_BHANDLE_FIELD = base_addr + 0x2400 + (unit<<10);
+ sc->sc_macno = unit;
+ memcpy( sc->arpcom.ac_enaddr, ea, ETHER_ADDR_LEN);
+
+ if ( 0 == METHODSPTR->n_probe(&THEDEVS[unit]) ) {
+ printf(NETDRIVER": Unit %i set up\n", unit + 1);
+ sc->irq_no = BSP_IRQ_ETH0 + unit;
+ return 1;
+ }
+ return 0;
+}
+
+static int
+gfe_early_init(int idx)
+{
+struct gfe_softc *sc;
+uint32_t d;
+
+ if ( idx < 0 || idx >= NETDRIVER_SLOTS )
+ return -1;
+
+ sc = device_get_softc(&the_gfe_devs[idx]);
+ d = bus_space_read_4(sc->sc_gt_memt, sc->sc_gt_memh, ETH_EPAR);
+
+ sc->sc_phyaddr = ETH_EPAR_PhyAD_GET(d, sc->sc_macno);
+ sc->sc_dev.dv_xname = NETDRIVER;
+ return 0;
+}
+
+static int
+gfe_early_read_phy(int idx, unsigned reg)
+{
+uint32_t rval;
+struct gfe_softc *sc;
+
+ if ( idx < 0 || idx >= NETDRIVER_SLOTS )
+ return -1;
+
+ sc = device_get_softc(&the_gfe_devs[idx]);
+
+ if ( gfe_mii_read( 0, sc, reg, &rval) )
+ return -1;
+ return rval & 0xffff;
+}
+
+
+static int
+gfe_early_write_phy(int idx, unsigned reg, unsigned val)
+{
+struct gfe_softc *sc;
+
+ if ( idx < 0 || idx >= NETDRIVER_SLOTS )
+ return -1;
+
+ sc = device_get_softc(&the_gfe_devs[idx]);
+
+ return gfe_mii_write( 0, sc, reg, val);
+}
+
+rtems_bsdnet_early_link_check_ops
+rtems_gfe_early_link_check_ops = {
+ init: gfe_early_init,
+ read_phy: gfe_early_read_phy,
+ write_phy: gfe_early_write_phy,
+ name: NETDRIVER,
+ num_slots: NETDRIVER_SLOTS
+};
diff --git a/c/src/lib/libbsp/powerpc/beatnik/network/if_gfe/if_gfevar.h b/c/src/lib/libbsp/powerpc/beatnik/network/if_gfe/if_gfevar.h
new file mode 100644
index 0000000000..cbb9609cf8
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/beatnik/network/if_gfe/if_gfevar.h
@@ -0,0 +1,225 @@
+#ifndef IF_GFEVAR_H
+#define IF_GFEVAR_H
+/* $NetBSD: if_gfevar.h,v 1.4.10.1 2005/04/29 11:28:56 kent Exp $ */
+
+/*
+ * Copyright (c) 2002 Allegro Networks, Inc., Wasabi Systems, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed for the NetBSD Project by
+ * Allegro Networks, Inc., and Wasabi Systems, Inc.
+ * 4. The name of Allegro Networks, Inc. may not be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ * 5. The name of Wasabi Systems, Inc. may not be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ALLEGRO NETWORKS, INC. AND
+ * WASABI SYSTEMS, INC. ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL EITHER ALLEGRO NETWORKS, INC. OR WASABI SYSTEMS, INC.
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* NOTE: GE_RXDESC_MAX * 16 <= GE_RXDESC_MEMSIZE */
+/* NOTE: the driver needs 4*GE_RXDESC_MAX mbuf clusters (4 queues) */
+#ifndef __rtems__
+#define GE_RXDESC_MEMSIZE (1 * PAGE_SIZE)
+#define GE_RXDESC_MAX 64
+#define GE_RXBUF_SIZE 2048
+#define GE_RXBUF_MEMSIZE (GE_RXDESC_MAX*GE_RXBUF_SIZE)
+#else
+#define GE_RXDESC_MEMSIZE (GE_RXDESC_MAX * sizeof(struct gt_eth_desc))
+#define GE_RXDESC_MAX (sc->num_rxdesc)
+#define GE_RXBUF_MEMSIZE 0
+#endif
+
+#define GE_RXBUF_NSEGS ((GE_RXBUF_MEMSIZE/PAGE_SIZE)+1)
+#define GE_DMSEG_MAX (GE_RXBUF_NSEGS)
+
+struct gfe_dmamem {
+ bus_dmamap_t gdm_map; /* dmamem'ed memory */
+#ifdef __rtems__
+ void *gdm_unaligned_buf;
+#endif
+ caddr_t gdm_kva; /* kva of tx memory */
+ int gdm_nsegs; /* # of segment in gdm_segs */
+ int gdm_maxsegs; /* maximum # of segments allowed */
+ size_t gdm_size; /* size of memory region */
+ bus_dma_segment_t gdm_segs[GE_DMSEG_MAX]; /* dma segment of tx memory */
+};
+
+/* With a 4096 page size, we get 256 descriptors per page.
+ */
+#ifndef __rtems__
+#define GE_TXDESC_MEMSIZE (1 * PAGE_SIZE)
+#define GE_TXDESC_MAX (GE_TXDESC_MEMSIZE / 16)
+#define GE_TXBUF_SIZE (4 * PAGE_SIZE)
+#else
+#define GE_TXDESC_MEMSIZE (sc->num_txdesc * sizeof(struct gt_eth_desc))
+#define GE_TXDESC_MAX (sc->num_txdesc)
+#endif
+
+struct gfe_txqueue {
+ struct ifqueue txq_pendq; /* these are ready to go to the GT */
+ struct ifqueue txq_sentq;
+ struct gfe_dmamem txq_desc_mem; /* transmit descriptor memory */
+#ifndef __rtems__
+ struct gfe_dmamem txq_buf_mem; /* transmit buffer memory */
+#endif
+ unsigned int txq_lo; /* next to be given to GT */
+ unsigned int txq_fi; /* next to be returned to CPU */
+#ifndef __rtems__
+ unsigned int txq_ei_gapcount; /* counter until next EI */
+#endif
+ unsigned int txq_nactive; /* number of active descriptors */
+#ifndef __rtems__
+ unsigned int txq_outptr; /* where to put next transmit packet */
+ unsigned int txq_inptr; /* start of 1st queued tx packet */
+#endif
+ uint32_t txq_intrbits; /* bits to write to EIMR */
+ uint32_t txq_esdcmrbits; /* bits to write to ESDCMR */
+ uint32_t txq_epsrbits; /* bits to test with EPSR */
+ volatile struct gt_eth_desc *txq_descs; /* ptr to tx descriptors */
+ bus_addr_t txq_ectdp; /* offset to cur. tx desc ptr reg */
+ bus_addr_t txq_desc_busaddr; /* bus addr of tx descriptors */
+#ifndef __rtems__
+ bus_addr_t txq_buf_busaddr; /* bus addr of tx buffers */
+#endif
+};
+
+/* With a 4096 page size, we get 256 descriptors per page. We want 1024
+ * which will give us about 8ms of 64 byte packets (2ms for each priority
+ * queue).
+ */
+
+#ifndef __rtems__
+struct gfe_rxbuf {
+ uint8_t rb_data[GE_RXBUF_SIZE];
+};
+#endif
+
+struct gfe_rxqueue {
+ struct gfe_dmamem rxq_desc_mem; /* receive descriptor memory */
+#ifndef __rtems__
+ struct gfe_dmamem rxq_buf_mem; /* receive buffer memory */
+ struct mbuf *rxq_curpkt; /* mbuf for current packet */
+#endif
+ volatile struct gt_eth_desc *rxq_descs;
+#ifndef __rtems__
+ struct gfe_rxbuf *rxq_bufs;
+#else
+ struct mbuf **rxq_bufs;
+#endif
+ unsigned int rxq_fi; /* next to be returned to CPU */
+ unsigned int rxq_active; /* # of descriptors given to GT */
+ uint32_t rxq_intrbits; /* bits to write to EIMR */
+ bus_addr_t rxq_desc_busaddr; /* bus addr of rx descriptors */
+ uint32_t rxq_cmdsts; /* save cmdsts from first descriptor */
+ bus_size_t rxq_efrdp;
+ bus_size_t rxq_ecrdp;
+};
+
+enum gfe_txprio {
+ GE_TXPRIO_HI=1,
+ GE_TXPRIO_LO=0,
+ GE_TXPRIO_NONE=2
+};
+enum gfe_rxprio {
+ GE_RXPRIO_HI=3,
+ GE_RXPRIO_MEDHI=2,
+ GE_RXPRIO_MEDLO=1,
+ GE_RXPRIO_LO=0
+};
+
+#ifdef __rtems__
+#define sc_ec arpcom
+#define ec_if ac_if
+#define sc_dev arpcom
+#define dv_xname ac_if.if_name
+#endif
+
+struct gfe_softc {
+#ifndef __rtems__
+ struct device sc_dev; /* must be first */
+ struct ethercom sc_ec; /* common ethernet glue */
+ struct callout sc_co; /* resource recovery */
+ mii_data_t sc_mii; /* mii interface */
+
+ /*
+ *
+ */
+ bus_space_tag_t sc_gt_memt;
+ bus_space_handle_t sc_gt_memh;
+ bus_space_handle_t sc_memh; /* subregion for ethernet */
+ bus_dma_tag_t sc_dmat;
+#else
+ struct arpcom sc_ec;
+ unsigned sc_gt_memh;
+ unsigned sc_memh;
+ unsigned char irq_no;
+ rtems_id tid;
+ int sc_phyaddr;
+ int num_rxdesc, num_txdesc;
+#endif
+ int sc_macno; /* which mac? 0, 1, or 2 */
+
+ unsigned int sc_tickflags;
+#define GE_TICK_TX_IFSTART 0x0001
+#define GE_TICK_RX_RESTART 0x0002
+ unsigned int sc_flags;
+#define GE_ALLMULTI 0x0001
+#define GE_PHYSTSCHG 0x0002
+#define GE_RXACTIVE 0x0004
+#define GE_NOFREE 0x0008 /* Don't free on disable */
+ uint32_t sc_pcr; /* current EPCR value */
+ uint32_t sc_pcxr; /* current EPCXR value */
+ uint32_t sc_intrmask; /* current EIMR value */
+ uint32_t sc_idlemask; /* suspended EIMR bits */
+ size_t sc_max_frame_length; /* maximum frame length */
+
+ /*
+ * Hash table related members
+ */
+ struct gfe_dmamem sc_hash_mem; /* dma'ble hash table */
+ uint64_t *sc_hashtable;
+ unsigned int sc_hashmask; /* 0x1ff or 0x1fff */
+
+ /*
+ * Transmit related members
+ */
+ struct gfe_txqueue sc_txq[2]; /* High & Low transmit queues */
+
+ /*
+ * Receive related members
+ */
+ struct gfe_rxqueue sc_rxq[4]; /* Hi/MedHi/MedLo/Lo receive queues */
+};
+
+#ifdef __rtems__
+int
+gfe_mii_read(int phy, void *arg, unsigned reg, uint32_t *pval);
+
+int
+gfe_mii_write(int phy, void *arg, unsigned reg, uint32_t value);
+#endif
+
+#endif
diff --git a/c/src/lib/libbsp/powerpc/beatnik/network/if_gfe/rtemscompat_defs.h b/c/src/lib/libbsp/powerpc/beatnik/network/if_gfe/rtemscompat_defs.h
new file mode 100644
index 0000000000..8234681b1b
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/beatnik/network/if_gfe/rtemscompat_defs.h
@@ -0,0 +1,122 @@
+#ifndef RTEMS_COMPAT_DEFS_H
+#define RTEMS_COMPAT_DEFS_H
+
+/* Number of device instances the driver should support
+ * - may be limited to 1 depending on IRQ API
+ * (braindamaged PC586 and powerpc)
+ */
+#define NETDRIVER_SLOTS 1
+/* String name to print with error messages */
+#define NETDRIVER "gfe"
+/* Name snippet used to make global symbols unique to this driver */
+#define NETDRIVER_PREFIX gfe
+
+/* Define according to endianness of the *ethernet*chip*
+ * (not the CPU - most probably are LE)
+ * This must be either NET_CHIP_LE or NET_CHIP_BE
+ */
+
+#define NET_CHIP_LE
+#undef NET_CHIP_BE
+
+/* Define either NET_CHIP_MEM_IO or NET_CHIP_PORT_IO,
+ * depending whether the CPU sees it in memory address space
+ * or (e.g. x86) uses special I/O instructions.
+ */
+#define NET_CHIP_MEM_IO
+#undef NET_CHIP_PORT_IO
+
+/* The name of the hijacked 'bus handle' field in the softc
+ * structure. We use this field to store the chip's base address.
+ */
+#define NET_SOFTC_BHANDLE_FIELD sc_memh
+
+/* define the names of the 'if_XXXreg.h' and 'if_XXXvar.h' headers
+ * (only if present, i.e., if the BSDNET driver has no respective
+ * header, leave this undefined).
+ *
+ */
+#undef IF_REG_HEADER
+#define IF_VAR_HEADER <if_gfevar.h>
+
+/* define if a pci device */
+/*
+#define NETDRIVER_PCI <bsp/pci.h>
+*/
+#undef NETDRIVER_PCI
+
+/* Macros to disable and enable interrupts, respectively.
+ * The 'disable' macro is expanded in the ISR, the 'enable'
+ * macro is expanded in the driver task.
+ * The global network semaphore usually provides mutex
+ * protection of the device registers.
+ * Special care must be taken when coding the 'disable' macro,
+ * however to MAKE SURE THERE ARE NO OTHER SIDE EFFECTS such
+ * as:
+ * - macro must not clear any status flags
+ * - macro must save/restore any context information
+ * (e.g., a address register pointer or a bank switch register)
+ *
+ * ARGUMENT: the macro arg is a pointer to the driver's 'softc' structure
+ */
+
+#define NET_DISABLE_IRQS(sc) GE_WRITE(sc, EIMR, 0)
+#define NET_ENABLE_IRQS(sc) GE_WRITE(sc, EIMR, sc->sc_intrmask)
+
+/* Driver may provide a macro/function to copy the hardware address
+ * from the device into 'softc.arpcom'.
+ * If this is undefined, the driver must to the copy itself.
+ * Preferrably, it should check soft.arpcom.ac_enaddr for all
+ * zeros and leave it alone if it is nonzero, i.e., write it
+ * to the hardware.
+#define NET_READ_MAC_ADDR(sc)
+ */
+
+typedef struct {
+ uint32_t ds_addr;
+ uint32_t ds_len;
+} bus_dma_segment_t;
+
+#define dm_segs gdm_segs
+#define dm_nsegs gdm_nsegs
+typedef struct gfe_dmamem *bus_dmamap_t;
+
+typedef uint32_t bus_addr_t;
+typedef uint32_t bus_size_t;
+
+typedef struct device blah;
+
+#define BUS_DMA_NOCACHE 0xdeadbeef
+
+#ifdef __PPC__
+#define bus_dmamap_sync(args...) do { asm volatile("sync":::"memory"); } while(0)
+#else
+#error "Dont' know how to sync memory on your CPU"
+#endif
+
+int ether_sprintf_r(const unsigned char *enaddr, char *buf, int len);
+
+/* we have it although we're not ansi */
+int snprintf(char *, size_t, const char *,...);
+
+#include <string.h>
+
+/* declare in every routine using ether_sprintf */
+#define SPRINTFVARDECL char rtems_sprintf_local_buf[3*6] /* ethernet string */
+
+#define ether_sprintf_macro(a) \
+ (snprintf(rtems_sprintf_local_buf, \
+ sizeof(rtems_sprintf_local_buf), \
+ "%02X:%02X:%02X:%02X:%02X:%02X", \
+ a[0],a[1],a[2],a[3],a[4],a[5]) ? \
+ rtems_sprintf_local_buf : 0 \
+ )
+
+
+#define aprint_normal(args...) printf(args)
+#define aprint_error(args...) fprintf(stderr,args)
+
+#define delay(arg) DELAY(arg)
+
+#define KASSERT(a...) do {} while (0)
+#endif
diff --git a/c/src/lib/libbsp/powerpc/beatnik/network/if_mve/if_mve_pub.h b/c/src/lib/libbsp/powerpc/beatnik/network/if_mve/if_mve_pub.h
new file mode 100644
index 0000000000..876c3fefdf
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/beatnik/network/if_mve/if_mve_pub.h
@@ -0,0 +1,423 @@
+/* $Id$ */
+#ifndef RTEMS_BSDNET_IF_MVE_PUBLIC_SYMBOLS_H
+#define RTEMS_BSDNET_IF_MVE_PUBLIC_SYMBOLS_H
+
+/*
+ * Authorship
+ * ----------
+ * This software ('beatnik' RTEMS BSP for MVME6100 and MVME5500) was
+ * created by Till Straumann <strauman@slac.stanford.edu>, 2005-2007,
+ * Stanford Linear Accelerator Center, Stanford University.
+ *
+ * Acknowledgement of sponsorship
+ * ------------------------------
+ * The 'beatnik' 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/rtems_bsdnet.h>
+#include <bsp/early_enet_link_status.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+extern int rtems_mve_attach(struct rtems_bsdnet_ifconfig *, int);
+extern rtems_bsdnet_early_link_check_ops rtems_mve_early_link_check_ops;
+
+/* Low-level Driver API.
+ * This provides driver access to applications that want to use e.g., the second
+ * ethernet interface w/o running the BSD TCP/IP stack.
+ */
+
+/* Opaque handle */
+struct mveth_private;
+
+/* Direct assignment of MVE flags to user API relies on irqs and x-irqs not overlapping */
+#define BSP_MVE_IRQ_RX (1<<2)
+#define BSP_MVE_IRQ_TX (1<<0)
+#define BSP_MVE_IRQ_LINK (1<<16)
+
+/* 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.
+ *
+ * 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_mve_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_mve_swipe_tx() or
+ * BSP_mve_send_buf(), BSP_mve_init_hw(), BSP_mve_stop_hw() (the latter
+ * ones calling BSP_mve_swipe_tx()).
+ * void *cleanup_txbuf_arg:
+ * Closure argument that is passed on to 'cleanup_txbuf()' callback;
+ *
+ * void *(*alloc_rxbuf)(int *p_size, unsigned long *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_mve_init_hw()) or when
+ * swiping it (BSP_mve_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_mve_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_mve_swipe_rx() or
+ * BSP_mve_swipe_tx(), respectively.
+ *
+ * irq_mask:
+ * Interrupts to enable. OR of flags from above.
+ *
+ */
+struct mveth_private *
+BSP_mve_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
+);
+
+/*
+ * Alternate 'setup' routine allowing the user to install an ISR rather
+ * than a task ID.
+ * All parameters (other than 'isr' / 'isr_arg') and the return value
+ * are identical to the BSP_mve_setup() entry point.
+ */
+struct mveth_private *
+BSP_mve_setup_1(
+ int unit,
+ void (*isr)(void *isr_arg),
+ void *isr_arg,
+ 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
+);
+
+
+/*
+ * Initialize interface hardware
+ *
+ * 'mp' handle obtained by from BSP_mve_setup().
+ * 'promisc' whether to set promiscuous flag.
+ * 'enaddr' pointer to six bytes with MAC address. Read
+ * from the device if NULL.
+ *
+ * Note: Multicast filters are cleared by this routine.
+ * However, in promiscuous mode the mcast filters
+ * are programmed to accept all multicast frames.
+ */
+void
+BSP_mve_init_hw(struct mveth_private *mp, int promisc, unsigned char *enaddr);
+
+/*
+ * Clear multicast hash filter. No multicast frames are accepted
+ * after executing this routine (unless the hardware was initialized
+ * in 'promiscuous' mode).
+ */
+void
+BSP_mve_mcast_filter_clear(struct mveth_private *mp);
+
+/*
+ * Program multicast filter to accept all multicast frames
+ */
+void
+BSP_mve_mcast_filter_accept_all(struct mveth_private *mp);
+
+/*
+ * Add a MAC address to the multicast filter.
+ * Existing entries are not changed but note that
+ * the filter is imperfect, i.e., multiple MAC addresses
+ * may alias to a single filter entry. Hence software
+ * filtering must still be performed.
+ *
+ * If a higher-level driver implements IP multicasting
+ * then multiple IP addresses may alias to the same MAC
+ * address. This driver maintains a 'reference-count'
+ * which is incremented every time the same MAC-address
+ * is passed to this routine; the address is only removed
+ * from the filter if BSP_mve_mcast_filter_accept_del()
+ * is called the same number of times (or by BSP_mve_mcast_filter_clear).
+ */
+void
+BSP_mve_mcast_filter_accept_add(struct mveth_private *mp, unsigned char *enaddr);
+
+/*
+ * Remove a MAC address from the multicast filter.
+ * This routine decrements the reference count of the given
+ * MAC-address and removes it from the filter once the
+ * count reaches zero.
+ */
+void
+BSP_mve_mcast_filter_accept_del(struct mveth_private *mp, unsigned char *enaddr);
+
+/*
+ * Shutdown hardware and clean out the rings
+ */
+void
+BSP_mve_stop_hw(struct mveth_private *mp);
+
+/* calls BSP_mve_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_mve_detach(struct mveth_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 send (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_mve_send_buf(struct mveth_private *mp, void *m_head, void *data_p, int len);
+
+/* Descriptor scavenger; cleanup the TX ring, passing all buffers
+ * that have been sent to the cleanup_tx() callback.
+ * This routine is called from BSP_mve_send_buf(), BSP_mve_init_hw(),
+ * BSP_mve_stop_hw().
+ *
+ * RETURNS: number of buffers processed.
+ */
+int
+BSP_mve_swipe_tx(struct mveth_private *mp);
+
+/* 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_mve_swipe_rx(struct mveth_private *mp);
+
+/* read ethernet address from hw to buffer */
+void
+BSP_mve_read_eaddr(struct mveth_private *mp, unsigned char *eaddr);
+
+/* 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
+ *
+ * NOTE: This routine is thread-safe.
+ */
+int
+BSP_mve_media_ioctl(struct mveth_private *mp, int cmd, int *parg);
+
+/* Interrupt related routines */
+
+/* Note: the BSP_mve_enable/disable/ack_irqs() entry points
+ * are deprecated.
+ * The newer API where the user passes a mask allows
+ * for more selective control.
+ */
+
+/* Enable all supported interrupts at device */
+void
+BSP_mve_enable_irqs(struct mveth_private *mp);
+
+/* Disable all supported interrupts at device */
+void
+BSP_mve_disable_irqs(struct mveth_private *mp);
+
+/* Acknowledge (and clear) all supported interrupts.
+ * RETURNS: interrupts that were raised.
+ */
+uint32_t
+BSP_mve_ack_irqs(struct mveth_private *mp);
+
+/* Enable interrupts included in 'mask' (leaving
+ * already enabled interrupts on). If the mask
+ * includes bits that were not passed to the 'setup'
+ * routine then the behavior is undefined.
+ */
+void
+BSP_mve_enable_irq_mask(struct mveth_private *mp, uint32_t irq_mask);
+
+/* Disable interrupts included in 'mask' (leaving
+ * other ones that are currently enabled on). If the
+ * mask includes bits that were not passed to the 'setup'
+ * routine then the behavior is undefined.
+ *
+ * RETURNS: Bitmask of interrupts that were enabled upon entry
+ * into this routine. This can be used to restore the
+ * previous state.
+ */
+uint32_t
+BSP_mve_disable_irq_mask(struct mveth_private *mp, uint32_t irq_mask);
+
+/* Acknowledge and clear selected interrupts.
+ *
+ * RETURNS: All pending interrupts.
+ *
+ * NOTE: Only pending interrupts contained in 'mask'
+ * are cleared. Others are left pending.
+ *
+ * This routine can be used to check for pending
+ * interrupts (pass mask == 0) or to clear all
+ * interrupts (pass mask == -1).
+ */
+uint32_t
+BSP_mve_ack_irq_mask(struct mveth_private *mp, uint32_t mask);
+
+/* If the PHY link status changes then some
+ * internal settings in the ethernet controller's
+ * serial port need to be updated to match the
+ * PHY settings. Use this routine to perform the
+ * necessary steps after a link change has been
+ * detected.
+ *
+ * RETURNS: 0 on success, -1 if the PHY state
+ * could not be determined.
+ *
+ * The current state of the media as read
+ * by BSP_mve_media_ioctl() is returned in
+ * *pmedia.
+ *
+ * NOTE: This routine calls BSP_mve_media_ioctl().
+ */
+int
+BSP_mve_ack_link_chg(struct mveth_private *mp, int *pmedia);
+
+/* Retrieve the driver daemon TID that was passed to
+ * BSP_mve_setup().
+ */
+
+rtems_id
+BSP_mve_get_tid(struct mveth_private *mp);
+
+/* Dump statistics to file (stdout if NULL)
+ *
+ * NOTE: this routine is not thread safe
+ */
+void
+BSP_mve_dump_stats(struct mveth_private *mp, FILE *f);
+
+/*
+ *
+ * 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_mve_ack_irqs(handle);
+ * if ( irqs & BSP_MVE_IRQ_TX ) {
+ * BSP_mve_swipe_tx(handle); / * cleanup_txbuf() callback executed * /
+ * }
+ * if ( irqs & BSP_MVE_IRQ_RX ) {
+ * BSP_mve_swipe_rx(handle); / * alloc_rxbuf() and consume_rxbuf() executed * /
+ * }
+ * if ( irqs & BSP_MVE_IRQ_LINK ) {
+ * / * update serial port settings from current link status * /
+ * BSP_mve_ack_link_chg(handle, 0);
+ * }
+ * BSP_mve_enable_irqs(handle);
+ * } while (1);
+ *
+ */
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif
diff --git a/c/src/lib/libbsp/powerpc/beatnik/network/if_mve/mv643xx_eth.c b/c/src/lib/libbsp/powerpc/beatnik/network/if_mve/mv643xx_eth.c
new file mode 100644
index 0000000000..e9e1779574
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/beatnik/network/if_mve/mv643xx_eth.c
@@ -0,0 +1,3297 @@
+/* $Id$ */
+
+/* RTEMS driver for the mv643xx gigabit ethernet chip */
+
+/* Acknowledgement:
+ *
+ * Valuable information for developing this driver was obtained
+ * from the linux open-source driver mv643xx_eth.c which was written
+ * by the following people and organizations:
+ *
+ * Matthew Dharm <mdharm@momenco.com>
+ * rabeeh@galileo.co.il
+ * PMC-Sierra, Inc., Manish Lachwani
+ * Ralf Baechle <ralf@linux-mips.org>
+ * MontaVista Software, Inc., Dale Farnsworth <dale@farnsworth.org>
+ * Steven J. Hill <sjhill1@rockwellcollins.com>/<sjhill@realitydiluted.com>
+ *
+ * Note however, that in spite of the identical name of this file
+ * (and some of the symbols used herein) this file provides a
+ * new implementation and is the original work by the author.
+ */
+
+/*
+ * Authorship
+ * ----------
+ * This software (mv643xx ethernet driver for RTEMS) was
+ * created by Till Straumann <strauman@slac.stanford.edu>, 2005-2007,
+ * Stanford Linear Accelerator Center, Stanford University.
+ *
+ * Acknowledgement of sponsorship
+ * ------------------------------
+ * The 'mv643xx ethernet driver for RTEMS' 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: Some register (e.g., the SMI register) are SHARED among the
+ * three devices. Concurrent access protection is provided by
+ * the global networking semaphore.
+ * If other drivers are running on a subset of IFs then proper
+ * locking of all shared registers must be implemented!
+ *
+ * Some things I learned about this hardware can be found
+ * further down...
+ */
+
+#ifndef KERNEL
+#define KERNEL
+#endif
+#ifndef _KERNEL
+#define _KERNEL
+#endif
+
+#include <rtems.h>
+#include <rtems/bspIo.h>
+#include <rtems/error.h>
+#include <bsp.h>
+#include <bsp/irq.h>
+#include <bsp/gtreg.h>
+#include <libcpu/byteorder.h>
+
+#include <dev/mii/mii.h>
+#include <net/if_media.h>
+
+/* Not so nice; would be more elegant not to depend on C library but the
+ * RTEMS-specific ioctl for dumping statistics needs stdio anyways.
+ */
+
+/*#define NDEBUG effectively removes all assertions
+ * If defining NDEBUG, MAKE SURE assert() EXPRESSION HAVE NO SIDE_EFFECTS!!
+ * This driver DOES have side-effects, so DONT DEFINE NDEBUG
+ * Performance-critical assertions are removed by undefining MVETH_TESTING.
+ */
+
+#undef NDEBUG
+#include <assert.h>
+#include <stdio.h>
+#include <errno.h>
+#include <inttypes.h>
+
+#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/early_enet_link_status.h>
+#include <bsp/if_mve_pub.h>
+
+/* CONFIGURABLE PARAMETERS */
+
+/* Enable Hardware Snooping; if this is disabled (undefined),
+ * cache coherency is maintained by software.
+ */
+#undef ENABLE_HW_SNOOPING
+
+/* Compile-time debugging features */
+
+/* Enable paranoia assertions and checks; reduce # of descriptors to minimum for stressing */
+#undef MVETH_TESTING
+
+/* Enable debugging messages and some support routines (dump rings etc.) */
+#undef MVETH_DEBUG
+
+#ifndef DISABLE_DETACHING /* can override from Makefile */
+/* Hack for driver development; rtems bsdnet doesn't implement detaching an interface :-(
+ * but this hack allows us to unload/reload the driver module which makes development
+ * a lot less painful.
+ */
+#define MVETH_DETACH_HACK
+#endif
+
+/* Ring sizes */
+
+#ifdef MVETH_TESTING
+
+/* hard and small defaults */
+#undef MV643XX_RX_RING_SIZE
+#define MV643XX_RX_RING_SIZE 2
+#undef MV643XX_TX_RING_SIZE
+#define MV643XX_TX_RING_SIZE 4
+
+#else /* MVETH_TESTING */
+
+/* Define default ring sizes, allow override from bsp.h, Makefile,... and from ifcfg->rbuf_count/xbuf_count */
+
+#ifndef MV643XX_RX_RING_SIZE
+#define MV643XX_RX_RING_SIZE 40 /* attached buffers are always 2k clusters, i.e., this
+ * driver - with a configured ring size of 40 - constantly
+ * locks 80k of cluster memory - your app config better
+ * provides enough space!
+ */
+#endif
+
+#ifndef MV643XX_TX_RING_SIZE
+/* NOTE: tx ring size MUST be > max. # of fragments / mbufs in a chain;
+ * in 'TESTING' mode, special code is compiled in to repackage
+ * chains that are longer than the ring size. Normally, this is
+ * disabled for sake of speed.
+ * I observed chains of >17 entries regularly!
+ *
+ * Also, TX_NUM_TAG_SLOTS (1) must be left empty as a marker, hence
+ * the ring size must be > max. #frags + 1.
+ */
+#define MV643XX_TX_RING_SIZE 200 /* these are smaller fragments and not occupied when
+ * the driver is idle.
+ */
+#endif
+
+#endif /* MVETH_TESTING */
+
+/* How many instances to we support (bsp.h could override) */
+#ifndef MV643XXETH_NUM_DRIVER_SLOTS
+#define MV643XXETH_NUM_DRIVER_SLOTS 2
+#endif
+
+#define TX_NUM_TAG_SLOTS 1 /* leave room for tag; must not be 0 */
+
+/* This is REAL; chip reads from 64-bit down-aligned buffer
+ * if the buffer size is < 8 !!! for buffer sizes 8 and upwards
+ * alignment is not an issue. This was verified using the
+ * 'mve_smallbuf_test.c'
+ */
+#define ENABLE_TX_WORKAROUND_8_BYTE_PROBLEM
+
+/* Chip register configuration values */
+#define MVETH_PORT_CONFIG_VAL (0 \
+ | MV643XX_ETH_DFLT_RX_Q(0) \
+ | MV643XX_ETH_DFLT_RX_ARP_Q(0) \
+ | MV643XX_ETH_DFLT_RX_TCP_Q(0) \
+ | MV643XX_ETH_DFLT_RX_UDP_Q(0) \
+ | MV643XX_ETH_DFLT_RX_BPDU_Q(0) \
+ )
+
+
+#define MVETH_PORT_XTEND_CONFIG_VAL 0
+
+#ifdef OLDCONFIGVAL
+#define MVETH_SERIAL_CTRL_CONFIG_VAL (0 \
+ | MV643XX_ETH_FORCE_LINK_PASS \
+ | MV643XX_ETH_DISABLE_AUTO_NEG_FOR_FLOWCTL \
+ | MV643XX_ETH_ADVERTISE_SYMMETRIC_FLOWCTL \
+ | MV643XX_ETH_BIT9_UNKNOWN \
+ | MV643XX_ETH_FORCE_LINK_FAIL_DISABLE \
+ | MV643XX_ETH_SC_MAX_RX_1552 \
+ | MV643XX_ETH_SET_FULL_DUPLEX \
+ | MV643XX_ETH_ENBL_FLOWCTL_TX_RX_IN_FD \
+ )
+#endif
+/* If we enable autoneg (duplex, speed, ...) then it seems
+ * that the chip automatically updates link settings
+ * (correct link settings are reflected in PORT_STATUS_R).
+ * However, when we disable aneg in the PHY then things
+ * can get messed up and the port doesn't work anymore.
+ * => we follow the linux driver in disabling all aneg
+ * in the serial config reg. and manually updating the
+ * speed & duplex bits when the phy link status changes.
+ * FIXME: don't know what to do about pause/flow-ctrl.
+ * It is best to just use ANEG anyways!!!
+ */
+#define MVETH_SERIAL_CTRL_CONFIG_VAL (0 \
+ | MV643XX_ETH_DISABLE_AUTO_NEG_FOR_DUPLEX \
+ | MV643XX_ETH_DISABLE_AUTO_NEG_FOR_FLOWCTL \
+ | MV643XX_ETH_ADVERTISE_SYMMETRIC_FLOWCTL \
+ | MV643XX_ETH_BIT9_UNKNOWN \
+ | MV643XX_ETH_FORCE_LINK_FAIL_DISABLE \
+ | MV643XX_ETH_DISABLE_AUTO_NEG_SPEED_GMII \
+ | MV643XX_ETH_SC_MAX_RX_1552 \
+ )
+
+#define MVETH_SERIAL_CTRL_CONFIG_MSK (0 \
+ | MV643XX_ETH_SERIAL_PORT_ENBL \
+ | MV643XX_ETH_FORCE_LINK_PASS \
+ | MV643XX_ETH_SC_MAX_RX_MASK \
+ )
+
+
+#ifdef __PPC__
+#define MVETH_SDMA_CONFIG_VAL (0 \
+ | MV643XX_ETH_RX_BURST_SZ_4_64BIT \
+ | MV643XX_ETH_TX_BURST_SZ_4_64BIT \
+ )
+#else
+#define MVETH_SDMA_CONFIG_VAL (0 \
+ | MV643XX_ETH_RX_BURST_SZ_16_64BIT \
+ | MV643XX_ETH_TX_BURST_SZ_16_64BIT \
+ )
+#endif
+
+/* minimal frame size we accept */
+#define MVETH_MIN_FRAMSZ_CONFIG_VAL 40
+
+/* END OF CONFIGURABLE SECTION */
+
+/*
+ * Here's stuff I learned about this chip:
+ *
+ *
+ * RX interrupt flags:
+ *
+ * broadcast packet RX: 0x00000005
+ * last buf: 0x00000c05
+ * overrun: 0x00000c00
+ * unicast packet RX: 0x00000005
+ * bad CRC received: 0x00000005
+ *
+ * clearing 0x00000004 -> clears 0x00000001
+ * clearing 0x00000400 -> clears 0x00000800
+ *
+ * --> 0x0801 are probably some sort of summary bits.
+ *
+ * TX interrupt flags:
+ *
+ * broadcast packet in 1 buf: xcause: 0x00000001 (cause 0x00080000)
+ * into disconn. link: " "
+ *
+ * in some cases, I observed xcause: 0x00000101 (reason for 0x100 unknown
+ * but the linux driver accepts it also).
+ *
+ *
+ * Here a few more ugly things about this piece of hardware I learned
+ * (painfully, painfully; spending many many hours & nights :-()
+ *
+ * a) Especially in the case of 'chained' descriptors, the DMA keeps
+ * clobbering 'cmd_sts' long after it cleared the OWNership flag!!!
+ * Only after the whole chain is processed (OWN cleared on the
+ * last descriptor) it is safe to change cmd_sts.
+ * However, in the case of hardware snooping I found that the
+ * last descriptor in chain has its cmd_sts still clobbered *after*
+ * checking ownership!, I.e.,
+ * if ( ! OWN & cmd_sts ) {
+ * cmd_sts = 0;
+ * }
+ * --> sometimes, cmd_sts is STILL != 0 here
+ *
+ * b) Sometimes, the OWNership flag is *not cleared*.
+ *
+ * c) Weird things happen if the chip finds a descriptor with 'OWN'
+ * still set (i.e., not properly loaded), i.e., corrupted packets
+ * are sent [with OK checksum since the chip calculates it].
+ *
+ * Combine a+b+c and we end up with a real mess.
+ *
+ * The fact that the chip doesn't reliably reset OWN and that OTOH,
+ * it can't be reliably reset by the driver and still, the chip needs
+ * it for proper communication doesn't make things easy...
+ *
+ * Here the basic workarounds:
+ *
+ * - In addition to check OWN, the scavenger compares the "currently
+ * served desc" register to the descriptor it tries to recover and
+ * ignores OWN if they do not match. Hope this is OK.
+ * Otherwise, we could scan the list of used descriptors and proceed
+ * recycling descriptors if we find a !OWNed one behind the target...
+ *
+ * - Always keep an empty slot around to mark the end of the list of
+ * jobs. The driver clears the descriptor ahead when enqueueing a new
+ * packet.
+ */
+
+#define DRVNAME "mve"
+#define MAX_NUM_SLOTS 3
+
+#if MV643XXETH_NUM_DRIVER_SLOTS > MAX_NUM_SLOTS
+#error "mv643xxeth: only MAX_NUM_SLOTS supported"
+#endif
+
+#ifdef NDEBUG
+#error "Driver uses assert() statements with side-effects; MUST NOT define NDEBUG"
+#endif
+
+#ifdef MVETH_DEBUG
+#define STATIC
+#else
+#define STATIC static
+#endif
+
+#define TX_AVAILABLE_RING_SIZE(mp) ((mp)->xbuf_count - (TX_NUM_TAG_SLOTS))
+
+/* macros for ring alignment; proper alignment is a hardware req; . */
+
+#ifdef ENABLE_HW_SNOOPING
+
+#define RING_ALIGNMENT 16
+/* rx buffers must be 64-bit aligned (chip requirement) */
+#define RX_BUF_ALIGNMENT 8
+
+#else /* ENABLE_HW_SNOOPING */
+
+/* Software cache management */
+
+#ifndef __PPC__
+#error "Dont' know how to deal with cache on this CPU architecture"
+#endif
+
+/* Ring entries are 32 bytes; coherency-critical chunks are 16 -> software coherency
+ * management works for cache line sizes of 16 and 32 bytes only. If the line size
+ * is bigger, the descriptors could be padded...
+ */
+#if PPC_CACHE_ALIGMENT != 16 && PPC_CACHE_ALIGNMENT != 32
+#error "Cache line size must be 16 or 32"
+#else
+#define RING_ALIGNMENT PPC_CACHE_ALIGNMENT
+#define RX_BUF_ALIGNMENT PPC_CACHE_ALIGNMENT
+#endif
+
+#endif /* ENABLE_HW_SNOOPING */
+
+
+/* HELPER MACROS */
+
+/* Align base to alignment 'a' */
+#define _ALIGN(b, a) ((((uint32_t)(b)) + (a)-1) & (~((a)-1)))
+
+#define NOOP() do {} while(0)
+
+/* Function like macros */
+#define MV_READ(off) \
+ ld_le32((volatile uint32_t *)(BSP_MV64x60_BASE + (off)))
+#define MV_WRITE(off, data) \
+ st_le32((volatile uint32_t *)(BSP_MV64x60_BASE + (off)), ((unsigned)data))
+
+
+/* ENET window mapped 1:1 to CPU addresses by our BSP/MotLoad
+ * -- if this is changed, we should think about caching the 'next' and 'buf' pointers.
+ */
+#define CPUADDR2ENET(a) ((Dma_addr_t)(a))
+#define ENET2CPUADDR(a) (a)
+
+#if 1 /* Whether to automatically try to reclaim descriptors when enqueueing new packets */
+#define MVETH_CLEAN_ON_SEND(mp) (BSP_mve_swipe_tx(mp))
+#else
+#define MVETH_CLEAN_ON_SEND(mp) (-1)
+#endif
+
+#define NEXT_TXD(d) (d)->next
+#define NEXT_RXD(d) (d)->next
+
+/* REGISTER AND DESCRIPTOR OFFSET AND BIT DEFINITIONS */
+
+/* Descriptor Definitions */
+/* Rx descriptor */
+#define RDESC_ERROR (1<< 0) /* Error summary */
+
+/* Error code (bit 1&2) is only valid if summary bit is set */
+#define RDESC_CRC_ERROR ( 1)
+#define RDESC_OVERRUN_ERROR ( 3)
+#define RDESC_MAX_FRAMELENGTH_ERROR ( 5)
+#define RDESC_RESOURCE_ERROR ( 7)
+
+#define RDESC_LAST (1<<26) /* Last Descriptor */
+#define RDESC_FRST (1<<27) /* First Descriptor */
+#define RDESC_INT_ENA (1<<29) /* Enable Interrupts */
+#define RDESC_DMA_OWNED (1<<31)
+
+/* Tx descriptor */
+#define TDESC_ERROR (1<< 0) /* Error summary */
+#define TDESC_ZERO_PAD (1<<19)
+#define TDESC_LAST (1<<20) /* Last Descriptor */
+#define TDESC_FRST (1<<21) /* First Descriptor */
+#define TDESC_GEN_CRC (1<<22)
+#define TDESC_INT_ENA (1<<23) /* Enable Interrupts */
+#define TDESC_DMA_OWNED (1<<31)
+
+
+
+/* Register Definitions */
+#define MV643XX_ETH_PHY_ADDR_R (0x2000)
+#define MV643XX_ETH_SMI_R (0x2004)
+#define MV643XX_ETH_SMI_BUSY (1<<28)
+#define MV643XX_ETH_SMI_VALID (1<<27)
+#define MV643XX_ETH_SMI_OP_WR (0<<26)
+#define MV643XX_ETH_SMI_OP_RD (1<<26)
+
+#define MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_R(port) (0x2448 + ((port)<<10))
+#define MV643XX_ETH_TX_START(queue) (0x0001<<(queue))
+#define MV643XX_ETH_TX_STOP(queue) (0x0100<<(queue))
+#define MV643XX_ETH_TX_START_M(queues) ((queues)&0xff)
+#define MV643XX_ETH_TX_STOP_M(queues) (((queues)&0xff)<<8)
+#define MV643XX_ETH_TX_STOP_ALL (0xff00)
+#define MV643XX_ETH_TX_ANY_RUNNING (0x00ff)
+
+#define MV643XX_ETH_RECEIVE_QUEUE_COMMAND_R(port) (0x2680 + ((port)<<10))
+#define MV643XX_ETH_RX_START(queue) (0x0001<<(queue))
+#define MV643XX_ETH_RX_STOP(queue) (0x0100<<(queue))
+#define MV643XX_ETH_RX_STOP_ALL (0xff00)
+#define MV643XX_ETH_RX_ANY_RUNNING (0x00ff)
+
+#define MV643XX_ETH_CURRENT_SERVED_TX_DESC(port) (0x2684 + ((port)<<10))
+
+/* The chip puts the ethernet header at offset 2 into the buffer so
+ * that the payload is aligned
+ */
+#define ETH_RX_OFFSET 2
+#define ETH_CRC_LEN 4 /* strip FCS at end of packet */
+
+
+#define MV643XX_ETH_INTERRUPT_CAUSE_R(port) (0x2460 + ((port)<<10))
+/* not fully understood; RX seems to raise 0x0005 or 0x0c05 if last buffer is filled and 0x0c00
+ * if there are no buffers
+ */
+#define MV643XX_ETH_ALL_IRQS (0x0007ffff)
+#define MV643XX_ETH_KNOWN_IRQS (0x00000c05)
+#define MV643XX_ETH_IRQ_EXT_ENA (1<<1)
+#define MV643XX_ETH_IRQ_RX_DONE (1<<2)
+#define MV643XX_ETH_IRQ_RX_NO_DESC (1<<10)
+
+#define MV643XX_ETH_INTERRUPT_EXTEND_CAUSE_R(port) (0x2464 + ((port)<<10))
+/* not fully understood; TX seems to raise 0x0001 and link change is 0x00010000
+ * if there are no buffers
+ */
+#define MV643XX_ETH_ALL_EXT_IRQS (0x0011ffff)
+#define MV643XX_ETH_KNOWN_EXT_IRQS (0x00010101)
+#define MV643XX_ETH_EXT_IRQ_TX_DONE (1<<0)
+#define MV643XX_ETH_EXT_IRQ_LINK_CHG (1<<16)
+#define MV643XX_ETH_INTERRUPT_ENBL_R(port) (0x2468 + ((port)<<10))
+#define MV643XX_ETH_INTERRUPT_EXTEND_ENBL_R(port) (0x246c + ((port)<<10))
+
+/* port configuration */
+#define MV643XX_ETH_PORT_CONFIG_R(port) (0x2400 + ((port)<<10))
+#define MV643XX_ETH_UNICAST_PROMISC_MODE (1<<0)
+#define MV643XX_ETH_DFLT_RX_Q(q) ((q)<<1)
+#define MV643XX_ETH_DFLT_RX_ARP_Q(q) ((q)<<4)
+#define MV643XX_ETH_REJ_BCAST_IF_NOT_IP_OR_ARP (1<<7)
+#define MV643XX_ETH_REJ_BCAST_IF_IP (1<<8)
+#define MV643XX_ETH_REJ_BCAST_IF_ARP (1<<9)
+#define MV643XX_ETH_TX_AM_NO_UPDATE_ERR_SUMMARY (1<<12)
+#define MV643XX_ETH_CAPTURE_TCP_FRAMES_ENBL (1<<14)
+#define MV643XX_ETH_CAPTURE_UDP_FRAMES_ENBL (1<<15)
+#define MV643XX_ETH_DFLT_RX_TCP_Q(q) ((q)<<16)
+#define MV643XX_ETH_DFLT_RX_UDP_Q(q) ((q)<<19)
+#define MV643XX_ETH_DFLT_RX_BPDU_Q(q) ((q)<<22)
+
+
+
+#define MV643XX_ETH_PORT_CONFIG_XTEND_R(port) (0x2404 + ((port)<<10))
+#define MV643XX_ETH_CLASSIFY_ENBL (1<<0)
+#define MV643XX_ETH_SPAN_BPDU_PACKETS_AS_NORMAL (0<<1)
+#define MV643XX_ETH_SPAN_BPDU_PACKETS_2_Q7 (1<<1)
+#define MV643XX_ETH_PARTITION_DISBL (0<<2)
+#define MV643XX_ETH_PARTITION_ENBL (1<<2)
+
+#define MV643XX_ETH_SDMA_CONFIG_R(port) (0x241c + ((port)<<10))
+#define MV643XX_ETH_SDMA_RIFB (1<<0)
+#define MV643XX_ETH_RX_BURST_SZ_1_64BIT (0<<1)
+#define MV643XX_ETH_RX_BURST_SZ_2_64BIT (1<<1)
+#define MV643XX_ETH_RX_BURST_SZ_4_64BIT (2<<1)
+#define MV643XX_ETH_RX_BURST_SZ_8_64BIT (3<<1)
+#define MV643XX_ETH_RX_BURST_SZ_16_64BIT (4<<1)
+#define MV643XX_ETH_SMDA_BLM_RX_NO_SWAP (1<<4)
+#define MV643XX_ETH_SMDA_BLM_TX_NO_SWAP (1<<5)
+#define MV643XX_ETH_SMDA_DESC_BYTE_SWAP (1<<6)
+#define MV643XX_ETH_TX_BURST_SZ_1_64BIT (0<<22)
+#define MV643XX_ETH_TX_BURST_SZ_2_64BIT (1<<22)
+#define MV643XX_ETH_TX_BURST_SZ_4_64BIT (2<<22)
+#define MV643XX_ETH_TX_BURST_SZ_8_64BIT (3<<22)
+#define MV643XX_ETH_TX_BURST_SZ_16_64BIT (4<<22)
+
+#define MV643XX_ETH_RX_MIN_FRAME_SIZE_R(port) (0x247c + ((port)<<10))
+
+
+#define MV643XX_ETH_SERIAL_CONTROL_R(port) (0x243c + ((port)<<10))
+#define MV643XX_ETH_SERIAL_PORT_ENBL (1<<0) /* Enable serial port */
+#define MV643XX_ETH_FORCE_LINK_PASS (1<<1)
+#define MV643XX_ETH_DISABLE_AUTO_NEG_FOR_DUPLEX (1<<2)
+#define MV643XX_ETH_DISABLE_AUTO_NEG_FOR_FLOWCTL (1<<3)
+#define MV643XX_ETH_ADVERTISE_SYMMETRIC_FLOWCTL (1<<4)
+#define MV643XX_ETH_FORCE_FC_MODE_TX_PAUSE_DIS (1<<5)
+#define MV643XX_ETH_FORCE_BP_MODE_JAM_TX (1<<7)
+#define MV643XX_ETH_FORCE_BP_MODE_JAM_TX_ON_RX_ERR (1<<8)
+#define MV643XX_ETH_BIT9_UNKNOWN (1<<9) /* unknown purpose; linux sets this */
+#define MV643XX_ETH_FORCE_LINK_FAIL_DISABLE (1<<10)
+#define MV643XX_ETH_RETRANSMIT_FOREVER (1<<11) /* limit to 16 attempts if clear */
+#define MV643XX_ETH_DISABLE_AUTO_NEG_SPEED_GMII (1<<13)
+#define MV643XX_ETH_DTE_ADV_1 (1<<14)
+#define MV643XX_ETH_AUTO_NEG_BYPASS_ENBL (1<<15)
+#define MV643XX_ETH_RESTART_AUTO_NEG (1<<16)
+#define MV643XX_ETH_SC_MAX_RX_1518 (0<<17) /* Limit RX packet size */
+#define MV643XX_ETH_SC_MAX_RX_1522 (1<<17) /* Limit RX packet size */
+#define MV643XX_ETH_SC_MAX_RX_1552 (2<<17) /* Limit RX packet size */
+#define MV643XX_ETH_SC_MAX_RX_9022 (3<<17) /* Limit RX packet size */
+#define MV643XX_ETH_SC_MAX_RX_9192 (4<<17) /* Limit RX packet size */
+#define MV643XX_ETH_SC_MAX_RX_9700 (5<<17) /* Limit RX packet size */
+#define MV643XX_ETH_SC_MAX_RX_MASK (7<<17) /* bitmask */
+#define MV643XX_ETH_SET_EXT_LOOPBACK (1<<20)
+#define MV643XX_ETH_SET_FULL_DUPLEX (1<<21)
+#define MV643XX_ETH_ENBL_FLOWCTL_TX_RX_IN_FD (1<<22) /* enable flow ctrl on rx and tx in full-duplex */
+#define MV643XX_ETH_SET_GMII_SPEED_1000 (1<<23) /* 10/100 if clear */
+#define MV643XX_ETH_SET_MII_SPEED_100 (1<<24) /* 10 if clear */
+
+#define MV643XX_ETH_PORT_STATUS_R(port) (0x2444 + ((port)<<10))
+
+#define MV643XX_ETH_PORT_STATUS_MODE_10_BIT (1<<0)
+#define MV643XX_ETH_PORT_STATUS_LINK_UP (1<<1)
+#define MV643XX_ETH_PORT_STATUS_FDX (1<<2)
+#define MV643XX_ETH_PORT_STATUS_FC (1<<3)
+#define MV643XX_ETH_PORT_STATUS_1000 (1<<4)
+#define MV643XX_ETH_PORT_STATUS_100 (1<<5)
+/* PSR bit 6 unknown */
+#define MV643XX_ETH_PORT_STATUS_TX_IN_PROGRESS (1<<7)
+#define MV643XX_ETH_PORT_STATUS_ANEG_BYPASSED (1<<8)
+#define MV643XX_ETH_PORT_STATUS_PARTITION (1<<9)
+#define MV643XX_ETH_PORT_STATUS_TX_FIFO_EMPTY (1<<10)
+
+#define MV643XX_ETH_MIB_COUNTERS(port) (0x3000 + ((port)<<7))
+#define MV643XX_ETH_NUM_MIB_COUNTERS 32
+
+#define MV643XX_ETH_MIB_GOOD_OCTS_RCVD_LO (0)
+#define MV643XX_ETH_MIB_GOOD_OCTS_RCVD_HI (1<<2)
+#define MV643XX_ETH_MIB_BAD_OCTS_RCVD (2<<2)
+#define MV643XX_ETH_MIB_INTERNAL_MAC_TX_ERR (3<<2)
+#define MV643XX_ETH_MIB_GOOD_FRAMES_RCVD (4<<2)
+#define MV643XX_ETH_MIB_BAD_FRAMES_RCVD (5<<2)
+#define MV643XX_ETH_MIB_BCAST_FRAMES_RCVD (6<<2)
+#define MV643XX_ETH_MIB_MCAST_FRAMES_RCVD (7<<2)
+#define MV643XX_ETH_MIB_FRAMES_64_OCTS (8<<2)
+#define MV643XX_ETH_MIB_FRAMES_65_127_OCTS (9<<2)
+#define MV643XX_ETH_MIB_FRAMES_128_255_OCTS (10<<2)
+#define MV643XX_ETH_MIB_FRAMES_256_511_OCTS (11<<2)
+#define MV643XX_ETH_MIB_FRAMES_512_1023_OCTS (12<<2)
+#define MV643XX_ETH_MIB_FRAMES_1024_MAX_OCTS (13<<2)
+#define MV643XX_ETH_MIB_GOOD_OCTS_SENT_LO (14<<2)
+#define MV643XX_ETH_MIB_GOOD_OCTS_SENT_HI (15<<2)
+#define MV643XX_ETH_MIB_GOOD_FRAMES_SENT (16<<2)
+#define MV643XX_ETH_MIB_EXCESSIVE_COLL (17<<2)
+#define MV643XX_ETH_MIB_MCAST_FRAMES_SENT (18<<2)
+#define MV643XX_ETH_MIB_BCAST_FRAMES_SENT (19<<2)
+#define MV643XX_ETH_MIB_UNREC_MAC_CTRL_RCVD (20<<2)
+#define MV643XX_ETH_MIB_FC_SENT (21<<2)
+#define MV643XX_ETH_MIB_GOOD_FC_RCVD (22<<2)
+#define MV643XX_ETH_MIB_BAD_FC_RCVD (23<<2)
+#define MV643XX_ETH_MIB_UNDERSIZE_RCVD (24<<2)
+#define MV643XX_ETH_MIB_FRAGMENTS_RCVD (25<<2)
+#define MV643XX_ETH_MIB_OVERSIZE_RCVD (26<<2)
+#define MV643XX_ETH_MIB_JABBER_RCVD (27<<2)
+#define MV643XX_ETH_MIB_MAC_RX_ERR (28<<2)
+#define MV643XX_ETH_MIB_BAD_CRC_EVENT (29<<2)
+#define MV643XX_ETH_MIB_COLL (30<<2)
+#define MV643XX_ETH_MIB_LATE_COLL (31<<2)
+
+#define MV643XX_ETH_DA_FILTER_SPECL_MCAST_TBL(port) (0x3400+((port)<<10))
+#define MV643XX_ETH_DA_FILTER_OTHER_MCAST_TBL(port) (0x3500+((port)<<10))
+#define MV643XX_ETH_DA_FILTER_UNICAST_TBL(port) (0x3600+((port)<<10))
+#define MV643XX_ETH_NUM_MCAST_ENTRIES 64
+#define MV643XX_ETH_NUM_UNICAST_ENTRIES 4
+
+#define MV643XX_ETH_BAR_0 (0x2200)
+#define MV643XX_ETH_SIZE_R_0 (0x2204)
+#define MV643XX_ETH_BAR_1 (0x2208)
+#define MV643XX_ETH_SIZE_R_1 (0x220c)
+#define MV643XX_ETH_BAR_2 (0x2210)
+#define MV643XX_ETH_SIZE_R_2 (0x2214)
+#define MV643XX_ETH_BAR_3 (0x2218)
+#define MV643XX_ETH_SIZE_R_3 (0x221c)
+#define MV643XX_ETH_BAR_4 (0x2220)
+#define MV643XX_ETH_SIZE_R_4 (0x2224)
+#define MV643XX_ETH_BAR_5 (0x2228)
+#define MV643XX_ETH_SIZE_R_5 (0x222c)
+#define MV643XX_ETH_NUM_BARS 6
+
+/* Bits in the BAR reg to program cache snooping */
+#define MV64360_ENET2MEM_SNOOP_NONE 0x0000
+#define MV64360_ENET2MEM_SNOOP_WT 0x1000
+#define MV64360_ENET2MEM_SNOOP_WB 0x2000
+#define MV64360_ENET2MEM_SNOOP_MSK 0x3000
+
+
+#define MV643XX_ETH_BAR_ENBL_R (0x2290)
+#define MV643XX_ETH_BAR_DISABLE(bar) (1<<(bar))
+#define MV643XX_ETH_BAR_DISBL_ALL 0x3f
+
+#define MV643XX_ETH_RX_Q0_CURRENT_DESC_PTR(port) (0x260c+((port)<<10))
+#define MV643XX_ETH_RX_Q1_CURRENT_DESC_PTR(port) (0x261c+((port)<<10))
+#define MV643XX_ETH_RX_Q2_CURRENT_DESC_PTR(port) (0x262c+((port)<<10))
+#define MV643XX_ETH_RX_Q3_CURRENT_DESC_PTR(port) (0x263c+((port)<<10))
+#define MV643XX_ETH_RX_Q4_CURRENT_DESC_PTR(port) (0x264c+((port)<<10))
+#define MV643XX_ETH_RX_Q5_CURRENT_DESC_PTR(port) (0x265c+((port)<<10))
+#define MV643XX_ETH_RX_Q6_CURRENT_DESC_PTR(port) (0x266c+((port)<<10))
+#define MV643XX_ETH_RX_Q7_CURRENT_DESC_PTR(port) (0x267c+((port)<<10))
+
+#define MV643XX_ETH_TX_Q0_CURRENT_DESC_PTR(port) (0x26c0+((port)<<10))
+#define MV643XX_ETH_TX_Q1_CURRENT_DESC_PTR(port) (0x26c4+((port)<<10))
+#define MV643XX_ETH_TX_Q2_CURRENT_DESC_PTR(port) (0x26c8+((port)<<10))
+#define MV643XX_ETH_TX_Q3_CURRENT_DESC_PTR(port) (0x26cc+((port)<<10))
+#define MV643XX_ETH_TX_Q4_CURRENT_DESC_PTR(port) (0x26d0+((port)<<10))
+#define MV643XX_ETH_TX_Q5_CURRENT_DESC_PTR(port) (0x26d4+((port)<<10))
+#define MV643XX_ETH_TX_Q6_CURRENT_DESC_PTR(port) (0x26d8+((port)<<10))
+#define MV643XX_ETH_TX_Q7_CURRENT_DESC_PTR(port) (0x26dc+((port)<<10))
+
+#define MV643XX_ETH_MAC_ADDR_LO(port) (0x2414+((port)<<10))
+#define MV643XX_ETH_MAC_ADDR_HI(port) (0x2418+((port)<<10))
+
+/* TYPE DEFINITIONS */
+
+/* just to make the purpose explicit; vars of this
+ * type may need CPU-dependent address translation,
+ * endian conversion etc.
+ */
+typedef uint32_t Dma_addr_t;
+
+typedef volatile struct mveth_rx_desc {
+#ifndef __BIG_ENDIAN__
+#error "descriptor declaration not implemented for little endian machines"
+#endif
+ uint16_t byte_cnt;
+ uint16_t buf_size;
+ uint32_t cmd_sts; /* control and status */
+ Dma_addr_t next_desc_ptr; /* next descriptor (as seen from DMA) */
+ Dma_addr_t buf_ptr;
+ /* fields below here are not used by the chip */
+ void *u_buf; /* user buffer */
+ volatile struct mveth_rx_desc *next; /* next descriptor (CPU address; next_desc_ptr is a DMA address) */
+ uint32_t pad[2];
+} MvEthRxDescRec, *MvEthRxDesc
+__attribute__(( aligned(RING_ALIGNMENT) ));
+
+typedef volatile struct mveth_tx_desc {
+#ifndef __BIG_ENDIAN__
+#error "descriptor declaration not implemented for little endian machines"
+#endif
+ uint16_t byte_cnt;
+ uint16_t l4i_chk;
+ uint32_t cmd_sts; /* control and status */
+ Dma_addr_t next_desc_ptr; /* next descriptor (as seen from DMA) */
+ Dma_addr_t buf_ptr;
+ /* fields below here are not used by the chip */
+ uint32_t workaround[2]; /* use this space to work around the 8byte problem (is this real?) */
+ void *u_buf; /* user buffer */
+ volatile struct mveth_tx_desc *next; /* next descriptor (CPU address; next_desc_ptr is a DMA address) */
+} MvEthTxDescRec, *MvEthTxDesc
+__attribute__(( aligned(RING_ALIGNMENT) ));
+
+/* Assume there are never more then 64k aliasing entries */
+typedef uint16_t Mc_Refcnt[MV643XX_ETH_NUM_MCAST_ENTRIES*4];
+
+/* driver private data and bsdnet interface structure */
+struct mveth_private {
+ MvEthRxDesc rx_ring; /* pointers to aligned ring area */
+ MvEthTxDesc tx_ring; /* pointers to aligned ring area */
+ MvEthRxDesc ring_area; /* allocated ring area */
+ int rbuf_count, xbuf_count; /* saved ring sizes from ifconfig */
+ int port_num;
+ int phy;
+ MvEthRxDesc d_rx_t; /* tail of the RX ring; next received packet */
+ MvEthTxDesc d_tx_t, d_tx_h;
+ uint32_t rx_desc_dma, tx_desc_dma; /* ring address as seen by DMA; (1:1 on this BSP) */
+ int avail;
+ void (*isr)(void*);
+ void *isr_arg;
+ /* Callbacks to handle buffers */
+ void (*cleanup_txbuf)(void*, void*, int); /* callback to cleanup TX buffer */
+ void *cleanup_txbuf_arg;
+ void *(*alloc_rxbuf)(int *psize, uintptr_t *paddr); /* allocate RX buffer */
+ void (*consume_rxbuf)(void*, void*, int); /* callback to consume RX buffer */
+ void *consume_rxbuf_arg;
+ rtems_id tid;
+ uint32_t irq_mask; /* IRQs we use */
+ uint32_t xirq_mask;
+ int promisc;
+ struct {
+ unsigned irqs;
+ unsigned maxchain;
+ unsigned repack;
+ unsigned packet;
+ unsigned odrops; /* no counter in core code */
+ struct {
+ uint64_t good_octs_rcvd; /* 64-bit */
+ uint32_t bad_octs_rcvd;
+ uint32_t internal_mac_tx_err;
+ uint32_t good_frames_rcvd;
+ uint32_t bad_frames_rcvd;
+ uint32_t bcast_frames_rcvd;
+ uint32_t mcast_frames_rcvd;
+ uint32_t frames_64_octs;
+ uint32_t frames_65_127_octs;
+ uint32_t frames_128_255_octs;
+ uint32_t frames_256_511_octs;
+ uint32_t frames_512_1023_octs;
+ uint32_t frames_1024_max_octs;
+ uint64_t good_octs_sent; /* 64-bit */
+ uint32_t good_frames_sent;
+ uint32_t excessive_coll;
+ uint32_t mcast_frames_sent;
+ uint32_t bcast_frames_sent;
+ uint32_t unrec_mac_ctrl_rcvd;
+ uint32_t fc_sent;
+ uint32_t good_fc_rcvd;
+ uint32_t bad_fc_rcvd;
+ uint32_t undersize_rcvd;
+ uint32_t fragments_rcvd;
+ uint32_t oversize_rcvd;
+ uint32_t jabber_rcvd;
+ uint32_t mac_rx_err;
+ uint32_t bad_crc_event;
+ uint32_t coll;
+ uint32_t late_coll;
+ } mib;
+ } stats;
+ struct {
+ Mc_Refcnt specl, other;
+ } mc_refcnt;
+};
+
+/* stuff needed for bsdnet support */
+struct mveth_bsdsupp {
+ int oif_flags; /* old / cached if_flags */
+};
+
+struct mveth_softc {
+ struct arpcom arpcom;
+ struct mveth_bsdsupp bsd;
+ struct mveth_private pvt;
+};
+
+/* GLOBAL VARIABLES */
+#ifdef MVETH_DEBUG_TX_DUMP
+int mveth_tx_dump = 0;
+#endif
+
+/* THE array of driver/bsdnet structs */
+
+/* If detaching/module unloading is enabled, the main driver data
+ * structure must remain in memory; hence it must reside in its own
+ * 'dummy' module...
+ */
+#ifdef MVETH_DETACH_HACK
+extern
+#else
+STATIC
+#endif
+struct mveth_softc theMvEths[MV643XXETH_NUM_DRIVER_SLOTS]
+#ifndef MVETH_DETACH_HACK
+= {{{{0}},}}
+#endif
+;
+
+/* daemon task id */
+STATIC rtems_id mveth_tid = 0;
+/* register access protection mutex */
+STATIC rtems_id mveth_mtx = 0;
+#define REGLOCK() do { \
+ if ( RTEMS_SUCCESSFUL != rtems_semaphore_obtain(mveth_mtx, RTEMS_WAIT, RTEMS_NO_TIMEOUT) ) \
+ rtems_panic(DRVNAME": unable to lock register protection mutex"); \
+ } while (0)
+#define REGUNLOCK() rtems_semaphore_release(mveth_mtx)
+
+/* Format strings for statistics messages */
+static const char *mibfmt[] = {
+ " GOOD_OCTS_RCVD: %"PRIu64"\n",
+ 0,
+ " BAD_OCTS_RCVD: %"PRIu32"\n",
+ " INTERNAL_MAC_TX_ERR: %"PRIu32"\n",
+ " GOOD_FRAMES_RCVD: %"PRIu32"\n",
+ " BAD_FRAMES_RCVD: %"PRIu32"\n",
+ " BCAST_FRAMES_RCVD: %"PRIu32"\n",
+ " MCAST_FRAMES_RCVD: %"PRIu32"\n",
+ " FRAMES_64_OCTS: %"PRIu32"\n",
+ " FRAMES_65_127_OCTS: %"PRIu32"\n",
+ " FRAMES_128_255_OCTS: %"PRIu32"\n",
+ " FRAMES_256_511_OCTS: %"PRIu32"\n",
+ " FRAMES_512_1023_OCTS:%"PRIu32"\n",
+ " FRAMES_1024_MAX_OCTS:%"PRIu32"\n",
+ " GOOD_OCTS_SENT: %"PRIu64"\n",
+ 0,
+ " GOOD_FRAMES_SENT: %"PRIu32"\n",
+ " EXCESSIVE_COLL: %"PRIu32"\n",
+ " MCAST_FRAMES_SENT: %"PRIu32"\n",
+ " BCAST_FRAMES_SENT: %"PRIu32"\n",
+ " UNREC_MAC_CTRL_RCVD: %"PRIu32"\n",
+ " FC_SENT: %"PRIu32"\n",
+ " GOOD_FC_RCVD: %"PRIu32"\n",
+ " BAD_FC_RCVD: %"PRIu32"\n",
+ " UNDERSIZE_RCVD: %"PRIu32"\n",
+ " FRAGMENTS_RCVD: %"PRIu32"\n",
+ " OVERSIZE_RCVD: %"PRIu32"\n",
+ " JABBER_RCVD: %"PRIu32"\n",
+ " MAC_RX_ERR: %"PRIu32"\n",
+ " BAD_CRC_EVENT: %"PRIu32"\n",
+ " COLL: %"PRIu32"\n",
+ " LATE_COLL: %"PRIu32"\n",
+};
+
+/* Interrupt Handler Connection */
+
+/* forward decls + implementation for IRQ API funcs */
+
+static void mveth_isr(rtems_irq_hdl_param unit);
+static void mveth_isr_1(rtems_irq_hdl_param unit);
+static void noop(const rtems_irq_connect_data *unused) {}
+static int noop1(const rtems_irq_connect_data *unused) { return 0; }
+
+static rtems_irq_connect_data irq_data[MAX_NUM_SLOTS] = {
+ {
+ BSP_IRQ_ETH0,
+ 0,
+ (rtems_irq_hdl_param)0,
+ noop,
+ noop,
+ noop1
+ },
+ {
+ BSP_IRQ_ETH1,
+ 0,
+ (rtems_irq_hdl_param)1,
+ noop,
+ noop,
+ noop1
+ },
+ {
+ BSP_IRQ_ETH2,
+ 0,
+ (rtems_irq_hdl_param)2,
+ noop,
+ noop,
+ noop1
+ },
+};
+
+/* MII Ioctl Interface */
+
+STATIC unsigned
+mveth_mii_read(struct mveth_private *mp, unsigned addr);
+
+STATIC unsigned
+mveth_mii_write(struct mveth_private *mp, unsigned addr, unsigned v);
+
+
+/* mdio / mii interface wrappers for rtems_mii_ioctl API */
+
+static int mveth_mdio_r(int phy, void *uarg, unsigned reg, uint32_t *pval)
+{
+ if ( phy > 1 )
+ return -1;
+
+ *pval = mveth_mii_read(uarg, reg);
+ return 0;
+}
+
+static int mveth_mdio_w(int phy, void *uarg, unsigned reg, uint32_t val)
+{
+ if ( phy > 1 )
+ return -1;
+ mveth_mii_write(uarg, reg, val);
+ return 0;
+}
+
+static struct rtems_mdio_info mveth_mdio = {
+ mdio_r: mveth_mdio_r,
+ mdio_w: mveth_mdio_w,
+ has_gmii: 1,
+};
+
+/* LOW LEVEL SUPPORT ROUTINES */
+
+/* Software Cache Coherency */
+#ifndef ENABLE_HW_SNOOPING
+#ifndef __PPC__
+#error "Software cache coherency maintenance is not implemented for your CPU architecture"
+#endif
+
+static inline unsigned INVAL_DESC(volatile void *d)
+{
+typedef const char cache_line[PPC_CACHE_ALIGNMENT];
+ asm volatile("dcbi 0, %1":"=m"(*(cache_line*)d):"r"(d));
+ return (unsigned)d; /* so this can be used in comma expression */
+}
+
+static inline void FLUSH_DESC(volatile void *d)
+{
+typedef const char cache_line[PPC_CACHE_ALIGNMENT];
+ asm volatile("dcbf 0, %0"::"r"(d),"m"(*(cache_line*)d));
+}
+
+static inline void FLUSH_BARRIER(void)
+{
+ asm volatile("eieio");
+}
+
+/* RX buffers are always cache-line aligned
+ * ASSUMPTIONS:
+ * - 'addr' is cache aligned
+ * - len is a multiple >0 of cache lines
+ */
+static inline void INVAL_BUF(register uintptr_t addr, register int len)
+{
+typedef char maxbuf[2048]; /* more than an ethernet packet */
+ do {
+ len -= RX_BUF_ALIGNMENT;
+ asm volatile("dcbi %0, %1"::"b"(addr),"r"(len));
+ } while (len > 0);
+ asm volatile("":"=m"(*(maxbuf*)addr));
+}
+
+/* Flushing TX buffers is a little bit trickier; we don't really know their
+ * alignment but *assume* adjacent addresses are covering 'ordinary' memory
+ * so that flushing them does no harm!
+ */
+static inline void FLUSH_BUF(register uintptr_t addr, register int len)
+{
+typedef char maxbuf[2048]; /* more than an ethernet packet */
+ asm volatile("":::"memory");
+ len = _ALIGN(len, RX_BUF_ALIGNMENT);
+ do {
+ asm volatile("dcbf %0, %1"::"b"(addr),"r"(len));
+ len -= RX_BUF_ALIGNMENT;
+ } while ( len >= 0 );
+}
+
+#else /* hardware snooping enabled */
+
+/* inline this to silence compiler warnings */
+static inline int INVAL_DESC(volatile void *d)
+{ return 0; }
+
+#define FLUSH_DESC(d) NOOP()
+#define INVAL_BUF(b,l) NOOP()
+#define FLUSH_BUF(b,l) NOOP()
+#define FLUSH_BARRIER() NOOP()
+
+#endif /* cache coherency support */
+
+/* Synchronize memory access */
+#ifdef __PPC__
+static inline void membarrier(void)
+{
+ asm volatile("sync":::"memory");
+}
+#else
+#error "memory barrier instruction not defined (yet) for this CPU"
+#endif
+
+/* Enable and disable interrupts at the device */
+static inline void
+mveth_enable_irqs(struct mveth_private *mp, uint32_t mask)
+{
+rtems_interrupt_level l;
+uint32_t val;
+ rtems_interrupt_disable(l);
+
+ val = MV_READ(MV643XX_ETH_INTERRUPT_ENBL_R(mp->port_num));
+ val = (val | mask | MV643XX_ETH_IRQ_EXT_ENA) & mp->irq_mask;
+
+ MV_WRITE(MV643XX_ETH_INTERRUPT_ENBL_R(mp->port_num), val);
+
+ val = MV_READ(MV643XX_ETH_INTERRUPT_EXTEND_ENBL_R(mp->port_num));
+ val = (val | mask) & mp->xirq_mask;
+ MV_WRITE(MV643XX_ETH_INTERRUPT_EXTEND_ENBL_R(mp->port_num), val);
+
+ rtems_interrupt_enable(l);
+}
+
+static inline uint32_t
+mveth_disable_irqs(struct mveth_private *mp, uint32_t mask)
+{
+rtems_interrupt_level l;
+uint32_t val,xval,tmp;
+ rtems_interrupt_disable(l);
+
+ val = MV_READ(MV643XX_ETH_INTERRUPT_ENBL_R(mp->port_num));
+ tmp = ( (val & ~mask) | MV643XX_ETH_IRQ_EXT_ENA ) & mp->irq_mask;
+ MV_WRITE(MV643XX_ETH_INTERRUPT_ENBL_R(mp->port_num), tmp);
+
+ xval = MV_READ(MV643XX_ETH_INTERRUPT_EXTEND_ENBL_R(mp->port_num));
+ tmp = (xval & ~mask) & mp->xirq_mask;
+ MV_WRITE(MV643XX_ETH_INTERRUPT_EXTEND_ENBL_R(mp->port_num), tmp);
+
+ rtems_interrupt_enable(l);
+
+ return (val | xval);
+}
+
+/* This should be safe even w/o turning off interrupts if multiple
+ * threads ack different bits in the cause register (and ignore
+ * other ones) since writing 'ones' into the cause register doesn't
+ * 'stick'.
+ */
+
+static inline uint32_t
+mveth_ack_irqs(struct mveth_private *mp, uint32_t mask)
+{
+register uint32_t x,xe,p;
+
+ p = mp->port_num;
+ /* Get cause */
+ x = MV_READ(MV643XX_ETH_INTERRUPT_CAUSE_R(p));
+
+ /* Ack interrupts filtering the ones we're interested in */
+
+ /* Note: EXT_IRQ bit clears by itself if EXT interrupts are cleared */
+ MV_WRITE(MV643XX_ETH_INTERRUPT_CAUSE_R(p), ~ (x & mp->irq_mask & mask));
+
+ /* linux driver tests 1<<1 as a summary bit for extended interrupts;
+ * the mv64360 seems to use 1<<19 for that purpose; for the moment,
+ * I just check both.
+ * Update: link status irq (1<<16 in xe) doesn't set (1<<19) in x!
+ */
+ if ( 1 /* x & 2 */ )
+ {
+ xe = MV_READ(MV643XX_ETH_INTERRUPT_EXTEND_CAUSE_R(p));
+
+ MV_WRITE(MV643XX_ETH_INTERRUPT_EXTEND_CAUSE_R(p), ~ (xe & mp->xirq_mask & mask));
+ } else {
+ xe = 0;
+ }
+#ifdef MVETH_TESTING
+ if ( ((x & MV643XX_ETH_ALL_IRQS) & ~MV643XX_ETH_KNOWN_IRQS)
+ || ((xe & MV643XX_ETH_ALL_EXT_IRQS) & ~MV643XX_ETH_KNOWN_EXT_IRQS) ) {
+ fprintf(stderr, "Unknown IRQs detected; leaving all disabled for debugging:\n");
+ fprintf(stderr, "Cause reg was 0x%08x, ext cause 0x%08x\n", x, xe);
+ mp->irq_mask = 0;
+ mp->xirq_mask = 0;
+ }
+#endif
+ /* luckily, the extended and 'normal' interrupts we use don't overlap so
+ * we can just OR them into a single word
+ */
+ return (xe & mp->xirq_mask) | (x & mp->irq_mask);
+}
+
+static void mveth_isr(rtems_irq_hdl_param arg)
+{
+unsigned unit = (unsigned)arg;
+ mveth_disable_irqs(&theMvEths[unit].pvt, -1);
+ theMvEths[unit].pvt.stats.irqs++;
+ rtems_event_send( theMvEths[unit].pvt.tid, 1<<unit );
+}
+
+static void mveth_isr_1(rtems_irq_hdl_param arg)
+{
+unsigned unit = (unsigned)arg;
+struct mveth_private *mp = &theMvEths[unit].pvt;
+
+ mp->stats.irqs++;
+ mp->isr(mp->isr_arg);
+}
+
+static void
+mveth_clear_mib_counters(struct mveth_private *mp)
+{
+register int i;
+register uint32_t b;
+ /* reading the counters resets them */
+ b = MV643XX_ETH_MIB_COUNTERS(mp->port_num);
+ for (i=0; i< MV643XX_ETH_NUM_MIB_COUNTERS; i++, b+=4)
+ (void)MV_READ(b);
+}
+
+/* Reading a MIB register also clears it. Hence we read the lo
+ * register first, then the hi one. Correct reading is guaranteed since
+ * the 'lo' register cannot overflow after it is read since it had
+ * been reset to 0.
+ */
+static unsigned long long
+read_long_mib_counter(int port_num, int idx)
+{
+unsigned long lo;
+unsigned long long hi;
+ lo = MV_READ(MV643XX_ETH_MIB_COUNTERS(port_num)+(idx<<2));
+ idx++;
+ hi = MV_READ(MV643XX_ETH_MIB_COUNTERS(port_num)+(idx<<2));
+ return (hi<<32) | lo;
+}
+
+static inline unsigned long
+read_mib_counter(int port_num, int idx)
+{
+ return MV_READ(MV643XX_ETH_MIB_COUNTERS(port_num)+(idx<<2));
+}
+
+
+/* write ethernet address from buffer to hardware (need to change unicast filter after this) */
+static void
+mveth_write_eaddr(struct mveth_private *mp, unsigned char *eaddr)
+{
+int i;
+uint32_t x;
+
+ /* build hi word */
+ for (i=4,x=0; i; i--, eaddr++) {
+ x = (x<<8) | *eaddr;
+ }
+ MV_WRITE(MV643XX_ETH_MAC_ADDR_HI(mp->port_num), x);
+
+ /* build lo word */
+ for (i=2,x=0; i; i--, eaddr++) {
+ x = (x<<8) | *eaddr;
+ }
+ MV_WRITE(MV643XX_ETH_MAC_ADDR_LO(mp->port_num), x);
+}
+
+/* PHY/MII Interface
+ *
+ * Read/write a PHY register;
+ *
+ * NOTE: The SMI register is shared among the three devices.
+ * Protection is provided by the global networking semaphore.
+ * If non-bsd drivers are running on a subset of IFs proper
+ * locking of all shared registers must be implemented!
+ */
+STATIC unsigned
+mveth_mii_read(struct mveth_private *mp, unsigned addr)
+{
+unsigned v;
+unsigned wc = 0;
+
+ addr &= 0x1f;
+
+ /* wait until not busy */
+ do {
+ v = MV_READ(MV643XX_ETH_SMI_R);
+ wc++;
+ } while ( MV643XX_ETH_SMI_BUSY & v );
+
+ MV_WRITE(MV643XX_ETH_SMI_R, (addr <<21 ) | (mp->phy<<16) | MV643XX_ETH_SMI_OP_RD );
+
+ do {
+ v = MV_READ(MV643XX_ETH_SMI_R);
+ wc++;
+ } while ( MV643XX_ETH_SMI_BUSY & v );
+
+ if (wc>0xffff)
+ wc = 0xffff;
+ return (wc<<16) | (v & 0xffff);
+}
+
+STATIC unsigned
+mveth_mii_write(struct mveth_private *mp, unsigned addr, unsigned v)
+{
+unsigned wc = 0;
+
+ addr &= 0x1f;
+ v &= 0xffff;
+
+ /* busywait is ugly but not preventing ISRs or high priority tasks from
+ * preempting us
+ */
+
+ /* wait until not busy */
+ while ( MV643XX_ETH_SMI_BUSY & MV_READ(MV643XX_ETH_SMI_R) )
+ wc++ /* wait */;
+
+ MV_WRITE(MV643XX_ETH_SMI_R, (addr <<21 ) | (mp->phy<<16) | MV643XX_ETH_SMI_OP_WR | v );
+
+ return wc;
+}
+
+/* MID-LAYER SUPPORT ROUTINES */
+
+/* Stop TX and wait for the command queues to stop and the fifo to drain */
+static uint32_t
+mveth_stop_tx(int port)
+{
+uint32_t active_q;
+
+ active_q = (MV_READ(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_R(port)) & MV643XX_ETH_TX_ANY_RUNNING);
+
+ if ( active_q ) {
+ /* Halt TX and wait for activity to stop */
+ MV_WRITE(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_R(port), MV643XX_ETH_TX_STOP_ALL);
+ while ( MV643XX_ETH_TX_ANY_RUNNING & MV_READ(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_R(port)) )
+ /* poll-wait */;
+ /* Wait for Tx FIFO to drain */
+ while ( ! (MV643XX_ETH_PORT_STATUS_R(port) & MV643XX_ETH_PORT_STATUS_TX_FIFO_EMPTY) )
+ /* poll-wait */;
+ }
+
+ return active_q;
+}
+
+/* update serial port settings from current link status */
+static void
+mveth_update_serial_port(struct mveth_private *mp, int media)
+{
+int port = mp->port_num;
+uint32_t old, new;
+
+ new = old = MV_READ(MV643XX_ETH_SERIAL_CONTROL_R(port));
+
+ /* mask speed and duplex settings */
+ new &= ~( MV643XX_ETH_SET_GMII_SPEED_1000
+ | MV643XX_ETH_SET_MII_SPEED_100
+ | MV643XX_ETH_SET_FULL_DUPLEX );
+
+ if ( IFM_FDX & media )
+ new |= MV643XX_ETH_SET_FULL_DUPLEX;
+
+ switch ( IFM_SUBTYPE(media) ) {
+ default: /* treat as 10 */
+ break;
+ case IFM_100_TX:
+ new |= MV643XX_ETH_SET_MII_SPEED_100;
+ break;
+ case IFM_1000_T:
+ new |= MV643XX_ETH_SET_GMII_SPEED_1000;
+ break;
+ }
+
+ if ( new != old ) {
+ if ( ! (MV643XX_ETH_SERIAL_PORT_ENBL & new) ) {
+ /* just write */
+ MV_WRITE(MV643XX_ETH_SERIAL_CONTROL_R(port), new);
+ } else {
+ uint32_t were_running;
+
+ were_running = mveth_stop_tx(port);
+
+ old &= ~MV643XX_ETH_SERIAL_PORT_ENBL;
+ MV_WRITE(MV643XX_ETH_SERIAL_CONTROL_R(port), old);
+ MV_WRITE(MV643XX_ETH_SERIAL_CONTROL_R(port), new);
+ /* linux driver writes twice... */
+ MV_WRITE(MV643XX_ETH_SERIAL_CONTROL_R(port), new);
+
+ if ( were_running ) {
+ MV_WRITE(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_R(mp->port_num), MV643XX_ETH_TX_START(0));
+ }
+ }
+ }
+}
+
+/* Clear multicast filters */
+void
+BSP_mve_mcast_filter_clear(struct mveth_private *mp)
+{
+int i;
+register uint32_t s,o;
+uint32_t v = mp->promisc ? 0x01010101 : 0x00000000;
+ s = MV643XX_ETH_DA_FILTER_SPECL_MCAST_TBL(mp->port_num);
+ o = MV643XX_ETH_DA_FILTER_OTHER_MCAST_TBL(mp->port_num);
+ for (i=0; i<MV643XX_ETH_NUM_MCAST_ENTRIES; i++) {
+ MV_WRITE(s,v);
+ MV_WRITE(o,v);
+ s+=4;
+ o+=4;
+ }
+ for (i=0; i<sizeof(mp->mc_refcnt.specl)/sizeof(mp->mc_refcnt.specl[0]); i++) {
+ mp->mc_refcnt.specl[i] = 0;
+ mp->mc_refcnt.other[i] = 0;
+ }
+}
+
+void
+BSP_mve_mcast_filter_accept_all(struct mveth_private *mp)
+{
+int i;
+register uint32_t s,o;
+ s = MV643XX_ETH_DA_FILTER_SPECL_MCAST_TBL(mp->port_num);
+ o = MV643XX_ETH_DA_FILTER_OTHER_MCAST_TBL(mp->port_num);
+ for (i=0; i<MV643XX_ETH_NUM_MCAST_ENTRIES; i++) {
+ MV_WRITE(s,0x01010101);
+ MV_WRITE(o,0x01010101);
+ s+=4;
+ o+=4;
+ /* Not clear what we should do with the reference count.
+ * For now just increment it.
+ */
+ for (i=0; i<sizeof(mp->mc_refcnt.specl)/sizeof(mp->mc_refcnt.specl[0]); i++) {
+ mp->mc_refcnt.specl[i]++;
+ mp->mc_refcnt.other[i]++;
+ }
+ }
+}
+
+static void add_entry(uint32_t off, uint8_t hash, Mc_Refcnt *refcnt)
+{
+uint32_t val;
+uint32_t slot = hash & 0xfc;
+
+ if ( 0 == (*refcnt)[hash]++ ) {
+ val = MV_READ(off+slot) | ( 1 << ((hash&3)<<3) );
+ MV_WRITE(off+slot, val);
+ }
+}
+
+static void del_entry(uint32_t off, uint8_t hash, Mc_Refcnt *refcnt)
+{
+uint32_t val;
+uint32_t slot = hash & 0xfc;
+
+ if ( (*refcnt)[hash] > 0 && 0 == --(*refcnt)[hash] ) {
+ val = MV_READ(off+slot) & ~( 1 << ((hash&3)<<3) );
+ MV_WRITE(off+slot, val);
+ }
+}
+
+void
+BSP_mve_mcast_filter_accept_add(struct mveth_private *mp, unsigned char *enaddr)
+{
+uint32_t hash;
+static const char spec[]={0x01,0x00,0x5e,0x00,0x00};
+static const char bcst[]={0xff,0xff,0xff,0xff,0xff,0xff};
+uint32_t tabl;
+Mc_Refcnt *refcnt;
+
+ if ( ! (0x01 & enaddr[0]) ) {
+ /* not a multicast address; ignore */
+ return;
+ }
+
+ if ( 0 == memcmp(enaddr, bcst, sizeof(bcst)) ) {
+ /* broadcast address; ignore */
+ return;
+ }
+
+ if ( 0 == memcmp(enaddr, spec, sizeof(spec)) ) {
+ hash = enaddr[5];
+ tabl = MV643XX_ETH_DA_FILTER_SPECL_MCAST_TBL(mp->port_num);
+ refcnt = &mp->mc_refcnt.specl;
+ } else {
+ uint32_t test, mask;
+ int i;
+ /* algorithm used by linux driver */
+ for ( hash=0, i=0; i<6; i++ ) {
+ hash = (hash ^ enaddr[i]) << 8;
+ for ( test=0x8000, mask=0x8380; test>0x0080; test>>=1, mask>>=1 ) {
+ if ( hash & test )
+ hash ^= mask;
+ }
+ }
+ tabl = MV643XX_ETH_DA_FILTER_OTHER_MCAST_TBL(mp->port_num);
+ refcnt = &mp->mc_refcnt.other;
+ }
+ add_entry(tabl, hash, refcnt);
+}
+
+void
+BSP_mve_mcast_filter_accept_del(struct mveth_private *mp, unsigned char *enaddr)
+{
+uint32_t hash;
+static const char spec[]={0x01,0x00,0x5e,0x00,0x00};
+static const char bcst[]={0xff,0xff,0xff,0xff,0xff,0xff};
+uint32_t tabl;
+Mc_Refcnt *refcnt;
+
+ if ( ! (0x01 & enaddr[0]) ) {
+ /* not a multicast address; ignore */
+ return;
+ }
+
+ if ( 0 == memcmp(enaddr, bcst, sizeof(bcst)) ) {
+ /* broadcast address; ignore */
+ return;
+ }
+
+ if ( 0 == memcmp(enaddr, spec, sizeof(spec)) ) {
+ hash = enaddr[5];
+ tabl = MV643XX_ETH_DA_FILTER_SPECL_MCAST_TBL(mp->port_num);
+ refcnt = &mp->mc_refcnt.specl;
+ } else {
+ uint32_t test, mask;
+ int i;
+ /* algorithm used by linux driver */
+ for ( hash=0, i=0; i<6; i++ ) {
+ hash = (hash ^ enaddr[i]) << 8;
+ for ( test=0x8000, mask=0x8380; test>0x0080; test>>=1, mask>>=1 ) {
+ if ( hash & test )
+ hash ^= mask;
+ }
+ }
+ tabl = MV643XX_ETH_DA_FILTER_OTHER_MCAST_TBL(mp->port_num);
+ refcnt = &mp->mc_refcnt.other;
+ }
+ del_entry(tabl, hash, refcnt);
+}
+
+/* Clear all address filters (multi- and unicast) */
+static void
+mveth_clear_addr_filters(struct mveth_private *mp)
+{
+register int i;
+register uint32_t u;
+ u = MV643XX_ETH_DA_FILTER_UNICAST_TBL(mp->port_num);
+ for (i=0; i<MV643XX_ETH_NUM_UNICAST_ENTRIES; i++) {
+ MV_WRITE(u,0);
+ u+=4;
+ }
+ BSP_mve_mcast_filter_clear(mp);
+}
+
+/* Setup unicast filter for a given MAC address (least significant nibble) */
+static void
+mveth_ucfilter(struct mveth_private *mp, unsigned char mac_lsbyte, int accept)
+{
+unsigned nib, slot, bit;
+uint32_t val;
+ /* compute slot in table */
+ nib = mac_lsbyte & 0xf; /* strip nibble */
+ slot = nib & ~3; /* (nibble/4)*4 */
+ bit = (nib & 3)<<3; /* 8*(nibble % 4) */
+ val = MV_READ(MV643XX_ETH_DA_FILTER_UNICAST_TBL(mp->port_num) + slot);
+ if ( accept ) {
+ val |= 0x01 << bit;
+ } else {
+ val &= 0x0e << bit;
+ }
+ MV_WRITE(MV643XX_ETH_DA_FILTER_UNICAST_TBL(mp->port_num) + slot, val);
+}
+
+#if defined( ENABLE_TX_WORKAROUND_8_BYTE_PROBLEM ) && 0
+/* Currently unused; small unaligned buffers seem to be rare
+ * so we just use memcpy()...
+ */
+
+/* memcpy for 0..7 bytes; arranged so that gcc
+ * optimizes for powerpc...
+ */
+
+static inline void memcpy8(void *to, void *fr, unsigned x)
+{
+register uint8_t *d = to, *s = fro;
+
+ d+=l; s+=l;
+ if ( l & 1 ) {
+ *--d=*--s;
+ }
+ if ( l & 2 ) {
+ /* pre-decrementing causes gcc to use auto-decrementing
+ * PPC instructions (lhzu rx, -2(ry))
+ */
+ d-=2; s-=2;
+ /* use memcpy; don't cast to short -- accessing
+ * misaligned data as short is not portable
+ * (but it works on PPC).
+ */
+ __builtin_memcpy(d,s,2);
+ }
+ if ( l & 4 ) {
+ d-=4; s-=4;
+ /* see above */
+ __builtin_memcpy(d,s,4);
+ }
+}
+#endif
+
+/* Assign values (buffer + user data) to a tx descriptor slot */
+static int
+mveth_assign_desc(MvEthTxDesc d, struct mbuf *m, unsigned long extra)
+{
+int rval = (d->byte_cnt = m->m_len);
+
+#ifdef MVETH_TESTING
+ assert( !d->mb );
+ assert( m->m_len );
+#endif
+
+ /* set CRC on all descriptors; seems to be necessary */
+ d->cmd_sts = extra | (TDESC_GEN_CRC | TDESC_ZERO_PAD);
+
+#ifdef ENABLE_TX_WORKAROUND_8_BYTE_PROBLEM
+ /* The buffer must be 64bit aligned if the payload is <8 (??) */
+ if ( rval < 8 && ((mtod(m, uintptr_t)) & 7) ) {
+ d->buf_ptr = CPUADDR2ENET( d->workaround );
+ memcpy((void*)d->workaround, mtod(m, void*), rval);
+ } else
+#endif
+ {
+ d->buf_ptr = CPUADDR2ENET( mtod(m, unsigned long) );
+ }
+ d->l4i_chk = 0;
+ return rval;
+}
+
+static int
+mveth_assign_desc_raw(MvEthTxDesc d, void *buf, int len, unsigned long extra)
+{
+int rval = (d->byte_cnt = len);
+
+#ifdef MVETH_TESTING
+ assert( !d->u_buf );
+ assert( len );
+#endif
+
+ /* set CRC on all descriptors; seems to be necessary */
+ d->cmd_sts = extra | (TDESC_GEN_CRC | TDESC_ZERO_PAD);
+
+#ifdef ENABLE_TX_WORKAROUND_8_BYTE_PROBLEM
+ /* The buffer must be 64bit aligned if the payload is <8 (??) */
+ if ( rval < 8 && ( ((uintptr_t)buf) & 7) ) {
+ d->buf_ptr = CPUADDR2ENET( d->workaround );
+ memcpy((void*)d->workaround, buf, rval);
+ } else
+#endif
+ {
+ d->buf_ptr = CPUADDR2ENET( (unsigned long)buf );
+ }
+ d->l4i_chk = 0;
+ return rval;
+}
+
+/*
+ * Ring Initialization
+ *
+ * ENDIAN ASSUMPTION: DMA engine matches CPU endianness (???)
+ *
+ * Linux driver discriminates __LITTLE and __BIG endian for re-arranging
+ * the u16 fields in the descriptor structs. However, no endian conversion
+ * is done on the individual fields (SDMA byte swapping is disabled on LE).
+ */
+
+STATIC int
+mveth_init_rx_desc_ring(struct mveth_private *mp)
+{
+int i,sz;
+MvEthRxDesc d;
+uintptr_t baddr;
+
+ memset((void*)mp->rx_ring, 0, sizeof(*mp->rx_ring)*mp->rbuf_count);
+
+ mp->rx_desc_dma = CPUADDR2ENET(mp->rx_ring);
+
+ for ( i=0, d = mp->rx_ring; i<mp->rbuf_count; i++, d++ ) {
+ d->u_buf = mp->alloc_rxbuf(&sz, &baddr);
+ assert( d->u_buf );
+
+#ifndef ENABLE_HW_SNOOPING
+ /* could reduce the area to max. ethernet packet size */
+ INVAL_BUF(baddr, sz);
+#endif
+
+ d->buf_size = sz;
+ d->byte_cnt = 0;
+ d->cmd_sts = RDESC_DMA_OWNED | RDESC_INT_ENA;
+ d->next = mp->rx_ring + (i+1) % mp->rbuf_count;
+
+ d->buf_ptr = CPUADDR2ENET( baddr );
+ d->next_desc_ptr = CPUADDR2ENET(d->next);
+ FLUSH_DESC(d);
+ }
+ FLUSH_BARRIER();
+
+ mp->d_rx_t = mp->rx_ring;
+
+ /* point the chip to the start of the ring */
+ MV_WRITE(MV643XX_ETH_RX_Q0_CURRENT_DESC_PTR(mp->port_num),mp->rx_desc_dma);
+
+
+ return i;
+}
+
+STATIC int
+mveth_init_tx_desc_ring(struct mveth_private *mp)
+{
+int i;
+MvEthTxDesc d;
+
+ memset((void*)mp->tx_ring, 0, sizeof(*mp->tx_ring)*mp->xbuf_count);
+
+ /* DMA and CPU live in the same address space (rtems) */
+ mp->tx_desc_dma = CPUADDR2ENET(mp->tx_ring);
+ mp->avail = TX_AVAILABLE_RING_SIZE(mp);
+
+ for ( i=0, d=mp->tx_ring; i<mp->xbuf_count; i++,d++ ) {
+ d->l4i_chk = 0;
+ d->byte_cnt = 0;
+ d->cmd_sts = 0;
+ d->buf_ptr = 0;
+
+ d->next = mp->tx_ring + (i+1) % mp->xbuf_count;
+ d->next_desc_ptr = CPUADDR2ENET(d->next);
+ FLUSH_DESC(d);
+ }
+ FLUSH_BARRIER();
+
+ mp->d_tx_h = mp->d_tx_t = mp->tx_ring;
+
+ /* point the chip to the start of the ring */
+ MV_WRITE(MV643XX_ETH_TX_Q0_CURRENT_DESC_PTR(mp->port_num),mp->tx_desc_dma);
+
+ return i;
+}
+
+/* PUBLIC LOW-LEVEL DRIVER ACCESS */
+
+static struct mveth_private *
+mve_setup_internal(
+ int unit,
+ rtems_id tid,
+ void (*isr)(void*isr_arg),
+ void *isr_arg,
+ void (*cleanup_txbuf)(void *user_buf, void *closure, 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 *closure, int len),
+ void *consume_rxbuf_arg,
+ int rx_ring_size,
+ int tx_ring_size,
+ int irq_mask
+)
+
+{
+struct mveth_private *mp;
+struct ifnet *ifp;
+int InstallISRSuccessful;
+
+ if ( unit <= 0 || unit > MV643XXETH_NUM_DRIVER_SLOTS ) {
+ printk(DRVNAME": Bad unit number %i; must be 1..%i\n", unit, MV643XXETH_NUM_DRIVER_SLOTS);
+ return 0;
+ }
+ ifp = &theMvEths[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;
+
+ if ( MV_64360 != BSP_getDiscoveryVersion(0) ) {
+ printk(DRVNAME": not mv64360 chip\n");
+ return 0;
+ }
+
+ /* lazy init of mutex (non thread-safe! - we assume 1st initialization is single-threaded) */
+ if ( ! mveth_mtx ) {
+ rtems_status_code sc;
+ sc = rtems_semaphore_create(
+ rtems_build_name('m','v','e','X'),
+ 1,
+ RTEMS_BINARY_SEMAPHORE | RTEMS_PRIORITY | RTEMS_INHERIT_PRIORITY | RTEMS_DEFAULT_ATTRIBUTES,
+ 0,
+ &mveth_mtx);
+ if ( RTEMS_SUCCESSFUL != sc ) {
+ rtems_error(sc,DRVNAME": creating mutex\n");
+ rtems_panic("unable to proceed\n");
+ }
+ }
+
+ mp = &theMvEths[unit-1].pvt;
+
+ memset(mp, 0, sizeof(*mp));
+
+ mp->port_num = unit-1;
+ mp->phy = (MV_READ(MV643XX_ETH_PHY_ADDR_R) >> (5*mp->port_num)) & 0x1f;
+
+ mp->tid = tid;
+ mp->isr = isr;
+ mp->isr_arg = isr_arg;
+
+ 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;
+
+ mp->rbuf_count = rx_ring_size ? rx_ring_size : MV643XX_RX_RING_SIZE;
+ mp->xbuf_count = tx_ring_size ? tx_ring_size : MV643XX_TX_RING_SIZE;
+
+ if ( mp->xbuf_count > 0 )
+ mp->xbuf_count += TX_NUM_TAG_SLOTS;
+
+ if ( mp->rbuf_count < 0 )
+ mp->rbuf_count = 0;
+ if ( mp->xbuf_count < 0 )
+ mp->xbuf_count = 0;
+
+ /* allocate ring area; add 1 entry -- room for alignment */
+ assert( !mp->ring_area );
+ mp->ring_area = malloc(
+ sizeof(*mp->ring_area) *
+ (mp->rbuf_count + mp->xbuf_count + 1),
+ M_DEVBUF,
+ M_WAIT );
+ assert( mp->ring_area );
+
+ BSP_mve_stop_hw(mp);
+
+ if ( irq_mask ) {
+ irq_data[mp->port_num].hdl = tid ? mveth_isr : mveth_isr_1;
+ InstallISRSuccessful = BSP_install_rtems_irq_handler( &irq_data[mp->port_num] );
+ assert( InstallISRSuccessful );
+ }
+
+ /* mark as used */
+ ifp->if_init = (void*)(-1);
+
+ if ( rx_ring_size < 0 )
+ irq_mask &= ~ MV643XX_ETH_IRQ_RX_DONE;
+ if ( tx_ring_size < 0 )
+ irq_mask &= ~ MV643XX_ETH_EXT_IRQ_TX_DONE;
+
+ mp->irq_mask = (irq_mask & MV643XX_ETH_IRQ_RX_DONE);
+ if ( (irq_mask &= (MV643XX_ETH_EXT_IRQ_TX_DONE | MV643XX_ETH_EXT_IRQ_LINK_CHG)) ) {
+ mp->irq_mask |= MV643XX_ETH_IRQ_EXT_ENA;
+ mp->xirq_mask = irq_mask;
+ } else {
+ mp->xirq_mask = 0;
+ }
+
+ return mp;
+}
+
+struct mveth_private *
+BSP_mve_setup(
+ int unit,
+ rtems_id tid,
+ void (*cleanup_txbuf)(void *user_buf, void *closure, 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 *closure, int len),
+ void *consume_rxbuf_arg,
+ int rx_ring_size,
+ int tx_ring_size,
+ int irq_mask
+)
+{
+ if ( irq_mask && 0 == tid ) {
+ printk(DRVNAME": must supply a TID if irq_msk not zero\n");
+ return 0;
+ }
+
+ return mve_setup_internal(
+ unit,
+ tid,
+ 0, 0,
+ cleanup_txbuf, cleanup_txbuf_arg,
+ alloc_rxbuf,
+ consume_rxbuf, consume_rxbuf_arg,
+ rx_ring_size, tx_ring_size,
+ irq_mask);
+}
+
+struct mveth_private *
+BSP_mve_setup_1(
+ int unit,
+ void (*isr)(void *isr_arg),
+ void *isr_arg,
+ void (*cleanup_txbuf)(void *user_buf, void *closure, 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 *closure, int len),
+ void *consume_rxbuf_arg,
+ int rx_ring_size,
+ int tx_ring_size,
+ int irq_mask
+)
+{
+ if ( irq_mask && 0 == isr ) {
+ printk(DRVNAME": must supply an ISR if irq_msk not zero\n");
+ return 0;
+ }
+
+ return mve_setup_internal(
+ unit,
+ 0,
+ isr, isr_arg,
+ cleanup_txbuf, cleanup_txbuf_arg,
+ alloc_rxbuf,
+ consume_rxbuf, consume_rxbuf_arg,
+ rx_ring_size, tx_ring_size,
+ irq_mask);
+}
+
+rtems_id
+BSP_mve_get_tid(struct mveth_private *mp)
+{
+ return mp->tid;
+}
+
+int
+BSP_mve_detach(struct mveth_private *mp)
+{
+int unit = mp->port_num;
+ BSP_mve_stop_hw(mp);
+ if ( mp->irq_mask || mp->xirq_mask ) {
+ if ( !BSP_remove_rtems_irq_handler( &irq_data[mp->port_num] ) )
+ return -1;
+ }
+ free( (void*)mp->ring_area, M_DEVBUF );
+ memset(mp, 0, sizeof(*mp));
+ __asm__ __volatile__("":::"memory");
+ /* mark as unused */
+ theMvEths[unit].arpcom.ac_if.if_init = 0;
+ return 0;
+}
+
+/* MAIN RX-TX ROUTINES
+ *
+ * BSP_mve_swipe_tx(): descriptor scavenger; releases mbufs
+ * BSP_mve_send_buf(): xfer mbufs from IF to chip
+ * BSP_mve_swipe_rx(): enqueue received mbufs to interface
+ * allocate new ones and yield them to the
+ * chip.
+ */
+
+/* clean up the TX ring freeing up buffers */
+int
+BSP_mve_swipe_tx(struct mveth_private *mp)
+{
+int rval = 0;
+register MvEthTxDesc d;
+
+ for ( d = mp->d_tx_t; d->buf_ptr; d = NEXT_TXD(d) ) {
+
+ INVAL_DESC(d);
+
+ if ( (TDESC_DMA_OWNED & d->cmd_sts)
+ && (uint32_t)d == MV_READ(MV643XX_ETH_CURRENT_SERVED_TX_DESC(mp->port_num)) )
+ break;
+
+ /* d->u_buf is only set on the last descriptor in a chain;
+ * we only count errors in the last descriptor;
+ */
+ if ( d->u_buf ) {
+ mp->cleanup_txbuf(d->u_buf, mp->cleanup_txbuf_arg, (d->cmd_sts & TDESC_ERROR) ? 1 : 0);
+ d->u_buf = 0;
+ }
+
+ d->buf_ptr = 0;
+
+ rval++;
+ }
+ mp->d_tx_t = d;
+ mp->avail += rval;
+
+ return rval;
+}
+
+/* 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;
+}
+
+/* Enqueue a mbuf chain or a raw data buffer for transmission;
+ * RETURN: #bytes sent or -1 if there are not enough descriptors
+ *
+ * If 'len' is <=0 then 'm_head' is assumed to point to a mbuf chain.
+ * OTOH, a raw data packet may be send (non-BSD driver) by pointing
+ * m_head to the start of the data and passing 'len' > 0.
+ *
+ * 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.
+ */
+int
+BSP_mve_send_buf(struct mveth_private *mp, void *m_head, void *data_p, int len)
+{
+int rval;
+register MvEthTxDesc l,d,h;
+register struct mbuf *m1;
+int nmbs;
+int ismbuf = (len <= 0);
+
+/* Only way to get here is when we discover that the mbuf chain
+ * is too long for the tx ring
+ */
+startover:
+
+ rval = 0;
+
+#ifdef MVETH_TESTING
+ assert(m_head);
+#endif
+
+ /* if no descriptor is available; try to wipe the queue */
+ if ( (mp->avail < 1) && MVETH_CLEAN_ON_SEND(mp)<=0 ) {
+ return -1;
+ }
+
+ h = mp->d_tx_h;
+
+#ifdef MVETH_TESTING
+ assert( !h->buf_ptr );
+ assert( !h->mb );
+#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_mve_swipe_tx()
+ * needs mp->d_tx_h->buf_ptr == NULL as a marker. Hence, we
+ * start with the second mbuf and fill the first descriptor
+ * last.
+ */
+
+ l = h;
+ d = NEXT_TXD(h);
+
+ mp->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->avail < 1 && MVETH_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_TXD(h); l!=d; l=NEXT_TXD(l) ) {
+#ifdef MVETH_TESTING
+ assert( l->mb == 0 );
+#endif
+ l->buf_ptr = 0;
+ l->cmd_sts = 0;
+ mp->avail++;
+ }
+ mp->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++;
+ return 0;
+ }
+ goto startover;
+ }
+ return -1;
+ }
+
+ mp->avail--;
+
+#ifdef MVETH_TESTING
+ assert( d != h );
+ assert( !d->buf_ptr );
+#endif
+
+ /* fill this slot */
+ rval += mveth_assign_desc(d, m, TDESC_DMA_OWNED);
+
+ FLUSH_BUF(mtod(m, uint32_t), m->m_len);
+
+ l = d;
+ d = NEXT_TXD(d);
+
+ FLUSH_DESC(l);
+ }
+
+ /* fill first slot - don't release to DMA yet */
+ rval += mveth_assign_desc(h, m1, TDESC_FRST);
+
+
+ FLUSH_BUF(mtod(m1, uint32_t), m1->m_len);
+
+ } else {
+ /* fill first slot with raw buffer - don't release to DMA yet */
+ rval += mveth_assign_desc_raw(h, data_p, len, TDESC_FRST);
+
+ FLUSH_BUF( (uint32_t)data_p, len);
+ }
+
+ /* tag last slot; this covers the case where 1st==last */
+ l->cmd_sts |= TDESC_LAST | TDESC_INT_ENA;
+ /* mbuf goes into last desc */
+ l->u_buf = m_head;
+
+
+ FLUSH_DESC(l);
+
+ /* Tag end; make sure chip doesn't try to read ahead of here! */
+ l->next->cmd_sts = 0;
+ FLUSH_DESC(l->next);
+
+#ifdef MVETH_DEBUG_TX_DUMP
+ if ( (mveth_tx_dump & (1<<mp->port_num)) ) {
+ int ll,kk;
+ if ( ismbuf ) {
+ struct mbuf *m;
+ for ( kk=0, m=m_head; m; m=m->m_next) {
+ for ( ll=0; ll<m->m_len; ll++ ) {
+ printf("%02X ",*(mtod(m,char*) + ll));
+ if ( ((++kk)&0xf) == 0 )
+ printf("\n");
+ }
+ }
+ } else {
+ for ( ll=0; ll<len; ) {
+ printf("%02X ",*((char*)data_p + ll));
+ if ( ((++ll)&0xf) == 0 )
+ printf("\n");
+ }
+ }
+ printf("\n");
+ }
+#endif
+
+ membarrier();
+
+ /* turn over the whole chain by flipping ownership of the first desc */
+ h->cmd_sts |= TDESC_DMA_OWNED;
+
+ FLUSH_DESC(h);
+
+ membarrier();
+
+ /* notify the device */
+ MV_WRITE(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_R(mp->port_num), MV643XX_ETH_TX_START(0));
+
+ /* Update softc */
+ mp->stats.packet++;
+ if ( nmbs > mp->stats.maxchain )
+ mp->stats.maxchain = nmbs;
+
+ /* remember new head */
+ mp->d_tx_h = d;
+
+ return rval; /* #bytes sent */
+}
+
+int
+BSP_mve_send_buf_raw(
+ struct mveth_private *mp,
+ void *head_p,
+ int h_len,
+ void *data_p,
+ int d_len)
+{
+int rval;
+register MvEthTxDesc l,d,h;
+int needed;
+void *frst_buf;
+int frst_len;
+
+ rval = 0;
+
+#ifdef MVETH_TESTING
+ assert(header || data);
+#endif
+
+ needed = head_p && data_p ? 2 : 1;
+
+ /* if no descriptor is available; try to wipe the queue */
+ if ( ( mp->avail < needed )
+ && ( MVETH_CLEAN_ON_SEND(mp) <= 0 || mp->avail < needed ) ) {
+ return -1;
+ }
+
+ h = mp->d_tx_h;
+
+#ifdef MVETH_TESTING
+ assert( !h->buf_ptr );
+ assert( !h->mb );
+#endif
+
+ /* find the 'first' user buffer */
+ if ( (frst_buf = head_p) ) {
+ frst_len = h_len;
+ } else {
+ frst_buf = data_p;
+ frst_len = d_len;
+ }
+
+ /* Don't use the first descriptor yet because BSP_mve_swipe_tx()
+ * needs mp->d_tx_h->buf_ptr == NULL as a marker. Hence, we
+ * start with the second (optional) slot and fill the first
+ * descriptor last.
+ */
+
+ l = h;
+ d = NEXT_TXD(h);
+
+ mp->avail--;
+
+ if ( needed > 1 ) {
+ mp->avail--;
+#ifdef MVETH_TESTING
+ assert( d != h );
+ assert( !d->buf_ptr );
+#endif
+ rval += mveth_assign_desc_raw(d, data_p, d_len, TDESC_DMA_OWNED);
+ FLUSH_BUF( (uint32_t)data_p, d_len );
+ d->u_buf = data_p;
+
+ l = d;
+ d = NEXT_TXD(d);
+
+ FLUSH_DESC(l);
+ }
+
+ /* fill first slot with raw buffer - don't release to DMA yet */
+ rval += mveth_assign_desc_raw(h, frst_buf, frst_len, TDESC_FRST);
+
+ FLUSH_BUF( (uint32_t)frst_buf, frst_len);
+
+ /* tag last slot; this covers the case where 1st==last */
+ l->cmd_sts |= TDESC_LAST | TDESC_INT_ENA;
+
+ /* first buffer of 'chain' goes into last desc */
+ l->u_buf = frst_buf;
+
+ FLUSH_DESC(l);
+
+ /* Tag end; make sure chip doesn't try to read ahead of here! */
+ l->next->cmd_sts = 0;
+ FLUSH_DESC(l->next);
+
+ membarrier();
+
+ /* turn over the whole chain by flipping ownership of the first desc */
+ h->cmd_sts |= TDESC_DMA_OWNED;
+
+ FLUSH_DESC(h);
+
+ membarrier();
+
+ /* notify the device */
+ MV_WRITE(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_R(mp->port_num), MV643XX_ETH_TX_START(0));
+
+ /* Update softc */
+ mp->stats.packet++;
+ if ( needed > mp->stats.maxchain )
+ mp->stats.maxchain = needed;
+
+ /* remember new head */
+ mp->d_tx_h = d;
+
+ return rval; /* #bytes sent */
+}
+
+/* send received buffers upwards and replace them
+ * with freshly allocated ones;
+ * ASSUMPTION: buffer length NEVER changes and is set
+ * when the ring is initialized.
+ * TS 20060727: not sure if this assumption is still necessary - I believe it isn't.
+ */
+
+int
+BSP_mve_swipe_rx(struct mveth_private *mp)
+{
+int rval = 0, err;
+register MvEthRxDesc d;
+void *newbuf;
+int sz;
+uintptr_t baddr;
+
+ for ( d = mp->d_rx_t; ! (INVAL_DESC(d), (RDESC_DMA_OWNED & d->cmd_sts)); d=NEXT_RXD(d) ) {
+
+#ifdef MVETH_TESTING
+ assert(d->u_buf);
+#endif
+
+ err = (RDESC_ERROR & d->cmd_sts);
+
+ if ( err || !(newbuf = mp->alloc_rxbuf(&sz, &baddr)) ) {
+ /* drop packet and recycle buffer */
+ newbuf = d->u_buf;
+ mp->consume_rxbuf(0, mp->consume_rxbuf_arg, err ? -1 : 0);
+ } else {
+#ifdef MVETH_TESTING
+ assert( d->byte_cnt > 0 );
+#endif
+ mp->consume_rxbuf(d->u_buf, mp->consume_rxbuf_arg, d->byte_cnt);
+
+#ifndef ENABLE_HW_SNOOPING
+ /* could reduce the area to max. ethernet packet size */
+ INVAL_BUF(baddr, sz);
+#endif
+ d->u_buf = newbuf;
+ d->buf_ptr = CPUADDR2ENET(baddr);
+ d->buf_size = sz;
+ FLUSH_DESC(d);
+ }
+
+ membarrier();
+
+ d->cmd_sts = RDESC_DMA_OWNED | RDESC_INT_ENA;
+
+ FLUSH_DESC(d);
+
+ rval++;
+ }
+ MV_WRITE(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_R(mp->port_num), MV643XX_ETH_RX_START(0));
+ mp->d_rx_t = d;
+ return rval;
+}
+
+/* Stop hardware and clean out the rings */
+void
+BSP_mve_stop_hw(struct mveth_private *mp)
+{
+MvEthTxDesc d;
+MvEthRxDesc r;
+int i;
+
+ mveth_disable_irqs(mp, -1);
+
+ mveth_stop_tx(mp->port_num);
+
+ /* cleanup TX rings */
+ if (mp->d_tx_t) { /* maybe ring isn't initialized yet */
+ for ( i=0, d=mp->tx_ring; i<mp->xbuf_count; i++, d++ ) {
+ /* should be safe to clear ownership */
+ d->cmd_sts &= ~TDESC_DMA_OWNED;
+ FLUSH_DESC(d);
+ }
+ FLUSH_BARRIER();
+
+ BSP_mve_swipe_tx(mp);
+
+#ifdef MVETH_TESTING
+ assert( mp->d_tx_h == mp->d_tx_t );
+ for ( i=0, d=mp->tx_ring; i<mp->xbuf_count; i++, d++ ) {
+ assert( !d->buf_ptr );
+ }
+#endif
+ }
+
+ MV_WRITE(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_R(mp->port_num), MV643XX_ETH_RX_STOP_ALL);
+ while ( MV643XX_ETH_RX_ANY_RUNNING & MV_READ(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_R(mp->port_num)) )
+ /* poll-wait */;
+
+ /* stop serial port */
+ MV_WRITE(MV643XX_ETH_SERIAL_CONTROL_R(mp->port_num),
+ MV_READ(MV643XX_ETH_SERIAL_CONTROL_R(mp->port_num))
+ & ~( MV643XX_ETH_SERIAL_PORT_ENBL | MV643XX_ETH_FORCE_LINK_FAIL_DISABLE | MV643XX_ETH_FORCE_LINK_PASS)
+ );
+
+ /* clear pending interrupts */
+ MV_WRITE(MV643XX_ETH_INTERRUPT_CAUSE_R(mp->port_num), 0);
+ MV_WRITE(MV643XX_ETH_INTERRUPT_EXTEND_CAUSE_R(mp->port_num), 0);
+
+ /* cleanup RX rings */
+ if ( mp->rx_ring ) {
+ for ( i=0, r=mp->rx_ring; i<mp->rbuf_count; i++, r++ ) {
+ /* should be OK to clear ownership flag */
+ r->cmd_sts = 0;
+ FLUSH_DESC(r);
+ mp->consume_rxbuf(r->u_buf, mp->consume_rxbuf_arg, 0);
+ r->u_buf = 0;
+ }
+ FLUSH_BARRIER();
+ }
+
+
+}
+
+uint32_t mveth_serial_ctrl_config_val = MVETH_SERIAL_CTRL_CONFIG_VAL;
+
+/* Fire up the low-level driver
+ *
+ * - make sure hardware is halted
+ * - enable cache snooping
+ * - clear address filters
+ * - clear mib counters
+ * - reset phy
+ * - initialize (or reinitialize) descriptor rings
+ * - check that the firmware has set up a reasonable mac address.
+ * - generate unicast filter entry for our mac address
+ * - write register config values to the chip
+ * - start hardware (serial port and SDMA)
+ */
+
+void
+BSP_mve_init_hw(struct mveth_private *mp, int promisc, unsigned char *enaddr)
+{
+int i;
+uint32_t v;
+static int inited = 0;
+
+#ifdef MVETH_DEBUG
+ printk(DRVNAME"%i: Entering BSP_mve_init_hw()\n", mp->port_num+1);
+#endif
+
+ /* since enable/disable IRQ routine only operate on select bitsets
+ * we must make sure everything is masked initially.
+ */
+ MV_WRITE(MV643XX_ETH_INTERRUPT_ENBL_R(mp->port_num), 0);
+ MV_WRITE(MV643XX_ETH_INTERRUPT_EXTEND_ENBL_R(mp->port_num), 0);
+
+ BSP_mve_stop_hw(mp);
+
+ memset(&mp->stats, 0, sizeof(mp->stats));
+
+ mp->promisc = promisc;
+
+ /* MotLoad has cache snooping disabled on the ENET2MEM windows.
+ * Some comments in (linux) indicate that there are errata
+ * which cause problems which would be a real bummer.
+ * We try it anyways...
+ */
+ if ( !inited ) {
+ unsigned long disbl, bar;
+ inited = 1; /* FIXME: non-thread safe lazy init */
+ disbl = MV_READ(MV643XX_ETH_BAR_ENBL_R);
+ /* disable all 6 windows */
+ MV_WRITE(MV643XX_ETH_BAR_ENBL_R, MV643XX_ETH_BAR_DISBL_ALL);
+ /* set WB snooping on enabled bars */
+ for ( i=0; i<MV643XX_ETH_NUM_BARS*8; i+=8 ) {
+ if ( (bar = MV_READ(MV643XX_ETH_BAR_0 + i)) && MV_READ(MV643XX_ETH_SIZE_R_0 + i) ) {
+#ifdef ENABLE_HW_SNOOPING
+ MV_WRITE(MV643XX_ETH_BAR_0 + i, bar | MV64360_ENET2MEM_SNOOP_WB);
+#else
+ MV_WRITE(MV643XX_ETH_BAR_0 + i, bar & ~MV64360_ENET2MEM_SNOOP_MSK);
+#endif
+ /* read back to flush fifo [linux comment] */
+ (void)MV_READ(MV643XX_ETH_BAR_0 + i);
+ }
+ }
+ /* restore/re-enable */
+ MV_WRITE(MV643XX_ETH_BAR_ENBL_R, disbl);
+ }
+
+ mveth_clear_mib_counters(mp);
+ mveth_clear_addr_filters(mp);
+
+/* Just leave it alone...
+ reset_phy();
+*/
+
+ if ( mp->rbuf_count > 0 ) {
+ mp->rx_ring = (MvEthRxDesc)_ALIGN(mp->ring_area, RING_ALIGNMENT);
+ mveth_init_rx_desc_ring(mp);
+ }
+
+ if ( mp->xbuf_count > 0 ) {
+ mp->tx_ring = (MvEthTxDesc)mp->rx_ring + mp->rbuf_count;
+ mveth_init_tx_desc_ring(mp);
+ }
+
+ if ( enaddr ) {
+ /* set ethernet address from arpcom struct */
+#ifdef MVETH_DEBUG
+ printk(DRVNAME"%i: Writing MAC addr ", mp->port_num+1);
+ for (i=5; i>=0; i--) {
+ printk("%02X%c", enaddr[i], i?':':'\n');
+ }
+#endif
+ mveth_write_eaddr(mp, enaddr);
+ }
+
+ /* set mac address and unicast filter */
+
+ {
+ uint32_t machi, maclo;
+ maclo = MV_READ(MV643XX_ETH_MAC_ADDR_LO(mp->port_num));
+ machi = MV_READ(MV643XX_ETH_MAC_ADDR_HI(mp->port_num));
+ /* ASSUME: firmware has set the mac address for us
+ * - if assertion fails, we have to do more work...
+ */
+ assert( maclo && machi && maclo != 0xffffffff && machi != 0xffffffff );
+ mveth_ucfilter(mp, maclo&0xff, 1/* accept */);
+ }
+
+ /* port, serial and sdma configuration */
+ v = MVETH_PORT_CONFIG_VAL;
+ if ( promisc ) {
+ /* multicast filters were already set up to
+ * accept everything (mveth_clear_addr_filters())
+ */
+ v |= MV643XX_ETH_UNICAST_PROMISC_MODE;
+ } else {
+ v &= ~MV643XX_ETH_UNICAST_PROMISC_MODE;
+ }
+ MV_WRITE(MV643XX_ETH_PORT_CONFIG_R(mp->port_num),
+ v);
+ MV_WRITE(MV643XX_ETH_PORT_CONFIG_XTEND_R(mp->port_num),
+ MVETH_PORT_XTEND_CONFIG_VAL);
+
+ v = MV_READ(MV643XX_ETH_SERIAL_CONTROL_R(mp->port_num));
+ v &= ~(MVETH_SERIAL_CTRL_CONFIG_MSK);
+ v |= mveth_serial_ctrl_config_val;
+ MV_WRITE(MV643XX_ETH_SERIAL_CONTROL_R(mp->port_num), v);
+
+ i = IFM_MAKEWORD(0, 0, 0, 0);
+ if ( 0 == BSP_mve_media_ioctl(mp, SIOCGIFMEDIA, &i) ) {
+ if ( (IFM_LINK_OK & i) ) {
+ mveth_update_serial_port(mp, i);
+ }
+ }
+
+ /* enable serial port */
+ v = MV_READ(MV643XX_ETH_SERIAL_CONTROL_R(mp->port_num));
+ MV_WRITE(MV643XX_ETH_SERIAL_CONTROL_R(mp->port_num),
+ v | MV643XX_ETH_SERIAL_PORT_ENBL);
+
+#ifndef __BIG_ENDIAN__
+#error "byte swapping needs to be disabled for little endian machines"
+#endif
+ MV_WRITE(MV643XX_ETH_SDMA_CONFIG_R(mp->port_num), MVETH_SDMA_CONFIG_VAL);
+
+ /* allow short frames */
+ MV_WRITE(MV643XX_ETH_RX_MIN_FRAME_SIZE_R(mp->port_num), MVETH_MIN_FRAMSZ_CONFIG_VAL);
+
+ MV_WRITE(MV643XX_ETH_INTERRUPT_CAUSE_R(mp->port_num), 0);
+ MV_WRITE(MV643XX_ETH_INTERRUPT_EXTEND_CAUSE_R(mp->port_num), 0);
+ /* TODO: set irq coalescing */
+
+ /* enable Rx */
+ if ( mp->rbuf_count > 0 ) {
+ MV_WRITE(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_R(mp->port_num), MV643XX_ETH_RX_START(0));
+ }
+
+ mveth_enable_irqs(mp, -1);
+
+#ifdef MVETH_DEBUG
+ printk(DRVNAME"%i: Leaving BSP_mve_init_hw()\n", mp->port_num+1);
+#endif
+}
+
+/* read ethernet address from hw to buffer */
+void
+BSP_mve_read_eaddr(struct mveth_private *mp, unsigned char *oeaddr)
+{
+int i;
+uint32_t x;
+unsigned char buf[6], *eaddr;
+
+ eaddr = oeaddr ? oeaddr : buf;
+
+ eaddr += 5;
+ x = MV_READ(MV643XX_ETH_MAC_ADDR_LO(mp->port_num));
+
+ /* lo word */
+ for (i=2; i; i--, eaddr--) {
+ *eaddr = (unsigned char)(x & 0xff);
+ x>>=8;
+ }
+
+ x = MV_READ(MV643XX_ETH_MAC_ADDR_HI(mp->port_num));
+ /* hi word */
+ for (i=4; i; i--, eaddr--) {
+ *eaddr = (unsigned char)(x & 0xff);
+ x>>=8;
+ }
+
+ if ( !oeaddr ) {
+ printf("%02X",buf[0]);
+ for (i=1; i<sizeof(buf); i++)
+ printf(":%02X",buf[i]);
+ printf("\n");
+ }
+}
+
+int
+BSP_mve_media_ioctl(struct mveth_private *mp, int cmd, int *parg)
+{
+int rval;
+ /* alias cmd == 0,1 */
+ switch ( cmd ) {
+ case 0: cmd = SIOCGIFMEDIA;
+ break;
+ case 1: cmd = SIOCSIFMEDIA;
+ case SIOCGIFMEDIA:
+ case SIOCSIFMEDIA:
+ break;
+ default: return -1;
+ }
+ REGLOCK();
+ rval = rtems_mii_ioctl(&mveth_mdio, mp, cmd, parg);
+ REGUNLOCK();
+ return rval;
+}
+
+void
+BSP_mve_enable_irqs(struct mveth_private *mp)
+{
+ mveth_enable_irqs(mp, -1);
+}
+
+void
+BSP_mve_disable_irqs(struct mveth_private *mp)
+{
+ mveth_disable_irqs(mp, -1);
+}
+
+uint32_t
+BSP_mve_ack_irqs(struct mveth_private *mp)
+{
+ return mveth_ack_irqs(mp, -1);
+}
+
+
+void
+BSP_mve_enable_irq_mask(struct mveth_private *mp, uint32_t mask)
+{
+ mveth_enable_irqs(mp, mask);
+}
+
+uint32_t
+BSP_mve_disable_irq_mask(struct mveth_private *mp, uint32_t mask)
+{
+ return mveth_disable_irqs(mp, mask);
+}
+
+uint32_t
+BSP_mve_ack_irq_mask(struct mveth_private *mp, uint32_t mask)
+{
+ return mveth_ack_irqs(mp, mask);
+}
+
+int
+BSP_mve_ack_link_chg(struct mveth_private *mp, int *pmedia)
+{
+int media = IFM_MAKEWORD(0,0,0,0);
+
+ if ( 0 == BSP_mve_media_ioctl(mp, SIOCGIFMEDIA, &media)) {
+ if ( IFM_LINK_OK & media ) {
+ mveth_update_serial_port(mp, media);
+ }
+ if ( pmedia )
+ *pmedia = media;
+ return 0;
+ }
+ return -1;
+}
+
+/* BSDNET SUPPORT/GLUE ROUTINES */
+
+static void
+mveth_set_filters(struct ifnet *ifp);
+
+STATIC void
+mveth_stop(struct mveth_softc *sc)
+{
+ BSP_mve_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 = _ALIGN(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, uintptr_t);
+
+ return (void*) m;
+}
+
+static void consume_rx_mbuf(void *buf, void *arg, int len)
+{
+struct ifnet *ifp = arg;
+struct mbuf *m = buf;
+
+ if ( len <= 0 ) {
+ ifp->if_iqdrops++;
+ if ( len < 0 ) {
+ ifp->if_ierrors++;
+ }
+ if ( m )
+ m_freem(m);
+ } else {
+ struct ether_header *eh;
+
+ 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;
+
+ 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 {
+ /* send buffer upwards */
+ 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);
+}
+
+static void
+dump_update_stats(struct mveth_private *mp, FILE *f)
+{
+int p = mp->port_num;
+int idx;
+uint32_t v;
+
+ if ( !f )
+ f = stdout;
+
+ fprintf(f, DRVNAME"%i Statistics:\n", mp->port_num + 1);
+ fprintf(f, " # IRQS: %i\n", mp->stats.irqs);
+ fprintf(f, " Max. mbuf chain length: %i\n", mp->stats.maxchain);
+ fprintf(f, " # repacketed: %i\n", mp->stats.repack);
+ fprintf(f, " # packets: %i\n", mp->stats.packet);
+ fprintf(f, "MIB Counters:\n");
+ for ( idx = MV643XX_ETH_MIB_GOOD_OCTS_RCVD_LO>>2;
+ idx < MV643XX_ETH_NUM_MIB_COUNTERS;
+ idx++ ) {
+ switch ( idx ) {
+ case MV643XX_ETH_MIB_GOOD_OCTS_RCVD_LO>>2:
+ mp->stats.mib.good_octs_rcvd += read_long_mib_counter(p, idx);
+ fprintf(f, mibfmt[idx], mp->stats.mib.good_octs_rcvd);
+ idx++;
+ break;
+
+ case MV643XX_ETH_MIB_GOOD_OCTS_SENT_LO>>2:
+ mp->stats.mib.good_octs_sent += read_long_mib_counter(p, idx);
+ fprintf(f, mibfmt[idx], mp->stats.mib.good_octs_sent);
+ idx++;
+ break;
+
+ default:
+ v = ((uint32_t*)&mp->stats.mib)[idx] += read_mib_counter(p, idx);
+ fprintf(f, mibfmt[idx], v);
+ break;
+ }
+ }
+ fprintf(f, "\n");
+}
+
+void
+BSP_mve_dump_stats(struct mveth_private *mp, FILE *f)
+{
+ dump_update_stats(mp, f);
+}
+
+/* BSDNET DRIVER CALLBACKS */
+
+static void
+mveth_init(void *arg)
+{
+struct mveth_softc *sc = arg;
+struct ifnet *ifp = &sc->arpcom.ac_if;
+int media;
+
+ BSP_mve_init_hw(&sc->pvt, ifp->if_flags & IFF_PROMISC, sc->arpcom.ac_enaddr);
+
+ media = IFM_MAKEWORD(0, 0, 0, 0);
+ if ( 0 == BSP_mve_media_ioctl(&sc->pvt, SIOCGIFMEDIA, &media) ) {
+ if ( (IFM_LINK_OK & media) ) {
+ ifp->if_flags &= ~IFF_OACTIVE;
+ } else {
+ ifp->if_flags |= IFF_OACTIVE;
+ }
+ }
+
+ /* if promiscuous then there is no need to change */
+ if ( ! (ifp->if_flags & IFF_PROMISC) )
+ mveth_set_filters(ifp);
+
+ ifp->if_flags |= IFF_RUNNING;
+ sc->arpcom.ac_if.if_timer = 0;
+}
+
+/* bsdnet driver entry to start transmission */
+static void
+mveth_start(struct ifnet *ifp)
+{
+struct mveth_softc *sc = ifp->if_softc;
+struct mbuf *m = 0;
+
+ while ( ifp->if_snd.ifq_head ) {
+ IF_DEQUEUE( &ifp->if_snd, m );
+ if ( BSP_mve_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
+mveth_watchdog(struct ifnet *ifp)
+{
+struct mveth_softc *sc = ifp->if_softc;
+
+ ifp->if_oerrors++;
+ printk(DRVNAME"%i: watchdog timeout; resetting\n", ifp->if_unit);
+
+ mveth_init(sc);
+ mveth_start(ifp);
+}
+
+static void
+mveth_set_filters(struct ifnet *ifp)
+{
+struct mveth_softc *sc = ifp->if_softc;
+uint32_t v;
+
+ v = MV_READ(MV643XX_ETH_PORT_CONFIG_R(sc->pvt.port_num));
+ if ( ifp->if_flags & IFF_PROMISC )
+ v |= MV643XX_ETH_UNICAST_PROMISC_MODE;
+ else
+ v &= ~MV643XX_ETH_UNICAST_PROMISC_MODE;
+ MV_WRITE(MV643XX_ETH_PORT_CONFIG_R(sc->pvt.port_num), v);
+
+ if ( ifp->if_flags & (IFF_PROMISC | IFF_ALLMULTI) ) {
+ BSP_mve_mcast_filter_accept_all(&sc->pvt);
+ } else {
+ struct ether_multi *enm;
+ struct ether_multistep step;
+
+ BSP_mve_mcast_filter_clear( &sc->pvt );
+
+ ETHER_FIRST_MULTI(step, (struct arpcom *)ifp, enm);
+
+ while ( enm ) {
+ if ( memcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN) )
+ assert( !"Should never get here; IFF_ALLMULTI should be set!" );
+
+ BSP_mve_mcast_filter_accept_add(&sc->pvt, enm->enm_addrlo);
+
+ ETHER_NEXT_MULTI(step, enm);
+ }
+ }
+}
+
+/* bsdnet driver ioctl entry */
+static int
+mveth_ioctl(struct ifnet *ifp, ioctl_command_t cmd, caddr_t data)
+{
+struct mveth_softc *sc = ifp->if_softc;
+struct ifreq *ifr = (struct ifreq *)data;
+int error = 0;
+int f;
+
+ switch ( cmd ) {
+ case SIOCSIFFLAGS:
+ f = ifp->if_flags;
+ if ( f & IFF_UP ) {
+ if ( ! ( f & IFF_RUNNING ) ) {
+ mveth_init(sc);
+ } else {
+ if ( (f & IFF_PROMISC) != (sc->bsd.oif_flags & IFF_PROMISC) ) {
+ /* Note: in all other scenarios the 'promisc' flag
+ * in the low-level driver [which affects the way
+ * the multicast filter is setup: accept none vs.
+ * accept all in promisc mode] is eventually
+ * set when the IF is brought up...
+ */
+ sc->pvt.promisc = (f & IFF_PROMISC);
+
+ mveth_set_filters(ifp);
+ }
+ /* FIXME: other flag changes are ignored/unimplemented */
+ }
+ } else {
+ if ( f & IFF_RUNNING ) {
+ mveth_stop(sc);
+ ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
+ }
+ }
+ sc->bsd.oif_flags = ifp->if_flags;
+ break;
+
+ case SIOCGIFMEDIA:
+ case SIOCSIFMEDIA:
+ error = BSP_mve_media_ioctl(&sc->pvt, cmd, &ifr->ifr_media);
+ break;
+
+ case SIOCADDMULTI:
+ case SIOCDELMULTI:
+ error = (cmd == SIOCADDMULTI)
+ ? ether_addmulti(ifr, &sc->arpcom)
+ : ether_delmulti(ifr, &sc->arpcom);
+
+ if (error == ENETRESET) {
+ if (ifp->if_flags & IFF_RUNNING) {
+ mveth_set_filters(ifp);
+ }
+ error = 0;
+ }
+ break;
+
+
+ break;
+
+ case SIO_RTEMS_SHOW_STATS:
+ dump_update_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 mveth_daemon(void *arg)
+{
+struct mveth_softc *sc;
+struct ifnet *ifp;
+rtems_event_set evs;
+ for (;;) {
+ rtems_bsdnet_event_receive( 7, RTEMS_WAIT | RTEMS_EVENT_ANY, RTEMS_NO_TIMEOUT, &evs );
+ evs &= 7;
+ for ( sc = theMvEths; evs; evs>>=1, sc++ ) {
+ if ( (evs & 1) ) {
+ register uint32_t x;
+
+ ifp = &sc->arpcom.ac_if;
+
+ if ( !(ifp->if_flags & IFF_UP) ) {
+ mveth_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 = mveth_ack_irqs(&sc->pvt, -1);
+
+ if ( MV643XX_ETH_EXT_IRQ_LINK_CHG & x ) {
+ /* phy status changed */
+ int media;
+
+ if ( 0 == BSP_mve_ack_link_chg(&sc->pvt, &media) ) {
+ if ( IFM_LINK_OK & media ) {
+ ifp->if_flags &= ~IFF_OACTIVE;
+ mveth_start(ifp);
+ } else {
+ /* stop sending */
+ ifp->if_flags |= IFF_OACTIVE;
+ }
+ }
+ }
+ /* free tx chain */
+ if ( (MV643XX_ETH_EXT_IRQ_TX_DONE & x) && BSP_mve_swipe_tx(&sc->pvt) ) {
+ ifp->if_flags &= ~IFF_OACTIVE;
+ if ( TX_AVAILABLE_RING_SIZE(&sc->pvt) == sc->pvt.avail )
+ ifp->if_timer = 0;
+ mveth_start(ifp);
+ }
+ if ( (MV643XX_ETH_IRQ_RX_DONE & x) )
+ BSP_mve_swipe_rx(&sc->pvt);
+
+ mveth_enable_irqs(&sc->pvt, -1);
+ }
+ }
+ }
+}
+
+#ifdef MVETH_DETACH_HACK
+static int mveth_detach(struct mveth_softc *sc);
+#endif
+
+
+/* PUBLIC RTEMS BSDNET ATTACH FUNCTION */
+int
+rtems_mve_attach(struct rtems_bsdnet_ifconfig *ifcfg, int attaching)
+{
+char *unitName;
+int unit,i,cfgUnits;
+struct mveth_softc *sc;
+struct ifnet *ifp;
+
+ unit = rtems_bsdnet_parse_driver_name(ifcfg, &unitName);
+ if ( unit <= 0 || unit > MV643XXETH_NUM_DRIVER_SLOTS ) {
+ printk(DRVNAME": Bad unit number %i; must be 1..%i\n", unit, MV643XXETH_NUM_DRIVER_SLOTS);
+ return 1;
+ }
+
+ sc = &theMvEths[unit-1];
+ ifp = &sc->arpcom.ac_if;
+ sc->pvt.port_num = unit-1;
+ sc->pvt.phy = (MV_READ(MV643XX_ETH_PHY_ADDR_R) >> (5*sc->pvt.port_num)) & 0x1f;
+
+ if ( attaching ) {
+ if ( ifp->if_init ) {
+ printk(DRVNAME": instance %i already attached.\n", unit);
+ return -1;
+ }
+
+ for ( i=cfgUnits = 0; i<MV643XXETH_NUM_DRIVER_SLOTS; i++ ) {
+ if ( theMvEths[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 ( !mveth_tid ) {
+ /* newproc uses the 1st 4 chars of name string to build an rtems name */
+ mveth_tid = rtems_bsdnet_newproc("MVEd", 4096, mveth_daemon, 0);
+ }
+
+ if ( !BSP_mve_setup( unit,
+ mveth_tid,
+ release_tx_mbuf, ifp,
+ alloc_mbuf_rx,
+ consume_rx_mbuf, ifp,
+ ifcfg->rbuf_count,
+ ifcfg->xbuf_count,
+ BSP_MVE_IRQ_TX | BSP_MVE_IRQ_RX | BSP_MVE_IRQ_LINK) ) {
+ return -1;
+ }
+
+ if ( nmbclusters < sc->pvt.rbuf_count * cfgUnits + 60 /* arbitrary */ ) {
+ printk(DRVNAME"%i: (mv643xx 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_mve_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 = mveth_init;
+ ifp->if_ioctl = mveth_ioctl;
+ ifp->if_start = mveth_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 = mveth_watchdog;
+ ifp->if_timer = 0;
+
+ sc->bsd.oif_flags = /* ... */
+ ifp->if_flags = IFF_BROADCAST | IFF_MULTICAST | 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.xbuf_count;
+ */
+ ifp->if_snd.ifq_maxlen = ifqmaxlen;
+
+#ifdef MVETH_DETACH_HACK
+ if ( !ifp->if_addrlist ) /* do only the first time [reattach hack] */
+#endif
+ {
+ if_attach(ifp);
+ ether_ifattach(ifp);
+ }
+
+ } else {
+#ifdef MVETH_DETACH_HACK
+ if ( !ifp->if_init ) {
+ printk(DRVNAME": instance %i not attached.\n", unit);
+ return -1;
+ }
+ return mveth_detach(sc);
+#else
+ printk(DRVNAME": interface detaching not implemented\n");
+ return -1;
+#endif
+ }
+
+ return 0;
+}
+
+/* EARLY PHY ACCESS */
+static int
+mveth_early_init(int idx)
+{
+ if ( idx < 0 || idx >= MV643XXETH_NUM_DRIVER_SLOTS )
+ return -1;
+
+ /* determine the phy */
+ theMvEths[idx].pvt.phy = (MV_READ(MV643XX_ETH_PHY_ADDR_R) >> (5*idx)) & 0x1f;
+ return 0;
+}
+
+static int
+mveth_early_read_phy(int idx, unsigned reg)
+{
+int rval;
+
+ if ( idx < 0 || idx >= MV643XXETH_NUM_DRIVER_SLOTS )
+ return -1;
+
+ rval = mveth_mii_read(&theMvEths[idx].pvt, reg);
+ return rval < 0 ? rval : rval & 0xffff;
+}
+
+static int
+mveth_early_write_phy(int idx, unsigned reg, unsigned val)
+{
+ if ( idx < 0 || idx >= MV643XXETH_NUM_DRIVER_SLOTS )
+ return -1;
+
+ mveth_mii_write(&theMvEths[idx].pvt, reg, val);
+ return 0;
+}
+
+rtems_bsdnet_early_link_check_ops
+rtems_mve_early_link_check_ops = {
+ init: mveth_early_init,
+ read_phy: mveth_early_read_phy,
+ write_phy: mveth_early_write_phy,
+ name: DRVNAME,
+ num_slots: MAX_NUM_SLOTS
+};
+
+/* DEBUGGING */
+
+#ifdef MVETH_DEBUG
+/* Display/dump descriptor rings */
+
+int
+mveth_dring(struct mveth_softc *sc)
+{
+int i;
+if (1) {
+MvEthRxDesc pr;
+printf("RX:\n");
+
+ for (i=0, pr=sc->pvt.rx_ring; i<sc->pvt.rbuf_count; i++, pr++) {
+#ifndef ENABLE_HW_SNOOPING
+ /* can't just invalidate the descriptor - if it contains
+ * data that hasn't been flushed yet, we create an inconsistency...
+ */
+ rtems_bsdnet_semaphore_obtain();
+ INVAL_DESC(pr);
+#endif
+ printf("cnt: 0x%04x, size: 0x%04x, stat: 0x%08x, next: 0x%08x, buf: 0x%08x\n",
+ pr->byte_cnt, pr->buf_size, pr->cmd_sts, (uint32_t)pr->next_desc_ptr, pr->buf_ptr);
+
+#ifndef ENABLE_HW_SNOOPING
+ rtems_bsdnet_semaphore_release();
+#endif
+ }
+}
+if (1) {
+MvEthTxDesc pt;
+printf("TX:\n");
+ for (i=0, pt=sc->pvt.tx_ring; i<sc->pvt.xbuf_count; i++, pt++) {
+#ifndef ENABLE_HW_SNOOPING
+ rtems_bsdnet_semaphore_obtain();
+ INVAL_DESC(pt);
+#endif
+ printf("cnt: 0x%04x, stat: 0x%08x, next: 0x%08x, buf: 0x%08x, mb: 0x%08x\n",
+ pt->byte_cnt, pt->cmd_sts, (uint32_t)pt->next_desc_ptr, pt->buf_ptr,
+ (uint32_t)pt->mb);
+
+#ifndef ENABLE_HW_SNOOPING
+ rtems_bsdnet_semaphore_release();
+#endif
+ }
+}
+ return 0;
+}
+
+#endif
+
+/* DETACH HACK DETAILS */
+
+#ifdef MVETH_DETACH_HACK
+int
+_cexpModuleFinalize(void *mh)
+{
+int i;
+ for ( i=0; i<MV643XXETH_NUM_DRIVER_SLOTS; i++ ) {
+ if ( theMvEths[i].arpcom.ac_if.if_init ) {
+ printf("Interface %i still attached; refuse to unload\n", i+1);
+ return -1;
+ }
+ }
+ /* delete task; since there are no attached interfaces, it should block
+ * for events and hence not hold the semaphore or other resources...
+ */
+ rtems_task_delete(mveth_tid);
+ return 0;
+}
+
+/* ugly hack to allow unloading/reloading the driver core.
+ * needed because rtems' bsdnet release doesn't implement
+ * if_detach(). Therefore, we bring the interface down but
+ * keep the device record alive...
+ */
+static void
+ether_ifdetach_pvt(struct ifnet *ifp)
+{
+ ifp->if_flags = 0;
+ ifp->if_ioctl = 0;
+ ifp->if_start = 0;
+ ifp->if_watchdog = 0;
+ ifp->if_init = 0;
+}
+
+static int
+mveth_detach(struct mveth_softc *sc)
+{
+struct ifnet *ifp = &sc->arpcom.ac_if;
+ if ( ifp->if_init ) {
+ if ( ifp->if_flags & (IFF_UP | IFF_RUNNING) ) {
+ printf(DRVNAME"%i: refuse to detach; interface still up\n",sc->pvt.port_num+1);
+ return -1;
+ }
+ mveth_stop(sc);
+/* not implemented in BSDnet/RTEMS (yet) but declared in header */
+#define ether_ifdetach ether_ifdetach_pvt
+ ether_ifdetach(ifp);
+ }
+ free( (void*)sc->pvt.ring_area, M_DEVBUF );
+ sc->pvt.ring_area = 0;
+ sc->pvt.tx_ring = 0;
+ sc->pvt.rx_ring = 0;
+ sc->pvt.d_tx_t = sc->pvt.d_tx_h = 0;
+ sc->pvt.d_rx_t = 0;
+ sc->pvt.avail = 0;
+ /* may fail if ISR was not installed yet */
+ BSP_remove_rtems_irq_handler( &irq_data[sc->pvt.port_num] );
+ return 0;
+}
+
+#ifdef MVETH_DEBUG
+struct rtems_bsdnet_ifconfig mveth_dbg_config = {
+ name: DRVNAME"1",
+ attach: rtems_mve_attach,
+ ip_address: "192.168.2.10", /* not used by rtems_bsdnet_attach */
+ ip_netmask: "255.255.255.0", /* not used by rtems_bsdnet_attach */
+ hardware_address: 0, /* (void *) */
+ ignore_broadcast: 0, /* TODO driver should honour this */
+ mtu: 0,
+ rbuf_count: 0, /* TODO driver should honour this */
+ xbuf_count: 0, /* TODO driver should honour this */
+};
+#endif
+#endif
diff --git a/c/src/lib/libbsp/powerpc/beatnik/network/if_mve/mve_smallbuf_tst.c b/c/src/lib/libbsp/powerpc/beatnik/network/if_mve/mve_smallbuf_tst.c
new file mode 100644
index 0000000000..62469f736c
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/beatnik/network/if_mve/mve_smallbuf_tst.c
@@ -0,0 +1,144 @@
+#include <rtems.h>
+#include <bsp.h>
+#include <bsp/if_mve_pub.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+/* Demo for the mv64360 ethernet quirk:
+ *
+ * $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
+ * $$ buffer segments < 8 bytes must be aligned $$
+ * $$ to 8 bytes but larger segments are not $$
+ * $$ sensitive to alignment. $$
+ * $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
+ *
+ * How to use:
+ *
+ * Init MVE driver on (unused) unit 2:
+ *
+ * mve = mvtst_init(2)
+ *
+ * data = { 1,2,3,4,5,6,7,8,9,0xa,0xb, ... }
+ *
+ * Alloc 2-element mbuf chain (1st holds an
+ * ethernet header which is > 8bytes so we can't
+ * test this with only 1 mbuf. The 2nd mbuf holds
+ * a small fragment of data).
+ *
+ * mb = mvtst_getbuf(mve)
+ *
+ * Copy data into aligned area inside 2nd mbuf,
+ * (so that you can see if the chip starts using
+ * the aligned area rather than the unaligned
+ * buffer pointer). Point mbuf's data pointer
+ * at 'off'set from the aligned area:
+ *
+ * mvtst_putbuf(mb, data, len, offset)
+ *
+ * Send chain off:
+ *
+ * BSP_mve_send_buf(mve, mb, 0, 0)
+ *
+ * Watch raw data:
+ *
+ * tcpdump -XX -vv -s0 ether host <my-ether-addr>
+ *
+ * E.g, if offset = 1, len = 2 then we would like
+ * to see
+ *
+ * GOOD:
+ * < 14 header bytes > 0x02, 0x03
+
+ * but if the chip starts DMA at aligned address
+ * we see instead
+ * BAD:
+ * < 14 header bytes > 0x01, 0x02
+ */
+
+static inline void *rmalloc(size_t l) { return malloc(l); }
+static inline void rfree(void *p) { return free(p); }
+
+#define _KERNEL
+#include <sys/mbuf.h>
+
+static void
+cleanup_buf(void *u_b, void *closure, int error)
+{
+rtems_bsdnet_semaphore_obtain();
+ m_freem((struct mbuf*)u_b);
+rtems_bsdnet_semaphore_release();
+}
+
+struct mbuf *mvtst_getbuf(struct mveth_private *mp)
+{
+struct mbuf *m,*n;
+
+ if ( !mp ) {
+ printf("need driver ptr arg\n");
+ return 0;
+ }
+rtems_bsdnet_semaphore_obtain();
+ MGETHDR(m, M_DONTWAIT, MT_DATA);
+ MGET(n, M_DONTWAIT, MT_DATA);
+ m->m_next = n;
+rtems_bsdnet_semaphore_release();
+ /* Ethernet header */
+ memset( mtod(m, unsigned char*), 0xff, 6);
+ BSP_mve_read_eaddr(mp, mtod(m, unsigned char*) + 6);
+ /* Arbitrary; setting to IP but we don't bother
+ * to setup a real IP header. We just watch the
+ * raw packet contents...
+ */
+ mtod(m, unsigned char*)[12] = 0x08;
+ mtod(m, unsigned char*)[13] = 0x00;
+ m->m_pkthdr.len = m->m_len = 14;
+ n->m_len = 0;
+ return m;
+}
+
+int
+mvtst_putbuf(struct mbuf *m, void *data, int len, int off)
+{
+int i;
+ if ( m ) {
+ m->m_pkthdr.len += len;
+ if ( ( m= m->m_next ) ) {
+ m->m_len = len;
+ memcpy(mtod(m, void*), data, 32);
+ m->m_data += off;
+ printf("m.dat: 0x%08x, m.data: 0x%08x\n", m->m_dat, m->m_data);
+ for ( i=0; i< 16; i++ ) {
+ printf(" %02x,",mtod(m, unsigned char*)[i]);
+ }
+ printf("\n");
+ }
+ }
+
+ return 0;
+}
+
+static void *alloc_rxbuf(int *p_size, unsigned long *paddr)
+{
+ return *(void**)paddr = rmalloc((*p_size = 1800));
+}
+
+static void consume_buf(void *buf, void *closure, int len)
+{
+ rfree(buf);
+}
+
+void *
+mvtst_init(int unit)
+{
+struct mveth_private *mp;
+ mp = BSP_mve_setup(
+ unit, 0,
+ cleanup_buf, 0,
+ alloc_rxbuf,
+ consume_buf, 0,
+ 10, 10,
+ 0);
+ if ( mp )
+ BSP_mve_init_hw(mp, 0, 0);
+ return mp;
+}
diff --git a/c/src/lib/libbsp/powerpc/beatnik/network/if_mve/testing.c b/c/src/lib/libbsp/powerpc/beatnik/network/if_mve/testing.c
new file mode 100644
index 0000000000..71090a3aa0
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/beatnik/network/if_mve/testing.c
@@ -0,0 +1,323 @@
+#ifndef KERNEL
+#define KERNEL
+#endif
+
+#include <rtems.h>
+#include <rtems/rtems_bsdnet_internal.h>
+#include <bsp.h>
+#include <sys/mbuf.h>
+
+#include "mv64340_eth_ll.h"
+
+#include <string.h>
+#include <assert.h>
+
+#include <netinet/in.h>
+#include <stdio.h>
+
+#define RX_SPACING 1
+#define TX_SPACING 1
+
+#define RX_RING_SIZE (MV64340_RX_QUEUE_SIZE*RX_SPACING)
+#define TX_RING_SIZE (MV64340_TX_QUEUE_SIZE*TX_SPACING)
+
+
+struct eth_rx_desc rx_ring[RX_RING_SIZE] __attribute__((aligned(32)));
+struct eth_rx_desc rx_ring[RX_RING_SIZE] = {{0},};
+
+struct eth_tx_desc tx_ring[TX_RING_SIZE] __attribute__((aligned(32)));
+struct eth_tx_desc tx_ring[TX_RING_SIZE] = {{0},};
+
+/* packet buffers */
+char rx_buf[MV64340_RX_QUEUE_SIZE][2048] __attribute__((aligned(8)));
+char rx_buf[MV64340_RX_QUEUE_SIZE][2048];
+
+char tx_buf[MV64340_RX_QUEUE_SIZE][2048] __attribute__((aligned(8)));
+char tx_buf[MV64340_RX_QUEUE_SIZE][2048];
+
+char BcHeader[22] = {
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* dst */
+ 0x00, 0x01, 0xaf, 0x13, 0xb5, 0x3e, /* src */
+ 00, 00, /* len */
+ 0xAA, /* dsap */
+ 0xAA, /* ssap */
+ 0x03, /* ctrl */
+ 0x08, 0x00, 0x56, /* snap_org [stanford] */
+ 0x80, 0x5b, /* snap_type (stanford kernel) */
+};
+
+struct mv64340_private mveth = {
+ port_num: 0,
+ port_mac_addr: {0x00,0x01,0xAF,0x13,0xB5,0x3C},
+ /* port_config .. tx_resource_err are set by port_init */
+ 0
+};
+
+struct pkt_info p0,p1;
+
+static inline void rx_stopq(int port)
+{
+ MV_WRITE(MV64340_ETH_RECEIVE_QUEUE_COMMAND_REG(port), 0x0000ff00);
+}
+
+static inline void tx_stopq(int port)
+{
+ MV_WRITE(MV64340_ETH_TRANSMIT_QUEUE_COMMAND_REG(port), 0x0000ff00);
+}
+
+#define MV64360_ENET2MEM_SNOOP_NONE 0x0000
+#define MV64360_ENET2MEM_SNOOP_WT 0x1000
+#define MV64360_ENET2MEM_SNOOP_WB 0x2000
+
+#if 0
+int
+mveth_init(struct mv64340_private *mp)
+{
+int i;
+ mp->p_rx_desc_area = rx_ring;
+ mp->p_tx_desc_area = tx_ring;
+
+ rx_stopq(mp->port_num);
+ tx_stopq(mp->port_num);
+
+ /* MotLoad has cache snooping disabled on the ENET2MEM windows.
+ * Some comments in (linux) indicate that there are errata
+ * which cause problems which is a real bummer.
+ * We try it anyways...
+ */
+ {
+ unsigned long disbl, bar;
+ disbl = MV_READ(MV64340_ETH_BASE_ADDR_ENABLE_REG);
+ /* disable all 6 windows */
+ MV_WRITE(MV64340_ETH_BASE_ADDR_ENABLE_REG, 0x3f);
+ /* set WB snooping */
+ for ( i=0; i<6*8; i+=8 ) {
+ if ( (bar = MV_READ(MV64340_ETH_BAR_0 + i)) && MV_READ(MV64340_ETH_SIZE_REG_0 + i) ) {
+ MV_WRITE(MV64340_ETH_BAR_0 + i, bar | MV64360_ENET2MEM_SNOOP_WB);
+ /* read back to flush fifo [linux comment] */
+ (void)MV_READ(MV64340_ETH_BAR_0 + i);
+ }
+ }
+ /* restore/re-enable */
+ MV_WRITE(MV64340_ETH_BASE_ADDR_ENABLE_REG, disbl);
+ }
+
+ eth_port_init(mp);
+
+ sleep(1);
+
+ mveth_init_tx_desc_ring(mp);
+ mveth_init_rx_desc_ring(mp);
+#if 0
+ for ( i = 0; i<MV64340_RX_QUEUE_SIZE; i++ ) {
+ p0.byte_cnt = sizeof(rx_buf[0]);
+ p0.buf_ptr = (dma_addr_t)rx_buf[i];
+ p0.return_info = (void*)i;
+ /* other fields are not used by ll driver */
+ assert ( ETH_OK == eth_rx_return_buff(mp,&p0) );
+ }
+ memset(&p0, 0, sizeof(p0));
+#endif
+
+ return eth_port_start(mp);
+}
+#endif
+
+void
+mveth_stop(struct mv64340_private *mp)
+{
+extern void mveth_stop_hw();
+ rtems_bsdnet_semaphore_obtain();
+ mveth_stop_hw(mp);
+ rtems_bsdnet_semaphore_release();
+}
+
+extern int mveth_send_mbuf();
+extern int mveth_swipe_tx();
+
+int
+mveth_tx(struct mv64340_private *mp, char *data, int len, int nbufs)
+{
+int rval = -1,l;
+char *p;
+struct mbuf *m;
+char *emsg = 0;
+
+ rtems_bsdnet_semaphore_obtain();
+ MGETHDR(m, M_WAIT, MT_DATA);
+ if ( !m ) {
+ emsg="Unable to allocate header\n";
+ goto bail;
+ }
+ MCLGET(m, M_WAIT);
+ if ( !(m->m_flags & M_EXT) ) {
+ m_freem(m);
+ emsg="Unable to allocate cluster\n";
+ goto bail;
+ }
+ p = mtod(m, char *);
+ l = 0;
+ switch (nbufs) {
+ case 3:
+ default:
+ emsg="nbufs arg must be 1..3\n";
+ goto bail;
+
+ case 1:
+ l += sizeof(BcHeader);
+ memcpy(p, &BcHeader, sizeof(BcHeader));
+ p += sizeof(BcHeader);
+
+ case 2:
+ memcpy(p,data,len);
+ l += len;
+ m->m_len = m->m_pkthdr.len = l;
+ if ( 2 == nbufs ) {
+ M_PREPEND(m, sizeof (BcHeader), M_WAIT);
+ if (!m) {
+ emsg = "Unable to prepend\n";
+ goto bail;
+ }
+ p = mtod(m, char*);
+ memcpy(p,&BcHeader,sizeof(BcHeader));
+ l += sizeof(BcHeader);
+ }
+ break;
+ }
+ *(short*)(mtod(m, char*) + 12) = htons(l-14);
+ rval = mveth_send_mbuf(mp,m);
+
+bail:
+ rtems_bsdnet_semaphore_release();
+ if (emsg)
+ printf(emsg);
+
+#if 0
+ /*
+ * Add local net header. If no space in first mbuf,
+ * allocate another.
+ */
+ M_PREPEND(m, sizeof (struct ether_header), M_DONTWAIT);
+ if (m == 0)
+ senderr(ENOBUFS);
+ eh = mtod(m, struct ether_header *);
+ (void)memcpy(&eh->ether_type, &type,
+ sizeof(eh->ether_type));
+ (void)memcpy(eh->ether_dhost, edst, sizeof (edst));
+ (void)memcpy(eh->ether_shost, ac->ac_enaddr,
+ sizeof(eh->ether_shost));
+#endif
+ return rval;
+}
+
+int
+mveth_protected(int (*p)(struct mv64340_private*), struct mv64340_private *mp)
+{
+int rval;
+ rtems_bsdnet_semaphore_obtain();
+ rval = p(mp);
+ rtems_bsdnet_semaphore_release();
+ return rval;
+}
+
+int
+mveth_rx(struct mv64340_private *mp)
+{
+extern int mveth_swipe_rx();
+ return mveth_protected(mveth_swipe_rx,mp);
+}
+
+int
+mveth_reclaim(struct mv64340_private *mp)
+{
+extern int mveth_swipe_tx();
+ return mveth_protected(mveth_swipe_tx,mp);
+}
+
+
+int preth(FILE *f, char *p)
+{
+int i;
+ for (i=0; i<4; i++)
+ fprintf(f,"%02X:",p[i]);
+ fprintf(f,"%02X",p[i]);
+ return 6;
+}
+
+char *errcode2str(st)
+{
+char *rval;
+ switch(st) {
+ case ETH_OK:
+ rval = "OK";
+ break;
+ case ETH_ERROR:
+ rval = "Fundamental error.";
+ break;
+ case ETH_RETRY:
+ rval = "Could not process request. Try later.";
+ break;
+ case ETH_END_OF_JOB:
+ rval = "Ring has nothing to process.";
+ break;
+ case ETH_QUEUE_FULL:
+ rval = "Ring resource error.";
+ break;
+ case ETH_QUEUE_LAST_RESOURCE:
+ rval = "Ring resources about to exhaust.";
+ break;
+ default:
+ rval = "UNKNOWN"; break;
+ }
+ return rval;
+}
+
+
+#if 0
+int
+mveth_rx(struct mv64340_private *mp)
+{
+int st;
+struct pkt_info p;
+ if ( ETH_OK != (st=eth_port_receive(mp, &p)) ) {
+ fprintf(stderr,"receive: %s\n", errcode2str(st));
+ return -1;
+ }
+ printf("%i bytes received from ", p.byte_cnt);
+ preth(stdout,(char*)p.buf_ptr+6);
+ printf(" (desc. stat: 0x%08x)\n", p.cmd_sts);
+
+ p.byte_cnt = sizeof(rx_buf[0]);
+ p.buf_ptr -= RX_BUF_OFFSET;
+ if ( ETH_OK != (st=eth_rx_return_buff(mp,&p) ) ) {
+ fprintf(stderr,"returning buffer: %s\n", errcode2str(st));
+ return -1;
+ }
+ return 0;
+}
+#endif
+
+int
+dring()
+{
+int i;
+if (1) {
+struct eth_rx_desc *pr;
+printf("RX:\n");
+ for (i=0, pr=rx_ring; i<RX_RING_SIZE; i+=RX_SPACING, pr+=RX_SPACING) {
+ dcbi(pr);
+ printf("cnt: 0x%04x, size: 0x%04x, stat: 0x%08x, next: 0x%08x, buf: 0x%08x\n",
+ pr->byte_cnt, pr->buf_size, pr->cmd_sts, pr->next_desc_ptr, pr->buf_ptr);
+ }
+}
+if (1) {
+struct eth_tx_desc *pt;
+printf("TX:\n");
+ for (i=0, pt=tx_ring; i<TX_RING_SIZE; i+=TX_SPACING, pt+=TX_SPACING) {
+ dcbi(pt);
+ printf("cnt: 0x%04x, stat: 0x%08x, next: 0x%08x, buf: 0x%08x\n",
+ pt->byte_cnt, pt->cmd_sts, pt->next_desc_ptr, pt->buf_ptr);
+ }
+}
+ return 0;
+}
diff --git a/c/src/lib/libbsp/powerpc/beatnik/network/porting/LICENSE b/c/src/lib/libbsp/powerpc/beatnik/network/porting/LICENSE
new file mode 100644
index 0000000000..62b91ab03d
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/beatnik/network/porting/LICENSE
@@ -0,0 +1,51 @@
+/* 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. Some files were ported from
+ * netbsd and/or freebsd and are covered by the respective
+ * file header copyright notices.
+ */
+
+/*
+ * Authorship
+ * ----------
+ * This software ('RTEMS-portability wrappers for BSD network drivers') was
+ * created by Till Straumann <strauman@slac.stanford.edu>, 2005-2007,
+ * Stanford Linear Accelerator Center, Stanford University.
+ *
+ * Acknowledgement of sponsorship
+ * ------------------------------
+ * The 'RTEMS-portability wrappers for BSD network drivers' 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
+ */
diff --git a/c/src/lib/libbsp/powerpc/beatnik/network/porting/Makefile.template b/c/src/lib/libbsp/powerpc/beatnik/network/porting/Makefile.template
new file mode 100644
index 0000000000..3c5d6e3e33
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/beatnik/network/porting/Makefile.template
@@ -0,0 +1,84 @@
+#
+# Makefile.lib,v 1.5 2000/06/12 15:00:14 joel Exp
+#
+# Copyright: Till Straumann <strauman@slac.stanford.edu>, 2005;
+# License: see LICENSE file.
+#
+# Templates/Makefile.lib
+# Template library Makefile
+#
+
+LIBNAME=libif_XXX.a # XXX- your library names goes here
+LIB=${ARCH}/${LIBNAME}
+
+# C and C++ source names, if any, go here -- minus the .c or .cc
+C_PIECES=if_XXX if_XXX_rtems
+C_FILES=$(C_PIECES:%=%.c)
+C_O_FILES=$(C_PIECES:%=${ARCH}/%.o)
+
+CC_PIECES=
+CC_FILES=$(CC_PIECES:%=%.cc)
+CC_O_FILES=$(CC_PIECES:%=${ARCH}/%.o)
+
+H_FILES=
+
+# Assembly source names, if any, go here -- minus the .S
+S_PIECES=
+S_FILES=$(S_PIECES:%=%.S)
+S_O_FILES=$(S_FILES:%.S=${ARCH}/%.o)
+
+SRCS=$(C_FILES) $(CC_FILES) $(H_FILES) $(S_FILES)
+OBJS=$(C_O_FILES) $(CC_O_FILES) $(S_O_FILES)
+
+include $(RTEMS_MAKEFILE_PATH)/Makefile.inc
+
+include $(RTEMS_CUSTOM)
+include $(RTEMS_ROOT)/make/lib.cfg
+
+#
+# Add local stuff here using +=
+#
+
+#DEFINES += -DHAVE_LIBBSPEXT -DDEBUG_MODULAR
+CPPFLAGS += -I. -Ilibchip -Iporting
+# bsdnet newproc generated daemon is non-FP;
+# prevent optimizer from generating FP instructions
+CFLAGS += -Wno-unused-variable -msoft-float
+
+#
+# Add your list of files to delete here. The config files
+# already know how to delete some stuff, so you may want
+# to just run 'make clean' first to see what gets missed.
+# 'make clobber' already includes 'make clean'
+#
+
+CLEAN_ADDITIONS +=
+CLOBBER_ADDITIONS +=
+
+all: ${ARCH} $(SRCS) $(LIB)
+
+$(LIB): ${OBJS}
+ $(make-library)
+
+ifndef RTEMS_SITE_INSTALLDIR
+RTEMS_SITE_INSTALLDIR = $(PROJECT_RELEASE)
+endif
+
+${RTEMS_SITE_INSTALLDIR}/include \
+${RTEMS_SITE_INSTALLDIR}/lib \
+${RTEMS_SITE_INSTALLDIR}/bin \
+${RTEMS_SITE_INSTALLDIR}/$(RTEMS_BSP)/include \
+${RTEMS_SITE_INSTALLDIR}/$(RTEMS_BSP)/lib \
+${RTEMS_SITE_INSTALLDIR}/$(RTEMS_BSP)/bin :
+ test -d $@ || mkdir -p $@
+
+# Install the library, appending _g or _p as appropriate.
+# for include files, just use $(INSTALL_CHANGE)
+#
+# NOTES:
+# - BSP specific libraries, headers etc. should be installed to
+# $RTEMS_SITE_INSTALLDIR)/$(RTEMS_BSP)/lib
+#
+
+install: all $(RTEMS_SITE_INSTALLDIR)/lib
+ $(INSTALL_VARIANT) -m 644 ${LIB} ${RTEMS_SITE_INSTALLDIR}/lib
diff --git a/c/src/lib/libbsp/powerpc/beatnik/network/porting/README b/c/src/lib/libbsp/powerpc/beatnik/network/porting/README
new file mode 100644
index 0000000000..57a5690e9e
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/beatnik/network/porting/README
@@ -0,0 +1,106 @@
+Templates to help porting freebsd networking drivers
+to rtems (focus on i386 and powerpc) using a 'quick and dirty'
+approach.
+This is not an elegant piece of software -- be warned.
+
+/* Copyright: Till Straumann <strauman@slac.stanford.edu>, 2005;
+ * License: see LICENSE file.
+ */
+
+Release info: $Name$
+
+Usage:
+
+ A obtain the freebsd driver source. It usually is made
+ up of a
+ if_XXX.c -- core driver
+ if_XXXreg.h -- core header
+ if_XXXvar.h -- some have it, some don't
+ if_XXX_<bus>.c -- glue to integrate the core
+ driver with different environments
+ (such as pccard, pci, ...). There
+ are several of these.
+
+ Note that you might have to get an older version
+ as some structures and interfaces may have undergone
+ significant changes since the bsd/networking version that
+ was ported to rtems.
+
+ B Copy the Makefile and rtemscompat_defs.h templates to the
+ driver source dir and edit them.
+
+ C Edit if_XXXreg.h and comment all unneeded fields from the
+ 'softc' structure declaration with
+
+ #ifndef __rtems__
+ #endif
+
+ In particular, the bushandle field (as defined in rtemscompat_defs.h)
+ above, see comments in the template) must be re-declared:
+
+ #ifndef __rtems__
+ bus_space_handle_t XXX_bhandle;
+ #else
+ unsigned XXX_bhandle;
+ unsigned char irq_no;
+ unsigned char b,d,f; /* PCI tuple; needed for PCI only */
+ rtems_id tid; /* driver task id */
+ #endif
+
+ Later, the compilation attempts will help identifying
+ fields that need to be removed.
+
+ I like the #ifdef __rtems__ construct as it minimizes changes
+ to the source thus making merging updated driver versions easier.
+
+ D Edit if_XXX.c; at the very top, include the lines
+
+ #ifdef __rtems__
+ #include <rtemscompat.h>
+ #endif
+
+ use the #ifndef __rtems__ #endif construct to comment
+ unneeded / unsupported inclusion of headers and code pieces.
+
+ - inclusion of net/if_media.h must usually be mapped to
+ libchip/if_media.h
+
+ comment all vm, machine, bus, mii etc. related headers.
+
+ - replace inclusion of if_XXXreg.h by
+
+ #include "if_XXXreg.h"
+ #include <rtemscompat1.h>
+
+ - work through the if_XXX.c and if_XXXreg.h files commenting
+ stuff until if_XXX.c compiles. This might involve hacking
+ the helper headers.
+
+ - pay attention to endian issues; things may need to be fixed!
+
+ - at the top where the freebsd 'methods' and the like are
+ commented, add a definition of the driver methods for RTEMS:
+
+ #ifdef __rtems__
+ net_drv_tbl_t METHODS = {
+ n_probe : XXX_probe,
+ n_attach : XXX_attach,
+ n_detach : XXX_detach, /* optional; */
+ n_intr : XXX_intr, /* freebsd ISR; executed from daemon under RTEMS */
+ };
+ #endif
+
+ - make sure all the if_xxx methods are set; in particular,
+ set
+ sc->if_output = ether_output;
+
+ - on input:
+ you can use DO_ETHER_INPUT_SKIPPING_ETHER_HEADER() macro
+ -- if you don't MAKE SURE THE RECEIVING INTERFACE IS SET
+ in the mbuf packet header!!!
+
+ E create 'rtems_<chip>_setup()' to probe for devices and
+ set the softc struct's base address, interrupt line and
+ bus/dev/fun triple (PCI only).
+ For PCI devices, a generic setup routine already comes with
+ porting/if_xxx_rtems.c -> nothing needs to be written!
diff --git a/c/src/lib/libbsp/powerpc/beatnik/network/porting/if_xxx.modini.c b/c/src/lib/libbsp/powerpc/beatnik/network/porting/if_xxx.modini.c
new file mode 100644
index 0000000000..1abad7dc22
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/beatnik/network/porting/if_xxx.modini.c
@@ -0,0 +1,34 @@
+#include <rtems.h>
+#include <porting/rtemscompat.h>
+
+/* CEXP module initialization/finalization */
+
+/* Copyright: Till Straumann <strauman@slac.stanford.edu>, 2005;
+ * License: see LICENSE file.
+ */
+
+void
+_cexpModuleInitialize(void *unused)
+{
+extern void NET_EMBEMB(rtems_,NETDRIVER_PREFIX,_bringup)(char *);
+ METHODSPTR = &METHODS;
+/*
+#ifdef DEBUG
+ NET_EMBEMB(rtems_,NETDRIVER_PREFIX,_bringup)("192.168.2.13/255.255.255.0");
+#endif
+*/
+}
+
+int
+_cexpModuleFinalize(void *unused)
+{
+#ifdef DEBUG
+extern int NET_EMBEMB(rtems_,NETDRIVER_PREFIX,_bringdown)();
+ if (NET_EMBEMB(rtems_,NETDRIVER_PREFIX,_bringdown)())
+ return -1;
+ METHODSPTR = 0;
+ return 0;
+#else
+ return -1;
+#endif
+}
diff --git a/c/src/lib/libbsp/powerpc/beatnik/network/porting/if_xxx_rtems.c b/c/src/lib/libbsp/powerpc/beatnik/network/porting/if_xxx_rtems.c
new file mode 100644
index 0000000000..0c7d2d9eba
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/beatnik/network/porting/if_xxx_rtems.c
@@ -0,0 +1,504 @@
+/* $Id$ */
+#include <rtemscompat.h>
+
+/* Template for driver task, setup and attach routines. To be instantiated
+ * by defining the relevant symbols in header files.
+ */
+
+/* Copyright: Till Straumann <strauman@slac.stanford.edu>, 2005;
+ * License: see LICENSE file.
+ */
+
+/* $Name$ */
+
+#include <rtems/irq.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include <sys/cdefs.h>
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+
+#include <net/if.h>
+#include <net/if_arp.h>
+
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+#include <arpa/inet.h>
+
+#include <net/if_media.h>
+
+#ifdef IF_REG_HEADER
+#include IF_REG_HEADER
+#endif
+#ifdef IF_VAR_HEADER
+#include IF_VAR_HEADER
+#endif
+
+#include <rtemscompat1.h>
+
+#define EX_EVENT RTEMS_EVENT_1
+#undef IRQ_AT_8259
+
+NETDEV_DECL = { /*[0]:*/{ /* softc: */ { /* arpcom: */{ /* ac_if: */ { 0 }}}}};
+
+static void net_daemon(void *arg);
+
+#ifdef HAVE_LIBBSPEXT
+#include <bsp/bspExt.h>
+static void the_net_isr(void *);
+#else
+static void noop(const rtems_irq_connect_data *unused) {}
+static int noop1(const rtems_irq_connect_data *unused) { return 0;}
+#if ISMINVERSION(4,6,99)
+static void the_net_isr(rtems_irq_hdl_param);
+#else
+static void the_net_isr();
+#if NETDRIVER_SLOTS > 1
+#error only one instance supported (stupid IRQ API)
+#else
+static struct NET_SOFTC *thesc;
+#endif
+#endif
+#endif
+
+#if defined(NETDRIVER_PCI)
+/* Public setup routine for PCI devices;
+ * TODO: currently doesn't work for subsystem vendor/id , i.e.
+ * devices behind a standard PCI interface...
+ */
+int
+NET_EMBEMB(rtems_,NETDRIVER_PREFIX,_pci_setup)(int inst);
+#endif
+
+static unsigned
+NET_EMBEMB(,NETDRIVER_PREFIX,_net_driver_ticks_per_sec) = 0;
+
+/* other drivers may already have this created */
+extern unsigned net_driver_ticks_per_sec
+__attribute__((weak, alias(NET_STRSTR(NETDRIVER_PREFIX)"_net_driver_ticks_per_sec") ));
+
+#ifdef DEBUG_MODULAR
+net_drv_tbl_t * volatile METHODSPTR = 0;
+#endif
+
+
+int
+NET_EMBEMB(rtems_,NETDRIVER_PREFIX,_attach)
+ (struct rtems_bsdnet_ifconfig *config, int attaching)
+{
+ int error = 0;
+ device_t dev = net_dev_get(config);
+ struct NET_SOFTC *sc;
+ struct ifnet *ifp;
+#ifndef HAVE_LIBBSPEXT
+ rtems_irq_connect_data irq_data = {
+ 0,
+ the_net_isr,
+#if ISMINVERSION(4,6,99)
+ 0,
+#endif
+ noop,
+ noop,
+ noop1 };
+#endif
+
+ if ( !dev )
+ return 1;
+
+ if ( !dev->d_softc.NET_SOFTC_BHANDLE_FIELD ) {
+#if defined(NETDRIVER_PCI)
+ device_printf(dev,NETDRIVER" unit not configured; executing setup...");
+ /* setup should really be performed prior to attaching.
+ * Wipe the device; setup and re-obtain the device...
+ */
+ memset(dev,0,sizeof(*dev));
+ error = NET_EMBEMB(rtems_,NETDRIVER_PREFIX,_pci_setup)(-1);
+ /* re-obtain the device */
+ dev = net_dev_get(config);
+ if ( !dev ) {
+ printk("Unable to re-assign device structure???\n");
+ return 1;
+ }
+ if (error <= 0) {
+ device_printf(dev,NETDRIVER" FAILED; unable to attach interface, sorry\n");
+ return 1;
+ }
+ device_printf(dev,"success\n");
+#else
+ device_printf(dev,NETDRIVER" unit not configured; use 'rtems_"NETDRIVER"_setup()'\n");
+ return 1;
+#endif
+ }
+
+ if ( !net_driver_ticks_per_sec )
+ rtems_clock_get( RTEMS_CLOCK_GET_TICKS_PER_SECOND, &net_driver_ticks_per_sec );
+
+ sc = device_get_softc( dev );
+ ifp = &sc->arpcom.ac_if;
+
+#ifdef DEBUG_MODULAR
+ if (!METHODSPTR) {
+ device_printf(dev,NETDRIVER": method pointer not set\n");
+ return -1;
+ }
+#endif
+
+ if ( attaching ) {
+ if ( ifp->if_init ) {
+ device_printf(dev,NETDRIVER" Driver already attached.\n");
+ return -1;
+ }
+ if ( config->hardware_address ) {
+ /* use configured MAC address */
+ memcpy(sc->arpcom.ac_enaddr, config->hardware_address, ETHER_ADDR_LEN);
+ } else {
+#ifdef NET_READ_MAC_ADDR
+ NET_READ_MAC_ADDR(sc);
+#endif
+ }
+ if ( METHODSPTR->n_attach(dev) ) {
+ device_printf(dev,NETDRIVER"_attach() failed\n");
+ return -1;
+ }
+ } else {
+ if ( !ifp->if_init ) {
+ device_printf(dev,NETDRIVER" Driver not attached.\n");
+ return -1;
+ }
+ if ( METHODSPTR->n_detach ) {
+ if ( METHODSPTR->n_detach(dev) ) {
+ device_printf(dev,NETDRIVER"_detach() failed\n");
+ return -1;
+ }
+ } else {
+ device_printf(dev,NETDRIVER"_detach() not implemented\n");
+ return -1;
+ }
+ }
+
+
+ if ( !sc->tid )
+ sc->tid = rtems_bsdnet_newproc(NETDRIVER"d", 4096, net_daemon, sc);
+
+ if (attaching) {
+#ifdef DEBUG
+ printf("Installing IRQ # %i\n",sc->irq_no);
+#endif
+#ifdef HAVE_LIBBSPEXT
+ if ( bspExtInstallSharedISR(sc->irq_no, the_net_isr, sc, 0) )
+#else
+ /* BSP dependent :-( */
+ irq_data.name = sc->irq_no;
+#if ISMINVERSION(4,6,99)
+ irq_data.handle = (rtems_irq_hdl_param)sc;
+#else
+ thesc = sc;
+#endif
+ if ( ! BSP_install_rtems_irq_handler( &irq_data ) )
+#endif
+ {
+ fprintf(stderr,NETDRIVER": unable to install ISR\n");
+ error = -1;
+ }
+ } else {
+ if ( sc->irq_no ) {
+#ifdef DEBUG
+ printf("Removing IRQ # %i\n",sc->irq_no);
+#endif
+#ifdef HAVE_LIBBSPEXT
+ if (bspExtRemoveSharedISR(sc->irq_no, the_net_isr, sc))
+#else
+ /* BSP dependent :-( */
+ irq_data.name = sc->irq_no;
+#if ISMINVERSION(4,6,99)
+ irq_data.handle = (rtems_irq_hdl_param)sc;
+#endif
+ if ( ! BSP_remove_rtems_irq_handler( &irq_data ) )
+#endif
+ {
+ fprintf(stderr,NETDRIVER": unable to uninstall ISR\n");
+ error = -1;
+ }
+ }
+ }
+ return error;
+}
+
+static void
+the_net_isr(
+#ifdef HAVE_LIBBSPEXT
+void *thesc
+#elif ISMINVERSION(4,6,99)
+rtems_irq_hdl_param thesc
+#endif
+)
+{
+struct NET_SOFTC *sc = thesc;
+
+ /* disable interrupts */
+ NET_DISABLE_IRQS(sc);
+
+ rtems_event_send( sc->tid, EX_EVENT );
+}
+
+static void net_daemon(void *arg)
+{
+struct NET_SOFTC *sc = arg;
+rtems_event_set evs;
+
+ for (;;) {
+ rtems_bsdnet_event_receive(
+ EX_EVENT,
+ RTEMS_WAIT | RTEMS_EVENT_ANY,
+ RTEMS_NO_TIMEOUT,
+ &evs);
+
+ METHODSPTR->n_intr(sc);
+
+ /* re-enable interrupts */
+ NET_ENABLE_IRQS(sc);
+ }
+}
+
+static struct NET_SOFTC *
+net_drv_check_unit(int unit)
+{
+ unit--;
+ if ( unit < 0 || unit >= NETDRIVER_SLOTS ) {
+ fprintf(stderr,"Invalid unit # %i (not in %i..%i)\n", unit+1, 1, NETDRIVER_SLOTS);
+ return 0;
+ }
+
+ if ( THEDEVS[unit].d_name ) {
+ fprintf(stderr,"Unit %i already set up\n", unit+1);
+ return 0;
+ }
+
+ memset( &THEDEVS[unit], 0, sizeof(THEDEVS[0]) );
+
+ return &THEDEVS[unit].d_softc;
+}
+
+struct rtems_bsdnet_ifconfig NET_EMBEMB(NETDRIVER_PREFIX,_dbg,_config) = {
+ NETDRIVER"1",
+ NET_EMBEMB(rtems_,NETDRIVER_PREFIX,_attach),
+ 0
+};
+
+#ifdef DEBUG
+void
+NET_EMBEMB(rtems_,NETDRIVER_PREFIX,_bringup)(char *ipaddr)
+{
+short flags;
+struct sockaddr_in addr;
+char *mask;
+
+
+ if (!ipaddr) {
+ printf("Need an ip[/mask] argument (dot notation)\n");
+ return;
+ }
+
+ ipaddr = strdup(ipaddr);
+
+ if ( (mask = strchr(ipaddr,'/')) ) {
+ *mask++=0;
+ } else {
+ mask = "255.255.255.0";
+ }
+
+#if defined(NETDRIVER_PCI)
+ /* this fails if already setup */
+ NET_EMBEMB(rtems_,NETDRIVER_PREFIX,_pci_setup)(-1);
+#endif
+ rtems_bsdnet_attach(&NET_EMBEMB(NETDRIVER_PREFIX,_dbg,_config));
+
+ flags = IFF_UP /*| IFF_PROMISC*/;
+ if ( rtems_bsdnet_ifconfig(NETDRIVER"1",SIOCSIFFLAGS,&flags) < 0 ) {
+ printf("Can't bring '"NETDRIVER"1' up\n");
+ goto cleanup;
+ }
+ memset(&addr,0,sizeof(addr));
+ addr.sin_len = sizeof(addr);
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = inet_addr(mask);
+ if ( rtems_bsdnet_ifconfig(NETDRIVER"1",SIOCSIFNETMASK,&addr) < 0 ) {
+ printf("Unable to set netmask on '"NETDRIVER"1'\n");
+ goto cleanup;
+ }
+ addr.sin_addr.s_addr = inet_addr(ipaddr);
+ if ( rtems_bsdnet_ifconfig(NETDRIVER"1",SIOCSIFADDR,&addr) < 0 ) {
+ printf("Unable to set address on '"NETDRIVER"1'\n");
+ goto cleanup;
+ }
+cleanup:
+ the_real_free (ipaddr);
+}
+
+int
+NET_EMBEMB(rtems_,NETDRIVER_PREFIX,_bringdown)()
+{
+short flags;
+ flags = 0;
+ if ( rtems_bsdnet_ifconfig(NETDRIVER"1",SIOCSIFFLAGS,&flags) < 0 ) {
+ printf("Can't bring '"NETDRIVER"1' down\n");
+ return -1;
+ }
+
+ rtems_bsdnet_detach(&NET_EMBEMB(NETDRIVER_PREFIX,_dbg,_config));
+ return 0;
+}
+#endif
+
+
+#if defined(NETDRIVER_PCI) && !defined(NETDRIVER_OWN_SETUP)
+/* Public setup routine for PCI devices;
+ * TODO: currently doesn't work for subsystem vendor/id , i.e.
+ * devices behind a standard PCI interface...
+ * passing 'inst' > only sets-up the 'inst'th card; passing
+ * 'inst' == 0 sets-up all matching cards.
+ */
+int
+NET_EMBEMB(rtems_,NETDRIVER_PREFIX,_pci_setup)(int inst)
+{
+unsigned b,d,f,i,isio,unit;
+rtemscompat_32_t base;
+unsigned short cmd,id;
+unsigned char h;
+struct NET_SOFTC *sc;
+unsigned try[] = { PCI_BASE_ADDRESS_0, PCI_BASE_ADDRESS_1, 0 };
+
+#ifdef DEBUG_MODULAR
+ if ( !METHODSPTR ) {
+ fprintf(stderr,NETDRIVER": Methods pointer not set\n");
+ return -1;
+ }
+#endif
+
+ /* 0 can be reached when looking for the desired instance */
+ if ( 0 == inst )
+ inst = -1;
+
+#ifdef HAVE_LIBBSPEXT
+ /* make sure it's initialized */
+ bspExtInit();
+#endif
+
+ /* scan PCI for supported devices */
+ for ( b=0, sc=0, unit=0; b<pci_bus_count(); b++ ) {
+ for ( d=0; d<PCI_MAX_DEVICES; d++ ) {
+ pci_read_config_word(b,d,0,PCI_VENDOR_ID,&id);
+ if ( 0xffff == id )
+ continue; /* empty slot */
+
+ pci_read_config_byte(b,d,0,PCI_HEADER_TYPE,&h);
+ h = h&0x80 ? PCI_MAX_FUNCTIONS : 1; /* multifunction device ? */
+
+ for ( f=0; f<h; f++ ) {
+ if ( !sc && !(sc=net_drv_check_unit(unit+1))) {
+ fprintf(stderr,"Not enough driver slots; stop looking for more devices...\n");
+ return unit;
+ }
+ pci_read_config_word(b,d,f,PCI_VENDOR_ID,&id);
+ if ( 0xffff == id )
+ continue; /* empty slot */
+
+ pci_read_config_word(b,d,f,PCI_CLASS_DEVICE,&id);
+ if ( PCI_CLASS_NETWORK_ETHERNET != id )
+ continue; /* only look at ethernet devices */
+
+ sc->b = b;
+ sc->d = d;
+ sc->f = f;
+
+ for ( i=0, base=0, isio=0; try[i]; i++ ) {
+ pci_read_config_dword(b,d,f,try[i],&base);
+ if ( base ) {
+ if ( (isio = (PCI_BASE_ADDRESS_SPACE_IO == (base & PCI_BASE_ADDRESS_SPACE )) ) ) {
+#ifdef NET_CHIP_PORT_IO
+ base &= PCI_BASE_ADDRESS_IO_MASK;
+ sc->NET_SOFTC_BHANDLE_FIELD = PCI_IO_2LOCAL(base,b);
+#ifdef DEBUG
+ printf("Found PCI I/O Base 0x%08x\n", (unsigned)base);
+#endif
+#else
+ base = 0;
+ continue;
+#endif
+ } else {
+#ifdef NET_CHIP_MEM_IO
+ base &= PCI_BASE_ADDRESS_MEM_MASK;
+ sc->NET_SOFTC_BHANDLE_FIELD = PCI2LOCAL(base,b);
+#ifdef DEBUG
+ printf("Found PCI MEM Base 0x%08x\n", (unsigned)base);
+#endif
+#else
+ base = 0;
+ continue;
+#endif
+ }
+ break;
+ }
+ }
+ if ( !base ) {
+#ifdef DEBUG
+ fprintf(stderr, NETDRIVER": (warning) Neither PCI base address 0 nor 1 are configured; skipping bus %i, slot %i, fn %i...\n",b,d,f);
+#endif
+ continue;
+ }
+
+ if ( 0 == METHODSPTR->n_probe(&THEDEVS[unit]) && (inst < 0 || !--inst) ) {
+ pci_read_config_word(b,d,f,PCI_COMMAND,&cmd);
+ pci_write_config_word(b,d,f,PCI_COMMAND,
+ cmd | (isio ? PCI_COMMAND_IO : PCI_COMMAND_MEMORY) | PCI_COMMAND_MASTER );
+ pci_read_config_byte(b,d,f,PCI_INTERRUPT_LINE,&sc->irq_no);
+ printf(NETDRIVER": card found @PCI[%s] 0x%08x (local 0x%08x), IRQ %i\n",
+ (isio ? "io" : "mem"), (unsigned)base, sc->NET_SOFTC_BHANDLE_FIELD, sc->irq_no);
+
+ sc = 0; /* need to allocate a new slot */
+ unit++;
+
+ if ( 0 == inst ) {
+ /* found desired instance */
+ goto terminated;
+ }
+ }
+ }
+ }
+ }
+
+terminated:
+ return unit;
+}
+#else
+
+/* simple skeleton
+int
+NET_EMBEMB(rtems_,NETDRIVER_PREFIX,_setup)(
+ int unit,
+ void *base_addr,
+ int irq_no)
+{
+struct NET_SOFTC *sc;
+ if ( !(sc=net_drv_check_unit(unit)) ) {
+ fprintf(stderr,"Bad unit number -- (not enought driver slots?)\n");
+ return 0;
+ }
+ sc->NET_SOFTC_BHANDLE_FIELD = base_addr;
+ if ( 0 == METHODSPTR->n_probe(&THEDEVS[unit-1]) ) {
+ sc->irq_no = irq_no;
+ printf(NETDRIVER": Unit %i set up\n", unit);
+ return unit;
+ }
+ return 0;
+}
+*/
+
+#endif
diff --git a/c/src/lib/libbsp/powerpc/beatnik/network/porting/pcireg.h b/c/src/lib/libbsp/powerpc/beatnik/network/porting/pcireg.h
new file mode 100644
index 0000000000..8487f5b8f6
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/beatnik/network/porting/pcireg.h
@@ -0,0 +1,405 @@
+/*-
+ * Copyright (c) 1997, Stefan Esser <se@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD: /repoman/r/ncvs/src/sys/dev/pci/pcireg.h,v 1.39.4.3 2005/04/02 05:03:34 jmg Exp $
+ *
+ */
+
+/*
+ * PCIM_xxx: mask to locate subfield in register
+ * PCIR_xxx: config register offset
+ * PCIC_xxx: device class
+ * PCIS_xxx: device subclass
+ * PCIP_xxx: device programming interface
+ * PCIV_xxx: PCI vendor ID (only required to fixup ancient devices)
+ * PCID_xxx: device ID
+ * PCIY_xxx: capability identification number
+ */
+
+/* some PCI bus constants */
+
+#define PCI_BUSMAX 255
+#define PCI_SLOTMAX 31
+#define PCI_FUNCMAX 7
+#define PCI_REGMAX 255
+#define PCI_MAXHDRTYPE 2
+
+/* PCI config header registers for all devices */
+
+#define PCIR_DEVVENDOR 0x00
+#define PCIR_VENDOR 0x00
+#define PCIR_DEVICE 0x02
+#define PCIR_COMMAND 0x04
+#define PCIM_CMD_PORTEN 0x0001
+#define PCIM_CMD_MEMEN 0x0002
+#define PCIM_CMD_BUSMASTEREN 0x0004
+#define PCIM_CMD_SPECIALEN 0x0008
+#define PCIM_CMD_MWRICEN 0x0010
+#define PCIM_CMD_PERRESPEN 0x0040
+#define PCIM_CMD_SERRESPEN 0x0100
+#define PCIM_CMD_BACKTOBACK 0x0200
+#define PCIR_STATUS 0x06
+#define PCIM_STATUS_CAPPRESENT 0x0010
+#define PCIM_STATUS_66CAPABLE 0x0020
+#define PCIM_STATUS_BACKTOBACK 0x0080
+#define PCIM_STATUS_PERRREPORT 0x0100
+#define PCIM_STATUS_SEL_FAST 0x0000
+#define PCIM_STATUS_SEL_MEDIMUM 0x0200
+#define PCIM_STATUS_SEL_SLOW 0x0400
+#define PCIM_STATUS_SEL_MASK 0x0600
+#define PCIM_STATUS_STABORT 0x0800
+#define PCIM_STATUS_RTABORT 0x1000
+#define PCIM_STATUS_RMABORT 0x2000
+#define PCIM_STATUS_SERR 0x4000
+#define PCIM_STATUS_PERR 0x8000
+#define PCIR_REVID 0x08
+#define PCIR_PROGIF 0x09
+#define PCIR_SUBCLASS 0x0a
+#define PCIR_CLASS 0x0b
+#define PCIR_CACHELNSZ 0x0c
+#define PCIR_LATTIMER 0x0d
+#define PCIR_HDRTYPE 0x0e
+#ifndef BURN_BRIDGES
+#define PCIR_HEADERTYPE PCIR_HDRTYPE
+#endif
+#define PCIM_HDRTYPE 0x7f
+#define PCIM_HDRTYPE_NORMAL 0x00
+#define PCIM_HDRTYPE_BRIDGE 0x01
+#define PCIM_HDRTYPE_CARDBUS 0x02
+#define PCIM_MFDEV 0x80
+#define PCIR_BIST 0x0f
+
+/* Capability Identification Numbers */
+
+#define PCIY_PMG 0x01 /* PCI Power Management */
+#define PCIY_AGP 0x02 /* AGP */
+#define PCIY_VPD 0x03 /* Vital Product Data */
+#define PCIY_SLOTID 0x04 /* Slot Identification */
+#define PCIY_MSI 0x05 /* Message Signaled Interrupts */
+#define PCIY_CHSWP 0x06 /* CompactPCI Hot Swap */
+#define PCIY_PCIX 0x07 /* PCI-X */
+#define PCIY_HT 0x08 /* HyperTransport */
+#define PCIY_VENDOR 0x09 /* Vendor Unique */
+#define PCIY_DEBUG 0x0a /* Debug port */
+#define PCIY_CRES 0x0b /* CompactPCI central resource control */
+#define PCIY_HOTPLUG 0x0c /* PCI Hot-Plug */
+#define PCIY_AGP8X 0x0e /* AGP 8x */
+#define PCIY_SECDEV 0x0f /* Secure Device */
+#define PCIY_EXPRESS 0x10 /* PCI Express */
+#define PCIY_MSIX 0x11 /* MSI-X */
+
+/* config registers for header type 0 devices */
+
+#define PCIR_BARS 0x10
+#define PCIR_BAR(x) (PCIR_BARS + (x) * 4)
+#ifndef BURN_BRIDGES
+#define PCIR_MAPS PCIR_BARS
+#endif
+#define PCIR_CARDBUSCIS 0x28
+#define PCIR_SUBVEND_0 0x2c
+#define PCIR_SUBDEV_0 0x2e
+#define PCIR_BIOS 0x30
+#define PCIM_BIOS_ENABLE 0x01
+#define PCIR_CAP_PTR 0x34
+#define PCIR_INTLINE 0x3c
+#define PCIR_INTPIN 0x3d
+#define PCIR_MINGNT 0x3e
+#define PCIR_MAXLAT 0x3f
+
+/* config registers for header type 1 (PCI-to-PCI bridge) devices */
+
+#define PCIR_SECSTAT_1 0x1e
+
+#define PCIR_PRIBUS_1 0x18
+#define PCIR_SECBUS_1 0x19
+#define PCIR_SUBBUS_1 0x1a
+#define PCIR_SECLAT_1 0x1b
+
+#define PCIR_IOBASEL_1 0x1c
+#define PCIR_IOLIMITL_1 0x1d
+#define PCIR_IOBASEH_1 0x30
+#define PCIR_IOLIMITH_1 0x32
+#define PCIM_BRIO_16 0x0
+#define PCIM_BRIO_32 0x1
+#define PCIM_BRIO_MASK 0xf
+
+#define PCIR_MEMBASE_1 0x20
+#define PCIR_MEMLIMIT_1 0x22
+
+#define PCIR_PMBASEL_1 0x24
+#define PCIR_PMLIMITL_1 0x26
+#define PCIR_PMBASEH_1 0x28
+#define PCIR_PMLIMITH_1 0x2c
+
+#define PCIR_BRIDGECTL_1 0x3e
+
+#define PCIR_SUBVEND_1 0x34
+#define PCIR_SUBDEV_1 0x36
+
+/* config registers for header type 2 (CardBus) devices */
+
+#define PCIR_SECSTAT_2 0x16
+
+#define PCIR_PRIBUS_2 0x18
+#define PCIR_SECBUS_2 0x19
+#define PCIR_SUBBUS_2 0x1a
+#define PCIR_SECLAT_2 0x1b
+
+#define PCIR_MEMBASE0_2 0x1c
+#define PCIR_MEMLIMIT0_2 0x20
+#define PCIR_MEMBASE1_2 0x24
+#define PCIR_MEMLIMIT1_2 0x28
+#define PCIR_IOBASE0_2 0x2c
+#define PCIR_IOLIMIT0_2 0x30
+#define PCIR_IOBASE1_2 0x34
+#define PCIR_IOLIMIT1_2 0x38
+
+#define PCIR_BRIDGECTL_2 0x3e
+
+#define PCIR_SUBVEND_2 0x40
+#define PCIR_SUBDEV_2 0x42
+
+#define PCIR_PCCARDIF_2 0x44
+
+/* PCI device class, subclass and programming interface definitions */
+
+#define PCIC_OLD 0x00
+#define PCIS_OLD_NONVGA 0x00
+#define PCIS_OLD_VGA 0x01
+
+#define PCIC_STORAGE 0x01
+#define PCIS_STORAGE_SCSI 0x00
+#define PCIS_STORAGE_IDE 0x01
+#define PCIP_STORAGE_IDE_MODEPRIM 0x01
+#define PCIP_STORAGE_IDE_PROGINDPRIM 0x02
+#define PCIP_STORAGE_IDE_MODESEC 0x04
+#define PCIP_STORAGE_IDE_PROGINDSEC 0x08
+#define PCIP_STORAGE_IDE_MASTERDEV 0x80
+#define PCIS_STORAGE_FLOPPY 0x02
+#define PCIS_STORAGE_IPI 0x03
+#define PCIS_STORAGE_RAID 0x04
+#define PCIS_STORAGE_OTHER 0x80
+
+#define PCIC_NETWORK 0x02
+#define PCIS_NETWORK_ETHERNET 0x00
+#define PCIS_NETWORK_TOKENRING 0x01
+#define PCIS_NETWORK_FDDI 0x02
+#define PCIS_NETWORK_ATM 0x03
+#define PCIS_NETWORK_ISDN 0x04
+#define PCIS_NETWORK_OTHER 0x80
+
+#define PCIC_DISPLAY 0x03
+#define PCIS_DISPLAY_VGA 0x00
+#define PCIS_DISPLAY_XGA 0x01
+#define PCIS_DISPLAY_3D 0x02
+#define PCIS_DISPLAY_OTHER 0x80
+
+#define PCIC_MULTIMEDIA 0x04
+#define PCIS_MULTIMEDIA_VIDEO 0x00
+#define PCIS_MULTIMEDIA_AUDIO 0x01
+#define PCIS_MULTIMEDIA_TELE 0x02
+#define PCIS_MULTIMEDIA_OTHER 0x80
+
+#define PCIC_MEMORY 0x05
+#define PCIS_MEMORY_RAM 0x00
+#define PCIS_MEMORY_FLASH 0x01
+#define PCIS_MEMORY_OTHER 0x80
+
+#define PCIC_BRIDGE 0x06
+#define PCIS_BRIDGE_HOST 0x00
+#define PCIS_BRIDGE_ISA 0x01
+#define PCIS_BRIDGE_EISA 0x02
+#define PCIS_BRIDGE_MCA 0x03
+#define PCIS_BRIDGE_PCI 0x04
+#define PCIS_BRIDGE_PCMCIA 0x05
+#define PCIS_BRIDGE_NUBUS 0x06
+#define PCIS_BRIDGE_CARDBUS 0x07
+#define PCIS_BRIDGE_RACEWAY 0x08
+#define PCIS_BRIDGE_OTHER 0x80
+
+#define PCIC_SIMPLECOMM 0x07
+#define PCIS_SIMPLECOMM_UART 0x00
+#define PCIP_SIMPLECOMM_UART_16550A 0x02
+#define PCIS_SIMPLECOMM_PAR 0x01
+#define PCIS_SIMPLECOMM_MULSER 0x02
+#define PCIS_SIMPLECOMM_MODEM 0x03
+#define PCIS_SIMPLECOMM_OTHER 0x80
+
+#define PCIC_BASEPERIPH 0x08
+#define PCIS_BASEPERIPH_PIC 0x00
+#define PCIS_BASEPERIPH_DMA 0x01
+#define PCIS_BASEPERIPH_TIMER 0x02
+#define PCIS_BASEPERIPH_RTC 0x03
+#define PCIS_BASEPERIPH_PCIHOT 0x04
+#define PCIS_BASEPERIPH_OTHER 0x80
+
+#define PCIC_INPUTDEV 0x09
+#define PCIS_INPUTDEV_KEYBOARD 0x00
+#define PCIS_INPUTDEV_DIGITIZER 0x01
+#define PCIS_INPUTDEV_MOUSE 0x02
+#define PCIS_INPUTDEV_SCANNER 0x03
+#define PCIS_INPUTDEV_GAMEPORT 0x04
+#define PCIS_INPUTDEV_OTHER 0x80
+
+#define PCIC_DOCKING 0x0a
+#define PCIS_DOCKING_GENERIC 0x00
+#define PCIS_DOCKING_OTHER 0x80
+
+#define PCIC_PROCESSOR 0x0b
+#define PCIS_PROCESSOR_386 0x00
+#define PCIS_PROCESSOR_486 0x01
+#define PCIS_PROCESSOR_PENTIUM 0x02
+#define PCIS_PROCESSOR_ALPHA 0x10
+#define PCIS_PROCESSOR_POWERPC 0x20
+#define PCIS_PROCESSOR_MIPS 0x30
+#define PCIS_PROCESSOR_COPROC 0x40
+
+#define PCIC_SERIALBUS 0x0c
+#define PCIS_SERIALBUS_FW 0x00
+#define PCIS_SERIALBUS_ACCESS 0x01
+#define PCIS_SERIALBUS_SSA 0x02
+#define PCIS_SERIALBUS_USB 0x03
+#define PCIP_SERIALBUS_USB_UHCI 0x00
+#define PCIP_SERIALBUS_USB_OHCI 0x10
+#define PCIP_SERIALBUS_USB_EHCI 0x20
+#define PCIS_SERIALBUS_FC 0x04
+#define PCIS_SERIALBUS_SMBUS 0x05
+
+#define PCIC_WIRELESS 0x0d
+#define PCIS_WIRELESS_IRDA 0x00
+#define PCIS_WIRELESS_IR 0x01
+#define PCIS_WIRELESS_RF 0x10
+#define PCIS_WIRELESS_OTHER 0x80
+
+#define PCIC_INTELLIIO 0x0e
+#define PCIS_INTELLIIO_I2O 0x00
+
+#define PCIC_SATCOM 0x0f
+#define PCIS_SATCOM_TV 0x01
+#define PCIS_SATCOM_AUDIO 0x02
+#define PCIS_SATCOM_VOICE 0x03
+#define PCIS_SATCOM_DATA 0x04
+
+#define PCIC_CRYPTO 0x10
+#define PCIS_CRYPTO_NETCOMP 0x00
+#define PCIS_CRYPTO_ENTERTAIN 0x10
+#define PCIS_CRYPTO_OTHER 0x80
+
+#define PCIC_DASP 0x11
+#define PCIS_DASP_DPIO 0x00
+#define PCIS_DASP_OTHER 0x80
+
+#define PCIC_OTHER 0xff
+
+/* PCI power manangement */
+
+#define PCIR_POWER_CAP 0x2
+#define PCIM_PCAP_SPEC 0x0007
+#define PCIM_PCAP_PMEREQCLK 0x0008
+#define PCIM_PCAP_PMEREQPWR 0x0010
+#define PCIM_PCAP_DEVSPECINIT 0x0020
+#define PCIM_PCAP_DYNCLOCK 0x0040
+#define PCIM_PCAP_SECCLOCK 0x00c0
+#define PCIM_PCAP_CLOCKMASK 0x00c0
+#define PCIM_PCAP_REQFULLCLOCK 0x0100
+#define PCIM_PCAP_D1SUPP 0x0200
+#define PCIM_PCAP_D2SUPP 0x0400
+#define PCIM_PCAP_D0PME 0x1000
+#define PCIM_PCAP_D1PME 0x2000
+#define PCIM_PCAP_D2PME 0x4000
+
+#define PCIR_POWER_STATUS 0x4
+#define PCIM_PSTAT_D0 0x0000
+#define PCIM_PSTAT_D1 0x0001
+#define PCIM_PSTAT_D2 0x0002
+#define PCIM_PSTAT_D3 0x0003
+#define PCIM_PSTAT_DMASK 0x0003
+#define PCIM_PSTAT_REPENABLE 0x0010
+#define PCIM_PSTAT_PMEENABLE 0x0100
+#define PCIM_PSTAT_D0POWER 0x0000
+#define PCIM_PSTAT_D1POWER 0x0200
+#define PCIM_PSTAT_D2POWER 0x0400
+#define PCIM_PSTAT_D3POWER 0x0600
+#define PCIM_PSTAT_D0HEAT 0x0800
+#define PCIM_PSTAT_D1HEAT 0x1000
+#define PCIM_PSTAT_D2HEAT 0x1200
+#define PCIM_PSTAT_D3HEAT 0x1400
+#define PCIM_PSTAT_DATAUNKN 0x0000
+#define PCIM_PSTAT_DATADIV10 0x2000
+#define PCIM_PSTAT_DATADIV100 0x4000
+#define PCIM_PSTAT_DATADIV1000 0x6000
+#define PCIM_PSTAT_DATADIVMASK 0x6000
+#define PCIM_PSTAT_PME 0x8000
+
+#define PCIR_POWER_PMCSR 0x6
+#define PCIM_PMCSR_DCLOCK 0x10
+#define PCIM_PMCSR_B2SUPP 0x20
+#define PCIM_BMCSR_B3SUPP 0x40
+#define PCIM_BMCSR_BPCE 0x80
+
+#define PCIR_POWER_DATA 0x7
+
+/* PCI Message Signalled Interrupts (MSI) */
+#define PCIR_MSI_CTRL 0x2
+#define PCIM_MSICTRL_VECTOR 0x0100
+#define PCIM_MSICTRL_64BIT 0x0080
+#define PCIM_MSICTRL_MME_MASK 0x0070
+#define PCIM_MSICTRL_MME_1 0x0000
+#define PCIM_MSICTRL_MME_2 0x0010
+#define PCIM_MSICTRL_MME_4 0x0020
+#define PCIM_MSICTRL_MME_8 0x0030
+#define PCIM_MSICTRL_MME_16 0x0040
+#define PCIM_MSICTRL_MME_32 0x0050
+#define PCIM_MSICTRL_MMC_MASK 0x000E
+#define PCIM_MSICTRL_MMC_1 0x0000
+#define PCIM_MSICTRL_MMC_2 0x0002
+#define PCIM_MSICTRL_MMC_4 0x0004
+#define PCIM_MSICTRL_MMC_8 0x0006
+#define PCIM_MSICTRL_MMC_16 0x0008
+#define PCIM_MSICTRL_MMC_32 0x000A
+#define PCIM_MSICTRL_MSI_ENABLE 0x0001
+#define PCIR_MSI_ADDR 0x4
+#define PCIR_MSI_ADDR_HIGH 0x8
+#define PCIR_MSI_DATA 0x8
+#define PCIR_MSI_DATA_64BIT 0xc
+#define PCIR_MSI_MASK 0x10
+#define PCIR_MSI_PENDING 0x14
+
+/* PCI-X definitions */
+#define PCIXR_COMMAND 0x96
+#define PCIXR_DEVADDR 0x98
+#define PCIXM_DEVADDR_FNUM 0x0003 /* Function Number */
+#define PCIXM_DEVADDR_DNUM 0x00F8 /* Device Number */
+#define PCIXM_DEVADDR_BNUM 0xFF00 /* Bus Number */
+#define PCIXR_STATUS 0x9A
+#define PCIXM_STATUS_64BIT 0x0001 /* Active 64bit connection to device. */
+#define PCIXM_STATUS_133CAP 0x0002 /* Device is 133MHz capable */
+#define PCIXM_STATUS_SCDISC 0x0004 /* Split Completion Discarded */
+#define PCIXM_STATUS_UNEXPSC 0x0008 /* Unexpected Split Completion */
+#define PCIXM_STATUS_CMPLEXDEV 0x0010 /* Device Complexity (set == bridge) */
+#define PCIXM_STATUS_MAXMRDBC 0x0060 /* Maximum Burst Read Count */
+#define PCIXM_STATUS_MAXSPLITS 0x0380 /* Maximum Split Transactions */
+#define PCIXM_STATUS_MAXCRDS 0x1C00 /* Maximum Cumulative Read Size */
+#define PCIXM_STATUS_RCVDSCEM 0x2000 /* Received a Split Comp w/Error msg */
diff --git a/c/src/lib/libbsp/powerpc/beatnik/network/porting/rtemscompat.h b/c/src/lib/libbsp/powerpc/beatnik/network/porting/rtemscompat.h
new file mode 100644
index 0000000000..ea1c251261
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/beatnik/network/porting/rtemscompat.h
@@ -0,0 +1,459 @@
+#ifndef RTEMS_COMPAT_BSD_NET_H
+#define RTEMS_COMPAT_BSD_NET_H
+
+/* BSD -> rtems wrappers; stuff that must be defined
+ * prior to including most BSD headers
+ */
+
+/* Copyright: Till Straumann <strauman@slac.stanford.edu>, 2005;
+ * License: see LICENSE file.
+ */
+
+#include <rtems.h>
+#include <sys/errno.h>
+#include <sys/types.h>
+
+#include <stdlib.h>
+
+/* Check for RTEMS version; true if >= ma.mi.re */
+#define ISMINVERSION(ma,mi,re) \
+ ( __RTEMS_MAJOR__ > (ma) \
+ || (__RTEMS_MAJOR__ == (ma) && __RTEMS_MINOR__ > (mi)) \
+ || (__RTEMS_MAJOR__ == (ma) && __RTEMS_MINOR__ == (mi) && __RTEMS_REVISION__ >= (re)) \
+ )
+
+/* 'align' ARG is evaluated more than once */
+#define _DO_ALIGN(addr, align) (((uint32_t)(addr) + (align) - 1) & ~((align)-1))
+
+
+/* malloc/free are redefined :-( */
+static inline void *the_real_malloc(size_t n)
+{
+ return malloc(n);
+}
+
+static inline void the_real_free(void *p)
+{
+ return free(p);
+}
+
+#define __INSIDE_RTEMS_BSD_TCPIP_STACK__
+#include <rtems/rtems_bsdnet.h>
+#include <rtems/rtems_bsdnet_internal.h>
+#ifdef __i386__
+#include <libcpu/cpu.h>
+#elif defined(__PPC__)
+#include <libcpu/io.h>
+#else
+#error "dunno what IO ops to use on this architecture"
+#endif
+#include <rtems/bspIo.h>
+
+#include "rtemscompat_defs.h"
+
+#define NET_EMB(x,y,z) x ## y ## z
+#define NET_EMBEMB(x,y,z) NET_EMB(x,y,z)
+
+#define NET_STR(arg) #arg
+#define NET_STRSTR(arg) NET_STR(arg)
+
+#define NET_SOFTC NET_EMBEMB(,NETDRIVER_PREFIX,_softc)
+
+#define METHODS NET_EMBEMB(rtems_,NETDRIVER_PREFIX,_methods)
+extern struct _net_drv_tbl METHODS;
+
+#ifdef DEBUG_MODULAR
+#define METHODSPTR NET_EMBEMB(rtems_,NETDRIVER_PREFIX,_methods_p)
+extern struct _net_drv_tbl *volatile METHODSPTR;
+#else
+#define METHODSPTR (&METHODS)
+#endif
+
+#if defined(__LITTLE_ENDIAN__) || (__i386__)
+static inline uint16_t htole16(uint16_t v) { return v; }
+static inline uint32_t htole32(uint32_t v) { return v; }
+static inline uint64_t htole64(uint64_t v) { return v; }
+static inline uint16_t le16toh(uint16_t v) { return v; }
+static inline uint32_t le32toh(uint32_t v) { return v; }
+static inline uint64_t le64toh(uint64_t v) { return v; }
+#elif defined(__BIG_ENDIAN__)
+#ifdef __PPC__
+#include <libcpu/byteorder.h>
+
+/* Different RTEMS versions use different types
+ * for 32-bit (unsigned vs. unsigned long which
+ * always cause gcc warnings and possible alias
+ * violations, sigh).
+ */
+
+#if ISMINVERSION(4,8,0)
+typedef uint32_t rtemscompat_32_t;
+#else
+typedef unsigned rtemscompat_32_t;
+#endif
+
+static inline uint16_t
+htole16(uint16_t v)
+{
+uint16_t rval;
+ st_le16(&rval,v);
+ return rval;
+}
+
+static inline uint16_t
+le16toh(uint16_t v)
+{
+ return ld_le16((unsigned short*)&v);
+}
+
+static inline uint32_t
+htole32(uint32_t v)
+{
+rtemscompat_32_t rval;
+ st_le32(&rval,v);
+ return rval;
+}
+
+static inline uint32_t
+le32toh(uint32_t v)
+{
+rtemscompat_32_t vv = v;
+ return ld_le32(&vv);
+}
+
+/* Compiler generated floating point instructions for this
+ * and rtems_bsdnet_newproc()-generated tasks are non-FP
+ * :-(
+ */
+static inline uint64_t
+htole64(uint64_t v)
+{
+union {
+ rtemscompat_32_t tmp[2];
+ uint64_t rval;
+} u;
+
+ st_le32( &u.tmp[0], (unsigned)(v&0xffffffff) );
+ st_le32( &u.tmp[1], (unsigned)((v>>32)&0xffffffff) );
+
+ return u.rval;
+}
+
+#else
+#error "need htoleXX() implementation for this CPU arch"
+#endif
+
+#else
+#error "Unknown CPU endianness"
+#endif
+
+
+
+#ifdef __PPC__
+#define _out_byte(a,v) out_8((volatile unsigned char*)(a),(v))
+#define _inp_byte(a) in_8((volatile unsigned char*)(a))
+#ifdef NET_CHIP_LE
+#define _out_word(a,v) out_le16((volatile unsigned short*)(a),(v))
+#define _out_long(a,v) out_le32((volatile unsigned *)(a),(v))
+#define _inp_word(a) in_le16((volatile unsigned short*)(a))
+#define _inp_long(a) in_le32((volatile unsigned *)(a))
+#elif defined(NET_CHIP_BE)
+#define _out_word(a,v) out_be16((volatile unsigned short*)(a),(v))
+#define _out_long(a,v) out_be32((volatile unsigned *)(a),(v))
+#define _inp_word(a) in_be16((volatile unsigned short*)(a))
+#define _inp_long(a) in_be32((volatile unsigned *)(a))
+#else
+#error rtemscompat_defs.h must define either NET_CHIP_LE or NET_CHIP_BE
+#endif
+static inline void wrle32(unsigned *a, unsigned v)
+{
+ asm volatile("stwbrx %1,0,%2":"=m"(*a):"r"(v),"r"(a));
+}
+static inline unsigned rdle32(unsigned *a)
+{
+ asm volatile("lwbrx %0,0,%0":"=r"(a):"0"(a),"m"(*a));
+ return (unsigned)a;
+}
+static inline void orle32(unsigned *a,unsigned v) { wrle32(a, rdle32(a) | v); }
+static inline void anle32(unsigned *a,unsigned v) { wrle32(a, rdle32(a) & v); }
+
+static inline void wrle16(unsigned short *a, unsigned short v)
+{
+ asm volatile("sthbrx %1,0,%2":"=m"(*a):"r"(v),"r"(a));
+}
+static inline unsigned short rdle16(unsigned short *a)
+{
+ asm volatile("lhbrx %0,0,%0":"=r"(a):"0"(a),"m"(*a));
+ return (unsigned short)(unsigned)a;
+}
+static inline void orle16(unsigned short *a,unsigned short v) { wrle16(a, rdle16(a) | v); }
+static inline void anle16(unsigned short *a,unsigned short v) { wrle16(a, rdle16(a) & v); }
+#endif
+
+#ifdef __i386__
+#ifdef NET_CHIP_BE
+#error dunno how to output BE data
+#endif
+
+static inline void wrle32(volatile unsigned *p, unsigned v) { *p = v; }
+static inline void orle32(volatile unsigned *p, unsigned v) { *p |= v; }
+static inline void anle32(volatile unsigned *p, unsigned v) { *p &= v; }
+static inline unsigned rdle32(volatile unsigned *p) { return *p; }
+
+static inline void wrle16(volatile unsigned short *p, unsigned short v) { *p = v; }
+static inline void orle16(volatile unsigned short *p, unsigned short v) { *p |= v; }
+static inline void anle16(volatile unsigned short *p, unsigned short v) { *p &= v; }
+static inline unsigned short rdle16(volatile unsigned short *p) { return *p; }
+
+#ifdef NET_CHIP_MEM_IO
+
+#ifdef __i386__
+static inline void _out_byte(unsigned a, unsigned char v) { *(volatile unsigned char*)a = v; }
+static inline unsigned char _inp_byte(unsigned a) { return *(volatile unsigned char*)a; }
+#ifdef NET_CHIP_LE
+static inline void _out_word(unsigned a, unsigned short v) { *(volatile unsigned short*)a = v; }
+static inline unsigned short _inp_word(unsigned a) { return *(volatile unsigned short*)a; }
+static inline void _out_long(unsigned a, unsigned v) { *(volatile unsigned *)a = v; }
+static inline unsigned _inp_long(unsigned a) { return *(volatile unsigned *)a; }
+#elif defined(NET_CHIP_BE)
+#error "BE memory IO not implemented for i386 yet"
+#else
+#error rtemscompat_defs.h must define either NET_CHIP_LE or NET_CHIP_BE
+#endif
+#else
+
+#error "Memory IO not implemented for this CPU architecture yet"
+
+#endif
+#elif defined(NET_CHIP_PORT_IO)
+#define _out_byte(addr,val) outport_byte((addr),(val))
+#define _out_word(addr,val) outport_word((addr),(val))
+#define _out_long(addr,val) outport_long((addr),(val))
+
+static inline u_int8_t _inp_byte(volatile unsigned char *a)
+{
+register u_int8_t rval;
+ inport_byte((unsigned short)(unsigned)a,rval);
+ return rval;
+}
+static inline u_int16_t _inp_word(volatile unsigned short *a)
+{
+register u_int16_t rval;
+ inport_word((unsigned short)(unsigned)a,rval);
+ return rval;
+}
+static inline u_int32_t _inp_long(volatile unsigned *a)
+{
+register u_int32_t rval;
+ inport_long((unsigned short)(unsigned)a,rval);
+ return rval;
+}
+#else
+#error either NET_CHIP_MEM_IO or NET_CHIP_PORT_IO must be defined
+#endif
+#endif
+
+#ifndef __FBSDID
+#define __FBSDID(arg)
+#endif
+
+#define _KERNEL
+
+#define device_printf(device,format,args...) printk(format,## args)
+
+static inline u_int8_t bus_space_do_read_1(u_long handle, unsigned reg)
+{
+ return _inp_byte((volatile unsigned char*)((handle)+(reg)));
+}
+
+static inline u_int16_t bus_space_do_read_2(u_long handle, unsigned reg)
+{
+ return _inp_word((volatile unsigned short*)((handle)+(reg)));
+}
+
+static inline u_int32_t bus_space_do_read_4(u_long handle, unsigned reg)
+{
+ return _inp_long((volatile unsigned *)((handle)+(reg)));
+}
+
+#define bus_space_read_1(tag,handle,reg) bus_space_do_read_1((handle),(reg))
+#define bus_space_read_2(tag,handle,reg) bus_space_do_read_2((handle),(reg))
+#define bus_space_read_4(tag,handle,reg) bus_space_do_read_4((handle),(reg))
+
+static inline void bus_space_do_write_multi_1(u_long handle, unsigned reg, unsigned char *addr, int cnt)
+{
+ int i; for (i=0; i<cnt; i++) _out_byte( (handle) + (reg), (addr)[i]);
+}
+
+static inline void bus_space_do_write_multi_2(u_long handle, unsigned reg, unsigned short *addr, int cnt)
+{
+ int i; for (i=0; i<cnt; i++) _out_word( (handle) + (reg), (addr)[i]);
+}
+
+static inline void bus_space_do_write_multi_4(u_long handle, unsigned reg, unsigned long *addr, int cnt)
+{
+ int i; for (i=0; i<cnt; i++) _out_long( (handle) + (reg), (addr)[i]);
+}
+
+
+#define bus_space_write_multi_1(tag, handle, reg, addr, cnt) \
+ bus_space_do_write_multi_1(handle, reg, addr, cnt)
+#define bus_space_write_multi_2(tag, handle, reg, addr, cnt) \
+ bus_space_do_write_multi_2(handle, reg, addr, cnt)
+#define bus_space_write_multi_4(tag, handle, reg, addr, cnt) \
+ bus_space_do_write_multi_4(handle, reg, addr, cnt)
+
+static inline void bus_space_do_read_multi_1(u_long handle, unsigned reg, unsigned char *addr, int cnt)
+{
+ int i; for (i=0; i<cnt; i++)
+ (addr)[i] = _inp_byte((volatile unsigned char*)((handle)+(reg)));
+}
+
+static inline void bus_space_do_read_multi_2(u_long handle, unsigned reg, unsigned short *addr, int cnt)
+{
+ int i; for (i=0; i<cnt; i++)
+ (addr)[i] = _inp_word((volatile unsigned short*)((handle)+(reg)));
+}
+
+static inline void bus_space_do_read_multi_4(u_long handle, unsigned reg, unsigned long *addr, int cnt)
+{
+ int i; for (i=0; i<cnt; i++)
+ (addr)[i] = _inp_long((volatile unsigned *)((handle)+(reg)));
+}
+
+#define bus_space_read_multi_1(tag, handle, reg, addr, cnt) \
+ bus_space_do_read_multi_1(handle, reg, addr, cnt)
+#define bus_space_read_multi_2(tag, handle, reg, addr, cnt) \
+ bus_space_do_read_multi_2(handle, reg, addr, cnt)
+#define bus_space_read_multi_4(tag, handle, reg, addr, cnt) \
+ bus_space_do_read_multi_4(handle, reg, addr, cnt)
+
+
+
+#define bus_space_write_1(tag, handle, reg, val) \
+ do { _out_byte( (handle) + (reg), (val)); } while (0)
+
+#define bus_space_write_2(tag, handle, reg, val) \
+ do { _out_word( (handle) + (reg), (val)); } while (0)
+
+#define bus_space_write_4(tag, handle, reg, val) \
+ do { _out_long( (handle) + (reg), (val)); } while (0)
+
+#define BPF_MTAP(a,b) do { } while (0)
+
+extern unsigned net_driver_ticks_per_sec;
+
+#ifdef __PPC__
+/* PPC has a timebase - based delay */
+#define DELAY(n) do { \
+ if ( (n) > 10000 ) \
+ rtems_task_wake_after((((n)*net_driver_ticks_per_sec)/1000000) + 1); \
+ else \
+ rtems_bsp_delay(n); \
+ } while (0)
+#else
+#warning "Have no good usec delay implementation"
+#define DELAY(n) do { \
+ rtems_task_wake_after((((n)*net_driver_ticks_per_sec)/1000000) + 1); \
+ } while (0)
+#endif
+
+
+#define IRQ_LOCKED(code) \
+ do { unsigned long _xtre_irq_flags; \
+ rtems_interrupt_disable(_xtre_irq_flags); \
+ do { code } while(0); \
+ rtems_interrupt_enable(_xtre_irq_flags); \
+ } while (0)
+
+typedef struct _netdev_t *device_t;
+typedef void (driver_intr_t)(void *);
+
+#define if_xname if_name
+
+/* need to replace those with LOCAL2PCI() and make sure the bus handle is initialized
+ * (on most BSPs we get away with PCI_DRAM_OFFSET [no bus handle needed at all]
+ */
+#ifndef PCI_DRAM_OFFSET
+#define PCI_DRAM_OFFSET 0
+#endif
+
+#ifndef PCI_MEM_BASE
+#define PCI_MEM_BASE 0
+#endif
+
+#define kvtop(a) ((unsigned long)(a) + PCI_DRAM_OFFSET)
+#define vtophys(a) ((unsigned long)(a) + PCI_DRAM_OFFSET)
+
+#define PCI2LOCAL(a,bus) ((unsigned long)(a) + PCI_MEM_BASE)
+
+#ifdef PCI0_IO_BASE /* special mvme5500 hack :-( */
+#define PCI_IO_2LOCAL(a,bus) ((unsigned long)(a) + PCI0_IO_BASE)
+#elif defined(PCI_IO_BASE)
+#define PCI_IO_2LOCAL(a,bus) ((unsigned long)(a) + PCI_IO_BASE)
+#elif defined(_IO_BASE)
+#define PCI_IO_2LOCAL(a,bus) ((unsigned long)(a) + _IO_BASE)
+#else
+#warning "Unable to determine base address of PCI IO space; using ZERO"
+#define PCI_IO_2LOCAL(a,bus) ((unsigned long)(a))
+#endif
+
+#define if_printf(if,fmt,args...) printf("%s:"fmt,(if)->if_name,args)
+
+#ifndef BUS_PROBE_DEFAULT
+#define BUS_PROBE_DEFAULT 0
+#endif
+
+static inline void *
+contigmalloc(
+ unsigned long size,
+ int type,
+ int flags,
+ unsigned long lo,
+ unsigned long hi,
+ unsigned long align,
+ unsigned long bound)
+{
+void *ptr = rtems_bsdnet_malloc(size + sizeof(ptr) + align-1, type, flags);
+char *rval = 0;
+ if ( ptr ) {
+ unsigned tmp = (unsigned)ptr + align - 1;
+ tmp -= tmp % align;
+ rval = (char*)tmp;
+ /* save backlink */
+ *(void**)(rval+size) = ptr;
+ }
+ return rval;
+}
+
+static inline void
+contigfree(void *ptr, size_t size, int type)
+{
+ rtems_bsdnet_free( *(void**)((unsigned)ptr + size), type);
+}
+
+/* callout stuff */
+#define callout_init(args...) do {} while (0);
+#define callout_reset(args...) do {} while (0);
+#define callout_stop(args...) do {} while (0);
+
+#define IFQ_DRV_IS_EMPTY(q) (0 == (q)->ifq_head)
+#define IFQ_DRV_DEQUEUE(q,m) IF_DEQUEUE((q),(m))
+#define IFQ_DRV_PREPEND(q,m) IF_PREPEND((q),(m))
+
+#define DO_ETHER_INPUT_SKIPPING_ETHER_HEADER(ifp,m) \
+ { struct ether_header *eh; \
+ eh = mtod(m, struct ether_header*); \
+ m->m_data += sizeof(struct ether_header); \
+ m->m_len -= sizeof(struct ether_header); \
+ m->m_pkthdr.len -= sizeof(struct ether_header); \
+ m->m_pkthdr.rcvif = ifp; \
+ ether_input(ifp, eh, m); \
+ } while (0)
+
+
+#ifndef __KERNEL_RCSID
+#define __KERNEL_RCSID(arg...)
+#endif
+
+#endif
diff --git a/c/src/lib/libbsp/powerpc/beatnik/network/porting/rtemscompat1.h b/c/src/lib/libbsp/powerpc/beatnik/network/porting/rtemscompat1.h
new file mode 100644
index 0000000000..0795fd30d0
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/beatnik/network/porting/rtemscompat1.h
@@ -0,0 +1,219 @@
+#ifndef RTEMS_COMPAT1_BSD_NET_H
+#define RTEMS_COMPAT1_BSD_NET_H
+
+/* BSD -> RTEMS conversion wrappers; stuff that must be defined
+ * after most BSD headers are included.
+ */
+
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+
+/* Copyright: Till Straumann <strauman@slac.stanford.edu>, 2005;
+ * License: see LICENSE file.
+ */
+
+typedef struct _netdev_t {
+ struct NET_SOFTC d_softc; /* MUST BE FIRST FIELD */
+ char *d_name;
+ char *d_desc;
+ int d_unit;
+ int flags;
+ /* pointer to ifconfig only valid during excution of
+ * the n_attach/n_detach methods (see below)
+ */
+ struct rtems_bsdnet_ifconfig *d_ifconfig;
+} netdev_t;
+
+#define THEDEVS NET_EMBEMB(the_,NETDRIVER_PREFIX,_devs)
+#define NETDEV_DECL netdev_t THEDEVS[NETDRIVER_SLOTS]
+
+extern NETDEV_DECL;
+
+typedef struct _net_drv_tbl {
+ int (*n_probe)(device_t);
+ int (*n_attach)(device_t);
+ int (*n_detach)(device_t);
+ void (*n_intr)(void *);
+} net_drv_tbl_t;
+
+static inline netdev_t *
+net_dev_get(struct rtems_bsdnet_ifconfig *config)
+{
+ int unitNo;
+ char *unitName;
+
+ unitNo = rtems_bsdnet_parse_driver_name(config, &unitName);
+ if ( unitNo < 0 )
+ return 0;
+
+ if ( unitNo <=0 || unitNo > NETDRIVER_SLOTS ) {
+ device_printf(dev, "Bad "NETDRIVER" unit number.\n");
+ return 0;
+ }
+
+ if ( THEDEVS[unitNo-1].d_unit && THEDEVS[unitNo-1].d_unit != unitNo ) {
+ device_printf(dev, "Unit # mismatch !!??\n");
+ return 0;
+ }
+
+ THEDEVS[unitNo-1].d_unit = unitNo;
+ THEDEVS[unitNo-1].d_name = unitName;
+ THEDEVS[unitNo-1].d_ifconfig = config;
+
+ return &THEDEVS[unitNo - 1];
+}
+
+/* kludge; that's why softc needs to be first */
+static inline netdev_t *
+softc_get_device(struct NET_SOFTC *sc)
+{
+ return (netdev_t *)sc;
+}
+
+static inline struct NET_SOFTC *
+device_get_softc(netdev_t *dev)
+{ return &dev->d_softc; }
+
+static inline int
+device_get_unit(netdev_t *dev)
+{ return dev->d_unit; }
+
+static inline char *
+device_get_name(netdev_t *dev)
+{ return dev->d_name; }
+
+static inline void
+if_initname(struct ifnet *ifp, char *name, int unit)
+{
+ ifp->if_name = name;
+ ifp->if_unit = unit;
+}
+
+static inline void
+device_set_desc(netdev_t *dev, char *str)
+{
+ dev->d_desc = str;
+}
+
+static inline void
+device_set_desc_copy(netdev_t *dev, char *str)
+{
+ dev->d_desc = strdup(str);
+}
+
+
+static inline int
+device_is_attached(netdev_t *dev)
+{
+ return dev->d_softc.arpcom.ac_if.if_addrlist && dev->d_softc.arpcom.ac_if.if_init;
+}
+
+#ifdef NETDRIVER_PCI
+#include NETDRIVER_PCI
+#include <pcireg.h>
+
+static inline unsigned
+pci_read_config(device_t dev, unsigned addr, unsigned width)
+{
+rtemscompat_32_t d;
+unsigned short s;
+unsigned char b;
+struct NET_SOFTC *sc = device_get_softc(dev);
+ switch (width) {
+ case 1: pci_read_config_byte(sc->b, sc->d, sc->f, addr, &b);
+ return b;
+ case 2: pci_read_config_word(sc->b, sc->d, sc->f, addr, &s);
+ return s;
+ case 4: pci_read_config_dword(sc->b, sc->d, sc->f, addr, &d);
+ return d;
+ default:
+ break;
+ }
+ return 0xdeadbeef;
+}
+
+static inline void
+pci_write_config(device_t dev, unsigned addr, unsigned width, unsigned val)
+{
+struct NET_SOFTC *sc = device_get_softc(dev);
+ switch (width) {
+ case 1: pci_write_config_byte(sc->b, sc->d, sc->f, addr, val);
+ return ;
+ case 2: pci_write_config_word(sc->b, sc->d, sc->f, addr, val);
+ return ;
+ case 4: pci_write_config_dword(sc->b, sc->d, sc->f, addr, val);
+ return ;
+ default:
+ break;
+ }
+}
+
+
+static inline unsigned short
+pci_get_vendor(device_t dev)
+{
+ return pci_read_config(dev, PCIR_VENDOR, 2);
+}
+
+static inline unsigned short
+pci_get_device(device_t dev)
+{
+ return pci_read_config(dev, PCIR_DEVICE, 2);
+}
+
+static inline unsigned short
+pci_get_subvendor(device_t dev)
+{
+ return pci_read_config(dev, PCIR_SUBVEND_0, 2);
+}
+
+static inline unsigned short
+pci_get_subdevice(device_t dev)
+{
+ return pci_read_config(dev, PCIR_SUBDEV_0, 2);
+}
+
+
+static inline void
+pci_enable_busmaster(device_t dev)
+{
+ pci_write_config(
+ dev,
+ PCIR_COMMAND,
+ 2,
+ pci_read_config(dev, PCIR_COMMAND, 2)
+ | PCIM_CMD_BUSMASTEREN);
+}
+
+#define mtx_init(a,b,c,d) do {} while(0)
+#define mtx_initialized(ma) (1)
+#define mtx_destroy(ma) do {} while(0)
+#define mtx_lock(a) do {} while(0)
+#define mtx_unlock(a) do {} while(0)
+#define mtx_assert(a,b) do {} while(0)
+
+#define callout_handle_init(x) do {} while (0)
+#define untimeout(a...) do {} while (0)
+
+#if !ISMINVERSION(4,6,99)
+#define pci_bus_count BusCountPCI
+#endif
+
+#endif
+
+/* Ugly hack to allow unloading/reloading the driver core.
+ * Needed because rtems' bsdnet release doesn't implement
+ * if_detach(). Therefore, we bring the interface down but
+ * keep the device record alive...
+ */
+static inline void
+__ether_ifdetach(struct ifnet *ifp)
+{
+ ifp->if_flags = 0;
+ ifp->if_ioctl = 0;
+ ifp->if_start = 0;
+ ifp->if_watchdog = 0;
+ ifp->if_init = 0;
+}
+
+#endif
diff --git a/c/src/lib/libbsp/powerpc/beatnik/network/porting/rtemscompat_defs.h.template b/c/src/lib/libbsp/powerpc/beatnik/network/porting/rtemscompat_defs.h.template
new file mode 100644
index 0000000000..5dc8d1efff
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/beatnik/network/porting/rtemscompat_defs.h.template
@@ -0,0 +1,97 @@
+#ifndef RTEMS_COMPAT_DEFS_H
+#define RTEMS_COMPAT_DEFS_H
+
+/* Symbol definitions for a particular driver */
+
+/* Copyright: Till Straumann <strauman@slac.stanford.edu>, 2005;
+ * License: see LICENSE file.
+ */
+
+/* Number of device instances the driver should support
+ * - may be limited to 1 depending on IRQ API
+ * (braindamaged PC586 and powerpc)
+ */
+#define NETDRIVER_SLOTS 1
+/* String name to print with error messages */
+#define NETDRIVER "PCN"
+/* Name snippet used to make global symbols unique to this driver */
+#define NETDRIVER_PREFIX pcn
+
+/* Define according to endianness of the *ethernet*chip*
+ * (not the CPU - most probably are LE)
+ * This must be either NET_CHIP_LE or NET_CHIP_BE
+ */
+
+#define NET_CHIP_LE
+#undef NET_CHIP_BE
+
+/* Define either NET_CHIP_MEM_IO or NET_CHIP_PORT_IO,
+ * depending whether the CPU sees it in memory address space
+ * or (e.g. x86) uses special I/O instructions.
+ */
+#define NET_CHIP_MEM_IO
+#undef NET_CHIP_PORT_IO
+
+/* The name of the hijacked 'bus handle' field in the softc
+ * structure. We use this field to store the chip's base address.
+ */
+#define NET_SOFTC_BHANDLE_FIELD pcn_bhandle
+
+/* define the names of the 'if_XXXreg.h' and 'if_XXXvar.h' headers
+ * (only if present, i.e., if the BSDNET driver has no respective
+ * header, leave this undefined).
+ *
+ */
+#undef IF_REG_HEADER <if_XXXreg.h>
+#undef IF_VAR_HEADER <if_XXXvar.h>
+
+/* define if a pci device */
+#define NETDRIVER_PCI <bsp/pci.h>
+
+/* Macros to disable and enable interrupts, respectively.
+ * The 'disable' macro is expanded in the ISR, the 'enable'
+ * macro is expanded in the driver task.
+ * The global network semaphore usually provides mutex
+ * protection of the device registers.
+ * Special care must be taken when coding the 'disable' macro,
+ * however to MAKE SURE THERE ARE NO OTHER SIDE EFFECTS such
+ * as:
+ * - macro must not clear any status flags
+ * - macro must save/restore any context information
+ * (e.g., a address register pointer or a bank switch register)
+ *
+ * ARGUMENT: the macro arg is a pointer to the driver's 'softc' structure
+ */
+
+/* Here EXAMPLES for the pcnet chip which addresses registers indirectly
+ * through a 'address-pointer' (RAP) and 'data-port' (RDP) register pair:
+#define NET_DISABLE_IRQS(sc) do { \
+ unsigned rap = CSR_READ_4((sc),PCN_IO32_RAP); \
+ unsigned val; \
+ CSR_WRITE_4((sc),PCN_IO32_RAP,PCN_CSR_CSR); \
+ val = CSR_READ_4((sc),PCN_IO32_RDP); \
+ CSR_WRITE_4((sc), PCN_IO32_RDP, val & ~(CSR0_INT_STATUS_MASK | PCN_CSR_INTEN)); \
+ CSR_WRITE_4((sc), PCN_IO32_RAP, rap); \
+ } while (0)
+
+#define NET_ENABLE_IRQS(sc) do { \
+ unsigned flags,val; \
+ rtems_interrupt_disable(flags); \
+ CSR_WRITE_4((sc),PCN_IO32_RAP,PCN_CSR_CSR); \
+ val = CSR_READ_4((sc),PCN_IO32_RDP); \
+ CSR_WRITE_4((sc), PCN_IO32_RDP, (val & ~CSR0_INT_STATUS_MASK) | PCN_CSR_INTEN); \
+ rtems_interrupt_enable(flags); \
+ } while (0)
+*/
+
+/* Driver may provide a macro/function to copy the hardware address
+ * from the device into 'softc.arpcom'.
+ * If this is undefined, the driver must to the copy itself.
+ * Preferrably, it should check soft.arpcom.ac_enaddr for all
+ * zeros and leave it alone if it is nonzero, i.e., write it
+ * to the hardware.
+#define NET_READ_MAC_ADDR(sc)
+ */
+
+#define KASSERT(a...) do {} while (0)
+#endif
diff --git a/c/src/lib/libbsp/powerpc/beatnik/network/support/bsp_attach.c b/c/src/lib/libbsp/powerpc/beatnik/network/support/bsp_attach.c
new file mode 100644
index 0000000000..8dae0cae3a
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/beatnik/network/support/bsp_attach.c
@@ -0,0 +1,468 @@
+/* $Id$ */
+
+/* BSP specific wrapper for rtems_bsdnet_attach(). This wrapper
+ * dispatches to the correct driver attach routine depending on
+ * the board type, boot parameters, link status etc.
+ *
+ * Also, it performs board-specific setup of driver parameters
+ * (such as ethernet address, base addresses and the like)
+ */
+
+/*
+ * Authorship
+ * ----------
+ * This software ('beatnik' RTEMS BSP for MVME6100 and MVME5500) was
+ * created by Till Straumann <strauman@slac.stanford.edu>, 2005-2007,
+ * Stanford Linear Accelerator Center, Stanford University.
+ *
+ * Acknowledgement of sponsorship
+ * ------------------------------
+ * The 'beatnik' 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/rtems_bsdnet.h>
+
+#include <bsp.h>
+#include <bsp/irq.h>
+#include <bsp/pci.h>
+
+#include <bsp/early_enet_link_status.h>
+
+#include <bsp/if_mve_pub.h>
+#include <bsp/if_gfe_pub.h>
+#include <bsp/if_em_pub.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+#define IS_6100() (MVME6100 == BSP_getBoardType())
+#define IS_5500() (MVME5500 == BSP_getBoardType())
+
+static int bsp_gfe_attach(struct rtems_bsdnet_ifconfig *, int);
+static int mvme5500_em_attach (struct rtems_bsdnet_ifconfig *, int);
+static int mvme5500_em_find_onboard_unit(void);
+
+char BSP_auto_network_driver_name[20] = {0,};
+
+static BSP_NetIFDescRec mvme6100_netifs[] = {
+ {
+ name: "mve1",
+ description: "MV64360 built-in 10/100/1000 Ethernet 1",
+ attach_fn: rtems_mve_attach
+ },
+ {
+ name: "mve2",
+ description: "MV64360 built-in 10/100/1000 Ethernet 2",
+ attach_fn: rtems_mve_attach
+ },
+ {
+ name: 0,
+ }
+};
+
+static BSP_NetIFDescRec mvme5500_netifs[] = {
+ {
+ name: "em1",
+ description: "Intel 82544 on-board 10/100/1000 Ethernet (port 1)",
+ attach_fn: mvme5500_em_attach,
+ },
+ {
+ name: "gfe1",
+ description: "GT64260 built-in 10/100 Ethernet (port 2)",
+ attach_fn: bsp_gfe_attach,
+ },
+ {
+ name: 0,
+ }
+};
+
+
+/* wrap the 'gfe' and 'em' attach functions.
+ * RATIONALE: 'rtems_gfe_attach()' and 'rtems_em_attach()' are
+ * *chip* specific functions. However, they require
+ * some *board* specific parameter setup prior to
+ * being attached which is what these wrappers do...
+ */
+
+static unsigned em_info[];
+
+static int scan4irqLine(int bus, int dev, int fn, void *uarg)
+{
+unsigned char byte;
+unsigned short word;
+int i;
+
+ /* count the number of 82544 we find */
+ pci_read_config_word(bus, dev, fn, PCI_VENDOR_ID, &word);
+ if ( 0x8086 != word )
+ return 0;
+
+ pci_read_config_word(bus, dev, fn, PCI_DEVICE_ID, &word);
+ for ( i = 0; em_info[i]; i++ ) {
+ if ( em_info[i] == word )
+ break;
+ }
+
+ if ( !em_info[i] )
+ return 0;
+
+ /* found a candidate; bump unit number */
+ (*(int *)uarg)++;
+
+ pci_read_config_byte(bus, dev, fn, PCI_INTERRUPT_LINE, &byte);
+
+ /* On the mvme5500 the 82544 is hooked to GPP IRQ 20 */
+
+ return ( BSP_IRQ_GPP_0 + 20 == byte ) ? 1 : 0;
+}
+
+/* Setup only once */
+static void
+onboard_em_setup_once(void)
+{
+static char done = 0;
+
+ /* If scanning didn't do anything, passing 0 will setup all interfaces */
+ if ( !done
+ && rtems_em_pci_setup( mvme5500_em_find_onboard_unit() > 0 ) ) {
+ done=1;
+ }
+}
+
+static void
+onboard_gfe_setup_once(void)
+{
+static char done = 0;
+
+ /* must setup HW address -- note that the label on the
+ * board indicates that the gfe is the second interface
+ * but motLoad etc. interprets the order actually
+ * the other way round...
+ */
+ if ( !done
+ && rtems_gfe_setup( 1, BSP_enetAddr0, BSP_MV64x60_BASE ) > 0 ) {
+ done=1;
+ }
+}
+
+
+/* Find the unit number of the on-board 82544 (even if there is another one
+ * plugged into PMC...
+ *
+ * RETURNS: unit # (>0) or zero if nothing at all was found. (New board rev.
+ * with the 82544 hooked to a different IRQ line, new PCI device ID,
+ * ...)
+ */
+static int
+mvme5500_em_find_onboard_unit(void)
+{
+int unit = 0;
+void *h;
+ /* Determine the on-board 'em' adapter; we know it's interrupt line :-) */
+ for ( h=0; (h=BSP_pciScan(h, scan4irqLine, &unit)); )
+ /* nothing else to do */;
+ return h ? unit : 0;
+}
+
+static int
+mvme5500_em_attach(struct rtems_bsdnet_ifconfig *ifcfg, int attaching)
+{
+ if ( attaching ) {
+ onboard_em_setup_once();
+
+ /* Make sure there is no conflict in MAC address -- see below
+ * why we 'swap' the addresses. (We actually don't but swap the
+ * order of the interfaces so they match the label.)
+ */
+ if ( !ifcfg->hardware_address )
+ ifcfg->hardware_address = BSP_enetAddr1;
+ }
+
+ return rtems_em_attach(ifcfg, attaching);
+}
+
+static int
+bsp_gfe_attach(struct rtems_bsdnet_ifconfig *ifcfg, int attaching)
+{
+ if ( attaching ) {
+ onboard_gfe_setup_once();
+ }
+ return rtems_gfe_attach(ifcfg, attaching);
+}
+
+BSP_NetIFDesc
+BSP_availableNetIFs(void)
+{
+ if ( IS_6100() )
+ return mvme6100_netifs;
+ if ( IS_5500() )
+ return mvme5500_netifs;
+
+ fprintf(stderr,"BSP_availableNetIFs() -- productIdent not set? unable to identify board type\n");
+
+ return 0;
+}
+
+typedef int (*read_op_t)(int,unsigned);
+typedef int (*write_op_t)(int,unsigned,unsigned);
+
+struct poll_job {
+ read_op_t rdop;
+ write_op_t wrop;
+ int unit;
+};
+
+static int
+check_phys(struct poll_job *job)
+{
+struct poll_job *j;
+int rval = -2;
+ for ( j=job; j->rdop; j++ ) {
+ unsigned w;
+ w = j->rdop(j->unit, 1/*status*/);
+ if ( 0x04 & w ) /* active link */
+ return j-job;
+ if ( !(0x20 & w) ) /* aneg not done */
+ rval = -1;
+ }
+ return rval;
+}
+
+/* check a number of phys
+ * RETURNS: -1 if at least one is still busy
+ * -2 if all are terminated but no link is found
+ * >=0 index of first IF with a live link
+ */
+static int
+poll_phys(struct poll_job *job)
+{
+int rval;
+struct poll_job *j = job;
+int retry = 4;
+
+ /* see if we already have a link */
+ if ( (rval=check_phys(job)) < 0 ) {
+ /* no - start negotiation */
+ for ( j = job; j->rdop; j++ ) {
+ j->wrop(j->unit, 0/* ctrl */, 0x1200 /* start aneg */);
+ }
+
+ do {
+ sleep(1);
+ } while ( -1 == (rval = check_phys(job)) && retry-- );
+ }
+
+ return rval;
+}
+
+
+/* note that detaching is not supported by the current version of the BSD stack */
+int
+BSP_auto_enet_attach(struct rtems_bsdnet_ifconfig *ifcfg, int attaching)
+{
+int i = -1;
+BSP_NetIFDesc d = BSP_availableNetIFs();
+struct poll_job job[3];
+
+ if ( !d )
+ return -1;
+
+ /* If they pass a name, find the attach fn */
+ if ( ifcfg->name && RTEMS_BSP_NETWORK_DRIVER_NAME != ifcfg->name && attaching ) {
+ for (i = 0; d[i].name; i++ ) {
+ if ( !strcmp(d[i].name, ifcfg->name) ) {
+ ifcfg->attach = d[i].attach_fn;
+ break;
+ }
+ }
+ if ( !d[i].name ) {
+ fprintf(stderr,"WARNING: have no '%s' interface - using default\n", ifcfg->name);
+ ifcfg->name = 0;
+ }
+ }
+
+ if ( !ifcfg->name || ifcfg->name == RTEMS_BSP_NETWORK_DRIVER_NAME ) {
+ /* automatically choose and attach an interface */
+ if ( RTEMS_BSP_NETWORK_DRIVER_NAME[0] ) {
+ fprintf(stderr,
+ "Configuration error: 'auto' network if already chosen (%s)\n",
+ RTEMS_BSP_NETWORK_DRIVER_NAME);
+ return -1;
+ }
+ if ( IS_6100() ) {
+#define ops rtems_mve_early_link_check_ops
+ assert(ops.num_slots >= 2);
+ ops.init(0);
+ ops.init(1);
+ job[0].rdop = ops.read_phy;
+ job[0].wrop = ops.write_phy;
+ job[0].unit = 0;
+ job[1].rdop = ops.read_phy;
+ job[1].wrop = ops.write_phy;
+ job[1].unit = 1;
+#undef ops
+ } else if ( IS_5500() ) {
+#define opsgfe rtems_gfe_early_link_check_ops
+#define opsem rtems_em_early_link_check_ops
+ assert(opsgfe.num_slots >= 1);
+ onboard_gfe_setup_once();
+ opsgfe.init(0);
+ assert(opsem.num_slots >= 1);
+ onboard_em_setup_once();
+ opsem.init(0);
+ job[0].rdop = opsem.read_phy;
+ job[0].wrop = opsem.write_phy;
+ job[0].unit = 0;
+ job[1].rdop = opsgfe.read_phy;
+ job[1].wrop = opsgfe.write_phy;
+ job[1].unit = 0;
+#undef opsgfe
+#undef opsem
+ }
+ job[2].rdop = 0; /* tag end */
+ i = poll_phys(job);
+ if ( i >= 0 ) {
+ printf("L");
+ } else {
+ i = 0;
+ printf("No l");
+ }
+ printf("ink detected; attaching %s\n",d[i].name);
+
+ /* set attach function and IF name */
+ ifcfg->attach = d[i].attach_fn;
+ ifcfg->name = RTEMS_BSP_NETWORK_DRIVER_NAME;
+ strcpy(RTEMS_BSP_NETWORK_DRIVER_NAME, d[i].name);
+ }
+ return ifcfg->attach(ifcfg, attaching);
+}
+
+/* from 'em' */
+
+/* PCI Device IDs */
+#define E1000_DEV_ID_82542 0x1000
+#define E1000_DEV_ID_82543GC_FIBER 0x1001
+#define E1000_DEV_ID_82543GC_COPPER 0x1004
+#define E1000_DEV_ID_82544EI_COPPER 0x1008
+#define E1000_DEV_ID_82544EI_FIBER 0x1009
+#define E1000_DEV_ID_82544GC_COPPER 0x100C
+#define E1000_DEV_ID_82544GC_LOM 0x100D
+#define E1000_DEV_ID_82540EM 0x100E
+#define E1000_DEV_ID_82541ER_LOM 0x1014
+#define E1000_DEV_ID_82540EM_LOM 0x1015
+#define E1000_DEV_ID_82540EP_LOM 0x1016
+#define E1000_DEV_ID_82540EP 0x1017
+#define E1000_DEV_ID_82540EP_LP 0x101E
+#define E1000_DEV_ID_82545EM_COPPER 0x100F
+#define E1000_DEV_ID_82545EM_FIBER 0x1011
+#define E1000_DEV_ID_82545GM_COPPER 0x1026
+#define E1000_DEV_ID_82545GM_FIBER 0x1027
+#define E1000_DEV_ID_82545GM_SERDES 0x1028
+#define E1000_DEV_ID_82546EB_COPPER 0x1010
+#define E1000_DEV_ID_82546EB_FIBER 0x1012
+#define E1000_DEV_ID_82546EB_QUAD_COPPER 0x101D
+#define E1000_DEV_ID_82541EI 0x1013
+#define E1000_DEV_ID_82541EI_MOBILE 0x1018
+#define E1000_DEV_ID_82541ER 0x1078
+#define E1000_DEV_ID_82547GI 0x1075
+#define E1000_DEV_ID_82541GI 0x1076
+#define E1000_DEV_ID_82541GI_MOBILE 0x1077
+#define E1000_DEV_ID_82541GI_LF 0x107C
+#define E1000_DEV_ID_82546GB_COPPER 0x1079
+#define E1000_DEV_ID_82546GB_FIBER 0x107A
+#define E1000_DEV_ID_82546GB_SERDES 0x107B
+#define E1000_DEV_ID_82546GB_PCIE 0x108A
+#define E1000_DEV_ID_82547EI 0x1019
+#define E1000_DEV_ID_82547EI_MOBILE 0x101A
+#define E1000_DEV_ID_82573E 0x108B
+#define E1000_DEV_ID_82573E_IAMT 0x108C
+
+#define E1000_DEV_ID_82546GB_QUAD_COPPER 0x1099
+
+static unsigned em_info[] =
+{
+ /* Intel(R) PRO/1000 Network Connection */
+ E1000_DEV_ID_82540EM,
+ E1000_DEV_ID_82540EM_LOM,
+ E1000_DEV_ID_82540EP,
+ E1000_DEV_ID_82540EP_LOM,
+ E1000_DEV_ID_82540EP_LP,
+
+ E1000_DEV_ID_82541EI,
+ E1000_DEV_ID_82541ER,
+ E1000_DEV_ID_82541ER_LOM,
+ E1000_DEV_ID_82541EI_MOBILE,
+ E1000_DEV_ID_82541GI,
+ E1000_DEV_ID_82541GI_LF,
+ E1000_DEV_ID_82541GI_MOBILE,
+
+ E1000_DEV_ID_82542,
+
+ E1000_DEV_ID_82543GC_FIBER,
+ E1000_DEV_ID_82543GC_COPPER,
+
+ E1000_DEV_ID_82544EI_COPPER,
+ E1000_DEV_ID_82544EI_FIBER,
+ E1000_DEV_ID_82544GC_COPPER,
+ E1000_DEV_ID_82544GC_LOM,
+
+ E1000_DEV_ID_82545EM_COPPER,
+ E1000_DEV_ID_82545EM_FIBER,
+ E1000_DEV_ID_82545GM_COPPER,
+ E1000_DEV_ID_82545GM_FIBER,
+ E1000_DEV_ID_82545GM_SERDES,
+
+ E1000_DEV_ID_82546EB_COPPER,
+ E1000_DEV_ID_82546EB_FIBER,
+ E1000_DEV_ID_82546EB_QUAD_COPPER,
+ E1000_DEV_ID_82546GB_COPPER,
+ E1000_DEV_ID_82546GB_FIBER,
+ E1000_DEV_ID_82546GB_SERDES,
+ E1000_DEV_ID_82546GB_PCIE,
+ E1000_DEV_ID_82546GB_QUAD_COPPER,
+
+ E1000_DEV_ID_82547EI,
+ E1000_DEV_ID_82547EI_MOBILE,
+ E1000_DEV_ID_82547GI,
+
+ E1000_DEV_ID_82573E,
+ E1000_DEV_ID_82573E_IAMT,
+
+ /* required last entry */
+ 0,
+};
diff --git a/c/src/lib/libbsp/powerpc/beatnik/network/support/bsp_bsdnet_attach.h b/c/src/lib/libbsp/powerpc/beatnik/network/support/bsp_bsdnet_attach.h
new file mode 100644
index 0000000000..fa7d16b5b5
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/beatnik/network/support/bsp_bsdnet_attach.h
@@ -0,0 +1,80 @@
+/* $Id$ */
+#ifndef BSP_BSDNET_ATTACH_INFO_H
+#define BSP_BSDNET_ATTACH_INFO_H
+
+/* Author: Till Straumann, 2005; see ../../LICENSE */
+
+/* Rationale: traditionally, BSPs only supported a single networking interface
+ * the BSP defined RTEMS_NETWORK_DRIVER_NAME & friends macros
+ * for applications to use.
+ * If more than one interface is present, this simple approach is
+ * not enough.
+ * Hence, this BSP exports a routine declaring all available interfaces
+ * so the application can make a choice.
+ */
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/* Fwd. decl just in case */
+struct rtems_bsdnet_ifconfig;
+
+typedef struct {
+ /* name of the interface */
+ const char *name;
+ /* optional description (to be used by chooser 'help' function etc.) */
+ const char *description;
+ /* driver 'attach' function */
+ int (*attach_fn)(struct rtems_bsdnet_ifconfig*, int);
+} BSP_NetIFDescRec, *BSP_NetIFDesc;
+
+/* Return a pointer to the (static) list of network interface descriptions
+ * of this board.
+ *
+ * NOTES: A NULL value is returned if e.g., the board type cannot be determined
+ * or for other reasons.
+ * The 'description' field is optional, i.e., may be NULL.
+ * The list is terminated by an element with a NULL name field.
+ * The interfaces are listed in the order they are labelled.
+ */
+
+BSP_NetIFDesc
+BSP_availableNetIFs();
+
+/* Define this macro so applications can conditionally compile this API */
+#define BSP_HAS_MULTIPLE_NETIFS(x) BSP_availableNetIFs()
+
+/* Legacy macro; applications should use BSP_Available_NetIfs() to choose
+ * an interface and attach function.
+ */
+extern char BSP_auto_network_driver_name[20];
+#define RTEMS_BSP_NETWORK_DRIVER_NAME BSP_auto_network_driver_name
+
+#define RTEMS_BSP_NETWORK_DRIVER_ATTACH BSP_auto_enet_attach
+
+/* This routine checks the name field passed in the 'ifconfig'.
+ * If the name is NULL or points to the BSP_auto_network_driver_name
+ * array, the routine checks all interfaces for an active link and
+ * attaches the first alive one.
+ * It also updates 'ifconfig' to reflect the chosen interface's name
+ * and attach function.
+ *
+ * If another name is passed in, the routine scans
+ * the available interfaces for that name and uses it, if found.
+ * Eventually, a default interface is chosen (provided that
+ * the board type is successfully detected).
+ *
+ * Note that only ONE interface chained into rtems_bsdnet_config
+ * may use the "auto" name.
+ *
+ */
+
+int
+BSP_auto_enet_attach(struct rtems_bsdnet_ifconfig *ifconfig, int attaching);
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif
diff --git a/c/src/lib/libbsp/powerpc/beatnik/network/support/early_enet_link_status.h b/c/src/lib/libbsp/powerpc/beatnik/network/support/early_enet_link_status.h
new file mode 100644
index 0000000000..7a6543c281
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/beatnik/network/support/early_enet_link_status.h
@@ -0,0 +1,31 @@
+/*$Id$*/
+#ifndef BSP_EARLY_ENET_LINK_STATUS_H
+#define BSP_EARLY_ENET_LINK_STATUS_H
+
+/* Determine link status of ethernet device before network is initialized */
+
+/* T. Straumann, 2005; see ../../LICENSE */
+
+#include <rtems.h>
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+typedef struct {
+ int (*init)(int idx); /* perform enough initialization to access (default) phy */
+ int (*read_phy)(int idx, unsigned reg);
+ int (*write_phy)(int idx, unsigned reg, unsigned val);
+ const char *name; /* driver name */
+ unsigned char num_slots; /* max number of supported devices */
+ unsigned char initialized; /* must be initialized to 0; */
+} rtems_bsdnet_early_link_check_ops;
+
+int
+BSP_early_check_link_status(int unit, rtems_bsdnet_early_link_check_ops *ops);
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif
diff --git a/c/src/lib/libbsp/powerpc/beatnik/network/support/early_link_status.c b/c/src/lib/libbsp/powerpc/beatnik/network/support/early_link_status.c
new file mode 100644
index 0000000000..be76cdeaa0
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/beatnik/network/support/early_link_status.c
@@ -0,0 +1,41 @@
+/* $Id$ */
+#include <rtems.h>
+#include <bsp/early_enet_link_status.h>
+#include <rtems/bspIo.h>
+
+/* T. Straumann, 2005; see ../../LICENSE */
+
+static const char *ename = ": rtems_em_early_check_link_status() - ";
+
+int
+BSP_early_check_link_status(int unit, rtems_bsdnet_early_link_check_ops *ops)
+{
+int status;
+
+ unit--;
+ if ( unit < 0 || unit >= ops->num_slots ) {
+ printk("%s%sinvalid unit # %i (not in %i..%i)\n",
+ ops->name, ename, unit+1, 1, ops->num_slots);
+ return -1;
+ }
+
+ if ( !ops->initialized ) {
+ if ( ops->init(unit) ) {
+ printk("%s%sFAILURE to init hardware\n",ops->name, ename);
+ return -1;
+ }
+ /* Start autoneg */
+ if ( ops->write_phy(unit, 0, 0x1200) ) {
+ printk("%s%sFAILURE to start autonegotiation\n",ops->name, ename);
+ return -1;
+ }
+ /* Dont wait here; the caller can do this on various interfaces
+ * and wait herself.
+ */
+ ops->initialized = 1;
+ }
+ if ( (status = ops->read_phy(unit, 1)) < 0 ) {
+ printk("%s%sFAILURE to read phy status\n", ops->name, ename);
+ }
+ return status;
+}
diff --git a/c/src/lib/libbsp/powerpc/beatnik/pci/gt_pci_init.c b/c/src/lib/libbsp/powerpc/beatnik/pci/gt_pci_init.c
new file mode 100644
index 0000000000..7acb240d72
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/beatnik/pci/gt_pci_init.c
@@ -0,0 +1,274 @@
+/* $Id$ */
+
+/* PCI configuration space access */
+
+/*
+ * Acknowledgements:
+ * Valuable information was obtained from the following drivers
+ * netbsd: (C) Allegro Networks Inc; Wasabi Systems Inc.
+ * linux: (C) MontaVista, Software, Inc; Chris Zankel, Mark A. Greer.
+ * rtems: (C) Brookhaven National Laboratory; K. Feng
+ */
+
+/*
+ * Original file header of libbsp/shared/pci.c where this file is based upon.
+ *
+ * Copyright (C) 1999 valette@crf.canon.fr
+ *
+ * This code is heavily 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.
+ *
+ * $Id$
+ *
+ * Till Straumann, <strauman@slac.stanford.edu>, 1/2002
+ * - separated bridge detection code out of this file
+ */
+
+#include <rtems.h>
+#include <bsp.h>
+#include <libcpu/io.h>
+#include <bsp/pci.h>
+#include <rtems/bspIo.h>
+#include <stdint.h>
+
+/* set to max so we get early access to hose 0 */
+unsigned BSP_pci_hose1_bus_base = (unsigned)-1;
+
+#define MV64x60_PCI0_CONFIG_ADDR (BSP_MV64x60_BASE + 0xcf8)
+#define MV64x60_PCI0_CONFIG_DATA (BSP_MV64x60_BASE + 0xcfc)
+#define MV64x60_PCI1_CONFIG_ADDR (BSP_MV64x60_BASE + 0xc78)
+#define MV64x60_PCI1_CONFIG_DATA (BSP_MV64x60_BASE + 0xc7c)
+
+#define PCI_BUS2HOSE(bus) (bus<BSP_pci_hose1_bus_base?0:1)
+
+void detect_host_bridge(void)
+{
+
+}
+
+typedef struct {
+ volatile unsigned char *pci_config_addr;
+ volatile unsigned char *pci_config_data;
+} PciHoseCfg;
+
+static PciHoseCfg hoses[2] = {
+ {
+ pci_config_addr: (volatile unsigned char *)(MV64x60_PCI0_CONFIG_ADDR),
+ pci_config_data: (volatile unsigned char *)(MV64x60_PCI0_CONFIG_DATA),
+ },
+ {
+ pci_config_addr: (volatile unsigned char *)(MV64x60_PCI1_CONFIG_ADDR),
+ pci_config_data: (volatile unsigned char *)(MV64x60_PCI1_CONFIG_DATA),
+ }
+};
+
+#define pci hoses[hose]
+
+#define HOSE_PREAMBLE \
+ uint8_t hose; \
+ if (bus < BSP_pci_hose1_bus_base) { \
+ hose = 0; \
+ } else { \
+ hose = 1; \
+ bus -= BSP_pci_hose1_bus_base; \
+ }
+
+
+/* Sigh; we have to copy those out from the shared area... */
+static int
+indirect_pci_read_config_byte(unsigned char bus, unsigned char slot,
+ unsigned char function,
+ unsigned char offset, uint8_t *val) {
+HOSE_PREAMBLE;
+ out_be32((volatile unsigned *) pci.pci_config_addr,
+ 0x80|(bus<<8)|(PCI_DEVFN(slot,function)<<16)|((offset&~3)<<24));
+ *val = in_8(pci.pci_config_data + (offset&3));
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int
+indirect_pci_read_config_word(unsigned char bus, unsigned char slot,
+ unsigned char function,
+ unsigned char offset, uint16_t *val) {
+HOSE_PREAMBLE;
+ *val = 0xffff;
+ if (offset&1) return PCIBIOS_BAD_REGISTER_NUMBER;
+ out_be32((unsigned int*) pci.pci_config_addr,
+ 0x80|(bus<<8)|(PCI_DEVFN(slot,function)<<16)|((offset&~3)<<24));
+ *val = in_le16((volatile unsigned short *)(pci.pci_config_data + (offset&3)));
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int
+indirect_pci_read_config_dword(unsigned char bus, unsigned char slot,
+ unsigned char function,
+ unsigned char offset, uint32_t *val) {
+HOSE_PREAMBLE;
+ *val = 0xffffffff;
+ if (offset&3) return PCIBIOS_BAD_REGISTER_NUMBER;
+ out_be32((unsigned int*) pci.pci_config_addr,
+ 0x80|(bus<<8)|(PCI_DEVFN(slot,function)<<16)|(offset<<24));
+ *val = in_le32((volatile unsigned *)pci.pci_config_data);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int
+indirect_pci_write_config_byte(unsigned char bus, unsigned char slot,
+ unsigned char function,
+ unsigned char offset, uint8_t val) {
+HOSE_PREAMBLE;
+ out_be32((unsigned int*) pci.pci_config_addr,
+ 0x80|(bus<<8)|(PCI_DEVFN(slot,function)<<16)|((offset&~3)<<24));
+ out_8(pci.pci_config_data + (offset&3), val);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int
+indirect_pci_write_config_word(unsigned char bus, unsigned char slot,
+ unsigned char function,
+ unsigned char offset, uint16_t val) {
+HOSE_PREAMBLE;
+ if (offset&1) return PCIBIOS_BAD_REGISTER_NUMBER;
+ out_be32((unsigned int*) pci.pci_config_addr,
+ 0x80|(bus<<8)|(PCI_DEVFN(slot,function)<<16)|((offset&~3)<<24));
+ out_le16((volatile unsigned short *)(pci.pci_config_data + (offset&3)), val);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int
+indirect_pci_write_config_dword(unsigned char bus, unsigned char slot,
+ unsigned char function,
+ unsigned char offset, uint32_t val) {
+HOSE_PREAMBLE;
+ if (offset&3) return PCIBIOS_BAD_REGISTER_NUMBER;
+ out_be32((unsigned int*) pci.pci_config_addr,
+ 0x80|(bus<<8)|(PCI_DEVFN(slot,function)<<16)|(offset<<24));
+ out_le32((volatile unsigned *)pci.pci_config_data, val);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+const pci_config_access_functions pci_hosed_indirect_functions = {
+ indirect_pci_read_config_byte,
+ indirect_pci_read_config_word,
+ indirect_pci_read_config_dword,
+ indirect_pci_write_config_byte,
+ indirect_pci_write_config_word,
+ indirect_pci_write_config_dword
+};
+
+
+extern unsigned char ucMaxPCIBus; /* importing this is ugly */
+
+/* This is a very ugly hack. I don't want to change the shared
+ * code to support multiple hoses so we hide everything under
+ * the hood with horrible kludges for now. Sorry.
+ */
+void
+BSP_pci_initialize(void)
+{
+
+#if 0 /* These values are already set up for the shared/pci.c code */
+{
+extern pci_config_access_functions pci_indirect_functions;
+ /* by means of the PCI_CONFIG_ADDR/PCI_CONFIG_DATA macros (bsp.h) */
+ BSP_pci_configuration.pci_config_addr = hoses[0].pci_config_addr;
+ BSP_pci_configuration.pci_config_data = hoses[0].pci_config_data;
+ BSP_pci_configuration.pci_functions = &pci_indirect_functions;
+}
+#endif
+ /* initialize the first hose */
+ /* scan hose 0 and sets the maximum bus number */
+ pci_initialize();
+ /* remember the boundary */
+ BSP_pci_hose1_bus_base = pci_bus_count();
+ /* so far, so good -- now comes the cludgy part: */
+ /* hack/reset the bus count */
+ ucMaxPCIBus = 0;
+ /* scan hose 1 */
+ BSP_pci_configuration.pci_config_addr = hoses[1].pci_config_addr;
+ BSP_pci_configuration.pci_config_data = hoses[1].pci_config_data;
+ pci_initialize();
+ /* check for overflow of an unsigned char */
+ if ( BSP_pci_hose1_bus_base + pci_bus_count() > 255 ) {
+ BSP_panic("Too many PCI busses in the system");
+ }
+ /* readjust total number */
+ ucMaxPCIBus+=BSP_pci_hose1_bus_base;
+
+ /* install new access functions that can hide the hoses */
+ BSP_pci_configuration.pci_config_addr = (volatile unsigned char *)0xdeadbeef;
+ BSP_pci_configuration.pci_config_data = (volatile unsigned char *)0xdeadbeef;
+ BSP_pci_configuration.pci_functions = &pci_hosed_indirect_functions;
+}
+
+#define PCI_ERR_BITS 0xf900
+#define PCI_STATUS_OK(x) (!((x)&PCI_ERR_BITS))
+
+/* For now, just clear errors in the PCI status reg.
+ *
+ * Returns: (for diagnostic purposes)
+ * original settings (i.e. before applying the clearing
+ * sequence)
+ * (pci_status(hose_1)&0xff00) | ((pci_status(hose_2)>>8)&0xff)
+ */
+
+static unsigned long clear_hose_errors(int bus, int quiet)
+{
+unsigned long rval;
+uint16_t pcistat;
+int count;
+int hose = PCI_BUS2HOSE(bus);
+
+ /* read error status for info return */
+ pci_read_config_word(bus,0,0,PCI_STATUS,&pcistat);
+ rval = pcistat;
+
+ count=10;
+ do {
+ /* clear error reporting registers */
+
+ /* clear PCI status register */
+ pci_write_config_word(bus,0,0,PCI_STATUS, PCI_ERR_BITS);
+
+ /* read new status */
+ pci_read_config_word(bus,0,0,PCI_STATUS, &pcistat);
+
+ } while ( ! PCI_STATUS_OK(pcistat) && count-- );
+
+ if ( !PCI_STATUS_OK(rval) && !quiet) {
+ printk("Cleared PCI errors at discovery (hose %i): pci_stat was 0x%04x\n", hose, rval);
+ }
+ if ( !PCI_STATUS_OK(pcistat) ) {
+ printk("Unable to clear PCI errors at discovery (hose %i) still 0x%04x after 10 attempts\n",hose, pcistat);
+ }
+ return rval;
+}
+
+unsigned short
+(*_BSP_clear_vmebridge_errors)(int) = 0;
+
+unsigned long
+_BSP_clear_hostbridge_errors(int enableMCP, int quiet)
+{
+unsigned long rval;
+
+ /* MCP is not connected */
+ if ( enableMCP )
+ return -1;
+
+ rval = (clear_hose_errors(0, quiet) & PCI_ERR_BITS)>>8;
+ rval |= clear_hose_errors(BSP_pci_hose1_bus_base, quiet) & PCI_ERR_BITS;
+
+ /* Tsi148 doesn't propagate VME bus errors to PCI status reg. */
+ if ( _BSP_clear_vmebridge_errors )
+ rval |= _BSP_clear_vmebridge_errors(quiet)<<16;
+
+ return rval;
+}
diff --git a/c/src/lib/libbsp/powerpc/beatnik/pci/motload_fixup.c b/c/src/lib/libbsp/powerpc/beatnik/pci/motload_fixup.c
new file mode 100644
index 0000000000..93746e6d0e
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/beatnik/pci/motload_fixup.c
@@ -0,0 +1,182 @@
+/* $Id$ */
+
+/* remap the zero-based PCI IO spaces of both hoses to a single
+ * address space
+ *
+ * This must be called AFTER to BSP_pci_initialize()
+ */
+
+/*
+ * Authorship
+ * ----------
+ * This software ('beatnik' RTEMS BSP for MVME6100 and MVME5500) was
+ * created by Till Straumann <strauman@slac.stanford.edu>, 2005-2007,
+ * Stanford Linear Accelerator Center, Stanford University.
+ *
+ * Acknowledgement of sponsorship
+ * ------------------------------
+ * The 'beatnik' 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/io.h>
+#include <bsp/pci.h>
+#include <bsp/irq.h>
+#include <rtems/bspIo.h>
+#include <bsp/gtreg.h>
+#include "pci_io_remap.h"
+
+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_IRQ_GPP_0 ) {
+ pci_write_config_byte( bus, slot, fun, PCI_INTERRUPT_LINE, line + BSP_IRQ_GPP_0 );
+ }
+
+ return 0;
+}
+
+void BSP_motload_pci_fixup(void)
+{
+uint32_t b0,b1,r0,r1,lim,dis;
+
+ /* MotLoad on the mvme5500 and mvme6100 configures the PCI
+ * busses nicely, i.e., the values read from the memory address
+ * space BARs by means of PCI config cycles directly reflect the
+ * CPU memory map. Thus, the presence of two hoses is already hidden.
+ *
+ * Unfortunately, all PCI I/O addresses are 'zero-based' i.e.,
+ * a hose-specific base address would have to be added to
+ * the values read from config space.
+ *
+ * We fix this here so I/O BARs also reflect the CPU memory map.
+ *
+ * Furthermore, the mvme5500 uses
+ * f000.0000
+ * ..f07f.ffff for PCI-0 / hose0
+ *
+ * and
+ *
+ * f080.0000
+ * ..f0ff.0000 for PCI-1 / hose 0
+ *
+ * whereas the mvme6100 does it the other way round...
+ */
+
+ b0 = in_le32( (volatile unsigned*)(BSP_MV64x60_BASE + GT_PCI0_IO_Low_Decode) );
+ b1 = in_le32( (volatile unsigned*)(BSP_MV64x60_BASE + GT_PCI1_IO_Low_Decode) );
+
+ r0 = in_le32( (volatile unsigned*)(BSP_MV64x60_BASE + GT_PCI0_IO_Remap) );
+ r1 = in_le32( (volatile unsigned*)(BSP_MV64x60_BASE + GT_PCI1_IO_Remap) );
+
+ switch ( BSP_getDiscoveryVersion(0) ) {
+ case MV_64360:
+ /* In case of the MV64360 the 'limit' is actually a 'size'!
+ * Disable by setting special bits in the 'BAR disable reg'.
+ */
+ dis = in_le32( (volatile unsigned*)(BSP_MV64x60_BASE + MV_64360_BASE_ADDR_DISBL) );
+ /* disable PCI0 I/O and PCI1 I/O */
+ out_le32( (volatile unsigned*)(BSP_MV64x60_BASE + MV_64360_BASE_ADDR_DISBL), dis | (1<<9) | (1<<14) );
+ /* remap busses on hose 0; if the remap register was already set, assume
+ * that someone else [such as the bootloader] already performed the fixup
+ */
+ if ( (b0 & 0xffff) && 0 == (r0 & 0xffff) ) {
+ rtems_pci_io_remap( 0, BSP_pci_hose1_bus_base, (b0 & 0xffff)<<16 );
+ out_le32( (volatile unsigned*)(BSP_MV64x60_BASE + GT_PCI0_IO_Remap), (b0 & 0xffff) );
+ }
+
+ /* remap busses on hose 1 */
+ if ( (b1 & 0xffff) && 0 == (r1 & 0xffff) ) {
+ rtems_pci_io_remap( BSP_pci_hose1_bus_base, pci_bus_count(), (b1 & 0xffff)<<16 );
+ out_le32( (volatile unsigned*)(BSP_MV64x60_BASE + GT_PCI1_IO_Remap), (b1 & 0xffff) );
+ }
+
+ /* re-enable */
+ out_le32( (volatile unsigned*)(BSP_MV64x60_BASE + MV_64360_BASE_ADDR_DISBL), dis );
+ break;
+
+ case GT_64260_A:
+ case GT_64260_B:
+
+ if ( (b0 & 0xfff) && 0 == (r0 & 0xfff) ) { /* base are only 12 bits */
+ /* switch window off by setting the limit < base */
+ lim = in_le32( (volatile unsigned*)(BSP_MV64x60_BASE + GT_PCI0_IO_High_Decode) );
+ out_le32( (volatile unsigned*)(BSP_MV64x60_BASE + GT_PCI0_IO_High_Decode), 0 );
+ /* remap busses on hose 0 */
+ rtems_pci_io_remap( 0, BSP_pci_hose1_bus_base, (b0 & 0xfff)<<20 );
+
+ /* BTW: it seems that writing the base register also copies the
+ * value into the 'remap' register automatically (??)
+ */
+ out_le32( (volatile unsigned*)(BSP_MV64x60_BASE + GT_PCI0_IO_Remap), (b0 & 0xfff) );
+
+ /* re-enable */
+ out_le32( (volatile unsigned*)(BSP_MV64x60_BASE + GT_PCI0_IO_High_Decode), lim );
+ }
+
+ if ( (b1 & 0xfff) && 0 == (r1 & 0xfff) ) { /* base are only 12 bits */
+ /* switch window off by setting the limit < base */
+ lim = in_le32( (volatile unsigned*)(BSP_MV64x60_BASE + GT_PCI1_IO_High_Decode) );
+ out_le32( (volatile unsigned*)(BSP_MV64x60_BASE + GT_PCI1_IO_High_Decode), 0 );
+
+ /* remap busses on hose 1 */
+ rtems_pci_io_remap( BSP_pci_hose1_bus_base, pci_bus_count(), (b1 & 0xfff)<<20 );
+
+ out_le32( (volatile unsigned*)(BSP_MV64x60_BASE + GT_PCI1_IO_Remap), (b1 & 0xfff) );
+
+ /* re-enable */
+ out_le32( (volatile unsigned*)(BSP_MV64x60_BASE + GT_PCI1_IO_High_Decode), lim );
+ }
+ break;
+
+ default:
+ BSP_panic("Unknown discovery version; switch in file: "__FILE__" not implemented (yet)");
+ break; /* never get here */
+ }
+
+ /* Fixup the IRQ lines; the mvme6100 maps them nicely into our scheme, i.e., GPP
+ * interrupts start at 64 upwards
+ *
+ * The mvme5500 is apparently initialized differently :-(. GPP interrupts start at 0
+ * Since all PCI interrupts are wired to GPP we simply check for a value < 64 and
+ * reprogram the interrupt line register.
+ */
+ BSP_pciScan(0, fixup_irq_line, 0);
+}
+
+
diff --git a/c/src/lib/libbsp/powerpc/beatnik/pci/pci_io_remap.c b/c/src/lib/libbsp/powerpc/beatnik/pci/pci_io_remap.c
new file mode 100644
index 0000000000..cb25c5b7e4
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/beatnik/pci/pci_io_remap.c
@@ -0,0 +1,207 @@
+/* $Id$ */
+
+/* Adjust a PCI bus range's I/O address space by adding an offset */
+
+/*
+ * Authorship
+ * ----------
+ * This software ('beatnik' RTEMS BSP for MVME6100 and MVME5500) was
+ * created by Till Straumann <strauman@slac.stanford.edu>, 2005-2007,
+ * Stanford Linear Accelerator Center, Stanford University.
+ *
+ * Acknowledgement of sponsorship
+ * ------------------------------
+ * The 'beatnik' 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/bspIo.h>
+#include <bsp/pci.h>
+#include <stdint.h>
+
+#ifndef PCI_MULTI_FUN
+#define PCI_MULTI_FUN 0x80
+#endif
+
+#ifndef PCI_HEADER_TYPE_MSK
+#define PCI_HEADER_TYPE_MSK 0x7f
+#endif
+
+/* Reconfigure all I/O base address registers for a range of PCI busses
+ * (from and including 'bus_from' up to and not including 'bus_to').
+ * adding an offset. This involves adjusting the base and limit registers
+ * of PCI-PCI bridges, too.
+ *
+ * RESTRICTIONS: 'offset' must be 4k aligned (PCI req.); no argument check
+ * on the bus numbers is done.
+ *
+ * RETURNS: 0 on success and a number > 0 indicating the number of
+ * non-32bit bridges found where the offset couldn't be added.
+ * Devices behind such a bridge are not accessible through I/O
+ * and should probably be switched off (not done by this code).
+ */
+
+int
+rtems_pci_io_remap(int bus_from, int bus_to, uint32_t offset)
+{
+int rval = 0;
+
+int bus, dev, fun, maxf;
+int bar, numBars = 0;
+
+uint8_t b;
+uint16_t s;
+uint32_t d;
+unsigned int bas, lim;
+
+ if ( offset & ((1<<12)-1) ) {
+ BSP_panic("rtems_pci_io_remap(): offset must be 4k aligned");
+ return -1;
+ }
+
+
+ for ( bus=bus_from; bus < bus_to; bus++ ) {
+ for ( dev = 0; dev<PCI_MAX_DEVICES; dev++ ) {
+
+ maxf = 1;
+
+ for ( fun = 0; fun < maxf; fun++ ) {
+ pci_read_config_word( bus, dev, fun, PCI_VENDOR_ID, &s );
+ if ( 0xffff == s )
+ continue;
+
+ pci_read_config_byte( bus, dev, fun, PCI_HEADER_TYPE, &b );
+
+ /* readjust the max. function number to scan if this is a multi-function
+ * device.
+ */
+ if ( 0 == fun && (PCI_MULTI_FUN & b) )
+ maxf = PCI_MAX_FUNCTIONS;
+
+ /* Check the header type; panic if unknown.
+ * header type 0 has 6 bars, header type 1 (PCI-PCI bridge) has 2
+ */
+ b &= PCI_HEADER_TYPE_MSK;
+ switch ( b ) {
+ default:
+ printk("PCI header type %i (@%i/%i/%i)\n", b, bus, dev, fun);
+ BSP_panic("rtems_pci_io_remap(): unknown PCI header type");
+ return -1; /* keep compiler happy */
+
+ case PCI_HEADER_TYPE_CARDBUS:
+ printk("PCI header type %i (@%i/%i/%i)\n", b, bus, dev, fun);
+ BSP_panic("rtems_pci_io_remap(): don't know how to deal with Cardbus bridge");
+ return -1;
+
+ case PCI_HEADER_TYPE_NORMAL:
+ numBars = 6*4; /* loop below counts reg. offset in bytes */
+ break;
+
+ case PCI_HEADER_TYPE_BRIDGE:
+ numBars = 2*4; /* loop below counts reg. offset in bytes */
+ break;
+
+ }
+
+ for ( bar = 0; bar < numBars; bar+=4 ) {
+ pci_read_config_dword( bus, dev, fun, PCI_BASE_ADDRESS_0 + bar, &d );
+ if ( PCI_BASE_ADDRESS_SPACE_IO & d ) {
+ /* It's an I/O BAR; remap */
+ d &= PCI_BASE_ADDRESS_IO_MASK;
+ if ( d ) {
+ /* IO bar was configured; add offset */
+ d += offset;
+ pci_write_config_dword( bus, dev, fun, PCI_BASE_ADDRESS_0 + bar, d );
+ }
+ } else {
+ /* skip upper half of 64-bit window */
+ d &= PCI_BASE_ADDRESS_MEM_TYPE_MASK;
+ if ( PCI_BASE_ADDRESS_MEM_TYPE_64 == d )
+ bar+=4;
+ }
+ }
+
+ /* Now it's time to deal with bridges */
+ if ( PCI_HEADER_TYPE_BRIDGE == b ) {
+ /* must adjust the limit registers */
+ pci_read_config_byte( bus, dev, fun, PCI_IO_LIMIT, &b );
+ pci_read_config_word( bus, dev, fun, PCI_IO_LIMIT_UPPER16, &s );
+ lim = (s<<16) + (( b & PCI_IO_RANGE_MASK ) << 8);
+ lim += offset;
+
+ pci_read_config_byte( bus, dev, fun, PCI_IO_BASE, &b );
+ pci_read_config_word( bus, dev, fun, PCI_IO_BASE_UPPER16, &s );
+ bas = (s<<16) + (( b & PCI_IO_RANGE_MASK ) << 8);
+ bas += offset;
+
+ b &= PCI_IO_RANGE_TYPE_MASK;
+ switch ( b ) {
+ default:
+ printk("Unknown IO range type 0x%x (@%i/%i/%i)\n", b, bus, dev, fun);
+ BSP_panic("rtems_pci_io_remap(): unknown IO range type");
+ return -1;
+
+ case PCI_IO_RANGE_TYPE_16:
+ if ( bas > 0xffff || lim > 0xffff ) {
+ printk("PCI I/O range type 1 (16bit) bridge (@%i/%i/%i) found:\n", bus, dev, fun);
+ printk("WARNING: base (0x%08x) or limit (0x%08x) exceed 16-bit;\n", bas, lim);
+ printk(" devices behind this bridge are NOT accessible!\n");
+
+ /* FIXME: should we disable devices behind this bridge ? */
+ bas = lim = 0;
+ }
+ break;
+
+ case PCI_IO_RANGE_TYPE_32:
+ break;
+ }
+
+ b = (uint8_t)((bas>>8) & PCI_IO_RANGE_MASK);
+ pci_write_config_byte( bus, dev, fun, PCI_IO_BASE, b );
+
+ s = (uint16_t)((bas>>16)&0xffff);
+ pci_write_config_word( bus, dev, fun, PCI_IO_BASE_UPPER16, s);
+
+ b = (uint8_t)((lim>>8) & PCI_IO_RANGE_MASK);
+ pci_write_config_byte( bus, dev, fun, PCI_IO_LIMIT, b );
+ s = (uint16_t)((lim>>16)&0xffff);
+ pci_write_config_word( bus, dev, fun, PCI_IO_LIMIT_UPPER16, s );
+ }
+ }
+ }
+ }
+ return rval;
+}
diff --git a/c/src/lib/libbsp/powerpc/beatnik/pci/pci_io_remap.h b/c/src/lib/libbsp/powerpc/beatnik/pci/pci_io_remap.h
new file mode 100644
index 0000000000..533519a2ae
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/beatnik/pci/pci_io_remap.h
@@ -0,0 +1,66 @@
+#ifndef RTEMS_PCI_IO_REMAP_H
+#define RTEMS_PCI_IO_REMAP_H
+/* Reconfigure all I/O base address registers for a range of PCI busses
+ * (from and including 'bus_from' up to and not including 'bus_to').
+ * adding an offset. This involves adjusting the base and limit registers
+ * of PCI-PCI bridges, too.
+ *
+ * RESTRICTIONS: 'offset' must be 4k aligned (PCI req.); no argument check
+ * on the bus numbers is done.
+ *
+ * RETURNS: 0 on success and a number > 0 indicating the number of
+ * non-32bit bridges found where the offset couldn't be added.
+ * Devices behind such a bridge are not accessible through I/O
+ * and should probably be switched off (not done by this code).
+ */
+
+int
+rtems_pci_io_remap(int bus_from, int bus_to, uint32_t offset);
+
+/*
+ * Authorship
+ * ----------
+ * This software ('beatnik' RTEMS BSP for MVME6100 and MVME5500) was
+ * created by Till Straumann <strauman@slac.stanford.edu>, 2005-2007,
+ * Stanford Linear Accelerator Center, Stanford University.
+ *
+ * Acknowledgement of sponsorship
+ * ------------------------------
+ * The 'beatnik' 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
+ */
+
+#endif
+
diff --git a/c/src/lib/libbsp/powerpc/beatnik/preinstall.am b/c/src/lib/libbsp/powerpc/beatnik/preinstall.am
new file mode 100644
index 0000000000..51a83f2ded
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/beatnik/preinstall.am
@@ -0,0 +1,188 @@
+## 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_INCLUDE)/bsp/$(dirstamp):
+ @$(MKDIR_P) $(PROJECT_INCLUDE)/bsp
+ @: > $(PROJECT_INCLUDE)/bsp/$(dirstamp)
+PREINSTALL_DIRS += $(PROJECT_INCLUDE)/bsp/$(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/bootcard.h: ../../shared/include/bootcard.h $(PROJECT_INCLUDE)/bsp/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/bootcard.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/bootcard.h
+
+$(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)/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)/linkcmds: ../shared/startup/linkcmds $(PROJECT_LIB)/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_LIB)/linkcmds
+PREINSTALL_FILES += $(PROJECT_LIB)/linkcmds
+
+$(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/consoleIo.h: ../../powerpc/shared/console/consoleIo.h $(PROJECT_INCLUDE)/bsp/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/consoleIo.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/consoleIo.h
+
+$(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/gtreg.h: marvell/gtreg.h $(PROJECT_INCLUDE)/bsp/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/gtreg.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/gtreg.h
+
+$(PROJECT_INCLUDE)/bsp/gtintrreg.h: marvell/gtintrreg.h $(PROJECT_INCLUDE)/bsp/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/gtintrreg.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/gtintrreg.h
+
+$(PROJECT_INCLUDE)/bsp/gti2creg.h: marvell/gti2creg.h $(PROJECT_INCLUDE)/bsp/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/gti2creg.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/gti2creg.h
+
+$(PROJECT_INCLUDE)/bsp/gti2c_busdrv.h: marvell/gti2c_busdrv.h $(PROJECT_INCLUDE)/bsp/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/gti2c_busdrv.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/gti2c_busdrv.h
+
+$(PROJECT_INCLUDE)/bsp/gt_timer.h: marvell/gt_timer.h $(PROJECT_INCLUDE)/bsp/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/gt_timer.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/gt_timer.h
+
+$(PROJECT_INCLUDE)/bsp/gtpcireg.h: marvell/gtpcireg.h $(PROJECT_INCLUDE)/bsp/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/gtpcireg.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/gtpcireg.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/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/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/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/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/vmeUniverse.h: ../../shared/vmeUniverse/vmeUniverse.h $(PROJECT_INCLUDE)/bsp/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/vmeUniverse.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/vmeUniverse.h
+
+$(PROJECT_INCLUDE)/bsp/vmeUniverseDMA.h: ../../shared/vmeUniverse/vmeUniverseDMA.h $(PROJECT_INCLUDE)/bsp/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/vmeUniverseDMA.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/vmeUniverseDMA.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/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/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/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/VMEDMA.h: ../../shared/vmeUniverse/VMEDMA.h $(PROJECT_INCLUDE)/bsp/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/VMEDMA.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/VMEDMA.h
+
+if HAS_NETWORKING
+$(PROJECT_INCLUDE)/bsp/early_enet_link_status.h: network/support/early_enet_link_status.h $(PROJECT_INCLUDE)/bsp/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/early_enet_link_status.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/early_enet_link_status.h
+
+$(PROJECT_INCLUDE)/bsp/bsp_bsdnet_attach.h: network/support/bsp_bsdnet_attach.h $(PROJECT_INCLUDE)/bsp/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/bsp_bsdnet_attach.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/bsp_bsdnet_attach.h
+
+$(PROJECT_INCLUDE)/bsp/if_mve_pub.h: network/if_mve/if_mve_pub.h $(PROJECT_INCLUDE)/bsp/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/if_mve_pub.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/if_mve_pub.h
+
+$(PROJECT_INCLUDE)/bsp/if_gfe_pub.h: network/if_gfe/if_gfe_pub.h $(PROJECT_INCLUDE)/bsp/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/if_gfe_pub.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/if_gfe_pub.h
+
+$(PROJECT_INCLUDE)/bsp/if_em_pub.h: network/if_em/if_em_pub.h $(PROJECT_INCLUDE)/bsp/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/if_em_pub.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/if_em_pub.h
+endif
+$(PROJECT_INCLUDE)/tod.h: ../../shared/tod.h $(PROJECT_INCLUDE)/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/tod.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/tod.h
+
diff --git a/c/src/lib/libbsp/powerpc/beatnik/startup/bspclean.c b/c/src/lib/libbsp/powerpc/beatnik/startup/bspclean.c
new file mode 100644
index 0000000000..746a48fbde
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/beatnik/startup/bspclean.c
@@ -0,0 +1,11 @@
+#include <bsp.h>
+#include <rtems/bspIo.h>
+
+void bsp_cleanup(void)
+{
+ /* We can't go back to MotLoad since we blew it's memory area
+ * and vectors. Just pull the reset line...
+ */
+ printk("bsp_cleanup(): RTEMS terminated -- no way back to MotLoad so I reset the card\n");
+ bsp_reset();
+}
diff --git a/c/src/lib/libbsp/powerpc/beatnik/startup/bspstart.c b/c/src/lib/libbsp/powerpc/beatnik/startup/bspstart.c
new file mode 100644
index 0000000000..d88476a3f1
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/beatnik/startup/bspstart.c
@@ -0,0 +1,397 @@
+/*
+ * 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.OARcorp.com/rtems/license.html.
+ *
+ * Modified to support the MCP750.
+ * Modifications Copyright (C) 1999 Eric Valette. valette@crf.canon.fr
+ *
+ * Modified to support the Synergy VGM & Motorola PowerPC boards.
+ * (C) by Till Straumann, <strauman@slac.stanford.edu>, 2002, 2004, 2005
+ *
+ * Modified to support the mvme5500 BSP
+ * (C) by Kate Feng <feng1@bnl.gov>, 2003, 2004
+ * under the contract DE-AC02-98CH10886 with the Deaprtment of Energy
+ *
+ * T. Straumann: 2005-2007; stolen again for 'beatnik'...
+ */
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#include <rtems/system.h>
+#include <rtems/libio.h>
+#include <rtems/libcsupport.h>
+#include <rtems/bspIo.h>
+#include <rtems/powerpc/powerpc.h>
+/*#include <bsp/consoleIo.h>*/
+#include <libcpu/spr.h> /* registers.h is included here */
+#include <bsp.h>
+#include <bsp/uart.h>
+#include <bsp/pci.h>
+#include <bsp/gtreg.h>
+#include <bsp/gt_timer.h>
+#include <libcpu/bat.h>
+#include <libcpu/pte121.h>
+#include <libcpu/cpuIdent.h>
+#include <bsp/vectors.h>
+#include <bsp/vpd.h>
+
+/* for RTEMS_VERSION :-( I dont like the preassembled string */
+#include <rtems/sptables.h>
+
+#ifdef __RTEMS_APPLICATION__
+#undef __RTEMS_APPLICATION__
+#endif
+
+#define SHOW_MORE_INIT_SETTINGS
+
+BSP_output_char_function_type BSP_output_char = BSP_output_char_via_serial;
+
+extern char *BSP_build_date;
+extern void bsp_cleanup(void);
+extern Triv121PgTbl BSP_pgtbl_setup(unsigned int *);
+extern void BSP_pgtbl_activate(Triv121PgTbl);
+extern void BSP_motload_pci_fixup(void);
+
+extern unsigned long __rtems_end[];
+
+/* We really shouldn't use these since MMUoff also sets IP;
+ * nevertheless, during early init I don't care for now
+ */
+extern void MMUoff(void);
+extern void MMUon(void);
+
+extern uint32_t probeMemoryEnd(void);
+
+SPR_RW(SPRG0)
+SPR_RW(SPRG1)
+SPR_RO(HID1)
+
+/* Table of PLL multipliers for 7455/7457:
+01000 2 00010 7.5 00000 11.5 00001 17
+10000 3 11000 8 10111 12 00101 18
+10100 4 01100 8.5 11111 12.5 00111 20
+10110 5 01111 9 01011 13 01001 21
+10010 5.5 01110 9.5 11100 13.5 01101 24
+11010 6 10101 10 11001 14 11101 28
+01010 6.5 10001 10.5 00011 15 00110 bypass
+00100 7 10011 11 11011 16 11110 off
+*/
+
+/* Sorted according to CFG bits and multiplied by 2 it looks
+ * like this (note that this is in sequential order, not
+ * tabulated as above)
+ */
+signed char mpc7450PllMultByTwo[32] = {
+23, 34, 15, 30,
+14, 36, 2/*bypass*/, 40,
+4, 42, 13, 26,
+17, 48, 19, 18,
+6, 21, 11, 22,
+8, 20, 10, 24,
+16, 28, 12, 32,
+27, 56, 0/*off*/, 25,
+};
+
+uint32_t bsp_clicks_per_usec = 0;
+
+/*
+ * Total memory using probing.
+ */
+unsigned int BSP_mem_size;
+
+/*
+ * PCI Bus Frequency
+ */
+unsigned int BSP_bus_frequency = 0xdeadbeef;
+/*
+ * processor clock frequency
+ */
+unsigned int BSP_processor_frequency = 0xdeadbeef;
+
+/*
+ * Time base divisior (bus freq / TB clock)
+ */
+unsigned int BSP_time_base_divisor = 4000; /* most 604+ CPUs seem to use this */
+
+/* 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};
+
+/*
+ * 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
+ */
+
+extern void bsp_pretasking_hook(void);
+
+#define CMDLINE_BUF_SIZE 2048
+
+static char cmdline_buf[CMDLINE_BUF_SIZE];
+char *BSP_commandline_string = cmdline_buf;
+
+/* this routine is called early and must be safe with a not properly
+ * aligned stack
+ */
+char *
+save_boot_params(void *r3, void *r4, void* r5, char *cmdline_start, char *cmdline_end)
+{
+int i=cmdline_end-cmdline_start;
+ if ( i >= CMDLINE_BUF_SIZE )
+ i = CMDLINE_BUF_SIZE-1;
+ else if ( i < 0 )
+ i = 0;
+ memmove(cmdline_buf, cmdline_start, i);
+ cmdline_buf[i]=0;
+ return cmdline_buf;
+}
+
+static BSP_BoardType board_type = Unknown;
+
+BSP_BoardType
+BSP_getBoardType( void )
+{
+ return board_type;
+}
+
+/*
+ * bsp_start
+ *
+ * This routine does the bulk of the system initialization.
+ */
+
+void bsp_start( void )
+{
+ unsigned char *stack;
+ char *chpt;
+ uint32_t intrStackStart;
+ uint32_t intrStackSize;
+
+ Triv121PgTbl pt=0;
+
+ 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: CpuClockHz, instance: 0, buf: &BSP_processor_frequency, buflen: sizeof(BSP_processor_frequency) },
+ { key: BusClockHz, instance: 0, buf: &BSP_bus_frequency, buflen: sizeof(BSP_bus_frequency) },
+ { key: EthernetAddr, instance: 0, buf: BSP_enetAddr0, buflen: sizeof(BSP_enetAddr0) },
+ { key: EthernetAddr, instance: 1, buf: BSP_enetAddr1, buflen: sizeof(BSP_enetAddr1) },
+ VPD_END
+ };
+
+ /* T. Straumann: 4/2005
+ *
+ * Need to map the system registers early, so we can printk...
+ * (otherwise we silently die)
+ */
+ /* map the PCI 0, 1 Domain I/O space, GT64260B registers
+ * and the reserved area so that the size is the power of 2.
+ */
+ setdbat(7, BSP_DEV_AND_PCI_IO_BASE, BSP_DEV_AND_PCI_IO_BASE, BSP_DEV_AND_PCI_IO_SIZE, IO_PAGE);
+
+ /* Intersperse messages with actions to help locate problems */
+ printk("-----------------------------------------\n");
+
+ /*
+ * Get CPU identification dynamically. Note that the get_ppc_cpu_type() & friends functions
+ * store the result in global variables so that it can be used latter...
+ * This also verifies that we run on a known CPU.
+ */
+ get_ppc_cpu_type();
+ get_ppc_cpu_revision();
+
+ /* Make sure we detect a known host bridge */
+ BSP_getDiscoveryVersion(/* assert detection */ 1);
+
+ printk("Welcome to %s ($Name$)\n", _RTEMS_version );
+
+ /* Leave all caches as MotLoad left them. Seems to be fine */
+
+ /*
+ * 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));
+
+ /* tag the bottom (T. Straumann 6/36/2001 <strauman@slac.stanford.edu>) */
+
+ *((uint32_t *)stack) = 0;
+
+ /*
+ * Initialize the interrupt related settings
+ * SPRG0 = interrupt nesting level count
+ * SPRG1 = software managed IRQ stack
+ *
+ * This could be done latter (e.g in IRQ_INIT) but it helps to understand
+ * some settings below...
+ */
+ intrStackStart = (uint32_t)__rtems_end;
+ intrStackSize = rtems_configuration_get_interrupt_stack_size();
+
+
+ /*
+ * Initialize default raw exception handlers. See vectors/vectors_init.c
+ */
+ ppc_exc_initialize(
+ PPC_INTERRUPT_DISABLE_MASK_DEFAULT,
+ intrStackStart,
+ intrStackSize
+ );
+
+ printk("CPU: %s\n", get_ppc_cpu_type_name(current_ppc_cpu));
+
+ /*
+ * Initialize RTEMS IRQ system
+ */
+ BSP_rtems_irq_mng_init(0);
+
+ printk("Build Date: %s\n",BSP_build_date);
+
+ BSP_vpdRetrieveFields(vpdData);
+
+ if ( !strncmp(BSP_productIdent,"MVME5500",8) )
+ board_type = MVME5500;
+ else if ( !strncmp(BSP_productIdent,"MVME6100",8) )
+ board_type = MVME6100;
+
+ printk("Board Type: %s (S/N %s)\n",
+ BSP_productIdent[0] ? BSP_productIdent : "n/a",
+ BSP_serialNumber[0] ? BSP_serialNumber : "n/a");
+
+ if ( 0xdeadbeef == BSP_bus_frequency ) {
+ BSP_bus_frequency = 133333333;
+ printk("Bus Clock Freq NOT FOUND in VPD; using %10u Hz\n",
+ BSP_bus_frequency);
+ } else {
+ printk("Bus Clock Freq: %10u Hz\n",
+ BSP_bus_frequency);
+ }
+
+ if ( 0xdeadbeef == BSP_processor_frequency ) {
+ BSP_processor_frequency = BSP_bus_frequency/2;
+ BSP_processor_frequency *= mpc7450PllMultByTwo[ (_read_HID1() >> (31-19)) & 31 ];
+ }
+ printk("CPU Clock Freq: %10u Hz\n", BSP_processor_frequency);
+
+ /* probe real memory size; if it's more than 256M we can't currently access it
+ * since at this point only BAT-0 maps 0..256M
+ */
+ BSP_mem_size = probeMemoryEnd();
+
+ 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);
+
+ if ( BSP_mem_size > 0x10000000 ) {
+ uint32_t s;
+ if ( BSP_mem_size > 0x80000000 ) {
+ BSP_mem_size = 0x80000000;
+ printk("Memory clipped to 0x%08x for now, sorry\n", BSP_mem_size);
+ }
+ for ( s = 0x20000000; s < BSP_mem_size ; s<<=1)
+ ;
+ MMUoff();
+ /* since it's currently in use we must first surrender it */
+ setdbat(0, 0, 0, 0, 0);
+ setdbat(0, 0, 0, s, _PAGE_RW);
+ MMUon();
+ }
+
+ printk("-----------------------------------------\n");
+
+ /* Maybe not setup yet because of the warning message */
+
+ /* Allocate and set up the page table mappings
+ * This is only available on >604 CPUs.
+ *
+ * NOTE: This setup routine may modify the available memory
+ * size. It is essential to call it before
+ * calculating the workspace etc.
+ */
+ pt = BSP_pgtbl_setup(&BSP_mem_size);
+ if (!pt)
+ printk("WARNING: unable to setup page tables.\n");
+
+#ifdef SHOW_MORE_INIT_SETTINGS
+ printk("Now BSP_mem_size = 0x%x\n",BSP_mem_size);
+#endif
+
+ /*
+ * Set up our hooks
+ * Make sure libc_init is done before drivers initialized so that
+ * they can use atexit()
+ */
+
+ 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
+
+ /* Activate the page table mappings only after
+ * initializing interrupts because the irq_mng_init()
+ * routine needs to modify the text
+ */
+ if ( pt ) {
+#ifdef SHOW_MORE_INIT_SETTINGS
+ printk("Page table setup finished; will activate it NOW...\n");
+#endif
+ BSP_pgtbl_activate(pt);
+ }
+
+#ifdef SHOW_MORE_INIT_SETTINGS
+ printk("Going to start PCI buses scanning and initialization\n");
+#endif
+ BSP_pci_initialize();
+
+ /* need to tweak the motload setup */
+ BSP_motload_pci_fixup();
+
+ /* map 512M, 256 for PCI 256 for VME */
+ setdbat(5,BSP_PCI_HOSE0_MEM_BASE, BSP_PCI_HOSE0_MEM_BASE, BSP_PCI_HOSE0_MEM_SIZE, IO_PAGE);
+ setdbat(6,BSP_PCI_HOSE1_MEM_BASE, BSP_PCI_HOSE1_MEM_BASE, 0x10000000, IO_PAGE);
+
+#ifdef SHOW_MORE_INIT_SETTINGS
+ printk("Number of PCI buses found is : %d\n", pci_bus_count());
+#endif
+
+ /*
+ * Initialize hardware timer facility (not used by BSP itself)
+ * Needs PCI to identify discovery version...
+ */
+ BSP_timers_initialize();
+
+#ifdef SHOW_MORE_INIT_SETTINGS
+ printk("MSR %x \n", _read_MSR());
+ printk("Exit from bspstart\n");
+#endif
+}
diff --git a/c/src/lib/libbsp/powerpc/beatnik/startup/i2c_init.c b/c/src/lib/libbsp/powerpc/beatnik/startup/i2c_init.c
new file mode 100644
index 0000000000..a91d456cf8
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/beatnik/startup/i2c_init.c
@@ -0,0 +1,132 @@
+/* $Id$ */
+#include <rtems.h>
+#include <bsp.h>
+#include <rtems/libi2c.h>
+#include <libchip/i2c-2b-eeprom.h>
+#include <libchip/i2c-ds1621.h>
+#include <bsp/gti2c_busdrv.h>
+#include <rtems/libio.h>
+
+#include <stdio.h>
+#include <sys/stat.h>
+
+/* Register i2c bus driver & devices */
+
+/*
+ * Authorship
+ * ----------
+ * This software ('beatnik' RTEMS BSP for MVME6100 and MVME5500) was
+ * created by Till Straumann <strauman@slac.stanford.edu>, 2005-2007,
+ * Stanford Linear Accelerator Center, Stanford University.
+ *
+ * Acknowledgement of sponsorship
+ * ------------------------------
+ * The 'beatnik' 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
+ */
+
+int
+BSP_i2c_initialize( void )
+{
+int busno;
+ /* Initialize the library */
+ if ( rtems_libi2c_initialize() ) {
+ fprintf(stderr,"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 ) {
+ perror("Registering gt64260 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 ) {
+ perror("Registering i2c VPD eeprom driver failed");
+ return -1;
+ }
+
+ /* 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_USR_I2C_ADDR) < 0 ) {
+ perror("Registering i2c USR eeprom driver failed");
+ return -1;
+ }
+
+ /* The thermostat */
+ if ( rtems_libi2c_register_drv(
+ BSP_I2C_DS1621_NAME,
+ i2c_ds1621_driver_descriptor,
+ busno,
+ BSP_THM_I2C_ADDR) < 0 ) {
+ perror("Registering i2c ds1621 temp sensor. driver failed");
+ return -1;
+ }
+
+ /* 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))) ) {
+ perror("Creating device node for raw ds1621 access failed");
+ return -1;
+ }
+ printf("I2C devices registered\n");
+ return 0;
+}
diff --git a/c/src/lib/libbsp/powerpc/beatnik/startup/linkcmds b/c/src/lib/libbsp/powerpc/beatnik/startup/linkcmds
new file mode 100644
index 0000000000..a186b6dcae
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/beatnik/startup/linkcmds
@@ -0,0 +1,261 @@
+OUTPUT_FORMAT("elf32-powerpc", "elf32-powerpc",
+ "elf32-powerpc")
+OUTPUT_ARCH(powerpc)
+ENTRY(_start)
+/* Do we need any of these for elf?
+ __DYNAMIC = 0; */
+PROVIDE (__stack = 0);
+
+
+MEMORY {
+ BOTTOM : ORIGIN = 0x00, LENGTH = 0x80
+ MAILBOX : ORIGIN = 0x80, LENGTH = 0x80 /* RESERVED */
+ VECTORS : ORIGIN = 0x100 , LENGTH = 0x3000 - 0x100
+ CODE : ORIGIN = 0x3000 , LENGTH = 32M-0x3000
+}
+SECTIONS
+{
+ /* discard the 'shared/vector.S' entry point section */
+ /DISCARD/ :
+ {
+ *(.entry_point_section)
+ }
+
+
+ .vectors :
+ {
+ /* should be the first thing... */
+ *(.ppc_preloader_section)
+
+ /*
+ * This section is used only if NO_DYNAMIC_EXCEPTION_VECTOR_INSTALL
+ * is defined in vectors/vectors.S
+ * *(.vectors)
+ * We actually RELY on dynamic vector installation since we need
+ * this space for the preloader...
+ */
+ } > VECTORS
+
+
+ /* START OF THE LOADED IMAGE (parts moved by the preloader) */
+ .image_start :
+ {
+ __rtems_start = ABSOLUTE(.);
+ } > CODE
+
+ /* Read-only sections, merged into text segment: */
+ .interp : { *(.interp) } > CODE
+ .hash : { *(.hash) } > CODE
+ .dynsym : { *(.dynsym) } > CODE
+ .dynstr : { *(.dynstr) } > CODE
+ .gnu.version : { *(.gnu.version) } > CODE
+ .gnu.version_d : { *(.gnu.version_d) } > CODE
+ .gnu.version_r : { *(.gnu.version_r) } > CODE
+ .rela.text :
+ { *(.rela.text) *(.rela.gnu.linkonce.t*) } > CODE
+ .rela.data :
+ { *(.rela.data) *(.rela.gnu.linkonce.d*) } > CODE
+ .rela.rodata :
+ { *(.rela.rodata) *(.rela.gnu.linkonce.r*) } > CODE
+ .rela.got : { *(.rela.got) } > CODE
+ .rela.got1 : { *(.rela.got1) } > CODE
+ .rela.got2 : { *(.rela.got2) } > CODE
+ .rela.ctors : { *(.rela.ctors) } > CODE
+ .rela.dtors : { *(.rela.dtors) } > CODE
+ .rela.init : { *(.rela.init) } > CODE
+ .rela.fini : { *(.rela.fini) } > CODE
+ .rela.bss : { *(.rela.bss) } > CODE
+ .rela.plt : { *(.rela.plt) } > CODE
+ .rela.sdata : { *(.rela.sdata) } > CODE
+ .rela.sbss : { *(.rela.sbss) } > CODE
+ .rela.sdata2 : { *(.rela.sdata2) } > CODE
+ .rela.sbss2 : { *(.rela.sbss2) } > CODE
+
+ .init : { *(.init) } >CODE
+
+ .text :
+ {
+ *(.text*)
+
+ /*
+ * Special FreeBSD sysctl sections.
+ */
+ . = ALIGN (16);
+ __start_set_sysctl_set = .;
+ *(set_sysctl_*);
+ __stop_set_sysctl_set = ABSOLUTE(.);
+ *(set_domain_*);
+ *(set_pseudo_*);
+
+ /* .gnu.warning sections are handled specially by elf32.em. */
+ *(.gnu.warning)
+ *(.gnu.linkonce.t*)
+ } > CODE
+
+ .fini : { _fini = .; *(.fini) } >CODE
+ .rodata : { *(.rodata*) *(.gnu.linkonce.r*) } > CODE
+ .rodata1 : { *(.rodata1) } > CODE
+_SDA2_BASE_ = __SDATA2_START__ + 0x8000;
+ .sdata2 : { *(.sdata2) *(.gnu.linkonce.s2.*) } > CODE
+ .sbss2 : {
+ PROVIDE (__sbss2_start = .);
+ *(.sbss2*) *(.gnu.linkonce.sb2.*)
+ /* avoid empty sdata2/sbss2 area because __eabi wouldn't set up r2
+ * (IMPORTANT if run-time loading is involved)
+ */
+ . += 1 ;
+ PROVIDE (__sbss2_end = .);
+ } > CODE
+ .eh_frame : { *.(eh_frame) } >CODE
+ _etext = .;
+ PROVIDE (etext = .);
+ /* Adjust the address for the data segment. We want to adjust up to
+ the same address within the page on the next page up. It would
+ be more correct to do this:
+ . = ALIGN(0x40000) + (ALIGN(8) & (0x40000 - 1));
+ The current expression does not correctly handle the case of a
+ text segment ending precisely at the end of a page; it causes the
+ data segment to skip a page. The above expression does not have
+ this problem, but it will currently (2/95) cause BFD to allocate
+ a single segment, combining both text and data, for this case.
+ This will prevent the text segment from being shared among
+ multiple executions of the program; I think that is more
+ important than losing a page of the virtual address space (note
+ that no actual memory is lost; the page which is skipped can not
+ be referenced). */
+ .data ALIGN(0x1000) :
+ {
+ PROVIDE(__DATA_START__ = ABSOLUTE(.) );
+ *(.data)
+ *(.gnu.linkonce.d*)
+ CONSTRUCTORS
+ } > CODE
+ .data1 : { *(.data1) } > CODE
+ PROVIDE (__EXCEPT_START__ = .);
+ .gcc_except_table : { *(.gcc_except_table) } > CODE
+ PROVIDE (__EXCEPT_END__ = .);
+ .got1 : { *(.got1) } > CODE
+ .dynamic : { *(.dynamic) } > CODE
+ /* Put .ctors and .dtors next to the .got2 section, so that the pointers
+ get relocated with -mrelocatable. Also put in the .fixup pointers.
+ The current compiler no longer needs this, but keep it around for 2.7.2 */
+ PROVIDE (_GOT2_START_ = .);
+ .got2 : { *(.got2) } > CODE
+/*
+ PROVIDE (__CTOR_LIST__ = .);
+ .ctors : { *(.ctors) } > CODE
+ PROVIDE (__CTOR_END__ = .);
+*/
+ .ctors :
+ {
+ KEEP(*crtbegin.o(.ctors))
+ KEEP(*(EXCLUDE_FILE(*crtend.o) .ctors))
+ KEEP(*(SORT(.ctors.*)))
+ KEEP(*(.ctors))
+ } > CODE
+ .dtors :
+ {
+ KEEP(*crtbegin.o(.dtors))
+ KEEP(*(EXCLUDE_FILE(*crtend.o) .dtors))
+ KEEP(*(SORT(.dtors.*)))
+ KEEP(*(.dtors))
+ } > CODE
+/*
+ PROVIDE (__DTOR_LIST__ = .);
+ .dtors : { *(.dtors) } > CODE
+ PROVIDE (__DTOR_END__ = .);
+*/
+ PROVIDE (_FIXUP_START_ = .);
+ .fixup : { *(.fixup) } > CODE
+ PROVIDE (_FIXUP_END_ = .);
+ PROVIDE (_GOT2_END_ = .);
+ PROVIDE (_GOT_START_ = .);
+ .got : { *(.got) } > CODE
+ .got.plt : { *(.got.plt) } > CODE
+ PROVIDE (_GOT_END_ = .);
+
+ .jcr : { KEEP (*(.jcr)) } > CODE
+
+ /* We want the small data sections together, so single-instruction offsets
+ can access them all, and initialized data all before uninitialized, so
+ we can shorten the on-disk segment size. */
+_SDA_BASE_ = __SDATA_START__ + 0x8000;
+ .sdata : { *(.sdata*) *(.gnu.linkonce.s.*) } > CODE
+ _edata = .;
+ PROVIDE (edata = .);
+/* END OF THE LOADED IMAGE (parts moved by the preloader) */
+/* BELOW THIS POINT, NO LOADABLE ITEMS MUST APPEAR */
+ .sbss :
+ {
+ PROVIDE (__sbss_start = ABSOLUTE(.));
+ *(.sbss) *(.sbss.*) *(.gnu.linkonce.sb.*)
+ *(.scommon)
+ *(.dynsbss)
+ /* avoid empty sdata/sbss area because __eabi wouldn't set up r13
+ * (IMPORTANT if run-time loading is involved)
+ */
+ . += 1 ;
+ PROVIDE (__sbss_end = ABSOLUTE(.));
+ } > CODE
+ .plt : { *(.plt) } > CODE
+ .bss :
+ {
+ PROVIDE (__bss_start = ABSOLUTE(.));
+ *(.dynbss)
+ *(.bss*) *(.gnu.linkonce.b.*)
+ *(COMMON)
+ . = ALIGN(16);
+ } > CODE
+ /* proper alignment for SYSV stack
+ * (init stack is allocated just after __rtems_end
+ */
+ . = ALIGN(16);
+ _end = . ;
+ __rtems_end = . ;
+ PROVIDE (end = .);
+ /DISCARD/ :
+ {
+ *(.comment)
+ }
+
+
+ /* Stabs debugging sections. */
+ .stab 0 : { *(.stab) }
+ .stabstr 0 : { *(.stabstr) }
+ .stab.excl 0 : { *(.stab.excl) }
+ .stab.exclstr 0 : { *(.stab.exclstr) }
+ .stab.index 0 : { *(.stab.index) }
+ .stab.indexstr 0 : { *(.stab.indexstr) }
+ .comment 0 : { *(.comment) }
+
+ /* DWARF debug sections.
+ Symbols in the DWARF debugging sections are relative to the beginning
+ of the section so we begin them at 0. */
+ /* DWARF 1 */
+ .debug 0 : { *(.debug) }
+ .line 0 : { *(.line) }
+
+ /* GNU DWARF 1 extensions */
+ .debug_srcinfo 0 : { *(.debug_srcinfo) }
+ .debug_sfnames 0 : { *(.debug_sfnames) }
+
+ /* DWARF 1.1 and DWARF 2 */
+ .debug_aranges 0 : { *(.debug_aranges) }
+ .debug_pubnames 0 : { *(.debug_pubnames) }
+
+ /* DWARF 2 */
+ .debug_info 0 : { *(.debug_info) }
+ .debug_abbrev 0 : { *(.debug_abbrev) }
+ .debug_line 0 : { *(.debug_line) }
+ .debug_frame 0 : { *(.debug_frame) }
+ .debug_str 0 : { *(.debug_str) }
+ .debug_loc 0 : { *(.debug_loc) }
+ .debug_macinfo 0 : { *(.debug_macinfo) }
+
+ /* SGI/MIPS DWARF 2 extensions */
+ .debug_weaknames 0 : { *(.debug_weaknames) }
+ .debug_funcnames 0 : { *(.debug_funcnames) }
+ .debug_typenames 0 : { *(.debug_typenames) }
+ .debug_varnames 0 : { *(.debug_varnames) }
+ /* These must appear regardless of . */
+}
diff --git a/c/src/lib/libbsp/powerpc/beatnik/startup/reboot.c b/c/src/lib/libbsp/powerpc/beatnik/startup/reboot.c
new file mode 100644
index 0000000000..0e6af195f4
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/beatnik/startup/reboot.c
@@ -0,0 +1,16 @@
+#include <rtems.h>
+#include <bsp.h>
+#include <rtems/bspIo.h>
+#include <libcpu/io.h>
+#include <libcpu/stackTrace.h>
+
+void bsp_reset()
+{
+
+ printk("Printing a stack trace for your convenience :-)\n");
+ CPU_print_stack();
+
+ printk("RTEMS terminated; Rebooting ...\n");
+ /* Mvme5500 board reset : 2004 S. Kate Feng <feng1@bnl.gov> */
+ out_8((volatile unsigned char*) (BSP_MV64x60_DEV1_BASE +2), 0x80);
+}
diff --git a/c/src/lib/libbsp/powerpc/beatnik/tod/todcfg.c b/c/src/lib/libbsp/powerpc/beatnik/tod/todcfg.c
new file mode 100644
index 0000000000..10f123b27f
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/beatnik/tod/todcfg.c
@@ -0,0 +1,36 @@
+/*
+ * This file contains the RTC driver table for Motorola shared BSPs.
+ *
+ * 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 <bsp.h>
+#include <libchip/rtc.h>
+#include <libchip/m48t08.h>
+
+/* The following table configures the RTC drivers used in this BSP */
+rtc_tbl RTC_Table[] = {
+ {
+ "/dev/rtc", /* sDeviceName */
+ RTC_M48T08, /* deviceType */
+ &m48t08_fns, /* pDeviceFns */
+ rtc_probe, /* deviceProbe */
+ NULL, /* pDeviceParams */
+ BSP_NVRAM_RTC_START, /* ulCtrlPort1 */
+ 0x00, /* ulDataPort */
+ m48t08_get_register, /* getRegister */
+ m48t08_set_register /* setRegister */
+ }
+};
+
+/* 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/beatnik/vme/VMEConfig.h b/c/src/lib/libbsp/powerpc/beatnik/vme/VMEConfig.h
new file mode 100644
index 0000000000..5d3364473e
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/beatnik/vme/VMEConfig.h
@@ -0,0 +1,112 @@
+#ifndef RTEMS_BSP_VME_CONFIG_H
+#define RTEMS_BSP_VME_CONFIG_H
+/* $Id$ */
+
+/* BSP specific address space configuration parameters */
+
+/*
+ * Authorship
+ * ----------
+ * This software ('beatnik' RTEMS BSP for MVME6100 and MVME5500) was
+ * created by Till Straumann <strauman@slac.stanford.edu>, 2005-2007,
+ * Stanford Linear Accelerator Center, Stanford University.
+ *
+ * Acknowledgement of sponsorship
+ * ------------------------------
+ * The 'beatnik' 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
+ */
+
+#define _VME_DRIVER_TSI148
+#define _VME_DRIVER_UNIVERSE
+
+/*
+ * NOTE: the BSP (startup/bspstart.c) uses
+ * hardcoded window lengths that match this
+ * layout when setting BATs:
+ */
+#define _VME_A32_WIN0_ON_PCI 0x90000000
+/* If _VME_CSR_ON_PCI is defined then the A32 window is reduced to accommodate
+ * CSR for space.
+ */
+#define _VME_CSR_ON_PCI 0x9e000000
+#define _VME_A24_ON_PCI 0x9f000000
+#define _VME_A16_ON_PCI 0x9fff0000
+
+/* start of the A32 window on the VME bus
+ * TODO: this should perhaps be a configuration option
+ */
+#define _VME_A32_WIN0_ON_VME 0x20000000
+
+/* if _VME_DRAM_OFFSET is defined, the BSP
+ * will map our RAM onto the VME bus, starting
+ * at _VME_DRAM_OFFSET
+ */
+#define _VME_DRAM_OFFSET 0x90000000
+
+#define BSP_VME_INSTALL_IRQ_MGR(err) \
+ do { \
+ err = -1; \
+ switch (BSP_getBoardType()) { \
+ case MVME6100: \
+ err = theOps->install_irq_mgr( \
+ VMETSI148_IRQ_MGR_FLAG_SHARED, \
+ 0, BSP_IRQ_GPP_0 + 20, \
+ 1, BSP_IRQ_GPP_0 + 21, \
+ 2, BSP_IRQ_GPP_0 + 22, \
+ 3, BSP_IRQ_GPP_0 + 23, \
+ -1); \
+ break; \
+ \
+ case MVME5500: \
+ err = theOps->install_irq_mgr( \
+ VMEUNIVERSE_IRQ_MGR_FLAG_SHARED | \
+ VMEUNIVERSE_IRQ_MGR_FLAG_PW_WORKAROUND, \
+ 0, BSP_IRQ_GPP_0 + 12, \
+ 1, BSP_IRQ_GPP_0 + 13, \
+ 2, BSP_IRQ_GPP_0 + 14, \
+ 3, BSP_IRQ_GPP_0 + 15, \
+ -1); \
+ break; \
+ \
+ default: \
+ printk("WARNING: unknown board; "); \
+ break; \
+ } \
+ if ( err ) \
+ printk("VME interrupt manager NOT INSTALLED (error: %i)\n", err); \
+ } while (0)
+
+#endif
diff --git a/c/src/lib/libbsp/powerpc/beatnik/vme/vme_dma.c b/c/src/lib/libbsp/powerpc/beatnik/vme/vme_dma.c
new file mode 100644
index 0000000000..368bf4c844
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/beatnik/vme/vme_dma.c
@@ -0,0 +1,217 @@
+/* $Id$ */
+
+/* Setup/glue to attach VME DMA driver to the beatnik BSP */
+
+/*
+ * Authorship
+ * ----------
+ * This software ('beatnik' RTEMS BSP for MVME6100 and MVME5500) was
+ * created by Till Straumann <strauman@slac.stanford.edu>, 2005-2007,
+ * Stanford Linear Accelerator Center, Stanford University.
+ *
+ * Acknowledgement of sponsorship
+ * ------------------------------
+ * The 'beatnik' 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 <stdio.h>
+#include <stdint.h>
+#include <rtems.h>
+#include <bsp.h>
+#include <bsp/VME.h>
+#include <bsp/vmeTsi148.h>
+#include <bsp/vmeUniverse.h>
+#include <bsp/VMEDMA.h>
+#include <bsp/vmeTsi148DMA.h>
+#include <bsp/vmeUniverseDMA.h>
+#include <bsp/bspVmeDmaList.h>
+
+typedef struct DmaOpsRec_ {
+ int (*setup)(int, uint32_t, uint32_t, void *);
+ int (*start)(int, uint32_t, uint32_t, uint32_t);
+ uint32_t (*status)(int);
+ VMEDmaListClass listClass;
+} DmaOpsRec, *DmaOps;
+
+static DmaOpsRec universeOps = {
+ vmeUniverseDmaSetup,
+ vmeUniverseDmaStart,
+ vmeUniverseDmaStatus,
+ &vmeUniverseDmaListClass,
+};
+
+static DmaOpsRec tsiOps = {
+ vmeTsi148DmaSetup,
+ vmeTsi148DmaStart,
+ vmeTsi148DmaStatus,
+ &vmeTsi148DmaListClass,
+};
+
+static int setup(int a, uint32_t b, uint32_t c, void *d);
+static int start(int a, uint32_t b, uint32_t c, uint32_t d);
+static uint32_t status(int a);
+
+static DmaOpsRec jumpstartOps = {
+ setup,
+ start,
+ status,
+ 0
+};
+
+static DmaOps dmaOps = &jumpstartOps;
+
+static DmaOps selectOps()
+{
+ return (MVME6100 != BSP_getBoardType()) ?
+ &universeOps : &tsiOps;
+}
+
+static int
+setup(int a, uint32_t b, uint32_t c, void *d)
+{
+ return (dmaOps=selectOps())->setup(a,b,c,d);
+}
+
+static int
+start(int a, uint32_t b, uint32_t c, uint32_t d)
+{
+ return (dmaOps=selectOps())->start(a,b,c,d);
+}
+
+static uint32_t
+status(int a)
+{
+ return (dmaOps=selectOps())->status(a);
+}
+
+
+int
+BSP_VMEDmaSetup(int channel, uint32_t bus_mode, uint32_t xfer_mode, void *custom_setup)
+{
+ return dmaOps->setup(channel, bus_mode, xfer_mode, custom_setup);
+}
+
+int
+BSP_VMEDmaStart(int channel, uint32_t pci_addr, uint32_t vme_addr, uint32_t n_bytes)
+{
+ return dmaOps->start(channel, pci_addr, vme_addr, n_bytes);
+}
+
+uint32_t
+BSP_VMEDmaStatus(int channel)
+{
+ return dmaOps->status(channel);
+}
+
+BSP_VMEDmaListDescriptor
+BSP_VMEDmaListDescriptorSetup(
+ BSP_VMEDmaListDescriptor d,
+ uint32_t attr_mask,
+ uint32_t xfer_mode,
+ uint32_t pci_addr,
+ uint32_t vme_addr,
+ uint32_t n_bytes)
+{
+VMEDmaListClass pc;
+ if ( !d ) {
+ if ( ! (pc = dmaOps->listClass) ) {
+ pc = (dmaOps = selectOps())->listClass;
+ }
+ return BSP_VMEDmaListDescriptorNewTool(
+ pc,
+ attr_mask,
+ xfer_mode,
+ pci_addr,
+ vme_addr,
+ n_bytes);
+
+ }
+ return BSP_VMEDmaListDescriptorSetupTool(d, attr_mask, xfer_mode, pci_addr, vme_addr, n_bytes);
+}
+
+int
+BSP_VMEDmaListStart(int channel, BSP_VMEDmaListDescriptor list)
+{
+ return BSP_VMEDmaListDescriptorStartTool(0, channel, list);
+}
+
+/* NOT thread safe! */
+int
+BSP_VMEDmaInstallISR(int channel, BSP_VMEDmaIRQCallback cb, void *usr_arg)
+{
+int vec;
+BSP_VME_ISR_t curr;
+void *carg;
+
+ if ( MVME6100 != BSP_getBoardType() ) {
+ if ( channel != 0 )
+ return -1;
+
+ vec = UNIV_DMA_INT_VEC;
+
+ } else {
+ if ( channel < 0 || channel > 1 )
+ return -1;
+
+ vec = (channel ? TSI_DMA1_INT_VEC : TSI_DMA_INT_VEC );
+ }
+
+ curr = BSP_getVME_isr(vec, &carg);
+
+ if ( cb && curr ) {
+ /* IRQ currently in use */
+ return -1;
+ }
+
+ if ( !cb && !curr ) {
+ /* Allow uninstall if no handler is currently installed;
+ * just make sure IRQ is disabled
+ */
+ BSP_disableVME_int_lvl(vec);
+ return 0;
+ }
+
+ if ( cb ) {
+ if ( BSP_installVME_isr(vec, (BSP_VME_ISR_t)cb, usr_arg) )
+ return -4;
+ BSP_enableVME_int_lvl(vec);
+ } else {
+ BSP_disableVME_int_lvl(vec);
+ if ( BSP_removeVME_isr(vec, curr, carg) )
+ return -4;
+ }
+ return 0;
+}
diff --git a/c/src/lib/libbsp/powerpc/beatnik/vme/vmeconfig.c b/c/src/lib/libbsp/powerpc/beatnik/vme/vmeconfig.c
new file mode 100644
index 0000000000..577ef8011b
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/beatnik/vme/vmeconfig.c
@@ -0,0 +1,305 @@
+/* $Id$ */
+
+/* Standard VME bridge configuration for MVME5500, MVME6100 */
+
+/*
+ * Authorship
+ * ----------
+ * This software ('beatnik' RTEMS BSP for MVME6100 and MVME5500) was
+ * created by Till Straumann <strauman@slac.stanford.edu>, 2005-2007,
+ * Stanford Linear Accelerator Center, Stanford University.
+ *
+ * Acknowledgement of sponsorship
+ * ------------------------------
+ * The 'beatnik' 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/bspIo.h>
+#include <bsp.h>
+#include <bsp/VME.h>
+#include <bsp/VMEConfig.h>
+#include <bsp/irq.h>
+#include <bsp/vmeUniverse.h>
+#define _VME_TSI148_DECLARE_SHOW_ROUTINES
+#include <bsp/vmeTsi148.h>
+#include <libcpu/bat.h>
+
+/* Use a weak alias for the VME configuration.
+ * This permits individual applications to override
+ * this routine.
+ * They may even create an 'empty'
+ *
+ * void BSP_vme_config(void) {}
+ *
+ * which will avoid linking in the Universe driver
+ * at all :-).
+ */
+
+void BSP_vme_config(void) __attribute__ (( weak, alias("__BSP_default_vme_config") ));
+
+typedef struct {
+ int (*xlate_adrs)(int, int, unsigned long, unsigned long, unsigned long *);
+ int (*install_isr)(unsigned long, BSP_VME_ISR_t, void *);
+ int (*remove_isr)(unsigned long, BSP_VME_ISR_t, void *);
+ BSP_VME_ISR_t (*get_isr)(unsigned long vector, void **);
+ int (*enable_int_lvl)(unsigned int);
+ int (*disable_int_lvl)(unsigned int);
+ int (*outbound_p_cfg)(unsigned long, unsigned long, unsigned long, unsigned long, unsigned long);
+ int (*inbound_p_cfg) (unsigned long, unsigned long, unsigned long, unsigned long, unsigned long);
+ void (*outbound_p_show)(FILE*);
+ void (*inbound_p_show) (FILE*);
+ void (*reset_bus)(void);
+ int (*install_irq_mgr)(int, int, int, ...);
+} VMEOpsRec, *VMEOps;
+
+static VMEOpsRec uniOpsRec = {
+ xlate_adrs: vmeUniverseXlateAddr,
+ install_isr: vmeUniverseInstallISR,
+ remove_isr: vmeUniverseRemoveISR,
+ get_isr: vmeUniverseISRGet,
+ enable_int_lvl: vmeUniverseIntEnable,
+ disable_int_lvl: vmeUniverseIntDisable,
+ outbound_p_cfg: vmeUniverseMasterPortCfg,
+ inbound_p_cfg: vmeUniverseSlavePortCfg,
+ outbound_p_show: vmeUniverseMasterPortsShow,
+ inbound_p_show: vmeUniverseSlavePortsShow,
+ reset_bus: vmeUniverseResetBus,
+ install_irq_mgr: vmeUniverseInstallIrqMgrAlt,
+};
+
+static VMEOpsRec tsiOpsRec = {
+ xlate_adrs: vmeTsi148XlateAddr,
+ install_isr: vmeTsi148InstallISR,
+ remove_isr: vmeTsi148RemoveISR,
+ get_isr: vmeTsi148ISRGet,
+ enable_int_lvl: vmeTsi148IntEnable,
+ disable_int_lvl: vmeTsi148IntDisable,
+ outbound_p_cfg: vmeTsi148OutboundPortCfg,
+ inbound_p_cfg: vmeTsi148InboundPortCfg,
+ outbound_p_show: vmeTsi148OutboundPortsShow,
+ inbound_p_show: vmeTsi148InboundPortsShow,
+ reset_bus: vmeTsi148ResetBus,
+ install_irq_mgr: vmeTsi148InstallIrqMgrAlt,
+};
+
+static VMEOps theOps = 0;
+
+int
+BSP_vme2local_adrs(unsigned long am, unsigned long vmeaddr, unsigned long *plocaladdr)
+{
+int rval=theOps->xlate_adrs(1,0,am,vmeaddr,plocaladdr);
+ *plocaladdr+=PCI_MEM_BASE;
+ return rval;
+}
+
+int
+BSP_local2vme_adrs(unsigned long am, unsigned long localaddr, unsigned long *pvmeaddr)
+{
+ return theOps->xlate_adrs(0, 0, am,localaddr+PCI_DRAM_OFFSET,pvmeaddr);
+}
+
+int
+BSP_installVME_isr(unsigned long vector, BSP_VME_ISR_t handler, void *arg)
+{
+ return theOps->install_isr(vector, handler, arg);
+}
+
+int
+BSP_removeVME_isr(unsigned long vector, BSP_VME_ISR_t handler, void *arg)
+{
+ return theOps->remove_isr(vector, handler, arg);
+}
+
+/* retrieve the currently installed ISR for a given vector */
+BSP_VME_ISR_t
+BSP_getVME_isr(unsigned long vector, void **parg)
+{
+ return theOps->get_isr(vector, parg);
+}
+
+int
+BSP_enableVME_int_lvl(unsigned int level)
+{
+ return theOps->enable_int_lvl(level);
+}
+
+int
+BSP_disableVME_int_lvl(unsigned int level)
+{
+ return theOps->disable_int_lvl(level);
+}
+
+int
+BSP_VMEOutboundPortCfg(
+ unsigned long port,
+ unsigned long address_space,
+ unsigned long vme_address,
+ unsigned long pci_address,
+ unsigned long size)
+{
+ return theOps->outbound_p_cfg(port, address_space, vme_address, pci_address, size);
+}
+
+int
+BSP_VMEInboundPortCfg(
+ unsigned long port,
+ unsigned long address_space,
+ unsigned long vme_address,
+ unsigned long pci_address,
+ unsigned long size)
+{
+ return theOps->inbound_p_cfg(port, address_space, vme_address, pci_address, size);
+}
+
+void
+BSP_VMEOutboundPortsShow(FILE *f)
+{
+ theOps->outbound_p_show(f);
+}
+
+void
+BSP_VMEInboundPortsShow(FILE *f)
+{
+ theOps->inbound_p_show(f);
+}
+
+void
+BSP_VMEResetBus(void)
+{
+ theOps->reset_bus();
+}
+
+static unsigned short
+tsi_clear_errors(int quiet)
+{
+unsigned long v;
+unsigned short rval;
+ v = vmeTsi148ClearVMEBusErrors(0);
+
+ /* return bits 8..23 of VEAT; set bit 15 to make sure rval is nonzero on error */
+ rval = v ? ((v>>8) & 0xffff) | (1<<15) : 0;
+ return rval;
+}
+
+void
+__BSP_default_vme_config(void)
+{
+int err = 1;
+ if ( 0 == vmeUniverseInit() ) {
+ theOps = &uniOpsRec;
+ vmeUniverseReset();
+ } else if ( 0 == vmeTsi148Init() ) {
+ theOps = &tsiOpsRec;
+ vmeTsi148Reset();
+ _BSP_clear_vmebridge_errors = tsi_clear_errors;
+ } else
+ return; /* no VME bridge found chip */
+
+ /* map VME address ranges */
+ BSP_VMEOutboundPortCfg(
+ 0,
+ VME_AM_EXT_SUP_DATA,
+ _VME_A32_WIN0_ON_VME,
+ _VME_A32_WIN0_ON_PCI,
+ 0x0e000000
+ );
+ BSP_VMEOutboundPortCfg(
+ 1,
+ VME_AM_STD_SUP_DATA,
+ 0x00000000,
+ _VME_A24_ON_PCI,
+ 0x00ff0000);
+ BSP_VMEOutboundPortCfg(
+ 2,
+ VME_AM_SUP_SHORT_IO,
+ 0x00000000,
+ _VME_A16_ON_PCI,
+ 0x00010000);
+
+#ifdef _VME_CSR_ON_PCI
+ /* Map VME64 CSR */
+ BSP_VMEOutboundPortCfg(
+ 7,
+ VME_AM_CSR,
+ 0,
+ _VME_CSR_ON_PCI,
+ 0x01000000);
+#endif
+
+#ifdef _VME_DRAM_OFFSET
+ /* map our memory to VME */
+ BSP_VMEInboundPortCfg(
+ 0,
+ VME_AM_EXT_SUP_DATA | VME_AM_IS_MEMORY,
+ _VME_DRAM_OFFSET,
+ PCI_DRAM_OFFSET,
+ BSP_mem_size);
+#endif
+
+ /* stdio is not yet initialized; the driver will revert to printk */
+ BSP_VMEOutboundPortsShow(0);
+ BSP_VMEInboundPortsShow(0);
+
+ switch (BSP_getBoardType()) {
+ case MVME6100:
+ err = theOps->install_irq_mgr(
+ VMETSI148_IRQ_MGR_FLAG_SHARED,
+ 0, BSP_IRQ_GPP_0 + 20,
+ 1, BSP_IRQ_GPP_0 + 21,
+ 2, BSP_IRQ_GPP_0 + 22,
+ 3, BSP_IRQ_GPP_0 + 23,
+ -1);
+ break;
+
+ case MVME5500:
+ err = theOps->install_irq_mgr(
+ VMEUNIVERSE_IRQ_MGR_FLAG_SHARED |
+ VMEUNIVERSE_IRQ_MGR_FLAG_PW_WORKAROUND,
+ 0, BSP_IRQ_GPP_0 + 12,
+ 1, BSP_IRQ_GPP_0 + 13,
+ 2, BSP_IRQ_GPP_0 + 14,
+ 3, BSP_IRQ_GPP_0 + 15,
+ -1);
+ break;
+
+ default:
+ printk("WARNING: unknown board; ");
+ break;
+ }
+ if ( err )
+ printk("VME interrupt manager NOT INSTALLED (error: %i)\n", err);
+}