1*471aeecfSnaddy /* $OpenBSD: xive.c,v 1.17 2022/04/06 18:59:27 naddy Exp $ */
21af8fcf9Skettenis /*
31af8fcf9Skettenis * Copyright (c) 2020 Mark Kettenis <kettenis@openbsd.org>
41af8fcf9Skettenis *
51af8fcf9Skettenis * Permission to use, copy, modify, and distribute this software for any
61af8fcf9Skettenis * purpose with or without fee is hereby granted, provided that the above
71af8fcf9Skettenis * copyright notice and this permission notice appear in all copies.
81af8fcf9Skettenis *
91af8fcf9Skettenis * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
101af8fcf9Skettenis * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
111af8fcf9Skettenis * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
121af8fcf9Skettenis * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
131af8fcf9Skettenis * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
141af8fcf9Skettenis * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
151af8fcf9Skettenis * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
161af8fcf9Skettenis */
171af8fcf9Skettenis
181af8fcf9Skettenis #include <sys/param.h>
191af8fcf9Skettenis #include <sys/systm.h>
201af8fcf9Skettenis #include <sys/device.h>
211af8fcf9Skettenis #include <sys/evcount.h>
221af8fcf9Skettenis #include <sys/malloc.h>
231af8fcf9Skettenis #include <sys/queue.h>
241af8fcf9Skettenis
251af8fcf9Skettenis #include <machine/bus.h>
261af8fcf9Skettenis #include <machine/fdt.h>
271af8fcf9Skettenis #include <machine/opal.h>
281af8fcf9Skettenis
291af8fcf9Skettenis #include <dev/ofw/openfirm.h>
301af8fcf9Skettenis #include <dev/ofw/fdt.h>
311af8fcf9Skettenis
321af8fcf9Skettenis #define XIVE_NUM_PRIORITIES 8
331af8fcf9Skettenis #define XIVE_NUM_IRQS 1024
341af8fcf9Skettenis
351af8fcf9Skettenis #define XIVE_EQ_SIZE PAGE_SHIFT
361af8fcf9Skettenis #define XIVE_EQ_IDX_MASK ((1 << (PAGE_SHIFT - 2)) - 1)
371af8fcf9Skettenis #define XIVE_EQ_GEN_MASK 0x80000000
381af8fcf9Skettenis
391af8fcf9Skettenis #define XIVE_TM_CPPR_HV 0x031
401af8fcf9Skettenis
411af8fcf9Skettenis #define XIVE_TM_SPC_ACK_HV 0x830
421af8fcf9Skettenis #define XIVE_TM_SPC_ACK_HE_MASK 0xc000
431af8fcf9Skettenis #define XIVE_TM_SPC_ACK_HE_NONE 0x0000
441af8fcf9Skettenis #define XIVE_TM_SPC_ACK_HE_PHYS 0x8000
451af8fcf9Skettenis
461af8fcf9Skettenis #define XIVE_ESB_STORE_TRIGGER 0x000
473e2fcfc8Skettenis #define XIVE_ESB_LOAD_EOI 0x000
483e2fcfc8Skettenis #define XIVE_ESB_STORE_EOI 0x400
491af8fcf9Skettenis #define XIVE_ESB_SET_PQ_00 0xc00
501af8fcf9Skettenis #define XIVE_ESB_SET_PQ_01 0xd00
511af8fcf9Skettenis #define XIVE_ESB_SET_PQ_10 0xe00
521af8fcf9Skettenis #define XIVE_ESB_SET_PQ_11 0xf00
531af8fcf9Skettenis
541af8fcf9Skettenis #define XIVE_ESB_VAL_P 0x2
551af8fcf9Skettenis #define XIVE_ESB_VAL_Q 0x1
561af8fcf9Skettenis
571af8fcf9Skettenis static inline uint8_t
xive_prio(int ipl)581af8fcf9Skettenis xive_prio(int ipl)
591af8fcf9Skettenis {
601af8fcf9Skettenis return ((IPL_IPI - ipl) > 7 ? 0xff : IPL_IPI - ipl);
611af8fcf9Skettenis }
621af8fcf9Skettenis
631af8fcf9Skettenis static inline int
xive_ipl(uint8_t prio)641af8fcf9Skettenis xive_ipl(uint8_t prio)
651af8fcf9Skettenis {
661af8fcf9Skettenis return (IPL_IPI - prio);
671af8fcf9Skettenis }
681af8fcf9Skettenis
691af8fcf9Skettenis struct intrhand {
701af8fcf9Skettenis TAILQ_ENTRY(intrhand) ih_list;
711af8fcf9Skettenis int (*ih_func)(void *);
721af8fcf9Skettenis void *ih_arg;
731af8fcf9Skettenis int ih_ipl;
741af8fcf9Skettenis int ih_flags;
751af8fcf9Skettenis uint32_t ih_girq;
761af8fcf9Skettenis struct evcount ih_count;
771af8fcf9Skettenis const char *ih_name;
781af8fcf9Skettenis
791af8fcf9Skettenis bus_space_handle_t ih_esb_eoi;
801af8fcf9Skettenis bus_space_handle_t ih_esb_trig;
811af8fcf9Skettenis uint64_t ih_xive_flags;
821af8fcf9Skettenis };
831af8fcf9Skettenis
841af8fcf9Skettenis struct xive_eq {
851af8fcf9Skettenis struct xive_dmamem *eq_queue;
861af8fcf9Skettenis uint32_t eq_idx;
871af8fcf9Skettenis uint32_t eq_gen;
881af8fcf9Skettenis };
891af8fcf9Skettenis
901af8fcf9Skettenis struct xive_softc {
911af8fcf9Skettenis struct device sc_dev;
921af8fcf9Skettenis bus_space_tag_t sc_iot;
931af8fcf9Skettenis bus_space_handle_t sc_ioh;
941af8fcf9Skettenis bus_dma_tag_t sc_dmat;
951af8fcf9Skettenis
961af8fcf9Skettenis struct intrhand *sc_handler[XIVE_NUM_IRQS];
97fcf94dc6Skettenis struct xive_eq sc_eq[MAXCPUS][XIVE_NUM_PRIORITIES];
981af8fcf9Skettenis
991af8fcf9Skettenis uint32_t sc_page_size;
1001af8fcf9Skettenis uint32_t sc_lirq;
1011af8fcf9Skettenis };
1021af8fcf9Skettenis
1031af8fcf9Skettenis struct xive_softc *xive_sc;
1041af8fcf9Skettenis
1051af8fcf9Skettenis struct xive_dmamem {
1061af8fcf9Skettenis bus_dmamap_t xdm_map;
1071af8fcf9Skettenis bus_dma_segment_t xdm_seg;
1081af8fcf9Skettenis size_t xdm_size;
1091af8fcf9Skettenis caddr_t xdm_kva;
1101af8fcf9Skettenis };
1111af8fcf9Skettenis
1121af8fcf9Skettenis #define XIVE_DMA_MAP(_xdm) ((_xdm)->xdm_map)
1131af8fcf9Skettenis #define XIVE_DMA_LEN(_xdm) ((_xdm)->xdm_size)
1141af8fcf9Skettenis #define XIVE_DMA_DVA(_xdm) ((_xdm)->xdm_map->dm_segs[0].ds_addr)
1151af8fcf9Skettenis #define XIVE_DMA_KVA(_xdm) ((void *)(_xdm)->xdm_kva)
1161af8fcf9Skettenis
1171af8fcf9Skettenis struct xive_dmamem *xive_dmamem_alloc(bus_dma_tag_t, bus_size_t,
1181af8fcf9Skettenis bus_size_t);
1191af8fcf9Skettenis void xive_dmamem_free(bus_dma_tag_t, struct xive_dmamem *);
1201af8fcf9Skettenis
1211af8fcf9Skettenis static inline void
xive_write_1(struct xive_softc * sc,bus_size_t off,uint8_t val)1221af8fcf9Skettenis xive_write_1(struct xive_softc *sc, bus_size_t off, uint8_t val)
1231af8fcf9Skettenis {
1241af8fcf9Skettenis bus_space_write_1(sc->sc_iot, sc->sc_ioh, off, val);
1251af8fcf9Skettenis }
1261af8fcf9Skettenis
1271af8fcf9Skettenis static inline uint16_t
xive_read_2(struct xive_softc * sc,bus_size_t off)1281af8fcf9Skettenis xive_read_2(struct xive_softc *sc, bus_size_t off)
1291af8fcf9Skettenis {
1301af8fcf9Skettenis return bus_space_read_2(sc->sc_iot, sc->sc_ioh, off);
1311af8fcf9Skettenis }
1321af8fcf9Skettenis
1333e2fcfc8Skettenis static inline void
xive_unmask(struct xive_softc * sc,struct intrhand * ih)1343e2fcfc8Skettenis xive_unmask(struct xive_softc *sc, struct intrhand *ih)
1353e2fcfc8Skettenis {
1363e2fcfc8Skettenis bus_space_read_8(sc->sc_iot, ih->ih_esb_eoi, XIVE_ESB_SET_PQ_00);
1373e2fcfc8Skettenis }
1383e2fcfc8Skettenis
1391af8fcf9Skettenis int xive_match(struct device *, void *, void *);
1401af8fcf9Skettenis void xive_attach(struct device *, struct device *, void *);
1418c64a04eSkettenis int xive_activate(struct device *, int);
1421af8fcf9Skettenis
143*471aeecfSnaddy const struct cfattach xive_ca = {
1448c64a04eSkettenis sizeof (struct xive_softc), xive_match, xive_attach, NULL,
1458c64a04eSkettenis xive_activate
1461af8fcf9Skettenis };
1471af8fcf9Skettenis
1481af8fcf9Skettenis struct cfdriver xive_cd = {
1491af8fcf9Skettenis NULL, "xive", DV_DULL
1501af8fcf9Skettenis };
1511af8fcf9Skettenis
1521af8fcf9Skettenis void xive_hvi(struct trapframe *);
153a940e3deSkettenis void *xive_intr_establish(uint32_t, int, int, struct cpu_info *,
1541af8fcf9Skettenis int (*)(void *), void *, const char *);
155fcf94dc6Skettenis void xive_intr_send_ipi(void *);
1561af8fcf9Skettenis void xive_setipl(int);
1571af8fcf9Skettenis
1581af8fcf9Skettenis int
xive_match(struct device * parent,void * match,void * aux)1591af8fcf9Skettenis xive_match(struct device *parent, void *match, void *aux)
1601af8fcf9Skettenis {
1611af8fcf9Skettenis struct fdt_attach_args *faa = aux;
1621af8fcf9Skettenis
1631af8fcf9Skettenis return OF_is_compatible(faa->fa_node, "ibm,opal-xive-pe");
1641af8fcf9Skettenis }
1651af8fcf9Skettenis
1661af8fcf9Skettenis void
xive_attach(struct device * parent,struct device * self,void * aux)1671af8fcf9Skettenis xive_attach(struct device *parent, struct device *self, void *aux)
1681af8fcf9Skettenis {
1691af8fcf9Skettenis struct xive_softc *sc = (struct xive_softc *)self;
1701af8fcf9Skettenis struct fdt_attach_args *faa = aux;
171fcf94dc6Skettenis struct cpu_info *ci;
172fcf94dc6Skettenis CPU_INFO_ITERATOR cii;
1731af8fcf9Skettenis int64_t error;
1741af8fcf9Skettenis int i;
1751af8fcf9Skettenis
1761af8fcf9Skettenis if (faa->fa_nreg < 2) {
1771af8fcf9Skettenis printf(": no registers\n");
1781af8fcf9Skettenis return;
1791af8fcf9Skettenis }
1801af8fcf9Skettenis
1811af8fcf9Skettenis sc->sc_iot = faa->fa_iot;
1821af8fcf9Skettenis if (bus_space_map(sc->sc_iot, faa->fa_reg[1].addr,
1831af8fcf9Skettenis faa->fa_reg[1].size, 0, &sc->sc_ioh)) {
1841af8fcf9Skettenis printf(": can't map registers\n");
1851af8fcf9Skettenis return;
1861af8fcf9Skettenis }
1871af8fcf9Skettenis
1881af8fcf9Skettenis sc->sc_dmat = faa->fa_dmat;
1891af8fcf9Skettenis
1901af8fcf9Skettenis sc->sc_page_size = OF_getpropint(faa->fa_node,
1911af8fcf9Skettenis "ibm,xive-provision-page-size", 0);
1921af8fcf9Skettenis
1931af8fcf9Skettenis error = opal_xive_reset(OPAL_XIVE_MODE_EXPL);
1941af8fcf9Skettenis if (error != OPAL_SUCCESS)
1951af8fcf9Skettenis printf(": can't enable exploitation mode\n");
1961af8fcf9Skettenis
1971af8fcf9Skettenis printf("\n");
1981af8fcf9Skettenis
199fcf94dc6Skettenis CPU_INFO_FOREACH(cii, ci) {
2001af8fcf9Skettenis for (i = 0; i < XIVE_NUM_PRIORITIES; i++) {
201fcf94dc6Skettenis sc->sc_eq[ci->ci_cpuid][i].eq_queue =
202fcf94dc6Skettenis xive_dmamem_alloc(sc->sc_dmat,
2031af8fcf9Skettenis 1 << XIVE_EQ_SIZE, 1 << XIVE_EQ_SIZE);
204fcf94dc6Skettenis if (sc->sc_eq[ci->ci_cpuid][i].eq_queue == NULL) {
2051af8fcf9Skettenis printf("%s: can't allocate event queue\n",
2061af8fcf9Skettenis sc->sc_dev.dv_xname);
2071af8fcf9Skettenis return;
2081af8fcf9Skettenis }
2091af8fcf9Skettenis
210fcf94dc6Skettenis error = opal_xive_set_queue_info(ci->ci_pir, i,
211fcf94dc6Skettenis XIVE_DMA_DVA(sc->sc_eq[ci->ci_cpuid][i].eq_queue),
212fcf94dc6Skettenis XIVE_EQ_SIZE, OPAL_XIVE_EQ_ENABLED |
213fcf94dc6Skettenis OPAL_XIVE_EQ_ALWAYS_NOTIFY);
2141af8fcf9Skettenis if (error != OPAL_SUCCESS) {
2151af8fcf9Skettenis printf("%s: can't enable event queue\n",
2161af8fcf9Skettenis sc->sc_dev.dv_xname);
2171af8fcf9Skettenis return;
2181af8fcf9Skettenis }
2191af8fcf9Skettenis
220fcf94dc6Skettenis sc->sc_eq[ci->ci_cpuid][i].eq_gen = XIVE_EQ_GEN_MASK;
221fcf94dc6Skettenis }
2221af8fcf9Skettenis }
2231af8fcf9Skettenis
2241af8fcf9Skettenis /* There can be only one. */
2251af8fcf9Skettenis KASSERT(xive_sc == NULL);
2261af8fcf9Skettenis xive_sc = sc;
2271af8fcf9Skettenis
2281af8fcf9Skettenis _hvi = xive_hvi;
2291af8fcf9Skettenis _intr_establish = xive_intr_establish;
230fcf94dc6Skettenis _intr_send_ipi = xive_intr_send_ipi;
2311af8fcf9Skettenis _setipl = xive_setipl;
2321af8fcf9Skettenis
2331af8fcf9Skettenis /* Synchronize hardware state to software state. */
2341e897c56Skettenis xive_write_1(sc, XIVE_TM_CPPR_HV, xive_prio(curcpu()->ci_cpl));
23577005140Skettenis eieio();
2361af8fcf9Skettenis }
2371af8fcf9Skettenis
2388c64a04eSkettenis int
xive_activate(struct device * self,int act)2398c64a04eSkettenis xive_activate(struct device *self, int act)
2408c64a04eSkettenis {
2418c64a04eSkettenis switch (act) {
2428c64a04eSkettenis case DVACT_POWERDOWN:
2438c64a04eSkettenis opal_xive_reset(OPAL_XIVE_MODE_EMU);
2448c64a04eSkettenis break;
2458c64a04eSkettenis }
2468c64a04eSkettenis
2478c64a04eSkettenis return 0;
2488c64a04eSkettenis }
2498c64a04eSkettenis
2501af8fcf9Skettenis void *
xive_intr_establish(uint32_t girq,int type,int level,struct cpu_info * ci,int (* func)(void *),void * arg,const char * name)251a940e3deSkettenis xive_intr_establish(uint32_t girq, int type, int level, struct cpu_info *ci,
2521af8fcf9Skettenis int (*func)(void *), void *arg, const char *name)
2531af8fcf9Skettenis {
2541af8fcf9Skettenis struct xive_softc *sc = xive_sc;
2551af8fcf9Skettenis struct intrhand *ih;
2561af8fcf9Skettenis bus_space_handle_t eoi, trig;
2571af8fcf9Skettenis bus_size_t page_size;
2581af8fcf9Skettenis uint64_t flags, eoi_page, trig_page;
2591af8fcf9Skettenis uint32_t esb_shift, lirq;
2601af8fcf9Skettenis int64_t error;
2611af8fcf9Skettenis
262a4fe4c27Skettenis if (ci == NULL)
263a4fe4c27Skettenis ci = cpu_info_primary;
264a4fe4c27Skettenis
2651af8fcf9Skettenis /* Allocate a logical IRQ. */
2661af8fcf9Skettenis if (sc->sc_lirq >= XIVE_NUM_IRQS)
2671af8fcf9Skettenis return NULL;
2681af8fcf9Skettenis lirq = sc->sc_lirq++;
2691af8fcf9Skettenis
2700d8e59b5Skettenis error = opal_xive_get_irq_info(girq, opal_phys(&flags),
2710d8e59b5Skettenis opal_phys(&eoi_page), opal_phys(&trig_page),
2720d8e59b5Skettenis opal_phys(&esb_shift), NULL);
2731af8fcf9Skettenis if (error != OPAL_SUCCESS)
2741af8fcf9Skettenis return NULL;
2751af8fcf9Skettenis page_size = 1 << esb_shift;
2761af8fcf9Skettenis
2771af8fcf9Skettenis /* Map EOI page. */
2781af8fcf9Skettenis if (bus_space_map(sc->sc_iot, eoi_page, page_size, 0, &eoi))
2791af8fcf9Skettenis return NULL;
2801af8fcf9Skettenis
2811af8fcf9Skettenis /* Map trigger page. */
2821af8fcf9Skettenis if (trig_page == eoi_page)
2831af8fcf9Skettenis trig = eoi;
2841af8fcf9Skettenis else if (trig_page == 0)
2851af8fcf9Skettenis trig = 0;
2861af8fcf9Skettenis else if (bus_space_map(sc->sc_iot, trig_page, page_size, 0, &trig)) {
2871af8fcf9Skettenis bus_space_unmap(sc->sc_iot, trig, page_size);
2881af8fcf9Skettenis return NULL;
2891af8fcf9Skettenis }
2901af8fcf9Skettenis
291a940e3deSkettenis error = opal_xive_set_irq_config(girq, ci->ci_pir,
2921af8fcf9Skettenis xive_prio(level & IPL_IRQMASK), lirq);
2931af8fcf9Skettenis if (error != OPAL_SUCCESS) {
2941af8fcf9Skettenis if (trig != eoi && trig != 0)
2951af8fcf9Skettenis bus_space_unmap(sc->sc_iot, trig, page_size);
2961af8fcf9Skettenis bus_space_unmap(sc->sc_iot, eoi, page_size);
2971af8fcf9Skettenis return NULL;
2981af8fcf9Skettenis }
2991af8fcf9Skettenis
3001af8fcf9Skettenis ih = malloc(sizeof(*ih), M_DEVBUF, M_WAITOK);
3011af8fcf9Skettenis ih->ih_func = func;
3021af8fcf9Skettenis ih->ih_arg = arg;
3031af8fcf9Skettenis ih->ih_ipl = level & IPL_IRQMASK;
3041af8fcf9Skettenis ih->ih_flags = level & IPL_FLAGMASK;
3051af8fcf9Skettenis ih->ih_girq = girq;
3061af8fcf9Skettenis ih->ih_name = name;
3071af8fcf9Skettenis ih->ih_esb_eoi = eoi;
3081af8fcf9Skettenis ih->ih_esb_trig = trig;
3091af8fcf9Skettenis ih->ih_xive_flags = flags;
3101af8fcf9Skettenis sc->sc_handler[lirq] = ih;
3113e2fcfc8Skettenis
312812e8c63Skettenis if (name != NULL)
313812e8c63Skettenis evcount_attach(&ih->ih_count, name, &ih->ih_girq);
314812e8c63Skettenis
3153e2fcfc8Skettenis xive_unmask(sc, ih);
3163e2fcfc8Skettenis
3171af8fcf9Skettenis return ih;
3181af8fcf9Skettenis }
3191af8fcf9Skettenis
3201af8fcf9Skettenis void
xive_intr_send_ipi(void * cookie)321fcf94dc6Skettenis xive_intr_send_ipi(void *cookie)
322fcf94dc6Skettenis {
323fcf94dc6Skettenis struct xive_softc *sc = xive_sc;
324fcf94dc6Skettenis struct intrhand *ih = cookie;
325fcf94dc6Skettenis
326fcf94dc6Skettenis if (ih && ih->ih_esb_trig)
327fcf94dc6Skettenis bus_space_write_8(sc->sc_iot, ih->ih_esb_trig,
328fcf94dc6Skettenis XIVE_ESB_STORE_TRIGGER, 0);
329fcf94dc6Skettenis }
330fcf94dc6Skettenis
331fcf94dc6Skettenis void
xive_eoi(struct xive_softc * sc,struct intrhand * ih)3321af8fcf9Skettenis xive_eoi(struct xive_softc *sc, struct intrhand *ih)
3331af8fcf9Skettenis {
3341af8fcf9Skettenis uint64_t eoi;
3351af8fcf9Skettenis
3363e2fcfc8Skettenis if (ih->ih_xive_flags & OPAL_XIVE_IRQ_STORE_EOI) {
3373e2fcfc8Skettenis bus_space_write_8(sc->sc_iot, ih->ih_esb_eoi,
3383e2fcfc8Skettenis XIVE_ESB_STORE_EOI, 0);
3393e2fcfc8Skettenis } else if (ih->ih_xive_flags & OPAL_XIVE_IRQ_LSI) {
3403e2fcfc8Skettenis eoi = bus_space_read_8(sc->sc_iot, ih->ih_esb_eoi,
3413e2fcfc8Skettenis XIVE_ESB_LOAD_EOI);
3423e2fcfc8Skettenis } else {
3433e2fcfc8Skettenis eoi = bus_space_read_8(sc->sc_iot, ih->ih_esb_eoi,
3443e2fcfc8Skettenis XIVE_ESB_SET_PQ_00);
3451af8fcf9Skettenis if ((eoi & XIVE_ESB_VAL_Q) && ih->ih_esb_trig != 0)
3461af8fcf9Skettenis bus_space_write_8(sc->sc_iot, ih->ih_esb_trig,
3471af8fcf9Skettenis XIVE_ESB_STORE_TRIGGER, 0);
3481af8fcf9Skettenis }
3493e2fcfc8Skettenis }
3501af8fcf9Skettenis
3511af8fcf9Skettenis void
xive_setipl(int new)3521af8fcf9Skettenis xive_setipl(int new)
3531af8fcf9Skettenis {
3541af8fcf9Skettenis struct xive_softc *sc = xive_sc;
3551af8fcf9Skettenis struct cpu_info *ci = curcpu();
3561af8fcf9Skettenis uint8_t oldprio = xive_prio(ci->ci_cpl);
3571af8fcf9Skettenis uint8_t newprio = xive_prio(new);
3581af8fcf9Skettenis u_long msr;
3591af8fcf9Skettenis
3601af8fcf9Skettenis msr = intr_disable();
3611af8fcf9Skettenis ci->ci_cpl = new;
36277005140Skettenis if (newprio != oldprio) {
3631af8fcf9Skettenis xive_write_1(sc, XIVE_TM_CPPR_HV, newprio);
36477005140Skettenis eieio();
36577005140Skettenis }
3661af8fcf9Skettenis intr_restore(msr);
3671af8fcf9Skettenis }
3681af8fcf9Skettenis
3691af8fcf9Skettenis void
xive_run_handler(struct intrhand * ih)37004be1c60Skettenis xive_run_handler(struct intrhand *ih)
37104be1c60Skettenis {
37204be1c60Skettenis int handled;
37304be1c60Skettenis
37404be1c60Skettenis #ifdef MULTIPROCESSOR
37504be1c60Skettenis int need_lock;
37604be1c60Skettenis
37704be1c60Skettenis if (ih->ih_flags & IPL_MPSAFE)
37804be1c60Skettenis need_lock = 0;
37904be1c60Skettenis else
38004be1c60Skettenis need_lock = (ih->ih_ipl < IPL_SCHED);
38104be1c60Skettenis
38204be1c60Skettenis if (need_lock)
38304be1c60Skettenis KERNEL_LOCK();
38404be1c60Skettenis #endif
38504be1c60Skettenis handled = ih->ih_func(ih->ih_arg);
38604be1c60Skettenis if (handled)
38704be1c60Skettenis ih->ih_count.ec_count++;
38804be1c60Skettenis #ifdef MULTIPROCESSOR
38904be1c60Skettenis if (need_lock)
39004be1c60Skettenis KERNEL_UNLOCK();
39104be1c60Skettenis #endif
39204be1c60Skettenis }
39304be1c60Skettenis
39404be1c60Skettenis void
xive_hvi(struct trapframe * frame)3951af8fcf9Skettenis xive_hvi(struct trapframe *frame)
3961af8fcf9Skettenis {
3971af8fcf9Skettenis struct xive_softc *sc = xive_sc;
3981af8fcf9Skettenis struct cpu_info *ci = curcpu();
3991af8fcf9Skettenis struct intrhand *ih;
4001af8fcf9Skettenis struct xive_eq *eq;
4011af8fcf9Skettenis uint32_t *event;
4021af8fcf9Skettenis uint32_t lirq;
4031af8fcf9Skettenis int old, new;
4041af8fcf9Skettenis uint16_t ack, he;
4051af8fcf9Skettenis uint8_t cppr;
4061af8fcf9Skettenis
4071af8fcf9Skettenis old = ci->ci_cpl;
4081af8fcf9Skettenis
4091af8fcf9Skettenis while (1) {
4101af8fcf9Skettenis ack = xive_read_2(sc, XIVE_TM_SPC_ACK_HV);
4111af8fcf9Skettenis
4121af8fcf9Skettenis he = (ack & XIVE_TM_SPC_ACK_HE_MASK);
4131af8fcf9Skettenis if (he == XIVE_TM_SPC_ACK_HE_NONE)
4141af8fcf9Skettenis break;
4151af8fcf9Skettenis KASSERT(he == XIVE_TM_SPC_ACK_HE_PHYS);
4161af8fcf9Skettenis
4171af8fcf9Skettenis eieio();
4181af8fcf9Skettenis
419ba36e0ccSkettenis /* Synchronize software state to hardware state. */
420ba36e0ccSkettenis cppr = ack;
421ba36e0ccSkettenis new = xive_ipl(cppr);
4220c5cb021Skettenis if (new <= old) {
4230c5cb021Skettenis /*
4240c5cb021Skettenis * QEMU generates spurious interrupts. It is
4250c5cb021Skettenis * unclear whether this can happen on real
4260c5cb021Skettenis * hardware as well. We just ignore the
4270c5cb021Skettenis * interrupt, but we need to reset the CPPR
4280c5cb021Skettenis * register since we did accept the interrupt.
4290c5cb021Skettenis */
4300c5cb021Skettenis goto spurious;
4310c5cb021Skettenis }
432ba36e0ccSkettenis ci->ci_cpl = new;
433ba36e0ccSkettenis
4341af8fcf9Skettenis KASSERT(cppr < XIVE_NUM_PRIORITIES);
435fcf94dc6Skettenis eq = &sc->sc_eq[ci->ci_cpuid][cppr];
4361af8fcf9Skettenis event = XIVE_DMA_KVA(eq->eq_queue);
4371af8fcf9Skettenis while ((event[eq->eq_idx] & XIVE_EQ_GEN_MASK) == eq->eq_gen) {
4381af8fcf9Skettenis lirq = event[eq->eq_idx] & ~XIVE_EQ_GEN_MASK;
4391af8fcf9Skettenis KASSERT(lirq < XIVE_NUM_IRQS);
4401af8fcf9Skettenis ih = sc->sc_handler[lirq];
4411af8fcf9Skettenis if (ih != NULL) {
4421af8fcf9Skettenis intr_enable();
44304be1c60Skettenis xive_run_handler(ih);
4441af8fcf9Skettenis intr_disable();
4451af8fcf9Skettenis xive_eoi(sc, ih);
4461af8fcf9Skettenis }
4471af8fcf9Skettenis eq->eq_idx = (eq->eq_idx + 1) & XIVE_EQ_IDX_MASK;
4481af8fcf9Skettenis
4491af8fcf9Skettenis /* Toggle generation on wrap around. */
4501af8fcf9Skettenis if (eq->eq_idx == 0)
4511af8fcf9Skettenis eq->eq_gen ^= XIVE_EQ_GEN_MASK;
4521af8fcf9Skettenis }
4531af8fcf9Skettenis
4541af8fcf9Skettenis ci->ci_cpl = old;
4550c5cb021Skettenis spurious:
4561af8fcf9Skettenis xive_write_1(sc, XIVE_TM_CPPR_HV, xive_prio(old));
457ba36e0ccSkettenis eieio();
458ba36e0ccSkettenis }
4591af8fcf9Skettenis }
4601af8fcf9Skettenis
4611af8fcf9Skettenis struct xive_dmamem *
xive_dmamem_alloc(bus_dma_tag_t dmat,bus_size_t size,bus_size_t align)4621af8fcf9Skettenis xive_dmamem_alloc(bus_dma_tag_t dmat, bus_size_t size, bus_size_t align)
4631af8fcf9Skettenis {
4641af8fcf9Skettenis struct xive_dmamem *xdm;
4651af8fcf9Skettenis int nsegs;
4661af8fcf9Skettenis
4671af8fcf9Skettenis xdm = malloc(sizeof(*xdm), M_DEVBUF, M_WAITOK | M_ZERO);
4681af8fcf9Skettenis xdm->xdm_size = size;
4691af8fcf9Skettenis
4701af8fcf9Skettenis if (bus_dmamap_create(dmat, size, 1, size, 0,
4711af8fcf9Skettenis BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW, &xdm->xdm_map) != 0)
4721af8fcf9Skettenis goto xdmfree;
4731af8fcf9Skettenis
4741af8fcf9Skettenis if (bus_dmamem_alloc(dmat, size, align, 0, &xdm->xdm_seg, 1,
4751af8fcf9Skettenis &nsegs, BUS_DMA_WAITOK | BUS_DMA_ZERO) != 0)
4761af8fcf9Skettenis goto destroy;
4771af8fcf9Skettenis
4781af8fcf9Skettenis if (bus_dmamem_map(dmat, &xdm->xdm_seg, nsegs, size,
4791af8fcf9Skettenis &xdm->xdm_kva, BUS_DMA_WAITOK | BUS_DMA_NOCACHE) != 0)
4801af8fcf9Skettenis goto free;
4811af8fcf9Skettenis
4821af8fcf9Skettenis if (bus_dmamap_load_raw(dmat, xdm->xdm_map, &xdm->xdm_seg,
4831af8fcf9Skettenis nsegs, size, BUS_DMA_WAITOK) != 0)
4841af8fcf9Skettenis goto unmap;
4851af8fcf9Skettenis
4861af8fcf9Skettenis return xdm;
4871af8fcf9Skettenis
4881af8fcf9Skettenis unmap:
4891af8fcf9Skettenis bus_dmamem_unmap(dmat, xdm->xdm_kva, size);
4901af8fcf9Skettenis free:
4911af8fcf9Skettenis bus_dmamem_free(dmat, &xdm->xdm_seg, 1);
4921af8fcf9Skettenis destroy:
4931af8fcf9Skettenis bus_dmamap_destroy(dmat, xdm->xdm_map);
4941af8fcf9Skettenis xdmfree:
4951af8fcf9Skettenis free(xdm, M_DEVBUF, sizeof(*xdm));
4961af8fcf9Skettenis
4971af8fcf9Skettenis return NULL;
4981af8fcf9Skettenis }
4991af8fcf9Skettenis
5001af8fcf9Skettenis void
xive_dmamem_free(bus_dma_tag_t dmat,struct xive_dmamem * xdm)5011af8fcf9Skettenis xive_dmamem_free(bus_dma_tag_t dmat, struct xive_dmamem *xdm)
5021af8fcf9Skettenis {
5031af8fcf9Skettenis bus_dmamem_unmap(dmat, xdm->xdm_kva, xdm->xdm_size);
5041af8fcf9Skettenis bus_dmamem_free(dmat, &xdm->xdm_seg, 1);
5051af8fcf9Skettenis bus_dmamap_destroy(dmat, xdm->xdm_map);
5061af8fcf9Skettenis free(xdm, M_DEVBUF, sizeof(*xdm));
5071af8fcf9Skettenis }
508