9ae3a8
From da332a238d28a29821dc57437f43feed54a3f418 Mon Sep 17 00:00:00 2001
9ae3a8
From: Gerd Hoffmann <kraxel@redhat.com>
9ae3a8
Date: Fri, 11 Jul 2014 14:20:55 +0200
9ae3a8
Subject: [PATCH 21/43] xhci: Call usb_device_alloc/free_streams
9ae3a8
9ae3a8
Message-id: <1405088470-24115-23-git-send-email-kraxel@redhat.com>
9ae3a8
Patchwork-id: 59834
9ae3a8
O-Subject: [RHEL-7.1 qemu-kvm PATCH 22/37] xhci: Call usb_device_alloc/free_streams
9ae3a8
Bugzilla: 980833
9ae3a8
RH-Acked-by: Dr. David Alan Gilbert (git) <dgilbert@redhat.com>
9ae3a8
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
9ae3a8
RH-Acked-by: Laszlo Ersek <lersek@redhat.com>
9ae3a8
9ae3a8
From: Hans de Goede <hdegoede@redhat.com>
9ae3a8
9ae3a8
Note this code is not as KISS as I would like, the reason for this is that
9ae3a8
the Linux kernel interface wants streams on eps belonging to one interface
9ae3a8
to be allocated in one call. Things will also work if we do this one ep at a
9ae3a8
time (as long as all eps support the same amount of streams), but lets stick
9ae3a8
to the kernel API.
9ae3a8
9ae3a8
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
9ae3a8
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
9ae3a8
(cherry picked from commit 72391da50621c9f11bb8c57193ab2d1ad8bc5ad8)
9ae3a8
---
9ae3a8
 hw/usb/hcd-xhci.c | 117 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
9ae3a8
 1 file changed, 117 insertions(+)
9ae3a8
9ae3a8
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
9ae3a8
---
9ae3a8
 hw/usb/hcd-xhci.c | 117 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
9ae3a8
 1 file changed, 117 insertions(+)
9ae3a8
9ae3a8
diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c
9ae3a8
index 944b255..5f0840b 100644
9ae3a8
--- a/hw/usb/hcd-xhci.c
9ae3a8
+++ b/hw/usb/hcd-xhci.c
9ae3a8
@@ -1153,6 +1153,111 @@ static void xhci_free_streams(XHCIEPContext *epctx)
9ae3a8
     epctx->nr_pstreams = 0;
9ae3a8
 }
9ae3a8
 
9ae3a8
+static int xhci_epmask_to_eps_with_streams(XHCIState *xhci,
9ae3a8
+                                           unsigned int slotid,
9ae3a8
+                                           uint32_t epmask,
9ae3a8
+                                           XHCIEPContext **epctxs,
9ae3a8
+                                           USBEndpoint **eps)
9ae3a8
+{
9ae3a8
+    XHCISlot *slot;
9ae3a8
+    XHCIEPContext *epctx;
9ae3a8
+    USBEndpoint *ep;
9ae3a8
+    int i, j;
9ae3a8
+
9ae3a8
+    assert(slotid >= 1 && slotid <= xhci->numslots);
9ae3a8
+
9ae3a8
+    slot = &xhci->slots[slotid - 1];
9ae3a8
+
9ae3a8
+    for (i = 2, j = 0; i <= 31; i++) {
9ae3a8
+        if (!(epmask & (1 << i))) {
9ae3a8
+            continue;
9ae3a8
+        }
9ae3a8
+
9ae3a8
+        epctx = slot->eps[i - 1];
9ae3a8
+        ep = xhci_epid_to_usbep(xhci, slotid, i);
9ae3a8
+        if (!epctx || !epctx->nr_pstreams || !ep) {
9ae3a8
+            continue;
9ae3a8
+        }
9ae3a8
+
9ae3a8
+        if (epctxs) {
9ae3a8
+            epctxs[j] = epctx;
9ae3a8
+        }
9ae3a8
+        eps[j++] = ep;
9ae3a8
+    }
9ae3a8
+    return j;
9ae3a8
+}
9ae3a8
+
9ae3a8
+static void xhci_free_device_streams(XHCIState *xhci, unsigned int slotid,
9ae3a8
+                                     uint32_t epmask)
9ae3a8
+{
9ae3a8
+    USBEndpoint *eps[30];
9ae3a8
+    int nr_eps;
9ae3a8
+
9ae3a8
+    nr_eps = xhci_epmask_to_eps_with_streams(xhci, slotid, epmask, NULL, eps);
9ae3a8
+    if (nr_eps) {
9ae3a8
+        usb_device_free_streams(eps[0]->dev, eps, nr_eps);
9ae3a8
+    }
9ae3a8
+}
9ae3a8
+
9ae3a8
+static TRBCCode xhci_alloc_device_streams(XHCIState *xhci, unsigned int slotid,
9ae3a8
+                                          uint32_t epmask)
9ae3a8
+{
9ae3a8
+    XHCIEPContext *epctxs[30];
9ae3a8
+    USBEndpoint *eps[30];
9ae3a8
+    int i, r, nr_eps, req_nr_streams, dev_max_streams;
9ae3a8
+
9ae3a8
+    nr_eps = xhci_epmask_to_eps_with_streams(xhci, slotid, epmask, epctxs,
9ae3a8
+                                             eps);
9ae3a8
+    if (nr_eps == 0) {
9ae3a8
+        return CC_SUCCESS;
9ae3a8
+    }
9ae3a8
+
9ae3a8
+    req_nr_streams = epctxs[0]->nr_pstreams;
9ae3a8
+    dev_max_streams = eps[0]->max_streams;
9ae3a8
+
9ae3a8
+    for (i = 1; i < nr_eps; i++) {
9ae3a8
+        /*
9ae3a8
+         * HdG: I don't expect these to ever trigger, but if they do we need
9ae3a8
+         * to come up with another solution, ie group identical endpoints
9ae3a8
+         * together and make an usb_device_alloc_streams call per group.
9ae3a8
+         */
9ae3a8
+        if (epctxs[i]->nr_pstreams != req_nr_streams) {
9ae3a8
+            FIXME("guest streams config not identical for all eps");
9ae3a8
+            return CC_RESOURCE_ERROR;
9ae3a8
+        }
9ae3a8
+        if (eps[i]->max_streams != dev_max_streams) {
9ae3a8
+            FIXME("device streams config not identical for all eps");
9ae3a8
+            return CC_RESOURCE_ERROR;
9ae3a8
+        }
9ae3a8
+    }
9ae3a8
+
9ae3a8
+    /*
9ae3a8
+     * max-streams in both the device descriptor and in the controller is a
9ae3a8
+     * power of 2. But stream id 0 is reserved, so if a device can do up to 4
9ae3a8
+     * streams the guest will ask for 5 rounded up to the next power of 2 which
9ae3a8
+     * becomes 8. For emulated devices usb_device_alloc_streams is a nop.
9ae3a8
+     *
9ae3a8
+     * For redirected devices however this is an issue, as there we must ask
9ae3a8
+     * the real xhci controller to alloc streams, and the host driver for the
9ae3a8
+     * real xhci controller will likely disallow allocating more streams then
9ae3a8
+     * the device can handle.
9ae3a8
+     *
9ae3a8
+     * So we limit the requested nr_streams to the maximum number the device
9ae3a8
+     * can handle.
9ae3a8
+     */
9ae3a8
+    if (req_nr_streams > dev_max_streams) {
9ae3a8
+        req_nr_streams = dev_max_streams;
9ae3a8
+    }
9ae3a8
+
9ae3a8
+    r = usb_device_alloc_streams(eps[0]->dev, eps, nr_eps, req_nr_streams);
9ae3a8
+    if (r != 0) {
9ae3a8
+        fprintf(stderr, "xhci: alloc streams failed\n");
9ae3a8
+        return CC_RESOURCE_ERROR;
9ae3a8
+    }
9ae3a8
+
9ae3a8
+    return CC_SUCCESS;
9ae3a8
+}
9ae3a8
+
9ae3a8
 static XHCIStreamContext *xhci_find_stream(XHCIEPContext *epctx,
9ae3a8
                                            unsigned int streamid,
9ae3a8
                                            uint32_t *cc_error)
9ae3a8
@@ -2325,6 +2430,8 @@ static TRBCCode xhci_configure_slot(XHCIState *xhci, unsigned int slotid,
9ae3a8
         return CC_CONTEXT_STATE_ERROR;
9ae3a8
     }
9ae3a8
 
9ae3a8
+    xhci_free_device_streams(xhci, slotid, ictl_ctx[0] | ictl_ctx[1]);
9ae3a8
+
9ae3a8
     for (i = 2; i <= 31; i++) {
9ae3a8
         if (ictl_ctx[0] & (1<
9ae3a8
             xhci_disable_ep(xhci, slotid, i);
9ae3a8
@@ -2346,6 +2453,16 @@ static TRBCCode xhci_configure_slot(XHCIState *xhci, unsigned int slotid,
9ae3a8
         }
9ae3a8
     }
9ae3a8
 
9ae3a8
+    res = xhci_alloc_device_streams(xhci, slotid, ictl_ctx[1]);
9ae3a8
+    if (res != CC_SUCCESS) {
9ae3a8
+        for (i = 2; i <= 31; i++) {
9ae3a8
+            if (ictl_ctx[1] & (1 << i)) {
9ae3a8
+                xhci_disable_ep(xhci, slotid, i);
9ae3a8
+            }
9ae3a8
+        }
9ae3a8
+        return res;
9ae3a8
+    }
9ae3a8
+
9ae3a8
     slot_ctx[3] &= ~(SLOT_STATE_MASK << SLOT_STATE_SHIFT);
9ae3a8
     slot_ctx[3] |= SLOT_CONFIGURED << SLOT_STATE_SHIFT;
9ae3a8
     slot_ctx[0] &= ~(SLOT_CONTEXT_ENTRIES_MASK << SLOT_CONTEXT_ENTRIES_SHIFT);
9ae3a8
-- 
9ae3a8
1.8.3.1
9ae3a8