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