1*ae38162bSvisa /* $OpenBSD: octciu.c,v 1.19 2022/12/11 05:31:05 visa Exp $ */
289182934Svisa
389182934Svisa /*
489182934Svisa * Copyright (c) 2000-2004 Opsycon AB (www.opsycon.se)
589182934Svisa *
689182934Svisa * Redistribution and use in source and binary forms, with or without
789182934Svisa * modification, are permitted provided that the following conditions
889182934Svisa * are met:
989182934Svisa * 1. Redistributions of source code must retain the above copyright
1089182934Svisa * notice, this list of conditions and the following disclaimer.
1189182934Svisa * 2. Redistributions in binary form must reproduce the above copyright
1289182934Svisa * notice, this list of conditions and the following disclaimer in the
1389182934Svisa * documentation and/or other materials provided with the distribution.
1489182934Svisa *
1589182934Svisa * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
1689182934Svisa * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
1789182934Svisa * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1889182934Svisa * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
1989182934Svisa * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2089182934Svisa * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2189182934Svisa * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2289182934Svisa * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2389182934Svisa * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2489182934Svisa * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2589182934Svisa * SUCH DAMAGE.
2689182934Svisa *
2789182934Svisa */
2889182934Svisa
2989182934Svisa /*
3089182934Svisa * Driver for OCTEON Central Interrupt Unit (CIU).
3189182934Svisa *
3289182934Svisa * CIU is present at least on CN3xxx, CN5xxx, CN60xx, CN61xx,
3389182934Svisa * CN70xx, and CN71xx.
3489182934Svisa */
3589182934Svisa
3689182934Svisa #include <sys/param.h>
3789182934Svisa #include <sys/systm.h>
3889182934Svisa #include <sys/conf.h>
3989182934Svisa #include <sys/device.h>
40095618ebSvisa #include <sys/evcount.h>
4189182934Svisa #include <sys/kernel.h>
4289182934Svisa #include <sys/malloc.h>
4389182934Svisa
4489182934Svisa #include <dev/ofw/fdt.h>
4589182934Svisa #include <dev/ofw/openfirm.h>
4689182934Svisa
4789182934Svisa #include <mips64/mips_cpu.h>
4889182934Svisa
4989182934Svisa #include <machine/autoconf.h>
5089182934Svisa #include <machine/fdt.h>
5189182934Svisa #include <machine/intr.h>
5289182934Svisa #include <machine/octeonreg.h>
5389182934Svisa
54429e2826Svisa #define OCTCIU_NINTS 192
5589182934Svisa
5689182934Svisa #define INTPRI_CIU_0 (INTPRI_CLOCK + 1)
57429e2826Svisa #define INTPRI_CIU_1 (INTPRI_CLOCK + 2)
5889182934Svisa
5989182934Svisa struct intrbank {
6089182934Svisa uint64_t en; /* enable mask register */
6189182934Svisa uint64_t sum; /* service request register */
6289182934Svisa int id; /* bank number */
6389182934Svisa };
6489182934Svisa
65429e2826Svisa #define NBANKS 3
6689182934Svisa #define BANK_SIZE 64
6789182934Svisa #define IRQ_TO_BANK(x) ((x) >> 6)
6889182934Svisa #define IRQ_TO_BIT(x) ((x) & 0x3f)
6989182934Svisa
70e842824bSvisa #define IS_WORKQ_IRQ(x) ((unsigned int)(x) < 16)
71e842824bSvisa
72273c963eSvisa struct octciu_intrhand {
73041e95aeSvisa SLIST_ENTRY(octciu_intrhand)
74041e95aeSvisa ih_list;
75273c963eSvisa int (*ih_fun)(void *);
76273c963eSvisa void *ih_arg;
77273c963eSvisa int ih_level;
78273c963eSvisa int ih_irq;
79273c963eSvisa struct evcount ih_count;
80273c963eSvisa int ih_flags;
81273c963eSvisa cpuid_t ih_cpuid;
82273c963eSvisa };
83273c963eSvisa
84273c963eSvisa /* ih_flags */
85273c963eSvisa #define CIH_MPSAFE 0x01
86273c963eSvisa
874196a899Svisa struct octciu_cpu {
884196a899Svisa struct intrbank scpu_ibank[NBANKS];
894196a899Svisa uint64_t scpu_intem[NBANKS];
904196a899Svisa uint64_t scpu_imask[NIPLS][NBANKS];
914196a899Svisa };
924196a899Svisa
9389182934Svisa struct octciu_softc {
9489182934Svisa struct device sc_dev;
9589182934Svisa bus_space_tag_t sc_iot;
9689182934Svisa bus_space_handle_t sc_ioh;
974196a899Svisa struct octciu_cpu sc_cpu[MAXCPUS];
98041e95aeSvisa SLIST_HEAD(, octciu_intrhand)
99041e95aeSvisa sc_intrhand[OCTCIU_NINTS];
100429e2826Svisa unsigned int sc_nbanks;
10189182934Svisa
10289182934Svisa int (*sc_ipi_handler)(void *);
10389182934Svisa
10489182934Svisa struct intr_controller sc_ic;
10589182934Svisa };
10689182934Svisa
10789182934Svisa int octciu_match(struct device *, void *, void *);
10889182934Svisa void octciu_attach(struct device *, struct device *, void *);
10989182934Svisa
11089182934Svisa void octciu_init(void);
11189182934Svisa void octciu_intr_makemasks(struct octciu_softc *);
112429e2826Svisa uint32_t octciu_intr0(uint32_t, struct trapframe *);
113429e2826Svisa uint32_t octciu_intr2(uint32_t, struct trapframe *);
11489182934Svisa uint32_t octciu_intr_bank(struct octciu_softc *, struct intrbank *,
11589182934Svisa struct trapframe *);
11689182934Svisa void *octciu_intr_establish(int, int, int (*)(void *), void *,
11789182934Svisa const char *);
11889182934Svisa void *octciu_intr_establish_fdt_idx(void *, int, int, int,
11989182934Svisa int (*)(void *), void *, const char *);
12089182934Svisa void octciu_intr_disestablish(void *);
1210dd6b0daSvisa void octciu_intr_barrier(void *);
12289182934Svisa void octciu_splx(int);
12389182934Svisa
12489182934Svisa uint32_t octciu_ipi_intr(uint32_t, struct trapframe *);
12589182934Svisa int octciu_ipi_establish(int (*)(void *), cpuid_t);
12689182934Svisa void octciu_ipi_set(cpuid_t);
12789182934Svisa void octciu_ipi_clear(cpuid_t);
12889182934Svisa
12989182934Svisa const struct cfattach octciu_ca = {
13089182934Svisa sizeof(struct octciu_softc), octciu_match, octciu_attach
13189182934Svisa };
13289182934Svisa
13389182934Svisa struct cfdriver octciu_cd = {
13489182934Svisa NULL, "octciu", DV_DULL
13589182934Svisa };
13689182934Svisa
13789182934Svisa struct octciu_softc *octciu_sc;
13889182934Svisa
13989182934Svisa int
octciu_match(struct device * parent,void * match,void * aux)14089182934Svisa octciu_match(struct device *parent, void *match, void *aux)
14189182934Svisa {
14289182934Svisa struct fdt_attach_args *faa = aux;
14389182934Svisa
14489182934Svisa return OF_is_compatible(faa->fa_node, "cavium,octeon-3860-ciu");
14589182934Svisa }
14689182934Svisa
14789182934Svisa void
octciu_attach(struct device * parent,struct device * self,void * aux)14889182934Svisa octciu_attach(struct device *parent, struct device *self, void *aux)
14989182934Svisa {
150f83d439fSvisa struct fdt_attach_args *faa = aux;
15189182934Svisa struct octciu_softc *sc = (struct octciu_softc *)self;
152041e95aeSvisa int i;
15389182934Svisa
154f83d439fSvisa if (faa->fa_nreg != 1) {
155f83d439fSvisa printf(": expected one IO space, got %d\n", faa->fa_nreg);
15689182934Svisa return;
15789182934Svisa }
15889182934Svisa
159f83d439fSvisa sc->sc_iot = faa->fa_iot;
160f83d439fSvisa if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, faa->fa_reg[0].size,
16189182934Svisa 0, &sc->sc_ioh)) {
16289182934Svisa printf(": could not map IO space\n");
16389182934Svisa return;
16489182934Svisa }
16589182934Svisa
166429e2826Svisa if (octeon_ver == OCTEON_2 || octeon_ver == OCTEON_3)
167429e2826Svisa sc->sc_nbanks = 3;
168429e2826Svisa else
169429e2826Svisa sc->sc_nbanks = 2;
170429e2826Svisa
171041e95aeSvisa for (i = 0; i < OCTCIU_NINTS; i++)
172041e95aeSvisa SLIST_INIT(&sc->sc_intrhand[i]);
173041e95aeSvisa
17489182934Svisa printf("\n");
17589182934Svisa
17689182934Svisa sc->sc_ic.ic_cookie = sc;
177f83d439fSvisa sc->sc_ic.ic_node = faa->fa_node;
17889182934Svisa sc->sc_ic.ic_init = octciu_init;
17989182934Svisa sc->sc_ic.ic_establish = octciu_intr_establish;
18089182934Svisa sc->sc_ic.ic_establish_fdt_idx = octciu_intr_establish_fdt_idx;
18189182934Svisa sc->sc_ic.ic_disestablish = octciu_intr_disestablish;
1820dd6b0daSvisa sc->sc_ic.ic_intr_barrier = octciu_intr_barrier;
18389182934Svisa #ifdef MULTIPROCESSOR
18489182934Svisa sc->sc_ic.ic_ipi_establish = octciu_ipi_establish;
18589182934Svisa sc->sc_ic.ic_ipi_set = octciu_ipi_set;
18689182934Svisa sc->sc_ic.ic_ipi_clear = octciu_ipi_clear;
18789182934Svisa #endif
18889182934Svisa
18989182934Svisa octciu_sc = sc;
19089182934Svisa
191429e2826Svisa set_intr(INTPRI_CIU_0, CR_INT_0, octciu_intr0);
192429e2826Svisa if (sc->sc_nbanks == 3)
193429e2826Svisa set_intr(INTPRI_CIU_1, CR_INT_2, octciu_intr2);
19489182934Svisa #ifdef MULTIPROCESSOR
19589182934Svisa set_intr(INTPRI_IPI, CR_INT_1, octciu_ipi_intr);
19689182934Svisa #endif
19789182934Svisa
19889182934Svisa octciu_init();
19989182934Svisa
20089182934Svisa register_splx_handler(octciu_splx);
20189182934Svisa octeon_intr_register(&sc->sc_ic);
20289182934Svisa }
20389182934Svisa
20489182934Svisa void
octciu_init(void)20589182934Svisa octciu_init(void)
20689182934Svisa {
20789182934Svisa struct octciu_softc *sc = octciu_sc;
2084196a899Svisa struct octciu_cpu *scpu;
20989182934Svisa int cpuid = cpu_number();
210e842824bSvisa int s;
21189182934Svisa
2124196a899Svisa scpu = &sc->sc_cpu[cpuid];
2134196a899Svisa
21489182934Svisa bus_space_write_8(sc->sc_iot, sc->sc_ioh, CIU_IP2_EN0(cpuid), 0);
21589182934Svisa bus_space_write_8(sc->sc_iot, sc->sc_ioh, CIU_IP3_EN0(cpuid), 0);
21689182934Svisa bus_space_write_8(sc->sc_iot, sc->sc_ioh, CIU_IP2_EN1(cpuid), 0);
21789182934Svisa bus_space_write_8(sc->sc_iot, sc->sc_ioh, CIU_IP3_EN1(cpuid), 0);
21889182934Svisa
219429e2826Svisa if (sc->sc_nbanks == 3)
220429e2826Svisa bus_space_write_8(sc->sc_iot, sc->sc_ioh,
221429e2826Svisa CIU_IP4_EN2(cpuid), 0);
222429e2826Svisa
2234196a899Svisa scpu->scpu_ibank[0].en = CIU_IP2_EN0(cpuid);
2244196a899Svisa scpu->scpu_ibank[0].sum = CIU_IP2_SUM0(cpuid);
2254196a899Svisa scpu->scpu_ibank[0].id = 0;
2264196a899Svisa scpu->scpu_ibank[1].en = CIU_IP2_EN1(cpuid);
2274196a899Svisa scpu->scpu_ibank[1].sum = CIU_INT32_SUM1;
2284196a899Svisa scpu->scpu_ibank[1].id = 1;
229429e2826Svisa scpu->scpu_ibank[2].en = CIU_IP4_EN2(cpuid);
230429e2826Svisa scpu->scpu_ibank[2].sum = CIU_IP4_SUM2(cpuid);
231429e2826Svisa scpu->scpu_ibank[2].id = 2;
232e842824bSvisa
233e842824bSvisa s = splhigh();
234e842824bSvisa octciu_intr_makemasks(sc);
235e842824bSvisa splx(s); /* causes hw mask update */
23689182934Svisa }
23789182934Svisa
23889182934Svisa void *
octciu_intr_establish(int irq,int level,int (* ih_fun)(void *),void * ih_arg,const char * ih_what)23989182934Svisa octciu_intr_establish(int irq, int level, int (*ih_fun)(void *),
24089182934Svisa void *ih_arg, const char *ih_what)
24189182934Svisa {
24289182934Svisa struct octciu_softc *sc = octciu_sc;
243041e95aeSvisa struct octciu_intrhand *ih, *last, *tmp;
24489182934Svisa int cpuid = cpu_number();
24589182934Svisa int flags;
24689182934Svisa int s;
24789182934Svisa
24889182934Svisa #ifdef DIAGNOSTIC
249429e2826Svisa if (irq >= sc->sc_nbanks * BANK_SIZE || irq < 0)
25034745855Svisa panic("%s: illegal irq %d", __func__, irq);
25189182934Svisa #endif
25289182934Svisa
253e842824bSvisa #ifdef MULTIPROCESSOR
254e842824bSvisa /* Span work queue interrupts across CPUs. */
255cb20e335Svisa if (IS_WORKQ_IRQ(irq))
256fee69528Svisa cpuid = irq % ncpus;
257e842824bSvisa #endif
258e842824bSvisa
259273c963eSvisa flags = (level & IPL_MPSAFE) ? CIH_MPSAFE : 0;
26089182934Svisa level &= ~IPL_MPSAFE;
26189182934Svisa
26289182934Svisa ih = malloc(sizeof *ih, M_DEVBUF, M_NOWAIT);
26389182934Svisa if (ih == NULL)
26489182934Svisa return NULL;
26589182934Svisa
26689182934Svisa ih->ih_fun = ih_fun;
26789182934Svisa ih->ih_arg = ih_arg;
26889182934Svisa ih->ih_level = level;
26989182934Svisa ih->ih_flags = flags;
27089182934Svisa ih->ih_irq = irq;
271e842824bSvisa ih->ih_cpuid = cpuid;
27289182934Svisa evcount_attach(&ih->ih_count, ih_what, &ih->ih_irq);
273*ae38162bSvisa evcount_percpu(&ih->ih_count);
27489182934Svisa
27589182934Svisa s = splhigh();
27689182934Svisa
277041e95aeSvisa if (SLIST_EMPTY(&sc->sc_intrhand[irq])) {
278041e95aeSvisa SLIST_INSERT_HEAD(&sc->sc_intrhand[irq], ih, ih_list);
279041e95aeSvisa } else {
280041e95aeSvisa last = NULL;
281041e95aeSvisa SLIST_FOREACH(tmp, &sc->sc_intrhand[irq], ih_list)
282041e95aeSvisa last = tmp;
283041e95aeSvisa SLIST_INSERT_AFTER(last, ih, ih_list);
284041e95aeSvisa }
28589182934Svisa
2864196a899Svisa sc->sc_cpu[cpuid].scpu_intem[IRQ_TO_BANK(irq)] |=
2874196a899Svisa 1UL << IRQ_TO_BIT(irq);
28889182934Svisa octciu_intr_makemasks(sc);
28989182934Svisa
29089182934Svisa splx(s); /* causes hw mask update */
29189182934Svisa
29289182934Svisa return (ih);
29389182934Svisa }
29489182934Svisa
29589182934Svisa void *
octciu_intr_establish_fdt_idx(void * cookie,int node,int idx,int level,int (* ih_fun)(void *),void * ih_arg,const char * ih_what)29689182934Svisa octciu_intr_establish_fdt_idx(void *cookie, int node, int idx, int level,
29789182934Svisa int (*ih_fun)(void *), void *ih_arg, const char *ih_what)
29889182934Svisa {
29989182934Svisa uint32_t *cells;
30089182934Svisa int irq, len;
30189182934Svisa
30289182934Svisa len = OF_getproplen(node, "interrupts");
30389182934Svisa if (len / (sizeof(uint32_t) * 2) <= idx ||
30489182934Svisa len % (sizeof(uint32_t) * 2) != 0)
30589182934Svisa return NULL;
30689182934Svisa
30789182934Svisa cells = malloc(len, M_TEMP, M_NOWAIT);
30889182934Svisa if (cells == NULL)
30989182934Svisa return NULL;
31089182934Svisa
31189182934Svisa OF_getpropintarray(node, "interrupts", cells, len);
31289182934Svisa irq = cells[idx * 2] * BANK_SIZE + cells[idx * 2 + 1];
31389182934Svisa
31489182934Svisa free(cells, M_TEMP, len);
31589182934Svisa
31689182934Svisa return octciu_intr_establish(irq, level, ih_fun, ih_arg, ih_what);
31789182934Svisa }
31889182934Svisa
31989182934Svisa void
octciu_intr_disestablish(void * _ih)32089182934Svisa octciu_intr_disestablish(void *_ih)
32189182934Svisa {
322273c963eSvisa struct octciu_intrhand *ih = _ih;
323041e95aeSvisa struct octciu_intrhand *tmp;
32489182934Svisa struct octciu_softc *sc = octciu_sc;
32589182934Svisa unsigned int irq = ih->ih_irq;
32689182934Svisa int cpuid = cpu_number();
327041e95aeSvisa int found = 0;
32889182934Svisa int s;
32989182934Svisa
330429e2826Svisa KASSERT(irq < sc->sc_nbanks * BANK_SIZE);
331e842824bSvisa KASSERT(!IS_WORKQ_IRQ(irq));
33289182934Svisa
33389182934Svisa s = splhigh();
33489182934Svisa
335041e95aeSvisa SLIST_FOREACH(tmp, &sc->sc_intrhand[irq], ih_list) {
336041e95aeSvisa if (tmp == ih) {
337041e95aeSvisa found = 1;
33889182934Svisa break;
33989182934Svisa }
34089182934Svisa }
341041e95aeSvisa if (found == 0)
342041e95aeSvisa panic("%s: intrhand %p not registered", __func__, ih);
343041e95aeSvisa
344041e95aeSvisa SLIST_REMOVE(&sc->sc_intrhand[irq], ih, octciu_intrhand, ih_list);
3457abddf2dSvisa evcount_detach(&ih->ih_count);
346041e95aeSvisa
347041e95aeSvisa if (SLIST_EMPTY(&sc->sc_intrhand[irq])) {
348041e95aeSvisa sc->sc_cpu[cpuid].scpu_intem[IRQ_TO_BANK(irq)] &=
349041e95aeSvisa ~(1UL << IRQ_TO_BIT(irq));
35089182934Svisa }
35189182934Svisa
35289182934Svisa octciu_intr_makemasks(sc);
35389182934Svisa splx(s); /* causes hw mask update */
354041e95aeSvisa
355041e95aeSvisa free(ih, M_DEVBUF, sizeof(*ih));
35689182934Svisa }
35789182934Svisa
3580dd6b0daSvisa void
octciu_intr_barrier(void * _ih)3590dd6b0daSvisa octciu_intr_barrier(void *_ih)
3600dd6b0daSvisa {
3610dd6b0daSvisa struct cpu_info *ci = NULL;
3620dd6b0daSvisa #ifdef MULTIPROCESSOR
3630dd6b0daSvisa struct octciu_intrhand *ih = _ih;
3640dd6b0daSvisa
3650dd6b0daSvisa if (IS_WORKQ_IRQ(ih->ih_irq))
3660dd6b0daSvisa ci = get_cpu_info(ih->ih_irq % ncpus);
3670dd6b0daSvisa #endif
3680dd6b0daSvisa
3690dd6b0daSvisa sched_barrier(ci);
3700dd6b0daSvisa }
3710dd6b0daSvisa
37289182934Svisa /*
37389182934Svisa * Recompute interrupt masks.
37489182934Svisa */
37589182934Svisa void
octciu_intr_makemasks(struct octciu_softc * sc)37689182934Svisa octciu_intr_makemasks(struct octciu_softc *sc)
37789182934Svisa {
378e842824bSvisa cpuid_t cpuid = cpu_number();
379e842824bSvisa struct octciu_cpu *scpu = &sc->sc_cpu[cpuid];
380273c963eSvisa struct octciu_intrhand *q;
38189182934Svisa uint intrlevel[OCTCIU_NINTS];
3824196a899Svisa int irq, level;
38389182934Svisa
38489182934Svisa /* First, figure out which levels each IRQ uses. */
38589182934Svisa for (irq = 0; irq < OCTCIU_NINTS; irq++) {
38689182934Svisa uint levels = 0;
387041e95aeSvisa SLIST_FOREACH(q, &sc->sc_intrhand[irq], ih_list) {
388e842824bSvisa if (q->ih_cpuid == cpuid)
38989182934Svisa levels |= 1 << q->ih_level;
390e842824bSvisa }
39189182934Svisa intrlevel[irq] = levels;
39289182934Svisa }
39389182934Svisa
39489182934Svisa /*
39589182934Svisa * Then figure out which IRQs use each level.
39689182934Svisa * Note that we make sure never to overwrite imask[IPL_HIGH], in
39789182934Svisa * case an interrupt occurs during intr_disestablish() and causes
39889182934Svisa * an unfortunate splx() while we are here recomputing the masks.
39989182934Svisa */
40089182934Svisa for (level = IPL_NONE; level < NIPLS; level++) {
40189182934Svisa uint64_t mask[NBANKS] = {};
40289182934Svisa for (irq = 0; irq < OCTCIU_NINTS; irq++)
40389182934Svisa if (intrlevel[irq] & (1 << level))
40489182934Svisa mask[IRQ_TO_BANK(irq)] |=
40589182934Svisa 1UL << IRQ_TO_BIT(irq);
4064196a899Svisa scpu->scpu_imask[level][0] = mask[0];
4074196a899Svisa scpu->scpu_imask[level][1] = mask[1];
408429e2826Svisa scpu->scpu_imask[level][2] = mask[2];
40989182934Svisa }
41089182934Svisa /*
41189182934Svisa * There are tty, network and disk drivers that use free() at interrupt
41289182934Svisa * time, so vm > (tty | net | bio).
41389182934Svisa *
41489182934Svisa * Enforce a hierarchy that gives slow devices a better chance at not
41589182934Svisa * dropping data.
41689182934Svisa */
41789182934Svisa #define ADD_MASK(dst, src) do { \
41889182934Svisa dst[0] |= src[0]; \
41989182934Svisa dst[1] |= src[1]; \
420429e2826Svisa dst[2] |= src[2]; \
42189182934Svisa } while (0)
4224196a899Svisa ADD_MASK(scpu->scpu_imask[IPL_NET], scpu->scpu_imask[IPL_BIO]);
4234196a899Svisa ADD_MASK(scpu->scpu_imask[IPL_TTY], scpu->scpu_imask[IPL_NET]);
4244196a899Svisa ADD_MASK(scpu->scpu_imask[IPL_VM], scpu->scpu_imask[IPL_TTY]);
4254196a899Svisa ADD_MASK(scpu->scpu_imask[IPL_CLOCK], scpu->scpu_imask[IPL_VM]);
4264196a899Svisa ADD_MASK(scpu->scpu_imask[IPL_HIGH], scpu->scpu_imask[IPL_CLOCK]);
4274196a899Svisa ADD_MASK(scpu->scpu_imask[IPL_IPI], scpu->scpu_imask[IPL_HIGH]);
42889182934Svisa
42989182934Svisa /*
43089182934Svisa * These are pseudo-levels.
43189182934Svisa */
4324196a899Svisa scpu->scpu_imask[IPL_NONE][0] = 0;
4334196a899Svisa scpu->scpu_imask[IPL_NONE][1] = 0;
434429e2826Svisa scpu->scpu_imask[IPL_NONE][2] = 0;
43589182934Svisa }
43689182934Svisa
43789182934Svisa static inline int
octciu_next_irq(uint64_t * isr)43889182934Svisa octciu_next_irq(uint64_t *isr)
43989182934Svisa {
44089182934Svisa uint64_t irq, tmp = *isr;
44189182934Svisa
44289182934Svisa if (tmp == 0)
44389182934Svisa return -1;
44489182934Svisa
44589182934Svisa asm volatile (
44689182934Svisa " .set push\n"
44789182934Svisa " .set mips64\n"
44889182934Svisa " dclz %0, %0\n"
44989182934Svisa " .set pop\n"
45089182934Svisa : "=r" (tmp) : "0" (tmp));
45189182934Svisa
45289182934Svisa irq = 63u - tmp;
45389182934Svisa *isr &= ~(1u << irq);
45489182934Svisa return irq;
45589182934Svisa }
45689182934Svisa
45789182934Svisa /*
45889182934Svisa * Dispatch interrupts in given bank.
45989182934Svisa */
46089182934Svisa uint32_t
octciu_intr_bank(struct octciu_softc * sc,struct intrbank * bank,struct trapframe * frame)46189182934Svisa octciu_intr_bank(struct octciu_softc *sc, struct intrbank *bank,
46289182934Svisa struct trapframe *frame)
46389182934Svisa {
46489182934Svisa struct cpu_info *ci = curcpu();
465273c963eSvisa struct octciu_intrhand *ih;
466d7d80ecdSvisa struct octciu_cpu *scpu = &sc->sc_cpu[ci->ci_cpuid];
46789182934Svisa uint64_t imr, isr, mask;
46889182934Svisa int handled, ipl, irq;
46989182934Svisa #ifdef MULTIPROCESSOR
47089182934Svisa register_t sr;
47189182934Svisa int need_lock;
47289182934Svisa #endif
47389182934Svisa
47489182934Svisa isr = bus_space_read_8(sc->sc_iot, sc->sc_ioh, bank->sum);
47589182934Svisa imr = bus_space_read_8(sc->sc_iot, sc->sc_ioh, bank->en);
47689182934Svisa
47789182934Svisa isr &= imr;
47889182934Svisa if (isr == 0)
47989182934Svisa return 0; /* not for us */
48089182934Svisa
48189182934Svisa /*
48289182934Svisa * Mask all pending interrupts.
48389182934Svisa */
48489182934Svisa bus_space_write_8(sc->sc_iot, sc->sc_ioh, bank->en, imr & ~isr);
48589182934Svisa
48689182934Svisa /*
48789182934Svisa * If interrupts are spl-masked, mask them and wait for splx()
48889182934Svisa * to reenable them when necessary.
48989182934Svisa */
4904196a899Svisa if ((mask = isr & scpu->scpu_imask[frame->ipl][bank->id])
49189182934Svisa != 0) {
49289182934Svisa isr &= ~mask;
49389182934Svisa imr &= ~mask;
49489182934Svisa }
49589182934Svisa if (isr == 0)
49689182934Svisa return 1;
49789182934Svisa
49889182934Svisa /*
49989182934Svisa * Now process allowed interrupts.
50089182934Svisa */
50189182934Svisa
50289182934Svisa ipl = ci->ci_ipl;
50389182934Svisa
50489182934Svisa while ((irq = octciu_next_irq(&isr)) >= 0) {
50589182934Svisa irq += bank->id * BANK_SIZE;
50689182934Svisa handled = 0;
507041e95aeSvisa SLIST_FOREACH(ih, &sc->sc_intrhand[irq], ih_list) {
50889182934Svisa splraise(ih->ih_level);
50989182934Svisa #ifdef MULTIPROCESSOR
51089182934Svisa if (ih->ih_level < IPL_IPI) {
51189182934Svisa sr = getsr();
51289182934Svisa ENABLEIPI();
51389182934Svisa }
514273c963eSvisa if (ih->ih_flags & CIH_MPSAFE)
51589182934Svisa need_lock = 0;
51689182934Svisa else
517f8189779Svisa need_lock = 1;
51889182934Svisa if (need_lock)
51989182934Svisa __mp_lock(&kernel_lock);
52089182934Svisa #endif
52189182934Svisa if ((*ih->ih_fun)(ih->ih_arg) != 0) {
52289182934Svisa handled = 1;
523*ae38162bSvisa evcount_inc(&ih->ih_count);
52489182934Svisa }
52589182934Svisa #ifdef MULTIPROCESSOR
52689182934Svisa if (need_lock)
52789182934Svisa __mp_unlock(&kernel_lock);
52889182934Svisa if (ih->ih_level < IPL_IPI)
52989182934Svisa setsr(sr);
53089182934Svisa #endif
53189182934Svisa }
53289182934Svisa if (!handled)
5335e9543b6Svisa printf("%s: spurious interrupt %d on cpu %lu\n",
5345e9543b6Svisa sc->sc_dev.dv_xname, irq, ci->ci_cpuid);
53589182934Svisa }
53689182934Svisa
53789182934Svisa ci->ci_ipl = ipl;
53889182934Svisa
53989182934Svisa /*
54089182934Svisa * Reenable interrupts which have been serviced.
54189182934Svisa */
54289182934Svisa bus_space_write_8(sc->sc_iot, sc->sc_ioh, bank->en, imr);
54389182934Svisa
54489182934Svisa return 1;
54589182934Svisa }
54689182934Svisa
54789182934Svisa uint32_t
octciu_intr0(uint32_t hwpend,struct trapframe * frame)548429e2826Svisa octciu_intr0(uint32_t hwpend, struct trapframe *frame)
54989182934Svisa {
55089182934Svisa struct octciu_softc *sc = octciu_sc;
5514196a899Svisa struct octciu_cpu *scpu = &sc->sc_cpu[cpu_number()];
55289182934Svisa int handled;
55389182934Svisa
5544196a899Svisa handled = octciu_intr_bank(sc, &scpu->scpu_ibank[0], frame);
5554196a899Svisa handled |= octciu_intr_bank(sc, &scpu->scpu_ibank[1], frame);
55689182934Svisa return handled ? hwpend : 0;
55789182934Svisa }
55889182934Svisa
559429e2826Svisa uint32_t
octciu_intr2(uint32_t hwpend,struct trapframe * frame)560429e2826Svisa octciu_intr2(uint32_t hwpend, struct trapframe *frame)
561429e2826Svisa {
562429e2826Svisa struct octciu_softc *sc = octciu_sc;
563429e2826Svisa struct octciu_cpu *scpu = &sc->sc_cpu[cpu_number()];
564429e2826Svisa int handled;
565429e2826Svisa
566429e2826Svisa handled = octciu_intr_bank(sc, &scpu->scpu_ibank[2], frame);
567429e2826Svisa return handled ? hwpend : 0;
568429e2826Svisa }
569429e2826Svisa
57089182934Svisa void
octciu_splx(int newipl)57189182934Svisa octciu_splx(int newipl)
57289182934Svisa {
57389182934Svisa struct cpu_info *ci = curcpu();
5744196a899Svisa struct octciu_softc *sc = octciu_sc;
5754196a899Svisa struct octciu_cpu *scpu = &sc->sc_cpu[ci->ci_cpuid];
57689182934Svisa
57789182934Svisa ci->ci_ipl = newipl;
57889182934Svisa
57989182934Svisa /* Set hardware masks. */
5804196a899Svisa bus_space_write_8(sc->sc_iot, sc->sc_ioh, scpu->scpu_ibank[0].en,
5814196a899Svisa scpu->scpu_intem[0] & ~scpu->scpu_imask[newipl][0]);
5824196a899Svisa bus_space_write_8(sc->sc_iot, sc->sc_ioh, scpu->scpu_ibank[1].en,
5834196a899Svisa scpu->scpu_intem[1] & ~scpu->scpu_imask[newipl][1]);
58489182934Svisa
585429e2826Svisa if (sc->sc_nbanks == 3)
586429e2826Svisa bus_space_write_8(sc->sc_iot, sc->sc_ioh,
587429e2826Svisa scpu->scpu_ibank[2].en,
588429e2826Svisa scpu->scpu_intem[2] & ~scpu->scpu_imask[newipl][2]);
589429e2826Svisa
59085caa4b9Scheloha /* Trigger deferred clock interrupt if it is now unmasked. */
59185caa4b9Scheloha if (ci->ci_clock_deferred && newipl < IPL_CLOCK)
59285caa4b9Scheloha md_triggerclock();
59385caa4b9Scheloha
59489182934Svisa /* If we still have softints pending trigger processing. */
59589182934Svisa if (ci->ci_softpending != 0 && newipl < IPL_SOFTINT)
59689182934Svisa setsoftintr0();
59789182934Svisa }
59889182934Svisa
59989182934Svisa #ifdef MULTIPROCESSOR
60089182934Svisa uint32_t
octciu_ipi_intr(uint32_t hwpend,struct trapframe * frame)60189182934Svisa octciu_ipi_intr(uint32_t hwpend, struct trapframe *frame)
60289182934Svisa {
60389182934Svisa struct octciu_softc *sc = octciu_sc;
60489182934Svisa u_long cpuid = cpu_number();
60589182934Svisa
60689182934Svisa /*
60789182934Svisa * Mask all pending interrupts.
60889182934Svisa */
60989182934Svisa bus_space_write_8(sc->sc_iot, sc->sc_ioh, CIU_IP3_EN0(cpuid), 0);
61089182934Svisa
61189182934Svisa if (sc->sc_ipi_handler == NULL)
61289182934Svisa return hwpend;
61389182934Svisa
61489182934Svisa sc->sc_ipi_handler((void *)cpuid);
61589182934Svisa
61689182934Svisa /*
61789182934Svisa * Reenable interrupts which have been serviced.
61889182934Svisa */
61989182934Svisa bus_space_write_8(sc->sc_iot, sc->sc_ioh, CIU_IP3_EN0(cpuid),
62089182934Svisa (1ULL << CIU_INT_MBOX0)|(1ULL << CIU_INT_MBOX1));
62189182934Svisa return hwpend;
62289182934Svisa }
62389182934Svisa
62489182934Svisa int
octciu_ipi_establish(int (* func)(void *),cpuid_t cpuid)62589182934Svisa octciu_ipi_establish(int (*func)(void *), cpuid_t cpuid)
62689182934Svisa {
62789182934Svisa struct octciu_softc *sc = octciu_sc;
62889182934Svisa
62989182934Svisa if (cpuid == 0)
63089182934Svisa sc->sc_ipi_handler = func;
63189182934Svisa
63289182934Svisa bus_space_write_8(sc->sc_iot, sc->sc_ioh, CIU_MBOX_CLR(cpuid),
63389182934Svisa 0xffffffff);
63489182934Svisa bus_space_write_8(sc->sc_iot, sc->sc_ioh, CIU_IP3_EN0(cpuid),
63589182934Svisa (1ULL << CIU_INT_MBOX0)|(1ULL << CIU_INT_MBOX1));
63689182934Svisa
63789182934Svisa return 0;
63889182934Svisa }
63989182934Svisa
64089182934Svisa void
octciu_ipi_set(cpuid_t cpuid)64189182934Svisa octciu_ipi_set(cpuid_t cpuid)
64289182934Svisa {
64389182934Svisa struct octciu_softc *sc = octciu_sc;
64489182934Svisa
64589182934Svisa bus_space_write_8(sc->sc_iot, sc->sc_ioh, CIU_MBOX_SET(cpuid), 1);
64689182934Svisa }
64789182934Svisa
64889182934Svisa void
octciu_ipi_clear(cpuid_t cpuid)64989182934Svisa octciu_ipi_clear(cpuid_t cpuid)
65089182934Svisa {
65189182934Svisa struct octciu_softc *sc = octciu_sc;
65289182934Svisa uint64_t clr;
65389182934Svisa
65489182934Svisa clr = bus_space_read_8(sc->sc_iot, sc->sc_ioh, CIU_MBOX_CLR(cpuid));
65589182934Svisa bus_space_write_8(sc->sc_iot, sc->sc_ioh, CIU_MBOX_CLR(cpuid), clr);
65689182934Svisa }
65789182934Svisa #endif /* MULTIPROCESSOR */
658