Source-Changes-HG archive

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

[src/trunk]: src/sys/arch/alpha/pci Support CPU interrupt affinity on Tsunami...



details:   https://anonhg.NetBSD.org/src/rev/bcdeacfb1750
branches:  trunk
changeset: 1014546:bcdeacfb1750
user:      thorpej <thorpej%NetBSD.org@localhost>
date:      Sat Sep 26 02:50:41 2020 +0000

description:
Support CPU interrupt affinity on Tsunami systems.

diffstat:

 sys/arch/alpha/pci/pci_6600.c |  137 ++++++++++++++++++++++++++++++++++++++---
 1 files changed, 125 insertions(+), 12 deletions(-)

diffs (207 lines):

diff -r 1299d76b99ca -r bcdeacfb1750 sys/arch/alpha/pci/pci_6600.c
--- a/sys/arch/alpha/pci/pci_6600.c     Sat Sep 26 02:46:27 2020 +0000
+++ b/sys/arch/alpha/pci/pci_6600.c     Sat Sep 26 02:50:41 2020 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: pci_6600.c,v 1.27 2020/09/23 18:48:50 thorpej Exp $ */
+/* $NetBSD: pci_6600.c,v 1.28 2020/09/26 02:50:41 thorpej Exp $ */
 
 /*-
  * Copyright (c) 1999 by Ross Harvey.  All rights reserved.
@@ -33,13 +33,14 @@
 
 #include <sys/cdefs.h>
 
-__KERNEL_RCSID(0, "$NetBSD: pci_6600.c,v 1.27 2020/09/23 18:48:50 thorpej Exp $");
+__KERNEL_RCSID(0, "$NetBSD: pci_6600.c,v 1.28 2020/09/26 02:50:41 thorpej Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/kernel.h>
 #include <sys/device.h>
 #include <sys/malloc.h>
+#include <sys/cpu.h>
 
 #include <machine/autoconf.h>
 #define _ALPHA_BUS_DMA_PRIVATE
@@ -94,9 +95,15 @@
 
 static void    dec_6600_intr_enable(pci_chipset_tag_t, int irq);
 static void    dec_6600_intr_disable(pci_chipset_tag_t, int irq);
+static void    dec_6600_intr_set_affinity(pci_chipset_tag_t, int,
+                   struct cpu_info *);
 
-/* Software copy of enabled interrupt bits. */
+/*
+ * We keep 2 software copies of the interrupt enables: one global one,
+ * and one per-CPU for setting the interrupt affinity.
+ */
 static uint64_t        dec_6600_intr_enables __read_mostly;
+static uint64_t dec_6600_cpu_intr_enables[4] __read_mostly;
 
 void
 pci_6600_pickintr(struct tsp_config *pcp)
@@ -105,6 +112,8 @@
        pci_chipset_tag_t pc = &pcp->pc_pc;
        char *cp;
        int i;
+       struct cpu_info *ci;
+       CPU_INFO_ITERATOR cii;
 
        pc->pc_intr_v = pcp;
        pc->pc_intr_map = dec_6600_intr_map;
@@ -121,12 +130,25 @@
 
        pc->pc_intr_enable = dec_6600_intr_enable;
        pc->pc_intr_disable = dec_6600_intr_disable;
+       pc->pc_intr_set_affinity = dec_6600_intr_set_affinity;
+
+       /* Note eligible CPUs for interrupt routing purposes. */
+       for (CPU_INFO_FOREACH(cii, ci)) {
+               KASSERT(ci->ci_cpuid < 4);
+               pc->pc_eligible_cpus |= __BIT(ci->ci_cpuid);
+       }
 
        /*
         * System-wide and Pchip-0-only logic...
         */
        if (sioprimary == NULL) {
                sioprimary = pcp;
+               /*
+                * Unless explicitly routed, all interrupts go to the
+                * primary CPU.
+                */
+               dec_6600_cpu_intr_enables[cpu_info_primary.ci_cpuid] =
+                   __BITS(0,63);
                pc->pc_pciide_compat_intr_establish =
                    dec_6600_pciide_compat_intr_establish;
 #define PCI_6600_IRQ_STR       8
@@ -146,7 +168,10 @@
                }
 #if NSIO
                sio_intr_setup(pc, iot);
-               dec_6600_intr_enable(pc, PCI_SIO_IRQ);  /* irq line for sio */
+
+               mutex_enter(&cpu_lock);
+               dec_6600_intr_enable(pc, PCI_SIO_IRQ);
+               mutex_exit(&cpu_lock);
 #endif
        } else {
                pc->pc_shared_intrs = sioprimary->pc_pc.pc_shared_intrs;
@@ -266,21 +291,109 @@
 }
 
 static void
-dec_6600_intr_enable(pci_chipset_tag_t const pc __unused, int const irq)
+dec_6600_intr_program(pci_chipset_tag_t const pc)
 {
-       dec_6600_intr_enables |= 1UL << irq;
+       unsigned int irq, cpuno, cnt;
+
+       /*
+        * Validate the configuration before we program it: each enabled
+        * IRQ must be routed to exactly one CPU.
+        */
+       for (irq = 0; irq < PCI_NIRQ; irq++) {
+               if ((dec_6600_intr_enables & __BIT(irq)) == 0)
+                       continue;
+               for (cpuno = 0, cnt = 0; cpuno < 4; cpuno++) {
+                       if (dec_6600_cpu_intr_enables[cpuno] != 0 &&
+                           (pc->pc_eligible_cpus & __BIT(cpuno)) == 0)
+                               panic("%s: interrupts enabled on non-existent CPU %u",
+                                   __func__, cpuno);
+                       if (dec_6600_cpu_intr_enables[cpuno] & __BIT(irq))
+                               cnt++;
+               }
+               if (cnt != 1) {
+                       panic("%s: irq %u enabled on %u CPUs", __func__,
+                           irq, cnt);
+               }
+       }
+
+       const uint64_t enab0 =
+           dec_6600_intr_enables & dec_6600_cpu_intr_enables[0];
+       const uint64_t enab1 =
+           dec_6600_intr_enables & dec_6600_cpu_intr_enables[1];
+       const uint64_t enab2 =
+           dec_6600_intr_enables & dec_6600_cpu_intr_enables[2];
+       const uint64_t enab3 =
+           dec_6600_intr_enables & dec_6600_cpu_intr_enables[3];
+
+       /* Don't touch DIMx registers for non-existent CPUs. */
+       uint64_t black_hole;
+       volatile uint64_t * const dim0 = (pc->pc_eligible_cpus & __BIT(0)) ?
+           (void *)ALPHA_PHYS_TO_K0SEG(TS_C_DIM0) : &black_hole;
+       volatile uint64_t * const dim1 = (pc->pc_eligible_cpus & __BIT(1)) ?
+           (void *)ALPHA_PHYS_TO_K0SEG(TS_C_DIM1) : &black_hole;
+       volatile uint64_t * const dim2 = (pc->pc_eligible_cpus & __BIT(2)) ?
+           (void *)ALPHA_PHYS_TO_K0SEG(TS_C_DIM2) : &black_hole;
+       volatile uint64_t * const dim3 = (pc->pc_eligible_cpus & __BIT(3)) ?
+           (void *)ALPHA_PHYS_TO_K0SEG(TS_C_DIM3) : &black_hole;
+
+       const unsigned long psl = alpha_pal_swpipl(ALPHA_PSL_IPL_HIGH);
+
        alpha_mb();
-       STQP(TS_C_DIM0) = dec_6600_intr_enables;
+       *dim0 = enab0;
+       *dim1 = enab1;
+       *dim2 = enab2;
+       *dim3 = enab3;
        alpha_mb();
+       (void) *dim0;
+       (void) *dim1;
+       (void) *dim2;
+       (void) *dim3;
+       alpha_mb();
+
+       alpha_pal_swpipl(psl);
 }
 
 static void
-dec_6600_intr_disable(pci_chipset_tag_t const pc __unused, int const irq)
+dec_6600_intr_enable(pci_chipset_tag_t const pc, int const irq)
+{
+
+       KASSERT(mutex_owned(&cpu_lock));
+
+       dec_6600_intr_enables |= __BIT(irq);
+       dec_6600_intr_program(pc);
+}
+
+static void
+dec_6600_intr_disable(pci_chipset_tag_t const pc, int const irq)
 {
-       dec_6600_intr_enables &= ~(1UL << irq);
-       alpha_mb();
-       STQP(TS_C_DIM0) = dec_6600_intr_enables;
-       alpha_mb();
+
+       KASSERT(mutex_owned(&cpu_lock));
+
+       dec_6600_intr_enables &= ~__BIT(irq);
+       dec_6600_intr_program(pc);
+}
+
+static void
+dec_6600_intr_set_affinity(pci_chipset_tag_t const pc, int const irq,
+    struct cpu_info * const ci)
+{
+       const uint64_t intr_bit = __BIT(irq);
+       cpuid_t cpuno;
+
+       KASSERT(mutex_owned(&cpu_lock));
+       KASSERT(ci->ci_cpuid < 4);
+       KASSERT(pc->pc_eligible_cpus & __BIT(ci->ci_cpuid));
+
+       for (cpuno = 0; cpuno < 4; cpuno++) {
+               if (cpuno == ci->ci_cpuid)
+                       dec_6600_cpu_intr_enables[cpuno] |= intr_bit;
+               else
+                       dec_6600_cpu_intr_enables[cpuno] &= ~intr_bit;
+       }
+
+       /* Only program the hardware if the irq is enabled. */
+       if (dec_6600_intr_enables & intr_bit)
+               dec_6600_intr_program(pc);
 }
 
 static void *



Home | Main Index | Thread Index | Old Index