Commit e096c443 authored by P33M's avatar P33M Committed by popcornmix
Browse files

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()
parent 525571c4
Loading
Loading
Loading
Loading
+8 −2
Original line number Diff line number Diff line
@@ -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.
			 */
			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)
+16 −3
Original line number Diff line number Diff line
@@ -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.
		 */
		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);