1 /* $NetBSD: rmixl_intr.c,v 1.2 2009/12/14 00:46:07 matt Exp $ */ 2 3 /*- 4 * Copyright (c) 2007 Ruslan Ermilov and Vsevolod Lobko. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or 8 * without modification, are permitted provided that the following 9 * conditions are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above 13 * copyright notice, this list of conditions and the following 14 * disclaimer in the documentation and/or other materials provided 15 * with the distribution. 16 * 3. The names of the authors may not be used to endorse or promote 17 * products derived from this software without specific prior 18 * written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY 21 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 22 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 23 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS 24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 25 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 27 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 29 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 30 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 31 * OF SUCH DAMAGE. 32 */ 33 /*- 34 * Copyright (c) 2001 The NetBSD Foundation, Inc. 35 * All rights reserved. 36 * 37 * This code is derived from software contributed to The NetBSD Foundation 38 * by Jason R. Thorpe. 39 * 40 * Redistribution and use in source and binary forms, with or without 41 * modification, are permitted provided that the following conditions 42 * are met: 43 * 1. Redistributions of source code must retain the above copyright 44 * notice, this list of conditions and the following disclaimer. 45 * 2. Redistributions in binary form must reproduce the above copyright 46 * notice, this list of conditions and the following disclaimer in the 47 * documentation and/or other materials provided with the distribution. 48 * 49 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 50 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 51 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 52 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 53 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 54 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 55 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 56 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 57 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 58 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 59 * POSSIBILITY OF SUCH DAMAGE. 60 */ 61 62 /* 63 * Platform-specific interrupt support for the RMI XLP, XLR, XLS 64 */ 65 66 #include <sys/cdefs.h> 67 __KERNEL_RCSID(0, "$NetBSD: rmixl_intr.c,v 1.2 2009/12/14 00:46:07 matt Exp $"); 68 69 #include "opt_ddb.h" 70 71 #include <sys/param.h> 72 #include <sys/queue.h> 73 #include <sys/malloc.h> 74 #include <sys/systm.h> 75 #include <sys/device.h> 76 #include <sys/kernel.h> 77 78 #include <machine/bus.h> 79 #include <machine/intr.h> 80 81 #include <mips/cpu.h> 82 #include <mips/locore.h> 83 84 #include <mips/rmi/rmixlreg.h> 85 #include <mips/rmi/rmixlvar.h> 86 87 #include <dev/pci/pcireg.h> 88 #include <dev/pci/pcivar.h> 89 90 #ifdef IOINTR_DEBUG 91 int iointr_debug = IOINTR_DEBUG; 92 # define DPRINTF(x) do { if (iointr_debug) printf x ; } while(0) 93 #else 94 # define DPRINTF(x) 95 #endif 96 97 #define RMIXL_PICREG_READ(off) \ 98 RMIXL_IOREG_READ(RMIXL_IO_DEV_PIC + (off)) 99 #define RMIXL_PICREG_WRITE(off, val) \ 100 RMIXL_IOREG_WRITE(RMIXL_IO_DEV_PIC + (off), (val)) 101 /* 102 * This is a mask of bits to clear in the SR when we go to a 103 * given hardware interrupt priority level. 104 * _SR_BITS_DFLT bits are to be always clear (disabled) 105 */ 106 #define _SR_BITS_DFLT (MIPS_INT_MASK_2|MIPS_INT_MASK_3|MIPS_INT_MASK_4) 107 const uint32_t ipl_sr_bits[_IPL_N] = { 108 [IPL_NONE] = _SR_BITS_DFLT, 109 [IPL_SOFTCLOCK] = 110 _SR_BITS_DFLT 111 | MIPS_SOFT_INT_MASK_0, 112 [IPL_SOFTNET] = 113 _SR_BITS_DFLT 114 | MIPS_SOFT_INT_MASK_0 115 | MIPS_SOFT_INT_MASK_1, 116 [IPL_VM] = 117 _SR_BITS_DFLT 118 | MIPS_SOFT_INT_MASK_0 119 | MIPS_SOFT_INT_MASK_1 120 | MIPS_INT_MASK_0, 121 [IPL_SCHED] = 122 MIPS_INT_MASK, 123 }; 124 125 /* 126 * 'IRQs' here are indiividual interrupt sources 127 * each has a slot in the Interrupt Redirection Table (IRT) 128 * in the order listed 129 * 130 * NOTE: many irq sources depend on the chip family 131 * XLS1xx vs. XLS2xx vs. XLS3xx vs. XLS6xx 132 * use the right table for the CPU that's running. 133 */ 134 135 /* 136 * rmixl_irqnames_xls1xx 137 * - use for XLS1xx, XLS2xx, XLS4xx-Lite 138 */ 139 #define NIRQS 32 140 static const char *rmixl_irqnames_xls1xx[NIRQS] = { 141 "int 0 (watchdog)", /* 0 */ 142 "int 1 (timer0)", /* 1 */ 143 "int 2 (timer1)", /* 2 */ 144 "int 3 (timer2)", /* 3 */ 145 "int 4 (timer3)", /* 4 */ 146 "int 5 (timer4)", /* 5 */ 147 "int 6 (timer5)", /* 6 */ 148 "int 7 (timer6)", /* 7 */ 149 "int 8 (timer7)", /* 8 */ 150 "int 9 (uart0)", /* 9 */ 151 "int 10 (uart1)", /* 10 */ 152 "int 11 (i2c0)", /* 11 */ 153 "int 12 (i2c1)", /* 12 */ 154 "int 13 (pcmcia)", /* 13 */ 155 "int 14 (gpio_a)", /* 14 */ 156 "int 15 (irq15)", /* 15 */ 157 "int 16 (bridge_tb)", /* 16 */ 158 "int 17 (gmac0)", /* 17 */ 159 "int 18 (gmac1)", /* 18 */ 160 "int 19 (gmac2)", /* 19 */ 161 "int 20 (gmac3)", /* 20 */ 162 "int 21 (irq21)", /* 21 */ 163 "int 22 (irq22)", /* 22 */ 164 "int 23 (irq23)", /* 23 */ 165 "int 24 (irq24)", /* 24 */ 166 "int 25 (bridge_err)", /* 25 */ 167 "int 26 (pcie_link0)", /* 26 */ 168 "int 27 (pcie_link1)", /* 27 */ 169 "int 28 (irq28)", /* 28 */ 170 "int 29 (irq29)", /* 29 */ 171 "int 30 (gpio_b)", /* 30 */ 172 "int 31 (usb)", /* 31 */ 173 }; 174 175 /* 176 * rmixl_irqnames_xls4xx: 177 * - use for XLS4xx, XLS6xx 178 */ 179 static const char *rmixl_irqnames_xls4xx[NIRQS] = { 180 "int 0 (watchdog)", /* 0 */ 181 "int 1 (timer0)", /* 1 */ 182 "int 2 (timer1)", /* 2 */ 183 "int 3 (timer2)", /* 3 */ 184 "int 4 (timer3)", /* 4 */ 185 "int 5 (timer4)", /* 5 */ 186 "int 6 (timer5)", /* 6 */ 187 "int 7 (timer6)", /* 7 */ 188 "int 8 (timer7)", /* 8 */ 189 "int 9 (uart0)", /* 9 */ 190 "int 10 (uart1)", /* 10 */ 191 "int 11 (i2c0)", /* 11 */ 192 "int 12 (i2c1)", /* 12 */ 193 "int 13 (pcmcia)", /* 13 */ 194 "int 14 (gpio_a)", /* 14 */ 195 "int 15 (irq15)", /* 15 */ 196 "int 16 (bridge_tb)", /* 16 */ 197 "int 17 (gmac0)", /* 17 */ 198 "int 18 (gmac1)", /* 18 */ 199 "int 19 (gmac2)", /* 19 */ 200 "int 20 (gmac3)", /* 20 */ 201 "int 21 (irq21)", /* 21 */ 202 "int 22 (irq22)", /* 22 */ 203 "int 23 (irq23)", /* 23 */ 204 "int 24 (irq24)", /* 24 */ 205 "int 25 (bridge_err)", /* 25 */ 206 "int 26 (pcie_link0)", /* 26 */ 207 "int 27 (pcie_link1)", /* 27 */ 208 "int 28 (pcie_link2)", /* 28 */ 209 "int 29 (pcie_link3)", /* 29 */ 210 "int 30 (gpio_b)", /* 30 */ 211 "int 31 (usb)", /* 31 */ 212 }; 213 214 /* 215 * rmixl_irqnames_xls4xx: 216 * - use for unknown cpu implementation 217 */ 218 static const char *rmixl_irqnames_generic[NIRQS] = { 219 "int 0", /* 0 */ 220 "int 1", /* 1 */ 221 "int 2", /* 2 */ 222 "int 3", /* 3 */ 223 "int 4", /* 4 */ 224 "int 5", /* 5 */ 225 "int 6", /* 6 */ 226 "int 7", /* 7 */ 227 "int 8", /* 8 */ 228 "int 9", /* 9 */ 229 "int 10", /* 10 */ 230 "int 11", /* 11 */ 231 "int 12", /* 12 */ 232 "int 13", /* 13 */ 233 "int 14", /* 14 */ 234 "int 15", /* 15 */ 235 "int 16", /* 16 */ 236 "int 17", /* 17 */ 237 "int 18", /* 18 */ 238 "int 19", /* 19 */ 239 "int 20", /* 20 */ 240 "int 21", /* 21 */ 241 "int 22", /* 22 */ 242 "int 23", /* 23 */ 243 "int 24", /* 24 */ 244 "int 25", /* 25 */ 245 "int 26", /* 26 */ 246 "int 27", /* 27 */ 247 "int 28", /* 28 */ 248 "int 29", /* 29 */ 249 "int 30", /* 30 */ 250 "int 31", /* 31 */ 251 }; 252 253 /* 254 * per-IRQ event stats 255 */ 256 struct rmixl_irqtab { 257 struct evcnt irq_count; 258 void *irq_ih; 259 }; 260 static struct rmixl_irqtab rmixl_irqtab[NIRQS]; 261 262 263 /* 264 * 'vectors' here correspond to IRT Entry vector numbers 265 * - IRT Entry vector# is bit# in EIRR 266 * - note that EIRR[7:0] == CAUSE[15:8] 267 * - we actually only use the first _IPL_N bits 268 * (less than 8) 269 * 270 * each IRT entry gets routed to a vector 271 * (if and when that interrupt is established) 272 * the vectors are shared on a per-IPL basis 273 * which simplifies dispatch 274 * 275 * XXX use of mips64 extended IRQs is TBD 276 */ 277 #define NINTRVECS _IPL_N 278 279 /* 280 * translate IPL to vector number 281 */ 282 static const int rmixl_iplvec[_IPL_N] = { 283 [IPL_NONE] = -1, /* XXX */ 284 [IPL_SOFTCLOCK] = 0, 285 [IPL_SOFTNET] = 1, 286 [IPL_VM] = 2, 287 [IPL_SCHED] = 3, 288 }; 289 290 /* 291 * list and ref count manage sharing of each vector 292 */ 293 struct rmixl_intrvec { 294 LIST_HEAD(, evbmips_intrhand) iv_list; 295 uint32_t iv_ack; 296 rmixl_intr_trigger_t iv_trigger; 297 rmixl_intr_polarity_t iv_polarity; 298 u_int iv_refcnt; 299 }; 300 static struct rmixl_intrvec rmixl_intrvec[NINTRVECS]; 301 302 #ifdef DIAGNOSTIC 303 static int evbmips_intr_init_done; 304 #endif 305 306 307 static void rmixl_intr_irt_init(int); 308 static void rmixl_intr_irt_disestablish(int); 309 static void rmixl_intr_irt_establish(int, int, rmixl_intr_trigger_t, 310 rmixl_intr_polarity_t, int); 311 312 313 static inline void 314 pic_irt_print(const char *s, const int n, u_int irq) 315 { 316 #ifdef IOINTR_DEBUG 317 uint32_t c0, c1; 318 319 c0 = RMIXL_PICREG_READ(RMIXL_PIC_IRTENTRYC0(irq)); 320 c1 = RMIXL_PICREG_READ(RMIXL_PIC_IRTENTRYC1(irq)); 321 printf("%s:%d: irq %d: c0 %#x, c1 %#x\n", s, n, irq, c0, c1); 322 #endif 323 } 324 325 void 326 evbmips_intr_init(void) 327 { 328 uint32_t r; 329 int i; 330 331 KASSERT(cpu_rmixls(mycpu)); 332 333 #ifdef DIAGNOSTIC 334 if (evbmips_intr_init_done != 0) 335 panic("%s: evbmips_intr_init_done %d", 336 __func__, evbmips_intr_init_done); 337 #endif 338 339 for (i=0; i < NIRQS; i++) { 340 evcnt_attach_dynamic(&rmixl_irqtab[i].irq_count, 341 EVCNT_TYPE_INTR, NULL, "rmixl", rmixl_intr_string(i)); 342 rmixl_irqtab[i].irq_ih = NULL; 343 } 344 345 for (i=0; i < NINTRVECS; i++) { 346 LIST_INIT(&rmixl_intrvec[i].iv_list); 347 rmixl_intrvec[i].iv_ack = 0; 348 rmixl_intrvec[i].iv_refcnt = 0; 349 } 350 351 /* 352 * disable watchdog NMI, timers 353 * 354 * XXX 355 * WATCHDOG_ENB is preserved because clearing it causes 356 * hang on the XLS616 (but not on the XLS408) 357 */ 358 r = RMIXL_PICREG_READ(RMIXL_PIC_CONTROL); 359 r &= RMIXL_PIC_CONTROL_RESV|RMIXL_PIC_CONTROL_WATCHDOG_ENB; 360 RMIXL_PICREG_WRITE(RMIXL_PIC_CONTROL, r); 361 362 /* 363 * initialize all IRT Entries 364 */ 365 for (i=0; i < NIRQS; i++) 366 rmixl_intr_irt_init(i); 367 368 /* 369 * establish IRT entry for mips3 clock interrupt 370 */ 371 rmixl_intr_irt_establish(7, IPL_CLOCK, RMIXL_INTR_LEVEL, 372 RMIXL_INTR_HIGH, rmixl_iplvec[IPL_CLOCK]); 373 374 #ifdef DIAGNOSTIC 375 evbmips_intr_init_done = 1; 376 #endif 377 } 378 379 const char * 380 rmixl_intr_string(int irq) 381 { 382 const char *name; 383 384 if (irq < 0 || irq >= NIRQS) 385 panic("%s: irq %d out of range, max %d", 386 __func__, irq, NIRQS - 1); 387 388 switch (MIPS_PRID_IMPL(cpu_id)) { 389 case MIPS_XLS104: 390 case MIPS_XLS108: 391 case MIPS_XLS204: 392 case MIPS_XLS208: 393 case MIPS_XLS404LITE: 394 case MIPS_XLS408LITE: 395 name = rmixl_irqnames_xls1xx[irq]; 396 break; 397 case MIPS_XLS404: 398 case MIPS_XLS408: 399 case MIPS_XLS416: 400 case MIPS_XLS608: 401 case MIPS_XLS616: 402 name = rmixl_irqnames_xls4xx[irq]; 403 break; 404 default: 405 name = rmixl_irqnames_generic[irq]; 406 break; 407 } 408 409 return name; 410 } 411 412 /* 413 * rmixl_intr_irt_init 414 * - invalidate IRT Entry for irq 415 * - unmask Thread#0 in low word (assume we only have 1 thread) 416 */ 417 static void 418 rmixl_intr_irt_init(int irq) 419 { 420 RMIXL_PICREG_WRITE(RMIXL_PIC_IRTENTRYC1(irq), 0); /* high word */ 421 RMIXL_PICREG_WRITE(RMIXL_PIC_IRTENTRYC0(irq), 1); /* low word */ 422 } 423 424 /* 425 * rmixl_intr_irt_disestablish 426 * - invalidate IRT Entry for irq 427 * - writes to IRTENTRYC1 only; leave IRTENTRYC0 as-is 428 */ 429 static void 430 rmixl_intr_irt_disestablish(int irq) 431 { 432 DPRINTF(("%s: irq %d, irtc1 %#x\n", __func__, irq, 0)); 433 RMIXL_PICREG_WRITE(RMIXL_PIC_IRTENTRYC1(irq), 0); /* high word */ 434 } 435 436 /* 437 * rmixl_intr_irt_establish 438 * - construct and IRT Entry for irq and write to PIC 439 * - writes to IRTENTRYC1 only; assumes IRTENTRYC0 has been initialized 440 */ 441 static void 442 rmixl_intr_irt_establish(int irq, int ipl, rmixl_intr_trigger_t trigger, 443 rmixl_intr_polarity_t polarity, int vec) 444 { 445 uint32_t irtc1; 446 447 irtc1 = RMIXL_PIC_IRTENTRYC1_VALID; 448 irtc1 |= RMIXL_PIC_IRTENTRYC1_GL; /* local */ 449 450 if (trigger == RMIXL_INTR_LEVEL) 451 irtc1 |= RMIXL_PIC_IRTENTRYC1_TRG; 452 453 if ((polarity == RMIXL_INTR_FALLING) || (polarity == RMIXL_INTR_LOW)) 454 irtc1 |= RMIXL_PIC_IRTENTRYC1_P; 455 456 irtc1 |= vec; 457 458 /* 459 * write IRT Entry to PIC (high word only) 460 */ 461 DPRINTF(("%s: irq %d, irtc1 %#x\n", __func__, irq, irtc1)); 462 RMIXL_PICREG_WRITE(RMIXL_PIC_IRTENTRYC1(irq), irtc1); 463 } 464 465 void * 466 rmixl_intr_establish(int irq, int ipl, rmixl_intr_trigger_t trigger, 467 rmixl_intr_polarity_t polarity, int (*func)(void *), void *arg) 468 { 469 struct evbmips_intrhand *ih; 470 struct rmixl_intrvec *ivp; 471 int vec; 472 int s; 473 474 #ifdef DIAGNOSTIC 475 if (evbmips_intr_init_done == 0) 476 panic("%s: called before evbmips_intr_init", __func__); 477 #endif 478 479 /* 480 * check args and assemble an IRT Entry 481 */ 482 if (irq < 0 || irq >= NIRQS) 483 panic("%s: irq %d out of range, max %d", 484 __func__, irq, NIRQS - 1); 485 if (ipl <= 0 || ipl >= _IPL_N) 486 panic("%s: ipl %d out of range, min %d, max %d", 487 __func__, ipl, 1, _IPL_N - 1); 488 if (rmixl_irqtab[irq].irq_ih != NULL) 489 panic("%s: irq %d busy", __func__, irq); 490 491 switch (trigger) { 492 case RMIXL_INTR_EDGE: 493 case RMIXL_INTR_LEVEL: 494 break; 495 default: 496 panic("%s: bad trigger %d\n", __func__, trigger); 497 } 498 499 switch (polarity) { 500 case RMIXL_INTR_RISING: 501 case RMIXL_INTR_HIGH: 502 case RMIXL_INTR_FALLING: 503 case RMIXL_INTR_LOW: 504 break; 505 default: 506 panic("%s: bad polarity %d\n", __func__, polarity); 507 } 508 509 /* 510 * ipl determines which vector to use 511 */ 512 vec = rmixl_iplvec[ipl]; 513 DPRINTF(("%s: irq %d, ipl %d, vec %d\n", __func__, irq, ipl, vec)); 514 KASSERT((vec & ~RMIXL_PIC_IRTENTRYC1_INTVEC) == 0); 515 516 s = splhigh(); 517 518 ivp = &rmixl_intrvec[vec]; 519 if (ivp->iv_refcnt == 0) { 520 ivp->iv_trigger = trigger; 521 ivp->iv_polarity = polarity; 522 } else { 523 if (ivp->iv_trigger != trigger) { 524 #ifdef DIAGNOSTIC 525 printf("%s: vec %d, irqs {", __func__, vec); 526 LIST_FOREACH(ih, &ivp->iv_list, ih_q) { 527 printf(" %d", ih->ih_irq); 528 } 529 printf(" } trigger type %d; irq %d wants type %d\n", 530 ivp->iv_trigger, irq, trigger); 531 #endif 532 panic("%s: trigger mismatch at vec %d\n", 533 __func__, vec); 534 } 535 if (ivp->iv_polarity != polarity) { 536 #ifdef DIAGNOSTIC 537 printf("%s: vec %d, irqs {", __func__, vec); 538 LIST_FOREACH(ih, &ivp->iv_list, ih_q) { 539 printf(" %d", ih->ih_irq); 540 } 541 printf(" } polarity type %d; irq %d wants type %d\n", 542 ivp->iv_polarity, irq, polarity); 543 #endif 544 panic("%s: polarity mismatch at vec %d\n", 545 __func__, vec); 546 } 547 } 548 ivp->iv_ack |= (1 << irq); 549 550 /* 551 * allocate and initialize an interrupt handle 552 */ 553 ih = malloc(sizeof(*ih), M_DEVBUF, M_NOWAIT); 554 if (ih == NULL) 555 return NULL; 556 557 ih->ih_func = func; 558 ih->ih_arg = arg; 559 ih->ih_irq = irq; 560 ih->ih_ipl = ipl; 561 562 /* 563 * mark this irq as established, busy 564 */ 565 rmixl_irqtab[irq].irq_ih = ih; 566 567 /* 568 * link this ih into the tables and bump reference count 569 */ 570 LIST_INSERT_HEAD(&ivp->iv_list, ih, ih_q); 571 ivp->iv_refcnt++; 572 573 /* 574 * establish IRT Entry 575 */ 576 rmixl_intr_irt_establish(irq, ipl, trigger, polarity, vec); 577 578 splx(s); 579 580 return ih; 581 } 582 583 void 584 rmixl_intr_disestablish(void *cookie) 585 { 586 struct evbmips_intrhand *ih = cookie; 587 struct rmixl_intrvec *ivp; 588 int irq; 589 int vec; 590 int s; 591 592 irq = ih->ih_irq; 593 vec = rmixl_iplvec[ih->ih_ipl]; 594 ivp = &rmixl_intrvec[vec]; 595 596 s = splhigh(); 597 598 /* 599 * disable the IRT Entry (high word only) 600 */ 601 rmixl_intr_irt_disestablish(irq); 602 603 /* 604 * remove from the table and adjust the reference count 605 */ 606 LIST_REMOVE(ih, ih_q); 607 ivp->iv_refcnt--; 608 ivp->iv_ack &= ~(1 << irq); 609 610 /* 611 * this irq now disestablished, not busy 612 */ 613 rmixl_irqtab[irq].irq_ih = NULL; 614 615 splx(s); 616 617 free(ih, M_DEVBUF); 618 } 619 620 static inline void 621 pci_int_status(const char *s, const int n) 622 { 623 #ifdef IOINTR_DEBUG 624 uint32_t r; 625 r = RMIXL_IOREG_READ(RMIXL_IO_DEV_PCIE_LE + 0xa0); 626 printf("%s:%d: PCIE_LINK0_INT_STATUS0 %#x\n", s, n, r); 627 #endif 628 } 629 630 void 631 evbmips_iointr(uint32_t status, uint32_t cause, uint32_t pc, uint32_t ipending) 632 { 633 struct evbmips_intrhand *ih; 634 struct rmixl_intrvec *ivp; 635 int vec; 636 uint64_t eirr; 637 #ifdef IOINTR_DEBUG 638 uint64_t eimr; 639 640 printf("%s: status %#x, cause %#x, pc %#x, ipending %#x\n", 641 __func__, status, cause, pc, ipending); 642 643 asm volatile("dmfc0 %0, $9, 6;" : "=r"(eirr)); 644 asm volatile("dmfc0 %0, $9, 7;" : "=r"(eimr)); 645 printf("%s:%d: eirr %#lx, eimr %#lx\n", __func__, __LINE__, eirr, eimr); 646 pci_int_status(__func__, __LINE__); 647 #endif 648 649 for (vec = NINTRVECS - 1; vec >= 2; vec--) { 650 if ((ipending & (MIPS_SOFT_INT_MASK_0 << vec)) == 0) 651 continue; 652 653 ivp = &rmixl_intrvec[vec]; 654 655 eirr = 1ULL << vec; 656 asm volatile("dmtc0 %0, $9, 6;" :: "r"(eirr)); 657 658 #ifdef IOINTR_DEBUG 659 printf("%s: interrupt at vec %d\n", 660 __func__, vec); 661 if (LIST_EMPTY(&ivp->iv_list)) 662 printf("%s: unexpected interrupt at vec %d\n", 663 __func__, vec); 664 #endif 665 LIST_FOREACH(ih, &ivp->iv_list, ih_q) { 666 pic_irt_print(__func__, __LINE__, ih->ih_irq); 667 RMIXL_PICREG_WRITE(RMIXL_PIC_INTRACK, 668 (1 << ih->ih_irq)); 669 if ((*ih->ih_func)(ih->ih_arg) != 0) { 670 rmixl_irqtab[ih->ih_irq].irq_count.ev_count++; 671 } 672 } 673 674 pci_int_status(__func__, __LINE__); 675 676 cause &= ~(MIPS_SOFT_INT_MASK_0 << vec); 677 } 678 679 680 /* Re-enable anything that we have processed. */ 681 _splset(MIPS_SR_INT_IE | ((status & ~cause) & MIPS_HARD_INT_MASK)); 682 } 683 684 #ifdef DEBUG 685 int rmixl_intrvec_print(void); 686 int 687 rmixl_intrvec_print(void) 688 { 689 struct evbmips_intrhand *ih; 690 struct rmixl_intrvec *ivp; 691 int vec; 692 693 ivp = &rmixl_intrvec[0]; 694 for (vec=0; vec < NINTRVECS ; vec++) { 695 printf("vec %d, irqs {", vec); 696 LIST_FOREACH(ih, &ivp->iv_list, ih_q) 697 printf(" %d", ih->ih_irq); 698 printf(" } trigger type %d\n", ivp->iv_trigger); 699 ivp++; 700 } 701 return 0; 702 } 703 #endif 704