linux/drivers/thermal/intel/intel_tcc_cooling.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * cooling device driver that activates the processor throttling by
   4 * programming the TCC Offset register.
   5 * Copyright (c) 2021, Intel Corporation.
   6 */
   7#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
   8
   9#include <linux/device.h>
  10#include <linux/module.h>
  11#include <linux/thermal.h>
  12#include <asm/cpu_device_id.h>
  13
  14#define TCC_SHIFT 24
  15#define TCC_MASK        (0x3fULL<<24)
  16#define TCC_PROGRAMMABLE        BIT(30)
  17
  18static struct thermal_cooling_device *tcc_cdev;
  19
  20static int tcc_get_max_state(struct thermal_cooling_device *cdev, unsigned long
  21                             *state)
  22{
  23        *state = TCC_MASK >> TCC_SHIFT;
  24        return 0;
  25}
  26
  27static int tcc_offset_update(int tcc)
  28{
  29        u64 val;
  30        int err;
  31
  32        err = rdmsrl_safe(MSR_IA32_TEMPERATURE_TARGET, &val);
  33        if (err)
  34                return err;
  35
  36        val &= ~TCC_MASK;
  37        val |= tcc << TCC_SHIFT;
  38
  39        err = wrmsrl_safe(MSR_IA32_TEMPERATURE_TARGET, val);
  40        if (err)
  41                return err;
  42
  43        return 0;
  44}
  45
  46static int tcc_get_cur_state(struct thermal_cooling_device *cdev, unsigned long
  47                             *state)
  48{
  49        u64 val;
  50        int err;
  51
  52        err = rdmsrl_safe(MSR_IA32_TEMPERATURE_TARGET, &val);
  53        if (err)
  54                return err;
  55
  56        *state = (val & TCC_MASK) >> TCC_SHIFT;
  57        return 0;
  58}
  59
  60static int tcc_set_cur_state(struct thermal_cooling_device *cdev, unsigned long
  61                             state)
  62{
  63        return tcc_offset_update(state);
  64}
  65
  66static const struct thermal_cooling_device_ops tcc_cooling_ops = {
  67        .get_max_state = tcc_get_max_state,
  68        .get_cur_state = tcc_get_cur_state,
  69        .set_cur_state = tcc_set_cur_state,
  70};
  71
  72static const struct x86_cpu_id tcc_ids[] __initconst = {
  73        X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE, NULL),
  74        X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE_L, NULL),
  75        X86_MATCH_INTEL_FAM6_MODEL(KABYLAKE, NULL),
  76        X86_MATCH_INTEL_FAM6_MODEL(KABYLAKE_L, NULL),
  77        X86_MATCH_INTEL_FAM6_MODEL(ICELAKE, NULL),
  78        X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_L, NULL),
  79        X86_MATCH_INTEL_FAM6_MODEL(TIGERLAKE, NULL),
  80        X86_MATCH_INTEL_FAM6_MODEL(TIGERLAKE_L, NULL),
  81        X86_MATCH_INTEL_FAM6_MODEL(COMETLAKE, NULL),
  82        {}
  83};
  84
  85MODULE_DEVICE_TABLE(x86cpu, tcc_ids);
  86
  87static int __init tcc_cooling_init(void)
  88{
  89        int ret;
  90        u64 val;
  91        const struct x86_cpu_id *id;
  92
  93        int err;
  94
  95        id = x86_match_cpu(tcc_ids);
  96        if (!id)
  97                return -ENODEV;
  98
  99        err = rdmsrl_safe(MSR_PLATFORM_INFO, &val);
 100        if (err)
 101                return err;
 102
 103        if (!(val & TCC_PROGRAMMABLE))
 104                return -ENODEV;
 105
 106        pr_info("Programmable TCC Offset detected\n");
 107
 108        tcc_cdev =
 109            thermal_cooling_device_register("TCC Offset", NULL,
 110                                            &tcc_cooling_ops);
 111        if (IS_ERR(tcc_cdev)) {
 112                ret = PTR_ERR(tcc_cdev);
 113                return ret;
 114        }
 115        return 0;
 116}
 117
 118module_init(tcc_cooling_init)
 119
 120static void __exit tcc_cooling_exit(void)
 121{
 122        thermal_cooling_device_unregister(tcc_cdev);
 123}
 124
 125module_exit(tcc_cooling_exit)
 126
 127MODULE_DESCRIPTION("TCC offset cooling device Driver");
 128MODULE_AUTHOR("Zhang Rui <rui.zhang@intel.com>");
 129MODULE_LICENSE("GPL v2");
 130