The communication mean of the _CPC desired performance can be PCC, System Memory, System IO, or Functional Fixed Hardware. commit b7898fda5bc7 ("cpufreq: Support for fast frequency switching") fast_switching is 'for switching CPU frequencies from interrupt context'. Writes to SystemMemory and SystemIo are fast and suitable this. This is not the case for PCC and might not be the case for FFH. Enable fast_switching for the cppc_cpufreq driver in above cases. Add cppc_allow_fast_switch() to check the desired performance register address space and set fast_switching accordingly.
Unified · Split
| @@ -434,6 +434,24 @@ bool acpi_cpc_valid(void) · 433 unmodified lines | |||
| 434 | } | 434 | } |
| 435 | EXPORT_SYMBOL_GPL(acpi_cpc_valid); | 435 | EXPORT_SYMBOL_GPL(acpi_cpc_valid); |
| 436 | 436 | ||
| 437 | bool cppc_allow_fast_switch(void) | ||
| 438 | { | ||
| 439 | struct cpc_register_resource *desired_reg; | ||
| 440 | struct cpc_desc *cpc_ptr; | ||
| 441 | int cpu; | ||
| 442 | |||
| 443 | for_each_possible_cpu(cpu) { | ||
| 444 | cpc_ptr = per_cpu(cpc_desc_ptr, cpu); | ||
| 445 | desired_reg = &cpc_ptr->cpc_regs[DESIRED_PERF]; | ||
| 446 | if (!CPC_IN_SYSTEM_MEMORY(desired_reg) && | ||
| 447 | !CPC_IN_SYSTEM_IO(desired_reg)) | ||
| 448 | return false; | ||
| 449 | } | ||
| 450 | |||
| 451 | return true; | ||
| 452 | } | ||
| 453 | EXPORT_SYMBOL_GPL(cppc_allow_fast_switch); | ||
| 454 | |||
| 437 | /** | 455 | /** |
| 438 | * acpi_get_psd_map - Map the CPUs in the freq domain of a given cpu | 456 | * acpi_get_psd_map - Map the CPUs in the freq domain of a given cpu |
| 439 | * @cpu: Find all CPUs that share a domain with cpu. | 457 | * @cpu: Find all CPUs that share a domain with cpu. |
| @@ -389,6 +389,27 @@ static int cppc_cpufreq_set_target(struct cpufreq_policy *policy, · 388 unmodified lines | |||
| 389 | return ret; | 389 | return ret; |
| 390 | } | 390 | } |
| 391 | 391 | ||
| 392 | static unsigned int cppc_cpufreq_fast_switch(struct cpufreq_policy *policy, | ||
| 393 | unsigned int target_freq) | ||
| 394 | { | ||
| 395 | struct cppc_cpudata *cpu_data = policy->driver_data; | ||
| 396 | unsigned int cpu = policy->cpu; | ||
| 397 | u32 desired_perf; | ||
| 398 | int ret; | ||
| 399 | |||
| 400 | desired_perf = cppc_cpufreq_khz_to_perf(cpu_data, target_freq); | ||
| 401 | cpu_data->perf_ctrls.desired_perf = desired_perf; | ||
| 402 | ret = cppc_set_perf(cpu, &cpu_data->perf_ctrls); | ||
| 403 | |||
| 404 | if (ret) { | ||
| 405 | pr_debug("Failed to set target on CPU:%d. ret:%d\n", | ||
| 406 | cpu, ret); | ||
| 407 | return 0; | ||
| 408 | } | ||
| 409 | |||
| 410 | return target_freq; | ||
| 411 | } | ||
| 412 | |||
| 392 | static int cppc_verify_policy(struct cpufreq_policy_data *policy) | 413 | static int cppc_verify_policy(struct cpufreq_policy_data *policy) |
| 393 | { | 414 | { |
| 394 | cpufreq_verify_within_cpu_limits(policy); | 415 | cpufreq_verify_within_cpu_limits(policy); |
| @@ -721,6 +742,8 @@ static int cppc_cpufreq_cpu_init(struct cpufreq_policy *policy) · 326 unmodified lines | |||
| 721 | goto out; | 742 | goto out; |
| 722 | } | 743 | } |
| 723 | 744 | ||
| 745 | policy->fast_switch_possible = cppc_allow_fast_switch(); | ||
| 746 | |||
| 724 | /* | 747 | /* |
| 725 | * If 'highest_perf' is greater than 'nominal_perf', we assume CPU Boost | 748 | * If 'highest_perf' is greater than 'nominal_perf', we assume CPU Boost |
| 726 | * is supported. | 749 | * is supported. |
| @@ -866,6 +889,7 @@ static struct cpufreq_driver cppc_cpufreq_driver = { · 139 unmodified lines | |||
| 866 | .verify = cppc_verify_policy, | 889 | .verify = cppc_verify_policy, |
| 867 | .target = cppc_cpufreq_set_target, | 890 | .target = cppc_cpufreq_set_target, |
| 868 | .get = cppc_cpufreq_get_rate, | 891 | .get = cppc_cpufreq_get_rate, |
| 892 | .fast_switch = cppc_cpufreq_fast_switch, | ||
| 869 | .init = cppc_cpufreq_cpu_init, | 893 | .init = cppc_cpufreq_cpu_init, |
| 870 | .exit = cppc_cpufreq_cpu_exit, | 894 | .exit = cppc_cpufreq_cpu_exit, |
| 871 | .set_boost = cppc_cpufreq_set_boost, | 895 | .set_boost = cppc_cpufreq_set_boost, |
| @@ -141,6 +141,7 @@ extern int cppc_set_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls); · 140 unmodified lines | |||
| 141 | extern int cppc_set_enable(int cpu, bool enable); | 141 | extern int cppc_set_enable(int cpu, bool enable); |
| 142 | extern int cppc_get_perf_caps(int cpu, struct cppc_perf_caps *caps); | 142 | extern int cppc_get_perf_caps(int cpu, struct cppc_perf_caps *caps); |
| 143 | extern bool acpi_cpc_valid(void); | 143 | extern bool acpi_cpc_valid(void); |
| 144 | extern bool cppc_allow_fast_switch(void); | ||
| 144 | extern int acpi_get_psd_map(unsigned int cpu, struct cppc_cpudata *cpu_data); | 145 | extern int acpi_get_psd_map(unsigned int cpu, struct cppc_cpudata *cpu_data); |
| 145 | extern unsigned int cppc_get_transition_latency(int cpu); | 146 | extern unsigned int cppc_get_transition_latency(int cpu); |
| 146 | extern bool cpc_ffh_supported(void); | 147 | extern bool cpc_ffh_supported(void); |
| @@ -175,6 +176,10 @@ static inline bool acpi_cpc_valid(void) · 28 unmodified lines | |||
| 175 | { | 176 | { |
| 176 | return false; | 177 | return false; |
| 177 | } | 178 | } |
| 179 | static inline bool cppc_allow_fast_switch(void) | ||
| 180 | { | ||
| 181 | return false; | ||
| 182 | } | ||
| 178 | static inline unsigned int cppc_get_transition_latency(int cpu) | 183 | static inline unsigned int cppc_get_transition_latency(int cpu) |
| 179 | { | 184 | { |
| 180 | return CPUFREQ_ETERNAL; | 185 | return CPUFREQ_ETERNAL; |