uhci: Retry to fill the queue while waiting for td completion
If the guest is using multiple transfers to try and keep the usb bus busy / used at maximum efficiency, currently we would see / do the following: 1) submit transfer 1 to the device 2) submit transfer 2 to the device 3) report transfer 1 completion to guest 4) report transfer 2 completion to guest 5) submit transfer 1 to the device 6) report transfer 1 completion to guest 7) submit transfer 2 to the device 8) report transfer 2 completion to guest etc. So after the initial submission we would effectively only have 1 transfer in flight, rather then 2. This is caused by us not checking the queue for addition of new transfers by the guest (ie the resubmission of a recently finished transfer), while waiting for a pending transfer to complete. This patch does add a check for this, changing the sequence to: 1) submit transfer 1 to the device 2) submit transfer 2 to the device 3) report transfer 1 completion to guest 4) submit transfer 1 to the device 5) report transfer 2 completion to guest 6) submit transfer 2 to the device etc. Thus keeping 2 transfers in flight (most of the time, and always 1), as intended by the guest. Signed-off-by: Hans de Goede <hdegoede@redhat.com> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
This commit is contained in:
parent
3905097ea8
commit
8928c9c43d
|
@ -110,7 +110,7 @@ struct UHCIQueue {
|
||||||
UHCIState *uhci;
|
UHCIState *uhci;
|
||||||
USBEndpoint *ep;
|
USBEndpoint *ep;
|
||||||
QTAILQ_ENTRY(UHCIQueue) next;
|
QTAILQ_ENTRY(UHCIQueue) next;
|
||||||
QTAILQ_HEAD(, UHCIAsync) asyncs;
|
QTAILQ_HEAD(asyncs_head, UHCIAsync) asyncs;
|
||||||
int8_t valid;
|
int8_t valid;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -843,15 +843,25 @@ static int uhci_handle_td(UHCIState *s, UHCIQueue *q, uint32_t qh_addr,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (async) {
|
if (async) {
|
||||||
if (!async->done)
|
|
||||||
return TD_RESULT_ASYNC_CONT;
|
|
||||||
if (queuing) {
|
if (queuing) {
|
||||||
/* we are busy filling the queue, we are not prepared
|
/* we are busy filling the queue, we are not prepared
|
||||||
to consume completed packages then, just leave them
|
to consume completed packages then, just leave them
|
||||||
in async state */
|
in async state */
|
||||||
return TD_RESULT_ASYNC_CONT;
|
return TD_RESULT_ASYNC_CONT;
|
||||||
}
|
}
|
||||||
|
if (!async->done) {
|
||||||
|
UHCI_TD last_td;
|
||||||
|
UHCIAsync *last = QTAILQ_LAST(&async->queue->asyncs, asyncs_head);
|
||||||
|
/*
|
||||||
|
* While we are waiting for the current td to complete, the guest
|
||||||
|
* may have added more tds to the queue. Note we re-read the td
|
||||||
|
* rather then caching it, as we want to see guest made changes!
|
||||||
|
*/
|
||||||
|
uhci_read_td(s, &last_td, last->td_addr);
|
||||||
|
uhci_queue_fill(async->queue, &last_td);
|
||||||
|
|
||||||
|
return TD_RESULT_ASYNC_CONT;
|
||||||
|
}
|
||||||
uhci_async_unlink(async);
|
uhci_async_unlink(async);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue