diff options
Diffstat (limited to 'drivers/mmc')
| -rw-r--r-- | drivers/mmc/card/block.c | 26 | ||||
| -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 | 52 | ||||
| -rw-r--r-- | drivers/mmc/core/host.c | 5 | ||||
| -rw-r--r-- | drivers/mmc/core/mmc.c | 2 | ||||
| -rw-r--r-- | drivers/mmc/host/dw_mmc.c | 6 | ||||
| -rw-r--r-- | drivers/mmc/host/omap_hsmmc.c | 4 | ||||
| -rw-r--r-- | drivers/mmc/host/sdhci-of-esdhc.c | 14 |
9 files changed, 104 insertions, 13 deletions
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index 7d2ceda7f80e..de7def1f4f1c 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++) { @@ -3173,11 +3182,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) @@ -4065,9 +4074,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..2af0e819d0cb 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; } @@ -4493,6 +4535,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/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/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-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) |
