Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

powercap: intel_rapl: Prepare read_raw() interface for atomic-context callers

The current read_raw() implementation of the TPMI, MMIO and MSR
interfaces does not distinguish between atomic and non-atomic callers.

rapl_msr_read_raw() uses rdmsrq_safe_on_cpu(), which can sleep and
issue cross CPU calls. When MSR-based RAPL PMU support is enabled, PMU
event handlers can invoke this function from atomic context where
sleeping or rescheduling is not allowed. In atomic context, the caller
is already executing on the target CPU, so a direct rdmsrq() is
sufficient.

To support such usage, introduce an atomic flag to the read_raw()
interface to allow callers pass the context information. Modify the
common RAPL code to propagate this flag, and set the flag to reflect
the calling contexts.

Utilize the atomic flag in rapl_msr_read_raw() to perform direct MSR
read with rdmsrq() when running in atomic context, and a sanity check
to ensure target CPU matches the current CPU for such use cases.

The TPMI and MMIO implementations do not require special atomic
handling, so the flag is ignored in those paths.

This is a preparatory patch for adding MSR-based RAPL PMU support.

Signed-off-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
Reviewed-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
[ rjw: Subject tweak ]
Link: https://patch.msgid.link/20251121000539.386069-2-sathyanarayanan.kuppuswamy@linux.intel.com
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>

authored by

Kuppuswamy Sathyanarayanan and committed by
Rafael J. Wysocki
1d6c9158 58075aec

+31 -15
+13 -11
drivers/powercap/intel_rapl_common.c
··· 253 253 static void rapl_init_domains(struct rapl_package *rp); 254 254 static int rapl_read_data_raw(struct rapl_domain *rd, 255 255 enum rapl_primitives prim, 256 - bool xlate, u64 *data); 256 + bool xlate, u64 *data, 257 + bool atomic); 257 258 static int rapl_write_data_raw(struct rapl_domain *rd, 258 259 enum rapl_primitives prim, 259 260 unsigned long long value); ··· 290 289 cpus_read_lock(); 291 290 rd = power_zone_to_rapl_domain(power_zone); 292 291 293 - if (!rapl_read_data_raw(rd, ENERGY_COUNTER, true, &energy_now)) { 292 + if (!rapl_read_data_raw(rd, ENERGY_COUNTER, true, &energy_now, false)) { 294 293 *energy_raw = energy_now; 295 294 cpus_read_unlock(); 296 295 ··· 831 830 * 63-------------------------- 31--------------------------- 0 832 831 */ 833 832 static int rapl_read_data_raw(struct rapl_domain *rd, 834 - enum rapl_primitives prim, bool xlate, u64 *data) 833 + enum rapl_primitives prim, bool xlate, u64 *data, 834 + bool atomic) 835 835 { 836 836 u64 value; 837 837 enum rapl_primitives prim_fixed = prim_fixups(rd, prim); ··· 854 852 855 853 ra.mask = rpi->mask; 856 854 857 - if (rd->rp->priv->read_raw(get_rid(rd->rp), &ra)) { 855 + if (rd->rp->priv->read_raw(get_rid(rd->rp), &ra, atomic)) { 858 856 pr_debug("failed to read reg 0x%llx for %s:%s\n", ra.reg.val, rd->rp->name, rd->name); 859 857 return -EIO; 860 858 } ··· 906 904 if (!is_pl_valid(rd, pl)) 907 905 return -EINVAL; 908 906 909 - return rapl_read_data_raw(rd, prim, xlate, data); 907 + return rapl_read_data_raw(rd, prim, xlate, data, false); 910 908 } 911 909 912 910 static int rapl_write_pl_data(struct rapl_domain *rd, int pl, ··· 943 941 944 942 ra.reg = rd->regs[RAPL_DOMAIN_REG_UNIT]; 945 943 ra.mask = ~0; 946 - if (rd->rp->priv->read_raw(get_rid(rd->rp), &ra)) { 944 + if (rd->rp->priv->read_raw(get_rid(rd->rp), &ra, false)) { 947 945 pr_err("Failed to read power unit REG 0x%llx on %s:%s, exit.\n", 948 946 ra.reg.val, rd->rp->name, rd->name); 949 947 return -ENODEV; ··· 971 969 972 970 ra.reg = rd->regs[RAPL_DOMAIN_REG_UNIT]; 973 971 ra.mask = ~0; 974 - if (rd->rp->priv->read_raw(get_rid(rd->rp), &ra)) { 972 + if (rd->rp->priv->read_raw(get_rid(rd->rp), &ra, false)) { 975 973 pr_err("Failed to read power unit REG 0x%llx on %s:%s, exit.\n", 976 974 ra.reg.val, rd->rp->name, rd->name); 977 975 return -ENODEV; ··· 1158 1156 1159 1157 ra.reg = rd->regs[RAPL_DOMAIN_REG_UNIT]; 1160 1158 ra.mask = ~0; 1161 - if (rd->rp->priv->read_raw(get_rid(rd->rp), &ra)) { 1159 + if (rd->rp->priv->read_raw(get_rid(rd->rp), &ra, false)) { 1162 1160 pr_err("Failed to read power unit REG 0x%llx on %s:%s, exit.\n", 1163 1161 ra.reg.val, rd->rp->name, rd->name); 1164 1162 return -ENODEV; ··· 1330 1328 struct rapl_primitive_info *rpi = get_rpi(rp, prim); 1331 1329 1332 1330 if (!rapl_read_data_raw(&rp->domains[dmn], prim, 1333 - rpi->unit, &val)) 1331 + rpi->unit, &val, false)) 1334 1332 rp->domains[dmn].rdd.primitives[prim] = val; 1335 1333 } 1336 1334 } ··· 1430 1428 */ 1431 1429 1432 1430 ra.mask = ENERGY_STATUS_MASK; 1433 - if (rp->priv->read_raw(get_rid(rp), &ra) || !ra.value) 1431 + if (rp->priv->read_raw(get_rid(rp), &ra, false) || !ra.value) 1434 1432 return -ENODEV; 1435 1433 1436 1434 return 0; ··· 1641 1639 if (event->hw.idx < 0) 1642 1640 return 0; 1643 1641 1644 - ret = rapl_read_data_raw(&rp->domains[event->hw.idx], ENERGY_COUNTER, false, &val); 1642 + ret = rapl_read_data_raw(&rp->domains[event->hw.idx], ENERGY_COUNTER, false, &val, true); 1645 1643 1646 1644 /* Return 0 for failed read */ 1647 1645 if (ret)
+15 -1
drivers/powercap/intel_rapl_msr.c
··· 102 102 return 0; 103 103 } 104 104 105 - static int rapl_msr_read_raw(int cpu, struct reg_action *ra) 105 + static int rapl_msr_read_raw(int cpu, struct reg_action *ra, bool atomic) 106 106 { 107 + /* 108 + * When called from atomic-context (eg PMU event handler) 109 + * perform MSR read directly using rdmsrq(). 110 + */ 111 + if (atomic) { 112 + if (unlikely(smp_processor_id() != cpu)) 113 + return -EIO; 114 + 115 + rdmsrq(ra->reg.msr, ra->value); 116 + goto out; 117 + } 118 + 107 119 if (rdmsrq_safe_on_cpu(cpu, ra->reg.msr, &ra->value)) { 108 120 pr_debug("failed to read msr 0x%x on cpu %d\n", ra->reg.msr, cpu); 109 121 return -EIO; 110 122 } 123 + 124 + out: 111 125 ra->value &= ra->mask; 112 126 return 0; 113 127 }
+1 -1
drivers/powercap/intel_rapl_tpmi.c
··· 60 60 61 61 static struct powercap_control_type *tpmi_control_type; 62 62 63 - static int tpmi_rapl_read_raw(int id, struct reg_action *ra) 63 + static int tpmi_rapl_read_raw(int id, struct reg_action *ra, bool atomic) 64 64 { 65 65 if (!ra->reg.mmio) 66 66 return -EINVAL;
+1 -1
drivers/thermal/intel/int340x_thermal/processor_thermal_rapl.c
··· 19 19 .limits[RAPL_DOMAIN_DRAM] = BIT(POWER_LIMIT2), 20 20 }; 21 21 22 - static int rapl_mmio_read_raw(int cpu, struct reg_action *ra) 22 + static int rapl_mmio_read_raw(int cpu, struct reg_action *ra, bool atomic) 23 23 { 24 24 if (!ra->reg.mmio) 25 25 return -EINVAL;
+1 -1
include/linux/intel_rapl.h
··· 152 152 union rapl_reg reg_unit; 153 153 union rapl_reg regs[RAPL_DOMAIN_MAX][RAPL_DOMAIN_REG_MAX]; 154 154 int limits[RAPL_DOMAIN_MAX]; 155 - int (*read_raw)(int id, struct reg_action *ra); 155 + int (*read_raw)(int id, struct reg_action *ra, bool atomic); 156 156 int (*write_raw)(int id, struct reg_action *ra); 157 157 void *defaults; 158 158 void *rpi;