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.
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(-)
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;
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;
32 BUG_ON(NULL == dev_id);
33 BUG_ON(NULL == host_priv->dma_chan_base);
35 - spin_lock_irqsave(&host->lock, flags);
36 + sdhci_spin_lock(host);
38 dma_cs = readl(host_priv->dma_chan_base + BCM2708_DMA_CS);
40 @@ -917,8 +917,7 @@ static irqreturn_t sdhci_bcm2708_dma_irq(int irq, void *dev_id)
45 - spin_unlock_irqrestore(&host->lock, flags);
46 + sdhci_spin_unlock(host);
50 @@ -1193,9 +1192,12 @@ static int sdhci_bcm2708_probe(struct platform_device *pdev)
51 sdhci_bcm2708_ops.missing_status = sdhci_bcm2708_missing_status;
54 + printk("sdhci: %s low-latency mode\n",enable_llm?"Enable":"Disable");
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;
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)
65 host_priv->dma_chan = ret;
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);
72 dev_err(&pdev->dev, "cannot set DMA IRQ\n");
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);
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");
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 *
101 \*****************************************************************************/
102 +extern bool enable_llm;
103 +static int sdhci_locked=0;
104 +void sdhci_spin_lock(struct sdhci_host *host)
106 + spin_lock(&host->lock);
107 +#ifdef CONFIG_PREEMPT
110 + disable_irq_nosync(host->irq);
111 + if(host->second_irq)
112 + disable_irq_nosync(host->second_irq);
113 + local_irq_enable();
118 +void sdhci_spin_unlock(struct sdhci_host *host)
120 +#ifdef CONFIG_PREEMPT
123 + local_irq_disable();
124 + if(host->second_irq)
125 + enable_irq(host->second_irq);
126 + enable_irq(host->irq);
129 + spin_unlock(&host->lock);
132 +void sdhci_spin_lock_irqsave(struct sdhci_host *host,unsigned long *flags)
134 +#ifdef CONFIG_PREEMPT
137 + while(sdhci_locked)
139 + preempt_schedule();
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();
149 + spin_lock_irqsave(&host->lock,*flags);
152 +void sdhci_spin_unlock_irqrestore(struct sdhci_host *host,unsigned long flags)
154 +#ifdef CONFIG_PREEMPT
157 + local_irq_disable();
158 + if(host->second_irq)
159 + enable_irq(host->second_irq);
160 + enable_irq(host->irq);
163 + spin_unlock_irqrestore(&host->lock,flags);
166 +static void sdhci_spin_enable_schedule(struct sdhci_host *host)
168 +#ifdef CONFIG_PREEMPT
177 +static void sdhci_spin_disable_schedule(struct sdhci_host *host)
179 +#ifdef CONFIG_PREEMPT
188 static void sdhci_clear_set_irqs(struct sdhci_host *host, u32 clear, u32 set)
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);
194 - spin_lock_irqsave(&host->lock, flags);
195 + sdhci_spin_lock_irqsave(host, &flags);
197 if (host->runtime_suspended)
199 @@ -299,7 +384,7 @@ static void sdhci_led_control(struct led_classdev *led,
201 sdhci_activate_led(host);
203 - spin_unlock_irqrestore(&host->lock, flags);
204 + sdhci_spin_unlock_irqrestore(host, flags);
208 @@ -1007,7 +1092,9 @@ static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
212 + sdhci_spin_enable_schedule(host);
214 + sdhci_spin_disable_schedule(host);
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:
222 + sdhci_spin_enable_schedule(host);
224 + sdhci_spin_disable_schedule(host);
227 clk |= SDHCI_CLOCK_CARD_EN;
228 @@ -1330,7 +1419,7 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
230 sdhci_runtime_pm_get(host);
232 - spin_lock_irqsave(&host->lock, flags);
233 + sdhci_spin_lock_irqsave(host, &flags);
235 WARN_ON(host->mrq != NULL);
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);
247 /* Restore original mmc_request structure */
249 @@ -1404,7 +1493,7 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
253 - spin_unlock_irqrestore(&host->lock, flags);
254 + sdhci_spin_unlock_irqrestore(host, flags);
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)
262 - spin_lock_irqsave(&host->lock, flags);
263 + sdhci_spin_lock_irqsave(host, &flags);
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);
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);
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);
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);
287 - spin_unlock_irqrestore(&host->lock, flags);
288 + sdhci_spin_unlock_irqrestore(host, flags);
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)
296 - spin_lock_irqsave(&host->lock, flags);
297 + sdhci_spin_lock_irqsave(host, &flags);
299 if (host->flags & SDHCI_DEVICE_DEAD)
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);
305 - spin_unlock_irqrestore(&host->lock, flags);
306 + sdhci_spin_unlock_irqrestore(host, flags);
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);
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);
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);
326 - spin_lock_irqsave(&host->lock, flags);
327 + sdhci_spin_lock_irqsave(host, &flags);
329 /* Check host->mrq first in case we are runtime suspended */
331 @@ -2077,7 +2166,7 @@ static void sdhci_card_event(struct mmc_host *mmc)
332 tasklet_schedule(&host->finish_tasklet);
335 - spin_unlock_irqrestore(&host->lock, flags);
336 + sdhci_spin_unlock_irqrestore(host, flags);
339 static const struct mmc_host_ops sdhci_ops = {
340 @@ -2116,14 +2205,14 @@ static void sdhci_tasklet_finish(unsigned long param)
342 host = (struct sdhci_host*)param;
344 - spin_lock_irqsave(&host->lock, flags);
345 + sdhci_spin_lock_irqsave(host, &flags);
348 * If this tasklet gets rescheduled while running, it will
349 * be run again afterwards but without any active request.
352 - spin_unlock_irqrestore(&host->lock, flags);
353 + sdhci_spin_unlock_irqrestore(host, flags);
357 @@ -2161,7 +2250,7 @@ static void sdhci_tasklet_finish(unsigned long param)
361 - spin_unlock_irqrestore(&host->lock, flags);
362 + sdhci_spin_unlock_irqrestore(host, flags);
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)
368 host = (struct sdhci_host*)data;
370 - spin_lock_irqsave(&host->lock, flags);
371 + sdhci_spin_lock_irqsave(host, &flags);
374 pr_err("%s: Timeout waiting for hardware "
375 @@ -2195,7 +2284,7 @@ static void sdhci_timeout_timer(unsigned long data)
379 - spin_unlock_irqrestore(&host->lock, flags);
380 + sdhci_spin_unlock_irqrestore(host, flags);
383 static void sdhci_tuning_timer(unsigned long data)
384 @@ -2205,11 +2294,11 @@ static void sdhci_tuning_timer(unsigned long data)
386 host = (struct sdhci_host *)data;
388 - spin_lock_irqsave(&host->lock, flags);
389 + sdhci_spin_lock_irqsave(host, &flags);
391 host->flags |= SDHCI_NEEDS_RETUNING;
393 - spin_unlock_irqrestore(&host->lock, flags);
394 + sdhci_spin_unlock_irqrestore(host, flags);
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;
402 - spin_lock(&host->lock);
403 + sdhci_spin_lock(host);
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));
411 @@ -2540,7 +2629,7 @@ again:
412 if (intmask && --max_loops)
415 - spin_unlock(&host->lock);
416 + sdhci_spin_unlock(host);
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;
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);
430 synchronize_irq(host->irq);
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);
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);
451 /* Set the re-tuning expiration flag */
452 if (host->flags & SDHCI_USING_RETUNING_TIMER)
453 host->flags |= SDHCI_NEEDS_RETUNING;
455 - spin_lock_irqsave(&host->lock, flags);
456 + sdhci_spin_lock_irqsave(host, &flags);
458 host->runtime_suspended = false;
460 @@ -2756,7 +2845,7 @@ int sdhci_runtime_resume_host(struct sdhci_host *host)
461 /* Enable Card Detection */
462 sdhci_enable_card_detection(host);
464 - spin_unlock_irqrestore(&host->lock, flags);
465 + sdhci_spin_unlock_irqrestore(host, flags);
469 @@ -3248,7 +3337,7 @@ int sdhci_add_host(struct sdhci_host *host)
470 host->tuning_timer.function = sdhci_tuning_timer;
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);
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)
482 - spin_lock_irqsave(&host->lock, flags);
483 + sdhci_spin_lock_irqsave(host, &flags);
485 host->flags |= SDHCI_DEVICE_DEAD;
487 @@ -3324,7 +3413,7 @@ void sdhci_remove_host(struct sdhci_host *host, int dead)
488 tasklet_schedule(&host->finish_tasklet);
491 - spin_unlock_irqrestore(&host->lock, flags);
492 + sdhci_spin_unlock_irqrestore(host, flags);
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);
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);
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)
518 int irq; /* Device IRQ */
519 + int second_irq; /* Additional IRQ to disable/enable in low-latency mode */
520 void __iomem *ioaddr; /* Mapped address */
522 const struct sdhci_ops *ops; /* Low level hw interface */