Home | History | Annotate | Line # | Download | only in pci
pcib.c revision 1.5
      1  1.5  thorpej /*	$NetBSD: pcib.c,v 1.5 2002/10/01 03:02:07 thorpej 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.2   simonb 	struct mips_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.2   simonb struct mips_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.5  thorpej CFATTACH_DECL(pcib, sizeof(struct pcib_softc),
    136  1.5  thorpej     pcib_match, pcib_attach, NULL, NULL)
    137  1.1   simonb 
    138  1.1   simonb static int
    139  1.1   simonb pcib_match(struct device *parent, struct cfdata *match, void *aux)
    140  1.1   simonb {
    141  1.1   simonb 	struct pci_attach_args *pa = aux;
    142  1.1   simonb 
    143  1.1   simonb 	if (PCI_CLASS(pa->pa_class) == PCI_CLASS_BRIDGE &&
    144  1.1   simonb 	    PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_BRIDGE_ISA)
    145  1.1   simonb 		return (1);
    146  1.1   simonb 
    147  1.1   simonb 	return (0);
    148  1.1   simonb }
    149  1.1   simonb 
    150  1.1   simonb static void
    151  1.1   simonb pcib_attach(struct device *parent, struct device *self, void *aux)
    152  1.1   simonb {
    153  1.1   simonb 	struct pci_attach_args *pa = aux;
    154  1.1   simonb 	char devinfo[256];
    155  1.1   simonb 	int i;
    156  1.1   simonb 
    157  1.1   simonb 	printf("\n");
    158  1.1   simonb 
    159  1.1   simonb 	if (my_sc != NULL)
    160  1.3   provos 		panic("pcib_attach: already attached!");
    161  1.1   simonb 	my_sc = (void *)self;
    162  1.1   simonb 
    163  1.1   simonb 	/*
    164  1.1   simonb 	 * Just print out a description and defer configuration
    165  1.1   simonb 	 * until all PCI devices have been attached.
    166  1.1   simonb 	 */
    167  1.1   simonb 	pci_devinfo(pa->pa_id, pa->pa_class, 0, devinfo);
    168  1.1   simonb 	printf("%s: %s, (rev . 0x%02x)\n", self->dv_xname, devinfo,
    169  1.1   simonb 	    PCI_REVISION(pa->pa_class));
    170  1.1   simonb 
    171  1.1   simonb 	my_sc->sc_iot = pa->pa_iot;
    172  1.1   simonb 
    173  1.1   simonb 	/*
    174  1.1   simonb 	 * Map the PIC/ELCR registers.
    175  1.1   simonb 	 */
    176  1.1   simonb 	if (bus_space_map(my_sc->sc_iot, 0x4d0, 2, 0, &my_sc->sc_ioh_elcr) != 0)
    177  1.1   simonb 		printf("%s: unable to map ELCR registers\n",
    178  1.1   simonb 		    my_sc->sc_dev.dv_xname);
    179  1.1   simonb 	if (bus_space_map(my_sc->sc_iot, IO_ICU1, 2, 0, &my_sc->sc_ioh_icu1) != 0)
    180  1.1   simonb 		printf("%s: unable to map ICU1 registers\n",
    181  1.1   simonb 		    my_sc->sc_dev.dv_xname);
    182  1.1   simonb 	if (bus_space_map(my_sc->sc_iot, IO_ICU2, 2, 0, &my_sc->sc_ioh_icu2) != 0)
    183  1.1   simonb 		printf("%s: unable to map ICU2 registers\n",
    184  1.1   simonb 		    my_sc->sc_dev.dv_xname);
    185  1.1   simonb 
    186  1.1   simonb 	/* All interrupts default to "masked off". */
    187  1.1   simonb 	my_sc->sc_imask = 0xffff;
    188  1.1   simonb 
    189  1.1   simonb 	/* All interrupts default to edge-triggered. */
    190  1.1   simonb 	my_sc->sc_elcr = 0;
    191  1.1   simonb 
    192  1.1   simonb 	/*
    193  1.1   simonb 	 * Initialize the 8259s.
    194  1.1   simonb 	 */
    195  1.1   simonb 	/* reset, program device, 4 bytes */
    196  1.1   simonb 	bus_space_write_1(my_sc->sc_iot, my_sc->sc_ioh_icu1, PIC_ICW1,
    197  1.1   simonb 	    ICW1_SELECT | ICW1_IC4);
    198  1.1   simonb 	bus_space_write_1(my_sc->sc_iot, my_sc->sc_ioh_icu1, PIC_ICW2,
    199  1.1   simonb 	    ICW2_VECTOR(0)/*XXX*/);
    200  1.1   simonb 	bus_space_write_1(my_sc->sc_iot, my_sc->sc_ioh_icu1, PIC_ICW3,
    201  1.1   simonb 	    ICW3_CASCADE(2));
    202  1.1   simonb 	bus_space_write_1(my_sc->sc_iot, my_sc->sc_ioh_icu1, PIC_ICW4,
    203  1.1   simonb 	    ICW4_8086);
    204  1.1   simonb 
    205  1.1   simonb 	/* mask all interrupts */
    206  1.1   simonb 	bus_space_write_1(my_sc->sc_iot, my_sc->sc_ioh_icu1, PIC_OCW1,
    207  1.1   simonb 	    my_sc->sc_imask & 0xff);
    208  1.1   simonb 
    209  1.1   simonb 	/* enable special mask mode */
    210  1.1   simonb 	bus_space_write_1(my_sc->sc_iot, my_sc->sc_ioh_icu1, PIC_OCW3,
    211  1.1   simonb 	    OCW3_SELECT | OCW3_SSMM | OCW3_SMM);
    212  1.1   simonb 
    213  1.1   simonb 	/* read IRR by default */
    214  1.1   simonb 	bus_space_write_1(my_sc->sc_iot, my_sc->sc_ioh_icu1, PIC_OCW3,
    215  1.1   simonb 	    OCW3_SELECT | OCW3_RR);
    216  1.1   simonb 
    217  1.1   simonb 	/* reset, program device, 4 bytes */
    218  1.1   simonb 	bus_space_write_1(my_sc->sc_iot, my_sc->sc_ioh_icu2, PIC_ICW1,
    219  1.1   simonb 	    ICW1_SELECT | ICW1_IC4);
    220  1.1   simonb 	bus_space_write_1(my_sc->sc_iot, my_sc->sc_ioh_icu2, PIC_ICW2,
    221  1.1   simonb 	    ICW2_VECTOR(0)/*XXX*/);
    222  1.1   simonb 	bus_space_write_1(my_sc->sc_iot, my_sc->sc_ioh_icu2, PIC_ICW3,
    223  1.1   simonb 	    ICW3_CASCADE(2));
    224  1.1   simonb 	bus_space_write_1(my_sc->sc_iot, my_sc->sc_ioh_icu2, PIC_ICW4,
    225  1.1   simonb 	    ICW4_8086);
    226  1.1   simonb 
    227  1.1   simonb 	/* mask all interrupts */
    228  1.1   simonb 	bus_space_write_1(my_sc->sc_iot, my_sc->sc_ioh_icu2, PIC_OCW1,
    229  1.1   simonb 	    my_sc->sc_imask & 0xff);
    230  1.1   simonb 
    231  1.1   simonb 	/* enable special mask mode */
    232  1.1   simonb 	bus_space_write_1(my_sc->sc_iot, my_sc->sc_ioh_icu2, PIC_OCW3,
    233  1.1   simonb 	    OCW3_SELECT | OCW3_SSMM | OCW3_SMM);
    234  1.1   simonb 
    235  1.1   simonb 	/* read IRR by default */
    236  1.1   simonb 	bus_space_write_1(my_sc->sc_iot, my_sc->sc_ioh_icu2, PIC_OCW3,
    237  1.1   simonb 	    OCW3_SELECT | OCW3_RR);
    238  1.1   simonb 
    239  1.1   simonb 	/*
    240  1.1   simonb 	 * Default all interrupts to edge-triggered.
    241  1.1   simonb 	 */
    242  1.1   simonb 	bus_space_write_1(my_sc->sc_iot, my_sc->sc_ioh_elcr, 0,
    243  1.1   simonb 	    my_sc->sc_elcr & 0xff);
    244  1.1   simonb 	bus_space_write_1(my_sc->sc_iot, my_sc->sc_ioh_elcr, 1,
    245  1.1   simonb 	    (my_sc->sc_elcr >> 8) & 0xff);
    246  1.1   simonb 
    247  1.1   simonb 	/*
    248  1.1   simonb 	 * Some ISA interrupts are reserved for devices that
    249  1.1   simonb 	 * we know are hard-wired to certain IRQs.
    250  1.1   simonb 	 */
    251  1.1   simonb 	my_sc->sc_reserved =
    252  1.1   simonb 		(1U << 0) |     /* timer */
    253  1.1   simonb 		(1U << 1) |     /* keyboard controller (keyboard) */
    254  1.1   simonb 		(1U << 2) |     /* PIC cascade */
    255  1.1   simonb 		(1U << 3) |     /* COM 2 */
    256  1.1   simonb 		(1U << 4) |     /* COM 1 */
    257  1.1   simonb 		(1U << 6) |     /* floppy */
    258  1.1   simonb 		(1U << 7) |     /* centronics */
    259  1.1   simonb 		(1U << 8) |     /* RTC */
    260  1.1   simonb 		(1U << 9) |	/* I2C */
    261  1.1   simonb 		(1U << 12) |    /* keyboard controller (mouse) */
    262  1.1   simonb 		(1U << 14) |    /* IDE primary */
    263  1.1   simonb 		(1U << 15);     /* IDE secondary */
    264  1.1   simonb 
    265  1.1   simonb 	/* Set up our ISA chipset. */
    266  1.1   simonb 	my_sc->sc_ic.ic_v = my_sc;
    267  1.1   simonb 	my_sc->sc_ic.ic_intr_evcnt = pcib_isa_intr_evcnt;
    268  1.1   simonb 	my_sc->sc_ic.ic_intr_establish = pcib_isa_intr_establish;
    269  1.1   simonb 	my_sc->sc_ic.ic_intr_disestablish = pcib_isa_intr_disestablish;
    270  1.1   simonb 	my_sc->sc_ic.ic_intr_alloc = pcib_isa_intr_alloc;
    271  1.1   simonb 	my_sc->sc_ic.ic_intr_string = pcib_isa_intr_string;
    272  1.1   simonb 
    273  1.1   simonb 	pcib_ic = &my_sc->sc_ic;	/* XXX for external use */
    274  1.1   simonb 
    275  1.1   simonb 	/* Initialize our interrupt table. */
    276  1.1   simonb 	for (i = 0; i < ICU_LEN; i++) {
    277  1.1   simonb #if 0
    278  1.1   simonb 		char irqstr[8];		/* 4 + 2 + NULL + sanity */
    279  1.1   simonb 
    280  1.1   simonb 		sprintf(irqstr, "irq %d", i);
    281  1.1   simonb 		evcnt_attach_dynamic(&my_sc->sc_intrtab[i].intr_count,
    282  1.1   simonb 		    EVCNT_TYPE_INTR, NULL, "pcib", irqstr);
    283  1.1   simonb #else
    284  1.1   simonb 		evcnt_attach_dynamic(&my_sc->sc_intrtab[i].intr_count,
    285  1.1   simonb 		    EVCNT_TYPE_INTR, NULL, "pcib", isa_intrnames[i]);
    286  1.1   simonb #endif
    287  1.1   simonb 		LIST_INIT(&my_sc->sc_intrtab[i].intr_q);
    288  1.1   simonb 		my_sc->sc_intrtab[i].intr_type = IST_NONE;
    289  1.1   simonb 	}
    290  1.1   simonb 
    291  1.1   simonb 	/* Hook up our interrupt handler. */
    292  1.1   simonb 	my_sc->sc_ih = evbmips_intr_establish(MALTA_SOUTHBRIDGE_INTR, pcib_intr, my_sc);
    293  1.1   simonb 	if (my_sc->sc_ih == NULL)
    294  1.1   simonb 		printf("%s: WARNING: unable to register interrupt handler\n",
    295  1.1   simonb 		    my_sc->sc_dev.dv_xname);
    296  1.1   simonb 
    297  1.1   simonb 
    298  1.1   simonb 	/*
    299  1.1   simonb 	 * Disable ISA interrupts before returning to YAMON.
    300  1.1   simonb 	 */
    301  1.1   simonb 	if (shutdownhook_establish(pcib_cleanup, my_sc) == NULL)
    302  1.1   simonb 		panic("pcib_attach: could not establish shutdown hook");
    303  1.1   simonb 
    304  1.1   simonb 	config_defer(self, pcib_bridge_callback);
    305  1.1   simonb }
    306  1.1   simonb 
    307  1.1   simonb static void
    308  1.1   simonb pcib_bridge_callback(struct device *self)
    309  1.1   simonb {
    310  1.1   simonb 	struct pcib_softc *sc = (void *)self;
    311  1.1   simonb 	struct malta_config *mcp = &malta_configuration;
    312  1.1   simonb 	struct isabus_attach_args iba;
    313  1.1   simonb 
    314  1.1   simonb 	/*
    315  1.1   simonb 	 * Attach the ISA bus behind this bridge.
    316  1.1   simonb 	 */
    317  1.1   simonb 	memset(&iba, 0, sizeof(iba));
    318  1.1   simonb 
    319  1.1   simonb 	iba.iba_busname = "isa";
    320  1.1   simonb 	iba.iba_iot = &mcp->mc_iot;
    321  1.1   simonb 	iba.iba_memt = &mcp->mc_memt;
    322  1.1   simonb 	iba.iba_dmat = &mcp->mc_isa_dmat;
    323  1.1   simonb 
    324  1.1   simonb 	iba.iba_ic = &sc->sc_ic;
    325  1.1   simonb 	iba.iba_ic->ic_attach_hook = pcib_isa_attach_hook;
    326  1.1   simonb 
    327  1.1   simonb 	config_found(&sc->sc_dev, &iba, pcib_print);
    328  1.1   simonb }
    329  1.1   simonb 
    330  1.1   simonb static int
    331  1.1   simonb pcib_print(void *aux, const char *pnp)
    332  1.1   simonb {
    333  1.1   simonb 
    334  1.1   simonb 	/* Only ISAs can attach to pcib's; easy. */
    335  1.1   simonb 	if (pnp)
    336  1.1   simonb 		printf("isa at %s", pnp);
    337  1.1   simonb 	return (UNCONF);
    338  1.1   simonb }
    339  1.1   simonb 
    340  1.1   simonb static void
    341  1.1   simonb pcib_isa_attach_hook(struct device *parent, struct device *self,
    342  1.1   simonb     struct isabus_attach_args *iba)
    343  1.1   simonb {
    344  1.1   simonb 
    345  1.1   simonb 	/* Nothing to do. */
    346  1.1   simonb }
    347  1.1   simonb 
    348  1.1   simonb static void
    349  1.1   simonb pcib_set_icus(struct pcib_softc *sc)
    350  1.1   simonb {
    351  1.1   simonb 
    352  1.1   simonb 	/* Enable the cascade IRQ (2) if 8-15 is enabled. */
    353  1.1   simonb 	if ((sc->sc_imask & 0xff00) != 0xff00)
    354  1.1   simonb 		sc->sc_imask &= ~(1U << 2);
    355  1.1   simonb 	else
    356  1.1   simonb 		sc->sc_imask |= (1U << 2);
    357  1.1   simonb 
    358  1.1   simonb 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW1,
    359  1.1   simonb 	    sc->sc_imask & 0xff);
    360  1.1   simonb 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, PIC_OCW1,
    361  1.1   simonb 	    (sc->sc_imask >> 8) & 0xff);
    362  1.1   simonb 
    363  1.1   simonb 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_elcr, 0,
    364  1.1   simonb 	    sc->sc_elcr & 0xff);
    365  1.1   simonb 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_elcr, 1,
    366  1.1   simonb 	    (sc->sc_elcr >> 8) & 0xff);
    367  1.1   simonb }
    368  1.1   simonb 
    369  1.1   simonb static int
    370  1.1   simonb pcib_intr(void *v)
    371  1.1   simonb {
    372  1.1   simonb 	struct pcib_softc *sc = v;
    373  1.1   simonb 	struct evbmips_intrhand *ih;
    374  1.1   simonb 	int irq;
    375  1.1   simonb 
    376  1.1   simonb 	for (;;) {
    377  1.1   simonb #if 1
    378  1.1   simonb 		bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW3,
    379  1.1   simonb 		    OCW3_SELECT | OCW3_POLL);
    380  1.1   simonb 		irq = bus_space_read_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW3);
    381  1.1   simonb 		if ((irq & OCW3_POLL_PENDING) == 0)
    382  1.1   simonb 			return (1);
    383  1.1   simonb 
    384  1.1   simonb 		irq = OCW3_POLL_IRQ(irq);
    385  1.1   simonb 
    386  1.1   simonb 		if (irq == 2) {
    387  1.1   simonb 			bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2,
    388  1.1   simonb 			    PIC_OCW3, OCW3_SELECT | OCW3_POLL);
    389  1.1   simonb 			irq = bus_space_read_1(sc->sc_iot, sc->sc_ioh_icu2,
    390  1.1   simonb 			    PIC_OCW3);
    391  1.1   simonb 			if (irq & OCW3_POLL_PENDING)
    392  1.1   simonb 				irq = OCW3_POLL_IRQ(irq) + 8;
    393  1.1   simonb 			else
    394  1.1   simonb 				irq = 2;
    395  1.1   simonb 		}
    396  1.1   simonb #else
    397  1.1   simonb 		/* XXX - should be a function call to gt.c? */
    398  1.1   simonb 		irq = GT_REGVAL(GT_PCI0_INTR_ACK) & 0xff;
    399  1.1   simonb 
    400  1.1   simonb 		/*
    401  1.1   simonb 		 * From YAMON source code:
    402  1.1   simonb 		 *
    403  1.1   simonb 		 * IRQ7 is used to detect spurious interrupts.
    404  1.1   simonb 		 * The interrupt acknowledge cycle returns IRQ7, if no
    405  1.1   simonb 		 * interrupts is requested.
    406  1.1   simonb 		 * We can differentiate between this situation and a
    407  1.1   simonb 		 * "Normal" IRQ7 by reading the ISR.
    408  1.1   simonb 		 */
    409  1.1   simonb 
    410  1.1   simonb 		if (irq == 7) {
    411  1.1   simonb 			int reg;
    412  1.1   simonb 
    413  1.1   simonb 			bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW3,
    414  1.1   simonb 			    OCW3_SELECT | OCW3_RR | OCW3_RIS);
    415  1.1   simonb 			reg = bus_space_read_1(sc->sc_iot, sc->sc_ioh_icu1,
    416  1.1   simonb 			    PIC_OCW3);
    417  1.1   simonb 			if (!(reg & (1 << 7)))
    418  1.1   simonb 				break;	/* spurious interrupt */
    419  1.1   simonb 		}
    420  1.1   simonb #endif
    421  1.1   simonb 
    422  1.1   simonb 		sc->sc_intrtab[irq].intr_count.ev_count++;
    423  1.1   simonb 		LIST_FOREACH(ih, &sc->sc_intrtab[irq].intr_q, ih_q)
    424  1.1   simonb 			(*ih->ih_func)(ih->ih_arg);
    425  1.1   simonb 
    426  1.1   simonb 		/* Send a specific EOI to the 8259. */
    427  1.1   simonb 		if (irq > 7) {
    428  1.1   simonb 			bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2,
    429  1.1   simonb 			    PIC_OCW2, OCW2_SELECT | OCW3_EOI | OCW3_SL |
    430  1.1   simonb 			    OCW2_ILS(irq & 7));
    431  1.1   simonb 			irq = 2;
    432  1.1   simonb 		}
    433  1.1   simonb 
    434  1.1   simonb 		bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW2,
    435  1.1   simonb 		    OCW2_SELECT | OCW3_EOI | OCW3_SL | OCW2_ILS(irq));
    436  1.1   simonb 	}
    437  1.1   simonb }
    438  1.1   simonb 
    439  1.1   simonb const char *
    440  1.1   simonb pcib_isa_intr_string(void *v, int irq)
    441  1.1   simonb {
    442  1.1   simonb 	static char irqstr[12];		/* 8 + 2 + NULL + sanity */
    443  1.1   simonb 
    444  1.1   simonb 	if (irq == 0 || irq >= ICU_LEN || irq == 2)
    445  1.3   provos 		panic("pcib_isa_intr_string: bogus isa irq 0x%x", irq);
    446  1.1   simonb 
    447  1.1   simonb 	sprintf(irqstr, "isa irq %d", irq);
    448  1.1   simonb 	return (irqstr);
    449  1.1   simonb }
    450  1.1   simonb 
    451  1.1   simonb const struct evcnt *
    452  1.1   simonb pcib_isa_intr_evcnt(void *v, int irq)
    453  1.1   simonb {
    454  1.1   simonb 
    455  1.1   simonb 	if (irq == 0 || irq >= ICU_LEN || irq == 2)
    456  1.3   provos 		panic("pcib_isa_intr_evcnt: bogus isa irq 0x%x", irq);
    457  1.1   simonb 
    458  1.1   simonb 	return (&my_sc->sc_intrtab[irq].intr_count);
    459  1.1   simonb }
    460  1.1   simonb 
    461  1.1   simonb void *
    462  1.1   simonb pcib_isa_intr_establish(void *v, int irq, int type, int level,
    463  1.1   simonb     int (*func)(void *), void *arg)
    464  1.1   simonb {
    465  1.1   simonb 	struct evbmips_intrhand *ih;
    466  1.1   simonb 	int s;
    467  1.1   simonb 
    468  1.1   simonb 	if (irq >= ICU_LEN || irq == 2 || type == IST_NONE)
    469  1.1   simonb 		panic("pcib_isa_intr_establish: bad irq or type");
    470  1.1   simonb 
    471  1.1   simonb 	switch (my_sc->sc_intrtab[irq].intr_type) {
    472  1.1   simonb 	case IST_NONE:
    473  1.1   simonb 		my_sc->sc_intrtab[irq].intr_type = type;
    474  1.1   simonb 		break;
    475  1.1   simonb 
    476  1.1   simonb 	case IST_EDGE:
    477  1.1   simonb 	case IST_LEVEL:
    478  1.1   simonb 		if (type == my_sc->sc_intrtab[irq].intr_type)
    479  1.1   simonb 			break;
    480  1.1   simonb 		/* FALLTHROUGH */
    481  1.1   simonb 	case IST_PULSE:
    482  1.1   simonb 		/*
    483  1.1   simonb 		 * We can't share interrupts in this case.
    484  1.1   simonb 		 */
    485  1.1   simonb 		return (NULL);
    486  1.1   simonb 	}
    487  1.1   simonb 
    488  1.1   simonb 	ih = malloc(sizeof(*ih), M_DEVBUF, M_NOWAIT);
    489  1.1   simonb 	if (ih == NULL)
    490  1.1   simonb 		return (NULL);
    491  1.1   simonb 
    492  1.1   simonb 	ih->ih_func = func;
    493  1.1   simonb 	ih->ih_arg = arg;
    494  1.1   simonb 	ih->ih_irq = irq;
    495  1.1   simonb 
    496  1.1   simonb 	s = splhigh();
    497  1.1   simonb 
    498  1.1   simonb 	/* Insert the handler into the table. */
    499  1.1   simonb 	LIST_INSERT_HEAD(&my_sc->sc_intrtab[irq].intr_q, ih, ih_q);
    500  1.1   simonb 	my_sc->sc_intrtab[irq].intr_type = type;
    501  1.1   simonb 
    502  1.1   simonb 	/* Enable it, set trigger mode. */
    503  1.1   simonb 	my_sc->sc_imask &= ~(1 << irq);
    504  1.1   simonb 	if (my_sc->sc_intrtab[irq].intr_type == IST_LEVEL)
    505  1.1   simonb 		my_sc->sc_elcr |= (1 << irq);
    506  1.1   simonb 	else
    507  1.1   simonb 		my_sc->sc_elcr &= ~(1 << irq);
    508  1.1   simonb 
    509  1.1   simonb 	pcib_set_icus(my_sc);
    510  1.1   simonb 
    511  1.1   simonb 	splx(s);
    512  1.1   simonb 
    513  1.1   simonb 	return (ih);
    514  1.1   simonb }
    515  1.1   simonb 
    516  1.1   simonb void
    517  1.1   simonb pcib_isa_intr_disestablish(void *v, void *arg)
    518  1.1   simonb {
    519  1.1   simonb 	struct evbmips_intrhand *ih = arg;
    520  1.1   simonb 	int s;
    521  1.1   simonb 
    522  1.1   simonb 	s = splhigh();
    523  1.1   simonb 
    524  1.1   simonb 	LIST_REMOVE(ih, ih_q);
    525  1.1   simonb 
    526  1.1   simonb 	/* If there are no more handlers on this IRQ, disable it. */
    527  1.1   simonb 	if (LIST_FIRST(&my_sc->sc_intrtab[ih->ih_irq].intr_q) == NULL) {
    528  1.1   simonb 		my_sc->sc_imask |= (1 << ih->ih_irq);
    529  1.1   simonb 		pcib_set_icus(my_sc);
    530  1.1   simonb 	}
    531  1.1   simonb 
    532  1.1   simonb 	splx(s);
    533  1.1   simonb 
    534  1.1   simonb 	free(ih, M_DEVBUF);
    535  1.1   simonb }
    536  1.1   simonb 
    537  1.1   simonb static int
    538  1.1   simonb pcib_isa_intr_alloc(void *v, int mask, int type, int *irq)
    539  1.1   simonb {
    540  1.1   simonb 	int i, tmp, bestirq, count;
    541  1.1   simonb 	struct evbmips_intrhand *ih;
    542  1.1   simonb 
    543  1.1   simonb 	if (type == IST_NONE)
    544  1.1   simonb 		panic("pcib_intr_alloc: bogus type");
    545  1.1   simonb 
    546  1.1   simonb 	bestirq = -1;
    547  1.1   simonb 	count = -1;
    548  1.1   simonb 
    549  1.1   simonb 	mask &= ~my_sc->sc_reserved;
    550  1.1   simonb 
    551  1.1   simonb 	for (i = 0; i < ICU_LEN; i++) {
    552  1.1   simonb 		if ((mask & (1 << i)) == 0)
    553  1.1   simonb 			continue;
    554  1.1   simonb 
    555  1.1   simonb 		switch (my_sc->sc_intrtab[i].intr_type) {
    556  1.1   simonb 		case IST_NONE:
    557  1.1   simonb 			/*
    558  1.1   simonb 			 * If nothing's using the IRQ, just return it.
    559  1.1   simonb 			 */
    560  1.1   simonb 			*irq = i;
    561  1.1   simonb 			return (0);
    562  1.1   simonb 
    563  1.1   simonb 		case IST_EDGE:
    564  1.1   simonb 		case IST_LEVEL:
    565  1.1   simonb 			if (type != my_sc->sc_intrtab[i].intr_type)
    566  1.1   simonb 				continue;
    567  1.1   simonb 			/*
    568  1.1   simonb 			 * If the IRQ is sharable, count the number of
    569  1.1   simonb 			 * other handlers, and if it's smaller than the
    570  1.1   simonb 			 * last IRQ like this, remember it.
    571  1.1   simonb 			 */
    572  1.1   simonb 			tmp = 0;
    573  1.1   simonb 			for (ih = LIST_FIRST(&my_sc->sc_intrtab[i].intr_q);
    574  1.1   simonb 				ih != NULL; ih = LIST_NEXT(ih, ih_q))
    575  1.1   simonb 			tmp++;
    576  1.1   simonb 			if (bestirq == -1 || count > tmp) {
    577  1.1   simonb 				bestirq = i;
    578  1.1   simonb 				count = tmp;
    579  1.1   simonb 			}
    580  1.1   simonb 			break;
    581  1.1   simonb 
    582  1.1   simonb 		case IST_PULSE:
    583  1.1   simonb 		/* This just isn't sharable. */
    584  1.1   simonb 		continue;
    585  1.1   simonb 		}
    586  1.1   simonb 	}
    587  1.1   simonb 
    588  1.1   simonb 	if (bestirq == -1)
    589  1.1   simonb 		return (1);
    590  1.1   simonb 
    591  1.1   simonb 	*irq = bestirq;
    592  1.1   simonb 	return (0);
    593  1.1   simonb }
    594  1.1   simonb 
    595  1.1   simonb static void
    596  1.1   simonb pcib_cleanup(void *arg)
    597  1.1   simonb {
    598  1.1   simonb 
    599  1.1   simonb 	my_sc->sc_imask = 0xffff;
    600  1.1   simonb 	pcib_set_icus(my_sc);
    601  1.1   simonb }
    602