1 // SPDX-License-Identifier: GPL-2.0-only
3 * Housekeeping management. Manage the targets for routine code that can run on
4 * any CPU: unbound workqueues, timers, kthreads and any offloadable work.
6 * Copyright (C) 2017 Red Hat, Inc., Frederic Weisbecker
7 * Copyright (C) 2017-2018 SUSE, Frederic Weisbecker
12 DEFINE_STATIC_KEY_FALSE(housekeeping_overridden
);
13 EXPORT_SYMBOL_GPL(housekeeping_overridden
);
14 static cpumask_var_t housekeeping_mask
;
15 static unsigned int housekeeping_flags
;
17 bool housekeeping_enabled(enum hk_flags flags
)
19 return !!(housekeeping_flags
& flags
);
21 EXPORT_SYMBOL_GPL(housekeeping_enabled
);
23 int housekeeping_any_cpu(enum hk_flags flags
)
27 if (static_branch_unlikely(&housekeeping_overridden
)) {
28 if (housekeeping_flags
& flags
) {
29 cpu
= sched_numa_find_closest(housekeeping_mask
, smp_processor_id());
33 return cpumask_any_and(housekeeping_mask
, cpu_online_mask
);
36 return smp_processor_id();
38 EXPORT_SYMBOL_GPL(housekeeping_any_cpu
);
40 const struct cpumask
*housekeeping_cpumask(enum hk_flags flags
)
42 if (static_branch_unlikely(&housekeeping_overridden
))
43 if (housekeeping_flags
& flags
)
44 return housekeeping_mask
;
45 return cpu_possible_mask
;
47 EXPORT_SYMBOL_GPL(housekeeping_cpumask
);
49 void housekeeping_affine(struct task_struct
*t
, enum hk_flags flags
)
51 if (static_branch_unlikely(&housekeeping_overridden
))
52 if (housekeeping_flags
& flags
)
53 set_cpus_allowed_ptr(t
, housekeeping_mask
);
55 EXPORT_SYMBOL_GPL(housekeeping_affine
);
57 bool housekeeping_test_cpu(int cpu
, enum hk_flags flags
)
59 if (static_branch_unlikely(&housekeeping_overridden
))
60 if (housekeeping_flags
& flags
)
61 return cpumask_test_cpu(cpu
, housekeeping_mask
);
64 EXPORT_SYMBOL_GPL(housekeeping_test_cpu
);
66 void __init
housekeeping_init(void)
68 if (!housekeeping_flags
)
71 static_branch_enable(&housekeeping_overridden
);
73 if (housekeeping_flags
& HK_FLAG_TICK
)
74 sched_tick_offload_init();
76 /* We need at least one CPU to handle housekeeping work */
77 WARN_ON_ONCE(cpumask_empty(housekeeping_mask
));
80 static int __init
housekeeping_setup(char *str
, enum hk_flags flags
)
82 cpumask_var_t non_housekeeping_mask
;
86 alloc_bootmem_cpumask_var(&non_housekeeping_mask
);
87 err
= cpulist_parse(str
, non_housekeeping_mask
);
88 if (err
< 0 || cpumask_last(non_housekeeping_mask
) >= nr_cpu_ids
) {
89 pr_warn("Housekeeping: nohz_full= or isolcpus= incorrect CPU range\n");
90 free_bootmem_cpumask_var(non_housekeeping_mask
);
94 alloc_bootmem_cpumask_var(&tmp
);
95 if (!housekeeping_flags
) {
96 alloc_bootmem_cpumask_var(&housekeeping_mask
);
97 cpumask_andnot(housekeeping_mask
,
98 cpu_possible_mask
, non_housekeeping_mask
);
100 cpumask_andnot(tmp
, cpu_present_mask
, non_housekeeping_mask
);
101 if (cpumask_empty(tmp
)) {
102 pr_warn("Housekeeping: must include one present CPU, "
103 "using boot CPU:%d\n", smp_processor_id());
104 __cpumask_set_cpu(smp_processor_id(), housekeeping_mask
);
105 __cpumask_clear_cpu(smp_processor_id(), non_housekeeping_mask
);
108 cpumask_andnot(tmp
, cpu_present_mask
, non_housekeeping_mask
);
109 if (cpumask_empty(tmp
))
110 __cpumask_clear_cpu(smp_processor_id(), non_housekeeping_mask
);
111 cpumask_andnot(tmp
, cpu_possible_mask
, non_housekeeping_mask
);
112 if (!cpumask_equal(tmp
, housekeeping_mask
)) {
113 pr_warn("Housekeeping: nohz_full= must match isolcpus=\n");
114 free_bootmem_cpumask_var(tmp
);
115 free_bootmem_cpumask_var(non_housekeeping_mask
);
119 free_bootmem_cpumask_var(tmp
);
121 if ((flags
& HK_FLAG_TICK
) && !(housekeeping_flags
& HK_FLAG_TICK
)) {
122 if (IS_ENABLED(CONFIG_NO_HZ_FULL
)) {
123 tick_nohz_full_setup(non_housekeeping_mask
);
125 pr_warn("Housekeeping: nohz unsupported."
126 " Build with CONFIG_NO_HZ_FULL\n");
127 free_bootmem_cpumask_var(non_housekeeping_mask
);
132 housekeeping_flags
|= flags
;
134 free_bootmem_cpumask_var(non_housekeeping_mask
);
139 static int __init
housekeeping_nohz_full_setup(char *str
)
143 flags
= HK_FLAG_TICK
| HK_FLAG_WQ
| HK_FLAG_TIMER
| HK_FLAG_RCU
| HK_FLAG_MISC
;
145 return housekeeping_setup(str
, flags
);
147 __setup("nohz_full=", housekeeping_nohz_full_setup
);
149 static int __init
housekeeping_isolcpus_setup(char *str
)
151 unsigned int flags
= 0;
152 bool illegal
= false;
156 while (isalpha(*str
)) {
157 if (!strncmp(str
, "nohz,", 5)) {
159 flags
|= HK_FLAG_TICK
;
163 if (!strncmp(str
, "domain,", 7)) {
165 flags
|= HK_FLAG_DOMAIN
;
169 if (!strncmp(str
, "managed_irq,", 12)) {
171 flags
|= HK_FLAG_MANAGED_IRQ
;
176 * Skip unknown sub-parameter and validate that it is not
177 * containing an invalid character.
179 for (par
= str
, len
= 0; *str
&& *str
!= ','; str
++, len
++) {
180 if (!isalpha(*str
) && *str
!= '_')
185 pr_warn("isolcpus: Invalid flag %.*s\n", len
, par
);
189 pr_info("isolcpus: Skipped unknown flag %.*s\n", len
, par
);
193 /* Default behaviour for isolcpus without flags */
195 flags
|= HK_FLAG_DOMAIN
;
197 return housekeeping_setup(str
, flags
);
199 __setup("isolcpus=", housekeeping_isolcpus_setup
);