usb_drv: XHCI support for x86-architectures

USB 3.0 support on x86 (64/32) platforms, as well as pci support for XHCI
controllers.

Issue #1084
This commit is contained in:
Sebastian Sumpf 2014-02-14 13:36:21 +01:00 committed by Norman Feske
parent f02e9001e8
commit 5f0843082a
17 changed files with 219 additions and 53 deletions

View File

@ -123,6 +123,7 @@ linux-3.9/drivers/usb/host/xhci-ext-caps.h
linux-3.9/drivers/usb/host/xhci.h
linux-3.9/drivers/usb/host/xhci-hub.c
linux-3.9/drivers/usb/host/xhci-mem.c
linux-3.9/drivers/usb/host/xhci-pci.c
linux-3.9/drivers/usb/host/xhci-plat.c
linux-3.9/drivers/usb/host/xhci-ring.c
linux-3.9/drivers/usb/storage/alauda.c

View File

@ -1,5 +1,6 @@
SRC_C += usbnet.c asix_devices.c asix_common.c ax88172a.c ax88179_178a.c
include $(REP_DIR)/lib/mk/xhci.inc
include $(REP_DIR)/lib/mk/usb.inc
include $(REP_DIR)/lib/mk/arm/usb.inc
@ -12,7 +13,7 @@ SRC_CC += platform.cc
SRC_C += dwc3-exynos.c host.c core.c
#XHCI
SRC_C += xhci-dbg.c xhci-hub.c xhci-mem.c xhci-plat.c xhci-ring.c xhci.c
SRC_C += xhci-plat.c
vpath platform.cc $(LIB_DIR)/arm/platform_arndale
vpath %.c $(CONTRIB_DIR)/drivers/usb/dwc3

View File

@ -0,0 +1,21 @@
SRC_C += $(addprefix usb/host/,pci-quirks.c uhci-hcd.c ehci-pci.c)
#
# USB netwpork support
#
SRC_C += usbnet.c ax88179_178a.c
#XHCI
SRC_C += xhci-pci.c
SRC_CC += pci_driver.cc platform.cc
include $(REP_DIR)/lib/mk/xhci.inc
include $(REP_DIR)/lib/mk/usb.inc
CC_OPT += -DCONFIG_PCI -DCONFIG_USB_EHCI_PCI=1 -DCONFIG_USB_XHCI_HCD=1
vpath platform.cc $(LIB_DIR)/x86
vpath %.c $(CONTRIB_DIR)/drivers/net/usb
# vi:set ft=make :

View File

@ -1,9 +1,4 @@
SRC_C += $(addprefix usb/host/,pci-quirks.c uhci-hcd.c ehci-pci.c)
include $(REP_DIR)/lib/mk/usb.inc
CC_OPT += -DCONFIG_PCI -DCONFIG_USB_EHCI_PCI=1 -DCONFIG_USB_XHCI_HCD=0
INC_DIR += $(LIB_INC_DIR)/x86_32 $(LIB_INC_DIR)/x86
SRC_CC += pci_driver.cc platform.cc
vpath platform.cc $(LIB_DIR)/x86
include $(REP_DIR)/lib/mk/usb_x86.inc

View File

@ -1,9 +1,3 @@
SRC_C += $(addprefix usb/host/,pci-quirks.c uhci-hcd.c ehci-pci.c)
include $(REP_DIR)/lib/mk/usb.inc
CC_OPT += -DCONFIG_PCI -DCONFIG_USB_EHCI_PCI=1 -DCONFIG_USB_XHCI_HCD=0
INC_DIR += $(LIB_INC_DIR)/x86_64 $(LIB_INC_DIR)/x86
SRC_CC += pci_driver.cc platform.cc
vpath platform.cc $(LIB_DIR)/x86
include $(REP_DIR)/lib/mk/usb_x86.inc

View File

@ -0,0 +1,6 @@
#
# Generic XHCI files
#
SRC_C += xhci-dbg.c xhci-hub.c xhci-mem.c xhci-ring.c xhci.c
# vi:set ft=make :

View File

@ -1,20 +0,0 @@
diff -r 6978f825431c drivers/usb/host/xhci-plat.c
--- a/drivers/usb/host/xhci-plat.c Thu May 16 15:54:34 2013 +0200
+++ b/drivers/usb/host/xhci-plat.c Thu May 16 16:41:46 2013 +0200
@@ -25,6 +25,16 @@
* dev struct in order to setup MSI
*/
xhci->quirks |= XHCI_BROKEN_MSI;
+
+#ifdef DWC3_QUIRK
+ /*
+ * DWC3 controller
+ * One will see 'dev_error: ERROR Transfer event TRB DMA ptr not part of
+ * current TD' and last message was short (ep_ring->last_td_was_short, in
+ * xhci-ring.c
+ */
+ xhci->quirks |= XHCI_SPURIOUS_SUCCESS;
+#endif
}
/* called during probe() after chip reset completes */

View File

@ -0,0 +1,43 @@
diff -r a103aef8f269 drivers/usb/host/.xhci-pci.c.swp
Binary file drivers/usb/host/.xhci-pci.c.swp has changed
diff -r a103aef8f269 drivers/usb/host/xhci-pci.c
--- a/drivers/usb/host/xhci-pci.c Wed Mar 05 13:54:43 2014 +0100
+++ b/drivers/usb/host/xhci-pci.c Wed Mar 05 13:58:50 2014 +0100
@@ -34,6 +34,8 @@
#define PCI_VENDOR_ID_ETRON 0x1b6f
#define PCI_DEVICE_ID_ASROCK_P67 0x7023
+#define PCI_VENDOR_ID_RENESAS 0x1912
+
static const char hcd_name[] = "xhci_hcd";
/* called after powerup, by probe or system-pm "wakeup" */
@@ -81,6 +83,10 @@
if (pdev->vendor == PCI_VENDOR_ID_NEC)
xhci->quirks |= XHCI_NEC_HOST;
+ /* Quirk for RENESAS USB 3.0 express cards */
+ if (pdev->vendor == PCI_VENDOR_ID_RENESAS)
+ xhci->quirks |= XHCI_TRUST_TX_LENGTH;
+
if (pdev->vendor == PCI_VENDOR_ID_AMD && xhci->hci_version == 0x96)
xhci->quirks |= XHCI_AMD_0x96_HOST;
diff -r a103aef8f269 drivers/usb/host/xhci.c
--- a/drivers/usb/host/xhci.c Wed Mar 05 13:54:43 2014 +0100
+++ b/drivers/usb/host/xhci.c Wed Mar 05 13:58:50 2014 +0100
@@ -4683,6 +4683,14 @@
get_quirks(dev, xhci);
+
+ /* In xhci controllers which follow xhci 1.0 spec gives a spurious
+ * success event after a short transfer. This quirk will ignore such
+ * spurious event (This is taken from Linux 3.13)
+ */
+ if (xhci->hci_version > 0x96)
+ xhci->quirks |= XHCI_SPURIOUS_SUCCESS;
+
/* Make sure the HC is halted. */
retval = xhci_halt(xhci);
if (retval)

View File

@ -0,0 +1,66 @@
#
# Build
#
set build_components {
core init
drivers/timer
drivers/usb
test/input
}
build $build_components
create_boot_directory
#
# Generate config
#
append config {
<config>
<parent-provides>
<service name="ROM"/>
<service name="RAM"/>
<service name="IRQ"/>
<service name="IO_MEM"/>
<service name="IO_PORT"/>
<service name="CAP"/>
<service name="PD"/>
<service name="RM"/>
<service name="CPU"/>
<service name="LOG"/>
<service name="SIGNAL" />
</parent-provides>
<default-route>
<any-service> <parent/> <any-child/> </any-service>
</default-route>
<start name="timer">
<resource name="RAM" quantum="1M"/>
<provides><service name="Timer"/></provides>
</start>
<start name="usb_drv">
<resource name="RAM" quantum="12M"/>
<provides><service name="Input"/></provides>
<config>
<hid/>
</config>
</start>
<start name="test-input">
<resource name="RAM" quantum="1M"/>
</start>
</config>}
install_config $config
#
# Boot modules
#
# generic modules
set boot_modules {
core init timer usb_drv test-input
}
build_boot_image $boot_modules

View File

@ -11,7 +11,7 @@
# Build
#
build {
set build_components {
core init
drivers/pci drivers/timer drivers/usb
test/lwip/http_srv
@ -22,6 +22,7 @@ lappend_if [have_spec pci] build_components drivers/pci/device_pd
lappend_if [have_spec platform_arndale] build_components drivers/platform
lappend_if [have_spec gpio] build_components drivers/gpio
build $build_components
create_boot_directory
@ -56,7 +57,7 @@ set config {
<provides>
<service name="Nic"/>
</provides>
<config ehci="yes">
<config uhci="no" ehci="yes" xhci="yes">
<nic mac="2e:60:90:0c:4e:01" />
</config>
</start>
@ -66,7 +67,7 @@ set config {
append_if [have_spec acpi] config {
<start name="acpi">
<resource name="RAM" quantum="5M"/>
<resource name="RAM" quantum="10M"/>
<binary name="acpi_drv"/>
<provides>
<service name="PCI"/>
@ -122,5 +123,7 @@ lappend_if [have_spec gpio] boot_modules gpio_drv
build_boot_image $boot_modules
append qemu_args " -m 256 -nographic"
run_genode_until forever
# vi: set ft=tcl :

View File

@ -611,6 +611,7 @@ bool in_interrupt(void) { TRACE; return 1; }
/*****************
** linux/pci.h **
*****************/
int pci_bus_read_config_dword(struct pci_bus *bus, unsigned int devfn, int where, u32 *val) { TRACE; return 0; }
int pci_bus_write_config_dword(struct pci_bus *bus, unsigned int devfn, int where, u32 val) { TRACE; return 0; }
@ -633,6 +634,12 @@ const struct pci_device_id *pci_match_id(const struct pci_device_id *ids,
struct pci_dev *dev) { TRACE; return 0; }
void *pci_ioremap_bar(struct pci_dev *pdev, int bar);
int pci_enable_msi(struct pci_dev *pdev) { TRACE; return -1; }
void pci_disable_msi(struct pci_dev *pdev) { TRACE; }
int pci_enable_msix(struct pci_dev *pdev, struct msix_entry *entries, int vec) { TRACE; return -1; }
void pci_disable_msix(struct pci_dev *pdev) { TRACE; }
/**
* Omitted PCI functions
*/

View File

@ -645,6 +645,13 @@ int scnprintf(char *buf, size_t size, const char *fmt, ...);
struct completion;
void complete_and_exit(struct completion *, long);
/*********************
** linux/cpumask.h **
*********************/
static inline unsigned num_online_cpus(void) { return 1U; }
/******************
** linux/log2.h **
******************/
@ -1045,11 +1052,13 @@ typedef void (*work_func_t)(struct work_struct *work);
struct work_struct {
work_func_t func;
struct list_head entry;
unsigned pending;
};
struct delayed_work {
struct timer_list timer;
struct work_struct work;
unsigned pending;
};
bool cancel_work_sync(struct work_struct *work);
@ -1062,10 +1071,17 @@ bool flush_work_sync(struct work_struct *work);
#define PREPARE_WORK(_work, _func) \
do { (_work)->func = (_func); } while (0)
do { \
(_work)->func = (_func); \
(_work)->pending = 0; \
} while (0)
#define PREPARE_DELAYED_WORK(_work, _func) \
PREPARE_WORK(&(_work)->work, (_func))
do { \
PREPARE_WORK(&(_work)->work, (_func)); \
(_work)->pending = 0; \
} while (0)
#define __INIT_WORK(_work, _func, on_stack) \
do { \
@ -1080,6 +1096,7 @@ bool flush_work_sync(struct work_struct *work);
do { \
INIT_WORK(&(_work)->work, (_func)); \
init_timer(&(_work)->timer); \
(_work)->pending = 0; \
} while (0)
@ -2201,12 +2218,9 @@ bool in_interrupt(void);
/*
* Definitions normally found in pci_regs.h
*/
//enum { PCI_BASE_ADDRESS_MEM_MASK = ~0x0fUL };
//enum { PCI_CAP_ID_AGP = 0x02 };
extern struct bus_type pci_bus_type;
enum { PCI_ANY_ID = ~0U };
enum { DEVICE_COUNT_RESOURCE = 6 };
//enum { PCIBIOS_MIN_MEM = 0UL };
#define PCI_DEVICE_CLASS(dev_class,dev_class_mask) \
.class = (dev_class), .class_mask = (dev_class_mask), \
@ -2232,6 +2246,21 @@ typedef enum { PCI_D0 = 0 } pci_power_t;
#define class device_class
#endif /* __cplusplus */
struct msix_entry
{
u32 vector;
u16 entry;
};
struct pci_dev;
int pci_enable_msi(struct pci_dev *);
void pci_disable_msi(struct pci_dev *);
int pci_enable_msix(struct pci_dev *, struct msix_entry *, int);
void pci_disable_msix(struct pci_dev *);
#include <linux/mod_devicetable.h>
/*
@ -2769,6 +2798,8 @@ int scsi_normalize_sense(const u8 *sense_buffer, int sb_len,
const u8 * scsi_sense_desc_find(const u8 * sense_buffer, int sb_len,
int desc_type);
int scsi_sense_valid(struct scsi_sense_hdr *);
int scsi_sense_is_deferred(struct scsi_sense_hdr *);
/*********************
** scsi/scsi_tcq.h **
@ -3429,6 +3460,7 @@ struct tasklet_struct
{
void (*func)(unsigned long);
unsigned long data;
unsigned pending;
};
void tasklet_schedule(struct tasklet_struct *t);

View File

@ -34,7 +34,7 @@ class Routine : public Genode::List<Routine>::Element
{
private:
enum { STACK_SIZE = 0x2000 };
enum { STACK_SIZE = 4 * 1024 * sizeof(long) };
bool _started; /* true if already started */
jmp_buf _env; /* state */
int (*_func)(void *); /* function to call*/

View File

@ -914,7 +914,7 @@ int fls(int x)
for (int i = 31; i >= 0; i--)
if (x & (1 << i))
return i;
return i + 1;
return 0;
}

View File

@ -77,6 +77,10 @@ class Work : public Genode::List<Work>::Element
template <typename WORK>
static void schedule(WORK *work)
{
if (work->pending)
return;
work->pending = 1;
_list()->insert(new (Genode::env()->heap()) Work(work));
}
@ -92,6 +96,7 @@ class Work : public Genode::List<Work>::Element
{
work_struct *work = static_cast<work_struct *>(w->_work);
work->func(work);
work->pending = 0;
}
break;
@ -99,6 +104,7 @@ class Work : public Genode::List<Work>::Element
{
delayed_work *work = static_cast<delayed_work *>(w->_work);
work->work.func(&(work)->work);
work->pending = 0;
}
break;
@ -106,6 +112,7 @@ class Work : public Genode::List<Work>::Element
{
tasklet_struct *tasklet = static_cast<tasklet_struct *>(w->_work);
tasklet->func(tasklet->data);
tasklet->pending = 0;
}
break;
}
@ -269,8 +276,9 @@ bool queue_delayed_work(struct workqueue_struct *wq,
void tasklet_init(struct tasklet_struct *t, void (*f)(unsigned long), unsigned long d)
{
t->func = f;
t->data = d;
t->func = f;
t->data = d;
t->pending = 0;
}

View File

@ -120,13 +120,11 @@ class Irq_context : public Genode::List<Irq_context>::Element
bool handled = false;
/* report IRQ to all clients */
for (Irq_handler *h = _handler_list.first(); h; h = h->next()) {
if ((handled = _handle_one(h)))
for (Irq_handler *h = _handler_list.first(); h; h = h->next())
if ((handled = _handle_one(h))) {
dde_kit_log(DEBUG_IRQ, "IRQ: %u ret: %u h: %p dev: %p", _irq, handled, h->handler, h->dev);
break;
dde_kit_log(DEBUG_IRQ, "IRQ: %u ret: %u h: %p dev: %p", _irq, handled, h->handler, h->dev);
}
}
/* interrupt should be acked at device now */
_irq_sync.unlock();

View File

@ -15,12 +15,23 @@
#include <platform/platform.h>
extern "C" void module_ax88179_178a_driver_init();
extern "C" void module_usbnet_init();
extern "C" void module_ehci_hcd_init();
extern "C" void module_ehci_pci_init();
extern "C" void module_uhci_hcd_init();
extern "C" void module_xhci_hcd_init();
void platform_hcd_init(Services *s)
{
if (s->nic) {
module_usbnet_init();
module_ax88179_178a_driver_init();
}
if (s->xhci)
module_xhci_hcd_init();
/* ehci_hcd should always be loaded before uhci_hcd and ohci_hcd, not after */
if (s->ehci) {
module_ehci_hcd_init();