* Re: [PATCH] PCI: aspeed: Fix IRQ domain leak on platform_get_irq() failure
From: Manivannan Sadhasivam @ 2026-04-04 10:35 UTC (permalink / raw)
To: Jacky Chou, Lorenzo Pieralisi, Krzysztof Wilczyński,
Rob Herring, Bjorn Helgaas, Joel Stanley, Andrew Jeffery,
Felix Gu
Cc: linux-aspeed, linux-pci, linux-arm-kernel, linux-kernel
In-Reply-To: <20260324-aspeed-v1-1-354181624c00@gmail.com>
On Tue, 24 Mar 2026 01:57:59 +0800, Felix Gu wrote:
> The aspeed_pcie_probe() function calls aspeed_pcie_init_irq_domain()
> which allocates pcie->intx_domain and initializes MSI. However, if
> platform_get_irq() fails afterwards, the cleanup action was not yet
> registered via devm_add_action_or_reset(), causing the IRQ domain
> resources to leak.
>
> Fix this by registering the devm cleanup action immediately after
> aspeed_pcie_init_irq_domain() succeeds, before calling
> platform_get_irq(). This ensures proper cleanup on any subsequent
> failure.
>
> [...]
Applied, thanks!
[1/1] PCI: aspeed: Fix IRQ domain leak on platform_get_irq() failure
commit: c54d5f5b33990f2649c20f35407f340bcadb8a53
Best regards,
--
Manivannan Sadhasivam <mani@kernel.org>
^ permalink raw reply
* Re: [RFC PATCH 0/2] mm: continue using per-VMA lock when retrying page faults after I/O
From: wang lian @ 2026-04-04 9:19 UTC (permalink / raw)
To: 21cnbao
Cc: akpm, linux-arm-kernel, linux-fsdevel, linux-kernel, linux-mm,
linux-riscv, linux-s390, linuxppc-dev, loongarch, surenb, willy,
wang lian, Wang Lian, Kunwu Chan, Kunwu Chan
In-Reply-To: <CAGsJ_4wnwAet4svDrxT4sTdp24sweAU-2VyYn3iNPOoaKdXxPw@mail.gmail.com>
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset=y, Size: 6581 bytes --]
Hi Barry,
> If either you or Matthew have a reproducer for this issue, I’d be
> happy to try it out.
Kunwu and I evaluated this series ("mm: continue using per-VMA lock when
retrying page faults after I/O") under a stress scenario specifically
designed to expose the retry behavior in filemap_fault(). This models
the exact situation described by Matthew Wilcox [1], where retries after
I/O fail to make forward progress under memory pressure.
The scenario targets the critical window between I/O completion and
mmap_lock reacquisition. This workload deliberately includes frequent
mmap/munmap operations to simulate a highly contended mmap_lock
environment alongside severe memory pressure (1GB memcg limit). Under
this pressure, folios instantiated by the I/O can be aggressively
reclaimed before the delayed task can re-acquire the lock and install
the PTE, forcing retries to repeat the entire work.
To make this behavior reproducible, we constructed a stress setup that
intentionally extends this interval:
* 256-core x86 system
* 1GB memory cgroup
* 500 threads continuously faulting on a 16MB file
The core reproducer and the execution command are provided below:
#define _GNU_SOURCE
#include <errno.h>
#include <fcntl.h>
#include <pthread.h>
#include <stdatomic.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <unistd.h>
#include <time.h>
#define THREADS 500
#define FILE_SIZE (16 * 1024 * 1024) /* 16MB */
static _Atomic int g_stop = 0;
#define RUN_SECONDS 600
struct worker_arg {
long id;
uint64_t *counts;
};
void *worker(void *arg)
{
struct worker_arg *wa = (struct worker_arg *)arg;
long id = wa->id;
char path[64];
uint64_t local_rounds = 0;
snprintf(path, sizeof(path), "./test_file_%d_%ld.dat",
getpid(), id);
int fd = open(path, O_RDWR | O_CREAT | O_TRUNC, 0666);
if (fd < 0) return NULL;
if (ftruncate(fd, FILE_SIZE) < 0) {
close(fd); return NULL;
}
while (!atomic_load_explicit(&g_stop, memory_order_relaxed)) {
char *f_map = mmap(NULL, FILE_SIZE, PROT_READ,
MAP_SHARED, fd, 0);
if (f_map != MAP_FAILED) {
/* Pure page cache thrashing */
for (int i = 0; i < FILE_SIZE; i += 4096) {
volatile unsigned char c =
(unsigned char)f_map[i];
(void)c;
}
munmap(f_map, FILE_SIZE);
local_rounds++;
}
}
wa->counts[id] = local_rounds;
close(fd);
unlink(path);
return NULL;
}
int main(void)
{
printf("Pure File Thrashing Started. PID: %d\n", getpid());
pthread_t t[THREADS];
uint64_t local_counts[THREADS];
memset(local_counts, 0, sizeof(local_counts));
struct worker_arg args[THREADS];
for (long i = 0; i < THREADS; i++) {
args[i].id = i;
args[i].counts = local_counts;
pthread_create(&t[i], NULL, worker, &args[i]);
}
sleep(RUN_SECONDS);
atomic_store_explicit(&g_stop, 1, memory_order_relaxed);
for (int i = 0; i < THREADS; i++) pthread_join(t[i], NULL);
uint64_t total = 0;
for (int i = 0; i < THREADS; i++) total += local_counts[i];
printf("Total rounds : %llu\n", (unsigned long long)total);
printf("Throughput : %.2f rounds/sec\n",
(double)total / RUN_SECONDS);
return 0;
}
Command line used for the test:
systemd-run --scope -p MemoryHigh=1G -p MemoryMax=1.2G -p MemorySwapMax=0 \
--unit=mmap-thrash-$$ ./mmap_lock & \
TEST_PID=$!
We also added temporary counters in page fault retries [2]:
- RETRY_IO_MISS : folio not present after I/O completion
- RETRY_MMAP_DROP : retry fallback due to waiting for I/O
We report representative runs from our 600-second test iterations
(kernel v7.0-rc3):
| Case | Total Rounds | Throughput | Miss/Drop(%) | RETRY_MMAP_DROP | RETRY_IO_MISS |
| ------------------- | ------------ | ---------- | ------------ | --------------- | ------------- |
| Baseline (Run 1) | 22,711 | 37.85 /s | 45.04 | 970,078 | 436,956 |
| Baseline (Run 2) | 23,530 | 39.22 /s | 44.96 | 972,043 | 437,077 |
| With Series (Run A) | 54,428 | 90.71 /s | 1.69 | 1,204,124 | 20,398 |
| With Series (Run B) | 35,949 | 59.91 /s | 0.03 | 327,023 | 99 |
Notes:
1. Throughput Improvement: During the 600-second testing window, overall
workload throughput can more than double (e.g., Run A jumped from ~38
to 90.71 rounds/sec).
2. Elimination of Race Condition: Without the patch, ~45% of retries
were invalid because newly fetched folios were evicted during the
mmap_lock reacquisition delay. With the per-VMA retry path, the
invalidation ratio plummeted to near zero (0.03% - 1.69%).
3. Counter Scaling and Variance: In Run A, because the I/O wait
bottleneck is eliminated, the threads advance much faster. Thus, the
absolute number of mmap_lock drops naturally scales up with the
increased throughput. In Run B, the primary bottleneck shifts to the
mmap write-lock contention (lock convoying), causing throughput and
total drops to fluctuate. Crucially, the Miss/Drop ratio remains near
zero regardless of this variance.
Without this series, almost half of the retries fail to observe
completed I/O results, causing severe CPU and I/O waste. With the
finer-grained VMA lock, the faulting threads bypass the heavily
contended mmap_lock entirely during retries, completing the fault
almost instantly.
This scenario perfectly aligns with the exact concern raised, and these
results show that the patch not only successfully eliminates the retry
inefficiency but also tangibly boosts macro-level system throughput.
[1] https://lore.kernel.org/linux-mm/aSip2mWX13sqPW_l@casper.infradead.org/
[2] https://github.com/lianux-mm/ioretry_test/
Tested-by: Wang Lian <wanglian@kylinos.cn>
Tested-by: Kunwu Chan <chentao@kylinos.cn>
Reviewed-by: Wang Lian <lianux.mm@gmail.com>
Reviewed-by: Kunwu Chan <kunwu.chan@gmail.com>
--
Best Regards,
wang lian
^ permalink raw reply
* [PATCH] ARM: atags_compat: bound the deprecated command line copy
From: Pengpeng Hou @ 2026-04-03 8:56 UTC (permalink / raw)
To: linux-arm-kernel; +Cc: linux-kernel, pengpeng
`build_tag_list()` still converts the deprecated `param_struct`
command line with `strlen()` and `strcpy()` from a fixed
`commandline[COMMAND_LINE_SIZE]` array.
That source buffer is not locally proven NUL-terminated before the
conversion runs, so malformed old boot parameters can make the helper
read past the end of the source array while sizing or copying the ATAG
command line.
Use `strnlen()` against the source buffer size and copy the bounded
length with an explicit terminator.
Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>
---
arch/arm/kernel/atags_compat.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/arch/arm/kernel/atags_compat.c b/arch/arm/kernel/atags_compat.c
index 10da11c212cc..aa149710f0c0 100644
--- a/arch/arm/kernel/atags_compat.c
+++ b/arch/arm/kernel/atags_compat.c
@@ -92,6 +92,7 @@ static struct tag * __init memtag(struct tag *tag, unsigned long start, unsigned
static void __init build_tag_list(struct param_struct *params, void *taglist)
{
struct tag *tag = taglist;
+ size_t cmdline_len;
if (params->u1.s.page_size != PAGE_SIZE) {
pr_warn("Warning: bad configuration page, trying to continue\n");
@@ -195,9 +196,11 @@ static void __init build_tag_list(struct param_struct *params, void *taglist)
tag = tag_next(tag);
tag->hdr.tag = ATAG_CMDLINE;
- tag->hdr.size = (strlen(params->commandline) + 3 +
+ cmdline_len = strnlen(params->commandline, sizeof(params->commandline));
+ tag->hdr.size = (cmdline_len + 1 + 3 +
sizeof(struct tag_header)) >> 2;
- strcpy(tag->u.cmdline.cmdline, params->commandline);
+ memcpy(tag->u.cmdline.cmdline, params->commandline, cmdline_len);
+ tag->u.cmdline.cmdline[cmdline_len] = '\0';
tag = tag_next(tag);
tag->hdr.tag = ATAG_NONE;
--
2.50.1 (Apple Git-155)
^ permalink raw reply related
* Re: [PATCH 0/5] mm/sparse-vmemmap: provide generic vmemmap_set_pmd() and vmemmap_check_pmd()
From: Muchun Song @ 2026-04-04 7:35 UTC (permalink / raw)
To: Muchun Song
Cc: Catalin Marinas, Will Deacon, Huacai Chen, Paul Walmsley,
Palmer Dabbelt, Albert Ou, David S. Miller, Andreas Larsson,
Andrew Morton, David Hildenbrand, WANG Xuerui, Alexandre Ghiti,
Lorenzo Stoakes, Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Ryan Roberts, Kevin Brodsky,
Dev Jain, Anshuman Khandual, Yang Shi, Chaitanya S Prakash,
Yuquan Wang, Petr Tesarik, Austin Kim, Vishal Moola (Oracle),
Junhui Liu, Matthew Wilcox (Oracle), Alex Shi, Chengkaitao,
linux-arm-kernel, linux-kernel, loongarch, linux-riscv,
sparclinux, linux-mm
In-Reply-To: <20260404071720.3577290-1-songmuchun@bytedance.com>
> On Apr 4, 2026, at 15:17, Muchun Song <songmuchun@bytedance.com> wrote:
>
> The two weak functions vmemmap_set_pmd() and vmemmap_check_pmd() are
> currently no-ops on every architecture, forcing each platform that needs
> them to duplicate the same handful of lines. Provide a generic implementation:
>
> - vmemmap_set_pmd() simply sets a huge PMD with PAGE_KERNEL protection.
>
> - vmemmap_check_pmd() verifies that the PMD is present and leaf,
> then calls the existing vmemmap_verify() helper.
>
> Architectures that need special handling can continue to override the
> weak symbols; everyone else gets the standard version for free.
>
> This series drops the custom implementations in arm64, riscv, loongarch,
> and sparc, replacing them with the generic implementation introduced
> in the first patch.
>
> Muchun Song (5):
> mm/sparse-vmemmap: provide generic vmemmap_set_pmd() and
> vmemmap_check_pmd()
> arm64/mm: drop vmemmap_pmd helpers and use generic code
> riscv/mm: drop vmemmap_pmd helpers and use generic code
> loongarch/mm: drop vmemmap_check_pmd helper and use generic code
> sparc/mm: drop vmemmap_check_pmd helper and use generic code
Hi all,
Please accept my sincere apologies for the mailing list noise.
Due to an error in my local scripts (failing to clean up the patch
output directory before regenerating the series with an updated commit
range), multiple duplicate and conflicting patches were accidentally
sent to the list simultaneously (10 patches in total instead of the
intended 5).
Sorry again for the inconvenience.
Thanks,
Muchun
>
> arch/arm64/mm/mmu.c | 14 --------------
> arch/loongarch/mm/init.c | 11 -----------
> arch/riscv/mm/init.c | 13 -------------
> arch/sparc/mm/init_64.c | 11 -----------
> mm/sparse-vmemmap.c | 7 ++++++-
> 5 files changed, 6 insertions(+), 50 deletions(-)
>
> --
> 2.20.1
>
^ permalink raw reply
* [PATCH 2/5] arm64/mm: drop vmemmap_pmd helpers and use generic code
From: Muchun Song @ 2026-04-04 7:17 UTC (permalink / raw)
To: Catalin Marinas, Will Deacon
Cc: Muchun Song, Muchun Song, Ryan Roberts, Andrew Morton,
Kevin Brodsky, Dev Jain, Anshuman Khandual, Lorenzo Stoakes,
Yang Shi, Chaitanya S Prakash, linux-arm-kernel, linux-kernel
In-Reply-To: <20260404071720.3577290-1-songmuchun@bytedance.com>
The generic implementations now suffice; remove the arm64 copies.
Signed-off-by: Muchun Song <songmuchun@bytedance.com>
---
arch/arm64/mm/mmu.c | 14 --------------
1 file changed, 14 deletions(-)
diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
index ec1c6971a561..b87053452641 100644
--- a/arch/arm64/mm/mmu.c
+++ b/arch/arm64/mm/mmu.c
@@ -1745,20 +1745,6 @@ static void free_empty_tables(unsigned long addr, unsigned long end,
}
#endif
-void __meminit vmemmap_set_pmd(pmd_t *pmdp, void *p, int node,
- unsigned long addr, unsigned long next)
-{
- pmd_set_huge(pmdp, __pa(p), __pgprot(PROT_SECT_NORMAL));
-}
-
-int __meminit vmemmap_check_pmd(pmd_t *pmdp, int node,
- unsigned long addr, unsigned long next)
-{
- vmemmap_verify((pte_t *)pmdp, node, addr, next);
-
- return pmd_sect(READ_ONCE(*pmdp));
-}
-
int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node,
struct vmem_altmap *altmap)
{
--
2.20.1
^ permalink raw reply related
* [PATCH 1/4] arm64/mm: drop vmemmap_pmd helpers and use generic code
From: Muchun Song @ 2026-04-04 7:17 UTC (permalink / raw)
To: Catalin Marinas, Will Deacon
Cc: Muchun Song, Muchun Song, Ryan Roberts, Andrew Morton,
David Hildenbrand, Kevin Brodsky, Dev Jain, Lorenzo Stoakes,
Anshuman Khandual, Yang Shi, Chaitanya S Prakash,
linux-arm-kernel, linux-kernel
In-Reply-To: <20260404071720.3577290-1-songmuchun@bytedance.com>
The generic implementations now suffice; remove the arm64 copies.
Signed-off-by: Muchun Song <songmuchun@bytedance.com>
---
arch/arm64/mm/mmu.c | 14 --------------
1 file changed, 14 deletions(-)
diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
index ec1c6971a561..b87053452641 100644
--- a/arch/arm64/mm/mmu.c
+++ b/arch/arm64/mm/mmu.c
@@ -1745,20 +1745,6 @@ static void free_empty_tables(unsigned long addr, unsigned long end,
}
#endif
-void __meminit vmemmap_set_pmd(pmd_t *pmdp, void *p, int node,
- unsigned long addr, unsigned long next)
-{
- pmd_set_huge(pmdp, __pa(p), __pgprot(PROT_SECT_NORMAL));
-}
-
-int __meminit vmemmap_check_pmd(pmd_t *pmdp, int node,
- unsigned long addr, unsigned long next)
-{
- vmemmap_verify((pte_t *)pmdp, node, addr, next);
-
- return pmd_sect(READ_ONCE(*pmdp));
-}
-
int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node,
struct vmem_altmap *altmap)
{
--
2.20.1
^ permalink raw reply related
* [PATCH 0/5] mm/sparse-vmemmap: provide generic vmemmap_set_pmd() and vmemmap_check_pmd()
From: Muchun Song @ 2026-04-04 7:17 UTC (permalink / raw)
To: Catalin Marinas, Will Deacon, Huacai Chen, Paul Walmsley,
Palmer Dabbelt, Albert Ou, David S. Miller, Andreas Larsson,
Andrew Morton, David Hildenbrand
Cc: Muchun Song, Muchun Song, WANG Xuerui, Alexandre Ghiti,
Lorenzo Stoakes, Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Ryan Roberts, Kevin Brodsky,
Dev Jain, Anshuman Khandual, Yang Shi, Chaitanya S Prakash,
Yuquan Wang, Petr Tesarik, Austin Kim, Vishal Moola (Oracle),
Junhui Liu, Matthew Wilcox (Oracle), Alex Shi, Chengkaitao,
linux-arm-kernel, linux-kernel, loongarch, linux-riscv,
sparclinux, linux-mm
The two weak functions vmemmap_set_pmd() and vmemmap_check_pmd() are
currently no-ops on every architecture, forcing each platform that needs
them to duplicate the same handful of lines. Provide a generic implementation:
- vmemmap_set_pmd() simply sets a huge PMD with PAGE_KERNEL protection.
- vmemmap_check_pmd() verifies that the PMD is present and leaf,
then calls the existing vmemmap_verify() helper.
Architectures that need special handling can continue to override the
weak symbols; everyone else gets the standard version for free.
This series drops the custom implementations in arm64, riscv, loongarch,
and sparc, replacing them with the generic implementation introduced
in the first patch.
Muchun Song (5):
mm/sparse-vmemmap: provide generic vmemmap_set_pmd() and
vmemmap_check_pmd()
arm64/mm: drop vmemmap_pmd helpers and use generic code
riscv/mm: drop vmemmap_pmd helpers and use generic code
loongarch/mm: drop vmemmap_check_pmd helper and use generic code
sparc/mm: drop vmemmap_check_pmd helper and use generic code
arch/arm64/mm/mmu.c | 14 --------------
arch/loongarch/mm/init.c | 11 -----------
arch/riscv/mm/init.c | 13 -------------
arch/sparc/mm/init_64.c | 11 -----------
mm/sparse-vmemmap.c | 7 ++++++-
5 files changed, 6 insertions(+), 50 deletions(-)
--
2.20.1
^ permalink raw reply
* Re: [RFC PATCH v2 3/5] iommu/arm-smmu-v3: Add Stream Table Entry display to debugfs
From: Nicolin Chen @ 2026-04-04 5:43 UTC (permalink / raw)
To: Qinxin Xia
Cc: robin.murphy, will, jpb, linux-arm-kernel, iommu, wangzhou1,
prime.zeng, fanghao11, jonathan.cameron, wuyifan50, linuxarm
In-Reply-To: <20260328101706.3448655-4-xiaqinxin@huawei.com>
On Sat, Mar 28, 2026 at 06:17:04PM +0800, Qinxin Xia wrote:
> +static int smmu_debugfs_ste_show(struct seq_file *seq, void *unused)
> +{
> + struct ste_context *ctx = seq->private;
> + struct arm_smmu_master *master = ctx->master;
> + struct arm_smmu_device *smmu;
> + struct arm_smmu_ste *ste;
> + u32 sid, cfg;
> + int i;
> +
> + if (!master) {
> + seq_puts(seq, "No SMMU master data\n");
> + return 0;
> + }
> +
> + smmu = master->smmu;
> + scoped_guard(mutex, &smmu->streams_mutex) {
Instead:
guard(mutex)(&smmu->streams_mutex);
> + sid = ctx->sid;
> +
> + if (!arm_smmu_sid_in_range(smmu, sid)) {
> + seq_printf(seq, "Invalid Stream ID: %u (max %u)\n",
> + sid, (1 << smmu->sid_bits) - 1);
> + return 0;
> + }
> +
> + ste = arm_smmu_get_step_for_sid(smmu, sid);
> + if (!ste) {
> + seq_printf(seq, "STE not available for SID %u\n", sid);
> + return 0;
> + }
> +
> + seq_printf(seq, "STE for Stream ID %u\n", sid);
> + seq_printf(seq, " Valid: %s\n",
> + le64_to_cpu(ste->data[0]) & STRTAB_STE_0_V ? "Yes" : "No");
> +
> + seq_puts(seq, " Config: ");
> +
> + cfg = FIELD_GET(STRTAB_STE_0_CFG, le64_to_cpu(ste->data[0]));
> +
> + switch (cfg) {
> + case STRTAB_STE_0_CFG_BYPASS:
> + seq_puts(seq, "BYPASS\n");
> + break;
> + case STRTAB_STE_0_CFG_S1_TRANS:
> + seq_puts(seq, "only S1_TRANS\n");
> + break;
> + case STRTAB_STE_0_CFG_S2_TRANS:
> + seq_puts(seq, "only S2_TRANS\n");
> + break;
> + case STRTAB_STE_0_CFG_NESTED:
> + seq_puts(seq, "S1+S2_TRANS\n");
> + break;
> + case STRTAB_STE_0_CFG_ABORT:
> + seq_puts(seq, "ABORT\n");
> + break;
> + default:
> + seq_puts(seq, "UNKNOWN\n");
> + }
> +
> + if (le64_to_cpu(ste->data[0]) & STRTAB_STE_0_CFG_S1_TRANS) {
> + seq_printf(seq, " S1ContextPtr: 0x%016llx\n",
> + le64_to_cpu(ste->data[1]) & STRTAB_STE_0_S1CTXPTR_MASK);
> + }
> +
> + if (le64_to_cpu(ste->data[0]) & STRTAB_STE_0_CFG_S2_TRANS) {
> + seq_printf(seq, " S2ContextPtr: 0x%016llx\n",
> + le64_to_cpu(ste->data[3]) & STRTAB_STE_3_S2TTB_MASK);
> + }
> +
> + /* Display raw STE data */
> + seq_puts(seq, " Raw Data:\n");
> + for (i = 0; i < STRTAB_STE_DWORDS; i++)
> + seq_printf(seq, " STE[%d]: 0x%016llx\n", i,
> + le64_to_cpu(ste->data[i]));
> + }
> + return 0;
Check the indentation of the return line.
> +/**
> + * arm_smmu_debugfs_create_stream_table() - Create debugfs entries for stream table
> + * @dev: device to create entries for
> + * @smmu: SMMU device
> + *
> + * Return: 0 on success, negative error code on failure
> + */
> +int arm_smmu_debugfs_create_stream_table(struct device *dev,
> + struct arm_smmu_device *smmu)
Usually @smmu would be the first parameter.
> +{
> + struct dentry *stream_dir, *dev_dir;
> + struct arm_smmu_master *master;
> + struct ste_context *ctx;
> + char name[64];
> + u32 sid;
> + int i;
> +
> + scoped_guard(mutex, &arm_smmu_debugfs_lock) {
> + if (!smmu->debugfs->stream_dir) {
> + stream_dir = debugfs_create_dir("stream_table",
> + smmu->debugfs->smmu_dir);
> + if (!stream_dir)
> + return -ENOMEM;
> +
> + smmu->debugfs->stream_dir = stream_dir;
> + } else {
> + stream_dir = smmu->debugfs->stream_dir;
> + }
> + }
> +
> + master = dev_iommu_priv_get(dev);
> + if (!master || !master->num_streams)
> + return -ENODEV;
> +
> + for (i = 0; i < master->num_streams; i++) {
> + sid = master->streams[i].id;
> + snprintf(name, sizeof(name), "%u", sid);
> + dev_dir = debugfs_create_dir(name, stream_dir);
> + if (!dev_dir)
> + continue;
> +
> + /* Create STE file */
> + ctx = kzalloc_obj(*ctx);
> + ctx->master = master;
> + ctx->sid = sid;
> + spin_lock(&smmu->debugfs->stream_lock);
> + list_add_tail(&ctx->node, &smmu->debugfs->stream_list);
> + spin_unlock(&smmu->debugfs->stream_lock);
May consider an RCU list instead of locking.
> +/**
> + * arm_smmu_debugfs_remove_stream_table() - Remove debugfs entries for stream table
> + * @dev: device to remove entries for
> + * @smmu: SMMU device
Again, @smmu could be the first parameter.
> + * This function removes the debugfs directories created by
> + * arm_smmu_debugfs_create_stream_table().
> + */
> +void arm_smmu_debugfs_remove_stream_table(struct device *dev,
> + struct arm_smmu_device *smmu)
Please double check the indentation. It looks odd on my side.
> -static struct arm_smmu_ste *
> +#ifndef CONFIG_ARM_SMMU_V3_DEBUGFS
> +static
> +#endif
> +struct arm_smmu_ste *
> arm_smmu_get_step_for_sid(struct arm_smmu_device *smmu, u32 sid)
Could probably move this to the header.
> -static bool arm_smmu_sid_in_range(struct arm_smmu_device *smmu, u32 sid)
> +#ifndef CONFIG_ARM_SMMU_V3_DEBUGFS
> +static
> +#endif
> +bool arm_smmu_sid_in_range(struct arm_smmu_device *smmu, u32 sid)
Ditto
> @@ -3648,10 +3658,14 @@ static void arm_smmu_release_device(struct device *dev)
>
> WARN_ON(master->iopf_refcount);
>
> +#ifdef CONFIG_ARM_SMMU_V3_DEBUGFS
> + arm_smmu_debugfs_remove_stream_table(dev, master->smmu);
> +#endif
> arm_smmu_disable_pasid(master);
> arm_smmu_remove_master(master);
> if (arm_smmu_cdtab_allocated(&master->cd_table))
> arm_smmu_free_cd_tables(master);
> +
> kfree(master);
Meaningless line.
> struct arm_smmu_debugfs {
> + struct list_head stream_list;
> + spinlock_t stream_lock;
> struct dentry *smmu_dir;
> + struct dentry *stream_dir;
> /* Reserved for future extensions */
> };
That's the end of the struct. What do you reserve?
Nicolin
^ permalink raw reply
* [PATCH v3 2/8] perf build loongarch: Remove reference to missing file
From: Ian Rogers @ 2026-04-04 5:40 UTC (permalink / raw)
To: acme
Cc: irogers, 9erthalion6, adrian.hunter, alex, alexander.shishkin,
andrew.jones, aou, atrajeev, blakejones, ctshao, dapeng1.mi,
howardchu95, james.clark, john.g.garry, jolsa, leo.yan,
libunwind-devel, linux-arm-kernel, linux-kernel, linux-perf-users,
linux-riscv, mingo, namhyung, palmer, peterz, pjw, shimin.guo,
tglozar, tmricht, will, yuzhuo
In-Reply-To: <20260404054032.1538095-1-irogers@google.com>
The file was removed in commit e62fae9d9e85 ("perf unwind-libdw: Fix a
cross-arch unwinding bug") but the Build file not updated.
Fixes: e62fae9d9e85 ("perf unwind-libdw: Fix a cross-arch unwinding bug")
Signed-off-by: Ian Rogers <irogers@google.com>
---
tools/perf/arch/loongarch/util/Build | 1 -
1 file changed, 1 deletion(-)
diff --git a/tools/perf/arch/loongarch/util/Build b/tools/perf/arch/loongarch/util/Build
index 3ad73d0289f3..8d91e78d31c9 100644
--- a/tools/perf/arch/loongarch/util/Build
+++ b/tools/perf/arch/loongarch/util/Build
@@ -1,4 +1,3 @@
perf-util-y += header.o
perf-util-$(CONFIG_LOCAL_LIBUNWIND) += unwind-libunwind.o
-perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
--
2.53.0.1213.gd9a14994de-goog
^ permalink raw reply related
* [PATCH v3 1/8] perf unwind: Refactor get_entries to allow dynamic libdw/libunwind selection
From: Ian Rogers @ 2026-04-04 5:40 UTC (permalink / raw)
To: acme
Cc: irogers, 9erthalion6, adrian.hunter, alex, alexander.shishkin,
andrew.jones, aou, atrajeev, blakejones, ctshao, dapeng1.mi,
howardchu95, james.clark, john.g.garry, jolsa, leo.yan,
libunwind-devel, linux-arm-kernel, linux-kernel, linux-perf-users,
linux-riscv, mingo, namhyung, palmer, peterz, pjw, shimin.guo,
tglozar, tmricht, will, yuzhuo
In-Reply-To: <20260404054032.1538095-1-irogers@google.com>
Currently, both libdw and libunwind define 'unwind__get_entries'. This
causes a duplicate symbol build failure when both are compiled into
perf.
This commit refactors the DWARF unwind post-processing to be
configurable at runtime via the .perfconfig file option
'unwind.style', or using the argument '--unwind-style' in the commands
'perf report', 'perf script' and 'perf inject', in a similar manner to
the addr2line or the disassembler style.
The file 'tools/perf/util/unwind.c' adds the top-level dispatch
function 'unwind__get_entries'. The backend implementations are
renamed to 'libdw__get_entries' and 'libunwind__get_entries'. Both are
attempted as fallbacks if not configured, or if the primary backend
fails.
Fixes: 2e9191573a69 ("perf build: Remove NO_LIBDW_DWARF_UNWIND option")
Signed-off-by: Ian Rogers <irogers@google.com>
---
tools/perf/builtin-inject.c | 4 ++
tools/perf/builtin-report.c | 4 ++
tools/perf/builtin-script.c | 4 ++
tools/perf/util/Build | 1 +
tools/perf/util/symbol_conf.h | 10 +++
tools/perf/util/unwind-libdw.c | 2 +-
tools/perf/util/unwind-libunwind.c | 2 +-
tools/perf/util/unwind.c | 98 ++++++++++++++++++++++++++++++
tools/perf/util/unwind.h | 63 ++++++++++++-------
9 files changed, 163 insertions(+), 25 deletions(-)
create mode 100644 tools/perf/util/unwind.c
diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
index 5b29f4296861..9ad681b3c0dc 100644
--- a/tools/perf/builtin-inject.c
+++ b/tools/perf/builtin-inject.c
@@ -26,6 +26,7 @@
#include "util/synthetic-events.h"
#include "util/thread.h"
#include "util/namespaces.h"
+#include "util/unwind.h"
#include "util/util.h"
#include "util/tsc.h"
@@ -2539,6 +2540,9 @@ int cmd_inject(int argc, const char **argv)
OPT_STRING(0, "guestmount", &symbol_conf.guestmount, "directory",
"guest mount directory under which every guest os"
" instance has a subdir"),
+ OPT_CALLBACK(0, "unwind-style", NULL, "unwind style",
+ "unwind styles (libdw,libunwind)",
+ unwind__option),
OPT_BOOLEAN(0, "convert-callchain", &inject.convert_callchain,
"Generate callchains using DWARF and drop register/stack data"),
OPT_END()
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 95c0bdba6b11..0b0966d94128 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -48,6 +48,7 @@
#include "util/time-utils.h"
#include "util/auxtrace.h"
#include "util/units.h"
+#include "util/unwind.h"
#include "util/util.h" // perf_tip()
#include "ui/ui.h"
#include "ui/progress.h"
@@ -1449,6 +1450,9 @@ int cmd_report(int argc, const char **argv)
OPT_CALLBACK(0, "addr2line-style", NULL, "addr2line style",
"addr2line styles (libdw,llvm,libbfd,addr2line)",
report_parse_addr2line_config),
+ OPT_CALLBACK(0, "unwind-style", NULL, "unwind style",
+ "unwind styles (libdw,libunwind)",
+ unwind__option),
OPT_BOOLEAN(0, "demangle", &symbol_conf.demangle,
"Symbol demangling. Enabled by default, use --no-demangle to disable."),
OPT_BOOLEAN(0, "demangle-kernel", &symbol_conf.demangle_kernel,
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index 622130d3aed4..ee6131315f96 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -63,6 +63,7 @@
#include <linux/err.h>
#include "util/dlfilter.h"
#include "util/record.h"
+#include "util/unwind.h"
#include "util/util.h"
#include "util/cgroup.h"
#include "util/annotate.h"
@@ -4155,6 +4156,9 @@ int cmd_script(int argc, const char **argv)
"Enable symbol demangling"),
OPT_BOOLEAN(0, "demangle-kernel", &symbol_conf.demangle_kernel,
"Enable kernel symbol demangling"),
+ OPT_CALLBACK(0, "unwind-style", NULL, "unwind style",
+ "unwind styles (libdw,libunwind)",
+ unwind__option),
OPT_STRING(0, "addr2line", &symbol_conf.addr2line_path, "path",
"addr2line binary to use for line numbers"),
OPT_STRING(0, "time", &script.time_str, "str",
diff --git a/tools/perf/util/Build b/tools/perf/util/Build
index 70cc91d00804..01edfccebb88 100644
--- a/tools/perf/util/Build
+++ b/tools/perf/util/Build
@@ -216,6 +216,7 @@ ifndef CONFIG_SETNS
perf-util-y += setns.o
endif
+perf-util-y += unwind.o
perf-util-$(CONFIG_LIBDW) += probe-finder.o
perf-util-$(CONFIG_LIBDW) += dwarf-aux.o
perf-util-$(CONFIG_LIBDW) += dwarf-regs.o
diff --git a/tools/perf/util/symbol_conf.h b/tools/perf/util/symbol_conf.h
index ac1b444a8fd8..004c472cdfb1 100644
--- a/tools/perf/util/symbol_conf.h
+++ b/tools/perf/util/symbol_conf.h
@@ -9,6 +9,15 @@
struct strlist;
struct intlist;
+enum unwind_style {
+ UNWIND_STYLE_UNKNOWN = 0,
+ UNWIND_STYLE_LIBDW,
+ UNWIND_STYLE_LIBUNWIND,
+};
+
+#define MAX_UNWIND_STYLE (UNWIND_STYLE_LIBUNWIND + 1)
+
+
enum a2l_style {
A2L_STYLE_UNKNOWN = 0,
A2L_STYLE_LIBDW,
@@ -80,6 +89,7 @@ struct symbol_conf {
*bt_stop_list_str;
const char *addr2line_path;
enum a2l_style addr2line_style[MAX_A2L_STYLE];
+ enum unwind_style unwind_style[MAX_UNWIND_STYLE];
unsigned long time_quantum;
struct strlist *dso_list,
*comm_list,
diff --git a/tools/perf/util/unwind-libdw.c b/tools/perf/util/unwind-libdw.c
index 05e8e68bd49c..d8a5b7d54192 100644
--- a/tools/perf/util/unwind-libdw.c
+++ b/tools/perf/util/unwind-libdw.c
@@ -339,7 +339,7 @@ frame_callback(Dwfl_Frame *state, void *arg)
DWARF_CB_ABORT : DWARF_CB_OK;
}
-int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
+int libdw__get_entries(unwind_entry_cb_t cb, void *arg,
struct thread *thread,
struct perf_sample *data,
int max_stack,
diff --git a/tools/perf/util/unwind-libunwind.c b/tools/perf/util/unwind-libunwind.c
index cb8be6acfb6f..a0016b897dae 100644
--- a/tools/perf/util/unwind-libunwind.c
+++ b/tools/perf/util/unwind-libunwind.c
@@ -79,7 +79,7 @@ void unwind__finish_access(struct maps *maps)
ops->finish_access(maps);
}
-int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
+int libunwind__get_entries(unwind_entry_cb_t cb, void *arg,
struct thread *thread,
struct perf_sample *data, int max_stack,
bool best_effort)
diff --git a/tools/perf/util/unwind.c b/tools/perf/util/unwind.c
new file mode 100644
index 000000000000..86c2d1692d08
--- /dev/null
+++ b/tools/perf/util/unwind.c
@@ -0,0 +1,98 @@
+// SPDX-License-Identifier: GPL-2.0
+#include "debug.h"
+#include "symbol_conf.h"
+#include "unwind.h"
+#include <linux/string.h>
+#include <string.h>
+#include <stdlib.h>
+
+int unwind__get_entries(unwind_entry_cb_t cb __maybe_unused, void *arg __maybe_unused,
+ struct thread *thread __maybe_unused,
+ struct perf_sample *data __maybe_unused,
+ int max_stack __maybe_unused,
+ bool best_effort __maybe_unused)
+{
+ int ret = 0;
+
+#if defined(HAVE_LIBDW_SUPPORT) || defined(HAVE_LIBUNWIND_SUPPORT)
+ if (symbol_conf.unwind_style[0] == UNWIND_STYLE_UNKNOWN) {
+ int i = 0;
+#ifdef HAVE_LIBDW_SUPPORT
+ symbol_conf.unwind_style[i++] = UNWIND_STYLE_LIBDW;
+#endif
+#ifdef HAVE_LIBUNWIND_SUPPORT
+ symbol_conf.unwind_style[i++] = UNWIND_STYLE_LIBUNWIND;
+#endif
+ }
+#endif //defined(HAVE_LIBDW_SUPPORT) || defined(HAVE_LIBUNWIND_SUPPORT)
+
+ for (size_t i = 0; i < ARRAY_SIZE(symbol_conf.unwind_style); i++) {
+ switch (symbol_conf.unwind_style[i]) {
+ case UNWIND_STYLE_LIBDW:
+ ret = libdw__get_entries(cb, arg, thread, data, max_stack, best_effort);
+ break;
+ case UNWIND_STYLE_LIBUNWIND:
+ ret = libunwind__get_entries(cb, arg, thread, data, max_stack, best_effort);
+ break;
+ case UNWIND_STYLE_UNKNOWN:
+ default:
+#if !defined(HAVE_LIBDW_SUPPORT) && !defined(HAVE_LIBUNWIND_SUPPORT)
+ pr_warning_once(
+ "Error: dwarf unwinding not supported, build perf with libdw or libunwind.\n");
+#endif
+ ret = -1;
+ break;
+ }
+ if (ret == 0)
+ break;
+ }
+ return ret;
+}
+
+int unwind__configure(const char *var, const char *value, void *cb __maybe_unused)
+{
+ static const char * const unwind_style_names[] = {
+ [UNWIND_STYLE_LIBDW] = "libdw",
+ [UNWIND_STYLE_LIBUNWIND] = "libunwind",
+ NULL
+ };
+ char *s, *p, *saveptr;
+ size_t i = 0;
+
+ if (strcmp(var, "unwind.style"))
+ return 0;
+
+ if (!value)
+ return -1;
+
+ s = strdup(value);
+ if (!s)
+ return -1;
+
+ p = strtok_r(s, ",", &saveptr);
+ while (p && i < ARRAY_SIZE(symbol_conf.unwind_style)) {
+ bool found = false;
+ char *q = strim(p);
+
+ for (size_t j = UNWIND_STYLE_LIBDW; j < MAX_UNWIND_STYLE; j++) {
+ if (!strcasecmp(q, unwind_style_names[j])) {
+ symbol_conf.unwind_style[i++] = j;
+ found = true;
+ break;
+ }
+ }
+ if (!found)
+ pr_warning("Unknown unwind style: %s\n", q);
+ p = strtok_r(NULL, ",", &saveptr);
+ }
+
+ free(s);
+ return 0;
+}
+
+int unwind__option(const struct option *opt __maybe_unused,
+ const char *arg,
+ int unset __maybe_unused)
+{
+ return unwind__configure("unwind.style", arg, NULL);
+}
diff --git a/tools/perf/util/unwind.h b/tools/perf/util/unwind.h
index 9f7164c6d9aa..ac0776e39f84 100644
--- a/tools/perf/util/unwind.h
+++ b/tools/perf/util/unwind.h
@@ -4,9 +4,10 @@
#include <linux/compiler.h>
#include <linux/types.h>
-#include "util/map_symbol.h"
+#include "map_symbol.h"
struct maps;
+struct option;
struct perf_sample;
struct thread;
@@ -26,7 +27,9 @@ struct unwind_libunwind_ops {
struct perf_sample *data, int max_stack, bool best_effort);
};
-#ifdef HAVE_DWARF_UNWIND_SUPPORT
+int unwind__configure(const char *var, const char *value, void *cb);
+int unwind__option(const struct option *opt, const char *arg, int unset);
+
/*
* When best_effort is set, don't report errors and fail silently. This could
* be expanded in the future to be more permissive about things other than
@@ -36,8 +39,31 @@ int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
struct thread *thread,
struct perf_sample *data, int max_stack,
bool best_effort);
-/* libunwind specific */
+
+#ifdef HAVE_LIBDW_SUPPORT
+int libdw__get_entries(unwind_entry_cb_t cb, void *arg,
+ struct thread *thread,
+ struct perf_sample *data, int max_stack,
+ bool best_effort);
+#else
+#include "debug.h"
+static inline int libdw__get_entries(unwind_entry_cb_t cb __maybe_unused, void *arg __maybe_unused,
+ struct thread *thread __maybe_unused,
+ struct perf_sample *data __maybe_unused,
+ int max_stack __maybe_unused,
+ bool best_effort __maybe_unused)
+{
+ pr_err("Error: libdw dwarf unwinding not built into perf\n");
+ return -1;
+}
+#endif
+
#ifdef HAVE_LIBUNWIND_SUPPORT
+/* libunwind specific */
+int libunwind__get_entries(unwind_entry_cb_t cb, void *arg,
+ struct thread *thread,
+ struct perf_sample *data, int max_stack,
+ bool best_effort);
#ifndef LIBUNWIND__ARCH_REG_ID
#define LIBUNWIND__ARCH_REG_ID(regnum) libunwind__arch_reg_id(regnum)
#endif
@@ -47,26 +73,16 @@ int unwind__prepare_access(struct maps *maps, struct map *map, bool *initialized
void unwind__flush_access(struct maps *maps);
void unwind__finish_access(struct maps *maps);
#else
-static inline int unwind__prepare_access(struct maps *maps __maybe_unused,
- struct map *map __maybe_unused,
- bool *initialized __maybe_unused)
-{
- return 0;
-}
-
-static inline void unwind__flush_access(struct maps *maps __maybe_unused) {}
-static inline void unwind__finish_access(struct maps *maps __maybe_unused) {}
-#endif
-#else
-static inline int
-unwind__get_entries(unwind_entry_cb_t cb __maybe_unused,
- void *arg __maybe_unused,
- struct thread *thread __maybe_unused,
- struct perf_sample *data __maybe_unused,
- int max_stack __maybe_unused,
- bool best_effort __maybe_unused)
+#include "debug.h"
+static inline int libunwind__get_entries(unwind_entry_cb_t cb __maybe_unused,
+ void *arg __maybe_unused,
+ struct thread *thread __maybe_unused,
+ struct perf_sample *data __maybe_unused,
+ int max_stack __maybe_unused,
+ bool best_effort __maybe_unused)
{
- return 0;
+ pr_err("Error: libunwind dwarf unwinding not built into perf\n");
+ return -1;
}
static inline int unwind__prepare_access(struct maps *maps __maybe_unused,
@@ -78,5 +94,6 @@ static inline int unwind__prepare_access(struct maps *maps __maybe_unused,
static inline void unwind__flush_access(struct maps *maps __maybe_unused) {}
static inline void unwind__finish_access(struct maps *maps __maybe_unused) {}
-#endif /* HAVE_DWARF_UNWIND_SUPPORT */
+#endif
+
#endif /* __UNWIND_H */
--
2.53.0.1213.gd9a14994de-goog
^ permalink raw reply related
* [PATCH v3 8/8] perf unwind-libunwind: Add RISC-V libunwind support
From: Ian Rogers @ 2026-04-04 5:40 UTC (permalink / raw)
To: acme
Cc: irogers, 9erthalion6, adrian.hunter, alex, alexander.shishkin,
andrew.jones, aou, atrajeev, blakejones, ctshao, dapeng1.mi,
howardchu95, james.clark, john.g.garry, jolsa, leo.yan,
libunwind-devel, linux-arm-kernel, linux-kernel, linux-perf-users,
linux-riscv, mingo, namhyung, palmer, peterz, pjw, shimin.guo,
tglozar, tmricht, will, yuzhuo
In-Reply-To: <20260404054032.1538095-1-irogers@google.com>
Add a RISC-V implementation for unwinding.
Signed-off-by: Ian Rogers <irogers@google.com>
---
tools/perf/util/libunwind-arch/Build | 1 +
.../perf/util/libunwind-arch/libunwind-arch.c | 21 ++
.../perf/util/libunwind-arch/libunwind-arch.h | 22 ++
.../util/libunwind-arch/libunwind-riscv.c | 297 ++++++++++++++++++
4 files changed, 341 insertions(+)
create mode 100644 tools/perf/util/libunwind-arch/libunwind-riscv.c
diff --git a/tools/perf/util/libunwind-arch/Build b/tools/perf/util/libunwind-arch/Build
index 87fd657a3248..80d3571918b1 100644
--- a/tools/perf/util/libunwind-arch/Build
+++ b/tools/perf/util/libunwind-arch/Build
@@ -5,6 +5,7 @@ perf-util-$(CONFIG_LIBUNWIND) += libunwind-loongarch.o
perf-util-$(CONFIG_LIBUNWIND) += libunwind-mips.o
perf-util-$(CONFIG_LIBUNWIND) += libunwind-ppc32.o
perf-util-$(CONFIG_LIBUNWIND) += libunwind-ppc64.o
+perf-util-$(CONFIG_LIBUNWIND) += libunwind-riscv.o
perf-util-$(CONFIG_LIBUNWIND) += libunwind-s390.o
perf-util-$(CONFIG_LIBUNWIND) += libunwind-i386.o
perf-util-$(CONFIG_LIBUNWIND) += libunwind-x86_64.o
diff --git a/tools/perf/util/libunwind-arch/libunwind-arch.c b/tools/perf/util/libunwind-arch/libunwind-arch.c
index 8539b4233df4..9a74cf3c8729 100644
--- a/tools/perf/util/libunwind-arch/libunwind-arch.c
+++ b/tools/perf/util/libunwind-arch/libunwind-arch.c
@@ -20,6 +20,8 @@ int get_perf_regnum_for_unw_regnum(unsigned int e_machine, int unw_regnum)
return __get_perf_regnum_for_unw_regnum_ppc32(unw_regnum);
case EM_PPC64:
return __get_perf_regnum_for_unw_regnum_ppc64(unw_regnum);
+ case EM_RISCV:
+ return __get_perf_regnum_for_unw_regnum_riscv(unw_regnum);
case EM_S390:
return __get_perf_regnum_for_unw_regnum_s390(unw_regnum);
case EM_386:
@@ -58,6 +60,9 @@ void libunwind_arch__flush_access(struct maps *maps)
case EM_PPC64:
__libunwind_arch__flush_access_ppc64(maps);
break;
+ case EM_RISCV:
+ __libunwind_arch__flush_access_riscv(maps);
+ break;
case EM_S390:
__libunwind_arch__flush_access_s390(maps);
break;
@@ -98,6 +103,9 @@ void libunwind_arch__finish_access(struct maps *maps)
case EM_PPC64:
__libunwind_arch__finish_access_ppc64(maps);
break;
+ case EM_RISCV:
+ __libunwind_arch__finish_access_riscv(maps);
+ break;
case EM_S390:
__libunwind_arch__finish_access_s390(maps);
break;
@@ -128,6 +136,8 @@ void *libunwind_arch__create_addr_space(unsigned int e_machine)
return __libunwind_arch__create_addr_space_ppc32();
case EM_PPC64:
return __libunwind_arch__create_addr_space_ppc64();
+ case EM_RISCV:
+ return __libunwind_arch__create_addr_space_riscv();
case EM_S390:
return __libunwind_arch__create_addr_space_s390();
case EM_386:
@@ -167,6 +177,9 @@ int libunwind_arch__dwarf_search_unwind_table(unsigned int e_machine,
case EM_PPC64:
return __libunwind_arch__dwarf_search_unwind_table_ppc64(as, ip, di, pi,
need_unwind_info, arg);
+ case EM_RISCV:
+ return __libunwind_arch__dwarf_search_unwind_table_riscv(as, ip, di, pi,
+ need_unwind_info, arg);
case EM_S390:
return __libunwind_arch__dwarf_search_unwind_table_s390(as, ip, di, pi,
need_unwind_info, arg);
@@ -211,6 +224,9 @@ int libunwind_arch__dwarf_find_debug_frame(unsigned int e_machine,
case EM_PPC64:
return __libunwind_arch__dwarf_find_debug_frame_ppc64(found, di_debug, ip, segbase,
obj_name, start, end);
+ case EM_RISCV:
+ return __libunwind_arch__dwarf_find_debug_frame_riscv(found, di_debug, ip, segbase,
+ obj_name, start, end);
case EM_S390:
return __libunwind_arch__dwarf_find_debug_frame_s390(found, di_debug, ip, segbase,
obj_name, start, end);
@@ -250,6 +266,9 @@ struct unwind_info *libunwind_arch_unwind_info__new(struct thread *thread,
case EM_PPC64:
return __libunwind_arch_unwind_info__new_ppc64(thread, sample, max_stack,
best_effort, first_ip);
+ case EM_RISCV:
+ return __libunwind_arch_unwind_info__new_riscv(thread, sample, max_stack,
+ best_effort, first_ip);
case EM_S390:
return __libunwind_arch_unwind_info__new_s390(thread, sample, max_stack,
best_effort, first_ip);
@@ -285,6 +304,8 @@ int libunwind_arch__unwind_step(struct unwind_info *ui)
return __libunwind_arch__unwind_step_ppc32(ui);
case EM_PPC64:
return __libunwind_arch__unwind_step_ppc64(ui);
+ case EM_RISCV:
+ return __libunwind_arch__unwind_step_riscv(ui);
case EM_S390:
return __libunwind_arch__unwind_step_s390(ui);
case EM_386:
diff --git a/tools/perf/util/libunwind-arch/libunwind-arch.h b/tools/perf/util/libunwind-arch/libunwind-arch.h
index 2bf7fc33313b..74a09cd58f38 100644
--- a/tools/perf/util/libunwind-arch/libunwind-arch.h
+++ b/tools/perf/util/libunwind-arch/libunwind-arch.h
@@ -39,6 +39,7 @@ int __get_perf_regnum_for_unw_regnum_loongarch(int unw_regnum);
int __get_perf_regnum_for_unw_regnum_mips(int unw_regnum);
int __get_perf_regnum_for_unw_regnum_ppc32(int unw_regnum);
int __get_perf_regnum_for_unw_regnum_ppc64(int unw_regnum);
+int __get_perf_regnum_for_unw_regnum_riscv(int unw_regnum);
int __get_perf_regnum_for_unw_regnum_s390(int unw_regnum);
int __get_perf_regnum_for_unw_regnum_i386(int unw_regnum);
int __get_perf_regnum_for_unw_regnum_x86_64(int unw_regnum);
@@ -50,6 +51,7 @@ void __libunwind_arch__flush_access_loongarch(struct maps *maps);
void __libunwind_arch__flush_access_mips(struct maps *maps);
void __libunwind_arch__flush_access_ppc32(struct maps *maps);
void __libunwind_arch__flush_access_ppc64(struct maps *maps);
+void __libunwind_arch__flush_access_riscv(struct maps *maps);
void __libunwind_arch__flush_access_s390(struct maps *maps);
void __libunwind_arch__flush_access_i386(struct maps *maps);
void __libunwind_arch__flush_access_x86_64(struct maps *maps);
@@ -61,6 +63,7 @@ void __libunwind_arch__finish_access_loongarch(struct maps *maps);
void __libunwind_arch__finish_access_mips(struct maps *maps);
void __libunwind_arch__finish_access_ppc32(struct maps *maps);
void __libunwind_arch__finish_access_ppc64(struct maps *maps);
+void __libunwind_arch__finish_access_riscv(struct maps *maps);
void __libunwind_arch__finish_access_s390(struct maps *maps);
void __libunwind_arch__finish_access_i386(struct maps *maps);
void __libunwind_arch__finish_access_x86_64(struct maps *maps);
@@ -72,6 +75,7 @@ void *__libunwind_arch__create_addr_space_loongarch(void);
void *__libunwind_arch__create_addr_space_mips(void);
void *__libunwind_arch__create_addr_space_ppc32(void);
void *__libunwind_arch__create_addr_space_ppc64(void);
+void *__libunwind_arch__create_addr_space_riscv(void);
void *__libunwind_arch__create_addr_space_s390(void);
void *__libunwind_arch__create_addr_space_i386(void);
void *__libunwind_arch__create_addr_space_x86_64(void);
@@ -111,6 +115,11 @@ int __libunwind_arch__dwarf_search_unwind_table_ppc64(void *as, uint64_t ip,
void *pi,
int need_unwind_info,
void *arg);
+int __libunwind_arch__dwarf_search_unwind_table_riscv(void *as, uint64_t ip,
+ struct libarch_unwind__dyn_info *di,
+ void *pi,
+ int need_unwind_info,
+ void *arg);
int __libunwind_arch__dwarf_search_unwind_table_s390(void *as, uint64_t ip,
struct libarch_unwind__dyn_info *di,
void *pi,
@@ -176,6 +185,13 @@ int __libunwind_arch__dwarf_find_debug_frame_ppc64(int found,
const char *obj_name,
uint64_t start,
uint64_t end);
+int __libunwind_arch__dwarf_find_debug_frame_riscv(int found,
+ struct libarch_unwind__dyn_info *di_debug,
+ uint64_t ip,
+ uint64_t segbase,
+ const char *obj_name,
+ uint64_t start,
+ uint64_t end);
int __libunwind_arch__dwarf_find_debug_frame_s390(int found,
struct libarch_unwind__dyn_info *di_debug,
uint64_t ip,
@@ -236,6 +252,11 @@ struct unwind_info *__libunwind_arch_unwind_info__new_ppc64(struct thread *threa
int max_stack,
bool best_effort,
uint64_t first_ip);
+struct unwind_info *__libunwind_arch_unwind_info__new_riscv(struct thread *thread,
+ struct perf_sample *sample,
+ int max_stack,
+ bool best_effort,
+ uint64_t first_ip);
struct unwind_info *__libunwind_arch_unwind_info__new_s390(struct thread *thread,
struct perf_sample *sample,
int max_stack,
@@ -266,6 +287,7 @@ int __libunwind_arch__unwind_step_loongarch(struct unwind_info *ui);
int __libunwind_arch__unwind_step_mips(struct unwind_info *ui);
int __libunwind_arch__unwind_step_ppc32(struct unwind_info *ui);
int __libunwind_arch__unwind_step_ppc64(struct unwind_info *ui);
+int __libunwind_arch__unwind_step_riscv(struct unwind_info *ui);
int __libunwind_arch__unwind_step_s390(struct unwind_info *ui);
int __libunwind_arch__unwind_step_i386(struct unwind_info *ui);
int __libunwind_arch__unwind_step_x86_64(struct unwind_info *ui);
diff --git a/tools/perf/util/libunwind-arch/libunwind-riscv.c b/tools/perf/util/libunwind-arch/libunwind-riscv.c
new file mode 100644
index 000000000000..a70a2ea96644
--- /dev/null
+++ b/tools/perf/util/libunwind-arch/libunwind-riscv.c
@@ -0,0 +1,297 @@
+// SPDX-License-Identifier: GPL-2.0
+#include "libunwind-arch.h"
+#include "../debug.h"
+#include "../maps.h"
+#include "../thread.h"
+#include "../../../arch/riscv/include/uapi/asm/perf_regs.h"
+#include <linux/compiler.h>
+#include <linux/kernel.h>
+#include <linux/zalloc.h>
+#include <elf.h>
+#include <errno.h>
+
+#ifdef HAVE_LIBUNWIND_RISCV_SUPPORT
+#include <libunwind-riscv.h>
+#endif
+
+int __get_perf_regnum_for_unw_regnum_riscv(int unw_regnum __maybe_unused)
+{
+#ifndef HAVE_LIBUNWIND_RISCV_SUPPORT
+ return -EINVAL;
+#else
+ switch (unw_regnum) {
+ case UNW_RISCV_X1 ... UNW_RISCV_X31:
+ return unw_regnum - UNW_RISCV_X1 + PERF_REG_RISCV_RA;
+ case UNW_RISCV_PC:
+ return PERF_REG_RISCV_PC;
+ default:
+ pr_err("unwind: invalid reg id %d\n", unw_regnum);
+ return -EINVAL;
+ }
+#endif // HAVE_LIBUNWIND_RISCV_SUPPORT
+}
+
+void __libunwind_arch__flush_access_riscv(struct maps *maps __maybe_unused)
+{
+#ifdef HAVE_LIBUNWIND_RISCV_SUPPORT
+ unw_flush_cache(maps__addr_space(maps), 0, 0);
+#endif
+}
+
+void __libunwind_arch__finish_access_riscv(struct maps *maps __maybe_unused)
+{
+#ifdef HAVE_LIBUNWIND_RISCV_SUPPORT
+ unw_destroy_addr_space(maps__addr_space(maps));
+#endif
+}
+
+#ifdef HAVE_LIBUNWIND_RISCV_SUPPORT
+static int find_proc_info(unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pi,
+ int need_unwind_info, void *arg)
+{
+ return __libunwind__find_proc_info(as, ip, pi, need_unwind_info, arg, sizeof(unw_word_t));
+}
+
+static void put_unwind_info(unw_addr_space_t __maybe_unused as,
+ unw_proc_info_t *pi __maybe_unused,
+ void *arg __maybe_unused)
+{
+ pr_debug("unwind: put_unwind_info called\n");
+}
+
+static int get_dyn_info_list_addr(unw_addr_space_t __maybe_unused as,
+ unw_word_t __maybe_unused *dil_addr,
+ void __maybe_unused *arg)
+{
+ return -UNW_ENOINFO;
+}
+
+static int access_mem(unw_addr_space_t as, unw_word_t addr, unw_word_t *valp,
+ int __write, void *arg)
+{
+ return __libunwind__access_mem(as, addr, valp, __write, arg, sizeof(unw_word_t));
+}
+
+static int access_reg(unw_addr_space_t as, unw_regnum_t regnum, unw_word_t *valp,
+ int __write, void *arg)
+{
+ return __libunwind__access_reg(as, regnum, valp, __write, arg, sizeof(unw_word_t));
+}
+
+static int access_fpreg(unw_addr_space_t __maybe_unused as,
+ unw_regnum_t __maybe_unused num,
+ unw_fpreg_t __maybe_unused *val,
+ int __maybe_unused __write,
+ void __maybe_unused *arg)
+{
+ pr_err("unwind: access_fpreg unsupported\n");
+ return -UNW_EINVAL;
+}
+
+static int resume(unw_addr_space_t __maybe_unused as,
+ unw_cursor_t __maybe_unused *cu,
+ void __maybe_unused *arg)
+{
+ pr_err("unwind: resume unsupported\n");
+ return -UNW_EINVAL;
+}
+
+static int get_proc_name(unw_addr_space_t __maybe_unused as,
+ unw_word_t __maybe_unused addr,
+ char __maybe_unused *bufp, size_t __maybe_unused buf_len,
+ unw_word_t __maybe_unused *offp, void __maybe_unused *arg)
+{
+ pr_err("unwind: get_proc_name unsupported\n");
+ return -UNW_EINVAL;
+}
+#endif
+
+void *__libunwind_arch__create_addr_space_riscv(void)
+{
+#ifdef HAVE_LIBUNWIND_RISCV_SUPPORT
+ static unw_accessors_t accessors = {
+ .find_proc_info = find_proc_info,
+ .put_unwind_info = put_unwind_info,
+ .get_dyn_info_list_addr = get_dyn_info_list_addr,
+ .access_mem = access_mem,
+ .access_reg = access_reg,
+ .access_fpreg = access_fpreg,
+ .resume = resume,
+ .get_proc_name = get_proc_name,
+ };
+ unw_addr_space_t addr_space;
+
+ addr_space = unw_create_addr_space(&accessors, /*byte_order=*/0);
+ unw_set_caching_policy(addr_space, UNW_CACHE_GLOBAL);
+ return addr_space;
+#else
+ return NULL;
+#endif
+}
+
+#ifdef HAVE_LIBUNWIND_RISCV_SUPPORT
+extern int UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as,
+ unw_word_t ip,
+ unw_dyn_info_t *di,
+ unw_proc_info_t *pi,
+ int need_unwind_info, void *arg);
+#define dwarf_search_unwind_table UNW_OBJ(dwarf_search_unwind_table)
+#endif
+
+int __libunwind_arch__dwarf_search_unwind_table_riscv(void *as __maybe_unused,
+ uint64_t ip __maybe_unused,
+ struct libarch_unwind__dyn_info *_di __maybe_unused,
+ void *pi __maybe_unused,
+ int need_unwind_info __maybe_unused,
+ void *arg __maybe_unused)
+{
+#ifdef HAVE_LIBUNWIND_RISCV_SUPPORT
+ unw_dyn_info_t di = {
+ .format = UNW_INFO_FORMAT_REMOTE_TABLE,
+ .start_ip = _di->start_ip,
+ .end_ip = _di->end_ip,
+ .u = {
+ .rti = {
+ .segbase = _di->segbase,
+ .table_data = _di->table_data,
+ .table_len = _di->table_len,
+ },
+ },
+ };
+ int ret = dwarf_search_unwind_table(as, ip, &di, pi, need_unwind_info, arg);
+
+ _di->start_ip = di.start_ip;
+ _di->end_ip = di.end_ip;
+ _di->segbase = di.u.rti.segbase;
+ _di->table_data = di.u.rti.table_data;
+ _di->table_len = di.u.rti.table_len;
+ return ret;
+#else
+ return -EINVAL;
+#endif
+}
+
+#if defined(HAVE_LIBUNWIND_RISCV_SUPPORT) && !defined(NO_LIBUNWIND_DEBUG_FRAME_RISCV)
+extern int UNW_OBJ(dwarf_find_debug_frame) (int found, unw_dyn_info_t *di_debug,
+ unw_word_t ip,
+ unw_word_t segbase,
+ const char *obj_name, unw_word_t start,
+ unw_word_t end);
+#define dwarf_find_debug_frame UNW_OBJ(dwarf_find_debug_frame)
+#endif
+
+int __libunwind_arch__dwarf_find_debug_frame_riscv(int found __maybe_unused,
+ struct libarch_unwind__dyn_info *_di __maybe_unused,
+ uint64_t ip __maybe_unused,
+ uint64_t segbase __maybe_unused,
+ const char *obj_name __maybe_unused,
+ uint64_t start __maybe_unused,
+ uint64_t end __maybe_unused)
+{
+#if defined(HAVE_LIBUNWIND_RISCV_SUPPORT) && !defined(NO_LIBUNWIND_DEBUG_FRAME_RISCV)
+ unw_dyn_info_t di = {
+ .format = UNW_INFO_FORMAT_REMOTE_TABLE,
+ .start_ip = _di->start_ip,
+ .end_ip = _di->end_ip,
+ .u = {
+ .rti = {
+ .segbase = _di->segbase,
+ .table_data = _di->table_data,
+ .table_len = _di->table_len,
+ },
+ },
+ };
+ int ret = dwarf_find_debug_frame(found, &di, ip, segbase, obj_name, start, end);
+
+ _di->start_ip = di.start_ip;
+ _di->end_ip = di.end_ip;
+ _di->segbase = di.u.rti.segbase;
+ _di->table_data = di.u.rti.table_data;
+ _di->table_len = di.u.rti.table_len;
+ return ret;
+#else
+ return -EINVAL;
+#endif
+}
+
+struct unwind_info *__libunwind_arch_unwind_info__new_riscv(struct thread *thread __maybe_unused,
+ struct perf_sample *sample __maybe_unused,
+ int max_stack __maybe_unused,
+ bool best_effort __maybe_unused,
+ uint64_t first_ip __maybe_unused)
+{
+#ifdef HAVE_LIBUNWIND_RISCV_SUPPORT
+ struct arch_unwind_info {
+ struct unwind_info ui;
+ unw_cursor_t _cursor;
+ uint64_t _ips[];
+ };
+
+ struct maps *maps = thread__maps(thread);
+ void *addr_space = maps__addr_space(maps);
+ struct arch_unwind_info *ui;
+ int ret;
+
+ if (addr_space == NULL)
+ return NULL;
+
+ ui = zalloc(sizeof(*ui) + sizeof(ui->_ips[0]) * max_stack);
+ if (!ui)
+ return NULL;
+
+ ui->ui.machine = maps__machine(maps);
+ ui->ui.thread = thread;
+ ui->ui.sample = sample;
+ ui->ui.cursor = &ui->_cursor;
+ ui->ui.ips = &ui->_ips[0];
+ ui->ui.ips[0] = first_ip;
+ ui->ui.cur_ip = 1;
+ ui->ui.max_ips = max_stack;
+ ui->ui.unw_word_t_size = sizeof(unw_word_t);
+ ui->ui.e_machine = EM_RISCV;
+ ui->ui.best_effort = best_effort;
+
+ ret = unw_init_remote(&ui->_cursor, addr_space, &ui->ui);
+ if (ret) {
+ if (!best_effort)
+ pr_err("libunwind: %s\n", unw_strerror(ret));
+ free(ui);
+ return NULL;
+ }
+
+ return &ui->ui;
+#else
+ return NULL;
+#endif
+}
+
+int __libunwind_arch__unwind_step_riscv(struct unwind_info *ui __maybe_unused)
+{
+#ifdef HAVE_LIBUNWIND_RISCV_SUPPORT
+ int ret;
+
+ if (ui->cur_ip >= ui->max_ips)
+ return -1;
+
+ ret = unw_step(ui->cursor);
+ if (ret > 0) {
+ uint64_t ip;
+
+ unw_get_reg(ui->cursor, UNW_REG_IP, &ip);
+
+ if (unw_is_signal_frame(ui->cursor) <= 0) {
+ /*
+ * Decrement the IP for any non-activation frames. This
+ * is required to properly find the srcline for caller
+ * frames. See also the documentation for
+ * dwfl_frame_pc(), which this code tries to replicate.
+ */
+ --ip;
+ }
+ ui->ips[ui->cur_ip++] = ip;
+ }
+ return ret;
+#else
+ return -EINVAL;
+#endif
+}
--
2.53.0.1213.gd9a14994de-goog
^ permalink raw reply related
* [PATCH v3 6/8] perf unwind-libunwind: Move flush/finish access out of local
From: Ian Rogers @ 2026-04-04 5:40 UTC (permalink / raw)
To: acme
Cc: irogers, 9erthalion6, adrian.hunter, alex, alexander.shishkin,
andrew.jones, aou, atrajeev, blakejones, ctshao, dapeng1.mi,
howardchu95, james.clark, john.g.garry, jolsa, leo.yan,
libunwind-devel, linux-arm-kernel, linux-kernel, linux-perf-users,
linux-riscv, mingo, namhyung, palmer, peterz, pjw, shimin.guo,
tglozar, tmricht, will, yuzhuo
In-Reply-To: <20260404054032.1538095-1-irogers@google.com>
Flush and finish access are relatively simple calls into libunwind,
move them out struct unwind_libunwind_ops. So that the correct version
can be called, add an e_machine variable to maps. This size regression
will go away when the unwind_libunwind_ops no longer need stashing in
the maps. To set the e_machine up pass it into unwind__prepare_access,
which no longer needs to determine the unwind operations based on a
map dso because of this. This also means the maps copying code can
call unwind__prepare_access once for the e_machine rather than once
per map.
Signed-off-by: Ian Rogers <irogers@google.com>
---
.../perf/util/libunwind-arch/libunwind-arch.c | 82 +++++++++++++++++++
.../perf/util/libunwind-arch/libunwind-arch.h | 24 ++++++
.../perf/util/libunwind-arch/libunwind-arm.c | 19 +++++
.../util/libunwind-arch/libunwind-arm64.c | 20 +++++
.../perf/util/libunwind-arch/libunwind-i386.c | 15 ++++
.../util/libunwind-arch/libunwind-loongarch.c | 15 ++++
.../perf/util/libunwind-arch/libunwind-mips.c | 15 ++++
.../util/libunwind-arch/libunwind-ppc32.c | 15 ++++
.../util/libunwind-arch/libunwind-ppc64.c | 15 ++++
.../perf/util/libunwind-arch/libunwind-s390.c | 15 ++++
.../util/libunwind-arch/libunwind-x86_64.c | 15 ++++
tools/perf/util/maps.c | 31 ++++---
tools/perf/util/maps.h | 2 +
tools/perf/util/thread.c | 29 +------
tools/perf/util/unwind-libunwind-local.c | 12 ---
tools/perf/util/unwind-libunwind.c | 61 +++++---------
tools/perf/util/unwind.h | 8 +-
17 files changed, 299 insertions(+), 94 deletions(-)
diff --git a/tools/perf/util/libunwind-arch/libunwind-arch.c b/tools/perf/util/libunwind-arch/libunwind-arch.c
index 5439bf90d161..9692e6c81492 100644
--- a/tools/perf/util/libunwind-arch/libunwind-arch.c
+++ b/tools/perf/util/libunwind-arch/libunwind-arch.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
#include "libunwind-arch.h"
#include "../debug.h"
+#include "../maps.h"
#include <elf.h>
#include <errno.h>
@@ -30,3 +31,84 @@ int get_perf_regnum_for_unw_regnum(unsigned int e_machine, int unw_regnum)
return -EINVAL;
}
}
+
+
+void libunwind_arch__flush_access(struct maps *maps)
+{
+ unsigned int e_machine = maps__e_machine(maps);
+
+ switch (e_machine) {
+ case EM_NONE:
+ break; // No libunwind info on the maps.
+ case EM_ARM:
+ __libunwind_arch__flush_access_arm(maps);
+ break;
+ case EM_AARCH64:
+ __libunwind_arch__flush_access_arm64(maps);
+ break;
+ case EM_LOONGARCH:
+ __libunwind_arch__flush_access_loongarch(maps);
+ break;
+ case EM_MIPS:
+ __libunwind_arch__flush_access_mips(maps);
+ break;
+ case EM_PPC:
+ __libunwind_arch__flush_access_ppc32(maps);
+ break;
+ case EM_PPC64:
+ __libunwind_arch__flush_access_ppc64(maps);
+ break;
+ case EM_S390:
+ __libunwind_arch__flush_access_s390(maps);
+ break;
+ case EM_386:
+ __libunwind_arch__flush_access_i386(maps);
+ break;
+ case EM_X86_64:
+ __libunwind_arch__flush_access_x86_64(maps);
+ break;
+ default:
+ pr_err("ELF MACHINE %x is not supported.\n", e_machine);
+ break;
+ }
+}
+
+void libunwind_arch__finish_access(struct maps *maps)
+{
+ unsigned int e_machine = maps__e_machine(maps);
+
+ switch (e_machine) {
+ case EM_NONE:
+ break; // No libunwind info on the maps.
+ case EM_ARM:
+ __libunwind_arch__finish_access_arm(maps);
+ break;
+ case EM_AARCH64:
+ __libunwind_arch__finish_access_arm64(maps);
+ break;
+ case EM_LOONGARCH:
+ __libunwind_arch__finish_access_loongarch(maps);
+ break;
+ case EM_MIPS:
+ __libunwind_arch__finish_access_mips(maps);
+ break;
+ case EM_PPC:
+ __libunwind_arch__finish_access_ppc32(maps);
+ break;
+ case EM_PPC64:
+ __libunwind_arch__finish_access_ppc64(maps);
+ break;
+ case EM_S390:
+ __libunwind_arch__finish_access_s390(maps);
+ break;
+ case EM_386:
+ __libunwind_arch__finish_access_i386(maps);
+ break;
+ case EM_X86_64:
+ __libunwind_arch__finish_access_x86_64(maps);
+ break;
+ default:
+ pr_err("ELF MACHINE %x is not supported.\n", e_machine);
+ break;
+ }
+}
diff --git a/tools/perf/util/libunwind-arch/libunwind-arch.h b/tools/perf/util/libunwind-arch/libunwind-arch.h
index e1009c6cb965..c00277a5e914 100644
--- a/tools/perf/util/libunwind-arch/libunwind-arch.h
+++ b/tools/perf/util/libunwind-arch/libunwind-arch.h
@@ -2,6 +2,8 @@
#ifndef __LIBUNWIND_ARCH_H
#define __LIBUNWIND_ARCH_H
+struct maps;
+
int __get_perf_regnum_for_unw_regnum_arm(int unw_regnum);
int __get_perf_regnum_for_unw_regnum_arm64(int unw_regnum);
int __get_perf_regnum_for_unw_regnum_loongarch(int unw_regnum);
@@ -13,4 +15,26 @@ int __get_perf_regnum_for_unw_regnum_i386(int unw_regnum);
int __get_perf_regnum_for_unw_regnum_x86_64(int unw_regnum);
int get_perf_regnum_for_unw_regnum(unsigned int e_machine, int unw_regnum);
+void __libunwind_arch__flush_access_arm(struct maps *maps);
+void __libunwind_arch__flush_access_arm64(struct maps *maps);
+void __libunwind_arch__flush_access_loongarch(struct maps *maps);
+void __libunwind_arch__flush_access_mips(struct maps *maps);
+void __libunwind_arch__flush_access_ppc32(struct maps *maps);
+void __libunwind_arch__flush_access_ppc64(struct maps *maps);
+void __libunwind_arch__flush_access_s390(struct maps *maps);
+void __libunwind_arch__flush_access_i386(struct maps *maps);
+void __libunwind_arch__flush_access_x86_64(struct maps *maps);
+void libunwind_arch__flush_access(struct maps *maps);
+
+void __libunwind_arch__finish_access_arm(struct maps *maps);
+void __libunwind_arch__finish_access_arm64(struct maps *maps);
+void __libunwind_arch__finish_access_loongarch(struct maps *maps);
+void __libunwind_arch__finish_access_mips(struct maps *maps);
+void __libunwind_arch__finish_access_ppc32(struct maps *maps);
+void __libunwind_arch__finish_access_ppc64(struct maps *maps);
+void __libunwind_arch__finish_access_s390(struct maps *maps);
+void __libunwind_arch__finish_access_i386(struct maps *maps);
+void __libunwind_arch__finish_access_x86_64(struct maps *maps);
+void libunwind_arch__finish_access(struct maps *maps);
+
#endif /* __LIBUNWIND_ARCH_H */
diff --git a/tools/perf/util/libunwind-arch/libunwind-arm.c b/tools/perf/util/libunwind-arch/libunwind-arm.c
index 6740ee55b043..bbaf01406c52 100644
--- a/tools/perf/util/libunwind-arch/libunwind-arm.c
+++ b/tools/perf/util/libunwind-arch/libunwind-arm.c
@@ -1,10 +1,15 @@
// SPDX-License-Identifier: GPL-2.0
#include "libunwind-arch.h"
#include "../debug.h"
+#include "../maps.h"
#include "../../../arch/arm/include/uapi/asm/perf_regs.h"
#include <linux/compiler.h>
#include <errno.h>
+#ifdef HAVE_LIBUNWIND_ARM_SUPPORT
+#include <libunwind-arm.h>
+#endif
+
int __get_perf_regnum_for_unw_regnum_arm(int unw_regnum)
{
if (unw_regnum < 0 || unw_regnum >= PERF_REG_ARM_MAX) {
@@ -13,3 +18,17 @@ int __get_perf_regnum_for_unw_regnum_arm(int unw_regnum)
}
return unw_regnum;
}
+
+void __libunwind_arch__flush_access_arm(struct maps *maps __maybe_unused)
+{
+#ifdef HAVE_LIBUNWIND_ARM_SUPPORT
+ unw_flush_cache(maps__addr_space(maps), 0, 0);
+#endif
+}
+
+void __libunwind_arch__finish_access_arm(struct maps *maps __maybe_unused)
+{
+#ifdef HAVE_LIBUNWIND_ARM_SUPPORT
+ unw_destroy_addr_space(maps__addr_space(maps));
+#endif
+}
diff --git a/tools/perf/util/libunwind-arch/libunwind-arm64.c b/tools/perf/util/libunwind-arch/libunwind-arm64.c
index 53b1877dfa04..8ba510089736 100644
--- a/tools/perf/util/libunwind-arch/libunwind-arm64.c
+++ b/tools/perf/util/libunwind-arch/libunwind-arm64.c
@@ -1,9 +1,15 @@
// SPDX-License-Identifier: GPL-2.0
#include "libunwind-arch.h"
#include "../debug.h"
+#include "../maps.h"
#include "../../../arch/arm64/include/uapi/asm/perf_regs.h"
+#include <linux/compiler.h>
#include <errno.h>
+#ifdef HAVE_LIBUNWIND_AARCH64_SUPPORT
+#include <libunwind-aarch64.h>
+#endif
+
int __get_perf_regnum_for_unw_regnum_arm64(int unw_regnum)
{
if (unw_regnum < 0 || unw_regnum >= PERF_REG_ARM64_EXTENDED_MAX) {
@@ -12,3 +18,17 @@ int __get_perf_regnum_for_unw_regnum_arm64(int unw_regnum)
}
return unw_regnum;
}
+
+void __libunwind_arch__flush_access_arm64(struct maps *maps __maybe_unused)
+{
+#ifdef HAVE_LIBUNWIND_AARCH64_SUPPORT
+ unw_flush_cache(maps__addr_space(maps), 0, 0);
+#endif
+}
+
+void __libunwind_arch__finish_access_arm64(struct maps *maps __maybe_unused)
+{
+#ifdef HAVE_LIBUNWIND_AARCH64_SUPPORT
+ unw_destroy_addr_space(maps__addr_space(maps));
+#endif
+}
diff --git a/tools/perf/util/libunwind-arch/libunwind-i386.c b/tools/perf/util/libunwind-arch/libunwind-i386.c
index 9eaf4ebff0c2..45ff30c95c1b 100644
--- a/tools/perf/util/libunwind-arch/libunwind-i386.c
+++ b/tools/perf/util/libunwind-arch/libunwind-i386.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
#include "libunwind-arch.h"
#include "../debug.h"
+#include "../maps.h"
#include "../../../arch/x86/include/uapi/asm/perf_regs.h"
#include <linux/compiler.h>
#include <linux/kernel.h>
@@ -41,3 +42,17 @@ int __get_perf_regnum_for_unw_regnum_i386(int unw_regnum __maybe_unused)
return perf_i386_regnums[unw_regnum];
#endif // HAVE_LIBUNWIND_X86_SUPPORT
}
+
+void __libunwind_arch__flush_access_i386(struct maps *maps __maybe_unused)
+{
+#ifdef HAVE_LIBUNWIND_X86_SUPPORT
+ unw_flush_cache(maps__addr_space(maps), 0, 0);
+#endif
+}
+
+void __libunwind_arch__finish_access_i386(struct maps *maps __maybe_unused)
+{
+#ifdef HAVE_LIBUNWIND_X86_SUPPORT
+ unw_destroy_addr_space(maps__addr_space(maps));
+#endif
+}
diff --git a/tools/perf/util/libunwind-arch/libunwind-loongarch.c b/tools/perf/util/libunwind-arch/libunwind-loongarch.c
index 7009410989bc..837aa11e2b9f 100644
--- a/tools/perf/util/libunwind-arch/libunwind-loongarch.c
+++ b/tools/perf/util/libunwind-arch/libunwind-loongarch.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
#include "libunwind-arch.h"
#include "../debug.h"
+#include "../maps.h"
#include "../../../arch/loongarch/include/uapi/asm/perf_regs.h"
#include <linux/compiler.h>
#include <errno.h>
@@ -25,3 +26,17 @@ int __get_perf_regnum_for_unw_regnum_loongarch(int unw_regnum __maybe_unused)
}
#endif // HAVE_LIBUNWIND_LOONGARCH64_SUPPORT
}
+
+void __libunwind_arch__flush_access_loongarch(struct maps *maps __maybe_unused)
+{
+#ifdef HAVE_LIBUNWIND_LOONGARCH64_SUPPORT
+ unw_flush_cache(maps__addr_space(maps), 0, 0);
+#endif
+}
+
+void __libunwind_arch__finish_access_loongarch(struct maps *maps __maybe_unused)
+{
+#ifdef HAVE_LIBUNWIND_LOONGARCH64_SUPPORT
+ unw_destroy_addr_space(maps__addr_space(maps));
+#endif
+}
diff --git a/tools/perf/util/libunwind-arch/libunwind-mips.c b/tools/perf/util/libunwind-arch/libunwind-mips.c
index 01a506c8079c..1fa81742ff4a 100644
--- a/tools/perf/util/libunwind-arch/libunwind-mips.c
+++ b/tools/perf/util/libunwind-arch/libunwind-mips.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
#include "libunwind-arch.h"
#include "../debug.h"
+#include "../maps.h"
#include "../../../arch/mips/include/uapi/asm/perf_regs.h"
#include <linux/compiler.h>
#include <errno.h>
@@ -27,3 +28,17 @@ int __get_perf_regnum_for_unw_regnum_mips(int unw_regnum __maybe_unused)
}
#endif // HAVE_LIBUNWIND_MIPS_SUPPORT
}
+
+void __libunwind_arch__flush_access_mips(struct maps *maps __maybe_unused)
+{
+#ifdef HAVE_LIBUNWIND_MIPS_SUPPORT
+ unw_flush_cache(maps__addr_space(maps), 0, 0);
+#endif
+}
+
+void __libunwind_arch__finish_access_mips(struct maps *maps __maybe_unused)
+{
+#ifdef HAVE_LIBUNWIND_MIPS_SUPPORT
+ unw_destroy_addr_space(maps__addr_space(maps));
+#endif
+}
diff --git a/tools/perf/util/libunwind-arch/libunwind-ppc32.c b/tools/perf/util/libunwind-arch/libunwind-ppc32.c
index edcb0ec95dd7..fa8471c74bf3 100644
--- a/tools/perf/util/libunwind-arch/libunwind-ppc32.c
+++ b/tools/perf/util/libunwind-arch/libunwind-ppc32.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include "libunwind-arch.h"
#include "../debug.h"
+#include "../maps.h"
#include "../../../arch/powerpc/include/uapi/asm/perf_regs.h"
#include <linux/compiler.h>
#include <errno.h>
@@ -29,3 +30,17 @@ int __get_perf_regnum_for_unw_regnum_ppc32(int unw_regnum __maybe_unused)
}
#endif // HAVE_LIBUNWIND_PPC32_SUPPORT
}
+
+void __libunwind_arch__flush_access_ppc32(struct maps *maps __maybe_unused)
+{
+#ifdef HAVE_LIBUNWIND_PPC32_SUPPORT
+ unw_flush_cache(maps__addr_space(maps), 0, 0);
+#endif
+}
+
+void __libunwind_arch__finish_access_ppc32(struct maps *maps __maybe_unused)
+{
+#ifdef HAVE_LIBUNWIND_PPC32_SUPPORT
+ unw_destroy_addr_space(maps__addr_space(maps));
+#endif
+}
diff --git a/tools/perf/util/libunwind-arch/libunwind-ppc64.c b/tools/perf/util/libunwind-arch/libunwind-ppc64.c
index 9f57a049600b..2f746e347336 100644
--- a/tools/perf/util/libunwind-arch/libunwind-ppc64.c
+++ b/tools/perf/util/libunwind-arch/libunwind-ppc64.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include "libunwind-arch.h"
#include "../debug.h"
+#include "../maps.h"
#include "../../../arch/powerpc/include/uapi/asm/perf_regs.h"
#include <linux/compiler.h>
#include <errno.h>
@@ -31,3 +32,17 @@ int __get_perf_regnum_for_unw_regnum_ppc64(int unw_regnum __maybe_unused)
}
#endif // HAVE_LIBUNWIND_PPC64_SUPPORT
}
+
+void __libunwind_arch__flush_access_ppc64(struct maps *maps __maybe_unused)
+{
+#ifdef HAVE_LIBUNWIND_PPC64_SUPPORT
+ unw_flush_cache(maps__addr_space(maps), 0, 0);
+#endif
+}
+
+void __libunwind_arch__finish_access_ppc64(struct maps *maps __maybe_unused)
+{
+#ifdef HAVE_LIBUNWIND_PPC64_SUPPORT
+ unw_destroy_addr_space(maps__addr_space(maps));
+#endif
+}
diff --git a/tools/perf/util/libunwind-arch/libunwind-s390.c b/tools/perf/util/libunwind-arch/libunwind-s390.c
index 9fcc7885ca55..9f68d15438b2 100644
--- a/tools/perf/util/libunwind-arch/libunwind-s390.c
+++ b/tools/perf/util/libunwind-arch/libunwind-s390.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
#include "libunwind-arch.h"
#include "../debug.h"
+#include "../maps.h"
#include "../../../arch/s390/include/uapi/asm/perf_regs.h"
#include <linux/compiler.h>
#include <errno.h>
@@ -27,3 +28,17 @@ int __get_perf_regnum_for_unw_regnum_s390(int unw_regnum __maybe_unused)
}
#endif // HAVE_LIBUNWIND_S390X_SUPPORT
}
+
+void __libunwind_arch__flush_access_s390(struct maps *maps __maybe_unused)
+{
+#ifdef HAVE_LIBUNWIND_S390X_SUPPORT
+ unw_flush_cache(maps__addr_space(maps), 0, 0);
+#endif
+}
+
+void __libunwind_arch__finish_access_s390(struct maps *maps __maybe_unused)
+{
+#ifdef HAVE_LIBUNWIND_S390X_SUPPORT
+ unw_destroy_addr_space(maps__addr_space(maps));
+#endif
+}
diff --git a/tools/perf/util/libunwind-arch/libunwind-x86_64.c b/tools/perf/util/libunwind-arch/libunwind-x86_64.c
index 6072e3597e61..25e326bd3e15 100644
--- a/tools/perf/util/libunwind-arch/libunwind-x86_64.c
+++ b/tools/perf/util/libunwind-arch/libunwind-x86_64.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
#include "libunwind-arch.h"
#include "../debug.h"
+#include "../maps.h"
#include "../../../arch/x86/include/uapi/asm/perf_regs.h"
#include <linux/compiler.h>
#include <linux/kernel.h>
@@ -50,3 +51,17 @@ int __get_perf_regnum_for_unw_regnum_x86_64(int unw_regnum __maybe_unused)
return perf_x86_64_regnums[unw_regnum];
#endif // HAVE_LIBUNWIND_X86_64_SUPPORT
}
+
+void __libunwind_arch__flush_access_x86_64(struct maps *maps __maybe_unused)
+{
+#ifdef HAVE_LIBUNWIND_X86_64_SUPPORT
+ unw_flush_cache(maps__addr_space(maps), 0, 0);
+#endif
+}
+
+void __libunwind_arch__finish_access_x86_64(struct maps *maps __maybe_unused)
+{
+#ifdef HAVE_LIBUNWIND_X86_64_SUPPORT
+ unw_destroy_addr_space(maps__addr_space(maps));
+#endif
+}
diff --git a/tools/perf/util/maps.c b/tools/perf/util/maps.c
index 4092211cff62..8c7b2a1e7642 100644
--- a/tools/perf/util/maps.c
+++ b/tools/perf/util/maps.c
@@ -40,6 +40,7 @@ DECLARE_RC_STRUCT(maps) {
#ifdef HAVE_LIBUNWIND_SUPPORT
void *addr_space;
const struct unwind_libunwind_ops *unwind_libunwind_ops;
+ uint16_t e_machine;
#endif
#ifdef HAVE_LIBDW_SUPPORT
void *libdw_addr_space_dwfl;
@@ -206,6 +207,16 @@ void maps__set_unwind_libunwind_ops(struct maps *maps, const struct unwind_libun
{
RC_CHK_ACCESS(maps)->unwind_libunwind_ops = ops;
}
+
+uint16_t maps__e_machine(const struct maps *maps)
+{
+ return RC_CHK_ACCESS(maps)->e_machine;
+}
+
+void maps__set_e_machine(struct maps *maps, uint16_t e_machine)
+{
+ RC_CHK_ACCESS(maps)->e_machine = e_machine;
+}
#endif
#ifdef HAVE_LIBDW_SUPPORT
void *maps__libdw_addr_space_dwfl(const struct maps *maps)
@@ -1038,6 +1049,9 @@ int maps__copy_from(struct maps *dest, struct maps *parent)
down_write(maps__lock(dest));
down_read(maps__lock(parent));
+#ifdef HAVE_LIBUNWIND_SUPPORT
+ unwind__prepare_access(dest, maps__e_machine(parent));
+#endif
parent_maps_by_address = maps__maps_by_address(parent);
n = maps__nr_maps(parent);
if (maps__nr_maps(dest) == 0) {
@@ -1067,14 +1081,11 @@ int maps__copy_from(struct maps *dest, struct maps *parent)
if (!new)
err = -ENOMEM;
else {
- err = unwind__prepare_access(dest, new, NULL);
- if (!err) {
- dest_maps_by_address[i] = new;
- map__set_kmap_maps(new, dest);
- if (dest_maps_by_name)
- dest_maps_by_name[i] = map__get(new);
- RC_CHK_ACCESS(dest)->nr_maps = i + 1;
- }
+ dest_maps_by_address[i] = new;
+ map__set_kmap_maps(new, dest);
+ if (dest_maps_by_name)
+ dest_maps_by_name[i] = map__get(new);
+ RC_CHK_ACCESS(dest)->nr_maps = i + 1;
}
if (err)
map__put(new);
@@ -1099,9 +1110,7 @@ int maps__copy_from(struct maps *dest, struct maps *parent)
if (!new)
err = -ENOMEM;
else {
- err = unwind__prepare_access(dest, new, NULL);
- if (!err)
- err = __maps__insert(dest, new);
+ err = __maps__insert(dest, new);
}
map__put(new);
}
diff --git a/tools/perf/util/maps.h b/tools/perf/util/maps.h
index 20c52084ba9e..6469f62c41a8 100644
--- a/tools/perf/util/maps.h
+++ b/tools/perf/util/maps.h
@@ -51,6 +51,8 @@ void *maps__addr_space(const struct maps *maps);
void maps__set_addr_space(struct maps *maps, void *addr_space);
const struct unwind_libunwind_ops *maps__unwind_libunwind_ops(const struct maps *maps);
void maps__set_unwind_libunwind_ops(struct maps *maps, const struct unwind_libunwind_ops *ops);
+uint16_t maps__e_machine(const struct maps *maps);
+void maps__set_e_machine(struct maps *maps, uint16_t e_machine);
#endif
#ifdef HAVE_LIBDW_SUPPORT
void *maps__libdw_addr_space_dwfl(const struct maps *maps);
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c
index 22be77225bb0..c5df11ad329c 100644
--- a/tools/perf/util/thread.c
+++ b/tools/perf/util/thread.c
@@ -358,41 +358,20 @@ size_t thread__fprintf(struct thread *thread, FILE *fp)
int thread__insert_map(struct thread *thread, struct map *map)
{
int ret;
+ uint16_t e_machine = thread__e_machine(thread, /*machine=*/NULL, /*e_flags=*/NULL);
- ret = unwind__prepare_access(thread__maps(thread), map, NULL);
+ ret = unwind__prepare_access(thread__maps(thread), e_machine);
if (ret)
return ret;
return maps__fixup_overlap_and_insert(thread__maps(thread), map);
}
-struct thread__prepare_access_maps_cb_args {
- int err;
- struct maps *maps;
-};
-
-static int thread__prepare_access_maps_cb(struct map *map, void *data)
-{
- bool initialized = false;
- struct thread__prepare_access_maps_cb_args *args = data;
-
- args->err = unwind__prepare_access(args->maps, map, &initialized);
-
- return (args->err || initialized) ? 1 : 0;
-}
-
static int thread__prepare_access(struct thread *thread)
{
- struct thread__prepare_access_maps_cb_args args = {
- .err = 0,
- };
-
- if (dwarf_callchain_users) {
- args.maps = thread__maps(thread);
- maps__for_each_map(thread__maps(thread), thread__prepare_access_maps_cb, &args);
- }
+ uint16_t e_machine = thread__e_machine(thread, /*machine=*/NULL, /*e_flags=*/NULL);
- return args.err;
+ return unwind__prepare_access(thread__maps(thread), e_machine);
}
static int thread__clone_maps(struct thread *thread, struct thread *parent, bool do_maps_clone)
diff --git a/tools/perf/util/unwind-libunwind-local.c b/tools/perf/util/unwind-libunwind-local.c
index 3ecdb468b859..8f0128ba05a7 100644
--- a/tools/perf/util/unwind-libunwind-local.c
+++ b/tools/perf/util/unwind-libunwind-local.c
@@ -722,16 +722,6 @@ static int _unwind__prepare_access(struct maps *maps)
return 0;
}
-static void _unwind__flush_access(struct maps *maps)
-{
- unw_flush_cache(maps__addr_space(maps), 0, 0);
-}
-
-static void _unwind__finish_access(struct maps *maps)
-{
- unw_destroy_addr_space(maps__addr_space(maps));
-}
-
static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb,
void *arg, int max_stack)
{
@@ -821,8 +811,6 @@ static int _unwind__get_entries(unwind_entry_cb_t cb, void *arg,
static struct unwind_libunwind_ops
_unwind_libunwind_ops = {
.prepare_access = _unwind__prepare_access,
- .flush_access = _unwind__flush_access,
- .finish_access = _unwind__finish_access,
.get_entries = _unwind__get_entries,
};
diff --git a/tools/perf/util/unwind-libunwind.c b/tools/perf/util/unwind-libunwind.c
index a0016b897dae..eaee7b78d87c 100644
--- a/tools/perf/util/unwind-libunwind.c
+++ b/tools/perf/util/unwind-libunwind.c
@@ -7,76 +7,55 @@
#include "debug.h"
#include "env.h"
#include "callchain.h"
+#include "libunwind-arch/libunwind-arch.h"
+#include <dwarf-regs.h>
+#include <elf.h>
struct unwind_libunwind_ops __weak *local_unwind_libunwind_ops;
struct unwind_libunwind_ops __weak *x86_32_unwind_libunwind_ops;
struct unwind_libunwind_ops __weak *arm64_unwind_libunwind_ops;
-int unwind__prepare_access(struct maps *maps, struct map *map, bool *initialized)
+int unwind__prepare_access(struct maps *maps, uint16_t e_machine)
{
- const char *arch;
- enum dso_type dso_type;
struct unwind_libunwind_ops *ops = local_unwind_libunwind_ops;
- struct dso *dso = map__dso(map);
- struct machine *machine;
- int err;
if (!dwarf_callchain_users)
return 0;
if (maps__addr_space(maps)) {
- pr_debug("unwind: thread map already set, dso=%s\n", dso__name(dso));
- if (initialized)
- *initialized = true;
+ pr_debug3("unwind: thread map already set\n");
return 0;
}
- machine = maps__machine(maps);
- /* env->arch is NULL for live-mode (i.e. perf top) */
- if (!machine->env || !machine->env->arch)
- goto out_register;
-
- dso_type = dso__type(dso, machine);
- if (dso_type == DSO__TYPE_UNKNOWN)
- return 0;
-
- arch = perf_env__arch(machine->env);
-
- if (!strcmp(arch, "x86")) {
- if (dso_type != DSO__TYPE_64BIT)
+ if (e_machine != EM_HOST) {
+ /* If not live/local mode. */
+ switch (e_machine) {
+ case EM_386:
ops = x86_32_unwind_libunwind_ops;
- } else if (!strcmp(arch, "arm64") || !strcmp(arch, "arm")) {
- if (dso_type == DSO__TYPE_64BIT)
+ break;
+ case EM_AARCH64:
ops = arm64_unwind_libunwind_ops;
- }
-
- if (!ops) {
- pr_warning_once("unwind: target platform=%s is not supported\n", arch);
+ break;
+ default:
+ pr_warning_once("unwind: ELF machine type %d is not supported\n",
+ e_machine);
return 0;
+ }
}
-out_register:
maps__set_unwind_libunwind_ops(maps, ops);
+ maps__set_e_machine(maps, e_machine);
- err = maps__unwind_libunwind_ops(maps)->prepare_access(maps);
- if (initialized)
- *initialized = err ? false : true;
- return err;
+ return maps__unwind_libunwind_ops(maps)->prepare_access(maps);
}
void unwind__flush_access(struct maps *maps)
{
- const struct unwind_libunwind_ops *ops = maps__unwind_libunwind_ops(maps);
-
- if (ops)
- ops->flush_access(maps);
+ libunwind_arch__flush_access(maps);
}
void unwind__finish_access(struct maps *maps)
{
- const struct unwind_libunwind_ops *ops = maps__unwind_libunwind_ops(maps);
-
- if (ops)
- ops->finish_access(maps);
+ libunwind_arch__finish_access(maps);
}
int libunwind__get_entries(unwind_entry_cb_t cb, void *arg,
diff --git a/tools/perf/util/unwind.h b/tools/perf/util/unwind.h
index f8a8788ac986..ad610c5a241c 100644
--- a/tools/perf/util/unwind.h
+++ b/tools/perf/util/unwind.h
@@ -2,6 +2,7 @@
#ifndef __UNWIND_H
#define __UNWIND_H
+#include <stdint.h>
#include <linux/compiler.h>
#include <linux/types.h>
#include "map_symbol.h"
@@ -20,8 +21,6 @@ typedef int (*unwind_entry_cb_t)(struct unwind_entry *entry, void *arg);
struct unwind_libunwind_ops {
int (*prepare_access)(struct maps *maps);
- void (*flush_access)(struct maps *maps);
- void (*finish_access)(struct maps *maps);
int (*get_entries)(unwind_entry_cb_t cb, void *arg,
struct thread *thread,
struct perf_sample *data, int max_stack, bool best_effort);
@@ -64,7 +63,7 @@ int libunwind__get_entries(unwind_entry_cb_t cb, void *arg,
struct thread *thread,
struct perf_sample *data, int max_stack,
bool best_effort);
-int unwind__prepare_access(struct maps *maps, struct map *map, bool *initialized);
+int unwind__prepare_access(struct maps *maps, uint16_t e_machine);
void unwind__flush_access(struct maps *maps);
void unwind__finish_access(struct maps *maps);
#else
@@ -81,8 +80,7 @@ static inline int libunwind__get_entries(unwind_entry_cb_t cb __maybe_unused,
}
static inline int unwind__prepare_access(struct maps *maps __maybe_unused,
- struct map *map __maybe_unused,
- bool *initialized __maybe_unused)
+ uint16_t e_machine __maybe_unused)
{
return 0;
}
--
2.53.0.1213.gd9a14994de-goog
^ permalink raw reply related
* [PATCH v3 5/8] perf unwind-libunwind: Make libunwind register reading cross platform
From: Ian Rogers @ 2026-04-04 5:40 UTC (permalink / raw)
To: acme
Cc: irogers, 9erthalion6, adrian.hunter, alex, alexander.shishkin,
andrew.jones, aou, atrajeev, blakejones, ctshao, dapeng1.mi,
howardchu95, james.clark, john.g.garry, jolsa, leo.yan,
libunwind-devel, linux-arm-kernel, linux-kernel, linux-perf-users,
linux-riscv, mingo, namhyung, palmer, peterz, pjw, shimin.guo,
tglozar, tmricht, will, yuzhuo
In-Reply-To: <20260404054032.1538095-1-irogers@google.com>
Move the libunwind register to perf register mapping functions in
arch/../util/unwind-libunwind.c into a new libunwind-arch
directory. Rename the functions to
__get_perf_regnum_for_unw_regnum_<arch>. Add untested ppc32 and s390
functions. Add a get_perf_regnum_for_unw_regnum function that takes an
ELF machine as well as a register number and chooses the appropriate
architecture implementation.
Split the x86 and powerpc 32 and 64-bit implementations apart so that
a single libunwind-<arch>.h header is included.
Move the e_machine into the unwind_info struct to make it easier to
pass.
Signed-off-by: Ian Rogers <irogers@google.com>
---
tools/perf/arch/arm/util/Build | 2 -
tools/perf/arch/arm/util/unwind-libunwind.c | 50 --------
tools/perf/arch/arm64/util/Build | 1 -
tools/perf/arch/arm64/util/unwind-libunwind.c | 17 ---
tools/perf/arch/loongarch/util/Build | 2 -
.../arch/loongarch/util/unwind-libunwind.c | 82 -------------
tools/perf/arch/mips/Build | 1 -
tools/perf/arch/mips/util/Build | 1 -
tools/perf/arch/mips/util/unwind-libunwind.c | 22 ----
tools/perf/arch/powerpc/util/Build | 1 -
.../perf/arch/powerpc/util/unwind-libunwind.c | 92 --------------
tools/perf/arch/x86/util/Build | 3 -
tools/perf/arch/x86/util/unwind-libunwind.c | 115 ------------------
tools/perf/util/Build | 1 +
tools/perf/util/libunwind-arch/Build | 10 ++
.../perf/util/libunwind-arch/libunwind-arch.c | 32 +++++
.../perf/util/libunwind-arch/libunwind-arch.h | 16 +++
.../perf/util/libunwind-arch/libunwind-arm.c | 15 +++
.../util/libunwind-arch/libunwind-arm64.c | 14 +++
.../perf/util/libunwind-arch/libunwind-i386.c | 43 +++++++
.../util/libunwind-arch/libunwind-loongarch.c | 27 ++++
.../perf/util/libunwind-arch/libunwind-mips.c | 29 +++++
.../util/libunwind-arch/libunwind-ppc32.c | 31 +++++
.../util/libunwind-arch/libunwind-ppc64.c | 33 +++++
.../perf/util/libunwind-arch/libunwind-s390.c | 29 +++++
.../util/libunwind-arch/libunwind-x86_64.c | 52 ++++++++
tools/perf/util/libunwind/arm64.c | 5 -
tools/perf/util/libunwind/x86_32.c | 12 --
tools/perf/util/unwind-libunwind-local.c | 12 +-
tools/perf/util/unwind.h | 5 -
30 files changed, 338 insertions(+), 417 deletions(-)
delete mode 100644 tools/perf/arch/arm/util/unwind-libunwind.c
delete mode 100644 tools/perf/arch/arm64/util/unwind-libunwind.c
delete mode 100644 tools/perf/arch/loongarch/util/unwind-libunwind.c
delete mode 100644 tools/perf/arch/mips/Build
delete mode 100644 tools/perf/arch/mips/util/Build
delete mode 100644 tools/perf/arch/mips/util/unwind-libunwind.c
delete mode 100644 tools/perf/arch/powerpc/util/unwind-libunwind.c
delete mode 100644 tools/perf/arch/x86/util/unwind-libunwind.c
create mode 100644 tools/perf/util/libunwind-arch/Build
create mode 100644 tools/perf/util/libunwind-arch/libunwind-arch.c
create mode 100644 tools/perf/util/libunwind-arch/libunwind-arch.h
create mode 100644 tools/perf/util/libunwind-arch/libunwind-arm.c
create mode 100644 tools/perf/util/libunwind-arch/libunwind-arm64.c
create mode 100644 tools/perf/util/libunwind-arch/libunwind-i386.c
create mode 100644 tools/perf/util/libunwind-arch/libunwind-loongarch.c
create mode 100644 tools/perf/util/libunwind-arch/libunwind-mips.c
create mode 100644 tools/perf/util/libunwind-arch/libunwind-ppc32.c
create mode 100644 tools/perf/util/libunwind-arch/libunwind-ppc64.c
create mode 100644 tools/perf/util/libunwind-arch/libunwind-s390.c
create mode 100644 tools/perf/util/libunwind-arch/libunwind-x86_64.c
diff --git a/tools/perf/arch/arm/util/Build b/tools/perf/arch/arm/util/Build
index b94bf3c5279a..768ae5d16553 100644
--- a/tools/perf/arch/arm/util/Build
+++ b/tools/perf/arch/arm/util/Build
@@ -1,3 +1 @@
-perf-util-$(CONFIG_LOCAL_LIBUNWIND) += unwind-libunwind.o
-
perf-util-y += pmu.o auxtrace.o cs-etm.o
diff --git a/tools/perf/arch/arm/util/unwind-libunwind.c b/tools/perf/arch/arm/util/unwind-libunwind.c
deleted file mode 100644
index 438906bf0014..000000000000
--- a/tools/perf/arch/arm/util/unwind-libunwind.c
+++ /dev/null
@@ -1,50 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-
-#include <errno.h>
-#include <libunwind.h>
-#include "perf_regs.h"
-#include "../../../util/unwind.h"
-#include "../../../util/debug.h"
-
-int libunwind__arch_reg_id(int regnum)
-{
- switch (regnum) {
- case UNW_ARM_R0:
- return PERF_REG_ARM_R0;
- case UNW_ARM_R1:
- return PERF_REG_ARM_R1;
- case UNW_ARM_R2:
- return PERF_REG_ARM_R2;
- case UNW_ARM_R3:
- return PERF_REG_ARM_R3;
- case UNW_ARM_R4:
- return PERF_REG_ARM_R4;
- case UNW_ARM_R5:
- return PERF_REG_ARM_R5;
- case UNW_ARM_R6:
- return PERF_REG_ARM_R6;
- case UNW_ARM_R7:
- return PERF_REG_ARM_R7;
- case UNW_ARM_R8:
- return PERF_REG_ARM_R8;
- case UNW_ARM_R9:
- return PERF_REG_ARM_R9;
- case UNW_ARM_R10:
- return PERF_REG_ARM_R10;
- case UNW_ARM_R11:
- return PERF_REG_ARM_FP;
- case UNW_ARM_R12:
- return PERF_REG_ARM_IP;
- case UNW_ARM_R13:
- return PERF_REG_ARM_SP;
- case UNW_ARM_R14:
- return PERF_REG_ARM_LR;
- case UNW_ARM_R15:
- return PERF_REG_ARM_PC;
- default:
- pr_err("unwind: invalid reg id %d\n", regnum);
- return -EINVAL;
- }
-
- return -EINVAL;
-}
diff --git a/tools/perf/arch/arm64/util/Build b/tools/perf/arch/arm64/util/Build
index 4e06a08d281a..4b70c4788c80 100644
--- a/tools/perf/arch/arm64/util/Build
+++ b/tools/perf/arch/arm64/util/Build
@@ -1,4 +1,3 @@
-perf-util-$(CONFIG_LOCAL_LIBUNWIND) += unwind-libunwind.o
perf-util-y += ../../arm/util/auxtrace.o
perf-util-y += ../../arm/util/cs-etm.o
perf-util-y += ../../arm/util/pmu.o
diff --git a/tools/perf/arch/arm64/util/unwind-libunwind.c b/tools/perf/arch/arm64/util/unwind-libunwind.c
deleted file mode 100644
index 871af5992298..000000000000
--- a/tools/perf/arch/arm64/util/unwind-libunwind.c
+++ /dev/null
@@ -1,17 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-#include <errno.h>
-
-#ifndef REMOTE_UNWIND_LIBUNWIND
-#include <libunwind.h>
-#include "perf_regs.h"
-#include "../../../util/unwind.h"
-#endif
-#include "../../../util/debug.h"
-
-int LIBUNWIND__ARCH_REG_ID(int regnum)
-{
- if (regnum < 0 || regnum >= PERF_REG_ARM64_EXTENDED_MAX)
- return -EINVAL;
-
- return regnum;
-}
diff --git a/tools/perf/arch/loongarch/util/Build b/tools/perf/arch/loongarch/util/Build
index 8d91e78d31c9..2328fb9a30a3 100644
--- a/tools/perf/arch/loongarch/util/Build
+++ b/tools/perf/arch/loongarch/util/Build
@@ -1,3 +1 @@
perf-util-y += header.o
-
-perf-util-$(CONFIG_LOCAL_LIBUNWIND) += unwind-libunwind.o
diff --git a/tools/perf/arch/loongarch/util/unwind-libunwind.c b/tools/perf/arch/loongarch/util/unwind-libunwind.c
deleted file mode 100644
index f693167b86ef..000000000000
--- a/tools/perf/arch/loongarch/util/unwind-libunwind.c
+++ /dev/null
@@ -1,82 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-
-#include <errno.h>
-#include <libunwind.h>
-#include "perf_regs.h"
-#include "../../util/unwind.h"
-#include "util/debug.h"
-
-int libunwind__arch_reg_id(int regnum)
-{
- switch (regnum) {
- case UNW_LOONGARCH64_R1:
- return PERF_REG_LOONGARCH_R1;
- case UNW_LOONGARCH64_R2:
- return PERF_REG_LOONGARCH_R2;
- case UNW_LOONGARCH64_R3:
- return PERF_REG_LOONGARCH_R3;
- case UNW_LOONGARCH64_R4:
- return PERF_REG_LOONGARCH_R4;
- case UNW_LOONGARCH64_R5:
- return PERF_REG_LOONGARCH_R5;
- case UNW_LOONGARCH64_R6:
- return PERF_REG_LOONGARCH_R6;
- case UNW_LOONGARCH64_R7:
- return PERF_REG_LOONGARCH_R7;
- case UNW_LOONGARCH64_R8:
- return PERF_REG_LOONGARCH_R8;
- case UNW_LOONGARCH64_R9:
- return PERF_REG_LOONGARCH_R9;
- case UNW_LOONGARCH64_R10:
- return PERF_REG_LOONGARCH_R10;
- case UNW_LOONGARCH64_R11:
- return PERF_REG_LOONGARCH_R11;
- case UNW_LOONGARCH64_R12:
- return PERF_REG_LOONGARCH_R12;
- case UNW_LOONGARCH64_R13:
- return PERF_REG_LOONGARCH_R13;
- case UNW_LOONGARCH64_R14:
- return PERF_REG_LOONGARCH_R14;
- case UNW_LOONGARCH64_R15:
- return PERF_REG_LOONGARCH_R15;
- case UNW_LOONGARCH64_R16:
- return PERF_REG_LOONGARCH_R16;
- case UNW_LOONGARCH64_R17:
- return PERF_REG_LOONGARCH_R17;
- case UNW_LOONGARCH64_R18:
- return PERF_REG_LOONGARCH_R18;
- case UNW_LOONGARCH64_R19:
- return PERF_REG_LOONGARCH_R19;
- case UNW_LOONGARCH64_R20:
- return PERF_REG_LOONGARCH_R20;
- case UNW_LOONGARCH64_R21:
- return PERF_REG_LOONGARCH_R21;
- case UNW_LOONGARCH64_R22:
- return PERF_REG_LOONGARCH_R22;
- case UNW_LOONGARCH64_R23:
- return PERF_REG_LOONGARCH_R23;
- case UNW_LOONGARCH64_R24:
- return PERF_REG_LOONGARCH_R24;
- case UNW_LOONGARCH64_R25:
- return PERF_REG_LOONGARCH_R25;
- case UNW_LOONGARCH64_R26:
- return PERF_REG_LOONGARCH_R26;
- case UNW_LOONGARCH64_R27:
- return PERF_REG_LOONGARCH_R27;
- case UNW_LOONGARCH64_R28:
- return PERF_REG_LOONGARCH_R28;
- case UNW_LOONGARCH64_R29:
- return PERF_REG_LOONGARCH_R29;
- case UNW_LOONGARCH64_R30:
- return PERF_REG_LOONGARCH_R30;
- case UNW_LOONGARCH64_R31:
- return PERF_REG_LOONGARCH_R31;
- case UNW_LOONGARCH64_PC:
- return PERF_REG_LOONGARCH_PC;
- default:
- pr_err("unwind: invalid reg id %d\n", regnum);
- return -EINVAL;
- }
-
- return -EINVAL;
-}
diff --git a/tools/perf/arch/mips/Build b/tools/perf/arch/mips/Build
deleted file mode 100644
index e63eabc2c8f4..000000000000
--- a/tools/perf/arch/mips/Build
+++ /dev/null
@@ -1 +0,0 @@
-perf-util-y += util/
diff --git a/tools/perf/arch/mips/util/Build b/tools/perf/arch/mips/util/Build
deleted file mode 100644
index 818b808a8247..000000000000
--- a/tools/perf/arch/mips/util/Build
+++ /dev/null
@@ -1 +0,0 @@
-perf-util-$(CONFIG_LOCAL_LIBUNWIND) += unwind-libunwind.o
diff --git a/tools/perf/arch/mips/util/unwind-libunwind.c b/tools/perf/arch/mips/util/unwind-libunwind.c
deleted file mode 100644
index 0d8c99c29da6..000000000000
--- a/tools/perf/arch/mips/util/unwind-libunwind.c
+++ /dev/null
@@ -1,22 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-
-#include <errno.h>
-#include <libunwind.h>
-#include "perf_regs.h"
-#include "../../util/unwind.h"
-#include "util/debug.h"
-
-int libunwind__arch_reg_id(int regnum)
-{
- switch (regnum) {
- case UNW_MIPS_R1 ... UNW_MIPS_R25:
- return regnum - UNW_MIPS_R1 + PERF_REG_MIPS_R1;
- case UNW_MIPS_R28 ... UNW_MIPS_R31:
- return regnum - UNW_MIPS_R28 + PERF_REG_MIPS_R28;
- case UNW_MIPS_PC:
- return PERF_REG_MIPS_PC;
- default:
- pr_err("unwind: invalid reg id %d\n", regnum);
- return -EINVAL;
- }
-}
diff --git a/tools/perf/arch/powerpc/util/Build b/tools/perf/arch/powerpc/util/Build
index d66574cbb9a9..ae928050e07a 100644
--- a/tools/perf/arch/powerpc/util/Build
+++ b/tools/perf/arch/powerpc/util/Build
@@ -6,5 +6,4 @@ perf-util-y += evsel.o
perf-util-$(CONFIG_LIBDW) += skip-callchain-idx.o
-perf-util-$(CONFIG_LIBUNWIND) += unwind-libunwind.o
perf-util-y += auxtrace.o
diff --git a/tools/perf/arch/powerpc/util/unwind-libunwind.c b/tools/perf/arch/powerpc/util/unwind-libunwind.c
deleted file mode 100644
index 90a6beda20de..000000000000
--- a/tools/perf/arch/powerpc/util/unwind-libunwind.c
+++ /dev/null
@@ -1,92 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Copyright 2016 Chandan Kumar, IBM Corporation.
- */
-
-#include <errno.h>
-#include <libunwind.h>
-#include <asm/perf_regs.h>
-#include "../../util/unwind.h"
-#include "../../util/debug.h"
-
-int libunwind__arch_reg_id(int regnum)
-{
- switch (regnum) {
- case UNW_PPC64_R0:
- return PERF_REG_POWERPC_R0;
- case UNW_PPC64_R1:
- return PERF_REG_POWERPC_R1;
- case UNW_PPC64_R2:
- return PERF_REG_POWERPC_R2;
- case UNW_PPC64_R3:
- return PERF_REG_POWERPC_R3;
- case UNW_PPC64_R4:
- return PERF_REG_POWERPC_R4;
- case UNW_PPC64_R5:
- return PERF_REG_POWERPC_R5;
- case UNW_PPC64_R6:
- return PERF_REG_POWERPC_R6;
- case UNW_PPC64_R7:
- return PERF_REG_POWERPC_R7;
- case UNW_PPC64_R8:
- return PERF_REG_POWERPC_R8;
- case UNW_PPC64_R9:
- return PERF_REG_POWERPC_R9;
- case UNW_PPC64_R10:
- return PERF_REG_POWERPC_R10;
- case UNW_PPC64_R11:
- return PERF_REG_POWERPC_R11;
- case UNW_PPC64_R12:
- return PERF_REG_POWERPC_R12;
- case UNW_PPC64_R13:
- return PERF_REG_POWERPC_R13;
- case UNW_PPC64_R14:
- return PERF_REG_POWERPC_R14;
- case UNW_PPC64_R15:
- return PERF_REG_POWERPC_R15;
- case UNW_PPC64_R16:
- return PERF_REG_POWERPC_R16;
- case UNW_PPC64_R17:
- return PERF_REG_POWERPC_R17;
- case UNW_PPC64_R18:
- return PERF_REG_POWERPC_R18;
- case UNW_PPC64_R19:
- return PERF_REG_POWERPC_R19;
- case UNW_PPC64_R20:
- return PERF_REG_POWERPC_R20;
- case UNW_PPC64_R21:
- return PERF_REG_POWERPC_R21;
- case UNW_PPC64_R22:
- return PERF_REG_POWERPC_R22;
- case UNW_PPC64_R23:
- return PERF_REG_POWERPC_R23;
- case UNW_PPC64_R24:
- return PERF_REG_POWERPC_R24;
- case UNW_PPC64_R25:
- return PERF_REG_POWERPC_R25;
- case UNW_PPC64_R26:
- return PERF_REG_POWERPC_R26;
- case UNW_PPC64_R27:
- return PERF_REG_POWERPC_R27;
- case UNW_PPC64_R28:
- return PERF_REG_POWERPC_R28;
- case UNW_PPC64_R29:
- return PERF_REG_POWERPC_R29;
- case UNW_PPC64_R30:
- return PERF_REG_POWERPC_R30;
- case UNW_PPC64_R31:
- return PERF_REG_POWERPC_R31;
- case UNW_PPC64_LR:
- return PERF_REG_POWERPC_LINK;
- case UNW_PPC64_CTR:
- return PERF_REG_POWERPC_CTR;
- case UNW_PPC64_XER:
- return PERF_REG_POWERPC_XER;
- case UNW_PPC64_NIP:
- return PERF_REG_POWERPC_NIP;
- default:
- pr_err("unwind: invalid reg id %d\n", regnum);
- return -EINVAL;
- }
- return -EINVAL;
-}
diff --git a/tools/perf/arch/x86/util/Build b/tools/perf/arch/x86/util/Build
index b94c91984c66..7f89fffe4615 100644
--- a/tools/perf/arch/x86/util/Build
+++ b/tools/perf/arch/x86/util/Build
@@ -8,9 +8,6 @@ perf-util-y += evlist.o
perf-util-y += mem-events.o
perf-util-y += evsel.o
perf-util-y += iostat.o
-
-perf-util-$(CONFIG_LOCAL_LIBUNWIND) += unwind-libunwind.o
-
perf-util-y += auxtrace.o
perf-util-y += intel-pt.o
perf-util-y += intel-bts.o
diff --git a/tools/perf/arch/x86/util/unwind-libunwind.c b/tools/perf/arch/x86/util/unwind-libunwind.c
deleted file mode 100644
index 47357973b55b..000000000000
--- a/tools/perf/arch/x86/util/unwind-libunwind.c
+++ /dev/null
@@ -1,115 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-
-#include <errno.h>
-#include "../../util/debug.h"
-#ifndef REMOTE_UNWIND_LIBUNWIND
-#include <libunwind.h>
-#include "perf_regs.h"
-#include "../../util/unwind.h"
-#endif
-
-#ifdef HAVE_ARCH_X86_64_SUPPORT
-int LIBUNWIND__ARCH_REG_ID(int regnum)
-{
- int id;
-
- switch (regnum) {
- case UNW_X86_64_RAX:
- id = PERF_REG_X86_AX;
- break;
- case UNW_X86_64_RDX:
- id = PERF_REG_X86_DX;
- break;
- case UNW_X86_64_RCX:
- id = PERF_REG_X86_CX;
- break;
- case UNW_X86_64_RBX:
- id = PERF_REG_X86_BX;
- break;
- case UNW_X86_64_RSI:
- id = PERF_REG_X86_SI;
- break;
- case UNW_X86_64_RDI:
- id = PERF_REG_X86_DI;
- break;
- case UNW_X86_64_RBP:
- id = PERF_REG_X86_BP;
- break;
- case UNW_X86_64_RSP:
- id = PERF_REG_X86_SP;
- break;
- case UNW_X86_64_R8:
- id = PERF_REG_X86_R8;
- break;
- case UNW_X86_64_R9:
- id = PERF_REG_X86_R9;
- break;
- case UNW_X86_64_R10:
- id = PERF_REG_X86_R10;
- break;
- case UNW_X86_64_R11:
- id = PERF_REG_X86_R11;
- break;
- case UNW_X86_64_R12:
- id = PERF_REG_X86_R12;
- break;
- case UNW_X86_64_R13:
- id = PERF_REG_X86_R13;
- break;
- case UNW_X86_64_R14:
- id = PERF_REG_X86_R14;
- break;
- case UNW_X86_64_R15:
- id = PERF_REG_X86_R15;
- break;
- case UNW_X86_64_RIP:
- id = PERF_REG_X86_IP;
- break;
- default:
- pr_err("unwind: invalid reg id %d\n", regnum);
- return -EINVAL;
- }
-
- return id;
-}
-#else
-int LIBUNWIND__ARCH_REG_ID(int regnum)
-{
- int id;
-
- switch (regnum) {
- case UNW_X86_EAX:
- id = PERF_REG_X86_AX;
- break;
- case UNW_X86_EDX:
- id = PERF_REG_X86_DX;
- break;
- case UNW_X86_ECX:
- id = PERF_REG_X86_CX;
- break;
- case UNW_X86_EBX:
- id = PERF_REG_X86_BX;
- break;
- case UNW_X86_ESI:
- id = PERF_REG_X86_SI;
- break;
- case UNW_X86_EDI:
- id = PERF_REG_X86_DI;
- break;
- case UNW_X86_EBP:
- id = PERF_REG_X86_BP;
- break;
- case UNW_X86_ESP:
- id = PERF_REG_X86_SP;
- break;
- case UNW_X86_EIP:
- id = PERF_REG_X86_IP;
- break;
- default:
- pr_err("unwind: invalid reg id %d\n", regnum);
- return -EINVAL;
- }
-
- return id;
-}
-#endif /* HAVE_ARCH_X86_64_SUPPORT */
diff --git a/tools/perf/util/Build b/tools/perf/util/Build
index 01edfccebb88..bf4204135ccb 100644
--- a/tools/perf/util/Build
+++ b/tools/perf/util/Build
@@ -228,6 +228,7 @@ perf-util-$(CONFIG_LIBDW) += unwind-libdw.o
perf-util-$(CONFIG_LOCAL_LIBUNWIND) += unwind-libunwind-local.o
perf-util-$(CONFIG_LIBUNWIND) += unwind-libunwind.o
+perf-util-$(CONFIG_LIBUNWIND) += libunwind-arch/
perf-util-$(CONFIG_LIBUNWIND_X86) += libunwind/x86_32.o
perf-util-$(CONFIG_LIBUNWIND_AARCH64) += libunwind/arm64.o
diff --git a/tools/perf/util/libunwind-arch/Build b/tools/perf/util/libunwind-arch/Build
new file mode 100644
index 000000000000..87fd657a3248
--- /dev/null
+++ b/tools/perf/util/libunwind-arch/Build
@@ -0,0 +1,10 @@
+perf-util-$(CONFIG_LIBUNWIND) += libunwind-arch.o
+perf-util-$(CONFIG_LIBUNWIND) += libunwind-arm64.o
+perf-util-$(CONFIG_LIBUNWIND) += libunwind-arm.o
+perf-util-$(CONFIG_LIBUNWIND) += libunwind-loongarch.o
+perf-util-$(CONFIG_LIBUNWIND) += libunwind-mips.o
+perf-util-$(CONFIG_LIBUNWIND) += libunwind-ppc32.o
+perf-util-$(CONFIG_LIBUNWIND) += libunwind-ppc64.o
+perf-util-$(CONFIG_LIBUNWIND) += libunwind-s390.o
+perf-util-$(CONFIG_LIBUNWIND) += libunwind-i386.o
+perf-util-$(CONFIG_LIBUNWIND) += libunwind-x86_64.o
diff --git a/tools/perf/util/libunwind-arch/libunwind-arch.c b/tools/perf/util/libunwind-arch/libunwind-arch.c
new file mode 100644
index 000000000000..5439bf90d161
--- /dev/null
+++ b/tools/perf/util/libunwind-arch/libunwind-arch.c
@@ -0,0 +1,32 @@
+// SPDX-License-Identifier: GPL-2.0
+#include "libunwind-arch.h"
+#include "../debug.h"
+#include <elf.h>
+#include <errno.h>
+
+int get_perf_regnum_for_unw_regnum(unsigned int e_machine, int unw_regnum)
+{
+ switch (e_machine) {
+ case EM_ARM:
+ return __get_perf_regnum_for_unw_regnum_arm(unw_regnum);
+ case EM_AARCH64:
+ return __get_perf_regnum_for_unw_regnum_arm64(unw_regnum);
+ case EM_LOONGARCH:
+ return __get_perf_regnum_for_unw_regnum_loongarch(unw_regnum);
+ case EM_MIPS:
+ return __get_perf_regnum_for_unw_regnum_mips(unw_regnum);
+ case EM_PPC:
+ return __get_perf_regnum_for_unw_regnum_ppc32(unw_regnum);
+ case EM_PPC64:
+ return __get_perf_regnum_for_unw_regnum_ppc64(unw_regnum);
+ case EM_S390:
+ return __get_perf_regnum_for_unw_regnum_s390(unw_regnum);
+ case EM_386:
+ return __get_perf_regnum_for_unw_regnum_i386(unw_regnum);
+ case EM_X86_64:
+ return __get_perf_regnum_for_unw_regnum_x86_64(unw_regnum);
+ default:
+ pr_err("ELF MACHINE %x is not supported.\n", e_machine);
+ return -EINVAL;
+ }
+}
diff --git a/tools/perf/util/libunwind-arch/libunwind-arch.h b/tools/perf/util/libunwind-arch/libunwind-arch.h
new file mode 100644
index 000000000000..e1009c6cb965
--- /dev/null
+++ b/tools/perf/util/libunwind-arch/libunwind-arch.h
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __LIBUNWIND_ARCH_H
+#define __LIBUNWIND_ARCH_H
+
+int __get_perf_regnum_for_unw_regnum_arm(int unw_regnum);
+int __get_perf_regnum_for_unw_regnum_arm64(int unw_regnum);
+int __get_perf_regnum_for_unw_regnum_loongarch(int unw_regnum);
+int __get_perf_regnum_for_unw_regnum_mips(int unw_regnum);
+int __get_perf_regnum_for_unw_regnum_ppc32(int unw_regnum);
+int __get_perf_regnum_for_unw_regnum_ppc64(int unw_regnum);
+int __get_perf_regnum_for_unw_regnum_s390(int unw_regnum);
+int __get_perf_regnum_for_unw_regnum_i386(int unw_regnum);
+int __get_perf_regnum_for_unw_regnum_x86_64(int unw_regnum);
+int get_perf_regnum_for_unw_regnum(unsigned int e_machine, int unw_regnum);
+
+#endif /* __LIBUNWIND_ARCH_H */
diff --git a/tools/perf/util/libunwind-arch/libunwind-arm.c b/tools/perf/util/libunwind-arch/libunwind-arm.c
new file mode 100644
index 000000000000..6740ee55b043
--- /dev/null
+++ b/tools/perf/util/libunwind-arch/libunwind-arm.c
@@ -0,0 +1,15 @@
+// SPDX-License-Identifier: GPL-2.0
+#include "libunwind-arch.h"
+#include "../debug.h"
+#include "../../../arch/arm/include/uapi/asm/perf_regs.h"
+#include <linux/compiler.h>
+#include <errno.h>
+
+int __get_perf_regnum_for_unw_regnum_arm(int unw_regnum)
+{
+ if (unw_regnum < 0 || unw_regnum >= PERF_REG_ARM_MAX) {
+ pr_err("unwind: invalid reg id %d\n", unw_regnum);
+ return -EINVAL;
+ }
+ return unw_regnum;
+}
diff --git a/tools/perf/util/libunwind-arch/libunwind-arm64.c b/tools/perf/util/libunwind-arch/libunwind-arm64.c
new file mode 100644
index 000000000000..53b1877dfa04
--- /dev/null
+++ b/tools/perf/util/libunwind-arch/libunwind-arm64.c
@@ -0,0 +1,14 @@
+// SPDX-License-Identifier: GPL-2.0
+#include "libunwind-arch.h"
+#include "../debug.h"
+#include "../../../arch/arm64/include/uapi/asm/perf_regs.h"
+#include <errno.h>
+
+int __get_perf_regnum_for_unw_regnum_arm64(int unw_regnum)
+{
+ if (unw_regnum < 0 || unw_regnum >= PERF_REG_ARM64_EXTENDED_MAX) {
+ pr_err("unwind: invalid reg id %d\n", unw_regnum);
+ return -EINVAL;
+ }
+ return unw_regnum;
+}
diff --git a/tools/perf/util/libunwind-arch/libunwind-i386.c b/tools/perf/util/libunwind-arch/libunwind-i386.c
new file mode 100644
index 000000000000..9eaf4ebff0c2
--- /dev/null
+++ b/tools/perf/util/libunwind-arch/libunwind-i386.c
@@ -0,0 +1,43 @@
+// SPDX-License-Identifier: GPL-2.0
+#include "libunwind-arch.h"
+#include "../debug.h"
+#include "../../../arch/x86/include/uapi/asm/perf_regs.h"
+#include <linux/compiler.h>
+#include <linux/kernel.h>
+#include <errno.h>
+
+#ifdef HAVE_LIBUNWIND_X86_SUPPORT
+#include <libunwind-x86.h>
+#endif
+
+int __get_perf_regnum_for_unw_regnum_i386(int unw_regnum __maybe_unused)
+{
+#ifndef HAVE_LIBUNWIND_X86_SUPPORT
+ return -EINVAL;
+#else
+ static const int perf_i386_regnums[] = {
+#define REGNUM(reg) [UNW_X86_E ## reg] = PERF_REG_X86_ ## reg
+ REGNUM(AX),
+ REGNUM(DX),
+ REGNUM(CX),
+ REGNUM(BX),
+ REGNUM(SI),
+ REGNUM(DI),
+ REGNUM(BP),
+ REGNUM(SP),
+ REGNUM(IP),
+#undef REGNUM
+ };
+
+ if (unw_regnum == UNW_X86_EAX)
+ return PERF_REG_X86_AX;
+
+ if (unw_regnum < 0 || unw_regnum > (int)ARRAY_SIZE(perf_i386_regnums) ||
+ perf_i386_regnums[unw_regnum] == 0) {
+ pr_err("unwind: invalid reg id %d\n", unw_regnum);
+ return -EINVAL;
+ }
+
+ return perf_i386_regnums[unw_regnum];
+#endif // HAVE_LIBUNWIND_X86_SUPPORT
+}
diff --git a/tools/perf/util/libunwind-arch/libunwind-loongarch.c b/tools/perf/util/libunwind-arch/libunwind-loongarch.c
new file mode 100644
index 000000000000..7009410989bc
--- /dev/null
+++ b/tools/perf/util/libunwind-arch/libunwind-loongarch.c
@@ -0,0 +1,27 @@
+// SPDX-License-Identifier: GPL-2.0
+#include "libunwind-arch.h"
+#include "../debug.h"
+#include "../../../arch/loongarch/include/uapi/asm/perf_regs.h"
+#include <linux/compiler.h>
+#include <errno.h>
+
+#ifdef HAVE_LIBUNWIND_LOONGARCH64_SUPPORT
+#include <libunwind-loongarch64.h>
+#endif
+
+int __get_perf_regnum_for_unw_regnum_loongarch(int unw_regnum __maybe_unused)
+{
+#ifndef HAVE_LIBUNWIND_LOONGARCH64_SUPPORT
+ return -EINVAL;
+#else
+ switch (unw_regnum) {
+ case UNW_LOONGARCH64_R1 ... UNW_LOONGARCH64_31:
+ return unw_regnum - UNW_LOONGARCH64_R1 + PERF_REG_LOONGARCH_R1;
+ case UNW_LOONGARCH64_PC:
+ return PERF_REG_LOONGARCH_PC;
+ default:
+ pr_err("unwind: invalid reg id %d\n", unw_regnum);
+ return -EINVAL;
+ }
+#endif // HAVE_LIBUNWIND_LOONGARCH64_SUPPORT
+}
diff --git a/tools/perf/util/libunwind-arch/libunwind-mips.c b/tools/perf/util/libunwind-arch/libunwind-mips.c
new file mode 100644
index 000000000000..01a506c8079c
--- /dev/null
+++ b/tools/perf/util/libunwind-arch/libunwind-mips.c
@@ -0,0 +1,29 @@
+// SPDX-License-Identifier: GPL-2.0
+#include "libunwind-arch.h"
+#include "../debug.h"
+#include "../../../arch/mips/include/uapi/asm/perf_regs.h"
+#include <linux/compiler.h>
+#include <errno.h>
+
+#ifdef HAVE_LIBUNWIND_MIPS_SUPPORT
+#include <libunwind-mips.h>
+#endif
+
+int __get_perf_regnum_for_unw_regnum_mips(int unw_regnum __maybe_unused)
+{
+#ifndef HAVE_LIBUNWIND_MIPS_SUPPORT
+ return -EINVAL;
+#else
+ switch (unw_regnum) {
+ case UNW_MIPS_R1 ... UNW_MIPS_R25:
+ return unw_regnum - UNW_MIPS_R1 + PERF_REG_MIPS_R1;
+ case UNW_MIPS_R28 ... UNW_MIPS_R31:
+ return unw_regnum - UNW_MIPS_R28 + PERF_REG_MIPS_R28;
+ case UNW_MIPS_PC:
+ return PERF_REG_MIPS_PC;
+ default:
+ pr_err("unwind: invalid reg id %d\n", unw_regnum);
+ return -EINVAL;
+ }
+#endif // HAVE_LIBUNWIND_MIPS_SUPPORT
+}
diff --git a/tools/perf/util/libunwind-arch/libunwind-ppc32.c b/tools/perf/util/libunwind-arch/libunwind-ppc32.c
new file mode 100644
index 000000000000..edcb0ec95dd7
--- /dev/null
+++ b/tools/perf/util/libunwind-arch/libunwind-ppc32.c
@@ -0,0 +1,31 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+#include "libunwind-arch.h"
+#include "../debug.h"
+#include "../../../arch/powerpc/include/uapi/asm/perf_regs.h"
+#include <linux/compiler.h>
+#include <errno.h>
+
+#ifdef HAVE_LIBUNWIND_PPC32_SUPPORT
+#include <libunwind-ppc32.h>
+#endif
+
+int __get_perf_regnum_for_unw_regnum_ppc32(int unw_regnum __maybe_unused)
+{
+#ifndef HAVE_LIBUNWIND_PPC32_SUPPORT
+ return -EINVAL;
+#else
+ switch (unw_regnum) {
+ case UNW_PPC32_R0 ... UNW_PPC32_31:
+ return unw_regnum - UNW_PPC32_R0 + PERF_REG_POWERPC_R0;
+ case UNW_PPC32_LR:
+ return PERF_REG_POWERPC_LINK;
+ case UNW_PPC32_CTR:
+ return PERF_REG_POWERPC_CTR;
+ case UNW_PPC32_XER:
+ return PERF_REG_POWERPC_XER;
+ default:
+ pr_err("unwind: invalid reg id %d\n", unw_regnum);
+ return -EINVAL;
+ }
+#endif // HAVE_LIBUNWIND_PPC32_SUPPORT
+}
diff --git a/tools/perf/util/libunwind-arch/libunwind-ppc64.c b/tools/perf/util/libunwind-arch/libunwind-ppc64.c
new file mode 100644
index 000000000000..9f57a049600b
--- /dev/null
+++ b/tools/perf/util/libunwind-arch/libunwind-ppc64.c
@@ -0,0 +1,33 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+#include "libunwind-arch.h"
+#include "../debug.h"
+#include "../../../arch/powerpc/include/uapi/asm/perf_regs.h"
+#include <linux/compiler.h>
+#include <errno.h>
+
+#ifdef HAVE_LIBUNWIND_PPC64_SUPPORT
+#include <libunwind-ppc64.h>
+#endif
+
+int __get_perf_regnum_for_unw_regnum_ppc64(int unw_regnum __maybe_unused)
+{
+#ifndef HAVE_LIBUNWIND_PPC64_SUPPORT
+ return -EINVAL;
+#else
+ switch (unw_regnum) {
+ case UNW_PPC64_R0 ... UNW_PPC64_31:
+ return unw_regnum - UNW_PPC64_R0 + PERF_REG_POWERPC_R0;
+ case UNW_PPC64_LR:
+ return PERF_REG_POWERPC_LINK;
+ case UNW_PPC64_CTR:
+ return PERF_REG_POWERPC_CTR;
+ case UNW_PPC64_XER:
+ return PERF_REG_POWERPC_XER;
+ case UNW_PPC64_NIP:
+ return PERF_REG_POWERPC_NIP;
+ default:
+ pr_err("unwind: invalid reg id %d\n", unw_regnum);
+ return -EINVAL;
+ }
+#endif // HAVE_LIBUNWIND_PPC64_SUPPORT
+}
diff --git a/tools/perf/util/libunwind-arch/libunwind-s390.c b/tools/perf/util/libunwind-arch/libunwind-s390.c
new file mode 100644
index 000000000000..9fcc7885ca55
--- /dev/null
+++ b/tools/perf/util/libunwind-arch/libunwind-s390.c
@@ -0,0 +1,29 @@
+// SPDX-License-Identifier: GPL-2.0
+#include "libunwind-arch.h"
+#include "../debug.h"
+#include "../../../arch/s390/include/uapi/asm/perf_regs.h"
+#include <linux/compiler.h>
+#include <errno.h>
+
+#ifdef HAVE_LIBUNWIND_S390X_SUPPORT
+#include <libunwind-s390x.h>
+#endif
+
+int __get_perf_regnum_for_unw_regnum_s390(int unw_regnum __maybe_unused)
+{
+#ifndef HAVE_LIBUNWIND_S390X_SUPPORT
+ return -EINVAL;
+#else
+ switch (unw_regnum) {
+ case UNW_S390X_R0 ... UNW_S390_R15:
+ return unw_regnum - UNW_S390_R0 + PERF_REG_S390_R0;
+ case UNW_S390X_F0 ... UNW_S390_F15:
+ return unw_regnum - UNW_S390_F0 + PERF_REG_S390_FP0;
+ case UNW_S390X_IP:
+ return PERF_REG_S390_PC;
+ default:
+ pr_err("unwind: invalid reg id %d\n", unw_regnum);
+ return -EINVAL;
+ }
+#endif // HAVE_LIBUNWIND_S390X_SUPPORT
+}
diff --git a/tools/perf/util/libunwind-arch/libunwind-x86_64.c b/tools/perf/util/libunwind-arch/libunwind-x86_64.c
new file mode 100644
index 000000000000..6072e3597e61
--- /dev/null
+++ b/tools/perf/util/libunwind-arch/libunwind-x86_64.c
@@ -0,0 +1,52 @@
+// SPDX-License-Identifier: GPL-2.0
+#include "libunwind-arch.h"
+#include "../debug.h"
+#include "../../../arch/x86/include/uapi/asm/perf_regs.h"
+#include <linux/compiler.h>
+#include <linux/kernel.h>
+#include <errno.h>
+
+#ifdef HAVE_LIBUNWIND_X86_64_SUPPORT
+#include <libunwind-x86_64.h>
+#endif
+
+int __get_perf_regnum_for_unw_regnum_x86_64(int unw_regnum __maybe_unused)
+{
+#ifndef HAVE_LIBUNWIND_X86_64_SUPPORT
+ return -EINVAL;
+#else
+ static const int perf_x86_64_regnums[] = {
+#define REGNUM(reg) [UNW_X86_64_R ## reg] = PERF_REG_X86_ ## reg
+ REGNUM(AX),
+ REGNUM(DX),
+ REGNUM(CX),
+ REGNUM(BX),
+ REGNUM(SI),
+ REGNUM(DI),
+ REGNUM(BP),
+ REGNUM(SP),
+ REGNUM(IP),
+#undef REGNUM
+#define REGNUM(reg) [UNW_X86_64_ ## reg] = PERF_REG_X86_ ## reg
+ REGNUM(R8),
+ REGNUM(R9),
+ REGNUM(R10),
+ REGNUM(R11),
+ REGNUM(R12),
+ REGNUM(R13),
+ REGNUM(R14),
+ REGNUM(R15),
+#undef REGNUM
+ };
+
+ if (unw_regnum == UNW_X86_64_RAX)
+ return PERF_REG_X86_AX;
+
+ if (unw_regnum < 0 || unw_regnum > (int)ARRAY_SIZE(perf_x86_64_regnums) ||
+ perf_x86_64_regnums[unw_regnum] == 0) {
+ pr_err("unwind: invalid reg id %d\n", unw_regnum);
+ return -EINVAL;
+ }
+ return perf_x86_64_regnums[unw_regnum];
+#endif // HAVE_LIBUNWIND_X86_64_SUPPORT
+}
diff --git a/tools/perf/util/libunwind/arm64.c b/tools/perf/util/libunwind/arm64.c
index 37ecef0c53b9..15670a964495 100644
--- a/tools/perf/util/libunwind/arm64.c
+++ b/tools/perf/util/libunwind/arm64.c
@@ -14,11 +14,6 @@
#define REMOTE_UNWIND_LIBUNWIND
-/* Define arch specific functions & regs for libunwind, should be
- * defined before including "unwind.h"
- */
-#define LIBUNWIND__ARCH_REG_ID(regnum) libunwind__arm64_reg_id(regnum)
-
#include "unwind.h"
#include "libunwind-aarch64.h"
#define perf_event_arm_regs perf_event_arm64_regs
diff --git a/tools/perf/util/libunwind/x86_32.c b/tools/perf/util/libunwind/x86_32.c
index 1697dece1b74..1e9fb8bfec44 100644
--- a/tools/perf/util/libunwind/x86_32.c
+++ b/tools/perf/util/libunwind/x86_32.c
@@ -14,20 +14,8 @@
#define REMOTE_UNWIND_LIBUNWIND
-/* Define arch specific functions & regs for libunwind, should be
- * defined before including "unwind.h"
- */
-#define LIBUNWIND__ARCH_REG_ID(regnum) libunwind__x86_reg_id(regnum)
-
#include "unwind.h"
#include "libunwind-x86.h"
-#include <../../../../arch/x86/include/uapi/asm/perf_regs.h>
-
-/* HAVE_ARCH_X86_64_SUPPORT is used in'arch/x86/util/unwind-libunwind.c'
- * for x86_32, we undef it to compile code for x86_32 only.
- */
-#undef HAVE_ARCH_X86_64_SUPPORT
-#include "../../arch/x86/util/unwind-libunwind.c"
/* Explicitly define NO_LIBUNWIND_DEBUG_FRAME, because non-ARM has no
* dwarf_find_debug_frame() function.
diff --git a/tools/perf/util/unwind-libunwind-local.c b/tools/perf/util/unwind-libunwind-local.c
index 5b39ce21e333..3ecdb468b859 100644
--- a/tools/perf/util/unwind-libunwind-local.c
+++ b/tools/perf/util/unwind-libunwind-local.c
@@ -40,6 +40,7 @@
#include "debug.h"
#include "asm/bug.h"
#include "dso.h"
+#include "libunwind-arch/libunwind-arch.h"
extern int
UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as,
@@ -96,6 +97,7 @@ struct unwind_info {
struct perf_sample *sample;
struct machine *machine;
struct thread *thread;
+ uint16_t e_machine;
bool best_effort;
};
@@ -584,9 +586,7 @@ static int access_mem(unw_addr_space_t __maybe_unused as,
}
ret = perf_reg_value(&start, perf_sample__user_regs(ui->sample),
- perf_arch_reg_sp(thread__e_machine(ui->thread,
- ui->machine,
- /*e_flags=*/NULL)));
+ perf_arch_reg_sp(ui->e_machine));
if (ret)
return ret;
@@ -634,7 +634,7 @@ static int access_reg(unw_addr_space_t __maybe_unused as,
return 0;
}
- id = LIBUNWIND__ARCH_REG_ID(regnum);
+ id = get_perf_regnum_for_unw_regnum(ui->e_machine, regnum);
if (id < 0)
return -EINVAL;
@@ -735,7 +735,6 @@ static void _unwind__finish_access(struct maps *maps)
static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb,
void *arg, int max_stack)
{
- uint16_t e_machine = thread__e_machine(ui->thread, ui->machine, /*e_flags=*/NULL);
u64 val;
unw_word_t ips[max_stack];
unw_addr_space_t addr_space;
@@ -743,7 +742,7 @@ static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb,
int ret, i = 0;
ret = perf_reg_value(&val, perf_sample__user_regs(ui->sample),
- perf_arch_reg_ip(e_machine));
+ perf_arch_reg_ip(ui->e_machine));
if (ret)
return ret;
@@ -806,6 +805,7 @@ static int _unwind__get_entries(unwind_entry_cb_t cb, void *arg,
.sample = data,
.thread = thread,
.machine = maps__machine(thread__maps(thread)),
+ .e_machine = thread__e_machine(thread, /*machine=*/NULL, /*e_flags=*/NULL),
.best_effort = best_effort
};
diff --git a/tools/perf/util/unwind.h b/tools/perf/util/unwind.h
index ac0776e39f84..f8a8788ac986 100644
--- a/tools/perf/util/unwind.h
+++ b/tools/perf/util/unwind.h
@@ -64,11 +64,6 @@ int libunwind__get_entries(unwind_entry_cb_t cb, void *arg,
struct thread *thread,
struct perf_sample *data, int max_stack,
bool best_effort);
-#ifndef LIBUNWIND__ARCH_REG_ID
-#define LIBUNWIND__ARCH_REG_ID(regnum) libunwind__arch_reg_id(regnum)
-#endif
-
-int LIBUNWIND__ARCH_REG_ID(int regnum);
int unwind__prepare_access(struct maps *maps, struct map *map, bool *initialized);
void unwind__flush_access(struct maps *maps);
void unwind__finish_access(struct maps *maps);
--
2.53.0.1213.gd9a14994de-goog
^ permalink raw reply related
* [PATCH v3 4/8] perf build: Be more programmatic when setting up libunwind variables
From: Ian Rogers @ 2026-04-04 5:40 UTC (permalink / raw)
To: acme
Cc: irogers, 9erthalion6, adrian.hunter, alex, alexander.shishkin,
andrew.jones, aou, atrajeev, blakejones, ctshao, dapeng1.mi,
howardchu95, james.clark, john.g.garry, jolsa, leo.yan,
libunwind-devel, linux-arm-kernel, linux-kernel, linux-perf-users,
linux-riscv, mingo, namhyung, palmer, peterz, pjw, shimin.guo,
tglozar, tmricht, will, yuzhuo
In-Reply-To: <20260404054032.1538095-1-irogers@google.com>
Iterate LIBUNWIND_ARCHS when setting up CONFIG_ and HAVE_ definitions
rather than treating each architecture individually. This sets up the
libunwind build variables and C definitions beyond x86 and
arm/aarch64. The existing naming convention is followed for
compatibility.
Signed-off-by: Ian Rogers <irogers@google.com>
---
tools/perf/Makefile.config | 215 +++++++++++++++----------------------
1 file changed, 89 insertions(+), 126 deletions(-)
diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config
index 333ddd0e4bd8..9d31d0f6f52a 100644
--- a/tools/perf/Makefile.config
+++ b/tools/perf/Makefile.config
@@ -65,95 +65,83 @@ $(call detected_var,SRCARCH)
CFLAGS += -I$(OUTPUT)arch/$(SRCARCH)/include/generated
-# Additional ARCH settings for ppc
-ifeq ($(SRCARCH),powerpc)
- ifndef NO_LIBUNWIND
- LIBUNWIND_LIBS := -lunwind -lunwind-ppc64
- endif
-endif
-
# Additional ARCH settings for x86
ifeq ($(SRCARCH),x86)
$(call detected,CONFIG_X86)
ifeq (${IS_64_BIT}, 1)
CFLAGS += -DHAVE_ARCH_X86_64_SUPPORT
ARCH_INCLUDE = ../../arch/x86/lib/memcpy_64.S ../../arch/x86/lib/memset_64.S
- ifndef NO_LIBUNWIND
- LIBUNWIND_LIBS = -lunwind-x86_64 -lunwind -llzma
- endif
$(call detected,CONFIG_X86_64)
- else
- ifndef NO_LIBUNWIND
- LIBUNWIND_LIBS = -lunwind-x86 -llzma -lunwind
- endif
endif
endif
-ifeq ($(SRCARCH),arm)
- ifndef NO_LIBUNWIND
- LIBUNWIND_LIBS = -lunwind -lunwind-arm
- endif
+ifeq ($(ARCH),s390)
+ CFLAGS += -fPIC
endif
-ifeq ($(SRCARCH),arm64)
- ifndef NO_LIBUNWIND
- LIBUNWIND_LIBS = -lunwind -lunwind-aarch64
- endif
+ifneq ($(LIBUNWIND),1)
+ NO_LIBUNWIND := 1
endif
-ifeq ($(SRCARCH),loongarch)
- ifndef NO_LIBUNWIND
+ifndef NO_LIBUNWIND
+ ifeq ($(SRCARCH),arm)
+ LIBUNWIND_LIBS = -lunwind -lunwind-arm
+ endif
+ ifeq ($(SRCARCH),arm64)
+ LIBUNWIND_LIBS = -lunwind -lunwind-aarch64
+ endif
+ ifeq ($(SRCARCH),loongarch)
LIBUNWIND_LIBS = -lunwind -lunwind-loongarch64
endif
-endif
-
-ifeq ($(ARCH),s390)
- CFLAGS += -fPIC
-endif
-
-ifeq ($(ARCH),mips)
- ifndef NO_LIBUNWIND
+ ifeq ($(ARCH),mips)
LIBUNWIND_LIBS = -lunwind -lunwind-mips
endif
+ ifeq ($(SRCARCH),powerpc)
+ LIBUNWIND_LIBS := -lunwind -lunwind-ppc64
+ endif
+ ifeq ($(SRCARCH),riscv)
+ LIBUNWIND_LIBS := -lunwind -lunwind-riscv
+ endif
+ ifeq ($(SRCARCH),s390)
+ LIBUNWIND_LIBS := -lunwind -lunwind-s390x
+ endif
+ ifeq ($(SRCARCH),x86)
+ ifeq (${IS_64_BIT}, 1)
+ LIBUNWIND_LIBS = -lunwind-x86_64 -lunwind -llzma
+ else
+ LIBUNWIND_LIBS = -lunwind-x86 -lunwind -llzma
+ endif
+ endif
+ ifeq ($(LIBUNWIND_LIBS),)
+ NO_LIBUNWIND := 1
+ endif
endif
-ifneq ($(LIBUNWIND),1)
- NO_LIBUNWIND := 1
-endif
-
-ifeq ($(LIBUNWIND_LIBS),)
- NO_LIBUNWIND := 1
-endif
#
# For linking with debug library, run like:
#
# make DEBUG=1 LIBUNWIND_DIR=/opt/libunwind/
#
-
-libunwind_arch_set_flags = $(eval $(libunwind_arch_set_flags_code))
-define libunwind_arch_set_flags_code
- FEATURE_CHECK_CFLAGS-libunwind-$(1) = -I$(LIBUNWIND_DIR)/include
- FEATURE_CHECK_LDFLAGS-libunwind-$(1) = -L$(LIBUNWIND_DIR)/lib
-endef
-
-ifdef LIBUNWIND_DIR
- LIBUNWIND_CFLAGS = -I$(LIBUNWIND_DIR)/include
- LIBUNWIND_LDFLAGS = -L$(LIBUNWIND_DIR)/lib
- LIBUNWIND_ARCHS = x86 x86_64 arm aarch64 debug-frame-arm debug-frame-aarch64 loongarch
- $(foreach libunwind_arch,$(LIBUNWIND_ARCHS),$(call libunwind_arch_set_flags,$(libunwind_arch)))
-endif
+LIBUNWIND_ARCHS:=aarch64 arm loongarch64 mips ppc32 ppc64 riscv s390x x86 x86_64
ifndef NO_LIBUNWIND
- # Set per-feature check compilation flags
FEATURE_CHECK_CFLAGS-libunwind = $(LIBUNWIND_CFLAGS)
FEATURE_CHECK_LDFLAGS-libunwind = $(LIBUNWIND_LDFLAGS) $(LIBUNWIND_LIBS)
FEATURE_CHECK_CFLAGS-libunwind-debug-frame = $(LIBUNWIND_CFLAGS)
FEATURE_CHECK_LDFLAGS-libunwind-debug-frame = $(LIBUNWIND_LDFLAGS) $(LIBUNWIND_LIBS)
-
- FEATURE_CHECK_LDFLAGS-libunwind-arm += -lunwind -lunwind-arm
- FEATURE_CHECK_LDFLAGS-libunwind-aarch64 += -lunwind -lunwind-aarch64
- FEATURE_CHECK_LDFLAGS-libunwind-x86 += -lunwind -llzma -lunwind-x86
- FEATURE_CHECK_LDFLAGS-libunwind-x86_64 += -lunwind -llzma -lunwind-x86_64
+
+ ifdef LIBUNWIND_DIR
+ LIBUNWIND_CFLAGS = -I$(LIBUNWIND_DIR)/include
+ LIBUNWIND_LDFLAGS = -L$(LIBUNWIND_DIR)/lib
+
+ define libunwind_arch_set_flags
+ FEATURE_CHECK_CFLAGS-libunwind-$(1) = -I$(LIBUNWIND_DIR)/include
+ FEATURE_CHECK_LDFLAGS-libunwind-$(1) = -L$(LIBUNWIND_DIR)/lib
+ endef
+ $(foreach arch,$(LIBUNWIND_ARCHS), \
+ $(eval $(call libunwind_arch_set_flags,$(arch))) \
+ )
+ endif
endif
ifdef CSINCLUDES
@@ -638,49 +626,6 @@ ifeq ($(SRCARCH),powerpc)
endif
endif
-ifndef NO_LIBUNWIND
- have_libunwind :=
-
- $(call feature_check,libunwind)
-
- $(call feature_check,libunwind-x86)
- ifeq ($(feature-libunwind-x86), 1)
- $(call detected,CONFIG_LIBUNWIND_X86)
- CFLAGS += -DHAVE_LIBUNWIND_X86_SUPPORT
- LDFLAGS += -lunwind-x86
- EXTLIBS_LIBUNWIND += -lunwind-x86
- have_libunwind = 1
- endif
-
- $(call feature_check,libunwind-aarch64)
- ifeq ($(feature-libunwind-aarch64), 1)
- $(call detected,CONFIG_LIBUNWIND_AARCH64)
- CFLAGS += -DHAVE_LIBUNWIND_AARCH64_SUPPORT
- LDFLAGS += -lunwind-aarch64
- EXTLIBS_LIBUNWIND += -lunwind-aarch64
- have_libunwind = 1
- $(call feature_check,libunwind-debug-frame-aarch64)
- ifneq ($(feature-libunwind-debug-frame-aarch64), 1)
- $(warning No debug_frame support found in libunwind-aarch64)
- CFLAGS += -DNO_LIBUNWIND_DEBUG_FRAME_AARCH64
- endif
- endif
-
- ifneq ($(feature-libunwind), 1)
- $(warning No libunwind found. Please install libunwind-dev[el] >= 1.1 and/or set LIBUNWIND_DIR and set LIBUNWIND=1 in the make command line as it is opt-in now)
- NO_LOCAL_LIBUNWIND := 1
- else
- have_libunwind := 1
- $(call detected,CONFIG_LOCAL_LIBUNWIND)
- endif
-
- ifneq ($(have_libunwind), 1)
- NO_LIBUNWIND := 1
- endif
-else
- NO_LOCAL_LIBUNWIND := 1
-endif
-
ifndef NO_LIBBPF
ifneq ($(feature-bpf), 1)
$(warning BPF API too old. Please install recent kernel headers. BPF support in 'perf record' is disabled.)
@@ -739,6 +684,49 @@ ifndef GEN_VMLINUX_H
VMLINUX_H=$(src-perf)/util/bpf_skel/vmlinux/vmlinux.h
endif
+ifndef NO_LIBUNWIND
+ have_libunwind :=
+
+ $(call feature_check,libunwind)
+ ifneq ($(feature-libunwind), 1)
+ $(warning No libunwind found. Please install libunwind-dev[el] >= 1.1 and/or set LIBUNWIND_DIR and set LIBUNWIND=1 in the make command line as it is opt-in now)
+ NO_LOCAL_LIBUNWIND := 1
+ else
+ have_libunwind := 1
+ $(call detected,CONFIG_LOCAL_LIBUNWIND)
+ CFLAGS += -DHAVE_LIBUNWIND_SUPPORT
+ CFLAGS += $(LIBUNWIND_CFLAGS)
+ LDFLAGS += $(LIBUNWIND_LDFLAGS)
+ EXTLIBS += $(EXTLIBS_LIBUNWIND)
+ $(call feature_check,libunwind-debug-frame)
+ ifneq ($(feature-libunwind-debug-frame), 1)
+ CFLAGS += -DNO_LIBUNWIND_DEBUG_FRAME
+ endif
+ endif
+
+ define PROCESS_REMOTE_LIBUNWIND_ARCH
+ $(call feature_check,libunwind-$(1))
+
+ ifeq ($$(feature-libunwind-$(1)), 1)
+ upper_arch := $$(shell echo $(1) | tr '[:lower:]' '[:upper:]')
+ $$(call detected,CONFIG_LIBUNWIND_$$(upper_arch))
+
+ CFLAGS += -DHAVE_LIBUNWIND_$$(upper_arch)_SUPPORT
+ LDFLAGS += -lunwind-$(1)
+ EXTLIBS_LIBUNWIND += -lunwind-$(1)
+ have_libunwind := 1
+
+ $$(call feature_check,libunwind-debug-frame-$(1))
+ ifneq ($$(feature-libunwind-debug-frame-$(1)), 1)
+ CFLAGS += -DNO_LIBUNWIND_DEBUG_FRAME_$$(upper_arch)
+ endif
+ endif
+ endef
+ $(foreach arch,$(LIBUNWIND_ARCHS), \
+ $(eval $(call PROCESS_REMOTE_LIBUNWIND_ARCH,$(arch))) \
+ )
+endif
+
dwarf-post-unwind := 1
dwarf-post-unwind-text := BUG
@@ -761,31 +749,6 @@ ifeq ($(dwarf-post-unwind),1)
$(call detected,CONFIG_DWARF_UNWIND)
endif
-ifndef NO_LIBUNWIND
- ifndef NO_LOCAL_LIBUNWIND
- ifeq ($(SRCARCH),$(filter $(SRCARCH),arm arm64))
- $(call feature_check,libunwind-debug-frame)
- ifneq ($(feature-libunwind-debug-frame), 1)
- $(warning No debug_frame support found in libunwind)
- CFLAGS += -DNO_LIBUNWIND_DEBUG_FRAME
- endif
- else
- # non-ARM has no dwarf_find_debug_frame() function:
- CFLAGS += -DNO_LIBUNWIND_DEBUG_FRAME
- endif
- EXTLIBS += $(LIBUNWIND_LIBS)
- LDFLAGS += $(LIBUNWIND_LIBS)
- endif
- ifeq ($(findstring -static,${LDFLAGS}),-static)
- # gcc -static links libgcc_eh which contans piece of libunwind
- LIBUNWIND_LDFLAGS += -Wl,--allow-multiple-definition
- endif
- CFLAGS += -DHAVE_LIBUNWIND_SUPPORT
- CFLAGS += $(LIBUNWIND_CFLAGS)
- LDFLAGS += $(LIBUNWIND_LDFLAGS)
- EXTLIBS += $(EXTLIBS_LIBUNWIND)
-endif
-
ifneq ($(NO_LIBTRACEEVENT),1)
$(call detected,CONFIG_TRACE)
endif
--
2.53.0.1213.gd9a14994de-goog
^ permalink raw reply related
* [PATCH v3 3/8] tools build: Deduplicate test-libunwind for different architectures
From: Ian Rogers @ 2026-04-04 5:40 UTC (permalink / raw)
To: acme
Cc: irogers, 9erthalion6, adrian.hunter, alex, alexander.shishkin,
andrew.jones, aou, atrajeev, blakejones, ctshao, dapeng1.mi,
howardchu95, james.clark, john.g.garry, jolsa, leo.yan,
libunwind-devel, linux-arm-kernel, linux-kernel, linux-perf-users,
linux-riscv, mingo, namhyung, palmer, peterz, pjw, shimin.guo,
tglozar, tmricht, will, yuzhuo
In-Reply-To: <20260404054032.1538095-1-irogers@google.com>
The separate test files only exist to pass a different #include,
instead have a single source file and pass -include to $(CC) to
include the relevant header file for the architecture being
tested. Generate the rules using a foreach loop. Include tests for all
current libunwind architectures.
Signed-off-by: Ian Rogers <irogers@google.com>
---
tools/build/feature/Makefile | 38 +++++++++----------
tools/build/feature/test-libunwind-aarch64.c | 27 -------------
tools/build/feature/test-libunwind-arm.c | 28 --------------
.../test-libunwind-debug-frame-aarch64.c | 17 ---------
.../feature/test-libunwind-debug-frame-arm.c | 17 ---------
.../feature/test-libunwind-debug-frame.c | 1 -
tools/build/feature/test-libunwind-x86.c | 28 --------------
tools/build/feature/test-libunwind-x86_64.c | 28 --------------
tools/build/feature/test-libunwind.c | 1 -
9 files changed, 19 insertions(+), 166 deletions(-)
delete mode 100644 tools/build/feature/test-libunwind-aarch64.c
delete mode 100644 tools/build/feature/test-libunwind-arm.c
delete mode 100644 tools/build/feature/test-libunwind-debug-frame-aarch64.c
delete mode 100644 tools/build/feature/test-libunwind-debug-frame-arm.c
delete mode 100644 tools/build/feature/test-libunwind-x86.c
delete mode 100644 tools/build/feature/test-libunwind-x86_64.c
diff --git a/tools/build/feature/Makefile b/tools/build/feature/Makefile
index f163a245837a..bda8ef868e44 100644
--- a/tools/build/feature/Makefile
+++ b/tools/build/feature/Makefile
@@ -210,27 +210,27 @@ $(OUTPUT)test-numa_num_possible_cpus.bin:
$(BUILD) -lnuma
$(OUTPUT)test-libunwind.bin:
- $(BUILD) -lelf -llzma
+ $(BUILD) -include libunwind.h -lelf -llzma -lunwind
$(OUTPUT)test-libunwind-debug-frame.bin:
- $(BUILD) -lelf -llzma
-$(OUTPUT)test-libunwind-x86.bin:
- $(BUILD) -lelf -llzma -lunwind-x86
-
-$(OUTPUT)test-libunwind-x86_64.bin:
- $(BUILD) -lelf -llzma -lunwind-x86_64
-
-$(OUTPUT)test-libunwind-arm.bin:
- $(BUILD) -lelf -llzma -lunwind-arm
-
-$(OUTPUT)test-libunwind-aarch64.bin:
- $(BUILD) -lelf -llzma -lunwind-aarch64
-
-$(OUTPUT)test-libunwind-debug-frame-arm.bin:
- $(BUILD) -lelf -llzma -lunwind-arm
-
-$(OUTPUT)test-libunwind-debug-frame-aarch64.bin:
- $(BUILD) -lelf -llzma -lunwind-aarch64
+ $(BUILD) -include libunwind.h -lelf -llzma -lunwind
+
+LIBUNWIND_ARCHS:=aarch64 arm loongarch64 mips ppc32 ppc64 riscv s390x x86 x86_64
+define LIBUNWIND_RULE
+$$(OUTPUT)test-libunwind-$(1).bin:
+ $$(CC) $$(CFLAGS) -MD -Wall -Werror -include libunwind-$(1).h -o $$@ \
+ test-libunwind.c $$(LDFLAGS) -lelf -llzma -lunwind-$(1) \
+ > $$(@:.bin=.make.output) 2>&1
+
+$$(OUTPUT)test-libunwind-debug-frame-$(1).bin:
+ $$(CC) $$(CFLAGS) -MD -Wall -Werror -include libunwind-$(1).h -o $$@ \
+ test-libunwind-debug-frame.c $$(LDFLAGS) -lelf -llzma -lunwind-$(1) \
+ > $$(@:.bin=.make.output) 2>&1
+
+endef
+$(foreach arch,$(LIBUNWIND_ARCHS), \
+ $(eval $(call LIBUNWIND_RULE,$(arch))) \
+)
$(OUTPUT)test-libslang.bin:
$(BUILD) -lslang
diff --git a/tools/build/feature/test-libunwind-aarch64.c b/tools/build/feature/test-libunwind-aarch64.c
deleted file mode 100644
index 323803f49212..000000000000
--- a/tools/build/feature/test-libunwind-aarch64.c
+++ /dev/null
@@ -1,27 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-#include <libunwind-aarch64.h>
-#include <stdlib.h>
-
-extern int UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as,
- unw_word_t ip,
- unw_dyn_info_t *di,
- unw_proc_info_t *pi,
- int need_unwind_info, void *arg);
-
-#define dwarf_search_unwind_table UNW_OBJ(dwarf_search_unwind_table)
-
-static unw_accessors_t accessors;
-
-int main(void)
-{
- unw_addr_space_t addr_space;
-
- addr_space = unw_create_addr_space(&accessors, 0);
- if (addr_space)
- return 0;
-
- unw_init_remote(NULL, addr_space, NULL);
- dwarf_search_unwind_table(addr_space, 0, NULL, NULL, 0, NULL);
-
- return 0;
-}
diff --git a/tools/build/feature/test-libunwind-arm.c b/tools/build/feature/test-libunwind-arm.c
deleted file mode 100644
index cb378b7d6866..000000000000
--- a/tools/build/feature/test-libunwind-arm.c
+++ /dev/null
@@ -1,28 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-#include <libunwind-arm.h>
-#include <stdlib.h>
-
-extern int UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as,
- unw_word_t ip,
- unw_dyn_info_t *di,
- unw_proc_info_t *pi,
- int need_unwind_info, void *arg);
-
-
-#define dwarf_search_unwind_table UNW_OBJ(dwarf_search_unwind_table)
-
-static unw_accessors_t accessors;
-
-int main(void)
-{
- unw_addr_space_t addr_space;
-
- addr_space = unw_create_addr_space(&accessors, 0);
- if (addr_space)
- return 0;
-
- unw_init_remote(NULL, addr_space, NULL);
- dwarf_search_unwind_table(addr_space, 0, NULL, NULL, 0, NULL);
-
- return 0;
-}
diff --git a/tools/build/feature/test-libunwind-debug-frame-aarch64.c b/tools/build/feature/test-libunwind-debug-frame-aarch64.c
deleted file mode 100644
index 36d6646c185e..000000000000
--- a/tools/build/feature/test-libunwind-debug-frame-aarch64.c
+++ /dev/null
@@ -1,17 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-#include <libunwind-aarch64.h>
-#include <stdlib.h>
-
-extern int
-UNW_OBJ(dwarf_find_debug_frame) (int found, unw_dyn_info_t *di_debug,
- unw_word_t ip, unw_word_t segbase,
- const char *obj_name, unw_word_t start,
- unw_word_t end);
-
-#define dwarf_find_debug_frame UNW_OBJ(dwarf_find_debug_frame)
-
-int main(void)
-{
- dwarf_find_debug_frame(0, NULL, 0, 0, NULL, 0, 0);
- return 0;
-}
diff --git a/tools/build/feature/test-libunwind-debug-frame-arm.c b/tools/build/feature/test-libunwind-debug-frame-arm.c
deleted file mode 100644
index 8696e48e1268..000000000000
--- a/tools/build/feature/test-libunwind-debug-frame-arm.c
+++ /dev/null
@@ -1,17 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-#include <libunwind-arm.h>
-#include <stdlib.h>
-
-extern int
-UNW_OBJ(dwarf_find_debug_frame) (int found, unw_dyn_info_t *di_debug,
- unw_word_t ip, unw_word_t segbase,
- const char *obj_name, unw_word_t start,
- unw_word_t end);
-
-#define dwarf_find_debug_frame UNW_OBJ(dwarf_find_debug_frame)
-
-int main(void)
-{
- dwarf_find_debug_frame(0, NULL, 0, 0, NULL, 0, 0);
- return 0;
-}
diff --git a/tools/build/feature/test-libunwind-debug-frame.c b/tools/build/feature/test-libunwind-debug-frame.c
index efb55cdd8d01..4c57e37004b3 100644
--- a/tools/build/feature/test-libunwind-debug-frame.c
+++ b/tools/build/feature/test-libunwind-debug-frame.c
@@ -1,5 +1,4 @@
// SPDX-License-Identifier: GPL-2.0
-#include <libunwind.h>
#include <stdlib.h>
extern int
diff --git a/tools/build/feature/test-libunwind-x86.c b/tools/build/feature/test-libunwind-x86.c
deleted file mode 100644
index e5e0f6c89637..000000000000
--- a/tools/build/feature/test-libunwind-x86.c
+++ /dev/null
@@ -1,28 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-#include <libunwind-x86.h>
-#include <stdlib.h>
-
-extern int UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as,
- unw_word_t ip,
- unw_dyn_info_t *di,
- unw_proc_info_t *pi,
- int need_unwind_info, void *arg);
-
-
-#define dwarf_search_unwind_table UNW_OBJ(dwarf_search_unwind_table)
-
-static unw_accessors_t accessors;
-
-int main(void)
-{
- unw_addr_space_t addr_space;
-
- addr_space = unw_create_addr_space(&accessors, 0);
- if (addr_space)
- return 0;
-
- unw_init_remote(NULL, addr_space, NULL);
- dwarf_search_unwind_table(addr_space, 0, NULL, NULL, 0, NULL);
-
- return 0;
-}
diff --git a/tools/build/feature/test-libunwind-x86_64.c b/tools/build/feature/test-libunwind-x86_64.c
deleted file mode 100644
index 62ae4db597dc..000000000000
--- a/tools/build/feature/test-libunwind-x86_64.c
+++ /dev/null
@@ -1,28 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-#include <libunwind-x86_64.h>
-#include <stdlib.h>
-
-extern int UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as,
- unw_word_t ip,
- unw_dyn_info_t *di,
- unw_proc_info_t *pi,
- int need_unwind_info, void *arg);
-
-
-#define dwarf_search_unwind_table UNW_OBJ(dwarf_search_unwind_table)
-
-static unw_accessors_t accessors;
-
-int main(void)
-{
- unw_addr_space_t addr_space;
-
- addr_space = unw_create_addr_space(&accessors, 0);
- if (addr_space)
- return 0;
-
- unw_init_remote(NULL, addr_space, NULL);
- dwarf_search_unwind_table(addr_space, 0, NULL, NULL, 0, NULL);
-
- return 0;
-}
diff --git a/tools/build/feature/test-libunwind.c b/tools/build/feature/test-libunwind.c
index 53fd26614ff0..5af5dc3a73d4 100644
--- a/tools/build/feature/test-libunwind.c
+++ b/tools/build/feature/test-libunwind.c
@@ -1,5 +1,4 @@
// SPDX-License-Identifier: GPL-2.0
-#include <libunwind.h>
#include <stdlib.h>
extern int UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as,
--
2.53.0.1213.gd9a14994de-goog
^ permalink raw reply related
* [PATCH v3 0/8] perf libunwind multiple remote support
From: Ian Rogers @ 2026-04-04 5:40 UTC (permalink / raw)
To: acme
Cc: irogers, 9erthalion6, adrian.hunter, alex, alexander.shishkin,
andrew.jones, aou, atrajeev, blakejones, ctshao, dapeng1.mi,
howardchu95, james.clark, john.g.garry, jolsa, leo.yan,
libunwind-devel, linux-arm-kernel, linux-kernel, linux-perf-users,
linux-riscv, mingo, namhyung, palmer, peterz, pjw, shimin.guo,
tglozar, tmricht, will, yuzhuo
In-Reply-To: <20260305221927.3237145-1-irogers@google.com>
Fix the libunwind build for when libdw and libunwind are feature
detected, currently failing with a duplicate symbol.
Refactor the libunwind support so that whenever a remote target is
available, perf functions using the ELF machine can use that remote
target regardless of what the host/local machine is. Migrate existing
libunwind supported architectures like powerpc, arm64 and loongarch so
that they can work in a cross-architecture way. Add support for
RISC-V. Make the code more regular in function names, etc. and avoid
including a C-file. This increases the lines of code. It is similar in
style to the unwind-libdw implementation. It is hoped that the more
uniform nature of the code with help with refactoring the perf
registers for SIMD/APX support.
Aside from local host testing these patches are under tested, in part
as I'm failing to see how to build libunwind with support for multiple
remote targets. Please could I get help in testing.
v3: Minor whitespace clean up and warn when a dynamic choice of libdw
or libunwind is selected for unwinding and support is missing (Arnaldo).
v2: Move two fixes patches to position 1 and 2 in the series. Fix
struct naming inconsistency, Andrew Jones
<andrew.jones@oss.qualcomm.com>. Fix other inconsistencies and
potential non-x86 build issues.
https://lore.kernel.org/lkml/20260305221927.3237145-1-irogers@google.com/
v1: https://lore.kernel.org/lkml/20260224142938.26088-1-irogers@google.com/
Ian Rogers (8):
perf unwind: Refactor get_entries to allow dynamic libdw/libunwind
selection
perf build loongarch: Remove reference to missing file
tools build: Deduplicate test-libunwind for different architectures
perf build: Be more programmatic when setting up libunwind variables
perf unwind-libunwind: Make libunwind register reading cross platform
perf unwind-libunwind: Move flush/finish access out of local
perf unwind-libunwind: Remove libunwind-local
perf unwind-libunwind: Add RISC-V libunwind support
tools/build/feature/Makefile | 38 +-
tools/build/feature/test-libunwind-aarch64.c | 27 -
tools/build/feature/test-libunwind-arm.c | 28 -
.../test-libunwind-debug-frame-aarch64.c | 17 -
.../feature/test-libunwind-debug-frame-arm.c | 17 -
.../feature/test-libunwind-debug-frame.c | 1 -
tools/build/feature/test-libunwind-x86.c | 28 -
tools/build/feature/test-libunwind-x86_64.c | 28 -
tools/build/feature/test-libunwind.c | 1 -
tools/perf/Makefile.config | 215 ++---
tools/perf/arch/arm/util/Build | 2 -
tools/perf/arch/arm/util/unwind-libunwind.c | 50 --
tools/perf/arch/arm64/util/Build | 1 -
tools/perf/arch/arm64/util/unwind-libunwind.c | 17 -
tools/perf/arch/loongarch/util/Build | 3 -
.../arch/loongarch/util/unwind-libunwind.c | 82 --
tools/perf/arch/mips/Build | 1 -
tools/perf/arch/mips/util/Build | 1 -
tools/perf/arch/mips/util/unwind-libunwind.c | 22 -
tools/perf/arch/powerpc/util/Build | 1 -
.../perf/arch/powerpc/util/unwind-libunwind.c | 92 --
tools/perf/arch/x86/util/Build | 3 -
tools/perf/arch/x86/util/unwind-libunwind.c | 115 ---
tools/perf/builtin-inject.c | 4 +
tools/perf/builtin-report.c | 4 +
tools/perf/builtin-script.c | 4 +
tools/perf/util/Build | 5 +-
tools/perf/util/libunwind-arch/Build | 11 +
.../perf/util/libunwind-arch/libunwind-arch.c | 319 +++++++
.../perf/util/libunwind-arch/libunwind-arch.h | 296 +++++++
.../perf/util/libunwind-arch/libunwind-arm.c | 290 ++++++
.../util/libunwind-arch/libunwind-arm64.c | 289 ++++++
.../perf/util/libunwind-arch/libunwind-i386.c | 312 +++++++
.../util/libunwind-arch/libunwind-loongarch.c | 297 +++++++
.../perf/util/libunwind-arch/libunwind-mips.c | 299 +++++++
.../util/libunwind-arch/libunwind-ppc32.c | 301 +++++++
.../util/libunwind-arch/libunwind-ppc64.c | 303 +++++++
.../util/libunwind-arch/libunwind-riscv.c | 297 +++++++
.../perf/util/libunwind-arch/libunwind-s390.c | 299 +++++++
.../util/libunwind-arch/libunwind-x86_64.c | 320 +++++++
tools/perf/util/libunwind/arm64.c | 40 -
tools/perf/util/libunwind/x86_32.c | 41 -
tools/perf/util/maps.c | 29 +-
tools/perf/util/maps.h | 4 +-
tools/perf/util/symbol_conf.h | 10 +
tools/perf/util/thread.c | 29 +-
tools/perf/util/unwind-libdw.c | 2 +-
tools/perf/util/unwind-libunwind-local.c | 832 ------------------
tools/perf/util/unwind-libunwind.c | 679 ++++++++++++--
tools/perf/util/unwind.c | 98 +++
tools/perf/util/unwind.h | 77 +-
51 files changed, 4549 insertions(+), 1732 deletions(-)
delete mode 100644 tools/build/feature/test-libunwind-aarch64.c
delete mode 100644 tools/build/feature/test-libunwind-arm.c
delete mode 100644 tools/build/feature/test-libunwind-debug-frame-aarch64.c
delete mode 100644 tools/build/feature/test-libunwind-debug-frame-arm.c
delete mode 100644 tools/build/feature/test-libunwind-x86.c
delete mode 100644 tools/build/feature/test-libunwind-x86_64.c
delete mode 100644 tools/perf/arch/arm/util/unwind-libunwind.c
delete mode 100644 tools/perf/arch/arm64/util/unwind-libunwind.c
delete mode 100644 tools/perf/arch/loongarch/util/unwind-libunwind.c
delete mode 100644 tools/perf/arch/mips/Build
delete mode 100644 tools/perf/arch/mips/util/Build
delete mode 100644 tools/perf/arch/mips/util/unwind-libunwind.c
delete mode 100644 tools/perf/arch/powerpc/util/unwind-libunwind.c
delete mode 100644 tools/perf/arch/x86/util/unwind-libunwind.c
create mode 100644 tools/perf/util/libunwind-arch/Build
create mode 100644 tools/perf/util/libunwind-arch/libunwind-arch.c
create mode 100644 tools/perf/util/libunwind-arch/libunwind-arch.h
create mode 100644 tools/perf/util/libunwind-arch/libunwind-arm.c
create mode 100644 tools/perf/util/libunwind-arch/libunwind-arm64.c
create mode 100644 tools/perf/util/libunwind-arch/libunwind-i386.c
create mode 100644 tools/perf/util/libunwind-arch/libunwind-loongarch.c
create mode 100644 tools/perf/util/libunwind-arch/libunwind-mips.c
create mode 100644 tools/perf/util/libunwind-arch/libunwind-ppc32.c
create mode 100644 tools/perf/util/libunwind-arch/libunwind-ppc64.c
create mode 100644 tools/perf/util/libunwind-arch/libunwind-riscv.c
create mode 100644 tools/perf/util/libunwind-arch/libunwind-s390.c
create mode 100644 tools/perf/util/libunwind-arch/libunwind-x86_64.c
delete mode 100644 tools/perf/util/libunwind/arm64.c
delete mode 100644 tools/perf/util/libunwind/x86_32.c
delete mode 100644 tools/perf/util/unwind-libunwind-local.c
create mode 100644 tools/perf/util/unwind.c
--
2.53.0.1213.gd9a14994de-goog
^ permalink raw reply
* Re: [PATCH v3] PCI: imx6: Don't remove MSI capability for i.MX7D/i.MX8M
From: Manivannan Sadhasivam @ 2026-04-04 2:33 UTC (permalink / raw)
To: Bjorn Helgaas
Cc: Richard Zhu, frank.li, l.stach, lpieralisi, kwilczynski, robh,
bhelgaas, s.hauer, kernel, festevam, linux-pci, linux-arm-kernel,
imx, linux-kernel, stable
In-Reply-To: <20260403215656.GA360979@bhelgaas>
On Fri, Apr 03, 2026 at 04:56:56PM -0500, Bjorn Helgaas wrote:
> On Tue, Mar 31, 2026 at 04:52:52PM +0800, Richard Zhu wrote:
> > The MSI trigger mechanism for endpoint devices connected to i.MX7D,
> > i.MX8MM, and i.MX8MQ PCIe root complex ports depends on the MSI
> > capability register settings in the root complex. Removing the MSI
> > capability breaks MSI functionality for these endpoints.
> >
> > Add keep_rp_msi_en flag to indicate platforms (i.MX7D, i.MX8MM, i.MX8MQ)
> > that should preserve the MSI capability during initialization.
>
> I guess Mani added this to the commit log:
>
> Note that by keeping Root Port MSI capability, Root Port MSIs such as AER,
> PME and others won't be received by default. So users need to use
> workarounds such as passing 'pcie_pme=nomsi' cmdline param.
>
Yes, I did.
> Why can't we fix this automatically? I hate it when users are
> expected to use command line parameters to work around issues.
>
> Obviously we know at probe-time, before any PCI devices are
> enumerated, so it seems like we should be able to do the equivalent of
> "pcie_pme=nomsi" even without the parameter.
>
That's why we came up with the idea of disabling the MSI/MSI-X capabilities of
the Root Port so that the code falls back to INTx. But the issue is that,
disabling that capability or MSI Enable bit (mayebe?) prevents endpoint MSIs
from being received. We don't know exactly what's going on inside the hardware
though. But is broken at its best. Fortunately, this behavior only applies to a
subset of the NXP SoCs.
- Mani
> > Cc: stable@vger.kernel.org
> > Fixes: f5cd8a929c825 ("PCI: dwc: Remove MSI/MSIX capability for Root Port if iMSI-RX is used as MSI controller")
> > Suggested-by: Manivannan Sadhasivam <mani@kernel.org>
> > Signed-off-by: Richard Zhu <hongxing.zhu@nxp.com>
> > ---
> > v3 changes:
> > Use a flag 'dw_pcie_rp::keep_rp_msi_en' to identify SoCs that require MSI
> > capability preservation, and skip the capability removal in
> > pcie-designware-host.c accordingly.
> >
> > v2 changes:
> > CC stable tree.
> > ---
> > drivers/pci/controller/dwc/pci-imx6.c | 7 +++++++
> > drivers/pci/controller/dwc/pcie-designware-host.c | 2 +-
> > drivers/pci/controller/dwc/pcie-designware.h | 1 +
> > 3 files changed, 9 insertions(+), 1 deletion(-)
> >
> > diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c
> > index 20dafd2710a3..fde173770933 100644
> > --- a/drivers/pci/controller/dwc/pci-imx6.c
> > +++ b/drivers/pci/controller/dwc/pci-imx6.c
> > @@ -117,6 +117,8 @@ enum imx_pcie_variants {
> > #define IMX_PCIE_FLAG_HAS_LUT BIT(10)
> > #define IMX_PCIE_FLAG_8GT_ECN_ERR051586 BIT(11)
> > #define IMX_PCIE_FLAG_SKIP_L23_READY BIT(12)
> > +/* Preserve MSI capability for platforms that require it */
> > +#define IMX_PCIE_FLAG_KEEP_MSI_CAP BIT(13)
> >
> > #define imx_check_flag(pci, val) (pci->drvdata->flags & val)
> >
> > @@ -1820,6 +1822,8 @@ static int imx_pcie_probe(struct platform_device *pdev)
> > } else {
> > if (imx_check_flag(imx_pcie, IMX_PCIE_FLAG_SKIP_L23_READY))
> > pci->pp.skip_l23_ready = true;
> > + if (imx_check_flag(imx_pcie, IMX_PCIE_FLAG_KEEP_MSI_CAP))
> > + pci->pp.keep_rp_msi_en = true;
> > pci->pp.use_atu_msg = true;
> > ret = dw_pcie_host_init(&pci->pp);
> > if (ret < 0)
> > @@ -1897,6 +1901,7 @@ static const struct imx_pcie_drvdata drvdata[] = {
> > [IMX7D] = {
> > .variant = IMX7D,
> > .flags = IMX_PCIE_FLAG_SUPPORTS_SUSPEND |
> > + IMX_PCIE_FLAG_KEEP_MSI_CAP |
> > IMX_PCIE_FLAG_HAS_APP_RESET |
> > IMX_PCIE_FLAG_SKIP_L23_READY |
> > IMX_PCIE_FLAG_HAS_PHY_RESET,
> > @@ -1909,6 +1914,7 @@ static const struct imx_pcie_drvdata drvdata[] = {
> > [IMX8MQ] = {
> > .variant = IMX8MQ,
> > .flags = IMX_PCIE_FLAG_HAS_APP_RESET |
> > + IMX_PCIE_FLAG_KEEP_MSI_CAP |
> > IMX_PCIE_FLAG_HAS_PHY_RESET |
> > IMX_PCIE_FLAG_SUPPORTS_SUSPEND,
> > .gpr = "fsl,imx8mq-iomuxc-gpr",
> > @@ -1923,6 +1929,7 @@ static const struct imx_pcie_drvdata drvdata[] = {
> > [IMX8MM] = {
> > .variant = IMX8MM,
> > .flags = IMX_PCIE_FLAG_SUPPORTS_SUSPEND |
> > + IMX_PCIE_FLAG_KEEP_MSI_CAP |
> > IMX_PCIE_FLAG_HAS_PHYDRV |
> > IMX_PCIE_FLAG_HAS_APP_RESET,
> > .gpr = "fsl,imx8mm-iomuxc-gpr",
> > diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c
> > index a74339982c24..7b5558561e15 100644
> > --- a/drivers/pci/controller/dwc/pcie-designware-host.c
> > +++ b/drivers/pci/controller/dwc/pcie-designware-host.c
> > @@ -1171,7 +1171,7 @@ int dw_pcie_setup_rc(struct dw_pcie_rp *pp)
> > * the MSI and MSI-X capabilities of the Root Port to allow the drivers
> > * to fall back to INTx instead.
> > */
> > - if (pp->use_imsi_rx) {
> > + if (pp->use_imsi_rx && !pp->keep_rp_msi_en) {
> > dw_pcie_remove_capability(pci, PCI_CAP_ID_MSI);
> > dw_pcie_remove_capability(pci, PCI_CAP_ID_MSIX);
> > }
> > diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h
> > index ae6389dd9caa..b12c5334552c 100644
> > --- a/drivers/pci/controller/dwc/pcie-designware.h
> > +++ b/drivers/pci/controller/dwc/pcie-designware.h
> > @@ -421,6 +421,7 @@ struct dw_pcie_host_ops {
> >
> > struct dw_pcie_rp {
> > bool use_imsi_rx:1;
> > + bool keep_rp_msi_en:1;
> > bool cfg0_io_shared:1;
> > u64 cfg0_base;
> > void __iomem *va_cfg0_base;
> > --
> > 2.37.1
> >
--
மணிவண்ணன் சதாசிவம்
^ permalink raw reply
* Re: [PATCH RFC 0/2] clk: scmi: DT support for SCMI clock rate rounding modes (per‑clock policy)
From: Peng Fan @ 2026-04-04 1:53 UTC (permalink / raw)
To: Michael Turquette, Stephen Boyd, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Sudeep Holla, Cristian Marussi, Brian Masney
Cc: linux-kernel, linux-clk, devicetree, arm-scmi, linux-arm-kernel,
Peng Fan
In-Reply-To: <20260306-scmi-clk-round-v1-0-61e2a5df9051@nxp.com>
Hi All,
On Fri, Mar 06, 2026 at 02:20:11PM +0800, Peng Fan (OSS) wrote:
>The ARM SCMI specification (DEN0056E) defines rounding‑mode flags for the
>CLOCK_RATE_SET command, allowing a client to request that the firmware
>round a requested clock rate down, up, or autonomously choose the
>closest achievable rate.
Would you please give a look and give some feedback?
Thanks,
Peng
>This series introduces DT support in the SCMI clock provider to carry a
>per‑clock rounding policy from the device tree into the SCMI protocol.
>
>Patch 1 adds dt‑bindings constants for rounding modes:
>ROUND_DOWN, ROUND_UP, ROUND_AUTO.
>
>Patch 2 extends the SCMI clock provider to optionally support
>"#clock-cells = <2>", where the second cell encodes the rounding mode.
>The first consumer that references a given clock latches the per‑clock
>policy. Subsequent consumers of the same clock must specify the same
>mode; otherwise, the request is rejected to avoid non‑deterministic
>behavior. The selected mode is passed through to the SCMI Clock protocol
>and mapped to the corresponding CLOCK_SET_* flag.
>
>Patch 2 includes changes to drivers/clk/clk-scmi.c and drivers/firmware
>arm_scmi/clock.c, it is hard to separate the changes without breaking,
>so I put the changes in one patch.
>
>This design adopts a per‑clock policy model, not per‑consumer. The rounding
>mode is applied by the provider per clock (index).
>All consumers of the same clock must agree on the rounding mode.
>Conflicting per‑consumer requests for the same clock are invalid and
>are rejected during phandle translation.
>
>This avoids silent clobbering and preserves deterministic behavior.
>
>Existing device trees using #clock-cells = <1> continue to work and
>default to ROUND_DOWN, exactly as before.
>
>Signed-off-by: Peng Fan <peng.fan@nxp.com>
>---
>Peng Fan (2):
> dt-bindings: clock: Add SCMI clock rounding mode declarations
> clk: scmi: Add support for two #clock-cells to pass rate rounding mode
>
> drivers/clk/clk-scmi.c | 62 +++++++++++++++++++++++++++++++++++++--
> drivers/firmware/arm_scmi/clock.c | 15 ++++++++--
> include/dt-bindings/clock/scmi.h | 13 ++++++++
> include/linux/scmi_protocol.h | 8 ++++-
> 4 files changed, 92 insertions(+), 6 deletions(-)
>---
>base-commit: 3f9cd19e764b782706dbaacc69e502099cb014ba
>change-id: 20260306-scmi-clk-round-1615258cf0fa
>
>Best regards,
>--
>Peng Fan <peng.fan@nxp.com>
>
^ permalink raw reply
* Re: [PATCH] dmaengine: imx-sdma: Refine spba bus searching in probe
From: Frank Li @ 2026-04-04 1:48 UTC (permalink / raw)
To: Shengjiu Wang
Cc: vkoul, Frank.Li, s.hauer, kernel, festevam, dmaengine, imx,
linux-arm-kernel, linux-kernel
In-Reply-To: <20260403083313.1172292-1-shengjiu.wang@nxp.com>
On Fri, Apr 03, 2026 at 04:33:13PM +0800, Shengjiu Wang wrote:
> There are multi spba-busses for i.MX8M* platforms, if only search for
> the first spba-bus in DT, the found spba-bus may not the real bus of
> audio devices, which cause issue for sdma p2p case, as the sdma p2p
> script presently does not deal with the transactions involving two devices
> connected to the AIPS bus.
It is bug fixes. add fixes tags.
>
> Search the SDMA parent node first, which should be the AIPS bus, then
> search the child node whose compatible string is spba-bus under that AIPS
> bus for the above multi spba-busses case.
>
> Signed-off-by: Shengjiu Wang <shengjiu.wang@nxp.com>
> ---
> drivers/dma/imx-sdma.c | 5 ++++-
> 1 file changed, 4 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c
> index 3d527883776b..be2fb87b7a89 100644
> --- a/drivers/dma/imx-sdma.c
> +++ b/drivers/dma/imx-sdma.c
> @@ -2364,13 +2364,16 @@ static int sdma_probe(struct platform_device *pdev)
> return dev_err_probe(&pdev->dev, ret,
> "failed to register controller\n");
>
> - spba_bus = of_find_compatible_node(NULL, NULL, "fsl,spba-bus");
> + struct device_node *sdma_parent_np = of_get_parent(np);
use cleanup struct device_node *__free(device_node) * ...
You can change spba_bus in another patch also.
Frank
> +
> + spba_bus = of_get_compatible_child(sdma_parent_np, "fsl,spba-bus");
> ret = of_address_to_resource(spba_bus, 0, &spba_res);
> if (!ret) {
> sdma->spba_start_addr = spba_res.start;
> sdma->spba_end_addr = spba_res.end;
> }
> of_node_put(spba_bus);
> + of_node_put(sdma_parent_np);
> }
>
> /*
> --
> 2.34.1
>
^ permalink raw reply
* Re: (subset) [PATCH 05/15] dt-bindings: rtc: ingenic,rtc: Use generic power-controller schema
From: Peng Fan @ 2026-04-04 1:33 UTC (permalink / raw)
To: Alexandre Belloni
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Rafael J. Wysocki,
Ulf Hansson, Florian Fainelli,
Broadcom internal kernel review list, Ray Jui, Scott Branden,
Saenz Julienne, Lee Jones, Liam Girdwood, Mark Brown,
Shree Ramamoorthy, Jerome Neanne, Paul Cercueil, Dmitry Osipenko,
Heiko Stuebner, Joseph Chen, Chris Zhong, Zhang Qing,
Sebastian Reichel, Andreas Kemnade, Jonathan Neuschäfer,
Lubomir Rintel, Julien Panis, Matti Vaittinen, Alexander Kurz,
Krzysztof Kozlowski, André Draszik, devicetree, linux-kernel,
linux-rpi-kernel, linux-arm-kernel, linux-rtc, linux-rockchip,
linux-samsung-soc, Peng Fan
In-Reply-To: <177523251875.1559844.9690289848283345069.b4-ty@b4>
Hi Alexandre,
On Fri, Apr 03, 2026 at 06:09:00PM +0200, Alexandre Belloni wrote:
>On Mon, 16 Mar 2026 22:47:40 +0800, Peng Fan (OSS) wrote:
>> Convert the binding to use the generic power-controller schema instead by
>> referencing power-controller.yaml and removing the local
>> `system-power-controller` property definition.
>
>Applied, thanks!
Thanks, but patch [01/15] has not been accepted, so please drop 05/15.
Thanks,
Peng
>
>[05/15] dt-bindings: rtc: ingenic,rtc: Use generic power-controller schema
> https://git.kernel.org/abelloni/c/0452290110cc
>
>Best regards,
>
>--
>Alexandre Belloni, co-owner and COO, Bootlin
>Embedded Linux and Kernel engineering
>https://bootlin.com
>
^ permalink raw reply
* Re: [PATCH v15 4/5] ring-buffer: Add persistent ring buffer invalid-page inject test
From: Masami Hiramatsu @ 2026-04-04 0:32 UTC (permalink / raw)
To: Steven Rostedt
Cc: Catalin Marinas, Will Deacon, Mathieu Desnoyers, linux-kernel,
linux-trace-kernel, Ian Rogers, linux-arm-kernel
In-Reply-To: <20260401184055.2f932674@gandalf.local.home>
On Wed, 1 Apr 2026 18:40:55 -0400
Steven Rostedt <rostedt@goodmis.org> wrote:
>
> I replied with mostly grammar fixes and some rewrites of text.
Thanks for reviewing! Let me update it.
>
> On Tue, 31 Mar 2026 17:36:30 +0900
> "Masami Hiramatsu (Google)" <mhiramat@kernel.org> wrote:
>
> > From: Masami Hiramatsu (Google) <mhiramat@kernel.org>
> >
> > Add a self-destractive test for the persistent ring buffer.
>
> "self-destractive"? Do you mean "self-destructive"?
>
> Probably better to call it a "self-corrupting test".
>
> >
> > This will inject erroneous value to some sub-buffer pages (where
>
> inject an erroneous
>
> > the index is even or multiples of 5) in the persistent ring buffer
> > when kernel gets panic, and check whether the number of detected
>
> when the kernel panics, and checks whether
>
> > invalid pages and the total entry_bytes are the same as recorded
>
> same as the recorded
>
> > values after reboot.
> >
> > This can ensure the kernel correctly recover partially corrupted
>
> This ensures that the kernel can correctly recover a partially corrupted
>
> > persistent ring buffer when boot.
>
> after a reboot or panic.
>
> >
> > The test only runs on the persistent ring buffer whose name is
> > "ptracingtest". And user has to fill it up with events before
>
> The user has to fill it with events before a kernel panic.
>
> > kernel panics.
> >
> > To run the test, enable CONFIG_RING_BUFFER_PERSISTENT_INJECT
> > and you have to setup the kernel cmdline;
>
> and add the following kernel cmdline:
>
> Note, it's more proper to use a colon (:) than a semi-colon (;) when
> referencing an example on the next line.
OK,
>
> >
> > reserve_mem=20M:2M:trace trace_instance=ptracingtest^traceoff@trace
> > panic=1
> >
> > And run following commands after the 1st boot;
>
> Run the following commands after the 1st boot:
>
> >
> > cd /sys/kernel/tracing/instances/ptracingtest
> > echo 1 > tracing_on
> > echo 1 > events/enable
> > sleep 3
> > echo c > /proc/sysrq-trigger
> >
> > After panic message, the kernel will reboot and run the verification
> > on the persistent ring buffer, e.g.
> >
> > Ring buffer meta [2] invalid buffer page detected
> > Ring buffer meta [2] is from previous boot! (318 pages discarded)
> > Ring buffer testing [2] invalid pages: PASSED (318/318)
> > Ring buffer testing [2] entry_bytes: PASSED (1300476/1300476)
> >
> > Signed-off-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
> > ---
> > Changes in v15:
> > - Use pr_warn() for test result.
> > - Inject errors on the page index is multiples of 5 so that
> > this can reproduce contiguous empty pages.
> > Changes in v14:
> > - Rename config to CONFIG_RING_BUFFER_PERSISTENT_INJECT.
> > - Clear meta->nr_invalid/entry_bytes after testing.
> > - Add test commands in config comment.
> > Changes in v10:
> > - Add entry_bytes test.
> > - Do not compile test code if CONFIG_RING_BUFFER_PERSISTENT_SELFTEST=n.
> > Changes in v9:
> > - Test also reader pages.
> > ---
> > include/linux/ring_buffer.h | 1 +
> > kernel/trace/Kconfig | 31 ++++++++++++++++++
> > kernel/trace/ring_buffer.c | 74 +++++++++++++++++++++++++++++++++++++++++++
> > kernel/trace/trace.c | 4 ++
> > 4 files changed, 110 insertions(+)
> >
> > diff --git a/include/linux/ring_buffer.h b/include/linux/ring_buffer.h
> > index 994f52b34344..0670742b2d60 100644
> > --- a/include/linux/ring_buffer.h
> > +++ b/include/linux/ring_buffer.h
> > @@ -238,6 +238,7 @@ int ring_buffer_subbuf_size_get(struct trace_buffer *buffer);
> >
> > enum ring_buffer_flags {
> > RB_FL_OVERWRITE = 1 << 0,
> > + RB_FL_TESTING = 1 << 1,
> > };
> >
> > #ifdef CONFIG_RING_BUFFER
> > diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig
> > index e130da35808f..07305ed6d745 100644
> > --- a/kernel/trace/Kconfig
> > +++ b/kernel/trace/Kconfig
> > @@ -1202,6 +1202,37 @@ config RING_BUFFER_VALIDATE_TIME_DELTAS
> > Only say Y if you understand what this does, and you
> > still want it enabled. Otherwise say N
> >
> > +config RING_BUFFER_PERSISTENT_INJECT
> > + bool "Enable persistent ring buffer error injection test"
> > + depends on RING_BUFFER
> > + help
> > + Run a selftest on the persistent ring buffer which names
> > + "ptracingtest" (and its backup) when panic_on_reboot by
>
> Does this do anything with the backup?
This meant that if you make a backup of ptracingtest
(instance=backup=ptracingtest) the check runs on backup instance too.
But it may be redundant. I'll drop it.
>
> > + invalidating ring buffer pages.
>
> This option will have the kernel check if the persistent ring
> buffer is named "ptracingtest", and if so, it will corrupt some
> of its pages on a kernel panic. This is used to test if the
> persistent ring buffer can recover from some of its sub-buffers
> being corrupted.
>
> [space]
>
> > + To use this, boot kernel with "ptracingtest" persistent
>
> , boot a kernel with a "ptracingtest" persistent
>
> > + ring buffer, e.g.
> > +
> > + reserve_mem=20M:2M:trace trace_instance=ptracingtest@trace panic=1
> > +
> > + And after the 1st boot, run test command, like;
>
> , run the following commands:
>
> > +
> > + cd /sys/kernel/tracing/instances/ptracingtest
> > + echo 1 > events/enable
> > + echo 1 > tracing_on
> > + sleep 3
> > + echo c > /proc/sysrq-trigger
> > +
> > + After panic message, the kernel reboots and show test results
> > + on the boot log.
>
> After the panic message, the kernel will reboot and will show the
> test results in the console output.
>
> > +
> > + Note that user has to enable events on the persistent ring
> > + buffer manually to fill up ring buffers before rebooting.
>
> Note that events for the ring buffer needs to be enabled prior to
> crashing the kernel so that the ring buffer has content that the
> test will corrupt.
>
> > + Since this invalidates the data on test target ring buffer,
> > + "ptracingtest" persistent ring buffer must not be used for
> > + actual tracing, but only for testing.
>
> As the test will corrupt events in the "ptracingtest" persistent
> ring buffer, it should not be used for any other purpose other
> than his test.
>
>
> > +
> > + If unsure, say N
> > +
> > config MMIOTRACE_TEST
> > tristate "Test module for mmiotrace"
> > depends on MMIOTRACE && m
> > diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c
> > index 5ff632ca3858..fb098b0b4505 100644
> > --- a/kernel/trace/ring_buffer.c
> > +++ b/kernel/trace/ring_buffer.c
> > @@ -64,6 +64,10 @@ struct ring_buffer_cpu_meta {
> > unsigned long commit_buffer;
> > __u32 subbuf_size;
> > __u32 nr_subbufs;
> > +#ifdef CONFIG_RING_BUFFER_PERSISTENT_INJECT
> > + __u32 nr_invalid;
> > + __u32 entry_bytes;
> > +#endif
> > int buffers[];
> > };
> >
> > @@ -2079,6 +2083,21 @@ static void rb_meta_validate_events(struct
> > ring_buffer_per_cpu *cpu_buffer) if (discarded)
> > pr_cont(" (%d pages discarded)", discarded);
> > pr_cont("\n");
> > +
> > +#ifdef CONFIG_RING_BUFFER_PERSISTENT_INJECT
> > + if (meta->nr_invalid)
> > + pr_warn("Ring buffer testing [%d] invalid pages: %s (%d/%d)\n",
> > + cpu_buffer->cpu,
> > + (discarded == meta->nr_invalid) ? "PASSED" : "FAILED",
> > + discarded, meta->nr_invalid);
> > + if (meta->entry_bytes)
> > + pr_warn("Ring buffer testing [%d] entry_bytes: %s (%ld/%ld)\n",
> > + cpu_buffer->cpu,
> > + (entry_bytes == meta->entry_bytes) ? "PASSED" : "FAILED",
> > + (long)entry_bytes, (long)meta->entry_bytes);
> > + meta->nr_invalid = 0;
> > + meta->entry_bytes = 0;
> > +#endif
> > return;
> >
> > invalid:
> > @@ -2559,12 +2578,67 @@ static void rb_free_cpu_buffer(struct
> > ring_buffer_per_cpu *cpu_buffer) kfree(cpu_buffer);
> > }
> >
> > +#ifdef CONFIG_RING_BUFFER_PERSISTENT_INJECT
> > +static void rb_test_inject_invalid_pages(struct trace_buffer *buffer)
> > +{
> > + struct ring_buffer_per_cpu *cpu_buffer;
> > + struct ring_buffer_cpu_meta *meta;
> > + struct buffer_data_page *dpage;
> > + u32 entry_bytes = 0;
> > + unsigned long ptr;
> > + int subbuf_size;
> > + int invalid = 0;
> > + int cpu;
> > + int i;
> > +
> > + if (!(buffer->flags & RB_FL_TESTING))
> > + return;
> > +
> > + guard(preempt)();
> > + cpu = smp_processor_id();
> > +
> > + cpu_buffer = buffer->buffers[cpu];
> > + meta = cpu_buffer->ring_meta;
> > + ptr = (unsigned long)rb_subbufs_from_meta(meta);
> > + subbuf_size = meta->subbuf_size;
> > +
> > + for (i = 0; i < meta->nr_subbufs; i++) {
> > + int idx = meta->buffers[i];
> > +
> > + dpage = (void *)(ptr + idx * subbuf_size);
> > + /* Skip unused pages */
> > + if (!local_read(&dpage->commit))
> > + continue;
> > +
> > + /*
> > + * Invalidate even pages or multiples of 5. This will lead 3
>
> This will cause 3
OK, thanks for your comments. I'll update it according your
review.
Thank you,
>
> -- Steve
>
> > + * contiguous invalidated(empty) pages.
> > + */
> > + if (!(i & 0x1) || !(i % 5)) {
> > + local_add(subbuf_size + 1, &dpage->commit);
> > + invalid++;
> > + } else {
> > + /* Count total commit bytes. */
> > + entry_bytes += local_read(&dpage->commit);
> > + }
> > + }
> > +
> > + pr_info("Inject invalidated %d pages on CPU%d, total size: %ld\n",
> > + invalid, cpu, (long)entry_bytes);
> > + meta->nr_invalid = invalid;
> > + meta->entry_bytes = entry_bytes;
> > +}
--
Masami Hiramatsu (Google) <mhiramat@kernel.org>
^ permalink raw reply
* Re: [PATCH 0/3] arm64: dts: imx8m: Correct PAD settings for PMIC_nINT (2nd part)
From: Frank Li @ 2026-04-04 0:21 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam, Shawn Guo,
Himanshu Bhavani, Alexander Stein, Peng Fan (OSS)
Cc: Frank Li, devicetree, imx, linux-arm-kernel, linux-kernel, linux,
Peng Fan
In-Reply-To: <20260329-imx8m-regulator-v1-0-802c0ec507cc@nxp.com>
On Sun, 29 Mar 2026 21:00:10 +0800, Peng Fan (OSS) wrote:
> There was a patchset for i.MX8MP [1], but after further check,
> i.MX8MM/N were missed, there are three boards that might also has
> interrupt storm issue. I not have the boards, per NXP board design
> , PMIC_nINT requires CPU internal pull up, I think most vendors will
> follow NXP design. So updates the i.MX8MM/N boards, but I not have
> the boards for testing. If board owners would give a test, that would
> be great.
>
> [...]
Applied, thanks!
[1/3] arm64: dts: imx8mm-emtop-som: Correct PAD settings for PMIC_nINT
commit: 721dec3ee9ff5231d13a412ff87df63b966d137b
[2/3] arm64: dts: imx8mn-tqma8mqnl: Correct PAD settings for PMIC_nINT
commit: 0fb37990774113afd943eaa91323679388584b6d
[3/3] arm64: dts: imx8mm-tqma8mqml: Correct PAD settings for PMIC_nINT
commit: 42a9f5a16328ed78a88e0498556965b6c6ec515c
Best regards,
--
Frank Li <Frank.Li@nxp.com>
^ permalink raw reply
* [GIT PULL] i.MX fixes for 7.0 round 2
From: Frank Li @ 2026-04-04 0:18 UTC (permalink / raw)
To: soc, arm
Cc: Frank.Li, Shawn Guo, Fabio Estevam, kernel, imx, linux-arm-kernel
From: Frank.Li@nxp.com
The following changes since commit 511f76bf1dce5acf8907b65a7d1bc8f7e7c0d637:
arm64: dts: imx8mq-librem5: Bump BUCK1 suspend voltage up to 0.85V (2026-03-17 23:24:44 -0400)
are available in the Git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/frank.li/linux.git tags/imx-fixes-7.0-2nd
for you to fetch changes up to 42a9f5a16328ed78a88e0498556965b6c6ec515c:
arm64: dts: imx8mm-tqma8mqml: Correct PAD settings for PMIC_nINT (2026-04-02 22:07:41 -0400)
----------------------------------------------------------------
i.MX fixes for 7.0 2nd round:
- Fixes interrupt storm by adding pull up pinctrl config for pin PMIC_nINT.
----------------------------------------------------------------
Peng Fan (14):
arm64: dts: imx8mp-debix-model-a: Correct PAD settings for PMIC_nINT
arm64: dts: imx8mp-debix-som-a: Correct PAD settings for PMIC_nINT
arm64: dts: imx8mp-navqp: Correct PAD settings for PMIC_nINT
arm64: dts: imx8mp-icore-mx8mp: Correct PAD settings for PMIC_nINT
arm64: dts: imx8mp-edm-g: Correct PAD settings for PMIC_nINT
arm64: dts: imx8mp-aristainetos3a-som-v1: Correct PAD settings for PMIC_nINT
arm64: dts: imx8mp-nitrogen-som: Correct PAD settings for PMIC_nINT
arm64: dts: imx8mp-sr-som: Correct PAD settings for PMIC_nINT
arm64: dts: imx8mp-ultra-mach-sbc: Correct PAD settings for PMIC_nINT
arm64: dts: imx8mp-dhcom-som: Correct PAD settings for PMIC_nINT
arm64: dts: imx8mp-data-modul-edm-sbc: Correct PAD settings for PMIC_nINT
arm64: dts: imx8mm-emtop-som: Correct PAD settings for PMIC_nINT
arm64: dts: imx8mn-tqma8mqnl: Correct PAD settings for PMIC_nINT
arm64: dts: imx8mm-tqma8mqml: Correct PAD settings for PMIC_nINT
arch/arm64/boot/dts/freescale/imx8mm-emtop-som.dtsi | 4 ++--
arch/arm64/boot/dts/freescale/imx8mm-tqma8mqml.dtsi | 2 +-
arch/arm64/boot/dts/freescale/imx8mn-tqma8mqnl.dtsi | 2 +-
arch/arm64/boot/dts/freescale/imx8mp-aristainetos3a-som-v1.dtsi | 2 +-
arch/arm64/boot/dts/freescale/imx8mp-data-modul-edm-sbc.dts | 2 +-
arch/arm64/boot/dts/freescale/imx8mp-debix-model-a.dts | 2 +-
arch/arm64/boot/dts/freescale/imx8mp-debix-som-a-bmb-08.dts | 2 +-
arch/arm64/boot/dts/freescale/imx8mp-debix-som-a.dtsi | 2 +-
arch/arm64/boot/dts/freescale/imx8mp-dhcom-som.dtsi | 2 +-
arch/arm64/boot/dts/freescale/imx8mp-edm-g.dtsi | 2 +-
arch/arm64/boot/dts/freescale/imx8mp-icore-mx8mp.dtsi | 2 +-
arch/arm64/boot/dts/freescale/imx8mp-navqp.dts | 2 +-
arch/arm64/boot/dts/freescale/imx8mp-nitrogen-som.dtsi | 2 +-
arch/arm64/boot/dts/freescale/imx8mp-sr-som.dtsi | 4 ++--
arch/arm64/boot/dts/freescale/imx8mp-ultra-mach-sbc.dts | 4 ++--
15 files changed, 18 insertions(+), 18 deletions(-)
^ permalink raw reply
* [PATCH v4 9/9] driver core: Replace dev->offline + ->offline_disabled with accessors
From: Douglas Anderson @ 2026-04-04 0:05 UTC (permalink / raw)
To: Greg Kroah-Hartman, Rafael J . Wysocki, Danilo Krummrich,
Alan Stern
Cc: Saravana Kannan, Christoph Hellwig, Eric Dumazet, Johan Hovold,
Leon Romanovsky, Alexander Lobakin, Alexey Kardashevskiy,
Robin Murphy, Douglas Anderson, Mark Brown, ardb, catalin.marinas,
chleroy, david, driver-core, kees, kevin.brodsky, lenb,
linux-acpi, linux-arm-kernel, linux-cxl, linux-kernel, linux-mm,
linuxppc-dev, maddy, maz, miko.lenczewski, mpe, npiggin,
osalvador, oupton, peterz, tglx, will, yangyicong, yeoreum.yun
In-Reply-To: <20260404000644.522677-1-dianders@chromium.org>
In C, bitfields are not necessarily safe to modify from multiple
threads without locking. Switch "offline" and "offline_disabled" over
to the "flags" field so modifications are safe.
Cc: Rafael J. Wysocki <rafael@kernel.org>
Acked-by: Mark Brown <broonie@kernel.org>
Signed-off-by: Douglas Anderson <dianders@chromium.org>
---
Not fixing any known bugs; problem is theoretical and found by code
inspection. Change is done somewhat manually and only lightly tested
(mostly compile-time tested).
Changes in v4:
- Use accessor functions for flags
Changes in v3:
- New
arch/arm64/kernel/cpufeature.c | 2 +-
.../powerpc/platforms/pseries/hotplug-memory.c | 4 ++--
drivers/acpi/scan.c | 2 +-
drivers/base/core.c | 18 +++++++++---------
drivers/base/cpu.c | 4 ++--
drivers/base/memory.c | 2 +-
include/linux/device.h | 12 ++++++------
kernel/cpu.c | 4 ++--
8 files changed, 24 insertions(+), 24 deletions(-)
diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
index 32c2dbcc0c64..c832aa565dc2 100644
--- a/arch/arm64/kernel/cpufeature.c
+++ b/arch/arm64/kernel/cpufeature.c
@@ -4042,7 +4042,7 @@ static int enable_mismatched_32bit_el0(unsigned int cpu)
*/
lucky_winner = cpu_32bit ? cpu : cpumask_any_and(cpu_32bit_el0_mask,
cpu_active_mask);
- get_cpu_device(lucky_winner)->offline_disabled = true;
+ dev_set_offline_disabled(get_cpu_device(lucky_winner));
setup_elf_hwcaps(compat_elf_hwcaps);
elf_hwcap_fixup();
pr_info("Asymmetric 32-bit EL0 support detected on CPU %u; CPU hot-unplug disabled on CPU %u\n",
diff --git a/arch/powerpc/platforms/pseries/hotplug-memory.c b/arch/powerpc/platforms/pseries/hotplug-memory.c
index b2f14db59034..75f85a5da981 100644
--- a/arch/powerpc/platforms/pseries/hotplug-memory.c
+++ b/arch/powerpc/platforms/pseries/hotplug-memory.c
@@ -213,9 +213,9 @@ static int dlpar_change_lmb_state(struct drmem_lmb *lmb, bool online)
return -EINVAL;
}
- if (online && mem_block->dev.offline)
+ if (online && dev_offline(&mem_block->dev))
rc = device_online(&mem_block->dev);
- else if (!online && !mem_block->dev.offline)
+ else if (!online && !dev_offline(&mem_block->dev))
rc = device_offline(&mem_block->dev);
else
rc = 0;
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index e8cdbdb46fdb..1353adbcc234 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -122,7 +122,7 @@ bool acpi_scan_is_offline(struct acpi_device *adev, bool uevent)
mutex_lock_nested(&adev->physical_node_lock, SINGLE_DEPTH_NESTING);
list_for_each_entry(pn, &adev->physical_node_list, node)
- if (device_supports_offline(pn->dev) && !pn->dev->offline) {
+ if (device_supports_offline(pn->dev) && !dev_offline(pn->dev)) {
if (uevent)
kobject_uevent_env(&pn->dev->kobj, KOBJ_CHANGE, envp);
diff --git a/drivers/base/core.c b/drivers/base/core.c
index f12f3b53b4d0..79c85dbcffad 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -2788,7 +2788,7 @@ static ssize_t online_show(struct device *dev, struct device_attribute *attr,
bool val;
device_lock(dev);
- val = !dev->offline;
+ val = !dev_offline(dev);
device_unlock(dev);
return sysfs_emit(buf, "%u\n", val);
}
@@ -2913,7 +2913,7 @@ static int device_add_attrs(struct device *dev)
if (error)
goto err_remove_type_groups;
- if (device_supports_offline(dev) && !dev->offline_disabled) {
+ if (device_supports_offline(dev) && !dev_offline_disabled(dev)) {
error = device_create_file(dev, &dev_attr_online);
if (error)
goto err_remove_dev_groups;
@@ -4178,7 +4178,7 @@ static int device_check_offline(struct device *dev, void *not_used)
if (ret)
return ret;
- return device_supports_offline(dev) && !dev->offline ? -EBUSY : 0;
+ return device_supports_offline(dev) && !dev_offline(dev) ? -EBUSY : 0;
}
/**
@@ -4196,7 +4196,7 @@ int device_offline(struct device *dev)
{
int ret;
- if (dev->offline_disabled)
+ if (dev_offline_disabled(dev))
return -EPERM;
ret = device_for_each_child(dev, NULL, device_check_offline);
@@ -4205,13 +4205,13 @@ int device_offline(struct device *dev)
device_lock(dev);
if (device_supports_offline(dev)) {
- if (dev->offline) {
+ if (dev_offline(dev)) {
ret = 1;
} else {
ret = dev->bus->offline(dev);
if (!ret) {
kobject_uevent(&dev->kobj, KOBJ_OFFLINE);
- dev->offline = true;
+ dev_set_offline(dev);
}
}
}
@@ -4236,11 +4236,11 @@ int device_online(struct device *dev)
device_lock(dev);
if (device_supports_offline(dev)) {
- if (dev->offline) {
+ if (dev_offline(dev)) {
ret = dev->bus->online(dev);
if (!ret) {
kobject_uevent(&dev->kobj, KOBJ_ONLINE);
- dev->offline = false;
+ dev_clear_offline(dev);
}
} else {
ret = 1;
@@ -4714,7 +4714,7 @@ static int device_attrs_change_owner(struct device *dev, kuid_t kuid,
if (error)
return error;
- if (device_supports_offline(dev) && !dev->offline_disabled) {
+ if (device_supports_offline(dev) && !dev_offline_disabled(dev)) {
/* Change online device attributes of @dev to @kuid/@kgid. */
error = sysfs_file_change_owner(kobj, dev_attr_online.attr.name,
kuid, kgid);
diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c
index 875abdc9942e..19d288a3c80c 100644
--- a/drivers/base/cpu.c
+++ b/drivers/base/cpu.c
@@ -422,8 +422,8 @@ int register_cpu(struct cpu *cpu, int num)
cpu->dev.id = num;
cpu->dev.bus = &cpu_subsys;
cpu->dev.release = cpu_device_release;
- cpu->dev.offline_disabled = !cpu->hotpluggable;
- cpu->dev.offline = !cpu_online(num);
+ dev_assign_offline_disabled(&cpu->dev, !cpu->hotpluggable);
+ dev_assign_offline(&cpu->dev, !cpu_online(num));
cpu->dev.of_node = of_get_cpu_node(num, NULL);
cpu->dev.groups = common_cpu_attr_groups;
if (cpu->hotpluggable)
diff --git a/drivers/base/memory.c b/drivers/base/memory.c
index a3091924918b..5005654f44fa 100644
--- a/drivers/base/memory.c
+++ b/drivers/base/memory.c
@@ -697,7 +697,7 @@ static int __add_memory_block(struct memory_block *memory)
memory->dev.id = memory->start_section_nr / sections_per_block;
memory->dev.release = memory_block_release;
memory->dev.groups = memory_memblk_attr_groups;
- memory->dev.offline = memory->state == MEM_OFFLINE;
+ dev_assign_offline(&memory->dev, memory->state == MEM_OFFLINE);
ret = device_register(&memory->dev);
if (ret) {
diff --git a/include/linux/device.h b/include/linux/device.h
index 8132aab17e04..65fc6c566cc6 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -485,6 +485,8 @@ struct device_physical_location {
* architecture supports non-coherent devices.
* @DEV_FLAG_OF_NODE_REUSED: Set if the device-tree node is shared with an
* ancestor device.
+ * @DEV_FLAG_OFFLINE_DISABLED: If set, the device is permanently online.
+ * @DEV_FLAG_OFFLINE: Set after successful invocation of bus type's .offline().
*/
enum struct_device_flags {
DEV_FLAG_READY_TO_PROBE = 0,
@@ -495,6 +497,8 @@ enum struct_device_flags {
DEV_FLAG_STATE_SYNCED = 5,
DEV_FLAG_DMA_COHERENT = 6,
DEV_FLAG_OF_NODE_REUSED = 7,
+ DEV_FLAG_OFFLINE_DISABLED = 8,
+ DEV_FLAG_OFFLINE = 9,
DEV_FLAG_COUNT
};
@@ -573,9 +577,6 @@ enum struct_device_flags {
* @removable: Whether the device can be removed from the system. This
* should be set by the subsystem / bus driver that discovered
* the device.
- *
- * @offline_disabled: If set, the device is permanently online.
- * @offline: Set after successful invocation of bus type's .offline().
* @flags: DEV_FLAG_XXX flags. Use atomic bitfield operations to modify.
*
* At the lowest level, every device in a Linux system is represented by an
@@ -680,9 +681,6 @@ struct device {
enum device_removable removable;
- bool offline_disabled:1;
- bool offline:1;
-
DECLARE_BITMAP(flags, DEV_FLAG_COUNT);
};
@@ -716,6 +714,8 @@ __create_dev_flag_accessors(dma_ops_bypass, DEV_FLAG_DMA_OPS_BYPASS);
__create_dev_flag_accessors(state_synced, DEV_FLAG_STATE_SYNCED);
__create_dev_flag_accessors(dma_coherent, DEV_FLAG_DMA_COHERENT);
__create_dev_flag_accessors(of_node_reused, DEV_FLAG_OF_NODE_REUSED);
+__create_dev_flag_accessors(offline_disabled, DEV_FLAG_OFFLINE_DISABLED);
+__create_dev_flag_accessors(offline, DEV_FLAG_OFFLINE);
/**
* struct device_link - Device link representation.
diff --git a/kernel/cpu.c b/kernel/cpu.c
index bc4f7a9ba64e..f975bb34915b 100644
--- a/kernel/cpu.c
+++ b/kernel/cpu.c
@@ -2639,7 +2639,7 @@ static void cpuhp_offline_cpu_device(unsigned int cpu)
{
struct device *dev = get_cpu_device(cpu);
- dev->offline = true;
+ dev_set_offline(dev);
/* Tell user space about the state change */
kobject_uevent(&dev->kobj, KOBJ_OFFLINE);
}
@@ -2648,7 +2648,7 @@ static void cpuhp_online_cpu_device(unsigned int cpu)
{
struct device *dev = get_cpu_device(cpu);
- dev->offline = false;
+ dev_clear_offline(dev);
/* Tell user space about the state change */
kobject_uevent(&dev->kobj, KOBJ_ONLINE);
}
--
2.53.0.1213.gd9a14994de-goog
^ permalink raw reply related
* [PATCH v4 8/9] driver core: Replace dev->of_node_reused with dev_of_node_reused()
From: Douglas Anderson @ 2026-04-04 0:05 UTC (permalink / raw)
To: Greg Kroah-Hartman, Rafael J . Wysocki, Danilo Krummrich,
Alan Stern
Cc: Saravana Kannan, Christoph Hellwig, Eric Dumazet, Johan Hovold,
Leon Romanovsky, Alexander Lobakin, Alexey Kardashevskiy,
Robin Murphy, Douglas Anderson, Mark Brown, alexander.stein,
andrew, andrew, andriy.shevchenko, bhelgaas, brgl, davem,
devicetree, driver-core, hkallweit1, jirislaby, joel, kees, kuba,
lgirdwood, linux-arm-kernel, linux-aspeed, linux-kernel,
linux-pci, linux-serial, linux-usb, linux, mani, netdev, pabeni,
robh
In-Reply-To: <20260404000644.522677-1-dianders@chromium.org>
In C, bitfields are not necessarily safe to modify from multiple
threads without locking. Switch "of_node_reused" over to the "flags"
field so modifications are safe.
Cc: Johan Hovold <johan@kernel.org>
Acked-by: Mark Brown <broonie@kernel.org>
Signed-off-by: Douglas Anderson <dianders@chromium.org>
---
Not fixing any known bugs; problem is theoretical and found by code
inspection. Change is done somewhat manually and only lightly tested
(mostly compile-time tested).
Changes in v4:
- Use accessor functions for flags
Changes in v3:
- New
drivers/base/core.c | 2 +-
drivers/base/pinctrl.c | 2 +-
drivers/base/platform.c | 2 +-
drivers/net/pcs/pcs-xpcs-plat.c | 2 +-
drivers/of/device.c | 6 +++---
drivers/pci/of.c | 2 +-
drivers/pci/pwrctrl/core.c | 2 +-
drivers/regulator/bq257xx-regulator.c | 2 +-
drivers/regulator/rk808-regulator.c | 2 +-
drivers/tty/serial/serial_base_bus.c | 2 +-
drivers/usb/gadget/udc/aspeed-vhub/dev.c | 2 +-
include/linux/device.h | 7 ++++---
12 files changed, 17 insertions(+), 16 deletions(-)
diff --git a/drivers/base/core.c b/drivers/base/core.c
index 531f02a5469a..f12f3b53b4d0 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -5281,7 +5281,7 @@ void device_set_of_node_from_dev(struct device *dev, const struct device *dev2)
{
of_node_put(dev->of_node);
dev->of_node = of_node_get(dev2->of_node);
- dev->of_node_reused = true;
+ dev_set_of_node_reused(dev);
}
EXPORT_SYMBOL_GPL(device_set_of_node_from_dev);
diff --git a/drivers/base/pinctrl.c b/drivers/base/pinctrl.c
index 6e250272c843..0bbc83231234 100644
--- a/drivers/base/pinctrl.c
+++ b/drivers/base/pinctrl.c
@@ -24,7 +24,7 @@ int pinctrl_bind_pins(struct device *dev)
{
int ret;
- if (dev->of_node_reused)
+ if (dev_of_node_reused(dev))
return 0;
dev->pins = devm_kzalloc(dev, sizeof(*(dev->pins)), GFP_KERNEL);
diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index d44591d52e36..199e6fb25770 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -856,7 +856,7 @@ struct platform_device *platform_device_register_full(
pdev->dev.parent = pdevinfo->parent;
pdev->dev.fwnode = pdevinfo->fwnode;
pdev->dev.of_node = of_node_get(to_of_node(pdev->dev.fwnode));
- pdev->dev.of_node_reused = pdevinfo->of_node_reused;
+ dev_assign_of_node_reused(&pdev->dev, pdevinfo->of_node_reused);
if (pdevinfo->dma_mask) {
pdev->platform_dma_mask = pdevinfo->dma_mask;
diff --git a/drivers/net/pcs/pcs-xpcs-plat.c b/drivers/net/pcs/pcs-xpcs-plat.c
index b8c48f9effbf..f4b1b8246ce9 100644
--- a/drivers/net/pcs/pcs-xpcs-plat.c
+++ b/drivers/net/pcs/pcs-xpcs-plat.c
@@ -349,7 +349,7 @@ static int xpcs_plat_init_dev(struct dw_xpcs_plat *pxpcs)
* up later. Make sure DD-core is aware of the OF-node being re-used.
*/
device_set_node(&mdiodev->dev, fwnode_handle_get(dev_fwnode(dev)));
- mdiodev->dev.of_node_reused = true;
+ dev_set_of_node_reused(&mdiodev->dev);
/* Pass the data further so the DW XPCS driver core could use it */
mdiodev->dev.platform_data = (void *)device_get_match_data(dev);
diff --git a/drivers/of/device.c b/drivers/of/device.c
index f7e75e527667..be4e1584e0af 100644
--- a/drivers/of/device.c
+++ b/drivers/of/device.c
@@ -26,7 +26,7 @@
const struct of_device_id *of_match_device(const struct of_device_id *matches,
const struct device *dev)
{
- if (!matches || !dev->of_node || dev->of_node_reused)
+ if (!matches || !dev->of_node || dev_of_node_reused(dev))
return NULL;
return of_match_node(matches, dev->of_node);
}
@@ -192,7 +192,7 @@ ssize_t of_device_modalias(struct device *dev, char *str, ssize_t len)
{
ssize_t sl;
- if (!dev || !dev->of_node || dev->of_node_reused)
+ if (!dev || !dev->of_node || dev_of_node_reused(dev))
return -ENODEV;
sl = of_modalias(dev->of_node, str, len - 2);
@@ -254,7 +254,7 @@ int of_device_uevent_modalias(const struct device *dev, struct kobj_uevent_env *
{
int sl;
- if ((!dev) || (!dev->of_node) || dev->of_node_reused)
+ if ((!dev) || (!dev->of_node) || dev_of_node_reused(dev))
return -ENODEV;
/* Devicetree modalias is tricky, we add it in 2 steps */
diff --git a/drivers/pci/of.c b/drivers/pci/of.c
index 9f8eb5df279e..1f9b669abdb0 100644
--- a/drivers/pci/of.c
+++ b/drivers/pci/of.c
@@ -38,7 +38,7 @@ int pci_set_of_node(struct pci_dev *dev)
struct device *pdev __free(put_device) =
bus_find_device_by_of_node(&platform_bus_type, node);
if (pdev)
- dev->bus->dev.of_node_reused = true;
+ dev_set_of_node_reused(&dev->bus->dev);
device_set_node(&dev->dev, of_fwnode_handle(no_free_ptr(node)));
return 0;
diff --git a/drivers/pci/pwrctrl/core.c b/drivers/pci/pwrctrl/core.c
index 7754baed67f2..72963a92362a 100644
--- a/drivers/pci/pwrctrl/core.c
+++ b/drivers/pci/pwrctrl/core.c
@@ -39,7 +39,7 @@ static int pci_pwrctrl_notify(struct notifier_block *nb, unsigned long action,
* If we got here then the PCI device is the second after the
* power control platform device. Mark its OF node as reused.
*/
- dev->of_node_reused = true;
+ dev_set_of_node_reused(dev);
break;
}
diff --git a/drivers/regulator/bq257xx-regulator.c b/drivers/regulator/bq257xx-regulator.c
index dab8f1ab4450..40e0f1a7ae81 100644
--- a/drivers/regulator/bq257xx-regulator.c
+++ b/drivers/regulator/bq257xx-regulator.c
@@ -143,7 +143,7 @@ static int bq257xx_regulator_probe(struct platform_device *pdev)
struct regulator_config cfg = {};
pdev->dev.of_node = pdev->dev.parent->of_node;
- pdev->dev.of_node_reused = true;
+ dev_set_of_node_reused(&pdev->dev);
pdata = devm_kzalloc(&pdev->dev, sizeof(struct bq257xx_reg_data), GFP_KERNEL);
if (!pdata)
diff --git a/drivers/regulator/rk808-regulator.c b/drivers/regulator/rk808-regulator.c
index e66408f23bb6..8297d31cde9f 100644
--- a/drivers/regulator/rk808-regulator.c
+++ b/drivers/regulator/rk808-regulator.c
@@ -2115,7 +2115,7 @@ static int rk808_regulator_probe(struct platform_device *pdev)
int ret, i, nregulators;
pdev->dev.of_node = pdev->dev.parent->of_node;
- pdev->dev.of_node_reused = true;
+ dev_set_of_node_reused(&pdev->dev);
regmap = dev_get_regmap(pdev->dev.parent, NULL);
if (!regmap)
diff --git a/drivers/tty/serial/serial_base_bus.c b/drivers/tty/serial/serial_base_bus.c
index a12935f6b992..5f23284a8778 100644
--- a/drivers/tty/serial/serial_base_bus.c
+++ b/drivers/tty/serial/serial_base_bus.c
@@ -74,7 +74,7 @@ static int serial_base_device_init(struct uart_port *port,
dev->parent = parent_dev;
dev->bus = &serial_base_bus_type;
dev->release = release;
- dev->of_node_reused = true;
+ dev_set_of_node_reused(dev);
device_set_node(dev, fwnode_handle_get(dev_fwnode(parent_dev)));
diff --git a/drivers/usb/gadget/udc/aspeed-vhub/dev.c b/drivers/usb/gadget/udc/aspeed-vhub/dev.c
index 2ecd049dacc2..8b9449d16324 100644
--- a/drivers/usb/gadget/udc/aspeed-vhub/dev.c
+++ b/drivers/usb/gadget/udc/aspeed-vhub/dev.c
@@ -593,7 +593,7 @@ int ast_vhub_init_dev(struct ast_vhub *vhub, unsigned int idx)
d->gadget.max_speed = USB_SPEED_HIGH;
d->gadget.speed = USB_SPEED_UNKNOWN;
d->gadget.dev.of_node = vhub->pdev->dev.of_node;
- d->gadget.dev.of_node_reused = true;
+ dev_set_of_node_reused(&d->gadget.dev);
rc = usb_add_gadget_udc(d->port_dev, &d->gadget);
if (rc != 0)
diff --git a/include/linux/device.h b/include/linux/device.h
index fca986cef2ed..8132aab17e04 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -483,6 +483,8 @@ struct device_physical_location {
* driver/bus sync_state() callback.
* @DEV_FLAG_DMA_COHERENT: This particular device is dma coherent, even if the
* architecture supports non-coherent devices.
+ * @DEV_FLAG_OF_NODE_REUSED: Set if the device-tree node is shared with an
+ * ancestor device.
*/
enum struct_device_flags {
DEV_FLAG_READY_TO_PROBE = 0,
@@ -492,6 +494,7 @@ enum struct_device_flags {
DEV_FLAG_DMA_OPS_BYPASS = 4,
DEV_FLAG_STATE_SYNCED = 5,
DEV_FLAG_DMA_COHERENT = 6,
+ DEV_FLAG_OF_NODE_REUSED = 7,
DEV_FLAG_COUNT
};
@@ -573,8 +576,6 @@ enum struct_device_flags {
*
* @offline_disabled: If set, the device is permanently online.
* @offline: Set after successful invocation of bus type's .offline().
- * @of_node_reused: Set if the device-tree node is shared with an ancestor
- * device.
* @flags: DEV_FLAG_XXX flags. Use atomic bitfield operations to modify.
*
* At the lowest level, every device in a Linux system is represented by an
@@ -681,7 +682,6 @@ struct device {
bool offline_disabled:1;
bool offline:1;
- bool of_node_reused:1;
DECLARE_BITMAP(flags, DEV_FLAG_COUNT);
};
@@ -715,6 +715,7 @@ __create_dev_flag_accessors(dma_skip_sync, DEV_FLAG_DMA_SKIP_SYNC);
__create_dev_flag_accessors(dma_ops_bypass, DEV_FLAG_DMA_OPS_BYPASS);
__create_dev_flag_accessors(state_synced, DEV_FLAG_STATE_SYNCED);
__create_dev_flag_accessors(dma_coherent, DEV_FLAG_DMA_COHERENT);
+__create_dev_flag_accessors(of_node_reused, DEV_FLAG_OF_NODE_REUSED);
/**
* struct device_link - Device link representation.
--
2.53.0.1213.gd9a14994de-goog
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox