diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-07-10 11:16:00 -0700 | 
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-07-10 11:16:00 -0700 | 
| commit | bfffbea1aaeeb1eb6500c83ff9653416daa5b490 (patch) | |
| tree | 1325ecb176b7a3d04924d6a1563b15ad6085d36a /drivers/mmc/card | |
| parent | 34ae0a6f05aee9f51fca17001b4a90703d434ae1 (diff) | |
| parent | 01ebea1b411aafc8eab440bf1d2037f01bbed99b (diff) | |
| download | linux-bfffbea1aaeeb1eb6500c83ff9653416daa5b490.tar.bz2 | |
Merge tag 'mmc-updates-for-3.11-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc
Pull MMC updates from Chris Ball:
 "MMC highlights for 3.11:
  Core:
   - Add support for eMMC 5.1 devices
   - Add MMC_CAP_AGGRESSIVE_PM capability for aggressive power
     management of eMMC/SD between requests, using runtime PM
   - Add an ioctl to perform the eMMC 4.5 Sanitize command.  Sample code
     at:
       git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc-utils.git
  Drivers:
   - dw_mmc: Add support for Rockchip's Cortex-A9 SoCs
   - dw_mmc: Add support for Altera SoCFPGAs
   - sdhci-esdhc-imx: Add support for 8-bit bus width, non-removable
     cards
   - sdhci-bcm-kona: New driver for Broadcom Kona (281xx) SoCs
   - sdhi/tmio: Add DT DMA support"
* tag 'mmc-updates-for-3.11-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc: (87 commits)
  mmc: bcm281xx SDHCI driver
  mmc: sdhci: add card_event callback to sdhci
  mmc: core: Fixup Oops for SDIO shutdown
  mmc: sdhci-pci: add another device id
  mmc: esdhc: Fix bug when writing to SDHCI_HOST_CONTROL register
  mmc: esdhc: Add support for 8-bit bus width and non-removable card
  mmc: core: production year for eMMC 4.41 and later
  mmc: omap: remove unnecessary #if 0's
  mmc: sdhci: fix ctrl_2 on super-speed selection
  mmc: dw_mmc-pltfm: add Rockchip variant
  mmc: dw_mmc-pltfm: move probe and remove below dt match table
  mmc: dw_mmc-pltfm: remove static from dw_mci_pltfm_remove
  mmc: sdhci-acpi: add support for eMMC hardware reset for HID 80860F14
  mmc: sdhci-pci: add support for eMMC hardware reset for BYT eMMC.
  mmc: dw_mmc: Add support DW SD/MMC driver on SOCFPGA
  mmc: sdhci: fix caps2 for HS200
  sdhci-pxav3: Fix runtime PM initialization
  mmc: core: Add DT-bindings for MMC_CAP2_FULL_PWR_CYCLE
  mmc: core: Invent MMC_CAP2_FULL_PWR_CYCLE
  mmc: core: Enable power_off_notify for eMMC shutdown sequence
  ...
Diffstat (limited to 'drivers/mmc/card')
| -rw-r--r-- | drivers/mmc/card/block.c | 130 | ||||
| -rw-r--r-- | drivers/mmc/card/mmc_test.c | 5 | ||||
| -rw-r--r-- | drivers/mmc/card/queue.c | 2 | 
3 files changed, 101 insertions, 36 deletions
| diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index dd27b0783d52..cd0b7f4a1ff2 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -34,6 +34,7 @@  #include <linux/delay.h>  #include <linux/capability.h>  #include <linux/compat.h> +#include <linux/pm_runtime.h>  #include <linux/mmc/ioctl.h>  #include <linux/mmc/card.h> @@ -58,6 +59,8 @@ MODULE_ALIAS("mmc:block");  #define INAND_CMD38_ARG_SECTRIM1 0x81  #define INAND_CMD38_ARG_SECTRIM2 0x88  #define MMC_BLK_TIMEOUT_MS  (10 * 60 * 1000)        /* 10 minute timeout */ +#define MMC_SANITIZE_REQ_TIMEOUT 240000 +#define MMC_EXTRACT_INDEX_FROM_ARG(x) ((x & 0x00FF0000) >> 16)  #define mmc_req_rel_wr(req)	(((req->cmd_flags & REQ_FUA) || \  				  (req->cmd_flags & REQ_META)) && \ @@ -222,7 +225,7 @@ static ssize_t power_ro_lock_store(struct device *dev,  	md = mmc_blk_get(dev_to_disk(dev));  	card = md->queue.card; -	mmc_claim_host(card->host); +	mmc_get_card(card);  	ret = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BOOT_WP,  				card->ext_csd.boot_ro_lock | @@ -233,7 +236,7 @@ static ssize_t power_ro_lock_store(struct device *dev,  	else  		card->ext_csd.boot_ro_lock |= EXT_CSD_BOOT_WP_B_PWR_WP_EN; -	mmc_release_host(card->host); +	mmc_put_card(card);  	if (!ret) {  		pr_info("%s: Locking boot partition ro until next power on\n", @@ -408,6 +411,35 @@ static int ioctl_rpmb_card_status_poll(struct mmc_card *card, u32 *status,  	return err;  } +static int ioctl_do_sanitize(struct mmc_card *card) +{ +	int err; + +	if (!(mmc_can_sanitize(card) && +	      (card->host->caps2 & MMC_CAP2_SANITIZE))) { +			pr_warn("%s: %s - SANITIZE is not supported\n", +				mmc_hostname(card->host), __func__); +			err = -EOPNOTSUPP; +			goto out; +	} + +	pr_debug("%s: %s - SANITIZE IN PROGRESS...\n", +		mmc_hostname(card->host), __func__); + +	err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, +					EXT_CSD_SANITIZE_START, 1, +					MMC_SANITIZE_REQ_TIMEOUT); + +	if (err) +		pr_err("%s: %s - EXT_CSD_SANITIZE_START failed. err=%d\n", +		       mmc_hostname(card->host), __func__, err); + +	pr_debug("%s: %s - SANITIZE COMPLETED\n", mmc_hostname(card->host), +					     __func__); +out: +	return err; +} +  static int mmc_blk_ioctl_cmd(struct block_device *bdev,  	struct mmc_ioc_cmd __user *ic_ptr)  { @@ -491,7 +523,7 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev,  	mrq.cmd = &cmd; -	mmc_claim_host(card->host); +	mmc_get_card(card);  	err = mmc_blk_part_switch(card, md);  	if (err) @@ -510,6 +542,17 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev,  			goto cmd_rel_host;  	} +	if ((MMC_EXTRACT_INDEX_FROM_ARG(cmd.arg) == EXT_CSD_SANITIZE_START) && +	    (cmd.opcode == MMC_SWITCH)) { +		err = ioctl_do_sanitize(card); + +		if (err) +			pr_err("%s: ioctl_do_sanitize() failed. err = %d", +			       __func__, err); + +		goto cmd_rel_host; +	} +  	mmc_wait_for_req(card->host, &mrq);  	if (cmd.error) { @@ -558,7 +601,7 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev,  	}  cmd_rel_host: -	mmc_release_host(card->host); +	mmc_put_card(card);  cmd_done:  	mmc_blk_put(md); @@ -939,10 +982,10 @@ 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, trim_arg, erase_arg; +	unsigned int from, nr, arg;  	int err = 0, type = MMC_BLK_SECDISCARD; -	if (!(mmc_can_secure_erase_trim(card) || mmc_can_sanitize(card))) { +	if (!(mmc_can_secure_erase_trim(card))) {  		err = -EOPNOTSUPP;  		goto out;  	} @@ -950,23 +993,11 @@ static int mmc_blk_issue_secdiscard_rq(struct mmc_queue *mq,  	from = blk_rq_pos(req);  	nr = blk_rq_sectors(req); -	/* The sanitize operation is supported at v4.5 only */ -	if (mmc_can_sanitize(card)) { -		erase_arg = MMC_ERASE_ARG; -		trim_arg = MMC_TRIM_ARG; -	} else { -		erase_arg = MMC_SECURE_ERASE_ARG; -		trim_arg = MMC_SECURE_TRIM1_ARG; -	} +	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, @@ -1002,9 +1033,6 @@ retry:  			goto out;  	} -	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; @@ -1895,7 +1923,7 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)  	if (req && !mq->mqrq_prev->req)  		/* claim host only for the first request */ -		mmc_claim_host(card->host); +		mmc_get_card(card);  	ret = mmc_blk_part_switch(card, md);  	if (ret) { @@ -1939,7 +1967,7 @@ out:  		 * In case sepecial request, there is no reentry to  		 * the 'mmc_blk_issue_rq' with 'mqrq_prev->req'.  		 */ -		mmc_release_host(card->host); +		mmc_put_card(card);  	return ret;  } @@ -2158,6 +2186,14 @@ static void mmc_blk_remove_req(struct mmc_blk_data *md)  	struct mmc_card *card;  	if (md) { +		/* +		 * Flush remaining requests and free queues. It +		 * is freeing the queue that stops new requests +		 * from being accepted. +		 */ +		mmc_cleanup_queue(&md->queue); +		if (md->flags & MMC_BLK_PACKED_CMD) +			mmc_packed_clean(&md->queue);  		card = md->queue.card;  		if (md->disk->flags & GENHD_FL_UP) {  			device_remove_file(disk_to_dev(md->disk), &md->force_ro); @@ -2166,14 +2202,8 @@ static void mmc_blk_remove_req(struct mmc_blk_data *md)  				device_remove_file(disk_to_dev(md->disk),  					&md->power_ro_lock); -			/* Stop new requests from getting into the queue */  			del_gendisk(md->disk);  		} - -		/* Then flush out any already in there */ -		mmc_cleanup_queue(&md->queue); -		if (md->flags & MMC_BLK_PACKED_CMD) -			mmc_packed_clean(&md->queue);  		mmc_blk_put(md);  	}  } @@ -2336,6 +2366,19 @@ static int mmc_blk_probe(struct mmc_card *card)  		if (mmc_add_disk(part_md))  			goto out;  	} + +	pm_runtime_set_autosuspend_delay(&card->dev, 3000); +	pm_runtime_use_autosuspend(&card->dev); + +	/* +	 * Don't enable runtime PM for SD-combo cards here. Leave that +	 * decision to be taken during the SDIO init sequence instead. +	 */ +	if (card->type != MMC_TYPE_SD_COMBO) { +		pm_runtime_set_active(&card->dev); +		pm_runtime_enable(&card->dev); +	} +  	return 0;   out: @@ -2349,20 +2392,24 @@ static void mmc_blk_remove(struct mmc_card *card)  	struct mmc_blk_data *md = mmc_get_drvdata(card);  	mmc_blk_remove_parts(card, md); +	pm_runtime_get_sync(&card->dev);  	mmc_claim_host(card->host);  	mmc_blk_part_switch(card, md);  	mmc_release_host(card->host); +	if (card->type != MMC_TYPE_SD_COMBO) +		pm_runtime_disable(&card->dev); +	pm_runtime_put_noidle(&card->dev);  	mmc_blk_remove_req(md);  	mmc_set_drvdata(card, NULL);  } -#ifdef CONFIG_PM -static int mmc_blk_suspend(struct mmc_card *card) +static int _mmc_blk_suspend(struct mmc_card *card)  {  	struct mmc_blk_data *part_md;  	struct mmc_blk_data *md = mmc_get_drvdata(card);  	if (md) { +		pm_runtime_get_sync(&card->dev);  		mmc_queue_suspend(&md->queue);  		list_for_each_entry(part_md, &md->part, part) {  			mmc_queue_suspend(&part_md->queue); @@ -2371,6 +2418,17 @@ static int mmc_blk_suspend(struct mmc_card *card)  	return 0;  } +static void mmc_blk_shutdown(struct mmc_card *card) +{ +	_mmc_blk_suspend(card); +} + +#ifdef CONFIG_PM +static int mmc_blk_suspend(struct mmc_card *card) +{ +	return _mmc_blk_suspend(card); +} +  static int mmc_blk_resume(struct mmc_card *card)  {  	struct mmc_blk_data *part_md; @@ -2386,6 +2444,7 @@ static int mmc_blk_resume(struct mmc_card *card)  		list_for_each_entry(part_md, &md->part, part) {  			mmc_queue_resume(&part_md->queue);  		} +		pm_runtime_put(&card->dev);  	}  	return 0;  } @@ -2402,6 +2461,7 @@ static struct mmc_driver mmc_driver = {  	.remove		= mmc_blk_remove,  	.suspend	= mmc_blk_suspend,  	.resume		= mmc_blk_resume, +	.shutdown	= mmc_blk_shutdown,  };  static int __init mmc_blk_init(void) diff --git a/drivers/mmc/card/mmc_test.c b/drivers/mmc/card/mmc_test.c index 759714ed6bee..a69df5216274 100644 --- a/drivers/mmc/card/mmc_test.c +++ b/drivers/mmc/card/mmc_test.c @@ -3025,12 +3025,17 @@ static void mmc_test_remove(struct mmc_card *card)  	mmc_test_free_dbgfs_file(card);  } +static void mmc_test_shutdown(struct mmc_card *card) +{ +} +  static struct mmc_driver mmc_driver = {  	.drv		= {  		.name	= "mmc_test",  	},  	.probe		= mmc_test_probe,  	.remove		= mmc_test_remove, +	.shutdown	= mmc_test_shutdown,  };  static int __init mmc_test_init(void) diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c index 9447a0e970d1..fa9632eb63f1 100644 --- a/drivers/mmc/card/queue.c +++ b/drivers/mmc/card/queue.c @@ -173,7 +173,7 @@ static void mmc_queue_setup_discard(struct request_queue *q,  	/* granularity must not be greater than max. discard */  	if (card->pref_erase > max_discard)  		q->limits.discard_granularity = 0; -	if (mmc_can_secure_erase_trim(card) || mmc_can_sanitize(card)) +	if (mmc_can_secure_erase_trim(card))  		queue_flag_set_unlocked(QUEUE_FLAG_SECDISCARD, q);  } |