LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 3/5] powerpc/perf: Capture the HTM memory configuration as part of perf data
From: Athira Rajeev @ 2026-07-01  8:38 UTC (permalink / raw)
  To: linuxppc-dev, maddy
  Cc: linux-perf-users, atrajeev, hbathini, tejas05, venkat88, tshah
In-Reply-To: <20260701083806.79358-1-atrajeev@linux.ibm.com>

H_HTM (Hardware Trace Macro) hypervisor call has capability
to capture SystemMemory Configuration for a system. This
information helps to understand the physical to logical real
address mapping for the logical partitions in the system.

Along with saving HTM trace data, add support to capture
the memory mapping information also using the hcall.
Patch adds support in perf driver to expose HTM memory
configuration as part of perf.data

When monitoring the HTM pmu, auxiliary buffer captures
the "trace" data and SystemMemory Configuration. This
will be post processed later using perf. The size of memory
mapping data captured depends on how large is the system
and how much memory is allocated. To help with relating
and identifying the start of memory mapping data in the
auxiliary buffer, insert two PERF_SAMPLE_RAW records in the
ring buffer. First PERF_SAMPLE_RAW record will mark the
beginning of system memory mapping data in aux buffer. And second
PERF_SAMPLE_RAW record will be written at the end to make the
end of the data in aux buffer and also contains the total size
of the memory map data. These sample raw records
will be used during post processing in perf report.

Use sample raw to mark memory mapping in aux buffer.

Signed-off-by: Athira Rajeev <atrajeev@linux.ibm.com>
---
 arch/powerpc/perf/htm-perf.c | 110 ++++++++++++++++++++++++++++++++++-
 1 file changed, 108 insertions(+), 2 deletions(-)

diff --git a/arch/powerpc/perf/htm-perf.c b/arch/powerpc/perf/htm-perf.c
index ae7f469b6840..fe458bc3ec05 100644
--- a/arch/powerpc/perf/htm-perf.c
+++ b/arch/powerpc/perf/htm-perf.c
@@ -76,6 +76,10 @@ struct htm_pmu_buf {
 	bool    full;
 	int	htm_stopped;
 	int	collect_htm_trace;
+	u64	mem_head;
+	void	*htm_mem_buf;
+	u64	mem_start;
+	int	collect_htm_mem;
 };
 
 struct htm_pmu_ctx {
@@ -143,6 +147,86 @@ static ssize_t htm_return_check(int rc)
 	return -EINVAL;
 }
 
+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;
+	u64 *num_entries;
+	u64 to_copy = 0;
+	int htm_val;
+	long rc;
+	int ret;
+	int retries = 0;
+	size_t size;
+	size_t space_to_end = aux_buf->size - aux_buf->mem_head;
+
+	/* Capture HTM system memory configuration in aux buffer */
+	do {
+		rc = htm_hcall_wrapper(htmflags, 0, 0, 0,
+				0, H_HTM_OP_DUMP_SYSMEM_CONF, virt_to_phys(aux_buf->htm_mem_buf),
+				PAGE_SIZE, aux_buf->mem_start);
+		ret = htm_return_check(rc);
+	} while (ret == -EBUSY && ++retries < 100);
+
+	/* Return once there is no more data in HTM buffer */
+	if (ret <= 0) {
+		perf_sample_data_init(&data, 0, event->hw.last_period);
+		memset(&raw, 0, sizeof(raw));
+		memset(&regs, 0, sizeof(regs));
+
+		htm_val = (aux_buf->head/((aux_buf->nr_pages * PAGE_SIZE)));
+		raw.frag.data = &htm_val;
+		raw.frag.size = sizeof(htm_val);
+
+		aux_buf->collect_htm_mem = 0;
+		perf_sample_save_raw_data(&data, event, &raw);
+		perf_event_overflow(event, &data, &regs);
+		return 0;
+	}
+
+	/*
+	 * Find how much data to copy to aux buffer
+	 * If hcall returned H_PARTIAL, set mem_start to
+	 * indicate next offset of memory to read from
+	 */
+	num_entries = aux_buf->htm_mem_buf + 0x10;
+	aux_buf->mem_start = be64_to_cpu(*(u64 *)(aux_buf->htm_mem_buf + 0x8));
+
+	to_copy = 32 + (be64_to_cpu(*num_entries) * 32);
+
+	if (to_copy <= space_to_end) {
+		if ((to_copy + aux_buf->mem_head) >= ((aux_buf->nr_pages * PAGE_SIZE)/2)) {
+			/*
+			 * Crossing 50% threshold - flush and wrap.
+			 * Write current chunk, then pad to end of buffer.
+			 * This ensures next write starts at beginning with
+			 * perf head also at beginning (synchronized).
+			 */
+			memcpy(aux_buf->base + aux_buf->mem_head, aux_buf->htm_mem_buf, to_copy);
+			aux_buf->mem_head = 0;
+
+			/*
+			 * Return space_to_end to include padding.
+			 * Perf will advance head to end (wrapping to 0),
+			 * matching our mem_head position.
+			 */
+			size = space_to_end;
+		} else {
+			/* Normal case - chunk fits without crossing threshold */
+			memcpy(aux_buf->base + aux_buf->mem_head, aux_buf->htm_mem_buf, to_copy);
+			aux_buf->mem_head += to_copy;
+			size = to_copy;
+		}
+	} else {
+		return 0;
+	}
+
+	/* Return non-zero to indicate that one record is written to aux buffer */
+	return size;
+}
+
 static int htm_dump_sample_data(struct perf_event *event)
 {
 	struct htm_pmu_ctx *htm_ctx = this_cpu_ptr(&htm_pmu_ctx);
@@ -162,7 +246,7 @@ static int htm_dump_sample_data(struct perf_event *event)
 	if (!aux_buf)
 		return -1;
 
-	if (!aux_buf->collect_htm_trace) {
+	if (!aux_buf->collect_htm_mem && !aux_buf->collect_htm_trace) {
 		perf_aux_output_end(&htm_ctx->handle, 0);
 		return 0;
 	}
@@ -202,12 +286,17 @@ static int htm_dump_sample_data(struct perf_event *event)
 		if (ret > 0) {
 			aux_buf->head += (aux_buf->nr_pages * PAGE_SIZE);
 			perf_aux_output_end(&htm_ctx->handle, (aux_buf->nr_pages * PAGE_SIZE));
+			return ret;
 		} else {
 			aux_buf->collect_htm_trace = 0;
-			perf_aux_output_end(&htm_ctx->handle, 0);
 		}
 	}
 
+	if (aux_buf->collect_htm_mem) {
+		ret = htm_collect_memory_config(event, aux_buf);
+		perf_aux_output_end(&htm_ctx->handle, ret);
+	}
+
 	return ret;
 }
 
@@ -397,6 +486,13 @@ 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);
+		pr_err("Failed to allocate htm mem buf\n");
+		return NULL;
+	}
+
 	buf->nr_pages = nr_pages;
 	buf->snapshot = false;
 	buf->size = nr_pages << PAGE_SHIFT;
@@ -404,6 +500,9 @@ static void *htm_setup_aux(struct perf_event *event, void **pages,
 	buf->head_size = 0;
 	buf->htm_stopped = 0;
 	buf->collect_htm_trace = 1;
+	buf->mem_head = 0;
+	buf->collect_htm_mem = 1;
+	buf->mem_start = 0;
 	return buf;
 }
 
@@ -413,10 +512,17 @@ static void *htm_setup_aux(struct perf_event *event, void **pages,
 static void htm_free_aux(void *aux)
 {
 	struct htm_pmu_buf *buf = aux;
+	void *free_mem;
 
 	if (!buf)
 		return;
 
+	free_mem = buf->htm_mem_buf;
+	buf->htm_mem_buf = NULL;
+
+	smp_mb();
+
+	kfree(free_mem);
 	kfree(buf);
 }
 
-- 
2.52.0



^ permalink raw reply related

* [PATCH 4/5] docs: ABI: sysfs-bus-event_source-devices-htm: Document sysfs event format entries for htm pmu
From: Athira Rajeev @ 2026-07-01  8:38 UTC (permalink / raw)
  To: linuxppc-dev, maddy
  Cc: linux-perf-users, atrajeev, hbathini, tejas05, venkat88, tshah
In-Reply-To: <20260701083806.79358-1-atrajeev@linux.ibm.com>

Details are added for the htm pmu event and format
attributes in the ABI documentation.

Signed-off-by: Athira Rajeev <atrajeev@linux.ibm.com>
---
 .../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.52.0



^ permalink raw reply related

* [PATCH 5/5] powerpc/perf/htm: Add documentation for Hardware Trace Macro PMU
From: Athira Rajeev @ 2026-07-01  8:38 UTC (permalink / raw)
  To: linuxppc-dev, maddy
  Cc: linux-perf-users, atrajeev, hbathini, tejas05, venkat88, tshah
In-Reply-To: <20260701083806.79358-1-atrajeev@linux.ibm.com>

Documentation for htm (Hardware Trace Macro - HTM)
PMU interface. And how it can be used to collect the HTM traces
entries in perf data, how to process/report as part of perf report/perf
script.

Signed-off-by: Athira Rajeev <atrajeev@linux.ibm.com>
---
 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..f9dceffb93c6 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/
+
+Where:
+
+- N = node index
+- C = chip index within the node
+- R = core index on the chip
+- T = HTM type
+
+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
+
+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
+
+Trace Data Processing
+---------------------
+
+Process the collected trace data using perf script:
+
+.. code-block:: sh
+
+   # perf script -D
+
+This command:
+
+1. Reads the perf.data file
+2. Decodes HTM trace data using translation files
+3. Displays human-readable trace output
+4. Shows instruction addresses and execution flow
+
+The decoder automatically:
+
+- Translates physical addresses to logical addresses
+- Creates decoded output files for analysis
+- Correlates trace data with memory mappings
+
+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
+   ls htm.bin.*        # Binary trace files
+   ls translation.*    # Memory configuration files
+   ls perf.data        # Perf data file
+
+   # Step 3: Decode and view traces
+   perf script -D > decoded_trace.txt
+
+   # Step 4: Analyze with perf report to see the hot logical address
+   perf report
+
+
+Benefits of using HTM interface
 =======================================
 
 It is now possible to collect traces for a particular core/chip
-- 
2.52.0



^ permalink raw reply related

* Re: [PATCH v2 1/9] time: Respect COMPAT_32BIT_TIME for old time type functions
From: Thomas Weißschuh @ 2026-07-01  8:40 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Andy Lutomirski, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
	Dave Hansen, x86, H. Peter Anvin, Russell King, Catalin Marinas,
	Will Deacon, Madhavan Srinivasan, Michael Ellerman,
	Nicholas Piggin, Christophe Leroy, Thomas Bogendoerfer,
	Vincenzo Frascino, John Stultz, Stephen Boyd, David S . Miller,
	Andreas Larsson, linux-kernel, linux-arm-kernel, linuxppc-dev,
	linux-mips, linux-api, sparclinux
In-Reply-To: <0cda7366-2eb9-4ecb-b76a-b3b68ee10043@app.fastmail.com>

On Tue, Jun 30, 2026 at 03:00:37PM +0200, Arnd Bergmann wrote:
> On Tue, Jun 30, 2026, at 09:38, Thomas Weißschuh wrote:
> > The "old" time types use 32-bit seconds which are not y2038-safe.
> > Respect COMPAT_32BIT_TIME for functions using those types.
> > time(), stime() and gettimeofday() are disabled completely.
> 
> Looks good, yes

Sashiko found an issue [0], which I think is valid. I'll change that for v3.

> > settimeofday() is kept as it is required to do the initial timewarping
> > after boot. However the 'tv' argument will be rejected.
> 
> Not sure about this part, did we already discuss this last time?

This is my interpretation of [1].

> I can see how keeping the timewarping functionality is the easy way
> out, but completely disabling the settimeofday syscall the same
> way we do on new architectures seems so much more consistent.

Shouldn't we then do this completely? Irrespective of COMPAT_32BIT_TIME?
And then remove all of the timewarping and kernel timezone bits.

It would be nice however if this series, and my other ones blocked behind it,
are not blocked on that larger rework.

(...)

[0] https://sashiko.dev/#/patchset/20260630-vdso-compat_32bit_time-v2-0-520d194640dd%40linutronix.de?part=1
[1] https://lore.kernel.org/all/e9487ebe-3730-438a-9c23-e45f75986ecc@app.fastmail.com/


Thomas


^ permalink raw reply

* [PATCH 1/9] tool/perf: Move auxtrace_record__init for powerpc-vpadtl as separate utility
From: Athira Rajeev @ 2026-07-01  8:41 UTC (permalink / raw)
  To: acme, jolsa, adrian.hunter, maddy, irogers, namhyung
  Cc: linux-perf-users, linuxppc-dev, atrajeev, hbathini, tejas05,
	tshah, venkat88
In-Reply-To: <20260701084115.80383-1-atrajeev@linux.ibm.com>

The powerpc PMU collecting Dispatch Trace Log (DTL) entries makes use of
AUX support in perf infrastructure. To enable the creation of
PERF_RECORD_AUXTRACE, auxtrace_record__init() to initialize auxtrace
record is part of arch/powerpc/util/auxtrace.c

To enable other PMU's to use auxtrace, move the auxtrace_record__init
for powerpc-vpadtl to another file: arch/powerpc/util/vpa-dtl.c
In auxtrace_record__init, based on pmu used, call vpa_dtl_recording_init
to initialize recording options for DTL

Signed-off-by: Athira Rajeev <atrajeev@linux.ibm.com>
---
 tools/perf/arch/powerpc/util/Build      |  1 +
 tools/perf/arch/powerpc/util/auxtrace.c | 79 ++------------------
 tools/perf/arch/powerpc/util/vpa-dtl.c  | 96 +++++++++++++++++++++++++
 tools/perf/util/powerpc-vpadtl.h        |  1 +
 4 files changed, 104 insertions(+), 73 deletions(-)
 create mode 100644 tools/perf/arch/powerpc/util/vpa-dtl.c

diff --git a/tools/perf/arch/powerpc/util/Build b/tools/perf/arch/powerpc/util/Build
index ae928050e07a..7819c8f5af2d 100644
--- a/tools/perf/arch/powerpc/util/Build
+++ b/tools/perf/arch/powerpc/util/Build
@@ -7,3 +7,4 @@ perf-util-y += evsel.o
 perf-util-$(CONFIG_LIBDW) += skip-callchain-idx.o
 
 perf-util-y += auxtrace.o
+perf-util-y += vpa-dtl.o
diff --git a/tools/perf/arch/powerpc/util/auxtrace.c b/tools/perf/arch/powerpc/util/auxtrace.c
index 4600a1661b4f..0053526329e0 100644
--- a/tools/perf/arch/powerpc/util/auxtrace.c
+++ b/tools/perf/arch/powerpc/util/auxtrace.c
@@ -13,63 +13,12 @@
 #include "../../util/auxtrace.h"
 #include "../../util/powerpc-vpadtl.h"
 #include "../../util/record.h"
-#include <internal/lib.h> // page_size
-
-#define KiB(x) ((x) * 1024)
-
-static int
-powerpc_vpadtl_recording_options(struct auxtrace_record *ar __maybe_unused,
-			struct evlist *evlist __maybe_unused,
-			struct record_opts *opts)
-{
-	opts->full_auxtrace = true;
-
-	/*
-	 * Set auxtrace_mmap_pages to minimum
-	 * two pages
-	 */
-	if (!opts->auxtrace_mmap_pages) {
-		opts->auxtrace_mmap_pages = KiB(128) / page_size;
-		if (opts->mmap_pages == UINT_MAX)
-			opts->mmap_pages = KiB(256) / page_size;
-	}
-
-	return 0;
-}
-
-static size_t powerpc_vpadtl_info_priv_size(struct auxtrace_record *itr __maybe_unused,
-					struct evlist *evlist __maybe_unused)
-{
-	return VPADTL_AUXTRACE_PRIV_SIZE;
-}
-
-static int
-powerpc_vpadtl_info_fill(struct auxtrace_record *itr __maybe_unused,
-		struct perf_session *session __maybe_unused,
-		struct perf_record_auxtrace_info *auxtrace_info,
-		size_t priv_size __maybe_unused)
-{
-	auxtrace_info->type = PERF_AUXTRACE_VPA_DTL;
-
-	return 0;
-}
-
-static void powerpc_vpadtl_free(struct auxtrace_record *itr)
-{
-	free(itr);
-}
-
-static u64 powerpc_vpadtl_reference(struct auxtrace_record *itr __maybe_unused)
-{
-	return 0;
-}
 
 struct auxtrace_record *auxtrace_record__init(struct evlist *evlist,
 						int *err)
 {
-	struct auxtrace_record *aux;
 	struct evsel *pos;
-	int found = 0;
+	int found_vpa_dtl = 0;
 
 	/*
 	 * Set err value to zero here. Any fail later
@@ -79,32 +28,16 @@ struct auxtrace_record *auxtrace_record__init(struct evlist *evlist,
 
 	evlist__for_each_entry(evlist, pos) {
 		if (strstarts(pos->name, "vpa_dtl")) {
-			found = 1;
+			found_vpa_dtl = 1;
 			pos->needs_auxtrace_mmap = true;
 			break;
 		}
 	}
 
-	if (!found)
-		return NULL;
-
-	/*
-	 * To obtain the auxtrace buffer file descriptor, the auxtrace event
-	 * must come first.
-	 */
-	evlist__to_front(pos->evlist, pos);
-
-	aux = zalloc(sizeof(*aux));
-	if (aux == NULL) {
-		pr_debug("aux record is NULL\n");
-		*err = -ENOMEM;
+	if (found_vpa_dtl)
+		return vpa_dtl_recording_init(pos);
+	else {
+		*err = -EINVAL;
 		return NULL;
 	}
-
-	aux->recording_options = powerpc_vpadtl_recording_options;
-	aux->info_priv_size = powerpc_vpadtl_info_priv_size;
-	aux->info_fill = powerpc_vpadtl_info_fill;
-	aux->free = powerpc_vpadtl_free;
-	aux->reference = powerpc_vpadtl_reference;
-	return aux;
 }
diff --git a/tools/perf/arch/powerpc/util/vpa-dtl.c b/tools/perf/arch/powerpc/util/vpa-dtl.c
new file mode 100644
index 000000000000..ae81cbad0c38
--- /dev/null
+++ b/tools/perf/arch/powerpc/util/vpa-dtl.c
@@ -0,0 +1,96 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * VPA support
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/bitops.h>
+#include <linux/log2.h>
+#include <linux/string.h>
+#include <time.h>
+
+#include "../../util/cpumap.h"
+#include "../../util/evsel.h"
+#include "../../util/evlist.h"
+#include "../../util/session.h"
+#include "../../util/util.h"
+#include "../../util/pmu.h"
+#include "../../util/debug.h"
+#include "../../util/auxtrace.h"
+#include "../../util/powerpc-vpadtl.h"
+#include "../../util/record.h"
+#include <internal/lib.h> // page_size
+
+#define KiB(x) ((x) * 1024)
+
+static int
+powerpc_vpadtl_recording_options(struct auxtrace_record *ar __maybe_unused,
+			struct evlist *evlist __maybe_unused,
+			struct record_opts *opts)
+{
+	opts->full_auxtrace = true;
+
+	/*
+	 * Set auxtrace_mmap_pages to minimum
+	 * two pages
+	 */
+	if (!opts->auxtrace_mmap_pages) {
+		opts->auxtrace_mmap_pages = KiB(128) / page_size;
+		if (opts->mmap_pages == UINT_MAX)
+			opts->mmap_pages = KiB(256) / page_size;
+	}
+
+	return 0;
+}
+
+static size_t powerpc_vpadtl_info_priv_size(struct auxtrace_record *itr __maybe_unused,
+					struct evlist *evlist __maybe_unused)
+{
+	return VPADTL_AUXTRACE_PRIV_SIZE;
+}
+
+static int
+powerpc_vpadtl_info_fill(struct auxtrace_record *itr __maybe_unused,
+		struct perf_session *session __maybe_unused,
+		struct perf_record_auxtrace_info *auxtrace_info,
+		size_t priv_size __maybe_unused)
+{
+	auxtrace_info->type = PERF_AUXTRACE_VPA_DTL;
+
+	return 0;
+}
+
+static void powerpc_vpadtl_free(struct auxtrace_record *itr)
+{
+	free(itr);
+}
+
+static u64 powerpc_vpadtl_reference(struct auxtrace_record *itr __maybe_unused)
+{
+	return 0;
+}
+
+struct auxtrace_record *vpa_dtl_recording_init(struct evsel *pos)
+{
+	struct auxtrace_record *aux;
+
+	/*
+	 * To obtain the auxtrace buffer file descriptor, the auxtrace event
+	 * must come first.
+	 */
+	evlist__to_front(pos->evlist, pos);
+
+	aux = zalloc(sizeof(*aux));
+	if (aux == NULL) {
+		pr_debug("aux record is NULL\n");
+		return NULL;
+	}
+
+	aux->recording_options = powerpc_vpadtl_recording_options;
+	aux->info_priv_size = powerpc_vpadtl_info_priv_size;
+	aux->info_fill = powerpc_vpadtl_info_fill;
+	aux->free = powerpc_vpadtl_free;
+	aux->reference = powerpc_vpadtl_reference;
+	return aux;
+}
diff --git a/tools/perf/util/powerpc-vpadtl.h b/tools/perf/util/powerpc-vpadtl.h
index ca809660b9bb..5f17e660c562 100644
--- a/tools/perf/util/powerpc-vpadtl.h
+++ b/tools/perf/util/powerpc-vpadtl.h
@@ -20,4 +20,5 @@ struct perf_pmu;
 int powerpc_vpadtl_process_auxtrace_info(union perf_event *event,
 				  struct perf_session *session);
 
+struct auxtrace_record *vpa_dtl_recording_init(struct evsel *pos);
 #endif
-- 
2.52.0



^ permalink raw reply related

* [PATCH 2/9] tools/perf: Add CONFIG_AUXTRACE support for HTM pmu on powerpc
From: Athira Rajeev @ 2026-07-01  8:41 UTC (permalink / raw)
  To: acme, jolsa, adrian.hunter, maddy, irogers, namhyung
  Cc: linux-perf-users, linuxppc-dev, atrajeev, hbathini, tejas05,
	tshah, venkat88
In-Reply-To: <20260701084115.80383-1-atrajeev@linux.ibm.com>

The powerpc PMU collecting Hardware Trace Macro (HTM) entries makes use of
AUX support in perf infrastructure. The PMU driver has the functionality
to collect trace entries in the aux buffer. On the tools side, this data
is made available as PERF_RECORD_AUXTRACE records. This record is
generated by "perf record" command. To enable the creation of
PERF_RECORD_AUXTRACE, add functions to initialize auxtrace records ie
"htm_recording_init()". Fill in fields for other callbacks like
info_priv_size, info_fill, free, recording options etc. Add header file
to define htm pmu specific details.

Signed-off-by: Athira Rajeev <atrajeev@linux.ibm.com>
---
 tools/perf/arch/powerpc/util/Build      |   1 +
 tools/perf/arch/powerpc/util/auxtrace.c |  10 ++-
 tools/perf/arch/powerpc/util/htm.c      | 113 ++++++++++++++++++++++++
 tools/perf/util/powerpc-htm.h           |  23 +++++
 4 files changed, 146 insertions(+), 1 deletion(-)
 create mode 100644 tools/perf/arch/powerpc/util/htm.c
 create mode 100644 tools/perf/util/powerpc-htm.h

diff --git a/tools/perf/arch/powerpc/util/Build b/tools/perf/arch/powerpc/util/Build
index 7819c8f5af2d..297152591046 100644
--- a/tools/perf/arch/powerpc/util/Build
+++ b/tools/perf/arch/powerpc/util/Build
@@ -8,3 +8,4 @@ perf-util-$(CONFIG_LIBDW) += skip-callchain-idx.o
 
 perf-util-y += auxtrace.o
 perf-util-y += vpa-dtl.o
+perf-util-y += htm.o
diff --git a/tools/perf/arch/powerpc/util/auxtrace.c b/tools/perf/arch/powerpc/util/auxtrace.c
index 0053526329e0..ec84f8876a4a 100644
--- a/tools/perf/arch/powerpc/util/auxtrace.c
+++ b/tools/perf/arch/powerpc/util/auxtrace.c
@@ -12,6 +12,7 @@
 #include "../../util/debug.h"
 #include "../../util/auxtrace.h"
 #include "../../util/powerpc-vpadtl.h"
+#include "../../util/powerpc-htm.h"
 #include "../../util/record.h"
 
 struct auxtrace_record *auxtrace_record__init(struct evlist *evlist,
@@ -19,6 +20,7 @@ struct auxtrace_record *auxtrace_record__init(struct evlist *evlist,
 {
 	struct evsel *pos;
 	int found_vpa_dtl = 0;
+	int found_htm = 0;
 
 	/*
 	 * Set err value to zero here. Any fail later
@@ -31,13 +33,19 @@ struct auxtrace_record *auxtrace_record__init(struct evlist *evlist,
 			found_vpa_dtl = 1;
 			pos->needs_auxtrace_mmap = true;
 			break;
+		} else if (strstarts(pos->name, "htm")) {
+			found_htm = 1;
+			pos->needs_auxtrace_mmap = true;
+			break;
 		}
 	}
 
 	if (found_vpa_dtl)
 		return vpa_dtl_recording_init(pos);
+	else if (found_htm)
+		return htm_recording_init(pos);
 	else {
-		*err = -EINVAL;
+		*err = 0;
 		return NULL;
 	}
 }
diff --git a/tools/perf/arch/powerpc/util/htm.c b/tools/perf/arch/powerpc/util/htm.c
new file mode 100644
index 000000000000..cc733f45ac9b
--- /dev/null
+++ b/tools/perf/arch/powerpc/util/htm.c
@@ -0,0 +1,113 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * HTM support
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/bitops.h>
+#include <linux/log2.h>
+#include <linux/string.h>
+#include <time.h>
+
+#include "../../util/cpumap.h"
+#include "../../util/evsel.h"
+#include "../../util/evlist.h"
+#include "../../util/session.h"
+#include "../../util/util.h"
+#include "../../util/pmu.h"
+#include "../../util/debug.h"
+#include "../../util/auxtrace.h"
+#include "../../util/powerpc-htm.h"
+#include "../../util/record.h"
+#include <internal/lib.h> // page_size
+#include <errno.h>
+
+#define KiB(x) ((x) * 1024)
+
+static int
+htm_recording_options(struct auxtrace_record *ar __maybe_unused,
+			struct evlist *evlist __maybe_unused,
+			struct record_opts *opts)
+{
+	struct evsel *pos;
+
+	opts->full_auxtrace = true;
+
+	if (opts->target.system_wide) {
+		pr_info("System wide monitoring not supported, specify -C <cpu>\n");
+		return -EINVAL;
+	} else if (!opts->target.cpu_list) {
+		pr_info("-C option not provided, specify -C <cpu> to use HTM event\n");
+		return -EINVAL;
+	}
+
+	/*
+	 * Set auxtrace_mmap_pages to minimum
+	 * two pages
+	 */
+	if (!opts->auxtrace_mmap_pages) {
+		opts->auxtrace_mmap_pages = KiB(128) / page_size;
+		if (opts->mmap_pages == UINT_MAX)
+			opts->mmap_pages = KiB(256) / page_size;
+	}
+
+	evlist__for_each_entry(evlist, pos) {
+		if (strstarts(pos->name, "htm")) {
+			pos->needs_auxtrace_mmap = true;
+			pos->core.attr.aux_watermark = opts->auxtrace_mmap_pages * (size_t)page_size;
+			break;
+		}
+	}
+
+	return 0;
+}
+
+static size_t htm_info_priv_size(struct auxtrace_record *itr __maybe_unused,
+					struct evlist *evlist __maybe_unused)
+{
+	return HTM_AUXTRACE_PRIV_SIZE;
+}
+
+static int
+htm_info_fill(struct auxtrace_record *itr __maybe_unused,
+		struct perf_session *session __maybe_unused,
+		struct perf_record_auxtrace_info *auxtrace_info __maybe_unused,
+		size_t priv_size __maybe_unused)
+{
+	return 0;
+}
+
+static u64 htm_reference(struct auxtrace_record *itr __maybe_unused)
+{
+	return 0;
+}
+
+static void htm_free(struct auxtrace_record *itr)
+{
+	free(itr);
+}
+
+struct auxtrace_record *htm_recording_init(struct evsel *pos)
+{
+	struct auxtrace_record *aux;
+
+	/*
+	 * To obtain the auxtrace buffer file descriptor, the auxtrace event
+	 * must come first.
+	 */
+	evlist__to_front(pos->evlist, pos);
+
+	aux = zalloc(sizeof(*aux));
+	if (aux == NULL) {
+		pr_debug("aux record is NULL\n");
+		return NULL;
+	}
+
+	aux->recording_options = htm_recording_options;
+	aux->info_priv_size = htm_info_priv_size;
+	aux->info_fill = htm_info_fill;
+	aux->free = htm_free;
+	aux->reference = htm_reference;
+	return aux;
+}
diff --git a/tools/perf/util/powerpc-htm.h b/tools/perf/util/powerpc-htm.h
new file mode 100644
index 000000000000..be7f8c03e161
--- /dev/null
+++ b/tools/perf/util/powerpc-htm.h
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * HTM PMU Support
+ */
+
+#ifndef INCLUDE__PERF_POWERPC_HTM_H__
+#define INCLUDE__PERF_POWERPC_HTM_H__
+
+#define POWERPC_HTM_NAME "powerpc_htm_"
+
+enum {
+	POWERPC_HTM_TYPE,
+	HTM_AUXTRACE_PRIV_MAX,
+};
+
+#define HTM_AUXTRACE_PRIV_SIZE (HTM_AUXTRACE_PRIV_MAX * sizeof(u64))
+
+union perf_event;
+struct perf_session;
+struct perf_pmu;
+
+struct auxtrace_record *htm_recording_init(struct evsel *pos);
+#endif
-- 
2.52.0



^ permalink raw reply related

* [PATCH 0/9] tools/perf: Add interface to expose HTM trace data via perf
From: Athira Rajeev @ 2026-07-01  8:41 UTC (permalink / raw)
  To: acme, jolsa, adrian.hunter, maddy, irogers, namhyung
  Cc: linux-perf-users, linuxppc-dev, atrajeev, hbathini, tejas05,
	tshah, venkat88

H_HTM (Hardware Trace Macro) hypervisor call is an HCALL to export data
from Hardware Trace Macro (HTM) function. Patchset adds support for setup,
configuration and control of HTM functions as well as trace data
collection via perf PMU interface.

H_HTM is used as an interface for executing Hardware Trace Macro (HTM)
functions, including setup, configuration, control and dumping of the
HTM trace data. 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.

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. The interface uses AUX infrastructure for
capturing of trace data.

Patch 1: Move auxtrace_record__init for powerpc-vpadtl as separate
utility
 - Refactor VPA-DTL auxtrace initialization into arch/powerpc/util/vpa-dtl.c
   to allow multiple PMUs to use auxtrace

Patch 2: Add CONFIG_AUXTRACE support for HTM pmu on powerpc
 - Enable HTM PMU to use AUX buffers with recording options, info callbacks,
   and PERF_AUXTRACE_POWERPC_HTM type

Patch 3: Add arch_record__collect_final_data to collect additional data
before closing the event
 - Introduce callback mechanism to capture remaining data after
   evlist__disable but before event removal

Patch 4: Add powerpc callback support for arch_record__collect_final_data
 - Implement HTM-specific callback to read trace data until perf_evsel__read
   returns zero indicating completion

Patch 5: Process htm auxtrace events and display in perf report -D
 - Add PERF_RECORD_AUXTRACE_INFO processing and write HTM trace data
   to htm.bin.nXpXcX files

Patch 6: Add HTM trace data processing and decoding support
 - Extract system memory configuration, write translation files, and integrate
   htmdecode for trace analysis

Patch 7: Add physical to logical address mapping for HTM traces
 - Map physical addresses from HTM traces to logical addresses using LPAR
   memory configuration from /proc/powerpc/lparcfg

Patch 8: Add event name as htm of PERF_TYPE_SYNTH type to present htm samples
 - Create synthetic HTM event with PERF_SYNTH_POWERPC_HTM config to display
   logical addresses in perf report

Patch 9: Add logical address in decoded nest traces
  - Translate physical to logical addresses in decoded output and create
    .l files for source code correlation

Link to tools side changes:
https://lore.kernel.org/linux-perf-users/20260701083806.79358-1-atrajeev@linux.ibm.com/

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:

   - 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/

Where:

- N = node index
- C = chip index within the node
- R = core index on the chip
- T = HTM type

Basic Usage Example:
To collect HTM trace data for a specific chip:
 # perf record -C 1 -e htm/nodalchipindex=2,nodeindex=0,htm_type=1/ <workload>

In this example:

- nodeindex=0: Target node 0
- nodalchipindex=2: Target chip 2 within node 0
- htm_type=1: HTM trace type 1

Output Files:
After running "perf record", the following files are generated:

   # 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

Trace Data Processing:
Process the collected trace data using perf script:

   # perf script -D

This command:

1. Reads the perf.data file
2. Decodes HTM trace data using translation files
3. Displays human-readable trace output

The decoder automatically:

- Translates physical addresses to logical addresses
- Creates decoded output files for analysis
- Correlates trace data with memory mappings

Here's a complete example of collecting and analyzing HTM traces:

   # 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
   ls htm.bin.*        # Binary trace files
   ls translation.*    # Memory configuration files
   ls perf.data        # Perf data file

   # Step 3: Decode and view traces
   perf script -D > decoded_trace.txt

   # Step 4: Analyze with perf report to see the hot logical address
   perf report

Thanks
Athira

Athira Rajeev (8):
  tool/perf: Move auxtrace_record__init for powerpc-vpadtl as separate
    utility
  tools/perf: Add CONFIG_AUXTRACE support for HTM pmu on powerpc
  tools/perf: Add arch_record__collect_final_data to collect additional
    data before closing the event
  tools/perf: Add powerpc callback support for
    arch_record__collect_final_data
  tools/perf: process htm auxtrace events and display in perf report -D
  perf tools powerpc: Add HTM trace data processing and decoding support
  tools/perf/powerpc: Add event name as htm of PERF_TYPE_SYNTH type to
    present htm samples
  tools/perf/powerpc: Add logical address in decoded nest traces

Tanushree Shah (1):
  perf tools powerpc: Add physical to logical address mapping for HTM
    traces

 tools/perf/arch/powerpc/util/Build      |   2 +
 tools/perf/arch/powerpc/util/auxtrace.c |  87 +--
 tools/perf/arch/powerpc/util/htm.c      | 116 ++++
 tools/perf/arch/powerpc/util/vpa-dtl.c  |  96 +++
 tools/perf/builtin-record.c             |  29 +
 tools/perf/util/Build                   |   1 +
 tools/perf/util/auxtrace.c              |   4 +
 tools/perf/util/auxtrace.h              |   1 +
 tools/perf/util/event.h                 |   1 +
 tools/perf/util/powerpc-htm.c           | 883 ++++++++++++++++++++++++
 tools/perf/util/powerpc-htm.h           |  25 +
 tools/perf/util/powerpc-vpadtl.h        |   1 +
 tools/perf/util/record.h                |   4 +
 13 files changed, 1177 insertions(+), 73 deletions(-)
 create mode 100644 tools/perf/arch/powerpc/util/htm.c
 create mode 100644 tools/perf/arch/powerpc/util/vpa-dtl.c
 create mode 100644 tools/perf/util/powerpc-htm.c
 create mode 100644 tools/perf/util/powerpc-htm.h

-- 
2.52.0



^ permalink raw reply

* [PATCH 3/9] tools/perf: Add arch_record__collect_final_data to collect additional data before closing the event
From: Athira Rajeev @ 2026-07-01  8:41 UTC (permalink / raw)
  To: acme, jolsa, adrian.hunter, maddy, irogers, namhyung
  Cc: linux-perf-users, linuxppc-dev, atrajeev, hbathini, tejas05,
	tshah, venkat88
In-Reply-To: <20260701084115.80383-1-atrajeev@linux.ibm.com>

While collecting samples using "perf record", function
"__cmd_record" checks if monitoring is done. Once recording
is done, event list will be disabled using "evlist__disable".
After this, event fd won't be read and event will be removed.

Before removing the event, if any additional data needs
to be captured/written to perf.data, currently its not
possible. Introduce arch_record__collect_final_data to
collect additional data before closing the event

Signed-off-by: Athira Rajeev <atrajeev@linux.ibm.com>
---
 tools/perf/builtin-record.c | 29 +++++++++++++++++++++++++++++
 tools/perf/util/record.h    |  4 ++++
 2 files changed, 33 insertions(+)

diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index ebd3ed0c9b3e..1312f7223455 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -2426,6 +2426,34 @@ static unsigned long record__waking(struct record *rec)
 	return waking;
 }
 
+/*
+ * Weak symbol - architecture can override to indicate if more
+ * data needs to be collected before finishing output.
+ *
+ * Returns: 1 if more data exists, 0 if collection is complete
+ */
+__weak int arch_perf_record__need_read(struct evlist *evlist __maybe_unused)
+{
+	return 0;  /* Default: no arch-specific data to collect */
+}
+
+static void record__final_data(struct record *rec)
+{
+	/*
+	 * Collect any remaining architecture-specific data.
+	 * The arch code checks if more data exists, and we do the actual
+	 * reading here since we have access to record__mmap_read_all().
+	 */
+	while (arch_perf_record__need_read(rec->evlist)) {
+		if (record__mmap_read_all(rec, false) < 0)
+			break;
+		/* Re-enable events for next batch */
+		evlist__enable(rec->evlist);
+	}
+
+	return;
+}
+
 static int __cmd_record(struct record *rec, int argc, const char **argv)
 {
 	int err;
@@ -2853,6 +2881,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
 		 */
 		if (done && !disabled && !target__none(&opts->target)) {
 			trigger_off(&auxtrace_snapshot_trigger);
+			record__final_data(rec);
 			evlist__disable(rec->evlist);
 			disabled = true;
 		}
diff --git a/tools/perf/util/record.h b/tools/perf/util/record.h
index 93627c9a7338..21f51efd36fc 100644
--- a/tools/perf/util/record.h
+++ b/tools/perf/util/record.h
@@ -8,6 +8,8 @@
 #include <linux/stddef.h>
 #include <linux/perf_event.h>
 #include "util/target.h"
+#include "util/evlist.h"
+#include "util/util.h"
 
 struct option;
 
@@ -95,4 +97,6 @@ static inline bool record_opts__no_switch_events(const struct record_opts *opts)
 	return opts->record_switch_events_set && !opts->record_switch_events;
 }
 
+int arch_perf_record__need_read(struct evlist *evlist);
+
 #endif // _PERF_RECORD_H
-- 
2.52.0



^ permalink raw reply related

* [PATCH 4/9] tools/perf: Add powerpc callback support for arch_record__collect_final_data
From: Athira Rajeev @ 2026-07-01  8:41 UTC (permalink / raw)
  To: acme, jolsa, adrian.hunter, maddy, irogers, namhyung
  Cc: linux-perf-users, linuxppc-dev, atrajeev, hbathini, tejas05,
	tshah, venkat88
In-Reply-To: <20260701084115.80383-1-atrajeev@linux.ibm.com>

Add arch_record__collect_final_data to collect additional
data before closing the event. Define the callback in
util/powerpc-htm.c

Invoke record__mmap_read_all till the complete trace
data is collected in auxtrace buffer and copied to
perf.data . When the auxtrace buffer is full, perf_aux_output_end
will disable the event till data is written. Hence enable
the event using evlist__enable after reading event using
htm_read_data function. The perf_evsel__read returns zero, when
the trace data is completely read and completed. If the count
returns zero for the event, stop the data collection.

Signed-off-by: Athira Rajeev <atrajeev@linux.ibm.com>
---
 tools/perf/util/Build         |  1 +
 tools/perf/util/powerpc-htm.c | 74 +++++++++++++++++++++++++++++++++++
 2 files changed, 75 insertions(+)
 create mode 100644 tools/perf/util/powerpc-htm.c

diff --git a/tools/perf/util/Build b/tools/perf/util/Build
index 330311cac550..7fa354853d2a 100644
--- a/tools/perf/util/Build
+++ b/tools/perf/util/Build
@@ -141,6 +141,7 @@ perf-util-y += hisi-ptt.o
 perf-util-y += hisi-ptt-decoder/
 perf-util-y += s390-cpumsf.o
 perf-util-y += powerpc-vpadtl.o
+perf-util-y += powerpc-htm.o
 
 ifdef CONFIG_LIBOPENCSD
 perf-util-y += cs-etm.o
diff --git a/tools/perf/util/powerpc-htm.c b/tools/perf/util/powerpc-htm.c
new file mode 100644
index 000000000000..5043ff41a609
--- /dev/null
+++ b/tools/perf/util/powerpc-htm.c
@@ -0,0 +1,74 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * HTM support
+ */
+
+#include "../../../util/record.h"
+#include "evlist.h"
+#include "evsel.h"
+#include "session.h"
+#include "debug.h"
+#include <internal/xyarray.h>
+
+/*
+ * Check if HTM events have more data to collect.
+ *
+ * This function reads the HTM event counts. When the kernel driver
+ * has more data available, it returns a non-zero count. When all
+ * data has been collected, it returns zero.
+ *
+ * Returns: 1 if more data exists, 0 if collection is complete
+ */
+int arch_perf_record__need_read(struct evlist *evlist)
+{
+	struct evsel *evsel;
+	int found_htm = 0;
+
+	/* there was an error during record__open */
+	if (!evlist)
+		return 0;
+
+	/* First, check if any HTM events exist */
+	evlist__for_each_entry(evlist, evsel) {
+		if (strstr(evsel->name, "htm") != NULL)
+			found_htm = 1;
+	}
+
+	if (!found_htm)
+		return 0;
+
+	/* Read HTM event counts to check if more data is available */
+	evlist__for_each_entry(evlist, evsel) {
+		struct xyarray *xy = evsel->core.sample_id;
+
+		if (strstr(evsel->name, "htm") == NULL)
+			continue;
+
+		if (xy == NULL || evsel->core.fd == NULL)
+			continue;
+		if (xyarray__max_x(evsel->core.fd) != xyarray__max_x(xy) ||
+			xyarray__max_y(evsel->core.fd) != xyarray__max_y(xy)) {
+			pr_debug("Unmatched FD vs. sample ID: skip reading LOST count\n");
+			continue;
+		}
+
+		for (int x = 0; x < xyarray__max_x(xy); x++) {
+			for (int y = 0; y < xyarray__max_y(xy); y++) {
+				struct perf_counts_values count;
+
+				if (!strcmp(evsel->name, "dummy:u"))
+					continue;
+
+				if (strstr(evsel->name, "htm")) {
+					perf_evsel__read(&evsel->core, x, y, &count);
+					y = xyarray__max_y(xy);
+					x = xyarray__max_x(xy);
+				}
+				if (!count.val)
+					return 0;
+			}
+		}
+	}
+
+	return 1;
+}
-- 
2.52.0



^ permalink raw reply related

* [PATCH 5/9] tools/perf: process htm auxtrace events and display in perf report -D
From: Athira Rajeev @ 2026-07-01  8:41 UTC (permalink / raw)
  To: acme, jolsa, adrian.hunter, maddy, irogers, namhyung
  Cc: linux-perf-users, linuxppc-dev, atrajeev, hbathini, tejas05,
	tshah, venkat88
In-Reply-To: <20260701084115.80383-1-atrajeev@linux.ibm.com>

Add htm pmu auxtrace process function for "perf script -D".
The auxtrace event processing functions are defined in file
"util/powerpc-htm.c". Different PERF_RECORD_XXX are generated
during recording. PERF_RECORD_AUXTRACE_INFO is processed first
since it is of type perf_user_event_type and perf session event
delivers perf_session__process_user_event() first. Define function
powerpc_htm_process_auxtrace_info() to handle the processing of
PERF_RECORD_AUXTRACE_INFO records. In this function, initialize
the aux buffer queues using auxtrace_queues__init(). Setup the
required infrastructure for aux data processing.

The trace data which is part of each AUXTRACE record will be written
to a file named htm.bin.n<nodeindex>.p<nodalchipindex>.c<coreindexonchip>

Sample output:
 # perf record -C 8 -m,256 -e htm/event=0x901032/ ls
 [ perf record: Woken up 1 times to write data ]
 [ perf record: Captured and wrote 2048.915 MB perf.data ]

 # perf script -D -i perf.data
 . ... HTM PMU data: size <N> bytes

 # perf record -C 1 -e htm/nodalchipindex=2,nodeindex=0,htm_type=1/ -o perf_1.data ls 1>out
 [ perf record: Woken up 1 times to write data ]
 [ perf record: Captured and wrote 257.504 MB perf_1.data ]

Signed-off-by: Athira Rajeev <atrajeev@linux.ibm.com>
---
 tools/perf/arch/powerpc/util/htm.c |   3 +
 tools/perf/util/auxtrace.c         |   4 +
 tools/perf/util/auxtrace.h         |   1 +
 tools/perf/util/powerpc-htm.c      | 149 +++++++++++++++++++++++++++++
 tools/perf/util/powerpc-htm.h      |   2 +
 5 files changed, 159 insertions(+)

diff --git a/tools/perf/arch/powerpc/util/htm.c b/tools/perf/arch/powerpc/util/htm.c
index cc733f45ac9b..0e6638c02716 100644
--- a/tools/perf/arch/powerpc/util/htm.c
+++ b/tools/perf/arch/powerpc/util/htm.c
@@ -56,6 +56,7 @@ htm_recording_options(struct auxtrace_record *ar __maybe_unused,
 		if (strstarts(pos->name, "htm")) {
 			pos->needs_auxtrace_mmap = true;
 			pos->core.attr.aux_watermark = opts->auxtrace_mmap_pages * (size_t)page_size;
+			pos->core.attr.sample_type |= PERF_SAMPLE_RAW;
 			break;
 		}
 	}
@@ -75,6 +76,8 @@ htm_info_fill(struct auxtrace_record *itr __maybe_unused,
 		struct perf_record_auxtrace_info *auxtrace_info __maybe_unused,
 		size_t priv_size __maybe_unused)
 {
+	auxtrace_info->type = PERF_AUXTRACE_POWERPC_HTM;
+
 	return 0;
 }
 
diff --git a/tools/perf/util/auxtrace.c b/tools/perf/util/auxtrace.c
index 0b851f32e98c..9f32f54fad43 100644
--- a/tools/perf/util/auxtrace.c
+++ b/tools/perf/util/auxtrace.c
@@ -56,6 +56,7 @@
 #include "s390-cpumsf.h"
 #include "util/mmap.h"
 #include "powerpc-vpadtl.h"
+#include "powerpc-htm.h"
 
 #include <linux/ctype.h>
 #include "symbol/kallsyms.h"
@@ -1427,6 +1428,9 @@ int perf_event__process_auxtrace_info(const struct perf_tool *tool __maybe_unuse
 	case PERF_AUXTRACE_VPA_DTL:
 		err = powerpc_vpadtl_process_auxtrace_info(event, session);
 		break;
+	case PERF_AUXTRACE_POWERPC_HTM:
+		err = powerpc_htm_process_auxtrace_info(event, session);
+		break;
 	case PERF_AUXTRACE_UNKNOWN:
 	default:
 		return -EINVAL;
diff --git a/tools/perf/util/auxtrace.h b/tools/perf/util/auxtrace.h
index 6947f3f284c0..68b17802a419 100644
--- a/tools/perf/util/auxtrace.h
+++ b/tools/perf/util/auxtrace.h
@@ -46,6 +46,7 @@ enum auxtrace_type {
 	PERF_AUXTRACE_S390_CPUMSF,
 	PERF_AUXTRACE_HISI_PTT,
 	PERF_AUXTRACE_VPA_DTL,
+	PERF_AUXTRACE_POWERPC_HTM,
 };
 
 enum itrace_period_type {
diff --git a/tools/perf/util/powerpc-htm.c b/tools/perf/util/powerpc-htm.c
index 5043ff41a609..ffddf0e59fc1 100644
--- a/tools/perf/util/powerpc-htm.c
+++ b/tools/perf/util/powerpc-htm.c
@@ -9,6 +9,24 @@
 #include "session.h"
 #include "debug.h"
 #include <internal/xyarray.h>
+#include <linux/string.h>
+#include "color.h"
+#include <inttypes.h>
+#include "powerpc-htm.h"
+#include <errno.h>
+
+struct perf_session;
+
+struct powerpc_htm {
+	struct auxtrace			auxtrace;
+	struct auxtrace_queues		queues;
+	struct auxtrace_heap		heap;
+	u32				auxtrace_type;
+	struct perf_session		*session;
+	struct machine			*machine;
+	u32				pmu_type;
+	char				htmbin_file[64];
+};
 
 /*
  * Check if HTM events have more data to collect.
@@ -72,3 +90,134 @@ int arch_perf_record__need_read(struct evlist *evlist)
 
 	return 1;
 }
+
+static void powerpc_htm_dump_event(size_t len)
+{
+	const char *color = PERF_COLOR_BLUE;
+
+	color_fprintf(stdout, color,
+			". ... HTM PMU data: size %zu bytes\n",
+			len);
+}
+
+static int powerpc_htm_process_event(struct perf_session *session __maybe_unused,
+				 union perf_event *event __maybe_unused,
+				 struct perf_sample *sample __maybe_unused,
+				 const struct perf_tool *tool __maybe_unused)
+{
+	return 0;
+}
+
+static int powerpc_htm_process_auxtrace_event(struct perf_session *session __maybe_unused,
+					  union perf_event *event,
+					  const struct perf_tool *tool __maybe_unused)
+{
+	powerpc_htm_dump_event(event->auxtrace.size);
+
+	return 0;
+}
+
+static int powerpc_htm_flush(struct perf_session *session __maybe_unused,
+			 const struct perf_tool *tool __maybe_unused)
+{
+	return 0;
+}
+
+static void powerpc_htm_free_events(struct perf_session *session)
+{
+	struct powerpc_htm *htm = container_of(session->auxtrace, struct powerpc_htm,
+					     auxtrace);
+	struct auxtrace_queues *queues = &htm->queues;
+	unsigned int i;
+
+	for (i = 0; i < queues->nr_queues; i++)
+		zfree(&queues->queue_array[i].priv);
+
+	auxtrace_queues__free(queues);
+}
+
+static void powerpc_htm_free(struct perf_session *session)
+{
+	struct powerpc_htm *htm = container_of(session->auxtrace, struct powerpc_htm,
+					     auxtrace);
+
+	powerpc_htm_free_events(session);
+	session->auxtrace = NULL;
+	free(htm);
+}
+static const char * const powerpc_htm_info_fmts[] = {
+	[POWERPC_HTM_TYPE]		= "  PMU Type           %"PRId64"\n",
+};
+
+static void powerpc_htm_print_info(__u64 *arr)
+{
+	if (!dump_trace)
+		return;
+
+	fprintf(stdout, powerpc_htm_info_fmts[POWERPC_HTM_TYPE], arr[POWERPC_HTM_TYPE]);
+}
+
+int powerpc_htm_process_auxtrace_info(union perf_event *event,
+				  struct perf_session *session)
+{
+	struct perf_record_auxtrace_info *auxtrace_info = &event->auxtrace_info;
+	struct evsel *evsel = evlist__event2evsel(session->evlist, event);
+	u32 nodeindex, nodalchipindex, coreindexonchip;
+	int config = (evsel->core.attr.config);
+	size_t min_sz = sizeof(u64) * POWERPC_HTM_TYPE;
+	struct powerpc_htm *htm;
+	int err;
+	FILE *fp;
+
+	nodeindex = (config >> 4) & 0xff;
+	nodalchipindex = (config >> 12) & 0xff;
+	coreindexonchip = (config >> 20) & 0xff;
+
+	if (auxtrace_info->header.size < sizeof(struct perf_record_auxtrace_info) +
+					min_sz)
+		return -EINVAL;
+
+	htm = zalloc(sizeof(struct powerpc_htm));
+	if (!htm)
+		return -ENOMEM;
+
+	err = auxtrace_queues__init(&htm->queues);
+	if (err)
+		goto err_free;
+
+	htm->session = session;
+	htm->machine = &session->machines.host; /* No kvm support */
+	htm->auxtrace_type = auxtrace_info->type;
+	htm->pmu_type = auxtrace_info->priv[POWERPC_HTM_TYPE];
+
+	htm->auxtrace.process_event = powerpc_htm_process_event;
+	htm->auxtrace.process_auxtrace_event = powerpc_htm_process_auxtrace_event;
+	htm->auxtrace.flush_events = powerpc_htm_flush;
+	htm->auxtrace.free_events = powerpc_htm_free_events;
+	htm->auxtrace.free = powerpc_htm_free;
+	session->auxtrace = &htm->auxtrace;
+
+	snprintf(htm->htmbin_file, sizeof(htm->htmbin_file), "htm.bin.n%d.p%d.c%d", nodeindex, nodalchipindex, coreindexonchip);
+	fp = fopen(htm->htmbin_file, "w");
+	if (!fp) {
+		pr_err("Failed to create %s: %s\n", htm->htmbin_file, strerror(errno));
+		return -errno;
+	}
+	fclose(fp);
+
+	powerpc_htm_print_info(&auxtrace_info->priv[0]);
+
+	err = auxtrace_queues__process_index(&htm->queues, session);
+	if (err)
+		goto err_free_queues;
+
+	return 0;
+
+err_free_queues:
+	auxtrace_queues__free(&htm->queues);
+	session->auxtrace = NULL;
+
+err_free:
+	free(htm);
+	return err;
+}
diff --git a/tools/perf/util/powerpc-htm.h b/tools/perf/util/powerpc-htm.h
index be7f8c03e161..0dc31fa252b4 100644
--- a/tools/perf/util/powerpc-htm.h
+++ b/tools/perf/util/powerpc-htm.h
@@ -20,4 +20,6 @@ struct perf_session;
 struct perf_pmu;
 
 struct auxtrace_record *htm_recording_init(struct evsel *pos);
+int powerpc_htm_process_auxtrace_info(union perf_event *event,
+					struct perf_session *session);
 #endif
-- 
2.52.0



^ permalink raw reply related

* [PATCH 6/9] perf tools powerpc: Add HTM trace data processing and decoding support
From: Athira Rajeev @ 2026-07-01  8:41 UTC (permalink / raw)
  To: acme, jolsa, adrian.hunter, maddy, irogers, namhyung
  Cc: linux-perf-users, linuxppc-dev, atrajeev, hbathini, tejas05,
	tshah, venkat88
In-Reply-To: <20260701084115.80383-1-atrajeev@linux.ibm.com>

perf data includes SystemMemory Configuration dump. This
information helps to understand the physical to logical real
address mapping for the logical partitions in the system.

To help with relating and identifying the start of memory
mapping data in the auxiliary buffer, two PERF_SAMPLE_RAW records
are also present in the ring buffer. First PERF_SAMPLE_RAW record
represents beginning of system memory mapping data in aux buffer.
And second PERF_SAMPLE_RAW record represents the end of the trace
data in aux buffer and also contains the total size of the memory
map data. These sample raw records are used during post processing.

Add support for processing Hardware Trace Macro (HTM) auxiliary trace
data collected via perf AUX buffers. This enables post-processing of
HTM traces including system memory configuration and trace

HTM trace data includes two types of information:
1. Bus traces captured in the AUX buffer
2. System Memory Configuration that maps physical to logical real
   addresses for logical partitions

The implementation handles the challenge of large HTM trace buffers
(up to 8GB) being collected through perf AUX buffers (typically
16MB) by reading data in chunks during post-processing.

Key features:

- Process PERF_RECORD_SAMPLE events with RAW data that mark boundaries
  between trace data and memory configuration data in the AUX buffer

- Write HTM trace data to htm.bin.nXpXcX files where X represents
  node, chip, and core indices extracted from the event configuration

- Write system memory configuration to translation.nXpXcX files for
  address mapping analysis

- Integrate with external htmdecode tool for trace decoding
  when available (config bit 0 set indicates Bus traces)

- Use fork/exec pattern for secure external command execution with
  proper error handling and exit code checking

The memory configuration data is written in 32-byte entries with the
entry count stored at offset 0x10 in big-endian format. The first
PERF_SAMPLE_RAW record marks the start of memory mapping data, while
the second marks the end and contains the total buffer count.

Error handling includes:
- NULL checks for all file operations
- Verification of write operations
- Graceful degradation if htmdecode is not installed
- Proper resource cleanup (file handles, memory mappings)

Example usage:
  # perf record -C 1 -e htm/nodalchipindex=2,nodeindex=0,htm_type=1/ <workload> # Collect trace data
  # perf script -D    # Shows HTM trace data
  # ls htm.bin.*      # Binary trace files
  # ls translation.*  # Memory configuration files

Signed-off-by: Athira Rajeev <atrajeev@linux.ibm.com>
---
 tools/perf/util/powerpc-htm.c | 225 +++++++++++++++++++++++++++++++++-
 1 file changed, 224 insertions(+), 1 deletion(-)

diff --git a/tools/perf/util/powerpc-htm.c b/tools/perf/util/powerpc-htm.c
index ffddf0e59fc1..487989ca4fc7 100644
--- a/tools/perf/util/powerpc-htm.c
+++ b/tools/perf/util/powerpc-htm.c
@@ -14,6 +14,12 @@
 #include <inttypes.h>
 #include "powerpc-htm.h"
 #include <errno.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include "sample.h"
+#include <sys/types.h>
+#include <sys/wait.h>
 
 struct perf_session;
 
@@ -26,8 +32,140 @@ struct powerpc_htm {
 	struct machine			*machine;
 	u32				pmu_type;
 	char				htmbin_file[64];
+	char				trans_file[64];
+	int				htm_mem_entries;
+	int				mem_maps;
 };
 
+struct htm_mem {
+	uint64_t phy_real;
+	uint64_t logical_real;
+	uint32_t lp_index;
+	uint8_t mem_tier;
+	uint8_t mem_type;
+	uint16_t res;
+	uint64_t size;
+};
+
+static int run_htmdecode(const char *input_file, const char *output_file)
+{
+	pid_t pid;
+	int status;
+
+	pid = fork();
+	if (pid == -1) {
+		pr_err("fork() failed: %s\n", strerror(errno));
+		return -errno;
+	}
+
+	if (pid == 0) {
+		/* Child process */
+		int fd = open(output_file, O_WRONLY | O_CREAT | O_TRUNC, 0644);
+
+		if (fd == -1) {
+			pr_err("Failed to open output file: %s\n", strerror(errno));
+			exit(1);
+		}
+
+		/* Redirect stdout to output file */
+		dup2(fd, STDOUT_FILENO);
+		close(fd);
+
+		/* Execute htmdecode - execlp searches PATH automatically */
+		execlp("htmdecode", "htmdecode", "-o", "-j", "-w", "1",
+			"-f", input_file, NULL);
+
+		/* If execlp returns, it failed */
+		pr_err("Failed to execute htmdecode: %s\n", strerror(errno));
+		if (errno == ENOENT)
+			pr_err("htmdecode not found in PATH\n");
+
+		exit(127);  /* Standard "command not found" exit code */
+	}
+
+	/* Parent process - wait for child */
+	if (waitpid(pid, &status, 0) == -1) {
+		pr_err("waitpid() failed: %s\n", strerror(errno));
+		return -errno;
+	}
+
+	/* Check exit status */
+	if (WIFEXITED(status)) {
+		int exit_code = WEXITSTATUS(status);
+
+		if (exit_code == 127) {
+			pr_err("htmdecode not found in PATH\n");
+			return -ENOENT;
+		} else if (exit_code != 0) {
+			pr_err("htmdecode failed with exit code %d\n", exit_code);
+			return -EINVAL;
+		}
+	} else if (WIFSIGNALED(status)) {
+		pr_err("htmdecode killed by signal %d\n", WTERMSIG(status));
+		return -EINTR;
+	}
+
+	return 0;
+}
+
+static int create_mem_maps(struct powerpc_htm *htm)
+{
+	off_t file_size;
+	void *htmdata, *mapped_data;
+	int fd;
+	struct stat file_info;
+	struct htm_mem *mem;
+	char tracefile[128];
+	int ret;
+
+	snprintf(tracefile, sizeof(tracefile), "%s.out", htm->htmbin_file);
+
+	ret = run_htmdecode(htm->htmbin_file, tracefile);
+	if (ret) {
+		if (ret == -ENOENT)
+			pr_info("htmdecode not found. Install htmdecode to decode traces.\n");
+		else
+			pr_info("htmdecode failed with error %d\n", ret);
+		return ret;
+	}
+
+	fd = open(htm->trans_file, O_RDONLY);
+	if (fd == -1) {
+		pr_err("Failed to open %s: %s\n", htm->trans_file, strerror(errno));
+		return -1;
+	}
+
+	if (fstat(fd, &file_info) == -1) {
+		close(fd);
+		pr_err("fstat failed on %s: %s\n", htm->trans_file, strerror(errno));
+		return -1;
+	}
+
+	file_size = file_info.st_size;
+
+	mapped_data = mmap(NULL, file_size, PROT_READ, MAP_PRIVATE, fd, 0);
+	if (mapped_data == MAP_FAILED) {
+		close(fd);
+		pr_err("mmap failed on %s: %s\n", htm->trans_file, strerror(errno));
+		return -1;
+	}
+
+	htmdata = mapped_data + 0x20;
+	mem = (struct htm_mem *)htmdata;
+
+	if (!mem || !htm->htm_mem_entries) {
+		pr_info("No memory mapping entries captured in HTM translation\n");
+		munmap(mapped_data, file_size);
+		close(fd);
+		return -1;
+	}
+
+	munmap(mapped_data, file_size);
+	close(fd);
+
+	return 0;
+}
+
 /*
  * Check if HTM events have more data to collect.
  *
@@ -95,9 +233,55 @@ static void powerpc_htm_dump_event(size_t len)
 {
 	const char *color = PERF_COLOR_BLUE;
 
-	color_fprintf(stdout, color,
+	if (dump_trace) {
+		color_fprintf(stdout, color,
 			". ... HTM PMU data: size %zu bytes\n",
 			len);
+	}
+}
+
+static int write_htm(void *data, size_t size, struct powerpc_htm *htm)
+{
+	FILE *fp;
+	u64 *num_entries;
+	size_t entries;
+	size_t written;
+	int ret = -1;
+
+	if (htm->mem_maps) {
+		fp = fopen(htm->trans_file, "ab");
+		if (!fp) {
+			pr_err("Failed to open %s: %s\n", htm->trans_file, strerror(errno));
+			return ret;
+		}
+		num_entries = data + 0x10;
+		entries = be64_to_cpu(*num_entries);
+		entries++;
+		written = fwrite(data, 32, entries, fp);
+		if (written != entries) {
+			pr_err("Failed to write data: expected %zu, wrote %zu\n", entries, written);
+			fclose(fp);
+			return ret;
+		}
+		fclose(fp);
+		htm->htm_mem_entries += entries;
+		return 0;
+	}
+
+	fp = fopen(htm->htmbin_file, "a");
+	if (!fp) {
+		pr_err("Failed to open %s: %s\n", htm->htmbin_file, strerror(errno));
+		return ret;
+	}
+	written = fwrite(data, size, 1, fp);
+	if (!written) {
+		pr_err("Failed to htm trace data\n");
+		fclose(fp);
+		return ret;
+	}
+	fclose(fp);
+
+	return 0;
 }
 
 static int powerpc_htm_process_event(struct perf_session *session __maybe_unused,
@@ -105,6 +289,37 @@ static int powerpc_htm_process_event(struct perf_session *session __maybe_unused
 				 struct perf_sample *sample __maybe_unused,
 				 const struct perf_tool *tool __maybe_unused)
 {
+	struct powerpc_htm *htm = container_of(session->auxtrace, struct powerpc_htm,
+			auxtrace);
+
+	if ((event->header.type == PERF_RECORD_SAMPLE) && sample->raw_data) {
+		int *content = (int *)sample->raw_data;
+		struct evsel *evsel = evlist__event2evsel(session->evlist, event);
+		int config = (evsel->core.attr.config) & 0xF;
+		struct auxtrace_buffer *buffer = NULL;
+		struct auxtrace_queues *queues = &htm->queues;
+		unsigned int i = 0;
+		int j = 0;
+
+		if (strstr(evsel->name, "htm") == NULL)
+			return 0;
+
+		for (i = 0; i < queues->nr_queues; i++) {
+			buffer = auxtrace_buffer__next(&queues->queue_array[i], buffer);
+			for (; buffer;) {
+				if (j >= *content)
+					htm->mem_maps = 1;
+				if (write_htm(buffer->data, buffer->size, htm))
+					return -1;
+				j++;
+				buffer = auxtrace_buffer__next(&queues->queue_array[i], buffer);
+			}
+		}
+		/* Only for power bus traces, we decode traces */
+		if (config == 1)
+			create_mem_maps(htm);
+	}
+
 	return 0;
 }
 
@@ -205,6 +420,14 @@ int powerpc_htm_process_auxtrace_info(union perf_event *event,
 	}
 	fclose(fp);
 
+	snprintf(htm->trans_file, sizeof(htm->trans_file), "translation.n%d.p%d.c%d", nodeindex, nodalchipindex, coreindexonchip);
+	fp = fopen(htm->trans_file, "w");
+	if (!fp) {
+		pr_err("Failed to create %s: %s\n", htm->trans_file, strerror(errno));
+		return -errno;
+	}
+	fclose(fp);
+
 	powerpc_htm_print_info(&auxtrace_info->priv[0]);
 
 	err = auxtrace_queues__process_index(&htm->queues, session);
-- 
2.52.0



^ permalink raw reply related

* [PATCH 7/9] perf tools powerpc: Add physical to logical address mapping for HTM traces
From: Athira Rajeev @ 2026-07-01  8:41 UTC (permalink / raw)
  To: acme, jolsa, adrian.hunter, maddy, irogers, namhyung
  Cc: linux-perf-users, linuxppc-dev, atrajeev, hbathini, tejas05,
	tshah, venkat88
In-Reply-To: <20260701084115.80383-1-atrajeev@linux.ibm.com>

From: Tanushree Shah <tshah@linux.ibm.com>

Add support for mapping physical addresses from HTM (Hardware Trace Macro)
traces to logical addresses within the current LPAR (Logical Partition).
This enables correlation of HTM trace data with the logical address space
visible to applications and the kernel.

HTM traces capture physical memory addresses from the transactions, but for
meaningful analysis, these need to be mapped to the logical addresses used
by the partition. This patch implements the mapping by:

1. Reading the current partition ID from /proc/powerpc/lparcfg to identify
   which LPAR the trace belongs to

2. Extracting memory map entries from the HTM system memory configuration
   data, which contains:

3. Parsing the decoded HTM trace file using regex patterns to extract
   physical addresses and their associated event labels from each trace
   entry

4. For each physical address in the trace, finding the matching memory
   map entry by:
   - Checking if the address falls within the entry's physical range
   - Verifying the entry belongs to the current partition (LP index match)
   - Computing the offset from the physical range start
   - Adding the offset to the logical range start to get the logical address

The implementation uses dynamic memory allocation to handle variable numbers
of trace entries and memory map entries.

Data structures:
- struct mem_entries: Stores memory map metadata (physical start, logical
  start, LP index, size) extracted from HTM system memory configuration

- struct addr_map: Stores the mapping results (physical address,
  logical address) for each trace entry

The mapping results are output via pr_debug() for verification during
development and debugging. This information is essential for subsequent
patches that will use the logical addresses to generate synthetic perf
samples.

Error handling includes:
- NULL checks for all memory allocations
- Validation of file operations (fopen, fstat, mmap)
- Proper resource cleanup on all error paths
- Consistent error return codes using negative errno values
- Descriptive error messages using perf's pr_err() infrastructure

This patch is part of the HTM trace processing pipeline and works in
conjunction with:
- HTM trace collection (kernel driver)
- HTM trace decoding (htmdecode tool)
- Synthetic sample generation (subsequent patch)

This patch incorporates the following changes:
Store HTM memory map entries (start physical, start logical,
LP index) into a dedicated struct.

Parse HTM decoded trace file and extract the "addr" and
"label" fields and store it in a struct.

For each address in the trace, the code checks for a matching
memory map entry with the same LP index. If the address falls
within the entry's range, the offset is computed and added to
the logical start address (got from the memory map entry) to
get the logical address of the given address.

Signed-off-by: Tanushree Shah <tshah@linux.ibm.com>
---
 tools/perf/util/powerpc-htm.c | 264 ++++++++++++++++++++++++++++++++++
 1 file changed, 264 insertions(+)

diff --git a/tools/perf/util/powerpc-htm.c b/tools/perf/util/powerpc-htm.c
index 487989ca4fc7..83253850870c 100644
--- a/tools/perf/util/powerpc-htm.c
+++ b/tools/perf/util/powerpc-htm.c
@@ -20,6 +20,13 @@
 #include "sample.h"
 #include <sys/types.h>
 #include <sys/wait.h>
+#include <regex.h>
+#include <ctype.h>
+#include <errno.h>
+
+/* mask the 64th bit of a physical address */
+#define PHYS_ADDR_MASK        0x7FFFFFFFFFFFFFFFUL
+const char *lpar_cfg = "/proc/powerpc/lparcfg";
 
 struct perf_session;
 
@@ -47,6 +54,19 @@ struct htm_mem {
 	uint64_t size;
 };
 
+struct mem_entries {
+	unsigned long long phy_addr;
+	unsigned long logical_addr;
+	u32 lp_index;
+	u64 size;
+};
+
+struct addr_map {
+	char event[64];
+	unsigned long long phys_addr;
+	unsigned long logical_addr;
+};
+
 static int run_htmdecode(const char *input_file, const char *output_file)
 {
 	pid_t pid;
@@ -108,6 +128,187 @@ static int run_htmdecode(const char *input_file, const char *output_file)
 	return 0;
 }
 
+static void *safe_realloc(void *ptr, size_t new_size)
+{
+	void *tmp = realloc(ptr, new_size);
+
+	if (!tmp) {
+		pr_err("realloc failed: %s\n", strerror(errno));
+		return NULL;
+	}
+
+	return tmp;
+}
+
+static int add_map_entry(struct addr_map **arr, size_t *count, size_t *cap, struct addr_map entry)
+{
+	if (*count >= *cap) {
+		size_t new_cap = (*cap == 0) ? 1024 : (*cap * 2);
+		void *tmp = safe_realloc(*arr, new_cap * sizeof(struct addr_map));
+
+		if (!tmp)
+			return -1;  // allocation failed
+		*arr = tmp;
+		*cap = new_cap;
+
+	}
+
+	(*arr)[(*count)++] = entry;
+	return 0;
+}
+
+/*
+ * This effectively maps a physical address to its logical address
+ * within the selected LP partition.
+ */
+static unsigned long find_logical_addr(unsigned long long given_addr,
+				struct mem_entries *mem_entries_array,
+				size_t n_entries,
+				u32 lp_filter)
+{
+	for (size_t i = 0; i < n_entries; i++) {
+		unsigned long long start = mem_entries_array[i].phy_addr & PHYS_ADDR_MASK;
+		unsigned long long end   = start + mem_entries_array[i].size;
+
+		/* Skip entries with invalid logical_start sentinel */
+		if (mem_entries_array[i].logical_addr == UINT64_MAX) {
+			pr_debug("  SKIP i=%zu: logical_start sentinel=0x%016llx\n",
+			i, (unsigned long long)mem_entries_array[i].logical_addr);
+			continue;
+		}
+
+		/*
+		 * Check if 'given_addr' falls within the physical memory range of this entry
+		 * and belongs to the LP partition indicated by 'lp_filter'.
+		 * If so, calculate:
+		 * 'offset' and the 'logical address
+		 */
+		if (start <= given_addr && given_addr < end &&
+			mem_entries_array[i].lp_index == lp_filter) {
+			unsigned long long offset = given_addr - start;
+			unsigned long logical = mem_entries_array[i].logical_addr + offset;
+
+			pr_debug("DEBUG: Condition hit at i=%zu given_addr=0x%llx start=0x%llx end=0x%llx lp_index=%u\n",
+				i, given_addr,
+				start, end,
+				(unsigned int)mem_entries_array[i].lp_index);
+			pr_debug("logical = 0x%016lx\n", logical);
+			return logical;
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * Parse the HTM trace file line by line, extracting memory addresses and labels.
+ * Map each memory addresses to a corresponding logical address for a given
+ * lp_filter. Store the results in a dynamically growing map of entries.
+ */
+static struct addr_map *process_trace_file(const char *trace_file,
+				struct mem_entries *mem_entries_array,
+				size_t n_entries,
+				u32 lp_filter,
+				size_t *count_out)
+{
+	regex_t addr_regex, label_regex;
+	struct addr_map *maps;
+	size_t count, cap;
+	char *line = NULL;
+	size_t len;
+	regmatch_t pmatch[2];
+	const char *ptr;
+	unsigned long logical_addr;
+	size_t total_phys = 0;
+	size_t total_phys_to_logical = 0;
+
+	FILE *fp = fopen(trace_file, "r");
+
+	if (!fp) {
+		pr_err("Failed to open trace file %s: %s\n", trace_file, strerror(errno));
+		return NULL;
+	}
+
+	if (regcomp(&addr_regex, "addr:0x[0-9A-Fa-f]+", REG_EXTENDED) != 0) {
+		pr_err("Failed to compile addr_regex\n");
+		return NULL;
+	}
+
+	if (regcomp(&label_regex,
+		   "^[[:space:]]*[0-9A-Fa-f]+ : [^[:space:]]+[[:space:]]+([^[:space:]]+)",
+		   REG_EXTENDED) != 0) {
+		pr_err("Failed to compile label_regex\n");
+		return NULL;
+	}
+
+	maps = NULL;
+	count = 0;
+	cap = 0;
+
+	while (getline(&line, &len, fp) != -1) {
+		if (regexec(&label_regex, line, 2, pmatch, 0) == 0) {
+			char label[64] = {0};
+			int start = pmatch[1].rm_so;
+			int end   = pmatch[1].rm_eo;
+			int line_len   = end - start;
+
+			if (line_len < 0)
+				line_len = 0;
+			if ((size_t)line_len > sizeof(label) - 1)
+				line_len = (int)(sizeof(label) - 1);
+
+			/* Use snprintf to copy exactly len characters and
+			 * always null terminate
+			 */
+			snprintf(label, sizeof(label), "%.*s", line_len, line + start);
+			ptr = line;
+			while (regexec(&addr_regex, ptr, 1, pmatch, 0) == 0) {
+				unsigned long long phys_addr = 0;
+				struct addr_map entry = {0};
+
+				if (sscanf(ptr + pmatch[0].rm_so + strlen("addr:"),
+					  "%llx", &phys_addr) != 1) {
+					pr_debug("Failed to parse phys addr from trace line\n");
+					continue;
+				}
+
+				total_phys++;
+				pr_debug("Total Phys[%zu]: 0x%016llx\n", total_phys, phys_addr);
+				logical_addr = find_logical_addr(phys_addr,
+							mem_entries_array,
+							n_entries,
+							lp_filter);
+				if (logical_addr == 0) {
+					ptr += pmatch[0].rm_eo;
+					continue;
+				} else {
+					total_phys_to_logical++;
+					pr_debug("  Phys: 0x%016llx to Logical: 0x%016lx\n",
+					phys_addr,
+					logical_addr);
+				}
+				pr_debug("Total physical to logical found    : %zu\n",
+					total_phys_to_logical);
+				snprintf(entry.event, sizeof(entry.event), "%s", label);
+				entry.phys_addr   = phys_addr;
+				entry.logical_addr = logical_addr;
+
+				add_map_entry(&maps, &count, &cap, entry);
+
+				ptr += pmatch[0].rm_eo;
+			}
+		}
+	}
+
+	free(line);
+	fclose(fp);
+	regfree(&addr_regex);
+	regfree(&label_regex);
+
+	*count_out = count;
+	return maps;
+}
+
 static int create_mem_maps(struct powerpc_htm *htm)
 {
 	off_t file_size;
@@ -117,6 +318,13 @@ static int create_mem_maps(struct powerpc_htm *htm)
 	struct htm_mem *mem;
 	char tracefile[128];
 	int ret;
+	u32 lp_filter = 0;
+	size_t n_entries = htm->htm_mem_entries;
+	struct mem_entries *mem_entries_array;
+	size_t num_maps = 0;
+	struct addr_map *maps;
+	FILE *fp;
+	char lp_line[256];
 
 	snprintf(tracefile, sizeof(tracefile), "%s.out", htm->htmbin_file);
 
@@ -129,6 +337,27 @@ static int create_mem_maps(struct powerpc_htm *htm)
 		return ret;
 	}
 
+	/* get the lp index */
+	fp = fopen(lpar_cfg, "r");
+	if (!fp) {
+		pr_err("Failed to open %s: %s\n", lpar_cfg, strerror(errno));
+		return -errno;
+	}
+
+	while (fgets(lp_line, sizeof(lp_line), fp)) {
+		if (strncmp(lp_line, "partition_id=", 13) == 0) {
+			lp_filter = strtoul(lp_line + 13, NULL, 10);
+			break;
+		}
+	}
+
+	fclose(fp);
+
+	if (lp_filter == 0)
+		pr_info("partition_id not found in %s\n", lpar_cfg);
+	else
+		pr_info("Using partition_id = %" PRIu32 "\n", lp_filter);
+
 	fd = open(htm->trans_file, O_RDONLY);
 	if (fd == -1) {
 		pr_err("Failed to open %s: %s\n", htm->trans_file, strerror(errno));
@@ -160,9 +389,44 @@ static int create_mem_maps(struct powerpc_htm *htm)
 		return -1;
 	}
 
+	mem_entries_array = malloc(n_entries * sizeof(struct mem_entries));
+	if (!mem_entries_array) {
+		pr_err("Failed to allocate memory for mem entries: %s\n", strerror(errno));
+		munmap(mapped_data, file_size);
+		close(fd);
+		return -ENOMEM;
+	}
+
+	/* get the HTM memory map data and store it in mem_entries_array
+	 * to use it later on for physical->logical mapping
+	 */
+	for (u64 i = 0; i < n_entries; i++, mem++) {
+		mem_entries_array[i].phy_addr = bswap_64(mem->phy_real);
+		mem_entries_array[i].logical_addr = bswap_64(mem->logical_real);
+		mem_entries_array[i].lp_index = bswap_32(mem->lp_index);
+		mem_entries_array[i].size = bswap_64(mem->size);
+	}
+
 	munmap(mapped_data, file_size);
 	close(fd);
 
+	maps = process_trace_file(tracefile, mem_entries_array, n_entries, lp_filter, &num_maps);
+	if (!maps) {
+		pr_err("Error processing physical addresses from trace file\n");
+		free(mem_entries_array);
+		return -EINVAL;
+	}
+
+	for (size_t i = 0; i < num_maps; i++) {
+		pr_debug("Event: %-20s | Phys: 0x%016llx | Logical: 0x%lx\n",
+			maps[i].event,
+			maps[i].phys_addr,
+			(unsigned long)maps[i].logical_addr);
+	}
+
+	free(maps);
+	free(mem_entries_array);
+
 	return 0;
 }
 
-- 
2.52.0



^ permalink raw reply related

* [PATCH 8/9] tools/perf/powerpc: Add event name as htm of PERF_TYPE_SYNTH type to present htm samples
From: Athira Rajeev @ 2026-07-01  8:41 UTC (permalink / raw)
  To: acme, jolsa, adrian.hunter, maddy, irogers, namhyung
  Cc: linux-perf-users, linuxppc-dev, atrajeev, hbathini, tejas05,
	tshah, venkat88
In-Reply-To: <20260701084115.80383-1-atrajeev@linux.ibm.com>

HTM trace details are captured as-is in PERF_RECORD_AUXTRACE
records. To present htm entries as samples, create an event
with name as "htm" and type PERF_TYPE_SYNTH.

Add perf_synth_id, "PERF_SYNTH_POWERPC_HTM" as config value for the
event. Create a sample id to be a fixed offset from evsel id.
Invoke powerpc_htm_create_sample() using the logical address
as sample ip.

This will help in understanding hot logical address from the
traces.

Usage:

 # perf record -C 1 -e htm/nodalchipindex=2,nodeindex=0,htm_type=1/ -o perf_1.data ls 1>out
 [ perf record: Woken up 1 times to write data ]
 [ perf record: Captured and wrote 257.504 MB perf_1.data ]

 # ./perf report -i perf_1.data

 # Samples: 8M of event 'htm'
 # Event count (approx.): 8515199
 #
 # Children      Self  Command  Shared Object     Symbol
 # ........  ........  .......  ................  ......................
 #
     0.61%     0.61%  swapper  [unknown]         [.] 0x00000006fd567fe0
     0.33%     0.33%  swapper  [unknown]         [.] 0x00000006fc194b20
     0.20%     0.20%  swapper  [unknown]         [.] 0x0000000066113f80
     0.18%     0.18%  swapper  [unknown]         [.] 0x00000007fd888f20
     0.15%     0.15%  swapper  [unknown]         [.] 0x00000006fd567fc0
     0.08%     0.08%  swapper  [unknown]         [.] 0x00000006fc194b00
     0.05%     0.05%  swapper  [unknown]         [.] 0x00000007fd888f00
     0.03%     0.03%  swapper  [unknown]         [.] 0x0000000422510700
     0.03%     0.03%  swapper  [unknown]         [.] 0x0000000422510820
     0.03%     0.03%  swapper  [unknown]         [.] 0x00000007fd888b80
     0.02%     0.02%  swapper  [unknown]         [.] 0x000000000a0ece40
     0.02%     0.02%  swapper  [unknown]         [.] 0x000000000a0ed2e0
     0.01%     0.01%  swapper  [unknown]         [.] 0x00000007fd888c40
     0.01%     0.01%  swapper  [unknown]         [.] 0x00000007fd889000
     0.01%     0.01%  swapper  [unknown]         [.] 0x00000007fd5bc200
     0.01%     0.01%  swapper  [unknown]         [.] 0x00000007fd61c200
     0.01%     0.01%  swapper  [unknown]         [.] 0x00000007fd28c200
     0.01%     0.01%  swapper  [unknown]         [.] 0x00000007fd22c200
     0.01%     0.01%  swapper  [unknown]         [.] 0x00000007fd1fc200

Signed-off-by: Athira Rajeev <atrajeev@linux.ibm.com>
---
 tools/perf/util/event.h       |   1 +
 tools/perf/util/powerpc-htm.c | 110 +++++++++++++++++++++++++++++++++-
 2 files changed, 109 insertions(+), 2 deletions(-)

diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index 2ea83fdf8a03..f5aa7eb9f5b7 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -118,6 +118,7 @@ enum perf_synth_id {
 	PERF_SYNTH_INTEL_EVT,
 	PERF_SYNTH_INTEL_IFLAG_CHG,
 	PERF_SYNTH_POWERPC_VPA_DTL,
+	PERF_SYNTH_POWERPC_HTM,
 };
 
 /*
diff --git a/tools/perf/util/powerpc-htm.c b/tools/perf/util/powerpc-htm.c
index 83253850870c..050fbceac71e 100644
--- a/tools/perf/util/powerpc-htm.c
+++ b/tools/perf/util/powerpc-htm.c
@@ -42,6 +42,7 @@ struct powerpc_htm {
 	char				trans_file[64];
 	int				htm_mem_entries;
 	int				mem_maps;
+	u64				sample_id;
 };
 
 struct htm_mem {
@@ -128,6 +129,43 @@ static int run_htmdecode(const char *input_file, const char *output_file)
 	return 0;
 }
 
+static int powerpc_htm_create_sample(unsigned long addr, struct perf_session *session,
+		struct powerpc_htm *htm)
+{
+	struct perf_sample sample;
+	union perf_event event;
+
+	if (dump_trace)
+		return 0;
+
+	memset(&sample, 0, sizeof(sample));
+	sample.cpumode = PERF_RECORD_MISC_USER;
+
+	if (!addr)
+		return 0;
+
+	if (addr >= 0xc000000000000000)
+		sample.cpumode = PERF_RECORD_MISC_KERNEL;
+
+	sample.ip = addr;
+	sample.period = 1;
+	sample.cpu = 0;
+	sample.id = htm->sample_id;
+	sample.callchain = NULL;
+	sample.branch_stack = NULL;
+	memset(&event, 0, sizeof(event));
+	event.sample.header.type = PERF_RECORD_SAMPLE;
+	event.sample.header.misc = sample.cpumode;
+	event.sample.header.size = sizeof(struct perf_event_header);
+
+	if (perf_session__deliver_synth_event(session, &event, &sample)) {
+		pr_debug("Failed to create sample for htm entry\n");
+		return -1;
+	}
+
+	return 0;
+}
+
 static void *safe_realloc(void *ptr, size_t new_size)
 {
 	void *tmp = realloc(ptr, new_size);
@@ -309,7 +347,7 @@ static struct addr_map *process_trace_file(const char *trace_file,
 	return maps;
 }
 
-static int create_mem_maps(struct powerpc_htm *htm)
+static int create_mem_maps(struct perf_session *session, struct powerpc_htm *htm)
 {
 	off_t file_size;
 	void *htmdata, *mapped_data;
@@ -422,6 +460,7 @@ static int create_mem_maps(struct powerpc_htm *htm)
 			maps[i].event,
 			maps[i].phys_addr,
 			(unsigned long)maps[i].logical_addr);
+		powerpc_htm_create_sample(maps[i].logical_addr, session, htm);
 	}
 
 	free(maps);
@@ -581,7 +620,7 @@ static int powerpc_htm_process_event(struct perf_session *session __maybe_unused
 		}
 		/* Only for power bus traces, we decode traces */
 		if (config == 1)
-			create_mem_maps(htm);
+			create_mem_maps(session, htm);
 	}
 
 	return 0;
@@ -636,6 +675,69 @@ static void powerpc_htm_print_info(__u64 *arr)
 	fprintf(stdout, powerpc_htm_info_fmts[POWERPC_HTM_TYPE], arr[POWERPC_HTM_TYPE]);
 }
 
+static void set_event_name(struct evlist *evlist, u64 id,
+			const char *name)
+{
+	struct evsel *evsel;
+
+	evlist__for_each_entry(evlist, evsel) {
+		if (evsel->core.id && evsel->core.id[0] == id) {
+			if (evsel->name)
+				zfree(&evsel->name);
+			evsel->name = strdup(name);
+			if (!evsel->name) {
+				pr_err("Failed to allocate memory for event name\n");
+				return;
+			}
+			break;
+		}
+	}
+}
+
+static int
+powerpc_htm_synth_events(struct powerpc_htm *htm, struct perf_session *session)
+{
+	struct evlist *evlist = session->evlist;
+	struct evsel *evsel;
+	struct perf_event_attr attr;
+	bool found = false;
+	u64 id;
+	int err;
+
+	evlist__for_each_entry(evlist, evsel) {
+		if (strstarts(evsel->name, "htm")) {
+			found = true;
+			break;
+		}
+	}
+
+	if (!found) {
+		pr_debug("No selected events with HTM trace data\n");
+		return 0;
+	}
+
+	memset(&attr, 0, sizeof(struct perf_event_attr));
+	attr.size = sizeof(struct perf_event_attr);
+	attr.sample_type = evsel->core.attr.sample_type;
+	attr.sample_id_all = evsel->core.attr.sample_id_all;
+	attr.type = PERF_TYPE_SYNTH;
+	attr.config = PERF_SYNTH_POWERPC_HTM;
+
+	/* create new id val to be a fixed offset from evsel id */
+	id = evsel->core.id[0] + 1000000000;
+	if (!id)
+		id = 1;
+
+	err = perf_session__deliver_synth_attr_event(session, &attr, id);
+	if (err)
+		return err;
+
+	htm->sample_id = id;
+	set_event_name(evlist, id, "htm");
+
+	return 0;
+}
+
 int powerpc_htm_process_auxtrace_info(union perf_event *event,
 				  struct perf_session *session)
 {
@@ -698,6 +800,10 @@ int powerpc_htm_process_auxtrace_info(union perf_event *event,
 	if (err)
 		goto err_free_queues;
 
+	err = powerpc_htm_synth_events(htm, session);
+	if (err)
+		goto err_free;
+
 	return 0;
 
 err_free_queues:
-- 
2.52.0



^ permalink raw reply related

* [PATCH 9/9] tools/perf/powerpc: Add logical address in decoded traces
From: Athira Rajeev @ 2026-07-01  8:41 UTC (permalink / raw)
  To: acme, jolsa, adrian.hunter, maddy, irogers, namhyung
  Cc: linux-perf-users, linuxppc-dev, atrajeev, hbathini, tejas05,
	tshah, venkat88
In-Reply-To: <20260701084115.80383-1-atrajeev@linux.ibm.com>

Enhance the post processing to translate physical addresses to logical
addresses in the decoded output. This improves debuggability by
allowing direct correlation with source code and debug symbols.

The decoder now creates a .l output file with logical addresses,
making it easier to analyze traces using symbol tables and debuggers.
LP index filtering is made optional when dumping traces to show all
addresses.

Add logical address translation in the post-processing step of
process_trace_file(). For each physical address found in the decoded
trace, find_logical_addr() is used to look up the corresponding
logical address from the mem_entries array. The translated output is
written to a new file with a ".l" suffix alongside the original
decoded trace file.

LP index filtering in find_logical_addr() is made optional via a
new 'filter' parameter. When running with dump_trace (perf script -D),
filtering is disabled so all addresses are translated regardless of
LP index. This ensures complete coverage when dumping traces for
analysis.

Example output files after decoding:
  htm.bin.n0.p2.c0.out   - decoded trace with physical addresses
  htm.bin.n0.p2.c0.out.l - decoded trace with logical addresses

Signed-off-by: Athira Rajeev <atrajeev@linux.ibm.com>
---
 tools/perf/util/powerpc-htm.c | 81 ++++++++++++++++++++++++++++++++---
 1 file changed, 74 insertions(+), 7 deletions(-)

diff --git a/tools/perf/util/powerpc-htm.c b/tools/perf/util/powerpc-htm.c
index 050fbceac71e..1bd2664453c6 100644
--- a/tools/perf/util/powerpc-htm.c
+++ b/tools/perf/util/powerpc-htm.c
@@ -202,7 +202,7 @@ static int add_map_entry(struct addr_map **arr, size_t *count, size_t *cap, stru
 static unsigned long find_logical_addr(unsigned long long given_addr,
 				struct mem_entries *mem_entries_array,
 				size_t n_entries,
-				u32 lp_filter)
+				u32 lp_filter, int filter)
 {
 	for (size_t i = 0; i < n_entries; i++) {
 		unsigned long long start = mem_entries_array[i].phy_addr & PHYS_ADDR_MASK;
@@ -221,11 +221,13 @@ static unsigned long find_logical_addr(unsigned long long given_addr,
 		 * If so, calculate:
 		 * 'offset' and the 'logical address
 		 */
-		if (start <= given_addr && given_addr < end &&
-			mem_entries_array[i].lp_index == lp_filter) {
+		if (start <= given_addr && given_addr < end) {
 			unsigned long long offset = given_addr - start;
 			unsigned long logical = mem_entries_array[i].logical_addr + offset;
 
+			if (filter && (mem_entries_array[i].lp_index != lp_filter))
+				continue;
+
 			pr_debug("DEBUG: Condition hit at i=%zu given_addr=0x%llx start=0x%llx end=0x%llx lp_index=%u\n",
 				i, given_addr,
 				start, end,
@@ -259,36 +261,60 @@ static struct addr_map *process_trace_file(const char *trace_file,
 	unsigned long logical_addr;
 	size_t total_phys = 0;
 	size_t total_phys_to_logical = 0;
-
 	FILE *fp = fopen(trace_file, "r");
+	size_t prefix_len;
+	int found_match = 0;
+	FILE *fout;
+	int filter_lp = 1;
+	char *output = malloc(strlen(trace_file) + 3);  /* +3 for ".l" and null */
+
+	if (!output) {
+		pr_err("Failed to allocate memory for output filename\n");
+		fclose(fp);
+		return NULL;
+	}
 
 	if (!fp) {
 		pr_err("Failed to open trace file %s: %s\n", trace_file, strerror(errno));
 		return NULL;
 	}
 
+	snprintf(output, strlen(trace_file) + 3, "%s.l", trace_file);
+	fout = fopen(output, "w");
+	if (!fout) {
+		pr_err("Failed to open trace output file: %s\n", output);
+		fclose(fp);
+		return NULL;
+	}
+
 	if (regcomp(&addr_regex, "addr:0x[0-9A-Fa-f]+", REG_EXTENDED) != 0) {
 		pr_err("Failed to compile addr_regex\n");
-		return NULL;
+		goto out;
 	}
 
 	if (regcomp(&label_regex,
 		   "^[[:space:]]*[0-9A-Fa-f]+ : [^[:space:]]+[[:space:]]+([^[:space:]]+)",
 		   REG_EXTENDED) != 0) {
 		pr_err("Failed to compile label_regex\n");
-		return NULL;
+		regfree(&addr_regex);
+		goto out;
 	}
 
 	maps = NULL;
 	count = 0;
 	cap = 0;
 
+	/* When dumping traces, show all addresses regardless of LP index */
+	if (dump_trace)
+		filter_lp = 0;
+
 	while (getline(&line, &len, fp) != -1) {
 		if (regexec(&label_regex, line, 2, pmatch, 0) == 0) {
 			char label[64] = {0};
 			int start = pmatch[1].rm_so;
 			int end   = pmatch[1].rm_eo;
 			int line_len   = end - start;
+			found_match = 0;
 
 			if (line_len < 0)
 				line_len = 0;
@@ -303,6 +329,10 @@ static struct addr_map *process_trace_file(const char *trace_file,
 			while (regexec(&addr_regex, ptr, 1, pmatch, 0) == 0) {
 				unsigned long long phys_addr = 0;
 				struct addr_map entry = {0};
+				char *hex_start = strstr(line, "addr:0x");
+				const char *target = "addr:0x";
+				char *old_val_ptr;
+				size_t written;
 
 				if (sscanf(ptr + pmatch[0].rm_so + strlen("addr:"),
 					  "%llx", &phys_addr) != 1) {
@@ -315,7 +345,30 @@ static struct addr_map *process_trace_file(const char *trace_file,
 				logical_addr = find_logical_addr(phys_addr,
 							mem_entries_array,
 							n_entries,
-							lp_filter);
+							lp_filter, filter_lp);
+				/* create output.txt with logical address */
+				if (dump_trace && hex_start) {
+					old_val_ptr = hex_start + strlen(target);
+					prefix_len = hex_start - line;
+					written = fwrite(line, 1, prefix_len, fout);
+					if (written != prefix_len) {
+						pr_err("Failed to write prefix to output file\n");
+						continue;
+					}
+					if (fprintf(fout, "addr:0x%llx\t", (unsigned long long)logical_addr) < 0) {
+						pr_err("Failed to write to output file\n");
+						continue;
+					}
+					while (*old_val_ptr != ' ' && *old_val_ptr != '\n' && *old_val_ptr != '\0') {
+						old_val_ptr++;
+					}
+					if (fprintf(fout, "%s", old_val_ptr) < 0) {
+						pr_err("Failed to write suffix to output file\n");
+						continue;
+					}
+					found_match = 1;
+				}
+
 				if (logical_addr == 0) {
 					ptr += pmatch[0].rm_eo;
 					continue;
@@ -335,6 +388,12 @@ static struct addr_map *process_trace_file(const char *trace_file,
 
 				ptr += pmatch[0].rm_eo;
 			}
+			if (dump_trace && (!found_match) && line) {
+				if (fprintf(fout, "%s", line) < 0) {
+					pr_err("Failed to write line to output file\n");
+					continue;
+				}
+			}
 		}
 	}
 
@@ -342,9 +401,17 @@ static struct addr_map *process_trace_file(const char *trace_file,
 	fclose(fp);
 	regfree(&addr_regex);
 	regfree(&label_regex);
+	fclose(fout);
+	free(output);
 
 	*count_out = count;
 	return maps;
+
+out:
+	fclose(fp);
+	fclose(fout);
+	free(output);
+	return NULL;
 }
 
 static int create_mem_maps(struct perf_session *session, struct powerpc_htm *htm)
-- 
2.52.0



^ permalink raw reply related

* Re: [PATCH v2 1/3] selftests/mm: handle EINVAL when configuring gigantic hugepages
From: David Hildenbrand (Arm) @ 2026-07-01  8:48 UTC (permalink / raw)
  To: Sayali Patil, Andrew Morton, Shuah Khan, linux-mm, linux-kernel,
	linux-kselftest, Ritesh Harjani
  Cc: Zi Yan, Michal Hocko, Oscar Salvador, Lorenzo Stoakes, Dev Jain,
	Liam.Howlett, linuxppc-dev, Miaohe Lin, Venkat Rao Bagalkote
In-Reply-To: <968b496a-a83e-491a-950c-3f6f975fa5f5@linux.ibm.com>

On 6/30/26 22:20, Sayali Patil wrote:
> 
> 
> On 30/06/26 16:15, David Hildenbrand (Arm) wrote:
>> On 6/30/26 11:32, Sayali Patil wrote:
>>> Some MM selftests attempt to configure the amount of
>>> HugeTLB pages of different sizes by writing to nr_hugepages.
>>>
>>> PowerPC hash MMU pSeries systems advertise gigantic hugepage sizes
>>> but do not support runtime allocation of such pages, writes
>>> to the corresponding nr_hugepages file fail with -EINVAL.
>>> This causes the test to bail out even though the failure is due
>>> to a platform limitation rather than the
>>> functionality being tested.
>>>
>>> Treat -EINVAL from the sysfs write as a skipped configuration request
>>> and continue running the test instead of failing.
>>>
>>> Before patch:
>>>     -------------------------
>>>     running ./hugetlb-madvise
>>>     -------------------------
>>>     TAP version 13
>>>     1..1
>>>       [INFO] detected hugetlb page size: 16777216 KiB
>>>       [INFO] detected hugetlb page size: 16384 KiB
>>>      ok 1 MADV_DONTNEED and MADV_REMOVE on hugetlb
>>>      Totals: pass:1 fail:0 xfail:0 xpass:0 skip:0 error:0
>>>      Bail out! /sys/kernel/mm/hugepages/hugepages-16777216kB/nr_hugepages
>>>      write(0) failed: Invalid argument
>>>      Totals: pass:0 fail:0 xfail:0 xpass:0 skip:0 error:0
>>>      [FAIL]
>>>
>>> After patch:
>>>     -------------------------
>>>     running ./hugetlb-madvise
>>>     -------------------------
>>>     TAP version 13
>>>     1..1
>>>      [INFO] detected hugetlb page size: 16777216 KiB
>>>      [INFO] detected hugetlb page size: 16384 KiB
>>>     ok 1 MADV_DONTNEED and MADV_REMOVE on hugetlb
>>>     Totals: pass:1 fail:0 xfail:0 xpass:0 skip:0 error:0
>>>     /sys/kernel/mm/hugepages/hugepages-16777216kB/nr_hugepages
>>>     write(0) failed: Invalid argument
>>>     [PASS]
>>>
>>> Fixes: 27477b28b74f ("selftests/mm: hugepage_settings: add APIs to get and
>>> set nr_hugepages")
>>> Signed-off-by: Sayali Patil <sayalip@linux.ibm.com>
>>> ---
>>>   .../testing/selftests/mm/hugepage_settings.c  | 32 ++++++++++++++++++-
>>>   .../testing/selftests/mm/hugepage_settings.h  |  1 +
>>>   2 files changed, 32 insertions(+), 1 deletion(-)
>>>
>>> diff --git a/tools/testing/selftests/mm/hugepage_settings.c b/tools/testing/
>>> selftests/mm/hugepage_settings.c
>>> index 2eab2110ac6a..ce38ae3da01a 100644
>>> --- a/tools/testing/selftests/mm/hugepage_settings.c
>>> +++ b/tools/testing/selftests/mm/hugepage_settings.c
>>> @@ -422,6 +422,36 @@ static void hugetlb_sysfs_path(char *buf, size_t buflen,
>>>            size / 1024, attr);
>>>   }
>>>   +void hugetlb_write_num(const char *path, unsigned long num)
>>> +{
>>> +    int fd, saved_errno;
>>> +    ssize_t numwritten;
>>> +    char buf[21];
>>> +
>>> +    sprintf(buf, "%lu", num);
>>> +
>>> +    fd = open(path, O_WRONLY);
>>> +    if (fd == -1)
>>> +        ksft_exit_fail_msg("%s open failed: %s\n", path, strerror(errno));
>>> +
>>> +    numwritten = write(fd, buf, strlen(buf));
>>> +    saved_errno = errno;
>>> +    close(fd);
>>> +    errno = saved_errno;
>>> +
>>> +    /* Treat EINVAL as a skipped configuration (e.g., unsupported gigantic
>>> pages) */
>>> +    if (numwritten < 0 && errno == EINVAL) {
>>> +        ksft_print_msg("%s write(%s) failed: %s\n", path, buf,
>>> strerror(errno));
>>
>> Should we even print anything here? Rather confusing. It's just like we cannot
>> allocate anything (no memory).
>>
>> In general, you are copy-pasting a lot of write_num()+write_file() content,
>> which is really suboptimal.
>>
>> All you want is an option for write_num -> write_file to skip on -EINVAL,
>> correct?
>>
>> There are not that many write_num / write_file users ...
>>
> 
> Hi David,
> 
> Yes, all I need is to ignore the expected -EINVAL when attempting to
> configure gigantic hugepages via nr_hugepages.
> 
> I looked at extending write_num()/write_file() for this as in v1
> (https://lore.kernel.org/
> all/8bfa921e30eb94072685103f6496784aa23bb166.1782365671.git.sayalip@linux.ibm.com/),
> but these helpers are shared by several other selftests.
> For example, write_file() is used by split_huge_page_test setup and by
> khugepaged tests for drop_caches, and is also used for various THP and
> khugepaged settings where -EINVAL would indicate a genuine setup
> failure. This concern was also raised during the v1 review.
> 
> Because the expected -EINVAL is specific to gigantic hugepage runtime
> allocation, I kept the handling local to the hugetlb setup path rather
> than changing the semantics of the common helpers.
> 
> I also agree that printing a message is not particularly useful in this
> case, and we can simply return without emitting any output.

We can either convert the functions to use flags, or hide it in some internal helpers, like the following:

From 1b1b8ad51f1f0be469cb191736300254b9521fe4 Mon Sep 17 00:00:00 2001
From: "David Hildenbrand (Arm)" <david@kernel.org>
Date: Wed, 1 Jul 2026 10:45:16 +0200
Subject: [PATCH] tmp

Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
---
 tools/testing/selftests/mm/vm_util.c | 28 ++++++++++++++++++++++++----
 tools/testing/selftests/mm/vm_util.h |  1 +
 2 files changed, 25 insertions(+), 4 deletions(-)

diff --git a/tools/testing/selftests/mm/vm_util.c b/tools/testing/selftests/mm/vm_util.c
index 311fc5b4513eb..362070f817e9b 100644
--- a/tools/testing/selftests/mm/vm_util.c
+++ b/tools/testing/selftests/mm/vm_util.c
@@ -719,7 +719,8 @@ int read_file(const char *path, char *buf, size_t buflen)
 	return (unsigned int) numread;
 }
 
-void write_file(const char *path, const char *buf, size_t buflen)
+static int __write_file(const char *path, const char *buf, size_t buflen,
+		bool ignore_einval)
 {
 	int fd, saved_errno;
 	ssize_t numwritten;
@@ -735,14 +736,23 @@ void write_file(const char *path, const char *buf, size_t buflen)
 	saved_errno = errno;
 	close(fd);
 	errno = saved_errno;
-	if (numwritten < 0)
+
+	if (numwritten < 0) {
+		if (ignore_einval && errno == EINVAL)
+			return;
 		ksft_exit_fail_msg("%s write(%.*s) failed: %s\n", path, (int)(buflen - 1),
 				buf, strerror(errno));
+	}
 	if (numwritten != buflen - 1)
 		ksft_exit_fail_msg("%s write(%.*s) is truncated, expected %zu bytes, got %zd bytes\n",
 				path, (int)(buflen - 1), buf, buflen - 1, numwritten);
 }
 
+static void write_file(const char *path, const char *buf, size_t buflen)
+{
+	__write_file(path, bug, buflen, /* ignore_einval = */ false);
+}
+
 unsigned long read_num(const char *path)
 {
 	char buf[21];
@@ -753,12 +763,22 @@ unsigned long read_num(const char *path)
 	return strtoul(buf, NULL, 10);
 }
 
-void write_num(const char *path, unsigned long num)
+static void __write_num(const char *path, unsigned long num, bool ignore_einval)
 {
 	char buf[21];
 
 	sprintf(buf, "%lu", num);
-	write_file(path, buf, strlen(buf) + 1);
+	write_file(path, buf, strlen(buf) + 1, ignore_einval);
+}
+
+void write_num(const char *path, unsigned long num)
+{
+	return __write_num(path, num, /* ignore_einval = */ false);
+}
+
+void write_num_ignore_einval(const char *path, unsigned long num)
+{
+	return __write_num(path, num, /* ignore_einval = */ true);
 }
 
 static unsigned long shmall, shmmax;
diff --git a/tools/testing/selftests/mm/vm_util.h b/tools/testing/selftests/mm/vm_util.h
index ea8fc8fdf0eb0..7799154b67eed 100644
--- a/tools/testing/selftests/mm/vm_util.h
+++ b/tools/testing/selftests/mm/vm_util.h
@@ -168,6 +168,7 @@ void write_file(const char *path, const char *buf, size_t buflen);
 int read_file(const char *path, char *buf, size_t buflen);
 unsigned long read_num(const char *path);
 void write_num(const char *path, unsigned long num);
+void write_num_ignore_einval(const char *path, unsigned long num);
 
 void shm_limits_prepare(unsigned long length);
 void __shm_limits_restore(void);
-- 
2.43.0


-- 
Cheers,

David


^ permalink raw reply related

* Re: [PATCH v3] powerpc/audit: Convert powerpc to AUDIT_ARCH_COMPAT_GENERIC
From: Christophe Leroy (CS GROUP) @ 2026-07-01  8:53 UTC (permalink / raw)
  To: Venkat Rao Bagalkote, Madhavan Srinivasan, Paul Moore
  Cc: Harsh Prateek Bora, Michael Ellerman, Nicholas Piggin, Eric Paris,
	linux-kernel, linuxppc-dev, audit, Thomas Weissschuh,
	Cédric Le Goater, ritesh.list
In-Reply-To: <50507bb3-4229-4815-90e8-c01eaad058fc@linux.ibm.com>



Le 01/07/2026 à 10:09, Venkat Rao Bagalkote a écrit :
> 
> On 01/07/26 10:26 am, Christophe Leroy (CS GROUP) wrote:
>>
>>
>> Le 01/07/2026 à 06:32, Venkat Rao Bagalkote a écrit :
>>>
>>> On 01/07/26 7:44 am, Madhavan Srinivasan wrote:
>>>>
>>>> On 7/1/26 12:41 AM, Paul Moore wrote:
>>>>> On Wed, May 13, 2026 at 1:42 AM Madhavan Srinivasan 
>>>>> <maddy@linux.ibm.com> wrote:
>>>>>> On 5/13/26 10:05 AM, Harsh Prateek Bora wrote:
>>>>>>> On 11/03/26 12:49 am, Paul Moore wrote:
>>>>>>>> On Tue, Mar 10, 2026 at 11:08 AM Christophe Leroy (CS GROUP)
>>>>>>>> <chleroy@kernel.org> wrote:
>>>>>>>>> From: Christophe Leroy <christophe.leroy@csgroup.eu>
>>>>>>>>>
>>>>>>>>> Commit e65e1fc2d24b ("[PATCH] syscall class hookup for all normal
>>>>>>>>> targets") added generic support for AUDIT but that didn't include
>>>>>>>>> support for bi-arch like powerpc.
>>>>>>>>>
>>>>>>>>> Commit 4b58841149dc ("audit: Add generic compat syscall support")
>>>>>>>>> added generic support for bi-arch.
>>>>>>>>>
>>>>>>>>> Convert powerpc to that bi-arch generic audit support.
>>>>>>>>>
>>>>>>>>> With this change generated text is similar.
>>>>>>>>>
>>>>>>>>> Thomas has confirmed that the previously failing 
>>>>>>>>> filter_exclude/test
>>>>>>>>> is now successful both without and with this patch, see [1]
>>>>>>>>>
>>>>>>>>> [1]
>>>>>>>>> https://eur01.safelinks.protection.outlook.com/? 
>>>>>>>>> url=https%3A%2F%2Flore.kernel.org%2Fall%2F20260306115350- 
>>>>>>>>> ef265661-6d6b-4043-9bd0-8e6b437d0d67%40linutronix.de%2F&data=05%7C02%7Cchristophe.leroy%40csgroup.eu%7C81e1e4e3bae245103d3308ded729bb47%7C8b87af7d86474dc78df45f69a2011bb5%7C0%7C0%7C639184771399964577%7CUnknown%7CTWFpbGZsb3d8eyJFbXB0eU1hcGkiOnRydWUsIlYiOiIwLjAuMDAwMCIsIlAiOiJXaW4zMiIsIkFOIjoiTWFpbCIsIldUIjoyfQ%3D%3D%7C0%7C%7C%7C&sdata=%2FtCHXFR5np67gntCnXqv7Eemo5WuwaIEcywxZQzDADA%3D&reserved=0
>>>>>>>>>
>>>>>>>>> Link: https://eur01.safelinks.protection.outlook.com/? 
>>>>>>>>> url=https%3A%2F%2Fgithub.com%2Flinuxppc%2Fissues%2Fissues%2F412&data=05%7C02%7Cchristophe.leroy%40csgroup.eu%7C81e1e4e3bae245103d3308ded729bb47%7C8b87af7d86474dc78df45f69a2011bb5%7C0%7C0%7C639184771400190794%7CUnknown%7CTWFpbGZsb3d8eyJFbXB0eU1hcGkiOnRydWUsIlYiOiIwLjAuMDAwMCIsIlAiOiJXaW4zMiIsIkFOIjoiTWFpbCIsIldUIjoyfQ%3D%3D%7C0%7C%7C%7C&sdata=4fPEX7HuGBcxOcXlcJVQvDdP7Y9InhDpbz3z%2BS9lkCQ%3D&reserved=0
>>>>>>>>> Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
>>>>>>>>> Reviewed-by: Cédric Le Goater <clg@kaod.org>
>>>>>>>>> ---
>>>>>>>>> Venkat, a test result with
>>>>>>>>> https://eur01.safelinks.protection.outlook.com/? 
>>>>>>>>> url=https%3A%2F%2Fgithub.com%2Flinux-audit%2Faudit- 
>>>>>>>>> testsuite&data=05%7C02%7Cchristophe.leroy%40csgroup.eu%7C81e1e4e3bae245103d3308ded729bb47%7C8b87af7d86474dc78df45f69a2011bb5%7C0%7C0%7C639184771400214912%7CUnknown%7CTWFpbGZsb3d8eyJFbXB0eU1hcGkiOnRydWUsIlYiOiIwLjAuMDAwMCIsIlAiOiJXaW4zMiIsIkFOIjoiTWFpbCIsIldUIjoyfQ%3D%3D%7C0%7C%7C%7C&sdata=yHp3p5zNx%2BqQg2cKBsKJADWcUcKVtZstzNScBfWzF%2FQ%3D&reserved=0 would be appreciated.
>>>>>>>> Yes, I'd like to see confirmation that the audit test suite runs 
>>>>>>>> clean
>>>>>>>> on ppc systems with this patch applied, and unfortunately without a
>>>>>>>> ppc system I have no way to test this myself.
>>>>>> My bad, this is a miss from my end.
>>>>>> Venkat is already on this and will update the results here.
>>>>> Do we have an update on this?  Maybe I missed it, but I don't recall
>>>>> seeing any test results.
>>>> Venkat, did run the test but I guess he missed to respond here,
>>>> Details of his test run that he shared me in the internal chat from 
>>>> May 13.
>>>
>>>
>>> Sorry, My bad. I missed updating here. Yes, this was tested in May. 
>>> Please let me know, if a re-run is required?
>>
>> It looks like netcat (https://eur01.safelinks.protection.outlook.com/? 
>> url=https%3A%2F%2Flinux.die.net%2Fman%2F1%2Fnc&data=05%7C02%7Cchristophe.leroy%40csgroup.eu%7C97ac234e82884f729d1508ded7480f62%7C8b87af7d86474dc78df45f69a2011bb5%7C0%7C0%7C639184901648983046%7CUnknown%7CTWFpbGZsb3d8eyJFbXB0eU1hcGkiOnRydWUsIlYiOiIwLjAuMDAwMCIsIlAiOiJXaW4zMiIsIkFOIjoiTWFpbCIsIldUIjoyfQ%3D%3D%7C0%7C%7C%7C&sdata=18PJTLp9ozMqSkWWvBZmtjzjTI355Oq%2F5aqmU6zCiZE%3D&reserved=0) is not installed in you setup. Are you able to install it and rerun the test ?
> 
> 
> I investigated the failure on the RHEL 10 ppc64le test system.
> 
> 
> The netfilter_pkt failure is due to missing userspace dependencies:
> 
> Can't exec "nc": No such file or directory
> Can't exec "iptables": No such file or directory
> Can't exec "ip6tables": No such file or directory
> 
> I checked the system and confirmed that nc, ncat, iptables, and 
> ip6tables are not installed:
> 
> 
> which nc
> which ncat
> which iptables
> which ip6tables
> 
> 
> all return "not found".
> 
> The system has nftables installed (/usr/sbin/nft), but I was unable to 
> locate packages providing nc/ncat or iptables/ip6tables in the currently 
> enabled repositories (epel, rh10_base, rh10_app, rh10_crb).

Found:
- 
https://dl.fedoraproject.org/pub/epel/10/Everything/ppc64le/Packages/n/netcat-1.238-1.el10_3.ppc64le.rpm
- 
https://rpmfind.net/linux/RPM/almalinux-kitten/10/baseos/ppc64le/iptables-nft-1.8.11-6.el10.ppc64le.html
- 
https://www.rpmfind.net/linux/RPM/centos-stream/10/appstream/ppc64le/iptables-devel-1.8.11-14.el10.ppc64le.html

Does it help ?

Christophe

> 
> 
> At this point, the remaining failure appears to be an environmental 
> dependency issue rather than a test failure. Please let me know if there 
> is a recommended package/repository for EL10 ppc64le that provides 
> netcat and iptables compatibility tools, and I can re-run the test.
> 
> 
> Regards,
> 
> Venkat.
> 
>>
>> Thanks
>> Christophe
>>
>>>
>>> Regards,
>>>
>>> Venkat.
>>>
>>>>
>>>> backlog_wait_time_actual_reset/test .. ok
>>>> bpf/test ............................. ok
>>>> exec_execve/test ..................... ok
>>>> exec_name/test ....................... ok
>>>> fanotify/test ........................ ok
>>>> field_compare/test ................... ok
>>>> file_create/test ..................... ok
>>>> file_delete/test ..................... ok
>>>> file_permission/test ................. ok
>>>> file_rename/test ..................... ok
>>>> filter_exclude/test .................. ok
>>>> filter_exit/test ..................... ok
>>>> filter_saddr_fam/test ................ ok
>>>> filter_sessionid/test ................ ok
>>>> io_uring/test ........................ ok
>>>> login_tty/test ....................... ok
>>>> lost_reset/test ...................... ok
>>>> netfilter_pkt/test ................... Can't exec "nc": No such file 
>>>> or directory at netfilter_pkt/test line 83.
>>>>
>>>> Venkat, can you please re-run if possible and paste the log here.
>>>>
>>>> Thanks
>>>> Maddy
>>>>
>>>>
>>



^ permalink raw reply

* Re: [PATCH v2 0/8] powerpc/signal: Convert to scoped user access
From: Christophe Leroy (CS GROUP) @ 2026-07-01  8:58 UTC (permalink / raw)
  To: Michael Ellerman, Nicholas Piggin, Madhavan Srinivasan
  Cc: linux-kernel, linuxppc-dev
In-Reply-To: <cover.1780389863.git.chleroy@kernel.org>



Le 02/06/2026 à 10:46, Christophe Leroy (CS GROUP) a écrit :
> This series converts powerpc architecture signal handling to scoped
> user access and enlarges some of the block accesses to minimise the
> number of times user access has to be opened and closed.
> 
> As mentioned in individual patches, some bring real performance
> improvement.
> 
> This series is built from previous series [1] which predates
> implementation of scoped user access.
> 
> [1] https://lore.kernel.org/all/1718f38859d5366f82d5bef531f255cedf537b5d.1631861883.git.christophe.leroy@csgroup.eu/T/#t

Sashiko made relevant comments, I need to rework this series.

> 
> Changes in v2:
> - Add a stub setup_tm_sigcontexts() for when CONFIG_PPC_TRANSACTIONAL_MEM is not set in patch 2
> 
> Christophe Leroy (CS GROUP) (8):
>    powerpc/signal32: Convert to scoped user access
>    powerpc/signal64: Untangle setup_tm_sigcontexts() and
>      user_access_begin()
>    powerpc/signal64: Convert to scoped user access
>    powerpc/signal64: Access function descriptor with scoped user access
>    powerpc/signal: Include the new stack frame inside the user access
>      block
>    signal: Add unsafe_copy_siginfo_to_user()
>    powerpc/uaccess: Add unsafe_clear_user()
>    powerpc/signal: Use unsafe_copy_siginfo_to_user()
> 
>   arch/powerpc/include/asm/uaccess.h |  20 ++
>   arch/powerpc/kernel/signal_32.c    | 498 ++++++++++++++---------------
>   arch/powerpc/kernel/signal_64.c    | 138 ++++----
>   include/linux/signal.h             |  15 +
>   include/linux/uaccess.h            |   1 +
>   kernel/signal.c                    |   5 -
>   6 files changed, 334 insertions(+), 343 deletions(-)
> 

--
pw-bot: cr




^ permalink raw reply

* Re: [PATCH] powerpc/dt_cpu_ftrs: Avoid separate strlen() in scan_callback()
From: David Laight @ 2026-06-30 17:38 UTC (permalink / raw)
  To: Thorsten Blum
  Cc: Madhavan Srinivasan, Michael Ellerman, Nicholas Piggin,
	Christophe Leroy (CS GROUP), linuxppc-dev, linux-kernel
In-Reply-To: <20260630154657.693088-2-thorsten.blum@linux.dev>

On Tue, 30 Jun 2026 17:46:56 +0200
Thorsten Blum <thorsten.blum@linux.dev> wrote:

> Use the return value of strscpy() when copying the display name instead
> of checking the source string length with strlen() first.
> 
> Keep dt_cpu_name static but move it into dt_cpu_ftrs_scan_callback(),
> where it is assigned.
> 
> Signed-off-by: Thorsten Blum <thorsten.blum@linux.dev>
> ---
>  arch/powerpc/kernel/dt_cpu_ftrs.c | 7 ++-----
>  1 file changed, 2 insertions(+), 5 deletions(-)
> 
> diff --git a/arch/powerpc/kernel/dt_cpu_ftrs.c b/arch/powerpc/kernel/dt_cpu_ftrs.c
> index 3af6c06af02f..8d8e94e4d2bc 100644
> --- a/arch/powerpc/kernel/dt_cpu_ftrs.c
> +++ b/arch/powerpc/kernel/dt_cpu_ftrs.c
> @@ -90,8 +90,6 @@ static void __restore_cpu_cpufeatures(void)
>  		init_pmu_registers();
>  }
>  
> -static char dt_cpu_name[64];
> -
>  static struct cpu_spec __initdata base_cpu_spec = {
>  	.cpu_name		= NULL,
>  	.cpu_features		= CPU_FTRS_DT_CPU_BASE,
> @@ -1069,6 +1067,7 @@ static int __init count_cpufeatures_subnodes(unsigned long node,
>  static int __init dt_cpu_ftrs_scan_callback(unsigned long node, const char
>  					    *uname, int depth, void *data)
>  {
> +	static char dt_cpu_name[64];
>  	const __be32 *prop;
>  	int count, i;
>  	u32 isa;
> @@ -1106,10 +1105,8 @@ static int __init dt_cpu_ftrs_scan_callback(unsigned long node, const char
>  	}
>  
>  	prop = of_get_flat_dt_prop(node, "display-name", NULL);
> -	if (prop && strlen((char *)prop) != 0) {
> -		strscpy(dt_cpu_name, (char *)prop, sizeof(dt_cpu_name));
> +	if (prop && strscpy(dt_cpu_name, (char *)prop) != 0)

That is different code.
The old code only did the copy if the new string was non-empty.
So you want to replace the strlen() with *(char *)prop != 0.
Checks for strlen() == 0 are silly (but surprisingly common).
A search might show up this gem:
	str[strlen(str)] = 0;

-- David


>  		cur_cpu_spec->cpu_name = dt_cpu_name;
> -	}
>  
>  	cpufeatures_setup_finished();
>  
> 



^ permalink raw reply

* [PATCH] Connecting the SB600's i8259 controller rather in pasemi's pci.c than in pasemi's setup.c.
From: Christian Zigotzky @ 2026-07-01 10:54 UTC (permalink / raw)
  To: Madhavan Srinivasan, Michael Ellerman, Nicholas Piggin,
	Christophe Leroy (CS GROUP), Christian Zigotzky,
	Krzysztof Kozlowski,
	open list:LINUX FOR POWERPC (32-BIT AND 64-BIT), open list

 "pas_pci_init" was before "nemo_init_IRQ".
 Now "pas_pci_init" is after "nemo_init_IRQ" in the official kernel source
 code.
 I think "pas_pci_init" scans (discovers) the PCI(e) devices
 and after that, "nemo_init_IRQ" assigns interrupt numbers
 to these devices if required.
 It's not possible to assigns interrupt numbers to PCI(e) devices
 which have not been discovered yet.

Signed-off-by: Christian Zigotzky <chzigotzky@xenosoft.de>
---
 arch/powerpc/platforms/pasemi/pci.c   | 7 +++++++
 arch/powerpc/platforms/pasemi/setup.c | 7 ++++---
 2 files changed, 11 insertions(+), 3 deletions(-)

diff --git a/arch/powerpc/platforms/pasemi/pci.c b/arch/powerpc/platforms/pasemi/pci.c
index 2df955274652..7208c325bfc5 100644
--- a/arch/powerpc/platforms/pasemi/pci.c
+++ b/arch/powerpc/platforms/pasemi/pci.c
@@ -25,6 +25,8 @@
 
 #define PA_PXP_CFA(bus, devfn, off) (((bus) << 20) | ((devfn) << 12) | (off))
 
+extern void nemo_init_IRQ(void);
+
 static inline int pa_pxp_offset_valid(u8 bus, u8 devfn, int offset)
 {
 	/* Device 0 Function 0 is special: It's config space spans function 1 as
@@ -265,6 +267,11 @@ static int __init pas_add_bridge(struct device_node *dev)
 	 */
 	isa_bridge_find_early(hose);
 
+	/*
+	 * ISA bridge is now active, add the i8259 cascade (if needed)
+	 */
+	nemo_init_IRQ();
+
 	return 0;
 }
 
diff --git a/arch/powerpc/platforms/pasemi/setup.c b/arch/powerpc/platforms/pasemi/setup.c
index d03b41336901..eec74611be46 100644
--- a/arch/powerpc/platforms/pasemi/setup.c
+++ b/arch/powerpc/platforms/pasemi/setup.c
@@ -214,10 +214,12 @@ static void sb600_8259_cascade(struct irq_desc *desc)
 	chip->irq_eoi(&desc->irq_data);
 }
 
-static void __init nemo_init_IRQ(struct mpic *mpic)
+void nemo_init_IRQ(void)
 {
 	struct device_node *np;
 	int gpio_virq;
+	struct mpic *mpic;
+
 	/* Connect the SB600's legacy i8259 controller */
 	np = of_find_node_by_path("/pxp@0,e0000000");
 	i8259_init(np, 0);
@@ -228,6 +230,7 @@ static void __init nemo_init_IRQ(struct mpic *mpic)
 	irq_set_chained_handler(gpio_virq, sb600_8259_cascade);
 	mpic_unmask_irq(irq_get_irq_data(gpio_virq));
 
+	mpic = irq_get_chip_data(gpio_virq);
 	irq_set_default_domain(mpic->irqhost);
 }
 
@@ -298,8 +301,6 @@ static __init void pas_init_IRQ(void)
 		mpic_unmask_irq(irq_get_irq_data(nmi_virq));
 	}
 
-	nemo_init_IRQ(mpic);
-
 	of_node_put(mpic_node);
 	of_node_put(root);
 }
-- 
2.55.0.windows.1



^ permalink raw reply related

* Re: [PATCH] Connecting the SB600's i8259 controller rather in pasemi's pci.c than in pasemi's setup.c.
From: Christian Zigotzky @ 2026-07-01 11:14 UTC (permalink / raw)
  To: Christian Zigotzky, Krzysztof Kozlowski, Madhavan Srinivasan,
	Michael Ellerman, linux-kernel, Nicholas Piggin, linuxppc-dev,
	Christophe Leroy
  Cc: Darren Stevens, R.T.Dickinson, hypexed
In-Reply-To: <20260701105501.2093-1-chzigotzky@xenosoft.de>

[-- Attachment #1: Type: text/plain, Size: 4024 bytes --]


The Nemo board [1] doesn’t boot without this patch. Darren explained it really well:

Originally we initialised the PCI-e ports in setup arch, this is quite early, and it seems uses some kernel functions that were not recommended (They changed a whole lot of different platforms at the same time for the same reason)

After this we added the ISA bridge, then the kernel would init the IRQ contollers.

The patch that broke booting on the X1000 moved the pas_pci_init to a node in the machine description, where it called later in the boot sequence. Unfortunately this is after we've tried to add the i8259 contoller from the pas_init_IRQ. Since our ISA bridge can't be found until we've connected the PCI-e ports the system tries to write to registers that aren't yet mapped - result a kernel panic, but before console I/O has been initialised so it appears to be a hang. We had a similar problem when they were introducing Radix support.

My patch changes our code so that it works with the new kernel code in place. Basically I moved the code that adds the i8259 cascade to after we've scanned for the ISA bridge where I know it will work.

Hopefully this makes sense, shout out if it doesn't

Regards
Darren

[1] https://en.wikipedia.org/wiki/AmigaOne_X1000

> On 01 July 2026 at 12:55 pm, Christian Zigotzky <chzigotzky@xenosoft.de> wrote :
> 
>  "pas_pci_init" was before "nemo_init_IRQ".
> Now "pas_pci_init" is after "nemo_init_IRQ" in the official kernel source
> code.
> I think "pas_pci_init" scans (discovers) the PCI(e) devices
> and after that, "nemo_init_IRQ" assigns interrupt numbers
> to these devices if required.
> It's not possible to assigns interrupt numbers to PCI(e) devices
> which have not been discovered yet.
> 
> Signed-off-by: Christian Zigotzky <chzigotzky@xenosoft.de>
> ---
> arch/powerpc/platforms/pasemi/pci.c   | 7 +++++++
> arch/powerpc/platforms/pasemi/setup.c | 7 ++++---
> 2 files changed, 11 insertions(+), 3 deletions(-)
> 
> diff --git a/arch/powerpc/platforms/pasemi/pci.c b/arch/powerpc/platforms/pasemi/pci.c
> index 2df955274652..7208c325bfc5 100644
> --- a/arch/powerpc/platforms/pasemi/pci.c
> +++ b/arch/powerpc/platforms/pasemi/pci.c
> @@ -25,6 +25,8 @@
> 
> #define PA_PXP_CFA(bus, devfn, off) (((bus) << 20) | ((devfn) << 12) | (off))
> 
> +extern void nemo_init_IRQ(void);
> +
> static inline int pa_pxp_offset_valid(u8 bus, u8 devfn, int offset)
> {
>    /* Device 0 Function 0 is special: It's config space spans function 1 as
> @@ -265,6 +267,11 @@ static int __init pas_add_bridge(struct device_node *dev)
>     */
>    isa_bridge_find_early(hose);
> 
> +    /*
> +     * ISA bridge is now active, add the i8259 cascade (if needed)
> +     */
> +    nemo_init_IRQ();
> +
>    return 0;
> }
> 
> diff --git a/arch/powerpc/platforms/pasemi/setup.c b/arch/powerpc/platforms/pasemi/setup.c
> index d03b41336901..eec74611be46 100644
> --- a/arch/powerpc/platforms/pasemi/setup.c
> +++ b/arch/powerpc/platforms/pasemi/setup.c
> @@ -214,10 +214,12 @@ static void sb600_8259_cascade(struct irq_desc *desc)
>    chip->irq_eoi(&desc->irq_data);
> }
> 
> -static void __init nemo_init_IRQ(struct mpic *mpic)
> +void nemo_init_IRQ(void)
> {
>    struct device_node *np;
>    int gpio_virq;
> +    struct mpic *mpic;
> +
>    /* Connect the SB600's legacy i8259 controller */
>    np = of_find_node_by_path("/pxp@0,e0000000");
>    i8259_init(np, 0);
> @@ -228,6 +230,7 @@ static void __init nemo_init_IRQ(struct mpic *mpic)
>    irq_set_chained_handler(gpio_virq, sb600_8259_cascade);
>    mpic_unmask_irq(irq_get_irq_data(gpio_virq));
> 
> +    mpic = irq_get_chip_data(gpio_virq);
>    irq_set_default_domain(mpic->irqhost);
> }
> 
> @@ -298,8 +301,6 @@ static __init void pas_init_IRQ(void)
>        mpic_unmask_irq(irq_get_irq_data(nmi_virq));
>    }
> 
> -    nemo_init_IRQ(mpic);
> -
>    of_node_put(mpic_node);
>    of_node_put(root);
> }
> --
> 2.55.0.windows.1
> 

[-- Attachment #2: Type: text/html, Size: 5950 bytes --]

^ permalink raw reply

* [PATCH v2] powerpc/dt_cpu_ftrs: Avoid separate strlen() in scan_callback()
From: Thorsten Blum @ 2026-07-01 11:44 UTC (permalink / raw)
  To: Madhavan Srinivasan, Michael Ellerman, Nicholas Piggin,
	Christophe Leroy (CS GROUP)
  Cc: David Laight, Thorsten Blum, linuxppc-dev, linux-kernel

Check only the first byte instead of scanning the entire string with
strlen().  While at it, keep dt_cpu_name static, but move it into
dt_cpu_ftrs_scan_callback(), where it is assigned.

Signed-off-by: Thorsten Blum <thorsten.blum@linux.dev>
---
Changes in v2:
- Check only the first byte since strscpy() copies empty strings (David)
- v1: https://lore.kernel.org/lkml/20260630154657.693088-2-thorsten.blum@linux.dev/
---
 arch/powerpc/kernel/dt_cpu_ftrs.c | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/arch/powerpc/kernel/dt_cpu_ftrs.c b/arch/powerpc/kernel/dt_cpu_ftrs.c
index 3af6c06af02f..4f0799c8daa9 100644
--- a/arch/powerpc/kernel/dt_cpu_ftrs.c
+++ b/arch/powerpc/kernel/dt_cpu_ftrs.c
@@ -90,8 +90,6 @@ static void __restore_cpu_cpufeatures(void)
 		init_pmu_registers();
 }
 
-static char dt_cpu_name[64];
-
 static struct cpu_spec __initdata base_cpu_spec = {
 	.cpu_name		= NULL,
 	.cpu_features		= CPU_FTRS_DT_CPU_BASE,
@@ -1069,6 +1067,7 @@ static int __init count_cpufeatures_subnodes(unsigned long node,
 static int __init dt_cpu_ftrs_scan_callback(unsigned long node, const char
 					    *uname, int depth, void *data)
 {
+	static char dt_cpu_name[64];
 	const __be32 *prop;
 	int count, i;
 	u32 isa;
@@ -1106,8 +1105,8 @@ static int __init dt_cpu_ftrs_scan_callback(unsigned long node, const char
 	}
 
 	prop = of_get_flat_dt_prop(node, "display-name", NULL);
-	if (prop && strlen((char *)prop) != 0) {
-		strscpy(dt_cpu_name, (char *)prop, sizeof(dt_cpu_name));
+	if (prop && *(char *)prop != 0) {
+		strscpy(dt_cpu_name, (char *)prop);
 		cur_cpu_spec->cpu_name = dt_cpu_name;
 	}
 


^ permalink raw reply related

* Re: [PATCH] powerpc/dt_cpu_ftrs: Avoid separate strlen() in scan_callback()
From: Thorsten Blum @ 2026-07-01 11:48 UTC (permalink / raw)
  To: David Laight
  Cc: Madhavan Srinivasan, Michael Ellerman, Nicholas Piggin,
	Christophe Leroy (CS GROUP), linuxppc-dev, linux-kernel
In-Reply-To: <20260630183810.3287d10d@pumpkin>

On Tue, Jun 30, 2026 at 06:38:10PM +0100, David Laight wrote:
> On Tue, 30 Jun 2026 17:46:56 +0200
> Thorsten Blum <thorsten.blum@linux.dev> wrote:
> 
> > Use the return value of strscpy() when copying the display name instead
> > of checking the source string length with strlen() first.
> > 
> > Keep dt_cpu_name static but move it into dt_cpu_ftrs_scan_callback(),
> > where it is assigned.
> > 
> > Signed-off-by: Thorsten Blum <thorsten.blum@linux.dev>
> > ---
> >  arch/powerpc/kernel/dt_cpu_ftrs.c | 7 ++-----
> >  1 file changed, 2 insertions(+), 5 deletions(-)
> > 
> > diff --git a/arch/powerpc/kernel/dt_cpu_ftrs.c b/arch/powerpc/kernel/dt_cpu_ftrs.c
> > index 3af6c06af02f..8d8e94e4d2bc 100644
> > --- a/arch/powerpc/kernel/dt_cpu_ftrs.c
> > +++ b/arch/powerpc/kernel/dt_cpu_ftrs.c
> > @@ -90,8 +90,6 @@ static void __restore_cpu_cpufeatures(void)
> >  		init_pmu_registers();
> >  }
> >  
> > -static char dt_cpu_name[64];
> > -
> >  static struct cpu_spec __initdata base_cpu_spec = {
> >  	.cpu_name		= NULL,
> >  	.cpu_features		= CPU_FTRS_DT_CPU_BASE,
> > @@ -1069,6 +1067,7 @@ static int __init count_cpufeatures_subnodes(unsigned long node,
> >  static int __init dt_cpu_ftrs_scan_callback(unsigned long node, const char
> >  					    *uname, int depth, void *data)
> >  {
> > +	static char dt_cpu_name[64];
> >  	const __be32 *prop;
> >  	int count, i;
> >  	u32 isa;
> > @@ -1106,10 +1105,8 @@ static int __init dt_cpu_ftrs_scan_callback(unsigned long node, const char
> >  	}
> >  
> >  	prop = of_get_flat_dt_prop(node, "display-name", NULL);
> > -	if (prop && strlen((char *)prop) != 0) {
> > -		strscpy(dt_cpu_name, (char *)prop, sizeof(dt_cpu_name));
> > +	if (prop && strscpy(dt_cpu_name, (char *)prop) != 0)
> 
> That is different code.
> The old code only did the copy if the new string was non-empty.

Good catch, thanks!

I just sent a v2:
https://lore.kernel.org/lkml/20260701114428.818748-3-thorsten.blum@linux.dev/


^ permalink raw reply

* Re: [PATCH v2 4/9] arm64: vdso32: Respect COMPAT_32BIT_TIME
From: Philippe Mathieu-Daudé @ 2026-07-01  7:49 UTC (permalink / raw)
  To: Thomas Weißschuh, Andy Lutomirski, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, Dave Hansen, x86, H. Peter Anvin,
	Russell King, Catalin Marinas, Will Deacon, Madhavan Srinivasan,
	Michael Ellerman, Nicholas Piggin, Christophe Leroy (CS GROUP),
	Thomas Bogendoerfer, Vincenzo Frascino, John Stultz, Stephen Boyd,
	David S. Miller, Andreas Larsson
  Cc: linux-kernel, linux-arm-kernel, linuxppc-dev, linux-mips,
	Arnd Bergmann, linux-api, sparclinux
In-Reply-To: <20260630-vdso-compat_32bit_time-v2-4-520d194640dd@linutronix.de>

On 30/6/26 09:38, Thomas WeiÃschuh wrote:
> If CONFIG_COMPAT_32BIT_TIME is disabled then the vDSO should not
> provide any 32-bit time related functionality. This is the intended
> effect of the kconfig option and also the fallback system calls would
> also not be implemented.
> 
> Currently the kconfig option does not affect the gettimeofday() syscall,
> so also keep that in the vDSO.
> 
> Signed-off-by: Thomas Weißschuh <thomas.weissschuh@linutronix.de>
> ---
>   arch/arm64/kernel/vdso32/vdso.lds.S      |  2 ++
>   arch/arm64/kernel/vdso32/vgettimeofday.c | 14 ++++++++------
>   2 files changed, 10 insertions(+), 6 deletions(-)

Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>


^ permalink raw reply

* Re: [PATCH v2 5/9] ARM: VDSO: Respect COMPAT_32BIT_TIME
From: Philippe Mathieu-Daudé @ 2026-07-01  7:49 UTC (permalink / raw)
  To: Thomas Weißschuh, Andy Lutomirski, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, Dave Hansen, x86, H. Peter Anvin,
	Russell King, Catalin Marinas, Will Deacon, Madhavan Srinivasan,
	Michael Ellerman, Nicholas Piggin, Christophe Leroy (CS GROUP),
	Thomas Bogendoerfer, Vincenzo Frascino, John Stultz, Stephen Boyd,
	David S. Miller, Andreas Larsson
  Cc: linux-kernel, linux-arm-kernel, linuxppc-dev, linux-mips,
	Arnd Bergmann, linux-api, sparclinux
In-Reply-To: <20260630-vdso-compat_32bit_time-v2-5-520d194640dd@linutronix.de>

On 30/6/26 09:38, Thomas WeiÃschuh wrote:
> If CONFIG_COMPAT_32BIT_TIME is disabled then the vDSO should not
> provide any 32-bit time related functionality. This is the intended
> effect of the kconfig option and also the fallback system calls would
> also not be implemented.
> 
> Currently the kconfig option does not affect the gettimeofday() syscall,
> so also keep that in the vDSO.
> 
> Signed-off-by: Thomas Weißschuh <thomas.weissschuh@linutronix.de>
> ---
>   arch/arm/vdso/vdso.lds.S      |  2 ++
>   arch/arm/vdso/vgettimeofday.c | 14 ++++++++------
>   2 files changed, 10 insertions(+), 6 deletions(-)

Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>


^ permalink raw reply

* Re: [PATCH v2 8/9] sparc: vdso: Respect COMPAT_32BIT_TIME
From: Philippe Mathieu-Daudé @ 2026-07-01  7:50 UTC (permalink / raw)
  To: Thomas Weißschuh, Andy Lutomirski, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, Dave Hansen, x86, H. Peter Anvin,
	Russell King, Catalin Marinas, Will Deacon, Madhavan Srinivasan,
	Michael Ellerman, Nicholas Piggin, Christophe Leroy (CS GROUP),
	Thomas Bogendoerfer, Vincenzo Frascino, John Stultz, Stephen Boyd,
	David S. Miller, Andreas Larsson
  Cc: linux-kernel, linux-arm-kernel, linuxppc-dev, linux-mips,
	Arnd Bergmann, linux-api, sparclinux
In-Reply-To: <20260630-vdso-compat_32bit_time-v2-8-520d194640dd@linutronix.de>

On 30/6/26 09:38, Thomas WeiÃschuh wrote:
> If CONFIG_COMPAT_32BIT_TIME is disabled then the vDSO should not
> provide any 32-bit time related functionality. This is the intended
> effect of the kconfig option and also the fallback system calls would
> also not be implemented.
> 
> Currently the kconfig option does not affect the gettimeofday() syscall,
> so also keep that in the vDSO.
> 
> Signed-off-by: Thomas Weißschuh <thomas.weissschuh@linutronix.de>
> ---
>   arch/sparc/vdso/vclock_gettime.c    | 4 ++++
>   arch/sparc/vdso/vdso32/vdso32.lds.S | 6 ++++--
>   2 files changed, 8 insertions(+), 2 deletions(-)

Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>


^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox