mirror of
https://github.com/raspberrypi/linux.git
synced 2025-12-06 01:49:46 +00:00
dwc_otg: fix split transaction data toggle handling around dequeues
See https://github.com/raspberrypi/linux/issues/1709 Fix several issues regarding endpoint state when URBs are dequeued - If the HCD is disconnected, flush FIQ-enabled channels properly - Save the data toggle state for bulk endpoints if the last transfer from an endpoint where URBs were dequeued returned a data packet - Reset hc->start_pkt_count properly in assign_and_init_hc()
This commit is contained in:
@@ -193,8 +193,13 @@ static void kill_urbs_in_qh_list(dwc_otg_hcd_t * hcd, dwc_list_link_t * qh_list)
|
||||
* It is possible that the channel has already halted
|
||||
* but not yet been through the IRQ handler.
|
||||
*/
|
||||
dwc_otg_hc_halt(hcd->core_if, qh->channel,
|
||||
DWC_OTG_HC_XFER_URB_DEQUEUE);
|
||||
if (fiq_fsm_enable && (hcd->fiq_state->channel[qh->channel->hc_num].fsm != FIQ_PASSTHROUGH)) {
|
||||
qh->channel->halt_status = DWC_OTG_HC_XFER_URB_DEQUEUE;
|
||||
qh->channel->halt_pending = 1;
|
||||
} else {
|
||||
dwc_otg_hc_halt(hcd->core_if, qh->channel,
|
||||
DWC_OTG_HC_XFER_URB_DEQUEUE);
|
||||
}
|
||||
if(microframe_schedule)
|
||||
hcd->available_host_channels++;
|
||||
qh->channel = NULL;
|
||||
@@ -1270,6 +1275,7 @@ static void assign_and_init_hc(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
|
||||
if (qh->do_split) {
|
||||
uint32_t hub_addr, port_addr;
|
||||
hc->do_split = 1;
|
||||
hc->start_pkt_count = 1;
|
||||
hc->xact_pos = qtd->isoc_split_pos;
|
||||
/* We don't need to do complete splits anymore */
|
||||
// if(fiq_fsm_enable)
|
||||
|
||||
@@ -2378,12 +2378,20 @@ void dwc_otg_hcd_handle_hc_fsm(dwc_otg_hcd_t *hcd, uint32_t num)
|
||||
dwc_otg_qh_t *qh = hc->qh;
|
||||
dwc_otg_hc_regs_t *hc_regs = hcd->core_if->host_if->hc_regs[num];
|
||||
hcint_data_t hcint = hcd->fiq_state->channel[num].hcint_copy;
|
||||
hctsiz_data_t hctsiz = hcd->fiq_state->channel[num].hctsiz_copy;
|
||||
int hostchannels = 0;
|
||||
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. */
|
||||
if (st->fsm == FIQ_NP_SPLIT_DONE && hcint.b.xfercomp && qh->ep_type == UE_BULK) {
|
||||
if (hctsiz.b.pid == DWC_HCTSIZ_DATA0) {
|
||||
qh->data_toggle = DWC_OTG_HC_PID_DATA1;
|
||||
} else {
|
||||
qh->data_toggle = DWC_OTG_HC_PID_DATA0;
|
||||
}
|
||||
}
|
||||
release_channel(hcd, hc, NULL, hc->halt_status);
|
||||
return;
|
||||
}
|
||||
@@ -2641,10 +2649,15 @@ int32_t dwc_otg_hcd_handle_hc_n_intr(dwc_otg_hcd_t * dwc_otg_hcd, uint32_t num)
|
||||
hc = dwc_otg_hcd->hc_ptr_array[num];
|
||||
hc_regs = dwc_otg_hcd->core_if->host_if->hc_regs[num];
|
||||
if(hc->halt_status == DWC_OTG_HC_XFER_URB_DEQUEUE) {
|
||||
/* We are responding to a channel disable. Driver
|
||||
* state is cleared - our qtd has gone away.
|
||||
/* A dequeue was issued for this transfer. Our QTD has gone away
|
||||
* but in the case of a FIQ transfer, the transfer would have run
|
||||
* to completion.
|
||||
*/
|
||||
release_channel(dwc_otg_hcd, hc, NULL, hc->halt_status);
|
||||
if (fiq_fsm_enable && dwc_otg_hcd->fiq_state->channel[num].fsm != FIQ_PASSTHROUGH) {
|
||||
dwc_otg_hcd_handle_hc_fsm(dwc_otg_hcd, num);
|
||||
} else {
|
||||
release_channel(dwc_otg_hcd, hc, NULL, hc->halt_status);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
qtd = DWC_CIRCLEQ_FIRST(&hc->qh->qtd_list);
|
||||
|
||||
Reference in New Issue
Block a user