summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJulius Werner <jwerner@chromium.org>2014-04-28 16:04:24 -0700
committerMarc Jones <marc.jones@se-eng.com>2014-12-22 21:44:43 +0100
commit6af43804c5ef6e66e30e20997c48149bb56d5ff5 (patch)
treea749005672a3468a3c2769959646e509ec2f8372
parent2fe505bd9a4ff4e3e8bf081f254e0b71e41997be (diff)
downloadcoreboot-6af43804c5ef6e66e30e20997c48149bb56d5ff5.tar.xz
libpayload: usb: Try to avoid reusing device addresses
We recently changed the USB stack to detach devices aggressively that we don't intend to use. This alone is not really a problem, but it exarcerbates the fact that our device detachment itself is not very good. We destroy any local info about the device, but we don't properly disable the offending port. The device keeps thinking that it's active, and if we later try to reuse that device address for another device things become confused. The real fix would be to properly disable all ports that we don't intend to use. Unfortunately, this isn't really possible in our current device/hub polymorphism structure, and I don't want to hack a new disable_port() callback into usbdev_t that really doesn't belong there. We will only be able to fix this cleanly after we ported all root hubs to the generic_hub interface. Until then, an easy workaround is to just avoid reusing addresses as long as possible. This is firmware, so the chance that we'll ever run through 127 devices is really small in practice. Even if we ever fix the underlying issue, it's probably a smart precaution to keep. BRANCH=nyan,rambi BUG=chrome-os-partner:28328 TEST=Boot from a hub that has an "unknown" device in an earlier port than the stick you want to boot from, make sure you can still boot. Original-Change-Id: I9b522dd8cbcd441e8c3b8781fcecd2effa0f23ee Original-Signed-off-by: Julius Werner <jwerner@chromium.org> Original-Reviewed-on: https://chromium-review.googlesource.com/197420 Original-Reviewed-by: Shawn Nematbakhsh <shawnn@chromium.org> Original-Reviewed-by: David Hendricks <dhendrix@chromium.org> (cherry picked from commit 28b48aa69b55a983226edf2ea616f33cd4b959e2) Signed-off-by: Marc Jones <marc.jones@se-eng.com> Change-Id: Id4c5c92e75d6b5a7e8f0ee3e396c69c4efd13176 Reviewed-on: http://review.coreboot.org/7881 Tested-by: build bot (Jenkins) Reviewed-by: Patrick Georgi <pgeorgi@google.com>
-rw-r--r--payloads/libpayload/drivers/usb/usb.c14
-rw-r--r--payloads/libpayload/include/usb/usb.h1
2 files changed, 12 insertions, 3 deletions
diff --git a/payloads/libpayload/drivers/usb/usb.c b/payloads/libpayload/drivers/usb/usb.c
index 25bd954ded..53006fff21 100644
--- a/payloads/libpayload/drivers/usb/usb.c
+++ b/payloads/libpayload/drivers/usb/usb.c
@@ -206,10 +206,18 @@ clear_stall (endpoint_t *ep)
static int
get_free_address (hci_t *controller)
{
- int i;
- for (i = 1; i < 128; i++) {
- if (controller->devices[i] == 0)
+ int i = controller->latest_address + 1;
+ for (; i != controller->latest_address; i++) {
+ if (i >= ARRAY_SIZE(controller->devices) || i < 1) {
+ usb_debug("WARNING: Device addresses for controller %#x"
+ " wrapped around!\n", controller->reg_base);
+ i = 0;
+ continue;
+ }
+ if (controller->devices[i] == 0) {
+ controller->latest_address = i;
return i;
+ }
}
usb_debug ("no free address found\n");
return -1; // no free address
diff --git a/payloads/libpayload/include/usb/usb.h b/payloads/libpayload/include/usb/usb.h
index 381d0399ed..ec9912ae7f 100644
--- a/payloads/libpayload/include/usb/usb.h
+++ b/payloads/libpayload/include/usb/usb.h
@@ -213,6 +213,7 @@ struct usbdev_hc {
u32 reg_base;
pcidev_t pcidev; // 0 if not used (eg on ARM)
hc_type type;
+ int latest_address;
usbdev_t *devices[128]; // dev 0 is root hub, 127 is last addressable
/* start(): Resume operation. */