1*efc604cfSriastradh /* $NetBSD: octeon_intr.c,v 1.27 2022/04/09 23:34:40 riastradh Exp $ */
2f693c922Shikaru /*
3f693c922Shikaru * Copyright 2001, 2002 Wasabi Systems, Inc.
4f693c922Shikaru * All rights reserved.
5f693c922Shikaru *
6f693c922Shikaru * Written by Jason R. Thorpe and Simon Burge for Wasabi Systems, Inc.
7f693c922Shikaru *
8f693c922Shikaru * Redistribution and use in source and binary forms, with or without
9f693c922Shikaru * modification, are permitted provided that the following conditions
10f693c922Shikaru * are met:
11f693c922Shikaru * 1. Redistributions of source code must retain the above copyright
12f693c922Shikaru * notice, this list of conditions and the following disclaimer.
13f693c922Shikaru * 2. Redistributions in binary form must reproduce the above copyright
14f693c922Shikaru * notice, this list of conditions and the following disclaimer in the
15f693c922Shikaru * documentation and/or other materials provided with the distribution.
16f693c922Shikaru * 3. All advertising materials mentioning features or use of this software
17f693c922Shikaru * must display the following acknowledgement:
18f693c922Shikaru * This product includes software developed for the NetBSD Project by
19f693c922Shikaru * Wasabi Systems, Inc.
20f693c922Shikaru * 4. The name of Wasabi Systems, Inc. may not be used to endorse
21f693c922Shikaru * or promote products derived from this software without specific prior
22f693c922Shikaru * written permission.
23f693c922Shikaru *
24f693c922Shikaru * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
25f693c922Shikaru * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
26f693c922Shikaru * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
27f693c922Shikaru * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
28f693c922Shikaru * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29f693c922Shikaru * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30f693c922Shikaru * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31f693c922Shikaru * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
32f693c922Shikaru * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33f693c922Shikaru * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34f693c922Shikaru * POSSIBILITY OF SUCH DAMAGE.
35f693c922Shikaru */
36f693c922Shikaru
37f693c922Shikaru /*
38f693c922Shikaru * Platform-specific interrupt support for the MIPS Malta.
39f693c922Shikaru */
40f693c922Shikaru
414ac893a7Sskrll #include "opt_multiprocessor.h"
424ac893a7Sskrll
43847a1893Smatt #include "cpunode.h"
44f693c922Shikaru #define __INTR_PRIVATE
45f693c922Shikaru
46f693c922Shikaru #include <sys/cdefs.h>
47*efc604cfSriastradh __KERNEL_RCSID(0, "$NetBSD: octeon_intr.c,v 1.27 2022/04/09 23:34:40 riastradh Exp $");
48f693c922Shikaru
49f693c922Shikaru #include <sys/param.h>
50f693c922Shikaru #include <sys/cpu.h>
51f693c922Shikaru #include <sys/systm.h>
52f693c922Shikaru #include <sys/device.h>
53f693c922Shikaru #include <sys/intr.h>
54f693c922Shikaru #include <sys/kernel.h>
552d299731Smatt #include <sys/kmem.h>
562d299731Smatt #include <sys/atomic.h>
577bd5abd3Sriastradh #include <sys/xcall.h>
58f693c922Shikaru
59f693c922Shikaru #include <lib/libkern/libkern.h>
60f693c922Shikaru
61f693c922Shikaru #include <mips/locore.h>
62f693c922Shikaru
63f693c922Shikaru #include <mips/cavium/dev/octeon_ciureg.h>
64f693c922Shikaru #include <mips/cavium/octeonvar.h>
65f693c922Shikaru
66f693c922Shikaru /*
674b99df67Ssimonb * XXX:
684b99df67Ssimonb * Force all interrupts (except clock intrs and IPIs) to be routed
694b99df67Ssimonb * through cpu0 until MP on MIPS is more stable.
704b99df67Ssimonb */
714b99df67Ssimonb #define OCTEON_CPU0_INTERRUPTS
724b99df67Ssimonb
734b99df67Ssimonb
744b99df67Ssimonb /*
75f693c922Shikaru * This is a mask of bits to clear in the SR when we go to a
76f693c922Shikaru * given hardware interrupt priority level.
77f693c922Shikaru */
78f693c922Shikaru static const struct ipl_sr_map octeon_ipl_sr_map = {
79f693c922Shikaru .sr_bits = {
80f693c922Shikaru [IPL_NONE] = 0,
81f693c922Shikaru [IPL_SOFTCLOCK] = MIPS_SOFT_INT_MASK_0,
82f693c922Shikaru [IPL_SOFTNET] = MIPS_SOFT_INT_MASK,
83f693c922Shikaru [IPL_VM] = MIPS_SOFT_INT_MASK | MIPS_INT_MASK_0,
84f693c922Shikaru [IPL_SCHED] = MIPS_SOFT_INT_MASK | MIPS_INT_MASK_0
857a18db21Sskrll | MIPS_INT_MASK_1 | MIPS_INT_MASK_5,
862d299731Smatt [IPL_DDB] = MIPS_SOFT_INT_MASK | MIPS_INT_MASK_0
872d299731Smatt | MIPS_INT_MASK_1 | MIPS_INT_MASK_5,
88f693c922Shikaru [IPL_HIGH] = MIPS_INT_MASK,
89f693c922Shikaru },
90f693c922Shikaru };
91f693c922Shikaru
924f2a7f3aSsimonb static const char * octeon_intrnames[NIRQS] = {
93f693c922Shikaru "workq 0",
94f693c922Shikaru "workq 1",
95f693c922Shikaru "workq 2",
96f693c922Shikaru "workq 3",
97f693c922Shikaru "workq 4",
98f693c922Shikaru "workq 5",
99f693c922Shikaru "workq 6",
100f693c922Shikaru "workq 7",
101f693c922Shikaru "workq 8",
102f693c922Shikaru "workq 9",
103f693c922Shikaru "workq 10",
104f693c922Shikaru "workq 11",
105f693c922Shikaru "workq 12",
106f693c922Shikaru "workq 13",
107f693c922Shikaru "workq 14",
108f693c922Shikaru "workq 15",
109f693c922Shikaru "gpio 0",
110f693c922Shikaru "gpio 1",
111f693c922Shikaru "gpio 2",
112f693c922Shikaru "gpio 3",
113f693c922Shikaru "gpio 4",
114f693c922Shikaru "gpio 5",
115f693c922Shikaru "gpio 6",
116f693c922Shikaru "gpio 7",
117f693c922Shikaru "gpio 8",
118f693c922Shikaru "gpio 9",
119f693c922Shikaru "gpio 10",
120f693c922Shikaru "gpio 11",
121f693c922Shikaru "gpio 12",
122f693c922Shikaru "gpio 13",
123f693c922Shikaru "gpio 14",
124f693c922Shikaru "gpio 15",
125f693c922Shikaru "mbox 0-15",
126f693c922Shikaru "mbox 16-31",
127f693c922Shikaru "uart 0",
128f693c922Shikaru "uart 1",
129f693c922Shikaru "pci inta",
130f693c922Shikaru "pci intb",
131f693c922Shikaru "pci intc",
132f693c922Shikaru "pci intd",
133f693c922Shikaru "pci msi 0-15",
134f693c922Shikaru "pci msi 16-31",
135f693c922Shikaru "pci msi 32-47",
136f693c922Shikaru "pci msi 48-63",
137f693c922Shikaru "wdog summary",
138f693c922Shikaru "twsi",
139f693c922Shikaru "rml",
140f693c922Shikaru "trace",
141f693c922Shikaru "gmx drop",
142f693c922Shikaru "reserved",
143f693c922Shikaru "ipd drop",
144f693c922Shikaru "reserved",
145f693c922Shikaru "timer 0",
146f693c922Shikaru "timer 1",
147f693c922Shikaru "timer 2",
148f693c922Shikaru "timer 3",
149f693c922Shikaru "usb",
150f693c922Shikaru "pcm/tdm",
151f693c922Shikaru "mpi/spi",
152f693c922Shikaru "reserved",
153f693c922Shikaru "reserved",
154f693c922Shikaru "reserved",
155f693c922Shikaru "reserved",
156f693c922Shikaru "reserved",
157f693c922Shikaru };
158f693c922Shikaru
159f693c922Shikaru struct octeon_intrhand {
160f693c922Shikaru int (*ih_func)(void *);
161f693c922Shikaru void *ih_arg;
162f693c922Shikaru int ih_irq;
163f693c922Shikaru int ih_ipl;
164f693c922Shikaru };
165f693c922Shikaru
1662d299731Smatt #ifdef MULTIPROCESSOR
1672d299731Smatt static int octeon_send_ipi(struct cpu_info *, int);
1682d299731Smatt static int octeon_ipi_intr(void *);
1692d299731Smatt
170ccc08332Sskrll static struct octeon_intrhand ipi_intrhands[2] = {
1712d299731Smatt [0] = {
1722d299731Smatt .ih_func = octeon_ipi_intr,
1732d299731Smatt .ih_arg = (void *)(uintptr_t)__BITS(15,0),
17482a25ec3Ssimonb .ih_irq = CIU_INT_MBOX_15_0,
1752d299731Smatt .ih_ipl = IPL_HIGH,
1762d299731Smatt },
1774a584abcSjmcneill [1] = {
1784a584abcSjmcneill .ih_func = octeon_ipi_intr,
1794a584abcSjmcneill .ih_arg = (void *)(uintptr_t)__BITS(31,16),
1804a584abcSjmcneill .ih_irq = CIU_INT_MBOX_31_16,
1814a584abcSjmcneill .ih_ipl = IPL_SCHED,
1824a584abcSjmcneill },
183f693c922Shikaru };
1844a584abcSjmcneill
1854a584abcSjmcneill static int ipi_prio[NIPIS] = {
1864a584abcSjmcneill [IPI_NOP] = IPL_HIGH,
1874a584abcSjmcneill [IPI_AST] = IPL_HIGH,
1884a584abcSjmcneill [IPI_SHOOTDOWN] = IPL_SCHED,
1894a584abcSjmcneill [IPI_SYNCICACHE] = IPL_HIGH,
1904a584abcSjmcneill [IPI_KPREEMPT] = IPL_HIGH,
1914a584abcSjmcneill [IPI_SUSPEND] = IPL_HIGH,
1924a584abcSjmcneill [IPI_HALT] = IPL_HIGH,
1934a584abcSjmcneill [IPI_XCALL] = IPL_HIGH,
1944a584abcSjmcneill [IPI_GENERIC] = IPL_HIGH,
1954a584abcSjmcneill [IPI_WDOG] = IPL_HIGH,
1964a584abcSjmcneill };
1974a584abcSjmcneill
198f693c922Shikaru #endif
199f693c922Shikaru
2004f2a7f3aSsimonb static struct octeon_intrhand *octciu_intrs[NIRQS] = {
2012d299731Smatt #ifdef MULTIPROCESSOR
20282a25ec3Ssimonb [CIU_INT_MBOX_15_0] = &ipi_intrhands[0],
2034a584abcSjmcneill [CIU_INT_MBOX_31_16] = &ipi_intrhands[1],
2042d299731Smatt #endif
2052d299731Smatt };
2062d299731Smatt
2074f2a7f3aSsimonb static kmutex_t octeon_intr_lock;
2082d299731Smatt
209793877b0Sjmcneill #if defined(MULTIPROCESSOR)
210793877b0Sjmcneill #define OCTEON_NCPU MAXCPUS
211793877b0Sjmcneill #else
212793877b0Sjmcneill #define OCTEON_NCPU 1
213793877b0Sjmcneill #endif
214793877b0Sjmcneill
215793877b0Sjmcneill struct cpu_softc octeon_cpu_softc[OCTEON_NCPU];
216793877b0Sjmcneill
217793877b0Sjmcneill static void
octeon_intr_setup(void)218793877b0Sjmcneill octeon_intr_setup(void)
219793877b0Sjmcneill {
220793877b0Sjmcneill struct cpu_softc *cpu;
221793877b0Sjmcneill int cpunum;
222793877b0Sjmcneill
2232d299731Smatt #define X(a) MIPS_PHYS_TO_XKPHYS(OCTEON_CCA_NONE, (a))
2242d299731Smatt
225793877b0Sjmcneill for (cpunum = 0; cpunum < OCTEON_NCPU; cpunum++) {
226793877b0Sjmcneill cpu = &octeon_cpu_softc[cpunum];
2272d299731Smatt
228793877b0Sjmcneill cpu->cpu_ip2_sum0 = X(CIU_IP2_SUM0(cpunum));
229793877b0Sjmcneill cpu->cpu_ip3_sum0 = X(CIU_IP3_SUM0(cpunum));
230793877b0Sjmcneill cpu->cpu_ip4_sum0 = X(CIU_IP4_SUM0(cpunum));
231d911ef3aSjmcneill
232793877b0Sjmcneill cpu->cpu_int_sum1 = X(CIU_INT_SUM1);
2332d299731Smatt
234793877b0Sjmcneill cpu->cpu_ip2_en[0] = X(CIU_IP2_EN0(cpunum));
235793877b0Sjmcneill cpu->cpu_ip3_en[0] = X(CIU_IP3_EN0(cpunum));
236793877b0Sjmcneill cpu->cpu_ip4_en[0] = X(CIU_IP4_EN0(cpunum));
2372d299731Smatt
238793877b0Sjmcneill cpu->cpu_ip2_en[1] = X(CIU_IP2_EN1(cpunum));
239793877b0Sjmcneill cpu->cpu_ip3_en[1] = X(CIU_IP3_EN1(cpunum));
240793877b0Sjmcneill cpu->cpu_ip4_en[1] = X(CIU_IP4_EN1(cpunum));
2412d299731Smatt
242793877b0Sjmcneill cpu->cpu_wdog = X(CIU_WDOG(cpunum));
243793877b0Sjmcneill cpu->cpu_pp_poke = X(CIU_PP_POKE(cpunum));
244847a1893Smatt
2452d299731Smatt #ifdef MULTIPROCESSOR
246793877b0Sjmcneill cpu->cpu_mbox_set = X(CIU_MBOX_SET(cpunum));
247793877b0Sjmcneill cpu->cpu_mbox_clr = X(CIU_MBOX_CLR(cpunum));
2482d299731Smatt #endif
249847a1893Smatt }
250847a1893Smatt
2512d299731Smatt #undef X
2522d299731Smatt
253793877b0Sjmcneill }
254793877b0Sjmcneill
255f693c922Shikaru void
octeon_intr_init(struct cpu_info * ci)2562d299731Smatt octeon_intr_init(struct cpu_info *ci)
257f693c922Shikaru {
2582d299731Smatt const int cpunum = cpu_index(ci);
259793877b0Sjmcneill struct cpu_softc *cpu = &octeon_cpu_softc[cpunum];
2602d299731Smatt const char * const xname = cpu_name(ci);
261e78c0566Sjmcneill int bank;
2622d299731Smatt
263793877b0Sjmcneill cpu->cpu_ci = ci;
264793877b0Sjmcneill ci->ci_softc = cpu;
265793877b0Sjmcneill
266793877b0Sjmcneill KASSERT(cpunum == ci->ci_cpuid);
267f693c922Shikaru
2682d299731Smatt if (ci->ci_cpuid == 0) {
269847a1893Smatt ipl_sr_map = octeon_ipl_sr_map;
2702d299731Smatt mutex_init(&octeon_intr_lock, MUTEX_DEFAULT, IPL_HIGH);
2712d299731Smatt #ifdef MULTIPROCESSOR
2722d299731Smatt mips_locoresw.lsw_send_ipi = octeon_send_ipi;
2732d299731Smatt #endif
274793877b0Sjmcneill
275793877b0Sjmcneill octeon_intr_setup();
276f693c922Shikaru }
2772d299731Smatt
2782d299731Smatt #ifdef MULTIPROCESSOR
2792d299731Smatt // Enable the IPIs
2807d9c74a0Sjmcneill cpu->cpu_ip4_enable[0] |= __BIT(CIU_INT_MBOX_15_0);
2814a584abcSjmcneill cpu->cpu_ip3_enable[0] |= __BIT(CIU_INT_MBOX_31_16);
2822d299731Smatt #endif
2832d299731Smatt
284e78c0566Sjmcneill if (ci->ci_dev) {
285e78c0566Sjmcneill for (bank = 0; bank < NBANKS; bank++) {
286847a1893Smatt aprint_verbose_dev(ci->ci_dev,
287e78c0566Sjmcneill "enabling intr masks %u "
288e78c0566Sjmcneill " %#"PRIx64"/%#"PRIx64"/%#"PRIx64"\n",
289e78c0566Sjmcneill bank,
290793877b0Sjmcneill cpu->cpu_ip2_enable[bank],
291793877b0Sjmcneill cpu->cpu_ip3_enable[bank],
292793877b0Sjmcneill cpu->cpu_ip4_enable[bank]);
293e78c0566Sjmcneill }
294e78c0566Sjmcneill }
295847a1893Smatt
296e78c0566Sjmcneill for (bank = 0; bank < NBANKS; bank++) {
297793877b0Sjmcneill mips3_sd(cpu->cpu_ip2_en[bank], cpu->cpu_ip2_enable[bank]);
298793877b0Sjmcneill mips3_sd(cpu->cpu_ip3_en[bank], cpu->cpu_ip3_enable[bank]);
299793877b0Sjmcneill mips3_sd(cpu->cpu_ip4_en[bank], cpu->cpu_ip4_enable[bank]);
300e78c0566Sjmcneill }
3012d299731Smatt
3022d299731Smatt #ifdef MULTIPROCESSOR
303d7e78fcfSmatt mips3_sd(cpu->cpu_mbox_clr, __BITS(31,0));
3042d299731Smatt #endif
305f693c922Shikaru
306d911ef3aSjmcneill for (int i = 0; i < NIRQS; i++) {
307d911ef3aSjmcneill if (octeon_intrnames[i] == NULL)
308d911ef3aSjmcneill octeon_intrnames[i] = kmem_asprintf("irq %d", i);
3092d299731Smatt evcnt_attach_dynamic(&cpu->cpu_intr_evs[i],
3102d299731Smatt EVCNT_TYPE_INTR, NULL, xname, octeon_intrnames[i]);
311f693c922Shikaru }
312f693c922Shikaru }
313f693c922Shikaru
314f693c922Shikaru void
octeon_cal_timer(int corefreq)315f693c922Shikaru octeon_cal_timer(int corefreq)
316f693c922Shikaru {
317f693c922Shikaru /* Compute the number of cycles per second. */
318f693c922Shikaru curcpu()->ci_cpu_freq = corefreq;
319f693c922Shikaru
320f693c922Shikaru /* Compute the number of ticks for hz. */
321f693c922Shikaru curcpu()->ci_cycles_per_hz = (curcpu()->ci_cpu_freq + hz / 2) / hz;
322f693c922Shikaru
323f693c922Shikaru /* Compute the delay divisor and reciprical. */
324f693c922Shikaru curcpu()->ci_divisor_delay =
325f693c922Shikaru ((curcpu()->ci_cpu_freq + 500000) / 1000000);
326f693c922Shikaru #if 0
327f693c922Shikaru MIPS_SET_CI_RECIPRICAL(curcpu());
328f693c922Shikaru #endif
329f693c922Shikaru
330f693c922Shikaru mips3_cp0_count_write(0);
331f693c922Shikaru mips3_cp0_compare_write(0);
332f693c922Shikaru }
333f693c922Shikaru
334f693c922Shikaru void *
octeon_intr_establish(int irq,int ipl,int (* func)(void *),void * arg)3352d299731Smatt octeon_intr_establish(int irq, int ipl, int (*func)(void *), void *arg)
336f693c922Shikaru {
337f693c922Shikaru struct octeon_intrhand *ih;
338793877b0Sjmcneill struct cpu_softc *cpu;
3394b99df67Ssimonb #ifndef OCTEON_CPU0_INTERRUPTS
340793877b0Sjmcneill int cpunum;
3414b99df67Ssimonb #endif
342f693c922Shikaru
343f693c922Shikaru if (irq >= NIRQS)
344f693c922Shikaru panic("octeon_intr_establish: bogus IRQ %d", irq);
3452d299731Smatt if (ipl < IPL_VM)
3462d299731Smatt panic("octeon_intr_establish: bogus IPL %d", ipl);
347f693c922Shikaru
3482d299731Smatt ih = kmem_zalloc(sizeof(*ih), KM_NOSLEEP);
349f693c922Shikaru if (ih == NULL)
350f693c922Shikaru return (NULL);
351f693c922Shikaru
352f693c922Shikaru ih->ih_func = func;
353f693c922Shikaru ih->ih_arg = arg;
354f693c922Shikaru ih->ih_irq = irq;
3552d299731Smatt ih->ih_ipl = ipl;
356f693c922Shikaru
3572d299731Smatt mutex_enter(&octeon_intr_lock);
358f693c922Shikaru
359f693c922Shikaru /*
3602d299731Smatt * First, make it known.
361f693c922Shikaru */
3623f508e4dSsimonb KASSERTMSG(octciu_intrs[irq] == NULL, "irq %d in use! (%p)",
3633f508e4dSsimonb irq, octciu_intrs[irq]);
3642d299731Smatt
3653270682cSriastradh atomic_store_release(&octciu_intrs[irq], ih);
366f693c922Shikaru
367f693c922Shikaru /*
368f693c922Shikaru * Now enable it.
369f693c922Shikaru */
370d911ef3aSjmcneill const int bank = irq / 64;
371d911ef3aSjmcneill const uint64_t irq_mask = __BIT(irq % 64);
372f693c922Shikaru
3732d299731Smatt switch (ipl) {
3742d299731Smatt case IPL_VM:
375793877b0Sjmcneill cpu = &octeon_cpu_softc[0];
376793877b0Sjmcneill cpu->cpu_ip2_enable[bank] |= irq_mask;
377793877b0Sjmcneill mips3_sd(cpu->cpu_ip2_en[bank], cpu->cpu_ip2_enable[bank]);
378f693c922Shikaru break;
379f693c922Shikaru
3802d299731Smatt case IPL_SCHED:
3814b99df67Ssimonb #ifdef OCTEON_CPU0_INTERRUPTS
3824b99df67Ssimonb cpu = &octeon_cpu_softc[0];
3834b99df67Ssimonb cpu->cpu_ip3_enable[bank] |= irq_mask;
3844b99df67Ssimonb mips3_sd(cpu->cpu_ip3_en[bank], cpu->cpu_ip3_enable[bank]);
3854b99df67Ssimonb #else /* OCTEON_CPU0_INTERRUPTS */
386793877b0Sjmcneill for (cpunum = 0; cpunum < OCTEON_NCPU; cpunum++) {
387793877b0Sjmcneill cpu = &octeon_cpu_softc[cpunum];
388793877b0Sjmcneill if (cpu->cpu_ci == NULL)
389793877b0Sjmcneill break;
390793877b0Sjmcneill cpu->cpu_ip3_enable[bank] |= irq_mask;
391793877b0Sjmcneill mips3_sd(cpu->cpu_ip3_en[bank], cpu->cpu_ip3_enable[bank]);
392793877b0Sjmcneill }
3934b99df67Ssimonb #endif /* OCTEON_CPU0_INTERRUPTS */
3942d299731Smatt break;
3952d299731Smatt
3962d299731Smatt case IPL_DDB:
3972d299731Smatt case IPL_HIGH:
3984b99df67Ssimonb #ifdef OCTEON_CPU0_INTERRUPTS
3994b99df67Ssimonb cpu = &octeon_cpu_softc[0];
4004b99df67Ssimonb cpu->cpu_ip4_enable[bank] |= irq_mask;
4014b99df67Ssimonb mips3_sd(cpu->cpu_ip4_en[bank], cpu->cpu_ip4_enable[bank]);
4024b99df67Ssimonb #else /* OCTEON_CPU0_INTERRUPTS */
403793877b0Sjmcneill for (cpunum = 0; cpunum < OCTEON_NCPU; cpunum++) {
404793877b0Sjmcneill cpu = &octeon_cpu_softc[cpunum];
405793877b0Sjmcneill if (cpu->cpu_ci == NULL)
406793877b0Sjmcneill break;
407793877b0Sjmcneill cpu->cpu_ip4_enable[bank] |= irq_mask;
408793877b0Sjmcneill mips3_sd(cpu->cpu_ip4_en[bank], cpu->cpu_ip4_enable[bank]);
409793877b0Sjmcneill }
4104b99df67Ssimonb #endif /* OCTEON_CPU0_INTERRUPTS */
411f693c922Shikaru break;
412f693c922Shikaru }
413f693c922Shikaru
4142d299731Smatt mutex_exit(&octeon_intr_lock);
4152d299731Smatt
4162d299731Smatt return ih;
417f693c922Shikaru }
418f693c922Shikaru
419f693c922Shikaru void
octeon_intr_disestablish(void * cookie)420f693c922Shikaru octeon_intr_disestablish(void *cookie)
421f693c922Shikaru {
4222d299731Smatt struct octeon_intrhand * const ih = cookie;
423793877b0Sjmcneill struct cpu_softc *cpu;
4242d299731Smatt const int irq = ih->ih_irq & (NIRQS-1);
4252d299731Smatt const int ipl = ih->ih_ipl;
426793877b0Sjmcneill int cpunum;
427f693c922Shikaru
4282d299731Smatt mutex_enter(&octeon_intr_lock);
429f693c922Shikaru
430f693c922Shikaru /*
4312d299731Smatt * First disable it.
432f693c922Shikaru */
433d911ef3aSjmcneill const int bank = irq / 64;
434d911ef3aSjmcneill const uint64_t irq_mask = ~__BIT(irq % 64);
4352d299731Smatt
4362d299731Smatt switch (ipl) {
4372d299731Smatt case IPL_VM:
438793877b0Sjmcneill cpu = &octeon_cpu_softc[0];
439793877b0Sjmcneill cpu->cpu_ip2_enable[bank] &= ~irq_mask;
440793877b0Sjmcneill mips3_sd(cpu->cpu_ip2_en[bank], cpu->cpu_ip2_enable[bank]);
4412d299731Smatt break;
4422d299731Smatt
4432d299731Smatt case IPL_SCHED:
444793877b0Sjmcneill for (cpunum = 0; cpunum < OCTEON_NCPU; cpunum++) {
445793877b0Sjmcneill cpu = &octeon_cpu_softc[cpunum];
446793877b0Sjmcneill if (cpu->cpu_ci == NULL)
447793877b0Sjmcneill break;
448793877b0Sjmcneill cpu->cpu_ip3_enable[bank] &= ~irq_mask;
449793877b0Sjmcneill mips3_sd(cpu->cpu_ip3_en[bank], cpu->cpu_ip3_enable[bank]);
450793877b0Sjmcneill }
4512d299731Smatt break;
4522d299731Smatt
4532d299731Smatt case IPL_DDB:
4542d299731Smatt case IPL_HIGH:
455793877b0Sjmcneill for (cpunum = 0; cpunum < OCTEON_NCPU; cpunum++) {
456793877b0Sjmcneill cpu = &octeon_cpu_softc[cpunum];
457793877b0Sjmcneill if (cpu->cpu_ci == NULL)
458793877b0Sjmcneill break;
459793877b0Sjmcneill cpu->cpu_ip4_enable[bank] &= ~irq_mask;
460793877b0Sjmcneill mips3_sd(cpu->cpu_ip4_en[bank], cpu->cpu_ip4_enable[bank]);
461793877b0Sjmcneill }
4622d299731Smatt break;
4632d299731Smatt }
464f693c922Shikaru
4657bd5abd3Sriastradh atomic_store_relaxed(&octciu_intrs[irq], NULL);
466f693c922Shikaru
4672d299731Smatt mutex_exit(&octeon_intr_lock);
468f693c922Shikaru
4697bd5abd3Sriastradh /*
4707bd5abd3Sriastradh * Wait until the interrupt handler is no longer running on all
4717bd5abd3Sriastradh * CPUs before freeing ih and returning.
4727bd5abd3Sriastradh */
4737bd5abd3Sriastradh xc_barrier(0);
4742d299731Smatt kmem_free(ih, sizeof(*ih));
475f693c922Shikaru }
476f693c922Shikaru
477f693c922Shikaru void
octeon_iointr(int ipl,vaddr_t pc,uint32_t ipending)478f693c922Shikaru octeon_iointr(int ipl, vaddr_t pc, uint32_t ipending)
479f693c922Shikaru {
4802d299731Smatt struct cpu_info * const ci = curcpu();
4812d299731Smatt struct cpu_softc * const cpu = ci->ci_softc;
482d911ef3aSjmcneill int bank;
4832d299731Smatt
484847a1893Smatt KDASSERT(mips_cp0_status_read() & MIPS_SR_INT_IE);
4852d299731Smatt KASSERT((ipending & ~MIPS_INT_MASK) == 0);
4862d299731Smatt KASSERT(ipending & MIPS_HARD_INT_MASK);
487d911ef3aSjmcneill uint64_t hwpend[2] = { 0, 0 };
488d911ef3aSjmcneill
489d911ef3aSjmcneill const uint64_t sum1 = mips3_ld(cpu->cpu_int_sum1);
490f693c922Shikaru
4912d299731Smatt if (ipending & MIPS_INT_MASK_2) {
492793877b0Sjmcneill hwpend[0] = mips3_ld(cpu->cpu_ip4_sum0)
493793877b0Sjmcneill & cpu->cpu_ip4_enable[0];
494793877b0Sjmcneill hwpend[1] = sum1 & cpu->cpu_ip4_enable[1];
4952d299731Smatt } else if (ipending & MIPS_INT_MASK_1) {
496793877b0Sjmcneill hwpend[0] = mips3_ld(cpu->cpu_ip3_sum0)
497793877b0Sjmcneill & cpu->cpu_ip3_enable[0];
498793877b0Sjmcneill hwpend[1] = sum1 & cpu->cpu_ip3_enable[1];
4992d299731Smatt } else if (ipending & MIPS_INT_MASK_0) {
500793877b0Sjmcneill hwpend[0] = mips3_ld(cpu->cpu_ip2_sum0)
501793877b0Sjmcneill & cpu->cpu_ip2_enable[0];
502793877b0Sjmcneill hwpend[1] = sum1 & cpu->cpu_ip2_enable[1];
5032d299731Smatt } else {
5042d299731Smatt panic("octeon_iointr: unexpected ipending %#x", ipending);
505f693c922Shikaru }
506d911ef3aSjmcneill for (bank = 0; bank <= 1; bank++) {
507d911ef3aSjmcneill while (hwpend[bank] != 0) {
508d911ef3aSjmcneill const int bit = ffs64(hwpend[bank]) - 1;
509d911ef3aSjmcneill const int irq = (bank * 64) + bit;
510d911ef3aSjmcneill hwpend[bank] &= ~__BIT(bit);
5112d299731Smatt
5127bd5abd3Sriastradh struct octeon_intrhand * const ih =
5133270682cSriastradh atomic_load_consume(&octciu_intrs[irq]);
5142d299731Smatt cpu->cpu_intr_evs[irq].ev_count++;
5152d299731Smatt if (__predict_true(ih != NULL)) {
5162d299731Smatt #ifdef MULTIPROCESSOR
5172d299731Smatt if (ipl == IPL_VM) {
5182d299731Smatt KERNEL_LOCK(1, NULL);
5192d299731Smatt #endif
5202d299731Smatt (*ih->ih_func)(ih->ih_arg);
5212d299731Smatt #ifdef MULTIPROCESSOR
5222d299731Smatt KERNEL_UNLOCK_ONE(NULL);
5232d299731Smatt } else {
524f693c922Shikaru (*ih->ih_func)(ih->ih_arg);
525f693c922Shikaru }
5262d299731Smatt #endif
527847a1893Smatt KDASSERT(mips_cp0_status_read() & MIPS_SR_INT_IE);
528f693c922Shikaru }
5292d299731Smatt }
530d911ef3aSjmcneill }
531847a1893Smatt KDASSERT(mips_cp0_status_read() & MIPS_SR_INT_IE);
5322d299731Smatt }
5332d299731Smatt
5342d299731Smatt #ifdef MULTIPROCESSOR
5352d299731Smatt __CTASSERT(NIPIS < 16);
5362d299731Smatt
5372d299731Smatt int
octeon_ipi_intr(void * arg)5382d299731Smatt octeon_ipi_intr(void *arg)
5392d299731Smatt {
5402d299731Smatt struct cpu_info * const ci = curcpu();
5412d299731Smatt struct cpu_softc * const cpu = ci->ci_softc;
5424a584abcSjmcneill const uint32_t mbox_mask = (uintptr_t) arg;
5434a584abcSjmcneill uint32_t ipi_mask = mbox_mask;
544847a1893Smatt
5454a584abcSjmcneill KASSERTMSG((mbox_mask & __BITS(31,16)) == 0 || ci->ci_cpl >= IPL_SCHED,
5464a584abcSjmcneill "mbox_mask %#"PRIx32" cpl %d", mbox_mask, ci->ci_cpl);
5472d299731Smatt
5487d9c74a0Sjmcneill ipi_mask &= mips3_ld(cpu->cpu_mbox_set);
5497d9c74a0Sjmcneill if (ipi_mask == 0)
550847a1893Smatt return 0;
551*efc604cfSriastradh membar_acquire();
552847a1893Smatt
5537d9c74a0Sjmcneill mips3_sd(cpu->cpu_mbox_clr, ipi_mask);
5542d299731Smatt
5554a584abcSjmcneill KASSERT(__SHIFTOUT(ipi_mask, mbox_mask) < __BIT(NIPIS));
5562d299731Smatt
557847a1893Smatt #if NWDOG > 0
558847a1893Smatt // Handle WDOG requests ourselves.
559847a1893Smatt if (ipi_mask & __BIT(IPI_WDOG)) {
560847a1893Smatt softint_schedule(cpu->cpu_wdog_sih);
561847a1893Smatt atomic_and_64(&ci->ci_request_ipis, ~__BIT(IPI_WDOG));
562847a1893Smatt ipi_mask &= ~__BIT(IPI_WDOG);
563847a1893Smatt ci->ci_evcnt_per_ipi[IPI_WDOG].ev_count++;
564847a1893Smatt if (__predict_true(ipi_mask == 0))
565847a1893Smatt return 1;
566847a1893Smatt }
567847a1893Smatt #endif
568847a1893Smatt
5692d299731Smatt /* if the request is clear, it was previously processed */
570*efc604cfSriastradh if ((atomic_load_relaxed(&ci->ci_request_ipis) & ipi_mask) == 0)
5712d299731Smatt return 0;
572*efc604cfSriastradh membar_acquire();
5732d299731Smatt
5742d299731Smatt atomic_or_64(&ci->ci_active_ipis, ipi_mask);
5752d299731Smatt atomic_and_64(&ci->ci_request_ipis, ~ipi_mask);
5762d299731Smatt
5774a584abcSjmcneill ipi_process(ci, __SHIFTOUT(ipi_mask, mbox_mask));
5782d299731Smatt
5792d299731Smatt atomic_and_64(&ci->ci_active_ipis, ~ipi_mask);
5802d299731Smatt
5812d299731Smatt return 1;
5822d299731Smatt }
5832d299731Smatt
5842d299731Smatt int
octeon_send_ipi(struct cpu_info * ci,int req)5852d299731Smatt octeon_send_ipi(struct cpu_info *ci, int req)
5862d299731Smatt {
5872d299731Smatt KASSERT(req < NIPIS);
5882d299731Smatt if (ci == NULL) {
589847a1893Smatt CPU_INFO_ITERATOR cii;
590847a1893Smatt for (CPU_INFO_FOREACH(cii, ci)) {
591847a1893Smatt if (ci != curcpu()) {
592847a1893Smatt octeon_send_ipi(ci, req);
5932d299731Smatt }
594847a1893Smatt }
595847a1893Smatt return 0;
596847a1893Smatt }
597847a1893Smatt KASSERT(cold || ci->ci_softc != NULL);
598847a1893Smatt if (ci->ci_softc == NULL)
599847a1893Smatt return -1;
6002d299731Smatt
6012d299731Smatt struct cpu_softc * const cpu = ci->ci_softc;
6024a584abcSjmcneill const u_int ipi_shift = ipi_prio[req] == IPL_SCHED ? 16 : 0;
6034a584abcSjmcneill const uint32_t ipi_mask = __BIT(req + ipi_shift);
6042d299731Smatt
605*efc604cfSriastradh membar_release();
606441d694cSskrll atomic_or_64(&ci->ci_request_ipis, ipi_mask);
6072d299731Smatt
608*efc604cfSriastradh membar_release();
6097d9c74a0Sjmcneill mips3_sd(cpu->cpu_mbox_set, ipi_mask);
610679b5d89Sjmcneill
6112d299731Smatt return 0;
6122d299731Smatt }
6132d299731Smatt #endif /* MULTIPROCESSOR */
614