All of lore.kernel.org
 help / color / mirror / Atom feed
From: Gerd Hoffmann <kraxel@redhat.com>
To: qemu-devel@nongnu.org
Cc: Gerd Hoffmann <kraxel@redhat.com>,
	Martin Cerveny <M.Cerveny@computer.org>
Subject: [Qemu-devel] [PULL 2/5] usb-redir: merge interrupt packets
Date: Thu, 22 Aug 2019 08:52:39 +0200	[thread overview]
Message-ID: <20190822065242.12496-3-kraxel@redhat.com> (raw)
In-Reply-To: <20190822065242.12496-1-kraxel@redhat.com>

From: Martin Cerveny <M.Cerveny@computer.org>

Interrupt packets (limited by wMaxPacketSize) should be buffered and merged
by algorithm described in USB spec.
(see usb_20.pdf/5.7.3 Interrupt Transfer Packet Size Constraints).

Signed-off-by: Martin Cerveny <M.Cerveny@computer.org>
Message-id: 20190724125859.14624-2-M.Cerveny@computer.org
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 hw/usb/redirect.c | 71 ++++++++++++++++++++++++++++++++---------------
 1 file changed, 49 insertions(+), 22 deletions(-)

diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c
index be15b9f30334..e0f5ca6f818b 100644
--- a/hw/usb/redirect.c
+++ b/hw/usb/redirect.c
@@ -819,8 +819,8 @@ static void usbredir_handle_interrupt_in_data(USBRedirDevice *dev,
                                               USBPacket *p, uint8_t ep)
 {
     /* Input interrupt endpoint, buffered packet input */
-    struct buf_packet *intp;
-    int status, len;
+    struct buf_packet *intp, *intp_to_free;
+    int status, len, sum;
 
     if (!dev->endpoint[EP2I(ep)].interrupt_started &&
             !dev->endpoint[EP2I(ep)].interrupt_error) {
@@ -839,9 +839,17 @@ static void usbredir_handle_interrupt_in_data(USBRedirDevice *dev,
         dev->endpoint[EP2I(ep)].bufpq_dropping_packets = 0;
     }
 
-    intp = QTAILQ_FIRST(&dev->endpoint[EP2I(ep)].bufpq);
+    /* check for completed interrupt message (with all fragments) */
+    sum = 0;
+    QTAILQ_FOREACH(intp, &dev->endpoint[EP2I(ep)].bufpq, next) {
+        sum += intp->len;
+        if (intp->len < dev->endpoint[EP2I(ep)].max_packet_size ||
+            sum >= p->iov.size)
+            break;
+    }
+
     if (intp == NULL) {
-        DPRINTF2("interrupt-token-in ep %02X, no intp\n", ep);
+        DPRINTF2("interrupt-token-in ep %02X, no intp, buffered %d\n", ep, sum);
         /* Check interrupt_error for stream errors */
         status = dev->endpoint[EP2I(ep)].interrupt_error;
         dev->endpoint[EP2I(ep)].interrupt_error = 0;
@@ -852,18 +860,42 @@ static void usbredir_handle_interrupt_in_data(USBRedirDevice *dev,
         }
         return;
     }
-    DPRINTF("interrupt-token-in ep %02X status %d len %d\n", ep,
-            intp->status, intp->len);
-
-    status = intp->status;
-    len = intp->len;
-    if (len > p->iov.size) {
-        ERROR("received int data is larger then packet ep %02X\n", ep);
-        len = p->iov.size;
-        status = usb_redir_babble;
+
+    /* copy of completed interrupt message */
+    sum = 0;
+    status = usb_redir_success;
+    intp_to_free = NULL;
+    QTAILQ_FOREACH(intp, &dev->endpoint[EP2I(ep)].bufpq, next) {
+        if (intp_to_free) {
+            bufp_free(dev, intp_to_free, ep);
+        }
+        DPRINTF("interrupt-token-in ep %02X fragment status %d len %d\n", ep,
+                intp->status, intp->len);
+
+        sum += intp->len;
+        len = intp->len;
+        if (status == usb_redir_success) {
+            status = intp->status;
+        }
+        if (sum > p->iov.size) {
+            ERROR("received int data is larger then packet ep %02X\n", ep);
+            len -= (sum - p->iov.size);
+            sum = p->iov.size;
+            status = usb_redir_babble;
+        }
+
+        usb_packet_copy(p, intp->data, len);
+
+        intp_to_free = intp;
+        if (intp->len < dev->endpoint[EP2I(ep)].max_packet_size ||
+            sum >= p->iov.size)
+            break;
+    }
+    if (intp_to_free) {
+        bufp_free(dev, intp_to_free, ep);
     }
-    usb_packet_copy(p, intp->data, len);
-    bufp_free(dev, intp, ep);
+    DPRINTF("interrupt-token-in ep %02X summary status %d len %d\n", ep,
+            status, sum);
     usbredir_handle_status(dev, p, status);
 }
 
@@ -2041,22 +2073,17 @@ static void usbredir_interrupt_packet(void *priv, uint64_t id,
     }
 
     if (ep & USB_DIR_IN) {
-        bool q_was_empty;
-
         if (dev->endpoint[EP2I(ep)].interrupt_started == 0) {
             DPRINTF("received int packet while not started ep %02X\n", ep);
             free(data);
             return;
         }
 
-        q_was_empty = QTAILQ_EMPTY(&dev->endpoint[EP2I(ep)].bufpq);
-
         /* bufp_alloc also adds the packet to the ep queue */
         bufp_alloc(dev, data, data_len, interrupt_packet->status, ep, data);
 
-        if (q_was_empty) {
-            usb_wakeup(usb_ep_get(&dev->dev, USB_TOKEN_IN, ep & 0x0f), 0);
-        }
+        /* insufficient data solved with USB_RET_NAK */
+        usb_wakeup(usb_ep_get(&dev->dev, USB_TOKEN_IN, ep & 0x0f), 0);
     } else {
         /*
          * We report output interrupt packets as completed directly upon
-- 
2.18.1



  parent reply	other threads:[~2019-08-22  6:58 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-08-22  6:52 [Qemu-devel] [PULL 0/5] Usb 20190822 patches Gerd Hoffmann
2019-08-22  6:52 ` [Qemu-devel] [PULL 1/5] usbredir: fix buffer-overflow on vmload Gerd Hoffmann
2019-08-22  6:52 ` Gerd Hoffmann [this message]
2019-08-22  6:52 ` [Qemu-devel] [PULL 3/5] xhci: Add No Op Command Gerd Hoffmann
2019-08-22  6:52 ` [Qemu-devel] [PULL 4/5] usb: reword -usb command-line option and mention xHCI Gerd Hoffmann
2019-08-22  6:52 ` [Qemu-devel] [PULL 5/5] ehci: fix queue->dev null ptr dereference Gerd Hoffmann
2019-08-22 15:13 ` [Qemu-devel] [PULL 0/5] Usb 20190822 patches Peter Maydell

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20190822065242.12496-3-kraxel@redhat.com \
    --to=kraxel@redhat.com \
    --cc=M.Cerveny@computer.org \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.