From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([140.186.70.92]:56394) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QMAHh-0008Pl-So for qemu-devel@nongnu.org; Mon, 16 May 2011 22:45:22 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1QMAHg-0001vd-IO for qemu-devel@nongnu.org; Mon, 16 May 2011 22:45:21 -0400 Received: from sj-iport-3.cisco.com ([171.71.176.72]:22785) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QMAHg-0001v8-29 for qemu-devel@nongnu.org; Mon, 16 May 2011 22:45:20 -0400 Message-ID: <4DD1E13B.2010701@cisco.com> Date: Mon, 16 May 2011 20:45:15 -0600 From: David Ahern MIME-Version: 1.0 References: <1305575782-31766-1-git-send-email-kraxel@redhat.com> <1305575782-31766-13-git-send-email-kraxel@redhat.com> In-Reply-To: <1305575782-31766-13-git-send-email-kraxel@redhat.com> Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit Subject: Re: [Qemu-devel] [PATCH 12/18] usb-linux: split large xfers List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: Gerd Hoffmann Cc: qemu-devel@nongnu.org On 05/16/11 13:56, Gerd Hoffmann wrote: > 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 More specifically: http://www.mail-archive.com/qemu-devel@nongnu.org/msg30337.html And "roughly based" is a bit of a stretch. The logic for handling 20k requests in a 16k limit (the focus of this patch) came from the patch above. This patch is a forward port based on changes made to the USB code and some code movement. David > > 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; > + } > } > } >