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
next prev 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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).