Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+36 −83
Original line number Original line Diff line number Diff line
@@ -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)
		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,76 +1551,15 @@ 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;


	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);
	mmc_claim_host(host);
				/*
	for (i = 0; i < ARRAY_SIZE(freqs); i++) {
				 * Try SDMEM (but not MMC) even if SDIO
		if (!mmc_rescan_try_freq(host, max(freqs[i], host->f_min)))
				 * is broken.
			break;
				 */
		if (freqs[i] < host->f_min)
				mmc_power_up(host);
			break;
				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_release_host(host);
		mmc_power_off(host);

	}
 out:
 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);
+3 −3
Original line number Original line Diff line number Diff line
@@ -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;
+9 −4
Original line number Original line Diff line number Diff line
@@ -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)
		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);
+8 −3
Original line number Original line Diff line number Diff line
@@ -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)
		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);
+12 −6
Original line number Original line Diff line number Diff line
@@ -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)
			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)


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);