aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/events/amd/iommu.c113
-rw-r--r--include/linux/perf_event.h7
2 files changed, 57 insertions, 63 deletions
diff --git a/arch/x86/events/amd/iommu.c b/arch/x86/events/amd/iommu.c
index 7ac8138023cc..f0d94c8b382a 100644
--- a/arch/x86/events/amd/iommu.c
+++ b/arch/x86/events/amd/iommu.c
@@ -23,17 +23,16 @@
23 23
24#define COUNTER_SHIFT 16 24#define COUNTER_SHIFT 16
25 25
26#define _GET_BANK(ev) ((u8)(ev->hw.extra_reg.reg >> 8)) 26/* iommu pmu conf masks */
27#define _GET_CNTR(ev) ((u8)(ev->hw.extra_reg.reg)) 27#define GET_CSOURCE(x) ((x)->conf & 0xFFULL)
28 28#define GET_DEVID(x) (((x)->conf >> 8) & 0xFFFFULL)
29/* iommu pmu config masks */ 29#define GET_DOMID(x) (((x)->conf >> 24) & 0xFFFFULL)
30#define _GET_CSOURCE(ev) ((ev->hw.config & 0xFFULL)) 30#define GET_PASID(x) (((x)->conf >> 40) & 0xFFFFFULL)
31#define _GET_DEVID(ev) ((ev->hw.config >> 8) & 0xFFFFULL) 31
32#define _GET_PASID(ev) ((ev->hw.config >> 24) & 0xFFFFULL) 32/* iommu pmu conf1 masks */
33#define _GET_DOMID(ev) ((ev->hw.config >> 40) & 0xFFFFULL) 33#define GET_DEVID_MASK(x) ((x)->conf1 & 0xFFFFULL)
34#define _GET_DEVID_MASK(ev) ((ev->hw.extra_reg.config) & 0xFFFFULL) 34#define GET_DOMID_MASK(x) (((x)->conf1 >> 16) & 0xFFFFULL)
35#define _GET_PASID_MASK(ev) ((ev->hw.extra_reg.config >> 16) & 0xFFFFULL) 35#define GET_PASID_MASK(x) (((x)->conf1 >> 32) & 0xFFFFFULL)
36#define _GET_DOMID_MASK(ev) ((ev->hw.extra_reg.config >> 32) & 0xFFFFULL)
37 36
38static struct perf_amd_iommu __perf_iommu; 37static struct perf_amd_iommu __perf_iommu;
39 38
@@ -50,11 +49,11 @@ struct perf_amd_iommu {
50 *---------------------------------------------*/ 49 *---------------------------------------------*/
51PMU_FORMAT_ATTR(csource, "config:0-7"); 50PMU_FORMAT_ATTR(csource, "config:0-7");
52PMU_FORMAT_ATTR(devid, "config:8-23"); 51PMU_FORMAT_ATTR(devid, "config:8-23");
53PMU_FORMAT_ATTR(pasid, "config:24-39"); 52PMU_FORMAT_ATTR(domid, "config:24-39");
54PMU_FORMAT_ATTR(domid, "config:40-55"); 53PMU_FORMAT_ATTR(pasid, "config:40-59");
55PMU_FORMAT_ATTR(devid_mask, "config1:0-15"); 54PMU_FORMAT_ATTR(devid_mask, "config1:0-15");
56PMU_FORMAT_ATTR(pasid_mask, "config1:16-31"); 55PMU_FORMAT_ATTR(domid_mask, "config1:16-31");
57PMU_FORMAT_ATTR(domid_mask, "config1:32-47"); 56PMU_FORMAT_ATTR(pasid_mask, "config1:32-51");
58 57
59static struct attribute *iommu_format_attrs[] = { 58static struct attribute *iommu_format_attrs[] = {
60 &format_attr_csource.attr, 59 &format_attr_csource.attr,
@@ -150,30 +149,34 @@ static struct attribute_group amd_iommu_cpumask_group = {
150 149
151/*---------------------------------------------*/ 150/*---------------------------------------------*/
152 151
153static int get_next_avail_iommu_bnk_cntr(struct perf_amd_iommu *perf_iommu) 152static int get_next_avail_iommu_bnk_cntr(struct perf_event *event)
154{ 153{
154 struct perf_amd_iommu *piommu = container_of(event->pmu, struct perf_amd_iommu, pmu);
155 int max_cntrs = piommu->max_counters;
156 int max_banks = piommu->max_banks;
157 u32 shift, bank, cntr;
155 unsigned long flags; 158 unsigned long flags;
156 int shift, bank, cntr, retval; 159 int retval;
157 int max_banks = perf_iommu->max_banks;
158 int max_cntrs = perf_iommu->max_counters;
159 160
160 raw_spin_lock_irqsave(&perf_iommu->lock, flags); 161 raw_spin_lock_irqsave(&piommu->lock, flags);
161 162
162 for (bank = 0, shift = 0; bank < max_banks; bank++) { 163 for (bank = 0, shift = 0; bank < max_banks; bank++) {
163 for (cntr = 0; cntr < max_cntrs; cntr++) { 164 for (cntr = 0; cntr < max_cntrs; cntr++) {
164 shift = bank + (bank*3) + cntr; 165 shift = bank + (bank*3) + cntr;
165 if (perf_iommu->cntr_assign_mask & BIT_ULL(shift)) { 166 if (piommu->cntr_assign_mask & BIT_ULL(shift)) {
166 continue; 167 continue;
167 } else { 168 } else {
168 perf_iommu->cntr_assign_mask |= BIT_ULL(shift); 169 piommu->cntr_assign_mask |= BIT_ULL(shift);
169 retval = ((bank & 0xFF) << 8) | (cntr & 0xFF); 170 event->hw.iommu_bank = bank;
171 event->hw.iommu_cntr = cntr;
172 retval = 0;
170 goto out; 173 goto out;
171 } 174 }
172 } 175 }
173 } 176 }
174 retval = -ENOSPC; 177 retval = -ENOSPC;
175out: 178out:
176 raw_spin_unlock_irqrestore(&perf_iommu->lock, flags); 179 raw_spin_unlock_irqrestore(&piommu->lock, flags);
177 return retval; 180 return retval;
178} 181}
179 182
@@ -202,8 +205,6 @@ static int clear_avail_iommu_bnk_cntr(struct perf_amd_iommu *perf_iommu,
202static int perf_iommu_event_init(struct perf_event *event) 205static int perf_iommu_event_init(struct perf_event *event)
203{ 206{
204 struct hw_perf_event *hwc = &event->hw; 207 struct hw_perf_event *hwc = &event->hw;
205 struct perf_amd_iommu *perf_iommu;
206 u64 config, config1;
207 208
208 /* test the event attr type check for PMU enumeration */ 209 /* test the event attr type check for PMU enumeration */
209 if (event->attr.type != event->pmu->type) 210 if (event->attr.type != event->pmu->type)
@@ -225,21 +226,9 @@ static int perf_iommu_event_init(struct perf_event *event)
225 if (event->cpu < 0) 226 if (event->cpu < 0)
226 return -EINVAL; 227 return -EINVAL;
227 228
228 perf_iommu = &__perf_iommu;
229
230 if (event->pmu != &perf_iommu->pmu)
231 return -ENOENT;
232
233 if (perf_iommu) {
234 config = event->attr.config;
235 config1 = event->attr.config1;
236 } else {
237 return -EINVAL;
238 }
239
240 /* update the hw_perf_event struct with the iommu config data */ 229 /* update the hw_perf_event struct with the iommu config data */
241 hwc->config = config; 230 hwc->conf = event->attr.config;
242 hwc->extra_reg.config = config1; 231 hwc->conf1 = event->attr.config1;
243 232
244 return 0; 233 return 0;
245} 234}
@@ -247,26 +236,28 @@ static int perf_iommu_event_init(struct perf_event *event)
247static void perf_iommu_enable_event(struct perf_event *ev) 236static void perf_iommu_enable_event(struct perf_event *ev)
248{ 237{
249 struct amd_iommu *iommu = get_amd_iommu(0); 238 struct amd_iommu *iommu = get_amd_iommu(0);
250 u8 csource = _GET_CSOURCE(ev); 239 struct hw_perf_event *hwc = &ev->hw;
251 u16 devid = _GET_DEVID(ev); 240 u8 bank = hwc->iommu_bank;
252 u8 bank = _GET_BANK(ev); 241 u8 cntr = hwc->iommu_cntr;
253 u8 cntr = _GET_CNTR(ev);
254 u64 reg = 0ULL; 242 u64 reg = 0ULL;
255 243
256 reg = csource; 244 reg = GET_CSOURCE(hwc);
257 amd_iommu_pc_set_reg(iommu, bank, cntr, IOMMU_PC_COUNTER_SRC_REG, &reg); 245 amd_iommu_pc_set_reg(iommu, bank, cntr, IOMMU_PC_COUNTER_SRC_REG, &reg);
258 246
259 reg = devid | (_GET_DEVID_MASK(ev) << 32); 247 reg = GET_DEVID_MASK(hwc);
248 reg = GET_DEVID(hwc) | (reg << 32);
260 if (reg) 249 if (reg)
261 reg |= BIT(31); 250 reg |= BIT(31);
262 amd_iommu_pc_set_reg(iommu, bank, cntr, IOMMU_PC_DEVID_MATCH_REG, &reg); 251 amd_iommu_pc_set_reg(iommu, bank, cntr, IOMMU_PC_DEVID_MATCH_REG, &reg);
263 252
264 reg = _GET_PASID(ev) | (_GET_PASID_MASK(ev) << 32); 253 reg = GET_PASID_MASK(hwc);
254 reg = GET_PASID(hwc) | (reg << 32);
265 if (reg) 255 if (reg)
266 reg |= BIT(31); 256 reg |= BIT(31);
267 amd_iommu_pc_set_reg(iommu, bank, cntr, IOMMU_PC_PASID_MATCH_REG, &reg); 257 amd_iommu_pc_set_reg(iommu, bank, cntr, IOMMU_PC_PASID_MATCH_REG, &reg);
268 258
269 reg = _GET_DOMID(ev) | (_GET_DOMID_MASK(ev) << 32); 259 reg = GET_DOMID_MASK(hwc);
260 reg = GET_DOMID(hwc) | (reg << 32);
270 if (reg) 261 if (reg)
271 reg |= BIT(31); 262 reg |= BIT(31);
272 amd_iommu_pc_set_reg(iommu, bank, cntr, IOMMU_PC_DOMID_MATCH_REG, &reg); 263 amd_iommu_pc_set_reg(iommu, bank, cntr, IOMMU_PC_DOMID_MATCH_REG, &reg);
@@ -275,16 +266,16 @@ static void perf_iommu_enable_event(struct perf_event *ev)
275static void perf_iommu_disable_event(struct perf_event *event) 266static void perf_iommu_disable_event(struct perf_event *event)
276{ 267{
277 struct amd_iommu *iommu = get_amd_iommu(0); 268 struct amd_iommu *iommu = get_amd_iommu(0);
269 struct hw_perf_event *hwc = &event->hw;
278 u64 reg = 0ULL; 270 u64 reg = 0ULL;
279 271
280 amd_iommu_pc_set_reg(iommu, _GET_BANK(event), _GET_CNTR(event), 272 amd_iommu_pc_set_reg(iommu, hwc->iommu_bank, hwc->iommu_cntr,
281 IOMMU_PC_COUNTER_SRC_REG, &reg); 273 IOMMU_PC_COUNTER_SRC_REG, &reg);
282} 274}
283 275
284static void perf_iommu_start(struct perf_event *event, int flags) 276static void perf_iommu_start(struct perf_event *event, int flags)
285{ 277{
286 struct hw_perf_event *hwc = &event->hw; 278 struct hw_perf_event *hwc = &event->hw;
287 struct amd_iommu *iommu = get_amd_iommu(0);
288 279
289 if (WARN_ON_ONCE(!(hwc->state & PERF_HES_STOPPED))) 280 if (WARN_ON_ONCE(!(hwc->state & PERF_HES_STOPPED)))
290 return; 281 return;
@@ -293,8 +284,10 @@ static void perf_iommu_start(struct perf_event *event, int flags)
293 hwc->state = 0; 284 hwc->state = 0;
294 285
295 if (flags & PERF_EF_RELOAD) { 286 if (flags & PERF_EF_RELOAD) {
296 u64 prev_raw_count = local64_read(&hwc->prev_count); 287 u64 prev_raw_count = local64_read(&hwc->prev_count);
297 amd_iommu_pc_set_reg(iommu, _GET_BANK(event), _GET_CNTR(event), 288 struct amd_iommu *iommu = get_amd_iommu(0);
289
290 amd_iommu_pc_set_reg(iommu, hwc->iommu_bank, hwc->iommu_cntr,
298 IOMMU_PC_COUNTER_REG, &prev_raw_count); 291 IOMMU_PC_COUNTER_REG, &prev_raw_count);
299 } 292 }
300 293
@@ -309,7 +302,7 @@ static void perf_iommu_read(struct perf_event *event)
309 struct hw_perf_event *hwc = &event->hw; 302 struct hw_perf_event *hwc = &event->hw;
310 struct amd_iommu *iommu = get_amd_iommu(0); 303 struct amd_iommu *iommu = get_amd_iommu(0);
311 304
312 if (amd_iommu_pc_get_reg(iommu, _GET_BANK(event), _GET_CNTR(event), 305 if (amd_iommu_pc_get_reg(iommu, hwc->iommu_bank, hwc->iommu_cntr,
313 IOMMU_PC_COUNTER_REG, &count)) 306 IOMMU_PC_COUNTER_REG, &count))
314 return; 307 return;
315 308
@@ -329,7 +322,6 @@ static void perf_iommu_read(struct perf_event *event)
329static void perf_iommu_stop(struct perf_event *event, int flags) 322static void perf_iommu_stop(struct perf_event *event, int flags)
330{ 323{
331 struct hw_perf_event *hwc = &event->hw; 324 struct hw_perf_event *hwc = &event->hw;
332 u64 config;
333 325
334 if (hwc->state & PERF_HES_UPTODATE) 326 if (hwc->state & PERF_HES_UPTODATE)
335 return; 327 return;
@@ -341,7 +333,6 @@ static void perf_iommu_stop(struct perf_event *event, int flags)
341 if (hwc->state & PERF_HES_UPTODATE) 333 if (hwc->state & PERF_HES_UPTODATE)
342 return; 334 return;
343 335
344 config = hwc->config;
345 perf_iommu_read(event); 336 perf_iommu_read(event);
346 hwc->state |= PERF_HES_UPTODATE; 337 hwc->state |= PERF_HES_UPTODATE;
347} 338}
@@ -349,16 +340,12 @@ static void perf_iommu_stop(struct perf_event *event, int flags)
349static int perf_iommu_add(struct perf_event *event, int flags) 340static int perf_iommu_add(struct perf_event *event, int flags)
350{ 341{
351 int retval; 342 int retval;
352 struct perf_amd_iommu *perf_iommu =
353 container_of(event->pmu, struct perf_amd_iommu, pmu);
354 343
355 event->hw.state = PERF_HES_UPTODATE | PERF_HES_STOPPED; 344 event->hw.state = PERF_HES_UPTODATE | PERF_HES_STOPPED;
356 345
357 /* request an iommu bank/counter */ 346 /* request an iommu bank/counter */
358 retval = get_next_avail_iommu_bnk_cntr(perf_iommu); 347 retval = get_next_avail_iommu_bnk_cntr(event);
359 if (retval != -ENOSPC) 348 if (retval)
360 event->hw.extra_reg.reg = (u16)retval;
361 else
362 return retval; 349 return retval;
363 350
364 if (flags & PERF_EF_START) 351 if (flags & PERF_EF_START)
@@ -369,6 +356,7 @@ static int perf_iommu_add(struct perf_event *event, int flags)
369 356
370static void perf_iommu_del(struct perf_event *event, int flags) 357static void perf_iommu_del(struct perf_event *event, int flags)
371{ 358{
359 struct hw_perf_event *hwc = &event->hw;
372 struct perf_amd_iommu *perf_iommu = 360 struct perf_amd_iommu *perf_iommu =
373 container_of(event->pmu, struct perf_amd_iommu, pmu); 361 container_of(event->pmu, struct perf_amd_iommu, pmu);
374 362
@@ -376,8 +364,7 @@ static void perf_iommu_del(struct perf_event *event, int flags)
376 364
377 /* clear the assigned iommu bank/counter */ 365 /* clear the assigned iommu bank/counter */
378 clear_avail_iommu_bnk_cntr(perf_iommu, 366 clear_avail_iommu_bnk_cntr(perf_iommu,
379 _GET_BANK(event), 367 hwc->iommu_bank, hwc->iommu_cntr);
380 _GET_CNTR(event));
381 368
382 perf_event_update_userpage(event); 369 perf_event_update_userpage(event);
383} 370}
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index b6e75c9d4791..24a635887f28 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -165,6 +165,13 @@ struct hw_perf_event {
165 struct list_head bp_list; 165 struct list_head bp_list;
166 }; 166 };
167#endif 167#endif
168 struct { /* amd_iommu */
169 u8 iommu_bank;
170 u8 iommu_cntr;
171 u16 padding;
172 u64 conf;
173 u64 conf1;
174 };
168 }; 175 };
169 /* 176 /*
170 * If the event is a per task event, this will point to the task in 177 * If the event is a per task event, this will point to the task in