Module Name: src Committed By: thorpej Date: Sat Sep 26 02:46:28 UTC 2020
Modified Files: src/sys/arch/alpha/include: pci_machdep.h src/sys/arch/alpha/pci: pci_machdep.c Log Message: Add support for CPU interrupt affinity for PCI interrupts: - Keep a bitmap of eligible interrupt-handling CPUs in the pci_chipset_tag_t. If this bitmap is 0, then we assume that all PCI interrupts should be routed to the primary CPU. - Add an optional PCI chipset callback for setting the CPU affinity of an interrupt. - When an establishing an interrupt handler, select the CPU that will handle this irq using the following algorithm: ==> If the irq already has a CPU assignment, keep it. ==> Otherwise, find the CPU with the fewest registered handlers that is eligible from both a hardware (based on the pci_chipset_tag_t) and software (based on cpu_info::ci_schedstate.spc_flags) perspectives. ==> Fall back to the primary CPU failing all else. To generate a diff of this commit: cvs rdiff -u -r1.19 -r1.20 src/sys/arch/alpha/include/pci_machdep.h cvs rdiff -u -r1.26 -r1.27 src/sys/arch/alpha/pci/pci_machdep.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/arch/alpha/include/pci_machdep.h diff -u src/sys/arch/alpha/include/pci_machdep.h:1.19 src/sys/arch/alpha/include/pci_machdep.h:1.20 --- src/sys/arch/alpha/include/pci_machdep.h:1.19 Tue Sep 22 15:24:01 2020 +++ src/sys/arch/alpha/include/pci_machdep.h Sat Sep 26 02:46:27 2020 @@ -1,4 +1,4 @@ -/* $NetBSD: pci_machdep.h,v 1.19 2020/09/22 15:24:01 thorpej Exp $ */ +/* $NetBSD: pci_machdep.h,v 1.20 2020/09/26 02:46:27 thorpej Exp $ */ /* * Copyright (c) 1996 Carnegie-Mellon University. @@ -87,8 +87,12 @@ struct alpha_pci_chipset { u_long pc_vecbase; u_int pc_nirq; + u_long pc_eligible_cpus; + void (*pc_intr_enable)(pci_chipset_tag_t, int); void (*pc_intr_disable)(pci_chipset_tag_t, int); + void (*pc_intr_set_affinity)(pci_chipset_tag_t, int, + struct cpu_info *); }; /* Index: src/sys/arch/alpha/pci/pci_machdep.c diff -u src/sys/arch/alpha/pci/pci_machdep.c:1.26 src/sys/arch/alpha/pci/pci_machdep.c:1.27 --- src/sys/arch/alpha/pci/pci_machdep.c:1.26 Fri Sep 25 03:40:11 2020 +++ src/sys/arch/alpha/pci/pci_machdep.c Sat Sep 26 02:46:28 2020 @@ -1,4 +1,4 @@ -/* $NetBSD: pci_machdep.c,v 1.26 2020/09/25 03:40:11 thorpej Exp $ */ +/* $NetBSD: pci_machdep.c,v 1.27 2020/09/26 02:46:28 thorpej Exp $ */ /*- * Copyright (c) 2020 The NetBSD Foundation, Inc. @@ -62,7 +62,7 @@ #include <sys/cdefs.h> /* RCS ID & Copyright macro defns */ -__KERNEL_RCSID(0, "$NetBSD: pci_machdep.c,v 1.26 2020/09/25 03:40:11 thorpej Exp $"); +__KERNEL_RCSID(0, "$NetBSD: pci_machdep.c,v 1.27 2020/09/26 02:46:28 thorpej Exp $"); #include <sys/types.h> #include <sys/param.h> @@ -224,6 +224,63 @@ alpha_pci_generic_intr_evcnt(pci_chipset return alpha_shared_intr_evcnt(pc->pc_shared_intrs, irq); } +static struct cpu_info * +alpha_pci_generic_intr_select_cpu(pci_chipset_tag_t const pc, u_int const irq, + u_int const flags) +{ + struct cpu_info *ci, *best_ci; + CPU_INFO_ITERATOR cii; + + KASSERT(mutex_owned(&cpu_lock)); + + /* + * If the back-end didn't tell us where we can route, then + * they all go to the primry CPU. + */ + if (pc->pc_eligible_cpus == 0) { + return &cpu_info_primary; + } + + /* + * If the interrupt already has a CPU assigned, keep on using it, + * unless the CPU has become ineligible. + */ + ci = alpha_shared_intr_get_cpu(pc->pc_shared_intrs, irq); + if (ci != NULL) { + if ((ci->ci_schedstate.spc_flags & SPCF_NOINTR) == 0 || + CPU_IS_PRIMARY(ci)) { + return ci; + } + } + + /* + * Pick the CPU with the fewest handlers. + */ + best_ci = NULL; + for (CPU_INFO_FOREACH(cii, ci)) { + if ((pc->pc_eligible_cpus & __BIT(ci->ci_cpuid)) == 0) { + /* This CPU is not eligible in hardware. */ + continue; + } + if (ci->ci_schedstate.spc_flags & SPCF_NOINTR) { + /* This CPU is not eligible in software. */ + continue; + } + if (best_ci == NULL || + ci->ci_nintrhand < best_ci->ci_nintrhand) { + best_ci = ci; + } + } + + /* If we found one, cool... */ + if (best_ci != NULL) { + return best_ci; + } + + /* ...if not, well I guess we'll just fall back on the primary. */ + return &cpu_info_primary; +} + void * alpha_pci_generic_intr_establish(pci_chipset_tag_t const pc, pci_intr_handle_t const ih, int const level, @@ -243,6 +300,26 @@ alpha_pci_generic_intr_establish(pci_chi mutex_enter(&cpu_lock); + struct cpu_info *target_ci = + alpha_pci_generic_intr_select_cpu(pc, irq, flags); + struct cpu_info *current_ci = + alpha_shared_intr_get_cpu(pc->pc_shared_intrs, irq); + + const bool first_handler = + ! alpha_shared_intr_isactive(pc->pc_shared_intrs, irq); + + /* + * If this is the first handler on this interrupt, or if the + * target CPU has changed, then program the route if the + * hardware supports it. + */ + if (first_handler || target_ci != current_ci) { + alpha_shared_intr_set_cpu(pc->pc_shared_intrs, irq, target_ci); + if (pc->pc_intr_set_affinity != NULL) { + pc->pc_intr_set_affinity(pc, irq, target_ci); + } + } + if (! alpha_shared_intr_link(pc->pc_shared_intrs, cookie, pc->pc_intr_desc)) { mutex_exit(&cpu_lock); @@ -250,7 +327,7 @@ alpha_pci_generic_intr_establish(pci_chi return NULL; } - if (alpha_shared_intr_firstactive(pc->pc_shared_intrs, irq)) { + if (first_handler) { scb_set(pc->pc_vecbase + SCB_IDXTOVEC(irq), alpha_pci_generic_iointr, pc); pc->pc_intr_enable(pc, irq);