Allow usb hubs to map (software) ports to physical ports via op callback. This is needed to make bootorder work in case there isn't a simple linear mapping.
Signed-off-by: Gerd Hoffmann kraxel@redhat.com --- src/hw/usb.h | 1 + src/boot.c | 13 ++++++++++--- 2 files changed, 11 insertions(+), 3 deletions(-)
diff --git a/src/hw/usb.h b/src/hw/usb.h index 94e12b20dd..2cfb572177 100644 --- a/src/hw/usb.h +++ b/src/hw/usb.h @@ -56,6 +56,7 @@ struct usbhub_s { struct usbhub_op_s { int (*detect)(struct usbhub_s *hub, u32 port); int (*reset)(struct usbhub_s *hub, u32 port); + int (*portmap)(struct usbhub_s *hub, u32 port); void (*disconnect)(struct usbhub_s *hub, u32 port); };
diff --git a/src/boot.c b/src/boot.c index 59623fb63d..834ac3f3c5 100644 --- a/src/boot.c +++ b/src/boot.c @@ -207,6 +207,13 @@ int bootprio_find_named_rom(const char *name, int instance) return find_prio(desc); }
+static int usb_portmap(struct usbdevice_s *usbdev) +{ + if (usbdev->hub->op->portmap) + return usbdev->hub->op->portmap(usbdev->hub, usbdev->port); + return usbdev->port + 1; +} + static char * build_usb_path(char *buf, int max, struct usbhub_s *hub) { @@ -214,7 +221,7 @@ build_usb_path(char *buf, int max, struct usbhub_s *hub) // Root hub - nothing to add. return buf; char *p = build_usb_path(buf, max, hub->usbdev->hub); - p += snprintf(p, buf+max-p, "/hub@%x", hub->usbdev->port+1); + p += snprintf(p, buf+max-p, "/hub@%x", usb_portmap(hub->usbdev)); return p; }
@@ -227,12 +234,12 @@ int bootprio_find_usb(struct usbdevice_s *usbdev, int lun) p = build_pci_path(desc, sizeof(desc), "usb", usbdev->hub->cntl->pci); p = build_usb_path(p, desc+sizeof(desc)-p, usbdev->hub); snprintf(p, desc+sizeof(desc)-p, "/storage@%x/*@0/*@0,%x" - , usbdev->port+1, lun); + , usb_portmap(usbdev), lun); int ret = find_prio(desc); if (ret >= 0) return ret; // Try usb-host/redir - for example: /pci@i0cf8/usb@1,2/usb-host@1 - snprintf(p, desc+sizeof(desc)-p, "/usb-*@%x", usbdev->port+1); + snprintf(p, desc+sizeof(desc)-p, "/usb-*@%x", usb_portmap(usbdev)); return find_prio(desc); }
xhci controllers have two virtual ports per (usb3 capable) physical port, one for usb2 and one for usb3 devices. Add a hub portmap callback to map the virtual ports to physical ports.
Signed-off-by: Gerd Hoffmann kraxel@redhat.com --- src/hw/usb-xhci.c | 45 +++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 41 insertions(+), 4 deletions(-)
diff --git a/src/hw/usb-xhci.c b/src/hw/usb-xhci.c index 69954b9d8d..50b3b86d6b 100644 --- a/src/hw/usb-xhci.c +++ b/src/hw/usb-xhci.c @@ -226,6 +226,11 @@ struct xhci_ring { struct mutex_s lock; };
+struct xhci_portmap { + u8 start; + u8 count; +}; + struct usb_xhci_s { struct usb_s usb;
@@ -234,6 +239,8 @@ struct usb_xhci_s { u32 ports; u32 slots; u8 context64; + struct xhci_portmap usb2; + struct xhci_portmap usb3;
/* xhci registers */ struct xhci_caps *caps; @@ -374,6 +381,23 @@ xhci_hub_reset(struct usbhub_s *hub, u32 port) return rc; }
+static int +xhci_hub_portmap(struct usbhub_s *hub, u32 vport) +{ + struct usb_xhci_s *xhci = container_of(hub->cntl, struct usb_xhci_s, usb); + u32 pport = vport + 1; + + if (vport + 1 >= xhci->usb3.start && + vport + 1 < xhci->usb3.start + xhci->usb3.count) + pport = vport + 2 - xhci->usb3.start; + + if (vport + 1 >= xhci->usb2.start && + vport + 1 < xhci->usb2.start + xhci->usb2.count) + pport = vport + 2 - xhci->usb2.start; + + return pport; +} + static void xhci_hub_disconnect(struct usbhub_s *hub, u32 port) { @@ -383,6 +407,7 @@ xhci_hub_disconnect(struct usbhub_s *hub, u32 port) static struct usbhub_op_s xhci_hub_ops = { .detect = xhci_hub_detect, .reset = xhci_hub_reset, + .portmap = xhci_hub_portmap, .disconnect = xhci_hub_disconnect, };
@@ -553,17 +578,29 @@ xhci_controller_setup(struct pci_device *pci) case 0x02: name = readl(&xcap->data[0]); ports = readl(&xcap->data[1]); + u8 major = (cap >> 24) & 0xff; + u8 minor = (cap >> 16) & 0xff; + u8 count = (ports >> 8) & 0xff; + u8 start = (ports >> 0) & 0xff; dprintf(1, "XHCI protocol %c%c%c%c %x.%02x" ", %d ports (offset %d), def %x\n" , (name >> 0) & 0xff , (name >> 8) & 0xff , (name >> 16) & 0xff , (name >> 24) & 0xff - , (cap >> 24) & 0xff - , (cap >> 16) & 0xff - , (ports >> 8) & 0xff - , (ports >> 0) & 0xff + , major, minor + , count, start , ports >> 16); + if (name == 0x20425355 /* "USB " */) { + if (major == 2) { + xhci->usb2.start = start; + xhci->usb2.count = count; + } + if (major == 3) { + xhci->usb3.start = start; + xhci->usb3.count = count; + } + } break; default: dprintf(1, "XHCI extcap 0x%x @ %p\n", cap & 0xff, addr);
On Fri, 2017-07-28 at 16:01 +0200, Gerd Hoffmann wrote:
xhci controllers have two virtual ports per (usb3 capable) physical port, one for usb2 and one for usb3 devices. Add a hub portmap callback to map the virtual ports to physical ports.
Patches committed now.