From 603b2f3a74412110b5bc515a0d75929f8651dc6c Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Mon, 27 Jul 2015 22:39:36 +0200 Subject: [PATCH 1/6] mmc: dw_mmc: Stop bounce buffer even in case of failure The driver didn't stop the bounce buffer in case a data transfer failed. This would lead to memory leakage if the communication between the CPU and the card is unreliable. Add the missing call to stop the bounce buffer. Signed-off-by: Marek Vasut Cc: Dinh Nguyen Cc: Pantelis Antoniou Cc: Tom Rini --- drivers/mmc/dw_mmc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mmc/dw_mmc.c b/drivers/mmc/dw_mmc.c index 53a8aca84b..3fffa71166 100644 --- a/drivers/mmc/dw_mmc.c +++ b/drivers/mmc/dw_mmc.c @@ -215,6 +215,7 @@ static int dwmci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, mask = dwmci_readl(host, DWMCI_RINTSTS); if (mask & (DWMCI_DATA_ERR | DWMCI_DATA_TOUT)) { printf("%s: DATA ERROR!\n", __func__); + bounce_buffer_stop(&bbstate); return -1; } } while (!(mask & DWMCI_INTMSK_DTO)); From d9dbb97be0e4a550457aec5f11afefb446169c90 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Mon, 27 Jul 2015 22:39:37 +0200 Subject: [PATCH 2/6] mmc: dw_mmc: Zap endless timeout Endless timeouts are bad, since if we get stuck in one, we have no way out. Zap this one by implementing proper timeout. Signed-off-by: Marek Vasut Cc: Dinh Nguyen Cc: Pantelis Antoniou Cc: Tom Rini --- drivers/mmc/dw_mmc.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/dw_mmc.c b/drivers/mmc/dw_mmc.c index 3fffa71166..0f61f163e2 100644 --- a/drivers/mmc/dw_mmc.c +++ b/drivers/mmc/dw_mmc.c @@ -211,14 +211,29 @@ static int dwmci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, } if (data) { - do { + start = get_timer(0); + timeout = 1000; + for (;;) { mask = dwmci_readl(host, DWMCI_RINTSTS); + /* Error during data transfer. */ if (mask & (DWMCI_DATA_ERR | DWMCI_DATA_TOUT)) { printf("%s: DATA ERROR!\n", __func__); bounce_buffer_stop(&bbstate); return -1; } - } while (!(mask & DWMCI_INTMSK_DTO)); + + /* Data arrived correctly. */ + if (mask & DWMCI_INTMSK_DTO) + break; + + /* Check for timeout. */ + if (get_timer(start) > timeout) { + printf("%s: Timeout waiting for data!\n", + __func__); + bounce_buffer_stop(&bbstate); + return TIMEOUT; + } + } dwmci_writel(host, DWMCI_RINTSTS, mask); From 9042d974d2391b58d9a51f805756fac31f3c656f Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Mon, 27 Jul 2015 22:39:38 +0200 Subject: [PATCH 3/6] mmc: dw_mmc: Improve handling of data transfer failure In case the data transfer failure happens, instead of returning immediatelly, make sure the DMA is disabled, status register is cleared and the bounce buffer is stopped. Signed-off-by: Marek Vasut Cc: Dinh Nguyen Cc: Pantelis Antoniou Cc: Tom Rini --- drivers/mmc/dw_mmc.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/drivers/mmc/dw_mmc.c b/drivers/mmc/dw_mmc.c index 0f61f163e2..fcd5784899 100644 --- a/drivers/mmc/dw_mmc.c +++ b/drivers/mmc/dw_mmc.c @@ -110,7 +110,7 @@ static int dwmci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct dwmci_host *host = mmc->priv; ALLOC_CACHE_ALIGN_BUFFER(struct dwmci_idmac, cur_idmac, data ? DIV_ROUND_UP(data->blocks, 8) : 0); - int flags = 0, i; + int ret = 0, flags = 0, i; unsigned int timeout = 100000; u32 retry = 10000; u32 mask, ctrl; @@ -218,20 +218,22 @@ static int dwmci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, /* Error during data transfer. */ if (mask & (DWMCI_DATA_ERR | DWMCI_DATA_TOUT)) { printf("%s: DATA ERROR!\n", __func__); - bounce_buffer_stop(&bbstate); - return -1; + ret = -EINVAL; + break; } /* Data arrived correctly. */ - if (mask & DWMCI_INTMSK_DTO) + if (mask & DWMCI_INTMSK_DTO) { + ret = 0; break; + } /* Check for timeout. */ if (get_timer(start) > timeout) { printf("%s: Timeout waiting for data!\n", __func__); - bounce_buffer_stop(&bbstate); - return TIMEOUT; + ret = TIMEOUT; + break; } } @@ -246,7 +248,7 @@ static int dwmci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, udelay(100); - return 0; + return ret; } static int dwmci_setup_bus(struct dwmci_host *host, u32 freq) From 1c87ffe8d1eef2c759b97129fd48e218a039cbcd Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 6 Aug 2015 20:16:27 -0600 Subject: [PATCH 4/6] mmc: dw_mmc: Avoid using printf() for errors The dw_mmc driver uses printf() in various places. These bloat the code and cause problems for SPL. Use debug() where possible and try to return a useful error code instead. panto: Small rework to make it apply against top of tree. Signed-off-by: Simon Glass Signed-off-by: Pantelis Antoniou Acked-by: Jaehoon Chung --- drivers/mmc/dw_mmc.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/drivers/mmc/dw_mmc.c b/drivers/mmc/dw_mmc.c index fcd5784899..d34e4ee9dd 100644 --- a/drivers/mmc/dw_mmc.c +++ b/drivers/mmc/dw_mmc.c @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -119,7 +120,7 @@ static int dwmci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, while (dwmci_readl(host, DWMCI_STATUS) & DWMCI_BUSY) { if (get_timer(start) > timeout) { - printf("%s: Timeout on data busy\n", __func__); + debug("%s: Timeout on data busy\n", __func__); return TIMEOUT; } } @@ -178,7 +179,7 @@ static int dwmci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, } if (i == retry) { - printf("%s: Timeout.\n", __func__); + debug("%s: Timeout.\n", __func__); return TIMEOUT; } @@ -194,8 +195,8 @@ static int dwmci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, debug("%s: Response Timeout.\n", __func__); return TIMEOUT; } else if (mask & DWMCI_INTMSK_RE) { - printf("%s: Response Error.\n", __func__); - return -1; + debug("%s: Response Error.\n", __func__); + return -EIO; } @@ -217,7 +218,7 @@ static int dwmci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, mask = dwmci_readl(host, DWMCI_RINTSTS); /* Error during data transfer. */ if (mask & (DWMCI_DATA_ERR | DWMCI_DATA_TOUT)) { - printf("%s: DATA ERROR!\n", __func__); + debug("%s: DATA ERROR!\n", __func__); ret = -EINVAL; break; } @@ -230,7 +231,7 @@ static int dwmci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, /* Check for timeout. */ if (get_timer(start) > timeout) { - printf("%s: Timeout waiting for data!\n", + debug("%s: Timeout waiting for data!\n", __func__); ret = TIMEOUT; break; @@ -269,7 +270,7 @@ static int dwmci_setup_bus(struct dwmci_host *host, u32 freq) else if (host->bus_hz) sclk = host->bus_hz; else { - printf("%s: Didn't get source clock value.\n", __func__); + debug("%s: Didn't get source clock value.\n", __func__); return -EINVAL; } @@ -288,7 +289,7 @@ static int dwmci_setup_bus(struct dwmci_host *host, u32 freq) do { status = dwmci_readl(host, DWMCI_CMD); if (timeout-- < 0) { - printf("%s: Timeout!\n", __func__); + debug("%s: Timeout!\n", __func__); return -ETIMEDOUT; } } while (status & DWMCI_CMD_START); @@ -303,7 +304,7 @@ static int dwmci_setup_bus(struct dwmci_host *host, u32 freq) do { status = dwmci_readl(host, DWMCI_CMD); if (timeout-- < 0) { - printf("%s: Timeout!\n", __func__); + debug("%s: Timeout!\n", __func__); return -ETIMEDOUT; } } while (status & DWMCI_CMD_START); @@ -357,8 +358,8 @@ static int dwmci_init(struct mmc *mmc) dwmci_writel(host, DWMCI_PWREN, 1); if (!dwmci_wait_reset(host, DWMCI_RESET_ALL)) { - printf("%s[%d] Fail-reset!!\n", __func__, __LINE__); - return -1; + debug("%s[%d] Fail-reset!!\n", __func__, __LINE__); + return -EIO; } /* Enumerate at 400KHz */ From 760177dff4662d000c7b1331ec93b2ea4fbd564e Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 6 Aug 2015 20:16:29 -0600 Subject: [PATCH 5/6] dw_mmc: Calculate dwmmc FIFO threshold size if not provided We can calculate this. Add code to do this if it is not provided. panto: prefix changed to dw_mmc to make things easier to grep Signed-off-by: Simon Glass Acked-by: Jaehoon Chung --- drivers/mmc/dw_mmc.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/dw_mmc.c b/drivers/mmc/dw_mmc.c index d34e4ee9dd..77b87e0365 100644 --- a/drivers/mmc/dw_mmc.c +++ b/drivers/mmc/dw_mmc.c @@ -373,9 +373,15 @@ static int dwmci_init(struct mmc *mmc) dwmci_writel(host, DWMCI_IDINTEN, 0); dwmci_writel(host, DWMCI_BMOD, 1); - if (host->fifoth_val) { - dwmci_writel(host, DWMCI_FIFOTH, host->fifoth_val); + if (!host->fifoth_val) { + uint32_t fifo_size; + + fifo_size = dwmci_readl(host, DWMCI_FIFOTH); + fifo_size = ((fifo_size & RX_WMARK_MASK) >> RX_WMARK_SHIFT) + 1; + host->fifoth_val = MSIZE(0x2) | RX_WMARK(fifo_size / 2 - 1) | + TX_WMARK(fifo_size / 2); } + dwmci_writel(host, DWMCI_FIFOTH, host->fifoth_val); dwmci_writel(host, DWMCI_CLKENA, 0); dwmci_writel(host, DWMCI_CLKSRC, 0); From 6f67b69b1592662ec49485101a2358b71070bf57 Mon Sep 17 00:00:00 2001 From: Yoshinori Sato Date: Mon, 1 Jun 2015 15:22:37 +0900 Subject: [PATCH 6/6] mmc_spi: Big-endian support Currently implement always swap for big-endian value. So doesn't work big-endian environment. Signed-off-by: Yoshinori Sato --- drivers/mmc/mmc_spi.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/mmc/mmc_spi.c b/drivers/mmc/mmc_spi.c index 5b5b33a4b2..9032a73d78 100644 --- a/drivers/mmc/mmc_spi.c +++ b/drivers/mmc/mmc_spi.c @@ -11,7 +11,7 @@ #include #include #include -#include +#include /* MMC/SD in SPI mode reports R1 status always */ #define R1_SPI_IDLE (1 << 0) @@ -91,7 +91,7 @@ static uint mmc_spi_readdata(struct mmc *mmc, void *xbuf, spi_xfer(spi, bsize * 8, NULL, buf, 0); spi_xfer(spi, 2 * 8, NULL, &crc, 0); #ifdef CONFIG_MMC_SPI_CRC_ON - if (swab16(cyg_crc16(buf, bsize)) != crc) { + if (be_to_cpu16(cyg_crc16(buf, bsize)) != crc) { debug("%s: CRC error\n", mmc->cfg->name); r1 = R1_SPI_COM_CRC; break; @@ -120,7 +120,7 @@ static uint mmc_spi_writedata(struct mmc *mmc, const void *xbuf, tok[1] = multi ? SPI_TOKEN_MULTI_WRITE : SPI_TOKEN_SINGLE; while (bcnt--) { #ifdef CONFIG_MMC_SPI_CRC_ON - crc = swab16(cyg_crc16((u8 *)buf, bsize)); + crc = cpu_to_be16(cyg_crc16((u8 *)buf, bsize)); #endif spi_xfer(spi, 2 * 8, tok, NULL, 0); spi_xfer(spi, bsize * 8, buf, NULL, 0); @@ -193,7 +193,7 @@ static int mmc_spi_request(struct mmc *mmc, struct mmc_cmd *cmd, } else if (cmd->resp_type == MMC_RSP_R2) { r1 = mmc_spi_readdata(mmc, cmd->response, 1, 16); for (i = 0; i < 4; i++) - cmd->response[i] = swab32(cmd->response[i]); + cmd->response[i] = be32_to_cpu(cmd->response[i]); debug("r128 %x %x %x %x\n", cmd->response[0], cmd->response[1], cmd->response[2], cmd->response[3]); } else if (!data) { @@ -205,7 +205,7 @@ static int mmc_spi_request(struct mmc *mmc, struct mmc_cmd *cmd, case SD_CMD_SEND_IF_COND: case MMC_CMD_SPI_READ_OCR: spi_xfer(spi, 4 * 8, NULL, cmd->response, 0); - cmd->response[0] = swab32(cmd->response[0]); + cmd->response[0] = be32_to_cpu(cmd->response[0]); debug("r32 %x\n", cmd->response[0]); break; case MMC_CMD_SEND_STATUS: