From 0c6b7e6426986ce032937184c18bc87f16a41cba Mon Sep 17 00:00:00 2001 From: Seung-Woo Kim Date: Thu, 14 Feb 2019 15:14:54 +0900 Subject: [PATCH 01/16] ARM: configs: tizen_odroid: enable syscon-reboot-mode config To support reboot-mode, enable syscon-reboot-mode config option. Change-Id: I4fe5074f4eeaec4d27d686e5bea4eaf5820fd640 Signed-off-by: Seung-Woo Kim --- arch/arm/configs/tizen_odroid_defconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm/configs/tizen_odroid_defconfig b/arch/arm/configs/tizen_odroid_defconfig index 9f795ac..7d3b304 100644 --- a/arch/arm/configs/tizen_odroid_defconfig +++ b/arch/arm/configs/tizen_odroid_defconfig @@ -2371,7 +2371,8 @@ CONFIG_POWER_RESET=y # CONFIG_POWER_RESET_VERSATILE is not set CONFIG_POWER_RESET_SYSCON=y CONFIG_POWER_RESET_SYSCON_POWEROFF=y -# CONFIG_SYSCON_REBOOT_MODE is not set +CONFIG_REBOOT_MODE=y +CONFIG_SYSCON_REBOOT_MODE=y CONFIG_POWER_SUPPLY=y # CONFIG_POWER_SUPPLY_DEBUG is not set # CONFIG_PDA_POWER is not set -- 2.7.4 From cf15687a5326e22afba21aa5d9c7289c6a5119fe Mon Sep 17 00:00:00 2001 From: Seung-Woo Kim Date: Thu, 14 Feb 2019 15:15:50 +0900 Subject: [PATCH 02/16] arm64: dts: exynos5433-tm2: add syscon-reboot-mode Add syscon-reboot-mode dt node to support reboot mode. TM2 bootloader uses INFORM3 register to check reboot mode of kernel. Change-Id: I2d5ee09c005f14d4fa7c274fecade920385712e3 Signed-off-by: Seung-Woo Kim --- arch/arm64/boot/dts/exynos/exynos5433-tm2-common.dtsi | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/arm64/boot/dts/exynos/exynos5433-tm2-common.dtsi b/arch/arm64/boot/dts/exynos/exynos5433-tm2-common.dtsi index 4bf0912..b4a3078b 100644 --- a/arch/arm64/boot/dts/exynos/exynos5433-tm2-common.dtsi +++ b/arch/arm64/boot/dts/exynos/exynos5433-tm2-common.dtsi @@ -17,6 +17,7 @@ #include #include #include +#include #include / { @@ -1659,6 +1660,13 @@ &pmu_system_controller { assigned-clocks = <&pmu_system_controller 0>; assigned-clock-parents = <&xxti>; + + syscon-reboot-mode { + compatible = "syscon-reboot-mode"; + offset = <0x80c>; + mode-normal = ; + mode-download = ; + }; }; &serial_1 { -- 2.7.4 From 14e477e84fafd65ba68f4d7504cdc07344e06dff Mon Sep 17 00:00:00 2001 From: Seung-Woo Kim Date: Thu, 14 Feb 2019 15:17:00 +0900 Subject: [PATCH 03/16] arm64: configs: tizen_tm2_defconfig: enable syscon-reboot-mode config To support reboot-mode, enable syscon-reboot-mode config option. Change-Id: I27e2da1f29aa5fa271b0914fd62e38470f47b403 Signed-off-by: Seung-Woo Kim --- arch/arm64/configs/tizen_tm2_defconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm64/configs/tizen_tm2_defconfig b/arch/arm64/configs/tizen_tm2_defconfig index 01329ca..e31014d 100644 --- a/arch/arm64/configs/tizen_tm2_defconfig +++ b/arch/arm64/configs/tizen_tm2_defconfig @@ -2660,7 +2660,8 @@ CONFIG_POWER_RESET_SYSCON=y # CONFIG_POWER_RESET_SYSCON_POWEROFF is not set # CONFIG_POWER_RESET_RMOBILE is not set # CONFIG_POWER_RESET_ZX is not set -# CONFIG_SYSCON_REBOOT_MODE is not set +CONFIG_REBOOT_MODE=y +CONFIG_SYSCON_REBOOT_MODE=y CONFIG_POWER_SUPPLY=y # CONFIG_POWER_SUPPLY_DEBUG is not set # CONFIG_PDA_POWER is not set -- 2.7.4 From 1a85c9feaca04868826e2e49326e3e8cf4e900c4 Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Tue, 13 Nov 2018 12:32:50 +0100 Subject: [PATCH 04/16] rtc: s3c-rtc: Avoid using broken ALMYEAR register (RTC,ALM)YEAR registers of Exynos built-in RTC device contains 3 BCD characters. s3c-rtc driver uses only 2 lower of them and supports years from 2000..2099 range. The third BCD value is typically set to 0, but it looks that handling of it is broken in the hardware. It sometimes defaults to a random (even non-BCD) value. This is not an issue for handling RTCYEAR register, because bcd2bin() properly handles only 8bit values (2 BCD characters, the third one is skipped). The problem is however with ALMYEAR register and proper RTC alarm operation. When YEAREN bit is set for the configured alarm, RTC hardware triggers alarm only when ALMYEAR and RTCYEAR matches. This usually doesn't happen because of the random noise on the third BCD character. Fix this by simply skipping setting ALMYEAR register in alarm configuration. This workaround fixes broken alarm operation on Exynos built-in rtc device. My tests revealed that the issue happens on the following Exynos series: 3250, 4210, 4412, 5250 and 5410. Signed-off-by: Marek Szyprowski Signed-off-by: Alexandre Belloni [backport of mainline commit 50c8aec4212a966817e868056efc9bfbb73337c0] Signed-off-by: Marek Szyprowski Change-Id: I057ae196eeaa9a2c0fee5fcf4c66625783cdfc21 --- drivers/rtc/rtc-s3c.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c index a8992c2..4120a30 100644 --- a/drivers/rtc/rtc-s3c.c +++ b/drivers/rtc/rtc-s3c.c @@ -327,7 +327,6 @@ static int s3c_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) struct rtc_time *tm = &alrm->time; unsigned int alrm_en; int ret; - int year = tm->tm_year - 100; dev_dbg(dev, "s3c_rtc_setalarm: %d, %04d.%02d.%02d %02d:%02d:%02d\n", alrm->enabled, @@ -356,11 +355,6 @@ static int s3c_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) writeb(bin2bcd(tm->tm_hour), info->base + S3C2410_ALMHOUR); } - if (year < 100 && year >= 0) { - alrm_en |= S3C2410_RTCALM_YEAREN; - writeb(bin2bcd(year), info->base + S3C2410_ALMYEAR); - } - if (tm->tm_mon < 12 && tm->tm_mon >= 0) { alrm_en |= S3C2410_RTCALM_MONEN; writeb(bin2bcd(tm->tm_mon + 1), info->base + S3C2410_ALMMON); -- 2.7.4 From 09631c84ac395e8da3c4d45722da7c9e7eb1062c Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Mon, 21 Jan 2019 12:09:30 +0100 Subject: [PATCH 05/16] rtc: s3c: Rewrite clock handling s3c_rtc_enable/disable_clk() functions were designed to be called multiple times without reference counting, because they were initially only used in alarm setting/clearing functions, which can be called both when alarm is already set or not. Later however, calls to those functions have been added to other places in the driver - like time and /proc reading callbacks, what results in broken alarm if any of such events happens after the alarm has been set. Fix this by simplifying s3c_rtc_enable/disable_clk() functions to rely on proper reference counting in clock core and move alarm enable counter to s3c_rtc_setaie() function. Signed-off-by: Marek Szyprowski Reviewed-by: Krzysztof Kozlowski Signed-off-by: Alexandre Belloni [backport of mainline commit 5a5b614ba61cc2a89ad0dffc63d913a1a6ba1f9f] Signed-off-by: Marek Szyprowski Change-Id: Ib72a76ea0567ece0b7b5b706f2ee3b6cca850150 --- drivers/rtc/rtc-s3c.c | 74 +++++++++++++++++++++------------------------------ 1 file changed, 31 insertions(+), 43 deletions(-) diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c index 4120a30..624ca24 100644 --- a/drivers/rtc/rtc-s3c.c +++ b/drivers/rtc/rtc-s3c.c @@ -39,7 +39,7 @@ struct s3c_rtc { void __iomem *base; struct clk *rtc_clk; struct clk *rtc_src_clk; - bool clk_disabled; + bool alarm_enabled; const struct s3c_rtc_data *data; @@ -47,7 +47,7 @@ struct s3c_rtc { int irq_tick; spinlock_t pie_lock; - spinlock_t alarm_clk_lock; + spinlock_t alarm_lock; int ticnt_save; int ticnt_en_save; @@ -70,44 +70,27 @@ struct s3c_rtc_data { static int s3c_rtc_enable_clk(struct s3c_rtc *info) { - unsigned long irq_flags; - int ret = 0; + int ret; - spin_lock_irqsave(&info->alarm_clk_lock, irq_flags); + ret = clk_enable(info->rtc_clk); + if (ret) + return ret; - if (info->clk_disabled) { - ret = clk_enable(info->rtc_clk); - if (ret) - goto out; - - if (info->data->needs_src_clk) { - ret = clk_enable(info->rtc_src_clk); - if (ret) { - clk_disable(info->rtc_clk); - goto out; - } + if (info->data->needs_src_clk) { + ret = clk_enable(info->rtc_src_clk); + if (ret) { + clk_disable(info->rtc_clk); + return ret; } - info->clk_disabled = false; } - -out: - spin_unlock_irqrestore(&info->alarm_clk_lock, irq_flags); - - return ret; + return 0; } static void s3c_rtc_disable_clk(struct s3c_rtc *info) { - unsigned long irq_flags; - - spin_lock_irqsave(&info->alarm_clk_lock, irq_flags); - if (!info->clk_disabled) { - if (info->data->needs_src_clk) - clk_disable(info->rtc_src_clk); - clk_disable(info->rtc_clk); - info->clk_disabled = true; - } - spin_unlock_irqrestore(&info->alarm_clk_lock, irq_flags); + if (info->data->needs_src_clk) + clk_disable(info->rtc_src_clk); + clk_disable(info->rtc_clk); } /* IRQ Handlers */ @@ -135,6 +118,7 @@ static irqreturn_t s3c_rtc_alarmirq(int irq, void *id) static int s3c_rtc_setaie(struct device *dev, unsigned int enabled) { struct s3c_rtc *info = dev_get_drvdata(dev); + unsigned long flags; unsigned int tmp; int ret; @@ -151,17 +135,19 @@ static int s3c_rtc_setaie(struct device *dev, unsigned int enabled) writeb(tmp, info->base + S3C2410_RTCALM); - s3c_rtc_disable_clk(info); + spin_lock_irqsave(&info->alarm_lock, flags); - if (enabled) { - ret = s3c_rtc_enable_clk(info); - if (ret) - return ret; - } else { + if (info->alarm_enabled && !enabled) s3c_rtc_disable_clk(info); - } + else if (!info->alarm_enabled && enabled) + ret = s3c_rtc_enable_clk(info); - return 0; + info->alarm_enabled = enabled; + spin_unlock_irqrestore(&info->alarm_lock, flags); + + s3c_rtc_disable_clk(info); + + return ret; } /* Set RTC frequency */ @@ -369,10 +355,10 @@ static int s3c_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) writeb(alrm_en, info->base + S3C2410_RTCALM); - s3c_rtc_disable_clk(info); - s3c_rtc_setaie(dev, alrm->enabled); + s3c_rtc_disable_clk(info); + return 0; } @@ -503,7 +489,7 @@ static int s3c_rtc_probe(struct platform_device *pdev) return -EINVAL; } spin_lock_init(&info->pie_lock); - spin_lock_init(&info->alarm_clk_lock); + spin_lock_init(&info->alarm_lock); platform_set_drvdata(pdev, info); @@ -603,6 +589,8 @@ static int s3c_rtc_probe(struct platform_device *pdev) s3c_rtc_setfreq(info, 1); + s3c_rtc_disable_clk(info); + return 0; err_nortc: -- 2.7.4 From 50162a91958ab6eca749d9fc86306e435263ed9a Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Fri, 18 Jan 2019 14:28:37 +0100 Subject: [PATCH 06/16] rtc: s3c: Use generic helper to get driver data Replace of_match_node() with of_device_get_match_data(), which removes a few lines of code from the driver. Signed-off-by: Marek Szyprowski Reviewed-by: Krzysztof Kozlowski Signed-off-by: Alexandre Belloni [backport of mainline commit 64704c92fd19c599f20433aae1372a7ccab79a57] Signed-off-by: Marek Szyprowski Change-Id: I9e3a1662233334925ca9ace34609468dc8bc0a14 --- drivers/rtc/rtc-s3c.c | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c index 624ca24..269032a 100644 --- a/drivers/rtc/rtc-s3c.c +++ b/drivers/rtc/rtc-s3c.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -454,16 +455,6 @@ static int s3c_rtc_remove(struct platform_device *pdev) return 0; } -static const struct of_device_id s3c_rtc_dt_match[]; - -static const struct s3c_rtc_data *s3c_rtc_get_data(struct platform_device *pdev) -{ - const struct of_device_id *match; - - match = of_match_node(s3c_rtc_dt_match, pdev->dev.of_node); - return match->data; -} - static int s3c_rtc_probe(struct platform_device *pdev) { struct s3c_rtc *info = NULL; @@ -483,7 +474,7 @@ static int s3c_rtc_probe(struct platform_device *pdev) } info->dev = &pdev->dev; - info->data = s3c_rtc_get_data(pdev); + info->data = of_device_get_match_data(&pdev->dev); if (!info->data) { dev_err(&pdev->dev, "failed getting s3c_rtc_data\n"); return -EINVAL; -- 2.7.4 From 2c5198b5deb9d32049e848cfb60c4c5949bbcdfb Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Fri, 25 Jan 2019 14:49:53 +0100 Subject: [PATCH 07/16] devfreq: Suspend all devices on system shutdown This way devfreq core ensures that all its devices will be set to safe operation points before reboot operation. There are board on which some aggressive power saving operation points are behind the capabilities of the bootloader to properly reset the hardware and boot the board. This way one can avoid board crash early after reboot. Similar pattern is used in CPUfreq subsystem. Reported-by: Markus Reichl Signed-off-by: Marek Szyprowski Change-Id: I45467c8e02f7fedf90d1dfd5080e6143a8cb69f7 --- drivers/devfreq/devfreq.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c index 5db7249..2a08edc 100644 --- a/drivers/devfreq/devfreq.c +++ b/drivers/devfreq/devfreq.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -1421,6 +1422,10 @@ static struct attribute *devfreq_attrs[] = { }; ATTRIBUTE_GROUPS(devfreq); +static struct syscore_ops devfreq_syscore_ops = { + .shutdown = devfreq_suspend, +}; + static int __init devfreq_init(void) { devfreq_class = class_create(THIS_MODULE, "devfreq"); @@ -1437,6 +1442,8 @@ static int __init devfreq_init(void) } devfreq_class->dev_groups = devfreq_groups; + register_syscore_ops(&devfreq_syscore_ops); + return 0; } subsys_initcall(devfreq_init); -- 2.7.4 From 499b3a512e1493ebdd056c92c24ac06c1010de88 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Tue, 12 Feb 2019 12:36:46 +0530 Subject: [PATCH 08/16] cpufreq: Allow light-weight tear down and bring up of CPUs The cpufreq core doesn't remove the cpufreq policy anymore on CPU offline operation, rather that happens when the CPU device gets unregistered from the kernel. This allows faster recovery when the CPU comes back online. This is also very useful during system wide suspend/resume where we offline all non-boot CPUs during suspend and then bring them back on resume. This commit takes the same idea a step ahead to allow drivers to do light weight tear-down and bring-up during CPU offline and online operations. A new set of callbacks is introduced, online/offline(). online() gets called when the first CPU of an inactive policy is brought up and offline() gets called when all the CPUs of a policy are offlined. The existing init/exit() callback get called on policy creation/destruction. They also get called instead of online/offline() callbacks if the online/offline() callbacks aren't provided. This also moves around some code to get executed only for the new-policy case going forward. Signed-off-by: Viresh Kumar [pending patch for mainline] Signed-off-by: Marek Szyprowski Change-Id: I27bd475cac802ffae345308fc145490966eda456 --- drivers/cpufreq/cpufreq.c | 49 +++++++++++++++++++++++++++++++---------------- include/linux/cpufreq.h | 2 ++ 2 files changed, 35 insertions(+), 16 deletions(-) diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 9375430..6f34365 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -1198,24 +1198,35 @@ static int cpufreq_online(unsigned int cpu) return -ENOMEM; } - cpumask_copy(policy->cpus, cpumask_of(cpu)); + if (!new_policy && cpufreq_driver->online) { + ret = cpufreq_driver->online(policy); + if (ret) { + pr_debug("%s: %d: initialization failed\n", __func__, + __LINE__); + goto out_exit_policy; + } - /* call driver. From then on the cpufreq must be able - * to accept all calls to ->verify and ->setpolicy for this CPU - */ - ret = cpufreq_driver->init(policy); - if (ret) { - pr_debug("initialization failed\n"); - goto out_free_policy; - } + /* Recover policy->cpus using related_cpus */ + cpumask_copy(policy->cpus, policy->related_cpus); + } else { + cpumask_copy(policy->cpus, cpumask_of(cpu)); - down_write(&policy->rwsem); + /* + * Call driver. From then on the cpufreq must be able + * to accept all calls to ->verify and ->setpolicy for this CPU. + */ + ret = cpufreq_driver->init(policy); + if (ret) { + pr_debug("%s: %d: initialization failed\n", __func__, + __LINE__); + goto out_free_policy; + } - if (new_policy) { /* related_cpus should at least include policy->cpus. */ cpumask_copy(policy->related_cpus, policy->cpus); } + down_write(&policy->rwsem); /* * affected cpus must always be the one, which are online. We aren't * managing offline cpus here. @@ -1405,11 +1416,12 @@ static int cpufreq_offline(unsigned int cpu) cpufreq_exit_governor(policy); /* - * Perform the ->exit() even during light-weight tear-down, - * since this is a core component, and is essential for the - * subsequent light-weight ->init() to succeed. + * Perform the ->offline() during light-weight tear-down, as + * that allows fast recovery when the CPU comes back. */ - if (cpufreq_driver->exit) { + if (cpufreq_driver->offline) { + cpufreq_driver->offline(policy); + } else if (cpufreq_driver->exit) { cpufreq_driver->exit(policy); policy->freq_table = NULL; } @@ -1438,8 +1450,13 @@ static void cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif) cpumask_clear_cpu(cpu, policy->real_cpus); remove_cpu_dev_symlink(policy, dev); - if (cpumask_empty(policy->real_cpus)) + if (cpumask_empty(policy->real_cpus)) { + /* We did light-weight exit earlier, do full tear down now */ + if (cpufreq_driver->offline) + cpufreq_driver->exit(policy); + cpufreq_policy_free(policy); + } } /** diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index cbf85c4..2682c20 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -330,6 +330,8 @@ struct cpufreq_driver { /* optional */ int (*bios_limit)(int cpu, unsigned int *limit); + int (*online)(struct cpufreq_policy *policy); + int (*offline)(struct cpufreq_policy *policy); int (*exit)(struct cpufreq_policy *policy); void (*stop_cpu)(struct cpufreq_policy *policy); int (*suspend)(struct cpufreq_policy *policy); -- 2.7.4 From 85d986cd0f071770713d94ff5eb4adcaff24fecf Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Tue, 12 Feb 2019 12:36:47 +0530 Subject: [PATCH 09/16] cpufreq: dt: Implement online/offline() callbacks Implement the light-weight tear down and bring up helpers to reduce the amount of work to do on CPU offline/online operation. Signed-off-by: Viresh Kumar [pending patch for mainline] Signed-off-by: Marek Szyprowski Change-Id: I02a01f0f4d5c24102bcc58089937c371cc126b65 --- drivers/cpufreq/cpufreq-dt.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/drivers/cpufreq/cpufreq-dt.c b/drivers/cpufreq/cpufreq-dt.c index ca6ee9f..1648806 100644 --- a/drivers/cpufreq/cpufreq-dt.c +++ b/drivers/cpufreq/cpufreq-dt.c @@ -295,6 +295,21 @@ out_put_clk: return ret; } +static int cpufreq_online(struct cpufreq_policy *policy) +{ + /* We did light-weight tear down earlier, nothing to do here */ + return 0; +} + +static int cpufreq_offline(struct cpufreq_policy *policy) +{ + /* + * Preserve policy->driver_data and don't free resources on light-weight + * tear down. + */ + return 0; +} + static int cpufreq_exit(struct cpufreq_policy *policy) { struct private_data *priv = policy->driver_data; @@ -352,6 +367,8 @@ static struct cpufreq_driver dt_cpufreq_driver = { .init = cpufreq_init, .exit = cpufreq_exit, .ready = cpufreq_ready, + .online = cpufreq_online, + .offline = cpufreq_offline, .name = "cpufreq-dt", .attr = cpufreq_dt_attr, .suspend = cpufreq_generic_suspend, -- 2.7.4 From ef0131b58bf95da8a5eea26f5b7856ea571ff193 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Mon, 4 Feb 2019 16:01:55 +0100 Subject: [PATCH 10/16] arm: Use common outgoing-CPU-notification code This commit removes the open-coded CPU-offline notification with new common code. In particular, this change avoids calling scheduler code using RCU from an offline CPU that RCU is ignoring. This is a minimal change. A more intrusive change might invoke the cpu_check_up_prepare() and cpu_set_state_online() functions at CPU-online time, which would allow onlining throw an error if the CPU did not go offline properly. Signed-off-by: Paul E. McKenney Cc: linux-arm-kernel@lists.infradead.org Cc: Russell King [commit rejected in mainline, but needed on Exynos platform to fix suspicious RCU usage during suspend/resume] Signed-off-by: Marek Szyprowski Change-Id: I26ba637d48fc3264e1b79507cfd0cb82bb5e6390 --- arch/arm/kernel/smp.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index 5e31c62..80811a4 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -242,15 +242,13 @@ int __cpu_disable(void) return 0; } -static DECLARE_COMPLETION(cpu_died); - /* * called on the thread which is asking for a CPU to be shutdown - * waits until shutdown has completed, or it is timed out. */ void __cpu_die(unsigned int cpu) { - if (!wait_for_completion_timeout(&cpu_died, msecs_to_jiffies(5000))) { + if (!cpu_wait_death(cpu, 5)) { pr_err("CPU%u: cpu didn't die\n", cpu); return; } @@ -296,7 +294,7 @@ void arch_cpu_idle_dead(void) * this returns, power and/or clocks can be removed at any point * from this CPU and its cache by platform_cpu_kill(). */ - complete(&cpu_died); + (void)cpu_report_death(); /* * Ensure that the cache lines associated with that completion are -- 2.7.4 From 38aadf7e1025ba31a9961817c993150916ef693a Mon Sep 17 00:00:00 2001 From: Stuart Menefy Date: Mon, 28 Jan 2019 23:06:45 +0000 Subject: [PATCH 11/16] ARM: exynos: Fix timeout when booting secondary CPUs Without this fix the loop waiting for the timeout exits, but the subsequent test to see if the timeout occurred fails. Signed-off-by: Stuart Menefy Signed-off-by: Krzysztof Kozlowski [backport of mainline commit 4bdf2f3f20a9de9b07f97907820c42f3a49ba63d] Signed-off-by: Marek Szyprowski Change-Id: If43a148b759fa015abd46fdfb60d64fdfe3baf5f --- arch/arm/mach-exynos/platsmp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-exynos/platsmp.c b/arch/arm/mach-exynos/platsmp.c index cb6d199..9b9f6fc 100644 --- a/arch/arm/mach-exynos/platsmp.c +++ b/arch/arm/mach-exynos/platsmp.c @@ -326,9 +326,9 @@ static int exynos_boot_secondary(unsigned int cpu, struct task_struct *idle) /* wait max 10 ms until cpu1 is on */ while (exynos_cpu_power_state(core_id) != S5P_CORE_LOCAL_PWR_EN) { - if (timeout-- == 0) + if (timeout == 0) break; - + timeout--; mdelay(1); } -- 2.7.4 From 9de9c3af6677c5d8aaad9c1cf3cc6fb74214e2fb Mon Sep 17 00:00:00 2001 From: Stuart Menefy Date: Sun, 10 Feb 2019 22:51:13 +0000 Subject: [PATCH 12/16] clocksource: exynos_mct: Move one-shot check from tick clear to ISR When a timer tick occurs and the clock is in one-shot mode, the timer needs to be stopped to prevent it triggering subsequent interrupts. Currently this code is in exynos4_mct_tick_clear(), but as it is only needed when an ISR occurs move it into exynos4_mct_tick_isr(), leaving exynos4_mct_tick_clear() just doing what its name suggests it should. Signed-off-by: Stuart Menefy [pending patch for mainline] Signed-off-by: Marek Szyprowski Change-Id: I1004b6947a338d27dc629f4174607663dedc1f33 --- drivers/clocksource/exynos_mct.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/clocksource/exynos_mct.c b/drivers/clocksource/exynos_mct.c index 7a244b6..1e325f8 100644 --- a/drivers/clocksource/exynos_mct.c +++ b/drivers/clocksource/exynos_mct.c @@ -388,6 +388,13 @@ static void exynos4_mct_tick_start(unsigned long cycles, exynos4_mct_write(tmp, mevt->base + MCT_L_TCON_OFFSET); } +static void exynos4_mct_tick_clear(struct mct_clock_event_device *mevt) +{ + /* Clear the MCT tick interrupt */ + if (readl_relaxed(reg_base + mevt->base + MCT_L_INT_CSTAT_OFFSET) & 1) + exynos4_mct_write(0x1, mevt->base + MCT_L_INT_CSTAT_OFFSET); +} + static int exynos4_tick_set_next_event(unsigned long cycles, struct clock_event_device *evt) { @@ -420,8 +427,11 @@ static int set_state_periodic(struct clock_event_device *evt) return 0; } -static void exynos4_mct_tick_clear(struct mct_clock_event_device *mevt) +static irqreturn_t exynos4_mct_tick_isr(int irq, void *dev_id) { + struct mct_clock_event_device *mevt = dev_id; + struct clock_event_device *evt = &mevt->evt; + /* * This is for supporting oneshot mode. * Mct would generate interrupt periodically @@ -430,16 +440,6 @@ static void exynos4_mct_tick_clear(struct mct_clock_event_device *mevt) if (!clockevent_state_periodic(&mevt->evt)) exynos4_mct_tick_stop(mevt); - /* Clear the MCT tick interrupt */ - if (readl_relaxed(reg_base + mevt->base + MCT_L_INT_CSTAT_OFFSET) & 1) - exynos4_mct_write(0x1, mevt->base + MCT_L_INT_CSTAT_OFFSET); -} - -static irqreturn_t exynos4_mct_tick_isr(int irq, void *dev_id) -{ - struct mct_clock_event_device *mevt = dev_id; - struct clock_event_device *evt = &mevt->evt; - exynos4_mct_tick_clear(mevt); evt->event_handler(evt); -- 2.7.4 From fd05744784293aec511d0472f3e897846a17303d Mon Sep 17 00:00:00 2001 From: Stuart Menefy Date: Sun, 10 Feb 2019 22:51:14 +0000 Subject: [PATCH 13/16] clocksource: exynos_mct: Clear timer interrupt when shutdown When shutting down the timer, ensure that after we have stopped the timer any pending interrupts are cleared. This fixes a problem when suspending, as interrupts are disabled before the timer is stopped, so the timer interrupt may still be asserted, preventing the system entering a low power state when the wfi is executed. Signed-off-by: Stuart Menefy [pending patch for mainline] Signed-off-by: Marek Szyprowski Change-Id: I2068bbadeb5e778bb81f772693e30a47e64dd77c --- drivers/clocksource/exynos_mct.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clocksource/exynos_mct.c b/drivers/clocksource/exynos_mct.c index 1e325f8..d55c30f 100644 --- a/drivers/clocksource/exynos_mct.c +++ b/drivers/clocksource/exynos_mct.c @@ -411,6 +411,7 @@ static int set_state_shutdown(struct clock_event_device *evt) mevt = container_of(evt, struct mct_clock_event_device, evt); exynos4_mct_tick_stop(mevt); + exynos4_mct_tick_clear(mevt); return 0; } -- 2.7.4 From cc96612c12ef0833a332f21c6b6605894a91bead Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Thu, 14 Feb 2019 11:12:46 +0100 Subject: [PATCH 14/16] ARM: exynos: Fix undefined instruction during Exynos5422 resume During early system resume on Exynos5422 with performance counters enabled the following kernel oops happens: Internal error: Oops - undefined instruction: 0 [#1] PREEMPT SMP ARM Modules linked in: CPU: 0 PID: 1433 Comm: bash Tainted: G W 5.0.0-rc5-next-20190208-00023-gd5fb5a8a13e6-dirty #5480 Hardware name: SAMSUNG EXYNOS (Flattened Device Tree) PC is at reset_ctrl_regs+0x128/0x354 LR is at reset_ctrl_regs+0x124/0x354 pc : [] lr : [] psr: 600001d3 ... Flags: nZCv IRQs off FIQs off Mode SVC_32 ISA ARM Segment none Control: 10c5387d Table: 4451006a DAC: 00000051 Process bash (pid: 1433, stack limit = 0xb7e0e22f) ... [] (reset_ctrl_regs) from [] (dbg_cpu_pm_notify+0x1c/0x24) [] (dbg_cpu_pm_notify) from [] (notifier_call_chain+0x44/0x84) [] (notifier_call_chain) from [] (__atomic_notifier_call_chain+0x7c/0x128) [] (__atomic_notifier_call_chain) from [] (cpu_pm_notify+0x30/0x54) [] (cpu_pm_notify) from [] (syscore_resume+0x98/0x3f4) [] (syscore_resume) from [] (suspend_devices_and_enter+0x97c/0xe74) [] (suspend_devices_and_enter) from [] (pm_suspend+0x770/0xc04) [] (pm_suspend) from [] (state_store+0x6c/0xcc) [] (state_store) from [] (kobj_attr_store+0x14/0x20) [] (kobj_attr_store) from [] (sysfs_kf_write+0x4c/0x50) [] (sysfs_kf_write) from [] (kernfs_fop_write+0xfc/0x1e0) [] (kernfs_fop_write) from [] (__vfs_write+0x2c/0x160) [] (__vfs_write) from [] (vfs_write+0xa4/0x16c) [] (vfs_write) from [] (ksys_write+0x40/0x8c) [] (ksys_write) from [] (ret_fast_syscall+0x0/0x28) ... ---[ end trace 03fc9866185939bf ]--- Undefined instruction is triggered during CP14 reset, because bits: #16 (Secure privileged invasive debug disabled) and #17 (Secure privileged noninvasive debug disable) are set in DSCR. Those bits depend on SPNIDEN and SPIDEN lines, which are provided by Secure JTAG hardware block. That block in turn is powered from cluster 0 (big/Eagle), but the Exynos5422 boots on cluster 1 (LITTLE/KFC). To fix this issue it is enough to turn on the power on the cluster 0 for a while. This lets the Secure JTAG block to propagate the needed signals to LITTLE/KFC cores and change their DSCR. Signed-off-by: Marek Szyprowski Change-Id: I0fa6618740853169bd96efeb33975f0289ac3706 --- arch/arm/mach-exynos/suspend.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/arch/arm/mach-exynos/suspend.c b/arch/arm/mach-exynos/suspend.c index fcc8390..49bb921 100644 --- a/arch/arm/mach-exynos/suspend.c +++ b/arch/arm/mach-exynos/suspend.c @@ -453,8 +453,27 @@ early_wakeup: static void exynos5420_prepare_pm_resume(void) { + unsigned int mpidr, cluster; + + mpidr = read_cpuid_mpidr(); + cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1); + if (IS_ENABLED(CONFIG_EXYNOS5420_MCPM)) WARN_ON(mcpm_cpu_powered_up()); + + if (IS_ENABLED(CONFIG_HW_PERF_EVENTS) && cluster != 0) { + /* + * When system is resumed on the LITTLE/KFC core (cluster 1), + * the DSCR is not properly updated until the power is turned + * on also for the cluster 0. Enable it for a while to + * propagate the SPNIDEN and SPIDEN signals from Secure JTAG + * block and avoid undefined instruction issue on CP14 reset. + */ + pmu_raw_writel(S5P_CORE_LOCAL_PWR_EN, + EXYNOS_COMMON_CONFIGURATION(0)); + pmu_raw_writel(0, + EXYNOS_COMMON_CONFIGURATION(0)); + } } static void exynos5420_pm_resume(void) -- 2.7.4 From 5898a1c967a00c66d4bf863b6fb5b2ada89a71fb Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Wed, 13 Feb 2019 13:02:25 +0100 Subject: [PATCH 15/16] ARM: pm: fix HYP/SVC mode mismatch when MCPM is used MCPM does a soft reset of the CPUs and uses common cpu_resume() routine to perform low-level platform initialization. This results in a try to install HYP stubs for the second time for each CPU and results in false HYP/SVC mode mismatch detection. The HYP stubs are already installed at the beginning of the kernel initialization on the boot CPU (head.S) or in the secondary_startup() for other CPUs. To fix this issue MCPM code should use a cpu_resume() routine without HYP stubs installation. This change fixes HYP/SVC mode mismatch on Samsung Exynos5422-based Odroid XU3/XU4/HC1 boards. Fixes: 3721924c8154 ("ARM: 8081/1: MCPM: provide infrastructure to allow for MCPM loopback") Signed-off-by: Marek Szyprowski Acked-by: Nicolas Pitre Tested-by: Anand Moon Change-Id: I6f6225fd2a7e57e323010af616a6fdd4774a7222 --- arch/arm/common/mcpm_entry.c | 2 +- arch/arm/include/asm/suspend.h | 1 + arch/arm/kernel/sleep.S | 12 ++++++++++++ 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/arch/arm/common/mcpm_entry.c b/arch/arm/common/mcpm_entry.c index 2b913f1..c24a55b 100644 --- a/arch/arm/common/mcpm_entry.c +++ b/arch/arm/common/mcpm_entry.c @@ -379,7 +379,7 @@ static int __init nocache_trampoline(unsigned long _arg) unsigned int cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1); phys_reset_t phys_reset; - mcpm_set_entry_vector(cpu, cluster, cpu_resume); + mcpm_set_entry_vector(cpu, cluster, cpu_resume_no_hyp); setup_mm_for_reboot(); __mcpm_cpu_going_down(cpu, cluster); diff --git a/arch/arm/include/asm/suspend.h b/arch/arm/include/asm/suspend.h index 452bbdc..5063142 100644 --- a/arch/arm/include/asm/suspend.h +++ b/arch/arm/include/asm/suspend.h @@ -10,6 +10,7 @@ struct sleep_save_sp { }; extern void cpu_resume(void); +extern void cpu_resume_no_hyp(void); extern void cpu_resume_arm(void); extern int cpu_suspend(unsigned long, int (*)(unsigned long)); diff --git a/arch/arm/kernel/sleep.S b/arch/arm/kernel/sleep.S index a8257fc..5dc8b80 100644 --- a/arch/arm/kernel/sleep.S +++ b/arch/arm/kernel/sleep.S @@ -120,6 +120,14 @@ ENDPROC(cpu_resume_after_mmu) .text .align +#ifdef CONFIG_MCPM + .arm +THUMB( .thumb ) +ENTRY(cpu_resume_no_hyp) +ARM_BE8(setend be) @ ensure we are in BE mode + b no_hyp +#endif + #ifdef CONFIG_MMU .arm ENTRY(cpu_resume_arm) @@ -135,6 +143,7 @@ ARM_BE8(setend be) @ ensure we are in BE mode bl __hyp_stub_install_secondary #endif safe_svcmode_maskall r1 +no_hyp: mov r1, #0 ALT_SMP(mrc p15, 0, r0, c0, c0, 5) ALT_UP_B(1f) @@ -164,6 +173,9 @@ ENDPROC(cpu_resume) #ifdef CONFIG_MMU ENDPROC(cpu_resume_arm) #endif +#ifdef CONFIG_MCPM +ENDPROC(cpu_resume_no_hyp) +#endif .align 2 _sleep_save_sp: -- 2.7.4 From 54d9cf9443519b1596a91ec18e6f2269889bcfd6 Mon Sep 17 00:00:00 2001 From: Jaehoon Chung Date: Tue, 29 Mar 2016 19:43:34 +0900 Subject: [PATCH 16/16] mmc: block: Support the fixed index for mmcblk with aliases nodes Now, index of mmcblk is allocated in accordance with probing time. If want to use the mmcblk1 for some device, it can use alias. aliases { mmc0 = &mmc0; /* mmcblk0 for eMMC */ mmc1 = &mmc2; /* mmcblk1 for SD */ mmc2 = &mmc1; /* mmcblk2 for SDIO*/ }; If there are no corresponding values, it might be allocated with existing scheme. Signed-off-by: Jaehoon Chung [sw0312.kim: port to v4.14 - apply to host index instead of name_idx because host index is used in this version ] Signed-off-by: Seung-Woo Kim Change-Id: I44673d62e546ea0aeedd9cac314dbfd31fdcce66 --- Documentation/devicetree/bindings/mmc/mmc.txt | 12 ++++++++++++ drivers/mmc/core/host.c | 6 +++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/mmc/mmc.txt b/Documentation/devicetree/bindings/mmc/mmc.txt index b32ade64..a6f51dd 100644 --- a/Documentation/devicetree/bindings/mmc/mmc.txt +++ b/Documentation/devicetree/bindings/mmc/mmc.txt @@ -76,6 +76,11 @@ Optional SDIO properties: - wakeup-source: Enables wake up of host system on SDIO IRQ assertion (Legacy property supported: "enable-sdio-wakeup") +Aliases (Optional): +- If you want to use the fixed index for block device like mmcblkX, should be +represented in the aliases node using following format "mmc(X)". +(X is an unique number for the alias.) + MMC power --------- @@ -162,3 +167,10 @@ mmc3: mmc@01c12000 { interrupt-names = "host-wake"; }; }; + +Example with aliases nodes: + +aliases { + mmc0 = &mmc0; /* Fixed to mmcblk0 for &mmc0 */ + mmc1 = &mmc2; /* Fixed to mmcblk1 for &mmc2 */ +}; diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c index ad88deb..390e676 100644 --- a/drivers/mmc/core/host.c +++ b/drivers/mmc/core/host.c @@ -349,6 +349,7 @@ EXPORT_SYMBOL(mmc_of_parse); struct mmc_host *mmc_alloc_host(int extra, struct device *dev) { int err; + int idx = 0; struct mmc_host *host; host = kzalloc(sizeof(struct mmc_host) + extra, GFP_KERNEL); @@ -358,7 +359,10 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev) /* scanning will be enabled when we're ready */ host->rescan_disable = 1; - err = ida_simple_get(&mmc_host_ida, 0, 0, GFP_KERNEL); + if (dev->of_node) + idx = of_alias_get_id(dev->of_node, "mmc"); + + err = ida_simple_get(&mmc_host_ida, (idx < 0) ? 0 : idx, 0, GFP_KERNEL); if (err < 0) { kfree(host); return NULL; -- 2.7.4