2019-07-23 08:45:57

by Srinivas Pandruvada

[permalink] [raw]
Subject: [PATCH] drivers: thermal: processor_thermal_device: Export sysfs inteface for TCC offset

This change exports an interface to read tcc offset and allow writing if
the platform is not locked.

Refer to Intel SDM for details on the MSR: MSR_TEMPERATURE_TARGET.
Here TCC Activation Offset (R/W) bits allow temperature offset in degrees
in relation to TjMAX.

This change will be useful for improving performance from user space for
some platforms, if the current offset is not optimal.

Signed-off-by: Srinivas Pandruvada <[email protected]>
---
.../processor_thermal_device.c | 91 ++++++++++++++++++-
1 file changed, 87 insertions(+), 4 deletions(-)

diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c
index 213ab3cc6b80..a35635129fed 100644
--- a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c
+++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c
@@ -137,6 +137,72 @@ static const struct attribute_group power_limit_attribute_group = {
.name = "power_limits"
};

+static ssize_t tcc_offset_degree_celsius_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ u64 val;
+ int err;
+
+ err = rdmsrl_safe(MSR_IA32_TEMPERATURE_TARGET, &val);
+ if (err)
+ return err;
+
+ val = (val >> 24) & 0xff;
+ return sprintf(buf, "%d\n", (int)val);
+}
+
+static int tcc_offset_update(int tcc)
+{
+ u64 val;
+ int err;
+
+ if (!tcc)
+ return -EINVAL;
+
+ err = rdmsrl_safe(MSR_IA32_TEMPERATURE_TARGET, &val);
+ if (err)
+ return err;
+
+ val = ~GENMASK_ULL(31, 24);
+ val = (tcc & 0xff) << 24;
+
+ err = wrmsrl_safe(MSR_IA32_TEMPERATURE_TARGET, val);
+ if (err)
+ return err;
+
+ return 0;
+}
+
+static int tcc_offset_save;
+
+static ssize_t tcc_offset_degree_celsius_store(struct device *dev,
+ struct device_attribute *attr, const char *buf,
+ size_t count)
+{
+ u64 val;
+ int tcc, err;
+
+ err = rdmsrl_safe(MSR_PLATFORM_INFO, &val);
+ if (err)
+ return err;
+
+ if (!(val & BIT(30)))
+ return -EACCES;
+
+ if (kstrtoint(buf, 0, &tcc))
+ return -EINVAL;
+
+ err = tcc_offset_update(tcc);
+ if (err)
+ return err;
+
+ tcc_offset_save = tcc;
+
+ return count;
+}
+
+static DEVICE_ATTR_RW(tcc_offset_degree_celsius);
+
static int stored_tjmax; /* since it is fixed, we can have local storage */

static int get_tjmax(void)
@@ -332,6 +398,7 @@ static void proc_thermal_remove(struct proc_thermal_device *proc_priv)
acpi_remove_notify_handler(proc_priv->adev->handle,
ACPI_DEVICE_NOTIFY, proc_thermal_notify);
int340x_thermal_zone_remove(proc_priv->int340x_zone);
+ sysfs_remove_file(&proc_priv->dev->kobj, &dev_attr_tcc_offset_degree_celsius.attr);
sysfs_remove_group(&proc_priv->dev->kobj,
&power_limit_attribute_group);
}
@@ -355,8 +422,15 @@ static int int3401_add(struct platform_device *pdev)

dev_info(&pdev->dev, "Creating sysfs group for PROC_THERMAL_PLATFORM_DEV\n");

- return sysfs_create_group(&pdev->dev.kobj,
- &power_limit_attribute_group);
+ ret = sysfs_create_file(&pdev->dev.kobj, &dev_attr_tcc_offset_degree_celsius.attr);
+ if (ret)
+ return ret;
+
+ ret = sysfs_create_group(&pdev->dev.kobj, &power_limit_attribute_group);
+ if (ret)
+ sysfs_remove_file(&pdev->dev.kobj, &dev_attr_tcc_offset_degree_celsius.attr);
+
+ return ret;
}

static int int3401_remove(struct platform_device *pdev)
@@ -584,8 +658,15 @@ static int proc_thermal_pci_probe(struct pci_dev *pdev,

dev_info(&pdev->dev, "Creating sysfs group for PROC_THERMAL_PCI\n");

- return sysfs_create_group(&pdev->dev.kobj,
- &power_limit_attribute_group);
+ ret = sysfs_create_file(&pdev->dev.kobj, &dev_attr_tcc_offset_degree_celsius.attr);
+ if (ret)
+ return ret;
+
+ ret = sysfs_create_group(&pdev->dev.kobj, &power_limit_attribute_group);
+ if (ret)
+ sysfs_remove_file(&pdev->dev.kobj, &dev_attr_tcc_offset_degree_celsius.attr);
+
+ return ret;
}

static void proc_thermal_pci_remove(struct pci_dev *pdev)
@@ -611,6 +692,8 @@ static int proc_thermal_resume(struct device *dev)
proc_dev = dev_get_drvdata(dev);
proc_thermal_read_ppcc(proc_dev);

+ tcc_offset_update(tcc_offset_save);
+
return 0;
}
#else
--
2.17.2


2019-07-24 20:17:15

by Benjamin Berg

[permalink] [raw]
Subject: Re: [PATCH] drivers: thermal: processor_thermal_device: Export sysfs inteface for TCC offset

Tested-by: Benjamin Berg <[email protected]>

Hi,

this patch allows performance improvements of some machines. It would
be nice if this could still make 5.3.

Benjamin

On Mon, 2019-07-22 at 18:03 -0700, Srinivas Pandruvada wrote:
> This change exports an interface to read tcc offset and allow writing if
> the platform is not locked.
>
> Refer to Intel SDM for details on the MSR: MSR_TEMPERATURE_TARGET.
> Here TCC Activation Offset (R/W) bits allow temperature offset in degrees
> in relation to TjMAX.
>
> This change will be useful for improving performance from user space for
> some platforms, if the current offset is not optimal.
>
> Signed-off-by: Srinivas Pandruvada <[email protected]>
> ---
> .../processor_thermal_device.c | 91
> ++++++++++++++++++-
> 1 file changed, 87 insertions(+), 4 deletions(-)
>
> diff --git
> a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c
> b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c
> index 213ab3cc6b80..a35635129fed 100644
> ---
> a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c
> +++
> b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c
> @@ -137,6 +137,72 @@ static const struct attribute_group
> power_limit_attribute_group = {
> .name = "power_limits"
> };
>
> +static ssize_t tcc_offset_degree_celsius_show(struct device *dev,
> + struct device_attribute *attr, char
> *buf)
> +{
> + u64 val;
> + int err;
> +
> + err = rdmsrl_safe(MSR_IA32_TEMPERATURE_TARGET, &val);
> + if (err)
> + return err;
> +
> + val = (val >> 24) & 0xff;
> + return sprintf(buf, "%d\n", (int)val);
> +}
> +
> +static int tcc_offset_update(int tcc)
> +{
> + u64 val;
> + int err;
> +
> + if (!tcc)
> + return -EINVAL;
> +
> + err = rdmsrl_safe(MSR_IA32_TEMPERATURE_TARGET, &val);
> + if (err)
> + return err;
> +
> + val = ~GENMASK_ULL(31, 24);
> + val = (tcc & 0xff) << 24;
> +
> + err = wrmsrl_safe(MSR_IA32_TEMPERATURE_TARGET, val);
> + if (err)
> + return err;
> +
> + return 0;
> +}
> +
> +static int tcc_offset_save;
> +
> +static ssize_t tcc_offset_degree_celsius_store(struct device *dev,
> + struct device_attribute *attr, const
> char *buf,
> + size_t count)
> +{
> + u64 val;
> + int tcc, err;
> +
> + err = rdmsrl_safe(MSR_PLATFORM_INFO, &val);
> + if (err)
> + return err;
> +
> + if (!(val & BIT(30)))
> + return -EACCES;
> +
> + if (kstrtoint(buf, 0, &tcc))
> + return -EINVAL;
> +
> + err = tcc_offset_update(tcc);
> + if (err)
> + return err;
> +
> + tcc_offset_save = tcc;
> +
> + return count;
> +}
> +
> +static DEVICE_ATTR_RW(tcc_offset_degree_celsius);
> +
> static int stored_tjmax; /* since it is fixed, we can have local
> storage */
>
> static int get_tjmax(void)
> @@ -332,6 +398,7 @@ static void proc_thermal_remove(struct
> proc_thermal_device *proc_priv)
> acpi_remove_notify_handler(proc_priv->adev->handle,
> ACPI_DEVICE_NOTIFY,
> proc_thermal_notify);
> int340x_thermal_zone_remove(proc_priv->int340x_zone);
> + sysfs_remove_file(&proc_priv->dev->kobj,
> &dev_attr_tcc_offset_degree_celsius.attr);
> sysfs_remove_group(&proc_priv->dev->kobj,
> &power_limit_attribute_group);
> }
> @@ -355,8 +422,15 @@ static int int3401_add(struct platform_device
> *pdev)
>
> dev_info(&pdev->dev, "Creating sysfs group for
> PROC_THERMAL_PLATFORM_DEV\n");
>
> - return sysfs_create_group(&pdev->dev.kobj,
> - &power_limit_attribute_group);
> + ret = sysfs_create_file(&pdev->dev.kobj,
> &dev_attr_tcc_offset_degree_celsius.attr);
> + if (ret)
> + return ret;
> +
> + ret = sysfs_create_group(&pdev->dev.kobj,
> &power_limit_attribute_group);
> + if (ret)
> + sysfs_remove_file(&pdev->dev.kobj,
> &dev_attr_tcc_offset_degree_celsius.attr);
> +
> + return ret;
> }
>
> static int int3401_remove(struct platform_device *pdev)
> @@ -584,8 +658,15 @@ static int proc_thermal_pci_probe(struct
> pci_dev *pdev,
>
> dev_info(&pdev->dev, "Creating sysfs group for
> PROC_THERMAL_PCI\n");
>
> - return sysfs_create_group(&pdev->dev.kobj,
> - &power_limit_attribute_group);
> + ret = sysfs_create_file(&pdev->dev.kobj,
> &dev_attr_tcc_offset_degree_celsius.attr);
> + if (ret)
> + return ret;
> +
> + ret = sysfs_create_group(&pdev->dev.kobj,
> &power_limit_attribute_group);
> + if (ret)
> + sysfs_remove_file(&pdev->dev.kobj,
> &dev_attr_tcc_offset_degree_celsius.attr);
> +
> + return ret;
> }
>
> static void proc_thermal_pci_remove(struct pci_dev *pdev)
> @@ -611,6 +692,8 @@ static int proc_thermal_resume(struct device
> *dev)
> proc_dev = dev_get_drvdata(dev);
> proc_thermal_read_ppcc(proc_dev);
>
> + tcc_offset_update(tcc_offset_save);
> +
> return 0;
> }
> #else


Attachments:
signature.asc (849.00 B)
This is a digitally signed message part