Skip to content

Commit

Permalink
dwc_otg: make nak_holdoff work as intended with empty queues
Browse files Browse the repository at this point in the history
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 #1709
  • Loading branch information
P33M committed Apr 27, 2017
1 parent dc44db6 commit 282bed9
Show file tree
Hide file tree
Showing 3 changed files with 13 additions and 5 deletions.
4 changes: 3 additions & 1 deletion drivers/usb/host/dwc_otg/dwc_otg_hcd.c
Expand Up @@ -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);
Expand All @@ -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);
Expand Down
10 changes: 6 additions & 4 deletions drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c
Expand Up @@ -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;

Expand Down
4 changes: 4 additions & 0 deletions drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c
Expand Up @@ -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);
Expand Down

0 comments on commit 282bed9

Please sign in to comment.