]> git.hungrycats.org Git - linux/commitdiff
dwc_otg: fiq_split: use TTs with more granularity
authorP33M <P33M@github.com>
Tue, 30 Jul 2013 08:58:48 +0000 (09:58 +0100)
committerP33M <P33M@github.com>
Tue, 30 Jul 2013 10:59:50 +0000 (11:59 +0100)
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
drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c

index 3c619b4f3a14738583ba42e431cc6484eb4be3a7..c42172ffebb20e88f0551768044edf565d7b50e7 100644 (file)
@@ -1356,6 +1356,7 @@ dwc_otg_transaction_type_e dwc_otg_hcd_select_transactions(dwc_otg_hcd_t * hcd)
 {
        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_select_transactions(dwc_otg_hcd_t * hcd)
 
                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_select_transactions(dwc_otg_hcd_t * hcd)
                        }
                }
 
-               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--;
index 78e52ca6b4c179fb43948cc9866f66927a1636f1..2340dff83e8ec419ac662600e832832b9d100ef7 100644 (file)
@@ -1328,10 +1328,20 @@ static void release_channel(dwc_otg_hcd_t * 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. */