* [PATCH V2 0/6] powerpc/perf: Add HTM PMU driver and perf AUX support
@ 2026-07-20 10:44 Athira Rajeev
2026-07-20 10:44 ` [PATCH V2 1/6] powerpc/perf: Add HTM PMU driver to expose Hardware Trace Macro data Athira Rajeev
` (5 more replies)
0 siblings, 6 replies; 13+ messages in thread
From: Athira Rajeev @ 2026-07-20 10:44 UTC (permalink / raw)
To: linuxppc-dev, maddy
Cc: linux-perf-users, atrajeev, hbathini, tejas05, venkat88, tshah,
usha.r2
Overview:
The Hardware Trace Macro (HTM) on POWER systems provides hardware-level
bus-trace data for a specific node/chip/core target within a logical
partition. It is accessed via the H_HTM hypervisor call and traces
continuously at node, chip, or core scope independent of task scheduling.
This series adds a new "htm" PMU driver under arch/powerpc/perf/ that
exposes HTM trace collection via the standard perf interface using the
perf AUX buffer infrastructure, together with ABI and RST documentation.
Patch overview:
Patch 1 introduces the core HTM PMU driver (htm-perf.c). The event
configuration encodes the trace target as a 28-bit value in
perf_event_attr.config:
bits 0-3: htm_type (HTM_CORE=2, HTM_NEST=1)
bits 4-11: nodeindex
bits 12-19: nodalchipindex
bits 20-27: coreindexonchip
The PMU lifecycle maps to H_HTM_OP_CONFIGURE/DECONFIGURE at add/del time
and H_HTM_OP_START/STOP at start/stop time. Context-switch callbacks
(PERF_EF_RELOAD / PERF_EF_UPDATE) are intentionally ignored because HTM
traces the hardware scope, not individual tasks. Tracing state is kept
in event->pmu_private (HTM_TRACING_ACTIVE / HTM_TRACING_INACTIVE) as the
authoritative source, with event->hw.state kept in sync as a hint for the
perf core.
Patch 2 adds duplicate-reservation protection. When 'perf record -a' is
used, perf opens system-wide events on all CPUs in parallel. Without
driver-side tracking, concurrent opens for the same HTM target (node,
chip, core, type) can race and issue duplicate H_HTM_OP_CONFIGURE flows.
A global reserved-targets list is added; htm_event_init() rejects any
open that matches an already-reserved tuple, while different targets can
still be opened simultaneously on different CPUs.
Patch 3 adds AUX ring-buffer support so that high-volume trace data can
be streamed into a perf AUX buffer. The driver opts into
PERF_PMU_CAP_AUX_NO_SG | PERF_PMU_CAP_AUX_PREFER_LARGE to request
physically contiguous allocations, which H_HTM_OP_DUMP_DATA requires.
A page-by-page physical-continuity scan is performed before each dump to
detect and bound any fragmentation gaps, preventing silent memory
corruption. event->count is set to 1 when data is present and 0 when
the stream is exhausted; the perf tool uses this as a drain signal to
decide whether another read pass is needed before closing the event.
Patch 4 adds system memory configuration capture. After writing trace
data to the AUX buffer, htm_event_read() calls H_HTM_OP_DUMP_SYSMEM_CONF
and emits the returned physical-to-logical address mapping records as
PERF_SAMPLE_RAW data. Keeping trace data in the AUX stream and memory
configuration in raw samples allows each to be decoded independently in
userspace.
Patch 5 adds ABI documentation for the sysfs entries under
/sys/bus/event_source/devices/htm/, covering the format attribute
(config bit layout) and the events attribute group.
Patch 6 extends Documentation/arch/powerpc/htm.rst with a new section
on the perf interface: event syntax, required options, the two output
files (htm.bin.nX.pX.cX and translation.nX.pX.cX), and how to pass
them to htmdecode for trace decoding.
Usage example:
Collect HTM trace data from two simultaneous chip targets:
# perf record -m,256 \
-e htm/nodalchipindex=2,nodeindex=0,htm_type=1,cpu=8/ \
-e htm/nodalchipindex=1,nodeindex=0,htm_type=1,cpu=9/ \
-a -- sleep 10
# perf report
Output files written by perf report:
htm.bin.n0.p2.c0 raw HTM bus-trace, chip 2
htm.bin.n0.p1.c0 raw HTM bus-trace, chip 1
translation.n0.p2.c0 memory config records, chip 2
translation.n0.p1.c0 memory config records, chip 1
The htm.bin.* files can then be decoded with htmdecoder to produce
trace output.
Testing:
Tested on POWER10 with two simultaneous HTM targets. Both htm.bin.*
and translation.* files are produced correctly.
# perf record -C 9 -m,256 \
-e htm/nodalchipindex=2,nodeindex=0,htm_type=1/ sleep 3
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 256.277 MB perf.data ]
Athira Rajeev (6):
powerpc/perf: Add HTM PMU driver to expose Hardware Trace Macro data
powerpc/perf: Reject duplicate HTM target reservations
powerpc/perf: Add AUX buffer management to capture HTM trace data
powerpc/perf: Capture the HTM memory configuration as part of perf
data
docs: ABI: sysfs-bus-event_source-devices-htm: Document sysfs event
format entries for htm pmu
powerpc/perf/htm: Add documentation for Hardware Trace Macro PMU
.../sysfs-bus-event_source-devices-htm | 21 +
Documentation/arch/powerpc/htm.rst | 137 +++-
arch/powerpc/perf/Makefile | 2 +-
arch/powerpc/perf/htm-perf.c | 749 ++++++++++++++++++
4 files changed, 905 insertions(+), 4 deletions(-)
create mode 100644 Documentation/ABI/testing/sysfs-bus-event_source-devices-htm
create mode 100644 arch/powerpc/perf/htm-perf.c
--
2.43.0
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH V2 1/6] powerpc/perf: Add HTM PMU driver to expose Hardware Trace Macro data
2026-07-20 10:44 [PATCH V2 0/6] powerpc/perf: Add HTM PMU driver and perf AUX support Athira Rajeev
@ 2026-07-20 10:44 ` Athira Rajeev
2026-07-20 11:00 ` sashiko-bot
2026-07-20 10:44 ` [PATCH V2 2/6] powerpc/perf: Reject duplicate HTM target reservations Athira Rajeev
` (4 subsequent siblings)
5 siblings, 1 reply; 13+ messages in thread
From: Athira Rajeev @ 2026-07-20 10:44 UTC (permalink / raw)
To: linuxppc-dev, maddy
Cc: linux-perf-users, atrajeev, hbathini, tejas05, venkat88, tshah,
usha.r2
The H_HTM hypervisor call (hcall) provides an interface to the Hardware
Trace Macro (HTM) function on POWER systems. HTM captures hardware-level
trace data for a specific node/chip/core target within a logical partition.
Add a new "htm" Performance Monitoring Unit (PMU) that exposes HTM control
via the standard perf interface. The event configuration is a 28-bit value
packed into the perf config field:
bits 0-3: htm_type (HTM_CORE=2, HTM_NEST=1)
bits 4-11: nodeindex
bits 12-19: nodalchipindex
bits 20-27: coreindexonchip
PMU lifecycle:
add/del: Issue H_HTM_OP_CONFIGURE / H_HTM_OP_DECONFIGURE to reserve
and release the hardware trace resource.
start/stop: Issue H_HTM_OP_START / H_HTM_OP_STOP to control tracing.
HTM traces at node/chip/core scope continuously for the
duration of the event. Context-switch-triggered start/stop
callbacks (PERF_EF_RELOAD / PERF_EF_UPDATE) are ignored to
keep tracing uninterrupted. Explicit ioctl(ENABLE/DISABLE)
and event deletion do control the hardware.
State tracking uses event->pmu_private (HTM_TRACING_ACTIVE/INACTIVE) as
the source of information, with event->hw.state kept in sync as
a hint for the perf core. This avoids conflicts with infrastructure
writes to event->hw.state.
The H_HTM hcall may return H_BUSY (transient, retried up to MAX_RETRIES)
or H_LONG_BUSY_* (long delay required, not retried to avoid deadlocks in
atomic contexts).
After this patch the PMU is visible under sysfs:
# ls /sys/bus/event_source/devices/ |grep htm
htm
# ls /sys/bus/event_source/devices/htm/
events format perf_event_mux_interval_ms power subsystem type uevent
Signed-off-by: Athira Rajeev <atrajeev@linux.ibm.com>
---
Changes in V2:
- Replaced direct H_HTM_OP_CONFIGURE/DECONFIGURE calls in htm_event_add()
and htm_event_del() with separate htm_event_init() and destroy paths.
State tracking is now via event->pmu_private (HTM_TRACING_ACTIVE /
HTM_TRACING_INACTIVE) as the authoritative source, with event->hw.state
kept in sync as a hint for the perf core, avoiding conflicts with
infrastructure writes to event->hw.state.
- Context-switch callbacks (PERF_EF_RELOAD / PERF_EF_UPDATE) are now
explicitly ignored in htm_event_start()/stop() to keep tracing
uninterrupted across task switches; previously these paths were absent.
- H_BUSY retry loop is capped at MAX_RETRIES; H_LONG_BUSY_* is not
retried in atomic context to avoid deadlocks (was unconditionally
retried in V1).
arch/powerpc/perf/Makefile | 2 +-
arch/powerpc/perf/htm-perf.c | 379 +++++++++++++++++++++++++++++++++++
2 files changed, 380 insertions(+), 1 deletion(-)
create mode 100644 arch/powerpc/perf/htm-perf.c
diff --git a/arch/powerpc/perf/Makefile b/arch/powerpc/perf/Makefile
index 78dd7e25219e..26ef30c0693c 100644
--- a/arch/powerpc/perf/Makefile
+++ b/arch/powerpc/perf/Makefile
@@ -14,7 +14,7 @@ obj-$(CONFIG_PPC_POWERNV) += imc-pmu.o
obj-$(CONFIG_FSL_EMB_PERF_EVENT) += core-fsl-emb.o
obj-$(CONFIG_FSL_EMB_PERF_EVENT_E500) += e500-pmu.o e6500-pmu.o
-obj-$(CONFIG_HV_PERF_CTRS) += hv-24x7.o hv-gpci.o hv-common.o vpa-dtl.o
+obj-$(CONFIG_HV_PERF_CTRS) += hv-24x7.o hv-gpci.o hv-common.o vpa-dtl.o htm-perf.o
obj-$(CONFIG_VPA_PMU) += vpa-pmu.o
diff --git a/arch/powerpc/perf/htm-perf.c b/arch/powerpc/perf/htm-perf.c
new file mode 100644
index 000000000000..abecc9bb58dc
--- /dev/null
+++ b/arch/powerpc/perf/htm-perf.c
@@ -0,0 +1,379 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Perf interface to expose HTM Trace data.
+ *
+ * Copyright (C) 2026 Athira Rajeev, IBM Corporation
+ */
+
+#define pr_fmt(fmt) "htm: " fmt
+
+#include <asm/dtl.h>
+#include <linux/perf_event.h>
+#include <asm/plpar_wrappers.h>
+#include <asm/firmware.h>
+
+#define EVENT(_name, _code) enum{_name = _code}
+#define MAX_RETRIES 100
+
+EVENT(HTM_CORE, 0x2);
+EVENT(HTM_NEST, 0x1);
+
+GENERIC_EVENT_ATTR(htm_core, HTM_CORE);
+GENERIC_EVENT_ATTR(htm_nest, HTM_NEST);
+
+PMU_FORMAT_ATTR(event, "config:0-27");
+PMU_FORMAT_ATTR(htm_type, "config:0-3");
+PMU_FORMAT_ATTR(nodeindex, "config:4-11");
+PMU_FORMAT_ATTR(nodalchipindex, "config:12-19");
+PMU_FORMAT_ATTR(coreindexonchip, "config:20-27");
+
+static struct attribute *events_attr[] = {
+ GENERIC_EVENT_PTR(HTM_NEST),
+ GENERIC_EVENT_PTR(HTM_CORE),
+ NULL
+};
+
+static struct attribute_group event_group = {
+ .name = "events",
+ .attrs = events_attr,
+};
+
+static struct attribute *format_attrs[] = {
+ &format_attr_event.attr,
+ &format_attr_htm_type.attr,
+ &format_attr_nodeindex.attr,
+ &format_attr_nodalchipindex.attr,
+ &format_attr_coreindexonchip.attr,
+ NULL,
+};
+
+static const struct attribute_group format_group = {
+ .name = "format",
+ .attrs = format_attrs,
+};
+
+static const struct attribute_group *attr_groups[] = {
+ &format_group,
+ &event_group,
+ NULL,
+};
+
+static u64 htmflags = H_HTM_FLAGS_NOWRAP;
+
+struct htm_config {
+ u32 htmtype;
+ u32 nodeindex;
+ u32 nodalchipindex;
+ u32 coreindexonchip;
+};
+
+/*
+ * Per-event private state. Allocated in htm_event_init(), freed via the
+ * event->destroy callback (reset_htm_active()).
+ *
+ * cfg stores the HTM target identity parsed from event->attr.config.
+ * tracing_active tracks whether H_HTM_OP_START has been successfully issued
+ * for this event. It is the source of information used by
+ * htm_event_start() and htm_event_stop() to make hcall decisions.
+ * event->hw.state is kept in sync for the perf core only.
+ */
+struct htm_target_id {
+ struct htm_config cfg;
+ int tracing_active; /* HTM_TRACING_ACTIVE / HTM_TRACING_INACTIVE */
+};
+
+/* Helper to parse the 28-bit event config into distinct fields */
+static inline void parse_htm_config(u64 config, struct htm_config *cfg)
+{
+ cfg->htmtype = config & 0xf;
+ cfg->nodeindex = (config >> 4) & 0xff;
+ cfg->nodalchipindex = (config >> 12) & 0xff;
+ cfg->coreindexonchip = (config >> 20) & 0xff;
+}
+
+/*
+ * Check the return code for H_HTM hcall.
+ * Return 1 if either H_PARTIAL or H_SUCCESS is returned.
+ * Return 0 if H_NOT_AVAILABLE.
+ * Return exact negative error codes for expected issues.
+ */
+static ssize_t htm_return_check(int rc)
+{
+ switch (rc) {
+ case H_SUCCESS:
+ case H_PARTIAL:
+ return 1;
+ case H_NOT_AVAILABLE:
+ return 0;
+ case H_BUSY:
+ /* Transient busy: retry loop will spin up to MAX_RETRIES */
+ return -EBUSY;
+ case H_LONG_BUSY_ORDER_1_MSEC:
+ case H_LONG_BUSY_ORDER_10_MSEC:
+ case H_LONG_BUSY_ORDER_100_MSEC:
+ case H_LONG_BUSY_ORDER_1_SEC:
+ case H_LONG_BUSY_ORDER_10_SEC:
+ case H_LONG_BUSY_ORDER_100_SEC:
+ /*
+ * Hypervisor requests a long delay before retry (1ms-100s).
+ * Spinning in a kernel retry loop for this duration risks
+ * deadlocks in atomic contexts. Return -EAGAIN so callers
+ * exit immediately; the operation will fail and userspace
+ * can retry the perf_event_open() call.
+ * Note: all retry loops check ret == -EBUSY only, so
+ * -EAGAIN exits without retrying, this is intentional.
+ */
+ return -EAGAIN;
+ case H_PARAMETER:
+ case H_P2:
+ case H_P3:
+ case H_P4:
+ case H_P5:
+ case H_P6:
+ return -EINVAL;
+ case H_STATE:
+ return -EIO;
+ case H_AUTHORITY:
+ return -EPERM;
+ default:
+ /* Prevent silent fallthrough mapping of unhandled errors to 1 */
+ return -EIO;
+ }
+}
+
+/*
+ * HTM_TRACING_ACTIVE/INACTIVE: values for htm_target_id.tracing_active.
+ * Tracks whether H_HTM_OP_START has been successfully issued.
+ * HTM traces at node/chip/core scope, not per-task. Once started,
+ * context-switch-triggered stop/start (PERF_EF_UPDATE / PERF_EF_RELOAD)
+ * must not stop/restart the hardware. Only explicit API calls
+ * (ioctl DISABLE/ENABLE) and event_del should control the hcall.
+ */
+#define HTM_TRACING_ACTIVE 1
+#define HTM_TRACING_INACTIVE 0
+
+static void reset_htm_active(struct perf_event *event)
+{
+ kfree(event->pmu_private);
+ event->pmu_private = NULL;
+}
+
+static int htm_event_init(struct perf_event *event)
+{
+ u64 config = event->attr.config;
+ struct htm_config cfg;
+
+ if (event->attr.inherit)
+ return -EOPNOTSUPP;
+
+ if (event->attr.type != event->pmu->type)
+ return -ENOENT;
+
+ if (!perfmon_capable())
+ return -EACCES;
+
+ if (!is_sampling_event(event))
+ return -EOPNOTSUPP;
+
+ if (has_branch_stack(event))
+ return -EOPNOTSUPP;
+
+ parse_htm_config(config, &cfg);
+ switch (cfg.htmtype) {
+ case HTM_CORE:
+ case HTM_NEST:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* Allocate per-event private state; freed via event->destroy */
+ event->pmu_private = kzalloc(sizeof(struct htm_target_id), GFP_KERNEL);
+ if (!event->pmu_private)
+ return -ENOMEM;
+
+ ((struct htm_target_id *)event->pmu_private)->cfg = cfg;
+ event->destroy = reset_htm_active;
+ return 0;
+}
+
+static void htm_event_start(struct perf_event *event, int flags)
+{
+ int rc, ret, retries = 0;
+ struct htm_config cfg;
+ struct htm_target_id *target = event->pmu_private;
+
+ /*
+ * Ignore context-switch re-enables. The perf core passes
+ * PERF_EF_RELOAD on context-switch-in. HTM tracing is
+ * continuous at hardware level, no hcall needed.
+ */
+ if (flags & PERF_EF_RELOAD)
+ return;
+
+ /* Already tracing, don't issue a second start hcall */
+ if (target->tracing_active == HTM_TRACING_ACTIVE)
+ return;
+
+ cfg = target->cfg;
+
+ /* Only retry on transient H_BUSY; H_LONG_BUSY_* (-EAGAIN) exits immediately */
+ do {
+ rc = htm_hcall_wrapper(htmflags, cfg.nodeindex, cfg.nodalchipindex,
+ cfg.coreindexonchip, cfg.htmtype,
+ H_HTM_OP_START, 0, 0, 0);
+ ret = htm_return_check(rc);
+ } while (ret == -EBUSY && ++retries < MAX_RETRIES);
+
+ if (ret > 0) {
+ target->tracing_active = HTM_TRACING_ACTIVE;
+ event->hw.state &= ~PERF_HES_STOPPED;
+ }
+}
+
+static void htm_event_stop(struct perf_event *event, int flags)
+{
+ int rc, ret, retries = 0;
+ struct htm_config cfg;
+ struct htm_target_id *target = event->pmu_private;
+
+ /*
+ * Ignore context-switch-out stops. The perf core passes
+ * PERF_EF_UPDATE on context-switch-out. Do not stop the hcall.
+ */
+ if (flags & PERF_EF_UPDATE)
+ return;
+
+ /* Not tracing, nothing to stop */
+ if (target->tracing_active == HTM_TRACING_INACTIVE)
+ return;
+
+ cfg = target->cfg;
+
+ /* Only retry on transient H_BUSY; H_LONG_BUSY_* (-EAGAIN) exits immediately */
+ do {
+ rc = htm_hcall_wrapper(htmflags, cfg.nodeindex, cfg.nodalchipindex,
+ cfg.coreindexonchip, cfg.htmtype,
+ H_HTM_OP_STOP, 0, 0, 0);
+ ret = htm_return_check(rc);
+ } while (ret == -EBUSY && ++retries < MAX_RETRIES);
+
+ /*
+ * Only mark stopped if the hcall succeeded. If the stop failed
+ * (e.g. -EAGAIN on long-busy), leave tracing_active as ACTIVE so
+ * that htm_event_del will retry the stop hcall rather than
+ * skipping it and leaving the hypervisor permanently configured.
+ */
+ if (ret > 0) {
+ target->tracing_active = HTM_TRACING_INACTIVE;
+ event->hw.state |= PERF_HES_STOPPED;
+ }
+}
+
+static int htm_event_add(struct perf_event *event, int flags)
+{
+ int rc, ret, retries = 0;
+ unsigned long param1 = -1, param2 = -1;
+ struct htm_target_id *target = event->pmu_private;
+ struct htm_config cfg = target->cfg;
+
+ /* Configure the hardware, only retry on transient H_BUSY */
+ do {
+ rc = htm_hcall_wrapper(htmflags, cfg.nodeindex, cfg.nodalchipindex,
+ cfg.coreindexonchip, cfg.htmtype,
+ H_HTM_OP_CONFIGURE, param1, param2, 0);
+ ret = htm_return_check(rc);
+ } while (ret == -EBUSY && ++retries < MAX_RETRIES);
+
+ if (ret <= 0)
+ return (ret == 0) ? -ENODEV : ret;
+
+ /*
+ * htm_event_init() allocated event->pmu_private (struct htm_target_id)
+ * and set event->destroy = reset_htm_active to free it on teardown.
+ * Initialise the tracing state and hw.state before calling start.
+ */
+ target->tracing_active = HTM_TRACING_INACTIVE;
+ event->hw.state = PERF_HES_STOPPED;
+
+ /*
+ * Start tracing via the .start callback so the standard
+ * PERF_EF_START / ioctl(ENABLE) path is honoured.
+ */
+ if (flags & PERF_EF_START) {
+ htm_event_start(event, 0); /* flags=0: not a context switch */
+ if (target->tracing_active == HTM_TRACING_INACTIVE) {
+ /* Start failed, deconfigure to avoid resource leak */
+ retries = 0;
+ do {
+ rc = htm_hcall_wrapper(htmflags, cfg.nodeindex,
+ cfg.nodalchipindex, cfg.coreindexonchip,
+ cfg.htmtype, H_HTM_OP_DECONFIGURE, 0, 0, 0);
+ ret = htm_return_check(rc);
+ } while (ret == -EBUSY && ++retries < MAX_RETRIES);
+ return -EIO;
+ }
+ }
+
+ return 0;
+}
+
+static void htm_event_del(struct perf_event *event, int flags)
+{
+ int rc, ret, retries = 0;
+ struct htm_target_id *target = event->pmu_private;
+ struct htm_config cfg = target->cfg;
+
+ /* Stop tracing, flags=0 so htm_event_stop issues the hcall */
+ htm_event_stop(event, 0);
+
+ /* Deconfigure */
+ do {
+ rc = htm_hcall_wrapper(htmflags, cfg.nodeindex, cfg.nodalchipindex,
+ cfg.coreindexonchip, cfg.htmtype,
+ H_HTM_OP_DECONFIGURE, 0, 0, 0);
+ ret = htm_return_check(rc);
+ } while (ret == -EBUSY && ++retries < MAX_RETRIES);
+
+ /* pmu_private freed by event->destroy = reset_htm_active */
+}
+
+static void htm_event_read(struct perf_event *event)
+{
+}
+
+static struct pmu htm_pmu = {
+ .task_ctx_nr = perf_invalid_context,
+ .name = "htm",
+ .attr_groups = attr_groups,
+ .event_init = htm_event_init,
+ .add = htm_event_add,
+ .del = htm_event_del,
+ .read = htm_event_read,
+ .start = htm_event_start,
+ .stop = htm_event_stop,
+ .capabilities = PERF_PMU_CAP_NO_EXCLUDE | PERF_PMU_CAP_EXCLUSIVE,
+};
+
+static int htm_init(void)
+{
+ int r;
+
+ if (!firmware_has_feature(FW_FEATURE_LPAR)) {
+ pr_debug("Only supported on LPAR platforms running under a Hypervisor\n");
+ return -ENODEV;
+ }
+
+ if (is_kvm_guest()) {
+ pr_debug("Only supported for L1 host system\n");
+ return -ENODEV;
+ }
+
+ r = perf_pmu_register(&htm_pmu, htm_pmu.name, -1);
+ if (r)
+ return r;
+
+ return 0;
+}
+
+device_initcall(htm_init);
--
2.43.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH V2 2/6] powerpc/perf: Reject duplicate HTM target reservations
2026-07-20 10:44 [PATCH V2 0/6] powerpc/perf: Add HTM PMU driver and perf AUX support Athira Rajeev
2026-07-20 10:44 ` [PATCH V2 1/6] powerpc/perf: Add HTM PMU driver to expose Hardware Trace Macro data Athira Rajeev
@ 2026-07-20 10:44 ` Athira Rajeev
2026-07-20 10:55 ` sashiko-bot
2026-07-20 10:44 ` [PATCH V2 3/6] powerpc/perf: Add AUX buffer management to capture HTM trace data Athira Rajeev
` (3 subsequent siblings)
5 siblings, 1 reply; 13+ messages in thread
From: Athira Rajeev @ 2026-07-20 10:44 UTC (permalink / raw)
To: linuxppc-dev, maddy
Cc: linux-perf-users, atrajeev, hbathini, tejas05, venkat88, tshah,
usha.r2
HTM tracing is controlled through hypervisor calls and operates on a
system-scoped target identified by HTM type, node index, chip index,
and core index. When userspace opens a system-wide event such as via
'perf record -a', perf may initialize matching events on multiple CPUs
in parallel.
Without driver-side target tracking, concurrent event initialization for
the same HTM target can race and issue duplicate configure/start flows
for an identical tracing scope. This can lead to conflicts in the
underlying H_HTM operations.
Track reserved HTM targets globally and reject duplicate reservations
for the same target. The reservation is created during
htm_event_init() and released through the event destroy path. This
prevents concurrent duplicate opens while still allowing different HTM
targets to be used simultaneously on different CPUs.
Extend the existing per-event htm_target_id structure with a list node,
and use the stored htm_config in pmu_private for target comparison.
A cpumask-based approach was considered but not used: cpumask restricts
which CPUs an event may be opened on, but HTM operates on a hardware
target (node/chip/core) that is independent of the CPU opening the
event. A user may open an HTM event for a specific node/chip/core target
from any CPU in the system, not just CPUs that belong to that node. A
cpumask would therefore either over-restrict valid opens or require a
per-target mask that mirrors the target list anyway. The approach in
this patch handles the real constraint: the same hardware target cannot
be configured twice, regardless of which CPU does the event open.
Signed-off-by: Athira Rajeev <atrajeev@linux.ibm.com>
---
Changes in V2:
- New patch. V1 did not protect against concurrent duplicate opens of
the same HTM target when 'perf record -a' initialises system-wide
events in parallel on all CPUs.
- Adds a global reserved-targets list. htm_event_init() rejects any
open whose (node, chip, core, type) tuple is already reserved; the
reservation is released through the event destroy path.
- Different targets can still be opened simultaneously on different CPUs.
arch/powerpc/perf/htm-perf.c | 42 ++++++++++++++++++++++++++++++++----
1 file changed, 38 insertions(+), 4 deletions(-)
diff --git a/arch/powerpc/perf/htm-perf.c b/arch/powerpc/perf/htm-perf.c
index abecc9bb58dc..01c6bd2104cf 100644
--- a/arch/powerpc/perf/htm-perf.c
+++ b/arch/powerpc/perf/htm-perf.c
@@ -77,9 +77,13 @@ struct htm_config {
* htm_event_start() and htm_event_stop() to make hcall decisions.
* event->hw.state is kept in sync for the perf core only.
*/
+static LIST_HEAD(htm_active_targets_list);
+static DEFINE_MUTEX(htm_targets_lock);
+
struct htm_target_id {
struct htm_config cfg;
int tracing_active; /* HTM_TRACING_ACTIVE / HTM_TRACING_INACTIVE */
+ struct list_head list;
};
/* Helper to parse the 28-bit event config into distinct fields */
@@ -154,7 +158,17 @@ static ssize_t htm_return_check(int rc)
static void reset_htm_active(struct perf_event *event)
{
- kfree(event->pmu_private);
+ struct htm_target_id *target = event->pmu_private;
+
+ if (!target)
+ return;
+
+ mutex_lock(&htm_targets_lock);
+ if (!list_empty(&target->list))
+ list_del(&target->list);
+ mutex_unlock(&htm_targets_lock);
+
+ kfree(target);
event->pmu_private = NULL;
}
@@ -162,6 +176,7 @@ static int htm_event_init(struct perf_event *event)
{
u64 config = event->attr.config;
struct htm_config cfg;
+ struct htm_target_id *target, *tmp;
if (event->attr.inherit)
return -EOPNOTSUPP;
@@ -188,11 +203,30 @@ static int htm_event_init(struct perf_event *event)
}
/* Allocate per-event private state; freed via event->destroy */
- event->pmu_private = kzalloc(sizeof(struct htm_target_id), GFP_KERNEL);
- if (!event->pmu_private)
+ target = kzalloc(sizeof(*target), GFP_KERNEL);
+ if (!target)
return -ENOMEM;
- ((struct htm_target_id *)event->pmu_private)->cfg = cfg;
+ target->cfg = cfg;
+ target->tracing_active = HTM_TRACING_INACTIVE;
+ INIT_LIST_HEAD(&target->list);
+
+ mutex_lock(&htm_targets_lock);
+ list_for_each_entry(tmp, &htm_active_targets_list, list) {
+ if (tmp->cfg.htmtype == cfg.htmtype &&
+ tmp->cfg.nodeindex == cfg.nodeindex &&
+ tmp->cfg.nodalchipindex == cfg.nodalchipindex &&
+ tmp->cfg.coreindexonchip == cfg.coreindexonchip) {
+ mutex_unlock(&htm_targets_lock);
+ kfree(target);
+ return -EBUSY;
+ }
+ }
+
+ list_add_tail(&target->list, &htm_active_targets_list);
+ mutex_unlock(&htm_targets_lock);
+
+ event->pmu_private = target;
event->destroy = reset_htm_active;
return 0;
}
--
2.43.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH V2 3/6] powerpc/perf: Add AUX buffer management to capture HTM trace data
2026-07-20 10:44 [PATCH V2 0/6] powerpc/perf: Add HTM PMU driver and perf AUX support Athira Rajeev
2026-07-20 10:44 ` [PATCH V2 1/6] powerpc/perf: Add HTM PMU driver to expose Hardware Trace Macro data Athira Rajeev
2026-07-20 10:44 ` [PATCH V2 2/6] powerpc/perf: Reject duplicate HTM target reservations Athira Rajeev
@ 2026-07-20 10:44 ` Athira Rajeev
2026-07-20 11:10 ` sashiko-bot
2026-07-20 10:44 ` [PATCH V2 4/6] powerpc/perf: Capture the HTM memory configuration as part of perf data Athira Rajeev
` (2 subsequent siblings)
5 siblings, 1 reply; 13+ messages in thread
From: Athira Rajeev @ 2026-07-20 10:44 UTC (permalink / raw)
To: linuxppc-dev, maddy
Cc: linux-perf-users, atrajeev, hbathini, tejas05, venkat88, tshah,
usha.r2
Implement support for auxiliary (AUX) ring buffers in the HTM PMU driver.
This enables high-volume trace data to be streamed directly into a perf
AUX buffer for deferred post-processing by the perf tool.
Introduce the PMU data structures htm_pmu_buf and htm_pmu_ctx, and
implement the core lifecycle hooks:
htm_setup_aux(): Allocates per-CPU context and records the AUX buffer
base, head, and size for the active trace window.
htm_free_aux(): Releases the PMU-private tracking allocations.
The perf core AUX allocator (rb_alloc_aux) may return a page array with
physical fragmentation gaps. H_HTM_OP_DUMP_DATA operates on raw physical
addresses and requires a strictly contiguous region; crossing a gap would
cause silent memory corruption.
To prevent this, opt into PERF_PMU_CAP_AUX_NO_SG | PERF_PMU_CAP_AUX_PREFER_LARGE
to request large, physically contiguous allocations, and perform a
page-by-page physical continuity scan in htm_event_read() before each
H_HTM_OP_DUMP_DATA call. The scan verifies that
virt_to_phys(page[n]) + PAGE_SIZE == virt_to_phys(page[n+1]) and
breaks the loop on the first discontinuity, ensuring the dump to the
verified safe window.
Update htm_event_read() to set event->count to 1 when data is present
in the buffer and 0 when the stream is exhausted. This binary flag is
used by the perf tool drain hook to decide whether another read pass is
needed before closing the event. It does not represent an instruction
or cycle count; the actual trace records are decoded in userspace.
HTM target identity and tracing state are kept in event->pmu_private
(htm_target_id). AUX-private state holds only buffer metadata and
dump progress; htm_target_id.tracing_active remains the source for
tracing state.
Signed-off-by: Athira Rajeev <atrajeev@linux.ibm.com>
---
Changes in V2:
- Opted into PERF_PMU_CAP_AUX_NO_SG | PERF_PMU_CAP_AUX_PREFER_LARGE to
request physically contiguous allocations, which H_HTM_OP_DUMP_DATA
requires. V1 didn't handle no contiguity requirement.
- Added a page-by-page physical-continuity scan in htm_event_read()
before every H_HTM_OP_DUMP_DATA call. The scan verifies that
virt_to_phys(page[n]) + PAGE_SIZE == virt_to_phys(page[n+1]) and
stops at the first gap, bounding the dump to a verified safe window.
V1 had no such guard and could silently corrupt memory across gaps.
- event->count is now set to 1 when trace data is present and 0 when
the stream is exhausted. The perf tool uses this as a drain signal.
V1 relied on a separate arch_record__collect_final_data callback loop
with explicit evlist__enable cycling; this version doesn't need
explicit evlist__enable
arch/powerpc/perf/htm-perf.c | 216 ++++++++++++++++++++++++++++++++++-
1 file changed, 215 insertions(+), 1 deletion(-)
diff --git a/arch/powerpc/perf/htm-perf.c b/arch/powerpc/perf/htm-perf.c
index 01c6bd2104cf..edfca63e1e9b 100644
--- a/arch/powerpc/perf/htm-perf.c
+++ b/arch/powerpc/perf/htm-perf.c
@@ -95,6 +95,23 @@ static inline void parse_htm_config(u64 config, struct htm_config *cfg)
cfg->coreindexonchip = (config >> 20) & 0xff;
}
+struct htm_pmu_buf {
+ int nr_pages;
+ bool snapshot;
+ void *base;
+ void **pages;
+ u64 head;
+ u64 size;
+ int collect_htm_trace;
+ u64 trace_records;
+};
+
+struct htm_pmu_ctx {
+ struct perf_output_handle handle;
+};
+
+static DEFINE_PER_CPU(struct htm_pmu_ctx, htm_pmu_ctx);
+
/*
* Check the return code for H_HTM hcall.
* Return 1 if either H_PARTIAL or H_SUCCESS is returned.
@@ -372,8 +389,202 @@ static void htm_event_del(struct perf_event *event, int flags)
/* pmu_private freed by event->destroy = reset_htm_active */
}
+static int htm_dump_sample_data(struct perf_event *event)
+{
+ struct htm_pmu_ctx *htm_ctx = this_cpu_ptr(&htm_pmu_ctx);
+ struct htm_target_id *target = event->pmu_private;
+ struct htm_pmu_buf *aux_buf;
+ struct htm_config cfg = target->cfg;
+ u64 chunk_size, dump_offset, page_index, page_offset;
+ u64 max_contiguous_bytes, expected_phys, scan_index, actual_phys;
+ u64 hypervisor_target_phys;
+ void *target_page_virt;
+ int ret = 0, retries = 0;
+ long rc;
+
+ /* Start AUX transaction session framework */
+ aux_buf = perf_aux_output_begin(&htm_ctx->handle, event);
+ if (!aux_buf)
+ return 0;
+
+ if (!aux_buf->collect_htm_trace) {
+ perf_aux_output_end(&htm_ctx->handle, 0);
+ return 0;
+ }
+
+ if (target->tracing_active == HTM_TRACING_ACTIVE) {
+ htm_event_stop(event, 0);
+ if (target->tracing_active == HTM_TRACING_ACTIVE) {
+ perf_aux_output_end(&htm_ctx->handle, 0);
+ return -EAGAIN;
+ }
+ }
+
+ /* Derive the exact target destination point directly out of active ring pointers */
+ dump_offset = htm_ctx->handle.head & (aux_buf->size - 1);
+ page_index = dump_offset >> PAGE_SHIFT;
+ page_offset = dump_offset & (PAGE_SIZE - 1);
+
+ /*
+ * Assess constraints regarding space remaining across the mapping
+ * context boundary
+ */
+ chunk_size = htm_ctx->handle.size;
+ chunk_size &= PAGE_MASK;
+
+ if (chunk_size > (aux_buf->size - dump_offset))
+ chunk_size = aux_buf->size - dump_offset;
+
+ /*
+ * HTM driver uses these capabilities:
+ * PERF_PMU_CAP_AUX_NO_SG | PERF_PMU_CAP_AUX_PREFER_LARGE
+ * the core perf ring-buffer allocator (rb_alloc_aux) tries to allocate
+ * physically contiguous page block. If not available, it tries to allocate
+ * largest possible contiguous block.
+ *
+ * Example: If we ask perf for 1024 pages (64MB), the kernel executes a loop
+ * inside rb_alloc_aux() to fulfill that request using the buddy allocator. it
+ * always tries to grab the largest possible contiguous block of memory it can
+ * find first, then takes the next largest, and repeats until request is
+ * completely filled. Here while writing to aux buffer, to eliminate any
+ * virtual or physical boundary overruns, check for the page boundary.
+ *
+ * Dynamically scan forward page-by-page from our active page_index to
+ * calculate the absolute boundary limit of this current physically
+ * contiguous block chunk. Prevents hypervisor macro overruns across
+ * asymmetrical fragmentation gaps.
+ */
+ max_contiguous_bytes = PAGE_SIZE - page_offset;
+ scan_index = page_index + 1;
+ expected_phys = (u64)virt_to_phys(aux_buf->pages[page_index]) + PAGE_SIZE;
+
+ while (scan_index < aux_buf->nr_pages && max_contiguous_bytes < chunk_size) {
+ actual_phys = (u64)virt_to_phys(aux_buf->pages[scan_index]);
+
+ if (actual_phys != expected_phys)
+ break; /* Intersected a fragmentation boundary block link! */
+
+ max_contiguous_bytes += PAGE_SIZE;
+ expected_phys += PAGE_SIZE;
+ scan_index++;
+ }
+
+ /* Bound transfer length tightly within the validated contiguous window */
+ if (chunk_size > max_contiguous_bytes)
+ chunk_size = max_contiguous_bytes;
+
+ if (!chunk_size) {
+ aux_buf->collect_htm_trace = 0;
+ perf_aux_output_end(&htm_ctx->handle, 0);
+ return 0;
+ }
+
+ /*
+ * Compute the precise base target address using
+ * localized page offset rules
+ */
+ target_page_virt = aux_buf->pages[page_index];
+ hypervisor_target_phys = (u64)virt_to_phys(target_page_virt) + page_offset;
+
+ do {
+ /*
+ * Invoke H_HTM call with:
+ * - operation as htm dump (H_HTM_OP_DUMP_DATA)
+ * - last three values are address, size and offset
+ */
+ rc = htm_hcall_wrapper(htmflags, cfg.nodeindex, cfg.nodalchipindex,
+ cfg.coreindexonchip, cfg.htmtype, H_HTM_OP_DUMP_DATA,
+ hypervisor_target_phys, chunk_size, aux_buf->head);
+ ret = htm_return_check(rc);
+ } while (ret == -EBUSY && ++retries < MAX_RETRIES);
+
+ if (ret > 0) {
+ aux_buf->head += chunk_size;
+ aux_buf->trace_records++;
+ perf_aux_output_end(&htm_ctx->handle, chunk_size);
+ return ret;
+ }
+
+ aux_buf->collect_htm_trace = 0;
+ perf_aux_output_end(&htm_ctx->handle, 0);
+ return ret;
+}
+
static void htm_event_read(struct perf_event *event)
{
+ int ret;
+
+ /*
+ * Update event->count as a binary indicator:
+ * 1 if data was dumped into the
+ * AUX buffer, 0 otherwise. Actual trace record
+ * decoding is left to userspace.
+ */
+ ret = htm_dump_sample_data(event);
+ if (ret <= 0)
+ local64_set(&event->count, 0);
+ else
+ local64_set(&event->count, 1);
+}
+
+/*
+ * Set up pmu-private data structures for an AUX area
+ * **pages contains the aux buffer allocated for this event
+ * for the corresponding cpu. rb_alloc_aux uses "alloc_pages_node"
+ * and returns pointer to each page address.
+ * PMU capabilities: PERF_PMU_CAP_AUX_NO_SG | PERF_PMU_CAP_AUX_PREFER_LARGE
+ * to try get closest possible physically contiguous page blocks.
+ *
+ * The aux private data structure ie, "struct htm_pmu_buf" mainly
+ * saves
+ * - buf->base: aux buffer base address
+ * - buf->head: offset from base address where data will be written to.
+ * - buf->size: Size of allocated memory
+ */
+static void *htm_setup_aux(struct perf_event *event, void **pages,
+ int nr_pages, bool snapshot)
+{
+ int cpu = event->cpu;
+ struct htm_pmu_buf *buf;
+
+ if (!nr_pages)
+ return NULL;
+
+ if (cpu == -1)
+ cpu = raw_smp_processor_id();
+
+ buf = kzalloc_node(sizeof(*buf), GFP_KERNEL, cpu_to_node(cpu));
+ if (!buf)
+ return NULL;
+
+ buf->nr_pages = nr_pages;
+ buf->snapshot = snapshot;
+ buf->size = (u64)nr_pages << PAGE_SHIFT;
+ buf->pages = pages;
+
+ buf->base = pages[0];
+ if (!buf->base) {
+ kfree(buf);
+ return NULL;
+ }
+
+ buf->collect_htm_trace = 1;
+ buf->trace_records = 0;
+ buf->head = 0;
+ return buf;
+}
+
+/*
+ * free pmu-private AUX data structures
+ */
+static void htm_free_aux(void *aux)
+{
+ struct htm_pmu_buf *buf = aux;
+
+ if (!buf)
+ return;
+
+ kfree(buf);
}
static struct pmu htm_pmu = {
@@ -386,7 +597,10 @@ static struct pmu htm_pmu = {
.read = htm_event_read,
.start = htm_event_start,
.stop = htm_event_stop,
- .capabilities = PERF_PMU_CAP_NO_EXCLUDE | PERF_PMU_CAP_EXCLUSIVE,
+ .setup_aux = htm_setup_aux,
+ .free_aux = htm_free_aux,
+ .capabilities = PERF_PMU_CAP_NO_EXCLUDE | PERF_PMU_CAP_EXCLUSIVE
+ | PERF_PMU_CAP_AUX_NO_SG | PERF_PMU_CAP_AUX_PREFER_LARGE,
};
static int htm_init(void)
--
2.43.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH V2 4/6] powerpc/perf: Capture the HTM memory configuration as part of perf data
2026-07-20 10:44 [PATCH V2 0/6] powerpc/perf: Add HTM PMU driver and perf AUX support Athira Rajeev
` (2 preceding siblings ...)
2026-07-20 10:44 ` [PATCH V2 3/6] powerpc/perf: Add AUX buffer management to capture HTM trace data Athira Rajeev
@ 2026-07-20 10:44 ` Athira Rajeev
2026-07-20 11:09 ` sashiko-bot
2026-07-20 10:44 ` [PATCH V2 5/6] docs: ABI: sysfs-bus-event_source-devices-htm: Document sysfs event format entries for htm pmu Athira Rajeev
2026-07-20 10:44 ` [PATCH V2 6/6] powerpc/perf/htm: Add documentation for Hardware Trace Macro PMU Athira Rajeev
5 siblings, 1 reply; 13+ messages in thread
From: Athira Rajeev @ 2026-07-20 10:44 UTC (permalink / raw)
To: linuxppc-dev, maddy
Cc: linux-perf-users, atrajeev, hbathini, tejas05, venkat88, tshah,
usha.r2
The H_HTM hypervisor call can also return the system memory
configuration, which describes the physical to logical real address
mapping for logical partitions.
After dumping HTM trace data into the AUX buffer, capture the
corresponding HTM system memory configuration records and emit them as
raw perf sample data for userspace parsing.
Add AUX-private tracking for a hypervisor memory-configuration dump
buffer, a stable emit buffer, and iterator state. Once AUX trace dumping
completes, htm_event_read() switches to H_HTM_OP_DUMP_SYSMEM_CONF and
iterates over the returned records until the configuration stream is
exhausted.
Trace payload continues to be written to the AUX buffer, while memory
configuration records are emitted as raw perf samples. This keeps the
AUX stream focused on trace data and allows the configuration records to
be decoded separately in userspace.
Keep HTM tracing state in event->pmu_private via htm_target_id. AUX
private state is used only for dump progress and staging buffers.
Signed-off-by: Athira Rajeev <atrajeev@linux.ibm.com>
---
Changes in V2:
- Memory configuration records are now emitted as PERF_SAMPLE_RAW
samples directly by htm_event_read() after the AUX trace dump
completes, using H_HTM_OP_DUMP_SYSMEM_CONF. V1 embedded the
configuration data inside the AUX buffer itself and used two
PERF_SAMPLE_RAW boundary markers (start/end) to delimit it.
- The two-marker boundary scheme is removed. There is no longer any
interleaving of memory configuration data inside the AUX stream;
the AUX buffer carries only bus-trace data.
- Separate AUX-private fields for a hypervisor dump buffer, a stable
emit buffer, and iterator state are introduced to manage the
multi-call SYSMEM_CONF dump loop.
- Tracing state remains in event->pmu_private (htm_target_id); AUX
private state is used only for dump progress and staging buffers,
consistent with the restructuring in patches 1 and 3.
arch/powerpc/perf/htm-perf.c | 124 ++++++++++++++++++++++++++++++++++-
1 file changed, 123 insertions(+), 1 deletion(-)
diff --git a/arch/powerpc/perf/htm-perf.c b/arch/powerpc/perf/htm-perf.c
index edfca63e1e9b..7e6a67485800 100644
--- a/arch/powerpc/perf/htm-perf.c
+++ b/arch/powerpc/perf/htm-perf.c
@@ -104,6 +104,10 @@ struct htm_pmu_buf {
u64 size;
int collect_htm_trace;
u64 trace_records;
+ void *htm_mem_buf; /* Staging bounce area allocated node-locally */
+ void *emit_buf; /* Stable buffer for perf raw sample emission */
+ u64 mem_start; /* Hypervisor offset state iterator tracker */
+ int collect_htm_mem; /* State flag tracking whether memory logging is ongoing */
};
struct htm_pmu_ctx {
@@ -173,6 +177,99 @@ static ssize_t htm_return_check(int rc)
#define HTM_TRACING_ACTIVE 1
#define HTM_TRACING_INACTIVE 0
+#define HTM_MEM_MAX_ENTRIES 2013U
+#define HTM_MEM_BUF_SIZE (32 + HTM_MEM_MAX_ENTRIES * 32)
+
+static int htm_collect_memory_config(struct perf_event *event,
+ struct htm_pmu_buf *aux_buf)
+{
+ struct perf_sample_data data;
+ struct perf_raw_record raw;
+ struct pt_regs regs;
+ u8 *htm_mem_buf = aux_buf->htm_mem_buf;
+ __be64 *num_entries;
+ u64 next_start;
+ u64 to_copy;
+ void *emit_buf = aux_buf->emit_buf;
+ long rc;
+ int ret = 0;
+ int retries;
+ int emitted = 0;
+
+ /*
+ * htm_mem_buf is the hcall memory buffer target reused each iteration.
+ * emit_buf is a preallocated stable buffer used for perf raw
+ * sample emission, so raw.frag.data remains valid during
+ * perf_event_overflow().
+ * Size: 32-byte header + HTM_MEM_MAX_ENTRIES * 32-byte entries.
+ */
+ while (true) {
+ retries = 0;
+ do {
+ rc = htm_hcall_wrapper(htmflags, 0, 0, 0,
+ 0, H_HTM_OP_DUMP_SYSMEM_CONF,
+ virt_to_phys(aux_buf->htm_mem_buf),
+ HTM_MEM_BUF_SIZE, aux_buf->mem_start);
+ ret = htm_return_check(rc);
+ } while (ret == -EBUSY && ++retries < MAX_RETRIES);
+
+ /* H_NOT_AVAILABLE or error: no more data */
+ if (ret <= 0) {
+ aux_buf->collect_htm_mem = 0;
+ break;
+ }
+
+ /*
+ * Read next iterator value from the hcall response BEFORE
+ * emitting, but only commit it to mem_start after a
+ * successful writing of raw data/
+ */
+ next_start = be64_to_cpu(*((__be64 *)(htm_mem_buf + 0x8)));
+
+ /*
+ * The hcall was given HTM_MEM_BUF_SIZE bytes of buffer space,
+ * so num_entries is already bounded to HTM_MEM_MAX_ENTRIES.
+ * The response is a complete hcall data:
+ * [32-byte header][num_entries * 32-byte entries]
+ * Userspace can validate and parse it directly.
+ */
+ num_entries = (__be64 *)(htm_mem_buf + 0x10);
+ to_copy = 32 + (be64_to_cpu(*num_entries) * 32);
+ if (WARN_ON_ONCE(to_copy > HTM_MEM_BUF_SIZE)) {
+ ret = -EIO;
+ aux_buf->collect_htm_mem = 0;
+ break;
+ }
+
+ memcpy(emit_buf, aux_buf->htm_mem_buf, to_copy);
+
+ perf_sample_data_init(&data, 0, event->hw.last_period);
+ memset(&raw, 0, sizeof(raw));
+ raw.frag.data = emit_buf;
+ raw.frag.size = to_copy;
+ perf_sample_save_raw_data(&data, event, &raw);
+
+ if (perf_event_overflow(event, &data, ®s)) {
+ ret = 0;
+ break;
+ }
+
+ /* Record written: advance next read iterator */
+ aux_buf->mem_start = next_start;
+ emitted = 1;
+
+ if (!next_start) {
+ aux_buf->collect_htm_mem = 0;
+ break;
+ }
+ }
+
+ if (emitted)
+ return 1;
+
+ return ret;
+}
+
static void reset_htm_active(struct perf_event *event)
{
struct htm_target_id *target = event->pmu_private;
@@ -407,7 +504,7 @@ static int htm_dump_sample_data(struct perf_event *event)
if (!aux_buf)
return 0;
- if (!aux_buf->collect_htm_trace) {
+ if (!aux_buf->collect_htm_trace && !aux_buf->collect_htm_mem) {
perf_aux_output_end(&htm_ctx->handle, 0);
return 0;
}
@@ -420,6 +517,11 @@ static int htm_dump_sample_data(struct perf_event *event)
}
}
+ if (!aux_buf->collect_htm_trace) {
+ ret = htm_collect_memory_config(event, aux_buf);
+ goto out;
+ }
+
/* Derive the exact target destination point directly out of active ring pointers */
dump_offset = htm_ctx->handle.head & (aux_buf->size - 1);
page_index = dump_offset >> PAGE_SHIFT;
@@ -506,6 +608,8 @@ static int htm_dump_sample_data(struct perf_event *event)
}
aux_buf->collect_htm_trace = 0;
+ ret = htm_collect_memory_config(event, aux_buf);
+out:
perf_aux_output_end(&htm_ctx->handle, 0);
return ret;
}
@@ -568,7 +672,23 @@ static void *htm_setup_aux(struct perf_event *event, void **pages,
return NULL;
}
+ buf->htm_mem_buf = kmalloc_node(PAGE_SIZE, GFP_KERNEL, cpu_to_node(cpu));
+ if (!buf->htm_mem_buf) {
+ kfree(buf);
+ return NULL;
+ }
+
+ buf->emit_buf = kmalloc_node(HTM_MEM_BUF_SIZE, GFP_KERNEL,
+ cpu_to_node(cpu));
+ if (!buf->emit_buf) {
+ kfree(buf->htm_mem_buf);
+ kfree(buf);
+ return NULL;
+ }
+
buf->collect_htm_trace = 1;
+ buf->collect_htm_mem = 1;
+ buf->mem_start = 0;
buf->trace_records = 0;
buf->head = 0;
return buf;
@@ -584,6 +704,8 @@ static void htm_free_aux(void *aux)
if (!buf)
return;
+ kfree(buf->emit_buf);
+ kfree(buf->htm_mem_buf);
kfree(buf);
}
--
2.43.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH V2 5/6] docs: ABI: sysfs-bus-event_source-devices-htm: Document sysfs event format entries for htm pmu
2026-07-20 10:44 [PATCH V2 0/6] powerpc/perf: Add HTM PMU driver and perf AUX support Athira Rajeev
` (3 preceding siblings ...)
2026-07-20 10:44 ` [PATCH V2 4/6] powerpc/perf: Capture the HTM memory configuration as part of perf data Athira Rajeev
@ 2026-07-20 10:44 ` Athira Rajeev
2026-07-20 11:13 ` sashiko-bot
2026-07-20 10:44 ` [PATCH V2 6/6] powerpc/perf/htm: Add documentation for Hardware Trace Macro PMU Athira Rajeev
5 siblings, 1 reply; 13+ messages in thread
From: Athira Rajeev @ 2026-07-20 10:44 UTC (permalink / raw)
To: linuxppc-dev, maddy
Cc: linux-perf-users, atrajeev, hbathini, tejas05, venkat88, tshah,
usha.r2
Add ABI documentation for the sysfs entries exposed by the "htm" PMU
under /sys/bus/event_source/devices/htm/.
Document the format attribute group, which describes the bit layout of
perf_event_attr.config accepted by the htm PMU:
htm_type config bits 0-3 (HTM_CORE=2, HTM_NEST=1)
nodeindex config bits 4-11
nodalchipindex config bits 12-19
coreindexonchip config bits 20-27
Document the events attribute group, which lists the named events
available on the PMU. Users can pass these names directly to perf:
# perf record -e htm/nodalchipindex=2,nodeindex=0,htm_type=1/ ...
Signed-off-by: Athira Rajeev <atrajeev@linux.ibm.com>
---
Changes in V2:
- Updated the bit-range descriptions to match the V2 config layout:
htm_type is bits 0-3 (was listed inconsistently in V1), nodeindex
is bits 4-11, nodalchipindex is bits 12-19, coreindexonchip is
bits 20-27.
- Added documentation for the events/ sysfs group which lists named
events users can pass directly to perf (e.g.
htm/nodalchipindex=2,nodeindex=0,htm_type=1/). This group was not
documented in V1.
- Patch is now 5/6 instead of 4/5.
.../sysfs-bus-event_source-devices-htm | 21 +++++++++++++++++++
1 file changed, 21 insertions(+)
create mode 100644 Documentation/ABI/testing/sysfs-bus-event_source-devices-htm
diff --git a/Documentation/ABI/testing/sysfs-bus-event_source-devices-htm b/Documentation/ABI/testing/sysfs-bus-event_source-devices-htm
new file mode 100644
index 000000000000..784ba7c31b89
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-bus-event_source-devices-htm
@@ -0,0 +1,21 @@
+What: /sys/bus/event_source/devices/htm/format
+Date: June 2026
+Contact: Linux on PowerPC Developer List <linuxppc-dev at lists.ozlabs.org>
+Description: Read-only. Attribute group to describe the magic bits
+ that go into perf_event_attr.config for a particular pmu.
+ (See ABI/testing/sysfs-bus-event_source-devices-format).
+
+ Each attribute under this group defines a bit range of the
+ perf_event_attr.config. Supported attribute are listed
+ below::
+
+ event = "config:0-27" - event ID
+
+What: /sys/bus/event_source/devices/htm/events
+Date: June 2026
+Contact: Linux on PowerPC Developer List <linuxppc-dev at lists.ozlabs.org>
+Description: (RO) Attribute group to describe performance monitoring events
+ for the Hardware Trace Macro (HTM) trace. Each attribute in
+ this group describes a single performance monitoring event
+ supported by htm pmu. The name of the file is the name of
+ the event (See ABI/testing/sysfs-bus-event_source-devices-events).
--
2.43.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH V2 6/6] powerpc/perf/htm: Add documentation for Hardware Trace Macro PMU
2026-07-20 10:44 [PATCH V2 0/6] powerpc/perf: Add HTM PMU driver and perf AUX support Athira Rajeev
` (4 preceding siblings ...)
2026-07-20 10:44 ` [PATCH V2 5/6] docs: ABI: sysfs-bus-event_source-devices-htm: Document sysfs event format entries for htm pmu Athira Rajeev
@ 2026-07-20 10:44 ` Athira Rajeev
2026-07-20 11:17 ` sashiko-bot
5 siblings, 1 reply; 13+ messages in thread
From: Athira Rajeev @ 2026-07-20 10:44 UTC (permalink / raw)
To: linuxppc-dev, maddy
Cc: linux-perf-users, atrajeev, hbathini, tejas05, venkat88, tshah,
usha.r2
Extend Documentation/arch/powerpc/htm.rst with a new section covering
the HTM perf PMU interface.
The added documentation covers:
- How to open HTM events using perf record, including the event
syntax (nodalchipindex, nodeindex, htm_type, cpu=N) and the
required AUX buffer size (-m,256).
- The two output files produced by perf report:
htm.bin.nX.pX.cX raw bus-trace AUX data
translation.nX.pX.cX memory-configuration records
- How to pass the output files to htmdecode for trace decoding.
- Notes on system-wide collection (-a) vs CPU-pinned collection
(-C N) and the one-event-per-target PMU restriction.
The existing debugfs interface documentation is retained unchanged.
A brief cross-reference is added at the top to point readers to the
new perf interface section.
Signed-off-by: Athira Rajeev <atrajeev@linux.ibm.com>
---
Changes in V2:
- Updated the usage with more examples
- Patch is now 6/6 instead of 5/5.
Documentation/arch/powerpc/htm.rst | 137 ++++++++++++++++++++++++++++-
1 file changed, 134 insertions(+), 3 deletions(-)
diff --git a/Documentation/arch/powerpc/htm.rst b/Documentation/arch/powerpc/htm.rst
index fcb4eb6306b1..d574fd2225ea 100644
--- a/Documentation/arch/powerpc/htm.rst
+++ b/Documentation/arch/powerpc/htm.rst
@@ -18,9 +18,10 @@ H_HTM is used as an interface for executing Hardware Trace Macro (HTM)
functions, including setup, configuration, control and dumping of the HTM data.
For using HTM, it is required to setup HTM buffers and HTM operations can
be controlled using the H_HTM hcall. The hcall can be invoked for any core/chip
-of the system from within a partition itself. To use this feature, a debugfs
-folder called "htmdump" is present under /sys/kernel/debug/powerpc.
+of the system from within a partition itself.
+To use this feature, a debugfs folder called "htmdump" is present under
+/sys/kernel/debug/powerpc. Another interface is via perf.
HTM debugfs example usage
=========================
@@ -94,7 +95,137 @@ This trace file will contain the relevant instruction traces
collected during the workload execution. And can be used as
input file for trace decoders to understand data.
-Benefits of using HTM debugfs interface
+HTM perf interface usage
+========================
+
+The HTM (Hardware Trace Macro) perf interface enables collection and analysis
+of hardware trace data from PowerPC systems. This interface allows users to
+capture detailed execution traces for performance analysis and debugging.
+
+Event Configuration
+-------------------
+
+Use ``perf record`` with the htm PMU event. The event is configured using
+named parameters that specify the target hardware location and trace type:
+
+.. list-table::
+ :header-rows: 1
+ :widths: 25 75
+
+ * - Parameter
+ - Description
+ * - htm_type
+ - Type of HTM trace to collect (bits 0-3)
+ * - nodeindex
+ - Node index in the system topology (bits 4-11)
+ * - nodalchipindex
+ - Chip index within the specified node (bits 12-19)
+ * - coreindexonchip
+ - Core index on the specified chip (bits 20-27)
+
+- event: "config:0-27"
+- htm_type: "config:0-3"
+- nodeindex: "config:4-11"
+- nodalchipindex: "config:12-19"
+- coreindexonchip: "config:20-27"
+
+1) nodeindex, nodalchipindex, coreindexonchip: this specifies
+ which partition to configure the HTM for.
+2) htmtype: specifies the type of HTM.
+
+Event Syntax
+------------
+
+The event configuration uses named parameters::
+
+ htm/nodeindex=N,nodalchipindex=C,coreindexonchip=R,htm_type=T/
+
+To open the event on a specific cpu can be specified using::
+
+ htm/nodeindex=N,nodalchipindex=C,coreindexonchip=R,htm_type=T,cpu=x/
+
+Where:
+
+- N = node index
+- C = chip index within the node
+- R = core index on the chip
+- T = HTM type
+- x = CPU number
+
+Basic Usage Example
+-------------------
+
+To collect HTM trace data for a specific chip:
+
+.. code-block:: sh
+
+ # perf record -C 1 -e htm/nodalchipindex=2,nodeindex=0,htm_type=1/ <workload>
+
+In this example:
+
+- ``-C 1``: Collect on CPU 1
+- ``nodeindex=0``: Target node 0
+- ``nodalchipindex=2``: Target chip 2 within node 0
+- ``htm_type=1``: HTM trace type 1
+
+.. code-block:: sh
+
+ # perf record -m,256 -e htm/coreindexonchip=6,nodalchipindex=0,nodeindex=0,htm_type=2,cpu=16/ -a sleep 1
+
+In this example:
+
+- ``cpu=16``: Collect on CPU 16
+- ``nodeindex=0``: Target node 0
+- ``nodalchipindex=0``: Target chip 0 within node 0
+- ``coreindexonchip=6``: Target code 6
+- ``htm_type=2``: HTM trace type 2
+- ``-m,256``: specifies number of mmap pages
+
+Running trace collection for multiple targets:
+
+.. code-block:: sh
+
+ # perf record -m,256 -e htm/nodalchipindex=2,nodeindex=0,htm_type=1,cpu=8/ -e htm/nodalchipindex=1,nodeindex=0,htm_type=1,cpu=9/ -a sleep 1
+
+
+In this example, trace is collected for two events on different target chips
+
+Output Files
+------------
+
+After running ``perf record``, the following files are generated:
+
+.. code-block:: sh
+
+ # ls htm.bin.*
+ htm.bin.n0.p2.c0 htm.bin.n1.p3.c0 # Binary trace files
+
+ # ls translation.*
+ translation.n0.p2.c0 translation.n1.p3.c0 # Memory configuration files
+
+These files contain:
+
+- **htm.bin.*** - Raw HTM trace data in binary format
+- **translation.*** - Memory address translation information for decoding
+
+Complete Workflow Example
+--------------------------
+
+Here's a complete example of collecting and analyzing HTM traces:
+
+.. code-block:: sh
+
+ # Step 1: Collect trace data
+ perf record -C 1 -e htm/nodalchipindex=2,nodeindex=0,htm_type=1/ sleep 5
+
+ # Step 2: Verify output files
+ perf report -D
+
+ ls htm.bin.* # Binary trace files
+ ls translation.* # Memory configuration files
+ ls perf.data # Perf data file
+
+Benefits of using HTM interface
=======================================
It is now possible to collect traces for a particular core/chip
--
2.43.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [PATCH V2 2/6] powerpc/perf: Reject duplicate HTM target reservations
2026-07-20 10:44 ` [PATCH V2 2/6] powerpc/perf: Reject duplicate HTM target reservations Athira Rajeev
@ 2026-07-20 10:55 ` sashiko-bot
0 siblings, 0 replies; 13+ messages in thread
From: sashiko-bot @ 2026-07-20 10:55 UTC (permalink / raw)
To: Athira Rajeev; +Cc: linux-perf-users
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] Rejecting duplicate HTM target reservations with `-EBUSY` breaks `perf record -a`.
--
--- Patch [2]: [PATCH V2 2/6] powerpc/perf: Reject duplicate HTM target reservations ---
commit ab5064c1a585bcfce6e8560bc79aa814badd08ff
Author: Athira Rajeev <atrajeev@linux.ibm.com>
powerpc/perf: Reject duplicate HTM target reservations
This commit tracks reserved HTM targets globally to prevent concurrent
event initialization races. It rejects duplicate reservations for the same
target in htm_event_init() by returning -EBUSY.
> diff --git a/arch/powerpc/perf/htm-perf.c b/arch/powerpc/perf/htm-perf.c
> index 5d3aa9c7fd8d1..a188a40287044 100644
> --- a/arch/powerpc/perf/htm-perf.c
> +++ b/arch/powerpc/perf/htm-perf.c
[ ... ]
> @@ -188,11 +203,30 @@ static int htm_event_init(struct perf_event *event)
> }
>
> /* Allocate per-event private state; freed via event->destroy */
> - event->pmu_private = kzalloc(sizeof(struct htm_target_id), GFP_KERNEL);
> - if (!event->pmu_private)
> + target = kzalloc(sizeof(*target), GFP_KERNEL);
> + if (!target)
> return -ENOMEM;
>
> - ((struct htm_target_id *)event->pmu_private)->cfg = cfg;
> + target->cfg = cfg;
> + target->tracing_active = HTM_TRACING_INACTIVE;
> + INIT_LIST_HEAD(&target->list);
> +
> + mutex_lock(&htm_targets_lock);
> + list_for_each_entry(tmp, &htm_active_targets_list, list) {
> + if (tmp->cfg.htmtype == cfg.htmtype &&
> + tmp->cfg.nodeindex == cfg.nodeindex &&
> + tmp->cfg.nodalchipindex == cfg.nodalchipindex &&
> + tmp->cfg.coreindexonchip == cfg.coreindexonchip) {
> + mutex_unlock(&htm_targets_lock);
> + kfree(target);
> + return -EBUSY;
[Severity: High]
Does returning -EBUSY here break "perf record -a" for this PMU?
Since the commit message notes that a cpumask was deliberately omitted,
the perf tool will attempt to open the event on every online CPU sequentially
when running "perf record -a". The first open (e.g., for CPU 0) will succeed,
but the very next open (for CPU 1) will hit this path and return -EBUSY.
Because the perf tool treats -EBUSY as a fatal error, won't this abort the
entire profiling session instead of just skipping the duplicate target?
> + }
> + }
> +
> + list_add_tail(&target->list, &htm_active_targets_list);
> + mutex_unlock(&htm_targets_lock);
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260720104447.11843-1-atrajeev@linux.ibm.com?part=2
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH V2 1/6] powerpc/perf: Add HTM PMU driver to expose Hardware Trace Macro data
2026-07-20 10:44 ` [PATCH V2 1/6] powerpc/perf: Add HTM PMU driver to expose Hardware Trace Macro data Athira Rajeev
@ 2026-07-20 11:00 ` sashiko-bot
0 siblings, 0 replies; 13+ messages in thread
From: sashiko-bot @ 2026-07-20 11:00 UTC (permalink / raw)
To: Athira Rajeev; +Cc: linux-perf-users
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] Hardware Resource Leak on H_LONG_BUSY_* in Teardown Paths
- [High] Missing Global Target Collision Detection
- [High] Hypervisor HCALL Flooding via Misunderstood pmu->add Semantics
--
--- Patch [1]: [PATCH V2 1/6] powerpc/perf: Add HTM PMU driver to expose Hardware Trace Macro data ---
commit 5f73062ed0507987b187b59e32b4100e6330618a
Author: Athira Rajeev <atrajeev@linux.ibm.com>
powerpc/perf: Add HTM PMU driver to expose Hardware Trace Macro data
The H_HTM hypervisor call (hcall) provides an interface to the Hardware
Trace Macro (HTM) function on POWER systems. HTM captures hardware-level
trace data for a specific node/chip/core target within a logical partition.
> diff --git a/arch/powerpc/perf/htm-perf.c b/arch/powerpc/perf/htm-perf.c
> new file mode 100644
> index 0000000000000..5d3aa9c7fd8d1
> --- /dev/null
> +++ b/arch/powerpc/perf/htm-perf.c
[ ... ]
> +static ssize_t htm_return_check(int rc)
> +{
> + switch (rc) {
> + case H_SUCCESS:
> + case H_PARTIAL:
> + return 1;
> + case H_NOT_AVAILABLE:
> + return 0;
> + case H_BUSY:
> + /* Transient busy: retry loop will spin up to MAX_RETRIES */
> + return -EBUSY;
> + case H_LONG_BUSY_ORDER_1_MSEC:
> + case H_LONG_BUSY_ORDER_10_MSEC:
> + case H_LONG_BUSY_ORDER_100_MSEC:
> + case H_LONG_BUSY_ORDER_1_SEC:
> + case H_LONG_BUSY_ORDER_10_SEC:
> + case H_LONG_BUSY_ORDER_100_SEC:
> + /*
> + * Hypervisor requests a long delay before retry (1ms-100s).
> + * Spinning in a kernel retry loop for this duration risks
> + * deadlocks in atomic contexts. Return -EAGAIN so callers
> + * exit immediately; the operation will fail and userspace
> + * can retry the perf_event_open() call.
> + * Note: all retry loops check ret == -EBUSY only, so
> + * -EAGAIN exits without retrying, this is intentional.
> + */
> + return -EAGAIN;
[Severity: High]
The comment mentions that returning -EAGAIN will cause the perf_event_open()
call to fail so userspace can retry. Is this accurate for paths called
during event scheduling?
When htm_return_check() is called from htm_event_add(), -EAGAIN is returned
to the perf core's pmu->add() caller (event_sched_in). The perf core treats
-EAGAIN from pmu->add as a transient scheduling failure and will repeatedly
attempt to schedule the event on subsequent timer ticks or context switches.
Will this flood the hypervisor with H_HTM_OP_CONFIGURE hcalls exactly when
it is requesting a long backoff delay?
[ ... ]
> +static int htm_event_init(struct perf_event *event)
> +{
> + u64 config = event->attr.config;
> + struct htm_config cfg;
> +
> + if (event->attr.inherit)
> + return -EOPNOTSUPP;
[ ... ]
> + parse_htm_config(config, &cfg);
> + switch (cfg.htmtype) {
> + case HTM_CORE:
> + case HTM_NEST:
> + break;
> + default:
> + return -EINVAL;
> + }
> +
> + /* Allocate per-event private state; freed via event->destroy */
> + event->pmu_private = kzalloc(sizeof(struct htm_target_id), GFP_KERNEL);
> + if (!event->pmu_private)
> + return -ENOMEM;
[Severity: High]
Does this missing global target collision detection allow hardware state
corruption?
The driver sets PERF_PMU_CAP_EXCLUSIVE, but the perf core only enforces this
within the same per-CPU context. If two users concurrently create events for
the exact same HTM hardware resource (identical node/chip/core) on different
CPUs, they would bypass that check.
Without a global registry of active targets here in htm_event_init(), could
conflicting hcalls be issued to the identical hardware resource, clobbering
the hypervisor configuration?
[ ... ]
> +static void htm_event_stop(struct perf_event *event, int flags)
> +{
> + int rc, ret, retries = 0;
> + struct htm_config cfg;
> + struct htm_target_id *target = event->pmu_private;
> +
> + /*
> + * Ignore context-switch-out stops. The perf core passes
> + * PERF_EF_UPDATE on context-switch-out. Do not stop the hcall.
> + */
> + if (flags & PERF_EF_UPDATE)
> + return;
> +
> + /* Not tracing, nothing to stop */
> + if (target->tracing_active == HTM_TRACING_INACTIVE)
> + return;
> +
> + cfg = target->cfg;
> +
> + /* Only retry on transient H_BUSY; H_LONG_BUSY_* (-EAGAIN) exits immediately */
> + do {
> + rc = htm_hcall_wrapper(htmflags, cfg.nodeindex, cfg.nodalchipindex,
> + cfg.coreindexonchip, cfg.htmtype,
> + H_HTM_OP_STOP, 0, 0, 0);
> + ret = htm_return_check(rc);
> + } while (ret == -EBUSY && ++retries < MAX_RETRIES);
[Severity: High]
If the hypervisor returns H_LONG_BUSY_* (which maps to -EAGAIN), the loop
exits immediately. Since htm_event_stop() returns void, it cannot defer
the cleanup or notify the perf core. Does this permanently leave the trace
started in the hypervisor?
[ ... ]
> +static int htm_event_add(struct perf_event *event, int flags)
> +{
[ ... ]
> + /*
> + * Start tracing via the .start callback so the standard
> + * PERF_EF_START / ioctl(ENABLE) path is honoured.
> + */
> + if (flags & PERF_EF_START) {
> + htm_event_start(event, 0); /* flags=0: not a context switch */
> + if (target->tracing_active == HTM_TRACING_INACTIVE) {
> + /* Start failed, deconfigure to avoid resource leak */
> + retries = 0;
> + do {
> + rc = htm_hcall_wrapper(htmflags, cfg.nodeindex,
> + cfg.nodalchipindex, cfg.coreindexonchip,
> + cfg.htmtype, H_HTM_OP_DECONFIGURE, 0, 0, 0);
> + ret = htm_return_check(rc);
> + } while (ret == -EBUSY && ++retries < MAX_RETRIES);
> + return -EIO;
> + }
> + }
> +
> + return 0;
> +}
[Severity: High]
Similar to htm_event_stop(), if H_HTM_OP_DECONFIGURE returns a long busy
status here in the error rollback path, the retry loop exits immediately
and returns -EIO. Does this leak the configured hypervisor resource?
> +
> +static void htm_event_del(struct perf_event *event, int flags)
> +{
> + int rc, ret, retries = 0;
> + struct htm_target_id *target = event->pmu_private;
> + struct htm_config cfg = target->cfg;
> +
> + /* Stop tracing, flags=0 so htm_event_stop issues the hcall */
> + htm_event_stop(event, 0);
> +
> + /* Deconfigure */
> + do {
> + rc = htm_hcall_wrapper(htmflags, cfg.nodeindex, cfg.nodalchipindex,
> + cfg.coreindexonchip, cfg.htmtype,
> + H_HTM_OP_DECONFIGURE, 0, 0, 0);
> + ret = htm_return_check(rc);
> + } while (ret == -EBUSY && ++retries < MAX_RETRIES);
[Severity: High]
If this loop exits on -EAGAIN, the resource is silently abandoned without
deferring cleanup. The kernel will then free event->pmu_private during
event->destroy. Could this result in a permanent leak of shared hypervisor
HTM resources, potentially leading to a denial of service for hardware
tracing?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260720104447.11843-1-atrajeev@linux.ibm.com?part=1
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH V2 4/6] powerpc/perf: Capture the HTM memory configuration as part of perf data
2026-07-20 10:44 ` [PATCH V2 4/6] powerpc/perf: Capture the HTM memory configuration as part of perf data Athira Rajeev
@ 2026-07-20 11:09 ` sashiko-bot
0 siblings, 0 replies; 13+ messages in thread
From: sashiko-bot @ 2026-07-20 11:09 UTC (permalink / raw)
To: Athira Rajeev; +Cc: linux-perf-users
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [Critical] The staging buffer `htm_mem_buf` is allocated as `PAGE_SIZE` but the hypervisor is instructed to write up to `HTM_MEM_BUF_SIZE` (64448 bytes) into it, causing a physical memory overflow on 4K page configurations.
- [High] Uninitialized `struct pt_regs regs` allocated on the stack is passed directly to `perf_event_overflow()`, leading to a kernel stack memory leak.
- [Medium] The memory configuration iterator `mem_start` is not advanced when `perf_event_overflow` returns a non-zero (throttled) value, causing data duplication.
--
--- Patch [4]: [PATCH V2 4/6] powerpc/perf: Capture the HTM memory configuration as part of perf data ---
commit 5929e601ef9335650c92ad97d9999f8482e8f648
Author: Athira Rajeev <atrajeev@linux.ibm.com>
powerpc/perf: Capture the HTM memory configuration as part of perf data
This commit captures HTM system memory configuration during tracing by
retrieving it via a hypercall. The records are emitted as raw perf sample
data after the AUX trace dump completes.
> diff --git a/arch/powerpc/perf/htm-perf.c b/arch/powerpc/perf/htm-perf.c
> index b4020a6e8f30b..0fda0f552b4e1 100644
> --- a/arch/powerpc/perf/htm-perf.c
> +++ b/arch/powerpc/perf/htm-perf.c
[ ... ]
> @@ -173,6 +177,99 @@ static ssize_t htm_return_check(int rc)
> #define HTM_TRACING_ACTIVE 1
> #define HTM_TRACING_INACTIVE 0
>
> +#define HTM_MEM_MAX_ENTRIES 2013U
> +#define HTM_MEM_BUF_SIZE (32 + HTM_MEM_MAX_ENTRIES * 32)
> +
> +static int htm_collect_memory_config(struct perf_event *event,
> + struct htm_pmu_buf *aux_buf)
> +{
> + struct perf_sample_data data;
> + struct perf_raw_record raw;
> + struct pt_regs regs;
^^^^^^^^^^^^^^^^^^^^
[Severity: High]
Does this leak kernel stack memory to userspace?
The regs struct is allocated on the stack but never zeroed or initialized.
If userspace configures the perf event with PERF_SAMPLE_REGS_INTR or
PERF_SAMPLE_CALLCHAIN, the core perf framework will read these
uninitialized bytes in perf_event_overflow() and write them to the ring
buffer.
Should regs be initialized, for example via perf_fetch_caller_regs(®s)
or memset(®s, 0, sizeof(regs))?
> + u8 *htm_mem_buf = aux_buf->htm_mem_buf;
> + __be64 *num_entries;
> + u64 next_start;
> + u64 to_copy;
[ ... ]
> + memcpy(emit_buf, aux_buf->htm_mem_buf, to_copy);
> +
> + perf_sample_data_init(&data, 0, event->hw.last_period);
> + memset(&raw, 0, sizeof(raw));
> + raw.frag.data = emit_buf;
> + raw.frag.size = to_copy;
> + perf_sample_save_raw_data(&data, event, &raw);
> +
> + if (perf_event_overflow(event, &data, ®s)) {
> + ret = 0;
> + break;
> + }
^^^^^
[Severity: Medium]
If perf_event_overflow() throttles the event and returns a non-zero value,
we break out of the loop before advancing the iterator.
When tracing resumes and htm_collect_memory_config() is called again,
it will start with the stale aux_buf->mem_start value and repeatedly ask
the hypervisor for the same configuration block. Will this emit duplicate
records into the perf stream?
> +
> + /* Record written: advance next read iterator */
> + aux_buf->mem_start = next_start;
> + emitted = 1;
> +
> + if (!next_start) {
> + aux_buf->collect_htm_mem = 0;
> + break;
> + }
> + }
[ ... ]
> @@ -568,7 +672,23 @@ static void *htm_setup_aux(struct perf_event *event, void **pages,
> return NULL;
> }
>
> + buf->htm_mem_buf = kmalloc_node(PAGE_SIZE, GFP_KERNEL, cpu_to_node(cpu));
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
[Severity: Critical]
Can this corrupt physical memory on systems with 4K pages?
buf->htm_mem_buf is allocated using PAGE_SIZE, which is 4096 bytes if
CONFIG_PPC_4K_PAGES is enabled.
However, in htm_collect_memory_config(), the hypervisor is instructed that
the buffer length is HTM_MEM_BUF_SIZE:
arch/powerpc/perf/htm-perf.c:htm_collect_memory_config() {
...
rc = htm_hcall_wrapper(htmflags, 0, 0, 0,
0, H_HTM_OP_DUMP_SYSMEM_CONF,
virt_to_phys(aux_buf->htm_mem_buf),
HTM_MEM_BUF_SIZE, aux_buf->mem_start);
...
}
Since HTM_MEM_BUF_SIZE is defined as 32 + 2013 * 32 = 64448, the hypervisor
will assume it can write 64448 bytes, silently overwriting up to ~60KB of
contiguous physical kernel memory past the 4KB allocation.
Should this allocate HTM_MEM_BUF_SIZE bytes instead of PAGE_SIZE?
> + if (!buf->htm_mem_buf) {
> + kfree(buf);
> + return NULL;
> + }
> +
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260720104447.11843-1-atrajeev@linux.ibm.com?part=4
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH V2 3/6] powerpc/perf: Add AUX buffer management to capture HTM trace data
2026-07-20 10:44 ` [PATCH V2 3/6] powerpc/perf: Add AUX buffer management to capture HTM trace data Athira Rajeev
@ 2026-07-20 11:10 ` sashiko-bot
0 siblings, 0 replies; 13+ messages in thread
From: sashiko-bot @ 2026-07-20 11:10 UTC (permalink / raw)
To: Athira Rajeev; +Cc: linux-perf-users
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] Reentrancy corruption of the per-CPU perf_output_handle leads to Use-After-Free.
- [High] Transient conditions permanently disable trace collection and falsely signal EOF.
--
--- Patch [3]: [PATCH V2 3/6] powerpc/perf: Add AUX buffer management to capture HTM trace data ---
commit edd04ff363591ec700b1e3d07e1003b1787ccb4a
Author: Athira Rajeev <atrajeev@linux.ibm.com>
powerpc/perf: Add AUX buffer management to capture HTM trace data
This commit adds support for auxiliary (AUX) ring buffers in the HTM PMU
driver. It implements the core lifecycle hooks and dynamically checks for
physical continuity before dumping data to prevent memory corruption.
> diff --git a/arch/powerpc/perf/htm-perf.c b/arch/powerpc/perf/htm-perf.c
> index a188a40287044..b4020a6e8f30b 100644
> --- a/arch/powerpc/perf/htm-perf.c
> +++ b/arch/powerpc/perf/htm-perf.c
[ ... ]
> +struct htm_pmu_ctx {
> + struct perf_output_handle handle;
> +};
> +
> +static DEFINE_PER_CPU(struct htm_pmu_ctx, htm_pmu_ctx);
> +
[ ... ]
> +static int htm_dump_sample_data(struct perf_event *event)
> +{
> + struct htm_pmu_ctx *htm_ctx = this_cpu_ptr(&htm_pmu_ctx);
[ ... ]
> + /* Start AUX transaction session framework */
> + aux_buf = perf_aux_output_begin(&htm_ctx->handle, event);
[Severity: High]
What happens to the perf_output_handle if this is re-entered from an NMI
context?
htm_event_read() initiates a synchronous AUX output transaction using a
per-CPU struct perf_output_handle. Since this can be called from process
context (for instance, userspace reading the perf event fd), an NMI
interrupting this could trigger a BPF program that calls
bpf_perf_event_read() on the same CPU.
Would this overwrite the per-CPU handle, causing the interrupted outer
call to use a corrupted handle when it resumes, leading to underflowing
reference counts and a use-after-free of the AUX pages? Could the
handle be allocated on the stack instead to prevent this?
> + if (!aux_buf)
> + return 0;
[ ... ]
> + /*
> + * Assess constraints regarding space remaining across the mapping
> + * context boundary
> + */
> + chunk_size = htm_ctx->handle.size;
> + chunk_size &= PAGE_MASK;
> +
> + if (chunk_size > (aux_buf->size - dump_offset))
> + chunk_size = aux_buf->size - dump_offset;
[ ... ]
> + /* Bound transfer length tightly within the validated contiguous window */
> + if (chunk_size > max_contiguous_bytes)
> + chunk_size = max_contiguous_bytes;
> +
> + if (!chunk_size) {
> + aux_buf->collect_htm_trace = 0;
[Severity: High]
Does this permanently disable trace collection during a transient buffer full
condition?
If the remaining space in the user-space perf ring buffer is temporarily
less than PAGE_SIZE, chunk_size will evaluate to 0. This sets
collect_htm_trace to 0, which prevents any future trace collection for the
lifetime of the buffer.
> + perf_aux_output_end(&htm_ctx->handle, 0);
> + return 0;
> + }
> +
[ ... ]
> + do {
> + /*
> + * Invoke H_HTM call with:
> + * - operation as htm dump (H_HTM_OP_DUMP_DATA)
> + * - last three values are address, size and offset
> + */
> + rc = htm_hcall_wrapper(htmflags, cfg.nodeindex, cfg.nodalchipindex,
> + cfg.coreindexonchip, cfg.htmtype, H_HTM_OP_DUMP_DATA,
> + hypervisor_target_phys, chunk_size, aux_buf->head);
> + ret = htm_return_check(rc);
> + } while (ret == -EBUSY && ++retries < MAX_RETRIES);
> +
> + if (ret > 0) {
> + aux_buf->head += chunk_size;
> + aux_buf->trace_records++;
> + perf_aux_output_end(&htm_ctx->handle, chunk_size);
> + return ret;
> + }
> +
> + aux_buf->collect_htm_trace = 0;
[Severity: High]
If the hypervisor returns a transient long-busy status (like
H_LONG_BUSY_ORDER_1_MSEC), htm_return_check() returns -EAGAIN.
Will the loop exit and fall through to this block, permanently disabling
tracing for this buffer session?
> + perf_aux_output_end(&htm_ctx->handle, 0);
> + return ret;
> +}
> +
> +static void htm_event_read(struct perf_event *event)
> +{
> + int ret;
> +
> + /*
> + * Update event->count as a binary indicator:
> + * 1 if data was dumped into the
> + * AUX buffer, 0 otherwise. Actual trace record
> + * decoding is left to userspace.
> + */
> + ret = htm_dump_sample_data(event);
> + if (ret <= 0)
> + local64_set(&event->count, 0);
[Severity: High]
Since the transient buffer full condition or hypervisor busy state causes
htm_dump_sample_data() to return 0 or -EAGAIN, does this falsely signal
an EOF to userspace by setting event->count to 0?
> + else
> + local64_set(&event->count, 1);
> +}
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260720104447.11843-1-atrajeev@linux.ibm.com?part=3
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH V2 5/6] docs: ABI: sysfs-bus-event_source-devices-htm: Document sysfs event format entries for htm pmu
2026-07-20 10:44 ` [PATCH V2 5/6] docs: ABI: sysfs-bus-event_source-devices-htm: Document sysfs event format entries for htm pmu Athira Rajeev
@ 2026-07-20 11:13 ` sashiko-bot
0 siblings, 0 replies; 13+ messages in thread
From: sashiko-bot @ 2026-07-20 11:13 UTC (permalink / raw)
To: Athira Rajeev; +Cc: linux-perf-users
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [Medium] The format attributes documented in the ABI file do not match the V2 layout claimed in the commit message.
- [Medium] The commit message provides a fundamentally flawed example for using the 'events' attribute group, conflating it with the 'format' group.
- [Low] Minor grammatical error in the description text.
--
--- Patch [5]: [PATCH V2 5/6] docs: ABI: sysfs-bus-event_source-devices-htm: Document sysfs event format entries for htm pmu ---
commit 9ec8c4a8a34dc7a4a75859018f086bb71432aa4a
Author: Athira Rajeev <atrajeev@linux.ibm.com>
docs: ABI: sysfs-bus-event_source-devices-htm: Document sysfs event format entries for htm pmu
This commit adds ABI documentation for the sysfs entries exposed by the
HTM PMU under /sys/bus/event_source/devices/htm/. It documents the format
attribute group and the events attribute group.
> Document the events attribute group, which lists the named events
> available on the PMU. Users can pass these names directly to perf:
>
> # perf record -e htm/nodalchipindex=2,nodeindex=0,htm_type=1/ ...
[Severity: Medium]
Does this example conflate the 'events' attribute group with the 'format'
group? The example provided uses format attribute fields (key-value pairs),
whereas the 'events' directory is supposed to provide named aliases.
> diff --git a/Documentation/ABI/testing/sysfs-bus-event_source-devices-htm b/Documentation/ABI/testing/sysfs-bus-event_source-devices-htm
> new file mode 100644
> index 0000000000000..784ba7c31b89b
> --- /dev/null
> +++ b/Documentation/ABI/testing/sysfs-bus-event_source-devices-htm
> @@ -0,0 +1,21 @@
> +What: /sys/bus/event_source/devices/htm/format
> +Date: June 2026
> +Contact: Linux on PowerPC Developer List <linuxppc-dev at lists.ozlabs.org>
> +Description: Read-only. Attribute group to describe the magic bits
> + that go into perf_event_attr.config for a particular pmu.
> + (See ABI/testing/sysfs-bus-event_source-devices-format).
> +
> + Each attribute under this group defines a bit range of the
> + perf_event_attr.config. Supported attribute are listed
^^^^^^^^^
[Severity: Low]
This isn't a bug, but there is a grammatical error here ("attribute are"
instead of "attributes are").
> + below::
> +
> + event = "config:0-27" - event ID
[Severity: Medium]
Is the documentation missing the format attributes claimed in the commit
message?
The commit message explicitly states that htm_type, nodeindex,
nodalchipindex, and coreindexonchip were added for the V2 layout, but only
the generic 'event' attribute is listed here.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260720104447.11843-1-atrajeev@linux.ibm.com?part=5
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH V2 6/6] powerpc/perf/htm: Add documentation for Hardware Trace Macro PMU
2026-07-20 10:44 ` [PATCH V2 6/6] powerpc/perf/htm: Add documentation for Hardware Trace Macro PMU Athira Rajeev
@ 2026-07-20 11:17 ` sashiko-bot
0 siblings, 0 replies; 13+ messages in thread
From: sashiko-bot @ 2026-07-20 11:17 UTC (permalink / raw)
To: Athira Rajeev; +Cc: linux-perf-users
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [Medium] The documentation states that `perf record` or `perf report -D` generates specific binary output files (`htm.bin.*` and `translation.*`), but this functionality does not exist in the upstream `tools/perf` codebase.
- [Medium] The commit message claims to document `htmdecode` usage and notes on PMU restrictions, but these sections are entirely missing from the documentation text.
- [Low] There are several grammatical errors, typos, and inconsistencies in the newly added documentation text.
--
--- Patch [6]: [PATCH V2 6/6] powerpc/perf/htm: Add documentation for Hardware Trace Macro PMU ---
commit 630c94afa3c07b9d61db47792f5a5e0b40edd107
Author: Athira Rajeev <atrajeev@linux.ibm.com>
powerpc/perf/htm: Add documentation for Hardware Trace Macro PMU
This commit extends the HTM documentation with a new section covering the
perf PMU interface. It describes event configuration, syntax, basic usage
examples, and expected output files.
> The added documentation covers:
>
> - How to open HTM events using perf record, including the event
> syntax (nodalchipindex, nodeindex, htm_type, cpu=N) and the
> required AUX buffer size (-m,256).
>
> - The two output files produced by perf report:
> htm.bin.nX.pX.cX raw bus-trace AUX data
> translation.nX.pX.cX memory-configuration records
>
> - How to pass the output files to htmdecode for trace decoding.
>
> - Notes on system-wide collection (-a) vs CPU-pinned collection
> (-C N) and the one-event-per-target PMU restriction.
[Severity: Medium]
The commit message claims to document htmdecode usage, as well as notes on
system-wide vs CPU-pinned collection and PMU restrictions, but these sections
appear to be missing entirely from the added documentation text. Did these get
dropped during patch iteration?
> diff --git a/Documentation/arch/powerpc/htm.rst b/Documentation/arch/powerpc/htm.rst
> index fcb4eb6306b16..d574fd2225ea5 100644
> --- a/Documentation/arch/powerpc/htm.rst
> +++ b/Documentation/arch/powerpc/htm.rst
[ ... ]
> @@ -94,7 +95,137 @@ This trace file will contain the relevant instruction traces
> collected during the workload execution. And can be used as
> input file for trace decoders to understand data.
>
> -Benefits of using HTM debugfs interface
> +HTM perf interface usage
> +========================
[ ... ]
> +- event: "config:0-27"
> +- htm_type: "config:0-3"
> +- nodeindex: "config:4-11"
> +- nodalchipindex: "config:12-19"
> +- coreindexonchip: "config:20-27"
> +
> +1) nodeindex, nodalchipindex, coreindexonchip: this specifies
> + which partition to configure the HTM for.
> +2) htmtype: specifies the type of HTM.
[Severity: Low]
This isn't a bug, but should this say htm_type instead of htmtype to match
the parameter list above?
> +
> +Event Syntax
> +------------
> +
> +The event configuration uses named parameters::
> +
> + htm/nodeindex=N,nodalchipindex=C,coreindexonchip=R,htm_type=T/
> +
> +To open the event on a specific cpu can be specified using::
[Severity: Low]
This isn't a bug, but there is a grammatical error here. Could this be updated
to something like "Opening the event on a specific CPU can be specified
using::"?
> +
> + htm/nodeindex=N,nodalchipindex=C,coreindexonchip=R,htm_type=T,cpu=x/
> +
> +Where:
> +
> +- N = node index
> +- C = chip index within the node
> +- R = core index on the chip
> +- T = HTM type
> +- x = CPU number
> +
> +Basic Usage Example
> +-------------------
> +
> +To collect HTM trace data for a specific chip:
> +
> +.. code-block:: sh
> +
> + # perf record -C 1 -e htm/nodalchipindex=2,nodeindex=0,htm_type=1/ <workload>
> +
> +In this example:
> +
> +- ``-C 1``: Collect on CPU 1
> +- ``nodeindex=0``: Target node 0
> +- ``nodalchipindex=2``: Target chip 2 within node 0
> +- ``htm_type=1``: HTM trace type 1
> +
> +.. code-block:: sh
> +
> + # perf record -m,256 -e htm/coreindexonchip=6,nodalchipindex=0,nodeindex=0,htm_type=2,cpu=16/ -a sleep 1
> +
> +In this example:
> +
> +- ``cpu=16``: Collect on CPU 16
> +- ``nodeindex=0``: Target node 0
> +- ``nodalchipindex=0``: Target chip 0 within node 0
> +- ``coreindexonchip=6``: Target code 6
[Severity: Low]
This isn't a bug, but there's a typo here. Should "Target code" be
"Target core"?
> +- ``htm_type=2``: HTM trace type 2
> +- ``-m,256``: specifies number of mmap pages
> +
> +Running trace collection for multiple targets:
> +
> +.. code-block:: sh
> +
> + # perf record -m,256 -e htm/nodalchipindex=2,nodeindex=0,htm_type=1,cpu=8/ -e htm/nodalchipindex=1,nodeindex=0,htm_type=1,cpu=9/ -a sleep 1
> +
> +
> +In this example, trace is collected for two events on different target chips
> +
> +Output Files
> +------------
> +
> +After running ``perf record``, the following files are generated:
> +
> +.. code-block:: sh
> +
> + # ls htm.bin.*
> + htm.bin.n0.p2.c0 htm.bin.n1.p3.c0 # Binary trace files
> +
> + # ls translation.*
> + translation.n0.p2.c0 translation.n1.p3.c0 # Memory configuration files
> +
> +These files contain:
> +
> +- **htm.bin.*** - Raw HTM trace data in binary format
> +- **translation.*** - Memory address translation information for decoding
> +
> +Complete Workflow Example
> +--------------------------
> +
> +Here's a complete example of collecting and analyzing HTM traces:
> +
> +.. code-block:: sh
> +
> + # Step 1: Collect trace data
> + perf record -C 1 -e htm/nodalchipindex=2,nodeindex=0,htm_type=1/ sleep 5
> +
> + # Step 2: Verify output files
> + perf report -D
> +
> + ls htm.bin.* # Binary trace files
> + ls translation.* # Memory configuration files
[Severity: Medium]
Does perf report -D natively generate these specific binary output files
(htm.bin.* and translation.*) in the upstream tools/perf codebase?
This documentation seems to describe a non-existent feature in upstream
tools/perf and might rely on out-of-tree tooling that was not included in
this patch series. Should this be updated to reflect only supported features?
> + ls perf.data # Perf data file
> +
> +Benefits of using HTM interface
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260720104447.11843-1-atrajeev@linux.ibm.com?part=6
^ permalink raw reply [flat|nested] 13+ messages in thread
end of thread, other threads:[~2026-07-20 11:17 UTC | newest]
Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-20 10:44 [PATCH V2 0/6] powerpc/perf: Add HTM PMU driver and perf AUX support Athira Rajeev
2026-07-20 10:44 ` [PATCH V2 1/6] powerpc/perf: Add HTM PMU driver to expose Hardware Trace Macro data Athira Rajeev
2026-07-20 11:00 ` sashiko-bot
2026-07-20 10:44 ` [PATCH V2 2/6] powerpc/perf: Reject duplicate HTM target reservations Athira Rajeev
2026-07-20 10:55 ` sashiko-bot
2026-07-20 10:44 ` [PATCH V2 3/6] powerpc/perf: Add AUX buffer management to capture HTM trace data Athira Rajeev
2026-07-20 11:10 ` sashiko-bot
2026-07-20 10:44 ` [PATCH V2 4/6] powerpc/perf: Capture the HTM memory configuration as part of perf data Athira Rajeev
2026-07-20 11:09 ` sashiko-bot
2026-07-20 10:44 ` [PATCH V2 5/6] docs: ABI: sysfs-bus-event_source-devices-htm: Document sysfs event format entries for htm pmu Athira Rajeev
2026-07-20 11:13 ` sashiko-bot
2026-07-20 10:44 ` [PATCH V2 6/6] powerpc/perf/htm: Add documentation for Hardware Trace Macro PMU Athira Rajeev
2026-07-20 11:17 ` sashiko-bot
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox