From af75504c38960d5331b8c6c83ea9981e26d659e6 Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Thu, 17 Aug 2023 14:16:35 -0600 Subject: [PATCH 1/6] cpupower: Add Georgian translation to Makefile LANGUAGES Commit 4680b734e729 ("cpupower: Add Georgian translation") added new language support. This change didn't add "ka" to Makefile LANGUAGES variable. Add it now. Reported-by: Temuri Doghonadze Reported-by: Zurab Kargareteli Signed-off-by: Shuah Khan --- tools/power/cpupower/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/power/cpupower/Makefile b/tools/power/cpupower/Makefile index dc531805a570..b53753dee02f 100644 --- a/tools/power/cpupower/Makefile +++ b/tools/power/cpupower/Makefile @@ -57,7 +57,7 @@ LIB_MIN= 1 PACKAGE = cpupower PACKAGE_BUGREPORT = linux-pm@vger.kernel.org -LANGUAGES = de fr it cs pt +LANGUAGES = de fr it cs pt ka # Directory definitions. These are default and most probably From 1f464cb4a7febcc8b5ad325f3f9a83c8d4e4c199 Mon Sep 17 00:00:00 2001 From: Liao Chang Date: Tue, 29 Aug 2023 07:01:50 +0000 Subject: [PATCH 2/6] cpufreq: Avoid printing kernel addresses in cpufreq_resume() The pointer value of policy and driver structure are currently printed in the error messages of cpufreq_resume(), this is not recommended and helpful. In order to be consistent with the error message in cpufreq_suspend() and easier to understand, print the name of driver strcture and the manage CPU of policy structure individually in the error messages of cpufreq_resume(). Link: https://lore.kernel.org/all/b7be717c-41d8-bbbf-3e97-3799948ab757@huawei.com Signed-off-by: Liao Chang Acked-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index a757f90aa9d6..bd7bb0d58ef0 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -1943,16 +1943,16 @@ void cpufreq_resume(void) for_each_active_policy(policy) { if (cpufreq_driver->resume && cpufreq_driver->resume(policy)) { - pr_err("%s: Failed to resume driver: %p\n", __func__, - policy); + pr_err("%s: Failed to resume driver: %s\n", __func__, + cpufreq_driver->name); } else if (has_target()) { down_write(&policy->rwsem); ret = cpufreq_start_governor(policy); up_write(&policy->rwsem); if (ret) - pr_err("%s: Failed to start governor for policy: %p\n", - __func__, policy); + pr_err("%s: Failed to start governor for CPU%u's policy\n", + __func__, policy->cpu); } } } From 61bfbf7951ba561dcbdd5357702d3cbc2d447812 Mon Sep 17 00:00:00 2001 From: Liao Chang Date: Tue, 29 Aug 2023 07:03:18 +0000 Subject: [PATCH 3/6] cpufreq: Fix the race condition while updating the transition_task of policy The field 'transition_task' of policy structure is used to track the task which is performing the frequency transition. Using this field to print a warning once detect a case where the same task is calling _begin() again before completing the preivous frequency transition via the _end(). However, there is a potential race condition in _end() and _begin() APIs while updating the field 'transition_task' of policy, the scenario is depicted below: Task A Task B /* 1st freq transition */ Invoke _begin() { ... ... } /* 2nd freq transition */ Invoke _begin() { ... //waiting for A to ... //clear ... //transition_ongoing ... //in _end() for ... //the 1st transition | Change the frequency | | Invoke _end() { | ... | ... | transition_ongoing = false; V transition_ongoing = true; transition_task = current; transition_task = NULL; ... //A overwrites the task ... //performing the transition ... //result in error warning. } To fix this race condition, the transition_lock of policy structure is now acquired before updating policy structure in _end() API. Which ensure that only one task can update the 'transition_task' field at a time. Link: https://lore.kernel.org/all/b3c61d8a-d52d-3136-fbf0-d1de9f1ba411@huawei.com/ Fixes: ca654dc3a93d ("cpufreq: Catch double invocations of cpufreq_freq_transition_begin/end") Signed-off-by: Liao Chang Acked-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index bd7bb0d58ef0..d9eb036245c3 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -455,8 +455,10 @@ void cpufreq_freq_transition_end(struct cpufreq_policy *policy, policy->cur, policy->cpuinfo.max_freq); + spin_lock(&policy->transition_lock); policy->transition_ongoing = false; policy->transition_task = NULL; + spin_unlock(&policy->transition_lock); wake_up(&policy->transition_wait); } From 916f13884042f615cfbfc0b42cc68dadee826f2a Mon Sep 17 00:00:00 2001 From: Liao Chang Date: Tue, 29 Aug 2023 07:03:46 +0000 Subject: [PATCH 4/6] cpufreq: governor: Free dbs_data directly when gov->init() fails Due to the kobject embedded in the dbs_data doest not has a release() method yet, it needs to use kfree() to free dbs_data directly when governor fails to allocate the tunner field of dbs_data. Signed-off-by: Liao Chang Acked-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq_governor.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c index 85da677c43d6..af44ee6a6430 100644 --- a/drivers/cpufreq/cpufreq_governor.c +++ b/drivers/cpufreq/cpufreq_governor.c @@ -439,7 +439,7 @@ int cpufreq_dbs_governor_init(struct cpufreq_policy *policy) ret = gov->init(dbs_data); if (ret) - goto free_policy_dbs_info; + goto free_dbs_data; /* * The sampling interval should not be less than the transition latency @@ -474,6 +474,8 @@ int cpufreq_dbs_governor_init(struct cpufreq_policy *policy) if (!have_governor_per_policy()) gov->gdbs_data = NULL; gov->exit(dbs_data); + +free_dbs_data: kfree(dbs_data); free_policy_dbs_info: From 4c2fdf7393647a7b01a83f49c4a331d562016640 Mon Sep 17 00:00:00 2001 From: Liao Chang Date: Sat, 26 Aug 2023 09:57:43 +0000 Subject: [PATCH 5/6] cpufreq: pcc: Fix the potentinal scheduling delays in target_index() pcc_cpufreq_target(): cpufreq_freq_transition_begin(); spin_lock(&pcc_lock); [critical section] cpufreq_freq_transition_end(); spin_unlock(&pcc_lock); Above code has a performance issue, consider that Task0 executes 'cpufreq_freq_transition_end()' to wake Task1 and preempted imediatedly without releasing 'pcc_lock', then Task1 needs to wait for Task0 to release 'pcc_lock'. In the worst case, this locking order can result in Task1 wasting two scheduling rounds before it can enter the critical section. Signed-off-by: Liao Chang Acked-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/pcc-cpufreq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/cpufreq/pcc-cpufreq.c b/drivers/cpufreq/pcc-cpufreq.c index 84fe37def0f1..6f8b5ea7aeae 100644 --- a/drivers/cpufreq/pcc-cpufreq.c +++ b/drivers/cpufreq/pcc-cpufreq.c @@ -232,8 +232,8 @@ static int pcc_cpufreq_target(struct cpufreq_policy *policy, status = ioread16(&pcch_hdr->status); iowrite16(0, &pcch_hdr->status); - cpufreq_freq_transition_end(policy, &freqs, status != CMD_COMPLETE); spin_unlock(&pcc_lock); + cpufreq_freq_transition_end(policy, &freqs, status != CMD_COMPLETE); if (status != CMD_COMPLETE) { pr_debug("target: FAILED for cpu %d, with status: 0x%x\n", From 218a06a79d9a98a96ef46bb003d4d8adb0962056 Mon Sep 17 00:00:00 2001 From: Jie Zhan Date: Tue, 22 Aug 2023 20:48:37 +0800 Subject: [PATCH 6/6] cpufreq: Support per-policy performance boost The boost control currently applies to the whole system. However, users may prefer to boost a subset of cores in order to provide prioritized performance to workloads running on the boosted cores. Enable per-policy boost by adding a 'boost' sysfs interface under each policy path. This can be found at: /sys/devices/system/cpu/cpufreq/policy<*>/boost Same to the global boost switch, writing 1/0 to the per-policy 'boost' enables/disables boost on a cpufreq policy respectively. The user view of global and per-policy boost controls should be: 1. Enabling global boost initially enables boost on all policies, and per-policy boost can then be enabled or disabled individually, given that the platform does support so. 2. Disabling global boost makes the per-policy boost interface illegal. Signed-off-by: Jie Zhan Reviewed-by: Wei Xu Acked-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq.c | 43 +++++++++++++++++++++++++++++++++++++++ include/linux/cpufreq.h | 3 +++ 2 files changed, 46 insertions(+) diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index d9eb036245c3..60ed89000e82 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -86,6 +86,7 @@ static void cpufreq_governor_limits(struct cpufreq_policy *policy); static int cpufreq_set_policy(struct cpufreq_policy *policy, struct cpufreq_governor *new_gov, unsigned int new_pol); +static bool cpufreq_boost_supported(void); /* * Two notifier lists: the "policy" list is involved in the @@ -623,6 +624,40 @@ static ssize_t store_boost(struct kobject *kobj, struct kobj_attribute *attr, } define_one_global_rw(boost); +static ssize_t show_local_boost(struct cpufreq_policy *policy, char *buf) +{ + return sysfs_emit(buf, "%d\n", policy->boost_enabled); +} + +static ssize_t store_local_boost(struct cpufreq_policy *policy, + const char *buf, size_t count) +{ + int ret, enable; + + ret = kstrtoint(buf, 10, &enable); + if (ret || enable < 0 || enable > 1) + return -EINVAL; + + if (!cpufreq_driver->boost_enabled) + return -EINVAL; + + if (policy->boost_enabled == enable) + return count; + + cpus_read_lock(); + ret = cpufreq_driver->set_boost(policy, enable); + cpus_read_unlock(); + + if (ret) + return ret; + + policy->boost_enabled = enable; + + return count; +} + +static struct freq_attr local_boost = __ATTR(boost, 0644, show_local_boost, store_local_boost); + static struct cpufreq_governor *find_governor(const char *str_governor) { struct cpufreq_governor *t; @@ -1057,6 +1092,12 @@ static int cpufreq_add_dev_interface(struct cpufreq_policy *policy) return ret; } + if (cpufreq_boost_supported()) { + ret = sysfs_create_file(&policy->kobj, &local_boost.attr); + if (ret) + return ret; + } + return 0; } @@ -2718,6 +2759,8 @@ int cpufreq_boost_trigger_state(int state) ret = cpufreq_driver->set_boost(policy, state); if (ret) goto err_reset_state; + + policy->boost_enabled = state; } cpus_read_unlock(); diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index 43b363a99215..71d186d6933a 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -141,6 +141,9 @@ struct cpufreq_policy { */ bool dvfs_possible_from_any_cpu; + /* Per policy boost enabled flag. */ + bool boost_enabled; + /* Cached frequency lookup from cpufreq_driver_resolve_freq. */ unsigned int cached_target_freq; unsigned int cached_resolved_idx;