From patchwork Fri Feb 10 11:42:57 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gerd Hoffmann X-Patchwork-Id: 140589 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [140.186.70.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 04CEDB6F98 for ; Fri, 10 Feb 2012 23:05:28 +1100 (EST) Received: from localhost ([::1]:42356 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Rvotq-0007zO-Vq for incoming@patchwork.ozlabs.org; Fri, 10 Feb 2012 06:44:22 -0500 Received: from eggs.gnu.org ([140.186.70.92]:46425) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Rvot7-0005tm-Tb for qemu-devel@nongnu.org; Fri, 10 Feb 2012 06:43:43 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1Rvot0-0000Gg-QL for qemu-devel@nongnu.org; Fri, 10 Feb 2012 06:43:37 -0500 Received: from mx1.redhat.com ([209.132.183.28]:18076) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Rvot0-0000Gb-9n for qemu-devel@nongnu.org; Fri, 10 Feb 2012 06:43:30 -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 q1ABhTxU005498 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Fri, 10 Feb 2012 06:43:29 -0500 Received: from rincewind.home.kraxel.org (ovpn-116-66.ams2.redhat.com [10.36.116.66]) by int-mx02.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id q1ABhPm2006767; Fri, 10 Feb 2012 06:43:26 -0500 Received: by rincewind.home.kraxel.org (Postfix, from userid 500) id 3BB6241566; Fri, 10 Feb 2012 12:43:24 +0100 (CET) From: Gerd Hoffmann To: qemu-devel@nongnu.org Date: Fri, 10 Feb 2012 12:42:57 +0100 Message-Id: <1328874204-20920-2-git-send-email-kraxel@redhat.com> In-Reply-To: <1328874204-20920-1-git-send-email-kraxel@redhat.com> References: <1328874204-20920-1-git-send-email-kraxel@redhat.com> X-Scanned-By: MIMEDefang 2.67 on 10.5.11.12 X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 209.132.183.28 Cc: Gerd Hoffmann Subject: [Qemu-devel] [PATCH 01/28] usb-uhci: implement bandwidth management X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org The OS is allowed to make the UHCI Controller run in circles. That is usually done to serve multiple connected USB devices in a robin-round fashion, so the available USB bandwidth is evenly distributed between devices. The uhci emulation handles this in a very poor way though. When it figures it runs in circles it stops processing unconditionally, so it usually processes at most a single transfer desriptor per queue, even if there are multiple transfer descriptors are queued up. This patch makes uhci act in a more sophisticated way. It keeps track of successful processed transfer descriptors and transfered bytes. Then it will stop processing when there is nothing to do (no transfer descriptor was completed the last round) or when the transfered data reaches the usb bandwidth limit. Result is that the usb-storage devices connected to uhci are ten times faster, mkfs.vfat time for a 64M stick goes down from five seconds to a half second. Reason for this is that we are now processing up to 20 transfer descriptors (with 64 bytes each) per frame instead of a single one. Signed-off-by: Gerd Hoffmann --- hw/usb-uhci.c | 29 ++++++++++++++++++++++------- 1 files changed, 22 insertions(+), 7 deletions(-) diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c index cddcc89..e0c7dbb 100644 --- a/hw/usb-uhci.c +++ b/hw/usb-uhci.c @@ -73,7 +73,7 @@ #define FRAME_TIMER_FREQ 1000 -#define FRAME_MAX_LOOPS 100 +#define FRAME_MAX_LOOPS 256 #define NB_PORTS 2 @@ -942,7 +942,7 @@ static int qhdb_insert(QhDb *db, uint32_t addr) static void uhci_process_frame(UHCIState *s) { uint32_t frame_addr, link, old_td_ctrl, val, int_mask; - uint32_t curr_qh; + uint32_t curr_qh, td_count = 0, bytes_count = 0; int cnt, ret; UHCI_TD td; UHCI_QH qh; @@ -967,13 +967,26 @@ static void uhci_process_frame(UHCIState *s) if (qhdb_insert(&qhdb, link)) { /* * We're going in circles. Which is not a bug because - * HCD is allowed to do that as part of the BW management. - * In our case though it makes no sense to spin here. Sync transations - * are already done, and async completion handler will re-process - * the frame when something is ready. + * HCD is allowed to do that as part of the BW management. + * + * Stop processing here if + * (a) no transaction has been done since we've been + * here last time, or + * (b) we've reached the usb 1.1 bandwidth, which is + * 1280 bytes/frame. */ DPRINTF("uhci: detected loop. qh 0x%x\n", link); - break; + if (td_count == 0) { + DPRINTF("uhci: no transaction last round, stop\n"); + break; + } else if (bytes_count >= 1280) { + DPRINTF("uhci: bandwidth limit reached, stop\n"); + break; + } else { + td_count = 0; + qhdb_reset(&qhdb); + qhdb_insert(&qhdb, link); + } } pci_dma_read(&s->dev, link & ~0xf, &qh, sizeof(qh)); @@ -1033,6 +1046,8 @@ static void uhci_process_frame(UHCIState *s) link, td.link, td.ctrl, td.token, curr_qh); link = td.link; + td_count++; + bytes_count += (td.ctrl & 0x7ff) + 1; if (curr_qh) { /* update QH element link */