diff options
author | Hans de Goede <hdegoede@redhat.com> | 2012-03-02 21:27:15 +0100 |
---|---|---|
committer | Gerd Hoffmann <kraxel@redhat.com> | 2012-03-07 12:28:03 +0100 |
commit | dd54cfe0bcf30d1f3a34e9c397f619d423fe0c5b (patch) | |
tree | b7d27fbaf6599a5307822e0c44f081056967103a /hw | |
parent | 2763cbc751c494dd2f58f902ad80a8048f9cfd7b (diff) |
usb-ehci: Fix cerr tracking
cerr should only be decremented on errors which cause XactErr to be set, and
when that happens the failing transaction should be retried until cerr reaches
0 and only then should USBSTS_ERRINT be set (and inactive cleared and
USBSTS_INT set if requested).
Since we don't have any hardware level errors (and in case of redirection
the real hardware has already retried), re-trying makes no sense, so
immediately set cerr to 0 on errors which set XactErr.
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Diffstat (limited to 'hw')
-rw-r--r-- | hw/usb-ehci.c | 19 |
1 files changed, 6 insertions, 13 deletions
diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c index 507e4a8148..2685adc181 100644 --- a/hw/usb-ehci.c +++ b/hw/usb-ehci.c @@ -1291,7 +1291,7 @@ static void ehci_async_complete_packet(USBPort *port, USBPacket *packet) static void ehci_execute_complete(EHCIQueue *q) { - int c_err, reload; + int reload; assert(q->async != EHCI_ASYNC_INFLIGHT); q->async = EHCI_ASYNC_NONE; @@ -1300,15 +1300,10 @@ static void ehci_execute_complete(EHCIQueue *q) q->qhaddr, q->qh.next, q->qtdaddr, q->usb_status); if (q->usb_status < 0) { -err: - /* TO-DO: put this is in a function that can be invoked below as well */ - c_err = get_field(q->qh.token, QTD_TOKEN_CERR); - c_err--; - set_field(&q->qh.token, c_err, QTD_TOKEN_CERR); - switch(q->usb_status) { case USB_RET_NODEV: q->qh.token |= (QTD_TOKEN_HALT | QTD_TOKEN_XACTERR); + set_field(&q->qh.token, 0, QTD_TOKEN_CERR); ehci_record_interrupt(q->ehci, USBSTS_ERRINT); break; case USB_RET_STALL: @@ -1336,15 +1331,13 @@ err: assert(0); break; } + } else if ((q->usb_status > q->tbytes) && (q->pid == USB_TOKEN_IN)) { + q->usb_status = USB_RET_BABBLE; + q->qh.token |= (QTD_TOKEN_HALT | QTD_TOKEN_BABBLE); + ehci_record_interrupt(q->ehci, USBSTS_ERRINT); } else { - // DPRINTF("Short packet condition\n"); // TODO check 4.12 for splits - if ((q->usb_status > q->tbytes) && (q->pid == USB_TOKEN_IN)) { - q->usb_status = USB_RET_BABBLE; - goto err; - } - if (q->tbytes && q->pid == USB_TOKEN_IN) { q->tbytes -= q->usb_status; } else { |