Date: Wed, 14 May 2014 19:05:16 +0800 From: Ganbold Tsagaankhuu <ganbold@gmail.com> To: Hans Petter Selasky <hselasky@freebsd.org> Cc: svn-src-head@freebsd.org, svn-src-all@freebsd.org, src-committers@freebsd.org Subject: Re: svn commit: r265358 - head/sys/dev/usb/controller Message-ID: <CAGtf9xPgA0Urb7bZRoiRVFGBWCjHHFHU7wRYd_HrjBR2Jdj0cg@mail.gmail.com> In-Reply-To: <201405051150.s45BoqID055514@svn.freebsd.org> References: <201405051150.s45BoqID055514@svn.freebsd.org>
next in thread | previous in thread | raw e-mail | index | archive | help
Hans On Mon, May 5, 2014 at 7:50 PM, Hans Petter Selasky <hselasky@freebsd.org>wrote: > Author: hselasky > Date: Mon May 5 11:50:52 2014 > New Revision: 265358 > URL: http://svnweb.freebsd.org/changeset/base/265358 > > Log: > Improve DWC OTG USB host side support for isochronous FULL and HIGH > speed data traffic going directly to a USB device or through a > so-called USB transaction translator. > > Add checks that we are not overusing the TX FIFO. > > MFC after: 2 weeks > > Modified: > head/sys/dev/usb/controller/dwc_otg.c > head/sys/dev/usb/controller/dwc_otg.h > head/sys/dev/usb/controller/dwc_otgreg.h > > Modified: head/sys/dev/usb/controller/dwc_otg.c > > ============================================================================== > --- head/sys/dev/usb/controller/dwc_otg.c Mon May 5 11:30:45 2014 > (r265357) > +++ head/sys/dev/usb/controller/dwc_otg.c Mon May 5 11:50:52 2014 > (r265358) > @@ -207,6 +207,12 @@ dwc_otg_init_fifo(struct dwc_otg_softc * > /* reset active endpoints */ > sc->sc_active_rx_ep = 0; > > + /* reset TX size */ > + sc->sc_tx_cur_size = 0; > + > + /* reset TT info */ > + memset(sc->sc_tt_info, 0, sizeof(sc->sc_tt_info)); > + > fifo_size /= 2; > > DWC_OTG_WRITE_4(sc, DOTG_GNPTXFSIZ, > @@ -215,19 +221,17 @@ dwc_otg_init_fifo(struct dwc_otg_softc * > > tx_start += fifo_size; > > + for (x = 0; x != sc->sc_host_ch_max; x++) { > + /* enable all needed interrupts */ > + DWC_OTG_WRITE_4(sc, DOTG_HCINTMSK(x), > HCINT_DEFAULT_MASK); > + } > + > DWC_OTG_WRITE_4(sc, DOTG_HPTXFSIZ, > ((fifo_size / 4) << 16) | > (tx_start / 4)); > > - for (x = 0; x != sc->sc_host_ch_max; x++) { > - /* enable interrupts */ > - DWC_OTG_WRITE_4(sc, DOTG_HCINTMSK(x), > - HCINT_STALL | HCINT_BBLERR | > - HCINT_XACTERR | > - HCINT_NAK | HCINT_ACK | HCINT_NYET | > - HCINT_CHHLTD | HCINT_FRMOVRUN | > - HCINT_DATATGLERR); > - } > + /* store maximum TX FIFO size */ > + sc->sc_tx_max_size = fifo_size; > > /* enable host channel interrupts */ > DWC_OTG_WRITE_4(sc, DOTG_HAINTMSK, > @@ -309,6 +313,12 @@ dwc_otg_init_fifo(struct dwc_otg_softc * > } else { > /* reset active endpoints */ > sc->sc_active_rx_ep = 0; > + > + /* reset TX size */ > + sc->sc_tx_cur_size = 0; > + > + /* reset TT info */ > + memset(sc->sc_tt_info, 0, sizeof(sc->sc_tt_info)); > } > return (0); > } > @@ -376,9 +386,9 @@ dwc_otg_pull_down(struct dwc_otg_softc * > static void > dwc_otg_enable_sof_irq(struct dwc_otg_softc *sc) > { > - if (sc->sc_irq_mask & GINTSTS_SOF) > + if (sc->sc_irq_mask & GINTMSK_SOFMSK) > return; > - sc->sc_irq_mask |= GINTSTS_SOF; > + sc->sc_irq_mask |= GINTMSK_SOFMSK; > DWC_OTG_WRITE_4(sc, DOTG_GINTMSK, sc->sc_irq_mask); > } > > @@ -506,6 +516,7 @@ dwc_otg_clear_hcint(struct dwc_otg_softc > { > uint32_t hcint; > > + /* clear all pending interrupts */ > hcint = DWC_OTG_READ_4(sc, DOTG_HCINT(x)); > DWC_OTG_WRITE_4(sc, DOTG_HCINT(x), hcint); > > @@ -513,6 +524,10 @@ dwc_otg_clear_hcint(struct dwc_otg_softc > sc->sc_chan_state[x].hcint = 0; > } > > +/* > + * This function waits until a DWC OTG host channel is ready to be > + * used again: > + */ > static uint8_t > dwc_otg_host_channel_wait(struct dwc_otg_td *td) > { > @@ -545,6 +560,9 @@ dwc_otg_host_channel_wait(struct dwc_otg > sc->sc_chan_state[td->channel].allocated = 0; > sc->sc_chan_state[x].allocated = 1; > > + sc->sc_chan_state[x].tx_size = > + sc->sc_chan_state[td->channel].tx_size; > + > if (sc->sc_chan_state[td->channel].suspended) { > sc->sc_chan_state[td->channel].suspended = 0; > sc->sc_chan_state[x].suspended = 1; > @@ -579,6 +597,7 @@ static uint8_t > dwc_otg_host_channel_alloc(struct dwc_otg_td *td) > { > struct dwc_otg_softc *sc; > + uint32_t tx_size; > uint8_t x; > uint8_t max_channel; > > @@ -591,9 +610,25 @@ dwc_otg_host_channel_alloc(struct dwc_ot > if ((td->hcchar & HCCHAR_EPNUM_MASK) == 0) { > max_channel = 1; > x = 0; > + tx_size = td->max_packet_size; > + if ((sc->sc_tx_cur_size + tx_size) > sc->sc_tx_max_size) { > + DPRINTF("Too little FIFO space\n"); > + return (1); /* too little FIFO */ > + } > } else { > max_channel = sc->sc_host_ch_max; > x = 1; > + if ((td->hcchar & HCCHAR_EPDIR) == HCCHAR_EPDIR_OUT) { > + tx_size = td->max_packet_size; > + if (td->hcsplt != 0 && tx_size > > HCSPLT_XACTLEN_MAX) > + tx_size = HCSPLT_XACTLEN_MAX; > + if ((sc->sc_tx_cur_size + tx_size) > > sc->sc_tx_max_size) { > + DPRINTF("Too little FIFO space\n"); > + return (1); /* too little FIFO */ > + } > + } else { > + tx_size = 0; > + } > } > > for (; x != max_channel; x++) { > @@ -604,6 +639,10 @@ dwc_otg_host_channel_alloc(struct dwc_ot > continue; > > sc->sc_chan_state[x].allocated = 1; > + sc->sc_chan_state[x].tx_size = tx_size; > + > + /* keep track of used FIFO */ > + sc->sc_tx_cur_size += tx_size; > > /* clear interrupts */ > dwc_otg_clear_hcint(sc, x); > @@ -663,6 +702,9 @@ dwc_otg_host_channel_free(struct dwc_otg > sc->sc_chan_state[x].allocated = 0; > sc->sc_chan_state[x].suspended = 0; > > + /* keep track of used FIFO */ > + sc->sc_tx_cur_size -= sc->sc_chan_state[x].tx_size; > + > /* ack any pending messages */ > if (sc->sc_last_rx_status != 0 && > GRXSTSRD_CHNUM_GET(sc->sc_last_rx_status) == x) { > @@ -724,6 +766,8 @@ dwc_otg_host_setup_tx(struct dwc_otg_td > > switch (td->state) { > case DWC_CHAN_ST_START: > + if (!dwc_otg_host_channel_wait(td)) > + break; > goto send_pkt; > > case DWC_CHAN_ST_WAIT_ANE: > @@ -731,6 +775,7 @@ dwc_otg_host_setup_tx(struct dwc_otg_td > if (!dwc_otg_host_channel_wait(td)) > break; > td->did_nak = 1; > + td->tt_scheduled = 0; > goto send_pkt; > } > if (hcint & (HCINT_ACK | HCINT_NYET)) { > @@ -739,14 +784,17 @@ dwc_otg_host_setup_tx(struct dwc_otg_td > td->offset += td->tx_bytes; > td->remainder -= td->tx_bytes; > td->toggle = 1; > + td->tt_scheduled = 0; > return (0); /* complete */ > } > break; > + > case DWC_CHAN_ST_WAIT_S_ANE: > if (hcint & (HCINT_RETRY | HCINT_ERRORS)) { > if (!dwc_otg_host_channel_wait(td)) > break; > td->did_nak = 1; > + td->tt_scheduled = 0; > goto send_pkt; > } > if (hcint & (HCINT_ACK | HCINT_NYET)) { > @@ -755,6 +803,7 @@ dwc_otg_host_setup_tx(struct dwc_otg_td > goto send_cpkt; > } > break; > + > case DWC_CHAN_ST_WAIT_C_ANE: > if (hcint & HCINT_NYET) { > if (!dwc_otg_host_channel_wait(td)) > @@ -765,6 +814,7 @@ dwc_otg_host_setup_tx(struct dwc_otg_td > if (!dwc_otg_host_channel_wait(td)) > break; > td->did_nak = 1; > + td->tt_scheduled = 0; > goto send_pkt; > } > if (hcint & HCINT_ACK) { > @@ -776,8 +826,12 @@ dwc_otg_host_setup_tx(struct dwc_otg_td > return (0); /* complete */ > } > break; > - case DWC_CHAN_ST_TX_PKT_SYNC: > - goto send_pkt_sync; > + > + case DWC_CHAN_ST_WAIT_C_PKT: > + if (!dwc_otg_host_channel_wait(td)) > + break; > + goto send_cpkt; > + > default: > break; > } > @@ -789,19 +843,13 @@ send_pkt: > return (0); /* complete */ > } > > -send_pkt_sync: > if (td->hcsplt != 0) { > - uint32_t count; > - > - count = DWC_OTG_READ_4(sc, DOTG_HFNUM) & 7; > - /* check for not first microframe */ > - if (count != 0) { > - /* enable SOF interrupt */ > - dwc_otg_enable_sof_irq(sc); > - /* set state */ > - td->state = DWC_CHAN_ST_TX_PKT_SYNC; > - dwc_otg_host_channel_free(td); > - return (1); /* busy */ > + /* Wait for our turn, if TT transfer */ > + if (td->tt_scheduled == 0 || > + (sc->sc_last_frame_num & 7) < td->tt_start_slot) { > + /* set return state */ > + td->state = DWC_CHAN_ST_START; > + goto tt_wait; > } > > td->hcsplt &= ~HCSPLT_COMPSPLT; > @@ -835,6 +883,16 @@ send_pkt_sync: > return (1); /* busy */ > > send_cpkt: > + /* Wait for our turn, if TT transfer */ > + if (td->tt_scheduled == 0 || > + (sc->sc_last_frame_num & 7) < td->tt_complete_slot) { > + /* set return state */ > + td->state = DWC_CHAN_ST_WAIT_C_PKT; > + goto tt_wait; > + } > + /* wait until next slot before trying again */ > + td->tt_complete_slot++; > + > td->hcsplt |= HCSPLT_COMPSPLT; > td->state = DWC_CHAN_ST_WAIT_C_ANE; > > @@ -848,7 +906,14 @@ send_cpkt: > > /* must enable channel before writing data to FIFO */ > DWC_OTG_WRITE_4(sc, DOTG_HCCHAR(td->channel), hcchar); > + return (1); /* busy */ > > +tt_wait: > + /* enable SOF interrupt */ > + dwc_otg_enable_sof_irq(sc); > + > + /* free allocated channel */ > + dwc_otg_host_channel_free(td); > return (1); /* busy */ > } > > @@ -984,6 +1049,25 @@ not_complete: > } > > static uint8_t > +dwc_otg_host_rate_check_interrupt(struct dwc_otg_softc *sc, struct > dwc_otg_td *td) > +{ > + uint8_t delta; > + > + delta = sc->sc_tmr_val - td->tmr_val; > + if (delta >= 128) > + return (1); /* busy */ > + > + td->tmr_val = sc->sc_tmr_val + td->tmr_res; > + > + /* set toggle, if any */ > + if (td->set_toggle) { > + td->set_toggle = 0; > + td->toggle = 1; > + } > + return (0); > +} > + > +static uint8_t > dwc_otg_host_rate_check(struct dwc_otg_td *td) > { > struct dwc_otg_softc *sc; > @@ -992,31 +1076,30 @@ dwc_otg_host_rate_check(struct dwc_otg_t > /* get pointer to softc */ > sc = DWC_OTG_PC2SC(td->pc); > > + if (td->channel < DWC_OTG_MAX_CHANNELS && > + sc->sc_chan_state[td->channel].suspended) > + goto busy; > + > ep_type = ((td->hcchar & > HCCHAR_EPTYPE_MASK) >> HCCHAR_EPTYPE_SHIFT); > > - if (sc->sc_chan_state[td->channel].suspended) > - goto busy; > - > if (ep_type == UE_ISOCHRONOUS) { > - if (td->tmr_val & 1) > - td->hcchar |= HCCHAR_ODDFRM; > - else > - td->hcchar &= ~HCCHAR_ODDFRM; > - td->tmr_val += td->tmr_res; > - } else if (ep_type == UE_INTERRUPT) { > - uint8_t delta; > > - delta = sc->sc_tmr_val - td->tmr_val; > - if (delta >= 128) > + /* non TT isochronous traffic */ > + if ((td->tmr_val != 0) || > + (sc->sc_last_frame_num & (td->tmr_res - 1))) { > + /* enable SOF interrupt */ > + dwc_otg_enable_sof_irq(sc); > goto busy; > - td->tmr_val = sc->sc_tmr_val + td->tmr_res; > + } > + td->tmr_val = 1; /* executed */ > + td->toggle = 0; > + > + } else if (ep_type == UE_INTERRUPT) { > + /* non TT interrupt traffic */ > + return (dwc_otg_host_rate_check_interrupt(sc, td)); > } else if (td->did_nak != 0) { > goto busy; > - } > - > - if (ep_type == UE_ISOCHRONOUS) { > - td->toggle = 0; > } else if (td->set_toggle) { > td->set_toggle = 0; > td->toggle = 1; > @@ -1065,8 +1148,10 @@ dwc_otg_host_data_rx(struct dwc_otg_td * > DPRINTF("CH=%d ERROR\n", td->channel); > td->errcnt++; > if (td->hcsplt != 0 || td->errcnt >= 3) { > - td->error_any = 1; > - return (0); /* complete */ > + if (ep_type != UE_ISOCHRONOUS) { > + td->error_any = 1; > + return (0); /* complete */ > + } > } > } > > @@ -1103,25 +1188,42 @@ dwc_otg_host_data_rx(struct dwc_otg_td * > break; > } > > - td->toggle ^= 1; > - > /* get the packet byte count */ > count = GRXSTSRD_BCNT_GET(sc->sc_last_rx_status); > > - /* verify the packet byte count */ > - if (count != td->max_packet_size) { > - if (count < td->max_packet_size) { > - /* we have a short packet */ > - td->short_pkt = 1; > - td->got_short = 1; > + /* check for isochronous transfer or high-speed bandwidth > endpoint */ > + if (ep_type == UE_ISOCHRONOUS || td->max_packet_count > 1) > { > + if ((sc->sc_last_rx_status & GRXSTSRD_DPID_MASK) > != GRXSTSRD_DPID_DATA0) { > + td->tt_xactpos = HCSPLT_XACTPOS_MIDDLE; > } else { > - /* invalid USB packet */ > - td->error_any = 1; > + td->tt_xactpos = HCSPLT_XACTPOS_BEGIN; > + > + /* verify the packet byte count */ > + if (count < td->max_packet_size) { > + /* we have a short packet */ > + td->short_pkt = 1; > + td->got_short = 1; > + } > + } > + td->toggle = 0; > + } else { > + /* verify the packet byte count */ > + if (count != td->max_packet_size) { > + if (count < td->max_packet_size) { > + /* we have a short packet */ > + td->short_pkt = 1; > + td->got_short = 1; > + } else { > + /* invalid USB packet */ > + td->error_any = 1; > > - /* release FIFO */ > - dwc_otg_common_rx_ack(sc); > - return (0); /* we are complete */ > + /* release FIFO */ > + dwc_otg_common_rx_ack(sc); > + return (0); /* we are complete > */ > + } > } > + td->toggle ^= 1; > + td->tt_scheduled = 0; > } > > /* verify the packet byte count */ > @@ -1144,7 +1246,6 @@ dwc_otg_host_data_rx(struct dwc_otg_td * > break; > > default: > - DPRINTF("OTHER\n"); > break; > } > /* release FIFO */ > @@ -1153,6 +1254,8 @@ dwc_otg_host_data_rx(struct dwc_otg_td * > check_state: > switch (td->state) { > case DWC_CHAN_ST_START: > + if (!dwc_otg_host_channel_wait(td)) > + break; > if (td->hcsplt != 0) > goto receive_spkt; > else > @@ -1164,6 +1267,7 @@ check_state: > break; > > td->did_nak = 1; > + td->tt_scheduled = 0; > if (td->hcsplt != 0) > goto receive_spkt; > else > @@ -1171,11 +1275,13 @@ check_state: > } > if (!(hcint & HCINT_SOFTWARE_ONLY)) { > if (hcint & HCINT_NYET) { > - if (td->hcsplt != 0) { > - if (!dwc_otg_host_channel_wait(td)) > - break; > - goto receive_pkt; > + if (ep_type == UE_ISOCHRONOUS) { > + /* we missed the service interval > */ > + return (0); /* complete */ > } > + if (!dwc_otg_host_channel_wait(td)) > + break; > + goto receive_pkt; > } > break; > } > @@ -1183,29 +1289,44 @@ check_state: > if (!dwc_otg_host_channel_wait(td)) > break; > > - /* check if we are complete */ > - if ((td->remainder == 0) || (td->got_short != 0)) { > - if (td->short_pkt) > + if (ep_type == UE_ISOCHRONOUS) { > + /* check if we are complete */ > + if ((td->remainder == 0) || > + (td->tt_xactpos == > HCSPLT_XACTPOS_BEGIN)) > return (0); /* complete */ > > - /* > - * Else need to receive a zero length > - * packet. > - */ > - } > - if (td->hcsplt != 0) > - goto receive_spkt; > - else > goto receive_pkt; > + } else { > + /* check if we are complete */ > + if ((td->remainder == 0) || (td->got_short > != 0)) { > + if (td->short_pkt) > + return (0); /* > complete */ > + > + /* > + * Else need to receive a zero > length > + * packet. > + */ > + } > + td->tt_scheduled = 0; > + if (td->hcsplt != 0) > + goto receive_spkt; > + else > + goto receive_pkt; > + } > } > break; > > case DWC_CHAN_ST_WAIT_S_ANE: > + /* > + * NOTE: The DWC OTG hardware provides a fake ACK in > + * case of interrupt and isochronous transfers: > + */ > if (hcint & (HCINT_RETRY | HCINT_ERRORS)) { > if (!dwc_otg_host_channel_wait(td)) > break; > > td->did_nak = 1; > + td->tt_scheduled = 0; > goto receive_spkt; > } > if (hcint & (HCINT_ACK | HCINT_NYET)) { > @@ -1215,100 +1336,91 @@ check_state: > } > break; > > - case DWC_CHAN_ST_RX_PKT: > + case DWC_CHAN_ST_WAIT_C_PKT: > + if (!dwc_otg_host_channel_wait(td)) > + break; > goto receive_pkt; > > - case DWC_CHAN_ST_RX_SPKT: > - goto receive_spkt; > - > - case DWC_CHAN_ST_RX_SPKT_SYNC: > - goto receive_spkt_sync; > - > default: > break; > } > goto busy; > > receive_pkt: > - if (td->hcsplt != 0) { > - count = DWC_OTG_READ_4(sc, DOTG_HFNUM) & 7; > - > - /* check for even microframes */ > - if (count == td->curr_frame) { > - td->state = DWC_CHAN_ST_RX_PKT; > - dwc_otg_host_channel_free(td); > - /* enable SOF interrupt */ > - dwc_otg_enable_sof_irq(sc); > - goto busy; > - } else if (count == 0) { > - /* check for start split timeout */ > - goto receive_spkt; > + if (td->hcsplt != 0) { > + /* Wait for our turn, if TT transfer */ > + if (td->tt_scheduled == 0 || > + (sc->sc_last_frame_num & 7) < td->tt_complete_slot) { > + /* set return state */ > + td->state = DWC_CHAN_ST_WAIT_C_PKT; > + goto tt_wait; > + } > + /* wait until next slot before trying again */ > + td->tt_complete_slot++; > + > + /* set toggle, if any */ > + if (td->set_toggle) { > + td->set_toggle = 0; > + td->toggle = 1; > } > - > - td->curr_frame = count; > td->hcsplt |= HCSPLT_COMPSPLT; > - } else if (dwc_otg_host_rate_check(td)) { > - td->state = DWC_CHAN_ST_RX_PKT; > + count = HCSPLT_XACTLEN_MAX; > + } else if (td->tt_xactpos == HCSPLT_XACTPOS_BEGIN && > + dwc_otg_host_rate_check(td)) { > + td->state = DWC_CHAN_ST_START; > dwc_otg_host_channel_free(td); > goto busy; > + } else { > + count = td->max_packet_size; > } > - > td->state = DWC_CHAN_ST_WAIT_ANE; > > /* receive one packet */ > DWC_OTG_WRITE_4(sc, DOTG_HCTSIZ(td->channel), > - (td->max_packet_size << HCTSIZ_XFERSIZE_SHIFT) | > + (count << HCTSIZ_XFERSIZE_SHIFT) | > (1 << HCTSIZ_PKTCNT_SHIFT) | > (td->toggle ? (HCTSIZ_PID_DATA1 << HCTSIZ_PID_SHIFT) : > (HCTSIZ_PID_DATA0 << HCTSIZ_PID_SHIFT))); > > DWC_OTG_WRITE_4(sc, DOTG_HCSPLT(td->channel), td->hcsplt); > > + /* send ASAP */ > + if ((ep_type == UE_ISOCHRONOUS) && !(sc->sc_last_frame_num & 1)) > + td->hcchar |= HCCHAR_ODDFRM; > + else > + td->hcchar &= ~HCCHAR_ODDFRM; > + > hcchar = td->hcchar; > hcchar |= HCCHAR_EPDIR_IN; > > /* must enable channel before data can be received */ > DWC_OTG_WRITE_4(sc, DOTG_HCCHAR(td->channel), hcchar); > - > goto busy; > > receive_spkt: > - if (dwc_otg_host_rate_check(td)) { > - td->state = DWC_CHAN_ST_RX_SPKT; > - dwc_otg_host_channel_free(td); > - goto busy; > - } > - > -receive_spkt_sync: > - if (ep_type == UE_INTERRUPT || > - ep_type == UE_ISOCHRONOUS) { > - count = DWC_OTG_READ_4(sc, DOTG_HFNUM) & 7; > - td->curr_frame = count; > - > - /* check for non-zero microframe */ > - if (count != 0) { > - /* enable SOF interrupt */ > - dwc_otg_enable_sof_irq(sc); > - /* set state */ > - td->state = DWC_CHAN_ST_RX_SPKT_SYNC; > - dwc_otg_host_channel_free(td); > - goto busy; > - } > - } else { > - count = DWC_OTG_READ_4(sc, DOTG_HFNUM) & 7; > - td->curr_frame = count; > - > - /* check for two last frames */ > - if (count >= 6) { > - /* enable SOF interrupt */ > - dwc_otg_enable_sof_irq(sc); > - /* set state */ > - td->state = DWC_CHAN_ST_RX_SPKT_SYNC; > + /* Wait for our turn, if TT transfer */ > + if (td->tt_scheduled == 0) { > + if (ep_type == UE_INTERRUPT) { > + td->state = DWC_CHAN_ST_START; > dwc_otg_host_channel_free(td); > goto busy; > } > + /* set return state */ > + td->state = DWC_CHAN_ST_START; > + goto tt_wait; > + } > + if ((sc->sc_last_frame_num & 7) < td->tt_start_slot) { > + /* set return state */ > + td->state = DWC_CHAN_ST_START; > + goto tt_wait; > } > > + /* send ASAP */ > + if ((ep_type == UE_ISOCHRONOUS) && !(sc->sc_last_frame_num & 1)) > + td->hcchar |= HCCHAR_ODDFRM; > + else > + td->hcchar &= ~HCCHAR_ODDFRM; > + > td->hcsplt &= ~HCSPLT_COMPSPLT; > td->state = DWC_CHAN_ST_WAIT_S_ANE; > > @@ -1324,7 +1436,14 @@ receive_spkt_sync: > > /* must enable channel before data can be received */ > DWC_OTG_WRITE_4(sc, DOTG_HCCHAR(td->channel), hcchar); > + goto busy; > + > +tt_wait: > + /* enable SOF interrupt */ > + dwc_otg_enable_sof_irq(sc); > > + /* free allocated channel */ > + dwc_otg_host_channel_free(td); > busy: > return (1); /* busy */ > } > @@ -1497,6 +1616,8 @@ dwc_otg_host_data_tx(struct dwc_otg_td * > > switch (td->state) { > case DWC_CHAN_ST_START: > + if (!dwc_otg_host_channel_wait(td)) > + break; > goto send_pkt; > > case DWC_CHAN_ST_WAIT_ANE: > @@ -1504,6 +1625,7 @@ dwc_otg_host_data_tx(struct dwc_otg_td * > if (!dwc_otg_host_channel_wait(td)) > break; > td->did_nak = 1; > + td->tt_scheduled = 0; > goto send_pkt; > } > if (hcint & (HCINT_ACK | HCINT_NYET)) { > @@ -1513,6 +1635,7 @@ dwc_otg_host_data_tx(struct dwc_otg_td * > td->offset += td->tx_bytes; > td->remainder -= td->tx_bytes; > td->toggle ^= 1; > + td->tt_scheduled = 0; > > /* check remainder */ > if (td->remainder == 0) { > @@ -1527,11 +1650,13 @@ dwc_otg_host_data_tx(struct dwc_otg_td * > goto send_pkt; > } > break; > + > case DWC_CHAN_ST_WAIT_S_ANE: > if (hcint & (HCINT_RETRY | HCINT_ERRORS)) { > if (!dwc_otg_host_channel_wait(td)) > break; > td->did_nak = 1; > + td->tt_scheduled = 0; > goto send_pkt; > } > if (hcint & (HCINT_ACK | HCINT_NYET)) { > @@ -1540,6 +1665,7 @@ dwc_otg_host_data_tx(struct dwc_otg_td * > goto send_cpkt; > } > break; > + > case DWC_CHAN_ST_WAIT_C_ANE: > if (hcint & HCINT_NYET) { > if (!dwc_otg_host_channel_wait(td)) > @@ -1550,6 +1676,7 @@ dwc_otg_host_data_tx(struct dwc_otg_td * > if (!dwc_otg_host_channel_wait(td)) > break; > td->did_nak = 1; > + td->tt_scheduled = 0; > goto send_pkt; > } > if (hcint & HCINT_ACK) { > @@ -1558,6 +1685,7 @@ dwc_otg_host_data_tx(struct dwc_otg_td * > td->offset += td->tx_bytes; > td->remainder -= td->tx_bytes; > td->toggle ^= 1; > + td->tt_scheduled = 0; > > /* check remainder */ > if (td->remainder == 0) { > @@ -1570,64 +1698,204 @@ dwc_otg_host_data_tx(struct dwc_otg_td * > } > break; > > - case DWC_CHAN_ST_TX_PKT: > - goto send_pkt; > + case DWC_CHAN_ST_WAIT_C_PKT: > + if (!dwc_otg_host_channel_wait(td)) > + break; > + goto send_cpkt; > > - case DWC_CHAN_ST_TX_PKT_SYNC: > - goto send_pkt_sync; > + case DWC_CHAN_ST_TX_WAIT_ISOC: > > - case DWC_CHAN_ST_TX_CPKT: > - goto send_cpkt; > + /* Check if isochronous OUT traffic is complete */ > + if ((hcint & HCINT_ACK) == 0) > + break; > + > + td->offset += td->tx_bytes; > + td->remainder -= td->tx_bytes; > > + /* Update split token according to specification */ > + if (td->hcsplt != 0) { > + if (td->tt_xactpos == HCSPLT_XACTPOS_BEGIN) > + td->tt_xactpos = HCSPLT_XACTPOS_MIDDLE; > + } else if (td->max_packet_count > 1) { > + td->tt_xactpos++; > + } > + > + dwc_otg_host_channel_disable(sc, td->channel); > + > + if (td->remainder == 0) > + return (0); /* complete */ > + > + td->state = DWC_CHAN_ST_TX_PKT_ISOC; > + > + /* FALLTHROUGH */ > + > + case DWC_CHAN_ST_TX_PKT_ISOC: > + if (!dwc_otg_host_channel_wait(td)) > + break; > + > + if (td->hcsplt != 0) { > + if ((sc->sc_last_frame_num & 7) < > td->tt_start_slot) > + goto tt_wait; > + /* packets must be 125us apart */ > + td->tt_start_slot++; > + } > + goto send_isoc_pkt; > default: > break; > } > goto busy; > > send_pkt: > - if (dwc_otg_host_rate_check(td)) { > - td->state = DWC_CHAN_ST_TX_PKT; > + if (td->hcsplt != 0) { > + /* Wait for our turn, if TT transfer */ > + if (td->tt_scheduled == 0) { > + if (ep_type == UE_INTERRUPT) { > + td->state = DWC_CHAN_ST_START; > + dwc_otg_host_channel_free(td); > + goto busy; > + } > + /* set return state */ > + td->state = DWC_CHAN_ST_START; > + goto tt_wait; > + } > + if ((sc->sc_last_frame_num & 7) < td->tt_start_slot) { > + /* set return state */ > + td->state = DWC_CHAN_ST_START; > + goto tt_wait; > + } > + > + /* packets must be 125us apart */ > + td->tt_start_slot++; > + > + /* set toggle, if any */ > + if (td->set_toggle) { > + td->set_toggle = 0; > + td->toggle = 1; > + } > + } else if (dwc_otg_host_rate_check(td)) { > + td->state = DWC_CHAN_ST_START; > dwc_otg_host_channel_free(td); > goto busy; > } > > -send_pkt_sync: > - if (td->hcsplt != 0) { > - count = DWC_OTG_READ_4(sc, DOTG_HFNUM) & 7; > - /* check for first or last microframe */ > - if (count == 7 || count == 0) { > - /* enable SOF interrupt */ > - dwc_otg_enable_sof_irq(sc); > - /* set state */ > - td->state = DWC_CHAN_ST_TX_PKT_SYNC; > - dwc_otg_host_channel_free(td); > - goto busy; > + if (ep_type == UE_ISOCHRONOUS) { > +send_isoc_pkt: > + /* Isochronous OUT transfers don't have any ACKs */ > + td->state = DWC_CHAN_ST_TX_WAIT_ISOC; > + td->hcsplt &= ~HCSPLT_COMPSPLT; > + if (td->hcsplt != 0) { > + /* get maximum transfer length */ > + count = td->remainder; > + > + /* Update split token according to specification */ > + if (td->tt_xactpos == HCSPLT_XACTPOS_BEGIN) { > + if (count <= HCSPLT_XACTLEN_MAX) > + td->tt_xactpos = > HCSPLT_XACTPOS_ALL; > + else > + count = HCSPLT_XACTLEN_MAX; > + } else if (td->tt_xactpos == > HCSPLT_XACTPOS_MIDDLE) { > + if (count <= HCSPLT_XACTLEN_MAX) > + td->tt_xactpos = > HCSPLT_XACTPOS_LAST; > + else > + count = HCSPLT_XACTLEN_MAX; > + } > + > + /* Update transaction position */ > + td->hcsplt &= ~HCSPLT_XACTPOS_MASK; > + td->hcsplt |= ((uint32_t)td->tt_xactpos << > HCSPLT_XACTPOS_SHIFT); > + } else { > + /* send one packet at a time */ > + count = td->max_packet_size; > + if (td->remainder < count) { > + /* we have a short packet */ > + td->short_pkt = 1; > + count = td->remainder; > + } > } > + } else if (td->hcsplt != 0) { > > td->hcsplt &= ~HCSPLT_COMPSPLT; > + > + /* Wait for ACK/NAK/ERR from TT */ > td->state = DWC_CHAN_ST_WAIT_S_ANE; > + > + /* send one packet at a time */ > + count = td->max_packet_size; > + if (td->remainder < count) { > + /* we have a short packet */ > + td->short_pkt = 1; > + count = td->remainder; > + } > } else { > + /* Wait for ACK/NAK/STALL from device */ > td->state = DWC_CHAN_ST_WAIT_ANE; > - } > > - /* send one packet at a time */ > - count = td->max_packet_size; > - if (td->remainder < count) { > - /* we have a short packet */ > - td->short_pkt = 1; > - count = td->remainder; > + /* send one packet at a time */ > + count = td->max_packet_size; > + if (td->remainder < count) { > + /* we have a short packet */ > + td->short_pkt = 1; > + count = td->remainder; > + } > } > > - /* TODO: HCTSIZ_DOPNG */ > + /* check for High-Speed multi-packets */ > + if ((td->hcsplt == 0) && (td->max_packet_count > 1)) { > + if (td->npkt == 0) { > + if (td->remainder >= (3 * td->max_packet_size)) > + td->npkt = 3; > + else if (td->remainder >= (2 * > td->max_packet_size)) > + td->npkt = 2; > + else > + td->npkt = 1; > > - DWC_OTG_WRITE_4(sc, DOTG_HCTSIZ(td->channel), > - (count << HCTSIZ_XFERSIZE_SHIFT) | > - (1 << HCTSIZ_PKTCNT_SHIFT) | > - (td->toggle ? (HCTSIZ_PID_DATA1 << HCTSIZ_PID_SHIFT) : > - (HCTSIZ_PID_DATA0 << HCTSIZ_PID_SHIFT))); > + if (td->npkt > td->max_packet_count) > + td->npkt = td->max_packet_count; > + > + td->tt_xactpos = 1; /* overload */ > + } > + if (td->tt_xactpos == td->npkt) { > + if (td->npkt == 1) { > + DWC_OTG_WRITE_4(sc, > DOTG_HCTSIZ(td->channel), > + (count << HCTSIZ_XFERSIZE_SHIFT) | > + (1 << HCTSIZ_PKTCNT_SHIFT) | > + (HCTSIZ_PID_DATA0 << > HCTSIZ_PID_SHIFT)); > + } else if (td->npkt == 2) { > + DWC_OTG_WRITE_4(sc, > DOTG_HCTSIZ(td->channel), > + (count << HCTSIZ_XFERSIZE_SHIFT) | > + (1 << HCTSIZ_PKTCNT_SHIFT) | > + (HCTSIZ_PID_DATA1 << > HCTSIZ_PID_SHIFT)); > + } else { > + DWC_OTG_WRITE_4(sc, > DOTG_HCTSIZ(td->channel), > + (count << HCTSIZ_XFERSIZE_SHIFT) | > + (1 << HCTSIZ_PKTCNT_SHIFT) | > + (HCTSIZ_PID_DATA2 << > HCTSIZ_PID_SHIFT)); > + } > + td->npkt = 0; > + } else { > + DWC_OTG_WRITE_4(sc, DOTG_HCTSIZ(td->channel), > + (count << HCTSIZ_XFERSIZE_SHIFT) | > + (1 << HCTSIZ_PKTCNT_SHIFT) | > + (HCTSIZ_PID_MDATA << HCTSIZ_PID_SHIFT)); > + } > + } else { > + /* TODO: HCTSIZ_DOPNG */ > + > + DWC_OTG_WRITE_4(sc, DOTG_HCTSIZ(td->channel), > + (count << HCTSIZ_XFERSIZE_SHIFT) | > + (1 << HCTSIZ_PKTCNT_SHIFT) | > + (td->toggle ? (HCTSIZ_PID_DATA1 << HCTSIZ_PID_SHIFT) : > + (HCTSIZ_PID_DATA0 << HCTSIZ_PID_SHIFT))); > + } > > DWC_OTG_WRITE_4(sc, DOTG_HCSPLT(td->channel), td->hcsplt); > > + /* send ASAP */ > + if ((ep_type == UE_ISOCHRONOUS) && !(sc->sc_last_frame_num & 1)) > + td->hcchar |= HCCHAR_ODDFRM; > + else > + td->hcchar &= ~HCCHAR_ODDFRM; > + > hcchar = td->hcchar; > hcchar &= ~HCCHAR_EPDIR_IN; > > @@ -1651,18 +1919,20 @@ send_pkt_sync: > > /* store number of bytes transmitted */ > td->tx_bytes = count; > - > goto busy; > > send_cpkt: > - count = DWC_OTG_READ_4(sc, DOTG_HFNUM) & 7; > - /* check for first microframe */ > - if (count == 0) { > - /* send packet again */ > - goto send_pkt; > + /* Wait for our turn, if TT transfer */ > + if (td->tt_scheduled == 0 || > + (sc->sc_last_frame_num & 7) < td->tt_complete_slot) { > + /* set return state */ > + td->state = DWC_CHAN_ST_WAIT_C_PKT; > > *** DIFF OUTPUT TRUNCATED AT 1000 LINES *** > > Somehow some of recent dwc_otg changes make Radxa Rock board unable to find usb flash and mount rootfs. Part of boot log: http://pastebin.com/tprWJapH Now I'm running latest head but no dwc_otg changes (r265357), which works in my case. Ganbold
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?CAGtf9xPgA0Urb7bZRoiRVFGBWCjHHFHU7wRYd_HrjBR2Jdj0cg>