From 4e262d7f6fd43d798175cf26223c5bd3ebfd7b13 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Wed, 23 Oct 2013 14:51:31 +0200 Subject: mmc: sh_mobile_sdhi: Use modern PM macros to define pm callbacks Signed-off-by: Ulf Hansson Acked-by: Guennadi Liakhovetski Signed-off-by: Chris Ball --- drivers/mmc/host/sh_mobile_sdhi.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/mmc/host/sh_mobile_sdhi.c b/drivers/mmc/host/sh_mobile_sdhi.c index 2d6ce257a273..03fe7518bba4 100644 --- a/drivers/mmc/host/sh_mobile_sdhi.c +++ b/drivers/mmc/host/sh_mobile_sdhi.c @@ -316,10 +316,10 @@ static int sh_mobile_sdhi_remove(struct platform_device *pdev) } static const struct dev_pm_ops tmio_mmc_dev_pm_ops = { - .suspend = tmio_mmc_host_suspend, - .resume = tmio_mmc_host_resume, - .runtime_suspend = tmio_mmc_host_runtime_suspend, - .runtime_resume = tmio_mmc_host_runtime_resume, + SET_SYSTEM_SLEEP_PM_OPS(tmio_mmc_host_suspend, tmio_mmc_host_resume) + SET_RUNTIME_PM_OPS(tmio_mmc_host_runtime_suspend, + tmio_mmc_host_runtime_resume, + NULL) }; static struct platform_driver sh_mobile_sdhi_driver = { -- cgit v1.2.3 From c8964481d0273ef77a37ed2c627482fde3a1222c Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Wed, 23 Oct 2013 14:57:50 +0200 Subject: mmc: tmio_mmc: Convert from legacy to modern PM ops Signed-off-by: Ulf Hansson Acked-by: Guennadi Liakhovetski Signed-off-by: Chris Ball --- drivers/mmc/host/tmio_mmc.c | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/drivers/mmc/host/tmio_mmc.c b/drivers/mmc/host/tmio_mmc.c index 1900abb04236..cfad844730d8 100644 --- a/drivers/mmc/host/tmio_mmc.c +++ b/drivers/mmc/host/tmio_mmc.c @@ -23,38 +23,37 @@ #include "tmio_mmc.h" -#ifdef CONFIG_PM -static int tmio_mmc_suspend(struct platform_device *dev, pm_message_t state) +#ifdef CONFIG_PM_SLEEP +static int tmio_mmc_suspend(struct device *dev) { - const struct mfd_cell *cell = mfd_get_cell(dev); + struct platform_device *pdev = to_platform_device(dev); + const struct mfd_cell *cell = mfd_get_cell(pdev); int ret; - ret = tmio_mmc_host_suspend(&dev->dev); + ret = tmio_mmc_host_suspend(dev); /* Tell MFD core it can disable us now.*/ if (!ret && cell->disable) - cell->disable(dev); + cell->disable(pdev); return ret; } -static int tmio_mmc_resume(struct platform_device *dev) +static int tmio_mmc_resume(struct device *dev) { - const struct mfd_cell *cell = mfd_get_cell(dev); + struct platform_device *pdev = to_platform_device(dev); + const struct mfd_cell *cell = mfd_get_cell(pdev); int ret = 0; /* Tell the MFD core we are ready to be enabled */ if (cell->resume) - ret = cell->resume(dev); + ret = cell->resume(pdev); if (!ret) - ret = tmio_mmc_host_resume(&dev->dev); + ret = tmio_mmc_host_resume(dev); return ret; } -#else -#define tmio_mmc_suspend NULL -#define tmio_mmc_resume NULL #endif static int tmio_mmc_probe(struct platform_device *pdev) @@ -134,15 +133,18 @@ static int tmio_mmc_remove(struct platform_device *pdev) /* ------------------- device registration ----------------------- */ +static const struct dev_pm_ops tmio_mmc_dev_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(tmio_mmc_suspend, tmio_mmc_resume) +}; + static struct platform_driver tmio_mmc_driver = { .driver = { .name = "tmio-mmc", .owner = THIS_MODULE, + .pm = &tmio_mmc_dev_pm_ops, }, .probe = tmio_mmc_probe, .remove = tmio_mmc_remove, - .suspend = tmio_mmc_suspend, - .resume = tmio_mmc_resume, }; module_platform_driver(tmio_mmc_driver); -- cgit v1.2.3 From 710dec95d579bf59c157358cc9cf7b42907d1c0f Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Wed, 23 Oct 2013 14:55:07 +0200 Subject: mmc: tmio: Adapt to proper PM configs for exported functions Since the users of the exported PM functions are now using the modern PM ops macros, we can convert to the proper corresponding PM configs. Signed-off-by: Ulf Hansson Acked-by: Guennadi Liakhovetski Signed-off-by: Chris Ball --- drivers/mmc/host/tmio_mmc.h | 7 +++---- drivers/mmc/host/tmio_mmc_pio.c | 7 ++++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h index aaa9c7e9e730..100ffe0b2faf 100644 --- a/drivers/mmc/host/tmio_mmc.h +++ b/drivers/mmc/host/tmio_mmc.h @@ -162,16 +162,15 @@ static inline void tmio_mmc_abort_dma(struct tmio_mmc_host *host) } #endif -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP int tmio_mmc_host_suspend(struct device *dev); int tmio_mmc_host_resume(struct device *dev); -#else -#define tmio_mmc_host_suspend NULL -#define tmio_mmc_host_resume NULL #endif +#ifdef CONFIG_PM_RUNTIME int tmio_mmc_host_runtime_suspend(struct device *dev); int tmio_mmc_host_runtime_resume(struct device *dev); +#endif static inline u16 sd_ctrl_read16(struct tmio_mmc_host *host, int addr) { diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c index 8d8abf23a611..faf0924e71cb 100644 --- a/drivers/mmc/host/tmio_mmc_pio.c +++ b/drivers/mmc/host/tmio_mmc_pio.c @@ -1142,7 +1142,7 @@ void tmio_mmc_host_remove(struct tmio_mmc_host *host) } EXPORT_SYMBOL(tmio_mmc_host_remove); -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP int tmio_mmc_host_suspend(struct device *dev) { struct mmc_host *mmc = dev_get_drvdata(dev); @@ -1165,9 +1165,9 @@ int tmio_mmc_host_resume(struct device *dev) return 0; } EXPORT_SYMBOL(tmio_mmc_host_resume); +#endif -#endif /* CONFIG_PM */ - +#ifdef CONFIG_PM_RUNTIME int tmio_mmc_host_runtime_suspend(struct device *dev) { return 0; @@ -1184,5 +1184,6 @@ int tmio_mmc_host_runtime_resume(struct device *dev) return 0; } EXPORT_SYMBOL(tmio_mmc_host_runtime_resume); +#endif MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 2501c9179dff2add6aadd3898cd729e94e777d3a Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Wed, 30 Oct 2013 01:00:18 +0100 Subject: mmc: core: Use MMC_UNSAFE_RESUME as default behavior Invoking system suspend or shutdown without using the Kconfig option MMC_UNSAFE_RESUME, did trigger an ungraceful power cut of the card. To improve the situation, change the behavior to always make use of the available bus_ops callbacks that handles system suspend and shutdown properly. By changing the behavior MMC_UNSAFE_RESUME becomes redundant, so lets's remove it. Signed-off-by: Ulf Hansson Signed-off-by: Chris Ball --- drivers/mmc/core/Kconfig | 15 --------------- drivers/mmc/core/core.c | 17 ----------------- drivers/mmc/core/mmc.c | 23 +---------------------- drivers/mmc/core/sd.c | 23 +---------------------- include/linux/mmc/host.h | 5 +---- 5 files changed, 3 insertions(+), 80 deletions(-) diff --git a/drivers/mmc/core/Kconfig b/drivers/mmc/core/Kconfig index 269d072ef55e..9ebee72d9c3f 100644 --- a/drivers/mmc/core/Kconfig +++ b/drivers/mmc/core/Kconfig @@ -2,21 +2,6 @@ # MMC core configuration # -config MMC_UNSAFE_RESUME - bool "Assume MMC/SD cards are non-removable (DANGEROUS)" - help - If you say Y here, the MMC layer will assume that all cards - stayed in their respective slots during the suspend. The - normal behaviour is to remove them at suspend and - redetecting them at resume. Breaking this assumption will - in most cases result in data corruption. - - This option is usually just for embedded systems which use - a MMC/SD card for rootfs. Most people should say N here. - - This option sets a default which can be overridden by the - module parameter "removable=0" or "removable=1". - config MMC_CLKGATE bool "MMC host clock gating" help diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 098374b1ab2b..10856ec64412 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -64,23 +64,6 @@ static const unsigned freqs[] = { 400000, 300000, 200000, 100000 }; bool use_spi_crc = 1; module_param(use_spi_crc, bool, 0); -/* - * We normally treat cards as removed during suspend if they are not - * known to be on a non-removable bus, to avoid the risk of writing - * back data to a different card after resume. Allow this to be - * overridden if necessary. - */ -#ifdef CONFIG_MMC_UNSAFE_RESUME -bool mmc_assume_removable; -#else -bool mmc_assume_removable = 1; -#endif -EXPORT_SYMBOL(mmc_assume_removable); -module_param_named(removable, mmc_assume_removable, bool, 0644); -MODULE_PARM_DESC( - removable, - "MMC/SD cards are removable and may be removed during suspend"); - /* * Internal function. Schedule delayed work in the MMC work queue. */ diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 98e9eb0f6643..20f046895228 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -1634,16 +1634,6 @@ static int mmc_power_restore(struct mmc_host *host) } static const struct mmc_bus_ops mmc_ops = { - .remove = mmc_remove, - .detect = mmc_detect, - .suspend = NULL, - .resume = NULL, - .power_restore = mmc_power_restore, - .alive = mmc_alive, - .shutdown = mmc_shutdown, -}; - -static const struct mmc_bus_ops mmc_ops_unsafe = { .remove = mmc_remove, .detect = mmc_detect, .suspend = mmc_suspend, @@ -1655,17 +1645,6 @@ static const struct mmc_bus_ops mmc_ops_unsafe = { .shutdown = mmc_shutdown, }; -static void mmc_attach_bus_ops(struct mmc_host *host) -{ - const struct mmc_bus_ops *bus_ops; - - if (!mmc_card_is_removable(host)) - bus_ops = &mmc_ops_unsafe; - else - bus_ops = &mmc_ops; - mmc_attach_bus(host, bus_ops); -} - /* * Starting point for MMC card init. */ @@ -1685,7 +1664,7 @@ int mmc_attach_mmc(struct mmc_host *host) if (err) return err; - mmc_attach_bus_ops(host); + mmc_attach_bus(host, &mmc_ops); if (host->ocr_avail_mmc) host->ocr_avail = host->ocr_avail_mmc; diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index 692fdb177294..2dd359d2242f 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -1207,16 +1207,6 @@ static int mmc_sd_power_restore(struct mmc_host *host) } static const struct mmc_bus_ops mmc_sd_ops = { - .remove = mmc_sd_remove, - .detect = mmc_sd_detect, - .suspend = NULL, - .resume = NULL, - .power_restore = mmc_sd_power_restore, - .alive = mmc_sd_alive, - .shutdown = mmc_sd_suspend, -}; - -static const struct mmc_bus_ops mmc_sd_ops_unsafe = { .remove = mmc_sd_remove, .detect = mmc_sd_detect, .runtime_suspend = mmc_sd_runtime_suspend, @@ -1228,17 +1218,6 @@ static const struct mmc_bus_ops mmc_sd_ops_unsafe = { .shutdown = mmc_sd_suspend, }; -static void mmc_sd_attach_bus_ops(struct mmc_host *host) -{ - const struct mmc_bus_ops *bus_ops; - - if (!mmc_card_is_removable(host)) - bus_ops = &mmc_sd_ops_unsafe; - else - bus_ops = &mmc_sd_ops; - mmc_attach_bus(host, bus_ops); -} - /* * Starting point for SD card init. */ @@ -1254,7 +1233,7 @@ int mmc_attach_sd(struct mmc_host *host) if (err) return err; - mmc_sd_attach_bus_ops(host); + mmc_attach_bus(host, &mmc_sd_ops); if (host->ocr_avail_sd) host->ocr_avail = host->ocr_avail_sd; diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index 99f5709ac343..2a139b2bdb9e 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -424,12 +424,9 @@ static inline int mmc_regulator_get_supply(struct mmc_host *mmc) int mmc_pm_notify(struct notifier_block *notify_block, unsigned long, void *); -/* Module parameter */ -extern bool mmc_assume_removable; - static inline int mmc_card_is_removable(struct mmc_host *host) { - return !(host->caps & MMC_CAP_NONREMOVABLE) && mmc_assume_removable; + return !(host->caps & MMC_CAP_NONREMOVABLE); } static inline int mmc_card_keep_power(struct mmc_host *host) -- cgit v1.2.3 From 5601aaf73e5c2f0aa5e3607fee7b7d3511edfea9 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Wed, 30 Oct 2013 23:15:30 +0100 Subject: mmc: core: Remove unnecessary validations for bus_ops callbacks Due to the removal of the Kconfig option MMC_UNSAFE_RESUME, several validations of a present bus_ops callback became redundant. Let's remove these. Signed-off-by: Ulf Hansson Signed-off-by: Chris Ball --- drivers/mmc/core/bus.c | 12 ++---------- drivers/mmc/core/core.c | 13 +++++-------- 2 files changed, 7 insertions(+), 18 deletions(-) diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c index 64145a32b917..824644875d41 100644 --- a/drivers/mmc/core/bus.c +++ b/drivers/mmc/core/bus.c @@ -185,24 +185,16 @@ static int mmc_runtime_suspend(struct device *dev) { struct mmc_card *card = mmc_dev_to_card(dev); struct mmc_host *host = card->host; - int ret = 0; - if (host->bus_ops->runtime_suspend) - ret = host->bus_ops->runtime_suspend(host); - - return ret; + return host->bus_ops->runtime_suspend(host); } static int mmc_runtime_resume(struct device *dev) { struct mmc_card *card = mmc_dev_to_card(dev); struct mmc_host *host = card->host; - int ret = 0; - if (host->bus_ops->runtime_resume) - ret = host->bus_ops->runtime_resume(host); - - return ret; + return host->bus_ops->runtime_resume(host); } static int mmc_runtime_idle(struct device *dev) diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 10856ec64412..22427c684b36 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -2231,9 +2231,6 @@ static int mmc_do_hw_reset(struct mmc_host *host, int check) { struct mmc_card *card = host->card; - if (!host->bus_ops->power_restore) - return -EOPNOTSUPP; - if (!(host->caps & MMC_CAP_HW_RESET) || !host->ops->hw_reset) return -EOPNOTSUPP; @@ -2335,7 +2332,7 @@ int _mmc_detect_card_removed(struct mmc_host *host) { int ret; - if ((host->caps & MMC_CAP_NONREMOVABLE) || !host->bus_ops->alive) + if (host->caps & MMC_CAP_NONREMOVABLE) return 0; if (!host->card || mmc_card_removed(host->card)) @@ -2418,7 +2415,7 @@ void mmc_rescan(struct work_struct *work) * if there is a _removable_ card registered, check whether it is * still present */ - if (host->bus_ops && host->bus_ops->detect && !host->bus_dead + if (host->bus_ops && !host->bus_dead && !(host->caps & MMC_CAP_NONREMOVABLE)) host->bus_ops->detect(host); @@ -2520,7 +2517,7 @@ int mmc_power_save_host(struct mmc_host *host) mmc_bus_get(host); - if (!host->bus_ops || host->bus_dead || !host->bus_ops->power_restore) { + if (!host->bus_ops || host->bus_dead) { mmc_bus_put(host); return -EINVAL; } @@ -2546,7 +2543,7 @@ int mmc_power_restore_host(struct mmc_host *host) mmc_bus_get(host); - if (!host->bus_ops || host->bus_dead || !host->bus_ops->power_restore) { + if (!host->bus_ops || host->bus_dead) { mmc_bus_put(host); return -EINVAL; } @@ -2651,7 +2648,7 @@ int mmc_pm_notify(struct notifier_block *notify_block, /* Validate prerequisites for suspend */ if (host->bus_ops->pre_suspend) err = host->bus_ops->pre_suspend(host); - if (!err && host->bus_ops->suspend) + if (!err) break; /* Calling bus_ops->remove() with a claimed host can deadlock */ -- cgit v1.2.3 From a2d1086de6cc3ae2378d9db8b92712911c9e5fef Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Mon, 16 Dec 2013 14:37:26 +0100 Subject: mmc: card: Remove host cap MMC_CAP2_SANITIZE There is no need for keeping a host cap for MMC_CAP2_SANITIZE, instead we just make the feature default available. Signed-off-by: Ulf Hansson Signed-off-by: Chris Ball --- drivers/mmc/card/block.c | 3 +-- include/linux/mmc/host.h | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index 7b5424f398ac..c2187d5e9070 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -415,8 +415,7 @@ static int ioctl_do_sanitize(struct mmc_card *card) { int err; - if (!(mmc_can_sanitize(card) && - (card->host->caps2 & MMC_CAP2_SANITIZE))) { + if (!mmc_can_sanitize(card)) { pr_warn("%s: %s - SANITIZE is not supported\n", mmc_hostname(card->host), __func__); err = -EOPNOTSUPP; diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index 2a139b2bdb9e..40f832e5db40 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -281,7 +281,6 @@ struct mmc_host { #define MMC_CAP2_PACKED_CMD (MMC_CAP2_PACKED_RD | \ MMC_CAP2_PACKED_WR) #define MMC_CAP2_NO_PRESCAN_POWERUP (1 << 14) /* Don't power up before scan */ -#define MMC_CAP2_SANITIZE (1 << 15) /* Support Sanitize */ mmc_pm_flag_t pm_caps; /* supported pm features */ -- cgit v1.2.3 From 325e2f96b926ae852fa2aa5e64d1040ed9518ae1 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Mon, 16 Dec 2013 14:43:51 +0100 Subject: mmc: core: Remove unused host cap MMC_CAP2_BROKEN_VOLTAGE Signed-off-by: Ulf Hansson Signed-off-by: Chris Ball --- include/linux/mmc/host.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index 40f832e5db40..461c69f19425 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -272,7 +272,6 @@ struct mmc_host { #define MMC_CAP2_HS200_1_2V_SDR (1 << 6) /* can support */ #define MMC_CAP2_HS200 (MMC_CAP2_HS200_1_8V_SDR | \ MMC_CAP2_HS200_1_2V_SDR) -#define MMC_CAP2_BROKEN_VOLTAGE (1 << 7) /* Use the broken voltage */ #define MMC_CAP2_HC_ERASE_SZ (1 << 9) /* High-capacity erase size */ #define MMC_CAP2_CD_ACTIVE_HIGH (1 << 10) /* Card-detect signal active high */ #define MMC_CAP2_RO_ACTIVE_HIGH (1 << 11) /* Write-protect signal active high */ -- cgit v1.2.3 From 469a00b017a9b2c630bff962ffd64ba626977830 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Mon, 16 Dec 2013 14:46:00 +0100 Subject: mmc: core: Remove support for MMC_CAP2_NO_SLEEP_CMD There are no active users of this host capability. The primary reason for adding this cap was due to a bug in ux500 boot loader code, which is not a relevant issue any more. So, let's remove it. Signed-off-by: Ulf Hansson Signed-off-by: Chris Ball --- drivers/mmc/core/mmc.c | 3 --- include/linux/mmc/host.h | 1 - 2 files changed, 4 deletions(-) diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 20f046895228..5c4ee6ab2125 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -1358,9 +1358,6 @@ static int mmc_sleep(struct mmc_host *host) struct mmc_card *card = host->card; int err; - if (host->caps2 & MMC_CAP2_NO_SLEEP_CMD) - return 0; - err = mmc_deselect_cards(host); if (err) return err; diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index 461c69f19425..4c0176a8e474 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -267,7 +267,6 @@ struct mmc_host { #define MMC_CAP2_CACHE_CTRL (1 << 1) /* Allow cache control */ #define MMC_CAP2_FULL_PWR_CYCLE (1 << 2) /* Can do full power cycle */ #define MMC_CAP2_NO_MULTI_READ (1 << 3) /* Multiblock reads don't work */ -#define MMC_CAP2_NO_SLEEP_CMD (1 << 4) /* Don't allow sleep command */ #define MMC_CAP2_HS200_1_8V_SDR (1 << 5) /* can support */ #define MMC_CAP2_HS200_1_2V_SDR (1 << 6) /* can support */ #define MMC_CAP2_HS200 (MMC_CAP2_HS200_1_8V_SDR | \ -- cgit v1.2.3 From 10e5d9652499a8bc0a99ffc2a96a3030fee576cb Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Mon, 16 Dec 2013 16:23:22 +0100 Subject: mmc: core: Use mmc_flush_cache() during mmc suspend Earlier we disabled the cache during suspend, which meant a flush was internally at the eMMC performed as well. To simplify code we can make use of the mmc_flush_cache(), during mmc suspend, which makes the mmc_cache_ctrl() redundant so then we can remove it. Signed-off-by: Ulf Hansson Acked-by: Seungwon Jeon Signed-off-by: Chris Ball --- drivers/mmc/core/core.c | 38 -------------------------------------- drivers/mmc/core/mmc.c | 2 +- include/linux/mmc/host.h | 2 -- 3 files changed, 1 insertion(+), 41 deletions(-) diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 22427c684b36..8928f9f4cfe1 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -2582,44 +2582,6 @@ int mmc_flush_cache(struct mmc_card *card) } EXPORT_SYMBOL(mmc_flush_cache); -/* - * Turn the cache ON/OFF. - * Turning the cache OFF shall trigger flushing of the data - * to the non-volatile storage. - * This function should be called with host claimed - */ -int mmc_cache_ctrl(struct mmc_host *host, u8 enable) -{ - struct mmc_card *card = host->card; - unsigned int timeout; - int err = 0; - - if (!(host->caps2 & MMC_CAP2_CACHE_CTRL) || - mmc_card_is_removable(host)) - return err; - - if (card && mmc_card_mmc(card) && - (card->ext_csd.cache_size > 0)) { - enable = !!enable; - - if (card->ext_csd.cache_ctrl ^ enable) { - timeout = enable ? card->ext_csd.generic_cmd6_time : 0; - err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, - EXT_CSD_CACHE_CTRL, enable, timeout); - if (err) - pr_err("%s: cache %s error %d\n", - mmc_hostname(card->host), - enable ? "on" : "off", - err); - else - card->ext_csd.cache_ctrl = enable; - } - } - - return err; -} -EXPORT_SYMBOL(mmc_cache_ctrl); - #ifdef CONFIG_PM /* Do the card removal on suspend if card is assumed removeable diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 5c4ee6ab2125..6d446e217f36 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -1481,7 +1481,7 @@ static int _mmc_suspend(struct mmc_host *host, bool is_suspend) goto out; } - err = mmc_cache_ctrl(host, 0); + err = mmc_flush_cache(host->card); if (err) goto out; diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index 4c0176a8e474..f69bd70b1046 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -385,8 +385,6 @@ int mmc_power_restore_host(struct mmc_host *host); void mmc_detect_change(struct mmc_host *, unsigned long delay); void mmc_request_done(struct mmc_host *, struct mmc_request *); -int mmc_cache_ctrl(struct mmc_host *, u8); - static inline void mmc_signal_sdio_irq(struct mmc_host *host) { host->ops->enable_sdio_irq(host, 0); -- cgit v1.2.3 From 7536d3f83aa42ba1a3b1c6b30c2b6d94a820cbb2 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Wed, 18 Dec 2013 11:59:17 +0100 Subject: mmc: core: Enable MMC_CAP2_CACHE_CTRL as default There are no reason to why the use of a non-volatile internal eMMC cache should be controlled by a host cap. Instead let's just enable it if the eMMC card supports it. Signed-off-by: Ulf Hansson Acked-by: Seungwon Jeon Signed-off-by: Chris Ball --- drivers/mmc/core/core.c | 4 ---- drivers/mmc/core/mmc.c | 3 +-- include/linux/mmc/host.h | 1 - 3 files changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 8928f9f4cfe1..f5a068d55c36 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -2562,12 +2562,8 @@ EXPORT_SYMBOL(mmc_power_restore_host); */ int mmc_flush_cache(struct mmc_card *card) { - struct mmc_host *host = card->host; int err = 0; - if (!(host->caps2 & MMC_CAP2_CACHE_CTRL)) - return err; - if (mmc_card_mmc(card) && (card->ext_csd.cache_size > 0) && (card->ext_csd.cache_ctrl & 1)) { diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 6d446e217f36..072171183d5b 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -1287,8 +1287,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, * If cache size is higher than 0, this indicates * the existence of cache and it can be turned on. */ - if ((host->caps2 & MMC_CAP2_CACHE_CTRL) && - card->ext_csd.cache_size > 0) { + if (card->ext_csd.cache_size > 0) { err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_CACHE_CTRL, 1, card->ext_csd.generic_cmd6_time); diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index f69bd70b1046..719db89ef134 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -264,7 +264,6 @@ struct mmc_host { u32 caps2; /* More host capabilities */ #define MMC_CAP2_BOOTPART_NOACC (1 << 0) /* Boot partition no access */ -#define MMC_CAP2_CACHE_CTRL (1 << 1) /* Allow cache control */ #define MMC_CAP2_FULL_PWR_CYCLE (1 << 2) /* Can do full power cycle */ #define MMC_CAP2_NO_MULTI_READ (1 << 3) /* Multiblock reads don't work */ #define MMC_CAP2_HS200_1_8V_SDR (1 << 5) /* can support */ -- cgit v1.2.3 From 2772ef30eacd72fef013ac2fade2f384342ba6c7 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 20 Feb 2014 16:54:44 -0800 Subject: mmc: sdhi: tidyup sh_mobile_sdhi_of_match position It is easier to read if sh_mobile_sdhi_of_cfg and sh_mobile_sdhi_of_match are closer. Signed-off-by: Kuninori Morimoto Acked-by: Simon Horman Signed-off-by: Chris Ball --- drivers/mmc/host/sh_mobile_sdhi.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/drivers/mmc/host/sh_mobile_sdhi.c b/drivers/mmc/host/sh_mobile_sdhi.c index 03fe7518bba4..a7a3f689a309 100644 --- a/drivers/mmc/host/sh_mobile_sdhi.c +++ b/drivers/mmc/host/sh_mobile_sdhi.c @@ -45,6 +45,19 @@ static const struct sh_mobile_sdhi_of_data sh_mobile_sdhi_of_cfg[] = { }, }; +static const struct of_device_id sh_mobile_sdhi_of_match[] = { + { .compatible = "renesas,sdhi-shmobile" }, + { .compatible = "renesas,sdhi-sh7372" }, + { .compatible = "renesas,sdhi-sh73a0", .data = &sh_mobile_sdhi_of_cfg[0], }, + { .compatible = "renesas,sdhi-r8a73a4", .data = &sh_mobile_sdhi_of_cfg[0], }, + { .compatible = "renesas,sdhi-r8a7740", .data = &sh_mobile_sdhi_of_cfg[0], }, + { .compatible = "renesas,sdhi-r8a7778", .data = &sh_mobile_sdhi_of_cfg[0], }, + { .compatible = "renesas,sdhi-r8a7779", .data = &sh_mobile_sdhi_of_cfg[0], }, + { .compatible = "renesas,sdhi-r8a7790", .data = &sh_mobile_sdhi_of_cfg[0], }, + {}, +}; +MODULE_DEVICE_TABLE(of, sh_mobile_sdhi_of_match); + struct sh_mobile_sdhi { struct clk *clk; struct tmio_mmc_data mmc_data; @@ -114,19 +127,6 @@ static const struct sh_mobile_sdhi_ops sdhi_ops = { .cd_wakeup = sh_mobile_sdhi_cd_wakeup, }; -static const struct of_device_id sh_mobile_sdhi_of_match[] = { - { .compatible = "renesas,sdhi-shmobile" }, - { .compatible = "renesas,sdhi-sh7372" }, - { .compatible = "renesas,sdhi-sh73a0", .data = &sh_mobile_sdhi_of_cfg[0], }, - { .compatible = "renesas,sdhi-r8a73a4", .data = &sh_mobile_sdhi_of_cfg[0], }, - { .compatible = "renesas,sdhi-r8a7740", .data = &sh_mobile_sdhi_of_cfg[0], }, - { .compatible = "renesas,sdhi-r8a7778", .data = &sh_mobile_sdhi_of_cfg[0], }, - { .compatible = "renesas,sdhi-r8a7779", .data = &sh_mobile_sdhi_of_cfg[0], }, - { .compatible = "renesas,sdhi-r8a7790", .data = &sh_mobile_sdhi_of_cfg[0], }, - {}, -}; -MODULE_DEVICE_TABLE(of, sh_mobile_sdhi_of_match); - static int sh_mobile_sdhi_probe(struct platform_device *pdev) { const struct of_device_id *of_id = -- cgit v1.2.3 From b3a5d4ce65162d27a495b8fa3ac21dcdf58738b1 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 20 Feb 2014 16:54:58 -0800 Subject: mmc: sdhi: update sh_mobile_sdhi_of_data for r8a7778 This patch updates r8a7778 DT data to have SoC specific settings. Signed-off-by: Kuninori Morimoto Acked-by: Simon Horman Signed-off-by: Chris Ball --- drivers/mmc/host/sh_mobile_sdhi.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/host/sh_mobile_sdhi.c b/drivers/mmc/host/sh_mobile_sdhi.c index a7a3f689a309..e956bc4e28c1 100644 --- a/drivers/mmc/host/sh_mobile_sdhi.c +++ b/drivers/mmc/host/sh_mobile_sdhi.c @@ -37,6 +37,7 @@ struct sh_mobile_sdhi_of_data { unsigned long tmio_flags; + unsigned long capabilities; }; static const struct sh_mobile_sdhi_of_data sh_mobile_sdhi_of_cfg[] = { @@ -45,13 +46,18 @@ static const struct sh_mobile_sdhi_of_data sh_mobile_sdhi_of_cfg[] = { }, }; +static const struct sh_mobile_sdhi_of_data of_rcar_gen1_compatible = { + .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_WRPROTECT_DISABLE, + .capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ, +}; + static const struct of_device_id sh_mobile_sdhi_of_match[] = { { .compatible = "renesas,sdhi-shmobile" }, { .compatible = "renesas,sdhi-sh7372" }, { .compatible = "renesas,sdhi-sh73a0", .data = &sh_mobile_sdhi_of_cfg[0], }, { .compatible = "renesas,sdhi-r8a73a4", .data = &sh_mobile_sdhi_of_cfg[0], }, { .compatible = "renesas,sdhi-r8a7740", .data = &sh_mobile_sdhi_of_cfg[0], }, - { .compatible = "renesas,sdhi-r8a7778", .data = &sh_mobile_sdhi_of_cfg[0], }, + { .compatible = "renesas,sdhi-r8a7778", .data = &of_rcar_gen1_compatible, }, { .compatible = "renesas,sdhi-r8a7779", .data = &sh_mobile_sdhi_of_cfg[0], }, { .compatible = "renesas,sdhi-r8a7790", .data = &sh_mobile_sdhi_of_cfg[0], }, {}, @@ -212,6 +218,7 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev) if (of_id && of_id->data) { const struct sh_mobile_sdhi_of_data *of_data = of_id->data; mmc_data->flags |= of_data->tmio_flags; + mmc_data->capabilities |= of_data->capabilities; } /* SD control register space size is 0x100, 0x200 for bus_shift=1 */ -- cgit v1.2.3 From 81bbbc7278fa109fb691446a521dcfc18b87e57d Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 20 Feb 2014 16:55:12 -0800 Subject: mmc: sdhi: update sh_mobile_sdhi_of_data for r8a7779 This patch updates r8a7779 DT data to have SoC specific settings. Signed-off-by: Kuninori Morimoto Acked-by: Simon Horman Signed-off-by: Chris Ball --- drivers/mmc/host/sh_mobile_sdhi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mmc/host/sh_mobile_sdhi.c b/drivers/mmc/host/sh_mobile_sdhi.c index e956bc4e28c1..38acf2665bdf 100644 --- a/drivers/mmc/host/sh_mobile_sdhi.c +++ b/drivers/mmc/host/sh_mobile_sdhi.c @@ -58,7 +58,7 @@ static const struct of_device_id sh_mobile_sdhi_of_match[] = { { .compatible = "renesas,sdhi-r8a73a4", .data = &sh_mobile_sdhi_of_cfg[0], }, { .compatible = "renesas,sdhi-r8a7740", .data = &sh_mobile_sdhi_of_cfg[0], }, { .compatible = "renesas,sdhi-r8a7778", .data = &of_rcar_gen1_compatible, }, - { .compatible = "renesas,sdhi-r8a7779", .data = &sh_mobile_sdhi_of_cfg[0], }, + { .compatible = "renesas,sdhi-r8a7779", .data = &of_rcar_gen1_compatible, }, { .compatible = "renesas,sdhi-r8a7790", .data = &sh_mobile_sdhi_of_cfg[0], }, {}, }; -- cgit v1.2.3 From 423f6c2e977de73b8723e73d8cc585de40893f5b Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 20 Feb 2014 16:55:27 -0800 Subject: mmc: sdhi: update sh_mobile_sdhi_of_data for r8a7790 This patch updates r8a7790 DT data to have SoC specific settings. Signed-off-by: Kuninori Morimoto Acked-by: Simon Horman Signed-off-by: Chris Ball --- drivers/mmc/host/sh_mobile_sdhi.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/host/sh_mobile_sdhi.c b/drivers/mmc/host/sh_mobile_sdhi.c index 38acf2665bdf..cfc37ec26458 100644 --- a/drivers/mmc/host/sh_mobile_sdhi.c +++ b/drivers/mmc/host/sh_mobile_sdhi.c @@ -38,6 +38,7 @@ struct sh_mobile_sdhi_of_data { unsigned long tmio_flags; unsigned long capabilities; + unsigned long capabilities2; }; static const struct sh_mobile_sdhi_of_data sh_mobile_sdhi_of_cfg[] = { @@ -51,6 +52,12 @@ static const struct sh_mobile_sdhi_of_data of_rcar_gen1_compatible = { .capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ, }; +static const struct sh_mobile_sdhi_of_data of_rcar_gen2_compatible = { + .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_WRPROTECT_DISABLE, + .capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ, + .capabilities2 = MMC_CAP2_NO_MULTI_READ, +}; + static const struct of_device_id sh_mobile_sdhi_of_match[] = { { .compatible = "renesas,sdhi-shmobile" }, { .compatible = "renesas,sdhi-sh7372" }, @@ -59,7 +66,7 @@ static const struct of_device_id sh_mobile_sdhi_of_match[] = { { .compatible = "renesas,sdhi-r8a7740", .data = &sh_mobile_sdhi_of_cfg[0], }, { .compatible = "renesas,sdhi-r8a7778", .data = &of_rcar_gen1_compatible, }, { .compatible = "renesas,sdhi-r8a7779", .data = &of_rcar_gen1_compatible, }, - { .compatible = "renesas,sdhi-r8a7790", .data = &sh_mobile_sdhi_of_cfg[0], }, + { .compatible = "renesas,sdhi-r8a7790", .data = &of_rcar_gen2_compatible, }, {}, }; MODULE_DEVICE_TABLE(of, sh_mobile_sdhi_of_match); @@ -219,6 +226,7 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev) const struct sh_mobile_sdhi_of_data *of_data = of_id->data; mmc_data->flags |= of_data->tmio_flags; mmc_data->capabilities |= of_data->capabilities; + mmc_data->capabilities2 |= of_data->capabilities2; } /* SD control register space size is 0x100, 0x200 for bus_shift=1 */ -- cgit v1.2.3 From 81918d25a7ae2a7eada4237d00b8d6dbecffda6c Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 20 Feb 2014 16:55:40 -0800 Subject: mmc: sdhi: update sh_mobile_sdhi_of_data for r8a7791 This patch adds DT support for r8a7791. Signed-off-by: Kuninori Morimoto Acked-by: Simon Horman Signed-off-by: Chris Ball --- drivers/mmc/host/sh_mobile_sdhi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mmc/host/sh_mobile_sdhi.c b/drivers/mmc/host/sh_mobile_sdhi.c index cfc37ec26458..91058dabd11a 100644 --- a/drivers/mmc/host/sh_mobile_sdhi.c +++ b/drivers/mmc/host/sh_mobile_sdhi.c @@ -67,6 +67,7 @@ static const struct of_device_id sh_mobile_sdhi_of_match[] = { { .compatible = "renesas,sdhi-r8a7778", .data = &of_rcar_gen1_compatible, }, { .compatible = "renesas,sdhi-r8a7779", .data = &of_rcar_gen1_compatible, }, { .compatible = "renesas,sdhi-r8a7790", .data = &of_rcar_gen2_compatible, }, + { .compatible = "renesas,sdhi-r8a7791", .data = &of_rcar_gen2_compatible, }, {}, }; MODULE_DEVICE_TABLE(of, sh_mobile_sdhi_of_match); -- cgit v1.2.3 From 0e5c93e0200e9759561377d51d5478134f50f7ee Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Sat, 22 Feb 2014 18:01:37 +0200 Subject: mmc: omap: Fix NULL pointer dereference due uninitialized cover_tasklet Omap MMC driver initialization can cause a NULL pointer dereference in tasklet_hi_action on Nokia N810 if its miniSD cover is open during driver initialization. [ 1.070000] Unable to handle kernel NULL pointer dereference at virtual address 00000000 [ 1.080000] pgd = c0004000 [ 1.080000] [00000000] *pgd=00000000 [ 1.080000] Internal error: Oops: 80000005 [#1] PREEMPT ARM [ 1.080000] Modules linked in: [ 1.080000] CPU: 0 PID: 24 Comm: kworker/0:1 Not tainted 3.13.0-rc2+ #95 [ 1.080000] Workqueue: events menelaus_work [ 1.080000] task: c7863340 ti: c7878000 task.ti: c7878000 [ 1.080000] PC is at 0x0 [ 1.080000] LR is at tasklet_hi_action+0x68/0xa4 ... [ 1.080000] [] (tasklet_hi_action+0x68/0xa4) from [] (__do_softirq+0xbc/0x208) [ 1.080000] [] (__do_softirq+0xbc/0x208) from [] (irq_exit+0x84/0xac) [ 1.080000] [] (irq_exit+0x84/0xac) from [] (handle_IRQ+0x64/0x84) [ 1.080000] [] (handle_IRQ+0x64/0x84) from [] (omap2_intc_handle_irq+0x54/0x68) [ 1.080000] [] (omap2_intc_handle_irq+0x54/0x68) from [] (__irq_svc+0x40/0x74) [ 1.080000] Exception stack(0xc7879d70 to 0xc7879db8) [ 1.080000] 9d60: 000003f1 0000000a 00000009 0000001c [ 1.080000] 9d80: c7879e70 c780bc10 c780bc10 00000000 00000001 00008603 c780bc78 c7879e4e [ 1.080000] 9da0: 00000002 c7879db8 c00343b0 c0160c9c 20000113 ffffffff [ 1.080000] [] (__irq_svc+0x40/0x74) from [] (__aeabi_uidiv+0x20/0x9c) [ 1.080000] [] (__aeabi_uidiv+0x20/0x9c) from [] (msecs_to_jiffies+0x18/0x24) [ 1.080000] [] (msecs_to_jiffies+0x18/0x24) from [] (omap_i2c_xfer+0x30c/0x458) [ 1.080000] [] (omap_i2c_xfer+0x30c/0x458) from [] (__i2c_transfer+0x3c/0x74) [ 1.080000] [] (__i2c_transfer+0x3c/0x74) from [] (i2c_transfer+0x78/0x94) [ 1.080000] [] (i2c_transfer+0x78/0x94) from [] (i2c_smbus_xfer+0x3c0/0x4f8) [ 1.080000] [] (i2c_smbus_xfer+0x3c0/0x4f8) from [] (i2c_smbus_write_byte_data+0x34/0x3c) [ 1.080000] [] (i2c_smbus_write_byte_data+0x34/0x3c) from [] (menelaus_write_reg+0x1c/0x40) [ 1.080000] [] (menelaus_write_reg+0x1c/0x40) from [] (menelaus_work+0xa0/0xc4) [ 1.080000] [] (menelaus_work+0xa0/0xc4) from [] (process_one_work+0x1fc/0x334) [ 1.080000] [] (process_one_work+0x1fc/0x334) from [] (worker_thread+0x244/0x380) [ 1.080000] [] (worker_thread+0x244/0x380) from [] (kthread+0xc0/0xd4) [ 1.080000] [] (kthread+0xc0/0xd4) from [] (ret_from_fork+0x14/0x3c) [ 1.080000] Code: bad PC value [ 1.090000] ---[ end trace 7bc2fc7cd14f1d95 ]--- [ 1.100000] Kernel panic - not syncing: Fatal exception in interrupt Reason for this is that omap_notify_cover_event which calls tasklet_hi_schedule gets called before struct cover_tasklet is initialized. Call to omap_notify_cover_event on Nokia N810 happens from menelaus.c PMIC driver via board-n8x0.c during execution of mmc_add_host in case of open miniSD cover. Fix this by moving cover_timer and cover_tasklet initialization before mmc_add_host call in mmc_omap_new_slot. Signed-off-by: Jarkko Nikula Acked-by: Tony Lindgren Tested-by: Aaro Koskinen Signed-off-by: Chris Ball --- drivers/mmc/host/omap.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/mmc/host/omap.c b/drivers/mmc/host/omap.c index 98b6b6ef7e5c..42b665dfaa73 100644 --- a/drivers/mmc/host/omap.c +++ b/drivers/mmc/host/omap.c @@ -1262,6 +1262,13 @@ static int mmc_omap_new_slot(struct mmc_omap_host *host, int id) mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count; mmc->max_seg_size = mmc->max_req_size; + if (slot->pdata->get_cover_state != NULL) { + setup_timer(&slot->cover_timer, mmc_omap_cover_timer, + (unsigned long)slot); + tasklet_init(&slot->cover_tasklet, mmc_omap_cover_handler, + (unsigned long)slot); + } + r = mmc_add_host(mmc); if (r < 0) goto err_remove_host; @@ -1278,11 +1285,6 @@ static int mmc_omap_new_slot(struct mmc_omap_host *host, int id) &dev_attr_cover_switch); if (r < 0) goto err_remove_slot_name; - - setup_timer(&slot->cover_timer, mmc_omap_cover_timer, - (unsigned long)slot); - tasklet_init(&slot->cover_tasklet, mmc_omap_cover_handler, - (unsigned long)slot); tasklet_schedule(&slot->cover_tasklet); } -- cgit v1.2.3 From ae9b79c634b91d60fecd8663324434219b68b10f Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Sat, 22 Feb 2014 18:01:38 +0200 Subject: mmc: omap: Convert to devm_kzalloc Signed-off-by: Jarkko Nikula Acked-by: Tony Lindgren Tested-by: Aaro Koskinen Signed-off-by: Chris Ball --- drivers/mmc/host/omap.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/mmc/host/omap.c b/drivers/mmc/host/omap.c index 42b665dfaa73..927ed24d0708 100644 --- a/drivers/mmc/host/omap.c +++ b/drivers/mmc/host/omap.c @@ -1345,7 +1345,8 @@ static int mmc_omap_probe(struct platform_device *pdev) if (res == NULL) return -EBUSY; - host = kzalloc(sizeof(struct mmc_omap_host), GFP_KERNEL); + host = devm_kzalloc(&pdev->dev, sizeof(struct mmc_omap_host), + GFP_KERNEL); if (host == NULL) { ret = -ENOMEM; goto err_free_mem_region; @@ -1465,7 +1466,6 @@ err_free_iclk: err_free_mmc_host: iounmap(host->virt_base); err_ioremap: - kfree(host); err_free_mem_region: release_mem_region(res->start, resource_size(res)); return ret; @@ -1500,8 +1500,6 @@ static int mmc_omap_remove(struct platform_device *pdev) pdev->resource[0].end - pdev->resource[0].start + 1); destroy_workqueue(host->mmc_omap_wq); - kfree(host); - return 0; } -- cgit v1.2.3 From 5b7d23aa5ddf2d3318370d369d287c9646156ca4 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Sat, 22 Feb 2014 18:01:39 +0200 Subject: mmc: omap: Remove duplicate host->irq assignment host-irq is set twice so remove needless one. Signed-off-by: Jarkko Nikula Acked-by: Tony Lindgren Tested-by: Aaro Koskinen Signed-off-by: Chris Ball --- drivers/mmc/host/omap.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/mmc/host/omap.c b/drivers/mmc/host/omap.c index 927ed24d0708..b438f0addb3c 100644 --- a/drivers/mmc/host/omap.c +++ b/drivers/mmc/host/omap.c @@ -1375,7 +1375,6 @@ static int mmc_omap_probe(struct platform_device *pdev) host->mem_res = res; host->irq = irq; host->use_dma = 1; - host->irq = irq; host->phys_base = host->mem_res->start; host->virt_base = ioremap(res->start, resource_size(res)); if (!host->virt_base) -- cgit v1.2.3 From 2ca5dc6ffa3d9fefadfff0fee77e1ad52e2c0b72 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Sat, 22 Feb 2014 18:01:40 +0200 Subject: mmc: omap: Remove mem_res field from struct mmc_omap_host Field mem_res in struct mmc_omap_host is used only once in mmc_omap_probe when setting the phys_base field so we may just se the phys_base straight and remove needless mem_res. Signed-off-by: Jarkko Nikula Acked-by: Tony Lindgren Tested-by: Aaro Koskinen Signed-off-by: Chris Ball --- drivers/mmc/host/omap.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/mmc/host/omap.c b/drivers/mmc/host/omap.c index b438f0addb3c..0d669cfa6af6 100644 --- a/drivers/mmc/host/omap.c +++ b/drivers/mmc/host/omap.c @@ -130,7 +130,6 @@ struct mmc_omap_host { u32 dma_rx_burst; struct dma_chan *dma_tx; u32 dma_tx_burst; - struct resource *mem_res; void __iomem *virt_base; unsigned int phys_base; int irq; @@ -1372,10 +1371,9 @@ static int mmc_omap_probe(struct platform_device *pdev) platform_set_drvdata(pdev, host); host->id = pdev->id; - host->mem_res = res; host->irq = irq; host->use_dma = 1; - host->phys_base = host->mem_res->start; + host->phys_base = res->start; host->virt_base = ioremap(res->start, resource_size(res)); if (!host->virt_base) goto err_ioremap; -- cgit v1.2.3 From 64ac16ec80bc5aacdc2549226f2c0d48d185123c Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Sat, 22 Feb 2014 18:01:41 +0200 Subject: mmc: omap: Convert to devm_ioremap_resource Simplify probe and cleanup code by using devm_ioremap_resource. This also makes probe code to follow more common allocate private struct followed by other initialization style. Signed-off-by: Jarkko Nikula Acked-by: Tony Lindgren Tested-by: Aaro Koskinen Signed-off-by: Chris Ball --- drivers/mmc/host/omap.c | 41 ++++++++++++----------------------------- 1 file changed, 12 insertions(+), 29 deletions(-) diff --git a/drivers/mmc/host/omap.c b/drivers/mmc/host/omap.c index 0d669cfa6af6..e4c7a0380a63 100644 --- a/drivers/mmc/host/omap.c +++ b/drivers/mmc/host/omap.c @@ -1334,22 +1334,19 @@ static int mmc_omap_probe(struct platform_device *pdev) return -EPROBE_DEFER; } - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + host = devm_kzalloc(&pdev->dev, sizeof(struct mmc_omap_host), + GFP_KERNEL); + if (host == NULL) + return -ENOMEM; + irq = platform_get_irq(pdev, 0); - if (res == NULL || irq < 0) + if (irq < 0) return -ENXIO; - res = request_mem_region(res->start, resource_size(res), - pdev->name); - if (res == NULL) - return -EBUSY; - - host = devm_kzalloc(&pdev->dev, sizeof(struct mmc_omap_host), - GFP_KERNEL); - if (host == NULL) { - ret = -ENOMEM; - goto err_free_mem_region; - } + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + host->virt_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(host->virt_base)) + return PTR_ERR(host->virt_base); INIT_WORK(&host->slot_release_work, mmc_omap_slot_release_work); INIT_WORK(&host->send_stop_work, mmc_omap_send_stop_work); @@ -1374,15 +1371,9 @@ static int mmc_omap_probe(struct platform_device *pdev) host->irq = irq; host->use_dma = 1; host->phys_base = res->start; - host->virt_base = ioremap(res->start, resource_size(res)); - if (!host->virt_base) - goto err_ioremap; - host->iclk = clk_get(&pdev->dev, "ick"); - if (IS_ERR(host->iclk)) { - ret = PTR_ERR(host->iclk); - goto err_free_mmc_host; - } + if (IS_ERR(host->iclk)) + return PTR_ERR(host->iclk); clk_enable(host->iclk); host->fclk = clk_get(&pdev->dev, "fck"); @@ -1460,11 +1451,6 @@ err_free_dma: err_free_iclk: clk_disable(host->iclk); clk_put(host->iclk); -err_free_mmc_host: - iounmap(host->virt_base); -err_ioremap: -err_free_mem_region: - release_mem_region(res->start, resource_size(res)); return ret; } @@ -1492,9 +1478,6 @@ static int mmc_omap_remove(struct platform_device *pdev) if (host->dma_rx) dma_release_channel(host->dma_rx); - iounmap(host->virt_base); - release_mem_region(pdev->resource[0].start, - pdev->resource[0].end - pdev->resource[0].start + 1); destroy_workqueue(host->mmc_omap_wq); return 0; -- cgit v1.2.3 From a6c668fb95ac655fe94c08c1fb419f685040cf23 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Sat, 22 Feb 2014 18:01:42 +0200 Subject: mmc: omap: Remove always set use_dma flag from struct mmc_omap_host Because use_dma is set only in mmc_omap_probe and unset nowhere there is no need to carry that flag in struct mmc_omap_host for mmc_omap_prepare_data function. Signed-off-by: Jarkko Nikula Acked-by: Tony Lindgren Tested-by: Aaro Koskinen Signed-off-by: Chris Ball --- drivers/mmc/host/omap.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/drivers/mmc/host/omap.c b/drivers/mmc/host/omap.c index e4c7a0380a63..42175cd90435 100644 --- a/drivers/mmc/host/omap.c +++ b/drivers/mmc/host/omap.c @@ -152,7 +152,6 @@ struct mmc_omap_host { u32 total_bytes_left; unsigned features; - unsigned use_dma:1; unsigned brs_received:1, dma_done:1; unsigned dma_in_use:1; spinlock_t dma_lock; @@ -944,7 +943,7 @@ static void mmc_omap_prepare_data(struct mmc_omap_host *host, struct mmc_request *req) { struct mmc_data *data = req->data; - int i, use_dma, block_size; + int i, use_dma = 1, block_size; unsigned sg_len; host->data = data; @@ -969,13 +968,10 @@ mmc_omap_prepare_data(struct mmc_omap_host *host, struct mmc_request *req) sg_len = (data->blocks == 1) ? 1 : data->sg_len; /* Only do DMA for entire blocks */ - use_dma = host->use_dma; - if (use_dma) { - for (i = 0; i < sg_len; i++) { - if ((data->sg[i].length % block_size) != 0) { - use_dma = 0; - break; - } + for (i = 0; i < sg_len; i++) { + if ((data->sg[i].length % block_size) != 0) { + use_dma = 0; + break; } } @@ -1369,7 +1365,6 @@ static int mmc_omap_probe(struct platform_device *pdev) host->id = pdev->id; host->irq = irq; - host->use_dma = 1; host->phys_base = res->start; host->iclk = clk_get(&pdev->dev, "ick"); if (IS_ERR(host->iclk)) -- cgit v1.2.3 From b13d1f0f9ad64bc498ced07344495ba27321419e Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Sat, 22 Feb 2014 18:01:43 +0200 Subject: mmc: omap: Add erase capability This patch adds the erase capability to OMAP1/OMAP2420 MMC driver. Idea is the same than in commit 93caf8e ("omap_hsmmc: add erase capability") that we disable the data timeout interrupt for erases. Signed-off-by: Jarkko Nikula Acked-by: Tony Lindgren Tested-by: Aaro Koskinen Signed-off-by: Chris Ball --- drivers/mmc/host/omap.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/drivers/mmc/host/omap.c b/drivers/mmc/host/omap.c index 42175cd90435..5c2e58b29305 100644 --- a/drivers/mmc/host/omap.c +++ b/drivers/mmc/host/omap.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -336,6 +337,7 @@ mmc_omap_start_command(struct mmc_omap_host *host, struct mmc_command *cmd) u32 cmdreg; u32 resptype; u32 cmdtype; + u16 irq_mask; host->cmd = cmd; @@ -388,12 +390,14 @@ mmc_omap_start_command(struct mmc_omap_host *host, struct mmc_command *cmd) OMAP_MMC_WRITE(host, CTO, 200); OMAP_MMC_WRITE(host, ARGL, cmd->arg & 0xffff); OMAP_MMC_WRITE(host, ARGH, cmd->arg >> 16); - OMAP_MMC_WRITE(host, IE, - OMAP_MMC_STAT_A_EMPTY | OMAP_MMC_STAT_A_FULL | - OMAP_MMC_STAT_CMD_CRC | OMAP_MMC_STAT_CMD_TOUT | - OMAP_MMC_STAT_DATA_CRC | OMAP_MMC_STAT_DATA_TOUT | - OMAP_MMC_STAT_END_OF_CMD | OMAP_MMC_STAT_CARD_ERR | - OMAP_MMC_STAT_END_OF_DATA); + irq_mask = OMAP_MMC_STAT_A_EMPTY | OMAP_MMC_STAT_A_FULL | + OMAP_MMC_STAT_CMD_CRC | OMAP_MMC_STAT_CMD_TOUT | + OMAP_MMC_STAT_DATA_CRC | OMAP_MMC_STAT_DATA_TOUT | + OMAP_MMC_STAT_END_OF_CMD | OMAP_MMC_STAT_CARD_ERR | + OMAP_MMC_STAT_END_OF_DATA; + if (cmd->opcode == MMC_ERASE) + irq_mask &= ~OMAP_MMC_STAT_DATA_TOUT; + OMAP_MMC_WRITE(host, IE, irq_mask); OMAP_MMC_WRITE(host, CMD, cmdreg); } @@ -1234,7 +1238,7 @@ static int mmc_omap_new_slot(struct mmc_omap_host *host, int id) mmc->caps = 0; if (host->pdata->slots[id].wires >= 4) - mmc->caps |= MMC_CAP_4_BIT_DATA; + mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_ERASE; mmc->ops = &mmc_omap_ops; mmc->f_min = 400000; -- cgit v1.2.3 From 9107ebbf9652c033eb5dd10a6ea34a132db3cde1 Mon Sep 17 00:00:00 2001 From: Micky Ching Date: Fri, 21 Feb 2014 18:40:35 +0800 Subject: mmc: sdhci: add support for realtek rts5250 Add support for realtek rts5250 pci card reader. The card reader has some problems with DDR50 mode, so add a new quirks2 for broken ddr50. Signed-off-by: Micky Ching Signed-off-by: Chris Ball --- drivers/mmc/host/sdhci-pci.c | 20 ++++++++++++++++++++ drivers/mmc/host/sdhci.c | 3 ++- include/linux/mmc/sdhci.h | 2 ++ 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c index 0955777b6c7e..fdc612120362 100644 --- a/drivers/mmc/host/sdhci-pci.c +++ b/drivers/mmc/host/sdhci-pci.c @@ -610,6 +610,18 @@ static const struct sdhci_pci_fixes sdhci_via = { .probe = via_probe, }; +static int rtsx_probe_slot(struct sdhci_pci_slot *slot) +{ + slot->host->mmc->caps2 |= MMC_CAP2_HS200; + return 0; +} + +static const struct sdhci_pci_fixes sdhci_rtsx = { + .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | + SDHCI_QUIRK2_BROKEN_DDR50, + .probe_slot = rtsx_probe_slot, +}; + static const struct pci_device_id pci_ids[] = { { .vendor = PCI_VENDOR_ID_RICOH, @@ -731,6 +743,14 @@ static const struct pci_device_id pci_ids[] = { .driver_data = (kernel_ulong_t)&sdhci_via, }, + { + .vendor = PCI_VENDOR_ID_REALTEK, + .device = 0x5250, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = (kernel_ulong_t)&sdhci_rtsx, + }, + { .vendor = PCI_VENDOR_ID_INTEL, .device = PCI_DEVICE_ID_INTEL_MRST_SD0, diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 9ddef4763541..8958edc03e04 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -3020,7 +3020,8 @@ int sdhci_add_host(struct sdhci_host *host) } else if (caps[1] & SDHCI_SUPPORT_SDR50) mmc->caps |= MMC_CAP_UHS_SDR50; - if (caps[1] & SDHCI_SUPPORT_DDR50) + if ((caps[1] & SDHCI_SUPPORT_DDR50) && + !(host->quirks2 & SDHCI_QUIRK2_BROKEN_DDR50)) mmc->caps |= MMC_CAP_UHS_DDR50; /* Does the host need tuning for SDR50? */ diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h index 362927c48f97..7be12b883485 100644 --- a/include/linux/mmc/sdhci.h +++ b/include/linux/mmc/sdhci.h @@ -100,6 +100,8 @@ struct sdhci_host { #define SDHCI_QUIRK2_BROKEN_HOST_CONTROL (1<<5) /* Controller does not support HS200 */ #define SDHCI_QUIRK2_BROKEN_HS200 (1<<6) +/* Controller does not support DDR50 */ +#define SDHCI_QUIRK2_BROKEN_DDR50 (1<<7) int irq; /* Device IRQ */ void __iomem *ioaddr; /* Mapped address */ -- cgit v1.2.3 From 640e09bc45f5d03622da5230d131c0bfd0d2da3f Mon Sep 17 00:00:00 2001 From: Micky Ching Date: Mon, 17 Feb 2014 16:45:46 +0800 Subject: mmc: rtsx: fix card poweroff bug If the host driver removed while card in the slot, the host will not power off card power correctly. This bug is produced because host eject flag set before the last mmc_set_ios callback, we should set the eject flag after power off. Signed-off-by: Micky Ching Signed-off-by: Chris Ball --- drivers/mmc/host/rtsx_pci_sdmmc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/host/rtsx_pci_sdmmc.c b/drivers/mmc/host/rtsx_pci_sdmmc.c index c46feda07d56..cc80e3119d1d 100644 --- a/drivers/mmc/host/rtsx_pci_sdmmc.c +++ b/drivers/mmc/host/rtsx_pci_sdmmc.c @@ -1297,7 +1297,6 @@ static int rtsx_pci_sdmmc_drv_remove(struct platform_device *pdev) pcr->slots[RTSX_SD_CARD].p_dev = NULL; pcr->slots[RTSX_SD_CARD].card_event = NULL; mmc = host->mmc; - host->eject = true; mutex_lock(&host->host_mutex); if (host->mrq) { @@ -1315,6 +1314,8 @@ static int rtsx_pci_sdmmc_drv_remove(struct platform_device *pdev) mutex_unlock(&host->host_mutex); mmc_remove_host(mmc); + host->eject = true; + mmc_free_host(mmc); dev_dbg(&(pdev->dev), -- cgit v1.2.3 From abcc6b2943145ae2e17a52632ccab50cd612914c Mon Sep 17 00:00:00 2001 From: Micky Ching Date: Mon, 17 Feb 2014 16:45:47 +0800 Subject: mmc: rtsx: modify phase searching method for tuning The new phase searching method is more concise and easier to understand. Signed-off-by: Micky Ching Signed-off-by: Chris Ball --- drivers/mmc/host/rtsx_pci_sdmmc.c | 112 +++++++++++--------------------------- include/linux/mfd/rtsx_pci.h | 2 +- 2 files changed, 33 insertions(+), 81 deletions(-) diff --git a/drivers/mmc/host/rtsx_pci_sdmmc.c b/drivers/mmc/host/rtsx_pci_sdmmc.c index cc80e3119d1d..0b9ded13a3ae 100644 --- a/drivers/mmc/host/rtsx_pci_sdmmc.c +++ b/drivers/mmc/host/rtsx_pci_sdmmc.c @@ -31,16 +31,6 @@ #include #include -/* SD Tuning Data Structure - * Record continuous timing phase path - */ -struct timing_phase_path { - int start; - int end; - int mid; - int len; -}; - struct realtek_pci_sdmmc { struct platform_device *pdev; struct rtsx_pcr *pcr; @@ -511,85 +501,47 @@ static int sd_change_phase(struct realtek_pci_sdmmc *host, return 0; } -static u8 sd_search_final_phase(struct realtek_pci_sdmmc *host, u32 phase_map) +static inline u32 test_phase_bit(u32 phase_map, unsigned int bit) { - struct timing_phase_path path[MAX_PHASE + 1]; - int i, j, cont_path_cnt; - int new_block, max_len, final_path_idx; - u8 final_phase = 0xFF; + bit %= RTSX_PHASE_MAX; + return phase_map & (1 << bit); +} - /* Parse phase_map, take it as a bit-ring */ - cont_path_cnt = 0; - new_block = 1; - j = 0; - for (i = 0; i < MAX_PHASE + 1; i++) { - if (phase_map & (1 << i)) { - if (new_block) { - new_block = 0; - j = cont_path_cnt++; - path[j].start = i; - path[j].end = i; - } else { - path[j].end = i; - } - } else { - new_block = 1; - if (cont_path_cnt) { - /* Calculate path length and middle point */ - int idx = cont_path_cnt - 1; - path[idx].len = - path[idx].end - path[idx].start + 1; - path[idx].mid = - path[idx].start + path[idx].len / 2; - } - } - } +static int sd_get_phase_len(u32 phase_map, unsigned int start_bit) +{ + int i; - if (cont_path_cnt == 0) { - dev_dbg(sdmmc_dev(host), "No continuous phase path\n"); - goto finish; - } else { - /* Calculate last continuous path length and middle point */ - int idx = cont_path_cnt - 1; - path[idx].len = path[idx].end - path[idx].start + 1; - path[idx].mid = path[idx].start + path[idx].len / 2; + for (i = 0; i < RTSX_PHASE_MAX; i++) { + if (test_phase_bit(phase_map, start_bit + i) == 0) + return i; } + return RTSX_PHASE_MAX; +} + +static u8 sd_search_final_phase(struct realtek_pci_sdmmc *host, u32 phase_map) +{ + int start = 0, len = 0; + int start_final = 0, len_final = 0; + u8 final_phase = 0xFF; - /* Connect the first and last continuous paths if they are adjacent */ - if (!path[0].start && (path[cont_path_cnt - 1].end == MAX_PHASE)) { - /* Using negative index */ - path[0].start = path[cont_path_cnt - 1].start - MAX_PHASE - 1; - path[0].len += path[cont_path_cnt - 1].len; - path[0].mid = path[0].start + path[0].len / 2; - /* Convert negative middle point index to positive one */ - if (path[0].mid < 0) - path[0].mid += MAX_PHASE + 1; - cont_path_cnt--; + if (phase_map == 0) { + dev_err(sdmmc_dev(host), "phase error: [map:%x]\n", phase_map); + return final_phase; } - /* Choose the longest continuous phase path */ - max_len = 0; - final_phase = 0; - final_path_idx = 0; - for (i = 0; i < cont_path_cnt; i++) { - if (path[i].len > max_len) { - max_len = path[i].len; - final_phase = (u8)path[i].mid; - final_path_idx = i; + while (start < RTSX_PHASE_MAX) { + len = sd_get_phase_len(phase_map, start); + if (len_final < len) { + start_final = start; + len_final = len; } - - dev_dbg(sdmmc_dev(host), "path[%d].start = %d\n", - i, path[i].start); - dev_dbg(sdmmc_dev(host), "path[%d].end = %d\n", - i, path[i].end); - dev_dbg(sdmmc_dev(host), "path[%d].len = %d\n", - i, path[i].len); - dev_dbg(sdmmc_dev(host), "path[%d].mid = %d\n", - i, path[i].mid); + start += len ? len : 1; } -finish: - dev_dbg(sdmmc_dev(host), "Final chosen phase: %d\n", final_phase); + final_phase = (start_final + len_final / 2) % RTSX_PHASE_MAX; + dev_dbg(sdmmc_dev(host), "phase: [map:%x] [maxlen:%d] [final:%d]\n", + phase_map, len_final, final_phase); + return final_phase; } @@ -635,7 +587,7 @@ static int sd_tuning_phase(struct realtek_pci_sdmmc *host, int err, i; u32 raw_phase_map = 0; - for (i = MAX_PHASE; i >= 0; i--) { + for (i = 0; i < RTSX_PHASE_MAX; i++) { err = sd_tuning_rx_cmd(host, opcode, (u8)i); if (err == 0) raw_phase_map |= 1 << i; diff --git a/include/linux/mfd/rtsx_pci.h b/include/linux/mfd/rtsx_pci.h index 0ce772105508..a3835976f7c6 100644 --- a/include/linux/mfd/rtsx_pci.h +++ b/include/linux/mfd/rtsx_pci.h @@ -144,7 +144,7 @@ #define HOST_TO_DEVICE 0 #define DEVICE_TO_HOST 1 -#define MAX_PHASE 31 +#define RTSX_PHASE_MAX 32 #define RX_TUNING_CNT 3 /* SG descriptor */ -- cgit v1.2.3 From c42deffd5b53c9e583d83c7964854ede2f12410d Mon Sep 17 00:00:00 2001 From: Micky Ching Date: Mon, 17 Feb 2014 16:45:48 +0800 Subject: mmc: rtsx: add support for pre_req and post_req Add support for non-blocking request, pre_req() runs dma_map_sg() and post_req() runs dma_unmap_sg(). This patch can increase card read/write speed, especially for high speed card and slow CPU(for some embedded platform). Users can get a great benefit from this patch. if CPU frequency is 800MHz, SDR104 or DDR50 card read/write speed may increase more than 15%. test results: intel i3(800MHz - 2.3GHz), SD card clock 208MHz performance mode(2.3GHz): Before: dd if=/dev/mmcblk0p1 of=/dev/null bs=64k count=1024 67108864 bytes (67 MB) copied, 1.18191 s, 56.8 MB/s After: dd if=/dev/mmcblk0p1 of=/dev/null bs=64k count=1024 67108864 bytes (67 MB) copied, 1.09276 s, 61.4 MB/s powersave mode(800MHz): Before: dd if=/dev/mmcblk0p1 of=/dev/null bs=64k count=1024 67108864 bytes (67 MB) copied, 1.29569 s, 51.8 MB/s After: dd if=/dev/mmcblk0p1 of=/dev/null bs=64k count=1024 67108864 bytes (67 MB) copied, 1.11218 s, 60.3 MB/s Signed-off-by: Micky Ching Signed-off-by: Chris Ball --- drivers/mfd/rtsx_pcr.c | 132 ++++++++---- drivers/mmc/host/rtsx_pci_sdmmc.c | 418 +++++++++++++++++++++++++++++++------- include/linux/mfd/rtsx_common.h | 1 + include/linux/mfd/rtsx_pci.h | 6 + 4 files changed, 448 insertions(+), 109 deletions(-) diff --git a/drivers/mfd/rtsx_pcr.c b/drivers/mfd/rtsx_pcr.c index 1d15735f9ef9..c9de3d598ea5 100644 --- a/drivers/mfd/rtsx_pcr.c +++ b/drivers/mfd/rtsx_pcr.c @@ -338,58 +338,28 @@ int rtsx_pci_transfer_data(struct rtsx_pcr *pcr, struct scatterlist *sglist, int num_sg, bool read, int timeout) { struct completion trans_done; - u8 dir; - int err = 0, i, count; + int err = 0, count; long timeleft; unsigned long flags; - struct scatterlist *sg; - enum dma_data_direction dma_dir; - u32 val; - dma_addr_t addr; - unsigned int len; - - dev_dbg(&(pcr->pci->dev), "--> %s: num_sg = %d\n", __func__, num_sg); - - /* don't transfer data during abort processing */ - if (pcr->remove_pci) - return -EINVAL; - - if ((sglist == NULL) || (num_sg <= 0)) - return -EINVAL; - if (read) { - dir = DEVICE_TO_HOST; - dma_dir = DMA_FROM_DEVICE; - } else { - dir = HOST_TO_DEVICE; - dma_dir = DMA_TO_DEVICE; - } - - count = dma_map_sg(&(pcr->pci->dev), sglist, num_sg, dma_dir); + count = rtsx_pci_dma_map_sg(pcr, sglist, num_sg, read); if (count < 1) { dev_err(&(pcr->pci->dev), "scatterlist map failed\n"); return -EINVAL; } dev_dbg(&(pcr->pci->dev), "DMA mapping count: %d\n", count); - val = ((u32)(dir & 0x01) << 29) | TRIG_DMA | ADMA_MODE; - pcr->sgi = 0; - for_each_sg(sglist, sg, count, i) { - addr = sg_dma_address(sg); - len = sg_dma_len(sg); - rtsx_pci_add_sg_tbl(pcr, addr, len, i == count - 1); - } spin_lock_irqsave(&pcr->lock, flags); pcr->done = &trans_done; pcr->trans_result = TRANS_NOT_READY; init_completion(&trans_done); - rtsx_pci_writel(pcr, RTSX_HDBAR, pcr->host_sg_tbl_addr); - rtsx_pci_writel(pcr, RTSX_HDBCTLR, val); spin_unlock_irqrestore(&pcr->lock, flags); + rtsx_pci_dma_transfer(pcr, sglist, count, read); + timeleft = wait_for_completion_interruptible_timeout( &trans_done, msecs_to_jiffies(timeout)); if (timeleft <= 0) { @@ -413,7 +383,7 @@ out: pcr->done = NULL; spin_unlock_irqrestore(&pcr->lock, flags); - dma_unmap_sg(&(pcr->pci->dev), sglist, num_sg, dma_dir); + rtsx_pci_dma_unmap_sg(pcr, sglist, num_sg, read); if ((err < 0) && (err != -ENODEV)) rtsx_pci_stop_cmd(pcr); @@ -425,6 +395,73 @@ out: } EXPORT_SYMBOL_GPL(rtsx_pci_transfer_data); +int rtsx_pci_dma_map_sg(struct rtsx_pcr *pcr, struct scatterlist *sglist, + int num_sg, bool read) +{ + enum dma_data_direction dir = read ? DMA_FROM_DEVICE : DMA_TO_DEVICE; + + if (pcr->remove_pci) + return -EINVAL; + + if ((sglist == NULL) || num_sg < 1) + return -EINVAL; + + return dma_map_sg(&(pcr->pci->dev), sglist, num_sg, dir); +} +EXPORT_SYMBOL_GPL(rtsx_pci_dma_map_sg); + +int rtsx_pci_dma_unmap_sg(struct rtsx_pcr *pcr, struct scatterlist *sglist, + int num_sg, bool read) +{ + enum dma_data_direction dir = read ? DMA_FROM_DEVICE : DMA_TO_DEVICE; + + if (pcr->remove_pci) + return -EINVAL; + + if (sglist == NULL || num_sg < 1) + return -EINVAL; + + dma_unmap_sg(&(pcr->pci->dev), sglist, num_sg, dir); + return num_sg; +} +