Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * cooling device driver that activates the processor throttling by
0004  * programming the TCC Offset register.
0005  * Copyright (c) 2021, Intel Corporation.
0006  */
0007 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0008 
0009 #include <linux/device.h>
0010 #include <linux/module.h>
0011 #include <linux/thermal.h>
0012 #include <asm/cpu_device_id.h>
0013 
0014 #define TCC_SHIFT 24
0015 #define TCC_MASK    (0x3fULL<<24)
0016 #define TCC_PROGRAMMABLE    BIT(30)
0017 
0018 static struct thermal_cooling_device *tcc_cdev;
0019 
0020 static int tcc_get_max_state(struct thermal_cooling_device *cdev, unsigned long
0021                  *state)
0022 {
0023     *state = TCC_MASK >> TCC_SHIFT;
0024     return 0;
0025 }
0026 
0027 static int tcc_offset_update(int tcc)
0028 {
0029     u64 val;
0030     int err;
0031 
0032     err = rdmsrl_safe(MSR_IA32_TEMPERATURE_TARGET, &val);
0033     if (err)
0034         return err;
0035 
0036     val &= ~TCC_MASK;
0037     val |= tcc << TCC_SHIFT;
0038 
0039     err = wrmsrl_safe(MSR_IA32_TEMPERATURE_TARGET, val);
0040     if (err)
0041         return err;
0042 
0043     return 0;
0044 }
0045 
0046 static int tcc_get_cur_state(struct thermal_cooling_device *cdev, unsigned long
0047                  *state)
0048 {
0049     u64 val;
0050     int err;
0051 
0052     err = rdmsrl_safe(MSR_IA32_TEMPERATURE_TARGET, &val);
0053     if (err)
0054         return err;
0055 
0056     *state = (val & TCC_MASK) >> TCC_SHIFT;
0057     return 0;
0058 }
0059 
0060 static int tcc_set_cur_state(struct thermal_cooling_device *cdev, unsigned long
0061                  state)
0062 {
0063     return tcc_offset_update(state);
0064 }
0065 
0066 static const struct thermal_cooling_device_ops tcc_cooling_ops = {
0067     .get_max_state = tcc_get_max_state,
0068     .get_cur_state = tcc_get_cur_state,
0069     .set_cur_state = tcc_set_cur_state,
0070 };
0071 
0072 static const struct x86_cpu_id tcc_ids[] __initconst = {
0073     X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE, NULL),
0074     X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE_L, NULL),
0075     X86_MATCH_INTEL_FAM6_MODEL(KABYLAKE, NULL),
0076     X86_MATCH_INTEL_FAM6_MODEL(KABYLAKE_L, NULL),
0077     X86_MATCH_INTEL_FAM6_MODEL(ICELAKE, NULL),
0078     X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_L, NULL),
0079     X86_MATCH_INTEL_FAM6_MODEL(TIGERLAKE, NULL),
0080     X86_MATCH_INTEL_FAM6_MODEL(TIGERLAKE_L, NULL),
0081     X86_MATCH_INTEL_FAM6_MODEL(COMETLAKE, NULL),
0082     X86_MATCH_INTEL_FAM6_MODEL(ALDERLAKE, NULL),
0083     X86_MATCH_INTEL_FAM6_MODEL(ALDERLAKE_L, NULL),
0084     X86_MATCH_INTEL_FAM6_MODEL(ALDERLAKE_N, NULL),
0085     X86_MATCH_INTEL_FAM6_MODEL(RAPTORLAKE, NULL),
0086     X86_MATCH_INTEL_FAM6_MODEL(RAPTORLAKE_P, NULL),
0087     {}
0088 };
0089 
0090 MODULE_DEVICE_TABLE(x86cpu, tcc_ids);
0091 
0092 static int __init tcc_cooling_init(void)
0093 {
0094     int ret;
0095     u64 val;
0096     const struct x86_cpu_id *id;
0097 
0098     int err;
0099 
0100     id = x86_match_cpu(tcc_ids);
0101     if (!id)
0102         return -ENODEV;
0103 
0104     err = rdmsrl_safe(MSR_PLATFORM_INFO, &val);
0105     if (err)
0106         return err;
0107 
0108     if (!(val & TCC_PROGRAMMABLE))
0109         return -ENODEV;
0110 
0111     pr_info("Programmable TCC Offset detected\n");
0112 
0113     tcc_cdev =
0114         thermal_cooling_device_register("TCC Offset", NULL,
0115                         &tcc_cooling_ops);
0116     if (IS_ERR(tcc_cdev)) {
0117         ret = PTR_ERR(tcc_cdev);
0118         return ret;
0119     }
0120     return 0;
0121 }
0122 
0123 module_init(tcc_cooling_init)
0124 
0125 static void __exit tcc_cooling_exit(void)
0126 {
0127     thermal_cooling_device_unregister(tcc_cdev);
0128 }
0129 
0130 module_exit(tcc_cooling_exit)
0131 
0132 MODULE_DESCRIPTION("TCC offset cooling device Driver");
0133 MODULE_AUTHOR("Zhang Rui <rui.zhang@intel.com>");
0134 MODULE_LICENSE("GPL v2");