git: b2ba4131b9b0 - main - intrng: Shuffle unhandled interrupts too

From: Colin Percival <cperciva_at_FreeBSD.org>
Date: Wed, 18 Feb 2026 16:26:55 UTC
The branch main has been updated by cperciva:

URL: https://cgit.FreeBSD.org/src/commit/?id=b2ba4131b9b08d6231392c0b798d0ff35809f600

commit b2ba4131b9b08d6231392c0b798d0ff35809f600
Author:     Colin Percival <cperciva@FreeBSD.org>
AuthorDate: 2026-02-14 00:35:26 +0000
Commit:     Colin Percival <cperciva@FreeBSD.org>
CommitDate: 2026-02-18 16:26:37 +0000

    intrng: Shuffle unhandled interrupts too
    
    When interrupt vectors are first allocated, they get assigned to
    CPU #0; at SI_SUB_SMP / SI_ORDER_SECOND (aka once we have multiple
    CPUs), the intr_irq_shuffle SYSINIT clears their CPU sets with the
    effect of forcing them to be assigned to new CPUs later.
    
    In case where interrupt vectors were allocated *but not yet bound*
    this code did not run, with the effect that those interrupts would
    remain pinned to CPU #0 forever.  This affected the ena(4) driver,
    which allocates interrupts for I/O when the device is attached but
    doesn't set them up until the interface is brought up much later in
    the boot process (and, crucially, long after intr_irq_shuffle runs).
    
    Adjust intr_irq_shuffle to clear the CPU set for an interrupt source
    even if it currently has no handlers, so that it will be properly
    assigned to a CPU when it is used later.
    
    Reviewed by:    andrew, mhorne
    MFC after:      1 month
    Sponsored by:   Amazon
    Differential Revision:  https://reviews.freebsd.org/D55284
---
 sys/kern/subr_intr.c | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/sys/kern/subr_intr.c b/sys/kern/subr_intr.c
index 3de753a5192f..52170f083624 100644
--- a/sys/kern/subr_intr.c
+++ b/sys/kern/subr_intr.c
@@ -1291,10 +1291,22 @@ intr_irq_shuffle(void *arg __unused)
 	irq_assign_cpu = true;
 	for (i = 0; i < intr_nirq; i++) {
 		isrc = irq_sources[i];
-		if (isrc == NULL || isrc->isrc_handlers == 0 ||
+		if (isrc == NULL ||
 		    isrc->isrc_flags & (INTR_ISRCF_PPI | INTR_ISRCF_IPI))
 			continue;
 
+		/*
+		 * We can reach this point with isrc_handlers == 0 if a
+		 * driver allocates interrupts but does not set them up
+		 * immediately; for example, a network driver might
+		 * postpone calling bus_setup_intr on I/O IRQ(s) until
+		 * the interface is brought up.
+		 */
+		if (isrc->isrc_handlers == 0) {
+			CPU_ZERO(&isrc->isrc_cpu);
+			continue;
+		}
+
 		if (isrc->isrc_event != NULL &&
 		    isrc->isrc_flags & INTR_ISRCF_BOUND &&
 		    isrc->isrc_event->ie_cpu != CPU_FFS(&isrc->isrc_cpu) - 1)