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