diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 273a58b744703b748d2a0eb15734f9a1bcc6f49f..eb7334370cfe33612983cbb96c381f2d8ecfaa54 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -2306,6 +2306,9 @@ config ARCH_HIBERNATION_HEADER config ARCH_SUSPEND_POSSIBLE def_bool y +config ARCH_SUSPEND_NONZERO_CPU + def_bool y + endmenu menu "CPU Power Management" diff --git a/include/linux/cpu.h b/include/linux/cpu.h index c282f6355aef1a72d5cd0a60d29cf0f9a9ca68e3..513cd860b3e314b8bc6759062d5c15f35d683fb4 100644 --- a/include/linux/cpu.h +++ b/include/linux/cpu.h @@ -18,6 +18,7 @@ #include #include #include +#include struct device; struct device_node; @@ -163,7 +164,7 @@ static inline int suspend_disable_secondary_cpus(void) { int cpu = 0; - if (IS_ENABLED(CONFIG_PM_SLEEP_SMP_NONZERO_CPU)) + if (support_cpu0_nohz_full && IS_ENABLED(CONFIG_PM_SLEEP_SMP_NONZERO_CPU)) cpu = -1; return freeze_secondary_cpus(cpu); diff --git a/include/linux/sched/isolation.h b/include/linux/sched/isolation.h index 2f93081ad7a030729b9f7c9e8af1bba4fc63ac8c..09e80eccaf98b8404e167e5b7c097dab7fec8f6a 100644 --- a/include/linux/sched/isolation.h +++ b/include/linux/sched/isolation.h @@ -19,6 +19,7 @@ enum hk_flags { #ifdef CONFIG_CPU_ISOLATION extern bool enhanced_isolcpus; +extern bool support_cpu0_nohz_full; DECLARE_STATIC_KEY_FALSE(housekeeping_overridden); extern int housekeeping_any_cpu(enum hk_flags flags); extern const struct cpumask *housekeeping_cpumask(enum hk_flags flags); @@ -26,10 +27,13 @@ extern bool housekeeping_enabled(enum hk_flags flags); extern void housekeeping_affine(struct task_struct *t, enum hk_flags flags); extern bool housekeeping_test_cpu(int cpu, enum hk_flags flags); extern void __init housekeeping_init(void); +extern void check_housekeeping_cpus_online(void); #else #define enhanced_isolcpus 0 +#define support_cpu0_nohz_full 0 + static inline int housekeeping_any_cpu(enum hk_flags flags) { return smp_processor_id(); @@ -48,6 +52,7 @@ static inline bool housekeeping_enabled(enum hk_flags flags) static inline void housekeeping_affine(struct task_struct *t, enum hk_flags flags) { } static inline void housekeeping_init(void) { } +static inline void check_housekeeping_cpus_online(void) { } #endif /* CONFIG_CPU_ISOLATION */ static inline bool housekeeping_cpu(int cpu, enum hk_flags flags) diff --git a/kernel/sched/isolation.c b/kernel/sched/isolation.c index 785ef52011160d902e73f3aa51093134a57df13e..d8c6c51f1e54a7b7a0c11d1e1a6eac1406bbf862 100644 --- a/kernel/sched/isolation.c +++ b/kernel/sched/isolation.c @@ -13,6 +13,7 @@ DEFINE_STATIC_KEY_FALSE(housekeeping_overridden); EXPORT_SYMBOL_GPL(housekeeping_overridden); static cpumask_var_t housekeeping_mask; static unsigned int housekeeping_flags; +bool support_cpu0_nohz_full; bool housekeeping_enabled(enum hk_flags flags) { @@ -96,18 +97,28 @@ static int __init housekeeping_setup(char *str, enum hk_flags flags) alloc_bootmem_cpumask_var(&housekeeping_mask); cpumask_andnot(housekeeping_mask, cpu_possible_mask, non_housekeeping_mask); + if (support_cpu0_nohz_full && cpumask_empty(housekeeping_mask)) { + pr_warn("Housekeeping cpumask is NULL, using boot CPU\n"); + __cpumask_set_cpu(smp_processor_id(), housekeeping_mask); + /* update non_housekeeping_mask because it will be used below + in tick_nohz_full_setup() */ + cpumask_andnot(non_housekeeping_mask, + cpu_possible_mask, housekeeping_mask); + } cpumask_andnot(tmp, cpu_present_mask, non_housekeeping_mask); - if (cpumask_empty(tmp)) { + if (!support_cpu0_nohz_full && cpumask_empty(tmp)) { pr_warn("Housekeeping: must include one present CPU, " "using boot CPU:%d\n", smp_processor_id()); __cpumask_set_cpu(smp_processor_id(), housekeeping_mask); __cpumask_clear_cpu(smp_processor_id(), non_housekeeping_mask); } } else { - cpumask_andnot(tmp, cpu_present_mask, non_housekeeping_mask); - if (cpumask_empty(tmp)) - __cpumask_clear_cpu(smp_processor_id(), non_housekeeping_mask); + if (!support_cpu0_nohz_full) { + cpumask_andnot(tmp, cpu_present_mask, non_housekeeping_mask); + if (cpumask_empty(tmp)) + __cpumask_clear_cpu(smp_processor_id(), non_housekeeping_mask); + } cpumask_andnot(tmp, cpu_possible_mask, non_housekeeping_mask); if (!cpumask_equal(tmp, housekeeping_mask)) { pr_warn("Housekeeping: nohz_full= must match isolcpus=\n"); @@ -206,3 +217,23 @@ static int __init enhanced_isolcpus_setup(char *str) return 0; } __setup("enhanced_isolcpus", enhanced_isolcpus_setup); + +static int __init support_cpu0_nohz_full_setup(char *str) +{ + support_cpu0_nohz_full = true; + return 0; +} +early_param("support_cpu0_nohz_full", support_cpu0_nohz_full_setup); + +void check_housekeeping_cpus_online(void) +{ + if (!support_cpu0_nohz_full) + return; + if (!housekeeping_flags) + return; + if (!cpumask_subset(housekeeping_mask, cpu_online_mask)) { + pr_err("Not all the housekeeping CPUs are online, please modify the kernel parameter !\n"); + /* BUG_ON here, otherwise there may exist other potential error */ + BUG_ON(1); + } +} diff --git a/kernel/smp.c b/kernel/smp.c index 4b13a7ef6a31586ee8fbf42449d0b8245b467646..a1017ff0af9d3a53ca84aae3370cebd0b8f39002 100644 --- a/kernel/smp.c +++ b/kernel/smp.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -884,6 +885,9 @@ void __init smp_init(void) /* Any cleanup work */ smp_cpus_done(setup_max_cpus); + + /* Check whether all the housekeeping CPUs are online */ + check_housekeeping_cpus_online(); } /* diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c index f50dc8f367072ddbbe56a726c630f4f0f86760b1..cde853082074cda8e92c5eec2d14475d49b2a2d9 100644 --- a/kernel/time/tick-sched.c +++ b/kernel/time/tick-sched.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -557,7 +558,7 @@ void __init tick_nohz_init(void) } if (IS_ENABLED(CONFIG_PM_SLEEP_SMP) && - !IS_ENABLED(CONFIG_PM_SLEEP_SMP_NONZERO_CPU)) { + (!support_cpu0_nohz_full || !IS_ENABLED(CONFIG_PM_SLEEP_SMP_NONZERO_CPU))) { cpu = smp_processor_id(); if (cpumask_test_cpu(cpu, tick_nohz_full_mask)) {