summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDuncan Laurie <dlaurie@google.com>2020-03-18 12:19:14 -0700
committerPatrick Georgi <pgeorgi@google.com>2020-05-01 06:11:42 +0000
commit7724f1142ee5c71c3df6c3a45af6d9da3f0798b5 (patch)
treea4e3731573b8d90ab4bf6a91c352b3406af79f90
parent2d7173d462c66cbbca6a5354c1ac719941e117d9 (diff)
lp/drivers/usb: Add quirk for QEMU XHCI root hub
The QEMU XHCI driver does not implement the Port Change Detect bit in the USBSTS register. As a result no devices are attached without looking at each port individually. Detect this as a quirk based on the QEMU XHCI controller PCI ID, and apply it to the root hub quirk list so it can get used by the generic hub driver to skip this check. With this change an attached USB mass storage device is detected and able to boot when supplied to qemu: -drive if=none,id=usbmsc,format=raw,file=/tmp/disk.img -device qemu-xhci,id-xhci -device usb-storage,bus=xhci.0,drive=usbmsc Change-Id: I6689cb1dbb24c93d45f5c5ef040b713925d07588 Signed-off-by: Duncan Laurie <dlaurie@google.com> Reviewed-on: https://review.coreboot.org/c/coreboot/+/39839 Reviewed-by: Angel Pons <th3fanbus@gmail.com> Reviewed-by: Nico Huber <nico.h@gmx.de> Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
-rw-r--r--payloads/libpayload/drivers/usb/generic_hub.c6
-rw-r--r--payloads/libpayload/drivers/usb/quirks.c24
-rw-r--r--payloads/libpayload/drivers/usb/xhci.c4
-rw-r--r--payloads/libpayload/include/usb/usb.h2
4 files changed, 34 insertions, 2 deletions
diff --git a/payloads/libpayload/drivers/usb/generic_hub.c b/payloads/libpayload/drivers/usb/generic_hub.c
index 9d444ee792..7263400840 100644
--- a/payloads/libpayload/drivers/usb/generic_hub.c
+++ b/payloads/libpayload/drivers/usb/generic_hub.c
@@ -218,9 +218,11 @@ generic_hub_poll(usbdev_t *const dev)
if (!hub)
return;
- if (hub->ops->hub_status_changed &&
- hub->ops->hub_status_changed(dev) != 1)
+ if (!(dev->quirks & USB_QUIRK_HUB_NO_USBSTS_PCD) &&
+ hub->ops->hub_status_changed &&
+ hub->ops->hub_status_changed(dev) != 1) {
return;
+ }
int port;
for (port = 1; port <= hub->num_ports; ++port) {
diff --git a/payloads/libpayload/drivers/usb/quirks.c b/payloads/libpayload/drivers/usb/quirks.c
index 0a3514933c..d5be0e6cda 100644
--- a/payloads/libpayload/drivers/usb/quirks.c
+++ b/payloads/libpayload/drivers/usb/quirks.c
@@ -59,6 +59,30 @@ usb_quirks_t usb_quirks[] = {
*/
};
+#if CONFIG(LP_USB_PCI)
+usb_quirks_t pci_quirks[] = {
+ /* QEMU XHCI root hub does not implement port change detect */
+ { 0x1b36, 0x000d, USB_QUIRK_HUB_NO_USBSTS_PCD, 0 },
+};
+
+u32 pci_quirk_check(pcidev_t controller)
+{
+ int i;
+ u16 vendor = pci_read_config16(controller, REG_VENDOR_ID);
+ u16 device = pci_read_config16(controller, REG_DEVICE_ID);
+
+ for (i = 0; i < ARRAY_SIZE(pci_quirks); i++) {
+ if ((pci_quirks[i].vendor == vendor) &&
+ (pci_quirks[i].device == device)) {
+ printf("PCI quirks enabled: %08x\n", pci_quirks[i].quirks);
+ return pci_quirks[i].quirks;
+ }
+ }
+
+ return USB_QUIRK_NONE;
+}
+#endif
+
u32 usb_quirk_check(u16 vendor, u16 device)
{
int i;
diff --git a/payloads/libpayload/drivers/usb/xhci.c b/payloads/libpayload/drivers/usb/xhci.c
index ef1d73ff68..21af579f4c 100644
--- a/payloads/libpayload/drivers/usb/xhci.c
+++ b/payloads/libpayload/drivers/usb/xhci.c
@@ -314,9 +314,13 @@ xhci_pci_init (pcidev_t addr)
controller = xhci_init((unsigned long)reg_addr);
if (controller) {
+ xhci_t *xhci = controller->instance;
controller->pcidev = addr;
xhci_switch_ppt_ports(addr);
+
+ /* Set up any quirks for controller root hub */
+ xhci->roothub->quirks = pci_quirk_check(addr);
}
return controller;
diff --git a/payloads/libpayload/include/usb/usb.h b/payloads/libpayload/include/usb/usb.h
index 5d27f7cbc6..328e8839fc 100644
--- a/payloads/libpayload/include/usb/usb.h
+++ b/payloads/libpayload/include/usb/usb.h
@@ -318,6 +318,7 @@ void usb_detach_device(hci_t *controller, int devno);
int usb_attach_device(hci_t *controller, int hubaddress, int port,
usb_speed speed);
+u32 pci_quirk_check(pcidev_t controller);
u32 usb_quirk_check(u16 vendor, u16 device);
int usb_interface_check(u16 vendor, u16 device);
@@ -330,6 +331,7 @@ int usb_interface_check(u16 vendor, u16 device);
#define USB_QUIRK_MSC_FORCE_TRANS_CBI_I (1 << 6)
#define USB_QUIRK_MSC_NO_TEST_UNIT_READY (1 << 7)
#define USB_QUIRK_MSC_SHORT_INQUIRY (1 << 8)
+#define USB_QUIRK_HUB_NO_USBSTS_PCD (1 << 9)
#define USB_QUIRK_TEST (1 << 31)
#define USB_QUIRK_NONE 0