Update Linux to v5.4.2
Change-Id: Idf6911045d9d382da2cfe01b1edff026404ac8fd
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 654051e..b056400 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1,13 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* linux/drivers/mmc/host/sdhci.c - Secure Digital Host Controller Interface driver
*
* Copyright (C) 2005-2008 Pierre Ossman, All Rights Reserved.
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
- *
* Thanks to the following companies for their support:
*
* - JMicron (hardware and technical support)
@@ -82,8 +78,8 @@
SDHCI_DUMP("Int enab: 0x%08x | Sig enab: 0x%08x\n",
sdhci_readl(host, SDHCI_INT_ENABLE),
sdhci_readl(host, SDHCI_SIGNAL_ENABLE));
- SDHCI_DUMP("AC12 err: 0x%08x | Slot int: 0x%08x\n",
- sdhci_readw(host, SDHCI_ACMD12_ERR),
+ SDHCI_DUMP("ACmd stat: 0x%08x | Slot int: 0x%08x\n",
+ sdhci_readw(host, SDHCI_AUTO_CMD_STATUS),
sdhci_readw(host, SDHCI_SLOT_INT_STATUS));
SDHCI_DUMP("Caps: 0x%08x | Caps_1: 0x%08x\n",
sdhci_readl(host, SDHCI_CAPABILITIES),
@@ -123,6 +119,29 @@
* *
\*****************************************************************************/
+static void sdhci_do_enable_v4_mode(struct sdhci_host *host)
+{
+ u16 ctrl2;
+
+ ctrl2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+ if (ctrl2 & SDHCI_CTRL_V4_MODE)
+ return;
+
+ ctrl2 |= SDHCI_CTRL_V4_MODE;
+ sdhci_writew(host, ctrl2, SDHCI_HOST_CONTROL2);
+}
+
+/*
+ * This can be called before sdhci_add_host() by Vendor's host controller
+ * driver to enable v4 mode if supported.
+ */
+void sdhci_enable_v4_mode(struct sdhci_host *host)
+{
+ host->v4_mode = true;
+ sdhci_do_enable_v4_mode(host);
+}
+EXPORT_SYMBOL_GPL(sdhci_enable_v4_mode);
+
static inline bool sdhci_data_line_cmd(struct mmc_command *cmd)
{
return cmd->data || cmd->flags & MMC_RSP_BUSY;
@@ -247,6 +266,52 @@
sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
}
+static void sdhci_config_dma(struct sdhci_host *host)
+{
+ u8 ctrl;
+ u16 ctrl2;
+
+ if (host->version < SDHCI_SPEC_200)
+ return;
+
+ ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
+
+ /*
+ * Always adjust the DMA selection as some controllers
+ * (e.g. JMicron) can't do PIO properly when the selection
+ * is ADMA.
+ */
+ ctrl &= ~SDHCI_CTRL_DMA_MASK;
+ if (!(host->flags & SDHCI_REQ_USE_DMA))
+ goto out;
+
+ /* Note if DMA Select is zero then SDMA is selected */
+ if (host->flags & SDHCI_USE_ADMA)
+ ctrl |= SDHCI_CTRL_ADMA32;
+
+ if (host->flags & SDHCI_USE_64_BIT_DMA) {
+ /*
+ * If v4 mode, all supported DMA can be 64-bit addressing if
+ * controller supports 64-bit system address, otherwise only
+ * ADMA can support 64-bit addressing.
+ */
+ if (host->v4_mode) {
+ ctrl2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+ ctrl2 |= SDHCI_CTRL_64BIT_ADDR;
+ sdhci_writew(host, ctrl2, SDHCI_HOST_CONTROL2);
+ } else if (host->flags & SDHCI_USE_ADMA) {
+ /*
+ * Don't need to undo SDHCI_CTRL_ADMA32 in order to
+ * set SDHCI_CTRL_ADMA64.
+ */
+ ctrl |= SDHCI_CTRL_ADMA64;
+ }
+ }
+
+out:
+ sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
+}
+
static void sdhci_init(struct sdhci_host *host, int soft)
{
struct mmc_host *mmc = host->mmc;
@@ -256,6 +321,9 @@
else
sdhci_do_reset(host, SDHCI_RESET_ALL);
+ if (host->v4_mode)
+ sdhci_do_enable_v4_mode(host);
+
sdhci_set_default_irqs(host);
host->cqe_on = false;
@@ -277,6 +345,9 @@
{
u8 ctrl;
+ if (host->quirks & SDHCI_QUIRK_NO_LED)
+ return;
+
ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
ctrl |= SDHCI_CTRL_LED;
sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
@@ -286,6 +357,9 @@
{
u8 ctrl;
+ if (host->quirks & SDHCI_QUIRK_NO_LED)
+ return;
+
ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
ctrl &= ~SDHCI_CTRL_LED;
sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
@@ -315,6 +389,9 @@
{
struct mmc_host *mmc = host->mmc;
+ if (host->quirks & SDHCI_QUIRK_NO_LED)
+ return 0;
+
snprintf(host->led_name, sizeof(host->led_name),
"%s::", mmc_hostname(mmc));
@@ -328,6 +405,9 @@
static void sdhci_led_unregister(struct sdhci_host *host)
{
+ if (host->quirks & SDHCI_QUIRK_NO_LED)
+ return;
+
led_classdev_unregister(&host->led);
}
@@ -362,6 +442,28 @@
#endif
+static void sdhci_mod_timer(struct sdhci_host *host, struct mmc_request *mrq,
+ unsigned long timeout)
+{
+ if (sdhci_data_line_cmd(mrq->cmd))
+ mod_timer(&host->data_timer, timeout);
+ else
+ mod_timer(&host->timer, timeout);
+}
+
+static void sdhci_del_timer(struct sdhci_host *host, struct mmc_request *mrq)
+{
+ if (sdhci_data_line_cmd(mrq->cmd))
+ del_timer(&host->data_timer);
+ else
+ del_timer(&host->timer);
+}
+
+static inline bool sdhci_has_requests(struct sdhci_host *host)
+{
+ return host->cmd || host->data_cmd;
+}
+
/*****************************************************************************\
* *
* Core functions *
@@ -558,18 +660,31 @@
local_irq_restore(*flags);
}
-static void sdhci_adma_write_desc(struct sdhci_host *host, void *desc,
- dma_addr_t addr, int len, unsigned cmd)
+void sdhci_adma_write_desc(struct sdhci_host *host, void **desc,
+ dma_addr_t addr, int len, unsigned int cmd)
{
- struct sdhci_adma2_64_desc *dma_desc = desc;
+ struct sdhci_adma2_64_desc *dma_desc = *desc;
/* 32-bit and 64-bit descriptors have these members in same position */
dma_desc->cmd = cpu_to_le16(cmd);
dma_desc->len = cpu_to_le16(len);
- dma_desc->addr_lo = cpu_to_le32((u32)addr);
+ dma_desc->addr_lo = cpu_to_le32(lower_32_bits(addr));
if (host->flags & SDHCI_USE_64_BIT_DMA)
- dma_desc->addr_hi = cpu_to_le32((u64)addr >> 32);
+ dma_desc->addr_hi = cpu_to_le32(upper_32_bits(addr));
+
+ *desc += host->desc_sz;
+}
+EXPORT_SYMBOL_GPL(sdhci_adma_write_desc);
+
+static inline void __sdhci_adma_write_desc(struct sdhci_host *host,
+ void **desc, dma_addr_t addr,
+ int len, unsigned int cmd)
+{
+ if (host->ops->adma_write_desc)
+ host->ops->adma_write_desc(host, desc, addr, len, cmd);
+ else
+ sdhci_adma_write_desc(host, desc, addr, len, cmd);
}
static void sdhci_adma_mark_end(void *desc)
@@ -622,28 +737,24 @@
}
/* tran, valid */
- sdhci_adma_write_desc(host, desc, align_addr, offset,
- ADMA2_TRAN_VALID);
+ __sdhci_adma_write_desc(host, &desc, align_addr,
+ offset, ADMA2_TRAN_VALID);
BUG_ON(offset > 65536);
align += SDHCI_ADMA2_ALIGN;
align_addr += SDHCI_ADMA2_ALIGN;
- desc += host->desc_sz;
-
addr += offset;
len -= offset;
}
BUG_ON(len > 65536);
- if (len) {
- /* tran, valid */
- sdhci_adma_write_desc(host, desc, addr, len,
- ADMA2_TRAN_VALID);
- desc += host->desc_sz;
- }
+ /* tran, valid */
+ if (len)
+ __sdhci_adma_write_desc(host, &desc, addr, len,
+ ADMA2_TRAN_VALID);
/*
* If this triggers then we have a calculation bug
@@ -660,7 +771,7 @@
}
} else {
/* Add a terminating entry - nop, end, valid */
- sdhci_adma_write_desc(host, desc, 0, 0, ADMA2_NOP_END_VALID);
+ __sdhci_adma_write_desc(host, &desc, 0, 0, ADMA2_NOP_END_VALID);
}
}
@@ -705,7 +816,14 @@
}
}
-static u32 sdhci_sdma_address(struct sdhci_host *host)
+static void sdhci_set_adma_addr(struct sdhci_host *host, dma_addr_t addr)
+{
+ sdhci_writel(host, lower_32_bits(addr), SDHCI_ADMA_ADDRESS);
+ if (host->flags & SDHCI_USE_64_BIT_DMA)
+ sdhci_writel(host, upper_32_bits(addr), SDHCI_ADMA_ADDRESS_HI);
+}
+
+static dma_addr_t sdhci_sdma_address(struct sdhci_host *host)
{
if (host->bounce_buffer)
return host->bounce_addr;
@@ -713,6 +831,14 @@
return sg_dma_address(host->data->sg);
}
+static void sdhci_set_sdma_addr(struct sdhci_host *host, dma_addr_t addr)
+{
+ if (host->v4_mode)
+ sdhci_set_adma_addr(host, addr);
+ else
+ sdhci_writel(host, addr, SDHCI_DMA_ADDRESS);
+}
+
static unsigned int sdhci_target_timeout(struct sdhci_host *host,
struct mmc_command *cmd,
struct mmc_data *data)
@@ -779,7 +905,7 @@
bool *too_big)
{
u8 count;
- struct mmc_data *data = cmd->data;
+ struct mmc_data *data;
unsigned target_timeout, current_timeout;
*too_big = true;
@@ -793,6 +919,11 @@
if (host->quirks & SDHCI_QUIRK_BROKEN_TIMEOUT_VAL)
return 0xE;
+ /* Unspecified command, asume max */
+ if (cmd == NULL)
+ return 0xE;
+
+ data = cmd->data;
/* Unspecified timeout, assume max */
if (!data && !cmd->busy_timeout)
return 0xE;
@@ -841,6 +972,11 @@
else
host->ier = (host->ier & ~dma_irqs) | pio_irqs;
+ if (host->flags & (SDHCI_AUTO_CMD23 | SDHCI_AUTO_CMD12))
+ host->ier |= SDHCI_INT_AUTO_CMD_ERR;
+ else
+ host->ier &= ~SDHCI_INT_AUTO_CMD_ERR;
+
sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
}
@@ -880,7 +1016,6 @@
static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd)
{
- u8 ctrl;
struct mmc_data *data = cmd->data;
host->data_timeout = 0;
@@ -964,38 +1099,14 @@
host->flags &= ~SDHCI_REQ_USE_DMA;
} else if (host->flags & SDHCI_USE_ADMA) {
sdhci_adma_table_pre(host, data, sg_cnt);
-
- sdhci_writel(host, host->adma_addr, SDHCI_ADMA_ADDRESS);
- if (host->flags & SDHCI_USE_64_BIT_DMA)
- sdhci_writel(host,
- (u64)host->adma_addr >> 32,
- SDHCI_ADMA_ADDRESS_HI);
+ sdhci_set_adma_addr(host, host->adma_addr);
} else {
WARN_ON(sg_cnt != 1);
- sdhci_writel(host, sdhci_sdma_address(host),
- SDHCI_DMA_ADDRESS);
+ sdhci_set_sdma_addr(host, sdhci_sdma_address(host));
}
}
- /*
- * Always adjust the DMA selection as some controllers
- * (e.g. JMicron) can't do PIO properly when the selection
- * is ADMA.
- */
- if (host->version >= SDHCI_SPEC_200) {
- ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
- ctrl &= ~SDHCI_CTRL_DMA_MASK;
- if ((host->flags & SDHCI_REQ_USE_DMA) &&
- (host->flags & SDHCI_USE_ADMA)) {
- if (host->flags & SDHCI_USE_64_BIT_DMA)
- ctrl |= SDHCI_CTRL_ADMA64;
- else
- ctrl |= SDHCI_CTRL_ADMA32;
- } else {
- ctrl |= SDHCI_CTRL_SDMA;
- }
- sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
- }
+ sdhci_config_dma(host);
if (!(host->flags & SDHCI_REQ_USE_DMA)) {
int flags;
@@ -1014,7 +1125,19 @@
/* Set the DMA boundary value and block size */
sdhci_writew(host, SDHCI_MAKE_BLKSZ(host->sdma_boundary, data->blksz),
SDHCI_BLOCK_SIZE);
- sdhci_writew(host, data->blocks, SDHCI_BLOCK_COUNT);
+
+ /*
+ * For Version 4.10 onwards, if v4 mode is enabled, 32-bit Block Count
+ * can be supported, in that case 16-bit block count register must be 0.
+ */
+ if (host->version >= SDHCI_SPEC_410 && host->v4_mode &&
+ (host->quirks2 & SDHCI_QUIRK2_USE_32BIT_BLK_CNT)) {
+ if (sdhci_readw(host, SDHCI_BLOCK_COUNT))
+ sdhci_writew(host, 0, SDHCI_BLOCK_COUNT);
+ sdhci_writew(host, data->blocks, SDHCI_32BIT_BLK_CNT);
+ } else {
+ sdhci_writew(host, data->blocks, SDHCI_BLOCK_COUNT);
+ }
}
static inline bool sdhci_auto_cmd12(struct sdhci_host *host,
@@ -1024,6 +1147,43 @@
!mrq->cap_cmd_during_tfr;
}
+static inline void sdhci_auto_cmd_select(struct sdhci_host *host,
+ struct mmc_command *cmd,
+ u16 *mode)
+{
+ bool use_cmd12 = sdhci_auto_cmd12(host, cmd->mrq) &&
+ (cmd->opcode != SD_IO_RW_EXTENDED);
+ bool use_cmd23 = cmd->mrq->sbc && (host->flags & SDHCI_AUTO_CMD23);
+ u16 ctrl2;
+
+ /*
+ * In case of Version 4.10 or later, use of 'Auto CMD Auto
+ * Select' is recommended rather than use of 'Auto CMD12
+ * Enable' or 'Auto CMD23 Enable'.
+ */
+ if (host->version >= SDHCI_SPEC_410 && (use_cmd12 || use_cmd23)) {
+ *mode |= SDHCI_TRNS_AUTO_SEL;
+
+ ctrl2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+ if (use_cmd23)
+ ctrl2 |= SDHCI_CMD23_ENABLE;
+ else
+ ctrl2 &= ~SDHCI_CMD23_ENABLE;
+ sdhci_writew(host, ctrl2, SDHCI_HOST_CONTROL2);
+
+ return;
+ }
+
+ /*
+ * If we are sending CMD23, CMD12 never gets sent
+ * on successful completion (so no Auto-CMD12).
+ */
+ if (use_cmd12)
+ *mode |= SDHCI_TRNS_AUTO_CMD12;
+ else if (use_cmd23)
+ *mode |= SDHCI_TRNS_AUTO_CMD23;
+}
+
static void sdhci_set_transfer_mode(struct sdhci_host *host,
struct mmc_command *cmd)
{
@@ -1052,17 +1212,9 @@
if (mmc_op_multi(cmd->opcode) || data->blocks > 1) {
mode = SDHCI_TRNS_BLK_CNT_EN | SDHCI_TRNS_MULTI;
- /*
- * If we are sending CMD23, CMD12 never gets sent
- * on successful completion (so no Auto-CMD12).
- */
- if (sdhci_auto_cmd12(host, cmd->mrq) &&
- (cmd->opcode != SD_IO_RW_EXTENDED))
- mode |= SDHCI_TRNS_AUTO_CMD12;
- else if (cmd->mrq->sbc && (host->flags & SDHCI_AUTO_CMD23)) {
- mode |= SDHCI_TRNS_AUTO_CMD23;
+ sdhci_auto_cmd_select(host, cmd, &mode);
+ if (cmd->mrq->sbc && (host->flags & SDHCI_AUTO_CMD23))
sdhci_writel(host, cmd->mrq->sbc->arg, SDHCI_ARGUMENT2);
- }
}
if (data->flags & MMC_DATA_READ)
@@ -1078,8 +1230,7 @@
return (!(host->flags & SDHCI_DEVICE_DEAD) &&
((mrq->cmd && mrq->cmd->error) ||
(mrq->sbc && mrq->sbc->error) ||
- (mrq->data && ((mrq->data->error && !mrq->data->stop) ||
- (mrq->data->stop && mrq->data->stop->error))) ||
+ (mrq->data && mrq->data->stop && mrq->data->stop->error) ||
(host->quirks & SDHCI_QUIRK_RESET_AFTER_REQUEST)));
}
@@ -1087,6 +1238,18 @@
{
int i;
+ if (host->cmd && host->cmd->mrq == mrq)
+ host->cmd = NULL;
+
+ if (host->data_cmd && host->data_cmd->mrq == mrq)
+ host->data_cmd = NULL;
+
+ if (host->data && host->data->mrq == mrq)
+ host->data = NULL;
+
+ if (sdhci_needs_reset(host, mrq))
+ host->pending_reset = true;
+
for (i = 0; i < SDHCI_MAX_MRQS; i++) {
if (host->mrqs_done[i] == mrq) {
WARN_ON(1);
@@ -1103,24 +1266,17 @@
WARN_ON(i >= SDHCI_MAX_MRQS);
- tasklet_schedule(&host->finish_tasklet);
+ sdhci_del_timer(host, mrq);
+
+ if (!sdhci_has_requests(host))
+ sdhci_led_deactivate(host);
}
static void sdhci_finish_mrq(struct sdhci_host *host, struct mmc_request *mrq)
{
- if (host->cmd && host->cmd->mrq == mrq)
- host->cmd = NULL;
-
- if (host->data_cmd && host->data_cmd->mrq == mrq)
- host->data_cmd = NULL;
-
- if (host->data && host->data->mrq == mrq)
- host->data = NULL;
-
- if (sdhci_needs_reset(host, mrq))
- host->pending_reset = true;
-
__sdhci_finish_mrq(host, mrq);
+
+ queue_work(host->complete_wq, &host->complete_work);
}
static void sdhci_finish_data(struct sdhci_host *host)
@@ -1131,6 +1287,16 @@
host->data = NULL;
host->data_cmd = NULL;
+ /*
+ * The controller needs a reset of internal state machines upon error
+ * conditions.
+ */
+ if (data->error) {
+ if (!host->cmd || host->cmd == data_cmd)
+ sdhci_do_reset(host, SDHCI_RESET_CMD);
+ sdhci_do_reset(host, SDHCI_RESET_DATA);
+ }
+
if ((host->flags & (SDHCI_REQ_USE_DMA | SDHCI_USE_ADMA)) ==
(SDHCI_REQ_USE_DMA | SDHCI_USE_ADMA))
sdhci_adma_table_post(host, data);
@@ -1155,51 +1321,23 @@
if (data->stop &&
(data->error ||
!data->mrq->sbc)) {
-
- /*
- * The controller needs a reset of internal state machines
- * upon error conditions.
- */
- if (data->error) {
- if (!host->cmd || host->cmd == data_cmd)
- sdhci_do_reset(host, SDHCI_RESET_CMD);
- sdhci_do_reset(host, SDHCI_RESET_DATA);
- }
-
/*
* 'cap_cmd_during_tfr' request must not use the command line
* after mmc_command_done() has been called. It is upper layer's
* responsibility to send the stop command if required.
*/
if (data->mrq->cap_cmd_during_tfr) {
- sdhci_finish_mrq(host, data->mrq);
+ __sdhci_finish_mrq(host, data->mrq);
} else {
/* Avoid triggering warning in sdhci_send_command() */
host->cmd = NULL;
sdhci_send_command(host, data->stop);
}
} else {
- sdhci_finish_mrq(host, data->mrq);
+ __sdhci_finish_mrq(host, data->mrq);
}
}
-static void sdhci_mod_timer(struct sdhci_host *host, struct mmc_request *mrq,
- unsigned long timeout)
-{
- if (sdhci_data_line_cmd(mrq->cmd))
- mod_timer(&host->data_timer, timeout);
- else
- mod_timer(&host->timer, timeout);
-}
-
-static void sdhci_del_timer(struct sdhci_host *host, struct mmc_request *mrq)
-{
- if (sdhci_data_line_cmd(mrq->cmd))
- del_timer(&host->data_timer);
- else
- del_timer(&host->timer);
-}
-
void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
{
int flags;
@@ -1359,7 +1497,7 @@
sdhci_finish_data(host);
if (!cmd->data)
- sdhci_finish_mrq(host, cmd->mrq);
+ __sdhci_finish_mrq(host, cmd->mrq);
}
}
@@ -1497,8 +1635,8 @@
clk |= SDHCI_CLOCK_INT_EN;
sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
- /* Wait max 20 ms */
- timeout = ktime_add_ms(ktime_get(), 20);
+ /* Wait max 150 ms */
+ timeout = ktime_add_ms(ktime_get(), 150);
while (1) {
bool timedout = ktime_after(ktime_get(), timeout);
@@ -1514,6 +1652,29 @@
udelay(10);
}
+ if (host->version >= SDHCI_SPEC_410 && host->v4_mode) {
+ clk |= SDHCI_CLOCK_PLL_EN;
+ clk &= ~SDHCI_CLOCK_INT_STABLE;
+ sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
+
+ /* Wait max 150 ms */
+ timeout = ktime_add_ms(ktime_get(), 150);
+ while (1) {
+ bool timedout = ktime_after(ktime_get(), timeout);
+
+ clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
+ if (clk & SDHCI_CLOCK_INT_STABLE)
+ break;
+ if (timedout) {
+ pr_err("%s: PLL clock never stabilised.\n",
+ mmc_hostname(host->mmc));
+ sdhci_dumpregs(host);
+ return;
+ }
+ udelay(10);
+ }
+ }
+
clk |= SDHCI_CLOCK_CARD_EN;
sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
}
@@ -1638,7 +1799,7 @@
* *
\*****************************************************************************/
-static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
+void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
{
struct sdhci_host *host;
int present;
@@ -1674,9 +1835,9 @@
sdhci_send_command(host, mrq->cmd);
}
- mmiowb();
spin_unlock_irqrestore(&host->lock, flags);
}
+EXPORT_SYMBOL_GPL(sdhci_request);
void sdhci_set_bus_width(struct sdhci_host *host, int width)
{
@@ -1710,7 +1871,9 @@
ctrl_2 |= SDHCI_CTRL_UHS_SDR104;
else if (timing == MMC_TIMING_UHS_SDR12)
ctrl_2 |= SDHCI_CTRL_UHS_SDR12;
- else if (timing == MMC_TIMING_UHS_SDR25)
+ else if (timing == MMC_TIMING_SD_HS ||
+ timing == MMC_TIMING_MMC_HS ||
+ timing == MMC_TIMING_UHS_SDR25)
ctrl_2 |= SDHCI_CTRL_UHS_SDR25;
else if (timing == MMC_TIMING_UHS_SDR50)
ctrl_2 |= SDHCI_CTRL_UHS_SDR50;
@@ -1876,8 +2039,6 @@
*/
if (host->quirks & SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS)
sdhci_do_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA);
-
- mmiowb();
}
EXPORT_SYMBOL_GPL(sdhci_set_ios);
@@ -1919,6 +2080,8 @@
is_readonly = 0;
else if (host->ops->get_ro)
is_readonly = host->ops->get_ro(host);
+ else if (mmc_can_gpio_ro(host->mmc))
+ is_readonly = mmc_gpio_get_ro(host->mmc);
else
is_readonly = !(sdhci_readl(host, SDHCI_PRESENT_STATE)
& SDHCI_WRITE_PROTECT);
@@ -1969,7 +2132,6 @@
sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
- mmiowb();
}
}
@@ -1982,11 +2144,6 @@
pm_runtime_get_noresume(host->mmc->parent);
spin_lock_irqsave(&host->lock, flags);
- if (enable)
- host->flags |= SDHCI_SDIO_IRQ_ENABLED;
- else
- host->flags &= ~SDHCI_SDIO_IRQ_ENABLED;
-
sdhci_enable_sdio_irq_nolock(host, enable);
spin_unlock_irqrestore(&host->lock, flags);
@@ -1995,6 +2152,16 @@
}
EXPORT_SYMBOL_GPL(sdhci_enable_sdio_irq);
+static void sdhci_ack_sdio_irq(struct mmc_host *mmc)
+{
+ struct sdhci_host *host = mmc_priv(mmc);
+ unsigned long flags;
+
+ spin_lock_irqsave(&host->lock, flags);
+ sdhci_enable_sdio_irq_nolock(host, true);
+ spin_unlock_irqrestore(&host->lock, flags);
+}
+
int sdhci_start_signal_voltage_switch(struct mmc_host *mmc,
struct mmc_ios *ios)
{
@@ -2156,7 +2323,7 @@
}
EXPORT_SYMBOL_GPL(sdhci_reset_tuning);
-static void sdhci_abort_tuning(struct sdhci_host *host, u32 opcode)
+void sdhci_abort_tuning(struct sdhci_host *host, u32 opcode)
{
sdhci_reset_tuning(host);
@@ -2167,6 +2334,7 @@
mmc_abort_tuning(host->mmc, opcode);
}
+EXPORT_SYMBOL_GPL(sdhci_abort_tuning);
/*
* We use sdhci_send_tuning() because mmc_send_tuning() is not a good fit. SDHCI
@@ -2217,7 +2385,6 @@
host->tuning_done = 0;
- mmiowb();
spin_unlock_irqrestore(&host->lock, flags);
/* Wait for Buffer Read Ready interrupt */
@@ -2227,15 +2394,15 @@
}
EXPORT_SYMBOL_GPL(sdhci_send_tuning);
-static void __sdhci_execute_tuning(struct sdhci_host *host, u32 opcode)
+static int __sdhci_execute_tuning(struct sdhci_host *host, u32 opcode)
{
int i;
/*
* Issue opcode repeatedly till Execute Tuning is set to 0 or the number
- * of loops reaches 40 times.
+ * of loops reaches tuning loop count.
*/
- for (i = 0; i < MAX_TUNING_LOOP; i++) {
+ for (i = 0; i < host->tuning_loop_count; i++) {
u16 ctrl;
sdhci_send_tuning(host, opcode);
@@ -2244,24 +2411,26 @@
pr_info("%s: Tuning timeout, falling back to fixed sampling clock\n",
mmc_hostname(host->mmc));
sdhci_abort_tuning(host, opcode);
- return;
- }
-
- ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
- if (!(ctrl & SDHCI_CTRL_EXEC_TUNING)) {
- if (ctrl & SDHCI_CTRL_TUNED_CLK)
- return; /* Success! */
- break;
+ return -ETIMEDOUT;
}
/* Spec does not require a delay between tuning cycles */
if (host->tuning_delay > 0)
mdelay(host->tuning_delay);
+
+ ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+ if (!(ctrl & SDHCI_CTRL_EXEC_TUNING)) {
+ if (ctrl & SDHCI_CTRL_TUNED_CLK)
+ return 0; /* Success! */
+ break;
+ }
+
}
pr_info("%s: Tuning failed, falling back to fixed sampling clock\n",
mmc_hostname(host->mmc));
sdhci_reset_tuning(host);
+ return -EAGAIN;
}
int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
@@ -2323,7 +2492,7 @@
sdhci_start_tuning(host);
- __sdhci_execute_tuning(host, opcode);
+ host->tuning_err = __sdhci_execute_tuning(host, opcode);
sdhci_end_tuning(host);
out:
@@ -2390,11 +2559,6 @@
sdhci_pre_dma_transfer(host, mrq->data, COOKIE_PRE_MAPPED);
}
-static inline bool sdhci_has_requests(struct sdhci_host *host)
-{
- return host->cmd || host->data_cmd;
-}
-
static void sdhci_error_out_mrqs(struct sdhci_host *host, int err)
{
if (host->data_cmd) {
@@ -2447,6 +2611,7 @@
.get_ro = sdhci_get_ro,
.hw_reset = sdhci_hw_reset,
.enable_sdio_irq = sdhci_enable_sdio_irq,
+ .ack_sdio_irq = sdhci_ack_sdio_irq,
.start_signal_voltage_switch = sdhci_start_signal_voltage_switch,
.prepare_hs400_tuning = sdhci_prepare_hs400_tuning,
.execute_tuning = sdhci_execute_tuning,
@@ -2456,7 +2621,7 @@
/*****************************************************************************\
* *
- * Tasklets *
+ * Request done *
* *
\*****************************************************************************/
@@ -2479,8 +2644,6 @@
return true;
}
- sdhci_del_timer(host, mrq);
-
/*
* Always unmap the data buffers if they were mapped by
* sdhci_prepare_data() whenever we finish with a request.
@@ -2562,12 +2725,8 @@
host->pending_reset = false;
}
- if (!sdhci_has_requests(host))
- sdhci_led_deactivate(host);
-
host->mrqs_done[i] = NULL;
- mmiowb();
spin_unlock_irqrestore(&host->lock, flags);
mmc_request_done(host->mmc, mrq);
@@ -2575,9 +2734,10 @@
return false;
}
-static void sdhci_tasklet_finish(unsigned long param)
+static void sdhci_complete_work(struct work_struct *work)
{
- struct sdhci_host *host = (struct sdhci_host *)param;
+ struct sdhci_host *host = container_of(work, struct sdhci_host,
+ complete_work);
while (!sdhci_request_done(host))
;
@@ -2601,7 +2761,6 @@
sdhci_finish_mrq(host, host->cmd->mrq);
}
- mmiowb();
spin_unlock_irqrestore(&host->lock, flags);
}
@@ -2623,6 +2782,7 @@
if (host->data) {
host->data->error = -ETIMEDOUT;
sdhci_finish_data(host);
+ queue_work(host->complete_wq, &host->complete_work);
} else if (host->data_cmd) {
host->data_cmd->error = -ETIMEDOUT;
sdhci_finish_mrq(host, host->data_cmd->mrq);
@@ -2632,7 +2792,6 @@
}
}
- mmiowb();
spin_unlock_irqrestore(&host->lock, flags);
}
@@ -2642,8 +2801,23 @@
* *
\*****************************************************************************/
-static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask)
+static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask, u32 *intmask_p)
{
+ /* Handle auto-CMD12 error */
+ if (intmask & SDHCI_INT_AUTO_CMD_ERR && host->data_cmd) {
+ struct mmc_request *mrq = host->data_cmd->mrq;
+ u16 auto_cmd_status = sdhci_readw(host, SDHCI_AUTO_CMD_STATUS);
+ int data_err_bit = (auto_cmd_status & SDHCI_AUTO_CMD_TIMEOUT) ?
+ SDHCI_INT_DATA_TIMEOUT :
+ SDHCI_INT_DATA_CRC;
+
+ /* Treat auto-CMD12 error the same as data error */
+ if (!mrq->sbc && (host->flags & SDHCI_AUTO_CMD12)) {
+ *intmask_p |= data_err_bit;
+ return;
+ }
+ }
+
if (!host->cmd) {
/*
* SDHCI recovers from errors by resetting the cmd and data
@@ -2665,27 +2839,34 @@
else
host->cmd->error = -EILSEQ;
- /*
- * If this command initiates a data phase and a response
- * CRC error is signalled, the card can start transferring
- * data - the card may have received the command without
- * error. We must not terminate the mmc_request early.
- *
- * If the card did not receive the command or returned an
- * error which prevented it sending data, the data phase
- * will time out.
- */
+ /* Treat data command CRC error the same as data CRC error */
if (host->cmd->data &&
(intmask & (SDHCI_INT_CRC | SDHCI_INT_TIMEOUT)) ==
SDHCI_INT_CRC) {
host->cmd = NULL;
+ *intmask_p |= SDHCI_INT_DATA_CRC;
return;
}
- sdhci_finish_mrq(host, host->cmd->mrq);
+ __sdhci_finish_mrq(host, host->cmd->mrq);
return;
}
+ /* Handle auto-CMD23 error */
+ if (intmask & SDHCI_INT_AUTO_CMD_ERR) {
+ struct mmc_request *mrq = host->cmd->mrq;
+ u16 auto_cmd_status = sdhci_readw(host, SDHCI_AUTO_CMD_STATUS);
+ int err = (auto_cmd_status & SDHCI_AUTO_CMD_TIMEOUT) ?
+ -ETIMEDOUT :
+ -EILSEQ;
+
+ if (mrq->sbc && (host->flags & SDHCI_AUTO_CMD23)) {
+ mrq->sbc->error = err;
+ __sdhci_finish_mrq(host, mrq);
+ return;
+ }
+ }
+
if (intmask & SDHCI_INT_RESPONSE)
sdhci_finish_command(host);
}
@@ -2693,6 +2874,7 @@
static void sdhci_adma_show_error(struct sdhci_host *host)
{
void *desc = host->adma_table;
+ dma_addr_t dma = host->adma_addr;
sdhci_dumpregs(host);
@@ -2700,18 +2882,21 @@
struct sdhci_adma2_64_desc *dma_desc = desc;
if (host->flags & SDHCI_USE_64_BIT_DMA)
- DBG("%p: DMA 0x%08x%08x, LEN 0x%04x, Attr=0x%02x\n",
- desc, le32_to_cpu(dma_desc->addr_hi),
+ SDHCI_DUMP("%08llx: DMA 0x%08x%08x, LEN 0x%04x, Attr=0x%02x\n",
+ (unsigned long long)dma,
+ le32_to_cpu(dma_desc->addr_hi),
le32_to_cpu(dma_desc->addr_lo),
le16_to_cpu(dma_desc->len),
le16_to_cpu(dma_desc->cmd));
else
- DBG("%p: DMA 0x%08x, LEN 0x%04x, Attr=0x%02x\n",
- desc, le32_to_cpu(dma_desc->addr_lo),
+ SDHCI_DUMP("%08llx: DMA 0x%08x, LEN 0x%04x, Attr=0x%02x\n",
+ (unsigned long long)dma,
+ le32_to_cpu(dma_desc->addr_lo),
le16_to_cpu(dma_desc->len),
le16_to_cpu(dma_desc->cmd));
desc += host->desc_sz;
+ dma += host->desc_sz;
if (dma_desc->cmd & cpu_to_le16(ADMA2_END))
break;
@@ -2745,7 +2930,7 @@
if (intmask & SDHCI_INT_DATA_TIMEOUT) {
host->data_cmd = NULL;
data_cmd->error = -ETIMEDOUT;
- sdhci_finish_mrq(host, data_cmd->mrq);
+ __sdhci_finish_mrq(host, data_cmd->mrq);
return;
}
if (intmask & SDHCI_INT_DATA_END) {
@@ -2758,7 +2943,7 @@
if (host->cmd == data_cmd)
return;
- sdhci_finish_mrq(host, data_cmd->mrq);
+ __sdhci_finish_mrq(host, data_cmd->mrq);
return;
}
}
@@ -2787,7 +2972,8 @@
!= MMC_BUS_TEST_R)
host->data->error = -EILSEQ;
else if (intmask & SDHCI_INT_ADMA_ERROR) {
- pr_err("%s: ADMA error\n", mmc_hostname(host->mmc));
+ pr_err("%s: ADMA error: 0x%08x\n", mmc_hostname(host->mmc),
+ intmask);
sdhci_adma_show_error(host);
host->data->error = -EIO;
if (host->ops->adma_workaround)
@@ -2810,7 +2996,7 @@
* some controllers are faulty, don't trust them.
*/
if (intmask & SDHCI_INT_DMA_END) {
- u32 dmastart, dmanow;
+ dma_addr_t dmastart, dmanow;
dmastart = sdhci_sdma_address(host);
dmanow = dmastart + host->data->bytes_xfered;
@@ -2818,12 +3004,12 @@
* Force update to the next DMA block boundary.
*/
dmanow = (dmanow &
- ~(SDHCI_DEFAULT_BOUNDARY_SIZE - 1)) +
+ ~((dma_addr_t)SDHCI_DEFAULT_BOUNDARY_SIZE - 1)) +
SDHCI_DEFAULT_BOUNDARY_SIZE;
host->data->bytes_xfered = dmanow - dmastart;
- DBG("DMA base 0x%08x, transferred 0x%06x bytes, next 0x%08x\n",
- dmastart, host->data->bytes_xfered, dmanow);
- sdhci_writel(host, dmanow, SDHCI_DMA_ADDRESS);
+ DBG("DMA base %pad, transferred 0x%06x bytes, next %pad\n",
+ &dmastart, host->data->bytes_xfered, &dmanow);
+ sdhci_set_sdma_addr(host, dmanow);
}
if (intmask & SDHCI_INT_DATA_END) {
@@ -2841,16 +3027,28 @@
}
}
+static inline bool sdhci_defer_done(struct sdhci_host *host,
+ struct mmc_request *mrq)
+{
+ struct mmc_data *data = mrq->data;
+
+ return host->pending_reset ||
+ ((host->flags & SDHCI_REQ_USE_DMA) && data &&
+ data->host_cookie == COOKIE_MAPPED);
+}
+
static irqreturn_t sdhci_irq(int irq, void *dev_id)
{
+ struct mmc_request *mrqs_done[SDHCI_MAX_MRQS] = {0};
irqreturn_t result = IRQ_NONE;
struct sdhci_host *host = dev_id;
u32 intmask, mask, unexpected = 0;
int max_loops = 16;
+ int i;
spin_lock(&host->lock);
- if (host->runtime_suspended && !sdhci_sdio_irq_enabled(host)) {
+ if (host->runtime_suspended) {
spin_unlock(&host->lock);
return IRQ_NONE;
}
@@ -2906,7 +3104,7 @@
}
if (intmask & SDHCI_INT_CMD_MASK)
- sdhci_cmd_irq(host, intmask & SDHCI_INT_CMD_MASK);
+ sdhci_cmd_irq(host, intmask & SDHCI_INT_CMD_MASK, &intmask);
if (intmask & SDHCI_INT_DATA_MASK)
sdhci_data_irq(host, intmask & SDHCI_INT_DATA_MASK);
@@ -2921,8 +3119,7 @@
if ((intmask & SDHCI_INT_CARD_INT) &&
(host->ier & SDHCI_INT_CARD_INT)) {
sdhci_enable_sdio_irq_nolock(host, false);
- host->thread_isr |= SDHCI_INT_CARD_INT;
- result = IRQ_WAKE_THREAD;
+ sdio_signal_irq(host->mmc);
}
intmask &= ~(SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE |
@@ -2940,9 +3137,30 @@
intmask = sdhci_readl(host, SDHCI_INT_STATUS);
} while (intmask && --max_loops);
+
+ /* Determine if mrqs can be completed immediately */
+ for (i = 0; i < SDHCI_MAX_MRQS; i++) {
+ struct mmc_request *mrq = host->mrqs_done[i];
+
+ if (!mrq)
+ continue;
+
+ if (sdhci_defer_done(host, mrq)) {
+ result = IRQ_WAKE_THREAD;
+ } else {
+ mrqs_done[i] = mrq;
+ host->mrqs_done[i] = NULL;
+ }
+ }
out:
spin_unlock(&host->lock);
+ /* Process mrqs ready for immediate completion */
+ for (i = 0; i < SDHCI_MAX_MRQS; i++) {
+ if (mrqs_done[i])
+ mmc_request_done(host->mmc, mrqs_done[i]);
+ }
+
if (unexpected) {
pr_err("%s: Unexpected interrupt 0x%08x.\n",
mmc_hostname(host->mmc), unexpected);
@@ -2958,6 +3176,9 @@
unsigned long flags;
u32 isr;
+ while (!sdhci_request_done(host))
+ ;
+
spin_lock_irqsave(&host->lock, flags);
isr = host->thread_isr;
host->thread_isr = 0;
@@ -2970,16 +3191,7 @@
mmc_detect_change(mmc, msecs_to_jiffies(200));
}
- if (isr & SDHCI_INT_CARD_INT) {
- sdio_run_irqs(host->mmc);
-
- spin_lock_irqsave(&host->lock, flags);
- if (host->flags & SDHCI_SDIO_IRQ_ENABLED)
- sdhci_enable_sdio_irq_nolock(host, true);
- spin_unlock_irqrestore(&host->lock, flags);
- }
-
- return isr ? IRQ_HANDLED : IRQ_NONE;
+ return IRQ_HANDLED;
}
/*****************************************************************************\
@@ -3091,7 +3303,6 @@
mmc->ops->set_ios(mmc, &mmc->ios);
} else {
sdhci_init(host, (host->mmc->pm_flags & MMC_PM_KEEP_POWER));
- mmiowb();
}
if (host->irq_wake_enabled) {
@@ -3133,7 +3344,7 @@
}
EXPORT_SYMBOL_GPL(sdhci_runtime_suspend_host);
-int sdhci_runtime_resume_host(struct sdhci_host *host)
+int sdhci_runtime_resume_host(struct sdhci_host *host, int soft_reset)
{
struct mmc_host *mmc = host->mmc;
unsigned long flags;
@@ -3144,7 +3355,7 @@
host->ops->enable_dma(host);
}
- sdhci_init(host, 0);
+ sdhci_init(host, soft_reset);
if (mmc->ios.power_mode != MMC_POWER_UNDEFINED &&
mmc->ios.power_mode != MMC_POWER_OFF) {
@@ -3171,7 +3382,7 @@
host->runtime_suspended = false;
/* Enable SDIO IRQ */
- if (host->flags & SDHCI_SDIO_IRQ_ENABLED)
+ if (sdio_irq_claimed(mmc))
sdhci_enable_sdio_irq_nolock(host, true);
/* Enable Card Detection */
@@ -3201,7 +3412,14 @@
ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
ctrl &= ~SDHCI_CTRL_DMA_MASK;
- if (host->flags & SDHCI_USE_64_BIT_DMA)
+ /*
+ * Host from V4.10 supports ADMA3 DMA type.
+ * ADMA3 performs integrated descriptor which is more suitable
+ * for cmd queuing to fetch both command and transfer descriptors.
+ */
+ if (host->v4_mode && (host->caps1 & SDHCI_CAN_DO_ADMA3))
+ ctrl |= SDHCI_CTRL_ADMA3;
+ else if (host->flags & SDHCI_USE_64_BIT_DMA)
ctrl |= SDHCI_CTRL_ADMA64;
else
ctrl |= SDHCI_CTRL_ADMA32;
@@ -3211,7 +3429,7 @@
SDHCI_BLOCK_SIZE);
/* Set maximum timeout */
- sdhci_writeb(host, 0xE, SDHCI_TIMEOUT_CONTROL);
+ sdhci_set_timeout(host, NULL);
host->ier = host->cqe_ier;
@@ -3224,7 +3442,6 @@
mmc_hostname(mmc), host->ier,
sdhci_readl(host, SDHCI_INT_STATUS));
- mmiowb();
spin_unlock_irqrestore(&host->lock, flags);
}
EXPORT_SYMBOL_GPL(sdhci_cqe_enable);
@@ -3249,7 +3466,6 @@
mmc_hostname(mmc), host->ier,
sdhci_readl(host, SDHCI_INT_STATUS));
- mmiowb();
spin_unlock_irqrestore(&host->lock, flags);
}
EXPORT_SYMBOL_GPL(sdhci_cqe_disable);
@@ -3327,9 +3543,17 @@
host->cqe_err_ier = SDHCI_CQE_INT_ERR_MASK;
host->tuning_delay = -1;
+ host->tuning_loop_count = MAX_TUNING_LOOP;
host->sdma_boundary = SDHCI_DEFAULT_BOUNDARY_ARG;
+ /*
+ * The DMA table descriptor count is calculated as the maximum
+ * number of segments times 2, to allow for an alignment
+ * descriptor for each segment, plus 1 for a nop end descriptor.
+ */
+ host->adma_table_cnt = SDHCI_MAX_SEGS * 2 + 1;
+
return host;
}
@@ -3365,7 +3589,8 @@
return ret;
}
-void __sdhci_read_caps(struct sdhci_host *host, u16 *ver, u32 *caps, u32 *caps1)
+void __sdhci_read_caps(struct sdhci_host *host, const u16 *ver,
+ const u32 *caps, const u32 *caps1)
{
u16 v;
u64 dt_caps_mask = 0;
@@ -3384,6 +3609,9 @@
sdhci_do_reset(host, SDHCI_RESET_ALL);
+ if (host->v4_mode)
+ sdhci_do_enable_v4_mode(host);
+
of_property_read_u64(mmc_dev(host->mmc)->of_node,
"sdhci-caps-mask", &dt_caps_mask);
of_property_read_u64(mmc_dev(host->mmc)->of_node,
@@ -3416,7 +3644,7 @@
}
EXPORT_SYMBOL_GPL(__sdhci_read_caps);
-static int sdhci_allocate_bounce_buffer(struct sdhci_host *host)
+static void sdhci_allocate_bounce_buffer(struct sdhci_host *host)
{
struct mmc_host *mmc = host->mmc;
unsigned int max_blocks;
@@ -3454,7 +3682,7 @@
* Exiting with zero here makes sure we proceed with
* mmc->max_segs == 1.
*/
- return 0;
+ return;
}
host->bounce_addr = dma_map_single(mmc->parent,
@@ -3464,7 +3692,7 @@
ret = dma_mapping_error(mmc->parent, host->bounce_addr);
if (ret)
/* Again fall back to max_segs == 1 */
- return 0;
+ return;
host->bounce_buffer_size = bounce_size;
/* Lie about this since we're bouncing */
@@ -3474,8 +3702,19 @@
pr_info("%s bounce up to %u segments into one, max segment size %u bytes\n",
mmc_hostname(mmc), max_blocks, bounce_size);
+}
- return 0;
+static inline bool sdhci_can_64bit_dma(struct sdhci_host *host)
+{
+ /*
+ * According to SD Host Controller spec v4.10, bit[27] added from
+ * version 4.10 in Capabilities Register is used as 64-bit System
+ * Address support for V4 mode.
+ */
+ if (host->version >= SDHCI_SPEC_410 && host->v4_mode)
+ return host->caps & SDHCI_CAN_64BIT_V4;
+
+ return host->caps & SDHCI_CAN_64BIT;
}
int sdhci_setup_host(struct sdhci_host *host)
@@ -3514,7 +3753,7 @@
override_timeout_clk = host->timeout_clk;
- if (host->version > SDHCI_SPEC_300) {
+ if (host->version > SDHCI_SPEC_420) {
pr_err("%s: Unknown controller version (%d). You may experience problems.\n",
mmc_hostname(mmc), host->version);
}
@@ -3542,18 +3781,14 @@
host->flags &= ~SDHCI_USE_ADMA;
}
- /*
- * It is assumed that a 64-bit capable device has set a 64-bit DMA mask
- * and *must* do 64-bit DMA. A driver has the opportunity to change
- * that during the first call to ->enable_dma(). Similarly
- * SDHCI_QUIRK2_BROKEN_64_BIT_DMA must be left to the drivers to
- * implement.
- */
- if (host->caps & SDHCI_CAN_64BIT)
+ if (sdhci_can_64bit_dma(host))
host->flags |= SDHCI_USE_64_BIT_DMA;
if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) {
- ret = sdhci_set_dma_mask(host);
+ if (host->ops->set_dma_mask)
+ ret = host->ops->set_dma_mask(host);
+ else
+ ret = sdhci_set_dma_mask(host);
if (!ret && host->ops->enable_dma)
ret = host->ops->enable_dma(host);
@@ -3567,33 +3802,32 @@
}
}
- /* SDMA does not support 64-bit DMA */
- if (host->flags & SDHCI_USE_64_BIT_DMA)
+ /* SDMA does not support 64-bit DMA if v4 mode not set */
+ if ((host->flags & SDHCI_USE_64_BIT_DMA) && !host->v4_mode)
host->flags &= ~SDHCI_USE_SDMA;
if (host->flags & SDHCI_USE_ADMA) {
dma_addr_t dma;
void *buf;
- /*
- * The DMA descriptor table size is calculated as the maximum
- * number of segments times 2, to allow for an alignment
- * descriptor for each segment, plus 1 for a nop end descriptor,
- * all multipled by the descriptor size.
- */
if (host->flags & SDHCI_USE_64_BIT_DMA) {
- host->adma_table_sz = (SDHCI_MAX_SEGS * 2 + 1) *
- SDHCI_ADMA2_64_DESC_SZ;
- host->desc_sz = SDHCI_ADMA2_64_DESC_SZ;
+ host->adma_table_sz = host->adma_table_cnt *
+ SDHCI_ADMA2_64_DESC_SZ(host);
+ host->desc_sz = SDHCI_ADMA2_64_DESC_SZ(host);
} else {
- host->adma_table_sz = (SDHCI_MAX_SEGS * 2 + 1) *
+ host->adma_table_sz = host->adma_table_cnt *
SDHCI_ADMA2_32_DESC_SZ;
host->desc_sz = SDHCI_ADMA2_32_DESC_SZ;
}
host->align_buffer_sz = SDHCI_MAX_SEGS * SDHCI_ADMA2_ALIGN;
- buf = dma_alloc_coherent(mmc_dev(mmc), host->align_buffer_sz +
- host->adma_table_sz, &dma, GFP_KERNEL);
+ /*
+ * Use zalloc to zero the reserved high 32-bits of 128-bit
+ * descriptors so that they never need to be written.
+ */
+ buf = dma_alloc_coherent(mmc_dev(mmc),
+ host->align_buffer_sz + host->adma_table_sz,
+ &dma, GFP_KERNEL);
if (!buf) {
pr_warn("%s: Unable to allocate ADMA buffers - falling back to standard DMA\n",
mmc_hostname(mmc));
@@ -3716,10 +3950,13 @@
if (host->quirks & SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12)
host->flags |= SDHCI_AUTO_CMD12;
- /* Auto-CMD23 stuff only works in ADMA or PIO. */
+ /*
+ * For v3 mode, Auto-CMD23 stuff only works in ADMA or PIO.
+ * For v4 mode, SDMA may use Auto-CMD23 as well.
+ */
if ((host->version >= SDHCI_SPEC_300) &&
((host->flags & SDHCI_USE_ADMA) ||
- !(host->flags & SDHCI_USE_SDMA)) &&
+ !(host->flags & SDHCI_USE_SDMA) || host->v4_mode) &&
!(host->quirks2 & SDHCI_QUIRK2_ACMD23_BROKEN)) {
host->flags |= SDHCI_AUTO_CMD23;
DBG("Auto-CMD23 available\n");
@@ -3995,12 +4232,9 @@
*/
mmc->max_blk_count = (host->quirks & SDHCI_QUIRK_NO_MULTIBLOCK) ? 1 : 65535;
- if (mmc->max_segs == 1) {
+ if (mmc->max_segs == 1)
/* This may alter mmc->*_blk_* parameters */
- ret = sdhci_allocate_bounce_buffer(host);
- if (ret)
- return ret;
- }
+ sdhci_allocate_bounce_buffer(host);
return 0;
@@ -4037,14 +4271,15 @@
int __sdhci_add_host(struct sdhci_host *host)
{
+ unsigned int flags = WQ_UNBOUND | WQ_MEM_RECLAIM | WQ_HIGHPRI;
struct mmc_host *mmc = host->mmc;
int ret;
- /*
- * Init tasklets.
- */
- tasklet_init(&host->finish_tasklet,
- sdhci_tasklet_finish, (unsigned long)host);
+ host->complete_wq = alloc_workqueue("sdhci", flags, 0);
+ if (!host->complete_wq)
+ return -ENOMEM;
+
+ INIT_WORK(&host->complete_work, sdhci_complete_work);
timer_setup(&host->timer, sdhci_timeout_timer, 0);
timer_setup(&host->data_timer, sdhci_timeout_data_timer, 0);
@@ -4058,7 +4293,7 @@
if (ret) {
pr_err("%s: Failed to request IRQ %d: %d\n",
mmc_hostname(mmc), host->irq, ret);
- goto untasklet;
+ goto unwq;
}
ret = sdhci_led_register(host);
@@ -4068,8 +4303,6 @@
goto unirq;
}
- mmiowb();
-
ret = mmc_add_host(mmc);
if (ret)
goto unled;
@@ -4091,8 +4324,8 @@
sdhci_writel(host, 0, SDHCI_INT_ENABLE);
sdhci_writel(host, 0, SDHCI_SIGNAL_ENABLE);
free_irq(host->irq, host);
-untasklet:
- tasklet_kill(&host->finish_tasklet);
+unwq:
+ destroy_workqueue(host->complete_wq);
return ret;
}
@@ -4154,7 +4387,7 @@
del_timer_sync(&host->timer);
del_timer_sync(&host->data_timer);
- tasklet_kill(&host->finish_tasklet);
+ destroy_workqueue(host->complete_wq);
if (!IS_ERR(mmc->supply.vqmmc))
regulator_disable(mmc->supply.vqmmc);