1*ae38162bSvisa /* $OpenBSD: octcit.c,v 1.14 2022/12/11 05:31:05 visa Exp $ */
22e3f4418Svisa
32e3f4418Svisa /*
40dd6b0daSvisa * Copyright (c) 2017, 2019 Visa Hankala
52e3f4418Svisa *
62e3f4418Svisa * Permission to use, copy, modify, and distribute this software for any
72e3f4418Svisa * purpose with or without fee is hereby granted, provided that the above
82e3f4418Svisa * copyright notice and this permission notice appear in all copies.
92e3f4418Svisa *
102e3f4418Svisa * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
112e3f4418Svisa * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
122e3f4418Svisa * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
132e3f4418Svisa * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
142e3f4418Svisa * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
152e3f4418Svisa * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
162e3f4418Svisa * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
172e3f4418Svisa */
182e3f4418Svisa
192e3f4418Svisa /*
202e3f4418Svisa * Driver for OCTEON Central Interrupt Unit version 3 (CIU3).
212e3f4418Svisa *
222e3f4418Svisa * CIU3 is present on CN72xx, CN73xx, CN77xx, and CN78xx.
232e3f4418Svisa */
242e3f4418Svisa
252e3f4418Svisa #include <sys/param.h>
262e3f4418Svisa #include <sys/systm.h>
272e3f4418Svisa #include <sys/conf.h>
282e3f4418Svisa #include <sys/device.h>
29095618ebSvisa #include <sys/evcount.h>
302e3f4418Svisa #include <sys/kernel.h>
312e3f4418Svisa #include <sys/malloc.h>
322e3f4418Svisa
332e3f4418Svisa #include <dev/ofw/fdt.h>
342e3f4418Svisa #include <dev/ofw/openfirm.h>
352e3f4418Svisa
362e3f4418Svisa #include <mips64/mips_cpu.h>
372e3f4418Svisa
382e3f4418Svisa #include <machine/autoconf.h>
392e3f4418Svisa #include <machine/fdt.h>
402e3f4418Svisa #include <machine/intr.h>
412e3f4418Svisa #include <machine/octeonreg.h>
422e3f4418Svisa
432e3f4418Svisa #define CIU3_IDT(core, ipl) ((core) * 4 + (ipl))
442e3f4418Svisa #define CIU3_IDT_CTL(idt) ((idt) * 8 + 0x110000u)
452e3f4418Svisa #define CIU3_IDT_PP(idt) ((idt) * 32 + 0x120000u)
462e3f4418Svisa #define CIU3_IDT_IO(idt) ((idt) * 8 + 0x130000u)
472e3f4418Svisa #define CIU3_DEST_PP_INT(core) ((core) * 8 + 0x200000u)
482e3f4418Svisa #define CIU3_DEST_PP_INT_INTSN 0x000fffff00000000ull
492e3f4418Svisa #define CIU3_DEST_PP_INT_INTSN_SHIFT 32
502e3f4418Svisa #define CIU3_DEST_PP_INT_INTR 0x0000000000000001ull
512e3f4418Svisa #define CIU3_ISC_CTL(intsn) ((intsn) * 8 + 0x80000000u)
522e3f4418Svisa #define CIU3_ISC_CTL_IDT 0x0000000000ff0000ull
532e3f4418Svisa #define CIU3_ISC_CTL_IDT_SHIFT 16
542e3f4418Svisa #define CIU3_ISC_CTL_IMP 0x0000000000008000ull
552e3f4418Svisa #define CIU3_ISC_CTL_EN 0x0000000000000002ull
562e3f4418Svisa #define CIU3_ISC_CTL_RAW 0x0000000000000001ull
572e3f4418Svisa #define CIU3_ISC_W1C(intsn) ((intsn) * 8 + 0x90000000u)
582e3f4418Svisa #define CIU3_ISC_W1C_EN 0x0000000000000002ull
592e3f4418Svisa #define CIU3_ISC_W1C_RAW 0x0000000000000001ull
602e3f4418Svisa #define CIU3_ISC_W1S(intsn) ((intsn) * 8 + 0xa0000000u)
612e3f4418Svisa #define CIU3_ISC_W1S_EN 0x0000000000000002ull
622e3f4418Svisa #define CIU3_ISC_W1S_RAW 0x0000000000000001ull
632e3f4418Svisa #define CIU3_NINTSN (1u << 20)
642e3f4418Svisa
652e3f4418Svisa #define IS_MBOX(intsn) (((intsn) >> 12) == 4)
662e3f4418Svisa #define MBOX_INTSN(core) ((core) + 0x4000u)
672e3f4418Svisa
682e3f4418Svisa #define CIU3_RD_8(sc, reg) \
692e3f4418Svisa bus_space_read_8((sc)->sc_iot, (sc)->sc_ioh, (reg))
702e3f4418Svisa #define CIU3_WR_8(sc, reg, val) \
712e3f4418Svisa bus_space_write_8((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
722e3f4418Svisa
732e3f4418Svisa #define INTPRI_CIU_0 (INTPRI_CLOCK + 1)
742e3f4418Svisa
752e3f4418Svisa #define HASH_SIZE 64
762e3f4418Svisa
772e3f4418Svisa struct octcit_intrhand {
782e3f4418Svisa SLIST_ENTRY(octcit_intrhand)
792e3f4418Svisa ih_list;
802e3f4418Svisa int (*ih_func)(void *);
812e3f4418Svisa void *ih_arg;
822e3f4418Svisa int ih_intsn;
832e3f4418Svisa int ih_flags;
842e3f4418Svisa #define CIH_MPSAFE 0x01
852e3f4418Svisa #define CIH_EDGE 0x02 /* edge-triggered */
862e3f4418Svisa int ih_level;
872e3f4418Svisa struct evcount ih_count;
882e3f4418Svisa };
892e3f4418Svisa
902e3f4418Svisa struct octcit_softc {
912e3f4418Svisa struct device sc_dev;
922e3f4418Svisa bus_space_tag_t sc_iot;
932e3f4418Svisa bus_space_handle_t sc_ioh;
942e3f4418Svisa
952e3f4418Svisa SLIST_HEAD(, octcit_intrhand)
962e3f4418Svisa sc_handlers[HASH_SIZE];
972e3f4418Svisa int sc_minipl[MAXCPUS];
982e3f4418Svisa int (*sc_ipi_handler)(void *);
992e3f4418Svisa
1002e3f4418Svisa struct intr_controller sc_ic;
1012e3f4418Svisa };
1022e3f4418Svisa
1032e3f4418Svisa int octcit_match(struct device *, void *, void *);
1042e3f4418Svisa void octcit_attach(struct device *, struct device *, void *);
1052e3f4418Svisa
1062e3f4418Svisa void octcit_init(void);
1072e3f4418Svisa uint32_t octcit_intr(uint32_t, struct trapframe *);
1082e3f4418Svisa void *octcit_intr_establish(int, int, int (*)(void *), void *,
1092e3f4418Svisa const char *);
1102e3f4418Svisa void *octcit_intr_establish_intsn(int, int, int, int (*)(void *),
1112e3f4418Svisa void *, const char *);
1122e3f4418Svisa void *octcit_intr_establish_fdt_idx(void *, int, int, int,
1132e3f4418Svisa int (*)(void *), void *, const char *);
1142e3f4418Svisa void octcit_intr_disestablish(void *);
1150dd6b0daSvisa void octcit_intr_barrier(void *);
1162e3f4418Svisa void octcit_splx(int);
1172e3f4418Svisa
1182e3f4418Svisa uint32_t octcit_ipi_intr(uint32_t, struct trapframe *);
1192e3f4418Svisa int octcit_ipi_establish(int (*)(void *), cpuid_t);
1202e3f4418Svisa void octcit_ipi_set(cpuid_t);
1212e3f4418Svisa void octcit_ipi_clear(cpuid_t);
1222e3f4418Svisa
1232e3f4418Svisa const struct cfattach octcit_ca = {
1242e3f4418Svisa sizeof(struct octcit_softc), octcit_match, octcit_attach
1252e3f4418Svisa };
1262e3f4418Svisa
1272e3f4418Svisa struct cfdriver octcit_cd = {
1282e3f4418Svisa NULL, "octcit", DV_DULL
1292e3f4418Svisa };
1302e3f4418Svisa
1312e3f4418Svisa struct octcit_softc *octcit_sc;
1322e3f4418Svisa
1332e3f4418Svisa int
octcit_match(struct device * parent,void * match,void * aux)1342e3f4418Svisa octcit_match(struct device *parent, void *match, void *aux)
1352e3f4418Svisa {
1362e3f4418Svisa struct fdt_attach_args *faa = aux;
1372e3f4418Svisa
1382e3f4418Svisa return OF_is_compatible(faa->fa_node, "cavium,octeon-7890-ciu3");
1392e3f4418Svisa }
1402e3f4418Svisa
1412e3f4418Svisa void
octcit_attach(struct device * parent,struct device * self,void * aux)1422e3f4418Svisa octcit_attach(struct device *parent, struct device *self, void *aux)
1432e3f4418Svisa {
1442e3f4418Svisa struct fdt_attach_args *faa = aux;
1452e3f4418Svisa struct octcit_softc *sc = (struct octcit_softc *)self;
1462e3f4418Svisa uint64_t val;
1472e3f4418Svisa int hash, intsn;
1482e3f4418Svisa
1492e3f4418Svisa if (faa->fa_nreg != 1) {
1502e3f4418Svisa printf(": expected one IO space, got %d\n", faa->fa_nreg);
1512e3f4418Svisa return;
1522e3f4418Svisa }
1532e3f4418Svisa
1542e3f4418Svisa sc->sc_iot = faa->fa_iot;
1552e3f4418Svisa if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, faa->fa_reg[0].size,
1562e3f4418Svisa 0, &sc->sc_ioh)) {
1572e3f4418Svisa printf(": could not map IO space\n");
1582e3f4418Svisa return;
1592e3f4418Svisa }
1602e3f4418Svisa
1612e3f4418Svisa for (hash = 0; hash < HASH_SIZE; hash++)
1622e3f4418Svisa SLIST_INIT(&sc->sc_handlers[hash]);
1632e3f4418Svisa
1640e285dc5Svisa /* Disable all interrupts and acknowledge any pending ones. */
1652e3f4418Svisa for (intsn = 0; intsn < CIU3_NINTSN; intsn++) {
1662e3f4418Svisa val = CIU3_RD_8(sc, CIU3_ISC_CTL(intsn));
1672e3f4418Svisa if (ISSET(val, CIU3_ISC_CTL_IMP)) {
1680e285dc5Svisa CIU3_WR_8(sc, CIU3_ISC_W1C(intsn), CIU3_ISC_CTL_RAW);
1692e3f4418Svisa CIU3_WR_8(sc, CIU3_ISC_CTL(intsn), 0);
1702e3f4418Svisa (void)CIU3_RD_8(sc, CIU3_ISC_CTL(intsn));
1712e3f4418Svisa }
1722e3f4418Svisa }
1732e3f4418Svisa
1742e3f4418Svisa printf("\n");
1752e3f4418Svisa
1762e3f4418Svisa sc->sc_ic.ic_cookie = sc;
1772e3f4418Svisa sc->sc_ic.ic_node = faa->fa_node;
1782e3f4418Svisa sc->sc_ic.ic_init = octcit_init;
1792e3f4418Svisa sc->sc_ic.ic_establish = octcit_intr_establish;
1802e3f4418Svisa sc->sc_ic.ic_establish_fdt_idx = octcit_intr_establish_fdt_idx;
1812e3f4418Svisa sc->sc_ic.ic_disestablish = octcit_intr_disestablish;
1820dd6b0daSvisa sc->sc_ic.ic_intr_barrier = octcit_intr_barrier;
1832e3f4418Svisa #ifdef MULTIPROCESSOR
1842e3f4418Svisa sc->sc_ic.ic_ipi_establish = octcit_ipi_establish;
1852e3f4418Svisa sc->sc_ic.ic_ipi_set = octcit_ipi_set;
1862e3f4418Svisa sc->sc_ic.ic_ipi_clear = octcit_ipi_clear;
1872e3f4418Svisa #endif
1882e3f4418Svisa
1892e3f4418Svisa octcit_sc = sc;
1902e3f4418Svisa
1912e3f4418Svisa set_intr(INTPRI_CIU_0, CR_INT_0, octcit_intr);
1922e3f4418Svisa #ifdef MULTIPROCESSOR
1932e3f4418Svisa set_intr(INTPRI_IPI, CR_INT_1, octcit_ipi_intr);
1942e3f4418Svisa #endif
1952e3f4418Svisa
1962e3f4418Svisa octcit_init();
1972e3f4418Svisa
1982e3f4418Svisa register_splx_handler(octcit_splx);
1992e3f4418Svisa octeon_intr_register(&sc->sc_ic);
2002e3f4418Svisa }
2012e3f4418Svisa
2022e3f4418Svisa static inline int
intsn_hash(int intsn)2032e3f4418Svisa intsn_hash(int intsn)
2042e3f4418Svisa {
2052e3f4418Svisa int tmp;
2062e3f4418Svisa
2072e3f4418Svisa tmp = intsn * 0xffb;
2082e3f4418Svisa return ((tmp >> 14) ^ tmp) & (HASH_SIZE - 1);
2092e3f4418Svisa }
2102e3f4418Svisa
2112e3f4418Svisa void
octcit_init(void)2122e3f4418Svisa octcit_init(void)
2132e3f4418Svisa {
2142e3f4418Svisa struct cpu_info *ci = curcpu();
2152e3f4418Svisa struct octcit_softc *sc = octcit_sc;
2162e3f4418Svisa int core = ci->ci_cpuid;
2172e3f4418Svisa
2182e3f4418Svisa sc->sc_minipl[ci->ci_cpuid] = IPL_HIGH;
2192e3f4418Svisa
2202e3f4418Svisa /*
2212e3f4418Svisa * Set up interrupt routing.
2222e3f4418Svisa */
2232e3f4418Svisa
2242e3f4418Svisa /* Route IP2. */
2252e3f4418Svisa CIU3_WR_8(sc, CIU3_IDT_CTL(CIU3_IDT(core, 0)), 0);
2262e3f4418Svisa CIU3_WR_8(sc, CIU3_IDT_PP(CIU3_IDT(core, 0)), 1ul << core);
2272e3f4418Svisa CIU3_WR_8(sc, CIU3_IDT_IO(CIU3_IDT(core, 0)), 0);
2282e3f4418Svisa
2292e3f4418Svisa /* Route IP3. */
2302e3f4418Svisa CIU3_WR_8(sc, CIU3_IDT_CTL(CIU3_IDT(core , 1)), 1);
2312e3f4418Svisa CIU3_WR_8(sc, CIU3_IDT_PP(CIU3_IDT(core, 1)), 1ul << core);
2322e3f4418Svisa CIU3_WR_8(sc, CIU3_IDT_IO(CIU3_IDT(core, 1)), 0);
2332e3f4418Svisa
2342e3f4418Svisa /* Disable IP4. */
2352e3f4418Svisa CIU3_WR_8(sc, CIU3_IDT_CTL(CIU3_IDT(core, 2)), 0);
2362e3f4418Svisa CIU3_WR_8(sc, CIU3_IDT_PP(CIU3_IDT(core, 2)), 0);
2372e3f4418Svisa CIU3_WR_8(sc, CIU3_IDT_IO(CIU3_IDT(core, 2)), 0);
2382e3f4418Svisa
2392e3f4418Svisa /* Disable IP5. */
2402e3f4418Svisa CIU3_WR_8(sc, CIU3_IDT_CTL(CIU3_IDT(core, 3)), 0);
2412e3f4418Svisa CIU3_WR_8(sc, CIU3_IDT_PP(CIU3_IDT(core, 3)), 0);
2422e3f4418Svisa CIU3_WR_8(sc, CIU3_IDT_IO(CIU3_IDT(core, 3)), 0);
2432e3f4418Svisa }
2442e3f4418Svisa
2452e3f4418Svisa void *
octcit_intr_establish(int irq,int level,int (* func)(void *),void * arg,const char * name)2462e3f4418Svisa octcit_intr_establish(int irq, int level, int (*func)(void *), void *arg,
2472e3f4418Svisa const char *name)
2482e3f4418Svisa {
24976163558Svisa return octcit_intr_establish_intsn(irq, level, CIH_EDGE, func, arg,
25076163558Svisa name);
2512e3f4418Svisa }
2522e3f4418Svisa
2532e3f4418Svisa void *
octcit_intr_establish_intsn(int intsn,int level,int flags,int (* func)(void *),void * arg,const char * name)2542e3f4418Svisa octcit_intr_establish_intsn(int intsn, int level, int flags,
2552e3f4418Svisa int (*func)(void *), void *arg, const char *name)
2562e3f4418Svisa {
2572e3f4418Svisa struct cpu_info *ci = curcpu();
2582e3f4418Svisa struct octcit_intrhand *ih;
2592e3f4418Svisa struct octcit_softc *sc = octcit_sc;
2602e3f4418Svisa uint64_t val;
2612e3f4418Svisa int s;
2622e3f4418Svisa
2632e3f4418Svisa if ((unsigned int)intsn > CIU3_NINTSN)
2642e3f4418Svisa panic("%s: illegal intsn 0x%x", __func__, intsn);
2652e3f4418Svisa
2662e3f4418Svisa if (IS_MBOX(intsn))
2672e3f4418Svisa panic("%s: mbox intsn 0x%x not allowed", __func__, intsn);
2682e3f4418Svisa
2692e3f4418Svisa if (ISSET(level, IPL_MPSAFE))
2702e3f4418Svisa flags |= CIH_MPSAFE;
2712e3f4418Svisa level &= ~IPL_MPSAFE;
2722e3f4418Svisa
2732e3f4418Svisa ih = malloc(sizeof(*ih), M_DEVBUF, M_NOWAIT);
2742e3f4418Svisa if (ih == NULL)
2752e3f4418Svisa return NULL;
2762e3f4418Svisa
2772e3f4418Svisa ih->ih_func = func;
2782e3f4418Svisa ih->ih_arg = arg;
2792e3f4418Svisa ih->ih_level = level;
2802e3f4418Svisa ih->ih_flags = flags;
2812e3f4418Svisa ih->ih_intsn = intsn;
2822e3f4418Svisa evcount_attach(&ih->ih_count, name, &ih->ih_intsn);
283*ae38162bSvisa evcount_percpu(&ih->ih_count);
2842e3f4418Svisa
2852e3f4418Svisa s = splhigh();
2862e3f4418Svisa
2872e3f4418Svisa SLIST_INSERT_HEAD(&sc->sc_handlers[intsn_hash(intsn)], ih, ih_list);
2882e3f4418Svisa if (sc->sc_minipl[ci->ci_cpuid] > level)
2892e3f4418Svisa sc->sc_minipl[ci->ci_cpuid] = level;
2902e3f4418Svisa
2912e3f4418Svisa val = CIU3_ISC_CTL_EN | (CIU3_IDT(ci->ci_cpuid, 0) <<
2922e3f4418Svisa CIU3_ISC_CTL_IDT_SHIFT);
293629d9e02Svisa CIU3_WR_8(sc, CIU3_ISC_W1C(intsn), CIU3_ISC_W1C_EN);
2942e3f4418Svisa CIU3_WR_8(sc, CIU3_ISC_CTL(intsn), val);
2952e3f4418Svisa (void)CIU3_RD_8(sc, CIU3_ISC_CTL(intsn));
2962e3f4418Svisa
2972e3f4418Svisa splx(s);
2982e3f4418Svisa
2992e3f4418Svisa return ih;
3002e3f4418Svisa }
3012e3f4418Svisa
3022e3f4418Svisa void *
octcit_intr_establish_fdt_idx(void * cookie,int node,int idx,int level,int (* func)(void *),void * arg,const char * name)3032e3f4418Svisa octcit_intr_establish_fdt_idx(void *cookie, int node, int idx, int level,
3042e3f4418Svisa int (*func)(void *), void *arg, const char *name)
3052e3f4418Svisa {
3062e3f4418Svisa uint32_t *cells;
3072e3f4418Svisa int flags = 0;
3082e3f4418Svisa int intsn, len, type;
3092e3f4418Svisa
3102e3f4418Svisa len = OF_getproplen(node, "interrupts");
3112e3f4418Svisa if (len / (sizeof(uint32_t) * 2) <= idx ||
3122e3f4418Svisa len % (sizeof(uint32_t) * 2) != 0)
3132e3f4418Svisa return NULL;
3142e3f4418Svisa
3152e3f4418Svisa cells = malloc(len, M_TEMP, M_NOWAIT);
3162e3f4418Svisa if (cells == NULL)
3172e3f4418Svisa return NULL;
3182e3f4418Svisa
3192e3f4418Svisa OF_getpropintarray(node, "interrupts", cells, len);
3202e3f4418Svisa intsn = cells[idx * 2];
3212e3f4418Svisa type = cells[idx * 2 + 1];
3222e3f4418Svisa
3232e3f4418Svisa free(cells, M_TEMP, len);
3242e3f4418Svisa
3252e3f4418Svisa if (type != 4)
3262e3f4418Svisa flags |= CIH_EDGE;
3272e3f4418Svisa
3282e3f4418Svisa return octcit_intr_establish_intsn(intsn, level, flags, func, arg,
3292e3f4418Svisa name);
3302e3f4418Svisa }
3312e3f4418Svisa
3322e3f4418Svisa void
octcit_intr_disestablish(void * _ih)3332e3f4418Svisa octcit_intr_disestablish(void *_ih)
3342e3f4418Svisa {
3352e3f4418Svisa struct cpu_info *ci = curcpu();
3362e3f4418Svisa struct octcit_intrhand *ih = _ih;
3372e3f4418Svisa struct octcit_intrhand *tmp;
3382e3f4418Svisa struct octcit_softc *sc = octcit_sc;
3392e3f4418Svisa unsigned int count;
3402e3f4418Svisa int found = 0;
3412e3f4418Svisa int hash = intsn_hash(ih->ih_intsn);
3422e3f4418Svisa int i, s;
3432e3f4418Svisa
3442e3f4418Svisa count = 0;
3452e3f4418Svisa SLIST_FOREACH(tmp, &sc->sc_handlers[hash], ih_list) {
3462e3f4418Svisa if (tmp->ih_intsn == ih->ih_intsn)
3472e3f4418Svisa count++;
3482e3f4418Svisa if (tmp == ih)
3492e3f4418Svisa found = 1;
3502e3f4418Svisa }
3512e3f4418Svisa if (found == 0)
3522e3f4418Svisa panic("%s: intrhand %p not registered", __func__, ih);
3532e3f4418Svisa
3542e3f4418Svisa s = splhigh();
3552e3f4418Svisa
3562e3f4418Svisa if (count == 0) {
3572e3f4418Svisa CIU3_WR_8(sc, CIU3_ISC_W1C(ih->ih_intsn), CIU3_ISC_W1C_EN);
3582e3f4418Svisa CIU3_WR_8(sc, CIU3_ISC_CTL(ih->ih_intsn), 0);
3592e3f4418Svisa (void)CIU3_RD_8(sc, CIU3_ISC_CTL(ih->ih_intsn));
3602e3f4418Svisa }
3612e3f4418Svisa
3622e3f4418Svisa SLIST_REMOVE(&sc->sc_handlers[hash], ih, octcit_intrhand, ih_list);
3637abddf2dSvisa evcount_detach(&ih->ih_count);
3642e3f4418Svisa
3652e3f4418Svisa /* Recompute IPL floor if necessary. */
3662e3f4418Svisa if (sc->sc_minipl[ci->ci_cpuid] == ih->ih_level) {
3672e3f4418Svisa sc->sc_minipl[ci->ci_cpuid] = IPL_HIGH;
3682e3f4418Svisa for (i = 0; i < HASH_SIZE; i++) {
3692e3f4418Svisa SLIST_FOREACH(tmp, &sc->sc_handlers[i], ih_list) {
3702e3f4418Svisa if (sc->sc_minipl[ci->ci_cpuid] >
3712e3f4418Svisa tmp->ih_level)
3722e3f4418Svisa sc->sc_minipl[ci->ci_cpuid] =
3732e3f4418Svisa tmp->ih_level;
3742e3f4418Svisa }
3752e3f4418Svisa }
3762e3f4418Svisa }
3772e3f4418Svisa
3782e3f4418Svisa splx(s);
3792e3f4418Svisa
3802e3f4418Svisa free(ih, M_DEVBUF, sizeof(*ih));
3812e3f4418Svisa }
3822e3f4418Svisa
3830dd6b0daSvisa void
octcit_intr_barrier(void * _ih)3840dd6b0daSvisa octcit_intr_barrier(void *_ih)
3850dd6b0daSvisa {
3860dd6b0daSvisa sched_barrier(NULL);
3870dd6b0daSvisa }
3880dd6b0daSvisa
3892e3f4418Svisa uint32_t
octcit_intr(uint32_t hwpend,struct trapframe * frame)3902e3f4418Svisa octcit_intr(uint32_t hwpend, struct trapframe *frame)
3912e3f4418Svisa {
3922e3f4418Svisa struct cpu_info *ci = curcpu();
3932e3f4418Svisa struct octcit_intrhand *ih;
3942e3f4418Svisa struct octcit_softc *sc = octcit_sc;
3952e3f4418Svisa uint64_t destpp;
3962e3f4418Svisa uint64_t intsn;
3972e3f4418Svisa unsigned int core = ci->ci_cpuid;
3982e3f4418Svisa int handled = 0;
3992e3f4418Svisa int ipl;
4002e3f4418Svisa int ret;
4012e3f4418Svisa #ifdef MULTIPROCESSOR
4022e3f4418Svisa register_t sr;
4032e3f4418Svisa int need_lock;
4042e3f4418Svisa #endif
4052e3f4418Svisa
4062e3f4418Svisa if (frame->ipl >= sc->sc_minipl[ci->ci_cpuid]) {
4072e3f4418Svisa /* Disable IP2. */
4082e3f4418Svisa CIU3_WR_8(sc, CIU3_IDT_PP(CIU3_IDT(core, 0)), 0);
4092e3f4418Svisa (void)CIU3_RD_8(sc, CIU3_IDT_PP(CIU3_IDT(core, 0)));
4102e3f4418Svisa return hwpend;
4112e3f4418Svisa }
4122e3f4418Svisa
4132e3f4418Svisa destpp = CIU3_RD_8(sc, CIU3_DEST_PP_INT(core));
4142e3f4418Svisa if (!ISSET(destpp, CIU3_DEST_PP_INT_INTR))
4152e3f4418Svisa goto spurious;
4162e3f4418Svisa
4172e3f4418Svisa ipl = ci->ci_ipl;
4182e3f4418Svisa
4192e3f4418Svisa intsn = (destpp & CIU3_DEST_PP_INT_INTSN) >>
4202e3f4418Svisa CIU3_DEST_PP_INT_INTSN_SHIFT;
4212e3f4418Svisa SLIST_FOREACH(ih, &sc->sc_handlers[intsn_hash(intsn)], ih_list) {
4222e3f4418Svisa if (ih->ih_intsn != intsn)
4232e3f4418Svisa continue;
4242e3f4418Svisa
4252e3f4418Svisa splraise(ih->ih_level);
4262e3f4418Svisa
4272e3f4418Svisa /* Acknowledge the interrupt. */
4282e3f4418Svisa if (ISSET(ih->ih_flags, CIH_EDGE)) {
4292e3f4418Svisa CIU3_WR_8(sc, CIU3_ISC_W1C(intsn), CIU3_ISC_CTL_RAW);
4302e3f4418Svisa (void)CIU3_RD_8(sc, CIU3_ISC_W1C(intsn));
4312e3f4418Svisa }
4322e3f4418Svisa
4332e3f4418Svisa #ifdef MULTIPROCESSOR
4342e3f4418Svisa if (ih->ih_level < IPL_IPI) {
4352e3f4418Svisa sr = getsr();
4362e3f4418Svisa ENABLEIPI();
4372e3f4418Svisa }
4382821cfa0Svisa if (ISSET(ih->ih_flags, CIH_MPSAFE))
4392e3f4418Svisa need_lock = 0;
4402e3f4418Svisa else
441f8189779Svisa need_lock = 1;
4422e3f4418Svisa if (need_lock)
4432e3f4418Svisa __mp_lock(&kernel_lock);
4442e3f4418Svisa #endif
4452e3f4418Svisa ret = (*ih->ih_func)(ih->ih_arg);
4462e3f4418Svisa #ifdef MULTIPROCESSOR
4472e3f4418Svisa if (need_lock)
4482e3f4418Svisa __mp_unlock(&kernel_lock);
4492e3f4418Svisa if (ih->ih_level < IPL_IPI)
4502e3f4418Svisa setsr(sr);
4512e3f4418Svisa #endif
4522e3f4418Svisa
4532e3f4418Svisa if (ret != 0) {
4542e3f4418Svisa handled = 1;
455*ae38162bSvisa evcount_inc(&ih->ih_count);
4562e3f4418Svisa }
4572e3f4418Svisa
4582e3f4418Svisa /*
4592e3f4418Svisa * Stop processing when one handler has claimed the interrupt.
4602e3f4418Svisa * This saves cycles because interrupt sharing should not
4612e3f4418Svisa * happen on this hardware.
4622e3f4418Svisa */
4632e3f4418Svisa if (ret == 1)
4642e3f4418Svisa break;
4652e3f4418Svisa }
4662e3f4418Svisa
4672e3f4418Svisa ci->ci_ipl = ipl;
4682e3f4418Svisa
4692e3f4418Svisa spurious:
4702e3f4418Svisa if (handled == 0)
4715e9543b6Svisa printf("%s: spurious interrupt 0x%016llx on cpu %lu\n",
4725e9543b6Svisa sc->sc_dev.dv_xname, destpp, ci->ci_cpuid);
4732e3f4418Svisa
4742e3f4418Svisa return hwpend;
4752e3f4418Svisa }
4762e3f4418Svisa
4772e3f4418Svisa void
octcit_splx(int newipl)4782e3f4418Svisa octcit_splx(int newipl)
4792e3f4418Svisa {
4802e3f4418Svisa struct octcit_softc *sc = octcit_sc;
4812e3f4418Svisa struct cpu_info *ci = curcpu();
4822e3f4418Svisa unsigned int core = ci->ci_cpuid;
4832e3f4418Svisa
4842e3f4418Svisa ci->ci_ipl = newipl;
4852e3f4418Svisa
486864b814fSvisa if (newipl < sc->sc_minipl[ci->ci_cpuid]) {
4872e3f4418Svisa CIU3_WR_8(sc, CIU3_IDT_PP(CIU3_IDT(core, 0)), 1ul << core);
488864b814fSvisa (void)CIU3_RD_8(sc, CIU3_IDT_PP(CIU3_IDT(core, 0)));
489864b814fSvisa }
4902e3f4418Svisa
49185caa4b9Scheloha /* Trigger deferred clock interrupt if it is now unmasked. */
49285caa4b9Scheloha if (ci->ci_clock_deferred && newipl < IPL_CLOCK)
49385caa4b9Scheloha md_triggerclock();
49485caa4b9Scheloha
4952e3f4418Svisa /* If we still have softints pending trigger processing. */
4962e3f4418Svisa if (ci->ci_softpending != 0 && newipl < IPL_SOFTINT)
4972e3f4418Svisa setsoftintr0();
4982e3f4418Svisa }
4992e3f4418Svisa
5002e3f4418Svisa #ifdef MULTIPROCESSOR
5012e3f4418Svisa uint32_t
octcit_ipi_intr(uint32_t hwpend,struct trapframe * frame)5022e3f4418Svisa octcit_ipi_intr(uint32_t hwpend, struct trapframe *frame)
5032e3f4418Svisa {
5042e3f4418Svisa struct octcit_softc *sc = octcit_sc;
5052e3f4418Svisa u_long cpuid = cpu_number();
5062e3f4418Svisa
5072e3f4418Svisa if (sc->sc_ipi_handler != NULL)
5082e3f4418Svisa sc->sc_ipi_handler((void *)cpuid);
5092e3f4418Svisa
5102e3f4418Svisa return hwpend;
5112e3f4418Svisa }
5122e3f4418Svisa
5132e3f4418Svisa int
octcit_ipi_establish(int (* func)(void *),cpuid_t cpuid)5142e3f4418Svisa octcit_ipi_establish(int (*func)(void *), cpuid_t cpuid)
5152e3f4418Svisa {
5162e3f4418Svisa struct octcit_softc *sc = octcit_sc;
5172e3f4418Svisa uint64_t val;
5182e3f4418Svisa int intsn;
5192e3f4418Svisa
5202e3f4418Svisa if (cpuid == 0)
5212e3f4418Svisa sc->sc_ipi_handler = func;
5222e3f4418Svisa
5232e3f4418Svisa intsn = MBOX_INTSN(cpuid);
5242e3f4418Svisa val = CIU3_ISC_CTL_EN | (CIU3_IDT(cpuid, 1) << CIU3_ISC_CTL_IDT_SHIFT);
525629d9e02Svisa CIU3_WR_8(sc, CIU3_ISC_W1C(intsn), CIU3_ISC_W1C_EN);
5262e3f4418Svisa CIU3_WR_8(sc, CIU3_ISC_CTL(intsn), val);
5272e3f4418Svisa (void)CIU3_RD_8(sc, CIU3_ISC_CTL(intsn));
5282e3f4418Svisa
5292e3f4418Svisa return 0;
5302e3f4418Svisa }
5312e3f4418Svisa
5322e3f4418Svisa void
octcit_ipi_set(cpuid_t cpuid)5332e3f4418Svisa octcit_ipi_set(cpuid_t cpuid)
5342e3f4418Svisa {
5352e3f4418Svisa struct octcit_softc *sc = octcit_sc;
536864b814fSvisa uint64_t reg = CIU3_ISC_W1S(MBOX_INTSN(cpuid));
5372e3f4418Svisa
538864b814fSvisa CIU3_WR_8(sc, reg, CIU3_ISC_W1S_RAW);
539864b814fSvisa (void)CIU3_RD_8(sc, reg);
5402e3f4418Svisa }
5412e3f4418Svisa
5422e3f4418Svisa void
octcit_ipi_clear(cpuid_t cpuid)5432e3f4418Svisa octcit_ipi_clear(cpuid_t cpuid)
5442e3f4418Svisa {
5452e3f4418Svisa struct octcit_softc *sc = octcit_sc;
5462e3f4418Svisa uint64_t reg = CIU3_ISC_W1C(MBOX_INTSN(cpuid));
5472e3f4418Svisa
5482e3f4418Svisa CIU3_WR_8(sc, reg, CIU3_ISC_W1C_RAW);
5492e3f4418Svisa (void)CIU3_RD_8(sc, reg);
5502e3f4418Svisa }
5512e3f4418Svisa #endif /* MULTIPROCESSOR */
552