diff options
Diffstat (limited to 'drivers/mmc/core')
| -rw-r--r-- | drivers/mmc/core/host.c | 4 | ||||
| -rw-r--r-- | drivers/mmc/core/mmc_ops.c | 16 | ||||
| -rw-r--r-- | drivers/mmc/core/pwrseq_emmc.c | 38 | ||||
| -rw-r--r-- | drivers/mmc/core/queue.c | 1 | ||||
| -rw-r--r-- | drivers/mmc/core/quirks.h | 2 | ||||
| -rw-r--r-- | drivers/mmc/core/sd.c | 8 | 
6 files changed, 42 insertions, 27 deletions
| diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c index 3a4402a79904..6a51f7a06ce7 100644 --- a/drivers/mmc/core/host.c +++ b/drivers/mmc/core/host.c @@ -363,11 +363,11 @@ int mmc_of_parse_voltage(struct device_node *np, u32 *mask)  	int num_ranges, i;  	voltage_ranges = of_get_property(np, "voltage-ranges", &num_ranges); -	num_ranges = num_ranges / sizeof(*voltage_ranges) / 2;  	if (!voltage_ranges) {  		pr_debug("%pOF: voltage-ranges unspecified\n", np);  		return 0;  	} +	num_ranges = num_ranges / sizeof(*voltage_ranges) / 2;  	if (!num_ranges) {  		pr_err("%pOF: voltage-ranges empty\n", np);  		return -EINVAL; @@ -429,8 +429,6 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev)  	if (mmc_gpio_alloc(host)) {  		put_device(&host->class_dev); -		ida_simple_remove(&mmc_host_ida, host->index); -		kfree(host);  		return NULL;  	} diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c index c5208fb312ae..a533cab8fccc 100644 --- a/drivers/mmc/core/mmc_ops.c +++ b/drivers/mmc/core/mmc_ops.c @@ -184,11 +184,7 @@ int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)  		if (err)  			break; -		/* if we're just probing, do a single pass */ -		if (ocr == 0) -			break; - -		/* otherwise wait until reset completes */ +		/* wait until reset completes */  		if (mmc_host_is_spi(host)) {  			if (!(cmd.resp[0] & R1_SPI_IDLE))  				break; @@ -200,6 +196,16 @@ int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)  		err = -ETIMEDOUT;  		mmc_delay(10); + +		/* +		 * According to eMMC specification v5.1 section 6.4.3, we +		 * should issue CMD1 repeatedly in the idle state until +		 * the eMMC is ready. Otherwise some eMMC devices seem to enter +		 * the inactive mode after mmc_init_card() issued CMD0 when +		 * the eMMC device is busy. +		 */ +		if (!ocr && !mmc_host_is_spi(host)) +			cmd.arg = cmd.resp[0] | BIT(30);  	}  	if (rocr && !mmc_host_is_spi(host)) diff --git a/drivers/mmc/core/pwrseq_emmc.c b/drivers/mmc/core/pwrseq_emmc.c index efb8a7965dd4..154f4204d58c 100644 --- a/drivers/mmc/core/pwrseq_emmc.c +++ b/drivers/mmc/core/pwrseq_emmc.c @@ -30,19 +30,14 @@ struct mmc_pwrseq_emmc {  #define to_pwrseq_emmc(p) container_of(p, struct mmc_pwrseq_emmc, pwrseq) -static void __mmc_pwrseq_emmc_reset(struct mmc_pwrseq_emmc *pwrseq) -{ -	gpiod_set_value(pwrseq->reset_gpio, 1); -	udelay(1); -	gpiod_set_value(pwrseq->reset_gpio, 0); -	udelay(200); -} -  static void mmc_pwrseq_emmc_reset(struct mmc_host *host)  {  	struct mmc_pwrseq_emmc *pwrseq =  to_pwrseq_emmc(host->pwrseq); -	__mmc_pwrseq_emmc_reset(pwrseq); +	gpiod_set_value_cansleep(pwrseq->reset_gpio, 1); +	udelay(1); +	gpiod_set_value_cansleep(pwrseq->reset_gpio, 0); +	udelay(200);  }  static int mmc_pwrseq_emmc_reset_nb(struct notifier_block *this, @@ -50,8 +45,11 @@ static int mmc_pwrseq_emmc_reset_nb(struct notifier_block *this,  {  	struct mmc_pwrseq_emmc *pwrseq = container_of(this,  					struct mmc_pwrseq_emmc, reset_nb); +	gpiod_set_value(pwrseq->reset_gpio, 1); +	udelay(1); +	gpiod_set_value(pwrseq->reset_gpio, 0); +	udelay(200); -	__mmc_pwrseq_emmc_reset(pwrseq);  	return NOTIFY_DONE;  } @@ -72,14 +70,18 @@ static int mmc_pwrseq_emmc_probe(struct platform_device *pdev)  	if (IS_ERR(pwrseq->reset_gpio))  		return PTR_ERR(pwrseq->reset_gpio); -	/* -	 * register reset handler to ensure emmc reset also from -	 * emergency_reboot(), priority 255 is the highest priority -	 * so it will be executed before any system reboot handler. -	 */ -	pwrseq->reset_nb.notifier_call = mmc_pwrseq_emmc_reset_nb; -	pwrseq->reset_nb.priority = 255; -	register_restart_handler(&pwrseq->reset_nb); +	if (!gpiod_cansleep(pwrseq->reset_gpio)) { +		/* +		 * register reset handler to ensure emmc reset also from +		 * emergency_reboot(), priority 255 is the highest priority +		 * so it will be executed before any system reboot handler. +		 */ +		pwrseq->reset_nb.notifier_call = mmc_pwrseq_emmc_reset_nb; +		pwrseq->reset_nb.priority = 255; +		register_restart_handler(&pwrseq->reset_nb); +	} else { +		dev_notice(dev, "EMMC reset pin tied to a sleepy GPIO driver; reset on emergency-reboot disabled\n"); +	}  	pwrseq->pwrseq.ops = &mmc_pwrseq_emmc_ops;  	pwrseq->pwrseq.dev = dev; diff --git a/drivers/mmc/core/queue.c b/drivers/mmc/core/queue.c index 7c364a9c4eeb..b5b9c6142f08 100644 --- a/drivers/mmc/core/queue.c +++ b/drivers/mmc/core/queue.c @@ -472,6 +472,7 @@ void mmc_cleanup_queue(struct mmc_queue *mq)  		blk_mq_unquiesce_queue(q);  	blk_cleanup_queue(q); +	blk_mq_free_tag_set(&mq->tag_set);  	/*  	 * A request can be completed before the next request, potentially diff --git a/drivers/mmc/core/quirks.h b/drivers/mmc/core/quirks.h index dd2f73af8f2c..2d2d9ea8be4f 100644 --- a/drivers/mmc/core/quirks.h +++ b/drivers/mmc/core/quirks.h @@ -159,7 +159,7 @@ static inline void mmc_fixup_device(struct mmc_card *card,  		    (f->ext_csd_rev == EXT_CSD_REV_ANY ||  		     f->ext_csd_rev == card->ext_csd.rev) &&  		    rev >= f->rev_start && rev <= f->rev_end) { -			dev_dbg(&card->dev, "calling %pf\n", f->vendor_fixup); +			dev_dbg(&card->dev, "calling %ps\n", f->vendor_fixup);  			f->vendor_fixup(card, f->data);  		}  	} diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index 265e1aeeb9d8..d3d32f9a2cb1 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -221,6 +221,14 @@ static int mmc_decode_scr(struct mmc_card *card)  	if (scr->sda_spec3)  		scr->cmds = UNSTUFF_BITS(resp, 32, 2); + +	/* SD Spec says: any SD Card shall set at least bits 0 and 2 */ +	if (!(scr->bus_widths & SD_SCR_BUS_WIDTH_1) || +	    !(scr->bus_widths & SD_SCR_BUS_WIDTH_4)) { +		pr_err("%s: invalid bus width\n", mmc_hostname(card->host)); +		return -EINVAL; +	} +  	return 0;  } |