1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Scheduler code and data structures related to cpufreq. |
4 | * |
5 | * Copyright (C) 2016, Intel Corporation |
6 | * Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com> |
7 | */ |
8 | |
9 | DEFINE_PER_CPU(struct update_util_data __rcu *, cpufreq_update_util_data); |
10 | |
11 | /** |
12 | * cpufreq_add_update_util_hook - Populate the CPU's update_util_data pointer. |
13 | * @cpu: The CPU to set the pointer for. |
14 | * @data: New pointer value. |
15 | * @func: Callback function to set for the CPU. |
16 | * |
17 | * Set and publish the update_util_data pointer for the given CPU. |
18 | * |
19 | * The update_util_data pointer of @cpu is set to @data and the callback |
20 | * function pointer in the target struct update_util_data is set to @func. |
21 | * That function will be called by cpufreq_update_util() from RCU-sched |
22 | * read-side critical sections, so it must not sleep. @data will always be |
23 | * passed to it as the first argument which allows the function to get to the |
24 | * target update_util_data structure and its container. |
25 | * |
26 | * The update_util_data pointer of @cpu must be NULL when this function is |
27 | * called or it will WARN() and return with no effect. |
28 | */ |
29 | void cpufreq_add_update_util_hook(int cpu, struct update_util_data *data, |
30 | void (*func)(struct update_util_data *data, u64 time, |
31 | unsigned int flags)) |
32 | { |
33 | if (WARN_ON(!data || !func)) |
34 | return; |
35 | |
36 | if (WARN_ON(per_cpu(cpufreq_update_util_data, cpu))) |
37 | return; |
38 | |
39 | data->func = func; |
40 | rcu_assign_pointer(per_cpu(cpufreq_update_util_data, cpu), data); |
41 | } |
42 | EXPORT_SYMBOL_GPL(cpufreq_add_update_util_hook); |
43 | |
44 | /** |
45 | * cpufreq_remove_update_util_hook - Clear the CPU's update_util_data pointer. |
46 | * @cpu: The CPU to clear the pointer for. |
47 | * |
48 | * Clear the update_util_data pointer for the given CPU. |
49 | * |
50 | * Callers must use RCU callbacks to free any memory that might be |
51 | * accessed via the old update_util_data pointer or invoke synchronize_rcu() |
52 | * right after this function to avoid use-after-free. |
53 | */ |
54 | void cpufreq_remove_update_util_hook(int cpu) |
55 | { |
56 | rcu_assign_pointer(per_cpu(cpufreq_update_util_data, cpu), NULL); |
57 | } |
58 | EXPORT_SYMBOL_GPL(cpufreq_remove_update_util_hook); |
59 | |
60 | /** |
61 | * cpufreq_this_cpu_can_update - Check if cpufreq policy can be updated. |
62 | * @policy: cpufreq policy to check. |
63 | * |
64 | * Return 'true' if: |
65 | * - the local and remote CPUs share @policy, |
66 | * - dvfs_possible_from_any_cpu is set in @policy and the local CPU is not going |
67 | * offline (in which case it is not expected to run cpufreq updates any more). |
68 | */ |
69 | bool cpufreq_this_cpu_can_update(struct cpufreq_policy *policy) |
70 | { |
71 | return cpumask_test_cpu(smp_processor_id(), cpumask: policy->cpus) || |
72 | (policy->dvfs_possible_from_any_cpu && |
73 | rcu_dereference_sched(*this_cpu_ptr(&cpufreq_update_util_data))); |
74 | } |
75 | |