From patchwork Mon May 16 19:56:16 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gerd Hoffmann X-Patchwork-Id: 95825 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 3AA0BB6EF1 for ; Tue, 17 May 2011 06:02:14 +1000 (EST) Received: from localhost ([::1]:45394 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QM3zX-00068E-F6 for incoming@patchwork.ozlabs.org; Mon, 16 May 2011 16:02:11 -0400 Received: from eggs.gnu.org ([140.186.70.92]:57821) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QM3uI-0005Rg-2b for qemu-devel@nongnu.org; Mon, 16 May 2011 15:56:47 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1QM3uG-0004O2-RV for qemu-devel@nongnu.org; Mon, 16 May 2011 15:56:46 -0400 Received: from mx1.redhat.com ([209.132.183.28]:11474) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QM3uG-0004Nv-GF for qemu-devel@nongnu.org; Mon, 16 May 2011 15:56:44 -0400 Received: from int-mx10.intmail.prod.int.phx2.redhat.com (int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.23]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id p4GJuhSi015368 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Mon, 16 May 2011 15:56:43 -0400 Received: from rincewind.home.kraxel.org (vpn1-4-42.ams2.redhat.com [10.36.4.42]) by int-mx10.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id p4GJuXlJ027726; Mon, 16 May 2011 15:56:34 -0400 Received: by rincewind.home.kraxel.org (Postfix, from userid 500) id 6EAB242998; Mon, 16 May 2011 21:56:23 +0200 (CEST) From: Gerd Hoffmann To: qemu-devel@nongnu.org Date: Mon, 16 May 2011 21:56:16 +0200 Message-Id: <1305575782-31766-13-git-send-email-kraxel@redhat.com> In-Reply-To: <1305575782-31766-1-git-send-email-kraxel@redhat.com> References: <1305575782-31766-1-git-send-email-kraxel@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.23 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 12/18] usb-linux: split large xfers 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 Add support for splitting large transfers into multiple smaller ones. This is needed for the upcoming EHCI emulation which allows guests to submit requests up to 20k in size. The linux kernel allows 16k max size though. Roughly based on a patch from git://git.kiszka.org/qemu.git ehci Signed-off-by: Gerd Hoffmann --- usb-linux.c | 68 +++++++++++++++++++++++++++++++++++++--------------------- 1 files changed, 43 insertions(+), 25 deletions(-) diff --git a/usb-linux.c b/usb-linux.c index b8f7705..b95c119 100644 --- a/usb-linux.c +++ b/usb-linux.c @@ -89,6 +89,9 @@ static int usb_fs_type; #define ISO_URB_COUNT 3 #define INVALID_EP_TYPE 255 +/* devio.c limits single requests to 16k */ +#define MAX_USBFS_BUFFER_SIZE 16384 + typedef struct AsyncURB AsyncURB; struct endp_data { @@ -229,6 +232,7 @@ struct AsyncURB /* For regular async urbs */ USBPacket *packet; + int more; /* large transfer, more urbs follow */ /* For buffered iso handling */ int iso_frame_idx; /* -1 means in flight */ @@ -291,7 +295,7 @@ static void async_complete(void *opaque) if (p) { switch (aurb->urb.status) { case 0: - p->len = aurb->urb.actual_length; + p->len += aurb->urb.actual_length; break; case -EPIPE: @@ -306,7 +310,7 @@ static void async_complete(void *opaque) if (aurb->urb.type == USBDEVFS_URB_TYPE_CONTROL) { usb_generic_async_ctrl_complete(&s->dev, p); - } else { + } else if (!aurb->more) { usb_packet_complete(&s->dev, p); } } @@ -646,7 +650,8 @@ static int usb_host_handle_data(USBDevice *dev, USBPacket *p) USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev); struct usbdevfs_urb *urb; AsyncURB *aurb; - int ret; + int ret, rem; + uint8_t *pbuf; uint8_t ep; if (!is_valid(s, p->devep)) { @@ -673,32 +678,45 @@ static int usb_host_handle_data(USBDevice *dev, USBPacket *p) return usb_host_handle_iso_data(s, p, p->pid == USB_TOKEN_IN); } - aurb = async_alloc(s); - aurb->packet = p; + rem = p->len; + pbuf = p->data; + p->len = 0; + while (rem) { + aurb = async_alloc(s); + aurb->packet = p; - urb = &aurb->urb; + urb = &aurb->urb; + urb->endpoint = ep; + urb->type = USBDEVFS_URB_TYPE_BULK; + urb->usercontext = s; + urb->buffer = pbuf; - urb->endpoint = ep; - urb->buffer = p->data; - urb->buffer_length = p->len; - urb->type = USBDEVFS_URB_TYPE_BULK; - urb->usercontext = s; + if (rem > MAX_USBFS_BUFFER_SIZE) { + urb->buffer_length = MAX_USBFS_BUFFER_SIZE; + aurb->more = 1; + } else { + urb->buffer_length = rem; + aurb->more = 0; + } + pbuf += urb->buffer_length; + rem -= urb->buffer_length; - ret = ioctl(s->fd, USBDEVFS_SUBMITURB, urb); + ret = ioctl(s->fd, USBDEVFS_SUBMITURB, urb); - DPRINTF("husb: data submit. ep 0x%x len %u aurb %p\n", - urb->endpoint, p->len, aurb); + DPRINTF("husb: data submit: ep 0x%x, len %u, more %d, packet %p, aurb %p\n", + urb->endpoint, urb->buffer_length, aurb->more, p, aurb); - if (ret < 0) { - DPRINTF("husb: submit failed. errno %d\n", errno); - async_free(aurb); + if (ret < 0) { + DPRINTF("husb: submit failed. errno %d\n", errno); + async_free(aurb); - switch(errno) { - case ETIMEDOUT: - return USB_RET_NAK; - case EPIPE: - default: - return USB_RET_STALL; + switch(errno) { + case ETIMEDOUT: + return USB_RET_NAK; + case EPIPE: + default: + return USB_RET_STALL; + } } }