xref: /freebsd/sys/powerpc/powernv/xive.c (revision 685dc743dc3b5645e34836464128e1c0558b404b)
1d49fc192SJustin Hibbits /*-
2*4d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
3d49fc192SJustin Hibbits  *
4d49fc192SJustin Hibbits  * Copyright 2019 Justin Hibbits
5d49fc192SJustin Hibbits  *
6d49fc192SJustin Hibbits  * Redistribution and use in source and binary forms, with or without
7d49fc192SJustin Hibbits  * modification, are permitted provided that the following conditions
8d49fc192SJustin Hibbits  * are met:
9d49fc192SJustin Hibbits  * 1. Redistributions of source code must retain the above copyright
10d49fc192SJustin Hibbits  *    notice, this list of conditions and the following disclaimer.
11d49fc192SJustin Hibbits  * 2. Redistributions in binary form must reproduce the above copyright
12d49fc192SJustin Hibbits  *    notice, this list of conditions and the following disclaimer in the
13d49fc192SJustin Hibbits  *    documentation and/or other materials provided with the distribution.
14d49fc192SJustin Hibbits  *
15d49fc192SJustin Hibbits  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16d49fc192SJustin Hibbits  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17d49fc192SJustin Hibbits  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18d49fc192SJustin Hibbits  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19d49fc192SJustin Hibbits  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
20d49fc192SJustin Hibbits  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21d49fc192SJustin Hibbits  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
22d49fc192SJustin Hibbits  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23d49fc192SJustin Hibbits  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24d49fc192SJustin Hibbits  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25d49fc192SJustin Hibbits  * SUCH DAMAGE.
26d49fc192SJustin Hibbits  */
27d49fc192SJustin Hibbits 
28d49fc192SJustin Hibbits #include <sys/cdefs.h>
29d49fc192SJustin Hibbits #include "opt_platform.h"
30d49fc192SJustin Hibbits 
31d49fc192SJustin Hibbits #include <sys/param.h>
32d49fc192SJustin Hibbits #include <sys/systm.h>
33d49fc192SJustin Hibbits #include <sys/module.h>
34d49fc192SJustin Hibbits #include <sys/bus.h>
35d49fc192SJustin Hibbits #include <sys/conf.h>
36d49fc192SJustin Hibbits #include <sys/endian.h>
37d49fc192SJustin Hibbits #include <sys/kernel.h>
38e2e050c8SConrad Meyer #include <sys/lock.h>
39d49fc192SJustin Hibbits #include <sys/malloc.h>
40e2e050c8SConrad Meyer #include <sys/mutex.h>
41d49fc192SJustin Hibbits #include <sys/smp.h>
42d49fc192SJustin Hibbits 
43d49fc192SJustin Hibbits #include <vm/vm.h>
44d49fc192SJustin Hibbits #include <vm/pmap.h>
45d49fc192SJustin Hibbits 
46d49fc192SJustin Hibbits #include <machine/bus.h>
47d49fc192SJustin Hibbits #include <machine/intr_machdep.h>
48d49fc192SJustin Hibbits #include <machine/md_var.h>
49d49fc192SJustin Hibbits 
50d49fc192SJustin Hibbits #include <dev/ofw/ofw_bus.h>
51d49fc192SJustin Hibbits #include <dev/ofw/ofw_bus_subr.h>
52d49fc192SJustin Hibbits 
53d49fc192SJustin Hibbits #ifdef POWERNV
54d49fc192SJustin Hibbits #include <powerpc/powernv/opal.h>
55d49fc192SJustin Hibbits #endif
56d49fc192SJustin Hibbits 
57d49fc192SJustin Hibbits #include "pic_if.h"
58d49fc192SJustin Hibbits 
59d49fc192SJustin Hibbits #define XIVE_PRIORITY	7	/* Random non-zero number */
60d49fc192SJustin Hibbits #define MAX_XIVE_IRQS	(1<<24)	/* 24-bit XIRR field */
61d49fc192SJustin Hibbits 
62d49fc192SJustin Hibbits /* Registers */
63d49fc192SJustin Hibbits #define	XIVE_TM_QW1_OS		0x010	/* Guest OS registers */
64d49fc192SJustin Hibbits #define	XIVE_TM_QW2_HV_POOL	0x020	/* Hypervisor pool registers */
65d49fc192SJustin Hibbits #define	XIVE_TM_QW3_HV		0x030	/* Hypervisor registers */
66d49fc192SJustin Hibbits 
67d49fc192SJustin Hibbits #define	XIVE_TM_NSR	0x00
68d49fc192SJustin Hibbits #define	XIVE_TM_CPPR	0x01
69d49fc192SJustin Hibbits #define	XIVE_TM_IPB	0x02
70d49fc192SJustin Hibbits #define	XIVE_TM_LSMFB	0x03
71d49fc192SJustin Hibbits #define	XIVE_TM_ACK_CNT	0x04
72d49fc192SJustin Hibbits #define	XIVE_TM_INC	0x05
73d49fc192SJustin Hibbits #define	XIVE_TM_AGE	0x06
74d49fc192SJustin Hibbits #define	XIVE_TM_PIPR	0x07
75d49fc192SJustin Hibbits 
76d49fc192SJustin Hibbits #define	TM_WORD0	0x0
77d49fc192SJustin Hibbits #define	TM_WORD2	0x8
78d49fc192SJustin Hibbits #define	  TM_QW2W2_VP	  0x80000000
79d49fc192SJustin Hibbits 
80d49fc192SJustin Hibbits #define	XIVE_TM_SPC_ACK			0x800
81d49fc192SJustin Hibbits #define	  TM_QW3NSR_HE_SHIFT		  14
82d49fc192SJustin Hibbits #define	  TM_QW3_NSR_HE_NONE		  0
83d49fc192SJustin Hibbits #define	  TM_QW3_NSR_HE_POOL		  1
84d49fc192SJustin Hibbits #define	  TM_QW3_NSR_HE_PHYS		  2
85d49fc192SJustin Hibbits #define	  TM_QW3_NSR_HE_LSI		  3
86d49fc192SJustin Hibbits #define	XIVE_TM_SPC_PULL_POOL_CTX	0x828
87d49fc192SJustin Hibbits 
88d49fc192SJustin Hibbits #define	XIVE_IRQ_LOAD_EOI	0x000
89d49fc192SJustin Hibbits #define	XIVE_IRQ_STORE_EOI	0x400
90d49fc192SJustin Hibbits #define	XIVE_IRQ_PQ_00		0xc00
91d49fc192SJustin Hibbits #define	XIVE_IRQ_PQ_01		0xd00
92d49fc192SJustin Hibbits 
93d49fc192SJustin Hibbits #define	XIVE_IRQ_VAL_P		0x02
94d49fc192SJustin Hibbits #define	XIVE_IRQ_VAL_Q		0x01
95d49fc192SJustin Hibbits 
96d49fc192SJustin Hibbits struct xive_softc;
97d49fc192SJustin Hibbits struct xive_irq;
98d49fc192SJustin Hibbits 
99d49fc192SJustin Hibbits extern void (*powernv_smp_ap_extra_init)(void);
100d49fc192SJustin Hibbits 
101d49fc192SJustin Hibbits /* Private support */
102d49fc192SJustin Hibbits static void	xive_setup_cpu(void);
103d49fc192SJustin Hibbits static void	xive_smp_cpu_startup(void);
104d49fc192SJustin Hibbits static void	xive_init_irq(struct xive_irq *irqd, u_int irq);
105d49fc192SJustin Hibbits static struct xive_irq	*xive_configure_irq(u_int irq);
106d49fc192SJustin Hibbits static int	xive_provision_page(struct xive_softc *sc);
107d49fc192SJustin Hibbits 
108d49fc192SJustin Hibbits /* Interfaces */
109d49fc192SJustin Hibbits static int	xive_probe(device_t);
110d49fc192SJustin Hibbits static int	xive_attach(device_t);
111d49fc192SJustin Hibbits static int	xics_probe(device_t);
112d49fc192SJustin Hibbits static int	xics_attach(device_t);
113d49fc192SJustin Hibbits 
114d49fc192SJustin Hibbits static void	xive_bind(device_t, u_int, cpuset_t, void **);
115d49fc192SJustin Hibbits static void	xive_dispatch(device_t, struct trapframe *);
116d49fc192SJustin Hibbits static void	xive_enable(device_t, u_int, u_int, void **);
117d49fc192SJustin Hibbits static void	xive_eoi(device_t, u_int, void *);
118d49fc192SJustin Hibbits static void	xive_ipi(device_t, u_int);
119d49fc192SJustin Hibbits static void	xive_mask(device_t, u_int, void *);
120d49fc192SJustin Hibbits static void	xive_unmask(device_t, u_int, void *);
121d49fc192SJustin Hibbits static void	xive_translate_code(device_t dev, u_int irq, int code,
122d49fc192SJustin Hibbits 		    enum intr_trigger *trig, enum intr_polarity *pol);
123d49fc192SJustin Hibbits 
124d49fc192SJustin Hibbits static device_method_t  xive_methods[] = {
125d49fc192SJustin Hibbits 	/* Device interface */
126d49fc192SJustin Hibbits 	DEVMETHOD(device_probe,		xive_probe),
127d49fc192SJustin Hibbits 	DEVMETHOD(device_attach,	xive_attach),
128d49fc192SJustin Hibbits 
129d49fc192SJustin Hibbits 	/* PIC interface */
130d49fc192SJustin Hibbits 	DEVMETHOD(pic_bind,		xive_bind),
131d49fc192SJustin Hibbits 	DEVMETHOD(pic_dispatch,		xive_dispatch),
132d49fc192SJustin Hibbits 	DEVMETHOD(pic_enable,		xive_enable),
133d49fc192SJustin Hibbits 	DEVMETHOD(pic_eoi,		xive_eoi),
134d49fc192SJustin Hibbits 	DEVMETHOD(pic_ipi,		xive_ipi),
135d49fc192SJustin Hibbits 	DEVMETHOD(pic_mask,		xive_mask),
136d49fc192SJustin Hibbits 	DEVMETHOD(pic_unmask,		xive_unmask),
137d49fc192SJustin Hibbits 	DEVMETHOD(pic_translate_code,	xive_translate_code),
138d49fc192SJustin Hibbits 
139d49fc192SJustin Hibbits 	DEVMETHOD_END
140d49fc192SJustin Hibbits };
141d49fc192SJustin Hibbits 
142d49fc192SJustin Hibbits static device_method_t  xics_methods[] = {
143d49fc192SJustin Hibbits 	/* Device interface */
144d49fc192SJustin Hibbits 	DEVMETHOD(device_probe,		xics_probe),
145d49fc192SJustin Hibbits 	DEVMETHOD(device_attach,	xics_attach),
146d49fc192SJustin Hibbits 
147d49fc192SJustin Hibbits 	DEVMETHOD_END
148d49fc192SJustin Hibbits };
149d49fc192SJustin Hibbits 
150d49fc192SJustin Hibbits struct xive_softc {
151d49fc192SJustin Hibbits 	struct mtx sc_mtx;
152d49fc192SJustin Hibbits 	struct resource *sc_mem;
153d49fc192SJustin Hibbits 	vm_size_t	sc_prov_page_size;
154d49fc192SJustin Hibbits 	uint32_t	sc_offset;
155d49fc192SJustin Hibbits };
156d49fc192SJustin Hibbits 
157d49fc192SJustin Hibbits struct xive_queue {
158d49fc192SJustin Hibbits 	uint32_t	*q_page;
159d49fc192SJustin Hibbits 	uint32_t	*q_eoi_page;
160d49fc192SJustin Hibbits 	uint32_t	 q_toggle;
161d49fc192SJustin Hibbits 	uint32_t	 q_size;
162d49fc192SJustin Hibbits 	uint32_t	 q_index;
163d49fc192SJustin Hibbits 	uint32_t	 q_mask;
164d49fc192SJustin Hibbits };
165d49fc192SJustin Hibbits 
166d49fc192SJustin Hibbits struct xive_irq {
167d49fc192SJustin Hibbits 	uint32_t	girq;
168d49fc192SJustin Hibbits 	uint32_t	lirq;
169d49fc192SJustin Hibbits 	uint64_t	vp;
170d49fc192SJustin Hibbits 	uint64_t	flags;
171d49fc192SJustin Hibbits #define	OPAL_XIVE_IRQ_SHIFT_BUG		0x00000008
172d49fc192SJustin Hibbits #define	OPAL_XIVE_IRQ_LSI		0x00000004
173d49fc192SJustin Hibbits #define	OPAL_XIVE_IRQ_STORE_EOI		0x00000002
174d49fc192SJustin Hibbits #define	OPAL_XIVE_IRQ_TRIGGER_PAGE	0x00000001
175d49fc192SJustin Hibbits 	uint8_t	prio;
176d49fc192SJustin Hibbits 	vm_offset_t	eoi_page;
177d49fc192SJustin Hibbits 	vm_offset_t	trig_page;
178d49fc192SJustin Hibbits 	vm_size_t	esb_size;
179d49fc192SJustin Hibbits 	int		chip;
180d49fc192SJustin Hibbits };
181d49fc192SJustin Hibbits 
182d49fc192SJustin Hibbits struct xive_cpu {
183d49fc192SJustin Hibbits 	uint64_t	vp;
184d49fc192SJustin Hibbits 	uint64_t	flags;
185d49fc192SJustin Hibbits 	struct xive_irq	ipi_data;
186d49fc192SJustin Hibbits 	struct xive_queue	queue; /* We only use a single queue for now. */
187d49fc192SJustin Hibbits 	uint64_t	cam;
188d49fc192SJustin Hibbits 	uint32_t	chip;
189d49fc192SJustin Hibbits };
190d49fc192SJustin Hibbits 
191d49fc192SJustin Hibbits static driver_t xive_driver = {
192d49fc192SJustin Hibbits 	"xive",
193d49fc192SJustin Hibbits 	xive_methods,
194d49fc192SJustin Hibbits 	sizeof(struct xive_softc)
195d49fc192SJustin Hibbits };
196d49fc192SJustin Hibbits 
197d49fc192SJustin Hibbits static driver_t xics_driver = {
198d49fc192SJustin Hibbits 	"xivevc",
199d49fc192SJustin Hibbits 	xics_methods,
200d49fc192SJustin Hibbits 	0
201d49fc192SJustin Hibbits };
202d49fc192SJustin Hibbits 
2035edf159fSJohn Baldwin EARLY_DRIVER_MODULE(xive, ofwbus, xive_driver, 0, 0, BUS_PASS_INTERRUPT - 1);
2045edf159fSJohn Baldwin EARLY_DRIVER_MODULE(xivevc, ofwbus, xics_driver, 0, 0, BUS_PASS_INTERRUPT);
205d49fc192SJustin Hibbits 
206d49fc192SJustin Hibbits MALLOC_DEFINE(M_XIVE, "xive", "XIVE Memory");
207d49fc192SJustin Hibbits 
208d49fc192SJustin Hibbits DPCPU_DEFINE_STATIC(struct xive_cpu, xive_cpu_data);
209d49fc192SJustin Hibbits 
210d49fc192SJustin Hibbits static int xive_ipi_vector = -1;
211d49fc192SJustin Hibbits 
212d49fc192SJustin Hibbits /*
213d49fc192SJustin Hibbits  * XIVE Exploitation mode driver.
214d49fc192SJustin Hibbits  *
215d49fc192SJustin Hibbits  * The XIVE, present in the POWER9 CPU, can run in two modes: XICS emulation
216d49fc192SJustin Hibbits  * mode, and "Exploitation mode".  XICS emulation mode is compatible with the
217d49fc192SJustin Hibbits  * POWER8 and earlier XICS interrupt controller, using OPAL calls to emulate
218d49fc192SJustin Hibbits  * hypervisor calls and memory accesses.  Exploitation mode gives us raw access
219d49fc192SJustin Hibbits  * to the XIVE MMIO, improving performance significantly.
220d49fc192SJustin Hibbits  *
221d49fc192SJustin Hibbits  * The XIVE controller is a very bizarre interrupt controller.  It uses queues
222d49fc192SJustin Hibbits  * in memory to pass interrupts around, and maps itself into 512GB of physical
223d49fc192SJustin Hibbits  * device address space, giving each interrupt in the system one or more pages
224d49fc192SJustin Hibbits  * of address space.  An IRQ is tied to a virtual processor, which could be a
225d49fc192SJustin Hibbits  * physical CPU thread, or a guest CPU thread (LPAR running on a physical
226d49fc192SJustin Hibbits  * thread).  Thus, the controller can route interrupts directly to guest OSes
227d49fc192SJustin Hibbits  * bypassing processing by the hypervisor, thereby improving performance of the
228d49fc192SJustin Hibbits  * guest OS.
229d49fc192SJustin Hibbits  *
230d49fc192SJustin Hibbits  * An IRQ, in addition to being tied to a virtual processor, has one or two
231d49fc192SJustin Hibbits  * page mappings: an EOI page, and an optional trigger page.  The trigger page
232d49fc192SJustin Hibbits  * could be the same as the EOI page.  Level-sensitive interrupts (LSIs) don't
233d49fc192SJustin Hibbits  * have a trigger page, as they're external interrupts controlled by physical
234d49fc192SJustin Hibbits  * lines.  MSIs and IPIs have trigger pages.  An IPI is really just another IRQ
235d49fc192SJustin Hibbits  * in the XIVE, which is triggered by software.
236d49fc192SJustin Hibbits  *
237d49fc192SJustin Hibbits  * An interesting behavior of the XIVE controller is that oftentimes the
238d49fc192SJustin Hibbits  * contents of an address location don't actually matter, but the direction of
239d49fc192SJustin Hibbits  * the action is the signifier (read vs write), and the address is significant.
240d49fc192SJustin Hibbits  * Hence, masking and unmasking an interrupt is done by reading different
241d49fc192SJustin Hibbits  * addresses in the EOI page, and triggering an interrupt consists of writing to
242d49fc192SJustin Hibbits  * the trigger page.
243d49fc192SJustin Hibbits  *
244d49fc192SJustin Hibbits  * Additionally, the MMIO region mapped is CPU-sensitive, just like the
245d49fc192SJustin Hibbits  * per-processor register space (private access) in OpenPIC.  In order for a CPU
246d49fc192SJustin Hibbits  * to receive interrupts it must itself configure its CPPR (Current Processor
247d49fc192SJustin Hibbits  * Priority Register), it cannot be set by any other processor.  This
248d49fc192SJustin Hibbits  * necessitates the xive_smp_cpu_startup() function.
249d49fc192SJustin Hibbits  *
250d49fc192SJustin Hibbits  * Queues are pages of memory, sized powers-of-two, that are shared with the
251d49fc192SJustin Hibbits  * XIVE.  The XIVE writes into the queue with an alternating polarity bit, which
252d49fc192SJustin Hibbits  * flips when the queue wraps.
253d49fc192SJustin Hibbits  */
254d49fc192SJustin Hibbits 
255d49fc192SJustin Hibbits /*
256d49fc192SJustin Hibbits  * Offset-based read/write interfaces.
257d49fc192SJustin Hibbits  */
258d49fc192SJustin Hibbits static uint16_t
xive_read_2(struct xive_softc * sc,bus_size_t offset)259d49fc192SJustin Hibbits xive_read_2(struct xive_softc *sc, bus_size_t offset)
260d49fc192SJustin Hibbits {
261d49fc192SJustin Hibbits 
262d49fc192SJustin Hibbits 	return (bus_read_2(sc->sc_mem, sc->sc_offset + offset));
263d49fc192SJustin Hibbits }
264d49fc192SJustin Hibbits 
265d49fc192SJustin Hibbits static void
xive_write_1(struct xive_softc * sc,bus_size_t offset,uint8_t val)266d49fc192SJustin Hibbits xive_write_1(struct xive_softc *sc, bus_size_t offset, uint8_t val)
267d49fc192SJustin Hibbits {
268d49fc192SJustin Hibbits 
269d49fc192SJustin Hibbits 	bus_write_1(sc->sc_mem, sc->sc_offset + offset, val);
270d49fc192SJustin Hibbits }
271d49fc192SJustin Hibbits 
272d49fc192SJustin Hibbits /* EOI and Trigger page access interfaces. */
273d49fc192SJustin Hibbits static uint64_t
xive_read_mmap8(vm_offset_t addr)274d49fc192SJustin Hibbits xive_read_mmap8(vm_offset_t addr)
275d49fc192SJustin Hibbits {
276d49fc192SJustin Hibbits 	return (*(volatile uint64_t *)addr);
277d49fc192SJustin Hibbits }
278d49fc192SJustin Hibbits 
279d49fc192SJustin Hibbits static void
xive_write_mmap8(vm_offset_t addr,uint64_t val)280d49fc192SJustin Hibbits xive_write_mmap8(vm_offset_t addr, uint64_t val)
281d49fc192SJustin Hibbits {
282d49fc192SJustin Hibbits 	*(uint64_t *)(addr) = val;
283d49fc192SJustin Hibbits }
284d49fc192SJustin Hibbits 
285d49fc192SJustin Hibbits /* Device interfaces. */
286d49fc192SJustin Hibbits static int
xive_probe(device_t dev)287d49fc192SJustin Hibbits xive_probe(device_t dev)
288d49fc192SJustin Hibbits {
289d49fc192SJustin Hibbits 
290d49fc192SJustin Hibbits 	if (!ofw_bus_is_compatible(dev, "ibm,opal-xive-pe"))
291d49fc192SJustin Hibbits 		return (ENXIO);
292d49fc192SJustin Hibbits 
293d49fc192SJustin Hibbits 	device_set_desc(dev, "External Interrupt Virtualization Engine");
294d49fc192SJustin Hibbits 
295d49fc192SJustin Hibbits 	/* Make sure we always win against the xicp driver. */
296d49fc192SJustin Hibbits 	return (BUS_PROBE_DEFAULT);
297d49fc192SJustin Hibbits }
298d49fc192SJustin Hibbits 
299d49fc192SJustin Hibbits static int
xics_probe(device_t dev)300d49fc192SJustin Hibbits xics_probe(device_t dev)
301d49fc192SJustin Hibbits {
302d49fc192SJustin Hibbits 
303d49fc192SJustin Hibbits 	if (!ofw_bus_is_compatible(dev, "ibm,opal-xive-vc"))
304d49fc192SJustin Hibbits 		return (ENXIO);
305d49fc192SJustin Hibbits 
306d49fc192SJustin Hibbits 	device_set_desc(dev, "External Interrupt Virtualization Engine Root");
307d49fc192SJustin Hibbits 	return (BUS_PROBE_DEFAULT);
308d49fc192SJustin Hibbits }
309d49fc192SJustin Hibbits 
310d49fc192SJustin Hibbits static int
xive_attach(device_t dev)311d49fc192SJustin Hibbits xive_attach(device_t dev)
312d49fc192SJustin Hibbits {
313d49fc192SJustin Hibbits 	struct xive_softc *sc = device_get_softc(dev);
314d49fc192SJustin Hibbits 	struct xive_cpu *xive_cpud;
315d49fc192SJustin Hibbits 	phandle_t phandle = ofw_bus_get_node(dev);
316d49fc192SJustin Hibbits 	int64_t vp_block;
317d49fc192SJustin Hibbits 	int error;
318d49fc192SJustin Hibbits 	int rid;
319d49fc192SJustin Hibbits 	int i, order;
320d49fc192SJustin Hibbits 	uint64_t vp_id;
321d49fc192SJustin Hibbits 	int64_t ipi_irq;
322d49fc192SJustin Hibbits 
323d49fc192SJustin Hibbits 	opal_call(OPAL_XIVE_RESET, OPAL_XIVE_XICS_MODE_EXP);
324d49fc192SJustin Hibbits 
325d49fc192SJustin Hibbits 	error = OF_getencprop(phandle, "ibm,xive-provision-page-size",
326d49fc192SJustin Hibbits 	    (pcell_t *)&sc->sc_prov_page_size, sizeof(sc->sc_prov_page_size));
327d49fc192SJustin Hibbits 
328d49fc192SJustin Hibbits 	rid = 1;	/* Get the Hypervisor-level register set. */
329d49fc192SJustin Hibbits 	sc->sc_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
330d49fc192SJustin Hibbits 	    &rid, RF_ACTIVE);
331d49fc192SJustin Hibbits 	sc->sc_offset = XIVE_TM_QW3_HV;
332d49fc192SJustin Hibbits 
333d49fc192SJustin Hibbits 	mtx_init(&sc->sc_mtx, "XIVE", NULL, MTX_DEF);
334d49fc192SJustin Hibbits 
33569576451SBrandon Bergren 	/* Workaround for qemu single-thread powernv */
33669576451SBrandon Bergren 	if (mp_maxid == 0)
33769576451SBrandon Bergren 		order = 1;
33869576451SBrandon Bergren 	else
339d49fc192SJustin Hibbits 		order = fls(mp_maxid + (mp_maxid - 1)) - 1;
340d49fc192SJustin Hibbits 
341d49fc192SJustin Hibbits 	do {
342d49fc192SJustin Hibbits 		vp_block = opal_call(OPAL_XIVE_ALLOCATE_VP_BLOCK, order);
343d49fc192SJustin Hibbits 		if (vp_block == OPAL_BUSY)
344d49fc192SJustin Hibbits 			DELAY(10);
345d49fc192SJustin Hibbits 		else if (vp_block == OPAL_XIVE_PROVISIONING)
346d49fc192SJustin Hibbits 			xive_provision_page(sc);
347d49fc192SJustin Hibbits 		else
348d49fc192SJustin Hibbits 			break;
349d49fc192SJustin Hibbits 	} while (1);
350d49fc192SJustin Hibbits 
351d49fc192SJustin Hibbits 	if (vp_block < 0) {
352d49fc192SJustin Hibbits 		device_printf(dev,
353d49fc192SJustin Hibbits 		    "Unable to allocate VP block.  Opal error %d\n",
354d49fc192SJustin Hibbits 		    (int)vp_block);
355d49fc192SJustin Hibbits 		bus_release_resource(dev, SYS_RES_MEMORY, rid, sc->sc_mem);
356d49fc192SJustin Hibbits 		return (ENXIO);
357d49fc192SJustin Hibbits 	}
358d49fc192SJustin Hibbits 
359d49fc192SJustin Hibbits 	/*
360d49fc192SJustin Hibbits 	 * Set up the VPs.  Try to do as much as we can in attach, to lessen
361d49fc192SJustin Hibbits 	 * what's needed at AP spawn time.
362d49fc192SJustin Hibbits 	 */
363d49fc192SJustin Hibbits 	CPU_FOREACH(i) {
364d49fc192SJustin Hibbits 		vp_id = pcpu_find(i)->pc_hwref;
365d49fc192SJustin Hibbits 
366d49fc192SJustin Hibbits 		xive_cpud = DPCPU_ID_PTR(i, xive_cpu_data);
367d49fc192SJustin Hibbits 		xive_cpud->vp = vp_id + vp_block;
368d49fc192SJustin Hibbits 		opal_call(OPAL_XIVE_GET_VP_INFO, xive_cpud->vp, NULL,
369d49fc192SJustin Hibbits 		    vtophys(&xive_cpud->cam), NULL, vtophys(&xive_cpud->chip));
370d49fc192SJustin Hibbits 
371f9acb7a8SBrandon Bergren 		xive_cpud->cam = be64toh(xive_cpud->cam);
372f9acb7a8SBrandon Bergren 		xive_cpud->chip = be64toh(xive_cpud->chip);
373f9acb7a8SBrandon Bergren 
374d49fc192SJustin Hibbits 		/* Allocate the queue page and populate the queue state data. */
375d49fc192SJustin Hibbits 		xive_cpud->queue.q_page = contigmalloc(PAGE_SIZE, M_XIVE,
376d49fc192SJustin Hibbits 		    M_ZERO | M_WAITOK, 0, BUS_SPACE_MAXADDR, PAGE_SIZE, 0);
377d49fc192SJustin Hibbits 		xive_cpud->queue.q_size = 1 << PAGE_SHIFT;
378d49fc192SJustin Hibbits 		xive_cpud->queue.q_mask =
379d49fc192SJustin Hibbits 		    ((xive_cpud->queue.q_size / sizeof(int)) - 1);
380d49fc192SJustin Hibbits 		xive_cpud->queue.q_toggle = 0;
381d49fc192SJustin Hibbits 		xive_cpud->queue.q_index = 0;
382d49fc192SJustin Hibbits 		do {
383d49fc192SJustin Hibbits 			error = opal_call(OPAL_XIVE_SET_VP_INFO, xive_cpud->vp,
384d49fc192SJustin Hibbits 			    OPAL_XIVE_VP_ENABLED, 0);
385d49fc192SJustin Hibbits 		} while (error == OPAL_BUSY);
386d49fc192SJustin Hibbits 		error = opal_call(OPAL_XIVE_SET_QUEUE_INFO, vp_id,
387d49fc192SJustin Hibbits 		    XIVE_PRIORITY, vtophys(xive_cpud->queue.q_page), PAGE_SHIFT,
388d49fc192SJustin Hibbits 		    OPAL_XIVE_EQ_ALWAYS_NOTIFY | OPAL_XIVE_EQ_ENABLED);
389d49fc192SJustin Hibbits 
390d49fc192SJustin Hibbits 		do {
391d49fc192SJustin Hibbits 			ipi_irq = opal_call(OPAL_XIVE_ALLOCATE_IRQ,
392d49fc192SJustin Hibbits 			    xive_cpud->chip);
393d49fc192SJustin Hibbits 		} while (ipi_irq == OPAL_BUSY);
394d49fc192SJustin Hibbits 
395d49fc192SJustin Hibbits 		if (ipi_irq < 0)
396d49fc192SJustin Hibbits 			device_printf(root_pic,
397d49fc192SJustin Hibbits 			    "Failed allocating IPI.  OPAL error %d\n",
398d49fc192SJustin Hibbits 			    (int)ipi_irq);
399d49fc192SJustin Hibbits 		else {
400d49fc192SJustin Hibbits 			xive_init_irq(&xive_cpud->ipi_data, ipi_irq);
401d49fc192SJustin Hibbits 			xive_cpud->ipi_data.vp = vp_id;
402d49fc192SJustin Hibbits 			xive_cpud->ipi_data.lirq = MAX_XIVE_IRQS;
403d49fc192SJustin Hibbits 			opal_call(OPAL_XIVE_SET_IRQ_CONFIG, ipi_irq,
404d49fc192SJustin Hibbits 			    xive_cpud->ipi_data.vp, XIVE_PRIORITY,
405d49fc192SJustin Hibbits 			    MAX_XIVE_IRQS);
406d49fc192SJustin Hibbits 		}
407d49fc192SJustin Hibbits 	}
408d49fc192SJustin Hibbits 
409d49fc192SJustin Hibbits 	powerpc_register_pic(dev, OF_xref_from_node(phandle), MAX_XIVE_IRQS,
410d49fc192SJustin Hibbits 	    1 /* Number of IPIs */, FALSE);
411d49fc192SJustin Hibbits 	root_pic = dev;
412d49fc192SJustin Hibbits 
413d49fc192SJustin Hibbits 	xive_setup_cpu();
414d49fc192SJustin Hibbits 	powernv_smp_ap_extra_init = xive_smp_cpu_startup;
415d49fc192SJustin Hibbits 
416d49fc192SJustin Hibbits 	return (0);
417d49fc192SJustin Hibbits }
418d49fc192SJustin Hibbits 
419d49fc192SJustin Hibbits static int
xics_attach(device_t dev)420d49fc192SJustin Hibbits xics_attach(device_t dev)
421d49fc192SJustin Hibbits {
422d49fc192SJustin Hibbits 	phandle_t phandle = ofw_bus_get_node(dev);
423d49fc192SJustin Hibbits 
424d49fc192SJustin Hibbits 	/* The XIVE (root PIC) will handle all our interrupts */
425d49fc192SJustin Hibbits 	powerpc_register_pic(root_pic, OF_xref_from_node(phandle),
426d49fc192SJustin Hibbits 	    MAX_XIVE_IRQS, 1 /* Number of IPIs */, FALSE);
427d49fc192SJustin Hibbits 
428d49fc192SJustin Hibbits 	return (0);
429d49fc192SJustin Hibbits }
430d49fc192SJustin Hibbits 
431d49fc192SJustin Hibbits /*
432d49fc192SJustin Hibbits  * PIC I/F methods.
433d49fc192SJustin Hibbits  */
434d49fc192SJustin Hibbits 
435d49fc192SJustin Hibbits static void
xive_bind(device_t dev,u_int irq,cpuset_t cpumask,void ** priv)436d49fc192SJustin Hibbits xive_bind(device_t dev, u_int irq, cpuset_t cpumask, void **priv)
437d49fc192SJustin Hibbits {
438d49fc192SJustin Hibbits 	struct xive_irq *irqd;
439d49fc192SJustin Hibbits 	int cpu;
440d49fc192SJustin Hibbits 	int ncpus, i, error;
441d49fc192SJustin Hibbits 
442d49fc192SJustin Hibbits 	if (*priv == NULL)
443d49fc192SJustin Hibbits 		*priv = xive_configure_irq(irq);
444d49fc192SJustin Hibbits 
445d49fc192SJustin Hibbits 	irqd = *priv;
446d49fc192SJustin Hibbits 
447d49fc192SJustin Hibbits 	/*
448d49fc192SJustin Hibbits 	 * This doesn't appear to actually support affinity groups, so pick a
449d49fc192SJustin Hibbits 	 * random CPU.
450d49fc192SJustin Hibbits 	 */
451d49fc192SJustin Hibbits 	ncpus = 0;
452d49fc192SJustin Hibbits 	CPU_FOREACH(cpu)
453d49fc192SJustin Hibbits 		if (CPU_ISSET(cpu, &cpumask)) ncpus++;
454d49fc192SJustin Hibbits 
455d49fc192SJustin Hibbits 	i = mftb() % ncpus;
456d49fc192SJustin Hibbits 	ncpus = 0;
457d49fc192SJustin Hibbits 	CPU_FOREACH(cpu) {
458d49fc192SJustin Hibbits 		if (!CPU_ISSET(cpu, &cpumask))
459d49fc192SJustin Hibbits 			continue;
460d49fc192SJustin Hibbits 		if (ncpus == i)
461d49fc192SJustin Hibbits 			break;
462d49fc192SJustin Hibbits 		ncpus++;
463d49fc192SJustin Hibbits 	}
464d49fc192SJustin Hibbits 
465b94b2fcdSBrandon Bergren 	opal_call(OPAL_XIVE_SYNC, OPAL_XIVE_SYNC_QUEUE, irq);
466d49fc192SJustin Hibbits 
467d49fc192SJustin Hibbits 	irqd->vp = pcpu_find(cpu)->pc_hwref;
468d49fc192SJustin Hibbits 	error = opal_call(OPAL_XIVE_SET_IRQ_CONFIG, irq, irqd->vp,
469d49fc192SJustin Hibbits 	    XIVE_PRIORITY, irqd->lirq);
470d49fc192SJustin Hibbits 
471d49fc192SJustin Hibbits 	if (error < 0)
472d49fc192SJustin Hibbits 		panic("Cannot bind interrupt %d to CPU %d", irq, cpu);
473d49fc192SJustin Hibbits 
474d49fc192SJustin Hibbits 	xive_eoi(dev, irq, irqd);
475d49fc192SJustin Hibbits }
476d49fc192SJustin Hibbits 
477d49fc192SJustin Hibbits /* Read the next entry in the queue page and update the index. */
478d49fc192SJustin Hibbits static int
xive_read_eq(struct xive_queue * q)479d49fc192SJustin Hibbits xive_read_eq(struct xive_queue *q)
480d49fc192SJustin Hibbits {
481d49fc192SJustin Hibbits 	uint32_t i = be32toh(q->q_page[q->q_index]);
482d49fc192SJustin Hibbits 
483d49fc192SJustin Hibbits 	/* Check validity, using current queue polarity. */
484d49fc192SJustin Hibbits 	if ((i >> 31) == q->q_toggle)
485d49fc192SJustin Hibbits 		return (0);
486d49fc192SJustin Hibbits 
487d49fc192SJustin Hibbits 	q->q_index = (q->q_index + 1) & q->q_mask;
488d49fc192SJustin Hibbits 
489d49fc192SJustin Hibbits 	if (q->q_index == 0)
490d49fc192SJustin Hibbits 		q->q_toggle ^= 1;
491d49fc192SJustin Hibbits 
492d49fc192SJustin Hibbits 	return (i & 0x7fffffff);
493d49fc192SJustin Hibbits }
494d49fc192SJustin Hibbits 
495d49fc192SJustin Hibbits static void
xive_dispatch(device_t dev,struct trapframe * tf)496d49fc192SJustin Hibbits xive_dispatch(device_t dev, struct trapframe *tf)
497d49fc192SJustin Hibbits {
498d49fc192SJustin Hibbits 	struct xive_softc *sc;
499d49fc192SJustin Hibbits 	struct xive_cpu *xive_cpud;
500d49fc192SJustin Hibbits 	uint32_t vector;
501d49fc192SJustin Hibbits 	uint16_t ack;
502d49fc192SJustin Hibbits 	uint8_t cppr, he;
503d49fc192SJustin Hibbits 
504d49fc192SJustin Hibbits 	sc = device_get_softc(dev);
505d49fc192SJustin Hibbits 
50660185d89SBrandon Bergren 	xive_cpud = DPCPU_PTR(xive_cpu_data);
507d49fc192SJustin Hibbits 	for (;;) {
508d49fc192SJustin Hibbits 		ack = xive_read_2(sc, XIVE_TM_SPC_ACK);
509d49fc192SJustin Hibbits 		cppr = (ack & 0xff);
510d49fc192SJustin Hibbits 
511d49fc192SJustin Hibbits 		he = ack >> TM_QW3NSR_HE_SHIFT;
512d49fc192SJustin Hibbits 
513d49fc192SJustin Hibbits 		if (he == TM_QW3_NSR_HE_NONE)
514d49fc192SJustin Hibbits 			break;
51560185d89SBrandon Bergren 
51660185d89SBrandon Bergren 		else if (__predict_false(he != TM_QW3_NSR_HE_PHYS)) {
51760185d89SBrandon Bergren 			/*
51860185d89SBrandon Bergren 			 * We don't support TM_QW3_NSR_HE_POOL or
51960185d89SBrandon Bergren 			 * TM_QW3_NSR_HE_LSI interrupts.
52060185d89SBrandon Bergren 			 */
521d49fc192SJustin Hibbits 			device_printf(dev,
522d49fc192SJustin Hibbits 			    "Unexpected interrupt he type: %d\n", he);
523d49fc192SJustin Hibbits 			goto end;
524d49fc192SJustin Hibbits 		}
525d49fc192SJustin Hibbits 
526d49fc192SJustin Hibbits 		xive_write_1(sc, XIVE_TM_CPPR, cppr);
527d49fc192SJustin Hibbits 
528d49fc192SJustin Hibbits 		for (;;) {
529d49fc192SJustin Hibbits 			vector = xive_read_eq(&xive_cpud->queue);
530d49fc192SJustin Hibbits 
531d49fc192SJustin Hibbits 			if (vector == 0)
532d49fc192SJustin Hibbits 				break;
533d49fc192SJustin Hibbits 
534d49fc192SJustin Hibbits 			if (vector == MAX_XIVE_IRQS)
535d49fc192SJustin Hibbits 				vector = xive_ipi_vector;
536d49fc192SJustin Hibbits 
537d49fc192SJustin Hibbits 			powerpc_dispatch_intr(vector, tf);
538d49fc192SJustin Hibbits 		}
539d49fc192SJustin Hibbits 	}
540d49fc192SJustin Hibbits end:
541d49fc192SJustin Hibbits 	xive_write_1(sc, XIVE_TM_CPPR, 0xff);
542d49fc192SJustin Hibbits }
543d49fc192SJustin Hibbits 
544d49fc192SJustin Hibbits static void
xive_enable(device_t dev,u_int irq,u_int vector,void ** priv)545d49fc192SJustin Hibbits xive_enable(device_t dev, u_int irq, u_int vector, void **priv)
546d49fc192SJustin Hibbits {
547d49fc192SJustin Hibbits 	struct xive_irq *irqd;
548d49fc192SJustin Hibbits 	cell_t status, cpu;
549d49fc192SJustin Hibbits 
550d49fc192SJustin Hibbits 	if (irq == MAX_XIVE_IRQS) {
551d49fc192SJustin Hibbits 		if (xive_ipi_vector == -1)
552d49fc192SJustin Hibbits 			xive_ipi_vector = vector;
553d49fc192SJustin Hibbits 		return;
554d49fc192SJustin Hibbits 	}
555d49fc192SJustin Hibbits 	if (*priv == NULL)
556d49fc192SJustin Hibbits 		*priv = xive_configure_irq(irq);
557d49fc192SJustin Hibbits 
558d49fc192SJustin Hibbits 	irqd = *priv;
559d49fc192SJustin Hibbits 
560d49fc192SJustin Hibbits 	/* Bind to this CPU to start */
561d49fc192SJustin Hibbits 	cpu = PCPU_GET(hwref);
562d49fc192SJustin Hibbits 	irqd->lirq = vector;
563d49fc192SJustin Hibbits 
564d49fc192SJustin Hibbits 	for (;;) {
565d49fc192SJustin Hibbits 		status = opal_call(OPAL_XIVE_SET_IRQ_CONFIG, irq, cpu,
566d49fc192SJustin Hibbits 		    XIVE_PRIORITY, vector);
567d49fc192SJustin Hibbits 		if (status != OPAL_BUSY)
568d49fc192SJustin Hibbits 			break;
569d49fc192SJustin Hibbits 		DELAY(10);
570d49fc192SJustin Hibbits 	}
571d49fc192SJustin Hibbits 
572d49fc192SJustin Hibbits 	if (status != 0)
573d49fc192SJustin Hibbits 		panic("OPAL_SET_XIVE IRQ %d -> cpu %d failed: %d", irq,
574d49fc192SJustin Hibbits 		    cpu, status);
575d49fc192SJustin Hibbits 
576d49fc192SJustin Hibbits 	xive_unmask(dev, irq, *priv);
577d49fc192SJustin Hibbits }
578d49fc192SJustin Hibbits 
579d49fc192SJustin Hibbits static void
xive_eoi(device_t dev,u_int irq,void * priv)580d49fc192SJustin Hibbits xive_eoi(device_t dev, u_int irq, void *priv)
581d49fc192SJustin Hibbits {
582d49fc192SJustin Hibbits 	struct xive_irq *rirq;
583d49fc192SJustin Hibbits 	struct xive_cpu *cpud;
584d49fc192SJustin Hibbits 	uint8_t eoi_val;
585d49fc192SJustin Hibbits 
586d49fc192SJustin Hibbits 	if (irq == MAX_XIVE_IRQS) {
587d49fc192SJustin Hibbits 		cpud = DPCPU_PTR(xive_cpu_data);
588d49fc192SJustin Hibbits 		rirq = &cpud->ipi_data;
589d49fc192SJustin Hibbits 	} else
590d49fc192SJustin Hibbits 		rirq = priv;
591d49fc192SJustin Hibbits 
592be48fe60SJustin Hibbits 	if (rirq->flags & OPAL_XIVE_IRQ_STORE_EOI)
593d49fc192SJustin Hibbits 		xive_write_mmap8(rirq->eoi_page + XIVE_IRQ_STORE_EOI, 0);
594d49fc192SJustin Hibbits 	else if (rirq->flags & OPAL_XIVE_IRQ_LSI)
595d49fc192SJustin Hibbits 		xive_read_mmap8(rirq->eoi_page + XIVE_IRQ_LOAD_EOI);
596d49fc192SJustin Hibbits 	else {
597d49fc192SJustin Hibbits 		eoi_val = xive_read_mmap8(rirq->eoi_page + XIVE_IRQ_PQ_00);
598d49fc192SJustin Hibbits 		if ((eoi_val & XIVE_IRQ_VAL_Q) && rirq->trig_page != 0)
599d49fc192SJustin Hibbits 			xive_write_mmap8(rirq->trig_page, 0);
600d49fc192SJustin Hibbits 	}
601d49fc192SJustin Hibbits }
602d49fc192SJustin Hibbits 
603d49fc192SJustin Hibbits static void
xive_ipi(device_t dev,u_int cpu)604d49fc192SJustin Hibbits xive_ipi(device_t dev, u_int cpu)
605d49fc192SJustin Hibbits {
606d49fc192SJustin Hibbits 	struct xive_cpu *xive_cpud;
607d49fc192SJustin Hibbits 
608d49fc192SJustin Hibbits 	xive_cpud = DPCPU_ID_PTR(cpu, xive_cpu_data);
609d49fc192SJustin Hibbits 
610d49fc192SJustin Hibbits 	if (xive_cpud->ipi_data.trig_page == 0)
611d49fc192SJustin Hibbits 		return;
612d49fc192SJustin Hibbits 	xive_write_mmap8(xive_cpud->ipi_data.trig_page, 0);
613d49fc192SJustin Hibbits }
614d49fc192SJustin Hibbits 
615d49fc192SJustin Hibbits static void
xive_mask(device_t dev,u_int irq,void * priv)616d49fc192SJustin Hibbits xive_mask(device_t dev, u_int irq, void *priv)
617d49fc192SJustin Hibbits {
618d49fc192SJustin Hibbits 	struct xive_irq *rirq;
619d49fc192SJustin Hibbits 
620d49fc192SJustin Hibbits 	/* Never mask IPIs */
621d49fc192SJustin Hibbits 	if (irq == MAX_XIVE_IRQS)
622d49fc192SJustin Hibbits 		return;
623d49fc192SJustin Hibbits 
624d49fc192SJustin Hibbits 	rirq = priv;
625d49fc192SJustin Hibbits 
626d49fc192SJustin Hibbits 	if (!(rirq->flags & OPAL_XIVE_IRQ_LSI))
627d49fc192SJustin Hibbits 		return;
628d49fc192SJustin Hibbits 	xive_read_mmap8(rirq->eoi_page + XIVE_IRQ_PQ_01);
629d49fc192SJustin Hibbits }
630d49fc192SJustin Hibbits 
631d49fc192SJustin Hibbits static void
xive_unmask(device_t dev,u_int irq,void * priv)632d49fc192SJustin Hibbits xive_unmask(device_t dev, u_int irq, void *priv)
633d49fc192SJustin Hibbits {
634d49fc192SJustin Hibbits 	struct xive_irq *rirq;
635d49fc192SJustin Hibbits 
636d49fc192SJustin Hibbits 	rirq = priv;
637d49fc192SJustin Hibbits 
638d49fc192SJustin Hibbits 	xive_read_mmap8(rirq->eoi_page + XIVE_IRQ_PQ_00);
639d49fc192SJustin Hibbits }
640d49fc192SJustin Hibbits 
641d49fc192SJustin Hibbits static void
xive_translate_code(device_t dev,u_int irq,int code,enum intr_trigger * trig,enum intr_polarity * pol)642d49fc192SJustin Hibbits xive_translate_code(device_t dev, u_int irq, int code,
643d49fc192SJustin Hibbits     enum intr_trigger *trig, enum intr_polarity *pol)
644d49fc192SJustin Hibbits {
645d49fc192SJustin Hibbits 	switch (code) {
646d49fc192SJustin Hibbits 	case 0:
647d49fc192SJustin Hibbits 		/* L to H edge */
648d49fc192SJustin Hibbits 		*trig = INTR_TRIGGER_EDGE;
649d49fc192SJustin Hibbits 		*pol = INTR_POLARITY_HIGH;
650d49fc192SJustin Hibbits 		break;
651d49fc192SJustin Hibbits 	case 1:
652d49fc192SJustin Hibbits 		/* Active L level */
653d49fc192SJustin Hibbits 		*trig = INTR_TRIGGER_LEVEL;
654d49fc192SJustin Hibbits 		*pol = INTR_POLARITY_LOW;
655d49fc192SJustin Hibbits 		break;
656d49fc192SJustin Hibbits 	default:
657d49fc192SJustin Hibbits 		*trig = INTR_TRIGGER_CONFORM;
658d49fc192SJustin Hibbits 		*pol = INTR_POLARITY_CONFORM;
659d49fc192SJustin Hibbits 	}
660d49fc192SJustin Hibbits }
661d49fc192SJustin Hibbits 
662d49fc192SJustin Hibbits /* Private functions. */
663d49fc192SJustin Hibbits /*
664d49fc192SJustin Hibbits  * Setup the current CPU.  Called by the BSP at driver attachment, and by each
665d49fc192SJustin Hibbits  * AP at wakeup (via xive_smp_cpu_startup()).
666d49fc192SJustin Hibbits  */
667d49fc192SJustin Hibbits static void
xive_setup_cpu(void)668d49fc192SJustin Hibbits xive_setup_cpu(void)
669d49fc192SJustin Hibbits {
670d49fc192SJustin Hibbits 	struct xive_softc *sc;
671d49fc192SJustin Hibbits 	struct xive_cpu *cpup;
672d49fc192SJustin Hibbits 	uint32_t val;
673d49fc192SJustin Hibbits 
674d49fc192SJustin Hibbits 	cpup = DPCPU_PTR(xive_cpu_data);
675d49fc192SJustin Hibbits 
676d49fc192SJustin Hibbits 	sc = device_get_softc(root_pic);
677d49fc192SJustin Hibbits 
678d49fc192SJustin Hibbits 	val = bus_read_4(sc->sc_mem, XIVE_TM_QW2_HV_POOL + TM_WORD2);
679d49fc192SJustin Hibbits 	if (val & TM_QW2W2_VP)
680d49fc192SJustin Hibbits 		bus_read_8(sc->sc_mem, XIVE_TM_SPC_PULL_POOL_CTX);
681d49fc192SJustin Hibbits 
682d49fc192SJustin Hibbits 	bus_write_4(sc->sc_mem, XIVE_TM_QW2_HV_POOL + TM_WORD0, 0xff);
683d49fc192SJustin Hibbits 	bus_write_4(sc->sc_mem, XIVE_TM_QW2_HV_POOL + TM_WORD2,
684d49fc192SJustin Hibbits 	    TM_QW2W2_VP | cpup->cam);
685d49fc192SJustin Hibbits 
686d49fc192SJustin Hibbits 	xive_unmask(root_pic, cpup->ipi_data.girq, &cpup->ipi_data);
687d49fc192SJustin Hibbits 	xive_write_1(sc, XIVE_TM_CPPR, 0xff);
688d49fc192SJustin Hibbits }
689d49fc192SJustin Hibbits 
690d49fc192SJustin Hibbits /* Populate an IRQ structure, mapping the EOI and trigger pages. */
691d49fc192SJustin Hibbits static void
xive_init_irq(struct xive_irq * irqd,u_int irq)692d49fc192SJustin Hibbits xive_init_irq(struct xive_irq *irqd, u_int irq)
693d49fc192SJustin Hibbits {
694d49fc192SJustin Hibbits 	uint64_t eoi_phys, trig_phys;
695d49fc192SJustin Hibbits 	uint32_t esb_shift;
696d49fc192SJustin Hibbits 
697d49fc192SJustin Hibbits 	opal_call(OPAL_XIVE_GET_IRQ_INFO, irq,
698d49fc192SJustin Hibbits 	    vtophys(&irqd->flags), vtophys(&eoi_phys),
699d49fc192SJustin Hibbits 	    vtophys(&trig_phys), vtophys(&esb_shift),
700d49fc192SJustin Hibbits 	    vtophys(&irqd->chip));
701d49fc192SJustin Hibbits 
702f9acb7a8SBrandon Bergren 	irqd->flags = be64toh(irqd->flags);
703f9acb7a8SBrandon Bergren 	eoi_phys = be64toh(eoi_phys);
704f9acb7a8SBrandon Bergren 	trig_phys = be64toh(trig_phys);
705f9acb7a8SBrandon Bergren 	esb_shift = be32toh(esb_shift);
706f9acb7a8SBrandon Bergren 	irqd->chip = be32toh(irqd->chip);
707f9acb7a8SBrandon Bergren 
708d49fc192SJustin Hibbits 	irqd->girq = irq;
709d49fc192SJustin Hibbits 	irqd->esb_size = 1 << esb_shift;
710d49fc192SJustin Hibbits 	irqd->eoi_page = (vm_offset_t)pmap_mapdev(eoi_phys, irqd->esb_size);
711d49fc192SJustin Hibbits 
712d49fc192SJustin Hibbits 	if (eoi_phys == trig_phys)
713d49fc192SJustin Hibbits 		irqd->trig_page = irqd->eoi_page;
714d49fc192SJustin Hibbits 	else if (trig_phys != 0)
715d49fc192SJustin Hibbits 		irqd->trig_page = (vm_offset_t)pmap_mapdev(trig_phys,
716d49fc192SJustin Hibbits 		    irqd->esb_size);
717d49fc192SJustin Hibbits 	else
718d49fc192SJustin Hibbits 		irqd->trig_page = 0;
719d49fc192SJustin Hibbits 
720d49fc192SJustin Hibbits 	opal_call(OPAL_XIVE_GET_IRQ_CONFIG, irq, vtophys(&irqd->vp),
721d49fc192SJustin Hibbits 	    vtophys(&irqd->prio), vtophys(&irqd->lirq));
722f9acb7a8SBrandon Bergren 
723f9acb7a8SBrandon Bergren 	irqd->vp = be64toh(irqd->vp);
724f9acb7a8SBrandon Bergren 	irqd->prio = be64toh(irqd->prio);
725f9acb7a8SBrandon Bergren 	irqd->lirq = be32toh(irqd->lirq);
726d49fc192SJustin Hibbits }
727d49fc192SJustin Hibbits 
728d49fc192SJustin Hibbits /* Allocate an IRQ struct before populating it. */
729d49fc192SJustin Hibbits static struct xive_irq *
xive_configure_irq(u_int irq)730d49fc192SJustin Hibbits xive_configure_irq(u_int irq)
731d49fc192SJustin Hibbits {
732d49fc192SJustin Hibbits 	struct xive_irq *irqd;
733d49fc192SJustin Hibbits 
734d49fc192SJustin Hibbits 	irqd = malloc(sizeof(struct xive_irq), M_XIVE, M_WAITOK);
735d49fc192SJustin Hibbits 
736d49fc192SJustin Hibbits 	xive_init_irq(irqd, irq);
737d49fc192SJustin Hibbits 
738d49fc192SJustin Hibbits 	return (irqd);
739d49fc192SJustin Hibbits }
740d49fc192SJustin Hibbits 
741d49fc192SJustin Hibbits /*
742d49fc192SJustin Hibbits  * Part of the OPAL API.  OPAL_XIVE_ALLOCATE_VP_BLOCK might require more pages,
743d49fc192SJustin Hibbits  * provisioned through this call.
744d49fc192SJustin Hibbits  */
745d49fc192SJustin Hibbits static int
xive_provision_page(struct xive_softc * sc)746d49fc192SJustin Hibbits xive_provision_page(struct xive_softc *sc)
747d49fc192SJustin Hibbits {
748d49fc192SJustin Hibbits 	void *prov_page;
749d49fc192SJustin Hibbits 	int error;
750d49fc192SJustin Hibbits 
751d49fc192SJustin Hibbits 	do {
752d49fc192SJustin Hibbits 		prov_page = contigmalloc(sc->sc_prov_page_size, M_XIVE, 0,
753d49fc192SJustin Hibbits 		    0, BUS_SPACE_MAXADDR,
754d49fc192SJustin Hibbits 		    sc->sc_prov_page_size, sc->sc_prov_page_size);
755d49fc192SJustin Hibbits 
756d49fc192SJustin Hibbits 		error = opal_call(OPAL_XIVE_DONATE_PAGE, -1,
757d49fc192SJustin Hibbits 		    vtophys(prov_page));
758d49fc192SJustin Hibbits 	} while (error == OPAL_XIVE_PROVISIONING);
759d49fc192SJustin Hibbits 
760d49fc192SJustin Hibbits 	return (0);
761d49fc192SJustin Hibbits }
762d49fc192SJustin Hibbits 
763d49fc192SJustin Hibbits /* The XIVE_TM_CPPR register must be set by each thread */
764d49fc192SJustin Hibbits static void
xive_smp_cpu_startup(void)765d49fc192SJustin Hibbits xive_smp_cpu_startup(void)
766d49fc192SJustin Hibbits {
767d49fc192SJustin Hibbits 
768d49fc192SJustin Hibbits 	xive_setup_cpu();
769d49fc192SJustin Hibbits }
770