Provide an option "accumulator_status" via sysfs to enable/disable the software accumulation of energy counters. Signed-off-by: Naveen Krishna Chatradhi <nchatrad@xxxxxxx> --- drivers/hwmon/amd_energy.c | 104 ++++++++++++++++++++++++++++++------- 1 file changed, 86 insertions(+), 18 deletions(-) diff --git a/drivers/hwmon/amd_energy.c b/drivers/hwmon/amd_energy.c index 96c61784d05c..c294bea56c02 100644 --- a/drivers/hwmon/amd_energy.c +++ b/drivers/hwmon/amd_energy.c @@ -32,6 +32,8 @@ #define AMD_ENERGY_UNIT_MASK 0x01F00 #define AMD_ENERGY_MASK 0xFFFFFFFF +static struct device_attribute accumulate_attr; + struct sensor_accumulator { u64 energy_ctr; u64 prev_value; @@ -42,10 +44,12 @@ struct amd_energy_data { const struct hwmon_channel_info *info[2]; struct hwmon_chip_info chip; struct task_struct *wrap_accumulate; + struct device *hwmon_dev; /* Lock around the accumulator */ struct mutex lock; /* An accumulator for each core and socket */ struct sensor_accumulator *accums; + bool accumulator_status; /* Energy Status Units */ u64 energy_units; unsigned int timeout; @@ -128,13 +132,15 @@ static void amd_add_delta(struct amd_energy_data *data, int ch, rdmsrl_safe_on_cpu(cpu, reg, &input); input &= AMD_ENERGY_MASK; - accum = &data->accums[ch]; - if (input >= accum->prev_value) - input += accum->energy_ctr - - accum->prev_value; - else - input += UINT_MAX - accum->prev_value + - accum->energy_ctr; + if (data->accumulator_status) { + accum = &data->accums[ch]; + if (input >= accum->prev_value) + input += accum->energy_ctr - + accum->prev_value; + else + input += UINT_MAX - accum->prev_value + + accum->energy_ctr; + } /* Energy consumed = (1/(2^ESU) * RAW * 1000000UL) μJoules */ *val = div64_ul(input * 1000000UL, BIT(data->energy_units)); @@ -264,9 +270,67 @@ static int amd_create_sensor(struct device *dev, return 0; } +static ssize_t amd_energy_accumulate_show(struct device *dev, + struct device_attribute *dev_attr, + char *buf) +{ + struct amd_energy_data *data = dev_get_drvdata(dev); + + return sprintf(buf, "%d\n", data->accumulator_status); +} + +static ssize_t amd_energy_accumulate_store(struct device *dev, + struct device_attribute *dev_attr, + const char *buf, size_t count) +{ + struct amd_energy_data *data = dev_get_drvdata(dev); + bool input; + int ret; + + ret = kstrtobool(buf, &input); + if (ret) + return ret; + + if (data->accumulator_status == input) + return count; + + if (input) { + memset(data->accums, 0, (data->nr_cpus + data->nr_socks) * + sizeof(struct sensor_accumulator)); + + if (!data->wrap_accumulate) { + data->wrap_accumulate = + kthread_run(energy_accumulator, + data, "%s", dev_name(dev)); + if (IS_ERR(data->wrap_accumulate)) + return PTR_ERR(data->wrap_accumulate); + } + } else { + if (data && data->wrap_accumulate) { + ret = kthread_stop(data->wrap_accumulate); + if (ret) + return ret; + data->wrap_accumulate = NULL; + } + } + data->accumulator_status = input; + + return count; +} + +static int create_accumulate_status_file(struct amd_energy_data *data) +{ + accumulate_attr.attr.name = "accumulator_status"; + accumulate_attr.attr.mode = 0664; + accumulate_attr.show = amd_energy_accumulate_show; + accumulate_attr.store = amd_energy_accumulate_store; + + return sysfs_create_file(&data->hwmon_dev->kobj, + &accumulate_attr.attr); +} + static int amd_energy_probe(struct platform_device *pdev) { - struct device *hwmon_dev; struct amd_energy_data *data; struct device *dev = &pdev->dev; int ret; @@ -290,12 +354,12 @@ static int amd_energy_probe(struct platform_device *pdev) mutex_init(&data->lock); get_energy_units(data); - hwmon_dev = devm_hwmon_device_register_with_info(dev, DRVNAME, - data, - &data->chip, - NULL); - if (IS_ERR(hwmon_dev)) - return PTR_ERR(hwmon_dev); + data->hwmon_dev = devm_hwmon_device_register_with_info(dev, DRVNAME, + data, + &data->chip, + NULL); + if (IS_ERR(data->hwmon_dev)) + return PTR_ERR(data->hwmon_dev); /* Once in 3 minutes for a resolution of 1/2*16 */ if (data->energy_units == 0x10) @@ -305,10 +369,12 @@ static int amd_energy_probe(struct platform_device *pdev) if (data->energy_units == 0x6) data->timeout = 3 * 24 * 60 * 60; - data->wrap_accumulate = kthread_run(energy_accumulator, data, - "%s", dev_name(hwmon_dev)); - if (IS_ERR(data->wrap_accumulate)) - return PTR_ERR(data->wrap_accumulate); + /* Disabling the energy accumulation by default */ + data->accumulator_status = 0; + + ret = create_accumulate_status_file(data); + if (ret) + return ret; return 0; } @@ -317,6 +383,8 @@ static int amd_energy_remove(struct platform_device *pdev) { struct amd_energy_data *data = dev_get_drvdata(&pdev->dev); + sysfs_remove_file(&data->hwmon_dev->kobj, &accumulate_attr.attr); + if (data && data->wrap_accumulate) kthread_stop(data->wrap_accumulate); -- 2.26.2