blob: 1f61e440358d7de5dc9cc19424471d44fd603267 [file] [log] [blame]
Frederic Weisbecker78634062017-10-27 04:42:28 +02001/*
2 * Housekeeping management. Manage the targets for routine code that can run on
3 * any CPU: unbound workqueues, timers, kthreads and any offloadable work.
4 *
5 * Copyright (C) 2017 Red Hat, Inc., Frederic Weisbecker
6 *
7 */
8
9#include <linux/sched/isolation.h>
10#include <linux/tick.h>
11#include <linux/init.h>
12#include <linux/kernel.h>
Frederic Weisbeckere179f5a2017-10-27 04:42:32 +020013#include <linux/static_key.h>
Frederic Weisbecker78634062017-10-27 04:42:28 +020014
Frederic Weisbeckere179f5a2017-10-27 04:42:32 +020015DEFINE_STATIC_KEY_FALSE(housekeeping_overriden);
16EXPORT_SYMBOL_GPL(housekeeping_overriden);
Frederic Weisbecker7e56a1c2017-10-27 04:42:31 +020017static cpumask_var_t housekeeping_mask;
Frederic Weisbeckerde201552017-10-27 04:42:35 +020018static unsigned int housekeeping_flags;
Frederic Weisbecker7e56a1c2017-10-27 04:42:31 +020019
Frederic Weisbeckerde201552017-10-27 04:42:35 +020020int housekeeping_any_cpu(enum hk_flags flags)
Frederic Weisbecker7e56a1c2017-10-27 04:42:31 +020021{
Frederic Weisbeckere179f5a2017-10-27 04:42:32 +020022 if (static_branch_unlikely(&housekeeping_overriden))
Frederic Weisbeckerde201552017-10-27 04:42:35 +020023 if (housekeeping_flags & flags)
24 return cpumask_any_and(housekeeping_mask, cpu_online_mask);
Frederic Weisbecker7e56a1c2017-10-27 04:42:31 +020025 return smp_processor_id();
26}
27EXPORT_SYMBOL_GPL(housekeeping_any_cpu);
28
Frederic Weisbeckerde201552017-10-27 04:42:35 +020029const struct cpumask *housekeeping_cpumask(enum hk_flags flags)
Frederic Weisbecker7e56a1c2017-10-27 04:42:31 +020030{
Frederic Weisbeckere179f5a2017-10-27 04:42:32 +020031 if (static_branch_unlikely(&housekeeping_overriden))
Frederic Weisbeckerde201552017-10-27 04:42:35 +020032 if (housekeeping_flags & flags)
33 return housekeeping_mask;
Frederic Weisbecker7e56a1c2017-10-27 04:42:31 +020034 return cpu_possible_mask;
35}
36EXPORT_SYMBOL_GPL(housekeeping_cpumask);
37
Frederic Weisbeckerde201552017-10-27 04:42:35 +020038void housekeeping_affine(struct task_struct *t, enum hk_flags flags)
Frederic Weisbecker7e56a1c2017-10-27 04:42:31 +020039{
Frederic Weisbeckere179f5a2017-10-27 04:42:32 +020040 if (static_branch_unlikely(&housekeeping_overriden))
Frederic Weisbeckerde201552017-10-27 04:42:35 +020041 if (housekeeping_flags & flags)
42 set_cpus_allowed_ptr(t, housekeeping_mask);
Frederic Weisbecker7e56a1c2017-10-27 04:42:31 +020043}
44EXPORT_SYMBOL_GPL(housekeeping_affine);
45
Frederic Weisbeckerde201552017-10-27 04:42:35 +020046bool housekeeping_test_cpu(int cpu, enum hk_flags flags)
Frederic Weisbecker7e56a1c2017-10-27 04:42:31 +020047{
Frederic Weisbeckere179f5a2017-10-27 04:42:32 +020048 if (static_branch_unlikely(&housekeeping_overriden))
Frederic Weisbeckerde201552017-10-27 04:42:35 +020049 if (housekeeping_flags & flags)
50 return cpumask_test_cpu(cpu, housekeeping_mask);
Frederic Weisbecker7e56a1c2017-10-27 04:42:31 +020051 return true;
52}
53EXPORT_SYMBOL_GPL(housekeeping_test_cpu);
Frederic Weisbecker78634062017-10-27 04:42:28 +020054
55void __init housekeeping_init(void)
56{
Frederic Weisbecker6f1982f2017-10-27 04:42:36 +020057 if (!housekeeping_flags)
Frederic Weisbecker78634062017-10-27 04:42:28 +020058 return;
59
Frederic Weisbeckere179f5a2017-10-27 04:42:32 +020060 static_branch_enable(&housekeeping_overriden);
61
Frederic Weisbecker78634062017-10-27 04:42:28 +020062 /* We need at least one CPU to handle housekeeping work */
63 WARN_ON_ONCE(cpumask_empty(housekeeping_mask));
64}
Frederic Weisbecker6f1982f2017-10-27 04:42:36 +020065
66#ifdef CONFIG_NO_HZ_FULL
67static int __init housekeeping_nohz_full_setup(char *str)
68{
69 cpumask_var_t non_housekeeping_mask;
70
71 alloc_bootmem_cpumask_var(&non_housekeeping_mask);
72 if (cpulist_parse(str, non_housekeeping_mask) < 0) {
73 pr_warn("Housekeeping: Incorrect nohz_full cpumask\n");
74 free_bootmem_cpumask_var(non_housekeeping_mask);
75 return 0;
76 }
77
78 alloc_bootmem_cpumask_var(&housekeeping_mask);
79 cpumask_andnot(housekeeping_mask, cpu_possible_mask, non_housekeeping_mask);
80
81 if (cpumask_empty(housekeeping_mask))
82 cpumask_set_cpu(smp_processor_id(), housekeeping_mask);
83
84 housekeeping_flags = HK_FLAG_TICK | HK_FLAG_TIMER |
85 HK_FLAG_RCU | HK_FLAG_MISC;
86
87 tick_nohz_full_setup(non_housekeeping_mask);
88
89 free_bootmem_cpumask_var(non_housekeeping_mask);
90
91 return 1;
92}
93__setup("nohz_full=", housekeeping_nohz_full_setup);
94#endif