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);

Reply via email to