summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorhselasky <hselasky@FreeBSD.org>2012-09-10 12:23:56 +0000
committerhselasky <hselasky@FreeBSD.org>2012-09-10 12:23:56 +0000
commit3467c1af7a81e2a8c9aa8b461eeebc4fe5cf7b0d (patch)
tree956d3b0c0a27c1df83939db4510d5511a0998ba0
parent19f0291d49e2e6a8de3140a6184f82403c9948d5 (diff)
downloadFreeBSD-src-3467c1af7a81e2a8c9aa8b461eeebc4fe5cf7b0d.zip
FreeBSD-src-3467c1af7a81e2a8c9aa8b461eeebc4fe5cf7b0d.tar.gz
Fix for IRQ hang in DWC OTG host mode.
-rw-r--r--sys/dev/usb/controller/dwc_otg.c46
1 files changed, 27 insertions, 19 deletions
diff --git a/sys/dev/usb/controller/dwc_otg.c b/sys/dev/usb/controller/dwc_otg.c
index 82cb1be..a2b7438 100644
--- a/sys/dev/usb/controller/dwc_otg.c
+++ b/sys/dev/usb/controller/dwc_otg.c
@@ -498,8 +498,16 @@ dwc_otg_host_channel_alloc(struct dwc_otg_td *td)
DPRINTF("HCCHAR=0x%08x(0x%08x) HCSPLT=0x%08x\n",
td->hcchar, temp, td->hcsplt);
+ /* clear leftover interrupts */
temp = DWC_OTG_READ_4(sc, DOTG_HCINT(x));
DWC_OTG_WRITE_4(sc, DOTG_HCINT(x), temp);
+
+ /* enable interrupts */
+ DWC_OTG_WRITE_4(sc, DOTG_HCINTMSK(x),
+ HCINT_STALL | HCINT_BBLERR |
+ HCINT_AHBERR | HCINT_CHHLTD | HCINT_XACTERR |
+ HCINT_XFERCOMPL);
+
DWC_OTG_WRITE_4(sc, DOTG_HCSPLT(x), td->hcsplt);
DWC_OTG_WRITE_4(sc, DOTG_HCTSIZ(x), 0);
DWC_OTG_WRITE_4(sc, DOTG_HCCHAR(x), 0);
@@ -569,12 +577,6 @@ dwc_otg_host_setup_tx(struct dwc_otg_td *td)
/* must enable channel before writing data to FIFO */
DWC_OTG_WRITE_4(sc, DOTG_HCCHAR(td->channel), temp);
- /* enable interrupts */
- DWC_OTG_WRITE_4(sc, DOTG_HCINTMSK(td->channel),
- HCINT_STALL | HCINT_BBLERR |
- HCINT_AHBERR | HCINT_CHHLTD | HCINT_XACTERR |
- HCINT_XFERCOMPL);
-
/* transfer data into FIFO */
bus_space_write_region_4(sc->sc_io_tag, sc->sc_io_hdl,
DOTG_DFIFO(td->channel), (uint32_t *)&req, sizeof(req) / 4);
@@ -875,12 +877,6 @@ not_complete:
(td->toggle ? (HCTSIZ_PID_DATA1 << HCTSIZ_PID_SHIFT) :
(HCTSIZ_PID_DATA0 << HCTSIZ_PID_SHIFT)));
- /* enable interrupts */
- DWC_OTG_WRITE_4(sc, DOTG_HCINTMSK(td->channel),
- HCINT_STALL | HCINT_BBLERR |
- HCINT_AHBERR | HCINT_CHHLTD | HCINT_XACTERR |
- HCINT_XFERCOMPL);
-
temp |= HCCHAR_EPDIR_IN;
/* must enable channel before data can be received */
@@ -1123,12 +1119,6 @@ dwc_otg_host_data_tx(struct dwc_otg_td *td)
/* must enable before writing data to FIFO */
DWC_OTG_WRITE_4(sc, DOTG_HCCHAR(td->channel), temp);
- /* enable interrupts */
- DWC_OTG_WRITE_4(sc, DOTG_HCINTMSK(td->channel),
- HCINT_STALL | HCINT_BBLERR |
- HCINT_AHBERR | HCINT_CHHLTD | HCINT_XACTERR |
- HCINT_XFERCOMPL);
-
if (count != 0) {
/* clear topmost word before copy */
@@ -1632,7 +1622,17 @@ dwc_otg_interrupt(struct dwc_otg_softc *sc)
status, haint, DWC_OTG_READ_4(sc, DOTG_HFNUM));
if (haint != 0) {
+ uint8_t x;
+ /* clear left-over interrupts */
+ for (x = 0; x != sc->sc_host_ch_max; x++) {
+ /* check if channel is disabled */
+ if (sc->sc_hcchar[x] == 0) {
+ uint32_t temp;
+ temp = DWC_OTG_READ_4(sc, DOTG_HCINT(x));
+ DWC_OTG_WRITE_4(sc, DOTG_HCINT(x), temp);
+ }
+ }
}
if (status & GINTSTS_USBRST) {
@@ -2064,7 +2064,7 @@ dwc_otg_setup_standard_chain(struct usb_xfer *xfer)
td = xfer->td_transfer_first;
td->toggle = (xfer->endpoint->toggle_next ? 1 : 0);
- td->hcchar = ((xfer->max_packet_count & 3) << HCCHAR_MC_SHIFT) |
+ td->hcchar =
(xfer->address << HCCHAR_DEVADDR_SHIFT) |
(xfer_type << HCCHAR_EPTYPE_SHIFT) |
((xfer->endpointno & UE_ADDR) << HCCHAR_EPNUM_SHIFT) |
@@ -2092,6 +2092,14 @@ dwc_otg_setup_standard_chain(struct usb_xfer *xfer)
td->hcsplt = 0;
}
break;
+ case USB_SPEED_HIGH:
+ td->hcsplt = 0;
+ if (xfer_type == UE_ISOCHRONOUS ||
+ xfer_type == UE_INTERRUPT) {
+ td->hcchar |= ((xfer->max_packet_count & 3)
+ << HCCHAR_MC_SHIFT);
+ }
+ break;
default:
td->hcsplt = 0;
break;
OpenPOWER on IntegriCloud