return 0;
}
-static struct tmigr_hierarchy *__tmigr_get_hierarchy(unsigned int capacity)
+static unsigned int tmigr_get_capacity(int cpu)
{
+ /*
+ * nohz_full CPUs need to make sure there is always an available (online)
+ * and never idle migrator to handle all their global timers. That duty
+ * is served by the timekeeper which then never stops its tick. But the
+ * timekeeper must then belong to the same hierarchy as all the nohz_full
+ * CPUs. Simply turn off capacity awareness when nohz_full is running.
+ */
+ if (tick_nohz_full_enabled())
+ return SCHED_CAPACITY_SCALE;
+ else
+ return arch_scale_cpu_capacity(cpu);
+}
+
+static struct tmigr_hierarchy *__tmigr_get_hierarchy(int cpu)
+{
+ unsigned int capacity = tmigr_get_capacity(cpu);
struct tmigr_hierarchy *iter;
list_for_each_entry(iter, &tmigr_hierarchy_list, node) {
}
if (firstexp != KTIME_MAX) {
- struct tmigr_hierarchy *hier = __tmigr_get_hierarchy(arch_scale_cpu_capacity(cpu));
+ struct tmigr_hierarchy *hier = __tmigr_get_hierarchy(cpu);
if (WARN_ON_ONCE(!hier))
return -EINVAL;
return err;
}
-static struct tmigr_hierarchy *tmigr_get_hierarchy(unsigned int capacity)
+static struct tmigr_hierarchy *tmigr_get_hierarchy(int cpu)
{
struct tmigr_hierarchy *hier;
- hier = __tmigr_get_hierarchy(capacity);
+ hier = __tmigr_get_hierarchy(cpu);
if (hier)
return hier;
for (int i = 0; i < tmigr_hierarchy_levels; i++)
INIT_LIST_HEAD(&hier->level_list[i]);
- hier->capacity = capacity;
+ hier->capacity = tmigr_get_capacity(cpu);
list_add_tail(&hier->node, &tmigr_hierarchy_list);
return hier;
struct tmigr_hierarchy *hier;
int cpu = smp_processor_id();
- hier = __tmigr_get_hierarchy(arch_scale_cpu_capacity(cpu));
+ hier = __tmigr_get_hierarchy(cpu);
if (WARN_ON_ONCE(!hier))
return -EINVAL;
guard(mutex)(&tmigr_mutex);
- hier = tmigr_get_hierarchy(arch_scale_cpu_capacity(cpu));
+ hier = tmigr_get_hierarchy(cpu);
if (IS_ERR(hier))
return PTR_ERR(hier);