1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Resource Director Technology(RDT) 4 * - Intel Application Energy Telemetry 5 * 6 * Copyright (C) 2025 Intel Corporation 7 * 8 * Author: 9 * Tony Luck <tony.luck@intel.com> 10 */ 11 12 #define pr_fmt(fmt) "resctrl: " fmt 13 14 #include <linux/compiler_types.h> 15 #include <linux/err.h> 16 #include <linux/init.h> 17 #include <linux/intel_pmt_features.h> 18 #include <linux/intel_vsec.h> 19 #include <linux/resctrl.h> 20 #include <linux/resctrl_types.h> 21 #include <linux/stddef.h> 22 #include <linux/types.h> 23 24 #include "internal.h" 25 26 /** 27 * struct pmt_event - Telemetry event. 28 * @id: Resctrl event id. 29 * @idx: Counter index within each per-RMID block of counters. 30 * @bin_bits: Zero for integer valued events, else number bits in fraction 31 * part of fixed-point. 32 */ 33 struct pmt_event { 34 enum resctrl_event_id id; 35 unsigned int idx; 36 unsigned int bin_bits; 37 }; 38 39 #define EVT(_id, _idx, _bits) { .id = _id, .idx = _idx, .bin_bits = _bits } 40 41 /** 42 * struct event_group - Events with the same feature type ("energy" or "perf") and GUID. 43 * @pfname: PMT feature name ("energy" or "perf") of this event group. 44 * @pfg: Points to the aggregated telemetry space information 45 * returned by the intel_pmt_get_regions_by_feature() 46 * call to the INTEL_PMT_TELEMETRY driver that contains 47 * data for all telemetry regions of type @pfname. 48 * Valid if the system supports the event group, 49 * NULL otherwise. 50 * @guid: Unique number per XML description file. 51 * @mmio_size: Number of bytes of MMIO registers for this group. 52 * @num_events: Number of events in this group. 53 * @evts: Array of event descriptors. 54 */ 55 struct event_group { 56 /* Data fields for additional structures to manage this group. */ 57 const char *pfname; 58 struct pmt_feature_group *pfg; 59 60 /* Remaining fields initialized from XML file. */ 61 u32 guid; 62 size_t mmio_size; 63 unsigned int num_events; 64 struct pmt_event evts[] __counted_by(num_events); 65 }; 66 67 #define XML_MMIO_SIZE(num_rmids, num_events, num_extra_status) \ 68 (((num_rmids) * (num_events) + (num_extra_status)) * sizeof(u64)) 69 70 /* 71 * Link: https://github.com/intel/Intel-PMT/blob/main/xml/CWF/OOBMSM/RMID-ENERGY/cwf_aggregator.xml 72 */ 73 static struct event_group energy_0x26696143 = { 74 .pfname = "energy", 75 .guid = 0x26696143, 76 .mmio_size = XML_MMIO_SIZE(576, 2, 3), 77 .num_events = 2, 78 .evts = { 79 EVT(PMT_EVENT_ENERGY, 0, 18), 80 EVT(PMT_EVENT_ACTIVITY, 1, 18), 81 } 82 }; 83 84 /* 85 * Link: https://github.com/intel/Intel-PMT/blob/main/xml/CWF/OOBMSM/RMID-PERF/cwf_aggregator.xml 86 */ 87 static struct event_group perf_0x26557651 = { 88 .pfname = "perf", 89 .guid = 0x26557651, 90 .mmio_size = XML_MMIO_SIZE(576, 7, 3), 91 .num_events = 7, 92 .evts = { 93 EVT(PMT_EVENT_STALLS_LLC_HIT, 0, 0), 94 EVT(PMT_EVENT_C1_RES, 1, 0), 95 EVT(PMT_EVENT_UNHALTED_CORE_CYCLES, 2, 0), 96 EVT(PMT_EVENT_STALLS_LLC_MISS, 3, 0), 97 EVT(PMT_EVENT_AUTO_C6_RES, 4, 0), 98 EVT(PMT_EVENT_UNHALTED_REF_CYCLES, 5, 0), 99 EVT(PMT_EVENT_UOPS_RETIRED, 6, 0), 100 } 101 }; 102 103 static struct event_group *known_event_groups[] = { 104 &energy_0x26696143, 105 &perf_0x26557651, 106 }; 107 108 #define for_each_event_group(_peg) \ 109 for (_peg = known_event_groups; \ 110 _peg < &known_event_groups[ARRAY_SIZE(known_event_groups)]; \ 111 _peg++) 112 113 /* Stub for now */ 114 static bool enable_events(struct event_group *e, struct pmt_feature_group *p) 115 { 116 return false; 117 } 118 119 static enum pmt_feature_id lookup_pfid(const char *pfname) 120 { 121 if (!strcmp(pfname, "energy")) 122 return FEATURE_PER_RMID_ENERGY_TELEM; 123 else if (!strcmp(pfname, "perf")) 124 return FEATURE_PER_RMID_PERF_TELEM; 125 126 pr_warn("Unknown PMT feature name '%s'\n", pfname); 127 128 return FEATURE_INVALID; 129 } 130 131 /* 132 * Request a copy of struct pmt_feature_group for each event group. If there is 133 * one, the returned structure has an array of telemetry_region structures, 134 * each element of the array describes one telemetry aggregator. The 135 * telemetry aggregators may have different GUIDs so obtain duplicate struct 136 * pmt_feature_group for event groups with same feature type but different 137 * GUID. Post-processing ensures an event group can only use the telemetry 138 * aggregators that match its GUID. An event group keeps a pointer to its 139 * struct pmt_feature_group to indicate that its events are successfully 140 * enabled. 141 */ 142 bool intel_aet_get_events(void) 143 { 144 struct pmt_feature_group *p; 145 enum pmt_feature_id pfid; 146 struct event_group **peg; 147 bool ret = false; 148 149 for_each_event_group(peg) { 150 pfid = lookup_pfid((*peg)->pfname); 151 p = intel_pmt_get_regions_by_feature(pfid); 152 if (IS_ERR_OR_NULL(p)) 153 continue; 154 if (enable_events(*peg, p)) { 155 (*peg)->pfg = p; 156 ret = true; 157 } else { 158 intel_pmt_put_feature_group(p); 159 } 160 } 161 162 return ret; 163 } 164 165 void __exit intel_aet_exit(void) 166 { 167 struct event_group **peg; 168 169 for_each_event_group(peg) { 170 if ((*peg)->pfg) { 171 intel_pmt_put_feature_group((*peg)->pfg); 172 (*peg)->pfg = NULL; 173 } 174 } 175 } 176