diff options
author | hselasky <hselasky@FreeBSD.org> | 2013-05-27 06:32:07 +0000 |
---|---|---|
committer | hselasky <hselasky@FreeBSD.org> | 2013-05-27 06:32:07 +0000 |
commit | e97a0dc9656bc3f5214866731094513064e59725 (patch) | |
tree | 3b01e56476f35235925f4890cf33cc5ba129592c /sys/dev/usb/controller/uhci.c | |
parent | 2ed2ec066062b8067971d284fd1a77af06937b49 (diff) | |
download | FreeBSD-src-e97a0dc9656bc3f5214866731094513064e59725.zip FreeBSD-src-e97a0dc9656bc3f5214866731094513064e59725.tar.gz |
Workaround for for a problem seen with ATI Technologies EHCI
controller hardware most likely present on UHCI chipsets aswell. The
bug manifests itself when issuing isochronous transfers and bulk
transfers towards the same device simultaneously. From time to time it
happens that either the completion IRQ was missing or that the
completion IRQ was happening before the ITD/SITD was completely
written back to memory. The workaround assumes that double buffered
isochronous transfers are used, and that a second interrupt is
generated at the beginning of the next isochronous transfer to
complete the previous one. Possibly skipping the interrupt at the last
isochronous frame is possible, but will then break single buffered
isochronous transfers. For now we can live with some extra interrupts.
MFC after: 1 week
Diffstat (limited to 'sys/dev/usb/controller/uhci.c')
-rw-r--r-- | sys/dev/usb/controller/uhci.c | 13 |
1 files changed, 13 insertions, 0 deletions
diff --git a/sys/dev/usb/controller/uhci.c b/sys/dev/usb/controller/uhci.c index fe3cf93..49ce4e1 100644 --- a/sys/dev/usb/controller/uhci.c +++ b/sys/dev/usb/controller/uhci.c @@ -2138,6 +2138,7 @@ uhci_device_isoc_enter(struct usb_xfer *xfer) uint32_t nframes; uint32_t temp; uint32_t *plen; + uint8_t first = 1; #ifdef USB_DEBUG uint8_t once = 1; @@ -2253,6 +2254,18 @@ uhci_device_isoc_enter(struct usb_xfer *xfer) UHCI_TD_ACTIVE | UHCI_TD_IOS | UHCI_TD_IOC)); + } else if (first != 0) { + /* + * Workaround for lost or too early completion + * interrupt: + */ + first = 0; + td->td_status = htole32 + (UHCI_TD_ZERO_ACTLEN + (UHCI_TD_SET_ERRCNT(0) | + UHCI_TD_ACTIVE | + UHCI_TD_IOS | + UHCI_TD_IOC)); } else { td->td_status = htole32 (UHCI_TD_ZERO_ACTLEN |