peterdelevoryas / rpms / qemu

Forked from rpms/qemu 2 years ago
Clone

Blame 0340-xhci-update-port-handling.patch

c8dfc6
From ed16ece865cb40c9ad8ddf28905c0af3ad80e118 Mon Sep 17 00:00:00 2001
c8dfc6
From: Gerd Hoffmann <kraxel@redhat.com>
c8dfc6
Date: Tue, 28 Aug 2012 13:38:01 +0200
c8dfc6
Subject: [PATCH 340/366] xhci: update port handling
c8dfc6
c8dfc6
This patch changes the way xhci ports are linked to USBPorts.  The fixed
c8dfc6
1:1 relationship between xhci ports and USBPorts is gone.  Now each
c8dfc6
USBPort represents a physical plug which has usually two xhci ports
c8dfc6
assigned: one usb2 and ond usb3 port.  usb devices show up at one or the
c8dfc6
other, depending on whenever they support superspeed or not.
c8dfc6
c8dfc6
This patch also makes the number of usb2 and usb3 ports runtime
c8dfc6
configurable by adding 'p2' and 'p3' properties.  It is allowed to
c8dfc6
have different numbers of usb2 and usb3 ports.  Specifying p2=4,p3=2
c8dfc6
will give you an xhci adapter which supports all speeds on physical
c8dfc6
ports 1+2 and usb2 only on ports 3+4.
c8dfc6
---
c8dfc6
 hw/usb/hcd-xhci.c | 137 ++++++++++++++++++++++++++++++++++++++----------------
c8dfc6
 1 file changed, 97 insertions(+), 40 deletions(-)
c8dfc6
c8dfc6
diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c
c8dfc6
index 414b633..e08312e 100644
c8dfc6
--- a/hw/usb/hcd-xhci.c
c8dfc6
+++ b/hw/usb/hcd-xhci.c
c8dfc6
@@ -36,10 +36,10 @@
c8dfc6
 #define FIXME() do { fprintf(stderr, "FIXME %s:%d\n", \
c8dfc6
                              __func__, __LINE__); abort(); } while (0)
c8dfc6
 
c8dfc6
-#define USB2_PORTS 4
c8dfc6
-#define USB3_PORTS 4
c8dfc6
+#define MAXPORTS_2 8
c8dfc6
+#define MAXPORTS_3 8
c8dfc6
 
c8dfc6
-#define MAXPORTS (USB2_PORTS+USB3_PORTS)
c8dfc6
+#define MAXPORTS (MAXPORTS_2+MAXPORTS_3)
c8dfc6
 #define MAXSLOTS MAXPORTS
c8dfc6
 #define MAXINTRS 1 /* MAXPORTS */
c8dfc6
 
c8dfc6
@@ -300,8 +300,10 @@ typedef struct XHCIRing {
c8dfc6
 } XHCIRing;
c8dfc6
 
c8dfc6
 typedef struct XHCIPort {
c8dfc6
-    USBPort port;
c8dfc6
     uint32_t portsc;
c8dfc6
+    uint32_t portnr;
c8dfc6
+    USBPort  *uport;
c8dfc6
+    uint32_t speedmask;
c8dfc6
 } XHCIPort;
c8dfc6
 
c8dfc6
 struct XHCIState;
c8dfc6
@@ -379,9 +381,13 @@ struct XHCIState {
c8dfc6
     qemu_irq irq;
c8dfc6
     MemoryRegion mem;
c8dfc6
     const char *name;
c8dfc6
-    uint32_t msi;
c8dfc6
     unsigned int devaddr;
c8dfc6
 
c8dfc6
+    /* properties */
c8dfc6
+    uint32_t numports_2;
c8dfc6
+    uint32_t numports_3;
c8dfc6
+    uint32_t msi;
c8dfc6
+
c8dfc6
     /* Operational Registers */
c8dfc6
     uint32_t usbcmd;
c8dfc6
     uint32_t usbsts;
c8dfc6
@@ -392,8 +398,10 @@ struct XHCIState {
c8dfc6
     uint32_t dcbaap_high;
c8dfc6
     uint32_t config;
c8dfc6
 
c8dfc6
+    USBPort  uports[MAX(MAXPORTS_2, MAXPORTS_3)];
c8dfc6
     XHCIPort ports[MAXPORTS];
c8dfc6
     XHCISlot slots[MAXSLOTS];
c8dfc6
+    uint32_t numports;
c8dfc6
 
c8dfc6
     /* Runtime Registers */
c8dfc6
     uint32_t iman;
c8dfc6
@@ -578,6 +586,28 @@ static inline dma_addr_t xhci_mask64(uint64_t addr)
c8dfc6
     }
c8dfc6
 }
c8dfc6
 
c8dfc6
+static XHCIPort *xhci_lookup_port(XHCIState *xhci, struct USBPort *uport)
c8dfc6
+{
c8dfc6
+    int index;
c8dfc6
+
c8dfc6
+    if (!uport->dev) {
c8dfc6
+        return NULL;
c8dfc6
+    }
c8dfc6
+    switch (uport->dev->speed) {
c8dfc6
+    case USB_SPEED_LOW:
c8dfc6
+    case USB_SPEED_FULL:
c8dfc6
+    case USB_SPEED_HIGH:
c8dfc6
+        index = uport->index;
c8dfc6
+        break;
c8dfc6
+    case USB_SPEED_SUPER:
c8dfc6
+        index = uport->index + xhci->numports_2;
c8dfc6
+        break;
c8dfc6
+    default:
c8dfc6
+        return NULL;
c8dfc6
+    }
c8dfc6
+    return &xhci->ports[index];
c8dfc6
+}
c8dfc6
+
c8dfc6
 static void xhci_irq_update(XHCIState *xhci)
c8dfc6
 {
c8dfc6
     int level = 0;
c8dfc6
@@ -1126,7 +1156,7 @@ static TRBCCode xhci_reset_ep(XHCIState *xhci, unsigned int slotid,
c8dfc6
         ep |= 0x80;
c8dfc6
     }
c8dfc6
 
c8dfc6
-    dev = xhci->ports[xhci->slots[slotid-1].port-1].port.dev;
c8dfc6
+    dev = xhci->ports[xhci->slots[slotid-1].port-1].uport->dev;
c8dfc6
     if (!dev) {
c8dfc6
         return CC_USB_TRANSACTION_ERROR;
c8dfc6
     }
c8dfc6
@@ -1313,7 +1343,7 @@ static USBDevice *xhci_find_device(XHCIPort *port, uint8_t addr)
c8dfc6
     if (!(port->portsc & PORTSC_PED)) {
c8dfc6
         return NULL;
c8dfc6
     }
c8dfc6
-    return usb_find_device(&port->port, addr);
c8dfc6
+    return usb_find_device(port->uport, addr);
c8dfc6
 }
c8dfc6
 
c8dfc6
 static int xhci_setup_packet(XHCITransfer *xfer)
c8dfc6
@@ -1736,9 +1766,9 @@ static TRBCCode xhci_address_slot(XHCIState *xhci, unsigned int slotid,
c8dfc6
             ep0_ctx[0], ep0_ctx[1], ep0_ctx[2], ep0_ctx[3], ep0_ctx[4]);
c8dfc6
 
c8dfc6
     port = (slot_ctx[1]>>16) & 0xFF;
c8dfc6
-    dev = xhci->ports[port-1].port.dev;
c8dfc6
+    dev = xhci->ports[port-1].uport->dev;
c8dfc6
 
c8dfc6
-    if (port < 1 || port > MAXPORTS) {
c8dfc6
+    if (port < 1 || port > xhci->numports) {
c8dfc6
         fprintf(stderr, "xhci: bad port %d\n", port);
c8dfc6
         return CC_TRB_ERROR;
c8dfc6
     } else if (!dev) {
c8dfc6
@@ -1987,7 +2017,7 @@ static unsigned int xhci_get_slot(XHCIState *xhci, XHCIEvent *event, XHCITRB *tr
c8dfc6
 static TRBCCode xhci_get_port_bandwidth(XHCIState *xhci, uint64_t pctx)
c8dfc6
 {
c8dfc6
     dma_addr_t ctx;
c8dfc6
-    uint8_t bw_ctx[MAXPORTS+1];
c8dfc6
+    uint8_t bw_ctx[xhci->numports+1];
c8dfc6
 
c8dfc6
     DPRINTF("xhci_get_port_bandwidth()\n");
c8dfc6
 
c8dfc6
@@ -1997,7 +2027,7 @@ static TRBCCode xhci_get_port_bandwidth(XHCIState *xhci, uint64_t pctx)
c8dfc6
 
c8dfc6
     /* TODO: actually implement real values here */
c8dfc6
     bw_ctx[0] = 0;
c8dfc6
-    memset(&bw_ctx[1], 80, MAXPORTS); /* 80% */
c8dfc6
+    memset(&bw_ctx[1], 80, xhci->numports); /* 80% */
c8dfc6
     pci_dma_write(&xhci->pci_dev, ctx, bw_ctx, sizeof(bw_ctx));
c8dfc6
 
c8dfc6
     return CC_SUCCESS;
c8dfc6
@@ -2167,12 +2197,11 @@ static void xhci_process_commands(XHCIState *xhci)
c8dfc6
 
c8dfc6
 static void xhci_update_port(XHCIState *xhci, XHCIPort *port, int is_detach)
c8dfc6
 {
c8dfc6
-    int nr = port->port.index + 1;
c8dfc6
-
c8dfc6
     port->portsc = PORTSC_PP;
c8dfc6
-    if (port->port.dev && port->port.dev->attached && !is_detach) {
c8dfc6
+    if (port->uport->dev && port->uport->dev->attached && !is_detach &&
c8dfc6
+        (1 << port->uport->dev->speed) & port->speedmask) {
c8dfc6
         port->portsc |= PORTSC_CCS;
c8dfc6
-        switch (port->port.dev->speed) {
c8dfc6
+        switch (port->uport->dev->speed) {
c8dfc6
         case USB_SPEED_LOW:
c8dfc6
             port->portsc |= PORTSC_SPEED_LOW;
c8dfc6
             break;
c8dfc6
@@ -2182,14 +2211,18 @@ static void xhci_update_port(XHCIState *xhci, XHCIPort *port, int is_detach)
c8dfc6
         case USB_SPEED_HIGH:
c8dfc6
             port->portsc |= PORTSC_SPEED_HIGH;
c8dfc6
             break;
c8dfc6
+        case USB_SPEED_SUPER:
c8dfc6
+            port->portsc |= PORTSC_SPEED_SUPER;
c8dfc6
+            break;
c8dfc6
         }
c8dfc6
     }
c8dfc6
 
c8dfc6
     if (xhci_running(xhci)) {
c8dfc6
         port->portsc |= PORTSC_CSC;
c8dfc6
-        XHCIEvent ev = { ER_PORT_STATUS_CHANGE, CC_SUCCESS, nr << 24};
c8dfc6
+        XHCIEvent ev = { ER_PORT_STATUS_CHANGE, CC_SUCCESS,
c8dfc6
+                         port->portnr << 24};
c8dfc6
         xhci_event(xhci, &ev;;
c8dfc6
-        DPRINTF("xhci: port change event for port %d\n", nr);
c8dfc6
+        DPRINTF("xhci: port change event for port %d\n", port->portnr);
c8dfc6
     }
c8dfc6
 }
c8dfc6
 
c8dfc6
@@ -2217,7 +2250,7 @@ static void xhci_reset(DeviceState *dev)
c8dfc6
         xhci_disable_slot(xhci, i+1);
c8dfc6
     }
c8dfc6
 
c8dfc6
-    for (i = 0; i < MAXPORTS; i++) {
c8dfc6
+    for (i = 0; i < xhci->numports; i++) {
c8dfc6
         xhci_update_port(xhci, xhci->ports + i, 0);
c8dfc6
     }
c8dfc6
 
c8dfc6
@@ -2248,7 +2281,8 @@ static uint32_t xhci_cap_read(XHCIState *xhci, uint32_t reg)
c8dfc6
         ret = 0x01000000 | LEN_CAP;
c8dfc6
         break;
c8dfc6
     case 0x04: /* HCSPARAMS 1 */
c8dfc6
-        ret = (MAXPORTS<<24) | (MAXINTRS<<8) | MAXSLOTS;
c8dfc6
+        ret = ((xhci->numports_2+xhci->numports_3)<<24)
c8dfc6
+            | (MAXINTRS<<8) | MAXSLOTS;
c8dfc6
         break;
c8dfc6
     case 0x08: /* HCSPARAMS 2 */
c8dfc6
         ret = 0x0000000f;
c8dfc6
@@ -2278,7 +2312,7 @@ static uint32_t xhci_cap_read(XHCIState *xhci, uint32_t reg)
c8dfc6
         ret = 0x20425455; /* "USB " */
c8dfc6
         break;
c8dfc6
     case 0x28: /* Supported Protocol:08 */
c8dfc6
-        ret = 0x00000001 | (USB2_PORTS<<8);
c8dfc6
+        ret = 0x00000001 | (xhci->numports_2<<8);
c8dfc6
         break;
c8dfc6
     case 0x2c: /* Supported Protocol:0c */
c8dfc6
         ret = 0x00000000; /* reserved */
c8dfc6
@@ -2290,7 +2324,7 @@ static uint32_t xhci_cap_read(XHCIState *xhci, uint32_t reg)
c8dfc6
         ret = 0x20425455; /* "USB " */
c8dfc6
         break;
c8dfc6
     case 0x38: /* Supported Protocol:08 */
c8dfc6
-        ret = 0x00000000 | (USB2_PORTS+1) | (USB3_PORTS<<8);
c8dfc6
+        ret = 0x00000000 | (xhci->numports_2+1) | (xhci->numports_3<<8);
c8dfc6
         break;
c8dfc6
     case 0x3c: /* Supported Protocol:0c */
c8dfc6
         ret = 0x00000000; /* reserved */
c8dfc6
@@ -2309,7 +2343,7 @@ static uint32_t xhci_port_read(XHCIState *xhci, uint32_t reg)
c8dfc6
     uint32_t port = reg >> 4;
c8dfc6
     uint32_t ret;
c8dfc6
 
c8dfc6
-    if (port >= MAXPORTS) {
c8dfc6
+    if (port >= xhci->numports) {
c8dfc6
         fprintf(stderr, "xhci_port_read: port %d out of bounds\n", port);
c8dfc6
         ret = 0;
c8dfc6
         goto out;
c8dfc6
@@ -2342,7 +2376,7 @@ static void xhci_port_write(XHCIState *xhci, uint32_t reg, uint32_t val)
c8dfc6
 
c8dfc6
     trace_usb_xhci_port_write(port, reg & 0x0f, val);
c8dfc6
 
c8dfc6
-    if (port >= MAXPORTS) {
c8dfc6
+    if (port >= xhci->numports) {
c8dfc6
         fprintf(stderr, "xhci_port_read: port %d out of bounds\n", port);
c8dfc6
         return;
c8dfc6
     }
c8dfc6
@@ -2364,7 +2398,7 @@ static void xhci_port_write(XHCIState *xhci, uint32_t reg, uint32_t val)
c8dfc6
         /* write-1-to-start bits */
c8dfc6
         if (val & PORTSC_PR) {
c8dfc6
             DPRINTF("xhci: port %d reset\n", port);
c8dfc6
-            usb_device_reset(xhci->ports[port].port.dev);
c8dfc6
+            usb_device_reset(xhci->ports[port].uport->dev);
c8dfc6
             portsc |= PORTSC_PRC | PORTSC_PED;
c8dfc6
         }
c8dfc6
         xhci->ports[port].portsc = portsc;
c8dfc6
@@ -2659,7 +2693,7 @@ static const MemoryRegionOps xhci_mem_ops = {
c8dfc6
 static void xhci_attach(USBPort *usbport)
c8dfc6
 {
c8dfc6
     XHCIState *xhci = usbport->opaque;
c8dfc6
-    XHCIPort *port = &xhci->ports[usbport->index];
c8dfc6
+    XHCIPort *port = xhci_lookup_port(xhci, usbport);
c8dfc6
 
c8dfc6
     xhci_update_port(xhci, port, 0);
c8dfc6
 }
c8dfc6
@@ -2667,7 +2701,7 @@ static void xhci_attach(USBPort *usbport)
c8dfc6
 static void xhci_detach(USBPort *usbport)
c8dfc6
 {
c8dfc6
     XHCIState *xhci = usbport->opaque;
c8dfc6
-    XHCIPort *port = &xhci->ports[usbport->index];
c8dfc6
+    XHCIPort *port = xhci_lookup_port(xhci, usbport);
c8dfc6
 
c8dfc6
     xhci_update_port(xhci, port, 1);
c8dfc6
 }
c8dfc6
@@ -2675,9 +2709,9 @@ static void xhci_detach(USBPort *usbport)
c8dfc6
 static void xhci_wakeup(USBPort *usbport)
c8dfc6
 {
c8dfc6
     XHCIState *xhci = usbport->opaque;
c8dfc6
-    XHCIPort *port = &xhci->ports[usbport->index];
c8dfc6
-    int nr = port->port.index + 1;
c8dfc6
-    XHCIEvent ev = { ER_PORT_STATUS_CHANGE, CC_SUCCESS, nr << 24};
c8dfc6
+    XHCIPort *port = xhci_lookup_port(xhci, usbport);
c8dfc6
+    XHCIEvent ev = { ER_PORT_STATUS_CHANGE, CC_SUCCESS,
c8dfc6
+                     port->portnr << 24};
c8dfc6
     uint32_t pls;
c8dfc6
 
c8dfc6
     pls = (port->portsc >> PORTSC_PLS_SHIFT) & PORTSC_PLS_MASK;
c8dfc6
@@ -2759,22 +2793,43 @@ static USBBusOps xhci_bus_ops = {
c8dfc6
 
c8dfc6
 static void usb_xhci_init(XHCIState *xhci, DeviceState *dev)
c8dfc6
 {
c8dfc6
-    int i;
c8dfc6
+    XHCIPort *port;
c8dfc6
+    int i, usbports, speedmask;
c8dfc6
 
c8dfc6
     xhci->usbsts = USBSTS_HCH;
c8dfc6
 
c8dfc6
+    if (xhci->numports_2 > MAXPORTS_2) {
c8dfc6
+        xhci->numports_2 = MAXPORTS_2;
c8dfc6
+    }
c8dfc6
+    if (xhci->numports_3 > MAXPORTS_3) {
c8dfc6
+        xhci->numports_3 = MAXPORTS_3;
c8dfc6
+    }
c8dfc6
+    usbports = MAX(xhci->numports_2, xhci->numports_3);
c8dfc6
+    xhci->numports = xhci->numports_2 + xhci->numports_3;
c8dfc6
+
c8dfc6
     usb_bus_new(&xhci->bus, &xhci_bus_ops, &xhci->pci_dev.qdev);
c8dfc6
 
c8dfc6
-    for (i = 0; i < MAXPORTS; i++) {
c8dfc6
-        memset(&xhci->ports[i], 0, sizeof(xhci->ports[i]));
c8dfc6
-        usb_register_port(&xhci->bus, &xhci->ports[i].port, xhci, i,
c8dfc6
-                          &xhci_port_ops,
c8dfc6
-                          USB_SPEED_MASK_LOW  |
c8dfc6
-                          USB_SPEED_MASK_FULL |
c8dfc6
-                          USB_SPEED_MASK_HIGH);
c8dfc6
-    }
c8dfc6
-    for (i = 0; i < MAXSLOTS; i++) {
c8dfc6
-        xhci->slots[i].enabled = 0;
c8dfc6
+    for (i = 0; i < usbports; i++) {
c8dfc6
+        speedmask = 0;
c8dfc6
+        if (i < xhci->numports_2) {
c8dfc6
+            port = &xhci->ports[i];
c8dfc6
+            port->portnr = i + 1;
c8dfc6
+            port->uport = &xhci->uports[i];
c8dfc6
+            port->speedmask =
c8dfc6
+                USB_SPEED_MASK_LOW  |
c8dfc6
+                USB_SPEED_MASK_FULL |
c8dfc6
+                USB_SPEED_MASK_HIGH;
c8dfc6
+            speedmask |= port->speedmask;
c8dfc6
+        }
c8dfc6
+        if (i < xhci->numports_3) {
c8dfc6
+            port = &xhci->ports[i + xhci->numports_2];
c8dfc6
+            port->portnr = i + 1 + xhci->numports_2;
c8dfc6
+            port->uport = &xhci->uports[i];
c8dfc6
+            port->speedmask = USB_SPEED_MASK_SUPER;
c8dfc6
+            speedmask |= port->speedmask;
c8dfc6
+        }
c8dfc6
+        usb_register_port(&xhci->bus, &xhci->uports[i], xhci, i,
c8dfc6
+                          &xhci_port_ops, speedmask);
c8dfc6
     }
c8dfc6
 }
c8dfc6
 
c8dfc6
@@ -2830,6 +2885,8 @@ static const VMStateDescription vmstate_xhci = {
c8dfc6
 
c8dfc6
 static Property xhci_properties[] = {
c8dfc6
     DEFINE_PROP_UINT32("msi", XHCIState, msi, 0),
c8dfc6
+    DEFINE_PROP_UINT32("p2",  XHCIState, numports_2, 4),
c8dfc6
+    DEFINE_PROP_UINT32("p3",  XHCIState, numports_3, 4),
c8dfc6
     DEFINE_PROP_END_OF_LIST(),
c8dfc6
 };
c8dfc6
 
c8dfc6
-- 
c8dfc6
1.7.12
c8dfc6