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