Optimise host mode data roundtrip time. When BULK data is submitted to

the main processing queue, clear the NAK counter for any associated
BULK or CONTROL transfers and poll the endpoint(s) for 1 millisecond
at 125us rate interval, before going into slow, 10ms, NAK polling mode
again.  This has the effect that typical ping-ping protocols respond
quicker when initiated from the USB host.

MFC after:	2 weeks
This commit is contained in:
Hans Petter Selasky 2014-05-11 08:17:46 +00:00
parent 49588d0fac
commit 4541f27356
2 changed files with 72 additions and 27 deletions

View File

@ -760,7 +760,7 @@ dwc_otg_host_setup_tx(struct dwc_otg_td *td)
case DWC_CHAN_ST_WAIT_ANE:
if (hcint & (HCINT_RETRY | HCINT_ERRORS)) {
td->did_nak = 1;
td->did_nak++;
td->tt_scheduled = 0;
goto send_pkt;
} else if (hcint & (HCINT_ACK | HCINT_NYET)) {
@ -774,7 +774,7 @@ dwc_otg_host_setup_tx(struct dwc_otg_td *td)
case DWC_CHAN_ST_WAIT_S_ANE:
if (hcint & (HCINT_RETRY | HCINT_ERRORS)) {
td->did_nak = 1;
td->did_nak++;
td->tt_scheduled = 0;
goto send_pkt;
} else if (hcint & (HCINT_ACK | HCINT_NYET)) {
@ -786,7 +786,7 @@ dwc_otg_host_setup_tx(struct dwc_otg_td *td)
if (hcint & HCINT_NYET) {
goto send_cpkt;
} else if (hcint & (HCINT_RETRY | HCINT_ERRORS)) {
td->did_nak = 1;
td->did_nak++;
td->tt_scheduled = 0;
goto send_pkt;
} else if (hcint & HCINT_ACK) {
@ -1085,7 +1085,7 @@ dwc_otg_host_rate_check(struct dwc_otg_td *td)
if (!td->tt_scheduled)
goto busy;
td->tt_scheduled = 0;
} else if (td->did_nak != 0) {
} else if (td->did_nak >= DWC_OTG_NAK_MAX) {
goto busy;
} else if (td->set_toggle) {
td->set_toggle = 0;
@ -1244,7 +1244,7 @@ dwc_otg_host_data_rx(struct dwc_otg_td *td)
case DWC_CHAN_ST_WAIT_ANE:
if (hcint & (HCINT_RETRY | HCINT_ERRORS)) {
td->did_nak = 1;
td->did_nak++;
td->tt_scheduled = 0;
if (td->hcsplt != 0)
goto receive_spkt;
@ -1284,6 +1284,7 @@ dwc_otg_host_data_rx(struct dwc_otg_td *td)
*/
}
td->tt_scheduled = 0;
td->did_nak = 0;
if (td->hcsplt != 0)
goto receive_spkt;
else
@ -1298,14 +1299,16 @@ dwc_otg_host_data_rx(struct dwc_otg_td *td)
* case of interrupt and isochronous transfers:
*/
if (hcint & (HCINT_RETRY | HCINT_ERRORS)) {
td->did_nak = 1;
td->did_nak++;
td->tt_scheduled = 0;
goto receive_spkt;
} else if (hcint & HCINT_NYET) {
td->tt_scheduled = 0;
goto receive_spkt;
} else if (hcint & HCINT_ACK)
} else if (hcint & HCINT_ACK) {
td->did_nak = 0;
goto receive_pkt;
}
break;
case DWC_CHAN_ST_WAIT_C_PKT:
@ -1633,13 +1636,14 @@ dwc_otg_host_data_tx(struct dwc_otg_td *td)
case DWC_CHAN_ST_WAIT_ANE:
if (hcint & (HCINT_RETRY | HCINT_ERRORS)) {
td->did_nak = 1;
td->did_nak++;
td->tt_scheduled = 0;
goto send_pkt;
} else if (hcint & (HCINT_ACK | HCINT_NYET)) {
td->offset += td->tx_bytes;
td->remainder -= td->tx_bytes;
td->toggle ^= 1;
td->did_nak = 0;
td->tt_scheduled = 0;
/* check remainder */
@ -1658,24 +1662,27 @@ dwc_otg_host_data_tx(struct dwc_otg_td *td)
case DWC_CHAN_ST_WAIT_S_ANE:
if (hcint & (HCINT_RETRY | HCINT_ERRORS)) {
td->did_nak = 1;
td->did_nak++;
td->tt_scheduled = 0;
goto send_pkt;
} else if (hcint & (HCINT_ACK | HCINT_NYET))
} else if (hcint & (HCINT_ACK | HCINT_NYET)) {
td->did_nak = 0;
goto send_cpkt;
}
break;
case DWC_CHAN_ST_WAIT_C_ANE:
if (hcint & HCINT_NYET) {
goto send_cpkt;
} else if (hcint & (HCINT_RETRY | HCINT_ERRORS)) {
td->did_nak = 1;
td->did_nak++;
td->tt_scheduled = 0;
goto send_pkt;
} else if (hcint & HCINT_ACK) {
td->offset += td->tx_bytes;
td->remainder -= td->tx_bytes;
td->toggle ^= 1;
td->did_nak = 0;
td->tt_scheduled = 0;
/* check remainder */
@ -2283,9 +2290,11 @@ dwc_otg_timer(void *_sc)
TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry) {
td = xfer->td_transfer_cache;
if (td != NULL)
if (td != NULL) {
/* reset NAK counter */
td->did_nak = 0;
}
}
/* enable SOF interrupt, which will poll jobs */
dwc_otg_enable_sof_irq(sc);
@ -2429,8 +2438,11 @@ dwc_otg_update_host_transfer_schedule(struct dwc_otg_softc *sc)
TAILQ_FOREACH_SAFE(xfer, &sc->sc_bus.intr_q.head, wait_entry, xfer_next) {
td = xfer->td_transfer_cache;
if (td == NULL || td->did_nak != 0 || td->ep_type != UE_CONTROL)
if (td == NULL ||
td->ep_type != UE_CONTROL ||
td->did_nak >= DWC_OTG_NAK_MAX) {
continue;
}
sc->sc_needsof = 1;
@ -2448,8 +2460,11 @@ dwc_otg_update_host_transfer_schedule(struct dwc_otg_softc *sc)
if ((temp & 7) < 6) {
TAILQ_FOREACH_SAFE(xfer, &sc->sc_bus.intr_q.head, wait_entry, xfer_next) {
td = xfer->td_transfer_cache;
if (td == NULL || td->did_nak != 0 || td->ep_type != UE_BULK)
if (td == NULL ||
td->ep_type != UE_BULK ||
td->did_nak >= DWC_OTG_NAK_MAX) {
continue;
}
sc->sc_needsof = 1;
@ -3206,11 +3221,19 @@ static void
dwc_otg_start_standard_chain(struct usb_xfer *xfer)
{
struct dwc_otg_softc *sc = DWC_OTG_BUS2SC(xfer->xroot->bus);
struct usb_xfer_root *xroot;
struct dwc_otg_td *td;
DPRINTFN(9, "\n");
/* poll one time - will turn on interrupts */
if (dwc_otg_xfer_do_fifo(xfer)) {
/*
* Poll one time in device mode, which will turn on the
* endpoint interrupts. Else wait for SOF interrupt in host
* mode.
*/
if (sc->sc_flags.status_device_mode != 0 &&
dwc_otg_xfer_do_fifo(xfer) == 0)
goto done;
/* put transfer on interrupt queue */
usbd_transfer_enqueue(&xfer->xroot->bus->intr_q, xfer);
@ -3221,9 +3244,30 @@ dwc_otg_start_standard_chain(struct usb_xfer *xfer)
&dwc_otg_timeout, xfer->timeout);
}
if (sc->sc_flags.status_device_mode != 0)
goto done;
/* enable SOF interrupt, if any */
dwc_otg_enable_sof_irq(sc);
td = xfer->td_transfer_cache;
if (td->ep_type != UE_BULK)
goto done;
xroot = xfer->xroot;
/*
* Optimise the ping-pong effect by waking up other BULK
* transfers belonging to the same device group:
*/
TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry) {
td = xfer->td_transfer_cache;
if (td == NULL || td->ep_type != UE_BULK || xfer->xroot != xroot)
continue;
/* reset NAK counter */
td->did_nak = 0;
}
done:;
}
static void

View File

@ -37,6 +37,7 @@
#define DWC_OTG_TT_SLOT_MAX 8
#define DWC_OTG_SLOT_IDLE_MAX 4
#define DWC_OTG_SLOT_IDLE_MIN 2
#define DWC_OTG_NAK_MAX 8 /* 1 ms */
#define DWC_OTG_READ_4(sc, reg) \
bus_space_read_4((sc)->sc_io_tag, (sc)->sc_io_hdl, reg)
@ -64,6 +65,7 @@ struct dwc_otg_td {
uint8_t errcnt;
uint8_t tmr_res;
uint8_t tmr_val;
uint8_t did_nak; /* NAK counter */
uint8_t ep_no;
uint8_t ep_type;
uint8_t channel[2];
@ -87,7 +89,6 @@ struct dwc_otg_td {
uint8_t toggle:1;
uint8_t set_toggle:1;
uint8_t got_short:1;
uint8_t did_nak:1;
uint8_t tt_scheduled:1;
uint8_t tt_channel_tog:1;
};