Message ID | 20230206172157.49887-2-wyes.karny@amd.com (mailing list archive) |
---|---|
State | Superseded, archived |
Headers | show |
Series | amd_pstate: Add guided autonomous mode support | expand |
On Tue, Feb 07, 2023 at 01:21:52AM +0800, Karny, Wyes wrote: > Currently writing of min and max perf register is deferred in > cppc_set_perf function. In CPPC guided mode, these registers needed to > be written to guide the platform about min and max perf levels. Add this support > to make guided mode work properly on AMD shared memory systems. > > Signed-off-by: Wyes Karny <wyes.karny@amd.com> > Reviewed-by: Mario Limonciello <mario.limonciello@amd.com> Acked-by: Huang Rui <ray.huang@amd.com> > --- > drivers/acpi/cppc_acpi.c | 24 ++++++++++++++++-------- > 1 file changed, 16 insertions(+), 8 deletions(-) > > diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c > index 02d83c807271..91f9ef75f7de 100644 > --- a/drivers/acpi/cppc_acpi.c > +++ b/drivers/acpi/cppc_acpi.c > @@ -1487,7 +1487,7 @@ EXPORT_SYMBOL_GPL(cppc_set_enable); > int cppc_set_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls) > { > struct cpc_desc *cpc_desc = per_cpu(cpc_desc_ptr, cpu); > - struct cpc_register_resource *desired_reg; > + struct cpc_register_resource *desired_reg, *min_perf_reg, *max_perf_reg; > int pcc_ss_id = per_cpu(cpu_pcc_subspace_idx, cpu); > struct cppc_pcc_data *pcc_ss_data = NULL; > int ret = 0; > @@ -1498,6 +1498,8 @@ int cppc_set_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls) > } > > desired_reg = &cpc_desc->cpc_regs[DESIRED_PERF]; > + min_perf_reg = &cpc_desc->cpc_regs[MIN_PERF]; > + max_perf_reg = &cpc_desc->cpc_regs[MAX_PERF]; > > /* > * This is Phase-I where we want to write to CPC registers > @@ -1506,7 +1508,7 @@ int cppc_set_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls) > * Since read_lock can be acquired by multiple CPUs simultaneously we > * achieve that goal here > */ > - if (CPC_IN_PCC(desired_reg)) { > + if (CPC_IN_PCC(desired_reg) || CPC_IN_PCC(min_perf_reg) || CPC_IN_PCC(max_perf_reg)) { > if (pcc_ss_id < 0) { > pr_debug("Invalid pcc_ss_id\n"); > return -ENODEV; > @@ -1529,13 +1531,19 @@ int cppc_set_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls) > cpc_desc->write_cmd_status = 0; > } > > - /* > - * Skip writing MIN/MAX until Linux knows how to come up with > - * useful values. > - */ > cpc_write(cpu, desired_reg, perf_ctrls->desired_perf); > > - if (CPC_IN_PCC(desired_reg)) > + /** > + * Only write if min_perf and max_perf not zero. Some drivers pass zero > + * value to min and max perf, but they don't mean to set the zero value, > + * they just don't want to write to those registers. > + */ > + if (perf_ctrls->min_perf) > + cpc_write(cpu, min_perf_reg, perf_ctrls->min_perf); > + if (perf_ctrls->max_perf) > + cpc_write(cpu, max_perf_reg, perf_ctrls->max_perf); > + > + if (CPC_IN_PCC(desired_reg) || CPC_IN_PCC(min_perf_reg) || CPC_IN_PCC(max_perf_reg)) > up_read(&pcc_ss_data->pcc_lock); /* END Phase-I */ > /* > * This is Phase-II where we transfer the ownership of PCC to Platform > @@ -1583,7 +1591,7 @@ int cppc_set_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls) > * case during a CMD_READ and if there are pending writes it delivers > * the write command before servicing the read command > */ > - if (CPC_IN_PCC(desired_reg)) { > + if (CPC_IN_PCC(desired_reg) || CPC_IN_PCC(min_perf_reg) || CPC_IN_PCC(max_perf_reg)) { > if (down_write_trylock(&pcc_ss_data->pcc_lock)) {/* BEGIN Phase-II */ > /* Update only if there are pending write commands */ > if (pcc_ss_data->pending_pcc_write_cmd) > -- > 2.34.1 >
diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c index 02d83c807271..91f9ef75f7de 100644 --- a/drivers/acpi/cppc_acpi.c +++ b/drivers/acpi/cppc_acpi.c @@ -1487,7 +1487,7 @@ EXPORT_SYMBOL_GPL(cppc_set_enable); int cppc_set_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls) { struct cpc_desc *cpc_desc = per_cpu(cpc_desc_ptr, cpu); - struct cpc_register_resource *desired_reg; + struct cpc_register_resource *desired_reg, *min_perf_reg, *max_perf_reg; int pcc_ss_id = per_cpu(cpu_pcc_subspace_idx, cpu); struct cppc_pcc_data *pcc_ss_data = NULL; int ret = 0; @@ -1498,6 +1498,8 @@ int cppc_set_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls) } desired_reg = &cpc_desc->cpc_regs[DESIRED_PERF]; + min_perf_reg = &cpc_desc->cpc_regs[MIN_PERF]; + max_perf_reg = &cpc_desc->cpc_regs[MAX_PERF]; /* * This is Phase-I where we want to write to CPC registers @@ -1506,7 +1508,7 @@ int cppc_set_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls) * Since read_lock can be acquired by multiple CPUs simultaneously we * achieve that goal here */ - if (CPC_IN_PCC(desired_reg)) { + if (CPC_IN_PCC(desired_reg) || CPC_IN_PCC(min_perf_reg) || CPC_IN_PCC(max_perf_reg)) { if (pcc_ss_id < 0) { pr_debug("Invalid pcc_ss_id\n"); return -ENODEV; @@ -1529,13 +1531,19 @@ int cppc_set_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls) cpc_desc->write_cmd_status = 0; } - /* - * Skip writing MIN/MAX until Linux knows how to come up with - * useful values. - */ cpc_write(cpu, desired_reg, perf_ctrls->desired_perf); - if (CPC_IN_PCC(desired_reg)) + /** + * Only write if min_perf and max_perf not zero. Some drivers pass zero + * value to min and max perf, but they don't mean to set the zero value, + * they just don't want to write to those registers. + */ + if (perf_ctrls->min_perf) + cpc_write(cpu, min_perf_reg, perf_ctrls->min_perf); + if (perf_ctrls->max_perf) + cpc_write(cpu, max_perf_reg, perf_ctrls->max_perf); + + if (CPC_IN_PCC(desired_reg) || CPC_IN_PCC(min_perf_reg) || CPC_IN_PCC(max_perf_reg)) up_read(&pcc_ss_data->pcc_lock); /* END Phase-I */ /* * This is Phase-II where we transfer the ownership of PCC to Platform @@ -1583,7 +1591,7 @@ int cppc_set_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls) * case during a CMD_READ and if there are pending writes it delivers * the write command before servicing the read command */ - if (CPC_IN_PCC(desired_reg)) { + if (CPC_IN_PCC(desired_reg) || CPC_IN_PCC(min_perf_reg) || CPC_IN_PCC(max_perf_reg)) { if (down_write_trylock(&pcc_ss_data->pcc_lock)) {/* BEGIN Phase-II */ /* Update only if there are pending write commands */ if (pcc_ss_data->pending_pcc_write_cmd)