aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc
diff options
context:
space:
mode:
authorAdrian Hunter <adrian.hunter@intel.com>2011-11-28 09:22:00 -0500
committerChris Ball <cjb@laptop.org>2012-01-11 23:58:43 -0500
commitd30495048892980e5d453328d1cc9343b3f7e917 (patch)
treeeff2ac501e38bad357c837eb6bf2835f7e83eba8 /drivers/mmc
parent482fce997e143a8d5429406fe066d31aa76ef70a (diff)
mmc: allow upper layers to know immediately if card has been removed
Add a function mmc_detect_card_removed() which upper layers can use to determine immediately if a card has been removed. This function should be called after an I/O request fails so that all queued I/O requests can be errored out immediately instead of waiting for the card device to be removed. Signed-off-by: Adrian Hunter <adrian.hunter@intel.com> Acked-by: Sujit Reddy Thumma <sthumma@codeaurora.org> Signed-off-by: Chris Ball <cjb@laptop.org>
Diffstat (limited to 'drivers/mmc')
-rw-r--r--drivers/mmc/core/core.c51
-rw-r--r--drivers/mmc/core/core.h3
-rw-r--r--drivers/mmc/core/mmc.c12
-rw-r--r--drivers/mmc/core/sd.c12
-rw-r--r--drivers/mmc/core/sdio.c11
5 files changed, 83 insertions, 6 deletions
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 950b97d7412a..a2aa860956ef 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -140,7 +140,7 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq)
140 cmd->retries = 0; 140 cmd->retries = 0;
141 } 141 }
142 142
143 if (err && cmd->retries) { 143 if (err && cmd->retries && !mmc_card_removed(host->card)) {
144 /* 144 /*
145 * Request starter must handle retries - see 145 * Request starter must handle retries - see
146 * mmc_wait_for_req_done(). 146 * mmc_wait_for_req_done().
@@ -247,6 +247,11 @@ static void __mmc_start_req(struct mmc_host *host, struct mmc_request *mrq)
247{ 247{
248 init_completion(&mrq->completion); 248 init_completion(&mrq->completion);
249 mrq->done = mmc_wait_done; 249 mrq->done = mmc_wait_done;
250 if (mmc_card_removed(host->card)) {
251 mrq->cmd->error = -ENOMEDIUM;
252 complete(&mrq->completion);
253 return;
254 }
250 mmc_start_request(host, mrq); 255 mmc_start_request(host, mrq);
251} 256}
252 257
@@ -259,7 +264,8 @@ static void mmc_wait_for_req_done(struct mmc_host *host,
259 wait_for_completion(&mrq->completion); 264 wait_for_completion(&mrq->completion);
260 265
261 cmd = mrq->cmd; 266 cmd = mrq->cmd;
262 if (!cmd->error || !cmd->retries) 267 if (!cmd->error || !cmd->retries ||
268 mmc_card_removed(host->card))
263 break; 269 break;
264 270
265 pr_debug("%s: req failed (CMD%u): %d, retrying...\n", 271 pr_debug("%s: req failed (CMD%u): %d, retrying...\n",
@@ -1456,7 +1462,7 @@ void mmc_detect_change(struct mmc_host *host, unsigned long delay)
1456 WARN_ON(host->removed); 1462 WARN_ON(host->removed);
1457 spin_unlock_irqrestore(&host->lock, flags); 1463 spin_unlock_irqrestore(&host->lock, flags);
1458#endif 1464#endif
1459 1465 host->detect_change = 1;
1460 mmc_schedule_delayed_work(&host->detect, delay); 1466 mmc_schedule_delayed_work(&host->detect, delay);
1461} 1467}
1462 1468
@@ -2049,6 +2055,43 @@ static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq)
2049 return -EIO; 2055 return -EIO;
2050} 2056}
2051 2057
2058int _mmc_detect_card_removed(struct mmc_host *host)
2059{
2060 int ret;
2061
2062 if ((host->caps & MMC_CAP_NONREMOVABLE) || !host->bus_ops->alive)
2063 return 0;
2064
2065 if (!host->card || mmc_card_removed(host->card))
2066 return 1;
2067
2068 ret = host->bus_ops->alive(host);
2069 if (ret) {
2070 mmc_card_set_removed(host->card);
2071 pr_debug("%s: card remove detected\n", mmc_hostname(host));
2072 }
2073
2074 return ret;
2075}
2076
2077int mmc_detect_card_removed(struct mmc_host *host)
2078{
2079 struct mmc_card *card = host->card;
2080
2081 WARN_ON(!host->claimed);
2082 /*
2083 * The card will be considered unchanged unless we have been asked to
2084 * detect a change or host requires polling to provide card detection.
2085 */
2086 if (card && !host->detect_change && !(host->caps & MMC_CAP_NEEDS_POLL))
2087 return mmc_card_removed(card);
2088
2089 host->detect_change = 0;
2090
2091 return _mmc_detect_card_removed(host);
2092}
2093EXPORT_SYMBOL(mmc_detect_card_removed);
2094
2052void mmc_rescan(struct work_struct *work) 2095void mmc_rescan(struct work_struct *work)
2053{ 2096{
2054 static const unsigned freqs[] = { 400000, 300000, 200000, 100000 }; 2097 static const unsigned freqs[] = { 400000, 300000, 200000, 100000 };
@@ -2069,6 +2112,8 @@ void mmc_rescan(struct work_struct *work)
2069 && !(host->caps & MMC_CAP_NONREMOVABLE)) 2112 && !(host->caps & MMC_CAP_NONREMOVABLE))
2070 host->bus_ops->detect(host); 2113 host->bus_ops->detect(host);
2071 2114
2115 host->detect_change = 0;
2116
2072 /* 2117 /*
2073 * Let mmc_bus_put() free the bus/bus_ops if we've found that 2118 * Let mmc_bus_put() free the bus/bus_ops if we've found that
2074 * the card is no longer present. 2119 * the card is no longer present.
diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h
index 14664f1fb16f..34009241213c 100644
--- a/drivers/mmc/core/core.h
+++ b/drivers/mmc/core/core.h
@@ -24,6 +24,7 @@ struct mmc_bus_ops {
24 int (*resume)(struct mmc_host *); 24 int (*resume)(struct mmc_host *);
25 int (*power_save)(struct mmc_host *); 25 int (*power_save)(struct mmc_host *);
26 int (*power_restore)(struct mmc_host *); 26 int (*power_restore)(struct mmc_host *);
27 int (*alive)(struct mmc_host *);
27}; 28};
28 29
29void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops); 30void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops);
@@ -59,6 +60,8 @@ void mmc_rescan(struct work_struct *work);
59void mmc_start_host(struct mmc_host *host); 60void mmc_start_host(struct mmc_host *host);
60void mmc_stop_host(struct mmc_host *host); 61void mmc_stop_host(struct mmc_host *host);
61 62
63int _mmc_detect_card_removed(struct mmc_host *host);
64
62int mmc_attach_mmc(struct mmc_host *host); 65int mmc_attach_mmc(struct mmc_host *host);
63int mmc_attach_sd(struct mmc_host *host); 66int mmc_attach_sd(struct mmc_host *host);
64int mmc_attach_sdio(struct mmc_host *host); 67int mmc_attach_sdio(struct mmc_host *host);
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index d240427c1246..fc1059bb6a08 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -1105,6 +1105,14 @@ static void mmc_remove(struct mmc_host *host)
1105} 1105}
1106 1106
1107/* 1107/*
1108 * Card detection - card is alive.
1109 */
1110static int mmc_alive(struct mmc_host *host)
1111{
1112 return mmc_send_status(host->card, NULL);
1113}
1114
1115/*
1108 * Card detection callback from host. 1116 * Card detection callback from host.
1109 */ 1117 */
1110static void mmc_detect(struct mmc_host *host) 1118static void mmc_detect(struct mmc_host *host)
@@ -1119,7 +1127,7 @@ static void mmc_detect(struct mmc_host *host)
1119 /* 1127 /*
1120 * Just check if our card has been removed. 1128 * Just check if our card has been removed.
1121 */ 1129 */
1122 err = mmc_send_status(host->card, NULL); 1130 err = _mmc_detect_card_removed(host);
1123 1131
1124 mmc_release_host(host); 1132 mmc_release_host(host);
1125 1133
@@ -1224,6 +1232,7 @@ static const struct mmc_bus_ops mmc_ops = {
1224 .suspend = NULL, 1232 .suspend = NULL,
1225 .resume = NULL, 1233 .resume = NULL,
1226 .power_restore = mmc_power_restore, 1234 .power_restore = mmc_power_restore,
1235 .alive = mmc_alive,
1227}; 1236};
1228 1237
1229static const struct mmc_bus_ops mmc_ops_unsafe = { 1238static const struct mmc_bus_ops mmc_ops_unsafe = {
@@ -1234,6 +1243,7 @@ static const struct mmc_bus_ops mmc_ops_unsafe = {
1234 .suspend = mmc_suspend, 1243 .suspend = mmc_suspend,
1235 .resume = mmc_resume, 1244 .resume = mmc_resume,
1236 .power_restore = mmc_power_restore, 1245 .power_restore = mmc_power_restore,
1246 .alive = mmc_alive,
1237}; 1247};
1238 1248
1239static void mmc_attach_bus_ops(struct mmc_host *host) 1249static void mmc_attach_bus_ops(struct mmc_host *host)
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index 85b858f6d5d4..6f27d35081b8 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -1019,6 +1019,14 @@ static void mmc_sd_remove(struct mmc_host *host)
1019} 1019}
1020 1020
1021/* 1021/*
1022 * Card detection - card is alive.
1023 */
1024static int mmc_sd_alive(struct mmc_host *host)
1025{
1026 return mmc_send_status(host->card, NULL);
1027}
1028
1029/*
1022 * Card detection callback from host. 1030 * Card detection callback from host.
1023 */ 1031 */
1024static void mmc_sd_detect(struct mmc_host *host) 1032static void mmc_sd_detect(struct mmc_host *host)
@@ -1033,7 +1041,7 @@ static void mmc_sd_detect(struct mmc_host *host)
1033 /* 1041 /*
1034 * Just check if our card has been removed. 1042 * Just check if our card has been removed.
1035 */ 1043 */
1036 err = mmc_send_status(host->card, NULL); 1044 err = _mmc_detect_card_removed(host);
1037 1045
1038 mmc_release_host(host); 1046 mmc_release_host(host);
1039 1047
@@ -1102,6 +1110,7 @@ static const struct mmc_bus_ops mmc_sd_ops = {
1102 .suspend = NULL, 1110 .suspend = NULL,
1103 .resume = NULL, 1111 .resume = NULL,
1104 .power_restore = mmc_sd_power_restore, 1112 .power_restore = mmc_sd_power_restore,
1113 .alive = mmc_sd_alive,
1105}; 1114};
1106 1115
1107static const struct mmc_bus_ops mmc_sd_ops_unsafe = { 1116static const struct mmc_bus_ops mmc_sd_ops_unsafe = {
@@ -1110,6 +1119,7 @@ static const struct mmc_bus_ops mmc_sd_ops_unsafe = {
1110 .suspend = mmc_sd_suspend, 1119 .suspend = mmc_sd_suspend,
1111 .resume = mmc_sd_resume, 1120 .resume = mmc_sd_resume,
1112 .power_restore = mmc_sd_power_restore, 1121 .power_restore = mmc_sd_power_restore,
1122 .alive = mmc_sd_alive,
1113}; 1123};
1114 1124
1115static void mmc_sd_attach_bus_ops(struct mmc_host *host) 1125static void mmc_sd_attach_bus_ops(struct mmc_host *host)
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
index 8c04f7f46dec..b77f770ce5d1 100644
--- a/drivers/mmc/core/sdio.c
+++ b/drivers/mmc/core/sdio.c
@@ -820,6 +820,14 @@ static void mmc_sdio_remove(struct mmc_host *host)
820} 820}
821 821
822/* 822/*
823 * Card detection - card is alive.
824 */
825static int mmc_sdio_alive(struct mmc_host *host)
826{
827 return mmc_select_card(host->card);
828}
829
830/*
823 * Card detection callback from host. 831 * Card detection callback from host.
824 */ 832 */
825static void mmc_sdio_detect(struct mmc_host *host) 833static void mmc_sdio_detect(struct mmc_host *host)
@@ -841,7 +849,7 @@ static void mmc_sdio_detect(struct mmc_host *host)
841 /* 849 /*
842 * Just check if our card has been removed. 850 * Just check if our card has been removed.
843 */ 851 */
844 err = mmc_select_card(host->card); 852 err = _mmc_detect_card_removed(host);
845 853
846 mmc_release_host(host); 854 mmc_release_host(host);
847 855
@@ -1019,6 +1027,7 @@ static const struct mmc_bus_ops mmc_sdio_ops = {
1019 .suspend = mmc_sdio_suspend, 1027 .suspend = mmc_sdio_suspend,
1020 .resume = mmc_sdio_resume, 1028 .resume = mmc_sdio_resume,
1021 .power_restore = mmc_sdio_power_restore, 1029 .power_restore = mmc_sdio_power_restore,
1030 .alive = mmc_sdio_alive,
1022}; 1031};
1023 1032
1024 1033