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/arch/arm64/configs/openeuler_defconfig b/arch/arm64/configs/openeuler_defconfig index a8f83a4e2a4fc43c3632b7e6ea8c80f1a34de10b..fae2349f78c92a108d9d40566bc2293baf865b0b 100644 --- a/arch/arm64/configs/openeuler_defconfig +++ b/arch/arm64/configs/openeuler_defconfig @@ -583,6 +583,7 @@ CONFIG_HIBERNATION_SNAPSHOT_DEV=y CONFIG_PM_STD_PARTITION="" CONFIG_PM_SLEEP=y CONFIG_PM_SLEEP_SMP=y +CONFIG_PM_SLEEP_SMP_NONZERO_CPU=y # CONFIG_PM_AUTOSLEEP is not set # CONFIG_PM_WAKELOCKS is not set CONFIG_PM=y @@ -601,6 +602,7 @@ CONFIG_CPU_PM=y CONFIG_ARCH_HIBERNATION_POSSIBLE=y CONFIG_ARCH_HIBERNATION_HEADER=y CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_ARCH_SUSPEND_NONZERO_CPU=y # end of Power management options # diff --git a/include/linux/cpu.h b/include/linux/cpu.h index c282f6355aef1a72d5cd0a60d29cf0f9a9ca68e3..623e764cab13b7d41ea79afa44f302b6c0b51101 100644 --- a/include/linux/cpu.h +++ b/include/linux/cpu.h @@ -18,6 +18,9 @@ #include #include #include +#ifndef __GENKSYMS__ +#include +#endif struct device; struct device_node; @@ -163,7 +166,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..f665bc8ff63398e7fe7690a81d27893170750058 100644 --- a/include/linux/sched/isolation.h +++ b/include/linux/sched/isolation.h @@ -26,6 +26,7 @@ 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_cpu_online(void); #else @@ -48,6 +49,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_cpu_online(void) { } #endif /* CONFIG_CPU_ISOLATION */ static inline bool housekeeping_cpu(int cpu, enum hk_flags flags) diff --git a/include/linux/tick.h b/include/linux/tick.h index f34b7b779d440bde67adfe3c55e8881b45d4afbd..46c75dccaf8e76a0ad42379ee9a43a4bcbd2df65 100644 --- a/include/linux/tick.h +++ b/include/linux/tick.h @@ -41,8 +41,10 @@ extern void tick_irq_enter(void); # ifndef arch_needs_cpu # define arch_needs_cpu() (0) # endif +extern bool support_cpu0_nohz_full; # else static inline void tick_irq_enter(void) { } +#define support_cpu0_nohz_full 0 #endif #if defined(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST) && defined(CONFIG_TICK_ONESHOT) diff --git a/kernel/sched/isolation.c b/kernel/sched/isolation.c index 785ef52011160d902e73f3aa51093134a57df13e..42b13988a438e6a276e4eb56a0f3d05164c303e8 100644 --- a/kernel/sched/isolation.c +++ b/kernel/sched/isolation.c @@ -96,18 +96,30 @@ 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 +218,16 @@ static int __init enhanced_isolcpus_setup(char *str) return 0; } __setup("enhanced_isolcpus", enhanced_isolcpus_setup); + +void check_housekeeping_cpu_online(void) +{ + if (!support_cpu0_nohz_full) + return; + if (!housekeeping_flags) + return; + if (!cpumask_intersects(housekeeping_mask, cpu_online_mask)) { + pr_err("All the housekeeping CPUs are offline, 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..d9ba6935f83fec38ef3ec4fc7c39d847940c9af5 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 there exists a housekeeping CPU online */ + check_housekeeping_cpu_online(); } /* diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c index f50dc8f367072ddbbe56a726c630f4f0f86760b1..9e829ec93c2f7c9b9ace225c4fa4adbb5590d9c6 100644 --- a/kernel/time/tick-sched.c +++ b/kernel/time/tick-sched.c @@ -38,6 +38,8 @@ */ static DEFINE_PER_CPU(struct tick_sched, tick_cpu_sched); +bool support_cpu0_nohz_full; + struct tick_sched *tick_get_tick_sched(int cpu) { return &per_cpu(tick_cpu_sched, cpu); @@ -557,7 +559,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)) { @@ -1559,3 +1561,10 @@ int tick_check_oneshot_change(int allow_nohz) tick_nohz_switch_to_nohz(); return 0; } + +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);