2 * Housekeeping management. Manage the targets for routine code that can run on
3 * any CPU: unbound workqueues, timers, kthreads and any offloadable work.
5 * Copyright (C) 2017 Red Hat, Inc., Frederic Weisbecker
9 #include <linux/sched/isolation.h>
10 #include <linux/tick.h>
11 #include <linux/init.h>
12 #include <linux/kernel.h>
13 #include <linux/static_key.h>
15 DEFINE_STATIC_KEY_FALSE(housekeeping_overriden);
16 EXPORT_SYMBOL_GPL(housekeeping_overriden);
17 static cpumask_var_t housekeeping_mask;
18 static unsigned int housekeeping_flags;
20 int housekeeping_any_cpu(enum hk_flags flags)
22 if (static_branch_unlikely(&housekeeping_overriden))
23 if (housekeeping_flags & flags)
24 return cpumask_any_and(housekeeping_mask, cpu_online_mask);
25 return smp_processor_id();
27 EXPORT_SYMBOL_GPL(housekeeping_any_cpu);
29 const struct cpumask *housekeeping_cpumask(enum hk_flags flags)
31 if (static_branch_unlikely(&housekeeping_overriden))
32 if (housekeeping_flags & flags)
33 return housekeeping_mask;
34 return cpu_possible_mask;
36 EXPORT_SYMBOL_GPL(housekeeping_cpumask);
38 void housekeeping_affine(struct task_struct *t, enum hk_flags flags)
40 if (static_branch_unlikely(&housekeeping_overriden))
41 if (housekeeping_flags & flags)
42 set_cpus_allowed_ptr(t, housekeeping_mask);
44 EXPORT_SYMBOL_GPL(housekeeping_affine);
46 bool housekeeping_test_cpu(int cpu, enum hk_flags flags)
48 if (static_branch_unlikely(&housekeeping_overriden))
49 if (housekeeping_flags & flags)
50 return cpumask_test_cpu(cpu, housekeeping_mask);
53 EXPORT_SYMBOL_GPL(housekeeping_test_cpu);
55 void __init housekeeping_init(void)
57 if (!housekeeping_flags)
60 static_branch_enable(&housekeeping_overriden);
62 /* We need at least one CPU to handle housekeeping work */
63 WARN_ON_ONCE(cpumask_empty(housekeeping_mask));
66 static int __init housekeeping_setup(char *str, enum hk_flags flags)
68 cpumask_var_t non_housekeeping_mask;
71 alloc_bootmem_cpumask_var(&non_housekeeping_mask);
72 err = cpulist_parse(str, non_housekeeping_mask);
73 if (err < 0 || cpumask_last(non_housekeeping_mask) >= nr_cpu_ids) {
74 pr_warn("Housekeeping: nohz_full= or isolcpus= incorrect CPU range\n");
75 free_bootmem_cpumask_var(non_housekeeping_mask);
79 if (!housekeeping_flags) {
80 alloc_bootmem_cpumask_var(&housekeeping_mask);
81 cpumask_andnot(housekeeping_mask,
82 cpu_possible_mask, non_housekeeping_mask);
83 if (cpumask_empty(housekeeping_mask))
84 cpumask_set_cpu(smp_processor_id(), housekeeping_mask);
88 alloc_bootmem_cpumask_var(&tmp);
89 cpumask_andnot(tmp, cpu_possible_mask, non_housekeeping_mask);
90 if (!cpumask_equal(tmp, housekeeping_mask)) {
91 pr_warn("Housekeeping: nohz_full= must match isolcpus=\n");
92 free_bootmem_cpumask_var(tmp);
93 free_bootmem_cpumask_var(non_housekeeping_mask);
96 free_bootmem_cpumask_var(tmp);
99 if ((flags & HK_FLAG_TICK) && !(housekeeping_flags & HK_FLAG_TICK)) {
100 if (IS_ENABLED(CONFIG_NO_HZ_FULL)) {
101 tick_nohz_full_setup(non_housekeeping_mask);
103 pr_warn("Housekeeping: nohz unsupported."
104 " Build with CONFIG_NO_HZ_FULL\n");
105 free_bootmem_cpumask_var(non_housekeeping_mask);
110 housekeeping_flags |= flags;
112 free_bootmem_cpumask_var(non_housekeeping_mask);
117 static int __init housekeeping_nohz_full_setup(char *str)
121 flags = HK_FLAG_TICK | HK_FLAG_TIMER | HK_FLAG_RCU | HK_FLAG_MISC;
123 return housekeeping_setup(str, flags);
125 __setup("nohz_full=", housekeeping_nohz_full_setup);
127 static int __init housekeeping_isolcpus_setup(char *str)
129 return housekeeping_setup(str, HK_FLAG_DOMAIN);
131 __setup("isolcpus=", housekeeping_isolcpus_setup);