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: Andy Ross <andy.ross@windriver.com>
Reviewed-and-Tested-by: Hein Tibosch <hein_tibosch@yahoo.es>
Reviewed-by: Chris Ball <cjb@laptop.org>
Signed-off-by: Chris Ball <cjb@laptop.org>
This commit is contained in:
Andy Ross 2011-01-03 10:36:56 -08:00 committed by Chris Ball
parent 08c82dfad2
commit 807e8e4067
5 changed files with 68 additions and 99 deletions

View file

@ -1485,25 +1485,41 @@ int mmc_set_blocklen(struct mmc_card *card, unsigned int 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)
{
static const unsigned freqs[] = { 400000, 300000, 200000, 100000 };
struct mmc_host *host =
container_of(work, struct mmc_host, detect.work);
u32 ocr;
int err;
unsigned long flags;
int i;
const unsigned freqs[] = { 400000, 300000, 200000, 100000 };
spin_lock_irqsave(&host->lock, flags);
if (host->rescan_disable) {
spin_unlock_irqrestore(&host->lock, flags);
if (host->rescan_disable)
return;
}
spin_unlock_irqrestore(&host->lock, flags);
mmc_bus_get(host);
@ -1526,8 +1542,6 @@ void mmc_rescan(struct work_struct *work)
goto out;
}
/* detect a newly inserted card */
/*
* Only we can add a new handler, so it's safe to
* release the lock here.
@ -1537,77 +1551,16 @@ void mmc_rescan(struct work_struct *work)
if (host->ops->get_cd && host->ops->get_cd(host) == 0)
goto out;
mmc_claim_host(host);
for (i = 0; i < ARRAY_SIZE(freqs); i++) {
mmc_claim_host(host);
if (freqs[i] >= host->f_min)
host->f_init = freqs[i];
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);
if (!mmc_rescan_try_freq(host, max(freqs[i], host->f_min)))
break;
if (freqs[i] < host->f_min)
break;
}
out:
mmc_release_host(host);
out:
if (host->caps & MMC_CAP_NEEDS_POLL)
mmc_schedule_delayed_work(&host->detect, HZ);
}

View file

@ -57,9 +57,9 @@ void mmc_rescan(struct work_struct *work);
void mmc_start_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_sd(struct mmc_host *host, u32 ocr);
int mmc_attach_sdio(struct mmc_host *host, u32 ocr);
int mmc_attach_mmc(struct mmc_host *host);
int mmc_attach_sd(struct mmc_host *host);
int mmc_attach_sdio(struct mmc_host *host);
/* Module parameters */
extern int use_spi_crc;

View file

@ -755,13 +755,18 @@ static void mmc_attach_bus_ops(struct mmc_host *host)
/*
* 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;
u32 ocr;
BUG_ON(!host);
WARN_ON(!host->claimed);
err = mmc_send_op_cond(host, 0, &ocr);
if (err)
return err;
mmc_attach_bus_ops(host);
if (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)
goto err;
mmc_release_host(host);
err = mmc_add_card(host->card);
mmc_claim_host(host);
if (err)
goto remove_card;
return 0;
remove_card:
mmc_release_host(host);
mmc_remove_card(host->card);
host->card = NULL;
mmc_claim_host(host);
host->card = NULL;
err:
mmc_detach_bus(host);
mmc_release_host(host);
printk(KERN_ERR "%s: error %d whilst initialising MMC card\n",
mmc_hostname(host), err);

View file

@ -764,13 +764,18 @@ static void mmc_sd_attach_bus_ops(struct mmc_host *host)
/*
* 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;
u32 ocr;
BUG_ON(!host);
WARN_ON(!host->claimed);
err = mmc_send_app_op_cond(host, 0, &ocr);
if (err)
return err;
mmc_sd_attach_bus_ops(host);
if (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)
goto err;
mmc_release_host(host);
err = mmc_add_card(host->card);
mmc_claim_host(host);
if (err)
goto remove_card;
return 0;
remove_card:
mmc_release_host(host);
mmc_remove_card(host->card);
host->card = NULL;
mmc_claim_host(host);
err:
mmc_detach_bus(host);
mmc_release_host(host);
printk(KERN_ERR "%s: error %d whilst initialising SD card\n",
mmc_hostname(host), err);

View file

@ -702,15 +702,19 @@ static const struct mmc_bus_ops mmc_sdio_ops = {
/*
* 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 i, funcs;
int err, i, funcs;
u32 ocr;
struct mmc_card *card;
BUG_ON(!host);
WARN_ON(!host->claimed);
err = mmc_send_io_op_cond(host, 0, &ocr);
if (err)
return err;
mmc_attach_bus(host, &mmc_sdio_ops);
if (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)
pm_runtime_enable(&card->sdio_func[i]->dev);
}
mmc_release_host(host);
/*
* First add the card to the driver model...
*/
mmc_release_host(host);
err = mmc_add_card(host->card);
mmc_claim_host(host);
if (err)
goto remove_added;
@ -806,15 +810,17 @@ int mmc_attach_sdio(struct mmc_host *host, u32 ocr)
remove_added:
/* Remove without lock if the device has been added. */
mmc_release_host(host);
mmc_sdio_remove(host);
mmc_claim_host(host);
remove:
/* And with lock if it hasn't been added. */
mmc_release_host(host);
if (host->card)
mmc_sdio_remove(host);
mmc_claim_host(host);
err:
mmc_detach_bus(host);
mmc_release_host(host);
printk(KERN_ERR "%s: error %d whilst initialising SDIO card\n",
mmc_hostname(host), err);