* [PATCH 0/5] mmc: mxcmmc: add mpc512x support @ 2013-03-14 16:40 Anatolij Gustschin 2013-03-14 16:40 ` [PATCH 1/5] mmc: mxcmmc: add mpc512x SDHC support Anatolij Gustschin ` (5 more replies) 0 siblings, 6 replies; 14+ messages in thread From: Anatolij Gustschin @ 2013-03-14 16:40 UTC (permalink / raw) To: linux-mmc Cc: Chris Ball, Sascha Hauer, Markus Pargmann, devicetree-discuss, Anatolij Gustschin The SDHC controller on mpc512x is compatible with i.MX31 SDHC controller, the existing MMC host driver can be used on mpc512x with some modifications, the patch series extends the existing driver. It is based on the following mxcmmc DT support patch: http://thread.gmane.org/gmane.linux.kernel.mmc/19401 The series has been tested on mpc5121e based board and hasn't been tested on i.MX (only build tested using an ARM toolchain). If anyone could test it i.e. on i.MX31, I would really appreciate it. Thanks! Anatolij Gustschin (5): mmc: mxcmmc: add mpc512x SDHC support mmc: mxcmmc: use slot-gpio API for write-protect detection mmc: mxcmmc: constify mxcmci_devtype and fix build warning mmc: mxcmmc: enable DMA support on mpc512x mmc: mxcmmc: fix race conditions for host->req and host->data access arch/powerpc/boot/dts/mpc5121.dtsi | 2 + drivers/mmc/host/Kconfig | 10 +- drivers/mmc/host/mxcmmc.c | 300 +++++++++++++++++++++++++++--------- 3 files changed, 233 insertions(+), 79 deletions(-) -- 1.7.5.4 ^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH 1/5] mmc: mxcmmc: add mpc512x SDHC support 2013-03-14 16:40 [PATCH 0/5] mmc: mxcmmc: add mpc512x support Anatolij Gustschin @ 2013-03-14 16:40 ` Anatolij Gustschin 2013-03-14 16:50 ` Arnd Bergmann 2013-03-14 16:40 ` [PATCH 2/5] mmc: mxcmmc: use slot-gpio API for write-protect detection Anatolij Gustschin ` (4 subsequent siblings) 5 siblings, 1 reply; 14+ messages in thread From: Anatolij Gustschin @ 2013-03-14 16:40 UTC (permalink / raw) To: linux-mmc Cc: Chris Ball, Sascha Hauer, Markus Pargmann, devicetree-discuss, Anatolij Gustschin The SDHC controller on mpc512x is compatible with i.MX31 SDHC, so the mxcmmc driver can be used on mpc512x, too. Extend the driver to support mpc512x as well. Signed-off-by: Anatolij Gustschin <agust@denx.de> --- drivers/mmc/host/Kconfig | 10 +- drivers/mmc/host/mxcmmc.c | 222 +++++++++++++++++++++++++++++++++------------ 2 files changed, 167 insertions(+), 65 deletions(-) diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index d88219e..eda4376 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -319,12 +319,12 @@ config MMC_MSM support for SDIO devices. config MMC_MXC - tristate "Freescale i.MX21/27/31 Multimedia Card Interface support" - depends on ARCH_MXC + tristate "Freescale i.MX21/27/31 or MPC512x Multimedia Card support" + depends on ARCH_MXC || PPC_MPC512x help - This selects the Freescale i.MX21, i.MX27 and i.MX31 Multimedia card - Interface. If you have a i.MX platform with a Multimedia Card slot, - say Y or M here. + This selects the Freescale i.MX21, i.MX27, i.MX31 or MPC512x + Multimedia Card Interface. If you have an i.MX or MPC512x platform + with a Multimedia Card slot, say Y or M here. If unsure, say N. diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c index 626698b..562f4e6 100644 --- a/drivers/mmc/host/mxcmmc.c +++ b/drivers/mmc/host/mxcmmc.c @@ -41,7 +41,6 @@ #include <asm/dma.h> #include <asm/irq.h> -#include <asm/sizes.h> #include <linux/platform_data/mmc-mxcmmc.h> #include <linux/platform_data/dma-imx.h> @@ -119,8 +118,11 @@ enum mxcmci_type { IMX21_MMC, IMX31_MMC, + MPC512X_MMC, }; +struct mxcmci_reg_ops; + struct mxcmci_host { struct mmc_host *mmc; struct resource *res; @@ -162,6 +164,8 @@ struct mxcmci_host { struct timer_list watchdog; enum mxcmci_type devtype; + + struct mxcmci_reg_ops *reg_ops; }; static struct platform_device_id mxcmci_devtype[] = { @@ -172,6 +176,9 @@ static struct platform_device_id mxcmci_devtype[] = { .name = "imx31-mmc", .driver_data = IMX31_MMC, }, { + .name = "mpc512x-sdhc", + .driver_data = MPC512X_MMC, + }, { /* sentinel */ } }; @@ -185,6 +192,9 @@ static const struct of_device_id mxcmci_of_match[] = { .compatible = "fsl,imx31-mmc", .data = &mxcmci_devtype[IMX31_MMC], }, { + .compatible = "fsl,mpc5121-sdhc", + .data = &mxcmci_devtype[MPC512X_MMC], + }, { /* sentinel */ } }; @@ -195,6 +205,81 @@ static inline int is_imx31_mmc(struct mxcmci_host *host) return host->devtype == IMX31_MMC; } +static inline int is_mpc512x_mmc(struct mxcmci_host *host) +{ + return host->devtype == MPC512X_MMC; +} + +struct mxcmci_reg_ops { + void (*write_l)(struct mxcmci_host *host, u32 val, int reg); + u32 (*read_l)(struct mxcmci_host *host, int reg); + void (*write_w)(struct mxcmci_host *host, u16 val, int reg); + u16 (*read_w)(struct mxcmci_host *host, int reg); +}; + +#if IS_ENABLED(CONFIG_PPC_MPC512x) +static void mpcmci_writel(struct mxcmci_host *host, u32 val, int reg) +{ + out_be32(host->base + reg, val); +} + +static u32 mpcmci_readl(struct mxcmci_host *host, int reg) +{ + return in_be32(host->base + reg); +} + +static void mpcmci_writew(struct mxcmci_host *host, u16 val, int reg) +{ + out_be32(host->base + reg, val); +} + +static u16 mpcmci_readw(struct mxcmci_host *host, int reg) +{ + return in_be32(host->base + reg); +} + +struct mxcmci_reg_ops mxcmci_reg_ops = { + .read_l = mpcmci_readl, + .write_l = mpcmci_writel, + .read_w = mpcmci_readw, + .write_w = mpcmci_writew, +}; +#else +struct mxcmci_reg_ops mxcmci_reg_ops; +#endif + +static inline u32 mxcmci_readl(struct mxcmci_host *host, int reg) +{ + if (host->reg_ops->read_l) + return host->reg_ops->read_l(host, reg); + else + return readl(host->base + reg); +} + +static inline void mxcmci_writel(struct mxcmci_host *host, u32 val, int reg) +{ + if (host->reg_ops->write_l) + host->reg_ops->write_l(host, val, reg); + else + writel(val, host->base + reg); +} + +static inline u16 mxcmci_readw(struct mxcmci_host *host, int reg) +{ + if (host->reg_ops->read_w) + return host->reg_ops->read_w(host, reg); + else + return readw(host->base + reg); +} + +static inline void mxcmci_writew(struct mxcmci_host *host, u16 val, int reg) +{ + if (host->reg_ops->write_w) + host->reg_ops->write_w(host, val, reg); + else + writew(val, host->base + reg); +} + static void mxcmci_set_clk_rate(struct mxcmci_host *host, unsigned int clk_ios); static inline void mxcmci_init_ocr(struct mxcmci_host *host) @@ -246,14 +331,14 @@ static void mxcmci_softreset(struct mxcmci_host *host) dev_dbg(mmc_dev(host->mmc), "mxcmci_softreset\n"); /* reset sequence */ - writew(STR_STP_CLK_RESET, host->base + MMC_REG_STR_STP_CLK); - writew(STR_STP_CLK_RESET | STR_STP_CLK_START_CLK, - host->base + MMC_REG_STR_STP_CLK); + mxcmci_writew(host, STR_STP_CLK_RESET, MMC_REG_STR_STP_CLK); + mxcmci_writew(host, STR_STP_CLK_RESET | STR_STP_CLK_START_CLK, + MMC_REG_STR_STP_CLK); for (i = 0; i < 8; i++) - writew(STR_STP_CLK_START_CLK, host->base + MMC_REG_STR_STP_CLK); + mxcmci_writew(host, STR_STP_CLK_START_CLK, MMC_REG_STR_STP_CLK); - writew(0xff, host->base + MMC_REG_RES_TO); + mxcmci_writew(host, 0xff, MMC_REG_RES_TO); } static int mxcmci_setup_dma(struct mmc_host *mmc); @@ -272,8 +357,8 @@ static int mxcmci_setup_data(struct mxcmci_host *host, struct mmc_data *data) host->data = data; data->bytes_xfered = 0; - writew(nob, host->base + MMC_REG_NOB); - writew(blksz, host->base + MMC_REG_BLK_LEN); + mxcmci_writew(host, nob, MMC_REG_NOB); + mxcmci_writew(host, blksz, MMC_REG_BLK_LEN); host->datasize = datasize; if (!mxcmci_use_dma(host)) @@ -329,13 +414,13 @@ static void mxcmci_dma_callback(void *data) del_timer(&host->watchdog); - stat = readl(host->base + MMC_REG_STATUS); - writel(stat & ~STATUS_DATA_TRANS_DONE, host->base + MMC_REG_STATUS); + stat = mxcmci_readl(host, MMC_REG_STATUS); + mxcmci_writel(host, stat & ~STATUS_DATA_TRANS_DONE, MMC_REG_STATUS); dev_dbg(mmc_dev(host->mmc), "%s: 0x%08x\n", __func__, stat); if (stat & STATUS_READ_OP_DONE) - writel(STATUS_READ_OP_DONE, host->base + MMC_REG_STATUS); + mxcmci_writel(host, STATUS_READ_OP_DONE, MMC_REG_STATUS); mxcmci_data_done(host, stat); } @@ -383,12 +468,12 @@ static int mxcmci_start_cmd(struct mxcmci_host *host, struct mmc_command *cmd, spin_lock_irqsave(&host->lock, flags); if (host->use_sdio) int_cntr |= INT_SDIO_IRQ_EN; - writel(int_cntr, host->base + MMC_REG_INT_CNTR); + mxcmci_writel(host, int_cntr, MMC_REG_INT_CNTR); spin_unlock_irqrestore(&host->lock, flags); - writew(cmd->opcode, host->base + MMC_REG_CMD); - writel(cmd->arg, host->base + MMC_REG_ARG); - writew(cmdat, host->base + MMC_REG_CMD_DAT_CONT); + mxcmci_writew(host, cmd->opcode, MMC_REG_CMD); + mxcmci_writel(host, cmd->arg, MMC_REG_ARG); + mxcmci_writew(host, cmdat, MMC_REG_CMD_DAT_CONT); return 0; } @@ -402,7 +487,7 @@ static void mxcmci_finish_request(struct mxcmci_host *host, spin_lock_irqsave(&host->lock, flags); if (host->use_sdio) int_cntr |= INT_SDIO_IRQ_EN; - writel(int_cntr, host->base + MMC_REG_INT_CNTR); + mxcmci_writel(host, int_cntr, MMC_REG_INT_CNTR); spin_unlock_irqrestore(&host->lock, flags); host->req = NULL; @@ -477,14 +562,14 @@ static void mxcmci_read_response(struct mxcmci_host *host, unsigned int stat) if (cmd->flags & MMC_RSP_PRESENT) { if (cmd->flags & MMC_RSP_136) { for (i = 0; i < 4; i++) { - a = readw(host->base + MMC_REG_RES_FIFO); - b = readw(host->base + MMC_REG_RES_FIFO); + a = mxcmci_readw(host, MMC_REG_RES_FIFO); + b = mxcmci_readw(host, MMC_REG_RES_FIFO); cmd->resp[i] = a << 16 | b; } } else { - a = readw(host->base + MMC_REG_RES_FIFO); - b = readw(host->base + MMC_REG_RES_FIFO); - c = readw(host->base + MMC_REG_RES_FIFO); + a = mxcmci_readw(host, MMC_REG_RES_FIFO); + b = mxcmci_readw(host, MMC_REG_RES_FIFO); + c = mxcmci_readw(host, MMC_REG_RES_FIFO); cmd->resp[0] = a << 24 | b << 8 | c >> 8; } } @@ -496,7 +581,7 @@ static int mxcmci_poll_status(struct mxcmci_host *host, u32 mask) unsigned long timeout = jiffies + HZ; do { - stat = readl(host->base + MMC_REG_STATUS); + stat = mxcmci_readl(host, MMC_REG_STATUS); if (stat & STATUS_ERR_MASK) return stat; if (time_after(jiffies, timeout)) { @@ -520,7 +605,7 @@ static int mxcmci_pull(struct mxcmci_host *host, void *_buf, int bytes) STATUS_BUF_READ_RDY | STATUS_READ_OP_DONE); if (stat) return stat; - *buf++ = readl(host->base + MMC_REG_BUFFER_ACCESS); + *buf++ = cpu_to_le32(mxcmci_readl(host, MMC_REG_BUFFER_ACCESS)); bytes -= 4; } @@ -532,7 +617,7 @@ static int mxcmci_pull(struct mxcmci_host *host, void *_buf, int bytes) STATUS_BUF_READ_RDY | STATUS_READ_OP_DONE); if (stat) return stat; - tmp = readl(host->base + MMC_REG_BUFFER_ACCESS); + tmp = cpu_to_le32(mxcmci_readl(host, MMC_REG_BUFFER_ACCESS)); memcpy(b, &tmp, bytes); } @@ -548,7 +633,7 @@ static int mxcmci_push(struct mxcmci_host *host, void *_buf, int bytes) stat = mxcmci_poll_status(host, STATUS_BUF_WRITE_RDY); if (stat) return stat; - writel(*buf++, host->base + MMC_REG_BUFFER_ACCESS); + mxcmci_writel(host, cpu_to_le32(*buf++), MMC_REG_BUFFER_ACCESS); bytes -= 4; } @@ -561,7 +646,7 @@ static int mxcmci_push(struct mxcmci_host *host, void *_buf, int bytes) return stat; memcpy(&tmp, b, bytes); - writel(tmp, host->base + MMC_REG_BUFFER_ACCESS); + mxcmci_writel(host, cpu_to_le32(tmp), MMC_REG_BUFFER_ACCESS); } stat = mxcmci_poll_status(host, STATUS_BUF_WRITE_RDY); @@ -607,8 +692,8 @@ static void mxcmci_datawork(struct work_struct *work) datawork); int datastat = mxcmci_transfer_data(host); - writel(STATUS_READ_OP_DONE | STATUS_WRITE_OP_DONE, - host->base + MMC_REG_STATUS); + mxcmci_writel(host, STATUS_READ_OP_DONE | STATUS_WRITE_OP_DONE, + MMC_REG_STATUS); mxcmci_finish_data(host, datastat); if (host->req->stop) { @@ -670,9 +755,11 @@ static irqreturn_t mxcmci_irq(int irq, void *devid) bool sdio_irq; u32 stat; - stat = readl(host->base + MMC_REG_STATUS); - writel(stat & ~(STATUS_SDIO_INT_ACTIVE | STATUS_DATA_TRANS_DONE | - STATUS_WRITE_OP_DONE), host->base + MMC_REG_STATUS); + stat = mxcmci_readl(host, MMC_REG_STATUS); + mxcmci_writel(host, + stat & ~(STATUS_SDIO_INT_ACTIVE | STATUS_DATA_TRANS_DONE | + STATUS_WRITE_OP_DONE), + MMC_REG_STATUS); dev_dbg(mmc_dev(host->mmc), "%s: 0x%08x\n", __func__, stat); @@ -682,11 +769,11 @@ static irqreturn_t mxcmci_irq(int irq, void *devid) if (mxcmci_use_dma(host) && (stat & (STATUS_READ_OP_DONE | STATUS_WRITE_OP_DONE))) - writel(STATUS_READ_OP_DONE | STATUS_WRITE_OP_DONE, - host->base + MMC_REG_STATUS); + mxcmci_writel(host, STATUS_READ_OP_DONE | STATUS_WRITE_OP_DONE, + MMC_REG_STATUS); if (sdio_irq) { - writel(STATUS_SDIO_INT_ACTIVE, host->base + MMC_REG_STATUS); + mxcmci_writel(host, STATUS_SDIO_INT_ACTIVE, MMC_REG_STATUS); mmc_signal_sdio_irq(host->mmc); } @@ -768,7 +855,7 @@ static void mxcmci_set_clk_rate(struct mxcmci_host *host, unsigned int clk_ios) prescaler <<= 1; } - writew((prescaler << 4) | divider, host->base + MMC_REG_CLK_RATE); + mxcmci_writew(host, (prescaler << 4) | divider, MMC_REG_CLK_RATE); dev_dbg(mmc_dev(host->mmc), "scaler: %d divider: %d in: %d out: %d\n", prescaler, divider, clk_in, clk_ios); @@ -831,9 +918,9 @@ static void mxcmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) if (ios->clock) { mxcmci_set_clk_rate(host, ios->clock); - writew(STR_STP_CLK_START_CLK, host->base + MMC_REG_STR_STP_CLK); + mxcmci_writew(host, STR_STP_CLK_START_CLK, MMC_REG_STR_STP_CLK); } else { - writew(STR_STP_CLK_STOP_CLK, host->base + MMC_REG_STR_STP_CLK); + mxcmci_writew(host, STR_STP_CLK_STOP_CLK, MMC_REG_STR_STP_CLK); } host->clock = ios->clock; @@ -870,14 +957,14 @@ static void mxcmci_enable_sdio_irq(struct mmc_host *mmc, int enable) spin_lock_irqsave(&host->lock, flags); host->use_sdio = enable; - int_cntr = readl(host->base + MMC_REG_INT_CNTR); + int_cntr = mxcmci_readl(host, MMC_REG_INT_CNTR); if (enable) int_cntr |= INT_SDIO_IRQ_EN; else int_cntr &= ~INT_SDIO_IRQ_EN; - writel(int_cntr, host->base + MMC_REG_INT_CNTR); + mxcmci_writel(host, int_cntr, MMC_REG_INT_CNTR); spin_unlock_irqrestore(&host->lock, flags); } @@ -915,7 +1002,7 @@ static void mxcmci_watchdog(unsigned long data) struct mmc_host *mmc = (struct mmc_host *)data; struct mxcmci_host *host = mmc_priv(mmc); struct mmc_request *req = host->req; - unsigned int stat = readl(host->base + MMC_REG_STATUS); + unsigned int stat = mxcmci_readl(host, MMC_REG_STATUS); if (host->dma_dir == DMA_FROM_DEVICE) { dmaengine_terminate_all(host->dma); @@ -957,7 +1044,7 @@ static int mxcmci_probe(struct platform_device *pdev) const struct of_device_id *of_id; struct imxmmc_platform_data *pdata = pdev->dev.platform_data; - pr_info("i.MX SDHC driver\n"); + pr_info("i.MX/MPC512x SDHC driver\n"); of_id = of_match_device(mxcmci_of_match, &pdev->dev); @@ -999,6 +1086,8 @@ static int mxcmci_probe(struct platform_device *pdev) goto out_free; } + host->reg_ops = &mxcmci_reg_ops; + if (of_id) { struct platform_device_id *id_entry = of_id->data; host->devtype = id_entry->driver_data; @@ -1026,24 +1115,33 @@ static int mxcmci_probe(struct platform_device *pdev) host->res = r; host->irq = irq; - host->clk_ipg = devm_clk_get(&pdev->dev, "ipg"); - if (IS_ERR(host->clk_ipg)) { - ret = PTR_ERR(host->clk_ipg); - goto out_iounmap; - } + if (!is_mpc512x_mmc(host)) { + host->clk_ipg = devm_clk_get(&pdev->dev, "ipg"); + if (IS_ERR(host->clk_ipg)) { + ret = PTR_ERR(host->clk_ipg); + goto out_iounmap; + } - host->clk_per = devm_clk_get(&pdev->dev, "per"); - if (IS_ERR(host->clk_per)) { - ret = PTR_ERR(host->clk_per); - goto out_iounmap; - } + host->clk_per = devm_clk_get(&pdev->dev, "per"); + if (IS_ERR(host->clk_per)) { + ret = PTR_ERR(host->clk_per); + goto out_iounmap; + } - clk_prepare_enable(host->clk_per); - clk_prepare_enable(host->clk_ipg); + clk_prepare_enable(host->clk_per); + clk_prepare_enable(host->clk_ipg); + } else { + host->clk_per = clk_get(&pdev->dev, "sdhc_clk"); + if (IS_ERR(host->clk_per)) { + ret = PTR_ERR(host->clk_per); + goto out_iounmap; + } + clk_prepare_enable(host->clk_per); + } mxcmci_softreset(host); - host->rev_no = readw(host->base + MMC_REG_REV_NO); + host->rev_no = mxcmci_readw(host, MMC_REG_REV_NO); if (host->rev_no != 0x400) { ret = -ENODEV; dev_err(mmc_dev(host->mmc), "wrong rev.no. 0x%08x. aborting.\n", @@ -1055,9 +1153,9 @@ static int mxcmci_probe(struct platform_device *pdev) mmc->f_max = clk_get_rate(host->clk_per) >> 1; /* recommended in data sheet */ - writew(0x2db4, host->base + MMC_REG_READ_TO); + mxcmci_writew(host, 0x2db4, MMC_REG_READ_TO); - writel(host->default_irq_mask, host->base + MMC_REG_INT_CNTR); + mxcmci_writel(host, host->default_irq_mask, MMC_REG_INT_CNTR); if (!host->pdata) { host->dma = of_dma_request_slave_channel(pdev->dev.of_node, @@ -1110,7 +1208,8 @@ out_free_dma: dma_release_channel(host->dma); out_clk_put: clk_disable_unprepare(host->clk_per); - clk_disable_unprepare(host->clk_ipg); + if (!is_mpc512x_mmc(host)) + clk_disable_unprepare(host->clk_ipg); out_iounmap: iounmap(host->base); out_free: @@ -1142,7 +1241,8 @@ static int mxcmci_remove(struct platform_device *pdev) dma_release_channel(host->dma); clk_disable_unprepare(host->clk_per); - clk_disable_unprepare(host->clk_ipg); + if (!is_mpc512x_mmc(host)) + clk_disable_unprepare(host->clk_ipg); release_mem_region(host->res->start, resource_size(host->res)); @@ -1161,7 +1261,8 @@ static int mxcmci_suspend(struct device *dev) if (mmc) ret = mmc_suspend_host(mmc); clk_disable_unprepare(host->clk_per); - clk_disable_unprepare(host->clk_ipg); + if (!is_mpc512x_mmc(host)) + clk_disable_unprepare(host->clk_ipg); return ret; } @@ -1173,7 +1274,8 @@ static int mxcmci_resume(struct device *dev) int ret = 0; clk_prepare_enable(host->clk_per); - clk_prepare_enable(host->clk_ipg); + if (!is_mpc512x_mmc(host)) + clk_prepare_enable(host->clk_ipg); if (mmc) ret = mmc_resume_host(mmc); -- 1.7.5.4 ^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [PATCH 1/5] mmc: mxcmmc: add mpc512x SDHC support 2013-03-14 16:40 ` [PATCH 1/5] mmc: mxcmmc: add mpc512x SDHC support Anatolij Gustschin @ 2013-03-14 16:50 ` Arnd Bergmann 2013-03-14 18:13 ` Anatolij Gustschin 0 siblings, 1 reply; 14+ messages in thread From: Arnd Bergmann @ 2013-03-14 16:50 UTC (permalink / raw) To: Anatolij Gustschin Cc: linux-mmc, Chris Ball, Sascha Hauer, Markus Pargmann, devicetree-discuss On Thursday 14 March 2013 17:40:49 Anatolij Gustschin wrote: > + > +struct mxcmci_reg_ops mxcmci_reg_ops = { > + .read_l = mpcmci_readl, > + .write_l = mpcmci_writel, > + .read_w = mpcmci_readw, > + .write_w = mpcmci_writew, > +}; > +#else > +struct mxcmci_reg_ops mxcmci_reg_ops; > +#endif Should the struct be static? > +static inline u32 mxcmci_readl(struct mxcmci_host *host, int reg) > +{ > + if (host->reg_ops->read_l) > + return host->reg_ops->read_l(host, reg); > + else > + return readl(host->base + reg); > +} This seems a bit strange. I would suggest you either use the ops structure all the time and provide an imx variant, or you make it completely compile-time selected. > @@ -1026,24 +1115,33 @@ static int mxcmci_probe(struct platform_device *pdev) > host->res = r; > host->irq = irq; > > - host->clk_ipg = devm_clk_get(&pdev->dev, "ipg"); > - if (IS_ERR(host->clk_ipg)) { > - ret = PTR_ERR(host->clk_ipg); > - goto out_iounmap; > - } > + if (!is_mpc512x_mmc(host)) { > + host->clk_ipg = devm_clk_get(&pdev->dev, "ipg"); > + if (IS_ERR(host->clk_ipg)) { > + ret = PTR_ERR(host->clk_ipg); > + goto out_iounmap; > + } Does mpc512x have no clock management? I think it should still work without modifications if CONFIG_HAVE_CLK is disabled. In that case, devm_clk_get() will return NULL and we don't error out here. Arnd ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 1/5] mmc: mxcmmc: add mpc512x SDHC support 2013-03-14 16:50 ` Arnd Bergmann @ 2013-03-14 18:13 ` Anatolij Gustschin 2013-03-14 20:05 ` Sascha Hauer 2013-03-14 22:52 ` Arnd Bergmann 0 siblings, 2 replies; 14+ messages in thread From: Anatolij Gustschin @ 2013-03-14 18:13 UTC (permalink / raw) To: Arnd Bergmann Cc: linux-mmc, Chris Ball, Sascha Hauer, Markus Pargmann, devicetree-discuss On Thu, 14 Mar 2013 17:50:08 +0100 Arnd Bergmann <arnd@arndb.de> wrote: > On Thursday 14 March 2013 17:40:49 Anatolij Gustschin wrote: > > > + > > +struct mxcmci_reg_ops mxcmci_reg_ops = { > > + .read_l = mpcmci_readl, > > + .write_l = mpcmci_writel, > > + .read_w = mpcmci_readw, > > + .write_w = mpcmci_writew, > > +}; > > +#else > > +struct mxcmci_reg_ops mxcmci_reg_ops; > > +#endif > > Should the struct be static? yes, it should. > > +static inline u32 mxcmci_readl(struct mxcmci_host *host, int reg) > > +{ > > + if (host->reg_ops->read_l) > > + return host->reg_ops->read_l(host, reg); > > + else > > + return readl(host->base + reg); > > +} > > This seems a bit strange. I would suggest you either use the ops structure > all the time and provide an imx variant, or you make it completely > compile-time selected. I wanted to avoid additional levels of indirection and function calls on i.MX. If something like static inline u32 mxcmci_readl(struct mxcmci_host *host, int reg) { #if IS_ENABLED(CONFIG_PPC_MPC512x) return in_be32(host->base + reg); #else return readl(host->base + reg); #endif } is acceptable, I'll use it. > > @@ -1026,24 +1115,33 @@ static int mxcmci_probe(struct platform_device *pdev) > > host->res = r; > > host->irq = irq; > > > > - host->clk_ipg = devm_clk_get(&pdev->dev, "ipg"); > > - if (IS_ERR(host->clk_ipg)) { > > - ret = PTR_ERR(host->clk_ipg); > > - goto out_iounmap; > > - } > > + if (!is_mpc512x_mmc(host)) { > > + host->clk_ipg = devm_clk_get(&pdev->dev, "ipg"); > > + if (IS_ERR(host->clk_ipg)) { > > + ret = PTR_ERR(host->clk_ipg); > > + goto out_iounmap; > > + } > > Does mpc512x have no clock management? I think it should still > work without modifications if CONFIG_HAVE_CLK is disabled. > In that case, devm_clk_get() will return NULL and we don't > error out here. It does have some clock management (a platform clock driver) and the platform selects CONFIG_HAVE_CLK. But we do not have "ipg" and "per" clocks on that platform, but "sdhc_clk" instead. Thanks, Anatolij ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 1/5] mmc: mxcmmc: add mpc512x SDHC support 2013-03-14 18:13 ` Anatolij Gustschin @ 2013-03-14 20:05 ` Sascha Hauer 2013-03-14 22:52 ` Arnd Bergmann 1 sibling, 0 replies; 14+ messages in thread From: Sascha Hauer @ 2013-03-14 20:05 UTC (permalink / raw) To: Anatolij Gustschin Cc: devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ, Chris Ball, linux-mmc-u79uwXL29TY76Z2rM5mHXA On Thu, Mar 14, 2013 at 07:13:32PM +0100, Anatolij Gustschin wrote: > On Thu, 14 Mar 2013 17:50:08 +0100 > Arnd Bergmann <arnd-r2nGTMty4D4@public.gmane.org> wrote: > > > On Thursday 14 March 2013 17:40:49 Anatolij Gustschin wrote: > > > > > + > > > +struct mxcmci_reg_ops mxcmci_reg_ops = { > > > + .read_l = mpcmci_readl, > > > + .write_l = mpcmci_writel, > > > + .read_w = mpcmci_readw, > > > + .write_w = mpcmci_writew, > > > +}; > > > +#else > > > +struct mxcmci_reg_ops mxcmci_reg_ops; > > > +#endif > > > > Should the struct be static? > > yes, it should. > > > > +static inline u32 mxcmci_readl(struct mxcmci_host *host, int reg) > > > +{ > > > + if (host->reg_ops->read_l) > > > + return host->reg_ops->read_l(host, reg); > > > + else > > > + return readl(host->base + reg); > > > +} > > > > This seems a bit strange. I would suggest you either use the ops structure > > all the time and provide an imx variant, or you make it completely > > compile-time selected. > > I wanted to avoid additional levels of indirection and function calls > on i.MX. If something like > > static inline u32 mxcmci_readl(struct mxcmci_host *host, int reg) > { > #if IS_ENABLED(CONFIG_PPC_MPC512x) > return in_be32(host->base + reg); > #else > return readl(host->base + reg); > #endif I really wish we would have native endianess accessors... > > is acceptable, I'll use it. Looks better to me. > > > @@ -1026,24 +1115,33 @@ static int mxcmci_probe(struct platform_device *pdev) > > > host->res = r; > > > host->irq = irq; > > > > > > - host->clk_ipg = devm_clk_get(&pdev->dev, "ipg"); > > > - if (IS_ERR(host->clk_ipg)) { > > > - ret = PTR_ERR(host->clk_ipg); > > > - goto out_iounmap; > > > - } > > > + if (!is_mpc512x_mmc(host)) { > > > + host->clk_ipg = devm_clk_get(&pdev->dev, "ipg"); > > > + if (IS_ERR(host->clk_ipg)) { > > > + ret = PTR_ERR(host->clk_ipg); > > > + goto out_iounmap; > > > + } > > > > Does mpc512x have no clock management? I think it should still > > work without modifications if CONFIG_HAVE_CLK is disabled. > > In that case, devm_clk_get() will return NULL and we don't > > error out here. > > It does have some clock management (a platform clock driver) and > the platform selects CONFIG_HAVE_CLK. But we do not have "ipg" > and "per" clocks on that platform, but "sdhc_clk" instead. The clocks should be modelled after the input clocks the MMC controller has, not after the clocks the SoC provides control for. So if you cannot software control a clock then you should provide a dummy clock for it. That said, 'ipg' is not a very good name for a mpc SoC, something like 'bus' would probably be better. Sascha -- Pengutronix e.K. | | Industrial Linux Solutions | http://www.pengutronix.de/ | Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 | ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 1/5] mmc: mxcmmc: add mpc512x SDHC support 2013-03-14 18:13 ` Anatolij Gustschin 2013-03-14 20:05 ` Sascha Hauer @ 2013-03-14 22:52 ` Arnd Bergmann 1 sibling, 0 replies; 14+ messages in thread From: Arnd Bergmann @ 2013-03-14 22:52 UTC (permalink / raw) To: Anatolij Gustschin Cc: linux-mmc, Chris Ball, Sascha Hauer, Markus Pargmann, devicetree-discuss On Thursday 14 March 2013, Anatolij Gustschin wrote: > I wanted to avoid additional levels of indirection and function calls > on i.MX. If something like > > static inline u32 mxcmci_readl(struct mxcmci_host *host, int reg) > { > #if IS_ENABLED(CONFIG_PPC_MPC512x) > return in_be32(host->base + reg); > #else > return readl(host->base + reg); > #endif > } > > is acceptable, I'll use it. I think that's ok. A single #ifdef around the four functions might be nicer though. You could also use ioread32_be on powerpc and write it like static inline u32 mxcmci_readl(struct mxcmci_host *host, int reg) { if (IS_ENABLED(CONFIG_PPC_MPC512x)) return ioread32_be(host->base + reg); else return readl(host->base + reg); } > > Does mpc512x have no clock management? I think it should still > > work without modifications if CONFIG_HAVE_CLK is disabled. > > In that case, devm_clk_get() will return NULL and we don't > > error out here. > > It does have some clock management (a platform clock driver) and > the platform selects CONFIG_HAVE_CLK. But we do not have "ipg" > and "per" clocks on that platform, but "sdhc_clk" instead. As Sascha said, they should really use the same name, although it's possible that neither sdhc_clk nor ipg is a good name here. Arnd ^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH 2/5] mmc: mxcmmc: use slot-gpio API for write-protect detection 2013-03-14 16:40 [PATCH 0/5] mmc: mxcmmc: add mpc512x support Anatolij Gustschin 2013-03-14 16:40 ` [PATCH 1/5] mmc: mxcmmc: add mpc512x SDHC support Anatolij Gustschin @ 2013-03-14 16:40 ` Anatolij Gustschin 2013-03-14 16:40 ` [PATCH 3/5] mmc: mxcmmc: constify mxcmci_devtype and fix build warning Anatolij Gustschin ` (3 subsequent siblings) 5 siblings, 0 replies; 14+ messages in thread From: Anatolij Gustschin @ 2013-03-14 16:40 UTC (permalink / raw) To: linux-mmc Cc: Chris Ball, Sascha Hauer, Markus Pargmann, devicetree-discuss, Anatolij Gustschin slot-gpio API suppors read-only detection when "wp-gpios" property is present in the device tree mmc node. Use this API for write-protect detection. Signed-off-by: Anatolij Gustschin <agust@denx.de> --- drivers/mmc/host/mxcmmc.c | 8 +++++--- 1 files changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c index 562f4e6..dc25802 100644 --- a/drivers/mmc/host/mxcmmc.c +++ b/drivers/mmc/host/mxcmmc.c @@ -38,6 +38,7 @@ #include <linux/of_device.h> #include <linux/of_dma.h> #include <linux/of_gpio.h> +#include <linux/mmc/slot-gpio.h> #include <asm/dma.h> #include <asm/irq.h> @@ -943,10 +944,11 @@ static int mxcmci_get_ro(struct mmc_host *mmc) if (host->pdata && host->pdata->get_ro) return !!host->pdata->get_ro(mmc_dev(mmc)); /* - * Board doesn't support read only detection; let the mmc core - * decide what to do. + * If board doesn't support read only detection (no mmc_gpio + * context or gpio is invalid), then let the mmc core decide + * what to do. */ - return -ENOSYS; + return mmc_gpio_get_ro(mmc); } static void mxcmci_enable_sdio_irq(struct mmc_host *mmc, int enable) -- 1.7.5.4 ^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 3/5] mmc: mxcmmc: constify mxcmci_devtype and fix build warning 2013-03-14 16:40 [PATCH 0/5] mmc: mxcmmc: add mpc512x support Anatolij Gustschin 2013-03-14 16:40 ` [PATCH 1/5] mmc: mxcmmc: add mpc512x SDHC support Anatolij Gustschin 2013-03-14 16:40 ` [PATCH 2/5] mmc: mxcmmc: use slot-gpio API for write-protect detection Anatolij Gustschin @ 2013-03-14 16:40 ` Anatolij Gustschin 2013-03-14 16:40 ` Anatolij Gustschin ` (2 subsequent siblings) 5 siblings, 0 replies; 14+ messages in thread From: Anatolij Gustschin @ 2013-03-14 16:40 UTC (permalink / raw) To: linux-mmc Cc: Chris Ball, Sascha Hauer, Markus Pargmann, devicetree-discuss, Anatolij Gustschin Fix: drivers/mmc/host/mxcmmc.c: In function 'mxcmci_probe': drivers/mmc/host/mxcmmc.c:1137:41: warning: initialization discards 'const' qualifier from pointer target type [enabled by default] Signed-off-by: Anatolij Gustschin <agust@denx.de> --- drivers/mmc/host/mxcmmc.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c index dc25802..c0115e9 100644 --- a/drivers/mmc/host/mxcmmc.c +++ b/drivers/mmc/host/mxcmmc.c @@ -169,7 +169,7 @@ struct mxcmci_host { struct mxcmci_reg_ops *reg_ops; }; -static struct platform_device_id mxcmci_devtype[] = { +static const struct platform_device_id mxcmci_devtype[] = { { .name = "imx21-mmc", .driver_data = IMX21_MMC, @@ -1091,7 +1091,7 @@ static int mxcmci_probe(struct platform_device *pdev) host->reg_ops = &mxcmci_reg_ops; if (of_id) { - struct platform_device_id *id_entry = of_id->data; + const struct platform_device_id *id_entry = of_id->data; host->devtype = id_entry->driver_data; } else { host->devtype = pdev->id_entry->driver_data; -- 1.7.5.4 ^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 3/5] mmc: mxcmmc: constify mxcmci_devtype and fix build warning 2013-03-14 16:40 [PATCH 0/5] mmc: mxcmmc: add mpc512x support Anatolij Gustschin ` (2 preceding siblings ...) 2013-03-14 16:40 ` [PATCH 3/5] mmc: mxcmmc: constify mxcmci_devtype and fix build warning Anatolij Gustschin @ 2013-03-14 16:40 ` Anatolij Gustschin 2013-03-14 18:15 ` Anatolij Gustschin 2013-03-14 16:40 ` [PATCH 4/5] mmc: mxcmmc: enable DMA support on mpc512x Anatolij Gustschin 2013-03-14 16:40 ` [PATCH 5/5] mmc: mxcmmc: fix race conditions for host->req and host->data access Anatolij Gustschin 5 siblings, 1 reply; 14+ messages in thread From: Anatolij Gustschin @ 2013-03-14 16:40 UTC (permalink / raw) To: linux-mmc Cc: Chris Ball, Sascha Hauer, Markus Pargmann, devicetree-discuss, Anatolij Gustschin Fix: drivers/mmc/host/mxcmmc.c: In function 'mxcmci_probe': drivers/mmc/host/mxcmmc.c:1137:41: warning: initialization discards 'const' qualifier from pointer target type [enabled by default] Signed-off-by: Anatolij Gustschin <agust@denx.de> --- drivers/mmc/host/mxcmmc.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c index dc25802..c0115e9 100644 --- a/drivers/mmc/host/mxcmmc.c +++ b/drivers/mmc/host/mxcmmc.c @@ -169,7 +169,7 @@ struct mxcmci_host { struct mxcmci_reg_ops *reg_ops; }; -static struct platform_device_id mxcmci_devtype[] = { +static const struct platform_device_id mxcmci_devtype[] = { { .name = "imx21-mmc", .driver_data = IMX21_MMC, @@ -1091,7 +1091,7 @@ static int mxcmci_probe(struct platform_device *pdev) host->reg_ops = &mxcmci_reg_ops; if (of_id) { - struct platform_device_id *id_entry = of_id->data; + const struct platform_device_id *id_entry = of_id->data; host->devtype = id_entry->driver_data; } else { host->devtype = pdev->id_entry->driver_data; -- 1.7.5.4 ^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [PATCH 3/5] mmc: mxcmmc: constify mxcmci_devtype and fix build warning 2013-03-14 16:40 ` Anatolij Gustschin @ 2013-03-14 18:15 ` Anatolij Gustschin 0 siblings, 0 replies; 14+ messages in thread From: Anatolij Gustschin @ 2013-03-14 18:15 UTC (permalink / raw) To: Anatolij Gustschin Cc: linux-mmc, Chris Ball, Sascha Hauer, Markus Pargmann, devicetree-discuss On Thu, 14 Mar 2013 17:40:52 +0100 Anatolij Gustschin <agust@denx.de> wrote: > Fix: > drivers/mmc/host/mxcmmc.c: In function 'mxcmci_probe': > drivers/mmc/host/mxcmmc.c:1137:41: warning: initialization discards > 'const' qualifier from pointer target type [enabled by default] > > Signed-off-by: Anatolij Gustschin <agust@denx.de> > --- > drivers/mmc/host/mxcmmc.c | 4 ++-- > 1 files changed, 2 insertions(+), 2 deletions(-) that one has been sent by accident, please ignore it. Sorry for that. Anatolij ^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH 4/5] mmc: mxcmmc: enable DMA support on mpc512x 2013-03-14 16:40 [PATCH 0/5] mmc: mxcmmc: add mpc512x support Anatolij Gustschin ` (3 preceding siblings ...) 2013-03-14 16:40 ` Anatolij Gustschin @ 2013-03-14 16:40 ` Anatolij Gustschin 2013-03-14 20:11 ` Sascha Hauer 2013-03-14 16:40 ` [PATCH 5/5] mmc: mxcmmc: fix race conditions for host->req and host->data access Anatolij Gustschin 5 siblings, 1 reply; 14+ messages in thread From: Anatolij Gustschin @ 2013-03-14 16:40 UTC (permalink / raw) To: linux-mmc Cc: Chris Ball, Sascha Hauer, Markus Pargmann, devicetree-discuss, Anatolij Gustschin Add SDHC DMA channel description to the mpc512x device tree to enable slave channel requesting in the mxcmmc driver. mpc512x DMA engine doesn't support endianness conversion when reading/writing data from peripheral's FIFO, so we have to swap data buffers before each DMA write and after each DMA read transfer manually. Since chained SDHC DMA transfers are not supported on mpc512x, limit 'max_segs' tunable parameter to one and initialise it to 64 only when running on i.MX platforms. Signed-off-by: Anatolij Gustschin <agust@denx.de> --- arch/powerpc/boot/dts/mpc5121.dtsi | 2 ++ drivers/mmc/host/mxcmmc.c | 35 +++++++++++++++++++++++++++++++++-- 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/boot/dts/mpc5121.dtsi b/arch/powerpc/boot/dts/mpc5121.dtsi index d1fe070..712b15a 100644 --- a/arch/powerpc/boot/dts/mpc5121.dtsi +++ b/arch/powerpc/boot/dts/mpc5121.dtsi @@ -152,6 +152,8 @@ compatible = "fsl,mpc5121-sdhc"; reg = <0x1500 0x100>; interrupts = <8 0x8>; + dmas = <&dma0 30>; + dma-names = "rx-tx"; }; i2c@1700 { diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c index c0115e9..48e3fd8 100644 --- a/drivers/mmc/host/mxcmmc.c +++ b/drivers/mmc/host/mxcmmc.c @@ -343,6 +343,29 @@ static void mxcmci_softreset(struct mxcmci_host *host) } static int mxcmci_setup_dma(struct mmc_host *mmc); +#if IS_ENABLED(CONFIG_PPC_MPC512x) +static inline void buffer_swap32(u32 *buf, int len) +{ + int i; + + for (i = 0; i < ((len + 3) / 4); i++) { + st_le32(buf, *buf); + buf++; + } +} + +static void mxcmci_fixup_buffers(struct mmc_data *data) +{ + struct scatterlist *sg; + int i; + + for_each_sg(data->sg, sg, data->sg_len, i) + buffer_swap32(sg_virt(sg), sg->length); +} +#else +static inline void mxcmci_fixup_buffers(struct mmc_data *data) {} +#endif + static int mxcmci_setup_data(struct mxcmci_host *host, struct mmc_data *data) { unsigned int nob = data->blocks; @@ -378,6 +401,8 @@ static int mxcmci_setup_data(struct mxcmci_host *host, struct mmc_data *data) } else { host->dma_dir = DMA_TO_DEVICE; slave_dirn = DMA_MEM_TO_DEV; + + mxcmci_fixup_buffers(data); } nents = dma_map_sg(host->dma->device->dev, data->sg, @@ -503,9 +528,11 @@ static int mxcmci_finish_data(struct mxcmci_host *host, unsigned int stat) struct mmc_data *data = host->data; int data_error; - if (mxcmci_use_dma(host)) + if (mxcmci_use_dma(host)) { dma_unmap_sg(host->dma->device->dev, data->sg, data->sg_len, host->dma_dir); + mxcmci_fixup_buffers(data); + } if (stat & STATUS_ERR_MASK) { dev_dbg(mmc_dev(host->mmc), "request failed. status: 0x%08x\n", @@ -1075,7 +1102,6 @@ static int mxcmci_probe(struct platform_device *pdev) mmc->caps |= MMC_CAP_SDIO_IRQ; /* MMC core transfer sizes tunable parameters */ - mmc->max_segs = 64; mmc->max_blk_size = 2048; mmc->max_blk_count = 65535; mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count; @@ -1096,6 +1122,11 @@ static int mxcmci_probe(struct platform_device *pdev) } else { host->devtype = pdev->id_entry->driver_data; } + + /* adjust max_segs after devtype detection */ + if (!is_mpc512x_mmc(host)) + mmc->max_segs = 64; + host->mmc = mmc; host->pdata = pdata; spin_lock_init(&host->lock); -- 1.7.5.4 ^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [PATCH 4/5] mmc: mxcmmc: enable DMA support on mpc512x 2013-03-14 16:40 ` [PATCH 4/5] mmc: mxcmmc: enable DMA support on mpc512x Anatolij Gustschin @ 2013-03-14 20:11 ` Sascha Hauer 2013-03-14 21:18 ` Anatolij Gustschin 0 siblings, 1 reply; 14+ messages in thread From: Sascha Hauer @ 2013-03-14 20:11 UTC (permalink / raw) To: Anatolij Gustschin Cc: linux-mmc, Chris Ball, Markus Pargmann, devicetree-discuss On Thu, Mar 14, 2013 at 05:40:53PM +0100, Anatolij Gustschin wrote: > Add SDHC DMA channel description to the mpc512x device > tree to enable slave channel requesting in the mxcmmc > driver. > > mpc512x DMA engine doesn't support endianness conversion > when reading/writing data from peripheral's FIFO, so we > have to swap data buffers before each DMA write and after > each DMA read transfer manually. > > Since chained SDHC DMA transfers are not supported on > mpc512x, limit 'max_segs' tunable parameter to one and > initialise it to 64 only when running on i.MX platforms. They are also not supported on the older i.MX platforms. Shouldn't this be handled in the DMA driver? Sascha -- Pengutronix e.K. | | Industrial Linux Solutions | http://www.pengutronix.de/ | Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 | ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 4/5] mmc: mxcmmc: enable DMA support on mpc512x 2013-03-14 20:11 ` Sascha Hauer @ 2013-03-14 21:18 ` Anatolij Gustschin 0 siblings, 0 replies; 14+ messages in thread From: Anatolij Gustschin @ 2013-03-14 21:18 UTC (permalink / raw) To: Sascha Hauer; +Cc: linux-mmc, Chris Ball, Markus Pargmann, devicetree-discuss On Thu, 14 Mar 2013 21:11:39 +0100 Sascha Hauer <s.hauer@pengutronix.de> wrote: > On Thu, Mar 14, 2013 at 05:40:53PM +0100, Anatolij Gustschin wrote: > > Add SDHC DMA channel description to the mpc512x device > > tree to enable slave channel requesting in the mxcmmc > > driver. > > > > mpc512x DMA engine doesn't support endianness conversion > > when reading/writing data from peripheral's FIFO, so we > > have to swap data buffers before each DMA write and after > > each DMA read transfer manually. > > > > Since chained SDHC DMA transfers are not supported on > > mpc512x, limit 'max_segs' tunable parameter to one and > > initialise it to 64 only when running on i.MX platforms. > > They are also not supported on the older i.MX platforms. Shouldn't this > be handled in the DMA driver? This could be handled in the DMA driver, but up to now nobody cared to extend the DMA driver so. Anatolij ^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH 5/5] mmc: mxcmmc: fix race conditions for host->req and host->data access 2013-03-14 16:40 [PATCH 0/5] mmc: mxcmmc: add mpc512x support Anatolij Gustschin ` (4 preceding siblings ...) 2013-03-14 16:40 ` [PATCH 4/5] mmc: mxcmmc: enable DMA support on mpc512x Anatolij Gustschin @ 2013-03-14 16:40 ` Anatolij Gustschin 5 siblings, 0 replies; 14+ messages in thread From: Anatolij Gustschin @ 2013-03-14 16:40 UTC (permalink / raw) To: linux-mmc Cc: Chris Ball, Sascha Hauer, Markus Pargmann, devicetree-discuss, Anatolij Gustschin mxcmci_dma_callback() is invoked by DMA drivers in soft-irq context and can be interrupted by the mxcmci_irq() interrupt which can finish the mmc request or data transfer and set host->req or host->data pointers to NULL. Then mxcmci_data_done() crashes with a null pointer dereferences. Protect all accesses to host->req and host->data by spin locks. Also check host->data pointer in mxcmci_watchdog() before dereferencing it. Signed-off-by: Anatolij Gustschin <agust@denx.de> --- drivers/mmc/host/mxcmmc.c | 31 ++++++++++++++++++++++++------- 1 files changed, 24 insertions(+), 7 deletions(-) diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c index 48e3fd8..aef6299 100644 --- a/drivers/mmc/host/mxcmmc.c +++ b/drivers/mmc/host/mxcmmc.c @@ -736,24 +736,40 @@ static void mxcmci_datawork(struct work_struct *work) static void mxcmci_data_done(struct mxcmci_host *host, unsigned int stat) { - struct mmc_data *data = host->data; + struct mmc_request *req; int data_error; + unsigned long flags; + + spin_lock_irqsave(&host->lock, flags); - if (!data) + if (!host->data) { + spin_unlock_irqrestore(&host->lock, flags); return; + } + + if (!host->req) { + spin_unlock_irqrestore(&host->lock, flags); + return; + } + + req = host->req; + if (!req->stop) + host->req = NULL; /* we will handle finish req below */ data_error = mxcmci_finish_data(host, stat); + spin_unlock_irqrestore(&host->lock, flags); + mxcmci_read_response(host, stat); host->cmd = NULL; - if (host->req->stop) { - if (mxcmci_start_cmd(host, host->req->stop, 0)) { - mxcmci_finish_request(host, host->req); + if (req->stop) { + if (mxcmci_start_cmd(host, req->stop, 0)) { + mxcmci_finish_request(host, req); return; } } else { - mxcmci_finish_request(host, host->req); + mxcmci_finish_request(host, req); } } @@ -1047,7 +1063,8 @@ static void mxcmci_watchdog(unsigned long data) /* Mark transfer as erroneus and inform the upper layers */ - host->data->error = -ETIMEDOUT; + if (host->data) + host->data->error = -ETIMEDOUT; host->req = NULL; host->cmd = NULL; host->data = NULL; -- 1.7.5.4 ^ permalink raw reply related [flat|nested] 14+ messages in thread
end of thread, other threads:[~2013-03-14 22:52 UTC | newest] Thread overview: 14+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2013-03-14 16:40 [PATCH 0/5] mmc: mxcmmc: add mpc512x support Anatolij Gustschin 2013-03-14 16:40 ` [PATCH 1/5] mmc: mxcmmc: add mpc512x SDHC support Anatolij Gustschin 2013-03-14 16:50 ` Arnd Bergmann 2013-03-14 18:13 ` Anatolij Gustschin 2013-03-14 20:05 ` Sascha Hauer 2013-03-14 22:52 ` Arnd Bergmann 2013-03-14 16:40 ` [PATCH 2/5] mmc: mxcmmc: use slot-gpio API for write-protect detection Anatolij Gustschin 2013-03-14 16:40 ` [PATCH 3/5] mmc: mxcmmc: constify mxcmci_devtype and fix build warning Anatolij Gustschin 2013-03-14 16:40 ` Anatolij Gustschin 2013-03-14 18:15 ` Anatolij Gustschin 2013-03-14 16:40 ` [PATCH 4/5] mmc: mxcmmc: enable DMA support on mpc512x Anatolij Gustschin 2013-03-14 20:11 ` Sascha Hauer 2013-03-14 21:18 ` Anatolij Gustschin 2013-03-14 16:40 ` [PATCH 5/5] mmc: mxcmmc: fix race conditions for host->req and host->data access Anatolij Gustschin
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).