diff options
-rw-r--r-- | drivers/mmc/core/core.c | 51 | ||||
-rw-r--r-- | drivers/mmc/core/core.h | 3 | ||||
-rw-r--r-- | drivers/mmc/core/mmc.c | 12 | ||||
-rw-r--r-- | drivers/mmc/core/sd.c | 12 | ||||
-rw-r--r-- | drivers/mmc/core/sdio.c | 11 | ||||
-rw-r--r-- | include/linux/mmc/card.h | 3 | ||||
-rw-r--r-- | include/linux/mmc/core.h | 2 | ||||
-rw-r--r-- | include/linux/mmc/host.h | 1 |
8 files changed, 89 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 | ||
2058 | int _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 | |||
2077 | int 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 | } | ||
2093 | EXPORT_SYMBOL(mmc_detect_card_removed); | ||
2094 | |||
2052 | void mmc_rescan(struct work_struct *work) | 2095 | void 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 | ||
29 | void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops); | 30 | void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops); |
@@ -59,6 +60,8 @@ void mmc_rescan(struct work_struct *work); | |||
59 | void mmc_start_host(struct mmc_host *host); | 60 | void mmc_start_host(struct mmc_host *host); |
60 | void mmc_stop_host(struct mmc_host *host); | 61 | void mmc_stop_host(struct mmc_host *host); |
61 | 62 | ||
63 | int _mmc_detect_card_removed(struct mmc_host *host); | ||
64 | |||
62 | int mmc_attach_mmc(struct mmc_host *host); | 65 | int mmc_attach_mmc(struct mmc_host *host); |
63 | int mmc_attach_sd(struct mmc_host *host); | 66 | int mmc_attach_sd(struct mmc_host *host); |
64 | int mmc_attach_sdio(struct mmc_host *host); | 67 | int 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 | */ | ||
1110 | static 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 | */ |
1110 | static void mmc_detect(struct mmc_host *host) | 1118 | static 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 | ||
1229 | static const struct mmc_bus_ops mmc_ops_unsafe = { | 1238 | static 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 | ||
1239 | static void mmc_attach_bus_ops(struct mmc_host *host) | 1249 | static 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 | */ | ||
1024 | static 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 | */ |
1024 | static void mmc_sd_detect(struct mmc_host *host) | 1032 | static 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 | ||
1107 | static const struct mmc_bus_ops mmc_sd_ops_unsafe = { | 1116 | static 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 | ||
1115 | static void mmc_sd_attach_bus_ops(struct mmc_host *host) | 1125 | static 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 | */ | ||
825 | static 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 | */ |
825 | static void mmc_sdio_detect(struct mmc_host *host) | 833 | static 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 | ||
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h index 534974c3ef0c..6402d9224d6a 100644 --- a/include/linux/mmc/card.h +++ b/include/linux/mmc/card.h | |||
@@ -209,6 +209,7 @@ struct mmc_card { | |||
209 | #define MMC_STATE_HIGHSPEED_DDR (1<<4) /* card is in high speed mode */ | 209 | #define MMC_STATE_HIGHSPEED_DDR (1<<4) /* card is in high speed mode */ |
210 | #define MMC_STATE_ULTRAHIGHSPEED (1<<5) /* card is in ultra high speed mode */ | 210 | #define MMC_STATE_ULTRAHIGHSPEED (1<<5) /* card is in ultra high speed mode */ |
211 | #define MMC_CARD_SDXC (1<<6) /* card is SDXC */ | 211 | #define MMC_CARD_SDXC (1<<6) /* card is SDXC */ |
212 | #define MMC_CARD_REMOVED (1<<7) /* card has been removed */ | ||
212 | unsigned int quirks; /* card quirks */ | 213 | unsigned int quirks; /* card quirks */ |
213 | #define MMC_QUIRK_LENIENT_FN0 (1<<0) /* allow SDIO FN0 writes outside of the VS CCCR range */ | 214 | #define MMC_QUIRK_LENIENT_FN0 (1<<0) /* allow SDIO FN0 writes outside of the VS CCCR range */ |
214 | #define MMC_QUIRK_BLKSZ_FOR_BYTE_MODE (1<<1) /* use func->cur_blksize */ | 215 | #define MMC_QUIRK_BLKSZ_FOR_BYTE_MODE (1<<1) /* use func->cur_blksize */ |
@@ -370,6 +371,7 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data) | |||
370 | #define mmc_card_uhs(c) ((c)->state & MMC_STATE_ULTRAHIGHSPEED) | 371 | #define mmc_card_uhs(c) ((c)->state & MMC_STATE_ULTRAHIGHSPEED) |
371 | #define mmc_sd_card_uhs(c) ((c)->state & MMC_STATE_ULTRAHIGHSPEED) | 372 | #define mmc_sd_card_uhs(c) ((c)->state & MMC_STATE_ULTRAHIGHSPEED) |
372 | #define mmc_card_ext_capacity(c) ((c)->state & MMC_CARD_SDXC) | 373 | #define mmc_card_ext_capacity(c) ((c)->state & MMC_CARD_SDXC) |
374 | #define mmc_card_removed(c) ((c) && ((c)->state & MMC_CARD_REMOVED)) | ||
373 | 375 | ||
374 | #define mmc_card_set_present(c) ((c)->state |= MMC_STATE_PRESENT) | 376 | #define mmc_card_set_present(c) ((c)->state |= MMC_STATE_PRESENT) |
375 | #define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY) | 377 | #define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY) |
@@ -379,6 +381,7 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data) | |||
379 | #define mmc_card_set_uhs(c) ((c)->state |= MMC_STATE_ULTRAHIGHSPEED) | 381 | #define mmc_card_set_uhs(c) ((c)->state |= MMC_STATE_ULTRAHIGHSPEED) |
380 | #define mmc_sd_card_set_uhs(c) ((c)->state |= MMC_STATE_ULTRAHIGHSPEED) | 382 | #define mmc_sd_card_set_uhs(c) ((c)->state |= MMC_STATE_ULTRAHIGHSPEED) |
381 | #define mmc_card_set_ext_capacity(c) ((c)->state |= MMC_CARD_SDXC) | 383 | #define mmc_card_set_ext_capacity(c) ((c)->state |= MMC_CARD_SDXC) |
384 | #define mmc_card_set_removed(c) ((c)->state |= MMC_CARD_REMOVED) | ||
382 | 385 | ||
383 | /* | 386 | /* |
384 | * Quirk add/remove for MMC products. | 387 | * Quirk add/remove for MMC products. |
diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h index 174a844a5dda..87a976cc5654 100644 --- a/include/linux/mmc/core.h +++ b/include/linux/mmc/core.h | |||
@@ -180,6 +180,8 @@ extern int mmc_try_claim_host(struct mmc_host *host); | |||
180 | 180 | ||
181 | extern int mmc_flush_cache(struct mmc_card *); | 181 | extern int mmc_flush_cache(struct mmc_card *); |
182 | 182 | ||
183 | extern int mmc_detect_card_removed(struct mmc_host *host); | ||
184 | |||
183 | /** | 185 | /** |
184 | * mmc_claim_host - exclusively claim a host | 186 | * mmc_claim_host - exclusively claim a host |
185 | * @host: mmc host to claim | 187 | * @host: mmc host to claim |
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index 706f72279a17..9a03d0335745 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h | |||
@@ -299,6 +299,7 @@ struct mmc_host { | |||
299 | int claim_cnt; /* "claim" nesting count */ | 299 | int claim_cnt; /* "claim" nesting count */ |
300 | 300 | ||
301 | struct delayed_work detect; | 301 | struct delayed_work detect; |
302 | int detect_change; /* card detect flag */ | ||
302 | 303 | ||
303 | const struct mmc_bus_ops *bus_ops; /* current bus driver */ | 304 | const struct mmc_bus_ops *bus_ops; /* current bus driver */ |
304 | unsigned int bus_refs; /* reference counter */ | 305 | unsigned int bus_refs; /* reference counter */ |