aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorKevin O'Connor <kevin@koconnor.net>2013-12-05 18:43:20 -0500
committerKevin O'Connor <kevin@koconnor.net>2013-12-27 12:42:12 -0500
commitec443fff52edeaa08f2b978faeca46137bfe74d9 (patch)
treed9e984eb430be2c54c5b471a67aa451e83928bda /src
parent60f3b8022c643d7d5a77c3af58f0f13266f39cc5 (diff)
downloadseabios-hppa-ec443fff52edeaa08f2b978faeca46137bfe74d9.zip
seabios-hppa-ec443fff52edeaa08f2b978faeca46137bfe74d9.tar.gz
seabios-hppa-ec443fff52edeaa08f2b978faeca46137bfe74d9.tar.bz2
usb: Replace EHCI to UHCI/OHCI synchronization with new scheme.
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>
Diffstat (limited to 'src')
-rw-r--r--src/hw/usb-ehci.c83
-rw-r--r--src/hw/usb-ehci.h2
-rw-r--r--src/hw/usb-ohci.c21
-rw-r--r--src/hw/usb-ohci.h2
-rw-r--r--src/hw/usb-uhci.c21
-rw-r--r--src/hw/usb-uhci.h2
-rw-r--r--src/hw/usb-xhci.c26
-rw-r--r--src/hw/usb-xhci.h2
-rw-r--r--src/hw/usb.c59
-rw-r--r--src/hw/usb.h1
10 files changed, 92 insertions, 127 deletions
diff --git a/src/hw/usb-ehci.c b/src/hw/usb-ehci.c
index b495d6c..10c92fe 100644
--- a/src/hw/usb-ehci.c
+++ b/src/hw/usb-ehci.c
@@ -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();
}
diff --git a/src/hw/usb-ehci.h b/src/hw/usb-ehci.h
index 5672033..fcb8d94 100644
--- a/src/hw/usb-ehci.h
+++ b/src/hw/usb-ehci.h
@@ -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
diff --git a/src/hw/usb-ohci.c b/src/hw/usb-ohci.c
index 313e3fd..d55b64a 100644
--- a/src/hw/usb-ohci.c
+++ b/src/hw/usb-ohci.c
@@ -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
diff --git a/src/hw/usb-ohci.h b/src/hw/usb-ohci.h
index ad0ffec..3cae21f 100644
--- a/src/hw/usb-ohci.h
+++ b/src/hw/usb-ohci.h
@@ -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
diff --git a/src/hw/usb-uhci.c b/src/hw/usb-uhci.c
index 03eb5e1..2321e21 100644
--- a/src/hw/usb-uhci.c
+++ b/src/hw/usb-uhci.c
@@ -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
diff --git a/src/hw/usb-uhci.h b/src/hw/usb-uhci.h
index b83c487..2916465 100644
--- a/src/hw/usb-uhci.h
+++ b/src/hw/usb-uhci.h
@@ -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
diff --git a/src/hw/usb-xhci.c b/src/hw/usb-xhci.c
index 66ce3c4..14f243c 100644
--- a/src/hw/usb-xhci.c
+++ b/src/hw/usb-xhci.c
@@ -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);
+ }
}
diff --git a/src/hw/usb-xhci.h b/src/hw/usb-xhci.h
index 64ee82c..be6094c 100644
--- a/src/hw/usb-xhci.h
+++ b/src/hw/usb-xhci.h
@@ -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
diff --git a/src/hw/usb.c b/src/hw/usb.c
index 8fe741f..8430e50 100644
--- a/src/hw/usb.c
+++ b/src/hw/usb.c
@@ -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
@@ -439,52 +436,20 @@ usb_enumerate(struct usbhub_s *hub)
}
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);
}
diff --git a/src/hw/usb.h b/src/hw/usb.h
index 22173fb..883c608 100644
--- a/src/hw/usb.h
+++ b/src/hw/usb.h
@@ -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;
};