diff mbox series

[V2] thermal: intel: introduce tcc cooling driver

Message ID 20210411142613.9584-1-rui.zhang@intel.com (mailing list archive)
State Superseded, archived
Headers show
Series [V2] thermal: intel: introduce tcc cooling driver | expand

Commit Message

Zhang, Rui April 11, 2021, 2:26 p.m. UTC
On Intel processors, the core frequency can be reduced below OS request,
when the current temperature reaches the TCC (Thermal Control Circuit)
activation temperature.

The default TCC activation temperature is specified by
MSR_IA32_TEMPERATURE_TARGET. However, it can be adjusted by specifying an
offset in degrees C, using the TCC Offset bits in the same MSR register.

This patch introduces a cooling devices driver that utilizes the TCC
Offset feature. The bigger the current cooling state is, the lower the
effective TCC activation temperature is, so that the processors can be
throttled earlier before system critical overheats.

Note that, on different platforms, the behavior might be different on
how fast the setting takes effect, and how much the CPU frequency is
reduced.

This patch has been tested on a KBL mobile platform.

Signed-off-by: Zhang Rui <rui.zhang@intel.com>
---
V2:
  Add a note in both Kconfig description and changelog, to clarify that
  the behavior might not be consistent cross platforms.
---
 drivers/thermal/intel/Kconfig             |  11 ++
 drivers/thermal/intel/Makefile            |   1 +
 drivers/thermal/intel/intel_tcc_cooling.c | 128 ++++++++++++++++++++++
 3 files changed, 140 insertions(+)
 create mode 100644 drivers/thermal/intel/intel_tcc_cooling.c

Comments

Doug Smythies April 11, 2021, 5:12 p.m. UTC | #1
Hi Rui,
Thank you for your V2.

On Sun, Apr 11, 2021 at 7:15 AM Zhang Rui <rui.zhang@intel.com> wrote:
>
> On Intel processors, the core frequency can be reduced below OS request,
> when the current temperature reaches the TCC (Thermal Control Circuit)
> activation temperature.
>
> The default TCC activation temperature is specified by
> MSR_IA32_TEMPERATURE_TARGET. However, it can be adjusted by specifying an
> offset in degrees C, using the TCC Offset bits in the same MSR register.
>
> This patch introduces a cooling devices driver that utilizes the TCC
> Offset feature. The bigger the current cooling state is, the lower the
> effective TCC activation temperature is, so that the processors can be
> throttled earlier before system critical overheats.
>
> Note that, on different platforms, the behavior might be different on
> how fast the setting takes effect, and how much the CPU frequency is
> reduced.
>
> This patch has been tested on a KBL mobile platform.

V1 was also tested on what I think was a Coffee Lake (i5-9600K)
This V2 was tested on a Comet Lake (i5-10600K), with an additional
match patch added. See below.

>
> Signed-off-by: Zhang Rui <rui.zhang@intel.com>

Tested by: Doug Smythies <dsmythies@telus.net>

> ---
> V2:
>   Add a note in both Kconfig description and changelog, to clarify that
>   the behavior might not be consistent cross platforms.
> ---
>  drivers/thermal/intel/Kconfig             |  11 ++
>  drivers/thermal/intel/Makefile            |   1 +
>  drivers/thermal/intel/intel_tcc_cooling.c | 128 ++++++++++++++++++++++
>  3 files changed, 140 insertions(+)
>  create mode 100644 drivers/thermal/intel/intel_tcc_cooling.c
>
> diff --git a/drivers/thermal/intel/Kconfig b/drivers/thermal/intel/Kconfig
> index ce4f59213c7a..e4299ca3423c 100644
> --- a/drivers/thermal/intel/Kconfig
> +++ b/drivers/thermal/intel/Kconfig
> @@ -79,3 +79,14 @@ config INTEL_PCH_THERMAL
>           Enable this to support thermal reporting on certain intel PCHs.
>           Thermal reporting device will provide temperature reading,
>           programmable trip points and other information.
> +
> +config INTEL_TCC_COOLING
> +       tristate "Intel TCC offset cooling Driver"
> +       depends on X86
> +       help
> +         Enable this to support system cooling by adjusting the effective TCC
> +         activation temperature via the TCC Offset register, which is widely
> +         supported on modern Intel platforms.
> +         Note that, on different platforms, the behavior might be different
> +         on how fast the setting takes effect, and how much the CPU frequency
> +         is reduced.
> diff --git a/drivers/thermal/intel/Makefile b/drivers/thermal/intel/Makefile
> index ff2ad30ef397..5ff2afa388f7 100644
> --- a/drivers/thermal/intel/Makefile
> +++ b/drivers/thermal/intel/Makefile
> @@ -10,4 +10,5 @@ obj-$(CONFIG_INTEL_QUARK_DTS_THERMAL) += intel_quark_dts_thermal.o
>  obj-$(CONFIG_INT340X_THERMAL)  += int340x_thermal/
>  obj-$(CONFIG_INTEL_BXT_PMIC_THERMAL) += intel_bxt_pmic_thermal.o
>  obj-$(CONFIG_INTEL_PCH_THERMAL)        += intel_pch_thermal.o
> +obj-$(CONFIG_INTEL_TCC_COOLING)        += intel_tcc_cooling.o
>  obj-$(CONFIG_X86_THERMAL_VECTOR) += therm_throt.o
> diff --git a/drivers/thermal/intel/intel_tcc_cooling.c b/drivers/thermal/intel/intel_tcc_cooling.c
> new file mode 100644
> index 000000000000..aa6bbb9ba898
> --- /dev/null
> +++ b/drivers/thermal/intel/intel_tcc_cooling.c
> @@ -0,0 +1,128 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * cooling device driver that activates the processor throttling by
> + * programming the TCC Offset register.
> + * Copyright (c) 2021, Intel Corporation.
> + */
> +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> +
> +#include <linux/device.h>
> +#include <linux/module.h>
> +#include <linux/thermal.h>
> +#include <asm/cpu_device_id.h>
> +
> +#define TCC_SHIFT 24
> +#define TCC_MASK       (0x3fULL<<24)
> +#define TCC_PROGRAMMABLE       BIT(30)
> +
> +static struct thermal_cooling_device *tcc_cdev;
> +
> +static int tcc_get_max_state(struct thermal_cooling_device *cdev, unsigned long
> +                            *state)
> +{
> +       *state = TCC_MASK >> TCC_SHIFT;
> +       return 0;
> +}
> +
> +static int tcc_offset_update(int tcc)
> +{
> +       u64 val;
> +       int err;
> +
> +       err = rdmsrl_safe(MSR_IA32_TEMPERATURE_TARGET, &val);
> +       if (err)
> +               return err;
> +
> +       val &= ~TCC_MASK;
> +       val |= tcc << TCC_SHIFT;
> +
> +       err = wrmsrl_safe(MSR_IA32_TEMPERATURE_TARGET, val);
> +       if (err)
> +               return err;
> +
> +       return 0;
> +}
> +
> +static int tcc_get_cur_state(struct thermal_cooling_device *cdev, unsigned long
> +                            *state)
> +{
> +       u64 val;
> +       int err;
> +
> +       err = rdmsrl_safe(MSR_IA32_TEMPERATURE_TARGET, &val);
> +       if (err)
> +               return err;
> +
> +       *state = (val & TCC_MASK) >> TCC_SHIFT;
> +       return 0;
> +}
> +
> +static int tcc_set_cur_state(struct thermal_cooling_device *cdev, unsigned long
> +                            state)
> +{
> +       return tcc_offset_update(state);
> +}
> +
> +static const struct thermal_cooling_device_ops tcc_cooling_ops = {
> +       .get_max_state = tcc_get_max_state,
> +       .get_cur_state = tcc_get_cur_state,
> +       .set_cur_state = tcc_set_cur_state,
> +};
> +
> +static const struct x86_cpu_id tcc_ids[] __initconst = {
> +       X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE, NULL),
> +       X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE_L, NULL),
> +       X86_MATCH_INTEL_FAM6_MODEL(KABYLAKE, NULL),
> +       X86_MATCH_INTEL_FAM6_MODEL(KABYLAKE_L, NULL),
> +       X86_MATCH_INTEL_FAM6_MODEL(ICELAKE, NULL),
> +       X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_L, NULL),
> +       X86_MATCH_INTEL_FAM6_MODEL(TIGERLAKE, NULL),
> +       X86_MATCH_INTEL_FAM6_MODEL(TIGERLAKE_L, NULL),
> +       {}

Suggest the starting supported list be expanded. I only did what I had to:

diff --git a/drivers/thermal/intel/intel_tcc_cooling.c
b/drivers/thermal/intel/intel_tcc_cooling.c
index aa6bbb9ba898..8ec10d55d421 100644
--- a/drivers/thermal/intel/intel_tcc_cooling.c
+++ b/drivers/thermal/intel/intel_tcc_cooling.c
@@ -78,6 +78,7 @@ static const struct x86_cpu_id tcc_ids[] __initconst = {
        X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_L, NULL),
        X86_MATCH_INTEL_FAM6_MODEL(TIGERLAKE, NULL),
        X86_MATCH_INTEL_FAM6_MODEL(TIGERLAKE_L, NULL),
+       X86_MATCH_INTEL_FAM6_MODEL(COMETLAKE, NULL),
        {}
 };


> +};
> +
> +MODULE_DEVICE_TABLE(x86cpu, tcc_ids);
> +
> +static int __init tcc_cooling_init(void)
> +{
> +       int ret;
> +       u64 val;
> +       const struct x86_cpu_id *id;
> +
> +       int err;
> +
> +       id = x86_match_cpu(tcc_ids);
> +       if (!id)
> +               return -ENODEV;
> +
> +       err = rdmsrl_safe(MSR_PLATFORM_INFO, &val);
> +       if (err)
> +               return err;
> +
> +       if (!(val & TCC_PROGRAMMABLE))
> +               return -ENODEV;
> +
> +       pr_info("Programmable TCC Offset detected\n");
> +
> +       tcc_cdev =
> +           thermal_cooling_device_register("TCC Offset", NULL,
> +                                           &tcc_cooling_ops);
> +       if (IS_ERR(tcc_cdev)) {
> +               ret = PTR_ERR(tcc_cdev);
> +               return ret;
> +       }
> +       return 0;
> +}
> +
> +module_init(tcc_cooling_init)
> +
> +static void __exit tcc_cooling_exit(void)
> +{
> +       thermal_cooling_device_unregister(tcc_cdev);
> +}
> +
> +module_exit(tcc_cooling_exit)
> +
> +MODULE_DESCRIPTION("TCC offset cooling device Driver");
> +MODULE_AUTHOR("Zhang Rui <rui.zhang@intel.com>");
> +MODULE_LICENSE("GPL v2");
> --
> 2.17.1
>
Zhang, Rui April 13, 2021, 1:52 a.m. UTC | #2
On Sun, 2021-04-11 at 10:12 -0700, Doug Smythies wrote:
> Hi Rui,
> Thank you for your V2.
> 
> On Sun, Apr 11, 2021 at 7:15 AM Zhang Rui <rui.zhang@intel.com>
> wrote:
> > 
> > On Intel processors, the core frequency can be reduced below OS
> > request,
> > when the current temperature reaches the TCC (Thermal Control
> > Circuit)
> > activation temperature.
> > 
> > The default TCC activation temperature is specified by
> > MSR_IA32_TEMPERATURE_TARGET. However, it can be adjusted by
> > specifying an
> > offset in degrees C, using the TCC Offset bits in the same MSR
> > register.
> > 
> > This patch introduces a cooling devices driver that utilizes the
> > TCC
> > Offset feature. The bigger the current cooling state is, the lower
> > the
> > effective TCC activation temperature is, so that the processors can
> > be
> > throttled earlier before system critical overheats.
> > 
> > Note that, on different platforms, the behavior might be different
> > on
> > how fast the setting takes effect, and how much the CPU frequency
> > is
> > reduced.
> > 
> > This patch has been tested on a KBL mobile platform.
> 
> V1 was also tested on what I think was a Coffee Lake (i5-9600K)

I didn't include this in patch V3 because Coffee Lake is not supported
by this version of patch. Please feel free to send a patch on top if
you have confirmed that it works.

> This V2 was tested on a Comet Lake (i5-10600K), with an additional
> match patch added. See below.
> 
> > 
> > Signed-off-by: Zhang Rui <rui.zhang@intel.com>
> 
> Tested by: Doug Smythies <dsmythies@telus.net>
> 
And thanks for your test.

-rui
> > ---
> > V2:
> >   Add a note in both Kconfig description and changelog, to clarify
> > that
> >   the behavior might not be consistent cross platforms.
> > ---
> >  drivers/thermal/intel/Kconfig             |  11 ++
> >  drivers/thermal/intel/Makefile            |   1 +
> >  drivers/thermal/intel/intel_tcc_cooling.c | 128
> > ++++++++++++++++++++++
> >  3 files changed, 140 insertions(+)
> >  create mode 100644 drivers/thermal/intel/intel_tcc_cooling.c
> > 
> > diff --git a/drivers/thermal/intel/Kconfig
> > b/drivers/thermal/intel/Kconfig
> > index ce4f59213c7a..e4299ca3423c 100644
> > --- a/drivers/thermal/intel/Kconfig
> > +++ b/drivers/thermal/intel/Kconfig
> > @@ -79,3 +79,14 @@ config INTEL_PCH_THERMAL
> >           Enable this to support thermal reporting on certain intel
> > PCHs.
> >           Thermal reporting device will provide temperature
> > reading,
> >           programmable trip points and other information.
> > +
> > +config INTEL_TCC_COOLING
> > +       tristate "Intel TCC offset cooling Driver"
> > +       depends on X86
> > +       help
> > +         Enable this to support system cooling by adjusting the
> > effective TCC
> > +         activation temperature via the TCC Offset register, which
> > is widely
> > +         supported on modern Intel platforms.
> > +         Note that, on different platforms, the behavior might be
> > different
> > +         on how fast the setting takes effect, and how much the
> > CPU frequency
> > +         is reduced.
> > diff --git a/drivers/thermal/intel/Makefile
> > b/drivers/thermal/intel/Makefile
> > index ff2ad30ef397..5ff2afa388f7 100644
> > --- a/drivers/thermal/intel/Makefile
> > +++ b/drivers/thermal/intel/Makefile
> > @@ -10,4 +10,5 @@ obj-$(CONFIG_INTEL_QUARK_DTS_THERMAL) +=
> > intel_quark_dts_thermal.o
> >  obj-$(CONFIG_INT340X_THERMAL)  += int340x_thermal/
> >  obj-$(CONFIG_INTEL_BXT_PMIC_THERMAL) += intel_bxt_pmic_thermal.o
> >  obj-$(CONFIG_INTEL_PCH_THERMAL)        += intel_pch_thermal.o
> > +obj-$(CONFIG_INTEL_TCC_COOLING)        += intel_tcc_cooling.o
> >  obj-$(CONFIG_X86_THERMAL_VECTOR) += therm_throt.o
> > diff --git a/drivers/thermal/intel/intel_tcc_cooling.c
> > b/drivers/thermal/intel/intel_tcc_cooling.c
> > new file mode 100644
> > index 000000000000..aa6bbb9ba898
> > --- /dev/null
> > +++ b/drivers/thermal/intel/intel_tcc_cooling.c
> > @@ -0,0 +1,128 @@
> > +// SPDX-License-Identifier: GPL-2.0-only
> > +/*
> > + * cooling device driver that activates the processor throttling
> > by
> > + * programming the TCC Offset register.
> > + * Copyright (c) 2021, Intel Corporation.
> > + */
> > +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> > +
> > +#include <linux/device.h>
> > +#include <linux/module.h>
> > +#include <linux/thermal.h>
> > +#include <asm/cpu_device_id.h>
> > +
> > +#define TCC_SHIFT 24
> > +#define TCC_MASK       (0x3fULL<<24)
> > +#define TCC_PROGRAMMABLE       BIT(30)
> > +
> > +static struct thermal_cooling_device *tcc_cdev;
> > +
> > +static int tcc_get_max_state(struct thermal_cooling_device *cdev,
> > unsigned long
> > +                            *state)
> > +{
> > +       *state = TCC_MASK >> TCC_SHIFT;
> > +       return 0;
> > +}
> > +
> > +static int tcc_offset_update(int tcc)
> > +{
> > +       u64 val;
> > +       int err;
> > +
> > +       err = rdmsrl_safe(MSR_IA32_TEMPERATURE_TARGET, &val);
> > +       if (err)
> > +               return err;
> > +
> > +       val &= ~TCC_MASK;
> > +       val |= tcc << TCC_SHIFT;
> > +
> > +       err = wrmsrl_safe(MSR_IA32_TEMPERATURE_TARGET, val);
> > +       if (err)
> > +               return err;
> > +
> > +       return 0;
> > +}
> > +
> > +static int tcc_get_cur_state(struct thermal_cooling_device *cdev,
> > unsigned long
> > +                            *state)
> > +{
> > +       u64 val;
> > +       int err;
> > +
> > +       err = rdmsrl_safe(MSR_IA32_TEMPERATURE_TARGET, &val);
> > +       if (err)
> > +               return err;
> > +
> > +       *state = (val & TCC_MASK) >> TCC_SHIFT;
> > +       return 0;
> > +}
> > +
> > +static int tcc_set_cur_state(struct thermal_cooling_device *cdev,
> > unsigned long
> > +                            state)
> > +{
> > +       return tcc_offset_update(state);
> > +}
> > +
> > +static const struct thermal_cooling_device_ops tcc_cooling_ops = {
> > +       .get_max_state = tcc_get_max_state,
> > +       .get_cur_state = tcc_get_cur_state,
> > +       .set_cur_state = tcc_set_cur_state,
> > +};
> > +
> > +static const struct x86_cpu_id tcc_ids[] __initconst = {
> > +       X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE, NULL),
> > +       X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE_L, NULL),
> > +       X86_MATCH_INTEL_FAM6_MODEL(KABYLAKE, NULL),
> > +       X86_MATCH_INTEL_FAM6_MODEL(KABYLAKE_L, NULL),
> > +       X86_MATCH_INTEL_FAM6_MODEL(ICELAKE, NULL),
> > +       X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_L, NULL),
> > +       X86_MATCH_INTEL_FAM6_MODEL(TIGERLAKE, NULL),
> > +       X86_MATCH_INTEL_FAM6_MODEL(TIGERLAKE_L, NULL),
> > +       {}
> 
> Suggest the starting supported list be expanded. I only did what I
> had to:
> 
> diff --git a/drivers/thermal/intel/intel_tcc_cooling.c
> b/drivers/thermal/intel/intel_tcc_cooling.c
> index aa6bbb9ba898..8ec10d55d421 100644
> --- a/drivers/thermal/intel/intel_tcc_cooling.c
> +++ b/drivers/thermal/intel/intel_tcc_cooling.c
> @@ -78,6 +78,7 @@ static const struct x86_cpu_id tcc_ids[]
> __initconst = {
>         X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_L, NULL),
>         X86_MATCH_INTEL_FAM6_MODEL(TIGERLAKE, NULL),
>         X86_MATCH_INTEL_FAM6_MODEL(TIGERLAKE_L, NULL),
> +       X86_MATCH_INTEL_FAM6_MODEL(COMETLAKE, NULL),
>         {}
>  };
> 
> 
> > +};
> > +
> > +MODULE_DEVICE_TABLE(x86cpu, tcc_ids);
> > +
> > +static int __init tcc_cooling_init(void)
> > +{
> > +       int ret;
> > +       u64 val;
> > +       const struct x86_cpu_id *id;
> > +
> > +       int err;
> > +
> > +       id = x86_match_cpu(tcc_ids);
> > +       if (!id)
> > +               return -ENODEV;
> > +
> > +       err = rdmsrl_safe(MSR_PLATFORM_INFO, &val);
> > +       if (err)
> > +               return err;
> > +
> > +       if (!(val & TCC_PROGRAMMABLE))
> > +               return -ENODEV;
> > +
> > +       pr_info("Programmable TCC Offset detected\n");
> > +
> > +       tcc_cdev =
> > +           thermal_cooling_device_register("TCC Offset", NULL,
> > +                                           &tcc_cooling_ops);
> > +       if (IS_ERR(tcc_cdev)) {
> > +               ret = PTR_ERR(tcc_cdev);
> > +               return ret;
> > +       }
> > +       return 0;
> > +}
> > +
> > +module_init(tcc_cooling_init)
> > +
> > +static void __exit tcc_cooling_exit(void)
> > +{
> > +       thermal_cooling_device_unregister(tcc_cdev);
> > +}
> > +
> > +module_exit(tcc_cooling_exit)
> > +
> > +MODULE_DESCRIPTION("TCC offset cooling device Driver");
> > +MODULE_AUTHOR("Zhang Rui <rui.zhang@intel.com>");
> > +MODULE_LICENSE("GPL v2");
> > --
> > 2.17.1
> >
diff mbox series

Patch

diff --git a/drivers/thermal/intel/Kconfig b/drivers/thermal/intel/Kconfig
index ce4f59213c7a..e4299ca3423c 100644
--- a/drivers/thermal/intel/Kconfig
+++ b/drivers/thermal/intel/Kconfig
@@ -79,3 +79,14 @@  config INTEL_PCH_THERMAL
 	  Enable this to support thermal reporting on certain intel PCHs.
 	  Thermal reporting device will provide temperature reading,
 	  programmable trip points and other information.
+
+config INTEL_TCC_COOLING
+	tristate "Intel TCC offset cooling Driver"
+	depends on X86
+	help
+	  Enable this to support system cooling by adjusting the effective TCC
+	  activation temperature via the TCC Offset register, which is widely
+	  supported on modern Intel platforms.
+	  Note that, on different platforms, the behavior might be different
+	  on how fast the setting takes effect, and how much the CPU frequency
+	  is reduced.
diff --git a/drivers/thermal/intel/Makefile b/drivers/thermal/intel/Makefile
index ff2ad30ef397..5ff2afa388f7 100644
--- a/drivers/thermal/intel/Makefile
+++ b/drivers/thermal/intel/Makefile
@@ -10,4 +10,5 @@  obj-$(CONFIG_INTEL_QUARK_DTS_THERMAL)	+= intel_quark_dts_thermal.o
 obj-$(CONFIG_INT340X_THERMAL)  += int340x_thermal/
 obj-$(CONFIG_INTEL_BXT_PMIC_THERMAL) += intel_bxt_pmic_thermal.o
 obj-$(CONFIG_INTEL_PCH_THERMAL)	+= intel_pch_thermal.o
+obj-$(CONFIG_INTEL_TCC_COOLING)	+= intel_tcc_cooling.o
 obj-$(CONFIG_X86_THERMAL_VECTOR) += therm_throt.o
diff --git a/drivers/thermal/intel/intel_tcc_cooling.c b/drivers/thermal/intel/intel_tcc_cooling.c
new file mode 100644
index 000000000000..aa6bbb9ba898
--- /dev/null
+++ b/drivers/thermal/intel/intel_tcc_cooling.c
@@ -0,0 +1,128 @@ 
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * cooling device driver that activates the processor throttling by
+ * programming the TCC Offset register.
+ * Copyright (c) 2021, Intel Corporation.
+ */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/thermal.h>
+#include <asm/cpu_device_id.h>
+
+#define TCC_SHIFT 24
+#define TCC_MASK	(0x3fULL<<24)
+#define TCC_PROGRAMMABLE	BIT(30)
+
+static struct thermal_cooling_device *tcc_cdev;
+
+static int tcc_get_max_state(struct thermal_cooling_device *cdev, unsigned long
+			     *state)
+{
+	*state = TCC_MASK >> TCC_SHIFT;
+	return 0;
+}
+
+static int tcc_offset_update(int tcc)
+{
+	u64 val;
+	int err;
+
+	err = rdmsrl_safe(MSR_IA32_TEMPERATURE_TARGET, &val);
+	if (err)
+		return err;
+
+	val &= ~TCC_MASK;
+	val |= tcc << TCC_SHIFT;
+
+	err = wrmsrl_safe(MSR_IA32_TEMPERATURE_TARGET, val);
+	if (err)
+		return err;
+
+	return 0;
+}
+
+static int tcc_get_cur_state(struct thermal_cooling_device *cdev, unsigned long
+			     *state)
+{
+	u64 val;
+	int err;
+
+	err = rdmsrl_safe(MSR_IA32_TEMPERATURE_TARGET, &val);
+	if (err)
+		return err;
+
+	*state = (val & TCC_MASK) >> TCC_SHIFT;
+	return 0;
+}
+
+static int tcc_set_cur_state(struct thermal_cooling_device *cdev, unsigned long
+			     state)
+{
+	return tcc_offset_update(state);
+}
+
+static const struct thermal_cooling_device_ops tcc_cooling_ops = {
+	.get_max_state = tcc_get_max_state,
+	.get_cur_state = tcc_get_cur_state,
+	.set_cur_state = tcc_set_cur_state,
+};
+
+static const struct x86_cpu_id tcc_ids[] __initconst = {
+	X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE, NULL),
+	X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE_L, NULL),
+	X86_MATCH_INTEL_FAM6_MODEL(KABYLAKE, NULL),
+	X86_MATCH_INTEL_FAM6_MODEL(KABYLAKE_L, NULL),
+	X86_MATCH_INTEL_FAM6_MODEL(ICELAKE, NULL),
+	X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_L, NULL),
+	X86_MATCH_INTEL_FAM6_MODEL(TIGERLAKE, NULL),
+	X86_MATCH_INTEL_FAM6_MODEL(TIGERLAKE_L, NULL),
+	{}
+};
+
+MODULE_DEVICE_TABLE(x86cpu, tcc_ids);
+
+static int __init tcc_cooling_init(void)
+{
+	int ret;
+	u64 val;
+	const struct x86_cpu_id *id;
+
+	int err;
+
+	id = x86_match_cpu(tcc_ids);
+	if (!id)
+		return -ENODEV;
+
+	err = rdmsrl_safe(MSR_PLATFORM_INFO, &val);
+	if (err)
+		return err;
+
+	if (!(val & TCC_PROGRAMMABLE))
+		return -ENODEV;
+
+	pr_info("Programmable TCC Offset detected\n");
+
+	tcc_cdev =
+	    thermal_cooling_device_register("TCC Offset", NULL,
+					    &tcc_cooling_ops);
+	if (IS_ERR(tcc_cdev)) {
+		ret = PTR_ERR(tcc_cdev);
+		return ret;
+	}
+	return 0;
+}
+
+module_init(tcc_cooling_init)
+
+static void __exit tcc_cooling_exit(void)
+{
+	thermal_cooling_device_unregister(tcc_cdev);
+}
+
+module_exit(tcc_cooling_exit)
+
+MODULE_DESCRIPTION("TCC offset cooling device Driver");
+MODULE_AUTHOR("Zhang Rui <rui.zhang@intel.com>");
+MODULE_LICENSE("GPL v2");