]> xenbits.xensource.com Git - seabios.git/commitdiff
usb: Replace EHCI to UHCI/OHCI synchronization with new scheme.
authorKevin O'Connor <kevin@koconnor.net>
Thu, 5 Dec 2013 23:43:20 +0000 (18:43 -0500)
committerKevin O'Connor <kevin@koconnor.net>
Fri, 27 Dec 2013 17:42:12 +0000 (12:42 -0500)
The previous code attempts to correlate which UHCI and OHCI
controllers correlate with which EHCI controllers so that it can
ensure high speed devices are handled by the EHCI code while low/full
speed devices are handled by the UHCI/OHCI code.  Replace this logic
by initializing all EHCI controllers first, and then initializing all
UHCI and OHCI controllers.  This simplifies the code and improves
support for some hardware devices that don't follow the OHCI/UHCI to
EHCI correlation standard.

Also, remove the unused usb->busid field.

Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
src/hw/usb-ehci.c
src/hw/usb-ehci.h
src/hw/usb-ohci.c
src/hw/usb-ohci.h
src/hw/usb-uhci.c
src/hw/usb-uhci.h
src/hw/usb-xhci.c
src/hw/usb-xhci.h
src/hw/usb.c
src/hw/usb.h

index b495d6cd622a25b1da2a128f17690bad407727ab..10c92feef5e919e0c6b850bd0f4081ccb6100c97 100644 (file)
@@ -1,6 +1,6 @@
 // Code for handling EHCI USB controllers.
 //
-// Copyright (C) 2010  Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2010-2013  Kevin O'Connor <kevin@koconnor.net>
 //
 // This file may be distributed under the terms of the GNU LGPLv3 license.
 
@@ -14,8 +14,6 @@
 #include "string.h" // memset
 #include "usb.h" // struct usb_s
 #include "usb-ehci.h" // struct ehci_qh
-#include "usb-ohci.h" // ohci_setup
-#include "usb-uhci.h" // uhci_setup
 #include "util.h" // msleep
 #include "x86.h" // readl
 
@@ -24,9 +22,7 @@ struct usb_ehci_s {
     struct ehci_caps *caps;
     struct ehci_regs *regs;
     struct ehci_qh *async_qh;
-    struct pci_device *companion[8];
     int checkports;
-    int legacycount;
 };
 
 struct ehci_pipe {
@@ -36,6 +32,8 @@ struct ehci_pipe {
     struct usb_pipe pipe;
 };
 
+static int PendingEHCIPorts;
+
 
 /****************************************************************
  * Root hub
@@ -44,33 +42,6 @@ struct ehci_pipe {
 #define EHCI_TIME_POSTPOWER 20
 #define EHCI_TIME_POSTRESET 2
 
-// Check if need companion controllers for full/low speed devices
-static void
-ehci_note_port(struct usb_ehci_s *cntl)
-{
-    if (--cntl->checkports)
-        // Ports still being detected.
-        return;
-    if (! cntl->legacycount)
-        // No full/low speed devices found.
-        return;
-    // Start companion controllers.
-    int i;
-    for (i=0; i<ARRAY_SIZE(cntl->companion); i++) {
-        struct pci_device *pci = cntl->companion[i];
-        if (!pci)
-            break;
-
-        // ohci/uhci_setup call pci_config_X - don't run from irq handler.
-        wait_preempt();
-
-        if (pci_classprog(pci) == PCI_CLASS_SERIAL_USB_UHCI)
-            uhci_setup(pci, cntl->usb.busid + i);
-        else if (pci_classprog(pci) == PCI_CLASS_SERIAL_USB_OHCI)
-            ohci_setup(pci, cntl->usb.busid + i);
-    }
-}
-
 // Check if device attached to port
 static int
 ehci_hub_detect(struct usbhub_s *hub, u32 port)
@@ -97,7 +68,6 @@ ehci_hub_detect(struct usbhub_s *hub, u32 port)
 
     if ((portsc & PORT_LINESTATUS_MASK) == PORT_LINESTATUS_KSTATE) {
         // low speed device
-        cntl->legacycount++;
         writel(portreg, portsc | PORT_OWNER);
         goto doneearly;
     }
@@ -111,7 +81,7 @@ ehci_hub_detect(struct usbhub_s *hub, u32 port)
     return 0;
 
 doneearly:
-    ehci_note_port(cntl);
+    PendingEHCIPorts--;
     return -1;
 }
 
@@ -135,14 +105,13 @@ ehci_hub_reset(struct usbhub_s *hub, u32 port)
         goto resetfail;
     if (!(portsc & PORT_PE)) {
         // full speed device
-        cntl->legacycount++;
         writel(portreg, portsc | PORT_OWNER);
         goto resetfail;
     }
 
     rv = USB_HIGHSPEED;
 resetfail:
-    ehci_note_port(cntl);
+    PendingEHCIPorts--;
     return rv;
 }
 
@@ -310,7 +279,6 @@ configure_ehci(void *data)
 
     // Set default of high speed for root hub.
     writel(&cntl->regs->configflag, 1);
-    cntl->checkports = readl(&cntl->caps->hcsparams) & HCS_N_PORTS_MASK;
 
     // Find devices
     int count = check_ehci_ports(cntl);
@@ -329,12 +297,10 @@ fail:
     free(cntl);
 }
 
-int
-ehci_setup(struct pci_device *pci, int busid, struct pci_device *comppci)
+static void
+ehci_controller_setup(struct pci_device *pci)
 {
-    if (! CONFIG_USB_EHCI)
-        return -1;
-
+    wait_preempt();  // Avoid pci_config_readl when preempting
     u16 bdf = pci->bdf;
     u32 baseaddr = pci_config_readl(bdf, PCI_BASE_ADDRESS_0);
     struct ehci_caps *caps = (void*)(baseaddr & PCI_BASE_ADDRESS_MEM_MASK);
@@ -343,16 +309,17 @@ ehci_setup(struct pci_device *pci, int busid, struct pci_device *comppci)
     struct usb_ehci_s *cntl = malloc_tmphigh(sizeof(*cntl));
     if (!cntl) {
         warn_noalloc();
-        return -1;
+        return;
     }
     memset(cntl, 0, sizeof(*cntl));
-    cntl->usb.busid = busid;
     cntl->usb.pci = pci;
     cntl->usb.type = USB_TYPE_EHCI;
     cntl->caps = caps;
+    cntl->checkports = readl(&cntl->caps->hcsparams) & HCS_N_PORTS_MASK;
     cntl->regs = (void*)caps + readb(&caps->caplength);
     if (hcc_params & HCC_64BIT_ADDR)
         cntl->regs->ctrldssegment = 0;
+    PendingEHCIPorts += cntl->checkports;
 
     dprintf(1, "EHCI init on dev %02x:%02x.%x (regs=%p)\n"
             , pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf)
@@ -362,20 +329,24 @@ ehci_setup(struct pci_device *pci, int busid, struct pci_device *comppci)
 
     // XXX - check for and disable SMM control?
 
-    // Find companion controllers.
-    int count = 0;
-    for (;;) {
-        if (!comppci || comppci == pci)
-            break;
-        if (pci_classprog(comppci) == PCI_CLASS_SERIAL_USB_UHCI)
-            cntl->companion[count++] = comppci;
-        else if (pci_classprog(comppci) == PCI_CLASS_SERIAL_USB_OHCI)
-            cntl->companion[count++] = comppci;
-        comppci = container_of(comppci->node.next, struct pci_device, node);
+    run_thread(configure_ehci, cntl);
+}
+
+void
+ehci_setup(void)
+{
+    if (! CONFIG_USB_EHCI)
+        return;
+    struct pci_device *pci;
+    foreachpci(pci) {
+        if (pci_classprog(pci) == PCI_CLASS_SERIAL_USB_EHCI)
+            ehci_controller_setup(pci);
     }
 
-    run_thread(configure_ehci, cntl);
-    return 0;
+    // Wait for all EHCI ports to initialize.  This forces OHCI/UHCI
+    // setup to always be after any EHCI ports are set to low speed.
+    while (PendingEHCIPorts)
+        yield();
 }
 
 
index 5672033a0c63f8445ecc59f4939aed3324d8cca1..fcb8d949e03f3b40d5cd5bc67307bfe1a186a2cf 100644 (file)
@@ -2,7 +2,7 @@
 #define __USB_EHCI_H
 
 // usb-ehci.c
-int ehci_setup(struct pci_device *pci, int busid, struct pci_device *comppci);
+void ehci_setup(void);
 struct usbdevice_s;
 struct usb_endpoint_descriptor;
 struct usb_pipe *ehci_alloc_pipe(struct usbdevice_s *usbdev
index 313e3fd44de3434c89f6bc4d1ef5704676879b37..d55b64a91f11fa8b943ee37f7ef1d0bb91eb9723 100644 (file)
@@ -9,6 +9,7 @@
 #include "malloc.h" // free
 #include "output.h" // dprintf
 #include "pci.h" // pci_bdf_to_bus
+#include "pci_ids.h" // PCI_CLASS_SERIAL_USB_OHCI
 #include "pci_regs.h" // PCI_BASE_ADDRESS_0
 #include "string.h" // memset
 #include "usb.h" // struct usb_s
@@ -265,21 +266,19 @@ free:
     free(intr_ed);
 }
 
-void
-ohci_setup(struct pci_device *pci, int busid)
+static void
+ohci_controller_setup(struct pci_device *pci)
 {
-    if (! CONFIG_USB_OHCI)
-        return;
     struct usb_ohci_s *cntl = malloc_tmphigh(sizeof(*cntl));
     if (!cntl) {
         warn_noalloc();
         return;
     }
     memset(cntl, 0, sizeof(*cntl));
-    cntl->usb.busid = busid;
     cntl->usb.pci = pci;
     cntl->usb.type = USB_TYPE_OHCI;
 
+    wait_preempt();  // Avoid pci_config_readl when preempting
     u16 bdf = pci->bdf;
     u32 baseaddr = pci_config_readl(bdf, PCI_BASE_ADDRESS_0);
     cntl->regs = (void*)(baseaddr & PCI_BASE_ADDRESS_MEM_MASK);
@@ -301,6 +300,18 @@ ohci_setup(struct pci_device *pci, int busid)
     run_thread(configure_ohci, cntl);
 }
 
+void
+ohci_setup(void)
+{
+    if (! CONFIG_USB_OHCI)
+        return;
+    struct pci_device *pci;
+    foreachpci(pci) {
+        if (pci_classprog(pci) == PCI_CLASS_SERIAL_USB_OHCI)
+            ohci_controller_setup(pci);
+    }
+}
+
 
 /****************************************************************
  * End point communication
index ad0ffece5c930c3314d7ffa35d87590fc94039ad..3cae21ff26afee6dde34c1dc234c7ab88fa49588 100644 (file)
@@ -2,7 +2,7 @@
 #define __USB_OHCI_H
 
 // usb-ohci.c
-void ohci_setup(struct pci_device *pci, int busid);
+void ohci_setup(void);
 struct usbdevice_s;
 struct usb_endpoint_descriptor;
 struct usb_pipe *ohci_alloc_pipe(struct usbdevice_s *usbdev
index 03eb5e1a41dc0b8f391b1d4e923d5439fc864514..2321e21de0b768e5cfa82ad4863d4414d0d69184 100644 (file)
@@ -9,6 +9,7 @@
 #include "malloc.h" // free
 #include "output.h" // dprintf
 #include "pci.h" // pci_bdf_to_bus
+#include "pci_ids.h" // PCI_CLASS_SERIAL_USB_UHCI
 #include "pci_regs.h" // PCI_BASE_ADDRESS_4
 #include "string.h" // memset
 #include "usb.h" // struct usb_s
@@ -237,19 +238,17 @@ fail:
     free(cntl);
 }
 
-void
-uhci_setup(struct pci_device *pci, int busid)
+static void
+uhci_controller_setup(struct pci_device *pci)
 {
-    if (! CONFIG_USB_UHCI)
-        return;
     u16 bdf = pci->bdf;
     struct usb_uhci_s *cntl = malloc_tmphigh(sizeof(*cntl));
     if (!cntl) {
         warn_noalloc();
         return;
     }
+    wait_preempt();  // Avoid pci_config_readl when preempting
     memset(cntl, 0, sizeof(*cntl));
-    cntl->usb.busid = busid;
     cntl->usb.pci = pci;
     cntl->usb.type = USB_TYPE_UHCI;
     cntl->iobase = (pci_config_readl(bdf, PCI_BASE_ADDRESS_4)
@@ -266,6 +265,18 @@ uhci_setup(struct pci_device *pci, int busid)
     run_thread(configure_uhci, cntl);
 }
 
+void
+uhci_setup(void)
+{
+    if (! CONFIG_USB_UHCI)
+        return;
+    struct pci_device *pci;
+    foreachpci(pci) {
+        if (pci_classprog(pci) == PCI_CLASS_SERIAL_USB_UHCI)
+            uhci_controller_setup(pci);
+    }
+}
+
 
 /****************************************************************
  * End point communication
index b83c48711223859073f69f8ba49feccca7085e9b..2916465627c34b0a451a3c47a240987c75f6304e 100644 (file)
@@ -2,7 +2,7 @@
 #define __USB_UHCI_H
 
 // usb-uhci.c
-void uhci_setup(struct pci_device *pci, int busid);
+void uhci_setup(void);
 struct usbdevice_s;
 struct usb_endpoint_descriptor;
 struct usb_pipe *uhci_alloc_pipe(struct usbdevice_s *usbdev
index 66ce3c47353efc8f49d41e83ed06c052e4239755..14f243cd697a861c8fb5872f8e47a2f7302dd90d 100644 (file)
@@ -5,6 +5,7 @@
 #include "x86.h" // readl
 #include "malloc.h" // memalign_low
 #include "pci.h" // pci_bdf_to_bus
+#include "pci_ids.h" // PCI_CLASS_SERIAL_USB_XHCI
 #include "pci_regs.h" // PCI_BASE_ADDRESS_0
 #include "usb.h" // struct usb_s
 #include "usb-xhci.h" // struct ehci_qh
@@ -1054,20 +1055,17 @@ xhci_poll_intr(struct usb_pipe *p, void *data)
     return 0;
 }
 
-int
-xhci_setup(struct pci_device *pci, int busid)
+static void
+xhci_controller_setup(struct pci_device *pci)
 {
-    ASSERT32FLAT();
-    if (!CONFIG_USB_XHCI)
-        return -1;
-
     struct usb_xhci_s *xhci = malloc_low(sizeof(*xhci));
     if (!xhci) {
         warn_noalloc();
-        return -1;
+        return;
     }
     memset(xhci, 0, sizeof(*xhci));
 
+    wait_preempt();  // Avoid pci_config_readl when preempting
     xhci->baseaddr = pci_config_readl(pci->bdf, PCI_BASE_ADDRESS_0)
         & PCI_BASE_ADDRESS_MEM_MASK;
     xhci->caps  = (void*)(xhci->baseaddr);
@@ -1082,7 +1080,6 @@ xhci_setup(struct pci_device *pci, int busid)
     xhci->slots = hcs1         & 0xff;
     xhci->xcap  = ((hcc >> 16) & 0xffff) << 2;
 
-    xhci->usb.busid = busid;
     xhci->usb.pci = pci;
     xhci->usb.type = USB_TYPE_XHCI;
     xhci->hub.cntl = &xhci->usb;
@@ -1125,5 +1122,16 @@ xhci_setup(struct pci_device *pci, int busid)
     pci_config_maskw(pci->bdf, PCI_COMMAND, 0, PCI_COMMAND_MASTER);
 
     run_thread(configure_xhci, xhci);
-    return 0;
+}
+
+void
+xhci_setup(void)
+{
+    if (! CONFIG_USB_XHCI)
+        return;
+    struct pci_device *pci;
+    foreachpci(pci) {
+        if (pci_classprog(pci) == PCI_CLASS_SERIAL_USB_XHCI)
+            xhci_controller_setup(pci);
+    }
 }
index 64ee82c25912c18be4190aefbf2edea3742629d3..be6094cfd4500039353dd088cad683d97b3816d8 100644 (file)
@@ -8,7 +8,7 @@ struct usb_pipe;
 // --------------------------------------------------------------
 
 // usb-xhci.c
-int xhci_setup(struct pci_device *pci, int busid);
+void xhci_setup(void);
 struct usb_pipe *xhci_alloc_pipe(struct usbdevice_s *usbdev
                                  , struct usb_endpoint_descriptor *epdesc);
 struct usb_pipe *xhci_update_pipe(struct usbdevice_s *usbdev
index 8fe741f4a318ceae4f17dc308db67a631e88fb41..8430e50baf5e833c8c223b747ad93bef0022d25b 100644 (file)
@@ -1,6 +1,6 @@
 // Main code for handling USB controllers and devices.
 //
-// Copyright (C) 2009  Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2009-2013  Kevin O'Connor <kevin@koconnor.net>
 //
 // This file may be distributed under the terms of the GNU LGPLv3 license.
 
@@ -8,9 +8,6 @@
 #include "config.h" // CONFIG_*
 #include "malloc.h" // free
 #include "output.h" // dprintf
-#include "pci.h" // foreachpci
-#include "pci_ids.h" // PCI_CLASS_SERIAL_USB_UHCI
-#include "pci_regs.h" // PCI_CLASS_REVISION
 #include "string.h" // memset
 #include "usb.h" // struct usb_s
 #include "usb-ehci.h" // ehci_setup
@@ -438,53 +435,21 @@ usb_enumerate(struct usbhub_s *hub)
         yield();
 }
 
+void
+__usb_setup(void *data)
+{
+    dprintf(3, "init usb\n");
+    xhci_setup();
+    ehci_setup();
+    uhci_setup();
+    ohci_setup();
+}
+
 void
 usb_setup(void)
 {
     ASSERT32FLAT();
     if (! CONFIG_USB)
         return;
-
-    dprintf(3, "init usb\n");
-
-    // Look for USB controllers
-    int count = 0;
-    struct pci_device *pci, *ehcipci = NULL;
-    foreachpci(pci) {
-        if (pci->class != PCI_CLASS_SERIAL_USB)
-            continue;
-
-        if (!ehcipci || pci->bdf >= ehcipci->bdf) {
-            // Check to see if this device has an ehci controller
-            int found = 0;
-            ehcipci = pci;
-            for (;;) {
-                if (pci_classprog(ehcipci) == PCI_CLASS_SERIAL_USB_EHCI) {
-                    // Found an ehci controller.
-                    int ret = ehci_setup(ehcipci, count++, pci);
-                    if (ret)
-                        // Error
-                        break;
-                    count += found;
-                    pci = ehcipci;
-                    break;
-                }
-                if (ehcipci->class == PCI_CLASS_SERIAL_USB)
-                    found++;
-                ehcipci = container_of_or_null(
-                    ehcipci->node.next, struct pci_device, node);
-                if (!ehcipci || (pci_bdf_to_busdev(ehcipci->bdf)
-                                 != pci_bdf_to_busdev(pci->bdf)))
-                    // No ehci controller found.
-                    break;
-            }
-        }
-
-        if (pci_classprog(pci) == PCI_CLASS_SERIAL_USB_UHCI)
-            uhci_setup(pci, count++);
-        else if (pci_classprog(pci) == PCI_CLASS_SERIAL_USB_OHCI)
-            ohci_setup(pci, count++);
-        else if (pci_classprog(pci) == PCI_CLASS_SERIAL_USB_XHCI)
-            xhci_setup(pci, count++);
-    }
+    run_thread(__usb_setup, NULL);
 }
index 22173fb371cb84017572f74961be8dd9abc903c0..883c60895c5654f4366f7acd4928a9390ffcf925 100644 (file)
@@ -35,7 +35,6 @@ struct usb_s {
     struct usb_pipe *freelist;
     struct mutex_s resetlock;
     struct pci_device *pci;
-    int busid;
     u8 type;
     u8 maxaddr;
 };