dwc_otg: make nak_holdoff work as intended with empty queues

If URBs reading from non-periodic split endpoints were dequeued and
the last transfer from the endpoint was a NAK handshake, the resulting
qh->nak_frame value was stale which would result in unnecessarily long
polling intervals for the first subsequent transfer with a fresh URB.

Fixup qh->nak_frame in dwc_otg_hcd_urb_dequeue and also guard against
a case where a single URB is submitted to the endpoint, a NAK was
received on the transfer immediately prior to receiving data and the
device subsequently resubmits another URB past the qh->nak_frame interval.

Fixes https://github.com/raspberrypi/linux/issues/1709
This commit is contained in:
P33M
2017-04-27 16:24:34 +01:00
parent dc44db6e24
commit 282bed958b
3 changed files with 13 additions and 5 deletions

View File

@@ -616,7 +616,7 @@ int dwc_otg_hcd_urb_dequeue(dwc_otg_hcd_t * hcd,
if (fiq_fsm_enable && (hcd->fiq_state->channel[n].fsm != FIQ_PASSTHROUGH)) {
qh->channel->halt_status = DWC_OTG_HC_XFER_URB_DEQUEUE;
qh->channel->halt_pending = 1;
hcd->fiq_state->channel[n].fsm = FIQ_DEQUEUE_ISSUED;
//hcd->fiq_state->channel[n].fsm = FIQ_DEQUEUE_ISSUED;
} else {
dwc_otg_hc_halt(hcd->core_if, qh->channel,
DWC_OTG_HC_XFER_URB_DEQUEUE);
@@ -634,6 +634,8 @@ int dwc_otg_hcd_urb_dequeue(dwc_otg_hcd_t * hcd,
hcd->core_if->dma_desc_enable?"DMA ":"");
if (!hcd->core_if->dma_desc_enable) {
uint8_t b = urb_qtd->in_process;
if (nak_holdoff && qh->do_split && dwc_qh_is_non_per(qh))
qh->nak_frame = 0xFFFF;
dwc_otg_hcd_qtd_remove_and_free(hcd, urb_qtd, qh);
if (b) {
dwc_otg_hcd_qh_deactivate(hcd, qh, 0);

View File

@@ -2382,15 +2382,17 @@ void dwc_otg_hcd_handle_hc_fsm(dwc_otg_hcd_t *hcd, uint32_t num)
fiq_print(FIQDBG_INT, hcd->fiq_state, "OUT %01d %01d ", num , st->fsm);
hostchannels = hcd->available_host_channels;
if (hc->halt_pending) {
/* Dequeue: The FIQ was allowed to complete the transfer but state has been cleared. */
release_channel(hcd, hc, NULL, hc->halt_status);
return;
}
switch (st->fsm) {
case FIQ_TEST:
break;
case FIQ_DEQUEUE_ISSUED:
/* hc_halt was called. QTD no longer exists. */
/* TODO: for a nonperiodic split transaction, need to issue a
* CLEAR_TT_BUFFER hub command if we were in the start-split phase.
*/
/* Handled above, but keep for posterity */
release_channel(hcd, hc, NULL, hc->halt_status);
break;

View File

@@ -793,6 +793,10 @@ void dwc_otg_hcd_qh_deactivate(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh,
/* Add back to inactive non-periodic schedule. */
dwc_otg_hcd_qh_add(hcd, qh);
//hcd->fiq_state->kick_np_queues = 1;
} else {
if(nak_holdoff && qh->do_split) {
qh->nak_frame = 0xFFFF;
}
}
} else {
uint16_t frame_number = dwc_otg_hcd_get_frame_number(hcd);