From 5598a83a914636d239b087e5f6976d345366e2e3 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 4 Mar 2012 11:57:46 +0100 Subject: [PATCH 24/35] usb-ehci: split our qh queue into async and periodic queues RH-Author: Hans de Goede Message-id: <1330862278-22314-10-git-send-email-hdegoede@redhat.com> Patchwork-id: 37924 O-Subject: [PATCH 09/21] usb-ehci: split our qh queue into async and periodic queues Bugzilla: 758104 RH-Acked-by: Hans de Goede RH-Acked-by: Gerd Hoffmann RH-Acked-by: Alon Levy RH-Acked-by: Markus Armbruster qhs can be part of both the async and the periodic schedule, as is shown in later patches in this series it is useful to keep track of the qhs on a per schedule basis. Signed-off-by: Hans de Goede Upstream commit: df5d5c5c9eeaedb7705b4df6f5ee8083f39cf7b5 Upstream: http://patchwork.ozlabs.org/patch/144333/ (waiting for next usb pull request) [ rhel6: resolve conflicts ] --- hw/usb-ehci.c | 62 ++++++++++++++++++++++++++++++++++----------------------- 1 files changed, 37 insertions(+), 25 deletions(-) Signed-off-by: Michal Novotny --- hw/usb-ehci.c | 62 ++++++++++++++++++++++++++++++++++----------------------- 1 files changed, 37 insertions(+), 25 deletions(-) diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c index c3a1dff..84df063 100644 --- a/hw/usb-ehci.c +++ b/hw/usb-ehci.c @@ -344,7 +344,6 @@ enum async_state { struct EHCIQueue { EHCIState *ehci; QTAILQ_ENTRY(EHCIQueue) next; - bool async_schedule; uint32_t seen, ts; /* cached data from guest - needs to be flushed @@ -363,6 +362,8 @@ struct EHCIQueue { int usb_status; }; +typedef QTAILQ_HEAD(EHCIQueueHead, EHCIQueue) EHCIQueueHead; + struct EHCIState { PCIDevice dev; USBBus bus; @@ -407,7 +408,8 @@ struct EHCIState { USBPort ports[NB_PORTS]; USBPort *companion_ports[NB_PORTS]; uint32_t usbsts_pending; - QTAILQ_HEAD(, EHCIQueue) queues; + EHCIQueueHead aqueues; + EHCIQueueHead pqueues; uint32_t a_fetch_addr; // which address to look at next uint32_t p_fetch_addr; // which address to look at next @@ -649,31 +651,34 @@ static void ehci_trace_itd(EHCIState *s, target_phys_addr_t addr, EHCIitd *itd) static EHCIQueue *ehci_alloc_queue(EHCIState *ehci, int async) { + EHCIQueueHead *head = async ? &ehci->aqueues : &ehci->pqueues; EHCIQueue *q; q = qemu_mallocz(sizeof(*q)); q->ehci = ehci; - q->async_schedule = async; - QTAILQ_INSERT_HEAD(&ehci->queues, q, next); + QTAILQ_INSERT_HEAD(head, q, next); trace_usb_ehci_queue_action(q, "alloc"); return q; } -static void ehci_free_queue(EHCIQueue *q) +static void ehci_free_queue(EHCIQueue *q, int async) { + EHCIQueueHead *head = async ? &q->ehci->aqueues : &q->ehci->pqueues; trace_usb_ehci_queue_action(q, "free"); if (q->async == EHCI_ASYNC_INFLIGHT) { usb_cancel_packet(&q->packet); } - QTAILQ_REMOVE(&q->ehci->queues, q, next); + QTAILQ_REMOVE(head, q, next); qemu_free(q); } -static EHCIQueue *ehci_find_queue_by_qh(EHCIState *ehci, uint32_t addr) +static EHCIQueue *ehci_find_queue_by_qh(EHCIState *ehci, uint32_t addr, + int async) { + EHCIQueueHead *head = async ? &ehci->aqueues : &ehci->pqueues; EHCIQueue *q; - QTAILQ_FOREACH(q, &ehci->queues, next) { + QTAILQ_FOREACH(q, head, next) { if (addr == q->qhaddr) { return q; } @@ -681,11 +686,12 @@ static EHCIQueue *ehci_find_queue_by_qh(EHCIState *ehci, uint32_t addr) return NULL; } -static void ehci_queues_rip_unused(EHCIState *ehci) +static void ehci_queues_rip_unused(EHCIState *ehci, int async) { + EHCIQueueHead *head = async ? &ehci->aqueues : &ehci->pqueues; EHCIQueue *q, *tmp; - QTAILQ_FOREACH_SAFE(q, &ehci->queues, next, tmp) { + QTAILQ_FOREACH_SAFE(q, head, next, tmp) { if (q->seen) { q->seen = 0; q->ts = ehci->last_run_usec; @@ -695,28 +701,30 @@ static void ehci_queues_rip_unused(EHCIState *ehci) /* allow 0.25 sec idle */ continue; } - ehci_free_queue(q); + ehci_free_queue(q, async); } } -static void ehci_queues_rip_device(EHCIState *ehci, USBDevice *dev) +static void ehci_queues_rip_device(EHCIState *ehci, USBDevice *dev, int async) { + EHCIQueueHead *head = async ? &ehci->aqueues : &ehci->pqueues; EHCIQueue *q, *tmp; - QTAILQ_FOREACH_SAFE(q, &ehci->queues, next, tmp) { + QTAILQ_FOREACH_SAFE(q, head, next, tmp) { if (q->packet.owner != dev) { continue; } - ehci_free_queue(q); + ehci_free_queue(q, async); } } -static void ehci_queues_rip_all(EHCIState *ehci) +static void ehci_queues_rip_all(EHCIState *ehci, int async) { + EHCIQueueHead *head = async ? &ehci->aqueues : &ehci->pqueues; EHCIQueue *q, *tmp; - QTAILQ_FOREACH_SAFE(q, &ehci->queues, next, tmp) { - ehci_free_queue(q); + QTAILQ_FOREACH_SAFE(q, head, next, tmp) { + ehci_free_queue(q, async); } } @@ -761,7 +769,8 @@ static void ehci_detach(USBPort *port) return; } - ehci_queues_rip_device(s, port->dev); + ehci_queues_rip_device(s, port->dev, 0); + ehci_queues_rip_device(s, port->dev, 1); *portsc &= ~(PORTSC_CONNECT|PORTSC_PED); *portsc |= PORTSC_CSC; @@ -781,7 +790,8 @@ static void ehci_child_detach(USBPort *port, USBDevice *child) return; } - ehci_queues_rip_device(s, child); + ehci_queues_rip_device(s, child, 0); + ehci_queues_rip_device(s, child, 1); } static void ehci_wakeup(USBPort *port) @@ -879,7 +889,8 @@ static void ehci_reset(void *opaque) usb_send_msg(devs[i], USB_MSG_RESET); } } - ehci_queues_rip_all(s); + ehci_queues_rip_all(s, 0); + ehci_queues_rip_all(s, 1); qemu_del_timer(s->frame_timer); } @@ -1545,7 +1556,7 @@ static int ehci_state_waitlisthead(EHCIState *ehci, int async) ehci_set_usbsts(ehci, USBSTS_REC); } - ehci_queues_rip_unused(ehci); + ehci_queues_rip_unused(ehci, async); /* Find the head of the list (4.9.1.1) */ for(i = 0; i < MAX_QH; i++) { @@ -1626,7 +1637,7 @@ static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async) int reload; entry = ehci_get_fetch_addr(ehci, async); - q = ehci_find_queue_by_qh(ehci, entry); + q = ehci_find_queue_by_qh(ehci, entry, async); if (NULL == q) { q = ehci_alloc_queue(ehci, async); } @@ -2047,7 +2058,7 @@ static void ehci_advance_state(EHCIState *ehci, static void ehci_advance_async_state(EHCIState *ehci) { - int async = 1; + const int async = 1; switch(ehci_get_state(ehci, async)) { case EST_INACTIVE: @@ -2104,7 +2115,7 @@ static void ehci_advance_periodic_state(EHCIState *ehci) { uint32_t entry; uint32_t list; - int async = 0; + const int async = 0; // 4.6 @@ -2339,7 +2350,8 @@ static int usb_ehci_initfn(PCIDevice *dev) } s->frame_timer = qemu_new_timer(vm_clock, ehci_frame_timer, s); - QTAILQ_INIT(&s->queues); + QTAILQ_INIT(&s->aqueues); + QTAILQ_INIT(&s->pqueues); qemu_register_reset(ehci_reset, s); -- 1.7.7.6