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