e500_intr.c revision 1.14
1/*	$NetBSD: e500_intr.c,v 1.14 2011/06/29 05:55:47 matt Exp $	*/
2/*-
3 * Copyright (c) 2010, 2011 The NetBSD Foundation, Inc.
4 * All rights reserved.
5 *
6 * This code is derived from software contributed to The NetBSD Foundation
7 * by Raytheon BBN Technologies Corp and Defense Advanced Research Projects
8 * Agency and which was developed by Matt Thomas of 3am Software Foundry.
9 *
10 * This material is based upon work supported by the Defense Advanced Research
11 * Projects Agency and Space and Naval Warfare Systems Center, Pacific, under
12 * Contract No. N66001-09-C-2073.
13 * Approved for Public Release, Distribution Unlimited
14 *
15 * Redistribution and use in source and binary forms, with or without
16 * modification, are permitted provided that the following conditions
17 * are met:
18 * 1. Redistributions of source code must retain the above copyright
19 *    notice, this list of conditions and the following disclaimer.
20 * 2. Redistributions in binary form must reproduce the above copyright
21 *    notice, this list of conditions and the following disclaimer in the
22 *    documentation and/or other materials provided with the distribution.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
25 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
26 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
27 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
28 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
32 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34 * POSSIBILITY OF SUCH DAMAGE.
35 */
36
37#include "opt_mpc85xx.h"
38
39#define __INTR_PRIVATE
40
41#include <sys/param.h>
42#include <sys/proc.h>
43#include <sys/intr.h>
44#include <sys/cpu.h>
45#include <sys/kmem.h>
46#include <sys/atomic.h>
47#include <sys/bus.h>
48#include <sys/xcall.h>
49#include <sys/bitops.h>
50
51#include <uvm/uvm_extern.h>
52
53#ifdef __HAVE_FAST_SOFTINTS
54#include <powerpc/softint.h>
55#endif
56
57#include <powerpc/spr.h>
58#include <powerpc/booke/spr.h>
59
60#include <powerpc/booke/cpuvar.h>
61#include <powerpc/booke/e500reg.h>
62#include <powerpc/booke/e500var.h>
63#include <powerpc/booke/openpicreg.h>
64
65#define	IPL2CTPR(ipl)		((ipl) + 15 - IPL_HIGH)
66#define CTPR2IPL(ctpr)		((ctpr) - (15 - IPL_HIGH))
67
68#define	IST_PERCPU_P(ist)	((ist) >= IST_TIMER)
69
70struct e500_intr_irq_info {
71	bus_addr_t irq_vpr;
72	bus_addr_t irq_dr;
73	u_int irq_vector;
74};
75
76struct intr_source {
77	int (*is_func)(void *);
78	void *is_arg;
79	int8_t is_ipl;
80	uint8_t is_ist;
81	uint8_t is_irq;
82	bus_size_t is_vpr;
83	bus_size_t is_dr;
84};
85
86#define	INTR_SOURCE_INITIALIZER \
87	{ .is_func = e500_intr_spurious, .is_arg = NULL, \
88	.is_irq = -1, .is_ipl = IPL_NONE, .is_ist = IST_NONE, }
89
90struct e500_intr_name {
91	uint8_t in_irq;
92	const char in_name[15];
93};
94
95static const struct e500_intr_name e500_onchip_intr_names[] = {
96	{ ISOURCE_L2, "l2" },
97	{ ISOURCE_ECM, "ecm" },
98	{ ISOURCE_DDR, "ddr" },
99	{ ISOURCE_LBC, "lbc" },
100	{ ISOURCE_DMA_CHAN1, "dma-chan1" },
101	{ ISOURCE_DMA_CHAN2, "dma-chan2" },
102	{ ISOURCE_DMA_CHAN3, "dma-chan3" },
103	{ ISOURCE_DMA_CHAN4, "dma-chan4" },
104	{ ISOURCE_PCI1, "pci1" },
105	{ ISOURCE_PCIEX2, "pcie2" },
106	{ ISOURCE_PCIEX	, "pcie1" },
107	{ ISOURCE_PCIEX3, "pcie3" },
108	{ ISOURCE_USB1, "usb1" },
109	{ ISOURCE_ETSEC1_TX, "etsec1-tx" },
110	{ ISOURCE_ETSEC1_RX, "etsec1-rx" },
111	{ ISOURCE_ETSEC3_TX, "etsec3-tx" },
112	{ ISOURCE_ETSEC3_RX, "etsec3-rx" },
113	{ ISOURCE_ETSEC3_ERR, "etsec3-err" },
114	{ ISOURCE_ETSEC1_ERR, "etsec1-err" },
115	{ ISOURCE_ETSEC2_TX, "etsec2-tx" },
116	{ ISOURCE_ETSEC2_RX, "etsec2-rx" },
117	{ ISOURCE_ETSEC4_TX, "etsec4-tx" },
118	{ ISOURCE_ETSEC4_RX, "etsec4-rx" },
119	{ ISOURCE_ETSEC4_ERR, "etsec4-err" },
120	{ ISOURCE_ETSEC2_ERR, "etsec2-err" },
121	{ ISOURCE_DUART, "duart" },
122	{ ISOURCE_I2C, "i2c" },
123	{ ISOURCE_PERFMON, "perfmon" },
124	{ ISOURCE_SECURITY1, "sec1" },
125	{ ISOURCE_GPIO, "gpio" },
126	{ ISOURCE_SRIO_EWPU, "srio-ewpu" },
127	{ ISOURCE_SRIO_ODBELL, "srio-odbell" },
128	{ ISOURCE_SRIO_IDBELL, "srio-idbell" },
129	{ ISOURCE_SRIO_OMU1, "srio-omu1" },
130	{ ISOURCE_SRIO_IMU1, "srio-imu1" },
131	{ ISOURCE_SRIO_OMU2, "srio-omu2" },
132	{ ISOURCE_SRIO_IMU2, "srio-imu2" },
133	{ ISOURCE_SECURITY2, "sec2" },
134	{ ISOURCE_SPI, "spi" },
135	{ ISOURCE_ETSEC1_PTP, "etsec1-ptp" },
136	{ ISOURCE_ETSEC2_PTP, "etsec2-ptp" },
137	{ ISOURCE_ETSEC3_PTP, "etsec3-ptp" },
138	{ ISOURCE_ETSEC4_PTP, "etsec4-ptp" },
139	{ ISOURCE_ESDHC, "esdhc" },
140	{ 0, "" },
141};
142
143const struct e500_intr_name default_external_intr_names[] = {
144	{ 0, "" },
145};
146
147static const struct e500_intr_name e500_msigroup_intr_names[] = {
148	{ 0, "msigroup0" },
149	{ 1, "msigroup1" },
150	{ 2, "msigroup2" },
151	{ 3, "msigroup3" },
152	{ 4, "msigroup4" },
153	{ 5, "msigroup5" },
154	{ 6, "msigroup6" },
155	{ 7, "msigroup7" },
156	{ 0, "" },
157};
158
159static const struct e500_intr_name e500_timer_intr_names[] = {
160	{ 0, "timer0" },
161	{ 1, "timer1" },
162	{ 2, "timer2" },
163	{ 3, "timer3" },
164	{ 0, "" },
165};
166
167static const struct e500_intr_name e500_ipi_intr_names[] = {
168	{ 0, "ipi0" },
169	{ 1, "ipi1" },
170	{ 2, "ipi2" },
171	{ 3, "ipi3" },
172	{ 0, "" },
173};
174
175static const struct e500_intr_name e500_mi_intr_names[] = {
176	{ 0, "mi0" },
177	{ 1, "mi1" },
178	{ 2, "mi2" },
179	{ 3, "mi3" },
180	{ 0, "" },
181};
182
183struct e500_intr_info {
184	u_int ii_external_sources;
185	uint32_t ii_onchip_bitmap[2];
186	u_int ii_onchip_sources;
187	u_int ii_msigroup_sources;
188	u_int ii_ipi_sources;			/* per-cpu */
189	u_int ii_timer_sources;			/* per-cpu */
190	u_int ii_mi_sources;			/* per-cpu */
191	u_int ii_percpu_sources;
192	const struct e500_intr_name *ii_external_intr_names;
193	const struct e500_intr_name *ii_onchip_intr_names;
194	u_int8_t ii_ist_vectors[IST_MAX+1];
195};
196
197static kmutex_t e500_intr_lock __cacheline_aligned;
198static struct e500_intr_info e500_intr_info;
199
200#define	INTR_INFO_DECL(lc_chip, UC_CHIP)				\
201static const struct e500_intr_info lc_chip##_intr_info = {		\
202	.ii_external_sources = UC_CHIP ## _EXTERNALSOURCES,		\
203	.ii_onchip_bitmap = UC_CHIP ## _ONCHIPBITMAP,			\
204	.ii_onchip_sources = UC_CHIP ## _ONCHIPSOURCES,			\
205	.ii_msigroup_sources = UC_CHIP ## _MSIGROUPSOURCES,		\
206	.ii_timer_sources = UC_CHIP ## _TIMERSOURCES,			\
207	.ii_ipi_sources = UC_CHIP ## _IPISOURCES,			\
208	.ii_mi_sources = UC_CHIP ## _MISOURCES,				\
209	.ii_percpu_sources = UC_CHIP ## _TIMERSOURCES			\
210	    + UC_CHIP ## _IPISOURCES + UC_CHIP ## _MISOURCES, 		\
211	.ii_external_intr_names = lc_chip ## _external_intr_names,	\
212	.ii_onchip_intr_names = lc_chip ## _onchip_intr_names,		\
213	.ii_ist_vectors = {						\
214		[IST_NONE]		= ~0,				\
215		[IST_EDGE]		= 0,				\
216		[IST_LEVEL_LOW]		= 0,				\
217		[IST_LEVEL_HIGH]	= 0,				\
218		[IST_PULSE]		= 0,				\
219		[IST_ONCHIP]		= UC_CHIP ## _EXTERNALSOURCES,	\
220		[IST_MSIGROUP]		= UC_CHIP ## _EXTERNALSOURCES	\
221					    + UC_CHIP ## _ONCHIPSOURCES, \
222		[IST_TIMER]		= UC_CHIP ## _EXTERNALSOURCES	\
223					    + UC_CHIP ## _ONCHIPSOURCES	\
224					    + UC_CHIP ## _MSIGROUPSOURCES, \
225		[IST_IPI]		= UC_CHIP ## _EXTERNALSOURCES	\
226					    + UC_CHIP ## _ONCHIPSOURCES	\
227					    + UC_CHIP ## _MSIGROUPSOURCES \
228					    + UC_CHIP ## _TIMERSOURCES,	\
229		[IST_MI]		= UC_CHIP ## _EXTERNALSOURCES	\
230					    + UC_CHIP ## _ONCHIPSOURCES	\
231					    + UC_CHIP ## _MSIGROUPSOURCES \
232					    + UC_CHIP ## _TIMERSOURCES	\
233					    + UC_CHIP ## _IPISOURCES,	\
234		[IST_MAX]		= UC_CHIP ## _EXTERNALSOURCES	\
235					    + UC_CHIP ## _ONCHIPSOURCES	\
236					    + UC_CHIP ## _MSIGROUPSOURCES \
237					    + UC_CHIP ## _TIMERSOURCES	\
238					    + UC_CHIP ## _IPISOURCES	\
239					    + UC_CHIP ## _MISOURCES,	\
240	},								\
241}
242
243#ifdef MPC8536
244#define	mpc8536_external_intr_names	default_external_intr_names
245const struct e500_intr_name mpc8536_onchip_intr_names[] = {
246	{ ISOURCE_SATA2, "sata2" },
247	{ ISOURCE_USB2, "usb2" },
248	{ ISOURCE_USB3, "usb3" },
249	{ ISOURCE_SATA1, "sata1" },
250	{ 0, "" },
251};
252
253INTR_INFO_DECL(mpc8536, MPC8536);
254#endif
255
256#ifdef MPC8544
257#define	mpc8544_external_intr_names	default_external_intr_names
258const struct e500_intr_name mpc8544_onchip_intr_names[] = {
259	{ 0, "" },
260};
261
262INTR_INFO_DECL(mpc8544, MPC8544);
263#endif
264#ifdef MPC8548
265#define	mpc8548_external_intr_names	default_external_intr_names
266const struct e500_intr_name mpc8548_onchip_intr_names[] = {
267	{ ISOURCE_PCI1, "pci1" },
268	{ ISOURCE_PCI2, "pci2" },
269	{ 0, "" },
270};
271
272INTR_INFO_DECL(mpc8548, MPC8548);
273#endif
274#ifdef MPC8555
275#define	mpc8555_external_intr_names	default_external_intr_names
276const struct e500_intr_name mpc8555_onchip_intr_names[] = {
277	{ ISOURCE_PCI2, "pci2" },
278	{ ISOURCE_CPM, "CPM" },
279	{ 0, "" },
280};
281
282INTR_INFO_DECL(mpc8555, MPC8555);
283#endif
284#ifdef MPC8568
285#define	mpc8568_external_intr_names	default_external_intr_names
286const struct e500_intr_name mpc8568_onchip_intr_names[] = {
287	{ ISOURCE_QEB_LOW, "QEB low" },
288	{ ISOURCE_QEB_PORT, "QEB port" },
289	{ ISOURCE_QEB_IECC, "QEB iram ecc" },
290	{ ISOURCE_QEB_MUECC, "QEB ram ecc" },
291	{ ISOURCE_TLU1, "tlu1" },
292	{ ISOURCE_QEB_HIGH, "QEB high" },
293	{ 0, "" },
294};
295
296INTR_INFO_DECL(mpc8568, MPC8568);
297#endif
298#ifdef MPC8572
299#define	mpc8572_external_intr_names	default_external_intr_names
300const struct e500_intr_name mpc8572_onchip_intr_names[] = {
301	{ ISOURCE_PCIEX3_MPC8572, "pcie3" },
302	{ ISOURCE_FEC, "fec" },
303	{ ISOURCE_PME_GENERAL, "pme" },
304	{ ISOURCE_TLU1, "tlu1" },
305	{ ISOURCE_TLU2, "tlu2" },
306	{ ISOURCE_PME_CHAN1, "pme-chan1" },
307	{ ISOURCE_PME_CHAN2, "pme-chan2" },
308	{ ISOURCE_PME_CHAN3, "pme-chan3" },
309	{ ISOURCE_PME_CHAN4, "pme-chan4" },
310	{ ISOURCE_DMA2_CHAN1, "dma2-chan1" },
311	{ ISOURCE_DMA2_CHAN2, "dma2-chan2" },
312	{ ISOURCE_DMA2_CHAN3, "dma2-chan3" },
313	{ ISOURCE_DMA2_CHAN4, "dma2-chan4" },
314	{ 0, "" },
315};
316
317INTR_INFO_DECL(mpc8572, MPC8572);
318#endif
319#ifdef P2020
320#define	p20x0_external_intr_names	default_external_intr_names
321const struct e500_intr_name p20x0_onchip_intr_names[] = {
322	{ ISOURCE_PCIEX3_MPC8572, "pcie3" },
323	{ ISOURCE_DMA2_CHAN1, "dma2-chan1" },
324	{ ISOURCE_DMA2_CHAN2, "dma2-chan2" },
325	{ ISOURCE_DMA2_CHAN3, "dma2-chan3" },
326	{ ISOURCE_DMA2_CHAN4, "dma2-chan4" },
327	{ 0, "" },
328};
329
330INTR_INFO_DECL(p20x0, P20x0);
331#endif
332
333static const char ist_names[][12] = {
334	[IST_NONE] = "none",
335	[IST_EDGE] = "edge",
336	[IST_LEVEL_LOW] = "level-",
337	[IST_LEVEL_HIGH] = "level+",
338	[IST_PULSE] = "pulse",
339	[IST_MSI] = "msi",
340	[IST_ONCHIP] = "onchip",
341	[IST_MSIGROUP] = "msigroup",
342	[IST_TIMER] = "timer",
343	[IST_IPI] = "ipi",
344	[IST_MI] = "msgint",
345};
346
347static struct intr_source *e500_intr_sources;
348static const struct intr_source *e500_intr_last_source;
349
350static void 	*e500_intr_establish(int, int, int, int (*)(void *), void *);
351static void 	e500_intr_disestablish(void *);
352static void 	e500_intr_cpu_attach(struct cpu_info *ci);
353static void 	e500_intr_cpu_hatch(struct cpu_info *ci);
354static void	e500_intr_cpu_send_ipi(cpuid_t, uintptr_t);
355static void 	e500_intr_init(void);
356static const char *e500_intr_string(int, int);
357static const char *e500_intr_typename(int);
358static void 	e500_critintr(struct trapframe *tf);
359static void 	e500_decrintr(struct trapframe *tf);
360static void 	e500_extintr(struct trapframe *tf);
361static void 	e500_fitintr(struct trapframe *tf);
362static void 	e500_wdogintr(struct trapframe *tf);
363static void	e500_spl0(void);
364static int 	e500_splraise(int);
365static void 	e500_splx(int);
366
367const struct intrsw e500_intrsw = {
368	.intrsw_establish = e500_intr_establish,
369	.intrsw_disestablish = e500_intr_disestablish,
370	.intrsw_init = e500_intr_init,
371	.intrsw_cpu_attach = e500_intr_cpu_attach,
372	.intrsw_cpu_hatch = e500_intr_cpu_hatch,
373	.intrsw_cpu_send_ipi = e500_intr_cpu_send_ipi,
374	.intrsw_string = e500_intr_string,
375	.intrsw_typename = e500_intr_typename,
376
377	.intrsw_critintr = e500_critintr,
378	.intrsw_decrintr = e500_decrintr,
379	.intrsw_extintr = e500_extintr,
380	.intrsw_fitintr = e500_fitintr,
381	.intrsw_wdogintr = e500_wdogintr,
382
383	.intrsw_splraise = e500_splraise,
384	.intrsw_splx = e500_splx,
385	.intrsw_spl0 = e500_spl0,
386
387#ifdef __HAVE_FAST_SOFTINTS
388	.intrsw_softint_init_md = powerpc_softint_init_md,
389	.intrsw_softint_trigger = powerpc_softint_trigger,
390#endif
391};
392
393static inline uint32_t
394openpic_read(struct cpu_softc *cpu, bus_size_t offset)
395{
396
397	return bus_space_read_4(cpu->cpu_bst, cpu->cpu_bsh,
398	    OPENPIC_BASE + offset);
399}
400
401static inline void
402openpic_write(struct cpu_softc *cpu, bus_size_t offset, uint32_t val)
403{
404
405	return bus_space_write_4(cpu->cpu_bst, cpu->cpu_bsh,
406	    OPENPIC_BASE + offset, val);
407}
408
409static const char *
410e500_intr_external_name_lookup(int irq)
411{
412	prop_array_t extirqs = board_info_get_object("external-irqs");
413	prop_string_t irqname = prop_array_get(extirqs, irq);
414	KASSERT(irqname != NULL);
415	KASSERT(prop_object_type(irqname) == PROP_TYPE_STRING);
416
417	return prop_string_cstring_nocopy(irqname);
418}
419
420static const char *
421e500_intr_name_lookup(const struct e500_intr_name *names, int irq)
422{
423	for (; names->in_name[0] != '\0'; names++) {
424		if (names->in_irq == irq)
425			return names->in_name;
426	}
427
428	return NULL;
429}
430
431static const char *
432e500_intr_onchip_name_lookup(int irq)
433{
434	const char *name;
435
436	name = e500_intr_name_lookup(e500_intr_info.ii_onchip_intr_names, irq);
437	if (name == NULL)
438	       name = e500_intr_name_lookup(e500_onchip_intr_names, irq);
439
440	return name;
441}
442
443static inline void
444e500_splset(struct cpu_info *ci, int ipl)
445{
446	struct cpu_softc * const cpu = ci->ci_softc;
447
448	//KASSERT(!cpu_intr_p() || ipl >= IPL_VM);
449	KASSERT((curlwp->l_pflag & LP_INTR) == 0 || ipl != IPL_NONE);
450#if 0
451	u_int ctpr = ipl;
452	KASSERT(openpic_read(cpu, OPENPIC_CTPR) == ci->ci_cpl);
453#elif 0
454	u_int old_ctpr = (ci->ci_cpl >= IPL_VM ? 15 : ci->ci_cpl);
455	u_int ctpr = (ipl >= IPL_VM ? 15 : ipl);
456	KASSERT(openpic_read(cpu, OPENPIC_CTPR) == old_ctpr);
457#else
458	const u_int ctpr = IPL2CTPR(ipl);
459	KASSERT(openpic_read(cpu, OPENPIC_CTPR) == IPL2CTPR(ci->ci_cpl));
460#endif
461	openpic_write(cpu, OPENPIC_CTPR, ctpr);
462	KASSERT(openpic_read(cpu, OPENPIC_CTPR) == ctpr);
463	ci->ci_cpl = ipl;
464}
465
466static void
467e500_spl0(void)
468{
469	wrtee(0);
470
471	struct cpu_info * const ci = curcpu();
472
473#ifdef __HAVE_FAST_SOFTINTS
474	if (__predict_false(ci->ci_data.cpu_softints != 0)) {
475		e500_splset(ci, IPL_HIGH);
476		powerpc_softint(ci, IPL_NONE,
477		    (vaddr_t)__builtin_return_address(0));
478	}
479#endif /* __HAVE_FAST_SOFTINTS */
480	e500_splset(ci, IPL_NONE);
481
482	wrtee(PSL_EE);
483}
484
485static void
486e500_splx(int ipl)
487{
488	struct cpu_info * const ci = curcpu();
489	const int old_ipl = ci->ci_cpl;
490
491	KASSERT(mfmsr() & PSL_CE);
492
493	if (ipl == old_ipl)
494		return;
495
496	if (__predict_false(ipl > old_ipl)) {
497		printf("%s: %p: cpl=%u: ignoring splx(%u) to raise ipl\n",
498		    __func__, __builtin_return_address(0), old_ipl, ipl);
499		if (old_ipl == IPL_NONE)
500			Debugger();
501	}
502
503	// const
504	register_t msr = wrtee(0);
505#ifdef __HAVE_FAST_SOFTINTS
506	const u_int softints = (ci->ci_data.cpu_softints << ipl) & IPL_SOFTMASK;
507	if (__predict_false(softints != 0)) {
508		e500_splset(ci, IPL_HIGH);
509		powerpc_softint(ci, ipl,
510		    (vaddr_t)__builtin_return_address(0));
511	}
512#endif /* __HAVE_FAST_SOFTINTS */
513	e500_splset(ci, ipl);
514#if 1
515	if (ipl < IPL_VM && old_ipl >= IPL_VM)
516		msr = PSL_EE;
517#endif
518	wrtee(msr);
519}
520
521static int
522e500_splraise(int ipl)
523{
524	struct cpu_info * const ci = curcpu();
525	const int old_ipl = ci->ci_cpl;
526
527	KASSERT(mfmsr() & PSL_CE);
528
529	if (old_ipl < ipl) {
530		//const
531		register_t msr = wrtee(0);
532		e500_splset(ci, ipl);
533#if 1
534		if (old_ipl < IPL_VM && ipl >= IPL_VM)
535			msr = 0;
536#endif
537		wrtee(msr);
538	} else if (ipl == IPL_NONE) {
539		panic("%s: %p: cpl=%u: attempt to splraise(IPL_NONE)",
540		    __func__, __builtin_return_address(0), old_ipl);
541#if 0
542	} else if (old_ipl > ipl) {
543		printf("%s: %p: cpl=%u: ignoring splraise(%u) to lower ipl\n",
544		    __func__, __builtin_return_address(0), old_ipl, ipl);
545#endif
546	}
547
548	return old_ipl;
549}
550
551static int
552e500_intr_spurious(void *arg)
553{
554	return 0;
555}
556
557static bool
558e500_intr_irq_info_get(struct cpu_info *ci, u_int irq, int ipl, int ist,
559	struct e500_intr_irq_info *ii)
560{
561	const struct e500_intr_info * const info = &e500_intr_info;
562	bool ok;
563
564#if DEBUG > 2
565	printf("%s(%p,irq=%u,ipl=%u,ist=%u,%p)\n", __func__, ci, irq, ipl, ist, ii);
566#endif
567
568	if (ipl < IPL_VM || ipl > IPL_HIGH) {
569#if DEBUG > 2
570		printf("%s:%d ipl=%u\n", __func__, __LINE__, ipl);
571#endif
572		return false;
573	}
574
575	if (ist <= IST_NONE || ist >= IST_MAX) {
576#if DEBUG > 2
577		printf("%s:%d ist=%u\n", __func__, __LINE__, ist);
578#endif
579		return false;
580	}
581
582	ii->irq_vector = irq + info->ii_ist_vectors[ist];
583	if (IST_PERCPU_P(ist) && ist != IST_IPI)
584		ii->irq_vector += ci->ci_cpuid * info->ii_percpu_sources;
585
586	switch (ist) {
587	default:
588		ii->irq_vpr = OPENPIC_EIVPR(irq);
589		ii->irq_dr  = OPENPIC_EIDR(irq);
590		ok = irq < info->ii_external_sources
591		    && (ist == IST_EDGE
592			|| ist == IST_LEVEL_LOW
593			|| ist == IST_LEVEL_HIGH);
594		break;
595	case IST_PULSE:
596		ok = false;
597		break;
598	case IST_ONCHIP:
599		ii->irq_vpr = OPENPIC_IIVPR(irq);
600		ii->irq_dr  = OPENPIC_IIDR(irq);
601		ok = irq < 32 * __arraycount(info->ii_onchip_bitmap);
602#if DEBUG > 2
603		printf("%s: irq=%u: ok=%u\n", __func__, irq, ok);
604#endif
605		ok = ok && (info->ii_onchip_bitmap[irq/32] & (1 << (irq & 31)));
606#if DEBUG > 2
607		printf("%s: %08x%08x -> %08x%08x: ok=%u\n", __func__,
608		    irq < 32 ? 0 : (1 << irq), irq < 32 ? (1 << irq) : 0,
609		    info->ii_onchip_bitmap[1], info->ii_onchip_bitmap[0],
610		    ok);
611#endif
612		break;
613	case IST_MSIGROUP:
614		ii->irq_vpr = OPENPIC_MSIVPR(irq);
615		ii->irq_dr  = OPENPIC_MSIDR(irq);
616		ok = irq < info->ii_msigroup_sources
617		    && ipl == IPL_VM;
618		break;
619	case IST_TIMER:
620		ii->irq_vpr = OPENPIC_GTVPR(ci->ci_cpuid, irq);
621		ii->irq_dr  = OPENPIC_GTDR(ci->ci_cpuid, irq);
622		ok = irq < info->ii_timer_sources;
623#if DEBUG > 2
624		printf("%s: IST_TIMER irq=%u: ok=%u\n", __func__, irq, ok);
625#endif
626		break;
627	case IST_IPI:
628		ii->irq_vpr = OPENPIC_IPIVPR(irq);
629		ii->irq_dr  = OPENPIC_IPIDR(irq);
630		ok = irq < info->ii_ipi_sources;
631		break;
632	case IST_MI:
633		ii->irq_vpr = OPENPIC_MIVPR(irq);
634		ii->irq_dr  = OPENPIC_MIDR(irq);
635		ok = irq < info->ii_mi_sources;
636		break;
637	}
638
639	return ok;
640}
641
642static const char *
643e500_intr_string(int irq, int ist)
644{
645	struct cpu_info * const ci = curcpu();
646	struct cpu_softc * const cpu = ci->ci_softc;
647	struct e500_intr_irq_info ii;
648
649	if (!e500_intr_irq_info_get(ci, irq, IPL_VM, ist, &ii))
650		return NULL;
651
652	return cpu->cpu_evcnt_intrs[ii.irq_vector].ev_name;
653}
654
655__CTASSERT(__arraycount(ist_names) == IST_MAX);
656
657static const char *
658e500_intr_typename(int ist)
659{
660	if (IST_NONE <= ist && ist < IST_MAX)
661		return ist_names[ist];
662
663	return NULL;
664}
665
666static void *
667e500_intr_cpu_establish(struct cpu_info *ci, int irq, int ipl, int ist,
668	int (*handler)(void *), void *arg)
669{
670	struct cpu_softc * const cpu = ci->ci_softc;
671	struct e500_intr_irq_info ii;
672
673	KASSERT(ipl >= IPL_VM && ipl <= IPL_HIGH);
674	KASSERT(ist > IST_NONE && ist < IST_MAX && ist != IST_MSI);
675
676	if (!e500_intr_irq_info_get(ci, irq, ipl, ist, &ii)) {
677		printf("%s: e500_intr_irq_info_get(%p,%u,%u,%u,%p) failed\n",
678		    __func__, ci, irq, ipl, ist, &ii);
679		return NULL;
680	}
681
682	struct intr_source * const is = &e500_intr_sources[ii.irq_vector];
683	mutex_enter(&e500_intr_lock);
684	if (is->is_ipl != IPL_NONE)
685		return NULL;
686
687	is->is_func = handler;
688	is->is_arg = arg;
689	is->is_ipl = ipl;
690	is->is_ist = ist;
691	is->is_irq = irq;
692	is->is_vpr = ii.irq_vpr;
693	is->is_dr = ii.irq_dr;
694
695	uint32_t vpr = VPR_PRIORITY_MAKE(IPL2CTPR(ipl))
696	    | VPR_VECTOR_MAKE(((ii.irq_vector + 1) << 4) | ipl)
697	    | (ist == IST_LEVEL_LOW
698		? VPR_LEVEL_LOW
699		: (ist == IST_LEVEL_HIGH
700		    ? VPR_LEVEL_HIGH
701		    : (ist == IST_ONCHIP
702		      ? VPR_P_HIGH
703		      : 0)));
704
705	/*
706	 * All interrupts go to the primary except per-cpu interrupts which get
707	 * routed to the appropriate cpu.
708	 */
709	uint32_t dr = openpic_read(cpu, ii.irq_dr);
710
711	dr |= 1 << (IST_PERCPU_P(ist) ? ci->ci_cpuid : 0);
712
713	/*
714	 * Update the vector/priority and destination registers keeping the
715	 * interrupt masked.
716	 */
717	const register_t msr = wrtee(0);	/* disable interrupts */
718	openpic_write(cpu, ii.irq_vpr, vpr | VPR_MSK);
719	openpic_write(cpu, ii.irq_dr, dr);
720
721	/*
722	 * Now unmask the interrupt.
723	 */
724	openpic_write(cpu, ii.irq_vpr, vpr);
725
726	wrtee(msr);				/* re-enable interrupts */
727
728	mutex_exit(&e500_intr_lock);
729
730	return is;
731}
732
733static void *
734e500_intr_establish(int irq, int ipl, int ist,
735	int (*handler)(void *), void *arg)
736{
737	return e500_intr_cpu_establish(curcpu(), irq, ipl, ist, handler, arg);
738}
739
740static void
741e500_intr_disestablish(void *vis)
742{
743	struct cpu_softc * const cpu = curcpu()->ci_softc;
744	struct intr_source * const is = vis;
745	struct e500_intr_irq_info ii;
746
747	KASSERT(e500_intr_sources <= is);
748	KASSERT(is < e500_intr_last_source);
749	KASSERT(!cpu_intr_p());
750
751	bool ok = e500_intr_irq_info_get(curcpu(), is->is_irq, is->is_ipl,
752	    is->is_ist, &ii);
753	(void)ok;	/* appease gcc */
754	KASSERT(ok);
755	KASSERT(is - e500_intr_sources == ii.irq_vector);
756
757	mutex_enter(&e500_intr_lock);
758	/*
759	 * Mask the source using the mask (MSK) bit in the vector/priority reg.
760	 */
761	uint32_t vpr = openpic_read(cpu, ii.irq_vpr);
762	openpic_write(cpu, ii.irq_vpr, VPR_MSK | vpr);
763
764	/*
765	 * Wait for the Activity (A) bit for the source to be cleared.
766	 */
767	while (openpic_read(cpu, ii.irq_vpr) & VPR_A)
768		;
769
770	/*
771	 * Now the source can be modified.
772	 */
773	openpic_write(cpu, ii.irq_dr, 0);		/* stop delivery */
774	openpic_write(cpu, ii.irq_vpr, VPR_MSK);	/* mask/reset it */
775
776	*is = (struct intr_source)INTR_SOURCE_INITIALIZER;
777
778	mutex_exit(&e500_intr_lock);
779}
780
781static void
782e500_critintr(struct trapframe *tf)
783{
784	panic("%s: srr0/srr1=%#lx/%#lx", __func__, tf->tf_srr0, tf->tf_srr1);
785}
786
787static void
788e500_decrintr(struct trapframe *tf)
789{
790	panic("%s: srr0/srr1=%#lx/%#lx", __func__, tf->tf_srr0, tf->tf_srr1);
791}
792
793static void
794e500_fitintr(struct trapframe *tf)
795{
796	panic("%s: srr0/srr1=%#lx/%#lx", __func__, tf->tf_srr0, tf->tf_srr1);
797}
798
799static void
800e500_wdogintr(struct trapframe *tf)
801{
802	mtspr(SPR_TSR, TSR_ENW|TSR_WIS);
803	panic("%s: tf=%p tb=%"PRId64" srr0/srr1=%#lx/%#lx", __func__, tf,
804	    mftb(), tf->tf_srr0, tf->tf_srr1);
805}
806
807static void
808e500_extintr(struct trapframe *tf)
809{
810	struct cpu_info * const ci = curcpu();
811	struct cpu_softc * const cpu = ci->ci_softc;
812	const int old_ipl = ci->ci_cpl;
813
814	KASSERT(mfmsr() & PSL_CE);
815
816#if 0
817//	printf("%s(%p): idepth=%d enter\n", __func__, tf, ci->ci_idepth);
818	if ((register_t)tf >= (register_t)curlwp->l_addr + USPACE
819	    || (register_t)tf < (register_t)curlwp->l_addr + NBPG) {
820		printf("%s(entry): pid %d.%d (%s): srr0/srr1=%#lx/%#lx: invalid tf addr %p\n",
821		    __func__, curlwp->l_proc->p_pid, curlwp->l_lid,
822		    curlwp->l_proc->p_comm, tf->tf_srr0, tf->tf_srr1, tf);
823	}
824#endif
825
826
827	ci->ci_data.cpu_nintr++;
828	tf->tf_cf.cf_idepth = ci->ci_idepth++;
829	cpu->cpu_pcpls[ci->ci_idepth] = old_ipl;
830#if 1
831	if (mfmsr() & PSL_EE)
832		panic("%s(%p): MSR[EE] is on (%#lx)!", __func__, tf, mfmsr());
833	if (old_ipl == IPL_HIGH
834	    || IPL2CTPR(old_ipl) != openpic_read(cpu, OPENPIC_CTPR))
835		panic("%s(%p): old_ipl(%u) == IPL_HIGH(%u) "
836		    "|| old_ipl + %u != OPENPIC_CTPR (%u)",
837		    __func__, tf, old_ipl, IPL_HIGH,
838		    15 - IPL_HIGH, openpic_read(cpu, OPENPIC_CTPR));
839#else
840	if (old_ipl >= IPL_VM)
841		panic("%s(%p): old_ipl(%u) >= IPL_VM(%u) CTPR=%u",
842		    __func__, tf, old_ipl, IPL_VM, openpic_read(cpu, OPENPIC_CTPR));
843#endif
844
845	for (;;) {
846		/*
847		 * Find out the pending interrupt.
848		 */
849	if (mfmsr() & PSL_EE)
850		panic("%s(%p): MSR[EE] turned on (%#lx)!", __func__, tf, mfmsr());
851		if (IPL2CTPR(old_ipl) != openpic_read(cpu, OPENPIC_CTPR))
852			panic("%s(%p): %d: old_ipl(%u) + %u != OPENPIC_CTPR (%u)",
853			    __func__, tf, __LINE__, old_ipl,
854			    15 - IPL_HIGH, openpic_read(cpu, OPENPIC_CTPR));
855		const uint32_t iack = openpic_read(cpu, OPENPIC_IACK);
856#ifdef DIAGNOSTIC
857		const int ipl = iack & 0xf;
858#endif
859		const int irq = (iack >> 4) - 1;
860#if 0
861		printf("%s: iack=%d ipl=%d irq=%d <%s>\n",
862		    __func__, iack, ipl, irq,
863		    (iack != IRQ_SPURIOUS ?
864			cpu->cpu_evcnt_intrs[irq].ev_name : "spurious"));
865#endif
866		if (IPL2CTPR(old_ipl) != openpic_read(cpu, OPENPIC_CTPR))
867			panic("%s(%p): %d: old_ipl(%u) + %u != OPENPIC_CTPR (%u)",
868			    __func__, tf, __LINE__, old_ipl,
869			    15 - IPL_HIGH, openpic_read(cpu, OPENPIC_CTPR));
870		if (iack == IRQ_SPURIOUS)
871			break;
872
873		struct intr_source * const is = &e500_intr_sources[irq];
874		if (__predict_true(is < e500_intr_last_source)) {
875			/*
876			 * Timer interrupts get their argument overriden with
877			 * the pointer to the trapframe.
878			 */
879			KASSERT(is->is_ipl == ipl);
880			void *arg = (is->is_ist == IST_TIMER ? tf : is->is_arg);
881			if (is->is_ipl <= old_ipl)
882				panic("%s(%p): %s (%u): is->is_ipl (%u) <= old_ipl (%u)\n",
883				    __func__, tf,
884				    cpu->cpu_evcnt_intrs[irq].ev_name, irq,
885				    is->is_ipl, old_ipl);
886			KASSERT(is->is_ipl > old_ipl);
887			e500_splset(ci, is->is_ipl);	/* change IPL */
888			if (__predict_false(is->is_func == NULL)) {
889				aprint_error_dev(ci->ci_dev,
890				    "interrupt from unestablished irq %d\n",
891				    irq);
892			} else {
893				int (*func)(void *) = is->is_func;
894				wrtee(PSL_EE);
895				int rv = (*func)(arg);
896				wrtee(0);
897#if DEBUG > 2
898				printf("%s: %s handler %p(%p) returned %d\n",
899				    __func__,
900				    cpu->cpu_evcnt_intrs[irq].ev_name,
901				    func, arg, rv);
902#endif
903				if (rv == 0)
904					cpu->cpu_evcnt_spurious_intr.ev_count++;
905			}
906			e500_splset(ci, old_ipl);	/* restore IPL */
907			cpu->cpu_evcnt_intrs[irq].ev_count++;
908		} else {
909			aprint_error_dev(ci->ci_dev,
910			    "interrupt from illegal irq %d\n", irq);
911			cpu->cpu_evcnt_spurious_intr.ev_count++;
912		}
913		/*
914		 * If this is a nested interrupt, simply ack it and exit
915		 * because the loop we interrupted will complete looking
916		 * for interrupts.
917		 */
918	if (mfmsr() & PSL_EE)
919		panic("%s(%p): MSR[EE] left on (%#lx)!", __func__, tf, mfmsr());
920		if (IPL2CTPR(old_ipl) != openpic_read(cpu, OPENPIC_CTPR))
921			panic("%s(%p): %d: old_ipl(%u) + %u != OPENPIC_CTPR (%u)",
922			    __func__, tf, __LINE__, old_ipl,
923			    15 - IPL_HIGH, openpic_read(cpu, OPENPIC_CTPR));
924
925		openpic_write(cpu, OPENPIC_EOI, 0);
926		if (IPL2CTPR(old_ipl) != openpic_read(cpu, OPENPIC_CTPR))
927			panic("%s(%p): %d: old_ipl(%u) + %u != OPENPIC_CTPR (%u)",
928			    __func__, tf, __LINE__, old_ipl,
929			    15 - IPL_HIGH, openpic_read(cpu, OPENPIC_CTPR));
930		if (ci->ci_idepth > 0)
931			break;
932	}
933
934	ci->ci_idepth--;
935
936#ifdef __HAVE_FAST_SOFTINTS
937	/*
938	 * Before exiting, deal with any softints that need to be dealt with.
939	 */
940	const u_int softints = (ci->ci_data.cpu_softints << old_ipl) & IPL_SOFTMASK;
941	if (__predict_false(softints != 0)) {
942		KASSERT(old_ipl < IPL_VM);
943		e500_splset(ci, IPL_HIGH);	/* pop to high */
944		powerpc_softint(ci, old_ipl,	/* deal with them */
945		    tf->tf_srr0);
946		e500_splset(ci, old_ipl);	/* and drop back */
947	}
948#endif /* __HAVE_FAST_SOFTINTS */
949#if 1
950	KASSERT(ci->ci_cpl == old_ipl);
951#else
952	e500_splset(ci, old_ipl);		/* and drop back */
953#endif
954
955	/*
956	 * If we interrupted while power-saving and we need to exit idle,
957	 * we need to clear PSL_POW so we won't go back into power-saving.
958	 */
959	if (__predict_false(tf->tf_srr1 & PSL_POW) && ci->ci_want_resched)
960		tf->tf_srr1 &= ~PSL_POW;
961
962//	printf("%s(%p): idepth=%d exit\n", __func__, tf, ci->ci_idepth);
963}
964
965static void
966e500_intr_init(void)
967{
968	struct cpu_info * const ci = curcpu();
969	struct cpu_softc * const cpu = ci->ci_softc;
970	const uint32_t frr = openpic_read(cpu, OPENPIC_FRR);
971	const u_int nirq = FRR_NIRQ_GET(frr) + 1;
972//	const u_int ncpu = FRR_NCPU_GET(frr) + 1;
973	struct intr_source *is;
974	struct e500_intr_info * const ii = &e500_intr_info;
975
976	const uint16_t svr = (mfspr(SPR_SVR) & ~0x80000) >> 16;
977	switch (svr) {
978#ifdef MPC8536
979	case SVR_MPC8536v1 >> 16:
980		*ii = mpc8536_intr_info;
981		break;
982#endif
983#ifdef MPC8544
984	case SVR_MPC8544v1 >> 16:
985		*ii = mpc8544_intr_info;
986		break;
987#endif
988#ifdef MPC8548
989	case SVR_MPC8543v1 >> 16:
990	case SVR_MPC8548v1 >> 16:
991		*ii = mpc8548_intr_info;
992		break;
993#endif
994#ifdef MPC8555
995	case SVR_MPC8541v1 >> 16:
996	case SVR_MPC8555v1 >> 16:
997		*ii = mpc8555_intr_info;
998		break;
999#endif
1000#ifdef MPC8568
1001	case SVR_MPC8568v1 >> 16:
1002		*ii = mpc8568_intr_info;
1003		break;
1004#endif
1005#ifdef MPC8572
1006	case SVR_MPC8572v1 >> 16:
1007		*ii = mpc8572_intr_info;
1008		break;
1009#endif
1010#ifdef P2020
1011	case SVR_P2010v2 >> 16:
1012	case SVR_P2020v2 >> 16:
1013		*ii = p20x0_intr_info;
1014		break;
1015#endif
1016	default:
1017		panic("%s: don't know how to deal with SVR %#lx",
1018		    __func__, mfspr(SPR_SVR));
1019	}
1020
1021	/*
1022	 * We need to be in mixed mode.
1023	 */
1024	openpic_write(cpu, OPENPIC_GCR, GCR_M);
1025
1026	/*
1027	 * Make we and the openpic both agree about the current SPL level.
1028	 */
1029	e500_splset(ci, ci->ci_cpl);
1030
1031	/*
1032	 * Allow the required number of interrupt sources.
1033	 */
1034	is = kmem_zalloc(nirq * sizeof(*is), KM_SLEEP);
1035	KASSERT(is);
1036	e500_intr_sources = is;
1037	e500_intr_last_source = is + nirq;
1038
1039	/*
1040	 * Initialize all the external interrupts as active low.
1041	 */
1042	for (u_int irq = 0; irq < e500_intr_info.ii_external_sources; irq++) {
1043		openpic_write(cpu, OPENPIC_EIVPR(irq),
1044		    VPR_VECTOR_MAKE(irq) | VPR_LEVEL_LOW);
1045	}
1046}
1047
1048static void
1049e500_idlespin(void)
1050{
1051	KASSERTMSG(curcpu()->ci_cpl == IPL_NONE,
1052	    ("%s: cpu%u: ci_cpl (%d) != 0", __func__, cpu_number(),
1053	     curcpu()->ci_cpl));
1054	KASSERTMSG(CTPR2IPL(openpic_read(curcpu()->ci_softc, OPENPIC_CTPR)) == IPL_NONE,
1055	    ("%s: cpu%u: CTPR (%d) != IPL_NONE", __func__, cpu_number(),
1056	     CTPR2IPL(openpic_read(curcpu()->ci_softc, OPENPIC_CTPR))));
1057	KASSERT(mfmsr() & PSL_EE);
1058
1059	if (powersave > 0)
1060		mtmsr(mfmsr() | PSL_POW);
1061}
1062
1063static void
1064e500_intr_cpu_attach(struct cpu_info *ci)
1065{
1066	struct cpu_softc * const cpu = ci->ci_softc;
1067	const char * const xname = device_xname(ci->ci_dev);
1068
1069	const u_int32_t frr = openpic_read(cpu, OPENPIC_FRR);
1070	const u_int nirq = FRR_NIRQ_GET(frr) + 1;
1071//	const u_int ncpu = FRR_NCPU_GET(frr) + 1;
1072
1073	const struct e500_intr_info * const info = &e500_intr_info;
1074
1075	cpu->cpu_clock_gtbcr = OPENPIC_GTBCR(ci->ci_cpuid, E500_CLOCK_TIMER);
1076
1077	cpu->cpu_evcnt_intrs =
1078	    kmem_zalloc(nirq * sizeof(cpu->cpu_evcnt_intrs[0]), KM_SLEEP);
1079	KASSERT(cpu->cpu_evcnt_intrs);
1080
1081	struct evcnt *evcnt = cpu->cpu_evcnt_intrs;
1082	for (size_t j = 0; j < info->ii_external_sources; j++, evcnt++) {
1083		const char *name = e500_intr_external_name_lookup(j);
1084		evcnt_attach_dynamic(evcnt, EVCNT_TYPE_INTR, NULL, xname, name);
1085	}
1086	KASSERT(evcnt == cpu->cpu_evcnt_intrs + info->ii_ist_vectors[IST_ONCHIP]);
1087	for (size_t j = 0; j < info->ii_onchip_sources; j++, evcnt++) {
1088		if (info->ii_onchip_bitmap[j / 32] & __BIT(j & 31)) {
1089			const char *name = e500_intr_onchip_name_lookup(j);
1090			if (name != NULL) {
1091				evcnt_attach_dynamic(evcnt, EVCNT_TYPE_INTR,
1092				    NULL, xname, name);
1093#ifdef DIAGNOSTIC
1094			} else {
1095				printf("%s: missing evcnt for onchip irq %zu\n",
1096				    __func__, j);
1097#endif
1098			}
1099		}
1100	}
1101
1102	KASSERT(evcnt == cpu->cpu_evcnt_intrs + info->ii_ist_vectors[IST_MSIGROUP]);
1103	for (size_t j = 0; j < info->ii_msigroup_sources; j++, evcnt++) {
1104		evcnt_attach_dynamic(evcnt, EVCNT_TYPE_INTR,
1105		    NULL, xname, e500_msigroup_intr_names[j].in_name);
1106	}
1107
1108	KASSERT(evcnt == cpu->cpu_evcnt_intrs + info->ii_ist_vectors[IST_TIMER]);
1109	evcnt += ci->ci_cpuid * info->ii_percpu_sources;
1110	for (size_t j = 0; j < info->ii_timer_sources; j++, evcnt++) {
1111		evcnt_attach_dynamic(evcnt, EVCNT_TYPE_INTR,
1112		    NULL, xname, e500_timer_intr_names[j].in_name);
1113	}
1114
1115	for (size_t j = 0; j < info->ii_ipi_sources; j++, evcnt++) {
1116		evcnt_attach_dynamic(evcnt, EVCNT_TYPE_INTR,
1117		    NULL, xname, e500_ipi_intr_names[j].in_name);
1118	}
1119
1120	for (size_t j = 0; j < info->ii_mi_sources; j++, evcnt++) {
1121		evcnt_attach_dynamic(evcnt, EVCNT_TYPE_INTR,
1122		    NULL, xname, e500_mi_intr_names[j].in_name);
1123	}
1124
1125	ci->ci_idlespin = e500_idlespin;
1126}
1127
1128static void
1129e500_intr_cpu_send_ipi(cpuid_t target, uint32_t ipimsg)
1130{
1131	struct cpu_info * const ci = curcpu();
1132	struct cpu_softc * const cpu = ci->ci_softc;
1133	uint32_t dstmask;
1134
1135	if (target >= CPU_MAXNUM) {
1136		CPU_INFO_ITERATOR cii;
1137		struct cpu_info *dst_ci;
1138
1139		KASSERT(target == IPI_DST_NOTME || target == IPI_DST_ALL);
1140
1141		dstmask = 0;
1142		for (CPU_INFO_FOREACH(cii, dst_ci)) {
1143			if (target == IPI_DST_ALL || ci != dst_ci) {
1144				dstmask |= 1 << cpu_index(ci);
1145				if (ipimsg)
1146					atomic_or_32(&dst_ci->ci_pending_ipis,
1147					    ipimsg);
1148			}
1149		}
1150	} else {
1151		struct cpu_info * const dst_ci = cpu_lookup(target);
1152		KASSERT(dst_ci != NULL);
1153		KASSERTMSG(target == cpu_index(dst_ci),
1154		    ("%s: target (%lu) != cpu_index(cpu%u)",
1155		     __func__, target, cpu_index(dst_ci)));
1156		dstmask = (1 << target);
1157		if (ipimsg)
1158			atomic_or_32(&dst_ci->ci_pending_ipis, ipimsg);
1159	}
1160
1161	openpic_write(cpu, OPENPIC_IPIDR(0), dstmask);
1162}
1163
1164typedef void (*ipifunc_t)(void);
1165
1166#ifdef __HAVE_PREEEMPTION
1167static void
1168e500_ipi_kpreempt(void)
1169{
1170	poowerpc_softint_trigger(1 << IPL_NONE);
1171}
1172#endif
1173
1174static const ipifunc_t e500_ipifuncs[] = {
1175	[ilog2(IPI_XCALL)] =	xc_ipi_handler,
1176	[ilog2(IPI_HALT)] =	e500_ipi_halt,
1177#ifdef __HAVE_PREEMPTION
1178	[ilog2(IPI_KPREEMPT)] =	e500_ipi_kpreempt,
1179#endif
1180	[ilog2(IPI_TLB1SYNC)] =	e500_tlb1_sync,
1181};
1182
1183static int
1184e500_ipi_intr(void *v)
1185{
1186	struct cpu_info * const ci = curcpu();
1187
1188	ci->ci_ev_ipi.ev_count++;
1189
1190	uint32_t pending_ipis = atomic_swap_32(&ci->ci_pending_ipis, 0);
1191	for (u_int ipi = 31; pending_ipis != 0; ipi--, pending_ipis <<= 1) {
1192		const u_int bits = __builtin_clz(pending_ipis);
1193		ipi -= bits;
1194		pending_ipis <<= bits;
1195		KASSERT(e500_ipifuncs[ipi] != NULL);
1196		(*e500_ipifuncs[ipi])();
1197	}
1198
1199	return 1;
1200}
1201
1202static void
1203e500_intr_cpu_hatch(struct cpu_info *ci)
1204{
1205	/*
1206	 * Establish clock interrupt for this CPU.
1207	 */
1208	if (e500_intr_cpu_establish(ci, E500_CLOCK_TIMER, IPL_CLOCK, IST_TIMER,
1209	    e500_clock_intr, NULL) == NULL)
1210		panic("%s: failed to establish clock interrupt!", __func__);
1211
1212	/*
1213	 * Establish the IPI interrupts for this CPU.
1214	 */
1215	if (e500_intr_cpu_establish(ci, 0, IPL_VM, IST_IPI, e500_ipi_intr,
1216	    NULL) == NULL)
1217		panic("%s: failed to establish ipi interrupt!", __func__);
1218
1219	/*
1220	 * Enable watchdog interrupts.
1221	 */
1222	uint32_t tcr = mfspr(SPR_TCR);
1223	tcr |= TCR_WIE;
1224	mtspr(SPR_TCR, tcr);
1225}
1226