From 2b66f2f4f07ed87db0e241489d4e93881fe50a85 Mon Sep 17 00:00:00 2001 From: P33M Date: Tue, 30 Jul 2013 09:58:48 +0100 Subject: [PATCH 085/174] dwc_otg: fiq_split: use TTs with more granularity This fixes certain issues with split transaction scheduling. - Isochronous multi-packet OUT transactions now hog the TT until they are completed - this prevents hubs aborting transactions if they get a periodic start-split out-of-order - Don't perform TT allocation on non-periodic endpoints - this allows simultaneous use of the TT's bulk/control and periodic transaction buffers This commit will mainly affect USB audio playback. --- drivers/usb/host/dwc_otg/dwc_otg_hcd.c | 26 +++++++++++++------------- drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c | 20 ++++++++++++++++---- 2 files changed, 29 insertions(+), 17 deletions(-) --- a/drivers/usb/host/dwc_otg/dwc_otg_hcd.c +++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c @@ -1356,6 +1356,7 @@ dwc_otg_transaction_type_e dwc_otg_hcd_s { dwc_list_link_t *qh_ptr; dwc_otg_qh_t *qh; + dwc_otg_qtd_t *qtd; int num_channels; dwc_irqflags_t flags; dwc_spinlock_t *channel_lock = hcd->channel_lock; @@ -1379,11 +1380,18 @@ dwc_otg_transaction_type_e dwc_otg_hcd_s qh = DWC_LIST_ENTRY(qh_ptr, dwc_otg_qh_t, qh_list_entry); - if(qh->do_split && dwc_otg_hcd_allocate_port(hcd, qh)) - { - qh_ptr = DWC_LIST_NEXT(qh_ptr); - g_next_sched_frame = dwc_frame_num_inc(dwc_otg_hcd_get_frame_number(hcd), 1); - continue; + if(qh->do_split) { + qtd = DWC_CIRCLEQ_FIRST(&qh->qtd_list); + if(!(qh->ep_type == UE_ISOCHRONOUS && + (qtd->isoc_split_pos == DWC_HCSPLIT_XACTPOS_MID || + qtd->isoc_split_pos == DWC_HCSPLIT_XACTPOS_END))) { + if(dwc_otg_hcd_allocate_port(hcd, qh)) + { + qh_ptr = DWC_LIST_NEXT(qh_ptr); + g_next_sched_frame = dwc_frame_num_inc(dwc_otg_hcd_get_frame_number(hcd), 1); + continue; + } + } } if (microframe_schedule) { @@ -1451,18 +1459,10 @@ dwc_otg_transaction_type_e dwc_otg_hcd_s } } - if (qh->do_split && dwc_otg_hcd_allocate_port(hcd, qh)) - { - g_next_sched_frame = dwc_frame_num_inc(dwc_otg_hcd_get_frame_number(hcd), 1); - qh_ptr = DWC_LIST_NEXT(qh_ptr); - continue; - } - if (microframe_schedule) { DWC_SPINLOCK_IRQSAVE(channel_lock, &flags); if (hcd->available_host_channels < 1) { DWC_SPINUNLOCK_IRQRESTORE(channel_lock, flags); - if(qh->do_split) dwc_otg_hcd_release_port(hcd, qh); break; } hcd->available_host_channels--; --- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c +++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c @@ -1328,10 +1328,20 @@ static void release_channel(dwc_otg_hcd_ #ifdef FIQ_DEBUG int endp = qtd->urb ? qtd->urb->pipe_info.ep_num : 0; #endif + int hog_port = 0; DWC_DEBUGPL(DBG_HCDV, " %s: channel %d, halt_status %d, xfer_len %d\n", __func__, hc->hc_num, halt_status, hc->xfer_len); + if(fiq_split_enable && hc->do_split) { + if(!hc->ep_is_in && hc->ep_type == UE_ISOCHRONOUS) { + if(hc->xact_pos == DWC_HCSPLIT_XACTPOS_MID || + hc->xact_pos == DWC_HCSPLIT_XACTPOS_BEGIN) { + hog_port = 1; + } + } + } + switch (halt_status) { case DWC_OTG_HC_XFER_URB_COMPLETE: free_qtd = 1; @@ -1417,12 +1427,14 @@ cleanup: fiq_print(FIQDBG_ERR, "PRTNOTAL"); //BUG(); } - - hcd->hub_port[hc->hub_addr] &= ~(1 << hc->port_addr); + if(!hog_port && (hc->ep_type == DWC_OTG_EP_TYPE_ISOC || + hc->ep_type == DWC_OTG_EP_TYPE_INTR)) { + hcd->hub_port[hc->hub_addr] &= ~(1 << hc->port_addr); #ifdef FIQ_DEBUG - hcd->hub_port_alloc[hc->hub_addr * 16 + hc->port_addr] = -1; + hcd->hub_port_alloc[hc->hub_addr * 16 + hc->port_addr] = -1; #endif - fiq_print(FIQDBG_PORTHUB, "H%dP%d:RR%d", hc->hub_addr, hc->port_addr, endp); + fiq_print(FIQDBG_PORTHUB, "H%dP%d:RR%d", hc->hub_addr, hc->port_addr, endp); + } } /* Try to queue more transfers now that there's a free channel. */