0001
0002
0003
0004
0005
0006 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0007
0008 #include <linux/kernel.h>
0009 #include <linux/module.h>
0010 #include <linux/list.h>
0011 #include <linux/types.h>
0012 #include <linux/device.h>
0013 #include <linux/slab.h>
0014 #include <linux/log2.h>
0015 #include <linux/bitmap.h>
0016 #include <linux/delay.h>
0017 #include <linux/sysfs.h>
0018 #include <linux/cpu.h>
0019 #include <linux/powercap.h>
0020 #include <linux/suspend.h>
0021 #include <linux/intel_rapl.h>
0022 #include <linux/processor.h>
0023 #include <linux/platform_device.h>
0024
0025 #include <asm/iosf_mbi.h>
0026 #include <asm/cpu_device_id.h>
0027 #include <asm/intel-family.h>
0028
0029
0030 #define MSR_PLATFORM_POWER_LIMIT 0x0000065C
0031 #define MSR_VR_CURRENT_CONFIG 0x00000601
0032
0033
0034 static struct rapl_if_priv *rapl_msr_priv;
0035
0036 static struct rapl_if_priv rapl_msr_priv_intel = {
0037 .reg_unit = MSR_RAPL_POWER_UNIT,
0038 .regs[RAPL_DOMAIN_PACKAGE] = {
0039 MSR_PKG_POWER_LIMIT, MSR_PKG_ENERGY_STATUS, MSR_PKG_PERF_STATUS, 0, MSR_PKG_POWER_INFO },
0040 .regs[RAPL_DOMAIN_PP0] = {
0041 MSR_PP0_POWER_LIMIT, MSR_PP0_ENERGY_STATUS, 0, MSR_PP0_POLICY, 0 },
0042 .regs[RAPL_DOMAIN_PP1] = {
0043 MSR_PP1_POWER_LIMIT, MSR_PP1_ENERGY_STATUS, 0, MSR_PP1_POLICY, 0 },
0044 .regs[RAPL_DOMAIN_DRAM] = {
0045 MSR_DRAM_POWER_LIMIT, MSR_DRAM_ENERGY_STATUS, MSR_DRAM_PERF_STATUS, 0, MSR_DRAM_POWER_INFO },
0046 .regs[RAPL_DOMAIN_PLATFORM] = {
0047 MSR_PLATFORM_POWER_LIMIT, MSR_PLATFORM_ENERGY_STATUS, 0, 0, 0},
0048 .limits[RAPL_DOMAIN_PACKAGE] = 2,
0049 .limits[RAPL_DOMAIN_PLATFORM] = 2,
0050 };
0051
0052 static struct rapl_if_priv rapl_msr_priv_amd = {
0053 .reg_unit = MSR_AMD_RAPL_POWER_UNIT,
0054 .regs[RAPL_DOMAIN_PACKAGE] = {
0055 0, MSR_AMD_PKG_ENERGY_STATUS, 0, 0, 0 },
0056 .regs[RAPL_DOMAIN_PP0] = {
0057 0, MSR_AMD_CORE_ENERGY_STATUS, 0, 0, 0 },
0058 };
0059
0060
0061
0062
0063
0064
0065
0066
0067 static int rapl_cpu_online(unsigned int cpu)
0068 {
0069 struct rapl_package *rp;
0070
0071 rp = rapl_find_package_domain(cpu, rapl_msr_priv);
0072 if (!rp) {
0073 rp = rapl_add_package(cpu, rapl_msr_priv);
0074 if (IS_ERR(rp))
0075 return PTR_ERR(rp);
0076 }
0077 cpumask_set_cpu(cpu, &rp->cpumask);
0078 return 0;
0079 }
0080
0081 static int rapl_cpu_down_prep(unsigned int cpu)
0082 {
0083 struct rapl_package *rp;
0084 int lead_cpu;
0085
0086 rp = rapl_find_package_domain(cpu, rapl_msr_priv);
0087 if (!rp)
0088 return 0;
0089
0090 cpumask_clear_cpu(cpu, &rp->cpumask);
0091 lead_cpu = cpumask_first(&rp->cpumask);
0092 if (lead_cpu >= nr_cpu_ids)
0093 rapl_remove_package(rp);
0094 else if (rp->lead_cpu == cpu)
0095 rp->lead_cpu = lead_cpu;
0096 return 0;
0097 }
0098
0099 static int rapl_msr_read_raw(int cpu, struct reg_action *ra)
0100 {
0101 u32 msr = (u32)ra->reg;
0102
0103 if (rdmsrl_safe_on_cpu(cpu, msr, &ra->value)) {
0104 pr_debug("failed to read msr 0x%x on cpu %d\n", msr, cpu);
0105 return -EIO;
0106 }
0107 ra->value &= ra->mask;
0108 return 0;
0109 }
0110
0111 static void rapl_msr_update_func(void *info)
0112 {
0113 struct reg_action *ra = info;
0114 u32 msr = (u32)ra->reg;
0115 u64 val;
0116
0117 ra->err = rdmsrl_safe(msr, &val);
0118 if (ra->err)
0119 return;
0120
0121 val &= ~ra->mask;
0122 val |= ra->value;
0123
0124 ra->err = wrmsrl_safe(msr, val);
0125 }
0126
0127 static int rapl_msr_write_raw(int cpu, struct reg_action *ra)
0128 {
0129 int ret;
0130
0131 ret = smp_call_function_single(cpu, rapl_msr_update_func, ra, 1);
0132 if (WARN_ON_ONCE(ret))
0133 return ret;
0134
0135 return ra->err;
0136 }
0137
0138
0139 static const struct x86_cpu_id pl4_support_ids[] = {
0140 { X86_VENDOR_INTEL, 6, INTEL_FAM6_TIGERLAKE_L, X86_FEATURE_ANY },
0141 { X86_VENDOR_INTEL, 6, INTEL_FAM6_ALDERLAKE, X86_FEATURE_ANY },
0142 { X86_VENDOR_INTEL, 6, INTEL_FAM6_ALDERLAKE_L, X86_FEATURE_ANY },
0143 { X86_VENDOR_INTEL, 6, INTEL_FAM6_ALDERLAKE_N, X86_FEATURE_ANY },
0144 { X86_VENDOR_INTEL, 6, INTEL_FAM6_RAPTORLAKE, X86_FEATURE_ANY },
0145 { X86_VENDOR_INTEL, 6, INTEL_FAM6_RAPTORLAKE_P, X86_FEATURE_ANY },
0146 {}
0147 };
0148
0149 static int rapl_msr_probe(struct platform_device *pdev)
0150 {
0151 const struct x86_cpu_id *id = x86_match_cpu(pl4_support_ids);
0152 int ret;
0153
0154 switch (boot_cpu_data.x86_vendor) {
0155 case X86_VENDOR_INTEL:
0156 rapl_msr_priv = &rapl_msr_priv_intel;
0157 break;
0158 case X86_VENDOR_HYGON:
0159 case X86_VENDOR_AMD:
0160 rapl_msr_priv = &rapl_msr_priv_amd;
0161 break;
0162 default:
0163 pr_err("intel-rapl does not support CPU vendor %d\n", boot_cpu_data.x86_vendor);
0164 return -ENODEV;
0165 }
0166 rapl_msr_priv->read_raw = rapl_msr_read_raw;
0167 rapl_msr_priv->write_raw = rapl_msr_write_raw;
0168
0169 if (id) {
0170 rapl_msr_priv->limits[RAPL_DOMAIN_PACKAGE] = 3;
0171 rapl_msr_priv->regs[RAPL_DOMAIN_PACKAGE][RAPL_DOMAIN_REG_PL4] =
0172 MSR_VR_CURRENT_CONFIG;
0173 pr_info("PL4 support detected.\n");
0174 }
0175
0176 rapl_msr_priv->control_type = powercap_register_control_type(NULL, "intel-rapl", NULL);
0177 if (IS_ERR(rapl_msr_priv->control_type)) {
0178 pr_debug("failed to register powercap control_type.\n");
0179 return PTR_ERR(rapl_msr_priv->control_type);
0180 }
0181
0182 ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "powercap/rapl:online",
0183 rapl_cpu_online, rapl_cpu_down_prep);
0184 if (ret < 0)
0185 goto out;
0186 rapl_msr_priv->pcap_rapl_online = ret;
0187
0188 return 0;
0189
0190 out:
0191 if (ret)
0192 powercap_unregister_control_type(rapl_msr_priv->control_type);
0193 return ret;
0194 }
0195
0196 static int rapl_msr_remove(struct platform_device *pdev)
0197 {
0198 cpuhp_remove_state(rapl_msr_priv->pcap_rapl_online);
0199 powercap_unregister_control_type(rapl_msr_priv->control_type);
0200 return 0;
0201 }
0202
0203 static const struct platform_device_id rapl_msr_ids[] = {
0204 { .name = "intel_rapl_msr", },
0205 {}
0206 };
0207 MODULE_DEVICE_TABLE(platform, rapl_msr_ids);
0208
0209 static struct platform_driver intel_rapl_msr_driver = {
0210 .probe = rapl_msr_probe,
0211 .remove = rapl_msr_remove,
0212 .id_table = rapl_msr_ids,
0213 .driver = {
0214 .name = "intel_rapl_msr",
0215 },
0216 };
0217
0218 module_platform_driver(intel_rapl_msr_driver);
0219
0220 MODULE_DESCRIPTION("Driver for Intel RAPL (Running Average Power Limit) control via MSR interface");
0221 MODULE_AUTHOR("Zhang Rui <rui.zhang@intel.com>");
0222 MODULE_LICENSE("GPL v2");