svn commit: r251023 - head/sys/dev/usb/controller
Hans Petter Selasky
hselasky at FreeBSD.org
Mon May 27 06:32:07 UTC 2013
Author: hselasky
Date: Mon May 27 06:32:07 2013
New Revision: 251023
URL: http://svnweb.freebsd.org/changeset/base/251023
Log:
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
Modified:
head/sys/dev/usb/controller/ehci.c
head/sys/dev/usb/controller/uhci.c
Modified: head/sys/dev/usb/controller/ehci.c
==============================================================================
--- head/sys/dev/usb/controller/ehci.c Mon May 27 06:24:31 2013 (r251022)
+++ head/sys/dev/usb/controller/ehci.c Mon May 27 06:32:07 2013 (r251023)
@@ -2454,6 +2454,7 @@ ehci_device_isoc_fs_enter(struct usb_xfe
uint16_t tlen;
uint8_t sa;
uint8_t sb;
+ uint8_t first = 1;
#ifdef USB_DEBUG
uint8_t once = 1;
@@ -2618,6 +2619,16 @@ ehci_device_isoc_fs_enter(struct usb_xfe
EHCI_SITD_IOC |
EHCI_SITD_ACTIVE |
EHCI_SITD_SET_LEN(*plen));
+ } else if (first != 0) {
+ /*
+ * Workaround for lost or too early
+ * completion interrupt:
+ */
+ first = 0;
+ td->sitd_status = htohc32(sc,
+ EHCI_SITD_IOC |
+ EHCI_SITD_ACTIVE |
+ EHCI_SITD_SET_LEN(*plen));
} else {
td->sitd_status = htohc32(sc,
EHCI_SITD_ACTIVE |
@@ -2759,6 +2770,7 @@ ehci_device_isoc_hs_enter(struct usb_xfe
uint8_t td_no;
uint8_t page_no;
uint8_t shift = usbd_xfer_get_fps_shift(xfer);
+ uint8_t first = 1;
#ifdef USB_DEBUG
uint8_t once = 1;
@@ -2920,6 +2932,13 @@ ehci_device_isoc_hs_enter(struct usb_xfe
/* set IOC bit if we are complete */
if (nframes == 0) {
td->itd_status[td_no - 1] |= htohc32(sc, EHCI_ITD_IOC);
+ } else if (first != 0) {
+ /*
+ * Workaround for lost or too early
+ * completion interrupt:
+ */
+ first = 0;
+ td->itd_status[0] |= htohc32(sc, EHCI_ITD_IOC);
}
usb_pc_cpu_flush(td->page_cache);
#ifdef USB_DEBUG
Modified: head/sys/dev/usb/controller/uhci.c
==============================================================================
--- head/sys/dev/usb/controller/uhci.c Mon May 27 06:24:31 2013 (r251022)
+++ head/sys/dev/usb/controller/uhci.c Mon May 27 06:32:07 2013 (r251023)
@@ -2138,6 +2138,7 @@ uhci_device_isoc_enter(struct usb_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 *
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
More information about the svn-src-head
mailing list