dfb61a6cdb68a88d11f6922edbdd7fd9aa8af550
[openwrt/staging/yousong.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 */