From ae93d8106bdb5926efef9222d553adb295ebce96 Mon Sep 17 00:00:00 2001 From: Bharat Kumar Reddy Gooty Date: Fri, 22 Nov 2019 15:13:09 -0800 Subject: [PATCH 01/17] drivers: mmc: rpmb: Use R1 response If the host has Broken R1B, use only R1 response type. Signed-off-by: Bharat Kumar Reddy Gooty Signed-off-by: Vladimir Olovyannikov --- drivers/mmc/rpmb.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/mmc/rpmb.c b/drivers/mmc/rpmb.c index 33371fe562..ee6dbe30db 100644 --- a/drivers/mmc/rpmb.c +++ b/drivers/mmc/rpmb.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include "mmc_private.h" @@ -91,6 +92,7 @@ static int mmc_rpmb_request(struct mmc *mmc, const struct s_rpmb *s, { struct mmc_cmd cmd = {0}; struct mmc_data data; + struct sdhci_host *host = mmc->priv; int ret; ret = mmc_set_blockcount(mmc, count, is_rel_write); @@ -105,6 +107,9 @@ static int mmc_rpmb_request(struct mmc *mmc, const struct s_rpmb *s, cmd.cmdarg = 0; cmd.resp_type = MMC_RSP_R1; + if (host->quirks & SDHCI_QUIRK_BROKEN_R1B) + cmd.resp_type = MMC_RSP_R1; + data.src = (const char *)s; data.blocks = 1; data.blocksize = MMC_MAX_BLOCK_LEN; From 4af6659605abd707da3acc9ea525514e999b7aef Mon Sep 17 00:00:00 2001 From: Jaehoon Chung Date: Fri, 17 Jan 2020 15:06:54 +0900 Subject: [PATCH 02/17] mmc: fix the build error when MMC_WRITE is disabled MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit erase_grp_size is used, when MMC_WRITE is enabled. - error: ‘struct mmc’ has no member named ‘erase_grp_size’ Signed-off-by: Jaehoon Chung Reviewed-by: Peng Fan --- drivers/mmc/mmc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index d43983d4a6..6a2b855435 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -1126,9 +1126,11 @@ int mmc_hwpart_config(struct mmc *mmc, ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1; +#if CONFIG_IS_ENABLED(MMC_WRITE) /* update erase group size to be high-capacity */ mmc->erase_grp_size = ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024; +#endif } From 54a78cbdbee41e2c4b6691f950c2bacf7a50723f Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Tue, 21 Jan 2020 18:42:05 +0900 Subject: [PATCH 03/17] mmc: sdhci-cadence: send tune request twice to work around errata Cadence sent out an errata report to their customers of this IP. This errata is not so severe, but the tune request should be sent twice to avoid the potential issue. Quote from the report: Problem Summary --------------- The IP6116 SD/eMMC PHY design has a timing issue on receive data path. This issue may lead to an incorrect values of read/write pointers of the synchronization FIFO. Such a situation can happen at the SDR104 and HS200 tuning procedure when the PHY is requested to change a phase of sampling clock when moving to the next tuning iteration. Workarounds ----------- The following are valid workarounds to resolve the issue: 1. In eMMC mode, software sends tune request twice instead of once at each iteration. This means that the clock phase is not changed on the second request so there is no potential for clock instability. 2. In SD mode, software must not use the hardware tuning and instead perform an almost identical procedure to eMMC, using the HRS34 Tune Force register. Signed-off-by: Masahiro Yamada --- drivers/mmc/sdhci-cadence.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/drivers/mmc/sdhci-cadence.c b/drivers/mmc/sdhci-cadence.c index e9108dabd1..2d38c2270e 100644 --- a/drivers/mmc/sdhci-cadence.c +++ b/drivers/mmc/sdhci-cadence.c @@ -171,6 +171,7 @@ static int sdhci_cdns_set_tune_val(struct sdhci_cdns_plat *plat, { void __iomem *reg = plat->hrs_addr + SDHCI_CDNS_HRS06; u32 tmp; + int i, ret; if (WARN_ON(!FIELD_FIT(SDHCI_CDNS_HRS06_TUNE, val))) return -EINVAL; @@ -178,11 +179,23 @@ static int sdhci_cdns_set_tune_val(struct sdhci_cdns_plat *plat, tmp = readl(reg); tmp &= ~SDHCI_CDNS_HRS06_TUNE; tmp |= FIELD_PREP(SDHCI_CDNS_HRS06_TUNE, val); - tmp |= SDHCI_CDNS_HRS06_TUNE_UP; - writel(tmp, reg); - return readl_poll_timeout(reg, tmp, !(tmp & SDHCI_CDNS_HRS06_TUNE_UP), - 1); + /* + * Workaround for IP errata: + * The IP6116 SD/eMMC PHY design has a timing issue on receive data + * path. Send tune request twice. + */ + for (i = 0; i < 2; i++) { + tmp |= SDHCI_CDNS_HRS06_TUNE_UP; + writel(tmp, reg); + + ret = readl_poll_timeout(reg, tmp, + !(tmp & SDHCI_CDNS_HRS06_TUNE_UP), 1); + if (ret) + return ret; + } + + return 0; } static int __maybe_unused sdhci_cdns_execute_tuning(struct udevice *dev, From 8adf50effeda52bb84b2c2aa66bcebf2920778e9 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Thu, 23 Jan 2020 14:31:12 +0900 Subject: [PATCH 04/17] mmc: check the return value of mmc_select_mode_and_width() Since commit 01298da31d92 ("mmc: Change mode when switching to a boot partition"), errors in mmc_select_mode_and_width() are ignored. The return value should be checked. Fixes: 01298da31d92 ("mmc: Change mode when switching to a boot partition") Signed-off-by: Masahiro Yamada Reviewed-by: Jaehoon Chung --- drivers/mmc/mmc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 6a2b855435..2eb5e9d7aa 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -2577,7 +2577,7 @@ static int mmc_startup(struct mmc *mmc) err = mmc_get_capabilities(mmc); if (err) return err; - mmc_select_mode_and_width(mmc, mmc->card_caps); + err = mmc_select_mode_and_width(mmc, mmc->card_caps); } #endif if (err) From 76ca2d13035c8e649866546abc122cf46ed4e598 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Thu, 23 Jan 2020 15:54:01 +0900 Subject: [PATCH 05/17] mmc: remove unneeded forward declarations These functions are defined before the callers. Signed-off-by: Masahiro Yamada Reviewed-by: Peng Fan --- drivers/mmc/mmc.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 2eb5e9d7aa..b50fcbf6cf 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -24,10 +24,6 @@ #define DEFAULT_CMD6_TIMEOUT_MS 500 static int mmc_set_signal_voltage(struct mmc *mmc, uint signal_voltage); -static int mmc_power_cycle(struct mmc *mmc); -#if !CONFIG_IS_ENABLED(MMC_TINY) -static int mmc_select_mode_and_width(struct mmc *mmc, uint card_caps); -#endif #if !CONFIG_IS_ENABLED(DM_MMC) From ede2822864c3145859372f4ad1b82f4c98584128 Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Thu, 30 Jan 2020 12:06:45 +0000 Subject: [PATCH 06/17] mmc: fsl_esdhc: actually enable cache snooping on mpc830x The reference manuals for MPC8308 and MPC8309 both say that the esdhcctl aka DMA Control Register "is implemented as SDHCCR" in the System configuration registers. Unfortunately, that doesn't mean that the registers are just mirrors of each other - any write to esdhcctl is simply ignored. So to actually enable cache snooping, we unfortunately have to add a little ifdeffery. There is, naturally, no description of the bit fields of esdhcctl in the MPC8309 manual, but comparing the description of esdhcctl from the LS1021A reference manual to the description of the sdhccr in MPC8309, one also finds that the fields are bit-reversed, so the bit to set is 0x02000000 rather than 0x00000040 - this is also what board_mmc_init() uses in the two gdsys/mpc8308/ boards. Signed-off-by: Rasmus Villemoes Reviewed-by: Yangbo Lu --- drivers/mmc/fsl_esdhc.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/fsl_esdhc.c b/drivers/mmc/fsl_esdhc.c index ab40019ccb..386781da03 100644 --- a/drivers/mmc/fsl_esdhc.c +++ b/drivers/mmc/fsl_esdhc.c @@ -578,6 +578,18 @@ static int esdhc_set_ios_common(struct fsl_esdhc_priv *priv, struct mmc *mmc) return 0; } +static void esdhc_enable_cache_snooping(struct fsl_esdhc *regs) +{ +#ifdef CONFIG_ARCH_MPC830X + immap_t *immr = (immap_t *)CONFIG_SYS_IMMR; + sysconf83xx_t *sysconf = &immr->sysconf; + + setbits_be32(&sysconf->sdhccr, 0x02000000); +#else + esdhc_write32(®s->esdhcctl, 0x00000040); +#endif +} + static int esdhc_init_common(struct fsl_esdhc_priv *priv, struct mmc *mmc) { struct fsl_esdhc *regs = priv->esdhc_regs; @@ -593,8 +605,7 @@ static int esdhc_init_common(struct fsl_esdhc_priv *priv, struct mmc *mmc) return -ETIMEDOUT; } - /* Enable cache snooping */ - esdhc_write32(®s->esdhcctl, 0x00000040); + esdhc_enable_cache_snooping(regs); esdhc_setbits32(®s->sysctl, SYSCTL_HCKEN | SYSCTL_IPGEN); From c22c0dbd7d3bb7ce47779b757d567d2e7746744b Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 14 Feb 2020 16:40:17 +0900 Subject: [PATCH 07/17] dma-mapping: fix the prototype of dma_map_single() Make dma_map_single() return the dma address, and remove the pointless volatile. Signed-off-by: Masahiro Yamada --- arch/arm/include/asm/dma-mapping.h | 5 +++-- arch/nds32/include/asm/dma-mapping.h | 5 +++-- arch/riscv/include/asm/dma-mapping.h | 5 +++-- arch/x86/include/asm/dma-mapping.h | 5 +++-- 4 files changed, 12 insertions(+), 8 deletions(-) diff --git a/arch/arm/include/asm/dma-mapping.h b/arch/arm/include/asm/dma-mapping.h index d20703739f..d0895a2096 100644 --- a/arch/arm/include/asm/dma-mapping.h +++ b/arch/arm/include/asm/dma-mapping.h @@ -11,6 +11,7 @@ #include #include #include +#include #include #define dma_mapping_error(x, y) 0 @@ -26,8 +27,8 @@ static inline void dma_free_coherent(void *addr) free(addr); } -static inline unsigned long dma_map_single(volatile void *vaddr, size_t len, - enum dma_data_direction dir) +static inline dma_addr_t dma_map_single(void *vaddr, size_t len, + enum dma_data_direction dir) { unsigned long addr = (unsigned long)vaddr; diff --git a/arch/nds32/include/asm/dma-mapping.h b/arch/nds32/include/asm/dma-mapping.h index c8876ceadd..9387dec347 100644 --- a/arch/nds32/include/asm/dma-mapping.h +++ b/arch/nds32/include/asm/dma-mapping.h @@ -10,6 +10,7 @@ #include #include #include +#include #include static void *dma_alloc_coherent(size_t len, unsigned long *handle) @@ -18,8 +19,8 @@ static void *dma_alloc_coherent(size_t len, unsigned long *handle) return (void *)*handle; } -static inline unsigned long dma_map_single(volatile void *vaddr, size_t len, - enum dma_data_direction dir) +static inline dma_addr_t dma_map_single(void *vaddr, size_t len, + enum dma_data_direction dir) { unsigned long addr = (unsigned long)vaddr; diff --git a/arch/riscv/include/asm/dma-mapping.h b/arch/riscv/include/asm/dma-mapping.h index 6cc3946959..eac56f8fbd 100644 --- a/arch/riscv/include/asm/dma-mapping.h +++ b/arch/riscv/include/asm/dma-mapping.h @@ -10,6 +10,7 @@ #define __ASM_RISCV_DMA_MAPPING_H #include +#include #include #include #include @@ -28,8 +29,8 @@ static inline void dma_free_coherent(void *addr) free(addr); } -static inline unsigned long dma_map_single(volatile void *vaddr, size_t len, - enum dma_data_direction dir) +static inline dma_addr_t dma_map_single(void *vaddr, size_t len, + enum dma_data_direction dir) { unsigned long addr = (unsigned long)vaddr; diff --git a/arch/x86/include/asm/dma-mapping.h b/arch/x86/include/asm/dma-mapping.h index 900b99b8a6..7e205e3313 100644 --- a/arch/x86/include/asm/dma-mapping.h +++ b/arch/x86/include/asm/dma-mapping.h @@ -11,6 +11,7 @@ #include #include #include +#include #include #define dma_mapping_error(x, y) 0 @@ -26,8 +27,8 @@ static inline void dma_free_coherent(void *addr) free(addr); } -static inline unsigned long dma_map_single(volatile void *vaddr, size_t len, - enum dma_data_direction dir) +static inline dma_addr_t dma_map_single(void *vaddr, size_t len, + enum dma_data_direction dir) { unsigned long addr = (unsigned long)vaddr; From 950c5968672a22a65790534234d1106bd1303652 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 14 Feb 2020 16:40:18 +0900 Subject: [PATCH 08/17] dma-mapping: fix the prototype of dma_unmap_single() dma_unmap_single() takes the dma address, not virtual address. Signed-off-by: Masahiro Yamada --- arch/arm/include/asm/dma-mapping.h | 4 +--- arch/nds32/include/asm/dma-mapping.h | 4 +--- arch/riscv/include/asm/dma-mapping.h | 4 +--- arch/x86/include/asm/dma-mapping.h | 4 +--- drivers/mmc/tmio-common.c | 2 +- drivers/mtd/nand/raw/denali.c | 2 +- drivers/net/macb.c | 2 +- drivers/usb/dwc3/core.c | 6 +++--- drivers/usb/gadget/udc/udc-core.c | 2 +- 9 files changed, 11 insertions(+), 19 deletions(-) diff --git a/arch/arm/include/asm/dma-mapping.h b/arch/arm/include/asm/dma-mapping.h index d0895a2096..efdbed7280 100644 --- a/arch/arm/include/asm/dma-mapping.h +++ b/arch/arm/include/asm/dma-mapping.h @@ -42,11 +42,9 @@ static inline dma_addr_t dma_map_single(void *vaddr, size_t len, return addr; } -static inline void dma_unmap_single(volatile void *vaddr, size_t len, +static inline void dma_unmap_single(dma_addr_t addr, size_t len, enum dma_data_direction dir) { - unsigned long addr = (unsigned long)vaddr; - len = ALIGN(len, ARCH_DMA_MINALIGN); if (dir != DMA_TO_DEVICE) diff --git a/arch/nds32/include/asm/dma-mapping.h b/arch/nds32/include/asm/dma-mapping.h index 9387dec347..784f489db5 100644 --- a/arch/nds32/include/asm/dma-mapping.h +++ b/arch/nds32/include/asm/dma-mapping.h @@ -34,11 +34,9 @@ static inline dma_addr_t dma_map_single(void *vaddr, size_t len, return addr; } -static inline void dma_unmap_single(volatile void *vaddr, size_t len, +static inline void dma_unmap_single(dma_addr_t addr, size_t len, enum dma_data_direction dir) { - unsigned long addr = (unsigned long)vaddr; - len = ALIGN(len, ARCH_DMA_MINALIGN); if (dir != DMA_TO_DEVICE) diff --git a/arch/riscv/include/asm/dma-mapping.h b/arch/riscv/include/asm/dma-mapping.h index eac56f8fbd..1ac4a4fed5 100644 --- a/arch/riscv/include/asm/dma-mapping.h +++ b/arch/riscv/include/asm/dma-mapping.h @@ -44,11 +44,9 @@ static inline dma_addr_t dma_map_single(void *vaddr, size_t len, return addr; } -static inline void dma_unmap_single(volatile void *vaddr, size_t len, +static inline void dma_unmap_single(dma_addr_t addr, size_t len, enum dma_data_direction dir) { - unsigned long addr = (unsigned long)vaddr; - len = ALIGN(len, ARCH_DMA_MINALIGN); if (dir != DMA_TO_DEVICE) diff --git a/arch/x86/include/asm/dma-mapping.h b/arch/x86/include/asm/dma-mapping.h index 7e205e3313..37704da5dd 100644 --- a/arch/x86/include/asm/dma-mapping.h +++ b/arch/x86/include/asm/dma-mapping.h @@ -42,11 +42,9 @@ static inline dma_addr_t dma_map_single(void *vaddr, size_t len, return addr; } -static inline void dma_unmap_single(volatile void *vaddr, size_t len, +static inline void dma_unmap_single(dma_addr_t addr, size_t len, enum dma_data_direction dir) { - unsigned long addr = (unsigned long)vaddr; - len = ALIGN(len, ARCH_DMA_MINALIGN); if (dir != DMA_TO_DEVICE) diff --git a/drivers/mmc/tmio-common.c b/drivers/mmc/tmio-common.c index 092b740f56..5321388847 100644 --- a/drivers/mmc/tmio-common.c +++ b/drivers/mmc/tmio-common.c @@ -353,7 +353,7 @@ static int tmio_sd_dma_xfer(struct udevice *dev, struct mmc_data *data) if (poll_flag == TMIO_SD_DMA_INFO1_END_RD) udelay(1); - dma_unmap_single(buf, len, dir); + dma_unmap_single(dma_addr, len, dir); return ret; } diff --git a/drivers/mtd/nand/raw/denali.c b/drivers/mtd/nand/raw/denali.c index f51d3e25c7..3e0ac39777 100644 --- a/drivers/mtd/nand/raw/denali.c +++ b/drivers/mtd/nand/raw/denali.c @@ -581,7 +581,7 @@ static int denali_dma_xfer(struct denali_nand_info *denali, void *buf, iowrite32(0, denali->reg + DMA_ENABLE); - dma_unmap_single(buf, size, dir); + dma_unmap_single(dma_addr, size, dir); if (irq_status & INTR__ERASED_PAGE) memset(buf, 0xff, size); diff --git a/drivers/net/macb.c b/drivers/net/macb.c index 0d4929bec1..7a2b1abeeb 100644 --- a/drivers/net/macb.c +++ b/drivers/net/macb.c @@ -342,7 +342,7 @@ static int _macb_send(struct macb_device *macb, const char *name, void *packet, udelay(1); } - dma_unmap_single(packet, length, DMA_TO_DEVICE); + dma_unmap_single(paddr, length, DMA_TO_DEVICE); if (i <= MACB_TX_TIMEOUT) { if (ctrl & MACB_BIT(TX_UNDERRUN)) diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index c5066529b7..6ad1000c9a 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -288,8 +288,8 @@ static int dwc3_setup_scratch_buffers(struct dwc3 *dwc) return 0; err1: - dma_unmap_single((void *)(uintptr_t)dwc->scratch_addr, dwc->nr_scratch * - DWC3_SCRATCHBUF_SIZE, DMA_BIDIRECTIONAL); + dma_unmap_single(scratch_addr, dwc->nr_scratch * DWC3_SCRATCHBUF_SIZE, + DMA_BIDIRECTIONAL); err0: return ret; @@ -303,7 +303,7 @@ static void dwc3_free_scratch_buffers(struct dwc3 *dwc) if (!dwc->nr_scratch) return; - dma_unmap_single((void *)(uintptr_t)dwc->scratch_addr, dwc->nr_scratch * + dma_unmap_single(dwc->scratch_addr, dwc->nr_scratch * DWC3_SCRATCHBUF_SIZE, DMA_BIDIRECTIONAL); kfree(dwc->scratchbuf); } diff --git a/drivers/usb/gadget/udc/udc-core.c b/drivers/usb/gadget/udc/udc-core.c index a33ab5c95d..528874507b 100644 --- a/drivers/usb/gadget/udc/udc-core.c +++ b/drivers/usb/gadget/udc/udc-core.c @@ -67,7 +67,7 @@ void usb_gadget_unmap_request(struct usb_gadget *gadget, if (req->length == 0) return; - dma_unmap_single((void *)(uintptr_t)req->dma, req->length, + dma_unmap_single(req->dma, req->length, is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE); } EXPORT_SYMBOL_GPL(usb_gadget_unmap_request); From 9d86b89c590832c9bcb1c69d5ccdecdf731f97ae Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 14 Feb 2020 16:40:19 +0900 Subject: [PATCH 09/17] dma-mapping: move dma_map_(un)single() to The implementation of dma_map_single() and dma_unmap_single() is exactly the same for all the architectures that support them. Factor them out to , and make all drivers to include instead of . If we need to differentiate them for some architectures, we can move the generic definitions to . Add some comments to the helpers. The concept is quite similar to the DMA-API of Linux kernel. Drivers are agnostic about what is going on behind the scene. Just call dma_map_single() before the DMA, and dma_unmap_single() after it. Signed-off-by: Masahiro Yamada --- arch/arm/include/asm/dma-mapping.h | 26 ------------ arch/nds32/include/asm/dma-mapping.h | 24 ----------- arch/riscv/include/asm/dma-mapping.h | 26 ------------ arch/x86/include/asm/dma-mapping.h | 26 ------------ drivers/dma/ti/k3-udma.c | 2 +- drivers/mmc/tmio-common.c | 3 +- drivers/mtd/nand/raw/denali.c | 3 +- drivers/net/altera_tse.c | 2 +- drivers/net/ftmac110.c | 2 +- drivers/net/macb.c | 2 +- drivers/soc/ti/k3-navss-ringacc.c | 2 +- drivers/ufs/ufs.c | 2 +- drivers/usb/cdns3/gadget.c | 2 +- drivers/usb/dwc3/core.c | 2 +- drivers/usb/dwc3/gadget.c | 2 +- drivers/usb/gadget/udc/udc-core.c | 2 +- include/linux/dma-mapping.h | 63 ++++++++++++++++++++++++++++ 17 files changed, 75 insertions(+), 116 deletions(-) create mode 100644 include/linux/dma-mapping.h diff --git a/arch/arm/include/asm/dma-mapping.h b/arch/arm/include/asm/dma-mapping.h index efdbed7280..8bb3fa2e0e 100644 --- a/arch/arm/include/asm/dma-mapping.h +++ b/arch/arm/include/asm/dma-mapping.h @@ -14,8 +14,6 @@ #include #include -#define dma_mapping_error(x, y) 0 - static inline void *dma_alloc_coherent(size_t len, unsigned long *handle) { *handle = (unsigned long)memalign(ARCH_DMA_MINALIGN, ROUND(len, ARCH_DMA_MINALIGN)); @@ -27,28 +25,4 @@ static inline void dma_free_coherent(void *addr) free(addr); } -static inline dma_addr_t dma_map_single(void *vaddr, size_t len, - enum dma_data_direction dir) -{ - unsigned long addr = (unsigned long)vaddr; - - len = ALIGN(len, ARCH_DMA_MINALIGN); - - if (dir == DMA_FROM_DEVICE) - invalidate_dcache_range(addr, addr + len); - else - flush_dcache_range(addr, addr + len); - - return addr; -} - -static inline void dma_unmap_single(dma_addr_t addr, size_t len, - enum dma_data_direction dir) -{ - len = ALIGN(len, ARCH_DMA_MINALIGN); - - if (dir != DMA_TO_DEVICE) - invalidate_dcache_range(addr, addr + len); -} - #endif /* __ASM_ARM_DMA_MAPPING_H */ diff --git a/arch/nds32/include/asm/dma-mapping.h b/arch/nds32/include/asm/dma-mapping.h index 784f489db5..f8668f1fe5 100644 --- a/arch/nds32/include/asm/dma-mapping.h +++ b/arch/nds32/include/asm/dma-mapping.h @@ -19,28 +19,4 @@ static void *dma_alloc_coherent(size_t len, unsigned long *handle) return (void *)*handle; } -static inline dma_addr_t dma_map_single(void *vaddr, size_t len, - enum dma_data_direction dir) -{ - unsigned long addr = (unsigned long)vaddr; - - len = ALIGN(len, ARCH_DMA_MINALIGN); - - if (dir == DMA_FROM_DEVICE) - invalidate_dcache_range(addr, addr + len); - else - flush_dcache_range(addr, addr + len); - - return addr; -} - -static inline void dma_unmap_single(dma_addr_t addr, size_t len, - enum dma_data_direction dir) -{ - len = ALIGN(len, ARCH_DMA_MINALIGN); - - if (dir != DMA_TO_DEVICE) - invalidate_dcache_range(addr, addr + len); -} - #endif /* __ASM_NDS_DMA_MAPPING_H */ diff --git a/arch/riscv/include/asm/dma-mapping.h b/arch/riscv/include/asm/dma-mapping.h index 1ac4a4fed5..6ecadab41c 100644 --- a/arch/riscv/include/asm/dma-mapping.h +++ b/arch/riscv/include/asm/dma-mapping.h @@ -16,8 +16,6 @@ #include #include -#define dma_mapping_error(x, y) 0 - static inline void *dma_alloc_coherent(size_t len, unsigned long *handle) { *handle = (unsigned long)memalign(ARCH_DMA_MINALIGN, len); @@ -29,28 +27,4 @@ static inline void dma_free_coherent(void *addr) free(addr); } -static inline dma_addr_t dma_map_single(void *vaddr, size_t len, - enum dma_data_direction dir) -{ - unsigned long addr = (unsigned long)vaddr; - - len = ALIGN(len, ARCH_DMA_MINALIGN); - - if (dir == DMA_FROM_DEVICE) - invalidate_dcache_range(addr, addr + len); - else - flush_dcache_range(addr, addr + len); - - return addr; -} - -static inline void dma_unmap_single(dma_addr_t addr, size_t len, - enum dma_data_direction dir) -{ - len = ALIGN(len, ARCH_DMA_MINALIGN); - - if (dir != DMA_TO_DEVICE) - invalidate_dcache_range(addr, addr + len); -} - #endif /* __ASM_RISCV_DMA_MAPPING_H */ diff --git a/arch/x86/include/asm/dma-mapping.h b/arch/x86/include/asm/dma-mapping.h index 37704da5dd..8be1003e6b 100644 --- a/arch/x86/include/asm/dma-mapping.h +++ b/arch/x86/include/asm/dma-mapping.h @@ -14,8 +14,6 @@ #include #include -#define dma_mapping_error(x, y) 0 - static inline void *dma_alloc_coherent(size_t len, unsigned long *handle) { *handle = (unsigned long)memalign(ARCH_DMA_MINALIGN, len); @@ -27,28 +25,4 @@ static inline void dma_free_coherent(void *addr) free(addr); } -static inline dma_addr_t dma_map_single(void *vaddr, size_t len, - enum dma_data_direction dir) -{ - unsigned long addr = (unsigned long)vaddr; - - len = ALIGN(len, ARCH_DMA_MINALIGN); - - if (dir == DMA_FROM_DEVICE) - invalidate_dcache_range(addr, addr + len); - else - flush_dcache_range(addr, addr + len); - - return addr; -} - -static inline void dma_unmap_single(dma_addr_t addr, size_t len, - enum dma_data_direction dir) -{ - len = ALIGN(len, ARCH_DMA_MINALIGN); - - if (dir != DMA_TO_DEVICE) - invalidate_dcache_range(addr, addr + len); -} - #endif /* __ASM_X86_DMA_MAPPING_H */ diff --git a/drivers/dma/ti/k3-udma.c b/drivers/dma/ti/k3-udma.c index f274100f32..e587f1fcb2 100644 --- a/drivers/dma/ti/k3-udma.c +++ b/drivers/dma/ti/k3-udma.c @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/mmc/tmio-common.c b/drivers/mmc/tmio-common.c index 5321388847..faf18191b3 100644 --- a/drivers/mmc/tmio-common.c +++ b/drivers/mmc/tmio-common.c @@ -4,7 +4,6 @@ * Author: Masahiro Yamada */ -#include #include #include #include @@ -14,7 +13,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/mtd/nand/raw/denali.c b/drivers/mtd/nand/raw/denali.c index 3e0ac39777..b525b1be54 100644 --- a/drivers/mtd/nand/raw/denali.c +++ b/drivers/mtd/nand/raw/denali.c @@ -5,14 +5,13 @@ * Copyright (C) 2009-2010, Intel Corporation and its suppliers. */ -#include #include #include #include #include #include #include -#include +#include #include #include #include diff --git a/drivers/net/altera_tse.c b/drivers/net/altera_tse.c index aabddd6bb6..a511068d9a 100644 --- a/drivers/net/altera_tse.c +++ b/drivers/net/altera_tse.c @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include "altera_tse.h" diff --git a/drivers/net/ftmac110.c b/drivers/net/ftmac110.c index 1fa93d4d58..84082407d2 100644 --- a/drivers/net/ftmac110.c +++ b/drivers/net/ftmac110.c @@ -12,7 +12,7 @@ #include #include #include -#include +#include #if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) #include diff --git a/drivers/net/macb.c b/drivers/net/macb.c index 7a2b1abeeb..631b53b093 100644 --- a/drivers/net/macb.c +++ b/drivers/net/macb.c @@ -38,7 +38,7 @@ #include #include -#include +#include #include #include diff --git a/drivers/soc/ti/k3-navss-ringacc.c b/drivers/soc/ti/k3-navss-ringacc.c index 8cbfe2bf49..c5661c52fa 100644 --- a/drivers/soc/ti/k3-navss-ringacc.c +++ b/drivers/soc/ti/k3-navss-ringacc.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include @@ -17,6 +16,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/ufs/ufs.c b/drivers/ufs/ufs.c index c9346c2edc..24e1bc2a19 100644 --- a/drivers/ufs/ufs.c +++ b/drivers/ufs/ufs.c @@ -19,7 +19,7 @@ #include #include -#include +#include #include "ufs.h" diff --git a/drivers/usb/cdns3/gadget.c b/drivers/usb/cdns3/gadget.c index 22e90a5717..8377eb458b 100644 --- a/drivers/usb/cdns3/gadget.c +++ b/drivers/usb/cdns3/gadget.c @@ -63,7 +63,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 6ad1000c9a..4ec3f6df6a 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -17,9 +17,9 @@ #include #include #include -#include #include #include +#include #include #include #include diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 1502d67362..e445c705f1 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -16,10 +16,10 @@ #include #include #include -#include #include #include #include +#include #include #include diff --git a/drivers/usb/gadget/udc/udc-core.c b/drivers/usb/gadget/udc/udc-core.c index 528874507b..7f73926cb3 100644 --- a/drivers/usb/gadget/udc/udc-core.c +++ b/drivers/usb/gadget/udc/udc-core.c @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/include/linux/dma-mapping.h b/include/linux/dma-mapping.h new file mode 100644 index 0000000000..20b6d60dd8 --- /dev/null +++ b/include/linux/dma-mapping.h @@ -0,0 +1,63 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _LINUX_DMA_MAPPING_H +#define _LINUX_DMA_MAPPING_H + +#include +#include +#include +#include + +#define dma_mapping_error(x, y) 0 + +/** + * Map a buffer to make it available to the DMA device + * + * Linux-like DMA API that is intended to be used from drivers. This hides the + * underlying cache operation from drivers. Call this before starting the DMA + * transfer. In most of architectures in U-Boot, the virtual address matches to + * the physical address (but we have exceptions like sandbox). U-Boot does not + * support iommu at the driver level, so it also matches to the DMA address. + * Hence, this helper currently just performs the cache operation, then returns + * straight-mapped dma_address, which is intended to be set to the register of + * the DMA device. + * + * @vaddr: address of the buffer + * @len: length of the buffer + * @dir: the direction of DMA + */ +static inline dma_addr_t dma_map_single(void *vaddr, size_t len, + enum dma_data_direction dir) +{ + unsigned long addr = (unsigned long)vaddr; + + len = ALIGN(len, ARCH_DMA_MINALIGN); + + if (dir == DMA_FROM_DEVICE) + invalidate_dcache_range(addr, addr + len); + else + flush_dcache_range(addr, addr + len); + + return addr; +} + +/** + * Unmap a buffer to make it available to CPU + * + * Linux-like DMA API that is intended to be used from drivers. This hides the + * underlying cache operation from drivers. Call this after finishin the DMA + * transfer. + * + * @addr: DMA address + * @len: length of the buffer + * @dir: the direction of DMA + */ +static inline void dma_unmap_single(dma_addr_t addr, size_t len, + enum dma_data_direction dir) +{ + len = ALIGN(len, ARCH_DMA_MINALIGN); + + if (dir != DMA_TO_DEVICE) + invalidate_dcache_range(addr, addr + len); +} + +#endif From 057516308a0a1892a54f16bce0577c9dcccc4857 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Thu, 20 Feb 2020 14:15:37 +0900 Subject: [PATCH 10/17] dma-mapping: add for all architectures To avoid "asm/dma-mapping.h: No such file or directory" error, we need something. Signed-off-by: Masahiro Yamada --- arch/arc/include/asm/dma-mapping.h | 1 + arch/m68k/include/asm/dma-mapping.h | 1 + arch/microblaze/include/asm/dma-mapping.h | 1 + arch/mips/include/asm/dma-mapping.h | 1 + arch/powerpc/include/asm/dma-mapping.h | 1 + arch/sandbox/include/asm/dma-mapping.h | 1 + arch/sh/include/asm/dma-mapping.h | 1 + arch/xtensa/include/asm/dma-mapping.h | 1 + 8 files changed, 8 insertions(+) create mode 100644 arch/arc/include/asm/dma-mapping.h create mode 100644 arch/m68k/include/asm/dma-mapping.h create mode 100644 arch/microblaze/include/asm/dma-mapping.h create mode 100644 arch/mips/include/asm/dma-mapping.h create mode 100644 arch/powerpc/include/asm/dma-mapping.h create mode 100644 arch/sandbox/include/asm/dma-mapping.h create mode 100644 arch/sh/include/asm/dma-mapping.h create mode 100644 arch/xtensa/include/asm/dma-mapping.h diff --git a/arch/arc/include/asm/dma-mapping.h b/arch/arc/include/asm/dma-mapping.h new file mode 100644 index 0000000000..853b0877b3 --- /dev/null +++ b/arch/arc/include/asm/dma-mapping.h @@ -0,0 +1 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ diff --git a/arch/m68k/include/asm/dma-mapping.h b/arch/m68k/include/asm/dma-mapping.h new file mode 100644 index 0000000000..853b0877b3 --- /dev/null +++ b/arch/m68k/include/asm/dma-mapping.h @@ -0,0 +1 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ diff --git a/arch/microblaze/include/asm/dma-mapping.h b/arch/microblaze/include/asm/dma-mapping.h new file mode 100644 index 0000000000..853b0877b3 --- /dev/null +++ b/arch/microblaze/include/asm/dma-mapping.h @@ -0,0 +1 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ diff --git a/arch/mips/include/asm/dma-mapping.h b/arch/mips/include/asm/dma-mapping.h new file mode 100644 index 0000000000..853b0877b3 --- /dev/null +++ b/arch/mips/include/asm/dma-mapping.h @@ -0,0 +1 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ diff --git a/arch/powerpc/include/asm/dma-mapping.h b/arch/powerpc/include/asm/dma-mapping.h new file mode 100644 index 0000000000..853b0877b3 --- /dev/null +++ b/arch/powerpc/include/asm/dma-mapping.h @@ -0,0 +1 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ diff --git a/arch/sandbox/include/asm/dma-mapping.h b/arch/sandbox/include/asm/dma-mapping.h new file mode 100644 index 0000000000..853b0877b3 --- /dev/null +++ b/arch/sandbox/include/asm/dma-mapping.h @@ -0,0 +1 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ diff --git a/arch/sh/include/asm/dma-mapping.h b/arch/sh/include/asm/dma-mapping.h new file mode 100644 index 0000000000..853b0877b3 --- /dev/null +++ b/arch/sh/include/asm/dma-mapping.h @@ -0,0 +1 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ diff --git a/arch/xtensa/include/asm/dma-mapping.h b/arch/xtensa/include/asm/dma-mapping.h new file mode 100644 index 0000000000..853b0877b3 --- /dev/null +++ b/arch/xtensa/include/asm/dma-mapping.h @@ -0,0 +1 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ From c8cc18b7a7e05da529a3365bfa463e5c5c83efe8 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 14 Feb 2020 16:40:21 +0900 Subject: [PATCH 11/17] mmc: sdhci: put the aligned buffer pointer to struct sdhci_host Using the global variable does not look nice. Add a new field sthci::align_buffer to point to the bounce buffer. Signed-off-by: Masahiro Yamada Reviewed-by: Jaehoon Chung --- drivers/mmc/sdhci.c | 27 +++++++++++++-------------- include/sdhci.h | 1 + 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c index 01fa5a9d4d..18fbcb5f18 100644 --- a/drivers/mmc/sdhci.c +++ b/drivers/mmc/sdhci.c @@ -16,12 +16,6 @@ #include #include -#if defined(CONFIG_FIXED_SDHCI_ALIGNED_BUFFER) -void *aligned_buffer = (void *)CONFIG_FIXED_SDHCI_ALIGNED_BUFFER; -#else -void *aligned_buffer; -#endif - static void sdhci_reset(struct sdhci_host *host, u8 mask) { unsigned long timeout; @@ -149,9 +143,10 @@ static void sdhci_prepare_dma(struct sdhci_host *host, struct mmc_data *data, if ((host->quirks & SDHCI_QUIRK_32BIT_DMA_ADDR) && (host->start_addr & 0x7) != 0x0) { *is_aligned = 0; - host->start_addr = (unsigned long)aligned_buffer; + host->start_addr = (unsigned long)host->align_buffer; if (data->flags != MMC_DATA_READ) - memcpy(aligned_buffer, data->src, trans_bytes); + memcpy(host->align_buffer, data->src, + trans_bytes); } #if defined(CONFIG_FIXED_SDHCI_ALIGNED_BUFFER) @@ -160,9 +155,9 @@ static void sdhci_prepare_dma(struct sdhci_host *host, struct mmc_data *data, * CONFIG_FIXED_SDHCI_ALIGNED_BUFFER is defined */ *is_aligned = 0; - host->start_addr = (unsigned long)aligned_buffer; + host->start_addr = (unsigned long)host->align_buffer; if (data->flags != MMC_DATA_READ) - memcpy(aligned_buffer, data->src, trans_bytes); + memcpy(host->align_buffer, data->src, trans_bytes); #endif sdhci_writel(host, host->start_addr, SDHCI_DMA_ADDRESS); @@ -381,7 +376,7 @@ static int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd, if (!ret) { if ((host->quirks & SDHCI_QUIRK_32BIT_DMA_ADDR) && !is_aligned && (data->flags == MMC_DATA_READ)) - memcpy(data->dest, aligned_buffer, trans_bytes); + memcpy(data->dest, host->align_buffer, trans_bytes); return 0; } @@ -630,14 +625,18 @@ static int sdhci_init(struct mmc *mmc) sdhci_reset(host, SDHCI_RESET_ALL); - if ((host->quirks & SDHCI_QUIRK_32BIT_DMA_ADDR) && !aligned_buffer) { - aligned_buffer = memalign(8, 512*1024); - if (!aligned_buffer) { +#if defined(CONFIG_FIXED_SDHCI_ALIGNED_BUFFER) + host->align_buffer = (void *)CONFIG_FIXED_SDHCI_ALIGNED_BUFFER; +#else + if (host->quirks & SDHCI_QUIRK_32BIT_DMA_ADDR) { + host->align_buffer = memalign(8, 512 * 1024); + if (!host->align_buffer) { printf("%s: Aligned buffer alloc failed!!!\n", __func__); return -ENOMEM; } } +#endif sdhci_set_power(host, fls(mmc->cfg->voltages) - 1); diff --git a/include/sdhci.h b/include/sdhci.h index 01addb7a60..1358218270 100644 --- a/include/sdhci.h +++ b/include/sdhci.h @@ -321,6 +321,7 @@ struct sdhci_host { uint voltages; struct mmc_config cfg; + void *align_buffer; dma_addr_t start_addr; int flags; #define USE_SDMA (0x1 << 0) From f5df6aa1e64bdde7c26cf349dfd3a773f5c18e26 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 14 Feb 2020 16:40:22 +0900 Subject: [PATCH 12/17] mmc: sdhci: reduce code duplication for aligned buffer The same code is run for both SDHCI_QUIRK_32BIT_DMA_ADDR and define(CONFIG_FIXED_SDHCI_ALIGNED_BUFFER). Unify the code. Signed-off-by: Masahiro Yamada Reviewed-by: Jaehoon Chung --- drivers/mmc/sdhci.c | 22 ++++++++-------------- include/sdhci.h | 2 ++ 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c index 18fbcb5f18..b4713e7b9b 100644 --- a/drivers/mmc/sdhci.c +++ b/drivers/mmc/sdhci.c @@ -140,27 +140,16 @@ static void sdhci_prepare_dma(struct sdhci_host *host, struct mmc_data *data, sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); if (host->flags & USE_SDMA) { - if ((host->quirks & SDHCI_QUIRK_32BIT_DMA_ADDR) && - (host->start_addr & 0x7) != 0x0) { + if (host->force_align_buffer || + (host->quirks & SDHCI_QUIRK_32BIT_DMA_ADDR && + (host->start_addr & 0x7) != 0x0)) { *is_aligned = 0; host->start_addr = (unsigned long)host->align_buffer; if (data->flags != MMC_DATA_READ) memcpy(host->align_buffer, data->src, trans_bytes); } - -#if defined(CONFIG_FIXED_SDHCI_ALIGNED_BUFFER) - /* - * Always use this bounce-buffer when - * CONFIG_FIXED_SDHCI_ALIGNED_BUFFER is defined - */ - *is_aligned = 0; - host->start_addr = (unsigned long)host->align_buffer; - if (data->flags != MMC_DATA_READ) - memcpy(host->align_buffer, data->src, trans_bytes); -#endif sdhci_writel(host, host->start_addr, SDHCI_DMA_ADDRESS); - } else if (host->flags & (USE_ADMA | USE_ADMA64)) { sdhci_prepare_adma_table(host, data); @@ -627,6 +616,11 @@ static int sdhci_init(struct mmc *mmc) #if defined(CONFIG_FIXED_SDHCI_ALIGNED_BUFFER) host->align_buffer = (void *)CONFIG_FIXED_SDHCI_ALIGNED_BUFFER; + /* + * Always use this bounce-buffer when CONFIG_FIXED_SDHCI_ALIGNED_BUFFER + * is defined. + */ + host->force_align_buffer = true; #else if (host->quirks & SDHCI_QUIRK_32BIT_DMA_ADDR) { host->align_buffer = memalign(8, 512 * 1024); diff --git a/include/sdhci.h b/include/sdhci.h index 1358218270..7f8feefa45 100644 --- a/include/sdhci.h +++ b/include/sdhci.h @@ -9,6 +9,7 @@ #ifndef __SDHCI_HW_H #define __SDHCI_HW_H +#include #include #include #include @@ -322,6 +323,7 @@ struct sdhci_host { struct mmc_config cfg; void *align_buffer; + bool force_align_buffer; dma_addr_t start_addr; int flags; #define USE_SDMA (0x1 << 0) From a2b0221c9cb332415648c061c85f0ab1595c3429 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 14 Feb 2020 16:40:23 +0900 Subject: [PATCH 13/17] mmc: sdhci: use lower_32_bit2() and upper_32_bits() for setting adma_addr Use {lower,upper}_32_bits() instead of the combination of cast and shift. Signed-off-by: Masahiro Yamada Reviewed-by: Jaehoon Chung --- drivers/mmc/sdhci.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c index b4713e7b9b..fefe81016e 100644 --- a/drivers/mmc/sdhci.c +++ b/drivers/mmc/sdhci.c @@ -153,9 +153,10 @@ static void sdhci_prepare_dma(struct sdhci_host *host, struct mmc_data *data, } else if (host->flags & (USE_ADMA | USE_ADMA64)) { sdhci_prepare_adma_table(host, data); - sdhci_writel(host, (u32)host->adma_addr, SDHCI_ADMA_ADDRESS); + sdhci_writel(host, lower_32_bits(host->adma_addr), + SDHCI_ADMA_ADDRESS); if (host->flags & USE_ADMA64) - sdhci_writel(host, (u64)host->adma_addr >> 32, + sdhci_writel(host, upper_32_bits(host->adma_addr), SDHCI_ADMA_ADDRESS_HI); } From fdd84c8be40b8f31445d8f4b2e907c7e24e2e3f9 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 14 Feb 2020 16:40:24 +0900 Subject: [PATCH 14/17] mmc: sdhci: remove unneeded casts host->mmc is already (struct mmc *). memalign() returns an opaque pointer, so there is no need for casting. Signed-off-by: Masahiro Yamada Reviewed-by: Jaehoon Chung --- drivers/mmc/sdhci.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c index fefe81016e..ee54d78a28 100644 --- a/drivers/mmc/sdhci.c +++ b/drivers/mmc/sdhci.c @@ -522,7 +522,7 @@ static void sdhci_set_power(struct sdhci_host *host, unsigned short power) void sdhci_set_uhs_timing(struct sdhci_host *host) { - struct mmc *mmc = (struct mmc *)host->mmc; + struct mmc *mmc = host->mmc; u32 reg; reg = sdhci_readw(host, SDHCI_HOST_CONTROL2); @@ -735,8 +735,7 @@ int sdhci_setup_cfg(struct mmc_config *cfg, struct sdhci_host *host, __func__); return -EINVAL; } - host->adma_desc_table = (struct sdhci_adma_desc *) - memalign(ARCH_DMA_MINALIGN, ADMA_TABLE_SZ); + host->adma_desc_table = memalign(ARCH_DMA_MINALIGN, ADMA_TABLE_SZ); host->adma_addr = (dma_addr_t)host->adma_desc_table; #ifdef CONFIG_DMA_ADDR_T_64BIT From a7b2b6cc0aa9294b570a3161a05c6ccf4c0b6e40 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 14 Feb 2020 16:40:25 +0900 Subject: [PATCH 15/17] mmc: add mmc_get_dma_dir() helper Copied from Linux kernel. include/linux/mmc/host.h Signed-off-by: Masahiro Yamada Reviewed-by: Jaehoon Chung --- include/mmc.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/include/mmc.h b/include/mmc.h index b5cb514f57..71e2e1735a 100644 --- a/include/mmc.h +++ b/include/mmc.h @@ -12,6 +12,7 @@ #include #include #include +#include #include #if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) @@ -880,4 +881,9 @@ int mmc_get_env_dev(void); */ struct blk_desc *mmc_get_blk_desc(struct mmc *mmc); +static inline enum dma_data_direction mmc_get_dma_dir(struct mmc_data *data) +{ + return data->flags & MMC_DATA_WRITE ? DMA_TO_DEVICE : DMA_FROM_DEVICE; +} + #endif /* _MMC_H_ */ From 58d8ace12be763351df37cdcf6fdfceb646fb4dd Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 14 Feb 2020 16:40:26 +0900 Subject: [PATCH 16/17] mmc: sdhci: use dma_map_single() instead of flush_cache() before DMA Currently, sdhci_prepare_dma() calls flush_cache() regardless of the DMA direction. Actually, cache invalidation is enough when reading data from the device. This is correctly handled by dma_map_single(), which mimics the DMA-API in Linux kernel. Drivers can be agnostic which cache operation occurs behind the scene. This commit also sanitizes the difference between the virtual address and the dma address. Signed-off-by: Masahiro Yamada --- drivers/mmc/sdhci.c | 51 ++++++++++++++++++++++----------------------- 1 file changed, 25 insertions(+), 26 deletions(-) diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c index ee54d78a28..77a88bc043 100644 --- a/drivers/mmc/sdhci.c +++ b/drivers/mmc/sdhci.c @@ -15,6 +15,7 @@ #include #include #include +#include static void sdhci_reset(struct sdhci_host *host, u8 mask) { @@ -65,8 +66,8 @@ static void sdhci_transfer_pio(struct sdhci_host *host, struct mmc_data *data) } #if CONFIG_IS_ENABLED(MMC_SDHCI_ADMA) -static void sdhci_adma_desc(struct sdhci_host *host, char *buf, u16 len, - bool end) +static void sdhci_adma_desc(struct sdhci_host *host, dma_addr_t dma_addr, + u16 len, bool end) { struct sdhci_adma_desc *desc; u8 attr; @@ -82,9 +83,9 @@ static void sdhci_adma_desc(struct sdhci_host *host, char *buf, u16 len, desc->attr = attr; desc->len = len; desc->reserved = 0; - desc->addr_lo = (dma_addr_t)buf; + desc->addr_lo = lower_32_bits(dma_addr); #ifdef CONFIG_DMA_ADDR_T_64BIT - desc->addr_hi = (u64)buf >> 32; + desc->addr_hi = upper_32_bits(dma_addr); #endif } @@ -94,22 +95,17 @@ static void sdhci_prepare_adma_table(struct sdhci_host *host, uint trans_bytes = data->blocksize * data->blocks; uint desc_count = DIV_ROUND_UP(trans_bytes, ADMA_MAX_LEN); int i = desc_count; - char *buf; + dma_addr_t dma_addr = host->start_addr; host->desc_slot = 0; - if (data->flags & MMC_DATA_READ) - buf = data->dest; - else - buf = (char *)data->src; - while (--i) { - sdhci_adma_desc(host, buf, ADMA_MAX_LEN, false); - buf += ADMA_MAX_LEN; + sdhci_adma_desc(host, dma_addr, ADMA_MAX_LEN, false); + dma_addr += ADMA_MAX_LEN; trans_bytes -= ADMA_MAX_LEN; } - sdhci_adma_desc(host, buf, trans_bytes, true); + sdhci_adma_desc(host, dma_addr, trans_bytes, true); flush_cache((dma_addr_t)host->adma_desc_table, ROUND(desc_count * sizeof(struct sdhci_adma_desc), @@ -125,11 +121,12 @@ static void sdhci_prepare_dma(struct sdhci_host *host, struct mmc_data *data, int *is_aligned, int trans_bytes) { unsigned char ctrl; + void *buf; if (data->flags == MMC_DATA_READ) - host->start_addr = (dma_addr_t)data->dest; + buf = data->dest; else - host->start_addr = (dma_addr_t)data->src; + buf = (void *)data->src; ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL); ctrl &= ~SDHCI_CTRL_DMA_MASK; @@ -139,16 +136,20 @@ static void sdhci_prepare_dma(struct sdhci_host *host, struct mmc_data *data, ctrl |= SDHCI_CTRL_ADMA32; sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); + if (host->flags & USE_SDMA && + (host->force_align_buffer || + (host->quirks & SDHCI_QUIRK_32BIT_DMA_ADDR && + ((unsigned long)buf & 0x7) != 0x0))) { + *is_aligned = 0; + if (data->flags != MMC_DATA_READ) + memcpy(host->align_buffer, buf, trans_bytes); + buf = host->align_buffer; + } + + host->start_addr = dma_map_single(buf, trans_bytes, + mmc_get_dma_dir(data)); + if (host->flags & USE_SDMA) { - if (host->force_align_buffer || - (host->quirks & SDHCI_QUIRK_32BIT_DMA_ADDR && - (host->start_addr & 0x7) != 0x0)) { - *is_aligned = 0; - host->start_addr = (unsigned long)host->align_buffer; - if (data->flags != MMC_DATA_READ) - memcpy(host->align_buffer, data->src, - trans_bytes); - } sdhci_writel(host, host->start_addr, SDHCI_DMA_ADDRESS); } else if (host->flags & (USE_ADMA | USE_ADMA64)) { sdhci_prepare_adma_table(host, data); @@ -159,8 +160,6 @@ static void sdhci_prepare_dma(struct sdhci_host *host, struct mmc_data *data, sdhci_writel(host, upper_32_bits(host->adma_addr), SDHCI_ADMA_ADDRESS_HI); } - - flush_cache(host->start_addr, ROUND(trans_bytes, ARCH_DMA_MINALIGN)); } #else static void sdhci_prepare_dma(struct sdhci_host *host, struct mmc_data *data, From 4155ad9aac9474610038b525da9eec8ad9afbc12 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 14 Feb 2020 16:40:27 +0900 Subject: [PATCH 17/17] mmc: sdhci: fix missing cache invalidation after reading by DMA This driver currently performs cache operation before the DMA start, but does nothing after the DMA completion. When reading data by DMA, the cache invalidation is needed also after finishing the DMA transfer. Otherwise, the CPU might read data from the cache instead of from the main memory when speculative memory read or memory prefetch occurs. Instead of calling the cache operation directly, this commit adds dma_unmap_single(), which performs cache invalidation internally, but drivers do not need which operation is being run. Signed-off-by: Masahiro Yamada --- drivers/mmc/sdhci.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c index 77a88bc043..9b7c5f8f68 100644 --- a/drivers/mmc/sdhci.c +++ b/drivers/mmc/sdhci.c @@ -215,6 +215,10 @@ static int sdhci_transfer_data(struct sdhci_host *host, struct mmc_data *data) return -ETIMEDOUT; } } while (!(stat & SDHCI_INT_DATA_END)); + + dma_unmap_single(host->start_addr, data->blocks * data->blocksize, + mmc_get_dma_dir(data)); + return 0; }