Skip to content

Commit

Permalink
mmc: Fix sd/sdio/mmc initialization frequency retries
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Andy Ross authored and cjb committed Jan 9, 2011
1 parent 08c82df commit 807e8e4
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 99 deletions.
119 changes: 36 additions & 83 deletions drivers/mmc/core/core.c
Expand Up @@ -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);

Expand All @@ -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.
Expand All @@ -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);
}
Expand Down
6 changes: 3 additions & 3 deletions drivers/mmc/core/core.h
Expand Up @@ -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;
Expand Down
13 changes: 9 additions & 4 deletions drivers/mmc/core/mmc.c
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down
11 changes: 8 additions & 3 deletions drivers/mmc/core/sd.c
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down
18 changes: 12 additions & 6 deletions drivers/mmc/core/sdio.c
Expand Up @@ -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;
Expand Down Expand Up @@ -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;

Expand All @@ -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);
Expand Down

0 comments on commit 807e8e4

Please sign in to comment.