* [PATCH v8 10/20] KVM: selftests: Add a helper to set proc IRQ affinity for IRQ test
From: Sean Christopherson @ 2026-06-26 21:35 UTC (permalink / raw)
To: Paolo Bonzini, Marc Zyngier, Oliver Upton, Sean Christopherson
Cc: Joey Gouly, Steffen Eiden, Suzuki K Poulose, Zenghui Yu, kvm,
linux-arm-kernel, kvmarm, linux-kernel, David Matlack, Josh Hilke
In-Reply-To: <20260626213534.3866178-1-seanjc@google.com>
From: Josh Hilke <jrhilke@google.com>
Add a utility, proc_irq_set_smp_affinity(), to set the CPU affinity of a
Linux host IRQ via the proc filesystem. Use smp_affinity_list instead of
smp_affinity to avoid having to convert the single CPU to a bitmask.
The helper will be used by the eventfd IRQ test to verify delivery of IRQs
when the affinity is randomized/modified.
Signed-off-by: Josh Hilke <jrhilke@google.com>
[sean: make the utility self-contained, drop "list", massage changelog]
Signed-off-by: Sean Christopherson <seanjc@google.com>
---
tools/testing/selftests/kvm/include/proc_util.h | 2 ++
tools/testing/selftests/kvm/lib/proc_util.c | 14 ++++++++++++++
2 files changed, 16 insertions(+)
diff --git a/tools/testing/selftests/kvm/include/proc_util.h b/tools/testing/selftests/kvm/include/proc_util.h
index 704839b6d7af..d1ddc967d11d 100644
--- a/tools/testing/selftests/kvm/include/proc_util.h
+++ b/tools/testing/selftests/kvm/include/proc_util.h
@@ -6,4 +6,6 @@
unsigned int vfio_msix_to_host_irq(const char *vfio_device_bdf, int msix);
+void proc_irq_set_smp_affinity(unsigned int irq, int cpu);
+
#endif /* SELFTEST_KVM_PROC_UTIL_H */
diff --git a/tools/testing/selftests/kvm/lib/proc_util.c b/tools/testing/selftests/kvm/lib/proc_util.c
index 84d30f055a0a..3960b3841d63 100644
--- a/tools/testing/selftests/kvm/lib/proc_util.c
+++ b/tools/testing/selftests/kvm/lib/proc_util.c
@@ -38,3 +38,17 @@ unsigned int vfio_msix_to_host_irq(const char *device_bdf, int msix)
return (unsigned int)irq;
}
+void proc_irq_set_smp_affinity(unsigned int irq, int cpu)
+{
+ char path[PATH_MAX];
+ int r, fd;
+
+ snprintf(path, sizeof(path), "/proc/irq/%u/smp_affinity_list", irq);
+ fd = open(path, O_RDWR);
+ TEST_ASSERT(fd >= 0, "Failed to open %s", path);
+
+ r = dprintf(fd, "%d\n", cpu);
+ TEST_ASSERT(r > 0, "Failed to affinitize IRQ-%u to CPU %d", irq, cpu);
+
+ kvm_close(fd);
+}
--
2.55.0.rc0.799.gd6f94ed593-goog
^ permalink raw reply related
* [PATCH v8 06/20] KVM: selftests: Add helper to generate random u64 in range [min,max]
From: Sean Christopherson @ 2026-06-26 21:35 UTC (permalink / raw)
To: Paolo Bonzini, Marc Zyngier, Oliver Upton, Sean Christopherson
Cc: Joey Gouly, Steffen Eiden, Suzuki K Poulose, Zenghui Yu, kvm,
linux-arm-kernel, kvmarm, linux-kernel, David Matlack, Josh Hilke
In-Reply-To: <20260626213534.3866178-1-seanjc@google.com>
From: Josh Hilke <jrhilke@google.com>
Introduce kvm_random_u64_in_range(state, min, max). This function
returns a random u64 in the inclusive range of [min, max] using a struct
kvm_random_state.
Suggested-by: Sean Christopherson <seanjc@google.com>
Signed-off-by: Josh Hilke <jrhilke@google.com>
Signed-off-by: Sean Christopherson <seanjc@google.com>
---
.../testing/selftests/kvm/include/test_util.h | 3 +++
tools/testing/selftests/kvm/lib/test_util.c | 18 ++++++++++++++++++
2 files changed, 21 insertions(+)
diff --git a/tools/testing/selftests/kvm/include/test_util.h b/tools/testing/selftests/kvm/include/test_util.h
index 44c0104d60ac..d64c8a228207 100644
--- a/tools/testing/selftests/kvm/include/test_util.h
+++ b/tools/testing/selftests/kvm/include/test_util.h
@@ -134,6 +134,9 @@ static inline u64 kvm_random_u64(struct kvm_random_state *state)
return ((u64)kvm_random_u32(state) << 32) | kvm_random_u32(state);
}
+u64 kvm_random_u64_in_range(struct kvm_random_state *state, u64 min,
+ u64 max);
+
enum vm_mem_backing_src_type {
VM_MEM_SRC_ANONYMOUS,
VM_MEM_SRC_ANONYMOUS_THP,
diff --git a/tools/testing/selftests/kvm/lib/test_util.c b/tools/testing/selftests/kvm/lib/test_util.c
index e98ca7ef439c..e208a57f190c 100644
--- a/tools/testing/selftests/kvm/lib/test_util.c
+++ b/tools/testing/selftests/kvm/lib/test_util.c
@@ -42,6 +42,24 @@ u32 kvm_random_u32(struct kvm_random_state *state)
return state->seed;
}
+/* Returns a random u64 in the inclusive range [min, max] */
+u64 kvm_random_u64_in_range(struct kvm_random_state *state, u64 min,
+ u64 max)
+{
+ u64 value;
+ u64 range;
+
+ TEST_ASSERT(min <= max, "PEBKAC, min = 0x%lx, max = 0x%lx", min, max);
+
+ value = kvm_random_u64(state);
+
+ range = max - min;
+ if (range == ULLONG_MAX)
+ return value;
+
+ return min + (value % (range + 1));
+}
+
/*
* Parses "[0-9]+[kmgt]?".
*/
--
2.55.0.rc0.799.gd6f94ed593-goog
^ permalink raw reply related
* [PATCH v8 07/20] KVM: selftests: Add an irqfd send+receive (and later IRQ bypass) test
From: Sean Christopherson @ 2026-06-26 21:35 UTC (permalink / raw)
To: Paolo Bonzini, Marc Zyngier, Oliver Upton, Sean Christopherson
Cc: Joey Gouly, Steffen Eiden, Suzuki K Poulose, Zenghui Yu, kvm,
linux-arm-kernel, kvmarm, linux-kernel, David Matlack, Josh Hilke
In-Reply-To: <20260626213534.3866178-1-seanjc@google.com>
From: David Matlack <dmatlack@google.com>
Add a new test, irq_test to verify that KVM correctly delivers interrupts
to a running vCPU, when triggered via an eventfd bound to a KVM GSI using
KVM's irqfd mechanism.
This test is intentionally simple, for now. Support for sending interrupts
via VFIO devices, for IRQ bypass, and for other features will be added in
the near future.
Add the test in common code, even though it currently will only build and
run on x86, as the concept and the bulk of the host-side code isn't
specific to x86.
Suggested-by: Sean Christopherson <seanjc@google.com>
Link: https://lore.kernel.org/kvm/20250404193923.1413163-68-seanjc@google.com
Signed-off-by: David Matlack <dmatlack@google.com>
Co-developed-by: Josh Hilke <jrhilke@google.com>
Signed-off-by: Josh Hilke <jrhilke@google.com>
[sean: use while() and TEST_ASSERT() instead of if-statement => TEST_FAIL()]
Signed-off-by: Sean Christopherson <seanjc@google.com>
---
tools/testing/selftests/kvm/Makefile.kvm | 1 +
tools/testing/selftests/kvm/irq_test.c | 170 +++++++++++++++++++++++
2 files changed, 171 insertions(+)
create mode 100644 tools/testing/selftests/kvm/irq_test.c
diff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selftests/kvm/Makefile.kvm
index ae0dfd67dd31..a24875fada03 100644
--- a/tools/testing/selftests/kvm/Makefile.kvm
+++ b/tools/testing/selftests/kvm/Makefile.kvm
@@ -157,6 +157,7 @@ TEST_GEN_PROGS_x86 += coalesced_io_test
TEST_GEN_PROGS_x86 += dirty_log_perf_test
TEST_GEN_PROGS_x86 += guest_memfd_test
TEST_GEN_PROGS_x86 += hardware_disable_test
+TEST_GEN_PROGS_x86 += irq_test
TEST_GEN_PROGS_x86 += mmu_stress_test
TEST_GEN_PROGS_x86 += rseq_test
TEST_GEN_PROGS_x86 += steal_time
diff --git a/tools/testing/selftests/kvm/irq_test.c b/tools/testing/selftests/kvm/irq_test.c
new file mode 100644
index 000000000000..9f8895b89821
--- /dev/null
+++ b/tools/testing/selftests/kvm/irq_test.c
@@ -0,0 +1,170 @@
+// SPDX-License-Identifier: GPL-2.0
+#include "kvm_util.h"
+#include "test_util.h"
+#include "apic.h"
+#include "processor.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <sys/eventfd.h>
+
+static u64 timeout_ns = 2ULL * 1000 * 1000 * 1000;
+static bool guest_ready_for_irqs[KVM_MAX_VCPUS];
+static bool guest_received_irq[KVM_MAX_VCPUS];
+static bool done;
+
+#define GUEST_RECEIVED_IRQ(__vcpu) \
+ SYNC_FROM_GUEST_AND_READ((__vcpu)->vm, guest_received_irq[(__vcpu)->id])
+
+static u32 guest_get_vcpu_id(void)
+{
+ return x2apic_read_reg(APIC_ID);
+}
+
+static void guest_irq_handler(struct ex_regs *regs)
+{
+ WRITE_ONCE(guest_received_irq[guest_get_vcpu_id()], true);
+
+ x2apic_write_reg(APIC_EOI, 0);
+}
+
+static void guest_code(void)
+{
+ x2apic_enable();
+
+ sti_nop();
+
+ WRITE_ONCE(guest_ready_for_irqs[guest_get_vcpu_id()], true);
+
+ while (!READ_ONCE(done))
+ cpu_relax();
+
+ GUEST_DONE();
+}
+
+static void *vcpu_thread_main(void *arg)
+{
+ struct kvm_vcpu *vcpu = arg;
+ struct ucall uc;
+
+ vcpu_run(vcpu);
+ TEST_ASSERT_EQ(UCALL_DONE, get_ucall(vcpu, &uc));
+
+ return NULL;
+}
+
+static void kvm_route_msi(struct kvm_vm *vm, u32 gsi, struct kvm_vcpu *vcpu,
+ u8 vector)
+{
+ struct {
+ struct kvm_irq_routing header;
+ struct kvm_irq_routing_entry entry;
+ } routing = {
+ .header.nr = 1,
+ .entry = {
+ .gsi = gsi,
+ .type = KVM_IRQ_ROUTING_MSI,
+ .u.msi.address_lo = 0xFEE00000 | (vcpu->id << 12),
+ .u.msi.data = vector,
+ },
+ };
+
+ vm_ioctl(vm, KVM_SET_GSI_ROUTING, &routing.header);
+}
+
+static void help(const char *name)
+{
+ printf("Usage: %s [-h]\n", name);
+ printf("\n");
+ printf("Tests KVM interrupt routing and delivery via irqfd.\n");
+ printf("\n");
+ exit(KSFT_FAIL);
+}
+
+int main(int argc, char **argv)
+{
+ /*
+ * Pick a random vector and a random GSI to use for device IRQ.
+ *
+ * Pick an IRQ vector in range [32, UINT8_MAX]. Min value is 32 because
+ * Linux/x86 reserves vectors 0-31 for exceptions and architecture
+ * defined NMIs and interrupts.
+ *
+ * Pick a GSI in range [24, KVM_MAX_IRQ_ROUTES - 1]. The min value is 24
+ * because KVM reserves GSIs 0-15 for legacy ISA IRQs and 16-23 only go
+ * to the IOAPIC. The max is KVM_MAX_IRQ_ROUTES - 1, because
+ * KVM_MAX_IRQ_ROUTES is exclusive.
+ */
+ u32 gsi = kvm_random_u64_in_range(&kvm_rng, 24, KVM_MAX_IRQ_ROUTES - 1);
+ u8 vector = kvm_random_u64_in_range(&kvm_rng, 32, UINT8_MAX);
+
+ struct kvm_vcpu *vcpus[KVM_MAX_VCPUS];
+ pthread_t vcpu_threads[KVM_MAX_VCPUS];
+ int nr_irqs = 1000, nr_vcpus = 1;
+ int i, j, c, eventfd;
+ struct kvm_vm *vm;
+
+ while ((c = getopt(argc, argv, "h")) != -1) {
+ switch (c) {
+ case 'h':
+ default:
+ help(argv[0]);
+ }
+ }
+
+ TEST_REQUIRE(kvm_arch_has_default_irqchip());
+
+ vm = vm_create_with_vcpus(nr_vcpus, guest_code, vcpus);
+ vm_install_exception_handler(vm, vector, guest_irq_handler);
+
+ eventfd = kvm_new_eventfd();
+
+ pr_info("Injecting interrupts for GSI %d (guest vector 0x%x) %d times\n",
+ gsi, vector, nr_irqs);
+
+ kvm_assign_irqfd(vm, gsi, eventfd);
+
+ for (i = 0; i < nr_vcpus; i++)
+ pthread_create(&vcpu_threads[i], NULL, vcpu_thread_main, vcpus[i]);
+
+ for (i = 0; i < nr_vcpus; i++) {
+ struct kvm_vcpu *vcpu = vcpus[i];
+
+ while (!SYNC_FROM_GUEST_AND_READ(vm, guest_ready_for_irqs[vcpu->id]))
+ continue;
+ }
+
+ for (i = 0; i < nr_irqs; i++) {
+ struct kvm_vcpu *vcpu = vcpus[i % nr_vcpus];
+ struct timespec start;
+
+ kvm_route_msi(vm, gsi, vcpu, vector);
+
+ for (j = 0; j < nr_vcpus; j++)
+ TEST_ASSERT(!GUEST_RECEIVED_IRQ(vcpus[j]),
+ "IRQ flag for vCPU %d not clear prior to test",
+ vcpus[j]->id);
+
+ eventfd_write(eventfd, 1);
+
+ clock_gettime(CLOCK_MONOTONIC, &start);
+ while (!GUEST_RECEIVED_IRQ(vcpu) &&
+ timespec_to_ns(timespec_elapsed(start)) <= timeout_ns)
+ cpu_relax();
+
+ TEST_ASSERT(GUEST_RECEIVED_IRQ(vcpu),
+ "vCPU %d timed out waiting for IRQ (vector 0x%x) from GSI %d\n",
+ vcpu->id, vector, gsi);
+
+ WRITE_AND_SYNC_TO_GUEST(vm, guest_received_irq[vcpu->id], false);
+ }
+
+ WRITE_AND_SYNC_TO_GUEST(vm, done, true);
+
+ for (i = 0; i < nr_vcpus; i++)
+ pthread_join(vcpu_threads[i], NULL);
+
+ return 0;
+}
--
2.55.0.rc0.799.gd6f94ed593-goog
^ permalink raw reply related
* [PATCH v8 13/20] KVM: selftests: Make number of IRQs configurable in IRQ test
From: Sean Christopherson @ 2026-06-26 21:35 UTC (permalink / raw)
To: Paolo Bonzini, Marc Zyngier, Oliver Upton, Sean Christopherson
Cc: Joey Gouly, Steffen Eiden, Suzuki K Poulose, Zenghui Yu, kvm,
linux-arm-kernel, kvmarm, linux-kernel, David Matlack, Josh Hilke
In-Reply-To: <20260626213534.3866178-1-seanjc@google.com>
From: David Matlack <dmatlack@google.com>
Extend the eventfd IRQ test with a '-i' flag to let the user specify the
the number of IRQs to generate (instead of hardcoding the test to always
generate 1000 interrupts).
Signed-off-by: David Matlack <dmatlack@google.com>
Co-developed-by: Josh Hilke <jrhilke@google.com>
Signed-off-by: Josh Hilke <jrhilke@google.com>
[sean: massage changelog]
Signed-off-by: Sean Christopherson <seanjc@google.com>
---
tools/testing/selftests/kvm/irq_test.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/tools/testing/selftests/kvm/irq_test.c b/tools/testing/selftests/kvm/irq_test.c
index fd03ec940362..bb20bb81e930 100644
--- a/tools/testing/selftests/kvm/irq_test.c
+++ b/tools/testing/selftests/kvm/irq_test.c
@@ -146,12 +146,13 @@ static const char *probe_iommu_type(void)
static void help(const char *name)
{
- printf("Usage: %s [-a] [-d <segment:bus:device.function>] [-e] [-h] [-t iommu_type]\n", name);
+ printf("Usage: %s [-a] [-d <segment:bus:device.function>] [-e] [-h] [-i nr_irqs] [-t iommu_type]\n", name);
printf("\n");
printf("Tests KVM interrupt routing and delivery via irqfd.\n");
printf("-a Affine the device's host IRQ to a random physical CPU\n");
printf("-d Use a VFIO device to send MSI-X interrupts instead of manually signaling the eventfd\n");
printf("-e Set empty GSI routing in-between some interrupts\n");
+ printf("-i The number of IRQs to generate during the test\n");
printf("-t Override the IOMMU type to use (vfio_type1_iommu or iommufd)\n");
printf("\n");
exit(KSFT_FAIL);
@@ -186,7 +187,7 @@ int main(int argc, char **argv)
struct kvm_vm *vm;
int irq, irq_cpu;
- while ((c = getopt(argc, argv, "ad:eht:")) != -1) {
+ while ((c = getopt(argc, argv, "ad:ehi:t:")) != -1) {
switch (c) {
case 'a':
irq_affinity = true;
@@ -197,6 +198,9 @@ int main(int argc, char **argv)
case 'e':
set_empty_routing = true;
break;
+ case 'i':
+ nr_irqs = atoi_positive("Number of IRQs", optarg);
+ break;
case 't':
iommu_type = optarg;
break;
--
2.55.0.rc0.799.gd6f94ed593-goog
^ permalink raw reply related
* [PATCH v8 14/20] KVM: selftests: Verify non-postable IRQ remapping in IRQ test
From: Sean Christopherson @ 2026-06-26 21:35 UTC (permalink / raw)
To: Paolo Bonzini, Marc Zyngier, Oliver Upton, Sean Christopherson
Cc: Joey Gouly, Steffen Eiden, Suzuki K Poulose, Zenghui Yu, kvm,
linux-arm-kernel, kvmarm, linux-kernel, David Matlack, Josh Hilke
In-Reply-To: <20260626213534.3866178-1-seanjc@google.com>
Extend the eventfd IRQ test with an '-n' flag to route a subset of device
interrupts as NMIs (Non-Maskable Interrupts) into the guest using an
alternating pattern of 4 NMIs followed by 4 regular interrupts.
While this adds coverage for NMI injection, the primary goal is to
validate KVM's handling of non-postable interrupt delivery (AMD and Intel
IOMMUs only support posting fixed IRQs targeting a single vCPU). KVM
has historically bungled handling transitions between posted and remapped
modes. Use NMIs to stress the transitions, because they are a reliable,
architectural way to force these code paths.
Signed-off-by: David Matlack <dmatlack@google.com>
Co-developed-by: Josh Hilke <jrhilke@google.com>
Signed-off-by: Josh Hilke <jrhilke@google.com>
[sean: add GUEST_RECEIVED_INTERRUPT(), massage changelog]
Signed-off-by: Sean Christopherson <seanjc@google.com>
---
tools/testing/selftests/kvm/irq_test.c | 48 ++++++++++++++++++++------
1 file changed, 37 insertions(+), 11 deletions(-)
diff --git a/tools/testing/selftests/kvm/irq_test.c b/tools/testing/selftests/kvm/irq_test.c
index bb20bb81e930..48520c6dea69 100644
--- a/tools/testing/selftests/kvm/irq_test.c
+++ b/tools/testing/selftests/kvm/irq_test.c
@@ -17,11 +17,17 @@
static u64 timeout_ns = 2ULL * 1000 * 1000 * 1000;
static bool guest_ready_for_irqs[KVM_MAX_VCPUS];
static bool guest_received_irq[KVM_MAX_VCPUS];
+static bool guest_received_nmi[KVM_MAX_VCPUS];
static bool irq_affinity;
static bool done;
#define GUEST_RECEIVED_IRQ(__vcpu) \
SYNC_FROM_GUEST_AND_READ((__vcpu)->vm, guest_received_irq[(__vcpu)->id])
+#define GUEST_RECEIVED_NMI(__vcpu) \
+ SYNC_FROM_GUEST_AND_READ((__vcpu)->vm, guest_received_nmi[(__vcpu)->id])
+
+#define GUEST_RECEIVED_INTERRUPT(__vcpu, __nmi) \
+ ((__nmi) ? GUEST_RECEIVED_NMI(__vcpu) : GUEST_RECEIVED_IRQ(__vcpu))
static u32 guest_get_vcpu_id(void)
{
@@ -35,6 +41,11 @@ static void guest_irq_handler(struct ex_regs *regs)
x2apic_write_reg(APIC_EOI, 0);
}
+static void guest_nmi_handler(struct ex_regs *regs)
+{
+ WRITE_ONCE(guest_received_nmi[guest_get_vcpu_id()], true);
+}
+
static void guest_code(void)
{
x2apic_enable();
@@ -103,7 +114,7 @@ static void trigger_interrupt(struct vfio_pci_device *device, int eventfd)
static void kvm_route_msi(struct kvm_vm *vm, u32 gsi, struct kvm_vcpu *vcpu,
- u8 vector)
+ u8 vector, bool use_nmi)
{
struct {
struct kvm_irq_routing header;
@@ -114,7 +125,7 @@ static void kvm_route_msi(struct kvm_vm *vm, u32 gsi, struct kvm_vcpu *vcpu,
.gsi = gsi,
.type = KVM_IRQ_ROUTING_MSI,
.u.msi.address_lo = 0xFEE00000 | (vcpu->id << 12),
- .u.msi.data = vector,
+ .u.msi.data = use_nmi ? NMI_VECTOR | (4 << 8) : vector,
},
};
@@ -146,13 +157,14 @@ static const char *probe_iommu_type(void)
static void help(const char *name)
{
- printf("Usage: %s [-a] [-d <segment:bus:device.function>] [-e] [-h] [-i nr_irqs] [-t iommu_type]\n", name);
+ printf("Usage: %s [-a] [-d <segment:bus:device.function>] [-e] [-h] [-i nr_irqs] [-n] [-t iommu_type]\n", name);
printf("\n");
printf("Tests KVM interrupt routing and delivery via irqfd.\n");
printf("-a Affine the device's host IRQ to a random physical CPU\n");
printf("-d Use a VFIO device to send MSI-X interrupts instead of manually signaling the eventfd\n");
printf("-e Set empty GSI routing in-between some interrupts\n");
printf("-i The number of IRQs to generate during the test\n");
+ printf("-n Deliver 50 percent of IRQs as non-maskable interrupts\n");
printf("-t Override the IOMMU type to use (vfio_type1_iommu or iommufd)\n");
printf("\n");
exit(KSFT_FAIL);
@@ -183,11 +195,12 @@ int main(int argc, char **argv)
const char *device_bdf = NULL;
const char *iommu_type = NULL;
int i, j, c, msix, eventfd;
+ bool use_nmi = false;
struct iommu *iommu;
struct kvm_vm *vm;
int irq, irq_cpu;
- while ((c = getopt(argc, argv, "ad:ehi:t:")) != -1) {
+ while ((c = getopt(argc, argv, "ad:ehi:nt:")) != -1) {
switch (c) {
case 'a':
irq_affinity = true;
@@ -201,6 +214,9 @@ int main(int argc, char **argv)
case 'i':
nr_irqs = atoi_positive("Number of IRQs", optarg);
break;
+ case 'n':
+ use_nmi = true;
+ break;
case 't':
iommu_type = optarg;
break;
@@ -214,6 +230,7 @@ int main(int argc, char **argv)
vm = vm_create_with_vcpus(nr_vcpus, guest_code, vcpus);
vm_install_exception_handler(vm, vector, guest_irq_handler);
+ vm_install_exception_handler(vm, NMI_VECTOR, guest_nmi_handler);
if (device_bdf) {
if (!iommu_type)
@@ -251,36 +268,45 @@ int main(int argc, char **argv)
for (i = 0; i < nr_irqs; i++) {
const bool do_set_empty_routing = set_empty_routing && (i & BIT(3));
+ const bool do_use_nmi = use_nmi && (i & BIT(2));
struct kvm_vcpu *vcpu = vcpus[i % nr_vcpus];
struct timespec start;
if (do_set_empty_routing)
kvm_set_empty_gsi_routing(vm);
- kvm_route_msi(vm, gsi, vcpu, vector);
+ kvm_route_msi(vm, gsi, vcpu, vector, do_use_nmi);
if (irq_affinity) {
irq_cpu = kvm_random_u64(&kvm_rng) % get_nprocs();
proc_irq_set_smp_affinity(irq, irq_cpu);
}
- for (j = 0; j < nr_vcpus; j++)
+ for (j = 0; j < nr_vcpus; j++) {
TEST_ASSERT(!GUEST_RECEIVED_IRQ(vcpus[j]),
"IRQ flag for vCPU %d not clear prior to test",
vcpus[j]->id);
+ TEST_ASSERT(!GUEST_RECEIVED_NMI(vcpus[j]),
+ "NMI flag for vCPU %d not clear prior to test",
+ vcpus[j]->id);
+ }
trigger_interrupt(device, eventfd);
clock_gettime(CLOCK_MONOTONIC, &start);
- while (!GUEST_RECEIVED_IRQ(vcpu) &&
+ while (!GUEST_RECEIVED_INTERRUPT(vcpu, do_use_nmi) &&
timespec_to_ns(timespec_elapsed(start)) <= timeout_ns)
cpu_relax();
- TEST_ASSERT(GUEST_RECEIVED_IRQ(vcpu),
- "vCPU %d timed out waiting for IRQ (vector 0x%x) from GSI %d (via CPU %d)\n",
- vcpu->id, vector, gsi, irq_cpu);
+ TEST_ASSERT(GUEST_RECEIVED_INTERRUPT(vcpu, do_use_nmi),
+ "vCPU %d timed out waiting for %s (vector 0x%x) from GSI %d (via CPU %d)\n",
+ vcpu->id, do_use_nmi ? "NMI" : "IRQ",
+ do_use_nmi ? NMI_VECTOR : vector, gsi, irq_cpu);
- WRITE_AND_SYNC_TO_GUEST(vm, guest_received_irq[vcpu->id], false);
+ if (do_use_nmi)
+ WRITE_AND_SYNC_TO_GUEST(vm, guest_received_nmi[vcpu->id], false);
+ else
+ WRITE_AND_SYNC_TO_GUEST(vm, guest_received_irq[vcpu->id], false);
}
WRITE_AND_SYNC_TO_GUEST(vm, done, true);
--
2.55.0.rc0.799.gd6f94ed593-goog
^ permalink raw reply related
* Re: [PATCH] usb: dwc3: st: Propagate reset deassert failures
From: Thinh Nguyen @ 2026-06-26 22:07 UTC (permalink / raw)
To: Pengpeng Hou
Cc: Patrice Chotard, Thinh Nguyen, Greg Kroah-Hartman, Philipp Zabel,
linux-arm-kernel@lists.infradead.org, linux-usb@vger.kernel.org,
linux-kernel@vger.kernel.org
In-Reply-To: <20260624055728.46078-1-pengpeng@iscas.ac.cn>
On Wed, Jun 24, 2026, Pengpeng Hou wrote:
> The ST DWC3 glue driver treats the powerdown and softreset reset
> controls as required resources, but ignores reset_control_deassert()
> failures before populating the child DWC3 device. Resume ignores the
> same failures before returning success.
>
> Check the deassert operations and unwind the already deasserted
> powerdown reset if softreset deassertion fails.
>
> Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>
> ---
> drivers/usb/dwc3/dwc3-st.c | 19 +++++++++++++++----
> 1 file changed, 15 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/usb/dwc3/dwc3-st.c b/drivers/usb/dwc3/dwc3-st.c
> index 5d513decaacd..bbabfd933798 100644
> --- a/drivers/usb/dwc3/dwc3-st.c
> +++ b/drivers/usb/dwc3/dwc3-st.c
> @@ -242,7 +242,9 @@ static int st_dwc3_probe(struct platform_device *pdev)
> "could not get power controller\n");
>
> /* Manage PowerDown */
> - reset_control_deassert(dwc3_data->rstc_pwrdn);
> + ret = reset_control_deassert(dwc3_data->rstc_pwrdn);
> + if (ret)
> + return ret;
>
> dwc3_data->rstc_rst =
> devm_reset_control_get_shared(dev, "softreset");
> @@ -253,7 +255,9 @@ static int st_dwc3_probe(struct platform_device *pdev)
> }
>
> /* Manage SoftReset */
> - reset_control_deassert(dwc3_data->rstc_rst);
> + ret = reset_control_deassert(dwc3_data->rstc_rst);
> + if (ret)
> + goto undo_powerdown;
This should goto undo_softreset instead of undo_powerdown.
BR,
Thinh
^ permalink raw reply
* [PATCH v8 19/20] KVM: selftests: Make number of vCPUs configurable in IRQ test
From: Sean Christopherson @ 2026-06-26 21:35 UTC (permalink / raw)
To: Paolo Bonzini, Marc Zyngier, Oliver Upton, Sean Christopherson
Cc: Joey Gouly, Steffen Eiden, Suzuki K Poulose, Zenghui Yu, kvm,
linux-arm-kernel, kvmarm, linux-kernel, David Matlack, Josh Hilke
In-Reply-To: <20260626213534.3866178-1-seanjc@google.com>
From: David Matlack <dmatlack@google.com>
Extend the eventfd IRQ test with a '-v' flag to allow the user to
configure the number of vCPUs to create and run (versus only ever using a
single vCPU).
Update the routing logic to play nice with 32 bit IDs, enable x2APIC format
in KVM (to enable 32-bit ID routing), and disable KVM's x2APIC broadcast
quirk so that targeting vCPU 255 doesn't blast the interrupt to all vCPUs
when in x2APIC mode.
Signed-off-by: David Matlack <dmatlack@google.com>
Co-developed-by: Josh Hilke <jrhilke@google.com>
Signed-off-by: Josh Hilke <jrhilke@google.com>
Co-developed-by: Sean Christopherson <seanjc@google.com>
Signed-off-by: Sean Christopherson <seanjc@google.com>
---
tools/testing/selftests/kvm/irq_test.c | 16 +++++++++++++---
1 file changed, 13 insertions(+), 3 deletions(-)
diff --git a/tools/testing/selftests/kvm/irq_test.c b/tools/testing/selftests/kvm/irq_test.c
index c0ff6e60b167..d2c745c54960 100644
--- a/tools/testing/selftests/kvm/irq_test.c
+++ b/tools/testing/selftests/kvm/irq_test.c
@@ -124,7 +124,8 @@ static void kvm_route_msi(struct kvm_vm *vm, u32 gsi, struct kvm_vcpu *vcpu,
.entry = {
.gsi = gsi,
.type = KVM_IRQ_ROUTING_MSI,
- .u.msi.address_lo = 0xFEE00000 | (vcpu->id << 12),
+ .u.msi.address_lo = 0xFEE00000 | (vcpu->id & GENMASK(7, 0)) << 12,
+ .u.msi.address_hi = vcpu->id & GENMASK(31, 8),
.u.msi.data = use_nmi ? NMI_VECTOR | (4 << 8) : vector,
},
};
@@ -157,7 +158,7 @@ static const char *probe_iommu_type(void)
static void help(const char *name)
{
- printf("Usage: %s [-a] [-d <segment:bus:device.function>] [-e] [-h] [-i nr_irqs] [-m] [-n] [-t iommu_type]\n", name);
+ printf("Usage: %s [-a] [-d <segment:bus:device.function>] [-e] [-h] [-i nr_irqs] [-m] [-n] [-t iommu_type] [-v nr_vcpus]\n", name);
printf("\n");
printf("Tests KVM interrupt routing and delivery via irqfd.\n");
printf("-a Affine the device's host IRQ to a random physical CPU\n");
@@ -167,6 +168,7 @@ static void help(const char *name)
printf("-m Pin target vCPU to random physical CPU before triggering interrupt\n");
printf("-n Deliver 50 percent of IRQs as non-maskable interrupts\n");
printf("-t Override the IOMMU type to use (vfio_type1_iommu or iommufd)\n");
+ printf("-v Number of vCPUS to run\n");
printf("\n");
exit(KSFT_FAIL);
}
@@ -203,7 +205,7 @@ int main(int argc, char **argv)
struct kvm_vm *vm;
int irq, irq_cpu;
- while ((c = getopt(argc, argv, "ad:ehi:mnt:")) != -1) {
+ while ((c = getopt(argc, argv, "ad:ehi:mnt:v:")) != -1) {
switch (c) {
case 'a':
irq_affinity = true;
@@ -226,6 +228,11 @@ int main(int argc, char **argv)
case 't':
iommu_type = optarg;
break;
+ case 'v':
+ nr_vcpus = atoi_positive("Number of vCPUS", optarg);
+ TEST_ASSERT(nr_vcpus <= KVM_MAX_VCPUS,
+ "KVM selftests support at most %u vCPUs", KVM_MAX_VCPUS);
+ break;
case 'h':
default:
help(argv[0]);
@@ -235,6 +242,9 @@ int main(int argc, char **argv)
TEST_REQUIRE(kvm_arch_has_default_irqchip());
vm = vm_create_with_vcpus(nr_vcpus, guest_code, vcpus);
+ vm_enable_cap(vm, KVM_CAP_X2APIC_API, KVM_X2APIC_API_USE_32BIT_IDS |
+ KVM_X2APIC_API_DISABLE_BROADCAST_QUIRK);
+
vm_install_exception_handler(vm, vector, guest_irq_handler);
vm_install_exception_handler(vm, NMI_VECTOR, guest_nmi_handler);
--
2.55.0.rc0.799.gd6f94ed593-goog
^ permalink raw reply related
* [PATCH v8 20/20] KVM: selftests: Add xAPIC support in eventfd IRQ test
From: Sean Christopherson @ 2026-06-26 21:35 UTC (permalink / raw)
To: Paolo Bonzini, Marc Zyngier, Oliver Upton, Sean Christopherson
Cc: Joey Gouly, Steffen Eiden, Suzuki K Poulose, Zenghui Yu, kvm,
linux-arm-kernel, kvmarm, linux-kernel, David Matlack, Josh Hilke
In-Reply-To: <20260626213534.3866178-1-seanjc@google.com>
From: David Matlack <dmatlack@google.com>
Extend the eventfd IRQ test with a '-x' flag to let the user run the test
in xAPIC mode instead of the default x2APIC mode. When using xAPIC mode,
sanity check user input to ensure the test is being run with at most 255
vCPUs, as xAPIC can only address IDs 0-254 (255, i.e. 0xff, broadcasts to
all CPUs).
Signed-off-by: David Matlack <dmatlack@google.com>
Co-developed-by: Josh Hilke <jrhilke@google.com>
Signed-off-by: Josh Hilke <jrhilke@google.com>
[sean: add sanity check on number of vCPUs]
Signed-off-by: Sean Christopherson <seanjc@google.com>
---
tools/testing/selftests/kvm/irq_test.c | 31 +++++++++++++++++++++-----
1 file changed, 26 insertions(+), 5 deletions(-)
diff --git a/tools/testing/selftests/kvm/irq_test.c b/tools/testing/selftests/kvm/irq_test.c
index d2c745c54960..240f6f0fdbe4 100644
--- a/tools/testing/selftests/kvm/irq_test.c
+++ b/tools/testing/selftests/kvm/irq_test.c
@@ -18,6 +18,7 @@ static u64 timeout_ns = 2ULL * 1000 * 1000 * 1000;
static bool guest_ready_for_irqs[KVM_MAX_VCPUS];
static bool guest_received_irq[KVM_MAX_VCPUS];
static bool guest_received_nmi[KVM_MAX_VCPUS];
+static bool x2apic = true;
static bool irq_affinity;
static bool done;
@@ -31,14 +32,20 @@ static bool done;
static u32 guest_get_vcpu_id(void)
{
- return x2apic_read_reg(APIC_ID);
+ if (x2apic)
+ return x2apic_read_reg(APIC_ID);
+ else
+ return xapic_read_reg(APIC_ID) >> 24;
}
static void guest_irq_handler(struct ex_regs *regs)
{
WRITE_ONCE(guest_received_irq[guest_get_vcpu_id()], true);
- x2apic_write_reg(APIC_EOI, 0);
+ if (x2apic)
+ x2apic_write_reg(APIC_EOI, 0);
+ else
+ xapic_write_reg(APIC_EOI, 0);
}
static void guest_nmi_handler(struct ex_regs *regs)
@@ -48,7 +55,10 @@ static void guest_nmi_handler(struct ex_regs *regs)
static void guest_code(void)
{
- x2apic_enable();
+ if (x2apic)
+ x2apic_enable();
+ else
+ xapic_enable();
sti_nop();
@@ -158,7 +168,7 @@ static const char *probe_iommu_type(void)
static void help(const char *name)
{
- printf("Usage: %s [-a] [-d <segment:bus:device.function>] [-e] [-h] [-i nr_irqs] [-m] [-n] [-t iommu_type] [-v nr_vcpus]\n", name);
+ printf("Usage: %s [-a] [-d <segment:bus:device.function>] [-e] [-h] [-i nr_irqs] [-m] [-n] [-t iommu_type] [-v nr_vcpus] [-x]\n", name);
printf("\n");
printf("Tests KVM interrupt routing and delivery via irqfd.\n");
printf("-a Affine the device's host IRQ to a random physical CPU\n");
@@ -169,6 +179,7 @@ static void help(const char *name)
printf("-n Deliver 50 percent of IRQs as non-maskable interrupts\n");
printf("-t Override the IOMMU type to use (vfio_type1_iommu or iommufd)\n");
printf("-v Number of vCPUS to run\n");
+ printf("-x Use xAPIC mode instead of x2APIC mode in the guest\n");
printf("\n");
exit(KSFT_FAIL);
}
@@ -205,7 +216,7 @@ int main(int argc, char **argv)
struct kvm_vm *vm;
int irq, irq_cpu;
- while ((c = getopt(argc, argv, "ad:ehi:mnt:v:")) != -1) {
+ while ((c = getopt(argc, argv, "ad:ehi:mnt:v:x")) != -1) {
switch (c) {
case 'a':
irq_affinity = true;
@@ -233,6 +244,9 @@ int main(int argc, char **argv)
TEST_ASSERT(nr_vcpus <= KVM_MAX_VCPUS,
"KVM selftests support at most %u vCPUs", KVM_MAX_VCPUS);
break;
+ case 'x':
+ x2apic = false;
+ break;
case 'h':
default:
help(argv[0]);
@@ -248,6 +262,11 @@ int main(int argc, char **argv)
vm_install_exception_handler(vm, vector, guest_irq_handler);
vm_install_exception_handler(vm, NMI_VECTOR, guest_nmi_handler);
+ if (!x2apic) {
+ TEST_ASSERT(nr_vcpus < 256, "xAPIC can only target IDs [0-254] (255 vCPUs)");
+ virt_pg_map(vm, APIC_DEFAULT_GPA, APIC_DEFAULT_GPA);
+ }
+
if (device_bdf) {
if (!iommu_type)
iommu_type = probe_iommu_type();
@@ -271,6 +290,8 @@ int main(int argc, char **argv)
kvm_assign_irqfd(vm, gsi, eventfd);
+ sync_global_to_guest(vm, x2apic);
+
if (migrate_vcpus)
kvm_sched_getaffinity(0, sizeof(available_cpus), &available_cpus);
--
2.55.0.rc0.799.gd6f94ed593-goog
^ permalink raw reply related
* [PATCH v8 18/20] KVM: selftests: Verify vCPU migration during IRQ delivery in IRQ test
From: Sean Christopherson @ 2026-06-26 21:35 UTC (permalink / raw)
To: Paolo Bonzini, Marc Zyngier, Oliver Upton, Sean Christopherson
Cc: Joey Gouly, Steffen Eiden, Suzuki K Poulose, Zenghui Yu, kvm,
linux-arm-kernel, kvmarm, linux-kernel, David Matlack, Josh Hilke
In-Reply-To: <20260626213534.3866178-1-seanjc@google.com>
From: David Matlack <dmatlack@google.com>
Extend the eventfd IRQ test with a '-m' flag to have the test migrate the
target vCPU to a random physical CPU before triggering its interrupt, e.g.
to validate KVM's ability to update device posted IRQ routing.
Signed-off-by: David Matlack <dmatlack@google.com>
Co-developed-by: Josh Hilke <jrhilke@google.com>
Signed-off-by: Josh Hilke <jrhilke@google.com>
[sean: pin one vCPU at a time to simplify things, use main()'s affinity]
Signed-off-by: Sean Christopherson <seanjc@google.com>
---
tools/testing/selftests/kvm/irq_test.c | 19 ++++++++++++++++---
1 file changed, 16 insertions(+), 3 deletions(-)
diff --git a/tools/testing/selftests/kvm/irq_test.c b/tools/testing/selftests/kvm/irq_test.c
index 48520c6dea69..c0ff6e60b167 100644
--- a/tools/testing/selftests/kvm/irq_test.c
+++ b/tools/testing/selftests/kvm/irq_test.c
@@ -157,13 +157,14 @@ static const char *probe_iommu_type(void)
static void help(const char *name)
{
- printf("Usage: %s [-a] [-d <segment:bus:device.function>] [-e] [-h] [-i nr_irqs] [-n] [-t iommu_type]\n", name);
+ printf("Usage: %s [-a] [-d <segment:bus:device.function>] [-e] [-h] [-i nr_irqs] [-m] [-n] [-t iommu_type]\n", name);
printf("\n");
printf("Tests KVM interrupt routing and delivery via irqfd.\n");
printf("-a Affine the device's host IRQ to a random physical CPU\n");
printf("-d Use a VFIO device to send MSI-X interrupts instead of manually signaling the eventfd\n");
printf("-e Set empty GSI routing in-between some interrupts\n");
printf("-i The number of IRQs to generate during the test\n");
+ printf("-m Pin target vCPU to random physical CPU before triggering interrupt\n");
printf("-n Deliver 50 percent of IRQs as non-maskable interrupts\n");
printf("-t Override the IOMMU type to use (vfio_type1_iommu or iommufd)\n");
printf("\n");
@@ -195,12 +196,14 @@ int main(int argc, char **argv)
const char *device_bdf = NULL;
const char *iommu_type = NULL;
int i, j, c, msix, eventfd;
+ bool migrate_vcpus = false;
+ cpu_set_t available_cpus;
bool use_nmi = false;
struct iommu *iommu;
struct kvm_vm *vm;
int irq, irq_cpu;
- while ((c = getopt(argc, argv, "ad:ehi:nt:")) != -1) {
+ while ((c = getopt(argc, argv, "ad:ehi:mnt:")) != -1) {
switch (c) {
case 'a':
irq_affinity = true;
@@ -214,6 +217,9 @@ int main(int argc, char **argv)
case 'i':
nr_irqs = atoi_positive("Number of IRQs", optarg);
break;
+ case 'm':
+ migrate_vcpus = true;
+ break;
case 'n':
use_nmi = true;
break;
@@ -248,7 +254,6 @@ int main(int argc, char **argv)
eventfd = kvm_new_eventfd();
irq = -1;
- irq_cpu = -1;
}
pr_info("Injecting interrupts for GSI %d (guest vector 0x%x) %d times\n",
@@ -256,6 +261,9 @@ int main(int argc, char **argv)
kvm_assign_irqfd(vm, gsi, eventfd);
+ if (migrate_vcpus)
+ kvm_sched_getaffinity(0, sizeof(available_cpus), &available_cpus);
+
for (i = 0; i < nr_vcpus; i++)
pthread_create(&vcpu_threads[i], NULL, vcpu_thread_main, vcpus[i]);
@@ -266,6 +274,8 @@ int main(int argc, char **argv)
continue;
}
+ irq_cpu = -1;
+
for (i = 0; i < nr_irqs; i++) {
const bool do_set_empty_routing = set_empty_routing && (i & BIT(3));
const bool do_use_nmi = use_nmi && (i & BIT(2));
@@ -282,6 +292,9 @@ int main(int argc, char **argv)
proc_irq_set_smp_affinity(irq, irq_cpu);
}
+ if (migrate_vcpus)
+ pin_task_to_random_cpu(vcpu_threads[i % nr_vcpus], &available_cpus);
+
for (j = 0; j < nr_vcpus; j++) {
TEST_ASSERT(!GUEST_RECEIVED_IRQ(vcpus[j]),
"IRQ flag for vCPU %d not clear prior to test",
--
2.55.0.rc0.799.gd6f94ed593-goog
^ permalink raw reply related
* [PATCH v8 17/20] KVM: selftests: Add a utility to pin a task to a random CPU, given a CPU set
From: Sean Christopherson @ 2026-06-26 21:35 UTC (permalink / raw)
To: Paolo Bonzini, Marc Zyngier, Oliver Upton, Sean Christopherson
Cc: Joey Gouly, Steffen Eiden, Suzuki K Poulose, Zenghui Yu, kvm,
linux-arm-kernel, kvmarm, linux-kernel, David Matlack, Josh Hilke
In-Reply-To: <20260626213534.3866178-1-seanjc@google.com>
From: Josh Hilke <jrhilke@google.com>
Add a helper function, pin_task_to_random_cpu(), to pin a task to a random
CPU from a given cpu_set_t.
This helper will be used eventfd IRQ test to migrate vCPUs to random pCPUs,
to stress host-side interrupt routing and delivery.
Suggested-by: Sean Christopherson <seanjc@google.com>
Signed-off-by: Josh Hilke <jrhilke@google.com>
[sean: massage changelog]
Signed-off-by: Sean Christopherson <seanjc@google.com>
---
.../testing/selftests/kvm/include/kvm_util.h | 2 ++
tools/testing/selftests/kvm/lib/kvm_util.c | 21 +++++++++++++++++++
2 files changed, 23 insertions(+)
diff --git a/tools/testing/selftests/kvm/include/kvm_util.h b/tools/testing/selftests/kvm/include/kvm_util.h
index c1f588154398..b39e713c30a4 100644
--- a/tools/testing/selftests/kvm/include/kvm_util.h
+++ b/tools/testing/selftests/kvm/include/kvm_util.h
@@ -1094,6 +1094,8 @@ static inline void pin_task_to_cpu(pthread_t task, int cpu)
TEST_ASSERT(!r, "Failed to set thread affinity to pCPU '%u'", cpu);
}
+void pin_task_to_random_cpu(pthread_t task, cpu_set_t *possible_cpus);
+
static inline int pin_task_to_any_cpu(pthread_t task)
{
int cpu = sched_getcpu();
diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c
index 6a0ee033fdef..3794575d2ca0 100644
--- a/tools/testing/selftests/kvm/lib/kvm_util.c
+++ b/tools/testing/selftests/kvm/lib/kvm_util.c
@@ -668,6 +668,27 @@ void kvm_print_vcpu_pinning_help(void)
" (default: no pinning)\n", name, name);
}
+void pin_task_to_random_cpu(pthread_t task, cpu_set_t *possible_cpus)
+{
+ int target_idx;
+ int nr_cpus;
+ int cpu;
+
+ nr_cpus = CPU_COUNT(possible_cpus);
+ TEST_ASSERT(nr_cpus > 0, "No CPUs available in possible_cpus");
+
+ target_idx = kvm_random_u64(&kvm_rng) % nr_cpus;
+
+ for (cpu = 0; cpu < CPU_SETSIZE; cpu++) {
+ if (CPU_ISSET(cpu, possible_cpus) && target_idx-- == 0) {
+ pin_task_to_cpu(task, cpu);
+ return;
+ }
+ }
+
+ TEST_FAIL("Failed to find random CPU in possible_cpus");
+}
+
void kvm_parse_vcpu_pinning(const char *pcpus_string, u32 vcpu_to_pcpu[],
int nr_vcpus)
{
--
2.55.0.rc0.799.gd6f94ed593-goog
^ permalink raw reply related
* Re: [PATCH v2] usb: dwc3: imx8mp: make dwc3_imx_glue_ops static and rename to imx8mp
From: Thinh Nguyen @ 2026-06-26 22:32 UTC (permalink / raw)
To: Ben Dooks
Cc: Thinh Nguyen, Greg Kroah-Hartman, Frank Li, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam, linux-usb@vger.kernel.org,
imx@lists.linux.dev, linux-arm-kernel@lists.infradead.org,
linux-kernel@vger.kernel.org
In-Reply-To: <20260623101043.748359-1-ben.dooks@codethink.co.uk>
On Tue, Jun 23, 2026, Ben Dooks wrote:
> The dwc3_imx_glue_ops is not used outside this file, and technically this
> is the dwc3-imx8mp driver so whilst making this static to avoid the
> following warning, rename it dwc3_imx8mp_glue_ops to distinguish it from
> the other driver which also has dwc3_imx_glue_ops.
>
> Fixes:
> drivers/usb/dwc3/dwc3-imx8mp.c:176:22: warning: symbol 'dwc3_imx_glue_ops' was not declared. Should it be static?
>
> Signed-off-by: Ben Dooks <ben.dooks@codethink.co.uk>
> ---
> drivers/usb/dwc3/dwc3-imx8mp.c | 8 ++++----
> 1 file changed, 4 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/usb/dwc3/dwc3-imx8mp.c b/drivers/usb/dwc3/dwc3-imx8mp.c
> index 1cf96540b66e..de8c17bc940d 100644
> --- a/drivers/usb/dwc3/dwc3-imx8mp.c
> +++ b/drivers/usb/dwc3/dwc3-imx8mp.c
> @@ -158,7 +158,7 @@ static irqreturn_t dwc3_imx8mp_interrupt(int irq, void *_dwc3_imx)
> return IRQ_HANDLED;
> }
>
> -static void dwc3_imx_pre_set_role(struct dwc3 *dwc, enum usb_role role)
> +static void dwc3_imx8mp_pre_set_role(struct dwc3 *dwc, enum usb_role role)
> {
> if (role == USB_ROLE_HOST)
> /*
> @@ -173,8 +173,8 @@ static void dwc3_imx_pre_set_role(struct dwc3 *dwc, enum usb_role role)
> pm_runtime_use_autosuspend(dwc->dev);
> }
>
> -struct dwc3_glue_ops dwc3_imx_glue_ops = {
> - .pre_set_role = dwc3_imx_pre_set_role,
> +static struct dwc3_glue_ops dwc3_imx8mp_glue_ops = {
> + .pre_set_role = dwc3_imx8mp_pre_set_role,
> };
>
> static int dwc3_imx8mp_probe(struct platform_device *pdev)
> @@ -266,7 +266,7 @@ static int dwc3_imx8mp_probe(struct platform_device *pdev)
> goto put_dwc3;
> }
>
> - dwc3->glue_ops = &dwc3_imx_glue_ops;
> + dwc3->glue_ops = &dwc3_imx8mp_glue_ops;
>
> if (dwc3->dr_mode == USB_DR_MODE_HOST)
> pm_runtime_dont_use_autosuspend(dwc3->dev);
> --
> 2.37.2.352.g3c44437643
>
Please add Fixes and Cc stable tags and backport this change also.
Thanks,
Thinh
^ permalink raw reply
* Re: [PATCH] arm64: mm: refresh stale pmd snapshot after split_contpmd()
From: Yang Shi @ 2026-06-26 22:53 UTC (permalink / raw)
To: lirongqing, Catalin Marinas, Will Deacon, Ryan Roberts,
Ard Biesheuvel, David Hildenbrand, Anshuman Khandual,
Kevin Brodsky, Chaitanya S Prakash, linux-arm-kernel,
linux-kernel
In-Reply-To: <20260625113953.2332-1-lirongqing@baidu.com>
On 6/25/26 4:39 AM, lirongqing wrote:
> From: Li RongQing <lirongqing@baidu.com>
>
> split_contpmd() modifies the pmd entries in-place by clearing the CONT
> bit, but the local 'pmd' variable still holds the old snapshot with CONT
> set. The subsequent split_pmd() call uses this stale value to derive the
> pgprot for the new PTE entries via pmd_pgprot(), causing the resulting
> PTEs to be populated with incorrect protection bits.
If I read the code correctly, CONT bit is cleared by split_pmd(), then
the bit may be set again for PTEs if we want to have cont ptes. So I
don't see any problem, did I miss something?
Thanks,
Yang
>
> Fix this by re-reading the pmd from memory after split_contpmd() returns
> in both call sites: split_kernel_leaf_mapping_locked() and
> split_to_ptes_pmd_entry().
>
> Fixes: a166563e7ec3 ("arm64: mm: support large block mapping when rodata=full")
> Signed-off-by: Li RongQing <lirongqing@baidu.com>
> ---
> arch/arm64/mm/mmu.c | 8 ++++++--
> 1 file changed, 6 insertions(+), 2 deletions(-)
>
> diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
> index 12e862c..e510336 100644
> --- a/arch/arm64/mm/mmu.c
> +++ b/arch/arm64/mm/mmu.c
> @@ -746,8 +746,10 @@ static int split_kernel_leaf_mapping_locked(unsigned long addr)
> if (!pmd_present(pmd))
> goto out;
> if (pmd_leaf(pmd)) {
> - if (pmd_cont(pmd))
> + if (pmd_cont(pmd)) {
> split_contpmd(pmdp);
> + pmd = pmdp_get(pmdp);
> + }
> /*
> * PMD: If addr is PMD aligned then addr already describes a
> * leaf boundary. Otherwise, split to contpte.
> @@ -891,8 +893,10 @@ static int split_to_ptes_pmd_entry(pmd_t *pmdp, unsigned long addr,
> int ret = 0;
>
> if (pmd_leaf(pmd)) {
> - if (pmd_cont(pmd))
> + if (pmd_cont(pmd)) {
> split_contpmd(pmdp);
> + pmd = pmdp_get(pmdp);
> + }
> ret = split_pmd(pmdp, pmd, gfp, false);
>
> /*
^ permalink raw reply
* Re: [PATCH 1/1] dt-bindings: mfd: st,stmpe: document st,stmpe610 compatible
From: Linus Walleij @ 2026-06-26 23:05 UTC (permalink / raw)
To: Frank.Li
Cc: Lee Jones, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Maxime Coquelin, Alexandre Torgue,
open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
moderated list:ARM/STM32 ARCHITECTURE,
moderated list:ARM/STM32 ARCHITECTURE, open list, imx, Frank Li
In-Reply-To: <20260626183140.3499179-1-Frank.Li@oss.nxp.com>
Hi Frank,
thanks for your patch!
On Fri, Jun 26, 2026 at 8:31 PM <Frank.Li@oss.nxp.com> wrote:
> From: Frank Li <Frank.Li@nxp.com>
>
> The STMPE610 has long been supported by the STMPE I2C MFD driver, but its
> compatible string was never documented.
>
> Add the missing st,stmpe610 compatible string to fix below CHECK_DTBS
> warnings:
> imx53-m53evk.dtb: /soc/bus@60000000/i2c@63fc4000/touchscreen@41: failed to match any schema with compatible: ['st,stmpe610']
>
> Signed-off-by: Frank Li <Frank.Li@nxp.com>
(...)
> compatible:
> enum:
> - st,stmpe601
> + - st,stmpe610
There is no STMPE601.
It's a mis-spelled STMPE610, so please delete the row above and
edit the committ message accordingly.
Yours,
Linus Walleij
^ permalink raw reply
* Re: [PATCH] usb: dwc3: meson-g12a: fix refcount leak in dwc3_meson_g12a_resume()
From: Thinh Nguyen @ 2026-06-26 23:20 UTC (permalink / raw)
To: WenTao Liang
Cc: Thinh Nguyen, gregkh@linuxfoundation.org,
neil.armstrong@linaro.org, khilman@baylibre.com,
jbrunet@baylibre.com, martin.blumenstingl@googlemail.com,
linux-usb@vger.kernel.org, linux-arm-kernel@lists.infradead.org,
linux-amlogic@lists.infradead.org, linux-kernel@vger.kernel.org,
stable@vger.kernel.org
In-Reply-To: <20260611131121.81784-1-vulab@iscas.ac.cn>
On Thu, Jun 11, 2026, WenTao Liang wrote:
> If dwc3_meson_g12a_resume() succeeds in calling
> reset_control_reset(), an internal triggered_count reference is
> acquired. If any later step fails (usb_init, phy_init,
> phy_power_on, regulator_enable, or usb_post_init), the function
> returns the error without rearming the reset control. This leaks
> the reference and leaves the reset control in a triggered state,
> causing future reset_control_reset() calls to incorrectly return
> early as if already reset.
>
> Add an error path that calls reset_control_rearm() to balance
> the reference before returning the error.
>
> Cc: stable@vger.kernel.org
> Fixes: 5b0ba0caaf3a ("usb: dwc3: meson-g12a: refactor usb init")
> Signed-off-by: WenTao Liang <vulab@iscas.ac.cn>
> ---
> drivers/usb/dwc3/dwc3-meson-g12a.c | 14 +++++++++-----
> 1 file changed, 9 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/usb/dwc3/dwc3-meson-g12a.c b/drivers/usb/dwc3/dwc3-meson-g12a.c
> index 55e144ba8cfc..4d611c08e8a4 100644
> --- a/drivers/usb/dwc3/dwc3-meson-g12a.c
> +++ b/drivers/usb/dwc3/dwc3-meson-g12a.c
> @@ -907,35 +907,39 @@ static int __maybe_unused dwc3_meson_g12a_resume(struct device *dev)
>
> ret = priv->drvdata->usb_init(priv);
> if (ret)
> - return ret;
> + goto err_rearm;
>
> /* Init PHYs */
> for (i = 0 ; i < PHY_COUNT ; ++i) {
> ret = phy_init(priv->phys[i]);
> if (ret)
> - return ret;
> + goto err_rearm;
Should we unwind here and below instead of just reset_control_rearm? I
see we do that in probe() error path.
BR,
Thinh
> }
>
> /* Set PHY Power */
> for (i = 0 ; i < PHY_COUNT ; ++i) {
> ret = phy_power_on(priv->phys[i]);
> if (ret)
> - return ret;
> + goto err_rearm;
> }
>
> if (priv->vbus && priv->otg_phy_mode == PHY_MODE_USB_HOST) {
> ret = regulator_enable(priv->vbus);
> if (ret)
> - return ret;
> + goto err_rearm;
> }
>
> if (priv->drvdata->usb_post_init) {
> ret = priv->drvdata->usb_post_init(priv);
> if (ret)
> - return ret;
> + goto err_rearm;
> }
>
> return 0;
> +
> +err_rearm:
> + reset_control_rearm(priv->reset);
> + return ret;
> }
>
> static const struct dev_pm_ops dwc3_meson_g12a_dev_pm_ops = {
> --
> 2.50.1 (Apple Git-155)
>
^ permalink raw reply
* Re: [PATCH v2 00/11] iommu/arm-smmu-v3: Add PRI support
From: Nicolin Chen @ 2026-06-27 0:43 UTC (permalink / raw)
To: harsha.v
Cc: will, robin.murphy, jgg, joro, bhelgaas, praan, kevin.tian, kees,
smostafa, baolu.lu, linux-arm-kernel, iommu, linux-kernel,
linux-pci, skaestle, mmarrid, skolothumtho, bbiber
In-Reply-To: <2a52ecb1-be8a-4522-aa23-f3277f0555fa@oss.qualcomm.com>
On Fri, Jun 26, 2026 at 08:24:31PM +0530, harsha.v@oss.qualcomm.com wrote:
> One thing I noticed while reviewing: when arm_smmu_priq_thread() detects
> PRIQ overflow, partial faults (non-LAST pages stored via
> report_partial_fault()) whose LAST page was lost in the overflow remain
> permanently in iopf_param->partial. This is a monotonic memory leak —
> it grows with each overflow event.
>
> Intel VT-d handles this in prq_event_thread() (drivers/iommu/intel/prq.c):
> if (head == tail) {
> iopf_queue_discard_partial(iommu->iopf_queue);
> writel(DMA_PRS_PRO, iommu->reg + DMAR_PRS_REG);
> }
>
> iopf_queue_discard_partial() was written for exactly this scenario.
> Could we add the same here arm_smmu_priq_thread()
> (drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c) ?
>
> if (queue_sync_prod_in(q) == -EOVERFLOW) {
> dev_err(smmu->dev, "PRIQ overflow detected -- requests lost\n");
> + iopf_queue_discard_partial(smmu->evtq.iopf);
> }
>
> At this point all surviving entries have already been consumed by the
> loop above, so discarding unconditionally is safe — implicitly matching
> Intel's "head == tail" guard.
I will fold it in.
Thanks!
Nicolin
^ permalink raw reply
* Re: [PATCH v2 05/11] iommu/arm-smmu-v3: Submit CMDQ_OP_PRI_RESP for IOPF event
From: Nicolin Chen @ 2026-06-27 0:44 UTC (permalink / raw)
To: Robin Murphy
Cc: will, jgg, joro, bhelgaas, praan, kevin.tian, kees, smostafa,
baolu.lu, linux-arm-kernel, iommu, linux-kernel, linux-pci,
skaestle, mmarrid, skolothumtho, bbiber
In-Reply-To: <b5085e09-6533-4f88-938d-8d46751cf7da@arm.com>
On Fri, Jun 26, 2026 at 05:15:13PM +0100, Robin Murphy wrote:
> On 28/05/2026 8:59 am, Nicolin Chen wrote:
> > From: Malak Marrid <mmarrid@nvidia.com>
> >
> > To handle IOMMU_FAULT_PAGE_REQ from the PRI queue, arm_smmu_page_response()
> > must issue a CMDQ_OP_PRI_RESP back to the SMMU.
> >
> > However, either a stall event in the EVTQ or a PRI request in the PRIQ can
> > surface to the IOPF infrastructure with fault.type == IOMMU_FAULT_PAGE_REQ,
> > and a single master can in principle be both stall-capable and PRI-capable
>
> No, the SMMU architecture does all it can to specifically forbid this, see
> 3.12.1 and 16.4, it just can't be made architecturally ILLEGAL to enable
> stalls for PCIe devices because there's no strict architectural definition
> for what "a PCIe device" actually is. Similarly with the note in the
> definition of STE.EATS about the relationship with CD.S - the unwritten
> implication is that defining specific behaviours would only create an
> unreasonable burden for hardware validation, for the sake of something that
> nobody in their right mind should ever do anyway.
>
> The expectation is that RCiEPs which do speak stallable non-PCIe bus
> protocols will not go to the effort of implementing ATS/PRI capabilities
> (not least because there's every chance that such protocols simply doesn't
> have that kind of transaction flow anyway). And conversely that it can be
> considered an egregious firmware (or system design) error to even claim (let
> alone force) stall capability for a real PCIe root port which may be
> deadlocked by blocking its requirement for free-flowing writes. Thus I think
> we could go so far as to refuse to handle any endpoint which did somehow
> claim both.
Oh, I missed that. This certainly can simplify things here.
I will fix it.
Thanks!
Nicolin
^ permalink raw reply
* Re: cleanup the RAID6 P/Q library v3
From: H. Peter Anvin @ 2026-06-27 0:52 UTC (permalink / raw)
To: Christoph Hellwig, Andrew Morton
Cc: Catalin Marinas, Will Deacon, Ard Biesheuvel, Huacai Chen,
WANG Xuerui, Madhavan Srinivasan, Michael Ellerman,
Nicholas Piggin, Christophe Leroy (CS GROUP), Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Heiko Carstens,
Vasily Gorbik, Alexander Gordeev, Christian Borntraeger,
Sven Schnelle, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
Dave Hansen, x86, Herbert Xu, Dan Williams, Chris Mason,
David Sterba, Arnd Bergmann, Song Liu, Yu Kuai, Li Nan,
linux-kernel, linux-arm-kernel, loongarch, linuxppc-dev,
linux-riscv, linux-s390, linux-crypto, linux-btrfs, linux-arch,
linux-raid
In-Reply-To: <20260519082432.GA14956@lst.de>
On 2026-05-19 01:24, Christoph Hellwig wrote:
>
> raid6: rework registration of optimized algorithms
>
> - avx2 instead of avx512 is probably the right thing for no
> benchmarking, but if it was intentional (it wasn't), that should
> be document. So I'll just switch back to the previous version to
> keep the state of the art
It is unlikely to be the right thing *going forward*, though.
The very unfortunate performance inversion is likely model-specific. It is one
of those things where you largely would have to have a list of quirks :(
-hpa
^ permalink raw reply
* Re: [PATCH 08/18] raid6: warn when using less than four devices
From: H. Peter Anvin @ 2026-06-27 1:14 UTC (permalink / raw)
To: Christoph Hellwig, Andrew Morton
Cc: Catalin Marinas, Will Deacon, Ard Biesheuvel, Huacai Chen,
WANG Xuerui, Madhavan Srinivasan, Michael Ellerman,
Nicholas Piggin, Christophe Leroy (CS GROUP), Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Heiko Carstens,
Vasily Gorbik, Alexander Gordeev, Christian Borntraeger,
Sven Schnelle, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
Dave Hansen, x86, Herbert Xu, Dan Williams, Chris Mason,
David Sterba, Arnd Bergmann, Song Liu, Yu Kuai, Li Nan,
linux-kernel, linux-arm-kernel, loongarch, linuxppc-dev,
linux-riscv, linux-s390, linux-crypto, linux-btrfs, linux-arch,
linux-raid
In-Reply-To: <20260518051804.462141-9-hch@lst.de>
On 2026-05-17 22:17, Christoph Hellwig wrote:
> Quoting H. Peter Anvin who came up with the RAID6 P/Q algorithm, and
> who wrote the initial implementation, then still part of the md driver:
>
> The RAID-6 code has *never* supported only 3 units, and if it ever
> worked for *any* of the implementations it was purely by accident.
> Speaking as the original author I should know; this was deliberate as
> in some cases the degenerate case (3) would have required extra trays
Stupid autocorrect. That was of course supposed to be "tests" (as in extra
code paths) not "trays" :)
> in the code to no user benefit.
>
> While md never allowed less than 4 devices, btrfs does. This new
> warning will trigger for such file systems, but given how it already
> causes havoc that is a good thing. If btrfs wants to fix third, it
> should switch to transparently use three-way mirroring underneath,
> which will work as P and Q are copies of the single data device by
> the definition of the Linux RAID 6 P/Q algorithm.
For what it's worth, this is also true in the degenerate two-drive RAID-4|5
case (D = P).
-hpa
^ permalink raw reply
* Re: [PATCH v3 2/2] ARM: mm: protect show_pte() in do_DataAbort() fallback path
From: Xie Yuanbin @ 2026-06-27 1:22 UTC (permalink / raw)
To: linux; +Cc: akpm, linux-arm-kernel, linux-kernel, sunnanyong, xieyuanbin1,
xiqi2
In-Reply-To: <aj5ybKcDxl1tOIx4@shell.armlinux.org.uk>
On Fri, 26 Jun 2026 13:37:00 +0100, Russell King wrote:
> On Fri, Jun 26, 2026 at 06:16:15PM +0800, Xie Yuanbin wrote:
>> I suggest that waiting for this patch to be merged first:
>> https://lore.kernel.org/20260625122612.43501-1-xieyuanbin1@huawei.com
>> which make sure that interrupts are enabled here.
>
> No, it doesn't ensure that.
Oh, I'm sorry my description wasn't clear. It should make sure that
for user unhandled faults, interrupts are enabled here, without
kernel unhandled faults.
> We are not "fixing" show_pte(), which is a diagnostic function when
> things go wrong in the kernel, and is there to *try* to give us
> information to diagnose what happened. It is *not* a function that
> is used routinely in the kernel.
For kernel faults, I fully agree with it. However, for
user faults, I think "fixing" is necessary.
We might be able to construct a user-mode program in some way to
repeatedly trigger unhandled faults -> show_pte(), such as executing bkpt
instruction, or something else, and then the kernel panic, this may be a
security vulnerability.
^ permalink raw reply
* Re: [PATCH v3 1/2] ARM: mm: fix use-after-free in __do_user_fault() under CONFIG_DEBUG_USER
From: Qi Xi @ 2026-06-27 1:39 UTC (permalink / raw)
To: Russell King
Cc: Andrew Morton, linux-arm-kernel, linux-kernel, Yuanbin Xie,
Nanyong Sun
In-Reply-To: <aj5KCj1cRX3_IpPN@shell.armlinux.org.uk>
Hi Russell,
Thank you for the review. I understand the general concern about
taking locks in fault paths, but I would like to clarify the specific
case here.
__do_user_fault() with CONFIG_DEBUG_USER is not a kernel-dying path.
After show_pte() prints debug info, the kernel calls
force_sig_fault(SIGSEGV) and returns to user space. The system
continues running normally. Without this fix, a concurrent munmap can
cause show_pte() to trigger a secondary kernel fault, turning a
harmless SIGSEGV into a kernel panic.
Regarding your concern about the mm lock being already held: I have
verified that all three callers of __do_user_fault() (do_page_fault
-> bad_area, do_bad_area user path, and do_kernel_address_page_fault
user path) release mmap_read_lock or never hold it before entering
__do_user_fault(). So the lock is not held here.
It is also worth noting that we did NOT modify the paths where the
kernel is already dying (die_kernel_fault, __do_kernel_fault). Those
paths remain unchanged and continue to call show_pte() without any
lock, just as they always have.
On 26/06/2026 17:44, Russell King wrote:
> On Fri, Jun 26, 2026 at 03:30:47PM +0800, Qi Xi wrote:
>> When CONFIG_DEBUG_USER is enabled with user_debug=31 on 32-bit ARM,
>> a user page fault triggers show_pte() via __do_user_fault() after
>> do_page_fault() has already released mmap_read_lock. If another
>> thread concurrently calls munmap(), the page table pages can be
>> freed while show_pte() is still reading them, causing a
>> use-after-free in show_pte().
>>
>> The race can be reproduced on multi_v7_defconfig with:
>> CONFIG_DEBUG_USER=y
>> CONFIG_ARM_LPAE=y
>> kernel command line: user_debug=31
>>
>> A delay inserted in show_pte() for testing widens the race window and
>> makes the UAF reliably reproducible. On LPAE, the race works as
>> follows:
>>
>> CPU 0 (fault path) CPU 1 (munmap)
>> munmap(page 0) -> clears PTE[0]
>> PTE/PMD pages remain
>>
>> read page 0 -> page fault
>> -> do_DataAbort()
>> -> do_page_fault()
>> -> lock_mm_and_find_vma() -> no VMA
>> (mmap_read_lock released)
>> -> __do_user_fault()
>> -> show_pte(tsk->mm, addr)
>> -> *pgd (valid)
>> -> p4d/pud checks pass
>>
>> -> [delay] munmap(page 1)
>> -> clears PTE[1]
>> -> PTE/PMD pages freed
>> -> PGD cleared
>>
>> -> pmd_offset(pud, addr)
>> -> *pud=0 -> __va(0)
>> -> dereference
>> -> secondary data abort (kernel)
>>
>> Fix by taking mmap_read_lock() around show_pte() in __do_user_fault().
>> __do_user_fault() is called from process context with interrupts
>> enabled, so the context can sleep and mmap_read_lock() is safe here.
> This is a fault path which should only be called when something is
> already wrong, the mm lock may already be held (e.g. a kernel
> fault while already holding the mmap lock.) We can't take any locks
> here.
>
^ permalink raw reply
* 答复: [外部邮件] Re: [PATCH] arm64: mm: refresh stale pmd snapshot after split_contpmd()
From: Li,Rongqing @ 2026-06-27 2:46 UTC (permalink / raw)
To: Yang Shi, Catalin Marinas, Will Deacon, Ryan Roberts,
Ard Biesheuvel, David Hildenbrand, Anshuman Khandual,
Kevin Brodsky, Chaitanya S Prakash,
linux-arm-kernel@lists.infradead.org,
linux-kernel@vger.kernel.org
In-Reply-To: <32e089d6-7832-4af3-87fc-c1d6bcdb5ba8@os.amperecomputing.com>
>
>
>
> On 6/25/26 4:39 AM, lirongqing wrote:
> > From: Li RongQing <lirongqing@baidu.com>
> >
> > split_contpmd() modifies the pmd entries in-place by clearing the CONT
> > bit, but the local 'pmd' variable still holds the old snapshot with
> > CONT set. The subsequent split_pmd() call uses this stale value to
> > derive the pgprot for the new PTE entries via pmd_pgprot(), causing
> > the resulting PTEs to be populated with incorrect protection bits.
>
> If I read the code correctly, CONT bit is cleared by split_pmd(), then the bit
> may be set again for PTEs if we want to have cont ptes. So I don't see any
> problem, did I miss something?
>
You are right, there's no functional issue with the current code.
However, I think explicitly re-reading the pmd is the safer and clearer
approach — it makes the intent obvious (we need the post-modification state)
rather than relying on the implicit assumption that "CONT bit doesn't affect pgprot."
Thanks
[Li,Rongqing]
> Thanks,
> Yang
>
> >
> > Fix this by re-reading the pmd from memory after split_contpmd()
> > returns in both call sites: split_kernel_leaf_mapping_locked() and
> > split_to_ptes_pmd_entry().
> >
> > Fixes: a166563e7ec3 ("arm64: mm: support large block mapping when
> > rodata=full")
> > Signed-off-by: Li RongQing <lirongqing@baidu.com>
> > ---
> > arch/arm64/mm/mmu.c | 8 ++++++--
> > 1 file changed, 6 insertions(+), 2 deletions(-)
> >
> > diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c index
> > 12e862c..e510336 100644
> > --- a/arch/arm64/mm/mmu.c
> > +++ b/arch/arm64/mm/mmu.c
> > @@ -746,8 +746,10 @@ static int
> split_kernel_leaf_mapping_locked(unsigned long addr)
> > if (!pmd_present(pmd))
> > goto out;
> > if (pmd_leaf(pmd)) {
> > - if (pmd_cont(pmd))
> > + if (pmd_cont(pmd)) {
> > split_contpmd(pmdp);
> > + pmd = pmdp_get(pmdp);
> > + }
> > /*
> > * PMD: If addr is PMD aligned then addr already describes a
> > * leaf boundary. Otherwise, split to contpte.
> > @@ -891,8 +893,10 @@ static int split_to_ptes_pmd_entry(pmd_t *pmdp,
> unsigned long addr,
> > int ret = 0;
> >
> > if (pmd_leaf(pmd)) {
> > - if (pmd_cont(pmd))
> > + if (pmd_cont(pmd)) {
> > split_contpmd(pmdp);
> > + pmd = pmdp_get(pmdp);
> > + }
> > ret = split_pmd(pmdp, pmd, gfp, false);
> >
> > /*
^ permalink raw reply
* Re: [PATCH] ARM: entry: Convert IRQ handling to generic IRQ entry
From: Jinjie Ruan @ 2026-06-27 2:57 UTC (permalink / raw)
To: Linus Walleij, Paul E. McKenney, Arnd Bergmann, Russell King,
Oleg Nesterov, Thomas Gleixner
Cc: linux-arm-kernel, linux-kernel
In-Reply-To: <20260623-arm-generic-irq-entry-v7-1-v1-1-f25ca7079e3b@kernel.org>
On 6/23/2026 6:52 AM, Linus Walleij wrote:
> Bring ARM to the same level of generic-ness as ARM64 by enabling
> GENERIC_IRQ_ENTRY.
>
> Route ARM IRQ entry through C wrappers that use the generic IRQ entry
> helpers. Conversely put the FIQ entry under the generic NMI-style entry
> helpers.
>
> Select GENERIC_IRQ_ENTRY, add the ARM entry prototypes, and provide
> regs_irqs_disabled() for the generic IRQ entry return path.
>
> The kernel-mode IRQ return path relies on the generic IRQ entry
> preemption handling, matching the arm64 structure and avoiding the old
> assembly reschedule check.
>
> The reschedule check is now done in raw_irqentry_exit_cond_resched()
> in kernel/entry/common.c.
>
> User-mode IRQs __irq_usr is neither calling ct_user_exit/enter
> or asm_trace_hardirqs_off/on anymore. The corresponding calls happen on
> irqentry_enter/exit() call paths, e.g the irq-disabled C variants
> __ct_user_exit/enter() are called instead.
>
> As __irq_usr no longer returns by jumping to ret_to_user_from_irq,
> the corresponding code has been inlined, except the slow_work_pending
> part, which is now also handled by generic entry. ret_to_user_from_irq
> is only called from v7m so it has been renamed accordingly.
>
> arch_do_signal_or_restart() is required, but we only need a very small
> stub, since we keep the existing syscall restart code around in assembly.
>
> Tested on with multi_v7_defconfig and qemu-system-arm vexpress-a15
> using vexpress-v2p-ca15-tc1.dtb and some different loads.
>
> A note on V7M: the reason we cannot switch the V7M entry over to generic
> entry is that it raises a "pendable service call" ("pendv") exception to
> process deferred work at the end of the interrupt handler. This is done
> so higher priority work can come in. This has no corresponding structure
> in other ARM cores.
>
> This is a reduced patch based on the earlier generic entry series avoiding
> all the syscall handling changes.
>
> Link: https://lore.kernel.org/linux-arm-kernel/20250420-arm-generic-entry-v6-0-95f1fcdfeeb2@linaro.org/
> Signed-off-by: Linus Walleij <linusw@kernel.org>
> ---
> arch/arm/Kconfig | 1 +
> arch/arm/include/asm/entry-common.h | 7 ++++
> arch/arm/include/asm/entry.h | 10 +++++
> arch/arm/include/asm/ptrace.h | 7 +++-
> arch/arm/kernel/Makefile | 2 +-
> arch/arm/kernel/entry-armv.S | 75 ++++++++-----------------------------
> arch/arm/kernel/entry-common.S | 5 ++-
> arch/arm/kernel/entry-header.S | 7 +++-
> arch/arm/kernel/entry-v7m.S | 2 +-
> arch/arm/kernel/entry.c | 51 +++++++++++++++++++++++++
> arch/arm/kernel/irq.c | 6 +++
> arch/arm/kernel/irq.h | 2 +
> arch/arm/kernel/signal.c | 6 +++
> 13 files changed, 116 insertions(+), 65 deletions(-)
>
> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
> index 73e6647bea46..aad21d645ff3 100644
> --- a/arch/arm/Kconfig
> +++ b/arch/arm/Kconfig
> @@ -71,6 +71,7 @@ config ARM
> select GENERIC_CPU_AUTOPROBE
> select GENERIC_CPU_DEVICES
> select GENERIC_EARLY_IOREMAP
> + select GENERIC_IRQ_ENTRY if !CPU_V7M
> select GENERIC_IDLE_POLL_SETUP
> select GENERIC_IRQ_MULTI_HANDLER
> select GENERIC_IRQ_PROBE
> diff --git a/arch/arm/include/asm/entry-common.h b/arch/arm/include/asm/entry-common.h
> new file mode 100644
> index 000000000000..c017df5f39d5
> --- /dev/null
> +++ b/arch/arm/include/asm/entry-common.h
> @@ -0,0 +1,7 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +#ifndef __ASM_ARM_ENTRY_COMMON_H
> +#define __ASM_ARM_ENTRY_COMMON_H
> +
> +#include <asm/stacktrace.h>
> +
> +#endif
> diff --git a/arch/arm/include/asm/entry.h b/arch/arm/include/asm/entry.h
> new file mode 100644
> index 000000000000..864c9b3abbf1
> --- /dev/null
> +++ b/arch/arm/include/asm/entry.h
> @@ -0,0 +1,10 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +#ifndef __ASM_ENTRY_H__
> +#define __ASM_ENTRY_H__
> +
> +struct pt_regs;
> +
> +void arm_irq_handler(struct pt_regs *regs, int mode);
> +void arm_fiq_handler(struct pt_regs *regs);
> +
> +#endif /* __ASM_ENTRY_H__ */
> diff --git a/arch/arm/include/asm/ptrace.h b/arch/arm/include/asm/ptrace.h
> index 6eb311fb2da0..88ddb9371a02 100644
> --- a/arch/arm/include/asm/ptrace.h
> +++ b/arch/arm/include/asm/ptrace.h
> @@ -46,8 +46,13 @@ struct svc_pt_regs {
> #define processor_mode(regs) \
> ((regs)->ARM_cpsr & MODE_MASK)
>
> +static inline bool regs_irqs_disabled(const struct pt_regs *regs)
> +{
> + return regs->ARM_cpsr & PSR_I_BIT;
> +}
Hi Linus,
Thanks for the patch.
I have a small suggestion regarding the `interrupts_enabled` logic. If
arm32 could also implement `regs_irqs_disabled(regs)` (similar to what
arm64 and some other architectures already have), we might be able to
unify this across subsystems.
Specifically, we could then replace the custom `interrupts_enabled`
usage in both the arm64 architecture code and drivers like
`drivers/irqchip/irq-gic-v3.c`.
--- a/arch/arm64/include/asm/ptrace.h
+++ b/arch/arm64/include/asm/ptrace.h
@@ -215,8 +215,6 @@ static __always_inline bool regs_irqs_disabled(const
struct pt_regs *regs)
return (regs->pstate & PSR_I_BIT) || !irqs_priority_unmasked(regs);
}
-#define interrupts_enabled(regs) (!regs_irqs_disabled(regs))
-
static inline unsigned long user_stack_pointer(struct pt_regs *regs)
{
if (compat_user_mode(regs))
diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
index 99444a1b2ffa..60fa6a60adce 100644
--- a/drivers/irqchip/irq-gic-v3.c
+++ b/drivers/irqchip/irq-gic-v3.c
@@ -914,7 +914,7 @@ static void __gic_handle_irq_from_irqsoff(struct
pt_regs *regs)
static void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
{
- if (unlikely(gic_supports_nmi() && !interrupts_enabled(regs)))
+ if (unlikely(gic_supports_nmi() && regs_irqs_disabled(regs)))
__gic_handle_irq_from_irqsoff(regs);
else
__gic_handle_irq_from_irqson(regs);
Best regards,
Jinjie
> +
> #define interrupts_enabled(regs) \
> - (!((regs)->ARM_cpsr & PSR_I_BIT))
> + (!regs_irqs_disabled(regs))
>
> #define fast_interrupts_enabled(regs) \
> (!((regs)->ARM_cpsr & PSR_F_BIT))
> diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
> index b36cf0cfd4a7..3b8a62f6f54d 100644
> --- a/arch/arm/kernel/Makefile
> +++ b/arch/arm/kernel/Makefile
> @@ -17,7 +17,7 @@ CFLAGS_REMOVE_return_address.o = -pg
>
> # Object file lists.
>
> -obj-y := elf.o entry-common.o irq.o opcodes.o \
> +obj-y := elf.o entry.o entry-common.o irq.o opcodes.o \
> process.o ptrace.o reboot.o io.o \
> setup.o signal.o sigreturn_codes.o \
> stacktrace.o sys_arm.o time.o traps.o
> diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
> index a3d050ce9b79..8ac7f1512ee8 100644
> --- a/arch/arm/kernel/entry-armv.S
> +++ b/arch/arm/kernel/entry-armv.S
> @@ -36,35 +36,6 @@
> #define RELOC_TEXT_NONE
> #endif
>
> -/*
> - * Interrupt handling.
> - */
> - .macro irq_handler, from_user:req
> - mov r1, sp
> - ldr_this_cpu r2, irq_stack_ptr, r2, r3
> - .if \from_user == 0
> - @
> - @ If we took the interrupt while running in the kernel, we may already
> - @ be using the IRQ stack, so revert to the original value in that case.
> - @
> - subs r3, r2, r1 @ SP above bottom of IRQ stack?
> - rsbscs r3, r3, #THREAD_SIZE @ ... and below the top?
> -#ifdef CONFIG_VMAP_STACK
> - ldr_va r3, high_memory, cc @ End of the linear region
> - cmpcc r3, r1 @ Stack pointer was below it?
> -#endif
> - bcc 0f @ If not, switch to the IRQ stack
> - mov r0, r1
> - bl generic_handle_arch_irq
> - b 1f
> -0:
> - .endif
> -
> - mov_l r0, generic_handle_arch_irq
> - bl call_with_stack
> -1:
> - .endm
> -
> .macro pabt_helper
> @ PABORT handler takes pt_regs in r2, fault address in r4 and psr in r5
> #ifdef MULTI_PABORT
> @@ -224,34 +195,17 @@ ENDPROC(__dabt_svc)
>
> .align 5
> __irq_svc:
> - svc_entry
> - irq_handler from_user=0
> -
> -#ifdef CONFIG_PREEMPTION
> - ldr r8, [tsk, #TI_PREEMPT] @ get preempt count
> - ldr r0, [tsk, #TI_FLAGS] @ get flags
> - teq r8, #0 @ if preempt count != 0
> - movne r0, #0 @ force flags to 0
> - tst r0, #_TIF_NEED_RESCHED
> - blne svc_preempt
> -#endif
> + svc_entry trace=0
> + mov r0, sp @ regs
> + mov r1, #0 @ from kernel mode
> + bl arm_irq_handler
>
> - svc_exit r5, irq = 1 @ return from exception
> + svc_exit r5, irqentry = 1 @ return from exception
> UNWIND(.fnend )
> ENDPROC(__irq_svc)
>
> .ltorg
>
> -#ifdef CONFIG_PREEMPTION
> -svc_preempt:
> - mov r8, lr
> -1: bl preempt_schedule_irq @ irq en/disable is done inside
> - ldr r0, [tsk, #TI_FLAGS] @ get new tasks TI_FLAGS
> - tst r0, #_TIF_NEED_RESCHED
> - reteq r8 @ go again
> - b 1b
> -#endif
> -
> __und_fault:
> @ Correct the PC such that it is pointing at the instruction
> @ which caused the fault. If the faulting instruction was ARM
> @@ -302,7 +256,7 @@ ENDPROC(__pabt_svc)
> __fiq_svc:
> svc_entry trace=0
> mov r0, sp @ struct pt_regs *regs
> - bl handle_fiq_as_nmi
> + bl arm_fiq_handler
> svc_exit_via_fiq
> UNWIND(.fnend )
> ENDPROC(__fiq_svc)
> @@ -331,7 +285,7 @@ __fiq_abt:
> stmfd sp!, {r1 - r2}
>
> add r0, sp, #8 @ struct pt_regs *regs
> - bl handle_fiq_as_nmi
> + bl arm_fiq_handler
>
> ldmfd sp!, {r1 - r2}
> ARM( msr cpsr_c, #ABT_MODE | PSR_I_BIT | PSR_F_BIT )
> @@ -438,12 +392,15 @@ ENDPROC(__dabt_usr)
>
> .align 5
> __irq_usr:
> - usr_entry
> + usr_entry trace=0
> kuser_cmpxchg_check
> - irq_handler from_user=1
> - get_thread_info tsk
> - mov why, #0
> - b ret_to_user_from_irq
> + mov r0, sp @ regs
> + mov r1, #1 @ from user mode
> + bl arm_irq_handler
> +#ifdef CONFIG_KSTACK_ERASE
> + bl stackleak_erase_on_task_stack
> +#endif
> + restore_user_regs fast = 0, offset = 0
> UNWIND(.fnend )
> ENDPROC(__irq_usr)
>
> @@ -498,7 +455,7 @@ __fiq_usr:
> usr_entry trace=0
> kuser_cmpxchg_check
> mov r0, sp @ struct pt_regs *regs
> - bl handle_fiq_as_nmi
> + bl arm_fiq_handler
> get_thread_info tsk
> restore_user_regs fast = 0, offset = 0
> UNWIND(.fnend )
> diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S
> index 88336a1292bb..d5fdb234c1d4 100644
> --- a/arch/arm/kernel/entry-common.S
> +++ b/arch/arm/kernel/entry-common.S
> @@ -110,7 +110,8 @@ ret_slow_syscall:
> bl do_rseq_syscall
> #endif
> disable_irq_notrace @ disable interrupts
> -ENTRY(ret_to_user_from_irq)
> +ENTRY(v7m_ret_to_user_from_irq)
> + /* Only the v7m jumps directly to v7m_ret_to_user_from_irq */
> ldr r1, [tsk, #TI_FLAGS]
> movs r1, r1, lsl #16
> bne slow_work_pending
> @@ -123,7 +124,7 @@ no_work_pending:
> bl stackleak_erase_on_task_stack
> #endif
> restore_user_regs fast = 0, offset = 0
> -ENDPROC(ret_to_user_from_irq)
> +ENDPROC(v7m_ret_to_user_from_irq)
> ENDPROC(ret_to_user)
>
> /*
> diff --git a/arch/arm/kernel/entry-header.S b/arch/arm/kernel/entry-header.S
> index 99411fa91350..e83f2fb8a592 100644
> --- a/arch/arm/kernel/entry-header.S
> +++ b/arch/arm/kernel/entry-header.S
> @@ -199,7 +199,11 @@
> .endm
>
>
> - .macro svc_exit, rpsr, irq = 0
> + .macro svc_exit, rpsr, irq = 0, irqentry = 0
> + .if \irqentry != 0
> + @ Generic IRQ entry already handled tracing and lockdep state.
> + disable_irq_notrace
> + .else
> .if \irq != 0
> @ IRQs already off
> #ifdef CONFIG_TRACE_IRQFLAGS
> @@ -216,6 +220,7 @@
> tst \rpsr, #PSR_I_BIT
> blne trace_hardirqs_off
> #endif
> + .endif
> .endif
> uaccess_exit tsk, r0, r1
>
> diff --git a/arch/arm/kernel/entry-v7m.S b/arch/arm/kernel/entry-v7m.S
> index 52bacf07ba16..49a3a34e2913 100644
> --- a/arch/arm/kernel/entry-v7m.S
> +++ b/arch/arm/kernel/entry-v7m.S
> @@ -94,7 +94,7 @@ __pendsv_entry:
> @ execute the pending work, including reschedule
> get_thread_info tsk
> mov why, #0
> - b ret_to_user_from_irq
> + b v7m_ret_to_user_from_irq
> ENDPROC(__pendsv_entry)
>
> /*
> diff --git a/arch/arm/kernel/entry.c b/arch/arm/kernel/entry.c
> new file mode 100644
> index 000000000000..1142e418d161
> --- /dev/null
> +++ b/arch/arm/kernel/entry.c
> @@ -0,0 +1,51 @@
> +// SPDX-License-Identifier: GPL-2.0
> +#include <linux/hardirq.h>
> +#include <linux/irq-entry-common.h>
> +#include <linux/irq.h>
> +
> +#include <asm/entry.h>
> +#include <asm/stacktrace.h>
> +#include <asm/traps.h>
> +
> +#include "irq.h"
> +
> +static void noinstr handle_arm_irq(void *data)
> +{
> + struct pt_regs *regs = data;
> + struct pt_regs *old_regs;
> +
> + irq_enter_rcu();
> + old_regs = set_irq_regs(regs);
> +
> + handle_arch_irq(regs);
> +
> + set_irq_regs(old_regs);
> + irq_exit_rcu();
> +}
> +
> +noinstr void arm_irq_handler(struct pt_regs *regs, int mode)
> +{
> + irqentry_state_t state = irqentry_enter(regs);
> +
> + /*
> + * mode == 1 means we came from userspace, and then we
> + * should just immediately switch to the irq stack.
> + * Then we check of we are on the thread stack. If we are
> + * not, then by definition we are already using the irq stack.
> + */
> + if (mode == 1 || on_thread_stack())
> + call_on_irq_stack(handle_arm_irq, regs);
> + else
> + handle_arm_irq(regs);
> +
> + irqentry_exit(regs, state);
> +}
> +
> +noinstr void arm_fiq_handler(struct pt_regs *regs)
> +{
> + irqentry_state_t state = irqentry_nmi_enter(regs);
> +
> + handle_fiq_as_nmi(regs);
> +
> + irqentry_nmi_exit(regs, state);
> +}
> diff --git a/arch/arm/kernel/irq.c b/arch/arm/kernel/irq.c
> index e1993e28a9ec..f99d6b24d8ff 100644
> --- a/arch/arm/kernel/irq.c
> +++ b/arch/arm/kernel/irq.c
> @@ -43,6 +43,7 @@
> #include <asm/mach/irq.h>
> #include <asm/mach/time.h>
>
> +#include "irq.h"
> #include "reboot.h"
>
> unsigned long irq_err_count;
> @@ -71,6 +72,11 @@ static void __init init_irq_stacks(void)
> }
> }
>
> +void call_on_irq_stack(void (*fn)(void *), void *arg)
> +{
> + call_with_stack(fn, arg, __this_cpu_read(irq_stack_ptr));
> +}
> +
> #ifdef CONFIG_SOFTIRQ_ON_OWN_STACK
> static void ____do_softirq(void *arg)
> {
> diff --git a/arch/arm/kernel/irq.h b/arch/arm/kernel/irq.h
> new file mode 100644
> index 000000000000..80dd5bfe6403
> --- /dev/null
> +++ b/arch/arm/kernel/irq.h
> @@ -0,0 +1,2 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +void call_on_irq_stack(void (*fn)(void *), void *arg);
> diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c
> index 7be9188d83d9..9084c04c07f7 100644
> --- a/arch/arm/kernel/signal.c
> +++ b/arch/arm/kernel/signal.c
> @@ -12,6 +12,7 @@
> #include <linux/resume_user_mode.h>
> #include <linux/uprobes.h>
> #include <linux/syscalls.h>
> +#include <linux/irq-entry-common.h>
>
> #include <asm/elf.h>
> #include <asm/cacheflush.h>
> @@ -599,6 +600,11 @@ static int do_signal(struct pt_regs *regs, int syscall)
> return 0;
> }
>
> +void arch_do_signal_or_restart(struct pt_regs *regs)
> +{
> + do_signal(regs, 0);
> +}
> +
> asmlinkage int
> do_work_pending(struct pt_regs *regs, unsigned int thread_flags, int syscall)
> {
>
> ---
> base-commit: 8cd9520d35a6c38db6567e97dd93b1f11f185dc6
> change-id: 20260622-arm-generic-irq-entry-v7-1-ff6c1d6c9c48
>
> Best regards,
> --
> Linus Walleij <linusw@kernel.org>
>
^ permalink raw reply related
* Re: [PATCH] ARM: entry: Convert IRQ handling to generic IRQ entry
From: Jinjie Ruan @ 2026-06-27 3:16 UTC (permalink / raw)
To: Linus Walleij, Paul E. McKenney, Arnd Bergmann, Russell King,
Oleg Nesterov, Thomas Gleixner
Cc: linux-arm-kernel, linux-kernel
In-Reply-To: <20260623-arm-generic-irq-entry-v7-1-v1-1-f25ca7079e3b@kernel.org>
On 6/23/2026 6:52 AM, Linus Walleij wrote:
> Bring ARM to the same level of generic-ness as ARM64 by enabling
> GENERIC_IRQ_ENTRY.
>
> Route ARM IRQ entry through C wrappers that use the generic IRQ entry
> helpers. Conversely put the FIQ entry under the generic NMI-style entry
> helpers.
>
> Select GENERIC_IRQ_ENTRY, add the ARM entry prototypes, and provide
> regs_irqs_disabled() for the generic IRQ entry return path.
>
> The kernel-mode IRQ return path relies on the generic IRQ entry
> preemption handling, matching the arm64 structure and avoiding the old
> assembly reschedule check.
>
> The reschedule check is now done in raw_irqentry_exit_cond_resched()
> in kernel/entry/common.c.
>
> User-mode IRQs __irq_usr is neither calling ct_user_exit/enter
> or asm_trace_hardirqs_off/on anymore. The corresponding calls happen on
> irqentry_enter/exit() call paths, e.g the irq-disabled C variants
> __ct_user_exit/enter() are called instead.
>
> As __irq_usr no longer returns by jumping to ret_to_user_from_irq,
> the corresponding code has been inlined, except the slow_work_pending
> part, which is now also handled by generic entry. ret_to_user_from_irq
> is only called from v7m so it has been renamed accordingly.
>
> arch_do_signal_or_restart() is required, but we only need a very small
> stub, since we keep the existing syscall restart code around in assembly.
>
> Tested on with multi_v7_defconfig and qemu-system-arm vexpress-a15
> using vexpress-v2p-ca15-tc1.dtb and some different loads.
>
> A note on V7M: the reason we cannot switch the V7M entry over to generic
> entry is that it raises a "pendable service call" ("pendv") exception to
> process deferred work at the end of the interrupt handler. This is done
> so higher priority work can come in. This has no corresponding structure
> in other ARM cores.
>
> This is a reduced patch based on the earlier generic entry series avoiding
> all the syscall handling changes.
>
> Link: https://lore.kernel.org/linux-arm-kernel/20250420-arm-generic-entry-v6-0-95f1fcdfeeb2@linaro.org/
> Signed-off-by: Linus Walleij <linusw@kernel.org>
> ---
> arch/arm/Kconfig | 1 +
> arch/arm/include/asm/entry-common.h | 7 ++++
> arch/arm/include/asm/entry.h | 10 +++++
> arch/arm/include/asm/ptrace.h | 7 +++-
> arch/arm/kernel/Makefile | 2 +-
> arch/arm/kernel/entry-armv.S | 75 ++++++++-----------------------------
> arch/arm/kernel/entry-common.S | 5 ++-
> arch/arm/kernel/entry-header.S | 7 +++-
> arch/arm/kernel/entry-v7m.S | 2 +-
> arch/arm/kernel/entry.c | 51 +++++++++++++++++++++++++
> arch/arm/kernel/irq.c | 6 +++
> arch/arm/kernel/irq.h | 2 +
> arch/arm/kernel/signal.c | 6 +++
> 13 files changed, 116 insertions(+), 65 deletions(-)
>
> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
> index 73e6647bea46..aad21d645ff3 100644
> --- a/arch/arm/Kconfig
> +++ b/arch/arm/Kconfig
> @@ -71,6 +71,7 @@ config ARM
> select GENERIC_CPU_AUTOPROBE
> select GENERIC_CPU_DEVICES
> select GENERIC_EARLY_IOREMAP
> + select GENERIC_IRQ_ENTRY if !CPU_V7M
> select GENERIC_IDLE_POLL_SETUP
> select GENERIC_IRQ_MULTI_HANDLER
> select GENERIC_IRQ_PROBE
> diff --git a/arch/arm/include/asm/entry-common.h b/arch/arm/include/asm/entry-common.h
> new file mode 100644
> index 000000000000..c017df5f39d5
> --- /dev/null
> +++ b/arch/arm/include/asm/entry-common.h
> @@ -0,0 +1,7 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +#ifndef __ASM_ARM_ENTRY_COMMON_H
> +#define __ASM_ARM_ENTRY_COMMON_H
> +
> +#include <asm/stacktrace.h>
> +
> +#endif
> diff --git a/arch/arm/include/asm/entry.h b/arch/arm/include/asm/entry.h
> new file mode 100644
> index 000000000000..864c9b3abbf1
> --- /dev/null
> +++ b/arch/arm/include/asm/entry.h
> @@ -0,0 +1,10 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +#ifndef __ASM_ENTRY_H__
> +#define __ASM_ENTRY_H__
> +
> +struct pt_regs;
> +
> +void arm_irq_handler(struct pt_regs *regs, int mode);
> +void arm_fiq_handler(struct pt_regs *regs);
> +
> +#endif /* __ASM_ENTRY_H__ */
> diff --git a/arch/arm/include/asm/ptrace.h b/arch/arm/include/asm/ptrace.h
> index 6eb311fb2da0..88ddb9371a02 100644
> --- a/arch/arm/include/asm/ptrace.h
> +++ b/arch/arm/include/asm/ptrace.h
> @@ -46,8 +46,13 @@ struct svc_pt_regs {
> #define processor_mode(regs) \
> ((regs)->ARM_cpsr & MODE_MASK)
>
> +static inline bool regs_irqs_disabled(const struct pt_regs *regs)
> +{
> + return regs->ARM_cpsr & PSR_I_BIT;
> +}
> +
> #define interrupts_enabled(regs) \
> - (!((regs)->ARM_cpsr & PSR_I_BIT))
> + (!regs_irqs_disabled(regs))
>
> #define fast_interrupts_enabled(regs) \
> (!((regs)->ARM_cpsr & PSR_F_BIT))
> diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
> index b36cf0cfd4a7..3b8a62f6f54d 100644
> --- a/arch/arm/kernel/Makefile
> +++ b/arch/arm/kernel/Makefile
> @@ -17,7 +17,7 @@ CFLAGS_REMOVE_return_address.o = -pg
>
> # Object file lists.
>
> -obj-y := elf.o entry-common.o irq.o opcodes.o \
> +obj-y := elf.o entry.o entry-common.o irq.o opcodes.o \
> process.o ptrace.o reboot.o io.o \
> setup.o signal.o sigreturn_codes.o \
> stacktrace.o sys_arm.o time.o traps.o
> diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
> index a3d050ce9b79..8ac7f1512ee8 100644
> --- a/arch/arm/kernel/entry-armv.S
> +++ b/arch/arm/kernel/entry-armv.S
> @@ -36,35 +36,6 @@
> #define RELOC_TEXT_NONE
> #endif
>
> -/*
> - * Interrupt handling.
> - */
> - .macro irq_handler, from_user:req
> - mov r1, sp
> - ldr_this_cpu r2, irq_stack_ptr, r2, r3
> - .if \from_user == 0
> - @
> - @ If we took the interrupt while running in the kernel, we may already
> - @ be using the IRQ stack, so revert to the original value in that case.
> - @
> - subs r3, r2, r1 @ SP above bottom of IRQ stack?
> - rsbscs r3, r3, #THREAD_SIZE @ ... and below the top?
> -#ifdef CONFIG_VMAP_STACK
> - ldr_va r3, high_memory, cc @ End of the linear region
> - cmpcc r3, r1 @ Stack pointer was below it?
> -#endif
> - bcc 0f @ If not, switch to the IRQ stack
> - mov r0, r1
> - bl generic_handle_arch_irq
> - b 1f
> -0:
> - .endif
> -
> - mov_l r0, generic_handle_arch_irq
> - bl call_with_stack
> -1:
> - .endm
> -
> .macro pabt_helper
> @ PABORT handler takes pt_regs in r2, fault address in r4 and psr in r5
> #ifdef MULTI_PABORT
> @@ -224,34 +195,17 @@ ENDPROC(__dabt_svc)
>
> .align 5
> __irq_svc:
> - svc_entry
> - irq_handler from_user=0
> -
> -#ifdef CONFIG_PREEMPTION
> - ldr r8, [tsk, #TI_PREEMPT] @ get preempt count
> - ldr r0, [tsk, #TI_FLAGS] @ get flags
> - teq r8, #0 @ if preempt count != 0
> - movne r0, #0 @ force flags to 0
> - tst r0, #_TIF_NEED_RESCHED
> - blne svc_preempt
> -#endif
> + svc_entry trace=0
> + mov r0, sp @ regs
> + mov r1, #0 @ from kernel mode
> + bl arm_irq_handler
>
> - svc_exit r5, irq = 1 @ return from exception
> + svc_exit r5, irqentry = 1 @ return from exception
> UNWIND(.fnend )
> ENDPROC(__irq_svc)
>
> .ltorg
>
> -#ifdef CONFIG_PREEMPTION
> -svc_preempt:
> - mov r8, lr
> -1: bl preempt_schedule_irq @ irq en/disable is done inside
> - ldr r0, [tsk, #TI_FLAGS] @ get new tasks TI_FLAGS
> - tst r0, #_TIF_NEED_RESCHED
> - reteq r8 @ go again
> - b 1b
> -#endif
> -
> __und_fault:
> @ Correct the PC such that it is pointing at the instruction
> @ which caused the fault. If the faulting instruction was ARM
> @@ -302,7 +256,7 @@ ENDPROC(__pabt_svc)
> __fiq_svc:
> svc_entry trace=0
> mov r0, sp @ struct pt_regs *regs
> - bl handle_fiq_as_nmi
> + bl arm_fiq_handler
> svc_exit_via_fiq
> UNWIND(.fnend )
> ENDPROC(__fiq_svc)
> @@ -331,7 +285,7 @@ __fiq_abt:
> stmfd sp!, {r1 - r2}
>
> add r0, sp, #8 @ struct pt_regs *regs
> - bl handle_fiq_as_nmi
> + bl arm_fiq_handler
>
> ldmfd sp!, {r1 - r2}
> ARM( msr cpsr_c, #ABT_MODE | PSR_I_BIT | PSR_F_BIT )
> @@ -438,12 +392,15 @@ ENDPROC(__dabt_usr)
>
> .align 5
> __irq_usr:
> - usr_entry
> + usr_entry trace=0
> kuser_cmpxchg_check
> - irq_handler from_user=1
> - get_thread_info tsk
> - mov why, #0
> - b ret_to_user_from_irq
> + mov r0, sp @ regs
> + mov r1, #1 @ from user mode
> + bl arm_irq_handler
> +#ifdef CONFIG_KSTACK_ERASE
> + bl stackleak_erase_on_task_stack
> +#endif
> + restore_user_regs fast = 0, offset = 0
> UNWIND(.fnend )
> ENDPROC(__irq_usr)
>
> @@ -498,7 +455,7 @@ __fiq_usr:
> usr_entry trace=0
> kuser_cmpxchg_check
> mov r0, sp @ struct pt_regs *regs
> - bl handle_fiq_as_nmi
> + bl arm_fiq_handler
> get_thread_info tsk
> restore_user_regs fast = 0, offset = 0
> UNWIND(.fnend )
> diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S
> index 88336a1292bb..d5fdb234c1d4 100644
> --- a/arch/arm/kernel/entry-common.S
> +++ b/arch/arm/kernel/entry-common.S
> @@ -110,7 +110,8 @@ ret_slow_syscall:
> bl do_rseq_syscall
> #endif
> disable_irq_notrace @ disable interrupts
> -ENTRY(ret_to_user_from_irq)
> +ENTRY(v7m_ret_to_user_from_irq)
> + /* Only the v7m jumps directly to v7m_ret_to_user_from_irq */
> ldr r1, [tsk, #TI_FLAGS]
> movs r1, r1, lsl #16
> bne slow_work_pending
> @@ -123,7 +124,7 @@ no_work_pending:
> bl stackleak_erase_on_task_stack
> #endif
> restore_user_regs fast = 0, offset = 0
> -ENDPROC(ret_to_user_from_irq)
> +ENDPROC(v7m_ret_to_user_from_irq)
> ENDPROC(ret_to_user)
>
> /*
> diff --git a/arch/arm/kernel/entry-header.S b/arch/arm/kernel/entry-header.S
> index 99411fa91350..e83f2fb8a592 100644
> --- a/arch/arm/kernel/entry-header.S
> +++ b/arch/arm/kernel/entry-header.S
> @@ -199,7 +199,11 @@
> .endm
>
>
> - .macro svc_exit, rpsr, irq = 0
> + .macro svc_exit, rpsr, irq = 0, irqentry = 0
> + .if \irqentry != 0
> + @ Generic IRQ entry already handled tracing and lockdep state.
> + disable_irq_notrace
> + .else
> .if \irq != 0
> @ IRQs already off
> #ifdef CONFIG_TRACE_IRQFLAGS
> @@ -216,6 +220,7 @@
> tst \rpsr, #PSR_I_BIT
> blne trace_hardirqs_off
> #endif
> + .endif
> .endif
> uaccess_exit tsk, r0, r1
>
> diff --git a/arch/arm/kernel/entry-v7m.S b/arch/arm/kernel/entry-v7m.S
> index 52bacf07ba16..49a3a34e2913 100644
> --- a/arch/arm/kernel/entry-v7m.S
> +++ b/arch/arm/kernel/entry-v7m.S
> @@ -94,7 +94,7 @@ __pendsv_entry:
> @ execute the pending work, including reschedule
> get_thread_info tsk
> mov why, #0
> - b ret_to_user_from_irq
> + b v7m_ret_to_user_from_irq
> ENDPROC(__pendsv_entry)
>
> /*
> diff --git a/arch/arm/kernel/entry.c b/arch/arm/kernel/entry.c
> new file mode 100644
> index 000000000000..1142e418d161
> --- /dev/null
> +++ b/arch/arm/kernel/entry.c
> @@ -0,0 +1,51 @@
> +// SPDX-License-Identifier: GPL-2.0
> +#include <linux/hardirq.h>
> +#include <linux/irq-entry-common.h>
> +#include <linux/irq.h>
> +
> +#include <asm/entry.h>
> +#include <asm/stacktrace.h>
> +#include <asm/traps.h>
> +
> +#include "irq.h"
> +
> +static void noinstr handle_arm_irq(void *data)
> +{
> + struct pt_regs *regs = data;
> + struct pt_regs *old_regs;
> +
> + irq_enter_rcu();
> + old_regs = set_irq_regs(regs);
> +
> + handle_arch_irq(regs);
> +
> + set_irq_regs(old_regs);
> + irq_exit_rcu();
> +}
> +
> +noinstr void arm_irq_handler(struct pt_regs *regs, int mode)
> +{
> + irqentry_state_t state = irqentry_enter(regs);
> +
> + /*
> + * mode == 1 means we came from userspace, and then we
> + * should just immediately switch to the irq stack.
> + * Then we check of we are on the thread stack. If we are
> + * not, then by definition we are already using the irq stack.
> + */
> + if (mode == 1 || on_thread_stack())
> + call_on_irq_stack(handle_arm_irq, regs);
It seems that the CONFIG_VMAP_STACK Overflow Protection is missing,
should we implement the C version of CONFIG_VMAP_STACK first, before
moving the IRQ handling to C?"
- .macro irq_handler, from_user:req
-#ifdef CONFIG_VMAP_STACK
- ldr_va r3, high_memory, cc @ End of the linear region
- cmpcc r3, r1 @ Stack pointer was below it?
-#endif
> + else
> + handle_arm_irq(regs);
> +
> + irqentry_exit(regs, state);
> +}
> +
> +noinstr void arm_fiq_handler(struct pt_regs *regs)
> +{
> + irqentry_state_t state = irqentry_nmi_enter(regs);
> +
> + handle_fiq_as_nmi(regs);
> +
> + irqentry_nmi_exit(regs, state);
> +}
> diff --git a/arch/arm/kernel/irq.c b/arch/arm/kernel/irq.c
> index e1993e28a9ec..f99d6b24d8ff 100644
> --- a/arch/arm/kernel/irq.c
> +++ b/arch/arm/kernel/irq.c
> @@ -43,6 +43,7 @@
> #include <asm/mach/irq.h>
> #include <asm/mach/time.h>
>
> +#include "irq.h"
> #include "reboot.h"
>
> unsigned long irq_err_count;
> @@ -71,6 +72,11 @@ static void __init init_irq_stacks(void)
> }
> }
>
> +void call_on_irq_stack(void (*fn)(void *), void *arg)
> +{
> + call_with_stack(fn, arg, __this_cpu_read(irq_stack_ptr));
> +}
> +
> #ifdef CONFIG_SOFTIRQ_ON_OWN_STACK
> static void ____do_softirq(void *arg)
> {
> diff --git a/arch/arm/kernel/irq.h b/arch/arm/kernel/irq.h
> new file mode 100644
> index 000000000000..80dd5bfe6403
> --- /dev/null
> +++ b/arch/arm/kernel/irq.h
> @@ -0,0 +1,2 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +void call_on_irq_stack(void (*fn)(void *), void *arg);
> diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c
> index 7be9188d83d9..9084c04c07f7 100644
> --- a/arch/arm/kernel/signal.c
> +++ b/arch/arm/kernel/signal.c
> @@ -12,6 +12,7 @@
> #include <linux/resume_user_mode.h>
> #include <linux/uprobes.h>
> #include <linux/syscalls.h>
> +#include <linux/irq-entry-common.h>
>
> #include <asm/elf.h>
> #include <asm/cacheflush.h>
> @@ -599,6 +600,11 @@ static int do_signal(struct pt_regs *regs, int syscall)
> return 0;
> }
>
> +void arch_do_signal_or_restart(struct pt_regs *regs)
> +{
> + do_signal(regs, 0);
> +}
> +
> asmlinkage int
> do_work_pending(struct pt_regs *regs, unsigned int thread_flags, int syscall)
> {
>
> ---
> base-commit: 8cd9520d35a6c38db6567e97dd93b1f11f185dc6
> change-id: 20260622-arm-generic-irq-entry-v7-1-ff6c1d6c9c48
>
> Best regards,
> --
> Linus Walleij <linusw@kernel.org>
>
>
>
^ permalink raw reply
* [PATCH v2 5.15.y] kselftest/arm64: signal: Skip SVE signal test if not enough VLs supported
From: Yijia Wang @ 2026-06-27 3:22 UTC (permalink / raw)
To: stable, sashal, gregkh
Cc: andre.przywara, linux-kernel, cristian.marussi, will,
catalin.marinas, broonie, shuah, linux-arm-kernel,
linux-kselftest, Yijia Wang
In-Reply-To: <stable-reply-item017-arm64-sve-resend-20260626@kernel.org>
[ Upstream commit 78c09c0f4df89fabdcfb3e5e53d3196cf67f64ef ]
On platform where SVE is supported but there are less than 2 VLs available
the signal SVE change test should be skipped instead of failing.
Reported-by: Andre Przywara <andre.przywara@arm.com>
Tested-by: Andre Przywara <andre.przywara@arm.com>
Cc: Mark Brown <broonie@kernel.org>
Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
Reviewed-by: Mark Brown <broonie@kernel.org>
Link: https://lore.kernel.org/r/20220524103149.2802-1-cristian.marussi@arm.com
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
Signed-off-by: Yijia Wang <wangyijia.yeah@bytedance.com>
---
Changes in v2:
- Keep the commit message aligned with the upstream commit, as requested by
Sasha.
- Link to v1:
https://lore.kernel.org/r/20260626-b4-arm64-515-preview-clean-v1-1-ad19e286e322@bytedance.com
.../arm64/signal/testcases/fake_sigreturn_sve_change_vl.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_sve_change_vl.c b/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_sve_change_vl.c
index bb50b5adb..915821375 100644
--- a/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_sve_change_vl.c
+++ b/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_sve_change_vl.c
@@ -6,6 +6,7 @@
* supported and is expected to segfault.
*/
+#include <kselftest.h>
#include <signal.h>
#include <ucontext.h>
#include <sys/prctl.h>
@@ -40,6 +41,7 @@ static bool sve_get_vls(struct tdescr *td)
/* We need at least two VLs */
if (nvls < 2) {
fprintf(stderr, "Only %d VL supported\n", nvls);
+ td->result = KSFT_SKIP;
return false;
}
--
2.43.0
^ permalink raw reply related
* [PATCH v1] ARM: dts: aspeed: g6: Use KCS AST2600 compatible string
From: Haiyue Wang @ 2026-06-27 5:27 UTC (permalink / raw)
To: devicetree, Andrew Jeffery
Cc: Haiyue Wang, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Joel Stanley, moderated list:ARM/ASPEED MACHINE SUPPORT,
moderated list:ARM/ASPEED MACHINE SUPPORT, open list
As the commit 2596f6b93a60 ("ipmi: kcs: aspeed: Add AST2600 compatible
string") does, change the AST2600 DTS file to use kcs ast2600 compatible
string.
Signed-off-by: Haiyue Wang <haiyuewa@163.com>
---
arch/arm/boot/dts/aspeed/aspeed-g6.dtsi | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/arch/arm/boot/dts/aspeed/aspeed-g6.dtsi b/arch/arm/boot/dts/aspeed/aspeed-g6.dtsi
index 56bb3b0444f7..774d5af495fb 100644
--- a/arch/arm/boot/dts/aspeed/aspeed-g6.dtsi
+++ b/arch/arm/boot/dts/aspeed/aspeed-g6.dtsi
@@ -585,7 +585,7 @@ lpc: lpc@1e789000 {
ranges = <0x0 0x1e789000 0x1000>;
kcs1: kcs@24 {
- compatible = "aspeed,ast2500-kcs-bmc-v2";
+ compatible = "aspeed,ast2600-kcs-bmc";
reg = <0x24 0x1>, <0x30 0x1>, <0x3c 0x1>;
interrupts = <GIC_SPI 138 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&syscon ASPEED_CLK_GATE_LCLK>;
@@ -594,7 +594,7 @@ kcs1: kcs@24 {
};
kcs2: kcs@28 {
- compatible = "aspeed,ast2500-kcs-bmc-v2";
+ compatible = "aspeed,ast2600-kcs-bmc";
reg = <0x28 0x1>, <0x34 0x1>, <0x40 0x1>;
interrupts = <GIC_SPI 139 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&syscon ASPEED_CLK_GATE_LCLK>;
@@ -602,7 +602,7 @@ kcs2: kcs@28 {
};
kcs3: kcs@2c {
- compatible = "aspeed,ast2500-kcs-bmc-v2";
+ compatible = "aspeed,ast2600-kcs-bmc";
reg = <0x2c 0x1>, <0x38 0x1>, <0x44 0x1>;
interrupts = <GIC_SPI 140 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&syscon ASPEED_CLK_GATE_LCLK>;
@@ -610,7 +610,7 @@ kcs3: kcs@2c {
};
kcs4: kcs@114 {
- compatible = "aspeed,ast2500-kcs-bmc-v2";
+ compatible = "aspeed,ast2600-kcs-bmc";
reg = <0x114 0x1>, <0x118 0x1>, <0x11c 0x1>;
interrupts = <GIC_SPI 141 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&syscon ASPEED_CLK_GATE_LCLK>;
--
2.54.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