From owner-svn-src-all@FreeBSD.ORG Thu Jun 5 18:17:41 2014 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id 76579CD7; Thu, 5 Jun 2014 18:17:41 +0000 (UTC) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 628D02ABC; Thu, 5 Jun 2014 18:17:41 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.8/8.14.8) with ESMTP id s55IHf3v004210; Thu, 5 Jun 2014 18:17:41 GMT (envelope-from hselasky@svn.freebsd.org) Received: (from hselasky@localhost) by svn.freebsd.org (8.14.8/8.14.8/Submit) id s55IHf5u004208; Thu, 5 Jun 2014 18:17:41 GMT (envelope-from hselasky@svn.freebsd.org) Message-Id: <201406051817.s55IHf5u004208@svn.freebsd.org> From: Hans Petter Selasky Date: Thu, 5 Jun 2014 18:17:41 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r267120 - head/sys/dev/usb/controller X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 05 Jun 2014 18:17:41 -0000 Author: hselasky Date: Thu Jun 5 18:17:40 2014 New Revision: 267120 URL: http://svnweb.freebsd.org/changeset/base/267120 Log: Try to fix DWC OTG regression issues with full and low speed devices: - Remove double buffering interrupt and isochronous traffic via the transaction translator. It can be avoided because the DWC OTG will always delay the start split transactions for interrupt and isochronous traffic, but will not delay the complete split transactions, if we set the odd frame bit correctly. - Need to check the transfer cache field in the device done function to be sure all allocated channels are freed and not the transfer first one. This seems to resolve the control endpoint transfer type quirk which is now removed. - Make sure any received data upon TX is dumped else RX path will stop. - Transmit isochronous data before receiving isochronous data as a means to optimise the TT schedule. - Implement a simple TT bandwidth scheduler. - Cleanup use of old "td->error" variable. - On interrupt IN traffic via the transaction translator we simply ignore missed transfer opportunities and silently retry the transaction upon next available time slot. MFC after: 3 days Modified: head/sys/dev/usb/controller/dwc_otg.c head/sys/dev/usb/controller/dwc_otg.h Modified: head/sys/dev/usb/controller/dwc_otg.c ============================================================================== --- head/sys/dev/usb/controller/dwc_otg.c Thu Jun 5 18:01:59 2014 (r267119) +++ head/sys/dev/usb/controller/dwc_otg.c Thu Jun 5 18:17:40 2014 (r267120) @@ -592,13 +592,13 @@ dwc_otg_clear_hcint(struct dwc_otg_softc } static uint8_t -dwc_otg_host_channel_alloc(struct dwc_otg_softc *sc, struct dwc_otg_td *td, uint8_t which, uint8_t is_out) +dwc_otg_host_channel_alloc(struct dwc_otg_softc *sc, struct dwc_otg_td *td, uint8_t is_out) { uint32_t tx_p_size; uint32_t tx_np_size; uint8_t x; - if (td->channel[which] < DWC_OTG_MAX_CHANNELS) + if (td->channel < DWC_OTG_MAX_CHANNELS) return (0); /* already allocated */ /* check if device is suspended */ @@ -658,7 +658,7 @@ dwc_otg_host_channel_alloc(struct dwc_ot sc->sc_active_rx_ep |= (1 << x); /* set channel */ - td->channel[which] = x; + td->channel = x; return (0); /* allocated */ } @@ -668,16 +668,16 @@ dwc_otg_host_channel_alloc(struct dwc_ot } static void -dwc_otg_host_channel_free(struct dwc_otg_softc *sc, struct dwc_otg_td *td, uint8_t which) +dwc_otg_host_channel_free(struct dwc_otg_softc *sc, struct dwc_otg_td *td) { uint8_t x; - if (td->channel[which] >= DWC_OTG_MAX_CHANNELS) + if (td->channel >= DWC_OTG_MAX_CHANNELS) return; /* already freed */ /* free channel */ - x = td->channel[which]; - td->channel[which] = DWC_OTG_MAX_CHANNELS; + x = td->channel; + td->channel = DWC_OTG_MAX_CHANNELS; DPRINTF("CH=%d\n", x); @@ -707,6 +707,18 @@ dwc_otg_host_channel_free(struct dwc_otg sc->sc_active_rx_ep &= ~(1 << x); } +static void +dwc_otg_host_dump_rx(struct dwc_otg_softc *sc, struct dwc_otg_td *td) +{ + /* dump any pending messages */ + if (sc->sc_last_rx_status != 0) { + if (td->channel < DWC_OTG_MAX_CHANNELS && + td->channel == GRXSTSRD_CHNUM_GET(sc->sc_last_rx_status)) { + dwc_otg_common_rx_ack(sc); + } + } +} + static uint8_t dwc_otg_host_setup_tx(struct dwc_otg_softc *sc, struct dwc_otg_td *td) { @@ -715,13 +727,15 @@ dwc_otg_host_setup_tx(struct dwc_otg_sof uint32_t hcchar; uint8_t delta; - if (td->channel[0] < DWC_OTG_MAX_CHANNELS) { - hcint = sc->sc_chan_state[td->channel[0]].hcint; + dwc_otg_host_dump_rx(sc, td); + + if (td->channel < DWC_OTG_MAX_CHANNELS) { + hcint = sc->sc_chan_state[td->channel].hcint; DPRINTF("CH=%d ST=%d HCINT=0x%08x HCCHAR=0x%08x HCTSIZ=0x%08x\n", - td->channel[0], td->state, hcint, - DWC_OTG_READ_4(sc, DOTG_HCCHAR(td->channel[0])), - DWC_OTG_READ_4(sc, DOTG_HCTSIZ(td->channel[0]))); + td->channel, td->state, hcint, + DWC_OTG_READ_4(sc, DOTG_HCCHAR(td->channel)), + DWC_OTG_READ_4(sc, DOTG_HCTSIZ(td->channel))); } else { hcint = 0; goto check_state; @@ -731,12 +745,12 @@ dwc_otg_host_setup_tx(struct dwc_otg_sof HCINT_ACK | HCINT_NYET)) { /* give success bits priority over failure bits */ } else if (hcint & HCINT_STALL) { - DPRINTF("CH=%d STALL\n", td->channel[0]); + DPRINTF("CH=%d STALL\n", td->channel); td->error_stall = 1; td->error_any = 1; goto complete; } else if (hcint & HCINT_ERRORS) { - DPRINTF("CH=%d ERROR\n", td->channel[0]); + DPRINTF("CH=%d ERROR\n", td->channel); td->errcnt++; if (td->hcsplt != 0 || td->errcnt >= 3) { td->error_any = 1; @@ -804,7 +818,7 @@ check_state: send_pkt: /* free existing channel, if any */ - dwc_otg_host_channel_free(sc, td, 0); + dwc_otg_host_channel_free(sc, td); if (sizeof(req) != td->remainder) { td->error_any = 1; @@ -827,7 +841,7 @@ send_pkt: } /* allocate a new channel */ - if (dwc_otg_host_channel_alloc(sc, td, 0, 1)) { + if (dwc_otg_host_channel_alloc(sc, td, 1)) { td->state = DWC_CHAN_ST_START; goto busy; } @@ -841,23 +855,29 @@ send_pkt: usbd_copy_out(td->pc, 0, &req, sizeof(req)); - DWC_OTG_WRITE_4(sc, DOTG_HCTSIZ(td->channel[0]), + DWC_OTG_WRITE_4(sc, DOTG_HCTSIZ(td->channel), (sizeof(req) << HCTSIZ_XFERSIZE_SHIFT) | (1 << HCTSIZ_PKTCNT_SHIFT) | (HCTSIZ_PID_SETUP << HCTSIZ_PID_SHIFT)); - DWC_OTG_WRITE_4(sc, DOTG_HCSPLT(td->channel[0]), td->hcsplt); + DWC_OTG_WRITE_4(sc, DOTG_HCSPLT(td->channel), td->hcsplt); hcchar = td->hcchar; hcchar &= ~(HCCHAR_EPDIR_IN | HCCHAR_EPTYPE_MASK); hcchar |= UE_CONTROL << HCCHAR_EPTYPE_SHIFT; /* must enable channel before writing data to FIFO */ - DWC_OTG_WRITE_4(sc, DOTG_HCCHAR(td->channel[0]), hcchar); + DWC_OTG_WRITE_4(sc, DOTG_HCCHAR(td->channel), hcchar); /* transfer data into FIFO */ bus_space_write_region_4(sc->sc_io_tag, sc->sc_io_hdl, - DOTG_DFIFO(td->channel[0]), (uint32_t *)&req, sizeof(req) / 4); + DOTG_DFIFO(td->channel), (uint32_t *)&req, sizeof(req) / 4); + + /* wait until next slot before trying complete split */ + if (td->ep_type == UE_INTERRUPT || td->ep_type == UE_ISOCHRONOUS) + td->tt_complete_slot = sc->sc_last_frame_num + 2; + else + td->tt_complete_slot = sc->sc_last_frame_num + 1; /* store number of bytes transmitted */ td->tx_bytes = sizeof(req); @@ -865,7 +885,7 @@ send_pkt: send_cpkt: /* free existing channel, if any */ - dwc_otg_host_channel_free(sc, td, 0); + dwc_otg_host_channel_free(sc, td); delta = td->tt_complete_slot - sc->sc_last_frame_num - 1; if (td->tt_scheduled == 0 || delta < DWC_OTG_TT_SLOT_MAX) { @@ -880,34 +900,34 @@ send_cpkt: goto complete; } /* allocate a new channel */ - if (dwc_otg_host_channel_alloc(sc, td, 0, 0)) { + if (dwc_otg_host_channel_alloc(sc, td, 0)) { td->state = DWC_CHAN_ST_WAIT_C_PKT; goto busy; } - /* wait until next slot before trying again */ - td->tt_complete_slot++; + /* wait until next slot before trying complete split */ + td->tt_complete_slot = sc->sc_last_frame_num + 1; td->hcsplt |= HCSPLT_COMPSPLT; td->state = DWC_CHAN_ST_WAIT_C_ANE; - DWC_OTG_WRITE_4(sc, DOTG_HCTSIZ(td->channel[0]), + DWC_OTG_WRITE_4(sc, DOTG_HCTSIZ(td->channel), (HCTSIZ_PID_SETUP << HCTSIZ_PID_SHIFT)); - DWC_OTG_WRITE_4(sc, DOTG_HCSPLT(td->channel[0]), td->hcsplt); + DWC_OTG_WRITE_4(sc, DOTG_HCSPLT(td->channel), td->hcsplt); hcchar = td->hcchar; hcchar &= ~(HCCHAR_EPDIR_IN | HCCHAR_EPTYPE_MASK); hcchar |= UE_CONTROL << HCCHAR_EPTYPE_SHIFT; /* must enable channel before writing data to FIFO */ - DWC_OTG_WRITE_4(sc, DOTG_HCCHAR(td->channel[0]), hcchar); + DWC_OTG_WRITE_4(sc, DOTG_HCCHAR(td->channel), hcchar); busy: return (1); /* busy */ complete: - dwc_otg_host_channel_free(sc, td, 0); + dwc_otg_host_channel_free(sc, td); return (0); /* complete */ } @@ -1085,55 +1105,21 @@ busy: } static uint8_t -dwc_otg_host_data_rx(struct dwc_otg_softc *sc, struct dwc_otg_td *td) +dwc_otg_host_data_rx_sub(struct dwc_otg_softc *sc, struct dwc_otg_td *td) { - uint32_t hcint; - uint32_t hcchar; uint32_t count; - uint8_t delta; uint8_t channel; - channel = td->channel[td->tt_channel_tog]; - - if (channel < DWC_OTG_MAX_CHANNELS) { - hcint = sc->sc_chan_state[channel].hcint; - - DPRINTF("CH=%d ST=%d HCINT=0x%08x HCCHAR=0x%08x HCTSIZ=0x%08x\n", - channel, td->state, hcint, - DWC_OTG_READ_4(sc, DOTG_HCCHAR(channel)), - DWC_OTG_READ_4(sc, DOTG_HCTSIZ(channel))); - } else { - hcint = 0; - goto check_state; - } - - /* check interrupt bits */ - - if (hcint & (HCINT_RETRY | - HCINT_ACK | HCINT_NYET)) { - /* give success bits priority over failure bits */ - } else if (hcint & HCINT_STALL) { - DPRINTF("CH=%d STALL\n", channel); - td->error_stall = 1; - td->error_any = 1; - goto complete; - } else if (hcint & HCINT_ERRORS) { - DPRINTF("CH=%d ERROR\n", channel); - td->errcnt++; - if (td->hcsplt != 0 || td->errcnt >= 3) { - if (td->ep_type != UE_ISOCHRONOUS) { - td->error_any = 1; - goto complete; - } - } - } - /* check endpoint status */ if (sc->sc_last_rx_status == 0) - goto check_state; + goto busy; + + channel = td->channel; + if (channel >= DWC_OTG_MAX_CHANNELS) + goto busy; if (GRXSTSRD_CHNUM_GET(sc->sc_last_rx_status) != channel) - goto check_state; + goto busy; switch (sc->sc_last_rx_status & GRXSTSRD_PKTSTS_MASK) { case GRXSTSRH_IN_DATA: @@ -1141,7 +1127,7 @@ dwc_otg_host_data_rx(struct dwc_otg_soft DPRINTF("DATA ST=%d STATUS=0x%08x\n", (int)td->state, (int)sc->sc_last_rx_status); - if (hcint & HCINT_SOFTWARE_ONLY) { + if (sc->sc_chan_state[channel].hcint & HCINT_SOFTWARE_ONLY) { /* * When using SPLIT transactions on interrupt * endpoints, sometimes data occurs twice. @@ -1203,21 +1189,71 @@ dwc_otg_host_data_rx(struct dwc_otg_soft td->remainder -= count; td->offset += count; - hcint |= HCINT_SOFTWARE_ONLY; - sc->sc_chan_state[channel].hcint = hcint; + sc->sc_chan_state[channel].hcint |= HCINT_SOFTWARE_ONLY; break; - default: break; } /* release FIFO */ dwc_otg_common_rx_ack(sc); +busy: + return (0); +complete: + return (1); +} -check_state: - if (hcint & (HCINT_ERRORS | HCINT_RETRY | - HCINT_ACK | HCINT_NYET)) { - if (!(hcint & HCINT_ERRORS)) - td->errcnt = 0; +static uint8_t +dwc_otg_host_data_rx(struct dwc_otg_softc *sc, struct dwc_otg_td *td) +{ + uint32_t hcint; + uint32_t hcchar; + uint8_t delta; + uint8_t channel; + + channel = td->channel; + + if (channel < DWC_OTG_MAX_CHANNELS) { + hcint = sc->sc_chan_state[channel].hcint; + + DPRINTF("CH=%d ST=%d HCINT=0x%08x HCCHAR=0x%08x HCTSIZ=0x%08x\n", + channel, td->state, hcint, + DWC_OTG_READ_4(sc, DOTG_HCCHAR(channel)), + DWC_OTG_READ_4(sc, DOTG_HCTSIZ(channel))); + + /* check interrupt bits */ + if (hcint & (HCINT_RETRY | + HCINT_ACK | HCINT_NYET)) { + /* give success bits priority over failure bits */ + } else if (hcint & HCINT_STALL) { + DPRINTF("CH=%d STALL\n", channel); + td->error_stall = 1; + td->error_any = 1; + goto complete; + } else if (hcint & HCINT_ERRORS) { + DPRINTF("CH=%d ERROR\n", channel); + td->errcnt++; + if (td->hcsplt != 0 || td->errcnt >= 3) { + if (td->ep_type != UE_ISOCHRONOUS) { + td->error_any = 1; + goto complete; + } + } + } + + /* check channels for data, if any */ + if (dwc_otg_host_data_rx_sub(sc, td)) + goto complete; + + /* refresh interrupt status */ + hcint = sc->sc_chan_state[channel].hcint; + + if (hcint & (HCINT_ERRORS | HCINT_RETRY | + HCINT_ACK | HCINT_NYET)) { + if (!(hcint & HCINT_ERRORS)) + td->errcnt = 0; + } + } else { + hcint = 0; } switch (td->state) { @@ -1306,7 +1342,7 @@ check_state: receive_pkt: /* free existing channel, if any */ - dwc_otg_host_channel_free(sc, td, td->tt_channel_tog); + dwc_otg_host_channel_free(sc, td); if (td->hcsplt != 0) { delta = td->tt_complete_slot - sc->sc_last_frame_num - 1; @@ -1316,9 +1352,18 @@ receive_pkt: } delta = sc->sc_last_frame_num - td->tt_start_slot; if (delta > DWC_OTG_TT_SLOT_MAX) { - /* we missed the service interval */ - if (td->ep_type != UE_ISOCHRONOUS) + if (td->ep_type == UE_INTERRUPT) { + /* + * Happens from time to time avoid + * posting an error, instead retry + * the start split packet: + */ + td->tt_scheduled = 0; + goto receive_spkt; + } else if (td->ep_type != UE_ISOCHRONOUS) { + /* we missed the service interval */ td->error_any = 1; + } goto complete; } /* complete split */ @@ -1330,12 +1375,12 @@ receive_pkt: } /* allocate a new channel */ - if (dwc_otg_host_channel_alloc(sc, td, td->tt_channel_tog, 0)) { + if (dwc_otg_host_channel_alloc(sc, td, 0)) { td->state = DWC_CHAN_ST_WAIT_C_PKT; goto busy; } - channel = td->channel[td->tt_channel_tog]; + channel = td->channel; /* set toggle, if any */ if (td->set_toggle) { @@ -1357,46 +1402,23 @@ receive_pkt: hcchar = td->hcchar; hcchar |= HCCHAR_EPDIR_IN; - /* check if other channel is allocated */ - if (td->channel[td->tt_channel_tog ^ 1] < DWC_OTG_MAX_CHANNELS) { - /* second - receive after next SOF event */ - if ((sc->sc_last_frame_num & 1) != 0) - hcchar |= HCCHAR_ODDFRM; - else - hcchar &= ~HCCHAR_ODDFRM; - - /* other channel is next */ - td->tt_channel_tog ^= 1; - td->tt_complete_slot++; + /* receive complete split ASAP */ + if ((sc->sc_last_frame_num & 1) != 0) + hcchar |= HCCHAR_ODDFRM; + else + hcchar &= ~HCCHAR_ODDFRM; - /* must enable channel before data can be received */ - DWC_OTG_WRITE_4(sc, DOTG_HCCHAR(channel), hcchar); - } else { - /* first - receive after second next SOF event */ - if ((sc->sc_last_frame_num & 1) == 0) - hcchar |= HCCHAR_ODDFRM; - else - hcchar &= ~HCCHAR_ODDFRM; + /* must enable channel before data can be received */ + DWC_OTG_WRITE_4(sc, DOTG_HCCHAR(channel), hcchar); - /* must enable channel before data can be received */ - DWC_OTG_WRITE_4(sc, DOTG_HCCHAR(channel), hcchar); + /* wait until next slot before trying complete split */ + td->tt_complete_slot = sc->sc_last_frame_num + 1; - if (td->hcsplt != 0) { - if (td->ep_type == UE_ISOCHRONOUS || td->ep_type == UE_INTERRUPT) { - /* allocate a second channel */ - td->tt_channel_tog ^= 1; - goto receive_pkt; - } else { - td->tt_complete_slot++; - } - } - } goto busy; receive_spkt: /* free existing channel(s), if any */ - dwc_otg_host_channel_free(sc, td, 0); - dwc_otg_host_channel_free(sc, td, 1); + dwc_otg_host_channel_free(sc, td); delta = td->tt_start_slot - sc->sc_last_frame_num - 1; if (td->tt_scheduled == 0 || delta < DWC_OTG_TT_SLOT_MAX) { @@ -1412,19 +1434,16 @@ receive_spkt: } /* allocate a new channel */ - if (dwc_otg_host_channel_alloc(sc, td, 0, 0)) { + if (dwc_otg_host_channel_alloc(sc, td, 0)) { td->state = DWC_CHAN_ST_START; goto busy; } - channel = td->channel[0]; + channel = td->channel; td->hcsplt &= ~HCSPLT_COMPSPLT; td->state = DWC_CHAN_ST_WAIT_S_ANE; - /* reset channel toggle */ - td->tt_channel_tog = 0; - /* receive one packet */ DWC_OTG_WRITE_4(sc, DOTG_HCTSIZ(channel), (HCTSIZ_PID_DATA0 << HCTSIZ_PID_SHIFT)); @@ -1440,14 +1459,19 @@ receive_spkt: hcchar = td->hcchar; hcchar |= HCCHAR_EPDIR_IN; + /* wait until next slot before trying complete split */ + if (td->ep_type == UE_INTERRUPT || td->ep_type == UE_ISOCHRONOUS) + td->tt_complete_slot = sc->sc_last_frame_num + 2; + else + td->tt_complete_slot = sc->sc_last_frame_num + 1; + /* must enable channel before data can be received */ DWC_OTG_WRITE_4(sc, DOTG_HCCHAR(channel), hcchar); busy: return (1); /* busy */ complete: - dwc_otg_host_channel_free(sc, td, 0); - dwc_otg_host_channel_free(sc, td, 1); + dwc_otg_host_channel_free(sc, td); return (0); /* complete */ } @@ -1569,7 +1593,9 @@ dwc_otg_host_data_tx(struct dwc_otg_soft uint8_t delta; uint8_t channel; - channel = td->channel[td->tt_channel_tog]; + dwc_otg_host_dump_rx(sc, td); + + channel = td->channel; if (channel < DWC_OTG_MAX_CHANNELS) { hcint = sc->sc_chan_state[channel].hcint; @@ -1578,36 +1604,34 @@ dwc_otg_host_data_tx(struct dwc_otg_soft channel, td->state, hcint, DWC_OTG_READ_4(sc, DOTG_HCCHAR(channel)), DWC_OTG_READ_4(sc, DOTG_HCTSIZ(channel))); - } else { - hcint = 0; - goto check_state; - } - if (hcint & (HCINT_RETRY | - HCINT_ACK | HCINT_NYET)) { - /* give success bits priority over failure bits */ - } else if (hcint & HCINT_STALL) { - DPRINTF("CH=%d STALL\n", channel); - td->error_stall = 1; - td->error_any = 1; - goto complete; - } else if (hcint & HCINT_ERRORS) { - DPRINTF("CH=%d ERROR\n", channel); - td->errcnt++; - if (td->hcsplt != 0 || td->errcnt >= 3) { + if (hcint & (HCINT_RETRY | + HCINT_ACK | HCINT_NYET)) { + /* give success bits priority over failure bits */ + } else if (hcint & HCINT_STALL) { + DPRINTF("CH=%d STALL\n", channel); + td->error_stall = 1; td->error_any = 1; goto complete; + } else if (hcint & HCINT_ERRORS) { + DPRINTF("CH=%d ERROR\n", channel); + td->errcnt++; + if (td->hcsplt != 0 || td->errcnt >= 3) { + td->error_any = 1; + goto complete; + } } - } - if (hcint & (HCINT_ERRORS | HCINT_RETRY | - HCINT_ACK | HCINT_NYET)) { + if (hcint & (HCINT_ERRORS | HCINT_RETRY | + HCINT_ACK | HCINT_NYET)) { - if (!(hcint & HCINT_ERRORS)) - td->errcnt = 0; + if (!(hcint & HCINT_ERRORS)) + td->errcnt = 0; + } + } else { + hcint = 0; } -check_state: switch (td->state) { case DWC_CHAN_ST_START: goto send_pkt; @@ -1694,16 +1718,16 @@ check_state: td->tt_xactpos++; /* free existing channel, if any */ - dwc_otg_host_channel_free(sc, td, td->tt_channel_tog); + dwc_otg_host_channel_free(sc, td); td->state = DWC_CHAN_ST_TX_PKT_ISOC; /* FALLTHROUGH */ case DWC_CHAN_ST_TX_PKT_ISOC: - if (dwc_otg_host_channel_alloc(sc, td, 0, 1)) + if (dwc_otg_host_channel_alloc(sc, td, 1)) break; - channel = td->channel[0]; + channel = td->channel; goto send_isoc_pkt; default: break; @@ -1712,8 +1736,7 @@ check_state: send_pkt: /* free existing channel(s), if any */ - dwc_otg_host_channel_free(sc, td, 0); - dwc_otg_host_channel_free(sc, td, 1); + dwc_otg_host_channel_free(sc, td); if (td->hcsplt != 0) { delta = td->tt_start_slot - sc->sc_last_frame_num - 1; @@ -1734,12 +1757,12 @@ send_pkt: } /* allocate a new channel */ - if (dwc_otg_host_channel_alloc(sc, td, 0, 1)) { + if (dwc_otg_host_channel_alloc(sc, td, 1)) { td->state = DWC_CHAN_ST_START; goto busy; } - channel = td->channel[0]; + channel = td->channel; /* set toggle, if any */ if (td->set_toggle) { @@ -1757,7 +1780,7 @@ send_isoc_pkt: count = td->remainder; if (count > HCSPLT_XACTLEN_BURST) { DPRINTF("TT overflow\n"); - td->error = 1; + td->error_any = 1; goto complete; } /* Update transaction position */ @@ -1883,7 +1906,7 @@ send_isoc_pkt: send_cpkt: /* free existing channel, if any */ - dwc_otg_host_channel_free(sc, td, td->tt_channel_tog); + dwc_otg_host_channel_free(sc, td); delta = td->tt_complete_slot - sc->sc_last_frame_num - 1; if (td->tt_scheduled == 0 || delta < DWC_OTG_TT_SLOT_MAX) { @@ -1899,12 +1922,12 @@ send_cpkt: } /* allocate a new channel */ - if (dwc_otg_host_channel_alloc(sc, td, td->tt_channel_tog, 0)) { + if (dwc_otg_host_channel_alloc(sc, td, 0)) { td->state = DWC_CHAN_ST_WAIT_C_PKT; goto busy; } - channel = td->channel[td->tt_channel_tog]; + channel = td->channel; td->hcsplt |= HCSPLT_COMPSPLT; td->state = DWC_CHAN_ST_WAIT_C_ANE; @@ -1917,48 +1940,22 @@ send_cpkt: hcchar = td->hcchar; hcchar &= ~HCCHAR_EPDIR_IN; - /* check if other channel is allocated */ - if (td->channel[td->tt_channel_tog ^ 1] < DWC_OTG_MAX_CHANNELS) { - /* second - receive after next SOF event */ - if ((sc->sc_last_frame_num & 1) != 0) - hcchar |= HCCHAR_ODDFRM; - else - hcchar &= ~HCCHAR_ODDFRM; - - /* other channel is next */ - td->tt_channel_tog ^= 1; - /* wait until next slot before trying again */ - td->tt_complete_slot++; - - /* must enable channel before data can be received */ - DWC_OTG_WRITE_4(sc, DOTG_HCCHAR(channel), hcchar); - } else { - /* first - receive after second next SOF event */ - if ((sc->sc_last_frame_num & 1) == 0) - hcchar |= HCCHAR_ODDFRM; - else - hcchar &= ~HCCHAR_ODDFRM; + /* receive complete split ASAP */ + if ((sc->sc_last_frame_num & 1) != 0) + hcchar |= HCCHAR_ODDFRM; + else + hcchar &= ~HCCHAR_ODDFRM; - /* must enable channel before data can be received */ - DWC_OTG_WRITE_4(sc, DOTG_HCCHAR(channel), hcchar); + /* must enable channel before data can be received */ + DWC_OTG_WRITE_4(sc, DOTG_HCCHAR(channel), hcchar); - if (td->hcsplt != 0) { - if (td->ep_type == UE_ISOCHRONOUS || td->ep_type == UE_INTERRUPT) { - /* allocate a second channel */ - td->tt_channel_tog ^= 1; - goto send_cpkt; - } else { - /* wait until next slot before trying again */ - td->tt_complete_slot++; - } - } - } + /* wait until next slot before trying complete split */ + td->tt_complete_slot = sc->sc_last_frame_num + 1; busy: return (1); /* busy */ complete: - dwc_otg_host_channel_free(sc, td, 0); - dwc_otg_host_channel_free(sc, td, 1); + dwc_otg_host_channel_free(sc, td); return (0); /* complete */ } @@ -2348,6 +2345,21 @@ dwc_otg_host_channel_disable(struct dwc_ sc->sc_chan_state[x].tx_np_size = 0; } +static uint16_t +dwc_otg_compute_tt_slot(struct dwc_otg_tt_info *pinfo, uint16_t io_bytes) +{ + const uint16_t limit = (188 * 5) / 6; /* includes bit-stuffing */ + uint16_t retval = pinfo->slot_index; + + pinfo->bytes_used += io_bytes; + while (pinfo->slot_index < 6 && + pinfo->bytes_used >= limit) { + pinfo->bytes_used -= limit; + pinfo->slot_index++; + } + return (retval); +} + static uint8_t dwc_otg_update_host_transfer_schedule_locked(struct dwc_otg_softc *sc) { @@ -2356,6 +2368,7 @@ dwc_otg_update_host_transfer_schedule_lo struct usb_xfer *xfer_next; struct dwc_otg_td *td; uint16_t temp; + uint16_t slot; uint8_t x; temp = DWC_OTG_READ_4(sc, DOTG_HFNUM) & DWC_OTG_FRAME_MASK; @@ -2377,11 +2390,19 @@ dwc_otg_update_host_transfer_schedule_lo } if ((temp & 7) == 0) { + + /* reset the schedule */ + memset(sc->sc_tt_info, 0, sizeof(sc->sc_tt_info)); + TAILQ_FOREACH_SAFE(xfer, &sc->sc_bus.intr_q.head, wait_entry, xfer_next) { td = xfer->td_transfer_cache; if (td == NULL || td->ep_type != UE_ISOCHRONOUS) continue; + /* check for IN direction */ + if ((td->hcchar & HCCHAR_EPDIR_IN) != 0) + continue; + /* execute more frames */ td->tmr_val = 0; @@ -2390,9 +2411,40 @@ dwc_otg_update_host_transfer_schedule_lo if (td->hcsplt == 0 || td->tt_scheduled != 0) continue; + /* compute slot */ + slot = temp + dwc_otg_compute_tt_slot( + sc->sc_tt_info + td->tt_index, td->remainder); + /* Start ASAP */ - td->tt_start_slot = temp + 0; - td->tt_complete_slot = temp + 2; + td->tt_start_slot = slot + 0; + td->tt_scheduled = 1; + TAILQ_REMOVE(&sc->sc_bus.intr_q.head, xfer, wait_entry); + TAILQ_INSERT_TAIL(&head, xfer, wait_entry); + } + + TAILQ_FOREACH_SAFE(xfer, &sc->sc_bus.intr_q.head, wait_entry, xfer_next) { + td = xfer->td_transfer_cache; + if (td == NULL || td->ep_type != UE_ISOCHRONOUS) + continue; + + /* check for OUT direction */ + if ((td->hcchar & HCCHAR_EPDIR_IN) == 0) + continue; + + /* execute more frames */ + td->tmr_val = 0; + + sc->sc_needsof = 1; + + if (td->hcsplt == 0 || td->tt_scheduled != 0) + continue; + + /* compute slot */ + slot = temp + dwc_otg_compute_tt_slot( + sc->sc_tt_info + td->tt_index, td->remainder); + + /* Start ASAP */ + td->tt_start_slot = slot + 0; td->tt_scheduled = 1; TAILQ_REMOVE(&sc->sc_bus.intr_q.head, xfer, wait_entry); TAILQ_INSERT_TAIL(&head, xfer, wait_entry); @@ -2417,9 +2469,12 @@ dwc_otg_update_host_transfer_schedule_lo continue; } + /* compute slot */ + slot = temp + dwc_otg_compute_tt_slot(sc->sc_tt_info + td->tt_index, + td->max_packet_size); + /* start ASAP */ - td->tt_start_slot = temp + 0; - td->tt_complete_slot = temp + 2; + td->tt_start_slot = slot + 0; sc->sc_needsof = 1; td->tt_scheduled = 1; TAILQ_REMOVE(&sc->sc_bus.intr_q.head, xfer, wait_entry); @@ -2439,9 +2494,11 @@ dwc_otg_update_host_transfer_schedule_lo if (td->hcsplt == 0 || td->tt_scheduled != 0) continue; + /* compute slot */ + slot = temp + dwc_otg_compute_tt_slot(sc->sc_tt_info + td->tt_index, 0); + /* start ASAP */ - td->tt_start_slot = temp + 0; - td->tt_complete_slot = temp + 1; + td->tt_start_slot = slot + 0; td->tt_scheduled = 1; TAILQ_REMOVE(&sc->sc_bus.intr_q.head, xfer, wait_entry); TAILQ_INSERT_TAIL(&head, xfer, wait_entry); @@ -2461,9 +2518,17 @@ dwc_otg_update_host_transfer_schedule_lo if (td->hcsplt == 0 || td->tt_scheduled != 0) continue; + /* compute slot */ + slot = dwc_otg_compute_tt_slot(sc->sc_tt_info + td->tt_index, 0); + + /* figure out highest slot number */ + if (slot < (temp & 7)) + slot = temp; + else + slot += (temp & ~7); + /* start ASAP */ - td->tt_start_slot = temp + 0; - td->tt_complete_slot = temp + 1; + td->tt_start_slot = slot + 0; td->tt_scheduled = 1; TAILQ_REMOVE(&sc->sc_bus.intr_q.head, xfer, wait_entry); TAILQ_INSERT_TAIL(&head, xfer, wait_entry); @@ -2940,12 +3005,10 @@ dwc_otg_setup_standard_chain_sub(struct td->set_toggle = 0; td->got_short = 0; td->did_nak = 0; - td->channel[0] = DWC_OTG_MAX_CHANNELS; - td->channel[1] = DWC_OTG_MAX_CHANNELS; + td->channel = DWC_OTG_MAX_CHANNELS; td->state = 0; td->errcnt = 0; td->tt_scheduled = 0; - td->tt_channel_tog = 0; td->tt_xactpos = HCSPLT_XACTPOS_BEGIN; } @@ -3159,23 +3222,9 @@ dwc_otg_setup_standard_chain(struct usb_ (xfer->address << HCCHAR_DEVADDR_SHIFT) | ((xfer->endpointno & UE_ADDR) << HCCHAR_EPNUM_SHIFT) | (xfer->max_packet_size << HCCHAR_MPS_SHIFT) | + (td->ep_type << HCCHAR_EPTYPE_SHIFT) | HCCHAR_CHENA; - /* - * XXX stability hack - possible HW issue - * - * Disable workaround when using a transaction - * translator, hence some TTs reject control endpoint - * traffic using BULK endpoint type: - */ - if (td->ep_type == UE_CONTROL && - (xfer->xroot->udev->speed == USB_SPEED_HIGH || - xfer->xroot->udev->parent_hs_hub == NULL)) { - hcchar |= (UE_BULK << HCCHAR_EPTYPE_SHIFT); - } else { - hcchar |= (td->ep_type << HCCHAR_EPTYPE_SHIFT); - } - if (usbd_get_speed(xfer->xroot->udev) == USB_SPEED_LOW) hcchar |= HCCHAR_LSPDDEV; if (UE_GET_DIR(xfer->endpointno) == UE_DIR_IN) @@ -3472,12 +3521,9 @@ dwc_otg_device_done(struct usb_xfer *xfe } else { struct dwc_otg_td *td; - td = xfer->td_transfer_first; - - if (td != NULL) { - dwc_otg_host_channel_free(sc, td, 0); - dwc_otg_host_channel_free(sc, td, 1); - } + td = xfer->td_transfer_cache; + if (td != NULL) + dwc_otg_host_channel_free(sc, td); } /* dequeue transfer and start next transfer */ usbd_transfer_done(xfer, error); @@ -4674,6 +4720,16 @@ dwc_otg_xfer_setup(struct usb_setup_para td = USB_ADD_BYTES(parm->buf, parm->size[0]); + /* compute shared bandwidth resource index for TT */ + if (parm->udev->parent_hs_hub != NULL && parm->udev->speed != USB_SPEED_HIGH) { + if (parm->udev->parent_hs_hub->ddesc.bDeviceProtocol == UDPROTO_HSHUBMTT) + td->tt_index = parm->udev->device_index; + else + td->tt_index = parm->udev->parent_hs_hub->device_index; + } else { + td->tt_index = parm->udev->device_index; + } + /* init TD */ td->max_packet_size = xfer->max_packet_size; td->max_packet_count = xfer->max_packet_count; Modified: head/sys/dev/usb/controller/dwc_otg.h ============================================================================== --- head/sys/dev/usb/controller/dwc_otg.h Thu Jun 5 18:01:59 2014 (r267119) +++ head/sys/dev/usb/controller/dwc_otg.h Thu Jun 5 18:17:40 2014 (r267120) @@ -68,7 +68,8 @@ struct dwc_otg_td { uint8_t did_nak; /* NAK counter */ uint8_t ep_no; uint8_t ep_type; - uint8_t channel[2]; + uint8_t channel; + uint8_t tt_index; /* TT data */ uint8_t tt_start_slot; /* TT data */ uint8_t tt_complete_slot; /* TT data */ uint8_t tt_xactpos; /* TT data */ @@ -80,7 +81,6 @@ struct dwc_otg_td { #define DWC_CHAN_ST_WAIT_C_PKT 4 #define DWC_CHAN_ST_TX_PKT_ISOC 5 #define DWC_CHAN_ST_TX_WAIT_ISOC 6 - uint8_t error:1; uint8_t error_any:1; uint8_t error_stall:1; uint8_t alt_next:1; @@ -90,7 +90,12 @@ struct dwc_otg_td { uint8_t set_toggle:1; uint8_t got_short:1; uint8_t tt_scheduled:1; - uint8_t tt_channel_tog:1; +}; + +struct dwc_otg_tt_info { + uint16_t bytes_used; + uint8_t slot_index; + uint8_t dummy; }; struct dwc_otg_std_temp { @@ -160,6 +165,7 @@ struct dwc_otg_softc { struct usb_bus sc_bus; union dwc_otg_hub_temp sc_hub_temp; struct dwc_otg_profile sc_hw_ep_profile[DWC_OTG_MAX_ENDPOINTS]; + struct dwc_otg_tt_info sc_tt_info[DWC_OTG_MAX_DEVICES]; struct usb_callout sc_timer; struct usb_device *sc_devices[DWC_OTG_MAX_DEVICES];