1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
|
From c63af7f27233c7e7c6f0e4ee7d040e9545190df8 Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Mon, 11 Apr 2016 12:50:58 +0100
Subject: [PATCH] bcm2835-sdhost: Reset the clock in task context
Since reprogramming the clock can now involve a round-trip to the
firmware it must not be done at atomic context, and a tasklet
is not a task.
Signed-off-by: Phil Elwell <phil@raspberrypi.org>
---
drivers/mmc/host/bcm2835-sdhost.c | 25 ++++++++++++++++++-------
1 file changed, 18 insertions(+), 7 deletions(-)
--- a/drivers/mmc/host/bcm2835-sdhost.c
+++ b/drivers/mmc/host/bcm2835-sdhost.c
@@ -185,6 +185,7 @@ struct bcm2835_host {
unsigned int debug:1; /* Enable debug output */
unsigned int firmware_sets_cdiv:1; /* Let the firmware manage the clock */
+ unsigned int reset_clock:1; /* Reset the clock fore the next request */
/*DMA part*/
struct dma_chan *dma_chan_rxtx; /* DMA channel for reads and writes */
@@ -1505,6 +1506,7 @@ void bcm2835_sdhost_set_clock(struct bcm
{
int div = 0; /* Initialized for compiler warning */
unsigned int input_clock = clock;
+ unsigned long flags;
if (host->debug)
pr_info("%s: set_clock(%d)\n", mmc_hostname(host->mmc), clock);
@@ -1544,13 +1546,17 @@ void bcm2835_sdhost_set_clock(struct bcm
&msg, sizeof(msg));
clock = max(msg[1], msg[2]);
+ spin_lock_irqsave(&host->lock, flags);
} else {
+ spin_lock_irqsave(&host->lock, flags);
if (clock < 100000) {
/* Can't stop the clock, but make it as slow as
* possible to show willing
*/
host->cdiv = SDCDIV_MAX_CDIV;
bcm2835_sdhost_write(host, host->cdiv, SDCDIV);
+ mmiowb();
+ spin_unlock_irqrestore(&host->lock, flags);
return;
}
@@ -1605,6 +1611,11 @@ void bcm2835_sdhost_set_clock(struct bcm
bcm2835_sdhost_write(host, clock/2, SDTOUT);
host->mmc->actual_clock = clock;
+ host->clock = input_clock;
+ host->reset_clock = 0;
+
+ mmiowb();
+ spin_unlock_irqrestore(&host->lock, flags);
}
static void bcm2835_sdhost_request(struct mmc_host *mmc, struct mmc_request *mrq)
@@ -1653,6 +1664,9 @@ static void bcm2835_sdhost_request(struc
(mrq->data->blocks > host->pio_limit))
bcm2835_sdhost_prepare_dma(host, mrq->data);
+ if (host->reset_clock)
+ bcm2835_sdhost_set_clock(host, host->clock);
+
spin_lock_irqsave(&host->lock, flags);
WARN_ON(host->mrq != NULL);
@@ -1731,14 +1745,12 @@ static void bcm2835_sdhost_set_ios(struc
bcm2835_sdhost_write(host, host->hcfg, SDHCFG);
- if (!ios->clock || ios->clock != host->clock) {
- bcm2835_sdhost_set_clock(host, ios->clock);
- host->clock = ios->clock;
- }
-
mmiowb();
spin_unlock_irqrestore(&host->lock, flags);
+
+ if (!ios->clock || ios->clock != host->clock)
+ bcm2835_sdhost_set_clock(host, ios->clock);
}
static struct mmc_host_ops bcm2835_sdhost_ops = {
@@ -1810,7 +1822,7 @@ static void bcm2835_sdhost_tasklet_finis
host->overclock_50--;
pr_warn("%s: reducing overclock due to errors\n",
mmc_hostname(host->mmc));
- bcm2835_sdhost_set_clock(host,50*MHZ);
+ host->reset_clock = 1;
mrq->cmd->error = -EILSEQ;
mrq->cmd->retries = 1;
}
@@ -1979,7 +1991,6 @@ static int bcm2835_sdhost_probe(struct p
mmc->ops = &bcm2835_sdhost_ops;
host = mmc_priv(mmc);
host->mmc = mmc;
- host->cmd_quick_poll_retries = 0;
host->pio_timeout = msecs_to_jiffies(500);
host->pio_limit = 1;
host->max_delay = 1; /* Warn if over 1ms */
|