Commit 807e8e40 authored by Andy Ross's avatar Andy Ross Committed by Chris Ball

mmc: Fix sd/sdio/mmc initialization frequency retries

Rewrite and clean up mmc_rescan() to properly retry frequencies lower
than 400kHz.  Failures can happen both in sd_send_* calls and
mmc_attach_*.  Break out "mmc_rescan_try_freq" from the frequency
selection loop.  Symmetrize claim/release logic in mmc_attach_* API,
and move the sd_send_* calls there to make mmc_rescan easier to read.
Signed-off-by: default avatarAndy Ross <andy.ross@windriver.com>
Reviewed-and-Tested-by: default avatarHein Tibosch <hein_tibosch@yahoo.es>
Reviewed-by: default avatarChris Ball <cjb@laptop.org>
Signed-off-by: default avatarChris Ball <cjb@laptop.org>
parent 08c82dfa
...@@ -1485,25 +1485,41 @@ int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen) ...@@ -1485,25 +1485,41 @@ int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen)
} }
EXPORT_SYMBOL(mmc_set_blocklen); EXPORT_SYMBOL(mmc_set_blocklen);
static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq)
{
host->f_init = freq;
#ifdef CONFIG_MMC_DEBUG
pr_info("%s: %s: trying to init card at %u Hz\n",
mmc_hostname(host), __func__, host->f_init);
#endif
mmc_power_up(host);
sdio_reset(host);
mmc_go_idle(host);
mmc_send_if_cond(host, host->ocr_avail);
/* Order's important: probe SDIO, then SD, then MMC */
if (!mmc_attach_sdio(host))
return 0;
if (!mmc_attach_sd(host))
return 0;
if (!mmc_attach_mmc(host))
return 0;
mmc_power_off(host);
return -EIO;
}
void mmc_rescan(struct work_struct *work) void mmc_rescan(struct work_struct *work)
{ {
static const unsigned freqs[] = { 400000, 300000, 200000, 100000 };
struct mmc_host *host = struct mmc_host *host =
container_of(work, struct mmc_host, detect.work); container_of(work, struct mmc_host, detect.work);
u32 ocr;
int err;
unsigned long flags;
int i; int i;
const unsigned freqs[] = { 400000, 300000, 200000, 100000 };
spin_lock_irqsave(&host->lock, flags);
if (host->rescan_disable) { if (host->rescan_disable)
spin_unlock_irqrestore(&host->lock, flags);
return; return;
}
spin_unlock_irqrestore(&host->lock, flags);
mmc_bus_get(host); mmc_bus_get(host);
...@@ -1526,8 +1542,6 @@ void mmc_rescan(struct work_struct *work) ...@@ -1526,8 +1542,6 @@ void mmc_rescan(struct work_struct *work)
goto out; goto out;
} }
/* detect a newly inserted card */
/* /*
* Only we can add a new handler, so it's safe to * Only we can add a new handler, so it's safe to
* release the lock here. * release the lock here.
...@@ -1537,77 +1551,16 @@ void mmc_rescan(struct work_struct *work) ...@@ -1537,77 +1551,16 @@ void mmc_rescan(struct work_struct *work)
if (host->ops->get_cd && host->ops->get_cd(host) == 0) if (host->ops->get_cd && host->ops->get_cd(host) == 0)
goto out; goto out;
mmc_claim_host(host);
for (i = 0; i < ARRAY_SIZE(freqs); i++) { for (i = 0; i < ARRAY_SIZE(freqs); i++) {
mmc_claim_host(host); if (!mmc_rescan_try_freq(host, max(freqs[i], host->f_min)))
break;
if (freqs[i] >= host->f_min) if (freqs[i] < host->f_min)
host->f_init = freqs[i]; break;
else if (!i || freqs[i-1] > host->f_min)
host->f_init = host->f_min;
else {
mmc_release_host(host);
goto out;
}
#ifdef CONFIG_MMC_DEBUG
pr_info("%s: %s: trying to init card at %u Hz\n",
mmc_hostname(host), __func__, host->f_init);
#endif
mmc_power_up(host);
sdio_reset(host);
mmc_go_idle(host);
mmc_send_if_cond(host, host->ocr_avail);
/*
* First we search for SDIO...
*/
err = mmc_send_io_op_cond(host, 0, &ocr);
if (!err) {
if (mmc_attach_sdio(host, ocr)) {
mmc_claim_host(host);
/*
* Try SDMEM (but not MMC) even if SDIO
* is broken.
*/
mmc_power_up(host);
sdio_reset(host);
mmc_go_idle(host);
mmc_send_if_cond(host, host->ocr_avail);
if (mmc_send_app_op_cond(host, 0, &ocr))
goto out_fail;
if (mmc_attach_sd(host, ocr))
mmc_power_off(host);
}
goto out;
}
/*
* ...then normal SD...
*/
err = mmc_send_app_op_cond(host, 0, &ocr);
if (!err) {
if (mmc_attach_sd(host, ocr))
mmc_power_off(host);
goto out;
}
/*
* ...and finally MMC.
*/
err = mmc_send_op_cond(host, 0, &ocr);
if (!err) {
if (mmc_attach_mmc(host, ocr))
mmc_power_off(host);
goto out;
}
out_fail:
mmc_release_host(host);
mmc_power_off(host);
} }
out: mmc_release_host(host);
out:
if (host->caps & MMC_CAP_NEEDS_POLL) if (host->caps & MMC_CAP_NEEDS_POLL)
mmc_schedule_delayed_work(&host->detect, HZ); mmc_schedule_delayed_work(&host->detect, HZ);
} }
......
...@@ -57,9 +57,9 @@ void mmc_rescan(struct work_struct *work); ...@@ -57,9 +57,9 @@ void mmc_rescan(struct work_struct *work);
void mmc_start_host(struct mmc_host *host); void mmc_start_host(struct mmc_host *host);
void mmc_stop_host(struct mmc_host *host); void mmc_stop_host(struct mmc_host *host);
int mmc_attach_mmc(struct mmc_host *host, u32 ocr); int mmc_attach_mmc(struct mmc_host *host);
int mmc_attach_sd(struct mmc_host *host, u32 ocr); int mmc_attach_sd(struct mmc_host *host);
int mmc_attach_sdio(struct mmc_host *host, u32 ocr); int mmc_attach_sdio(struct mmc_host *host);
/* Module parameters */ /* Module parameters */
extern int use_spi_crc; extern int use_spi_crc;
......
...@@ -755,13 +755,18 @@ static void mmc_attach_bus_ops(struct mmc_host *host) ...@@ -755,13 +755,18 @@ static void mmc_attach_bus_ops(struct mmc_host *host)
/* /*
* Starting point for MMC card init. * Starting point for MMC card init.
*/ */
int mmc_attach_mmc(struct mmc_host *host, u32 ocr) int mmc_attach_mmc(struct mmc_host *host)
{ {
int err; int err;
u32 ocr;
BUG_ON(!host); BUG_ON(!host);
WARN_ON(!host->claimed); WARN_ON(!host->claimed);
err = mmc_send_op_cond(host, 0, &ocr);
if (err)
return err;
mmc_attach_bus_ops(host); mmc_attach_bus_ops(host);
if (host->ocr_avail_mmc) if (host->ocr_avail_mmc)
host->ocr_avail = host->ocr_avail_mmc; host->ocr_avail = host->ocr_avail_mmc;
...@@ -804,20 +809,20 @@ int mmc_attach_mmc(struct mmc_host *host, u32 ocr) ...@@ -804,20 +809,20 @@ int mmc_attach_mmc(struct mmc_host *host, u32 ocr)
goto err; goto err;
mmc_release_host(host); mmc_release_host(host);
err = mmc_add_card(host->card); err = mmc_add_card(host->card);
mmc_claim_host(host);
if (err) if (err)
goto remove_card; goto remove_card;
return 0; return 0;
remove_card: remove_card:
mmc_release_host(host);
mmc_remove_card(host->card); mmc_remove_card(host->card);
host->card = NULL;
mmc_claim_host(host); mmc_claim_host(host);
host->card = NULL;
err: err:
mmc_detach_bus(host); mmc_detach_bus(host);
mmc_release_host(host);
printk(KERN_ERR "%s: error %d whilst initialising MMC card\n", printk(KERN_ERR "%s: error %d whilst initialising MMC card\n",
mmc_hostname(host), err); mmc_hostname(host), err);
......
...@@ -764,13 +764,18 @@ static void mmc_sd_attach_bus_ops(struct mmc_host *host) ...@@ -764,13 +764,18 @@ static void mmc_sd_attach_bus_ops(struct mmc_host *host)
/* /*
* Starting point for SD card init. * Starting point for SD card init.
*/ */
int mmc_attach_sd(struct mmc_host *host, u32 ocr) int mmc_attach_sd(struct mmc_host *host)
{ {
int err; int err;
u32 ocr;
BUG_ON(!host); BUG_ON(!host);
WARN_ON(!host->claimed); WARN_ON(!host->claimed);
err = mmc_send_app_op_cond(host, 0, &ocr);
if (err)
return err;
mmc_sd_attach_bus_ops(host); mmc_sd_attach_bus_ops(host);
if (host->ocr_avail_sd) if (host->ocr_avail_sd)
host->ocr_avail = host->ocr_avail_sd; host->ocr_avail = host->ocr_avail_sd;
...@@ -823,20 +828,20 @@ int mmc_attach_sd(struct mmc_host *host, u32 ocr) ...@@ -823,20 +828,20 @@ int mmc_attach_sd(struct mmc_host *host, u32 ocr)
goto err; goto err;
mmc_release_host(host); mmc_release_host(host);
err = mmc_add_card(host->card); err = mmc_add_card(host->card);
mmc_claim_host(host);
if (err) if (err)
goto remove_card; goto remove_card;
return 0; return 0;
remove_card: remove_card:
mmc_release_host(host);
mmc_remove_card(host->card); mmc_remove_card(host->card);
host->card = NULL; host->card = NULL;
mmc_claim_host(host); mmc_claim_host(host);
err: err:
mmc_detach_bus(host); mmc_detach_bus(host);
mmc_release_host(host);
printk(KERN_ERR "%s: error %d whilst initialising SD card\n", printk(KERN_ERR "%s: error %d whilst initialising SD card\n",
mmc_hostname(host), err); mmc_hostname(host), err);
......
...@@ -702,15 +702,19 @@ static const struct mmc_bus_ops mmc_sdio_ops = { ...@@ -702,15 +702,19 @@ static const struct mmc_bus_ops mmc_sdio_ops = {
/* /*
* Starting point for SDIO card init. * Starting point for SDIO card init.
*/ */
int mmc_attach_sdio(struct mmc_host *host, u32 ocr) int mmc_attach_sdio(struct mmc_host *host)
{ {
int err; int err, i, funcs;
int i, funcs; u32 ocr;
struct mmc_card *card; struct mmc_card *card;
BUG_ON(!host); BUG_ON(!host);
WARN_ON(!host->claimed); WARN_ON(!host->claimed);
err = mmc_send_io_op_cond(host, 0, &ocr);
if (err)
return err;
mmc_attach_bus(host, &mmc_sdio_ops); mmc_attach_bus(host, &mmc_sdio_ops);
if (host->ocr_avail_sdio) if (host->ocr_avail_sdio)
host->ocr_avail = host->ocr_avail_sdio; host->ocr_avail = host->ocr_avail_sdio;
...@@ -783,12 +787,12 @@ int mmc_attach_sdio(struct mmc_host *host, u32 ocr) ...@@ -783,12 +787,12 @@ int mmc_attach_sdio(struct mmc_host *host, u32 ocr)
pm_runtime_enable(&card->sdio_func[i]->dev); pm_runtime_enable(&card->sdio_func[i]->dev);
} }
mmc_release_host(host);
/* /*
* First add the card to the driver model... * First add the card to the driver model...
*/ */
mmc_release_host(host);
err = mmc_add_card(host->card); err = mmc_add_card(host->card);
mmc_claim_host(host);
if (err) if (err)
goto remove_added; goto remove_added;
...@@ -806,15 +810,17 @@ int mmc_attach_sdio(struct mmc_host *host, u32 ocr) ...@@ -806,15 +810,17 @@ int mmc_attach_sdio(struct mmc_host *host, u32 ocr)
remove_added: remove_added:
/* Remove without lock if the device has been added. */ /* Remove without lock if the device has been added. */
mmc_release_host(host);
mmc_sdio_remove(host); mmc_sdio_remove(host);
mmc_claim_host(host); mmc_claim_host(host);
remove: remove:
/* And with lock if it hasn't been added. */ /* And with lock if it hasn't been added. */
mmc_release_host(host);
if (host->card) if (host->card)
mmc_sdio_remove(host); mmc_sdio_remove(host);
mmc_claim_host(host);
err: err:
mmc_detach_bus(host); mmc_detach_bus(host);
mmc_release_host(host);
printk(KERN_ERR "%s: error %d whilst initialising SDIO card\n", printk(KERN_ERR "%s: error %d whilst initialising SDIO card\n",
mmc_hostname(host), err); mmc_hostname(host), err);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment