xref: /netbsd-src/sys/arch/arc/isa/isabus.c (revision 5c255dd2d0805ff3d827b666d7cf4d14c1156a03)
1*5c255dd2Sthorpej /*	$NetBSD: isabus.c,v 1.54 2023/12/07 03:46:10 thorpej Exp $	*/
271f6ef9eSsoda /*	$OpenBSD: isabus.c,v 1.15 1998/03/16 09:38:46 pefo Exp $	*/
3564df9b6Ssoda /*	NetBSD: isa.c,v 1.33 1995/06/28 04:30:51 cgd Exp 	*/
422d43f5aSsoda 
522d43f5aSsoda /*-
622d43f5aSsoda  * Copyright (c) 1990 The Regents of the University of California.
722d43f5aSsoda  * All rights reserved.
822d43f5aSsoda  *
922d43f5aSsoda  * This code is derived from software contributed to Berkeley by
1022d43f5aSsoda  * William Jolitz and Don Ahn.
1122d43f5aSsoda  *
1222d43f5aSsoda  * Redistribution and use in source and binary forms, with or without
1322d43f5aSsoda  * modification, are permitted provided that the following conditions
1422d43f5aSsoda  * are met:
1522d43f5aSsoda  * 1. Redistributions of source code must retain the above copyright
1622d43f5aSsoda  *    notice, this list of conditions and the following disclaimer.
1722d43f5aSsoda  * 2. Redistributions in binary form must reproduce the above copyright
1822d43f5aSsoda  *    notice, this list of conditions and the following disclaimer in the
1922d43f5aSsoda  *    documentation and/or other materials provided with the distribution.
20aad01611Sagc  * 3. Neither the name of the University nor the names of its contributors
21aad01611Sagc  *    may be used to endorse or promote products derived from this software
22aad01611Sagc  *    without specific prior written permission.
23aad01611Sagc  *
24aad01611Sagc  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25aad01611Sagc  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26aad01611Sagc  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27aad01611Sagc  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28aad01611Sagc  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29aad01611Sagc  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30aad01611Sagc  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31aad01611Sagc  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32aad01611Sagc  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33aad01611Sagc  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34aad01611Sagc  * SUCH DAMAGE.
35aad01611Sagc  *
36aad01611Sagc  *	@(#)isa.c	7.2 (Berkeley) 5/12/91
37aad01611Sagc  */
38aad01611Sagc /*-
39aad01611Sagc  * Copyright (c) 1995 Per Fogelstrom
40aad01611Sagc  * Copyright (c) 1993, 1994 Charles M. Hannum.
41aad01611Sagc  *
42aad01611Sagc  * This code is derived from software contributed to Berkeley by
43aad01611Sagc  * William Jolitz and Don Ahn.
44aad01611Sagc  *
45aad01611Sagc  * Redistribution and use in source and binary forms, with or without
46aad01611Sagc  * modification, are permitted provided that the following conditions
47aad01611Sagc  * are met:
48aad01611Sagc  * 1. Redistributions of source code must retain the above copyright
49aad01611Sagc  *    notice, this list of conditions and the following disclaimer.
50aad01611Sagc  * 2. Redistributions in binary form must reproduce the above copyright
51aad01611Sagc  *    notice, this list of conditions and the following disclaimer in the
52aad01611Sagc  *    documentation and/or other materials provided with the distribution.
5322d43f5aSsoda  * 3. All advertising materials mentioning features or use of this software
5422d43f5aSsoda  *    must display the following acknowledgement:
5522d43f5aSsoda  *	This product includes software developed by the University of
5622d43f5aSsoda  *	California, Berkeley and its contributors.
5722d43f5aSsoda  * 4. Neither the name of the University nor the names of its contributors
5822d43f5aSsoda  *    may be used to endorse or promote products derived from this software
5922d43f5aSsoda  *    without specific prior written permission.
6022d43f5aSsoda  *
6122d43f5aSsoda  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
6222d43f5aSsoda  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
6322d43f5aSsoda  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
6422d43f5aSsoda  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
6522d43f5aSsoda  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
6622d43f5aSsoda  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
6722d43f5aSsoda  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
6822d43f5aSsoda  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
6922d43f5aSsoda  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
7022d43f5aSsoda  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
7122d43f5aSsoda  * SUCH DAMAGE.
7222d43f5aSsoda  *
7322d43f5aSsoda  *	@(#)isa.c	7.2 (Berkeley) 5/12/91
7422d43f5aSsoda  */
7522d43f5aSsoda /*
7622d43f5aSsoda  * Mach Operating System
7722d43f5aSsoda  * Copyright (c) 1991,1990,1989 Carnegie Mellon University
7822d43f5aSsoda  * All Rights Reserved.
7922d43f5aSsoda  *
8022d43f5aSsoda  * Permission to use, copy, modify and distribute this software and its
8122d43f5aSsoda  * documentation is hereby granted, provided that both the copyright
8222d43f5aSsoda  * notice and this permission notice appear in all copies of the
8322d43f5aSsoda  * software, derivative works or modified versions, and any portions
8422d43f5aSsoda  * thereof, and that both notices appear in supporting documentation.
8522d43f5aSsoda  *
8622d43f5aSsoda  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
8722d43f5aSsoda  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
8822d43f5aSsoda  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
8922d43f5aSsoda  *
9022d43f5aSsoda  * Carnegie Mellon requests users of this software to return to
9122d43f5aSsoda  *
9222d43f5aSsoda  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
9322d43f5aSsoda  *  School of Computer Science
9422d43f5aSsoda  *  Carnegie Mellon University
9522d43f5aSsoda  *  Pittsburgh PA 15213-3890
9622d43f5aSsoda  *
9722d43f5aSsoda  * any improvements or extensions that they make and grant Carnegie Mellon
9822d43f5aSsoda  * the rights to redistribute these changes.
9922d43f5aSsoda  */
10022d43f5aSsoda /*
10122d43f5aSsoda   Copyright 1988, 1989 by Intel Corporation, Santa Clara, California.
10222d43f5aSsoda 
10322d43f5aSsoda 		All Rights Reserved
10422d43f5aSsoda 
10522d43f5aSsoda Permission to use, copy, modify, and distribute this software and
10622d43f5aSsoda its documentation for any purpose and without fee is hereby
10722d43f5aSsoda granted, provided that the above copyright notice appears in all
10822d43f5aSsoda copies and that both the copyright notice and this permission notice
10922d43f5aSsoda appear in supporting documentation, and that the name of Intel
11022d43f5aSsoda not be used in advertising or publicity pertaining to distribution
11122d43f5aSsoda of the software without specific, written prior permission.
11222d43f5aSsoda 
11322d43f5aSsoda INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
11422d43f5aSsoda INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
11522d43f5aSsoda IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
11622d43f5aSsoda CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
11722d43f5aSsoda LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
11822d43f5aSsoda NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
11922d43f5aSsoda WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
12022d43f5aSsoda */
12122d43f5aSsoda 
122a4183603Slukem #include <sys/cdefs.h>
123*5c255dd2Sthorpej __KERNEL_RCSID(0, "$NetBSD: isabus.c,v 1.54 2023/12/07 03:46:10 thorpej Exp $");
124a4183603Slukem 
12522d43f5aSsoda #include <sys/param.h>
126564df9b6Ssoda #include <sys/proc.h>
12722d43f5aSsoda #include <sys/systm.h>
128b667a5a3Sthorpej #include <sys/callout.h>
12922d43f5aSsoda #include <sys/time.h>
13022d43f5aSsoda #include <sys/kernel.h>
13122d43f5aSsoda #include <sys/device.h>
1326f97a7c1Sthorpej #include <sys/kmem.h>
133*5c255dd2Sthorpej #include <sys/vmem_impl.h>
13447ef8ee9Smrg 
13547ef8ee9Smrg #include <uvm/uvm_extern.h>
13622d43f5aSsoda 
13722d43f5aSsoda #include <machine/cpu.h>
13822d43f5aSsoda #include <machine/pio.h>
13922d43f5aSsoda #include <machine/autoconf.h>
140564df9b6Ssoda #include <machine/intr.h>
14122d43f5aSsoda 
142bc7a643dStsutsui #include <mips/locore.h>
143bc7a643dStsutsui 
144ba6a3c6dSsoda #include <dev/ic/i8253reg.h>
14555472718Stsutsui #include <dev/ic/i8259reg.h>
14622d43f5aSsoda #include <dev/isa/isareg.h>
14722d43f5aSsoda #include <dev/isa/isavar.h>
148ba6a3c6dSsoda #include <arc/isa/isabrvar.h>
149564df9b6Ssoda #include <arc/isa/spkrreg.h>
15022d43f5aSsoda 
151bc7a643dStsutsui #include <arc/arc/timervar.h>
152bc7a643dStsutsui 
15322d43f5aSsoda static int beeping;
15488ab7da9Sad static callout_t sysbeep_ch;
15522d43f5aSsoda 
156*5c255dd2Sthorpej #define	ISA_MEM_BTAG_COUNT	VMEM_EST_BTCOUNT(1, 16)
157*5c255dd2Sthorpej #define	ISA_IO_BTAG_COUNT	VMEM_EST_BTCOUNT(1, 16)
158*5c255dd2Sthorpej 
159*5c255dd2Sthorpej static struct vmem isa_mem_arena_store;
160*5c255dd2Sthorpej static struct vmem isa_io_arena_store;
161*5c255dd2Sthorpej static struct vmem_btag isa_mem_btag_store[ISA_MEM_BTAG_COUNT];
162*5c255dd2Sthorpej static struct vmem_btag isa_io_btag_store[ISA_IO_BTAG_COUNT];
1637826bdceStsutsui 
164564df9b6Ssoda #define	IRQ_SLAVE	2
165564df9b6Ssoda 
166564df9b6Ssoda /* Definition of the driver for autoconfig. */
1670f31d9deStsutsui static int isabrprint(void *, const char *);
168564df9b6Ssoda 
169e5b560a3Ssoda extern struct arc_bus_space arc_bus_io, arc_bus_mem;
170e5b560a3Ssoda 
1710f31d9deStsutsui static void isabr_attach_hook(device_t , device_t,
1727fe2a5a0Stsutsui     struct isabus_attach_args *);
173d4b4af5dSdyoung static void isabr_detach_hook(isa_chipset_tag_t, device_t);
1740f31d9deStsutsui static const struct evcnt *isabr_intr_evcnt(isa_chipset_tag_t, int);
1750f31d9deStsutsui static void *isabr_intr_establish(isa_chipset_tag_t, int, int, int,
1767fe2a5a0Stsutsui     int (*)(void *), void *);
1770f31d9deStsutsui static void isabr_intr_disestablish(isa_chipset_tag_t, void*);
1780f31d9deStsutsui static void isabr_initicu(void);
1790f31d9deStsutsui static void intr_calculatemasks(void);
1800f31d9deStsutsui static int fakeintr(void *a);
181564df9b6Ssoda 
182ba6a3c6dSsoda struct isabr_config *isabr_conf = NULL;
1837fe2a5a0Stsutsui uint32_t imask[_IPL_N];	/* XXX */
184564df9b6Ssoda 
185564df9b6Ssoda void
isabrattach(struct isabr_softc * sc)1867fe2a5a0Stsutsui isabrattach(struct isabr_softc *sc)
187564df9b6Ssoda {
188564df9b6Ssoda 	struct isabus_attach_args iba;
189564df9b6Ssoda 
190ebf92f14She 	callout_init(&sysbeep_ch, 0);
19188ab7da9Sad 
192ba6a3c6dSsoda 	if (isabr_conf == NULL)
193ba6a3c6dSsoda 		panic("isabr_conf isn't initialized");
194ba6a3c6dSsoda 
1950f31d9deStsutsui 	aprint_normal("\n");
196564df9b6Ssoda 
197564df9b6Ssoda 	/* Initialize interrupt controller */
198564df9b6Ssoda 	isabr_initicu();
199564df9b6Ssoda 
2007c109ba7Ssoda 	sc->arc_isa_cs.ic_attach_hook = isabr_attach_hook;
201d4b4af5dSdyoung 	sc->arc_isa_cs.ic_detach_hook = isabr_detach_hook;
202cffb5808Scgd 	sc->arc_isa_cs.ic_intr_evcnt = isabr_intr_evcnt;
203564df9b6Ssoda 	sc->arc_isa_cs.ic_intr_establish = isabr_intr_establish;
204564df9b6Ssoda 	sc->arc_isa_cs.ic_intr_disestablish = isabr_intr_disestablish;
205564df9b6Ssoda 
206*5c255dd2Sthorpej 	arc_bus_space_init_arena(&arc_bus_mem, &isa_mem_arena_store,
207*5c255dd2Sthorpej 	    isa_mem_btag_store, ISA_MEM_BTAG_COUNT);
208*5c255dd2Sthorpej 	arc_bus_space_init_arena(&arc_bus_io, &isa_io_arena_store,
209*5c255dd2Sthorpej 	    isa_io_btag_store, ISA_IO_BTAG_COUNT);
2107826bdceStsutsui 
2117c109ba7Ssoda 	iba.iba_iot = &arc_bus_io;
2127c109ba7Ssoda 	iba.iba_memt = &arc_bus_mem;
2137c109ba7Ssoda 	iba.iba_dmat = &sc->sc_dmat;
214564df9b6Ssoda 	iba.iba_ic = &sc->arc_isa_cs;
2152685996bSthorpej 	config_found(sc->sc_dev, &iba, isabrprint,
216c7fb772bSthorpej 	    CFARGS(.iattr = "isabus"));
217564df9b6Ssoda }
218564df9b6Ssoda 
2190f31d9deStsutsui static int
isabrprint(void * aux,const char * pnp)2207fe2a5a0Stsutsui isabrprint(void *aux, const char *pnp)
221564df9b6Ssoda {
222564df9b6Ssoda 
223564df9b6Ssoda         if (pnp)
22446289e1fSdrochner                 aprint_normal("isa at %s", pnp);
2257cce9d88Smatt         aprint_verbose(" isa_io_base 0x%"PRIxVADDR" isa_mem_base 0x%"PRIxVADDR,
226e5b560a3Ssoda 	    arc_bus_io.bs_vbase, arc_bus_mem.bs_vbase);
2270f31d9deStsutsui         return UNCONF;
228564df9b6Ssoda }
229564df9b6Ssoda 
230564df9b6Ssoda 
231564df9b6Ssoda /*
232564df9b6Ssoda  *	Interrupt system driver code
233564df9b6Ssoda  *	============================
234564df9b6Ssoda  */
235564df9b6Ssoda #define LEGAL_IRQ(x)    ((x) >= 0 && (x) < ICU_LEN && (x) != 2)
236564df9b6Ssoda 
237564df9b6Ssoda int	imen;
238564df9b6Ssoda int	intrtype[ICU_LEN], intrmask[ICU_LEN], intrlevel[ICU_LEN];
2390f6618f0Stsutsui struct isa_intrhand *isa_intrhand[ICU_LEN];
240564df9b6Ssoda 
2410f31d9deStsutsui static int
fakeintr(void * a)2420f31d9deStsutsui fakeintr(void *a)
243564df9b6Ssoda {
2447fe2a5a0Stsutsui 
245564df9b6Ssoda 	return 0;
246564df9b6Ssoda }
247564df9b6Ssoda 
248564df9b6Ssoda /*
249564df9b6Ssoda  * Recalculate the interrupt masks from scratch.
250564df9b6Ssoda  * We could code special registry and deregistry versions of this function that
251564df9b6Ssoda  * would be faster, but the code would be nastier, and we don't expect this to
252564df9b6Ssoda  * happen very much anyway.
253564df9b6Ssoda  */
2540f31d9deStsutsui static void
intr_calculatemasks(void)2557fe2a5a0Stsutsui intr_calculatemasks(void)
256564df9b6Ssoda {
257564df9b6Ssoda 	int irq, level;
2580f6618f0Stsutsui 	struct isa_intrhand *q;
259564df9b6Ssoda 
260564df9b6Ssoda 	/* First, figure out which levels each IRQ uses. */
261564df9b6Ssoda 	for (irq = 0; irq < ICU_LEN; irq++) {
2628e19dfb2Stsutsui 		int levels = 0;
2630f6618f0Stsutsui 		for (q = isa_intrhand[irq]; q; q = q->ih_next)
264564df9b6Ssoda 			levels |= 1 << q->ih_level;
265564df9b6Ssoda 		intrlevel[irq] = levels;
266564df9b6Ssoda 	}
267564df9b6Ssoda 
268564df9b6Ssoda 	/* Then figure out which IRQs use each level. */
26951260decStsutsui 	for (level = 0; level < _IPL_N; level++) {
2708e19dfb2Stsutsui 		int irqs = 0;
271564df9b6Ssoda 		for (irq = 0; irq < ICU_LEN; irq++)
272564df9b6Ssoda 			if (intrlevel[irq] & (1 << level))
273564df9b6Ssoda 				irqs |= 1 << irq;
27451260decStsutsui 		imask[level] = irqs;
275564df9b6Ssoda 	}
276564df9b6Ssoda 
27751260decStsutsui 	imask[IPL_NONE] = 0;
27851260decStsutsui 
2794b293a84Sad 	imask[IPL_SOFTCLOCK] |= imask[IPL_NONE];
28051260decStsutsui 	imask[IPL_SOFTNET] |= imask[IPL_SOFTCLOCK];
281564df9b6Ssoda 
282564df9b6Ssoda 	/*
283564df9b6Ssoda 	 * Enforce a hierarchy that gives slow devices a better chance at not
284564df9b6Ssoda 	 * dropping data.
285564df9b6Ssoda 	 */
2864b293a84Sad 	imask[IPL_VM] |= imask[IPL_SOFTNET];
287564df9b6Ssoda 
288564df9b6Ssoda 	/*
28951260decStsutsui 	 * Since run queues may be manipulated by both the statclock and tty,
29051260decStsutsui 	 * network, and diskdrivers, clock > tty.
291564df9b6Ssoda 	 */
2924b293a84Sad 	imask[IPL_SCHED] |= imask[IPL_VM];
293564df9b6Ssoda 
294564df9b6Ssoda 	/* And eventually calculate the complete masks. */
295564df9b6Ssoda 	for (irq = 0; irq < ICU_LEN; irq++) {
2968e19dfb2Stsutsui 		int irqs = 1 << irq;
2970f6618f0Stsutsui 		for (q = isa_intrhand[irq]; q; q = q->ih_next)
298564df9b6Ssoda 			irqs |= imask[q->ih_level];
29951260decStsutsui 		intrmask[irq] = irqs;
300564df9b6Ssoda 	}
301564df9b6Ssoda 
302564df9b6Ssoda 	/* Lastly, determine which IRQs are actually in use. */
303564df9b6Ssoda 	{
3048e19dfb2Stsutsui 		int irqs = 0;
305564df9b6Ssoda 		for (irq = 0; irq < ICU_LEN; irq++)
3060f6618f0Stsutsui 			if (isa_intrhand[irq])
307564df9b6Ssoda 				irqs |= 1 << irq;
308564df9b6Ssoda 		if (irqs >= 0x100) /* any IRQs >= 8 in use */
309564df9b6Ssoda 			irqs |= 1 << IRQ_SLAVE;
310564df9b6Ssoda 		imen = ~irqs;
31155472718Stsutsui 		isa_outb(IO_ICU1 + PIC_OCW1, imen);
31255472718Stsutsui 		isa_outb(IO_ICU2 + PIC_OCW1, imen >> 8);
313564df9b6Ssoda 	}
314564df9b6Ssoda }
315564df9b6Ssoda 
3160f31d9deStsutsui static void
isabr_attach_hook(device_t parent,device_t self,struct isabus_attach_args * iba)317cbab9cadSchs isabr_attach_hook(device_t parent, device_t self,
3187fe2a5a0Stsutsui     struct isabus_attach_args *iba)
3197c109ba7Ssoda {
3207c109ba7Ssoda 
3217c109ba7Ssoda 	/* Nothing to do. */
3227c109ba7Ssoda }
3237c109ba7Ssoda 
324d4b4af5dSdyoung static void
isabr_detach_hook(isa_chipset_tag_t ic,device_t self)325d4b4af5dSdyoung isabr_detach_hook(isa_chipset_tag_t ic, device_t self)
326d4b4af5dSdyoung {
327d4b4af5dSdyoung 
328d4b4af5dSdyoung 	/* Nothing to do. */
329d4b4af5dSdyoung }
330d4b4af5dSdyoung 
3310f31d9deStsutsui static const struct evcnt *
isabr_intr_evcnt(isa_chipset_tag_t ic,int irq)3327fe2a5a0Stsutsui isabr_intr_evcnt(isa_chipset_tag_t ic, int irq)
333cffb5808Scgd {
334cffb5808Scgd 
335cffb5808Scgd 	/* XXX for now, no evcnt parent reported */
336cffb5808Scgd 	return NULL;
337cffb5808Scgd }
338cffb5808Scgd 
339564df9b6Ssoda /*
340564df9b6Ssoda  *	Establish a ISA bus interrupt.
341564df9b6Ssoda  */
3420f31d9deStsutsui static void *
isabr_intr_establish(isa_chipset_tag_t ic,int irq,int type,int level,int (* ih_fun)(void *),void * ih_arg)3437fe2a5a0Stsutsui isabr_intr_establish(isa_chipset_tag_t ic, int irq, int type, int level,
3447fe2a5a0Stsutsui     int (*ih_fun)(void *), void *ih_arg)
345564df9b6Ssoda {
3460f6618f0Stsutsui 	struct isa_intrhand **p, *q, *ih;
3470f6618f0Stsutsui 	static struct isa_intrhand fakehand = {NULL, fakeintr};
348564df9b6Ssoda 
3496f97a7c1Sthorpej 	ih = kmem_alloc(sizeof *ih, KM_SLEEP);
350564df9b6Ssoda 
351564df9b6Ssoda 	if (!LEGAL_IRQ(irq) || type == IST_NONE)
352564df9b6Ssoda 		panic("intr_establish: bogus irq or type");
353564df9b6Ssoda 
354564df9b6Ssoda 	switch (intrtype[irq]) {
3555c69b735Stsutsui 	case IST_NONE:
3565c69b735Stsutsui 		intrtype[irq] = type;
3575c69b735Stsutsui 		break;
358564df9b6Ssoda 	case IST_EDGE:
359564df9b6Ssoda 	case IST_LEVEL:
360564df9b6Ssoda 		if (type == intrtype[irq])
361564df9b6Ssoda 			break;
362564df9b6Ssoda 	case IST_PULSE:
363564df9b6Ssoda 		if (type != IST_NONE)
364564df9b6Ssoda 			panic("intr_establish: can't share %s with %s",
365564df9b6Ssoda 			    isa_intr_typename(intrtype[irq]),
366564df9b6Ssoda 			    isa_intr_typename(type));
367564df9b6Ssoda 		break;
368564df9b6Ssoda 	}
369564df9b6Ssoda 
370564df9b6Ssoda 	/*
371564df9b6Ssoda 	 * Figure out where to put the handler.
372564df9b6Ssoda 	 * This is O(N^2), but we want to preserve the order, and N is
373564df9b6Ssoda 	 * generally small.
374564df9b6Ssoda 	 */
3750f6618f0Stsutsui 	for (p = &isa_intrhand[irq]; (q = *p) != NULL; p = &q->ih_next)
376564df9b6Ssoda 		;
377564df9b6Ssoda 
378564df9b6Ssoda 	/*
379564df9b6Ssoda 	 * Actually install a fake handler momentarily, since we might be doing
380564df9b6Ssoda 	 * this with interrupts enabled and don't want the real routine called
381564df9b6Ssoda 	 * until masking is set up.
382564df9b6Ssoda 	 */
383564df9b6Ssoda 	fakehand.ih_level = level;
384564df9b6Ssoda 	*p = &fakehand;
385564df9b6Ssoda 
386564df9b6Ssoda 	intr_calculatemasks();
387564df9b6Ssoda 
388564df9b6Ssoda 	/*
389564df9b6Ssoda 	 * Poke the real handler in now.
390564df9b6Ssoda 	 */
391564df9b6Ssoda 	ih->ih_fun = ih_fun;
392564df9b6Ssoda 	ih->ih_arg = ih_arg;
393564df9b6Ssoda 	ih->ih_count = 0;
394564df9b6Ssoda 	ih->ih_next = NULL;
395564df9b6Ssoda 	ih->ih_level = level;
396564df9b6Ssoda 	ih->ih_irq = irq;
3975c40f381Stsutsui 	snprintf(ih->ih_evname, sizeof(ih->ih_evname), "irq %d", irq);
3985c40f381Stsutsui 	evcnt_attach_dynamic(&ih->ih_evcnt, EVCNT_TYPE_INTR, NULL, "isa",
3995c40f381Stsutsui 	    ih->ih_evname);
400564df9b6Ssoda 	*p = ih;
401564df9b6Ssoda 
4027fe2a5a0Stsutsui 	return ih;
403564df9b6Ssoda }
404564df9b6Ssoda 
4050f31d9deStsutsui static void
isabr_intr_disestablish(isa_chipset_tag_t ic,void * arg)4067fe2a5a0Stsutsui isabr_intr_disestablish(isa_chipset_tag_t ic, void *arg)
407564df9b6Ssoda {
408564df9b6Ssoda 
409564df9b6Ssoda }
410564df9b6Ssoda 
411564df9b6Ssoda /*
412564df9b6Ssoda  *	Process an interrupt from the ISA bus.
413564df9b6Ssoda  */
4147310abdeStsutsui uint32_t
isabr_iointr(uint32_t mask,struct clockframe * cf)4157310abdeStsutsui isabr_iointr(uint32_t mask, struct clockframe *cf)
416564df9b6Ssoda {
4170f6618f0Stsutsui 	struct isa_intrhand *ih;
418564df9b6Ssoda 	int isa_vector;
419564df9b6Ssoda 	int o_imen;
420564df9b6Ssoda 
421ba6a3c6dSsoda 	isa_vector = (*isabr_conf->ic_intr_status)();
422ba6a3c6dSsoda 	if (isa_vector < 0)
4231a5b627bStsutsui 		return 0;
424564df9b6Ssoda 
425564df9b6Ssoda 	o_imen = imen;
426564df9b6Ssoda 	imen |= 1 << (isa_vector & (ICU_LEN - 1));
427564df9b6Ssoda 	if (isa_vector & 0x08) {
42855472718Stsutsui 		isa_inb(IO_ICU2 + PIC_OCW1);
42955472718Stsutsui 		isa_outb(IO_ICU2 + PIC_OCW1, imen >> 8);
43055472718Stsutsui 		isa_outb(IO_ICU2 + PIC_OCW2,
43155472718Stsutsui 		    OCW2_SELECT | OCW2_EOI | OCW2_SL |
43255472718Stsutsui 		    OCW2_ILS((isa_vector & 7)));
43355472718Stsutsui 		isa_outb(IO_ICU1,
43455472718Stsutsui 		    OCW2_SELECT | OCW2_EOI | OCW2_SL | IRQ_SLAVE);
4357fe2a5a0Stsutsui 	} else {
43655472718Stsutsui 		isa_inb(IO_ICU1 + PIC_OCW1);
43755472718Stsutsui 		isa_outb(IO_ICU1 + PIC_OCW1, imen);
43855472718Stsutsui 		isa_outb(IO_ICU1 + PIC_OCW2,
43955472718Stsutsui 		    OCW2_SELECT | OCW2_EOI | OCW2_SL | OCW2_ILS(isa_vector));
440564df9b6Ssoda 	}
4410f6618f0Stsutsui 	ih = isa_intrhand[isa_vector];
442114eee64Stsutsui 	if (isa_vector == 0 && ih) {	/* Clock */	/*XXX*/
443bc7a643dStsutsui 		last_cp0_count = mips3_cp0_count_read();
44404595a48Stsutsui 		/* XXX: spllowerclock() not allowed */
44504595a48Stsutsui 		cf->sr &= ~MIPS_SR_INT_IE;
4465c40f381Stsutsui 		if ((*ih->ih_fun)(cf))
4475c40f381Stsutsui 			ih->ih_evcnt.ev_count++;
448564df9b6Ssoda 		ih = ih->ih_next;
449564df9b6Ssoda 	}
450564df9b6Ssoda 	while (ih) {
4515c40f381Stsutsui 		if ((*ih->ih_fun)(ih->ih_arg))
4525c40f381Stsutsui 			ih->ih_evcnt.ev_count++;
453564df9b6Ssoda 		ih = ih->ih_next;
454564df9b6Ssoda 	}
455564df9b6Ssoda 	imen = o_imen;
45655472718Stsutsui 	isa_inb(IO_ICU1 + PIC_OCW1);
45755472718Stsutsui 	isa_inb(IO_ICU2 + PIC_OCW1);
45855472718Stsutsui 	isa_outb(IO_ICU1 + PIC_OCW1, imen);
45955472718Stsutsui 	isa_outb(IO_ICU2 + PIC_OCW1, imen >> 8);
460564df9b6Ssoda 
4614f59bf75Stsutsui 	return MIPS_INT_MASK_2;
462564df9b6Ssoda }
463564df9b6Ssoda 
464564df9b6Ssoda 
465564df9b6Ssoda /*
466564df9b6Ssoda  * Initialize the Interrupt controller logic.
467564df9b6Ssoda  */
4680f31d9deStsutsui static void
isabr_initicu(void)4697fe2a5a0Stsutsui isabr_initicu(void)
470564df9b6Ssoda {
471564df9b6Ssoda 
4725c69b735Stsutsui 	int i;
4735c69b735Stsutsui 
4745c69b735Stsutsui 	for (i = 0; i < ICU_LEN; i++) {
4755c69b735Stsutsui 		switch (i) {
4765c69b735Stsutsui 		case 2:
4775c69b735Stsutsui 		case 8:
4785c69b735Stsutsui 			intrtype[i] = IST_EDGE;
4795c69b735Stsutsui 			break;
4805c69b735Stsutsui 		default:
4815c69b735Stsutsui 			intrtype[i] = IST_NONE;
4825c69b735Stsutsui 			break;
4835c69b735Stsutsui 		}
4845c69b735Stsutsui 	}
4855c69b735Stsutsui 
48655472718Stsutsui 	/* reset; program device, four bytes */
48755472718Stsutsui 	isa_outb(IO_ICU1 + PIC_ICW1, ICW1_SELECT | ICW1_IC4);
48855472718Stsutsui 	/* starting at this vector index */
48955472718Stsutsui 	isa_outb(IO_ICU1 + PIC_ICW2, 0);
49055472718Stsutsui 	/* slave on line 2 */
49155472718Stsutsui 	isa_outb(IO_ICU1 + PIC_ICW3, ICW3_CASCADE(IRQ_SLAVE));
49255472718Stsutsui 	/* 8086 mode */
49355472718Stsutsui 	isa_outb(IO_ICU1 + PIC_ICW4, ICW4_8086);
49455472718Stsutsui 
49555472718Stsutsui 	/* leave interrupts masked */
49655472718Stsutsui 	isa_outb(IO_ICU1 + PIC_OCW1, 0xff);
49755472718Stsutsui 
49855472718Stsutsui 	/* special mask mode (if available) */
49955472718Stsutsui 	isa_outb(IO_ICU1 + PIC_OCW3, OCW3_SELECT | OCW3_SSMM | OCW3_SMM);
50055472718Stsutsui 	/* Read IRR by default. */
50155472718Stsutsui 	isa_outb(IO_ICU1 + PIC_OCW3, OCW3_SELECT | OCW3_RR);
502564df9b6Ssoda #ifdef REORDER_IRQ
50355472718Stsutsui 	/* pri order 3-7, 0-2 (com2 first) */
50455472718Stsutsui 	isa_outb(IO_ICU1 + PIC_OCW2,
50555472718Stsutsui 	    OCW2_SELECT | OCW2_R | OCW2_SL OCW2_ILS(3 - 1));
506564df9b6Ssoda #endif
507564df9b6Ssoda 
50855472718Stsutsui 	/* reset; program device, four bytes */
50955472718Stsutsui 	isa_outb(IO_ICU2 + PIC_ICW1, ICW1_SELECT | ICW1_IC4);
51055472718Stsutsui 	/* staring at this vector index */
51155472718Stsutsui 	isa_outb(IO_ICU2 + PIC_ICW2, 8);
51255472718Stsutsui 	/* slave connected to line 2 of master */
51355472718Stsutsui 	isa_outb(IO_ICU2 + PIC_ICW3, ICW3_SIC(IRQ_SLAVE));
51455472718Stsutsui 	/* 8086 mode */
51555472718Stsutsui 	isa_outb(IO_ICU2 + PIC_ICW4, ICW4_8086);
51655472718Stsutsui 
51755472718Stsutsui 	/* leave interrupts masked */
51855472718Stsutsui 	isa_outb(IO_ICU2 + PIC_OCW1, 0xff);
51955472718Stsutsui 
52055472718Stsutsui 	/* special mask mode (if available) */
52155472718Stsutsui 	isa_outb(IO_ICU2 + PIC_OCW3, OCW3_SELECT | OCW3_SSMM | OCW3_SMM);
52255472718Stsutsui 	/* Read IRR by default. */
52355472718Stsutsui 	isa_outb(IO_ICU2 + PIC_OCW3, OCW3_SELECT | OCW3_RR);
524564df9b6Ssoda }
525564df9b6Ssoda 
526564df9b6Ssoda 
527564df9b6Ssoda /*
528564df9b6Ssoda  *	SPEAKER BEEPER...
529564df9b6Ssoda  */
53022d43f5aSsoda void
sysbeepstop(void * arg)5317fe2a5a0Stsutsui sysbeepstop(void *arg)
53222d43f5aSsoda {
53322d43f5aSsoda 	int s;
53422d43f5aSsoda 
53522d43f5aSsoda 	/* disable counter 2 */
53622d43f5aSsoda 	s = splhigh();
53722d43f5aSsoda 	isa_outb(PITAUX_PORT, isa_inb(PITAUX_PORT) & ~PIT_SPKR);
53822d43f5aSsoda 	splx(s);
53922d43f5aSsoda 	beeping = 0;
54022d43f5aSsoda }
54122d43f5aSsoda 
54222d43f5aSsoda void
sysbeep(int pitch,int period)5437fe2a5a0Stsutsui sysbeep(int pitch, int period)
54422d43f5aSsoda {
54522d43f5aSsoda 	static int last_pitch, last_period;
54622d43f5aSsoda 	int s;
547564df9b6Ssoda 
548564df9b6Ssoda 	if (cold)
549564df9b6Ssoda 		return;		/* Can't beep yet. */
55022d43f5aSsoda 
55122d43f5aSsoda 	if (beeping)
552b667a5a3Sthorpej 		callout_stop(&sysbeep_ch);
55322d43f5aSsoda 	if (!beeping || last_pitch != pitch) {
55422d43f5aSsoda 		s = splhigh();
555564df9b6Ssoda 		isa_outb(IO_TIMER1 + TIMER_MODE,
556564df9b6Ssoda 		    TIMER_SEL2 | TIMER_16BIT | TIMER_SQWAVE);
557564df9b6Ssoda 		isa_outb(IO_TIMER1 + TIMER_CNTR2, TIMER_DIV(pitch) % 256);
558564df9b6Ssoda 		isa_outb(IO_TIMER1 + TIMER_CNTR2, TIMER_DIV(pitch) / 256);
55922d43f5aSsoda 		isa_outb(PITAUX_PORT, isa_inb(PITAUX_PORT) | PIT_SPKR);
56022d43f5aSsoda 		splx(s);
56122d43f5aSsoda 	}
56222d43f5aSsoda 	last_pitch = pitch;
56322d43f5aSsoda 	beeping = last_period = period;
564b667a5a3Sthorpej 	callout_reset(&sysbeep_ch, period, sysbeepstop, NULL);
56522d43f5aSsoda }
566afa910a4Stsutsui 
567afa910a4Stsutsui int
isa_intr_alloc(isa_chipset_tag_t c,int mask,int type,int * irq_p)568afa910a4Stsutsui isa_intr_alloc(isa_chipset_tag_t c, int mask, int type, int *irq_p)
569afa910a4Stsutsui {
570afa910a4Stsutsui 	int irq;
571afa910a4Stsutsui 	int maybe_irq = -1;
572afa910a4Stsutsui 	int shared_depth = 0;
573afa910a4Stsutsui 	mask &= 0x8b28; /* choose from 3, 5, 8, 9, 11, 15 XXX */
574afa910a4Stsutsui 	for (irq = 0; mask != 0; mask >>= 1, irq++) {
575afa910a4Stsutsui 		if ((mask & 1) == 0)
576afa910a4Stsutsui 			continue;
577afa910a4Stsutsui 		if (intrtype[irq] == IST_NONE) {
578afa910a4Stsutsui 			*irq_p = irq;
579afa910a4Stsutsui 			return 0;
580afa910a4Stsutsui 		}
581afa910a4Stsutsui 		/* Level interrupts can be shared */
582afa910a4Stsutsui 		if (type == IST_LEVEL && intrtype[irq] == IST_LEVEL) {
5830f6618f0Stsutsui 			struct isa_intrhand *ih = isa_intrhand[irq];
584afa910a4Stsutsui 			int depth;
585afa910a4Stsutsui 			if (maybe_irq == -1) {
586afa910a4Stsutsui  				maybe_irq = irq;
587afa910a4Stsutsui 				continue;
588afa910a4Stsutsui 			}
589afa910a4Stsutsui 			for (depth = 0; ih != NULL; ih = ih->ih_next)
590afa910a4Stsutsui 				depth++;
591afa910a4Stsutsui 			if (depth < shared_depth) {
592afa910a4Stsutsui 				maybe_irq = irq;
593afa910a4Stsutsui 				shared_depth = depth;
594afa910a4Stsutsui 			}
595afa910a4Stsutsui 		}
596afa910a4Stsutsui 	}
597afa910a4Stsutsui 	if (maybe_irq != -1) {
598afa910a4Stsutsui 		*irq_p = maybe_irq;
599afa910a4Stsutsui 		return 0;
600afa910a4Stsutsui 	}
601afa910a4Stsutsui 	return 1;
602afa910a4Stsutsui }
603