1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Intel Running Average Power Limit (RAPL) Driver via MSR interface 4 * Copyright (c) 2019, Intel Corporation. 5 */ 6 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 7 8 #include <linux/kernel.h> 9 #include <linux/module.h> 10 #include <linux/list.h> 11 #include <linux/types.h> 12 #include <linux/device.h> 13 #include <linux/slab.h> 14 #include <linux/log2.h> 15 #include <linux/bitmap.h> 16 #include <linux/delay.h> 17 #include <linux/sysfs.h> 18 #include <linux/cpu.h> 19 #include <linux/powercap.h> 20 #include <linux/suspend.h> 21 #include <linux/intel_rapl.h> 22 #include <linux/processor.h> 23 #include <linux/platform_device.h> 24 25 #include <asm/cpu_device_id.h> 26 #include <asm/intel-family.h> 27 #include <asm/msr.h> 28 29 /* Local defines */ 30 #define MSR_PLATFORM_POWER_LIMIT 0x0000065C 31 #define MSR_VR_CURRENT_CONFIG 0x00000601 32 33 /* private data for RAPL MSR Interface */ 34 static struct rapl_if_priv *rapl_msr_priv; 35 36 static bool rapl_msr_pmu __ro_after_init; 37 38 static struct rapl_if_priv rapl_msr_priv_intel = { 39 .type = RAPL_IF_MSR, 40 .reg_unit.msr = MSR_RAPL_POWER_UNIT, 41 .regs[RAPL_DOMAIN_PACKAGE][RAPL_DOMAIN_REG_LIMIT].msr = MSR_PKG_POWER_LIMIT, 42 .regs[RAPL_DOMAIN_PACKAGE][RAPL_DOMAIN_REG_STATUS].msr = MSR_PKG_ENERGY_STATUS, 43 .regs[RAPL_DOMAIN_PACKAGE][RAPL_DOMAIN_REG_PERF].msr = MSR_PKG_PERF_STATUS, 44 .regs[RAPL_DOMAIN_PACKAGE][RAPL_DOMAIN_REG_INFO].msr = MSR_PKG_POWER_INFO, 45 .regs[RAPL_DOMAIN_PP0][RAPL_DOMAIN_REG_LIMIT].msr = MSR_PP0_POWER_LIMIT, 46 .regs[RAPL_DOMAIN_PP0][RAPL_DOMAIN_REG_STATUS].msr = MSR_PP0_ENERGY_STATUS, 47 .regs[RAPL_DOMAIN_PP0][RAPL_DOMAIN_REG_POLICY].msr = MSR_PP0_POLICY, 48 .regs[RAPL_DOMAIN_PP1][RAPL_DOMAIN_REG_LIMIT].msr = MSR_PP1_POWER_LIMIT, 49 .regs[RAPL_DOMAIN_PP1][RAPL_DOMAIN_REG_STATUS].msr = MSR_PP1_ENERGY_STATUS, 50 .regs[RAPL_DOMAIN_PP1][RAPL_DOMAIN_REG_POLICY].msr = MSR_PP1_POLICY, 51 .regs[RAPL_DOMAIN_DRAM][RAPL_DOMAIN_REG_LIMIT].msr = MSR_DRAM_POWER_LIMIT, 52 .regs[RAPL_DOMAIN_DRAM][RAPL_DOMAIN_REG_STATUS].msr = MSR_DRAM_ENERGY_STATUS, 53 .regs[RAPL_DOMAIN_DRAM][RAPL_DOMAIN_REG_PERF].msr = MSR_DRAM_PERF_STATUS, 54 .regs[RAPL_DOMAIN_DRAM][RAPL_DOMAIN_REG_INFO].msr = MSR_DRAM_POWER_INFO, 55 .regs[RAPL_DOMAIN_PLATFORM][RAPL_DOMAIN_REG_LIMIT].msr = MSR_PLATFORM_POWER_LIMIT, 56 .regs[RAPL_DOMAIN_PLATFORM][RAPL_DOMAIN_REG_STATUS].msr = MSR_PLATFORM_ENERGY_STATUS, 57 .limits[RAPL_DOMAIN_PACKAGE] = BIT(POWER_LIMIT2), 58 .limits[RAPL_DOMAIN_PLATFORM] = BIT(POWER_LIMIT2), 59 }; 60 61 static struct rapl_if_priv rapl_msr_priv_amd = { 62 .type = RAPL_IF_MSR, 63 .reg_unit.msr = MSR_AMD_RAPL_POWER_UNIT, 64 .regs[RAPL_DOMAIN_PACKAGE][RAPL_DOMAIN_REG_STATUS].msr = MSR_AMD_PKG_ENERGY_STATUS, 65 .regs[RAPL_DOMAIN_PP0][RAPL_DOMAIN_REG_STATUS].msr = MSR_AMD_CORE_ENERGY_STATUS, 66 }; 67 68 /* Handles CPU hotplug on multi-socket systems. 69 * If a CPU goes online as the first CPU of the physical package 70 * we add the RAPL package to the system. Similarly, when the last 71 * CPU of the package is removed, we remove the RAPL package and its 72 * associated domains. Cooling devices are handled accordingly at 73 * per-domain level. 74 */ 75 static int rapl_cpu_online(unsigned int cpu) 76 { 77 struct rapl_package *rp; 78 79 rp = rapl_find_package_domain_cpuslocked(cpu, rapl_msr_priv, true); 80 if (!rp) { 81 rp = rapl_add_package_cpuslocked(cpu, rapl_msr_priv, true); 82 if (IS_ERR(rp)) 83 return PTR_ERR(rp); 84 if (rapl_msr_pmu) 85 rapl_package_add_pmu_locked(rp); 86 } 87 cpumask_set_cpu(cpu, &rp->cpumask); 88 return 0; 89 } 90 91 static int rapl_cpu_down_prep(unsigned int cpu) 92 { 93 struct rapl_package *rp; 94 int lead_cpu; 95 96 rp = rapl_find_package_domain_cpuslocked(cpu, rapl_msr_priv, true); 97 if (!rp) 98 return 0; 99 100 cpumask_clear_cpu(cpu, &rp->cpumask); 101 lead_cpu = cpumask_first(&rp->cpumask); 102 if (lead_cpu >= nr_cpu_ids) { 103 if (rapl_msr_pmu) 104 rapl_package_remove_pmu_locked(rp); 105 rapl_remove_package_cpuslocked(rp); 106 } else if (rp->lead_cpu == cpu) { 107 rp->lead_cpu = lead_cpu; 108 } 109 110 return 0; 111 } 112 113 static int rapl_msr_read_raw(int cpu, struct reg_action *ra, bool atomic) 114 { 115 /* 116 * When called from atomic-context (eg PMU event handler) 117 * perform MSR read directly using rdmsrq(). 118 */ 119 if (atomic) { 120 if (unlikely(smp_processor_id() != cpu)) 121 return -EIO; 122 123 rdmsrq(ra->reg.msr, ra->value); 124 goto out; 125 } 126 127 if (rdmsrq_safe_on_cpu(cpu, ra->reg.msr, &ra->value)) { 128 pr_debug("failed to read msr 0x%x on cpu %d\n", ra->reg.msr, cpu); 129 return -EIO; 130 } 131 132 out: 133 ra->value &= ra->mask; 134 return 0; 135 } 136 137 static void rapl_msr_update_func(void *info) 138 { 139 struct reg_action *ra = info; 140 u64 val; 141 142 ra->err = rdmsrq_safe(ra->reg.msr, &val); 143 if (ra->err) 144 return; 145 146 val &= ~ra->mask; 147 val |= ra->value; 148 149 ra->err = wrmsrq_safe(ra->reg.msr, val); 150 } 151 152 static int rapl_msr_write_raw(int cpu, struct reg_action *ra) 153 { 154 int ret; 155 156 ret = smp_call_function_single(cpu, rapl_msr_update_func, ra, 1); 157 if (WARN_ON_ONCE(ret)) 158 return ret; 159 160 return ra->err; 161 } 162 163 /* List of verified CPUs. */ 164 static const struct x86_cpu_id pl4_support_ids[] = { 165 X86_MATCH_VFM(INTEL_ICELAKE_L, NULL), 166 X86_MATCH_VFM(INTEL_TIGERLAKE_L, NULL), 167 X86_MATCH_VFM(INTEL_ALDERLAKE, NULL), 168 X86_MATCH_VFM(INTEL_ALDERLAKE_L, NULL), 169 X86_MATCH_VFM(INTEL_ATOM_GRACEMONT, NULL), 170 X86_MATCH_VFM(INTEL_RAPTORLAKE, NULL), 171 X86_MATCH_VFM(INTEL_RAPTORLAKE_P, NULL), 172 X86_MATCH_VFM(INTEL_METEORLAKE, NULL), 173 X86_MATCH_VFM(INTEL_METEORLAKE_L, NULL), 174 X86_MATCH_VFM(INTEL_ARROWLAKE_U, NULL), 175 X86_MATCH_VFM(INTEL_ARROWLAKE_H, NULL), 176 X86_MATCH_VFM(INTEL_PANTHERLAKE_L, NULL), 177 X86_MATCH_VFM(INTEL_WILDCATLAKE_L, NULL), 178 X86_MATCH_VFM(INTEL_NOVALAKE, NULL), 179 X86_MATCH_VFM(INTEL_NOVALAKE_L, NULL), 180 {} 181 }; 182 183 /* List of MSR-based RAPL PMU support CPUs */ 184 static const struct x86_cpu_id pmu_support_ids[] = { 185 X86_MATCH_VFM(INTEL_PANTHERLAKE_L, NULL), 186 X86_MATCH_VFM(INTEL_WILDCATLAKE_L, NULL), 187 {} 188 }; 189 190 static int rapl_msr_probe(struct platform_device *pdev) 191 { 192 const struct x86_cpu_id *id = x86_match_cpu(pl4_support_ids); 193 int ret; 194 195 switch (boot_cpu_data.x86_vendor) { 196 case X86_VENDOR_INTEL: 197 rapl_msr_priv = &rapl_msr_priv_intel; 198 break; 199 case X86_VENDOR_HYGON: 200 case X86_VENDOR_AMD: 201 rapl_msr_priv = &rapl_msr_priv_amd; 202 break; 203 default: 204 pr_err("intel-rapl does not support CPU vendor %d\n", boot_cpu_data.x86_vendor); 205 return -ENODEV; 206 } 207 rapl_msr_priv->read_raw = rapl_msr_read_raw; 208 rapl_msr_priv->write_raw = rapl_msr_write_raw; 209 210 if (id) { 211 rapl_msr_priv->limits[RAPL_DOMAIN_PACKAGE] |= BIT(POWER_LIMIT4); 212 rapl_msr_priv->regs[RAPL_DOMAIN_PACKAGE][RAPL_DOMAIN_REG_PL4].msr = 213 MSR_VR_CURRENT_CONFIG; 214 pr_info("PL4 support detected.\n"); 215 } 216 217 if (x86_match_cpu(pmu_support_ids)) { 218 rapl_msr_pmu = true; 219 pr_info("MSR-based RAPL PMU support enabled\n"); 220 } 221 222 rapl_msr_priv->control_type = powercap_register_control_type(NULL, "intel-rapl", NULL); 223 if (IS_ERR(rapl_msr_priv->control_type)) { 224 pr_debug("failed to register powercap control_type.\n"); 225 return PTR_ERR(rapl_msr_priv->control_type); 226 } 227 228 ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "powercap/rapl:online", 229 rapl_cpu_online, rapl_cpu_down_prep); 230 if (ret < 0) 231 goto out; 232 rapl_msr_priv->pcap_rapl_online = ret; 233 234 return 0; 235 236 out: 237 if (ret) 238 powercap_unregister_control_type(rapl_msr_priv->control_type); 239 return ret; 240 } 241 242 static void rapl_msr_remove(struct platform_device *pdev) 243 { 244 cpuhp_remove_state(rapl_msr_priv->pcap_rapl_online); 245 powercap_unregister_control_type(rapl_msr_priv->control_type); 246 } 247 248 static const struct platform_device_id rapl_msr_ids[] = { 249 { .name = "intel_rapl_msr", }, 250 {} 251 }; 252 MODULE_DEVICE_TABLE(platform, rapl_msr_ids); 253 254 static struct platform_driver intel_rapl_msr_driver = { 255 .probe = rapl_msr_probe, 256 .remove = rapl_msr_remove, 257 .id_table = rapl_msr_ids, 258 .driver = { 259 .name = "intel_rapl_msr", 260 }, 261 }; 262 263 module_platform_driver(intel_rapl_msr_driver); 264 265 MODULE_DESCRIPTION("Driver for Intel RAPL (Running Average Power Limit) control via MSR interface"); 266 MODULE_AUTHOR("Zhang Rui <rui.zhang@intel.com>"); 267 MODULE_LICENSE("GPL v2"); 268