Currently, if we test hibernation, it will fails at the ITS driver, because its can't resume and suspend successuly during the phase of hibernation.
Add its herbinate state to support its resume correctly.
Hongbo Yao (2): PM / hibernate: introduce system_in_hibernation irqchip/gic-v3-its: its support herbination
drivers/irqchip/irq-gic-v3-its.c | 19 +++++++++++++++++-- include/linux/suspend.h | 2 ++ kernel/power/hibernate.c | 11 +++++++++++ 3 files changed, 30 insertions(+), 2 deletions(-)
From: Hongbo Yao yaohongbo@huawei.com
hulk inclusion category: bugfix bugzilla: 26326 CVE: NA
------------------------------------------------- Introduce boolean function system_in_hibernation() returning 'true' when the system carrying out hibernation.
Some device drivers or syscore need such a function to check if it is in the phase of hibernation.
Signed-off-by: Hongbo Yao yaohongbo@huawei.com Reviewed-by: Hanjun Guo guohanjun@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- include/linux/suspend.h | 2 ++ kernel/power/hibernate.c | 11 +++++++++++ 2 files changed, 13 insertions(+)
diff --git a/include/linux/suspend.h b/include/linux/suspend.h index 50e81bf..aff2489 100644 --- a/include/linux/suspend.h +++ b/include/linux/suspend.h @@ -414,6 +414,7 @@ static inline void __init register_nosave_region_late(unsigned long b, unsigned extern void hibernation_set_ops(const struct platform_hibernation_ops *ops); extern int hibernate(void); extern bool system_entering_hibernation(void); +extern bool system_in_hibernation(void); extern bool hibernation_available(void); asmlinkage int swsusp_save(void); extern struct pbe *restore_pblist; @@ -427,6 +428,7 @@ static inline void swsusp_unset_page_free(struct page *p) {} static inline void hibernation_set_ops(const struct platform_hibernation_ops *ops) {} static inline int hibernate(void) { return -ENOSYS; } static inline bool system_entering_hibernation(void) { return false; } +static inline bool system_in_hibernation(void) { return false; } static inline bool hibernation_available(void) { return false; } #endif /* CONFIG_HIBERNATION */
diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c index f5ce9f7..72ef9df 100644 --- a/kernel/power/hibernate.c +++ b/kernel/power/hibernate.c @@ -104,6 +104,15 @@ bool system_entering_hibernation(void) } EXPORT_SYMBOL(system_entering_hibernation);
+/* To let some devices or syscore know if system carrying out hibernation*/ +static bool carry_out_hibernation; + +bool system_in_hibernation(void) +{ + return carry_out_hibernation; +} +EXPORT_SYMBOL(system_in_hibernation); + #ifdef CONFIG_PM_DEBUG static void hibernation_debug_sleep(void) { @@ -711,6 +720,7 @@ int hibernate(void) }
pr_info("hibernation entry\n"); + carry_out_hibernation = true; pm_prepare_console(); error = __pm_notifier_call_chain(PM_HIBERNATION_PREPARE, -1, &nr_calls); if (error) { @@ -781,6 +791,7 @@ int hibernate(void) atomic_inc(&snapshot_device_available); Unlock: unlock_system_sleep(); + carry_out_hibernation = false; pr_info("hibernation exit\n");
return error;
From: Hongbo Yao yaohongbo@huawei.com
hulk inclusion category: bugfix bugzilla: 26326 CVE: NA
-------------------------------------------------
Currently, when we test hibernation, it will fail at the ITS. [11384.327419] Call trace: [11384.329854] dump_backtrace+0x0/0x180 [11384.333503] show_stack+0x14/0x20 [11384.336805] dump_stack+0x8c/0xac [11384.340107] dequeue_task_idle+0x2c/0x68 [11384.344016] do_set_cpus_allowed+0x5c/0x148 [11384.348186] cpuset_cpus_allowed_fallback+0x1c/0x48 [11384.353050] select_fallback_rq+0x17c/0x220 [11384.355310] ITS queue not draining [11384.357219] sched_cpu_dying+0x328/0x368 [11384.364513] cpuhp_invoke_callback+0xc0/0x1f0 [11384.368856] _cpu_up+0x164/0x1e0 [11384.372070] enable_nonboot_cpus+0x7c/0xf8 [11384.376153] hibernation_snapshot+0x1c0/0x348 [11384.380496] hibernate+0xf4/0x290 [11384.383797] state_store+0x70/0xa0 [11384.387185] kobj_attr_store+0x14/0x28 [11384.390921] sysfs_kf_write+0x4c/0x60 [11384.394569] kernfs_fop_write+0x11c/0x1d0 [11384.398566] __vfs_write+0x1c/0x138 [11384.402041] vfs_write+0xb4/0x190 [11384.405342] ksys_write+0x50/0xa0 [11384.408643] __arm64_sys_write+0x14/0x20 [11384.412552] el0_svc_common+0x100/0x168 [11384.416374] el0_svc_handler+0x4c/0x68 [11384.420109] el0_svc+0x8/0xc [11384.422984] Unable to handle kernel NULL pointer dereference at virtual address 0000000000000000
The its doesn't support hibernate, when hibernate() calls, the its doesn't suspend() and resume() successfully.
Add its herbinate state to support its suspend and resume correctly.
https://lkml.org/lkml/2019/12/2/270
Signed-off-by: Hongbo Yao yaohongbo@huawei.com Reviewed-by: Hanjun Guo guohanjun@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- drivers/irqchip/irq-gic-v3-its.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-)
diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c index 21dfe22..f75f6d7 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c @@ -38,6 +38,7 @@ #include <linux/of_platform.h> #include <linux/percpu.h> #include <linux/slab.h> +#include <linux/suspend.h> #include <linux/syscore_ops.h>
#include <linux/irqchip.h> @@ -53,6 +54,7 @@ #define ITS_FLAGS_WORKAROUND_CAVIUM_22375 (1ULL << 1) #define ITS_FLAGS_WORKAROUND_CAVIUM_23144 (1ULL << 2) #define ITS_FLAGS_SAVE_SUSPEND_STATE (1ULL << 3) +#define ITS_FLAGS_SAVE_HIBERNATE_STATE (1ULL << 4)
#define RDIST_FLAGS_PROPBASE_NEEDS_FLUSHING (1 << 0) #define RDIST_FLAGS_RD_TABLES_PREALLOCATED (1 << 1) @@ -3365,8 +3367,16 @@ static int its_save_disable(void) raw_spin_lock(&its_lock); list_for_each_entry(its, &its_nodes, entry) { void __iomem *base; + u64 flags;
- if (!(its->flags & ITS_FLAGS_SAVE_SUSPEND_STATE)) + if (system_in_hibernation()) + its->flags |= ITS_FLAGS_SAVE_HIBERNATE_STATE; + + flags = its->flags; + flags &= (ITS_FLAGS_SAVE_SUSPEND_STATE | + ITS_FLAGS_SAVE_HIBERNATE_STATE); + + if (!flags) continue;
base = its->base; @@ -3407,11 +3417,16 @@ static void its_restore_enable(void) raw_spin_lock(&its_lock); list_for_each_entry(its, &its_nodes, entry) { void __iomem *base; + u64 flags; int i;
- if (!(its->flags & ITS_FLAGS_SAVE_SUSPEND_STATE)) + flags = its->flags; + flags &= (ITS_FLAGS_SAVE_SUSPEND_STATE | + ITS_FLAGS_SAVE_HIBERNATE_STATE); + if (!flags) continue;
+ its->flags &= ~ITS_FLAGS_SAVE_HIBERNATE_STATE; base = its->base;
/*