]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blob - queue-5.0/mmc-alcor-don-t-write-data-before-command-has-completed.patch
3.18-stable patches
[thirdparty/kernel/stable-queue.git] / queue-5.0 / mmc-alcor-don-t-write-data-before-command-has-completed.patch
1 From 157c99c5a2956a9ab1ae12de0136a2d8a1b1a307 Mon Sep 17 00:00:00 2001
2 From: Daniel Drake <drake@endlessm.com>
3 Date: Tue, 26 Mar 2019 15:04:14 +0800
4 Subject: mmc: alcor: don't write data before command has completed
5
6 From: Daniel Drake <drake@endlessm.com>
7
8 commit 157c99c5a2956a9ab1ae12de0136a2d8a1b1a307 upstream.
9
10 The alcor driver is setting up data transfer and submitting the associated
11 MMC command at the same time. While this works most of the time, it
12 occasionally causes problems upon write.
13
14 In the working case, after setting up the data transfer and submitting
15 the MMC command, an interrupt comes in a moment later with CMD_END and
16 WRITE_BUF_RDY bits set. The data transfer then happens without problem.
17
18 However, on occasion, the interrupt that arrives at that point only
19 has WRITE_BUF_RDY set. The hardware notifies that it's ready to write
20 data, but the associated MMC command is still running. Regardless, the
21 driver was proceeding to write data immediately, and that would then cause
22 another interrupt indicating data CRC error, and the write would fail.
23
24 Additionally, the transfer setup function alcor_trigger_data_transfer()
25 was being called 3 times for each write operation, which was confusing
26 and may be contributing to this issue.
27
28 Solve this by tweaking the driver behaviour to follow the sequence observed
29 in the original ampe_stor vendor driver:
30 1. When starting request handling, write 0 to DATA_XFER_CTRL
31 2. Submit the command
32 3. Wait for CMD_END interrupt and then trigger data transfer
33 4. For the PIO case, trigger the next step of the data transfer only
34 upon the following DATA_END interrupt, which occurs after the block has
35 been written.
36
37 I confirmed that the read path still works (DMA & PIO) and also now
38 presents more consistency with the operations performed by ampe_stor.
39
40 Signed-off-by: Daniel Drake <drake@endlessm.com>
41 Fixes: c5413ad815a6 ("mmc: add new Alcor Micro Cardreader SD/MMC driver")
42 Cc: stable@vger.kernel.org
43 Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
44 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
45
46 ---
47 drivers/mmc/host/alcor.c | 34 +++++++++++++---------------------
48 1 file changed, 13 insertions(+), 21 deletions(-)
49
50 --- a/drivers/mmc/host/alcor.c
51 +++ b/drivers/mmc/host/alcor.c
52 @@ -48,7 +48,6 @@ struct alcor_sdmmc_host {
53 struct mmc_command *cmd;
54 struct mmc_data *data;
55 unsigned int dma_on:1;
56 - unsigned int early_data:1;
57
58 struct mutex cmd_mutex;
59
60 @@ -144,8 +143,7 @@ static void alcor_data_set_dma(struct al
61 host->sg_count--;
62 }
63
64 -static void alcor_trigger_data_transfer(struct alcor_sdmmc_host *host,
65 - bool early)
66 +static void alcor_trigger_data_transfer(struct alcor_sdmmc_host *host)
67 {
68 struct alcor_pci_priv *priv = host->alcor_pci;
69 struct mmc_data *data = host->data;
70 @@ -155,13 +153,6 @@ static void alcor_trigger_data_transfer(
71 ctrl |= AU6601_DATA_WRITE;
72
73 if (data->host_cookie == COOKIE_MAPPED) {
74 - if (host->early_data) {
75 - host->early_data = false;
76 - return;
77 - }
78 -
79 - host->early_data = early;
80 -
81 alcor_data_set_dma(host);
82 ctrl |= AU6601_DATA_DMA_MODE;
83 host->dma_on = 1;
84 @@ -231,6 +222,7 @@ static void alcor_prepare_sg_miter(struc
85 static void alcor_prepare_data(struct alcor_sdmmc_host *host,
86 struct mmc_command *cmd)
87 {
88 + struct alcor_pci_priv *priv = host->alcor_pci;
89 struct mmc_data *data = cmd->data;
90
91 if (!data)
92 @@ -248,7 +240,7 @@ static void alcor_prepare_data(struct al
93 if (data->host_cookie != COOKIE_MAPPED)
94 alcor_prepare_sg_miter(host);
95
96 - alcor_trigger_data_transfer(host, true);
97 + alcor_write8(priv, 0, AU6601_DATA_XFER_CTRL);
98 }
99
100 static void alcor_send_cmd(struct alcor_sdmmc_host *host,
101 @@ -435,7 +427,7 @@ static int alcor_cmd_irq_done(struct alc
102 if (!host->data)
103 return false;
104
105 - alcor_trigger_data_transfer(host, false);
106 + alcor_trigger_data_transfer(host);
107 host->cmd = NULL;
108 return true;
109 }
110 @@ -456,7 +448,7 @@ static void alcor_cmd_irq_thread(struct
111 if (!host->data)
112 alcor_request_complete(host, 1);
113 else
114 - alcor_trigger_data_transfer(host, false);
115 + alcor_trigger_data_transfer(host);
116 host->cmd = NULL;
117 }
118
119 @@ -487,15 +479,9 @@ static int alcor_data_irq_done(struct al
120 break;
121 case AU6601_INT_READ_BUF_RDY:
122 alcor_trf_block_pio(host, true);
123 - if (!host->blocks)
124 - break;
125 - alcor_trigger_data_transfer(host, false);
126 return 1;
127 case AU6601_INT_WRITE_BUF_RDY:
128 alcor_trf_block_pio(host, false);
129 - if (!host->blocks)
130 - break;
131 - alcor_trigger_data_transfer(host, false);
132 return 1;
133 case AU6601_INT_DMA_END:
134 if (!host->sg_count)
135 @@ -508,8 +494,14 @@ static int alcor_data_irq_done(struct al
136 break;
137 }
138
139 - if (intmask & AU6601_INT_DATA_END)
140 - return 0;
141 + if (intmask & AU6601_INT_DATA_END) {
142 + if (!host->dma_on && host->blocks) {
143 + alcor_trigger_data_transfer(host);
144 + return 1;
145 + } else {
146 + return 0;
147 + }
148 + }
149
150 return 1;
151 }