RE: [PATCH] mmc: core: Ensure clocks are always enabled before host interaction

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



	
> -----Original Message-----
> From: linux-mmc-owner@xxxxxxxxxxxxxxx [mailto:linux-mmc-
> owner@xxxxxxxxxxxxxxx] On Behalf Of Sujit Reddy Thumma
> Sent: Monday, December 12, 2011 1:52 PM
> To: linux-mmc@xxxxxxxxxxxxxxx
> Cc: Sujit Reddy Thumma; cjb@xxxxxxxxxx
> Subject: [PATCH] mmc: core: Ensure clocks are always enabled before
> host interaction
> 
> Ensure clocks are always enabled before any interaction with the
> host controller driver. This makes sure that there is no race
> between host execution and the core layer turning off clocks
> in different context with clock gating framework.

Thanks Sujit.

We were seeing the race between mmc_host_clk_gate_delayed and
execute_tuning(). Basically when host driver is in their execute_tuning()
ops, mmc_host_clk_gate_delayed() may disable the clocks which may cause the
execute_tuning() to fail. Your patch fixes this issue.

Acked-by: Subhash Jadavani <subhashj@xxxxxxxxxxxxxx>

> 
> Signed-off-by: Sujit Reddy Thumma <sthumma@xxxxxxxxxxxxxx>
> ---
>  drivers/mmc/core/core.c     |   19 ++++++++++++++++---
>  drivers/mmc/core/host.h     |   21 ---------------------
>  drivers/mmc/core/sd.c       |   22 ++++++++++++++++++----
>  drivers/mmc/core/sdio.c     |   12 ++++++++++--
>  drivers/mmc/core/sdio_irq.c |   10 ++++++++--
>  include/linux/mmc/host.h    |   19 +++++++++++++++++++
>  6 files changed, 71 insertions(+), 32 deletions(-)
> 
> diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
> index a2aa860..03ad9fa 100644
> --- a/drivers/mmc/core/core.c
> +++ b/drivers/mmc/core/core.c
> @@ -290,8 +290,11 @@ static void mmc_wait_for_req_done(struct mmc_host
> *host,
>  static void mmc_pre_req(struct mmc_host *host, struct mmc_request
> *mrq,
>  		 bool is_first_req)
>  {
> -	if (host->ops->pre_req)
> +	if (host->ops->pre_req) {
> +		mmc_host_clk_hold(host);
>  		host->ops->pre_req(host, mrq, is_first_req);
> +		mmc_host_clk_release(host);
> +	}
>  }
> 
>  /**
> @@ -306,8 +309,11 @@ static void mmc_pre_req(struct mmc_host *host,
> struct mmc_request *mrq,
>  static void mmc_post_req(struct mmc_host *host, struct mmc_request
> *mrq,
>  			 int err)
>  {
> -	if (host->ops->post_req)
> +	if (host->ops->post_req) {
> +		mmc_host_clk_hold(host);
>  		host->ops->post_req(host, mrq, err);
> +		mmc_host_clk_release(host);
> +	}
>  }
> 
>  /**
> @@ -620,7 +626,9 @@ int mmc_host_enable(struct mmc_host *host)
>  		int err;
> 
>  		host->en_dis_recurs = 1;
> +		mmc_host_clk_hold(host);
>  		err = host->ops->enable(host);
> +		mmc_host_clk_release(host);
>  		host->en_dis_recurs = 0;
> 
>  		if (err) {
> @@ -640,7 +648,9 @@ static int mmc_host_do_disable(struct mmc_host
> *host, int lazy)
>  		int err;
> 
>  		host->en_dis_recurs = 1;
> +		mmc_host_clk_hold(host);
>  		err = host->ops->disable(host, lazy);
> +		mmc_host_clk_release(host);
>  		host->en_dis_recurs = 0;
> 
>  		if (err < 0) {
> @@ -1203,8 +1213,11 @@ int mmc_set_signal_voltage(struct mmc_host
> *host, int signal_voltage, bool cmd11
> 
>  	host->ios.signal_voltage = signal_voltage;
> 
> -	if (host->ops->start_signal_voltage_switch)
> +	if (host->ops->start_signal_voltage_switch) {
> +		mmc_host_clk_hold(host);
>  		err = host->ops->start_signal_voltage_switch(host, &host-
> >ios);
> +		mmc_host_clk_release(host);
> +	}
> 
>  	return err;
>  }
> diff --git a/drivers/mmc/core/host.h b/drivers/mmc/core/host.h
> index fb8a5cd..08a7852 100644
> --- a/drivers/mmc/core/host.h
> +++ b/drivers/mmc/core/host.h
> @@ -14,27 +14,6 @@
> 
>  int mmc_register_host_class(void);
>  void mmc_unregister_host_class(void);
> -
> -#ifdef CONFIG_MMC_CLKGATE
> -void mmc_host_clk_hold(struct mmc_host *host);
> -void mmc_host_clk_release(struct mmc_host *host);
> -unsigned int mmc_host_clk_rate(struct mmc_host *host);
> -
> -#else
> -static inline void mmc_host_clk_hold(struct mmc_host *host)
> -{
> -}
> -
> -static inline void mmc_host_clk_release(struct mmc_host *host)
> -{
> -}
> -
> -static inline unsigned int mmc_host_clk_rate(struct mmc_host *host)
> -{
> -	return host->ios.clock;
> -}
> -#endif
> -
>  void mmc_host_deeper_disable(struct work_struct *work);
> 
>  #endif
> diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
> index 6f27d35..b5212b8 100644
> --- a/drivers/mmc/core/sd.c
> +++ b/drivers/mmc/core/sd.c
> @@ -451,9 +451,11 @@ static int sd_select_driver_type(struct mmc_card
> *card, u8 *status)
>  	 * information and let the hardware specific code
>  	 * return what is possible given the options
>  	 */
> +	mmc_host_clk_hold(card->host);
>  	drive_strength = card->host->ops->select_drive_strength(
>  		card->sw_caps.uhs_max_dtr,
>  		host_drv_type, card_drv_type);
> +	mmc_host_clk_release(card->host);
> 
>  	err = mmc_sd_switch(card, 1, 2, drive_strength, status);
>  	if (err)
> @@ -660,8 +662,11 @@ static int mmc_sd_init_uhs_card(struct mmc_card
> *card)
>  		goto out;
> 
>  	/* SPI mode doesn't define CMD19 */
> -	if (!mmc_host_is_spi(card->host) && card->host->ops-
> >execute_tuning)
> +	if (!mmc_host_is_spi(card->host) && card->host->ops-
> >execute_tuning) {
> +		mmc_host_clk_hold(card->host);
>  		err = card->host->ops->execute_tuning(card->host);
> +		mmc_host_clk_release(card->host);
> +	}
> 
>  out:
>  	kfree(status);
> @@ -849,8 +854,11 @@ int mmc_sd_setup_card(struct mmc_host *host,
> struct mmc_card *card,
>  	if (!reinit) {
>  		int ro = -1;
> 
> -		if (host->ops->get_ro)
> +		if (host->ops->get_ro) {
> +			mmc_host_clk_hold(host);
>  			ro = host->ops->get_ro(host);
> +			mmc_host_clk_release(host);
> +		}
> 
>  		if (ro < 0) {
>  			pr_warning("%s: host does not "
> @@ -966,8 +974,11 @@ static int mmc_sd_init_card(struct mmc_host *host,
> u32 ocr,
>  		 * Since initialization is now complete, enable preset
>  		 * value registers for UHS-I cards.
>  		 */
> -		if (host->ops->enable_preset_value)
> +		if (host->ops->enable_preset_value) {
> +			mmc_host_clk_hold(host);
>  			host->ops->enable_preset_value(host, true);
> +			mmc_host_clk_release(host);
> +		}
>  	} else {
>  		/*
>  		 * Attempt to change to high-speed (if supported)
> @@ -1150,8 +1161,11 @@ int mmc_attach_sd(struct mmc_host *host)
>  		return err;
> 
>  	/* Disable preset value enable if already set since last time */
> -	if (host->ops->enable_preset_value)
> +	if (host->ops->enable_preset_value) {
> +		mmc_host_clk_hold(host);
>  		host->ops->enable_preset_value(host, false);
> +		mmc_host_clk_release(host);
> +	}
> 
>  	err = mmc_send_app_op_cond(host, 0, &ocr);
>  	if (err)
> diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
> index b77f770..c9c2424 100644
> --- a/drivers/mmc/core/sdio.c
> +++ b/drivers/mmc/core/sdio.c
> @@ -438,9 +438,11 @@ static void sdio_select_driver_type(struct
> mmc_card *card)
>  	 * information and let the hardware specific code
>  	 * return what is possible given the options
>  	 */
> +	mmc_host_clk_hold(card->host);
>  	drive_strength = card->host->ops->select_drive_strength(
>  		card->sw_caps.uhs_max_dtr,
>  		host_drv_type, card_drv_type);
> +	mmc_host_clk_release(card->host);
> 
>  	/* if error just use default for drive strength B */
>  	err = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_DRIVE_STRENGTH, 0,
> @@ -555,8 +557,11 @@ static int mmc_sdio_init_uhs_card(struct mmc_card
> *card)
>  		goto out;
> 
>  	/* Initialize and start re-tuning timer */
> -	if (!mmc_host_is_spi(card->host) && card->host->ops-
> >execute_tuning)
> +	if (!mmc_host_is_spi(card->host) && card->host->ops-
> >execute_tuning) {
> +		mmc_host_clk_hold(card->host);
>  		err = card->host->ops->execute_tuning(card->host);
> +		mmc_host_clk_release(card->host);
> +	}
> 
>  out:
> 
> @@ -626,8 +631,11 @@ static int mmc_sdio_init_card(struct mmc_host
> *host, u32 ocr,
>  	/*
>  	 * Call the optional HC's init_card function to handle quirks.
>  	 */
> -	if (host->ops->init_card)
> +	if (host->ops->init_card) {
> +		mmc_host_clk_hold(host);
>  		host->ops->init_card(host, card);
> +		mmc_host_clk_release(host);
> +	}
> 
>  	/*
>  	 * If the host and card support UHS-I mode request the card
> diff --git a/drivers/mmc/core/sdio_irq.c b/drivers/mmc/core/sdio_irq.c
> index 68f81b9..f573e7f 100644
> --- a/drivers/mmc/core/sdio_irq.c
> +++ b/drivers/mmc/core/sdio_irq.c
> @@ -146,15 +146,21 @@ static int sdio_irq_thread(void *_host)
>  		}
> 
>  		set_current_state(TASK_INTERRUPTIBLE);
> -		if (host->caps & MMC_CAP_SDIO_IRQ)
> +		if (host->caps & MMC_CAP_SDIO_IRQ) {
> +			mmc_host_clk_hold(host);
>  			host->ops->enable_sdio_irq(host, 1);
> +			mmc_host_clk_release(host);
> +		}
>  		if (!kthread_should_stop())
>  			schedule_timeout(period);
>  		set_current_state(TASK_RUNNING);
>  	} while (!kthread_should_stop());
> 
> -	if (host->caps & MMC_CAP_SDIO_IRQ)
> +	if (host->caps & MMC_CAP_SDIO_IRQ) {
> +		mmc_host_clk_hold(host);
>  		host->ops->enable_sdio_irq(host, 0);
> +		mmc_host_clk_release(host);
> +	}
> 
>  	pr_debug("%s: IRQ thread exiting with code %d\n",
>  		 mmc_hostname(host), ret);
> diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
> index 9a03d03..aa2d7ee 100644
> --- a/include/linux/mmc/host.h
> +++ b/include/linux/mmc/host.h
> @@ -428,4 +428,23 @@ static inline int mmc_boot_partition_access(struct
> mmc_host *host)
>  	return !(host->caps2 & MMC_CAP2_BOOTPART_NOACC);
>  }
> 
> +#ifdef CONFIG_MMC_CLKGATE
> +void mmc_host_clk_hold(struct mmc_host *host);
> +void mmc_host_clk_release(struct mmc_host *host);
> +unsigned int mmc_host_clk_rate(struct mmc_host *host);
> +
> +#else
> +static inline void mmc_host_clk_hold(struct mmc_host *host)
> +{
> +}
> +
> +static inline void mmc_host_clk_release(struct mmc_host *host)
> +{
> +}
> +
> +static inline unsigned int mmc_host_clk_rate(struct mmc_host *host)
> +{
> +	return host->ios.clock;
> +}
> +#endif
>  #endif /* LINUX_MMC_HOST_H */
> --
> Sent by a consultant of the Qualcomm Innovation Center, Inc.
> The Qualcomm Innovation Center, Inc. is a member of the Code Aurora
> Forum.
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
> the body of a message to majordomo@xxxxxxxxxxxxxxx
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux USB Devel]     [Linux Media]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux