From patchwork Mon May 6 08:48:57 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hans de Goede X-Patchwork-Id: 241604 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 19AD72C00E8 for ; Mon, 6 May 2013 18:45:39 +1000 (EST) Received: from localhost ([::1]:35905 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1UZH3B-0007Gm-BD for incoming@patchwork.ozlabs.org; Mon, 06 May 2013 04:45:37 -0400 Received: from eggs.gnu.org ([208.118.235.92]:35001) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1UZH2l-0007FD-A8 for qemu-devel@nongnu.org; Mon, 06 May 2013 04:45:14 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1UZH2j-0003Tt-Ta for qemu-devel@nongnu.org; Mon, 06 May 2013 04:45:11 -0400 Received: from mx1.redhat.com ([209.132.183.28]:19459) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1UZH2j-0003T6-Li for qemu-devel@nongnu.org; Mon, 06 May 2013 04:45:09 -0400 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 r468j8p9013002 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Mon, 6 May 2013 04:45:08 -0400 Received: from shalem.localdomain.com (vpn1-5-84.ams2.redhat.com [10.36.5.84]) by int-mx02.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id r468j24x008787; Mon, 6 May 2013 04:45:07 -0400 From: Hans de Goede To: Gerd Hoffmann Date: Mon, 6 May 2013 10:48:57 +0200 Message-Id: <1367830137-9382-2-git-send-email-hdegoede@redhat.com> In-Reply-To: <1367830137-9382-1-git-send-email-hdegoede@redhat.com> References: <1367830137-9382-1-git-send-email-hdegoede@redhat.com> X-Scanned-By: MIMEDefang 2.67 on 10.5.11.12 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x X-Received-From: 209.132.183.28 Cc: Hans de Goede , qemu-devel@nongnu.org Subject: [Qemu-devel] [PATCH] uhci: Use an intermediate buffer for usb packet data 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 Due to various unfortunate reasons we cannot reliable detect a guest cancelling a packet as soon as it happens, instead we detect cancels with some delay. When packets are handled async, and we directly pass the guest memory for the packet to the usb-device as iovec, this means that the usb-device can write to guest-memory which the guest has already re-used for other purposes -> not good! This patch fixes this by adding an intermediate buffer and writing back not only the result, but also the data, of async completed packets when scanning the schedule. Signed-off-by: Hans de Goede --- hw/usb/hcd-uhci.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/hw/usb/hcd-uhci.c b/hw/usb/hcd-uhci.c index f8c4286..c85b203 100644 --- a/hw/usb/hcd-uhci.c +++ b/hw/usb/hcd-uhci.c @@ -119,7 +119,8 @@ struct UHCIPCIDeviceClass { struct UHCIAsync { USBPacket packet; - QEMUSGList sgl; + uint8_t static_buf[64]; /* 64 bytes is enough, except for isoc packets */ + uint8_t *buf; UHCIQueue *queue; QTAILQ_ENTRY(UHCIAsync) next; uint32_t td_addr; @@ -264,7 +265,6 @@ static UHCIAsync *uhci_async_alloc(UHCIQueue *queue, uint32_t td_addr) async->queue = queue; async->td_addr = td_addr; usb_packet_init(&async->packet); - pci_dma_sglist_init(&async->sgl, &queue->uhci->dev, 1); trace_usb_uhci_packet_add(async->queue->token, async->td_addr); return async; @@ -274,7 +274,9 @@ static void uhci_async_free(UHCIAsync *async) { trace_usb_uhci_packet_del(async->queue->token, async->td_addr); usb_packet_cleanup(&async->packet); - qemu_sglist_destroy(&async->sgl); + if (async->buf != async->static_buf) { + g_free(async->buf); + } g_free(async); } @@ -299,7 +301,6 @@ static void uhci_async_cancel(UHCIAsync *async) async->done); if (!async->done) usb_cancel_packet(&async->packet); - usb_packet_unmap(&async->packet, &async->sgl); uhci_async_free(async); } @@ -774,6 +775,7 @@ static int uhci_complete_td(UHCIState *s, UHCI_TD *td, UHCIAsync *async, uint32_ *int_mask |= 0x01; if (pid == USB_TOKEN_IN) { + pci_dma_write(&s->dev, td->buffer, async->buf, len); if ((td->ctrl & TD_CTRL_SPD) && len < max_len) { *int_mask |= 0x02; /* short packet: do not update QH */ @@ -881,12 +883,17 @@ static int uhci_handle_td(UHCIState *s, UHCIQueue *q, uint32_t qh_addr, spd = (pid == USB_TOKEN_IN && (td->ctrl & TD_CTRL_SPD) != 0); usb_packet_setup(&async->packet, pid, q->ep, 0, td_addr, spd, (td->ctrl & TD_CTRL_IOC) != 0); - qemu_sglist_add(&async->sgl, td->buffer, max_len); - usb_packet_map(&async->packet, &async->sgl); + if (max_len <= sizeof(async->static_buf)) { + async->buf = async->static_buf; + } else { + async->buf = g_malloc(max_len); + } + usb_packet_addbuf(&async->packet, async->buf, max_len); switch(pid) { case USB_TOKEN_OUT: case USB_TOKEN_SETUP: + pci_dma_read(&s->dev, td->buffer, async->buf, max_len); usb_handle_packet(q->ep->dev, &async->packet); if (async->packet.status == USB_RET_SUCCESS) { async->packet.actual_length = max_len; @@ -899,7 +906,6 @@ static int uhci_handle_td(UHCIState *s, UHCIQueue *q, uint32_t qh_addr, default: /* invalid pid : frame interrupted */ - usb_packet_unmap(&async->packet, &async->sgl); uhci_async_free(async); s->status |= UHCI_STS_HCPERR; uhci_update_irq(s); @@ -916,7 +922,6 @@ static int uhci_handle_td(UHCIState *s, UHCIQueue *q, uint32_t qh_addr, done: ret = uhci_complete_td(s, td, async, int_mask); - usb_packet_unmap(&async->packet, &async->sgl); uhci_async_free(async); return ret; }