diff options
Diffstat (limited to 'drivers/mmc')
| -rw-r--r-- | drivers/mmc/card/block.c | 47 | ||||
| -rw-r--r-- | drivers/mmc/card/queue.c | 5 | ||||
| -rw-r--r-- | drivers/mmc/core/bus.c | 3 | ||||
| -rw-r--r-- | drivers/mmc/core/core.c | 64 | ||||
| -rw-r--r-- | drivers/mmc/core/host.c | 5 | ||||
| -rw-r--r-- | drivers/mmc/core/mmc.c | 2 | ||||
| -rw-r--r-- | drivers/mmc/core/sd.c | 20 | ||||
| -rw-r--r-- | drivers/mmc/host/dw_mmc.c | 6 | ||||
| -rw-r--r-- | drivers/mmc/host/jz4740_mmc.c | 2 | ||||
| -rw-r--r-- | drivers/mmc/host/omap_hsmmc.c | 4 | ||||
| -rw-r--r-- | drivers/mmc/host/sdhci-msm.c | 43 | ||||
| -rw-r--r-- | drivers/mmc/host/sdhci-of-esdhc.c | 14 |
12 files changed, 180 insertions, 35 deletions
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index 7d2ceda7f80e..13e0df67d3b7 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -1048,6 +1048,12 @@ static int mmc_blk_ioctl_rpmb_cmd(struct block_device *bdev, goto idata_free; } + /* + * Ensure rpmb_req_pending flag is synchronized between multiple + * entities which may use rpmb ioclts with a lock. + */ + mutex_lock(&card->host->rpmb_req_mutex); + atomic_set(&card->host->rpmb_req_pending, 1); mmc_get_card(card); if (mmc_card_doing_bkops(card)) { @@ -1163,6 +1169,9 @@ static int mmc_blk_ioctl_rpmb_cmd(struct block_device *bdev, cmd_rel_host: mmc_put_card(card); + atomic_set(&card->host->rpmb_req_pending, 0); + mutex_unlock(&card->host->rpmb_req_mutex); + idata_free: for (i = 0; i < MMC_IOC_MAX_RPMB_CMD; i++) { @@ -1292,9 +1301,26 @@ static int mmc_blk_ioctl_multi_cmd(struct block_device *bdev, mmc_get_card(card); + if (mmc_card_cmdq(card)) { + err = mmc_cmdq_halt(card->host, true); + if (err) { + pr_err("%s: halt failed while doing %s err (%d)\n", + mmc_hostname(card->host), + __func__, err); + mmc_put_card(card); + goto cmd_done; + } + } + for (i = 0; i < num_of_cmds && !ioc_err; i++) ioc_err = __mmc_blk_ioctl_cmd(card, md, idata[i]); + if (mmc_card_cmdq(card)) { + if (mmc_cmdq_halt(card->host, false)) + pr_err("%s: %s: cmdq unhalt failed\n", + mmc_hostname(card->host), __func__); + } + mmc_put_card(card); /* copy to user if data and response */ @@ -3173,11 +3199,11 @@ static struct mmc_cmdq_req *mmc_blk_cmdq_rw_prep( static void mmc_blk_cmdq_requeue_rw_rq(struct mmc_queue *mq, struct request *req) { - struct mmc_card *card = mq->card; - struct mmc_host *host = card->host; + struct request_queue *q = req->q; - blk_requeue_request(req->q, req); - mmc_put_card(host->card); + spin_lock_irq(q->queue_lock); + blk_requeue_request(q, req); + spin_unlock_irq(q->queue_lock); } static int mmc_blk_cmdq_issue_rw_rq(struct mmc_queue *mq, struct request *req) @@ -3605,7 +3631,7 @@ void mmc_blk_cmdq_complete_rq(struct request *rq) * or disable state so cannot receive any completion of * other requests. */ - BUG_ON(test_bit(CMDQ_STATE_ERR, &ctx_info->curr_state)); + WARN_ON(test_bit(CMDQ_STATE_ERR, &ctx_info->curr_state)); /* clear pending request */ BUG_ON(!test_and_clear_bit(cmdq_req->tag, @@ -3639,7 +3665,7 @@ void mmc_blk_cmdq_complete_rq(struct request *rq) out: mmc_cmdq_clk_scaling_stop_busy(host, true, is_dcmd); - if (!test_bit(CMDQ_STATE_ERR, &ctx_info->curr_state)) { + if (!(err || cmdq_req->resp_err)) { mmc_host_clk_release(host); wake_up(&ctx_info->wait); mmc_put_card(host->card); @@ -4065,9 +4091,16 @@ static int mmc_blk_cmdq_issue_rq(struct mmc_queue *mq, struct request *req) * If issuing of the request fails with eitehr EBUSY or * EAGAIN error, re-queue the request. * This case would occur with ICE calls. + * For request which gets completed successfully or + * errored out, we release host lock in completion or + * error handling softirq context. But here the request + * is neither completed nor erred-out, so release the + * host lock explicitly. */ - if (ret == -EBUSY || ret == -EAGAIN) + if (ret == -EBUSY || ret == -EAGAIN) { mmc_blk_cmdq_requeue_rw_rq(mq, req); + mmc_put_card(host->card); + } } } diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c index ccf22eb5bdc0..397bbd09034d 100644 --- a/drivers/mmc/card/queue.c +++ b/drivers/mmc/card/queue.c @@ -95,7 +95,9 @@ static inline void mmc_cmdq_ready_wait(struct mmc_host *host, * be any other direct command active. * 3. cmdq state should be unhalted. * 4. cmdq state shouldn't be in error state. - * 5. free tag available to process the new request. + * 5. There is no outstanding RPMB request pending. + * 6. free tag available to process the new request. + * (This must be the last condtion to check) */ wait_event(ctx->wait, kthread_should_stop() || (mmc_peek_request(mq) && @@ -106,6 +108,7 @@ static inline void mmc_cmdq_ready_wait(struct mmc_host *host, && !(!host->card->part_curr && mmc_host_cq_disable(host) && !mmc_card_suspended(host->card)) && !test_bit(CMDQ_STATE_ERR, &ctx->curr_state) + && !atomic_read(&host->rpmb_req_pending) && !mmc_check_blk_queue_start_tag(q, mq->cmdq_req_peeked))); } diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c index 548a9e8b72ae..0b527a708bd7 100644 --- a/drivers/mmc/core/bus.c +++ b/drivers/mmc/core/bus.c @@ -373,12 +373,13 @@ int mmc_add_card(struct mmc_card *card) mmc_card_ddr52(card) ? "DDR " : "", type); } else { - pr_info("%s: new %s%s%s%s%s card at address %04x\n", + pr_info("%s: new %s%s%s%s%s%s card at address %04x\n", mmc_hostname(card->host), mmc_card_uhs(card) ? "ultra high speed " : (mmc_card_hs(card) ? "high speed " : ""), mmc_card_hs400(card) ? "HS400 " : (mmc_card_hs200(card) ? "HS200 " : ""), + mmc_card_hs400es(card) ? "Enhanced strobe " : "", mmc_card_ddr52(card) ? "DDR " : "", uhs_bus_speed_mode, type, card->rca); } diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index d1d045f04368..547d18c9feef 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -1170,6 +1170,46 @@ static int mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) return 0; } +static int mmc_cmdq_check_retune(struct mmc_host *host) +{ + bool cmdq_mode; + int err = 0; + + if (!host->need_retune || host->doing_retune || !host->card || + mmc_card_hs400es(host->card) || + (host->ios.clock <= MMC_HIGH_DDR_MAX_DTR)) + return 0; + + cmdq_mode = mmc_card_cmdq(host->card); + if (cmdq_mode) { + err = mmc_cmdq_halt(host, true); + if (err) { + pr_err("%s: %s: failed halting queue (%d)\n", + mmc_hostname(host), __func__, err); + host->cmdq_ops->dumpstate(host); + goto halt_failed; + } + } + + mmc_retune_hold(host); + err = mmc_retune(host); + mmc_retune_release(host); + + if (cmdq_mode) { + if (mmc_cmdq_halt(host, false)) { + pr_err("%s: %s: cmdq unhalt failed\n", + mmc_hostname(host), __func__); + host->cmdq_ops->dumpstate(host); + } + } + +halt_failed: + pr_debug("%s: %s: Retuning done err: %d\n", + mmc_hostname(host), __func__, err); + + return err; +} + static int mmc_start_cmdq_request(struct mmc_host *host, struct mmc_request *mrq) { @@ -1196,6 +1236,7 @@ static int mmc_start_cmdq_request(struct mmc_host *host, } mmc_host_clk_hold(host); + mmc_cmdq_check_retune(host); if (likely(host->cmdq_ops->request)) { ret = host->cmdq_ops->request(host, mrq); } else { @@ -1558,7 +1599,8 @@ static void mmc_wait_for_req_done(struct mmc_host *host, mmc_card_removed(host->card)) { if (cmd->error && !cmd->retries && cmd->opcode != MMC_SEND_STATUS && - cmd->opcode != MMC_SEND_TUNING_BLOCK) + cmd->opcode != MMC_SEND_TUNING_BLOCK && + cmd->opcode != MMC_SEND_TUNING_BLOCK_HS200) mmc_recovery_fallback_lower_speed(host); break; } @@ -2969,8 +3011,16 @@ int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage, u32 ocr) */ mmc_host_clk_hold(host); err = mmc_wait_for_cmd(host, &cmd, 0); - if (err) - goto err_command; + if (err) { + if (err == -ETIMEDOUT) { + pr_debug("%s: voltage switching failed with err %d\n", + mmc_hostname(host), err); + err = -EAGAIN; + goto power_cycle; + } else { + goto err_command; + } + } if (!mmc_host_is_spi(host) && (cmd.resp[0] & R1_ERROR)) { err = -EIO; @@ -4493,6 +4543,14 @@ int mmc_pm_notify(struct notifier_block *notify_block, if (!err) break; + if (!mmc_card_is_removable(host)) { + dev_warn(mmc_dev(host), + "pre_suspend failed for non-removable host: " + "%d\n", err); + /* Avoid removing non-removable hosts */ + break; + } + /* Calling bus_ops->remove() with a claimed host can deadlock */ host->bus_ops->remove(host); mmc_claim_host(host); diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c index 88699f852aa2..b3b9d78f789a 100644 --- a/drivers/mmc/core/host.c +++ b/drivers/mmc/core/host.c @@ -388,7 +388,8 @@ int mmc_retune(struct mmc_host *host) else return 0; - if (!host->need_retune || host->doing_retune || !host->card) + if (!host->need_retune || host->doing_retune || !host->card || + mmc_card_hs400es(host->card)) return 0; host->need_retune = 0; @@ -635,6 +636,8 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev) #endif setup_timer(&host->retune_timer, mmc_retune_timer, (unsigned long)host); + mutex_init(&host->rpmb_req_mutex); + /* * By default, hosts do not support SGIO or large requests. * They have to set these according to their abilities. diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 6f4f81a370d8..c8f85b31e2ac 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -1275,6 +1275,8 @@ static int mmc_select_hs400(struct mmc_card *card) if (card->ext_csd.strobe_support && host->ops->enhanced_strobe) { mmc_host_clk_hold(host); err = host->ops->enhanced_strobe(host); + if (!err) + host->ios.enhanced_strobe = true; mmc_host_clk_release(host); } else if ((host->caps2 & MMC_CAP2_HS400_POST_TUNING) && host->ops->execute_tuning) { diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index 65d7dbe1dea4..2aa04b6bdfb3 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -335,6 +335,7 @@ static int mmc_read_switch(struct mmc_card *card) card->sw_caps.sd3_bus_mode = status[13]; /* Driver Strengths supported by the card */ card->sw_caps.sd3_drv_type = status[9]; + card->sw_caps.sd3_curr_limit = status[7] | status[6] << 8; } out: @@ -557,14 +558,25 @@ static int sd_set_current_limit(struct mmc_card *card, u8 *status) * when we set current limit to 200ma, the card will draw 200ma, and * when we set current limit to 400/600/800ma, the card will draw its * maximum 300ma from the host. + * + * The above is incorrect: if we try to set a current limit that is + * not supported by the card, the card can rightfully error out the + * attempt, and remain at the default current limit. This results + * in a 300mA card being limited to 200mA even though the host + * supports 800mA. Failures seen with SanDisk 8GB UHS cards with + * an iMX6 host. --rmk */ - if (max_current >= 800) + if (max_current >= 800 && + card->sw_caps.sd3_curr_limit & SD_MAX_CURRENT_800) current_limit = SD_SET_CURRENT_LIMIT_800; - else if (max_current >= 600) + else if (max_current >= 600 && + card->sw_caps.sd3_curr_limit & SD_MAX_CURRENT_600) current_limit = SD_SET_CURRENT_LIMIT_600; - else if (max_current >= 400) + else if (max_current >= 400 && + card->sw_caps.sd3_curr_limit & SD_MAX_CURRENT_400) current_limit = SD_SET_CURRENT_LIMIT_400; - else if (max_current >= 200) + else if (max_current >= 200 && + card->sw_caps.sd3_curr_limit & SD_MAX_CURRENT_200) current_limit = SD_SET_CURRENT_LIMIT_200; if (current_limit != SD_SET_CURRENT_NO_CHANGE) { diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index fb204ee6ff89..581f5d0271f4 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -619,6 +619,7 @@ static int dw_mci_idmac_init(struct dw_mci *host) (sizeof(struct idmac_desc_64addr) * (i + 1))) >> 32; /* Initialize reserved and buffer size fields to "0" */ + p->des0 = 0; p->des1 = 0; p->des2 = 0; p->des3 = 0; @@ -640,6 +641,7 @@ static int dw_mci_idmac_init(struct dw_mci *host) i++, p++) { p->des3 = cpu_to_le32(host->sg_dma + (sizeof(struct idmac_desc) * (i + 1))); + p->des0 = 0; p->des1 = 0; } @@ -2807,8 +2809,8 @@ static bool dw_mci_reset(struct dw_mci *host) } if (host->use_dma == TRANS_MODE_IDMAC) - /* It is also recommended that we reset and reprogram idmac */ - dw_mci_idmac_reset(host); + /* It is also required that we reinit idmac */ + dw_mci_idmac_init(host); ret = true; diff --git a/drivers/mmc/host/jz4740_mmc.c b/drivers/mmc/host/jz4740_mmc.c index 76e8bce6f46e..ad572a0f2124 100644 --- a/drivers/mmc/host/jz4740_mmc.c +++ b/drivers/mmc/host/jz4740_mmc.c @@ -368,9 +368,9 @@ static void jz4740_mmc_set_irq_enabled(struct jz4740_mmc_host *host, host->irq_mask &= ~irq; else host->irq_mask |= irq; - spin_unlock_irqrestore(&host->lock, flags); writew(host->irq_mask, host->base + JZ_REG_MMC_IMASK); + spin_unlock_irqrestore(&host->lock, flags); } static void jz4740_mmc_clock_enable(struct jz4740_mmc_host *host, diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 7fb0753abe30..6b814d7d6560 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -1776,8 +1776,8 @@ static int omap_hsmmc_configure_wake_irq(struct omap_hsmmc_host *host) */ if (host->pdata->controller_flags & OMAP_HSMMC_SWAKEUP_MISSING) { struct pinctrl *p = devm_pinctrl_get(host->dev); - if (!p) { - ret = -ENODEV; + if (IS_ERR(p)) { + ret = PTR_ERR(p); goto err_free_irq; } if (IS_ERR(pinctrl_lookup_state(p, PINCTRL_STATE_DEFAULT))) { diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index aea00ce708b6..81a781c1f9d6 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -39,6 +39,7 @@ #include <linux/msm-bus.h> #include <linux/pm_runtime.h> #include <trace/events/mmc.h> +#include <soc/qcom/boot_stats.h> #include "sdhci-msm.h" #include "sdhci-msm-ice.h" @@ -801,19 +802,23 @@ static int msm_init_cm_dll(struct sdhci_host *host) | CORE_CK_OUT_EN), host->ioaddr + msm_host_offset->CORE_DLL_CONFIG); - wait_cnt = 50; - /* Wait until DLL_LOCK bit of DLL_STATUS register becomes '1' */ - while (!(readl_relaxed(host->ioaddr + - msm_host_offset->CORE_DLL_STATUS) & CORE_DLL_LOCK)) { - /* max. wait for 50us sec for LOCK bit to be set */ - if (--wait_cnt == 0) { - pr_err("%s: %s: DLL failed to LOCK\n", - mmc_hostname(mmc), __func__); - rc = -ETIMEDOUT; - goto out; + /* For hs400es mode, no need to wait for core dll lock */ + if (!(msm_host->enhanced_strobe && + mmc_card_strobe(msm_host->mmc->card))) { + wait_cnt = 50; + /* Wait until DLL_LOCK bit of DLL_STATUS register becomes '1' */ + while (!(readl_relaxed(host->ioaddr + + msm_host_offset->CORE_DLL_STATUS) & CORE_DLL_LOCK)) { + /* max. wait for 50us sec for LOCK bit to be set */ + if (--wait_cnt == 0) { + pr_err("%s: %s: DLL failed to LOCK\n", + mmc_hostname(mmc), __func__); + rc = -ETIMEDOUT; + goto out; + } + /* wait for 1us before polling again */ + udelay(1); } - /* wait for 1us before polling again */ - udelay(1); } out: @@ -3166,7 +3171,10 @@ static void sdhci_msm_set_clock(struct sdhci_host *host, unsigned int clock) | CORE_HC_SELECT_IN_EN), host->ioaddr + msm_host_offset->CORE_VENDOR_SPEC); } - if (!host->mmc->ios.old_rate && !msm_host->use_cdclp533) { + /* No need to check for DLL lock for HS400es mode */ + if (!host->mmc->ios.old_rate && !msm_host->use_cdclp533 && + !((card && mmc_card_strobe(card) && + msm_host->enhanced_strobe))) { /* * Poll on DLL_LOCK and DDR_DLL_LOCK bits in * CORE_DLL_STATUS to be set. This should get set @@ -4250,6 +4258,7 @@ static int sdhci_msm_probe(struct platform_device *pdev) void __iomem *tlmm_mem; unsigned long flags; bool force_probe; + char boot_marker[40]; pr_debug("%s: Enter %s\n", dev_name(&pdev->dev), __func__); msm_host = devm_kzalloc(&pdev->dev, sizeof(struct sdhci_msm_host), @@ -4274,6 +4283,10 @@ static int sdhci_msm_probe(struct platform_device *pdev) goto out_host_free; } + snprintf(boot_marker, sizeof(boot_marker), + "M - DRIVER %s Init", mmc_hostname(host->mmc)); + place_marker(boot_marker); + pltfm_host = sdhci_priv(host); pltfm_host->priv = msm_host; msm_host->mmc = host->mmc; @@ -4747,6 +4760,10 @@ static int sdhci_msm_probe(struct platform_device *pdev) if (sdhci_msm_is_bootdevice(&pdev->dev)) mmc_flush_detect_work(host->mmc); + snprintf(boot_marker, sizeof(boot_marker), + "M - DRIVER %s Ready", mmc_hostname(host->mmc)); + place_marker(boot_marker); + /* Successful initialization */ goto out; diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c index 83b1226471c1..ac66c61d9433 100644 --- a/drivers/mmc/host/sdhci-of-esdhc.c +++ b/drivers/mmc/host/sdhci-of-esdhc.c @@ -418,6 +418,20 @@ static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock) if (esdhc->vendor_ver < VENDOR_V_23) pre_div = 2; + /* + * Limit SD clock to 167MHz for ls1046a according to its datasheet + */ + if (clock > 167000000 && + of_find_compatible_node(NULL, NULL, "fsl,ls1046a-esdhc")) + clock = 167000000; + + /* + * Limit SD clock to 125MHz for ls1012a according to its datasheet + */ + if (clock > 125000000 && + of_find_compatible_node(NULL, NULL, "fsl,ls1012a-esdhc")) + clock = 125000000; + /* Workaround to reduce the clock frequency for p1010 esdhc */ if (of_find_compatible_node(NULL, NULL, "fsl,p1010-esdhc")) { if (clock > 20000000) |
