[PATCH] mmc: toshsd: Fix unbalanced locking

2014-12-10 Thread Axel Lin
Fix returning IRQ_HANDLED with spin_lock held.

Signed-off-by: Axel Lin 
---
 drivers/mmc/host/toshsd.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/mmc/host/toshsd.c b/drivers/mmc/host/toshsd.c
index 4666262..a5aa539 100644
--- a/drivers/mmc/host/toshsd.c
+++ b/drivers/mmc/host/toshsd.c
@@ -176,7 +176,8 @@ static irqreturn_t toshsd_thread_irq(int irq, void *dev_id)
spin_lock_irqsave(&host->lock, flags);
 
if (!sg_miter_next(sg_miter))
-   return IRQ_HANDLED;
+   goto done;
+
buf = sg_miter->addr;
 
/* Ensure we dont read more than one block. The chip will interrupt us
@@ -198,6 +199,7 @@ static irqreturn_t toshsd_thread_irq(int irq, void *dev_id)
sg_miter->consumed = count;
sg_miter_stop(sg_miter);
 
+done:
spin_unlock_irqrestore(&host->lock, flags);
 
return IRQ_HANDLED;
-- 
1.9.1



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


Re: [PATCH] mmc: sdhci: use pipeline mmc requests to improve performance

2014-12-10 Thread Dong Aisheng
On Tue, Dec 9, 2014 at 5:04 PM, Haibo Chen  wrote:
> This patch is based on the patches by Per Forlin, Tony Lin and Ryan QIAN.
>
> This patch complete the API 'post_req' and 'pre_req' in sdhci host side,
>
> Test Env:
> 1. i.MX6Q-SABREAUTO board, CPU @ 996MHz, use ADMA in uSDHC controller.
> 2. Test command:
> $ echo 1 > /proc/sys/vm/drop_caches
> write to sd card:
> $ dd if=/dev/zero of=/dev/mmcblk0 bs=1M count=2000 conv=fsync
> read the sd card:
> $ dd if=/dev/mmcblk0 of=/dev/null bs=1M count=2000
>
> 3. TOSHIBA 16GB SD3.0 card, running at 4 bit, SDR104 @ 198MHZ
> Performance with and without this patch:
>   -
>   || read speed | write speed |
>   |
>   | with this patch| ~76.7 MB/s |  ~23.3 MB/s |
>   |
>   |without this patch  | ~60.5 MB/s |  ~22.5 MB/s |
>   -
>
> 4. SanDisk 8GB SD3.0 card, running at 4 bit, DDR50 @ 50MHZ
> Performance with and without this patch:
>   -
>   || read speed | write speed |
>   |
>   | with this patch| ~40.5 MB/s |  ~15.6 MB/s |
>   |
>   |without this patch  | ~36.1 MB/s |  ~14.1 MB/s |
>   -
>
> 5. Kingston 8GB SD2.0 card, running at 4 bit, High-speed @ 50MHZ
> Performance with and without this patch:
>   -
>   || read speed | write speed |
>   |
>   | with this patch| ~22.7 MB/s |  ~8.2 MB/s  |
>   |
>   |without this patch  | ~21.3 MB/s |  ~8.0 MB/s  |
>   -
>
> 6. About eMMC, Sandisk 8GB eMMC on i.MX6DL-sabresd board, CPU @ 792MHZ,
>eMMC running at 8 bit, DDR52 @ 52MHZ.
> Performance with and without this patch:
>   -
>   || read speed | write speed |
>   |
>   | with this patch| ~37.3 MB/s |  ~10.5 MB/s |
>   |
>   |without this patch  | ~33.4 MB/s |  ~10.5 MB/s |
>   -
>
> Signed-off-by: Haibo Chen 

Can someone else test and see if can get the same performance improvement?

Regards
Dong Aisheng

> ---
>  drivers/mmc/host/sdhci.c  | 100 
> --
>  include/linux/mmc/sdhci.h |   6 +++
>  2 files changed, 94 insertions(+), 12 deletions(-)
>
> diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
> index ada1a3e..50f8a4f 100644
> --- a/drivers/mmc/host/sdhci.c
> +++ b/drivers/mmc/host/sdhci.c
> @@ -55,6 +55,9 @@ static void sdhci_finish_command(struct sdhci_host *);
>  static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode);
>  static void sdhci_tuning_timer(unsigned long data);
>  static void sdhci_enable_preset_value(struct sdhci_host *host, bool enable);
> +static int sdhci_pre_dma_transfer(struct sdhci_host *host,
> +  struct mmc_data *data,
> +  struct sdhci_host_next *next);
>
>  #ifdef CONFIG_PM_RUNTIME
>  static int sdhci_runtime_pm_get(struct sdhci_host *host);
> @@ -494,9 +497,8 @@ static int sdhci_adma_table_pre(struct sdhci_host *host,
> goto fail;
> BUG_ON(host->align_addr & 0x3);
>
> -   host->sg_count = dma_map_sg(mmc_dev(host->mmc),
> -   data->sg, data->sg_len, direction);
> -   if (host->sg_count == 0)
> +   host->sg_count = sdhci_pre_dma_transfer(host, data, NULL);
> +   if (host->sg_count < 0)
> goto unmap_align;
>
> desc = host->adma_desc;
> @@ -633,8 +635,9 @@ static void sdhci_adma_table_post(struct sdhci_host *host,
> }
> }
>
> -   dma_unmap_sg(mmc_dev(host->mmc), data->sg,
> -   data->sg_len, direction);
> +   if (!data->host_cookie)
> +   dma_unmap_sg(mmc_dev(host->mmc), data->sg,
> +   data->sg_len, direction);
>  }
>
>  static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command 
> *cmd)
> @@ -826,11 +829,7 @@ static void sdhci_prepare_data(struct sdhci_host *host, 
> struct mmc_command *cmd)
> } else {
> int sg_cnt;
>
> -   sg_cnt = dma_m

[PATCH 3/4] mmc: dw_mmc: Use mmc_regulator_set_vqmmc in start_signal_voltage_switch

2014-12-10 Thread Doug Anderson
We've introduced a new helper in the MMC core:
mmc_regulator_set_vqmmc().  Let's use this in dw_mmc.  Using this new
helper has some advantages:

1. We get the mmc_regulator_set_vqmmc() behavior of trying to match
   VQMMC and VMMC when the signal voltage is 3.3V.  This ensures max
   compatibility.

2. We get rid of a few more warnings when probing unsupported
   voltages.

3. We get rid of some non-dw_mmc specific code in dw_mmc.

Signed-off-by: Doug Anderson 
---
 drivers/mmc/host/dw_mmc.c | 17 +
 1 file changed, 1 insertion(+), 16 deletions(-)

diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index 67c0451..4ae800c 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -1160,8 +1160,6 @@ static int dw_mci_switch_voltage(struct mmc_host *mmc, 
struct mmc_ios *ios)
struct dw_mci *host = slot->host;
u32 uhs;
u32 v18 = SDMMC_UHS_18V << slot->id;
-   int min_uv, max_uv;
-   int ret;
 
/*
 * Program the voltage.  Note that some instances of dw_mmc may use
@@ -1170,24 +1168,11 @@ static int dw_mci_switch_voltage(struct mmc_host *mmc, 
struct mmc_ios *ios)
 */
uhs = mci_readl(host, UHS_REG);
if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
-   min_uv = 270;
-   max_uv = 360;
uhs &= ~v18;
} else {
-   min_uv = 170;
-   max_uv = 195;
uhs |= v18;
}
-   if (!IS_ERR(mmc->supply.vqmmc)) {
-   ret = regulator_set_voltage(mmc->supply.vqmmc, min_uv, max_uv);
-
-   if (ret) {
-   dev_dbg(&mmc->class_dev,
-"Regulator set error %d: %d - %d\n",
-ret, min_uv, max_uv);
-   return ret;
-   }
-   }
+   mmc_regulator_set_vqmmc(mmc, ios);
mci_writel(host, UHS_REG, uhs);
 
return 0;
-- 
2.2.0.rc0.207.ga3a616c

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


[PATCH 2/4] mmc: core: Add mmc_regulator_set_vqmmc()

2014-12-10 Thread Doug Anderson
This adds logic to the MMC core to set VQMMC.  This is expected to be
called by MMC drivers like dw_mmc as part of (or instead of) their
start_signal_voltage_switch() callback.

A few notes:

* When setting the signal voltage to 3.3V we do our best to make VQMMC
  and VMMC match.  It's been reported that this makes some old cards
  happy since they were tested back in the day before UHS when VQMMC
  and VMMC were provided by the same regulator.  A nice side effect of
  this is that we don't end up on the hairy edge of VQMMC (2.7V),
  which some EEs claim is a little too close to the minimum for
  comfort.

* When setting the signal voltage to 1.8V or 1.2V we aim for that
  specific voltage instead of picking the lowest one in the range.

* We very purposely don't print errors in mmc_regulator_set_vqmmc().
  There are cases where the MMC core will try several different
  voltages and we don't want to pollute the logs.

Signed-off-by: Doug Anderson 
---
 drivers/mmc/core/core.c  | 53 
 include/linux/mmc/host.h |  7 +++
 2 files changed, 60 insertions(+)

diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 9584bff..d0da480 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -1333,6 +1333,59 @@ int mmc_regulator_set_ocr(struct mmc_host *mmc,
 }
 EXPORT_SYMBOL_GPL(mmc_regulator_set_ocr);
 
+static int mmc_regulator_set_voltage_if_supported(struct regulator *regulator,
+ int min_uV, int ideal_uV,
+ int max_uV)
+{
+   /*
+* Check if supported first to avoid errors since we may try several
+* signal levels during power up and don't want to show errors.
+*/
+   if (!regulator_is_supported_voltage(regulator, min_uV, max_uV))
+   return -EINVAL;
+
+   return regulator_set_closest_voltage(regulator, min_uV, ideal_uV,
+max_uV);
+}
+
+/**
+ * mmc_regulator_set_vqmmc - Set VQMMC as per the ios
+ *
+ * For 3.3V signaling, we try to match vqmmc to vmmc as closely as possible.
+ * That will match the behavior of old boards where vqmmc and vmmc were 
supplied
+ * by the same supply.
+ *
+ * For 1.2V and 1.8V signaling we'll try to get as close as possible to the
+ * requested voltage.  This is definitely a good idea for UHS where there's a
+ * separate regulator on the card that's trying to make 1.8V and it's best if
+ * we match.
+ *
+ * This function is expected to be used by a controller's
+ * start_signal_voltage_switch() function.
+ */
+int mmc_regulator_set_vqmmc(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+   /* If no vqmmc supply then we can't change the voltage */
+   if (IS_ERR(mmc->supply.vqmmc))
+   return -EINVAL;
+
+   switch (ios->signal_voltage) {
+   case MMC_SIGNAL_VOLTAGE_120:
+   return mmc_regulator_set_voltage_if_supported(
+   mmc->supply.vqmmc, 110, 120, 130);
+   case MMC_SIGNAL_VOLTAGE_180:
+   return mmc_regulator_set_voltage_if_supported(
+   mmc->supply.vqmmc, 170, 180, 195);
+   case MMC_SIGNAL_VOLTAGE_330:
+   return mmc_regulator_set_voltage_if_supported(
+   mmc->supply.vqmmc, 270,
+   regulator_get_voltage(mmc->supply.vmmc), 360);
+   default:
+   return -EINVAL;
+   }
+}
+EXPORT_SYMBOL_GPL(mmc_regulator_set_vqmmc);
+
 #endif /* CONFIG_REGULATOR */
 
 int mmc_regulator_get_supply(struct mmc_host *mmc)
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 9f32270..524d6fc 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -416,6 +416,7 @@ int mmc_regulator_get_ocrmask(struct regulator *supply);
 int mmc_regulator_set_ocr(struct mmc_host *mmc,
struct regulator *supply,
unsigned short vdd_bit);
+int mmc_regulator_set_vqmmc(struct mmc_host *mmc, struct mmc_ios *ios);
 #else
 static inline int mmc_regulator_get_ocrmask(struct regulator *supply)
 {
@@ -428,6 +429,12 @@ static inline int mmc_regulator_set_ocr(struct mmc_host 
*mmc,
 {
return 0;
 }
+
+static inline int mmc_regulator_set_vqmmc(struct mmc_host *mmc,
+ struct mmc_ios *ios)
+{
+   return -EINVAL;
+}
 #endif
 
 int mmc_regulator_get_supply(struct mmc_host *mmc);
-- 
2.2.0.rc0.207.ga3a616c

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