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