mmc: core: hw_reset changes
v5 cover mmc: core: hw_reset changes
Make the mmc_hw_reset routines more generic, by putting the (e)MMC- specific stuff in the new bus_ops->hw_reset. Simplify them by putting the functionality required by the mmc_test framework in mmc_test.c
As I don't have an eMMC device myself, much less one with a reset line, I'd be very happy if someone could help me test the code with an eMMC?
v5:
- Move the mmc_test-specific code to mmc_test.c
- Fall back to a power_cycle if the bus_ops->hw_reset is missing
- Because of this, skip the bus_ops->hw_reset in sd.c
v4:
- Rebase onto next
v3:
- Keep mmc_can_reset
- Always set bus_mode = MMC_BUSMODE_PUSHPULL in mmc_set_initial_state()
v2:
- Call the new bus_ops member hw_reset instead of power_reset
- Create mmc_set_initial_state and call it from mmc_mmc_hw_reset instead of mmc_power_up
- Keep "mmc_hw_reset" naming
Johan Rudholm (2):
mmc: core: refactor the hw_reset routines
mmc: core: let hw_reset default to power_cycle
drivers/mmc/card/mmc_test.c | 24 +++++++++----- drivers/mmc/core/core.c | 70 ++++++++++++++++-------------------------- drivers/mmc/core/core.h | 2 +- drivers/mmc/core/mmc.c | 23 ++++++++++++++ drivers/mmc/core/mmc_ops.c | 1 + drivers/mmc/core/mmc_ops.h | 1 - include/linux/mmc/core.h | 5 ++- 7 files changed, 70 insertions(+), 56 deletions(-)
Signature · 1 line
1.7.2.5
PATCH v5 1/2 mmc: core: refactor the hw_reset routines
Split the (e)MMC specific hw_reset code from core.c into mmc.c and mmc_test.c. Call the code from the new bus_ops member hw_reset.
Export mmc_set_initial_state and mmc_send_status so that they may be called from mmc_test.
--- drivers/mmc/card/mmc_test.c | 24 ++++++++++------ drivers/mmc/core/core.c | 66 +++++++++++++++---------------------------- drivers/mmc/core/core.h | 2 +- drivers/mmc/core/mmc.c | 23 +++++++++++++++ drivers/mmc/core/mmc_ops.c | 1 + drivers/mmc/core/mmc_ops.h | 1 - include/linux/mmc/core.h | 5 ++- 7 files changed, 66 insertions(+), 56 deletions(-)
drivers/mmc/card/mmc_test.c +15 -9
@@ -2342,20 +2342,26 @@ static int mmc_test_hw_reset(struct mmc_test_card *test)struct mmc_host *host = card->host;int err; - err =mmc_hw_reset_check (host); -if (!err) -return RESULT_OK ; +if (!mmc_card_mmc (card)) +return RESULT_UNSUP_CARD ; -if (err == -ENOSYS ) -return RESULT_FAIL ; + err =mmc_hw_reset_noinit (host); +if (!err) { +u32 status; -if (err != -EOPNOTSUPP ) -return err; +if (!mmc_send_status (card, &status)) +return RESULT_FAIL ; +mmc_set_initial_state (host); +mmc_power_restore_host (host); +return RESULT_OK ; + } -if (!mmc_can_reset (card)) +if (err == -ENOSYS ) +return RESULT_UNSUP_HOST ; +else if (err == -EOPNOTSUPP )return RESULT_UNSUP_CARD ; -return RESULT_UNSUP_HOST ; +return RESULT_FAIL ; }static const struct mmc_test_case mmc_test_cases[] = {
drivers/mmc/core/core.c +23 -43
95 lines not on this page · raw message
drivers/mmc/core/core.h +1 -1
@@ -27,6 +27,7 @@ struct mmc_bus_ops {int (*power_restore)(struct mmc_host *);int (*alive)(struct mmc_host *);int (*shutdown)(struct mmc_host *); +int (*hw_reset)(struct mmc_host *); };void mmc_attach_bus (struct mmc_host *host,const struct mmc_bus_ops *ops);
@@ -49,7 +50,6 @@ void mmc_set_driver_type(struct mmc_host *host, unsigned int drv_type);void mmc_power_up (struct mmc_host *host,u32 ocr);void mmc_power_off (struct mmc_host *host);void mmc_power_cycle (struct mmc_host *host,u32 ocr); -void mmc_set_initial_state (struct mmc_host *host);static inline void mmc_delay (unsigned int ms) {
drivers/mmc/core/mmc.c +23 -0
@@ -1821,6 +1821,28 @@ static int mmc_power_restore(struct mmc_host *host)return ret; } +static int mmc_mmc_hw_reset (struct mmc_host *host) +{ +struct mmc_card *card = host->card; +u8 rst_n_function; + + rst_n_function = card->ext_csd.rst_n_function; +if ((rst_n_function &EXT_CSD_RST_N_EN_MASK ) !=EXT_CSD_RST_N_ENABLED ) +return -EOPNOTSUPP ; + +if (!(host->caps &MMC_CAP_HW_RESET ) || !host->ops->hw_reset) +return -ENOSYS ; + +mmc_host_clk_hold (host); +mmc_set_clock (host, host->f_init); + + host->ops->hw_reset (host); + +mmc_host_clk_release (host); + +return 0 ; +} +static const struct mmc_bus_ops mmc_ops = { .remove = mmc_remove, .detect = mmc_detect,
@@ -1831,6 +1853,7 @@ static const struct mmc_bus_ops mmc_ops = { .power_restore = mmc_power_restore, .alive = mmc_alive, .shutdown = mmc_shutdown, + .hw_reset = mmc_mmc_hw_reset, };/*
drivers/mmc/core/mmc_ops.c +1 -0
@@ -56,6 +56,7 @@ int mmc_send_status(struct mmc_card *card, u32 *status) {return __mmc_send_status (card, status, false); } +EXPORT_SYMBOL_GPL (mmc_send_status);static int _mmc_select_card (struct mmc_host *host,struct mmc_card *card) {
drivers/mmc/core/mmc_ops.h +0 -1
@@ -20,7 +20,6 @@ int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr);int mmc_all_send_cid (struct mmc_host *host,u32 *cid);int mmc_set_relative_addr (struct mmc_card *card);int mmc_send_csd (struct mmc_card *card,u32 *csd); -int mmc_send_status (struct mmc_card *card,u32 *status);int mmc_send_cid (struct mmc_host *host,u32 *cid);int mmc_spi_read_ocr (struct mmc_host *host,int highcap,u32 *ocrp);int mmc_spi_set_crc (struct mmc_host *host,int use_crc);
include/linux/mmc/core.h +3 -2
@@ -156,6 +156,7 @@ extern int __mmc_switch(struct mmc_card *, u8, u8, u8, unsigned int, bool,extern int mmc_switch (struct mmc_card *,u8 ,u8 ,u8 ,unsigned int );extern int mmc_send_tuning (struct mmc_card *card);extern int mmc_get_ext_csd (struct mmc_card *card,u8 **new_ext_csd); +extern int mmc_send_status (struct mmc_card *card,u32 *status);#define MMC_ERASE_ARG 0x00000000#define MMC_SECURE_ERASE_ARG 0x80000000
@@ -182,8 +183,7 @@ extern int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen);extern int mmc_set_blockcount (struct mmc_card *card,unsigned int blockcount,bool is_rel_write);extern int mmc_hw_reset (struct mmc_host *host); -extern int mmc_hw_reset_check (struct mmc_host *host); -extern int mmc_can_reset (struct mmc_card *card); +extern int mmc_hw_reset_noinit (struct mmc_host *host);extern void mmc_set_data_timeout (struct mmc_data *,const struct mmc_card *);extern unsigned int mmc_align_data_size (struct mmc_card *,unsigned int );
@@ -198,6 +198,7 @@ extern int mmc_flush_cache(struct mmc_card *);extern int mmc_detect_card_removed (struct mmc_host *host); +extern void mmc_set_initial_state (struct mmc_host *host);/** * mmc_claim_host - exclusively claim a host * @host: mmc host to claim
Signature · 1 line
1.7.2.5
PATCH v5 2/2 mmc: core: let hw_reset default to power_cycle
In reply to Johan RudholmIf bus_ops->hw_reset is missing, try to power cycle the card instead.
This will allow SD cards to be power cycled and re-initialized as well. Power cycling a buggy SD card sometimes helps it get back on track.
--- drivers/mmc/core/core.c | 18 +++++++++++------- 1 files changed, 11 insertions(+), 7 deletions(-)
drivers/mmc/core/core.c +11 -7
@@ -2254,19 +2254,23 @@ static int mmc_do_hw_reset(struct mmc_host *host, int do_init)return -EINVAL ;mmc_bus_get (host); -if (!host->bus_ops || host->bus_dead || !host->bus_ops->hw_reset) { +if (!host->bus_ops || host->bus_dead) { ret = -EINVAL ; goto out; } - ret = host->bus_ops->hw_reset (host); -if (ret) - goto out; +if (!host->bus_ops->hw_reset) { +mmc_power_cycle (host, host->card->ocr); + }else { + ret = host->bus_ops->hw_reset (host); +if (ret) + goto out; +if (do_init) +mmc_set_initial_state (host); + } -if (do_init) { -mmc_set_initial_state (host); +if (do_init) ret = host->bus_ops->power_restore (host); - }pr_warn ("%s: tried to reset card\n" ,mmc_hostname (host)); out:
Signature · 1 line
1.7.2.5