1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
|
From fa6cd2944967a33088bc4cb66d1dc0323665b7c6 Mon Sep 17 00:00:00 2001
From: P33M <P33M@github.com>
Date: Tue, 30 Jul 2013 09:58:48 +0100
Subject: [PATCH 085/196] 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(-)
diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c
index 3c619b4..c42172f 100644
--- 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_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--;
diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c
index 488defb..7d521d9 100644
--- 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_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. */
--
1.9.1
|