From: Hans de Goede Date: Wed, 24 Oct 2012 16:14:04 +0000 (+0200) Subject: ehci: Retry to fill the queue while waiting for td completion X-Git-Tag: TizenStudio_2.0_p2.3.2~208^2~3171^2~28 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=b4ea86649915eca5551a5166f76e7a9d9032de50;p=sdk%2Femulator%2Fqemu.git ehci: 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 Signed-off-by: Gerd Hoffmann --- diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c index 8bd87c7..a02fe96 100644 --- a/hw/usb/hcd-ehci.c +++ b/hw/usb/hcd-ehci.c @@ -381,7 +381,7 @@ struct EHCIQueue { uint32_t qhaddr; /* address QH read from */ uint32_t qtdaddr; /* address QTD read from */ USBDevice *dev; - QTAILQ_HEAD(, EHCIPacket) packets; + QTAILQ_HEAD(pkts_head, EHCIPacket) packets; }; typedef QTAILQ_HEAD(EHCIQueueHead, EHCIQueue) EHCIQueueHead; @@ -488,6 +488,7 @@ static const char *ehci_mmio_names[] = { static int ehci_state_executing(EHCIQueue *q); static int ehci_state_writeback(EHCIQueue *q); +static int ehci_fill_queue(EHCIPacket *p); static const char *nr2str(const char **n, size_t len, uint32_t nr) { @@ -1994,7 +1995,7 @@ static int ehci_state_fetchqtd(EHCIQueue *q) { EHCIqtd qtd; EHCIPacket *p; - int again = 0; + int again = 1; get_dwords(q->ehci, NLPTR_GET(q->qtdaddr), (uint32_t *) &qtd, sizeof(EHCIqtd) >> 2); @@ -2022,7 +2023,6 @@ static int ehci_state_fetchqtd(EHCIQueue *q) p = NULL; } ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH); - again = 1; } else if (p != NULL) { switch (p->async) { case EHCI_ASYNC_NONE: @@ -2031,6 +2031,9 @@ static int ehci_state_fetchqtd(EHCIQueue *q) ehci_set_state(q->ehci, q->async, EST_EXECUTE); break; case EHCI_ASYNC_INFLIGHT: + /* Check if the guest has added new tds to the queue */ + again = (ehci_fill_queue(QTAILQ_LAST(&q->packets, pkts_head)) == + USB_RET_PROCERR) ? -1 : 1; /* Unfinished async handled packet, go horizontal */ ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH); break; @@ -2042,13 +2045,11 @@ static int ehci_state_fetchqtd(EHCIQueue *q) ehci_set_state(q->ehci, q->async, EST_EXECUTING); break; } - again = 1; } else { p = ehci_alloc_packet(q); p->qtdaddr = q->qtdaddr; p->qtd = qtd; ehci_set_state(q->ehci, q->async, EST_EXECUTE); - again = 1; } return again;