xref: /openbsd-src/sys/arch/powerpc64/dev/xive.c (revision 471aeecfc619bc9b69519928152daf993376c2a1)
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