From 20348d1981da783d125c8265ce2ba7e3f2a24103 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Wed, 19 Oct 2016 11:04:42 +0200 Subject: mmc: core: Make mmc_switch_status() available for mmc core Following changes needs mmc_switch_status() to be available both from mmc.c and mmc_ops.c. Allow that by moving its implementation to mmc_ops.c and make it available via mmc_ops.h. Moving mmc_switch_status() to mmc_ops.c, also enables us to turn mmc_switch_status_error() into static function. So let's take the opportunity to change this as well. Signed-off-by: Ulf Hansson Acked-by: Jaehoon Chung Tested-by: Jaehoon Chung --- drivers/mmc/core/mmc.c | 13 ------------- drivers/mmc/core/mmc_ops.c | 15 ++++++++++++++- drivers/mmc/core/mmc_ops.h | 2 +- 3 files changed, 15 insertions(+), 15 deletions(-) (limited to 'drivers/mmc/core') diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index df19777068a6..9355366d3259 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -1003,19 +1003,6 @@ static int mmc_select_bus_width(struct mmc_card *card) return err; } -/* Caller must hold re-tuning */ -static int mmc_switch_status(struct mmc_card *card) -{ - u32 status; - int err; - - err = mmc_send_status(card, &status); - if (err) - return err; - - return mmc_switch_status_error(card->host, status); -} - /* * Switch to the high-speed mode */ diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c index ad6e9798e949..f9af1c0c0bd6 100644 --- a/drivers/mmc/core/mmc_ops.c +++ b/drivers/mmc/core/mmc_ops.c @@ -440,7 +440,7 @@ int mmc_spi_set_crc(struct mmc_host *host, int use_crc) return err; } -int mmc_switch_status_error(struct mmc_host *host, u32 status) +static int mmc_switch_status_error(struct mmc_host *host, u32 status) { if (mmc_host_is_spi(host)) { if (status & R1_SPI_ILLEGAL_COMMAND) @@ -455,6 +455,19 @@ int mmc_switch_status_error(struct mmc_host *host, u32 status) return 0; } +/* Caller must hold re-tuning */ +int mmc_switch_status(struct mmc_card *card) +{ + u32 status; + int err; + + err = mmc_send_status(card, &status); + if (err) + return err; + + return mmc_switch_status_error(card->host, status); +} + /** * __mmc_switch - modify EXT_CSD register * @card: the MMC card associated with the data transfer diff --git a/drivers/mmc/core/mmc_ops.h b/drivers/mmc/core/mmc_ops.h index f1b8e81aaa28..7f6c0e98e7f5 100644 --- a/drivers/mmc/core/mmc_ops.h +++ b/drivers/mmc/core/mmc_ops.h @@ -27,7 +27,7 @@ int mmc_spi_set_crc(struct mmc_host *host, int use_crc); int mmc_bus_test(struct mmc_card *card, u8 bus_width); int mmc_send_hpi_cmd(struct mmc_card *card, u32 *status); int mmc_can_ext_csd(struct mmc_card *card); -int mmc_switch_status_error(struct mmc_host *host, u32 status); +int mmc_switch_status(struct mmc_card *card); int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value, unsigned int timeout_ms, bool use_busy_signal, bool send_status, bool ignore_crc); -- cgit v1.2.3 From cb26ce069ffa87a1d237d0288176aac8ff79bffa Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Wed, 19 Oct 2016 11:35:12 +0200 Subject: mmc: core: Clarify code which deals with polling in __mmc_switch() The __mmc_switch() deserves a clean-up. In this step, let's move some code outside of the do-while loop, which deal deals with the card busy polling. This change simplifies the code in that sense that it becomes easier to follow what is being executed during card busy polling, but it also gives a better understanding for when polling isn't done. Signed-off-by: Ulf Hansson Acked-by: Jaehoon Chung Tested-by: Jaehoon Chung --- drivers/mmc/core/mmc_ops.c | 39 ++++++++++++++++++--------------------- 1 file changed, 18 insertions(+), 21 deletions(-) (limited to 'drivers/mmc/core') diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c index f9af1c0c0bd6..5a77af7a24b3 100644 --- a/drivers/mmc/core/mmc_ops.c +++ b/drivers/mmc/core/mmc_ops.c @@ -535,18 +535,29 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value, if (!use_busy_signal) goto out; - /* - * CRC errors shall only be ignored in cases were CMD13 is used to poll - * to detect busy completion. - */ - if ((host->caps & MMC_CAP_WAIT_WHILE_BUSY) && use_r1b_resp) - ignore_crc = false; + /*If SPI or used HW busy detection above, then we don't need to poll. */ + if (((host->caps & MMC_CAP_WAIT_WHILE_BUSY) && use_r1b_resp) || + mmc_host_is_spi(host)) { + if (send_status) + err = mmc_switch_status(card); + goto out; + } /* We have an unspecified cmd timeout, use the fallback value. */ if (!timeout_ms) timeout_ms = MMC_OPS_TIMEOUT_MS; - /* Must check status to be sure of no errors. */ + /* + * In cases when not allowed to poll by using CMD13 or because we aren't + * capable of polling by using ->card_busy(), then rely on waiting the + * stated timeout to be sufficient. + */ + if (!send_status && !host->ops->card_busy) { + mmc_delay(timeout_ms); + goto out; + } + + /* Let's poll to find out when the command is completed. */ timeout = jiffies + msecs_to_jiffies(timeout_ms) + 1; do { /* @@ -560,25 +571,11 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value, if (err) goto out; } - if ((host->caps & MMC_CAP_WAIT_WHILE_BUSY) && use_r1b_resp) - break; if (host->ops->card_busy) { if (!host->ops->card_busy(host)) break; busy = true; } - if (mmc_host_is_spi(host)) - break; - - /* - * We are not allowed to issue a status command and the host - * does'nt support MMC_CAP_WAIT_WHILE_BUSY, then we can only - * rely on waiting for the stated timeout to be sufficient. - */ - if (!send_status && !host->ops->card_busy) { - mmc_delay(timeout_ms); - goto out; - } /* Timeout if the device never leaves the program state. */ if (expired && -- cgit v1.2.3 From 716bdb8953c7cad649a62e3333bf59cdd177db3b Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Wed, 19 Oct 2016 13:20:49 +0200 Subject: mmc: core: Factor out code related to polling in __mmc_switch() In yet another step of cleaning up __mmc_switch(), let's factor out the code that deals with card busy polling. Signed-off-by: Ulf Hansson Acked-by: Jaehoon Chung Tested-by: Jaehoon Chung --- drivers/mmc/core/mmc_ops.c | 108 +++++++++++++++++++++++++-------------------- 1 file changed, 59 insertions(+), 49 deletions(-) (limited to 'drivers/mmc/core') diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c index 5a77af7a24b3..a84a880c986f 100644 --- a/drivers/mmc/core/mmc_ops.c +++ b/drivers/mmc/core/mmc_ops.c @@ -468,6 +468,63 @@ int mmc_switch_status(struct mmc_card *card) return mmc_switch_status_error(card->host, status); } +static int mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms, + bool send_status, bool ignore_crc) +{ + struct mmc_host *host = card->host; + int err; + unsigned long timeout; + u32 status = 0; + bool expired = false; + bool busy = false; + + /* We have an unspecified cmd timeout, use the fallback value. */ + if (!timeout_ms) + timeout_ms = MMC_OPS_TIMEOUT_MS; + + /* + * In cases when not allowed to poll by using CMD13 or because we aren't + * capable of polling by using ->card_busy(), then rely on waiting the + * stated timeout to be sufficient. + */ + if (!send_status && !host->ops->card_busy) { + mmc_delay(timeout_ms); + return 0; + } + + timeout = jiffies + msecs_to_jiffies(timeout_ms) + 1; + do { + /* + * Due to the possibility of being preempted after + * sending the status command, check the expiration + * time first. + */ + expired = time_after(jiffies, timeout); + if (send_status) { + err = __mmc_send_status(card, &status, ignore_crc); + if (err) + return err; + } + if (host->ops->card_busy) { + if (!host->ops->card_busy(host)) + break; + busy = true; + } + + /* Timeout if the device never leaves the program state. */ + if (expired && + (R1_CURRENT_STATE(status) == R1_STATE_PRG || busy)) { + pr_err("%s: Card stuck in programming state! %s\n", + mmc_hostname(host), __func__); + return -ETIMEDOUT; + } + } while (R1_CURRENT_STATE(status) == R1_STATE_PRG || busy); + + err = mmc_switch_status_error(host, status); + + return err; +} + /** * __mmc_switch - modify EXT_CSD register * @card: the MMC card associated with the data transfer @@ -489,11 +546,7 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value, struct mmc_host *host = card->host; int err; struct mmc_command cmd = {0}; - unsigned long timeout; - u32 status = 0; bool use_r1b_resp = use_busy_signal; - bool expired = false; - bool busy = false; mmc_retune_hold(host); @@ -543,51 +596,8 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value, goto out; } - /* We have an unspecified cmd timeout, use the fallback value. */ - if (!timeout_ms) - timeout_ms = MMC_OPS_TIMEOUT_MS; - - /* - * In cases when not allowed to poll by using CMD13 or because we aren't - * capable of polling by using ->card_busy(), then rely on waiting the - * stated timeout to be sufficient. - */ - if (!send_status && !host->ops->card_busy) { - mmc_delay(timeout_ms); - goto out; - } - - /* Let's poll to find out when the command is completed. */ - timeout = jiffies + msecs_to_jiffies(timeout_ms) + 1; - do { - /* - * Due to the possibility of being preempted after - * sending the status command, check the expiration - * time first. - */ - expired = time_after(jiffies, timeout); - if (send_status) { - err = __mmc_send_status(card, &status, ignore_crc); - if (err) - goto out; - } - if (host->ops->card_busy) { - if (!host->ops->card_busy(host)) - break; - busy = true; - } - - /* Timeout if the device never leaves the program state. */ - if (expired && - (R1_CURRENT_STATE(status) == R1_STATE_PRG || busy)) { - pr_err("%s: Card stuck in programming state! %s\n", - mmc_hostname(host), __func__); - err = -ETIMEDOUT; - goto out; - } - } while (R1_CURRENT_STATE(status) == R1_STATE_PRG || busy); - - err = mmc_switch_status_error(host, status); + /* Let's try to poll to find out when the command is completed. */ + err = mmc_poll_for_busy(card, timeout_ms, send_status, ignore_crc); out: mmc_retune_release(host); -- cgit v1.2.3 From 70562644f4ee15214986966720ffe82fad03e693 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Wed, 19 Oct 2016 16:15:31 +0200 Subject: mmc: core: Don't use ->card_busy() and CMD13 in combination when polling When polling for busy after sending a MMC_SWITCH command, both the optional ->card_busy() callback and CMD13 are being used in conjunction. This doesn't make sense. Instead it's more reasonable to rely solely on the ->card_busy() callback when it exists. Let's change that and instead use the CMD13 as a fall-back. In this way we avoid sending CMD13, unless it's really needed. Within this context, let's also take the opportunity to make some additional clean-ups and clarifications to the related code. Signed-off-by: Ulf Hansson Acked-by: Jaehoon Chung Tested-by: Jaehoon Chung --- drivers/mmc/core/mmc_ops.c | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) (limited to 'drivers/mmc/core') diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c index a84a880c986f..481bbdbae6e7 100644 --- a/drivers/mmc/core/mmc_ops.c +++ b/drivers/mmc/core/mmc_ops.c @@ -495,34 +495,32 @@ static int mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms, timeout = jiffies + msecs_to_jiffies(timeout_ms) + 1; do { /* - * Due to the possibility of being preempted after - * sending the status command, check the expiration - * time first. + * Due to the possibility of being preempted while polling, + * check the expiration time first. */ expired = time_after(jiffies, timeout); - if (send_status) { + + if (host->ops->card_busy) { + busy = host->ops->card_busy(host); + } else { err = __mmc_send_status(card, &status, ignore_crc); if (err) return err; - } - if (host->ops->card_busy) { - if (!host->ops->card_busy(host)) - break; - busy = true; + busy = R1_CURRENT_STATE(status) == R1_STATE_PRG; } - /* Timeout if the device never leaves the program state. */ - if (expired && - (R1_CURRENT_STATE(status) == R1_STATE_PRG || busy)) { - pr_err("%s: Card stuck in programming state! %s\n", + /* Timeout if the device still remains busy. */ + if (expired && busy) { + pr_err("%s: Card stuck being busy! %s\n", mmc_hostname(host), __func__); return -ETIMEDOUT; } - } while (R1_CURRENT_STATE(status) == R1_STATE_PRG || busy); + } while (busy); - err = mmc_switch_status_error(host, status); + if (host->ops->card_busy && send_status) + return mmc_switch_status(card); - return err; + return mmc_switch_status_error(host, status); } /** -- cgit v1.2.3 From 50fcbbbb79de4b95a765ea170677c9810fcb9cee Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Wed, 12 Oct 2016 10:50:37 +0800 Subject: mmc: core: expose the capability of gpio card detect Add new helper API mmc_can_gpio_cd for slot-gpio to make host drivers know whether it supports gpio card detect. Signed-off-by: Shawn Lin Signed-off-by: Jaehoon Chung Signed-off-by: Ulf Hansson --- drivers/mmc/core/slot-gpio.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers/mmc/core') diff --git a/drivers/mmc/core/slot-gpio.c b/drivers/mmc/core/slot-gpio.c index 27117ba47073..babe591aea96 100644 --- a/drivers/mmc/core/slot-gpio.c +++ b/drivers/mmc/core/slot-gpio.c @@ -258,6 +258,14 @@ int mmc_gpiod_request_cd(struct mmc_host *host, const char *con_id, } EXPORT_SYMBOL(mmc_gpiod_request_cd); +bool mmc_can_gpio_cd(struct mmc_host *host) +{ + struct mmc_gpio *ctx = host->slot.handler_priv; + + return ctx->cd_gpio ? true : false; +} +EXPORT_SYMBOL(mmc_can_gpio_cd); + /** * mmc_gpiod_request_ro - request a gpio descriptor for write protection * @host: mmc host -- cgit v1.2.3 From c2c24819b28087f2a62750957e8dfa889d1f8bb2 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Thu, 13 Oct 2016 13:37:40 +0200 Subject: mmc: core: Don't power off the card when starting the host The MMC_CAP2_NO_PRESCAN_POWERUP was invented to avoid running the power up sequence, mmc_power_up(), during ->probe() of the mmc host driver, but instead defer this to the mmc detect work. This is especially useful for those hosts that suffers from a long initialization time, as this time would otherwise add up to the total boot time. However, due to the introduction of runtime PM of mmc host devices in the mmc core, this behaviour changed a bit. More precisely, it caused the mmc core to runtime resume the host device during ->probe() of the host driver. In cases like the rtsx_usb_sdmmc, runtime resuming the device may be costly and thus affecting the total boot time. To improve this behaviour when using MMC_CAP2_NO_PRESCAN_POWERUP, let's postpone also calling mmc_power_off() when starting the host. This change allows the mmc core to avoid runtime resuming the device, as it don't need to claim the host for that execution path. Cc: Ritesh Raj Sarraf Cc: Alan Stern Signed-off-by: Ulf Hansson --- drivers/mmc/core/core.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers/mmc/core') diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 2553d903a82b..2ad729138bee 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -2824,12 +2824,11 @@ void mmc_start_host(struct mmc_host *host) host->rescan_disable = 0; host->ios.power_mode = MMC_POWER_UNDEFINED; - mmc_claim_host(host); - if (host->caps2 & MMC_CAP2_NO_PRESCAN_POWERUP) - mmc_power_off(host); - else + if (!(host->caps2 & MMC_CAP2_NO_PRESCAN_POWERUP)) { + mmc_claim_host(host); mmc_power_up(host, host->ocr_avail); - mmc_release_host(host); + mmc_release_host(host); + } mmc_gpiod_request_cd_irq(host); _mmc_detect_change(host, 0, false); -- cgit v1.2.3 From 8e8b3f514c12a3b800bba8a7766c71139ad75b89 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Fri, 4 Nov 2016 11:05:19 +0100 Subject: mmc: core: use enum mmc_blk_status properly There were several instances of code using the enum mmc_blk_status by arbitrarily converting it to an int and throwing it around to different functions. This makes the code hard to understand to may give rise to strange errors. Especially the function prototype mmc_start_req() had to be modified to take a pointer to an enum mmc_blk_status and the function pointer .err_check() inside struct mmc_async_req needed to return an enum mmc_blk_status. In every case: instead of assigning the block layer error code to an int, use the enum, also change the signature of all functions actually passing this enum to use the enum. To make it possible to use the enum everywhere applicable, move it to so that all code actually using it can also see it. An interesting case was encountered in the MMC test code which did not return a enum mmc_blk_status at all in the .err_check function supposed to check whether asynchronous requests worked or not: instead it returned a normal -ERROR or even the test frameworks internal error codes. The test code would also pass on enum mmc_blk_status codes as error codes inside the test code instead of converting them to the local RESULT_* codes. I have tried to fix all instances properly and run some tests on the result. Cc: Chunyan Zhang Cc: Baolin Wang Signed-off-by: Linus Walleij Signed-off-by: Ulf Hansson --- drivers/mmc/core/core.c | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) (limited to 'drivers/mmc/core') diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 2ad729138bee..50bb9a16380d 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -497,13 +497,13 @@ static int __mmc_start_req(struct mmc_host *host, struct mmc_request *mrq) * * Returns enum mmc_blk_status after checking errors. */ -static int mmc_wait_for_data_req_done(struct mmc_host *host, +static enum mmc_blk_status mmc_wait_for_data_req_done(struct mmc_host *host, struct mmc_request *mrq, struct mmc_async_req *next_req) { struct mmc_command *cmd; struct mmc_context_info *context_info = &host->context_info; - int err; + enum mmc_blk_status status; unsigned long flags; while (1) { @@ -520,9 +520,9 @@ static int mmc_wait_for_data_req_done(struct mmc_host *host, if (!cmd->error || !cmd->retries || mmc_card_removed(host->card)) { - err = host->areq->err_check(host->card, - host->areq); - break; /* return err */ + status = host->areq->err_check(host->card, + host->areq); + break; /* return status */ } else { mmc_retune_recheck(host); pr_info("%s: req failed (CMD%u): %d, retrying...\n", @@ -540,7 +540,7 @@ static int mmc_wait_for_data_req_done(struct mmc_host *host, } } mmc_retune_release(host); - return err; + return status; } void mmc_wait_for_req_done(struct mmc_host *host, struct mmc_request *mrq) @@ -658,9 +658,10 @@ static void mmc_post_req(struct mmc_host *host, struct mmc_request *mrq, * is returned without waiting. NULL is not an error condition. */ struct mmc_async_req *mmc_start_req(struct mmc_host *host, - struct mmc_async_req *areq, int *error) + struct mmc_async_req *areq, + enum mmc_blk_status *ret_stat) { - int err = 0; + enum mmc_blk_status status = MMC_BLK_SUCCESS; int start_err = 0; struct mmc_async_req *data = host->areq; @@ -669,10 +670,10 @@ struct mmc_async_req *mmc_start_req(struct mmc_host *host, mmc_pre_req(host, areq->mrq, !host->areq); if (host->areq) { - err = mmc_wait_for_data_req_done(host, host->areq->mrq, areq); - if (err == MMC_BLK_NEW_REQUEST) { - if (error) - *error = err; + status = mmc_wait_for_data_req_done(host, host->areq->mrq, areq); + if (status == MMC_BLK_NEW_REQUEST) { + if (ret_stat) + *ret_stat = status; /* * The previous request was not completed, * nothing to return @@ -699,23 +700,23 @@ struct mmc_async_req *mmc_start_req(struct mmc_host *host, } } - if (!err && areq) + if (status == MMC_BLK_SUCCESS && areq) start_err = __mmc_start_data_req(host, areq->mrq); if (host->areq) mmc_post_req(host, host->areq->mrq, 0); /* Cancel a prepared request if it was not started. */ - if ((err || start_err) && areq) + if ((status != MMC_BLK_SUCCESS || start_err) && areq) mmc_post_req(host, areq->mrq, -EINVAL); - if (err) + if (status != MMC_BLK_SUCCESS) host->areq = NULL; else host->areq = areq; - if (error) - *error = err; + if (ret_stat) + *ret_stat = status; return data; } EXPORT_SYMBOL(mmc_start_req); -- cgit v1.2.3 From 437590a123b6617a52e0b136cd25fe3616e4d50f Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Tue, 8 Nov 2016 13:53:36 +0100 Subject: mmc: core: Retry instead of ignore at CRC errors when polling for busy After a CMD6 command has been sent, the __mmc_switch() function might be advised to poll the card for busy by using CMD13 and also by ignoring CRC errors. In the case of ignoring CRC errors, the mmc core tells the mmc host to also ignore these errors via masking the MMC_RSP_CRC response flag. This seems wrong, as it leads to that the mmc host could propagate an unreliable response, instead of a proper error code. What we really want, is not to ignore CRC errors but instead retry the polling attempt. So, let's change this by treating a CRC error as the card is still being busy and thus continue to run the polling loop. Signed-off-by: Ulf Hansson Tested-by: Linus Walleij Acked-by: Adrian Hunter --- drivers/mmc/core/mmc_ops.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers/mmc/core') diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c index 481bbdbae6e7..4773c562312d 100644 --- a/drivers/mmc/core/mmc_ops.c +++ b/drivers/mmc/core/mmc_ops.c @@ -503,10 +503,13 @@ static int mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms, if (host->ops->card_busy) { busy = host->ops->card_busy(host); } else { - err = __mmc_send_status(card, &status, ignore_crc); - if (err) + err = mmc_send_status(card, &status); + if (ignore_crc && err == -EILSEQ) + busy = true; + else if (err) return err; - busy = R1_CURRENT_STATE(status) == R1_STATE_PRG; + else + busy = R1_CURRENT_STATE(status) == R1_STATE_PRG; } /* Timeout if the device still remains busy. */ -- cgit v1.2.3 From 89e57aedda337a121eca5f2b0adfecbc6ab39b3d Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Tue, 8 Nov 2016 15:27:27 +0100 Subject: mmc: core: Remove redundant __mmc_send_status() There are only one users left which calls __mmc_send_status(). Moreover, the ignore_crc parameter isn't being used, so let's just remove these redundant parts. Signed-off-by: Ulf Hansson Tested-by: Linus Walleij Acked-by: Adrian Hunter --- drivers/mmc/core/mmc_ops.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) (limited to 'drivers/mmc/core') diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c index 4773c562312d..0515748ac528 100644 --- a/drivers/mmc/core/mmc_ops.c +++ b/drivers/mmc/core/mmc_ops.c @@ -54,8 +54,7 @@ static const u8 tuning_blk_pattern_8bit[] = { 0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, }; -static inline int __mmc_send_status(struct mmc_card *card, u32 *status, - bool ignore_crc) +int mmc_send_status(struct mmc_card *card, u32 *status) { int err; struct mmc_command cmd = {0}; @@ -67,8 +66,6 @@ static inline int __mmc_send_status(struct mmc_card *card, u32 *status, if (!mmc_host_is_spi(card->host)) cmd.arg = card->rca << 16; cmd.flags = MMC_RSP_SPI_R2 | MMC_RSP_R1 | MMC_CMD_AC; - if (ignore_crc) - cmd.flags &= ~MMC_RSP_CRC; err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES); if (err) @@ -83,11 +80,6 @@ static inline int __mmc_send_status(struct mmc_card *card, u32 *status, return 0; } -int mmc_send_status(struct mmc_card *card, u32 *status) -{ - return __mmc_send_status(card, status, false); -} - static int _mmc_select_card(struct mmc_host *host, struct mmc_card *card) { struct mmc_command cmd = {0}; -- cgit v1.2.3 From 625228fa3e017d80f547b35214c60b4081b5c07d Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Tue, 8 Nov 2016 15:39:13 +0100 Subject: mmc: core: Rename ignore_crc to retry_crc_err to reflect its purpose The ignore_crc parameter/variable name is used at a couple of places in the mmc core. Let's rename it to retry_crc_err to reflect its new purpose. Signed-off-by: Ulf Hansson Tested-by: Linus Walleij Acked-by: Adrian Hunter --- drivers/mmc/core/mmc_ops.c | 10 +++++----- drivers/mmc/core/mmc_ops.h | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/mmc/core') diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c index 0515748ac528..214e7342e946 100644 --- a/drivers/mmc/core/mmc_ops.c +++ b/drivers/mmc/core/mmc_ops.c @@ -461,7 +461,7 @@ int mmc_switch_status(struct mmc_card *card) } static int mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms, - bool send_status, bool ignore_crc) + bool send_status, bool retry_crc_err) { struct mmc_host *host = card->host; int err; @@ -496,7 +496,7 @@ static int mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms, busy = host->ops->card_busy(host); } else { err = mmc_send_status(card, &status); - if (ignore_crc && err == -EILSEQ) + if (retry_crc_err && err == -EILSEQ) busy = true; else if (err) return err; @@ -528,13 +528,13 @@ static int mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms, * timeout of zero implies maximum possible timeout * @use_busy_signal: use the busy signal as response type * @send_status: send status cmd to poll for busy - * @ignore_crc: ignore CRC errors when sending status cmd to poll for busy + * @retry_crc_err: retry when CRC errors when polling with CMD13 for busy * * Modifies the EXT_CSD register for selected card. */ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value, unsigned int timeout_ms, bool use_busy_signal, bool send_status, - bool ignore_crc) + bool retry_crc_err) { struct mmc_host *host = card->host; int err; @@ -590,7 +590,7 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value, } /* Let's try to poll to find out when the command is completed. */ - err = mmc_poll_for_busy(card, timeout_ms, send_status, ignore_crc); + err = mmc_poll_for_busy(card, timeout_ms, send_status, retry_crc_err); out: mmc_retune_release(host); diff --git a/drivers/mmc/core/mmc_ops.h b/drivers/mmc/core/mmc_ops.h index 7f6c0e98e7f5..9fccddb48148 100644 --- a/drivers/mmc/core/mmc_ops.h +++ b/drivers/mmc/core/mmc_ops.h @@ -30,7 +30,7 @@ int mmc_can_ext_csd(struct mmc_card *card); int mmc_switch_status(struct mmc_card *card); int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value, unsigned int timeout_ms, bool use_busy_signal, bool send_status, - bool ignore_crc); + bool retry_crc_err); #endif -- cgit v1.2.3 From 5ec32f84111a500c142961c82dd415c22e64e2be Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Mon, 21 Nov 2016 15:49:48 +0100 Subject: mmc: core: Check SWITCH_ERROR bit from each CMD13 response when polling According to the JEDEC specification, the SWITCH_ERROR bit in the device status from a R1 response, is an error bit which may be cleared as soon as the response that reports the error is sent. When polling with CMD13 to find out when the card stops signaling busy after a CMD6 has been sent, we currently parse only the last CMD13 response for the SWITCH_ERROR bit. Consequentially we could loose important information about the card. In worst case if the card stops signaling busy within the allowed timeout, we could end up believing that the CMD6 command completed successfully, when in fact it didn't. To improve the behaviour, let's parse each CMD13 response to see if the SWITCH_ERROR bit is set in the device status. In such case, we abort the polling loop and report the error. Signed-off-by: Ulf Hansson Tested-by: Linus Walleij Acked-by: Adrian Hunter --- drivers/mmc/core/mmc_ops.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'drivers/mmc/core') diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c index 214e7342e946..fba5d2954165 100644 --- a/drivers/mmc/core/mmc_ops.c +++ b/drivers/mmc/core/mmc_ops.c @@ -496,12 +496,16 @@ static int mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms, busy = host->ops->card_busy(host); } else { err = mmc_send_status(card, &status); - if (retry_crc_err && err == -EILSEQ) + if (retry_crc_err && err == -EILSEQ) { busy = true; - else if (err) + } else if (err) { return err; - else + } else { + err = mmc_switch_status_error(host, status); + if (err) + return err; busy = R1_CURRENT_STATE(status) == R1_STATE_PRG; + } } /* Timeout if the device still remains busy. */ @@ -515,7 +519,7 @@ static int mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms, if (host->ops->card_busy && send_status) return mmc_switch_status(card); - return mmc_switch_status_error(host, status); + return 0; } /** -- cgit v1.2.3 From aa33ce3c411ab7a1b3c56f584b27bf4b6cc523ba Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Wed, 9 Nov 2016 17:33:36 +0100 Subject: mmc: core: Enable __mmc_switch() to change bus speed timing for the host In cases when a speed mode change is requested for mmc cards, a CMD6 is sent by calling __mmc_switch() during the card initialization. The CMD6 leads to the card entering a busy period. When that is completed, the host must parse the CMD6 status to find out whether the change of the speed mode succeeded. To enable the mmc core to poll the card by using CMD13 to find out when the busy period is completed, it's reasonable to make sure polling is done by having the mmc host and the mmc card, being configured to operate at the same selected bus speed timing. Therefore, let's extend __mmc_switch() to take yet another parameter, which allow its callers to update the bus speed timing of the mmc host. In this way, __mmc_switch() also becomes capable of reading and validating the CMD6 status by sending a CMD13, in cases when that's desired. If __mmc_switch() encounters a failure, we make sure to restores the old bus speed timing for the mmc host, before propagating the error code. Signed-off-by: Ulf Hansson Tested-by: Linus Walleij Acked-by: Adrian Hunter --- drivers/mmc/core/core.c | 2 +- drivers/mmc/core/mmc.c | 18 +++++++++--------- drivers/mmc/core/mmc_ops.c | 20 +++++++++++++++----- drivers/mmc/core/mmc_ops.h | 4 ++-- 4 files changed, 27 insertions(+), 17 deletions(-) (limited to 'drivers/mmc/core') diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 50bb9a16380d..060f76742550 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -380,7 +380,7 @@ void mmc_start_bkops(struct mmc_card *card, bool from_exception) mmc_retune_hold(card->host); err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, - EXT_CSD_BKOPS_START, 1, timeout, + EXT_CSD_BKOPS_START, 1, timeout, 0, use_busy_signal, true, false); if (err) { pr_warn("%s: Error %d starting bkops\n", diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 9355366d3259..cb1cf4e5d916 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -1012,7 +1012,7 @@ static int mmc_select_hs(struct mmc_card *card) err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS, - card->ext_csd.generic_cmd6_time, + card->ext_csd.generic_cmd6_time, 0, true, false, true); if (!err) { mmc_set_timing(card->host, MMC_TIMING_MMC_HS); @@ -1115,7 +1115,7 @@ static int mmc_select_hs400(struct mmc_card *card) val = EXT_CSD_TIMING_HS; err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, val, - card->ext_csd.generic_cmd6_time, + card->ext_csd.generic_cmd6_time, 0, true, false, true); if (err) { pr_err("%s: switch to high-speed from hs200 failed, err:%d\n", @@ -1150,7 +1150,7 @@ static int mmc_select_hs400(struct mmc_card *card) card->drive_strength << EXT_CSD_DRV_STR_SHIFT; err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, val, - card->ext_csd.generic_cmd6_time, + card->ext_csd.generic_cmd6_time, 0, true, false, true); if (err) { pr_err("%s: switch to hs400 failed, err:%d\n", @@ -1193,7 +1193,7 @@ int mmc_hs400_to_hs200(struct mmc_card *card) /* Switch HS400 to HS DDR */ val = EXT_CSD_TIMING_HS; err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, - val, card->ext_csd.generic_cmd6_time, + val, card->ext_csd.generic_cmd6_time, 0, true, false, true); if (err) goto out_err; @@ -1207,7 +1207,7 @@ int mmc_hs400_to_hs200(struct mmc_card *card) /* Switch HS DDR to HS */ err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH, EXT_CSD_BUS_WIDTH_8, card->ext_csd.generic_cmd6_time, - true, false, true); + 0, true, false, true); if (err) goto out_err; @@ -1221,7 +1221,7 @@ int mmc_hs400_to_hs200(struct mmc_card *card) val = EXT_CSD_TIMING_HS200 | card->drive_strength << EXT_CSD_DRV_STR_SHIFT; err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, - val, card->ext_csd.generic_cmd6_time, + val, card->ext_csd.generic_cmd6_time, 0, true, false, true); if (err) goto out_err; @@ -1295,7 +1295,7 @@ static int mmc_select_hs400es(struct mmc_card *card) card->drive_strength << EXT_CSD_DRV_STR_SHIFT; err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, val, - card->ext_csd.generic_cmd6_time, + card->ext_csd.generic_cmd6_time, 0, true, false, true); if (err) { pr_err("%s: switch to hs400es failed, err:%d\n", @@ -1377,7 +1377,7 @@ static int mmc_select_hs200(struct mmc_card *card) card->drive_strength << EXT_CSD_DRV_STR_SHIFT; err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, val, - card->ext_csd.generic_cmd6_time, + card->ext_csd.generic_cmd6_time, 0, true, false, true); if (err) goto err; @@ -1841,7 +1841,7 @@ static int mmc_poweroff_notify(struct mmc_card *card, unsigned int notify_type) err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_POWER_OFF_NOTIFICATION, - notify_type, timeout, true, false, false); + notify_type, timeout, 0, true, false, false); if (err) pr_err("%s: Power Off Notification timed out, %u\n", mmc_hostname(card->host), timeout); diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c index fba5d2954165..9b2617cfff67 100644 --- a/drivers/mmc/core/mmc_ops.c +++ b/drivers/mmc/core/mmc_ops.c @@ -530,6 +530,7 @@ static int mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms, * @value: value to program into EXT_CSD register * @timeout_ms: timeout (ms) for operation performed by register write, * timeout of zero implies maximum possible timeout + * @timing: new timing to change to * @use_busy_signal: use the busy signal as response type * @send_status: send status cmd to poll for busy * @retry_crc_err: retry when CRC errors when polling with CMD13 for busy @@ -537,13 +538,14 @@ static int mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms, * Modifies the EXT_CSD register for selected card. */ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value, - unsigned int timeout_ms, bool use_busy_signal, bool send_status, - bool retry_crc_err) + unsigned int timeout_ms, unsigned char timing, + bool use_busy_signal, bool send_status, bool retry_crc_err) { struct mmc_host *host = card->host; int err; struct mmc_command cmd = {0}; bool use_r1b_resp = use_busy_signal; + unsigned char old_timing = host->ios.timing; mmc_retune_hold(host); @@ -585,16 +587,24 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value, if (!use_busy_signal) goto out; + /* Switch to new timing before poll and check switch status. */ + if (timing) + mmc_set_timing(host, timing); + /*If SPI or used HW busy detection above, then we don't need to poll. */ if (((host->caps & MMC_CAP_WAIT_WHILE_BUSY) && use_r1b_resp) || mmc_host_is_spi(host)) { if (send_status) err = mmc_switch_status(card); - goto out; + goto out_tim; } /* Let's try to poll to find out when the command is completed. */ err = mmc_poll_for_busy(card, timeout_ms, send_status, retry_crc_err); + +out_tim: + if (err && timing) + mmc_set_timing(host, old_timing); out: mmc_retune_release(host); @@ -604,8 +614,8 @@ out: int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value, unsigned int timeout_ms) { - return __mmc_switch(card, set, index, value, timeout_ms, true, true, - false); + return __mmc_switch(card, set, index, value, timeout_ms, 0, + true, true, false); } EXPORT_SYMBOL_GPL(mmc_switch); diff --git a/drivers/mmc/core/mmc_ops.h b/drivers/mmc/core/mmc_ops.h index 9fccddb48148..761cb69c46af 100644 --- a/drivers/mmc/core/mmc_ops.h +++ b/drivers/mmc/core/mmc_ops.h @@ -29,8 +29,8 @@ int mmc_send_hpi_cmd(struct mmc_card *card, u32 *status); int mmc_can_ext_csd(struct mmc_card *card); int mmc_switch_status(struct mmc_card *card); int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value, - unsigned int timeout_ms, bool use_busy_signal, bool send_status, - bool retry_crc_err); + unsigned int timeout_ms, unsigned char timing, + bool use_busy_signal, bool send_status, bool retry_crc_err); #endif -- cgit v1.2.3 From 53e60650f74ed42957bea947ea791b6dea215b01 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Wed, 9 Nov 2016 19:40:29 +0100 Subject: mmc: core: Allow CMD13 polling when switching to HS mode for mmc In cases when the mmc host doesn't support HW busy detection, polling for a card being busy by using CMD13 is beneficial. That is because, instead of waiting a fixed amount of time, 500ms or the generic CMD6 time from EXT_CSD, we find out a lot sooner when the card stops signaling busy. This leads to a significant decreased total initialization time for the mmc card. However, to allow polling with CMD13 during a bus timing change operation, such as switching to HS mode, we first need to update the mmc host's bus timing before starting to poll. Deal with that, simply by providing MMC_TIMING_MMC_HS as the timing parameter to __mmc_switch() from mmc_select_hs(). By telling __mmc_switch() to allow polling with CMD13, also makes it validate the CMD6 status, thus we can remove the corresponding checks. When switching to HS400ES, the mmc_select_hs() function is called in one of the intermediate steps. To still prevent CMD13 polling for HS400ES, let's call the __mmc_switch() function in this path as it enables us to keep using the existing method. Signed-off-by: Ulf Hansson Tested-by: Linus Walleij Acked-by: Adrian Hunter --- drivers/mmc/core/mmc.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) (limited to 'drivers/mmc/core') diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index cb1cf4e5d916..15dd51cfd083 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -1012,13 +1012,8 @@ static int mmc_select_hs(struct mmc_card *card) err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS, - card->ext_csd.generic_cmd6_time, 0, - true, false, true); - if (!err) { - mmc_set_timing(card->host, MMC_TIMING_MMC_HS); - err = mmc_switch_status(card); - } - + card->ext_csd.generic_cmd6_time, MMC_TIMING_MMC_HS, + true, true, true); if (err) pr_warn("%s: switch to high-speed failed, err:%d\n", mmc_hostname(card->host), err); @@ -1268,16 +1263,23 @@ static int mmc_select_hs400es(struct mmc_card *card) goto out_err; /* Switch card to HS mode */ - err = mmc_select_hs(card); - if (err) + err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, + EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS, + card->ext_csd.generic_cmd6_time, 0, + true, false, true); + if (err) { + pr_err("%s: switch to hs for hs400es failed, err:%d\n", + mmc_hostname(host), err); goto out_err; + } - mmc_set_clock(host, card->ext_csd.hs_max_dtr); - + mmc_set_timing(host, MMC_TIMING_MMC_HS); err = mmc_switch_status(card); if (err) goto out_err; + mmc_set_clock(host, card->ext_csd.hs_max_dtr); + /* Switch card to DDR with strobe bit */ val = EXT_CSD_DDR_BUS_WIDTH_8 | EXT_CSD_BUS_WIDTH_STROBE; err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, -- cgit v1.2.3 From e173f8911f091fa50ccf8cc1fa316dd5569bc470 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Wed, 9 Nov 2016 21:00:26 +0100 Subject: mmc: core: Update CMD13 polling policy when switch to HS DDR mode According to the JEDEC specification, during bus timing change operations for mmc, sending a CMD13 could trigger CRC errors. As switching to HS DDR mode indeed causes a bus timing change, polling with CMD13 to detect card busy, may thus potentially trigger CRC errors. Currently these errors are treated as the switch to HS DDR mode failed. To improve this behaviour, let's instead tell __mmc_switch() to retry when it encounters CRC errors during polling. Moreover, when switching to HS DDR mode, let's make sure the CMD13 polling is done by having the mmc host and the mmc card, being configured to operate at the same selected bus speed timing. Fix this by providing MMC_TIMING_MMC_DDR52 as the timing parameter to __mmc_switch(). Signed-off-by: Ulf Hansson Tested-by: Linus Walleij Acked-by: Adrian Hunter --- drivers/mmc/core/mmc.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'drivers/mmc/core') diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 15dd51cfd083..3268fcd3378d 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -1040,10 +1040,12 @@ static int mmc_select_hs_ddr(struct mmc_card *card) ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ? EXT_CSD_DDR_BUS_WIDTH_8 : EXT_CSD_DDR_BUS_WIDTH_4; - err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, - EXT_CSD_BUS_WIDTH, - ext_csd_bits, - card->ext_csd.generic_cmd6_time); + err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, + EXT_CSD_BUS_WIDTH, + ext_csd_bits, + card->ext_csd.generic_cmd6_time, + MMC_TIMING_MMC_DDR52, + true, true, true); if (err) { pr_err("%s: switch to bus width %d ddr failed\n", mmc_hostname(host), 1 << bus_width); @@ -1086,9 +1088,6 @@ static int mmc_select_hs_ddr(struct mmc_card *card) if (err) err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330); - if (!err) - mmc_set_timing(host, MMC_TIMING_MMC_DDR52); - return err; } -- cgit v1.2.3 From d3c6aac3bdfe97b8b44db6a8aba59786cb9531dc Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 23 Nov 2016 11:02:24 +0100 Subject: mmc: delete is_first_req parameter from pre-request callback The void (*pre_req) callback in the struct mmc_host_ops vtable is passing an argument "is_first_req" indicating whether this is the first request or not. None of the in-kernel users use this parameter: instead, since they all just do variants of dma_map* they use the DMA cookie to indicate whether a pre* callback has already been done for a request when they decide how to handle it. Delete the parameter from the callback and all users, as it is just pointless cruft. Signed-off-by: Linus Walleij Acked-by: Jaehoon Chung Signed-off-by: Ulf Hansson --- drivers/mmc/core/core.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) (limited to 'drivers/mmc/core') diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 060f76742550..f39397f7c8dc 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -611,18 +611,15 @@ EXPORT_SYMBOL(mmc_is_req_done); * mmc_pre_req - Prepare for a new request * @host: MMC host to prepare command * @mrq: MMC request to prepare for - * @is_first_req: true if there is no previous started request - * that may run in parellel to this call, otherwise false * * mmc_pre_req() is called in prior to mmc_start_req() to let * host prepare for the new request. Preparation of a request may be * performed while another request is running on the host. */ -static void mmc_pre_req(struct mmc_host *host, struct mmc_request *mrq, - bool is_first_req) +static void mmc_pre_req(struct mmc_host *host, struct mmc_request *mrq) { if (host->ops->pre_req) - host->ops->pre_req(host, mrq, is_first_req); + host->ops->pre_req(host, mrq); } /** @@ -667,7 +664,7 @@ struct mmc_async_req *mmc_start_req(struct mmc_host *host, /* Prepare a new request */ if (areq) - mmc_pre_req(host, areq->mrq, !host->areq); + mmc_pre_req(host, areq->mrq); if (host->areq) { status = mmc_wait_for_data_req_done(host, host->areq->mrq, areq); @@ -696,7 +693,7 @@ struct mmc_async_req *mmc_start_req(struct mmc_host *host, /* prepare the request again */ if (areq) - mmc_pre_req(host, areq->mrq, !host->areq); + mmc_pre_req(host, areq->mrq); } } -- cgit v1.2.3 From e0097cf5f2f1b7b8a594beaa32a604776d3ca6ce Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Tue, 29 Nov 2016 12:09:10 +0200 Subject: mmc: queue: Fix queue thread wake-up The only time the driver sleeps expecting to be woken upon the arrival of a new request, is when the dispatch queue is empty. The only time that it is known whether the dispatch queue is empty is after NULL is returned from blk_fetch_request() while under the queue lock. Recognizing those facts, simplify the synchronization between the queue thread and the request function. A couple of flags tell the request function what to do, and the queue lock and barriers associated with wake-ups ensure synchronization. The result is simpler and allows the removal of the context_info lock. Signed-off-by: Adrian Hunter Reviewed-by: Linus Walleij Reviewed-by: Harjani Ritesh Signed-off-by: Ulf Hansson --- drivers/mmc/core/core.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers/mmc/core') diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index f39397f7c8dc..dc1f27ee50b8 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -504,18 +504,14 @@ static enum mmc_blk_status mmc_wait_for_data_req_done(struct mmc_host *host, struct mmc_command *cmd; struct mmc_context_info *context_info = &host->context_info; enum mmc_blk_status status; - unsigned long flags; while (1) { wait_event_interruptible(context_info->wait, (context_info->is_done_rcv || context_info->is_new_req)); - spin_lock_irqsave(&context_info->lock, flags); context_info->is_waiting_last_req = false; - spin_unlock_irqrestore(&context_info->lock, flags); if (context_info->is_done_rcv) { context_info->is_done_rcv = false; - context_info->is_new_req = false; cmd = mrq->cmd; if (!cmd->error || !cmd->retries || @@ -534,7 +530,6 @@ static enum mmc_blk_status mmc_wait_for_data_req_done(struct mmc_host *host, continue; /* wait for done/new event again */ } } else if (context_info->is_new_req) { - context_info->is_new_req = false; if (!next_req) return MMC_BLK_NEW_REQUEST; } @@ -3016,7 +3011,6 @@ void mmc_unregister_pm_notifier(struct mmc_host *host) */ void mmc_init_context_info(struct mmc_host *host) { - spin_lock_init(&host->context_info.lock); host->context_info.is_new_req = false; host->context_info.is_done_rcv = false; host->context_info.is_waiting_last_req = false; -- cgit v1.2.3 From 925ff3a7a334b3fe968ae15f07d22df21addad26 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Tue, 29 Nov 2016 12:09:16 +0200 Subject: mmc: mmc: Add Command Queue definitions Add definitions relating to Command Queuing. Signed-off-by: Adrian Hunter Reviewed-by: Linus Walleij Signed-off-by: Ulf Hansson --- drivers/mmc/core/mmc.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'drivers/mmc/core') diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 3268fcd3378d..16cf6ea6e1ba 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -618,6 +618,24 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd) (ext_csd[EXT_CSD_SUPPORTED_MODE] & 0x1) && !(ext_csd[EXT_CSD_FW_CONFIG] & 0x1); } + + /* eMMC v5.1 or later */ + if (card->ext_csd.rev >= 8) { + card->ext_csd.cmdq_support = ext_csd[EXT_CSD_CMDQ_SUPPORT] & + EXT_CSD_CMDQ_SUPPORTED; + card->ext_csd.cmdq_depth = (ext_csd[EXT_CSD_CMDQ_DEPTH] & + EXT_CSD_CMDQ_DEPTH_MASK) + 1; + /* Exclude inefficiently small queue depths */ + if (card->ext_csd.cmdq_depth <= 2) { + card->ext_csd.cmdq_support = false; + card->ext_csd.cmdq_depth = 0; + } + if (card->ext_csd.cmdq_support) { + pr_debug("%s: Command Queue supported depth %u\n", + mmc_hostname(card->host), + card->ext_csd.cmdq_depth); + } + } out: return err; } -- cgit v1.2.3 From 5df0e8231f9518ee5ca3f58a0777556dd03addd6 Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Wed, 2 Nov 2016 15:24:00 +0800 Subject: mmc: core: remove BUG_ONs from sdio BUG_ONs doesn't help anything except for stop the system from running. If it occurs, it implies we should deploy proper error handling for that. So this patch is gonna discard these meaningless BUG_ONs and deploy error handling if needed. Signed-off-by: Shawn Lin Signed-off-by: Ulf Hansson --- drivers/mmc/core/sdio.c | 17 ++--------------- drivers/mmc/core/sdio_cis.c | 3 ++- drivers/mmc/core/sdio_irq.c | 12 +++++++----- 3 files changed, 11 insertions(+), 21 deletions(-) (limited to 'drivers/mmc/core') diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index bd44ba8116d1..ecbc52981ba5 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -63,7 +63,8 @@ static int sdio_init_func(struct mmc_card *card, unsigned int fn) int ret; struct sdio_func *func; - BUG_ON(fn > SDIO_MAX_FUNCS); + if (WARN_ON(fn > SDIO_MAX_FUNCS)) + return -EINVAL; func = sdio_alloc_func(card); if (IS_ERR(func)) @@ -555,7 +556,6 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr, u32 rocr = 0; u32 ocr_card = ocr; - BUG_ON(!host); WARN_ON(!host->claimed); /* to query card if 1.8V signalling is supported */ @@ -791,9 +791,6 @@ static void mmc_sdio_remove(struct mmc_host *host) { int i; - BUG_ON(!host); - BUG_ON(!host->card); - for (i = 0;i < host->card->sdio_funcs;i++) { if (host->card->sdio_func[i]) { sdio_remove_func(host->card->sdio_func[i]); @@ -820,9 +817,6 @@ static void mmc_sdio_detect(struct mmc_host *host) { int err; - BUG_ON(!host); - BUG_ON(!host->card); - /* Make sure card is powered before detecting it */ if (host->caps & MMC_CAP_POWER_OFF_CARD) { err = pm_runtime_get_sync(&host->card->dev); @@ -916,9 +910,6 @@ static int mmc_sdio_resume(struct mmc_host *host) { int err = 0; - BUG_ON(!host); - BUG_ON(!host->card); - /* Basic card reinitialization. */ mmc_claim_host(host); @@ -970,9 +961,6 @@ static int mmc_sdio_power_restore(struct mmc_host *host) { int ret; - BUG_ON(!host); - BUG_ON(!host->card); - mmc_claim_host(host); /* @@ -1063,7 +1051,6 @@ int mmc_attach_sdio(struct mmc_host *host) u32 ocr, rocr; struct mmc_card *card; - BUG_ON(!host); WARN_ON(!host->claimed); err = mmc_send_io_op_cond(host, 0, &ocr); diff --git a/drivers/mmc/core/sdio_cis.c b/drivers/mmc/core/sdio_cis.c index dcb3dee59fa5..f8c372839d24 100644 --- a/drivers/mmc/core/sdio_cis.c +++ b/drivers/mmc/core/sdio_cis.c @@ -262,7 +262,8 @@ static int sdio_read_cis(struct mmc_card *card, struct sdio_func *func) else prev = &card->tuples; - BUG_ON(*prev); + if (*prev) + return -EINVAL; do { unsigned char tpl_code, tpl_link; diff --git a/drivers/mmc/core/sdio_irq.c b/drivers/mmc/core/sdio_irq.c index 91bbbfb29f3f..f1faf9acc007 100644 --- a/drivers/mmc/core/sdio_irq.c +++ b/drivers/mmc/core/sdio_irq.c @@ -214,7 +214,9 @@ static int sdio_card_irq_put(struct mmc_card *card) struct mmc_host *host = card->host; WARN_ON(!host->claimed); - BUG_ON(host->sdio_irqs < 1); + + if (host->sdio_irqs < 1) + return -EINVAL; if (!--host->sdio_irqs) { if (!(host->caps2 & MMC_CAP2_SDIO_IRQ_NOTHREAD)) { @@ -261,8 +263,8 @@ int sdio_claim_irq(struct sdio_func *func, sdio_irq_handler_t *handler) int ret; unsigned char reg; - BUG_ON(!func); - BUG_ON(!func->card); + if (!func) + return -EINVAL; pr_debug("SDIO: Enabling IRQ for %s...\n", sdio_func_id(func)); @@ -304,8 +306,8 @@ int sdio_release_irq(struct sdio_func *func) int ret; unsigned char reg; - BUG_ON(!func); - BUG_ON(!func->card); + if (!func) + return -EINVAL; pr_debug("SDIO: Disabling IRQ for %s...\n", sdio_func_id(func)); -- cgit v1.2.3 From a48ee3e65a9e7395e8bab86728fcdc81c30a89ca Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Wed, 2 Nov 2016 15:24:39 +0800 Subject: mmc: debugfs: remove BUG_ON from mmc_ext_csd_open Return error value for file_operations callback instead of triggering BUG_ON which is meaningless. Personally I don't believe n != EXT_CSD_STR_LEN could happen. Anyway, propagate the error to the caller. Signed-off-by: Shawn Lin Signed-off-by: Ulf Hansson --- drivers/mmc/core/debugfs.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/mmc/core') diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c index c8451ce557ae..30623b8b86a4 100644 --- a/drivers/mmc/core/debugfs.c +++ b/drivers/mmc/core/debugfs.c @@ -321,7 +321,11 @@ static int mmc_ext_csd_open(struct inode *inode, struct file *filp) for (i = 0; i < 512; i++) n += sprintf(buf + n, "%02x", ext_csd[i]); n += sprintf(buf + n, "\n"); - BUG_ON(n != EXT_CSD_STR_LEN); + + if (n != EXT_CSD_STR_LEN) { + err = -EINVAL; + goto out_free; + } filp->private_data = buf; kfree(ext_csd); -- cgit v1.2.3 From 8cce3ecc535daf91c6f5c895684195932a949be1 Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Wed, 2 Nov 2016 15:25:33 +0800 Subject: mmc: core: remove BUG_ONs from mmc BUG_ONs doesn't help anything except for stop the system from running. If it occurs, it implies we should deploy proper error handling for that. So this patch is gonna discard these meaningless BUG_ONs and deploy error handling if needed. Signed-off-by: Shawn Lin Signed-off-by: Ulf Hansson --- drivers/mmc/core/mmc.c | 14 -------------- drivers/mmc/core/mmc_ops.c | 17 ----------------- 2 files changed, 31 deletions(-) (limited to 'drivers/mmc/core') diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 16cf6ea6e1ba..033e00abe93f 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -1486,7 +1486,6 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, u32 cid[4]; u32 rocr; - BUG_ON(!host); WARN_ON(!host->claimed); /* Set correct bus mode for MMC before attempting init */ @@ -1876,9 +1875,6 @@ static int mmc_poweroff_notify(struct mmc_card *card, unsigned int notify_type) */ static void mmc_remove(struct mmc_host *host) { - BUG_ON(!host); - BUG_ON(!host->card); - mmc_remove_card(host->card); host->card = NULL; } @@ -1898,9 +1894,6 @@ static void mmc_detect(struct mmc_host *host) { int err; - BUG_ON(!host); - BUG_ON(!host->card); - mmc_get_card(host->card); /* @@ -1926,9 +1919,6 @@ static int _mmc_suspend(struct mmc_host *host, bool is_suspend) unsigned int notify_type = is_suspend ? EXT_CSD_POWER_OFF_SHORT : EXT_CSD_POWER_OFF_LONG; - BUG_ON(!host); - BUG_ON(!host->card); - mmc_claim_host(host); if (mmc_card_suspended(host->card)) @@ -1985,9 +1975,6 @@ static int _mmc_resume(struct mmc_host *host) { int err = 0; - BUG_ON(!host); - BUG_ON(!host->card); - mmc_claim_host(host); if (!mmc_card_suspended(host->card)) @@ -2120,7 +2107,6 @@ int mmc_attach_mmc(struct mmc_host *host) int err; u32 ocr, rocr; - BUG_ON(!host); WARN_ON(!host->claimed); /* Set correct bus mode for MMC before attempting attach */ diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c index 9b2617cfff67..cb7006feb5c4 100644 --- a/drivers/mmc/core/mmc_ops.c +++ b/drivers/mmc/core/mmc_ops.c @@ -59,9 +59,6 @@ int mmc_send_status(struct mmc_card *card, u32 *status) int err; struct mmc_command cmd = {0}; - BUG_ON(!card); - BUG_ON(!card->host); - cmd.opcode = MMC_SEND_STATUS; if (!mmc_host_is_spi(card->host)) cmd.arg = card->rca << 16; @@ -84,8 +81,6 @@ static int _mmc_select_card(struct mmc_host *host, struct mmc_card *card) { struct mmc_command cmd = {0}; - BUG_ON(!host); - cmd.opcode = MMC_SELECT_CARD; if (card) { @@ -101,7 +96,6 @@ static int _mmc_select_card(struct mmc_host *host, struct mmc_card *card) int mmc_select_card(struct mmc_card *card) { - BUG_ON(!card); return _mmc_select_card(card->host, card); } @@ -173,8 +167,6 @@ int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr) struct mmc_command cmd = {0}; int i, err = 0; - BUG_ON(!host); - cmd.opcode = MMC_SEND_OP_COND; cmd.arg = mmc_host_is_spi(host) ? 0 : ocr; cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R3 | MMC_CMD_BCR; @@ -213,9 +205,6 @@ int mmc_all_send_cid(struct mmc_host *host, u32 *cid) int err; struct mmc_command cmd = {0}; - BUG_ON(!host); - BUG_ON(!cid); - cmd.opcode = MMC_ALL_SEND_CID; cmd.arg = 0; cmd.flags = MMC_RSP_R2 | MMC_CMD_BCR; @@ -233,9 +222,6 @@ int mmc_set_relative_addr(struct mmc_card *card) { struct mmc_command cmd = {0}; - BUG_ON(!card); - BUG_ON(!card->host); - cmd.opcode = MMC_SET_RELATIVE_ADDR; cmd.arg = card->rca << 16; cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; @@ -249,9 +235,6 @@ mmc_send_cxd_native(struct mmc_host *host, u32 arg, u32 *cxd, int opcode) int err; struct mmc_command cmd = {0}; - BUG_ON(!host); - BUG_ON(!cxd); - cmd.opcode = opcode; cmd.arg = arg; cmd.flags = MMC_RSP_R2 | MMC_CMD_AC; -- cgit v1.2.3 From 349583d66620a7d3eda760c82119ab7a8c253272 Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Wed, 2 Nov 2016 15:25:48 +0800 Subject: mmc: core: remove BUG_ONs from sd BUG_ONs doesn't help anything except for stop the system from running. If it occurs, it implies we should deploy proper error handling for that. So this patch is gonna discard these meaningless BUG_ONs and deploy error handling if needed. Signed-off-by: Shawn Lin Signed-off-by: Ulf Hansson --- drivers/mmc/core/sd.c | 14 -------------- drivers/mmc/core/sd_ops.c | 27 ++++----------------------- 2 files changed, 4 insertions(+), 37 deletions(-) (limited to 'drivers/mmc/core') diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index 73c762a28dfe..deb90c2ff6b4 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -927,7 +927,6 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr, u32 cid[4]; u32 rocr = 0; - BUG_ON(!host); WARN_ON(!host->claimed); err = mmc_sd_get_cid(host, ocr, cid, &rocr); @@ -1043,9 +1042,6 @@ free_card: */ static void mmc_sd_remove(struct mmc_host *host) { - BUG_ON(!host); - BUG_ON(!host->card); - mmc_remove_card(host->card); host->card = NULL; } @@ -1065,9 +1061,6 @@ static void mmc_sd_detect(struct mmc_host *host) { int err; - BUG_ON(!host); - BUG_ON(!host->card); - mmc_get_card(host->card); /* @@ -1091,9 +1084,6 @@ static int _mmc_sd_suspend(struct mmc_host *host) { int err = 0; - BUG_ON(!host); - BUG_ON(!host->card); - mmc_claim_host(host); if (mmc_card_suspended(host->card)) @@ -1136,9 +1126,6 @@ static int _mmc_sd_resume(struct mmc_host *host) { int err = 0; - BUG_ON(!host); - BUG_ON(!host->card); - mmc_claim_host(host); if (!mmc_card_suspended(host->card)) @@ -1221,7 +1208,6 @@ int mmc_attach_sd(struct mmc_host *host) int err; u32 ocr, rocr; - BUG_ON(!host); WARN_ON(!host->claimed); err = mmc_send_app_op_cond(host, 0, &ocr); diff --git a/drivers/mmc/core/sd_ops.c b/drivers/mmc/core/sd_ops.c index 16b774c18e75..de125a41aa7a 100644 --- a/drivers/mmc/core/sd_ops.c +++ b/drivers/mmc/core/sd_ops.c @@ -27,8 +27,8 @@ int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card) int err; struct mmc_command cmd = {0}; - BUG_ON(!host); - BUG_ON(card && (card->host != host)); + if (WARN_ON(card && card->host != host)) + return -EINVAL; cmd.opcode = MMC_APP_CMD; @@ -72,8 +72,8 @@ int mmc_wait_for_app_cmd(struct mmc_host *host, struct mmc_card *card, int i, err; - BUG_ON(!cmd); - BUG_ON(retries < 0); + if (retries < 0) + retries = MMC_CMD_RETRIES; err = -EIO; @@ -122,9 +122,6 @@ int mmc_app_set_bus_width(struct mmc_card *card, int width) { struct mmc_command cmd = {0}; - BUG_ON(!card); - BUG_ON(!card->host); - cmd.opcode = SD_APP_SET_BUS_WIDTH; cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; @@ -147,8 +144,6 @@ int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr) struct mmc_command cmd = {0}; int i, err = 0; - BUG_ON(!host); - cmd.opcode = SD_APP_OP_COND; if (mmc_host_is_spi(host)) cmd.arg = ocr & (1 << 30); /* SPI only defines one bit */ @@ -224,9 +219,6 @@ int mmc_send_relative_addr(struct mmc_host *host, unsigned int *rca) int err; struct mmc_command cmd = {0}; - BUG_ON(!host); - BUG_ON(!rca); - cmd.opcode = SD_SEND_RELATIVE_ADDR; cmd.arg = 0; cmd.flags = MMC_RSP_R6 | MMC_CMD_BCR; @@ -249,10 +241,6 @@ int mmc_app_send_scr(struct mmc_card *card, u32 *scr) struct scatterlist sg; void *data_buf; - BUG_ON(!card); - BUG_ON(!card->host); - BUG_ON(!scr); - /* NOTE: caller guarantees scr is heap-allocated */ err = mmc_app_cmd(card->host, card); @@ -307,9 +295,6 @@ int mmc_sd_switch(struct mmc_card *card, int mode, int group, struct mmc_data data = {0}; struct scatterlist sg; - BUG_ON(!card); - BUG_ON(!card->host); - /* NOTE: caller guarantees resp is heap-allocated */ mode = !!mode; @@ -352,10 +337,6 @@ int mmc_app_sd_status(struct mmc_card *card, void *ssr) struct mmc_data data = {0}; struct scatterlist sg; - BUG_ON(!card); - BUG_ON(!card->host); - BUG_ON(!ssr); - /* NOTE: caller guarantees ssr is heap-allocated */ err = mmc_app_cmd(card->host, card); -- cgit v1.2.3 From 6ff897ff5c62cd0454af39734408fcec8c4cf3f3 Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Wed, 2 Nov 2016 15:26:16 +0800 Subject: mmc: core: remove BUG_ONs from core.c BUG_ONs doesn't help anything except for stop the system from running. If it occurs, it implies we should deploy proper error handling for that. So this patch is gonna discard these meaningless BUG_ONs and deploy erro