From 5f0843082ab655960aefb14889d032c70a9aef80 Mon Sep 17 00:00:00 2001 From: Sebastian Sumpf Date: Fri, 14 Feb 2014 13:36:21 +0100 Subject: [PATCH] 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 --- dde_linux/files.list | 1 + dde_linux/lib/mk/platform_arndale/usb.mk | 3 +- dde_linux/lib/mk/usb_x86.inc | 21 ++++++++ dde_linux/lib/mk/x86_32/usb.mk | 9 +--- dde_linux/lib/mk/x86_64/usb.mk | 8 +-- dde_linux/lib/mk/xhci.inc | 6 +++ dde_linux/patches/dw3_quirk.patch | 20 ------- dde_linux/patches/xhci-quirks.patch | 43 +++++++++++++++ dde_linux/run/usb_hid_panda.run | 66 ++++++++++++++++++++++++ dde_linux/run/usb_net.run | 9 ++-- dde_linux/src/lib/usb/dummies.c | 7 +++ dde_linux/src/lib/usb/include/lx_emul.h | 42 +++++++++++++-- dde_linux/src/lib/usb/include/routine.h | 2 +- dde_linux/src/lib/usb/lx_emul.cc | 2 +- dde_linux/src/lib/usb/signal/event.cc | 12 ++++- dde_linux/src/lib/usb/signal/irq.cc | 10 ++-- dde_linux/src/lib/usb/x86/platform.cc | 11 ++++ 17 files changed, 219 insertions(+), 53 deletions(-) create mode 100644 dde_linux/lib/mk/usb_x86.inc create mode 100644 dde_linux/lib/mk/xhci.inc delete mode 100644 dde_linux/patches/dw3_quirk.patch create mode 100644 dde_linux/patches/xhci-quirks.patch create mode 100644 dde_linux/run/usb_hid_panda.run diff --git a/dde_linux/files.list b/dde_linux/files.list index a600543a6..4c1ab1f6b 100644 --- a/dde_linux/files.list +++ b/dde_linux/files.list @@ -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 diff --git a/dde_linux/lib/mk/platform_arndale/usb.mk b/dde_linux/lib/mk/platform_arndale/usb.mk index 7694265d0..97e56e1ef 100644 --- a/dde_linux/lib/mk/platform_arndale/usb.mk +++ b/dde_linux/lib/mk/platform_arndale/usb.mk @@ -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 diff --git a/dde_linux/lib/mk/usb_x86.inc b/dde_linux/lib/mk/usb_x86.inc new file mode 100644 index 000000000..522f0ae3b --- /dev/null +++ b/dde_linux/lib/mk/usb_x86.inc @@ -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 : diff --git a/dde_linux/lib/mk/x86_32/usb.mk b/dde_linux/lib/mk/x86_32/usb.mk index b87eaca3d..8f7568c5e 100644 --- a/dde_linux/lib/mk/x86_32/usb.mk +++ b/dde_linux/lib/mk/x86_32/usb.mk @@ -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 + diff --git a/dde_linux/lib/mk/x86_64/usb.mk b/dde_linux/lib/mk/x86_64/usb.mk index 25cb21fc2..c49ca7eeb 100644 --- a/dde_linux/lib/mk/x86_64/usb.mk +++ b/dde_linux/lib/mk/x86_64/usb.mk @@ -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 diff --git a/dde_linux/lib/mk/xhci.inc b/dde_linux/lib/mk/xhci.inc new file mode 100644 index 000000000..8a2a95ac2 --- /dev/null +++ b/dde_linux/lib/mk/xhci.inc @@ -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 : diff --git a/dde_linux/patches/dw3_quirk.patch b/dde_linux/patches/dw3_quirk.patch deleted file mode 100644 index d08aa5d28..000000000 --- a/dde_linux/patches/dw3_quirk.patch +++ /dev/null @@ -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 */ diff --git a/dde_linux/patches/xhci-quirks.patch b/dde_linux/patches/xhci-quirks.patch new file mode 100644 index 000000000..96f52ea3b --- /dev/null +++ b/dde_linux/patches/xhci-quirks.patch @@ -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) diff --git a/dde_linux/run/usb_hid_panda.run b/dde_linux/run/usb_hid_panda.run new file mode 100644 index 000000000..85a3310d3 --- /dev/null +++ b/dde_linux/run/usb_hid_panda.run @@ -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 { + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +} + +install_config $config + +# +# Boot modules +# + +# generic modules +set boot_modules { + core init timer usb_drv test-input +} + +build_boot_image $boot_modules + diff --git a/dde_linux/run/usb_net.run b/dde_linux/run/usb_net.run index 2c2a4016a..0b3695089 100644 --- a/dde_linux/run/usb_net.run +++ b/dde_linux/run/usb_net.run @@ -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 { - + @@ -66,7 +67,7 @@ set config { append_if [have_spec acpi] config { - + @@ -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 : diff --git a/dde_linux/src/lib/usb/dummies.c b/dde_linux/src/lib/usb/dummies.c index 9ab528092..9ad080020 100644 --- a/dde_linux/src/lib/usb/dummies.c +++ b/dde_linux/src/lib/usb/dummies.c @@ -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 */ diff --git a/dde_linux/src/lib/usb/include/lx_emul.h b/dde_linux/src/lib/usb/include/lx_emul.h index 2b8cc6bdf..5bc0f53c9 100644 --- a/dde_linux/src/lib/usb/include/lx_emul.h +++ b/dde_linux/src/lib/usb/include/lx_emul.h @@ -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 /* @@ -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); diff --git a/dde_linux/src/lib/usb/include/routine.h b/dde_linux/src/lib/usb/include/routine.h index bd566d67d..ea3558d2f 100644 --- a/dde_linux/src/lib/usb/include/routine.h +++ b/dde_linux/src/lib/usb/include/routine.h @@ -34,7 +34,7 @@ class Routine : public Genode::List::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*/ diff --git a/dde_linux/src/lib/usb/lx_emul.cc b/dde_linux/src/lib/usb/lx_emul.cc index f1f1659da..811bbd503 100644 --- a/dde_linux/src/lib/usb/lx_emul.cc +++ b/dde_linux/src/lib/usb/lx_emul.cc @@ -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; } diff --git a/dde_linux/src/lib/usb/signal/event.cc b/dde_linux/src/lib/usb/signal/event.cc index fe563e9ba..80a46a4d6 100644 --- a/dde_linux/src/lib/usb/signal/event.cc +++ b/dde_linux/src/lib/usb/signal/event.cc @@ -77,6 +77,10 @@ class Work : public Genode::List::Element template 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::Element { work_struct *work = static_cast(w->_work); work->func(work); + work->pending = 0; } break; @@ -99,6 +104,7 @@ class Work : public Genode::List::Element { delayed_work *work = static_cast(w->_work); work->work.func(&(work)->work); + work->pending = 0; } break; @@ -106,6 +112,7 @@ class Work : public Genode::List::Element { tasklet_struct *tasklet = static_cast(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; } diff --git a/dde_linux/src/lib/usb/signal/irq.cc b/dde_linux/src/lib/usb/signal/irq.cc index de4c9243a..02e8fbc5a 100644 --- a/dde_linux/src/lib/usb/signal/irq.cc +++ b/dde_linux/src/lib/usb/signal/irq.cc @@ -120,13 +120,11 @@ class Irq_context : public Genode::List::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(); diff --git a/dde_linux/src/lib/usb/x86/platform.cc b/dde_linux/src/lib/usb/x86/platform.cc index 3e28b11d7..c2cce95f3 100644 --- a/dde_linux/src/lib/usb/x86/platform.cc +++ b/dde_linux/src/lib/usb/x86/platform.cc @@ -15,12 +15,23 @@ #include +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();