xref: /netbsd-src/sys/arch/algor/pci/pcib.c (revision a5175f1e986253dff5bbe596a6ad8c22a091e4b6)
1*a5175f1eSandvar /*	$NetBSD: pcib.c,v 1.29 2024/02/08 20:11:55 andvar Exp $	*/
216b9c606Sthorpej 
316b9c606Sthorpej /*-
416b9c606Sthorpej  * Copyright (c) 2000, 2001 The NetBSD Foundation, Inc.
516b9c606Sthorpej  * All rights reserved.
616b9c606Sthorpej  *
716b9c606Sthorpej  * This code is derived from software contributed to The NetBSD Foundation
816b9c606Sthorpej  * by Jason R. Thorpe.
916b9c606Sthorpej  *
1016b9c606Sthorpej  * Redistribution and use in source and binary forms, with or without
1116b9c606Sthorpej  * modification, are permitted provided that the following conditions
1216b9c606Sthorpej  * are met:
1316b9c606Sthorpej  * 1. Redistributions of source code must retain the above copyright
1416b9c606Sthorpej  *    notice, this list of conditions and the following disclaimer.
1516b9c606Sthorpej  * 2. Redistributions in binary form must reproduce the above copyright
1616b9c606Sthorpej  *    notice, this list of conditions and the following disclaimer in the
1716b9c606Sthorpej  *    documentation and/or other materials provided with the distribution.
1816b9c606Sthorpej  *
1916b9c606Sthorpej  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
2016b9c606Sthorpej  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
2116b9c606Sthorpej  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2216b9c606Sthorpej  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
2316b9c606Sthorpej  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2416b9c606Sthorpej  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2516b9c606Sthorpej  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2616b9c606Sthorpej  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2716b9c606Sthorpej  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2816b9c606Sthorpej  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2916b9c606Sthorpej  * POSSIBILITY OF SUCH DAMAGE.
3016b9c606Sthorpej  */
3116b9c606Sthorpej 
3216b9c606Sthorpej #include <sys/cdefs.h>			/* RCS ID & Copyright macro defns */
3316b9c606Sthorpej 
34*a5175f1eSandvar __KERNEL_RCSID(0, "$NetBSD: pcib.c,v 1.29 2024/02/08 20:11:55 andvar Exp $");
3516b9c606Sthorpej 
3616b9c606Sthorpej #include "opt_algor_p5064.h"
3716b9c606Sthorpej #include "opt_algor_p6032.h"
3816b9c606Sthorpej 
3916b9c606Sthorpej #include <sys/param.h>
40e265f67bSdyoung #include <sys/bus.h>
41f5439ed7Smatt #include <sys/device.h>
42f5439ed7Smatt #include <sys/intr.h>
43f5439ed7Smatt #include <sys/kernel.h>
44ae873cf0Sthorpej #include <sys/kmem.h>
45f5439ed7Smatt #include <sys/systm.h>
46f5439ed7Smatt 
47f5439ed7Smatt #include <algor/autoconf.h>
4816b9c606Sthorpej 
497c074dc8Sthorpej #include <dev/isa/isareg.h>
5016b9c606Sthorpej #include <dev/isa/isavar.h>
5116b9c606Sthorpej 
5216b9c606Sthorpej #include <dev/pci/pcireg.h>
5316b9c606Sthorpej #include <dev/pci/pcivar.h>
5416b9c606Sthorpej #include <dev/pci/pcidevs.h>
5516b9c606Sthorpej 
56f3410434Sthorpej #include <dev/ic/i8259reg.h>
57f3410434Sthorpej 
5816b9c606Sthorpej #ifdef ALGOR_P5064
5916b9c606Sthorpej #include <algor/algor/algor_p5064var.h>
6016b9c606Sthorpej #endif
6116b9c606Sthorpej 
6216b9c606Sthorpej #ifdef ALGOR_P6032
6316b9c606Sthorpej #include <algor/algor/algor_p6032var.h>
6416b9c606Sthorpej #endif
6516b9c606Sthorpej 
66eee38be7Smatt const char * const pcib_intrnames[16] = {
677c074dc8Sthorpej 	"irq 0",
687c074dc8Sthorpej 	"irq 1",
697c074dc8Sthorpej 	"irq 2",
707c074dc8Sthorpej 	"irq 3",
717c074dc8Sthorpej 	"irq 4",
727c074dc8Sthorpej 	"irq 5",
737c074dc8Sthorpej 	"irq 6",
747c074dc8Sthorpej 	"irq 7",
757c074dc8Sthorpej 	"irq 8",
767c074dc8Sthorpej 	"irq 9",
777c074dc8Sthorpej 	"irq 10",
787c074dc8Sthorpej 	"irq 11",
797c074dc8Sthorpej 	"irq 12",
807c074dc8Sthorpej 	"irq 13",
817c074dc8Sthorpej 	"irq 14",
827c074dc8Sthorpej 	"irq 15",
837c074dc8Sthorpej };
847c074dc8Sthorpej 
857c074dc8Sthorpej struct pcib_intrhead {
86f5439ed7Smatt 	LIST_HEAD(, evbmips_intrhand) intr_q;
877c074dc8Sthorpej 	struct evcnt intr_count;
887c074dc8Sthorpej 	int intr_type;
897c074dc8Sthorpej };
9016b9c606Sthorpej 
9116b9c606Sthorpej struct pcib_softc {
92f5439ed7Smatt 	device_t	sc_dev;
937c074dc8Sthorpej 
947c074dc8Sthorpej 	bus_space_tag_t	sc_iot;
957c074dc8Sthorpej 	bus_space_handle_t sc_ioh_icu1;
967c074dc8Sthorpej 	bus_space_handle_t sc_ioh_icu2;
977c074dc8Sthorpej 	bus_space_handle_t sc_ioh_elcr;
987c074dc8Sthorpej 
99eee38be7Smatt 	struct mips_isa_chipset sc_ic;
1007c074dc8Sthorpej 
1017c074dc8Sthorpej 	struct pcib_intrhead sc_intrtab[16];
1027c074dc8Sthorpej 
103f3410434Sthorpej 	u_int16_t	sc_imask;
1047c074dc8Sthorpej 	u_int16_t	sc_elcr;
1057c074dc8Sthorpej 
1067c074dc8Sthorpej #if defined(ALGOR_P5064)
1077c074dc8Sthorpej 	isa_chipset_tag_t sc_parent_ic;
1087c074dc8Sthorpej #endif
1097c074dc8Sthorpej 
110f3410434Sthorpej 	u_int16_t	sc_reserved;
111f3410434Sthorpej 
1127c074dc8Sthorpej 	void		*sc_ih;
11316b9c606Sthorpej };
11416b9c606Sthorpej 
115f5439ed7Smatt int	pcib_match(device_t, cfdata_t, void *);
116f5439ed7Smatt void	pcib_attach(device_t, device_t, void *);
11716b9c606Sthorpej 
118f5439ed7Smatt CFATTACH_DECL_NEW(pcib, sizeof(struct pcib_softc),
1195a9ddc14Sthorpej     pcib_match, pcib_attach, NULL, NULL);
12016b9c606Sthorpej 
121f5439ed7Smatt void	pcib_isa_attach_hook(device_t, device_t, struct isabus_attach_args *);
12222b3444cSdyoung void	pcib_isa_detach_hook(isa_chipset_tag_t, device_t);
12316b9c606Sthorpej 
1247c074dc8Sthorpej int	pcib_intr(void *);
1257c074dc8Sthorpej 
126f5439ed7Smatt void	pcib_bridge_callback(device_t);
12716b9c606Sthorpej 
1287c074dc8Sthorpej const struct evcnt *pcib_isa_intr_evcnt(void *, int);
1297c074dc8Sthorpej void	*pcib_isa_intr_establish(void *, int, int, int,
1307c074dc8Sthorpej 	    int (*)(void *), void *);
1317c074dc8Sthorpej void	pcib_isa_intr_disestablish(void *, void *);
1327c074dc8Sthorpej int	pcib_isa_intr_alloc(void *, int, int, int *);
1337c074dc8Sthorpej 
1347c074dc8Sthorpej void	pcib_set_icus(struct pcib_softc *);
1357c074dc8Sthorpej 
13616b9c606Sthorpej int
pcib_match(device_t parent,cfdata_t match,void * aux)137f5439ed7Smatt pcib_match(device_t parent, cfdata_t match, void *aux)
13816b9c606Sthorpej {
13916b9c606Sthorpej 	struct pci_attach_args *pa = aux;
14016b9c606Sthorpej 
14116b9c606Sthorpej 	if (PCI_CLASS(pa->pa_class) == PCI_CLASS_BRIDGE &&
14216b9c606Sthorpej 	    PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_BRIDGE_ISA)
14316b9c606Sthorpej 		return (1);
14416b9c606Sthorpej 
14516b9c606Sthorpej 	return (0);
14616b9c606Sthorpej }
14716b9c606Sthorpej 
14816b9c606Sthorpej void
pcib_attach(device_t parent,device_t self,void * aux)149f5439ed7Smatt pcib_attach(device_t parent, device_t self, void *aux)
15016b9c606Sthorpej {
151f5439ed7Smatt 	struct pcib_softc *sc = device_private(self);
15216b9c606Sthorpej 	struct pci_attach_args *pa = aux;
15316b9c606Sthorpej 	char devinfo[256];
1547c074dc8Sthorpej 	int i;
15516b9c606Sthorpej 
15661230437Sitojun 	pci_devinfo(pa->pa_id, pa->pa_class, 0, devinfo, sizeof(devinfo));
157f5439ed7Smatt 	aprint_normal(": %s (rev. 0x%02x)\n", devinfo,
15816b9c606Sthorpej 	    PCI_REVISION(pa->pa_class));
15916b9c606Sthorpej 
160f5439ed7Smatt 	sc->sc_dev = self;
1617c074dc8Sthorpej 	sc->sc_iot = pa->pa_iot;
1627c074dc8Sthorpej 
1637c074dc8Sthorpej 	/*
1647c074dc8Sthorpej 	 * Map the PIC/ELCR registers.
1657c074dc8Sthorpej 	 */
1667c074dc8Sthorpej 	if (bus_space_map(sc->sc_iot, 0x4d0, 2, 0, &sc->sc_ioh_elcr) != 0)
167f5439ed7Smatt 		aprint_error_dev(self, "unable to map ELCR registers\n");
1687c074dc8Sthorpej 	if (bus_space_map(sc->sc_iot, IO_ICU1, 2, 0, &sc->sc_ioh_icu1) != 0)
169f5439ed7Smatt 		aprint_error_dev(self, "unable to map ICU1 registers\n");
1707c074dc8Sthorpej 	if (bus_space_map(sc->sc_iot, IO_ICU2, 2, 0, &sc->sc_ioh_icu2) != 0)
171f5439ed7Smatt 		aprint_error_dev(self, "unable to map ICU2 registers\n");
1727c074dc8Sthorpej 
173f3410434Sthorpej 	/* All interrupts default to "masked off". */
174f3410434Sthorpej 	sc->sc_imask = 0xffff;
175f3410434Sthorpej 
176f3410434Sthorpej 	/* All interrupts default to edge-triggered. */
177f3410434Sthorpej 	sc->sc_elcr = 0;
178f3410434Sthorpej 
1797c074dc8Sthorpej 	/*
1807c074dc8Sthorpej 	 * Initialize the 8259s.
1817c074dc8Sthorpej 	 */
1827c074dc8Sthorpej 
183f3410434Sthorpej 	/* reset, program device, 4 bytes */
184f3410434Sthorpej 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_ICW1,
1851ce7119fSthorpej 	    ICW1_SELECT | ICW1_IC4);
186f3410434Sthorpej 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_ICW2,
1870c37c9e8Sthorpej 	    ICW2_VECTOR(0)/*XXX*/);
188f3410434Sthorpej 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_ICW3,
1891ce7119fSthorpej 	    ICW3_CASCADE(2));
190f3410434Sthorpej 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_ICW4,
191f3410434Sthorpej 	    ICW4_8086);
1927c074dc8Sthorpej 
193f3410434Sthorpej 	/* mask all interrupts */
194f3410434Sthorpej 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW1,
195f3410434Sthorpej 	    sc->sc_imask & 0xff);
1967c074dc8Sthorpej 
197f3410434Sthorpej 	/* enable special mask mode */
198f3410434Sthorpej 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW3,
1991ce7119fSthorpej 	    OCW3_SELECT | OCW3_SSMM | OCW3_SMM);
2007c074dc8Sthorpej 
201f3410434Sthorpej 	/* read IRR by default */
202f3410434Sthorpej 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW3,
2031ce7119fSthorpej 	    OCW3_SELECT | OCW3_RR);
2047c074dc8Sthorpej 
205f3410434Sthorpej 	/* reset; program device, 4 bytes */
206f3410434Sthorpej 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, PIC_ICW1,
2071ce7119fSthorpej 	    ICW1_SELECT | ICW1_IC4);
208f3410434Sthorpej 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, PIC_ICW2,
2090c37c9e8Sthorpej 	    ICW2_VECTOR(0)/*XXX*/);
210f3410434Sthorpej 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, PIC_ICW3,
211f3410434Sthorpej 	    ICW3_SIC(2));
212f3410434Sthorpej 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, PIC_ICW4,
213f3410434Sthorpej 	    ICW4_8086);
2147c074dc8Sthorpej 
215f3410434Sthorpej 	/* mask all interrupts */
216f3410434Sthorpej 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, PIC_OCW1,
217f3410434Sthorpej 	    (sc->sc_imask >> 8) & 0xff);
2187c074dc8Sthorpej 
219f3410434Sthorpej 	/* enable special mask mode */
220f3410434Sthorpej 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, PIC_OCW3,
2211ce7119fSthorpej 	    OCW3_SELECT | OCW3_SSMM | OCW3_SMM);
2227c074dc8Sthorpej 
223f3410434Sthorpej 	/* read IRR by default */
224f3410434Sthorpej 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, PIC_OCW3,
2251ce7119fSthorpej 	    OCW3_SELECT | OCW3_RR);
2267c074dc8Sthorpej 
2277c074dc8Sthorpej 	/*
2287c074dc8Sthorpej 	 * Default all interrupts to edge-triggered.
2297c074dc8Sthorpej 	 */
2307c074dc8Sthorpej 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_elcr, 0,
2317c074dc8Sthorpej 	    sc->sc_elcr & 0xff);
2327c074dc8Sthorpej 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_elcr, 1,
2337c074dc8Sthorpej 	    (sc->sc_elcr >> 8) & 0xff);
2347c074dc8Sthorpej 
235f3410434Sthorpej 	/*
236f3410434Sthorpej 	 * Some ISA interrupts are reserved for devices that
237f3410434Sthorpej 	 * we know are hard-wired to certain IRQs.
238f3410434Sthorpej 	 */
239f3410434Sthorpej 	sc->sc_reserved =
240f3410434Sthorpej 		(1U << 0) |	/* timer */
241f3410434Sthorpej 		(1U << 1) |	/* keyboard controller */
2421ce7119fSthorpej 		(1U << 2) |	/* PIC cascade */
243f3410434Sthorpej 		(1U << 3) |	/* COM 2 */
244f3410434Sthorpej 		(1U << 4) |	/* COM 1 */
245f3410434Sthorpej 		(1U << 6) |	/* floppy */
246f3410434Sthorpej 		(1U << 7) |	/* centronics */
247f3410434Sthorpej 		(1U << 8) |	/* RTC */
248f3410434Sthorpej 		(1U << 12) |	/* keyboard controller */
249f3410434Sthorpej 		(1U << 14) |	/* IDE 0 */
250f3410434Sthorpej 		(1U << 15);	/* IDE 1 */
251f3410434Sthorpej 
2527c074dc8Sthorpej #if defined(ALGOR_P5064)
2537c074dc8Sthorpej 	/*
2547c074dc8Sthorpej 	 * Some "ISA" interrupts are a little wacky, wired up directly
2557c074dc8Sthorpej 	 * to the P-5064 interrupt controller.
2567c074dc8Sthorpej 	 */
2577c074dc8Sthorpej 	sc->sc_parent_ic = &p5064_configuration.ac_ic;
2587c074dc8Sthorpej #endif /* ALGOR_P5064 */
2597c074dc8Sthorpej 
2607c074dc8Sthorpej 	/* Set up our ISA chipset. */
2617c074dc8Sthorpej 	sc->sc_ic.ic_v = sc;
2627c074dc8Sthorpej 	sc->sc_ic.ic_intr_evcnt = pcib_isa_intr_evcnt;
2637c074dc8Sthorpej 	sc->sc_ic.ic_intr_establish = pcib_isa_intr_establish;
2647c074dc8Sthorpej 	sc->sc_ic.ic_intr_disestablish = pcib_isa_intr_disestablish;
2657c074dc8Sthorpej 	sc->sc_ic.ic_intr_alloc = pcib_isa_intr_alloc;
2667c074dc8Sthorpej 
2677c074dc8Sthorpej 	/* Initialize our interrupt table. */
2687c074dc8Sthorpej 	for (i = 0; i < 16; i++) {
2697c074dc8Sthorpej 		LIST_INIT(&sc->sc_intrtab[i].intr_q);
2707c074dc8Sthorpej 		evcnt_attach_dynamic(&sc->sc_intrtab[i].intr_count,
2717c074dc8Sthorpej 		    EVCNT_TYPE_INTR, NULL, "pcib", pcib_intrnames[i]);
2727c074dc8Sthorpej 		sc->sc_intrtab[i].intr_type = IST_NONE;
2737c074dc8Sthorpej 	}
2747c074dc8Sthorpej 
2757c074dc8Sthorpej 	/* Hook up our interrupt handler. */
2767c074dc8Sthorpej #if defined(ALGOR_P5064)
277e51a0439Sthorpej 	sc->sc_ih = (*algor_intr_establish)(P5064_IRQ_ISABRIDGE,
278e51a0439Sthorpej 	    pcib_intr, sc);
2797c074dc8Sthorpej #elif defined(ALGOR_P6032)
280b440db94Sthorpej 	sc->sc_ih = (*algor_intr_establish)(P6032_IRQ_ISABRIDGE,
2817c074dc8Sthorpej 	    pcib_intr, sc);
2827c074dc8Sthorpej #endif
2837c074dc8Sthorpej 	if (sc->sc_ih == NULL)
2847c074dc8Sthorpej 		printf("%s: WARNING: unable to register interrupt handler\n",
285f5439ed7Smatt 		    device_xname(sc->sc_dev));
2867c074dc8Sthorpej 
28716b9c606Sthorpej 	config_defer(self, pcib_bridge_callback);
28816b9c606Sthorpej }
28916b9c606Sthorpej 
29016b9c606Sthorpej void
pcib_bridge_callback(device_t self)291f5439ed7Smatt pcib_bridge_callback(device_t self)
29216b9c606Sthorpej {
293f5439ed7Smatt 	struct pcib_softc *sc = device_private(self);
29416b9c606Sthorpej 	struct isabus_attach_args iba;
29516b9c606Sthorpej 
29616b9c606Sthorpej 	memset(&iba, 0, sizeof(iba));
29716b9c606Sthorpej 
298c702830cSthorpej #if defined(ALGOR_P5064)
29916b9c606Sthorpej 	    {
30016b9c606Sthorpej 		struct p5064_config *acp = &p5064_configuration;
30116b9c606Sthorpej 
30216b9c606Sthorpej 		iba.iba_iot = &acp->ac_iot;
30316b9c606Sthorpej 		iba.iba_memt = &acp->ac_memt;
30416b9c606Sthorpej 		iba.iba_dmat = &acp->ac_isa_dmat;
30516b9c606Sthorpej 	    }
30616b9c606Sthorpej #elif defined(ALGOR_P6032)
30716b9c606Sthorpej 	    {
3080c37c9e8Sthorpej 		struct p6032_config *acp = &p6032_configuration;
3090c37c9e8Sthorpej 
3100c37c9e8Sthorpej 		iba.iba_iot = &acp->ac_iot;
3110c37c9e8Sthorpej 		iba.iba_memt = &acp->ac_memt;
3120c37c9e8Sthorpej 		iba.iba_dmat = &acp->ac_isa_dmat;
31316b9c606Sthorpej 	    }
31416b9c606Sthorpej #endif
31516b9c606Sthorpej 
316f3410434Sthorpej 	iba.iba_ic = &sc->sc_ic;
31716b9c606Sthorpej 	iba.iba_ic->ic_attach_hook = pcib_isa_attach_hook;
31822b3444cSdyoung 	iba.iba_ic->ic_detach_hook = pcib_isa_detach_hook;
31916b9c606Sthorpej 
320c7fb772bSthorpej 	config_found(sc->sc_dev, &iba, isabusprint, CFARGS_NONE);
32116b9c606Sthorpej }
32216b9c606Sthorpej 
32316b9c606Sthorpej void
pcib_isa_attach_hook(device_t parent,device_t self,struct isabus_attach_args * iba)324f5439ed7Smatt pcib_isa_attach_hook(device_t parent, device_t self,
32516b9c606Sthorpej     struct isabus_attach_args *iba)
32616b9c606Sthorpej {
32716b9c606Sthorpej 
32816b9c606Sthorpej 	/* Nothing to do. */
32916b9c606Sthorpej }
3307c074dc8Sthorpej 
3317c074dc8Sthorpej void
pcib_isa_detach_hook(isa_chipset_tag_t ic,device_t self)33222b3444cSdyoung pcib_isa_detach_hook(isa_chipset_tag_t ic, device_t self)
33322b3444cSdyoung {
33422b3444cSdyoung 
33522b3444cSdyoung 	/* Nothing to do. */
33622b3444cSdyoung }
33722b3444cSdyoung 
33822b3444cSdyoung void
pcib_set_icus(struct pcib_softc * sc)3397c074dc8Sthorpej pcib_set_icus(struct pcib_softc *sc)
3407c074dc8Sthorpej {
3417c074dc8Sthorpej 
3427c074dc8Sthorpej 	/* Enable the cascade IRQ (2) if 8-15 is enabled. */
343f3410434Sthorpej 	if ((sc->sc_imask & 0xff00) != 0xff00)
344f3410434Sthorpej 		sc->sc_imask &= ~(1U << 2);
3457c074dc8Sthorpej 	else
346f3410434Sthorpej 		sc->sc_imask |= (1U << 2);
3477c074dc8Sthorpej 
348f3410434Sthorpej 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW1,
349f3410434Sthorpej 	    sc->sc_imask & 0xff);
350f3410434Sthorpej 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, PIC_OCW1,
351f3410434Sthorpej 	    (sc->sc_imask >> 8) & 0xff);
3527c074dc8Sthorpej 
3537c074dc8Sthorpej 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_elcr, 0,
3547c074dc8Sthorpej 	    sc->sc_elcr & 0xff);
3557c074dc8Sthorpej 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_elcr, 1,
3567c074dc8Sthorpej 	    (sc->sc_elcr >> 8) & 0xff);
3577c074dc8Sthorpej }
3587c074dc8Sthorpej 
3597c074dc8Sthorpej int
pcib_intr(void * v)3607c074dc8Sthorpej pcib_intr(void *v)
3617c074dc8Sthorpej {
3627c074dc8Sthorpej 	struct pcib_softc *sc = v;
363f5439ed7Smatt 	struct evbmips_intrhand *ih;
364f3410434Sthorpej 	int irq;
3657c074dc8Sthorpej 
3661ce7119fSthorpej 	for (;;) {
367f3410434Sthorpej 		bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW3,
368f3410434Sthorpej 		    OCW3_SELECT | OCW3_POLL);
3691ce7119fSthorpej 		irq = bus_space_read_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW3);
3701ce7119fSthorpej 		if ((irq & OCW3_POLL_PENDING) == 0)
3711ce7119fSthorpej 			return (1);
3721ce7119fSthorpej 
3731ce7119fSthorpej 		irq = OCW3_POLL_IRQ(irq);
3747c074dc8Sthorpej 
375f3410434Sthorpej 		if (irq == 2) {
3761ce7119fSthorpej 			bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2,
3771ce7119fSthorpej 			    PIC_OCW3, OCW3_SELECT | OCW3_POLL);
3781ce7119fSthorpej 			irq = bus_space_read_1(sc->sc_iot, sc->sc_ioh_icu2,
3791ce7119fSthorpej 			    PIC_OCW3);
3801ce7119fSthorpej 			if (irq & OCW3_POLL_PENDING)
3811ce7119fSthorpej 				irq = OCW3_POLL_IRQ(irq) + 8;
3821ce7119fSthorpej 			else
3831ce7119fSthorpej 				irq = 2;
384f3410434Sthorpej 		}
385f3410434Sthorpej 
386f3410434Sthorpej 		sc->sc_intrtab[irq].intr_count.ev_count++;
387f3410434Sthorpej 		for (ih = LIST_FIRST(&sc->sc_intrtab[irq].intr_q);
3887c074dc8Sthorpej 		     ih != NULL; ih = LIST_NEXT(ih, ih_q)) {
3897c074dc8Sthorpej 			(*ih->ih_func)(ih->ih_arg);
3907c074dc8Sthorpej 		}
3917c074dc8Sthorpej 
3927c074dc8Sthorpej 		/* Send a specific EOI to the 8259. */
3931ce7119fSthorpej 		if (irq > 7) {
3947c074dc8Sthorpej 			bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2,
395337a4c70Stsutsui 			    PIC_OCW2, OCW2_SELECT | OCW2_EOI | OCW2_SL |
396f3410434Sthorpej 			    OCW2_ILS(irq & 7));
3971ce7119fSthorpej 			irq = 2;
3981ce7119fSthorpej 		}
399f3410434Sthorpej 
400f3410434Sthorpej 		bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW2,
401337a4c70Stsutsui 		    OCW2_SELECT | OCW2_EOI | OCW2_SL | OCW2_ILS(irq));
4021ce7119fSthorpej 	}
4037c074dc8Sthorpej }
4047c074dc8Sthorpej 
4057c074dc8Sthorpej const struct evcnt *
pcib_isa_intr_evcnt(void * v,int irq)4067c074dc8Sthorpej pcib_isa_intr_evcnt(void *v, int irq)
4077c074dc8Sthorpej {
4087c074dc8Sthorpej 	struct pcib_softc *sc = v;
4097c074dc8Sthorpej 
410be7629b7Sthorpej #if defined(ALGOR_P5064)
411f3410434Sthorpej 	if (p5064_isa_to_irqmap[irq] != -1)
412be7629b7Sthorpej 		return (isa_intr_evcnt(sc->sc_parent_ic, irq));
413be7629b7Sthorpej #endif
414be7629b7Sthorpej 
4157c074dc8Sthorpej 	return (&sc->sc_intrtab[irq].intr_count);
4167c074dc8Sthorpej }
4177c074dc8Sthorpej 
4187c074dc8Sthorpej void *
pcib_isa_intr_establish(void * v,int irq,int type,int level,int (* func)(void *),void * arg)4197c074dc8Sthorpej pcib_isa_intr_establish(void *v, int irq, int type, int level,
4207c074dc8Sthorpej     int (*func)(void *), void *arg)
4217c074dc8Sthorpej {
4227c074dc8Sthorpej 	struct pcib_softc *sc = v;
423f5439ed7Smatt 	struct evbmips_intrhand *ih;
4247c074dc8Sthorpej 	int s;
4257c074dc8Sthorpej 
4267c074dc8Sthorpej 	if (irq > 15 || irq == 2 || type == IST_NONE)
4277c074dc8Sthorpej 		panic("pcib_isa_intr_establish: bad irq or type");
4287c074dc8Sthorpej 
4297c074dc8Sthorpej #if defined(ALGOR_P5064)
430f3410434Sthorpej 	if (p5064_isa_to_irqmap[irq] != -1)
431f3410434Sthorpej 		return (isa_intr_establish(sc->sc_parent_ic, irq, type,
432f3410434Sthorpej 		    level, func, arg));
4337c074dc8Sthorpej #endif
4347c074dc8Sthorpej 
4357c074dc8Sthorpej 	switch (sc->sc_intrtab[irq].intr_type) {
4367c074dc8Sthorpej 	case IST_NONE:
4377c074dc8Sthorpej 		sc->sc_intrtab[irq].intr_type = type;
4387c074dc8Sthorpej 		break;
4397c074dc8Sthorpej 
4407c074dc8Sthorpej 	case IST_EDGE:
4417c074dc8Sthorpej 	case IST_LEVEL:
4427c074dc8Sthorpej 		if (type == sc->sc_intrtab[irq].intr_type)
4437c074dc8Sthorpej 			break;
4447c074dc8Sthorpej 		/* FALLTHROUGH */
4457c074dc8Sthorpej 	case IST_PULSE:
4467c074dc8Sthorpej 		/*
4477c074dc8Sthorpej 		 * We can't share interrupts in this case.
4487c074dc8Sthorpej 		 */
4497c074dc8Sthorpej 		return (NULL);
4507c074dc8Sthorpej 	}
4517c074dc8Sthorpej 
452ae873cf0Sthorpej 	ih = kmem_alloc(sizeof(*ih), KM_SLEEP);
4537c074dc8Sthorpej 	ih->ih_func = func;
4547c074dc8Sthorpej 	ih->ih_arg = arg;
4557c074dc8Sthorpej 	ih->ih_irq = irq;
4567c074dc8Sthorpej 	ih->ih_irqmap = NULL;
4577c074dc8Sthorpej 
4587c074dc8Sthorpej 	s = splhigh();
4597c074dc8Sthorpej 
4607c074dc8Sthorpej 	/* Insert the handler into the table. */
4617c074dc8Sthorpej 	LIST_INSERT_HEAD(&sc->sc_intrtab[irq].intr_q, ih, ih_q);
4627c074dc8Sthorpej 	sc->sc_intrtab[irq].intr_type = type;
4637c074dc8Sthorpej 
4647c074dc8Sthorpej 	/* Enable it, set trigger mode. */
465f3410434Sthorpej 	sc->sc_imask &= ~(1 << irq);
4667c074dc8Sthorpej 	if (sc->sc_intrtab[irq].intr_type == IST_LEVEL)
4677c074dc8Sthorpej 		sc->sc_elcr |= (1 << irq);
4687c074dc8Sthorpej 	else
4697c074dc8Sthorpej 		sc->sc_elcr &= ~(1 << irq);
4707c074dc8Sthorpej 
4717c074dc8Sthorpej 	pcib_set_icus(sc);
4727c074dc8Sthorpej 
4737c074dc8Sthorpej 	splx(s);
4747c074dc8Sthorpej 
4757c074dc8Sthorpej 	return (ih);
4767c074dc8Sthorpej }
4777c074dc8Sthorpej 
4787c074dc8Sthorpej void
pcib_isa_intr_disestablish(void * v,void * arg)4797c074dc8Sthorpej pcib_isa_intr_disestablish(void *v, void *arg)
4807c074dc8Sthorpej {
4817c074dc8Sthorpej 	struct pcib_softc *sc = v;
482f5439ed7Smatt 	struct evbmips_intrhand *ih = arg;
4837c074dc8Sthorpej 	int s;
4847c074dc8Sthorpej 
4857c074dc8Sthorpej #if defined(ALGOR_P5064)
486f3410434Sthorpej 	if (p5064_isa_to_irqmap[ih->ih_irq] != -1) {
4877c074dc8Sthorpej 		isa_intr_disestablish(sc->sc_parent_ic, ih);
4887c074dc8Sthorpej 		return;
4897c074dc8Sthorpej 	}
4907c074dc8Sthorpej #endif
4917c074dc8Sthorpej 
4927c074dc8Sthorpej 	s = splhigh();
4937c074dc8Sthorpej 
4947c074dc8Sthorpej 	LIST_REMOVE(ih, ih_q);
4957c074dc8Sthorpej 
4967c074dc8Sthorpej 	/* If there are no more handlers on this IRQ, disable it. */
4977c074dc8Sthorpej 	if (LIST_FIRST(&sc->sc_intrtab[ih->ih_irq].intr_q) == NULL) {
498f3410434Sthorpej 		sc->sc_imask |= (1 << ih->ih_irq);
4997c074dc8Sthorpej 		pcib_set_icus(sc);
5007c074dc8Sthorpej 	}
5017c074dc8Sthorpej 
5027c074dc8Sthorpej 	splx(s);
5037c074dc8Sthorpej 
504ae873cf0Sthorpej 	kmem_free(ih, sizeof(*ih));
5057c074dc8Sthorpej }
5067c074dc8Sthorpej 
5077c074dc8Sthorpej int
pcib_isa_intr_alloc(void * v,int mask,int type,int * irq)5087c074dc8Sthorpej pcib_isa_intr_alloc(void *v, int mask, int type, int *irq)
5097c074dc8Sthorpej {
5107c074dc8Sthorpej 	struct pcib_softc *sc = v;
5117c074dc8Sthorpej 	int i, tmp, bestirq, count;
512f5439ed7Smatt 	struct evbmips_intrhand *ih;
5137c074dc8Sthorpej 
5147c074dc8Sthorpej 	if (type == IST_NONE)
5157c074dc8Sthorpej 		panic("pcib_intr_alloc: bogus type");
5167c074dc8Sthorpej 
5177c074dc8Sthorpej 	bestirq = -1;
5187c074dc8Sthorpej 	count = -1;
5197c074dc8Sthorpej 
5207c074dc8Sthorpej 	mask &= ~sc->sc_reserved;
5217c074dc8Sthorpej 
522f3410434Sthorpej #if 0
523f3410434Sthorpej 	printf("pcib_intr_alloc: mask = 0x%04x\n", mask);
524f3410434Sthorpej #endif
525f3410434Sthorpej 
5267c074dc8Sthorpej 	for (i = 0; i < 16; i++) {
5271ce7119fSthorpej 		if ((mask & (1 << i)) == 0)
5287c074dc8Sthorpej 			continue;
5297c074dc8Sthorpej 
5307c074dc8Sthorpej 		switch (sc->sc_intrtab[i].intr_type) {
5317c074dc8Sthorpej 		case IST_NONE:
5327c074dc8Sthorpej 			/*
5337c074dc8Sthorpej 			 * If nothing's using the IRQ, just return it.
5347c074dc8Sthorpej 			 */
5357c074dc8Sthorpej 			*irq = i;
5367c074dc8Sthorpej 			return (0);
5377c074dc8Sthorpej 
5387c074dc8Sthorpej 		case IST_EDGE:
5397c074dc8Sthorpej 		case IST_LEVEL:
5407c074dc8Sthorpej 			if (type != sc->sc_intrtab[i].intr_type)
5417c074dc8Sthorpej 				continue;
5427c074dc8Sthorpej 			/*
543*a5175f1eSandvar 			 * If the IRQ is shareable, count the number of
5447c074dc8Sthorpej 			 * other handlers, and if it's smaller than the
5457c074dc8Sthorpej 			 * last IRQ like this, remember it.
5467c074dc8Sthorpej 			 */
5477c074dc8Sthorpej 			tmp = 0;
5487c074dc8Sthorpej 			for (ih = LIST_FIRST(&sc->sc_intrtab[i].intr_q);
5497c074dc8Sthorpej 			     ih != NULL; ih = LIST_NEXT(ih, ih_q))
5507c074dc8Sthorpej 				tmp++;
5517c074dc8Sthorpej 			if (bestirq == -1 || count > tmp) {
5527c074dc8Sthorpej 				bestirq = i;
5537c074dc8Sthorpej 				count = tmp;
5547c074dc8Sthorpej 			}
5557c074dc8Sthorpej 			break;
5567c074dc8Sthorpej 
5577c074dc8Sthorpej 		case IST_PULSE:
558*a5175f1eSandvar 			/* This just isn't shareable. */
5597c074dc8Sthorpej 			continue;
5607c074dc8Sthorpej 		}
5617c074dc8Sthorpej 	}
5627c074dc8Sthorpej 
5637c074dc8Sthorpej 	if (bestirq == -1)
5647c074dc8Sthorpej 		return (1);
5657c074dc8Sthorpej 
5667c074dc8Sthorpej 	*irq = bestirq;
5677c074dc8Sthorpej 	return (0);
5687c074dc8Sthorpej }
569