dcavalca / rpms / qemu

Forked from rpms/qemu a year ago
Clone

Blame 0620-xhci-add-XHCIInterrupter.patch

5544c1
From 40ddf0dafd6a8171d2a0f960a21d7d99bdf73cd6 Mon Sep 17 00:00:00 2001
Hans de Goede c8dfc6
From: Gerd Hoffmann <kraxel@redhat.com>
Hans de Goede c8dfc6
Date: Thu, 30 Aug 2012 15:49:03 +0200
5544c1
Subject: [PATCH] xhci: add XHCIInterrupter
Hans de Goede c8dfc6
Hans de Goede c8dfc6
Move all state belonging to the (single) interrupter into a separate
Hans de Goede c8dfc6
struct.  First step in adding support for multiple interrupters.
Hans de Goede c8dfc6
Hans de Goede c8dfc6
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Hans de Goede c8dfc6
---
Hans de Goede c8dfc6
 hw/usb/hcd-xhci.c | 307 ++++++++++++++++++++++++++++--------------------------
Hans de Goede c8dfc6
 trace-events      |   2 +-
Hans de Goede c8dfc6
 2 files changed, 161 insertions(+), 148 deletions(-)
Hans de Goede c8dfc6
Hans de Goede c8dfc6
diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c
5544c1
index 32d22f7..8a14ee8 100644
Hans de Goede c8dfc6
--- a/hw/usb/hcd-xhci.c
Hans de Goede c8dfc6
+++ b/hw/usb/hcd-xhci.c
Hans de Goede c8dfc6
@@ -378,6 +378,27 @@ typedef struct XHCIEvent {
Hans de Goede c8dfc6
     uint8_t epid;
Hans de Goede c8dfc6
 } XHCIEvent;
Hans de Goede c8dfc6
 
Hans de Goede c8dfc6
+typedef struct XHCIInterrupter {
Hans de Goede c8dfc6
+    uint32_t iman;
Hans de Goede c8dfc6
+    uint32_t imod;
Hans de Goede c8dfc6
+    uint32_t erstsz;
Hans de Goede c8dfc6
+    uint32_t erstba_low;
Hans de Goede c8dfc6
+    uint32_t erstba_high;
Hans de Goede c8dfc6
+    uint32_t erdp_low;
Hans de Goede c8dfc6
+    uint32_t erdp_high;
Hans de Goede c8dfc6
+
Hans de Goede c8dfc6
+    bool msix_used, er_pcs, er_full;
Hans de Goede c8dfc6
+
Hans de Goede c8dfc6
+    dma_addr_t er_start;
Hans de Goede c8dfc6
+    uint32_t er_size;
Hans de Goede c8dfc6
+    unsigned int er_ep_idx;
Hans de Goede c8dfc6
+
Hans de Goede c8dfc6
+    XHCIEvent ev_buffer[EV_QUEUE];
Hans de Goede c8dfc6
+    unsigned int ev_buffer_put;
Hans de Goede c8dfc6
+    unsigned int ev_buffer_get;
Hans de Goede c8dfc6
+
Hans de Goede c8dfc6
+} XHCIInterrupter;
Hans de Goede c8dfc6
+
Hans de Goede c8dfc6
 struct XHCIState {
Hans de Goede c8dfc6
     PCIDevice pci_dev;
Hans de Goede c8dfc6
     USBBus bus;
Hans de Goede c8dfc6
@@ -407,27 +428,9 @@ struct XHCIState {
Hans de Goede c8dfc6
     uint32_t numports;
Hans de Goede c8dfc6
 
Hans de Goede c8dfc6
     /* Runtime Registers */
Hans de Goede c8dfc6
-    uint32_t iman;
Hans de Goede c8dfc6
-    uint32_t imod;
Hans de Goede c8dfc6
-    uint32_t erstsz;
Hans de Goede c8dfc6
-    uint32_t erstba_low;
Hans de Goede c8dfc6
-    uint32_t erstba_high;
Hans de Goede c8dfc6
-    uint32_t erdp_low;
Hans de Goede c8dfc6
-    uint32_t erdp_high;
Hans de Goede c8dfc6
-    bool     msix_used;
Hans de Goede c8dfc6
-
Hans de Goede c8dfc6
     int64_t mfindex_start;
Hans de Goede c8dfc6
     QEMUTimer *mfwrap_timer;
Hans de Goede c8dfc6
-
Hans de Goede c8dfc6
-    dma_addr_t er_start;
Hans de Goede c8dfc6
-    uint32_t er_size;
Hans de Goede c8dfc6
-    bool er_pcs;
Hans de Goede c8dfc6
-    unsigned int er_ep_idx;
Hans de Goede c8dfc6
-    bool er_full;
Hans de Goede c8dfc6
-
Hans de Goede c8dfc6
-    XHCIEvent ev_buffer[EV_QUEUE];
Hans de Goede c8dfc6
-    unsigned int ev_buffer_put;
Hans de Goede c8dfc6
-    unsigned int ev_buffer_get;
Hans de Goede c8dfc6
+    XHCIInterrupter intr[MAXINTRS];
Hans de Goede c8dfc6
 
Hans de Goede c8dfc6
     XHCIRing cmd_ring;
Hans de Goede c8dfc6
 };
Hans de Goede c8dfc6
@@ -446,8 +449,8 @@ enum xhci_flags {
Hans de Goede c8dfc6
 
Hans de Goede c8dfc6
 static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid,
Hans de Goede c8dfc6
                          unsigned int epid);
Hans de Goede c8dfc6
-static void xhci_event(XHCIState *xhci, XHCIEvent *event);
Hans de Goede c8dfc6
-static void xhci_write_event(XHCIState *xhci, XHCIEvent *event);
Hans de Goede c8dfc6
+static void xhci_event(XHCIState *xhci, XHCIEvent *event, int v);
Hans de Goede c8dfc6
+static void xhci_write_event(XHCIState *xhci, XHCIEvent *event, int v);
Hans de Goede c8dfc6
 
Hans de Goede c8dfc6
 static const char *TRBType_names[] = {
Hans de Goede c8dfc6
     [TRB_RESERVED]                     = "TRB_RESERVED",
Hans de Goede c8dfc6
@@ -573,7 +576,7 @@ static void xhci_mfwrap_timer(void *opaque)
Hans de Goede c8dfc6
     XHCIState *xhci = opaque;
Hans de Goede c8dfc6
     XHCIEvent wrap = { ER_MFINDEX_WRAP, CC_SUCCESS };
Hans de Goede c8dfc6
 
Hans de Goede c8dfc6
-    xhci_event(xhci, &wrap);
Hans de Goede c8dfc6
+    xhci_event(xhci, &wrap, 0);
Hans de Goede c8dfc6
     xhci_mfwrap_update(xhci);
Hans de Goede c8dfc6
 }
Hans de Goede c8dfc6
 
Hans de Goede c8dfc6
@@ -626,8 +629,8 @@ static void xhci_intx_update(XHCIState *xhci)
Hans de Goede c8dfc6
         return;
Hans de Goede c8dfc6
     }
Hans de Goede c8dfc6
 
Hans de Goede c8dfc6
-    if (xhci->iman & IMAN_IP &&
Hans de Goede c8dfc6
-        xhci->iman & IMAN_IE &&
Hans de Goede c8dfc6
+    if (xhci->intr[0].iman & IMAN_IP &&
Hans de Goede c8dfc6
+        xhci->intr[0].iman & IMAN_IE &&
Hans de Goede c8dfc6
         xhci->usbcmd & USBCMD_INTE) {
Hans de Goede c8dfc6
         level = 1;
Hans de Goede c8dfc6
     }
Hans de Goede c8dfc6
@@ -636,7 +639,7 @@ static void xhci_intx_update(XHCIState *xhci)
Hans de Goede c8dfc6
     qemu_set_irq(xhci->irq, level);
Hans de Goede c8dfc6
 }
Hans de Goede c8dfc6
 
Hans de Goede c8dfc6
-static void xhci_msix_update(XHCIState *xhci)
Hans de Goede c8dfc6
+static void xhci_msix_update(XHCIState *xhci, int v)
Hans de Goede c8dfc6
 {
Hans de Goede c8dfc6
     bool enabled;
Hans de Goede c8dfc6
 
Hans de Goede c8dfc6
@@ -644,29 +647,29 @@ static void xhci_msix_update(XHCIState *xhci)
Hans de Goede c8dfc6
         return;
Hans de Goede c8dfc6
     }
Hans de Goede c8dfc6
 
Hans de Goede c8dfc6
-    enabled = xhci->iman & IMAN_IE;
Hans de Goede c8dfc6
-    if (enabled == xhci->msix_used) {
Hans de Goede c8dfc6
+    enabled = xhci->intr[v].iman & IMAN_IE;
Hans de Goede c8dfc6
+    if (enabled == xhci->intr[v].msix_used) {
Hans de Goede c8dfc6
         return;
Hans de Goede c8dfc6
     }
Hans de Goede c8dfc6
 
Hans de Goede c8dfc6
     if (enabled) {
Hans de Goede c8dfc6
-        trace_usb_xhci_irq_msix_use(0);
Hans de Goede c8dfc6
-        msix_vector_use(&xhci->pci_dev, 0);
Hans de Goede c8dfc6
-        xhci->msix_used = true;
Hans de Goede c8dfc6
+        trace_usb_xhci_irq_msix_use(v);
Hans de Goede c8dfc6
+        msix_vector_use(&xhci->pci_dev, v);
Hans de Goede c8dfc6
+        xhci->intr[v].msix_used = true;
Hans de Goede c8dfc6
     } else {
Hans de Goede c8dfc6
-        trace_usb_xhci_irq_msix_unuse(0);
Hans de Goede c8dfc6
-        msix_vector_unuse(&xhci->pci_dev, 0);
Hans de Goede c8dfc6
-        xhci->msix_used = false;
Hans de Goede c8dfc6
+        trace_usb_xhci_irq_msix_unuse(v);
Hans de Goede c8dfc6
+        msix_vector_unuse(&xhci->pci_dev, v);
Hans de Goede c8dfc6
+        xhci->intr[v].msix_used = false;
Hans de Goede c8dfc6
     }
Hans de Goede c8dfc6
 }
Hans de Goede c8dfc6
 
Hans de Goede c8dfc6
-static void xhci_intr_raise(XHCIState *xhci)
Hans de Goede c8dfc6
+static void xhci_intr_raise(XHCIState *xhci, int v)
Hans de Goede c8dfc6
 {
Hans de Goede c8dfc6
-    xhci->erdp_low |= ERDP_EHB;
Hans de Goede c8dfc6
-    xhci->iman |= IMAN_IP;
Hans de Goede c8dfc6
+    xhci->intr[v].erdp_low |= ERDP_EHB;
Hans de Goede c8dfc6
+    xhci->intr[v].iman |= IMAN_IP;
Hans de Goede c8dfc6
     xhci->usbsts |= USBSTS_EINT;
Hans de Goede c8dfc6
 
Hans de Goede c8dfc6
-    if (!(xhci->iman & IMAN_IE)) {
Hans de Goede c8dfc6
+    if (!(xhci->intr[v].iman & IMAN_IE)) {
Hans de Goede c8dfc6
         return;
Hans de Goede c8dfc6
     }
Hans de Goede c8dfc6
 
Hans de Goede c8dfc6
@@ -675,24 +678,26 @@ static void xhci_intr_raise(XHCIState *xhci)
Hans de Goede c8dfc6
     }
Hans de Goede c8dfc6
 
Hans de Goede c8dfc6
     if (msix_enabled(&xhci->pci_dev)) {
Hans de Goede c8dfc6
-        trace_usb_xhci_irq_msix(0);
Hans de Goede c8dfc6
-        msix_notify(&xhci->pci_dev, 0);
Hans de Goede c8dfc6
+        trace_usb_xhci_irq_msix(v);
Hans de Goede c8dfc6
+        msix_notify(&xhci->pci_dev, v);
Hans de Goede c8dfc6
         return;
Hans de Goede c8dfc6
     }
Hans de Goede c8dfc6
 
Hans de Goede c8dfc6
     if (msi_enabled(&xhci->pci_dev)) {
Hans de Goede c8dfc6
-        trace_usb_xhci_irq_msi(0);
Hans de Goede c8dfc6
-        msi_notify(&xhci->pci_dev, 0);
Hans de Goede c8dfc6
+        trace_usb_xhci_irq_msi(v);
Hans de Goede c8dfc6
+        msi_notify(&xhci->pci_dev, v);
Hans de Goede c8dfc6
         return;
Hans de Goede c8dfc6
     }
Hans de Goede c8dfc6
 
Hans de Goede c8dfc6
-    trace_usb_xhci_irq_intx(1);
Hans de Goede c8dfc6
-    qemu_set_irq(xhci->irq, 1);
Hans de Goede c8dfc6
+    if (v == 0) {
Hans de Goede c8dfc6
+        trace_usb_xhci_irq_intx(1);
Hans de Goede c8dfc6
+        qemu_set_irq(xhci->irq, 1);
Hans de Goede c8dfc6
+    }
Hans de Goede c8dfc6
 }
Hans de Goede c8dfc6
 
Hans de Goede c8dfc6
 static inline int xhci_running(XHCIState *xhci)
Hans de Goede c8dfc6
 {
Hans de Goede c8dfc6
-    return !(xhci->usbsts & USBSTS_HCH) && !xhci->er_full;
Hans de Goede c8dfc6
+    return !(xhci->usbsts & USBSTS_HCH) && !xhci->intr[0].er_full;
Hans de Goede c8dfc6
 }
Hans de Goede c8dfc6
 
Hans de Goede c8dfc6
 static void xhci_die(XHCIState *xhci)
Hans de Goede c8dfc6
@@ -701,8 +706,9 @@ static void xhci_die(XHCIState *xhci)
Hans de Goede c8dfc6
     fprintf(stderr, "xhci: asserted controller error\n");
Hans de Goede c8dfc6
 }
Hans de Goede c8dfc6
 
Hans de Goede c8dfc6
-static void xhci_write_event(XHCIState *xhci, XHCIEvent *event)
Hans de Goede c8dfc6
+static void xhci_write_event(XHCIState *xhci, XHCIEvent *event, int v)
Hans de Goede c8dfc6
 {
Hans de Goede c8dfc6
+    XHCIInterrupter *intr = &xhci->intr[v];
Hans de Goede c8dfc6
     XHCITRB ev_trb;
Hans de Goede c8dfc6
     dma_addr_t addr;
Hans de Goede c8dfc6
 
Hans de Goede c8dfc6
@@ -710,27 +716,28 @@ static void xhci_write_event(XHCIState *xhci, XHCIEvent *event)
Hans de Goede c8dfc6
     ev_trb.status = cpu_to_le32(event->length | (event->ccode << 24));
Hans de Goede c8dfc6
     ev_trb.control = (event->slotid << 24) | (event->epid << 16) |
Hans de Goede c8dfc6
                      event->flags | (event->type << TRB_TYPE_SHIFT);
Hans de Goede c8dfc6
-    if (xhci->er_pcs) {
Hans de Goede c8dfc6
+    if (intr->er_pcs) {
Hans de Goede c8dfc6
         ev_trb.control |= TRB_C;
Hans de Goede c8dfc6
     }
Hans de Goede c8dfc6
     ev_trb.control = cpu_to_le32(ev_trb.control);
Hans de Goede c8dfc6
 
Hans de Goede c8dfc6
-    trace_usb_xhci_queue_event(xhci->er_ep_idx, trb_name(&ev_trb),
Hans de Goede c8dfc6
+    trace_usb_xhci_queue_event(v, intr->er_ep_idx, trb_name(&ev_trb),
Hans de Goede c8dfc6
                                event_name(event), ev_trb.parameter,
Hans de Goede c8dfc6
                                ev_trb.status, ev_trb.control);
Hans de Goede c8dfc6
 
Hans de Goede c8dfc6
-    addr = xhci->er_start + TRB_SIZE*xhci->er_ep_idx;
Hans de Goede c8dfc6
+    addr = intr->er_start + TRB_SIZE*intr->er_ep_idx;
Hans de Goede c8dfc6
     pci_dma_write(&xhci->pci_dev, addr, &ev_trb, TRB_SIZE);
Hans de Goede c8dfc6
 
Hans de Goede c8dfc6
-    xhci->er_ep_idx++;
Hans de Goede c8dfc6
-    if (xhci->er_ep_idx >= xhci->er_size) {
Hans de Goede c8dfc6
-        xhci->er_ep_idx = 0;
Hans de Goede c8dfc6
-        xhci->er_pcs = !xhci->er_pcs;
Hans de Goede c8dfc6
+    intr->er_ep_idx++;
Hans de Goede c8dfc6
+    if (intr->er_ep_idx >= intr->er_size) {
Hans de Goede c8dfc6
+        intr->er_ep_idx = 0;
Hans de Goede c8dfc6
+        intr->er_pcs = !intr->er_pcs;
Hans de Goede c8dfc6
     }
Hans de Goede c8dfc6
 }
Hans de Goede c8dfc6
 
Hans de Goede c8dfc6
-static void xhci_events_update(XHCIState *xhci)
Hans de Goede c8dfc6
+static void xhci_events_update(XHCIState *xhci, int v)
Hans de Goede c8dfc6
 {
Hans de Goede c8dfc6
+    XHCIInterrupter *intr = &xhci->intr[v];
Hans de Goede c8dfc6
     dma_addr_t erdp;
Hans de Goede c8dfc6
     unsigned int dp_idx;
Hans de Goede c8dfc6
     bool do_irq = 0;
Hans de Goede c8dfc6
@@ -739,115 +746,116 @@ static void xhci_events_update(XHCIState *xhci)
Hans de Goede c8dfc6
         return;
Hans de Goede c8dfc6
     }
Hans de Goede c8dfc6
 
Hans de Goede c8dfc6
-    erdp = xhci_addr64(xhci->erdp_low, xhci->erdp_high);
Hans de Goede c8dfc6
-    if (erdp < xhci->er_start ||
Hans de Goede c8dfc6
-        erdp >= (xhci->er_start + TRB_SIZE*xhci->er_size)) {
Hans de Goede c8dfc6
+    erdp = xhci_addr64(intr->erdp_low, intr->erdp_high);
Hans de Goede c8dfc6
+    if (erdp < intr->er_start ||
Hans de Goede c8dfc6
+        erdp >= (intr->er_start + TRB_SIZE*intr->er_size)) {
Hans de Goede c8dfc6
         fprintf(stderr, "xhci: ERDP out of bounds: "DMA_ADDR_FMT"\n", erdp);
Hans de Goede c8dfc6
-        fprintf(stderr, "xhci: ER at "DMA_ADDR_FMT" len %d\n",
Hans de Goede c8dfc6
-                xhci->er_start, xhci->er_size);
Hans de Goede c8dfc6
+        fprintf(stderr, "xhci: ER[%d] at "DMA_ADDR_FMT" len %d\n",
Hans de Goede c8dfc6
+                v, intr->er_start, intr->er_size);
Hans de Goede c8dfc6
         xhci_die(xhci);
Hans de Goede c8dfc6
         return;
Hans de Goede c8dfc6
     }
Hans de Goede c8dfc6
-    dp_idx = (erdp - xhci->er_start) / TRB_SIZE;
Hans de Goede c8dfc6
-    assert(dp_idx < xhci->er_size);
Hans de Goede c8dfc6
+    dp_idx = (erdp - intr->er_start) / TRB_SIZE;
Hans de Goede c8dfc6
+    assert(dp_idx < intr->er_size);
Hans de Goede c8dfc6
 
Hans de Goede c8dfc6
     /* NEC didn't read section 4.9.4 of the spec (v1.0 p139 top Note) and thus
Hans de Goede c8dfc6
      * deadlocks when the ER is full. Hack it by holding off events until
Hans de Goede c8dfc6
      * the driver decides to free at least half of the ring */
Hans de Goede c8dfc6
-    if (xhci->er_full) {
Hans de Goede c8dfc6
-        int er_free = dp_idx - xhci->er_ep_idx;
Hans de Goede c8dfc6
+    if (intr->er_full) {
Hans de Goede c8dfc6
+        int er_free = dp_idx - intr->er_ep_idx;
Hans de Goede c8dfc6
         if (er_free <= 0) {
Hans de Goede c8dfc6
-            er_free += xhci->er_size;
Hans de Goede c8dfc6
+            er_free += intr->er_size;
Hans de Goede c8dfc6
         }
Hans de Goede c8dfc6
-        if (er_free < (xhci->er_size/2)) {
Hans de Goede c8dfc6
+        if (er_free < (intr->er_size/2)) {
Hans de Goede c8dfc6
             DPRINTF("xhci_events_update(): event ring still "
Hans de Goede c8dfc6
                     "more than half full (hack)\n");
Hans de Goede c8dfc6
             return;
Hans de Goede c8dfc6
         }
Hans de Goede c8dfc6
     }
Hans de Goede c8dfc6
 
Hans de Goede c8dfc6
-    while (xhci->ev_buffer_put != xhci->ev_buffer_get) {
Hans de Goede c8dfc6
-        assert(xhci->er_full);
Hans de Goede c8dfc6
-        if (((xhci->er_ep_idx+1) % xhci->er_size) == dp_idx) {
Hans de Goede c8dfc6
+    while (intr->ev_buffer_put != intr->ev_buffer_get) {
Hans de Goede c8dfc6
+        assert(intr->er_full);
Hans de Goede c8dfc6
+        if (((intr->er_ep_idx+1) % intr->er_size) == dp_idx) {
Hans de Goede c8dfc6
             DPRINTF("xhci_events_update(): event ring full again\n");
Hans de Goede c8dfc6
 #ifndef ER_FULL_HACK
Hans de Goede c8dfc6
             XHCIEvent full = {ER_HOST_CONTROLLER, CC_EVENT_RING_FULL_ERROR};
Hans de Goede c8dfc6
-            xhci_write_event(xhci, &full);
Hans de Goede c8dfc6
+            xhci_write_event(xhci, &full, v);
Hans de Goede c8dfc6
 #endif
Hans de Goede c8dfc6
             do_irq = 1;
Hans de Goede c8dfc6
             break;
Hans de Goede c8dfc6
         }
Hans de Goede c8dfc6
-        XHCIEvent *event = &xhci->ev_buffer[xhci->ev_buffer_get];
Hans de Goede c8dfc6
-        xhci_write_event(xhci, event);
Hans de Goede c8dfc6
-        xhci->ev_buffer_get++;
Hans de Goede c8dfc6
+        XHCIEvent *event = &intr->ev_buffer[intr->ev_buffer_get];
Hans de Goede c8dfc6
+        xhci_write_event(xhci, event, v);
Hans de Goede c8dfc6
+        intr->ev_buffer_get++;
Hans de Goede c8dfc6
         do_irq = 1;
Hans de Goede c8dfc6
-        if (xhci->ev_buffer_get == EV_QUEUE) {
Hans de Goede c8dfc6
-            xhci->ev_buffer_get = 0;
Hans de Goede c8dfc6
+        if (intr->ev_buffer_get == EV_QUEUE) {
Hans de Goede c8dfc6
+            intr->ev_buffer_get = 0;
Hans de Goede c8dfc6
         }
Hans de Goede c8dfc6
     }
Hans de Goede c8dfc6
 
Hans de Goede c8dfc6
     if (do_irq) {
Hans de Goede c8dfc6
-        xhci_intr_raise(xhci);
Hans de Goede c8dfc6
+        xhci_intr_raise(xhci, v);
Hans de Goede c8dfc6
     }
Hans de Goede c8dfc6
 
Hans de Goede c8dfc6
-    if (xhci->er_full && xhci->ev_buffer_put == xhci->ev_buffer_get) {
Hans de Goede c8dfc6
+    if (intr->er_full && intr->ev_buffer_put == intr->ev_buffer_get) {
Hans de Goede c8dfc6
         DPRINTF("xhci_events_update(): event ring no longer full\n");
Hans de Goede c8dfc6
-        xhci->er_full = 0;
Hans de Goede c8dfc6
+        intr->er_full = 0;
Hans de Goede c8dfc6
     }
Hans de Goede c8dfc6
     return;
Hans de Goede c8dfc6
 }
Hans de Goede c8dfc6
 
Hans de Goede c8dfc6
-static void xhci_event(XHCIState *xhci, XHCIEvent *event)
Hans de Goede c8dfc6
+static void xhci_event(XHCIState *xhci, XHCIEvent *event, int v)
Hans de Goede c8dfc6
 {
Hans de Goede c8dfc6
+    XHCIInterrupter *intr = &xhci->intr[v];
Hans de Goede c8dfc6
     dma_addr_t erdp;
Hans de Goede c8dfc6
     unsigned int dp_idx;
Hans de Goede c8dfc6
 
Hans de Goede c8dfc6
-    if (xhci->er_full) {
Hans de Goede c8dfc6
+    if (intr->er_full) {
Hans de Goede c8dfc6
         DPRINTF("xhci_event(): ER full, queueing\n");
Hans de Goede c8dfc6
-        if (((xhci->ev_buffer_put+1) % EV_QUEUE) == xhci->ev_buffer_get) {
Hans de Goede c8dfc6
+        if (((intr->ev_buffer_put+1) % EV_QUEUE) == intr->ev_buffer_get) {
Hans de Goede c8dfc6
             fprintf(stderr, "xhci: event queue full, dropping event!\n");
Hans de Goede c8dfc6
             return;
Hans de Goede c8dfc6
         }
Hans de Goede c8dfc6
-        xhci->ev_buffer[xhci->ev_buffer_put++] = *event;
Hans de Goede c8dfc6
-        if (xhci->ev_buffer_put == EV_QUEUE) {
Hans de Goede c8dfc6
-            xhci->ev_buffer_put = 0;
Hans de Goede c8dfc6
+        intr->ev_buffer[intr->ev_buffer_put++] = *event;
Hans de Goede c8dfc6
+        if (intr->ev_buffer_put == EV_QUEUE) {
Hans de Goede c8dfc6
+            intr->ev_buffer_put = 0;
Hans de Goede c8dfc6
         }
Hans de Goede c8dfc6
         return;
Hans de Goede c8dfc6
     }
Hans de Goede c8dfc6
 
Hans de Goede c8dfc6
-    erdp = xhci_addr64(xhci->erdp_low, xhci->erdp_high);
Hans de Goede c8dfc6
-    if (erdp < xhci->er_start ||
Hans de Goede c8dfc6
-        erdp >= (xhci->er_start + TRB_SIZE*xhci->er_size)) {
Hans de Goede c8dfc6
+    erdp = xhci_addr64(intr->erdp_low, intr->erdp_high);
Hans de Goede c8dfc6
+    if (erdp < intr->er_start ||
Hans de Goede c8dfc6
+        erdp >= (intr->er_start + TRB_SIZE*intr->er_size)) {
Hans de Goede c8dfc6
         fprintf(stderr, "xhci: ERDP out of bounds: "DMA_ADDR_FMT"\n", erdp);
Hans de Goede c8dfc6
-        fprintf(stderr, "xhci: ER at "DMA_ADDR_FMT" len %d\n",
Hans de Goede c8dfc6
-                xhci->er_start, xhci->er_size);
Hans de Goede c8dfc6
+        fprintf(stderr, "xhci: ER[%d] at "DMA_ADDR_FMT" len %d\n",
Hans de Goede c8dfc6
+                v, intr->er_start, intr->er_size);
Hans de Goede c8dfc6
         xhci_die(xhci);
Hans de Goede c8dfc6
         return;
Hans de Goede c8dfc6
     }
Hans de Goede c8dfc6
 
Hans de Goede c8dfc6
-    dp_idx = (erdp - xhci->er_start) / TRB_SIZE;
Hans de Goede c8dfc6
-    assert(dp_idx < xhci->er_size);
Hans de Goede c8dfc6
+    dp_idx = (erdp - intr->er_start) / TRB_SIZE;
Hans de Goede c8dfc6
+    assert(dp_idx < intr->er_size);
Hans de Goede c8dfc6
 
Hans de Goede c8dfc6
-    if ((xhci->er_ep_idx+1) % xhci->er_size == dp_idx) {
Hans de Goede c8dfc6
+    if ((intr->er_ep_idx+1) % intr->er_size == dp_idx) {
Hans de Goede c8dfc6
         DPRINTF("xhci_event(): ER full, queueing\n");
Hans de Goede c8dfc6
 #ifndef ER_FULL_HACK
Hans de Goede c8dfc6
         XHCIEvent full = {ER_HOST_CONTROLLER, CC_EVENT_RING_FULL_ERROR};
Hans de Goede c8dfc6
         xhci_write_event(xhci, &full);
Hans de Goede c8dfc6
 #endif
Hans de Goede c8dfc6
-        xhci->er_full = 1;
Hans de Goede c8dfc6
-        if (((xhci->ev_buffer_put+1) % EV_QUEUE) == xhci->ev_buffer_get) {
Hans de Goede c8dfc6
+        intr->er_full = 1;
Hans de Goede c8dfc6
+        if (((intr->ev_buffer_put+1) % EV_QUEUE) == intr->ev_buffer_get) {
Hans de Goede c8dfc6
             fprintf(stderr, "xhci: event queue full, dropping event!\n");
Hans de Goede c8dfc6
             return;
Hans de Goede c8dfc6
         }
Hans de Goede c8dfc6
-        xhci->ev_buffer[xhci->ev_buffer_put++] = *event;
Hans de Goede c8dfc6
-        if (xhci->ev_buffer_put == EV_QUEUE) {
Hans de Goede c8dfc6
-            xhci->ev_buffer_put = 0;
Hans de Goede c8dfc6
+        intr->ev_buffer[intr->ev_buffer_put++] = *event;
Hans de Goede c8dfc6
+        if (intr->ev_buffer_put == EV_QUEUE) {
Hans de Goede c8dfc6
+            intr->ev_buffer_put = 0;
Hans de Goede c8dfc6
         }
Hans de Goede c8dfc6
     } else {
Hans de Goede c8dfc6
-        xhci_write_event(xhci, event);
Hans de Goede c8dfc6
+        xhci_write_event(xhci, event, v);
Hans de Goede c8dfc6
     }
Hans de Goede c8dfc6
 
Hans de Goede c8dfc6
-    xhci_intr_raise(xhci);
Hans de Goede c8dfc6
+    xhci_intr_raise(xhci, v);
Hans de Goede c8dfc6
 }
Hans de Goede c8dfc6
 
Hans de Goede c8dfc6
 static void xhci_ring_init(XHCIState *xhci, XHCIRing *ring,
Hans de Goede c8dfc6
@@ -939,17 +947,18 @@ static int xhci_ring_chain_length(XHCIState *xhci, const XHCIRing *ring)
Hans de Goede c8dfc6
     }
Hans de Goede c8dfc6
 }
Hans de Goede c8dfc6
 
Hans de Goede c8dfc6
-static void xhci_er_reset(XHCIState *xhci)
Hans de Goede c8dfc6
+static void xhci_er_reset(XHCIState *xhci, int v)
Hans de Goede c8dfc6
 {
Hans de Goede c8dfc6
+    XHCIInterrupter *intr = &xhci->intr[v];
Hans de Goede c8dfc6
     XHCIEvRingSeg seg;
Hans de Goede c8dfc6
 
Hans de Goede c8dfc6
     /* cache the (sole) event ring segment location */
Hans de Goede c8dfc6
-    if (xhci->erstsz != 1) {
Hans de Goede c8dfc6
-        fprintf(stderr, "xhci: invalid value for ERSTSZ: %d\n", xhci->erstsz);
Hans de Goede c8dfc6
+    if (intr->erstsz != 1) {
Hans de Goede c8dfc6
+        fprintf(stderr, "xhci: invalid value for ERSTSZ: %d\n", intr->erstsz);
Hans de Goede c8dfc6
         xhci_die(xhci);
Hans de Goede c8dfc6
         return;
Hans de Goede c8dfc6
     }
Hans de Goede c8dfc6
-    dma_addr_t erstba = xhci_addr64(xhci->erstba_low, xhci->erstba_high);
Hans de Goede c8dfc6
+    dma_addr_t erstba = xhci_addr64(intr->erstba_low, intr->erstba_high);
Hans de Goede c8dfc6
     pci_dma_read(&xhci->pci_dev, erstba, &seg, sizeof(seg));
Hans de Goede c8dfc6
     le32_to_cpus(&seg.addr_low);
Hans de Goede c8dfc6
     le32_to_cpus(&seg.addr_high);
Hans de Goede c8dfc6
@@ -959,15 +968,15 @@ static void xhci_er_reset(XHCIState *xhci)
Hans de Goede c8dfc6
         xhci_die(xhci);
Hans de Goede c8dfc6
         return;
Hans de Goede c8dfc6
     }
Hans de Goede c8dfc6
-    xhci->er_start = xhci_addr64(seg.addr_low, seg.addr_high);
Hans de Goede c8dfc6
-    xhci->er_size = seg.size;
Hans de Goede c8dfc6
+    intr->er_start = xhci_addr64(seg.addr_low, seg.addr_high);
Hans de Goede c8dfc6
+    intr->er_size = seg.size;
Hans de Goede c8dfc6
 
Hans de Goede c8dfc6
-    xhci->er_ep_idx = 0;
Hans de Goede c8dfc6
-    xhci->er_pcs = 1;
Hans de Goede c8dfc6
-    xhci->er_full = 0;
Hans de Goede c8dfc6
+    intr->er_ep_idx = 0;
Hans de Goede c8dfc6
+    intr->er_pcs = 1;
Hans de Goede c8dfc6
+    intr->er_full = 0;
Hans de Goede c8dfc6
 
Hans de Goede c8dfc6
-    DPRINTF("xhci: event ring:" DMA_ADDR_FMT " [%d]\n",
Hans de Goede c8dfc6
-            xhci->er_start, xhci->er_size);
Hans de Goede c8dfc6
+    DPRINTF("xhci: event ring[%d]:" DMA_ADDR_FMT " [%d]\n",
Hans de Goede c8dfc6
+            v, intr->er_start, intr->er_size);
Hans de Goede c8dfc6
 }
Hans de Goede c8dfc6
 
Hans de Goede c8dfc6
 static void xhci_run(XHCIState *xhci)
Hans de Goede c8dfc6
@@ -1368,7 +1377,7 @@ static void xhci_xfer_report(XHCITransfer *xfer)
Hans de Goede c8dfc6
                 DPRINTF("xhci_xfer_data: EDTLA=%d\n", event.length);
Hans de Goede c8dfc6
                 edtla = 0;
Hans de Goede c8dfc6
             }
Hans de Goede c8dfc6
-            xhci_event(xhci, &event);
Hans de Goede c8dfc6
+            xhci_event(xhci, &event, 0 /* FIXME */);
Hans de Goede c8dfc6
             reported = 1;
Hans de Goede c8dfc6
             if (xfer->status != CC_SUCCESS) {
Hans de Goede c8dfc6
                 return;
5544c1
@@ -2244,7 +2253,7 @@ static void xhci_process_commands(XHCIState *xhci)
Hans de Goede c8dfc6
             break;
Hans de Goede c8dfc6
         }
Hans de Goede c8dfc6
         event.slotid = slotid;
Hans de Goede c8dfc6
-        xhci_event(xhci, &event);
Hans de Goede c8dfc6
+        xhci_event(xhci, &event, 0 /* FIXME */);
Hans de Goede c8dfc6
     }
Hans de Goede c8dfc6
 }
Hans de Goede c8dfc6
 
5544c1
@@ -2274,7 +2283,7 @@ static void xhci_update_port(XHCIState *xhci, XHCIPort *port, int is_detach)
Hans de Goede c8dfc6
         port->portsc |= PORTSC_CSC;
Hans de Goede c8dfc6
         XHCIEvent ev = { ER_PORT_STATUS_CHANGE, CC_SUCCESS,
Hans de Goede c8dfc6
                          port->portnr << 24};
Hans de Goede c8dfc6
-        xhci_event(xhci, &ev;;
Hans de Goede c8dfc6
+        xhci_event(xhci, &ev, 0 /* FIXME */);
Hans de Goede c8dfc6
         DPRINTF("xhci: port change event for port %d\n", port->portnr);
Hans de Goede c8dfc6
     }
Hans de Goede c8dfc6
 }
5544c1
@@ -2307,20 +2316,22 @@ static void xhci_reset(DeviceState *dev)
Hans de Goede c8dfc6
         xhci_update_port(xhci, xhci->ports + i, 0);
Hans de Goede c8dfc6
     }
Hans de Goede c8dfc6
 
Hans de Goede c8dfc6
-    xhci->iman = 0;
Hans de Goede c8dfc6
-    xhci->imod = 0;
Hans de Goede c8dfc6
-    xhci->erstsz = 0;
Hans de Goede c8dfc6
-    xhci->erstba_low = 0;
Hans de Goede c8dfc6
-    xhci->erstba_high = 0;
Hans de Goede c8dfc6
-    xhci->erdp_low = 0;
Hans de Goede c8dfc6
-    xhci->erdp_high = 0;
Hans de Goede c8dfc6
-    xhci->msix_used = 0;
Hans de Goede c8dfc6
+    for (i = 0; i < MAXINTRS; i++) {
Hans de Goede c8dfc6
+        xhci->intr[i].iman = 0;
Hans de Goede c8dfc6
+        xhci->intr[i].imod = 0;
Hans de Goede c8dfc6
+        xhci->intr[i].erstsz = 0;
Hans de Goede c8dfc6
+        xhci->intr[i].erstba_low = 0;
Hans de Goede c8dfc6
+        xhci->intr[i].erstba_high = 0;
Hans de Goede c8dfc6
+        xhci->intr[i].erdp_low = 0;
Hans de Goede c8dfc6
+        xhci->intr[i].erdp_high = 0;
Hans de Goede c8dfc6
+        xhci->intr[i].msix_used = 0;
Hans de Goede c8dfc6
 
Hans de Goede c8dfc6
-    xhci->er_ep_idx = 0;
Hans de Goede c8dfc6
-    xhci->er_pcs = 1;
Hans de Goede c8dfc6
-    xhci->er_full = 0;
Hans de Goede c8dfc6
-    xhci->ev_buffer_put = 0;
Hans de Goede c8dfc6
-    xhci->ev_buffer_get = 0;
Hans de Goede c8dfc6
+        xhci->intr[i].er_ep_idx = 0;
Hans de Goede c8dfc6
+        xhci->intr[i].er_pcs = 1;
Hans de Goede c8dfc6
+        xhci->intr[i].er_full = 0;
Hans de Goede c8dfc6
+        xhci->intr[i].ev_buffer_put = 0;
Hans de Goede c8dfc6
+        xhci->intr[i].ev_buffer_get = 0;
Hans de Goede c8dfc6
+    }
Hans de Goede c8dfc6
 
Hans de Goede c8dfc6
     xhci->mfindex_start = qemu_get_clock_ns(vm_clock);
Hans de Goede c8dfc6
     xhci_mfwrap_update(xhci);
5544c1
@@ -2551,7 +2562,7 @@ static void xhci_oper_write(XHCIState *xhci, uint32_t reg, uint32_t val)
Hans de Goede c8dfc6
         if (xhci->crcr_low & (CRCR_CA|CRCR_CS) && (xhci->crcr_low & CRCR_CRR)) {
Hans de Goede c8dfc6
             XHCIEvent event = {ER_COMMAND_COMPLETE, CC_COMMAND_RING_STOPPED};
Hans de Goede c8dfc6
             xhci->crcr_low &= ~CRCR_CRR;
Hans de Goede c8dfc6
-            xhci_event(xhci, &event);
Hans de Goede c8dfc6
+            xhci_event(xhci, &event, 0 /* FIXME */);
Hans de Goede c8dfc6
             DPRINTF("xhci: command ring stopped (CRCR=%08x)\n", xhci->crcr_low);
Hans de Goede c8dfc6
         } else {
Hans de Goede c8dfc6
             dma_addr_t base = xhci_addr64(xhci->crcr_low & ~0x3f, val);
5544c1
@@ -2575,6 +2586,7 @@ static void xhci_oper_write(XHCIState *xhci, uint32_t reg, uint32_t val)
Hans de Goede c8dfc6
 
Hans de Goede c8dfc6
 static uint32_t xhci_runtime_read(XHCIState *xhci, uint32_t reg)
Hans de Goede c8dfc6
 {
Hans de Goede c8dfc6
+    XHCIInterrupter *intr = &xhci->intr[0];
Hans de Goede c8dfc6
     uint32_t ret;
Hans de Goede c8dfc6
 
Hans de Goede c8dfc6
     switch (reg) {
5544c1
@@ -2582,25 +2594,25 @@ static uint32_t xhci_runtime_read(XHCIState *xhci, uint32_t reg)
Hans de Goede c8dfc6
         ret = xhci_mfindex_get(xhci) & 0x3fff;
Hans de Goede c8dfc6
         break;
Hans de Goede c8dfc6
     case 0x20: /* IMAN */
Hans de Goede c8dfc6
-        ret = xhci->iman;
Hans de Goede c8dfc6
+        ret = intr->iman;
Hans de Goede c8dfc6
         break;
Hans de Goede c8dfc6
     case 0x24: /* IMOD */
Hans de Goede c8dfc6
-        ret = xhci->imod;
Hans de Goede c8dfc6
+        ret = intr->imod;
Hans de Goede c8dfc6
         break;
Hans de Goede c8dfc6
     case 0x28: /* ERSTSZ */
Hans de Goede c8dfc6
-        ret = xhci->erstsz;
Hans de Goede c8dfc6
+        ret = intr->erstsz;
Hans de Goede c8dfc6
         break;
Hans de Goede c8dfc6
     case 0x30: /* ERSTBA low */
Hans de Goede c8dfc6
-        ret = xhci->erstba_low;
Hans de Goede c8dfc6
+        ret = intr->erstba_low;
Hans de Goede c8dfc6
         break;
Hans de Goede c8dfc6
     case 0x34: /* ERSTBA high */
Hans de Goede c8dfc6
-        ret = xhci->erstba_high;
Hans de Goede c8dfc6
+        ret = intr->erstba_high;
Hans de Goede c8dfc6
         break;
Hans de Goede c8dfc6
     case 0x38: /* ERDP low */
Hans de Goede c8dfc6
-        ret = xhci->erdp_low;
Hans de Goede c8dfc6
+        ret = intr->erdp_low;
Hans de Goede c8dfc6
         break;
Hans de Goede c8dfc6
     case 0x3c: /* ERDP high */
Hans de Goede c8dfc6
-        ret = xhci->erdp_high;
Hans de Goede c8dfc6
+        ret = intr->erdp_high;
Hans de Goede c8dfc6
         break;
Hans de Goede c8dfc6
     default:
Hans de Goede c8dfc6
         fprintf(stderr, "xhci_runtime_read: reg 0x%x unimplemented\n", reg);
5544c1
@@ -2613,42 +2625,43 @@ static uint32_t xhci_runtime_read(XHCIState *xhci, uint32_t reg)
Hans de Goede c8dfc6
 
Hans de Goede c8dfc6
 static void xhci_runtime_write(XHCIState *xhci, uint32_t reg, uint32_t val)
Hans de Goede c8dfc6
 {
Hans de Goede c8dfc6
+    XHCIInterrupter *intr = &xhci->intr[0];
Hans de Goede c8dfc6
     trace_usb_xhci_runtime_write(reg, val);
Hans de Goede c8dfc6
 
Hans de Goede c8dfc6
     switch (reg) {
Hans de Goede c8dfc6
     case 0x20: /* IMAN */
Hans de Goede c8dfc6
         if (val & IMAN_IP) {
Hans de Goede c8dfc6
-            xhci->iman &= ~IMAN_IP;
Hans de Goede c8dfc6
+            intr->iman &= ~IMAN_IP;
Hans de Goede c8dfc6
         }
Hans de Goede c8dfc6
-        xhci->iman &= ~IMAN_IE;
Hans de Goede c8dfc6
-        xhci->iman |= val & IMAN_IE;
Hans de Goede c8dfc6
+        intr->iman &= ~IMAN_IE;
Hans de Goede c8dfc6
+        intr->iman |= val & IMAN_IE;
Hans de Goede c8dfc6
         xhci_intx_update(xhci);
Hans de Goede c8dfc6
-        xhci_msix_update(xhci);
Hans de Goede c8dfc6
+        xhci_msix_update(xhci, 0);
Hans de Goede c8dfc6
         break;
Hans de Goede c8dfc6
     case 0x24: /* IMOD */
Hans de Goede c8dfc6
-        xhci->imod = val;
Hans de Goede c8dfc6
+        intr->imod = val;
Hans de Goede c8dfc6
         break;
Hans de Goede c8dfc6
     case 0x28: /* ERSTSZ */
Hans de Goede c8dfc6
-        xhci->erstsz = val & 0xffff;
Hans de Goede c8dfc6
+        intr->erstsz = val & 0xffff;
Hans de Goede c8dfc6
         break;
Hans de Goede c8dfc6
     case 0x30: /* ERSTBA low */
Hans de Goede c8dfc6
         /* XXX NEC driver bug: it doesn't align this to 64 bytes
Hans de Goede c8dfc6
-        xhci->erstba_low = val & 0xffffffc0; */
Hans de Goede c8dfc6
-        xhci->erstba_low = val & 0xfffffff0;
Hans de Goede c8dfc6
+        intr->erstba_low = val & 0xffffffc0; */
Hans de Goede c8dfc6
+        intr->erstba_low = val & 0xfffffff0;
Hans de Goede c8dfc6
         break;
Hans de Goede c8dfc6
     case 0x34: /* ERSTBA high */
Hans de Goede c8dfc6
-        xhci->erstba_high = val;
Hans de Goede c8dfc6
-        xhci_er_reset(xhci);
Hans de Goede c8dfc6
+        intr->erstba_high = val;
Hans de Goede c8dfc6
+        xhci_er_reset(xhci, 0);
Hans de Goede c8dfc6
         break;
Hans de Goede c8dfc6
     case 0x38: /* ERDP low */
Hans de Goede c8dfc6
         if (val & ERDP_EHB) {
Hans de Goede c8dfc6
-            xhci->erdp_low &= ~ERDP_EHB;
Hans de Goede c8dfc6
+            intr->erdp_low &= ~ERDP_EHB;
Hans de Goede c8dfc6
         }
Hans de Goede c8dfc6
-        xhci->erdp_low = (val & ~ERDP_EHB) | (xhci->erdp_low & ERDP_EHB);
Hans de Goede c8dfc6
+        intr->erdp_low = (val & ~ERDP_EHB) | (intr->erdp_low & ERDP_EHB);
Hans de Goede c8dfc6
         break;
Hans de Goede c8dfc6
     case 0x3c: /* ERDP high */
Hans de Goede c8dfc6
-        xhci->erdp_high = val;
Hans de Goede c8dfc6
-        xhci_events_update(xhci);
Hans de Goede c8dfc6
+        intr->erdp_high = val;
Hans de Goede c8dfc6
+        xhci_events_update(xhci, 0);
Hans de Goede c8dfc6
         break;
Hans de Goede c8dfc6
     default:
Hans de Goede c8dfc6
         fprintf(stderr, "xhci_oper_write: reg 0x%x unimplemented\n", reg);
Hans de Goede c8dfc6
@@ -2780,7 +2793,7 @@ static void xhci_wakeup(USBPort *usbport)
Hans de Goede c8dfc6
         return;
Hans de Goede c8dfc6
     }
Hans de Goede c8dfc6
     port->portsc |= PORTSC_PLC;
Hans de Goede c8dfc6
-    xhci_event(xhci, &ev;;
Hans de Goede c8dfc6
+    xhci_event(xhci, &ev, 0 /* FIXME */);
Hans de Goede c8dfc6
 }
Hans de Goede c8dfc6
 
Hans de Goede c8dfc6
 static void xhci_complete(USBPort *port, USBPacket *packet)
Hans de Goede c8dfc6
diff --git a/trace-events b/trace-events
5544c1
index f86bbda..f5b5097 100644
Hans de Goede c8dfc6
--- a/trace-events
Hans de Goede c8dfc6
+++ b/trace-events
5544c1
@@ -319,7 +319,7 @@ usb_xhci_irq_msi(uint32_t nr) "nr %d"
Hans de Goede c8dfc6
 usb_xhci_irq_msix(uint32_t nr) "nr %d"
Hans de Goede c8dfc6
 usb_xhci_irq_msix_use(uint32_t nr) "nr %d"
Hans de Goede c8dfc6
 usb_xhci_irq_msix_unuse(uint32_t nr) "nr %d"
Hans de Goede c8dfc6
-usb_xhci_queue_event(uint32_t idx, const char *trb, const char *evt, uint64_t param, uint32_t status, uint32_t control) "idx %d, %s, %s, p %016" PRIx64 ", s %08x, c 0x%08x"
Hans de Goede c8dfc6
+usb_xhci_queue_event(uint32_t vector, uint32_t idx, const char *trb, const char *evt, uint64_t param, uint32_t status, uint32_t control) "v %d, idx %d, %s, %s, p %016" PRIx64 ", s %08x, c 0x%08x"
Hans de Goede c8dfc6
 usb_xhci_fetch_trb(uint64_t addr, const char *name, uint64_t param, uint32_t status, uint32_t control) "addr %016" PRIx64 ", %s, p %016" PRIx64 ", s %08x, c 0x%08x"
Hans de Goede c8dfc6
 usb_xhci_slot_enable(uint32_t slotid) "slotid %d"
Hans de Goede c8dfc6
 usb_xhci_slot_disable(uint32_t slotid) "slotid %d"
Hans de Goede c8dfc6
-- 
5544c1
1.7.12.1
Hans de Goede c8dfc6