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