[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH 05/18] ehci: add queuing support
From: |
Gerd Hoffmann |
Subject: |
[Qemu-devel] [PATCH 05/18] ehci: add queuing support |
Date: |
Fri, 25 May 2012 14:40:21 +0200 |
Add packet queuing. Follow the qTD chain to see if there are more
packets we can submit. Improves performance on larger transfers,
especially with usb-host, as we don't have to wait for a packet to
finish before sending the next one to the host for processing.
Signed-off-by: Gerd Hoffmann <address@hidden>
---
hw/usb/hcd-ehci.c | 60 +++++++++++++++++++++++++++++++++++++++++++++--------
1 files changed, 51 insertions(+), 9 deletions(-)
diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
index f21b4be..ccaa947 100644
--- a/hw/usb/hcd-ehci.c
+++ b/hw/usb/hcd-ehci.c
@@ -671,10 +671,6 @@ static EHCIPacket *ehci_alloc_packet(EHCIQueue *q)
{
EHCIPacket *p;
-#if 1
- /* temporary, we don't handle multiple packets per queue (yet) */
- assert(QTAILQ_EMPTY(&q->packets));
-#endif
p = g_new0(EHCIPacket, 1);
p->queue = q;
usb_packet_init(&p->packet);
@@ -1394,7 +1390,7 @@ static void ehci_execute_complete(EHCIQueue *q)
// 4.10.3
-static int ehci_execute(EHCIPacket *p)
+static int ehci_execute(EHCIPacket *p, const char *action)
{
USBEndpoint *ep;
int ret;
@@ -1437,6 +1433,7 @@ static int ehci_execute(EHCIPacket *p)
usb_packet_setup(&p->packet, p->pid, ep);
usb_packet_map(&p->packet, &p->sgl);
+ trace_usb_ehci_packet_action(p->queue, p, action);
ret = usb_handle_packet(p->queue->dev, &p->packet);
DPRINTF("submit: qh %x next %x qtd %x pid %x len %zd "
"(total %d) endp %x ret %d\n",
@@ -1713,7 +1710,7 @@ static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int
async)
}
if (p && p->async == EHCI_ASYNC_FINISHED) {
/* I/O finished -- continue processing queue */
- trace_usb_ehci_queue_action(q, "resume");
+ trace_usb_ehci_packet_action(p->queue, p, "complete");
ehci_set_state(ehci, async, EST_EXECUTING);
goto out;
}
@@ -1858,7 +1855,22 @@ static int ehci_state_fetchqtd(EHCIQueue *q, int async)
sizeof(EHCIqtd) >> 2);
ehci_trace_qtd(q, NLPTR_GET(q->qtdaddr), &qtd);
- if (qtd.token & QTD_TOKEN_ACTIVE) {
+ p = QTAILQ_FIRST(&q->packets);
+ while (p != NULL && p->qtdaddr != q->qtdaddr) {
+ /* should not happen (guest bug) */
+ ehci_free_packet(p);
+ p = QTAILQ_FIRST(&q->packets);
+ }
+ if (p != NULL) {
+ ehci_qh_do_overlay(q);
+ ehci_flush_qh(q);
+ if (p->async == EHCI_ASYNC_INFLIGHT) {
+ ehci_set_state(q->ehci, async, EST_HORIZONTALQH);
+ } else {
+ ehci_set_state(q->ehci, async, EST_EXECUTING);
+ }
+ again = 1;
+ } else if (qtd.token & QTD_TOKEN_ACTIVE) {
p = ehci_alloc_packet(q);
p->qtdaddr = q->qtdaddr;
p->qtd = qtd;
@@ -1887,6 +1899,35 @@ static int ehci_state_horizqh(EHCIQueue *q, int async)
return again;
}
+static void ehci_fill_queue(EHCIPacket *p, int async)
+{
+ EHCIQueue *q = p->queue;
+ EHCIqtd qtd = p->qtd;
+ uint32_t qtdaddr;
+
+ for (;;) {
+ if (NLPTR_TBIT(qtd.altnext) == 0) {
+ break;
+ }
+ if (NLPTR_TBIT(qtd.next) != 0) {
+ break;
+ }
+ qtdaddr = qtd.next;
+ get_dwords(q->ehci, NLPTR_GET(qtdaddr),
+ (uint32_t *) &qtd, sizeof(EHCIqtd) >> 2);
+ ehci_trace_qtd(q, NLPTR_GET(qtdaddr), &qtd);
+ if (!(qtd.token & QTD_TOKEN_ACTIVE)) {
+ break;
+ }
+ p = ehci_alloc_packet(q);
+ p->qtdaddr = qtdaddr;
+ p->qtd = qtd;
+ p->usb_status = ehci_execute(p, "queue");
+ assert(p->usb_status = USB_RET_ASYNC);
+ p->async = EHCI_ASYNC_INFLIGHT;
+ }
+}
+
static int ehci_state_execute(EHCIQueue *q, int async)
{
EHCIPacket *p = QTAILQ_FIRST(&q->packets);
@@ -1916,17 +1957,18 @@ static int ehci_state_execute(EHCIQueue *q, int async)
ehci_set_usbsts(q->ehci, USBSTS_REC);
}
- p->usb_status = ehci_execute(p);
+ p->usb_status = ehci_execute(p, "process");
if (p->usb_status == USB_RET_PROCERR) {
again = -1;
goto out;
}
if (p->usb_status == USB_RET_ASYNC) {
ehci_flush_qh(q);
- trace_usb_ehci_queue_action(q, "suspend");
+ trace_usb_ehci_packet_action(p->queue, p, "async");
p->async = EHCI_ASYNC_INFLIGHT;
ehci_set_state(q->ehci, async, EST_HORIZONTALQH);
again = 1;
+ ehci_fill_queue(p, async);
goto out;
}
--
1.7.1
- [Qemu-devel] [PATCH 00/18] ehci updates, Gerd Hoffmann, 2012/05/25
- [Qemu-devel] [PATCH] uhci: fix irq routing, Gerd Hoffmann, 2012/05/25
- [Qemu-devel] [PATCH 10/18] ehci: kick async schedule on wakeup, Gerd Hoffmann, 2012/05/25
- [Qemu-devel] [PATCH 12/18] ehci: add ehci_*_enabled() helpers, Gerd Hoffmann, 2012/05/25
- [Qemu-devel] [PATCH 05/18] ehci: add queuing support,
Gerd Hoffmann <=
- [Qemu-devel] [PATCH 14/18] ehci: fix halt status handling, Gerd Hoffmann, 2012/05/25
- [Qemu-devel] [PATCH 04/18] ehci: move ehci_flush_qh, Gerd Hoffmann, 2012/05/25
- [Qemu-devel] [PATCH 13/18] ehci: update status bits in ehci_set_state, Gerd Hoffmann, 2012/05/25
- [Qemu-devel] [PATCH 03/18] ehci: cache USBDevice in EHCIQueue, Gerd Hoffmann, 2012/05/25
- [Qemu-devel] [PATCH 01/18] ehci: add EHCIPacket, Gerd Hoffmann, 2012/05/25
- [Qemu-devel] [PATCH 09/18] ehci: schedule async bh on async packet completion, Gerd Hoffmann, 2012/05/25
- [Qemu-devel] [PATCH 17/18] ehci: adaptive wakeup rate., Gerd Hoffmann, 2012/05/25
- [Qemu-devel] [PATCH 18/18] ehci: rework frame skipping, Gerd Hoffmann, 2012/05/25
- [Qemu-devel] [PATCH 15/18] ehci: remove unused attach_poll_counter, Gerd Hoffmann, 2012/05/25
- [Qemu-devel] [PATCH 16/18] ehci: create ehci_update_frindex, Gerd Hoffmann, 2012/05/25