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>
This commit is contained in:
Hans de Goede 2012-03-02 21:27:15 +01:00 committed by Gerd Hoffmann
parent 2763cbc751
commit dd54cfe0bc

View File

@ -1291,7 +1291,7 @@ static void ehci_async_complete_packet(USBPort *port, USBPacket *packet)
static void ehci_execute_complete(EHCIQueue *q) static void ehci_execute_complete(EHCIQueue *q)
{ {
int c_err, reload; int reload;
assert(q->async != EHCI_ASYNC_INFLIGHT); assert(q->async != EHCI_ASYNC_INFLIGHT);
q->async = EHCI_ASYNC_NONE; 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); q->qhaddr, q->qh.next, q->qtdaddr, q->usb_status);
if (q->usb_status < 0) { 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) { switch(q->usb_status) {
case USB_RET_NODEV: case USB_RET_NODEV:
q->qh.token |= (QTD_TOKEN_HALT | QTD_TOKEN_XACTERR); 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); ehci_record_interrupt(q->ehci, USBSTS_ERRINT);
break; break;
case USB_RET_STALL: case USB_RET_STALL:
@ -1336,15 +1331,13 @@ err:
assert(0); assert(0);
break; 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 { } else {
// DPRINTF("Short packet condition\n");
// TODO check 4.12 for splits // 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) { if (q->tbytes && q->pid == USB_TOKEN_IN) {
q->tbytes -= q->usb_status; q->tbytes -= q->usb_status;
} else { } else {