[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[RFC PATCH 2/3] drivers/char: search all buses for xhci



On (at least some) AMD systems, XHCI isn't on bus 0 (in my case, it was
bus 4). Search all of them.

Signed-off-by: Marek Marczykowski-Górecki <marmarek@xxxxxxxxxxxxxxxxxxxxxx>
---
 xen/drivers/char/xhci-dbc.c | 84 +++++++++++++++++++++++++++++---------
 1 file changed, 66 insertions(+), 18 deletions(-)

diff --git a/xen/drivers/char/xhci-dbc.c b/xen/drivers/char/xhci-dbc.c
index 60b781f87202..62b0ce88b6bf 100644
--- a/xen/drivers/char/xhci-dbc.c
+++ b/xen/drivers/char/xhci-dbc.c
@@ -286,39 +286,87 @@ static void *dbc_sys_map_xhc(uint64_t phys, size_t size)
     return fix_to_virt(FIX_XHCI_END);
 }
 
+static void xhci_bios_handoff(struct dbc *dbc)
+{
+    const uint32_t __iomem *xcap;
+    uint32_t xcap_val;
+    uint32_t next;
+    uint32_t id = 0;
+    const void __iomem *mmio = dbc->xhc_mmio;
+    const uint32_t __iomem *hccp1 = mmio + 0x10;
+    const uint32_t LEGACY_ID = 0x1;
+    int ttl = 48;
+    int timeout = 10000;
+
+    xcap = mmio;
+    /*
+     * This is initially an offset to the first capability. All the offsets
+     * (both in HCCP1 and then next capability pointer) are dword-based.
+     */
+    next = (readl(hccp1) & 0xFFFF0000) >> 16;
+
+    while ( id != LEGACY_ID && next && ttl-- )
+    {
+        xcap += next;
+        xcap_val = readl(xcap);
+        id = xcap_val & 0xFF;
+        next = (xcap_val & 0xFF00) >> 8;
+    }
+
+    if ( id != LEGACY_ID )
+        return;
+
+    xcap_val = readl(xcap);
+#define XHCI_HC_BIOS_OWNED (1U << 16)
+#define XHCI_HC_OS_OWNED (1U << 24)
+    if (xcap_val & XHCI_HC_BIOS_OWNED) {
+        dbc_error("bios owned\n");
+        writeb(1, (uint8_t*)xcap + 3);
+        while ((readl(xcap) & (XHCI_HC_BIOS_OWNED | XHCI_HC_OS_OWNED)) != 
XHCI_HC_OS_OWNED)
+        {
+            cpu_relax();
+            if (!--timeout)
+                break;
+        }
+        if (!timeout)
+            dbc_error("handoff timeout\n");
+        xcap_val = readl(xcap + 1);
+        xcap_val &= ((0x7 << 1) + (0xff << 5) + (0x7 << 17)); // 
XHCI_LEGACY_DISABLE_SMI
+        xcap_val |= (0x7 << 29); // XHCI_LEGACY_SMI_EVENTS
+        writel(xcap_val, xcap + 1);
+    }
+}
+
 static bool __init dbc_init_xhc(struct dbc *dbc)
 {
     uint32_t bar0;
     uint64_t bar1;
     uint64_t bar_val;
     uint64_t bar_size;
-    uint64_t devfn;
+    unsigned int bus, devfn;
     uint16_t cmd;
     size_t xhc_mmio_size;
 
     if ( dbc->sbdf.sbdf == 0 )
     {
-        /*
-         * Search PCI bus 0 for the xHC. All the host controllers supported so
-         * far are part of the chipset and are on bus 0.
-         */
-        for ( devfn = 0; devfn < 256; devfn++ )
-        {
-            pci_sbdf_t sbdf = PCI_SBDF(0, 0, devfn);
-            uint8_t hdr = pci_conf_read8(sbdf, PCI_HEADER_TYPE);
-
-            if ( hdr == 0 || hdr == 0x80 )
+        for ( bus = 0; bus < 0x100; bus++ )
+            for ( devfn = 0; devfn < 256; devfn++ )
             {
-                if ( (pci_conf_read32(sbdf, PCI_CLASS_REVISION) >> 8) ==
-                     DBC_XHC_CLASSC )
+                pci_sbdf_t sbdf = PCI_SBDF(0, bus, devfn);
+                uint8_t hdr = pci_conf_read8(sbdf, PCI_HEADER_TYPE);
+
+                if ( hdr == 0 || hdr == 0x80 )
                 {
-                    if ( dbc->xhc_num-- )
-                        continue;
-                    dbc->sbdf = sbdf;
-                    break;
+                    if ( (pci_conf_read32(sbdf, PCI_CLASS_REVISION) >> 8) ==
+                         DBC_XHC_CLASSC )
+                    {
+                        if ( dbc->xhc_num-- )
+                            continue;
+                        dbc->sbdf = sbdf;
+                        break;
+                    }
                 }
             }
-        }
     }
     else
     {
-- 
git-series 0.9.1



 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.