From ac00531d9f4be487366573e2bb943e68e9e523ab Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 5 Dec 2014 19:25:28 +0200 Subject: mmc: sdhci: Tuning should not change max_blk_count Re-tuning requires that the maximum data length is limited to 4MiB. The code currently changes max_blk_count in an attempt to achieve that. This is wrong because max_blk_count is a different limit, but it is also un-necessary because max_req_size is 512KiB anyway. Consequently, the changes to max_blk_count are removed and the comment for max_req_size adjusted accordingly. The comment is also tweaked to show that the 512KiB limit is a SDMA limit not an ADMA limit. Signed-off-by: Adrian Hunter Reviewed-by: Aaron Lu Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'drivers/mmc/host/sdhci.c') diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index cbb245b5853..040158d4fc9 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -259,8 +259,6 @@ static void sdhci_reinit(struct sdhci_host *host) del_timer_sync(&host->tuning_timer); host->flags &= ~SDHCI_NEEDS_RETUNING; - host->mmc->max_blk_count = - (host->quirks & SDHCI_QUIRK_NO_MULTIBLOCK) ? 1 : 65535; } sdhci_enable_card_detection(host); } @@ -2048,8 +2046,6 @@ out: host->flags |= SDHCI_USING_RETUNING_TIMER; mod_timer(&host->tuning_timer, jiffies + host->tuning_count * HZ); - /* Tuning mode 1 limits the maximum data length to 4MB */ - mmc->max_blk_count = (4 * 1024 * 1024) / mmc->max_blk_size; } else if (host->flags & SDHCI_USING_RETUNING_TIMER) { host->flags &= ~SDHCI_NEEDS_RETUNING; /* Reload the new initial value for timer */ @@ -3260,8 +3256,9 @@ int sdhci_add_host(struct sdhci_host *host) mmc->max_segs = SDHCI_MAX_SEGS; /* - * Maximum number of sectors in one transfer. Limited by DMA boundary - * size (512KiB). + * Maximum number of sectors in one transfer. Limited by SDMA boundary + * size (512KiB). Note some tuning modes impose a 4MiB limit, but this + * is less anyway. */ mmc->max_req_size = 524288; -- cgit v1.2.3-70-g09d2 From d519c863fc198f43c979e9d6a74b53d9c53d55aa Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 5 Dec 2014 19:25:29 +0200 Subject: mmc: sdhci: Add out_unlock to sdhci_execute_tuning A 'goto' can be used to save duplicating unlocking and returning. Signed-off-by: Adrian Hunter Reviewed-by: Aaron Lu Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/mmc/host/sdhci.c') diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 040158d4fc9..c45beaff1ab 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -1909,9 +1909,7 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode) /* FALLTHROUGH */ default: - spin_unlock_irqrestore(&host->lock, flags); - sdhci_runtime_pm_put(host); - return 0; + goto out_unlock; } if (host->ops->platform_execute_tuning) { @@ -2066,6 +2064,7 @@ out: sdhci_writel(host, host->ier, SDHCI_INT_ENABLE); sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); +out_unlock: spin_unlock_irqrestore(&host->lock, flags); sdhci_runtime_pm_put(host); -- cgit v1.2.3-70-g09d2 From 38e40bf5db9d5b8cbaeca9a78ee17f38473dd78d Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 5 Dec 2014 19:25:30 +0200 Subject: mmc: sdhci: Simplify use of tuning timer The tuning timer is always used if the tuning mode is 1 and there is a tuning count, irrespective of whether this is the first call, or any subsequent call. Consequently the logic to start the timer can be simplified. Signed-off-by: Adrian Hunter Reviewed-by: Aaron Lu Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci.c | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) (limited to 'drivers/mmc/host/sdhci.c') diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index c45beaff1ab..5c28c19622e 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -1885,10 +1885,14 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode) int tuning_loop_counter = MAX_TUNING_LOOP; int err = 0; unsigned long flags; + unsigned int tuning_count = 0; sdhci_runtime_pm_get(host); spin_lock_irqsave(&host->lock, flags); + if (host->tuning_mode == SDHCI_TUNING_MODE_1) + tuning_count = host->tuning_count; + /* * The Host Controller needs tuning only in case of SDR104 mode * and for SDR50 mode when Use Tuning for SDR50 is set in the @@ -2033,22 +2037,11 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode) } out: - /* - * If this is the very first time we are here, we start the retuning - * timer. Since only during the first time, SDHCI_NEEDS_RETUNING - * flag won't be set, we check this condition before actually starting - * the timer. - */ - if (!(host->flags & SDHCI_NEEDS_RETUNING) && host->tuning_count && - (host->tuning_mode == SDHCI_TUNING_MODE_1)) { + host->flags &= ~SDHCI_NEEDS_RETUNING; + + if (tuning_count) { host->flags |= SDHCI_USING_RETUNING_TIMER; - mod_timer(&host->tuning_timer, jiffies + - host->tuning_count * HZ); - } else if (host->flags & SDHCI_USING_RETUNING_TIMER) { - host->flags &= ~SDHCI_NEEDS_RETUNING; - /* Reload the new initial value for timer */ - mod_timer(&host->tuning_timer, jiffies + - host->tuning_count * HZ); + mod_timer(&host->tuning_timer, jiffies + tuning_count * HZ); } /* -- cgit v1.2.3-70-g09d2 From b5540ce1512eede3bed68ab1e9949df9ad556091 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 5 Dec 2014 19:25:31 +0200 Subject: mmc: sdhci: Disable re-tuning for HS400 Re-tuning for HS400 mode must be done in HS200 mode. Currently there is no support for that. That needs to be reflected in the code. Specifically, if tuning is executed in HS400 mode then return an error, and do not start the tuning timer if HS200 tuning is being done prior to switching to HS400. Note that periodic re-tuning is not expected to be needed for HS400 but re-tuning is still needed after the host controller has lost power. In the case of suspend/resume that is not necessary because the card is fully re-initialised. That just leaves runtime suspend/resume with no support for HS400 re-tuning. Signed-off-by: Adrian Hunter Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci.c | 29 +++++++++++++++++++++++++++++ include/linux/mmc/sdhci.h | 1 + 2 files changed, 30 insertions(+) (limited to 'drivers/mmc/host/sdhci.c') diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 5c28c19622e..398e9e49673 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -1878,6 +1878,18 @@ static int sdhci_card_busy(struct mmc_host *mmc) return !(present_state & SDHCI_DATA_LVL_MASK); } +static int sdhci_prepare_hs400_tuning(struct mmc_host *mmc, struct mmc_ios *ios) +{ + struct sdhci_host *host = mmc_priv(mmc); + unsigned long flags; + + spin_lock_irqsave(&host->lock, flags); + host->flags |= SDHCI_HS400_TUNING; + spin_unlock_irqrestore(&host->lock, flags); + + return 0; +} + static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode) { struct sdhci_host *host = mmc_priv(mmc); @@ -1886,10 +1898,14 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode) int err = 0; unsigned long flags; unsigned int tuning_count = 0; + bool hs400_tuning; sdhci_runtime_pm_get(host); spin_lock_irqsave(&host->lock, flags); + hs400_tuning = host->flags & SDHCI_HS400_TUNING; + host->flags &= ~SDHCI_HS400_TUNING; + if (host->tuning_mode == SDHCI_TUNING_MODE_1) tuning_count = host->tuning_count; @@ -1901,8 +1917,20 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode) * tuning function has to be executed. */ switch (host->timing) { + /* HS400 tuning is done in HS200 mode */ case MMC_TIMING_MMC_HS400: + err = -EINVAL; + goto out_unlock; + case MMC_TIMING_MMC_HS200: + /* + * Periodic re-tuning for HS400 is not expected to be needed, so + * disable it here. + */ + if (hs400_tuning) + tuning_count = 0; + break; + case MMC_TIMING_UHS_SDR104: break; @@ -2130,6 +2158,7 @@ static const struct mmc_host_ops sdhci_ops = { .hw_reset = sdhci_hw_reset, .enable_sdio_irq = sdhci_enable_sdio_irq, .start_signal_voltage_switch = sdhci_start_signal_voltage_switch, + .prepare_hs400_tuning = sdhci_prepare_hs400_tuning, .execute_tuning = sdhci_execute_tuning, .card_event = sdhci_card_event, .card_busy = sdhci_card_busy, diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h index 375af80bde7..f767a0de611 100644 --- a/include/linux/mmc/sdhci.h +++ b/include/linux/mmc/sdhci.h @@ -137,6 +137,7 @@ struct sdhci_host { #define SDHCI_SDR104_NEEDS_TUNING (1<<10) /* SDR104/HS200 needs tuning */ #define SDHCI_USING_RETUNING_TIMER (1<<11) /* Host is using a retuning timer for the card */ #define SDHCI_USE_64_BIT_DMA (1<<12) /* Use 64-bit DMA */ +#define SDHCI_HS400_TUNING (1<<13) /* Tuning for HS400 */ unsigned int version; /* SDHCI spec. version */ -- cgit v1.2.3-70-g09d2 From 2836766a9d0bd02c66073f8dd44796e6cc23848d Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 5 Jan 2015 10:50:15 +0100 Subject: mmc: sdhci: Fix sleep in atomic after inserting SD card Sleep in atomic context happened on Trats2 board after inserting or removing SD card because mmc_gpio_get_cd() was called under spin lock. Fix this by moving card detection earlier, before acquiring spin lock. The mmc_gpio_get_cd() call does not have to be protected by spin lock because it does not access any sdhci internal data. The sdhci_do_get_cd() call access host flags (SDHCI_DEVICE_DEAD). After moving it out side of spin lock it could theoretically race with driver removal but still there is no actual protection against manual card eject. Dmesg after inserting SD card: [ 41.663414] BUG: sleeping function called from invalid context at drivers/gpio/gpiolib.c:1511 [ 41.670469] in_atomic(): 1, irqs_disabled(): 128, pid: 30, name: kworker/u8:1 [ 41.677580] INFO: lockdep is turned off. [ 41.681486] irq event stamp: 61972 [ 41.684872] hardirqs last enabled at (61971): [] _raw_spin_unlock_irq+0x24/0x5c [ 41.693118] hardirqs last disabled at (61972): [] _raw_spin_lock_irq+0x18/0x54 [ 41.701190] softirqs last enabled at (61648): [] __do_softirq+0x234/0x2c8 [ 41.708914] softirqs last disabled at (61631): [] irq_exit+0xd0/0x114 [ 41.716206] Preemption disabled at:[< (null)>] (null) [ 41.721500] [ 41.722985] CPU: 3 PID: 30 Comm: kworker/u8:1 Tainted: G W 3.18.0-rc5-next-20141121 #883 [ 41.732111] Workqueue: kmmcd mmc_rescan [ 41.735945] [] (unwind_backtrace) from [] (show_stack+0x10/0x14) [ 41.743661] [] (show_stack) from [] (dump_stack+0x70/0xbc) [ 41.750867] [] (dump_stack) from [] (gpiod_get_raw_value_cansleep+0x18/0x30) [ 41.759628] [] (gpiod_get_raw_value_cansleep) from [] (mmc_gpio_get_cd+0x38/0x58) [ 41.768821] [] (mmc_gpio_get_cd) from [] (sdhci_request+0x50/0x1a4) [ 41.776808] [] (sdhci_request) from [] (mmc_start_request+0x138/0x268) [ 41.785051] [] (mmc_start_request) from [] (mmc_wait_for_req+0x58/0x1a0) [ 41.793469] [] (mmc_wait_for_req) from [] (mmc_wait_for_cmd+0x58/0x78) [ 41.801714] [] (mmc_wait_for_cmd) from [] (mmc_io_rw_direct_host+0x98/0x124) [ 41.810480] [] (mmc_io_rw_direct_host) from [] (sdio_reset+0x2c/0x64) [ 41.818641] [] (sdio_reset) from [] (mmc_rescan+0x254/0x2e4) [ 41.826028] [] (mmc_rescan) from [] (process_one_work+0x180/0x3f4) [ 41.833920] [] (process_one_work) from [] (worker_thread+0x34/0x4b0) [ 41.841991] [] (worker_thread) from [] (kthread+0xe4/0x104) [ 41.849285] [] (kthread) from [] (ret_from_fork+0x14/0x2c) [ 42.038276] mmc0: new high speed SDHC card at address 1234 Signed-off-by: Krzysztof Kozlowski Fixes: 94144a465dd0 ("mmc: sdhci: add get_cd() implementation") Cc: Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers/mmc/host/sdhci.c') diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 398e9e49673..1453cd12792 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -1351,6 +1351,8 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq) sdhci_runtime_pm_get(host); + present = mmc_gpio_get_cd(host->mmc); + spin_lock_irqsave(&host->lock, flags); WARN_ON(host->mrq != NULL); @@ -1379,7 +1381,6 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq) * zero: cd-gpio is used, and card is removed * one: cd-gpio is used, and card is present */ - present = mmc_gpio_get_cd(host->mmc); if (present < 0) { /* If polling, assume that the card is always present. */ if (host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) @@ -2126,15 +2127,18 @@ static void sdhci_card_event(struct mmc_host *mmc) { struct sdhci_host *host = mmc_priv(mmc); unsigned long flags; + int present; /* First check if client has provided their own card event */ if (host->ops->card_event) host->ops->card_event(host); + present = sdhci_do_get_cd(host); + spin_lock_irqsave(&host->lock, flags); /* Check host->mrq first in case we are runtime suspended */ - if (host->mrq && !sdhci_do_get_cd(host)) { + if (host->mrq && !present) { pr_err("%s: Card removed during transfer!\n", mmc_hostname(host->mmc)); pr_err("%s: Resetting controller.\n", -- cgit v1.2.3-70-g09d2 From 3cbc6123a93dc91b99b58f7ea37d267fe93e1cad Mon Sep 17 00:00:00 2001 From: Tim Kryger Date: Wed, 14 Jan 2015 07:24:12 +0100 Subject: mmc: sdhci: Set SDHCI_POWER_ON with external vmmc Host controllers lacking the required internal vmmc regulator may still follow the spec with regard to the LSB of SDHCI_POWER_CONTROL. Set the SDHCI_POWER_ON bit when vmmc is enabled to encourage the controller to to drive CMD, DAT, SDCLK. This fixes a regression observed on some Qualcomm and Nvidia boards caused by 5222161 mmc: sdhci: Improve external VDD regulator support. Fixes: 52221610dd84 (mmc: sdhci: Improve external VDD regulator support) Signed-off-by: Tim Kryger Tested-by: Bjorn Andersson Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/mmc/host/sdhci.c') diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 1453cd12792..f1a488ee432 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -1271,6 +1271,12 @@ static void sdhci_set_power(struct sdhci_host *host, unsigned char mode, spin_unlock_irq(&host->lock); mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, vdd); spin_lock_irq(&host->lock); + + if (mode != MMC_POWER_OFF) + sdhci_writeb(host, SDHCI_POWER_ON, SDHCI_POWER_CONTROL); + else + sdhci_writeb(host, 0, SDHCI_POWER_CONTROL); + return; } -- cgit v1.2.3-70-g09d2