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