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;
|
||||
USBEndpoint *ep;
|
||||
QTAILQ_ENTRY(UHCIQueue) next;
|
||||
QTAILQ_HEAD(, UHCIAsync) asyncs;
|
||||
QTAILQ_HEAD(asyncs_head, UHCIAsync) asyncs;
|
||||
int8_t valid;
|
||||
};
|
||||
|
||||
@ -843,15 +843,25 @@ static int uhci_handle_td(UHCIState *s, UHCIQueue *q, uint32_t qh_addr,
|
||||
}
|
||||
|
||||
if (async) {
|
||||
if (!async->done)
|
||||
return TD_RESULT_ASYNC_CONT;
|
||||
if (queuing) {
|
||||
/* we are busy filling the queue, we are not prepared
|
||||
to consume completed packages then, just leave them
|
||||
in async state */
|
||||
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);
|
||||
goto done;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user