From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([208.118.235.92]:45736) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1TsZ1K-0004Xy-Qg for qemu-devel@nongnu.org; Tue, 08 Jan 2013 08:15:13 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1TsZ1B-0002fy-Bj for qemu-devel@nongnu.org; Tue, 08 Jan 2013 08:15:10 -0500 Received: from mx1.redhat.com ([209.132.183.28]:25365) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1TsZ1B-0002fV-4s for qemu-devel@nongnu.org; Tue, 08 Jan 2013 08:15:01 -0500 Received: from int-mx02.intmail.prod.int.phx2.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id r08DF0Cc007786 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Tue, 8 Jan 2013 08:15:00 -0500 From: Gerd Hoffmann Date: Tue, 8 Jan 2013 14:14:37 +0100 Message-Id: <1357650894-16982-16-git-send-email-kraxel@redhat.com> In-Reply-To: <1357650894-16982-1-git-send-email-kraxel@redhat.com> References: <1357650894-16982-1-git-send-email-kraxel@redhat.com> Subject: [Qemu-devel] [PATCH 15/32] uhci: Limit amount of frames processed in one go List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Cc: Hans de Goede , Gerd Hoffmann From: Hans de Goede 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 Signed-off-by: Gerd Hoffmann --- 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