| From 394a0049ae5cb846bb7727d6b9a920f01276c2a2 Mon Sep 17 00:00:00 2001 |
| From: Russell King <rmk+kernel@armlinux.org.uk> |
| Date: Sun, 22 Sep 2019 11:26:58 +0100 |
| Subject: [PATCH] mmc: sdhci-of-esdhc: set DMA snooping based on DMA coherence |
| |
| commit 121bd08b029e03404c451bb237729cdff76eafed upstream. |
| |
| We must not unconditionally set the DMA snoop bit; if the DMA API is |
| assuming that the device is not DMA coherent, and the device snoops the |
| CPU caches, the device can see stale cache lines brought in by |
| speculative prefetch. |
| |
| This leads to the device seeing stale data, potentially resulting in |
| corrupted data transfers. Commonly, this results in a descriptor fetch |
| error such as: |
| |
| mmc0: ADMA error |
| mmc0: sdhci: ============ SDHCI REGISTER DUMP =========== |
| mmc0: sdhci: Sys addr: 0x00000000 | Version: 0x00002202 |
| mmc0: sdhci: Blk size: 0x00000008 | Blk cnt: 0x00000001 |
| mmc0: sdhci: Argument: 0x00000000 | Trn mode: 0x00000013 |
| mmc0: sdhci: Present: 0x01f50008 | Host ctl: 0x00000038 |
| mmc0: sdhci: Power: 0x00000003 | Blk gap: 0x00000000 |
| mmc0: sdhci: Wake-up: 0x00000000 | Clock: 0x000040d8 |
| mmc0: sdhci: Timeout: 0x00000003 | Int stat: 0x00000001 |
| mmc0: sdhci: Int enab: 0x037f108f | Sig enab: 0x037f108b |
| mmc0: sdhci: ACmd stat: 0x00000000 | Slot int: 0x00002202 |
| mmc0: sdhci: Caps: 0x35fa0000 | Caps_1: 0x0000af00 |
| mmc0: sdhci: Cmd: 0x0000333a | Max curr: 0x00000000 |
| mmc0: sdhci: Resp[0]: 0x00000920 | Resp[1]: 0x001d8a33 |
| mmc0: sdhci: Resp[2]: 0x325b5900 | Resp[3]: 0x3f400e00 |
| mmc0: sdhci: Host ctl2: 0x00000000 |
| mmc0: sdhci: ADMA Err: 0x00000009 | ADMA Ptr: 0x000000236d43820c |
| mmc0: sdhci: ============================================ |
| mmc0: error -5 whilst initialising SD card |
| |
| but can lead to other errors, and potentially direct the SDHCI |
| controller to read/write data to other memory locations (e.g. if a valid |
| descriptor is visible to the device in a stale cache line.) |
| |
| Fix this by ensuring that the DMA snoop bit corresponds with the |
| behaviour of the DMA API. Since the driver currently only supports DT, |
| use of_dma_is_coherent(). Note that device_get_dma_attr() can not be |
| used as that risks re-introducing this bug if/when the driver is |
| converted to ACPI. |
| |
| Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk> |
| Acked-by: Adrian Hunter <adrian.hunter@intel.com> |
| Cc: stable@vger.kernel.org |
| Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org> |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c |
| index 68c5866f5c85..d25c70e861f5 100644 |
| --- a/drivers/mmc/host/sdhci-of-esdhc.c |
| +++ b/drivers/mmc/host/sdhci-of-esdhc.c |
| @@ -495,7 +495,12 @@ static int esdhc_of_enable_dma(struct sdhci_host *host) |
| dma_set_mask_and_coherent(dev, DMA_BIT_MASK(40)); |
| |
| value = sdhci_readl(host, ESDHC_DMA_SYSCTL); |
| - value |= ESDHC_DMA_SNOOP; |
| + |
| + if (of_dma_is_coherent(dev->of_node)) |
| + value |= ESDHC_DMA_SNOOP; |
| + else |
| + value &= ~ESDHC_DMA_SNOOP; |
| + |
| sdhci_writel(host, value, ESDHC_DMA_SYSCTL); |
| return 0; |
| } |
| -- |
| 2.7.4 |
| |