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