Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/arch/alpha Add support for CPU interrupt affinity for PC...



details:   https://anonhg.NetBSD.org/src/rev/d44b279931ef
branches:  trunk
changeset: 939351:d44b279931ef
user:      thorpej <thorpej%NetBSD.org@localhost>
date:      Sat Sep 26 02:46:27 2020 +0000

description:
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.

diffstat:

 sys/arch/alpha/include/pci_machdep.h |   6 ++-
 sys/arch/alpha/pci/pci_machdep.c     |  83 ++++++++++++++++++++++++++++++++++-
 2 files changed, 85 insertions(+), 4 deletions(-)

diffs (140 lines):

diff -r 01a032243aad -r d44b279931ef sys/arch/alpha/include/pci_machdep.h
--- a/sys/arch/alpha/include/pci_machdep.h      Sat Sep 26 02:35:31 2020 +0000
+++ b/sys/arch/alpha/include/pci_machdep.h      Sat Sep 26 02:46:27 2020 +0000
@@ -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 @@
        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 *);
 };
 
 /*
diff -r 01a032243aad -r d44b279931ef sys/arch/alpha/pci/pci_machdep.c
--- a/sys/arch/alpha/pci/pci_machdep.c  Sat Sep 26 02:35:31 2020 +0000
+++ b/sys/arch/alpha/pci/pci_machdep.c  Sat Sep 26 02:46:27 2020 +0000
@@ -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 @@
        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 @@
 
        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 @@
                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);



Home | Main Index | Thread Index | Old Index