Add attributes only for registers that are supported by the platform. This prevents unsupported, optional registers from having sysfs entries created. Signed-off-by: Janakarajan Natarajan <Janakarajan.Natarajan@xxxxxxx> --- drivers/acpi/cppc_acpi.c | 82 +++++++++++++++++++++++++++++++++------- 1 file changed, 68 insertions(+), 14 deletions(-) diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c index c43de65531ae..53a9dc9960b6 100644 --- a/drivers/acpi/cppc_acpi.c +++ b/drivers/acpi/cppc_acpi.c @@ -183,22 +183,8 @@ static ssize_t show_feedback_ctrs(struct kobject *kobj, } define_one_cppc_ro(feedback_ctrs); -static struct attribute *cppc_attrs[] = { - &feedback_ctrs.attr, - &reference_perf.attr, - &wraparound_time.attr, - &highest_perf.attr, - &lowest_perf.attr, - &lowest_nonlinear_perf.attr, - &nominal_perf.attr, - &nominal_freq.attr, - &lowest_freq.attr, - NULL -}; - static struct kobj_type cppc_ktype = { .sysfs_ops = &kobj_sysfs_ops, - .default_attrs = cppc_attrs, }; static int check_pcc_chan(int pcc_ss_id, bool chk_err_bit) @@ -733,6 +719,69 @@ static bool is_buf_only(int reg_idx) CPC_SUP_BUFFER_ONLY(&cpc->cpc_regs[idx]) : \ CPC_SUPPORTED(&cpc->cpc_regs[idx])) +static int is_mandatory_reg(int reg_idx) +{ + switch (reg_idx) { + case HIGHEST_PERF: + case NOMINAL_PERF: + case LOW_NON_LINEAR_PERF: + case LOWEST_PERF: + case REFERENCE_CTR: + case DELIVERED_CTR: + return 1; + } + + return 0; +} + +#define MANDATORY_REG_CNT 6 + +static int set_cppc_attrs(struct cpc_desc *cpc, int entries) +{ + int i, attr_i = 0, opt_reg_cnt; + static struct attribute **cppc_attrs; + + cppc_attrs = kcalloc(entries, sizeof(*cppc_attrs), GFP_KERNEL); + if (!cppc_attrs) + return -ENOMEM; + + /* Set optional regs */ + opt_reg_cnt = entries - MANDATORY_REG_CNT; + for (i = 0; i < MAX_CPC_REG_ENT && attr_i < opt_reg_cnt; i++) { + if (is_mandatory_reg(i) || !REG_SUPPORTED(cpc, i)) + continue; + + switch (i) { + case NOMINAL_FREQ: + cppc_attrs[attr_i++] = &nominal_freq.attr; + break; + case LOWEST_FREQ: + cppc_attrs[attr_i++] = &lowest_freq.attr; + break; + case REFERENCE_PERF: + cppc_attrs[attr_i++] = &reference_perf.attr; + break; + case CTR_WRAP_TIME: + cppc_attrs[attr_i++] = &wraparound_time.attr; + break; + } + } + + /* Set mandatory regs */ + cppc_attrs[attr_i++] = &highest_perf.attr; + cppc_attrs[attr_i++] = &nominal_perf.attr; + cppc_attrs[attr_i++] = &lowest_nonlinear_perf.attr; + cppc_attrs[attr_i++] = &lowest_perf.attr; + + /* Set feedback_ctr sysfs entry */ + cppc_attrs[attr_i] = &feedback_ctrs.attr; + + /* Set kobj_type member */ + cppc_ktype.default_attrs = cppc_attrs; + + return 0; +} + /** * acpi_cppc_processor_probe - Search for per CPU _CPC objects. * @pr: Ptr to acpi_processor containing this CPU's logical ID. @@ -887,6 +936,10 @@ int acpi_cppc_processor_probe(struct acpi_processor *pr) /* Plug PSD data into this CPU's CPC descriptor. */ per_cpu(cpc_desc_ptr, pr->id) = cpc_ptr; + ret = set_cppc_attrs(cpc_ptr, num_ent - 2); + if (ret) + goto out_free; + ret = kobject_init_and_add(&cpc_ptr->kobj, &cppc_ktype, &cpu_dev->kobj, "acpi_cppc"); if (ret) { @@ -948,6 +1001,7 @@ void acpi_cppc_processor_exit(struct acpi_processor *pr) iounmap(addr); } + kfree(cppc_ktype.default_attrs); kobject_put(&cpc_ptr->kobj); kfree(cpc_ptr); } -- 2.17.1