aboutsummaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
authorYuri Benditovich <yuri.benditovich@janustech.com>2019-01-28 20:05:09 +0000
committerGerd Hoffmann <kraxel@redhat.com>2019-01-30 06:47:52 +0100
commitb4329d1a2a42d3c49ac4b76ec86b6c9db19ea1e9 (patch)
treed774c2e6d006f11c372d225fa3a5616cc74517e5 /hw
parenta587c832a3f1d6d47dce93bda52c80cfa163e7cf (diff)
downloadqemu-b4329d1a2a42d3c49ac4b76ec86b6c9db19ea1e9.zip
qemu-b4329d1a2a42d3c49ac4b76ec86b6c9db19ea1e9.tar.gz
qemu-b4329d1a2a42d3c49ac4b76ec86b6c9db19ea1e9.tar.bz2
usb: implement XHCI underrun/overrun events
Implement underrun/overrun events of isochronous endpoints according to XHCI spec (4.10.3.1) Guest software restarts data streaming when receives these events. The XHCI reports these events using interrupter assigned to the slot (as these events do not have TRB), so current commit adds the field of assigned interrupter to the XHCISlot structure. Guest software assigns interrupter to the slot on 'Address Device' and 'Evaluate Context' commands. Signed-off-by: Yuri Benditovich <yuri.benditovich@janustech.com> Message-id: 20190128200444.5128-3-yuri.benditovich@janustech.com Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Diffstat (limited to 'hw')
-rw-r--r--hw/usb/hcd-xhci.c17
-rw-r--r--hw/usb/hcd-xhci.h1
2 files changed, 16 insertions, 2 deletions
diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c
index 1a8fd96..19c64f7 100644
--- a/hw/usb/hcd-xhci.c
+++ b/hw/usb/hcd-xhci.c
@@ -1949,6 +1949,16 @@ static void xhci_kick_epctx(XHCIEPContext *epctx, unsigned int streamid)
while (1) {
length = xhci_ring_chain_length(xhci, ring);
if (length <= 0) {
+ if (epctx->type == ET_ISO_OUT || epctx->type == ET_ISO_IN) {
+ /* 4.10.3.1 */
+ XHCIEvent ev = { ER_TRANSFER };
+ ev.ccode = epctx->type == ET_ISO_IN ?
+ CC_RING_OVERRUN : CC_RING_UNDERRUN;
+ ev.slotid = epctx->slotid;
+ ev.epid = epctx->epid;
+ ev.ptr = epctx->ring.dequeue;
+ xhci_event(xhci, &ev, xhci->slots[epctx->slotid-1].intr);
+ }
break;
}
xfer = xhci_ep_alloc_xfer(epctx, length);
@@ -2028,6 +2038,7 @@ static TRBCCode xhci_disable_slot(XHCIState *xhci, unsigned int slotid)
xhci->slots[slotid-1].enabled = 0;
xhci->slots[slotid-1].addressed = 0;
xhci->slots[slotid-1].uport = NULL;
+ xhci->slots[slotid-1].intr = 0;
return CC_SUCCESS;
}
@@ -2127,6 +2138,7 @@ static TRBCCode xhci_address_slot(XHCIState *xhci, unsigned int slotid,
slot = &xhci->slots[slotid-1];
slot->uport = uport;
slot->ctx = octx;
+ slot->intr = get_field(slot_ctx[2], TRB_INTR);
/* Make sure device is in USB_STATE_DEFAULT state */
usb_device_reset(dev);
@@ -2300,8 +2312,9 @@ static TRBCCode xhci_evaluate_slot(XHCIState *xhci, unsigned int slotid,
slot_ctx[1] &= ~0xFFFF; /* max exit latency */
slot_ctx[1] |= islot_ctx[1] & 0xFFFF;
- slot_ctx[2] &= ~0xFF00000; /* interrupter target */
- slot_ctx[2] |= islot_ctx[2] & 0xFF000000;
+ /* update interrupter target field */
+ xhci->slots[slotid-1].intr = get_field(islot_ctx[2], TRB_INTR);
+ set_field(&slot_ctx[2], xhci->slots[slotid-1].intr, TRB_INTR);
DPRINTF("xhci: output slot context: %08x %08x %08x %08x\n",
slot_ctx[0], slot_ctx[1], slot_ctx[2], slot_ctx[3]);
diff --git a/hw/usb/hcd-xhci.h b/hw/usb/hcd-xhci.h
index fc36a4c..240caa4 100644
--- a/hw/usb/hcd-xhci.h
+++ b/hw/usb/hcd-xhci.h
@@ -140,6 +140,7 @@ typedef struct XHCIPort {
typedef struct XHCISlot {
bool enabled;
bool addressed;
+ uint16_t intr;
dma_addr_t ctx;
USBPort *uport;
XHCIEPContext *eps[31];