hc
2024-10-12 a5969cabbb4660eab42b6ef0412cbbd1200cf14d
kernel/arch/x86/events/amd/iommu.c
....@@ -1,3 +1,4 @@
1
+// SPDX-License-Identifier: GPL-2.0-only
12 /*
23 * Copyright (C) 2013 Advanced Micro Devices, Inc.
34 *
....@@ -5,10 +6,6 @@
56 * Author: Suravee Suthikulpanit <Suraveee.Suthikulpanit@amd.com>
67 *
78 * Perf: amd_iommu - AMD IOMMU Performance Counter PMU implementation
8
- *
9
- * This program is free software; you can redistribute it and/or modify
10
- * it under the terms of the GNU General Public License version 2 as
11
- * published by the Free Software Foundation.
129 */
1310
1411 #define pr_fmt(fmt) "perf/amd_iommu: " fmt
....@@ -20,8 +17,6 @@
2017
2118 #include "../perf_event.h"
2219 #include "iommu.h"
23
-
24
-#define COUNTER_SHIFT 16
2520
2621 /* iommu pmu conf masks */
2722 #define GET_CSOURCE(x) ((x)->conf & 0xFFULL)
....@@ -223,11 +218,6 @@
223218 if (is_sampling_event(event) || event->attach_state & PERF_ATTACH_TASK)
224219 return -EINVAL;
225220
226
- /* IOMMU counters do not have usr/os/guest/host bits */
227
- if (event->attr.exclude_user || event->attr.exclude_kernel ||
228
- event->attr.exclude_host || event->attr.exclude_guest)
229
- return -EINVAL;
230
-
231221 if (event->cpu < 0)
232222 return -EINVAL;
233223
....@@ -293,22 +283,31 @@
293283 WARN_ON_ONCE(!(hwc->state & PERF_HES_UPTODATE));
294284 hwc->state = 0;
295285
286
+ /*
287
+ * To account for power-gating, which prevents write to
288
+ * the counter, we need to enable the counter
289
+ * before setting up counter register.
290
+ */
291
+ perf_iommu_enable_event(event);
292
+
296293 if (flags & PERF_EF_RELOAD) {
297
- u64 prev_raw_count = local64_read(&hwc->prev_count);
294
+ u64 count = 0;
298295 struct amd_iommu *iommu = perf_event_2_iommu(event);
299296
297
+ /*
298
+ * Since the IOMMU PMU only support counting mode,
299
+ * the counter always start with value zero.
300
+ */
300301 amd_iommu_pc_set_reg(iommu, hwc->iommu_bank, hwc->iommu_cntr,
301
- IOMMU_PC_COUNTER_REG, &prev_raw_count);
302
+ IOMMU_PC_COUNTER_REG, &count);
302303 }
303304
304
- perf_iommu_enable_event(event);
305305 perf_event_update_userpage(event);
306
-
307306 }
308307
309308 static void perf_iommu_read(struct perf_event *event)
310309 {
311
- u64 count, prev, delta;
310
+ u64 count;
312311 struct hw_perf_event *hwc = &event->hw;
313312 struct amd_iommu *iommu = perf_event_2_iommu(event);
314313
....@@ -319,14 +318,11 @@
319318 /* IOMMU pc counter register is only 48 bits */
320319 count &= GENMASK_ULL(47, 0);
321320
322
- prev = local64_read(&hwc->prev_count);
323
- if (local64_cmpxchg(&hwc->prev_count, prev, count) != prev)
324
- return;
325
-
326
- /* Handle 48-bit counter overflow */
327
- delta = (count << COUNTER_SHIFT) - (prev << COUNTER_SHIFT);
328
- delta >>= COUNTER_SHIFT;
329
- local64_add(delta, &event->count);
321
+ /*
322
+ * Since the counter always start with value zero,
323
+ * simply just accumulate the count for the event.
324
+ */
325
+ local64_add(count, &event->count);
330326 }
331327
332328 static void perf_iommu_stop(struct perf_event *event, int flags)
....@@ -336,15 +332,16 @@
336332 if (hwc->state & PERF_HES_UPTODATE)
337333 return;
338334
335
+ /*
336
+ * To account for power-gating, in which reading the counter would
337
+ * return zero, we need to read the register before disabling.
338
+ */
339
+ perf_iommu_read(event);
340
+ hwc->state |= PERF_HES_UPTODATE;
341
+
339342 perf_iommu_disable_event(event);
340343 WARN_ON_ONCE(hwc->state & PERF_HES_STOPPED);
341344 hwc->state |= PERF_HES_STOPPED;
342
-
343
- if (hwc->state & PERF_HES_UPTODATE)
344
- return;
345
-
346
- perf_iommu_read(event);
347
- hwc->state |= PERF_HES_UPTODATE;
348345 }
349346
350347 static int perf_iommu_add(struct perf_event *event, int flags)
....@@ -398,7 +395,7 @@
398395 return 0;
399396 }
400397
401
-const struct attribute_group *amd_iommu_attr_groups[] = {
398
+static const struct attribute_group *amd_iommu_attr_groups[] = {
402399 &amd_iommu_format_group,
403400 &amd_iommu_cpumask_group,
404401 &amd_iommu_events_group,
....@@ -414,6 +411,7 @@
414411 .read = perf_iommu_read,
415412 .task_ctx_nr = perf_invalid_context,
416413 .attr_groups = amd_iommu_attr_groups,
414
+ .capabilities = PERF_PMU_CAP_NO_EXCLUDE,
417415 };
418416
419417 static __init int init_one_iommu(unsigned int idx)