brcm2708: update against latest rpi-3.10.y branch
[openwrt/svn-archive/archive.git] / target / linux / brcm2708 / patches-3.10 / 0032-Add-NAK-holdoff-scheme.-Enabled-by-default-disable-w.patch
1 From 99e6d36a5f752bb0237a61143bea29c93e6da22c Mon Sep 17 00:00:00 2001
2 From: popcornmix <popcornmix@gmail.com>
3 Date: Mon, 8 Apr 2013 21:12:48 +0100
4 Subject: [PATCH 032/174] Add NAK holdoff scheme. Enabled by default, disable
5 with dwc_otg.nak_holdoff_enable=0. Thanks gsh
6
7 ---
8 drivers/usb/host/dwc_otg/dwc_otg_driver.c | 7 ++++++-
9 drivers/usb/host/dwc_otg/dwc_otg_hcd.c | 22 +++++++++++++++++++++-
10 drivers/usb/host/dwc_otg/dwc_otg_hcd.h | 5 +++++
11 drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c | 21 +++++++++++++++++++--
12 drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c | 19 +++++++++++++++++++
13 5 files changed, 70 insertions(+), 4 deletions(-)
14
15 --- a/drivers/usb/host/dwc_otg/dwc_otg_driver.c
16 +++ b/drivers/usb/host/dwc_otg/dwc_otg_driver.c
17 @@ -243,6 +243,9 @@ static struct dwc_otg_driver_module_para
18 //Global variable to switch the fiq fix on or off (declared in bcm2708.c)
19 extern bool fiq_fix_enable;
20
21 +//Global variable to switch the nak holdoff on or off
22 +bool nak_holdoff_enable = true;
23 +
24
25 /**
26 * This function shows the Driver Version.
27 @@ -1086,6 +1089,7 @@ static int __init dwc_otg_driver_init(vo
28 return retval;
29 }
30 printk(KERN_DEBUG "dwc_otg: FIQ %s\n", fiq_fix_enable ? "enabled":"disabled");
31 + printk(KERN_DEBUG "dwc_otg: NAK holdoff %s\n", nak_holdoff_enable ? "enabled":"disabled");
32
33 error = driver_create_file(drv, &driver_attr_version);
34 #ifdef DEBUG
35 @@ -1366,9 +1370,10 @@ MODULE_PARM_DESC(otg_ver, "OTG revision
36 module_param(microframe_schedule, bool, 0444);
37 MODULE_PARM_DESC(microframe_schedule, "Enable the microframe scheduler");
38
39 -
40 module_param(fiq_fix_enable, bool, 0444);
41 MODULE_PARM_DESC(fiq_fix_enable, "Enable the fiq fix");
42 +module_param(nak_holdoff_enable, bool, 0444);
43 +MODULE_PARM_DESC(nak_holdoff_enable, "Enable the NAK holdoff");
44
45 /** @page "Module Parameters"
46 *
47 --- a/drivers/usb/host/dwc_otg/dwc_otg_hcd.c
48 +++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c
49 @@ -527,6 +527,8 @@ int dwc_otg_hcd_urb_dequeue(dwc_otg_hcd_
50 {
51 dwc_otg_qh_t *qh;
52 dwc_otg_qtd_t *urb_qtd;
53 + BUG_ON(!hcd);
54 + BUG_ON(!dwc_otg_urb);
55
56 #ifdef DEBUG /* integrity checks (Broadcom) */
57
58 @@ -543,14 +545,17 @@ int dwc_otg_hcd_urb_dequeue(dwc_otg_hcd_
59 return -DWC_E_INVALID;
60 }
61 urb_qtd = dwc_otg_urb->qtd;
62 + BUG_ON(!urb_qtd);
63 if (urb_qtd->qh == NULL) {
64 DWC_ERROR("**** DWC OTG HCD URB Dequeue with QTD with NULL Q handler\n");
65 return -DWC_E_INVALID;
66 }
67 #else
68 urb_qtd = dwc_otg_urb->qtd;
69 + BUG_ON(!urb_qtd);
70 #endif
71 qh = urb_qtd->qh;
72 + BUG_ON(!qh);
73 if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) {
74 if (urb_qtd->in_process) {
75 dump_channel_info(hcd, qh);
76 @@ -1309,6 +1314,22 @@ dwc_otg_transaction_type_e dwc_otg_hcd_s
77 num_channels - hcd->periodic_channels) &&
78 !DWC_CIRCLEQ_EMPTY(&hcd->free_hc_list)) {
79
80 + qh = DWC_LIST_ENTRY(qh_ptr, dwc_otg_qh_t, qh_list_entry);
81 +
82 + /*
83 + * Check to see if this is a NAK'd retransmit, in which case ignore for retransmission
84 + * we hold off on bulk retransmissions to reduce NAK interrupt overhead for
85 + * cheeky devices that just hold off using NAKs
86 + */
87 + if (dwc_full_frame_num(qh->nak_frame) == dwc_full_frame_num(dwc_otg_hcd_get_frame_number(hcd))) {
88 + // Make fiq interrupt run on next frame (i.e. 8 uframes)
89 + g_next_sched_frame = ((qh->nak_frame + 8) & ~7) & DWC_HFNUM_MAX_FRNUM;
90 + qh_ptr = DWC_LIST_NEXT(qh_ptr);
91 + continue;
92 + }
93 + else
94 + qh->nak_frame = 0xffff;
95 +
96 if (microframe_schedule) {
97 DWC_SPINLOCK_IRQSAVE(channel_lock, &flags);
98 if (hcd->available_host_channels < 1) {
99 @@ -1321,7 +1342,6 @@ dwc_otg_transaction_type_e dwc_otg_hcd_s
100 last_sel_trans_num_nonper_scheduled++;
101 #endif /* DEBUG_HOST_CHANNELS */
102 }
103 - qh = DWC_LIST_ENTRY(qh_ptr, dwc_otg_qh_t, qh_list_entry);
104
105 assign_and_init_hc(hcd, qh);
106
107 --- a/drivers/usb/host/dwc_otg/dwc_otg_hcd.h
108 +++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd.h
109 @@ -321,6 +321,11 @@ typedef struct dwc_otg_qh {
110 */
111 uint16_t sched_frame;
112
113 + /*
114 + ** Frame a NAK was received on this queue head, used to minimise NAK retransmission
115 + */
116 + uint16_t nak_frame;
117 +
118 /** (micro)frame at which last start split was initialized. */
119 uint16_t start_split_frame;
120
121 --- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c
122 +++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c
123 @@ -56,7 +56,12 @@ int fiq_done, int_done;
124 int g_next_sched_frame, g_np_count, g_np_sent, g_work_expected;
125 static int mphi_int_count = 0 ;
126
127 -extern bool fiq_fix_enable;
128 +extern bool fiq_fix_enable, nak_holdoff_enable;
129 +
130 +hcchar_data_t nak_hcchar;
131 +hctsiz_data_t nak_hctsiz;
132 +hcsplt_data_t nak_hcsplt;
133 +int nak_count;
134
135 void __attribute__ ((naked)) dwc_otg_hcd_handle_fiq(void)
136 {
137 @@ -230,7 +235,7 @@ exit_handler_routine:
138 DWC_WRITE_REG32(c_mphi_regs.ctrl, (1<<31));
139 mphi_int_count = 0;
140 }
141 - int_done++;
142 + int_done++;
143 if((jiffies / HZ) > last_time)
144 {
145 /* Once a second output the fiq and irq numbers, useful for debug */
146 @@ -1419,6 +1424,18 @@ static int32_t handle_hc_nak_intr(dwc_ot
147 "NAK Received--\n", hc->hc_num);
148
149 /*
150 + * When we get bulk NAKs then remember this so we holdoff on this qh until
151 + * the beginning of the next frame
152 + */
153 + switch(dwc_otg_hcd_get_pipe_type(&qtd->urb->pipe_info)) {
154 + case UE_BULK:
155 + //case UE_INTERRUPT:
156 + //case UE_CONTROL:
157 + if (nak_holdoff_enable)
158 + hc->qh->nak_frame = dwc_otg_hcd_get_frame_number(hcd);
159 + }
160 +
161 + /*
162 * Handle NAK for IN/OUT SSPLIT/CSPLIT transfers, bulk, control, and
163 * interrupt. Re-start the SSPLIT transfer.
164 */
165 --- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c
166 +++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c
167 @@ -181,6 +181,7 @@ void qh_init(dwc_otg_hcd_t * hcd, dwc_ot
168 if (microframe_schedule)
169 qh->speed = dev_speed;
170
171 + qh->nak_frame = 0xffff;
172
173 if (((dev_speed == USB_SPEED_LOW) ||
174 (dev_speed == USB_SPEED_FULL)) &&
175 @@ -764,6 +765,24 @@ void dwc_otg_hcd_qh_deactivate(dwc_otg_h
176 int sched_next_periodic_split)
177 {
178 if (dwc_qh_is_non_per(qh)) {
179 +
180 + dwc_otg_qh_t *qh_tmp;
181 + dwc_list_link_t *qh_list;
182 + DWC_LIST_FOREACH(qh_list, &hcd->non_periodic_sched_inactive)
183 + {
184 + qh_tmp = DWC_LIST_ENTRY(qh_list, struct dwc_otg_qh, qh_list_entry);
185 + if(qh_tmp == qh)
186 + {
187 + /*
188 + * FIQ is being disabled because this one nevers gets a np_count increment
189 + * This is still not absolutely correct, but it should fix itself with
190 + * just an unnecessary extra interrupt
191 + */
192 + g_np_sent = g_np_count;
193 + }
194 + }
195 +
196 +
197 dwc_otg_hcd_qh_remove(hcd, qh);
198 if (!DWC_CIRCLEQ_EMPTY(&qh->qtd_list)) {
199 /* Add back to inactive non-periodic schedule. */