diff --git a/Documentation/ABI/testing/sysfs-devices-system-cpu b/Documentation/ABI/testing/sysfs-devices-system-cpu index 3107b013e333d..e848ea79745e1 100644 --- a/Documentation/ABI/testing/sysfs-devices-system-cpu +++ b/Documentation/ABI/testing/sysfs-devices-system-cpu @@ -327,32 +327,6 @@ Description: Energy performance preference This file is only present if the cppc-cpufreq driver is in use. -What: /sys/devices/system/cpu/cpuX/cpufreq/min_perf -Date: February 2026 -Contact: linux-pm@vger.kernel.org -Description: Minimum Performance Frequency - - Read/write a frequency value in kHz from/to this file. This - file sets the minimum performance level (as frequency) at - which the platform may run. The frequency value is internally - converted to a performance value and must be in the range - [cpuinfo_min_freq, cpuinfo_max_freq], inclusive. - - This file is only present if the cppc-cpufreq driver is in use. - -What: /sys/devices/system/cpu/cpuX/cpufreq/max_perf -Date: February 2026 -Contact: linux-pm@vger.kernel.org -Description: Maximum Performance Frequency - - Read/write a frequency value in kHz from/to this file. This - file sets the maximum performance level (as frequency) at - which the platform may run. The frequency value is internally - converted to a performance value and must be in the range - [cpuinfo_min_freq, cpuinfo_max_freq], inclusive. - - This file is only present if the cppc-cpufreq driver is in use. - What: /sys/devices/system/cpu/cpuX/cpufreq/perf_limited Date: February 2026 Contact: linux-pm@vger.kernel.org diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index c7665adbe226a..35958f16288ff 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -943,6 +943,19 @@ policy to use. This governor must be registered in the kernel before the cpufreq driver probes. + cppc_cpufreq.auto_sel_mode= + [CPU_FREQ] Enable ACPI CPPC autonomous performance + selection. When enabled, hardware automatically adjusts + CPU frequency on all CPUs based on workload demands. + In Autonomous mode, Energy Performance Preference (EPP) + hints guide hardware toward performance (0x0) or energy + efficiency (0xff). + Requires ACPI CPPC autonomous selection register support. + Format: + Default: 0 (disabled) + 0: use cpufreq governors + 1: enable if supported by hardware + cpu_init_udelay=N [X86,EARLY] Delay for N microsec between assert and de-assert of APIC INIT to start processors. This delay occurs diff --git a/Documentation/cpu-freq/cpu-drivers.rst b/Documentation/cpu-freq/cpu-drivers.rst index c5635ac3de547..ab4f3c0f3a89b 100644 --- a/Documentation/cpu-freq/cpu-drivers.rst +++ b/Documentation/cpu-freq/cpu-drivers.rst @@ -114,8 +114,14 @@ Then, the driver must fill in the following values: |policy->cur | The current operating frequency of | | | this CPU (if appropriate) | +-----------------------------------+--------------------------------------+ -|policy->min, | | -|policy->max, | | +|policy->min | If set by the driver in ->init(), | +| | used as initial minimum frequency | +| | QoS request. | ++-----------------------------------+--------------------------------------+ +|policy->max | If set by the driver in ->init(), | +| | used as initial maximum frequency | +| | QoS request. | ++-----------------------------------+--------------------------------------+ |policy->policy and, if necessary, | | |policy->governor | must contain the "default policy" for| | | this CPU. A few moments later, | diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c index 0cbeeccae8cb8..7c845a4312c43 100644 --- a/drivers/acpi/cppc_acpi.c +++ b/drivers/acpi/cppc_acpi.c @@ -177,12 +177,12 @@ __ATTR(_name, 0444, show_##_name, NULL) show_cppc_data(cppc_get_perf_caps, cppc_perf_caps, highest_perf); show_cppc_data(cppc_get_perf_caps, cppc_perf_caps, lowest_perf); show_cppc_data(cppc_get_perf_caps, cppc_perf_caps, nominal_perf); +show_cppc_data(cppc_get_perf_caps, cppc_perf_caps, reference_perf); show_cppc_data(cppc_get_perf_caps, cppc_perf_caps, lowest_nonlinear_perf); show_cppc_data(cppc_get_perf_caps, cppc_perf_caps, guaranteed_perf); show_cppc_data(cppc_get_perf_caps, cppc_perf_caps, lowest_freq); show_cppc_data(cppc_get_perf_caps, cppc_perf_caps, nominal_freq); -show_cppc_data(cppc_get_perf_ctrs, cppc_perf_fb_ctrs, reference_perf); show_cppc_data(cppc_get_perf_ctrs, cppc_perf_fb_ctrs, wraparound_time); /* Check for valid access_width, otherwise, fallback to using bit_width */ @@ -1353,9 +1353,10 @@ int cppc_get_perf_caps(int cpunum, struct cppc_perf_caps *perf_caps) { struct cpc_desc *cpc_desc = per_cpu(cpc_desc_ptr, cpunum); struct cpc_register_resource *highest_reg, *lowest_reg, - *lowest_non_linear_reg, *nominal_reg, *guaranteed_reg, - *low_freq_reg = NULL, *nom_freq_reg = NULL; - u64 high, low, guaranteed, nom, min_nonlinear, low_f = 0, nom_f = 0; + *lowest_non_linear_reg, *nominal_reg, *reference_reg, + *guaranteed_reg, *low_freq_reg = NULL, *nom_freq_reg = NULL; + u64 high, low, guaranteed, nom, ref, min_nonlinear, + low_f = 0, nom_f = 0; int pcc_ss_id = per_cpu(cpu_pcc_subspace_idx, cpunum); struct cppc_pcc_data *pcc_ss_data = NULL; int ret = 0, regs_in_pcc = 0; @@ -1369,6 +1370,7 @@ int cppc_get_perf_caps(int cpunum, struct cppc_perf_caps *perf_caps) lowest_reg = &cpc_desc->cpc_regs[LOWEST_PERF]; lowest_non_linear_reg = &cpc_desc->cpc_regs[LOW_NON_LINEAR_PERF]; nominal_reg = &cpc_desc->cpc_regs[NOMINAL_PERF]; + reference_reg = &cpc_desc->cpc_regs[REFERENCE_PERF]; low_freq_reg = &cpc_desc->cpc_regs[LOWEST_FREQ]; nom_freq_reg = &cpc_desc->cpc_regs[NOMINAL_FREQ]; guaranteed_reg = &cpc_desc->cpc_regs[GUARANTEED_PERF]; @@ -1376,6 +1378,7 @@ int cppc_get_perf_caps(int cpunum, struct cppc_perf_caps *perf_caps) /* Are any of the regs PCC ?*/ if (CPC_IN_PCC(highest_reg) || CPC_IN_PCC(lowest_reg) || CPC_IN_PCC(lowest_non_linear_reg) || CPC_IN_PCC(nominal_reg) || + (CPC_SUPPORTED(reference_reg) && CPC_IN_PCC(reference_reg)) || CPC_IN_PCC(low_freq_reg) || CPC_IN_PCC(nom_freq_reg) || CPC_IN_PCC(guaranteed_reg)) { if (pcc_ss_id < 0) { @@ -1392,35 +1395,66 @@ int cppc_get_perf_caps(int cpunum, struct cppc_perf_caps *perf_caps) } } - cpc_read(cpunum, highest_reg, &high); + ret = cpc_read(cpunum, highest_reg, &high); + if (ret) + goto out_err; perf_caps->highest_perf = high; - cpc_read(cpunum, lowest_reg, &low); + ret = cpc_read(cpunum, lowest_reg, &low); + if (ret) + goto out_err; perf_caps->lowest_perf = low; - cpc_read(cpunum, nominal_reg, &nom); + ret = cpc_read(cpunum, nominal_reg, &nom); + if (ret) + goto out_err; perf_caps->nominal_perf = nom; + /* + * If reference perf register is not supported then we should + * use the nominal perf value + */ + if (CPC_SUPPORTED(reference_reg)) { + ret = cpc_read(cpunum, reference_reg, &ref); + if (ret) + goto out_err; + } else { + ref = nom; + } + perf_caps->reference_perf = ref; + if (guaranteed_reg->type != ACPI_TYPE_BUFFER || IS_NULL_REG(&guaranteed_reg->cpc_entry.reg)) { perf_caps->guaranteed_perf = 0; } else { - cpc_read(cpunum, guaranteed_reg, &guaranteed); + ret = cpc_read(cpunum, guaranteed_reg, &guaranteed); + if (ret) + goto out_err; perf_caps->guaranteed_perf = guaranteed; } - cpc_read(cpunum, lowest_non_linear_reg, &min_nonlinear); + ret = cpc_read(cpunum, lowest_non_linear_reg, &min_nonlinear); + if (ret) + goto out_err; perf_caps->lowest_nonlinear_perf = min_nonlinear; - if (!high || !low || !nom || !min_nonlinear) + if (!high || !low || !nom || !ref || !min_nonlinear) { ret = -EFAULT; + goto out_err; + } /* Read optional lowest and nominal frequencies if present */ - if (CPC_SUPPORTED(low_freq_reg)) - cpc_read(cpunum, low_freq_reg, &low_f); + if (CPC_SUPPORTED(low_freq_reg)) { + ret = cpc_read(cpunum, low_freq_reg, &low_f); + if (ret) + goto out_err; + } - if (CPC_SUPPORTED(nom_freq_reg)) - cpc_read(cpunum, nom_freq_reg, &nom_f); + if (CPC_SUPPORTED(nom_freq_reg)) { + ret = cpc_read(cpunum, nom_freq_reg, &nom_f); + if (ret) + goto out_err; + } perf_caps->lowest_freq = low_f; perf_caps->nominal_freq = nom_f; @@ -1447,7 +1481,6 @@ bool cppc_perf_ctrs_in_pcc(void) int cpu; for_each_online_cpu(cpu) { - struct cpc_register_resource *ref_perf_reg; struct cpc_desc *cpc_desc; cpc_desc = per_cpu(cpc_desc_ptr, cpu); @@ -1456,19 +1489,6 @@ bool cppc_perf_ctrs_in_pcc(void) CPC_IN_PCC(&cpc_desc->cpc_regs[REFERENCE_CTR]) || CPC_IN_PCC(&cpc_desc->cpc_regs[CTR_WRAP_TIME])) return true; - - - ref_perf_reg = &cpc_desc->cpc_regs[REFERENCE_PERF]; - - /* - * If reference perf register is not supported then we should - * use the nominal perf value - */ - if (!CPC_SUPPORTED(ref_perf_reg)) - ref_perf_reg = &cpc_desc->cpc_regs[NOMINAL_PERF]; - - if (CPC_IN_PCC(ref_perf_reg)) - return true; } return false; @@ -1486,10 +1506,10 @@ int cppc_get_perf_ctrs(int cpunum, struct cppc_perf_fb_ctrs *perf_fb_ctrs) { struct cpc_desc *cpc_desc = per_cpu(cpc_desc_ptr, cpunum); struct cpc_register_resource *delivered_reg, *reference_reg, - *ref_perf_reg, *ctr_wrap_reg; + *ctr_wrap_reg; int pcc_ss_id = per_cpu(cpu_pcc_subspace_idx, cpunum); struct cppc_pcc_data *pcc_ss_data = NULL; - u64 delivered, reference, ref_perf, ctr_wrap_time; + u64 delivered, reference, ctr_wrap_time; int ret = 0, regs_in_pcc = 0; if (!cpc_desc) { @@ -1499,19 +1519,11 @@ int cppc_get_perf_ctrs(int cpunum, struct cppc_perf_fb_ctrs *perf_fb_ctrs) delivered_reg = &cpc_desc->cpc_regs[DELIVERED_CTR]; reference_reg = &cpc_desc->cpc_regs[REFERENCE_CTR]; - ref_perf_reg = &cpc_desc->cpc_regs[REFERENCE_PERF]; ctr_wrap_reg = &cpc_desc->cpc_regs[CTR_WRAP_TIME]; - /* - * If reference perf register is not supported then we should - * use the nominal perf value - */ - if (!CPC_SUPPORTED(ref_perf_reg)) - ref_perf_reg = &cpc_desc->cpc_regs[NOMINAL_PERF]; - /* Are any of the regs PCC ?*/ if (CPC_IN_PCC(delivered_reg) || CPC_IN_PCC(reference_reg) || - CPC_IN_PCC(ctr_wrap_reg) || CPC_IN_PCC(ref_perf_reg)) { + CPC_IN_PCC(ctr_wrap_reg)) { if (pcc_ss_id < 0) { pr_debug("Invalid pcc_ss_id\n"); return -ENODEV; @@ -1526,9 +1538,13 @@ int cppc_get_perf_ctrs(int cpunum, struct cppc_perf_fb_ctrs *perf_fb_ctrs) } } - cpc_read(cpunum, delivered_reg, &delivered); - cpc_read(cpunum, reference_reg, &reference); - cpc_read(cpunum, ref_perf_reg, &ref_perf); + ret = cpc_read(cpunum, delivered_reg, &delivered); + if (ret) + goto out_err; + + ret = cpc_read(cpunum, reference_reg, &reference); + if (ret) + goto out_err; /* * Per spec, if ctr_wrap_time optional register is unsupported, then the @@ -1536,17 +1552,19 @@ int cppc_get_perf_ctrs(int cpunum, struct cppc_perf_fb_ctrs *perf_fb_ctrs) * platform */ ctr_wrap_time = (u64)(~((u64)0)); - if (CPC_SUPPORTED(ctr_wrap_reg)) - cpc_read(cpunum, ctr_wrap_reg, &ctr_wrap_time); + if (CPC_SUPPORTED(ctr_wrap_reg)) { + ret = cpc_read(cpunum, ctr_wrap_reg, &ctr_wrap_time); + if (ret) + goto out_err; + } - if (!delivered || !reference || !ref_perf) { + if (!delivered || !reference) { ret = -EFAULT; goto out_err; } perf_fb_ctrs->delivered = delivered; perf_fb_ctrs->reference = reference; - perf_fb_ctrs->reference_perf = ref_perf; perf_fb_ctrs->wraparound_time = ctr_wrap_time; out_err: if (regs_in_pcc) @@ -1747,106 +1765,6 @@ int cppc_set_auto_sel(int cpu, bool enable) } EXPORT_SYMBOL_GPL(cppc_set_auto_sel); -/** - * cppc_get_min_perf - Read minimum performance register. - * @cpu: CPU from which to read register. - * @min_perf: Return address. - */ -int cppc_get_min_perf(int cpu, u64 *min_perf) -{ - return cppc_get_reg_val(cpu, MIN_PERF, min_perf); -} -EXPORT_SYMBOL_GPL(cppc_get_min_perf); - -/** - * cppc_set_min_perf - Write minimum performance register. - * @cpu: CPU to which to write register. - * @min_perf: the desired minimum performance value to be updated. - */ -int cppc_set_min_perf(int cpu, u32 min_perf) -{ - return cppc_set_reg_val(cpu, MIN_PERF, min_perf); -} -EXPORT_SYMBOL_GPL(cppc_set_min_perf); - -/** - * cppc_get_max_perf - Read maximum performance register. - * @cpu: CPU from which to read register. - * @max_perf: Return address. - */ -int cppc_get_max_perf(int cpu, u64 *max_perf) -{ - return cppc_get_reg_val(cpu, MAX_PERF, max_perf); -} -EXPORT_SYMBOL_GPL(cppc_get_max_perf); - -/** - * cppc_set_max_perf - Write maximum performance register. - * @cpu: CPU to which to write register. - * @max_perf: the desired maximum performance value to be updated. - */ -int cppc_set_max_perf(int cpu, u32 max_perf) -{ - return cppc_set_reg_val(cpu, MAX_PERF, max_perf); -} -EXPORT_SYMBOL_GPL(cppc_set_max_perf); - -/** - * cppc_get_perf_limited - Get the Performance Limited register value. - * @cpu: CPU from which to get Performance Limited register. - * @perf_limited: Pointer to store the Performance Limited value. - * - * The returned value contains sticky status bits indicating platform-imposed - * performance limitations. - * - * Return: 0 for success, -EIO on failure, -EOPNOTSUPP if not supported. - */ -int cppc_get_perf_limited(int cpu, u64 *perf_limited) -{ - return cppc_get_reg_val(cpu, PERF_LIMITED, perf_limited); -} -EXPORT_SYMBOL_GPL(cppc_get_perf_limited); - -/** - * cppc_set_perf_limited() - Clear bits in the Performance Limited register. - * @cpu: CPU on which to write register. - * @bits_to_clear: Bitmask of bits to clear in the perf_limited register. - * - * The Performance Limited register contains two sticky bits set by platform: - * - Bit 0 (Desired_Excursion): Set when delivered performance is constrained - * below desired performance. Not used when Autonomous Selection is enabled. - * - Bit 1 (Minimum_Excursion): Set when delivered performance is constrained - * below minimum performance. - * - * These bits are sticky and remain set until OSPM explicitly clears them. - * This function only allows clearing bits (the platform sets them). - * - * Return: 0 for success, -EINVAL for invalid bits, -EIO on register - * access failure, -EOPNOTSUPP if not supported. - */ -int cppc_set_perf_limited(int cpu, u64 bits_to_clear) -{ - u64 current_val, new_val; - int ret; - - /* Only bits 0 and 1 are valid */ - if (bits_to_clear & ~CPPC_PERF_LIMITED_MASK) - return -EINVAL; - - if (!bits_to_clear) - return 0; - - ret = cppc_get_perf_limited(cpu, ¤t_val); - if (ret) - return ret; - - /* Clear the specified bits */ - new_val = current_val & ~bits_to_clear; - - return cppc_set_reg_val(cpu, PERF_LIMITED, new_val); -} -EXPORT_SYMBOL_GPL(cppc_set_perf_limited); - /** * cppc_set_enable - Set to enable CPPC on the processor by writing the * Continuous Performance Control package EnableRegister field. @@ -1914,24 +1832,39 @@ int cppc_get_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls) } /* Read optional elements if present */ - if (CPC_SUPPORTED(max_perf_reg)) - cpc_read(cpu, max_perf_reg, &max); + if (CPC_SUPPORTED(max_perf_reg)) { + ret = cpc_read(cpu, max_perf_reg, &max); + if (ret) + goto out_err; + } perf_ctrls->max_perf = max; - if (CPC_SUPPORTED(min_perf_reg)) - cpc_read(cpu, min_perf_reg, &min); + if (CPC_SUPPORTED(min_perf_reg)) { + ret = cpc_read(cpu, min_perf_reg, &min); + if (ret) + goto out_err; + } perf_ctrls->min_perf = min; - if (CPC_SUPPORTED(desired_perf_reg)) - cpc_read(cpu, desired_perf_reg, &desired_perf); + if (CPC_SUPPORTED(desired_perf_reg)) { + ret = cpc_read(cpu, desired_perf_reg, &desired_perf); + if (ret) + goto out_err; + } perf_ctrls->desired_perf = desired_perf; - if (CPC_SUPPORTED(energy_perf_reg)) - cpc_read(cpu, energy_perf_reg, &energy_perf); + if (CPC_SUPPORTED(energy_perf_reg)) { + ret = cpc_read(cpu, energy_perf_reg, &energy_perf); + if (ret) + goto out_err; + } perf_ctrls->energy_perf = energy_perf; - if (CPC_SUPPORTED(auto_sel_reg)) - cpc_read(cpu, auto_sel_reg, &auto_sel); + if (CPC_SUPPORTED(auto_sel_reg)) { + ret = cpc_read(cpu, auto_sel_reg, &auto_sel); + if (ret) + goto out_err; + } perf_ctrls->auto_sel = (bool)auto_sel; out_err: @@ -2073,6 +2006,62 @@ int cppc_set_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls) } EXPORT_SYMBOL_GPL(cppc_set_perf); +/** + * cppc_get_perf_limited - Get the Performance Limited register value. + * @cpu: CPU from which to get Performance Limited register. + * @perf_limited: Pointer to store the Performance Limited value. + * + * The returned value contains sticky status bits indicating platform-imposed + * performance limitations. + * + * Return: 0 for success, -EIO on failure, -EOPNOTSUPP if not supported. + */ +int cppc_get_perf_limited(int cpu, u64 *perf_limited) +{ + return cppc_get_reg_val(cpu, PERF_LIMITED, perf_limited); +} +EXPORT_SYMBOL_GPL(cppc_get_perf_limited); + +/** + * cppc_set_perf_limited() - Clear bits in the Performance Limited register. + * @cpu: CPU on which to write register. + * @bits_to_clear: Bitmask of bits to clear in the perf_limited register. + * + * The Performance Limited register contains two sticky bits set by platform: + * - Bit 0 (Desired_Excursion): Set when delivered performance is constrained + * below desired performance. Not used when Autonomous Selection is enabled. + * - Bit 1 (Minimum_Excursion): Set when delivered performance is constrained + * below minimum performance. + * + * These bits are sticky and remain set until OSPM explicitly clears them. + * This function only allows clearing bits (the platform sets them). + * + * Return: 0 for success, -EINVAL for invalid bits, -EIO on register + * access failure, -EOPNOTSUPP if not supported. + */ +int cppc_set_perf_limited(int cpu, u64 bits_to_clear) +{ + u64 current_val, new_val; + int ret; + + /* Only bits 0 and 1 are valid */ + if (bits_to_clear & ~CPPC_PERF_LIMITED_MASK) + return -EINVAL; + + if (!bits_to_clear) + return 0; + + ret = cppc_get_perf_limited(cpu, ¤t_val); + if (ret) + return ret; + + /* Clear the specified bits */ + new_val = current_val & ~bits_to_clear; + + return cppc_set_reg_val(cpu, PERF_LIMITED, new_val); +} +EXPORT_SYMBOL_GPL(cppc_set_perf_limited); + /** * cppc_get_transition_latency - returns frequency transition latency in ns * @cpu_num: CPU number for per_cpu(). diff --git a/drivers/cpufreq/amd-pstate.c b/drivers/cpufreq/amd-pstate.c index 602e4fa81d6c5..8847b6a50463c 100644 --- a/drivers/cpufreq/amd-pstate.c +++ b/drivers/cpufreq/amd-pstate.c @@ -754,8 +754,6 @@ static int amd_pstate_cpu_boost_update(struct cpufreq_policy *policy, bool on) else if (policy->cpuinfo.max_freq > nominal_freq) policy->cpuinfo.max_freq = nominal_freq; - policy->max = policy->cpuinfo.max_freq; - if (cppc_state == AMD_PSTATE_PASSIVE) { ret = freq_qos_update_request(&cpudata->req[1], policy->cpuinfo.max_freq); if (ret < 0) @@ -1003,12 +1001,10 @@ static int amd_pstate_cpu_init(struct cpufreq_policy *policy) perf = READ_ONCE(cpudata->perf); - policy->cpuinfo.min_freq = policy->min = perf_to_freq(perf, - cpudata->nominal_freq, - perf.lowest_perf); - policy->cpuinfo.max_freq = policy->max = perf_to_freq(perf, - cpudata->nominal_freq, - perf.highest_perf); + policy->cpuinfo.min_freq = perf_to_freq(perf, cpudata->nominal_freq, + perf.lowest_perf); + policy->cpuinfo.max_freq = perf_to_freq(perf, cpudata->nominal_freq, + perf.highest_perf); ret = amd_pstate_cppc_enable(policy); if (ret) @@ -1492,12 +1488,10 @@ static int amd_pstate_epp_cpu_init(struct cpufreq_policy *policy) perf = READ_ONCE(cpudata->perf); - policy->cpuinfo.min_freq = policy->min = perf_to_freq(perf, - cpudata->nominal_freq, - perf.lowest_perf); - policy->cpuinfo.max_freq = policy->max = perf_to_freq(perf, - cpudata->nominal_freq, - perf.highest_perf); + policy->cpuinfo.min_freq = perf_to_freq(perf, cpudata->nominal_freq, + perf.lowest_perf); + policy->cpuinfo.max_freq = perf_to_freq(perf, cpudata->nominal_freq, + perf.highest_perf); policy->driver_data = cpudata; ret = amd_pstate_cppc_enable(policy); diff --git a/drivers/cpufreq/cppc_cpufreq.c b/drivers/cpufreq/cppc_cpufreq.c index 7f8ff60dda01f..f6fa368116bb6 100644 --- a/drivers/cpufreq/cppc_cpufreq.c +++ b/drivers/cpufreq/cppc_cpufreq.c @@ -28,6 +28,9 @@ static struct cpufreq_driver cppc_cpufreq_driver; +/* Autonomous Selection boot parameter */ +static bool auto_sel_mode; + #ifdef CONFIG_ACPI_CPPC_CPUFREQ_FIE static enum { FIE_UNSET = -1, @@ -50,7 +53,8 @@ struct cppc_freq_invariance { static DEFINE_PER_CPU(struct cppc_freq_invariance, cppc_freq_inv); static struct kthread_worker *kworker_fie; -static int cppc_perf_from_fbctrs(struct cppc_perf_fb_ctrs *fb_ctrs_t0, +static int cppc_perf_from_fbctrs(u64 reference_perf, + struct cppc_perf_fb_ctrs *fb_ctrs_t0, struct cppc_perf_fb_ctrs *fb_ctrs_t1); /** @@ -76,7 +80,7 @@ static void cppc_scale_freq_workfn(struct kthread_work *work) struct cppc_perf_fb_ctrs fb_ctrs = {0}; struct cppc_cpudata *cpu_data; unsigned long local_freq_scale; - u64 perf; + u64 perf, ref_perf; cppc_fi = container_of(work, struct cppc_freq_invariance, work); cpu_data = cppc_fi->cpu_data; @@ -86,7 +90,9 @@ static void cppc_scale_freq_workfn(struct kthread_work *work) return; } - perf = cppc_perf_from_fbctrs(&cppc_fi->prev_perf_fb_ctrs, &fb_ctrs); + ref_perf = cpu_data->perf_caps.reference_perf; + perf = cppc_perf_from_fbctrs(ref_perf, + &cppc_fi->prev_perf_fb_ctrs, &fb_ctrs); if (!perf) return; @@ -256,6 +262,21 @@ static inline void cppc_freq_invariance_exit(void) } #endif /* CONFIG_ACPI_CPPC_CPUFREQ_FIE */ +static void cppc_cpufreq_update_perf_limits(struct cppc_cpudata *cpu_data, + struct cpufreq_policy *policy) +{ + struct cppc_perf_caps *caps = &cpu_data->perf_caps; + u32 min_perf, max_perf; + + min_perf = cppc_khz_to_perf(caps, policy->min); + max_perf = cppc_khz_to_perf(caps, policy->max); + + cpu_data->perf_ctrls.min_perf = + clamp_t(u32, min_perf, caps->lowest_perf, caps->highest_perf); + cpu_data->perf_ctrls.max_perf = + clamp_t(u32, max_perf, caps->lowest_perf, caps->highest_perf); +} + static int cppc_cpufreq_set_target(struct cpufreq_policy *policy, unsigned int target_freq, unsigned int relation) @@ -267,6 +288,8 @@ static int cppc_cpufreq_set_target(struct cpufreq_policy *policy, cpu_data->perf_ctrls.desired_perf = cppc_khz_to_perf(&cpu_data->perf_caps, target_freq); + cppc_cpufreq_update_perf_limits(cpu_data, policy); + freqs.old = policy->cur; freqs.new = target_freq; @@ -291,8 +314,9 @@ static unsigned int cppc_cpufreq_fast_switch(struct cpufreq_policy *policy, desired_perf = cppc_khz_to_perf(&cpu_data->perf_caps, target_freq); cpu_data->perf_ctrls.desired_perf = desired_perf; - ret = cppc_set_perf(cpu, &cpu_data->perf_ctrls); + cppc_cpufreq_update_perf_limits(cpu_data, policy); + ret = cppc_set_perf(cpu, &cpu_data->perf_ctrls); if (ret) { pr_debug("Failed to set target on CPU:%d. ret:%d\n", cpu, ret); @@ -539,35 +563,6 @@ static void populate_efficiency_class(void) } #endif -/* Set min/max performance HW register and cache the value */ -static int cppc_cpufreq_set_mperf_reg(struct cpufreq_policy *policy, - u64 val, bool is_min) -{ - struct cppc_cpudata *cpu_data = policy->driver_data; - struct cppc_perf_caps *caps = &cpu_data->perf_caps; - unsigned int cpu = policy->cpu; - u32 perf; - int ret; - - perf = clamp(val, caps->lowest_perf, caps->highest_perf); - - ret = is_min ? cppc_set_min_perf(cpu, perf) : - cppc_set_max_perf(cpu, perf); - if (ret) { - if (ret != -EOPNOTSUPP) - pr_warn("CPU%d: set %s_perf=%u failed (%d)\n", - cpu, is_min ? "min" : "max", perf, ret); - return ret; - } - - if (is_min) - cpu_data->perf_ctrls.min_perf = perf; - else - cpu_data->perf_ctrls.max_perf = perf; - - return 0; -} - static struct cppc_cpudata *cppc_cpufreq_get_cpu_data(unsigned int cpu) { struct cppc_cpudata *cpu_data; @@ -632,13 +627,19 @@ static int cppc_cpufreq_cpu_init(struct cpufreq_policy *policy) caps = &cpu_data->perf_caps; policy->driver_data = cpu_data; + /* + * Enable CPPC for both OS-driven and autonomous modes. + * The Enable register is optional - some platforms may not support it + */ + ret = cppc_set_enable(cpu, true); + if (ret && ret != -EOPNOTSUPP) + pr_warn("Failed to enable CPPC for CPU%d (%d)\n", cpu, ret); + /* * Set min to lowest nonlinear perf to avoid any efficiency penalty (see * Section 8.4.7.1.1.5 of ACPI 6.1 spec) */ policy->min = cppc_perf_to_khz(caps, caps->lowest_nonlinear_perf); - policy->max = cppc_perf_to_khz(caps, policy->boost_enabled ? - caps->highest_perf : caps->nominal_perf); /* * Set cpuinfo.min_freq to Lowest to make the full range of performance @@ -646,7 +647,8 @@ static int cppc_cpufreq_cpu_init(struct cpufreq_policy *policy) * nonlinear perf */ policy->cpuinfo.min_freq = cppc_perf_to_khz(caps, caps->lowest_perf); - policy->cpuinfo.max_freq = policy->max; + policy->cpuinfo.max_freq = cppc_perf_to_khz(caps, policy->boost_enabled ? + caps->highest_perf : caps->nominal_perf); policy->transition_delay_us = cppc_cpufreq_get_transition_delay_us(cpu); policy->shared_type = cpu_data->shared_type; @@ -685,11 +687,71 @@ static int cppc_cpufreq_cpu_init(struct cpufreq_policy *policy) policy->cur = cppc_perf_to_khz(caps, caps->highest_perf); cpu_data->perf_ctrls.desired_perf = caps->highest_perf; - ret = cppc_set_perf(cpu, &cpu_data->perf_ctrls); - if (ret) { - pr_debug("Err setting perf value:%d on CPU:%d. ret:%d\n", - caps->highest_perf, cpu, ret); - goto out; + /* + * Enable autonomous mode on first init if boot param is set. + * Check last_governor to detect first init and skip if auto_sel + * is already enabled. + */ + if (auto_sel_mode && policy->last_governor[0] == '\0' && + !cpu_data->perf_ctrls.auto_sel) { + /* Init min/max_perf from caps if not already set by HW. */ + if (!cpu_data->perf_ctrls.min_perf) + cpu_data->perf_ctrls.min_perf = caps->lowest_nonlinear_perf; + if (!cpu_data->perf_ctrls.max_perf) + cpu_data->perf_ctrls.max_perf = policy->boost_enabled ? + caps->highest_perf : caps->nominal_perf; + + cpu_data->perf_ctrls.desired_perf = + clamp_t(u32, cpu_data->perf_ctrls.desired_perf, + cpu_data->perf_ctrls.min_perf, + cpu_data->perf_ctrls.max_perf); + + policy->cur = cppc_perf_to_khz(caps, + cpu_data->perf_ctrls.desired_perf); + + /* EPP is optional - some platforms may not support it */ + ret = cppc_set_epp(cpu, CPPC_EPP_PERFORMANCE_PREF); + if (ret && ret != -EOPNOTSUPP) + pr_warn("Failed to set EPP for CPU%d (%d)\n", cpu, ret); + else if (!ret) + cpu_data->perf_ctrls.energy_perf = CPPC_EPP_PERFORMANCE_PREF; + + /* Program min/max/desired into CPPC regs before enabling auto_sel. */ + ret = cppc_set_perf(cpu, &cpu_data->perf_ctrls); + if (ret) { + pr_debug("Err setting perf for autonomous mode CPU:%d ret:%d\n", + cpu, ret); + goto out; + } + + ret = cppc_set_auto_sel(cpu, true); + if (ret && ret != -EOPNOTSUPP) { + pr_warn("Failed autonomous config for CPU%d (%d)\n", + cpu, ret); + goto out; + } + if (!ret) + cpu_data->perf_ctrls.auto_sel = true; + } + + if (cpu_data->perf_ctrls.auto_sel) { + /* Sync policy limits from HW when autonomous mode is active */ + policy->min = cppc_perf_to_khz(caps, + cpu_data->perf_ctrls.min_perf ?: + caps->lowest_nonlinear_perf); + policy->max = cppc_perf_to_khz(caps, + cpu_data->perf_ctrls.max_perf ?: + (policy->boost_enabled ? + caps->highest_perf : + caps->nominal_perf)); + } else { + /* Normal mode: governors control frequency */ + ret = cppc_set_perf(cpu, &cpu_data->perf_ctrls); + if (ret) { + pr_debug("Err setting perf value:%d on CPU:%d. ret:%d\n", + caps->highest_perf, cpu, ret); + goto out; + } } cppc_cpufreq_cpu_fie_init(policy); @@ -727,13 +789,11 @@ static inline u64 get_delta(u64 t1, u64 t0) return (u32)t1 - (u32)t0; } -static int cppc_perf_from_fbctrs(struct cppc_perf_fb_ctrs *fb_ctrs_t0, +static int cppc_perf_from_fbctrs(u64 reference_perf, + struct cppc_perf_fb_ctrs *fb_ctrs_t0, struct cppc_perf_fb_ctrs *fb_ctrs_t1) { u64 delta_reference, delta_delivered; - u64 reference_perf; - - reference_perf = fb_ctrs_t0->reference_perf; delta_reference = get_delta(fb_ctrs_t1->reference, fb_ctrs_t0->reference); @@ -770,7 +830,7 @@ static unsigned int cppc_cpufreq_get_rate(unsigned int cpu) struct cpufreq_policy *policy __free(put_cpufreq_policy) = cpufreq_cpu_get(cpu); struct cppc_perf_fb_ctrs fb_ctrs_t0 = {0}, fb_ctrs_t1 = {0}; struct cppc_cpudata *cpu_data; - u64 delivered_perf; + u64 delivered_perf, reference_perf; int ret; if (!policy) @@ -787,7 +847,9 @@ static unsigned int cppc_cpufreq_get_rate(unsigned int cpu) return 0; } - delivered_perf = cppc_perf_from_fbctrs(&fb_ctrs_t0, &fb_ctrs_t1); + reference_perf = cpu_data->perf_caps.reference_perf; + delivered_perf = cppc_perf_from_fbctrs(reference_perf, + &fb_ctrs_t0, &fb_ctrs_t1); if (!delivered_perf) goto out_invalid_counters; @@ -811,17 +873,11 @@ static int cppc_cpufreq_set_boost(struct cpufreq_policy *policy, int state) { struct cppc_cpudata *cpu_data = policy->driver_data; struct cppc_perf_caps *caps = &cpu_data->perf_caps; - int ret; if (state) - policy->max = cppc_perf_to_khz(caps, caps->highest_perf); + policy->cpuinfo.max_freq = cppc_perf_to_khz(caps, caps->highest_perf); else - policy->max = cppc_perf_to_khz(caps, caps->nominal_perf); - policy->cpuinfo.max_freq = policy->max; - - ret = freq_qos_update_request(policy->max_freq_req, policy->max); - if (ret < 0) - return ret; + policy->cpuinfo.max_freq = cppc_perf_to_khz(caps, caps->nominal_perf); return 0; } @@ -867,6 +923,27 @@ static ssize_t store_auto_select(struct cpufreq_policy *policy, cpu_data->perf_ctrls.auto_sel = val; + if (val) { + u32 old_min_perf = cpu_data->perf_ctrls.min_perf; + u32 old_max_perf = cpu_data->perf_ctrls.max_perf; + + /* + * When enabling autonomous selection, program MIN_PERF and + * MAX_PERF from current policy limits so that the platform + * uses the correct performance bounds immediately. + */ + cppc_cpufreq_update_perf_limits(cpu_data, policy); + + ret = cppc_set_perf(policy->cpu, &cpu_data->perf_ctrls); + if (ret) { + cpu_data->perf_ctrls.min_perf = old_min_perf; + cpu_data->perf_ctrls.max_perf = old_max_perf; + cppc_set_auto_sel(policy->cpu, false); + cpu_data->perf_ctrls.auto_sel = false; + return ret; + } + } + return count; } @@ -944,138 +1021,6 @@ store_energy_performance_preference_val(struct cpufreq_policy *policy, return count; } -/** - * show_min_perf - Show minimum performance as frequency (kHz) - * @policy: cpufreq policy - * @buf: buffer to write the frequency value to - * - * Reads the MIN_PERF register and converts the performance value to - * frequency (kHz). - */ -static ssize_t show_min_perf(struct cpufreq_policy *policy, char *buf) -{ - struct cppc_cpudata *cpu_data = policy->driver_data; - struct cppc_perf_caps *caps = &cpu_data->perf_caps; - u64 perf; - int ret; - - ret = cppc_get_min_perf(policy->cpu, &perf); - if (ret == -EOPNOTSUPP) - return sysfs_emit(buf, "\n"); - if (ret) - return ret; - - /* Use lowest_perf if register is uninitialized or out of range */ - if (perf == 0 || perf < caps->lowest_perf) - perf = caps->lowest_perf; - - /* Convert performance to frequency (kHz) for user */ - return sysfs_emit(buf, "%u\n", cppc_perf_to_khz(caps, perf)); -} - -/** - * store_min_perf - Set minimum performance from frequency (kHz) - * @policy: cpufreq policy - * @buf: buffer containing the frequency value - * @count: size of @buf - * - * Converts the user-provided frequency (kHz) to a performance value - * and writes it to the MIN_PERF register. - */ -static ssize_t store_min_perf(struct cpufreq_policy *policy, const char *buf, - size_t count) -{ - struct cppc_cpudata *cpu_data = policy->driver_data; - unsigned int freq_khz; - u64 perf; - int ret; - - ret = kstrtouint(buf, 0, &freq_khz); - if (ret) - return ret; - - /* Convert frequency (kHz) to performance value */ - perf = cppc_khz_to_perf(&cpu_data->perf_caps, freq_khz); - - /* - * min_perf must be less than or equal to max_perf. - * Skip check if max_perf is 0 (uninitialized). - */ - if (cpu_data->perf_ctrls.max_perf && - perf > cpu_data->perf_ctrls.max_perf) - return -EINVAL; - - ret = cppc_cpufreq_set_mperf_reg(policy, perf, true); - if (ret) - return ret; - - return count; -} - -/** - * show_max_perf - Show maximum performance as frequency (kHz) - * @policy: cpufreq policy - * @buf: buffer to write the frequency value to - * - * Reads the MAX_PERF register and converts the performance value to - * frequency (kHz). - */ -static ssize_t show_max_perf(struct cpufreq_policy *policy, char *buf) -{ - struct cppc_cpudata *cpu_data = policy->driver_data; - struct cppc_perf_caps *caps = &cpu_data->perf_caps; - u64 perf; - int ret; - - ret = cppc_get_max_perf(policy->cpu, &perf); - if (ret == -EOPNOTSUPP) - return sysfs_emit(buf, "\n"); - if (ret) - return ret; - - /* Use highest_perf if register is uninitialized or out of range */ - if (perf == 0 || perf > caps->highest_perf) - perf = caps->highest_perf; - - /* Convert performance to frequency (kHz) for user */ - return sysfs_emit(buf, "%u\n", cppc_perf_to_khz(caps, perf)); -} - -/** - * store_max_perf - Set maximum performance from frequency (kHz) - * @policy: cpufreq policy - * @buf: buffer containing the frequency value - * @count: size of @buf - * - * Converts the user-provided frequency (kHz) to a performance value - * and writes it to the MAX_PERF register. - */ -static ssize_t store_max_perf(struct cpufreq_policy *policy, const char *buf, - size_t count) -{ - struct cppc_cpudata *cpu_data = policy->driver_data; - unsigned int freq_khz; - u64 perf; - int ret; - - ret = kstrtouint(buf, 0, &freq_khz); - if (ret) - return ret; - - /* Convert frequency (kHz) to performance value */ - perf = cppc_khz_to_perf(&cpu_data->perf_caps, freq_khz); - - /* max_perf must be greater than or equal to min_perf */ - if (perf < cpu_data->perf_ctrls.min_perf) - return -EINVAL; - - ret = cppc_cpufreq_set_mperf_reg(policy, perf, false); - if (ret) - return ret; - - return count; -} - CPPC_CPUFREQ_ATTR_RW_U64(perf_limited, cppc_get_perf_limited, cppc_set_perf_limited) @@ -1083,8 +1028,6 @@ cpufreq_freq_attr_ro(freqdomain_cpus); cpufreq_freq_attr_rw(auto_select); cpufreq_freq_attr_rw(auto_act_window); cpufreq_freq_attr_rw(energy_performance_preference_val); -cpufreq_freq_attr_rw(min_perf); -cpufreq_freq_attr_rw(max_perf); cpufreq_freq_attr_rw(perf_limited); static struct freq_attr *cppc_cpufreq_attr[] = { @@ -1092,8 +1035,6 @@ static struct freq_attr *cppc_cpufreq_attr[] = { &auto_select, &auto_act_window, &energy_performance_preference_val, - &min_perf, - &max_perf, &perf_limited, NULL, }; @@ -1130,10 +1071,18 @@ static int __init cppc_cpufreq_init(void) static void __exit cppc_cpufreq_exit(void) { + unsigned int cpu; + + for_each_present_cpu(cpu) + cppc_set_auto_sel(cpu, false); + cpufreq_unregister_driver(&cppc_cpufreq_driver); cppc_freq_invariance_exit(); } +module_param(auto_sel_mode, bool, 0444); +MODULE_PARM_DESC(auto_sel_mode, "Enable CPPC autonomous performance selection at boot"); + module_exit(cppc_cpufreq_exit); MODULE_AUTHOR("Ashwin Chaugule"); MODULE_DESCRIPTION("CPUFreq driver based on the ACPI CPPC v5.0+ spec"); diff --git a/drivers/cpufreq/cpufreq-nforce2.c b/drivers/cpufreq/cpufreq-nforce2.c index fbbbe501cf2dc..831102522ad64 100644 --- a/drivers/cpufreq/cpufreq-nforce2.c +++ b/drivers/cpufreq/cpufreq-nforce2.c @@ -355,8 +355,8 @@ static int nforce2_cpu_init(struct cpufreq_policy *policy) min_fsb = NFORCE2_MIN_FSB; /* cpuinfo and default policy values */ - policy->min = policy->cpuinfo.min_freq = min_fsb * fid * 100; - policy->max = policy->cpuinfo.max_freq = max_fsb * fid * 100; + policy->cpuinfo.min_freq = min_fsb * fid * 100; + policy->cpuinfo.max_freq = max_fsb * fid * 100; return 0; } diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 852e024facc3c..b7ebe113e8afc 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -603,10 +603,19 @@ static int policy_set_boost(struct cpufreq_policy *policy, bool enable) policy->boost_enabled = enable; ret = cpufreq_driver->set_boost(policy, enable); - if (ret) + if (ret) { policy->boost_enabled = !policy->boost_enabled; + return ret; + } - return ret; + ret = freq_qos_update_request(&policy->boost_freq_req, policy->cpuinfo.max_freq); + if (ret < 0) { + policy->boost_enabled = !policy->boost_enabled; + cpufreq_driver->set_boost(policy, policy->boost_enabled); + return ret; + } + + return 0; } static ssize_t store_local_boost(struct cpufreq_policy *policy, @@ -754,7 +763,7 @@ static ssize_t store_##file_name \ if (ret) \ return ret; \ \ - ret = freq_qos_update_request(policy->object##_freq_req, val);\ + ret = freq_qos_update_request(&policy->object##_freq_req, val); \ return ret >= 0 ? count : ret; \ } @@ -1359,7 +1368,7 @@ static void cpufreq_policy_free(struct cpufreq_policy *policy) /* Cancel any pending policy->update work before freeing the policy. */ cancel_work_sync(&policy->update); - if (policy->max_freq_req) { + if (freq_qos_request_active(&policy->max_freq_req)) { /* * Remove max_freq_req after sending CPUFREQ_REMOVE_POLICY * notification, since CPUFREQ_CREATE_POLICY notification was @@ -1367,11 +1376,13 @@ static void cpufreq_policy_free(struct cpufreq_policy *policy) */ blocking_notifier_call_chain(&cpufreq_policy_notifier_list, CPUFREQ_REMOVE_POLICY, policy); - freq_qos_remove_request(policy->max_freq_req); + freq_qos_remove_request(&policy->max_freq_req); } - freq_qos_remove_request(policy->min_freq_req); - kfree(policy->min_freq_req); + if (freq_qos_request_active(&policy->min_freq_req)) + freq_qos_remove_request(&policy->min_freq_req); + if (freq_qos_request_active(&policy->boost_freq_req)) + freq_qos_remove_request(&policy->boost_freq_req); cpufreq_policy_put_kobj(policy); free_cpumask_var(policy->real_cpus); @@ -1380,6 +1391,47 @@ static void cpufreq_policy_free(struct cpufreq_policy *policy) kfree(policy); } +static int cpufreq_policy_init_qos(struct cpufreq_policy *policy) +{ + unsigned int min_freq, max_freq; + int ret; + + /* Use policy->min/max set by the driver as QoS requests. */ + min_freq = max(FREQ_QOS_MIN_DEFAULT_VALUE, policy->min); + if (policy->max) + max_freq = min(FREQ_QOS_MAX_DEFAULT_VALUE, policy->max); + else + max_freq = FREQ_QOS_MAX_DEFAULT_VALUE; + + /* + * If the driver didn't set policy->min/max, set them as + * they are used to clamp frequency requests. + */ + policy->min = policy->min ? policy->min : policy->cpuinfo.min_freq; + policy->max = policy->max ? policy->max : policy->cpuinfo.max_freq; + + if (policy->boost_supported) { + ret = freq_qos_add_request(&policy->constraints, + &policy->boost_freq_req, + FREQ_QOS_MAX, + policy->cpuinfo.max_freq); + if (ret < 0) + return ret; + } + + ret = freq_qos_add_request(&policy->constraints, &policy->min_freq_req, + FREQ_QOS_MIN, min_freq); + if (ret < 0) + return ret; + + ret = freq_qos_add_request(&policy->constraints, &policy->max_freq_req, + FREQ_QOS_MAX, max_freq); + if (ret < 0) + return ret; + + return ret; +} + static int cpufreq_policy_online(struct cpufreq_policy *policy, unsigned int cpu, bool new_policy) { @@ -1425,6 +1477,12 @@ static int cpufreq_policy_online(struct cpufreq_policy *policy, if (ret) goto out_offline_policy; + if (new_policy) { + ret = cpufreq_policy_init_qos(policy); + if (ret < 0) + goto out_offline_policy; + } + /* related_cpus should at least include policy->cpus. */ cpumask_copy(policy->related_cpus, policy->cpus); } @@ -1441,47 +1499,8 @@ static int cpufreq_policy_online(struct cpufreq_policy *policy, add_cpu_dev_symlink(policy, j, get_cpu_device(j)); } - policy->min_freq_req = kzalloc(2 * sizeof(*policy->min_freq_req), - GFP_KERNEL); - if (!policy->min_freq_req) { - ret = -ENOMEM; - goto out_destroy_policy; - } - - ret = freq_qos_add_request(&policy->constraints, - policy->min_freq_req, FREQ_QOS_MIN, - FREQ_QOS_MIN_DEFAULT_VALUE); - if (ret < 0) { - /* - * So we don't call freq_qos_remove_request() for an - * uninitialized request. - */ - kfree(policy->min_freq_req); - policy->min_freq_req = NULL; - goto out_destroy_policy; - } - - /* - * This must be initialized right here to avoid calling - * freq_qos_remove_request() on uninitialized request in case - * of errors. - */ - policy->max_freq_req = policy->min_freq_req + 1; - - ret = freq_qos_add_request(&policy->constraints, - policy->max_freq_req, FREQ_QOS_MAX, - FREQ_QOS_MAX_DEFAULT_VALUE); - if (ret < 0) { - policy->max_freq_req = NULL; - goto out_destroy_policy; - } - blocking_notifier_call_chain(&cpufreq_policy_notifier_list, CPUFREQ_CREATE_POLICY, policy); - } else { - ret = freq_qos_update_request(policy->max_freq_req, policy->max); - if (ret < 0) - goto out_destroy_policy; } if (cpufreq_driver->get && has_target()) { @@ -2783,16 +2802,10 @@ int cpufreq_boost_set_sw(struct cpufreq_policy *policy, int state) return -ENXIO; ret = cpufreq_frequency_table_cpuinfo(policy); - if (ret) { + if (ret) pr_err("%s: Policy frequency update failed\n", __func__); - return ret; - } - ret = freq_qos_update_request(policy->max_freq_req, policy->max); - if (ret < 0) - return ret; - - return 0; + return ret; } EXPORT_SYMBOL_GPL(cpufreq_boost_set_sw); diff --git a/drivers/cpufreq/freq_table.c b/drivers/cpufreq/freq_table.c index 7f251daf03ce3..9b37f37c36389 100644 --- a/drivers/cpufreq/freq_table.c +++ b/drivers/cpufreq/freq_table.c @@ -49,16 +49,15 @@ int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy) max_freq = freq; } - policy->min = policy->cpuinfo.min_freq = min_freq; - policy->max = max_freq; + policy->cpuinfo.min_freq = min_freq; /* * If the driver has set its own cpuinfo.max_freq above max_freq, leave * it as is. */ if (policy->cpuinfo.max_freq < max_freq) - policy->max = policy->cpuinfo.max_freq = max_freq; + policy->cpuinfo.max_freq = max_freq; - if (policy->min == ~0) + if (min_freq == ~0) return -EINVAL; else return 0; diff --git a/drivers/cpufreq/gx-suspmod.c b/drivers/cpufreq/gx-suspmod.c index 75b3ef7ec6796..0970ba6757ec2 100644 --- a/drivers/cpufreq/gx-suspmod.c +++ b/drivers/cpufreq/gx-suspmod.c @@ -421,7 +421,7 @@ static int cpufreq_gx_cpu_init(struct cpufreq_policy *policy) policy->min = maxfreq / max_duration; else policy->min = maxfreq / POLICY_MIN_DIV; - policy->max = maxfreq; + policy->cpuinfo.min_freq = maxfreq / max_duration; policy->cpuinfo.max_freq = maxfreq; diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index 5efda8af4b708..1e64f97eced69 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c @@ -3080,9 +3080,6 @@ static int __intel_pstate_cpu_init(struct cpufreq_policy *policy) policy->cpuinfo.max_freq = READ_ONCE(global.no_turbo) ? cpu->pstate.max_freq : cpu->pstate.turbo_freq; - policy->min = policy->cpuinfo.min_freq; - policy->max = policy->cpuinfo.max_freq; - intel_pstate_init_acpi_perf_limits(policy); policy->fast_switch_possible = true; diff --git a/drivers/cpufreq/pcc-cpufreq.c b/drivers/cpufreq/pcc-cpufreq.c index ac2e90a65f0c4..0f185a13577f8 100644 --- a/drivers/cpufreq/pcc-cpufreq.c +++ b/drivers/cpufreq/pcc-cpufreq.c @@ -551,13 +551,11 @@ static int pcc_cpufreq_cpu_init(struct cpufreq_policy *policy) goto out; } - policy->max = policy->cpuinfo.max_freq = - ioread32(&pcch_hdr->nominal) * 1000; - policy->min = policy->cpuinfo.min_freq = - ioread32(&pcch_hdr->minimum_frequency) * 1000; + policy->cpuinfo.max_freq = ioread32(&pcch_hdr->nominal) * 1000; + policy->cpuinfo.min_freq = ioread32(&pcch_hdr->minimum_frequency) * 1000; - pr_debug("init: policy->max is %d, policy->min is %d\n", - policy->max, policy->min); + pr_debug("init: max_freq is %d, min_freq is %d\n", + policy->cpuinfo.max_freq, policy->cpuinfo.min_freq); out: return result; } diff --git a/drivers/cpufreq/pxa3xx-cpufreq.c b/drivers/cpufreq/pxa3xx-cpufreq.c index 4afa48d172dbe..433da686ea573 100644 --- a/drivers/cpufreq/pxa3xx-cpufreq.c +++ b/drivers/cpufreq/pxa3xx-cpufreq.c @@ -185,9 +185,8 @@ static int pxa3xx_cpufreq_init(struct cpufreq_policy *policy) int ret = -EINVAL; /* set default policy and cpuinfo */ - policy->min = policy->cpuinfo.min_freq = 104000; - policy->max = policy->cpuinfo.max_freq = - (cpu_is_pxa320()) ? 806000 : 624000; + policy->cpuinfo.min_freq = 104000; + policy->cpuinfo.max_freq = (cpu_is_pxa320()) ? 806000 : 624000; policy->cpuinfo.transition_latency = 1000; /* FIXME: 1 ms, assumed */ if (cpu_is_pxa300() || cpu_is_pxa310()) diff --git a/drivers/cpufreq/sh-cpufreq.c b/drivers/cpufreq/sh-cpufreq.c index 642ddb9ea217e..3c99d7009cbe2 100644 --- a/drivers/cpufreq/sh-cpufreq.c +++ b/drivers/cpufreq/sh-cpufreq.c @@ -124,10 +124,8 @@ static int sh_cpufreq_cpu_init(struct cpufreq_policy *policy) dev_notice(dev, "no frequency table found, falling back " "to rate rounding.\n"); - policy->min = policy->cpuinfo.min_freq = - (clk_round_rate(cpuclk, 1) + 500) / 1000; - policy->max = policy->cpuinfo.max_freq = - (clk_round_rate(cpuclk, ~0UL) + 500) / 1000; + policy->cpuinfo.min_freq = (clk_round_rate(cpuclk, 1) + 500) / 1000; + policy->cpuinfo.max_freq = (clk_round_rate(cpuclk, ~0UL) + 500) / 1000; } return 0; diff --git a/drivers/cpufreq/virtual-cpufreq.c b/drivers/cpufreq/virtual-cpufreq.c index 6ffa16d239b2b..60707bf6ce1e3 100644 --- a/drivers/cpufreq/virtual-cpufreq.c +++ b/drivers/cpufreq/virtual-cpufreq.c @@ -164,10 +164,7 @@ static int virt_cpufreq_get_freq_info(struct cpufreq_policy *policy) policy->cpuinfo.min_freq = 1; policy->cpuinfo.max_freq = virt_cpufreq_get_perftbl_entry(policy->cpu, 0); - policy->min = policy->cpuinfo.min_freq; - policy->max = policy->cpuinfo.max_freq; - - policy->cur = policy->max; + policy->cur = policy->cpuinfo.max_freq; return 0; } diff --git a/include/acpi/cppc_acpi.h b/include/acpi/cppc_acpi.h index 57e04326a4b61..1a1e41214cd54 100644 --- a/include/acpi/cppc_acpi.h +++ b/include/acpi/cppc_acpi.h @@ -121,6 +121,7 @@ struct cppc_perf_caps { u32 guaranteed_perf; u32 highest_perf; u32 nominal_perf; + u32 reference_perf; u32 lowest_perf; u32 lowest_nonlinear_perf; u32 lowest_freq; @@ -138,7 +139,6 @@ struct cppc_perf_ctrls { struct cppc_perf_fb_ctrs { u64 reference; u64 delivered; - u64 reference_perf; u64 wraparound_time; }; @@ -178,12 +178,8 @@ extern int cppc_get_auto_act_window(int cpu, u64 *auto_act_window); extern int cppc_set_auto_act_window(int cpu, u64 auto_act_window); extern int cppc_get_auto_sel(int cpu, bool *enable); extern int cppc_set_auto_sel(int cpu, bool enable); -extern int cppc_get_min_perf(int cpu, u64 *min_perf); -extern int cppc_set_min_perf(int cpu, u32 min_perf); -extern int cppc_get_max_perf(int cpu, u64 *max_perf); -extern int cppc_set_max_perf(int cpu, u32 max_perf); extern int cppc_get_perf_limited(int cpu, u64 *perf_limited); -extern int cppc_set_perf_limited(int cpu, u64 perf_limited); +extern int cppc_set_perf_limited(int cpu, u64 bits_to_clear); extern int amd_get_highest_perf(unsigned int cpu, u32 *highest_perf); extern int amd_get_boost_ratio_numerator(unsigned int cpu, u64 *numerator); extern int amd_detect_prefcore(bool *detected); @@ -276,27 +272,11 @@ static inline int cppc_set_auto_sel(int cpu, bool enable) { return -EOPNOTSUPP; } -static inline int cppc_get_min_perf(int cpu, u64 *min_perf) -{ - return -EOPNOTSUPP; -} -static inline int cppc_set_min_perf(int cpu, u32 min_perf) -{ - return -EOPNOTSUPP; -} -static inline int cppc_get_max_perf(int cpu, u64 *max_perf) -{ - return -EOPNOTSUPP; -} -static inline int cppc_set_max_perf(int cpu, u32 max_perf) -{ - return -EOPNOTSUPP; -} static inline int cppc_get_perf_limited(int cpu, u64 *perf_limited) { return -EOPNOTSUPP; } -static inline int cppc_set_perf_limited(int cpu, u64 perf_limited) +static inline int cppc_set_perf_limited(int cpu, u64 bits_to_clear) { return -EOPNOTSUPP; } diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index 0465d1e6f72ac..2a2ad2a4586b8 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -79,8 +79,9 @@ struct cpufreq_policy { * called, but you're in IRQ context */ struct freq_constraints constraints; - struct freq_qos_request *min_freq_req; - struct freq_qos_request *max_freq_req; + struct freq_qos_request min_freq_req; + struct freq_qos_request max_freq_req; + struct freq_qos_request boost_freq_req; struct cpufreq_frequency_table *freq_table; enum cpufreq_table_sorting freq_table_sorted;