mmc: core: hw_reset changes
v4 cover mmc: core: hw_reset changes
Make the mmc_hw_reset routines more generic, so we can easily add a power cycle of SD cards as well. Also simplify the (e)MMC specific parts of the reset code.
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?
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: turn hw_reset into a bus_ops
mmc: sd: add hw_reset callback
drivers/mmc/core/core.c | 56 +++++++++++++++------------------------------- drivers/mmc/core/core.h | 5 ++++ drivers/mmc/core/mmc.c | 40 +++++++++++++++++++++++++++++++++ drivers/mmc/core/sd.c | 13 +++++++++++ 4 files changed, 76 insertions(+), 38 deletions(-)
Signature · 1 line
1.7.2.5
PATCH v4 1/2 mmc: core: turn hw_reset into a bus_ops
Move the (e)MMC specific hw_reset code from core.c into mmc.c and call it from the new bus_ops member hw_reset. This also lets us add code for resetting SD cards as well.
--- drivers/mmc/core/core.c | 56 +++++++++++++++------------------------------- drivers/mmc/core/core.h | 5 ++++ drivers/mmc/core/mmc.c | 40 +++++++++++++++++++++++++++++++++ 3 files changed, 63 insertions(+), 38 deletions(-)
drivers/mmc/core/core.c +18 -38
@@ -2245,67 +2245,47 @@ static void mmc_hw_reset_for_init(struct mmc_host *host)mmc_host_clk_release (host); } -int mmc_can_reset (struct mmc_card *card) -{ -u8 rst_n_function; - -if (!mmc_card_mmc (card)) -return 0 ; - 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 0 ; -return 1 ; -} -EXPORT_SYMBOL (mmc_can_reset); - +/* Reset card in a bus-specific way */ static int mmc_do_hw_reset (struct mmc_host *host,int check) { -struct mmc_card *card = host->card; - -if (!(host->caps &MMC_CAP_HW_RESET ) || !host->ops->hw_reset) -return -EOPNOTSUPP ; +int ret; -if (!card) +if (!host->card)return -EINVAL ; -if (!mmc_can_reset (card)) +if (!host->bus_ops || !host->bus_ops->hw_reset || + host->bus_ops->hw_reset (host,MMC_HW_RESET_TEST ))return -EOPNOTSUPP ; -mmc_host_clk_hold (host); -mmc_set_clock (host, host->f_init); + ret = host->bus_ops->hw_reset (host, check); - host->ops->hw_reset (host); - -/* If the reset has happened, then a status command will fail */ -if (check) { -u32 status; - -if (!mmc_send_status (card, &status)) { -mmc_host_clk_release (host); -return -ENOSYS ; - } - } - -/* Set initial state and call mmc_set_ios */ -mmc_set_initial_state (host); +if (check ==MMC_HW_RESET_TEST_CARD ) +return ret; -mmc_host_clk_release (host); +pr_warn ("%s: tried to reset card (status %d)\n" , +mmc_hostname (host), ret);return host->bus_ops->power_restore (host); }int mmc_hw_reset (struct mmc_host *host) { -return mmc_do_hw_reset (host,0 ); +return mmc_do_hw_reset (host,MMC_HW_RESET_RESET ); }EXPORT_SYMBOL (mmc_hw_reset);int mmc_hw_reset_check (struct mmc_host *host) { -return mmc_do_hw_reset (host,1 ); +return mmc_do_hw_reset (host,MMC_HW_RESET_CHECK ); }EXPORT_SYMBOL (mmc_hw_reset_check); +int mmc_can_reset (struct mmc_card *card) +{ +return mmc_do_hw_reset (card->host,MMC_HW_RESET_TEST_CARD ); +} +EXPORT_SYMBOL (mmc_can_reset); +static int mmc_rescan_try_freq (struct mmc_host *host,unsigned freq) { host->f_init = freq;
drivers/mmc/core/core.h +5 -0
@@ -27,6 +27,11 @@ 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 *,int ); +#define MMC_HW_RESET_RESET 0 +#define MMC_HW_RESET_TEST 1 +#define MMC_HW_RESET_CHECK 2 +#define MMC_HW_RESET_TEST_CARD 3 };void mmc_attach_bus (struct mmc_host *host,const struct mmc_bus_ops *ops);
drivers/mmc/core/mmc.c +40 -0
@@ -1821,6 +1821,45 @@ static int mmc_power_restore(struct mmc_host *host)return ret; } +static int mmc_mmc_hw_reset (struct mmc_host *host,int test) +{ +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 (test ==MMC_HW_RESET_TEST_CARD ) +return 0 ; + +if (!(host->caps &MMC_CAP_HW_RESET ) || !host->ops->hw_reset) +return -EOPNOTSUPP ; + +if (test ==MMC_HW_RESET_TEST ) +return 0 ; + +mmc_host_clk_hold (host); +mmc_set_clock (host, host->f_init); + + host->ops->hw_reset (host); + +if (test ==MMC_HW_RESET_CHECK ) { +u32 status; + +if (!mmc_send_status (card, &status)) { +mmc_host_clk_release (host); +return -ENOSYS ; + } + } + +mmc_set_initial_state (host); + +mmc_host_clk_release (host); + +return 0 ; +} +static const struct mmc_bus_ops mmc_ops = { .remove = mmc_remove, .detect = mmc_detect,
@@ -1831,6 +1870,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, };/*
Signature · 1 line
1.7.2.5
Re: [PATCH v4 1/2] mmc: core: turn hw_reset into a bus_ops
Quoted 21 lines · Johan Rudholm
Move the (e)MMC specific
hw_resetcode fromcore.cintommc.cand call it from the newbus_opsmemberhw_reset. This also lets us add code for resetting SD cards as well.Signed-off-by Johan Rudholm <[email protected]>--- drivers/mmc/core/core.c | 56 +++++++++++++++------------------------------- drivers/mmc/core/core.h | 5 ++++ drivers/mmc/core/mmc.c | 40 +++++++++++++++++++++++++++++++++ 3 files changed, 63 insertions(+), 38 deletions(-)drivers/mmc/core/core.c +0
-2@@ -2245,67 +2245,47 @@ static void mmc_hw_reset_for_init(struct mmc_host *host)mmc_host_clk_release (host); } -int mmc_can_reset (struct mmc_card *card) -{
drivers/mmc/core/core.c static void mmc_hw_reset_for_init(struct mmc_host *host) · line 2259
Quoted 10 lines
drivers/mmc/core/core.c +0
-10-u8 rst_n_function; - -if (!mmc_card_mmc (card)) -return 0 ; - 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 0 ; -return 1 ; -} -EXPORT_SYMBOL (mmc_can_reset);
Isn't the mmc_can_reset() function used from mmc_test.c?
Quoted 5 lines
drivers/mmc/core/core.c +1
-2- +/* Reset card in a bus-specific way */ static int mmc_do_hw_reset (struct mmc_host *host,int check) { -struct mmc_card *card = host->card;
drivers/mmc/core/core.c static void mmc_hw_reset_for_init(struct mmc_host *host) · line 2271
Quoted 10 lines
drivers/mmc/core/core.c +2
-5- -if (!(host->caps &MMC_CAP_HW_RESET ) || !host->ops->hw_reset) -return -EOPNOTSUPP ; +int ret; -if (!card) +if (!host->card)return -EINVAL ; -if (!mmc_can_reset (card))
You need a mmc_bus_get() here before accessing the host->bus_ops callbacks.
Well, if you would executed this code with the host claimed and from the mmc block layer, you can be sure the bus_ops to exist. Now, since this is an exported function, I think you need to be more safe to also do the mmc_bus_get|put().
drivers/mmc/core/core.c static void mmc_hw_reset_for_init(struct mmc_host *host) · line 2260
Quoted 7 lines
drivers/mmc/core/core.c +3
-2+if (!host->bus_ops || !host->bus_ops->hw_reset || + host->bus_ops->hw_reset (host,MMC_HW_RESET_TEST ))return -EOPNOTSUPP ; -mmc_host_clk_hold (host); -mmc_set_clock (host, host->f_init); + ret = host->bus_ops->hw_reset (host, check);
What's going on here? You are invoking the ->hw_reset() callback twice. That seems odd.
Quoted 53 lines
drivers/mmc/core/core.c +12
-17- host->ops->hw_reset (host); - -/* If the reset has happened, then a status command will fail */ -if (check) { -u32 status; - -if (!mmc_send_status (card, &status)) { -mmc_host_clk_release (host); -return -ENOSYS ; - } - } - -/* Set initial state and call mmc_set_ios */ -mmc_set_initial_state (host); +if (check ==MMC_HW_RESET_TEST_CARD ) +return ret; -mmc_host_clk_release (host); +pr_warn ("%s: tried to reset card (status %d)\n" , +mmc_hostname (host), ret);return host->bus_ops->power_restore (host); }int mmc_hw_reset (struct mmc_host *host) { -return mmc_do_hw_reset (host,0 ); +return mmc_do_hw_reset (host,MMC_HW_RESET_RESET ); }EXPORT_SYMBOL (mmc_hw_reset);int mmc_hw_reset_check (struct mmc_host *host) { -return mmc_do_hw_reset (host,1 ); +return mmc_do_hw_reset (host,MMC_HW_RESET_CHECK ); }EXPORT_SYMBOL (mmc_hw_reset_check); +int mmc_can_reset (struct mmc_card *card) +{ +return mmc_do_hw_reset (card->host,MMC_HW_RESET_TEST_CARD ); +} +EXPORT_SYMBOL (mmc_can_reset); +static int mmc_rescan_try_freq (struct mmc_host *host,unsigned freq) { host->f_init = freq;drivers/mmc/core/core.h +0
-0
drivers/mmc/core/core.h struct mmc_bus_ops { · line 34
Quoted 8 lines
drivers/mmc/core/core.h +5
-0@@ -27,6 +27,11 @@ 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 *,int ); +#define MMC_HW_RESET_RESET 0 +#define MMC_HW_RESET_TEST 1 +#define MMC_HW_RESET_CHECK 2 +#define MMC_HW_RESET_TEST_CARD 3
Urgh. Is there a way to remove all this? I just don't like all these options.
In fact, I would prefer to have none of them.
Quoted 62 lines
drivers/mmc/core/core.h +0
-0};void mmc_attach_bus (struct mmc_host *host,const struct mmc_bus_ops *ops);drivers/mmc/core/mmc.c +40
-1@@ -1821,6 +1821,45 @@ static int mmc_power_restore(struct mmc_host *host)return ret; } +static int mmc_mmc_hw_reset (struct mmc_host *host,int test) +{ +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 (test ==MMC_HW_RESET_TEST_CARD ) +return 0 ; + +if (!(host->caps &MMC_CAP_HW_RESET ) || !host->ops->hw_reset) +return -EOPNOTSUPP ; + +if (test ==MMC_HW_RESET_TEST ) +return 0 ; + +mmc_host_clk_hold (host); +mmc_set_clock (host, host->f_init); + + host->ops->hw_reset (host); + +if (test ==MMC_HW_RESET_CHECK ) { +u32 status; + +if (!mmc_send_status (card, &status)) { +mmc_host_clk_release (host); +return -ENOSYS ; + } + } + +mmc_set_initial_state (host); + +mmc_host_clk_release (host); + +return 0 ; +} +static const struct mmc_bus_ops mmc_ops = { .remove = mmc_remove, .detect = mmc_detect,@@ -1831,6 +1870,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, };/* --
Quoted 2 lines
1.7.2.5
Kind regards
Uffe
Re: [PATCH v4 1/2] mmc: core: turn hw_reset into a bus_ops
Hi Ulf,
2014-11-25 14:48 GMT+01:00 Ulf Hansson <[email protected]>:
Quoted 20 lines · Johan Rudholm
Quoted 19 lines
Move the (e)MMC specific
hw_resetcode fromcore.cintommc.cand call it from the newbus_opsmemberhw_reset. This also lets us add code for resetting SD cards as well.Signed-off-by Johan Rudholm <[email protected]>--- drivers/mmc/core/core.c | 56 +++++++++++++++------------------------------- drivers/mmc/core/core.h | 5 ++++ drivers/mmc/core/mmc.c | 40 +++++++++++++++++++++++++++++++++ 3 files changed, 63 insertions(+), 38 deletions(-)drivers/mmc/core/core.c +0
-0@@ -2245,67 +2245,47 @@ static void mmc_hw_reset_for_init(struct mmc_host *host)mmc_host_clk_release (host); }
Quoted 14 lines
drivers/mmc/core/core.c static void mmc_hw_reset_for_init(struct mmc_host *host) · line 2259
Quoted 12 lines
drivers/mmc/core/core.c +0
-12-int mmc_can_reset (struct mmc_card *card) -{ -u8 rst_n_function; - -if (!mmc_card_mmc (card)) -return 0 ; - 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 0 ; -return 1 ; -} -EXPORT_SYMBOL (mmc_can_reset);Isn't the
mmc_can_reset()function used frommmc_test.c?
Yes. Maybe we should move this stuff to mmc_test instead. We could also move the code that checks if the reset worked or not to mmc_test, since this is the only place where the check is performed.
Quoted 14 lines
Quoted 14 lines
drivers/mmc/core/core.c +3
-6- +/* Reset card in a bus-specific way */ static int mmc_do_hw_reset (struct mmc_host *host,int check) { -struct mmc_card *card = host->card; - -if (!(host->caps &MMC_CAP_HW_RESET ) || !host->ops->hw_reset) -return -EOPNOTSUPP ; +int ret; -if (!card) +if (!host->card)return -EINVAL ;
Quoted 8 lines
drivers/mmc/core/core.c static void mmc_hw_reset_for_init(struct mmc_host *host) · line 2271
Quoted 1 line
drivers/mmc/core/core.c +0
-1-if (!mmc_can_reset (card))You need a
mmc_bus_get()here before accessing thehost->bus_opscallbacks.Well, if you would executed this code with the host claimed and from the mmc block layer, you can be sure the
bus_opsto exist. Now, since this is an exported function, I think you need to be more safe to also do the mmc_bus_get|put().
Got it, thanks.
Quoted 74 lines
drivers/mmc/core/core.c static void mmc_hw_reset_for_init(struct mmc_host *host) · line 2260
Quoted 7 lines
drivers/mmc/core/core.c +3
-2+if (!host->bus_ops || !host->bus_ops->hw_reset || + host->bus_ops->hw_reset (host,MMC_HW_RESET_TEST ))return -EOPNOTSUPP ; -mmc_host_clk_hold (host); -mmc_set_clock (host, host->f_init); + ret = host->bus_ops->hw_reset (host, check);What's going on here? You are invoking the ->hw_reset() callback twice. That seems odd.
Quoted 53 lines
drivers/mmc/core/core.c +12
-17- host->ops->hw_reset (host); - -/* If the reset has happened, then a status command will fail */ -if (check) { -u32 status; - -if (!mmc_send_status (card, &status)) { -mmc_host_clk_release (host); -return -ENOSYS ; - } - } - -/* Set initial state and call mmc_set_ios */ -mmc_set_initial_state (host); +if (check ==MMC_HW_RESET_TEST_CARD ) +return ret; -mmc_host_clk_release (host); +pr_warn ("%s: tried to reset card (status %d)\n" , +mmc_hostname (host), ret);return host->bus_ops->power_restore (host); }int mmc_hw_reset (struct mmc_host *host) { -return mmc_do_hw_reset (host,0 ); +return mmc_do_hw_reset (host,MMC_HW_RESET_RESET ); }EXPORT_SYMBOL (mmc_hw_reset);int mmc_hw_reset_check (struct mmc_host *host) { -return mmc_do_hw_reset (host,1 ); +return mmc_do_hw_reset (host,MMC_HW_RESET_CHECK ); }EXPORT_SYMBOL (mmc_hw_reset_check); +int mmc_can_reset (struct mmc_card *card) +{ +return mmc_do_hw_reset (card->host,MMC_HW_RESET_TEST_CARD ); +} +EXPORT_SYMBOL (mmc_can_reset); +static int mmc_rescan_try_freq (struct mmc_host *host,unsigned freq) { host->f_init = freq;drivers/mmc/core/core.h +0
-0drivers/mmc/core/core.h struct mmc_bus_ops { · line 34
Quoted 8 lines
drivers/mmc/core/core.h +5
-0@@ -27,6 +27,11 @@ 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 *,int ); +#define MMC_HW_RESET_RESET 0 +#define MMC_HW_RESET_TEST 1 +#define MMC_HW_RESET_CHECK 2 +#define MMC_HW_RESET_TEST_CARD 3Urgh. Is there a way to remove all this? I just don't like all these options.
Quoted 1 line
In fact, I would prefer to have none of them.
If we move the test and check functionality to mmc_test, I think we can avoid these. What do you think of this approach?
//Johan
Re: [PATCH v4 1/2] mmc: core: turn hw_reset into a bus_ops
Quoted 141 lines · Johan Rudholm
Hi Ulf,
2014-11-25 14:48 GMT+01:00 Ulf Hansson <[email protected]>:
Quoted 20 lines · Johan Rudholm
Quoted 19 lines
Move the (e)MMC specific
hw_resetcode fromcore.cintommc.cand call it from the newbus_opsmemberhw_reset. This also lets us add code for resetting SD cards as well.Signed-off-by Johan Rudholm <[email protected]>--- drivers/mmc/core/core.c | 56 +++++++++++++++------------------------------- drivers/mmc/core/core.h | 5 ++++ drivers/mmc/core/mmc.c | 40 +++++++++++++++++++++++++++++++++ 3 files changed, 63 insertions(+), 38 deletions(-)drivers/mmc/core/core.c +0
-0@@ -2245,67 +2245,47 @@ static void mmc_hw_reset_for_init(struct mmc_host *host)mmc_host_clk_release (host); }Quoted 14 lines
drivers/mmc/core/core.c static void mmc_hw_reset_for_init(struct mmc_host *host) · line 2259
Quoted 12 lines
drivers/mmc/core/core.c +0
-12-int mmc_can_reset (struct mmc_card *card) -{ -u8 rst_n_function; - -if (!mmc_card_mmc (card)) -return 0 ; - 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 0 ; -return 1 ; -} -EXPORT_SYMBOL (mmc_can_reset);Isn't the
mmc_can_reset()function used frommmc_test.c?Yes. Maybe we should move this stuff to
mmc_testinstead. We could also move the code that checks if the reset worked or not tommc_test, since this is the only place where the check is performed.Quoted 14 lines
Quoted 14 lines
drivers/mmc/core/core.c +3
-6- +/* Reset card in a bus-specific way */ static int mmc_do_hw_reset (struct mmc_host *host,int check) { -struct mmc_card *card = host->card; - -if (!(host->caps &MMC_CAP_HW_RESET ) || !host->ops->hw_reset) -return -EOPNOTSUPP ; +int ret; -if (!card) +if (!host->card)return -EINVAL ;Quoted 8 lines
drivers/mmc/core/core.c static void mmc_hw_reset_for_init(struct mmc_host *host) · line 2271
Quoted 1 line
drivers/mmc/core/core.c +0
-1-if (!mmc_can_reset (card))You need a
mmc_bus_get()here before accessing thehost->bus_opscallbacks.Well, if you would executed this code with the host claimed and from the mmc block layer, you can be sure the
bus_opsto exist. Now, since this is an exported function, I think you need to be more safe to also do the mmc_bus_get|put().Got it, thanks.
Quoted 74 lines
drivers/mmc/core/core.c static void mmc_hw_reset_for_init(struct mmc_host *host) · line 2260
Quoted 7 lines
drivers/mmc/core/core.c +3
-2+if (!host->bus_ops || !host->bus_ops->hw_reset || + host->bus_ops->hw_reset (host,MMC_HW_RESET_TEST ))return -EOPNOTSUPP ; -mmc_host_clk_hold (host); -mmc_set_clock (host, host->f_init); + ret = host->bus_ops->hw_reset (host, check);What's going on here? You are invoking the ->hw_reset() callback twice. That seems odd.
Quoted 53 lines
drivers/mmc/core/core.c +12
-17- host->ops->hw_reset (host); - -/* If the reset has happened, then a status command will fail */ -if (check) { -u32 status; - -if (!mmc_send_status (card, &status)) { -mmc_host_clk_release (host); -return -ENOSYS ; - } - } - -/* Set initial state and call mmc_set_ios */ -mmc_set_initial_state (host); +if (check ==MMC_HW_RESET_TEST_CARD ) +return ret; -mmc_host_clk_release (host); +pr_warn ("%s: tried to reset card (status %d)\n" , +mmc_hostname (host), ret);return host->bus_ops->power_restore (host); }int mmc_hw_reset (struct mmc_host *host) { -return mmc_do_hw_reset (host,0 ); +return mmc_do_hw_reset (host,MMC_HW_RESET_RESET ); }EXPORT_SYMBOL (mmc_hw_reset);int mmc_hw_reset_check (struct mmc_host *host) { -return mmc_do_hw_reset (host,1 ); +return mmc_do_hw_reset (host,MMC_HW_RESET_CHECK ); }EXPORT_SYMBOL (mmc_hw_reset_check); +int mmc_can_reset (struct mmc_card *card) +{ +return mmc_do_hw_reset (card->host,MMC_HW_RESET_TEST_CARD ); +} +EXPORT_SYMBOL (mmc_can_reset); +static int mmc_rescan_try_freq (struct mmc_host *host,unsigned freq) { host->f_init = freq;drivers/mmc/core/core.h +0
-0drivers/mmc/core/core.h struct mmc_bus_ops { · line 34
Quoted 8 lines
drivers/mmc/core/core.h +5
-0@@ -27,6 +27,11 @@ 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 *,int ); +#define MMC_HW_RESET_RESET 0 +#define MMC_HW_RESET_TEST 1 +#define MMC_HW_RESET_CHECK 2 +#define MMC_HW_RESET_TEST_CARD 3Urgh. Is there a way to remove all this? I just don't like all these options.
Quoted 4 lines
Quoted 1 line
In fact, I would prefer to have none of them.
If we move the test and check functionality to
mmc_test, I think we can avoid these. What do you think of this approach?
I like that approach.
In principle I think we should have only one API for hardware reset, typically that should be mmc_hw_reset(). Then, convert mmc_test_hw_reset() into invoking the mmc_hw_reset() API and let it handle further tests by itself.
Kind regards
Uffe
Re: [PATCH v4 1/2] mmc: core: turn hw_reset into a bus_ops
2014-11-27 10:50 GMT+01:00 Ulf Hansson <[email protected]>:
Quoted 147 lines · Johan Rudholm
Quoted 141 lines
Hi Ulf,
2014-11-25 14:48 GMT+01:00 Ulf Hansson <[email protected]>:
Quoted 20 lines · Johan Rudholm
Quoted 19 lines
Move the (e)MMC specific
hw_resetcode fromcore.cintommc.cand call it from the newbus_opsmemberhw_reset. This also lets us add code for resetting SD cards as well.Signed-off-by Johan Rudholm <[email protected]>--- drivers/mmc/core/core.c | 56 +++++++++++++++------------------------------- drivers/mmc/core/core.h | 5 ++++ drivers/mmc/core/mmc.c | 40 +++++++++++++++++++++++++++++++++ 3 files changed, 63 insertions(+), 38 deletions(-)drivers/mmc/core/core.c +0
-0@@ -2245,67 +2245,47 @@ static void mmc_hw_reset_for_init(struct mmc_host *host)mmc_host_clk_release (host); }Quoted 14 lines
drivers/mmc/core/core.c static void mmc_hw_reset_for_init(struct mmc_host *host) · line 2259
Quoted 12 lines
drivers/mmc/core/core.c +0
-12-int mmc_can_reset (struct mmc_card *card) -{ -u8 rst_n_function; - -if (!mmc_card_mmc (card)) -return 0 ; - 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 0 ; -return 1 ; -} -EXPORT_SYMBOL (mmc_can_reset);Isn't the
mmc_can_reset()function used frommmc_test.c?Yes. Maybe we should move this stuff to
mmc_testinstead. We could also move the code that checks if the reset worked or not tommc_test, since this is the only place where the check is performed.Quoted 14 lines
Quoted 14 lines
drivers/mmc/core/core.c +3
-6- +/* Reset card in a bus-specific way */ static int mmc_do_hw_reset (struct mmc_host *host,int check) { -struct mmc_card *card = host->card; - -if (!(host->caps &MMC_CAP_HW_RESET ) || !host->ops->hw_reset) -return -EOPNOTSUPP ; +int ret; -if (!card) +if (!host->card)return -EINVAL ;Quoted 8 lines
drivers/mmc/core/core.c static void mmc_hw_reset_for_init(struct mmc_host *host) · line 2271
Quoted 1 line
drivers/mmc/core/core.c +0
-1-if (!mmc_can_reset (card))You need a
mmc_bus_get()here before accessing thehost->bus_opscallbacks.Well, if you would executed this code with the host claimed and from the mmc block layer, you can be sure the
bus_opsto exist. Now, since this is an exported function, I think you need to be more safe to also do the mmc_bus_get|put().Got it, thanks.
Quoted 74 lines
drivers/mmc/core/core.c static void mmc_hw_reset_for_init(struct mmc_host *host) · line 2260
Quoted 7 lines
drivers/mmc/core/core.c +3
-2+if (!host->bus_ops || !host->bus_ops->hw_reset || + host->bus_ops->hw_reset (host,MMC_HW_RESET_TEST ))return -EOPNOTSUPP ; -mmc_host_clk_hold (host); -mmc_set_clock (host, host->f_init); + ret = host->bus_ops->hw_reset (host, check);What's going on here? You are invoking the ->hw_reset() callback twice. That seems odd.
Quoted 53 lines
drivers/mmc/core/core.c +12
-17- host->ops->hw_reset (host); - -/* If the reset has happened, then a status command will fail */ -if (check) { -u32 status; - -if (!mmc_send_status (card, &status)) { -mmc_host_clk_release (host); -return -ENOSYS ; - } - } - -/* Set initial state and call mmc_set_ios */ -mmc_set_initial_state (host); +if (check ==MMC_HW_RESET_TEST_CARD ) +return ret; -mmc_host_clk_release (host); +pr_warn ("%s: tried to reset card (status %d)\n" , +mmc_hostname (host), ret);return host->bus_ops->power_restore (host); }int mmc_hw_reset (struct mmc_host *host) { -return mmc_do_hw_reset (host,0 ); +return mmc_do_hw_reset (host,MMC_HW_RESET_RESET ); }EXPORT_SYMBOL (mmc_hw_reset);int mmc_hw_reset_check (struct mmc_host *host) { -return mmc_do_hw_reset (host,1 ); +return mmc_do_hw_reset (host,MMC_HW_RESET_CHECK ); }EXPORT_SYMBOL (mmc_hw_reset_check); +int mmc_can_reset (struct mmc_card *card) +{ +return mmc_do_hw_reset (card->host,MMC_HW_RESET_TEST_CARD ); +} +EXPORT_SYMBOL (mmc_can_reset); +static int mmc_rescan_try_freq (struct mmc_host *host,unsigned freq) { host->f_init = freq;drivers/mmc/core/core.h +0
-0drivers/mmc/core/core.h struct mmc_bus_ops { · line 34
Quoted 8 lines
drivers/mmc/core/core.h +5
-0@@ -27,6 +27,11 @@ 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 *,int ); +#define MMC_HW_RESET_RESET 0 +#define MMC_HW_RESET_TEST 1 +#define MMC_HW_RESET_CHECK 2 +#define MMC_HW_RESET_TEST_CARD 3Urgh. Is there a way to remove all this? I just don't like all these options.
Quoted 4 lines
Quoted 1 line
In fact, I would prefer to have none of them.
If we move the test and check functionality to
mmc_test, I think we can avoid these. What do you think of this approach?
Quoted 6 lines
I like that approach.
In principle I think we should have only one API for hardware reset, typically that should be
mmc_hw_reset(). Then, convertmmc_test_hw_reset()into invoking themmc_hw_reset()API and let it handle further tests by itself.
The trouble is that mmc_test_hw_reset() needs to check if the reset was a success after calling host_ops->hw_reset, but before calling mmc_set_initial_values and bus_ops->power_restore, so some provisions for this need to be done in mmc_hw_reset. I'll soon send up a new patchset, please let me know if I'm on the right track.
BR, Johan
Re: [PATCH v4 1/2] mmc: core: turn hw_reset into a bus_ops
Quoted 150 lines · Johan Rudholm
2014-11-27 10:50 GMT+01:00 Ulf Hansson <[email protected]>:
Quoted 149 lines · Johan Rudholm
Quoted 141 lines
Hi Ulf,
2014-11-25 14:48 GMT+01:00 Ulf Hansson <[email protected]>:
Quoted 20 lines · Johan Rudholm
Quoted 19 lines
Move the (e)MMC specific
hw_resetcode fromcore.cintommc.cand call it from the newbus_opsmemberhw_reset. This also lets us add code for resetting SD cards as well.Signed-off-by Johan Rudholm <[email protected]>--- drivers/mmc/core/core.c | 56 +++++++++++++++------------------------------- drivers/mmc/core/core.h | 5 ++++ drivers/mmc/core/mmc.c | 40 +++++++++++++++++++++++++++++++++ 3 files changed, 63 insertions(+), 38 deletions(-)drivers/mmc/core/core.c +0
-0@@ -2245,67 +2245,47 @@ static void mmc_hw_reset_for_init(struct mmc_host *host)mmc_host_clk_release (host); }Quoted 14 lines
drivers/mmc/core/core.c static void mmc_hw_reset_for_init(struct mmc_host *host) · line 2259
Quoted 12 lines
drivers/mmc/core/core.c +0
-12-int mmc_can_reset (struct mmc_card *card) -{ -u8 rst_n_function; - -if (!mmc_card_mmc (card)) -return 0 ; - 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 0 ; -return 1 ; -} -EXPORT_SYMBOL (mmc_can_reset);Isn't the
mmc_can_reset()function used frommmc_test.c?Yes. Maybe we should move this stuff to
mmc_testinstead. We could also move the code that checks if the reset worked or not tommc_test, since this is the only place where the check is performed.Quoted 14 lines
Quoted 14 lines
drivers/mmc/core/core.c +3
-6- +/* Reset card in a bus-specific way */ static int mmc_do_hw_reset (struct mmc_host *host,int check) { -struct mmc_card *card = host->card; - -if (!(host->caps &MMC_CAP_HW_RESET ) || !host->ops->hw_reset) -return -EOPNOTSUPP ; +int ret; -if (!card) +if (!host->card)return -EINVAL ;Quoted 8 lines
drivers/mmc/core/core.c static void mmc_hw_reset_for_init(struct mmc_host *host) · line 2271
Quoted 1 line
drivers/mmc/core/core.c +0
-1-if (!mmc_can_reset (card))You need a
mmc_bus_get()here before accessing thehost->bus_opscallbacks.Well, if you would executed this code with the host claimed and from the mmc block layer, you can be sure the
bus_opsto exist. Now, since this is an exported function, I think you need to be more safe to also do the mmc_bus_get|put().Got it, thanks.
Quoted 74 lines
drivers/mmc/core/core.c static void mmc_hw_reset_for_init(struct mmc_host *host) · line 2260
Quoted 7 lines
drivers/mmc/core/core.c +3
-2+if (!host->bus_ops || !host->bus_ops->hw_reset || + host->bus_ops->hw_reset (host,MMC_HW_RESET_TEST ))return -EOPNOTSUPP ; -mmc_host_clk_hold (host); -mmc_set_clock (host, host->f_init); + ret = host->bus_ops->hw_reset (host, check);What's going on here? You are invoking the ->hw_reset() callback twice. That seems odd.
Quoted 53 lines
drivers/mmc/core/core.c +12
-17- host->ops->hw_reset (host); - -/* If the reset has happened, then a status command will fail */ -if (check) { -u32 status; - -if (!mmc_send_status (card, &status)) { -mmc_host_clk_release (host); -return -ENOSYS ; - } - } - -/* Set initial state and call mmc_set_ios */ -mmc_set_initial_state (host); +if (check ==MMC_HW_RESET_TEST_CARD ) +return ret; -mmc_host_clk_release (host); +pr_warn ("%s: tried to reset card (status %d)\n" , +mmc_hostname (host), ret);return host->bus_ops->power_restore (host); }int mmc_hw_reset (struct mmc_host *host) { -return mmc_do_hw_reset (host,0 ); +return mmc_do_hw_reset (host,MMC_HW_RESET_RESET ); }EXPORT_SYMBOL (mmc_hw_reset);int mmc_hw_reset_check (struct mmc_host *host) { -return mmc_do_hw_reset (host,1 ); +return mmc_do_hw_reset (host,MMC_HW_RESET_CHECK ); }EXPORT_SYMBOL (mmc_hw_reset_check); +int mmc_can_reset (struct mmc_card *card) +{ +return mmc_do_hw_reset (card->host,MMC_HW_RESET_TEST_CARD ); +} +EXPORT_SYMBOL (mmc_can_reset); +static int mmc_rescan_try_freq (struct mmc_host *host,unsigned freq) { host->f_init = freq;drivers/mmc/core/core.h +0
-0drivers/mmc/core/core.h struct mmc_bus_ops { · line 34
Quoted 8 lines
drivers/mmc/core/core.h +5
-0@@ -27,6 +27,11 @@ 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 *,int ); +#define MMC_HW_RESET_RESET 0 +#define MMC_HW_RESET_TEST 1 +#define MMC_HW_RESET_CHECK 2 +#define MMC_HW_RESET_TEST_CARD 3Urgh. Is there a way to remove all this? I just don't like all these options.
Quoted 4 lines
Quoted 1 line
In fact, I would prefer to have none of them.
If we move the test and check functionality to
mmc_test, I think we can avoid these. What do you think of this approach?I like that approach.
Quoted 7 lines
Quoted 4 lines
In principle I think we should have only one API for hardware reset, typically that should be
mmc_hw_reset(). Then, convertmmc_test_hw_reset()into invoking themmc_hw_reset()API and let it handle further tests by itself.The trouble is that
mmc_test_hw_reset()needs to check if the reset was a success after callinghost_ops->hw_reset, but before calling
How about always do the CMD13 check when host_ops->hw_reset() exist and returns suceess? The error handling for CMD13 check could be print an error. It shouldn't prevent us from proceeding with the rest of power cycle operations.
Quoted 4 lines
mmc_set_initial_valuesandbus_ops->power_restore, so some provisions for this need to be done inmmc_hw_reset. I'll soon send up a new patchset, please let me know if I'm on the right track.
Kind regards
Uffe
Re: [PATCH v4 1/2] mmc: core: turn hw_reset into a bus_ops
Hi Ulf,
2014-12-01 11:50 GMT+01:00 Ulf Hansson <[email protected]>:
Quoted 156 lines · Johan Rudholm
Quoted 155 lines
2014-11-27 10:50 GMT+01:00 Ulf Hansson <[email protected]>:
Quoted 153 lines · Johan Rudholm
Quoted 141 lines
Hi Ulf,
2014-11-25 14:48 GMT+01:00 Ulf Hansson <[email protected]>:
Quoted 20 lines · Johan Rudholm
Quoted 19 lines
Move the (e)MMC specific
hw_resetcode fromcore.cintommc.cand call it from the newbus_opsmemberhw_reset. This also lets us add code for resetting SD cards as well.Signed-off-by Johan Rudholm <[email protected]>--- drivers/mmc/core/core.c | 56 +++++++++++++++------------------------------- drivers/mmc/core/core.h | 5 ++++ drivers/mmc/core/mmc.c | 40 +++++++++++++++++++++++++++++++++ 3 files changed, 63 insertions(+), 38 deletions(-)drivers/mmc/core/core.c +0
-0@@ -2245,67 +2245,47 @@ static void mmc_hw_reset_for_init(struct mmc_host *host)mmc_host_clk_release (host); }Quoted 14 lines
drivers/mmc/core/core.c static void mmc_hw_reset_for_init(struct mmc_host *host) · line 2259
Quoted 12 lines
drivers/mmc/core/core.c +0
-12-int mmc_can_reset (struct mmc_card *card) -{ -u8 rst_n_function; - -if (!mmc_card_mmc (card)) -return 0 ; - 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 0 ; -return 1 ; -} -EXPORT_SYMBOL (mmc_can_reset);Isn't the
mmc_can_reset()function used frommmc_test.c?Yes. Maybe we should move this stuff to
mmc_testinstead. We could also move the code that checks if the reset worked or not tommc_test, since this is the only place where the check is performed.Quoted 14 lines
Quoted 14 lines
drivers/mmc/core/core.c +3
-6- +/* Reset card in a bus-specific way */ static int mmc_do_hw_reset (struct mmc_host *host,int check) { -struct mmc_card *card = host->card; - -if (!(host->caps &MMC_CAP_HW_RESET ) || !host->ops->hw_reset) -return -EOPNOTSUPP ; +int ret; -if (!card) +if (!host->card)return -EINVAL ;Quoted 8 lines
drivers/mmc/core/core.c static void mmc_hw_reset_for_init(struct mmc_host *host) · line 2271
Quoted 1 line
drivers/mmc/core/core.c +0
-1-if (!mmc_can_reset (card))You need a
mmc_bus_get()here before accessing thehost->bus_opscallbacks.Well, if you would executed this code with the host claimed and from the mmc block layer, you can be sure the
bus_opsto exist. Now, since this is an exported function, I think you need to be more safe to also do the mmc_bus_get|put().Got it, thanks.
Quoted 74 lines
drivers/mmc/core/core.c static void mmc_hw_reset_for_init(struct mmc_host *host) · line 2260
Quoted 7 lines
drivers/mmc/core/core.c +3
-2+if (!host->bus_ops || !host->bus_ops->hw_reset || + host->bus_ops->hw_reset (host,MMC_HW_RESET_TEST ))return -EOPNOTSUPP ; -mmc_host_clk_hold (host); -mmc_set_clock (host, host->f_init); + ret = host->bus_ops->hw_reset (host, check);What's going on here? You are invoking the ->hw_reset() callback twice. That seems odd.
Quoted 53 lines
drivers/mmc/core/core.c +12
-17- host->ops->hw_reset (host); - -/* If the reset has happened, then a status command will fail */ -if (check) { -u32 status; - -if (!mmc_send_status (card, &status)) { -mmc_host_clk_release (host); -return -ENOSYS ; - } - } - -/* Set initial state and call mmc_set_ios */ -mmc_set_initial_state (host); +if (check ==MMC_HW_RESET_TEST_CARD ) +return ret; -mmc_host_clk_release (host); +pr_warn ("%s: tried to reset card (status %d)\n" , +mmc_hostname (host), ret);return host->bus_ops->power_restore (host); }int mmc_hw_reset (struct mmc_host *host) { -return mmc_do_hw_reset (host,0 ); +return mmc_do_hw_reset (host,MMC_HW_RESET_RESET ); }EXPORT_SYMBOL (mmc_hw_reset);int mmc_hw_reset_check (struct mmc_host *host) { -return mmc_do_hw_reset (host,1 ); +return mmc_do_hw_reset (host,MMC_HW_RESET_CHECK ); }EXPORT_SYMBOL (mmc_hw_reset_check); +int mmc_can_reset (struct mmc_card *card) +{ +return mmc_do_hw_reset (card->host,MMC_HW_RESET_TEST_CARD ); +} +EXPORT_SYMBOL (mmc_can_reset); +static int mmc_rescan_try_freq (struct mmc_host *host,unsigned freq) { host->f_init = freq;drivers/mmc/core/core.h +0
-0drivers/mmc/core/core.h struct mmc_bus_ops { · line 34
Quoted 8 lines
drivers/mmc/core/core.h +5
-0@@ -27,6 +27,11 @@ 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 *,int ); +#define MMC_HW_RESET_RESET 0 +#define MMC_HW_RESET_TEST 1 +#define MMC_HW_RESET_CHECK 2 +#define MMC_HW_RESET_TEST_CARD 3Urgh. Is there a way to remove all this? I just don't like all these options.
Quoted 4 lines
Quoted 1 line
In fact, I would prefer to have none of them.
If we move the test and check functionality to
mmc_test, I think we can avoid these. What do you think of this approach?I like that approach.
In principle I think we should have only one API for hardware reset, typically that should be
mmc_hw_reset(). Then, convertmmc_test_hw_reset()into invoking themmc_hw_reset()API and let it handle further tests by itself.
Quoted 7 lines
Quoted 2 lines
The trouble is that
mmc_test_hw_reset()needs to check if the reset was a success after callinghost_ops->hw_reset, but before callingHow about always do the CMD13 check when
host_ops->hw_reset()exist and returns suceess? The error handling for CMD13 check could be print an error. It shouldn't prevent us from proceeding with the rest of power cycle operations.
Sorry for having dropped this conversation for so long. I've thought about the best approach for a while now and I'll soon send out a patch set with your suggestions incorporated.
Kind regards, Johan
PATCH v4 2/2 mmc: sd: add hw_reset callback
In reply to Johan RudholmEnable power cycle and re-initialization of SD cards via the hw_reset bus_ops. Power cycling a buggy SD card sometimes helps it get back on track.
--- drivers/mmc/core/sd.c | 13 +++++++++++++ 1 files changed, 13 insertions(+), 0 deletions(-)
drivers/mmc/core/sd.c +13 -0
@@ -1180,6 +1180,18 @@ static int mmc_sd_runtime_resume(struct mmc_host *host)return 0 ; } +static int mmc_sd_hw_reset (struct mmc_host *host,int test) +{ +struct mmc_card *card = host->card; + +if (test ==MMC_HW_RESET_TEST || test ==MMC_HW_RESET_TEST_CARD ) +return 0 ; + +mmc_power_cycle (host, card->ocr); + +return 0 ; +} +static int mmc_sd_power_restore (struct mmc_host *host) {int ret;
@@ -1201,6 +1213,7 @@ static const struct mmc_bus_ops mmc_sd_ops = { .power_restore = mmc_sd_power_restore, .alive = mmc_sd_alive, .shutdown = mmc_sd_suspend, + .hw_reset = mmc_sd_hw_reset, };/*
Signature · 1 line
1.7.2.5