Commit 126a3483 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'mmc-fixes-for-3.4-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc

Pull MMC fixes from Chris Ball:
 - Build fix for omap_hsmmc with OF against 3.4-rc1.
 - Fix CONFIG_MMC_UNSAFE_RESUME semantics regression against 3.3, which
   broke hotplug card detection when UNSAFE_RESUME is set.
 - Fix a race condition in omap_hsmmc with runtime PM.
 - Fix two libertas SDIO-powered-resume regressions.
 - Small fixes for discard/sanitize, dw_mmc, cd-gpio and esdhc-imx.

* tag 'mmc-fixes-for-3.4-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc:
  mmc: core: Do not pre-claim host in suspend
  mmc: dw_mmc: prevent NULL dereference for dma_ops
  mmc: unbreak sdhci-esdhc-imx on i.MX25
  mmc: cd-gpio: Include header to pickup exported symbol prototypes
  mmc: sdhci: refine non-removable card checking for card detection
  mmc: dw_mmc: Fix switch from DMA to PIO
  mmc: remove MMC bus legacy suspend/resume method
  mmc: omap_hsmmc: Get rid of of_have_populated_dt() usage
  mmc: omap_hsmmc: build fix for CONFIG_OF=y and CONFIG_MMC_OMAP_HS=m
  mmc: fixes for eMMC v4.5 sanitize operation
  mmc: fixes for eMMC v4.5 discard operation
parents 88981596 7c570919
Loading
Loading
Loading
Loading
+39 −17
Original line number Diff line number Diff line
@@ -873,7 +873,7 @@ static int mmc_blk_issue_secdiscard_rq(struct mmc_queue *mq,
{
	struct mmc_blk_data *md = mq->data;
	struct mmc_card *card = md->queue.card;
	unsigned int from, nr, arg;
	unsigned int from, nr, arg, trim_arg, erase_arg;
	int err = 0, type = MMC_BLK_SECDISCARD;

	if (!(mmc_can_secure_erase_trim(card) || mmc_can_sanitize(card))) {
@@ -881,20 +881,26 @@ static int mmc_blk_issue_secdiscard_rq(struct mmc_queue *mq,
		goto out;
	}

	from = blk_rq_pos(req);
	nr = blk_rq_sectors(req);

	/* The sanitize operation is supported at v4.5 only */
	if (mmc_can_sanitize(card)) {
		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
				EXT_CSD_SANITIZE_START, 1, 0);
		goto out;
		erase_arg = MMC_ERASE_ARG;
		trim_arg = MMC_TRIM_ARG;
	} else {
		erase_arg = MMC_SECURE_ERASE_ARG;
		trim_arg = MMC_SECURE_TRIM1_ARG;
	}

	from = blk_rq_pos(req);
	nr = blk_rq_sectors(req);

	if (mmc_can_trim(card) && !mmc_erase_group_aligned(card, from, nr))
		arg = MMC_SECURE_TRIM1_ARG;
	else
		arg = MMC_SECURE_ERASE_ARG;
	if (mmc_erase_group_aligned(card, from, nr))
		arg = erase_arg;
	else if (mmc_can_trim(card))
		arg = trim_arg;
	else {
		err = -EINVAL;
		goto out;
	}
retry:
	if (card->quirks & MMC_QUIRK_INAND_CMD38) {
		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
@@ -904,25 +910,41 @@ retry:
				 INAND_CMD38_ARG_SECERASE,
				 0);
		if (err)
			goto out;
			goto out_retry;
	}

	err = mmc_erase(card, from, nr, arg);
	if (!err && arg == MMC_SECURE_TRIM1_ARG) {
	if (err == -EIO)
		goto out_retry;
	if (err)
		goto out;

	if (arg == MMC_SECURE_TRIM1_ARG) {
		if (card->quirks & MMC_QUIRK_INAND_CMD38) {
			err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
					 INAND_CMD38_ARG_EXT_CSD,
					 INAND_CMD38_ARG_SECTRIM2,
					 0);
			if (err)
				goto out;
				goto out_retry;
		}

		err = mmc_erase(card, from, nr, MMC_SECURE_TRIM2_ARG);
		if (err == -EIO)
			goto out_retry;
		if (err)
			goto out;
	}
out:
	if (err == -EIO && !mmc_blk_reset(md, card->host, type))

	if (mmc_can_sanitize(card))
		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
				 EXT_CSD_SANITIZE_START, 1, 0);
out_retry:
	if (err && !mmc_blk_reset(md, card->host, type))
		goto retry;
	if (!err)
		mmc_blk_reset_success(md, type);
out:
	spin_lock_irq(&md->lock);
	__blk_end_request(req, err, blk_rq_bytes(req));
	spin_unlock_irq(&md->lock);
@@ -1802,7 +1824,7 @@ static void mmc_blk_remove(struct mmc_card *card)
}

#ifdef CONFIG_PM
static int mmc_blk_suspend(struct mmc_card *card, pm_message_t state)
static int mmc_blk_suspend(struct mmc_card *card)
{
	struct mmc_blk_data *part_md;
	struct mmc_blk_data *md = mmc_get_drvdata(card);
+1 −1
Original line number Diff line number Diff line
@@ -139,7 +139,7 @@ static void mmc_queue_setup_discard(struct request_queue *q,

	queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, q);
	q->limits.max_discard_sectors = max_discard;
	if (card->erased_byte == 0)
	if (card->erased_byte == 0 && !mmc_can_discard(card))
		q->limits.discard_zeroes_data = 1;
	q->limits.discard_granularity = card->pref_erase << 9;
	/* granularity must not be greater than max. discard */
+8 −16
Original line number Diff line number Diff line
@@ -122,14 +122,14 @@ static int mmc_bus_remove(struct device *dev)
	return 0;
}

static int mmc_bus_suspend(struct device *dev, pm_message_t state)
static int mmc_bus_suspend(struct device *dev)
{
	struct mmc_driver *drv = to_mmc_driver(dev->driver);
	struct mmc_card *card = mmc_dev_to_card(dev);
	int ret = 0;

	if (dev->driver && drv->suspend)
		ret = drv->suspend(card, state);
		ret = drv->suspend(card);
	return ret;
}

@@ -165,20 +165,14 @@ static int mmc_runtime_idle(struct device *dev)
	return pm_runtime_suspend(dev);
}

#endif /* !CONFIG_PM_RUNTIME */

static const struct dev_pm_ops mmc_bus_pm_ops = {
	.runtime_suspend	= mmc_runtime_suspend,
	.runtime_resume		= mmc_runtime_resume,
	.runtime_idle		= mmc_runtime_idle,
	SET_RUNTIME_PM_OPS(mmc_runtime_suspend, mmc_runtime_resume,
			mmc_runtime_idle)
	SET_SYSTEM_SLEEP_PM_OPS(mmc_bus_suspend, mmc_bus_resume)
};

#define MMC_PM_OPS_PTR	(&mmc_bus_pm_ops)

#else /* !CONFIG_PM_RUNTIME */

#define MMC_PM_OPS_PTR	NULL

#endif /* !CONFIG_PM_RUNTIME */

static struct bus_type mmc_bus_type = {
	.name		= "mmc",
	.dev_attrs	= mmc_dev_attrs,
@@ -186,9 +180,7 @@ static struct bus_type mmc_bus_type = {
	.uevent		= mmc_bus_uevent,
	.probe		= mmc_bus_probe,
	.remove		= mmc_bus_remove,
	.suspend	= mmc_bus_suspend,
	.resume		= mmc_bus_resume,
	.pm		= MMC_PM_OPS_PTR,
	.pm		= &mmc_bus_pm_ops,
};

int mmc_register_bus(void)
+1 −0
Original line number Diff line number Diff line
@@ -12,6 +12,7 @@
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/jiffies.h>
#include <linux/mmc/cd-gpio.h>
#include <linux/mmc/host.h>
#include <linux/module.h>
#include <linux/slab.h>
+26 −38
Original line number Diff line number Diff line
@@ -1409,7 +1409,10 @@ static unsigned int mmc_mmc_erase_timeout(struct mmc_card *card,
{
	unsigned int erase_timeout;

	if (card->ext_csd.erase_group_def & 1) {
	if (arg == MMC_DISCARD_ARG ||
	    (arg == MMC_TRIM_ARG && card->ext_csd.rev >= 6)) {
		erase_timeout = card->ext_csd.trim_timeout;
	} else if (card->ext_csd.erase_group_def & 1) {
		/* High Capacity Erase Group Size uses HC timeouts */
		if (arg == MMC_TRIM_ARG)
			erase_timeout = card->ext_csd.trim_timeout;
@@ -1681,8 +1684,6 @@ int mmc_can_trim(struct mmc_card *card)
{
	if (card->ext_csd.sec_feature_support & EXT_CSD_SEC_GB_CL_EN)
		return 1;
	if (mmc_can_discard(card))
		return 1;
	return 0;
}
EXPORT_SYMBOL(mmc_can_trim);
@@ -1701,6 +1702,8 @@ EXPORT_SYMBOL(mmc_can_discard);

int mmc_can_sanitize(struct mmc_card *card)
{
	if (!mmc_can_trim(card) && !mmc_can_erase(card))
		return 0;
	if (card->ext_csd.sec_feature_support & EXT_CSD_SEC_SANITIZE)
		return 1;
	return 0;
@@ -2235,6 +2238,7 @@ int mmc_cache_ctrl(struct mmc_host *host, u8 enable)
			mmc_card_is_removable(host))
		return err;

	mmc_claim_host(host);
	if (card && mmc_card_mmc(card) &&
			(card->ext_csd.cache_size > 0)) {
		enable = !!enable;
@@ -2252,6 +2256,7 @@ int mmc_cache_ctrl(struct mmc_host *host, u8 enable)
				card->ext_csd.cache_ctrl = enable;
		}
	}
	mmc_release_host(host);

	return err;
}
@@ -2269,30 +2274,16 @@ int mmc_suspend_host(struct mmc_host *host)

	cancel_delayed_work(&host->detect);
	mmc_flush_scheduled_work();
	if (mmc_try_claim_host(host)) {
		err = mmc_cache_ctrl(host, 0);
		mmc_release_host(host);
	} else {
		err = -EBUSY;
	}

	err = mmc_cache_ctrl(host, 0);
	if (err)
		goto out;

	mmc_bus_get(host);
	if (host->bus_ops && !host->bus_dead) {

		/*
		 * A long response time is not acceptable for device drivers
		 * when doing suspend. Prevent mmc_claim_host in the suspend
		 * sequence, to potentially wait "forever" by trying to
		 * pre-claim the host.
		 */
		if (mmc_try_claim_host(host)) {
			if (host->bus_ops->suspend) {
		if (host->bus_ops->suspend)
			err = host->bus_ops->suspend(host);
			}
			mmc_release_host(host);

		if (err == -ENOSYS || !host->bus_ops->resume) {
			/*
@@ -2310,9 +2301,6 @@ int mmc_suspend_host(struct mmc_host *host)
			host->pm_flags = 0;
			err = 0;
		}
		} else {
			err = -EBUSY;
		}
	}
	mmc_bus_put(host);

Loading