Skip to content

Commit 0cbc94d

Browse files
Wolfram Sangstorulf
authored andcommitted
mmc: renesas_sdhi_internal_dmac: limit DMA RX for old SoCs
Early revisions of certain SoCs cannot do multiple DMA RX streams in parallel. To avoid data corruption, only allow one DMA RX channel and fall back to PIO, if needed. Signed-off-by: Wolfram Sang <wsa+renesas@sang-engineering.com> Reviewed-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com> Tested-by: Nguyen Viet Dung <dung.nguyen.aj@renesas.com> Reviewed-by: Simon Horman <horms+renesas@verge.net.au> Cc: stable@vger.kernel.org Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
1 parent 300ad89 commit 0cbc94d

File tree

1 file changed

+33
-6
lines changed

1 file changed

+33
-6
lines changed

drivers/mmc/host/renesas_sdhi_internal_dmac.c

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
* published by the Free Software Foundation.
1010
*/
1111

12+
#include <linux/bitops.h>
1213
#include <linux/device.h>
1314
#include <linux/dma-mapping.h>
1415
#include <linux/io-64-nonatomic-hi-lo.h>
@@ -62,6 +63,17 @@
6263
* need a custom accessor.
6364
*/
6465

66+
static unsigned long global_flags;
67+
/*
68+
* Workaround for avoiding to use RX DMAC by multiple channels.
69+
* On R-Car H3 ES1.* and M3-W ES1.0, when multiple SDHI channels use
70+
* RX DMAC simultaneously, sometimes hundreds of bytes data are not
71+
* stored into the system memory even if the DMAC interrupt happened.
72+
* So, this driver then uses one RX DMAC channel only.
73+
*/
74+
#define SDHI_INTERNAL_DMAC_ONE_RX_ONLY 0
75+
#define SDHI_INTERNAL_DMAC_RX_IN_USE 1
76+
6577
/* Definitions for sampling clocks */
6678
static struct renesas_sdhi_scc rcar_gen3_scc_taps[] = {
6779
{
@@ -126,6 +138,9 @@ renesas_sdhi_internal_dmac_abort_dma(struct tmio_mmc_host *host) {
126138
renesas_sdhi_internal_dmac_dm_write(host, DM_CM_RST,
127139
RST_RESERVED_BITS | val);
128140

141+
if (host->data && host->data->flags & MMC_DATA_READ)
142+
clear_bit(SDHI_INTERNAL_DMAC_RX_IN_USE, &global_flags);
143+
129144
renesas_sdhi_internal_dmac_enable_dma(host, true);
130145
}
131146

@@ -155,6 +170,9 @@ renesas_sdhi_internal_dmac_start_dma(struct tmio_mmc_host *host,
155170
if (data->flags & MMC_DATA_READ) {
156171
dtran_mode |= DTRAN_MODE_CH_NUM_CH1;
157172
dir = DMA_FROM_DEVICE;
173+
if (test_bit(SDHI_INTERNAL_DMAC_ONE_RX_ONLY, &global_flags) &&
174+
test_and_set_bit(SDHI_INTERNAL_DMAC_RX_IN_USE, &global_flags))
175+
goto force_pio;
158176
} else {
159177
dtran_mode |= DTRAN_MODE_CH_NUM_CH0;
160178
dir = DMA_TO_DEVICE;
@@ -208,6 +226,9 @@ static void renesas_sdhi_internal_dmac_complete_tasklet_fn(unsigned long arg)
208226
renesas_sdhi_internal_dmac_enable_dma(host, false);
209227
dma_unmap_sg(&host->pdev->dev, host->sg_ptr, host->sg_len, dir);
210228

229+
if (dir == DMA_FROM_DEVICE)
230+
clear_bit(SDHI_INTERNAL_DMAC_RX_IN_USE, &global_flags);
231+
211232
tmio_mmc_do_data_irq(host);
212233
out:
213234
spin_unlock_irq(&host->lock);
@@ -251,18 +272,24 @@ static const struct tmio_mmc_dma_ops renesas_sdhi_internal_dmac_dma_ops = {
251272
* implementation as others may use a different implementation.
252273
*/
253274
static const struct soc_device_attribute gen3_soc_whitelist[] = {
254-
{ .soc_id = "r8a7795", .revision = "ES1.*" },
255-
{ .soc_id = "r8a7795", .revision = "ES2.0" },
256-
{ .soc_id = "r8a7796", .revision = "ES1.0" },
257-
{ .soc_id = "r8a77995", .revision = "ES1.0" },
258-
{ /* sentinel */ }
275+
{ .soc_id = "r8a7795", .revision = "ES1.*",
276+
.data = (void *)BIT(SDHI_INTERNAL_DMAC_ONE_RX_ONLY) },
277+
{ .soc_id = "r8a7795", .revision = "ES2.0" },
278+
{ .soc_id = "r8a7796", .revision = "ES1.0",
279+
.data = (void *)BIT(SDHI_INTERNAL_DMAC_ONE_RX_ONLY) },
280+
{ .soc_id = "r8a77995", .revision = "ES1.0" },
281+
{ /* sentinel */ }
259282
};
260283

261284
static int renesas_sdhi_internal_dmac_probe(struct platform_device *pdev)
262285
{
263-
if (!soc_device_match(gen3_soc_whitelist))
286+
const struct soc_device_attribute *soc = soc_device_match(gen3_soc_whitelist);
287+
288+
if (!soc)
264289
return -ENODEV;
265290

291+
global_flags |= (unsigned long)soc->data;
292+
266293
return renesas_sdhi_probe(pdev, &renesas_sdhi_internal_dmac_dma_ops);
267294
}
268295

0 commit comments

Comments
 (0)