diff options
Diffstat (limited to 'drivers/mmc/core')
| -rw-r--r-- | drivers/mmc/core/core.c | 200 | ||||
| -rw-r--r-- | drivers/mmc/core/mmc.c | 77 | ||||
| -rw-r--r-- | drivers/mmc/core/sd.c | 68 | ||||
| -rw-r--r-- | drivers/mmc/core/sdio.c | 39 | ||||
| -rw-r--r-- | drivers/mmc/core/sdio_bus.c | 10 | 
5 files changed, 320 insertions, 74 deletions
| diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 68091dda3f31..89bdeaec7182 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -23,6 +23,7 @@  #include <linux/log2.h>  #include <linux/regulator/consumer.h>  #include <linux/pm_runtime.h> +#include <linux/suspend.h>  #include <linux/mmc/card.h>  #include <linux/mmc/host.h> @@ -198,9 +199,109 @@ mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)  static void mmc_wait_done(struct mmc_request *mrq)  { -	complete(mrq->done_data); +	complete(&mrq->completion);  } +static void __mmc_start_req(struct mmc_host *host, struct mmc_request *mrq) +{ +	init_completion(&mrq->completion); +	mrq->done = mmc_wait_done; +	mmc_start_request(host, mrq); +} + +static void mmc_wait_for_req_done(struct mmc_host *host, +				  struct mmc_request *mrq) +{ +	wait_for_completion(&mrq->completion); +} + +/** + *	mmc_pre_req - Prepare for a new request + *	@host: MMC host to prepare command + *	@mrq: MMC request to prepare for + *	@is_first_req: true if there is no previous started request + *                     that may run in parellel to this call, otherwise false + * + *	mmc_pre_req() is called in prior to mmc_start_req() to let + *	host prepare for the new request. Preparation of a request may be + *	performed while another request is running on the host. + */ +static void mmc_pre_req(struct mmc_host *host, struct mmc_request *mrq, +		 bool is_first_req) +{ +	if (host->ops->pre_req) +		host->ops->pre_req(host, mrq, is_first_req); +} + +/** + *	mmc_post_req - Post process a completed request + *	@host: MMC host to post process command + *	@mrq: MMC request to post process for + *	@err: Error, if non zero, clean up any resources made in pre_req + * + *	Let the host post process a completed request. Post processing of + *	a request may be performed while another reuqest is running. + */ +static void mmc_post_req(struct mmc_host *host, struct mmc_request *mrq, +			 int err) +{ +	if (host->ops->post_req) +		host->ops->post_req(host, mrq, err); +} + +/** + *	mmc_start_req - start a non-blocking request + *	@host: MMC host to start command + *	@areq: async request to start + *	@error: out parameter returns 0 for success, otherwise non zero + * + *	Start a new MMC custom command request for a host. + *	If there is on ongoing async request wait for completion + *	of that request and start the new one and return. + *	Does not wait for the new request to complete. + * + *      Returns the completed request, NULL in case of none completed. + *	Wait for the an ongoing request (previoulsy started) to complete and + *	return the completed request. If there is no ongoing request, NULL + *	is returned without waiting. NULL is not an error condition. + */ +struct mmc_async_req *mmc_start_req(struct mmc_host *host, +				    struct mmc_async_req *areq, int *error) +{ +	int err = 0; +	struct mmc_async_req *data = host->areq; + +	/* Prepare a new request */ +	if (areq) +		mmc_pre_req(host, areq->mrq, !host->areq); + +	if (host->areq) { +		mmc_wait_for_req_done(host, host->areq->mrq); +		err = host->areq->err_check(host->card, host->areq); +		if (err) { +			mmc_post_req(host, host->areq->mrq, 0); +			if (areq) +				mmc_post_req(host, areq->mrq, -EINVAL); + +			host->areq = NULL; +			goto out; +		} +	} + +	if (areq) +		__mmc_start_req(host, areq->mrq); + +	if (host->areq) +		mmc_post_req(host, host->areq->mrq, 0); + +	host->areq = areq; + out: +	if (error) +		*error = err; +	return data; +} +EXPORT_SYMBOL(mmc_start_req); +  /**   *	mmc_wait_for_req - start a request and wait for completion   *	@host: MMC host to start command @@ -212,16 +313,9 @@ static void mmc_wait_done(struct mmc_request *mrq)   */  void mmc_wait_for_req(struct mmc_host *host, struct mmc_request *mrq)  { -	DECLARE_COMPLETION_ONSTACK(complete); - -	mrq->done_data = &complete; -	mrq->done = mmc_wait_done; - -	mmc_start_request(host, mrq); - -	wait_for_completion(&complete); +	__mmc_start_req(host, mrq); +	mmc_wait_for_req_done(host, mrq);  } -  EXPORT_SYMBOL(mmc_wait_for_req);  /** @@ -1245,7 +1339,7 @@ static unsigned int mmc_mmc_erase_timeout(struct mmc_card *card,  		 */  		timeout_clks <<= 1;  		timeout_us += (timeout_clks * 1000) / -			      (card->host->ios.clock / 1000); +			      (mmc_host_clk_rate(card->host) / 1000);  		erase_timeout = timeout_us / 1000; @@ -1516,6 +1610,82 @@ int mmc_erase_group_aligned(struct mmc_card *card, unsigned int from,  }  EXPORT_SYMBOL(mmc_erase_group_aligned); +static unsigned int mmc_do_calc_max_discard(struct mmc_card *card, +					    unsigned int arg) +{ +	struct mmc_host *host = card->host; +	unsigned int max_discard, x, y, qty = 0, max_qty, timeout; +	unsigned int last_timeout = 0; + +	if (card->erase_shift) +		max_qty = UINT_MAX >> card->erase_shift; +	else if (mmc_card_sd(card)) +		max_qty = UINT_MAX; +	else +		max_qty = UINT_MAX / card->erase_size; + +	/* Find the largest qty with an OK timeout */ +	do { +		y = 0; +		for (x = 1; x && x <= max_qty && max_qty - x >= qty; x <<= 1) { +			timeout = mmc_erase_timeout(card, arg, qty + x); +			if (timeout > host->max_discard_to) +				break; +			if (timeout < last_timeout) +				break; +			last_timeout = timeout; +			y = x; +		} +		qty += y; +	} while (y); + +	if (!qty) +		return 0; + +	if (qty == 1) +		return 1; + +	/* Convert qty to sectors */ +	if (card->erase_shift) +		max_discard = --qty << card->erase_shift; +	else if (mmc_card_sd(card)) +		max_discard = qty; +	else +		max_discard = --qty * card->erase_size; + +	return max_discard; +} + +unsigned int mmc_calc_max_discard(struct mmc_card *card) +{ +	struct mmc_host *host = card->host; +	unsigned int max_discard, max_trim; + +	if (!host->max_discard_to) +		return UINT_MAX; + +	/* +	 * Without erase_group_def set, MMC erase timeout depends on clock +	 * frequence which can change.  In that case, the best choice is +	 * just the preferred erase size. +	 */ +	if (mmc_card_mmc(card) && !(card->ext_csd.erase_group_def & 1)) +		return card->pref_erase; + +	max_discard = mmc_do_calc_max_discard(card, MMC_ERASE_ARG); +	if (mmc_can_trim(card)) { +		max_trim = mmc_do_calc_max_discard(card, MMC_TRIM_ARG); +		if (max_trim < max_discard) +			max_discard = max_trim; +	} else if (max_discard < card->erase_size) { +		max_discard = 0; +	} +	pr_debug("%s: calculated max. discard sectors %u for timeout %u ms\n", +		 mmc_hostname(host), max_discard, host->max_discard_to); +	return max_discard; +} +EXPORT_SYMBOL(mmc_calc_max_discard); +  int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen)  {  	struct mmc_command cmd = {0}; @@ -1663,6 +1833,10 @@ int mmc_power_save_host(struct mmc_host *host)  {  	int ret = 0; +#ifdef CONFIG_MMC_DEBUG +	pr_info("%s: %s: powering down\n", mmc_hostname(host), __func__); +#endif +  	mmc_bus_get(host);  	if (!host->bus_ops || host->bus_dead || !host->bus_ops->power_restore) { @@ -1685,6 +1859,10 @@ int mmc_power_restore_host(struct mmc_host *host)  {  	int ret; +#ifdef CONFIG_MMC_DEBUG +	pr_info("%s: %s: powering up\n", mmc_hostname(host), __func__); +#endif +  	mmc_bus_get(host);  	if (!host->bus_ops || host->bus_dead || !host->bus_ops->power_restore) { diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 2a7e43bc796d..aa7d1d79b8c5 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -247,12 +247,12 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)  		return 0;  	/* Version is coded in the CSD_STRUCTURE byte in the EXT_CSD register */ +	card->ext_csd.raw_ext_csd_structure = ext_csd[EXT_CSD_STRUCTURE];  	if (card->csd.structure == 3) { -		int ext_csd_struct = ext_csd[EXT_CSD_STRUCTURE]; -		if (ext_csd_struct > 2) { +		if (card->ext_csd.raw_ext_csd_structure > 2) {  			printk(KERN_ERR "%s: unrecognised EXT_CSD structure "  				"version %d\n", mmc_hostname(card->host), -					ext_csd_struct); +					card->ext_csd.raw_ext_csd_structure);  			err = -EINVAL;  			goto out;  		} @@ -266,6 +266,10 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)  		goto out;  	} +	card->ext_csd.raw_sectors[0] = ext_csd[EXT_CSD_SEC_CNT + 0]; +	card->ext_csd.raw_sectors[1] = ext_csd[EXT_CSD_SEC_CNT + 1]; +	card->ext_csd.raw_sectors[2] = ext_csd[EXT_CSD_SEC_CNT + 2]; +	card->ext_csd.raw_sectors[3] = ext_csd[EXT_CSD_SEC_CNT + 3];  	if (card->ext_csd.rev >= 2) {  		card->ext_csd.sectors =  			ext_csd[EXT_CSD_SEC_CNT + 0] << 0 | @@ -277,7 +281,7 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)  		if (card->ext_csd.sectors > (2u * 1024 * 1024 * 1024) / 512)  			mmc_card_set_blockaddr(card);  	} - +	card->ext_csd.raw_card_type = ext_csd[EXT_CSD_CARD_TYPE];  	switch (ext_csd[EXT_CSD_CARD_TYPE] & EXT_CSD_CARD_TYPE_MASK) {  	case EXT_CSD_CARD_TYPE_DDR_52 | EXT_CSD_CARD_TYPE_52 |  	     EXT_CSD_CARD_TYPE_26: @@ -307,6 +311,11 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)  			mmc_hostname(card->host));  	} +	card->ext_csd.raw_s_a_timeout = ext_csd[EXT_CSD_S_A_TIMEOUT]; +	card->ext_csd.raw_erase_timeout_mult = +		ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT]; +	card->ext_csd.raw_hc_erase_grp_size = +		ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];  	if (card->ext_csd.rev >= 3) {  		u8 sa_shift = ext_csd[EXT_CSD_S_A_TIMEOUT];  		card->ext_csd.part_config = ext_csd[EXT_CSD_PART_CONFIG]; @@ -334,6 +343,16 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)  		card->ext_csd.boot_size = ext_csd[EXT_CSD_BOOT_MULT] << 17;  	} +	card->ext_csd.raw_hc_erase_gap_size = +		ext_csd[EXT_CSD_PARTITION_ATTRIBUTE]; +	card->ext_csd.raw_sec_trim_mult = +		ext_csd[EXT_CSD_SEC_TRIM_MULT]; +	card->ext_csd.raw_sec_erase_mult = +		ext_csd[EXT_CSD_SEC_ERASE_MULT]; +	card->ext_csd.raw_sec_feature_support = +		ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT]; +	card->ext_csd.raw_trim_mult = +		ext_csd[EXT_CSD_TRIM_MULT];  	if (card->ext_csd.rev >= 4) {  		/*  		 * Enhanced area feature support -- check whether the eMMC @@ -341,7 +360,7 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)  		 * area offset and size to user by adding sysfs interface.  		 */  		if ((ext_csd[EXT_CSD_PARTITION_SUPPORT] & 0x2) && -				(ext_csd[EXT_CSD_PARTITION_ATTRIBUTE] & 0x1)) { +		    (ext_csd[EXT_CSD_PARTITION_ATTRIBUTE] & 0x1)) {  			u8 hc_erase_grp_sz =  				ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];  			u8 hc_wp_grp_sz = @@ -401,17 +420,17 @@ static inline void mmc_free_ext_csd(u8 *ext_csd)  } -static int mmc_compare_ext_csds(struct mmc_card *card, u8 *ext_csd, -			unsigned bus_width) +static int mmc_compare_ext_csds(struct mmc_card *card, unsigned bus_width)  {  	u8 *bw_ext_csd;  	int err; +	if (bus_width == MMC_BUS_WIDTH_1) +		return 0; +  	err = mmc_get_ext_csd(card, &bw_ext_csd); -	if (err) -		return err; -	if ((ext_csd == NULL || bw_ext_csd == NULL)) { +	if (err || bw_ext_csd == NULL) {  		if (bus_width != MMC_BUS_WIDTH_1)  			err = -EINVAL;  		goto out; @@ -421,35 +440,40 @@ static int mmc_compare_ext_csds(struct mmc_card *card, u8 *ext_csd,  		goto out;  	/* only compare read only fields */ -	err = (!(ext_csd[EXT_CSD_PARTITION_SUPPORT] == +	err = (!(card->ext_csd.raw_partition_support ==  			bw_ext_csd[EXT_CSD_PARTITION_SUPPORT]) && -		(ext_csd[EXT_CSD_ERASED_MEM_CONT] == +		(card->ext_csd.raw_erased_mem_count ==  			bw_ext_csd[EXT_CSD_ERASED_MEM_CONT]) && -		(ext_csd[EXT_CSD_REV] == +		(card->ext_csd.rev ==  			bw_ext_csd[EXT_CSD_REV]) && -		(ext_csd[EXT_CSD_STRUCTURE] == +		(card->ext_csd.raw_ext_csd_structure ==  			bw_ext_csd[EXT_CSD_STRUCTURE]) && -		(ext_csd[EXT_CSD_CARD_TYPE] == +		(card->ext_csd.raw_card_type ==  			bw_ext_csd[EXT_CSD_CARD_TYPE]) && -		(ext_csd[EXT_CSD_S_A_TIMEOUT] == +		(card->ext_csd.raw_s_a_timeout ==  			bw_ext_csd[EXT_CSD_S_A_TIMEOUT]) && -		(ext_csd[EXT_CSD_HC_WP_GRP_SIZE] == +		(card->ext_csd.raw_hc_erase_gap_size ==  			bw_ext_csd[EXT_CSD_HC_WP_GRP_SIZE]) && -		(ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT] == +		(card->ext_csd.raw_erase_timeout_mult ==  			bw_ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT]) && -		(ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] == +		(card->ext_csd.raw_hc_erase_grp_size ==  			bw_ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]) && -		(ext_csd[EXT_CSD_SEC_TRIM_MULT] == +		(card->ext_csd.raw_sec_trim_mult ==  			bw_ext_csd[EXT_CSD_SEC_TRIM_MULT]) && -		(ext_csd[EXT_CSD_SEC_ERASE_MULT] == +		(card->ext_csd.raw_sec_erase_mult ==  			bw_ext_csd[EXT_CSD_SEC_ERASE_MULT]) && -		(ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT] == +		(card->ext_csd.raw_sec_feature_support ==  			bw_ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT]) && -		(ext_csd[EXT_CSD_TRIM_MULT] == +		(card->ext_csd.raw_trim_mult ==  			bw_ext_csd[EXT_CSD_TRIM_MULT]) && -		memcmp(&ext_csd[EXT_CSD_SEC_CNT], -		       &bw_ext_csd[EXT_CSD_SEC_CNT], -		       4) != 0); +		(card->ext_csd.raw_sectors[0] == +			bw_ext_csd[EXT_CSD_SEC_CNT + 0]) && +		(card->ext_csd.raw_sectors[1] == +			bw_ext_csd[EXT_CSD_SEC_CNT + 1]) && +		(card->ext_csd.raw_sectors[2] == +			bw_ext_csd[EXT_CSD_SEC_CNT + 2]) && +		(card->ext_csd.raw_sectors[3] == +			bw_ext_csd[EXT_CSD_SEC_CNT + 3]));  	if (err)  		err = -EINVAL; @@ -770,7 +794,6 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,  				 */  				if (!(host->caps & MMC_CAP_BUS_WIDTH_TEST))  					err = mmc_compare_ext_csds(card, -						ext_csd,  						bus_width);  				else  					err = mmc_bus_test(card, bus_width); diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index ff2774128aa9..633975ff2bb3 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -409,52 +409,62 @@ out:  static int sd_select_driver_type(struct mmc_card *card, u8 *status)  { -	int host_drv_type = 0, card_drv_type = 0; +	int host_drv_type = SD_DRIVER_TYPE_B; +	int card_drv_type = SD_DRIVER_TYPE_B; +	int drive_strength;  	int err;  	/*  	 * If the host doesn't support any of the Driver Types A,C or D, -	 * default Driver Type B is used. +	 * or there is no board specific handler then default Driver +	 * Type B is used.  	 */  	if (!(card->host->caps & (MMC_CAP_DRIVER_TYPE_A | MMC_CAP_DRIVER_TYPE_C  	    | MMC_CAP_DRIVER_TYPE_D)))  		return 0; -	if (card->host->caps & MMC_CAP_DRIVER_TYPE_A) { -		host_drv_type = MMC_SET_DRIVER_TYPE_A; -		if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_A) -			card_drv_type = MMC_SET_DRIVER_TYPE_A; -		else if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_B) -			card_drv_type = MMC_SET_DRIVER_TYPE_B; -		else if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_C) -			card_drv_type = MMC_SET_DRIVER_TYPE_C; -	} else if (card->host->caps & MMC_CAP_DRIVER_TYPE_C) { -		host_drv_type = MMC_SET_DRIVER_TYPE_C; -		if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_C) -			card_drv_type = MMC_SET_DRIVER_TYPE_C; -	} else if (!(card->host->caps & MMC_CAP_DRIVER_TYPE_D)) { -		/* -		 * If we are here, that means only the default driver type -		 * B is supported by the host. -		 */ -		host_drv_type = MMC_SET_DRIVER_TYPE_B; -		if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_B) -			card_drv_type = MMC_SET_DRIVER_TYPE_B; -		else if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_C) -			card_drv_type = MMC_SET_DRIVER_TYPE_C; -	} +	if (!card->host->ops->select_drive_strength) +		return 0; + +	if (card->host->caps & MMC_CAP_DRIVER_TYPE_A) +		host_drv_type |= SD_DRIVER_TYPE_A; + +	if (card->host->caps & MMC_CAP_DRIVER_TYPE_C) +		host_drv_type |= SD_DRIVER_TYPE_C; + +	if (card->host->caps & MMC_CAP_DRIVER_TYPE_D) +		host_drv_type |= SD_DRIVER_TYPE_D; + +	if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_A) +		card_drv_type |= SD_DRIVER_TYPE_A; + +	if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_C) +		card_drv_type |= SD_DRIVER_TYPE_C; + +	if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_D) +		card_drv_type |= SD_DRIVER_TYPE_D; + +	/* +	 * The drive strength that the hardware can support +	 * depends on the board design.  Pass the appropriate +	 * information and let the hardware specific code +	 * return what is possible given the options +	 */ +	drive_strength = card->host->ops->select_drive_strength( +		card->sw_caps.uhs_max_dtr, +		host_drv_type, card_drv_type); -	err = mmc_sd_switch(card, 1, 2, card_drv_type, status); +	err = mmc_sd_switch(card, 1, 2, drive_strength, status);  	if (err)  		return err; -	if ((status[15] & 0xF) != card_drv_type) { -		printk(KERN_WARNING "%s: Problem setting driver strength!\n", +	if ((status[15] & 0xF) != drive_strength) { +		printk(KERN_WARNING "%s: Problem setting drive strength!\n",  			mmc_hostname(card->host));  		return 0;  	} -	mmc_set_driver_type(card->host, host_drv_type); +	mmc_set_driver_type(card->host, drive_strength);  	return 0;  } diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index 4d0c15bfa514..262fff019177 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -691,15 +691,54 @@ static int mmc_sdio_resume(struct mmc_host *host)  static int mmc_sdio_power_restore(struct mmc_host *host)  {  	int ret; +	u32 ocr;  	BUG_ON(!host);  	BUG_ON(!host->card);  	mmc_claim_host(host); + +	/* +	 * Reset the card by performing the same steps that are taken by +	 * mmc_rescan_try_freq() and mmc_attach_sdio() during a "normal" probe. +	 * +	 * sdio_reset() is technically not needed. Having just powered up the +	 * hardware, it should already be in reset state. However, some +	 * platforms (such as SD8686 on OLPC) do not instantly cut power, +	 * meaning that a reset is required when restoring power soon after +	 * powering off. It is harmless in other cases. +	 * +	 * The CMD5 reset (mmc_send_io_op_cond()), according to the SDIO spec, +	 * is not necessary for non-removable cards. However, it is required +	 * for OLPC SD8686 (which expects a [CMD5,5,3,7] init sequence), and +	 * harmless in other situations. +	 * +	 * With these steps taken, mmc_select_voltage() is also required to +	 * restore the correct voltage setting of the card. +	 */ +	sdio_reset(host); +	mmc_go_idle(host); +	mmc_send_if_cond(host, host->ocr_avail); + +	ret = mmc_send_io_op_cond(host, 0, &ocr); +	if (ret) +		goto out; + +	if (host->ocr_avail_sdio) +		host->ocr_avail = host->ocr_avail_sdio; + +	host->ocr = mmc_select_voltage(host, ocr & ~0x7F); +	if (!host->ocr) { +		ret = -EINVAL; +		goto out; +	} +  	ret = mmc_sdio_init_card(host, host->ocr, host->card,  				mmc_card_keep_power(host));  	if (!ret && host->sdio_irqs)  		mmc_signal_sdio_irq(host); + +out:  	mmc_release_host(host);  	return ret; diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c index d29b9c36919a..e4e6822d09e3 100644 --- a/drivers/mmc/core/sdio_bus.c +++ b/drivers/mmc/core/sdio_bus.c @@ -167,11 +167,8 @@ static int sdio_bus_remove(struct device *dev)  	int ret = 0;  	/* Make sure card is powered before invoking ->remove() */ -	if (func->card->host->caps & MMC_CAP_POWER_OFF_CARD) { -		ret = pm_runtime_get_sync(dev); -		if (ret < 0) -			goto out; -	} +	if (func->card->host->caps & MMC_CAP_POWER_OFF_CARD) +		pm_runtime_get_sync(dev);  	drv->remove(func); @@ -189,9 +186,8 @@ static int sdio_bus_remove(struct device *dev)  	/* Then undo the runtime PM settings in sdio_bus_probe() */  	if (func->card->host->caps & MMC_CAP_POWER_OFF_CARD) -		pm_runtime_put_noidle(dev); +		pm_runtime_put_sync(dev); -out:  	return ret;  } | 
