brcm2708: switch to 3.14
[15.05/openwrt.git] / target / linux / brcm2708 / patches-3.10 / 0026-Add-low-latency-mode-to-sdcard-driver.-Disable-with-.patch
1 From 4ec6de1f59d1f0b5ed9cfebf3c1b4080d7215dc2 Mon Sep 17 00:00:00 2001
2 From: popcornmix <popcornmix@gmail.com>
3 Date: Sun, 12 May 2013 12:27:48 +0100
4 Subject: [PATCH 026/196] Add low-latency mode to sdcard driver. Disable with
5  sdhci-bcm2708.enable_llm=0. Thanks ddv2005.
6
7 ---
8  drivers/mmc/host/sdhci-bcm2708.c |  17 ++--
9  drivers/mmc/host/sdhci.c         | 165 ++++++++++++++++++++++++++++++---------
10  drivers/mmc/host/sdhci.h         |   6 ++
11  include/linux/mmc/sdhci.h        |   1 +
12  4 files changed, 145 insertions(+), 44 deletions(-)
13
14 diff --git a/drivers/mmc/host/sdhci-bcm2708.c b/drivers/mmc/host/sdhci-bcm2708.c
15 index 7a703c2..7ce2829 100644
16 --- a/drivers/mmc/host/sdhci-bcm2708.c
17 +++ b/drivers/mmc/host/sdhci-bcm2708.c
18 @@ -135,6 +135,7 @@ static bool allow_highspeed = 1;
19  static int emmc_clock_freq = BCM2708_EMMC_CLOCK_FREQ;
20  static bool sync_after_dma = 1;
21  static bool missing_status = 1;
22 +bool enable_llm = 1;
23  
24  #if 0
25  static void hptime_test(void)
26 @@ -871,12 +872,11 @@ static irqreturn_t sdhci_bcm2708_dma_irq(int irq, void *dev_id)
27         struct sdhci_host *host = dev_id;
28         struct sdhci_bcm2708_priv *host_priv = SDHCI_HOST_PRIV(host);
29         u32 dma_cs; /* control and status register */
30 -       unsigned long flags;
31  
32         BUG_ON(NULL == dev_id);
33         BUG_ON(NULL == host_priv->dma_chan_base);
34  
35 -       spin_lock_irqsave(&host->lock, flags);
36 +       sdhci_spin_lock(host);
37  
38         dma_cs = readl(host_priv->dma_chan_base + BCM2708_DMA_CS);
39  
40 @@ -917,8 +917,7 @@ static irqreturn_t sdhci_bcm2708_dma_irq(int irq, void *dev_id)
41  
42                 result = IRQ_HANDLED;
43         }
44 -
45 -       spin_unlock_irqrestore(&host->lock, flags);
46 +       sdhci_spin_unlock(host);
47  
48         return result;
49  }
50 @@ -1193,9 +1192,12 @@ static int sdhci_bcm2708_probe(struct platform_device *pdev)
51                 sdhci_bcm2708_ops.missing_status = sdhci_bcm2708_missing_status;
52         }
53  
54 +       printk("sdhci: %s low-latency mode\n",enable_llm?"Enable":"Disable");
55 +
56         host->hw_name = "BCM2708_Arasan";
57         host->ops = &sdhci_bcm2708_ops;
58         host->irq = platform_get_irq(pdev, 0);
59 +       host->second_irq = 0;
60  
61         host->quirks = SDHCI_QUIRK_BROKEN_CARD_DETECTION |
62                        SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |
63 @@ -1256,12 +1258,13 @@ static int sdhci_bcm2708_probe(struct platform_device *pdev)
64         }
65         host_priv->dma_chan = ret;
66  
67 -       ret = request_irq(host_priv->dma_irq, sdhci_bcm2708_dma_irq,
68 -                         IRQF_SHARED, DRIVER_NAME " (dma)", host);
69 +       ret = request_irq(host_priv->dma_irq, sdhci_bcm2708_dma_irq,0,//IRQF_SHARED,
70 +                         DRIVER_NAME " (dma)", host);
71         if (ret) {
72                 dev_err(&pdev->dev, "cannot set DMA IRQ\n");
73                 goto err_add_dma_irq;
74         }
75 +       host->second_irq = host_priv->dma_irq;
76         DBG("DMA CBs %p handle %08X DMA%d %p DMA IRQ %d\n",
77             host_priv->cb_base, (unsigned)host_priv->cb_handle,
78             host_priv->dma_chan, host_priv->dma_chan_base,
79 @@ -1384,6 +1387,7 @@ module_param(allow_highspeed, bool, 0444);
80  module_param(emmc_clock_freq, int, 0444);
81  module_param(sync_after_dma, bool, 0444);
82  module_param(missing_status, bool, 0444);
83 +module_param(enable_llm, bool, 0444);
84  
85  MODULE_DESCRIPTION("Secure Digital Host Controller Interface platform driver");
86  MODULE_AUTHOR("Broadcom <info@broadcom.com>");
87 @@ -1394,5 +1398,6 @@ MODULE_PARM_DESC(allow_highspeed, "Allow high speed transfers modes");
88  MODULE_PARM_DESC(emmc_clock_freq, "Specify the speed of emmc clock");
89  MODULE_PARM_DESC(sync_after_dma, "Block in driver until dma complete");
90  MODULE_PARM_DESC(missing_status, "Use the missing status quirk");
91 +MODULE_PARM_DESC(enable_llm, "Enable low-latency mode");
92  
93  
94 diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
95 index 179e83e..470860b 100644
96 --- a/drivers/mmc/host/sdhci.c
97 +++ b/drivers/mmc/host/sdhci.c
98 @@ -124,6 +124,91 @@ static void sdhci_dumpregs(struct sdhci_host *host)
99   * Low level functions                                                       *
100   *                                                                           *
101  \*****************************************************************************/
102 +extern bool enable_llm;
103 +static int sdhci_locked=0;
104 +void sdhci_spin_lock(struct sdhci_host *host)
105 +{
106 +       spin_lock(&host->lock);
107 +#ifdef CONFIG_PREEMPT
108 +       if(enable_llm)
109 +       {
110 +               disable_irq_nosync(host->irq);
111 +               if(host->second_irq)
112 +                       disable_irq_nosync(host->second_irq);
113 +               local_irq_enable();
114 +       }
115 +#endif
116 +}
117 +
118 +void sdhci_spin_unlock(struct sdhci_host *host)
119 +{
120 +#ifdef CONFIG_PREEMPT
121 +       if(enable_llm)
122 +       {
123 +               local_irq_disable();
124 +               if(host->second_irq)
125 +                       enable_irq(host->second_irq);
126 +               enable_irq(host->irq);
127 +       }
128 +#endif
129 +       spin_unlock(&host->lock);
130 +}
131 +
132 +void sdhci_spin_lock_irqsave(struct sdhci_host *host,unsigned long *flags)
133 +{
134 +#ifdef CONFIG_PREEMPT
135 +       if(enable_llm)
136 +       {
137 +               while(sdhci_locked)
138 +               {
139 +                       preempt_schedule();
140 +               }
141 +               spin_lock_irqsave(&host->lock,*flags);
142 +               disable_irq(host->irq);
143 +               if(host->second_irq)
144 +                       disable_irq(host->second_irq);
145 +               local_irq_enable();
146 +       }
147 +       else
148 +#endif
149 +               spin_lock_irqsave(&host->lock,*flags);
150 +}
151 +
152 +void sdhci_spin_unlock_irqrestore(struct sdhci_host *host,unsigned long flags)
153 +{
154 +#ifdef CONFIG_PREEMPT
155 +       if(enable_llm)
156 +       {
157 +               local_irq_disable();
158 +               if(host->second_irq)
159 +                       enable_irq(host->second_irq);
160 +               enable_irq(host->irq);
161 +       }
162 +#endif
163 +       spin_unlock_irqrestore(&host->lock,flags);
164 +}
165 +
166 +static void sdhci_spin_enable_schedule(struct sdhci_host *host)
167 +{
168 +#ifdef CONFIG_PREEMPT
169 +       if(enable_llm)
170 +       {
171 +               sdhci_locked = 1;
172 +               preempt_enable();
173 +       }
174 +#endif
175 +}
176 +
177 +static void sdhci_spin_disable_schedule(struct sdhci_host *host)
178 +{
179 +#ifdef CONFIG_PREEMPT
180 +       if(enable_llm)
181 +       {
182 +               preempt_disable();
183 +               sdhci_locked = 0;
184 +       }
185 +#endif
186 +}
187  
188  static void sdhci_clear_set_irqs(struct sdhci_host *host, u32 clear, u32 set)
189  {
190 @@ -289,7 +374,7 @@ static void sdhci_led_control(struct led_classdev *led,
191         struct sdhci_host *host = container_of(led, struct sdhci_host, led);
192         unsigned long flags;
193  
194 -       spin_lock_irqsave(&host->lock, flags);
195 +       sdhci_spin_lock_irqsave(host, &flags);
196  
197         if (host->runtime_suspended)
198                 goto out;
199 @@ -299,7 +384,7 @@ static void sdhci_led_control(struct led_classdev *led,
200         else
201                 sdhci_activate_led(host);
202  out:
203 -       spin_unlock_irqrestore(&host->lock, flags);
204 +       sdhci_spin_unlock_irqrestore(host, flags);
205  }
206  #endif
207  
208 @@ -1007,7 +1092,9 @@ static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
209                         return;
210                 }
211                 timeout--;
212 +               sdhci_spin_enable_schedule(host);
213                 mdelay(1);
214 +               sdhci_spin_disable_schedule(host);
215         }
216         DBG("send cmd %d - wait 0x%X irq 0x%x\n", cmd->opcode, mask,
217             sdhci_readl(host, SDHCI_INT_STATUS));
218 @@ -1234,7 +1321,9 @@ clock_set:
219                         return;
220                 }
221                 timeout--;
222 +               sdhci_spin_enable_schedule(host);
223                 mdelay(1);
224 +               sdhci_spin_disable_schedule(host);
225         }
226  
227         clk |= SDHCI_CLOCK_CARD_EN;
228 @@ -1330,7 +1419,7 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
229  
230         sdhci_runtime_pm_get(host);
231  
232 -       spin_lock_irqsave(&host->lock, flags);
233 +       sdhci_spin_lock_irqsave(host, &flags);
234  
235         WARN_ON(host->mrq != NULL);
236  
237 @@ -1388,9 +1477,9 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
238                                         mmc->card->type == MMC_TYPE_MMC ?
239                                         MMC_SEND_TUNING_BLOCK_HS200 :
240                                         MMC_SEND_TUNING_BLOCK;
241 -                               spin_unlock_irqrestore(&host->lock, flags);
242 +                               sdhci_spin_unlock_irqrestore(host, flags);
243                                 sdhci_execute_tuning(mmc, tuning_opcode);
244 -                               spin_lock_irqsave(&host->lock, flags);
245 +                               sdhci_spin_lock_irqsave(host, &flags);
246  
247                                 /* Restore original mmc_request structure */
248                                 host->mrq = mrq;
249 @@ -1404,7 +1493,7 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
250         }
251  
252         mmiowb();
253 -       spin_unlock_irqrestore(&host->lock, flags);
254 +       sdhci_spin_unlock_irqrestore(host, flags);
255  }
256  
257  static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
258 @@ -1413,10 +1502,10 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
259         int vdd_bit = -1;
260         u8 ctrl;
261  
262 -       spin_lock_irqsave(&host->lock, flags);
263 +       sdhci_spin_lock_irqsave(host, &flags);
264  
265         if (host->flags & SDHCI_DEVICE_DEAD) {
266 -               spin_unlock_irqrestore(&host->lock, flags);
267 +               sdhci_spin_unlock_irqrestore(host, flags);
268                 if (host->vmmc && ios->power_mode == MMC_POWER_OFF)
269                         mmc_regulator_set_ocr(host->mmc, host->vmmc, 0);
270                 return;
271 @@ -1443,9 +1532,9 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
272                 vdd_bit = sdhci_set_power(host, ios->vdd);
273  
274         if (host->vmmc && vdd_bit != -1) {
275 -               spin_unlock_irqrestore(&host->lock, flags);
276 +               sdhci_spin_unlock_irqrestore(host, flags);
277                 mmc_regulator_set_ocr(host->mmc, host->vmmc, vdd_bit);
278 -               spin_lock_irqsave(&host->lock, flags);
279 +               sdhci_spin_lock_irqsave(host, &flags);
280         }
281  
282         if (host->ops->platform_send_init_74_clocks)
283 @@ -1583,7 +1672,7 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
284                 sdhci_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA);
285  
286         mmiowb();
287 -       spin_unlock_irqrestore(&host->lock, flags);
288 +       sdhci_spin_unlock_irqrestore(host, flags);
289  }
290  
291  static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
292 @@ -1631,7 +1720,7 @@ static int sdhci_check_ro(struct sdhci_host *host)
293         unsigned long flags;
294         int is_readonly;
295  
296 -       spin_lock_irqsave(&host->lock, flags);
297 +       sdhci_spin_lock_irqsave(host, &flags);
298  
299         if (host->flags & SDHCI_DEVICE_DEAD)
300                 is_readonly = 0;
301 @@ -1641,7 +1730,7 @@ static int sdhci_check_ro(struct sdhci_host *host)
302                 is_readonly = !(sdhci_readl(host, SDHCI_PRESENT_STATE)
303                                 & SDHCI_WRITE_PROTECT);
304  
305 -       spin_unlock_irqrestore(&host->lock, flags);
306 +       sdhci_spin_unlock_irqrestore(host, flags);
307  
308         /* This quirk needs to be replaced by a callback-function later */
309         return host->quirks & SDHCI_QUIRK_INVERTED_WRITE_PROTECT ?
310 @@ -1714,9 +1803,9 @@ static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable)
311         struct sdhci_host *host = mmc_priv(mmc);
312         unsigned long flags;
313  
314 -       spin_lock_irqsave(&host->lock, flags);
315 +       sdhci_spin_lock_irqsave(host, &flags);
316         sdhci_enable_sdio_irq_nolock(host, enable);
317 -       spin_unlock_irqrestore(&host->lock, flags);
318 +       sdhci_spin_unlock_irqrestore(host, flags);
319  }
320  
321  static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host,
322 @@ -2060,7 +2149,7 @@ static void sdhci_card_event(struct mmc_host *mmc)
323         struct sdhci_host *host = mmc_priv(mmc);
324         unsigned long flags;
325  
326 -       spin_lock_irqsave(&host->lock, flags);
327 +       sdhci_spin_lock_irqsave(host, &flags);
328  
329         /* Check host->mrq first in case we are runtime suspended */
330         if (host->mrq &&
331 @@ -2077,7 +2166,7 @@ static void sdhci_card_event(struct mmc_host *mmc)
332                 tasklet_schedule(&host->finish_tasklet);
333         }
334  
335 -       spin_unlock_irqrestore(&host->lock, flags);
336 +       sdhci_spin_unlock_irqrestore(host, flags);
337  }
338  
339  static const struct mmc_host_ops sdhci_ops = {
340 @@ -2116,14 +2205,14 @@ static void sdhci_tasklet_finish(unsigned long param)
341  
342         host = (struct sdhci_host*)param;
343  
344 -       spin_lock_irqsave(&host->lock, flags);
345 +       sdhci_spin_lock_irqsave(host, &flags);
346  
347          /*
348           * If this tasklet gets rescheduled while running, it will
349           * be run again afterwards but without any active request.
350           */
351         if (!host->mrq) {
352 -               spin_unlock_irqrestore(&host->lock, flags);
353 +               sdhci_spin_unlock_irqrestore(host, flags);
354                 return;
355         }
356  
357 @@ -2161,7 +2250,7 @@ static void sdhci_tasklet_finish(unsigned long param)
358  #endif
359  
360         mmiowb();
361 -       spin_unlock_irqrestore(&host->lock, flags);
362 +       sdhci_spin_unlock_irqrestore(host, flags);
363  
364         mmc_request_done(host->mmc, mrq);
365         sdhci_runtime_pm_put(host);
366 @@ -2174,7 +2263,7 @@ static void sdhci_timeout_timer(unsigned long data)
367  
368         host = (struct sdhci_host*)data;
369  
370 -       spin_lock_irqsave(&host->lock, flags);
371 +       sdhci_spin_lock_irqsave(host, &flags);
372  
373         if (host->mrq) {
374                 pr_err("%s: Timeout waiting for hardware "
375 @@ -2195,7 +2284,7 @@ static void sdhci_timeout_timer(unsigned long data)
376         }
377  
378         mmiowb();
379 -       spin_unlock_irqrestore(&host->lock, flags);
380 +       sdhci_spin_unlock_irqrestore(host, flags);
381  }
382  
383  static void sdhci_tuning_timer(unsigned long data)
384 @@ -2205,11 +2294,11 @@ static void sdhci_tuning_timer(unsigned long data)
385  
386         host = (struct sdhci_host *)data;
387  
388 -       spin_lock_irqsave(&host->lock, flags);
389 +       sdhci_spin_lock_irqsave(host, &flags);
390  
391         host->flags |= SDHCI_NEEDS_RETUNING;
392  
393 -       spin_unlock_irqrestore(&host->lock, flags);
394 +       sdhci_spin_unlock_irqrestore(host, flags);
395  }
396  
397  /*****************************************************************************\
398 @@ -2433,10 +2522,10 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
399         u32 intmask, unexpected = 0;
400         int cardint = 0, max_loops = 16;
401  
402 -       spin_lock(&host->lock);
403 +       sdhci_spin_lock(host);
404  
405         if (host->runtime_suspended) {
406 -               spin_unlock(&host->lock);
407 +               sdhci_spin_unlock(host);
408                 pr_warning("%s: got irq while runtime suspended\n",
409                        mmc_hostname(host->mmc));
410                 return IRQ_HANDLED;
411 @@ -2540,7 +2629,7 @@ again:
412         if (intmask && --max_loops)
413                 goto again;
414  out:
415 -       spin_unlock(&host->lock);
416 +       sdhci_spin_unlock(host);
417  
418         if (unexpected) {
419                 pr_err("%s: Unexpected interrupt 0x%08x.\n",
420 @@ -2702,15 +2791,15 @@ int sdhci_runtime_suspend_host(struct sdhci_host *host)
421                 host->flags &= ~SDHCI_NEEDS_RETUNING;
422         }
423  
424 -       spin_lock_irqsave(&host->lock, flags);
425 +       sdhci_spin_lock_irqsave(host, &flags);
426         sdhci_mask_irqs(host, SDHCI_INT_ALL_MASK);
427 -       spin_unlock_irqrestore(&host->lock, flags);
428 +       sdhci_spin_unlock_irqrestore(host, flags);
429  
430         synchronize_irq(host->irq);
431  
432 -       spin_lock_irqsave(&host->lock, flags);
433 +       sdhci_spin_lock_irqsave(host, &flags);
434         host->runtime_suspended = true;
435 -       spin_unlock_irqrestore(&host->lock, flags);
436 +       sdhci_spin_unlock_irqrestore(host, flags);
437  
438         return ret;
439  }
440 @@ -2736,16 +2825,16 @@ int sdhci_runtime_resume_host(struct sdhci_host *host)
441         sdhci_do_start_signal_voltage_switch(host, &host->mmc->ios);
442         if ((host_flags & SDHCI_PV_ENABLED) &&
443                 !(host->quirks2 & SDHCI_QUIRK2_PRESET_VALUE_BROKEN)) {
444 -               spin_lock_irqsave(&host->lock, flags);
445 +               sdhci_spin_lock_irqsave(host, &flags);
446                 sdhci_enable_preset_value(host, true);
447 -               spin_unlock_irqrestore(&host->lock, flags);
448 +               sdhci_spin_unlock_irqrestore(host, flags);
449         }
450  
451         /* Set the re-tuning expiration flag */
452         if (host->flags & SDHCI_USING_RETUNING_TIMER)
453                 host->flags |= SDHCI_NEEDS_RETUNING;
454  
455 -       spin_lock_irqsave(&host->lock, flags);
456 +       sdhci_spin_lock_irqsave(host, &flags);
457  
458         host->runtime_suspended = false;
459  
460 @@ -2756,7 +2845,7 @@ int sdhci_runtime_resume_host(struct sdhci_host *host)
461         /* Enable Card Detection */
462         sdhci_enable_card_detection(host);
463  
464 -       spin_unlock_irqrestore(&host->lock, flags);
465 +       sdhci_spin_unlock_irqrestore(host, flags);
466  
467         return ret;
468  }
469 @@ -3248,7 +3337,7 @@ int sdhci_add_host(struct sdhci_host *host)
470                 host->tuning_timer.function = sdhci_tuning_timer;
471         }
472  
473 -       ret = request_irq(host->irq, sdhci_irq, IRQF_SHARED,
474 +       ret = request_irq(host->irq, sdhci_irq, 0,//IRQF_SHARED,
475                 mmc_hostname(mmc), host);
476         if (ret) {
477                 pr_err("%s: Failed to request IRQ %d: %d\n",
478 @@ -3312,7 +3401,7 @@ void sdhci_remove_host(struct sdhci_host *host, int dead)
479         unsigned long flags;
480  
481         if (dead) {
482 -               spin_lock_irqsave(&host->lock, flags);
483 +               sdhci_spin_lock_irqsave(host, &flags);
484  
485                 host->flags |= SDHCI_DEVICE_DEAD;
486  
487 @@ -3324,7 +3413,7 @@ void sdhci_remove_host(struct sdhci_host *host, int dead)
488                         tasklet_schedule(&host->finish_tasklet);
489                 }
490  
491 -               spin_unlock_irqrestore(&host->lock, flags);
492 +               sdhci_spin_unlock_irqrestore(host, flags);
493         }
494  
495         sdhci_disable_card_detection(host);
496 diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
497 index f90574e..cc393af 100644
498 --- a/drivers/mmc/host/sdhci.h
499 +++ b/drivers/mmc/host/sdhci.h
500 @@ -441,4 +441,10 @@ extern int sdhci_runtime_suspend_host(struct sdhci_host *host);
501  extern int sdhci_runtime_resume_host(struct sdhci_host *host);
502  #endif
503  
504 +extern void sdhci_spin_lock_irqsave(struct sdhci_host *host,unsigned long *flags);
505 +extern void sdhci_spin_unlock_irqrestore(struct sdhci_host *host,unsigned long flags);
506 +extern void sdhci_spin_lock(struct sdhci_host *host);
507 +extern void sdhci_spin_unlock(struct sdhci_host *host);
508 +
509 +
510  #endif /* __SDHCI_HW_H */
511 diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h
512 index f3a39c1..58bfab0 100644
513 --- a/include/linux/mmc/sdhci.h
514 +++ b/include/linux/mmc/sdhci.h
515 @@ -97,6 +97,7 @@ struct sdhci_host {
516  #define SDHCI_QUIRK2_PRESET_VALUE_BROKEN               (1<<3)
517  
518         int irq;                /* Device IRQ */
519 +       int second_irq;         /* Additional IRQ to disable/enable in low-latency mode */
520         void __iomem *ioaddr;   /* Mapped address */
521  
522         const struct sdhci_ops *ops;    /* Low level hw interface */
523 -- 
524 1.9.1
525