From: Yazen Ghannam <Yazen.Ghannam@xxxxxxx> To enable CPPC on a processor, the OS should write a value "1" to the CPPC Enable register. Add support for this register. Signed-off-by: Yazen Ghannam <Yazen.Ghannam@xxxxxxx> [ carved out into a patch, cleaned up, productized ] Signed-off-by: Janakarajan Natarajan <Janakarajan.Natarajan@xxxxxxx> --- drivers/acpi/cppc_acpi.c | 96 ++++++++++++++++++++++++++++++++++++++++ include/acpi/cppc_acpi.h | 1 + 2 files changed, 97 insertions(+) diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c index f8827ba7015d..8c6804976bb8 100644 --- a/drivers/acpi/cppc_acpi.c +++ b/drivers/acpi/cppc_acpi.c @@ -224,6 +224,43 @@ static ssize_t show_feedback_ctrs(struct kobject *kobj, } define_one_cppc_ro(feedback_ctrs); +/* Used to move ENABLE register value between userspace and platform */ +static bool cppc_cpu_enable; + +static ssize_t show_enable(struct kobject *kobj, + struct attribute *attr, + char *buf) +{ + struct cpc_desc *cpc_ptr = to_cpc_desc(kobj); + int ret; + + ret = cppc_get_enable(cpc_ptr->cpu_id); + if (ret) + return ret; + + return scnprintf(buf, PAGE_SIZE, "%d\n", cppc_cpu_enable); +} + +static ssize_t store_enable(struct kobject *kobj, + struct attribute *attr, + const char *c, ssize_t count) +{ + struct cpc_desc *cpc_ptr = to_cpc_desc(kobj); + int ret; + + ret = kstrtobool(c, &cppc_cpu_enable); + if (ret) + return ret; + + ret = cppc_set_reg(cpc_ptr->cpu_id, NULL, ENABLE); + if (ret) + return ret; + + return count; +} + +define_one_cppc_rw(enable); + static struct kobj_type cppc_ktype = { .sysfs_ops = &kobj_sysfs_ops, }; @@ -794,6 +831,9 @@ int set_cppc_attrs(struct cpc_desc *cpc, int entries) case DESIRED_PERF: cppc_attrs[attr_i++] = &desired_perf.attr; break; + case ENABLE: + cppc_attrs[attr_i++] = &enable.attr; + break; } } @@ -1383,6 +1423,9 @@ int cppc_set_reg(int cpu, struct cppc_perf_ctrls *perf_ctrls, } switch (reg_idx) { + case ENABLE: + value = cppc_cpu_enable; + break; case DESIRED_PERF: value = perf_ctrls->desired_perf; break; @@ -1572,6 +1615,59 @@ int cppc_get_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls) } EXPORT_SYMBOL_GPL(cppc_get_perf); +/** + * cppc_get_enable - Read a CPUs enable register. + * @cpu: CPU from which to read control values. + * + * Return: 0 for success. + */ +int cppc_get_enable(int cpu) +{ + struct cpc_desc *cpc_desc = per_cpu(cpc_desc_ptr, cpu); + int pcc_ss_id = per_cpu(cpu_pcc_subspace_idx, cpu); + struct cpc_register_resource *enable_reg; + struct cppc_pcc_data *pcc_ss_data = NULL; + int ret = 0, regs_in_pcc = 0; + u64 enable; + + if (!cpc_desc) { + pr_debug("No CPC descriptor for CPU: %d\n", cpu); + return -ENODEV; + } + + enable_reg = &cpc_desc->cpc_regs[ENABLE]; + + if (!CPC_SUPPORTED(enable_reg)) { + pr_warn("CPC ENABLE register not supported.\n"); + return -ENOTSUPP; + } + + if (CPC_IN_PCC(enable_reg)) { + pcc_ss_data = pcc_data[pcc_ss_id]; + down_write(&pcc_ss_data->pcc_lock); + regs_in_pcc = 1; + /* Ring doorbell once to update PCC subspace */ + if (send_pcc_cmd(pcc_ss_id, CMD_READ) < 0) { + ret = -EIO; + goto out_err; + } + } + + if (cpc_read(cpu, enable_reg, &enable)) { + ret = -EFAULT; + goto out_err; + } + + cppc_cpu_enable = enable; + +out_err: + if (regs_in_pcc) + up_write(&pcc_ss_data->pcc_lock); + + return ret; +} +EXPORT_SYMBOL_GPL(cppc_get_enable); + /** * cppc_get_transition_latency - returns frequency transition latency in ns * diff --git a/include/acpi/cppc_acpi.h b/include/acpi/cppc_acpi.h index 6f651235933c..fcdedff8e6bd 100644 --- a/include/acpi/cppc_acpi.h +++ b/include/acpi/cppc_acpi.h @@ -139,6 +139,7 @@ struct cppc_cpudata { cpumask_var_t shared_cpu_map; }; +extern int cppc_get_enable(int cpu); extern int cppc_get_desired_perf(int cpunum, u64 *desired_perf); extern int cppc_get_perf_ctrs(int cpu, struct cppc_perf_fb_ctrs *perf_fb_ctrs); extern int cppc_set_reg(int cpu, struct cppc_perf_ctrls *perf_ctrls, enum cppc_regs reg_idx); -- 2.17.1