Stefan Reinauer (stefan.reinauer(a)coreboot.org) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/7064
-gerrit
commit 2ec56c32d6e0ee6f45ee6531f9021ed819eaf26b
Author: Stefan Reinauer <stefan.reinauer(a)coreboot.org>
Date: Thu Oct 16 12:18:41 2014 +0200
test commit
Change-Id: I8a31ab3c12841ebb65d8032ce716a215bda38f4e
---
test | 1 +
1 file changed, 1 insertion(+)
diff --git a/test b/test
new file mode 100644
index 0000000..9daeafb
--- /dev/null
+++ b/test
@@ -0,0 +1 @@
+test
the following patch was just integrated into master:
commit 822bc65b0e8cb9c17721b8b776ec7ecf6ac4129e
Author: Vladimir Serbinenko <phcoder(a)gmail.com>
Date: Fri Jan 3 15:55:40 2014 +0100
ACPI: Remove CONFIG_GENERATE_ACPI_TABLES
As currently many systems would be barely functional without ACPI,
always generate ACPI tables if supported.
Change-Id: I372dbd03101030c904dab153552a1291f3b63518
Signed-off-by: Vladimir Serbinenko <phcoder(a)gmail.com>
Reviewed-on: http://review.coreboot.org/4609
Tested-by: build bot (Jenkins)
Reviewed-by: Aaron Durbin <adurbin(a)google.com>
See http://review.coreboot.org/4609 for details.
-gerrit
Kyösti Mälkki (kyosti.malkki(a)gmail.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/4583
-gerrit
commit 1264c2702f346a82106d687a3751fd5336beefe8
Author: Kyösti Mälkki <kyosti.malkki(a)gmail.com>
Date: Sun Dec 29 12:07:54 2013 +0200
AMD (K8/fam10): Rewrite CAR migration in post_cache_as_ram
Old routine copied all of CAR region as-is right below CONFIG_RAMTOP.
Most of this region was reserved to interleave AP CPU address spaces
and unused on BSP CPU. The only part of CAR region requiring a copy
in RAM is the sysinfo structure.
Improved routine changes this as follows:
A region of size 'backup_size' below CONFIG_RAMTOP is cleared. In
case of S3 resume, OS context from this region is first copied to
high memory (CBMEM_ID_RESUME).
At stack switch, CAR stack is discarded. Top of the stack for BSP
is located at 'CONFIG_RAMTOP - car_size' for the remaining part
of the romstage. This region is part of 'backup_size' and was zeroed
before the switch took place.
Before CAR is torn down the region of CAR_GLOBALS (and CAR_CBMEM),
including the relevant sysinfo data for AP nodes memory training,
is copied at 'CONFIG_RAMTOP - car_size'.
NOTE: While CAR_GLOBAL variables are recovered, there are currently
no means to calculate their offsets in RAM.
NOTE: Boards with multiple CPU packages are likely already broken since
bbc880ee amdk8/amdfam10: Use CAR_GLOBAL for sysinfo
This moved the copy of sysinfo in RAM from above the stack to below
the stack, but code for AP CPU's was not adjusted accordingly.
Change-Id: Ie45b576aec6a2e006bfcb26b52fdb77c24f72e3b
Signed-off-by: Kyösti Mälkki <kyosti.malkki(a)gmail.com>
---
src/cpu/amd/car/cache_as_ram.inc | 5 +-
src/cpu/amd/car/post_cache_as_ram.c | 174 ++++++++++++++++++------------------
src/include/cpu/amd/car.h | 4 +-
3 files changed, 91 insertions(+), 92 deletions(-)
diff --git a/src/cpu/amd/car/cache_as_ram.inc b/src/cpu/amd/car/cache_as_ram.inc
index dd02f6c..dadf8f7 100644
--- a/src/cpu/amd/car/cache_as_ram.inc
+++ b/src/cpu/amd/car/cache_as_ram.inc
@@ -424,10 +424,9 @@ CAR_FAM10_ap_out:
cache_as_ram_switch_stack:
/* Return address. */
popl %eax
- /* Resume memory. */
+ /* New stack. */
popl %eax
- subl $(( (CONFIG_DCACHE_RAM_BASE + CONFIG_DCACHE_RAM_SIZE)- (CONFIG_RAMTOP) )), %esp
- pushl %eax
+ movl %eax, %esp
call cache_as_ram_new_stack
all_mtrr_msrs:
diff --git a/src/cpu/amd/car/post_cache_as_ram.c b/src/cpu/amd/car/post_cache_as_ram.c
index 3a0763a..61874a9 100644
--- a/src/cpu/amd/car/post_cache_as_ram.c
+++ b/src/cpu/amd/car/post_cache_as_ram.c
@@ -10,58 +10,78 @@
#include "cbmem.h"
#include "cpu/amd/car/disable_cache_as_ram.c"
-static inline void print_debug_pcar(const char *strval, uint32_t val)
+#if CONFIG_RAMTOP <= 0x100000
+ #error "You need to set CONFIG_RAMTOP greater than 1M"
+#endif
+
+#define PRINTK_IN_CAR 1
+
+#if PRINTK_IN_CAR
+#define print_car_debug(x) print_debug(x)
+#else
+#define print_car_debug(x)
+#endif
+
+extern char _car_data_start[];
+extern char _car_data_end[];
+
+static size_t car_data_size(void)
{
- printk(BIOS_DEBUG, "%s%08x\n", strval, val);
+ size_t car_size = &_car_data_end[0] - &_car_data_start[0];
+ return ALIGN(car_size, 64);
}
-/* from linux kernel 2.6.32 asm/string_32.h */
-
-static void inline __attribute__((always_inline)) memcopy(void *dest, const void *src, unsigned long bytes)
+static size_t backup_size(void)
{
- int d0, d1, d2;
- asm volatile("cld ; rep ; movsl\n\t"
- "movl %4,%%ecx\n\t"
- "andl $3,%%ecx\n\t"
- "jz 1f\n\t"
- "rep ; movsb\n\t"
- "1:"
- : "=&c" (d0), "=&D" (d1), "=&S" (d2)
- : "0" (bytes / 4), "g" (bytes), "1" ((long)dest), "2" ((long)src)
- : "memory", "cc");
+ size_t car_size = &_car_data_end[0] - &_car_data_start[0];
+ return ALIGN(car_size + 1024, 1024);
}
-#if CONFIG_HAVE_ACPI_RESUME
+static void memcpy_(void *d, const void *s, size_t len)
+{
+#if PRINTK_IN_CAR
+ printk(BIOS_SPEW, " Copy [%08x-%08x] to [%08x - %08x] ... ",
+ (u32) s, (u32) (s + len - 1), (u32) d, (u32) (d + len - 1));
+#endif
+ memcpy(d, s, len);
+}
-static inline void *backup_resume(void) {
- void *resume_backup_memory;
- int suspend = acpi_is_wakeup_early();
+static void memset_(void *d, int val, size_t len)
+{
+#if PRINTK_IN_CAR
+ printk(BIOS_SPEW, " Fill [%08x-%08x] ... ", (u32) d, (u32) (d + len - 1));
+#endif
+ memset(d, val, len);
+}
- if (!suspend)
- return NULL;
+static void prepare_romstage_ramstack(void *resume_backup_memory)
+{
+ size_t backup_top = backup_size();
+ print_car_debug("Prepare CAR migration and stack regions...");
- if (cbmem_recovery(1))
- return NULL;
+ if (resume_backup_memory) {
+ memcpy_(resume_backup_memory + HIGH_MEMORY_SAVE - backup_top,
+ (void *)(CONFIG_RAMTOP - backup_top), backup_top);
+ }
+ memset_((void *)(CONFIG_RAMTOP - backup_top), 0, backup_top);
- resume_backup_memory = cbmem_find(CBMEM_ID_RESUME);
+ print_car_debug("Done\n");
+}
- /* copy 1MB - 64K to high tables ram_base to prevent memory corruption
- * through stage 2. We could keep stuff like stack and heap in high tables
- * memory completely, but that's a wonderful clean up task for another
- * day.
- */
+static void prepare_ramstage_region(void *resume_backup_memory)
+{
+ size_t backup_top = backup_size();
+ print_car_debug("Prepare ramstage memory region... ");
if (resume_backup_memory) {
- print_debug_pcar("Will copy coreboot region to: ", (uint32_t) resume_backup_memory);
- /* copy only backup only memory used for CAR */
- memcopy(resume_backup_memory+HIGH_MEMORY_SAVE-CONFIG_DCACHE_RAM_SIZE,
- (void *)((CONFIG_RAMTOP)-CONFIG_DCACHE_RAM_SIZE),
- CONFIG_DCACHE_RAM_SIZE); //inline
+ memcpy_(resume_backup_memory, (void *) CONFIG_RAMBASE, HIGH_MEMORY_SAVE - backup_top);
+ memset_((void*) CONFIG_RAMBASE, 0, HIGH_MEMORY_SAVE - backup_top);
+ } else {
+ memset_((void*)0, 0, CONFIG_RAMTOP - backup_top);
}
- return resume_backup_memory;
+ print_car_debug("Done\n");
}
-#endif
/* Disable Erratum 343 Workaround, see RevGuide for Fam10h, Pub#41322 Rev 3.33 */
@@ -80,73 +100,53 @@ static void vErrata343(void)
void post_cache_as_ram(void)
{
void *resume_backup_memory = NULL;
-#if 1
- {
- /* Check value of esp to verify if we have enough room for stack in Cache as RAM */
- unsigned v_esp;
- __asm__ volatile (
- "movl %%esp, %0\n\t"
- : "=a" (v_esp)
- );
- print_debug_pcar("v_esp=", v_esp);
- }
-#endif
-
- /* copy data from cache as ram to
- ram need to set CONFIG_RAMTOP to 2M and use var mtrr instead.
- */
-#if CONFIG_RAMTOP <= 0x100000
- #error "You need to set CONFIG_RAMTOP greater than 1M"
-#endif
-#if CONFIG_HAVE_ACPI_RESUME
- resume_backup_memory = backup_resume();
+ int s3resume = acpi_s3_resume_allowed() && acpi_is_wakeup_early();
+ if (s3resume) {
+#if IS_ENABLED(CONFIG_HAVE_ACPI_RESUME)
+ cbmem_recovery(s3resume);
+ resume_backup_memory = cbmem_find(CBMEM_ID_RESUME);
#endif
-
- print_debug("Copying data from cache to RAM -- switching to use RAM as stack... ");
+ }
+ prepare_romstage_ramstack(resume_backup_memory);
/* from here don't store more data in CAR */
vErrata343();
- memcopy((void *)((CONFIG_RAMTOP)-CONFIG_DCACHE_RAM_SIZE), (void *)CONFIG_DCACHE_RAM_BASE, CONFIG_DCACHE_RAM_SIZE); //inline
- cache_as_ram_switch_stack(resume_backup_memory);
-}
+ size_t car_size = car_data_size();
+ void *migrated_car = (void *)(CONFIG_RAMTOP - car_size);
-void
-cache_as_ram_new_stack (void *resume_backup_memory __attribute__ ((unused)))
-{
- /* We can put data to stack again */
+ print_car_debug("Copying data from cache to RAM... ");
+ memcpy_(migrated_car, &_car_data_start[0], car_size);
+ print_car_debug("Done\n");
+
+ /* New stack grows right below migrated_car. */
+ print_car_debug("Switching to use RAM as stack... ");
+ cache_as_ram_switch_stack(migrated_car);
- /* only global variable sysinfo in cache need to be offset */
- print_debug("Done\n");
+ /* We do not come back. */
+}
- print_debug("Disabling cache as ram now \n");
+void cache_as_ram_new_stack (void)
+{
+ void *resume_backup_memory = NULL;
+#if PRINTK_IN_CAR
+ printk(BIOS_DEBUG, "Top about %08x ... Done\n", (u32) &resume_backup_memory);
+#endif
+ print_car_debug("Disabling cache as ram now\n");
disable_cache_as_ram_bsp();
disable_cache();
set_var_mtrr(0, 0x00000000, CONFIG_RAMTOP, MTRR_TYPE_WRBACK);
enable_cache();
-#if CONFIG_HAVE_ACPI_RESUME
- /* now copy the rest of the area, using the WB method because we already
- run normal RAM */
- if (resume_backup_memory) {
- memcopy(resume_backup_memory,
- (void *)(CONFIG_RAMBASE),
- (CONFIG_RAMTOP) - CONFIG_RAMBASE - CONFIG_DCACHE_RAM_SIZE);
- }
+ if (acpi_s3_resume_allowed() && acpi_is_wakeup_early()) {
+#if IS_ENABLED(CONFIG_HAVE_ACPI_RESUME)
+ resume_backup_memory = cbmem_find(CBMEM_ID_RESUME);
#endif
-
- print_debug("Clearing initial memory region: ");
-
-#if CONFIG_HAVE_ACPI_RESUME
- /* clear only coreboot used region of memory. Note: this may break ECC enabled boards */
- memset((void*) CONFIG_RAMBASE, 0, (CONFIG_RAMTOP) - CONFIG_RAMBASE - CONFIG_DCACHE_RAM_SIZE);
-#else
- memset((void*)0, 0, ((CONFIG_RAMTOP) - CONFIG_DCACHE_RAM_SIZE));
-#endif
- print_debug("Done\n");
+ }
+ prepare_ramstage_region(resume_backup_memory);
set_sysinfo_in_ram(1); // So other core0 could start to train mem
@@ -154,5 +154,5 @@ cache_as_ram_new_stack (void *resume_backup_memory __attribute__ ((unused)))
copy_and_run();
/* We will not return */
- print_debug("should not be here -\n");
+ print_car_debug("should not be here -\n");
}
diff --git a/src/include/cpu/amd/car.h b/src/include/cpu/amd/car.h
index a001c93..c00310a 100644
--- a/src/include/cpu/amd/car.h
+++ b/src/include/cpu/amd/car.h
@@ -5,8 +5,8 @@ void cache_as_ram_main(unsigned long bist, unsigned long cpu_init_detectedx);
void done_cache_as_ram_main(void);
void post_cache_as_ram(void);
-void cache_as_ram_switch_stack(void *resume_backup_memory);
-void cache_as_ram_new_stack(void *resume_backup_memory);
+void cache_as_ram_switch_stack(void *stacktop);
+void cache_as_ram_new_stack(void);
#if CONFIG_CPU_AMD_AGESA
void disable_cache_as_ram(void);
Nico Huber (nico.h(a)gmx.de) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/4695
-gerrit
commit 17b1d1932dd38599bec3a6950e10c22eb1bc6ff3
Author: Nico Huber <nico.h(a)gmx.de>
Date: Wed Jan 1 20:47:55 2014 +0100
uio_usbdebug: User-space-i/o framework for usbdebug
uio_usbdebug enables you to debug coreboot's usbdebug driver inside a
running operating system (only Linux at this time). This comes very
handy if you're hacking the usbdebug driver and don't have any other
debug output from coreboot itself.
Currently, only Intel chipsets are supported.
Change-Id: Iaf0bcd4b4c01ae0b099d1206d553344054a62f31
Signed-off-by: Nico Huber <nico.h(a)gmx.de>
---
util/uio_usbdebug/Makefile | 54 +++++++++++++++
util/uio_usbdebug/README | 77 ++++++++++++++++++++++
util/uio_usbdebug/console/printk.c | 34 ++++++++++
util/uio_usbdebug/drivers/usb/pci_ehci.c | 98 +++++++++++++++++++++++++++
util/uio_usbdebug/include/device/device.h | 35 ++++++++++
util/uio_usbdebug/lib/cbmem.c | 8 +++
util/uio_usbdebug/linux/Makefile | 13 ++++
util/uio_usbdebug/linux/uio_ehci_pci.c | 106 ++++++++++++++++++++++++++++++
util/uio_usbdebug/uio_usbdebug.c | 67 +++++++++++++++++++
util/uio_usbdebug/uio_usbdebug_intel.c | 67 +++++++++++++++++++
10 files changed, 559 insertions(+)
diff --git a/util/uio_usbdebug/Makefile b/util/uio_usbdebug/Makefile
new file mode 100644
index 0000000..74bc80e
--- /dev/null
+++ b/util/uio_usbdebug/Makefile
@@ -0,0 +1,54 @@
+include ../../.config
+
+ARCHDIR-$(CONFIG_ARCH_ARMV7) := armv7
+ARCHDIR-$(CONFIG_ARCH_X86) := x86
+
+# Only Intel chipsets supported, currently.
+OBJ-$(CONFIG_SOUTHBRIDGE_INTEL_COMMON) += uio_usbdebug_intel.o
+
+PROGRAM := uio_usbdebug
+
+CB_SRC := $(shell realpath ../../src)
+CB_SOURCES := drivers/usb/ehci_debug.c
+CB_INCLUDES := \
+ drivers/usb/ehci.h \
+ drivers/usb/ehci_debug.h \
+ drivers/usb/usb_ch9.h
+INCLUDES := \
+ include/device/device.h
+OBJECTS := \
+ uio_usbdebug.o \
+ drivers/usb/pci_ehci.o \
+ console/printk.o \
+ lib/cbmem.o \
+ $(OBJ-y) \
+ $(patsubst %.c,%.o,$(CB_SOURCES))
+
+KCONFIG_H := ../../src/include/kconfig.h
+
+CFLAGS += \
+ -m32 -g \
+ -Wall -Wextra -Werror \
+ -Wno-unused-parameter -Wno-error=sign-compare
+CPPFLAGS += \
+ -Iinclude/ \
+ -I../../src/include/ -I../../src/arch/$(ARCHDIR-y)/include/ \
+ -I../../build/ -include$(KCONFIG_H)
+
+LIBS := -lpci -lz
+
+all: $(PROGRAM)
+
+$(PROGRAM): $(OBJECTS)
+ $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJECTS) $(LIBS)
+
+$(CB_SOURCES) $(CB_INCLUDES):
+ @mkdir -p $(dir $@)
+ @ln -sf $(CB_SRC)/$@ $@
+
+$(OBJECTS): $(CONFIG_H) $(CB_INCLUDES) $(INCLUDES)
+
+clean:
+ -@rm -rf $(CB_SOURCES) $(CB_INCLUDES) $(OBJECTS) $(PROGRAM)
+
+.PHONY: all clean
diff --git a/util/uio_usbdebug/README b/util/uio_usbdebug/README
new file mode 100644
index 0000000..2d52338
--- /dev/null
+++ b/util/uio_usbdebug/README
@@ -0,0 +1,77 @@
+
+uio_usbdebug - Run coreboot's usbdebug driver in userspace
+==========================================================
+
+
+## Purpose
+
+uio_usbdebug enables you to debug coreboot's usbdebug driver inside a
+running operating system (only Linux at this time). This comes very
+handy if you're hacking the usbdebug driver and don't have any other
+debug output from coreboot itself.
+
+
+## State
+
+Currently only Intel chipsets are supported. Support for other chipsets
+should be straightforward (normally just some port-enable code has to
+be implemented).
+
+The Linux kernel driver (see linux/uio_ehci_pci.c) has only one PCI ID
+hardcoded (for ICH7). The whole setup has been developed and tested on
+a ThinkPad T60.
+
+### Files
+
+uio_usbdebug.c - The userspace part of the uio interface.
+
+uio_usbdebug_intel.c - Port enable code for Intel chipsets.
+
+linux/uio_ehci_pci.c - Kernel part of the uio interface.
+
+console/printk.c - A do_printk() implementation so you can see debug
+ output with CONFIG_DEBUG_USBDEBUG enabled.
+
+device/*.c lib/*.c - Some stubs for (hopefully) unneeded functions for
+ proper linking.
+
+
+## Usage
+
+### Preparations
+
+The MMIO space has to be a whole 4K page in size and alignment to be
+mapped into userspace. This is very uncommon, so you'll most probably
+have to remap the MMIO space. The Linux kernel does that for you with
+the `pci=resource_alignment=<pci address>` kernel parameter (e.g.
+`pci=resource_alignment=0:1d.7` for ICH7).
+
+If your PCI device isn't listed in the kernel driver yet, you might want
+to add it to the `ehci_pci_ids` table in `linux/uio_ehci_pci.c` (or do
+some module alias magic if you know how to).
+
+### Build / Install
+
+Somehow like this:
+
+$ # Configure coreboot for your board and enable CONFIG_USBDEBUG
+$ make menuconfig
+$ cd util/uio_usbdebug/
+$ make -Clinux/
+$ sudo make -Clinux/ install
+$ make
+
+### Run
+
+$ # Unload Linux' EHCI driver (high-speed devices will stop working)
+$ sudo modprobe -r ehci-pci
+$ # Load the uio driver
+$ sudo modprobe uio-ehci-pci
+$ # Find your uio device
+$ ls /sys/module/uio_ehci_pci/drivers/*/*/uio/
+uio0
+$ # Run uio_usbdebug on this device
+$ sudo ./uio_usbdebug /dev/uio0
+
+Sadly, uio_usbdebug has to be run with root privileges since there are
+port-80 writes in the usbdebug driver.
diff --git a/util/uio_usbdebug/console/printk.c b/util/uio_usbdebug/console/printk.c
new file mode 100644
index 0000000..a73407c
--- /dev/null
+++ b/util/uio_usbdebug/console/printk.c
@@ -0,0 +1,34 @@
+/*
+ * This file is part of uio_usbdebug
+ *
+ * Copyright (C) 2013 Nico Huber <nico.h(a)gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <console/console.h>
+
+int do_printk(int msg_level, const char *const fmt, ...)
+{
+ va_list args;
+ int i;
+
+ va_start(args, fmt);
+ i = vfprintf(stderr, fmt, args);
+ va_end(args);
+
+ return i;
+}
diff --git a/util/uio_usbdebug/drivers/usb/pci_ehci.c b/util/uio_usbdebug/drivers/usb/pci_ehci.c
new file mode 100644
index 0000000..6a316a7
--- /dev/null
+++ b/util/uio_usbdebug/drivers/usb/pci_ehci.c
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2014 Nico Huber <nico.h(a)gmx.de>
+ *
+ * Code borrowed from pci_early.c:
+ * Copyright (C) 2011 Google Inc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
+ */
+
+#include <device/pci_ehci.h>
+
+static unsigned pci_find_next_capability(pci_devfn_t dev, unsigned cap, unsigned last)
+{
+ unsigned pos = 0;
+ u16 status;
+ unsigned reps = 48;
+
+ status = pci_read_config16(dev, PCI_STATUS);
+ if (!(status & PCI_STATUS_CAP_LIST))
+ return 0;
+
+ u8 hdr_type = pci_read_config8(dev, PCI_HEADER_TYPE);
+ switch (hdr_type & 0x7f) {
+ case PCI_HEADER_TYPE_NORMAL:
+ case PCI_HEADER_TYPE_BRIDGE:
+ pos = PCI_CAPABILITY_LIST;
+ break;
+ case PCI_HEADER_TYPE_CARDBUS:
+ pos = PCI_CB_CAPABILITY_LIST;
+ break;
+ default:
+ return 0;
+ }
+
+ pos = pci_read_config8(dev, pos);
+ while (reps-- && (pos >= 0x40)) { /* Loop through the linked list. */
+ unsigned this_cap;
+
+ pos &= ~3;
+ this_cap = pci_read_config8(dev, pos + PCI_CAP_LIST_ID);
+ if (this_cap == 0xff)
+ break;
+
+ if (!last && (this_cap == cap))
+ return pos;
+
+ if (last == pos)
+ last = 0;
+
+ pos = pci_read_config8(dev, pos + PCI_CAP_LIST_NEXT);
+ }
+ return 0;
+}
+
+static unsigned pci_find_capability(pci_devfn_t dev, unsigned cap)
+{
+ return pci_find_next_capability(dev, cap, 0);
+}
+
+extern void *ehci_bar;
+int ehci_debug_hw_enable(unsigned int *base, unsigned int *dbg_offset)
+{
+ pci_devfn_t dbg_dev = pci_ehci_dbg_dev(CONFIG_USBDEBUG_HCD_INDEX);
+ pci_ehci_dbg_enable(dbg_dev, CONFIG_EHCI_BAR);
+ pci_devfn_t dev = dbg_dev;
+
+ u8 pos = pci_find_capability(dev, PCI_CAP_ID_EHCI_DEBUG);
+ if (!pos)
+ return -1;
+
+ u32 cap = pci_read_config32(dev, pos);
+
+ /* FIXME: We should remove static EHCI_BAR_INDEX. */
+ u8 dbg_bar = 0x10 + 4 * ((cap >> 29) - 1);
+ if (dbg_bar != EHCI_BAR_INDEX)
+ return -1;
+
+ *base = (u32)ehci_bar;
+ *dbg_offset = (cap>>16) & 0x1ffc;
+ return 0;
+}
+
+void ehci_debug_select_port(unsigned int port)
+{
+ pci_devfn_t dbg_dev = pci_ehci_dbg_dev(CONFIG_USBDEBUG_HCD_INDEX);
+ pci_ehci_dbg_set_port(dbg_dev, port);
+}
diff --git a/util/uio_usbdebug/include/device/device.h b/util/uio_usbdebug/include/device/device.h
new file mode 100644
index 0000000..1838f4d
--- /dev/null
+++ b/util/uio_usbdebug/include/device/device.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2014 Nico Huber <nico.h(a)gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
+ */
+
+
+#ifndef _DEVICE_DEVICE_H
+#define _DEVICE_DEVICE_H
+
+#include <pci/pci.h>
+
+typedef struct pci_dev *pci_devfn_t;
+
+#define pci_read_config8 pci_read_byte
+#define pci_read_config16 pci_read_word
+#define pci_read_config32 pci_read_long
+
+#define PCI_CAP_ID_EHCI_DEBUG PCI_CAP_ID_DBG
+
+extern struct pci_access *pci_access;
+#define PCI_DEV(b, d, f) pci_get_dev(pci_access, 0, b, d, f)
+
+#endif
diff --git a/util/uio_usbdebug/lib/cbmem.c b/util/uio_usbdebug/lib/cbmem.c
new file mode 100644
index 0000000..6d87880
--- /dev/null
+++ b/util/uio_usbdebug/lib/cbmem.c
@@ -0,0 +1,8 @@
+
+#include <stdint.h>
+#include <stddef.h>
+
+void *cbmem_find(u32 id)
+{
+ return NULL;
+}
diff --git a/util/uio_usbdebug/linux/Makefile b/util/uio_usbdebug/linux/Makefile
new file mode 100644
index 0000000..fd60b4f
--- /dev/null
+++ b/util/uio_usbdebug/linux/Makefile
@@ -0,0 +1,13 @@
+
+obj-m := uio_ehci_pci.o
+
+all: uio_ehci_pci.c
+ @$(MAKE) -C/lib/modules/`uname -r`/build M=$(CURDIR) modules
+
+install:
+ @$(MAKE) -C/lib/modules/`uname -r`/build M=$(CURDIR) modules_install
+
+clean:
+ -@$(MAKE) -C/lib/modules/`uname -r`/build M=$(CURDIR) clean
+
+.PHONY: all install clean
diff --git a/util/uio_usbdebug/linux/uio_ehci_pci.c b/util/uio_usbdebug/linux/uio_ehci_pci.c
new file mode 100644
index 0000000..d5c33e3
--- /dev/null
+++ b/util/uio_usbdebug/linux/uio_ehci_pci.c
@@ -0,0 +1,106 @@
+/*
+ * uio_ehci_pci - UIO driver for PCI EHCI devices
+ *
+ * Copyright (C) 2013 Nico Huber <nico.h(a)gmx.de>
+ *
+ * This only implements MMIO access (no interrupts).
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
+ */
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/uio_driver.h>
+
+#define DRIVER_VERSION "0.0.1"
+#define DRIVER_AUTHOR "Nico Huber <nico.h(a)gmx.de>"
+#define DRIVER_DESC "UIO driver for PCI EHCI devices"
+#define DRIVER_TAG "uio_ehci_pci"
+
+static int probe(struct pci_dev *const pci_dev,
+ const struct pci_device_id *const did)
+{
+ struct uio_info *info;
+ int ret;
+
+ ret = pci_enable_device(pci_dev);
+ if (ret)
+ goto return_;
+
+ ret = pci_request_regions(pci_dev, DRIVER_TAG);
+ if (ret)
+ goto return_disable;
+
+ info = kzalloc(sizeof(struct uio_info), GFP_KERNEL);
+ if (!info) {
+ ret = -ENOMEM;
+ goto return_release;
+ }
+
+ info->name = DRIVER_TAG;
+ info->version = DRIVER_VERSION;
+
+ info->mem[0].name = "EHCI MMIO area";
+ info->mem[0].addr = pci_resource_start(pci_dev, 0);
+ if (!info->mem[0].addr) {
+ ret = -ENODEV;
+ goto return_free;
+ }
+ info->mem[0].size = pci_resource_len(pci_dev, 0);
+ info->mem[0].memtype = UIO_MEM_PHYS;
+
+ ret = uio_register_device(&pci_dev->dev, info);
+ if (ret)
+ goto return_free;
+ pci_set_drvdata(pci_dev, info);
+
+ return 0;
+return_free:
+ kfree(info);
+return_release:
+ pci_release_regions(pci_dev);
+return_disable:
+ pci_disable_device(pci_dev);
+return_:
+ return ret;
+}
+
+static void remove(struct pci_dev *const pci_dev)
+{
+ struct uio_info *const info = pci_get_drvdata(pci_dev);
+
+ uio_unregister_device(info);
+ kfree(info);
+ pci_release_regions(pci_dev);
+ pci_disable_device(pci_dev);
+}
+
+static DEFINE_PCI_DEVICE_TABLE(ehci_pci_ids) = {
+ { PCI_DEVICE(0x8086, 0x27cc) },
+ { 0, }
+};
+
+static struct pci_driver uio_ehci_pci_driver = {
+ .name = DRIVER_TAG,
+ .id_table = ehci_pci_ids,
+ .probe = probe,
+ .remove = remove,
+};
+
+module_pci_driver(uio_ehci_pci_driver);
+MODULE_VERSION(DRIVER_VERSION);
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/util/uio_usbdebug/uio_usbdebug.c b/util/uio_usbdebug/uio_usbdebug.c
new file mode 100644
index 0000000..e2836fc
--- /dev/null
+++ b/util/uio_usbdebug/uio_usbdebug.c
@@ -0,0 +1,67 @@
+/*
+ * uio_usbdebug - Run coreboot's usbdebug driver in userspace
+ *
+ * Copyright (C) 2013 Nico Huber <nico.h(a)gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <stdio.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/mman.h>
+
+#include <pci/pci.h>
+
+/* coreboot's arch/io.h conflicts with libc's sys/io.h, so declare this here: */
+int ioperm(unsigned long from, unsigned long num, int turn_on);
+
+#include <arch/io.h>
+#include <console/usb.h>
+
+void *ehci_bar;
+struct pci_access *pci_access;
+
+int main(int argc, char *argv[])
+{
+ if (argc != 2) {
+ fprintf(stderr, "Usage: %s <uio-dev>\n", argv[0]);
+ return 1;
+ }
+ const int fd = open(argv[1], O_RDWR);
+ if (fd < 0) {
+ perror("Failed to open uio device");
+ return 2;
+ }
+ ehci_bar =
+ mmap(NULL, 1 << 8, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+ if (MAP_FAILED == ehci_bar) {
+ perror("Failed to map ehci bar");
+ close(fd);
+ return 3;
+ }
+
+ ioperm(0x80, 1, 1);
+
+ pci_access = pci_alloc();
+ pci_init(pci_access);
+
+ usbdebug_init();
+
+ pci_cleanup(pci_access);
+ munmap(ehci_bar, 1 << 8);
+ close(fd);
+ return 0;
+}
diff --git a/util/uio_usbdebug/uio_usbdebug_intel.c b/util/uio_usbdebug/uio_usbdebug_intel.c
new file mode 100644
index 0000000..5e4d926
--- /dev/null
+++ b/util/uio_usbdebug/uio_usbdebug_intel.c
@@ -0,0 +1,67 @@
+/*
+ * This file is part of uio_usbdebug
+ *
+ * Copyright (C) 2013 Nico Huber <nico.h(a)gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <arch/io.h>
+#include <device/device.h>
+#include <device/pci_ehci.h>
+#include <console/usb.h>
+
+extern void *ehci_bar;
+
+pci_devfn_t pci_ehci_dbg_dev(unsigned hcd_idx)
+{
+ u32 class;
+ pci_devfn_t dev;
+
+#if CONFIG_HAVE_USBDEBUG_OPTIONS
+ if (hcd_idx==2)
+ dev = PCI_DEV(0, 0x1a, 0);
+ else
+ dev = PCI_DEV(0, 0x1d, 0);
+#else
+ dev = PCI_DEV(0, 0x1d, 7);
+#endif
+
+ class = pci_read_config32(dev, PCI_CLASS_REVISION) >> 8;
+#if CONFIG_HAVE_USBDEBUG_OPTIONS
+ if (class != PCI_EHCI_CLASSCODE) {
+ /* If we enter here before RCBA programming, EHCI function may
+ * appear with the highest function number instead.
+ */
+ dev |= PCI_DEV(0, 0, 7);
+ class = pci_read_config32(dev, PCI_CLASS_REVISION) >> 8;
+ }
+#endif
+ if (class != PCI_EHCI_CLASSCODE)
+ return 0;
+
+ return dev;
+}
+
+void pci_ehci_dbg_set_port(pci_devfn_t dev, unsigned int port)
+{
+ /* claim usb debug port */
+ const unsigned long dbgctl_addr =
+ ((unsigned long)ehci_bar) + CONFIG_EHCI_DEBUG_OFFSET;
+ write32(dbgctl_addr, read32(dbgctl_addr) | (1 << 30));
+}
+
+void pci_ehci_dbg_enable(pci_devfn_t dev, unsigned long base)
+{
+}