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