Home | History | Annotate | Line # | Download | only in pci
pcib.c revision 1.1
      1  1.1  simonb /*	$NetBSD: pcib.c,v 1.1 2002/03/07 14:44:05 simonb Exp $	*/
      2  1.1  simonb 
      3  1.1  simonb /*
      4  1.1  simonb  * Copyright 2002 Wasabi Systems, Inc.
      5  1.1  simonb  * All rights reserved.
      6  1.1  simonb  *
      7  1.1  simonb  * Written by Simon Burge for Wasabi Systems, Inc.
      8  1.1  simonb  *
      9  1.1  simonb  * Redistribution and use in source and binary forms, with or without
     10  1.1  simonb  * modification, are permitted provided that the following conditions
     11  1.1  simonb  * are met:
     12  1.1  simonb  * 1. Redistributions of source code must retain the above copyright
     13  1.1  simonb  *    notice, this list of conditions and the following disclaimer.
     14  1.1  simonb  * 2. Redistributions in binary form must reproduce the above copyright
     15  1.1  simonb  *    notice, this list of conditions and the following disclaimer in the
     16  1.1  simonb  *    documentation and/or other materials provided with the distribution.
     17  1.1  simonb  * 3. All advertising materials mentioning features or use of this software
     18  1.1  simonb  *    must display the following acknowledgement:
     19  1.1  simonb  *      This product includes software developed for the NetBSD Project by
     20  1.1  simonb  *      Wasabi Systems, Inc.
     21  1.1  simonb  * 4. The name of Wasabi Systems, Inc. may not be used to endorse
     22  1.1  simonb  *    or promote products derived from this software without specific prior
     23  1.1  simonb  *    written permission.
     24  1.1  simonb  *
     25  1.1  simonb  * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
     26  1.1  simonb  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     27  1.1  simonb  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     28  1.1  simonb  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WASABI SYSTEMS, INC
     29  1.1  simonb  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     30  1.1  simonb  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     31  1.1  simonb  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     32  1.1  simonb  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     33  1.1  simonb  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     34  1.1  simonb  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     35  1.1  simonb  * POSSIBILITY OF SUCH DAMAGE.
     36  1.1  simonb  */
     37  1.1  simonb 
     38  1.1  simonb #include <sys/param.h>
     39  1.1  simonb #include <sys/systm.h>
     40  1.1  simonb #include <sys/kernel.h>
     41  1.1  simonb #include <sys/device.h>
     42  1.1  simonb #include <sys/malloc.h>
     43  1.1  simonb 
     44  1.1  simonb #include <machine/bus.h>
     45  1.1  simonb #include <evbmips/malta/maltareg.h>
     46  1.1  simonb #include <evbmips/malta/maltavar.h>
     47  1.1  simonb #include <evbmips/malta/dev/gtreg.h>
     48  1.1  simonb #include <evbmips/malta/pci/pcibvar.h>
     49  1.1  simonb 
     50  1.1  simonb #include <dev/isa/isareg.h>
     51  1.1  simonb #include <dev/isa/isavar.h>
     52  1.1  simonb 
     53  1.1  simonb #include <dev/pci/pcireg.h>
     54  1.1  simonb #include <dev/pci/pcivar.h>
     55  1.1  simonb #include <dev/pci/pcidevs.h>
     56  1.1  simonb 
     57  1.1  simonb #include <dev/ic/i8259reg.h>
     58  1.1  simonb 
     59  1.1  simonb 
     60  1.1  simonb #define	ICU_LEN		16	/* number of ISA IRQs */
     61  1.1  simonb 
     62  1.1  simonb const char *isa_intrnames[ICU_LEN] = {
     63  1.1  simonb 	"timer",
     64  1.1  simonb 	"keyboard",
     65  1.1  simonb 	"reserved",		/* by South Bridge (for cascading) */
     66  1.1  simonb 	"com1",
     67  1.1  simonb 	"com0",
     68  1.1  simonb 	"not used",
     69  1.1  simonb 	"floppy",
     70  1.1  simonb 	"centronics",
     71  1.1  simonb 	"mcclock",
     72  1.1  simonb 	"i2c",
     73  1.1  simonb 	"pci A,B",		/* PCI slots 1..4, ethernet */
     74  1.1  simonb 	"pci C,D",		/* PCI slots 1..4, audio, usb */
     75  1.1  simonb 	"mouse",
     76  1.1  simonb 	"reserved",
     77  1.1  simonb 	"ide primary",
     78  1.1  simonb 	"ide secondary",	/* and compact flash connector */
     79  1.1  simonb };
     80  1.1  simonb 
     81  1.1  simonb struct pcib_intrhead {
     82  1.1  simonb 	LIST_HEAD(, evbmips_intrhand) intr_q;
     83  1.1  simonb 	struct evcnt intr_count;
     84  1.1  simonb 	int intr_type;
     85  1.1  simonb };
     86  1.1  simonb 
     87  1.1  simonb struct pcib_softc {
     88  1.1  simonb 	struct device sc_dev;
     89  1.1  simonb 
     90  1.1  simonb 	bus_space_tag_t sc_iot;
     91  1.1  simonb 	bus_space_handle_t sc_ioh_icu1;
     92  1.1  simonb 	bus_space_handle_t sc_ioh_icu2;
     93  1.1  simonb 	bus_space_handle_t sc_ioh_elcr;
     94  1.1  simonb 
     95  1.1  simonb 	struct evbmips_isa_chipset sc_ic;
     96  1.1  simonb 
     97  1.1  simonb 	struct pcib_intrhead sc_intrtab[ICU_LEN];
     98  1.1  simonb 
     99  1.1  simonb 	u_int16_t	sc_imask;
    100  1.1  simonb 	u_int16_t	sc_elcr;
    101  1.1  simonb 
    102  1.1  simonb 	u_int16_t	sc_reserved;
    103  1.1  simonb 
    104  1.1  simonb 	void *sc_ih;
    105  1.1  simonb };
    106  1.1  simonb 
    107  1.1  simonb /*
    108  1.1  simonb  * XXX
    109  1.1  simonb  *	There is only one pci-isa bridge, and all external interrupts
    110  1.1  simonb  *	are routed through it, so we need to remember the softc when
    111  1.1  simonb  *	called from other interrupt handling code.
    112  1.1  simonb  */
    113  1.1  simonb static struct pcib_softc *my_sc;
    114  1.1  simonb struct evbmips_isa_chipset *pcib_ic;
    115  1.1  simonb 
    116  1.1  simonb static int	pcib_match(struct device *, struct cfdata *, void *);
    117  1.1  simonb static void	pcib_attach(struct device *, struct device *, void *);
    118  1.1  simonb static int	pcib_intr(void *v);
    119  1.1  simonb static void	pcib_bridge_callback(struct device *);
    120  1.1  simonb static int	pcib_print(void *, const char *);
    121  1.1  simonb static void	pcib_set_icus(struct pcib_softc *sc);
    122  1.1  simonb static void	pcib_cleanup(void *arg);
    123  1.1  simonb 
    124  1.1  simonb static const struct evcnt *
    125  1.1  simonb 		pcib_isa_intr_evcnt(void *, int);
    126  1.1  simonb static void	*pcib_isa_intr_establish(void *, int, int, int,
    127  1.1  simonb 		    int (*)(void *), void *);
    128  1.1  simonb static void	pcib_isa_intr_disestablish(void *, void *);
    129  1.1  simonb static void	pcib_isa_attach_hook(struct device *, struct device *,
    130  1.1  simonb 		    struct isabus_attach_args *);
    131  1.1  simonb static int	pcib_isa_intr_alloc(void *, int, int, int *);
    132  1.1  simonb static const char *
    133  1.1  simonb 		pcib_isa_intr_string(void *, int);
    134  1.1  simonb 
    135  1.1  simonb struct cfattach pcib_ca = {
    136  1.1  simonb 	sizeof(struct pcib_softc), pcib_match, pcib_attach
    137  1.1  simonb };
    138  1.1  simonb 
    139  1.1  simonb static int
    140  1.1  simonb pcib_match(struct device *parent, struct cfdata *match, void *aux)
    141  1.1  simonb {
    142  1.1  simonb 	struct pci_attach_args *pa = aux;
    143  1.1  simonb 
    144  1.1  simonb 	if (PCI_CLASS(pa->pa_class) == PCI_CLASS_BRIDGE &&
    145  1.1  simonb 	    PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_BRIDGE_ISA)
    146  1.1  simonb 		return (1);
    147  1.1  simonb 
    148  1.1  simonb 	return (0);
    149  1.1  simonb }
    150  1.1  simonb 
    151  1.1  simonb static void
    152  1.1  simonb pcib_attach(struct device *parent, struct device *self, void *aux)
    153  1.1  simonb {
    154  1.1  simonb 	struct pci_attach_args *pa = aux;
    155  1.1  simonb 	char devinfo[256];
    156  1.1  simonb 	int i;
    157  1.1  simonb 
    158  1.1  simonb 	printf("\n");
    159  1.1  simonb 
    160  1.1  simonb 	if (my_sc != NULL)
    161  1.1  simonb 		panic("pcib_attach: already attached!\n");
    162  1.1  simonb 	my_sc = (void *)self;
    163  1.1  simonb 
    164  1.1  simonb 	/*
    165  1.1  simonb 	 * Just print out a description and defer configuration
    166  1.1  simonb 	 * until all PCI devices have been attached.
    167  1.1  simonb 	 */
    168  1.1  simonb 	pci_devinfo(pa->pa_id, pa->pa_class, 0, devinfo);
    169  1.1  simonb 	printf("%s: %s, (rev . 0x%02x)\n", self->dv_xname, devinfo,
    170  1.1  simonb 	    PCI_REVISION(pa->pa_class));
    171  1.1  simonb 
    172  1.1  simonb 	my_sc->sc_iot = pa->pa_iot;
    173  1.1  simonb 
    174  1.1  simonb 	/*
    175  1.1  simonb 	 * Map the PIC/ELCR registers.
    176  1.1  simonb 	 */
    177  1.1  simonb 	if (bus_space_map(my_sc->sc_iot, 0x4d0, 2, 0, &my_sc->sc_ioh_elcr) != 0)
    178  1.1  simonb 		printf("%s: unable to map ELCR registers\n",
    179  1.1  simonb 		    my_sc->sc_dev.dv_xname);
    180  1.1  simonb 	if (bus_space_map(my_sc->sc_iot, IO_ICU1, 2, 0, &my_sc->sc_ioh_icu1) != 0)
    181  1.1  simonb 		printf("%s: unable to map ICU1 registers\n",
    182  1.1  simonb 		    my_sc->sc_dev.dv_xname);
    183  1.1  simonb 	if (bus_space_map(my_sc->sc_iot, IO_ICU2, 2, 0, &my_sc->sc_ioh_icu2) != 0)
    184  1.1  simonb 		printf("%s: unable to map ICU2 registers\n",
    185  1.1  simonb 		    my_sc->sc_dev.dv_xname);
    186  1.1  simonb 
    187  1.1  simonb 	/* All interrupts default to "masked off". */
    188  1.1  simonb 	my_sc->sc_imask = 0xffff;
    189  1.1  simonb 
    190  1.1  simonb 	/* All interrupts default to edge-triggered. */
    191  1.1  simonb 	my_sc->sc_elcr = 0;
    192  1.1  simonb 
    193  1.1  simonb 	/*
    194  1.1  simonb 	 * Initialize the 8259s.
    195  1.1  simonb 	 */
    196  1.1  simonb 	/* reset, program device, 4 bytes */
    197  1.1  simonb 	bus_space_write_1(my_sc->sc_iot, my_sc->sc_ioh_icu1, PIC_ICW1,
    198  1.1  simonb 	    ICW1_SELECT | ICW1_IC4);
    199  1.1  simonb 	bus_space_write_1(my_sc->sc_iot, my_sc->sc_ioh_icu1, PIC_ICW2,
    200  1.1  simonb 	    ICW2_VECTOR(0)/*XXX*/);
    201  1.1  simonb 	bus_space_write_1(my_sc->sc_iot, my_sc->sc_ioh_icu1, PIC_ICW3,
    202  1.1  simonb 	    ICW3_CASCADE(2));
    203  1.1  simonb 	bus_space_write_1(my_sc->sc_iot, my_sc->sc_ioh_icu1, PIC_ICW4,
    204  1.1  simonb 	    ICW4_8086);
    205  1.1  simonb 
    206  1.1  simonb 	/* mask all interrupts */
    207  1.1  simonb 	bus_space_write_1(my_sc->sc_iot, my_sc->sc_ioh_icu1, PIC_OCW1,
    208  1.1  simonb 	    my_sc->sc_imask & 0xff);
    209  1.1  simonb 
    210  1.1  simonb 	/* enable special mask mode */
    211  1.1  simonb 	bus_space_write_1(my_sc->sc_iot, my_sc->sc_ioh_icu1, PIC_OCW3,
    212  1.1  simonb 	    OCW3_SELECT | OCW3_SSMM | OCW3_SMM);
    213  1.1  simonb 
    214  1.1  simonb 	/* read IRR by default */
    215  1.1  simonb 	bus_space_write_1(my_sc->sc_iot, my_sc->sc_ioh_icu1, PIC_OCW3,
    216  1.1  simonb 	    OCW3_SELECT | OCW3_RR);
    217  1.1  simonb 
    218  1.1  simonb 	/* reset, program device, 4 bytes */
    219  1.1  simonb 	bus_space_write_1(my_sc->sc_iot, my_sc->sc_ioh_icu2, PIC_ICW1,
    220  1.1  simonb 	    ICW1_SELECT | ICW1_IC4);
    221  1.1  simonb 	bus_space_write_1(my_sc->sc_iot, my_sc->sc_ioh_icu2, PIC_ICW2,
    222  1.1  simonb 	    ICW2_VECTOR(0)/*XXX*/);
    223  1.1  simonb 	bus_space_write_1(my_sc->sc_iot, my_sc->sc_ioh_icu2, PIC_ICW3,
    224  1.1  simonb 	    ICW3_CASCADE(2));
    225  1.1  simonb 	bus_space_write_1(my_sc->sc_iot, my_sc->sc_ioh_icu2, PIC_ICW4,
    226  1.1  simonb 	    ICW4_8086);
    227  1.1  simonb 
    228  1.1  simonb 	/* mask all interrupts */
    229  1.1  simonb 	bus_space_write_1(my_sc->sc_iot, my_sc->sc_ioh_icu2, PIC_OCW1,
    230  1.1  simonb 	    my_sc->sc_imask & 0xff);
    231  1.1  simonb 
    232  1.1  simonb 	/* enable special mask mode */
    233  1.1  simonb 	bus_space_write_1(my_sc->sc_iot, my_sc->sc_ioh_icu2, PIC_OCW3,
    234  1.1  simonb 	    OCW3_SELECT | OCW3_SSMM | OCW3_SMM);
    235  1.1  simonb 
    236  1.1  simonb 	/* read IRR by default */
    237  1.1  simonb 	bus_space_write_1(my_sc->sc_iot, my_sc->sc_ioh_icu2, PIC_OCW3,
    238  1.1  simonb 	    OCW3_SELECT | OCW3_RR);
    239  1.1  simonb 
    240  1.1  simonb 	/*
    241  1.1  simonb 	 * Default all interrupts to edge-triggered.
    242  1.1  simonb 	 */
    243  1.1  simonb 	bus_space_write_1(my_sc->sc_iot, my_sc->sc_ioh_elcr, 0,
    244  1.1  simonb 	    my_sc->sc_elcr & 0xff);
    245  1.1  simonb 	bus_space_write_1(my_sc->sc_iot, my_sc->sc_ioh_elcr, 1,
    246  1.1  simonb 	    (my_sc->sc_elcr >> 8) & 0xff);
    247  1.1  simonb 
    248  1.1  simonb 	/*
    249  1.1  simonb 	 * Some ISA interrupts are reserved for devices that
    250  1.1  simonb 	 * we know are hard-wired to certain IRQs.
    251  1.1  simonb 	 */
    252  1.1  simonb 	my_sc->sc_reserved =
    253  1.1  simonb 		(1U << 0) |     /* timer */
    254  1.1  simonb 		(1U << 1) |     /* keyboard controller (keyboard) */
    255  1.1  simonb 		(1U << 2) |     /* PIC cascade */
    256  1.1  simonb 		(1U << 3) |     /* COM 2 */
    257  1.1  simonb 		(1U << 4) |     /* COM 1 */
    258  1.1  simonb 		(1U << 6) |     /* floppy */
    259  1.1  simonb 		(1U << 7) |     /* centronics */
    260  1.1  simonb 		(1U << 8) |     /* RTC */
    261  1.1  simonb 		(1U << 9) |	/* I2C */
    262  1.1  simonb 		(1U << 12) |    /* keyboard controller (mouse) */
    263  1.1  simonb 		(1U << 14) |    /* IDE primary */
    264  1.1  simonb 		(1U << 15);     /* IDE secondary */
    265  1.1  simonb 
    266  1.1  simonb 	/* Set up our ISA chipset. */
    267  1.1  simonb 	my_sc->sc_ic.ic_v = my_sc;
    268  1.1  simonb 	my_sc->sc_ic.ic_intr_evcnt = pcib_isa_intr_evcnt;
    269  1.1  simonb 	my_sc->sc_ic.ic_intr_establish = pcib_isa_intr_establish;
    270  1.1  simonb 	my_sc->sc_ic.ic_intr_disestablish = pcib_isa_intr_disestablish;
    271  1.1  simonb 	my_sc->sc_ic.ic_intr_alloc = pcib_isa_intr_alloc;
    272  1.1  simonb 	my_sc->sc_ic.ic_intr_string = pcib_isa_intr_string;
    273  1.1  simonb 
    274  1.1  simonb 	pcib_ic = &my_sc->sc_ic;	/* XXX for external use */
    275  1.1  simonb 
    276  1.1  simonb 	/* Initialize our interrupt table. */
    277  1.1  simonb 	for (i = 0; i < ICU_LEN; i++) {
    278  1.1  simonb #if 0
    279  1.1  simonb 		char irqstr[8];		/* 4 + 2 + NULL + sanity */
    280  1.1  simonb 
    281  1.1  simonb 		sprintf(irqstr, "irq %d", i);
    282  1.1  simonb 		evcnt_attach_dynamic(&my_sc->sc_intrtab[i].intr_count,
    283  1.1  simonb 		    EVCNT_TYPE_INTR, NULL, "pcib", irqstr);
    284  1.1  simonb #else
    285  1.1  simonb 		evcnt_attach_dynamic(&my_sc->sc_intrtab[i].intr_count,
    286  1.1  simonb 		    EVCNT_TYPE_INTR, NULL, "pcib", isa_intrnames[i]);
    287  1.1  simonb #endif
    288  1.1  simonb 		LIST_INIT(&my_sc->sc_intrtab[i].intr_q);
    289  1.1  simonb 		my_sc->sc_intrtab[i].intr_type = IST_NONE;
    290  1.1  simonb 	}
    291  1.1  simonb 
    292  1.1  simonb 	/* Hook up our interrupt handler. */
    293  1.1  simonb 	my_sc->sc_ih = evbmips_intr_establish(MALTA_SOUTHBRIDGE_INTR, pcib_intr, my_sc);
    294  1.1  simonb 	if (my_sc->sc_ih == NULL)
    295  1.1  simonb 		printf("%s: WARNING: unable to register interrupt handler\n",
    296  1.1  simonb 		    my_sc->sc_dev.dv_xname);
    297  1.1  simonb 
    298  1.1  simonb 
    299  1.1  simonb 	/*
    300  1.1  simonb 	 * Disable ISA interrupts before returning to YAMON.
    301  1.1  simonb 	 */
    302  1.1  simonb 	if (shutdownhook_establish(pcib_cleanup, my_sc) == NULL)
    303  1.1  simonb 		panic("pcib_attach: could not establish shutdown hook");
    304  1.1  simonb 
    305  1.1  simonb 	config_defer(self, pcib_bridge_callback);
    306  1.1  simonb }
    307  1.1  simonb 
    308  1.1  simonb static void
    309  1.1  simonb pcib_bridge_callback(struct device *self)
    310  1.1  simonb {
    311  1.1  simonb 	struct pcib_softc *sc = (void *)self;
    312  1.1  simonb 	struct malta_config *mcp = &malta_configuration;
    313  1.1  simonb 	struct isabus_attach_args iba;
    314  1.1  simonb 
    315  1.1  simonb 	/*
    316  1.1  simonb 	 * Attach the ISA bus behind this bridge.
    317  1.1  simonb 	 */
    318  1.1  simonb 	memset(&iba, 0, sizeof(iba));
    319  1.1  simonb 
    320  1.1  simonb 	iba.iba_busname = "isa";
    321  1.1  simonb 	iba.iba_iot = &mcp->mc_iot;
    322  1.1  simonb 	iba.iba_memt = &mcp->mc_memt;
    323  1.1  simonb 	iba.iba_dmat = &mcp->mc_isa_dmat;
    324  1.1  simonb 
    325  1.1  simonb 	iba.iba_ic = &sc->sc_ic;
    326  1.1  simonb 	iba.iba_ic->ic_attach_hook = pcib_isa_attach_hook;
    327  1.1  simonb 
    328  1.1  simonb 	config_found(&sc->sc_dev, &iba, pcib_print);
    329  1.1  simonb }
    330  1.1  simonb 
    331  1.1  simonb static int
    332  1.1  simonb pcib_print(void *aux, const char *pnp)
    333  1.1  simonb {
    334  1.1  simonb 
    335  1.1  simonb 	/* Only ISAs can attach to pcib's; easy. */
    336  1.1  simonb 	if (pnp)
    337  1.1  simonb 		printf("isa at %s", pnp);
    338  1.1  simonb 	return (UNCONF);
    339  1.1  simonb }
    340  1.1  simonb 
    341  1.1  simonb static void
    342  1.1  simonb pcib_isa_attach_hook(struct device *parent, struct device *self,
    343  1.1  simonb     struct isabus_attach_args *iba)
    344  1.1  simonb {
    345  1.1  simonb 
    346  1.1  simonb 	/* Nothing to do. */
    347  1.1  simonb }
    348  1.1  simonb 
    349  1.1  simonb static void
    350  1.1  simonb pcib_set_icus(struct pcib_softc *sc)
    351  1.1  simonb {
    352  1.1  simonb 
    353  1.1  simonb 	/* Enable the cascade IRQ (2) if 8-15 is enabled. */
    354  1.1  simonb 	if ((sc->sc_imask & 0xff00) != 0xff00)
    355  1.1  simonb 		sc->sc_imask &= ~(1U << 2);
    356  1.1  simonb 	else
    357  1.1  simonb 		sc->sc_imask |= (1U << 2);
    358  1.1  simonb 
    359  1.1  simonb 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW1,
    360  1.1  simonb 	    sc->sc_imask & 0xff);
    361  1.1  simonb 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, PIC_OCW1,
    362  1.1  simonb 	    (sc->sc_imask >> 8) & 0xff);
    363  1.1  simonb 
    364  1.1  simonb 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_elcr, 0,
    365  1.1  simonb 	    sc->sc_elcr & 0xff);
    366  1.1  simonb 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_elcr, 1,
    367  1.1  simonb 	    (sc->sc_elcr >> 8) & 0xff);
    368  1.1  simonb }
    369  1.1  simonb 
    370  1.1  simonb static int
    371  1.1  simonb pcib_intr(void *v)
    372  1.1  simonb {
    373  1.1  simonb 	struct pcib_softc *sc = v;
    374  1.1  simonb 	struct evbmips_intrhand *ih;
    375  1.1  simonb 	int irq;
    376  1.1  simonb 
    377  1.1  simonb 	for (;;) {
    378  1.1  simonb #if 1
    379  1.1  simonb 		bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW3,
    380  1.1  simonb 		    OCW3_SELECT | OCW3_POLL);
    381  1.1  simonb 		irq = bus_space_read_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW3);
    382  1.1  simonb 		if ((irq & OCW3_POLL_PENDING) == 0)
    383  1.1  simonb 			return (1);
    384  1.1  simonb 
    385  1.1  simonb 		irq = OCW3_POLL_IRQ(irq);
    386  1.1  simonb 
    387  1.1  simonb 		if (irq == 2) {
    388  1.1  simonb 			bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2,
    389  1.1  simonb 			    PIC_OCW3, OCW3_SELECT | OCW3_POLL);
    390  1.1  simonb 			irq = bus_space_read_1(sc->sc_iot, sc->sc_ioh_icu2,
    391  1.1  simonb 			    PIC_OCW3);
    392  1.1  simonb 			if (irq & OCW3_POLL_PENDING)
    393  1.1  simonb 				irq = OCW3_POLL_IRQ(irq) + 8;
    394  1.1  simonb 			else
    395  1.1  simonb 				irq = 2;
    396  1.1  simonb 		}
    397  1.1  simonb #else
    398  1.1  simonb 		/* XXX - should be a function call to gt.c? */
    399  1.1  simonb 		irq = GT_REGVAL(GT_PCI0_INTR_ACK) & 0xff;
    400  1.1  simonb 
    401  1.1  simonb 		/*
    402  1.1  simonb 		 * From YAMON source code:
    403  1.1  simonb 		 *
    404  1.1  simonb 		 * IRQ7 is used to detect spurious interrupts.
    405  1.1  simonb 		 * The interrupt acknowledge cycle returns IRQ7, if no
    406  1.1  simonb 		 * interrupts is requested.
    407  1.1  simonb 		 * We can differentiate between this situation and a
    408  1.1  simonb 		 * "Normal" IRQ7 by reading the ISR.
    409  1.1  simonb 		 */
    410  1.1  simonb 
    411  1.1  simonb 		if (irq == 7) {
    412  1.1  simonb 			int reg;
    413  1.1  simonb 
    414  1.1  simonb 			bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW3,
    415  1.1  simonb 			    OCW3_SELECT | OCW3_RR | OCW3_RIS);
    416  1.1  simonb 			reg = bus_space_read_1(sc->sc_iot, sc->sc_ioh_icu1,
    417  1.1  simonb 			    PIC_OCW3);
    418  1.1  simonb 			if (!(reg & (1 << 7)))
    419  1.1  simonb 				break;	/* spurious interrupt */
    420  1.1  simonb 		}
    421  1.1  simonb #endif
    422  1.1  simonb 
    423  1.1  simonb 		sc->sc_intrtab[irq].intr_count.ev_count++;
    424  1.1  simonb 		LIST_FOREACH(ih, &sc->sc_intrtab[irq].intr_q, ih_q)
    425  1.1  simonb 			(*ih->ih_func)(ih->ih_arg);
    426  1.1  simonb 
    427  1.1  simonb 		/* Send a specific EOI to the 8259. */
    428  1.1  simonb 		if (irq > 7) {
    429  1.1  simonb 			bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2,
    430  1.1  simonb 			    PIC_OCW2, OCW2_SELECT | OCW3_EOI | OCW3_SL |
    431  1.1  simonb 			    OCW2_ILS(irq & 7));
    432  1.1  simonb 			irq = 2;
    433  1.1  simonb 		}
    434  1.1  simonb 
    435  1.1  simonb 		bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW2,
    436  1.1  simonb 		    OCW2_SELECT | OCW3_EOI | OCW3_SL | OCW2_ILS(irq));
    437  1.1  simonb 	}
    438  1.1  simonb }
    439  1.1  simonb 
    440  1.1  simonb const char *
    441  1.1  simonb pcib_isa_intr_string(void *v, int irq)
    442  1.1  simonb {
    443  1.1  simonb 	static char irqstr[12];		/* 8 + 2 + NULL + sanity */
    444  1.1  simonb 
    445  1.1  simonb 	if (irq == 0 || irq >= ICU_LEN || irq == 2)
    446  1.1  simonb 		panic("pcib_isa_intr_string: bogus isa irq 0x%x\n", irq);
    447  1.1  simonb 
    448  1.1  simonb 	sprintf(irqstr, "isa irq %d", irq);
    449  1.1  simonb 	return (irqstr);
    450  1.1  simonb }
    451  1.1  simonb 
    452  1.1  simonb const struct evcnt *
    453  1.1  simonb pcib_isa_intr_evcnt(void *v, int irq)
    454  1.1  simonb {
    455  1.1  simonb 
    456  1.1  simonb 	if (irq == 0 || irq >= ICU_LEN || irq == 2)
    457  1.1  simonb 		panic("pcib_isa_intr_evcnt: bogus isa irq 0x%x\n", irq);
    458  1.1  simonb 
    459  1.1  simonb 	return (&my_sc->sc_intrtab[irq].intr_count);
    460  1.1  simonb }
    461  1.1  simonb 
    462  1.1  simonb void *
    463  1.1  simonb pcib_isa_intr_establish(void *v, int irq, int type, int level,
    464  1.1  simonb     int (*func)(void *), void *arg)
    465  1.1  simonb {
    466  1.1  simonb 	struct evbmips_intrhand *ih;
    467  1.1  simonb 	int s;
    468  1.1  simonb 
    469  1.1  simonb 	if (irq >= ICU_LEN || irq == 2 || type == IST_NONE)
    470  1.1  simonb 		panic("pcib_isa_intr_establish: bad irq or type");
    471  1.1  simonb 
    472  1.1  simonb 	switch (my_sc->sc_intrtab[irq].intr_type) {
    473  1.1  simonb 	case IST_NONE:
    474  1.1  simonb 		my_sc->sc_intrtab[irq].intr_type = type;
    475  1.1  simonb 		break;
    476  1.1  simonb 
    477  1.1  simonb 	case IST_EDGE:
    478  1.1  simonb 	case IST_LEVEL:
    479  1.1  simonb 		if (type == my_sc->sc_intrtab[irq].intr_type)
    480  1.1  simonb 			break;
    481  1.1  simonb 		/* FALLTHROUGH */
    482  1.1  simonb 	case IST_PULSE:
    483  1.1  simonb 		/*
    484  1.1  simonb 		 * We can't share interrupts in this case.
    485  1.1  simonb 		 */
    486  1.1  simonb 		return (NULL);
    487  1.1  simonb 	}
    488  1.1  simonb 
    489  1.1  simonb 	ih = malloc(sizeof(*ih), M_DEVBUF, M_NOWAIT);
    490  1.1  simonb 	if (ih == NULL)
    491  1.1  simonb 		return (NULL);
    492  1.1  simonb 
    493  1.1  simonb 	ih->ih_func = func;
    494  1.1  simonb 	ih->ih_arg = arg;
    495  1.1  simonb 	ih->ih_irq = irq;
    496  1.1  simonb 
    497  1.1  simonb 	s = splhigh();
    498  1.1  simonb 
    499  1.1  simonb 	/* Insert the handler into the table. */
    500  1.1  simonb 	LIST_INSERT_HEAD(&my_sc->sc_intrtab[irq].intr_q, ih, ih_q);
    501  1.1  simonb 	my_sc->sc_intrtab[irq].intr_type = type;
    502  1.1  simonb 
    503  1.1  simonb 	/* Enable it, set trigger mode. */
    504  1.1  simonb 	my_sc->sc_imask &= ~(1 << irq);
    505  1.1  simonb 	if (my_sc->sc_intrtab[irq].intr_type == IST_LEVEL)
    506  1.1  simonb 		my_sc->sc_elcr |= (1 << irq);
    507  1.1  simonb 	else
    508  1.1  simonb 		my_sc->sc_elcr &= ~(1 << irq);
    509  1.1  simonb 
    510  1.1  simonb 	pcib_set_icus(my_sc);
    511  1.1  simonb 
    512  1.1  simonb 	splx(s);
    513  1.1  simonb 
    514  1.1  simonb 	return (ih);
    515  1.1  simonb }
    516  1.1  simonb 
    517  1.1  simonb void
    518  1.1  simonb pcib_isa_intr_disestablish(void *v, void *arg)
    519  1.1  simonb {
    520  1.1  simonb 	struct evbmips_intrhand *ih = arg;
    521  1.1  simonb 	int s;
    522  1.1  simonb 
    523  1.1  simonb 	s = splhigh();
    524  1.1  simonb 
    525  1.1  simonb 	LIST_REMOVE(ih, ih_q);
    526  1.1  simonb 
    527  1.1  simonb 	/* If there are no more handlers on this IRQ, disable it. */
    528  1.1  simonb 	if (LIST_FIRST(&my_sc->sc_intrtab[ih->ih_irq].intr_q) == NULL) {
    529  1.1  simonb 		my_sc->sc_imask |= (1 << ih->ih_irq);
    530  1.1  simonb 		pcib_set_icus(my_sc);
    531  1.1  simonb 	}
    532  1.1  simonb 
    533  1.1  simonb 	splx(s);
    534  1.1  simonb 
    535  1.1  simonb 	free(ih, M_DEVBUF);
    536  1.1  simonb }
    537  1.1  simonb 
    538  1.1  simonb static int
    539  1.1  simonb pcib_isa_intr_alloc(void *v, int mask, int type, int *irq)
    540  1.1  simonb {
    541  1.1  simonb 	int i, tmp, bestirq, count;
    542  1.1  simonb 	struct evbmips_intrhand *ih;
    543  1.1  simonb 
    544  1.1  simonb 	if (type == IST_NONE)
    545  1.1  simonb 		panic("pcib_intr_alloc: bogus type");
    546  1.1  simonb 
    547  1.1  simonb 	bestirq = -1;
    548  1.1  simonb 	count = -1;
    549  1.1  simonb 
    550  1.1  simonb 	mask &= ~my_sc->sc_reserved;
    551  1.1  simonb 
    552  1.1  simonb 	for (i = 0; i < ICU_LEN; i++) {
    553  1.1  simonb 		if ((mask & (1 << i)) == 0)
    554  1.1  simonb 			continue;
    555  1.1  simonb 
    556  1.1  simonb 		switch (my_sc->sc_intrtab[i].intr_type) {
    557  1.1  simonb 		case IST_NONE:
    558  1.1  simonb 			/*
    559  1.1  simonb 			 * If nothing's using the IRQ, just return it.
    560  1.1  simonb 			 */
    561  1.1  simonb 			*irq = i;
    562  1.1  simonb 			return (0);
    563  1.1  simonb 
    564  1.1  simonb 		case IST_EDGE:
    565  1.1  simonb 		case IST_LEVEL:
    566  1.1  simonb 			if (type != my_sc->sc_intrtab[i].intr_type)
    567  1.1  simonb 				continue;
    568  1.1  simonb 			/*
    569  1.1  simonb 			 * If the IRQ is sharable, count the number of
    570  1.1  simonb 			 * other handlers, and if it's smaller than the
    571  1.1  simonb 			 * last IRQ like this, remember it.
    572  1.1  simonb 			 */
    573  1.1  simonb 			tmp = 0;
    574  1.1  simonb 			for (ih = LIST_FIRST(&my_sc->sc_intrtab[i].intr_q);
    575  1.1  simonb 				ih != NULL; ih = LIST_NEXT(ih, ih_q))
    576  1.1  simonb 			tmp++;
    577  1.1  simonb 			if (bestirq == -1 || count > tmp) {
    578  1.1  simonb 				bestirq = i;
    579  1.1  simonb 				count = tmp;
    580  1.1  simonb 			}
    581  1.1  simonb 			break;
    582  1.1  simonb 
    583  1.1  simonb 		case IST_PULSE:
    584  1.1  simonb 		/* This just isn't sharable. */
    585  1.1  simonb 		continue;
    586  1.1  simonb 		}
    587  1.1  simonb 	}
    588  1.1  simonb 
    589  1.1  simonb 	if (bestirq == -1)
    590  1.1  simonb 		return (1);
    591  1.1  simonb 
    592  1.1  simonb 	*irq = bestirq;
    593  1.1  simonb 	return (0);
    594  1.1  simonb }
    595  1.1  simonb 
    596  1.1  simonb static void
    597  1.1  simonb pcib_cleanup(void *arg)
    598  1.1  simonb {
    599  1.1  simonb 
    600  1.1  simonb 	my_sc->sc_imask = 0xffff;
    601  1.1  simonb 	pcib_set_icus(my_sc);
    602  1.1  simonb }
    603