From patchwork Thu Aug 4 15:10:20 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gerd Hoffmann X-Patchwork-Id: 108522 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 5A7C0B6F62 for ; Fri, 5 Aug 2011 01:28:54 +1000 (EST) Received: from localhost ([::1]:37454 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Qozqs-0001Bo-JW for incoming@patchwork.ozlabs.org; Thu, 04 Aug 2011 11:28:50 -0400 Received: from eggs.gnu.org ([140.186.70.92]:38657) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Qozau-0007p2-Of for qemu-devel@nongnu.org; Thu, 04 Aug 2011 11:12:24 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1QozZb-0007tT-PJ for qemu-devel@nongnu.org; Thu, 04 Aug 2011 11:11:06 -0400 Received: from mx1.redhat.com ([209.132.183.28]:31966) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QozZb-0007r8-Ff for qemu-devel@nongnu.org; Thu, 04 Aug 2011 11:10:59 -0400 Received: from int-mx01.intmail.prod.int.phx2.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id p74FAe4w014082 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Thu, 4 Aug 2011 11:10:41 -0400 Received: from rincewind.home.kraxel.org (ovpn-116-28.ams2.redhat.com [10.36.116.28]) by int-mx01.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id p74FAWMl024591; Thu, 4 Aug 2011 11:10:32 -0400 Received: by rincewind.home.kraxel.org (Postfix, from userid 500) id 0E44D41981; Thu, 4 Aug 2011 17:10:27 +0200 (CEST) From: Gerd Hoffmann To: qemu-devel@nongnu.org Date: Thu, 4 Aug 2011 17:10:20 +0200 Message-Id: <1312470626-25872-11-git-send-email-kraxel@redhat.com> In-Reply-To: <1312470626-25872-1-git-send-email-kraxel@redhat.com> References: <1312470626-25872-1-git-send-email-kraxel@redhat.com> X-Scanned-By: MIMEDefang 2.67 on 10.5.11.11 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 10/16] ehci: iovec support, remove buffer 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 Map guest memory and pass on a direct pointer instead of copying the bits to a indirect buffer. EHCI transfer descriptors can reference multiple (physical guest) pages so we'll actually start seeing usb packets wich carry iovec with more than one element. Signed-off-by: Gerd Hoffmann --- hw/usb-ehci.c | 147 ++++++++++++++++++++++++--------------------------------- 1 files changed, 62 insertions(+), 85 deletions(-) diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c index 799e31a..2b43895 100644 --- a/hw/usb-ehci.c +++ b/hw/usb-ehci.c @@ -28,6 +28,7 @@ #include "pci.h" #include "monitor.h" #include "trace.h" +#include "dma.h" #define EHCI_DEBUG 0 @@ -269,6 +270,7 @@ typedef struct EHCIqtd { uint32_t bufptr[5]; // Standard buffer pointer #define QTD_BUFPTR_MASK 0xfffff000 +#define QTD_BUFPTR_SH 12 } EHCIqtd; /* EHCI spec version 1.0 Section 3.6 @@ -357,7 +359,7 @@ struct EHCIQueue { uint32_t qtdaddr; // address QTD read from USBPacket packet; - uint8_t buffer[BUFF_SIZE]; + QEMUSGList sgl; int pid; uint32_t tbytes; enum async_state async; @@ -414,7 +416,7 @@ struct EHCIState { uint32_t p_fetch_addr; // which address to look at next USBPacket ipacket; - uint8_t ibuffer[BUFF_SIZE]; + QEMUSGList isgl; int isoch_pause; uint64_t last_run_ns; @@ -1165,58 +1167,56 @@ static int ehci_qh_do_overlay(EHCIQueue *q) return 0; } -static int ehci_buffer_rw(EHCIQueue *q, int bytes, int rw) +static int ehci_init_transfer(EHCIQueue *q) { - int bufpos = 0; - int cpage, offset; - uint32_t head; - uint32_t tail; - - - if (!bytes) { - return 0; - } - - cpage = get_field(q->qh.token, QTD_TOKEN_CPAGE); - if (cpage > 4) { - fprintf(stderr, "cpage out of range (%d)\n", cpage); - return USB_RET_PROCERR; - } + uint32_t cpage, offset, bytes, plen; + target_phys_addr_t page; + cpage = get_field(q->qh.token, QTD_TOKEN_CPAGE); + bytes = get_field(q->qh.token, QTD_TOKEN_TBYTES); offset = q->qh.bufptr[0] & ~QTD_BUFPTR_MASK; + qemu_sglist_init(&q->sgl, 5); - do { - /* start and end of this page */ - head = q->qh.bufptr[cpage] & QTD_BUFPTR_MASK; - tail = head + ~QTD_BUFPTR_MASK + 1; - /* add offset into page */ - head |= offset; - - if (bytes <= (tail - head)) { - tail = head + bytes; + while (bytes > 0) { + if (cpage > 4) { + fprintf(stderr, "cpage out of range (%d)\n", cpage); + return USB_RET_PROCERR; } - trace_usb_ehci_data(rw, cpage, offset, head, tail-head, bufpos); - cpu_physical_memory_rw(head, q->buffer + bufpos, tail - head, rw); - - bufpos += (tail - head); - offset += (tail - head); - bytes -= (tail - head); - - if (bytes > 0) { - cpage++; + page = q->qh.bufptr[cpage] & QTD_BUFPTR_MASK; + page += offset; + plen = bytes; + if (plen > 4096 - offset) { + plen = 4096 - offset; offset = 0; + cpage++; } - } while (bytes > 0); - /* save cpage */ - set_field(&q->qh.token, cpage, QTD_TOKEN_CPAGE); + qemu_sglist_add(&q->sgl, page, plen); + bytes -= plen; + } + return 0; +} - /* save offset into cpage */ - q->qh.bufptr[0] &= QTD_BUFPTR_MASK; - q->qh.bufptr[0] |= offset; +static void ehci_finish_transfer(EHCIQueue *q, int status) +{ + uint32_t cpage, offset; - return 0; + qemu_sglist_destroy(&q->sgl); + + if (status > 0) { + /* update cpage & offset */ + cpage = get_field(q->qh.token, QTD_TOKEN_CPAGE); + offset = q->qh.bufptr[0] & ~QTD_BUFPTR_MASK; + + offset += status; + cpage += offset >> QTD_BUFPTR_SH; + offset &= ~QTD_BUFPTR_MASK; + + set_field(&q->qh.token, cpage, QTD_TOKEN_CPAGE); + q->qh.bufptr[0] &= QTD_BUFPTR_MASK; + q->qh.bufptr[0] |= offset; + } } static void ehci_async_complete_packet(USBPort *port, USBPacket *packet) @@ -1295,10 +1295,6 @@ err: } if (q->tbytes && q->pid == USB_TOKEN_IN) { - if (ehci_buffer_rw(q, q->usb_status, 1) != 0) { - q->usb_status = USB_RET_PROCERR; - return; - } q->tbytes -= q->usb_status; } else { q->tbytes = 0; @@ -1307,6 +1303,8 @@ err: DPRINTF("updating tbytes to %d\n", q->tbytes); set_field(&q->qh.token, q->tbytes, QTD_TOKEN_TBYTES); } + ehci_finish_transfer(q, q->usb_status); + usb_packet_unmap(&q->packet); q->qh.token ^= QTD_TOKEN_DTOGGLE; q->qh.token &= ~QTD_TOKEN_ACTIVE; @@ -1346,8 +1344,7 @@ static int ehci_execute(EHCIQueue *q) default: fprintf(stderr, "bad token\n"); break; } - if ((q->tbytes && q->pid != USB_TOKEN_IN) && - (ehci_buffer_rw(q, q->tbytes, 0) != 0)) { + if (ehci_init_transfer(q) != 0) { return USB_RET_PROCERR; } @@ -1356,6 +1353,9 @@ static int ehci_execute(EHCIQueue *q) ret = USB_RET_NODEV; + usb_packet_setup(&q->packet, q->pid, devadr, endp); + usb_packet_map(&q->packet, &q->sgl); + // TO-DO: associating device with ehci port for(i = 0; i < NB_PORTS; i++) { port = &q->ehci->ports[i]; @@ -1367,9 +1367,6 @@ static int ehci_execute(EHCIQueue *q) continue; } - usb_packet_setup(&q->packet, q->pid, devadr, endp); - usb_packet_addbuf(&q->packet, q->buffer, q->tbytes); - ret = usb_handle_packet(dev, &q->packet); DPRINTF("submit: qh %x next %x qtd %x pid %x len %zd " @@ -1399,7 +1396,7 @@ static int ehci_process_itd(EHCIState *ehci, USBPort *port; USBDevice *dev; int ret; - uint32_t i, j, len, len1, len2, pid, dir, devaddr, endp; + uint32_t i, j, len, pid, dir, devaddr, endp; uint32_t pg, off, ptr1, ptr2, max, mult; dir =(itd->bufptr[1] & ITD_BUFPTR_DIRECTION); @@ -1424,29 +1421,23 @@ static int ehci_process_itd(EHCIState *ehci, return USB_RET_PROCERR; } + qemu_sglist_init(&ehci->isgl, 2); if (off + len > 4096) { /* transfer crosses page border */ - len2 = off + len - 4096; - len1 = len - len2; + uint32_t len2 = off + len - 4096; + uint32_t len1 = len - len2; + qemu_sglist_add(&ehci->isgl, ptr1 + off, len1); + qemu_sglist_add(&ehci->isgl, ptr2, len2); } else { - len1 = len; - len2 = 0; + qemu_sglist_add(&ehci->isgl, ptr1 + off, len); } - if (!dir) { - pid = USB_TOKEN_OUT; - trace_usb_ehci_data(0, pg, off, ptr1 + off, len1, 0); - cpu_physical_memory_rw(ptr1 + off, &ehci->ibuffer[0], len1, 0); - if (len2) { - trace_usb_ehci_data(0, pg+1, 0, ptr2, len2, len1); - cpu_physical_memory_rw(ptr2, &ehci->ibuffer[len1], len2, 0); - } - } else { - pid = USB_TOKEN_IN; - } + pid = dir ? USB_TOKEN_IN : USB_TOKEN_OUT; - ret = USB_RET_NODEV; + usb_packet_setup(&ehci->ipacket, pid, devaddr, endp); + usb_packet_map(&ehci->ipacket, &ehci->isgl); + ret = USB_RET_NODEV; for (j = 0; j < NB_PORTS; j++) { port = &ehci->ports[j]; dev = port->dev; @@ -1455,9 +1446,6 @@ static int ehci_process_itd(EHCIState *ehci, continue; } - usb_packet_setup(&ehci->ipacket, pid, devaddr, endp); - usb_packet_addbuf(&ehci->ipacket, ehci->ibuffer, len); - ret = usb_handle_packet(dev, &ehci->ipacket); if (ret != USB_RET_NODEV) { @@ -1465,6 +1453,9 @@ static int ehci_process_itd(EHCIState *ehci, } } + usb_packet_unmap(&ehci->ipacket); + qemu_sglist_destroy(&ehci->isgl); + #if 0 /* In isoch, there is no facility to indicate a NAK so let's * instead just complete a zero-byte transaction. Setting @@ -1502,20 +1493,6 @@ static int ehci_process_itd(EHCIState *ehci, set_field(&itd->transact[i], len - ret, ITD_XACT_LENGTH); } else { /* IN */ - if (len1 > ret) { - len1 = ret; - } - if (len2 > ret - len1) { - len2 = ret - len1; - } - if (len1) { - trace_usb_ehci_data(1, pg, off, ptr1 + off, len1, 0); - cpu_physical_memory_rw(ptr1 + off, &ehci->ibuffer[0], len1, 1); - } - if (len2) { - trace_usb_ehci_data(1, pg+1, 0, ptr2, len2, len1); - cpu_physical_memory_rw(ptr2, &ehci->ibuffer[len1], len2, 1); - } set_field(&itd->transact[i], ret, ITD_XACT_LENGTH); }