summaryrefslogtreecommitdiffstats
path: root/src/roms/SLOF/lib
diff options
context:
space:
mode:
Diffstat (limited to 'src/roms/SLOF/lib')
-rw-r--r--src/roms/SLOF/lib/Makefile35
-rw-r--r--src/roms/SLOF/lib/libbases/Makefile40
-rw-r--r--src/roms/SLOF/lib/libbases/libbases.code43
-rw-r--r--src/roms/SLOF/lib/libbases/libbases.in17
-rw-r--r--src/roms/SLOF/lib/libbcm/Makefile53
-rw-r--r--src/roms/SLOF/lib/libbcm/bcm.code57
-rw-r--r--src/roms/SLOF/lib/libbcm/bcm.in20
-rw-r--r--src/roms/SLOF/lib/libbcm/bcm57xx.c3461
-rw-r--r--src/roms/SLOF/lib/libbcm/bcm57xx.h323
-rw-r--r--src/roms/SLOF/lib/libbootmsg/Makefile75
-rw-r--r--src/roms/SLOF/lib/libbootmsg/bootmsg.code61
-rw-r--r--src/roms/SLOF/lib/libbootmsg/bootmsg.in19
-rw-r--r--src/roms/SLOF/lib/libbootmsg/bootmsg_lvl.S204
-rw-r--r--src/roms/SLOF/lib/libbootmsg/libbootmsg.h21
-rw-r--r--src/roms/SLOF/lib/libc/Makefile61
-rw-r--r--src/roms/SLOF/lib/libc/README.txt49
-rw-r--r--src/roms/SLOF/lib/libc/ctype/Makefile.inc20
-rw-r--r--src/roms/SLOF/lib/libc/ctype/isdigit.c25
-rw-r--r--src/roms/SLOF/lib/libc/ctype/isprint.c18
-rw-r--r--src/roms/SLOF/lib/libc/ctype/isspace.c29
-rw-r--r--src/roms/SLOF/lib/libc/ctype/isxdigit.c21
-rw-r--r--src/roms/SLOF/lib/libc/ctype/tolower.c18
-rw-r--r--src/roms/SLOF/lib/libc/ctype/toupper.c21
-rw-r--r--src/roms/SLOF/lib/libc/getopt/Makefile.inc17
-rw-r--r--src/roms/SLOF/lib/libc/getopt/getopt.c470
-rw-r--r--src/roms/SLOF/lib/libc/include/ctype.h24
-rw-r--r--src/roms/SLOF/lib/libc/include/errno.h34
-rw-r--r--src/roms/SLOF/lib/libc/include/getopt.h37
-rw-r--r--src/roms/SLOF/lib/libc/include/limits.h32
-rw-r--r--src/roms/SLOF/lib/libc/include/stdarg.h22
-rw-r--r--src/roms/SLOF/lib/libc/include/stdbool.h20
-rw-r--r--src/roms/SLOF/lib/libc/include/stddef.h25
-rw-r--r--src/roms/SLOF/lib/libc/include/stdint.h28
-rw-r--r--src/roms/SLOF/lib/libc/include/stdio.h63
-rw-r--r--src/roms/SLOF/lib/libc/include/stdlib.h33
-rw-r--r--src/roms/SLOF/lib/libc/include/string.h37
-rw-r--r--src/roms/SLOF/lib/libc/include/unistd.h28
-rw-r--r--src/roms/SLOF/lib/libc/stdio/Makefile.inc23
-rw-r--r--src/roms/SLOF/lib/libc/stdio/fileno.c19
-rw-r--r--src/roms/SLOF/lib/libc/stdio/fprintf.c26
-rw-r--r--src/roms/SLOF/lib/libc/stdio/fscanf.c26
-rw-r--r--src/roms/SLOF/lib/libc/stdio/printf.c27
-rw-r--r--src/roms/SLOF/lib/libc/stdio/putc.c25
-rw-r--r--src/roms/SLOF/lib/libc/stdio/putchar.c21
-rw-r--r--src/roms/SLOF/lib/libc/stdio/puts.c28
-rw-r--r--src/roms/SLOF/lib/libc/stdio/scanf.c26
-rw-r--r--src/roms/SLOF/lib/libc/stdio/setvbuf.c28
-rw-r--r--src/roms/SLOF/lib/libc/stdio/sprintf.c30
-rw-r--r--src/roms/SLOF/lib/libc/stdio/stdchnls.c23
-rw-r--r--src/roms/SLOF/lib/libc/stdio/vfprintf.c27
-rw-r--r--src/roms/SLOF/lib/libc/stdio/vfscanf.c266
-rw-r--r--src/roms/SLOF/lib/libc/stdio/vsnprintf.c242
-rw-r--r--src/roms/SLOF/lib/libc/stdio/vsprintf.c19
-rw-r--r--src/roms/SLOF/lib/libc/stdio/vsscanf.c131
-rw-r--r--src/roms/SLOF/lib/libc/stdlib/Makefile.inc22
-rw-r--r--src/roms/SLOF/lib/libc/stdlib/atoi.c18
-rw-r--r--src/roms/SLOF/lib/libc/stdlib/atol.c18
-rw-r--r--src/roms/SLOF/lib/libc/stdlib/error.c15
-rw-r--r--src/roms/SLOF/lib/libc/stdlib/free.c26
-rw-r--r--src/roms/SLOF/lib/libc/stdlib/malloc.c157
-rw-r--r--src/roms/SLOF/lib/libc/stdlib/malloc_defs.h16
-rw-r--r--src/roms/SLOF/lib/libc/stdlib/memalign.c26
-rw-r--r--src/roms/SLOF/lib/libc/stdlib/rand.c24
-rw-r--r--src/roms/SLOF/lib/libc/stdlib/realloc.c40
-rw-r--r--src/roms/SLOF/lib/libc/stdlib/strtol.c115
-rw-r--r--src/roms/SLOF/lib/libc/stdlib/strtoul.c105
-rw-r--r--src/roms/SLOF/lib/libc/string/Makefile.inc22
-rw-r--r--src/roms/SLOF/lib/libc/string/memchr.c29
-rw-r--r--src/roms/SLOF/lib/libc/string/memcmp.c30
-rw-r--r--src/roms/SLOF/lib/libc/string/memcpy.c27
-rw-r--r--src/roms/SLOF/lib/libc/string/memmove.c42
-rw-r--r--src/roms/SLOF/lib/libc/string/memset.c25
-rw-r--r--src/roms/SLOF/lib/libc/string/strcasecmp.c28
-rw-r--r--src/roms/SLOF/lib/libc/string/strcat.c24
-rw-r--r--src/roms/SLOF/lib/libc/string/strchr.c28
-rw-r--r--src/roms/SLOF/lib/libc/string/strcmp.c28
-rw-r--r--src/roms/SLOF/lib/libc/string/strcpy.c25
-rw-r--r--src/roms/SLOF/lib/libc/string/strlen.c27
-rw-r--r--src/roms/SLOF/lib/libc/string/strncasecmp.c32
-rw-r--r--src/roms/SLOF/lib/libc/string/strncmp.c31
-rw-r--r--src/roms/SLOF/lib/libc/string/strncpy.c33
-rw-r--r--src/roms/SLOF/lib/libc/string/strstr.c37
-rw-r--r--src/roms/SLOF/lib/libc/string/strtok.c45
-rw-r--r--src/roms/SLOF/lib/libe1k/Makefile51
-rw-r--r--src/roms/SLOF/lib/libe1k/e1k.c1000
-rw-r--r--src/roms/SLOF/lib/libe1k/e1k.code75
-rw-r--r--src/roms/SLOF/lib/libe1k/e1k.h108
-rw-r--r--src/roms/SLOF/lib/libe1k/e1k.in21
-rw-r--r--src/roms/SLOF/lib/libelf/Makefile47
-rw-r--r--src/roms/SLOF/lib/libelf/elf.c190
-rw-r--r--src/roms/SLOF/lib/libelf/elf32.c193
-rw-r--r--src/roms/SLOF/lib/libelf/elf64.c473
-rw-r--r--src/roms/SLOF/lib/libelf/elf_claim.c28
-rw-r--r--src/roms/SLOF/lib/libelf/libelf.code43
-rw-r--r--src/roms/SLOF/lib/libelf/libelf.in18
-rw-r--r--src/roms/SLOF/lib/libhvcall/Makefile57
-rw-r--r--src/roms/SLOF/lib/libhvcall/brokensc1.c162
-rw-r--r--src/roms/SLOF/lib/libhvcall/hvcall.S134
-rw-r--r--src/roms/SLOF/lib/libhvcall/hvcall.code131
-rw-r--r--src/roms/SLOF/lib/libhvcall/hvcall.in34
-rw-r--r--src/roms/SLOF/lib/libhvcall/libhvcall.h107
-rw-r--r--src/roms/SLOF/lib/libipmi/Makefile28
-rw-r--r--src/roms/SLOF/lib/libipmi/libipmi.code120
-rw-r--r--src/roms/SLOF/lib/libipmi/libipmi.h33
-rw-r--r--src/roms/SLOF/lib/libipmi/libipmi.in24
-rw-r--r--src/roms/SLOF/lib/libipmi/libipmi.ocobin0 -> 104462 bytes
-rw-r--r--src/roms/SLOF/lib/libnativeio/nativeio.code25
-rw-r--r--src/roms/SLOF/lib/libnativeio/nativeio.in22
-rw-r--r--src/roms/SLOF/lib/libnvram/Makefile53
-rw-r--r--src/roms/SLOF/lib/libnvram/envvar.c243
-rw-r--r--src/roms/SLOF/lib/libnvram/libnvram.code287
-rw-r--r--src/roms/SLOF/lib/libnvram/libnvram.in42
-rw-r--r--src/roms/SLOF/lib/libnvram/nvram.c623
-rw-r--r--src/roms/SLOF/lib/libnvram/nvram.h73
-rw-r--r--src/roms/SLOF/lib/libusb/Makefile52
-rw-r--r--src/roms/SLOF/lib/libusb/tools.h77
-rw-r--r--src/roms/SLOF/lib/libusb/usb-core.c590
-rw-r--r--src/roms/SLOF/lib/libusb/usb-core.h279
-rw-r--r--src/roms/SLOF/lib/libusb/usb-ehci.c609
-rw-r--r--src/roms/SLOF/lib/libusb/usb-ehci.h155
-rw-r--r--src/roms/SLOF/lib/libusb/usb-hid.c468
-rw-r--r--src/roms/SLOF/lib/libusb/usb-hub.c183
-rw-r--r--src/roms/SLOF/lib/libusb/usb-key.c446
-rw-r--r--src/roms/SLOF/lib/libusb/usb-key.h42
-rw-r--r--src/roms/SLOF/lib/libusb/usb-ohci.c1055
-rw-r--r--src/roms/SLOF/lib/libusb/usb-ohci.h217
-rw-r--r--src/roms/SLOF/lib/libusb/usb-slof.c61
-rw-r--r--src/roms/SLOF/lib/libusb/usb-xhci.c1488
-rw-r--r--src/roms/SLOF/lib/libusb/usb-xhci.h391
-rw-r--r--src/roms/SLOF/lib/libusb/usb.code162
-rw-r--r--src/roms/SLOF/lib/libusb/usb.h77
-rw-r--r--src/roms/SLOF/lib/libusb/usb.in29
-rw-r--r--src/roms/SLOF/lib/libveth/Makefile52
-rw-r--r--src/roms/SLOF/lib/libveth/veth.c273
-rw-r--r--src/roms/SLOF/lib/libveth/veth.code61
-rw-r--r--src/roms/SLOF/lib/libveth/veth.h24
-rw-r--r--src/roms/SLOF/lib/libveth/veth.in20
-rw-r--r--src/roms/SLOF/lib/libvirtio/Makefile55
-rw-r--r--src/roms/SLOF/lib/libvirtio/p9.c575
-rw-r--r--src/roms/SLOF/lib/libvirtio/p9.h68
-rw-r--r--src/roms/SLOF/lib/libvirtio/virtio-9p.c336
-rw-r--r--src/roms/SLOF/lib/libvirtio/virtio-9p.h32
-rw-r--r--src/roms/SLOF/lib/libvirtio/virtio-blk.c185
-rw-r--r--src/roms/SLOF/lib/libvirtio/virtio-blk.h60
-rw-r--r--src/roms/SLOF/lib/libvirtio/virtio-net.c369
-rw-r--r--src/roms/SLOF/lib/libvirtio/virtio-net.h43
-rw-r--r--src/roms/SLOF/lib/libvirtio/virtio-scsi.c145
-rw-r--r--src/roms/SLOF/lib/libvirtio/virtio-scsi.h69
-rw-r--r--src/roms/SLOF/lib/libvirtio/virtio.c241
-rw-r--r--src/roms/SLOF/lib/libvirtio/virtio.code164
-rw-r--r--src/roms/SLOF/lib/libvirtio/virtio.h90
-rw-r--r--src/roms/SLOF/lib/libvirtio/virtio.in33
152 files changed, 21364 insertions, 0 deletions
diff --git a/src/roms/SLOF/lib/Makefile b/src/roms/SLOF/lib/Makefile
new file mode 100644
index 0000000..ed8a359
--- /dev/null
+++ b/src/roms/SLOF/lib/Makefile
@@ -0,0 +1,35 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2008 IBM Corporation
+# * All rights reserved.
+# * This program and the accompanying materials
+# * are made available under the terms of the BSD License
+# * which accompanies this distribution, and is available at
+# * http://www.opensource.org/licenses/bsd-license.php
+# *
+# * Contributors:
+# * IBM Corporation - initial implementation
+# ****************************************************************************/
+
+SUBDIRS = libc libipmi libbootmsg libbases libnvram libelf libhvcall libvirtio \
+ libusb libveth libe1k libbcm
+
+all: subdirs
+
+.PHONY : subdirs $(SUBDIRS) clean distclean
+
+
+subdirs: $(SUBDIRS)
+
+$(SUBDIRS):
+ $(MAKE) -C $@ $(MAKEARG)
+
+# Rules for making clean:
+clean:
+ @for dir in $(SUBDIRS); do \
+ $(MAKE) -C $$dir clean || exit 1; \
+ done
+
+distclean:
+ @for dir in $(SUBDIRS); do \
+ $(MAKE) -C $$dir distclean || exit 1; \
+ done
diff --git a/src/roms/SLOF/lib/libbases/Makefile b/src/roms/SLOF/lib/libbases/Makefile
new file mode 100644
index 0000000..add4ed1
--- /dev/null
+++ b/src/roms/SLOF/lib/libbases/Makefile
@@ -0,0 +1,40 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2008 IBM Corporation
+# * All rights reserved.
+# * This program and the accompanying materials
+# * are made available under the terms of the BSD License
+# * which accompanies this distribution, and is available at
+# * http://www.opensource.org/licenses/bsd-license.php
+# *
+# * Contributors:
+# * IBM Corporation - initial implementation
+# ****************************************************************************/
+
+TOPCMNDIR ?= ../..
+
+include $(TOPCMNDIR)/make.rules
+
+ASFLAGS = $(FLAG) $(RELEASE) $(CPUARCHDEF) -Wa,-mregnames
+CPPFLAGS = -I../libc/include $(CPUARCHDEF) -I$(INCLBRDDIR) -I. -I../../include
+LDFLAGS = -nostdlib
+
+all:
+
+clean:
+ $(RM) $(TARGET) $(OBJS)
+
+distclean: clean
+ $(RM) Makefile.dep
+
+
+# Rules for creating the dependency file:
+depend:
+ $(RM) Makefile.dep
+ $(MAKE) Makefile.dep
+
+Makefile.dep: Makefile
+
+
+# Include dependency file if available:
+-include Makefile.dep
+
diff --git a/src/roms/SLOF/lib/libbases/libbases.code b/src/roms/SLOF/lib/libbases/libbases.code
new file mode 100644
index 0000000..128b94a
--- /dev/null
+++ b/src/roms/SLOF/lib/libbases/libbases.code
@@ -0,0 +1,43 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+#include <southbridge.h>
+#include <nvram.h>
+
+// : get-nvram-base ( -- base )
+PRIM(get_X2d_nvram_X2d_base)
+ PUSH;
+ TOS.u = SB_NVRAM_adr;
+MIRP
+
+// : get-nvram-size ( -- size )
+PRIM(get_X2d_nvram_X2d_size)
+ PUSH;
+ TOS.u = get_nvram_size();
+MIRP
+
+// : get-flash-base ( -- base )
+PRIM(get_X2d_flash_X2d_base)
+ PUSH;
+ TOS.u = SB_FLASH_adr;
+MIRP
+
+// : get-flash-size ( -- size )
+PRIM(get_X2d_flash_X2d_size)
+ PUSH;
+ TOS.u = FLASH_LENGTH;
+MIRP
+
+// : get-mbx-base ( -- base )
+PRIM(get_X2d_mbx_X2d_base)
+ PUSH;
+ TOS.u = SB_MAILBOX_adr;
+MIRP
diff --git a/src/roms/SLOF/lib/libbases/libbases.in b/src/roms/SLOF/lib/libbases/libbases.in
new file mode 100644
index 0000000..844a55d
--- /dev/null
+++ b/src/roms/SLOF/lib/libbases/libbases.in
@@ -0,0 +1,17 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+cod(get-nvram-base)
+cod(get-nvram-size)
+cod(get-flash-base)
+cod(get-flash-size)
+cod(get-mbx-base)
diff --git a/src/roms/SLOF/lib/libbcm/Makefile b/src/roms/SLOF/lib/libbcm/Makefile
new file mode 100644
index 0000000..1aead4c
--- /dev/null
+++ b/src/roms/SLOF/lib/libbcm/Makefile
@@ -0,0 +1,53 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2008, 2013 IBM Corporation
+# * All rights reserved.
+# * This program and the accompanying materials
+# * are made available under the terms of the BSD License
+# * which accompanies this distribution, and is available at
+# * http://www.opensource.org/licenses/bsd-license.php
+# *
+# * Contributors:
+# * IBM Corporation - initial implementation
+# ****************************************************************************/
+
+TOPCMNDIR ?= ../..
+
+include $(TOPCMNDIR)/make.rules
+
+CPPFLAGS = -I../libc/include $(CPUARCHDEF) -I$(INCLBRDDIR) \
+ -I$(INCLCMNDIR) -I$(INCLCMNDIR)/$(CPUARCH)
+
+#CFLAGS += -O2 -I. -I../common -I$(TOP)/clients/net-snk/include -I$(TOP)/lib/libc/include -fno-builtin -ffreestanding -msoft-float -Wall -nostdinc
+
+LDFLAGS = -nostdlib
+
+TARGET = ../libbcm.a
+
+
+all: $(TARGET) Makefile.dep
+
+SRCS = bcm57xx.c
+
+OBJS = $(SRCS:%.c=%.o)
+
+$(TARGET): $(OBJS)
+ $(AR) -rc $@ $(OBJS)
+ $(RANLIB) $@
+
+clean:
+ $(RM) $(TARGET) $(OBJS)
+
+distclean: clean
+ $(RM) Makefile.dep
+
+
+# Rules for creating the dependency file:
+depend:
+ $(RM) Makefile.dep
+ $(MAKE) Makefile.dep
+
+Makefile.dep: Makefile
+ $(CC) -M $(CPPFLAGS) $(CFLAGS) $(SRCS) $(SRCSS) > Makefile.dep
+
+# Include dependency file if available:
+-include Makefile.dep
diff --git a/src/roms/SLOF/lib/libbcm/bcm.code b/src/roms/SLOF/lib/libbcm/bcm.code
new file mode 100644
index 0000000..308ebba
--- /dev/null
+++ b/src/roms/SLOF/lib/libbcm/bcm.code
@@ -0,0 +1,57 @@
+/******************************************************************************
+ * Copyright (c) 2013 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+/*
+ * libbcm Forth wrapper
+ */
+
+#include <bcm57xx.h>
+
+// : bcm57xx-open ( -- false | [ driver true ] )
+PRIM(BCM57XX_X2d_OPEN)
+{
+ net_driver_t *net_driver = bcm57xx_open();
+ if (net_driver) {
+ PUSH;
+ TOS.u = (unsigned long)net_driver; PUSH;
+ TOS.n = -1;
+ } else {
+ PUSH;
+ TOS.n = 0;
+ }
+}
+MIRP
+
+// : bcm57xx-close ( driver -- )
+PRIM(BCM57XX_X2d_CLOSE)
+{
+ net_driver_t *driver = TOS.a; POP;
+ bcm57xx_close(driver);
+}
+MIRP
+
+
+// : bcm57xx-read ( addr len -- actual )
+PRIM(BCM57XX_X2d_READ)
+{
+ int len = TOS.u; POP;
+ TOS.n = bcm57xx_read(TOS.a, len);
+}
+MIRP
+
+// : bcm57xx-write ( addr len -- actual )
+PRIM(BCM57XX_X2d_WRITE)
+{
+ int len = TOS.u; POP;
+ TOS.n = bcm57xx_write(TOS.a, len);
+}
+MIRP
diff --git a/src/roms/SLOF/lib/libbcm/bcm.in b/src/roms/SLOF/lib/libbcm/bcm.in
new file mode 100644
index 0000000..ee50a6e
--- /dev/null
+++ b/src/roms/SLOF/lib/libbcm/bcm.in
@@ -0,0 +1,20 @@
+/******************************************************************************
+ * Copyright (c) 2013 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+/*
+ * libbcm bindings for Forth - definitions
+ */
+
+cod(BCM57XX-OPEN)
+cod(BCM57XX-CLOSE)
+cod(BCM57XX-READ)
+cod(BCM57XX-WRITE)
diff --git a/src/roms/SLOF/lib/libbcm/bcm57xx.c b/src/roms/SLOF/lib/libbcm/bcm57xx.c
new file mode 100644
index 0000000..2ecb517
--- /dev/null
+++ b/src/roms/SLOF/lib/libbcm/bcm57xx.c
@@ -0,0 +1,3461 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+/*
+ *
+ ******************************************************************************
+ * reference:
+ * Broadcom 57xx
+ * Host Programmer Interface Specification for the
+ * NetXtreme Family of Highly-Integrated Media Access Controlers
+ */
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <byteorder.h>
+#include <helpers.h>
+#include <netdriver.h>
+#include "bcm57xx.h"
+
+/*
+ * local defines
+ ******************************************************************************
+ */
+
+
+// #define BCM_VLAN_TAG ( (uint32_t) 0x1 )
+
+// number of tx/rx rings
+// NOTE: 5714 only uses 1 rx/tx ring, but memory
+// for the other rings is cleaned anyways for
+// sanity & future use
+#define BCM_MAX_TX_RING 16
+#define BCM_MAX_RXRET_RING 16
+#define BCM_MAX_RXPROD_RCB 3
+
+// bd descriptions
+#define BCM_RXPROD_RING_SIZE 512 // don't change
+#define BCM_RXRET_RING_SIZE 512 // don't change
+#define BCM_TX_RING_SIZE 512 // don't change
+#define BCM_BUF_SIZE 1536 // don't change
+#define BCM_MTU_MAX_LEN 1522
+#define BCM_MAX_RX_BUF 64
+#define BCM_MAX_TX_BUF 16
+
+// number of MAC addresses in NIC
+#define BCM_NUM_MAC_ADDR 4
+#define BCM_NUM_MAC5704_ADDR 12
+// offset of mac address field(s) in bcm register space
+#define MAC5704_ADDR_OFFS ( (uint16_t) 0x0530 )
+
+// offset of NIC memory start address from base address
+#define BCM_MEMORY_OFFS ( (uint64_t) 0x8000 )
+
+// offset of statistics block in NIC memory
+#define BCM_STATISTIC_OFFS ( (uint64_t) 0x0300 )
+// size of statistic block in NIC memory
+#define BCM_STATISTIC_SIZE 0x800
+
+// offsets of NIC rx/tx rings in NIC memory
+#define BCM_NIC_TX_OFFS ( (uint16_t) 0x4000 )
+#define BCM_NIC_RX_OFFS ( (uint16_t) 0x6000 )
+#define BCM_NIC_TX_SIZE ( (uint16_t) ( ( BCM_TX_RING_SIZE * BCM_RCB_SIZE_u16 ) / 4 ) )
+
+// device mailboxes
+#define BCM_FW_MBX ( (uint16_t) 0x0b50 )
+#define BCM_FW_MBX_CMD ( (uint16_t) 0x0b78 )
+#define BCM_FW_MBX_LEN ( (uint16_t) 0x0b7c )
+#define BCM_FW_MBX_DATA ( (uint16_t) 0x0b80 )
+#define BCM_NICDRV_STATE_MBX ( (uint16_t) 0x0c04 )
+
+// device mailbox commands
+#define BCM_NICDRV_ALIVE ( (uint32_t) 0x00000001 )
+#define BCM_NICDRV_PAUSE_FW ( (uint32_t) 0x00000002 )
+
+// device values
+#define BCM_MAGIC_NUMBER ( (uint32_t) 0x4b657654 )
+
+// device states
+#define NIC_FWDRV_STATE_START ( (uint32_t) 0x00000001 )
+#define NIC_FWDRV_STATE_START_DONE ( (uint32_t) 0x80000001 )
+#define NIC_FWDRV_STATE_UNLOAD ( (uint32_t) 0x00000002 )
+#define NIC_FWDRV_STATE_UNLOAD_DONE ( (uint32_t) 0x80000002 )
+#define NIC_FWDRV_STATE_SUSPEND ( (uint32_t) 0x00000004 )
+
+// timer prescaler value
+#define BCM_TMR_PRESCALE ( (uint32_t) 0x41 )
+
+// offset of transmit rcb's in NIC memory
+#define BCM_TX_RCB_OFFS ( (uint16_t) 0x0100 )
+// offset of receive return rcb's in NIC memory
+#define BCM_RXRET_RCB_OFFS ( (uint16_t) 0x0200 )
+
+// register offsets for ring indices
+#define TX_PROD_IND ( (uint16_t) 0x0304 )
+#define TX_CONS_IND ( (uint16_t) 0x3cc0 )
+#define RXPROD_PROD_IND ( (uint16_t) 0x026c )
+#define RXPROD_CONS_IND ( (uint16_t) 0x3c54 )
+#define RXRET_PROD_IND ( (uint16_t) 0x3c80 )
+#define RXRET_CONS_IND ( (uint16_t) 0x0284 )
+// NIC producer index only needed for initialization
+#define TX_NIC_PROD_IND ( (uint16_t) 0x0384 )
+
+/*
+ * predefined register values used during initialization
+ * may be adapted by user
+ */
+#define DMA_RW_CTRL_VAL_5714 ( (uint32_t) 0x76144000 )
+#define DMA_RW_CTRL_VAL ( (uint32_t) 0x760F0000 )
+#define TX_MAC_LEN_VAL ( (uint32_t) 0x00002620 )
+
+#define RX_LST_PLC_CFG_VAL ( (uint32_t) 0x00000109 )
+#define RX_LST_PLC_STAT_EN_VAL ( (uint32_t) 0x007e000f )
+#define NVM_ADDR_MSK ( (uint32_t) 0x000fffff )
+
+// Number of Receive Rules /w or /wo SOL enabled
+#define RX_RULE_CFG_VAL ( (uint32_t) 0x00000008 )
+#define NUM_RX_RULE ( (uint32_t) 16 )
+#define NUM_RX_RULE_ASF ( (uint32_t) ( NUM_RX_RULE - 4 ) )
+
+// RCB register offsets
+#define BCM_RXPROD_RCB_JUM ( (uint16_t) 0x2440 )
+#define BCM_RXPROD_RCB_STD ( (uint16_t) 0x2450 )
+#define BCM_RXPROD_RCB_MIN ( (uint16_t) 0x2460 )
+
+// macros needed for new addressing method
+#define BCM_RCB_HOSTADDR_HI_u16( rcb ) ( (uint16_t) rcb + 0x00 )
+#define BCM_RCB_HOSTADDR_LOW_u16( rcb ) ( (uint16_t) rcb + 0x04 )
+#define BCM_RCB_LENFLAG_u16( rcb ) ( (uint16_t) rcb + 0x08 )
+#define BCM_RCB_NICADDR_u16( rcb ) ( (uint16_t) rcb + 0x0c )
+#define BCM_RCB_SIZE_u16 ( (uint16_t) 0x0010 )
+
+// RCB flags
+#define RCB_FLAG_RING_DISABLED BIT32( 1 )
+
+// BCM device ID masks
+#define BCM_DEV_5714 ( (uint64_t) 0x1 )
+#define BCM_DEV_5704 ( (uint64_t) 0x2 )
+#define BCM_DEV_5703 ( (uint64_t) 0x4 )
+#define BCM_DEV_SERDES ( (uint64_t) 0x80000000 )
+#define BCM_DEV_COPPER ( (uint64_t) 0x40000000 )
+
+#define IS_5714 ( ( bcm_device_u64 & BCM_DEV_5714 ) != 0 )
+#define IS_5704 ( ( bcm_device_u64 & BCM_DEV_5704 ) != 0 )
+#define IS_5703 ( ( bcm_device_u64 & BCM_DEV_5703 ) != 0 )
+#define IS_SERDES ( ( bcm_device_u64 & BCM_DEV_SERDES ) != 0 )
+#define IS_COPPER_PHY ( ( bcm_device_u64 & BCM_DEV_COPPER ) != 0 )
+
+#define BUFFERED_FLASH_PAGE_POS 9
+#define BUFFERED_FLASH_BYTE_ADDR_MASK ((<<BUFFERED_FLASH_PAGE_POS) - 1)
+#define BUFFERED_FLASH_PAGE_SIZE 264
+#define BUFFERED_FLASH_PHY_SIZE 512
+#define MANUFACTURING_INFO_SIZE 140
+#define CRC32_POLYNOMIAL 0xEDB88320
+
+/*
+ * local types
+ ******************************************************************************
+ */
+typedef struct {
+ uint32_t m_dev_u32;
+ uint64_t m_devmsk_u64;
+} bcm_dev_t;
+
+/*
+ * BCM common data structures
+ * BCM57xx Programmer's Guide: Section 5
+ */
+
+/*
+ * 64bit host address in a way the NIC is able to understand it
+ */
+typedef struct {
+ uint32_t m_hi_u32;
+ uint32_t m_lo_u32;
+} bcm_addr64_t;
+/*
+ * ring control block
+ */
+typedef struct {
+ bcm_addr64_t m_hostaddr_st;
+ uint32_t m_lenflags_u32; // upper 16b: len, lower 16b: flags
+ uint32_t m_nicaddr_u32;
+} bcm_rcb_t;
+
+/*
+ * tx buffer descriptor
+ */
+typedef struct {
+ bcm_addr64_t m_hostaddr_st;
+ uint32_t m_lenflags_u32; // upper 16b: len, lower 16b: flags
+ uint32_t m_VLANtag_u32; // lower 16b: vtag
+} bcm_txbd_t;
+
+/*
+ * rx buffer descriptor
+ */
+typedef struct {
+ bcm_addr64_t m_hostaddr_st;
+ uint32_t m_idxlen_u32; // upper 16b: idx, lower 16b: len
+ uint32_t m_typeflags_u32; // upper 16b: type, lower 16b: flags
+ uint32_t m_chksum_u32; // upper 16b: ip, lower 16b: tcp/udp
+ uint32_t m_errvlan_u32; // upper 16b: err, lower 16b: vlan tag
+ uint32_t m_reserved_u32;
+ uint32_t m_opaque_u32;
+} bcm_rxbd_t;
+
+/*
+ * bcm status block
+ * NOTE: in fact the status block is not used and configured
+ * so that it is not updated by the NIC. Still it has to be
+ * set up so the NIC is satisfied
+ */
+typedef struct {
+ uint32_t m_st_word_u32;
+ uint32_t m_st_tag_u32;
+ uint16_t m_rxprod_cons_u16;
+ uint16_t m_unused_u16;
+ uint32_t m_unused_u32;
+ uint16_t m_tx_cons_u16;
+ uint16_t m_rxret_prod_u16;
+} bcm_status_t;
+
+/*
+ * local constants
+ ******************************************************************************
+ */
+static const bcm_dev_t bcm_dev[] = {
+ { 0x166b, BCM_DEV_5714 },
+ { 0x1668, BCM_DEV_5714 },
+ { 0x1669, BCM_DEV_5714 },
+ { 0x166a, BCM_DEV_5714 },
+ { 0x1648, BCM_DEV_5704 },
+ { 0x1649, BCM_DEV_5704 | BCM_DEV_SERDES },
+ { 0x16a8, BCM_DEV_5704 | BCM_DEV_SERDES },
+ { 0x16a7, BCM_DEV_5703 | BCM_DEV_SERDES },
+ { 0x16c7, BCM_DEV_5703 | BCM_DEV_SERDES },
+ { 0 , 0 }
+};
+
+/*
+ * local variables
+ ******************************************************************************
+ */
+static uint64_t bcm_device_u64;
+static uint32_t bcm_rxret_ring_sz;
+static uint64_t bcm_baseaddr_u64;
+static uint64_t bcm_memaddr_u64;
+
+/*
+ * rings & their buffers
+ */
+// the rings made of buffer descriptors
+static bcm_txbd_t bcm_tx_ring[BCM_TX_RING_SIZE];
+static bcm_rxbd_t bcm_rxprod_ring[BCM_RXPROD_RING_SIZE];
+static bcm_rxbd_t bcm_rxret_ring[BCM_RXRET_RING_SIZE*2];
+
+// the buffers used in the rings
+static uint8_t bcm_tx_buffer_pu08[BCM_MAX_TX_BUF][BCM_BUF_SIZE];
+static uint8_t bcm_rx_buffer_pu08[BCM_MAX_RX_BUF][BCM_BUF_SIZE];
+
+// tx ring index of first/last bd
+static uint32_t bcm_tx_start_u32;
+static uint32_t bcm_tx_stop_u32;
+static uint32_t bcm_tx_bufavail_u32;
+
+/*
+ * status block
+ */
+static bcm_status_t bcm_status;
+
+/*
+ * implementation
+ ******************************************************************************
+ */
+
+
+/*
+ * global functions
+ ******************************************************************************
+ */
+
+
+/*
+ * local helper functions
+ ******************************************************************************
+ */
+#if 0
+static char *
+memcpy( char *dest, const char *src, size_t n )
+{
+ char *ret = dest;
+ while( n-- ) {
+ *dest++ = *src++;
+ }
+
+ return( ret );
+}
+#endif
+
+static char *
+memset_ci( char *dest, int c, size_t n )
+{
+ char *ret = dest;
+
+ while( n-- ) {
+ wr08( dest, c );
+ dest++;
+ }
+
+ return( ret );
+}
+
+#if 0
+static char *
+memset( char *dest, int c, size_t n )
+{
+ char *ret = dest;
+ while( n-- ) {
+ *dest++ = (char) c;
+ }
+
+ return( ret );
+}
+#endif
+
+static uint32_t
+bcm_nvram_logical_to_physical_address(uint32_t address)
+{
+ uint32_t page_no = address / BUFFERED_FLASH_PAGE_SIZE;
+ uint32_t page_addr = address % BUFFERED_FLASH_PAGE_SIZE;
+
+ return (page_no << BUFFERED_FLASH_PAGE_POS) + page_addr;
+}
+
+/*
+ * read/write functions to access NIC registers & memory
+ * NOTE: all functions are executed with cache inhibitation (dead slow :-) )
+ */
+static uint32_t
+bcm_read_mem32( uint16_t f_offs_u16 )
+{ // caution: shall only be used after initialization!
+ return rd32( bcm_memaddr_u64 + (uint64_t) f_offs_u16 );
+}
+
+/* not used so far
+static uint16_t
+bcm_read_mem16( uint16_t f_offs_u16 )
+{ // caution: shall only be used after initialization!
+ return rd16( bcm_memaddr_u64 + (uint64_t) f_offs_u16 );
+}*/
+/* not used so far
+static uint8_t
+bcm_read_mem08( uint16_t f_offs_u16 )
+{ // caution: shall only be used after initialization!
+ return rd08( bcm_memaddr_u64 + (uint64_t) f_offs_u16 );
+}*/
+
+static uint32_t
+bcm_read_reg32_indirect( uint16_t f_offs_u16 )
+{ // caution: shall only be used after initialization!
+ SLOF_pci_config_write32(REG_BASE_ADDR_REG, f_offs_u16);
+ /*snk_kernel_interface->pci_config_write( bcm_pcicfg_puid,
+ 4,
+ bcm_pcicfg_bus,
+ bcm_pcicfg_devfn,
+ REG_BASE_ADDR_REG,
+ f_offs_u16 );*/
+ return bswap_32(SLOF_pci_config_read32(REG_DATA_REG));
+ /*return (uint32_t) bswap_32( snk_kernel_interface->pci_config_read( bcm_pcicfg_puid,
+ 4,
+ bcm_pcicfg_bus,
+ bcm_pcicfg_devfn,
+ REG_DATA_REG ) ) ;*/
+}
+
+static uint32_t
+bcm_read_reg32( uint16_t f_offs_u16 )
+{ // caution: shall only be used after initialization!
+ if(f_offs_u16 >= 0x200 && f_offs_u16 <0x400)
+ return bcm_read_reg32_indirect( f_offs_u16 + 0x5600 );
+ return rd32( bcm_baseaddr_u64 + (uint64_t) f_offs_u16 );
+}
+
+static uint16_t
+bcm_read_reg16( uint16_t f_offs_u16 )
+{ // caution: shall only be used after initialization!
+ return rd16( bcm_baseaddr_u64 + (uint64_t) f_offs_u16 );
+}
+/* not used so far
+static uint8_t
+bcm_read_reg08( uint16_t f_offs_u16 )
+{ // caution: shall only be used after initialization!
+ return rd08( bcm_baseaddr_u64 + (uint64_t) f_offs_u16 );
+}*/
+
+static void
+bcm_write_mem32_indirect( uint16_t f_offs_u16, uint32_t f_val_u32 )
+{ // caution: shall only be used after initialization!
+ SLOF_pci_config_write32(MEM_BASE_ADDR_REG, f_offs_u16);
+ /*snk_kernel_interface->pci_config_write( bcm_pcicfg_puid,
+ 4,
+ bcm_pcicfg_bus,
+ bcm_pcicfg_devfn,
+ MEM_BASE_ADDR_REG,
+ f_offs_u16 );*/
+ SLOF_pci_config_write32(MEM_DATA_REG, bswap_32(f_val_u32));
+ /*snk_kernel_interface->pci_config_write( bcm_pcicfg_puid,
+ 4,
+ bcm_pcicfg_bus,
+ bcm_pcicfg_devfn,
+ MEM_DATA_REG,
+ bswap_32 ( f_val_u32 ) );*/
+}
+
+static void
+bcm_write_mem32( uint16_t f_offs_u16, uint32_t f_val_u32 )
+{ // caution: shall only be used after initialization!
+ if(f_offs_u16 >= BCM_RXRET_RCB_OFFS &&
+ f_offs_u16 < BCM_RXRET_RCB_OFFS + (BCM_MAX_RXRET_RING*BCM_RCB_SIZE_u16))
+ bcm_write_mem32_indirect( f_offs_u16, f_val_u32 );
+ else if(f_offs_u16 >= BCM_TX_RCB_OFFS &&
+ f_offs_u16 < BCM_TX_RCB_OFFS + (BCM_MAX_TX_RING*BCM_RCB_SIZE_u16))
+ bcm_write_mem32_indirect( f_offs_u16, f_val_u32 );
+ else
+ wr32( bcm_memaddr_u64 + (uint64_t) f_offs_u16, f_val_u32 );
+}
+/* not used so far
+static void
+bcm_write_mem16( uint16_t f_offs_u16, uint16_t f_val_u16 )
+{ // caution: shall only be used after initialization!
+ wr16( bcm_memaddr_u64 + (uint64_t) f_offs_u16, f_val_u16 );
+}*/
+/* not used so far
+static void
+bcm_write_mem08( uint16_t f_offs_u16, uint8_t f_val_u08 )
+{ // caution: shall only be used after initialization!
+ wr08( bcm_memaddr_u64 + (uint64_t) f_offs_u16, f_val_u08 );
+}*/
+
+static void
+bcm_write_reg32_indirect( uint16_t f_offs_u16, uint32_t f_val_u32 )
+{ // caution: shall only be used after initialization!
+ SLOF_pci_config_write32(REG_BASE_ADDR_REG, f_offs_u16);
+ /*snk_kernel_interface->pci_config_write( bcm_pcicfg_puid,
+ 4,
+ bcm_pcicfg_bus,
+ bcm_pcicfg_devfn,
+ REG_BASE_ADDR_REG,
+ f_offs_u16 );*/
+ SLOF_pci_config_write32(REG_DATA_REG, bswap_32(f_val_u32));
+ /*snk_kernel_interface->pci_config_write( bcm_pcicfg_puid,
+ 4,
+ bcm_pcicfg_bus,
+ bcm_pcicfg_devfn,
+ REG_DATA_REG,
+ bswap_32 ( f_val_u32 ) );*/
+}
+
+static void
+bcm_write_reg32( uint16_t f_offs_u16, uint32_t f_val_u32 )
+{ // caution: shall only be used after initialization!
+ if(f_offs_u16 >= 0x200 && f_offs_u16 <0x400)
+ bcm_write_reg32_indirect( f_offs_u16 + 0x5600, f_val_u32 );
+ else
+ wr32( bcm_baseaddr_u64 + (uint64_t) f_offs_u16, f_val_u32 );
+}
+
+static void
+bcm_write_reg16( uint16_t f_offs_u16, uint16_t f_val_u16 )
+{ // caution: shall only be used after initialization!
+ wr16( bcm_baseaddr_u64 + (uint64_t) f_offs_u16, f_val_u16 );
+}
+/* not used so far
+static void
+bcm_write_reg08( uint16_t f_offs_u16, uint8_t f_val_u08 )
+{ // caution: shall only be used after initialization!
+ wr08( bcm_baseaddr_u64 + (uint64_t) f_offs_u16, f_val_u08 );
+}*/
+
+static void
+bcm_setb_reg32( uint16_t f_offs_u16, uint32_t f_mask_u32 )
+{
+ uint32_t v;
+
+ v = bcm_read_reg32( f_offs_u16 );
+ v |= f_mask_u32;
+ bcm_write_reg32( f_offs_u16, v );
+}
+/* not used so far
+static void
+bcm_setb_reg16( uint16_t f_offs_u16, uint16_t f_mask_u16 )
+{
+ uint16_t v;
+ v = rd16( bcm_baseaddr_u64 + (uint64_t) f_offs_u16 );
+ v |= f_mask_u16;
+ wr16( bcm_baseaddr_u64 + (uint64_t) f_offs_u16, v );
+}*/
+/* not used so far
+static void
+bcm_setb_reg08( uint16_t f_offs_u16, uint8_t f_mask_u08 )
+{
+ uint8_t v;
+ v = rd08( bcm_baseaddr_u64 + (uint64_t) f_offs_u16 );
+ v |= f_mask_u08;
+ wr08( bcm_baseaddr_u64 + (uint64_t) f_offs_u16, v );
+}*/
+
+static void
+bcm_clrb_reg32( uint16_t f_offs_u16, uint32_t f_mask_u32 )
+{
+ uint32_t v;
+
+ v = bcm_read_reg32( f_offs_u16 );
+ v &= ~f_mask_u32;
+ bcm_write_reg32( f_offs_u16, v );
+}
+
+static void
+bcm_clrb_reg16( uint16_t f_offs_u16, uint16_t f_mask_u16 )
+{
+ uint16_t v;
+
+ v = bcm_read_reg16( f_offs_u16 );
+ v &= ~f_mask_u16;
+ bcm_write_reg16( f_offs_u16, v );
+}
+/* not used so far
+static void
+bcm_clrb_reg08( uint16_t f_offs_u16, uint8_t f_mask_u08 )
+{
+ uint8_t v;
+ v = rd08( bcm_baseaddr_u64 + (uint64_t) f_offs_u16 );
+ v &= ~f_mask_u32;
+ wr08( bcm_baseaddr_u64 + (uint64_t) f_offs_u16, v );
+}*/
+
+static void
+bcm_clr_wait_bit32( uint16_t r, uint32_t b )
+{
+ uint32_t i;
+
+ bcm_clrb_reg32( r, b );
+
+ i = 1000;
+ while( --i ) {
+
+ if( ( bcm_read_reg32( r ) & b ) == 0 ) {
+ break;
+ }
+
+ SLOF_usleep( 10 );
+ }
+#ifdef BCM_DEBUG
+ if( ( bcm_read_reg32( r ) & b ) != 0 ) {
+ printf( "bcm57xx: bcm_clear_wait_bit32 failed (0x%04X)!\n", r );
+ }
+#endif
+}
+
+/*
+ * (g)mii bus access
+ */
+#if 0
+// not used so far
+static int32_t
+bcm_mii_write16( uint32_t f_reg_u32, uint16_t f_value_u16 )
+{
+ static const uint32_t WR_VAL = ( ( ((uint32_t) 0x1) << 21 ) | BIT32( 29 ) | BIT32( 26 ) );
+ int32_t l_autopoll_i32 = 0;
+ uint32_t l_wrval_u32;
+ uint32_t i;
+
+ /*
+ * only 0x00-0x1f are valid registers
+ */
+ if( f_reg_u32 > (uint32_t) 0x1f ) {
+ return -1;
+ }
+
+ /*
+ * disable auto polling if enabled
+ */
+ if( ( bcm_read_reg32( MI_MODE_R ) & BIT32( 4 ) ) != 0 ) {
+ l_autopoll_i32 = (int32_t) !0;
+ bcm_clrb_reg32( MI_MODE_R, BIT32( 4 ) );
+ SLOF_usleep( 40 );
+ }
+
+ /*
+ * construct & write mi com register value
+ */
+ l_wrval_u32 = ( WR_VAL | ( f_reg_u32 << 16 ) | (uint32_t) f_value_u16 );
+ bcm_write_reg32( MI_COM_R, l_wrval_u32 );
+
+ /*
+ * wait for transaction to complete
+ */
+ i = 25;
+ while( ( --i ) &&
+ ( ( bcm_read_reg32( MI_COM_R ) & BIT32( 29 ) ) != 0 ) ) {
+ SLOF_usleep( 10 );
+ }
+
+ /*
+ * re-enable auto polling if necessary
+ */
+ if( l_autopoll_i32 ) {
+ bcm_setb_reg32( MI_MODE_R, BIT32( 4 ) );
+ }
+
+ // return on error
+ if( i == 0 ) {
+ return -1;
+ }
+
+ return 0;
+}
+#endif
+
+static int32_t
+bcm_mii_read16( uint32_t f_reg_u32, uint16_t *f_value_pu16 )
+{
+ static const uint32_t RD_VAL = ( ( ((uint32_t) 0x1) << 21 ) | BIT32( 29 ) | BIT32( 27 ) );
+ int32_t l_autopoll_i32 = 0;
+ uint32_t l_rdval_u32;
+ uint32_t i;
+ uint16_t first_not_busy;
+
+ /*
+ * only 0x00-0x1f are valid registers
+ */
+ if( f_reg_u32 > (uint32_t) 0x1f ) {
+ return -1;
+ }
+
+ /*
+ * disable auto polling if enabled
+ */
+ if( ( bcm_read_reg32( MI_MODE_R ) & BIT32( 4 ) ) != 0 ) {
+ l_autopoll_i32 = ( int32_t ) !0;
+ bcm_clrb_reg32( MI_MODE_R, BIT32( 4 ) );
+ SLOF_usleep( 40 );
+ }
+
+ /*
+ * construct & write mi com register value
+ */
+ l_rdval_u32 = ( RD_VAL | ( f_reg_u32 << 16 ) );
+ bcm_write_reg32( MI_COM_R, l_rdval_u32 );
+
+ /*
+ * wait for transaction to complete
+ * ERRATA workaround: must read two "not busy" states to indicate transaction complete
+ */
+ i = 25;
+ first_not_busy = 0;
+ l_rdval_u32 = bcm_read_reg32( MI_COM_R );
+ while( ( --i ) &&
+ ( (first_not_busy == 0) || ( ( l_rdval_u32 & BIT32( 29 ) ) != 0 ) ) ) {
+ /* Is this the first clear BUSY state? */
+ if ( ( l_rdval_u32 & BIT32( 29 ) ) == 0 )
+ first_not_busy++;
+ SLOF_usleep( 10 );
+ l_rdval_u32 = bcm_read_reg32( MI_COM_R );
+ }
+
+ /*
+ * re-enable autopolling if necessary
+ */
+ if( l_autopoll_i32 ) {
+ bcm_setb_reg32( MI_MODE_R, BIT32( 4 ) );
+ }
+
+ /*
+ * return on read transaction error
+ * (check read failed bit)
+ */
+ if( ( i == 0 ) ||
+ ( ( l_rdval_u32 & BIT32( 28 ) ) != 0 ) ) {
+ return -1;
+ }
+
+ /*
+ * return read value
+ */
+ *f_value_pu16 = (uint16_t) ( l_rdval_u32 & (uint32_t) 0xffff );
+
+ return 0;
+}
+
+/*
+ * ht2000 dump (not complete)
+ */
+#if 0
+static void
+bcm_dump( void )
+{
+ uint32_t i, j;
+
+ printf( "*** DUMP ***********************************************************************\n\n" );
+
+ printf( "* PCI Configuration Registers:\n" );
+ for( i = 0, j = 0; i < 0x40; i += 4 ) {
+
+ printf( "%04X: %08X ", i, bcm_read_reg32( i ) );
+
+ if( ( ++j & 0x3 ) == 0 ) {
+ printf( "\n" );
+ }
+
+ }
+
+ printf( "\n* Private PCI Configuration Registers:\n" );
+ for( i = 0x68, j = 0; i < 0x88; i += 4 ) {
+
+ printf( "%04X: %08X ", i, bcm_read_reg32( i ) );
+
+ if( ( ++j & 0x3 ) == 0 ) {
+ printf( "\n" );
+ }
+
+ }
+
+ printf( "\n* VPD Config:\n" );
+ printf( "%04X: %08X \n", 0x94, bcm_read_reg32( 0x94 ) );
+
+ printf( "\n* Dual MAC Control Registers:\n" );
+ for( i = 0xb8, j = 0; i < 0xd0; i += 4 ) {
+
+ printf( "%04X: %08X ", i, bcm_read_reg32( i ) );
+
+ if( ( ++j & 0x3 ) == 0 ) {
+ printf( "\n" );
+ }
+
+ }
+
+ printf( "\n* Ethernet MAC Control Registers:\n" );
+ for( i = 0x400, j = 0; i < 0x590; i += 4 ) {
+
+ printf( "%04X: %08X ", i, bcm_read_reg32( i ) );
+
+ if( ( ++j & 0x3 ) == 0 ) {
+ printf( "\n" );
+ }
+
+ }
+
+ printf( "\n* Send Data Initiator Control:\n" );
+ for( i = 0xc00, j = 0; i < 0xc10; i += 4 ) {
+
+ printf( "%04X: %08X ", i, bcm_read_reg32( i ) );
+
+ if( ( ++j & 0x3 ) == 0 ) {
+ printf( "\n" );
+ }
+
+ }
+
+ printf( "\n* Send Data Completion Control:\n" );
+ printf( "%04X: %08X ", 0x1000, bcm_read_reg32( 0x1000 ) );
+ printf( "%04X: %08X \n", 0x1008, bcm_read_reg32( 0x1008 ) );
+
+ printf( "\n* Send BD Ring Selector Control:\n" );
+ printf( "%04X: %08X ", 0x1400, bcm_read_reg32( 0x1400 ) );
+ printf( "%04X: %08X ", 0x1404, bcm_read_reg32( 0x1404 ) );
+ printf( "%04X: %08X \n", 0x1408, bcm_read_reg32( 0x1408 ) );
+
+ printf( "\n* Send BD Initiator Control:\n" );
+ printf( "%04X: %08X ", 0x1800, bcm_read_reg32( 0x1800 ) );
+ printf( "%04X: %08X \n", 0x1804, bcm_read_reg32( 0x1804 ) );
+
+ printf( "\n* Send BD Completion Control:\n" );
+ printf( "%04X: %08X ", 0x1c00, bcm_read_reg32( 0x1c00 ) );
+
+ printf( "\n* Receive List Placement Control:\n" );
+ for( i = 0x2000, j = 0; i < 0x2020; i += 4 ) {
+
+ printf( "%04X: %08X ", i, bcm_read_reg32( i ) );
+
+ if( ( ++j & 0x3 ) == 0 ) {
+ printf( "\n" );
+ }
+
+ }
+
+ printf( "\n* Receive Data & Receive BD Initiator Control:\n" );
+ printf( "%04X: %08X ", 0x2400, bcm_read_reg32( 0x2400 ) );
+ printf( "%04X: %08X \n", 0x2404, bcm_read_reg32( 0x2404 ) );
+
+ printf( "\n* Jumbo Receive BD Ring RCB:\n" );
+ for( i = 0x2440, j = 0; i < 0x2450; i += 4 ) {
+
+ printf( "%04X: %08X ", i, bcm_read_reg32( i ) );
+
+ if( ( ++j & 0x3 ) == 0 ) {
+ printf( "\n" );
+ }
+
+ }
+
+ printf( "\n* Standard Receive BD Ring RCB:\n" );
+ for( i = 0x2450, j = 0; i < 0x2460; i += 4 ) {
+
+ printf( "%04X: %08X ", i, bcm_read_reg32( i ) );
+
+ if( ( ++j & 0x3 ) == 0 ) {
+ printf( "\n" );
+ }
+
+ }
+
+ printf( "\n* Mini Receive BD Ring RCB:\n" );
+ for( i = 0x2460, j = 0; i < 0x2470; i += 4 ) {
+
+ printf( "%04X: %08X ", i, bcm_read_reg32( i ) );
+
+ if( ( ++j & 0x3 ) == 0 ) {
+ printf( "\n" );
+ }
+
+ }
+
+ printf( "\nRDI Timer Mode Register:\n" );
+ printf( "%04X: %08X \n", 0x24f0, bcm_read_reg32( 0x24f0 ) );
+
+ printf( "\n* Receive BD Initiator Control:\n" );
+ for( i = 0x2c00, j = 0; i < 0x2c20; i += 4 ) {
+
+ printf( "%04X: %08X ", i, bcm_read_reg32( i ) );
+
+ if( ( ++j & 0x3 ) == 0 ) {
+ printf( "\n" );
+ }
+
+ }
+
+ printf( "\n* Receive BD Completion Control:\n" );
+ for( i = 0x3000, j = 0; i < 0x3014; i += 4 ) {
+
+ printf( "%04X: %08X ", i, bcm_read_reg32( i ) );
+
+ if( ( ++j & 0x3 ) == 0 ) {
+ printf( "\n" );
+ }
+
+ }
+}
+#endif
+
+
+
+/*
+ * NVRAM access
+ */
+
+static int
+bcm_nvram_lock( void )
+{
+ int i;
+
+ /*
+ * Acquire NVRam lock (REQ0) & wait for arbitration won (ARB0_WON)
+ */
+// bcm_setb_reg32( SW_ARB_R, BIT32( 0 ) );
+ bcm_setb_reg32( SW_ARB_R, BIT32( 1 ) );
+
+ i = 2000;
+ while( ( --i ) &&
+// ( bcm_read_reg32( SW_ARB_R ) & BIT32( 8 ) ) == 0 ) {
+ ( bcm_read_reg32( SW_ARB_R ) & BIT32( 9 ) ) == 0 ) {
+ SLOF_msleep( 1 );
+ }
+
+ // return on error
+ if( i == 0 ) {
+#ifdef BCM_DEBUG
+ printf("bcm57xx: failed to lock nvram");
+#endif
+ return -1;
+ }
+
+ return 0;
+}
+
+static void
+bcm_nvram_unlock( void )
+{
+ /*
+ * release NVRam lock (CLR0)
+ */
+// bcm_setb_reg32( SW_ARB_R, BIT32( 4 ) );
+ bcm_setb_reg32( SW_ARB_R, BIT32( 5 ) );
+}
+
+static void
+bcm_nvram_init( void )
+{
+ /*
+ * enable access to NVRAM registers
+ */
+ if(IS_5714) {
+ bcm_setb_reg32( NVM_ACC_R, BIT32( 1 ) | BIT32( 0 ) );
+ }
+
+ /*
+ * disable bit-bang method 19& disable interface bypass
+ */
+ bcm_clrb_reg32( NVM_CFG1_R, BIT32( 31 ) | BIT32( 3 ) | BIT32( 2 ) | BIT32( 14 ) | BIT32( 16 ) );
+ bcm_setb_reg32( NVM_CFG1_R, BIT32 ( 13 ) | BIT32 ( 17 ));
+
+ /*
+ * enable Auto SEEPROM Access
+ */
+ bcm_setb_reg32( MISC_LOCAL_CTRL_R, BIT32 ( 24 ) );
+
+ /*
+ * NVRAM write enable
+ */
+ bcm_setb_reg32( MODE_CTRL_R, BIT32 ( 21 ) );
+}
+
+static int32_t
+bcm_nvram_read( uint32_t f_addr_u32, uint32_t *f_val_pu32, uint32_t lock )
+{
+ uint32_t i;
+
+ /*
+ * parameter check
+ */
+ if( f_addr_u32 > NVM_ADDR_MSK ) {
+ return -1;
+ }
+
+ /*
+ * Acquire NVRam lock (REQ0) & wait for arbitration won (ARB0_WON)
+ */
+ if( lock && (bcm_nvram_lock() == -1) ) {
+ return -1;
+ }
+
+ /*
+ * setup address to read
+ */
+ bcm_write_reg32( NVM_ADDR_R,
+ bcm_nvram_logical_to_physical_address(f_addr_u32) );
+// bcm_write_reg32( NVM_ADDR_R, f_addr_u32 );
+
+ /*
+ * get the command going
+ */
+ bcm_write_reg32( NVM_COM_R, BIT32( 8 ) | BIT32( 7 ) |
+ BIT32( 4 ) | BIT32( 3 ) );
+
+ /*
+ * wait for command completion
+ */
+ i = 2000;
+ while( ( --i ) &&
+ ( ( bcm_read_reg32( NVM_COM_R ) & BIT32( 3 ) ) == 0 ) ) {
+ SLOF_msleep( 1 );
+ }
+
+ /*
+ * read back data if no error
+ */
+ if( i != 0 ) {
+ /*
+ * read back data
+ */
+ *f_val_pu32 = bcm_read_reg32( NVM_READ_R );
+ }
+
+ if(lock)
+ bcm_nvram_unlock();
+
+ // error
+ if( i == 0 ) {
+#ifdef BCM_DEBUG
+ printf("bcm57xx: reading from NVRAM failed\n");
+#endif
+ return -1;
+ }
+
+ // success
+ return 0;
+}
+
+static int32_t
+bcm_nvram_write( uint32_t f_addr_u32, uint32_t f_value_u32, uint32_t lock )
+{
+ uint32_t i;
+
+ /*
+ * parameter check
+ */
+ if( f_addr_u32 > NVM_ADDR_MSK ) {
+ return -1;
+ }
+
+ /*
+ * Acquire NVRam lock (REQ0) & wait for arbitration won (ARB0_WON)
+ */
+ if( lock && (bcm_nvram_lock() == -1) ) {
+ return -1;
+ }
+
+ /*
+ * setup address to write
+ */
+ bcm_write_reg32( NVM_ADDR_R, bcm_nvram_logical_to_physical_address( f_addr_u32 ) );
+
+ /*
+ * setup write data
+ */
+ bcm_write_reg32( NVM_WRITE_R, f_value_u32 );
+
+ /*
+ * get the command going
+ */
+ bcm_write_reg32( NVM_COM_R, BIT32( 8 ) | BIT32( 7 ) |
+ BIT32( 5 ) | BIT32( 4 ) | BIT32( 3 ) );
+
+ /*
+ * wait for command completion
+ */
+ i = 2000;
+ while( ( --i ) &&
+ ( ( bcm_read_reg32( NVM_COM_R ) & BIT32( 3 ) ) == 0 ) ) {
+ SLOF_msleep( 1 );
+ }
+
+ /*
+ * release NVRam lock (CLR0)
+ */
+ if(lock)
+ bcm_nvram_unlock();
+
+ // error
+ if( i == 0 ) {
+#ifdef BCM_DEBUG
+ printf("bcm57xx: writing to NVRAM failed\n");
+#endif
+ return -1;
+ }
+
+ // success
+ return 0;
+}
+
+/*
+ * PHY initialization
+ */
+static int32_t
+bcm_mii_phy_init( void )
+{
+ static const uint32_t PHY_STAT_R = (uint32_t) 0x01;
+ static const uint32_t AUX_STAT_R = (uint32_t) 0x19;
+ static const uint32_t MODE_GMII = BIT32( 3 );
+ static const uint32_t MODE_MII = BIT32( 2 );
+ static const uint32_t NEG_POLARITY = BIT32( 10 );
+ static const uint32_t MII_MSK = ( MODE_GMII | MODE_MII );
+ static const uint16_t GIGA_ETH = ( BIT16( 10 ) | BIT16( 9 ) );
+ int32_t i;
+ uint16_t v;
+
+ /*
+ * enable MDI communication
+ */
+ bcm_write_reg32( MDI_CTRL_R, (uint32_t) 0x0 );
+
+ /*
+ * check link up
+ */
+ i = 2500;
+ do {
+ SLOF_msleep( 1 );
+ // register needs to be read twice!
+ bcm_mii_read16( PHY_STAT_R, &v );
+ bcm_mii_read16( PHY_STAT_R, &v );
+ } while( ( --i ) &&
+ ( ( v & BIT16( 2 ) ) == 0 ) );
+
+ if( i == 0 ) {
+#ifdef BCM_DEBUG
+ printf( "bcm57xx: link is down\n" );
+#endif
+ return -1;
+ }
+
+#ifdef BCM_DEBUG
+ printf( "bcm57xx: link is up\n" );
+#endif
+ if( !IS_COPPER_PHY ) {
+ return 0;
+ }
+
+ /*
+ * setup GMII or MII interface
+ */
+ i = bcm_read_reg32( ETH_MAC_MODE_R );
+ /*
+ * read status register twice, since the first
+ * read fails once between here and the moon...
+ */
+ bcm_mii_read16( AUX_STAT_R, &v );
+ bcm_mii_read16( AUX_STAT_R, &v );
+
+ if( ( v & GIGA_ETH ) == GIGA_ETH ) {
+#ifdef BCM_DEBUG
+ printf( "bcm57xx: running PHY in GMII mode (1000BaseT)\n" );
+#endif
+ // GMII device
+ if( ( i & MII_MSK ) != MODE_GMII ) {
+ i &= ~MODE_MII;
+ i |= MODE_GMII;
+ }
+
+ } else {
+#ifdef BCM_DEBUG
+ printf( "bcm57xx: running PHY in MII mode (10/100BaseT)\n" );
+#endif
+ // MII device
+ if( ( i & MII_MSK ) != MODE_MII ) {
+ i &= ~MODE_GMII;
+ i |= MODE_MII;
+ }
+
+ }
+
+ if( IS_5704 && !IS_SERDES ) {
+#ifdef BCM_DEBUG
+ printf( "bcm57xx: set the link ready signal for 5704C to negative polarity\n" );
+#endif
+ i |= NEG_POLARITY; // set the link ready signal for 5704C to negative polarity
+ }
+
+ bcm_write_reg32( ETH_MAC_MODE_R, i );
+
+ return 0;
+}
+
+static int32_t
+bcm_tbi_phy_init( void )
+{
+ int32_t i;
+#if 0
+ /*
+ * set TBI mode full duplex
+ */
+ bcm_clrb_reg32( ETH_MAC_MODE_R, BIT32( 1 ) );
+ bcm_setb_reg32( ETH_MAC_MODE_R, BIT32( 2 ) | BIT32( 3 ) );
+
+ /*
+ * enable MDI communication
+ */
+ bcm_write_reg32( MDI_CTRL_R, (uint32_t) 0x0 );
+
+ /* Disable link change interrupt. */
+ bcm_write_reg32( ETH_MAC_EVT_EN_R, 0 );
+
+ /*
+ * set link polarity
+ */
+ bcm_clrb_reg32( ETH_MAC_MODE_R, BIT32( 10 ) );
+
+ /*
+ * wait for sync/config changes
+ */
+ for( i = 0; i < 100; i++ ) {
+ bcm_write_reg32( ETH_MAC_STAT_R,
+ BIT32( 3 ) | BIT32( 4 ) );
+
+ SLOF_usleep( 20 );
+
+ if( ( bcm_read_reg32( ETH_MAC_STAT_R ) &
+ ( BIT32( 3 ) | BIT32( 4 ) ) ) == 0 ) {
+ break;
+ }
+
+ }
+#endif
+ /*
+ * wait for sync to come up
+ */
+ for( i = 0; i < 100; i++ ) {
+
+ if( ( bcm_read_reg32( ETH_MAC_STAT_R ) & BIT32( 0 ) ) != 0 ) {
+ break;
+ }
+
+ SLOF_usleep( 20 );
+ }
+
+ if( ( bcm_read_reg32( ETH_MAC_STAT_R ) & BIT32( 0 ) ) == 0) {
+#ifdef BCM_DEBUG
+ printf( "bcm57xx: link is down\n" );
+#endif
+ return -1;
+ }
+#if 0
+ /*
+ * clear all attentions
+ */
+ bcm_write_reg32( ETH_MAC_STAT_R, (uint32_t) ~0 );
+#endif
+
+#ifdef BCM_DEBUG
+ printf( "bcm57xx: link is up\n" );
+#endif
+ return 0;
+}
+
+static int32_t
+bcm_phy_init( void )
+{
+ static const uint16_t SRAM_HW_CFG = (uint16_t) 0x0b58;
+ uint32_t l_val_u32;
+ int32_t l_ret_i32 = 0;
+
+ /*
+ * get HW configuration from SRAM
+ */
+ l_val_u32 = bcm_read_mem32( SRAM_HW_CFG );
+ l_val_u32 &= ( BIT32( 5 ) | BIT32( 4 ) );
+
+ switch( l_val_u32 ) {
+ case 0x10: {
+ #ifdef BCM_DEBUG
+ printf( "bcm57xx: copper PHY detected\n" );
+ #endif
+
+ bcm_device_u64 |= BCM_DEV_COPPER;
+ l_ret_i32 = bcm_mii_phy_init();
+ } break;
+
+ case 0x20: {
+ #ifdef BCM_DEBUG
+ printf( "bcm57xx: fiber PHY detected\n" );
+ #endif
+
+ if( !IS_SERDES ) {
+ #ifdef BCM_DEBUG
+ printf( "bcm57xx: running PHY in gmii/mii mode\n" );
+ #endif
+ l_ret_i32 = bcm_mii_phy_init();
+ } else {
+ #ifdef BCM_DEBUG
+ printf( "bcm57xx: running PHY in tbi mode\n" );
+ #endif
+ l_ret_i32 = bcm_tbi_phy_init();
+ }
+
+ } break;
+
+ default: {
+ #ifdef BCM_DEBUG
+ printf( "bcm57xx: unknown PHY type detected, terminating\n" );
+ #endif
+ l_ret_i32 = -1;
+ }
+
+ }
+
+ return l_ret_i32;
+}
+
+/*
+ * ring initialization
+ */
+static void
+bcm_init_rxprod_ring( void )
+{
+ uint32_t v;
+ uint32_t i;
+
+ /*
+ * clear out the whole rx prod ring for sanity
+ */
+ memset( (void *) &bcm_rxprod_ring,
+ 0,
+ BCM_RXPROD_RING_SIZE * sizeof( bcm_rxbd_t ) );
+ mb();
+
+ /*
+ * assign buffers & indices to the ring members
+ */
+ for( i = 0; i < BCM_MAX_RX_BUF; i++ ) {
+ bcm_rxprod_ring[i].m_hostaddr_st.m_hi_u32 =
+ (uint32_t) ( (uint64_t) &bcm_rx_buffer_pu08[i] >> 32 );
+ bcm_rxprod_ring[i].m_hostaddr_st.m_lo_u32 =
+ (uint32_t) ( (uint64_t) &bcm_rx_buffer_pu08[i] &
+ (uint64_t) 0xffffffff );
+ bcm_rxprod_ring[i].m_idxlen_u32 = ( i << 16 );
+ bcm_rxprod_ring[i].m_idxlen_u32 += BCM_BUF_SIZE;
+ }
+
+ /*
+ * clear rcb registers & disable rings
+ * NOTE: mini & jumbo rings are not supported,
+ * still rcb's are cleaned out for sanity
+ */
+ bcm_write_reg32( BCM_RCB_LENFLAG_u16( BCM_RXPROD_RCB_JUM ), RCB_FLAG_RING_DISABLED );
+ bcm_write_reg32( BCM_RCB_HOSTADDR_HI_u16( BCM_RXPROD_RCB_JUM ), 0 );
+ bcm_write_reg32( BCM_RCB_HOSTADDR_LOW_u16( BCM_RXPROD_RCB_JUM ), 0 );
+ bcm_write_reg32( BCM_RCB_NICADDR_u16( BCM_RXPROD_RCB_JUM ), 0 );
+
+ bcm_write_reg32( BCM_RCB_LENFLAG_u16( BCM_RXPROD_RCB_STD ), RCB_FLAG_RING_DISABLED );
+ bcm_write_reg32( BCM_RCB_HOSTADDR_HI_u16( BCM_RXPROD_RCB_STD ), 0 );
+ bcm_write_reg32( BCM_RCB_HOSTADDR_LOW_u16( BCM_RXPROD_RCB_STD ), 0 );
+ bcm_write_reg32( BCM_RCB_NICADDR_u16( BCM_RXPROD_RCB_STD ), 0 );
+
+ bcm_write_reg32( BCM_RCB_LENFLAG_u16( BCM_RXPROD_RCB_MIN ), RCB_FLAG_RING_DISABLED );
+ bcm_write_reg32( BCM_RCB_HOSTADDR_HI_u16( BCM_RXPROD_RCB_MIN ), 0 );
+ bcm_write_reg32( BCM_RCB_HOSTADDR_LOW_u16( BCM_RXPROD_RCB_MIN ), 0 );
+ bcm_write_reg32( BCM_RCB_NICADDR_u16( BCM_RXPROD_RCB_MIN ), 0 );
+
+ /*
+ * clear rx producer index of std producer ring
+ */
+ bcm_write_reg32( RXPROD_PROD_IND, 0 );
+
+ /*
+ * setup rx standard rcb using recommended NIC addr (hard coded)
+ */
+ bcm_write_reg32( BCM_RCB_HOSTADDR_HI_u16( BCM_RXPROD_RCB_STD ),
+ (uint32_t) ( (uint64_t) &bcm_rxprod_ring >> 32 ) );
+ bcm_write_reg32( BCM_RCB_HOSTADDR_LOW_u16( BCM_RXPROD_RCB_STD ),
+ (uint32_t) ( (uint64_t) &bcm_rxprod_ring & (uint64_t) 0xffffffff ) );
+ bcm_write_reg32( BCM_RCB_NICADDR_u16( BCM_RXPROD_RCB_STD ),
+ (uint32_t) BCM_NIC_RX_OFFS );
+
+ if( IS_5704 || IS_5703 ) {
+ // 5704: length field = max buffer len
+ v = (uint32_t) BCM_BUF_SIZE << 16;
+ } else {
+ // 5714: length field = number of ring entries
+ v = (uint32_t) BCM_RXPROD_RING_SIZE << 16;
+ }
+
+ v &= (uint32_t) ~RCB_FLAG_RING_DISABLED;
+ bcm_write_reg32( BCM_RCB_LENFLAG_u16( BCM_RXPROD_RCB_STD ), v );
+}
+
+static void
+bcm_init_rxret_ring( void )
+{
+ uint32_t i;
+ uint16_t v;
+
+ /*
+ * clear out the whole rx ret ring for sanity
+ */
+ memset( (void *) &bcm_rxret_ring,
+ 0,
+ 2 * BCM_RXRET_RING_SIZE * sizeof( bcm_rxbd_t ) );
+ mb();
+
+ /*
+ * setup return ring size dependent on installed device
+ */
+ bcm_rxret_ring_sz = BCM_RXRET_RING_SIZE;
+ if( IS_5704 || IS_5703 ) {
+ bcm_rxret_ring_sz *= 2;
+ }
+
+ /*
+ * clear rcb memory & disable rings
+ * NOTE: 5714 only supports one return ring,
+ * still all possible rcb's are cleaned out for sanity
+ */
+ v = BCM_RXRET_RCB_OFFS;
+ for( i = 0; i < BCM_MAX_RXRET_RING; i++ ) {
+ bcm_write_mem32( BCM_RCB_LENFLAG_u16( v ), RCB_FLAG_RING_DISABLED );
+ bcm_write_mem32( BCM_RCB_HOSTADDR_HI_u16( v ), 0 );
+ bcm_write_mem32( BCM_RCB_HOSTADDR_LOW_u16( v ), 0 );
+ bcm_write_mem32( BCM_RCB_NICADDR_u16( v ), 0 );
+
+ v += BCM_RCB_SIZE_u16;
+ }
+
+ /*
+ * clear rx consumer index of return ring
+ */
+ bcm_write_reg32( RXRET_CONS_IND, 0 );
+
+ /*
+ * setup rx ret rcb
+ * NOTE: NIC address not aplicable in return rings
+ */
+ bcm_write_mem32( BCM_RCB_HOSTADDR_HI_u16( BCM_RXRET_RCB_OFFS ),
+ (uint32_t) ( (uint64_t) &bcm_rxret_ring >> 32 ) );
+ bcm_write_mem32( BCM_RCB_HOSTADDR_LOW_u16( BCM_RXRET_RCB_OFFS ),
+ (uint32_t) ( (uint64_t) &bcm_rxret_ring &
+ (uint64_t) 0xffffffff ) );
+ bcm_write_mem32( BCM_RCB_NICADDR_u16( BCM_RXRET_RCB_OFFS ), 0 );
+
+ i = bcm_rxret_ring_sz;
+ i <<= 16;
+ i &= (uint32_t) ~RCB_FLAG_RING_DISABLED;
+ bcm_write_reg32( BCM_RCB_LENFLAG_u16( BCM_RXRET_RCB_OFFS ), i );
+}
+
+static void
+bcm_init_tx_ring( void )
+{
+ uint32_t i;
+ uint16_t v;
+
+ /*
+ * clear out the whole tx ring for sanity
+ */
+ memset( (void *) &bcm_tx_ring,
+ 0,
+ BCM_TX_RING_SIZE * sizeof( bcm_txbd_t ) );
+ mb();
+
+ /*
+ * assign buffers to the ring members & setup invariant flags
+ */
+ for( i = 0; i < BCM_MAX_TX_BUF; i++ ) {
+ bcm_tx_ring[i].m_hostaddr_st.m_hi_u32 =
+ (uint32_t) ( (uint64_t) &bcm_tx_buffer_pu08[i] >> 32 );
+ bcm_tx_ring[i].m_hostaddr_st.m_lo_u32 =
+ (uint32_t) ( (uint64_t) &bcm_tx_buffer_pu08[i] &
+ (uint64_t) 0xffffffff );
+ // flags: indicate last packet & coal now
+ // -last packet is always true (only one send packet supported)
+ // -coal now needed to always get the consumed bd's (since
+ // only a few bd's are set up which permanently are recycled)
+ bcm_tx_ring[i].m_lenflags_u32 = ( BIT32( 2 ) | BIT32( 7 ) );
+ bcm_tx_ring[i].m_VLANtag_u32 = (uint32_t) 0; // not used
+ }
+
+ /*
+ * clear rcb memory & disable rings
+ * NOTE: 5714 only supports one send ring,
+ * still all possible rcb's are cleaned out for sanity
+ */
+ v = BCM_TX_RCB_OFFS;
+ for( i = 0; i < BCM_MAX_TX_RING; i++ ) {
+ bcm_write_mem32( BCM_RCB_LENFLAG_u16( v ), RCB_FLAG_RING_DISABLED );
+ bcm_write_mem32( BCM_RCB_HOSTADDR_HI_u16( v ), 0 );
+ bcm_write_mem32( BCM_RCB_HOSTADDR_LOW_u16( v ), 0 );
+ bcm_write_mem32( BCM_RCB_NICADDR_u16( v ), 0 );
+
+ v += BCM_RCB_SIZE_u16;
+ }
+
+ /*
+ * clear host/nic producer indices
+ */
+ bcm_write_reg32( TX_NIC_PROD_IND, 0 );
+ bcm_write_reg32( TX_PROD_IND, 0 );
+
+ /*
+ * setup tx rcb using recommended NIC addr (hard coded)
+ */
+ bcm_write_mem32( BCM_RCB_HOSTADDR_HI_u16( BCM_TX_RCB_OFFS ),
+ (uint32_t) ( (uint64_t) &bcm_tx_ring >> 32 ) );
+ bcm_write_mem32( BCM_RCB_HOSTADDR_LOW_u16( BCM_TX_RCB_OFFS ),
+ (uint32_t) ( (uint64_t) &bcm_tx_ring &
+ (uint64_t) 0xffffffff ) );
+ bcm_write_mem32( BCM_RCB_NICADDR_u16( BCM_TX_RCB_OFFS ),
+ (uint32_t) BCM_NIC_TX_OFFS );
+
+ if( IS_5704 || IS_5703 ) {
+ // 5704: length field = max buffer len
+ i = (uint32_t) BCM_BUF_SIZE << 16;
+ } else {
+ // 5714: length field = number of ring entries
+ i = (uint32_t) BCM_TX_RING_SIZE << 16;
+ }
+
+ i &= ( uint32_t ) ~RCB_FLAG_RING_DISABLED;
+ bcm_write_mem32( BCM_RCB_LENFLAG_u16( BCM_TX_RCB_OFFS ), i );
+
+ /*
+ * remember the next bd index to be used
+ * & number of available buffers
+ */
+ bcm_tx_stop_u32 = BCM_MAX_TX_BUF;
+ bcm_tx_bufavail_u32 = BCM_MAX_TX_BUF;
+}
+
+static int32_t
+bcm_mac_init( uint8_t *f_mac_pu08 )
+{
+ static const uint16_t MEM_MAC_LO = (uint16_t) 0x0c18;
+ static const uint16_t MEM_MAC_HI = (uint16_t) 0x0c14;
+
+ uint32_t NVR_MAC_LO = (uint16_t) 0x80;
+ uint32_t NVR_MAC_HI = (uint16_t) 0x7c;
+
+ bcm_addr64_t l_mac_st;
+ uint32_t i;
+ uint32_t v;
+
+ /*
+ * Use MAC address from device tree if possible
+ */
+ for( i = 0, v = 0; i < 6; i++ ) {
+ v += (uint32_t) f_mac_pu08[i];
+ }
+
+ if( v != 0 ) {
+ l_mac_st.m_hi_u32 = ( ( (uint32_t) f_mac_pu08[0]) << 8 );
+ l_mac_st.m_hi_u32 |= ( ( (uint32_t) f_mac_pu08[1]) << 0 );
+ l_mac_st.m_lo_u32 = ( ( (uint32_t) f_mac_pu08[2]) << 24 );
+ l_mac_st.m_lo_u32 |= ( ( (uint32_t) f_mac_pu08[3]) << 16 );
+ l_mac_st.m_lo_u32 |= ( ( (uint32_t) f_mac_pu08[4]) << 8 );
+ l_mac_st.m_lo_u32 |= ( ( (uint32_t) f_mac_pu08[5]) << 0 );
+ } else {
+ /*
+ * try to read MAC address from MAC mailbox
+ */
+ l_mac_st.m_hi_u32 = bcm_read_mem32( MEM_MAC_HI );
+
+ if( ( l_mac_st.m_hi_u32 >> 16 ) == (uint32_t) 0x484b ) {
+ l_mac_st.m_hi_u32 &= (uint32_t) 0xffff;
+ l_mac_st.m_lo_u32 = bcm_read_mem32( MEM_MAC_LO );
+ } else {
+ int32_t l_err_i32;
+
+ /*
+ * otherwise retrieve MAC address from NVRam
+ */
+ if( ( bcm_read_reg32( MAC_FUNC_R ) & BIT32( 2 ) ) != 0 ) {
+ // secondary MAC is in use, address in NVRAM changes
+ NVR_MAC_LO += 0x50;
+ NVR_MAC_HI += 0x50;
+ }
+
+ l_err_i32 = bcm_nvram_read( NVR_MAC_LO, &l_mac_st.m_lo_u32, 1 );
+ l_err_i32 += bcm_nvram_read( NVR_MAC_HI, &l_mac_st.m_hi_u32, 1 );
+
+ // return on read error
+ if( l_err_i32 < 0 ) {
+#ifdef BCM_DEBUG
+ printf( "bcm57xx: failed to retrieve MAC address\n" );
+#endif
+ return -1;
+ }
+ }
+ }
+
+ /*
+ * write the mac addr into the NIC's register area
+ */
+ bcm_write_reg32( MAC_ADDR_OFFS_HI(0), l_mac_st.m_hi_u32 );
+ bcm_write_reg32( MAC_ADDR_OFFS_LO(0), l_mac_st.m_lo_u32 );
+ for( i = 1; i < BCM_NUM_MAC_ADDR; i++ ) {
+ bcm_write_reg32( MAC_ADDR_OFFS_HI(i), 0 );
+ bcm_write_reg32( MAC_ADDR_OFFS_LO(i), 0 );
+ }
+
+ /*
+ * WY 26.01.07
+ * not needed anymore, s.a.
+ if( IS_5704 != 0 ) {
+
+ v = MAC5704_ADDR_OFFS;
+ for( i = 0; i < BCM_NUM_MAC5704_ADDR; i++ ) {
+ bcm_write_reg32( v, l_mac_st.m_hi_u32 );
+ v += sizeof( uint32_t );
+ bcm_write_reg32( v, l_mac_st.m_lo_u32 );
+ v += sizeof( uint32_t );
+ }
+
+ }
+ */
+
+ /*
+ * return MAC address as string
+ */
+ f_mac_pu08[0] = (uint8_t) ( ( l_mac_st.m_hi_u32 >> 8 ) & (uint32_t) 0xff );
+ f_mac_pu08[1] = (uint8_t) ( ( l_mac_st.m_hi_u32 ) & (uint32_t) 0xff );
+ f_mac_pu08[2] = (uint8_t) ( ( l_mac_st.m_lo_u32 >> 24 ) & (uint32_t) 0xff );
+ f_mac_pu08[3] = (uint8_t) ( ( l_mac_st.m_lo_u32 >> 16 ) & (uint32_t) 0xff );
+ f_mac_pu08[4] = (uint8_t) ( ( l_mac_st.m_lo_u32 >> 8 ) & (uint32_t) 0xff );
+ f_mac_pu08[5] = (uint8_t) ( ( l_mac_st.m_lo_u32 ) & (uint32_t) 0xff );
+
+#ifdef BCM_DEBUG
+ do {
+ int32_t i;
+ printf( "bcm57xx: retrieved MAC address " );
+
+ for( i = 0; i < 6; i++ ) {
+ printf( "%02X", f_mac_pu08[i] );
+
+ if( i != 5 ) {
+ printf( ":" );
+ }
+
+ }
+
+ printf( "\n" );
+ } while( 0 );
+#endif
+
+ return 0;
+}
+
+
+/*
+ ******************************************************************************
+ * ASF Firmware
+ ******************************************************************************
+ */
+
+
+#ifdef BCM_DEBUG
+#ifdef BCM_SHOW_ASF_REGS
+static void
+bcm_asf_check_register( void )
+{
+ uint32_t i;
+
+ i = bcm_read_reg32( ASF_CTRL_R );
+ printf( "bcm57xx: ASF control : %x\n", i );
+
+ i = bcm_read_reg32( ASF_WATCHDOG_TIMER_R );
+ printf( "bcm57xx: ASF Watchdog Timer : %x\n", i );
+
+ i = bcm_read_reg32( ASF_HEARTBEAT_TIMER_R );
+ printf( "bcm57xx: ASF Heartbeat Timer : %x\n", i );
+
+ i = bcm_read_reg32( ASF_POLL_TIMER_R );
+ printf( "bcm57xx: ASF Poll Timer : %x\n", i );
+
+ i = bcm_read_reg32( POLL_LEGACY_TIMER_R );
+ printf( "bcm57xx: Poll Legacy Timer : %x\n", i );
+
+ i = bcm_read_reg32( RETRANSMISSION_TIMER_R );
+ printf( "bcm57xx: Retransmission Timer : %x\n", i );
+
+ i = bcm_read_reg32( TIME_STAMP_COUNTER_R );
+ printf( "bcm57xx: Time Stamp Counter : %x\n", i );
+
+ i = bcm_read_reg32( RX_CPU_MODE_R );
+ printf( "bcm57xx: RX RISC Mode : %x\n", i );
+
+ i = bcm_read_reg32( RX_CPU_STATE_R );
+ printf( "bcm57xx: RX RISC State : %x\n", i );
+
+ i = bcm_read_reg32( RX_CPU_PC_R );
+ printf( "bcm57xx: RX RISC Prg. Counter : %x\n", i );
+}
+#endif
+#endif
+
+static int
+bcm_fw_halt( void )
+{
+ int i;
+
+ bcm_write_mem32( BCM_FW_MBX_CMD, BCM_NICDRV_PAUSE_FW );
+ bcm_setb_reg32( RX_CPU_EVENT_R, BIT32( 14 ) );
+
+ /* Wait for RX cpu to ACK the event. */
+ for (i = 0; i < 100; i++) {
+ if(bcm_read_reg32( RX_CPU_EVENT_R ) & BIT32( 14 ))
+ break;
+ SLOF_msleep(1);
+ }
+ if( i>= 100)
+ return -1;
+ return 0;
+}
+
+
+#ifdef BCM_SW_AUTONEG
+static void
+bcm_sw_autoneg( void ) {
+ uint32_t i, j, k;
+ uint32_t SerDesCfg;
+ uint32_t SgDigControl;
+ uint32_t SgDigStatus;
+ uint32_t ExpectedSgDigControl;
+ int AutoNegJustInitiated = 0;
+
+ // step 1: init TX 1000BX Autoneg. Register to zero
+ bcm_write_reg32(TX_1000BX_AUTONEG_R, 0);
+
+ // step 2&3: set TBI mode
+ bcm_setb_reg32( ETH_MAC_MODE_R, BIT32( 2 ) | BIT32( 3 ) );
+ SLOF_usleep(10);
+
+ // step 4: enable link attention
+ bcm_setb_reg32( ETH_MAC_EVT_EN_R, BIT32( 12 ) );
+
+ // step 5: preserve voltage regulator bits
+ SerDesCfg = bcm_read_reg32(SERDES_CTRL_R) & ( BIT32( 20 ) | BIT32( 21 )
+ | BIT32( 22 ) | BIT32( 23 ) );
+
+ // step 6: preserve voltage regulator bits
+ SgDigControl = bcm_read_reg32(HW_AUTONEG_CTRL_R);
+
+ // step 7: if device is NOT set-up for auto negotiation, then go to step 26
+ // goto bcm_setup_phy_step26;
+
+ // We want to use auto negotiation
+
+ // step 8: we don't want to use flow control
+ ExpectedSgDigControl = 0x81388400; // no flow control
+
+ // step 9: compare SgDigControl with 0x81388400
+ if(SgDigControl == ExpectedSgDigControl) {
+ goto bcm_setup_phy_step17;
+ }
+#ifdef BCM_DEBUG
+ printf("bcm57xx: SgDigControl = %08X\n", SgDigControl);
+#endif
+ // step 10
+ bcm_write_reg32(SERDES_CTRL_R, SerDesCfg | 0xC011880);
+
+ // step 11: restart auto negotiation
+ bcm_write_reg32(HW_AUTONEG_CTRL_R, ExpectedSgDigControl | BIT32( 30 ) );
+
+ // step 12: read back HW_AUTONEG_CTRL_R
+ bcm_read_reg32(HW_AUTONEG_CTRL_R);
+
+ // step 13
+ SLOF_usleep( 5 );
+
+ // step 14,15,16: same as step 11, but don't restart auto neg.
+ bcm_write_reg32(HW_AUTONEG_CTRL_R, ExpectedSgDigControl);
+ AutoNegJustInitiated = 1;
+ goto bcm_setup_phy_step30;
+
+ // step 17:
+ bcm_setup_phy_step17:
+ if( ( bcm_read_reg32(ETH_MAC_STAT_R) & ( BIT32( 1 ) | BIT32( 0 ) ) ) == 0 ) {
+ goto bcm_setup_phy_step30;
+ }
+
+ // step 18: Get HW Autoneg. Status
+ SgDigStatus = bcm_read_reg32(HW_AUTONEG_STAT_R);
+
+ // step 19:
+ if( ( SgDigStatus & BIT32(1) )
+ && ( bcm_read_reg32(ETH_MAC_STAT_R) & BIT32(0) ) ) {
+ // resolve the current flow control?
+ AutoNegJustInitiated = 0;
+ goto bcm_setup_phy_step30;
+ }
+
+ // step 20
+ if( SgDigStatus & BIT32(1) ) {
+ goto bcm_setup_phy_step30;
+ }
+ if( AutoNegJustInitiated != 0) {
+ AutoNegJustInitiated = 0;
+ goto bcm_setup_phy_step29;
+ }
+
+ // step 21, 22, 23, 24: fallback to 1000Mbps-FullDuplex forced mode
+ if( ( bcm_read_reg32( MAC_FUNC_R ) & BIT32( 2 ) ) == 0 ) {
+ // port 0
+ bcm_write_reg32( SERDES_CTRL_R, 0xC010880 );
+ }
+ else { // port 1
+ bcm_write_reg32( SERDES_CTRL_R, 0x4010880 );
+ }
+ // set to 1000Mbps-FullDuplex
+ bcm_write_reg32(HW_AUTONEG_CTRL_R, 0x1388400);
+ // read back
+ bcm_read_reg32(HW_AUTONEG_CTRL_R);
+ SLOF_usleep( 40 );
+
+ // step 25: a little bit reduces...
+ goto bcm_setup_phy_step30;
+
+ // step 26: check if auto negotiation bit is NOT set
+// bcm_setup_phy_step26:
+ if( ( SgDigControl & BIT32(31) )== 0 ) {
+ printf("No autoneg.\n");
+ goto bcm_setup_phy_step29;
+ }
+
+ // step 27:
+ if( ( bcm_read_reg32( MAC_FUNC_R ) & BIT32( 2 ) ) == 0 ) {
+ // port 0
+ bcm_write_reg32( SERDES_CTRL_R, 0xC010880 );
+ }
+ else { // port 1
+ bcm_write_reg32( SERDES_CTRL_R, 0x4010880 );
+ }
+
+ // step 28: disable auto neg. and force 1000FD mode
+ bcm_write_reg32(HW_AUTONEG_CTRL_R, 0x1388400);
+
+ // step 29-31: omitted for 5704S
+ bcm_setup_phy_step29:
+ bcm_setup_phy_step30:
+
+ // step 32: clear link attentions
+ i = bcm_read_reg32( ETH_MAC_STAT_R ) | BIT32( 3 ) | BIT32( 4 );
+ k = 100;
+ do {
+ bcm_write_reg32( ETH_MAC_STAT_R, i );
+ j = bcm_read_reg32( ETH_MAC_STAT_R );
+ if( ( j & BIT32( 3 ) ) != 0 )
+ i = i & ~(BIT32( 3 ));
+ if( ( j & BIT32( 4 ) ) != 0 )
+ i = i & ~(BIT32( 4 ));
+ --k;
+ } while( i & k);
+
+ // step 33
+ if( ( bcm_read_reg32( ETH_MAC_STAT_R ) & BIT32( 0 ) ) == 0 ) {
+ goto bcm_setup_phy_step35;
+ }
+
+ // step 34
+ i = bcm_read_reg32( ETH_MAC_MODE_R );
+ i|= BIT32( 17 );
+ bcm_write_reg32( ETH_MAC_MODE_R, i );
+
+ SLOF_usleep( 1 );
+
+ i = bcm_read_reg32( ETH_MAC_STAT_R );
+ i&= ~BIT32( 17 );
+ bcm_write_reg32( ETH_MAC_STAT_R, i );
+
+ // step 35 & 36: done
+ bcm_setup_phy_step35:
+#ifdef BCM_DEBUG
+ printf("bcm57xx: SetupPhy\n");
+#endif
+ return;
+}
+#endif
+
+static int
+bcm_handle_events( void ) {
+#ifdef BCM_DEBUG
+#ifdef BCM_SHOW_ASF_REGS
+ // ASF REGISTER CHECK
+ // ------------------
+ // check if watchdog timer expired
+ if( bcm_read_reg32( ASF_WATCHDOG_TIMER_R ) == 0 ) {
+ // Show ASF registers
+ bcm_asf_check_register();
+
+ // rearm watchdog timer
+ bcm_write_reg32( ASF_WATCHDOG_TIMER_R, 5 );
+ }
+#endif
+#endif
+
+#ifdef BCM_SW_AUTONEG
+ // AUTO NEGOTIATION
+ // ----------------
+
+ // Check event for Auto Negotiation
+ if( ( bcm_read_reg32( ETH_MAC_STAT_R ) &
+ ( BIT32( 12 ) | BIT32( 3 ) | BIT32( 0 ) ) ) != 0 ) {
+ // link timer procedure
+ bcm_sw_autoneg();
+ }
+#endif
+
+ // ASF FW HEARTBEAT
+ // ----------------
+
+ // check if heartsbeat timer expired
+ if( bcm_read_reg32( ASF_HEARTBEAT_TIMER_R ) <= 2) {
+ int i;
+
+ // Send heartbeat event
+ bcm_write_mem32( BCM_FW_MBX_CMD, BCM_NICDRV_ALIVE );
+ bcm_write_mem32( BCM_FW_MBX_LEN, 4 );
+ bcm_write_mem32( BCM_FW_MBX_DATA, 5 );
+ bcm_setb_reg32( RX_CPU_EVENT_R, BIT32( 14 ) );
+
+ // Wait for RX cpu to ACK the event.
+ for (i = 100; i > 0; i--) {
+ if(bcm_read_reg32( RX_CPU_EVENT_R ) & BIT32( 14 ))
+ break;
+ SLOF_msleep(1);
+ }
+ if( i == 0) {
+#ifdef BCM_DEBUG
+ printf( "bcm57xx: RX cpu did not acknowledge heartbeat event\n" );
+#endif
+ return -1;
+ }
+
+ // rearm heartbeat timer
+ bcm_write_reg32( ASF_HEARTBEAT_TIMER_R, 5 );
+ }
+ return 0;
+}
+
+/*
+ * interface
+ ******************************************************************************
+ */
+
+/*
+ * bcm_receive
+ */
+static int
+bcm_receive( char *f_buffer_pc, int f_len_i )
+{
+ uint32_t l_rxret_prod_u32 = bcm_read_reg32( RXRET_PROD_IND );
+ uint32_t l_rxret_cons_u32 = bcm_read_reg32( RXRET_CONS_IND );
+ uint32_t l_rxprod_prod_u32 = bcm_read_reg32( RXPROD_PROD_IND );
+ int l_ret_i;
+#ifdef BCM_DEBUG
+#ifdef BCM_SHOW_RCV_DATA
+ int i, j;
+#endif
+#endif
+
+ /*
+ * NOTE: dummy read to ensure data has already been DMA'd is
+ * done by the indice reads
+ */
+
+ bcm_handle_events();
+
+ /*
+ * if producer index == consumer index then nothing was received
+ */
+ if( l_rxret_prod_u32 == l_rxret_cons_u32 ) {
+ return 0;
+ }
+
+ /*
+ * discard erroneous packets
+ */
+ if( ( bcm_rxret_ring[l_rxret_cons_u32].m_typeflags_u32 & BIT32( 10 ) ) != 0 ) {
+#ifdef BCM_DEBUG
+ printf( "bcm57xx: erroneous frame received\n" );
+ printf( " : frame discarded\n" );
+#endif
+ l_ret_i = 0;
+ } else {
+ /*
+ * get packet length, throw away checksum (last 4 bytes)
+ */
+ l_ret_i = (int) ( bcm_rxret_ring[l_rxret_cons_u32].m_idxlen_u32 &
+ (uint32_t) 0xffff ) - (int) 4;
+
+ /*
+ * discard oversized packets
+ */
+ if( l_ret_i > f_len_i ) {
+#ifdef BCM_DEBUG
+ printf( "bcm57xx: receive packet length error:\n" );
+ printf( " : incoming 0x%X bytes, available buffer 0x%X bytes\n", l_ret_i, f_len_i );
+ printf( " : frame discarded\n" );
+#endif
+ l_ret_i = 0;
+ }
+
+ }
+
+ /*
+ * copy & update data & indices
+ */
+ if( l_ret_i != 0 ) {
+ uint64_t l_cpyaddr_u64;
+
+ l_cpyaddr_u64 =
+ ( (uint64_t) bcm_rxret_ring[l_rxret_cons_u32].m_hostaddr_st.m_hi_u32 << 32 );
+ l_cpyaddr_u64 +=
+ ( (uint64_t) bcm_rxret_ring[l_rxret_cons_u32].m_hostaddr_st.m_lo_u32 );
+
+// FIXME:
+ if(l_cpyaddr_u64 == 0) {
+#ifdef BCM_DEBUG
+ printf("bcm57xx: NULL address\n");
+#endif
+ return 0;
+ }
+//
+ memcpy( (void *) f_buffer_pc,
+ (void *) l_cpyaddr_u64,
+ (size_t) l_ret_i );
+
+ }
+
+ /*
+ * replenish bd to producer ring
+ */
+ bcm_rxprod_ring[l_rxprod_prod_u32] =
+ bcm_rxret_ring[l_rxret_cons_u32];
+ bcm_rxprod_ring[l_rxprod_prod_u32].m_idxlen_u32 =
+ ( l_rxprod_prod_u32 << 16 );
+ bcm_rxprod_ring[l_rxprod_prod_u32].m_idxlen_u32 +=
+ (uint32_t) BCM_BUF_SIZE;
+
+ /*
+ * update producer ring's producer index
+ */
+ l_rxprod_prod_u32 = ( l_rxprod_prod_u32 + 1 ) & ( BCM_RXPROD_RING_SIZE - 1 );
+
+ /*
+ * move to the next bd in return ring
+ */
+ l_rxret_cons_u32 = ( l_rxret_cons_u32 + 1 ) & ( bcm_rxret_ring_sz - 1 );
+
+ /*
+ * synchronize before new indices are send to NIC
+ */
+ mb();
+
+ /*
+ * write back new indices
+ */
+ bcm_write_reg32( RXRET_CONS_IND, l_rxret_cons_u32 );
+ bcm_write_reg32( RXPROD_PROD_IND, l_rxprod_prod_u32 );
+
+#ifdef BCM_DEBUG
+#ifdef BCM_SHOW_RCV
+ if( l_ret_i != 0 ) {
+ printf( "bcm57xx: received bytes: %d\n", l_ret_i );
+ }
+#ifdef BCM_SHOW_RCV_DATA
+ for( i = 0, j = 0; i < l_ret_i; i++ ) {
+ printf( "%02X ", ( uint32_t ) f_buffer_pc[i] );
+
+ if( ( ++j % 0x18 ) == 0 ) {
+ printf( "\n" );
+ }
+ }
+
+ if( ( i % 0x18 ) != 0 ) {
+ printf( "\n" );
+ }
+#endif
+#endif
+#endif
+
+ /*
+ * return packet length
+ */
+ return l_ret_i;
+}
+
+static int
+bcm_xmit( char *f_buffer_pc, int f_len_i )
+{
+ uint32_t l_tx_cons_u32 = bcm_read_reg32( TX_CONS_IND );
+ uint32_t l_tx_prod_u32 = bcm_read_reg32( TX_PROD_IND );
+ uint64_t l_cpyaddr_u64;
+
+#ifdef BCM_DEBUG
+#ifdef BCM_SHOW_XMIT_DATA
+ int i, j;
+#endif
+#ifdef BCM_SHOW_IDX
+ printf( "\n" );
+ printf( "bcm57xx: TX_PROD_IND : 0x%03X\n", l_tx_prod_u32 );
+ printf( "bcm57xx: TX_CONS_IND : 0x%03X\n", l_tx_cons_u32 );
+ printf( "bcm57xx: RXPROD_PROD_IND: 0x%03X\n", bcm_read_reg32( RXPROD_PROD_IND ) );
+ printf( "bcm57xx: RXPROD_CONS_IND: 0x%03X\n", bcm_read_reg32( RXPROD_CONS_IND ) );
+ printf( "bcm57xx: RXRET_PROD_IND : 0x%03X\n", bcm_read_reg32( RXRET_PROD_IND ) );
+ printf( "bcm57xx: RXRET_CONS_IND : 0x%03X\n", bcm_read_reg32( RXRET_CONS_IND ) );
+ printf( "bcm57xx: available txb : 0x%03X\n", bcm_tx_bufavail_u32 );
+#endif
+#ifdef BCM_SHOW_STATS
+ printf( "bcm57xx: bcm_status.m_st_word_u32: %08X\n", bcm_status.m_st_word_u32 );
+ printf( "bcm57xx: bcm_status.m_st_tag_u32 : %08X\n", bcm_status.m_st_tag_u32 );
+ printf( "bcm57xx: bcm_status.m_rxprod_cons_u16: %04X\n", ( uint32_t ) bcm_status.m_rxprod_cons_u16 );
+ printf( "bcm57xx: bcm_status.m_unused_u16: %04X\n", ( uint32_t ) bcm_status.m_unused_u16 );
+ printf( "bcm57xx: bcm_status.m_unused_u32: %08X\n", bcm_status.m_unused_u32 );
+ printf( "bcm57xx: bcm_status.m_tx_cons_u16: %04X\n", ( uint32_t ) bcm_status.m_tx_cons_u16 );
+ printf( "bcm57xx: bcm_status.m_rxret_prod_u16: %04X\n", ( uint32_t ) bcm_status.m_rxret_prod_u16 );
+#endif
+#endif
+
+ bcm_handle_events();
+
+ /*
+ * make all consumed bd's available in the ring again
+ * this way only a few buffers are needed instead of
+ * having 512 buffers allocated
+ */
+ while( bcm_tx_start_u32 != l_tx_cons_u32 ) {
+ bcm_tx_ring[bcm_tx_stop_u32] = bcm_tx_ring[bcm_tx_start_u32];
+ bcm_tx_stop_u32 = ( bcm_tx_stop_u32 + 1 ) & ( BCM_TX_RING_SIZE - 1 );
+ bcm_tx_start_u32 = ( bcm_tx_start_u32 + 1 ) & ( BCM_TX_RING_SIZE - 1 );
+ bcm_tx_bufavail_u32++;
+ }
+
+ /*
+ * check for tx buffer availability
+ */
+ if( bcm_tx_bufavail_u32 == 0 ) {
+#ifdef BCM_DEBUG
+ printf( "bcm57xx: no more transmit buffers available\n" );
+#endif
+ return 0;
+ }
+
+ /*
+ * setup next available bd in tx ring
+ */
+ bcm_tx_ring[l_tx_prod_u32].m_lenflags_u32 = ( BIT32( 2 ) | BIT32( 7 ) /*| BIT32( 6 )*/ );
+ bcm_tx_ring[l_tx_prod_u32].m_lenflags_u32 += ( (uint32_t) f_len_i << 16 );
+// bcm_tx_ring[l_tx_prod_u32].m_VLANtag_u32 = BCM_VLAN_TAG;
+
+ l_cpyaddr_u64 = ( (uint64_t) bcm_tx_ring[l_tx_prod_u32].m_hostaddr_st.m_hi_u32 << 32 );
+ l_cpyaddr_u64 += ( (uint64_t) bcm_tx_ring[l_tx_prod_u32].m_hostaddr_st.m_lo_u32 );
+
+#ifdef BCM_DEBUG
+#ifdef BCM_SHOW_XMIT_STATS
+ printf("bcm57xx: xmit: l_cpyaddr_u64: 0x%lx\n", l_cpyaddr_u64 );
+ printf(" f_buffer_pc : 0x%lx\n", f_buffer_pc );
+ printf(" f_len_i : %d\n", f_len_i );
+#endif
+#endif
+ memcpy( (void *) l_cpyaddr_u64, (void *) f_buffer_pc, (size_t) f_len_i );
+
+ /*
+ * update tx producer index & available buffers
+ */
+ l_tx_prod_u32 = ( l_tx_prod_u32 + 1 ) & ( BCM_TX_RING_SIZE - 1 );
+ bcm_tx_bufavail_u32--;
+
+ /*
+ * synchronize before new index is send to NIC
+ */
+ mb();
+
+ bcm_write_reg32( TX_PROD_IND, l_tx_prod_u32 );
+
+#ifdef BCM_DEBUG
+#ifdef BCM_SHOW_XMIT
+ printf( "bcm57xx: sent bytes: %d\n", f_len_i );
+#ifdef BCM_SHOW_XMIT_DATA
+ for( i = 0, j = 0; i < f_len_i; i++ ) {
+ printf( "%02X ", ( uint32_t ) f_buffer_pc[i] );
+
+ if( ( ++j % 0x18 ) == 0 ) {
+ printf( "\n" );
+ }
+
+ }
+ if( ( i % 0x18 ) != 0 ) {
+ printf( "\n" );
+ }
+#endif
+#endif
+
+#ifdef BCM_SHOW_STATS
+ // coalesce status block now
+ bcm_setb_reg32( HOST_COAL_MODE_R, BIT32( 3 ) | BIT32( 1 ) );
+#endif
+
+#endif
+ return f_len_i;
+}
+
+static int
+check_driver( uint16_t vendor_id, uint16_t device_id )
+{
+ uint64_t i;
+
+ /*
+ * checks whether the driver is handling this device
+ * by verifying vendor & device id
+ * vendor id 0x14e4 == Broadcom
+ */
+ if( vendor_id != 0x14e4 ) {
+#ifdef BCM_DEBUG
+ printf( "bcm57xx: netdevice not supported, illegal vendor id\n" );
+#endif
+ return -1;
+ }
+
+ for( i = 0; bcm_dev[i].m_dev_u32 != 0; i++ ) {
+ if( bcm_dev[i].m_dev_u32 == (uint32_t) device_id ) {
+ // success
+ break;
+ }
+ }
+
+ if(bcm_dev[i].m_dev_u32 == 0) {
+#ifdef BCM_DEBUG
+ printf( "bcm57xx: netdevice not supported, illegal device ID\n" );
+#endif
+ return -1;
+ }
+
+ /*
+ * initialize static variables
+ */
+ bcm_device_u64 = bcm_dev[i].m_devmsk_u64;
+ bcm_rxret_ring_sz = 0;
+ bcm_baseaddr_u64 = 0;
+ bcm_memaddr_u64 = 0;
+
+ bcm_tx_start_u32 = 0;
+ bcm_tx_stop_u32 = 0;
+ bcm_tx_bufavail_u32 = 0;
+
+ return 0;
+}
+
+static void
+bcm_wol_activate(void)
+{
+#ifdef BCM_DEBUG
+ uint16_t reg_pwr_cap;
+#endif
+ uint16_t reg_pwr_crtl;
+ uint32_t wol_mode;
+
+ wol_mode = bcm_read_reg32( WOL_MODE_R );
+ bcm_write_reg32( WOL_MODE_R, wol_mode | BIT32(0) );
+
+#ifdef BCM_DEBUG
+ printf( "bcm57xx: WOL activating..." );
+#endif
+
+// bcm_write_mem32( BCM_NICDRV_STATE_MBX, NIC_FWDRV_STATE_WOL );
+// SLOF_msleep( 100 );
+
+#ifdef BCM_DEBUG
+ reg_pwr_cap = SLOF_pci_config_read16(0x4a);
+ /*reg_pwr_cap = snk_kernel_interface->pci_config_read( bcm_pcicfg_puid,
+ 2,
+ bcm_pcicfg_bus,
+ bcm_pcicfg_devfn,
+ 0x4a );*/
+ printf( "bcm57xx: PM Capability Register: %04X\n", reg_pwr_cap );
+#endif
+ /* get curretn power control register */
+ reg_pwr_crtl = SLOF_pci_config_read16(0x4c);
+ /*reg_pwr_crtl = snk_kernel_interface->pci_config_read( bcm_pcicfg_puid,
+ 2,
+ bcm_pcicfg_bus,
+ bcm_pcicfg_devfn,
+ 0x4c );*/
+
+#ifdef BCM_DEBUG
+ printf( "bcm57xx: PM Control/Status Register: %04X\n", reg_pwr_crtl );
+#endif
+
+ /* switch to power state D0 */
+ reg_pwr_crtl |= 0x8000;
+ reg_pwr_crtl &= ~(0x0003);
+ SLOF_pci_config_write16(0x4c, reg_pwr_crtl);
+ /*snk_kernel_interface->pci_config_write( bcm_pcicfg_puid,
+ 2,
+ bcm_pcicfg_bus,
+ bcm_pcicfg_devfn,
+ 0x4c,
+ reg_pwr_crtl );*/
+ SLOF_msleep(10);
+
+/*
+ bcm_write_mem32( BCM_NICDRV_WOL_MBX, BCM_WOL_MAGIC_NUMBER |
+ NIC_WOLDRV_STATE_SHUTDOWN |
+ NIC_WOLDRV_WOL |
+ NIC_WOLDRV_SET_MAGIC_PKT );
+*/
+
+ /* switch to power state D3hot */
+/*
+ reg_pwr_crtl |= 0x0103;
+ SLOF_pci_config_write16(0x4c, reg_pwr_crtl);
+ snk_kernel_interface->pci_config_write( bcm_pcicfg_puid,
+ 2,
+ bcm_pcicfg_bus,
+ bcm_pcicfg_devfn,
+ 0x4c,
+ reg_pwr_crtl );
+ SLOF_msleep(10);
+*/
+
+#ifdef BCM_DEBUG
+ reg_pwr_crtl = SLOF_pci_config_read16(0x4c);
+ /*reg_pwr_crtl = snk_kernel_interface->pci_config_read( bcm_pcicfg_puid,
+ 2,
+ bcm_pcicfg_bus,
+ bcm_pcicfg_devfn,
+ 0x4c );*/
+
+ printf( "bcm57xx: PM Control/Status Register: %04X\n", reg_pwr_crtl );
+#endif
+
+#ifdef BCM_DEBUG
+ printf( "bcm57xx: WOL activated" );
+#endif
+}
+
+static int
+bcm_init( net_driver_t *driver )
+{
+ static const uint32_t lc_Maxwait_u32 = (uint32_t) 1000;
+ uint32_t l_baseaddrL_u32;
+ uint32_t l_baseaddrH_u32;
+ uint32_t i;
+ uint8_t *mac_addr = driver->mac_addr;
+
+ if(driver->running != 0) {
+ return 0;
+ }
+#ifdef BCM_DEBUG
+ printf( "bcm57xx: detected device " );
+ if( IS_5703 ) {
+ printf( "5703S\n" );
+ } else if( IS_5704 ) {
+ printf( "5704" );
+
+ if( IS_SERDES ) {
+ printf( "S\n" );
+ } else {
+ printf( "C\n" );
+ }
+
+ } else if( IS_5714 ) {
+ printf( "5714\n" );
+ }
+#endif
+ /*
+ * setup register & memory base addresses of NIC
+ */
+ l_baseaddrL_u32 = (uint32_t) ~0xf &
+ (uint32_t) SLOF_pci_config_read32(PCI_BAR1_R);
+ /*l_baseaddrL_u32 = ( (uint32_t) ~0xf &
+ (uint32_t) snk_kernel_interface->pci_config_read( bcm_pcicfg_puid,
+ 4,
+ bcm_pcicfg_bus,
+ bcm_pcicfg_devfn,
+ PCI_BAR1_R ) );*/
+
+ l_baseaddrH_u32 = (uint32_t) SLOF_pci_config_read32(PCI_BAR2_R);
+ /*l_baseaddrH_u32 =
+ (uint32_t) snk_kernel_interface->pci_config_read( bcm_pcicfg_puid,
+ 4,
+ bcm_pcicfg_bus,
+ bcm_pcicfg_devfn,
+ PCI_BAR2_R );*/
+ bcm_baseaddr_u64 = (uint64_t) l_baseaddrH_u32;
+ bcm_baseaddr_u64 <<= 32;
+ bcm_baseaddr_u64 += (uint64_t) l_baseaddrL_u32;
+ bcm_baseaddr_u64 =
+ (uint64_t) SLOF_translate_my_address((void *)bcm_baseaddr_u64);
+ /*snk_kernel_interface->translate_addr(((void *)&(bcm_baseaddr_u64)));*/
+ bcm_memaddr_u64 = bcm_baseaddr_u64 + BCM_MEMORY_OFFS;
+
+#ifdef BCM_DEBUG
+ printf( "bcm57xx: device's register base high address = 0x%08X\n", l_baseaddrH_u32 );
+ printf( "bcm57xx: device's register base low address = 0x%08X\n", l_baseaddrL_u32 );
+ printf( "bcm57xx: device's register address = 0x%llx\n", bcm_baseaddr_u64 );
+#endif
+
+ /*
+ * 57xx hardware initialization
+ * BCM57xx Programmer's Guide: Section 8, "Initialization"
+ * steps 1 through 101
+ */
+
+ // step 1: enable bus master & memory space in command reg
+ i = ( BIT32( 10 ) | BIT32( 2 ) | BIT32( 1 ) );
+ SLOF_pci_config_write16(PCI_COM_R, i);
+ /*snk_kernel_interface->pci_config_write( bcm_pcicfg_puid,
+ 2,
+ bcm_pcicfg_bus,
+ bcm_pcicfg_devfn,
+ PCI_COM_R,
+ ( int ) i );*/
+ // step 2: disable & mask interrupts & enable pci byte/word swapping & enable indirect addressing mode
+ i = ( BIT32( 8 ) | BIT32( 7 ) | BIT32( 3 ) | BIT32( 2 ) | BIT32( 1 ) | BIT32( 0 ) );
+
+ SLOF_pci_config_write32(PCI_MISC_HCTRL_R, i);
+ /*snk_kernel_interface->pci_config_write( bcm_pcicfg_puid,
+ 4,
+ bcm_pcicfg_bus,
+ bcm_pcicfg_devfn,
+ PCI_MISC_HCTRL_R,
+ ( int ) i );*/
+
+ /*
+ * from now on access may be made through the local
+ * read/write functions
+ */
+
+ // step 3: Save ahche line size register
+ // omitted, because register is not used for 5704
+
+ // step 4: acquire the nvram lock
+ if( bcm_nvram_lock() != 0 ) {
+#ifdef BCM_DEBUG
+ printf( "bcm57xx: locking NVRAM failed\n" );
+#endif
+ return -1;
+ }
+
+ // step 5: prepare the chip for writing TG3_MAGIC_NUMBER
+ bcm_setb_reg32( MEMARB_MODE_R, BIT32( 1 ) );
+ i = ( BIT32( 8 ) | BIT32( 7 ) | BIT32( 3 ) | BIT32( 2 ) | BIT32( 1 ) | BIT32( 0 ) );
+ SLOF_pci_config_write32(PCI_MISC_HCTRL_R, i);
+ /*snk_kernel_interface->pci_config_write( bcm_pcicfg_puid,
+ 4,
+ bcm_pcicfg_bus,
+ bcm_pcicfg_devfn,
+ PCI_MISC_HCTRL_R,
+ ( int ) i );*/
+ bcm_write_reg32( MODE_CTRL_R, BIT32( 23 ) | BIT32( 20 ) |
+ BIT32( 17 ) | BIT32( 16 ) |
+ BIT32( 14 ) | BIT32( 13 ) |
+ BIT32( 5 ) | BIT32( 4 ) |
+ BIT32( 2 ) | BIT32( 1 ) );
+
+ // step 6: write TG3_MAGIC_NUMBER
+ bcm_write_mem32( BCM_FW_MBX, BCM_MAGIC_NUMBER );
+
+ // step 7: reset core clocks
+
+ if( IS_5714 ) {
+ bcm_setb_reg32( MISC_CFG_R, BIT32( 26 ) | BIT32( 0 ) );
+ } else {
+ bcm_setb_reg32( MISC_CFG_R, BIT32( 0 ) );
+ }
+ // step 8
+ SLOF_msleep( 20 );
+
+ // step 9: disable & mask interrupts & enable indirect addressing mode &
+ // enable pci byte/word swapping initialize the misc host control register
+ i = ( BIT32( 8 ) | BIT32( 7 ) | BIT32( 3 ) | BIT32( 2 ) | BIT32( 1 ) | BIT32( 0 ) );
+ SLOF_pci_config_write32(PCI_MISC_HCTRL_R, i);
+ /*snk_kernel_interface->pci_config_write( bcm_pcicfg_puid,
+ 4,
+ bcm_pcicfg_bus,
+ bcm_pcicfg_devfn,
+ PCI_MISC_HCTRL_R,
+ ( int ) i );*/
+
+ // step 10: set but master et cetera
+ i = ( BIT32( 10 ) | BIT32( 2 ) | BIT32( 1 ) );
+ SLOF_pci_config_write16(PCI_COM_R, i);
+ /*snk_kernel_interface->pci_config_write( bcm_pcicfg_puid,
+ 2,
+ bcm_pcicfg_bus,
+ bcm_pcicfg_devfn,
+ PCI_COM_R,
+ ( int ) i );*/
+
+ // step 11: disable PCI-X relaxed ordering
+ bcm_clrb_reg16( PCI_X_COM_R, BIT16( 1 ) );
+
+ // step 12: enable the MAC memory arbiter
+ bcm_setb_reg32( MEMARB_MODE_R, BIT32( 1 ) );
+
+ // step 13: omitted, only for BCM5700
+ // step 14: s. step 10
+ i = ( BIT32( 8 ) | BIT32( 7 ) | BIT32( 3 ) | BIT32( 2 ) | BIT32( 1 ) | BIT32( 0 ) );
+ SLOF_pci_config_write32(PCI_MISC_HCTRL_R, i);
+ /*snk_kernel_interface->pci_config_write( bcm_pcicfg_puid,
+ 4,
+ bcm_pcicfg_bus,
+ bcm_pcicfg_devfn,
+ PCI_MISC_HCTRL_R,
+ ( int ) i );*/
+ // step 15: set byte swapping (incl. step 27/28/29/30)
+ // included prohibition of tx/rx interrupts
+ bcm_write_reg32( MODE_CTRL_R, BIT32( 23 ) | BIT32( 20 ) |
+ BIT32( 17 ) | BIT32( 16 ) |
+ BIT32( 14 ) | BIT32( 13 ) |
+ BIT32( 5 ) | BIT32( 4 ) |
+ BIT32( 2 ) | BIT32( 1 ) );
+ // step 16: omitted
+ i = 1000;
+ while( ( --i ) &&
+ ( bcm_read_mem32( BCM_FW_MBX ) != ~BCM_MAGIC_NUMBER ) ) {
+#ifdef BCM_DEBUG
+ printf( "." );
+#endif
+ SLOF_msleep( 1 );
+ }
+
+ // return on error
+ if( bcm_read_mem32( BCM_FW_MBX ) != ~BCM_MAGIC_NUMBER ) {
+ printf( "bootcode not loaded: %x\n", bcm_read_mem32( BCM_FW_MBX ) );
+#ifdef BCM_DEBUG
+ printf( "failed\n" );
+#endif
+ return -1;
+ }
+
+
+ // if ASF Firmware enabled
+ bcm_write_mem32( BCM_NICDRV_STATE_MBX, NIC_FWDRV_STATE_START );
+ SLOF_msleep( 10 );
+
+ // step 17: write ethernet mac mode register
+ /*
+ * WY 07.02.07
+ * omitted for correct SOL function
+ */
+ /*
+ if( IS_SERDES ) {
+ bcm_write_reg32( ETH_MAC_MODE_R, (uint32_t) 0xc );
+ } else {
+ bcm_write_reg32( ETH_MAC_MODE_R, (uint32_t) 0x0 );
+ }
+ */
+
+ // step 18/19: omitted
+ // step 20: enable hw bugfix for 5704
+ if( IS_5704 || IS_5703 ) {
+ bcm_setb_reg32( MSG_DATA_R, BIT32( 26 ) |
+ BIT32( 28 ) |
+ BIT32( 29 ) );
+ }
+
+ // step 21: omitted
+ // step 22: omitted
+ // step 23: 5704 clear statistics block
+ if( IS_5703 || IS_5704 ) {
+ memset_ci( (void *) ( bcm_memaddr_u64 + BCM_STATISTIC_OFFS ),
+ 0,
+ BCM_STATISTIC_SIZE );
+ }
+
+ // step 24/25: omitted
+ // step 26: set DMA Read/Write Control register
+ // NOTE: recommended values from the spec are used here
+ if( IS_5714 ) {
+ bcm_write_reg32( DMA_RW_CTRL_R, DMA_RW_CTRL_VAL_5714 );
+ } else {
+ uint32_t l_PCIState_u32 = bcm_read_reg32( PCI_STATE_R );
+ uint32_t l_DMAVal_u32 = DMA_RW_CTRL_VAL;
+
+ if( ( l_PCIState_u32 & BIT32( 2 ) ) != 0 ) { // PCI
+ l_DMAVal_u32 |= (uint32_t) 0x300000;
+ } else { // PCI-X
+ l_DMAVal_u32 |= (uint32_t) 0x900000;
+
+ if( ( bcm_read_reg32( PCI_CLK_CTRL_R ) & (uint32_t) 0x1f )
+ >= (uint32_t) 6 ) {
+ l_DMAVal_u32 |= (uint32_t) 0x4000;
+ }
+
+ }
+
+ bcm_write_reg32( DMA_RW_CTRL_R, l_DMAVal_u32 );
+ }
+
+ // step 27/28/29: s. step 14
+
+ // step 30: Configure TCP/UDP pseudo header checksum offloading
+ // already done in step 14: offloading disabled
+
+ // step 31: setup timer prescaler
+ i = bcm_read_reg32( MISC_CFG_R );
+ i &= (uint32_t) ~0xfe; // clear bits 7-1 first
+ i |= ( BCM_TMR_PRESCALE << 1 );
+ bcm_write_reg32( MISC_CFG_R, i );
+
+ // step 32: 5703/4 configure Mbuf pool address/length
+ // step 33: 5703/4 configure MAC DMA resource pool
+ // step 34: configure MAC memory pool watermarks
+ // step 35: 5703/4 configure DMA resource watermarks
+ // using recommended settings (hard coded)
+ if( IS_5703 || IS_5704 ) {
+
+ if( IS_5703 ) {
+ bcm_write_reg32( MBUF_POOL_ADDR_R, (uint32_t) 0x8000 );
+ bcm_write_reg32( MBUF_POOL_LEN_R, (uint32_t) 0x18000 );
+ } else {
+ bcm_write_reg32( MBUF_POOL_ADDR_R, (uint32_t) 0x10000 );
+ bcm_write_reg32( MBUF_POOL_LEN_R, (uint32_t) 0x10000 );
+ }
+
+ bcm_write_reg32( DMA_DESC_POOL_ADDR_R, (uint32_t) 0x2000 );
+ bcm_write_reg32( DMA_DESC_POOL_LEN_R, (uint32_t) 0x2000 );
+
+ bcm_write_reg32( DMA_RMBUF_LOW_WMARK_R, (uint32_t) 0x50 );
+ bcm_write_reg32( MAC_RXMBUF_LOW_WMARK_R, (uint32_t) 0x20 );
+ bcm_write_reg32( MBUF_HIGH_WMARK_R, (uint32_t) 0x60 );
+
+ bcm_write_reg32( DMA_DESC_LOW_WM_R, (uint32_t) 5 );
+ bcm_write_reg32( DMA_DESC_HIGH_WM_R, (uint32_t) 10 );
+ } else {
+ bcm_write_reg32( DMA_RMBUF_LOW_WMARK_R, (uint32_t) 0x00 );
+ bcm_write_reg32( MAC_RXMBUF_LOW_WMARK_R, (uint32_t) 0x10 );
+ bcm_write_reg32( MBUF_HIGH_WMARK_R, (uint32_t) 0x60 );
+ }
+
+ // step 35: omitted
+ // step 36: Configure flow control behaviour
+ // using recommended settings (hard coded)
+ bcm_write_reg32( LOW_WMARK_MAX_RXFRAM_R, (uint32_t) 0x02 );
+
+ // step 37/38: enable buffer manager & wait for successful start
+ bcm_setb_reg32( BUF_MAN_MODE_R, BIT32( 2 ) | BIT32( 1 ) );
+
+ i = lc_Maxwait_u32;
+ while( ( --i ) &&
+ ( ( bcm_read_reg32( BUF_MAN_MODE_R ) & BIT32( 1 ) ) == 0 ) ) {
+ SLOF_usleep( 10 );
+ }
+
+ // return on error
+ if( i == 0 ) {
+#ifdef BCM_DEBUG
+ printf( "bcm57xx: init step 38: enable buffer manager failed\n" );
+#endif
+ return -1;
+ }
+
+ // step 39: enable internal hardware queues
+ bcm_write_reg32( FTQ_RES_R, (uint32_t) ~0 );
+ bcm_write_reg32( FTQ_RES_R, (uint32_t) 0 );
+
+ // step 40/41/42: initialize rx producer ring
+ bcm_init_rxprod_ring();
+
+ // step 43: set rx producer ring replenish threshold
+ // using recommended setting of maximum allocated BD's/8
+ bcm_write_reg32( STD_RXPR_REP_THR_R, (uint32_t) BCM_MAX_RX_BUF / 8 );
+
+ // step 44/45/46: initialize send rings
+ bcm_init_tx_ring();
+ bcm_init_rxret_ring();
+
+ // steps 47-50 done in ring init functions
+ // step 51: configure MAC unicast address
+ bcm_nvram_init();
+ if( bcm_mac_init( (uint8_t *) mac_addr ) < 0 ) {
+#ifdef BCM_DEBUG
+ printf( "bcm57xx: init step 51: configure MAC unicast address failed\n" );
+#endif
+ return -1;
+ }
+ memcpy(driver->mac_addr, mac_addr, 6);
+
+ // step 52: configure backoff random seed for transmit
+ // using recommended algorithm
+ i = (uint32_t) mac_addr[0] + (uint32_t) mac_addr[1] +
+ (uint32_t) mac_addr[2] + (uint32_t) mac_addr[3] +
+ (uint32_t) mac_addr[4] + (uint32_t) mac_addr[5];
+ i &= (uint32_t) 0x03ff;
+ bcm_write_reg32( ETH_TX_RND_BO_R, i );
+
+ // step 53: configure message transfer unit MTU size
+ bcm_write_reg32( RX_MTU_SIZE_R, (uint32_t) BCM_MTU_MAX_LEN );
+
+ // step 54: configure IPG for transmit
+ // using recommended value (through #define)
+ bcm_write_reg32( TX_MAC_LEN_R, TX_MAC_LEN_VAL );
+
+ // step 55: configure receive rules
+
+ // set RX rule default class
+ bcm_write_reg32( RX_RULE_CFG_R, RX_RULE_CFG_VAL );
+
+ // step 56: configure the number of receive lists
+ bcm_write_reg32( RX_LST_PLACE_CFG_R, RX_LST_PLC_CFG_VAL );
+ bcm_write_reg32( RX_LST_PLACE_STAT_EN_R, RX_LST_PLC_STAT_EN_VAL );
+
+/*
+ // rule 1: accept frames for our MAC address
+ bcm_write_reg32( RX_RULE_CTRL_R ( 0 ),
+ BIT32( 31 ) | // enable rule
+ BIT32( 30 ) | // and with next
+ BIT32( 26 ) | // split value register
+ BIT32( 8 ) ); // class 1
+ bcm_write_reg32( RX_RULE_VAL_R ( 0 ),
+ (uint32_t) 0xffff0000 |
+ ( bcm_read_reg32( MAC_ADDR_OFFS_HI(0) ) &
+ (uint32_t) 0xffff ) );
+
+ bcm_write_reg32( RX_RULE_CTRL_R ( 1 ),
+ BIT32( 31 ) | // enable rule
+ BIT32( 8 ) | // class 1
+ BIT32( 1 ) ); // offset 2
+ bcm_write_reg32( RX_RULE_VAL_R ( 1 ),
+ bcm_read_reg32( MAC_ADDR_OFFS_LO(0) ) );
+
+ // rule 2: accept broadcast frames
+ bcm_write_reg32( RX_RULE_CTRL_R ( 2 ),
+ BIT32( 31 ) | // enable rule
+ BIT32( 30 ) | // and with next
+ BIT32( 26 ) | // split value register
+ BIT32( 8 ) ); // class 1
+ bcm_write_reg32( RX_RULE_VAL_R ( 2 ),
+ (uint32_t) ~0 );
+
+ bcm_write_reg32( RX_RULE_CTRL_R ( 3 ),
+ BIT32( 31 ) | // enable rule
+ BIT32( 8 ) | // class 1
+ BIT32( 1 ) ); // offset 2
+ bcm_write_reg32( RX_RULE_VAL_R ( 3 ),
+ (uint32_t) ~0 );
+*/
+ for( i=0; i<NUM_RX_RULE_ASF; ++i) {
+ bcm_write_reg32( RX_RULE_CTRL_R ( i ), 0 );
+ bcm_write_reg32( RX_RULE_VAL_R ( i ), 0 );
+ }
+
+ // step 57-60: enable rx/tx statistics
+ // omitted, no need for statistics (so far)
+
+ // step 61/62: disable host coalescing engine/wait 20ms
+ bcm_write_reg32( HOST_COAL_MODE_R, (uint32_t) 0 );
+
+ i = lc_Maxwait_u32 * 2;
+ while( ( --i ) &&
+ ( bcm_read_reg32( HOST_COAL_MODE_R ) != 0 ) ) {
+ SLOF_usleep( 10 );
+ }
+
+ // return on error
+ if( i == 0 ) {
+#ifdef BCM_DEBUG
+ printf( "bcm57xx: init step 62: disable host coal. engine failed\n" );
+#endif
+ return -1;
+ }
+
+ // step 63-66: initialize coalescing engine
+ // NOTE: status block is unused in this driver,
+ // therefore the coal. engine status block
+ // automatic update is disabled (by writing
+ // 0 to every counter
+ bcm_write_reg32( RX_COAL_TICKS_R, 0 );
+ bcm_write_reg32( TX_COAL_TICKS_R, 0 );
+ bcm_write_reg32( RX_COAL_MAX_BD_R, 0 );
+ bcm_write_reg32( TX_COAL_MAX_BD_R, 0 );
+ bcm_write_reg32( RX_COAL_TICKS_INT_R, 0 );
+ bcm_write_reg32( TX_COAL_TICKS_INT_R, 0 );
+ bcm_write_reg32( RX_COAL_MAX_BD_INT_R, 0 );
+ bcm_write_reg32( TX_COAL_MAX_BD_INT_R, 0 );
+
+ // step 67: initialize host status block address
+ // NOTE: status block is not needed in this driver,
+ // still it needs to be set up
+ i = (uint32_t) ( (uint64_t) &bcm_status >> 32 );
+ bcm_write_reg32( STB_HOST_ADDR_HI_R, i );
+ i = (uint32_t) ( (uint64_t) &bcm_status & (uint64_t) 0xffffffff );
+ bcm_write_reg32( STB_HOST_ADDR_LO_R, i );
+
+ // 5704/3 adaption
+ if( IS_5703 || IS_5704 ) {
+ // step 68: 5704, for now omitted
+ // step 69: 5704 set the statistics coalescing tick counter
+ bcm_write_reg32( STAT_TICK_CNT_R, 0 );
+ // step 70: 5704 configure statistics block address in NIC memory
+ // using recommended values (hard coded)
+ bcm_write_reg32( STAT_NIC_ADDR_R, (uint32_t) 0x300 );
+ // step 71: 5704 configure status block address in NIC memory
+ // using recommended values (hard coded)
+ bcm_write_reg32( STB_NIC_ADDR_R, (uint32_t) 0xb00 );
+ }
+
+ // step 72: enable host coalescing engine
+ bcm_setb_reg32( HOST_COAL_MODE_R, BIT32( 12 ) | BIT32( 11 ) | BIT32( 1 ) );
+
+ // step 73: enable rx bd completion functional block
+ bcm_write_reg32( RX_BD_COMPL_MODE_R, BIT32( 1 ) | BIT32( 2 ) );
+
+ // step 74: enable rx list placement functional block
+ bcm_write_reg32( RX_LST_PLACE_MODE_R, BIT32( 1 ) );
+ // 5704/3 adaption
+ if( IS_5703 || IS_5704 ) {
+ // step 75: 5704/3 enable receive list selector func block
+ bcm_write_reg32( RX_LST_SEL_MODE_R, BIT32( 1 ) | BIT32( 2 ) );
+ }
+
+ // step 76: enable DMA engines
+ bcm_setb_reg32( ETH_MAC_MODE_R, BIT32( 23 ) | BIT32( 22 ) | BIT32( 21 ) );
+ /*
+ * WY 26.10.07 This is wrong for 5714, better leave it alone
+ if( IS_5714 ) {
+ bcm_setb_reg32( ETH_MAC_MODE_R, BIT32( 20 ) );
+ }
+ */
+
+ // step 77: omitted, statistics are not used
+ // step 78: Configure the General Misc Local Control register
+ // NOTE: as known so far nothing needs to be done here,
+ // default values should work fine
+ //bcm_setb_reg32( MISC_LOCAL_CTRL_R, 0 );
+
+ // step 79: clear interrupts in INT_MBX0_R low word
+ bcm_write_reg32( INT_MBX0_R, 0 );
+ // 5704/3 adaption
+ // step 80: 5704/3 enable DMA completion functional block
+ if( IS_5703 || IS_5704 ) {
+ bcm_write_reg32( DMA_COMPL_MODE_R, BIT32( 1 ) );
+ }
+
+ // step 81/82: configure write/read DMA mode registers
+ // disable MSI
+ bcm_write_reg32( RD_DMA_MODE_R, BIT32( 10 ) | BIT32( 9 ) | BIT32( 8 ) |
+ BIT32( 7 ) | BIT32( 6 ) | BIT32( 5 ) |
+ BIT32( 4 ) | BIT32( 3 ) | BIT32( 2 ) |
+ BIT32( 1 ) );
+ bcm_write_reg32( WR_DMA_MODE_R, BIT32( 9 ) | BIT32( 8 ) | BIT32( 7 ) |
+ BIT32( 6 ) | BIT32( 5 ) | BIT32( 4 ) |
+ BIT32( 3 ) | BIT32( 2 ) | BIT32( 1 ) );
+ bcm_clrb_reg32( MSI_MODE_R, BIT32( 1 ) );
+ SLOF_usleep( 100 );
+
+ // step 83-91: enable all these functional blocks...
+ bcm_write_reg32( RX_DAT_COMPL_MODE_R, BIT32( 1 ) | BIT32( 2 ) );
+
+ if( IS_5703 || IS_5704 ) {
+ bcm_write_reg32( MBUF_CLSTR_FREE_MODE_R, BIT32( 1 ) );
+ }
+
+ bcm_write_reg32( TX_DAT_COMPL_MODE_R, BIT32( 1 ) );
+ bcm_write_reg32( TX_BD_COMPL_MODE_R, BIT32( 1 ) | BIT32( 2 ) );
+ bcm_write_reg32( RX_BD_INIT_MODE_R, BIT32( 1 ) | BIT32( 2 ) );
+ bcm_write_reg32( RX_DAT_BD_INIT_MODE_R, BIT32( 1 ) );
+ bcm_write_reg32( TX_DAT_INIT_MODE_R, BIT32( 1 ) | BIT32( 3 ) );
+ bcm_write_reg32( TX_BD_INIT_MODE_R, BIT32( 1 ) | BIT32( 2 ) );
+ bcm_write_reg32( TX_BD_RING_SEL_MODE_R, BIT32( 1 ) | BIT32( 2 ) );
+
+ // step 92: omitted
+ // step 93/94: Enable Tx/Rx MAC
+ bcm_setb_reg32( TX_MAC_MODE_R, BIT32( 1 ) );
+// bcm_setb_reg32( RX_MAC_MODE_R, BIT32( 1 ) | BIT32( 2 ) ); // set BIT32( 8 ) for promiscious mode!
+ bcm_setb_reg32( RX_MAC_MODE_R, BIT32( 1 ) ); // set BIT32( 8 ) for promiscious mode!
+ // set BIT32( 10) for VLAN
+
+ // step 95: disable auto polling:
+ // bcm_phy_init takes care of this
+ // step 96: omitted
+ // step 97: omitted, may change though, but is not important
+ // step 98: activate link & enable MAC functional block
+ // NOTE autopolling is enabled so bit 0 needs not to be set
+ //bcm_setb_reg32( MI_STATUS_R, BIT32( 0 ) );
+
+ // step 99: setup PHY
+ // return if link is down
+ if( bcm_phy_init() < 0 ) {
+#ifdef BCM_DEBUG
+ printf( "bcm57xx: init step 99: PHY initialization failed\n" );
+#endif
+ return -1;
+ }
+
+ // step 100: setup multicast filters
+ bcm_write_reg32( MAC_HASH0_R, (uint32_t) 0 );
+ bcm_write_reg32( MAC_HASH1_R, (uint32_t) 0 );
+ bcm_write_reg32( MAC_HASH2_R, (uint32_t) 0 );
+ bcm_write_reg32( MAC_HASH3_R, (uint32_t) 0 );
+/*
+ // accept all multicast frames
+ bcm_write_reg32( MAC_HASH0_R, (uint32_t) 0xffffffff );
+ bcm_write_reg32( MAC_HASH1_R, (uint32_t) 0xffffffff );
+ bcm_write_reg32( MAC_HASH2_R, (uint32_t) 0xffffffff );
+ bcm_write_reg32( MAC_HASH3_R, (uint32_t) 0xffffffff );
+*/
+ // step 101: omitted, no interrupts used
+
+ // make initial receive buffers available for NIC
+ // this step has to be done here after RX DMA engine has started (step 94)
+ bcm_write_reg32( RXPROD_PROD_IND, BCM_MAX_RX_BUF );
+
+ // if ASF Firmware enabled
+ bcm_write_mem32( BCM_NICDRV_STATE_MBX, NIC_FWDRV_STATE_START_DONE );
+ SLOF_msleep( 10 );
+
+ // enable heartbeat timer
+
+ bcm_write_reg32( ASF_HEARTBEAT_TIMER_R, 0x5 );
+
+ driver->running = 1;
+ // off we go..
+ return 0;
+}
+
+static int
+bcm_reset( void )
+{
+ uint32_t i;
+
+#ifdef BCM_DEBUG
+ printf( "bcm57xx: resetting controller.." );
+#endif
+
+ bcm_write_mem32( BCM_FW_MBX, BCM_MAGIC_NUMBER );
+
+ if( IS_5714 ) {
+ bcm_setb_reg32( MISC_CFG_R, BIT32( 26 ) | BIT32( 0 ) );
+ } else {
+ bcm_setb_reg32( MISC_CFG_R, BIT32( 0 ) );
+ }
+
+ SLOF_msleep( 20 );
+
+ /*
+ * after reset local read/write functions cannot be used annymore
+ * until bus master & stuff is set up again
+ */
+
+ i = ( BIT32( 10 ) | BIT32( 2 ) | BIT32( 1 ) );
+ SLOF_pci_config_write16(PCI_COM_R, i);
+ /*snk_kernel_interface->pci_config_write( bcm_pcicfg_puid,
+ 2,
+ bcm_pcicfg_bus,
+ bcm_pcicfg_devfn,
+ PCI_COM_R,
+ ( int ) i );*/
+
+ // step 9 & 13: disable & mask interrupts & enable indirect addressing mode &
+ // enable pci byte/word swapping initialize the misc host control register
+ i = ( BIT32( 7 ) | BIT32( 5 ) | BIT32( 4 ) |
+ BIT32( 3 ) | BIT32( 2 ) | BIT32( 1 ) | BIT32( 0 ) );
+ SLOF_pci_config_write32(PCI_MISC_HCTRL_R, i);
+ /*snk_kernel_interface->pci_config_write( bcm_pcicfg_puid,
+ 4,
+ bcm_pcicfg_bus,
+ bcm_pcicfg_devfn,
+ PCI_MISC_HCTRL_R,
+ ( int ) i );*/
+
+ // step 16: poll for bootcode completion by waiting for the one's
+ // complement of the magic number previously written
+ i = 1000;
+ while( ( --i ) &&
+ ( bcm_read_mem32( BCM_FW_MBX ) != ~BCM_MAGIC_NUMBER ) ) {
+#ifdef BCM_DEBUG
+ printf( "." );
+#else
+ SLOF_msleep( 1 );
+#endif
+ }
+
+ // return on error
+ if( bcm_read_mem32( BCM_FW_MBX ) != ~BCM_MAGIC_NUMBER ) {
+#ifdef BCM_DEBUG
+ printf( "failed\n" );
+#endif
+ return -1;
+ }
+
+#ifdef BCM_DEBUG
+ printf( "done\n" );
+#endif
+ return 0;
+}
+
+static int
+bcm_term( void )
+{
+ uint32_t i;
+ uint16_t v;
+
+#ifdef BCM_DEBUG
+ printf( "bcm57xx: driver shutdown.." );
+#endif
+
+ /*
+ * halt ASF firmware
+ */
+ bcm_fw_halt();
+
+ /*
+ * unload ASF firmware
+ */
+ bcm_write_mem32( BCM_NICDRV_STATE_MBX, NIC_FWDRV_STATE_UNLOAD );
+
+ /*
+ * disable RX producer rings
+ */
+ bcm_write_reg32( BCM_RCB_LENFLAG_u16( BCM_RXPROD_RCB_JUM ), RCB_FLAG_RING_DISABLED );
+ bcm_write_reg32( BCM_RCB_HOSTADDR_HI_u16( BCM_RXPROD_RCB_JUM ), 0 );
+ bcm_write_reg32( BCM_RCB_HOSTADDR_LOW_u16( BCM_RXPROD_RCB_JUM ), 0 );
+ bcm_write_reg32( BCM_RCB_NICADDR_u16( BCM_RXPROD_RCB_JUM ), 0 );
+
+ bcm_write_reg32( BCM_RCB_LENFLAG_u16( BCM_RXPROD_RCB_STD ), RCB_FLAG_RING_DISABLED );
+ bcm_write_reg32( BCM_RCB_HOSTADDR_HI_u16( BCM_RXPROD_RCB_STD ), 0 );
+ bcm_write_reg32( BCM_RCB_HOSTADDR_LOW_u16( BCM_RXPROD_RCB_STD ), 0 );
+ bcm_write_reg32( BCM_RCB_NICADDR_u16( BCM_RXPROD_RCB_STD ), 0 );
+
+ bcm_write_reg32( BCM_RCB_LENFLAG_u16( BCM_RXPROD_RCB_MIN ), RCB_FLAG_RING_DISABLED );
+ bcm_write_reg32( BCM_RCB_HOSTADDR_HI_u16( BCM_RXPROD_RCB_MIN ), 0 );
+ bcm_write_reg32( BCM_RCB_HOSTADDR_LOW_u16( BCM_RXPROD_RCB_MIN ), 0 );
+ bcm_write_reg32( BCM_RCB_NICADDR_u16( BCM_RXPROD_RCB_MIN ), 0 );
+
+ /*
+ * disable RX return rings
+ */
+ v = BCM_RXRET_RCB_OFFS;
+ for( i = 0; i < BCM_MAX_RXRET_RING; i++ ) {
+ bcm_write_mem32( BCM_RCB_LENFLAG_u16( v ), RCB_FLAG_RING_DISABLED );
+ bcm_write_mem32( BCM_RCB_HOSTADDR_HI_u16( v ), 0 );
+ bcm_write_mem32( BCM_RCB_HOSTADDR_LOW_u16( v ), 0 );
+ bcm_write_mem32( BCM_RCB_NICADDR_u16( v ), 0 );
+
+ v += BCM_RCB_SIZE_u16;
+ }
+
+ /*
+ * disable TX rings
+ */
+ v = BCM_TX_RCB_OFFS;
+ for( i = 0; i < BCM_MAX_TX_RING; i++ ) {
+ bcm_write_mem32( BCM_RCB_LENFLAG_u16( v ), RCB_FLAG_RING_DISABLED );
+ bcm_write_mem32( BCM_RCB_HOSTADDR_HI_u16( v ), 0 );
+ bcm_write_mem32( BCM_RCB_HOSTADDR_LOW_u16( v ), 0 );
+ bcm_write_mem32( BCM_RCB_NICADDR_u16( v ), 0 );
+
+ v += BCM_RCB_SIZE_u16;
+ }
+
+ /*
+ * remove receive rules
+ */
+ bcm_write_reg32( RX_RULE_CTRL_R ( 0 ), 0 );
+ bcm_write_reg32( RX_RULE_VAL_R ( 0 ), 0 );
+ bcm_write_reg32( RX_RULE_CTRL_R ( 1 ), 0 );
+ bcm_write_reg32( RX_RULE_VAL_R ( 1 ), 0 );
+
+ /*
+ * shutdown sequence
+ * BCM57xx Programmer's Guide: Section 8, "Shutdown"
+ * the enable bit of every state machine of the 57xx
+ * has to be reset.
+ */
+
+ /*
+ * receive path shutdown sequence
+ */
+ bcm_clr_wait_bit32( RX_MAC_MODE_R, BIT32( 1 ) );
+ bcm_clr_wait_bit32( RX_LST_PLACE_MODE_R, BIT32( 1 ) );
+ bcm_clr_wait_bit32( RX_BD_INIT_MODE_R, BIT32( 1 ) );
+ bcm_clr_wait_bit32( RX_DAT_BD_INIT_MODE_R, BIT32( 1 ) );
+ bcm_clr_wait_bit32( RX_DAT_COMPL_MODE_R, BIT32( 1 ) );
+ bcm_clr_wait_bit32( RX_BD_COMPL_MODE_R, BIT32( 1 ) );
+
+ if( IS_5704 || IS_5703 ) {
+ bcm_clr_wait_bit32( RX_LST_SEL_MODE_R, BIT32( 1 ) );
+ }
+
+ /*
+ * transmit path & memory shutdown sequence
+ */
+ bcm_clr_wait_bit32( TX_BD_RING_SEL_MODE_R, BIT32( 1 ) );
+ bcm_clr_wait_bit32( TX_BD_INIT_MODE_R, BIT32( 1 ) );
+ bcm_clr_wait_bit32( TX_DAT_INIT_MODE_R, BIT32( 1 ) );
+ bcm_clr_wait_bit32( RD_DMA_MODE_R, BIT32( 1 ) );
+ bcm_clr_wait_bit32( TX_DAT_COMPL_MODE_R, BIT32( 1 ) );
+
+ if( IS_5704 ) {
+ bcm_clr_wait_bit32( DMA_COMPL_MODE_R, BIT32( 1 ) );
+ }
+
+ bcm_clr_wait_bit32( TX_BD_COMPL_MODE_R, BIT32( 1 ) );
+ bcm_clr_wait_bit32( ETH_MAC_MODE_R, BIT32( 21 ) );
+ bcm_clr_wait_bit32( TX_MAC_MODE_R, BIT32( 1 ) );
+
+ bcm_clr_wait_bit32( HOST_COAL_MODE_R, BIT32( 1 ) );
+ bcm_clr_wait_bit32( WR_DMA_MODE_R, BIT32( 1 ) );
+
+ if( IS_5704 || IS_5703 ) {
+ bcm_clr_wait_bit32( MBUF_CLSTR_FREE_MODE_R, BIT32( 1 ) );
+ }
+
+ bcm_write_reg32( FTQ_RES_R, (uint32_t) ~0 );
+ bcm_write_reg32( FTQ_RES_R, (uint32_t) 0 );
+
+ if( IS_5704 || IS_5703 ) {
+ bcm_clr_wait_bit32( BUF_MAN_MODE_R, BIT32( 1 ) );
+ bcm_clr_wait_bit32( MEMARB_MODE_R, BIT32( 1 ) );
+ }
+
+#ifdef BCM_DEBUG
+ printf( "done.\n" );
+#endif
+ /*
+ * controller reset
+ */
+ if( bcm_reset() != 0 ) {
+ return -1;
+ }
+
+ /*
+ * restart ASF firmware
+ */
+ bcm_write_mem32( BCM_NICDRV_STATE_MBX, NIC_FWDRV_STATE_UNLOAD );
+ SLOF_msleep( 10 );
+ bcm_write_mem32( BCM_NICDRV_STATE_MBX, NIC_FWDRV_STATE_UNLOAD_DONE );
+ SLOF_msleep( 100 );
+ bcm_write_mem32( BCM_NICDRV_STATE_MBX, NIC_FWDRV_STATE_START );
+ SLOF_msleep( 10 );
+ bcm_write_mem32( BCM_NICDRV_STATE_MBX, NIC_FWDRV_STATE_START_DONE );
+
+ /*
+ * activate Wake-on-LAN
+ */
+ bcm_wol_activate();
+
+ /*
+ * PCI shutdown
+ */
+ bcm_clrb_reg32( PCI_MISC_HCTRL_R, BIT32( 3 ) | BIT32( 2 ) );
+
+ /*
+ * from now on local rw functions cannot be used anymore
+ */
+
+// bcm_clrb_reg32( PCI_COM_R, BIT32( 10 ) | BIT32( 2 ) | BIT32( 1 ) );
+
+ SLOF_pci_config_write32(PCI_COM_R, BIT32(8) | BIT32(6));
+ /*snk_kernel_interface->pci_config_write( bcm_pcicfg_puid,
+ 2,
+ bcm_pcicfg_bus,
+ bcm_pcicfg_devfn,
+ PCI_COM_R,
+ BIT32(8) | BIT32(6) );*/
+
+ // no more networking...
+ return 0;
+}
+
+static int
+bcm_getmac(uint32_t addr, char mac[6])
+{
+ uint32_t t1, t2;
+ uint64_t t3;
+
+ if (bcm_nvram_read(addr, &t1, 1) != 0)
+ return -1;
+ if (bcm_nvram_read(addr+4, &t2, 1) != 0)
+ return -1;
+ t3 = ((uint64_t)t1 << 32) + t2;
+
+ mac[0] = (t3 >> 40) & 0xFF;
+ mac[1] = (t3 >> 32) & 0xFF;
+ mac[2] = (t3 >> 24) & 0xFF;
+ mac[3] = (t3 >> 16) & 0xFF;
+ mac[4] = (t3 >> 8) & 0xFF;
+ mac[5] = (t3 >> 0) & 0xFF;
+
+ return 0;
+}
+
+static char*
+print_itoa(char *text, uint32_t value)
+{
+ if(value >= 10)
+ text = print_itoa(text, value / 10);
+ *text = '0' + (value % 10);
+ ++text;
+ return text;
+}
+
+static int
+bcm_get_version(char *text)
+{
+ uint32_t t1;
+
+ if (bcm_nvram_read(0x94, &t1, 1) != 0)
+ return -1;
+
+ text = print_itoa(text, (t1 >> 8) & 0xFF);
+ text[0] = '.';
+ text = print_itoa(&text[1], t1 & 0xFF);
+ text[0] = '\n';
+ return 0;
+}
+
+static uint32_t
+util_gen_crc( char *pcDatabuf, uint32_t ulDatalen, uint32_t ulCrc_in)
+{
+ unsigned char data;
+ uint32_t idx, bit, crc = ulCrc_in;
+
+ for(idx = 0; idx < ulDatalen; idx++) {
+ data = *pcDatabuf++;
+ for(bit = 0; bit < 8; bit++, data >>= 1) {
+ crc = (crc >> 1) ^ (((crc ^ data) & 1) ?
+ CRC32_POLYNOMIAL : 0);
+ }
+ }
+ return bswap_32(~crc);
+}
+
+static int
+bcm_setmac(char mac_addr1[6], char mac_addr2[6])
+{
+ uint64_t mac1 = 0, mac2 = 0;
+ uint32_t manu[MANUFACTURING_INFO_SIZE/4];
+ int addr, i;
+ uint32_t crc, val1, val2, val3, val4;
+
+#ifdef BCM_DEBUG
+ printf("Flashing MAC 1: %02X:%02X:%02X:%02X:%02X:%02X\n",
+ ((unsigned int) mac_addr1[0]) & 0xFF,
+ ((unsigned int) mac_addr1[1]) & 0xFF,
+ ((unsigned int) mac_addr1[2]) & 0xFF,
+ ((unsigned int) mac_addr1[3]) & 0xFF,
+ ((unsigned int) mac_addr1[4]) & 0xFF,
+ ((unsigned int) mac_addr1[5]) & 0xFF);
+
+ printf("Flashing MAC 2: %02X:%02X:%02X:%02X:%02X:%02X\n",
+ ((unsigned int) mac_addr2[0]) & 0xFF,
+ ((unsigned int) mac_addr2[1]) & 0xFF,
+ ((unsigned int) mac_addr2[2]) & 0xFF,
+ ((unsigned int) mac_addr2[3]) & 0xFF,
+ ((unsigned int) mac_addr2[4]) & 0xFF,
+ ((unsigned int) mac_addr2[5]) & 0xFF);
+#endif
+
+ mac1 |= ((uint64_t) mac_addr1[0]) & 0xFF; mac1 = mac1 << 8;
+ mac1 |= ((uint64_t) mac_addr1[1]) & 0xFF; mac1 = mac1 << 8;
+ mac1 |= ((uint64_t) mac_addr1[2]) & 0xFF; mac1 = mac1 << 8;
+ mac1 |= ((uint64_t) mac_addr1[3]) & 0xFF; mac1 = mac1 << 8;
+ mac1 |= ((uint64_t) mac_addr1[4]) & 0xFF; mac1 = mac1 << 8;
+ mac1 |= ((uint64_t) mac_addr1[5]) & 0xFF;
+
+ mac2 |= ((uint64_t) mac_addr2[0]) & 0xFF; mac2 = mac2 << 8;
+ mac2 |= ((uint64_t) mac_addr2[1]) & 0xFF; mac2 = mac2 << 8;
+ mac2 |= ((uint64_t) mac_addr2[2]) & 0xFF; mac2 = mac2 << 8;
+ mac2 |= ((uint64_t) mac_addr2[3]) & 0xFF; mac2 = mac2 << 8;
+ mac2 |= ((uint64_t) mac_addr2[4]) & 0xFF; mac2 = mac2 << 8;
+ mac2 |= ((uint64_t) mac_addr2[5]) & 0xFF;
+
+ /* Extract the manufacturing data, starts at 0x74 */
+ if(bcm_nvram_lock() == -1) {
+ return -1;
+ }
+
+ addr = 0x74;
+ for (i = 0; i < (MANUFACTURING_INFO_SIZE/4); i++) {
+ if (bcm_nvram_read(addr, &manu[i], 0) != 0) {
+ printf("\nREAD FAILED\n");
+ bcm_nvram_unlock();
+ return -1;
+ }
+ addr+=4;
+ }
+ bcm_nvram_unlock();
+
+ /* Store the new MAC address in the manufacturing data */
+ val1 = mac1 >> 32;
+ val2 = mac1 & 0xFFFFFFFF;
+ val3 = mac2 >> 32;
+ val4 = mac2 & 0xFFFFFFFF;
+ manu[(0x7C-0x74)/4] = val1;
+ manu[(0x80-0x74)/4] = val2;
+ manu[(0xCC-0x74)/4] = val3;
+ manu[(0xD0-0x74)/4] = val4;
+
+ /* Calculate the new manufacturing datas CRC */
+ crc = util_gen_crc(((char *)manu),
+ MANUFACTURING_INFO_SIZE - 4, 0xFFFFFFFF);
+
+ /* Now write the new MAC addresses and CRC */
+ if ((bcm_nvram_write(0x7C, val1, 1) != 0) ||
+ (bcm_nvram_write(0x80, val2, 1) != 0) ||
+ (bcm_nvram_write(0xCC, val3, 1) != 0) ||
+ (bcm_nvram_write(0xD0, val4, 1) != 0) ||
+ (bcm_nvram_write(0xFC, crc, 1) != 0) )
+ {
+ /* Disastor ! */
+#ifdef BCM_DEBUG
+ printf("failed to write MAC address\n");
+#endif
+ return -1;
+ }
+
+ /* Success !!!! */
+ return 0;
+}
+
+static int
+bcm_ioctl( int request, void* data )
+{
+ uint32_t l_baseaddrL_u32;
+ uint32_t l_baseaddrH_u32;
+ uint32_t i;
+ int ret_val = 0;
+ char mac_addr[6];
+ ioctl_net_data_t *ioctl_data = (ioctl_net_data_t*) data;
+
+ if(request != SIOCETHTOOL) {
+ return -1;
+ }
+
+#ifdef BCM_DEBUG
+ printf( "bcm57xx: detected device " );
+ if( IS_5703 ) {
+ printf( "5703S" );
+ } else if( IS_5704 ) {
+ printf( "5704" );
+ if( IS_SERDES ) {
+ printf( "S\n" );
+ } else {
+ printf( "C\n" );
+ }
+ } else if( IS_5714 ) {
+ printf( "5714\n" );
+ }
+#endif
+ /*
+ * setup register & memory base addresses of NIC
+ */
+ l_baseaddrL_u32 = (uint32_t) ~0xf &
+ SLOF_pci_config_read32(PCI_BAR1_R);
+ /*l_baseaddrL_u32 = ( (uint32_t) ~0xf &
+ (uint32_t) snk_kernel_interface->pci_config_read( bcm_pcicfg_puid,
+ 4,
+ bcm_pcicfg_bus,
+ bcm_pcicfg_devfn,
+ PCI_BAR1_R ) );*/
+
+ l_baseaddrH_u32 = SLOF_pci_config_read32(PCI_BAR2_R);
+ /*l_baseaddrH_u32 =
+ (uint32_t) snk_kernel_interface->pci_config_read( bcm_pcicfg_puid,
+ 4,
+ bcm_pcicfg_bus,
+ bcm_pcicfg_devfn,
+ PCI_BAR2_R );*/
+
+ bcm_baseaddr_u64 = (uint64_t) l_baseaddrH_u32;
+ bcm_baseaddr_u64 <<= 32;
+ bcm_baseaddr_u64 += (uint64_t) l_baseaddrL_u32;
+ bcm_baseaddr_u64 =
+ (uint64_t)SLOF_translate_my_address((void *)bcm_baseaddr_u64);
+ /*snk_kernel_interface->translate_addr(((void *)&(bcm_baseaddr_u64)));*/
+ bcm_memaddr_u64 = bcm_baseaddr_u64 + BCM_MEMORY_OFFS;
+
+ /*
+ * 57xx hardware initialization
+ * BCM57xx Programmer's Guide: Section 8, "Initialization"
+ * steps 1 through 101
+ */
+
+ // step 1: enable bus master & memory space in command reg
+ i = ( BIT32( 10 ) | BIT32( 2 ) | BIT32( 1 ) );
+ SLOF_pci_config_write16(PCI_COM_R, i);
+ /*snk_kernel_interface->pci_config_write( bcm_pcicfg_puid,
+ 2,
+ bcm_pcicfg_bus,
+ bcm_pcicfg_devfn,
+ PCI_COM_R,
+ ( int ) i );*/
+
+ // step 2: disable & mask interrupts & enable pci byte/word swapping & enable indirect addressing mode
+ i = ( BIT32( 7 ) | BIT32( 3 ) | BIT32( 2 ) | BIT32( 1 ) | BIT32( 0 ) );
+ SLOF_pci_config_write32(PCI_MISC_HCTRL_R, i);
+ /*snk_kernel_interface->pci_config_write( bcm_pcicfg_puid,
+ 4,
+ bcm_pcicfg_bus,
+ bcm_pcicfg_devfn,
+ PCI_MISC_HCTRL_R,
+ ( int ) i );*/
+
+ bcm_nvram_init();
+
+ switch(ioctl_data->subcmd) {
+ case ETHTOOL_GMAC:
+ switch(ioctl_data->data.mac.idx) {
+ case 0:
+ ret_val = bcm_getmac(0x7C, ioctl_data->data.mac.address);
+ break;
+ case 1:
+ ret_val = bcm_getmac(0xCC, ioctl_data->data.mac.address);
+ break;
+ default:
+ ret_val = -1;
+ break;
+ }
+ break;
+ case ETHTOOL_SMAC:
+ switch(ioctl_data->data.mac.idx) {
+ case 0:
+ ret_val = bcm_getmac(0xCC, mac_addr);
+ if(ret_val == 0)
+ ret_val = bcm_setmac(ioctl_data->data.mac.address, mac_addr);
+ break;
+ case 1:
+ ret_val = bcm_getmac(0x7C, mac_addr);
+ if(ret_val == 0)
+ ret_val = bcm_setmac(mac_addr, ioctl_data->data.mac.address);
+ break;
+ default:
+ ret_val = -1;
+ break;
+ }
+ break;
+ case ETHTOOL_VERSION: {
+ char *text = ioctl_data->data.version.text;
+ memcpy(text, " BCM57xx Boot code level: ", 27);
+ ret_val = bcm_get_version(&text[27]);
+ break;
+ }
+ default:
+ ret_val = -1;
+ break;
+ }
+
+ bcm_term();
+ return ret_val;
+}
+
+net_driver_t *bcm57xx_open(void)
+{
+ net_driver_t *driver;
+ uint16_t vendor_id, device_id;
+
+ vendor_id = SLOF_pci_config_read16(0);
+ device_id = SLOF_pci_config_read16(2);
+ if (check_driver(vendor_id, device_id))
+ return NULL;
+
+ driver = SLOF_alloc_mem(sizeof(*driver));
+ if (!driver) {
+ printf("Unable to allocate virtio-net driver\n");
+ return NULL;
+ }
+ memset(driver, 0, sizeof(*driver));
+
+ if (bcm_init(driver))
+ goto FAIL;
+
+ return driver;
+
+FAIL: SLOF_free_mem(driver, sizeof(*driver));
+ return NULL;
+
+ return 0;
+}
+
+void bcm57xx_close(net_driver_t *driver)
+{
+ if (driver->running == 0)
+ return;
+
+ bcm_term();
+ driver->running = 0;
+ SLOF_free_mem(driver, sizeof(*driver));
+}
+
+int bcm57xx_read(char *buf, int len)
+{
+ if (buf)
+ return bcm_receive(buf, len);
+ return -1;
+}
+
+int bcm57xx_write(char *buf, int len)
+{
+ if (buf)
+ return bcm_xmit(buf, len);
+ return -1;
+}
diff --git a/src/roms/SLOF/lib/libbcm/bcm57xx.h b/src/roms/SLOF/lib/libbcm/bcm57xx.h
new file mode 100644
index 0000000..efaba60
--- /dev/null
+++ b/src/roms/SLOF/lib/libbcm/bcm57xx.h
@@ -0,0 +1,323 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <cache.h>
+#include <netdriver.h>
+
+// Debug switches
+//#define BCM_DEBUG // main debug switch, w/o it the other ones don't work
+//#define BCM_SHOW_RCV
+//#define BCM_SHOW_RCV_DATA
+//#define BCM_SHOW_XMIT
+//#define BCM_SHOW_XMIT_DATA
+//#define BCM_SHOW_XMIT_STATS
+//#define BCM_SHOW_IDX
+//#define BCM_SHOW_STATS
+//#define BCM_SHOW_ASF_REGS
+
+// Switch to enable SW AUTO-NEG
+// don't try, it's still incomplete
+//#define BCM_SW_AUTONEG
+
+/*
+ * used register offsets
+ */
+// PCI command register
+#define PCI_COM_R ( (uint16_t) 0x0004 )
+// PCI Cache Line Size register
+#define PCI_CACHELS_R ( (uint16_t) 0x000c )
+// PCI bar1 register
+#define PCI_BAR1_R ( (uint16_t) 0x0010 )
+// PCI bar2 register
+#define PCI_BAR2_R ( (uint16_t) 0x0014 )
+// PCI bar1 register
+#define PCI_SUBID_R ( (uint16_t) 0x002e )
+// PCI-X Comand register
+#define PCI_X_COM_R ( (uint16_t) 0x0042 )
+// Message Data Register
+#define MSG_DATA_R ( (uint16_t) 0x0064 )
+// PCI misc host contrl register
+#define PCI_MISC_HCTRL_R ( (uint16_t) 0x0068 )
+// DMA Read/Write Control register
+#define DMA_RW_CTRL_R ( (uint16_t) 0x006c )
+// PCI State register
+#define PCI_STATE_R ( (uint16_t) 0x0070 )
+// PCI_Clock Control register
+#define PCI_CLK_CTRL_R ( (uint16_t) 0x0074 )
+// Register Base Address Register
+#define REG_BASE_ADDR_REG ( (uint16_t) 0x0078 )
+// Memory Window Base Address Register
+#define MEM_BASE_ADDR_REG ( (uint16_t) 0x007c )
+// Register Data Register
+#define REG_DATA_REG ( (uint16_t) 0x0080 )
+// Memory Window Data Register
+#define MEM_DATA_REG ( (uint16_t) 0x0084 )
+// MAC Function register
+#define MAC_FUNC_R ( (uint16_t) 0x00b8 )
+// Interrupt Mailbox 0 register
+#define INT_MBX0_R ( (uint16_t) 0x0204 )
+// Ethernet MAC Mode register
+#define ETH_MAC_MODE_R ( (uint16_t) 0x0400 )
+// Ethernet MAC Addresses registers
+#define MAC_ADDR_OFFS_HI( idx ) ( (uint16_t) ( (idx*2 + 0)*sizeof( uint32_t ) + 0x0410 ) )
+#define MAC_ADDR_OFFS_LO( idx ) ( (uint16_t) ( (idx*2 + 1)*sizeof( uint32_t ) + 0x0410 ) )
+// Ethernet MAC Status register
+#define ETH_MAC_STAT_R ( (uint16_t) 0x0404 )
+// Ethernet MAC Event Enable register
+#define ETH_MAC_EVT_EN_R ( (uint16_t) 0x0408 )
+// Ethernet Transmit Random Backoff register
+#define ETH_TX_RND_BO_R ( (uint16_t) 0x0438 )
+// Receive MTU Size register
+#define RX_MTU_SIZE_R ( (uint16_t) 0x043c )
+// Transmit 1000BASE-X Auto Negotiation register
+#define TX_1000BX_AUTONEG_R ( (uint16_t) 0x0444 )
+// Receive 1000BASE-X Auto Negotiation register
+#define RX_1000BX_AUTONEG_R ( (uint16_t) 0x0448 )
+// MI Communication register
+#define MI_COM_R ( (uint16_t) 0x044c )
+// MI Status Register
+#define MI_STATUS_R ( (uint16_t) 0x0450 )
+// MI Mode register
+#define MI_MODE_R ( (uint16_t) 0x0454 )
+// Transmit MAC Mode register
+#define TX_MAC_MODE_R ( (uint16_t) 0x045c )
+// Transmit MAC Length register
+#define TX_MAC_LEN_R ( (uint16_t) 0x0464 )
+// Receive MAC Mode register
+#define RX_MAC_MODE_R ( (uint16_t) 0x0468 )
+// MAC Hash 0 register* VPD Config:
+#define MAC_HASH0_R ( (uint16_t) 0x0470 )
+// MAC Hash 1 register
+#define MAC_HASH1_R ( (uint16_t) 0x0474 )
+// MAC Hash 2 register
+#define MAC_HASH2_R ( (uint16_t) 0x0478 )
+// MAC Hash 3 register
+#define MAC_HASH3_R ( (uint16_t) 0x047c )
+// Receive Rules Control register
+#define RX_RULE_CTRL_R( idx ) ( (uint16_t) ( idx*8 + 0x0480 ) )
+// Receive Rules Value register
+#define RX_RULE_VAL_R( idx ) ( (uint16_t) ( idx*8 + 0x0484 ) )
+// Receive Rules Configuration register
+#define RX_RULE_CFG_R ( (uint16_t) 0x0500 )
+// Low Watermark Max Receive Frames register
+#define LOW_WMARK_MAX_RXFRAM_R ( (uint16_t) 0x0504 )
+// SerDes Control Register
+#define SERDES_CTRL_R ( (uint16_t) 0x0590 )
+// Hardware Auto Negotiation Control Register
+#define HW_AUTONEG_CTRL_R ( (uint16_t) 0x05B0 )
+// Hardware Auto Negotiation Status Register
+#define HW_AUTONEG_STAT_R ( (uint16_t) 0x05B4 )
+// Send Data Initiator Mode register
+#define TX_DAT_INIT_MODE_R ( (uint16_t) 0x0c00 )
+// Send Data Completion Mode register
+#define TX_DAT_COMPL_MODE_R ( (uint16_t) 0x1000 )
+// Send BD Ring Selector Mode register
+#define TX_BD_RING_SEL_MODE_R ( (uint16_t) 0x1400 )
+// Send BD Initiator Mode register
+#define TX_BD_INIT_MODE_R ( (uint16_t) 0x1800 )
+// Send BD Completion Mode register
+#define TX_BD_COMPL_MODE_R ( (uint16_t) 0x1c00 )
+// Receive List Placement Mode register
+#define RX_LST_PLACE_MODE_R ( (uint16_t) 0x2000 )
+// Receive List Placement Configuration register
+#define RX_LST_PLACE_CFG_R ( (uint16_t) 0x2010 )
+// Receive List Placement Statistics Enable Mask register
+#define RX_LST_PLACE_STAT_EN_R ( (uint16_t) 0x2018 )
+// Receive Data & Receive BD Initiator Mode register
+#define RX_DAT_BD_INIT_MODE_R ( (uint16_t) 0x2400 )
+// Receive Data Completion Mode register
+#define RX_DAT_COMPL_MODE_R ( (uint16_t) 0x2800 )
+// Receive BD Initiator Mode register
+#define RX_BD_INIT_MODE_R ( (uint16_t) 0x2c00 )
+// Standard Receive Producer Ring Replenish Threshold register
+#define STD_RXPR_REP_THR_R ( (uint16_t) 0x2c18 )
+// Receive BD Completion Mode register
+#define RX_BD_COMPL_MODE_R ( (uint16_t) 0x3000 )
+// Receive List Selector Mode register
+#define RX_LST_SEL_MODE_R ( (uint16_t) 0x3400 )
+// MBUF Cluster Free Mode register
+#define MBUF_CLSTR_FREE_MODE_R ( (uint16_t) 0x3800 )
+// Host Coalescing Mode register
+#define HOST_COAL_MODE_R ( (uint16_t) 0x3c00 )
+// Receive Coalescing Ticks register
+#define RX_COAL_TICKS_R ( (uint16_t) 0x3c08 )
+// Send Coalescing Ticks register
+#define TX_COAL_TICKS_R ( (uint16_t) 0x3c0c )
+// Receive Max Coalesced BD Count register
+#define RX_COAL_MAX_BD_R ( (uint16_t) 0x3c10 )
+// Send Max Coalesced BD Count register
+#define TX_COAL_MAX_BD_R ( (uint16_t) 0x3c14 )
+// Receive Coalescing Ticks During Int register
+#define RX_COAL_TICKS_INT_R ( (uint16_t) 0x3c18 )
+// Send Coalescing Ticks During Int register
+#define TX_COAL_TICKS_INT_R ( (uint16_t) 0x3c1c )
+// Receive Max Coalesced BD Count During Int register
+#define RX_COAL_MAX_BD_INT_R ( (uint16_t) 0x3c18 )
+// Send Max Coalesced BD Count During Int register
+#define TX_COAL_MAX_BD_INT_R ( (uint16_t) 0x3c1c )
+// Statistics Ticks Counter register
+#define STAT_TICK_CNT_R ( (uint16_t) 0x3c28 )
+// Status Block Host Address Low register
+#define STB_HOST_ADDR_HI_R ( (uint16_t) 0x3c38 )
+// Status Block Host Address High register
+#define STB_HOST_ADDR_LO_R ( (uint16_t) 0x3c3c )
+// Statistics Base Address register
+#define STAT_NIC_ADDR_R ( (uint16_t) 0x3c40 )
+// Status Block Base Address register
+#define STB_NIC_ADDR_R ( (uint16_t) 0x3c44 )
+// Memory Arbiter Mode register
+#define MEMARB_MODE_R ( (uint16_t) 0x4000 )
+// Buffer Manager Mode register
+#define BUF_MAN_MODE_R ( (uint16_t) 0x4400 )
+// MBuf Pool Address register
+#define MBUF_POOL_ADDR_R ( (uint16_t) 0x4408 )
+// MBuf Pool Length register
+#define MBUF_POOL_LEN_R ( (uint16_t) 0x440c )
+// Read DMA Mbuf Low Watermark register
+#define DMA_RMBUF_LOW_WMARK_R ( (uint16_t) 0x4410 )
+// MAC Rx Mbuf Low Watermark register
+#define MAC_RXMBUF_LOW_WMARK_R ( (uint16_t) 0x4414 )
+// Mbuf High Watermark register
+#define MBUF_HIGH_WMARK_R ( (uint16_t) 0x4418 )
+// DMA Descriptor Pool Address register
+#define DMA_DESC_POOL_ADDR_R ( (uint16_t) 0x442c )
+// DMA Descriptor Pool Length register
+#define DMA_DESC_POOL_LEN_R ( (uint16_t) 0x4430 )
+// DMA Descriptor Low Watermark register
+#define DMA_DESC_LOW_WM_R ( (uint16_t) 0x4434 )
+// DMA Descriptor HIGH Watermark register
+#define DMA_DESC_HIGH_WM_R ( (uint16_t) 0x4438 )
+// Read DMA Mode register
+#define RD_DMA_MODE_R ( (uint16_t) 0x4800 )
+// Write DMA Mode register
+#define WR_DMA_MODE_R ( (uint16_t) 0x4c00 )
+// FTQ Reset register
+#define FTQ_RES_R ( (uint16_t) 0x5c00 )
+// MSI Mode register
+#define MSI_MODE_R ( (uint16_t) 0x6000 )
+// DMA completion Mode register
+#define DMA_COMPL_MODE_R ( (uint16_t) 0x6400 )
+// Mode Control register
+#define MODE_CTRL_R ( (uint16_t) 0x6800 )
+// Misc Configuration register
+#define MISC_CFG_R ( (uint16_t) 0x6804 )
+// Misc Local Control register
+#define MISC_LOCAL_CTRL_R ( (uint16_t) 0x6808 )
+// RX-Risc Mode Register
+#define RX_CPU_MODE_R ( (uint16_t) 0x5000 )
+// RX-Risc State Register
+#define RX_CPU_STATE_R ( (uint16_t) 0x5004 )
+// RX-Risc Program Counter
+#define RX_CPU_PC_R ( (uint16_t) 0x501c )
+// RX-Risc Event Register
+#define RX_CPU_EVENT_R ( (uint16_t) 0x6810 )
+// MDI Control register
+#define MDI_CTRL_R ( (uint16_t) 0x6844 )
+// WOL Mode register
+#define WOL_MODE_R ( (uint16_t) 0x6880 )
+// WOL Config register
+#define WOL_CFG_R ( (uint16_t) 0x6884 )
+// WOL Status register
+#define WOL_STATUS_R ( (uint16_t) 0x6888 )
+
+// ASF Control register
+#define ASF_CTRL_R ( (uint16_t) 0x6c00 )
+// ASF Watchdog Timer register
+#define ASF_WATCHDOG_TIMER_R ( (uint16_t) 0x6c0c )
+// ASF Heartbeat Timer register
+#define ASF_HEARTBEAT_TIMER_R ( (uint16_t) 0x6c10 )
+// Poll ASF Timer register
+#define ASF_POLL_TIMER_R ( (uint16_t) 0x6c14 )
+// Poll Legacy Timer register
+#define POLL_LEGACY_TIMER_R ( (uint16_t) 0x6c18 )
+// Retransmission Timer register
+#define RETRANSMISSION_TIMER_R ( (uint16_t) 0x6c1c )
+// Time Stamp Counter register
+#define TIME_STAMP_COUNTER_R ( (uint16_t) 0x6c20 )
+
+// NVM Command register
+#define NVM_COM_R ( (uint16_t) 0x7000 )
+// NVM Write register
+#define NVM_WRITE_R ( (uint16_t) 0x7008 )
+// NVM Address register
+#define NVM_ADDR_R ( (uint16_t) 0x700c )
+// NVM Read registertg3_phy_copper_begin
+#define NVM_READ_R ( (uint16_t) 0x7010 )
+// NVM Access register
+#define NVM_ACC_R ( (uint16_t) 0x7024 )
+// NVM Config 1 register
+#define NVM_CFG1_R ( (uint16_t) 0x7014 )
+// Software arbitration register
+#define SW_ARB_R ( (uint16_t) 0x7020 )
+
+/*
+ * useful def's
+ */
+#define rd08(a) ci_read_8((uint8_t *)(a))
+#define rd16(a) ci_read_16((uint16_t *)(a))
+#define rd32(a) ci_read_32((uint32_t *)(a))
+#define wr08(a,v) ci_write_8((uint8_t *)(a), (v))
+#define wr16(a,v) ci_write_16((uint16_t *)(a), (v))
+#define wr32(a,v) ci_write_32((uint32_t *)(a), (v))
+
+#define BIT08( bit ) ( (uint8_t) 0x1 << (bit) )
+#define BIT16( bit ) ( (uint16_t) 0x1 << (bit) )
+#define BIT32( bit ) ( (uint32_t) 0x1 << (bit) )
+
+/*
+ * type definition
+ */
+
+/*
+ * Constants for different kinds of IOCTL requests
+ */
+
+#define SIOCETHTOOL 0x1000
+
+/*
+ * special structure and constants for IOCTL requests of type ETHTOOL
+ */
+
+#define ETHTOOL_GMAC 0x03
+#define ETHTOOL_SMAC 0x04
+#define ETHTOOL_VERSION 0x05
+
+typedef struct {
+ int idx;
+ char address[6];
+} ioctl_ethtool_mac_t;
+
+typedef struct {
+ unsigned int length;
+ char *text;
+} ioctl_ethtool_version_t;
+
+
+/*
+ * default structure and constants for IOCTL requests
+ */
+
+#define IF_NAME_SIZE 0xFF
+
+typedef struct {
+ char if_name[IF_NAME_SIZE];
+ int subcmd;
+ union {
+ ioctl_ethtool_mac_t mac;
+ ioctl_ethtool_version_t version;
+ } data;
+} ioctl_net_data_t;
+
+extern net_driver_t *bcm57xx_open(void);
+extern void bcm57xx_close(net_driver_t *driver);
+extern int bcm57xx_read(char *buf, int len);
+extern int bcm57xx_write(char *buf, int len);
diff --git a/src/roms/SLOF/lib/libbootmsg/Makefile b/src/roms/SLOF/lib/libbootmsg/Makefile
new file mode 100644
index 0000000..642c970
--- /dev/null
+++ b/src/roms/SLOF/lib/libbootmsg/Makefile
@@ -0,0 +1,75 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2008 IBM Corporation
+# * All rights reserved.
+# * This program and the accompanying materials
+# * are made available under the terms of the BSD License
+# * which accompanies this distribution, and is available at
+# * http://www.opensource.org/licenses/bsd-license.php
+# *
+# * Contributors:
+# * IBM Corporation - initial implementation
+# ****************************************************************************/
+
+TOPCMNDIR ?= ../..
+
+include $(TOPCMNDIR)/make.rules
+
+ASFLAGS = $(FLAG) $(RELEASE) $(CPUARCHDEF) -Wa,-mregnames
+CPPFLAGS = -I../libc/include $(CPUARCHDEF) -I$(INCLBRDDIR) -I. -I../../include
+LDFLAGS = -nostdlib
+
+TARGET = ../libbootmsg.a
+
+
+all: $(TARGET)
+
+ifeq ($(CPUARCH),cbea)
+SRCS =
+SRCSS = bootmsg_lvl.S
+else
+ifeq ($(CPUARCH),ppc970)
+SRCS =
+SRCSS = bootmsg_lvl.S
+else
+ifeq ($(CPUARCH),p5)
+SRCS =
+SRCSS = bootmsg_lvl.S
+else
+ifeq ($(CPUARCH),ppcp7)
+SRCS =
+SRCSS = bootmsg_lvl.S
+else
+SRCS = bootmsg.c
+SRCSS =
+endif
+endif
+endif
+endif
+
+OBJS = $(SRCS:%.c=%.o) $(SRCSS:%.S=%.o)
+
+$(TARGET): $(OBJS)
+ $(AR) -rc $@ $(OBJS)
+ $(RANLIB) $@
+
+%.o: %.S
+ $(CC) $(CPPFLAGS) $(ASFLAGS) -c $< -o $@
+
+clean:
+ $(RM) $(TARGET) $(OBJS)
+
+distclean: clean
+ $(RM) Makefile.dep
+
+
+# Rules for creating the dependency file:
+depend:
+ $(RM) Makefile.dep
+ $(MAKE) Makefile.dep
+
+Makefile.dep: Makefile
+ $(CC) -MM $(CPPFLAGS) $(CFLAGS) $(SRCS) $(SRCSS) > Makefile.dep
+
+# Include dependency file if available:
+-include Makefile.dep
+
diff --git a/src/roms/SLOF/lib/libbootmsg/bootmsg.code b/src/roms/SLOF/lib/libbootmsg/bootmsg.code
new file mode 100644
index 0000000..ae370af
--- /dev/null
+++ b/src/roms/SLOF/lib/libbootmsg/bootmsg.code
@@ -0,0 +1,61 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+#include <libbootmsg.h>
+
+// : cp ( cp-id -- )
+PRIM(bootmsg_X2d_cp)
+ int cpid = TOS.n; POP;
+ bootmsg_cp(cpid);
+MIRP
+
+// : bootmsg-warning ( cp-id lvl pstr -- )
+PRIM(bootmsg_X2d_warning)
+ char* str = TOS.a; POP;
+ short lvl = TOS.n; POP;
+ short cpid = TOS.n; POP;
+ bootmsg_warning(cpid, (const char*)str, lvl);
+MIRP
+
+// : bootmsg-error ( cp-id pstr -- )
+PRIM(bootmsg_X2d_error)
+ char* str = TOS.a; POP;
+ short cpid = TOS.n; POP;
+ bootmsg_error(cpid, (const char*)str);
+MIRP
+
+// : bootmsg-debugcp ( cp-id lvl pstr -- )
+PRIM(bootmsg_X2d_debugcp)
+ char* str = TOS.a; POP;
+ short lvl = TOS.n; POP;
+ short cpid = TOS.n; POP;
+ bootmsg_debugcp(cpid, (const char*)str, lvl);
+MIRP
+
+// : bootmsg-setlevel ( area lvl -- )
+PRIM(bootmsg_X2d_setlevel)
+ char lvl = TOS.n; POP;
+ short area = TOS.n; POP;
+ bootmsg_setlevel(area, lvl);
+MIRP
+
+// : bootmsg-checklevel ( area lvl -- [true|false] )
+PRIM(bootmsg_X2d_checklevel)
+ char lvl = TOS.n; POP;
+ short area = TOS.n; POP;
+ PUSH;
+ TOS.n = (bootmsg_checklevel(area, lvl)) ? -1 : 0;
+MIRP
+
+// : bootmsg-nvupdate ( -- )
+PRIM(bootmsg_X2d_nvupdate)
+ bootmsg_nvupdate();
+MIRP
diff --git a/src/roms/SLOF/lib/libbootmsg/bootmsg.in b/src/roms/SLOF/lib/libbootmsg/bootmsg.in
new file mode 100644
index 0000000..73e01e3
--- /dev/null
+++ b/src/roms/SLOF/lib/libbootmsg/bootmsg.in
@@ -0,0 +1,19 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+cod(bootmsg-cp)
+cod(bootmsg-warning)
+cod(bootmsg-error)
+cod(bootmsg-debugcp)
+cod(bootmsg-setlevel)
+cod(bootmsg-nvupdate)
+cod(bootmsg-checklevel)
diff --git a/src/roms/SLOF/lib/libbootmsg/bootmsg_lvl.S b/src/roms/SLOF/lib/libbootmsg/bootmsg_lvl.S
new file mode 100644
index 0000000..2e4c135
--- /dev/null
+++ b/src/roms/SLOF/lib/libbootmsg/bootmsg_lvl.S
@@ -0,0 +1,204 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+#define _ASM_
+#include "macros.h"
+#include "southbridge.h"
+#include "nvramlog.h"
+
+#define bootmsg_area_size 128
+
+ .text
+ .align 3
+
+// Declare the warning level for all 128 possibilities of AC/pCKG kombinations
+ WRNG_LVL:
+ .rept bootmsg_area_size
+ .byte 0x0
+ .endr
+
+
+//*****************************************************************************
+// Check UserWarningLevel against SystemWarningLevel
+// input : r3=cp-id, r5=level
+// change: r6,r7
+// output: CR0 ( compared user vs system level )
+// example:
+// bl GET_WRNG_LVL
+// ble print_warning
+// bgt do_not_print_warning
+ENTRY(GET_WRNG_LVL)
+ mflr r7 // save linkage register
+ bl 0f // get current
+0: mflr r6 // Instruction Address
+ mtlr r7 // restore linkage register
+ addi r6,r6,WRNG_LVL-0b // calc addr of WRNG_LVL array
+ rldic r7,r3,56,57 // calc index into array
+ lbzux r7,r6,r7 // read the warning level
+ cmpw r5,r7 // and compare it
+ blr
+
+//*****************************************************************************
+// Print CheckPoint
+// input : r3=cp-id
+// change: r3, r4, r5, r6, r7, r11
+// output: none
+ENTRY(bootmsg_cp)
+ mflr r11
+ mr r9, r3 // save checkpoint ID
+ li r3, 'C'
+ bl io_putchar // print character
+ mr r3, r9
+ bl io_printhex16 // print checkpoint ID
+ .rept 5
+ li r3,'\b'
+ bl io_putchar // print backspaces
+ .endr
+ mtlr r11
+ blr
+
+//*****************************************************************************
+// Print a general BootMessage
+// input : r3=cp-id, r4=string, r5=char (type C,W,E)
+// change: r3,r4,r5,r6,r7,r9,r10,r11,r12
+// output: none
+ENTRY(print_msg)
+ mflr r11 // Save linkage register
+ mr r9, r3 // Save ID
+ mr r10, r4 // Save ptr to string
+ mr r12, r5 // Save type (char [CWE])
+ li r3, '\n' // make it a new line
+ bl io_putchar
+ li r3, '\r'
+ bl io_putchar
+ mr r3, r12 // restore type
+ bl io_putchar // print character
+ mr r3, r9 // restore ID
+ bl io_printhex16 // print checkpoint ID
+ li r3, ' ' // print a space
+ bl io_putchar
+ mr r3, r10 // restore ptr to string
+ bl io_print // print message
+ li r3, '\n' // add a new line
+ bl io_putchar
+ li r3, '\r'
+ bl io_putchar
+ mtlr r11 // restore linkage register
+ blr
+
+//*****************************************************************************
+// Print an Error Boot Message
+// input : r3=cp-id, r4=string-ptr
+// change : r3,r4,r5,r6,r7,r9,r10,r11,r12
+// output : none
+ENTRY(bootmsg_error)
+ li r5, 'E' // E is for Error
+ b print_msg // and print this message
+
+//*****************************************************************************
+// Print a Warning Boot Message
+// input : r3=cp-id, r4=string-ptr, r5=level
+// change : r3,r4,r5,r6,r7,r9,r10,r11,r12
+// output : none
+ENTRY(bootmsg_warning)
+ mflr r11 // save linkage register
+ bl GET_WRNG_LVL // check UserLevel against SystemLevel
+ mtlr r11 // restore linkage register
+ li r5, 'W' // 'W' is for Warning
+ ble print_msg // if UserLevel<=SystemLevel print and return
+ blr // else return
+
+//*****************************************************************************
+// Print a Debug Checkpoint
+// input : r3=cp-id, r4=string-ptr, r5=level
+// change : r3,r4,r5,r6,r7,r9,r10,r11,r12
+// output : none
+// r3=cp-id, r4=string, r5=level
+ENTRY(bootmsg_debugcp)
+ mflr r11 // save linkage register
+ addi r5,r5,0x20 // add checkpoint offset
+ bl GET_WRNG_LVL // check UserLevel against SystemLevel
+ mtlr r11 // restore linkage register
+ li r5, 'D' // 'D' is for Debug CheckPoint
+ ble print_msg // if UserLevel<=SystemLevel print and return
+ blr // else return
+
+//*****************************************************************************
+// Check warning level
+// input : r3=cp-id, r4=level
+// change : r3,r4,r5,r6,r7,r9,r10,r11
+// output : r3 (true, false)
+// r3=cp-id, r4=level
+ENTRY(bootmsg_checklevel)
+ mflr r11
+ mr r5, r4
+ slwi r3, r3, 8
+ bl GET_WRNG_LVL // check UserLevel against SystemLevel
+ li r3, 0 // return 0
+ bgt 0f // IF ( UserLevel < SystemLevel )
+ li r3, 1 // | return 1
+0: mtlr r11 // FI
+ blr
+
+// r3=area|pkg, r4=level
+ENTRY(bootmsg_setlevel)
+ mflr r5
+ bl WarningMsg // calc current IA
+ WarningMsg:
+ mflr r6 // get current IA
+ addi r6,r6,WRNG_LVL-WarningMsg
+ andi. r3, r3, 0x7F
+ add r6,r3,r6 // address |
+ stb r4,0(r6) // store level |_ stwbrx r4,r3,r6
+
+#if !defined(DISABLE_NVRAM) && !defined(RTAS_NVRAM)
+ LOAD64(r6, SB_NVRAM_FWONLY_adr + 8 )
+ add r6,r6,r3
+ stb r4,0(r6)
+#endif
+ mtlr r5
+ blr
+
+ENTRY(bootmsg_nvupdate)
+#if !defined(DISABLE_NVRAM) && !defined(RTAS_NVRAM)
+ mflr r10
+ LOAD64(r3, SB_NVRAM_FWONLY_adr)
+ lwz r4, 0(r3)
+ cmpwi r4, 0x424E // find bootmsg area header
+ bne 0f
+
+ LOAD64(r5, bootmsg_area_size/8)
+ mtctr r5
+ bl WngMsg
+ WngMsg:
+ mflr r5
+ addi r5,r5,WRNG_LVL-WngMsg-8
+
+1:
+ ldu r4, 8(r3)
+ stdu r4, 8(r5)
+ bdnz+ 1b
+ b 2f
+
+0:
+ LOAD64(r5, bootmsg_area_size)
+ mtctr r5
+ li r4, 0x424E // clear bootmsg log area
+ stw r4, 0(r3)
+ li r4, 0
+
+1: stdu r4, 8(r3)
+ bdnz+ 1b
+
+2: // the end
+ mtlr r10
+#endif
+ blr
diff --git a/src/roms/SLOF/lib/libbootmsg/libbootmsg.h b/src/roms/SLOF/lib/libbootmsg/libbootmsg.h
new file mode 100644
index 0000000..9d0bd15
--- /dev/null
+++ b/src/roms/SLOF/lib/libbootmsg/libbootmsg.h
@@ -0,0 +1,21 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+#ifndef _LIBBOOTMSG_H
+#define _LIBBOOTMSG_H
+void bootmsg_cp(short p);
+void bootmsg_error(short p, const char *str);
+void bootmsg_warning(short p, const char *str, short lvl);
+void bootmsg_debugcp(short p, const char *str, short lvl);
+void bootmsg_setlevel(short p, short level);
+int bootmsg_checklevel(short p, short level);
+void *bootmsg_nvupdate(void);
+#endif /* _LIBBOOTMSG_H */
diff --git a/src/roms/SLOF/lib/libc/Makefile b/src/roms/SLOF/lib/libc/Makefile
new file mode 100644
index 0000000..0c762ec
--- /dev/null
+++ b/src/roms/SLOF/lib/libc/Makefile
@@ -0,0 +1,61 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2008 IBM Corporation
+# * All rights reserved.
+# * This program and the accompanying materials
+# * are made available under the terms of the BSD License
+# * which accompanies this distribution, and is available at
+# * http://www.opensource.org/licenses/bsd-license.php
+# *
+# * Contributors:
+# * IBM Corporation - initial implementation
+# ****************************************************************************/
+
+TOPCMNDIR ?= ../..
+
+LIBCCMNDIR = $(shell pwd)
+STRINGCMNDIR = $(LIBCCMNDIR)/string
+CTYPECMNDIR = $(LIBCCMNDIR)/ctype
+STDLIBCMNDIR = $(LIBCCMNDIR)/stdlib
+STDIOCMNDIR = $(LIBCCMNDIR)/stdio
+GETOPTCMNDIR = $(LIBCCMNDIR)/getopt
+
+include $(TOPCMNDIR)/make.rules
+
+
+CPPFLAGS = -I$(LIBCCMNDIR)/include
+LDFLAGS= -nostdlib
+
+TARGET = ../libc.a
+
+
+all: $(TARGET)
+
+# Use the following target to build a native version of the lib
+# (for example for debugging purposes):
+native:
+ $(MAKE) CROSS="" CC=$(HOSTCC) NATIVEBUILD=1
+
+
+include $(STRINGCMNDIR)/Makefile.inc
+include $(CTYPECMNDIR)/Makefile.inc
+include $(STDLIBCMNDIR)/Makefile.inc
+include $(STDIOCMNDIR)/Makefile.inc
+include $(GETOPTCMNDIR)/Makefile.inc
+
+OBJS = $(STRING_OBJS) $(CTYPE_OBJS) $(STDLIB_OBJS) $(STDIO_OBJS) $(GETOPT_OBJS)
+
+ifneq ($(NATIVEBUILD),1)
+# These parts of the libc use assembler, so they can only be compiled when
+# we are _not_ building a native version.
+endif
+
+
+$(TARGET): $(OBJS)
+ $(AR) -rc $@ $(OBJS)
+ $(RANLIB) $@
+
+
+clean:
+ $(RM) $(TARGET) $(OBJS)
+
+distclean: clean
diff --git a/src/roms/SLOF/lib/libc/README.txt b/src/roms/SLOF/lib/libc/README.txt
new file mode 100644
index 0000000..eaafdf4
--- /dev/null
+++ b/src/roms/SLOF/lib/libc/README.txt
@@ -0,0 +1,49 @@
+
+ Standard C library for the SLOF firmware project
+ ================================================
+
+To use this library, link your target against the "libc.a" archive.
+
+However, there are some prerequisites before you can use certain parts of the
+library:
+
+1) If you want to use malloc() and the like, you have to supply an implemen-
+ tation of sbrk() in your own code. malloc() uses sbrk() to get new, free
+ memory regions.
+
+ Prototype: void *sbrk(int incr);
+ Description: sbrk() increments the available data space by incr bytes and
+ returns a pointer to the start of the new area.
+
+ See the man-page of sbrk for details about this function.
+
+2) Before you can use the stdio output functions like printf(), puts() and the
+ like, you have to provide a standard write() function in your code.
+ printf() and the like use write() to print out the strings to the standard
+ output.
+
+ Prototype: ssize_t write(int fd, const void *buf, size_t cnt);
+ Description: Write cnt byte from the buffer buf to the stream associated
+ with the file descriptor fd.
+
+ The stdio functions will print their output to the stdout channel which is
+ assigned with the file descriptor 1 by default. Note that the stdio
+ functions will not use open() before calling write(), so if the stdout
+ cannel needs to be opened first, you should do that in your start-up code
+ before using the libc functions for the first time.
+
+3) Before you can use the stdio input functions like scanf() and the
+ like, you have to provide a standard read() function in your code.
+ scanf() and the like use read() to get the characters from the standard
+ input.
+
+ Prototype: ssize_t read(int fd, void *buf, size_t cnt);
+ Description: Read cnt byte from the stream associated with the file
+ descriptor fd and put them into the buffer buf.
+
+ The stdio functions will get their input from the stdin channel which is
+ assigned with the file descriptor 0 by default. Note that the stdio
+ functions will not use open() before calling read(), so if the stdin
+ cannel needs to be opened first, you should do that in your start-up code
+ before using the libc functions for the first time.
+
diff --git a/src/roms/SLOF/lib/libc/ctype/Makefile.inc b/src/roms/SLOF/lib/libc/ctype/Makefile.inc
new file mode 100644
index 0000000..25513a9
--- /dev/null
+++ b/src/roms/SLOF/lib/libc/ctype/Makefile.inc
@@ -0,0 +1,20 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2008 IBM Corporation
+# * All rights reserved.
+# * This program and the accompanying materials
+# * are made available under the terms of the BSD License
+# * which accompanies this distribution, and is available at
+# * http://www.opensource.org/licenses/bsd-license.php
+# *
+# * Contributors:
+# * IBM Corporation - initial implementation
+# ****************************************************************************/
+
+
+CTYPE_SRC_C = isdigit.c isprint.c isspace.c isxdigit.c tolower.c toupper.c
+CTYPE_SRC_ASM =
+CTYPE_SRCS = $(CTYPE_SRC_C:%=$(CTYPECMNDIR)/%) $(CTYPE_SRC_ASM:%=$(CTYPECMNDIR)/%)
+CTYPE_OBJS = $(CTYPE_SRC_C:%.c=%.o) $(CTYPE_SRC_ASM:%.S=%.o)
+
+%.o : $(CTYPECMNDIR)/%.c
+ $(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@
diff --git a/src/roms/SLOF/lib/libc/ctype/isdigit.c b/src/roms/SLOF/lib/libc/ctype/isdigit.c
new file mode 100644
index 0000000..62d08a1
--- /dev/null
+++ b/src/roms/SLOF/lib/libc/ctype/isdigit.c
@@ -0,0 +1,25 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <ctype.h>
+
+int isdigit(int ch)
+{
+ switch (ch) {
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ return 1;
+
+ default:
+ return 0;
+ }
+}
diff --git a/src/roms/SLOF/lib/libc/ctype/isprint.c b/src/roms/SLOF/lib/libc/ctype/isprint.c
new file mode 100644
index 0000000..c74880f
--- /dev/null
+++ b/src/roms/SLOF/lib/libc/ctype/isprint.c
@@ -0,0 +1,18 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <ctype.h>
+
+int isprint(int ch)
+{
+ return (ch >= 32 && ch < 127);
+}
diff --git a/src/roms/SLOF/lib/libc/ctype/isspace.c b/src/roms/SLOF/lib/libc/ctype/isspace.c
new file mode 100644
index 0000000..5123019
--- /dev/null
+++ b/src/roms/SLOF/lib/libc/ctype/isspace.c
@@ -0,0 +1,29 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <ctype.h>
+
+int isspace(int ch)
+{
+ switch (ch) {
+ case ' ':
+ case '\f':
+ case '\n':
+ case '\r':
+ case '\t':
+ case '\v':
+ return 1;
+
+ default:
+ return 0;
+ }
+}
diff --git a/src/roms/SLOF/lib/libc/ctype/isxdigit.c b/src/roms/SLOF/lib/libc/ctype/isxdigit.c
new file mode 100644
index 0000000..9d323f3
--- /dev/null
+++ b/src/roms/SLOF/lib/libc/ctype/isxdigit.c
@@ -0,0 +1,21 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <ctype.h>
+
+int isxdigit(int ch)
+{
+ return (
+ (ch >= '0' && ch <= '9') |
+ (ch >= 'A' && ch <= 'F') |
+ (ch >= 'a' && ch <= 'f') );
+}
diff --git a/src/roms/SLOF/lib/libc/ctype/tolower.c b/src/roms/SLOF/lib/libc/ctype/tolower.c
new file mode 100644
index 0000000..f775e90
--- /dev/null
+++ b/src/roms/SLOF/lib/libc/ctype/tolower.c
@@ -0,0 +1,18 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <ctype.h>
+
+int tolower(int c)
+{
+ return (((c >= 'A') && (c <= 'Z')) ? (c - 'A' + 'a' ) : c);
+}
diff --git a/src/roms/SLOF/lib/libc/ctype/toupper.c b/src/roms/SLOF/lib/libc/ctype/toupper.c
new file mode 100644
index 0000000..9bcee52
--- /dev/null
+++ b/src/roms/SLOF/lib/libc/ctype/toupper.c
@@ -0,0 +1,21 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+
+#include "ctype.h"
+
+int toupper (int cha)
+{
+ if((cha >= 'a') && (cha <= 'z'))
+ return(cha - 'a' + 'A');
+ return(cha);
+}
diff --git a/src/roms/SLOF/lib/libc/getopt/Makefile.inc b/src/roms/SLOF/lib/libc/getopt/Makefile.inc
new file mode 100644
index 0000000..8a2e32f
--- /dev/null
+++ b/src/roms/SLOF/lib/libc/getopt/Makefile.inc
@@ -0,0 +1,17 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2008 IBM Corporation
+# * All rights reserved.
+# * This program and the accompanying materials
+# * are made available under the terms of the BSD License
+# * which accompanies this distribution, and is available at
+# * http://www.opensource.org/licenses/bsd-license.php
+# *
+# * Contributors:
+# * IBM Corporation - initial implementation
+# ****************************************************************************/
+
+GETOPT_SRC_C = getopt.c
+GETOPT_OBJS = $(GETOPT_SRC_C:%.c=%.o)
+
+%.o : $(GETOPTCMNDIR)/%.c
+ $(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@
diff --git a/src/roms/SLOF/lib/libc/getopt/getopt.c b/src/roms/SLOF/lib/libc/getopt/getopt.c
new file mode 100644
index 0000000..be626dd
--- /dev/null
+++ b/src/roms/SLOF/lib/libc/getopt/getopt.c
@@ -0,0 +1,470 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+/*
+ * includes
+ *******************************************************************************
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+
+/*
+ * global variables, types & constants
+ * may be removed if already defined
+ *******************************************************************************
+ */
+int opterr = 1;
+int optopt = 0;
+int optind = 1;
+char *optarg = NULL;
+
+/*
+ * internal values needed by getopt
+ * DO NOT CHANGE or REMOVE
+ */
+enum {
+ OPTIONAL_ARG = 0,
+ MANDATORY_ARG = 1,
+ NO_ARG = 2
+};
+
+/*
+ * variables needed by getopt & getopt_long!
+ * DO NOT REMOVE
+ */
+static char *optstart = NULL;
+
+int
+getopt(int argc, char **argv, const char *options)
+{
+ char *optptr;
+ char *argptr;
+ int optman;
+ int idx;
+ int ret = 0;
+ int argpresent;
+
+ /*
+ * reset used global values
+ */
+ optopt = 0;
+ optarg = NULL;
+
+ /*
+ * reset getopt if a new argv pointer is passed
+ */
+ if (optstart != argv[0]) {
+ optopt = 0;
+ optind = 1;
+ optarg = NULL;
+ optstart = argv[0];
+ }
+
+ /*
+ * return if no more arguments are available
+ */
+ if (optind >= argc) {
+ return -1;
+ }
+
+ /*
+ * start parsing argv[optind]
+ */
+ idx = 0;
+
+ /*
+ * return if the option does not begin with a '-' or has more than 2 characters
+ */
+ if (argv[optind][idx] != '-') {
+
+ if (opterr != 0) {
+ printf("unknown option \'%s\', expecting \'-\'\n",
+ argv[optind]);
+ }
+
+ optopt = (int) argv[optind][idx];
+ optind++;
+
+ return '?';
+ }
+
+ /*
+ * continue to the next character in argv[optind]
+ */
+ idx++;
+
+ /*
+ * identify the option
+ * make sure if an option contains a ':' to invalidate the option
+ */
+ optptr = strchr(argv[optind], ':');
+
+ if (optptr == NULL) {
+ optptr = strchr(options, (int) argv[optind][idx]);
+ } else {
+ optptr = NULL;
+ }
+
+ /*
+ * check whether the option is present
+ */
+ if (optptr == NULL) {
+ /*
+ * unknown option detected
+ */
+ if (opterr != 0) {
+ printf("unknown option \'%s\'\n", argv[optind]);
+ }
+
+ optopt = (int) argv[optind][idx];
+ optind++;
+
+ return '?';
+ }
+
+ /*
+ * the option is present in the option string
+ * setup return value
+ */
+ ret = (int) *optptr;
+
+ /*
+ * get option argument if needed
+ */
+ optptr++;
+
+ /*
+ * determine between mandatory and optional argument
+ */
+ optman = NO_ARG;
+
+ if (*optptr == ':') {
+ optman--; // now set to MANDATORY_ARG
+ }
+
+ if (optman == MANDATORY_ARG) {
+ optptr++;
+
+ if (*optptr == ':') {
+ optman--; // now set to OPTIONAL_ARG
+ }
+
+ }
+
+ /*
+ * if strlen( argv[optind ) is greater than 2,
+ * the argument is in the same argv
+ */
+ if (strlen(argv[optind]) > 2) {
+ argptr = &argv[optind][2];
+
+ /*
+ * do not allow '-' in an argument
+ */
+ if (strchr(argptr, '-') != NULL) {
+
+ if (opterr != 0) {
+ printf
+ ("illegal argument value \'%s\' for option \'-%c\'\n",
+ argptr, ret);
+ }
+
+ optopt = ret;
+
+ return '?';
+ }
+
+ } else {
+ /*
+ * move on to the next argv
+ * it now either contains an argument or the next option
+ */
+ optind++;
+
+ /*
+ * make sure not to overflow
+ */
+ if (optind < argc) {
+ argptr = argv[optind];
+ } else {
+ argptr = NULL;
+ }
+
+ }
+
+ /*
+ * do the needed actions for the argument state
+ */
+ switch (optman) {
+ case OPTIONAL_ARG:
+
+ if (argptr == NULL) {
+ break;
+ }
+
+ if (*argptr != '-') {
+ /*
+ * argument present
+ */
+ optarg = argptr;
+ optind++;
+
+ }
+
+
+ break;
+
+ case MANDATORY_ARG:
+ argpresent = (argptr != NULL);
+
+ if (argpresent) {
+ argpresent = (*argptr != '-');
+ }
+
+ if (argpresent) {
+ /*
+ * argument present
+ */
+ optarg = argptr;
+ optind++;
+ } else {
+ /*
+ * mandatory argument missing
+ */
+ if (opterr != 0) {
+ printf
+ ("missing argument for option \'-%c\'\n",
+ ret);
+ }
+
+ optopt = ret;
+
+ /*
+ * if the first character of options is a ':'
+ * return a ':' instead of a '?' in case of
+ * a missing argument
+ */
+ if (*options == ':') {
+ ret = ':';
+ } else {
+ ret = '?';
+ }
+
+ }
+
+
+ break;
+
+ case NO_ARG:
+
+ if (strlen(argv[optind - 1]) > 2) {
+
+ if (opterr != 0) {
+ printf
+ ("too many arguments for option \'-%c\'\n",
+ ret);
+ }
+
+ optopt = ret;
+ ret = '?';
+ }
+
+
+ break;
+
+ }
+
+ return ret;
+}
+
+int
+getopt_long(int argc, char **argv, const char *shortopts,
+ const struct option *longopts, int *indexptr)
+{
+ struct option *optptr = (struct option *) longopts;
+ int optidx = 0;
+ int idx;
+ int ret = 0;
+ int argpresent;
+
+ /*
+ * reset used global values
+ */
+ optopt = 0;
+ optarg = NULL;
+
+ /*
+ * reset indexptr
+ */
+ *indexptr = -1;
+
+ /*
+ * reset getopt if a new argv pointer is passed
+ */
+ if (optstart != argv[0]) {
+ optopt = 0;
+ optind = 1;
+ optarg = NULL;
+ optstart = argv[0];
+ }
+
+ /*
+ * return if no more arguments are available
+ */
+ if (optind >= argc) {
+ return -1;
+ }
+
+ /*
+ * start parsing argv[optind]
+ */
+ idx = 0;
+
+ /*
+ * return if the option does not begin with a '-'
+ */
+ if (argv[optind][idx] != '-') {
+ printf("unknown option \'%s\', expecting \'-\'\n",
+ argv[optind]);
+
+ optind++;
+
+ return '?';
+ }
+
+ /*
+ * move on to the next character in argv[optind]
+ */
+ idx++;
+
+ /*
+ * return getopt() in case of a short option
+ */
+ if (argv[optind][idx] != '-') {
+ return getopt(argc, argv, shortopts);
+ }
+
+ /*
+ * handle a long option
+ */
+ idx++;
+
+ while (optptr->name != NULL) {
+
+ if (strcmp(&argv[optind][idx], optptr->name) == 0) {
+ break;
+ }
+
+ optptr++;
+ optidx++;
+ }
+
+ /*
+ * no matching option found
+ */
+ if (optptr->name == NULL) {
+ printf("unknown option \'%s\'\n", argv[optind]);
+
+ optind++;
+
+ return '?';
+ }
+
+ /*
+ * option was found, set up index pointer
+ */
+ *indexptr = optidx;
+
+ /*
+ * get argument
+ */
+ optind++;
+
+ switch (optptr->has_arg) {
+ case no_argument:
+ /*
+ * nothing to do
+ */
+
+ break;
+
+ case required_argument:
+ argpresent = (optind != argc);
+
+ if (argpresent) {
+ argpresent = (argv[optind][0] != '-');
+ }
+
+ if (argpresent) {
+ /*
+ * argument present
+ */
+ optarg = argv[optind];
+ optind++;
+ } else {
+ /*
+ * mandatory argument missing
+ */
+ printf("missing argument for option \'%s\'\n",
+ argv[optind - 1]);
+
+ ret = '?';
+ }
+
+
+ break;
+
+ case optional_argument:
+
+ if (optind == argc) {
+ break;
+ }
+
+ if (argv[optind][0] != '-') {
+ /*
+ * argument present
+ */
+ optarg = argv[optind];
+ optind++;
+ }
+
+
+ break;
+
+ default:
+ printf("unknown argument option for option \'%s\'\n",
+ argv[optind - 1]);
+
+ ret = '?';
+
+ break;
+
+ }
+
+ /*
+ * setup return values
+ */
+ if (ret != '?') {
+
+ if (optptr->flag == NULL) {
+ ret = optptr->val;
+ } else {
+ *optptr->flag = optptr->val;
+ ret = 0;
+ }
+
+ }
+
+ return ret;
+}
diff --git a/src/roms/SLOF/lib/libc/include/ctype.h b/src/roms/SLOF/lib/libc/include/ctype.h
new file mode 100644
index 0000000..9051a75
--- /dev/null
+++ b/src/roms/SLOF/lib/libc/include/ctype.h
@@ -0,0 +1,24 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#ifndef _CTYPE_H
+#define _CTYPE_H
+
+int isdigit(int c);
+int isxdigit(int c);
+int isprint(int c);
+int isspace(int c);
+
+int tolower(int c);
+int toupper(int c);
+
+#endif
diff --git a/src/roms/SLOF/lib/libc/include/errno.h b/src/roms/SLOF/lib/libc/include/errno.h
new file mode 100644
index 0000000..d585934
--- /dev/null
+++ b/src/roms/SLOF/lib/libc/include/errno.h
@@ -0,0 +1,34 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#ifndef _ERRNO_H
+#define _ERRNO_H
+
+extern int errno;
+
+/*
+ * Error number definitions
+ */
+#define EPERM 1 /* not permitted */
+#define ENOENT 2 /* file or directory not found */
+#define EIO 5 /* input/output error */
+#define ENOMEM 12 /* not enough space */
+#define EACCES 13 /* permission denied */
+#define EFAULT 14 /* bad address */
+#define EBUSY 16 /* resource busy */
+#define EEXIST 17 /* file already exists */
+#define ENODEV 19 /* device not found */
+#define EINVAL 22 /* invalid argument */
+#define EDOM 33 /* math argument out of domain of func */
+#define ERANGE 34 /* math result not representable */
+
+#endif
diff --git a/src/roms/SLOF/lib/libc/include/getopt.h b/src/roms/SLOF/lib/libc/include/getopt.h
new file mode 100644
index 0000000..5956986
--- /dev/null
+++ b/src/roms/SLOF/lib/libc/include/getopt.h
@@ -0,0 +1,37 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#ifndef GETOPT_H
+#define GETOPT_H
+
+extern char *optarg;
+extern int optind;
+extern int opterr;
+extern int optopt;
+
+struct option {
+ const char *name;
+ int has_arg;
+ int *flag;
+ int val;
+};
+
+enum {
+ no_argument = 0,
+ required_argument,
+ optional_argument
+};
+
+int getopt(int argc, char **, const char *);
+int getopt_long(int argc, char **, const char *, const struct option *, int *);
+
+#endif /* GETOPT_H */
diff --git a/src/roms/SLOF/lib/libc/include/limits.h b/src/roms/SLOF/lib/libc/include/limits.h
new file mode 100644
index 0000000..4726835
--- /dev/null
+++ b/src/roms/SLOF/lib/libc/include/limits.h
@@ -0,0 +1,32 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#ifndef _LIMITS_H
+#define _LIMITS_H
+
+#define UCHAR_MAX 255
+#define SCHAR_MAX 127
+#define SCHAR_MIN (-128)
+
+#define USHRT_MAX 65535
+#define SHRT_MAX 32767
+#define SHRT_MIN (-32768)
+
+#define UINT_MAX (4294967295U)
+#define INT_MAX 2147483647
+#define INT_MIN (-2147483648)
+
+#define ULONG_MAX ((unsigned long)-1L)
+#define LONG_MAX (ULONG_MAX/2)
+#define LONG_MIN ((-LONG_MAX)-1)
+
+#endif
diff --git a/src/roms/SLOF/lib/libc/include/stdarg.h b/src/roms/SLOF/lib/libc/include/stdarg.h
new file mode 100644
index 0000000..d3d12f7
--- /dev/null
+++ b/src/roms/SLOF/lib/libc/include/stdarg.h
@@ -0,0 +1,22 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#ifndef _STDARG_H
+#define _STDARG_H
+
+typedef __builtin_va_list va_list;
+
+#define va_start(v,l) __builtin_va_start(v,l)
+#define va_arg(v,l) __builtin_va_arg(v,l)
+#define va_end(v) __builtin_va_end(v)
+
+#endif
diff --git a/src/roms/SLOF/lib/libc/include/stdbool.h b/src/roms/SLOF/lib/libc/include/stdbool.h
new file mode 100644
index 0000000..5b7d36a
--- /dev/null
+++ b/src/roms/SLOF/lib/libc/include/stdbool.h
@@ -0,0 +1,20 @@
+/******************************************************************************
+ * Copyright (c) 2013 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#ifndef _STDBOOL_H
+#define _STDBOOL_H
+
+#ifndef __cplusplus
+typedef enum { false = 0, true } bool;
+#endif
+
+#endif
diff --git a/src/roms/SLOF/lib/libc/include/stddef.h b/src/roms/SLOF/lib/libc/include/stddef.h
new file mode 100644
index 0000000..ba2d960
--- /dev/null
+++ b/src/roms/SLOF/lib/libc/include/stddef.h
@@ -0,0 +1,25 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#ifndef _STDDEF_H
+#define _STDDEF_H
+
+
+#define NULL ((void *)0)
+
+
+typedef unsigned int size_t;
+
+
+#endif
+
+
diff --git a/src/roms/SLOF/lib/libc/include/stdint.h b/src/roms/SLOF/lib/libc/include/stdint.h
new file mode 100644
index 0000000..518a723
--- /dev/null
+++ b/src/roms/SLOF/lib/libc/include/stdint.h
@@ -0,0 +1,28 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#ifndef _STDINT_H
+#define _STDINT_H
+
+typedef unsigned char uint8_t;
+typedef signed char int8_t;
+
+typedef unsigned short uint16_t;
+typedef signed short int16_t;
+
+typedef unsigned int uint32_t;
+typedef signed int int32_t;
+
+typedef unsigned long long uint64_t;
+typedef signed long long int64_t;
+
+#endif
diff --git a/src/roms/SLOF/lib/libc/include/stdio.h b/src/roms/SLOF/lib/libc/include/stdio.h
new file mode 100644
index 0000000..84cddea
--- /dev/null
+++ b/src/roms/SLOF/lib/libc/include/stdio.h
@@ -0,0 +1,63 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#ifndef _STDIO_H
+#define _STDIO_H
+
+#include <stdarg.h>
+#include "stddef.h"
+
+#define EOF (-1)
+
+#define _IONBF 0
+#define _IOLBF 1
+#define _IOFBF 2
+#define BUFSIZ 80
+
+typedef struct {
+ int fd;
+ int mode;
+ int pos;
+ char *buf;
+ int bufsiz;
+} FILE;
+
+extern FILE stdin_data;
+extern FILE stdout_data;
+extern FILE stderr_data;
+
+#define stdin (&stdin_data)
+#define stdout (&stdout_data)
+#define stderr (&stderr_data)
+
+int fileno(FILE *stream);
+int printf(const char *format, ...) __attribute__((format (printf, 1, 2)));
+int fprintf(FILE *stream, const char *format, ...) __attribute__((format (printf, 2, 3)));
+int sprintf(char *str, const char *format, ...) __attribute__((format (printf, 2, 3)));
+int vfprintf(FILE *stream, const char *format, va_list);
+int vsprintf(char *str, const char *format, va_list);
+int vsnprintf(char *str, size_t size, const char *format, va_list);
+void setbuf(FILE *stream, char *buf);
+int setvbuf(FILE *stream, char *buf, int mode , size_t size);
+
+int putc(int ch, FILE *stream);
+int putchar(int ch);
+int puts(char *str);
+
+int scanf(const char *format, ...) __attribute__((format (scanf, 1, 2)));
+int fscanf(FILE *stream, const char *format, ...) __attribute__((format (scanf, 2, 3)));
+int vfscanf(FILE *stream, const char *format, va_list);
+int vsscanf(const char *str, const char *format, va_list);
+int getc(FILE *stream);
+int getchar(void);
+
+#endif
diff --git a/src/roms/SLOF/lib/libc/include/stdlib.h b/src/roms/SLOF/lib/libc/include/stdlib.h
new file mode 100644
index 0000000..dff57f5
--- /dev/null
+++ b/src/roms/SLOF/lib/libc/include/stdlib.h
@@ -0,0 +1,33 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#ifndef _STDLIB_H
+#define _STDLIB_H
+
+#include "stddef.h"
+
+#define RAND_MAX 32767
+
+
+void *malloc(size_t size);
+void *realloc(void *ptr, size_t size);
+void free(void *ptr);
+void *memalign(size_t boundary, size_t size);
+
+int atoi(const char *str);
+long atol(const char *str);
+unsigned long int strtoul(const char *nptr, char **endptr, int base);
+long int strtol(const char *nptr, char **endptr, int base);
+
+int rand(void);
+
+#endif
diff --git a/src/roms/SLOF/lib/libc/include/string.h b/src/roms/SLOF/lib/libc/include/string.h
new file mode 100644
index 0000000..0163c9a
--- /dev/null
+++ b/src/roms/SLOF/lib/libc/include/string.h
@@ -0,0 +1,37 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#ifndef _STRING_H
+#define _STRING_H
+
+#include "stddef.h"
+
+char *strcpy(char *dest, const char *src);
+char *strncpy(char *dest, const char *src, size_t n);
+char *strcat(char *dest, const char *src);
+int strcmp(const char *s1, const char *s2);
+int strncmp(const char *s1, const char *s2, size_t n);
+int strcasecmp(const char *s1, const char *s2);
+int strncasecmp(const char *s1, const char *s2, size_t n);
+char *strchr(const char *s, int c);
+char *strrchr(const char *s, int c);
+size_t strlen(const char *s);
+char *strstr(const char *hay, const char *needle);
+char *strtok(char *src, const char *pattern);
+
+void *memset(void *s, int c, size_t n);
+void *memchr(const void *s, int c, size_t n);
+void *memcpy(void *dest, const void *src, size_t n);
+void *memmove(void *dest, const void *src, size_t n);
+int memcmp(const void *s1, const void *s2, size_t n);
+
+#endif
diff --git a/src/roms/SLOF/lib/libc/include/unistd.h b/src/roms/SLOF/lib/libc/include/unistd.h
new file mode 100644
index 0000000..07210d6
--- /dev/null
+++ b/src/roms/SLOF/lib/libc/include/unistd.h
@@ -0,0 +1,28 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#ifndef _UNISTD_H
+#define _UNISTD_H
+
+#include <stddef.h>
+
+typedef long ssize_t;
+
+extern int open(const char *name, int flags);
+extern int close(int fd);
+extern ssize_t read(int fd, void *buf, size_t count);
+extern ssize_t write(int fd, const void *buf, size_t count);
+extern ssize_t lseek(int fd, long offset, int whence);
+
+extern void *sbrk(int increment);
+
+#endif
diff --git a/src/roms/SLOF/lib/libc/stdio/Makefile.inc b/src/roms/SLOF/lib/libc/stdio/Makefile.inc
new file mode 100644
index 0000000..ac5302d
--- /dev/null
+++ b/src/roms/SLOF/lib/libc/stdio/Makefile.inc
@@ -0,0 +1,23 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2008 IBM Corporation
+# * All rights reserved.
+# * This program and the accompanying materials
+# * are made available under the terms of the BSD License
+# * which accompanies this distribution, and is available at
+# * http://www.opensource.org/licenses/bsd-license.php
+# *
+# * Contributors:
+# * IBM Corporation - initial implementation
+# ****************************************************************************/
+
+
+STDIO_SRC_C = fscanf.c sprintf.c vfprintf.c vsnprintf.c vsprintf.c fprintf.c \
+ printf.c setvbuf.c putc.c puts.c putchar.c scanf.c stdchnls.c \
+ vfscanf.c vsscanf.c fileno.c
+
+STDIO_SRC_ASM =
+STDIO_SRCS = $(STDIO_SRC_C:%=$(STDIOCMNDIR)/%) $(STDIO_SRC_ASM:%=$(STDIOCMNDIR)/%)
+STDIO_OBJS = $(STDIO_SRC_C:%.c=%.o) $(STDIO_SRC_ASM:%.S=%.o)
+
+%.o : $(STDIOCMNDIR)/%.c
+ $(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@
diff --git a/src/roms/SLOF/lib/libc/stdio/fileno.c b/src/roms/SLOF/lib/libc/stdio/fileno.c
new file mode 100644
index 0000000..6e23951
--- /dev/null
+++ b/src/roms/SLOF/lib/libc/stdio/fileno.c
@@ -0,0 +1,19 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <stdio.h>
+
+int
+fileno(FILE *stream)
+{
+ return stream->fd;
+}
diff --git a/src/roms/SLOF/lib/libc/stdio/fprintf.c b/src/roms/SLOF/lib/libc/stdio/fprintf.c
new file mode 100644
index 0000000..866df39
--- /dev/null
+++ b/src/roms/SLOF/lib/libc/stdio/fprintf.c
@@ -0,0 +1,26 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include "stdio.h"
+
+
+int fprintf(FILE *stream, const char* fmt, ...)
+{
+ int count;
+ va_list ap;
+
+ va_start(ap, fmt);
+ count = vfprintf(stream, fmt, ap);
+ va_end(ap);
+
+ return count;
+}
diff --git a/src/roms/SLOF/lib/libc/stdio/fscanf.c b/src/roms/SLOF/lib/libc/stdio/fscanf.c
new file mode 100644
index 0000000..321b163
--- /dev/null
+++ b/src/roms/SLOF/lib/libc/stdio/fscanf.c
@@ -0,0 +1,26 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <stdio.h>
+
+int
+fscanf(FILE *stream, const char *fmt, ...)
+{
+ int count;
+ va_list ap;
+
+ va_start(ap, fmt);
+ count = vfscanf(stream, fmt, ap);
+ va_end(ap);
+
+ return count;
+}
diff --git a/src/roms/SLOF/lib/libc/stdio/printf.c b/src/roms/SLOF/lib/libc/stdio/printf.c
new file mode 100644
index 0000000..01f4592
--- /dev/null
+++ b/src/roms/SLOF/lib/libc/stdio/printf.c
@@ -0,0 +1,27 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include "stdio.h"
+
+
+int printf(const char* fmt, ...)
+{
+ int count;
+ va_list ap;
+
+ va_start(ap, fmt);
+ count = vfprintf(stdout, fmt, ap);
+ va_end(ap);
+
+ return count;
+}
+
diff --git a/src/roms/SLOF/lib/libc/stdio/putc.c b/src/roms/SLOF/lib/libc/stdio/putc.c
new file mode 100644
index 0000000..230e9d1
--- /dev/null
+++ b/src/roms/SLOF/lib/libc/stdio/putc.c
@@ -0,0 +1,25 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include "stdio.h"
+#include "unistd.h"
+
+int
+putc(int ch, FILE *stream)
+{
+ unsigned char outchar = ch;
+
+ if (write(stream->fd, &outchar, 1) == 1)
+ return outchar;
+ else
+ return EOF;
+}
diff --git a/src/roms/SLOF/lib/libc/stdio/putchar.c b/src/roms/SLOF/lib/libc/stdio/putchar.c
new file mode 100644
index 0000000..5c750d9
--- /dev/null
+++ b/src/roms/SLOF/lib/libc/stdio/putchar.c
@@ -0,0 +1,21 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+
+#include "stdio.h"
+
+
+int
+putchar(int ch)
+{
+ return putc(ch, stdout);
+}
diff --git a/src/roms/SLOF/lib/libc/stdio/puts.c b/src/roms/SLOF/lib/libc/stdio/puts.c
new file mode 100644
index 0000000..3f48dbf
--- /dev/null
+++ b/src/roms/SLOF/lib/libc/stdio/puts.c
@@ -0,0 +1,28 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+
+#include "stdio.h"
+#include "string.h"
+#include "unistd.h"
+
+
+int
+puts(char *str)
+{
+ int ret;
+
+ ret = write(stdout->fd, str, strlen(str));
+ write(stdout->fd, "\r\n", 2);
+
+ return ret;
+}
diff --git a/src/roms/SLOF/lib/libc/stdio/scanf.c b/src/roms/SLOF/lib/libc/stdio/scanf.c
new file mode 100644
index 0000000..96b6399
--- /dev/null
+++ b/src/roms/SLOF/lib/libc/stdio/scanf.c
@@ -0,0 +1,26 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <stdio.h>
+
+int
+scanf(const char *fmt, ...)
+{
+ int count;
+ va_list ap;
+
+ va_start(ap, fmt);
+ count = vfscanf(stdin, fmt, ap);
+ va_end(ap);
+
+ return count;
+}
diff --git a/src/roms/SLOF/lib/libc/stdio/setvbuf.c b/src/roms/SLOF/lib/libc/stdio/setvbuf.c
new file mode 100644
index 0000000..9b62dd8
--- /dev/null
+++ b/src/roms/SLOF/lib/libc/stdio/setvbuf.c
@@ -0,0 +1,28 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <stdio.h>
+
+int setvbuf(FILE *stream, char *buf, int mode , size_t size)
+{
+ if (mode != _IONBF && mode != _IOLBF && mode != _IOFBF)
+ return -1;
+ stream->buf = buf;
+ stream->mode = mode;
+ stream->bufsiz = size;
+ return 0;
+}
+
+void setbuf(FILE *stream, char *buf)
+{
+ setvbuf(stream, buf, buf ? _IOFBF : _IONBF, BUFSIZ);
+}
diff --git a/src/roms/SLOF/lib/libc/stdio/sprintf.c b/src/roms/SLOF/lib/libc/stdio/sprintf.c
new file mode 100644
index 0000000..9c4540e
--- /dev/null
+++ b/src/roms/SLOF/lib/libc/stdio/sprintf.c
@@ -0,0 +1,30 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <stdio.h>
+
+
+int sprintf(char *buff, const char *format, ...)
+{
+ va_list ar;
+ int count;
+
+ if ((buff==NULL) || (format==NULL))
+ return(-1);
+
+ va_start(ar, format);
+ count = vsprintf(buff, format, ar);
+ va_end(ar);
+
+ return(count);
+}
+
diff --git a/src/roms/SLOF/lib/libc/stdio/stdchnls.c b/src/roms/SLOF/lib/libc/stdio/stdchnls.c
new file mode 100644
index 0000000..41ed958
--- /dev/null
+++ b/src/roms/SLOF/lib/libc/stdio/stdchnls.c
@@ -0,0 +1,23 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+
+#include "stdio.h"
+
+static char stdin_buffer[BUFSIZ], stdout_buffer[BUFSIZ];
+
+FILE stdin_data = { .fd = 0, .mode = _IOLBF, .pos = 0,
+ .buf = stdin_buffer, .bufsiz = BUFSIZ };
+FILE stdout_data = { .fd = 1, .mode = _IOLBF, .pos = 0,
+ .buf = stdout_buffer, .bufsiz = BUFSIZ };
+FILE stderr_data = { .fd = 2, .mode = _IONBF, .pos = 0,
+ .buf = NULL, .bufsiz = 0 };
diff --git a/src/roms/SLOF/lib/libc/stdio/vfprintf.c b/src/roms/SLOF/lib/libc/stdio/vfprintf.c
new file mode 100644
index 0000000..765feea
--- /dev/null
+++ b/src/roms/SLOF/lib/libc/stdio/vfprintf.c
@@ -0,0 +1,27 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include "stdio.h"
+#include "unistd.h"
+
+
+int vfprintf(FILE *stream, const char *fmt, va_list ap)
+{
+ int count;
+ char buffer[320];
+
+ count = vsnprintf(buffer, sizeof(buffer), fmt, ap);
+ write(stream->fd, buffer, count);
+
+ return count;
+}
+
diff --git a/src/roms/SLOF/lib/libc/stdio/vfscanf.c b/src/roms/SLOF/lib/libc/stdio/vfscanf.c
new file mode 100644
index 0000000..4ddd210
--- /dev/null
+++ b/src/roms/SLOF/lib/libc/stdio/vfscanf.c
@@ -0,0 +1,266 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include "string.h"
+#include "ctype.h"
+#include "stdlib.h"
+#include "stdio.h"
+#include "unistd.h"
+
+
+static int
+_getc(FILE * stream)
+{
+ int count;
+ char c;
+
+ if (stream->mode == _IONBF || stream->buf == NULL) {
+ if (read(stream->fd, &c, 1) == 1)
+ return (int) c;
+ else
+ return EOF;
+ }
+
+ if (stream->pos == 0 || stream->pos >= BUFSIZ ||
+ stream->buf[stream->pos] == '\0') {
+ count = read(stream->fd, stream->buf, BUFSIZ);
+ if (count < 0)
+ count = 0;
+ if (count < BUFSIZ)
+ stream->buf[count] = '\0';
+ stream->pos = 0;
+ }
+
+ return stream->buf[stream->pos++];
+}
+
+static void
+_ungetc(int ch, FILE * stream)
+{
+ if (stream->mode != _IONBF && stream->pos > 0)
+ stream->pos--;
+}
+
+static int
+_is_voidage(int ch)
+{
+ if (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r' || ch == '\0')
+ return 1;
+ else
+ return 0;
+}
+
+
+static int
+_scanf(FILE * stream, const char *fmt, va_list * ap)
+{
+ int i = 0;
+ int length = 0;
+
+ fmt++;
+
+ while (*fmt != '\0') {
+
+ char tbuf[256];
+ char ch;
+
+ switch (*fmt) {
+ case 'd':
+ case 'i':
+ ch = _getc(stream);
+ if (length == 0) {
+ while (!_is_voidage(ch) && isdigit(ch)) {
+ tbuf[i] = ch;
+ ch = _getc(stream);
+ i++;
+ }
+ } else {
+ while (!_is_voidage(ch) && i < length
+ && isdigit(ch)) {
+ tbuf[i] = ch;
+ ch = _getc(stream);
+ i++;
+ }
+ }
+ /* We tried to understand what this is good for...
+ * but we did not. We know for sure that it does not
+ * work on SLOF if this is active. */
+ /* _ungetc(ch, stream); */
+ tbuf[i] = '\0';
+
+ /* ch = _getc(stream); */
+ if (!_is_voidage(ch))
+ _ungetc(ch, stream);
+
+ if (strlen(tbuf) == 0)
+ return 0;
+
+ *(va_arg(*ap, int *)) = strtol(tbuf, NULL, 10);
+ break;
+ case 'X':
+ case 'x':
+ ch = _getc(stream);
+ if (length == 0) {
+ while (!_is_voidage(ch) && isxdigit(ch)) {
+ tbuf[i] = ch;
+ ch = _getc(stream);
+ i++;
+ }
+ } else {
+ while (!_is_voidage(ch) && i < length
+ && isxdigit(ch)) {
+ tbuf[i] = ch;
+ ch = _getc(stream);
+ i++;
+ }
+ }
+ /* _ungetc(ch, stream); */
+ tbuf[i] = '\0';
+
+ /* ch = _getc(stream); */
+ if (!_is_voidage(ch))
+ _ungetc(ch, stream);
+
+ if (strlen(tbuf) == 0)
+ return 0;
+
+ *(va_arg(*ap, int *)) = strtol(tbuf, NULL, 16);
+ break;
+ case 'O':
+ case 'o':
+ ch = _getc(stream);
+ if (length == 0) {
+ while (!_is_voidage(ch)
+ && !(ch < '0' || ch > '7')) {
+ tbuf[i] = ch;
+ ch = _getc(stream);
+ i++;
+ }
+ } else {
+ while (!_is_voidage(ch) && i < length
+ && !(ch < '0' || ch > '7')) {
+ tbuf[i] = ch;
+ ch = _getc(stream);
+ i++;
+ }
+ }
+ /* _ungetc(ch, stream); */
+ tbuf[i] = '\0';
+
+ /* ch = _getc(stream); */
+ if (!_is_voidage(ch))
+ _ungetc(ch, stream);
+
+ if (strlen(tbuf) == 0)
+ return 0;
+
+ *(va_arg(*ap, int *)) = strtol(tbuf, NULL, 8);
+ break;
+ case 'c':
+ ch = _getc(stream);
+ while (_is_voidage(ch))
+ ch = _getc(stream);
+
+ *(va_arg(*ap, char *)) = ch;
+
+ ch = _getc(stream);
+ if (!_is_voidage(ch))
+ _ungetc(ch, stream);
+
+ break;
+ case 's':
+ ch = _getc(stream);
+ if (length == 0) {
+ while (!_is_voidage(ch)) {
+ tbuf[i] = ch;
+ ch = _getc(stream);
+ i++;
+ }
+ } else {
+ while (!_is_voidage(ch) && i < length) {
+ tbuf[i] = ch;
+ ch = _getc(stream);
+ i++;
+ }
+ }
+ /* _ungetc(ch, stream); */
+ tbuf[i] = '\0';
+
+ /* ch = _getc(stream); */
+ if (!_is_voidage(ch))
+ _ungetc(ch, stream);
+
+ strcpy(va_arg(*ap, char *), tbuf);
+ break;
+ default:
+ if (*fmt >= '0' && *fmt <= '9')
+ length += *fmt - '0';
+ break;
+ }
+ fmt++;
+ }
+
+ return 1;
+}
+
+
+
+int
+vfscanf(FILE * stream, const char *fmt, va_list ap)
+{
+ int args = 0;
+
+ while (*fmt != '\0') {
+
+ if (*fmt == '%') {
+
+ char formstr[20];
+ int i = 0;
+
+ do {
+ formstr[i] = *fmt;
+ fmt++;
+ i++;
+ } while (!
+ (*fmt == 'd' || *fmt == 'i' || *fmt == 'x'
+ || *fmt == 'X' || *fmt == 'p' || *fmt == 'c'
+ || *fmt == 's' || *fmt == '%' || *fmt == 'O'
+ || *fmt == 'o'));
+ formstr[i++] = *fmt;
+ formstr[i] = '\0';
+ if (*fmt != '%') {
+ if (_scanf(stream, formstr, &ap) <= 0)
+ return args;
+ else
+ args++;
+ }
+
+ }
+
+ fmt++;
+
+ }
+
+ return args;
+}
+
+int
+getc(FILE * stream)
+{
+ return _getc(stream);
+}
+
+int
+getchar(void)
+{
+ return _getc(stdin);
+}
diff --git a/src/roms/SLOF/lib/libc/stdio/vsnprintf.c b/src/roms/SLOF/lib/libc/stdio/vsnprintf.c
new file mode 100644
index 0000000..e78fb3d
--- /dev/null
+++ b/src/roms/SLOF/lib/libc/stdio/vsnprintf.c
@@ -0,0 +1,242 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include "stdio.h"
+#include "stdlib.h"
+#include "string.h"
+
+const static unsigned long long convert[] = {
+ 0x0, 0xFF, 0xFFFF, 0xFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFFFFULL, 0xFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFFFULL
+};
+
+
+
+static int
+print_itoa(char **buffer,unsigned long value, unsigned short int base)
+{
+ const char zeichen[] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
+ static char sign = 0;
+
+ if(base <= 2 || base > 16)
+ return 0;
+
+ if(value < 0) {
+ sign = 1;
+ value *= -1;
+ }
+
+ if(value < base) {
+ if(sign) {
+ **buffer = '-';
+ *buffer += 1;
+ sign = 0;
+ }
+ **buffer = zeichen[value];
+ *buffer += 1;
+ } else {
+ print_itoa(buffer, value / base, base);
+ **buffer = zeichen[(value % base)];
+ *buffer += 1;
+ }
+
+ return 1;
+}
+
+
+static unsigned int
+print_intlen(unsigned long value, unsigned short int base)
+{
+ int i = 0;
+
+ while(value > 0) {
+ value /= base;
+ i++;
+ }
+ if(i == 0) i = 1;
+ return i;
+}
+
+
+static int
+print_fill(char **buffer, char *sizec, unsigned long size, unsigned short int base, char c, int optlen)
+{
+ int i, sizei, len;
+
+ sizei = strtoul(sizec, NULL, 10);
+ len = print_intlen(size, base) + optlen;
+ if(sizei > len) {
+ for(i = 0; i < (sizei - len); i++) {
+ **buffer = c;
+ *buffer += 1;
+ }
+ }
+
+ return 0;
+}
+
+
+static int
+print_format(char **buffer, const char *format, void *var)
+{
+ unsigned long start;
+ unsigned int i = 0, sizei = 0, len = 0, length_mod = sizeof(int);
+ unsigned long value = 0;
+ unsigned long signBit;
+ char *form, sizec[32];
+ char sign = ' ';
+
+ form = (char *) format;
+ start = (unsigned long) *buffer;
+
+ form++;
+ if(*form == '0' || *form == '.') {
+ sign = '0';
+ form++;
+ }
+
+ while(*form != '\0') {
+ switch(*form) {
+ case 'u':
+ case 'd':
+ case 'i':
+ sizec[i] = '\0';
+ value = (unsigned long) var;
+ signBit = 0x1ULL << (length_mod * 8 - 1);
+ if (signBit & value) {
+ **buffer = '-';
+ *buffer += 1;
+ value = (-(unsigned long)value) & convert[length_mod];
+ }
+ print_fill(buffer, sizec, value, 10, sign, 0);
+ print_itoa(buffer, value, 10);
+ break;
+ case 'X':
+ case 'x':
+ sizec[i] = '\0';
+ value = (unsigned long) var & convert[length_mod];
+ print_fill(buffer, sizec, value, 16, sign, 0);
+ print_itoa(buffer, value, 16);
+ break;
+ case 'O':
+ case 'o':
+ sizec[i] = '\0';
+ value = (long int) var & convert[length_mod];
+ print_fill(buffer, sizec, value, 8, sign, 0);
+ print_itoa(buffer, value, 8);
+ break;
+ case 'p':
+ sizec[i] = '\0';
+ print_fill(buffer, sizec, (unsigned long) var, 16, ' ', 2);
+ **buffer = '0';
+ *buffer += 1;
+ **buffer = 'x';
+ *buffer += 1;
+ print_itoa(buffer,(unsigned long) var, 16);
+ break;
+ case 'c':
+ sizec[i] = '\0';
+ print_fill(buffer, sizec, 1, 10, ' ', 0);
+ **buffer = (unsigned long) var;
+ *buffer += 1;
+ break;
+ case 's':
+ sizec[i] = '\0';
+ sizei = strtoul(sizec, NULL, 10);
+ len = strlen((char *) var);
+ if(sizei > len) {
+ for(i = 0; i < (sizei - len); i++) {
+ **buffer = ' ';
+ *buffer += 1;
+ }
+ }
+ for(i = 0; i < strlen((char *) var); i++) {
+ **buffer = ((char *) var)[i];
+ *buffer += 1;
+ }
+ break;
+ case 'l':
+ form++;
+ if(*form == 'l') {
+ length_mod = sizeof(long long int);
+ } else {
+ form--;
+ length_mod = sizeof(long int);
+ }
+ break;
+ case 'h':
+ form++;
+ if(*form == 'h') {
+ length_mod = sizeof(signed char);
+ } else {
+ form--;
+ length_mod = sizeof(short int);
+ }
+ break;
+ default:
+ if(*form >= '0' && *form <= '9')
+ sizec[i++] = *form;
+ }
+ form++;
+ }
+
+
+ return (long int) (*buffer - start);
+}
+
+
+/*
+ * The vsnprintf function prints a formated strings into a buffer.
+ * BUG: buffer size checking does not fully work yet
+ */
+int
+vsnprintf(char *buffer, size_t bufsize, const char *format, va_list arg)
+{
+ char *ptr, *bstart;
+
+ bstart = buffer;
+ ptr = (char *) format;
+
+ while(*ptr != '\0' && (buffer - bstart) < bufsize)
+ {
+ if(*ptr == '%') {
+ char formstr[20];
+ int i=0;
+
+ do {
+ formstr[i] = *ptr;
+ ptr++;
+ i++;
+ } while(!(*ptr == 'd' || *ptr == 'i' || *ptr == 'u' || *ptr == 'x' || *ptr == 'X'
+ || *ptr == 'p' || *ptr == 'c' || *ptr == 's' || *ptr == '%'
+ || *ptr == 'O' || *ptr == 'o' ));
+ formstr[i++] = *ptr;
+ formstr[i] = '\0';
+ if(*ptr == '%') {
+ *buffer++ = '%';
+ } else {
+ print_format(&buffer, formstr, va_arg(arg, void *));
+ }
+ ptr++;
+ } else {
+
+ *buffer = *ptr;
+
+ buffer++;
+ ptr++;
+ }
+ }
+
+ *buffer = '\0';
+
+ return (buffer - bstart);
+}
diff --git a/src/roms/SLOF/lib/libc/stdio/vsprintf.c b/src/roms/SLOF/lib/libc/stdio/vsprintf.c
new file mode 100644
index 0000000..0dfd737
--- /dev/null
+++ b/src/roms/SLOF/lib/libc/stdio/vsprintf.c
@@ -0,0 +1,19 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include "stdio.h"
+
+int
+vsprintf(char *buffer, const char *format, va_list arg)
+{
+ return vsnprintf(buffer, 0x7fffffff, format, arg);
+}
diff --git a/src/roms/SLOF/lib/libc/stdio/vsscanf.c b/src/roms/SLOF/lib/libc/stdio/vsscanf.c
new file mode 100644
index 0000000..b9603e9
--- /dev/null
+++ b/src/roms/SLOF/lib/libc/stdio/vsscanf.c
@@ -0,0 +1,131 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include "stdio.h"
+#include "stdlib.h"
+#include "string.h"
+
+
+static void
+_scanf(const char **buffer, const char *fmt, va_list *ap)
+{
+ int i;
+ int length = 0;
+
+ fmt++;
+
+ while(*fmt != '\0') {
+
+ char tbuf[256];
+
+ switch(*fmt) {
+ case 'd':
+ case 'i':
+ if(length == 0) length = 256;
+
+ for(i = 0; **buffer != ' ' && **buffer != '\t' && **buffer != '\n' && i < length; i++) {
+ tbuf[i] = **buffer;
+ *buffer += 1;
+ }
+ tbuf[i] = '\0';
+
+ *(va_arg(*ap, int *)) = strtol(tbuf, NULL, 10);
+ break;
+ case 'X':
+ case 'x':
+ if(length == 0) length = 256;
+
+ for(i = 0; **buffer != ' ' && **buffer != '\t' && **buffer != '\n' && i < length; i++) {
+ tbuf[i] = **buffer;
+ *buffer += 1;
+ }
+ tbuf[i] = '\0';
+
+ *(va_arg(*ap, int *)) = strtol(tbuf, NULL, 16);
+ break;
+ case 'O':
+ case 'o':
+ if(length == 0) length = 256;
+
+ for(i = 0; **buffer != ' ' && **buffer != '\t' && **buffer != '\n' && i < length; i++) {
+ tbuf[i] = **buffer;
+ *buffer += 1;
+ }
+ tbuf[i] = '\0';
+
+ *(va_arg(*ap, int *)) = strtol(tbuf, NULL, 8);
+ break;
+ case 'c':
+ *(va_arg(*ap, char *)) = **buffer;
+ *buffer += 1;
+ if(length > 1)
+ for(i = 1; i < length; i++)
+ *buffer += 1;
+ break;
+ case 's':
+ if(length == 0) length = 256;
+
+ for(i = 0; **buffer != ' ' && **buffer != '\t' && **buffer != '\n' && i < length; i++) {
+ tbuf[i] = **buffer;
+ *buffer += 1;
+ }
+
+ tbuf[i] = '\0';
+
+ strcpy(va_arg(*ap, char *), tbuf);
+ break;
+ default:
+ if(*fmt >= '0' && *fmt <= '9')
+ length += *fmt - '0';
+ break;
+ }
+ fmt++;
+ }
+
+}
+
+
+int
+vsscanf(const char *buffer, const char *fmt, va_list ap)
+{
+
+ while(*fmt != '\0') {
+
+ if(*fmt == '%') {
+
+ char formstr[20];
+ int i=0;
+
+ do {
+ formstr[i] = *fmt;
+ fmt++;
+ i++;
+ } while(!(*fmt == 'd' || *fmt == 'i' || *fmt == 'x' || *fmt == 'X'
+ || *fmt == 'p' || *fmt == 'c' || *fmt == 's' || *fmt == '%'
+ || *fmt == 'O' || *fmt == 'o' ));
+ formstr[i++] = *fmt;
+ formstr[i] = '\0';
+ if(*fmt != '%') {
+ while(*buffer == ' ' || *buffer == '\t' || *buffer == '\n')
+ buffer++;
+ _scanf(&buffer, formstr, &ap);
+ }
+
+ }
+
+ fmt++;
+
+ }
+
+ return 0;
+}
+
diff --git a/src/roms/SLOF/lib/libc/stdlib/Makefile.inc b/src/roms/SLOF/lib/libc/stdlib/Makefile.inc
new file mode 100644
index 0000000..702f6d7
--- /dev/null
+++ b/src/roms/SLOF/lib/libc/stdlib/Makefile.inc
@@ -0,0 +1,22 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2008 IBM Corporation
+# * All rights reserved.
+# * This program and the accompanying materials
+# * are made available under the terms of the BSD License
+# * which accompanies this distribution, and is available at
+# * http://www.opensource.org/licenses/bsd-license.php
+# *
+# * Contributors:
+# * IBM Corporation - initial implementation
+# ****************************************************************************/
+
+
+STDLIB_SRC_C = error.c atoi.c atol.c strtoul.c strtol.c rand.c \
+ malloc.c memalign.c realloc.c free.c
+
+STDLIB_SRC_ASM =
+STDLIB_SRCS = $(STDLIB_SRC_C:%=$(STDLIBCMNDIR)/%) $(STDLIB_SRC_ASM:%=$(STDLIBCMNDIR)/%)
+STDLIB_OBJS = $(STDLIB_SRC_C:%.c=%.o) $(STDLIB_SRC_ASM:%.S=%.o)
+
+%.o : $(STDLIBCMNDIR)/%.c
+ $(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@
diff --git a/src/roms/SLOF/lib/libc/stdlib/atoi.c b/src/roms/SLOF/lib/libc/stdlib/atoi.c
new file mode 100644
index 0000000..d2fb33b
--- /dev/null
+++ b/src/roms/SLOF/lib/libc/stdlib/atoi.c
@@ -0,0 +1,18 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <stdlib.h>
+
+int atoi(const char *str)
+{
+ return strtol(str, NULL, 0);
+}
diff --git a/src/roms/SLOF/lib/libc/stdlib/atol.c b/src/roms/SLOF/lib/libc/stdlib/atol.c
new file mode 100644
index 0000000..a6aa47b
--- /dev/null
+++ b/src/roms/SLOF/lib/libc/stdlib/atol.c
@@ -0,0 +1,18 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <stdlib.h>
+
+long atol(const char *str)
+{
+ return strtol(str, NULL, 0);
+}
diff --git a/src/roms/SLOF/lib/libc/stdlib/error.c b/src/roms/SLOF/lib/libc/stdlib/error.c
new file mode 100644
index 0000000..81020ca
--- /dev/null
+++ b/src/roms/SLOF/lib/libc/stdlib/error.c
@@ -0,0 +1,15 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+
+int errno;
+
diff --git a/src/roms/SLOF/lib/libc/stdlib/free.c b/src/roms/SLOF/lib/libc/stdlib/free.c
new file mode 100644
index 0000000..9005450
--- /dev/null
+++ b/src/roms/SLOF/lib/libc/stdlib/free.c
@@ -0,0 +1,26 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+
+#include "stdlib.h"
+#include "malloc_defs.h"
+
+void
+free(void *ptr)
+{
+ struct chunk *header;
+
+ header = (struct chunk *) ptr;
+ header--;
+ header->inuse = 0;
+
+}
diff --git a/src/roms/SLOF/lib/libc/stdlib/malloc.c b/src/roms/SLOF/lib/libc/stdlib/malloc.c
new file mode 100644
index 0000000..b2a3138
--- /dev/null
+++ b/src/roms/SLOF/lib/libc/stdlib/malloc.c
@@ -0,0 +1,157 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+
+#include "stddef.h"
+#include "stdlib.h"
+#include "unistd.h"
+#include "malloc_defs.h"
+
+
+static int clean(void);
+
+
+/* act points to the end of the initialized heap and the start of uninitialized heap */
+static char *act;
+
+/* Pointers to start and end of heap: */
+static char *heap_start, *heap_end;
+
+
+/*
+ * Standard malloc function
+ */
+void *
+malloc(size_t size)
+{
+ char *header;
+ void *data;
+ size_t blksize; /* size of memory block including the chunk */
+
+ blksize = size + sizeof(struct chunk);
+
+ /* has malloc been called for the first time? */
+ if (act == 0) {
+ size_t initsize;
+ /* add some space so we have a good initial playground */
+ initsize = (blksize + 0x1000) & ~0x0fff;
+ /* get initial memory region with sbrk() */
+ heap_start = sbrk(initsize);
+ if (heap_start == (void*)-1)
+ return NULL;
+ heap_end = heap_start + initsize;
+ act = heap_start;
+ }
+
+ header = act;
+ data = act + sizeof(struct chunk);
+
+ /* Check if there is space left in the uninitialized part of the heap */
+ if (act + blksize > heap_end) {
+ //search at begin of heap
+ header = heap_start;
+
+ while ((((struct chunk *) header)->inuse != 0
+ || ((struct chunk *) header)->length < size)
+ && header < act) {
+ header = header + sizeof(struct chunk)
+ + ((struct chunk *) header)->length;
+ }
+
+ // check if heap is full
+ if (header >= act) {
+ if (clean()) {
+ // merging of free blocks succeeded, so try again
+ return malloc(size);
+ } else if (sbrk(blksize) == heap_end) {
+ // succeeded to get more memory, so try again
+ heap_end += blksize;
+ return malloc(size);
+ } else {
+ // No more memory available
+ return 0;
+ }
+ }
+
+ // Check if we need to split this memory block into two
+ if (((struct chunk *) header)->length > blksize) {
+ //available memory is too big
+ int alt;
+
+ alt = ((struct chunk *) header)->length;
+ ((struct chunk *) header)->inuse = 1;
+ ((struct chunk *) header)->length = size;
+ data = header + sizeof(struct chunk);
+
+ //mark the rest of the heap
+ header = data + size;
+ ((struct chunk *) header)->inuse = 0;
+ ((struct chunk *) header)->length =
+ alt - blksize;
+ } else {
+ //new memory matched exactly in available memory
+ ((struct chunk *) header)->inuse = 1;
+ data = header + sizeof(struct chunk);
+ }
+
+ } else {
+
+ ((struct chunk *) header)->inuse = 1;
+ ((struct chunk *) header)->length = size;
+
+ act += blksize;
+ }
+
+ return data;
+}
+
+
+/*
+ * Merge free memory blocks in initialized heap if possible
+ */
+static int
+clean(void)
+{
+ char *header;
+ char *firstfree = 0;
+ char check = 0;
+
+ header = heap_start;
+ //if (act == 0) // This should never happen
+ // act = heap_end;
+
+ while (header < act) {
+
+ if (((struct chunk *) header)->inuse == 0) {
+ if (firstfree == 0) {
+ /* First free block in a row, only save address */
+ firstfree = header;
+
+ } else {
+ /* more than one free block in a row, merge them! */
+ ((struct chunk *) firstfree)->length +=
+ ((struct chunk *) header)->length +
+ sizeof(struct chunk);
+ check = 1;
+ }
+ } else {
+ firstfree = 0;
+
+ }
+
+ header = header + sizeof(struct chunk)
+ + ((struct chunk *) header)->length;
+
+ }
+
+ return check;
+}
diff --git a/src/roms/SLOF/lib/libc/stdlib/malloc_defs.h b/src/roms/SLOF/lib/libc/stdlib/malloc_defs.h
new file mode 100644
index 0000000..1933026
--- /dev/null
+++ b/src/roms/SLOF/lib/libc/stdlib/malloc_defs.h
@@ -0,0 +1,16 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+struct chunk {
+ unsigned inuse : 4;
+ unsigned length : 28;
+} __attribute__((packed));
diff --git a/src/roms/SLOF/lib/libc/stdlib/memalign.c b/src/roms/SLOF/lib/libc/stdlib/memalign.c
new file mode 100644
index 0000000..3b678aa
--- /dev/null
+++ b/src/roms/SLOF/lib/libc/stdlib/memalign.c
@@ -0,0 +1,26 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+
+#include "stdlib.h"
+
+
+void *
+memalign(size_t blocksize, size_t bytes)
+{
+ void *x;
+
+ x = malloc(bytes + blocksize);
+ x = (void *) (((unsigned long) x + blocksize - 1) & ~(blocksize - 1));
+
+ return (void *) x;
+}
diff --git a/src/roms/SLOF/lib/libc/stdlib/rand.c b/src/roms/SLOF/lib/libc/stdlib/rand.c
new file mode 100644
index 0000000..87e3efd
--- /dev/null
+++ b/src/roms/SLOF/lib/libc/stdlib/rand.c
@@ -0,0 +1,24 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <stdlib.h>
+
+
+static unsigned long _rand = 1;
+
+int
+rand(void)
+{
+ _rand = _rand * 25364735 + 34563;
+
+ return ((unsigned int) (_rand << 16) & RAND_MAX);
+}
diff --git a/src/roms/SLOF/lib/libc/stdlib/realloc.c b/src/roms/SLOF/lib/libc/stdlib/realloc.c
new file mode 100644
index 0000000..652e900
--- /dev/null
+++ b/src/roms/SLOF/lib/libc/stdlib/realloc.c
@@ -0,0 +1,40 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+
+#include "stdlib.h"
+#include "string.h"
+#include "malloc_defs.h"
+
+void *
+realloc(void *ptr, size_t size)
+{
+ struct chunk *header;
+ char *newptr, *start;
+
+ header = (struct chunk *) ptr;
+ header--;
+
+ if (size <= header->length)
+ return ptr;
+
+ newptr = (char *) malloc(size);
+ if (newptr == NULL)
+ return 0;
+
+ start = newptr;
+ memcpy((void *) newptr, (const void *) ptr, header->length);
+
+ header->inuse = 0;
+
+ return start;
+}
diff --git a/src/roms/SLOF/lib/libc/stdlib/strtol.c b/src/roms/SLOF/lib/libc/stdlib/strtol.c
new file mode 100644
index 0000000..474597a
--- /dev/null
+++ b/src/roms/SLOF/lib/libc/stdlib/strtol.c
@@ -0,0 +1,115 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <stdlib.h>
+
+long int strtol(const char *S, char **PTR,int BASE)
+{
+ long rval = 0;
+ short int negative = 0;
+ short int digit;
+ // *PTR is S, unless PTR is NULL, in which case i override it with my own ptr
+ char* ptr;
+ if (PTR == 0)
+ {
+ //override
+ PTR = &ptr;
+ }
+ // i use PTR to advance through the string
+ *PTR = (char *) S;
+ //check if BASE is ok
+ if ((BASE < 0) || BASE > 36)
+ {
+ return 0;
+ }
+ // ignore white space at beginning of S
+ while ((**PTR == ' ')
+ || (**PTR == '\t')
+ || (**PTR == '\n')
+ || (**PTR == '\r')
+ )
+ {
+ (*PTR)++;
+ }
+ // check if S starts with "-" in which case the return value is negative
+ if (**PTR == '-')
+ {
+ negative = 1;
+ (*PTR)++;
+ }
+ // if BASE is 0... determine the base from the first chars...
+ if (BASE == 0)
+ {
+ // if S starts with "0x", BASE = 16, else 10
+ if ((**PTR == '0') && (*((*PTR)+1) == 'x'))
+ {
+ BASE = 16;
+ (*PTR)++;
+ (*PTR)++;
+ }
+ else
+ {
+ BASE = 10;
+ }
+ }
+ if (BASE == 16)
+ {
+ // S may start with "0x"
+ if ((**PTR == '0') && (*((*PTR)+1) == 'x'))
+ {
+ (*PTR)++;
+ (*PTR)++;
+ }
+ }
+ //until end of string
+ while (**PTR)
+ {
+ if (((**PTR) >= '0') && ((**PTR) <= '9'))
+ {
+ //digit (0..9)
+ digit = **PTR - '0';
+ }
+ else if (((**PTR) >= 'a') && ((**PTR) <='z'))
+ {
+ //alphanumeric digit lowercase(a (10) .. z (35) )
+ digit = (**PTR - 'a') + 10;
+ }
+ else if (((**PTR) >= 'A') && ((**PTR) <='Z'))
+ {
+ //alphanumeric digit uppercase(a (10) .. z (35) )
+ digit = (**PTR - 'A') + 10;
+ }
+ else
+ {
+ //end of parseable number reached...
+ break;
+ }
+ if (digit < BASE)
+ {
+ rval = (rval * BASE) + digit;
+ }
+ else
+ {
+ //digit found, but its too big for current base
+ //end of parseable number reached...
+ break;
+ }
+ //next...
+ (*PTR)++;
+ }
+ if (negative)
+ {
+ return rval * -1;
+ }
+ //else
+ return rval;
+}
diff --git a/src/roms/SLOF/lib/libc/stdlib/strtoul.c b/src/roms/SLOF/lib/libc/stdlib/strtoul.c
new file mode 100644
index 0000000..754e7db
--- /dev/null
+++ b/src/roms/SLOF/lib/libc/stdlib/strtoul.c
@@ -0,0 +1,105 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <stdlib.h>
+
+unsigned long int strtoul(const char *S, char **PTR,int BASE)
+{
+ unsigned long rval = 0;
+ short int digit;
+ // *PTR is S, unless PTR is NULL, in which case i override it with my own ptr
+ char* ptr;
+ if (PTR == 0)
+ {
+ //override
+ PTR = &ptr;
+ }
+ // i use PTR to advance through the string
+ *PTR = (char *) S;
+ //check if BASE is ok
+ if ((BASE < 0) || BASE > 36)
+ {
+ return 0;
+ }
+ // ignore white space at beginning of S
+ while ((**PTR == ' ')
+ || (**PTR == '\t')
+ || (**PTR == '\n')
+ || (**PTR == '\r')
+ )
+ {
+ (*PTR)++;
+ }
+ // if BASE is 0... determine the base from the first chars...
+ if (BASE == 0)
+ {
+ // if S starts with "0x", BASE = 16, else 10
+ if ((**PTR == '0') && (*((*PTR)+1) == 'x'))
+ {
+ BASE = 16;
+ (*PTR)++;
+ (*PTR)++;
+ }
+ else
+ {
+ BASE = 10;
+ }
+ }
+ if (BASE == 16)
+ {
+ // S may start with "0x"
+ if ((**PTR == '0') && (*((*PTR)+1) == 'x'))
+ {
+ (*PTR)++;
+ (*PTR)++;
+ }
+ }
+ //until end of string
+ while (**PTR)
+ {
+ if (((**PTR) >= '0') && ((**PTR) <='9'))
+ {
+ //digit (0..9)
+ digit = **PTR - '0';
+ }
+ else if (((**PTR) >= 'a') && ((**PTR) <='z'))
+ {
+ //alphanumeric digit lowercase(a (10) .. z (35) )
+ digit = (**PTR - 'a') + 10;
+ }
+ else if (((**PTR) >= 'A') && ((**PTR) <='Z'))
+ {
+ //alphanumeric digit uppercase(a (10) .. z (35) )
+ digit = (**PTR - 'A') + 10;
+ }
+ else
+ {
+ //end of parseable number reached...
+ break;
+ }
+ if (digit < BASE)
+ {
+ rval = (rval * BASE) + digit;
+ }
+ else
+ {
+ //digit found, but its too big for current base
+ //end of parseable number reached...
+ break;
+ }
+ //next...
+ (*PTR)++;
+ }
+ //done
+ return rval;
+}
+
diff --git a/src/roms/SLOF/lib/libc/string/Makefile.inc b/src/roms/SLOF/lib/libc/string/Makefile.inc
new file mode 100644
index 0000000..7ccf3c4
--- /dev/null
+++ b/src/roms/SLOF/lib/libc/string/Makefile.inc
@@ -0,0 +1,22 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2008 IBM Corporation
+# * All rights reserved.
+# * This program and the accompanying materials
+# * are made available under the terms of the BSD License
+# * which accompanies this distribution, and is available at
+# * http://www.opensource.org/licenses/bsd-license.php
+# *
+# * Contributors:
+# * IBM Corporation - initial implementation
+# ****************************************************************************/
+
+
+STRING_SRC_C = strcat.c strchr.c strcmp.c strcpy.c strlen.c strncmp.c \
+ strncpy.c strstr.c memset.c memcpy.c memmove.c memchr.c \
+ memcmp.c strcasecmp.c strncasecmp.c strtok.c
+STRING_SRC_ASM =
+STRING_SRCS = $(STRING_SRC_C:%=$(STRINGCMNDIR)/%) $(STRING_SRC_ASM:%=$(STRINGCMNDIR)/%)
+STRING_OBJS = $(STRING_SRC_C:%.c=%.o) $(STRING_SRC_ASM:%.S=%.o)
+
+%.o : $(STRINGCMNDIR)/%.c
+ $(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@
diff --git a/src/roms/SLOF/lib/libc/string/memchr.c b/src/roms/SLOF/lib/libc/string/memchr.c
new file mode 100644
index 0000000..c3fe751
--- /dev/null
+++ b/src/roms/SLOF/lib/libc/string/memchr.c
@@ -0,0 +1,29 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include "string.h"
+
+
+void *
+memchr(const void *ptr, int c, size_t n)
+{
+ unsigned char ch = (unsigned char)c;
+ const unsigned char *p = ptr;
+
+ while (n-- > 0) {
+ if (*p == ch)
+ return (void *)p;
+ p += 1;
+ }
+
+ return NULL;
+}
diff --git a/src/roms/SLOF/lib/libc/string/memcmp.c b/src/roms/SLOF/lib/libc/string/memcmp.c
new file mode 100644
index 0000000..3b69cef
--- /dev/null
+++ b/src/roms/SLOF/lib/libc/string/memcmp.c
@@ -0,0 +1,30 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include "string.h"
+
+
+int
+memcmp(const void *ptr1, const void *ptr2, size_t n)
+{
+ const unsigned char *p1 = ptr1;
+ const unsigned char *p2 = ptr2;
+
+ while (n-- > 0) {
+ if (*p1 != *p2)
+ return (*p1 - *p2);
+ p1 += 1;
+ p2 += 1;
+ }
+
+ return 0;
+}
diff --git a/src/roms/SLOF/lib/libc/string/memcpy.c b/src/roms/SLOF/lib/libc/string/memcpy.c
new file mode 100644
index 0000000..00f419b
--- /dev/null
+++ b/src/roms/SLOF/lib/libc/string/memcpy.c
@@ -0,0 +1,27 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include "string.h"
+
+void *
+memcpy(void *dest, const void *src, size_t n)
+{
+ char *cdest;
+ const char *csrc = src;
+
+ cdest = dest;
+ while (n-- > 0) {
+ *cdest++ = *csrc++;
+ }
+
+ return dest;
+}
diff --git a/src/roms/SLOF/lib/libc/string/memmove.c b/src/roms/SLOF/lib/libc/string/memmove.c
new file mode 100644
index 0000000..3acf1a9
--- /dev/null
+++ b/src/roms/SLOF/lib/libc/string/memmove.c
@@ -0,0 +1,42 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include "string.h"
+
+
+void *
+memmove(void *dest, const void *src, size_t n)
+{
+ char *cdest;
+ const char *csrc;
+ int i;
+
+ /* Do the buffers overlap in a bad way? */
+ if (src < dest && src + n >= dest) {
+ /* Copy from end to start */
+ cdest = dest + n - 1;
+ csrc = src + n - 1;
+ for (i = 0; i < n; i++) {
+ *cdest-- = *csrc--;
+ }
+ }
+ else {
+ /* Normal copy is possible */
+ cdest = dest;
+ csrc = src;
+ for (i = 0; i < n; i++) {
+ *cdest++ = *csrc++;
+ }
+ }
+
+ return dest;
+}
diff --git a/src/roms/SLOF/lib/libc/string/memset.c b/src/roms/SLOF/lib/libc/string/memset.c
new file mode 100644
index 0000000..f8dfbf5
--- /dev/null
+++ b/src/roms/SLOF/lib/libc/string/memset.c
@@ -0,0 +1,25 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include "string.h"
+
+void *
+memset(void *dest, int c, size_t size)
+{
+ unsigned char *d = (unsigned char *)dest;
+
+ while (size-- > 0) {
+ *d++ = (unsigned char)c;
+ }
+
+ return dest;
+}
diff --git a/src/roms/SLOF/lib/libc/string/strcasecmp.c b/src/roms/SLOF/lib/libc/string/strcasecmp.c
new file mode 100644
index 0000000..f75294f
--- /dev/null
+++ b/src/roms/SLOF/lib/libc/string/strcasecmp.c
@@ -0,0 +1,28 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <string.h>
+#include <ctype.h>
+
+int
+strcasecmp(const char *s1, const char *s2)
+{
+ while (*s1 != 0 && *s2 != 0) {
+ if (toupper(*s1) != toupper(*s2))
+ break;
+ ++s1;
+ ++s2;
+ }
+
+ return *s1 - *s2;
+}
+
diff --git a/src/roms/SLOF/lib/libc/string/strcat.c b/src/roms/SLOF/lib/libc/string/strcat.c
new file mode 100644
index 0000000..eb597a0
--- /dev/null
+++ b/src/roms/SLOF/lib/libc/string/strcat.c
@@ -0,0 +1,24 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <string.h>
+
+char *
+strcat(char *dst, const char *src)
+{
+ int p;
+
+ p = strlen(dst);
+ strcpy(&dst[p], src);
+
+ return dst;
+}
diff --git a/src/roms/SLOF/lib/libc/string/strchr.c b/src/roms/SLOF/lib/libc/string/strchr.c
new file mode 100644
index 0000000..528a319
--- /dev/null
+++ b/src/roms/SLOF/lib/libc/string/strchr.c
@@ -0,0 +1,28 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <string.h>
+
+char *
+strchr(const char *s, int c)
+{
+ char cb = c;
+
+ while (*s != 0) {
+ if (*s == cb) {
+ return (char *)s;
+ }
+ s += 1;
+ }
+
+ return NULL;
+}
diff --git a/src/roms/SLOF/lib/libc/string/strcmp.c b/src/roms/SLOF/lib/libc/string/strcmp.c
new file mode 100644
index 0000000..48eaed2
--- /dev/null
+++ b/src/roms/SLOF/lib/libc/string/strcmp.c
@@ -0,0 +1,28 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <string.h>
+
+
+int
+strcmp(const char *s1, const char *s2)
+{
+ while (*s1 != 0 && *s2 != 0) {
+ if (*s1 != *s2)
+ break;
+ s1 += 1;
+ s2 += 1;
+ }
+
+ return *s1 - *s2;
+}
+
diff --git a/src/roms/SLOF/lib/libc/string/strcpy.c b/src/roms/SLOF/lib/libc/string/strcpy.c
new file mode 100644
index 0000000..48eb62c
--- /dev/null
+++ b/src/roms/SLOF/lib/libc/string/strcpy.c
@@ -0,0 +1,25 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <string.h>
+
+char *
+strcpy(char *dst, const char *src)
+{
+ char *ptr = dst;
+
+ do {
+ *ptr++ = *src;
+ } while (*src++ != 0);
+
+ return dst;
+}
diff --git a/src/roms/SLOF/lib/libc/string/strlen.c b/src/roms/SLOF/lib/libc/string/strlen.c
new file mode 100644
index 0000000..37a1b78
--- /dev/null
+++ b/src/roms/SLOF/lib/libc/string/strlen.c
@@ -0,0 +1,27 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <string.h>
+
+size_t
+strlen(const char *s)
+{
+ int len = 0;
+
+ while (*s != 0) {
+ len += 1;
+ s += 1;
+ }
+
+ return len;
+}
+
diff --git a/src/roms/SLOF/lib/libc/string/strncasecmp.c b/src/roms/SLOF/lib/libc/string/strncasecmp.c
new file mode 100644
index 0000000..4140931
--- /dev/null
+++ b/src/roms/SLOF/lib/libc/string/strncasecmp.c
@@ -0,0 +1,32 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <string.h>
+#include <ctype.h>
+
+
+int
+strncasecmp(const char *s1, const char *s2, size_t n)
+{
+ if (n < 1)
+ return 0;
+
+ while (*s1 != 0 && *s2 != 0 && --n > 0) {
+ if (toupper(*s1) != toupper(*s2))
+ break;
+ ++s1;
+ ++s2;
+ }
+
+ return toupper(*s1) - toupper(*s2);
+}
+
diff --git a/src/roms/SLOF/lib/libc/string/strncmp.c b/src/roms/SLOF/lib/libc/string/strncmp.c
new file mode 100644
index 0000000..a886736
--- /dev/null
+++ b/src/roms/SLOF/lib/libc/string/strncmp.c
@@ -0,0 +1,31 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <string.h>
+
+
+int
+strncmp(const char *s1, const char *s2, size_t n)
+{
+ if (n < 1)
+ return 0;
+
+ while (*s1 != 0 && *s2 != 0 && --n > 0) {
+ if (*s1 != *s2)
+ break;
+ s1 += 1;
+ s2 += 1;
+ }
+
+ return *s1 - *s2;
+}
+
diff --git a/src/roms/SLOF/lib/libc/string/strncpy.c b/src/roms/SLOF/lib/libc/string/strncpy.c
new file mode 100644
index 0000000..0f41f93
--- /dev/null
+++ b/src/roms/SLOF/lib/libc/string/strncpy.c
@@ -0,0 +1,33 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <string.h>
+
+char *
+strncpy(char *dst, const char *src, size_t n)
+{
+ char *ret = dst;
+
+ /* Copy string */
+ while (*src != 0 && n > 0) {
+ *dst++ = *src++;
+ n -= 1;
+ }
+
+ /* strncpy always clears the rest of destination string... */
+ while (n > 0) {
+ *dst++ = 0;
+ n -= 1;
+ }
+
+ return ret;
+}
diff --git a/src/roms/SLOF/lib/libc/string/strstr.c b/src/roms/SLOF/lib/libc/string/strstr.c
new file mode 100644
index 0000000..3e090d2
--- /dev/null
+++ b/src/roms/SLOF/lib/libc/string/strstr.c
@@ -0,0 +1,37 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <string.h>
+
+char *
+strstr(const char *hay, const char *needle)
+{
+ char *pos;
+ int hlen, nlen;
+
+ if (hay == NULL || needle == NULL)
+ return NULL;
+
+ hlen = strlen(hay);
+ nlen = strlen(needle);
+ if (nlen < 1)
+ return (char *)hay;
+
+ for (pos = (char *)hay; pos < hay + hlen; pos++) {
+ if (strncmp(pos, needle, nlen) == 0) {
+ return pos;
+ }
+ }
+
+ return NULL;
+}
+
diff --git a/src/roms/SLOF/lib/libc/string/strtok.c b/src/roms/SLOF/lib/libc/string/strtok.c
new file mode 100644
index 0000000..665c08d
--- /dev/null
+++ b/src/roms/SLOF/lib/libc/string/strtok.c
@@ -0,0 +1,45 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <string.h>
+
+char *
+strtok(char *src, const char *pattern)
+{
+ static char *nxtTok;
+ char *retVal = NULL;
+
+ if (!src)
+ src = nxtTok;
+
+ while (*src) {
+ const char *pp = pattern;
+ while (*pp) {
+ if (*pp == *src) {
+ break;
+ }
+ pp++;
+ }
+ if (!*pp) {
+ if (!retVal)
+ retVal = src;
+ else if (!src[-1])
+ break;
+ } else
+ *src = '\0';
+ src++;
+ }
+
+ nxtTok = src;
+
+ return retVal;
+}
diff --git a/src/roms/SLOF/lib/libe1k/Makefile b/src/roms/SLOF/lib/libe1k/Makefile
new file mode 100644
index 0000000..0c3169f
--- /dev/null
+++ b/src/roms/SLOF/lib/libe1k/Makefile
@@ -0,0 +1,51 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2008, 2013 IBM Corporation
+# * All rights reserved.
+# * This program and the accompanying materials
+# * are made available under the terms of the BSD License
+# * which accompanies this distribution, and is available at
+# * http://www.opensource.org/licenses/bsd-license.php
+# *
+# * Contributors:
+# * IBM Corporation - initial implementation
+# ****************************************************************************/
+
+TOPCMNDIR ?= ../..
+
+include $(TOPCMNDIR)/make.rules
+
+CPPFLAGS = -I../libc/include $(CPUARCHDEF) -I$(INCLBRDDIR) \
+ -I$(INCLCMNDIR) -I$(INCLCMNDIR)/$(CPUARCH)
+
+LDFLAGS = -nostdlib
+
+TARGET = ../libe1k.a
+
+
+all: $(TARGET) Makefile.dep
+
+SRCS = e1k.c
+
+OBJS = $(SRCS:%.c=%.o)
+
+$(TARGET): $(OBJS)
+ $(AR) -rc $@ $(OBJS)
+ $(RANLIB) $@
+
+clean:
+ $(RM) $(TARGET) $(OBJS)
+
+distclean: clean
+ $(RM) Makefile.dep
+
+
+# Rules for creating the dependency file:
+depend:
+ $(RM) Makefile.dep
+ $(MAKE) Makefile.dep
+
+Makefile.dep: Makefile
+ $(CC) -M $(CPPFLAGS) $(CFLAGS) $(SRCS) $(SRCSS) > Makefile.dep
+
+# Include dependency file if available:
+-include Makefile.dep
diff --git a/src/roms/SLOF/lib/libe1k/e1k.c b/src/roms/SLOF/lib/libe1k/e1k.c
new file mode 100644
index 0000000..4dd7d2e
--- /dev/null
+++ b/src/roms/SLOF/lib/libe1k/e1k.c
@@ -0,0 +1,1000 @@
+/******************************************************************************
+ * Copyright (c) 2007, 2011, 2013 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+/*
+ * e1000 Gigabit Ethernet Driver for SLOF
+ *
+ * Reference:
+ * PCI/PCI-X Family of Gigabit Ethernet Controllers
+ * Software Developer's Manual Rev. 3.3, Intel, December 2006
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <byteorder.h>
+#include <helpers.h>
+#include <netdriver.h>
+#include "e1k.h"
+
+/*
+ * local defines
+ ******************************************************************************
+ */
+#define E1K_NUM_RX_DESC 128 // do not change
+#define E1K_NUM_TX_DESC 128 // do not change
+#define E1K_BUF_SIZE 2096 // do not change
+
+#define NUM_MAC_ADDR 16 // number of mac address register pairs
+#define EEPROM_MAC_OFFS 0 // position of mac address in eeprom
+
+/*
+ * local types
+ ******************************************************************************
+ */
+typedef struct {
+ uint32_t m_dev_u32;
+ uint64_t m_devmsk_u64;
+ char *m_name;
+} e1k_dev_t;
+
+/*
+ * e1k common data structures
+ */
+
+/*
+ * transmit buffer descriptor
+ */
+typedef struct {
+ uint64_t m_buffer_u64;
+ uint16_t m_len_u16;
+ uint8_t m_cso_u08;
+ uint8_t m_cmd_u08;
+ uint8_t m_sta_u08;
+ uint8_t m_css_u08;
+ uint16_t m_spe_u16;
+} __attribute__ ((packed)) e1k_tx_desc_st;
+
+
+/*
+ * receive buffer descriptor
+ */
+typedef struct {
+ uint64_t m_buffer_u64;
+ uint16_t m_len_u16;
+ uint16_t m_csm_u16;
+ uint8_t m_sta_u08;
+ uint8_t m_err_u08;
+ uint16_t m_spe_u16;
+} __attribute__ ((packed)) e1k_rx_desc_st;
+
+/*
+ * e1k device structure
+ */
+typedef struct {
+ /*
+ * device identification mask
+ */
+ uint64_t m_device_u64;
+
+ /*
+ * memory mapped base address of NIC
+ */
+ uint64_t m_baseaddr_u64;
+
+ /*
+ * transmit & receive rings
+ * must be 16 byte aligned
+ */
+ e1k_tx_desc_st m_tx_ring_pst[E1K_NUM_TX_DESC];
+ e1k_rx_desc_st m_rx_ring_pst[E1K_NUM_RX_DESC];
+
+ /*
+ * transmit & receive buffers
+ * must be 16 byte aligned
+ */
+ uint8_t m_tx_buffer_pu08[E1K_NUM_TX_DESC][E1K_BUF_SIZE];
+ uint8_t m_rx_buffer_pu08[E1K_NUM_RX_DESC][E1K_BUF_SIZE];
+
+ /*
+ * next receive descriptor index
+ */
+ uint32_t m_rx_next_u32;
+
+ /*
+ * command register storage
+ */
+ uint16_t m_com_r_u16;
+
+ /*
+ * padding to make the size of the structure a multiple of 16 byte
+ */
+ uint16_t m_pad16_u16;
+ uint64_t m_pad64_u32;
+
+} __attribute__ ((packed)) e1k_st;
+
+/*
+ * local constants
+ ******************************************************************************
+ */
+#define E1K_82540 ((uint64_t) 0x1)
+#define E1K_82541 ((uint64_t) 0x2)
+#define E1K_82544 ((uint64_t) 0x4)
+#define E1K_82545 ((uint64_t) 0x8)
+#define E1K_82546 ((uint64_t) 0x10)
+#define E1K_82547 ((uint64_t) 0x20)
+
+#define IS_82541 ((m_e1k.m_device_u64 & E1K_82541) != 0)
+#define IS_82546 ((m_e1k.m_device_u64 & E1K_82546) != 0)
+#define IS_82547 ((m_e1k.m_device_u64 & E1K_82547) != 0)
+
+static const e1k_dev_t e1k_dev[] = {
+ { 0x1019, E1K_82547, "82547EI/GI Copper" },
+ { 0x101A, E1K_82547, "82547EI Mobile" },
+ { 0x1010, E1K_82546, "52546EB Copper, Dual Port" },
+ { 0x1012, E1K_82546, "82546EB Fiber, Dual Port" },
+/* { 0x101D, E1K_82546, "82546EB Copper, Quad Port" }, */
+ { 0x1079, E1K_82546, "82546GB Copper, Dual Port" },
+ { 0x107A, E1K_82546, "82546GB Fiber, Dual Port" },
+ { 0x107B, E1K_82546, "82546GB SerDes, Dual Port" },
+ { 0x100F, E1K_82545, "82545EM Copper" },
+ { 0x1011, E1K_82545, "82545EM Fiber" },
+ { 0x1026, E1K_82545, "82545GM Copper" },
+ { 0x1027, E1K_82545, "82545GM Fiber" },
+ { 0x1028, E1K_82545, "82545GM SerDes" },
+ { 0x1107, E1K_82544, "82544EI Copper" },
+ { 0x1112, E1K_82544, "82544GC Copper" },
+ { 0x1013, E1K_82541, "82541EI Copper" },
+ { 0x1018, E1K_82541, "82541EI Mobile" },
+ { 0x1076, E1K_82541, "82541GI Copper" },
+ { 0x1077, E1K_82541, "82541GI Mobile" },
+ { 0x1078, E1K_82541, "82541ER Copper" },
+ { 0x107C, E1K_82541, "82541PI" },
+ { 0x1015, E1K_82540, "82540EM Mobile" },
+ { 0x1016, E1K_82540, "82540EP Mobile" },
+ { 0x1017, E1K_82540, "82540EP Desktop" },
+ { 0x100E, E1K_82540, "82540EM Desktop" },
+ { 0 , 0 }
+};
+
+/*
+ * local variables
+ ******************************************************************************
+ */
+static e1k_st m_e1k __attribute__ ((aligned(16)));
+static long dma_offset;
+
+/*
+ * global functions
+ ******************************************************************************
+ */
+int
+check_driver(uint16_t vendor_id, uint16_t device_id);
+
+static int e1k_init(net_driver_t *driver);
+static int e1k_term(void);
+static int e1k_xmit(char *f_buffer_pc, int f_len_i);
+static int e1k_receive(char *f_buffer_pc, int f_len_i);
+
+/**
+ * Translate virtual to "physical" address, ie. an address
+ * which can be used for DMA transfers.
+ */
+static uint64_t
+virt2dma(void *addr)
+{
+ return (uint64_t)addr + dma_offset;
+}
+
+static void *
+dma2virt(uint64_t addr)
+{
+ return (void *)(addr - dma_offset);
+}
+
+/*
+ * local inline functions for e1k register access
+ ******************************************************************************
+ */
+static uint32_t
+e1k_rd32(uint16_t f_offs_u16)
+{ // caution: shall only be used after initialization!
+ return bswap_32(rd32(m_e1k.m_baseaddr_u64 + (uint64_t) f_offs_u16));
+}
+
+/* not used so far
+static uint16_t
+e1k_rd16(uint16_t f_offs_u16)
+{ // caution: shall only be used after initialization!
+ return bswap_16(rd16(m_e1k.m_baseaddr_u64 + (uint64_t) f_offs_u16));
+}*/
+
+/* not used so far
+static uint8_t
+e1k_rd08(uint16_t f_offs_u16)
+{ // caution: shall only be used after initialization!
+ return rd08(m_e1k.m_baseaddr_u64 + (uint64_t) f_offs_u16);
+}*/
+
+static void
+e1k_wr32(uint16_t f_offs_u16, uint32_t f_val_u32)
+{ // caution: shall only be used after initialization!
+ wr32(m_e1k.m_baseaddr_u64 + (uint64_t) f_offs_u16, bswap_32(f_val_u32));
+}
+
+/* not used so far
+static void
+e1k_wr16(uint16_t f_offs_u16, uint16_t f_val_u16)
+{ // caution: shall only be used after initialization!
+ wr16(m_e1k.m_baseaddr_u64 + (uint64_t) f_offs_u16, bswap_16(f_val_u16));
+}*/
+
+/* not used so far
+static void
+e1k_wr08(uint16_t f_offs_u16, uint8_t f_val_u08)
+{ // caution: shall only be used after initialization!
+ wr08(m_e1k.m_baseaddr_u64 + (uint64_t) f_offs_u16, f_val_u08);
+}*/
+
+static void
+e1k_setb32(uint16_t f_offs_u16, uint32_t f_mask_u32)
+{
+ uint32_t v;
+
+ v = e1k_rd32(f_offs_u16);
+ v |= f_mask_u32;
+ e1k_wr32(f_offs_u16, v);
+}
+
+/* not used so far
+static void
+e1k_setb16(uint16_t f_offs_u16, uint16_t f_mask_u16)
+{
+ uint16_t v;
+ v = e1k_rd16(f_offs_u16);
+ v |= f_mask_u16;
+ e1k_wr16(f_offs_u16, v);
+}*/
+
+/* not used so far
+static void
+e1k_setb08(uint16_t f_offs_u16, uint8_t f_mask_u08)
+{
+ uint8_t v;
+ v = e1k_rd08(f_offs_u16);
+ v |= f_mask_u08;
+ e1k_wr08(f_offs_u16, v);
+}*/
+
+static void
+e1k_clrb32(uint16_t f_offs_u16, uint32_t f_mask_u32)
+{
+ uint32_t v;
+
+ v = e1k_rd32(f_offs_u16);
+ v &= ~f_mask_u32;
+ e1k_wr32(f_offs_u16, v);
+}
+
+/* not used so far
+static void
+e1k_clrb16(uint16_t f_offs_u16, uint16_t f_mask_u16)
+{
+ uint16_t v;
+
+ v = e1k_rd16(f_offs_u16);
+ v &= ~f_mask_u16;
+ e1k_wr16(f_offs_u16, v);
+}*/
+
+/* not used so far
+static void
+e1k_clrb08(uint16_t f_offs_u16, uint8_t f_mask_u08)
+{
+ uint8_t v;
+ v = e1k_rd08(f_offs_u16);
+ v &= ~f_mask_u08;
+ e1k_wr08(f_offs_u16, v);
+}*/
+
+static int32_t
+e1k_eep_rd16(uint8_t f_offs_u08, uint16_t *f_data_pu16)
+{
+ uint32_t i;
+ uint32_t v;
+ int32_t done_shft;
+ int32_t addr_shft;
+
+ if(IS_82541 || IS_82547) {
+ addr_shft = 2;
+ done_shft = 1;
+ } else {
+ addr_shft = 8;
+ done_shft = 4;
+ }
+
+ /*
+ * initiate eeprom read
+ */
+ e1k_wr32(EERD, ((uint32_t) f_offs_u08 << addr_shft) | // address
+ BIT32(0)); // start read
+
+ /*
+ * wait for read done bit to be set
+ */
+ i = 1000;
+ v = e1k_rd32(EERD);
+ while ((--i) &&
+ ((v & BIT32(done_shft)) == 0)) {
+ SLOF_msleep(1);
+ v = e1k_rd32(EERD);
+ }
+
+ /*
+ * return on error
+ */
+ if ((v & BIT32(done_shft)) == 0) {
+ return -1;
+ }
+
+ /*
+ * return data
+ */
+ *f_data_pu16 = (uint16_t) ((v >> 16) & 0xffff);
+
+ return 0;
+}
+
+/*
+ * ring initialization
+ */
+static void
+e1k_init_receiver(void)
+{
+ uint32_t i;
+ uint64_t addr;
+
+ /*
+ * disable receiver for initialization
+ */
+ e1k_wr32(RCTL, 0);
+
+ /*
+ * clear receive desciptors and setup buffer pointers
+ */
+ for (i = 0; i < E1K_NUM_RX_DESC; i++) {
+ memset((uint8_t *) &m_e1k.m_rx_ring_pst[i], 0,
+ sizeof(e1k_rx_desc_st));
+ mb();
+
+ m_e1k.m_rx_ring_pst[i].m_buffer_u64 =
+ bswap_64(virt2dma(&m_e1k.m_rx_buffer_pu08[i][0]));
+ }
+
+ /*
+ * initialize previously received index
+ */
+ m_e1k.m_rx_next_u32 = 0;
+
+ /*
+ * setup the base address and the length of the rx descriptor ring
+ */
+ addr = virt2dma(&m_e1k.m_rx_ring_pst[0]);
+ e1k_wr32(RDBAH, (uint32_t) ((uint64_t) addr >> 32));
+ e1k_wr32(RDBAL, (uint32_t) ((uint64_t) addr & 0xffffffff));
+ e1k_wr32(RDLEN, E1K_NUM_RX_DESC * sizeof(e1k_rx_desc_st));
+
+ /*
+ * setup the rx head and tail descriptor indices
+ */
+ e1k_wr32(RDH, 0);
+ e1k_wr32(RDT, E1K_NUM_RX_DESC - 1);
+
+ /*
+ * setup the receive delay timer register
+ */
+ e1k_wr32(RDTR, 0);
+
+ /*
+ * setup the receive control register
+ */
+ e1k_wr32(RCTL, BIT32( 1) | // enable receiver
+ BIT32( 4) | // enable multicast reception
+ BIT32(15)); // broadcast accept mode
+ // packet size 2048
+ // no buffer extension
+}
+
+static void
+e1k_init_transmitter(void)
+{
+ uint32_t i;
+ uint64_t addr;
+
+ /*
+ * clear transmit desciptors and setup buffer pointers
+ */
+ for (i = 0; i < E1K_NUM_TX_DESC; i++) {
+ memset((uint8_t *) &m_e1k.m_tx_ring_pst[i], 0,
+ sizeof(e1k_tx_desc_st));
+ mb();
+
+ m_e1k.m_tx_ring_pst[i].m_buffer_u64 =
+ bswap_64(virt2dma(&m_e1k.m_tx_buffer_pu08[i][0]));
+ }
+
+ /*
+ * setup the base address and the length of the tx descriptor ring
+ */
+ addr = virt2dma(&m_e1k.m_tx_ring_pst[0]);
+ e1k_wr32(TDBAH, (uint32_t) ((uint64_t) addr >> 32));
+ e1k_wr32(TDBAL, (uint32_t) ((uint64_t) addr & 0xffffffff));
+ e1k_wr32(TDLEN, E1K_NUM_TX_DESC * sizeof(e1k_tx_desc_st));
+
+ /*
+ * setup the rx head and tail descriptor indices
+ */
+ e1k_wr32(TDH, 0);
+ e1k_wr32(TDT, 0);
+
+ /*
+ * initialize the transmit control register
+ */
+ e1k_wr32(TCTL, BIT32(1) | // enable transmitter
+ BIT32(3) | // pad short packets
+ ((uint32_t) 0x0f << 4) | // collision threshhold
+ ((uint32_t) 0x40 << 12)); // collision distance
+}
+
+static int32_t
+e1k_mac_init(uint8_t *f_mac_pu08)
+{
+ uint32_t l_ah_u32;
+ uint32_t l_al_u32;
+ uint32_t i;
+ uint32_t v;
+
+ /*
+ * Use MAC address from device tree if possible
+ */
+ for (i = 0, v = 0; i < 6; i++) {
+ v += (uint32_t) f_mac_pu08[i];
+ }
+
+ if (v != 0) {
+ /*
+ * use passed mac address for transmission to nic
+ */
+ l_al_u32 = ((uint32_t) f_mac_pu08[3] << 24);
+ l_al_u32 |= ((uint32_t) f_mac_pu08[2] << 16);
+ l_al_u32 |= ((uint32_t) f_mac_pu08[1] << 8);
+ l_al_u32 |= ((uint32_t) f_mac_pu08[0] << 0);
+ l_ah_u32 = ((uint32_t) f_mac_pu08[5] << 8);
+ l_ah_u32 |= ((uint32_t) f_mac_pu08[4] << 0);
+ } else {
+ /*
+ * read mac address from eeprom
+ */
+ uint16_t w[3]; // 3 16 bit words from eeprom
+
+ for (i = 0; i < 3; i++) {
+ if (e1k_eep_rd16(EEPROM_MAC_OFFS + i, &w[i]) != 0) {
+ printf("Failed to read MAC address from EEPROM!\n");
+ return -1;
+ }
+ }
+
+ /*
+ * invert the least significant bit for 82546 dual port
+ * if the second device is in use (remember word is byteswapped)
+ */
+ if ((IS_82546) &&
+ ((e1k_rd32(STATUS) & BIT32(2)) != 0)) {
+ w[2] ^= (uint16_t) 0x100;
+ }
+
+ /*
+ * store mac address for transmission to nic
+ */
+ l_ah_u32 = ((uint32_t) w[2] << 0);
+ l_al_u32 = ((uint32_t) w[1] << 16);
+ l_al_u32 |= ((uint32_t) w[0] << 0);
+
+ /*
+ * return mac address
+ * mac address in eeprom is stored byteswapped
+ */
+ f_mac_pu08[1] = (uint8_t) ((w[0] >> 8) & 0xff);
+ f_mac_pu08[0] = (uint8_t) ((w[0] >> 0) & 0xff);
+ f_mac_pu08[3] = (uint8_t) ((w[1] >> 8) & 0xff);
+ f_mac_pu08[2] = (uint8_t) ((w[1] >> 0) & 0xff);
+ f_mac_pu08[5] = (uint8_t) ((w[2] >> 8) & 0xff);
+ f_mac_pu08[4] = (uint8_t) ((w[2] >> 0) & 0xff);
+ }
+
+ /*
+ * insert mac address in receive address register
+ * and set AV bit
+ */
+ e1k_wr32(RAL0, l_al_u32);
+ e1k_wr32(RAH0, l_ah_u32 | BIT32(31));
+
+ /*
+ * clear remaining receive address registers
+ */
+ for (i = 1; i < NUM_MAC_ADDR; i++) {
+ e1k_wr32(RAL0 + i * sizeof(uint64_t), 0);
+ e1k_wr32(RAH0 + i * sizeof(uint64_t), 0);
+ }
+
+ return 0;
+}
+
+
+/*
+ * interface
+ ******************************************************************************
+ */
+
+/*
+ * e1k_receive
+ */
+static int
+e1k_receive(char *f_buffer_pc, int f_len_i)
+{
+ uint32_t l_rdh_u32 = e1k_rd32(RDH); // this includes needed dummy read
+ e1k_rx_desc_st *rx;
+ int l_ret_i;
+
+ #ifdef E1K_DEBUG
+ #ifdef E1K_SHOW_RCV_DATA
+ int i;
+ #endif
+ #endif
+
+ /*
+ * check whether new packets have arrived
+ */
+ if (m_e1k.m_rx_next_u32 == l_rdh_u32) {
+ return 0;
+ }
+
+ /*
+ * get a pointer to the next rx descriptor for ease of use
+ */
+ rx = &m_e1k.m_rx_ring_pst[m_e1k.m_rx_next_u32];
+
+ /*
+ * check whether the descriptor done bit is set
+ */
+ if ((rx->m_sta_u08 & 0x1) == 0) {
+ return 0;
+ }
+
+ /*
+ * get the length of the packet, throw away checksum
+ */
+ l_ret_i = (int) bswap_16(rx->m_len_u16) - (int) 4;
+
+ /*
+ * copy the data
+ */
+ memcpy((uint8_t *) f_buffer_pc, dma2virt(bswap_64(rx->m_buffer_u64)),
+ (size_t) l_ret_i);
+
+ #ifdef E1K_DEBUG
+ #if defined(E1K_SHOW_RCV) || defined(E1K_SHOW_RCV_DATA)
+ printf("e1k: %d bytes received\n", l_ret_i);
+ #endif
+
+ #ifdef E1K_SHOW_RCV_DATA
+ for (i = 0; i < l_ret_i; i++) {
+
+ if ((i & 0x1f) == 0) {
+ printf("\n ");
+ }
+
+ printf("%02X ", f_buffer_pc[i]);
+ }
+
+ printf("\n\n");
+ #endif
+ #endif
+
+ /*
+ * clear descriptor for reusage, but leave buffer pointer untouched
+ */
+ memset((uint8_t *) &rx->m_len_u16, 0,
+ sizeof(e1k_rx_desc_st) - sizeof(uint64_t));
+ mb();
+
+ /*
+ * write new tail pointer
+ */
+ e1k_wr32(RDT, m_e1k.m_rx_next_u32);
+
+ /*
+ * update next receive index
+ */
+ m_e1k.m_rx_next_u32 = (m_e1k.m_rx_next_u32 + 1) & (E1K_NUM_RX_DESC - 1);
+
+ return l_ret_i;
+}
+
+static int
+e1k_xmit(char *f_buffer_pc, int f_len_i)
+{
+ uint32_t l_tdh_u32 = e1k_rd32(TDH);
+ uint32_t l_tdt_u32 = e1k_rd32(TDT);
+ uint32_t l_pre_u32 = (l_tdh_u32 + (E1K_NUM_TX_DESC - 1)) &
+ (E1K_NUM_TX_DESC - 1);
+ e1k_tx_desc_st *tx;
+ #if defined(E1K_DEBUG) && defined(E1K_SHOW_XMIT_DATA)
+ int i;
+ #endif
+
+ /*
+ * check for available buffers
+ */
+ if (l_pre_u32 == l_tdt_u32) {
+ return 0;
+ }
+
+ /*
+ * get a pointer to the next tx descriptor for ease of use
+ */
+ tx = &m_e1k.m_tx_ring_pst[l_tdt_u32];
+
+ /*
+ * copy the data
+ */
+ memcpy(dma2virt(bswap_64(tx->m_buffer_u64)), (uint8_t *) f_buffer_pc,
+ (size_t) f_len_i);
+
+ /*
+ * insert length & command flags
+ */
+ tx->m_len_u16 = bswap_16((uint16_t) f_len_i);
+ tx->m_cmd_u08 = (BIT08(0) | // EOP
+ BIT08(1)); // IFCS
+ tx->m_sta_u08 = 0;
+ mb();
+
+ /*
+ * update tail index
+ */
+ l_tdt_u32 = (l_tdt_u32 + 1) & (E1K_NUM_TX_DESC - 1);
+ e1k_wr32(TDT, l_tdt_u32);
+
+ #ifdef E1K_DEBUG
+ #if defined(E1K_SHOW_XMIT) || defined(E1K_SHOW_XMIT_DATA)
+ printf("e1k: %d bytes transmitted\n", bswap_16(tx->m_len_u16));
+ #endif
+
+ #ifdef E1K_SHOW_XMIT_DATA
+ for (i = 0; i < bswap_16(tx->m_len_u16); i++) {
+
+ if ((i & 0x1f) == 0) {
+ printf("\n ");
+ }
+
+ f_buffer_pc = dma2virt(bswap_64(tx->m_buffer_u64));
+ printf("%02X ", f_buffer_pc[i]);
+ }
+
+ printf("\n\n");
+ #endif
+ #endif
+
+ return f_len_i;
+}
+
+int
+check_driver(uint16_t vendor_id, uint16_t device_id)
+{
+ uint64_t i;
+
+ /*
+ * checks whether the driver is handling this device
+ * by verifying vendor & device id
+ * vendor id 0x8086 == Intel
+ */
+ if (vendor_id != 0x8086) {
+ #ifdef E1K_DEBUG
+ printf("e1k: netdevice with vendor id %04X not supported\n",
+ vendor_id);
+ #endif
+ return -1;
+ }
+
+ for (i = 0; e1k_dev[i].m_dev_u32 != 0; i++) {
+ if (e1k_dev[i].m_dev_u32 == (uint32_t) device_id) {
+ break;
+ }
+ }
+
+ if (e1k_dev[i].m_dev_u32 == 0) {
+ #ifdef E1K_DEBUG
+ printf("e1k: netdevice with device id %04X not supported\n",
+ device_id);
+ #endif
+ return -1;
+ }
+
+ /*
+ * initialize static variables
+ */
+ m_e1k.m_device_u64 = e1k_dev[i].m_devmsk_u64;
+ m_e1k.m_baseaddr_u64 = 0;
+
+ // success
+ #ifdef E1K_DEBUG
+ printf("e1k: found device %s\n", e1k_dev[i].m_name);
+ #endif
+
+ return 0;
+}
+
+static int
+e1k_init(net_driver_t *driver)
+{
+ uint32_t i;
+ uint32_t v;
+
+ if (!driver)
+ return -1;
+
+ #ifdef E1K_DEBUG
+ printf("\ne1k: initializing\n");
+ #endif
+
+ dma_offset = SLOF_dma_map_in(&m_e1k, sizeof(m_e1k), 0);
+ #ifdef E1K_DEBUG
+ printf("e1k: dma offset: %lx - %lx = %lx\n", dma_offset, (long)&m_e1k,
+ dma_offset - (long)&m_e1k);
+ #endif
+ dma_offset = dma_offset - (long)&m_e1k;
+
+ /*
+ * setup register & memory base addresses of NIC
+ */
+ //m_e1k.m_baseaddr_u64 = baseaddr;
+ #ifdef E1K_DEBUG
+ printf("e1k: base address register = 0x%llx\n", m_e1k.m_baseaddr_u64);
+ #endif
+
+ /*
+ * e1k hardware initialization
+ */
+
+ /*
+ * at first disable all interrupts
+ */
+ e1k_wr32(IMC, (uint32_t) ~0);
+
+ /*
+ * check for link up
+ */
+ #ifdef E1K_DEBUG
+ printf("e1k: checking link status..\n");
+ #endif
+
+ i = 50;
+ v = e1k_rd32(STATUS);
+ while ((--i) &&
+ ((v & BIT32(1)) == 0)) {
+ SLOF_msleep(100);
+ v = e1k_rd32(STATUS);
+ }
+
+ if ((v & BIT32(1)) == 0) {
+ #ifdef E1K_DEBUG
+ printf("e1k: link is down.\n");
+ printf(" terminating.\n");
+ #endif
+
+ return -1;
+ }
+
+ #ifdef E1K_DEBUG
+ printf("e1k: link is up\n");
+
+ switch ((v >> 6) & 0x3) {
+ case 0: {
+ printf(" 10 Mb/s\n");
+ } break;
+ case 1: {
+ printf(" 100 Mb/s\n");
+ } break;
+ case 2:
+ case 3: {
+ printf(" 1000 Mb/s\n");
+ } break;
+ }
+
+ if ((v & BIT32(0)) == 0) {
+ printf(" half-duplex\n");
+ } else {
+ printf(" full-duplex\n");
+ }
+ #endif
+
+ /*
+ * initialize mac address
+ */
+ #ifdef E1K_DEBUG
+ printf("e1k: initializing mac address.. ");
+ #endif
+ if (e1k_mac_init((uint8_t *)driver->mac_addr) != 0) {
+ #ifdef E1K_DEBUG
+ printf("failed.\n");
+ printf(" terminating.\n");
+ #endif
+
+ return -1;
+ }
+
+ #ifdef E1K_DEBUG
+ printf("done.\n");
+ printf(" mac address = %02X:%02X:%02X:%02X:%02X:%02X\n",
+ driver->mac_addr[0], driver->mac_addr[1], driver->mac_addr[2],
+ driver->mac_addr[3], driver->mac_addr[4], driver->mac_addr[5]);
+ #endif
+
+ /*
+ * initialize transmitter
+ */
+ #ifdef E1K_DEBUG
+ printf("e1k: initializing transmitter.. ");
+ #endif
+ e1k_init_transmitter();
+ #ifdef E1K_DEBUG
+ printf("done.\n");
+ #endif
+
+ /*
+ * initialize receiver
+ */
+ #ifdef E1K_DEBUG
+ printf("e1k: initializing receiver.. ");
+ #endif
+ e1k_init_receiver();
+ #ifdef E1K_DEBUG
+ printf("done.\n");
+ printf("e1k: initialization complete\n");
+ #endif
+
+ driver->running = 1;
+
+ return 0;
+}
+
+static int
+e1k_reset(void)
+{
+ /*
+ * reset the PHY
+ */
+ e1k_setb32(CTRL, BIT32(31));
+ SLOF_msleep(10);
+
+ /*
+ * reset the MAC
+ */
+ e1k_setb32(CTRL, BIT32(26));
+ SLOF_msleep(10);
+
+ return 0;
+}
+
+static int
+e1k_term(void)
+{
+ #ifdef E1K_DEBUG
+ printf("e1k: shutdown.. ");
+ #endif
+
+ /*
+ * disable receiver & transmitter
+ */
+ e1k_wr32(RCTL, 0);
+ e1k_wr32(TCTL, 0);
+ SLOF_msleep(10);
+
+ /*
+ * reset the ring indices
+ */
+ e1k_wr32(RDH, 0);
+ e1k_wr32(RDT, 0);
+ e1k_wr32(TDH, 0);
+ e1k_wr32(TDT, 0);
+
+ /*
+ * disable receive address
+ */
+ e1k_clrb32(RAH0, BIT32(31));
+
+ /*
+ * reset the mac/phy
+ */
+ e1k_reset();
+
+ /*
+ * Disable DMA translation
+ */
+ SLOF_dma_map_out((long)virt2dma(&m_e1k), (void *)&m_e1k, (long)sizeof(m_e1k));
+
+ #ifdef E1K_DEBUG
+ printf("done.\n");
+ #endif
+
+ return 0;
+}
+
+net_driver_t *e1k_open(uint64_t baseaddr)
+{
+ net_driver_t *driver;
+
+ m_e1k.m_baseaddr_u64 = baseaddr;
+ driver = SLOF_alloc_mem(sizeof(*driver));
+ if (!driver) {
+ printf("Unable to allocate virtio-net driver\n");
+ return NULL;
+ }
+ memset(driver, 0, sizeof(*driver));
+
+ if (e1k_init(driver))
+ goto FAIL;
+
+ return driver;
+
+FAIL: SLOF_free_mem(driver, sizeof(*driver));
+ return NULL;
+
+ return 0;
+}
+
+void e1k_close(net_driver_t *driver)
+{
+ if (driver->running == 0)
+ return;
+
+ e1k_term();
+ driver->running = 0;
+ SLOF_free_mem(driver, sizeof(*driver));
+}
+
+int e1k_read(char *buf, int len)
+{
+ if (buf)
+ return e1k_receive(buf, len);
+ return -1;
+}
+
+int e1k_write(char *buf, int len)
+{
+ if (buf)
+ return e1k_xmit(buf, len);
+ return -1;
+}
+
+int e1k_mac_setup(uint16_t vendor_id, uint16_t device_id,
+ uint64_t baseaddr, char *mac_addr)
+{
+ if (check_driver(vendor_id, device_id))
+ return -1;
+
+ m_e1k.m_baseaddr_u64 = baseaddr;
+ memset(mac_addr, 0, 6);
+
+ return e1k_mac_init((uint8_t *)mac_addr);
+}
diff --git a/src/roms/SLOF/lib/libe1k/e1k.code b/src/roms/SLOF/lib/libe1k/e1k.code
new file mode 100644
index 0000000..225ed4e
--- /dev/null
+++ b/src/roms/SLOF/lib/libe1k/e1k.code
@@ -0,0 +1,75 @@
+/******************************************************************************
+ * Copyright (c) 2013 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+/*
+ * libe1k Forth wrapper
+ */
+
+#include <e1k.h>
+
+// : e1k-open ( baseaddr -- false | [ driver true ] )
+PRIM(E1K_X2d_OPEN)
+{
+ uint64_t baseaddr = TOS.u; POP;
+ net_driver_t *net_driver = e1k_open(baseaddr);
+ if (net_driver) {
+ PUSH;
+ TOS.u = (unsigned long)net_driver; PUSH;
+ TOS.n = -1;
+ } else {
+ PUSH;
+ TOS.n = 0;
+ }
+}
+MIRP
+
+// : e1k-close ( driver -- )
+PRIM(E1K_X2d_CLOSE)
+{
+ net_driver_t *driver = TOS.a; POP;
+ e1k_close(driver);
+}
+MIRP
+
+
+// : e1k-read ( addr len -- actual )
+PRIM(E1K_X2d_READ)
+{
+ int len = TOS.u; POP;
+ TOS.n = e1k_read(TOS.a, len);
+}
+MIRP
+
+// : e1k-write ( addr len -- actual )
+PRIM(E1K_X2d_WRITE)
+{
+ int len = TOS.u; POP;
+ TOS.n = e1k_write(TOS.a, len);
+}
+MIRP
+
+// : e1k-mac-setup ( vendor-id device-id baseaddr addr -- false | [ mac-addr len true ] )
+PRIM(E1K_X2d_MAC_X2d_SETUP)
+{
+ char *mac_addr = TOS.a; POP;
+ uint64_t baseaddr = TOS.u; POP;
+ unsigned int device_id = TOS.u; POP;
+
+ int ret = e1k_mac_setup(TOS.u, device_id, baseaddr, mac_addr);
+ if (!ret) {
+ TOS.a = mac_addr; PUSH;
+ TOS.n = 6; PUSH;
+ TOS.n = -1;
+ } else
+ TOS.n = 0;
+}
+MIRP
diff --git a/src/roms/SLOF/lib/libe1k/e1k.h b/src/roms/SLOF/lib/libe1k/e1k.h
new file mode 100644
index 0000000..c88b3e5
--- /dev/null
+++ b/src/roms/SLOF/lib/libe1k/e1k.h
@@ -0,0 +1,108 @@
+/******************************************************************************
+ * Copyright (c) 2007, 2011, 2013 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+/*
+ * Definitions for the e1000 Gigabit Ethernet Driver for SLOF
+ */
+
+#include <stdint.h>
+#include <cache.h>
+
+// compiler switches
+
+// Debug switches
+//#define E1K_DEBUG // main debug switch, w/o it the other ones don't work
+//#define E1K_SHOW_RCV
+//#define E1K_SHOW_RCV_DATA
+//#define E1K_SHOW_XMIT
+//#define E1K_SHOW_XMIT_DATA
+
+/*
+ * pci register offsets
+ */
+// PCI command register
+#define PCI_COM_R ((uint16_t) 0x0004)
+// PCI Cache Line Size register
+#define PCI_CACHELS_R ((uint16_t) 0x000c)
+// PCI bar1 register
+#define PCI_BAR1_R ((uint16_t) 0x0010)
+// PCI bar2 register
+#define PCI_BAR2_R ((uint16_t) 0x0014)
+// PCI bar1 register
+#define PCI_SUBID_R ((uint16_t) 0x002e)
+
+/*
+ * e1000 register offsets
+ */
+// Device Control register
+#define CTRL ((uint16_t) 0x0000)
+// Device Status register
+#define STATUS ((uint16_t) 0x0008)
+// Eeprom Read register
+#define EERD ((uint16_t) 0x0014)
+// Interrupt Mask Clear register
+#define IMC ((uint16_t) 0x00d8)
+// Receive Control register
+#define RCTL ((uint16_t) 0x0100)
+// Receive Descriptor Base Address Low register
+#define RDBAL ((uint16_t) 0x2800)
+// Receive Descriptor Base Address High register
+#define RDBAH ((uint16_t) 0x2804)
+// Receive Descriptor Length register
+#define RDLEN ((uint16_t) 0x2808)
+// Receive Descriptor Head register
+#define RDH ((uint16_t) 0x2810)
+// Receive Descriptor Tail register
+#define RDT ((uint16_t) 0x2818)
+// Receive Delay Timer register
+#define RDTR ((uint16_t) 0x2820)
+// Transmit Control register
+#define TCTL ((uint16_t) 0x0400)
+// Transmit Descriptor Base Address Low register
+#define TDBAL ((uint16_t) 0x3800)
+// Transmit Descriptor Base Address High register
+#define TDBAH ((uint16_t) 0x3804)
+// Transmit Descriptor Length register
+#define TDLEN ((uint16_t) 0x3808)
+// Transmit Descriptor Head register
+#define TDH ((uint16_t) 0x3810)
+// Transmit Descriptor Tail register
+#define TDT ((uint16_t) 0x3818)
+// Receive Address Low register
+#define RAL0 ((uint16_t) 0x5400)
+// Receive Address High register
+#define RAH0 ((uint16_t) 0x5404)
+
+
+/*
+ * useful def's
+ */
+#define rd08(a) ci_read_8((uint32_t *)(a))
+#define rd16(a) ci_read_16((uint32_t *)(a))
+#define rd32(a) ci_read_32((uint32_t *)(a))
+#define wr08(a,v) ci_write_8((uint32_t *)(a), (v))
+#define wr16(a,v) ci_write_16((uint32_t *)(a), (v))
+#define wr32(a,v) ci_write_32((uint32_t *)(a), (v))
+//#define printk snk_kernel_interface->print
+//#define ms_delay snk_kernel_interface->ms_delay
+
+#define BIT08(bit) ((uint8_t) 0x1 << (bit))
+#define BIT16(bit) ((uint16_t) 0x1 << (bit))
+#define BIT32(bit) ((uint32_t) 0x1 << (bit))
+
+//#define mb() asm volatile("sync" ::: "memory");
+
+extern net_driver_t *e1k_open(uint64_t baseaddr);
+extern void e1k_close(net_driver_t *driver);
+extern int e1k_read(char *buf, int len);
+extern int e1k_write(char *buf, int len);
+extern int e1k_mac_setup(uint16_t vendor_id, uint16_t device_id,
+ uint64_t baseaddr, char *mac_addr);
diff --git a/src/roms/SLOF/lib/libe1k/e1k.in b/src/roms/SLOF/lib/libe1k/e1k.in
new file mode 100644
index 0000000..a9cb13f
--- /dev/null
+++ b/src/roms/SLOF/lib/libe1k/e1k.in
@@ -0,0 +1,21 @@
+/******************************************************************************
+ * Copyright (c) 2013 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+/*
+ * libe1k bindings for Forth - definitions
+ */
+
+cod(E1K-OPEN)
+cod(E1K-CLOSE)
+cod(E1K-READ)
+cod(E1K-WRITE)
+cod(E1K-MAC-SETUP)
diff --git a/src/roms/SLOF/lib/libelf/Makefile b/src/roms/SLOF/lib/libelf/Makefile
new file mode 100644
index 0000000..34a8f20
--- /dev/null
+++ b/src/roms/SLOF/lib/libelf/Makefile
@@ -0,0 +1,47 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2011 IBM Corporation
+# * All rights reserved.
+# * This program and the accompanying materials
+# * are made available under the terms of the BSD License
+# * which accompanies this distribution, and is available at
+# * http://www.opensource.org/licenses/bsd-license.php
+# *
+# * Contributors:
+# * IBM Corporation - initial implementation
+# ****************************************************************************/
+
+TOPCMNDIR ?= ../..
+
+include $(TOPCMNDIR)/make.rules
+
+CPPFLAGS = -I../libc/include $(CPUARCHDEF) -I$(INCLCMNDIR) -I$(INCLCMNDIR)/$(CPUARCH)
+LDFLAGS= -nostdlib
+
+TARGET = ../libelf.a
+
+all: $(TARGET)
+
+SRCS = elf.c elf32.c elf64.c elf_claim.c
+
+OBJS = $(SRCS:%.c=%.o)
+
+$(TARGET): $(OBJS)
+ $(AR) -rc $@ $(OBJS)
+ $(RANLIB) $@
+
+clean:
+ $(RM) $(TARGET) $(OBJS)
+
+distclean: clean
+ $(RM) Makefile.dep
+
+# Rules for creating the dependency file:
+depend:
+ $(RM) Makefile.dep
+ $(MAKE) Makefile.dep
+
+Makefile.dep: Makefile
+ $(CC) -MM $(CPPFLAGS) $(CFLAGS) $(SRCS) > Makefile.dep
+
+# Include dependency file if available:
+-include Makefile.dep
diff --git a/src/roms/SLOF/lib/libelf/elf.c b/src/roms/SLOF/lib/libelf/elf.c
new file mode 100644
index 0000000..db2d2ab
--- /dev/null
+++ b/src/roms/SLOF/lib/libelf/elf.c
@@ -0,0 +1,190 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2011 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+/*
+ * ELF loader
+ */
+
+#include <string.h>
+#include <cache.h>
+#include <libelf.h>
+#include <byteorder.h>
+
+/**
+ * elf_check_file tests if the file at file_addr is
+ * a correct endian, ELF PPC executable
+ * @param file_addr pointer to the start of the ELF file
+ * @return the class (1 for 32 bit, 2 for 64 bit)
+ * -1 if it is not an ELF file
+ * -2 if it has the wrong endianness
+ * -3 if it is not an ELF executable
+ * -4 if it is not for PPC
+ */
+static int
+elf_check_file(unsigned long *file_addr)
+{
+ struct ehdr *ehdr = (struct ehdr *) file_addr;
+ uint8_t native_endian;
+
+ /* check if it is an ELF image at all */
+ if (cpu_to_be32(ehdr->ei_ident) != 0x7f454c46)
+ return -1;
+
+#ifdef __BIG_ENDIAN__
+ native_endian = ELFDATA2MSB;
+#else
+ native_endian = ELFDATA2LSB;
+#endif
+
+ if (native_endian != ehdr->ei_data) {
+ switch (ehdr->ei_class) {
+ case 1:
+ elf_byteswap_header32(file_addr);
+ break;
+ case 2:
+ elf_byteswap_header64(file_addr);
+ break;
+ }
+ }
+
+ /* check if it is an ELF executable ... and also
+ * allow DYN files, since this is specified by ePAPR */
+ if (ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN)
+ return -3;
+
+ /* check if it is a PPC ELF executable */
+ if (ehdr->e_machine != 0x14 && ehdr->e_machine != 0x15)
+ return -4;
+
+ return ehdr->ei_class;
+}
+
+/**
+ * load_elf_file tries to load the ELF file specified in file_addr
+ *
+ * it first checks if the file is a PPC ELF executable and then loads
+ * the segments depending if it is a 64bit or 32 bit ELF file
+ *
+ * @param file_addr pointer to the start of the elf file
+ * @param entry pointer where the ELF loader will store
+ * the entry point
+ * @param pre_load handler that is called before copying a segment
+ * @param post_load handler that is called after copying a segment
+ * @return 1 for a 32 bit file
+ * 2 for a 64 bit BE file
+ * 3 for a 64 bit LE ABIv1 file
+ * 4 for a 64 bit LE ABIv2 file
+ * 5 for a 32 bit LE ABIv1 file
+ * anything else means an error during load
+ */
+int
+elf_load_file(void *file_addr, unsigned long *entry,
+ int (*pre_load)(void*, long),
+ void (*post_load)(void*, long))
+{
+ int type = elf_check_file(file_addr);
+ struct ehdr *ehdr = (struct ehdr *) file_addr;
+
+ switch (type) {
+ case 1:
+ *entry = elf_load_segments32(file_addr, 0, pre_load, post_load);
+ if (ehdr->ei_data != ELFDATA2MSB) {
+ type = 5; /* LE32 ABIv1 */
+ }
+ break;
+ case 2:
+ *entry = elf_load_segments64(file_addr, 0, pre_load, post_load);
+ if (ehdr->ei_data != ELFDATA2MSB) {
+ uint32_t flags = elf_get_eflags_64(file_addr);
+ if ((flags & 0x3) == 2)
+ type = 4; /* LE64 ABIv2 */
+ else
+ type = 3; /* LE64 ABIv1 */
+ }
+ break;
+ }
+ if (*entry == 0)
+ type = 0;
+
+ return type;
+}
+
+
+/**
+ * load_elf_file_to_addr loads an ELF file to given address.
+ * This is useful for 64-bit vmlinux images that use the virtual entry
+ * point address in their headers, and thereby need a special treatment.
+ *
+ * @param file_addr pointer to the start of the elf file
+ * @param entry pointer where the ELF loader will store
+ * the entry point
+ * @param pre_load handler that is called before copying a segment
+ * @param post_load handler that is called after copying a segment
+ * @return 1 for a 32 bit file
+ * 2 for a 64 bit file
+ * anything else means an error during load
+ */
+int
+elf_load_file_to_addr(void *file_addr, void *addr, unsigned long *entry,
+ int (*pre_load)(void*, long),
+ void (*post_load)(void*, long))
+{
+ int type;
+ long offset;
+
+ type = elf_check_file(file_addr);
+
+ switch (type) {
+ case 1:
+ /* Parse 32-bit image */
+ offset = (long)addr - elf_get_base_addr32(file_addr);
+ *entry = elf_load_segments32(file_addr, offset, pre_load,
+ post_load) + offset;
+ // TODO: elf_relocate32(...)
+ break;
+ case 2:
+ /* Parse 64-bit image */
+ offset = (long)addr - elf_get_base_addr64(file_addr);
+ *entry = elf_load_segments64(file_addr, offset, pre_load,
+ post_load) + offset;
+ elf_relocate64(file_addr, offset);
+ break;
+ }
+
+ return type;
+}
+
+
+/**
+ * Get the base load address of the ELF image
+ * @return The base address or -1 for error
+ */
+long
+elf_get_base_addr(void *file_addr)
+{
+ int type;
+
+ type = elf_check_file(file_addr);
+
+ switch (type) {
+ case 1:
+ /* Return 32-bit image base address */
+ return elf_get_base_addr32(file_addr);
+ break;
+ case 2:
+ /* Return 64-bit image base address */
+ return elf_get_base_addr64(file_addr);
+ break;
+ }
+
+ return -1;
+}
diff --git a/src/roms/SLOF/lib/libelf/elf32.c b/src/roms/SLOF/lib/libelf/elf32.c
new file mode 100644
index 0000000..fea5cf4
--- /dev/null
+++ b/src/roms/SLOF/lib/libelf/elf32.c
@@ -0,0 +1,193 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2011 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+/*
+ * 32-bit ELF loader
+ */
+#include <stdio.h>
+#include <string.h>
+#include <libelf.h>
+#include <byteorder.h>
+
+struct ehdr32 {
+ uint32_t ei_ident;
+ uint8_t ei_class;
+ uint8_t ei_data;
+ uint8_t ei_version;
+ uint8_t ei_pad[9];
+ uint16_t e_type;
+ uint16_t e_machine;
+ uint32_t e_version;
+ uint32_t e_entry;
+ uint32_t e_phoff;
+ uint32_t e_shoff;
+ uint32_t e_flags;
+ uint16_t e_ehsize;
+ uint16_t e_phentsize;
+ uint16_t e_phnum;
+ uint16_t e_shentsize;
+ uint16_t e_shnum;
+ uint16_t e_shstrndx;
+};
+
+struct phdr32 {
+ uint32_t p_type;
+ uint32_t p_offset;
+ uint32_t p_vaddr;
+ uint32_t p_paddr;
+ uint32_t p_filesz;
+ uint32_t p_memsz;
+ uint32_t p_flags;
+ uint32_t p_align;
+};
+
+
+static struct phdr32*
+get_phdr32(void *file_addr)
+{
+ return (struct phdr32 *) (((unsigned char *)file_addr)
+ + ((struct ehdr32 *)file_addr)->e_phoff);
+}
+
+static void
+load_segment(void *file_addr, struct phdr32 *phdr, signed long offset,
+ int (*pre_load)(void*, long),
+ void (*post_load)(void*, long))
+{
+ unsigned long src = phdr->p_offset + (unsigned long) file_addr;
+ unsigned long destaddr;
+
+ destaddr = (unsigned long)phdr->p_paddr;
+ destaddr = destaddr + offset;
+
+ /* check if we're allowed to copy */
+ if (pre_load != NULL) {
+ if (pre_load((void*)destaddr, phdr->p_memsz) != 0)
+ return;
+ }
+
+ /* copy into storage */
+ memmove((void *)destaddr, (void *)src, phdr->p_filesz);
+
+ /* clear bss */
+ memset((void *)(destaddr + phdr->p_filesz), 0,
+ phdr->p_memsz - phdr->p_filesz);
+
+ if (phdr->p_memsz && post_load) {
+ post_load((void*)destaddr, phdr->p_memsz);
+ }
+}
+
+unsigned int
+elf_load_segments32(void *file_addr, signed long offset,
+ int (*pre_load)(void*, long),
+ void (*post_load)(void*, long))
+{
+ struct ehdr32 *ehdr = (struct ehdr32 *) file_addr;
+ /* Calculate program header address */
+ struct phdr32 *phdr = get_phdr32(file_addr);
+ int i;
+
+ /* loop e_phnum times */
+ for (i = 0; i <= ehdr->e_phnum; i++) {
+ /* PT_LOAD ? */
+ if (phdr->p_type == 1) {
+ if (phdr->p_paddr != phdr->p_vaddr) {
+ printf("ELF32: VirtAddr(%lx) != PhysAddr(%lx) not supported, aborting\n",
+ (long)phdr->p_vaddr, (long)phdr->p_paddr);
+ return 0;
+ }
+
+ /* copy segment */
+ load_segment(file_addr, phdr, offset, pre_load,
+ post_load);
+ }
+ /* step to next header */
+ phdr = (struct phdr32 *)(((uint8_t *)phdr) + ehdr->e_phentsize);
+ }
+
+ /* Entry point is always a virtual address, so translate it
+ * to physical before returning it */
+ return ehdr->e_entry;
+}
+
+/**
+ * Return the base address for loading (i.e. the address of the first PT_LOAD
+ * segment)
+ * @param file_addr pointer to the ELF file in memory
+ * @return the base address
+ */
+long
+elf_get_base_addr32(void *file_addr)
+{
+ struct ehdr32 *ehdr = (struct ehdr32 *) file_addr;
+ struct phdr32 *phdr = get_phdr32(file_addr);
+ int i;
+
+ /* loop e_phnum times */
+ for (i = 0; i <= ehdr->e_phnum; i++) {
+ /* PT_LOAD ? */
+ if (phdr->p_type == 1) {
+ return phdr->p_paddr;
+ }
+ /* step to next header */
+ phdr = (struct phdr32 *)(((uint8_t *)phdr) + ehdr->e_phentsize);
+ }
+
+ return 0;
+}
+
+uint32_t elf_get_eflags_32(void *file_addr)
+{
+ struct ehdr32 *ehdr = (struct ehdr32 *) file_addr;
+
+ return ehdr->e_flags;
+}
+
+void
+elf_byteswap_header32(void *file_addr)
+{
+ struct ehdr32 *ehdr = (struct ehdr32 *) file_addr;
+ struct phdr32 *phdr;
+ int i;
+
+ bswap_16p(&ehdr->e_type);
+ bswap_16p(&ehdr->e_machine);
+ bswap_32p(&ehdr->e_version);
+ bswap_32p(&ehdr->e_entry);
+ bswap_32p(&ehdr->e_phoff);
+ bswap_32p(&ehdr->e_shoff);
+ bswap_32p(&ehdr->e_flags);
+ bswap_16p(&ehdr->e_ehsize);
+ bswap_16p(&ehdr->e_phentsize);
+ bswap_16p(&ehdr->e_phnum);
+ bswap_16p(&ehdr->e_shentsize);
+ bswap_16p(&ehdr->e_shnum);
+ bswap_16p(&ehdr->e_shstrndx);
+
+ phdr = get_phdr32(file_addr);
+
+ /* loop e_phnum times */
+ for (i = 0; i <= ehdr->e_phnum; i++) {
+ bswap_32p(&phdr->p_type);
+ bswap_32p(&phdr->p_offset);
+ bswap_32p(&phdr->p_vaddr);
+ bswap_32p(&phdr->p_paddr);
+ bswap_32p(&phdr->p_filesz);
+ bswap_32p(&phdr->p_memsz);
+ bswap_32p(&phdr->p_flags);
+ bswap_32p(&phdr->p_align);
+
+ /* step to next header */
+ phdr = (struct phdr32 *)(((uint8_t *)phdr) + ehdr->e_phentsize);
+ }
+}
diff --git a/src/roms/SLOF/lib/libelf/elf64.c b/src/roms/SLOF/lib/libelf/elf64.c
new file mode 100644
index 0000000..37e9c10
--- /dev/null
+++ b/src/roms/SLOF/lib/libelf/elf64.c
@@ -0,0 +1,473 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2011 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+/*
+ * 64-bit ELF loader for PowerPC.
+ * See the "64-bit PowerPC ELF Application Binary Interface Supplement" and
+ * the "ELF-64 Object File Format" documentation for details.
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include <libelf.h>
+#include <byteorder.h>
+
+struct ehdr64
+{
+ uint32_t ei_ident;
+ uint8_t ei_class;
+ uint8_t ei_data;
+ uint8_t ei_version;
+ uint8_t ei_pad[9];
+ uint16_t e_type;
+ uint16_t e_machine;
+ uint32_t e_version;
+ uint64_t e_entry;
+ uint64_t e_phoff;
+ uint64_t e_shoff;
+ uint32_t e_flags;
+ uint16_t e_ehsize;
+ uint16_t e_phentsize;
+ uint16_t e_phnum;
+ uint16_t e_shentsize;
+ uint16_t e_shnum;
+ uint16_t e_shstrndx;
+};
+
+struct phdr64
+{
+ uint32_t p_type;
+ uint32_t p_flags;
+ uint64_t p_offset;
+ uint64_t p_vaddr;
+ uint64_t p_paddr;
+ uint64_t p_filesz;
+ uint64_t p_memsz;
+ uint64_t p_align;
+};
+
+struct shdr64
+{
+ uint32_t sh_name; /* Section name */
+ uint32_t sh_type; /* Section type */
+ uint64_t sh_flags; /* Section attributes */
+ uint64_t sh_addr; /* Virtual address in memory */
+ uint64_t sh_offset; /* Offset in file */
+ uint64_t sh_size; /* Size of section */
+ uint32_t sh_link; /* Link to other section */
+ uint32_t sh_info; /* Miscellaneous information */
+ uint64_t sh_addralign; /* Address alignment boundary */
+ uint64_t sh_entsize; /* Size of entries, if section has table */
+};
+
+struct rela /* RelA relocation table entry */
+{
+ uint64_t r_offset; /* Address of reference */
+ uint64_t r_info; /* Symbol index and type of relocation */
+ int64_t r_addend; /* Constant part of expression */
+};
+
+struct sym64
+{
+ uint32_t st_name; /* Symbol name */
+ uint8_t st_info; /* Type and Binding attributes */
+ uint8_t st_other; /* Reserved */
+ uint16_t st_shndx; /* Section table index */
+ uint64_t st_value; /* Symbol value */
+ uint64_t st_size; /* Size of object (e.g., common) */
+};
+
+
+/* For relocations */
+#define ELF_R_SYM(i) ((i)>>32)
+#define ELF_R_TYPE(i) ((uint32_t)(i) & 0xFFFFFFFF)
+#define ELF_R_INFO(s,t) ((((uint64_t) (s)) << 32) + (t))
+
+/*
+ * Relocation types for PowerPC64.
+ */
+#define R_PPC64_NONE 0
+#define R_PPC64_ADDR32 1
+#define R_PPC64_ADDR24 2
+#define R_PPC64_ADDR16 3
+#define R_PPC64_ADDR16_LO 4
+#define R_PPC64_ADDR16_HI 5
+#define R_PPC64_ADDR16_HA 6
+#define R_PPC64_ADDR14 7
+#define R_PPC64_ADDR14_BRTAKEN 8
+#define R_PPC64_ADDR14_BRNTAKEN 9
+#define R_PPC64_REL24 10
+#define R_PPC64_REL14 11
+#define R_PPC64_REL14_BRTAKEN 12
+#define R_PPC64_REL14_BRNTAKEN 13
+#define R_PPC64_GOT16 14
+#define R_PPC64_GOT16_LO 15
+#define R_PPC64_GOT16_HI 16
+#define R_PPC64_GOT16_HA 17
+#define R_PPC64_COPY 19
+#define R_PPC64_GLOB_DAT 20
+#define R_PPC64_JMP_SLOT 21
+#define R_PPC64_RELATIVE 22
+#define R_PPC64_UADDR32 24
+#define R_PPC64_UADDR16 25
+#define R_PPC64_REL32 26
+#define R_PPC64_PLT32 27
+#define R_PPC64_PLTREL32 28
+#define R_PPC64_PLT16_LO 29
+#define R_PPC64_PLT16_HI 30
+#define R_PPC64_PLT16_HA 31
+#define R_PPC64_SECTOFF 33
+#define R_PPC64_SECTOFF_LO 34
+#define R_PPC64_SECTOFF_HI 35
+#define R_PPC64_SECTOFF_HA 36
+#define R_PPC64_ADDR30 37
+#define R_PPC64_ADDR64 38
+#define R_PPC64_ADDR16_HIGHER 39
+#define R_PPC64_ADDR16_HIGHERA 40
+#define R_PPC64_ADDR16_HIGHEST 41
+#define R_PPC64_ADDR16_HIGHESTA 42
+#define R_PPC64_UADDR64 43
+#define R_PPC64_REL64 44
+#define R_PPC64_PLT64 45
+#define R_PPC64_PLTREL64 46
+#define R_PPC64_TOC16 47
+#define R_PPC64_TOC16_LO 48
+#define R_PPC64_TOC16_HI 49
+#define R_PPC64_TOC16_HA 50
+#define R_PPC64_TOC 51
+#define R_PPC64_PLTGOT16 52
+#define R_PPC64_PLTGOT16_LO 53
+#define R_PPC64_PLTGOT16_HI 54
+#define R_PPC64_PLTGOT16_HA 55
+#define R_PPC64_ADDR16_DS 56
+#define R_PPC64_ADDR16_LO_DS 57
+#define R_PPC64_GOT16_DS 58
+#define R_PPC64_GOT16_LO_DS 59
+#define R_PPC64_PLT16_LO_DS 60
+#define R_PPC64_SECTOFF_DS 61
+#define R_PPC64_SECTOFF_LO_DS 62
+#define R_PPC64_TOC16_DS 63
+#define R_PPC64_TOC16_LO_DS 64
+#define R_PPC64_PLTGOT16_DS 65
+#define R_PPC64_PLTGOT16_LO_DS 66
+#define R_PPC64_TLS 67
+#define R_PPC64_DTPMOD64 68
+#define R_PPC64_TPREL16 69
+#define R_PPC64_TPREL16_LO 60
+#define R_PPC64_TPREL16_HI 71
+#define R_PPC64_TPREL16_HA 72
+#define R_PPC64_TPREL64 73
+#define R_PPC64_DTPREL16 74
+#define R_PPC64_DTPREL16_LO 75
+#define R_PPC64_DTPREL16_HI 76
+#define R_PPC64_DTPREL16_HA 77
+#define R_PPC64_DTPREL64 78
+#define R_PPC64_GOT_TLSGD16 79
+#define R_PPC64_GOT_TLSGD16_LO 80
+#define R_PPC64_GOT_TLSGD16_HI 81
+#define R_PPC64_GOT_TLSGD16_HA 82
+#define R_PPC64_GOT_TLSLD16 83
+#define R_PPC64_GOT_TLSLD16_LO 84
+#define R_PPC64_GOT_TLSLD16_HI 85
+#define R_PPC64_GOT_TLSLD16_HA 86
+#define R_PPC64_GOT_TPREL16_DS 87
+#define R_PPC64_GOT_TPREL16_LO_ DS 88
+#define R_PPC64_GOT_TPREL16_HI 89
+#define R_PPC64_GOT_TPREL16_HA 90
+#define R_PPC64_GOT_DTPREL16_DS 91
+#define R_PPC64_GOT_DTPREL16_LO_DS 92
+#define R_PPC64_GOT_DTPREL16_HI 93
+#define R_PPC64_GOT_DTPREL16_HA 94
+#define R_PPC64_TPREL16_DS 95
+#define R_PPC64_TPREL16_LO_DS 96
+#define R_PPC64_TPREL16_HIGHER 97
+#define R_PPC64_TPREL16_HIGHERA 98
+#define R_PPC64_TPREL16_HIGHEST 99
+#define R_PPC64_TPREL16_HIGHESTA 100
+#define R_PPC64_DTPREL16_DS 101
+#define R_PPC64_DTPREL16_LO_DS 102
+#define R_PPC64_DTPREL16_HIGHER 103
+#define R_PPC64_DTPREL16_HIGHERA 104
+#define R_PPC64_DTPREL16_HIGHEST 105
+#define R_PPC64_DTPREL16_HIGHESTA 106
+
+
+static struct phdr64*
+get_phdr64(unsigned long *file_addr)
+{
+ return (struct phdr64 *) (((unsigned char *) file_addr)
+ + ((struct ehdr64 *)file_addr)->e_phoff);
+}
+
+static void
+load_segment64(unsigned long *file_addr, struct phdr64 *phdr, signed long offset,
+ int (*pre_load)(void*, long),
+ void (*post_load)(void*, long))
+{
+ unsigned long src = phdr->p_offset + (unsigned long) file_addr;
+ unsigned long destaddr;
+
+ destaddr = phdr->p_paddr + offset;
+
+ /* check if we're allowed to copy */
+ if (pre_load != NULL) {
+ if (pre_load((void*)destaddr, phdr->p_memsz) != 0)
+ return;
+ }
+
+ /* copy into storage */
+ memmove((void*)destaddr, (void*)src, phdr->p_filesz);
+
+ /* clear bss */
+ memset((void*)(destaddr + phdr->p_filesz), 0,
+ phdr->p_memsz - phdr->p_filesz);
+
+ if (phdr->p_memsz && post_load != NULL) {
+ post_load((void*)destaddr, phdr->p_memsz);
+ }
+}
+
+unsigned long
+elf_load_segments64(void *file_addr, signed long offset,
+ int (*pre_load)(void*, long),
+ void (*post_load)(void*, long))
+{
+ struct ehdr64 *ehdr = (struct ehdr64 *) file_addr;
+ /* Calculate program header address */
+ struct phdr64 *phdr = get_phdr64(file_addr);
+ int i;
+
+ /* loop e_phnum times */
+ for (i = 0; i <= ehdr->e_phnum; i++) {
+ /* PT_LOAD ? */
+ if (phdr->p_type == PT_LOAD) {
+ if (phdr->p_paddr != phdr->p_vaddr) {
+ printf("ELF64: VirtAddr(%lx) != PhysAddr(%lx) not supported, aborting\n",
+ (long)phdr->p_vaddr, (long)phdr->p_paddr);
+ return 0;
+ }
+
+ /* copy segment */
+ load_segment64(file_addr, phdr, offset, pre_load, post_load);
+ }
+ /* step to next header */
+ phdr = (struct phdr64 *)(((uint8_t *)phdr) + ehdr->e_phentsize);
+ }
+
+ /* Entry point is always a virtual address, so translate it
+ * to physical before returning it */
+ return ehdr->e_entry;
+}
+
+/**
+ * Return the base address for loading (i.e. the address of the first PT_LOAD
+ * segment)
+ * @param file_addr pointer to the ELF file in memory
+ * @return the base address
+ */
+long
+elf_get_base_addr64(void *file_addr)
+{
+ struct ehdr64 *ehdr = (struct ehdr64 *) file_addr;
+ /* Calculate program header address */
+ struct phdr64 *phdr = get_phdr64(file_addr);
+ int i;
+
+ /* loop e_phnum times */
+ for (i = 0; i <= ehdr->e_phnum; i++) {
+ /* PT_LOAD ? */
+ if (phdr->p_type == PT_LOAD) {
+ /* Return base address */
+ return phdr->p_paddr;
+ }
+ /* step to next header */
+ phdr = (struct phdr64 *)(((uint8_t *)phdr) + ehdr->e_phentsize);
+ }
+
+ return 0;
+}
+
+
+/**
+ * Apply one relocation entry.
+ */
+static void
+elf_apply_rela64(void *file_addr, signed long offset, struct rela *relaentry,
+ struct sym64 *symtabentry)
+{
+ void *addr;
+ unsigned long s_a;
+ unsigned long base_addr;
+
+ base_addr = elf_get_base_addr64(file_addr);
+
+ /* Sanity check */
+ if (relaentry->r_offset < base_addr) {
+ printf("\nELF relocation out of bounds!\n");
+ return;
+ }
+
+ base_addr += offset;
+
+ /* Actual address where the relocation will be applied at. */
+ addr = (void*)(relaentry->r_offset + offset);
+
+ /* Symbol value (S) + Addend (A) */
+ s_a = symtabentry->st_value + offset + relaentry->r_addend;
+
+ switch (ELF_R_TYPE(relaentry->r_info)) {
+ case R_PPC64_ADDR32: /* S + A */
+ *(uint32_t *)addr = (uint32_t) s_a;
+ break;
+ case R_PPC64_ADDR64: /* S + A */
+ *(uint64_t *)addr = (uint64_t) s_a;
+ break;
+ case R_PPC64_TOC: /* .TOC */
+ *(uint64_t *)addr += offset;
+ break;
+ case R_PPC64_ADDR16_HIGHEST: /* #highest(S + A) */
+ *(uint16_t *)addr = ((s_a >> 48) & 0xffff);
+ break;
+ case R_PPC64_ADDR16_HIGHER: /* #higher(S + A) */
+ *(uint16_t *)addr = ((s_a >> 32) & 0xffff);
+ break;
+ case R_PPC64_ADDR16_HI: /* #hi(S + A) */
+ *(uint16_t *)addr = ((s_a >> 16) & 0xffff);
+ break;
+ case R_PPC64_ADDR16_LO: /* #lo(S + A) */
+ *(uint16_t *)addr = s_a & 0xffff;
+ break;
+ case R_PPC64_ADDR16_LO_DS:
+ *(uint16_t *)addr = (s_a & 0xfffc);
+ break;
+ case R_PPC64_ADDR16_HA: /* #ha(S + A) */
+ *(uint16_t *)addr = (((s_a >> 16) + ((s_a & 0x8000) ? 1 : 0))
+ & 0xffff);
+ break;
+
+ case R_PPC64_TOC16: /* half16* S + A - .TOC. */
+ case R_PPC64_TOC16_LO_DS:
+ case R_PPC64_TOC16_LO: /* #lo(S + A - .TOC.) */
+ case R_PPC64_TOC16_HI: /* #hi(S + A - .TOC.) */
+ case R_PPC64_TOC16_HA:
+ case R_PPC64_TOC16_DS: /* (S + A - .TOC) >> 2 */
+ case R_PPC64_REL14:
+ case R_PPC64_REL24: /* (S + A - P) >> 2 */
+ case R_PPC64_REL64: /* S + A - P */
+ case R_PPC64_GOT16_DS:
+ case R_PPC64_GOT16_LO_DS:
+ // printf("\t\tignoring relocation type %i\n",
+ // ELF_R_TYPE(relaentry->r_info));
+ break;
+ default:
+ printf("ERROR: Unhandled relocation (A) type %i\n",
+ ELF_R_TYPE(relaentry->r_info));
+ }
+}
+
+
+/**
+ * Step through all relocation entries and apply them one by one.
+ */
+static void
+elf_apply_all_rela64(void *file_addr, signed long offset, struct shdr64 *shdrs, int idx)
+{
+ struct shdr64 *rela_shdr = &shdrs[idx];
+ struct shdr64 *dst_shdr = &shdrs[rela_shdr->sh_info];
+ struct shdr64 *sym_shdr = &shdrs[rela_shdr->sh_link];
+ struct rela *relaentry;
+ struct sym64 *symtabentry;
+ uint32_t symbolidx;
+ int i;
+
+ /* If the referenced section has not been allocated, then it has
+ * not been loaded and thus does not need to be relocated. */
+ if ((dst_shdr->sh_flags & SHF_ALLOC) != SHF_ALLOC)
+ return;
+
+ for (i = 0; i < rela_shdr->sh_size; i += rela_shdr->sh_entsize) {
+ relaentry = (struct rela *)(file_addr + rela_shdr->sh_offset + i);
+
+ symbolidx = ELF_R_SYM(relaentry->r_info);
+ symtabentry = (struct sym64*)(file_addr + sym_shdr->sh_offset) + symbolidx;
+
+ elf_apply_rela64(file_addr, offset, relaentry, symtabentry);
+ }
+}
+
+
+/**
+ * Apply ELF relocations
+ */
+void
+elf_relocate64(void *file_addr, signed long offset)
+{
+ struct ehdr64 *ehdr = (struct ehdr64 *) file_addr;
+ /* Calculate section header address */
+ struct shdr64 *shdrs = (struct shdr64 *)
+ (((unsigned char *) file_addr) + ehdr->e_shoff);
+ int i;
+
+ /* loop over all segments */
+ for (i = 0; i <= ehdr->e_shnum; i++) {
+ /* Skip if it is not a relocation segment */
+ if (shdrs[i].sh_type == SHT_RELA) {
+ elf_apply_all_rela64(file_addr, offset, shdrs, i);
+ }
+ }
+}
+
+void
+elf_byteswap_header64(void *file_addr)
+{
+ struct ehdr64 *ehdr = (struct ehdr64 *) file_addr;
+ struct phdr64 *phdr;
+ int i;
+
+ bswap_16p(&ehdr->e_type);
+ bswap_16p(&ehdr->e_machine);
+ bswap_32p(&ehdr->e_version);
+ bswap_64p(&ehdr->e_entry);
+ bswap_64p(&ehdr->e_phoff);
+ bswap_64p(&ehdr->e_shoff);
+ bswap_32p(&ehdr->e_flags);
+ bswap_16p(&ehdr->e_ehsize);
+ bswap_16p(&ehdr->e_phentsize);
+ bswap_16p(&ehdr->e_phnum);
+ bswap_16p(&ehdr->e_shentsize);
+ bswap_16p(&ehdr->e_shnum);
+ bswap_16p(&ehdr->e_shstrndx);
+
+ phdr = get_phdr64(file_addr);
+
+ /* loop e_phnum times */
+ for (i = 0; i <= ehdr->e_phnum; i++) {
+ bswap_32p(&phdr->p_type);
+ bswap_32p(&phdr->p_flags);
+ bswap_64p(&phdr->p_offset);
+ bswap_64p(&phdr->p_vaddr);
+ bswap_64p(&phdr->p_paddr);
+ bswap_64p(&phdr->p_filesz);
+ bswap_64p(&phdr->p_memsz);
+ bswap_64p(&phdr->p_align);
+
+ /* step to next header */
+ phdr = (struct phdr64 *)(((uint8_t *)phdr) + ehdr->e_phentsize);
+ }
+}
+
+uint32_t elf_get_eflags_64(void *file_addr)
+{
+ struct ehdr64 *ehdr = (struct ehdr64 *) file_addr;
+
+ return ehdr->e_flags;
+}
diff --git a/src/roms/SLOF/lib/libelf/elf_claim.c b/src/roms/SLOF/lib/libelf/elf_claim.c
new file mode 100644
index 0000000..43540f9
--- /dev/null
+++ b/src/roms/SLOF/lib/libelf/elf_claim.c
@@ -0,0 +1,28 @@
+/******************************************************************************
+ * Copyright (c) 2009, 2011 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <string.h>
+#include <libelf.h>
+#include "../../slof/paflof.h"
+
+
+/**
+ * Call Forth code to try to claim the memory region
+ */
+int
+elf_forth_claim(void *addr, long size)
+{
+ forth_push((long)addr);
+ forth_push(size);
+ forth_eval("elf-claim-segment");
+ return forth_pop();
+}
diff --git a/src/roms/SLOF/lib/libelf/libelf.code b/src/roms/SLOF/lib/libelf/libelf.code
new file mode 100644
index 0000000..551468b
--- /dev/null
+++ b/src/roms/SLOF/lib/libelf/libelf.code
@@ -0,0 +1,43 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2011 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+/*
+ * libelf Forth wrapper
+ */
+
+#include <libelf.h>
+
+// : elf-load-file ( fileaddr -- entry type )
+PRIM(ELF_X2d_LOAD_X2d_FILE)
+{
+ void *file_addr = TOS.a;
+ int type;
+ unsigned long entry;
+ type = elf_load_file(file_addr, &entry, elf_forth_claim, flush_cache);
+ TOS.u = entry;
+ PUSH; TOS.n = type;
+}
+MIRP
+
+// : elf-load-file-to-addr ( fileaddr destaddr -- entry type )
+PRIM(ELF_X2d_LOAD_X2d_FILE_X2d_TO_X2d_ADDR)
+{
+ void *dest_addr = TOS.a; POP;
+ void *file_addr = TOS.a;
+ int type;
+ unsigned long entry;
+ type = elf_load_file_to_addr(file_addr, dest_addr, &entry,
+ elf_forth_claim, flush_cache);
+ TOS.u = entry;
+ PUSH; TOS.n = type;
+}
+MIRP
diff --git a/src/roms/SLOF/lib/libelf/libelf.in b/src/roms/SLOF/lib/libelf/libelf.in
new file mode 100644
index 0000000..9c5f019
--- /dev/null
+++ b/src/roms/SLOF/lib/libelf/libelf.in
@@ -0,0 +1,18 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2011 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+/*
+ * libelf bindings for Forth - definitions
+ */
+
+cod(ELF-LOAD-FILE)
+cod(ELF-LOAD-FILE-TO-ADDR)
diff --git a/src/roms/SLOF/lib/libhvcall/Makefile b/src/roms/SLOF/lib/libhvcall/Makefile
new file mode 100644
index 0000000..2a9b2d7
--- /dev/null
+++ b/src/roms/SLOF/lib/libhvcall/Makefile
@@ -0,0 +1,57 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2008 IBM Corporation
+# * All rights reserved.
+# * This program and the accompanying materials
+# * are made available under the terms of the BSD License
+# * which accompanies this distribution, and is available at
+# * http://www.opensource.org/licenses/bsd-license.php
+# *
+# * Contributors:
+# * IBM Corporation - initial implementation
+# ****************************************************************************/
+
+TOPCMNDIR ?= ../..
+
+include $(TOPCMNDIR)/make.rules
+
+ASFLAGS = $(FLAG) $(RELEASE) $(CPUARCHDEF) -Wa,-mregnames
+CPPFLAGS = -I../libc/include $(CPUARCHDEF) -I$(INCLBRDDIR) \
+ -I$(INCLCMNDIR) -I$(INCLCMNDIR)/$(CPUARCH)
+LDFLAGS = -nostdlib
+
+TARGET = ../libhvcall.a
+
+
+all: $(TARGET)
+
+SRCS = brokensc1.c
+SRCSS = hvcall.S
+
+
+OBJS = $(SRCS:%.c=%.o) $(SRCSS:%.S=%.o)
+
+$(TARGET): $(OBJS)
+ $(AR) -rc $@ $(OBJS)
+ $(RANLIB) $@
+
+%.o: %.S
+ $(CC) $(CPPFLAGS) $(ASFLAGS) -c $< -o $@
+
+clean:
+ $(RM) $(TARGET) $(OBJS)
+
+distclean: clean
+ $(RM) Makefile.dep
+
+
+# Rules for creating the dependency file:
+depend:
+ $(RM) Makefile.dep
+ $(MAKE) Makefile.dep
+
+Makefile.dep: Makefile
+ $(CC) -M $(CPPFLAGS) $(CFLAGS) $(SRCS) $(SRCSS) > Makefile.dep
+
+# Include dependency file if available:
+-include Makefile.dep
+
diff --git a/src/roms/SLOF/lib/libhvcall/brokensc1.c b/src/roms/SLOF/lib/libhvcall/brokensc1.c
new file mode 100644
index 0000000..e6387e0
--- /dev/null
+++ b/src/roms/SLOF/lib/libhvcall/brokensc1.c
@@ -0,0 +1,162 @@
+#include <stdint.h>
+#include <stddef.h>
+#include <cpu.h>
+#include "libhvcall.h"
+#include "byteorder.h"
+
+// #define DEBUG_PATCHERY
+
+#define H_SET_DABR 0x28
+#define INS_SC1 0x44000022
+#define INS_SC1_REPLACE 0x7c000268
+
+extern volatile uint32_t sc1ins;
+
+static unsigned long hcall(uint32_t inst, unsigned long arg0, unsigned long arg1)
+{
+ register unsigned long r3 asm("r3") = arg0;
+ register unsigned long r4 asm("r4") = arg1;
+ register unsigned long r5 asm("r5") = inst;
+ asm volatile("bl 1f \n"
+ "1: \n"
+ "li 11, 2f - 1b \n"
+ "mflr 12 \n"
+ "add 11, 11, 12 \n"
+ "stw 5, 0(11) \n"
+ "dcbst 0, 11 \n"
+ "sync \n"
+ "icbi 0, 11 \n"
+ "isync \n"
+ "2: \n"
+ ".long 0 \n"
+ : "=r" (r3)
+ : "r" (r3), "r" (r4), "r" (r5)
+ : "ctr", "r0", "r6", "r7", "r8", "r9", "r10", "r11",
+ "r12", "r13", "r31", "lr", "cc");
+ return r3;
+}
+
+static int check_broken_sc1(void)
+{
+ long r;
+
+ /*
+ * Check if we can do a simple hcall. If it works, we are running in
+ * a sane environment and everything's fine. If it doesn't, we need
+ * to patch the hypercall instruction to something that traps into
+ * supervisor mode.
+ */
+ r = hcall(INS_SC1, H_SET_DABR, 0);
+ if (r == H_SUCCESS || r == H_HARDWARE) {
+ /* All is fine */
+ return 0;
+ }
+
+ /* We found a broken sc1 host! */
+ return 1;
+}
+
+int patch_broken_sc1(void *start, void *end, uint32_t *test_ins)
+{
+ uint32_t *p;
+ /* The sc 1 instruction */
+ uint32_t sc1 = INS_SC1;
+ /* An illegal instruction that KVM interprets as sc 1 */
+ uint32_t sc1_replacement = INS_SC1_REPLACE;
+ int is_le = (test_ins && *test_ins == 0x48000008);
+#ifdef DEBUG_PATCHERY
+ int cnt = 0;
+#endif
+
+ /* The host is sane, get out of here */
+ if (!check_broken_sc1())
+ return 0;
+
+ /* We only get here with a broken sc1 implementation */
+
+ /* Trim the range we scan to not cover the data section */
+ if (test_ins) {
+ /* This is the cpu table matcher for 970FX */
+ uint32_t end_bytes[] = { 0xffff0000, 0x3c0000 };
+ /*
+ * The .__start symbol contains a trap instruction followed
+ * by lots of zeros.
+ */
+ uint32_t start_bytes[] = { 0x7fe00008, 0, 0, 0, 0 };
+
+ if (is_le) {
+ end_bytes[0] = bswap_32(end_bytes[0]);
+ end_bytes[1] = bswap_32(end_bytes[1]);
+ start_bytes[1] = bswap_32(start_bytes[1]);
+ }
+
+ /* Find the start of the text section */
+ for (p = test_ins; (long)p > (long)start; p--) {
+ if (p[0] == start_bytes[0] &&
+ p[1] == start_bytes[1] &&
+ p[2] == start_bytes[2] &&
+ p[3] == start_bytes[3] &&
+ p[4] == start_bytes[4]) {
+ /*
+ * We found a match of the instruction sequence
+ * trap
+ * .long 0
+ * .long 0
+ * .long 0
+ * .long 0
+ * which marks the beginning of the .text
+ * section on all Linux kernels I've checked.
+ */
+#ifdef DEBUG_PATCHERY
+ printf("Shortened start from %p to %p\n", end, p);
+#endif
+ start = p;
+ break;
+ }
+ }
+
+ /* Find the end of the text section */
+ for (p = start; (long)p < (long)end; p++) {
+ if (p[0] == end_bytes[0] && p[1] == end_bytes[1]) {
+ /*
+ * We found a match of the PPC970FX entry in the
+ * guest kernel's CPU table. That table is
+ * usually found early in the .data section and
+ * thus marks the end of the .text section for
+ * us which we need to patch.
+ */
+#ifdef DEBUG_PATCHERY
+ printf("Shortened end from %p to %p\n", end, p);
+#endif
+ end = p;
+ break;
+ }
+ }
+ }
+
+ if (is_le) {
+ /*
+ * The kernel was built for LE mode, so our sc1 and replacement
+ * opcodes are in the wrong byte order. Reverse them.
+ */
+ sc1 = bswap_32(sc1);
+ sc1_replacement = bswap_32(sc1_replacement);
+ }
+
+ /* Patch all sc 1 instructions to reserved instruction 31/308 */
+ for (p = start; (long)p < (long)end; p++) {
+ if (*p == sc1) {
+ *p = sc1_replacement;
+ flush_cache(p, sizeof(*p));
+#ifdef DEBUG_PATCHERY
+ cnt++;
+#endif
+ }
+ }
+
+#ifdef DEBUG_PATCHERY
+ printf("Patched %d instructions (%p - %p)\n", cnt, start, end);
+#endif
+
+ return 1;
+}
diff --git a/src/roms/SLOF/lib/libhvcall/hvcall.S b/src/roms/SLOF/lib/libhvcall/hvcall.S
new file mode 100644
index 0000000..92cf22e
--- /dev/null
+++ b/src/roms/SLOF/lib/libhvcall/hvcall.S
@@ -0,0 +1,134 @@
+#define _ASM
+#define __ASSEMBLY__
+#include "macros.h"
+#include "libhvcall.h"
+#include <termctrl.h>
+#include <product.h>
+
+#define HVCALL .long 0x44000022
+ .text
+ .align 3
+
+ENTRY(get_print_banner)
+ LOAD32(r4, print_version)
+ LOAD32(r5, print_version_end)
+ std r4,0(r3)
+ std r5,8(r3)
+ blr
+
+ENTRY(hv_generic)
+ HVCALL
+ blr
+
+/* r3 = char, r4 = hvtermno */
+ENTRY(hv_putchar)
+ sldi r6,r3,(24+32)
+ li r3,H_PUT_TERM_CHAR
+ li r5,1
+ HVCALL
+ blr
+
+/* r3 = hvtermno */
+ENTRY(hv_getchar)
+ mflr r10
+ bl .hv_haschar
+ mtlr r10
+ cmpwi cr0,r3,0
+ beqlr
+ lis r9,inbuf@h
+ ori r9,r9,inbuf@l
+ lwz r4,20(r9)
+ lbzx r3,r4,r9
+ addi r4,r4,1
+ stw r4,20(r9)
+ blr
+
+/* r3 = hvtermno */
+ENTRY(hv_haschar)
+ mr r4,r3
+ li r3,-1
+ lis r9,inbuf@h
+ ori r9,r9,inbuf@l
+ lwz r5,16(r9)
+ lwz r6,20(r9)
+ cmplw cr0,r5,r6
+ bnelr
+ li r3,H_GET_TERM_CHAR
+ HVCALL
+ lis r9,inbuf@h
+ ori r9,r9,inbuf@l
+ stw r4,16(r9)
+ li r3,0
+ stw r3,20(r9)
+ cmplwi cr0,r4,0
+ beqlr
+ li r3,-1
+ std r5,0(r9)
+ std r6,8(r9)
+ blr
+
+ENTRY(hv_send_crq)
+ ld r5,0(r4)
+ ld r6,8(r4)
+ mr r4,r3
+ li r3,H_SEND_CRQ
+ HVCALL
+ blr
+
+ENTRY(hv_send_logical_lan)
+ li r11,0 /* no continue token for now */
+ mr r10,r9
+ mr r9,r8
+ mr r8,r7
+ mr r7,r6
+ mr r6,r5
+ mr r5,r4
+ mr r4,r3
+ li r3,H_SEND_LOGICAL_LAN
+ HVCALL
+ blr
+
+ENTRY(hv_logical_ci_load)
+ mr r5,r4
+ mr r4,r3
+ li r3,H_LOGICAL_CI_LOAD
+ HVCALL
+ cmpdi cr0,r3,0
+ mr r3,r4
+ beqlr
+ li r3,-1
+ blr
+
+ENTRY(hv_logical_ci_store)
+ mr r6,r5
+ mr r5,r4
+ mr r4,r3
+ li r3,H_LOGICAL_CI_STORE
+ HVCALL
+ blr
+
+ENTRY(hv_logical_memop)
+ mr r8,r7
+ mr r7,r6
+ mr r6,r5
+ mr r5,r4
+ mr r4,r3
+ lis r3,KVMPPC_H_LOGICAL_MEMOP@h
+ ori r3,r3,KVMPPC_H_LOGICAL_MEMOP@l
+ HVCALL
+ blr
+
+ENTRY(hv_cas)
+ mr r6,r5
+ mr r5,r4
+ mr r4,r3
+ lis r3,KVMPPC_H_CAS@h
+ ori r3,r3,KVMPPC_H_CAS@l
+ HVCALL
+ blr
+
+ .section ".bss"
+inbuf: .space 16
+inlen: .space 4
+inpos: .space 4
+ .text
diff --git a/src/roms/SLOF/lib/libhvcall/hvcall.code b/src/roms/SLOF/lib/libhvcall/hvcall.code
new file mode 100644
index 0000000..0ff50f2
--- /dev/null
+++ b/src/roms/SLOF/lib/libhvcall/hvcall.code
@@ -0,0 +1,131 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2011 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <libhvcall.h>
+
+// : hv-putchar ( hvtermno char -- )
+PRIM(hv_X2d_putchar)
+ char c = TOS.n; POP;
+ int hvtermno = TOS.n; POP;
+ hv_putchar(c, hvtermno);
+MIRP
+
+// : hv-getchar ( hvtermno -- char )
+PRIM(hv_X2d_getchar)
+ TOS.n = hv_getchar(TOS.n);
+MIRP
+
+// : hv-haschar ( hvtermno -- res )
+PRIM(hv_X2d_haschar)
+ TOS.n = hv_haschar(TOS.n);
+MIRP
+
+// : hv-reg-crq ( unit qaddr qsize -- res )
+PRIM(hv_X2d_reg_X2d_crq)
+ unsigned long qsize = TOS.u; POP;
+ unsigned long qaddr = TOS.u; POP;
+ unsigned int unit = TOS.u;
+ TOS.n = hv_reg_crq(unit, qaddr, qsize);
+MIRP
+
+// : hv-free-crq ( unit -- )
+PRIM(hv_X2d_free_X2d_crq)
+ unsigned int unit = TOS.u; POP;
+ hv_free_crq(unit);
+MIRP
+
+// : hv-send-crq ( unit msgaddr -- rc )
+PRIM(hv_X2d_send_X2d_crq)
+ uint64_t *msgaddr = (uint64_t *)TOS.u; POP;
+ unsigned int unit = TOS.u;
+ TOS.n = hv_send_crq(unit, msgaddr);
+MIRP
+
+// : hv-put-tce ( liobn ioba tce -- rc )
+PRIM(hv_X2d_put_X2d_tce)
+ uint64_t tce = TOS.u; POP;
+ uint64_t ioba = TOS.u; POP;
+ uint32_t liobn = TOS.u;
+ TOS.u = hv_generic(H_PUT_TCE, liobn, ioba, tce);
+MIRP
+
+PRIM(RB_X40)
+ unsigned long qaddr = TOS.u;
+ TOS.u = hv_logical_ci_load(1, qaddr);
+MIRP
+PRIM(RB_X21)
+ unsigned long qaddr = TOS.u; POP;
+ unsigned char val = TOS.u; POP;
+ hv_logical_ci_store(1, qaddr, val);
+MIRP
+PRIM(RW_X40)
+ unsigned long qaddr = TOS.u;
+ TOS.u = hv_logical_ci_load(2, qaddr);
+MIRP
+PRIM(RW_X21)
+ unsigned long qaddr = TOS.u; POP;
+ unsigned short val = TOS.u; POP;
+ hv_logical_ci_store(2, qaddr, val);
+MIRP
+PRIM(RL_X40)
+ unsigned long qaddr = TOS.u;
+ TOS.u = hv_logical_ci_load(4, qaddr);
+MIRP
+PRIM(RL_X21)
+ unsigned long qaddr = TOS.u; POP;
+ unsigned int val = TOS.u; POP;
+ hv_logical_ci_store(4, qaddr, val);
+MIRP
+PRIM(RX_X40)
+ unsigned long qaddr = TOS.u;
+ TOS.u = hv_logical_ci_load(8, qaddr);
+MIRP
+PRIM(RX_X21)
+ unsigned long qaddr = TOS.u; POP;
+ unsigned long val = TOS.u; POP;
+ hv_logical_ci_store(8, qaddr, val);
+MIRP
+
+PRIM(hv_X2d_logical_X2d_memop)
+ unsigned long op = TOS.u; POP;
+ unsigned long count = TOS.u; POP;
+ unsigned long esize = TOS.u; POP;
+ unsigned long src = TOS.u; POP;
+ unsigned long dst = TOS.u;
+ TOS.u = hv_logical_memop(dst, src, esize, count, op);
+MIRP
+
+PRIM(hv_X2d_cas)
+ unsigned long size = TOS.u; POP;
+ unsigned long buf = TOS.u; POP;
+ unsigned long vec = TOS.u;
+ TOS.u = hv_cas(vec, buf, size);
+MIRP
+
+PRIM(hv_X2d_rtas_X2d_update)
+ unsigned long rtas_entry = TOS.u; POP;
+ unsigned long rtas_base = TOS.u;
+ TOS.u = hv_generic(KVMPPC_H_RTAS_UPDATE, rtas_base, rtas_entry);
+MIRP
+
+PRIM(get_X2d_print_X2d_version)
+ unsigned long addr = TOS.u; POP;
+ get_print_banner(addr);
+MIRP
+
+PRIM(check_X2d_and_X2d_patch_X2d_sc1)
+ unsigned long end = TOS.u; POP;
+ unsigned long start = TOS.u; POP;
+ unsigned long patch_ins = TOS.u; POP;
+
+ patch_broken_sc1((void*)start, (void*)end, (void*)patch_ins);
+MIRP
diff --git a/src/roms/SLOF/lib/libhvcall/hvcall.in b/src/roms/SLOF/lib/libhvcall/hvcall.in
new file mode 100644
index 0000000..4437b77
--- /dev/null
+++ b/src/roms/SLOF/lib/libhvcall/hvcall.in
@@ -0,0 +1,34 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2011 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+cod(hv-putchar)
+cod(hv-getchar)
+cod(hv-haschar)
+cod(hv-reg-crq)
+cod(hv-free-crq)
+cod(hv-send-crq)
+cod(hv-put-tce)
+cod(check-and-patch-sc1)
+
+cod(RB@)
+cod(RB!)
+cod(RW@)
+cod(RW!)
+cod(RL@)
+cod(RL!)
+cod(RX@)
+cod(RX!)
+
+cod(hv-logical-memop)
+cod(hv-cas)
+cod(hv-rtas-update)
+cod(get-print-version)
diff --git a/src/roms/SLOF/lib/libhvcall/libhvcall.h b/src/roms/SLOF/lib/libhvcall/libhvcall.h
new file mode 100644
index 0000000..193b738
--- /dev/null
+++ b/src/roms/SLOF/lib/libhvcall/libhvcall.h
@@ -0,0 +1,107 @@
+#ifndef __LIBHVCALL_H__
+#define __LIBHVCALL_H__
+
+#define H_SUCCESS 0
+#define H_HARDWARE -1
+
+#define H_GET_TCE 0x1C
+#define H_PUT_TCE 0x20
+#define H_LOGICAL_CI_LOAD 0x3c
+#define H_LOGICAL_CI_STORE 0x40
+#define H_GET_TERM_CHAR 0x54
+#define H_PUT_TERM_CHAR 0x58
+#define H_REG_CRQ 0xFC
+#define H_FREE_CRQ 0x100
+#define H_SEND_CRQ 0x108
+#define H_REGISTER_LOGICAL_LAN 0x114
+#define H_FREE_LOGICAL_LAN 0x118
+#define H_ADD_LOGICAL_LAN_BUFFER 0x11C
+#define H_SEND_LOGICAL_LAN 0x120
+
+/* KVM specific ones */
+#define KVMPPC_HCALL_BASE 0xf000
+#define KVMPPC_H_RTAS (KVMPPC_HCALL_BASE + 0x0)
+#define KVMPPC_H_LOGICAL_MEMOP (KVMPPC_HCALL_BASE + 0x1)
+/* Client Architecture support */
+#define KVMPPC_H_CAS (KVMPPC_HCALL_BASE + 0x2)
+#define KVMPPC_H_RTAS_UPDATE (KVMPPC_HCALL_BASE + 0x3)
+#define KVMPPC_H_REPORT_MC_ERR (KVMPPC_HCALL_BASE + 0x4)
+#define KVMPPC_HCALL_MAX KVMPPC_H_NMI_MCE
+
+#ifndef __ASSEMBLY__
+
+extern long hv_generic(unsigned long opcode, ...);
+
+extern void hv_putchar(char c, int hvtermno);
+extern char hv_getchar(int hvtermno);
+extern char hv_haschar(int hvtermno);
+extern void get_print_banner(unsigned long addr);
+
+extern int hv_send_crq(unsigned int unit, uint64_t *msgaddr);
+
+static inline long hv_reg_crq(unsigned int unit, unsigned long qaddr,
+ unsigned long qsize)
+{
+ return hv_generic(H_REG_CRQ, unit, qaddr, qsize);
+}
+
+static inline void hv_free_crq(unsigned int unit)
+{
+ hv_generic(H_FREE_CRQ, unit);
+}
+
+extern long hv_send_logical_lan(unsigned long unit_address,
+ unsigned long desc1, unsigned long desc2,
+ unsigned long desc3, unsigned long desc4,
+ unsigned long desc5, unsigned long desc6);
+
+static inline long h_register_logical_lan(unsigned long unit_address,
+ unsigned long buf_list,
+ unsigned long rec_q,
+ unsigned long filter_list,
+ unsigned long mac_address)
+{
+ return hv_generic(H_REGISTER_LOGICAL_LAN, unit_address,
+ buf_list, rec_q, filter_list, mac_address);
+}
+
+static inline long h_free_logical_lan(unsigned long unit_address)
+{
+ return hv_generic(H_FREE_LOGICAL_LAN, unit_address);
+}
+
+static inline long h_add_logical_lan_buffer(unsigned long unit_address,
+ unsigned long buffer)
+{
+ return hv_generic(H_ADD_LOGICAL_LAN_BUFFER, unit_address, buffer);
+}
+
+#define HV_RTAS_MAX_ARGRET 5
+
+struct hv_rtas_call {
+ uint32_t token;
+ uint32_t nargs;
+ uint32_t nrets;
+ uint32_t argret[HV_RTAS_MAX_ARGRET];
+};
+
+static inline unsigned long h_rtas(struct hv_rtas_call *rtas_buf)
+{
+ return hv_generic(KVMPPC_H_RTAS, (unsigned long)rtas_buf);
+}
+
+extern unsigned long hv_logical_ci_load(unsigned long size, unsigned long addr);
+extern unsigned long hv_logical_ci_store(unsigned long size, unsigned long addr,
+ unsigned long value);
+
+extern unsigned long hv_logical_memop(unsigned long dst, unsigned long src,
+ unsigned long esize, unsigned long count,
+ unsigned long op);
+extern int patch_broken_sc1(void *start, void *end, uint32_t *test_ins);
+
+extern unsigned long hv_cas(unsigned long vec, unsigned long buf,
+ unsigned long size);
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* __LIBHVCALL_H__ */
diff --git a/src/roms/SLOF/lib/libipmi/Makefile b/src/roms/SLOF/lib/libipmi/Makefile
new file mode 100644
index 0000000..4777f9e
--- /dev/null
+++ b/src/roms/SLOF/lib/libipmi/Makefile
@@ -0,0 +1,28 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2007 IBM Corporation
+# * All rights reserved.
+# * This program and the accompanying materials
+# * are made available under the terms of the BSD License
+# * which accompanies this distribution, and is available at
+# * http://www.opensource.org/licenses/bsd-license.php
+# *
+# * Contributors:
+# * IBM Corporation - initial implementation
+# ****************************************************************************/
+
+TOPCMNDIR ?= ../..
+
+LIBIPMICMNDIR = $(shell pwd)
+
+include $(TOPCMNDIR)/make.rules
+
+TARGET = ../libipmi.a
+
+all: $(TARGET)
+
+$(TARGET):
+ cp libipmi.oco $@
+
+clean:
+
+distclean:
diff --git a/src/roms/SLOF/lib/libipmi/libipmi.code b/src/roms/SLOF/lib/libipmi/libipmi.code
new file mode 100644
index 0000000..59c1244
--- /dev/null
+++ b/src/roms/SLOF/lib/libipmi/libipmi.code
@@ -0,0 +1,120 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <libipmi.h>
+
+// : ipmi-kcs-cmd ( in-buf in-len out-buf out-maxlen -- out-len errorcode )
+PRIM(IPMI_X2d_KCS_X2d_CMD)
+ cell maxlen = TOS; POP;
+ cell outbuf = TOS; POP;
+ int len = TOS.n; POP;
+ cell inbuf = TOS;
+ int retval;
+ retval = ipmi_kcs_cmd(inbuf.a, outbuf.a, maxlen.n, (uint32_t *) &len);
+ TOS.n = len;
+ PUSH; TOS.n = retval;
+MIRP
+
+
+PRIM(IPMI_X2d_SYSTEM_X2d_REBOOT)
+ ipmi_system_reboot();
+MIRP
+
+
+PRIM(IPMI_X2d_POWER_X2d_OFF)
+ ipmi_power_off();
+MIRP
+
+
+// : ipmi-oem-stop-bootwatchdog ( -- errorcode )
+PRIM(IPMI_X2d_OEM_X2d_STOP_X2d_BOOTWATCHDOG)
+ PUSH;
+ TOS.n = ipmi_oem_stop_bootwatchdog();
+MIRP
+
+
+// : ipmi-oem-set-bootwatchdog ( seconds -- errorcode )
+PRIM(IPMI_X2d_OEM_X2d_SET_X2d_BOOTWATCHDOG)
+ int sec = TOS.n;
+ TOS.n = ipmi_oem_set_bootwatchdog(sec);
+MIRP
+
+
+// : ipmi-oem-reset-bootwatchdog ( -- errorcode )
+PRIM(IPMI_X2d_OEM_X2d_RESET_X2d_BOOTWATCHDOG)
+ PUSH;
+ TOS.n = ipmi_oem_reset_bootwatchdog();
+MIRP
+
+
+// : ipmi-oem-led-set ( type instance state -- errorcode )
+PRIM(IPMI_X2d_OEM_X2d_LED_X2d_SET)
+ int state = TOS.n; POP;
+ int instance = TOS.n; POP;
+ int type = TOS.n;
+ TOS.n = ipmi_oem_led_set(type, instance, state);
+MIRP
+
+
+// : ipmi-oem-read-vpd ( offset length dst -- status )
+PRIM(IPMI_X2d_OEM_X2d_READ_X2d_VPD)
+ cell dest = TOS; POP;
+ int len = TOS.n; POP;
+ int offset = TOS.n;
+ TOS.n = ipmi_oem_read_vpd(dest.a, len, offset);
+MIRP
+
+// : ipmi-oem-write-vpd ( offset length src -- status )
+PRIM(IPMI_X2d_OEM_X2d_WRITE_X2d_VPD)
+ cell src = TOS; POP;
+ int len = TOS.n; POP;
+ int offset = TOS.n;
+ TOS.n = ipmi_oem_write_vpd(src.a, len, offset);
+MIRP
+
+
+// : ipmi-oem-get-blade-descr ( buf maxlen -- len status )
+PRIM(IPMI_X2d_OEM_X2d_GET_X2d_BLADE_X2d_DESCR)
+ int maxlen = TOS.n; POP;
+ cell buf = TOS;
+ int len = 0;
+ int retval;
+ retval = ipmi_oem_get_blade_descr(buf.a, maxlen, (uint32_t *) &len);
+ TOS.n = len;
+ PUSH; TOS.n = retval;
+MIRP
+
+
+// : ipmi-oem-bios2sp ( str-ptr str-len swid type -- errorcode )
+PRIM(IPMI_X2d_OEM_X2d_BIOS2SP)
+ int type = TOS.n; POP;
+ int swid = TOS.n; POP;
+ int len = TOS.n; POP;
+ void* addr = TOS.a;
+ TOS.n = ipmi_oem_bios2sp(swid, type, addr, len);
+MIRP
+
+// : ipmi-set-sensor ( param-1 ... param-n n command sensor - errorcode )
+PRIM(IPMI_X2d_SET_X2d_SENSOR)
+ int sensor = TOS.n; POP;
+ int cmd = TOS.n; POP;
+ int n = TOS.n;
+ int i = n;
+ uint8_t param[10];
+ while (i>0) {
+ i--;
+ POP; param[i]=TOS.n;
+ };
+ TOS.n = ipmi_set_sensor((cmd<<8)+sensor,n,
+ param[0],param[1],param[2],param[3],param[4],
+ param[5],param[6],param[7],param[8],param[9]);
+MIRP
diff --git a/src/roms/SLOF/lib/libipmi/libipmi.h b/src/roms/SLOF/lib/libipmi/libipmi.h
new file mode 100644
index 0000000..9ac8308
--- /dev/null
+++ b/src/roms/SLOF/lib/libipmi/libipmi.h
@@ -0,0 +1,33 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#ifndef __LIBIPMI_H
+#define __LIBIPMI_H
+
+#include <stdint.h>
+
+extern int ipmi_kcs_cmd(uint8_t *, uint8_t *, uint32_t, uint32_t *);
+
+extern void ipmi_system_reboot(void);
+extern void ipmi_power_off(void);
+extern int ipmi_set_sensor(const int sensor, int number_of_args, ...);
+
+extern int ipmi_oem_stop_bootwatchdog(void);
+extern int ipmi_oem_set_bootwatchdog(uint16_t seconds);
+extern int ipmi_oem_reset_bootwatchdog(void);
+extern int ipmi_oem_led_set(int type, int instance, int state);
+extern uint32_t ipmi_oem_read_vpd(uint8_t *dst, uint32_t len, uint32_t offset);
+extern uint32_t ipmi_oem_write_vpd(uint8_t *src, uint32_t len, uint32_t offset);
+extern uint32_t ipmi_oem_get_blade_descr(uint8_t *dst, uint32_t maxlen, uint32_t *len);
+extern int ipmi_oem_bios2sp(int swid, int type, char *data, int len);
+
+#endif
diff --git a/src/roms/SLOF/lib/libipmi/libipmi.in b/src/roms/SLOF/lib/libipmi/libipmi.in
new file mode 100644
index 0000000..5b0e0ec
--- /dev/null
+++ b/src/roms/SLOF/lib/libipmi/libipmi.in
@@ -0,0 +1,24 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+cod(IPMI-KCS-CMD)
+cod(IPMI-SYSTEM-REBOOT)
+cod(IPMI-POWER-OFF)
+cod(IPMI-OEM-STOP-BOOTWATCHDOG)
+cod(IPMI-OEM-SET-BOOTWATCHDOG)
+cod(IPMI-OEM-RESET-BOOTWATCHDOG)
+cod(IPMI-OEM-LED-SET)
+cod(IPMI-OEM-READ-VPD)
+cod(IPMI-OEM-WRITE-VPD)
+cod(IPMI-OEM-GET-BLADE-DESCR)
+cod(IPMI-OEM-BIOS2SP)
+cod(IPMI-SET-SENSOR)
diff --git a/src/roms/SLOF/lib/libipmi/libipmi.oco b/src/roms/SLOF/lib/libipmi/libipmi.oco
new file mode 100644
index 0000000..74af724
--- /dev/null
+++ b/src/roms/SLOF/lib/libipmi/libipmi.oco
Binary files differ
diff --git a/src/roms/SLOF/lib/libnativeio/nativeio.code b/src/roms/SLOF/lib/libnativeio/nativeio.code
new file mode 100644
index 0000000..4887b11
--- /dev/null
+++ b/src/roms/SLOF/lib/libnativeio/nativeio.code
@@ -0,0 +1,25 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+/* There are 970 implementations. If we are ever to run native IOs
+ * on Power7 in hypervisor mode, these will have to change to use
+ * the new CI-load/store instructions
+ */
+PRIM(RB_X40) GET_CHAR1; SET_CI; GET_CHAR2; CLR_CI; GET_CHAR3; MIRP
+PRIM(RB_X21) PUT_CHAR1; SET_CI; PUT_CHAR2; CLR_CI; MIRP
+PRIM(RW_X40) GET_WORD1; SET_CI; GET_WORD2; CLR_CI; GET_WORD3; MIRP
+PRIM(RW_X21) PUT_WORD1; SET_CI; PUT_WORD2; CLR_CI; MIRP
+PRIM(RL_X40) GET_LONG1; SET_CI; GET_LONG2; CLR_CI; GET_LONG3; MIRP
+PRIM(RL_X21) PUT_LONG1; SET_CI; PUT_LONG2; CLR_CI; MIRP
+PRIM(RX_X40) GET_XONG1; SET_CI; GET_XONG2; CLR_CI; GET_XONG3; MIRP
+PRIM(RX_X21) PUT_XONG1; SET_CI; PUT_XONG2; CLR_CI; MIRP
+
diff --git a/src/roms/SLOF/lib/libnativeio/nativeio.in b/src/roms/SLOF/lib/libnativeio/nativeio.in
new file mode 100644
index 0000000..f5fb9d9
--- /dev/null
+++ b/src/roms/SLOF/lib/libnativeio/nativeio.in
@@ -0,0 +1,22 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+// I/O accesses.
+cod(RB@)
+cod(RB!)
+cod(RW@)
+cod(RW!)
+cod(RL@)
+cod(RL!)
+cod(RX@)
+cod(RX!)
+
diff --git a/src/roms/SLOF/lib/libnvram/Makefile b/src/roms/SLOF/lib/libnvram/Makefile
new file mode 100644
index 0000000..d4e9a61
--- /dev/null
+++ b/src/roms/SLOF/lib/libnvram/Makefile
@@ -0,0 +1,53 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2008 IBM Corporation
+# * All rights reserved.
+# * This program and the accompanying materials
+# * are made available under the terms of the BSD License
+# * which accompanies this distribution, and is available at
+# * http://www.opensource.org/licenses/bsd-license.php
+# *
+# * Contributors:
+# * IBM Corporation - initial implementation
+# ****************************************************************************/
+
+SRCS = nvram.c envvar.c
+
+TOPCMNDIR ?= ../..
+
+include $(TOPCMNDIR)/make.rules
+
+ASFLAGS = $(FLAG) $(RELEASE) $(CPUARCHDEF) -Wa,-mregnames
+CPPFLAGS = -I../libc/include $(CPUARCHDEF) $(FLAG) \
+ -I$(INCLBRDDIR) -I$(INCLCMNDIR)/$(CPUARCH) -I. -I../../include
+LDFLAGS = -nostdlib
+
+TARGET = ../libnvram.a
+
+all: $(TARGET)
+
+OBJS = $(SRCS:%.c=%.o)
+
+$(TARGET): $(OBJS)
+ $(AR) -rc $@ $(OBJS)
+ $(RANLIB) $@
+
+
+clean:
+ $(RM) $(TARGET) $(OBJS)
+
+distclean: clean
+ $(RM) Makefile.dep
+
+
+# Rules for creating the dependency file:
+depend:
+ $(RM) Makefile.dep
+ $(MAKE) Makefile.dep
+
+Makefile.dep: Makefile
+ $(CC) -MM $(CPPFLAGS) $(CFLAGS) $(SRCS) > Makefile.dep
+
+
+# Include dependency file if available:
+-include Makefile.dep
+
diff --git a/src/roms/SLOF/lib/libnvram/envvar.c b/src/roms/SLOF/lib/libnvram/envvar.c
new file mode 100644
index 0000000..87aaf27
--- /dev/null
+++ b/src/roms/SLOF/lib/libnvram/envvar.c
@@ -0,0 +1,243 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <stdint.h>
+#include "../libc/include/stdio.h"
+#include "../libc/include/string.h"
+#include "../libc/include/stdlib.h"
+#include "nvram.h"
+
+/* returns the offset of the first byte after the searched envvar */
+static int get_past_env_pos(partition_t part, char *envvar)
+{
+ int offset, len;
+ static char temp[256];
+ uint8_t data;
+
+ offset=part.addr;
+
+ memset(temp, 0, 256);
+
+ do {
+ len=0;
+ while((data=nvram_read_byte(offset++)) && len < 256) {
+ temp[len++]=data;
+ }
+ if (!strncmp(envvar, temp, strlen(envvar))) {
+ return offset;
+ }
+ } while (len);
+
+ return -1;
+}
+
+/**
+ * @param partition name of the envvar partition
+ * @param envvar name of the environment variable
+ * @return pointer to temporary string containing the value of envvar
+ */
+
+char *get_env(partition_t part, char *envvar)
+{
+ static char temp[256+1];
+ int len, offset;
+ uint8_t data;
+
+ DEBUG("get_env %s... ", envvar);
+ if(!part.addr) {
+ /* ERROR: No environment variable partition */
+ DEBUG("invalid partition.\n");
+ return NULL;
+ }
+
+ offset=part.addr;
+
+ do {
+ len=0;
+ while((data=nvram_read_byte(offset++)) && len < 256) {
+ temp[len++]=data;
+ }
+ temp[len]=0;
+
+ if (!strncmp(envvar, temp, strlen(envvar))) {
+ int pos=0;
+ while (temp[pos]!='=' && pos < len) pos++;
+ // DEBUG("value='%s'\n", temp+pos+1);
+ return temp+pos+1;
+ }
+ } while (len);
+
+ DEBUG("not found\n");
+ return NULL;
+}
+
+static int find_last_envvar(partition_t part)
+{
+ uint8_t last, current;
+ int offset;
+
+ offset=part.addr;
+
+ last=nvram_read_byte(part.addr);
+
+ for (offset=part.addr; offset<(int)(part.addr+part.len); offset++) {
+ current=nvram_read_byte(offset);
+ if(!last && !current)
+ return offset;
+
+ last=current;
+ }
+
+ return -1;
+}
+
+int add_env(partition_t part, char *envvar, char *value)
+{
+ int freespace, last, len, offset;
+ unsigned int i;
+
+ /* Find offset where we can write */
+ last = find_last_envvar(part);
+
+ /* How much space do we have left? */
+ freespace = part.addr+part.len-last;
+
+ /* how long is the entry we want to write? */
+ len = strlen(envvar) + strlen(value) + 2;
+
+ if(freespace<len) {
+ // TODO try to increase partition size
+ return -1;
+ }
+
+ offset=last;
+
+ for(i=0; i<strlen(envvar); i++)
+ nvram_write_byte(offset++, envvar[i]);
+
+ nvram_write_byte(offset++, '=');
+
+ for(i=0; i<strlen(value); i++)
+ nvram_write_byte(offset++, value[i]);
+
+ return 0;
+}
+
+int del_env(partition_t part, char *envvar)
+{
+ int last, current, pos, i;
+ char *buffer;
+
+ if(!part.addr)
+ return -1;
+
+ last=find_last_envvar(part);
+ current = pos = get_past_env_pos(part, envvar);
+
+ // TODO is this really required?
+ /* go back to non-0 value */
+ current--;
+
+ while (nvram_read_byte(current))
+ current--;
+
+ // TODO is this required?
+ current++;
+
+ buffer=get_nvram_buffer(last-pos);
+
+ for (i=0; i<last-pos; i++)
+ buffer[i]=nvram_read_byte(i+pos);
+
+ for (i=0; i<last-pos; i++)
+ nvram_write_byte(i+current, buffer[i]);
+
+ free_nvram_buffer(buffer);
+
+ erase_nvram(last, current+last-pos);
+
+ return 0;
+}
+
+int set_env(partition_t part, char *envvar, char *value)
+{
+ char *oldvalue, *buffer;
+ int last, current, buffersize, i;
+
+ DEBUG("set_env %lx[%lx]: %s=%s\n", part.addr, part.len, envvar, value);
+
+ if(!part.addr)
+ return -1;
+
+ /* Check whether the environment variable exists already */
+ oldvalue = get_env(part, envvar);
+
+ if(oldvalue==NULL)
+ return add_env(part, envvar, value);
+
+
+ /* The value did not change. So we succeeded! */
+ if(!strncmp(oldvalue, value, strlen(value)+1))
+ return 0;
+
+ /* we need to overwrite environment variables, back them up first */
+
+ // DEBUG("overwriting existing environment variable\n");
+
+ /* allocate a buffer */
+ last=find_last_envvar(part);
+ current=get_past_env_pos(part, envvar);
+ buffersize = last - current;
+ buffer=get_nvram_buffer(buffersize);
+ if(!buffer)
+ return -1;
+
+ for (i=0; i<buffersize; i++) {
+ buffer[i] = nvram_read_byte(current+i);
+ }
+
+ /* walk back until the = */
+ while (nvram_read_byte(current)!='=') {
+ current--;
+ }
+
+ /* Start at envvar= */
+ current++;
+
+ /* Write the new value */
+ for(i=0; i<(int)strlen(value); i++) {
+ nvram_write_byte(current++, value[i]);
+ }
+
+ /* Write end of string marker */
+ nvram_write_byte(current++, 0);
+
+ /* Copy back the buffer */
+ for (i=0; i<buffersize; i++) {
+ nvram_write_byte(current++, buffer[i]);
+ }
+
+ free_nvram_buffer(buffer);
+
+ /* If the new environment variable content is shorter than the old one,
+ * we need to erase the rest of the bytes
+ */
+
+ if (current<last) {
+ for(i=current; i<last; i++) {
+ nvram_write_byte(i, 0);
+ }
+ }
+
+ return 0; /* success */
+}
+
diff --git a/src/roms/SLOF/lib/libnvram/libnvram.code b/src/roms/SLOF/lib/libnvram/libnvram.code
new file mode 100644
index 0000000..723941d
--- /dev/null
+++ b/src/roms/SLOF/lib/libnvram/libnvram.code
@@ -0,0 +1,287 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+#include <nvram.h>
+
+#define STRING_INIT(str) \
+ char str[255]; \
+ char * str##_address; \
+ int str##_length;
+
+#define STRING_FROM_STACK(str) \
+ str##_length = TOS.u; POP; \
+ str##_address = TOS.a; POP; \
+ memcpy(str, str##_address, str##_length); \
+ memset(str + str##_length, 0, 255 - str##_length);
+
+PRIM(nvram_X2d_c_X40)
+ unsigned int offset = TOS.u;
+ TOS.u=nvram_read_byte(offset);
+MIRP
+
+PRIM(nvram_X2d_w_X40)
+ unsigned int offset = TOS.u;
+ TOS.u=nvram_read_word(offset);
+MIRP
+
+PRIM(nvram_X2d_l_X40)
+ unsigned int offset = TOS.u;
+ TOS.u=nvram_read_dword(offset);
+MIRP
+
+PRIM(nvram_X2d_x_X40)
+ unsigned int offset = TOS.u;
+ TOS.u=nvram_read_qword(offset);
+MIRP
+
+PRIM(nvram_X2d_c_X21)
+ nvram_write_byte(TOS.u, NOS.u);
+ POP; POP;
+MIRP
+
+PRIM(nvram_X2d_w_X21)
+ nvram_write_word(TOS.u, NOS.u);
+ POP; POP;
+MIRP
+
+PRIM(nvram_X2d_l_X21)
+ nvram_write_dword(TOS.u, NOS.u);
+ POP; POP;
+MIRP
+
+PRIM(nvram_X2d_x_X21)
+ nvram_write_qword(TOS.u, NOS.u);
+ POP; POP;
+MIRP
+
+/* get-nvram-partition ( type -- addr len FAILED? ) */
+PRIM(get_X2d_nvram_X2d_partition)
+ partition_t partition;
+ unsigned int ptype = TOS.u;
+ partition = get_partition(ptype, NULL);
+ if(partition.len && partition.len != -1) {
+ TOS.u = partition.addr;
+ PUSH;
+ TOS.u = partition.len;
+ PUSH;
+ TOS.u = 0; // FALSE
+ } else {
+ TOS.u = -1; // TRUE
+ }
+MIRP
+
+/* get-named-nvram-partition ( name.addr name.len -- addr len FAILED? ) */
+PRIM(get_X2d_named_X2d_nvram_X2d_partition)
+ STRING_INIT(name)
+ partition_t partition;
+
+ STRING_FROM_STACK(name)
+ partition = get_partition(-1, name);
+
+ if(partition.len && partition.len != -1) {
+ PUSH;
+ TOS.u = partition.addr;
+ PUSH;
+ TOS.u = partition.len;
+ PUSH;
+ TOS.u = 0; // FALSE
+ } else {
+ PUSH;
+ TOS.u = -1; // TRUE
+ }
+MIRP
+
+
+
+/* new-nvram-partition ( type name.addr name.len len -- part.offs part.len FALSE | TRUE) */
+PRIM(new_X2d_nvram_X2d_partition)
+ int type, len, i, slen;
+ char name[12], *addr;
+ partition_t partition;
+
+ len = TOS.u; POP;
+ slen = TOS.u; POP;
+ addr = (char *)TOS.u; POP;
+ type = TOS.u; POP;
+
+ for (i=0; i<12; i++) {
+ if(slen>i)
+ name[i]=addr[i];
+ else
+ name[i]=0;
+ }
+
+ partition=new_nvram_partition(type, name, len);
+
+ if(!partition.len) {
+ PUSH; TOS.u = -1; // TRUE
+ } else {
+ PUSH; TOS.u = partition.addr;
+ PUSH; TOS.u = partition.len;
+ PUSH; TOS.u = 0; // FALSE
+ }
+MIRP
+
+/* inrease-nvram-partition ( part.offs part.len new-len -- FALSE | TRUE ) */
+PRIM(increase_X2d_nvram_X2d_partition)
+ int len, ret;
+ partition_t partition;
+
+ // FIXME
+ partition.addr = TOS.u; POP;
+ partition.len = TOS.u; POP;
+ len = TOS.u; POP;
+
+ ret=increase_nvram_partition_size(partition, len);
+
+ PUSH;
+
+ if(!ret)
+ TOS.u=-1; // TRUE
+ else
+ TOS.u=0; // FALSE
+
+MIRP
+
+PRIM(internal_X2d_reset_X2d_nvram)
+ reset_nvram();
+MIRP
+
+PRIM(wipe_X2d_nvram)
+ wipe_nvram();
+MIRP
+
+PRIM(nvram_X2d_debug)
+ nvram_debug();
+MIRP
+
+// ( part.start part.len name.addr name.len -- var.addr var.len TRUE | false )
+PRIM(internal_X2d_get_X2d_env)
+ STRING_INIT(name)
+ partition_t part;
+ char *val;
+
+ STRING_FROM_STACK(name)
+ part.len = TOS.u; POP;
+ part.addr = TOS.u; POP;
+
+ val=get_env(part, name);
+ if(val) {
+ PUSH; TOS.a = val;
+ PUSH; TOS.u = strlen(val);
+ PUSH; TOS.u = -1; // TRUE
+ } else {
+ PUSH; TOS.u = 0; // FALSE
+ }
+MIRP
+
+// ( part.start part.len name.addr name.len val.addr val.len -- FALSE|TRUE)
+PRIM(internal_X2d_add_X2d_env)
+ STRING_INIT(name)
+ STRING_INIT(value)
+ partition_t part;
+ int ret;
+
+ STRING_FROM_STACK(value)
+ STRING_FROM_STACK(name)
+ part.len = TOS.u; POP;
+ part.addr = TOS.u; POP;
+
+ ret=add_env(part, name, value);
+ if(ret) {
+ PUSH; TOS.u = -1; // TRUE
+ } else {
+ PUSH; TOS.u = 0; // FALSE
+ }
+MIRP
+
+// ( part.addr part.len name.addr name.len -- FALSE|TRUE)
+PRIM(internal_X2d_del_X2d_env)
+ STRING_INIT(name)
+ partition_t part;
+ int ret;
+
+ STRING_FROM_STACK(name);
+ part.len = TOS.u; POP;
+ part.addr = TOS.u; POP;
+
+ ret=del_env(part, name);
+ if(ret) {
+ PUSH; TOS.u = -1; // TRUE
+ } else {
+ PUSH; TOS.u = 0; // FALSE
+ }
+
+MIRP
+
+// internal-set-env ( part.addr part.len name.addr name.len val.addr val.len -- FALSE|TRUE)
+PRIM(internal_X2d_set_X2d_env)
+ STRING_INIT(name)
+ STRING_INIT(value)
+ partition_t part;
+ int ret;
+
+ STRING_FROM_STACK(value)
+ STRING_FROM_STACK(name)
+ part.len = TOS.u; POP;
+ part.addr = TOS.u; POP;
+
+ ret=set_env(part, name, value);
+ if(ret) {
+ PUSH; TOS.u = -1; // TRUE
+ } else {
+ PUSH; TOS.u = 0; // FALSE
+ }
+MIRP
+
+// ( part.addr part.len -- FALSE|TRUE)
+PRIM(erase_X2d_nvram_X2d_partition)
+ partition_t part;
+ int ret;
+
+ part.len = TOS.u; POP;
+ part.addr = TOS.u; POP;
+
+ ret=clear_nvram_partition(part);
+ if(ret) {
+ PUSH; TOS.u = -1; // TRUE
+ } else {
+ PUSH; TOS.u = 0; // FALSE
+ }
+
+MIRP
+
+// ( part.addr part.len -- FALSE|TRUE)
+PRIM(delete_X2d_nvram_X2d_partition)
+ partition_t part;
+ int ret;
+
+ part.len = TOS.u; POP;
+ part.addr = TOS.u; POP;
+
+ ret=delete_nvram_partition(part);
+ if(ret) {
+ PUSH; TOS.u = -1; // TRUE
+ } else {
+ PUSH; TOS.u = 0; // FALSE
+ }
+
+MIRP
+
+// ( fetch_token store_token size nvram-addr -- )
+PRIM(internal_X2d_nvram_X2d_init)
+ void *nvram_addr = TOS.a; POP;
+ uint32_t nvram_size = TOS.u; POP;
+ uint32_t store_token = TOS.u; POP;
+ long fetch_token = TOS.u; POP;
+
+ nvram_init(fetch_token, store_token, nvram_size, nvram_addr);
+MIRP
diff --git a/src/roms/SLOF/lib/libnvram/libnvram.in b/src/roms/SLOF/lib/libnvram/libnvram.in
new file mode 100644
index 0000000..bbb20a8
--- /dev/null
+++ b/src/roms/SLOF/lib/libnvram/libnvram.in
@@ -0,0 +1,42 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+/* NVRAM access primitives */
+cod(nvram-c@)
+cod(nvram-c!)
+cod(nvram-w@)
+cod(nvram-w!)
+cod(nvram-l@)
+cod(nvram-l!)
+cod(nvram-x@)
+cod(nvram-x!)
+
+/* Generic NVRAM helpers */
+cod(internal-reset-nvram)
+cod(nvram-debug)
+cod(wipe-nvram)
+
+/* NVRAM Partition Handling */
+cod(get-nvram-partition)
+cod(get-named-nvram-partition)
+cod(new-nvram-partition)
+cod(increase-nvram-partition)
+cod(erase-nvram-partition)
+cod(delete-nvram-partition)
+
+/* NVRAM environment access words */
+cod(internal-get-env)
+cod(internal-add-env)
+cod(internal-del-env)
+cod(internal-set-env)
+
+cod(internal-nvram-init)
diff --git a/src/roms/SLOF/lib/libnvram/nvram.c b/src/roms/SLOF/lib/libnvram/nvram.c
new file mode 100644
index 0000000..5c11376
--- /dev/null
+++ b/src/roms/SLOF/lib/libnvram/nvram.c
@@ -0,0 +1,623 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include "cache.h"
+#include "nvram.h"
+#include "../libhvcall/libhvcall.h"
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <southbridge.h>
+#include <nvramlog.h>
+#include <byteorder.h>
+
+#ifdef RTAS_NVRAM
+static uint32_t fetch_token;
+static uint32_t store_token;
+static uint32_t NVRAM_LENGTH;
+static char *nvram_buffer; /* use buffer allocated by SLOF code */
+#else
+#ifndef NVRAM_LENGTH
+#define NVRAM_LENGTH 0x10000
+#endif
+/*
+ * This is extremely ugly, but still better than implementing
+ * another sbrk() around it.
+ */
+static char nvram_buffer[NVRAM_LENGTH];
+#endif
+
+static uint8_t nvram_buffer_locked=0x00;
+
+void nvram_init(uint32_t _fetch_token, uint32_t _store_token,
+ long _nvram_length, void* nvram_addr)
+{
+#ifdef RTAS_NVRAM
+ fetch_token = _fetch_token;
+ store_token = _store_token;
+ NVRAM_LENGTH = _nvram_length;
+ nvram_buffer = nvram_addr;
+
+ DEBUG("\nNVRAM: size=%d, fetch=%x, store=%x\n",
+ NVRAM_LENGTH, fetch_token, store_token);
+#endif
+}
+
+
+void asm_cout(long Character,long UART,long NVRAM);
+
+#if defined(DISABLE_NVRAM)
+
+static volatile uint8_t nvram[NVRAM_LENGTH]; /* FAKE */
+
+#define nvram_access(type,size,name) \
+ type nvram_read_##name(unsigned int offset) \
+ { \
+ type *pos; \
+ if (offset > (NVRAM_LENGTH - sizeof(type))) \
+ return 0; \
+ pos = (type *)(nvram+offset); \
+ return *pos; \
+ } \
+ void nvram_write_##name(unsigned int offset, type data) \
+ { \
+ type *pos; \
+ if (offset > (NVRAM_LENGTH - sizeof(type))) \
+ return; \
+ pos = (type *)(nvram+offset); \
+ *pos = data; \
+ }
+
+#elif defined(RTAS_NVRAM)
+
+static inline void nvram_fetch(unsigned int offset, void *buf, unsigned int len)
+{
+ struct hv_rtas_call rtas = {
+ .token = fetch_token,
+ .nargs = 3,
+ .nrets = 2,
+ .argret = { offset, (uint32_t)(unsigned long)buf, len },
+ };
+ h_rtas(&rtas);
+}
+
+static inline void nvram_store(unsigned int offset, void *buf, unsigned int len)
+{
+ struct hv_rtas_call rtas = {
+ .token = store_token,
+ .nargs = 3,
+ .nrets = 2,
+ .argret = { offset, (uint32_t)(unsigned long)buf, len },
+ };
+ h_rtas(&rtas);
+}
+
+#define nvram_access(type,size,name) \
+ type nvram_read_##name(unsigned int offset) \
+ { \
+ type val; \
+ if (offset > (NVRAM_LENGTH - sizeof(type))) \
+ return 0; \
+ nvram_fetch(offset, &val, size / 8); \
+ return val; \
+ } \
+ void nvram_write_##name(unsigned int offset, type data) \
+ { \
+ if (offset > (NVRAM_LENGTH - sizeof(type))) \
+ return; \
+ nvram_store(offset, &data, size / 8); \
+ }
+
+#else /* DISABLE_NVRAM */
+
+static volatile uint8_t *nvram = (volatile uint8_t *)SB_NVRAM_adr;
+
+#define nvram_access(type,size,name) \
+ type nvram_read_##name(unsigned int offset) \
+ { \
+ type *pos; \
+ if (offset > (NVRAM_LENGTH - sizeof(type))) \
+ return 0; \
+ pos = (type *)(nvram+offset); \
+ return ci_read_##size(pos); \
+ } \
+ void nvram_write_##name(unsigned int offset, type data) \
+ { \
+ type *pos; \
+ if (offset > (NVRAM_LENGTH - sizeof(type))) \
+ return; \
+ pos = (type *)(nvram+offset); \
+ ci_write_##size(pos, data); \
+ }
+
+#endif
+
+/*
+ * producer for nvram access functions. Since these functions are
+ * basically all the same except for the used data types, produce
+ * them via the nvram_access macro to keep the code from bloating.
+ */
+
+nvram_access(uint8_t, 8, byte)
+nvram_access(uint16_t, 16, word)
+nvram_access(uint32_t, 32, dword)
+nvram_access(uint64_t, 64, qword)
+
+
+
+/**
+ * This function is a minimal abstraction for our temporary
+ * buffer. It should have been malloced, but since there is no
+ * usable malloc, we go this route.
+ *
+ * @return pointer to temporary buffer
+ */
+
+char *get_nvram_buffer(int len)
+{
+ if(len>NVRAM_LENGTH)
+ return NULL;
+
+ if(nvram_buffer_locked)
+ return NULL;
+
+ nvram_buffer_locked = 0xff;
+
+ return nvram_buffer;
+}
+
+/**
+ * @param buffer pointer to the allocated buffer. This
+ * is unused, but nice in case we ever get a real malloc
+ */
+
+void free_nvram_buffer(char *buffer __attribute__((unused)))
+{
+ nvram_buffer_locked = 0x00;
+}
+
+/**
+ * @param fmt format string, like in printf
+ * @param ... variable number of arguments
+ */
+
+int nvramlog_printf(const char* fmt, ...)
+{
+ char buff[256];
+ int count, i;
+ va_list ap;
+
+ va_start(ap, fmt);
+ count = vsprintf(buff, fmt, ap);
+ va_end(ap);
+
+ for (i=0; i<count; i++)
+ asm_cout(buff[i], 0, 1);
+
+ return count;
+}
+
+/**
+ * @param offset start offset of the partition header
+ */
+
+static uint8_t get_partition_type(int offset)
+{
+ return nvram_read_byte(offset);
+}
+
+/**
+ * @param offset start offset of the partition header
+ */
+
+static uint8_t get_partition_header_checksum(int offset)
+{
+ return nvram_read_byte(offset+1);
+}
+
+/**
+ * @param offset start offset of the partition header
+ */
+
+static uint16_t get_partition_len(int offset)
+{
+ return nvram_read_word(offset+2);
+}
+
+/**
+ * @param offset start offset of the partition header
+ * @return static char array containing the partition name
+ *
+ * NOTE: If the partition name needs to be non-temporary, strdup
+ * and use the copy instead.
+ */
+
+static char * get_partition_name(int offset)
+{
+ static char name[12];
+ int i;
+ for (i=0; i<12; i++)
+ name[i]=nvram_read_byte(offset+4+i);
+
+ DEBUG("name: \"%s\"\n", name);
+ return name;
+}
+
+static uint8_t calc_partition_header_checksum(int offset)
+{
+ uint16_t plainsum;
+ uint8_t checksum;
+ int i;
+
+ plainsum = nvram_read_byte(offset);
+
+ for (i=2; i<PARTITION_HEADER_SIZE; i++)
+ plainsum+=nvram_read_byte(offset+i);
+
+ checksum=(plainsum>>8)+(plainsum&0xff);
+
+ return checksum;
+}
+
+static int calc_used_nvram_space(void)
+{
+ int walk, len;
+
+ for (walk=0; walk<NVRAM_LENGTH;) {
+ if(nvram_read_byte(walk) == 0
+ || get_partition_header_checksum(walk) !=
+ calc_partition_header_checksum(walk)) {
+ /* If there's no valid entry, bail out */
+ break;
+ }
+
+ len=get_partition_len(walk);
+ DEBUG("... part len=%x, %x\n", len, len*16);
+
+ if(!len) {
+ /* If there's a partition type but no len, bail out.
+ * Don't bail out if type is 0. This can be used to
+ * find the offset of the first free byte.
+ */
+ break;
+ }
+
+ walk += len * 16;
+ }
+ DEBUG("used nvram space: %d\n", walk);
+
+ return walk;
+}
+
+/**
+ *
+ * @param type partition type. Set this to the partition type you are looking
+ * for. If there are several partitions with the same type, only
+ * the first partition with that type will be found.
+ * Set to -1 to ignore. Set to 0 to find free unpartitioned space.
+ *
+ * @param name partition name. Set this to the name of the partition you are
+ * looking for. If there are several partitions with the same name,
+ * only the first partition with that name will be found.
+ * Set to NULL to ignore.
+ *
+ * To disambiguate the partitions you should have a unique name if you plan to
+ * have several partitions of the same type.
+ *
+ */
+
+partition_t get_partition(unsigned int type, char *name)
+{
+ partition_t ret={0,-1};
+ int walk, len;
+
+ DEBUG("get_partition(%i, '%s')\n", type, name);
+
+ for (walk=0; walk<NVRAM_LENGTH;) {
+ // DEBUG("get_partition: walk=%x\n", walk);
+ if(get_partition_header_checksum(walk) !=
+ calc_partition_header_checksum(walk)) {
+ /* If there's no valid entry, bail out */
+ break;
+ }
+
+ len=get_partition_len(walk);
+ if(type && !len) {
+ /* If there's a partition type but no len, bail out.
+ * Don't bail out if type is 0. This can be used to
+ * find the offset of the first free byte.
+ */
+ break;
+ }
+
+ /* Check if either type or name or both do not match. */
+ if ( (type!=(unsigned int)-1 && type != get_partition_type(walk)) ||
+ (name && strncmp(get_partition_name(walk), name, 12)) ) {
+ /* We hit another partition. Continue
+ * at the end of this partition
+ */
+ walk += len*16;
+ continue;
+ }
+
+ ret.addr=walk+PARTITION_HEADER_SIZE;
+ ret.len=(len*16)-PARTITION_HEADER_SIZE;
+ break;
+ }
+
+ return ret;
+}
+
+void erase_nvram(int offset, int len)
+{
+ int i;
+
+ for (i=offset; i<offset+len; i++)
+ nvram_write_byte(i, 0);
+}
+
+void wipe_nvram(void)
+{
+ erase_nvram(0, NVRAM_LENGTH);
+}
+
+/**
+ * @param partition partition structure pointing to the partition to wipe.
+ * @param header_only if header_only is != 0 only the partition header is
+ * nulled out, not the whole partition.
+ */
+
+int wipe_partition(partition_t partition, int header_only)
+{
+ int pstart, len;
+
+ pstart=partition.addr-PARTITION_HEADER_SIZE;
+
+ len=PARTITION_HEADER_SIZE;
+
+ if(!header_only)
+ len += partition.len;
+
+ erase_nvram(pstart, len);
+
+ return 0;
+}
+
+
+static partition_t create_nvram_partition(int type, const char *name, int len)
+{
+ partition_t ret = { 0, 0 };
+ int offset, plen;
+ unsigned int i;
+
+ plen = ALIGN(len+PARTITION_HEADER_SIZE, 16);
+
+ DEBUG("Creating partition type=%x, name=%s, len=%d plen=%d\n",
+ type, name, len, plen);
+
+ offset = calc_used_nvram_space();
+
+ if (NVRAM_LENGTH-(calc_used_nvram_space())<plen) {
+ DEBUG("Not enough free space.\n");
+ return ret;
+ }
+
+ DEBUG("Writing header.");
+
+ nvram_write_byte(offset, type);
+ nvram_write_word(offset+2, plen/16);
+
+ for (i=0; i<strlen(name); i++)
+ nvram_write_byte(offset+4+i, name[i]);
+
+ nvram_write_byte(offset+1, calc_partition_header_checksum(offset));
+
+ ret.addr = offset+PARTITION_HEADER_SIZE;
+ ret.len = len;
+
+ DEBUG("partition created: addr=%lx len=%lx\n", ret.addr, ret.len);
+
+ return ret;
+}
+
+static int create_free_partition(void)
+{
+ int free_space;
+ partition_t free_part;
+
+ free_space = NVRAM_LENGTH - calc_used_nvram_space() - PARTITION_HEADER_SIZE;
+ free_part = create_nvram_partition(0x7f, "free space", free_space);
+
+ return (free_part.addr != 0);
+}
+
+partition_t new_nvram_partition(int type, char *name, int len)
+{
+ partition_t free_part, new_part = { 0, 0 };
+
+ /* NOTE: Assume all free space is consumed by the "free space"
+ * partition. This means a partition can not be increased in the middle
+ * of reset_nvram, which is obviously not a big loss.
+ */
+
+ free_part=get_partition(0x7f, NULL);
+ if( free_part.len && free_part.len != -1)
+ wipe_partition(free_part, 1);
+
+ new_part = create_nvram_partition(type, name, len);
+
+ if(new_part.len != len) {
+ new_part.len = 0;
+ new_part.addr = 0;
+ }
+
+ create_free_partition();
+
+ return new_part;
+}
+
+/**
+ * @param partition partition structure pointing to the partition to wipe.
+ */
+
+int delete_nvram_partition(partition_t partition)
+{
+ int i;
+ partition_t free_part;
+
+ if(!partition.len || partition.len == -1)
+ return 0;
+
+ for (i=partition.addr+partition.len; i< NVRAM_LENGTH; i++)
+ nvram_write_byte(i - partition.len - PARTITION_HEADER_SIZE, nvram_read_byte(i));
+
+ erase_nvram(NVRAM_LENGTH-partition.len-PARTITION_HEADER_SIZE,
+ partition.len-PARTITION_HEADER_SIZE);
+
+ free_part=get_partition(0x7f, NULL);
+ wipe_partition(free_part, 0);
+ create_free_partition();
+
+ return 1;
+}
+
+int clear_nvram_partition(partition_t part)
+{
+ if(!part.addr)
+ return 0;
+
+ erase_nvram(part.addr, part.len);
+
+ return 1;
+}
+
+
+int increase_nvram_partition_size(partition_t partition, int newsize)
+{
+ partition_t free_part;
+ int free_offset, end_offset, i;
+
+ /* We don't support shrinking partitions (yet) */
+ if (newsize < partition.len) {
+ return 0;
+ }
+
+ /* NOTE: Assume all free space is consumed by the "free space"
+ * partition. This means a partition can not be increased in the middle
+ * of reset_nvram, which is obviously not a big loss.
+ */
+
+ free_part=get_partition(0x7f, NULL);
+
+ // FIXME: It could be 16 byte more. Also handle empty "free" partition.
+ if (free_part.len == -1 || free_part.len < newsize - partition.len ) {
+ return 0;
+ }
+
+ free_offset=free_part.addr - PARTITION_HEADER_SIZE; // first unused byte
+ end_offset=partition.addr + partition.len; // last used byte of partition + 1
+
+ if(free_offset > end_offset) {
+ int j, bufferlen;
+ char *overlap_buffer;
+
+ bufferlen=free_offset - end_offset;
+
+ overlap_buffer=get_nvram_buffer(bufferlen);
+ if(!overlap_buffer) {
+ return 0;
+ }
+
+ for (i=end_offset, j=0; i<free_offset; i++, j++)
+ overlap_buffer[j]=nvram_read_byte(i);
+
+ /* Only wipe the header. The free space partition is empty per
+ * definition
+ */
+
+ wipe_partition(free_part, 1);
+
+ for (i=partition.addr+newsize, j=0; i<(int)(partition.addr+newsize+bufferlen); i++, j++)
+ nvram_write_byte(i, overlap_buffer[j]);
+
+ free_nvram_buffer(overlap_buffer);
+ } else {
+ /* Only wipe the header. */
+ wipe_partition(free_part, 1);
+ }
+
+ /* Clear the new partition space */
+ erase_nvram(partition.addr+partition.len, newsize-partition.len);
+
+ nvram_write_word(partition.addr - 16 + 2, newsize);
+
+ create_free_partition();
+
+ return 1;
+}
+
+static void init_cpulog_partition(partition_t cpulog)
+{
+ unsigned int offset=cpulog.addr;
+
+ /* see board-xxx/include/nvramlog.h for information */
+ nvram_write_word(offset+0, 0x40); // offset
+ nvram_write_word(offset+2, 0x00); // flags
+ nvram_write_dword(offset+4, 0x01); // pointer
+
+}
+
+void reset_nvram(void)
+{
+ partition_t cpulog0, cpulog1;
+ struct {
+ uint32_t prefix;
+ uint64_t name;
+ } __attribute__((packed)) header;
+
+ DEBUG("Erasing NVRAM\n");
+ erase_nvram(0, NVRAM_LENGTH);
+
+ DEBUG("Creating CPU log partitions\n");
+ header.prefix = be32_to_cpu(LLFW_LOG_BE0_NAME_PREFIX);
+ header.name = be64_to_cpu(LLFW_LOG_BE0_NAME);
+ cpulog0=create_nvram_partition(LLFW_LOG_BE0_SIGNATURE, (char *)&header,
+ (LLFW_LOG_BE0_LENGTH*16)-PARTITION_HEADER_SIZE);
+
+ header.prefix = be32_to_cpu(LLFW_LOG_BE1_NAME_PREFIX);
+ header.name = be64_to_cpu(LLFW_LOG_BE1_NAME);
+ cpulog1=create_nvram_partition(LLFW_LOG_BE1_SIGNATURE, (char *)&header,
+ (LLFW_LOG_BE1_LENGTH*16)-PARTITION_HEADER_SIZE);
+
+ DEBUG("Initializing CPU log partitions\n");
+ init_cpulog_partition(cpulog0);
+ init_cpulog_partition(cpulog1);
+
+ nvramlog_printf("Creating common NVRAM partition\r\n");
+ create_nvram_partition(0x70, "common", 0x01000-PARTITION_HEADER_SIZE);
+
+ create_free_partition();
+}
+
+void nvram_debug(void)
+{
+#ifndef RTAS_NVRAM
+ printf("\nNVRAM_BASE: %p\n", nvram);
+ printf("NVRAM_LEN: 0x%x\n", NVRAM_LENGTH);
+#endif
+}
+
+unsigned int get_nvram_size(void)
+{
+ return NVRAM_LENGTH;
+}
diff --git a/src/roms/SLOF/lib/libnvram/nvram.h b/src/roms/SLOF/lib/libnvram/nvram.h
new file mode 100644
index 0000000..fa6bdd4
--- /dev/null
+++ b/src/roms/SLOF/lib/libnvram/nvram.h
@@ -0,0 +1,73 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#ifndef __NVRAM_H
+#define __NVRAM_H 1
+
+/* data structures */
+
+typedef struct {
+ unsigned long addr;
+ long len;
+} partition_t;
+
+/* macros */
+
+#define DEBUG(x...)
+// #define DEBUG(x...) printf(x);
+
+#ifndef ALIGN
+#define ALIGN(x, a) (((x) + ((a) - 1)) & ~((a) - 1))
+#endif
+
+#define NULL ((void *)0)
+
+#define PARTITION_HEADER_SIZE 16
+
+
+/* exported functions */
+
+#define nvram_access_proto(type,name) \
+ type nvram_read_##name(unsigned int offset); \
+ void nvram_write_##name(unsigned int offset, type data);
+
+nvram_access_proto(uint8_t, byte)
+nvram_access_proto(uint16_t, word)
+nvram_access_proto(uint32_t, dword)
+nvram_access_proto(uint64_t, qword)
+
+/* nvram.c */
+
+char *get_nvram_buffer(int len);
+void free_nvram_buffer(char *buffer);
+int nvramlog_printf(const char* fmt, ...);
+partition_t get_partition(unsigned int type, char *name);
+void erase_nvram(int offset, int len);
+int wipe_partition(partition_t partition, int header_only);
+partition_t new_nvram_partition(int type, char *name, int len);
+int increase_nvram_partition_size(partition_t partition, int newsize);
+int clear_nvram_partition(partition_t part);
+int delete_nvram_partition(partition_t part);
+void reset_nvram(void);
+void wipe_nvram(void);
+void nvram_debug(void);
+void nvram_init(uint32_t store_token, uint32_t fetch_token,
+ long nv_size, void* nvram_addr);
+unsigned int get_nvram_size(void);
+
+/* envvar.c */
+char *get_env(partition_t part, char *envvar);
+int add_env(partition_t part, char *envvar, char *value);
+int del_env(partition_t part, char *envvar);
+int set_env(partition_t part, char *envvar, char *value);
+
+#endif
diff --git a/src/roms/SLOF/lib/libusb/Makefile b/src/roms/SLOF/lib/libusb/Makefile
new file mode 100644
index 0000000..0780489
--- /dev/null
+++ b/src/roms/SLOF/lib/libusb/Makefile
@@ -0,0 +1,52 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2008 IBM Corporation
+# * All rights reserved.
+# * This program and the accompanying materials
+# * are made available under the terms of the BSD License
+# * which accompanies this distribution, and is available at
+# * http://www.opensource.org/licenses/bsd-license.php
+# *
+# * Contributors:
+# * IBM Corporation - initial implementation
+# ****************************************************************************/
+
+TOPCMNDIR ?= ../..
+
+include $(TOPCMNDIR)/make.rules
+
+ASFLAGS = $(FLAG) $(RELEASE) $(CPUARCHDEF) -Wa,-mregnames
+CPPFLAGS = -I../libc/include $(CPUARCHDEF) -I$(INCLBRDDIR) \
+ -I$(INCLCMNDIR) -I$(INCLCMNDIR)/$(CPUARCH) -I$(SLOFCMNDIR)
+LDFLAGS = -nostdlib
+
+TARGET = ../libusb.a
+
+
+all: $(TARGET)
+
+SRCS = usb-core.c usb-ohci.c usb-ehci.c usb-slof.c usb-key.c usb-hid.c \
+ usb-hub.c usb-xhci.c
+
+OBJS = $(SRCS:%.c=%.o)
+
+$(TARGET): $(OBJS)
+ $(AR) -rc $@ $(OBJS)
+ $(RANLIB) $@
+
+clean:
+ $(RM) $(TARGET) $(OBJS)
+
+distclean: clean
+ $(RM) Makefile.dep
+
+
+# Rules for creating the dependency file:
+depend:
+ $(RM) Makefile.dep
+ $(MAKE) Makefile.dep
+
+Makefile.dep: Makefile
+ $(CC) -M $(CPPFLAGS) $(CFLAGS) $(SRCS) $(SRCSS) > Makefile.dep
+
+# Include dependency file if available:
+-include Makefile.dep
diff --git a/src/roms/SLOF/lib/libusb/tools.h b/src/roms/SLOF/lib/libusb/tools.h
new file mode 100644
index 0000000..f531175
--- /dev/null
+++ b/src/roms/SLOF/lib/libusb/tools.h
@@ -0,0 +1,77 @@
+/*****************************************************************************
+ * Copyright (c) 2013 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#ifndef __TOOLS_H
+#define __TOOLS_H
+
+#include <stdint.h>
+#include <byteorder.h>
+#include <cache.h>
+
+#define PTR_U32(x) ((uint32_t) (uint64_t) (x))
+
+static inline uint32_t read_reg32(uint32_t *reg)
+{
+ return bswap_32(ci_read_32(reg));
+}
+
+static inline void write_reg32(uint32_t *reg, uint32_t value)
+{
+ mb();
+ ci_write_32(reg, bswap_32(value));
+}
+
+static inline uint8_t read_reg8(uint8_t *reg)
+{
+ return ci_read_8(reg);
+}
+
+static inline void write_reg8(uint8_t *reg, uint8_t value)
+{
+ mb();
+ ci_write_8(reg, value);
+}
+
+static inline uint16_t read_reg16(uint16_t *reg)
+{
+ return bswap_16(ci_read_16(reg));
+}
+
+static inline void write_reg16(uint16_t *reg, uint16_t value)
+{
+ mb();
+ ci_write_16(reg, bswap_16(value));
+}
+
+static inline uint64_t read_reg64(uint64_t *reg)
+{
+ return bswap_64(ci_read_64(reg));
+}
+
+static inline void write_reg64(uint64_t *reg, uint64_t value)
+{
+ mb();
+ ci_write_64(reg, bswap_64(value));
+}
+
+static inline uint32_t ci_read_reg(uint32_t *reg)
+{
+ return bswap_32(ci_read_32(reg));
+}
+
+static inline void ci_write_reg(uint32_t *reg, uint32_t value)
+{
+ mb();
+ ci_write_32(reg, bswap_32(value));
+}
+
+#endif
diff --git a/src/roms/SLOF/lib/libusb/usb-core.c b/src/roms/SLOF/lib/libusb/usb-core.c
new file mode 100644
index 0000000..6719c57
--- /dev/null
+++ b/src/roms/SLOF/lib/libusb/usb-core.c
@@ -0,0 +1,590 @@
+/*****************************************************************************
+ * Copyright (c) 2013 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <string.h>
+#include "usb-core.h"
+
+#undef DEBUG
+//#define DEBUG
+#ifdef DEBUG
+#define dprintf(_x ...) do { printf(_x); } while(0)
+#else
+#define dprintf(_x ...)
+#endif
+
+#define __unused __attribute__((unused))
+
+struct usb_hcd_ops *head;
+struct usb_dev *devpool;
+#define USB_DEVPOOL_SIZE 4096
+
+static struct usb_dev *usb_alloc_devpool(void)
+{
+ struct usb_dev *head, *curr, *prev;
+ unsigned int dev_count = 0, i;
+
+ head = SLOF_alloc_mem(USB_DEVPOOL_SIZE);
+ if (!head)
+ return NULL;
+
+ dev_count = USB_DEVPOOL_SIZE/sizeof(struct usb_dev);
+ dprintf("%s: %d number of devices\n", __func__, dev_count);
+ /* Although an array, link them*/
+ for (i = 0, curr = head, prev = NULL; i < dev_count; i++, curr++) {
+ if (prev)
+ prev->next = curr;
+ curr->next = NULL;
+ prev = curr;
+ }
+
+#ifdef DEBUG
+ for (i = 0, curr = head; curr; curr = curr->next)
+ printf("%s: %d dev %p\n", __func__, i++, curr);
+#endif
+
+ return head;
+}
+
+struct usb_dev *usb_devpool_get(void)
+{
+ struct usb_dev *new;
+
+ if (!devpool) {
+ devpool = usb_alloc_devpool();
+ if (!devpool)
+ return NULL;
+ }
+
+ new = devpool;
+ devpool = devpool->next;
+ memset(new, 0, sizeof(*new));
+ new->next = NULL;
+ return new;
+}
+
+void usb_devpool_put(struct usb_dev *dev)
+{
+ struct usb_dev *curr;
+ if (!dev && !devpool)
+ return;
+
+ curr = devpool;
+ while (curr->next)
+ curr = curr->next;
+ curr->next = dev;
+ dev->next = NULL;
+}
+
+#ifndef DEBUG
+#define validate_hcd_ops(dev) (dev && dev->hcidev && dev->hcidev->ops)
+#else
+int validate_hcd_ops(struct usb_dev *dev)
+{
+ int ret = true;
+
+ if (!dev) {
+ printf("dev is NULL\n");
+ ret = false;
+ } else if (!dev->hcidev) {
+ printf("hcidev is NULL\n");
+ ret = false;
+ } else if (!dev->hcidev->ops) {
+ printf("ops is NULL\n");
+ ret = false;
+ }
+ return ret;
+}
+#endif
+
+struct usb_pipe *usb_get_pipe(struct usb_dev *dev, struct usb_ep_descr *ep,
+ char *buf, size_t len)
+{
+ if (validate_hcd_ops(dev) && dev->hcidev->ops->get_pipe)
+ return dev->hcidev->ops->get_pipe(dev, ep, buf, len);
+ else {
+ printf("%s: Failed\n", __func__);
+ return NULL;
+ }
+}
+
+void usb_put_pipe(struct usb_pipe *pipe)
+{
+ struct usb_dev *dev = NULL;
+ if (pipe && pipe->dev) {
+ dev = pipe->dev;
+ if (validate_hcd_ops(dev) && dev->hcidev->ops->put_pipe)
+ dev->hcidev->ops->put_pipe(pipe);
+ }
+}
+
+int usb_poll_intr(struct usb_pipe *pipe, uint8_t *buf)
+{
+ struct usb_dev *dev = NULL;
+ if (pipe && pipe->dev) {
+ dev = pipe->dev;
+ if (validate_hcd_ops(dev) && dev->hcidev->ops->poll_intr)
+ return dev->hcidev->ops->poll_intr(pipe, buf);
+ }
+ return 0;
+}
+
+void usb_hcd_register(struct usb_hcd_ops *ops)
+{
+ struct usb_hcd_ops *list;
+
+ if (!ops)
+ printf("Error");
+ dprintf("Registering %s %d\n", ops->name, ops->usb_type);
+
+ if (head) {
+ list = head;
+ while (list->next)
+ list = list->next;
+ list->next = ops;
+ } else
+ head = ops;
+}
+
+void usb_hcd_init(void *hcidev)
+{
+ struct usb_hcd_dev *dev = hcidev;
+ struct usb_hcd_ops *list = head;
+
+ if (!dev) {
+ printf("Device Error");
+ return;
+ }
+
+ while (list) {
+ if (list->usb_type == dev->type) {
+ dprintf("usb_ops(%p) for the controller found\n", list);
+ dev->ops = list;
+ dev->ops->init(dev);
+ return;
+ }
+ list = list->next;
+ }
+
+ dprintf("usb_ops for the controller not found\n");
+}
+
+void usb_hcd_exit(void *_hcidev)
+{
+ struct usb_hcd_dev *hcidev = _hcidev;
+
+ dprintf("%s: enter \n", __func__);
+ if (!hcidev) {
+ printf("Device Error");
+ return;
+ }
+
+ if (hcidev->ops->exit)
+ hcidev->ops->exit(hcidev);
+}
+
+int usb_send_ctrl(struct usb_pipe *pipe, struct usb_dev_req *req, void *data)
+{
+ struct usb_dev *dev = NULL;
+ if (!pipe)
+ return false;
+ dev = pipe->dev;
+ if (validate_hcd_ops(dev) && dev->hcidev->ops->send_ctrl)
+ return dev->hcidev->ops->send_ctrl(pipe, req, data);
+ else {
+ printf("%s: Failed\n", __func__);
+ return false;
+ }
+}
+
+int usb_transfer_ctrl(void *dev, void *req, void *data)
+{
+ struct usb_pipe *pipe = NULL;
+ struct usb_dev *usbdev;
+
+ if (!dev)
+ return false;
+ usbdev = (struct usb_dev *)dev;
+ pipe = usbdev->control;
+ return usb_send_ctrl(pipe, req, data);
+}
+
+int usb_transfer_bulk(void *dev, int dir, void *td, void *td_phys, void *data, int size)
+{
+ struct usb_pipe *pipe = NULL;
+ struct usb_dev *usbdev;
+
+ if (!dev)
+ return false;
+ usbdev = (struct usb_dev *)dev;
+ pipe = (dir == USB_PIPE_OUT) ? usbdev->bulk_out : usbdev->bulk_in;
+ if (!pipe)
+ return false;
+ if (validate_hcd_ops(usbdev) && usbdev->hcidev->ops->transfer_bulk)
+ return usbdev->hcidev->ops->transfer_bulk(pipe, td, td_phys, data, size);
+ else {
+ printf("%s: Failed\n", __func__);
+ return false;
+ }
+}
+
+/*
+ * USB Specification 1.1
+ * 9.3 USB Device Requests
+ * 9.4 Standard Device Requests
+ */
+static int usb_set_address(struct usb_dev *dev, uint32_t port)
+{
+ struct usb_dev_req req;
+ struct usb_hcd_dev *hcidev;
+
+ if (!dev)
+ return false;
+
+ hcidev = dev->hcidev;
+ req.bmRequestType = 0;
+ req.bRequest = REQ_SET_ADDRESS;
+ req.wIndex = 0;
+ req.wLength = 0;
+ req.wValue = cpu_to_le16((uint16_t)(hcidev->nextaddr));
+ if (usb_send_ctrl(dev->control, &req, NULL)) {
+ dev->addr = hcidev->nextaddr++;
+ return true;
+ } else
+ return false;
+}
+
+static int usb_get_device_descr(struct usb_dev *dev, void *data, size_t size)
+{
+ struct usb_dev_req req;
+
+ if (!dev)
+ return false;
+
+ req.bmRequestType = 0x80;
+ req.bRequest = REQ_GET_DESCRIPTOR;
+ req.wIndex = 0;
+ req.wLength = cpu_to_le16((uint16_t) size);
+ req.wValue = cpu_to_le16(DESCR_TYPE_DEVICE << 8);
+ return usb_send_ctrl(dev->control, &req, data);
+}
+
+static int usb_get_config_descr(struct usb_dev *dev, void *data, size_t size)
+{
+ struct usb_dev_req req;
+
+ if (!dev)
+ return false;
+
+ req.bmRequestType = 0x80;
+ req.bRequest = REQ_GET_DESCRIPTOR;
+ req.wIndex = 0;
+ req.wLength = cpu_to_le16((uint16_t) size);
+ req.wValue = cpu_to_le16(DESCR_TYPE_CONFIGURATION << 8);
+ return usb_send_ctrl(dev->control, &req, data);
+
+}
+
+static int usb_set_config(struct usb_dev *dev, uint8_t cfg_value)
+{
+ struct usb_dev_req req;
+
+ if (!dev)
+ return false;
+
+ req.bmRequestType = 0x00;
+ req.bRequest = REQ_SET_CONFIGURATION;
+ req.wIndex = 0;
+ req.wLength = 0;
+ req.wValue = cpu_to_le16(0x00FF & cfg_value);
+ return usb_send_ctrl(dev->control, &req, NULL);
+}
+
+static int usb_clear_halt(struct usb_pipe *pipe)
+{
+ struct usb_dev_req req;
+ struct usb_dev *dev;
+
+ if (pipe && pipe->dev) {
+ dev = pipe->dev;
+ dprintf("Clearing port %d dir %d type %d\n",
+ pipe->epno, pipe->dir, pipe->type);
+ req.bmRequestType = REQT_DIR_OUT | REQT_REC_EP;
+ req.bRequest = REQ_CLEAR_FEATURE;
+ req.wValue = FEATURE_ENDPOINT_HALT;
+ req.wIndex = cpu_to_le16(pipe->epno | pipe->dir);
+ req.wLength = 0;
+ return usb_send_ctrl(dev->control, &req, NULL);
+ }
+ return false;
+}
+
+int usb_dev_populate_pipe(struct usb_dev *dev, struct usb_ep_descr *ep,
+ void *buf, size_t len)
+{
+ uint8_t dir, type;
+
+ dir = (ep->bEndpointAddress & 0x80) >> 7;
+ type = ep->bmAttributes & USB_EP_TYPE_MASK;
+
+ dprintf("EP: %s: %d size %d type %d\n", dir ? "IN " : "OUT",
+ ep->bEndpointAddress & 0xF, le16_to_cpu(ep->wMaxPacketSize),
+ type);
+ if (type == USB_EP_TYPE_BULK) {
+ if (dir)
+ dev->bulk_in = usb_get_pipe(dev, ep, buf, len);
+ else
+ dev->bulk_out = usb_get_pipe(dev, ep, buf, len);
+ } else if (type == USB_EP_TYPE_INTR)
+ dev->intr = usb_get_pipe(dev, ep, buf, len);
+
+ return true;
+}
+
+static void usb_dev_copy_epdesc(struct usb_dev *dev, struct usb_ep_descr *ep)
+{
+ uint32_t ep_cnt;
+
+ ep_cnt = dev->ep_cnt;
+ if (ep_cnt < USB_DEV_EP_MAX)
+ memcpy((void *)&dev->ep[ep_cnt], ep, sizeof(*ep));
+ else
+ dprintf("usb-core: only %d EPs supported\n", USB_DEV_EP_MAX);
+ dev->ep_cnt++;
+}
+
+int usb_hid_init(void *vdev)
+{
+ struct usb_dev *dev;
+ dev = (struct usb_dev *) vdev;
+ if (!dev)
+ return false;
+ if (dev->class == DEV_HID_KEYB)
+ usb_hid_kbd_init(dev);
+ return true;
+}
+
+int usb_hid_exit(void *vdev)
+{
+ struct usb_dev *dev;
+ dev = (struct usb_dev *) vdev;
+ if (!dev)
+ return false;
+ if (dev->class == DEV_HID_KEYB)
+ usb_hid_kbd_exit(dev);
+ return true;
+}
+
+#define usb_get_intf_class(x) ((x & 0x00FF0000) >> 16)
+
+int usb_msc_init(void *vdev)
+{
+ struct usb_dev *dev;
+ int i;
+
+ dev = (struct usb_dev *) vdev;
+ dprintf("%s: enter %x\n", __func__, dev->class);
+ if (!dev)
+ return false;
+ if (usb_get_intf_class(dev->class) == 8) {
+ for (i = 0; i < dev->ep_cnt; i++) {
+ if ((dev->ep[i].bmAttributes & USB_EP_TYPE_MASK)
+ == USB_EP_TYPE_BULK)
+ usb_dev_populate_pipe(dev, &dev->ep[i], NULL, 0);
+ }
+ }
+ return true;
+}
+
+int usb_msc_exit(void *vdev)
+{
+ struct usb_dev *dev;
+ dev = (struct usb_dev *) vdev;
+ dprintf("%s: enter %x\n", __func__, dev->class);
+ if (!dev)
+ return false;
+ if (usb_get_intf_class(dev->class) == 8) {
+ if (dev->bulk_in)
+ usb_put_pipe(dev->bulk_in);
+ if (dev->bulk_out)
+ usb_put_pipe(dev->bulk_out);
+ }
+ return true;
+}
+
+static int usb_msc_reset(struct usb_dev *dev)
+{
+ struct usb_dev_req req;
+
+ if (!dev)
+ return false;
+
+ req.bmRequestType = REQT_TYPE_CLASS | REQT_REC_INTERFACE | REQT_DIR_OUT;
+ req.bRequest = 0xFF;
+ req.wLength = 0;
+ req.wValue = 0;
+ req.wIndex = cpu_to_le16(dev->intf_num);
+ return usb_send_ctrl(dev->control, &req, NULL);
+}
+
+void usb_msc_resetrecovery(struct usb_dev *dev)
+{
+ // usb_msc_reset(dev);
+ usb_clear_halt(dev->bulk_in);
+ usb_clear_halt(dev->bulk_out);
+ SLOF_msleep(2);
+}
+
+static int usb_handle_device(struct usb_dev *dev, struct usb_dev_config_descr *cfg,
+ uint8_t *ptr, uint16_t len)
+{
+ struct usb_dev_intf_descr *intf = NULL;
+ struct usb_ep_descr *ep = NULL;
+ struct usb_dev_hid_descr *hid __unused = NULL;
+ uint8_t desc_len, desc_type;
+
+ len -= sizeof(struct usb_dev_config_descr);
+ ptr = (uint8_t *)(ptr + sizeof(struct usb_dev_config_descr));
+
+ while (len > 0) {
+ desc_len = *ptr;
+ desc_type = *(ptr + 1);
+ switch (desc_type) {
+ case DESCR_TYPE_INTERFACE:
+ intf = (struct usb_dev_intf_descr *)ptr;
+ dev->class = intf->bInterfaceClass << 16 |
+ intf->bInterfaceSubClass << 8 |
+ intf->bInterfaceProtocol;
+ break;
+ case DESCR_TYPE_ENDPOINT:
+ ep = (struct usb_ep_descr *)ptr;
+ dev->intf_num = intf->bInterfaceNumber;
+ usb_dev_copy_epdesc(dev, ep);
+ break;
+ case DESCR_TYPE_HID:
+ hid = (struct usb_dev_hid_descr *)ptr;
+ dprintf("hid-report %d size %d\n",
+ hid->bReportType, le16_to_cpu(hid->wReportLength));
+ break;
+ case DESCR_TYPE_HUB:
+ break;
+ default:
+ printf("ptr %p desc_type %d\n", ptr, desc_type);
+ }
+ ptr += desc_len;
+ len -= desc_len;
+ }
+ return true;
+}
+
+int setup_new_device(struct usb_dev *dev, unsigned int port)
+{
+ struct usb_dev_descr descr;
+ struct usb_dev_config_descr cfg;
+ struct usb_ep_descr ep;
+ uint16_t len;
+ void *data = NULL;
+
+ dprintf("usb: %s - port %d\n", __func__, port);
+
+ dev->addr = 0;
+ dev->port = port;
+ ep.bEndpointAddress = 0;
+ ep.bmAttributes = USB_EP_TYPE_CONTROL;
+ ep.wMaxPacketSize = cpu_to_le16(8);
+ dev->control = usb_get_pipe(dev, &ep, NULL, 0);
+
+ if (!usb_get_device_descr(dev, &descr, 8))
+ goto fail;
+ dev->control->mps = descr.bMaxPacketSize0;
+
+ /*
+ * For USB3.0 ADDRESS-SLOT command takes care of setting
+ * address, skip this during generic device setup for USB3.0
+ * devices
+ */
+ if (dev->speed != USB_SUPER_SPEED) {
+ /*
+ * Qemu starts the port number from 1 which was
+ * revealed in bootindex and resulted in mismatch for
+ * storage devices names. Adjusting this here for
+ * compatibility.
+ */
+ dev->port = port + 1;
+ if(!usb_set_address(dev, dev->port))
+ goto fail;
+ }
+ mb();
+ SLOF_msleep(100);
+
+ if (!usb_get_device_descr(dev, &descr, sizeof(struct usb_dev_descr)))
+ goto fail;
+
+ if (!usb_get_config_descr(dev, &cfg, sizeof(struct usb_dev_config_descr)))
+ goto fail;
+
+ len = le16_to_cpu(cfg.wTotalLength);
+ /* No device config descriptor present */
+ if (len == sizeof(struct usb_dev_config_descr))
+ goto fail;
+
+ data = SLOF_dma_alloc(len);
+ if (!data) {
+ printf("%s: alloc failed %d\n", __func__, port);
+ goto fail;
+ }
+
+ if (!usb_get_config_descr(dev, data, len))
+ goto fail_mem_free;
+ if (!usb_set_config(dev, cfg.bConfigurationValue))
+ goto fail_mem_free;
+ mb();
+ SLOF_msleep(100);
+
+ if (!usb_handle_device(dev, &cfg, data, len))
+ goto fail_mem_free;
+
+ switch (usb_get_intf_class(dev->class)) {
+ case 3:
+ dprintf("HID found %06X\n", dev->class);
+ slof_usb_handle(dev);
+ break;
+ case 8:
+ dprintf("MASS STORAGE found %d %06X\n", dev->intf_num,
+ dev->class);
+ if ((dev->class & 0x50) != 0x50) { /* Bulk-only supported */
+ printf("Device not supported %06X\n", dev->class);
+ goto fail_mem_free;
+ }
+
+ if (!usb_msc_reset(dev)) {
+ printf("%s: bulk reset failed\n", __func__);
+ goto fail_mem_free;
+ }
+ SLOF_msleep(100);
+ slof_usb_handle(dev);
+ break;
+ case 9:
+ dprintf("HUB found\n");
+ slof_usb_handle(dev);
+ break;
+ default:
+ printf("USB Interface class -%x- Not supported\n", dev->class);
+ break;
+ }
+
+ SLOF_dma_free(data, len);
+ return true;
+fail_mem_free:
+ SLOF_dma_free(data, len);
+fail:
+ return false;
+}
diff --git a/src/roms/SLOF/lib/libusb/usb-core.h b/src/roms/SLOF/lib/libusb/usb-core.h
new file mode 100644
index 0000000..7441979
--- /dev/null
+++ b/src/roms/SLOF/lib/libusb/usb-core.h
@@ -0,0 +1,279 @@
+/*****************************************************************************
+ * Copyright (c) 2013 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#ifndef __USB_CORE_H
+#define __USB_CORE_H
+
+#include <stdio.h>
+#include <stdbool.h>
+#include "helpers.h"
+#include "usb.h"
+#include "tools.h"
+
+enum usb_hcd_type {
+ USB_OHCI = 1,
+ USB_EHCI = 2,
+ USB_XHCI = 3,
+};
+
+struct usb_hcd_dev;
+
+struct usb_hcd_dev {
+ void *base;
+ long type;
+ long num;
+ struct usb_hcd_ops *ops;
+ void *priv; /* hcd owned structure */
+ long nextaddr; /* address for devices */
+};
+
+struct usb_pipe;
+
+/*******************************************/
+/* Standard Endpoint Descriptor */
+/*******************************************/
+/* bmAttributes */
+#define USB_EP_TYPE_MASK 0x03
+#define USB_EP_TYPE_CONTROL 0
+#define USB_EP_TYPE_ISOC 1
+#define USB_EP_TYPE_BULK 2
+#define USB_EP_TYPE_INTR 3
+
+struct usb_ep_descr {
+ uint8_t bLength; /* size of descriptor */
+ uint8_t bDescriptorType; /* Type = 5 */
+ uint8_t bEndpointAddress;
+ uint8_t bmAttributes;
+ uint16_t wMaxPacketSize;
+ uint8_t bInterval;
+} __attribute__((packed));
+
+#define DEV_HID_KEYB 0x030101 /* class=HIB, protocol=Keyboard */
+#define DEV_HID_MOUSE 0x030102 /* class=HIB, protocol=Mouse */
+#define DEV_HUB 0x090000 /* class=HUB, subclass, protocol */
+#define DEV_MASS_RBC 0x080150 /* MassStorage, RBC, Bulk */
+#define DEV_CDROM_ATAPI 0x080250 /* MassStorage, SFF-8020i , Bulk */
+#define DEV_MASS_FLOPPY 0x080450 /* MassStorage, UFI, Bulk */
+#define DEV_MASS_ATAPI 0x080550 /* MassStorage, SFF-8070i , Bulk */
+#define DEV_MASS_SCSI 0x080650 /* MassStorage, SCSI, Bulk */
+
+enum USB_SPEED_TYPE {
+ USB_LOW_SPEED = 0,
+ USB_FULL_SPEED = 1,
+ USB_HIGH_SPEED = 2,
+ USB_SUPER_SPEED = 3,
+};
+
+/* Max number of endpoints supported in a device */
+#define USB_DEV_EP_MAX 4
+#define USB_TIMEOUT 5000 /* 5 sec usb timeout */
+
+struct usb_dev {
+ struct usb_dev *next;
+ struct usb_hcd_dev *hcidev;
+ struct usb_pipe *intr;
+ struct usb_pipe *control;
+ struct usb_pipe *bulk_in;
+ struct usb_pipe *bulk_out;
+ struct usb_ep_descr ep[USB_DEV_EP_MAX];
+ void *priv;
+ uint32_t ep_cnt;
+ uint32_t class;
+ uint32_t speed;
+ uint32_t addr;
+ uint32_t mps0;
+ uint32_t port;
+ uint16_t intf_num;
+};
+
+#define DEVICE_KEYBOARD 1
+#define DEVICE_MOUSE 2
+#define DEVICE_DISK 3
+#define DEVICE_HUB 4
+
+/* Structure in sync with FORTH code */
+struct slof_usb_dev {
+ void *udev;
+ uint32_t port;
+ uint32_t addr;
+ uint32_t hcitype;
+ uint32_t num;
+ uint32_t devtype;
+} __attribute__((packed));
+
+enum USB_PIPE_DIR {
+ USB_PIPE_OUT = 0,
+ USB_PIPE_IN,
+};
+
+struct usb_pipe {
+ struct usb_dev *dev;
+ struct usb_pipe *next;
+ uint32_t type;
+ uint32_t speed;
+ uint32_t dir;
+ uint16_t epno;
+ uint16_t mps;
+} __attribute__((packed));
+
+#define REQ_GET_STATUS 0 /* see Table 9-4 */
+#define REQ_CLEAR_FEATURE 1
+#define REQ_GET_STATE 2 /* HUB specific */
+#define REQ_SET_FEATURE 3
+#define REQ_SET_ADDRESS 5
+#define REQ_GET_DESCRIPTOR 6
+#define REQ_SET_DESCRIPTOR 7
+#define REQ_GET_CONFIGURATION 8
+#define REQ_SET_CONFIGURATION 9
+#define REQ_GET_INTERFACE 10
+#define REQ_SET_INTERFACE 11
+#define REQ_SYNCH_FRAME 12
+
+#define FEATURE_DEVICE_REMOTE_WAKEUP 1
+#define FEATURE_ENDPOINT_HALT 0
+
+#define REQT_REC_DEVICE 0
+#define REQT_REC_INTERFACE 1
+#define REQT_REC_EP 2
+#define REQT_REC_OTHER 3
+#define REQT_TYPE_STANDARD (0 << 5)
+#define REQT_TYPE_CLASS (1 << 5)
+#define REQT_TYPE_VENDOR (2 << 5)
+#define REQT_TYPE_RSRVD (3 << 5)
+#define REQT_DIR_OUT (0 << 7) /* host -> device */
+#define REQT_DIR_IN (1 << 7) /* device -> host */
+
+#define DESCR_TYPE_DEVICE 1 /* see Table 9-5 */
+#define DESCR_TYPE_CONFIGURATION 2
+#define DESCR_TYPE_STRING 3
+#define DESCR_TYPE_INTERFACE 4
+#define DESCR_TYPE_ENDPOINT 5
+#define DESCR_TYPE_HUB 0x29 /* Class Descriptor HUB */
+#define DESCR_TYPE_HID 0x21 /* Class Descriptor HID */
+#define DESCR_TYPE_REPORT 0x22 /* Class Descriptor HID */
+#define DESCR_TYPE_PHYSICAL 0x23 /* Class Descriptor HID */
+
+struct usb_dev_req {
+ uint8_t bmRequestType; /* direction, recipient */
+ uint8_t bRequest; /* see spec: Table 9-3 */
+ uint16_t wValue;
+ uint16_t wIndex;
+ uint16_t wLength; /* number of bytes to transfer */
+} __attribute__((packed));
+
+/* Standard Device Descriptor (18 Bytes) */
+/*******************************************/
+struct usb_dev_descr {
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+ uint16_t bcdUSB;
+ uint8_t bDeviceClass;
+ uint8_t bDeviceSubClass;
+ uint8_t bDeviceProtocol;
+ uint8_t bMaxPacketSize0;
+ uint16_t idVendor;
+ uint16_t idProduct;
+ uint16_t bcdDevice;
+ uint8_t iManufacturer;
+ uint8_t iProduct;
+ uint8_t iSerialNumber;
+ uint8_t bNumConfigurations;
+} __attribute__((packed));
+
+/*******************************************/
+/* Standard Configuration Descriptor */
+/*******************************************/
+struct usb_dev_config_descr {
+ uint8_t bLength; /* size of descriptor */
+ uint8_t bDescriptorType; /* Type = 2 */
+ uint16_t wTotalLength; /* total returned data */
+ uint8_t bNumInterfaces; /* interfaces supported by this config */
+ uint8_t bConfigurationValue; /* Configuration-ID for SetConfiguration */
+ uint8_t iConfiguration; /* index of string descriptor */
+ uint8_t bmAttributes; /* configuration characteristics */
+ uint8_t bMaxPower; /* in 2mA units */
+} __attribute__((packed));
+
+/*******************************************/
+/* Standard Interface Descriptor */
+/*******************************************/
+struct usb_dev_intf_descr {
+ uint8_t bLength; /* size of descriptor */
+ uint8_t bDescriptorType; /* Type = 4 */
+ uint8_t bInterfaceNumber;
+ uint8_t bAlternateSetting;
+ uint8_t bNumEndpoints;
+ uint8_t bInterfaceClass;
+ uint8_t bInterfaceSubClass;
+ uint8_t bInterfaceProtocol; /* protocol code */
+ uint8_t iInterface; /* index to string descriptor */
+} __attribute__((packed));
+
+/*******************************************/
+/* HUB-Class Descriptor */
+/*******************************************/
+struct usb_dev_hub_descr {
+ uint8_t bLength; /* size of complete descriptor */
+ uint8_t bDescriptorType; /* type = 0x29 for HUB */
+ uint8_t bNbrPorts; /* number of downstream ports */
+ uint8_t wHubCharacteristics; /* mode bits 7..0 */
+ uint8_t reserved; /* mode bits 15..8 */
+ uint8_t bPwrOn2PwrGood; /* in 2ms units */
+ uint8_t bHubContrCurrent; /* current requirement in mA */
+ uint8_t DeviceTable; /* length depends on number of ports */
+} __attribute__((packed));
+
+/*******************************************/
+/* HID-Class Descriptor */
+/*******************************************/
+struct usb_dev_hid_descr {
+ uint8_t bLength; /* size of this descriptor */
+ uint8_t bDescriptorType; /* type = 0x21 for HID */
+ uint16_t bcdHID; /* Sample: 0x0102 for 2.01 */
+ uint8_t bCountryCode; /* Hardware target country */
+ uint8_t bNumDescriptors; /* Number of HID class descr. */
+ uint8_t bReportType; /* Report Descriptor Type */
+ uint16_t wReportLength; /* Total Length of Report Descr. */
+} __attribute__((packed));
+
+struct usb_hcd_ops {
+ const char *name;
+ void (*init)(struct usb_hcd_dev *);
+ void (*exit)(struct usb_hcd_dev *);
+ void (*detect)(void);
+ void (*disconnect)(void);
+ int (*send_ctrl)(struct usb_pipe *pipe, struct usb_dev_req *req, void *data);
+ struct usb_pipe* (*get_pipe)(struct usb_dev *dev, struct usb_ep_descr *ep,
+ char *buf, size_t len);
+ int (*transfer_bulk)(struct usb_pipe *pipe, void *td, void *td_phys, void *data, int size);
+ void (*put_pipe)(struct usb_pipe *);
+ int (*poll_intr)(struct usb_pipe *, uint8_t *);
+ struct usb_hcd_ops *next;
+ unsigned int usb_type;
+};
+
+extern void usb_hcd_register(struct usb_hcd_ops *ops);
+extern struct usb_pipe *usb_get_pipe(struct usb_dev *dev, struct usb_ep_descr *ep,
+ char *buf, size_t len);
+extern void usb_put_pipe(struct usb_pipe *pipe);
+extern int usb_poll_intr(struct usb_pipe *pipe, uint8_t *buf);
+extern int usb_send_ctrl(struct usb_pipe *pipe, struct usb_dev_req *req, void *data);
+extern struct usb_dev *usb_devpool_get(void);
+extern void usb_devpool_put(struct usb_dev *);
+extern int setup_new_device(struct usb_dev *dev, unsigned int port);
+extern int slof_usb_handle(struct usb_dev *dev);
+extern int usb_dev_populate_pipe(struct usb_dev *dev, struct usb_ep_descr *ep,
+ void *buf, size_t len);
+extern int usb_hid_kbd_init(struct usb_dev *dev);
+extern int usb_hid_kbd_exit(struct usb_dev *dev);
+extern void usb_msc_resetrecovery(struct usb_dev *dev);
+#endif
diff --git a/src/roms/SLOF/lib/libusb/usb-ehci.c b/src/roms/SLOF/lib/libusb/usb-ehci.c
new file mode 100644
index 0000000..4cca0da
--- /dev/null
+++ b/src/roms/SLOF/lib/libusb/usb-ehci.c
@@ -0,0 +1,609 @@
+/*****************************************************************************
+ * Copyright (c) 2013 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <string.h>
+#include "usb.h"
+#include "usb-core.h"
+#include "usb-ehci.h"
+#include "tools.h"
+#include "paflof.h"
+
+#undef EHCI_DEBUG
+//#define EHCI_DEBUG
+#ifdef EHCI_DEBUG
+#define dprintf(_x ...) do { printf(_x); } while(0)
+#else
+#define dprintf(_x ...)
+#endif
+
+#ifdef EHCI_DEBUG
+static void dump_ehci_regs(struct ehci_hcd *ehcd)
+{
+ struct ehci_cap_regs *cap_regs;
+ struct ehci_op_regs *op_regs;
+
+ cap_regs = ehcd->cap_regs;
+ op_regs = ehcd->op_regs;
+
+ dprintf("\n - CAPLENGTH %02X", read_reg8(&cap_regs->caplength));
+ dprintf("\n - HCIVERSION %04X", read_reg16(&cap_regs->hciversion));
+ dprintf("\n - HCSPARAMS %08X", read_reg32(&cap_regs->hcsparams));
+ dprintf("\n - HCCPARAMS %08X", read_reg32(&cap_regs->hccparams));
+ dprintf("\n - HCSP_PORTROUTE %016llX", read_reg64(&cap_regs->portroute));
+ dprintf("\n");
+
+ dprintf("\n - USBCMD %08X", read_reg32(&op_regs->usbcmd));
+ dprintf("\n - USBSTS %08X", read_reg32(&op_regs->usbsts));
+ dprintf("\n - USBINTR %08X", read_reg32(&op_regs->usbintr));
+ dprintf("\n - FRINDEX %08X", read_reg32(&op_regs->frindex));
+ dprintf("\n - CTRLDSSEGMENT %08X", read_reg32(&op_regs->ctrldssegment));
+ dprintf("\n - PERIODICLISTBASE %08X", read_reg32(&op_regs->periodiclistbase));
+ dprintf("\n - ASYNCLISTADDR %08X", read_reg32(&op_regs->asynclistaddr));
+ dprintf("\n - CONFIGFLAG %08X", read_reg32(&op_regs->configflag));
+ dprintf("\n - PORTSC %08X", read_reg32(&op_regs->portsc[0]));
+ dprintf("\n");
+}
+#endif
+
+static int ehci_hub_check_ports(struct ehci_hcd *ehcd)
+{
+ uint32_t num_ports, portsc, i;
+ struct usb_dev *dev;
+
+ dprintf("%s: enter\n", __func__);
+ num_ports = read_reg32(&ehcd->cap_regs->hcsparams) & HCS_NPORTS_MASK;
+ for (i = 0; i < num_ports; i++) {
+ dprintf("%s: device %d\n", __func__, i);
+ portsc = read_reg32(&ehcd->op_regs->portsc[i]);
+ if (portsc & PORT_CONNECT) { /* Device present */
+ dprintf("usb-ehci: Device present on port %d\n", i);
+ /* Reset the port */
+ portsc = read_reg32(&ehcd->op_regs->portsc[i]);
+ portsc = (portsc & ~PORT_PE) | PORT_RESET;
+ write_reg32(&ehcd->op_regs->portsc[i], portsc);
+ SLOF_msleep(20);
+ portsc = read_reg32(&ehcd->op_regs->portsc[i]);
+ portsc &= ~PORT_RESET;
+ write_reg32(&ehcd->op_regs->portsc[i], portsc);
+ SLOF_msleep(20);
+ dev = usb_devpool_get();
+ dprintf("usb-ehci: allocated device %p\n", dev);
+ dev->hcidev = ehcd->hcidev;
+ dev->speed = USB_HIGH_SPEED; /* TODO: Check for Low/Full speed device */
+ if (!setup_new_device(dev, i))
+ printf("usb-ehci: unable to setup device on port %d\n", i);
+ }
+ }
+ dprintf("%s: exit\n", __func__);
+ return 0;
+}
+
+static int ehci_hcd_init(struct ehci_hcd *ehcd)
+{
+ uint32_t usbcmd;
+ uint32_t time;
+ struct ehci_framelist *fl;
+ struct ehci_qh *qh_intr, *qh_async;
+ int i;
+ long fl_phys = 0, qh_intr_phys = 0, qh_async_phys;
+
+ /* Reset the host controller */
+ time = SLOF_GetTimer() + 250;
+ usbcmd = read_reg32(&ehcd->op_regs->usbcmd);
+ write_reg32(&ehcd->op_regs->usbcmd, (usbcmd & ~(CMD_PSE | CMD_ASE)) | CMD_HCRESET);
+ while (time > SLOF_GetTimer())
+ cpu_relax();
+ usbcmd = read_reg32(&ehcd->op_regs->usbcmd);
+ if (usbcmd & CMD_HCRESET) {
+ printf("usb-ehci: reset failed\n");
+ return -1;
+ }
+
+ /* Initialize periodic list */
+ fl = SLOF_dma_alloc(sizeof(*fl));
+ if (!fl) {
+ printf("usb-ehci: Unable to allocate frame list\n");
+ goto fail;
+ }
+ fl_phys = SLOF_dma_map_in(fl, sizeof(*fl), true);
+ dprintf("fl %p, fl_phys %lx\n", fl, fl_phys);
+
+ /* TODO: allocate qh pool */
+ qh_intr = SLOF_dma_alloc(sizeof(*qh_intr));
+ if (!qh_intr) {
+ printf("usb-ehci: Unable to allocate interrupt queue head\n");
+ goto fail_qh_intr;
+ }
+ qh_intr_phys = SLOF_dma_map_in(qh_intr, sizeof(*qh_intr), true);
+ dprintf("qh_intr %p, qh_intr_phys %lx\n", qh_intr, qh_intr_phys);
+
+ memset(qh_intr, 0, sizeof(*qh_intr));
+ qh_intr->qh_ptr = QH_PTR_TERM;
+ qh_intr->ep_cap2 = cpu_to_le32(0x01 << QH_SMASK_SHIFT);
+ qh_intr->next_qtd = qh_intr->alt_next_qtd = QH_PTR_TERM;
+ qh_intr->token = cpu_to_le32(QH_STS_HALTED);
+ for (i = 0; i < FL_SIZE; i++)
+ fl->fl_ptr[i] = cpu_to_le32(qh_intr_phys | EHCI_TYP_QH);
+ write_reg32(&ehcd->op_regs->periodiclistbase, fl_phys);
+
+ /* Initialize async list */
+ qh_async = SLOF_dma_alloc(sizeof(*qh_async));
+ if (!qh_async) {
+ printf("usb-ehci: Unable to allocate async queue head\n");
+ goto fail_qh_async;
+ }
+ qh_async_phys = SLOF_dma_map_in(qh_async, sizeof(*qh_async), true);
+ dprintf("qh_async %p, qh_async_phys %lx\n", qh_async, qh_async_phys);
+
+ memset(qh_async, 0, sizeof(*qh_async));
+ qh_async->qh_ptr = cpu_to_le32(qh_async_phys | EHCI_TYP_QH);
+ qh_async->ep_cap1 = cpu_to_le32(QH_CAP_H);
+ qh_async->next_qtd = qh_async->alt_next_qtd = QH_PTR_TERM;
+ qh_async->token = cpu_to_le32(QH_STS_HALTED);
+ write_reg32(&ehcd->op_regs->asynclistaddr, qh_async_phys);
+ ehcd->qh_async = qh_async;
+ ehcd->qh_async_phys = qh_async_phys;
+ ehcd->qh_intr = qh_intr;
+ ehcd->qh_intr_phys = qh_intr_phys;
+ ehcd->fl = fl;
+ ehcd->fl_phys = fl_phys;
+
+ write_reg32(&ehcd->op_regs->usbcmd, usbcmd | CMD_ASE | CMD_RUN);
+ write_reg32(&ehcd->op_regs->configflag, 1);
+
+ return 0;
+
+fail_qh_async:
+ SLOF_dma_map_out(qh_intr_phys, qh_intr, sizeof(*qh_intr));
+ SLOF_dma_free(qh_intr, sizeof(*qh_intr));
+fail_qh_intr:
+ SLOF_dma_map_out(fl_phys, fl, sizeof(*fl));
+ SLOF_dma_free(fl, sizeof(*fl));
+fail:
+ return -1;
+}
+
+static int ehci_hcd_exit(struct ehci_hcd *ehcd)
+{
+ uint32_t usbcmd;
+
+ if (!ehcd) {
+ dprintf("NULL pointer\n");
+ return false;
+ }
+
+ usbcmd = read_reg32(&ehcd->op_regs->usbcmd);
+ write_reg32(&ehcd->op_regs->usbcmd, usbcmd | ~CMD_RUN);
+ write_reg32(&ehcd->op_regs->periodiclistbase, 0);
+
+ if (ehcd->pool) {
+ SLOF_dma_map_out(ehcd->pool_phys, ehcd->pool, EHCI_PIPE_POOL_SIZE);
+ SLOF_dma_free(ehcd->pool, EHCI_PIPE_POOL_SIZE);
+ }
+ if (ehcd->qh_intr) {
+ SLOF_dma_map_out(ehcd->qh_intr_phys, ehcd->qh_intr, sizeof(struct ehci_qh));
+ SLOF_dma_free(ehcd->qh_intr, sizeof(struct ehci_qh));
+ }
+ if (ehcd->qh_async) {
+ SLOF_dma_map_out(ehcd->qh_async_phys, ehcd->qh_async, sizeof(struct ehci_qh));
+ SLOF_dma_free(ehcd->qh_async, sizeof(struct ehci_qh));
+ }
+ if (ehcd->fl) {
+ SLOF_dma_map_out(ehcd->fl_phys, ehcd->fl, sizeof(struct ehci_framelist));
+ SLOF_dma_free(ehcd->fl, sizeof(struct ehci_framelist));
+ }
+ return true;
+}
+
+static int ehci_alloc_pipe_pool(struct ehci_hcd *ehcd)
+{
+ struct ehci_pipe *epipe, *curr, *prev;
+ unsigned int i, count;
+ long epipe_phys = 0;
+
+ count = EHCI_PIPE_POOL_SIZE/sizeof(*epipe);
+ ehcd->pool = epipe = SLOF_dma_alloc(EHCI_PIPE_POOL_SIZE);
+ if (!epipe)
+ return -1;
+ ehcd->pool_phys = epipe_phys = SLOF_dma_map_in(epipe, EHCI_PIPE_POOL_SIZE, true);
+ dprintf("%s: epipe %p, epipe_phys %lx\n", __func__, epipe, epipe_phys);
+
+ /* Although an array, link them */
+ for (i = 0, curr = epipe, prev = NULL; i < count; i++, curr++) {
+ if (prev)
+ prev->pipe.next = &curr->pipe;
+ curr->pipe.next = NULL;
+ prev = curr;
+ curr->qh_phys = epipe_phys + (curr - epipe) * sizeof(*curr) +
+ offset_of(struct ehci_pipe, qh);
+ dprintf("%s - %d: qh %p, qh_phys %lx\n", __func__,
+ i, &curr->qh, curr->qh_phys);
+ }
+
+ if (!ehcd->freelist)
+ ehcd->freelist = &epipe->pipe;
+ else
+ ehcd->end->next = &epipe->pipe;
+ ehcd->end = &prev->pipe;
+
+ return 0;
+}
+
+static void ehci_init(struct usb_hcd_dev *hcidev)
+{
+ struct ehci_hcd *ehcd;
+
+ printf(" EHCI: Initializing\n");
+ dprintf("%s: device base address %p\n", __func__, hcidev->base);
+
+ ehcd = SLOF_alloc_mem(sizeof(*ehcd));
+ if (!ehcd) {
+ printf("usb-ehci: Unable to allocate memory\n");
+ return;
+ }
+ memset(ehcd, 0, sizeof(*ehcd));
+
+ hcidev->nextaddr = 1;
+ hcidev->priv = ehcd;
+ ehcd->hcidev = hcidev;
+ ehcd->cap_regs = (struct ehci_cap_regs *)(hcidev->base);
+ ehcd->op_regs = (struct ehci_op_regs *)(hcidev->base +
+ read_reg8(&ehcd->cap_regs->caplength));
+#ifdef EHCI_DEBUG
+ dump_ehci_regs(ehcd);
+#endif
+ ehci_hcd_init(ehcd);
+ ehci_hub_check_ports(ehcd);
+}
+
+static void ehci_exit(struct usb_hcd_dev *hcidev)
+{
+ struct ehci_hcd *ehcd;
+ static int count = 0;
+
+ dprintf("%s: enter \n", __func__);
+
+ if (!hcidev && !hcidev->priv) {
+ return;
+ }
+ count++;
+ if (count > 1) {
+ printf("%s: already called once \n", __func__);
+ return;
+ }
+ ehcd = hcidev->priv;
+ ehci_hcd_exit(ehcd);
+ SLOF_free_mem(ehcd, sizeof(*ehcd));
+ hcidev->priv = NULL;
+}
+
+static void ehci_detect(void)
+{
+
+}
+
+static void ehci_disconnect(void)
+{
+
+}
+
+static int ehci_handshake(struct ehci_hcd *ehcd, uint32_t timeout)
+{
+ uint32_t usbsts = 0, time;
+ uint32_t usbcmd;
+ mb();
+ usbcmd = read_reg32(&ehcd->op_regs->usbcmd);
+ /* Ring a doorbell */
+ write_reg32(&ehcd->op_regs->usbcmd, usbcmd | CMD_IAAD);
+ mb();
+ time = SLOF_GetTimer() + timeout;
+ while ((time > SLOF_GetTimer())) {
+ /* Wait for controller to confirm */
+ usbsts = read_reg32(&ehcd->op_regs->usbsts);
+ if (usbsts & STS_IAA) {
+ /* Acknowledge it, for next doorbell to work */
+ write_reg32(&ehcd->op_regs->usbsts, STS_IAA);
+ return true;
+ }
+ cpu_relax();
+ }
+ return false;
+}
+
+static int fill_qtd_buff(struct ehci_qtd *qtd, long data, uint32_t size)
+{
+ long i, rem;
+ long pos = (data + 0x1000) & ~0xfff;
+
+ qtd->buffer[0] = cpu_to_le32(PTR_U32(data));
+ for (i = 1; i < 5; i++) {
+ if ((data + size - 1) >= pos) {
+ //dprintf("data spans page boundary: %d, %p\n", i, pos);
+ qtd->buffer[i] = cpu_to_le32(pos);
+ pos += 0x1000;
+ } else
+ break;
+ }
+ if ((data + size) > pos)
+ rem = data + size - pos;
+ else
+ rem = 0;
+ return rem;
+}
+
+static int ehci_send_ctrl(struct usb_pipe *pipe, struct usb_dev_req *req, void *data)
+{
+ struct ehci_hcd *ehcd;
+ struct ehci_qtd *qtd, *qtds, *qtds_phys;
+ struct ehci_pipe *epipe;
+ uint32_t transfer_size = sizeof(*req);
+ uint32_t datalen, pid;
+ uint32_t time;
+ long req_phys = 0, data_phys = 0;
+ int ret = true;
+
+ if (pipe->type != USB_EP_TYPE_CONTROL) {
+ printf("usb-ehci: Not a control pipe.\n");
+ return false;
+ }
+
+ ehcd = pipe->dev->hcidev->priv;
+ qtds = qtd = SLOF_dma_alloc(sizeof(*qtds) * 3);
+ if (!qtds) {
+ printf("Error allocating qTDs.\n");
+ return false;
+ }
+ qtds_phys = (struct ehci_qtd *)SLOF_dma_map_in(qtds, sizeof(*qtds) * 3, true);
+ memset(qtds, 0, sizeof(*qtds) * 3);
+ req_phys = SLOF_dma_map_in(req, sizeof(struct usb_dev_req), true);
+ qtd->next_qtd = cpu_to_le32(PTR_U32(&qtds_phys[1]));
+ qtd->alt_next_qtd = QH_PTR_TERM;
+ qtd->token = cpu_to_le32((transfer_size << TOKEN_TBTT_SHIFT) |
+ (3 << TOKEN_CERR_SHIFT) |
+ (PID_SETUP << TOKEN_PID_SHIFT) |
+ (QH_STS_ACTIVE << TOKEN_STATUS_SHIFT));
+ fill_qtd_buff(qtd, req_phys, sizeof(*req));
+
+ qtd++;
+ datalen = cpu_to_le16(req->wLength);
+ pid = (req->bmRequestType & REQT_DIR_IN) ? PID_IN : PID_OUT;
+ if (datalen) {
+ data_phys = SLOF_dma_map_in(data, datalen, true);
+ qtd->next_qtd = cpu_to_le32(PTR_U32(&qtds_phys[2]));
+ qtd->alt_next_qtd = QH_PTR_TERM;
+ qtd->token = cpu_to_le32((1 << TOKEN_DT_SHIFT) |
+ (datalen << TOKEN_TBTT_SHIFT) |
+ (3 << TOKEN_CERR_SHIFT) |
+ (pid << TOKEN_PID_SHIFT) |
+ (QH_STS_ACTIVE << TOKEN_STATUS_SHIFT));
+ fill_qtd_buff(qtd, data_phys, datalen);
+ qtd++;
+ }
+
+ if (pid == PID_IN)
+ pid = PID_OUT;
+ else
+ pid = PID_IN;
+ qtd->next_qtd = QH_PTR_TERM;
+ qtd->alt_next_qtd = QH_PTR_TERM;
+ qtd->token = cpu_to_le32((1 << TOKEN_DT_SHIFT) |
+ (3 << TOKEN_CERR_SHIFT) |
+ (pid << TOKEN_PID_SHIFT) |
+ (QH_STS_ACTIVE << TOKEN_STATUS_SHIFT));
+
+ /* link qtd to qh and attach to ehcd */
+ mb();
+ epipe = container_of(pipe, struct ehci_pipe, pipe);
+ epipe->qh.next_qtd = cpu_to_le32(PTR_U32(qtds_phys));
+ epipe->qh.qh_ptr = cpu_to_le32(ehcd->qh_async_phys | EHCI_TYP_QH);
+ epipe->qh.ep_cap1 = cpu_to_le32((pipe->mps << QH_MPS_SHIFT) |
+ (pipe->speed << QH_EPS_SHIFT) |
+ (pipe->epno << QH_EP_SHIFT) |
+ (pipe->dev->addr << QH_DEV_ADDR_SHIFT));
+ mb();
+
+ ehcd->qh_async->qh_ptr = cpu_to_le32(epipe->qh_phys | EHCI_TYP_QH);
+
+ /* transfer data */
+ mb();
+ qtd = &qtds[0];
+ time = SLOF_GetTimer() + USB_TIMEOUT;
+ do {
+ if (le32_to_cpu(qtd->token) & (QH_STS_ACTIVE << TOKEN_STATUS_SHIFT))
+ mb();
+ else
+ qtd++;
+
+ if (time < SLOF_GetTimer()) { /* timed out */
+ printf("usb-ehci: control transfer timed out_\n");
+ ret = false;
+ break;
+ }
+ } while (qtd->next_qtd != QH_PTR_TERM);
+
+ ehcd->qh_async->qh_ptr = cpu_to_le32(ehcd->qh_async_phys | EHCI_TYP_QH);
+ mb();
+ if (!ehci_handshake(ehcd, USB_TIMEOUT)) {
+ printf("%s: handshake failed\n", __func__);
+ ret = false;
+ }
+
+ SLOF_dma_map_out(req_phys, req, sizeof(struct usb_dev_req));
+ SLOF_dma_map_out(data_phys, data, datalen);
+ SLOF_dma_map_out(PTR_U32(qtds_phys), qtds, sizeof(*qtds) * 3);
+ SLOF_dma_free(qtds, sizeof(*qtds) * 3);
+
+ return ret;
+}
+
+static int ehci_transfer_bulk(struct usb_pipe *pipe, void *td, void *td_phys,
+ void *data_phys, int size)
+{
+ struct ehci_hcd *ehcd;
+ struct ehci_qtd *qtd, *qtd_phys;
+ struct ehci_pipe *epipe;
+ uint32_t pid;
+ int i, rem, ret = true;
+ uint32_t time;
+ long ptr;
+
+ dprintf("usb-ehci: bulk transfer: data %p, size %d, td %p, td_phys %p\n",
+ data_phys, size, td, td_phys);
+
+ if (pipe->type != USB_EP_TYPE_BULK) {
+ printf("usb-ehci: Not a bulk pipe.\n");
+ return false;
+ }
+
+ if (size > QTD_MAX_TRANSFER_LEN) {
+ printf("usb-ehci: bulk transfer size too big\n");
+ return false;
+ }
+
+ ehcd = pipe->dev->hcidev->priv;
+ pid = (pipe->dir == USB_PIPE_OUT) ? PID_OUT : PID_IN;
+ qtd = (struct ehci_qtd *)td;
+ qtd_phys = (struct ehci_qtd *)td_phys;
+ ptr = (long)data_phys;
+ for (i = 0; i < NUM_BULK_QTDS; i++) {
+ memset(qtd, 0, sizeof(*qtd));
+ rem = fill_qtd_buff(qtd, ptr, size);
+ qtd->token = cpu_to_le32((1 << TOKEN_DT_SHIFT) |
+ ((size - rem) << TOKEN_TBTT_SHIFT) |
+ (3 << TOKEN_CERR_SHIFT) |
+ (pid << TOKEN_PID_SHIFT) |
+ (QH_STS_ACTIVE << TOKEN_STATUS_SHIFT));
+ if (rem) {
+ qtd->next_qtd = cpu_to_le32(PTR_U32(&qtd_phys[i+1]));
+ qtd->alt_next_qtd = QH_PTR_TERM;
+ ptr += size - rem;
+ size = rem;
+ qtd++;
+ } else {
+ qtd->next_qtd = qtd->alt_next_qtd = QH_PTR_TERM;
+ break; /* no more data */
+ }
+ }
+
+ /* link qtd to qh and attach to ehcd */
+ mb();
+ epipe = container_of(pipe, struct ehci_pipe, pipe);
+ epipe->qh.next_qtd = cpu_to_le32(PTR_U32(qtd_phys));
+ epipe->qh.qh_ptr = cpu_to_le32(ehcd->qh_async_phys | EHCI_TYP_QH);
+ epipe->qh.ep_cap1 = cpu_to_le32((pipe->mps << QH_MPS_SHIFT) |
+ (pipe->speed << QH_EPS_SHIFT) |
+ (pipe->epno << QH_EP_SHIFT) |
+ (pipe->dev->addr << QH_DEV_ADDR_SHIFT));
+ mb();
+
+ ehcd->qh_async->qh_ptr = cpu_to_le32(epipe->qh_phys | EHCI_TYP_QH);
+
+ /* transfer data */
+ mb();
+ qtd = (struct ehci_qtd *)td;
+ for (i = 0; i < NUM_BULK_QTDS; i++) {
+ time = SLOF_GetTimer() + USB_TIMEOUT;
+ while ((time > SLOF_GetTimer()) &&
+ (le32_to_cpu(qtd->token) & (QH_STS_ACTIVE << TOKEN_STATUS_SHIFT)))
+ cpu_relax();
+ mb();
+ if (qtd->next_qtd == QH_PTR_TERM)
+ break;
+
+ if (le32_to_cpu(qtd->token) & (QH_STS_ACTIVE << TOKEN_STATUS_SHIFT)) {
+ printf("usb-ehci: bulk transfer timed out_\n");
+ ret = false;
+ break;
+ }
+ qtd++;
+ }
+
+ ehcd->qh_async->qh_ptr = cpu_to_le32(ehcd->qh_async_phys | EHCI_TYP_QH);
+ mb();
+ if (!ehci_handshake(ehcd, USB_TIMEOUT)) {
+ printf("%s: handshake failed\n", __func__);
+ ret = false;
+ }
+ return ret;
+}
+
+static struct usb_pipe *ehci_get_pipe(struct usb_dev *dev, struct usb_ep_descr *ep,
+ char *buf, size_t len)
+{
+ struct ehci_hcd *ehcd;
+ struct usb_pipe *new = NULL;
+
+ if (!dev)
+ return NULL;
+
+ ehcd = (struct ehci_hcd *)dev->hcidev->priv;
+ if (!ehcd->freelist) {
+ dprintf("usb-ehci: %s allocating pool\n", __func__);
+ if (ehci_alloc_pipe_pool(ehcd))
+ return NULL;
+ }
+
+ new = ehcd->freelist;
+ ehcd->freelist = ehcd->freelist->next;
+ if (!ehcd->freelist)
+ ehcd->end = NULL;
+
+ memset(new, 0, sizeof(*new));
+ new->dev = dev;
+ new->next = NULL;
+ new->type = ep->bmAttributes & USB_EP_TYPE_MASK;
+ new->speed = dev->speed;
+ new->mps = ep->wMaxPacketSize;
+ new->dir = (ep->bEndpointAddress & 0x80) >> 7;
+ new->epno = ep->bEndpointAddress & 0x0f;
+
+ return new;
+}
+
+static void ehci_put_pipe(struct usb_pipe *pipe)
+{
+ struct ehci_hcd *ehcd;
+
+ dprintf("usb-ehci: %s enter - %p\n", __func__, pipe);
+ if (!pipe || !pipe->dev)
+ return;
+ ehcd = pipe->dev->hcidev->priv;
+ if (ehcd->end)
+ ehcd->end->next = pipe;
+ else
+ ehcd->freelist = pipe;
+
+ ehcd->end = pipe;
+ pipe->next = NULL;
+ pipe->dev = NULL;
+ memset(pipe, 0, sizeof(*pipe));
+ dprintf("usb-ehci: %s exit\n", __func__);
+}
+
+struct usb_hcd_ops ehci_ops = {
+ .name = "ehci-hcd",
+ .init = ehci_init,
+ .exit = ehci_exit,
+ .detect = ehci_detect,
+ .disconnect = ehci_disconnect,
+ .get_pipe = ehci_get_pipe,
+ .put_pipe = ehci_put_pipe,
+ .send_ctrl = ehci_send_ctrl,
+ .transfer_bulk = ehci_transfer_bulk,
+ .usb_type = USB_EHCI,
+ .next = NULL,
+};
+
+void usb_ehci_register(void)
+{
+ usb_hcd_register(&ehci_ops);
+}
diff --git a/src/roms/SLOF/lib/libusb/usb-ehci.h b/src/roms/SLOF/lib/libusb/usb-ehci.h
new file mode 100644
index 0000000..2955a9c
--- /dev/null
+++ b/src/roms/SLOF/lib/libusb/usb-ehci.h
@@ -0,0 +1,155 @@
+/******************************************************************************
+ * Copyright (c) 2007, 2012, 2013 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+/*
+ * Definitions for EHCI Controller
+ *
+ */
+
+#ifndef USB_EHCI_H
+#define USB_EHCI_H
+
+#include <stdint.h>
+#include "usb-core.h"
+
+#define FL_SIZE 1024
+
+struct ehci_cap_regs {
+ uint8_t caplength;
+ uint8_t reserved;
+ uint16_t hciversion;
+ uint32_t hcsparams;
+ uint32_t hccparams;
+ uint64_t portroute;
+} __attribute__ ((packed));
+
+struct ehci_op_regs {
+ uint32_t usbcmd;
+ uint32_t usbsts;
+ uint32_t usbintr;
+ uint32_t frindex;
+ uint32_t ctrldssegment;
+ uint32_t periodiclistbase;
+ uint32_t asynclistaddr;
+ uint32_t reserved[9];
+ uint32_t configflag;
+ uint32_t portsc[0];
+} __attribute__ ((packed));
+
+struct ehci_framelist {
+ uint32_t fl_ptr[FL_SIZE];
+} __attribute__ ((packed));
+
+struct ehci_hcd {
+ struct ehci_cap_regs *cap_regs;
+ struct ehci_op_regs *op_regs;
+ struct usb_hcd_dev *hcidev;
+ struct ehci_qh *qh_async;
+ struct ehci_qh *qh_intr;
+ struct usb_pipe *freelist;
+ struct usb_pipe *end;
+ struct ehci_framelist *fl;
+ long qh_async_phys;
+ long qh_intr_phys;
+ long fl_phys;
+ void *pool;
+ long pool_phys;
+};
+
+struct ehci_qtd {
+ uint32_t next_qtd;
+ uint32_t alt_next_qtd;
+ uint32_t token;
+ uint32_t buffer[5];
+} __attribute__ ((packed));
+
+struct ehci_qh {
+ uint32_t qh_ptr;
+ uint32_t ep_cap1;
+ uint32_t ep_cap2;
+ uint32_t curr_qtd;
+ uint32_t next_qtd;
+ uint32_t alt_next_qtd;
+ uint32_t token;
+ uint32_t buffer[5];
+} __attribute__ ((packed)) __attribute__((aligned(32)));
+
+struct ehci_pipe {
+ struct ehci_qh qh;
+ struct usb_pipe pipe;
+ long qh_phys;
+};
+
+#define EHCI_PIPE_POOL_SIZE 4096
+
+#define EHCI_TYP_ITD 0x00
+#define EHCI_TYP_QH 0x02
+#define EHCI_TYP_SITD 0x04
+#define EHCI_TYP_FSTN 0x06
+
+#define PID_OUT 0x00
+#define PID_IN 0x01
+#define PID_SETUP 0x02
+
+#define HCS_NPORTS_MASK 0x000f
+
+#define CMD_IAAD (1 << 6)
+#define CMD_ASE (1 << 5)
+#define CMD_PSE (1 << 4)
+#define CMD_FLS_MASK (3 << 2)
+#define CMD_HCRESET (1 << 1)
+#define CMD_RUN (1 << 0)
+
+#define STS_IAA (1 << 5)
+
+#define PORT_RESET (1 << 8)
+#define PORT_PE (1 << 2)
+#define PORT_CSC (1 << 1)
+#define PORT_CONNECT (1 << 0)
+
+#define QH_LOW_SPEED 0
+#define QH_FULL_SPEED 1
+#define QH_HIGH_SPEED 2
+
+#define QH_RL_SHIFT 28
+#define QH_CAP_C (1 << 27)
+#define QH_MPS_SHIFT 16
+#define QH_CAP_H (1 << 15)
+#define QH_CAP_DTC (1 << 14)
+#define QH_EPS_SHIFT 12
+#define QH_EP_SHIFT 8
+#define QH_CAP_I (1 << 7)
+#define QH_DEV_ADDR_SHIFT 0
+
+#define QH_PTR_TERM __builtin_bswap32(1)
+#define QH_SMASK_SHIFT 0
+#define QH_STS_ACTIVE (1 << 7)
+#define QH_STS_HALTED (1 << 6)
+#define QH_STS_DBE (1 << 5)
+#define QH_STS_BABBLE (1 << 4)
+#define QH_STS_XACTERR (1 << 3)
+#define QH_STS_MMF (1 << 2)
+#define QH_STS_SXS (1 << 1)
+#define QH_STS_PING (1 << 0)
+
+#define NUM_BULK_QTDS 4
+#define MAX_XFER_PER_QTD (20 * 1024)
+#define QTD_MAX_TRANSFER_LEN (NUM_BULK_QTDS * MAX_XFER_PER_QTD)
+
+#define TOKEN_DT_SHIFT 31
+#define TOKEN_TBTT_SHIFT 16
+#define TOKEN_IOC_SHIFT 15
+#define TOKEN_CPAGE_SHIFT 12
+#define TOKEN_CERR_SHIFT 10
+#define TOKEN_PID_SHIFT 8
+#define TOKEN_STATUS_SHIFT 0
+
+#endif /* USB_EHCI_H */
diff --git a/src/roms/SLOF/lib/libusb/usb-hid.c b/src/roms/SLOF/lib/libusb/usb-hid.c
new file mode 100644
index 0000000..ac6616a
--- /dev/null
+++ b/src/roms/SLOF/lib/libusb/usb-hid.c
@@ -0,0 +1,468 @@
+/*****************************************************************************
+ * Copyright (c) 2013 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <stdio.h>
+#include <string.h>
+#include <termctrl.h>
+
+#include "usb-core.h"
+#include "usb-key.h"
+
+/*
+ * HID Spec Version 1.11
+ */
+
+#define HID_REQ_GET_REPORT 0x01
+#define HID_REQ_GET_IDLE 0x02
+#define HID_REQ_GET_PROTOCOL 0x03
+#define HID_REQ_SET_REPORT 0x09
+#define HID_REQ_SET_IDLE 0x0A
+#define HID_REQ_SET_PROTOCOL 0x0B
+
+//key position for latin letters
+#define KEYP_LATIN_A 4
+#define KEYP_LATIN_Z 29
+
+//#define KEY_DEBUG
+
+/* HID SPEC - 7.2.6 Set_Protocol Request */
+static int usb_hid_set_protocol(struct usb_dev *dev, uint16_t value)
+{
+ struct usb_dev_req req;
+ if (!dev)
+ return false;
+ req.bmRequestType = REQT_TYPE_CLASS | REQT_REC_INTERFACE | REQT_DIR_OUT;
+ req.bRequest = HID_REQ_SET_PROTOCOL;
+ req.wValue = cpu_to_le16(value);
+ req.wIndex = cpu_to_le16(dev->intf_num);
+ req.wLength = 0;
+ return usb_send_ctrl(dev->control, &req, NULL);
+}
+
+/* HID SPEC - 7.2.4 Set_Idle Request */
+static int usb_hid_set_idle(struct usb_dev *dev, uint16_t ms_delay)
+{
+ struct usb_dev_req req;
+ if (!dev)
+ return false;
+ req.bmRequestType = REQT_TYPE_CLASS | REQT_REC_INTERFACE | REQT_DIR_OUT;
+ req.bRequest = HID_REQ_SET_IDLE;
+ req.wValue = cpu_to_le16((ms_delay/4) << 8);
+ req.wIndex = cpu_to_le16(dev->intf_num);
+ req.wLength = 0;
+ return usb_send_ctrl(dev->control, &req, NULL);
+}
+
+/* HID SPEC - 7.2.1 Get Report Request */
+static int usb_hid_get_report(struct usb_dev *dev, void *data, size_t size)
+{
+ struct usb_dev_req req;
+ if (!dev)
+ return false;
+ req.bmRequestType = REQT_TYPE_CLASS | REQT_REC_INTERFACE | REQT_DIR_IN;
+ req.bRequest = HID_REQ_GET_REPORT;
+ req.wIndex = cpu_to_le16(dev->intf_num);
+
+ req.wLength = cpu_to_le16((uint16_t)size);
+ req.wValue = cpu_to_le16(1 << 8);
+ return usb_send_ctrl(dev->control, &req, data);
+}
+
+/* ring buffer with RD/WR indices for key buffering */
+static uint8_t keybuf[256]; /* size fixed to byte range ! */
+uint8_t r_ptr = 0; /* RD-index for Keyboard-Buffer */
+uint8_t w_ptr = 0; /* WR-index for Keyboard-Buffer */
+
+/* variables for LED status */
+uint8_t set_leds;
+const uint8_t *key_std = NULL;
+const uint8_t *key_std_shift = NULL;
+
+uint8_t ctrl; /* modifiers */
+
+/**
+ * read character from Keyboard-Buffer
+ *
+ * @param -
+ * @return > 0 Keycode
+ * = 0 if no key available
+ */
+static int read_key(void)
+{
+ if (r_ptr != w_ptr)
+ return (int)keybuf[r_ptr++];
+ else
+ return false;
+}
+
+/**
+ * Store character into Keyboard-Buffer
+ *
+ * @param Key = detected ASCII-Key (> 0)
+ * @return -
+ */
+static void write_key(uint8_t key)
+{
+ if ((w_ptr + 1) != r_ptr)
+ keybuf[w_ptr++] = key;
+}
+
+/**
+ * Checks if keypos is a latin key
+ * @param keypos
+ * @return -
+ */
+static bool is_latin(uint8_t keypos)
+{
+ return keypos >= KEYP_LATIN_A && keypos <= KEYP_LATIN_Z;
+}
+
+/**
+ * Convert keyboard usage-ID to ANSI-Code
+ *
+ * @param Ctrl=Modifier Byte
+ * Key =Usage ID from USB Keyboard
+ * @return -
+ */
+static void get_char(uint8_t ctrl, uint8_t keypos)
+{
+ uint8_t ch;
+ bool caps = false;
+
+#ifdef KEY_DEBUG
+ printf("pos %02X\n", keypos);
+#endif
+
+ if (set_leds & LED_CAPS_LOCK) /* is CAPS Lock set ? */
+ caps = true;
+
+ /* caps is a shift only for latin chars */
+ if ((!caps && ctrl == 0) || (caps && !is_latin(keypos))) {
+ ch = key_std[keypos];
+ if (ch != 0)
+ write_key(ch);
+ return;
+ }
+
+ if ((ctrl & MODIFIER_SHIFT) || caps) {
+ ch = key_std_shift[keypos];
+ if (ch != 0)
+ write_key(ch);
+ return;
+ }
+
+ if (ctrl & MODIFIER_CTRL) {
+ ch = keycodes_ctrl[keypos];
+ if (ch != 0)
+ write_key(ch);
+ return;
+ }
+
+ if (ctrl == MODIFIER_ALT_GR) {
+ ch = keycodes_alt_GR[keypos];
+ if (ch != 0)
+ write_key(ch);
+ return;
+ }
+}
+
+static void check_key_code(uint8_t *buf)
+{
+ static uint8_t key_last[6]; /* list of processed keys */
+ uint8_t i, j, key_pos;
+
+ /* set translation table to defaults */
+ if ((key_std == NULL) || (key_std_shift == NULL)) {
+ key_std = keycodes_std_US;
+ key_std_shift = keycodes_shift_US;
+ }
+
+ if (buf[0] & MODIFIER_SHIFT) /* any shift key pressed ? */
+ set_leds &= ~LED_CAPS_LOCK; /* CAPS-LOCK-LED always off */
+
+ i = 2; /* skip modifier byte and reserved byte */
+ while (i < 8) {
+ key_pos = buf[i];
+ if ((key_pos != 0) && (key_pos <= 100)) { /* support for 101 keys */
+ j = 0;
+ /* search if already processed */
+ while ((j < 6) && (key_pos != key_last[j]))
+ j++;
+
+ if (j >= 6) { /* not found (= not processed) */
+ switch (key_pos) {
+ case 0x39: /* caps-lock key ? */
+ case 0x32: /* caps-lock key ? */
+ set_leds ^= LED_CAPS_LOCK;
+ break;
+
+ case 0x36: /*Shift pressed*/
+ ctrl |= MODIFIER_SHIFT;
+ break;
+ case 0xb6: /*Shift unpressed*/
+ ctrl &= ~MODIFIER_SHIFT;
+ break;
+ case 0x3a: /* F1 */
+ write_key(0x1b);
+ write_key(0x5b);
+ write_key(0x4f);
+ write_key(0x50);
+ break;
+
+ case 0x3b: /* F2 */
+ write_key(0x1b);
+ write_key(0x5b);
+ write_key(0x4f);
+ write_key(0x51);
+ break;
+
+ case 0x3c:
+ write_key(0x1b); /* F3 */
+ write_key(0x5b);
+ write_key(0x4f);
+ write_key(0x52);
+ break;
+
+ case 0x3d:
+ write_key(0x1b); /* F4 */
+ write_key(0x5b);
+ write_key(0x4f);
+ write_key(0x53);
+ break;
+
+ case 0x3e:
+ write_key(0x1b); /* F5 */
+ write_key(0x5b);
+ write_key(0x31);
+ write_key(0x35);
+ write_key(0x7e);
+ break;
+
+ case 0x3f:
+ write_key(0x1b); /* F6 */
+ write_key(0x5b);
+ write_key(0x31);
+ write_key(0x37);
+ write_key(0x7e);
+ break;
+
+ case 0x40:
+ write_key(0x1b); /* F7 */
+ write_key(0x5b);
+ write_key(0x31);
+ write_key(0x38);
+ write_key(0x7e);
+ break;
+
+ case 0x41:
+ write_key(0x1b); /* F8 */
+ write_key(0x5b);
+ write_key(0x31);
+ write_key(0x39);
+ write_key(0x7e);
+ break;
+
+ case 0x42:
+ write_key(0x1b); /* F9 */
+ write_key(0x5b);
+ write_key(0x32);
+ write_key(0x30);
+ write_key(0x7e);
+ break;
+
+ case 0x43:
+ write_key(0x1b); /* F10 */
+ write_key(0x5b);
+ write_key(0x32);
+ write_key(0x31);
+ write_key(0x7e);
+ break;
+
+ case 0x44:
+ write_key(0x1b); /* F11 */
+ write_key(0x5b);
+ write_key(0x32);
+ write_key(0x33);
+ write_key(0x7e);
+ break;
+
+ case 0x45:
+ write_key(0x1b); /* F12 */
+ write_key(0x5b);
+ write_key(0x32);
+ write_key(0x34);
+ write_key(0x7e);
+ break;
+
+ case 0x47: /* scroll-lock key ? */
+ set_leds ^= LED_SCROLL_LOCK;
+ break;
+
+ case 0x49:
+ write_key(0x1b); /* INS */
+ write_key(0x5b);
+ write_key(0x32);
+ write_key(0x7e);
+ break;
+
+ case 0x4a:
+ write_key(0x1b); /* HOME */
+ write_key(0x4f);
+ write_key(0x48);
+ break;
+
+ case 0x4b:
+ write_key(0x1b); /* PgUp */
+ write_key(0x5b);
+ write_key(0x35);
+ write_key(0x7e);
+ break;
+
+ case 0x4c:
+ write_key(0x1b); /* DEL */
+ write_key(0x5b);
+ write_key(0x33);
+ write_key(0x7e);
+ break;
+
+ case 0x4d:
+ write_key(0x1b); /* END */
+ write_key(0x4f);
+ write_key(0x46);
+ break;
+
+ case 0x4e:
+ write_key(0x1b); /* PgDn */
+ write_key(0x5b);
+ write_key(0x36);
+ write_key(0x7e);
+ break;
+
+ case 0x4f:
+ write_key(0x1b); /* R-Arrow */
+ write_key(0x5b);
+ write_key(0x43);
+ break;
+
+ case 0x50:
+ write_key(0x1b); /* L-Arrow */
+ write_key(0x5b);
+ write_key(0x44);
+ break;
+
+ case 0x51:
+ write_key(0x1b); /* D-Arrow */
+ write_key(0x5b);
+ write_key(0x42);
+ break;
+
+ case 0x52:
+ write_key(0x1b); /* U-Arrow */
+ write_key(0x5b);
+ write_key(0x41);
+ break;
+
+ case 0x53: /* num-lock key ? */
+ set_leds ^= LED_NUM_LOCK;
+ break;
+
+ default:
+ /* convert key position to ASCII code */
+ get_char(buf[0], key_pos);
+ break;
+ }
+ }
+ }
+ i++;
+ }
+ /*****************************************/
+ /* all keys are processed, create a copy */
+ /* to flag them as processed */
+ /*****************************************/
+ for (i = 2, j = 0; j < 6; i++, j++)
+ key_last[j] = buf[i]; /* copy all actual keys to last */
+}
+
+#define USB_HID_SIZE 128
+uint32_t *kbd_buffer;
+
+int usb_hid_kbd_init(struct usb_dev *dev)
+{
+ int i;
+ uint8_t key[8];
+
+ usb_hid_set_protocol(dev, 0);
+ usb_hid_set_idle(dev, 500);
+
+ memset(key, 0, 8);
+ if (usb_hid_get_report(dev, key, 8))
+ check_key_code(key);
+
+ kbd_buffer = SLOF_dma_alloc(USB_HID_SIZE);
+ if (!kbd_buffer) {
+ printf("%s: unable to allocate keyboard buffer\n", __func__);
+ return false;
+ }
+
+#ifdef KEY_DEBUG
+ printf("HID kbd init %d\n", dev->ep_cnt);
+#endif
+ for (i = 0; i < dev->ep_cnt; i++) {
+ if ((dev->ep[i].bmAttributes & USB_EP_TYPE_MASK)
+ == USB_EP_TYPE_INTR)
+ usb_dev_populate_pipe(dev, &dev->ep[i], kbd_buffer, USB_HID_SIZE);
+ }
+ return true;
+}
+
+int usb_hid_kbd_exit(struct usb_dev *dev)
+{
+ if (dev->intr) {
+ usb_put_pipe(dev->intr);
+ dev->intr = NULL;
+ }
+ SLOF_dma_free(kbd_buffer, USB_HID_SIZE);
+ return true;
+}
+
+static int usb_poll_key(void *vdev)
+{
+ struct usb_dev *dev = vdev;
+ uint8_t key[8];
+ int rc;
+
+ memset(key, 0, 8);
+ rc = usb_poll_intr(dev->intr, key);
+ if (rc)
+ check_key_code(key);
+ return rc;
+}
+
+unsigned char usb_key_available(void *dev)
+{
+ if (!dev)
+ return false;
+
+ usb_poll_key(dev);
+ if (r_ptr != w_ptr)
+ return true;
+ else
+ return false;
+}
+
+unsigned char usb_read_keyb(void *vdev)
+{
+ if (usb_key_available(vdev))
+ return read_key();
+ else
+ return 0;
+}
diff --git a/src/roms/SLOF/lib/libusb/usb-hub.c b/src/roms/SLOF/lib/libusb/usb-hub.c
new file mode 100644
index 0000000..7059cd0
--- /dev/null
+++ b/src/roms/SLOF/lib/libusb/usb-hub.c
@@ -0,0 +1,183 @@
+/*****************************************************************************
+ * Copyright (c) 2013 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <stdio.h>
+#include <string.h>
+#include "usb-core.h"
+
+#undef HUB_DEBUG
+//#define HUB_DEBUG
+#ifdef HUB_DEBUG
+#define dprintf(_x ...) do { printf(_x); } while(0)
+#else
+#define dprintf(_x ...)
+#endif
+
+/*
+ * USB Spec 1.1
+ * 11.16.2 Class-specific Requests
+ */
+struct usb_hub_ps {
+ uint16_t wPortStatus;
+ uint16_t wPortChange;
+} __attribute__((packed));
+
+#define HUB_PS_CONNECTION (1 << 0)
+#define HUB_PS_ENABLE (1 << 1)
+#define HUB_PS_SUSPEND (1 << 2)
+#define HUB_PS_OVER_CURRENT (1 << 3)
+#define HUB_PS_RESET (1 << 4)
+#define HUB_PS_POWER (1 << 8)
+#define HUB_PS_LOW_SPEED (1 << 9)
+
+#define HUB_PF_CONNECTION 0
+#define HUB_PF_ENABLE 1
+#define HUB_PF_SUSPEND 2
+#define HUB_PF_OVER_CURRENT 3
+#define HUB_PF_RESET 4
+#define HUB_PF_POWER 8
+#define HUB_PF_LOWSPEED 9
+#define HUB_PF_C_CONNECTION 16
+#define HUB_PF_C_ENABLE 17
+#define HUB_PF_C_SUSPEND 18
+#define HUB_PF_C_OVER_CURRENT 19
+#define HUB_PF_C_RESET 20
+
+static int usb_get_hub_desc(struct usb_dev *dev, void *data, size_t size)
+{
+ struct usb_dev_req req;
+ if (!dev)
+ return false;
+ req.bmRequestType = REQT_DIR_IN | REQT_TYPE_CLASS | REQT_REC_DEVICE;
+ req.bRequest = REQ_GET_DESCRIPTOR;
+ req.wIndex = 0;
+ req.wLength = cpu_to_le16((uint16_t) size);
+ req.wValue = cpu_to_le16(DESCR_TYPE_HUB << 8);
+ return usb_send_ctrl(dev->control, &req, data);
+}
+
+static int hub_get_port_status(struct usb_dev *dev, int port, void *data, size_t size)
+{
+ struct usb_dev_req req;
+ if (!dev)
+ return false;
+ req.bmRequestType = REQT_DIR_IN | REQT_TYPE_CLASS | REQT_REC_OTHER;
+ req.bRequest = REQ_GET_STATUS;
+ req.wValue = 0;
+ req.wIndex = cpu_to_le16((uint16_t)(port + 1));
+ req.wLength = cpu_to_le16((uint16_t)size);
+ return usb_send_ctrl(dev->control, &req, data);
+}
+
+static int hub_set_port_feature(struct usb_dev *dev, int port, int feature)
+{
+ struct usb_dev_req req;
+ if (!dev)
+ return false;
+ req.bmRequestType = REQT_DIR_OUT | REQT_TYPE_CLASS | REQT_REC_OTHER;
+ req.bRequest = REQ_SET_FEATURE;
+ req.wLength = 0;
+ req.wValue = cpu_to_le16((uint16_t)feature);
+ req.wIndex = cpu_to_le16((uint16_t)(port + 1));
+ return usb_send_ctrl(dev->control, &req, NULL);
+}
+
+#if 0
+static int hub_clear_port_feature(struct usb_dev *dev, int port, int feature)
+{
+ struct usb_dev_req req;
+ if (!dev)
+ return false;
+ req.bmRequestType = REQT_DIR_OUT | REQT_TYPE_CLASS | REQT_REC_OTHER;
+ req.bRequest = REQ_CLEAR_FEATURE;
+ req.wLength = 0;
+ req.wValue = cpu_to_le16((uint16_t)feature);
+ req.wIndex = cpu_to_le16((uint16_t)(port + 1));
+ return usb_send_ctrl(dev->control, &req, NULL);
+}
+#endif
+
+static int hub_check_port(struct usb_dev *dev, int port)
+{
+ struct usb_hub_ps ps;
+ uint32_t time;
+
+ if (!hub_get_port_status(dev, port, &ps, sizeof(ps)))
+ return false;
+ dprintf("Port Status %04X Port Change %04X\n",
+ le16_to_cpu(ps.wPortStatus),
+ le16_to_cpu(ps.wPortChange));
+
+ if (!(le16_to_cpu(ps.wPortStatus) & HUB_PS_POWER)) {
+ hub_set_port_feature(dev, port, HUB_PF_POWER);
+ SLOF_msleep(100);
+ time = SLOF_GetTimer() + USB_TIMEOUT;
+ while (time > SLOF_GetTimer()) {
+ cpu_relax();
+ hub_get_port_status(dev, port, &ps, sizeof(ps));
+ if (le16_to_cpu(ps.wPortStatus) & HUB_PS_CONNECTION) {
+ dprintf("power on Port Status %04X Port Change %04X\n",
+ le16_to_cpu(ps.wPortStatus),
+ le16_to_cpu(ps.wPortChange));
+ break;
+ }
+ }
+ }
+
+ if (le16_to_cpu(ps.wPortStatus) & HUB_PS_CONNECTION) {
+ hub_set_port_feature(dev, port, HUB_PF_RESET);
+ SLOF_msleep(100);
+ time = SLOF_GetTimer() + USB_TIMEOUT;
+ while (time > SLOF_GetTimer()) {
+ cpu_relax();
+ hub_get_port_status(dev, port, &ps, sizeof(ps));
+ if (!(le16_to_cpu(ps.wPortStatus) & HUB_PS_RESET)) {
+ dprintf("reset Port Status %04X Port Change %04X\n",
+ le16_to_cpu(ps.wPortStatus),
+ le16_to_cpu(ps.wPortChange));
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+unsigned int usb_hub_init(void *hubdev)
+{
+ struct usb_dev *dev = hubdev;
+ struct usb_dev_hub_descr hub;
+ struct usb_dev *newdev;
+ int i;
+
+ dprintf("%s: enter %p\n", __func__, dev);
+ if (!dev) {
+ printf("usb-hub: NULL\n");
+ return false;
+ }
+ memset(&hub, 0, sizeof(hub));
+ usb_get_hub_desc(dev, &hub, sizeof(hub));
+ dprintf("usb-hub: ports connected %d\n", hub.bNbrPorts);
+ for (i = 0; i < hub.bNbrPorts; i++) {
+ dprintf("usb-hub: ports scanning %d\n", i);
+ if (hub_check_port(dev, i)) {
+ dprintf("***********************************************\n");
+ dprintf("\t\tusb-hub: device found %d\n", i);
+ dprintf("***********************************************\n");
+ newdev = usb_devpool_get();
+ dprintf("usb-hub: allocated device %p\n", newdev);
+ newdev->hcidev = dev->hcidev;
+ if (!setup_new_device(newdev, i))
+ printf("usb-hub: unable to setup device on port %d\n", i);
+ }
+ }
+ return true;
+}
diff --git a/src/roms/SLOF/lib/libusb/usb-key.c b/src/roms/SLOF/lib/libusb/usb-key.c
new file mode 100644
index 0000000..7fb45da
--- /dev/null
+++ b/src/roms/SLOF/lib/libusb/usb-key.c
@@ -0,0 +1,446 @@
+/*****************************************************************************
+ * Copyright (c) 2013 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <stdint.h>
+
+/***********************************/
+/* Keycodes for US Keyboard */
+/* - no control keys pressed - */
+/***********************************/
+const uint8_t keycodes_std_US[] = {
+ 0, /* 0 00 Reserved (no event indicated) */
+ 0, /* 1 01 Keyboard ErrorRollOver */
+ 0, /* 2 02 Keyboard POSTFail */
+ 0, /* 3 03 Keyboard ErrorUndefined */
+ 'a', /* 4 04 Keyboard a and A 31 */
+ 'b', /* 5 05 Keyboard b and B 50 */
+ 'c', /* 6 06 Keyboard c and C 48 */
+ 'd', /* 7 07 Keyboard d and D 33 */
+ 'e', /* 8 08 Keyboard e and E 19 */
+ 'f', /* 9 09 Keyboard f and F 34 */
+ 'g', /* 10 0A Keyboard g and G 35 */
+ 'h', /* 11 0B Keyboard h and H 36 */
+ 'i', /* 12 0C Keyboard i and I 24 */
+ 'j', /* 13 0D Keyboard j and J 37 */
+ 'k', /* 14 0E Keyboard k and K 38 */
+ 'l', /* 15 0F Keyboard l and L 39 */
+ 'm', /* 16 10 Keyboard m and M 52 */
+ 'n', /* 17 11 Keyboard n and N 51 */
+ 'o', /* 18 12 Keyboard o and O 25 */
+ 'p', /* 19 13 Keyboard p and P 26 */
+ 'q', /* 20 14 Keyboard q and Q 17 */
+ 'r', /* 21 15 Keyboard r and R 20 */
+ 's', /* 22 16 Keyboard s and S 32 */
+ 't', /* 23 17 Keyboard t and T 21 */
+ 'u', /* 24 18 Keyboard u and U 23 */
+ 'v', /* 25 19 Keyboard v and V 49 */
+ 'w', /* 26 1A Keyboard w and W 18 */
+ 'x', /* 27 1B Keyboard x and X 47 */
+ 'y', /* 28 1C Keyboard y and Y 22 */
+ 'z', /* 29 1D Keyboard z and Z 46 */
+ '1', /* 30 1E Keyboard 1 and ! 2 */
+ '2', /* 31 1F Keyboard 2 and @ 3 */
+ '3', /* 32 20 Keyboard 3 and # 4 */
+ '4', /* 33 21 Keyboard 4 and $ 5 */
+ '5', /* 34 22 Keyboard 5 and % 6 */
+ '6', /* 35 23 Keyboard 6 and ^ 7 */
+ '7', /* 36 24 Keyboard 7 and & 8 */
+ '8', /* 37 25 Keyboard 8 and * 9 */
+ '9', /* 38 26 Keyboard 9 and ( 10 */
+ '0', /* 39 27 Keyboard 0 and ) 11 */
+ 13, /* 40 28 Keyboard Return (ENTER) 43 */
+ 27, /* 41 29 Keyboard ESCAPE 110 */
+ 8, /* 42 2A Keyboard DELETE (BS) 15 */
+ 9, /* 43 2B Keyboard Tab 16 */
+ ' ', /* 44 2C Keyboard Spacebar 61 */
+ '-', /* 45 2D Keyboard - and (underscore) 12 */
+ '=', /* 46 2E Keyboard = and + 13 */
+ '[', /* 47 2F Keyboard [ and { 27 */
+ ']', /* 48 30 Keyboard ] and } 28 */
+ '\\', /* 49 31 Keyboard \ and | 29 */
+ '\\', /* 50 32 Keyboard \ and | 42 */
+ ';', /* 51 33 Keyboard ; and : 40 */
+ 39, /* 52 34 Keyboard ' and " 41 */
+ 96, /* 53 35 Keyboard Grave Accent and Tilde 1 */
+ ',', /* 54 36 Keyboard , and < 53 */
+ '.', /* 55 37 Keyboard . and > 54 */
+ '/', /* 56 38 Keyboard / and ? 55 */
+ 0, /* 57 39 Keyboard Caps Lock 30 */
+ 0, /* 58 3A Keyboard F1 112 */
+ 0, /* 59 3B Keyboard F2 113 */
+ 0, /* 60 3C Keyboard F3 114 */
+ 0, /* 61 3D Keyboard F4 115 */
+ 0, /* 62 3E Keyboard F5 116 */
+ 0, /* 63 3F Keyboard F6 117 */
+ 0, /* 64 40 Keyboard F7 118 */
+ 0, /* 65 41 Keyboard F8 119 */
+ 0, /* 66 42 Keyboard F9 120 */
+ 0, /* 67 43 Keyboard F10 121 */
+ 0, /* 68 44 Keyboard F11 122 */
+ 0, /* 69 45 Keyboard F12 123 */
+ 0, /* 70 46 Keyboard PrintScreen 124 */
+ 0, /* 71 47 Keyboard Scroll Lock 125 */
+ 0, /* 72 48 Keyboard Pause 126 */
+ 0, /* 73 49 Keyboard Insert 75 */
+ 0, /* 74 4A Keyboard Home 80 */
+ 0, /* 75 4B Keyboard PageUp 85 */
+ 0, /* 76 4C Keyboard Delete Forward 76 */
+ 0, /* 77 4D Keyboard End 81 */
+ 0, /* 78 4E Keyboard PageDown 86 */
+ 0, /* 79 4F Keyboard RightArrow 89 */
+ 0, /* 80 50 Keyboard LeftArrow 79 */
+ 0, /* 81 51 Keyboard DownArrow 84 */
+ 0, /* 82 52 Keyboard UpArrow 83 */
+ 0, /* 83 53 Keypad Num Lock and Clear 90 */
+ '/', /* 84 54 Keypad / 95 */
+ '*', /* 85 55 Keypad * 100 */
+ '-', /* 86 56 Keypad - 105 */
+ '+', /* 87 57 Keypad + 106 */
+ 13, /* 88 58 Keypad ENTER 108 */
+ '1', /* 89 59 Keypad 1 and End 93 */
+ '2', /* 90 5A Keypad 2 and Down Arrow 98 */
+ '3', /* 91 5B Keypad 3 and PageDn 103 */
+ '4', /* 92 5C Keypad 4 and Left Arrow 92 */
+ '5', /* 93 5D Keypad 5 97 */
+ '6', /* 94 5E Keypad 6 and Right Arrow 102 */
+ '7', /* 95 5F Keypad 7 and Home 91 */
+ '8', /* 96 60 Keypad 8 and Up Arrow 96 */
+ '9', /* 97 61 Keypad 9 and PageUp 101 */
+ '0', /* 98 62 Keypad 0 and Insert 99 */
+ '.', /* 99 63 Keypad . and Delete 104 */
+ '\\' /* 100 64 Keyboard Non-US \ and | 45 */
+};
+
+/***********************************/
+/* Keycodes for US Keyboard */
+/* - SHIFT-KEY pressed - */
+/***********************************/
+const uint8_t keycodes_shift_US[] = {
+ 0, /* 0 00 Reserved (no event indicated) */
+ 0, /* 1 01 Keyboard ErrorRollOver */
+ 0, /* 2 02 Keyboard POSTFail */
+ 0, /* 3 03 Keyboard ErrorUndefined */
+ 'A', /* 4 04 Keyboard a and A 31 */
+ 'B', /* 5 05 Keyboard b and B 50 */
+ 'C', /* 6 06 Keyboard c and C 48 */
+ 'D', /* 7 07 Keyboard d and D 33 */
+ 'E', /* 8 08 Keyboard e and E 19 */
+ 'F', /* 9 09 Keyboard f and F 34 */
+ 'G', /* 10 0A Keyboard g and G 35 */
+ 'H', /* 11 0B Keyboard h and H 36 */
+ 'I', /* 12 0C Keyboard i and I 24 */
+ 'J', /* 13 0D Keyboard j and J 37 */
+ 'K', /* 14 0E Keyboard k and K 38 */
+ 'L', /* 15 0F Keyboard l and L 39 */
+ 'M', /* 16 10 Keyboard m and M 52 */
+ 'N', /* 17 11 Keyboard n and N 51 */
+ 'O', /* 18 12 Keyboard o and O 25 */
+ 'P', /* 19 13 Keyboard p and P 26 */
+ 'Q', /* 20 14 Keyboard q and Q 17 */
+ 'R', /* 21 15 Keyboard r and R 20 */
+ 'S', /* 22 16 Keyboard s and S 32 */
+ 'T', /* 23 17 Keyboard t and T 21 */
+ 'U', /* 24 18 Keyboard u and U 23 */
+ 'V', /* 25 19 Keyboard v and V 49 */
+ 'W', /* 26 1A Keyboard w and W 18 */
+ 'X', /* 27 1B Keyboard x and X 47 */
+ 'Y', /* 28 1C Keyboard y and Y 22 */
+ 'Z', /* 29 1D Keyboard z and Z 46 */
+ '!', /* 30 1E Keyboard 1 and ! 2 */
+ '@', /* 31 1F Keyboard 2 and @ 3 */
+ '#', /* 32 20 Keyboard 3 and # 4 */
+ '$', /* 33 21 Keyboard 4 and $ 5 */
+ '%', /* 34 22 Keyboard 5 and % 6 */
+ '^', /* 35 23 Keyboard 6 and ^ 7 */
+ '&', /* 36 24 Keyboard 7 and & 8 */
+ '*', /* 37 25 Keyboard 8 and * 9 */
+ '(', /* 38 26 Keyboard 9 and ( 10 */
+ ')', /* 39 27 Keyboard 0 and ) 11 */
+ 13, /* 40 28 Keyboard Return (ENTER) 43 */
+ 27, /* 41 29 Keyboard ESCAPE 110 */
+ 8, /* 42 2A Keyboard DELETE (BS) 15 */
+ 9, /* 43 2B Keyboard Tab 16 */
+ ' ', /* 44 2C Keyboard Spacebar 61 */
+ '_', /* 45 2D Keyboard - and (underscore) 12 */
+ '+', /* 46 2E Keyboard = and + 13 */
+ '{', /* 47 2F Keyboard [ and { 27 */
+ '}', /* 48 30 Keyboard ] and } 28 */
+ '|', /* 49 31 Keyboard \ and | 29 */
+ '|', /* 50 32 Keyboard \ and | 42 */
+ ':', /* 51 33 Keyboard ; and : 40 */
+ '"', /* 52 34 Keyboard ' and " 41 */
+ '~', /* 53 35 Keyboard Grave Accent and Tilde 1 */
+ '<', /* 54 36 Keyboard , and < 53 */
+ '>', /* 55 37 Keyboard . and > 54 */
+ '?', /* 56 38 Keyboard / and ? 55 */
+ 0, /* 57 39 Keyboard Caps Lock 30 */
+ 0, /* 58 3A Keyboard F1 112 */
+ 0, /* 59 3B Keyboard F2 113 */
+ 0, /* 60 3C Keyboard F3 114 */
+ 0, /* 61 3D Keyboard F4 115 */
+ 0, /* 62 3E Keyboard F5 116 */
+ 0, /* 63 3F Keyboard F6 117 */
+ 0, /* 64 40 Keyboard F7 118 */
+ 0, /* 65 41 Keyboard F8 119 */
+ 0, /* 66 42 Keyboard F9 120 */
+ 0, /* 67 43 Keyboard F10 121 */
+ 0, /* 68 44 Keyboard F11 122 */
+ 0, /* 69 45 Keyboard F12 123 */
+ 0, /* 70 46 Keyboard PrintScreen 124 */
+ 0, /* 71 47 Keyboard Scroll Lock 125 */
+ 0, /* 72 48 Keyboard Pause 126 */
+ 48, /* 73 49 Keyboard Insert 75 */
+ 55, /* 74 4A Keyboard Home 80 */
+ 57, /* 75 4B Keyboard PageUp 85 */
+ 46, /* 76 4C Keyboard Delete Forward 76 */
+ 49, /* 77 4D Keyboard End 81 */
+ 51, /* 78 4E Keyboard PageDown 86 */
+ 54, /* 79 4F Keyboard RightArrow 89 */
+ 52, /* 80 50 Keyboard LeftArrow 79 */
+ 50, /* 81 51 Keyboard DownArrow 84 */
+ 56, /* 82 52 Keyboard UpArrow 83 */
+ 0, /* 83 53 Keypad Num Lock and Clear 90 */
+ '/', /* 84 54 Keypad / 95 */
+ '*', /* 85 55 Keypad * 100 */
+ '-', /* 86 56 Keypad - 105 */
+ '+', /* 87 57 Keypad + 106 */
+ 13, /* 88 58 Keypad ENTER 108 */
+ '1', /* 89 59 Keypad 1 and End 93 */
+ '2', /* 90 5A Keypad 2 and Down Arrow 98 */
+ '3', /* 91 5B Keypad 3 and PageDn 103 */
+ '4', /* 92 5C Keypad 4 and Left Arrow 92 */
+ '5', /* 93 5D Keypad 5 97 */
+ '6', /* 94 5E Keypad 6 and Right Arrow 102 */
+ '7', /* 95 5F Keypad 7 and Home 91 */
+ '8', /* 96 60 Keypad 8 and Up Arrow 96 */
+ '9', /* 97 61 Keypad 9 and PageUp 101 */
+ '0', /* 98 62 Keypad 0 and Insert 99 */
+ '.', /* 99 63 Keypad . and Delete 104 */
+ '|' /* 100 64 Keyboard Non-US \ and | 45 */
+};
+
+/***********************************/
+/* Keycodes for 1 byte translation */
+/* - CONTROL-KEY pressed - */
+/***********************************/
+const uint8_t keycodes_alt_GR[] = {
+ 0, /* 0 00 Reserved (no event indicated) */
+ 0, /* 1 01 Keyboard ErrorRollOver */
+ 0, /* 2 02 Keyboard POSTFail */
+ 0, /* 3 03 Keyboard ErrorUndefined */
+ 0, /* 4 04 Keyboard a and A 31 */
+ 0, /* 5 05 Keyboard b and B 50 */
+ 0, /* 6 06 Keyboard c and C 48 */
+ 0, /* 7 07 Keyboard d and D 33 */
+ 0, /* 8 08 Keyboard e and E 19 */
+ 0, /* 9 09 Keyboard f and F 34 */
+ 0, /* 10 0A Keyboard g and G 35 */
+ 0, /* 11 0B Keyboard h and H 36 */
+ 0, /* 12 0C Keyboard i and I 24 */
+ 0, /* 13 0D Keyboard j and J 37 */
+ 0, /* 14 0E Keyboard k and K 38 */
+ 0, /* 15 0F Keyboard l and L 39 */
+ 0, /* 16 10 Keyboard m and M 52 */
+ 0, /* 17 11 Keyboard n and N 51 */
+ 0, /* 18 12 Keyboard o and O 25 */
+ 0, /* 19 13 Keyboard p and P 26 */
+ '@', /* 20 14 Keyboard q and Q 17 */
+ 0, /* 21 15 Keyboard r and R 20 */
+ 0, /* 22 16 Keyboard s and S 32 */
+ 0, /* 23 17 Keyboard t and T 21 */
+ 0, /* 24 18 Keyboard u and U 23 */
+ 0, /* 25 19 Keyboard v and V 49 */
+ 0, /* 26 1A Keyboard w and W 18 */
+ 0, /* 27 1B Keyboard x and X 47 */
+ 0, /* 28 1C Keyboard y and Y 22 */
+ 0, /* 29 1D Keyboard z and Z 46 */
+ 0, /* 30 1E Keyboard 1 and ! 2 */
+ 0, /* 31 1F Keyboard 2 and @ 3 */
+ 0, /* 32 20 Keyboard 3 and # 4 */
+ 0, /* 33 21 Keyboard 4 and $ 5 */
+ 0, /* 34 22 Keyboard 5 and % 6 */
+ 0, /* 35 23 Keyboard 6 and ^ 7 */
+ '{', /* 36 24 Keyboard 7 and & 8 */
+ '[', /* 37 25 Keyboard 8 and * 9 */
+ ']', /* 38 26 Keyboard 9 and ( 10 */
+ '}', /* 39 27 Keyboard 0 and ) 11 */
+ 0, /* 40 28 Keyboard Return (ENTER) 43 */
+ 0, /* 41 29 Keyboard ESCAPE 110 */
+ 0, /* 42 2A Keyboard DELETE (BS) 15 */
+ 0, /* 43 2B Keyboard Tab 16 */
+ 0, /* 44 2C Keyboard Spacebar 61 */
+ '\\', /* 45 2D Keyboard - and (underscore) 12 */
+ 0, /* 46 2E Keyboard = and + 13 */
+ 0, /* 47 2F Keyboard [ and { 27 */
+ '~', /* 48 30 Keyboard ] and } 28 */
+ 0, /* 49 31 Keyboard \ and | 29 */
+ 0, /* 50 32 Keyboard Non-US # and ~ 42 */
+ 0, /* 51 33 Keyboard ; and : 40 */
+ 0, /* 52 34 Keyboard ' and " 41 */
+ 0, /* 53 35 Keyboard Grave Accent and Tilde 1 */
+ 0, /* 54 36 Keyboard , and < 53 */
+ 0, /* 55 37 Keyboard . and > 54 */
+ 0, /* 56 38 Keyboard / and ? 55 */
+ 0, /* 57 39 Keyboard Caps Lock 30 */
+ 0, /* 58 3A Keyboard F1 112 */
+ 0, /* 59 3B Keyboard F2 113 */
+ 0, /* 60 3C Keyboard F3 114 */
+ 0, /* 61 3D Keyboard F4 115 */
+ 0, /* 62 3E Keyboard F5 116 */
+ 0, /* 63 3F Keyboard F6 117 */
+ 0, /* 64 40 Keyboard F7 118 */
+ 0, /* 65 41 Keyboard F8 119 */
+ 0, /* 66 42 Keyboard F9 120 */
+ 0, /* 67 43 Keyboard F10 121 */
+ 0, /* 68 44 Keyboard F11 122 */
+ 0, /* 69 45 Keyboard F12 123 */
+ 0, /* 70 46 Keyboard PrintScreen 124 */
+ 0, /* 71 47 Keyboard Scroll Lock 125 */
+ 0, /* 72 48 Keyboard Pause 126 */
+ 0, /* 73 49 Keyboard Insert 75 */
+ 0, /* 74 4A Keyboard Home 80 */
+ 0, /* 75 4B Keyboard PageUp 85 */
+ 0, /* 76 4C Keyboard Delete Forward 76 */
+ 0, /* 77 4D Keyboard End 81 */
+ 0, /* 78 4E Keyboard PageDown 86 */
+ 0, /* 79 4F Keyboard RightArrow 89 */
+ 0, /* 80 50 Keyboard LeftArrow 79 */
+ 0, /* 81 51 Keyboard DownArrow 84 */
+ 0, /* 82 52 Keyboard UpArrow 83 */
+ 0, /* 83 53 Keypad Num Lock and Clear 90 */
+ 0, /* 84 54 Keypad / 95 */
+ 0, /* 85 55 Keypad * 100 */
+ 0, /* 86 56 Keypad - 105 */
+ 0, /* 87 57 Keypad + 106 */
+ 0, /* 88 58 Keypad ENTER 108 */
+ 0, /* 89 59 Keypad 1 and End 93 */
+ 0, /* 90 5A Keypad 2 and Down Arrow 98 */
+ 0, /* 91 5B Keypad 3 and PageDn 103 */
+ 0, /* 92 5C Keypad 4 and Left Arrow 92 */
+ 0, /* 93 5D Keypad 5 97 */
+ 0, /* 94 5E Keypad 6 and Right Arrow 102 */
+ 0, /* 95 5F Keypad 7 and Home 91 */
+ 0, /* 96 60 Keypad 8 and Up Arrow 96 */
+ 0, /* 97 61 Keypad 9 and PageUp 101 */
+ 0, /* 98 62 Keypad 0 and Insert 99 */
+ 0, /* 99 63 Keypad . and Delete 104 */
+ '|' /* 100 64 Keyboard Non-US \ and | 45 */
+};
+
+
+/***********************************/
+/* Keycodes for 1 byte translation */
+/* - CONTROL-KEY pressed - */
+/***********************************/
+const uint8_t keycodes_ctrl[] = {
+ 0, /* 0 00 Reserved (no event indicated) */
+ 0, /* 1 01 Keyboard ErrorRollOver */
+ 0, /* 2 02 Keyboard POSTFail */
+ 0, /* 3 03 Keyboard ErrorUndefined */
+ 1, /* 4 04 Keyboard a and A 31 */
+ 2, /* 5 05 Keyboard b and B 50 */
+ 3, /* 6 06 Keyboard c and C 48 */
+ 4, /* 7 07 Keyboard d and D 33 */
+ 5, /* 8 08 Keyboard e and E 19 */
+ 6, /* 9 09 Keyboard f and F 34 */
+ 7, /* 10 0A Keyboard g and G 35 */
+ 8, /* 11 0B Keyboard h and H 36 */
+ 9, /* 12 0C Keyboard i and I 24 */
+ 10, /* 13 0D Keyboard j and J 37 */
+ 11, /* 14 0E Keyboard k and K 38 */
+ 12, /* 15 0F Keyboard l and L 39 */
+ 13, /* 16 10 Keyboard m and M 52 */
+ 14, /* 17 11 Keyboard n and N 51 */
+ 15, /* 18 12 Keyboard o and O 25 */
+ 16, /* 19 13 Keyboard p and P 26 */
+ 17, /* 20 14 Keyboard q and Q 17 */
+ 18, /* 21 15 Keyboard r and R 20 */
+ 19, /* 22 16 Keyboard s and S 32 */
+ 20, /* 23 17 Keyboard t and T 21 */
+ 21, /* 24 18 Keyboard u and U 23 */
+ 22, /* 25 19 Keyboard v and V 49 */
+ 23, /* 26 1A Keyboard w and W 18 */
+ 24, /* 27 1B Keyboard x and X 47 */
+ 25, /* 28 1C Keyboard y and Y 22 */
+ 26, /* 29 1D Keyboard z and Z 46 */
+ 0, /* 30 1E Keyboard 1 and ! 2 */
+ 0, /* 31 1F Keyboard 2 and @ 3 */
+ 0, /* 32 20 Keyboard 3 and # 4 */
+ 0, /* 33 21 Keyboard 4 and $ 5 */
+ 0, /* 34 22 Keyboard 5 and % 6 */
+ 0, /* 35 23 Keyboard 6 and ^ 7 */
+ 0, /* 36 24 Keyboard 7 and & 8 */
+ 0, /* 37 25 Keyboard 8 and * 9 */
+ 0, /* 38 26 Keyboard 9 and ( 10 */
+ 0, /* 39 27 Keyboard 0 and ) 11 */
+ 0, /* 40 28 Keyboard Return (ENTER) 43 */
+ 0, /* 41 29 Keyboard ESCAPE 110 */
+ 0, /* 42 2A Keyboard DELETE (BS) 15 */
+ 0, /* 43 2B Keyboard Tab 16 */
+ 0, /* 44 2C Keyboard Spacebar 61 */
+ 0, /* 45 2D Keyboard - and (underscore) 12 */
+ 0, /* 46 2E Keyboard = and + 13 */
+ 0, /* 47 2F Keyboard [ and { 27 */
+ 0, /* 48 30 Keyboard ] and } 28 */
+ 0, /* 49 31 Keyboard \ and | 29 */
+ 0, /* 50 32 Keyboard Non-US # and ~ 42 */
+ 0, /* 51 33 Keyboard ; and : 40 */
+ 0, /* 52 34 Keyboard ' and " 41 */
+ 0, /* 53 35 Keyboard Grave Accent and Tilde 1 */
+ 0, /* 54 36 Keyboard , and < 53 */
+ 0, /* 55 37 Keyboard . and > 54 */
+ 0, /* 56 38 Keyboard / and ? 55 */
+ 0, /* 57 39 Keyboard Caps Lock 30 */
+ 0, /* 58 3A Keyboard F1 112 */
+ 0, /* 59 3B Keyboard F2 113 */
+ 0, /* 60 3C Keyboard F3 114 */
+ 0, /* 61 3D Keyboard F4 115 */
+ 0, /* 62 3E Keyboard F5 116 */
+ 0, /* 63 3F Keyboard F6 117 */
+ 0, /* 64 40 Keyboard F7 118 */
+ 0, /* 65 41 Keyboard F8 119 */
+ 0, /* 66 42 Keyboard F9 120 */
+ 0, /* 67 43 Keyboard F10 121 */
+ 0, /* 68 44 Keyboard F11 122 */
+ 0, /* 69 45 Keyboard F12 123 */
+ 0, /* 70 46 Keyboard PrintScreen 124 */
+ 0, /* 71 47 Keyboard Scroll Lock 125 */
+ 0, /* 72 48 Keyboard Pause 126 */
+ 0, /* 73 49 Keyboard Insert 75 */
+ 0, /* 74 4A Keyboard Home 80 */
+ 0, /* 75 4B Keyboard PageUp 85 */
+ 0, /* 76 4C Keyboard Delete Forward 76 */
+ 0, /* 77 4D Keyboard End 81 */
+ 0, /* 78 4E Keyboard PageDown 86 */
+ 0, /* 79 4F Keyboard RightArrow 89 */
+ 0, /* 80 50 Keyboard LeftArrow 79 */
+ 0, /* 81 51 Keyboard DownArrow 84 */
+ 0, /* 82 52 Keyboard UpArrow 83 */
+ 0, /* 83 53 Keypad Num Lock and Clear 90 */
+ 0, /* 84 54 Keypad / 95 */
+ 0, /* 85 55 Keypad * 100 */
+ 0, /* 86 56 Keypad - 105 */
+ 0, /* 87 57 Keypad + 106 */
+ 0, /* 88 58 Keypad ENTER 108 */
+ 0, /* 89 59 Keypad 1 and End 93 */
+ 0, /* 90 5A Keypad 2 and Down Arrow 98 */
+ 0, /* 91 5B Keypad 3 and PageDn 103 */
+ 0, /* 92 5C Keypad 4 and Left Arrow 92 */
+ 0, /* 93 5D Keypad 5 97 */
+ 0, /* 94 5E Keypad 6 and Right Arrow 102 */
+ 0, /* 95 5F Keypad 7 and Home 91 */
+ 0, /* 96 60 Keypad 8 and Up Arrow 96 */
+ 0, /* 97 61 Keypad 9 and PageUp 101 */
+ 0, /* 98 62 Keypad 0 and Insert 99 */
+ 0, /* 99 63 Keypad . and Delete 104 */
+ 0 /* 100 64 Keyboard Non-US \ and | 45 */
+};
diff --git a/src/roms/SLOF/lib/libusb/usb-key.h b/src/roms/SLOF/lib/libusb/usb-key.h
new file mode 100644
index 0000000..1871a99
--- /dev/null
+++ b/src/roms/SLOF/lib/libusb/usb-key.h
@@ -0,0 +1,42 @@
+#ifndef _USB_KEYB_H
+#define _USB_KEYB_H
+
+/*****************************************************************************
+ * Copyright (c) 2013 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#define BIT_0 1
+#define BIT_1 (BIT_0 << 1)
+#define BIT_2 (BIT_0 << 2)
+#define BIT_3 (BIT_0 << 3)
+#define BIT_4 (BIT_0 << 4)
+#define BIT_5 (BIT_0 << 5)
+#define BIT_6 (BIT_0 << 6)
+#define BIT_7 (BIT_0 << 7)
+
+/* bits from modifier input */
+#define MODIFIER_CTRL (BIT_0 | BIT_4)
+#define MODIFIER_SHIFT (BIT_1 | BIT_5)
+#define MODIFIER_ALT (BIT_2 | BIT_6)
+#define MODIFIER_GUI (BIT_3 | BIT_7)
+#define MODIFIER_ALT_GR BIT_6
+
+/* bits representing Keyboard-LEDs */
+#define LED_NUM_LOCK BIT_0
+#define LED_CAPS_LOCK BIT_1
+#define LED_SCROLL_LOCK BIT_2
+
+extern const uint8_t keycodes_std_US[];
+extern const uint8_t keycodes_shift_US[];
+extern const uint8_t keycodes_alt_GR[];
+extern const uint8_t keycodes_ctrl[];
+
+#endif
diff --git a/src/roms/SLOF/lib/libusb/usb-ohci.c b/src/roms/SLOF/lib/libusb/usb-ohci.c
new file mode 100644
index 0000000..0e84004
--- /dev/null
+++ b/src/roms/SLOF/lib/libusb/usb-ohci.c
@@ -0,0 +1,1055 @@
+/*****************************************************************************
+ * Copyright (c) 2013 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <string.h>
+#include <byteorder.h>
+#include "usb.h"
+#include "usb-core.h"
+#include "usb-ohci.h"
+
+#undef OHCI_DEBUG
+//#define OHCI_DEBUG
+#ifdef OHCI_DEBUG
+#define dprintf(_x ...) do { printf(_x); } while(0)
+#else
+#define dprintf(_x ...)
+#endif
+
+#undef OHCI_DEBUG_PACKET
+//#define OHCI_DEBUG_PACKET
+#ifdef OHCI_DEBUG_PACKET
+#define dpprintf(_x ...) do { printf(_x); } while(0)
+#else
+#define dpprintf(_x ...)
+#endif
+
+
+/*
+ * Dump OHCI register
+ *
+ * @param - ohci_hcd
+ * @return -
+ */
+static void ohci_dump_regs(struct ohci_regs *regs)
+{
+ dprintf("\n - HcRevision %08X", read_reg32(&regs->rev));
+ dprintf(" - HcControl %08X", read_reg32(&regs->control));
+ dprintf("\n - HcCommandStatus %08X", read_reg32(&regs->cmd_status));
+ dprintf(" - HcInterruptStatus %08X", read_reg32(&regs->intr_status));
+ dprintf("\n - HcInterruptEnable %08X", read_reg32(&regs->intr_enable));
+ dprintf(" - HcInterruptDisable %08X", read_reg32(&regs->intr_disable));
+ dprintf("\n - HcHCCA %08X", read_reg32(&regs->hcca));
+ dprintf(" - HcPeriodCurrentED %08X", read_reg32(&regs->period_curr_ed));
+ dprintf("\n - HcControlHeadED %08X", read_reg32(&regs->cntl_head_ed));
+ dprintf(" - HcControlCurrentED %08X", read_reg32(&regs->cntl_curr_ed));
+ dprintf("\n - HcBulkHeadED %08X", read_reg32(&regs->bulk_head_ed));
+ dprintf(" - HcBulkCurrentED %08X", read_reg32(&regs->bulk_curr_ed));
+ dprintf("\n - HcDoneHead %08X", read_reg32(&regs->done_head));
+ dprintf(" - HcFmInterval %08X", read_reg32(&regs->fm_interval));
+ dprintf("\n - HcFmRemaining %08X", read_reg32(&regs->fm_remaining));
+ dprintf(" - HcFmNumber %08X", read_reg32(&regs->fm_num));
+ dprintf("\n - HcPeriodicStart %08X", read_reg32(&regs->period_start));
+ dprintf(" - HcLSThreshold %08X", read_reg32(&regs->ls_threshold));
+ dprintf("\n - HcRhDescriptorA %08X", read_reg32(&regs->rh_desc_a));
+ dprintf(" - HcRhDescriptorB %08X", read_reg32(&regs->rh_desc_b));
+ dprintf("\n - HcRhStatus %08X", read_reg32(&regs->rh_status));
+ dprintf("\n");
+}
+
+/*
+ * OHCI Spec 5.1.1
+ * OHCI Spec 7.4 Root Hub Partition
+ */
+static int ohci_hcd_reset(struct ohci_regs *regs)
+{
+ uint32_t time;
+
+ /* USBRESET - 1sec */
+ write_reg32(&regs->control, 0);
+ SLOF_msleep(100);
+
+ write_reg32(&regs->intr_disable, ~0);
+ write_reg32(&regs->cmd_status, OHCI_CMD_STATUS_HCR);
+ mb();
+
+ time = 30; /* wait for not more than 30usec */
+ while ((read_reg32(&regs->cmd_status) & OHCI_CMD_STATUS_HCR) != 0) {
+ time--;
+ if (!time) {
+ printf(" ** HCD Reset failed...");
+ return -1;
+ }
+ SLOF_usleep(1);
+ }
+ return 0;
+}
+
+static int ohci_hcd_init(struct ohci_hcd *ohcd)
+{
+ struct ohci_regs *regs;
+ struct ohci_ed *ed;
+ long ed_phys = 0;
+ unsigned int i;
+ uint32_t oldrwc;
+ struct usb_dev *rhdev = NULL;
+ struct usb_ep_descr ep;
+ uint32_t reg;
+
+ if (!ohcd)
+ return -1;
+
+ regs = ohcd->regs;
+ rhdev = &ohcd->rhdev;
+ dprintf("%s: HCCA memory %p\n", __func__, ohcd->hcca);
+ dprintf("%s: OHCI Regs %p\n", __func__, regs);
+
+ rhdev->hcidev = ohcd->hcidev;
+ ep.bmAttributes = USB_EP_TYPE_INTR;
+ ep.wMaxPacketSize = 8;
+ rhdev->intr = usb_get_pipe(rhdev, &ep, NULL, 0);
+ if (!rhdev->intr) {
+ printf("usb-ohci: oops could not allocate intr_pipe\n");
+ return -1;
+ }
+
+ /*
+ * OHCI Spec 4.4: Host Controller Communications Area
+ */
+ ed = ohci_pipe_get_ed(rhdev->intr);
+ ed_phys = ohci_pipe_get_ed_phys(rhdev->intr);
+ memset(ohcd->hcca, 0, HCCA_SIZE);
+ memset(ed, 0, sizeof(struct ohci_ed));
+ ed->attr = cpu_to_le32(EDA_SKIP);
+ for (i = 0; i < HCCA_INTR_NUM; i++)
+ ohcd->hcca->intr_table[i] = cpu_to_le32(ed_phys);
+
+ write_reg32(&regs->hcca, ohcd->hcca_phys);
+ write_reg32(&regs->cntl_head_ed, 0);
+ write_reg32(&regs->bulk_head_ed, 0);
+
+ /* OHCI Spec 7.1.2 HcControl Register */
+ oldrwc = read_reg32(&regs->control) & OHCI_CTRL_RWC;
+ write_reg32(&regs->control, (OHCI_CTRL_CBSR | OHCI_CTRL_CLE |
+ OHCI_CTRL_BLE | OHCI_CTRL_PLE |
+ OHCI_USB_OPER | oldrwc));
+ SLOF_msleep(100);
+ /*
+ * For JS20/21 need to rewrite it after setting it to
+ * operational state
+ */
+ write_reg32(&regs->fm_interval, FRAME_INTERVAL);
+ write_reg32(&regs->period_start, PERIODIC_START);
+ reg = read_reg32(&regs->rh_desc_a);
+ reg &= ~( RHDA_PSM_INDIVIDUAL | RHDA_OCPM_PERPORT );
+ reg |= RHDA_NPS_ENABLE;
+ write_reg32(&regs->rh_desc_a, reg);
+ write_reg32(&regs->rh_desc_b, 0);
+ mb();
+ SLOF_msleep(100);
+ ohci_dump_regs(regs);
+ return 0;
+}
+
+/*
+ * OHCI Spec 7.4 Root Hub Partition
+ */
+static void ohci_hub_check_ports(struct ohci_hcd *ohcd)
+{
+ struct ohci_regs *regs;
+ struct usb_dev *dev;
+ unsigned int ports, i, port_status, port_clear = 0;
+
+ regs = ohcd->regs;
+ ports = read_reg32(&regs->rh_desc_a) & RHDA_NDP;
+ write_reg32(&regs->rh_status, RH_STATUS_LPSC);
+ SLOF_msleep(100);
+ dprintf("usb-ohci: ports connected %d\n", ports);
+ for (i = 0; i < ports; i++) {
+ dprintf("usb-ohci: ports scanning %d\n", i);
+ port_status = read_reg32(&regs->rh_ps[i]);
+ if (port_status & RH_PS_CSC) {
+ if (port_status & RH_PS_CCS) {
+ write_reg32(&regs->rh_ps[i], RH_PS_PRS);
+ mb();
+ port_clear |= RH_PS_CSC;
+ dprintf("Start enumerating device\n");
+ SLOF_msleep(100);
+ } else
+ printf("Start removing device\n");
+ }
+ port_status = read_reg32(&regs->rh_ps[i]);
+ if (port_status & RH_PS_PRSC) {
+ port_clear |= RH_PS_PRSC;
+ dev = usb_devpool_get();
+ dprintf("usb-ohci: Device reset, setting up %p\n", dev);
+ dev->hcidev = ohcd->hcidev;
+ if (!setup_new_device(dev, i))
+ printf("usb-ohci: unable to setup device on port %d\n", i);
+ }
+ if (port_status & RH_PS_PESC) {
+ port_clear |= RH_PS_PESC;
+ if (port_status & RH_PS_PES)
+ dprintf("enabled\n");
+ else
+ dprintf("disabled\n");
+ }
+ if (port_status & RH_PS_PSSC) {
+ port_clear |= RH_PS_PESC;
+ dprintf("suspended\n");
+ }
+ port_clear &= 0xFFFF0000;
+ if (port_clear)
+ write_reg32(&regs->rh_ps[i], port_clear);
+ }
+}
+
+static inline struct ohci_ed *ohci_pipe_get_ed(struct usb_pipe *pipe)
+{
+ struct ohci_pipe *opipe;
+ opipe = container_of(pipe, struct ohci_pipe, pipe);
+ dpprintf("%s: ed is %p\n", __func__, &opipe->ed);
+ return &opipe->ed;
+}
+
+static inline long ohci_pipe_get_ed_phys(struct usb_pipe *pipe)
+{
+ struct ohci_pipe *opipe;
+ opipe = container_of(pipe, struct ohci_pipe, pipe);
+ dpprintf("%s: ed_phys is %x\n", __func__, opipe->ed_phys);
+ return opipe->ed_phys;
+}
+
+static inline struct ohci_pipe *ohci_pipe_get_opipe(struct usb_pipe *pipe)
+{
+ struct ohci_pipe *opipe;
+ opipe = container_of(pipe, struct ohci_pipe, pipe);
+ dpprintf("%s: opipe is %p\n", __func__, opipe);
+ return opipe;
+}
+
+static int ohci_alloc_pipe_pool(struct ohci_hcd *ohcd)
+{
+ struct ohci_pipe *opipe, *curr, *prev;
+ long opipe_phys = 0;
+ unsigned int i, count;
+#ifdef OHCI_DEBUG_PACKET
+ struct usb_pipe *pipe;
+#endif
+
+ dprintf("usb-ohci: %s enter\n", __func__);
+ count = OHCI_PIPE_POOL_SIZE/sizeof(*opipe);
+ ohcd->pool = opipe = SLOF_dma_alloc(OHCI_PIPE_POOL_SIZE);
+ if (!opipe)
+ return false;
+
+ ohcd->pool_phys = opipe_phys = SLOF_dma_map_in(opipe, OHCI_PIPE_POOL_SIZE, true);
+ dprintf("usb-ohci: %s opipe %x, opipe_phys %x size %d count %d\n",
+ __func__, opipe, opipe_phys, sizeof(*opipe), count);
+ /* Although an array, link them*/
+ for (i = 0, curr = opipe, prev = NULL; i < count; i++, curr++) {
+ if (prev)
+ prev->pipe.next = &curr->pipe;
+ curr->pipe.next = NULL;
+ prev = curr;
+
+ if (((uint64_t)&curr->ed) % 16)
+ printf("usb-ohci: Warning ED not aligned to 16byte boundary");
+ curr->ed_phys = opipe_phys + (curr - opipe) * sizeof(*curr) +
+ offset_of(struct ohci_pipe, ed);
+ }
+
+ if (!ohcd->freelist)
+ ohcd->freelist = &opipe->pipe;
+ else
+ ohcd->end->next = &opipe->pipe;
+ ohcd->end = &prev->pipe;
+
+#ifdef OHCI_DEBUG_PACKET
+ for (i = 0, pipe = ohcd->freelist; pipe; pipe = pipe->next)
+ dprintf("usb-ohci: %d: pipe cur %p ed %p ed_phys %x\n",
+ i++, pipe, ohci_pipe_get_ed(pipe),
+ ohci_pipe_get_ed_phys(pipe));
+#endif
+
+ dprintf("usb-ohci: %s exit\n", __func__);
+ return true;
+}
+
+static void ohci_init(struct usb_hcd_dev *hcidev)
+{
+ struct ohci_hcd *ohcd;
+
+ printf(" OHCI: initializing\n");
+ dprintf("%s: device base address %p\n", __func__, hcidev->base);
+
+ ohcd = SLOF_alloc_mem(sizeof(struct ohci_hcd));
+ if (!ohcd) {
+ printf("usb-ohci: Unable to allocate memory\n");
+ goto out;
+ }
+
+ hcidev->nextaddr = 1;
+ hcidev->priv = ohcd;
+ memset(ohcd, 0, sizeof(*ohcd));
+ ohcd->hcidev = hcidev;
+ ohcd->freelist = NULL;
+ ohcd->end = NULL;
+ ohcd->regs = (struct ohci_regs *)(hcidev->base);
+ ohcd->hcca = SLOF_dma_alloc(sizeof(struct ohci_hcca));
+ if (!ohcd->hcca || PTR_U32(ohcd->hcca) & HCCA_ALIGN) {
+ printf("usb-ohci: Unable to allocate/unaligned HCCA memory %p\n",
+ ohcd->hcca);
+ goto out_free_hcd;
+ }
+ ohcd->hcca_phys = SLOF_dma_map_in(ohcd->hcca,
+ sizeof(struct ohci_hcca), true);
+ dprintf("usb-ohci: HCCA memory %p HCCA-dev memory %08lx\n",
+ ohcd->hcca, ohcd->hcca_phys);
+
+ ohci_hcd_reset(ohcd->regs);
+ ohci_hcd_init(ohcd);
+ ohci_hub_check_ports(ohcd);
+ return;
+
+out_free_hcd:
+ SLOF_dma_free(ohcd->hcca, sizeof(struct ohci_hcca));
+ SLOF_free_mem(ohcd, sizeof(struct ohci_hcd));
+out:
+ return;
+}
+
+static void ohci_exit(struct usb_hcd_dev *hcidev)
+{
+ struct ohci_hcd *ohcd = NULL;
+
+ dprintf("%s: enter \n", __func__);
+ if (!hcidev && !hcidev->priv)
+ return;
+
+ ohcd = hcidev->priv;
+ write_reg32(&ohcd->regs->control, (OHCI_CTRL_CBSR | OHCI_USB_SUSPEND));
+ SLOF_msleep(20);
+ write_reg32(&ohcd->regs->hcca, cpu_to_le32(0));
+
+ if (ohcd->pool) {
+ SLOF_dma_map_out(ohcd->pool_phys, ohcd->pool, OHCI_PIPE_POOL_SIZE);
+ SLOF_dma_free(ohcd->pool, OHCI_PIPE_POOL_SIZE);
+ }
+ if (ohcd->hcca) {
+ SLOF_dma_map_out(ohcd->hcca_phys, ohcd->hcca, sizeof(struct ohci_hcca));
+ SLOF_dma_free(ohcd->hcca, sizeof(struct ohci_hcca));
+ }
+ SLOF_free_mem(ohcd, sizeof(struct ohci_hcd));
+ return;
+}
+
+static void ohci_detect(void)
+{
+
+}
+
+static void ohci_disconnect(void)
+{
+
+}
+
+#define OHCI_CTRL_TDS 3
+
+static void ohci_fill_td(struct ohci_td *td, long next,
+ long req, size_t size, unsigned int attr)
+{
+ if (size && req) {
+ td->cbp = cpu_to_le32(req);
+ td->be = cpu_to_le32(req + size - 1);
+ } else {
+ td->cbp = 0;
+ td->be = 0;
+ }
+ td->attr = cpu_to_le32(attr);
+ td->next_td = cpu_to_le32(next);
+
+ dpprintf("%s: cbp %08X attr %08X next_td %08X be %08X\n", __func__,
+ le32_to_cpu(td->cbp), le32_to_cpu(td->attr),
+ le32_to_cpu(td->next_td), le32_to_cpu(td->be));
+}
+
+static void ohci_fill_ed(struct ohci_ed *ed, long headp, long tailp,
+ unsigned int attr, long next_ed)
+{
+ ed->attr = cpu_to_le32(attr);
+ ed->headp = cpu_to_le32(headp) | (ed->headp & ~EDA_HEADP_MASK_LE);
+ ed->tailp = cpu_to_le32(tailp);
+ ed->next_ed = cpu_to_le32(next_ed);
+ dpprintf("%s: headp %08X tailp %08X next_td %08X attr %08X\n", __func__,
+ le32_to_cpu(ed->headp), le32_to_cpu(ed->tailp),
+ le32_to_cpu(ed->next_ed), le32_to_cpu(ed->attr));
+
+}
+
+static long ohci_get_td_phys(struct ohci_td *curr, struct ohci_td *start, long td_phys)
+{
+ dpprintf("position %d\n", curr - start);
+ return td_phys + (curr - start) * sizeof(*start);
+}
+
+static long ohci_get_td_virt(struct ohci_td *curr, struct ohci_td *start, long td_virt, long total_count)
+{
+ dpprintf("position %d\n", curr - start);
+ if ( (curr - start) >= total_count) {
+ /* busted position, should ignore this */
+ return 0;
+ }
+ return td_virt + (curr - start) * sizeof(*start);
+}
+
+/* OHCI Spec: 4.4.2.3 HccaDoneHead*/
+static int ohci_process_done_head(struct ohci_hcd *ohcd,
+ struct ohci_td *td_start,
+ long __td_start_phys, long total_count)
+{
+ struct ohci_hcca *hcca;
+ struct ohci_td *td_phys = NULL, *td_start_phys;
+ struct ohci_td *td, *prev_td = NULL;
+ uint32_t reg = 0, time = 0;
+ int ret = true;
+ long count;
+
+ count = total_count;
+ td_start_phys = (struct ohci_td *) __td_start_phys;
+ hcca = ohcd->hcca;
+ time = SLOF_GetTimer() + USB_TIMEOUT;
+ dpprintf("Claiming %ld\n", count);
+
+again:
+ mb();
+ /* Check if there is an interrupt */
+ reg = read_reg32(&ohcd->regs->intr_status);
+ while(!(reg & OHCI_INTR_STATUS_WD))
+ {
+ if (time < SLOF_GetTimer()) {
+ printf("Timed out waiting for interrupt %x\n", reg);
+ return false;
+ }
+ mb();
+ reg = read_reg32(&ohcd->regs->intr_status);
+ }
+
+ /* Interrupt is there, read from done_head pointer */
+ td_phys = (struct ohci_td *)(uint64_t) le32_to_cpu(hcca->done_head);
+ if (!td_phys) {
+ dprintf("Again td_phys null %ld\n");
+ goto again;
+ }
+ hcca->done_head = 0;
+ mb();
+
+ while (td_phys && (count > 0)) {
+ td = (struct ohci_td *)(uint64_t) ohci_get_td_virt(td_phys,
+ td_start_phys,
+ PTR_U32(td_start),
+ total_count);
+
+ if (!td) {
+ printf("USB: Error TD null %p\n", td_phys);
+ break;
+ }
+ count--;
+ dprintf("Claimed %p(%p) td_start %p count %ld\n",
+ td, td_phys, td_start_phys, count);
+ dpprintf("%s: cbp %08X attr %08X next_td %08X be %08X\n",
+ __func__,
+ le32_to_cpu(td->cbp), le32_to_cpu(td->attr),
+ le32_to_cpu(td->next_td), le32_to_cpu(td->be));
+ mb();
+ reg = (le32_to_cpu(td->attr) & TDA_CC) >> 28;
+ if (reg) {
+ dprintf("%s: cbp %08X attr %08X next_td %08X be %08X\n",
+ __func__,
+ le32_to_cpu(td->cbp), le32_to_cpu(td->attr),
+ le32_to_cpu(td->next_td), le32_to_cpu(td->be));
+ printf("USB: Error %s %p\n", tda_cc_error[reg], td);
+ if (reg > 3) /* Return negative error code */
+ ret = reg * -1;
+ }
+ prev_td = td;
+ td_phys = (struct ohci_td *)(uint64_t) le32_to_cpu(td->next_td);
+ prev_td->attr |= cpu_to_le32(TDA_DONE);
+ prev_td->next_td = 0;
+ mb();
+ }
+ /* clear the WD interrupt status */
+ write_reg32(&ohcd->regs->intr_status, OHCI_INTR_STATUS_WD);
+ mb();
+ read_reg32(&ohcd->regs->intr_status);
+
+ if (count > 0) {
+ dpprintf("Pending count %d\n", count);
+ goto again;
+ }
+ dprintf("TD claims done\n");
+ return ret;
+}
+
+/*
+ * OHCI Spec:
+ * 4.2 Endpoint Descriptor
+ * 4.3.1 General Transfer Descriptor
+ * 5.2.8 Transfer Descriptor Queues
+ */
+static int ohci_send_ctrl(struct usb_pipe *pipe, struct usb_dev_req *req, void *data)
+{
+ struct ohci_ed *ed;
+ struct ohci_td *tds, *td, *td_phys;
+ struct ohci_regs *regs;
+ struct ohci_hcd *ohcd;
+ uint32_t datalen;
+ uint32_t dir, attr = 0;
+ uint32_t time;
+ int ret = true, i;
+ long req_phys = 0, data_phys = 0, td_next = 0, td_count = 0;
+ unsigned char *dbuf;
+
+ datalen = le16_to_cpu(req->wLength);
+ dir = (req->bmRequestType & REQT_DIR_IN) ? 1 : 0;
+
+ dprintf("usb-ohci: %s len %d DIR_IN %d\n", __func__, datalen, dir);
+
+ tds = td = (struct ohci_td *) SLOF_dma_alloc(sizeof(*td) * OHCI_CTRL_TDS);
+ td_phys = (struct ohci_td *) SLOF_dma_map_in(td, sizeof(*td) * OHCI_CTRL_TDS, true);
+ memset(td, 0, sizeof(*td) * OHCI_CTRL_TDS);
+
+ req_phys = SLOF_dma_map_in(req, sizeof(struct usb_dev_req), true);
+ attr = TDA_DP_SETUP | TDA_CC | TDA_TOGGLE_DATA0;
+ td_next = ohci_get_td_phys(td + 1, tds, PTR_U32(td_phys));
+ ohci_fill_td(td, td_next, req_phys, sizeof(*req), attr);
+ td++; td_count++;
+
+ if (datalen) {
+ data_phys = SLOF_dma_map_in(data, datalen, true);
+ attr = 0;
+ attr = (dir ? TDA_DP_IN : TDA_DP_OUT) | TDA_TOGGLE_DATA1 | TDA_CC;
+ td_next = ohci_get_td_phys(td + 1, tds, PTR_U32(td_phys));
+ ohci_fill_td(td, td_next, data_phys, datalen, attr);
+ td++; td_count++;
+ }
+
+ attr = 0;
+ attr = (dir ? TDA_DP_OUT : TDA_DP_IN) | TDA_CC | TDA_TOGGLE_DATA1;
+ td_next = ohci_get_td_phys(td + 1, tds, PTR_U32(td_phys));
+ ohci_fill_td(td, 0, 0, 0, attr);
+ td_count++;
+
+ ed = ohci_pipe_get_ed(pipe);
+ attr = 0;
+ attr = EDA_FADDR(pipe->dev->addr) | EDA_MPS(pipe->mps) | EDA_SKIP;
+ ohci_fill_ed(ed, PTR_U32(td_phys), td_next, attr, 0);
+ ed->tailp = 0; /* HACK */
+ dprintf("usb-ohci: %s - td_start %x td_end %x req %x\n", __func__,
+ td_phys, td_next, req_phys);
+ mb();
+ ed->attr &= cpu_to_le32(~EDA_SKIP);
+
+ ohcd = pipe->dev->hcidev->priv;
+ regs = ohcd->regs;
+ write_reg32(&regs->cntl_head_ed, ohci_pipe_get_ed_phys(pipe));
+ mb();
+ write_reg32(&regs->cmd_status, OHCI_CMD_STATUS_CLF);
+
+ time = SLOF_GetTimer() + USB_TIMEOUT;
+ while ((time > SLOF_GetTimer()) &&
+ ((ed->headp & EDA_HEADP_MASK_LE) != ed->tailp))
+ cpu_relax();
+
+ if ((ed->headp & EDA_HEADP_MASK_LE) == ed->tailp) {
+ dprintf("%s: packet sent\n", __func__);
+#ifdef OHCI_DEBUG_PACKET
+ dpprintf("Request: ");
+ dbuf = (unsigned char *)req;
+ for(i = 0; i < 8; i++)
+ printf("%02X ", dbuf[i]);
+ dpprintf("\n");
+ if (datalen) {
+ dbuf = (unsigned char *)data;
+ dpprintf("Reply: ");
+ for(i = 0; i < datalen; i++)
+ printf("%02X ", dbuf[i]);
+ dpprintf("\n");
+ }
+#endif
+ }
+ else {
+ printf("%s: timed out - failed\n", __func__);
+ dpprintf("%s: headp %08X tailp %08X next_td %08X attr %08X\n",
+ __func__,
+ le32_to_cpu(ed->headp), le32_to_cpu(ed->tailp),
+ le32_to_cpu(ed->next_ed), le32_to_cpu(ed->attr));
+ printf("Request: ");
+ dbuf = (unsigned char *)req;
+ for(i = 0; i < 8; i++)
+ printf("%02X ", dbuf[i]);
+ printf("\n");
+ }
+ ret = ohci_process_done_head(ohcd, tds, (long)td_phys, td_count);
+ mb();
+ ed->attr |= cpu_to_le32(EDA_SKIP);
+ mb();
+ write_reg32(&regs->cntl_head_ed, 0);
+ write_reg32(&regs->cntl_curr_ed, 0);
+
+ SLOF_dma_map_out(req_phys, req, sizeof(struct usb_dev_req));
+ if (datalen)
+ SLOF_dma_map_out(data_phys, data, datalen);
+ SLOF_dma_map_out(PTR_U32(td_phys), tds, sizeof(*td) * OHCI_CTRL_TDS);
+ SLOF_dma_free(tds, sizeof(*td) * OHCI_CTRL_TDS);
+ return (ret > 0) ? true : false;
+}
+
+static int ohci_transfer_bulk(struct usb_pipe *pipe, void *td_ptr,
+ void *td_phys_ptr, void *data_phys, int datalen)
+{
+ struct ohci_ed *ed;
+ struct ohci_td *td, *tds;
+ struct ohci_regs *regs;
+ struct ohci_hcd *ohcd;
+ long td_phys = 0, td_next, ed_phys, ptr, td_count = 0;
+ uint32_t dir, attr = 0, count;
+ size_t len, packet_len;
+ uint32_t time;
+ int ret = true;
+
+ if (pipe->type != USB_EP_TYPE_BULK) {
+ printf("usb-ohci: Not a bulk pipe.\n");
+ ret = false;
+ goto end;
+ }
+
+ dir = (pipe->dir == USB_PIPE_OUT) ? 0 : 1;
+ count = datalen / OHCI_MAX_BULK_SIZE;
+ if (count > OHCI_MAX_TDS) {
+ printf("usb-ohci: buffer size not supported - %d\n", datalen);
+ ret = false;
+ goto end;
+ }
+
+ td = tds = (struct ohci_td *) td_ptr;
+ td_phys = (long)td_phys_ptr;
+ dprintf("usb-ohci: %s pipe %p data_phys %p len %d DIR_IN %d td %p td_phys %p\n",
+ __func__, pipe, data_phys, datalen, dir, td, td_phys);
+
+ if (!tds) {
+ printf("%s: tds NULL recieved\n", __func__);
+ ret = false;
+ goto end;
+ }
+ memset(td, 0, sizeof(*td) * OHCI_MAX_TDS);
+
+ len = datalen;
+ ptr = (long)data_phys;
+ attr = 0;
+ attr = (dir ? TDA_DP_IN : TDA_DP_OUT) | TDA_CC | TDA_ROUNDING;
+ while (len) {
+ packet_len = (OHCI_MAX_BULK_SIZE < len)? OHCI_MAX_BULK_SIZE : len;
+ td_next = ohci_get_td_phys((td + 1), tds, td_phys);
+ ohci_fill_td(td, td_next, ptr, packet_len, attr);
+ ptr = ptr + packet_len;
+ len = len - packet_len;
+ td++; td_count++;
+ }
+
+ ed = ohci_pipe_get_ed(pipe);
+ attr = 0;
+ dir = pipe->dir ? EDA_DIR_IN : EDA_DIR_OUT;
+ attr = dir | EDA_FADDR(pipe->dev->addr) | EDA_MPS(pipe->mps)
+ | EDA_SKIP | pipe->dev->speed | EDA_EP(pipe->epno);
+ td_next = ohci_get_td_phys(td, tds, td_phys);
+ ohci_fill_ed(ed, td_phys, td_next, attr, 0);
+ dprintf("usb-ohci: %s - tds %p td %p\n", __func__, td_phys, td_next);
+ mb();
+ ed->attr &= cpu_to_le32(~EDA_SKIP);
+
+ ohcd = pipe->dev->hcidev->priv;
+ regs = ohcd->regs;
+ ed_phys = ohci_pipe_get_ed_phys(pipe);
+ write_reg32(&regs->bulk_head_ed, ed_phys);
+ mb();
+ write_reg32(&regs->cmd_status, 0x4);
+
+ time = SLOF_GetTimer() + USB_TIMEOUT;
+ while ((time > SLOF_GetTimer()) &&
+ ((ed->headp & EDA_HEADP_MASK_LE) != ed->tailp))
+ cpu_relax();
+
+ if ((ed->headp & EDA_HEADP_MASK_LE) == ed->tailp)
+ dprintf("%s: packet sent\n", __func__);
+ else {
+ dpprintf("%s: headp %08X tailp %08X next_td %08X attr %08X\n", __func__,
+ le32_to_cpu(ed->headp), le32_to_cpu(ed->tailp),
+ le32_to_cpu(ed->next_ed), le32_to_cpu(ed->attr));
+ }
+ mb();
+ ret = ohci_process_done_head(ohcd, tds, td_phys, td_count);
+ mb();
+ ed->attr |= cpu_to_le32(EDA_SKIP);
+ mb();
+ write_reg32(&regs->bulk_head_ed, 0);
+ write_reg32(&regs->bulk_curr_ed, 0);
+
+ if (le32_to_cpu(ed->headp) & EDA_HEADP_HALTED) {
+ printf("ED Halted\n");
+ printf("%s: headp %08X tailp %08X next_td %08X attr %08X\n", __func__,
+ le32_to_cpu(ed->headp), le32_to_cpu(ed->tailp),
+ le32_to_cpu(ed->next_ed), le32_to_cpu(ed->attr));
+ ed->headp &= ~cpu_to_le32(EDA_HEADP_HALTED);
+ mb();
+ if (ret == USB_STALL) /* Call reset recovery */
+ usb_msc_resetrecovery(pipe->dev);
+ }
+
+end:
+ return (ret > 0) ? true : false;
+}
+
+/* Populate the hcca intr region with periodic intr */
+static int ohci_get_pipe_intr(struct usb_pipe *pipe, struct ohci_hcd *ohcd,
+ char *buf, size_t buflen)
+{
+ struct ohci_hcca *hcca;
+ struct ohci_pipe *opipe;
+ struct ohci_ed *ed;
+ struct usb_dev *dev;
+ struct ohci_td *tds, *td;
+ int32_t count = 0, i;
+ uint8_t *ptr;
+ uint16_t mps;
+ long ed_phys, td_phys, td_next, buf_phys;
+
+ if (!pipe || !ohcd)
+ return false;
+
+ hcca = ohcd->hcca;
+ dev = pipe->dev;
+ if (dev->class != DEV_HID_KEYB && dev->class != DEV_HUB)
+ return false;
+
+ opipe = ohci_pipe_get_opipe(pipe);
+ ed = &(opipe->ed);
+ ed_phys = opipe->ed_phys;
+ mps = pipe->mps;
+ ed->attr = cpu_to_le32(EDA_DIR_IN |
+ EDA_FADDR(dev->addr) |
+ dev->speed |
+ EDA_MPS(pipe->mps) |
+ EDA_SKIP |
+ EDA_EP(pipe->epno));
+ dprintf("%s: pipe %p ed %p dev %p opipe %p\n", __func__,
+ pipe, ed, dev, opipe);
+ count = (buflen/mps) + 1;
+ tds = td = SLOF_dma_alloc(sizeof(*td) * count);
+ if (!tds) {
+ printf("%s: alloc failed\n", __func__);
+ return false;
+ }
+ td_phys = SLOF_dma_map_in(td, sizeof(*td) * count, false);
+
+ memset(tds, 0, sizeof(*tds) * count);
+ memset(buf, 0, buflen);
+ buf_phys = SLOF_dma_map_in(buf, buflen, false);
+ opipe->td = td;
+ opipe->td_phys = td_phys;
+ opipe->count = count;
+ opipe->buf = buf;
+ opipe->buflen = buflen;
+ opipe->buf_phys = buf_phys;
+
+ ptr = (uint8_t *)buf_phys;
+ for (i = 0; i < count - 1; i++, ptr += mps) {
+ td = &tds[i];
+ td_next = ohci_get_td_phys(td + 1, &tds[0], td_phys);
+ td->cbp = cpu_to_le32(PTR_U32(ptr));
+ td->attr = cpu_to_le32(TDA_DP_IN | TDA_ROUNDING | TDA_CC);
+ td->next_td = cpu_to_le32(td_next);
+ td->be = cpu_to_le32(PTR_U32(ptr) + mps - 1);
+ dprintf("td %x td++ %x ptr %x be %x\n",
+ td, le32_to_cpu(td->next_td),
+ ptr, (PTR_U32(ptr) + mps - 1));
+ }
+ td->next_td = 0;
+ td_next = ohci_get_td_phys(td, &tds[0], td_phys);
+ ed->headp = cpu_to_le32(td_phys);
+ ed->tailp = cpu_to_le32(td_next);
+
+ dprintf("%s: head %08X tail %08X, count %d, mps %d\n", __func__,
+ le32_to_cpu(ed->headp),
+ le32_to_cpu(ed->tailp),
+ count, mps);
+ ed->next_ed = 0;
+
+
+ switch (dev->class) {
+ case DEV_HID_KEYB:
+ dprintf("%s: Keyboard class %d\n", __func__, dev->class);
+ hcca->intr_table[0] = cpu_to_le32(ed_phys);
+ hcca->intr_table[8] = cpu_to_le32(ed_phys);
+ hcca->intr_table[16] = cpu_to_le32(ed_phys);
+ hcca->intr_table[24] = cpu_to_le32(ed_phys);
+ ed->attr &= cpu_to_le32(~EDA_SKIP);
+ break;
+
+ case DEV_HUB:
+ dprintf("%s: HUB class %x\n", __func__, dev->class);
+ hcca->intr_table[1] = cpu_to_le32(ed_phys);
+ ed->attr &= cpu_to_le32(~EDA_SKIP);
+ break;
+
+ default:
+ dprintf("%s: unhandled class %d\n", __func__, dev->class);
+ }
+ return true;
+}
+
+static int ohci_put_pipe_intr(struct usb_pipe *pipe, struct ohci_hcd *ohcd)
+{
+ struct ohci_hcca *hcca;
+ struct ohci_pipe *opipe;
+ struct ohci_ed *ed;
+ struct usb_dev *dev;
+ struct ohci_td *td;
+ long ed_phys;
+
+ if (!pipe || !ohcd)
+ return false;
+
+ hcca = ohcd->hcca;
+ dev = pipe->dev;
+
+ if (dev->class != DEV_HID_KEYB && dev->class != DEV_HUB)
+ return false;
+
+ opipe = ohci_pipe_get_opipe(pipe);
+ ed = &(opipe->ed);
+ ed_phys = opipe->ed_phys;
+ dprintf("%s: td %p td_phys %08lx buf %p buf_phys %08lx\n", __func__,
+ opipe->td, opipe->td_phys, opipe->buf, opipe->buf_phys);
+
+ ed->attr |= cpu_to_le32(EDA_SKIP);
+ mb();
+ ed->headp = 0;
+ ed->tailp = 0;
+ ed->next_ed = 0;
+ SLOF_dma_map_out(opipe->buf_phys, opipe->buf, opipe->buflen);
+ SLOF_dma_map_out(opipe->td_phys, opipe->td, sizeof(*td) * opipe->count);
+ SLOF_dma_free(opipe->td, sizeof(*td) * opipe->count);
+
+ switch (dev->class) {
+ case DEV_HID_KEYB:
+ dprintf("%s: Keyboard class %d\n", __func__, dev->class);
+ hcca->intr_table[0] = cpu_to_le32(ed_phys);
+ hcca->intr_table[8] = cpu_to_le32(ed_phys);
+ hcca->intr_table[16] = cpu_to_le32(ed_phys);
+ hcca->intr_table[24] = cpu_to_le32(ed_phys);
+ break;
+
+ case DEV_HUB:
+ dprintf("%s: HUB class %d\n", __func__, dev->class);
+ hcca->intr_table[1] = cpu_to_le32(ed_phys);
+ break;
+
+ default:
+ dprintf("%s: unhandled class %d\n", __func__, dev->class);
+ }
+ return true;
+}
+
+static int ohci_init_bulk_ed(struct usb_dev *dev, struct usb_pipe *pipe)
+{
+ struct ohci_pipe *opipe;
+ struct ohci_ed *ed;
+ uint32_t dir;
+
+ if (!pipe || !dev)
+ return false;
+
+ opipe = ohci_pipe_get_opipe(pipe);
+ ed = &(opipe->ed);
+ dir = pipe->dir ? EDA_DIR_IN : EDA_DIR_OUT;
+
+ ed->attr = cpu_to_le32(dir |
+ EDA_FADDR(dev->addr) |
+ dev->speed |
+ EDA_MPS(pipe->mps) |
+ EDA_SKIP |
+ EDA_EP(pipe->epno));
+
+ dprintf("%s: pipe %p attr %x\n", __func__, pipe,
+ le32_to_cpu(ed->attr));
+ return true;
+}
+
+static struct usb_pipe *ohci_get_pipe(struct usb_dev *dev, struct usb_ep_descr *ep,
+ char *buf, size_t buflen)
+{
+ struct ohci_hcd *ohcd;
+ struct usb_pipe *new = NULL;
+
+ dprintf("usb-ohci: %s enter %p\n", __func__, dev);
+ if (!dev)
+ return NULL;
+
+ ohcd = (struct ohci_hcd *)dev->hcidev->priv;
+ if (!ohcd->freelist) {
+ dprintf("usb-ohci: %s allocating pool\n", __func__);
+ if (!ohci_alloc_pipe_pool(ohcd))
+ return NULL;
+ }
+
+ new = ohcd->freelist;
+ ohcd->freelist = ohcd->freelist->next;
+ if (!ohcd->freelist)
+ ohcd->end = NULL;
+
+ memset(new, 0, sizeof(*new));
+ new->dev = dev;
+ new->next = NULL;
+ new->type = ep->bmAttributes & USB_EP_TYPE_MASK;
+ new->speed = dev->speed;
+ new->mps = le16_to_cpu(ep->wMaxPacketSize);
+ new->epno = ep->bEndpointAddress & 0xF;
+ new->dir = ep->bEndpointAddress & 0x80;
+ if (new->type == USB_EP_TYPE_INTR)
+ if (!ohci_get_pipe_intr(new, ohcd, buf, buflen))
+ dprintf("usb-ohci: %s alloc_intr failed %p\n",
+ __func__, new);
+ if (new->type == USB_EP_TYPE_BULK)
+ ohci_init_bulk_ed(dev, new);
+
+ dprintf("usb-ohci: %s exit %p\n", __func__, new);
+ return new;
+}
+
+static void ohci_put_pipe(struct usb_pipe *pipe)
+{
+ struct ohci_hcd *ohcd;
+
+ dprintf("usb-ohci: %s enter - %p\n", __func__, pipe);
+ if (!pipe || !pipe->dev)
+ return;
+ ohcd = pipe->dev->hcidev->priv;
+ if (ohcd->end)
+ ohcd->end->next = pipe;
+ else
+ ohcd->freelist = pipe;
+
+ if (pipe->type == USB_EP_TYPE_INTR)
+ if (!ohci_put_pipe_intr(pipe, ohcd))
+ dprintf("usb-ohci: %s alloc_intr failed %p\n",
+ __func__, pipe);
+
+ ohcd->end = pipe;
+ pipe->next = NULL;
+ pipe->dev = NULL;
+ memset(pipe, 0, sizeof(*pipe));
+ dprintf("usb-ohci: %s exit\n", __func__);
+}
+
+static uint16_t ohci_get_last_frame(struct usb_dev *dev)
+{
+ struct ohci_hcd *ohcd;
+ struct ohci_regs *regs;
+
+ ohcd = dev->hcidev->priv;
+ regs = ohcd->regs;
+ return read_reg32(&regs->fm_num);
+}
+
+static int ohci_poll_intr(struct usb_pipe *pipe, uint8_t *data)
+{
+ struct ohci_pipe *opipe;
+ struct ohci_ed *ed;
+ struct ohci_td *head, *tail, *curr, *next;
+ struct ohci_td *head_phys, *tail_phys, *curr_phys;
+ uint8_t *ptr = NULL;
+ unsigned int i, pos;
+ static uint16_t last_frame;
+ long ptr_phys = 0;
+ long td_next;
+
+ if (!pipe || last_frame == ohci_get_last_frame(pipe->dev))
+ return 0;
+
+ dprintf("%s: enter\n", __func__);
+
+ last_frame = ohci_get_last_frame(pipe->dev);
+ opipe = ohci_pipe_get_opipe(pipe);
+ ed = &opipe->ed;
+
+ head_phys = (struct ohci_td *)(long)(le32_to_cpu(ed->headp) & EDA_HEADP_MASK);
+ tail_phys = (struct ohci_td *)(long)le32_to_cpu(ed->tailp);
+ curr_phys = (struct ohci_td *) opipe->td_phys;
+ pos = (tail_phys - curr_phys + 1) % (opipe->count - 1);
+ dprintf("pos %d %ld -- %d\n", pos, (tail_phys - curr_phys + 1),
+ opipe->count);
+ curr = opipe->td + pos;
+ head = opipe->td + (head_phys - (struct ohci_td *) opipe->td_phys);
+ tail = opipe->td + (tail_phys - (struct ohci_td *) opipe->td_phys);
+
+ /* dprintf("%08X %08X %08X %08X\n",
+ opipe->td_phys, head_phys, tail_phys, curr_phys);
+ dprintf("%08X %08X %08X %08X\n", opipe->td, head, tail, curr); */
+
+ if (curr != head) {
+ ptr = (uint8_t *) ((long)opipe->buf + pipe->mps * pos);
+ ptr_phys = opipe->buf_phys + pipe->mps * pos;
+ if (le32_to_cpu(*(uint32_t *)ptr) != 0) {
+ for (i = 0; i < 8; i++)
+ data[i] = *(ptr + i);
+ }
+
+ next = curr + 1;
+ if (next == (opipe->td + opipe->count - 1))
+ next = opipe->td;
+
+ curr->attr = cpu_to_le32(TDA_DP_IN | TDA_ROUNDING | TDA_CC);
+ curr->next_td = cpu_to_le32(0);
+ curr->cbp = cpu_to_le32(PTR_U32(ptr_phys));
+ curr->be = cpu_to_le32(PTR_U32(ptr_phys + pipe->mps - 1));
+ td_next = ohci_get_td_phys(curr, opipe->td, opipe->td_phys);
+ dprintf("Connecting %p to %p(phys %08lx) ptr %p, "
+ "ptr_phys %08lx\n", tail, curr, td_next, ptr, ptr_phys);
+ tail->next_td = cpu_to_le32(td_next);
+ mb();
+ ed->tailp = cpu_to_le32(td_next);
+ } else
+ return 0;
+
+ dprintf("%s: exit\n", __func__);
+ return 1;
+}
+
+struct usb_hcd_ops ohci_ops = {
+ .name = "ohci-hcd",
+ .init = ohci_init,
+ .exit = ohci_exit,
+ .detect = ohci_detect,
+ .disconnect = ohci_disconnect,
+ .get_pipe = ohci_get_pipe,
+ .put_pipe = ohci_put_pipe,
+ .send_ctrl = ohci_send_ctrl,
+ .transfer_bulk = ohci_transfer_bulk,
+ .poll_intr = ohci_poll_intr,
+ .usb_type = USB_OHCI,
+ .next = NULL,
+};
+
+void usb_ohci_register(void)
+{
+ usb_hcd_register(&ohci_ops);
+}
diff --git a/src/roms/SLOF/lib/libusb/usb-ohci.h b/src/roms/SLOF/lib/libusb/usb-ohci.h
new file mode 100644
index 0000000..f4535fd
--- /dev/null
+++ b/src/roms/SLOF/lib/libusb/usb-ohci.h
@@ -0,0 +1,217 @@
+/******************************************************************************
+ * Copyright (c) 2007, 2012, 2013 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+/*
+ * Definitions for OHCI Controller
+ *
+ * USB on the PowerStation:
+ * ohci0 - port 0 -> not connected
+ * ohci0 - port 1 - 2 -> Internal connector (J60_USBINT)
+ * ohci1 - port 0 -> not connected
+ * ohci1 - port 1 - 2 -> External connector (J10_USBEXT)
+ */
+
+#ifndef USB_OHCI_H
+#define USB_OHCI_H
+
+#include <stdint.h>
+
+struct ohci_regs {
+ uint32_t rev;
+ uint32_t control;
+ uint32_t cmd_status;
+ uint32_t intr_status;
+ uint32_t intr_enable;
+ uint32_t intr_disable;
+ uint32_t hcca;
+ uint32_t period_curr_ed;
+ uint32_t cntl_head_ed;
+ uint32_t cntl_curr_ed;
+ uint32_t bulk_head_ed;
+ uint32_t bulk_curr_ed;
+ uint32_t done_head;
+ uint32_t fm_interval;
+ uint32_t fm_remaining;
+ uint32_t fm_num;
+ uint32_t period_start;
+ uint32_t ls_threshold;
+ uint32_t rh_desc_a;
+ uint32_t rh_desc_b;
+ uint32_t rh_status;
+ uint32_t rh_ps[5];
+} __attribute__((packed));
+
+#define EDA_FADDR(x) ((x & 0x7F))
+#define EDA_EP(x) ((x & 0x0F) << 7)
+#define EDA_DIR_OUT (1 << 11)
+#define EDA_DIR_IN (1 << 12)
+#define EDA_LOW_SPEED (1 << 13)
+#define EDA_SKIP (1 << 14)
+#define EDA_SKIP_LE (0x400000) /* avoiding conversions */
+#define EDA_FORMAT_ISO (1 << 15)
+#define EDA_MPS(x) ((x & 0x7FF) << 16)
+
+#define EDA_HEADP_MASK (0xFFFFFFFC)
+#define EDA_HEADP_MASK_LE (cpu_to_le32(EDA_HEADP_MASK))
+#define EDA_HEADP_HALTED (0x1)
+#define EDA_HEADP_CARRY (0x2)
+
+struct ohci_ed {
+ uint32_t attr;
+ uint32_t tailp;
+ uint32_t headp;
+ uint32_t next_ed;
+} __attribute__((packed));
+
+#define TDA_DONE (1 << 17)
+#define TDA_ROUNDING (1 << 18)
+#define TDA_DP_SETUP (0 << 19)
+#define TDA_DP_OUT (1 << 19)
+#define TDA_DP_IN (1 << 20)
+#define TDA_DI_NO (0x7 << 21)
+#define TDA_TOGGLE_DATA0 (0x02000000)
+#define TDA_TOGGLE_DATA1 (0x03000000)
+#define TDA_CC (0xF << 28)
+
+#define TDA_ERROR(x) ((x) * -1)
+
+/* Table 4-7: Completion Codes */
+const char *tda_cc_error[] = {
+#define USB_NOERROR TDA_ERROR(0)
+ "NOERROR",
+ "CRC",
+ "BITSTUFFING",
+ "DATATOGGLEMISMATCH",
+#define USB_STALL TDA_ERROR(4)
+ "STALL",
+ "DEVICENOTRESPONDING",
+ "PIDCHECKFAILURE",
+ "UNEXPECTEDPID",
+ "DATAOVERRUN",
+ "DATAUNDERRUN",
+ "reserved",
+ "reserved",
+ "BUFFEROVERRUN",
+ "BUFFERUNDERRUN",
+ "NOT ACCESSED",
+ "NOT ACCESSED",
+};
+
+struct ohci_td {
+ uint32_t attr;
+ uint32_t cbp;
+ uint32_t next_td;
+ uint32_t be;
+} __attribute__((packed));
+
+#define HCCA_SIZE 256
+#define HCCA_ALIGN (HCCA_SIZE - 1)
+#define HCCA_INTR_NUM 32
+struct ohci_hcca {
+ uint32_t intr_table[HCCA_INTR_NUM];
+ uint16_t frame_num;
+ uint16_t pad1;
+ uint32_t done_head;
+ uint32_t reserved[120];
+} __attribute__((packed));
+
+struct ohci_pipe {
+ struct ohci_ed ed; /* has to be aligned at 16 byte address*/
+ struct usb_pipe pipe;
+ struct ohci_td *td;
+ void *buf;
+ long ed_phys;
+ long td_phys;
+ long buf_phys;
+ uint32_t buflen;
+ uint32_t count;
+ uint8_t pad[0];
+}__attribute__((packed));
+
+#define OHCI_PIPE_POOL_SIZE 4096
+#define OHCI_MAX_TDS 256 /* supports 16k buffers, i.e. 64 * 256 */
+#define OHCI_MAX_BULK_SIZE 4096
+
+struct ohci_hcd {
+ struct ohci_hcca *hcca;
+ struct ohci_regs *regs;
+ struct usb_hcd_dev *hcidev;
+ struct usb_pipe *freelist;
+ struct usb_pipe *end;
+ struct usb_dev rhdev;
+ long hcca_phys;
+ void *pool;
+ long pool_phys;
+};
+
+#define OHCI_CTRL_CBSR (3 << 0)
+#define OHCI_CTRL_PLE (1 << 2)
+#define OHCI_CTRL_CLE (1 << 4)
+#define OHCI_CTRL_BLE (1 << 5)
+#define OHCI_CTRL_HCFS (3 << 6)
+#define OHCI_USB_RESET (0 << 6)
+#define OHCI_USB_OPER (2 << 6)
+#define OHCI_USB_SUSPEND (3 << 6)
+#define OHCI_CTRL_RWC (1 << 9)
+
+/* OHCI Command Status */
+#define OHCI_CMD_STATUS_HCR (1 << 0)
+#define OHCI_CMD_STATUS_CLF (1 << 1)
+#define OHCI_CMD_STATUS_BLF (1 << 2)
+
+/* OHCI Interrupt status */
+#define OHCI_INTR_STATUS_WD (1 << 1)
+
+/* Root Hub Descriptor A bits */
+#define RHDA_NDP (0xFF)
+#define RHDA_PSM_INDIVIDUAL (1 << 8)
+#define RHDA_NPS_ENABLE (1 << 9)
+#define RHDA_DT (1 << 10)
+#define RHDA_OCPM_PERPORT (1 << 11)
+#define RHDA_NOCP_ENABLE (1 << 12)
+
+/* Root Hub Descriptor B bits */
+#define RHDB_PPCM_PORT_POWER (0xFFFE)
+#define RHDB_PPCM_GLOBAL_POWER (0x0000)
+
+#define RH_STATUS_LPSC (1 << 16)
+#define RH_STATUS_OCIC (1 << 17)
+#define RH_STATUS_CREW (1 << 31)
+
+#define RH_PS_CCS (1 << 0)
+#define RH_PS_PES (1 << 1)
+#define RH_PS_PSS (1 << 2)
+#define RH_PS_POCI (1 << 3)
+#define RH_PS_PRS (1 << 4)
+#define RH_PS_PPS (1 << 8)
+#define RH_PS_LSDA (1 << 9)
+
+#define RH_PS_CSC (1 << 16)
+#define RH_PS_PESC (1 << 17)
+#define RH_PS_PSSC (1 << 18)
+#define RH_PS_OCIC (1 << 19)
+#define RH_PS_PRSC (1 << 20)
+
+/*********************************************************************/
+/* Values for USB Frame Timing */
+/* One USB frame (1ms) consists of 12000 bit-times as clock is 12MHz */
+/* controller can be adjusted for performance optimization */
+/* We use standard values (OHCI spec 6.3.1, 5.1.1.4, 5.4, 7.3.4) */
+/*********************************************************************/
+#define FRAME_INTERVAL (((((11999 - 210) * 6) / 7) << 16) | 11999)
+#define PERIODIC_START ((11999 * 9) / 10)
+
+
+static inline struct ohci_ed *ohci_pipe_get_ed(struct usb_pipe *pipe);
+static inline long ohci_pipe_get_ed_phys(struct usb_pipe *pipe);
+static int ohci_alloc_pipe_pool(struct ohci_hcd *ohcd);
+
+#endif /* USB_OHCI_H */
diff --git a/src/roms/SLOF/lib/libusb/usb-slof.c b/src/roms/SLOF/lib/libusb/usb-slof.c
new file mode 100644
index 0000000..de841f0
--- /dev/null
+++ b/src/roms/SLOF/lib/libusb/usb-slof.c
@@ -0,0 +1,61 @@
+/******************************************************************************
+ * Copyright (c) 2013 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+/*
+ * All functions concerning interface to slof
+ */
+
+#include <string.h>
+#include "helpers.h"
+#include "usb-core.h"
+#include "paflof.h"
+
+#undef SLOF_DEBUG
+//#define SLOF_DEBUG
+#ifdef SLOF_DEBUG
+#define dprintf(_x ...) do { printf(_x); } while(0)
+#else
+#define dprintf(_x ...)
+#endif
+
+int slof_usb_handle(struct usb_dev *dev)
+{
+ struct slof_usb_dev sdev;
+ sdev.port = dev->port;
+ sdev.addr = dev->addr;
+ sdev.hcitype = dev->hcidev->type;
+ sdev.num = dev->hcidev->num;
+ sdev.udev = dev;
+
+ if (dev->class == DEV_HID_KEYB) {
+ dprintf("Keyboard %ld %ld\n", dev->hcidev->type, dev->hcidev->num);
+ sdev.devtype = DEVICE_KEYBOARD;
+ forth_push((long)&sdev);
+ forth_eval("s\" dev-keyb.fs\" INCLUDED");
+ } else if (dev->class == DEV_HID_MOUSE) {
+ dprintf("Mouse %ld %ld\n", dev->hcidev->type, dev->hcidev->num);
+ sdev.devtype = DEVICE_MOUSE;
+ forth_push((long)&sdev);
+ forth_eval("s\" dev-mouse.fs\" INCLUDED");
+ } else if ((dev->class >> 16 & 0xFF) == 8) {
+ dprintf("MASS Storage device %ld %ld\n", dev->hcidev->type, dev->hcidev->num);
+ sdev.devtype = DEVICE_DISK;
+ forth_push((long)&sdev);
+ forth_eval("s\" dev-storage.fs\" INCLUDED");
+ } else if (dev->class == DEV_HUB) {
+ dprintf("Generic hub device %ld %ld\n", dev->hcidev->type,
+ dev->hcidev->num);
+ sdev.devtype = DEVICE_HUB;
+ forth_push((long)&sdev);
+ forth_eval("s\" dev-hub.fs\" INCLUDED");
+ }
+ return true;
+}
diff --git a/src/roms/SLOF/lib/libusb/usb-xhci.c b/src/roms/SLOF/lib/libusb/usb-xhci.c
new file mode 100644
index 0000000..7683c51
--- /dev/null
+++ b/src/roms/SLOF/lib/libusb/usb-xhci.c
@@ -0,0 +1,1488 @@
+/*****************************************************************************
+ * Copyright (c) 2013 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <string.h>
+#include "usb.h"
+#include "usb-core.h"
+#include "usb-xhci.h"
+#include "tools.h"
+#include "paflof.h"
+
+#undef XHCI_DEBUG
+//#define XHCI_DEBUG
+#ifdef XHCI_DEBUG
+#define dprintf(_x ...) do { printf("%s: ", __func__); printf(_x); } while (0)
+#else
+#define dprintf(_x ...)
+#endif
+
+static void dump_xhci_regs(struct xhci_hcd *xhcd)
+{
+#ifdef XHCI_DEBUG
+ struct xhci_cap_regs *cap;
+ struct xhci_op_regs *op;
+ struct xhci_run_regs *run;
+
+ cap = xhcd->cap_regs;
+ op = xhcd->op_regs;
+ run = xhcd->run_regs;
+
+ dprintf("\n");
+ dprintf(" - CAPLENGTH %02X\n", read_reg8 (&cap->caplength));
+ dprintf(" - HCIVERSION %04X\n", read_reg16(&cap->hciversion));
+ dprintf(" - HCSPARAMS1 %08X\n", read_reg32(&cap->hcsparams1));
+ dprintf(" - HCSPARAMS2 %08X\n", read_reg32(&cap->hcsparams2));
+ dprintf(" - HCSPARAMS3 %08X\n", read_reg32(&cap->hcsparams3));
+ dprintf(" - HCCPARAMS %08X\n", read_reg32(&cap->hccparams));
+ dprintf(" - DBOFF %08X\n", read_reg32(&cap->dboff));
+ dprintf(" - RTSOFF %08X\n", read_reg32(&cap->rtsoff));
+ dprintf("\n");
+
+ dprintf(" - USBCMD %08X\n", read_reg32(&op->usbcmd));
+ dprintf(" - USBSTS %08X\n", read_reg32(&op->usbsts));
+ dprintf(" - PAGESIZE %08X\n", read_reg32(&op->pagesize));
+ dprintf(" - DNCTRL %08X\n", read_reg32(&op->dnctrl));
+ dprintf(" - CRCR %016llX\n", read_reg64(&op->crcr));
+ dprintf(" - DCBAAP %016llX\n", read_reg64(&op->dcbaap));
+ dprintf(" - CONFIG %08X\n", read_reg32(&op->config));
+ dprintf("\n");
+
+ dprintf(" - MFINDEX %08X\n", read_reg32(&run->mfindex));
+ dprintf("\n");
+#endif
+}
+
+static void print_port_status(struct xhci_port_regs *prs)
+{
+#ifdef XHCI_DEBUG
+ uint32_t portsc;
+ uint32_t CCS, PED, PP, PLS, i, PR = 0;
+
+ portsc = read_reg32(&prs->portsc);
+ dprintf("portsc %08x portpmsc %08x portli %08x\n",
+ portsc,
+ read_reg32(&prs->portpmsc),
+ read_reg32(&prs->portli));
+
+ if (portsc & PORTSC_CCS) {
+ printf("CCS ");
+ CCS = 1;
+ }
+ if (portsc & PORTSC_PED) {
+ printf("PED ");
+ PED = 1;
+ }
+ if (portsc & PORTSC_OCA)
+ printf("OCA ");
+ if (portsc & PORTSC_PR)
+ printf("OCA ");
+ PLS = (portsc & PORTSC_PLS_MASK) >> 5;
+ printf("PLS:%d ", PLS);
+ if (portsc & PORTSC_PP) {
+ printf("PP ");
+ PP = 1;
+ }
+ printf("PS:%d ", (portsc & PORTSC_PS_MASK) >> 10);
+ printf("PIC:%d ", (portsc & PORTSC_PIC_MASK) >> 14);
+ if (portsc & PORTSC_LWS)
+ printf("LWS ");
+ if (portsc & PORTSC_CSC)
+ printf("CSC ");
+ if (portsc & PORTSC_PEC)
+ printf("PEC ");
+ if (portsc & PORTSC_WRC)
+ printf("WRC ");
+ if (portsc & PORTSC_OCC)
+ printf("OCC ");
+ if (portsc & PORTSC_PRC)
+ printf("PRC ");
+ if (portsc & PORTSC_PLC)
+ printf("PLC ");
+ if (portsc & PORTSC_CEC)
+ printf("CEC ");
+ if (portsc & PORTSC_CAS)
+ printf("CAS ");
+ if (portsc & PORTSC_WCE)
+ printf("WCE ");
+ if (portsc & PORTSC_WDE)
+ printf("WDE ");
+ if (portsc & PORTSC_WOE)
+ printf("WOE ");
+ if (portsc & PORTSC_DR)
+ printf("DR ");
+ if (portsc & PORTSC_WPR)
+ printf("WPR ");
+ printf("\n");
+
+ for (i = 0 ; i < (sizeof(ps_array_usb3)/sizeof(struct port_state)); i++) {
+ if (PP == ps_array_usb3[i].PP) {
+ if (CCS == ps_array_usb3[i].CCS) {
+ if (PED == ps_array_usb3[i].PED) {
+ if (PR == ps_array_usb3[i].PR) {
+ dprintf("%s - PLS %d\n", ps_array_usb3[i].state, PLS);
+ break;
+ }
+ }
+ }
+ }
+ }
+#endif
+
+}
+
+static inline bool xhci_is_hc_ready(uint32_t *usbsts)
+{
+ return !(read_reg32(usbsts) & XHCI_USBSTS_CNR);
+}
+
+static inline bool xhci_wait_for_cnr(uint32_t *usbsts)
+{
+ /* Standard:
+ * Note: The xHC should halt within 16 ms. of software clearing the
+ * R/S bit to ‘0’.
+ * Give some more time... 32ms
+ */
+ int count = 320;
+ dprintf("Waiting for Controller ready ..");
+ while (!xhci_is_hc_ready(usbsts)) {
+ dprintf(".");
+ count--;
+ if (!count) {
+ dprintf(" failed %08X\n", read_reg32(usbsts));
+ return false;
+ }
+ SLOF_usleep(100);
+ }
+ dprintf(" done\n");
+ return true;
+}
+
+static bool xhci_hcd_set_runstop(struct xhci_op_regs *op, bool run_req)
+{
+ uint32_t reg;
+
+ dprintf("Request %s\n", run_req ? "RUN" : "STOP");
+ if (!xhci_is_hc_ready(&op->usbsts)) {
+ dprintf("Controller not ready\n");
+ return false;
+ }
+
+ reg = read_reg32(&op->usbcmd);
+ if (run_req)
+ reg |= run_req;
+ else
+ reg &= (uint32_t)~1;
+ dprintf("writing %08X\n", reg);
+ write_reg32(&op->usbcmd, reg);
+ mb();
+ xhci_wait_for_cnr(&op->usbsts);
+ return true;
+}
+
+static bool xhci_hcd_reset(struct xhci_op_regs *op)
+{
+ uint32_t reg;
+
+ /* Check if the controller is halted, else halt it */
+ if (!(read_reg32(&op->usbsts) & XHCI_USBSTS_HCH)) {
+ dprintf("HCHalted not set\n");
+ if (!xhci_hcd_set_runstop(op, false))
+ return false;
+ }
+
+ if (read_reg32(&op->usbsts) & XHCI_USBSTS_CNR) {
+ dprintf("Controller not ready\n");
+ return false;
+ }
+
+ reg = read_reg32(&op->usbcmd) | XHCI_USBCMD_HCRST;
+ /* Ready to Reset the controller now */
+ write_reg32(&op->usbcmd, reg);
+ xhci_wait_for_cnr(&op->usbsts);
+ return true;
+}
+
+static void xhci_handle_cmd_completion(struct xhci_hcd *xhcd,
+ struct xhci_event_trb *event)
+{
+ uint32_t flags, slot_id, status;
+
+ status = le32_to_cpu(event->status);
+ flags = le32_to_cpu(event->flags);
+ slot_id = TRB_SLOT_ID(flags);
+ if (TRB_STATUS(status) == COMP_SUCCESS)
+ xhcd->slot_id = slot_id;
+ else
+ xhcd->slot_id = 0;
+}
+
+static uint64_t xhci_poll_event(struct xhci_hcd *xhcd,
+ uint32_t event_type)
+{
+ struct xhci_event_trb *event;
+ uint64_t val, retval = 0;
+ uint32_t flags, time;
+ int index;
+
+ mb();
+ event = (struct xhci_event_trb *)xhcd->ering.deq;
+ flags = le32_to_cpu(event->flags);
+
+ dprintf("Reading from event ptr %p %08x\n", event, flags);
+ time = SLOF_GetTimer() + USB_TIMEOUT;
+
+ while ((flags & TRB_CYCLE_STATE) != xhcd->ering.cycle_state) {
+ mb();
+ flags = le32_to_cpu(event->flags);
+ if (time < SLOF_GetTimer())
+ return 0;
+ }
+
+ mb();
+ flags = le32_to_cpu(event->flags);
+ switch(TRB_TYPE(flags))
+ {
+ case TRB_CMD_COMPLETION:
+ dprintf("CMD Completion\n");
+ xhci_handle_cmd_completion(xhcd, event);
+ break;
+ case TRB_PORT_STATUS:
+ dprintf("Port status event\n");
+ break;
+ case TRB_TRANSFER_EVENT:
+ dprintf("XFER event addr %16lx, status %08x, flags %08x\n",
+ le64_to_cpu(event->addr),
+ le32_to_cpu(event->status),
+ le32_to_cpu(event->flags));
+ break;
+ default:
+ printf("TRB_TYPE %d\n", TRB_TYPE(flags));
+ dprintf("Event addr %16lx, status %08x, flags %08x state %d\n",
+ le64_to_cpu(event->addr),
+ le32_to_cpu(event->status),
+ flags, xhcd->ering.cycle_state);
+ break;
+ }
+ xhcd->ering.deq = (uint64_t) (event + 1);
+ retval = le64_to_cpu(event->addr);
+
+ event->addr = 0;
+ event->status = 0;
+ event->flags = cpu_to_le32(xhcd->ering.cycle_state);
+
+ index = xhcd->ering.deq - (uint64_t)xhcd->ering.trbs;
+ val = xhcd->ering.trbs_dma;
+ val += (index % XHCI_EVENT_TRBS_SIZE);
+ if (!(index % XHCI_EVENT_TRBS_SIZE)) {
+ xhcd->ering.deq = (uint64_t)xhcd->ering.trbs;
+ xhcd->ering.cycle_state = xhcd->ering.cycle_state ? 0 : 1;
+ dprintf("Rounding %d\n", xhcd->ering.cycle_state);
+ }
+ dprintf("Update start %x deq %x index %d\n",
+ xhcd->ering.trbs_dma, val, index/sizeof(*event));
+ write_reg64(&xhcd->run_regs->irs[0].erdp, val);
+
+ if (retval == 0)
+ return (uint64_t)event;
+ else
+ return retval;
+}
+
+static void xhci_send_cmd(struct xhci_hcd *xhcd, uint32_t field1,
+ uint32_t field2, uint32_t field3, uint32_t field4)
+{
+ struct xhci_db_regs *dbr;
+ struct xhci_command_trb *cmd;
+ uint32_t val, cycle_state;
+
+ dbr = xhcd->db_regs;
+ cmd = (struct xhci_command_trb *)xhcd->crseg.enq;
+
+ cmd->field[0] = cpu_to_le32(field1);
+ cmd->field[1] = cpu_to_le32(field2);
+ cmd->field[2] = cpu_to_le32(field3);
+
+ val = le32_to_cpu(cmd->field[3]);
+ cycle_state = (val & 0x1) ? 0 : 1;
+ val = field4 | cycle_state;
+ cmd->field[3] = cpu_to_le32(val);
+
+ dprintf("CMD %016lx val %08x cycle_state %d field1 %08x, field2 %08x, field3 %08x field4 %08x\n",
+ cmd, val, cycle_state,
+ le32_to_cpu(cmd->field[0]),
+ le32_to_cpu(cmd->field[1]),
+ le32_to_cpu(cmd->field[2]),
+ le32_to_cpu(cmd->field[3])
+ );
+
+ /* Ring the doorbell */
+ write_reg32(&dbr->db[0], 0);
+ xhci_poll_event(xhcd, 0);
+ cmd++;
+ xhcd->crseg.enq = (uint64_t)cmd;
+ return;
+}
+
+static void xhci_send_enable_slot(struct xhci_hcd *xhcd, uint32_t port)
+{
+ uint32_t field1, field2, field3, field4;
+
+ field1 = 0;
+ field2 = 0;
+ field3 = 0;
+ field4 = TRB_CMD_TYPE(TRB_ENABLE_SLOT);
+ xhci_send_cmd(xhcd, field1, field2, field3, field4);
+}
+
+static void xhci_send_addr_device(struct xhci_hcd *xhcd, uint32_t slot_id,
+ uint64_t dma_in_ctx)
+{
+ uint32_t field1, field2, field3, field4;
+
+ dprintf("Address device %lx, low %x, high %x\n", dma_in_ctx,
+ TRB_ADDR_LOW(dma_in_ctx),
+ TRB_ADDR_HIGH(dma_in_ctx));
+ field1 = TRB_ADDR_LOW(dma_in_ctx) & ~0xF;
+ field2 = TRB_ADDR_HIGH(dma_in_ctx);
+ field3 = 0;
+ field4 = TRB_CMD_TYPE(TRB_ADDRESS_DEV) | TRB_CMD_SLOT_ID(slot_id);
+ xhci_send_cmd(xhcd, field1, field2, field3, field4);
+}
+
+static uint32_t xhci_get_epno(struct usb_pipe *pipe)
+{
+ uint32_t x_epno;
+ x_epno = pipe->dir | 2 * pipe->epno;
+ dprintf("EPno %d:%d DIR %d\n", pipe->epno, x_epno, pipe->dir);
+ return x_epno;
+}
+
+static void xhci_configure_ep(struct xhci_hcd *xhcd, uint32_t slot_id,
+ uint64_t dma_in_ctx)
+{
+ uint32_t field1, field2, field3, field4;
+
+ dprintf("Configure EP %lx, low %x, high %x\n", dma_in_ctx,
+ TRB_ADDR_LOW(dma_in_ctx),
+ TRB_ADDR_HIGH(dma_in_ctx));
+ field1 = TRB_ADDR_LOW(dma_in_ctx) & ~0xF;
+ field2 = TRB_ADDR_HIGH(dma_in_ctx);
+ field3 = 0;
+ field4 = TRB_CMD_TYPE(TRB_CONFIG_EP) | TRB_CMD_SLOT_ID(slot_id);
+ xhci_send_cmd(xhcd, field1, field2, field3, field4);
+}
+
+static void xhci_init_seg(struct xhci_seg *seg, uint32_t size, uint32_t type)
+{
+ struct xhci_link_trb *link;
+
+ seg->size = size / XHCI_TRB_SIZE;
+ seg->next = NULL;
+ seg->type = type;
+ seg->cycle_state = 1;
+ seg->enq = (uint64_t)seg->trbs;
+ seg->deq = (uint64_t)seg->trbs;
+ memset((void *)seg->trbs, 0, size);
+
+ if (type != TYPE_EVENT) {
+ link =(struct xhci_link_trb *) (seg->trbs + seg->size - 1);
+ link->addr = cpu_to_le64(seg->trbs_dma);
+ link->field2 = 0;
+ link->field3 = cpu_to_le32(0x1 | TRB_CMD_TYPE(TRB_LINK));
+ }
+ return;
+}
+
+static bool xhci_alloc_seg(struct xhci_seg *seg, uint32_t size, uint32_t type)
+{
+ seg->trbs = (union xhci_trb *)SLOF_dma_alloc(size);
+ if (!seg->trbs) {
+ dprintf("Alloc failed\n");
+ return false;
+ }
+ xhci_init_seg(seg, size, type);
+ seg->trbs_dma = SLOF_dma_map_in((void *)seg->trbs, size, false);
+
+ dprintf(" TRBs %016lX TRBS-DMA %016lX\n", seg->trbs, seg->trbs_dma);
+ return true;
+}
+
+static void xhci_free_seg(struct xhci_seg *seg, uint32_t size)
+{
+ if (seg->trbs) {
+ dprintf(" TRBs %016lX TRBS-DMA %016lX size %x\n", seg->trbs, seg->trbs_dma, size);
+ SLOF_dma_map_out(seg->trbs_dma, (void *)seg->trbs, size);
+ SLOF_dma_free((void *)seg->trbs, size);
+ }
+ memset(seg, 0, sizeof(*seg));
+}
+
+#define CTX_SIZE(x) ( (x) ? 64 : 32 )
+
+static bool xhci_alloc_ctx(struct xhci_ctx *ctx, uint32_t size, uint32_t type)
+{
+ ctx->addr = (uint8_t *)SLOF_dma_alloc(size);
+ if (!ctx->addr) {
+ dprintf("Alloc failed\n");
+ return false;
+ }
+ ctx->size = size;
+ ctx->type = type;
+ memset((void *)ctx->addr, 0, size);
+ ctx->dma_addr = SLOF_dma_map_in((void *)ctx->addr, size, false);
+ dprintf("ctx %llx, ctx_dma %llx\n", ctx->addr, ctx->dma_addr);
+ return true;
+}
+
+static struct xhci_control_ctx *xhci_get_control_ctx(struct xhci_ctx *ctx)
+{
+ if (ctx->type == XHCI_CTX_TYPE_INPUT)
+ return (struct xhci_control_ctx *) ctx->addr;
+ return NULL;
+}
+
+static struct xhci_slot_ctx *xhci_get_slot_ctx(struct xhci_ctx *ctx, uint32_t ctx_size)
+{
+ uint32_t offset = 0;
+
+ if (ctx->type == XHCI_CTX_TYPE_INPUT)
+ offset += ctx_size;
+ return (struct xhci_slot_ctx *)(ctx->addr + offset);
+}
+
+static struct xhci_ep_ctx *xhci_get_ep0_ctx(struct xhci_ctx *ctx, uint32_t ctx_size)
+{
+ uint32_t offset = 0;
+
+ offset = ctx_size;
+ if (ctx->type == XHCI_CTX_TYPE_INPUT)
+ offset += ctx_size;
+ return (struct xhci_ep_ctx *)(ctx->addr + offset);
+}
+
+static struct xhci_ep_ctx *xhci_get_ep_ctx(struct xhci_ctx *ctx, uint32_t ctx_size,
+ uint32_t epno)
+{
+ uint32_t offset = 0;
+
+ offset = ctx_size * epno;
+ if (ctx->type == XHCI_CTX_TYPE_INPUT)
+ offset += ctx_size;
+ return (struct xhci_ep_ctx *)(ctx->addr + offset);
+}
+
+static void xhci_free_ctx(struct xhci_ctx *ctx, uint32_t size)
+{
+ SLOF_dma_map_out(ctx->dma_addr, (void *)ctx->addr, size);
+ SLOF_dma_free((void *)ctx->addr, size);
+}
+
+static uint32_t usb_control_max_packet(uint32_t speed)
+{
+ uint32_t max_packet = 0;
+
+ switch(speed)
+ {
+ case USB_LOW_SPEED:
+ max_packet = 8;
+ break;
+ case USB_FULL_SPEED:
+ max_packet = 8;
+ break;
+ case USB_HIGH_SPEED:
+ max_packet = 64;
+ break;
+ case USB_SUPER_SPEED:
+ max_packet = 512;
+ break;
+ default:
+ /* should not reach here */
+ dprintf("Unknown speed\n");
+ }
+ return max_packet;
+}
+
+static bool xhci_alloc_dev(struct xhci_hcd *xhcd, uint32_t slot_id, uint32_t port)
+{
+ struct usb_dev *dev;
+ struct xhci_dev *xdev;
+ struct xhci_slot_ctx *slot;
+ struct xhci_control_ctx *ctrl;
+ struct xhci_ep_ctx *ep0;
+ uint32_t ctx_size, val;
+ uint16_t max_packet;
+ uint32_t newport;
+
+ ctx_size = CTX_SIZE(xhcd->hcc_csz_64);
+ xdev = &xhcd->xdevs[slot_id];
+ xdev->slot_id = slot_id;
+ xdev->ctx_size = ctx_size;
+
+ /* 4.3.3 Device Slot initialization */
+ /* Step 1 */
+ if (!xhci_alloc_ctx(&xdev->in_ctx, XHCI_CTX_BUF_SIZE, XHCI_CTX_TYPE_INPUT)) {
+ dprintf("Failed allocating in_ctx\n");
+ return false;
+ }
+
+ /* Step 2 */
+ ctrl = xhci_get_control_ctx(&xdev->in_ctx);
+ ctrl->a_flags = cpu_to_le32(0x3); /* A0, A1 */
+ ctrl->d_flags = 0;
+
+ /* Step 3 */
+ slot = xhci_get_slot_ctx(&xdev->in_ctx, ctx_size);
+ newport = port + 1;
+ val = LAST_CONTEXT(1) | SLOT_SPEED_SS | (newport << 16); /* FIXME speed, read from PS */
+ slot->field1 = cpu_to_le32(val);
+ slot->field2 = cpu_to_le32(ROOT_HUB_PORT(newport)); /* FIXME how to get port no */
+
+ /* Step 4 */
+ if (!xhci_alloc_seg(&xdev->control, XHCI_CONTROL_TRBS_SIZE, TYPE_CTRL)) {
+ dprintf("Failed allocating control\n");
+ goto fail_in_ctx;
+ }
+
+ /* Step 5 */
+ ep0 = xhci_get_ep0_ctx(&xdev->in_ctx, ctx_size);
+ val = 0;
+ max_packet = usb_control_max_packet(USB_SUPER_SPEED);
+ max_packet = 64;
+ val = EP_TYPE(EP_CTRL) | MAX_BURST(0) | ERROR_COUNT(3) |
+ MAX_PACKET_SIZE(max_packet);
+ ep0->field2 = cpu_to_le32(val);;
+ ep0->deq_addr = cpu_to_le64(xdev->control.trbs_dma | xdev->control.cycle_state);
+ ep0->field4 = cpu_to_le32(8);
+
+ /* Step 6 */
+ if (!xhci_alloc_ctx(&xdev->out_ctx, XHCI_CTX_BUF_SIZE, XHCI_CTX_TYPE_DEVICE)) {
+ dprintf("Failed allocating out_ctx\n");
+ goto fail_control_seg;
+ }
+
+ /* Step 7 */
+ xhcd->dcbaap[slot_id] = cpu_to_le64(xdev->out_ctx.dma_addr);
+
+ /* Step 8 */
+ slot = xhci_get_slot_ctx(&xdev->out_ctx, ctx_size);
+ ep0 = xhci_get_ep0_ctx(&xdev->out_ctx, ctx_size);
+
+ dprintf("Slot State %x \n", SLOT_STATE(le32_to_cpu(slot->field4)));
+ xhci_send_addr_device(xhcd, slot_id, xdev->in_ctx.dma_addr);
+ mb();
+ dprintf("Slot State %x \n", SLOT_STATE(le32_to_cpu(slot->field4)));
+
+ dprintf("EP0 f0 %08X f1 %08X %016lX %08X\n",
+ le32_to_cpu(ep0->field1),
+ le32_to_cpu(ep0->field2),
+ le64_to_cpu(ep0->deq_addr),
+ le32_to_cpu(ep0->field4));
+
+ /* Step 9 - configure ep */
+ ctrl->a_flags = cpu_to_le32(0x1); /* A0 */
+ ctrl->d_flags = 0;
+ xhci_configure_ep(xhcd, slot_id, xdev->in_ctx.dma_addr);
+ mb();
+ dprintf("Slot State %x \n", SLOT_STATE(le32_to_cpu(slot->field4)));
+ dprintf("USB Device address %d \n", USB_DEV_ADDRESS(le32_to_cpu(slot->field4)));
+ dprintf("EP0 f0 %08X f1 %08X %016lX %08X\n",
+ le32_to_cpu(ep0->field1),
+ le32_to_cpu(ep0->field2),
+ le64_to_cpu(ep0->deq_addr),
+ le32_to_cpu(ep0->field4));
+
+ dev = usb_devpool_get();
+ dprintf("allocated device %p\n", dev);
+ dev->hcidev = xhcd->hcidev;
+ dev->speed = USB_SUPER_SPEED;
+ dev->addr = USB_DEV_ADDRESS(slot->field4);
+ dev->port = newport;
+ dev->priv = xdev;
+ xdev->dev = dev;
+ if (setup_new_device(dev, newport))
+ return true;
+
+ xhci_free_ctx(&xdev->out_ctx, XHCI_CTX_BUF_SIZE);
+fail_control_seg:
+ xhci_free_seg(&xdev->control, XHCI_CONTROL_TRBS_SIZE);
+fail_in_ctx:
+ xhci_free_ctx(&xdev->in_ctx, XHCI_CTX_BUF_SIZE);
+ return false;
+}
+
+static void xhci_free_dev(struct xhci_dev *xdev)
+{
+ xhci_free_seg(&xdev->bulk_in, XHCI_DATA_TRBS_SIZE);
+ xhci_free_seg(&xdev->bulk_out, XHCI_DATA_TRBS_SIZE);
+ xhci_free_seg(&xdev->intr, XHCI_INTR_TRBS_SIZE);
+ xhci_free_seg(&xdev->control, XHCI_CONTROL_TRBS_SIZE);
+ xhci_free_ctx(&xdev->in_ctx, XHCI_CTX_BUF_SIZE);
+ xhci_free_ctx(&xdev->out_ctx, XHCI_CTX_BUF_SIZE);
+}
+
+static bool usb3_dev_init(struct xhci_hcd *xhcd, uint32_t port)
+{
+ /* Device enable slot */
+ xhci_send_enable_slot(xhcd, port);
+ if (!xhcd->slot_id) {
+ dprintf("Unable to get slot id\n");
+ return false;
+ }
+ dprintf("SLOT ID: %d\n", xhcd->slot_id);
+ if (!xhci_alloc_dev(xhcd, xhcd->slot_id, port)) {
+ dprintf("Unable to allocate device\n");
+ return false;
+ }
+ return true;
+}
+
+static int xhci_device_present(uint32_t portsc, uint32_t usb_ver)
+{
+ if (usb_ver == USB_XHCI) {
+ /* Device present and enabled state */
+ if ((portsc & PORTSC_CCS) &&
+ (portsc & PORTSC_PP) &&
+ (portsc & PORTSC_PED)) {
+ return true;
+ }
+ } else if (usb_ver == USB_EHCI) {
+ /* Device present and in disabled state */
+ if ((portsc & PORTSC_CCS) && (portsc & PORTSC_CSC))
+ return true;
+ }
+ return false;
+}
+
+static int xhci_port_scan(struct xhci_hcd *xhcd,
+ uint32_t usb_ver)
+{
+ uint32_t num_ports, portsc, i;
+ struct xhci_op_regs *op;
+ struct xhci_port_regs *prs;
+ struct xhci_cap_regs *cap;
+ uint32_t xecp_off;
+ uint32_t *xecp_addr, *base;
+ uint32_t port_off = 0, port_cnt;
+
+ dprintf("enter\n");
+
+ op = xhcd->op_regs;
+ cap = xhcd->cap_regs;
+ port_cnt = num_ports = read_reg32(&cap->hcsparams1) >> 24;
+
+ /* Read the xHCI extented capability to find usb3 ports and offset*/
+ xecp_off = XHCI_HCCPARAMS_XECP(read_reg32(&cap->hccparams));
+ base = (uint32_t *)cap;
+ while (xecp_off > 0) {
+ xecp_addr = base + xecp_off;
+ dprintf("xecp_off %d %p %p \n", xecp_off, base, xecp_addr);
+
+ if (XHCI_XECP_CAP_ID(read_reg32(xecp_addr)) == XHCI_XECP_CAP_SP &&
+ XHCI_XECP_CAP_SP_MJ(read_reg32(xecp_addr)) == usb_ver &&
+ XHCI_XECP_CAP_SP_MN(read_reg32(xecp_addr)) == 0) {
+ port_cnt = XHCI_XECP_CAP_SP_PC(read_reg32(xecp_addr + 2));
+ port_off = XHCI_XECP_CAP_SP_PO(read_reg32(xecp_addr + 2));
+ dprintf("PortCount %d Portoffset %d\n", port_cnt, port_off);
+ }
+ base = xecp_addr;
+ xecp_off = XHCI_XECP_NEXT_PTR(read_reg32(xecp_addr));
+ }
+ if (port_off == 0) /* port_off should always start from 1 */
+ return false;
+ for (i = (port_off - 1); i < (port_off + port_cnt - 1); i++) {
+ prs = &op->prs[i];
+ portsc = read_reg32(&prs->portsc);
+ if (xhci_device_present(portsc, usb_ver)) {
+ /* Device present */
+ dprintf("Device present on port %d\n", i);
+ /* Reset the port */
+ portsc = read_reg32(&prs->portsc);
+ portsc = portsc | PORTSC_PR;
+ write_reg32(&prs->portsc, portsc);
+ /* FIXME poll for port event */
+ SLOF_msleep(20);
+ xhci_poll_event(xhcd, 0);
+ portsc = read_reg32(&prs->portsc);
+ if (portsc & ~PORTSC_PRC) {
+ dprintf("Port reset complete %d\n", i);
+ }
+ print_port_status(prs);
+ if (!usb3_dev_init(xhcd, (i - (port_off - 1)))) {
+ dprintf("USB device initialization failed\n");
+ }
+ }
+ }
+ dprintf("exit\n");
+ return true;
+}
+
+static int xhci_hub_check_ports(struct xhci_hcd *xhcd)
+{
+ return xhci_port_scan(xhcd, USB_XHCI) | xhci_port_scan(xhcd, USB_EHCI);
+}
+
+static bool xhci_hcd_init(struct xhci_hcd *xhcd)
+{
+ struct xhci_op_regs *op;
+ struct xhci_int_regs *irs;
+ uint64_t val;
+ uint32_t reg;
+
+ if (!xhcd) {
+ dprintf("NULL pointer\n");
+ goto fail;
+ }
+
+ op = xhcd->op_regs;
+ irs = &xhcd->run_regs->irs[0];
+ if (!xhci_hcd_reset(op)) {
+ dprintf("Reset failed\n");
+ goto fail;
+ }
+
+ write_reg32(&op->config, XHCI_CONFIG_MAX_SLOT);
+ reg = read_reg32(&xhcd->cap_regs->hccparams);
+ /* 64byte context !! */
+ xhcd->hcc_csz_64 = (reg & XHCI_HCCPARAMS_CSZ) ? 1 : 0;
+
+ if (xhcd->hcc_csz_64) {
+ printf("usb-xhci: 64 Byte context not supported\n");
+ goto fail;
+ }
+ /*
+ * 6.1 Device Context Base Address Array
+ *
+ * Allocate memory and initialize
+ */
+ xhcd->dcbaap = (uint64_t *)SLOF_dma_alloc(XHCI_DCBAAP_MAX_SIZE);
+ if (!xhcd->dcbaap) {
+ dprintf("Alloc failed\n");
+ goto fail;
+ }
+ memset((void *)xhcd->dcbaap, 0, XHCI_DCBAAP_MAX_SIZE);
+ xhcd->dcbaap_dma = SLOF_dma_map_in((void *)xhcd->dcbaap,
+ XHCI_DCBAAP_MAX_SIZE, false);
+ dprintf("dcbaap %llx, dcbaap_phys %llx\n", xhcd->dcbaap, xhcd->dcbaap_dma);
+ write_reg64(&op->dcbaap, xhcd->dcbaap_dma);
+
+ /*
+ * Command Ring Control - TRB
+ * FIXME - better way to allocate it...
+ */
+ if (!xhci_alloc_seg(&xhcd->crseg, XHCI_CRCR_CRP_SIZE, TYPE_COMMAND))
+ goto fail_dcbaap;
+
+ val = read_reg64(&op->crcr) & ~XHCI_CRCR_CRP_MASK;
+ val = val | (xhcd->crseg.trbs_dma & XHCI_CRCR_CRP_MASK);
+ write_reg64(&op->crcr, val);
+
+ /*
+ * Event Ring Control - TRB
+ * Allocate event TRBS
+ */
+ if (!xhci_alloc_seg(&xhcd->ering, XHCI_EVENT_TRBS_SIZE, TYPE_EVENT))
+ goto fail_crseg;
+
+ /*
+ * Populate event ring segment table.
+ * Note: only using one segment.
+ */
+ xhcd->erst.entries = SLOF_dma_alloc(XHCI_EVENT_TRBS_SIZE);
+ if (!xhcd->erst.entries)
+ goto fail_ering;
+ xhcd->erst.dma = SLOF_dma_map_in((void *)xhcd->erst.entries,
+ XHCI_EVENT_TRBS_SIZE, false);
+ xhcd->erst.num_segs = XHCI_ERST_NUM_SEGS;
+
+ /* populate entries[0] */
+ write_reg64(&xhcd->erst.entries->addr, xhcd->ering.trbs_dma);
+ write_reg32(&xhcd->erst.entries->size, xhcd->ering.size);
+ write_reg32(&xhcd->erst.entries->reserved, 0);
+
+ /* populate erdp */
+ val = read_reg64(&irs->erdp) & ~XHCI_ERDP_MASK;
+ val = val | (xhcd->ering.trbs_dma & XHCI_ERDP_MASK);
+ write_reg64(&irs->erdp, val);
+
+ /* populate erstsz */
+ val = read_reg32(&irs->erstsz) & ~XHCI_ERST_SIZE_MASK;
+ val = val | xhcd->erst.num_segs;
+ write_reg32(&irs->erstsz, val);
+
+ /* Now write the erstba */
+ val = read_reg64(&irs->erstba) & ~XHCI_ERST_ADDR_MASK;
+ val = val | (xhcd->erst.dma & XHCI_ERST_ADDR_MASK);
+ write_reg64(&irs->erstba, val);
+
+ dprintf("ERDP %llx TRB-DMA %llx\n", read_reg64(&irs->erdp),
+ xhcd->ering.trbs_dma);
+ dprintf("ERST %llx, ERST DMA %llx, size %d\n",
+ (uint64_t)xhcd->erst.entries, xhcd->erst.dma,
+ xhcd->erst.num_segs);
+
+ mb();
+ if (!xhci_hcd_set_runstop(op, true))
+ goto fail_erst_entries;
+
+ if (!xhci_hub_check_ports(xhcd))
+ goto fail_erst_entries;
+
+ return true;
+fail_erst_entries:
+ write_reg64(&irs->erstba, 0);
+ mb();
+ SLOF_dma_map_out(xhcd->erst.dma, (void *)xhcd->erst.entries, XHCI_EVENT_TRBS_SIZE);
+ SLOF_dma_free((void *)xhcd->erst.entries, XHCI_EVENT_TRBS_SIZE);
+fail_ering:
+ xhci_free_seg(&xhcd->ering, XHCI_EVENT_TRBS_SIZE);
+fail_crseg:
+ val = read_reg64(&op->crcr) & ~XHCI_CRCR_CRP_MASK;
+ write_reg64(&op->crcr, val);
+ mb();
+ xhci_free_seg(&xhcd->crseg, XHCI_CRCR_CRP_SIZE);
+fail_dcbaap:
+ write_reg64(&op->dcbaap, 0);
+ mb();
+ SLOF_dma_map_out(xhcd->dcbaap_dma, (void *)xhcd->dcbaap, XHCI_DCBAAP_MAX_SIZE);
+ SLOF_dma_free((void *)xhcd->dcbaap, XHCI_DCBAAP_MAX_SIZE);
+fail:
+ return false;
+}
+
+static bool xhci_hcd_exit(struct xhci_hcd *xhcd)
+{
+ struct xhci_op_regs *op;
+ struct xhci_int_regs *irs;
+ uint64_t val;
+ int i;
+
+ if (!xhcd) {
+ dprintf("NULL pointer\n");
+ return false;
+ }
+ op = xhcd->op_regs;
+
+ if (!xhci_hcd_set_runstop(op, false)) {
+ dprintf("NULL pointer\n");
+ }
+
+ for (i = 1; i < XHCI_CONFIG_MAX_SLOT; i++) {
+ if (xhcd->xdevs[i].dev)
+ xhci_free_dev(&xhcd->xdevs[i]);
+ }
+
+ irs = &xhcd->run_regs->irs[0];
+ write_reg64(&irs->erstba, 0);
+ mb();
+ if (xhcd->erst.entries) {
+ SLOF_dma_map_out(xhcd->erst.dma, xhcd->erst.entries, XHCI_EVENT_TRBS_SIZE);
+ SLOF_dma_free(xhcd->erst.entries, XHCI_EVENT_TRBS_SIZE);
+ }
+ xhci_free_seg(&xhcd->ering, XHCI_EVENT_TRBS_SIZE);
+
+ val = read_reg64(&op->crcr) & ~XHCI_CRCR_CRP_MASK;
+ write_reg64(&op->crcr, val);
+ xhci_free_seg(&xhcd->crseg, XHCI_CRCR_CRP_SIZE);
+ write_reg64(&op->dcbaap, 0);
+ if (xhcd->dcbaap) {
+ SLOF_dma_map_out(xhcd->dcbaap_dma, (void *)xhcd->dcbaap, XHCI_DCBAAP_MAX_SIZE);
+ SLOF_dma_free((void *)xhcd->dcbaap, XHCI_DCBAAP_MAX_SIZE);
+ }
+
+ /*
+ * QEMU implementation of XHCI doesn't implement halt
+ * properly. It basically says that it's halted immediately
+ * but doesn't actually terminate ongoing activities and
+ * DMAs. This needs to be fixed in QEMU.
+ *
+ * For now, wait for 50ms grace time till qemu stops using
+ * this device.
+ */
+ SLOF_msleep(50);
+
+ return true;
+}
+
+static void xhci_init(struct usb_hcd_dev *hcidev)
+{
+ struct xhci_hcd *xhcd;
+
+ printf(" XHCI: Initializing\n");
+ dprintf("device base address %p\n", hcidev->base);
+
+ hcidev->base = (void *)((uint64_t)hcidev->base & ~7);
+ xhcd = SLOF_alloc_mem(sizeof(*xhcd));
+ if (!xhcd) {
+ printf("usb-xhci: Unable to allocate memory\n");
+ return;
+ }
+ memset(xhcd, 0, sizeof(*xhcd));
+
+ hcidev->nextaddr = 1;
+ hcidev->priv = xhcd;
+ xhcd->hcidev = hcidev;
+ xhcd->cap_regs = (struct xhci_cap_regs *)(hcidev->base);
+ xhcd->op_regs = (struct xhci_op_regs *)(hcidev->base +
+ read_reg8(&xhcd->cap_regs->caplength));
+ xhcd->run_regs = (struct xhci_run_regs *)(hcidev->base +
+ read_reg32(&xhcd->cap_regs->rtsoff));
+ xhcd->db_regs = (struct xhci_db_regs *)(hcidev->base +
+ read_reg32(&xhcd->cap_regs->dboff));
+ dump_xhci_regs(xhcd);
+ if (!xhci_hcd_init(xhcd))
+ printf("usb-xhci: failed to initialize XHCI controller.\n");
+ dump_xhci_regs(xhcd);
+}
+
+static void xhci_exit(struct usb_hcd_dev *hcidev)
+{
+ struct xhci_hcd *xhcd;
+
+ dprintf("%s: enter \n", __func__);
+ if (!hcidev && !hcidev->priv) {
+ return;
+ }
+
+ xhcd = hcidev->priv;
+ xhci_hcd_exit(xhcd);
+ SLOF_free_mem(xhcd, sizeof(*xhcd));
+ hcidev->priv = NULL;
+}
+
+static void fill_trb_buff(struct xhci_command_trb *cmd, uint32_t field1,
+ uint32_t field2, uint32_t field3, uint32_t field4)
+{
+ uint32_t val, cycle_state;
+
+ cmd->field[0] = cpu_to_le32(field1);
+ cmd->field[1] = cpu_to_le32(field2);
+ cmd->field[2] = cpu_to_le32(field3);
+
+ val = le32_to_cpu(cmd->field[3]);
+ cycle_state = (val & 0x1) ? 0 : 1;
+ val = cycle_state | (field4 & ~0x1);
+ cmd->field[3] = cpu_to_le32(val);
+
+ dprintf("CMD %016lx val %08x cycle_state %d field1 %08x, field2 %08x, field3 %08x field4 %08x\n",
+ cmd, val, cycle_state,
+ le32_to_cpu(cmd->field[0]),
+ le32_to_cpu(cmd->field[1]),
+ le32_to_cpu(cmd->field[2]),
+ le32_to_cpu(cmd->field[3])
+ );
+
+ return;
+}
+
+static void fill_setup_trb(struct xhci_command_trb *cmd, struct usb_dev_req *req,
+ uint32_t size)
+{
+ uint32_t field1, field2, field3, field4 = 0;
+ uint64_t req_raw;
+ uint32_t datalen = 0, pid = 0;
+
+ req_raw = *((uint64_t *)req);
+ dprintf("%lx %lx \n", *((uint64_t *)req), req_raw);
+ /* req_raw is already in right byte order... */
+ field1 = cpu_to_le32(TRB_ADDR_HIGH(req_raw));
+ field2 = cpu_to_le32(TRB_ADDR_LOW(req_raw));
+ field3 = 8; /* ALWAYS 8 */
+
+ datalen = cpu_to_le16(req->wLength);
+ if (datalen) {
+ pid = (req->bmRequestType & REQT_DIR_IN) ? 3 : 2;
+ field4 = TRB_TRT(pid);
+ }
+ field4 |= TRB_CMD_TYPE(TRB_SETUP_STAGE) | TRB_IDT;
+ fill_trb_buff(cmd, field1, field2, field3, field4);
+}
+
+static void fill_setup_data(struct xhci_command_trb *cmd, void *data,
+ uint32_t size, uint32_t dir)
+{
+ uint32_t field1, field2, field3, field4;
+
+ field1 = TRB_ADDR_LOW(data);
+ field2 = TRB_ADDR_HIGH(data);
+ field3 = size;
+ if (dir)
+ field4 = TRB_DIR_IN;
+ field4 |= TRB_CMD_TYPE(TRB_DATA_STAGE);
+ fill_trb_buff(cmd, field1, field2, field3, field4);
+}
+
+static void fill_status_trb(struct xhci_command_trb *cmd, uint32_t dir)
+{
+ uint32_t field1, field2, field3, field4;
+
+ field1 = 0;
+ field2 = 0;
+ field3 = 0;
+ if (dir)
+ field4 = TRB_DIR_IN;
+
+ field4 |= TRB_CMD_TYPE(TRB_STATUS_STAGE) | TRB_IOC;
+ fill_trb_buff(cmd, field1, field2, field3, field4);
+}
+
+static void fill_normal_trb(struct xhci_transfer_trb *trb, void *data,
+ uint32_t size)
+{
+ uint32_t field1, field2, field3, field4;
+
+ field1 = TRB_ADDR_LOW(data);
+ field2 = TRB_ADDR_HIGH(data);
+ field3 = size;
+ field4 = TRB_CMD_TYPE(TRB_NORMAL) | TRB_IOC;
+ fill_trb_buff((struct xhci_command_trb *)trb, field1, field2, field3, field4);
+}
+
+static int xhci_send_ctrl(struct usb_pipe *pipe, struct usb_dev_req *req, void *data)
+{
+ struct xhci_dev *xdev;
+ struct xhci_seg *ctrl;
+ struct xhci_hcd *xhcd;
+ struct xhci_command_trb *cmd;
+ struct xhci_db_regs *dbr;
+ long req_phys = 0, data_phys = 0;
+ int ret = true;
+ uint32_t slot_id, pid = 0, datalen = 0;
+
+ if (!pipe->dev || !pipe->dev->hcidev) {
+ dprintf(" NULL pointer\n");
+ return false;
+ }
+
+ xdev = pipe->dev->priv;
+ slot_id = xdev->slot_id;
+ ctrl = &xdev->control;
+ xhcd = (struct xhci_hcd *)pipe->dev->hcidev->priv;
+ dbr = xhcd->db_regs;
+ if (!ctrl || !xdev || !xhcd) {
+ dprintf(" NULL pointer\n");
+ return false;
+ }
+
+ cmd = (struct xhci_command_trb *)ctrl->enq;
+ req_phys = SLOF_dma_map_in(req, sizeof(struct usb_dev_req), true);
+ fill_setup_trb(cmd, req, sizeof(*req));
+
+ cmd++;
+ datalen = cpu_to_le16(req->wLength);
+ if (datalen)
+ pid = 1;
+ if (datalen) {
+ data_phys = SLOF_dma_map_in(data, datalen, true);
+ fill_setup_data(cmd, (void *) data_phys, datalen, pid);
+ cmd++;
+ }
+
+ fill_status_trb(cmd, pid);
+ cmd++;
+
+ /* Ring the doorbell - ep0 */
+ write_reg32(&dbr->db[slot_id], 1);
+ if (!xhci_poll_event(xhcd, 0)) {
+ dprintf("Command failed\n");
+ ret = false;
+ }
+ ctrl->enq = (uint64_t) cmd;
+ SLOF_dma_map_out(req_phys, req, sizeof(struct usb_dev_req));
+ if (datalen)
+ SLOF_dma_map_out(data_phys, data, datalen);
+ return ret;
+}
+
+static inline struct xhci_pipe *xhci_pipe_get_xpipe(struct usb_pipe *pipe)
+{
+ struct xhci_pipe *xpipe;
+ xpipe = container_of(pipe, struct xhci_pipe, pipe);
+ dprintf("%s: xpipe is %p\n", __func__, xpipe);
+ return xpipe;
+}
+
+static inline struct xhci_seg *xhci_pipe_get_seg(struct usb_pipe *pipe)
+{
+ struct xhci_pipe *xpipe;
+ xpipe = xhci_pipe_get_xpipe(pipe);
+ return xpipe->seg;
+}
+
+static inline void *xhci_get_trb(struct xhci_seg *seg)
+{
+ uint64_t val, enq;
+ int index;
+ struct xhci_link_trb *link;
+
+ enq = val = seg->enq;
+ val = val + XHCI_TRB_SIZE;
+ index = (enq - (uint64_t)seg->trbs) / XHCI_TRB_SIZE + 1;
+ dprintf("%s: enq %llx, val %llx %x\n", __func__, enq, val, index);
+ /* TRBs being a cyclic buffer, here we cycle back to beginning. */
+ if (index == (seg->size - 1)) {
+ dprintf("%s: rounding \n", __func__);
+ seg->enq = (uint64_t)seg->trbs;
+ seg->cycle_state ^= seg->cycle_state;
+ link = (struct xhci_link_trb *) (seg->trbs + seg->size - 1);
+ link->addr = cpu_to_le64(seg->trbs_dma);
+ link->field2 = 0;
+ link->field3 = cpu_to_le32(0x1 | TRB_CMD_TYPE(TRB_LINK));
+ mb();
+ }
+ else {
+ seg->enq = seg->enq + XHCI_TRB_SIZE;
+ }
+
+ return (void *)enq;
+}
+
+static uint64_t xhci_get_trb_phys(struct xhci_seg *seg, uint64_t trb)
+{
+ return seg->trbs_dma + (trb - (uint64_t)seg->trbs);
+}
+
+static int usb_kb = false;
+static int xhci_transfer_bulk(struct usb_pipe *pipe, void *td, void *td_phys,
+ void *data, int datalen)
+{
+ struct xhci_dev *xdev;
+ struct xhci_seg *seg;
+ struct xhci_hcd *xhcd;
+ struct xhci_transfer_trb *trb;
+ struct xhci_db_regs *dbr;
+ int ret = true;
+ uint32_t slot_id, epno, time;
+ uint64_t trb_phys, event_phys;
+
+ if (!pipe->dev || !pipe->dev->hcidev) {
+ dprintf(" NULL pointer\n");
+ dprintf(" pipe dev %p hcidev %p\n", pipe->dev, pipe->dev->hcidev);
+ return false;
+ }
+
+ xdev = pipe->dev->priv;
+ slot_id = xdev->slot_id;
+ seg = xhci_pipe_get_seg(pipe);
+ xhcd = (struct xhci_hcd *)pipe->dev->hcidev->priv;
+ dbr = xhcd->db_regs;
+ if (!seg || !xdev || !xhcd) {
+ dprintf(" NULL pointer\n");
+ dprintf(" seg %p xdev %p xhcd %p\n", seg, xdev, xhcd);
+ return false;
+ }
+
+ if (datalen > XHCI_MAX_BULK_SIZE) {
+ printf("usb-xhci: bulk transfer size too big\n");
+ return false;
+ }
+
+ trb = xhci_get_trb(seg);
+ trb_phys = xhci_get_trb_phys(seg, (uint64_t)trb);
+ fill_normal_trb(trb, (void *)data, datalen);
+
+ epno = xhci_get_epno(pipe);
+ write_reg32(&dbr->db[slot_id], epno);
+
+ time = SLOF_GetTimer() + USB_TIMEOUT;
+ while (1) {
+ event_phys = xhci_poll_event(xhcd, 0);
+ if (event_phys == trb_phys) {
+ break;
+ } else if (event_phys == 0) { /* polling timed out */
+ ret = false;
+ break;
+ } else
+ usb_kb = true;
+
+ /* transfer timed out */
+ if (time < SLOF_GetTimer())
+ return false;
+ }
+ trb->addr = 0;
+ trb->len = 0;
+ trb->flags = 0;
+ mb();
+
+ return ret;
+}
+
+static int xhci_alloc_pipe_pool(struct xhci_hcd *xhcd)
+{
+ struct xhci_pipe *xpipe, *curr, *prev;
+ unsigned int i, count;
+ long xpipe_phys = 0;
+
+ count = XHCI_PIPE_POOL_SIZE/sizeof(*xpipe);
+ xhcd->pool = xpipe = SLOF_dma_alloc(XHCI_PIPE_POOL_SIZE);
+ if (!xpipe)
+ return -1;
+ xhcd->pool_phys = xpipe_phys = SLOF_dma_map_in(xpipe, XHCI_PIPE_POOL_SIZE, true);
+ dprintf("%s: xpipe %p, xpipe_phys %lx\n", __func__, xpipe, xpipe_phys);
+
+ /* Although an array, link them */
+ for (i = 0, curr = xpipe, prev = NULL; i < count; i++, curr++) {
+ if (prev)
+ prev->pipe.next = &curr->pipe;
+ curr->pipe.next = NULL;
+ prev = curr;
+ }
+
+ if (!xhcd->freelist)
+ xhcd->freelist = &xpipe->pipe;
+ else
+ xhcd->end->next = &xpipe->pipe;
+ xhcd->end = &prev->pipe;
+
+ return 0;
+}
+
+static void xhci_init_bulk_ep(struct usb_dev *dev, struct usb_pipe *pipe)
+{
+ struct xhci_hcd *xhcd;
+ struct xhci_dev *xdev;
+ struct xhci_seg *seg;
+ struct xhci_pipe *xpipe;
+ struct xhci_control_ctx *ctrl;
+ struct xhci_ep_ctx *ep;
+ uint32_t x_epno, val, type;
+
+ if (!pipe || !dev || !dev->priv)
+ return;
+
+ xdev = dev->priv;
+ xhcd = dev->hcidev->priv;
+ dprintf("dir %d\n", pipe->dir);
+ seg = xhci_pipe_get_seg(pipe);
+ xpipe = xhci_pipe_get_xpipe(pipe);
+ if (pipe->dir) {
+ type = EP_BULK_IN;
+ seg = &xdev->bulk_in;
+ }
+ else {
+ type = EP_BULK_OUT;
+ seg = &xdev->bulk_out;
+ }
+
+ if (!seg->trbs) {
+ if (!xhci_alloc_seg(seg, XHCI_DATA_TRBS_SIZE, TYPE_BULK)) {
+ printf("usb-xhci: allocation failed for bulk endpoint\n");
+ return;
+ }
+ } else {
+ xhci_init_seg(seg, XHCI_DATA_TRBS_SIZE, TYPE_BULK);
+ }
+
+ pipe->mps = XHCI_MAX_BULK_SIZE;
+ ctrl = xhci_get_control_ctx(&xdev->in_ctx);
+ x_epno = xhci_get_epno(pipe);
+ ep = xhci_get_ep_ctx(&xdev->in_ctx, xdev->ctx_size, x_epno);
+ val = EP_TYPE(type) | MAX_BURST(0) | ERROR_COUNT(3) |
+ MAX_PACKET_SIZE(pipe->mps);
+ ep->field2 = cpu_to_le32(val);;
+ ep->deq_addr = cpu_to_le64(seg->trbs_dma | seg->cycle_state);
+ ep->field4 = cpu_to_le32(8);
+ ctrl->a_flags = cpu_to_le32(BIT(x_epno) | 0x1);
+ ctrl->d_flags = 0;
+ xhci_configure_ep(xhcd, xdev->slot_id, xdev->in_ctx.dma_addr);
+ xpipe->seg = seg;
+}
+
+static int xhci_get_pipe_intr(struct usb_pipe *pipe,
+ struct xhci_hcd *xhcd,
+ char *buf, size_t len)
+{
+ struct xhci_dev *xdev;
+ struct xhci_seg *seg;
+ struct xhci_pipe *xpipe;
+ struct xhci_control_ctx *ctrl;
+ struct xhci_ep_ctx *ep;
+ uint32_t x_epno, val, type;
+ struct usb_dev *dev;
+ struct xhci_transfer_trb *trb;
+
+ dev = pipe->dev;
+ if (dev->class != DEV_HID_KEYB)
+ return false;
+
+ xdev = dev->priv;
+ pipe->mps = 8;
+ seg = xhci_pipe_get_seg(pipe);
+ xpipe = xhci_pipe_get_xpipe(pipe);
+ type = EP_INT_IN;
+ seg = &xdev->intr;
+
+ if (!seg->trbs) {
+ if (!xhci_alloc_seg(seg, XHCI_INTR_TRBS_SIZE, TYPE_BULK)) {
+ printf("usb-xhci: allocation failed for interrupt endpoint\n");
+ return false;
+ }
+ } else {
+ xhci_init_seg(seg, XHCI_EVENT_TRBS_SIZE, TYPE_BULK);
+ }
+
+ xpipe->buf = buf;
+ xpipe->buf_phys = SLOF_dma_map_in(buf, len, false);
+ xpipe->buflen = len;
+
+ ctrl = xhci_get_control_ctx(&xdev->in_ctx);
+ x_epno = xhci_get_epno(pipe);
+ ep = xhci_get_ep_ctx(&xdev->in_ctx, xdev->ctx_size, x_epno);
+ val = EP_TYPE(type) | MAX_BURST(0) | ERROR_COUNT(3) |
+ MAX_PACKET_SIZE(pipe->mps);
+ ep->field2 = cpu_to_le32(val);
+ ep->deq_addr = cpu_to_le64(seg->trbs_dma | seg->cycle_state);
+ ep->field4 = cpu_to_le32(8);
+ ctrl->a_flags = cpu_to_le32(BIT(x_epno) | 0x1);
+ ctrl->d_flags = 0;
+ xhci_configure_ep(xhcd, xdev->slot_id, xdev->in_ctx.dma_addr);
+ xpipe->seg = seg;
+
+ trb = xhci_get_trb(seg);
+ fill_normal_trb(trb, (void *)xpipe->buf_phys, pipe->mps);
+ return true;
+}
+
+static struct usb_pipe* xhci_get_pipe(struct usb_dev *dev, struct usb_ep_descr *ep, char *buf, size_t len)
+{
+ struct xhci_hcd *xhcd;
+ struct usb_pipe *new = NULL;
+
+ if (!dev)
+ return NULL;
+
+ xhcd = (struct xhci_hcd *)dev->hcidev->priv;
+ if (!xhcd->freelist) {
+ dprintf("usb-xhci: %s allocating pool\n", __func__);
+ if (xhci_alloc_pipe_pool(xhcd))
+ return NULL;
+ }
+
+ new = xhcd->freelist;
+ xhcd->freelist = xhcd->freelist->next;
+ if (!xhcd->freelist)
+ xhcd->end = NULL;
+
+ memset(new, 0, sizeof(*new));
+ new->dev = dev;
+ new->next = NULL;
+ new->type = ep->bmAttributes & USB_EP_TYPE_MASK;
+ new->speed = dev->speed;
+ new->mps = ep->wMaxPacketSize;
+ new->dir = (ep->bEndpointAddress & 0x80) >> 7;
+ new->epno = ep->bEndpointAddress & 0x0f;
+
+ if (new->type == USB_EP_TYPE_INTR) {
+ if (!xhci_get_pipe_intr(new, xhcd, buf, len)) {
+ printf("usb-xhci: %s alloc_intr failed %p\n",
+ __func__, new);
+ }
+ }
+ if (new->type == USB_EP_TYPE_BULK)
+ xhci_init_bulk_ep(dev, new);
+
+ return new;
+}
+
+static void xhci_put_pipe(struct usb_pipe *pipe)
+{
+ struct xhci_hcd *xhcd;
+ struct xhci_pipe *xpipe;
+
+ dprintf("usb-xhci: %s enter - %p\n", __func__, pipe);
+ if (!pipe || !pipe->dev)
+ return;
+ xhcd = pipe->dev->hcidev->priv;
+
+ dprintf("dir %d\n", pipe->dir);
+ if (pipe->type == USB_EP_TYPE_BULK) {
+ xpipe = xhci_pipe_get_xpipe(pipe);
+ xpipe->seg = NULL;
+ } else if (pipe->type == USB_EP_TYPE_INTR) {
+ xpipe = xhci_pipe_get_xpipe(pipe);
+ SLOF_dma_map_out(xpipe->buf_phys, xpipe->buf, xpipe->buflen);
+ xpipe->seg = NULL;
+ }
+ if (xhcd->end)
+ xhcd->end->next = pipe;
+ else
+ xhcd->freelist = pipe;
+
+ xhcd->end = pipe;
+ pipe->next = NULL;
+ pipe->dev = NULL;
+ memset(pipe, 0, sizeof(*pipe));
+
+ dprintf("usb-xhci: %s exit\n", __func__);
+}
+
+static int xhci_poll_intr(struct usb_pipe *pipe, uint8_t *data)
+{
+ struct xhci_transfer_trb *trb;
+ struct xhci_seg *seg;
+ struct xhci_pipe *xpipe;
+ struct xhci_dev *xdev;
+ struct xhci_hcd *xhcd;
+ struct xhci_db_regs *dbr;
+ uint32_t x_epno;
+ uint8_t *buf, ret = 1;
+
+ if (!pipe || !pipe->dev || !pipe->dev->hcidev)
+ return 0;
+ xdev = pipe->dev->priv;
+ xhcd = (struct xhci_hcd *)pipe->dev->hcidev->priv;
+ x_epno = xhci_get_epno(pipe);
+ seg = xhci_pipe_get_seg(pipe);
+ xpipe = xhci_pipe_get_xpipe(pipe);
+
+ if (usb_kb == true) {
+ /* This event was consumed by bulk transfer */
+ usb_kb = false;
+ goto skip_poll;
+ }
+ buf = xpipe->buf;
+ memset(buf, 0, 8);
+
+ mb();
+ /* Ring the doorbell - x_epno */
+ dbr = xhcd->db_regs;
+ write_reg32(&dbr->db[xdev->slot_id], x_epno);
+ if (!xhci_poll_event(xhcd, 0)) {
+ printf("poll intr failed\n");
+ return 0;
+ }
+ mb();
+ memcpy(data, buf, 8);
+
+skip_poll:
+ trb = xhci_get_trb(seg);
+ fill_normal_trb(trb, (void *)xpipe->buf_phys, pipe->mps);
+ mb();
+ return ret;
+}
+
+struct usb_hcd_ops xhci_ops = {
+ .name = "xhci-hcd",
+ .init = xhci_init,
+ .exit = xhci_exit,
+ .usb_type = USB_XHCI,
+ .get_pipe = xhci_get_pipe,
+ .put_pipe = xhci_put_pipe,
+ .poll_intr = xhci_poll_intr,
+ .send_ctrl = xhci_send_ctrl,
+ .transfer_bulk = xhci_transfer_bulk,
+ .next = NULL,
+};
+
+void usb_xhci_register(void)
+{
+ usb_hcd_register(&xhci_ops);
+}
diff --git a/src/roms/SLOF/lib/libusb/usb-xhci.h b/src/roms/SLOF/lib/libusb/usb-xhci.h
new file mode 100644
index 0000000..3fc7e78
--- /dev/null
+++ b/src/roms/SLOF/lib/libusb/usb-xhci.h
@@ -0,0 +1,391 @@
+/******************************************************************************
+ * Copyright (c) 2013 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+/*
+ * Definitions for XHCI Controller - Revision 1.0 (5/21/10)
+ *
+ */
+
+#ifndef USB_XHCI_H
+#define USB_XHCI_H
+
+#include <stdint.h>
+#include "usb-core.h"
+
+#define BIT(x) (1 << x)
+
+/* 5.3 Host Controller Capability Registers
+ * Table 19
+ */
+struct xhci_cap_regs {
+ uint8_t caplength;
+ uint8_t reserved;
+ uint16_t hciversion;
+ uint32_t hcsparams1;
+ uint32_t hcsparams2;
+ uint32_t hcsparams3;
+ uint32_t hccparams;
+#define XHCI_HCCPARAMS_CSZ BIT(2)
+#define XHCI_HCCPARAMS_XECP(x) ((x & 0xFFFF0000) >> 16)
+ uint32_t dboff;
+ uint32_t rtsoff;
+} __attribute__ ((packed));
+
+/* USB 3.0: Section 7 and 7.2 */
+#define XHCI_XECP_CAP_ID(x) ((x & 0xF))
+#define XHCI_XECP_CAP_SP 2
+#define XHCI_XECP_CAP_SP_MN(x) ((x & 0xFF0000) >> 16)
+#define XHCI_XECP_CAP_SP_MJ(x) ((x & 0xFF000000) >> 24)
+#define XHCI_XECP_CAP_SP_PC(x) ((x & 0xFF00) >> 8)
+#define XHCI_XECP_CAP_SP_PO(x) (x & 0xFF)
+#define XHCI_XECP_NEXT_PTR(x) ((x & 0xFF00) >> 8)
+
+/* Table 27: Host Controller USB Port Register Set */
+struct xhci_port_regs {
+ uint32_t portsc;
+#define PORTSC_CCS BIT(0)
+#define PORTSC_PED BIT(1)
+#define PORTSC_OCA BIT(3)
+#define PORTSC_PR BIT(4)
+#define PORTSC_PLS_MASK (0xF << 5)
+#define PORTSC_PLS_U0 0
+#define PORTSC_PLS_U1 1
+#define PORTSC_PLS_U2 2
+#define PORTSC_PLS_U3 3
+#define PORTSC_PLS_DISABLED 4
+#define PORTSC_PLS_RXDETECT 5
+#define PORTSC_PLS_INACTIVE 6
+#define PORTSC_PLS_POLLING 7
+#define PORTSC_PLS_RECOVERY 8
+#define PORTSC_PLS_HOTRESET 9
+#define PORTSC_PLS_COMP_MODE 10
+#define PORTSC_PLS_TEST_MODE 11
+#define PORTSC_PLS_RESUME 15
+#define PORTSC_PP BIT(9)
+#define PORTSC_PS_MASK (0xF << 10)
+#define PORTSC_PIC_MASK (0x3 << 14)
+#define PORTSC_LWS BIT(16)
+#define PORTSC_CSC BIT(17)
+#define PORTSC_PEC BIT(18)
+#define PORTSC_WRC BIT(19)
+#define PORTSC_OCC BIT(20)
+#define PORTSC_PRC BIT(21)
+#define PORTSC_PLC BIT(22)
+#define PORTSC_CEC BIT(23)
+#define PORTSC_CAS BIT(24)
+#define PORTSC_WCE BIT(25)
+#define PORTSC_WDE BIT(26)
+#define PORTSC_WOE BIT(27)
+#define PORTSC_DR BIT(30)
+#define PORTSC_WPR BIT(31)
+
+ uint32_t portpmsc;
+ uint32_t portli;
+ uint32_t reserved;
+} __attribute__ ((packed));
+
+struct port_state {
+ bool PP;
+ bool CCS;
+ bool PED;
+ bool PR;
+ uint8_t PLS;
+ char *state;
+};
+
+
+struct port_state ps_array_usb2[] = {
+ {1, 0, 0, 0, PORTSC_PLS_U0, "ERROR"}
+};
+
+struct port_state ps_array_usb3[] = {
+ {0, 0, 0, 0, PORTSC_PLS_DISABLED, "Powered-OFF"},
+ {1, 0, 0, 0, PORTSC_PLS_POLLING, "Polling"},
+ {1, 0, 0, 0, PORTSC_PLS_U0, "Polling"},
+ {1, 0, 0, 0, PORTSC_PLS_RXDETECT, "*** Disconnected ***"},
+ {1, 0, 0, 0, PORTSC_PLS_DISABLED, "Disabled"},
+ {1, 0, 0, 0, PORTSC_PLS_INACTIVE, "Error"},
+ {1, 0, 0, 0, PORTSC_PLS_TEST_MODE,"Loopback"},
+ {1, 0, 0, 0, PORTSC_PLS_COMP_MODE,"Compliancek"},
+ {1, 1, 0, 1, PORTSC_PLS_U0, "****** Reset ******"},
+ {1, 1, 1, 0, PORTSC_PLS_U0, "****** Enabled ******"},
+};
+
+/* 5.4 Host Controller Operational Registers
+ * Table 26
+ */
+struct xhci_op_regs {
+ uint32_t usbcmd;
+#define XHCI_USBCMD_RS BIT(0)
+#define XHCI_USBCMD_HCRST BIT(1)
+
+ uint32_t usbsts;
+#define XHCI_USBSTS_HCH BIT(0)
+#define XHCI_USBSTS_CNR BIT(11)
+
+ uint32_t pagesize;
+ uint8_t reserved[8]; /* 0C - 13 */
+ uint32_t dnctrl; /* Device notification control */
+ uint64_t crcr; /* Command ring control */
+#define XHCI_CRCR_CRP_MASK 0xFFFFFFFFFFFFFFC0
+#define XHCI_CRCR_CRR BIT(3)
+#define XHCI_CRCR_CRP_SIZE 4096
+
+ uint8_t reserved1[16]; /* 20 - 2F */
+ uint64_t dcbaap; /* Device Context Base Address Array Pointer */
+#define XHCI_DCBAAP_MAX_SIZE 2048
+
+ uint32_t config; /* Configure */
+#define XHCI_CONFIG_MAX_SLOT 4
+
+ uint8_t reserved2[964]; /* 3C - 3FF */
+ /* USB Port register set */
+#define XHCI_PORT_MAX 256
+ struct xhci_port_regs prs[XHCI_PORT_MAX];
+} __attribute__ ((packed));
+
+/*
+ * 5.5.2 Interrupter Register Set
+ * Table 42: Interrupter Registers
+ */
+struct xhci_int_regs {
+ uint32_t iman;
+ uint32_t imod;
+ uint32_t erstsz;
+#define XHCI_ERST_SIZE_MASK 0xFFFF
+ uint32_t reserved;
+ uint64_t erstba;
+#define XHCI_ERST_ADDR_MASK (~(0x3FUL))
+ uint64_t erdp;
+#define XHCI_ERDP_MASK (~(0xFUL))
+} __attribute__ ((packed));
+
+/* 5.5 Host Controller Runtime Registers */
+struct xhci_run_regs {
+ uint32_t mfindex; /* microframe index */
+ uint8_t reserved[28];
+#define XHCI_IRS_MAX 1024
+ struct xhci_int_regs irs[XHCI_IRS_MAX];
+} __attribute__ ((packed));
+
+/* 5.6 Doorbell Registers*/
+struct xhci_db_regs {
+ uint32_t db[256];
+} __attribute__ ((packed));
+
+#define COMP_SUCCESS 1
+
+#define TRB_SLOT_ID(x) (((x) & (0xFF << 24)) >> 24)
+#define TRB_CMD_SLOT_ID(x) ((x & 0xFF) << 24)
+#define TRB_TYPE(x) (((x) & (0x3F << 10)) >> 10)
+#define TRB_CMD_TYPE(x) ((x & 0x3F) << 10)
+#define TRB_STATUS(x) (((x) & (0xFF << 24)) >> 24)
+#define TRB_ADDR_LOW(x) ((uint32_t)((uint64_t)(x)))
+#define TRB_ADDR_HIGH(x) ((uint32_t)((uint64_t)(x) >> 32))
+#define TRB_TRT(x) (((x) & 0x3) << 16 )
+#define TRB_DIR_IN BIT(16)
+#define TRB_IOC BIT(5)
+#define TRB_IDT BIT(6)
+
+#define TRB_CYCLE_STATE BIT(0)
+
+struct xhci_transfer_trb {
+ uint64_t addr;
+ uint32_t len;
+ uint32_t flags;
+} __attribute__ ((packed));
+
+struct xhci_link_trb {
+ uint64_t addr;
+ uint32_t field2;
+ uint32_t field3;
+} __attribute__ ((packed));
+
+/* Event TRB */
+struct xhci_event_trb {
+ uint64_t addr;
+ uint32_t status;
+ uint32_t flags;
+} __attribute__ ((packed));
+
+#define TRB_NORMAL 1
+#define TRB_SETUP_STAGE 2
+#define TRB_DATA_STAGE 3
+#define TRB_STATUS_STAGE 4
+#define TRB_ISOCH 5
+#define TRB_LINK 6
+#define TRB_EVENT_DATA 7
+#define TRB_NOOP 8
+#define TRB_ENABLE_SLOT 9
+#define TRB_DISABLE_SLOT 10
+#define TRB_ADDRESS_DEV 11
+#define TRB_CONFIG_EP 12
+#define TRB_EVAL_CNTX 13
+#define TRB_TRANSFER_EVENT 32
+#define TRB_CMD_COMPLETION 33
+#define TRB_PORT_STATUS 34
+
+struct xhci_command_trb {
+ uint32_t field[4];
+}__attribute__ ((packed));
+
+union xhci_trb {
+ struct xhci_event_trb event;
+ struct xhci_transfer_trb xfer;
+ struct xhci_command_trb cmd;
+ struct xhci_link_trb link;
+};
+
+enum xhci_seg_type {
+ TYPE_CTRL = 0,
+ TYPE_BULK,
+ TYPE_COMMAND,
+ TYPE_EVENT,
+};
+
+struct xhci_seg {
+ union xhci_trb *trbs;
+ struct xhci_seg *next;
+ uint64_t enq;
+ uint64_t deq;
+ uint64_t trbs_dma;
+ uint32_t size;
+ uint32_t cycle_state;
+ enum xhci_seg_type type;
+};
+
+#define XHCI_TRB_SIZE 16
+#define XHCI_EVENT_TRBS_SIZE 4096
+#define XHCI_CONTROL_TRBS_SIZE 4096
+#define XHCI_DATA_TRBS_SIZE 4096
+#define XHCI_INTR_TRBS_SIZE 4096
+#define XHCI_ERST_NUM_SEGS 1
+
+#define XHCI_MAX_BULK_SIZE 0xF000
+
+struct xhci_erst_entry {
+ uint64_t addr;
+ uint32_t size;
+ uint32_t reserved;
+} __attribute__ ((packed));
+
+struct xhci_erst {
+ struct xhci_erst_entry *entries;
+ uint64_t dma;
+ uint32_t num_segs; /* number of segments */
+};
+
+struct xhci_control_ctx {
+ uint32_t d_flags;
+ uint32_t a_flags;
+ uint32_t reserved[6];
+} __attribute__ ((packed));
+
+struct xhci_slot_ctx {
+ uint32_t field1;
+#define SLOT_SPEED_FS BIT(20)
+#define SLOT_SPEED_LS BIT(21)
+#define SLOT_SPEED_HS BIT(22)
+#define SLOT_SPEED_SS BIT(23)
+#define LAST_CONTEXT(x) (x << 27)
+
+ uint32_t field2;
+#define ROOT_HUB_PORT(x) ((x & 0xff) << 16)
+
+ uint32_t field3;
+ uint32_t field4;
+#define USB_DEV_ADDRESS(x) (x & 0xFFU)
+#define SLOT_STATE(x) ((x >> 27) & 0x1FU)
+#define SLOT_STATE_DIS_ENA 0
+#define SLOT_STATE_DEFAULT 1
+#define SLOT_STATE_ADDRESSED 2
+#define SLOT_STATE_CONFIGURED 3
+
+
+ uint32_t reserved[4];
+} __attribute__ ((packed));
+
+struct xhci_ep_ctx {
+ uint32_t field1;
+ uint32_t field2;
+#define MAX_PACKET_SIZE(x) (((x) & 0xFFFF) << 16)
+#define MAX_BURST(x) (((x) & 0xFF) << 8)
+#define EP_TYPE(x) (((x) & 0x07) << 3)
+#define EP_ISOC_OUT 1
+#define EP_BULK_OUT 2
+#define EP_INT_OUT 3
+#define EP_CTRL 4
+#define EP_ISOC_IN 5
+#define EP_BULK_IN 6
+#define EP_INT_IN 7
+
+#define ERROR_COUNT(x) (((x) & 0x03) << 1)
+
+ uint64_t deq_addr;
+ uint32_t field4;
+ uint32_t reserved[3];
+} __attribute__ ((packed));
+
+struct xhci_ctx {
+ uint8_t type;
+#define XHCI_CTX_TYPE_DEVICE 0x1
+#define XHCI_CTX_TYPE_INPUT 0x2
+ uint32_t size;
+ uint8_t *addr;
+#define XHCI_CTX_BUF_SIZE 4096
+ uint64_t dma_addr;
+};
+
+struct xhci_dev {
+ struct usb_dev *dev;
+ uint32_t slot_id;
+ struct xhci_ctx in_ctx;
+ struct xhci_ctx out_ctx;
+ struct xhci_seg control;
+ struct xhci_seg intr;
+ struct xhci_seg bulk_in;
+ struct xhci_seg bulk_out;
+ uint32_t ctx_size;
+};
+
+struct xhci_hcd {
+ struct xhci_cap_regs *cap_regs;
+ struct xhci_op_regs *op_regs;
+ struct xhci_run_regs *run_regs;
+ struct xhci_db_regs *db_regs;
+ struct usb_hcd_dev *hcidev;
+ struct xhci_dev xdevs[XHCI_CONFIG_MAX_SLOT + 1];
+ struct usb_pipe *freelist;
+ struct usb_pipe *end;
+ uint64_t *dcbaap;
+ uint64_t dcbaap_dma;
+ struct xhci_seg ering;
+ struct xhci_seg crseg;
+ struct xhci_erst erst;
+ uint64_t erds_dma;
+ uint32_t erds_size;
+ uint32_t slot_id;
+ uint32_t hcc_csz_64;
+ void *pool;
+#define XHCI_PIPE_POOL_SIZE 4096
+
+ long pool_phys;
+};
+
+struct xhci_pipe {
+ struct usb_pipe pipe;
+ struct xhci_seg *seg;
+ void *buf;
+ long buf_phys;
+ uint32_t buflen;
+};
+
+#endif /* USB_XHCI_H */
diff --git a/src/roms/SLOF/lib/libusb/usb.code b/src/roms/SLOF/lib/libusb/usb.code
new file mode 100644
index 0000000..fd92d9e
--- /dev/null
+++ b/src/roms/SLOF/lib/libusb/usb.code
@@ -0,0 +1,162 @@
+/******************************************************************************
+ * Copyright (c) 2013 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+/*
+ * libusb bindings for SLOF - implementation
+ */
+
+#include <usb.h>
+
+
+/************************************************/
+/* Register with the usb-core */
+/* SLOF: USB-OHCI-REGISTER ( -- ) */
+/* LIBNEWUSB: usb_ohci_register(void) */
+/************************************************/
+PRIM(USB_X2d_OHCI_X2d_REGISTER)
+ usb_ohci_register();
+MIRP
+
+/************************************************/
+/* Register with the usb-core */
+/* SLOF: USB-EHCI-REGISTER ( -- ) */
+/* LIBNEWUSB: usb_ehci_register(void) */
+/************************************************/
+PRIM(USB_X2d_EHCI_X2d_REGISTER)
+ usb_ehci_register();
+MIRP
+
+/************************************************/
+/* Register with the usb-core */
+/* SLOF: USB-XHCI-REGISTER ( -- ) */
+/* LIBNEWUSB: usb_xhci_register(void) */
+/************************************************/
+PRIM(USB_X2d_XHCI_X2d_REGISTER)
+ usb_xhci_register();
+MIRP
+
+/************************************************/
+/* Initialize hcidev with the usb-core */
+/* SLOF: USB-HCD-INIT ( hcidev -- ) */
+/* LIBNEWUSB: usb_hcd_init(hcidev) */
+/************************************************/
+PRIM(USB_X2d_HCD_X2d_INIT)
+ void *hcidev = TOS.a; POP;
+ usb_hcd_init(hcidev);
+MIRP
+
+/************************************************/
+/* Remove hcidev with the usb-core */
+/* SLOF: USB-HCD-EXIT ( hcidev -- ) */
+/* LIBNEWUSB: usb_hcd_exit(hcidev) */
+/************************************************/
+PRIM(USB_X2d_HCD_X2d_EXIT)
+ void *hcidev = TOS.a; POP;
+ usb_hcd_exit(hcidev);
+MIRP
+
+/************************************************/
+/* Initialize hid */
+/* SLOF: USB-HID-INIT ( dev -- true | false )*/
+/* LIBNEWUSB: usb_hid_init(hcidev) */
+/************************************************/
+PRIM(USB_X2d_HID_X2d_INIT)
+ void *dev = TOS.a;
+ TOS.n = usb_hid_init(dev);
+MIRP
+
+/************************************************/
+/* Exit hid */
+/* SLOF: USB-HID-EXIT ( dev -- true | false )*/
+/* LIBNEWUSB: usb_hid_exit(hcidev) */
+/************************************************/
+PRIM(USB_X2d_HID_X2d_EXIT)
+ void *dev = TOS.a;
+ TOS.n = usb_hid_exit(dev);
+MIRP
+
+/************************************************/
+/* Read usb keyboard for key */
+/* SLOF: USB-READ-KEYB ( dev -- */
+/* ( key | false )) */
+/* LIBNEWUSB: usb_read_keyb */
+/************************************************/
+PRIM(USB_X2d_READ_X2d_KEYB)
+ void *dev = TOS.a;
+ TOS.n = usb_read_keyb(dev);
+MIRP
+
+/************************************************/
+/* Is USB KEY available */
+/* SLOF: USB-KEY-AVAILABLE ( dev -- ( true | */
+/* false ))*/
+/* LIBNEWUSB: usb_key_available */
+/************************************************/
+PRIM(USB_X2d_KEY_X2d_AVAILABLE)
+ void *dev = TOS.a;
+ TOS.n = usb_key_available(dev);
+MIRP
+
+/************************************************/
+/* Initialize and enumerate generic hub */
+/* SLOF: USB-HUB-INIT ( dev -- true | false ) */
+/* LIBNEWUSB: usb_hub_init */
+/************************************************/
+PRIM(USB_X2d_HUB_X2d_INIT)
+ void *dev = TOS.a;
+ TOS.n = usb_hub_init(dev);
+MIRP
+
+/************************************************/
+/* Initialize msc */
+/* SLOF: USB-MSC-INIT ( dev -- true | false )*/
+/* LIBNEWUSB: usb_msc_init(hcidev) */
+/************************************************/
+PRIM(USB_X2d_MSC_X2d_INIT)
+ void *dev = TOS.a;
+ TOS.n = usb_msc_init(dev);
+MIRP
+
+/************************************************/
+/* Exit msc */
+/* SLOF: USB-MSC-EXIT ( dev -- true | false )*/
+/* LIBNEWUSB: usb_msc_exit(hcidev) */
+/************************************************/
+PRIM(USB_X2d_MSC_X2d_EXIT)
+ void *dev = TOS.a;
+ TOS.n = usb_msc_exit(dev);
+MIRP
+
+/*****************************************************************************/
+/* Transfer data through control endpoint */
+/* SLOF: USB-TRANSFER_CTRL ( dev req data -- true | false ) */
+/* LIBNEWUSB: int usb_transfer_ctrl(void *dev, void *req, void *data) */
+/*****************************************************************************/
+PRIM(USB_X2d_TRANSFER_X2d_CTRL)
+ void *data = TOS.a; POP;
+ void *req = TOS.a; POP;
+ TOS.n = usb_transfer_ctrl(TOS.a, req, data);
+MIRP
+
+/*****************************************************************************/
+/* Transfer data through bulk endpoint */
+/* SLOF: USB-TRANSFER_BULK ( dev dir td td-phys data size -- true | false ) */
+/* LIBNEWUSB: int usb_transfer_bulk(void *dev, int dir, void *td, */
+/* void *td_phys, void *data, int size) */
+/*****************************************************************************/
+PRIM(USB_X2d_TRANSFER_X2d_BULK)
+ int size = TOS.u; POP;
+ void *data = TOS.a; POP;
+ void *td_phys = TOS.a; POP;
+ void *td = TOS.a; POP;
+ int dir = TOS.u; POP;
+ TOS.n = usb_transfer_bulk(TOS.a, dir, td, td_phys, data, size);
+MIRP
diff --git a/src/roms/SLOF/lib/libusb/usb.h b/src/roms/SLOF/lib/libusb/usb.h
new file mode 100644
index 0000000..fba19d2
--- /dev/null
+++ b/src/roms/SLOF/lib/libusb/usb.h
@@ -0,0 +1,77 @@
+/******************************************************************************
+ * Copyright (c) 2006, 2012, 2013 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+/*
+ * prototypes for libusb implementation used in libusb.code
+ */
+
+#ifndef __LIBUSB_H
+#define __LIBUSB_H
+
+/*******************************************/
+/* SLOF: USB-OHCI-REGISTER */
+/*******************************************/
+extern void usb_ohci_register(void);
+/*******************************************/
+/* SLOF: USB-EHCI-REGISTER */
+/*******************************************/
+extern void usb_ehci_register(void);
+/*******************************************/
+/* SLOF: USB-XHCI-REGISTER */
+/*******************************************/
+extern void usb_xhci_register(void);
+/*******************************************/
+/* SLOF: USB-HCD-INIT */
+/*******************************************/
+extern void usb_hcd_init(void *hcidev);
+/*******************************************/
+/* SLOF: USB-HCD-EXIT */
+/*******************************************/
+extern void usb_hcd_exit(void *hcidev);
+/*******************************************/
+/* SLOF: USB-HID-INIT */
+/*******************************************/
+extern int usb_hid_init(void *dev);
+/*******************************************/
+/* SLOF: USB-HID-EXIT */
+/*******************************************/
+extern int usb_hid_exit(void *dev);
+/*******************************************/
+/* SLOF: USB-READ-KEYB */
+/*******************************************/
+extern unsigned char usb_read_keyb(void *dev);
+/*******************************************/
+/* SLOF: USB-KEY-AVAILABLE */
+/*******************************************/
+extern unsigned char usb_key_available(void *dev);
+/*******************************************/
+/* SLOF: USB-HUB-INIT */
+/*******************************************/
+extern unsigned int usb_hub_init(void *dev);
+/*******************************************/
+/* SLOF: USB-MSC-INIT */
+/*******************************************/
+extern int usb_msc_init(void *dev);
+/*******************************************/
+/* SLOF: USB-MSC-EXIT */
+/*******************************************/
+extern int usb_msc_exit(void *dev);
+/*******************************************/
+/* SLOF: USB-TRANSFER-CTRL */
+/*******************************************/
+extern int usb_transfer_ctrl(void *dev, void *req, void *data);
+/*******************************************/
+/* SLOF: USB-TRANSFER-BULK */
+/*******************************************/
+extern int usb_transfer_bulk(void *dev, int dir, void *td,
+ void *td_phys, void *data, int size);
+
+#endif
diff --git a/src/roms/SLOF/lib/libusb/usb.in b/src/roms/SLOF/lib/libusb/usb.in
new file mode 100644
index 0000000..7ceba7d
--- /dev/null
+++ b/src/roms/SLOF/lib/libusb/usb.in
@@ -0,0 +1,29 @@
+/******************************************************************************
+ * Copyright (c) 2007, 2012, 2013 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+/*
+ * libusb bindings for SLOF - definitions
+ */
+
+cod(USB-OHCI-REGISTER)
+cod(USB-EHCI-REGISTER)
+cod(USB-XHCI-REGISTER)
+cod(USB-HCD-INIT)
+cod(USB-HCD-EXIT)
+cod(USB-HID-INIT)
+cod(USB-HID-EXIT)
+cod(USB-READ-KEYB)
+cod(USB-KEY-AVAILABLE)
+cod(USB-HUB-INIT)
+cod(USB-MSC-INIT)
+cod(USB-MSC-EXIT)
+cod(USB-TRANSFER-CTRL)
+cod(USB-TRANSFER-BULK)
diff --git a/src/roms/SLOF/lib/libveth/Makefile b/src/roms/SLOF/lib/libveth/Makefile
new file mode 100644
index 0000000..dd1234a
--- /dev/null
+++ b/src/roms/SLOF/lib/libveth/Makefile
@@ -0,0 +1,52 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2008 IBM Corporation
+# * All rights reserved.
+# * This program and the accompanying materials
+# * are made available under the terms of the BSD License
+# * which accompanies this distribution, and is available at
+# * http://www.opensource.org/licenses/bsd-license.php
+# *
+# * Contributors:
+# * IBM Corporation - initial implementation
+# ****************************************************************************/
+
+TOPCMNDIR ?= ../..
+
+include $(TOPCMNDIR)/make.rules
+
+CPPFLAGS = -I../libc/include $(CPUARCHDEF) -I$(INCLBRDDIR) \
+ -I$(INCLCMNDIR) -I$(INCLCMNDIR)/$(CPUARCH)
+CPPFLAGS += -I../libhvcall
+
+LDFLAGS = -nostdlib
+
+TARGET = ../libveth.a
+
+
+all: $(TARGET)
+
+SRCS = veth.c
+
+OBJS = $(SRCS:%.c=%.o)
+
+$(TARGET): $(OBJS)
+ $(AR) -rc $@ $(OBJS)
+ $(RANLIB) $@
+
+clean:
+ $(RM) $(TARGET) $(OBJS)
+
+distclean: clean
+ $(RM) Makefile.dep
+
+
+# Rules for creating the dependency file:
+depend:
+ $(RM) Makefile.dep
+ $(MAKE) Makefile.dep
+
+Makefile.dep: Makefile
+ $(CC) -M $(CPPFLAGS) $(CFLAGS) $(SRCS) $(SRCSS) > Makefile.dep
+
+# Include dependency file if available:
+-include Makefile.dep
diff --git a/src/roms/SLOF/lib/libveth/veth.c b/src/roms/SLOF/lib/libveth/veth.c
new file mode 100644
index 0000000..7487308
--- /dev/null
+++ b/src/roms/SLOF/lib/libveth/veth.c
@@ -0,0 +1,273 @@
+/******************************************************************************
+ * Copyright (c) 2011, 2013 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <helpers.h>
+#include "veth.h"
+#include "libhvcall.h"
+
+#undef VETH_DEBUG
+//#define VETH_DEBUG
+#ifdef VETH_DEBUG
+#define dprintf(_x ...) do { printf(_x); } while(0)
+#else
+#define dprintf(_x ...)
+#endif
+
+/* *** WARNING: We pass our addresses as-is as DMA addresses,
+ * we -do- rely on the forth code to have enabled TCE bypass
+ * on our device !
+ */
+#define vaddr_to_dma(vaddr) ((uint64_t)vaddr)
+
+struct ibmveth_buf_desc_fields {
+ uint32_t flags_len;
+#define IBMVETH_BUF_VALID 0x80000000
+#define IBMVETH_BUF_TOGGLE 0x40000000
+#define IBMVETH_BUF_NO_CSUM 0x02000000
+#define IBMVETH_BUF_CSUM_GOOD 0x01000000
+#define IBMVETH_BUF_LEN_MASK 0x00FFFFFF
+ uint32_t address;
+};
+
+union ibmveth_buf_desc {
+ uint64_t desc;
+ struct ibmveth_buf_desc_fields fields;
+};
+
+struct ibmveth_rx_q_entry {
+ uint32_t flags_off;
+#define IBMVETH_RXQ_TOGGLE 0x80000000
+#define IBMVETH_RXQ_TOGGLE_SHIFT 31
+#define IBMVETH_RXQ_VALID 0x40000000
+#define IBMVETH_RXQ_NO_CSUM 0x02000000
+#define IBMVETH_RXQ_CSUM_GOOD 0x01000000
+#define IBMVETH_RXQ_OFF_MASK 0x0000FFFF
+
+ uint32_t length;
+ uint64_t correlator;
+};
+
+static void *buffer_list;
+static void *filter_list;
+static uint64_t *rx_bufs;
+static uint64_t *rx_bufs_aligned;
+static uint32_t cur_rx_toggle;
+static uint32_t cur_rx_index;
+
+#define RX_QUEUE_SIZE 256
+#define RX_BUF_SIZE 2048
+#define RX_BUF_MULT (RX_BUF_SIZE >> 3)
+
+static struct ibmveth_rx_q_entry *rx_queue;
+
+static inline uint64_t *veth_get_rx_buf(unsigned int i)
+{
+ return &rx_bufs_aligned[i * RX_BUF_MULT];
+}
+
+static int veth_init(net_driver_t *driver)
+{
+ char *mac_addr;
+ union ibmveth_buf_desc rxq_desc;
+ unsigned long rx_queue_len = sizeof(struct ibmveth_rx_q_entry) *
+ RX_QUEUE_SIZE;
+ unsigned int i;
+ long rc;
+
+ if (!driver)
+ return -1;
+
+ dprintf("veth_init(%02x:%02x:%02x:%02x:%02x:%02x)\n",
+ mac_addr[0], mac_addr[1], mac_addr[2],
+ mac_addr[3], mac_addr[4], mac_addr[5]);
+
+ if (driver->running != 0)
+ return 0;
+
+ mac_addr = (char *)driver->mac_addr;
+ cur_rx_toggle = IBMVETH_RXQ_TOGGLE;
+ cur_rx_index = 0;
+ buffer_list = SLOF_alloc_mem_aligned(8192, 4096);
+ filter_list = buffer_list + 4096;
+ rx_queue = SLOF_alloc_mem_aligned(rx_queue_len, 16);
+ rx_bufs = SLOF_alloc_mem(2048 * RX_QUEUE_SIZE + 4);
+ if (!buffer_list || !filter_list || !rx_queue || !rx_bufs) {
+ printf("veth: Failed to allocate memory !\n");
+ goto fail;
+ }
+ rx_bufs_aligned = (uint64_t *)(((uint64_t)rx_bufs | 3) + 1);
+ rxq_desc.fields.address = vaddr_to_dma(rx_queue);
+ rxq_desc.fields.flags_len = IBMVETH_BUF_VALID | rx_queue_len;
+
+ rc = h_register_logical_lan(driver->reg,
+ vaddr_to_dma(buffer_list),
+ rxq_desc.desc,
+ vaddr_to_dma(filter_list),
+ (*(uint64_t *)mac_addr) >> 16);
+ if (rc != H_SUCCESS) {
+ printf("veth: Error %ld registering interface !\n", rc);
+ goto fail;
+ }
+ for (i = 0; i < RX_QUEUE_SIZE; i++) {
+ uint64_t *buf = veth_get_rx_buf(i);
+ union ibmveth_buf_desc desc;
+ *buf = (uint64_t)buf;
+ desc.fields.address = vaddr_to_dma(buf);
+ desc.fields.flags_len = IBMVETH_BUF_VALID | RX_BUF_SIZE;
+ h_add_logical_lan_buffer(driver->reg, desc.desc);
+ }
+
+ driver->running = 1;
+
+ return 0;
+ fail:
+ if (buffer_list)
+ SLOF_free_mem(buffer_list, 8192);
+ if (rx_queue)
+ SLOF_free_mem(rx_queue, rx_queue_len);
+ if (rx_bufs)
+ SLOF_free_mem(rx_bufs, 2048 * RX_QUEUE_SIZE + 4);
+ return -1;
+}
+
+static int veth_term(net_driver_t *driver)
+{
+ dprintf("veth_term()\n");
+
+ if (driver->running == 0)
+ return 0;
+
+ h_free_logical_lan(driver->reg);
+
+ if (buffer_list)
+ SLOF_free_mem(buffer_list, 8192);
+ if (rx_queue)
+ SLOF_free_mem(rx_queue, sizeof(struct ibmveth_rx_q_entry) * RX_QUEUE_SIZE);
+ if (rx_bufs)
+ SLOF_free_mem(rx_bufs, 2048 * RX_QUEUE_SIZE + 4);
+
+ driver->running = 0;
+
+ return 0;
+}
+
+static int veth_receive(char *f_buffer_pc, int f_len_i, net_driver_t *driver)
+{
+ int packet = 0;
+
+ dprintf("veth_receive()\n");
+
+ while(!packet) {
+ struct ibmveth_rx_q_entry *desc = &rx_queue[cur_rx_index];
+ union ibmveth_buf_desc bdesc;
+ void *buf;
+
+ buf = (void *)desc->correlator;
+
+ if ((desc->flags_off & IBMVETH_RXQ_TOGGLE) != cur_rx_toggle)
+ break;
+
+ if (!(desc->flags_off & IBMVETH_RXQ_VALID))
+ goto recycle;
+ if (desc->length > f_len_i) {
+ printf("veth: Dropping too big packet [%d bytes]\n",
+ desc->length);
+ goto recycle;
+ }
+
+ packet = desc->length;
+ memcpy(f_buffer_pc,
+ buf + (desc->flags_off & IBMVETH_RXQ_OFF_MASK), packet);
+ recycle:
+ bdesc.fields.address = vaddr_to_dma(buf);
+ bdesc.fields.flags_len = IBMVETH_BUF_VALID | RX_BUF_SIZE;
+ h_add_logical_lan_buffer(driver->reg, bdesc.desc);
+
+ cur_rx_index = (cur_rx_index + 1) % RX_QUEUE_SIZE;
+ if (cur_rx_index == 0)
+ cur_rx_toggle ^= IBMVETH_RXQ_TOGGLE;
+ }
+
+ return packet;
+}
+
+static int veth_xmit(char *f_buffer_pc, int f_len_i, net_driver_t *driver)
+{
+ union ibmveth_buf_desc tx_desc;
+ long rc;
+
+ dprintf("veth_xmit(packet at %p, %d bytes)\n", f_buffer_pc, f_len_i);
+
+ tx_desc.fields.address = vaddr_to_dma(f_buffer_pc);
+ tx_desc.fields.flags_len = IBMVETH_BUF_VALID | f_len_i;
+
+ rc = hv_send_logical_lan(driver->reg, tx_desc.desc, 0, 0, 0, 0, 0);
+ if (rc != H_SUCCESS) {
+ printf("veth: Error %ld sending packet !\n", rc);
+ return -1;
+ }
+
+ return f_len_i;
+}
+
+net_driver_t *libveth_open(char *mac_addr, int mac_len, char *reg, int reg_len)
+{
+ net_driver_t *driver;
+
+ driver = SLOF_alloc_mem(sizeof(*driver));
+ if (!driver) {
+ printf("Unable to allocate veth driver\n");
+ return NULL;
+ }
+
+ /* veth uses a 8-byte wide property instead of 6-byte wide MACs */
+ if ((mac_len == 8) && (mac_addr[0] == 0) && mac_addr[1] == 0)
+ mac_addr += 2;
+ memcpy(driver->mac_addr, mac_addr, 6);
+ driver->reg = *(uint32_t *)reg;
+ driver->running = 0;
+
+ if (veth_init(driver)) {
+ SLOF_free_mem(driver, sizeof(*driver));
+ return NULL;
+ }
+
+ return driver;
+}
+
+void libveth_close(net_driver_t *driver)
+{
+ if (driver) {
+ veth_term(driver);
+ SLOF_free_mem(driver, sizeof(*driver));
+ }
+}
+
+int libveth_read(char *buf, int len, net_driver_t *driver)
+{
+ if (buf)
+ return veth_receive(buf, len, driver);
+
+ return -1;
+}
+
+int libveth_write(char *buf, int len, net_driver_t *driver)
+{
+ if (buf)
+ return veth_xmit(buf, len, driver);
+
+ return -1;
+}
diff --git a/src/roms/SLOF/lib/libveth/veth.code b/src/roms/SLOF/lib/libveth/veth.code
new file mode 100644
index 0000000..76d14a9
--- /dev/null
+++ b/src/roms/SLOF/lib/libveth/veth.code
@@ -0,0 +1,61 @@
+/******************************************************************************
+ * Copyright (c) 2013 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+/*
+ * libveth Forth wrapper
+ */
+
+#include <veth.h>
+
+// : libveth-open ( mac-addr-str len reg-str len -- false | [ driver true ] )
+PRIM(LIBVETH_X2d_OPEN)
+{
+ int reg_len = TOS.u; POP;
+ char *reg = TOS.a; POP;
+ int len = TOS.u; POP;
+ char *mac_addr = TOS.a;
+
+ net_driver_t *net_driver = libveth_open(mac_addr, len, reg, reg_len);
+ if (net_driver) {
+ TOS.u = (unsigned long)net_driver; PUSH;
+ TOS.n = -1;
+ } else
+ TOS.n = 0;
+}
+MIRP
+
+// : libveth-close ( driver -- )
+PRIM(LIBVETH_X2d_CLOSE)
+{
+ net_driver_t *driver = TOS.a; POP;
+ libveth_close(driver);
+}
+MIRP
+
+
+// : libveth-read ( addr len driver -- actual )
+PRIM(LIBVETH_X2d_READ)
+{
+ net_driver_t *driver = TOS.a; POP;
+ int len = TOS.u; POP;
+ TOS.n = libveth_read(TOS.a, len, driver);
+}
+MIRP
+
+// : libveth-write ( addr len driver -- actual )
+PRIM(LIBVETH_X2d_WRITE)
+{
+ net_driver_t *driver = TOS.a; POP;
+ int len = TOS.u; POP;
+ TOS.n = libveth_write(TOS.a, len, driver);
+}
+MIRP
diff --git a/src/roms/SLOF/lib/libveth/veth.h b/src/roms/SLOF/lib/libveth/veth.h
new file mode 100644
index 0000000..23af0ea
--- /dev/null
+++ b/src/roms/SLOF/lib/libveth/veth.h
@@ -0,0 +1,24 @@
+/******************************************************************************
+ * Copyright (c) 2013 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ ******************************************************************************/
+
+#ifndef _VETH_H
+#define _VETH_H
+
+#include <stdint.h>
+#include <netdriver.h>
+
+extern net_driver_t *libveth_open(char *mac_addr, int mac_len, char *reg, int reg_len);
+extern void libveth_close(net_driver_t *driver);
+extern int libveth_read(char *buf, int len, net_driver_t *driver);
+extern int libveth_write(char *buf, int len, net_driver_t *driver);
+
+#endif
diff --git a/src/roms/SLOF/lib/libveth/veth.in b/src/roms/SLOF/lib/libveth/veth.in
new file mode 100644
index 0000000..dc684fe
--- /dev/null
+++ b/src/roms/SLOF/lib/libveth/veth.in
@@ -0,0 +1,20 @@
+/******************************************************************************
+ * Copyright (c) 2013 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+/*
+ * libveth bindings for Forth - definitions
+ */
+
+cod(LIBVETH-OPEN)
+cod(LIBVETH-CLOSE)
+cod(LIBVETH-READ)
+cod(LIBVETH-WRITE)
diff --git a/src/roms/SLOF/lib/libvirtio/Makefile b/src/roms/SLOF/lib/libvirtio/Makefile
new file mode 100644
index 0000000..bd6a1fa
--- /dev/null
+++ b/src/roms/SLOF/lib/libvirtio/Makefile
@@ -0,0 +1,55 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2008 IBM Corporation
+# * All rights reserved.
+# * This program and the accompanying materials
+# * are made available under the terms of the BSD License
+# * which accompanies this distribution, and is available at
+# * http://www.opensource.org/licenses/bsd-license.php
+# *
+# * Contributors:
+# * IBM Corporation - initial implementation
+# ****************************************************************************/
+
+TOPCMNDIR ?= ../..
+
+include $(TOPCMNDIR)/make.rules
+
+ASFLAGS = $(FLAG) $(RELEASE) $(CPUARCHDEF) -Wa,-mregnames
+CPPFLAGS = -I../libc/include $(CPUARCHDEF) -I$(INCLBRDDIR) \
+ -I$(INCLCMNDIR) -I$(INCLCMNDIR)/$(CPUARCH)
+LDFLAGS = -nostdlib
+
+TARGET = ../libvirtio.a
+
+
+all: $(TARGET)
+
+SRCS = virtio.c virtio-blk.c p9.c virtio-9p.c virtio-scsi.c virtio-net.c
+
+OBJS = $(SRCS:%.c=%.o)
+
+$(TARGET): $(OBJS)
+ $(AR) -rc $@ $(OBJS)
+ $(RANLIB) $@
+
+%.o: %.S
+ $(CC) $(CPPFLAGS) $(ASFLAGS) -c $< -o $@
+
+clean:
+ $(RM) $(TARGET) $(OBJS)
+
+distclean: clean
+ $(RM) Makefile.dep
+
+
+# Rules for creating the dependency file:
+depend:
+ $(RM) Makefile.dep
+ $(MAKE) Makefile.dep
+
+Makefile.dep: Makefile
+ $(CC) -M $(CPPFLAGS) $(CFLAGS) $(SRCS) $(SRCSS) > Makefile.dep
+
+# Include dependency file if available:
+-include Makefile.dep
+
diff --git a/src/roms/SLOF/lib/libvirtio/p9.c b/src/roms/SLOF/lib/libvirtio/p9.c
new file mode 100644
index 0000000..a556629
--- /dev/null
+++ b/src/roms/SLOF/lib/libvirtio/p9.c
@@ -0,0 +1,575 @@
+/******************************************************************************
+ * Copyright (c) 2011 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <byteorder.h>
+#include "p9.h"
+
+
+/* Protocol stack marshaling. */
+uint8_t *sp;
+
+#define GET_08(s,i) (s)[(i)]
+#define GET_16(s,i) le16_to_cpu(*(uint16_t*)(&(s)[(i)]))
+#define GET_32(s,i) le32_to_cpu(*(uint32_t*)(&(s)[(i)]))
+#define GET_64(s,i) le64_to_cpu(*(uint64_t*)(&(s)[(i)]))
+
+#define SET_08(s,i,v) (s)[(i)] = (v)
+#define SET_16(s,i,v) *(uint16_t*)(&(s)[(i)]) = cpu_to_le16(v)
+#define SET_32(s,i,v) *(uint32_t*)(&(s)[(i)]) = cpu_to_le32(v)
+#define SET_64(s,i,v) *(uint64_t*)(&(s)[(i)]) = cpu_to_le64(v)
+
+#define PUT_08(v) sp[0] = (v);sp+=1
+#define PUT_16(v) *(uint16_t*)(&sp[0]) = cpu_to_le16(v);sp+=2
+#define PUT_32(v) *(uint32_t*)(&sp[0]) = cpu_to_le32(v);sp+=4
+#define PUT_64(v) *(uint64_t*)(&sp[0]) = cpu_to_le64(v);sp+=8
+
+#define PUT_HD(m,t) PUT_32(0);PUT_08(m);PUT_16(t)
+#define PUT_SN(v,n) PUT_16(n);memcpy(sp,(v),(n));sp+=n
+#define PUT_ST(v) PUT_16(strlen(v));memcpy(sp,(v),strlen(v));\
+ sp+=strlen(v)
+
+#define GET_SIZE (sp - tx)
+
+
+/* General defines. */
+#define MIN(a,b) ((a)>(b)?(b):(a))
+
+#define NOTAG ((uint16_t)~0)
+#define NOFID ((uint32_t)~0)
+#define TAG 1
+#define BUF_SIZE (8*1024)
+
+#define VERSION "9P2000.u"
+#define UNKNOWN_VER "unknown"
+
+#define MSG_SIZE 0
+#define MSG_ID 4
+#define MSG_ERR 0x6b
+#define MSG_ERR_STR 9
+#define MSG_ERR_STR_LEN 7
+#define MSG_TAG 5
+#define MSG_VER_MSIZE 7
+#define MSG_VER_STR_LEN 11
+#define MSG_VER_STR 13
+#define MSG_WALK_TX_ELMT 15
+#define MSG_WALK_RX_ELMT 7
+#define MSG_SIZE 0
+#define MSG_WALK_MAX_ELMT 16
+#define MSG_QID_SIZE 13
+#define MSG_WALK_RX_HDR_SIZE 9
+#define MSG_OPEN_IOUNIT 20
+#define MSG_OPEN_MODE_MASK 0x5f
+#define MSG_READ_COUNT 7
+#define MSG_READ_DATA 11
+#define MSG_STAT_LEN 42
+#define MSG_STAT_TYPE 17
+
+#define T_VERSION 100
+#define R_VERSION (T_VERSION + 1)
+#define T_ATTACH 104
+#define R_ATTACH (T_ATTACH + 1)
+#define T_ERROR 106
+#define R_ERROR (T_ERROR + 1)
+#define T_WALK 110
+#define R_WALK (T_WALK + 1)
+#define T_OPEN 112
+#define R_OPEN (T_OPEN + 1)
+#define T_READ 116
+#define R_READ (T_READ + 1)
+#define T_CLUNK 120
+#define R_CLUNK (T_CLUNK + 1)
+#define T_STAT 124
+#define R_STAT (T_STAT + 1)
+
+static p9_transact_t transact;
+static void *transact_opaque;
+static uint8_t *tx;
+static uint8_t *rx;
+
+
+/**
+ * p9_reg_transport
+ *
+ * Registers a transport function for use by the P9 protocol. The transport
+ * connects the P9 Client (this library) to a server instance.
+ *
+ * @param transact_func[in] Function pointer to type p9_transact_t.
+ * @param tx_buffer[in] TX buffer, must be 8k in size.
+ * @param rx_buffer[in] RX buffer, must be 8k in size.
+ */
+void p9_reg_transport(p9_transact_t transact_func, void *opaque,
+ uint8_t *tx_buffer, uint8_t *rx_buffer)
+{
+ transact = transact_func;
+ transact_opaque = opaque;
+ tx = tx_buffer;
+ rx = rx_buffer;
+}
+
+/**
+ * reset_buffers
+ *
+ * Reset the RX and TX buffers to BUF_SIZE (8k) and reset the Stack Pointer
+ * for the TX buffer, which is referenced by the PUT_* macro's.
+ */
+void reset_buffers(void)
+{
+ memset(tx, 0, BUF_SIZE);
+ memset(rx, 0, BUF_SIZE);
+ sp = tx;
+}
+
+/**
+ * p9_transaction
+ *
+ * Perform a transaction (send/recv) over the registered transport.
+ *
+ * @param connection[in|out] Connection object.
+ * @return 0 = success, -ve = error.
+ */
+int p9_transaction(p9_connection_t *connection)
+{
+ int rc;
+ int tx_size = GET_SIZE;
+ int rx_size = connection->message_size;
+
+ if (transact == NULL) {
+ return P9_NO_TRANSPORT;
+ }
+ if (tx == NULL || rx == NULL) {
+ return P9_NO_BUFFER;
+ }
+ if (connection->message_size > BUF_SIZE) {
+ return P9_MSG_SIZE_TOO_BIG;
+ }
+ if (tx_size > connection->message_size) {
+ return P9_MSG_TOO_LONG;
+ }
+
+ SET_32(tx, MSG_SIZE, tx_size);
+ rc = transact(transact_opaque, tx, tx_size, rx, &rx_size);
+
+ if (rc != 0) {
+ return P9_TRANSPORT_ERROR;
+ }
+ if (GET_16(tx, MSG_TAG) != GET_16(rx, MSG_TAG)) {
+ return P9_UNEXPECTED_TAG;
+ }
+ if (GET_08(rx, MSG_ID) == MSG_ERR) {
+ char error_string[200];
+
+ memset(error_string, 0, 200);
+ strncpy(error_string, (char *)&rx[MSG_ERR_STR],
+ MIN(200 - 1, GET_16(rx, MSG_ERR_STR_LEN)));
+#ifndef TEST
+ printf("\nError: %s\n", error_string);
+#endif
+ return P9_R_ERROR;
+ }
+ if ((GET_08(tx, MSG_ID) + 1) != GET_08(rx, MSG_ID)) {
+ return P9_UNEXPECTED_MSG;
+ }
+
+ return 0;
+}
+
+/**
+ * p9_version
+ *
+ * Called to start a session. Negotiates the maximum message size for the
+ * P9 protocol.
+ *
+ * @param connection[in|out] Connection object, contains message_size.
+ * @return 0 = success, -ve = error.
+ *
+ * @remark
+ * size[4] Tversion tag[2] msize[4] version[s]
+ * size[4] Rversion tag[2] msize[4] version[s]
+ */
+int p9_version(p9_connection_t *connection)
+{
+ int rc;
+ char *ver_str;
+ int ver_len;
+
+ reset_buffers();
+
+ /* Build message. */
+ PUT_HD(T_VERSION, NOTAG);
+ PUT_32(connection->message_size);
+ PUT_ST(VERSION);
+
+ /* Send message. */
+ rc = p9_transaction(connection);
+ if (rc != 0) {
+ return rc;
+ }
+
+ /* Handle response. */
+ connection->message_size = MIN(connection->message_size,
+ GET_32(rx, MSG_VER_MSIZE));
+
+ ver_str = (char *)&rx[MSG_VER_STR];
+ ver_len = GET_16(rx, MSG_VER_STR_LEN);
+ if (strncmp(UNKNOWN_VER, ver_str, ver_len) == 0) {
+ return P9_UNKNOWN_VERSION;
+ }
+
+
+ return 0;
+}
+
+/**
+ * p9_attach
+ *
+ * Called to open a connection for a user to a file tree on the server. There
+ * is no authorisation undertaken (NOFID).
+ *
+ * @param connection[in|out] Connection object, contains uname and aname as
+ * well as the connection fid and returned qid.
+ * @return 0 = success, -ve = error.
+ *
+ * @remark
+ * size[4] Tattach tag[2] fid[4] afid[4] uname[s] aname[s] n_uname[4]
+ * size[4] Rattach tag[2] qid[13]
+ */
+int p9_attach(p9_connection_t *connection)
+{
+ int rc;
+ int length = 19 + strlen(connection->uname) + strlen(connection->aname);
+
+ if (length > connection->message_size) {
+ return P9_MSG_TOO_LONG;
+ }
+
+ reset_buffers();
+
+ /* Build message. */
+ PUT_HD(T_ATTACH, TAG);
+ PUT_32(connection->fid);
+ PUT_32(NOFID);
+ PUT_ST(connection->uname);
+ PUT_ST(connection->aname);
+ PUT_32(~0); /* ??? */
+
+ /* Send message. */
+ rc = p9_transaction(connection);
+ if (rc != 0) {
+ return rc;
+ }
+
+
+ return 0;
+}
+
+/**
+ * p9_clunk
+ *
+ * Called when closing a file or connection (or after failed opens). Tells the
+ * server that the supplied fid is no longer needed by this client.
+ *
+ * @param connection[in|out] Connection object.
+ * @param fid[in] Fid to be clunked (released) on the server.
+ * @return 0 = success, -ve = error.
+ *
+ * @remark
+ * size[4] Tclunk tag[2] fid[4]
+ * size[4] Rclunk tag[2]
+ */
+int p9_clunk(p9_connection_t *connection, uint32_t fid)
+{
+ int rc;
+
+ reset_buffers();
+
+ /* Build message. */
+ PUT_HD(T_CLUNK, TAG);
+ PUT_32(fid);
+
+ /* Send message. */
+ rc = p9_transaction(connection);
+ if (rc != 0) {
+ return rc;
+ }
+
+
+ return 0;
+}
+
+/**
+ * p9_walk
+ *
+ * Walk the provided path to a file (or directory) starting at the directory
+ * indicated by fid and assigning new_fid to the last successfully walked
+ * element. If not all elements of the path can be walked then the pos
+ * pointer is set to the part of the path following the last successful
+ * walked element. The function can be called again to walk the remainder
+ * of the path (or produce an error).
+ *
+ * @param connection[in] Connection object.
+ * @param fid[in] Fid to start walk from, must be directory or root (from
+ * call to p9_attach).
+ * @param new_fid[in] Fid to be used for the last walked element.
+ * @param pos[in|out] Position in path that remains to be walked. If the
+ * path was completely walked without error this will point to the NULL
+ * at the end of path.
+ * @return 1 = partial walk, 0 = success, -ve = error.
+ *
+ * @remark
+ * size[4] Twalk tag[2] fid[4] newfid[4] nwname[2] nwname*(wname[s])
+ * size[4] Rwalk tag[2] nwqid[2] nwqid*(qid[13])
+ */
+int p9_walk(p9_connection_t *connection, uint32_t fid, uint32_t new_fid,
+ uint8_t **pos)
+{
+ int rc;
+ const char *path = (const char *)*pos;
+ uint8_t *s_tok;
+ uint8_t *e_tok;
+ int element_count = 0;
+
+ if (path == NULL) {
+ *pos = NULL;
+ return P9_NULL_PATH;
+ }
+
+ reset_buffers();
+
+ /* Build message. */
+ PUT_HD(T_WALK, TAG); /* Length to 0, set later. */
+ PUT_32(fid);
+ PUT_32(new_fid);
+ PUT_16(0); /* Element count to 0, set later. */
+
+ /* Get elements from path, and append to message. */
+ s_tok = (uint8_t *)path;
+ e_tok = s_tok;
+
+ while (*s_tok != 0) {
+ while (*s_tok == '/') {
+ s_tok++;
+ }
+ e_tok = s_tok;
+ while ((*e_tok != '/') && (*e_tok != 0)) {
+ e_tok++;
+ }
+
+ /* Check the element is OK. */
+ if (strncmp(".", (const char *)s_tok, (e_tok - s_tok)) == 0) {
+ /* Don't send ".", continue to next. */
+ s_tok = e_tok;
+ continue;
+ }
+ int tx_size = (e_tok - s_tok + 2 + GET_SIZE);
+ int rx_size = ((element_count + 1) * MSG_QID_SIZE
+ + MSG_WALK_RX_HDR_SIZE);
+ if ((tx_size > connection->message_size)
+ || (rx_size > connection->message_size)) {
+ /*
+ * Element makes TX msg too long OR expected RX msg
+ * too long. Move pos to previous element and do
+ * partial walk.
+ */
+ e_tok = s_tok;
+ if (*(e_tok - 1) == '/') {
+ e_tok--;
+ }
+ break;
+ }
+
+ /* Add the element to the message. */
+ PUT_SN(s_tok, e_tok - s_tok);
+ element_count++;
+
+ /* Server supports no more than 16 elements, partial walk. */
+ if (element_count == MSG_WALK_MAX_ELMT) {
+ break;
+ }
+
+ /* Ready to find the next element. */
+ s_tok = e_tok;
+ }
+
+ if ((element_count == 0) && (strlen(path) > 0)) {
+ return P9_PATH_ELEMENT_TOO_LONG;
+ }
+
+ *pos = e_tok;
+
+ /* Update counts and then send message. */
+ SET_16(tx, MSG_WALK_TX_ELMT, element_count);
+ rc = p9_transaction(connection);
+ if (rc != 0) {
+ return rc;
+ }
+
+ /* Check for special return conditions. */
+ if (element_count != GET_16(rx, MSG_WALK_RX_ELMT)) {
+ /* Find the last element successfully walked */
+ s_tok = (uint8_t *)path;
+ e_tok = s_tok;
+ element_count = GET_16(rx, MSG_WALK_RX_ELMT);
+
+ while (element_count--) {
+ while (*s_tok == '/') {
+ s_tok++;
+ }
+
+ e_tok = s_tok;
+
+ while ((*e_tok != '/') && (*e_tok != 0)) {
+ e_tok++;
+ }
+
+ s_tok = e_tok;
+ }
+
+ *pos = e_tok;
+ }
+ if (**pos != 0) {
+ rc = P9_PARTIAL_WALK;
+ }
+
+
+ return rc;
+}
+
+/**
+ * p9_open
+ *
+ * Opens the file represented by fid with associated mode bit mask. The iounit
+ * size returned from the server is written to the connection object.
+ *
+ * @param file[in|out] File object, contains fid for file.
+ * @param mode[in] Mode to open with. Bit's 0=R, 1=W, 2=RW, 3=EX, 4=Trunc
+ * and 6=Delete on Close.
+ * @return 0 = success, -ve = error.
+ *
+ * @remark
+ * size[4] Topen tag[2] fid[4] mode[1]
+ * size[4] Ropen tag[2] qid[13] iounit[4]
+ */
+int p9_open(p9_file_t *file, uint8_t mode)
+{
+ int rc;
+ p9_connection_t *connection = file->connection;
+
+ reset_buffers();
+ file->iounit = 0;
+
+ /* Build message. */
+ PUT_HD(T_OPEN, TAG);
+ PUT_32(file->fid);
+ PUT_08(mode & MSG_OPEN_MODE_MASK);
+
+ /* Send message. */
+ rc = p9_transaction(connection);
+ if (rc != 0) {
+ return rc;
+ }
+
+ /* Handle response. */
+ file->iounit = GET_32(rx, MSG_OPEN_IOUNIT);
+
+
+ return 0;
+}
+
+/**
+ * p9_read
+ *
+ * Reads the file in to buffer.
+ *
+ * @param file[in] File object, contains fid for file.
+ * @param buffer[out] Buffer for data.
+ * @param count[in] Number of bytes to read (less bytes than requested
+ * may be read).
+ * @param offset[in] Offset in file to read from.
+ * @return Bytes read, -ve = error.
+ *
+ * @remark
+ * size[4] Tread tag[2] fid[4] offset[8] count[4]
+ * size[4] Rread tag[2] count[4] data[count]
+ */
+int p9_read(p9_file_t *file, uint8_t *buffer,
+ uint32_t count, uint64_t offset)
+{
+ int rc;
+ p9_connection_t *connection = file->connection;
+ uint32_t got;
+
+ reset_buffers();
+ count = MIN((connection->message_size - MSG_READ_DATA), count);
+
+ /* Build message. */
+ PUT_HD(T_READ, TAG);
+ PUT_32(file->fid);
+ PUT_64(offset);
+ PUT_32(count);
+
+ /* Send message. */
+ rc = p9_transaction(connection);
+ if (rc != 0) {
+ return rc;
+ }
+ got = GET_32(rx, MSG_READ_COUNT);
+ if (got > count) {
+ return P9_READ_UNEXPECTED_DATA;
+ }
+
+ /* Handle response. */
+ memcpy(buffer, &rx[MSG_READ_DATA], got);
+
+ return got;
+}
+
+/**
+ * p9_stat
+ *
+ * Stat's the fid and writes the type and length to the file object.
+ *
+ * @param file[in|out] File object, contains fid for file.
+ * @return 0 = success, -ve = error.
+ *
+ * @remark
+ * size[4] Tstat tag[2] fid[4]
+ * size[4] Rstat tag[2] size[2] stat[n]
+ */
+int p9_stat(p9_file_t *file)
+{
+ int rc;
+ p9_connection_t *connection = file->connection;
+
+ reset_buffers();
+ file->length = 0;
+ file->type = 0;
+
+ /* Build message. */
+ PUT_HD(T_STAT, TAG);
+ PUT_32(file->fid);
+
+ /* Send message. */
+ rc = p9_transaction(connection);
+ if (rc != 0) {
+ return rc;
+ }
+
+ /* Handle response. */
+ file->length = GET_64(rx, MSG_STAT_LEN);
+ file->type = GET_08(rx, MSG_STAT_TYPE);
+
+
+ return 0;
+}
diff --git a/src/roms/SLOF/lib/libvirtio/p9.h b/src/roms/SLOF/lib/libvirtio/p9.h
new file mode 100644
index 0000000..7df9ef4
--- /dev/null
+++ b/src/roms/SLOF/lib/libvirtio/p9.h
@@ -0,0 +1,68 @@
+/******************************************************************************
+ * Copyright (c) 2011 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#ifndef P9_H
+#define P9_H
+
+#include <stdint.h>
+
+
+#define P9_ERROR -1
+#define P9_UNKNOWN_VERSION -2
+#define P9_R_ERROR -3
+#define P9_MSG_TOO_LONG -4
+#define P9_UNEXPECTED_MSG -5
+#define P9_UNEXPECTED_TAG -6
+#define P9_TRANSPORT_ERROR -7
+#define P9_NO_TRANSPORT -8
+#define P9_NULL_PATH -9
+#define P9_PATH_ELEMENT_TOO_LONG -10
+#define P9_READ_UNEXPECTED_DATA -11
+#define P9_NO_BUFFER -12
+#define P9_MSG_SIZE_TOO_BIG -13
+
+#define P9_PARTIAL_WALK 1
+
+typedef int (*p9_transact_t)(void *opaque, uint8_t *tx, int tx_size,
+ uint8_t *rx, int *rx_size);
+
+typedef struct {
+ uint32_t message_size;
+ char *uname; /* User name. */
+ char *aname; /* Tree/mount name/path. */
+ uint32_t fid; /* Represents mount point. */
+} p9_connection_t;
+
+typedef struct {
+ uint32_t fid; /* Identifies the file to P9 server. */
+ uint32_t iounit; /* Maximum read size in bytes. */
+ uint8_t type; /* Type of file. */
+ uint64_t length; /* Length of file. */
+ p9_connection_t *connection;
+} p9_file_t;
+
+
+void reset_buffers(void);
+void p9_reg_transport(p9_transact_t transact_func, void *opaque,
+ uint8_t *tx_buffer, uint8_t *rx_buffer);
+int p9_transaction(p9_connection_t *connection);
+int p9_version(p9_connection_t *connection);
+int p9_attach(p9_connection_t *connection);
+int p9_clunk(p9_connection_t *connection, uint32_t fid);
+int p9_walk(p9_connection_t *connection, uint32_t fid, uint32_t new_fid,
+ uint8_t **pos);
+int p9_open(p9_file_t *file, uint8_t mode);
+int p9_read(p9_file_t *file, uint8_t *buffer,
+ uint32_t count, uint64_t offset);
+int p9_stat(p9_file_t *file);
+
+#endif
diff --git a/src/roms/SLOF/lib/libvirtio/virtio-9p.c b/src/roms/SLOF/lib/libvirtio/virtio-9p.c
new file mode 100644
index 0000000..5a5fd01
--- /dev/null
+++ b/src/roms/SLOF/lib/libvirtio/virtio-9p.c
@@ -0,0 +1,336 @@
+/******************************************************************************
+ * Copyright (c) 2011 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <byteorder.h>
+#include <cpu.h>
+
+#include "virtio-9p.h"
+#include "p9.h"
+
+
+/**
+ * Notes for 9P Server config:
+ *
+ * make distclean; cm make qemu
+ * sudo cp boot_rom.bin /opt/qemu/share/qemu/slof.bin
+ * /opt/qemu/bin/qemu-system-ppc64 -M pseries -m 512 -boot d -nographic -fsdev
+ * local,id=trule,path=/home/trule/virtfs,security_model=none -device
+ * virtio-9p-spapr,fsdev=trule,mount_tag=trule
+ * load virtfs:\some\file
+ */
+
+/* We support only one instance due to the (ab)use of globals. We
+ * use the buffer size as an open marker as well.
+ */
+static int __buf_size;
+
+
+#define ROOT_FID 1
+#define FILE_FID 2
+#define TAG_SIZE 128
+#define MIN(a,b) ((a)>(b)?(b):(a))
+
+
+#undef DEBUG
+//#define DEBUG
+#ifdef DEBUG
+#define dprintf(_x ...) do { printf(_x); } while(0)
+#else
+#define dprintf(_x ...)
+#endif
+
+#ifdef DEBUG
+static void dprint_buffer(const char *name, uint8_t *buffer, int length)
+{
+ int i;
+
+ printf("*** %s ***", name);
+
+ for (i = 0; i < length; i++) {
+ if (i % 16 == 0) {
+ printf("\n %04x:", i);
+ }
+
+ printf(" %02x", buffer[i]);
+ }
+
+ printf("\n");
+}
+#else
+#define dprint_buffer(n, b, l)
+#endif
+
+/**
+ * virtio_9p_transact
+ *
+ * Perform a 9P transaction over the VIRTIO queue interface. This function is
+ * registered with the p9.c library via p9_reg_transport() to provide
+ * connectivity to the 9P server.
+ *
+ * @param tx[in] Data to send, mapped to first queue item.
+ * @param tx_size[in] Size of data to send.
+ * @param rx[out] Data to receive, mappend to second queue item.
+ * @param rx_size[out] Size of data received.
+ * @return 0 = success, -ve = error.
+ */
+static int virtio_9p_transact(void *opaque, uint8_t *tx, int tx_size, uint8_t *rx,
+ int *rx_size)
+{
+ struct virtio_device *dev = opaque;
+ struct vring_desc *desc;
+ int id, i;
+ uint32_t vq_size;
+ struct vring_desc *vq_desc;
+ struct vring_avail *vq_avail;
+ struct vring_used *vq_used;
+ volatile uint16_t *current_used_idx;
+ uint16_t last_used_idx;
+
+
+ /* Virt IO queues. */
+ vq_size = virtio_get_qsize(dev, 0);
+ vq_desc = virtio_get_vring_desc(dev, 0);
+ vq_avail = virtio_get_vring_avail(dev, 0);
+ vq_used = virtio_get_vring_used(dev, 0);
+
+ last_used_idx = vq_used->idx;
+ current_used_idx = &vq_used->idx;
+
+ /* Determine descriptor index */
+ id = (vq_avail->idx * 3) % vq_size;
+
+ /* TX in first queue item. */
+ dprint_buffer("TX", tx, tx_size);
+
+ desc = &vq_desc[id];
+ desc->addr = (uint64_t)tx;
+ desc->len = tx_size;
+ desc->flags = VRING_DESC_F_NEXT;
+ desc->next = (id + 1) % vq_size;
+
+ /* RX in the second queue item. */
+ desc = &vq_desc[(id + 1) % vq_size];
+ desc->addr = (uint64_t)rx;
+ desc->len = *rx_size;
+ desc->flags = VRING_DESC_F_WRITE;
+ desc->next = 0;
+
+ /* Tell HV that the queue is ready */
+ vq_avail->ring[vq_avail->idx % vq_size] = id;
+ mb();
+ vq_avail->idx += 1;
+ virtio_queue_notify(dev, 0);
+
+ /* Receive the response. */
+ i = 10000000;
+ while (*current_used_idx == last_used_idx && i-- > 0) {
+ // do something better
+ mb();
+ }
+ if (i == 0) {
+ return -1;
+ }
+
+ *rx_size = MIN(*rx_size, le32_to_cpu(*(uint32_t*)(&rx[0])));
+ dprint_buffer("RX", rx, *rx_size);
+
+ return 0;
+}
+
+/**
+ * virtio_9p_init
+ *
+ * Establish the VIRTIO connection for use with the 9P server. Setup queues
+ * and negotiate capabilities. Setup the 9P (Client) library.
+ *
+ * @param reg[in] Pointer to device tree node for VIRTIO/9P interface.
+ * @param tx_buf[in] TX buffer for use by 9P Client lib - 8K in size.
+ * @param rx_buf[in] TX buffer for use by 9P Client lib - 8K in size.
+ * @param buf_size Somewhat redundant, buffer size expected to be 8k.
+ * @return 0 = success, -ve = error.
+ */
+int virtio_9p_init(struct virtio_device *dev, void *tx_buf, void *rx_buf,
+ int buf_size)
+{
+ struct vring_avail *vq_avail;
+
+ /* Check for double open */
+ if (__buf_size)
+ return -1;
+ __buf_size = buf_size;
+
+ dprintf("%s : device at %p\n", __func__, dev->base);
+ dprintf("%s : type is %04x\n", __func__, dev->type);
+
+ /* Reset device */
+ // XXX That will clear the virtq base. We need to move
+ // initializing it to here anyway
+ //
+ // virtio_reset_device(dev);
+
+ /* Acknowledge device. */
+ virtio_set_status(dev, VIRTIO_STAT_ACKNOWLEDGE);
+
+ /* Tell HV that we know how to drive the device. */
+ virtio_set_status(dev, VIRTIO_STAT_ACKNOWLEDGE | VIRTIO_STAT_DRIVER);
+
+ /* Device specific setup - we do not support special features */
+ virtio_set_guest_features(dev, 0);
+
+ vq_avail = virtio_get_vring_avail(dev, 0);
+ vq_avail->flags = VRING_AVAIL_F_NO_INTERRUPT;
+ vq_avail->idx = 0;
+
+ /* Tell HV that setup succeeded */
+ virtio_set_status(dev, VIRTIO_STAT_ACKNOWLEDGE | VIRTIO_STAT_DRIVER
+ |VIRTIO_STAT_DRIVER_OK);
+
+ /* Setup 9P library. */
+ p9_reg_transport(virtio_9p_transact, dev,(uint8_t *)tx_buf,
+ (uint8_t *)rx_buf);
+
+ dprintf("%s : complete\n", __func__);
+ return 0;
+}
+
+/**
+ * virtio_9p_shutdown
+ */
+void virtio_9p_shutdown(struct virtio_device *dev)
+{
+ /* Quiesce device */
+ virtio_set_status(dev, VIRTIO_STAT_FAILED);
+
+ /* Reset device */
+ virtio_reset_device(dev);
+
+ __buf_size = 0;
+}
+
+/**
+ * virtio_9p_load
+ *
+ * Read a file from the 9P Server on the VIRTIO interface.
+ *
+ * @param file_name[in] File to read, use Linux style paths.
+ * @param buffer[out] Where to read the file to.
+ * @return +ve = amount of data read, -ve = error.
+ */
+int virtio_9p_load(struct virtio_device *dev, const char *file_name, uint8_t *buffer)
+{
+ int rc;
+ uint16_t tag_len;
+ char tag_name[TAG_SIZE];
+ uint64_t offset = 0;
+ uint8_t *pos = (uint8_t *)file_name;
+ int start_fid = ROOT_FID;
+ p9_connection_t connection = {
+ .message_size = __buf_size,
+ .fid = ROOT_FID,
+ .uname = "slof"
+ };
+ p9_file_t file = {
+ .connection = &connection,
+ .fid = FILE_FID,
+ };
+
+
+ /* Get the share name from 9P config space. */
+ tag_len = virtio_get_config(dev, 0, sizeof(tag_len));
+ if (tag_len >= TAG_SIZE)
+ tag_len = TAG_SIZE - 1;
+ __virtio_read_config(dev, tag_name, 2, tag_len);
+ connection.aname = tag_name;
+
+ /* Connect to the 9P server. */
+ dprintf("%s : connecting, tag = %s, user = %s, msgsize = %d\n",
+ __func__, connection.aname, connection.uname,
+ connection.message_size);
+ rc = p9_version(&connection);
+ if (rc != 0) {
+ printf("Version check failed, rc = %d\n", rc);
+ goto cleanup_connection;
+ }
+ rc = p9_attach(&connection);
+ if (rc != 0) {
+ printf("Attach failed, rc = %d\n", rc);
+ goto cleanup_connection;
+ }
+ dprintf("%s : connected, msgsize = %d\n", __func__,
+ connection.message_size);
+
+ /* Walk to the file. */
+ do {
+ dprintf("%s : walk path %s\n", __func__, pos);
+ rc = p9_walk(&connection, start_fid, FILE_FID, &pos);
+
+ if (rc < 0) { /* Some error. */
+ printf("Walk failed, rc = %d\n", rc);
+ goto cleanup_connection;
+ }
+
+ /*
+ * If partial walk (*pos != 0) then continue the walk from
+ * mid point with start_fid updated to current position
+ * FILE_FID. FILE_FID will then be reused for the result of
+ * the next call to walk.
+ */
+ start_fid = FILE_FID;
+ } while (*pos != 0);
+
+ /* Open the file. */
+ dprintf("%s : stat and open\n", __func__);
+ rc = p9_stat(&file);
+ if (rc != 0) {
+ printf("Stat failed, rc = %d\n", rc);
+ goto cleanup_file;
+ }
+ rc = p9_open(&file, 0x00); /* TODO find include for "read mode" */
+ if (rc != 0) {
+ printf("Open failed, rc = %d\n", rc);
+ goto cleanup_file;
+ }
+ dprintf("%s : file opened, size %lld\n", __func__, file.length);
+
+ /* Read the file contents to buffer. */
+ while (offset < file.length) {
+ dprintf("%s : read from offset %llu\n", __func__, offset);
+ rc = p9_read(&file, buffer + offset,
+ file.length - offset, offset);
+ dprintf("%s : read done, length was %d\n", __func__, rc);
+ if (rc < 0) {
+ printf("Read failed, rc = %d\n", rc);
+ goto cleanup_file;
+ }
+ if (rc == 0) {
+ break;
+ }
+ offset += rc;
+ rc = 0;
+ }
+
+ /* Cleanup and disconnect. */
+cleanup_file:
+ dprintf("%s : clunking file\n", __func__);
+ p9_clunk(&connection, file.fid);
+
+cleanup_connection:
+ dprintf("%s : clunking connection\n", __func__);
+ p9_clunk(&connection, connection.fid);
+
+
+ dprintf("%s : complete, read %llu bytes\n", __func__, offset);
+ return rc == 0 ? offset : rc;
+}
diff --git a/src/roms/SLOF/lib/libvirtio/virtio-9p.h b/src/roms/SLOF/lib/libvirtio/virtio-9p.h
new file mode 100644
index 0000000..4bf47d0
--- /dev/null
+++ b/src/roms/SLOF/lib/libvirtio/virtio-9p.h
@@ -0,0 +1,32 @@
+/******************************************************************************
+ * Copyright (c) 2011 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#ifndef VIRTIO_9P_H_
+#define VIRTIO_9P_H_
+
+#include <stdint.h>
+
+#include "virtio.h"
+
+#if 0
+typedef struct {
+ uint16_t tag_lenth;
+ char tag[0];
+} virtio_9p_config_t;
+#endif
+int virtio_9p_init(struct virtio_device *dev, void *tx_buf, void *rx_buf,
+ int buf_size);
+void virtio_9p_shutdown(struct virtio_device *dev);
+int virtio_9p_load(struct virtio_device *dev, const char *file_name, uint8_t *buffer);
+
+
+#endif /* VIRTIO_9P_H_ */
diff --git a/src/roms/SLOF/lib/libvirtio/virtio-blk.c b/src/roms/SLOF/lib/libvirtio/virtio-blk.c
new file mode 100644
index 0000000..826f2ea
--- /dev/null
+++ b/src/roms/SLOF/lib/libvirtio/virtio-blk.c
@@ -0,0 +1,185 @@
+/******************************************************************************
+ * Copyright (c) 2011 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <stdio.h>
+#include <cpu.h>
+#include <helpers.h>
+#include "virtio.h"
+#include "virtio-blk.h"
+
+#define DEFAULT_SECTOR_SIZE 512
+
+/**
+ * Initialize virtio-block device.
+ * @param dev pointer to virtio device information
+ */
+int
+virtioblk_init(struct virtio_device *dev)
+{
+ struct vring_avail *vq_avail;
+ int blk_size = DEFAULT_SECTOR_SIZE;
+ int features;
+
+ /* Reset device */
+ // XXX That will clear the virtq base. We need to move
+ // initializing it to here anyway
+ //
+ // virtio_reset_device(dev);
+
+ /* Acknowledge device. */
+ virtio_set_status(dev, VIRTIO_STAT_ACKNOWLEDGE);
+
+ /* Tell HV that we know how to drive the device. */
+ virtio_set_status(dev, VIRTIO_STAT_ACKNOWLEDGE|VIRTIO_STAT_DRIVER);
+
+ /* Device specific setup - we support F_BLK_SIZE */
+ virtio_set_guest_features(dev, VIRTIO_BLK_F_BLK_SIZE);
+
+ vq_avail = virtio_get_vring_avail(dev, 0);
+ vq_avail->flags = VRING_AVAIL_F_NO_INTERRUPT;
+ vq_avail->idx = 0;
+
+ /* Tell HV that setup succeeded */
+ virtio_set_status(dev, VIRTIO_STAT_ACKNOWLEDGE|VIRTIO_STAT_DRIVER
+ |VIRTIO_STAT_DRIVER_OK);
+
+ virtio_get_host_features(dev, &features);
+ if (features & VIRTIO_BLK_F_BLK_SIZE) {
+ blk_size = virtio_get_config(dev,
+ offset_of(struct virtio_blk_cfg, blk_size),
+ sizeof(blk_size));
+ }
+
+ return blk_size;
+}
+
+
+/**
+ * Shutdown the virtio-block device.
+ * @param dev pointer to virtio device information
+ */
+void
+virtioblk_shutdown(struct virtio_device *dev)
+{
+ /* Quiesce device */
+ virtio_set_status(dev, VIRTIO_STAT_FAILED);
+
+ /* Reset device */
+ virtio_reset_device(dev);
+}
+
+
+/**
+ * Read blocks
+ * @param reg pointer to "reg" property
+ * @param buf pointer to destination buffer
+ * @param blocknum block number of the first block that should be read
+ * @param cnt amount of blocks that should be read
+ * @return number of blocks that have been read successfully
+ */
+int
+virtioblk_read(struct virtio_device *dev, char *buf, long blocknum, long cnt)
+{
+ struct vring_desc *desc;
+ int id;
+ static struct virtio_blk_req blkhdr;
+ //struct virtio_blk_config *blkconf;
+ uint64_t capacity;
+ uint32_t vq_size, time;
+ struct vring_desc *vq_desc; /* Descriptor vring */
+ struct vring_avail *vq_avail; /* "Available" vring */
+ struct vring_used *vq_used; /* "Used" vring */
+ volatile uint8_t status = -1;
+ volatile uint16_t *current_used_idx;
+ uint16_t last_used_idx;
+ int blk_size = DEFAULT_SECTOR_SIZE;
+
+ //printf("virtioblk_read: dev=%p buf=%p blocknum=%li count=%li\n",
+ // dev, buf, blocknum, cnt);
+
+ /* Check whether request is within disk capacity */
+ capacity = virtio_get_config(dev,
+ offset_of(struct virtio_blk_cfg, capacity),
+ sizeof(capacity));
+ if (blocknum + cnt - 1 > capacity) {
+ puts("virtioblk_read: Access beyond end of device!");
+ return 0;
+ }
+
+ blk_size = virtio_get_config(dev,
+ offset_of(struct virtio_blk_cfg, blk_size),
+ sizeof(blk_size));
+ if (blk_size % DEFAULT_SECTOR_SIZE) {
+ fprintf(stderr, "virtio-blk: Unaligned sector read %d\n", blk_size);
+ return 0;
+ }
+
+ vq_size = virtio_get_qsize(dev, 0);
+ vq_desc = virtio_get_vring_desc(dev, 0);
+ vq_avail = virtio_get_vring_avail(dev, 0);
+ vq_used = virtio_get_vring_used(dev, 0);
+
+ last_used_idx = vq_used->idx;
+ current_used_idx = &vq_used->idx;
+
+ /* Set up header */
+ blkhdr.type = VIRTIO_BLK_T_IN | VIRTIO_BLK_T_BARRIER;
+ blkhdr.ioprio = 1;
+ blkhdr.sector = blocknum * blk_size / DEFAULT_SECTOR_SIZE;
+
+ /* Determine descriptor index */
+ id = (vq_avail->idx * 3) % vq_size;
+
+ /* Set up virtqueue descriptor for header */
+ desc = &vq_desc[id];
+ desc->addr = (uint64_t)&blkhdr;
+ desc->len = sizeof(struct virtio_blk_req);
+ desc->flags = VRING_DESC_F_NEXT;
+ desc->next = (id + 1) % vq_size;
+
+ /* Set up virtqueue descriptor for data */
+ desc = &vq_desc[(id + 1) % vq_size];
+ desc->addr = (uint64_t)buf;
+ desc->len = cnt * blk_size;
+ desc->flags = VRING_DESC_F_NEXT | VRING_DESC_F_WRITE;
+ desc->next = (id + 2) % vq_size;
+
+ /* Set up virtqueue descriptor for status */
+ desc = &vq_desc[(id + 2) % vq_size];
+ desc->addr = (uint64_t)&status;
+ desc->len = 1;
+ desc->flags = VRING_DESC_F_WRITE;
+ desc->next = 0;
+
+ vq_avail->ring[vq_avail->idx % vq_size] = id;
+ mb();
+ vq_avail->idx += 1;
+
+ /* Tell HV that the queue is ready */
+ virtio_queue_notify(dev, 0);
+
+ /* Wait for host to consume the descriptor */
+ time = SLOF_GetTimer() + VIRTIO_TIMEOUT;
+ while (*current_used_idx == last_used_idx) {
+ // do something better
+ mb();
+ if (time < SLOF_GetTimer())
+ break;
+ }
+
+ if (status == 0)
+ return cnt;
+
+ printf("virtioblk_read failed! status = %i\n", status);
+
+ return 0;
+}
diff --git a/src/roms/SLOF/lib/libvirtio/virtio-blk.h b/src/roms/SLOF/lib/libvirtio/virtio-blk.h
new file mode 100644
index 0000000..ac8bf28
--- /dev/null
+++ b/src/roms/SLOF/lib/libvirtio/virtio-blk.h
@@ -0,0 +1,60 @@
+/******************************************************************************
+ * Copyright (c) 2011 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+/*
+ * Virtio block device definitions.
+ * See Virtio Spec, Appendix D, for details
+ */
+
+#ifndef _VIRTIO_BLK_H
+#define _VIRTIO_BLK_H
+
+#include <stdint.h>
+
+
+struct virtio_blk_cfg {
+ uint64_t capacity;
+ uint32_t size_max;
+ uint32_t seg_max;
+ struct virtio_blk_geometry {
+ uint16_t cylinders;
+ uint8_t heads;
+ uint8_t sectors;
+ } geometry;
+ uint32_t blk_size;
+ uint32_t sectors_max;
+} __attribute__ ((packed)) ;
+
+/* Block request */
+struct virtio_blk_req {
+ uint32_t type ;
+ uint32_t ioprio ;
+ uint64_t sector ;
+};
+
+/* Block request types */
+#define VIRTIO_BLK_T_IN 0
+#define VIRTIO_BLK_T_OUT 1
+#define VIRTIO_BLK_T_SCSI_CMD 2
+#define VIRTIO_BLK_T_SCSI_CMD_OUT 3
+#define VIRTIO_BLK_T_FLUSH 4
+#define VIRTIO_BLK_T_FLUSH_OUT 5
+#define VIRTIO_BLK_T_BARRIER 0x80000000
+
+/* VIRTIO_BLK Feature bits */
+#define VIRTIO_BLK_F_BLK_SIZE (1 << 6)
+
+extern int virtioblk_init(struct virtio_device *dev);
+extern void virtioblk_shutdown(struct virtio_device *dev);
+extern int virtioblk_read(struct virtio_device *dev, char *buf, long blocknum, long cnt);
+
+#endif /* _VIRTIO_BLK_H */
diff --git a/src/roms/SLOF/lib/libvirtio/virtio-net.c b/src/roms/SLOF/lib/libvirtio/virtio-net.c
new file mode 100644
index 0000000..99c19d9
--- /dev/null
+++ b/src/roms/SLOF/lib/libvirtio/virtio-net.c
@@ -0,0 +1,369 @@
+/******************************************************************************
+ * Copyright (c) 2011 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+/*
+ * This is the implementation for the Virtio network device driver. Details
+ * about the virtio-net interface can be found in Rusty Russel's "Virtio PCI
+ * Card Specification v0.8.10", appendix C, which can be found here:
+ *
+ * http://ozlabs.org/~rusty/virtio-spec/virtio-spec.pdf
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <helpers.h>
+#include <cache.h>
+#include <byteorder.h>
+#include "virtio.h"
+#include "virtio-net.h"
+
+#undef DEBUG
+//#define DEBUG
+#ifdef DEBUG
+# define dprintf(fmt...) do { printf(fmt); } while(0)
+#else
+# define dprintf(fmt...)
+#endif
+
+#define sync() asm volatile (" sync \n" ::: "memory")
+
+/* PCI virtio header offsets */
+#define VIRTIOHDR_DEVICE_FEATURES 0
+#define VIRTIOHDR_GUEST_FEATURES 4
+#define VIRTIOHDR_QUEUE_ADDRESS 8
+#define VIRTIOHDR_QUEUE_SIZE 12
+#define VIRTIOHDR_QUEUE_SELECT 14
+#define VIRTIOHDR_QUEUE_NOTIFY 16
+#define VIRTIOHDR_DEVICE_STATUS 18
+#define VIRTIOHDR_ISR_STATUS 19
+#define VIRTIOHDR_DEVICE_CONFIG 20
+#define VIRTIOHDR_MAC_ADDRESS 20
+
+struct virtio_device virtiodev;
+struct vqs vq[2]; /* Information about virtqueues */
+
+/* See Virtio Spec, appendix C, "Device Operation" */
+struct virtio_net_hdr {
+ uint8_t flags;
+ uint8_t gso_type;
+ uint16_t hdr_len;
+ uint16_t gso_size;
+ uint16_t csum_start;
+ uint16_t csum_offset;
+ // uint16_t num_buffers; /* Only if VIRTIO_NET_F_MRG_RXBUF */
+};
+
+static uint16_t last_rx_idx; /* Last index in RX "used" ring */
+
+/**
+ * Module init for virtio via PCI.
+ * Checks whether we're reponsible for the given device and set up
+ * the virtqueue configuration.
+ */
+static int virtionet_init_pci(struct virtio_device *dev)
+{
+ int i;
+
+ dprintf("virtionet: doing virtionet_init_pci!\n");
+
+ if (!dev)
+ return -1;
+
+ virtiodev.base = dev->base;
+ virtiodev.type = dev->type;
+
+ /* Reset device */
+ virtio_reset_device(&virtiodev);
+
+ /* The queue information can be retrieved via the virtio header that
+ * can be found in the I/O BAR. First queue is the receive queue,
+ * second the transmit queue, and the forth is the control queue for
+ * networking options.
+ * We are only interested in the receive and transmit queue here. */
+
+ for (i=VQ_RX; i<=VQ_TX; i++) {
+ /* Select ring (0=RX, 1=TX): */
+ vq[i].id = i-VQ_RX;
+ ci_write_16(virtiodev.base+VIRTIOHDR_QUEUE_SELECT,
+ cpu_to_le16(vq[i].id));
+
+ vq[i].size = le16_to_cpu(ci_read_16(virtiodev.base+VIRTIOHDR_QUEUE_SIZE));
+ vq[i].desc = SLOF_alloc_mem_aligned(virtio_vring_size(vq[i].size), 4096);
+ if (!vq[i].desc) {
+ printf("memory allocation failed!\n");
+ return -1;
+ }
+ memset(vq[i].desc, 0, virtio_vring_size(vq[i].size));
+ ci_write_32(virtiodev.base+VIRTIOHDR_QUEUE_ADDRESS,
+ cpu_to_le32((long)vq[i].desc / 4096));
+ vq[i].avail = (void*)vq[i].desc
+ + vq[i].size * sizeof(struct vring_desc);
+ vq[i].used = (void*)VQ_ALIGN((long)vq[i].avail
+ + vq[i].size * sizeof(struct vring_avail));
+
+ dprintf("%i: vq.id = %llx\nvq.size =%x\n vq.avail =%p\nvq.used=%p\n",
+ i, vq[i].id, vq[i].size, vq[i].avail, vq[i].used);
+ }
+
+ /* Acknowledge device. */
+ virtio_set_status(&virtiodev, VIRTIO_STAT_ACKNOWLEDGE);
+
+ return 0;
+}
+
+/**
+ * Initialize the virtio-net device.
+ * See the Virtio Spec, chapter 2.2.1 and Appendix C "Device Initialization"
+ * for details.
+ */
+static int virtionet_init(net_driver_t *driver)
+{
+ int i;
+
+ dprintf("virtionet_init(%02x:%02x:%02x:%02x:%02x:%02x)\n",
+ driver->mac_addr[0], driver->mac_addr[1],
+ driver->mac_addr[2], driver->mac_addr[3],
+ driver->mac_addr[4], driver->mac_addr[5]);
+
+ if (driver->running != 0)
+ return 0;
+
+ /* Tell HV that we know how to drive the device. */
+ virtio_set_status(&virtiodev, VIRTIO_STAT_ACKNOWLEDGE|VIRTIO_STAT_DRIVER);
+
+ /* Device specific setup - we do not support special features right now */
+ virtio_set_guest_features(&virtiodev, 0);
+
+ /* Allocate memory for one transmit an multiple receive buffers */
+ vq[VQ_RX].buf_mem = SLOF_alloc_mem((BUFFER_ENTRY_SIZE+sizeof(struct virtio_net_hdr))
+ * RX_QUEUE_SIZE);
+ if (!vq[VQ_RX].buf_mem) {
+ printf("virtionet: Failed to allocate buffers!\n");
+ virtio_set_status(&virtiodev, VIRTIO_STAT_FAILED);
+ return -1;
+ }
+
+ /* Prepare receive buffer queue */
+ for (i = 0; i < RX_QUEUE_SIZE; i++) {
+ struct vring_desc *desc;
+ /* Descriptor for net_hdr: */
+ desc = &vq[VQ_RX].desc[i*2];
+ desc->addr = (uint64_t)vq[VQ_RX].buf_mem
+ + i * (BUFFER_ENTRY_SIZE+sizeof(struct virtio_net_hdr));
+ desc->len = sizeof(struct virtio_net_hdr);
+ desc->flags = VRING_DESC_F_NEXT | VRING_DESC_F_WRITE;
+ desc->next = i*2+1;
+
+ /* Descriptor for data: */
+ desc = &vq[VQ_RX].desc[i*2+1];
+ desc->addr = vq[VQ_RX].desc[i*2].addr + sizeof(struct virtio_net_hdr);
+ desc->len = BUFFER_ENTRY_SIZE;
+ desc->flags = VRING_DESC_F_WRITE;
+ desc->next = 0;
+
+ vq[VQ_RX].avail->ring[i] = i*2;
+ }
+ sync();
+ vq[VQ_RX].avail->flags = VRING_AVAIL_F_NO_INTERRUPT;
+ vq[VQ_RX].avail->idx = RX_QUEUE_SIZE;
+
+ last_rx_idx = vq[VQ_RX].used->idx;
+
+ vq[VQ_TX].avail->flags = VRING_AVAIL_F_NO_INTERRUPT;
+ vq[VQ_TX].avail->idx = 0;
+
+ /* Tell HV that setup succeeded */
+ virtio_set_status(&virtiodev, VIRTIO_STAT_ACKNOWLEDGE
+ |VIRTIO_STAT_DRIVER
+ |VIRTIO_STAT_DRIVER_OK);
+
+ /* Tell HV that RX queues are ready */
+ virtio_queue_notify(&virtiodev, VQ_RX);
+
+ driver->running = 1;
+
+ return 0;
+}
+
+
+/**
+ * Shutdown driver.
+ * We've got to make sure that the hosts stops all transfers since the buffers
+ * in our main memory will become invalid after this module has been terminated.
+ */
+static int virtionet_term(net_driver_t *driver)
+{
+ dprintf("virtionet_term()\n");
+
+ if (driver->running == 0)
+ return 0;
+
+ /* Quiesce device */
+ virtio_set_status(&virtiodev, VIRTIO_STAT_FAILED);
+
+ /* Reset device */
+ virtio_reset_device(&virtiodev);
+
+ driver->running = 0;
+
+ return 0;
+}
+
+
+/**
+ * Transmit a packet
+ */
+static int virtionet_xmit(char *buf, int len)
+{
+ struct vring_desc *desc;
+ int id;
+ static struct virtio_net_hdr nethdr;
+
+ if (len > BUFFER_ENTRY_SIZE) {
+ printf("virtionet: Packet too big!\n");
+ return 0;
+ }
+
+ dprintf("\nvirtionet_xmit(packet at %p, %d bytes)\n", buf, len);
+
+ memset(&nethdr, 0, sizeof(nethdr));
+
+ /* Determine descriptor index */
+ id = (vq[VQ_TX].avail->idx * 2) % vq[VQ_TX].size;
+
+ /* Set up virtqueue descriptor for header */
+ desc = &vq[VQ_TX].desc[id];
+ desc->addr = (uint64_t)&nethdr;
+ desc->len = sizeof(struct virtio_net_hdr);
+ desc->flags = VRING_DESC_F_NEXT;
+ desc->next = id + 1;
+
+ /* Set up virtqueue descriptor for data */
+ desc = &vq[VQ_TX].desc[id+1];
+ desc->addr = (uint64_t)buf;
+ desc->len = len;
+ desc->flags = 0;
+ desc->next = 0;
+
+ vq[VQ_TX].avail->ring[vq[VQ_TX].avail->idx % vq[VQ_TX].size] = id;
+ sync();
+ vq[VQ_TX].avail->idx += 1;
+ sync();
+
+ /* Tell HV that TX queue is ready */
+ virtio_queue_notify(&virtiodev, VQ_TX);
+
+ return len;
+}
+
+
+/**
+ * Receive a packet
+ */
+static int virtionet_receive(char *buf, int maxlen)
+{
+ int len = 0;
+ int id;
+
+ if (last_rx_idx == vq[VQ_RX].used->idx) {
+ /* Nothing received yet */
+ return 0;
+ }
+
+ id = (vq[VQ_RX].used->ring[last_rx_idx % vq[VQ_RX].size].id + 1)
+ % vq[VQ_RX].size;
+ len = vq[VQ_RX].used->ring[last_rx_idx % vq[VQ_RX].size].len
+ - sizeof(struct virtio_net_hdr);
+
+ dprintf("virtionet_receive() last_rx_idx=%i, vq[VQ_RX].used->idx=%i,"
+ " id=%i len=%i\n", last_rx_idx, vq[VQ_RX].used->idx, id, len);
+
+ if (len > maxlen) {
+ printf("virtio-net: Receive buffer not big enough!\n");
+ len = maxlen;
+ }
+
+#if 0
+ /* Dump packet */
+ printf("\n");
+ int i;
+ for (i=0; i<64; i++) {
+ printf(" %02x", *(uint8_t*)(vq[VQ_RX].desc[id].addr+i));
+ if ((i%16)==15)
+ printf("\n");
+ }
+ prinfk("\n");
+#endif
+
+ /* Copy data to destination buffer */
+ memcpy(buf, (void*)vq[VQ_RX].desc[id].addr, len);
+
+ /* Move indices to next entries */
+ last_rx_idx = last_rx_idx + 1;
+
+ vq[VQ_RX].avail->ring[vq[VQ_RX].avail->idx % vq[VQ_RX].size] = id - 1;
+ sync();
+ vq[VQ_RX].avail->idx += 1;
+
+ /* Tell HV that RX queue entry is ready */
+ virtio_queue_notify(&virtiodev, VQ_RX);
+
+ return len;
+}
+
+net_driver_t *virtionet_open(char *mac_addr, int len, struct virtio_device *dev)
+{
+ net_driver_t *driver;
+
+ driver = SLOF_alloc_mem(sizeof(*driver));
+ if (!driver) {
+ printf("Unable to allocate virtio-net driver\n");
+ return NULL;
+ }
+
+ memcpy(driver->mac_addr, mac_addr, 6);
+ driver->running = 0;
+
+ if (virtionet_init_pci(dev))
+ goto FAIL;
+
+ if (virtionet_init(driver))
+ goto FAIL;
+
+ return driver;
+
+FAIL: SLOF_free_mem(driver, sizeof(*driver));
+ return NULL;
+}
+
+void virtionet_close(net_driver_t *driver)
+{
+ if (driver) {
+ virtionet_term(driver);
+ SLOF_free_mem(driver, sizeof(*driver));
+ }
+}
+
+int virtionet_read(char *buf, int len)
+{
+ if (buf)
+ return virtionet_receive(buf, len);
+ return -1;
+}
+
+int virtionet_write(char *buf, int len)
+{
+ if (buf)
+ return virtionet_xmit(buf, len);
+ return -1;
+}
diff --git a/src/roms/SLOF/lib/libvirtio/virtio-net.h b/src/roms/SLOF/lib/libvirtio/virtio-net.h
new file mode 100644
index 0000000..bc7a189
--- /dev/null
+++ b/src/roms/SLOF/lib/libvirtio/virtio-net.h
@@ -0,0 +1,43 @@
+/******************************************************************************
+ * Copyright (c) 2011 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#ifndef VIRTIO_NET_H
+#define VIRTIO_NET_H
+
+#include <netdriver.h>
+
+#define RX_QUEUE_SIZE 128
+#define BUFFER_ENTRY_SIZE 1514
+
+enum {
+ VQ_RX = 0, /* Receive Queue */
+ VQ_TX = 1, /* Transmit Queue */
+};
+
+struct vqs {
+ uint64_t id; /* Queue ID */
+ uint32_t size;
+ void *buf_mem;
+ struct vring_desc *desc;
+ struct vring_avail *avail;
+ struct vring_used *used;
+};
+
+/* Device is identified by RX queue ID: */
+#define DEVICE_ID vq[0].id
+
+extern net_driver_t *virtionet_open(char *mac_addr, int len, struct virtio_device *dev);
+extern void virtionet_close(net_driver_t *driver);
+extern int virtionet_read(char *buf, int len);
+extern int virtionet_write(char *buf, int len);
+
+#endif
diff --git a/src/roms/SLOF/lib/libvirtio/virtio-scsi.c b/src/roms/SLOF/lib/libvirtio/virtio-scsi.c
new file mode 100644
index 0000000..4828928
--- /dev/null
+++ b/src/roms/SLOF/lib/libvirtio/virtio-scsi.c
@@ -0,0 +1,145 @@
+/******************************************************************************
+ * Copyright (c) 2012 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <stdio.h>
+#include <string.h>
+#include <cpu.h>
+#include <helpers.h>
+#include "virtio.h"
+#include "virtio-scsi.h"
+
+int virtioscsi_send(struct virtio_device *dev,
+ struct virtio_scsi_req_cmd *req,
+ struct virtio_scsi_resp_cmd *resp,
+ int is_read, void *buf, uint64_t buf_len)
+{
+ struct vring_desc *desc;
+ struct vring_desc *vq_desc; /* Descriptor vring */
+ struct vring_avail *vq_avail; /* "Available" vring */
+ struct vring_used *vq_used; /* "Used" vring */
+
+ volatile uint16_t *current_used_idx;
+ uint16_t last_used_idx;
+ int id;
+ uint32_t vq_size, time;
+
+ int vq = VIRTIO_SCSI_REQUEST_VQ;
+
+ vq_size = virtio_get_qsize(dev, vq);
+ vq_desc = virtio_get_vring_desc(dev, vq);
+ vq_avail = virtio_get_vring_avail(dev, vq);
+ vq_used = virtio_get_vring_used(dev, vq);
+
+ last_used_idx = vq_used->idx;
+ current_used_idx = &vq_used->idx;
+
+ /* Determine descriptor index */
+ id = (vq_avail->idx * 3) % vq_size;
+
+ desc = &vq_desc[id];
+ desc->addr = (uint64_t)req;
+ desc->len = sizeof(*req);
+ desc->flags = VRING_DESC_F_NEXT;
+ desc->next = (id + 1) % vq_size;
+
+ /* Set up virtqueue descriptor for data */
+ desc = &vq_desc[(id + 1) % vq_size];
+ desc->addr = (uint64_t)resp;
+ desc->len = sizeof(*resp);
+ desc->flags = VRING_DESC_F_NEXT | VRING_DESC_F_WRITE;
+ desc->next = (id + 2) % vq_size;
+
+ if (buf && buf_len) {
+ /* Set up virtqueue descriptor for status */
+ desc = &vq_desc[(id + 2) % vq_size];
+ desc->addr = (uint64_t)buf;
+ desc->len = buf_len;
+ desc->flags = is_read ? VRING_DESC_F_WRITE : 0;
+ desc->next = 0;
+ } else
+ desc->flags &= ~VRING_DESC_F_NEXT;
+
+ vq_avail->ring[vq_avail->idx % vq_size] = id;
+ mb();
+ vq_avail->idx += 1;
+
+ /* Tell HV that the vq is ready */
+ virtio_queue_notify(dev, vq);
+
+ /* Wait for host to consume the descriptor */
+ time = SLOF_GetTimer() + VIRTIO_TIMEOUT;
+ while (*current_used_idx == last_used_idx) {
+ // do something better
+ mb();
+ if (time < SLOF_GetTimer())
+ break;
+ }
+
+ return 0;
+}
+
+/**
+ * Initialize virtio-block device.
+ * @param dev pointer to virtio device information
+ */
+int virtioscsi_init(struct virtio_device *dev)
+{
+ struct vring_avail *vq_avail;
+ unsigned int idx = 0;
+ int qsize = 0;
+
+ /* Reset device */
+ // XXX That will clear the virtq base. We need to move
+ // initializing it to here anyway
+ //
+ // virtio_reset_device(dev);
+
+ /* Acknowledge device. */
+ virtio_set_status(dev, VIRTIO_STAT_ACKNOWLEDGE);
+
+ /* Tell HV that we know how to drive the device. */
+ virtio_set_status(dev, VIRTIO_STAT_ACKNOWLEDGE|VIRTIO_STAT_DRIVER);
+
+ /* Device specific setup - we do not support special features right now */
+ virtio_set_guest_features(dev, 0);
+
+ while(1) {
+ qsize = virtio_get_qsize(dev, idx);
+ if (!qsize)
+ break;
+ virtio_vring_size(qsize);
+
+ vq_avail = virtio_get_vring_avail(dev, 0);
+ vq_avail->flags = VRING_AVAIL_F_NO_INTERRUPT;
+ vq_avail->idx = 0;
+ idx++;
+ }
+
+ /* Tell HV that setup succeeded */
+ virtio_set_status(dev, VIRTIO_STAT_ACKNOWLEDGE|VIRTIO_STAT_DRIVER
+ |VIRTIO_STAT_DRIVER_OK);
+
+ return 0;
+}
+
+/**
+ * Shutdown the virtio-block device.
+ * @param dev pointer to virtio device information
+ */
+void virtioscsi_shutdown(struct virtio_device *dev)
+{
+ /* Quiesce device */
+ virtio_set_status(dev, VIRTIO_STAT_FAILED);
+
+ /* Reset device */
+ virtio_reset_device(dev);
+}
diff --git a/src/roms/SLOF/lib/libvirtio/virtio-scsi.h b/src/roms/SLOF/lib/libvirtio/virtio-scsi.h
new file mode 100644
index 0000000..451ba4d
--- /dev/null
+++ b/src/roms/SLOF/lib/libvirtio/virtio-scsi.h
@@ -0,0 +1,69 @@
+/******************************************************************************
+ * Copyright (c) 2012 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+/*
+ * Virtio SCSI Host device definitions.
+ * See Virtio Spec, Appendix I, for details
+ */
+
+#ifndef _VIRTIO_SCSI_H
+#define _VIRTIO_SCSI_H
+
+#define VIRTIO_SCSI_CDB_SIZE 32
+#define VIRTIO_SCSI_SENSE_SIZE 96
+
+#define VIRTIO_SCSI_CONTROL_VQ 0
+#define VIRTIO_SCSI_EVENT_VQ 1
+#define VIRTIO_SCSI_REQUEST_VQ 2
+
+struct virtio_scsi_config
+{
+ uint32_t num_queues;
+ uint32_t seg_max;
+ uint32_t max_sectors;
+ uint32_t cmd_per_lun;
+ uint32_t event_info_size;
+ uint32_t sense_size;
+ uint32_t cdb_size;
+ uint16_t max_channel;
+ uint16_t max_target;
+ uint32_t max_lun;
+} __attribute__((packed));
+
+/* This is the first element of the "out" scatter-gather list. */
+struct virtio_scsi_req_cmd {
+ uint8_t lun[8];
+ uint64_t tag;
+ uint8_t task_attr;
+ uint8_t prio;
+ uint8_t crn;
+ char cdb[VIRTIO_SCSI_CDB_SIZE];
+};
+
+/* This is the first element of the "in" scatter-gather list. */
+struct virtio_scsi_resp_cmd {
+ uint32_t sense_len;
+ uint32_t residual;
+ uint16_t status_qualifier;
+ uint8_t status;
+ uint8_t response;
+ uint8_t sense[VIRTIO_SCSI_SENSE_SIZE];
+};
+
+extern int virtioscsi_init(struct virtio_device *dev);
+extern void virtioscsi_shutdown(struct virtio_device *dev);
+extern int virtioscsi_send(struct virtio_device *dev,
+ struct virtio_scsi_req_cmd *req,
+ struct virtio_scsi_resp_cmd *resp,
+ int is_read, void *buf, uint64_t buf_len);
+
+#endif /* _VIRTIO_SCSI_H */
diff --git a/src/roms/SLOF/lib/libvirtio/virtio.c b/src/roms/SLOF/lib/libvirtio/virtio.c
new file mode 100644
index 0000000..f9c00a6
--- /dev/null
+++ b/src/roms/SLOF/lib/libvirtio/virtio.c
@@ -0,0 +1,241 @@
+/******************************************************************************
+ * Copyright (c) 2011 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <cpu.h>
+#include <cache.h>
+#include <byteorder.h>
+#include "virtio.h"
+
+/* PCI virtio header offsets */
+#define VIRTIOHDR_DEVICE_FEATURES 0
+#define VIRTIOHDR_GUEST_FEATURES 4
+#define VIRTIOHDR_QUEUE_ADDRESS 8
+#define VIRTIOHDR_QUEUE_SIZE 12
+#define VIRTIOHDR_QUEUE_SELECT 14
+#define VIRTIOHDR_QUEUE_NOTIFY 16
+#define VIRTIOHDR_DEVICE_STATUS 18
+#define VIRTIOHDR_ISR_STATUS 19
+#define VIRTIOHDR_DEVICE_CONFIG 20
+
+
+/**
+ * Calculate ring size according to queue size number
+ */
+unsigned long virtio_vring_size(unsigned int qsize)
+{
+ return VQ_ALIGN(sizeof(struct vring_desc) * qsize +
+ sizeof(struct vring_avail) + sizeof(uint16_t) * qsize) +
+ VQ_ALIGN(sizeof(struct vring_used) +
+ sizeof(struct vring_used_elem) * qsize);
+}
+
+
+/**
+ * Get number of elements in a vring
+ * @param dev pointer to virtio device information
+ * @param queue virtio queue number
+ * @return number of elements
+ */
+int virtio_get_qsize(struct virtio_device *dev, int queue)
+{
+ int size = 0;
+
+ if (dev->type == VIRTIO_TYPE_PCI) {
+ ci_write_16(dev->base+VIRTIOHDR_QUEUE_SELECT,
+ cpu_to_le16(queue));
+ eieio();
+ size = le16_to_cpu(ci_read_16(dev->base+VIRTIOHDR_QUEUE_SIZE));
+ }
+
+ return size;
+}
+
+
+/**
+ * Get address of descriptor vring
+ * @param dev pointer to virtio device information
+ * @param queue virtio queue number
+ * @return pointer to the descriptor ring
+ */
+struct vring_desc *virtio_get_vring_desc(struct virtio_device *dev, int queue)
+{
+ struct vring_desc *desc = 0;
+
+ if (dev->type == VIRTIO_TYPE_PCI) {
+ ci_write_16(dev->base+VIRTIOHDR_QUEUE_SELECT,
+ cpu_to_le16(queue));
+ eieio();
+ desc = (void*)(4096L *
+ le32_to_cpu(ci_read_32(dev->base+VIRTIOHDR_QUEUE_ADDRESS)));
+ }
+
+ return desc;
+}
+
+
+/**
+ * Get address of "available" vring
+ * @param dev pointer to virtio device information
+ * @param queue virtio queue number
+ * @return pointer to the "available" ring
+ */
+struct vring_avail *virtio_get_vring_avail(struct virtio_device *dev, int queue)
+{
+ return (void*)((uint64_t)virtio_get_vring_desc(dev, queue)
+ + virtio_get_qsize(dev, queue) * sizeof(struct vring_desc));
+}
+
+
+/**
+ * Get address of "used" vring
+ * @param dev pointer to virtio device information
+ * @param queue virtio queue number
+ * @return pointer to the "used" ring
+ */
+struct vring_used *virtio_get_vring_used(struct virtio_device *dev, int queue)
+{
+ return (void*)VQ_ALIGN((uint64_t)virtio_get_vring_avail(dev, queue)
+ + virtio_get_qsize(dev, queue)
+ * sizeof(struct vring_avail));
+}
+
+
+/**
+ * Reset virtio device
+ */
+void virtio_reset_device(struct virtio_device *dev)
+{
+ if (dev->type == VIRTIO_TYPE_PCI) {
+ ci_write_8(dev->base+VIRTIOHDR_DEVICE_STATUS, 0);
+ }
+}
+
+
+/**
+ * Notify hypervisor about queue update
+ */
+void virtio_queue_notify(struct virtio_device *dev, int queue)
+{
+ if (dev->type == VIRTIO_TYPE_PCI) {
+ ci_write_16(dev->base+VIRTIOHDR_QUEUE_NOTIFY, cpu_to_le16(queue));
+ }
+}
+
+/**
+ * Set queue address
+ */
+void virtio_set_qaddr(struct virtio_device *dev, int queue, unsigned int qaddr)
+{
+ if (dev->type == VIRTIO_TYPE_PCI) {
+ uint32_t val = qaddr;
+ val = val >> 12;
+ ci_write_16(dev->base+VIRTIOHDR_QUEUE_SELECT,
+ cpu_to_le16(queue));
+ eieio();
+ ci_write_32(dev->base+VIRTIOHDR_QUEUE_ADDRESS,
+ cpu_to_le32(val));
+ }
+}
+
+/**
+ * Set device status bits
+ */
+void virtio_set_status(struct virtio_device *dev, int status)
+{
+ if (dev->type == VIRTIO_TYPE_PCI) {
+ ci_write_8(dev->base+VIRTIOHDR_DEVICE_STATUS, status);
+ }
+}
+
+
+/**
+ * Set guest feature bits
+ */
+void virtio_set_guest_features(struct virtio_device *dev, int features)
+
+{
+ if (dev->type == VIRTIO_TYPE_PCI) {
+ ci_write_32(dev->base+VIRTIOHDR_GUEST_FEATURES, bswap_32(features));
+ }
+}
+
+/**
+ * Get host feature bits
+ */
+void virtio_get_host_features(struct virtio_device *dev, int *features)
+
+{
+ if (dev->type == VIRTIO_TYPE_PCI && features) {
+ *features = bswap_32(ci_read_32(dev->base+VIRTIOHDR_DEVICE_FEATURES));
+ }
+}
+
+
+/**
+ * Get additional config values
+ */
+uint64_t virtio_get_config(struct virtio_device *dev, int offset, int size)
+{
+ uint64_t val = ~0ULL;
+ void *confbase;
+
+ switch (dev->type) {
+ case VIRTIO_TYPE_PCI:
+ confbase = dev->base+VIRTIOHDR_DEVICE_CONFIG;
+ break;
+ default:
+ return ~0ULL;
+ }
+ switch (size) {
+ case 1:
+ val = ci_read_8(confbase+offset);
+ break;
+ case 2:
+ val = ci_read_16(confbase+offset);
+ break;
+ case 4:
+ val = ci_read_32(confbase+offset);
+ break;
+ case 8:
+ /* We don't support 8 bytes PIO accesses
+ * in qemu and this is all PIO
+ */
+ val = ci_read_32(confbase+offset);
+ val <<= 32;
+ val |= ci_read_32(confbase+offset+4);
+ break;
+ }
+
+ return val;
+}
+
+/**
+ * Get config blob
+ */
+int __virtio_read_config(struct virtio_device *dev, void *dst,
+ int offset, int len)
+{
+ void *confbase;
+ unsigned char *buf = dst;
+ int i;
+
+ switch (dev->type) {
+ case VIRTIO_TYPE_PCI:
+ confbase = dev->base+VIRTIOHDR_DEVICE_CONFIG;
+ break;
+ default:
+ return 0;
+ }
+ for (i = 0; i < len; i++)
+ buf[i] = ci_read_8(confbase + offset + i);
+ return len;
+}
diff --git a/src/roms/SLOF/lib/libvirtio/virtio.code b/src/roms/SLOF/lib/libvirtio/virtio.code
new file mode 100644
index 0000000..258b9bb
--- /dev/null
+++ b/src/roms/SLOF/lib/libvirtio/virtio.code
@@ -0,0 +1,164 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2011 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <virtio.h>
+#include <virtio-blk.h>
+#include <virtio-9p.h>
+#include <virtio-scsi.h>
+#include <virtio-net.h>
+
+/******** core virtio ********/
+
+// : virtio-vring-size ( queuesize -- ringsize )
+PRIM(virtio_X2d_vring_X2d_size)
+ TOS.u = virtio_vring_size(TOS.u);
+MIRP
+
+// : virtio-get-qsize ( dev queue -- queuesize )
+PRIM(virtio_X2d_get_X2d_qsize)
+ int queue = TOS.u; POP;
+ TOS.u = virtio_get_qsize(TOS.a, queue);
+MIRP
+
+// : virtio-get-config ( dev offset size -- val )
+PRIM(virtio_X2d_get_X2d_config)
+ int size = TOS.u; POP;
+ int offset = TOS.u; POP;
+ TOS.u = virtio_get_config(TOS.a, offset, size);
+MIRP
+
+// : virtio-set-qaddr ( dev queue qaddr -- )
+PRIM(virtio_X2d_set_X2d_qaddr)
+ unsigned int qaddr = TOS.u; POP;
+ int queue = TOS.u; POP;
+ void *dev = TOS.a; POP;
+ virtio_set_qaddr(dev, queue, qaddr);
+MIRP
+
+/******** virtio-blk ********/
+
+// : virtio-blk-init ( dev -- blk-size)
+PRIM(virtio_X2d_blk_X2d_init)
+ void *dev = TOS.a;
+ TOS.u = virtioblk_init(dev);
+MIRP
+
+// : virtio-blk-shutdown ( dev -- )
+PRIM(virtio_X2d_blk_X2d_shutdown)
+ void *dev = TOS.a; POP;
+ virtioblk_shutdown(dev);
+MIRP
+
+// : virtio-blk-read ( dev blkno cnt reg -- #read )
+PRIM(virtio_X2d_blk_X2d_read)
+ void *dev = TOS.a; POP;
+ long cnt = TOS.n; POP;
+ long blkno = TOS.n; POP;
+ void *buf = TOS.a;
+ TOS.n = virtioblk_read(dev, buf, blkno, cnt);
+MIRP
+
+/******** virtio-fs ********/
+
+// : virtio-fs-init ( dev tx rx size -- success )
+PRIM(virtio_X2d_fs_X2d_init)
+ int size = TOS.n; POP;
+ void *rx = TOS.a; POP;
+ void *tx = TOS.a; POP;
+ void *dev = TOS.a;
+
+ TOS.n = virtio_9p_init(dev, tx, rx, size) == 0 ? -1 : 0;
+MIRP
+
+// : virtio-fs-shutdown ( dev -- )
+PRIM(virtio_X2d_fs_X2d_shutdown)
+ void *dev = TOS.a; POP;
+
+ virtio_9p_shutdown(dev);
+MIRP
+
+// : virtio-fs-load ( dev buf str -- #read )
+PRIM(virtio_X2d_fs_X2d_load)
+ char *str = TOS.a; POP;
+ void *buf = TOS.a; POP;
+ void *dev = TOS.a;
+
+ TOS.n = virtio_9p_load(dev, str, buf);
+MIRP
+
+/******** virtio-scsi ********/
+
+// : virtio-scsi-init ( dev -- success )
+PRIM(virtio_X2d_scsi_X2d_init)
+ void *dev = TOS.a;
+ TOS.u = virtioscsi_init(dev);
+MIRP
+
+// : virtio-scsi-shutdown ( dev -- )
+PRIM(virtio_X2d_scsi_X2d_shutdown)
+ void *dev = TOS.a; POP;
+ virtioscsi_shutdown(dev);
+MIRP
+
+// : virtio-scsi-send ( buf_addr buf_len is_read req_ptr rsp_ptr dev -- success)
+PRIM(virtio_X2d_scsi_X2d_send)
+ void *dev = TOS.a; POP;
+ void *resp = TOS.a; POP;
+ void *req = TOS.a; POP;
+ int is_read = !!TOS.n; POP;
+ uint64_t blen = TOS.n; POP;
+ void *buf = TOS.a;
+ TOS.n = virtioscsi_send(dev, req, resp, is_read, buf, blen);
+MIRP
+
+/******** virtio-net ********/
+
+// : virtio-net-open ( mac-addr-str len dev -- false | [ driver true ] )
+PRIM(virtio_X2d_net_X2d_open)
+{
+ void *dev = TOS.a; POP;
+ int len = TOS.u; POP;
+ char *mac_addr = TOS.a;
+
+ net_driver_t *net_driver = virtionet_open(mac_addr, len, dev);
+
+ if (net_driver) {
+ TOS.u = (unsigned long)net_driver; PUSH;
+ TOS.n = -1;
+ } else
+ TOS.n = 0;
+}
+MIRP
+
+// : virtio-net-close ( driver -- )
+PRIM(virtio_X2d_net_X2d_close)
+{
+ net_driver_t *driver = TOS.a; POP;
+ virtionet_close(driver);
+}
+MIRP
+
+// : virtio-net-read ( addr len -- actual )
+PRIM(virtio_X2d_net_X2d_read)
+{
+ int len = TOS.u; POP;
+ TOS.n = virtionet_read(TOS.a, len);
+}
+MIRP
+
+// : virtio-net-write ( addr len -- actual )
+PRIM(virtio_X2d_net_X2d_write)
+{
+ int len = TOS.u; POP;
+ TOS.n = virtionet_write(TOS.a, len);
+}
+MIRP
diff --git a/src/roms/SLOF/lib/libvirtio/virtio.h b/src/roms/SLOF/lib/libvirtio/virtio.h
new file mode 100644
index 0000000..d5759b4
--- /dev/null
+++ b/src/roms/SLOF/lib/libvirtio/virtio.h
@@ -0,0 +1,90 @@
+/******************************************************************************
+ * Copyright (c) 2011 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#ifndef _LIBVIRTIO_H
+#define _LIBVIRTIO_H
+
+#include <stdint.h>
+
+/* Device status bits */
+#define VIRTIO_STAT_ACKNOWLEDGE 1
+#define VIRTIO_STAT_DRIVER 2
+#define VIRTIO_STAT_DRIVER_OK 4
+#define VIRTIO_STAT_FAILED 128
+
+#define VIRTIO_TIMEOUT 5000 /* 5 sec timeout */
+
+/* Definitions for vring_desc.flags */
+#define VRING_DESC_F_NEXT 1 /* buffer continues via the next field */
+#define VRING_DESC_F_WRITE 2 /* buffer is write-only (otherwise read-only) */
+#define VRING_DESC_F_INDIRECT 4 /* buffer contains a list of buffer descriptors */
+
+/* Descriptor table entry - see Virtio Spec chapter 2.3.2 */
+struct vring_desc {
+ uint64_t addr; /* Address (guest-physical) */
+ uint32_t len; /* Length */
+ uint16_t flags; /* The flags as indicated above */
+ uint16_t next; /* Next field if flags & NEXT */
+};
+
+/* Definitions for vring_avail.flags */
+#define VRING_AVAIL_F_NO_INTERRUPT 1
+
+/* Available ring - see Virtio Spec chapter 2.3.4 */
+struct vring_avail {
+ uint16_t flags;
+ uint16_t idx;
+ uint16_t ring[];
+};
+
+
+/* Definitions for vring_used.flags */
+#define VRING_USED_F_NO_NOTIFY 1
+
+struct vring_used_elem {
+ uint32_t id; /* Index of start of used descriptor chain */
+ uint32_t len; /* Total length of the descriptor chain which was used */
+};
+
+struct vring_used {
+ uint16_t flags;
+ uint16_t idx;
+ struct vring_used_elem ring[];
+};
+
+#define VIRTIO_TYPE_PCI 0 /* For virtio-pci interface */
+struct virtio_device {
+ void *base; /* base address */
+ int type; /* VIRTIO_TYPE_PCI or VIRTIO_TYPE_VIO */
+};
+
+/* Parts of the virtqueue are aligned on a 4096 byte page boundary */
+#define VQ_ALIGN(addr) (((addr) + 0xfff) & ~0xfff)
+
+extern unsigned long virtio_vring_size(unsigned int qsize);
+extern int virtio_get_qsize(struct virtio_device *dev, int queue);
+extern struct vring_desc *virtio_get_vring_desc(struct virtio_device *dev, int queue);
+extern struct vring_avail *virtio_get_vring_avail(struct virtio_device *dev, int queue);
+extern struct vring_used *virtio_get_vring_used(struct virtio_device *dev, int queue);
+
+extern void virtio_reset_device(struct virtio_device *dev);
+extern void virtio_queue_notify(struct virtio_device *dev, int queue);
+extern void virtio_set_status(struct virtio_device *dev, int status);
+extern void virtio_set_qaddr(struct virtio_device *dev, int queue, unsigned int qaddr);
+extern void virtio_set_guest_features(struct virtio_device *dev, int features);
+extern void virtio_get_host_features(struct virtio_device *dev, int *features);
+extern uint64_t virtio_get_config(struct virtio_device *dev, int offset, int size);
+extern int __virtio_read_config(struct virtio_device *dev, void *dst,
+ int offset, int len);
+
+
+#endif /* _LIBVIRTIO_H */
diff --git a/src/roms/SLOF/lib/libvirtio/virtio.in b/src/roms/SLOF/lib/libvirtio/virtio.in
new file mode 100644
index 0000000..c36d127
--- /dev/null
+++ b/src/roms/SLOF/lib/libvirtio/virtio.in
@@ -0,0 +1,33 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2011 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+cod(virtio-vring-size)
+cod(virtio-get-qsize)
+cod(virtio-get-config)
+cod(virtio-set-qaddr)
+
+cod(virtio-blk-init)
+cod(virtio-blk-shutdown)
+cod(virtio-blk-read)
+
+cod(virtio-scsi-init)
+cod(virtio-scsi-shutdown)
+cod(virtio-scsi-send)
+
+cod(virtio-fs-init)
+cod(virtio-fs-shutdown)
+cod(virtio-fs-load)
+
+cod(virtio-net-open)
+cod(virtio-net-close)
+cod(virtio-net-read)
+cod(virtio-net-write)
OpenPOWER on IntegriCloud