[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH 15/32] uhci: Limit amount of frames processed in one
From: |
Gerd Hoffmann |
Subject: |
[Qemu-devel] [PATCH 15/32] uhci: Limit amount of frames processed in one go |
Date: |
Tue, 8 Jan 2013 14:14:37 +0100 |
From: Hans de Goede <address@hidden>
Before this patch uhci would process an unlimited amount of frames when
behind on schedule, by setting the timer to a time already past, causing the
timer subsys to immediately recall the frame_timer function gain.
This would cause invalid cancellations of bulk queues when the catching up
processed more then 32 frames at a moment when the bulk qh was temporarily
unlinked (which the Linux uhci driver does).
This patch fixes this by processing maximum 16 frames in one go, and always
setting the timer one ms later, making the code behave more like the ehci
code.
Signed-off-by: Hans de Goede <address@hidden>
Signed-off-by: Gerd Hoffmann <address@hidden>
---
hw/usb/hcd-uhci.c | 43 +++++++++++++++++++++++++++----------------
1 files changed, 27 insertions(+), 16 deletions(-)
diff --git a/hw/usb/hcd-uhci.c b/hw/usb/hcd-uhci.c
index d61d879..e5c3e59 100644
--- a/hw/usb/hcd-uhci.c
+++ b/hw/usb/hcd-uhci.c
@@ -78,6 +78,8 @@
/* Must be large enough to handle 10 frame delay for initial isoc requests */
#define QH_VALID 32
+#define MAX_FRAMES_PER_TICK (QH_VALID / 2)
+
#define NB_PORTS 2
enum {
@@ -500,7 +502,7 @@ static void uhci_ioport_writew(void *opaque, uint32_t addr,
uint32_t val)
trace_usb_uhci_schedule_start();
s->expire_time = qemu_get_clock_ns(vm_clock) +
(get_ticks_per_sec() / FRAME_TIMER_FREQ);
- qemu_mod_timer(s->frame_timer, qemu_get_clock_ns(vm_clock));
+ qemu_mod_timer(s->frame_timer, s->expire_time);
s->status &= ~UHCI_STS_HCHALTED;
} else if (!(val & UHCI_CMD_RS)) {
s->status |= UHCI_STS_HCHALTED;
@@ -1176,10 +1178,10 @@ static void uhci_bh(void *opaque)
static void uhci_frame_timer(void *opaque)
{
UHCIState *s = opaque;
+ uint64_t t_now, t_last_run;
+ int i, frames;
+ const uint64_t frame_t = get_ticks_per_sec() / FRAME_TIMER_FREQ;
- /* prepare the timer for the next frame */
- s->expire_time += (get_ticks_per_sec() / FRAME_TIMER_FREQ);
- s->frame_bytes = 0;
s->completions_only = false;
qemu_bh_cancel(s->bh);
@@ -1193,20 +1195,29 @@ static void uhci_frame_timer(void *opaque)
return;
}
- /* Process the current frame */
- trace_usb_uhci_frame_start(s->frnum);
-
- uhci_async_validate_begin(s);
-
- uhci_process_frame(s);
+ /* We still store expire_time in our state, for migration */
+ t_last_run = s->expire_time - frame_t;
+ t_now = qemu_get_clock_ns(vm_clock);
- uhci_async_validate_end(s);
+ /* Process up to MAX_FRAMES_PER_TICK frames */
+ frames = (t_now - t_last_run) / frame_t;
+ if (frames > MAX_FRAMES_PER_TICK) {
+ frames = MAX_FRAMES_PER_TICK;
+ }
- /* The uhci spec says frnum reflects the frame currently being processed,
- * and the guest must look at frnum - 1 on interrupt, so inc frnum now */
- s->frnum = (s->frnum + 1) & 0x7ff;
+ for (i = 0; i < frames; i++) {
+ s->frame_bytes = 0;
+ trace_usb_uhci_frame_start(s->frnum);
+ uhci_async_validate_begin(s);
+ uhci_process_frame(s);
+ uhci_async_validate_end(s);
+ /* The spec says frnum is the frame currently being processed, and
+ * the guest must look at frnum - 1 on interrupt, so inc frnum now */
+ s->frnum = (s->frnum + 1) & 0x7ff;
+ s->expire_time += frame_t;
+ }
- /* Complete the previous frame */
+ /* Complete the previous frame(s) */
if (s->pending_int_mask) {
s->status2 |= s->pending_int_mask;
s->status |= UHCI_STS_USBINT;
@@ -1214,7 +1225,7 @@ static void uhci_frame_timer(void *opaque)
}
s->pending_int_mask = 0;
- qemu_mod_timer(s->frame_timer, s->expire_time);
+ qemu_mod_timer(s->frame_timer, t_now + frame_t);
}
static const MemoryRegionPortio uhci_portio[] = {
--
1.7.1
- [Qemu-devel] [PATCH 05/32] ehci: writeback_async_complete_packet: verify qh and qtd, (continued)
- [Qemu-devel] [PATCH 05/32] ehci: writeback_async_complete_packet: verify qh and qtd, Gerd Hoffmann, 2013/01/08
- [Qemu-devel] [PATCH 11/32] ehci: Don't call commit_irq after raising PCD, Gerd Hoffmann, 2013/01/08
- [Qemu-devel] [PATCH 12/32] uhci: Fix 1 ms delay in interrupt reporting to the guest, Gerd Hoffmann, 2013/01/08
- [Qemu-devel] [PATCH 14/32] uhci: Add a QH_VALID define, Gerd Hoffmann, 2013/01/08
- [Qemu-devel] [PATCH 21/32] usbredir: Add USBEP2I and I2USBEP helper macros, Gerd Hoffmann, 2013/01/08
- [Qemu-devel] [PATCH 01/32] ehci: Add a ehci_writeback_async_complete_packet helper function, Gerd Hoffmann, 2013/01/08
- [Qemu-devel] [PATCH 29/32] usb/ehci: Add SysBus EHCI device for Exynos4210, Gerd Hoffmann, 2013/01/08
- [Qemu-devel] [PATCH 06/32] ehci: Verify qtd for async completed packets, Gerd Hoffmann, 2013/01/08
- [Qemu-devel] [PATCH 26/32] xhci: call set-address with dummy usbpacket, Gerd Hoffmann, 2013/01/08
- [Qemu-devel] [PATCH 13/32] uhci: Fix pending interrupts getting lost on migration, Gerd Hoffmann, 2013/01/08
- [Qemu-devel] [PATCH 15/32] uhci: Limit amount of frames processed in one go,
Gerd Hoffmann <=
- [Qemu-devel] [PATCH 23/32] usbredir: Verify we have 32 bits bulk length cap when redirecting to xhci, Gerd Hoffmann, 2013/01/08
- [Qemu-devel] [PATCH 30/32] exynos4210: Add EHCI support, Gerd Hoffmann, 2013/01/08
- [Qemu-devel] [PATCH 20/32] usbredir: Add an usbredir_stop_ep helper function, Gerd Hoffmann, 2013/01/08
- [Qemu-devel] [PATCH 22/32] usbredir: Add ep_stopped USBDevice method, Gerd Hoffmann, 2013/01/08
- [Qemu-devel] [PATCH 32/32] uhci: stop using portio lists, Gerd Hoffmann, 2013/01/08
- [Qemu-devel] [PATCH 28/32] usb/ehci: Move capsbase and opregbase into SysBus EHCI class, Gerd Hoffmann, 2013/01/08
- [Qemu-devel] [PATCH 24/32] usbredir: Add usbredir_init_endpoints() helper, Gerd Hoffmann, 2013/01/08
- [Qemu-devel] [PATCH 16/32] uhci: Maximize how many frames we catch up when behind, Gerd Hoffmann, 2013/01/08
- [Qemu-devel] [PATCH 27/32] usb/ehci: Clean up SysBus and PCI EHCI split, Gerd Hoffmann, 2013/01/08
- [Qemu-devel] [PATCH 18/32] usb: Fix usb_ep_find_packet_by_id, Gerd Hoffmann, 2013/01/08