gintsts_data_t intr;
dwc_otg_hcd_t *dwc_otg_hcd = p;
+ DWC_SPINLOCK(dwc_otg_hcd->lock);
/*
* Set status flags for the hub driver.
*/
dwc_otg_hcd->flags.b.port_connect_status_change = 1;
dwc_otg_hcd->flags.b.port_connect_status = 0;
- if(fiq_enable)
+ if(fiq_enable) {
local_fiq_disable();
+ fiq_fsm_spin_lock(&dwc_otg_hcd->fiq_state->lock);
+ }
/*
* Shutdown any transfers in process by clearing the Tx FIFO Empty
* interrupt mask and status bits and disabling subsequent host
* in release_channel_ddma(). Which called from ep_disable
* when device disconnect.
*/
- channel->qh = NULL;
+ if (dwc_otg_hcd->core_if->dma_desc_enable)
+ channel->qh = NULL;
}
}
if(fiq_fsm_enable) {
}
- if(fiq_enable)
+ if(fiq_enable) {
+ fiq_fsm_spin_unlock(&dwc_otg_hcd->fiq_state->lock);
local_fiq_enable();
+ }
if (dwc_otg_hcd->fops->disconnect) {
dwc_otg_hcd->fops->disconnect(dwc_otg_hcd);
}
+ DWC_SPINUNLOCK(dwc_otg_hcd->lock);
return 1;
}
int hub_addr, port_addr, frame, uframe;
struct fiq_channel_state *st = &hcd->fiq_state->channel[hc->hc_num];
- if (st->fsm != FIQ_PASSTHROUGH)
+ /*
+ * Non-periodic channel assignments stay in the non_periodic_active queue.
+ * Therefore we get repeatedly called until the FIQ's done processing this channel.
+ */
+ if (qh->channel->xfer_started == 1)
return 0;
+
+ if (st->fsm != FIQ_PASSTHROUGH) {
+ pr_warn_ratelimited("%s:%d: Queue called for an active channel\n", __func__, __LINE__);
+ return 0;
+ }
+
+ qh->channel->xfer_started = 1;
+
st->nr_errors = 0;
st->hcchar_copy.d32 = 0;
{
struct fiq_channel_state *st = &hcd->fiq_state->channel[num];
dwc_hc_t *hc = hcd->hc_ptr_array[num];
- dwc_otg_qtd_t *qtd = DWC_CIRCLEQ_FIRST(&hc->qh->qtd_list);
- dwc_otg_qh_t *qh = hc->qh;
+ dwc_otg_qtd_t *qtd;
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;
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 (hc->qh && st->fsm == FIQ_NP_SPLIT_DONE &&
+ hcint.b.xfercomp && hc->qh->ep_type == UE_BULK) {
if (hctsiz.b.pid == DWC_HCTSIZ_DATA0) {
- qh->data_toggle = DWC_OTG_HC_PID_DATA1;
+ hc->qh->data_toggle = DWC_OTG_HC_PID_DATA1;
} else {
- qh->data_toggle = DWC_OTG_HC_PID_DATA0;
+ hc->qh->data_toggle = DWC_OTG_HC_PID_DATA0;
}
}
release_channel(hcd, hc, NULL, hc->halt_status);
return;
}
+
+ qtd = DWC_CIRCLEQ_FIRST(&hc->qh->qtd_list);
switch (st->fsm) {
case FIQ_TEST:
break;
handle_hc_xfercomp_intr(hcd, hc, hc_regs, qtd);
} else if (hcint.b.nak) {
handle_hc_nak_intr(hcd, hc, hc_regs, qtd);
+ } else {
+ DWC_WARN("Unexpected IRQ state on FSM transaction:"
+ "dev_addr=%d ep=%d fsm=%d, hcint=0x%08x\n",
+ hc->dev_addr, hc->ep_num, st->fsm, hcint.d32);
+ release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NO_HALT_STATUS);
}
break;
} else if (hcint.b.ahberr) {
handle_hc_ahberr_intr(hcd, hc, hc_regs, qtd);
} else {
- local_fiq_disable();
- BUG();
+ DWC_WARN("Unexpected IRQ state on FSM transaction:"
+ "dev_addr=%d ep=%d fsm=%d, hcint=0x%08x\n",
+ hc->dev_addr, hc->ep_num, st->fsm, hcint.d32);
+ release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NO_HALT_STATUS);
}
break;
} else if (hcint.b.ahberr) {
handle_hc_ahberr_intr(hcd, hc, hc_regs, qtd);
} else {
- local_fiq_disable();
- BUG();
+ DWC_WARN("Unexpected IRQ state on FSM transaction:"
+ "dev_addr=%d ep=%d fsm=%d, hcint=0x%08x\n",
+ hc->dev_addr, hc->ep_num, st->fsm, hcint.d32);
+ release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NO_HALT_STATUS);
}
break;
} else {
frame_desc->status = 0;
/* Unswizzle dma */
- len = dwc_otg_fiq_unsetup_per_dma(hcd, qh, qtd, num);
+ len = dwc_otg_fiq_unsetup_per_dma(hcd, hc->qh, qtd, num);
frame_desc->actual_length = len;
}
qtd->isoc_frame_index++;
* The status is recorded as the interrupt state should the transaction
* fail.
*/
- dwc_otg_fiq_unmangle_isoc(hcd, qh, qtd, num);
+ dwc_otg_fiq_unmangle_isoc(hcd, hc->qh, qtd, num);
hcd->fops->complete(hcd, qtd->urb->priv, qtd->urb, 0);
release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_URB_COMPLETE);
break;