* [kvm-unit-tests PATCH 2/6] configure: Make arch_libdir a first-class entity
From: Chinmay Rath @ 2026-07-08 10:51 UTC (permalink / raw)
To: thuth
Cc: npiggin, harshpb, lvivier, linuxppc-dev, kvm, andrew.jones, sbhat,
Chinmay Rath
In-Reply-To: <20260708105122.1177210-1-rathc@linux.ibm.com>
From: Nicholas Piggin <npiggin@gmail.com>
arch_libdir was brought in to improve the heuristic determination of
the lib/ directory based on arch and testdir names, but it did not
entirely clean that mess up.
Remove the arch_libdir->arch->testdir heuristic and just require
everybody sets arch_libdir correctly. Fail if the lib/arch or
lib/arch/asm directories can not be found.
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
Reviewed-by: Andrew Jones <andrew.jones@linux.dev>
Signed-off-by: Chinmay Rath <rathc@linux.ibm.com>
---
Makefile | 2 +-
configure | 20 ++++++++++++--------
2 files changed, 13 insertions(+), 9 deletions(-)
diff --git a/Makefile b/Makefile
index 42ef5826..8e002043 100644
--- a/Makefile
+++ b/Makefile
@@ -12,7 +12,7 @@ vpath %.s $(SRCDIR)
vpath %.S $(SRCDIR)
libdirs-get = $(shell [ -d "lib/$(1)" ] && echo "lib/$(1) lib/$(1)/asm")
-ARCH_LIBDIRS := $(call libdirs-get,$(ARCH_LIBDIR)) $(call libdirs-get,$(TEST_DIR))
+ARCH_LIBDIRS := $(call libdirs-get,$(ARCH_LIBDIR))
OBJDIRS := $(ARCH_LIBDIRS)
DESTDIR := $(PREFIX)/share/kvm-unit-tests/
diff --git a/configure b/configure
index 6d549d1e..aeb5570c 100755
--- a/configure
+++ b/configure
@@ -274,7 +274,6 @@ fi
arch_name=$arch
[ "$arch" = "aarch64" ] && arch="arm64"
[ "$arch_name" = "arm64" ] && arch_name="aarch64"
-arch_libdir=$arch
if [ "$arch" = "riscv" ]; then
echo "riscv32 or riscv64 must be specified"
@@ -373,8 +372,10 @@ fi
if [ "$arch" = "i386" ] || [ "$arch" = "x86_64" ]; then
testdir=x86
+ arch_libdir=x86
elif [ "$arch" = "arm" ] || [ "$arch" = "arm64" ]; then
testdir=arm
+ arch_libdir=$arch
if [ "$target" = "qemu" ]; then
: "${uart_early_addr:=0x9000000}"
elif [ "$target" = "kvmtool" ]; then
@@ -385,6 +386,7 @@ elif [ "$arch" = "arm" ] || [ "$arch" = "arm64" ]; then
fi
elif [ "$arch" = "ppc64" ]; then
testdir=powerpc
+ arch_libdir=ppc64
firmware="$testdir/boot_rom.bin"
if [ "$endian" != "little" ] && [ "$endian" != "big" ]; then
echo "You must provide endianness (big or little)!"
@@ -400,6 +402,7 @@ elif [ "$arch" = "riscv32" ] || [ "$arch" = "riscv64" ]; then
fi
elif [ "$arch" = "s390x" ]; then
testdir=s390x
+ arch_libdir=s390x
else
echo "arch $arch is not supported!"
arch=
@@ -409,6 +412,10 @@ if [ ! -d "$srcdir/$testdir" ]; then
echo "$srcdir/$testdir does not exist!"
exit 1
fi
+if [ ! -d "$srcdir/lib/$arch_libdir" ]; then
+ echo "$srcdir/lib/$arch_libdir does not exist!"
+ exit 1
+fi
if [ "$efi" = "y" ] && [ -f "$srcdir/$testdir/efi/run" ]; then
ln -fs "$srcdir/$testdir/efi/run" $testdir-run
@@ -471,15 +478,12 @@ fi
# link lib/asm for the architecture
rm -f lib/asm
asm="asm-generic"
-if [ -d "$srcdir/lib/$arch/asm" ]; then
- asm="$srcdir/lib/$arch/asm"
- mkdir -p "lib/$arch"
-elif [ -d "$srcdir/lib/$arch_libdir/asm" ]; then
+if [ -d "$srcdir/lib/$arch_libdir/asm" ]; then
asm="$srcdir/lib/$arch_libdir/asm"
mkdir -p "lib/$arch_libdir"
-elif [ -d "$srcdir/lib/$testdir/asm" ]; then
- asm="$srcdir/lib/$testdir/asm"
- mkdir -p "lib/$testdir"
+else
+ echo "$srcdir/lib/$arch_libdir/asm does not exist"
+ exit 1
fi
ln -sf "$asm" lib/asm
mkdir -p lib/generated lib/libfdt
--
2.53.0
^ permalink raw reply related
* [kvm-unit-tests PATCH 1/6] powerpc: add pmu tests
From: Chinmay Rath @ 2026-07-08 10:51 UTC (permalink / raw)
To: thuth
Cc: npiggin, harshpb, lvivier, linuxppc-dev, kvm, andrew.jones, sbhat,
Chinmay Rath
In-Reply-To: <20260708105122.1177210-1-rathc@linux.ibm.com>
From: Nicholas Piggin <npiggin@gmail.com>
Add some initial PMU testing.
- PMC5/6 tests
- PMAE / PMI test
- BHRB basic tests
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
Signed-off-by: Chinmay Rath <rathc@linux.ibm.com>
---
lib/powerpc/asm/processor.h | 2 +
lib/powerpc/asm/reg.h | 9 +
lib/powerpc/asm/setup.h | 1 +
lib/powerpc/setup.c | 20 ++
powerpc/Makefile.common | 3 +-
powerpc/pmu.c | 567 ++++++++++++++++++++++++++++++++++++
powerpc/unittests.cfg | 3 +
7 files changed, 604 insertions(+), 1 deletion(-)
create mode 100644 powerpc/pmu.c
diff --git a/lib/powerpc/asm/processor.h b/lib/powerpc/asm/processor.h
index 153126fe..08506438 100644
--- a/lib/powerpc/asm/processor.h
+++ b/lib/powerpc/asm/processor.h
@@ -17,6 +17,8 @@ extern bool cpu_has_hv;
extern bool cpu_has_power_mce;
extern bool cpu_has_siar;
extern bool cpu_has_heai;
+extern bool cpu_has_bhrb;
+extern bool cpu_has_p10_bhrb;
extern bool cpu_has_radix;
extern bool cpu_has_prefix;
extern bool cpu_has_sc_lev;
diff --git a/lib/powerpc/asm/reg.h b/lib/powerpc/asm/reg.h
index 69ef21ad..602fba1b 100644
--- a/lib/powerpc/asm/reg.h
+++ b/lib/powerpc/asm/reg.h
@@ -40,10 +40,19 @@
#define SPR_LPIDR 0x13f
#define SPR_HEIR 0x153
#define SPR_PTCR 0x1d0
+#define SPR_MMCRA 0x312
+#define MMCRA_BHRBRD UL(0x0000002000000000)
+#define MMCRA_IFM_MASK UL(0x00000000c0000000)
+#define SPR_PMC5 0x317
+#define SPR_PMC6 0x318
#define SPR_MMCR0 0x31b
#define MMCR0_FC UL(0x80000000)
+#define MMCR0_FCP UL(0x20000000)
#define MMCR0_PMAE UL(0x04000000)
+#define MMCR0_BHRBA UL(0x00200000)
+#define MMCR0_FCPC UL(0x00001000)
#define MMCR0_PMAO UL(0x00000080)
+#define MMCR0_FC56 UL(0x00000010)
#define SPR_SIAR 0x31c
/* Machine State Register definitions: */
diff --git a/lib/powerpc/asm/setup.h b/lib/powerpc/asm/setup.h
index 9ca318ce..8f0b58ed 100644
--- a/lib/powerpc/asm/setup.h
+++ b/lib/powerpc/asm/setup.h
@@ -10,6 +10,7 @@
#define NR_CPUS 8 /* arbitrarily set for now */
extern uint64_t tb_hz;
+extern uint64_t cpu_hz;
#define NR_MEM_REGIONS 8
#define MR_F_PRIMARY (1U << 0)
diff --git a/lib/powerpc/setup.c b/lib/powerpc/setup.c
index c1f0f9ad..ef4ebdbc 100644
--- a/lib/powerpc/setup.c
+++ b/lib/powerpc/setup.c
@@ -33,6 +33,7 @@ u32 initrd_size;
u32 cpu_to_hwid[NR_CPUS] = { [0 ... NR_CPUS-1] = (~0U) };
int nr_cpus_present;
uint64_t tb_hz;
+uint64_t cpu_hz;
struct mem_region mem_regions[NR_MEM_REGIONS];
phys_addr_t __physical_start, __physical_end;
@@ -42,6 +43,7 @@ struct cpu_set_params {
unsigned icache_bytes;
unsigned dcache_bytes;
uint64_t tb_hz;
+ uint64_t cpu_hz;
};
static void cpu_set(int fdtnode, u64 regval, void *info)
@@ -95,6 +97,19 @@ static void cpu_set(int fdtnode, u64 regval, void *info)
data = (u32 *)prop->data;
params->tb_hz = fdt32_to_cpu(*data);
+ prop = fdt_get_property(dt_fdt(), fdtnode,
+ "ibm,extended-clock-frequency", NULL);
+ if (prop) {
+ u64 *data64 = (u64 *)prop->data;
+ params->cpu_hz = fdt64_to_cpu(*data64);
+ } else {
+ prop = fdt_get_property(dt_fdt(), fdtnode,
+ "clock-frequency", NULL);
+ assert(prop != NULL);
+ data = (u32 *)prop->data;
+ params->cpu_hz = fdt32_to_cpu(*data);
+ }
+
read_common_info = true;
}
}
@@ -103,6 +118,8 @@ bool cpu_has_hv;
bool cpu_has_power_mce; /* POWER CPU machine checks */
bool cpu_has_siar;
bool cpu_has_heai;
+bool cpu_has_bhrb;
+bool cpu_has_p10_bhrb;
bool cpu_has_radix;
bool cpu_has_prefix;
bool cpu_has_sc_lev; /* sc interrupt has LEV field in SRR1 */
@@ -119,12 +136,14 @@ static void cpu_init_params(void)
__icache_bytes = params.icache_bytes;
__dcache_bytes = params.dcache_bytes;
tb_hz = params.tb_hz;
+ cpu_hz = params.cpu_hz;
switch (mfspr(SPR_PVR) & PVR_VERSION_MASK) {
case PVR_VER_POWER10:
cpu_has_prefix = true;
cpu_has_sc_lev = true;
cpu_has_pause_short = true;
+ cpu_has_p10_bhrb = true;
case PVR_VER_POWER9:
cpu_has_radix = true;
case PVR_VER_POWER8E:
@@ -133,6 +152,7 @@ static void cpu_init_params(void)
cpu_has_power_mce = true;
cpu_has_heai = true;
cpu_has_siar = true;
+ cpu_has_bhrb = true;
break;
default:
break;
diff --git a/powerpc/Makefile.common b/powerpc/Makefile.common
index db4a34f2..3b357982 100644
--- a/powerpc/Makefile.common
+++ b/powerpc/Makefile.common
@@ -18,7 +18,8 @@ tests-common = \
$(TEST_DIR)/sprs.elf \
$(TEST_DIR)/timebase.elf \
$(TEST_DIR)/interrupts.elf \
- $(TEST_DIR)/mmu.elf
+ $(TEST_DIR)/mmu.elf \
+ $(TEST_DIR)/pmu.elf
tests-all = $(tests-common) $(tests)
all: directories $(TEST_DIR)/boot_rom.bin $(tests-all)
diff --git a/powerpc/pmu.c b/powerpc/pmu.c
new file mode 100644
index 00000000..402ce569
--- /dev/null
+++ b/powerpc/pmu.c
@@ -0,0 +1,567 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Test PMU
+ *
+ * Copyright 2024 Nicholas Piggin, IBM Corp.
+ */
+#include <libcflat.h>
+#include <util.h>
+#include <migrate.h>
+#include <alloc.h>
+#include <asm/setup.h>
+#include <asm/handlers.h>
+#include <asm/hcall.h>
+#include <asm/processor.h>
+#include <asm/time.h>
+#include <asm/barrier.h>
+#include <asm/mmu.h>
+#include <asm/smp.h>
+#include "alloc_phys.h"
+#include "vmalloc.h"
+
+static volatile bool got_interrupt;
+static volatile struct pt_regs recorded_regs;
+static volatile unsigned long recorded_mmcr0;
+
+static void illegal_handler(struct pt_regs *regs, void *data)
+{
+ got_interrupt = true;
+ regs_advance_insn(regs);
+}
+
+static void fault_handler(struct pt_regs *regs, void *data)
+{
+ got_interrupt = true;
+ regs_advance_insn(regs);
+}
+
+static void sc_handler(struct pt_regs *regs, void *data)
+{
+ got_interrupt = true;
+}
+
+static void reset_mmcr0(void)
+{
+ mtspr(SPR_MMCR0, mfspr(SPR_MMCR0) | (MMCR0_FC | MMCR0_FC56));
+ mtspr(SPR_MMCR0, mfspr(SPR_MMCR0) & ~(MMCR0_PMAE | MMCR0_PMAO));
+}
+
+static __attribute__((__noinline__)) unsigned long pmc5_count_nr_insns(unsigned long nr)
+{
+ reset_mmcr0();
+ mtspr(SPR_PMC5, 0);
+ mtspr(SPR_MMCR0, mfspr(SPR_MMCR0) & ~(MMCR0_FC | MMCR0_FC56));
+ asm volatile("mtctr %0 ; 1: bdnz 1b" :: "r"(nr) : "ctr");
+ mtspr(SPR_MMCR0, mfspr(SPR_MMCR0) | (MMCR0_FC | MMCR0_FC56));
+
+ return mfspr(SPR_PMC5);
+}
+
+static void test_pmc5(void)
+{
+ unsigned long pmc5;
+ unsigned long mmcr;
+
+ reset_mmcr0();
+ mmcr = mfspr(SPR_MMCR0);
+ mtspr(SPR_PMC5, 0);
+ mtspr(SPR_MMCR0, mmcr & ~(MMCR0_FC | MMCR0_FC56));
+ asm volatile(".rep 20 ; nop ; .endr" ::: "memory");
+ mtspr(SPR_MMCR0, mmcr);
+ pmc5 = mfspr(SPR_PMC5);
+
+ report_kfail(true, pmc5 == 21, "PMC5 counts instructions exactly %ld", pmc5);
+}
+
+static void test_pmc5_with_branch(void)
+{
+ unsigned long pmc5;
+ unsigned long mmcr;
+
+ reset_mmcr0();
+ mmcr = mfspr(SPR_MMCR0);
+ mtspr(SPR_PMC5, 0);
+ mtspr(SPR_MMCR0, mmcr & ~(MMCR0_FC | MMCR0_FC56));
+ asm volatile(".rep 20 ; b $+4 ; .endr" ::: "memory");
+ mtspr(SPR_MMCR0, mmcr);
+ pmc5 = mfspr(SPR_PMC5);
+
+ /* TCG and POWER9 do not count instructions around faults correctly */
+ report_kfail(true, pmc5 == 21, "PMC5 counts instructions with branch %ld", pmc5);
+}
+
+static void test_pmc5_with_cond_branch(void)
+{
+ unsigned long pmc5;
+ unsigned long mmcr;
+
+ reset_mmcr0();
+ mmcr = mfspr(SPR_MMCR0);
+ mtspr(SPR_PMC5, 0);
+ mtspr(SPR_MMCR0, mmcr & ~(MMCR0_FC | MMCR0_FC56));
+ asm volatile(".rep 10 ; nop ; .endr ; cmpdi %0,1 ; beq 1f ; .rep 10 ; nop ; .endr ; 1:" : : "r"(0) : "memory", "cr0");
+ mtspr(SPR_MMCR0, mmcr);
+ pmc5 = mfspr(SPR_PMC5);
+
+ /* TCG and POWER9 do not count instructions around faults correctly */
+ report_kfail(true, pmc5 == 24,
+ "PMC5 counts instructions wth conditional branch %ld", pmc5);
+}
+
+static void test_pmc5_with_ill(void)
+{
+ unsigned long pmc5_1, pmc5_2;
+
+ handle_exception(0x700, &illegal_handler, NULL);
+ handle_exception(0xe40, &illegal_handler, NULL);
+
+ reset_mmcr0();
+ mtspr(SPR_PMC5, 0);
+ mtspr(SPR_MMCR0, mfspr(SPR_MMCR0) & ~(MMCR0_FC | MMCR0_FC56));
+ asm volatile(".long 0x0" ::: "memory");
+ mtspr(SPR_MMCR0, mfspr(SPR_MMCR0) | (MMCR0_FC | MMCR0_FC56));
+ assert(got_interrupt);
+ got_interrupt = false;
+ pmc5_1 = mfspr(SPR_PMC5);
+
+ reset_mmcr0();
+ mtspr(SPR_PMC5, 0);
+ mtspr(SPR_MMCR0, mfspr(SPR_MMCR0) & ~(MMCR0_FC | MMCR0_FC56));
+ asm volatile(".rep 10 ; nop ; .endr ; .long 0x0 ; .rep 10 ; nop ; .endr " ::: "memory");
+ mtspr(SPR_MMCR0, mfspr(SPR_MMCR0) | (MMCR0_FC | MMCR0_FC56));
+ assert(got_interrupt);
+ got_interrupt = false;
+ pmc5_2 = mfspr(SPR_PMC5);
+
+ /* TCG and POWER9 do not count instructions around faults correctly */
+ report_kfail(true, pmc5_1 + 20 == pmc5_2,
+ "PMC5 counts instructions with illegal instruction");
+
+ handle_exception(0x700, NULL, NULL);
+ handle_exception(0xe40, NULL, NULL);
+}
+
+static void test_pmc5_with_fault(void)
+{
+ unsigned long pmc5_1, pmc5_2;
+ unsigned long tmp;
+
+ setup_vm();
+
+ handle_exception(0x300, &fault_handler, NULL);
+ handle_exception(0x380, &fault_handler, NULL);
+
+ reset_mmcr0();
+ mtspr(SPR_PMC5, 0);
+ mtspr(SPR_MMCR0, mfspr(SPR_MMCR0) & ~(MMCR0_FC | MMCR0_FC56));
+ asm volatile("ld %0,0(%1)" : "=r"(tmp) : "r"(NULL) : "memory");
+ mtspr(SPR_MMCR0, mfspr(SPR_MMCR0) | (MMCR0_FC | MMCR0_FC56));
+ assert(got_interrupt);
+ got_interrupt = false;
+ pmc5_1 = mfspr(SPR_PMC5);
+
+ reset_mmcr0();
+ mtspr(SPR_PMC5, 0);
+ mtspr(SPR_MMCR0, mfspr(SPR_MMCR0) & ~(MMCR0_FC | MMCR0_FC56));
+ asm volatile(".rep 10 ; nop ; .endr ; ld %0,0(%1) ; .rep 10 ; nop ; .endr " : "=r"(tmp) : "r"(NULL) : "memory");
+ mtspr(SPR_MMCR0, mfspr(SPR_MMCR0) | (MMCR0_FC | MMCR0_FC56));
+ assert(got_interrupt);
+ got_interrupt = false;
+ pmc5_2 = mfspr(SPR_PMC5);
+
+ /* TCG and POWER9 do not count instructions around faults correctly */
+ report_kfail(true, pmc5_1 + 20 == pmc5_2, "PMC5 counts instructions with fault");
+
+ handle_exception(0x300, NULL, NULL);
+ handle_exception(0x380, NULL, NULL);
+}
+
+static void test_pmc5_with_sc(void)
+{
+ unsigned long pmc5_1, pmc5_2;
+
+ handle_exception(0xc00, &sc_handler, NULL);
+
+ reset_mmcr0();
+ mtspr(SPR_PMC5, 0);
+ mtspr(SPR_MMCR0, mfspr(SPR_MMCR0) & ~(MMCR0_FC | MMCR0_FC56));
+ asm volatile("sc 0" ::: "memory");
+ mtspr(SPR_MMCR0, mfspr(SPR_MMCR0) | (MMCR0_FC | MMCR0_FC56));
+ assert(got_interrupt);
+ got_interrupt = false;
+ pmc5_1 = mfspr(SPR_PMC5);
+
+ reset_mmcr0();
+ mtspr(SPR_PMC5, 0);
+ mtspr(SPR_MMCR0, mfspr(SPR_MMCR0) & ~(MMCR0_FC | MMCR0_FC56));
+ asm volatile(".rep 10 ; nop ; .endr ; sc 0 ; .rep 10 ; nop ; .endr" ::: "memory");
+ mtspr(SPR_MMCR0, mfspr(SPR_MMCR0) | (MMCR0_FC | MMCR0_FC56));
+ assert(got_interrupt);
+ got_interrupt = false;
+ pmc5_2 = mfspr(SPR_PMC5);
+
+ /* TCG does not count instructions around syscalls correctly */
+ report_kfail(host_is_tcg, pmc5_1 + 20 == pmc5_2,
+ "PMC5 counts instructions with syscall");
+
+ handle_exception(0xc00, NULL, NULL);
+}
+
+extern char next_insn[];
+
+static void test_pmc5_with_rfid(void)
+{
+ unsigned long pmc5;
+ unsigned long mmcr;
+
+ mtspr(SPR_SRR0, (unsigned long)next_insn);
+ mtspr(SPR_SRR1, mfmsr());
+ reset_mmcr0();
+ mmcr = mfspr(SPR_MMCR0);
+ mtspr(SPR_PMC5, 0);
+ mtspr(SPR_MMCR0, mmcr & ~(MMCR0_FC | MMCR0_FC56));
+ asm volatile("rfid ; trap ; .global next_insn ; next_insn: " ::: "memory");
+ mtspr(SPR_MMCR0, mmcr);
+ pmc5 = mfspr(SPR_PMC5);
+
+ /* TCG does not count instructions around syscalls correctly */
+ report_kfail(host_is_tcg, pmc5 == 2,
+ "PMC5 counts instructions with rfid %ld", pmc5);
+}
+
+static void test_pmc5_with_ldat(void)
+{
+ unsigned long pmc5_1, pmc5_2;
+ register unsigned long r4 asm("r4");
+ register unsigned long r5 asm("r5");
+ register unsigned long r6 asm("r6");
+ uint64_t val;
+
+ reset_mmcr0();
+ mtspr(SPR_PMC5, 0);
+ mtspr(SPR_MMCR0, mfspr(SPR_MMCR0) & ~(MMCR0_FC | MMCR0_FC56));
+ asm volatile(".rep 20 ; nop ; .endr" ::: "memory");
+ mtspr(SPR_MMCR0, mfspr(SPR_MMCR0) | (MMCR0_FC | MMCR0_FC56));
+ pmc5_1 = mfspr(SPR_PMC5);
+
+ val = 0xdeadbeef;
+ r4 = 0;
+ r5 = 0xdeadbeef;
+ r6 = 100;
+ reset_mmcr0();
+ mtspr(SPR_PMC5, 0);
+ mtspr(SPR_MMCR0, mfspr(SPR_MMCR0) & ~(MMCR0_FC | MMCR0_FC56));
+ asm volatile(".rep 10 ; nop ; .endr ; "
+ "ldat %0,%3,0x10 ; "
+ ".rep 10 ; nop ; .endr"
+ : "=r"(r4), "+r"(r5), "+r"(r6)
+ : "r"(&val)
+ : "memory");
+ mtspr(SPR_MMCR0, mfspr(SPR_MMCR0) | (MMCR0_FC | MMCR0_FC56));
+ pmc5_2 = mfspr(SPR_PMC5);
+ assert(r4 == 0xdeadbeef);
+ assert(val == 0xdeadbeef);
+
+ /* TCG does not count instructions around syscalls correctly */
+ report_kfail(host_is_tcg, pmc5_1 != pmc5_2 + 1,
+ "PMC5 counts instructions with ldat");
+}
+
+static void test_pmc56(void)
+{
+ unsigned long tmp;
+
+ report_prefix_push("pmc56");
+
+ reset_mmcr0();
+ mtspr(SPR_PMC5, 0);
+ mtspr(SPR_PMC6, 0);
+ report(mfspr(SPR_PMC5) == 0, "PMC5 zeroed");
+ report(mfspr(SPR_PMC6) == 0, "PMC6 zeroed");
+ mtspr(SPR_MMCR0, mfspr(SPR_MMCR0) & ~MMCR0_FC);
+ msleep(100);
+ report(mfspr(SPR_PMC5) == 0, "PMC5 frozen");
+ report(mfspr(SPR_PMC6) == 0, "PMC6 frozen");
+ mtspr(SPR_MMCR0, mfspr(SPR_MMCR0) & ~MMCR0_FC56);
+ mdelay(100);
+ mtspr(SPR_MMCR0, mfspr(SPR_MMCR0) | (MMCR0_FC | MMCR0_FC56));
+ report(mfspr(SPR_PMC5) != 0, "PMC5 counting");
+ report(mfspr(SPR_PMC6) != 0, "PMC6 counting");
+
+ /* Dynamic frequency scaling could cause to be out, so don't fail. */
+ tmp = mfspr(SPR_PMC6);
+ report(true, "PMC6 ratio to reported clock frequency is %ld%%",
+ tmp * 1000 / cpu_hz);
+
+ tmp = pmc5_count_nr_insns(100);
+ tmp = pmc5_count_nr_insns(1000) - tmp;
+ report(tmp == 900, "PMC5 counts instructions precisely %ld", tmp);
+
+ test_pmc5();
+ test_pmc5_with_branch();
+ test_pmc5_with_cond_branch();
+ test_pmc5_with_ill();
+ test_pmc5_with_fault();
+ test_pmc5_with_sc();
+ test_pmc5_with_rfid();
+ test_pmc5_with_ldat();
+
+ report_prefix_pop();
+}
+
+static void dec_ignore_handler(struct pt_regs *regs, void *data)
+{
+ mtspr(SPR_DEC, 0x7fffffff);
+}
+
+static void pmi_handler(struct pt_regs *regs, void *data)
+{
+ got_interrupt = true;
+ memcpy((void *)&recorded_regs, regs, sizeof(struct pt_regs));
+ recorded_mmcr0 = mfspr(SPR_MMCR0);
+ if (mfspr(SPR_MMCR0) & MMCR0_PMAO) {
+ /* This may cause infinite interrupts, so clear it. */
+ mtspr(SPR_MMCR0, mfspr(SPR_MMCR0) & ~MMCR0_PMAO);
+ }
+}
+
+static void test_pmi(void)
+{
+ report_prefix_push("pmi");
+ handle_exception(0x900, &dec_ignore_handler, NULL);
+ handle_exception(0xf00, &pmi_handler, NULL);
+ reset_mmcr0();
+ mtspr(SPR_MMCR0, mfspr(SPR_MMCR0) | MMCR0_PMAO);
+ mtmsr(mfmsr() | MSR_EE);
+ mtmsr(mfmsr() & ~MSR_EE);
+ report(got_interrupt, "PMAO caused interrupt");
+ got_interrupt = false;
+ handle_exception(0xf00, NULL, NULL);
+ handle_exception(0x900, NULL, NULL);
+ report_prefix_pop();
+}
+
+static void clrbhrb(void)
+{
+ asm volatile("clrbhrb" ::: "memory");
+}
+
+static inline unsigned long mfbhrbe(int nr)
+{
+ unsigned long e;
+
+ asm volatile("mfbhrbe %0,%1" : "=r"(e) : "i"(nr) : "memory");
+
+ return e;
+}
+
+extern unsigned char dummy_branch_1[];
+extern unsigned char dummy_branch_2[];
+
+static __attribute__((__noinline__)) void bhrb_dummy(int i)
+{
+ asm volatile(
+ " cmpdi %0,1 \n\t"
+ " beq 1f \n\t"
+ ".global dummy_branch_1 \n\t"
+ "dummy_branch_1: \n\t"
+ " b 2f \n\t"
+ "1: trap \n\t"
+ ".global dummy_branch_2 \n\t"
+ "dummy_branch_2: \n\t"
+ "2: bne 3f \n\t"
+ " trap \n\t"
+ "3: nop \n\t"
+ : : "r"(i));
+}
+
+#define NR_BHRBE 16
+static unsigned long bhrbe[NR_BHRBE];
+static int nr_bhrbe;
+
+static void run_and_load_bhrb(void)
+{
+ int i;
+
+ mtspr(SPR_MMCR0, mfspr(SPR_MMCR0) & ~MMCR0_PMAE);
+ clrbhrb();
+ mtspr(SPR_MMCR0, mfspr(SPR_MMCR0) | MMCR0_BHRBA);
+ mtspr(SPR_MMCR0, mfspr(SPR_MMCR0) & ~(MMCR0_FC | MMCR0_FCP | MMCR0_FCPC));
+ mtspr(SPR_MMCRA, mfspr(SPR_MMCRA) & ~(MMCRA_BHRBRD | MMCRA_IFM_MASK));
+
+ if (cpu_has_p10_bhrb) {
+ mtspr(SPR_MMCR0, mfspr(SPR_MMCR0) | MMCR0_PMAE);
+ asm volatile("isync" ::: "memory");
+ enter_usermode();
+ bhrb_dummy(0);
+ exit_usermode();
+ mtspr(SPR_MMCR0, mfspr(SPR_MMCR0) & ~MMCR0_PMAE);
+ asm volatile("isync" ::: "memory");
+ } else {
+ mtspr(SPR_MMCR0, mfspr(SPR_MMCR0) | MMCR0_PMAE);
+ asm volatile("isync" ::: "memory");
+ mtmsr(mfmsr());
+ asm volatile(".rept 100 ; nop ; .endr");
+ bhrb_dummy(0);
+ mtspr(SPR_MMCR0, mfspr(SPR_MMCR0) & ~MMCR0_PMAE);
+ asm volatile("isync" ::: "memory");
+ }
+
+ bhrbe[0] = mfbhrbe(0);
+ bhrbe[1] = mfbhrbe(1);
+ bhrbe[2] = mfbhrbe(2);
+ bhrbe[3] = mfbhrbe(3);
+ bhrbe[4] = mfbhrbe(4);
+ bhrbe[5] = mfbhrbe(5);
+ bhrbe[6] = mfbhrbe(6);
+ bhrbe[7] = mfbhrbe(7);
+ bhrbe[8] = mfbhrbe(8);
+ bhrbe[9] = mfbhrbe(9);
+ bhrbe[10] = mfbhrbe(10);
+ bhrbe[11] = mfbhrbe(11);
+ bhrbe[12] = mfbhrbe(12);
+ bhrbe[13] = mfbhrbe(13);
+ bhrbe[14] = mfbhrbe(14);
+ bhrbe[15] = mfbhrbe(15);
+
+ for (i = 0; i < NR_BHRBE; i++) {
+ bhrbe[i] &= ~0x1UL; /* remove prediction bit */
+ if (!bhrbe[i])
+ break;
+ }
+ nr_bhrbe = i;
+}
+
+static void test_bhrb(void)
+{
+ int i;
+
+ if (cpu_has_p10_bhrb && !vm_available())
+ return;
+
+ report_prefix_push("bhrb");
+
+ /* TCG doesn't impelment BHRB yet */
+ handle_exception(0x700, &illegal_handler, NULL);
+ handle_exception(0xe40, &illegal_handler, NULL);
+ clrbhrb();
+ handle_exception(0x700, NULL, NULL);
+ handle_exception(0xe40, NULL, NULL);
+ if (got_interrupt) {
+ got_interrupt = false;
+ report_skip("BHRB support missing");
+ report_prefix_pop();
+ return;
+ }
+
+ if (vm_available()) {
+ handle_exception(0x900, &dec_ignore_handler, NULL);
+ setup_vm();
+ }
+ reset_mmcr0();
+ clrbhrb();
+ if (cpu_has_p10_bhrb) {
+ enter_usermode();
+ bhrb_dummy(0);
+ exit_usermode();
+ } else {
+ bhrb_dummy(0);
+ }
+ report(mfbhrbe(0) == 0, "BHRB is frozen");
+
+ /*
+ * BHRB may be cleared at any time (e.g., by OS or hypervisor)
+ * so this test could be occasionally incorrect. Try several
+ * times before giving up...
+ */
+
+ if (cpu_has_p10_bhrb) {
+ /*
+ * BHRB should have 8 entries:
+ * 1. enter_usermode blr
+ * 2. enter_usermode blr target
+ * 3. bl dummy
+ * 4. dummy unconditional
+ * 5. dummy conditional
+ * 6. dummy blr
+ * 7. dummy blr target
+ * 8. exit_usermode bl
+ *
+ * POWER10 often gives 4 entries, if other threads are
+ * running on the core, it seems to struggle.
+ */
+ for (i = 0; i < 200; i++) {
+ run_and_load_bhrb();
+ if (nr_bhrbe == 8)
+ break;
+ if (i > 100 && nr_bhrbe == 4)
+ break;
+ }
+ report(nr_bhrbe, "BHRB has been written");
+ report_kfail(!host_is_tcg, nr_bhrbe == 8,
+ "BHRB has written 8 entries");
+ if (nr_bhrbe == 8) {
+ report(bhrbe[4] == (unsigned long)dummy_branch_1,
+ "correct unconditional branch address");
+ report(bhrbe[3] == (unsigned long)dummy_branch_2,
+ "correct conditional branch address");
+ } else if (nr_bhrbe == 4) {
+ /* POWER10 workaround */
+ report(nr_bhrbe == 4, "BHRB has written 4 entries");
+ report(bhrbe[3] == (unsigned long)dummy_branch_2,
+ "correct conditional branch address");
+ }
+ } else {
+ /*
+ * BHRB should have 6 entries:
+ * 1. bl dummy
+ * 2. dummy unconditional
+ * 3. dummy conditional
+ * 4. dummy blr
+ * 5. dummy blr target
+ * 6. Final b loop before disabled.
+ *
+ * POWER9 often gives 4 entries, if other threads are
+ * running on the core, it seems to struggle.
+ */
+ for (i = 0; i < 200; i++) {
+ run_and_load_bhrb();
+ if (nr_bhrbe == 6)
+ break;
+ if (i > 100 && nr_bhrbe == 4)
+ break;
+ }
+ report(nr_bhrbe, "BHRB has been written");
+ report_kfail(!host_is_tcg, nr_bhrbe == 6,
+ "BHRB has written 6 entries");
+ if (nr_bhrbe == 6) {
+ report(bhrbe[4] == (unsigned long)dummy_branch_1,
+ "correct unconditional branch address");
+ report(bhrbe[3] == (unsigned long)dummy_branch_2,
+ "correct conditional branch address");
+ } else if (nr_bhrbe == 4) {
+ /* POWER9 workaround */
+ report(nr_bhrbe == 4, "BHRB has written 4 entries");
+ report(bhrbe[3] == (unsigned long)dummy_branch_2,
+ "correct conditional branch address");
+ }
+ }
+
+ handle_exception(0x900, NULL, NULL);
+
+ report_prefix_pop();
+}
+
+int main(int argc, char **argv)
+{
+ report_prefix_push("pmu");
+
+ test_pmc56();
+ test_pmi();
+ if (cpu_has_bhrb)
+ test_bhrb();
+
+ report_prefix_pop();
+
+ return report_summary();
+}
diff --git a/powerpc/unittests.cfg b/powerpc/unittests.cfg
index 2dd32edf..60c73086 100644
--- a/powerpc/unittests.cfg
+++ b/powerpc/unittests.cfg
@@ -75,6 +75,9 @@ file = interrupts.elf
file = mmu.elf
smp = 2
+[pmu]
+file = pmu.elf
+
[smp]
file = smp.elf
smp = 2
--
2.53.0
^ permalink raw reply related
* [kvm-unit-tests PATCH 0/6] powerpc improvements
From: Chinmay Rath @ 2026-07-08 10:51 UTC (permalink / raw)
To: thuth
Cc: npiggin, harshpb, lvivier, linuxppc-dev, kvm, andrew.jones, sbhat,
Chinmay Rath
This series aims to add a couple of new powerpc tests and improve the
powerpc build structure.
This is originally Nick's work. The last version (v10) of which can be seen here :
https://lore.kernel.org/linuxppc-dev/20240612052322.218726-1-npiggin@gmail.com/
Couple of patches from the series are already merged.
Since it has been 2 years since this series was posted, I originally
posted this as a RFC. This v1 series has changes accomodating the review comments
received in the RFC :
https://lore.kernel.org/kvm/20260602064806.3101025-1-rathc@linux.ibm.com/
I have rebased the patches to the upstream state.
For the patches which did not require any changes in the existing upstream code,
I have retained the "Reviewed-by"s and "Acked-by" (patch 3,5 & 6) from
Nick's series. I have also added Andrew's "Reviewed-by" received on
patch 2 in the RFC. Nick had originally introduced powernv tests as well.
Removed it for now since it was causing CI failure in the current upstream.
Link to Gitlab tree with patches :
https://gitlab.com/rathc/kvm-unit-tests/-/tree/ppc64
Link to Gitlab pipeline :
https://gitlab.com/rathc/kvm-unit-tests/-/pipelines/2661271889
Change log from RFC :
1. Patch 2: Added Andrew's "Reviewed-by".
2. Patch 4: Removed usage of gitlab-ci group to run test - Thomas
It would be nice to make use of the gitlab-ci group, but doing the
change of all archs would make sense in a separate series. I look
forward to doing that.
3. Patch 6: Removed addition of panic test in gitlab-ci group - Thomas
There was a discussion on the build failing in Travis CI with Clang, in the
RFC, which I have addressed there.
Nicholas Piggin (6):
powerpc: add pmu tests
configure: Make arch_libdir a first-class entity
powerpc: Remove remnants of ppc64 directory and build structure
powerpc: gitlab CI update
scripts/arch-run.bash: Fix run_panic() success exit status
powerpc: Add a panic test
.gitlab-ci.yml | 21 +-
MAINTAINERS | 1 -
Makefile | 2 +-
configure | 21 +-
lib/{ppc64 => powerpc}/asm-offsets.c | 0
lib/{ppc64 => powerpc}/asm/asm-offsets.h | 0
lib/{ppc64 => powerpc}/asm/atomic.h | 0
lib/{ppc64 => powerpc}/asm/barrier.h | 4 +-
lib/{ppc64 => powerpc}/asm/bitops.h | 4 +-
lib/{ppc64 => powerpc}/asm/io.h | 4 +-
lib/{ppc64 => powerpc}/asm/mmu.h | 0
lib/{ppc64 => powerpc}/asm/opal.h | 4 +-
lib/{ppc64 => powerpc}/asm/page.h | 6 +-
lib/{ppc64 => powerpc}/asm/pgtable-hwdef.h | 6 +-
lib/{ppc64 => powerpc}/asm/pgtable.h | 2 +-
lib/powerpc/asm/processor.h | 2 +
lib/{ppc64 => powerpc}/asm/ptrace.h | 6 +-
lib/powerpc/asm/reg.h | 9 +
lib/powerpc/asm/rtas.h | 1 +
lib/powerpc/asm/setup.h | 1 +
lib/powerpc/asm/spinlock.h | 6 +
lib/powerpc/asm/stack.h | 3 +
lib/{ppc64 => powerpc}/asm/vpa.h | 0
lib/{ppc64 => powerpc}/mmu.c | 0
lib/{ppc64 => powerpc}/opal-calls.S | 0
lib/{ppc64 => powerpc}/opal.c | 0
lib/powerpc/rtas.c | 16 +
lib/powerpc/setup.c | 20 +
lib/{ppc64 => powerpc}/stack.c | 0
lib/ppc64/.gitignore | 1 -
lib/ppc64/asm/handlers.h | 1 -
lib/ppc64/asm/hcall.h | 1 -
lib/ppc64/asm/memory_areas.h | 6 -
lib/ppc64/asm/ppc_asm.h | 1 -
lib/ppc64/asm/processor.h | 1 -
lib/ppc64/asm/reg.h | 1 -
lib/ppc64/asm/rtas.h | 1 -
lib/ppc64/asm/setup.h | 1 -
lib/ppc64/asm/smp.h | 1 -
lib/ppc64/asm/spinlock.h | 6 -
lib/ppc64/asm/stack.h | 11 -
lib/ppc64/asm/time.h | 1 -
powerpc/Makefile | 111 +++-
powerpc/Makefile.common | 94 ----
powerpc/Makefile.ppc64 | 31 --
powerpc/pmu.c | 567 +++++++++++++++++++++
powerpc/run | 2 +-
powerpc/selftest.c | 17 +-
powerpc/unittests.cfg | 17 +-
scripts/arch-run.bash | 1 +
50 files changed, 817 insertions(+), 195 deletions(-)
rename lib/{ppc64 => powerpc}/asm-offsets.c (100%)
rename lib/{ppc64 => powerpc}/asm/asm-offsets.h (100%)
rename lib/{ppc64 => powerpc}/asm/atomic.h (100%)
rename lib/{ppc64 => powerpc}/asm/barrier.h (83%)
rename lib/{ppc64 => powerpc}/asm/bitops.h (69%)
rename lib/{ppc64 => powerpc}/asm/io.h (50%)
rename lib/{ppc64 => powerpc}/asm/mmu.h (100%)
rename lib/{ppc64 => powerpc}/asm/opal.h (90%)
rename lib/{ppc64 => powerpc}/asm/page.h (94%)
rename lib/{ppc64 => powerpc}/asm/pgtable-hwdef.h (93%)
rename lib/{ppc64 => powerpc}/asm/pgtable.h (99%)
rename lib/{ppc64 => powerpc}/asm/ptrace.h (89%)
create mode 100644 lib/powerpc/asm/spinlock.h
rename lib/{ppc64 => powerpc}/asm/vpa.h (100%)
rename lib/{ppc64 => powerpc}/mmu.c (100%)
rename lib/{ppc64 => powerpc}/opal-calls.S (100%)
rename lib/{ppc64 => powerpc}/opal.c (100%)
rename lib/{ppc64 => powerpc}/stack.c (100%)
delete mode 100644 lib/ppc64/.gitignore
delete mode 100644 lib/ppc64/asm/handlers.h
delete mode 100644 lib/ppc64/asm/hcall.h
delete mode 100644 lib/ppc64/asm/memory_areas.h
delete mode 100644 lib/ppc64/asm/ppc_asm.h
delete mode 100644 lib/ppc64/asm/processor.h
delete mode 100644 lib/ppc64/asm/reg.h
delete mode 100644 lib/ppc64/asm/rtas.h
delete mode 100644 lib/ppc64/asm/setup.h
delete mode 100644 lib/ppc64/asm/smp.h
delete mode 100644 lib/ppc64/asm/spinlock.h
delete mode 100644 lib/ppc64/asm/stack.h
delete mode 100644 lib/ppc64/asm/time.h
delete mode 100644 powerpc/Makefile.common
delete mode 100644 powerpc/Makefile.ppc64
create mode 100644 powerpc/pmu.c
--
2.53.0
^ permalink raw reply
* [PATCH v2 10/10] soc: fsl: qe: Add support of IRQs in QE GPIO
From: Paul Louvel @ 2026-07-08 10:15 UTC (permalink / raw)
To: Qiang Zhao, Christophe Leroy (CS GROUP), Thomas Gleixner,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Linus Walleij,
Bartosz Golaszewski, Madhavan Srinivasan, Michael Ellerman,
Nicholas Piggin
Cc: linuxppc-dev, linux-arm-kernel, linux-kernel, devicetree,
linux-gpio, Paul Louvel, Herve Codina
In-Reply-To: <20260708-qe-pic-gpios-v2-0-1972044cfbd1@bootlin.com>
Some QE GPIO pins have an associated interrupt line in the QE PIC to
signal state changes on the pin.
Because the GPIO controller does not perform any interrupt handling
itself, a nexus node (interrupt-map) is used to map each GPIO line
supporting IRQ to the parent QE PIC interrupt domain.
Add the to_irq() method in the corresponding GPIO controller driver,
that uses the nexus node to perform the translation.
Signed-off-by: Paul Louvel <paul.louvel@bootlin.com>
---
drivers/soc/fsl/qe/gpio.c | 28 +++++++++++++++++++++++++++-
1 file changed, 27 insertions(+), 1 deletion(-)
diff --git a/drivers/soc/fsl/qe/gpio.c b/drivers/soc/fsl/qe/gpio.c
index 66828f2a3577..f8919642f40d 100644
--- a/drivers/soc/fsl/qe/gpio.c
+++ b/drivers/soc/fsl/qe/gpio.c
@@ -16,6 +16,7 @@
#include <linux/gpio/driver.h>
#include <linux/slab.h>
#include <linux/export.h>
+#include <linux/of_irq.h>
#include <linux/platform_device.h>
#include <soc/fsl/qe/qe.h>
@@ -23,6 +24,7 @@
#define PIN_MASK(gpio) (1UL << (QE_PIO_PINS - 1 - (gpio)))
struct qe_gpio_chip {
+ struct device_node *np;
struct gpio_chip gc;
void __iomem *regs;
spinlock_t lock;
@@ -135,6 +137,29 @@ static int qe_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
return 0;
}
+static int qe_gpio_to_irq(struct gpio_chip *gc, unsigned int gpio)
+{
+ struct qe_gpio_chip *qe_gc = gpiochip_get_data(gc);
+ struct of_phandle_args oirq;
+ struct irq_domain *domain;
+ int ret;
+
+ oirq.np = qe_gc->np;
+ oirq.args_count = 2;
+ oirq.args[0] = gpio;
+ oirq.args[1] = 0;
+
+ ret = of_irq_parse_raw(NULL, &oirq);
+ if (ret)
+ return ret;
+
+ domain = irq_find_host(oirq.np);
+ if (!domain)
+ return -EPROBE_DEFER;
+
+ return irq_create_of_mapping(&oirq);
+}
+
struct qe_pin {
/*
* The qe_gpio_chip name is unfortunate, we should change that to
@@ -299,7 +324,7 @@ static int qe_gpio_probe(struct platform_device *ofdev)
qe_gc = devm_kzalloc(dev, sizeof(*qe_gc), GFP_KERNEL);
if (!qe_gc)
return -ENOMEM;
-
+ qe_gc->np = np;
spin_lock_init(&qe_gc->lock);
gc = &qe_gc->gc;
@@ -311,6 +336,7 @@ static int qe_gpio_probe(struct platform_device *ofdev)
gc->get = qe_gpio_get;
gc->set = qe_gpio_set;
gc->set_multiple = qe_gpio_set_multiple;
+ gc->to_irq = qe_gpio_to_irq;
gc->parent = dev;
gc->owner = THIS_MODULE;
--
2.55.0
^ permalink raw reply related
* [PATCH v2 09/10] soc: fsl: qe: Rename irq variable to parent_irq
From: Paul Louvel @ 2026-07-08 10:15 UTC (permalink / raw)
To: Qiang Zhao, Christophe Leroy (CS GROUP), Thomas Gleixner,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Linus Walleij,
Bartosz Golaszewski, Madhavan Srinivasan, Michael Ellerman,
Nicholas Piggin
Cc: linuxppc-dev, linux-arm-kernel, linux-kernel, devicetree,
linux-gpio, Paul Louvel, Herve Codina
In-Reply-To: <20260708-qe-pic-gpios-v2-0-1972044cfbd1@bootlin.com>
Rename the local variable holding the platform IRQ to parent_irq, which
better describes its role as the upstream/chained interrupt in the
hierarchy.
Signed-off-by: Paul Louvel <paul.louvel@bootlin.com>
---
drivers/soc/fsl/qe/qe_ports_ic.c | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/drivers/soc/fsl/qe/qe_ports_ic.c b/drivers/soc/fsl/qe/qe_ports_ic.c
index 4f6b75439f9f..7375f92f528b 100644
--- a/drivers/soc/fsl/qe/qe_ports_ic.c
+++ b/drivers/soc/fsl/qe/qe_ports_ic.c
@@ -18,7 +18,7 @@
struct qepic_data {
void __iomem *reg;
- int irq;
+ int parent_irq;
};
static void qepic_mask(struct irq_data *d)
@@ -117,7 +117,7 @@ static int qepic_domain_init(struct irq_domain *d)
{
struct qepic_data *data = d->host_data;
- irq_set_chained_handler_and_data(data->irq, qepic_cascade, d);
+ irq_set_chained_handler_and_data(data->parent_irq, qepic_cascade, d);
return 0;
}
@@ -126,7 +126,7 @@ static void qepic_domain_exit(struct irq_domain *d)
{
struct qepic_data *data = d->host_data;
- irq_set_chained_handler_and_data(data->irq, NULL, NULL);
+ irq_set_chained_handler_and_data(data->parent_irq, NULL, NULL);
}
static int qepic_probe(struct platform_device *pdev)
@@ -161,9 +161,9 @@ static int qepic_probe(struct platform_device *pdev)
if (IS_ERR(data->reg))
return PTR_ERR(data->reg);
- data->irq = platform_get_irq(pdev, 0);
- if (data->irq < 0)
- return data->irq;
+ data->parent_irq = platform_get_irq(pdev, 0);
+ if (data->parent_irq < 0)
+ return data->parent_irq;
domain = devm_irq_domain_instantiate(dev, &d_info);
if (IS_ERR(domain))
--
2.55.0
^ permalink raw reply related
* [PATCH v2 08/10] soc: fsl: qe: Convert to generic IRQ chip
From: Paul Louvel @ 2026-07-08 10:15 UTC (permalink / raw)
To: Qiang Zhao, Christophe Leroy (CS GROUP), Thomas Gleixner,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Linus Walleij,
Bartosz Golaszewski, Madhavan Srinivasan, Michael Ellerman,
Nicholas Piggin
Cc: linuxppc-dev, linux-arm-kernel, linux-kernel, devicetree,
linux-gpio, Paul Louvel, Herve Codina
In-Reply-To: <20260708-qe-pic-gpios-v2-0-1972044cfbd1@bootlin.com>
The generic IRQ chip framework is available to handle IRQ chips. Using
this framework for the QE interrupt controller allows to simplify the
driver. Indeed, the framework internally handles operations coded
directly in the driver.
Signed-off-by: Paul Louvel <paul.louvel@bootlin.com>
---
drivers/soc/fsl/qe/Kconfig | 1 +
drivers/soc/fsl/qe/qe_ports_ic.c | 116 +++++++++++++++++++++++++--------------
2 files changed, 76 insertions(+), 41 deletions(-)
diff --git a/drivers/soc/fsl/qe/Kconfig b/drivers/soc/fsl/qe/Kconfig
index b35a8fd30ebf..87cd1662e168 100644
--- a/drivers/soc/fsl/qe/Kconfig
+++ b/drivers/soc/fsl/qe/Kconfig
@@ -71,6 +71,7 @@ config QE_USB
config QE_GPIO
bool "QE GPIO support"
depends on QUICC_ENGINE
+ select GENERIC_IRQ_CHIP
select GPIOLIB
help
Say Y here if you're going to use hardware that connects to the
diff --git a/drivers/soc/fsl/qe/qe_ports_ic.c b/drivers/soc/fsl/qe/qe_ports_ic.c
index 29f4334db5a0..4f6b75439f9f 100644
--- a/drivers/soc/fsl/qe/qe_ports_ic.c
+++ b/drivers/soc/fsl/qe/qe_ports_ic.c
@@ -18,107 +18,144 @@
struct qepic_data {
void __iomem *reg;
- struct irq_domain *host;
int irq;
};
static void qepic_mask(struct irq_data *d)
{
- struct qepic_data *data = irq_data_get_irq_chip_data(d);
- u32 val = ioread32be(data->reg + CEPIMR);
+ struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
+ u32 val;
- iowrite32be(val & ~(1 << (31 - irqd_to_hwirq(d))), data->reg + CEPIMR);
+ guard(raw_spinlock)(&gc->lock);
+
+ val = ioread32be(gc->reg_base + CEPIMR);
+ iowrite32be(val & ~d->mask, gc->reg_base + CEPIMR);
}
static void qepic_unmask(struct irq_data *d)
{
- struct qepic_data *data = irq_data_get_irq_chip_data(d);
- u32 val = ioread32be(data->reg + CEPIMR);
+ struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
+ u32 val;
+
+ guard(raw_spinlock)(&gc->lock);
- iowrite32be(val | 1 << (31 - irqd_to_hwirq(d)), data->reg + CEPIMR);
+ val = ioread32be(gc->reg_base + CEPIMR);
+ iowrite32be(val | d->mask, gc->reg_base + CEPIMR);
}
static void qepic_end(struct irq_data *d)
{
- struct qepic_data *data = irq_data_get_irq_chip_data(d);
+ struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
- iowrite32be(1 << (31 - irqd_to_hwirq(d)), data->reg + CEPIER);
+ iowrite32be(d->mask, gc->reg_base + CEPIER);
+}
+
+static void qepic_calc_mask(struct irq_data *d)
+{
+ d->mask = 1 << (31 - irqd_to_hwirq(d));
}
static int qepic_set_type(struct irq_data *d, unsigned int flow_type)
{
- struct qepic_data *data = irq_data_get_irq_chip_data(d);
- unsigned int vec = (unsigned int)irqd_to_hwirq(d);
- u32 val = ioread32be(data->reg + CEPICR);
+ struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
+ u32 val;
+ guard(raw_spinlock)(&gc->lock);
+
+ val = ioread32be(gc->reg_base + CEPICR);
switch (flow_type & IRQ_TYPE_SENSE_MASK) {
case IRQ_TYPE_EDGE_FALLING:
- iowrite32be(val | 1 << (31 - vec), data->reg + CEPICR);
+ iowrite32be(val | d->mask, gc->reg_base + CEPICR);
return 0;
case IRQ_TYPE_EDGE_BOTH:
case IRQ_TYPE_NONE:
- iowrite32be(val & ~(1 << (31 - vec)), data->reg + CEPICR);
+ iowrite32be(val & ~d->mask, gc->reg_base + CEPICR);
return 0;
}
return -EINVAL;
}
-static struct irq_chip qepic = {
- .name = "QEPIC",
- .irq_mask = qepic_mask,
- .irq_unmask = qepic_unmask,
- .irq_eoi = qepic_end,
- .irq_set_type = qepic_set_type,
-};
-
static void qepic_cascade(struct irq_desc *desc)
{
- struct qepic_data *data = irq_desc_get_handler_data(desc);
+ struct irq_domain *domain = irq_desc_get_handler_data(desc);
+ struct irq_chip_generic *gc = irq_get_domain_generic_chip(domain, 0);
struct irq_chip *chip = irq_desc_get_chip(desc);
unsigned long event, bit;
chained_irq_enter(chip, desc);
- event = ioread32be(data->reg + CEPIER);
+ event = ioread32be(gc->reg_base + CEPIER);
if (!event) {
handle_bad_irq(desc);
goto out;
}
for_each_set_bit(bit, &event, 32)
- generic_handle_domain_irq(data->host, 31 - bit);
+ generic_handle_domain_irq(domain, 31 - bit);
out:
chained_irq_exit(chip, desc);
}
-static int qepic_host_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t hw)
+static int qepic_chip_init(struct irq_chip_generic *gc)
{
- irq_set_chip_data(virq, h->host_data);
- irq_set_chip_and_handler(virq, &qepic, handle_fasteoi_irq);
+ struct qepic_data *data = gc->domain->host_data;
+ struct irq_chip_type *ct = gc->chip_types;
+
+ gc->reg_base = data->reg;
+
+ ct->chip.irq_mask = qepic_mask;
+ ct->chip.irq_unmask = qepic_unmask;
+ ct->chip.irq_eoi = qepic_end;
+ ct->chip.irq_set_type = qepic_set_type;
+ ct->chip.irq_calc_mask = qepic_calc_mask;
+
return 0;
}
-static const struct irq_domain_ops qepic_host_ops = {
- .map = qepic_host_map,
-};
+static int qepic_domain_init(struct irq_domain *d)
+{
+ struct qepic_data *data = d->host_data;
+
+ irq_set_chained_handler_and_data(data->irq, qepic_cascade, d);
+
+ return 0;
+}
-static void qepic_remove(void *res)
+static void qepic_domain_exit(struct irq_domain *d)
{
- struct qepic_data *data = res;
+ struct qepic_data *data = d->host_data;
irq_set_chained_handler_and_data(data->irq, NULL, NULL);
- irq_domain_remove(data->host);
}
static int qepic_probe(struct platform_device *pdev)
{
+ struct irq_domain_chip_generic_info dgc_info = {
+ .name = "QEPIC",
+ .handler = handle_fasteoi_irq,
+ .irqs_per_chip = 32,
+ .num_ct = 1,
+ .init = qepic_chip_init,
+ };
+ struct irq_domain_info d_info = {
+ .fwnode = of_fwnode_handle(pdev->dev.of_node),
+ .domain_flags = IRQ_DOMAIN_FLAG_DESTROY_GC,
+ .size = 32,
+ .hwirq_max = 32,
+ .ops = &irq_generic_chip_ops,
+ .dgc_info = &dgc_info,
+ .init = qepic_domain_init,
+ .exit = qepic_domain_exit,
+ };
struct device *dev = &pdev->dev;
+ struct irq_domain *domain;
struct qepic_data *data;
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
+ d_info.host_data = data;
data->reg = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(data->reg))
@@ -128,14 +165,11 @@ static int qepic_probe(struct platform_device *pdev)
if (data->irq < 0)
return data->irq;
- data->host = irq_domain_create_linear(dev_fwnode(dev), 32, &qepic_host_ops, data);
- if (!data->host)
- return -ENODEV;
-
- irq_set_chained_handler_and_data(data->irq, qepic_cascade, data);
-
- return devm_add_action_or_reset(dev, qepic_remove, data);
+ domain = devm_irq_domain_instantiate(dev, &d_info);
+ if (IS_ERR(domain))
+ return PTR_ERR(domain);
+ return 0;
}
static const struct of_device_id qepic_match[] = {
--
2.55.0
^ permalink raw reply related
* [PATCH v2 07/10] soc: fsl: qe: Handle spurious interrupts
From: Paul Louvel @ 2026-07-08 10:15 UTC (permalink / raw)
To: Qiang Zhao, Christophe Leroy (CS GROUP), Thomas Gleixner,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Linus Walleij,
Bartosz Golaszewski, Madhavan Srinivasan, Michael Ellerman,
Nicholas Piggin
Cc: linuxppc-dev, linux-arm-kernel, linux-kernel, devicetree,
linux-gpio, Paul Louvel, Herve Codina
In-Reply-To: <20260708-qe-pic-gpios-v2-0-1972044cfbd1@bootlin.com>
When no interrupt bits are set in the event register, call
handle_bad_irq() to account for the spurious interrupt before
exiting the cascade handler.
Signed-off-by: Paul Louvel <paul.louvel@bootlin.com>
---
drivers/soc/fsl/qe/qe_ports_ic.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/drivers/soc/fsl/qe/qe_ports_ic.c b/drivers/soc/fsl/qe/qe_ports_ic.c
index bc8b68e5d1a9..29f4334db5a0 100644
--- a/drivers/soc/fsl/qe/qe_ports_ic.c
+++ b/drivers/soc/fsl/qe/qe_ports_ic.c
@@ -80,9 +80,15 @@ static void qepic_cascade(struct irq_desc *desc)
chained_irq_enter(chip, desc);
event = ioread32be(data->reg + CEPIER);
+ if (!event) {
+ handle_bad_irq(desc);
+ goto out;
+ }
+
for_each_set_bit(bit, &event, 32)
generic_handle_domain_irq(data->host, 31 - bit);
+out:
chained_irq_exit(chip, desc);
}
--
2.55.0
^ permalink raw reply related
* [PATCH v2 06/10] soc: fsl: qe: Iterate over all pending interrupts in cascade handler
From: Paul Louvel @ 2026-07-08 10:15 UTC (permalink / raw)
To: Qiang Zhao, Christophe Leroy (CS GROUP), Thomas Gleixner,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Linus Walleij,
Bartosz Golaszewski, Madhavan Srinivasan, Michael Ellerman,
Nicholas Piggin
Cc: linuxppc-dev, linux-arm-kernel, linux-kernel, devicetree,
linux-gpio, Paul Louvel, Herve Codina
In-Reply-To: <20260708-qe-pic-gpios-v2-0-1972044cfbd1@bootlin.com>
Instead of only servicing a single interrupt, the chained handler can
handle all IRQs that have their bit set in the event register.
This avoid multiple parent IRQ handler being serviced if more than one
interrupt are pending on the QE PIC.
Remove unused code.
Signed-off-by: Paul Louvel <paul.louvel@bootlin.com>
---
drivers/soc/fsl/qe/qe_ports_ic.c | 17 +++++------------
1 file changed, 5 insertions(+), 12 deletions(-)
diff --git a/drivers/soc/fsl/qe/qe_ports_ic.c b/drivers/soc/fsl/qe/qe_ports_ic.c
index c8fff45e353c..bc8b68e5d1a9 100644
--- a/drivers/soc/fsl/qe/qe_ports_ic.c
+++ b/drivers/soc/fsl/qe/qe_ports_ic.c
@@ -5,6 +5,7 @@
* Copyright (c) 2025 Christophe Leroy CS GROUP France (christophe.leroy@csgroup.eu)
*/
+#include <linux/bitops.h>
#include <linux/irq.h>
#include <linux/irqchip/chained_irq.h>
#include <linux/irqdomain.h>
@@ -70,25 +71,17 @@ static struct irq_chip qepic = {
.irq_set_type = qepic_set_type,
};
-static int qepic_get_irq(struct irq_desc *desc)
-{
- struct qepic_data *data = irq_desc_get_handler_data(desc);
- u32 event = ioread32be(data->reg + CEPIER);
-
- if (!event)
- return -1;
-
- return 32 - ffs(event);
-}
-
static void qepic_cascade(struct irq_desc *desc)
{
struct qepic_data *data = irq_desc_get_handler_data(desc);
struct irq_chip *chip = irq_desc_get_chip(desc);
+ unsigned long event, bit;
chained_irq_enter(chip, desc);
- generic_handle_domain_irq(data->host, qepic_get_irq(desc));
+ event = ioread32be(data->reg + CEPIER);
+ for_each_set_bit(bit, &event, 32)
+ generic_handle_domain_irq(data->host, 31 - bit);
chained_irq_exit(chip, desc);
}
--
2.55.0
^ permalink raw reply related
* [PATCH v2 05/10] soc: fsl: qe: Use generic_handle_domain_irq()
From: Paul Louvel @ 2026-07-08 10:15 UTC (permalink / raw)
To: Qiang Zhao, Christophe Leroy (CS GROUP), Thomas Gleixner,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Linus Walleij,
Bartosz Golaszewski, Madhavan Srinivasan, Michael Ellerman,
Nicholas Piggin
Cc: linuxppc-dev, linux-arm-kernel, linux-kernel, devicetree,
linux-gpio, Paul Louvel, Herve Codina
In-Reply-To: <20260708-qe-pic-gpios-v2-0-1972044cfbd1@bootlin.com>
Replace the irq_find_mapping() + generic_handle_irq() pattern with
generic_handle_domain_irq(), which handles the IRQ domain lookup
internally. This is less error-prone and more idiomatic.
Remove the now-unused irq_find_mapping() call from qepic_get_irq().
Signed-off-by: Paul Louvel <paul.louvel@bootlin.com>
---
drivers/soc/fsl/qe/qe_ports_ic.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/drivers/soc/fsl/qe/qe_ports_ic.c b/drivers/soc/fsl/qe/qe_ports_ic.c
index c3768c82a58c..c8fff45e353c 100644
--- a/drivers/soc/fsl/qe/qe_ports_ic.c
+++ b/drivers/soc/fsl/qe/qe_ports_ic.c
@@ -78,16 +78,17 @@ static int qepic_get_irq(struct irq_desc *desc)
if (!event)
return -1;
- return irq_find_mapping(data->host, 32 - ffs(event));
+ return 32 - ffs(event);
}
static void qepic_cascade(struct irq_desc *desc)
{
+ struct qepic_data *data = irq_desc_get_handler_data(desc);
struct irq_chip *chip = irq_desc_get_chip(desc);
chained_irq_enter(chip, desc);
- generic_handle_irq(qepic_get_irq(desc));
+ generic_handle_domain_irq(data->host, qepic_get_irq(desc));
chained_irq_exit(chip, desc);
}
--
2.55.0
^ permalink raw reply related
* [PATCH v2 04/10] dt-bindings: soc: fsl: qe: Add support of IRQ in QE GPIO
From: Paul Louvel @ 2026-07-08 10:15 UTC (permalink / raw)
To: Qiang Zhao, Christophe Leroy (CS GROUP), Thomas Gleixner,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Linus Walleij,
Bartosz Golaszewski, Madhavan Srinivasan, Michael Ellerman,
Nicholas Piggin
Cc: linuxppc-dev, linux-arm-kernel, linux-kernel, devicetree,
linux-gpio, Paul Louvel, Herve Codina
In-Reply-To: <20260708-qe-pic-gpios-v2-0-1972044cfbd1@bootlin.com>
Some QE GPIO pins have an associated interrupt line in the QE PIC to
signal state changes on the pin. Add the corresponding
interrupt-controller / nexus properties to the QE GPIO binding.
Because the GPIO controller does not perform any interrupt handling
itself, a nexus node (interrupt-map) is used to map each GPIO line
supporting IRQ to the parent QE PIC interrupt domain.
As the QE PIC can be configured to generate an interrupt on either a
high-to-low transition or any change in signal state, three
interrupt-map entries are needed per GPIO pin that can yield an
interrupt (falling, both, and the "none" case which defaults to both in
QE PIC). This overhead is necessary because the interrupt-map-pass-thru
property is not part of the DT specification.
The interrupt-map property is optional: it is not required for GPIO
banks that have no interrupt capable GPIO line (e.g. port D on MPC8323),
or when interrupt functionality is not used.
Update the example to show a scenario where each bank supports a
different numbers of IRQs, or no IRQs at all.
Signed-off-by: Paul Louvel <paul.louvel@bootlin.com>
---
.../bindings/gpio/fsl,mpc8323-qe-pario-bank.yaml | 39 ++++++++++++++++++++++
1 file changed, 39 insertions(+)
diff --git a/Documentation/devicetree/bindings/gpio/fsl,mpc8323-qe-pario-bank.yaml b/Documentation/devicetree/bindings/gpio/fsl,mpc8323-qe-pario-bank.yaml
index 1af99339ff40..1d2ab44fcd3c 100644
--- a/Documentation/devicetree/bindings/gpio/fsl,mpc8323-qe-pario-bank.yaml
+++ b/Documentation/devicetree/bindings/gpio/fsl,mpc8323-qe-pario-bank.yaml
@@ -27,6 +27,17 @@ properties:
"#gpio-cells":
const: 2
+ "#address-cells":
+ const: 0
+
+ "#interrupt-cells":
+ const: 2
+
+ interrupt-map:
+ description: |
+ Specifies the mapping of GPIO lines to the parent interrupt controller, as the
+ GPIO controller does not do interrupt handling itself.
+
required:
- compatible
- reg
@@ -37,9 +48,37 @@ additionalProperties: false
examples:
- |
+ #include <dt-bindings/interrupt-controller/irq.h>
+
gpio-controller@1400 {
compatible = "fsl,mpc8360-qe-pario-bank", "fsl,mpc8323-qe-pario-bank";
reg = <0x1400 0x18>;
gpio-controller;
#gpio-cells = <2>;
};
+
+ gpio-controller@1418 {
+ compatible = "fsl,mpc8323-qe-pario-bank";
+ reg = <0x1418 0x18>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ #address-cells = <0>;
+ #interrupt-cells = <2>;
+ interrupt-map = <
+ 7 IRQ_TYPE_EDGE_FALLING &pic 4 IRQ_TYPE_EDGE_FALLING
+ 7 IRQ_TYPE_EDGE_BOTH &pic 4 IRQ_TYPE_EDGE_BOTH
+ 7 0 &pic 4 IRQ_TYPE_NONE
+
+ 9 IRQ_TYPE_EDGE_FALLING &pic 5 IRQ_TYPE_EDGE_FALLING
+ 9 IRQ_TYPE_EDGE_BOTH &pic 5 IRQ_TYPE_EDGE_BOTH
+ 9 0 &pic 5 IRQ_TYPE_NONE
+
+ 25 IRQ_TYPE_EDGE_FALLING &pic 6 IRQ_TYPE_EDGE_FALLING
+ 25 IRQ_TYPE_EDGE_BOTH &pic 6 IRQ_TYPE_EDGE_BOTH
+ 25 0 &pic 6 IRQ_TYPE_NONE
+
+ 27 IRQ_TYPE_EDGE_FALLING &pic 7 IRQ_TYPE_EDGE_FALLING
+ 27 IRQ_TYPE_EDGE_BOTH &pic 7 IRQ_TYPE_EDGE_BOTH
+ 27 0 &pic 7 IRQ_TYPE_NONE
+ >;
+ };
--
2.55.0
^ permalink raw reply related
* [PATCH v2 03/10] dt-bindings: soc: fsl: qe: Convert QE GPIO to DT schema
From: Paul Louvel @ 2026-07-08 10:15 UTC (permalink / raw)
To: Qiang Zhao, Christophe Leroy (CS GROUP), Thomas Gleixner,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Linus Walleij,
Bartosz Golaszewski, Madhavan Srinivasan, Michael Ellerman,
Nicholas Piggin
Cc: linuxppc-dev, linux-arm-kernel, linux-kernel, devicetree,
linux-gpio, Paul Louvel, Herve Codina, Christophe Leroy
In-Reply-To: <20260708-qe-pic-gpios-v2-0-1972044cfbd1@bootlin.com>
From: Christophe Leroy <christophe.leroy@csgroup.eu>
Convert QE GPIO devicetree binding to DT schema. The old binding uses
fsl,<chip>-qe-pario-bank because multiple MCP83XX SoC has support for
these GPIO banks. The best practice is to list out every <chip> instead.
Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
Signed-off-by: Paul Louvel <paul.louvel@bootlin.com>
---
.../bindings/gpio/fsl,mpc8323-qe-pario-bank.yaml | 45 ++++++++++++++++++++++
.../bindings/soc/fsl/cpm_qe/qe/par_io.txt | 26 +------------
2 files changed, 46 insertions(+), 25 deletions(-)
diff --git a/Documentation/devicetree/bindings/gpio/fsl,mpc8323-qe-pario-bank.yaml b/Documentation/devicetree/bindings/gpio/fsl,mpc8323-qe-pario-bank.yaml
new file mode 100644
index 000000000000..1af99339ff40
--- /dev/null
+++ b/Documentation/devicetree/bindings/gpio/fsl,mpc8323-qe-pario-bank.yaml
@@ -0,0 +1,45 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/gpio/fsl,mpc8323-qe-pario-bank.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Freescale QUICC Engine Parallel I/O (QE PARIO) GPIO Bank
+
+maintainers:
+ - Christophe Leroy <christophe.leroy@csgroup.eu>
+
+properties:
+ compatible:
+ oneOf:
+ - items:
+ - enum:
+ - fsl,mpc8360-qe-pario-bank
+ - fsl,mpc8569-qe-pario-bank
+ - const: fsl,mpc8323-qe-pario-bank
+ - const: fsl,mpc8323-qe-pario-bank
+
+ reg:
+ maxItems: 1
+
+ gpio-controller: true
+
+ "#gpio-cells":
+ const: 2
+
+required:
+ - compatible
+ - reg
+ - gpio-controller
+ - "#gpio-cells"
+
+additionalProperties: false
+
+examples:
+ - |
+ gpio-controller@1400 {
+ compatible = "fsl,mpc8360-qe-pario-bank", "fsl,mpc8323-qe-pario-bank";
+ reg = <0x1400 0x18>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
diff --git a/Documentation/devicetree/bindings/soc/fsl/cpm_qe/qe/par_io.txt b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/qe/par_io.txt
index 09b1b05fa677..782699c14567 100644
--- a/Documentation/devicetree/bindings/soc/fsl/cpm_qe/qe/par_io.txt
+++ b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/qe/par_io.txt
@@ -24,28 +24,4 @@ par_io@1400 {
Note that "par_io" nodes are obsolete, and should not be used for
the new device trees. Instead, each Par I/O bank should be represented
-via its own gpio-controller node:
-
-Required properties:
-- #gpio-cells : should be "2".
-- compatible : should be "fsl,<chip>-qe-pario-bank",
- "fsl,mpc8323-qe-pario-bank".
-- reg : offset to the register set and its length.
-- gpio-controller : node to identify gpio controllers.
-
-Example:
- qe_pio_a: gpio-controller@1400 {
- #gpio-cells = <2>;
- compatible = "fsl,mpc8360-qe-pario-bank",
- "fsl,mpc8323-qe-pario-bank";
- reg = <0x1400 0x18>;
- gpio-controller;
- };
-
- qe_pio_e: gpio-controller@1460 {
- #gpio-cells = <2>;
- compatible = "fsl,mpc8360-qe-pario-bank",
- "fsl,mpc8323-qe-pario-bank";
- reg = <0x1460 0x18>;
- gpio-controller;
- };
+via its own gpio-controller node.
--
2.55.0
^ permalink raw reply related
* [PATCH v2 02/10] dt-bindings: soc: fsl: qe: Set #interrupt-cells to 2 to support interrupt type encoding
From: Paul Louvel @ 2026-07-08 10:15 UTC (permalink / raw)
To: Qiang Zhao, Christophe Leroy (CS GROUP), Thomas Gleixner,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Linus Walleij,
Bartosz Golaszewski, Madhavan Srinivasan, Michael Ellerman,
Nicholas Piggin
Cc: linuxppc-dev, linux-arm-kernel, linux-kernel, devicetree,
linux-gpio, Paul Louvel, Herve Codina, Krzysztof Kozlowski
In-Reply-To: <20260708-qe-pic-gpios-v2-0-1972044cfbd1@bootlin.com>
The QUICC Engine port interrupt controller can be configured to generate
an interrupt on either a high-to-low transition or any change in the
signal state on the related GPIOs.
Update the #interrupt-cells property to 2 so consumers can encode
interrupt level information.
Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
Signed-off-by: Paul Louvel <paul.louvel@bootlin.com>
---
.../devicetree/bindings/interrupt-controller/fsl,qe-ports-ic.yaml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/Documentation/devicetree/bindings/interrupt-controller/fsl,qe-ports-ic.yaml b/Documentation/devicetree/bindings/interrupt-controller/fsl,qe-ports-ic.yaml
index 2b8e7b9c6d7a..2b7c6b4f0389 100644
--- a/Documentation/devicetree/bindings/interrupt-controller/fsl,qe-ports-ic.yaml
+++ b/Documentation/devicetree/bindings/interrupt-controller/fsl,qe-ports-ic.yaml
@@ -23,7 +23,7 @@ properties:
const: 0
'#interrupt-cells':
- const: 1
+ const: 2
interrupts:
maxItems: 1
@@ -45,7 +45,7 @@ examples:
reg = <0xc00 0x18>;
interrupt-controller;
#address-cells = <0>;
- #interrupt-cells = <1>;
+ #interrupt-cells = <2>;
interrupts = <74 0x8>;
interrupt-parent = <&ipic>;
};
--
2.55.0
^ permalink raw reply related
* [PATCH v2 00/10] soc: fsl: qe: QE PIC improvement and add support of IRQs to QUICC ENGINE GPIOs
From: Paul Louvel @ 2026-07-08 10:15 UTC (permalink / raw)
To: Qiang Zhao, Christophe Leroy (CS GROUP), Thomas Gleixner,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Linus Walleij,
Bartosz Golaszewski, Madhavan Srinivasan, Michael Ellerman,
Nicholas Piggin
Cc: linuxppc-dev, linux-arm-kernel, linux-kernel, devicetree,
linux-gpio, Paul Louvel, Herve Codina, stable,
Krzysztof Kozlowski, Christophe Leroy
This series modernizes the QUICC Engine Port Interrupt Controller (QE
PIC) driver and adds the ability for QE GPIO pins to generate interrupts
through the QE PIC, completing Christophe Leroy's prior work [1].
Christophe's series was partially merged; patches 4, 6 and 7 did not
make it to mainline.
The series is organized in three parts:
1) Add missing chained_irq_{enter,exit}() calls
- In a chained handler, the parent controller need to mask and ack
the interrupt source.
2) DT binding updates
- Update #interrupt-cells from 1 to 2 in the QE PIC binding so
consumers can encode the interrupt type (falling-edge or
both-edges).
- Convert the QE GPIO binding from freeform text to DT schema.
- Extend the QE GPIO binding with an interrupt-map (nexus node) that
maps GPIO lines to parent QE PIC interrupts. This approach was
suggested by Rob Herring [2] as an alternative to using compatible
strings and driver data to specify which pins support interrupts in
a given bank.
3) QE PIC driver refactoring
- The QE PIC is a perfect fit to use the generic irq framework
instead. Perform the necessary changes to the driver to convert it.
- Minor cleanups.
4) QE GPIO interrupt support
- Add a to_irq() method to the QE GPIO driver that perform the
mapping of the GPIO pin to the parent interrupt domain, allowing
GPIO pins to be used as interrupt sources through the QE PIC via
gpio_to_irq().
[1] https://lore.kernel.org/all/cover.1758212309.git.christophe.leroy@csgroup.eu/
[2] https://lore.kernel.org/all/20250919152414.GB852815-robh@kernel.org/
Signed-off-by: Paul Louvel <paul.louvel@bootlin.com>
---
Changes in v2:
- Applied Christophe two patches before this series [3] [4].
- Fix a miscalculation in patch 6 when iterating over bits set in
CEPIER. Old ffs() is 1-indexed, but for_each_set_bit() is 0-indexed.
- Add in patch 3 commit message more info about the changes introduced
by the conversion to DT schema.
- In patch 4, keep the existing example without any IRQ supports, and
add only one new example. Also fix the DTS coding style that was wrong.
- Add raw spinlock guard to mask and unmasking hook since multiple CPUs
can modify different IRQs concurrently. Also add it to set_type hook.
- Drop usage of register offset in irq_chip_type. It requires additional
load instruction with no real benefit since irq_gc_* functions are not
used.
- A race condition can occurs if an interrupt fires immediately after
the domain is initialised, because gc is NULL.
Instead, do not carry gc in the struct qepic_data. Add the domain in
the handler data, and retrieve gc with irq_data_get_irq_chip_data() in
hook functions.
Because of this modification, patch 10 and 11 are dropped.
- Link to v1: https://patch.msgid.link/20260703-qe-pic-gpios-v1-0-6c3e706e27dc@bootlin.com
[3] https://lore.kernel.org/all/b08f76c1d8ff864774246f1e2c2158c223c001be.1783435914.git.chleroy@kernel.org/
[4] https://lore.kernel.org/all/cd46aec4b325745d38ac7992e4d3d5b4f4c4e95f.1783435914.git.chleroy@kernel.org/
---
Christophe Leroy (1):
dt-bindings: soc: fsl: qe: Convert QE GPIO to DT schema
Paul Louvel (9):
soc: fsl: qe: Add chained_irq_{enter,exit}() calls in cascade handler
dt-bindings: soc: fsl: qe: Set #interrupt-cells to 2 to support interrupt type encoding
dt-bindings: soc: fsl: qe: Add support of IRQ in QE GPIO
soc: fsl: qe: Use generic_handle_domain_irq()
soc: fsl: qe: Iterate over all pending interrupts in cascade handler
soc: fsl: qe: Handle spurious interrupts
soc: fsl: qe: Convert to generic IRQ chip
soc: fsl: qe: Rename irq variable to parent_irq
soc: fsl: qe: Add support of IRQs in QE GPIO
.../bindings/gpio/fsl,mpc8323-qe-pario-bank.yaml | 84 ++++++++++++
.../interrupt-controller/fsl,qe-ports-ic.yaml | 4 +-
.../bindings/soc/fsl/cpm_qe/qe/par_io.txt | 26 +---
drivers/soc/fsl/qe/Kconfig | 1 +
drivers/soc/fsl/qe/gpio.c | 28 +++-
drivers/soc/fsl/qe/qe_ports_ic.c | 145 +++++++++++++--------
6 files changed, 208 insertions(+), 80 deletions(-)
---
base-commit: c34b47a17bc566c7113679e6ae095d5510b4f1c6
change-id: 20260513-qe-pic-gpios-073e284615a3
Best regards,
--
Paul Louvel, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
^ permalink raw reply
* [PATCH v2 01/10] soc: fsl: qe: Add chained_irq_{enter,exit}() calls in cascade handler
From: Paul Louvel @ 2026-07-08 10:15 UTC (permalink / raw)
To: Qiang Zhao, Christophe Leroy (CS GROUP), Thomas Gleixner,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Linus Walleij,
Bartosz Golaszewski, Madhavan Srinivasan, Michael Ellerman,
Nicholas Piggin
Cc: linuxppc-dev, linux-arm-kernel, linux-kernel, devicetree,
linux-gpio, Paul Louvel, Herve Codina, stable
In-Reply-To: <20260708-qe-pic-gpios-v2-0-1972044cfbd1@bootlin.com>
Wrap the cascade handler body with chained_irq_{enter,exit}() to
properly inform the parent IRQ chip that a chained interrupt is being
serviced.
Fixes: f0bcd784e1b76 ("soc: fsl: qe: Add an interrupt controller for QUICC Engine Ports")
Signed-off-by: Paul Louvel <paul.louvel@bootlin.com>
Cc: stable@kernel.org
---
drivers/soc/fsl/qe/qe_ports_ic.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/drivers/soc/fsl/qe/qe_ports_ic.c b/drivers/soc/fsl/qe/qe_ports_ic.c
index 33ca1ddafe18..c3768c82a58c 100644
--- a/drivers/soc/fsl/qe/qe_ports_ic.c
+++ b/drivers/soc/fsl/qe/qe_ports_ic.c
@@ -6,6 +6,7 @@
*/
#include <linux/irq.h>
+#include <linux/irqchip/chained_irq.h>
#include <linux/irqdomain.h>
#include <linux/platform_device.h>
@@ -82,7 +83,13 @@ static int qepic_get_irq(struct irq_desc *desc)
static void qepic_cascade(struct irq_desc *desc)
{
+ struct irq_chip *chip = irq_desc_get_chip(desc);
+
+ chained_irq_enter(chip, desc);
+
generic_handle_irq(qepic_get_irq(desc));
+
+ chained_irq_exit(chip, desc);
}
static int qepic_host_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t hw)
--
2.55.0
^ permalink raw reply related
* Re: [PATCH RFC] RAS: hwerr_tracking: move recoverable hardware error tracking out of vmcoreinfo
From: Breno Leitao @ 2026-07-08 10:13 UTC (permalink / raw)
To: Borislav Petkov
Cc: Tony Luck, Thomas Gleixner, Ingo Molnar, Dave Hansen, x86,
H. Peter Anvin, Rafael J. Wysocki, Hanjun Guo,
Mauro Carvalho Chehab, Shuai Xue, Len Brown, Mahesh J Salgaonkar,
Oliver O'Halloran, Bjorn Helgaas, Breno Leitao, linux-kernel,
linux-edac, linux-acpi, linuxppc-dev, linux-pci, kernel-team
In-Reply-To: <20260707183517.GCak1G5TKyF1ggs8WW@fat_crate.local>
On Tue, Jul 07, 2026 at 11:35:17AM -0700, Borislav Petkov wrote:
> On Tue, Jul 07, 2026 at 09:53:34AM -0700, Breno Leitao wrote:
> > The current vmcoreinfo implementation defaults to enabled, so I wanted to
> > preserve that behavior to avoid silently removing symbols that existing
> > tools may depend on. Would you prefer a different default?
>
> You do know Linus' stance on enabling things by default which are not
> ubiquitous, right?
Oh yea, I am familiar with it. :-)
> Logging hw errors in vmcore is really necessary to be enabled everywhere?
I am happy to make it no, if we transform it to a KCONFIG. Right now it
is not a Kconfig, so, it comes with VMCORE set of exported fields.
> > I agree the sysfs exposure duplicates existing infrastructure, points
> > taken. However, tracking fatal hardware errors provides value at crash
> > analysis time—it lets us quickly determine whether a fatal hardware
> > error occurred during the kernel's lifetime, which is useful for
> > root-cause attribution.
>
> Yes, that's why you put it in vmcore. You can't read sysfs if you encounter
> a fatal hw error.
Ack. Right now it is not tracking fatal error (just recoverable error),
although I think it is a good idea to also track Fatal error (of course
that not on sysfs).
> > For this, would you like to keep it in vmcore info (as of today), or
> > move to RAS subsystem?
>
> You mean, would I like to pay attention to more patches than now?
>
> Not really - I can barely manage as it is.
Come one Borislav, we need your insights/review/opinions here as well.
:-)
^ permalink raw reply
* RE: [PATCH] ASoC: fsl_sai: Fix spurious BCLK on resume by clearing BYP
From: Chancel Liu (OSS) @ 2026-07-08 9:34 UTC (permalink / raw)
To: Shengjiu Wang, Chancel Liu (OSS)
Cc: Xiubo.Lee@gmail.com, festevam@gmail.com, nicoleotsuka@gmail.com,
lgirdwood@gmail.com, broonie@kernel.org, perex@perex.cz,
tiwai@suse.com, linux-kernel@vger.kernel.org,
linuxppc-dev@lists.ozlabs.org, linux-sound@vger.kernel.org
In-Reply-To: <CAA+D8AOoO98Zi2+GP4He2zhSLaM=aKZC5F0PBu70QTFGJnp2Pw@mail.gmail.com>
> > From: Chancel Liu <chancel.liu@nxp.com>
> >
> > When the BCLK divider ratio is 1:1, fsl_sai_set_bclk() enables bypass
> > mode by setting BYP, but never clears the bit. The BYP=1 value remains
> > in the regcache, and is restored by regcache_sync() on the next
> > runtime resume.
> >
> > Since BYP=1 combined with BCD=1 immediately outputs the ungated MCLK
> > as BCLK without waiting for BCE/TE/RE to be enabled, the clock is
> > driven prematurely before the stream is fully configured, causing
> > noise on some codecs.
> >
> > Fix this by clearing BYP and BCI together in fsl_sai_config_disable().
> > Also clear BCI, which is programmed together with the bypass case in
> > synchronous mode, so the cached CR2 state is clean and regcache_sync()
> > will not restore bypass mode prematurely on the next resume.
> >
> > Fixes: a50b7926d015 ("ASoC: fsl_sai: implement 1:1 bclk:mclk ratio
> > support")
> > Signed-off-by: Chancel Liu <chancel.liu@nxp.com>
>
> Reviewed-by: Shengjiu Wang <shengjiu.wang@gmail.com>
>
Thanks for your review. As sashiko reported this patch has potential
regression. I have to rework on it.
Regards,
Chancel Liu
> Best regards
> Shengjiu Wang
> > ---
> > sound/soc/fsl/fsl_sai.c | 3 +++
> > 1 file changed, 3 insertions(+)
> >
> > diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index
> > 9661602b53c5..4c0626d572a5 100644
> > --- a/sound/soc/fsl/fsl_sai.c
> > +++ b/sound/soc/fsl/fsl_sai.c
> > @@ -847,6 +847,9 @@ static void fsl_sai_config_disable(struct fsl_sai
> *sai, int dir)
> > regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx, ofs),
> > FSL_SAI_CSR_FR, FSL_SAI_CSR_FR);
> >
> > + regmap_update_bits(sai->regmap, FSL_SAI_xCR2(tx, ofs),
> > + FSL_SAI_CR2_BCI | FSL_SAI_CR2_BYP, 0);
> > +
> > /*
> > * For sai master mode, after several open/close sai,
> > * there will be no frame clock, and can't recover
> > --
> > 2.50.1
> >
^ permalink raw reply
* Re: [patch 18/18] entry, treewide: Make syscall_enter_from_user_mode[_work]() indicate syscall execution
From: Thomas Gleixner @ 2026-07-08 9:16 UTC (permalink / raw)
To: Shrikanth Hegde, LKML
Cc: Peter Zijlstra, Michal Suchánek, Jonathan Corbet,
Arnd Bergmann, Mark Rutland, Huacai Chen, Michael Ellerman,
Paul Walmsley, Palmer Dabbelt, Sven Schnelle, linux-doc,
loongarch, linuxppc-dev, linux-riscv, linux-s390, Kees Cook, x86,
Jinjie Ruan, Andy Lutomirski, Oleg Nesterov, Richard Henderson,
Russell King, Catalin Marinas, Guo Ren, Geert Uytterhoeven,
Thomas Bogendoerfer, Helge Deller, Yoshinori Sato,
Richard Weinberger, Chris Zankel, linux-arm-kernel, linux-alpha,
linux-csky, linux-m68k, linux-mips, linux-parisc, linux-sh,
linux-um, Vineet Gupta, Will Deacon, Brian Cain, Michal Simek,
Dinh Nguyen, David S. Miller, Andreas Larsson, linux-snps-arc,
linux-hexagon, linux-openrisc, sparclinux, linux-arch
In-Reply-To: <5c202ab4-33f1-42e9-bef2-81fbd0a9992e@linux.ibm.com>
On Wed, Jul 08 2026 at 10:51, Shrikanth Hegde wrote:
> On 7/8/26 12:37 AM, Thomas Gleixner wrote:
>> - r0 = syscall_enter_from_user_mode_randomize_stack(regs, r0);
>> + if (unlikely(!syscall_enter_from_user_mode_randomize_stack(regs, &r0))
>> + return syscall_get_error(current, regs);
>>
>
> There is one missing )
Bah.
^ permalink raw reply
* Re: [patch 11/18] seccomp, treewide: Rename and convert __secure_computing() to return boolean
From: Thomas Gleixner @ 2026-07-08 9:15 UTC (permalink / raw)
To: Jinjie Ruan, LKML
Cc: Peter Zijlstra, Mark Rutland, Kees Cook, Andy Lutomirski,
Oleg Nesterov, Richard Henderson, Russell King, Catalin Marinas,
Guo Ren, Geert Uytterhoeven, Thomas Bogendoerfer, Helge Deller,
Yoshinori Sato, Richard Weinberger, Chris Zankel,
linux-arm-kernel, linux-alpha, linux-csky, linux-m68k, linux-mips,
linux-parisc, linux-sh, linux-um, Michael Ellerman,
Shrikanth Hegde, linuxppc-dev, Huacai Chen, loongarch,
Paul Walmsley, Palmer Dabbelt, linux-riscv, Sven Schnelle,
linux-s390, x86, Arnd Bergmann, Vineet Gupta, Will Deacon,
Brian Cain, Michal Simek, Dinh Nguyen, David S. Miller,
Andreas Larsson, linux-snps-arc, linux-hexagon, linux-openrisc,
sparclinux, linux-arch, Michal Suchánek, Jonathan Corbet,
linux-doc
In-Reply-To: <2e6ed364-ce8f-4b4b-8675-acd07f140f4f@huawei.com>
On Wed, Jul 08 2026 at 09:43, Jinjie Ruan wrote:
> On 7/8/2026 3:06 AM, Thomas Gleixner wrote:
> As Ada pointed out, the description of secure_computing in arch/Kconfig
> need to be updated, a possible suggestion:
>
> --- a/arch/Kconfig
> +++ b/arch/Kconfig
> @@ -636,8 +636,8 @@ config HAVE_ARCH_SECCOMP_FILTER
> - syscall_rollback()
> - syscall_set_return_value()
> - SIGSYS siginfo_t support
> - - secure_computing is called from a ptrace_event()-safe context
> - - secure_computing return value is checked and a return value
> of -1
> + - seccomp_permits_syscall is called from a ptrace_event()-safe
> context
> + - seccomp_permits_syscall return value is checked and if false
Makes sense.
>> if (__seccomp_filter(this_syscall, true))
>> - return -1;
>> + return false;
>
> The return value of __seccomp_filter is checked in the wrong way, check
> -1 should be replaced with check false, maybe:
>
> - if (__seccomp_filter(this_syscall, true))
> - return -1;
> + if (!__seccomp_filter(this_syscall, true))
> + return false;
Ooops.
^ permalink raw reply
* Re: [PATCH V17 4/7] rust/powerpc: Set min rustc version for powerpc
From: Link Mauve @ 2026-07-08 8:39 UTC (permalink / raw)
To: Mukesh Kumar Chaurasiya (IBM)
Cc: maddy, mpe, npiggin, chleroy, peterz, jpoimboe, jbaron, aliceryhl,
rostedt, ardb, ojeda, boqun, gary, bjorn3_gh, lossin, a.hindborg,
tmgross, dakr, daniel.almeida, tamird, acourbot, work, nathan,
ndesaulniers, morbo, justinstitt, fujita.tomonori, joelagnelf,
gregkh, prafulrai522, nsc, japo, lina+kernel, j, airlied,
linuxppc-dev, linux-kernel, rust-for-linux, llvm
In-Reply-To: <20260708082454.1254320-5-mkchauras@gmail.com>
Hi,
On Wed, Jul 08, 2026 at 01:54:51PM +0530, Mukesh Kumar Chaurasiya (IBM) wrote:
> Minimum `rustc` version required for powerpc is 1.95 as some critical
> features required for compiling rust code for kernel are not there.
>
> For example Stable inline asm support which got merged in 1.95.
Didn’t we decide on 1.85.0 with the asm_experimental_arch feature
instead? And possibly on 64-bit 1.87.0 if it isn’t possible to disable
altivec correctly there?
>
> Link: https://github.com/rust-lang/rust/pull/147996
> Signed-off-by: Mukesh Kumar Chaurasiya (IBM) <mkchauras@gmail.com>
> ---
> scripts/min-tool-version.sh | 2 ++
> 1 file changed, 2 insertions(+)
>
> diff --git a/scripts/min-tool-version.sh b/scripts/min-tool-version.sh
> index 031f2192b390..99bfdcaa3396 100755
> --- a/scripts/min-tool-version.sh
> +++ b/scripts/min-tool-version.sh
> @@ -33,6 +33,8 @@ llvm)
> rustc)
> if [ "$SRCARCH" = "s390" ]; then
> echo 1.96.0
> + elif [ "$ARCH" = powerpc ]; then
> + echo 1.95.0
> else
> echo 1.85.0
> fi
> --
> 2.55.0
>
>
--
Link Mauve
^ permalink raw reply
* Re: [PATCH v2] powerpc/powernv: Cache OPAL check_token() results
From: Shivang Upadhyay @ 2026-07-08 8:32 UTC (permalink / raw)
To: Nikhil Kumar Singh, linuxppc-dev; +Cc: Sourabh Jain
In-Reply-To: <1be96e32-ac9c-4160-9f2b-23eb29c22893@linux.ibm.com>
[-- Attachment #1: Type: text/plain, Size: 616 bytes --]
On Tue, 2026-07-07 at 12:36 +0530, Nikhil Kumar Singh wrote:
> You can wrap the if (token_cache[token] == SUPP_UNKNOWN) check, as
> well as the if (token > OPAL_LAST) check above it, with unlikely(),
> since this function is in the hot path. Out-of-bounds tokens are very
> rare, and after the cache is populated, the SUPP_UNKNOWN condition is
> expected to be false in almost all cases. Wrapping these checks with
> unlikely() will help the compiler optimize branch
Thanks for your suggestion, but Which hotpath code is calling this?
we can maybe change that hotpath to not do rtas calls.
~Shivang.
[-- Attachment #2: Type: text/html, Size: 1093 bytes --]
^ permalink raw reply
* [PATCH V17 7/7] powerpc: Enable Rust for ppc64le
From: Mukesh Kumar Chaurasiya (IBM) @ 2026-07-08 8:24 UTC (permalink / raw)
To: maddy, mpe, npiggin, chleroy, peterz, jpoimboe, jbaron, aliceryhl,
rostedt, ardb, ojeda, boqun, gary, bjorn3_gh, lossin, a.hindborg,
tmgross, dakr, daniel.almeida, tamird, acourbot, work, nathan,
ndesaulniers, morbo, justinstitt, fujita.tomonori, joelagnelf,
gregkh, prafulrai522, nsc, japo, mkchauras, lina+kernel, j,
airlied, linuxppc-dev, linux-kernel, rust-for-linux, llvm
Cc: Link Mauve, Venkat Rao Bagalkote
In-Reply-To: <20260708082454.1254320-1-mkchauras@gmail.com>
Enabling rust support for ppc64le.
Tested on pseries Power11:
╰─❯ dmesg | grep rust
[ 0.225728] Initialise system trusted keyrings
[ 0.270961] rust_minimal: Rust minimal sample (init)
[ 0.270968] rust_minimal: Am I built-in? true
[ 0.270974] rust_minimal: test_parameter: 1
[ 0.270983] rust_misc_device: Initialising Rust Misc Device Sample
[ 0.271012] rust_print: Rust printing macros sample (init)
[ 0.271019] rust_print: Emergency message (level 0) without args
[ 0.271023] rust_print: Alert message (level 1) without args
[ 0.271026] rust_print: Critical message (level 2) without args
[ 0.271030] rust_print: Error message (level 3) without args
[ 0.271033] rust_print: Warning message (level 4) without args
[ 0.271037] rust_print: Notice message (level 5) without args
[ 0.271040] rust_print: Info message (level 6) without args
[ 0.271043] rust_print: A line that is continued without args
[ 0.271054] rust_print: Emergency message (level 0) with args
[ 0.271064] rust_print: Alert message (level 1) with args
[ 0.271072] rust_print: Critical message (level 2) with args
[ 0.271077] rust_print: Error message (level 3) with args
[ 0.271083] rust_print: Warning message (level 4) with args
[ 0.271091] rust_print: Notice message (level 5) with args
[ 0.271097] rust_print: Info message (level 6) with args
[ 0.271102] rust_print: A line that is continued with args
[ 0.271110] rust_print: 1
[ 0.271113] rust_print: "hello, world"
[ 0.271121] rust_print: [samples/rust/rust_print_main.rs:35:5] c = "hello, world"
[ 0.271129] rust_print: Arc<dyn Display> says 42
[ 0.271130] rust_print: Arc<dyn Display> says hello, world
[ 0.271136] rust_print: "hello, world"
[ 0.271198] usbcore: registered new interface driver rust_driver_usb
[ 0.271207] rust_faux_driver: Initialising Rust Faux Device Sample
[ 0.271227] faux_driver rust-faux-sample-device: Hello from faux device!
[ 0.271297] rust_configfs: Rust configfs sample (init)
Reviewed-by: Link Mauve <linkmauve@linkmauve.fr>
Tested-by: Link Mauve <linkmauve@linkmauve.fr>
Reviewed-by: Christophe Leroy (CS GROUP) <chleroy@kernel.org>
Tested-by: Venkat Rao Bagalkote <venkat88@linux.ibm.com>
Link: https://github.com/Rust-for-Linux/linux/issues/105
Link: https://github.com/linuxppc/issues/issues/451
Acked-by: Gary Guo <gary@garyguo.net>
Link: https://github.com/rust-lang/compiler-team/issues/987
Link: https://github.com/rust-lang/compiler-team/issues/988
Signed-off-by: Mukesh Kumar Chaurasiya (IBM) <mkchauras@gmail.com>
---
arch/powerpc/Kconfig | 1 +
arch/powerpc/Makefile | 7 ++++++-
rust/Makefile | 6 ++++++
3 files changed, 13 insertions(+), 1 deletion(-)
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index badd7c99b87f..650283107b92 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -286,6 +286,7 @@ config PPC
select HAVE_RELIABLE_STACKTRACE
select HAVE_RSEQ
select HAVE_RUST if PPC32
+ select HAVE_RUST if PPC64 && CPU_LITTLE_ENDIAN
select HAVE_SAMPLE_FTRACE_DIRECT if HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
select HAVE_SAMPLE_FTRACE_DIRECT_MULTI if HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
select HAVE_SETUP_PER_CPU_AREA if PPC64
diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile
index 589613eaa5dc..9385db478c59 100644
--- a/arch/powerpc/Makefile
+++ b/arch/powerpc/Makefile
@@ -61,7 +61,12 @@ else
KBUILD_LDFLAGS_MODULE += $(objtree)/arch/powerpc/lib/crtsavres.o
endif
-KBUILD_RUSTFLAGS += --target=powerpc-unknown-linux-gnu
+ifdef CONFIG_PPC64
+KBUILD_RUSTFLAGS += --target=powerpc64le-unknown-linux-gnu
+KBUILD_RUSTFLAGS += -Ctarget-feature=-mma,-vsx,-hard-float,-altivec
+else
+KBUILD_RUSTFLAGS += --target=powerpc-unknown-linux-gnu
+endif
ifdef CONFIG_CPU_LITTLE_ENDIAN
KBUILD_CPPFLAGS += -mlittle-endian
diff --git a/rust/Makefile b/rust/Makefile
index 61e7dc496fe4..d2f74998d3c1 100644
--- a/rust/Makefile
+++ b/rust/Makefile
@@ -459,7 +459,13 @@ BINDGEN_TARGET_loongarch := loongarch64-linux-gnusf
BINDGEN_TARGET_s390 := s390x-linux-gnu
# This is only for i386 UM builds, which need the 32-bit target not -m32
BINDGEN_TARGET_i386 := i386-linux-gnu
+
+ifdef CONFIG_PPC64
+BINDGEN_TARGET_powerpc := powerpc64le-linux-gnu
+else
BINDGEN_TARGET_powerpc := powerpc-linux-gnu
+endif
+
BINDGEN_TARGET_um := $(BINDGEN_TARGET_$(SUBARCH))
BINDGEN_TARGET := $(BINDGEN_TARGET_$(SRCARCH))
--
2.55.0
^ permalink raw reply related
* [PATCH V17 6/7] rust: Add PowerPC support
From: Mukesh Kumar Chaurasiya (IBM) @ 2026-07-08 8:24 UTC (permalink / raw)
To: maddy, mpe, npiggin, chleroy, peterz, jpoimboe, jbaron, aliceryhl,
rostedt, ardb, ojeda, boqun, gary, bjorn3_gh, lossin, a.hindborg,
tmgross, dakr, daniel.almeida, tamird, acourbot, work, nathan,
ndesaulniers, morbo, justinstitt, fujita.tomonori, joelagnelf,
gregkh, prafulrai522, nsc, japo, mkchauras, lina+kernel, j,
airlied, linuxppc-dev, linux-kernel, rust-for-linux, llvm
Cc: Link Mauve
In-Reply-To: <20260708082454.1254320-1-mkchauras@gmail.com>
From: Link Mauve <linkmauve@linkmauve.fr>
For now only Big Endian 32-bit PowerPC is supported, as that is the only
hardware I have. This has been tested on the Nintendo Wii so far, but I
plan on also using it on the GameCube, Wii U and Apple G4.
These changes aren’t the only ones required to get the kernel to compile
and link on PowerPC, libcore will also have to be changed to not use
integer division to format u64, u128 and core::time::Duration, otherwise
__udivdi3() and __umoddi3() will have to be added. I have tested this
change by replacing the three implementations with unimplemented!() and
it linked just fine.
Signed-off-by: Link Mauve <linkmauve@linkmauve.fr>
Link: https://github.com/Rust-for-Linux/linux/issues/105
Link: https://github.com/linuxppc/issues/issues/451
Acked-by: Gary Guo <gary@garyguo.net>
Link: https://github.com/rust-lang/compiler-team/issues/986
Signed-off-by: Mukesh Kumar Chaurasiya (IBM) <mkchauras@gmail.com>
---
arch/powerpc/Kconfig | 1 +
arch/powerpc/Makefile | 2 ++
rust/Makefile | 4 +++-
3 files changed, 6 insertions(+), 1 deletion(-)
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index f7ce5fff81f0..badd7c99b87f 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -285,6 +285,7 @@ config PPC
select HAVE_REGS_AND_STACK_ACCESS_API
select HAVE_RELIABLE_STACKTRACE
select HAVE_RSEQ
+ select HAVE_RUST if PPC32
select HAVE_SAMPLE_FTRACE_DIRECT if HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
select HAVE_SAMPLE_FTRACE_DIRECT_MULTI if HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
select HAVE_SETUP_PER_CPU_AREA if PPC64
diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile
index a58b1029592c..589613eaa5dc 100644
--- a/arch/powerpc/Makefile
+++ b/arch/powerpc/Makefile
@@ -61,6 +61,8 @@ else
KBUILD_LDFLAGS_MODULE += $(objtree)/arch/powerpc/lib/crtsavres.o
endif
+KBUILD_RUSTFLAGS += --target=powerpc-unknown-linux-gnu
+
ifdef CONFIG_CPU_LITTLE_ENDIAN
KBUILD_CPPFLAGS += -mlittle-endian
KBUILD_LDFLAGS += -EL
diff --git a/rust/Makefile b/rust/Makefile
index 7aa8fcad4c43..61e7dc496fe4 100644
--- a/rust/Makefile
+++ b/rust/Makefile
@@ -448,7 +448,8 @@ bindgen_skip_c_flags := -mno-fp-ret-in-387 -mpreferred-stack-boundary=% \
-fstrict-flex-arrays=% -fmin-function-alignment=% \
-fzero-init-padding-bits=% -mno-fdpic \
-fdiagnostics-show-context -fdiagnostics-show-context=% \
- --param=% --param asan-% -fno-isolate-erroneous-paths-dereference
+ --param=% --param asan-% -fno-isolate-erroneous-paths-dereference \
+ -ffixed-r2 -mmultiple -mno-readonly-in-sdata
# Derived from `scripts/Makefile.clang`.
BINDGEN_TARGET_x86 := x86_64-linux-gnu
@@ -458,6 +459,7 @@ BINDGEN_TARGET_loongarch := loongarch64-linux-gnusf
BINDGEN_TARGET_s390 := s390x-linux-gnu
# This is only for i386 UM builds, which need the 32-bit target not -m32
BINDGEN_TARGET_i386 := i386-linux-gnu
+BINDGEN_TARGET_powerpc := powerpc-linux-gnu
BINDGEN_TARGET_um := $(BINDGEN_TARGET_$(SUBARCH))
BINDGEN_TARGET := $(BINDGEN_TARGET_$(SRCARCH))
--
2.55.0
^ permalink raw reply related
* [PATCH V17 5/7] rust: Make __udivdi3() and __umoddi3() panic
From: Mukesh Kumar Chaurasiya (IBM) @ 2026-07-08 8:24 UTC (permalink / raw)
To: maddy, mpe, npiggin, chleroy, peterz, jpoimboe, jbaron, aliceryhl,
rostedt, ardb, ojeda, boqun, gary, bjorn3_gh, lossin, a.hindborg,
tmgross, dakr, daniel.almeida, tamird, acourbot, work, nathan,
ndesaulniers, morbo, justinstitt, fujita.tomonori, joelagnelf,
gregkh, prafulrai522, nsc, japo, mkchauras, lina+kernel, j,
airlied, linuxppc-dev, linux-kernel, rust-for-linux, llvm
Cc: Link Mauve
In-Reply-To: <20260708082454.1254320-1-mkchauras@gmail.com>
From: Link Mauve <linkmauve@linkmauve.fr>
The core crate currently depends on these two functions for i64/u64/
i128/u128/core::time::Duration formatting, but we shouldn’t use that in
the kernel so let’s panic if they are ever called.
This doesn’t yet fix drm_panic_qr.rs, which also uses __udivdi3 when
CONFIG_CC_OPTIMIZE_FOR_SIZE=y, but at least makes the rest of the kernel
build on PPC32.
Signed-off-by: Link Mauve <linkmauve@linkmauve.fr>
Signed-off-by: Mukesh Kumar Chaurasiya (IBM) <mkchauras@gmail.com>
---
rust/Makefile | 4 ++++
rust/compiler_builtins.rs | 6 ++++++
2 files changed, 10 insertions(+)
diff --git a/rust/Makefile b/rust/Makefile
index 17b2f329c13d..7aa8fcad4c43 100644
--- a/rust/Makefile
+++ b/rust/Makefile
@@ -677,6 +677,10 @@ ifneq ($(or $(CONFIG_ARM64),$(and $(CONFIG_RISCV),$(CONFIG_64BIT))),)
__ashrti3 \
__ashlti3 __lshrti3
endif
+ifdef CONFIG_PPC32
+ redirect-intrinsics += \
+ __udivdi3 __umoddi3
+endif
ifdef CONFIG_MODVERSIONS
cmd_gendwarfksyms = $(if $(skip_gendwarfksyms),, \
diff --git a/rust/compiler_builtins.rs b/rust/compiler_builtins.rs
index dd16c1dc899c..fc6b54636dd5 100644
--- a/rust/compiler_builtins.rs
+++ b/rust/compiler_builtins.rs
@@ -97,5 +97,11 @@ pub extern "C" fn $ident() {
__aeabi_uldivmod,
});
+#[cfg(target_arch = "powerpc")]
+define_panicking_intrinsics!("`u64` division/modulo should not be used", {
+ __udivdi3,
+ __umoddi3,
+});
+
// NOTE: if you are adding a new intrinsic here, you should also add it to
// `redirect-intrinsics` in `rust/Makefile`.
--
2.55.0
^ permalink raw reply related
* [PATCH V17 4/7] rust/powerpc: Set min rustc version for powerpc
From: Mukesh Kumar Chaurasiya (IBM) @ 2026-07-08 8:24 UTC (permalink / raw)
To: maddy, mpe, npiggin, chleroy, peterz, jpoimboe, jbaron, aliceryhl,
rostedt, ardb, ojeda, boqun, gary, bjorn3_gh, lossin, a.hindborg,
tmgross, dakr, daniel.almeida, tamird, acourbot, work, nathan,
ndesaulniers, morbo, justinstitt, fujita.tomonori, joelagnelf,
gregkh, prafulrai522, nsc, japo, mkchauras, lina+kernel, j,
airlied, linuxppc-dev, linux-kernel, rust-for-linux, llvm
In-Reply-To: <20260708082454.1254320-1-mkchauras@gmail.com>
Minimum `rustc` version required for powerpc is 1.95 as some critical
features required for compiling rust code for kernel are not there.
For example Stable inline asm support which got merged in 1.95.
Link: https://github.com/rust-lang/rust/pull/147996
Signed-off-by: Mukesh Kumar Chaurasiya (IBM) <mkchauras@gmail.com>
---
scripts/min-tool-version.sh | 2 ++
1 file changed, 2 insertions(+)
diff --git a/scripts/min-tool-version.sh b/scripts/min-tool-version.sh
index 031f2192b390..99bfdcaa3396 100755
--- a/scripts/min-tool-version.sh
+++ b/scripts/min-tool-version.sh
@@ -33,6 +33,8 @@ llvm)
rustc)
if [ "$SRCARCH" = "s390" ]; then
echo 1.96.0
+ elif [ "$ARCH" = powerpc ]; then
+ echo 1.95.0
else
echo 1.85.0
fi
--
2.55.0
^ permalink raw reply related
* [PATCH V17 3/7] powerpc/jump_label: adjust inline asm to be consistent
From: Mukesh Kumar Chaurasiya (IBM) @ 2026-07-08 8:24 UTC (permalink / raw)
To: maddy, mpe, npiggin, chleroy, peterz, jpoimboe, jbaron, aliceryhl,
rostedt, ardb, ojeda, boqun, gary, bjorn3_gh, lossin, a.hindborg,
tmgross, dakr, daniel.almeida, tamird, acourbot, work, nathan,
ndesaulniers, morbo, justinstitt, fujita.tomonori, joelagnelf,
gregkh, prafulrai522, nsc, japo, mkchauras, lina+kernel, j,
airlied, linuxppc-dev, linux-kernel, rust-for-linux, llvm
In-Reply-To: <20260708082454.1254320-1-mkchauras@gmail.com>
Added support for a new macro ARCH_STATIC_BRANCH_ASM in powerpc
to avoid duplication of inline asm between C and Rust. This is
inline with 'commit aecaf181651c ("jump_label: adjust inline asm to be consistent")'
Co-developed-by: Madhavan Srinivasan <maddy@linux.ibm.com>
Signed-off-by: Madhavan Srinivasan <maddy@linux.ibm.com>
Reviewed-by: Alice Ryhl <aliceryhl@google.com>
Reviewed-by: Christophe Leroy (CS GROUP) <chleroy@kernel.org>
Reviewed-by: Gary Guo <gary@garyguo.net>
Link: https://github.com/Rust-for-Linux/linux/issues/105
Link: https://github.com/linuxppc/issues/issues/451
Signed-off-by: Mukesh Kumar Chaurasiya (IBM) <mkchauras@gmail.com>
---
arch/powerpc/include/asm/jump_label.h | 23 +++++++++++++----------
1 file changed, 13 insertions(+), 10 deletions(-)
diff --git a/arch/powerpc/include/asm/jump_label.h b/arch/powerpc/include/asm/jump_label.h
index d4eaba459a0e..3016e9c8d6bc 100644
--- a/arch/powerpc/include/asm/jump_label.h
+++ b/arch/powerpc/include/asm/jump_label.h
@@ -15,14 +15,20 @@
#define JUMP_ENTRY_TYPE stringify_in_c(FTR_ENTRY_LONG)
#define JUMP_LABEL_NOP_SIZE 4
+#define JUMP_TABLE_ENTRY(key, label) \
+ ".pushsection __jump_table, \"aw\" \n\t" \
+ ".long 1b - ., " label " - . \n\t" \
+ JUMP_ENTRY_TYPE key " - . \n\t" \
+ ".popsection \n\t"
+
+#define ARCH_STATIC_BRANCH_ASM(key, label) \
+ "1: nop \n\t" \
+ JUMP_TABLE_ENTRY(key, label)
+
static __always_inline bool arch_static_branch(struct static_key *key, bool branch)
{
- asm goto("1:\n\t"
- "nop # arch_static_branch\n\t"
- ".pushsection __jump_table, \"aw\"\n\t"
- ".long 1b - ., %l[l_yes] - .\n\t"
- JUMP_ENTRY_TYPE "%c0 - .\n\t"
- ".popsection \n\t"
+ asm goto(
+ ARCH_STATIC_BRANCH_ASM("%c0", "%l[l_yes]")
: : "i" (&((char *)key)[branch]) : : l_yes);
return false;
@@ -34,10 +40,7 @@ static __always_inline bool arch_static_branch_jump(struct static_key *key, bool
{
asm goto("1:\n\t"
"b %l[l_yes] # arch_static_branch_jump\n\t"
- ".pushsection __jump_table, \"aw\"\n\t"
- ".long 1b - ., %l[l_yes] - .\n\t"
- JUMP_ENTRY_TYPE "%c0 - .\n\t"
- ".popsection \n\t"
+ JUMP_TABLE_ENTRY("%c0", "%l[l_yes]")
: : "i" (&((char *)key)[branch]) : : l_yes);
return false;
--
2.55.0
^ 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