xref: /openbsd-src/sys/arch/macppc/dev/macintr.c (revision de0524796acd867538c2bb2b0f4ab84447da8e6c)
1*de052479Scheloha /*	$OpenBSD: macintr.c,v 1.57 2022/07/24 00:28:09 cheloha Exp $	*/
2d9a5f17fSdrahn 
3d9a5f17fSdrahn /*-
4d7469fedSdrahn  * Copyright (c) 2008 Dale Rahn <drahn@openbsd.org>
5d9a5f17fSdrahn  * Copyright (c) 1995 Per Fogelstrom
6d9a5f17fSdrahn  * Copyright (c) 1993, 1994 Charles M. Hannum.
7d9a5f17fSdrahn  * Copyright (c) 1990 The Regents of the University of California.
8d9a5f17fSdrahn  * All rights reserved.
9d9a5f17fSdrahn  *
10d9a5f17fSdrahn  * This code is derived from software contributed to Berkeley by
11d9a5f17fSdrahn  * William Jolitz and Don Ahn.
12d9a5f17fSdrahn  *
13d9a5f17fSdrahn  * Redistribution and use in source and binary forms, with or without
14d9a5f17fSdrahn  * modification, are permitted provided that the following conditions
15d9a5f17fSdrahn  * are met:
16d9a5f17fSdrahn  * 1. Redistributions of source code must retain the above copyright
17d9a5f17fSdrahn  *    notice, this list of conditions and the following disclaimer.
18d9a5f17fSdrahn  * 2. Redistributions in binary form must reproduce the above copyright
19d9a5f17fSdrahn  *    notice, this list of conditions and the following disclaimer in the
20d9a5f17fSdrahn  *    documentation and/or other materials provided with the distribution.
2129295d1cSmillert  * 3. Neither the name of the University nor the names of its contributors
22d9a5f17fSdrahn  *    may be used to endorse or promote products derived from this software
23d9a5f17fSdrahn  *    without specific prior written permission.
24d9a5f17fSdrahn  *
25d9a5f17fSdrahn  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26d9a5f17fSdrahn  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27d9a5f17fSdrahn  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28d9a5f17fSdrahn  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29d9a5f17fSdrahn  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30d9a5f17fSdrahn  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31d9a5f17fSdrahn  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32d9a5f17fSdrahn  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33d9a5f17fSdrahn  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34d9a5f17fSdrahn  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35d9a5f17fSdrahn  * SUCH DAMAGE.
36d9a5f17fSdrahn  *
37d9a5f17fSdrahn  *	@(#)isa.c	7.2 (Berkeley) 5/12/91
38d9a5f17fSdrahn  */
39d9a5f17fSdrahn 
40d9a5f17fSdrahn #include <sys/param.h>
41d9a5f17fSdrahn #include <sys/device.h>
42d9a5f17fSdrahn #include <sys/systm.h>
43417aa565Smpi #include <sys/malloc.h>
4430c76742Smickey 
45417aa565Smpi #include <uvm/uvm_extern.h>
46004d591fSdrahn #include <ddb/db_var.h>
47d9a5f17fSdrahn 
48ecb97ccfSmiod #include <machine/atomic.h>
49d9a5f17fSdrahn #include <machine/autoconf.h>
50d9a5f17fSdrahn #include <machine/intr.h>
51d9a5f17fSdrahn #include <machine/psl.h>
52d9a5f17fSdrahn #include <machine/pio.h>
53d9a5f17fSdrahn 
54d9a5f17fSdrahn #include <dev/ofw/openfirm.h>
55d9a5f17fSdrahn 
56d9a5f17fSdrahn #define ICU_LEN 64
57d9a5f17fSdrahn #define LEGAL_IRQ(x) ((x >= 0) && (x < ICU_LEN))
58d9a5f17fSdrahn 
59d7469fedSdrahn int macintr_ienable_l[IPL_NUM], macintr_ienable_h[IPL_NUM];
60d7469fedSdrahn int macintr_pri_share[IPL_NUM];
61d9a5f17fSdrahn 
62d7469fedSdrahn struct intrq macintr_handler[ICU_LEN];
63d7469fedSdrahn 
64d7469fedSdrahn void macintr_calc_mask(void);
65d7469fedSdrahn void macintr_eoi(int irq);
66d7469fedSdrahn int macintr_read_irq(void);
67d9a5f17fSdrahn 
68d9a5f17fSdrahn extern u_int32_t *heathrow_FCR;
69d9a5f17fSdrahn 
70d9a5f17fSdrahn #define INT_STATE_REG0  (interrupt_reg + 0x20)
71d9a5f17fSdrahn #define INT_ENABLE_REG0 (interrupt_reg + 0x24)
72d9a5f17fSdrahn #define INT_CLEAR_REG0  (interrupt_reg + 0x28)
73d9a5f17fSdrahn #define INT_LEVEL_REG0  (interrupt_reg + 0x2c)
74d9a5f17fSdrahn #define INT_STATE_REG1  (INT_STATE_REG0  - 0x10)
75d9a5f17fSdrahn #define INT_ENABLE_REG1 (INT_ENABLE_REG0 - 0x10)
76d9a5f17fSdrahn #define INT_CLEAR_REG1  (INT_CLEAR_REG0  - 0x10)
77d9a5f17fSdrahn #define INT_LEVEL_REG1  (INT_LEVEL_REG0  - 0x10)
78d9a5f17fSdrahn 
79d9a5f17fSdrahn struct macintr_softc {
80d9a5f17fSdrahn 	struct device sc_dev;
81d9a5f17fSdrahn };
82d9a5f17fSdrahn 
83c4071fd1Smillert int	macintr_match(struct device *parent, void *cf, void *aux);
84c4071fd1Smillert void	macintr_attach(struct device *, struct device *, void *);
85c4071fd1Smillert void	mac_ext_intr(void);
86d7469fedSdrahn void	macintr_collect_preconf_intr(void);
87d7469fedSdrahn void	macintr_setipl(int ipl);
88d9a5f17fSdrahn 
8989ed722cSmpi const struct cfattach macintr_ca = {
90d9a5f17fSdrahn 	sizeof(struct macintr_softc),
91d9a5f17fSdrahn 	macintr_match,
92d9a5f17fSdrahn 	macintr_attach
93d9a5f17fSdrahn };
94d9a5f17fSdrahn 
95d9a5f17fSdrahn struct cfdriver macintr_cd = {
96d9a5f17fSdrahn 	NULL, "macintr", DV_DULL
97d9a5f17fSdrahn };
98d9a5f17fSdrahn 
99d9a5f17fSdrahn int
macintr_match(struct device * parent,void * cf,void * aux)100093da1aaSdrahn macintr_match(struct device *parent, void *cf, void *aux)
101d9a5f17fSdrahn {
102d9a5f17fSdrahn 	struct confargs *ca = aux;
103d9a5f17fSdrahn 	char type[40];
104d9a5f17fSdrahn 
105d9a5f17fSdrahn 	/*
106d9a5f17fSdrahn 	 * Match entry according to "present" openfirmware entry.
107d9a5f17fSdrahn 	 */
108d9a5f17fSdrahn 	if (strcmp(ca->ca_name, "interrupt-controller") == 0 ) {
109d9a5f17fSdrahn 		OF_getprop(ca->ca_node, "device_type", type, sizeof(type));
110093da1aaSdrahn 		if (strcmp(type,  "interrupt-controller") == 0)
111d9a5f17fSdrahn 			return 1;
112d9a5f17fSdrahn 	}
113d9a5f17fSdrahn 
114d9a5f17fSdrahn 	/*
115d9a5f17fSdrahn 	 * Check name for legacy interrupt controller, this is
116d9a5f17fSdrahn 	 * faked to allow old firmware which does not have an entry
117d9a5f17fSdrahn 	 * to attach to this device.
118d9a5f17fSdrahn 	 */
119093da1aaSdrahn 	if (strcmp(ca->ca_name, "legacy-interrupt-controller") == 0 )
120d9a5f17fSdrahn 		return 1;
121d9a5f17fSdrahn 	return 0;
122d9a5f17fSdrahn }
123d9a5f17fSdrahn 
124d9a5f17fSdrahn u_int8_t *interrupt_reg;
125d9a5f17fSdrahn typedef void  (void_f) (void);
1261e3220c2Sdrahn int macintr_prog_button (void *arg);
127d9a5f17fSdrahn 
128d9a5f17fSdrahn intr_establish_t macintr_establish;
129d9a5f17fSdrahn intr_disestablish_t macintr_disestablish;
130d7469fedSdrahn 
131d7469fedSdrahn ppc_splraise_t macintr_splraise;
132d7469fedSdrahn ppc_spllower_t macintr_spllower;
133d7469fedSdrahn ppc_splx_t macintr_splx;
134d7469fedSdrahn 
135d7469fedSdrahn 
136d7469fedSdrahn int
macintr_splraise(int newcpl)137d7469fedSdrahn macintr_splraise(int newcpl)
138d7469fedSdrahn {
139d7469fedSdrahn 	struct cpu_info *ci = curcpu();
140d7469fedSdrahn 	int ocpl = ci->ci_cpl;
1411c471f42Smpi 	int s;
1421c471f42Smpi 
1431c471f42Smpi 	newcpl = macintr_pri_share[newcpl];
144d7469fedSdrahn 	if (ocpl > newcpl)
145d7469fedSdrahn 		newcpl = ocpl;
146d7469fedSdrahn 
1471c471f42Smpi 	s = ppc_intr_disable();
148d7469fedSdrahn 	macintr_setipl(newcpl);
1491c471f42Smpi 	ppc_intr_enable(s);
150d7469fedSdrahn 
151d7469fedSdrahn 	return ocpl;
152d7469fedSdrahn }
153d7469fedSdrahn 
154d7469fedSdrahn int
macintr_spllower(int newcpl)155d7469fedSdrahn macintr_spllower(int newcpl)
156d7469fedSdrahn {
157d7469fedSdrahn 	struct cpu_info *ci = curcpu();
158d7469fedSdrahn 	int ocpl = ci->ci_cpl;
159d7469fedSdrahn 
160d7469fedSdrahn 	macintr_splx(newcpl);
161d7469fedSdrahn 
162d7469fedSdrahn 	return ocpl;
163d7469fedSdrahn }
164d7469fedSdrahn 
165d7469fedSdrahn void
macintr_splx(int newcpl)166d7469fedSdrahn macintr_splx(int newcpl)
167d7469fedSdrahn {
168d7469fedSdrahn 	struct cpu_info *ci = curcpu();
1691c471f42Smpi 	int intr, s;
170d7469fedSdrahn 
1711c471f42Smpi 	intr = ppc_intr_disable();
172d7469fedSdrahn 	macintr_setipl(newcpl);
173*de052479Scheloha 	if (ci->ci_dec_deferred && newcpl < IPL_CLOCK) {
174*de052479Scheloha 		ppc_mtdec(0);
175*de052479Scheloha 		ppc_mtdec(UINT32_MAX);	/* raise DEC exception */
176*de052479Scheloha 	}
1771c471f42Smpi 	if ((newcpl < IPL_SOFTTTY && ci->ci_ipending & ppc_smask[newcpl])) {
1781c471f42Smpi 		s = splsofttty();
1791c471f42Smpi 		dosoftint(newcpl);
1801c471f42Smpi 		macintr_setipl(s); /* no-overhead splx */
1811c471f42Smpi 	}
1821c471f42Smpi 	ppc_intr_enable(intr);
183d7469fedSdrahn }
184d9a5f17fSdrahn 
185d9a5f17fSdrahn void
macintr_attach(struct device * parent,struct device * self,void * aux)186093da1aaSdrahn macintr_attach(struct device *parent, struct device *self, void *aux)
187d9a5f17fSdrahn {
188d7469fedSdrahn 	struct cpu_info *ci = curcpu();
189d9a5f17fSdrahn 	struct confargs *ca = aux;
190d9a5f17fSdrahn 	extern intr_establish_t *intr_establish_func;
191d9a5f17fSdrahn 	extern intr_disestablish_t *intr_disestablish_func;
192d7469fedSdrahn 	struct intrq *iq;
193d7469fedSdrahn 	int i;
194d9a5f17fSdrahn 
1951d379536Sdrahn 	interrupt_reg = (void *)mapiodev(ca->ca_baseaddr,0x100); /* XXX */
196d9a5f17fSdrahn 
197d7469fedSdrahn 	for (i = 0; i < ICU_LEN; i++) {
198d7469fedSdrahn 		iq = &macintr_handler[i];
199d7469fedSdrahn 		TAILQ_INIT(&iq->iq_list);
200d7469fedSdrahn 	}
201d7469fedSdrahn 	ppc_smask_init();
202d7469fedSdrahn 
203d9a5f17fSdrahn 	install_extint(mac_ext_intr);
204d9a5f17fSdrahn 	intr_establish_func  = macintr_establish;
205d9a5f17fSdrahn 	intr_disestablish_func  = macintr_disestablish;
206d9a5f17fSdrahn 
207d7469fedSdrahn 	ppc_intr_func.raise = macintr_splraise;
208d7469fedSdrahn 	ppc_intr_func.lower = macintr_spllower;
209d7469fedSdrahn 	ppc_intr_func.x = macintr_splx;
210d7469fedSdrahn 
21149669151Smpi 	ci->ci_flags = 0;
212d7469fedSdrahn 
213d9a5f17fSdrahn 	macintr_collect_preconf_intr();
214d9a5f17fSdrahn 
215d9a5f17fSdrahn 	mac_intr_establish(parent, 0x14, IST_LEVEL, IPL_HIGH,
2161e3220c2Sdrahn 	    macintr_prog_button, (void *)0x14, "progbutton");
217d9a5f17fSdrahn 
218d9a5f17fSdrahn 	ppc_intr_enable(1);
219d9a5f17fSdrahn 	printf("\n");
220d9a5f17fSdrahn }
221093da1aaSdrahn 
222d9a5f17fSdrahn void
macintr_collect_preconf_intr(void)223af7e7ea9Sderaadt macintr_collect_preconf_intr(void)
224d9a5f17fSdrahn {
225d9a5f17fSdrahn 	int i;
226d9a5f17fSdrahn 	for (i = 0; i < ppc_configed_intr_cnt; i++) {
2273a00bd28Smiod #ifdef DEBUG
2289d376840Smiod 		printf("\n\t%s irq %d level %d fun %p arg %p",
229d9a5f17fSdrahn 			ppc_configed_intr[i].ih_what,
230d9a5f17fSdrahn 			ppc_configed_intr[i].ih_irq,
231d9a5f17fSdrahn 			ppc_configed_intr[i].ih_level,
232d9a5f17fSdrahn 			ppc_configed_intr[i].ih_fun,
233d9a5f17fSdrahn 			ppc_configed_intr[i].ih_arg
234d9a5f17fSdrahn 			);
2353a00bd28Smiod #endif
236d9a5f17fSdrahn 		macintr_establish(NULL,
237d9a5f17fSdrahn 			ppc_configed_intr[i].ih_irq,
238d9a5f17fSdrahn 			IST_LEVEL,
239d9a5f17fSdrahn 			ppc_configed_intr[i].ih_level,
240d9a5f17fSdrahn 			ppc_configed_intr[i].ih_fun,
241d9a5f17fSdrahn 			ppc_configed_intr[i].ih_arg,
242d9a5f17fSdrahn 			ppc_configed_intr[i].ih_what);
243d9a5f17fSdrahn 	}
244d9a5f17fSdrahn }
245d9a5f17fSdrahn 
246d9a5f17fSdrahn 
2471e3220c2Sdrahn /*
2481e3220c2Sdrahn  * programmer_button function to fix args to Debugger.
2491e3220c2Sdrahn  * deal with any enables/disables, if necessary.
2501e3220c2Sdrahn  */
251d9a5f17fSdrahn int
macintr_prog_button(void * arg)2521e3220c2Sdrahn macintr_prog_button (void *arg)
253d9a5f17fSdrahn {
254d9a5f17fSdrahn #ifdef DDB
255004d591fSdrahn 	if (db_console)
256e97088d6Smpi 		db_enter();
257d9a5f17fSdrahn #else
258d9a5f17fSdrahn 	printf("programmer button pressed, debugger not available\n");
259d9a5f17fSdrahn #endif
260d9a5f17fSdrahn 	return 1;
261d9a5f17fSdrahn }
262d9a5f17fSdrahn 
2631c471f42Smpi /* Must be called with interrupt disable. */
264d7469fedSdrahn void
macintr_setipl(int ipl)265d7469fedSdrahn macintr_setipl(int ipl)
266d9a5f17fSdrahn {
267d7469fedSdrahn 	struct cpu_info *ci = curcpu();
2681c471f42Smpi 
269d7469fedSdrahn 	ci->ci_cpl = ipl;
270d7469fedSdrahn 	if (heathrow_FCR)
271d7469fedSdrahn 		out32rb(INT_ENABLE_REG1,
272d7469fedSdrahn 		    macintr_ienable_h[macintr_pri_share[ipl]]);
273d9a5f17fSdrahn 
274d7469fedSdrahn 	out32rb(INT_ENABLE_REG0, macintr_ienable_l[macintr_pri_share[ipl]]);
275d9a5f17fSdrahn }
276d9a5f17fSdrahn 
277d9a5f17fSdrahn /*
278d9a5f17fSdrahn  * Register an interrupt handler.
279d9a5f17fSdrahn  */
280d9a5f17fSdrahn void *
macintr_establish(void * lcv,int irq,int type,int level,int (* ih_fun)(void *),void * ih_arg,const char * name)281093da1aaSdrahn macintr_establish(void * lcv, int irq, int type, int level,
282c03b1b92Smk     int (*ih_fun)(void *), void *ih_arg, const char *name)
283d9a5f17fSdrahn {
284d7469fedSdrahn 	struct cpu_info *ci = curcpu();
285d7469fedSdrahn 	struct intrq *iq;
286d7469fedSdrahn 	struct intrhand *ih;
287bb536b7dSmpi 	int s, flags;
288d9a5f17fSdrahn 
289f0144ea9Smpi 	if (!LEGAL_IRQ(irq) || type == IST_NONE) {
290f0144ea9Smpi 		printf("%s: bogus irq %d or type %d", __func__, irq, type);
291f0144ea9Smpi 		return (NULL);
292f0144ea9Smpi 	}
293f0144ea9Smpi 
294d9a5f17fSdrahn 	/* no point in sleeping unless someone can free memory. */
295d9a5f17fSdrahn 	ih = malloc(sizeof *ih, M_DEVBUF, cold ? M_NOWAIT : M_WAITOK);
296d9a5f17fSdrahn 	if (ih == NULL)
297d9a5f17fSdrahn 		panic("intr_establish: can't malloc handler info");
298d9a5f17fSdrahn 
299d7469fedSdrahn 	iq = &macintr_handler[irq];
300d7469fedSdrahn 	switch (iq->iq_ist) {
301d9a5f17fSdrahn 	case IST_NONE:
302d7469fedSdrahn 		iq->iq_ist = type;
303d9a5f17fSdrahn 		break;
304d9a5f17fSdrahn 	case IST_EDGE:
3052edcc96aSderaadt 		intr_shared_edge = 1;
3062edcc96aSderaadt 		/* FALLTHROUGH */
307d9a5f17fSdrahn 	case IST_LEVEL:
308d7469fedSdrahn 		if (type == iq->iq_ist)
309d9a5f17fSdrahn 			break;
310d9a5f17fSdrahn 	case IST_PULSE:
311d9a5f17fSdrahn 		if (type != IST_NONE)
312d9a5f17fSdrahn 			panic("intr_establish: can't share %s with %s",
313d7469fedSdrahn 			    ppc_intr_typename(iq->iq_ist),
314d7469fedSdrahn 			    ppc_intr_typename(type));
315d9a5f17fSdrahn 		break;
316d9a5f17fSdrahn 	}
317d9a5f17fSdrahn 
318bb536b7dSmpi 	flags = level & IPL_MPSAFE;
319bb536b7dSmpi 	level &= ~IPL_MPSAFE;
320bb536b7dSmpi 
321bb536b7dSmpi 	KASSERT(level <= IPL_TTY || level >= IPL_CLOCK || flags & IPL_MPSAFE);
322bb536b7dSmpi 
3235e058f67Sderaadt 	ih->ih_fun = ih_fun;
3245e058f67Sderaadt 	ih->ih_arg = ih_arg;
3255e058f67Sderaadt 	ih->ih_level = level;
326bb536b7dSmpi 	ih->ih_flags = flags;
3275e058f67Sderaadt 	ih->ih_irq = irq;
328d7469fedSdrahn 	evcount_attach(&ih->ih_count, name, &ih->ih_irq);
329d7469fedSdrahn 
330d7469fedSdrahn 	/*
331d7469fedSdrahn 	 * Append handler to end of list
332d7469fedSdrahn 	 */
333d7469fedSdrahn 	s = ppc_intr_disable();
334d7469fedSdrahn 
335d7469fedSdrahn 	TAILQ_INSERT_TAIL(&iq->iq_list, ih, ih_list);
336d7469fedSdrahn 	macintr_calc_mask();
337d7469fedSdrahn 
338d7469fedSdrahn 	macintr_setipl(ci->ci_cpl);
339d7469fedSdrahn 	ppc_intr_enable(s);
340d9a5f17fSdrahn 
341d9a5f17fSdrahn 	return (ih);
342d9a5f17fSdrahn }
343d9a5f17fSdrahn 
344d9a5f17fSdrahn /*
345d9a5f17fSdrahn  * Deregister an interrupt handler.
346d9a5f17fSdrahn  */
347d9a5f17fSdrahn void
macintr_disestablish(void * lcp,void * arg)348093da1aaSdrahn macintr_disestablish(void *lcp, void *arg)
349d9a5f17fSdrahn {
350d7469fedSdrahn 	struct cpu_info *ci = curcpu();
351d9a5f17fSdrahn 	struct intrhand *ih = arg;
352d9a5f17fSdrahn 	int irq = ih->ih_irq;
353d7469fedSdrahn 	int s;
354d7469fedSdrahn 	struct intrq *iq;
355d9a5f17fSdrahn 
356f0144ea9Smpi 	if (!LEGAL_IRQ(irq)) {
357f0144ea9Smpi 		printf("%s: bogus irq %d", __func__, irq);
358f0144ea9Smpi 		return;
359f0144ea9Smpi 	}
360d9a5f17fSdrahn 
361d9a5f17fSdrahn 	/*
362d9a5f17fSdrahn 	 * Remove the handler from the chain.
363d9a5f17fSdrahn 	 */
364d7469fedSdrahn 
365d7469fedSdrahn 	iq = &macintr_handler[irq];
366d7469fedSdrahn 	s = ppc_intr_disable();
367d7469fedSdrahn 
368d7469fedSdrahn 	TAILQ_REMOVE(&iq->iq_list, ih, ih_list);
369d7469fedSdrahn 	macintr_calc_mask();
370d7469fedSdrahn 
371d7469fedSdrahn 	macintr_setipl(ci->ci_cpl);
372d7469fedSdrahn 	ppc_intr_enable(s);
373a4867f13Saaron 
374a4867f13Saaron 	evcount_detach(&ih->ih_count);
37558d5cf8aSderaadt 	free(ih, M_DEVBUF, sizeof *ih);
376d9a5f17fSdrahn 
377d7469fedSdrahn 	if (TAILQ_EMPTY(&iq->iq_list))
378d7469fedSdrahn 		iq->iq_ist = IST_NONE;
379d9a5f17fSdrahn }
380d9a5f17fSdrahn 
381d9a5f17fSdrahn /*
382d9a5f17fSdrahn  * Recalculate the interrupt masks from scratch.
383d9a5f17fSdrahn  * We could code special registry and deregistry versions of this function that
384d9a5f17fSdrahn  * would be faster, but the code would be nastier, and we don't expect this to
385d9a5f17fSdrahn  * happen very much anyway.
386d9a5f17fSdrahn  */
387d7469fedSdrahn void
macintr_calc_mask(void)388af7e7ea9Sderaadt macintr_calc_mask(void)
389d9a5f17fSdrahn {
390d9a5f17fSdrahn 	int irq;
391d7469fedSdrahn 	struct intrhand *ih;
3926a15553dSdrahn 	int i;
3936a15553dSdrahn 
394d7469fedSdrahn 	for (i = IPL_NONE; i < IPL_NUM; i++) {
395d7469fedSdrahn 		macintr_pri_share[i] = i;
3966a15553dSdrahn 	}
3976a15553dSdrahn 
398d7469fedSdrahn 	for (irq = 0; irq < ICU_LEN; irq++) {
399d7469fedSdrahn 		int maxipl = IPL_NONE;
400d7469fedSdrahn 		int minipl = IPL_HIGH;
401d7469fedSdrahn 		struct intrq *iq = &macintr_handler[irq];
402d9a5f17fSdrahn 
403d7469fedSdrahn 		TAILQ_FOREACH(ih, &iq->iq_list, ih_list) {
404d7469fedSdrahn 			if (ih->ih_level > maxipl)
405d7469fedSdrahn 				maxipl = ih->ih_level;
406d7469fedSdrahn 			if (ih->ih_level < minipl)
407d7469fedSdrahn 				minipl = ih->ih_level;
408d7469fedSdrahn 		}
409d9a5f17fSdrahn 
410d7469fedSdrahn 		iq->iq_ipl = maxipl;
411d7469fedSdrahn 
412d7469fedSdrahn 		if (maxipl == IPL_NONE) {
413d7469fedSdrahn 			minipl = IPL_NONE; /* Interrupt not enabled */
414d7469fedSdrahn 		} else {
415e8200877Sdrahn 			for (i = minipl; i < maxipl; i++)
416e8200877Sdrahn 				macintr_pri_share[i] =
417e8200877Sdrahn 				    macintr_pri_share[maxipl];
418d7469fedSdrahn 		}
419d7469fedSdrahn 
420d7469fedSdrahn 		/* Enable interrupts at lower levels */
421d7469fedSdrahn 
422d7469fedSdrahn 		if (irq < 32) {
423d7469fedSdrahn 			for (i = IPL_NONE; i < minipl; i++)
424d7469fedSdrahn 				macintr_ienable_l[i] |= (1 << irq);
425d7469fedSdrahn 			for (; i <= IPL_HIGH; i++)
426d7469fedSdrahn 				macintr_ienable_l[i] &= ~(1 << irq);
427d7469fedSdrahn 		} else {
428d7469fedSdrahn 			for (i = IPL_NONE; i < minipl; i++)
429d7469fedSdrahn 				macintr_ienable_h[i] |= (1 << (irq-32));
430d7469fedSdrahn 			for (; i <= IPL_HIGH; i++)
431d7469fedSdrahn 				macintr_ienable_h[i] &= ~(1 << (irq-32));
432d7469fedSdrahn 		}
433d7469fedSdrahn 	}
434d7469fedSdrahn 
435d9a5f17fSdrahn #if 0
436d7469fedSdrahn 	for (i = 0; i < IPL_NUM; i++)
437d7469fedSdrahn 		printf("imask[%d] %x %x\n", i, macintr_ienable_l[i],
438d7469fedSdrahn 		    macintr_ienable_h[i]);
439d9a5f17fSdrahn #endif
440d9a5f17fSdrahn }
441d9a5f17fSdrahn 
442d9a5f17fSdrahn /*
443d9a5f17fSdrahn  * external interrupt handler
444d9a5f17fSdrahn  */
445d9a5f17fSdrahn void
mac_ext_intr(void)446af7e7ea9Sderaadt mac_ext_intr(void)
447d9a5f17fSdrahn {
448d9a5f17fSdrahn 	int irq = 0;
4492edcc96aSderaadt 	int pcpl, ret;
4509e61e18aSkettenis 	struct cpu_info *ci = curcpu();
451d7469fedSdrahn 	struct intrq *iq;
452d9a5f17fSdrahn 	struct intrhand *ih;
453d9a5f17fSdrahn 
4549e61e18aSkettenis 	pcpl = ci->ci_cpl;	/* Turn off all */
455d9a5f17fSdrahn 
456d7469fedSdrahn 	irq = macintr_read_irq();
457d7469fedSdrahn 	while (irq != 255) {
458d7469fedSdrahn 		iq = &macintr_handler[irq];
459d7469fedSdrahn 		macintr_setipl(iq->iq_ipl);
460d9a5f17fSdrahn 
461d7469fedSdrahn 		TAILQ_FOREACH(ih, &iq->iq_list, ih_list) {
462d7469fedSdrahn 			ppc_intr_enable(1);
4632edcc96aSderaadt 			ret = ((*ih->ih_fun)(ih->ih_arg));
4642edcc96aSderaadt 			if (ret) {
465a4867f13Saaron 				ih->ih_count.ec_count++;
4662edcc96aSderaadt 				if (intr_shared_edge == 0 && ret == 1)
4672edcc96aSderaadt 					break;
4682edcc96aSderaadt 			}
469d7469fedSdrahn 			(void)ppc_intr_disable();
470d9a5f17fSdrahn 		}
471d7469fedSdrahn 		macintr_eoi(irq);
472d7469fedSdrahn 		macintr_setipl(pcpl);
473d9a5f17fSdrahn 
474d9a5f17fSdrahn 		uvmexp.intrs++;
4758bfe5d75Sdrahn 
476d7469fedSdrahn 		irq = macintr_read_irq();
477d7469fedSdrahn 	}
478d7469fedSdrahn 
4791c471f42Smpi 	macintr_splx(pcpl);	/* Process pendings. */
480d9a5f17fSdrahn }
481d9a5f17fSdrahn 
482d7469fedSdrahn void
macintr_eoi(int irq)483d7469fedSdrahn macintr_eoi(int irq)
484d9a5f17fSdrahn {
485d7469fedSdrahn 	u_int32_t state0, state1;
486d7469fedSdrahn 
487d7469fedSdrahn 	if (irq < 32) {
488d7469fedSdrahn 		state0 =  1 << irq;
489d7469fedSdrahn 		out32rb(INT_CLEAR_REG0, state0);
490d7469fedSdrahn 	} else {
491d7469fedSdrahn 		if (heathrow_FCR) {		/* has heathrow? */
492d7469fedSdrahn 			state1 = 1 << (irq - 32);
493d7469fedSdrahn 			out32rb(INT_CLEAR_REG1, state1);
494d7469fedSdrahn 		}
495d7469fedSdrahn 	}
496d7469fedSdrahn }
497d7469fedSdrahn 
498d7469fedSdrahn int
macintr_read_irq(void)499af7e7ea9Sderaadt macintr_read_irq(void)
500d7469fedSdrahn {
501d7469fedSdrahn 	struct cpu_info *ci = curcpu();
502d7469fedSdrahn 	u_int32_t state0, state1, irq_mask;
503d7469fedSdrahn 	int ipl, irq;
504d9a5f17fSdrahn 
505d9a5f17fSdrahn 	state0 = in32rb(INT_STATE_REG0);
506d9a5f17fSdrahn 
507d9a5f17fSdrahn 	if (heathrow_FCR)			/* has heathrow? */
508d9a5f17fSdrahn 		state1 = in32rb(INT_STATE_REG1);
509d9a5f17fSdrahn 	else
510d9a5f17fSdrahn 		state1 = 0;
511d9a5f17fSdrahn 
512d7469fedSdrahn 	for (ipl = IPL_HIGH; ipl >= ci->ci_cpl; ipl --) {
513d7469fedSdrahn 		irq_mask = state0 & macintr_ienable_l[ipl];
514d7469fedSdrahn 		if (irq_mask) {
515d7469fedSdrahn 			irq = ffs(irq_mask) - 1;
516d7469fedSdrahn 			return irq;
517d9a5f17fSdrahn 		}
518d7469fedSdrahn 		irq_mask = state1 & macintr_ienable_h[ipl];
519d7469fedSdrahn 		if (irq_mask) {
520d7469fedSdrahn 			irq = ffs(irq_mask) + 31;
521d7469fedSdrahn 			return irq;
522d7469fedSdrahn 		}
523d7469fedSdrahn 	}
524d7469fedSdrahn 	return 255;
525d9a5f17fSdrahn }
526