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