1 /* $NetBSD: tx39icu.c,v 1.27 2010/12/20 00:25:34 matt Exp $ */ 2 3 /*- 4 * Copyright (c) 1999-2001 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by UCHIYAMA Yasushi. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 __KERNEL_RCSID(0, "$NetBSD: tx39icu.c,v 1.27 2010/12/20 00:25:34 matt Exp $"); 34 35 #include "opt_vr41xx.h" 36 #include "opt_tx39xx.h" 37 38 #include "opt_use_poll.h" 39 #include "opt_tx39icu_debug.h" 40 #include "opt_tx39_watchdogtimer.h" 41 42 #include <sys/param.h> 43 #include <sys/systm.h> 44 #include <sys/device.h> 45 #include <sys/malloc.h> 46 #include <sys/queue.h> 47 #include <sys/cpu.h> 48 49 #include <uvm/uvm_extern.h> 50 51 #include <mips/cpuregs.h> 52 #include <machine/bus.h> 53 54 #include <hpcmips/tx/tx39var.h> 55 #include <hpcmips/tx/tx39icureg.h> 56 #include <hpcmips/tx/tx39clockvar.h> 57 58 #include <machine/cpu.h> 59 #include <dev/dec/clockvar.h> 60 61 #undef TX39ICU_DEBUG_PRINT_PENDING_INTERRUPT /* For explorer. good luck! */ 62 63 #if defined(VR41XX) && defined(TX39XX) 64 #define TX_INTR tx_intr 65 #else 66 #define TX_INTR cpu_intr /* locore_mips3 directly call this */ 67 #endif 68 void TX_INTR(u_int32_t, u_int32_t, u_int32_t, u_int32_t); 69 70 #ifdef TX39ICU_DEBUG 71 #define DPRINTF_ENABLE 72 #define DPRINTF_DEBUG tx39icu_debug 73 #endif 74 #include <machine/debug.h> 75 76 u_int32_t tx39intrvec; 77 78 /* 79 * This is a mask of bits to clear in the SR when we go to a 80 * given interrupt priority level. 81 */ 82 const u_int32_t __ipl_sr_bits_tx[_IPL_N] = { 83 0, /* IPL_NONE */ 84 85 MIPS_SOFT_INT_MASK_0, /* IPL_SOFTCLOCK */ 86 87 MIPS_SOFT_INT_MASK_0| 88 MIPS_SOFT_INT_MASK_1, /* IPL_SOFTNET */ 89 90 MIPS_SOFT_INT_MASK_0| 91 MIPS_SOFT_INT_MASK_1| 92 MIPS_INT_MASK_2| 93 MIPS_INT_MASK_4, /* IPL_VM */ 94 95 MIPS_SOFT_INT_MASK_0| 96 MIPS_SOFT_INT_MASK_1| 97 MIPS_INT_MASK_2| 98 MIPS_INT_MASK_4, /* IPL_SCHED */ 99 }; 100 101 /* IRQHIGH lines list */ 102 static const struct irqhigh_list { 103 int qh_pri; /* IRQHIGH priority */ 104 int qh_set; /* Register set */ 105 int qh_bit; /* bit offset in the register set */ 106 } irqhigh_list[] = { 107 {15, 5, 25}, /* POSPWROKINT */ 108 {15, 5, 24}, /* NEGPWROKINT */ 109 {14, 5, 30}, /* ALARMINT*/ 110 {13, 5, 29}, /* PERINT */ 111 #ifdef TX391X 112 {12, 2, 3}, /* MBUSPOSINT */ 113 {12, 2, 2}, /* MBUSNEGINT */ 114 {11, 2, 31}, /* UARTARXINT */ 115 {10, 2, 21}, /* UARTBRXINT */ 116 {9, 3, 19}, /* MFIOPOSINT19 */ 117 {9, 3, 18}, /* MFIOPOSINT18 */ 118 {9, 3, 17}, /* MFIOPOSINT17 */ 119 {9, 3, 16}, /* MFIOPOSINT16 */ 120 {8, 3, 1}, /* MFIOPOSINT1 */ 121 {8, 3, 0}, /* MFIOPOSINT0 */ 122 {8, 5, 13}, /* IOPOSINT6 */ 123 {8, 5, 12}, /* IOPOSINT5 */ 124 {7, 4, 19}, /* MFIONEGINT19 */ 125 {7, 4, 18}, /* MFIONEGINT18 */ 126 {7, 4, 17}, /* MFIONEGINT17 */ 127 {7, 4, 16}, /* MFIONEGINT16 */ 128 {6, 4, 1}, /* MFIONEGINT1 */ 129 {6, 4, 0}, /* MFIONEGINT0 */ 130 {6, 5, 6}, /* IONEGINT6 */ 131 {6, 5, 5}, /* IONEGINT5 */ 132 {5, 2, 5}, /* MBUSDMAFULLINT */ 133 #endif /* TX391X */ 134 #ifdef TX392X 135 {12, 2, 31}, /* UARTARXINT */ 136 {12, 2, 21}, /* UARTBRXINT */ 137 {11, 3, 19}, /* MFIOPOSINT19 */ 138 {11, 3, 18}, /* MFIOPOSINT18 */ 139 {11, 3, 17}, /* MFIOPOSINT17 */ 140 {11, 3, 16}, /* MFIOPOSINT16 */ 141 {10, 3, 1}, /* MFIOPOSINT1 */ 142 {10, 3, 0}, /* MFIOPOSINT0 */ 143 {10, 5, 13}, /* IOPOSINT6 */ 144 {10, 5, 12}, /* IOPOSINT5 */ 145 {9, 4, 19}, /* MFIONEGINT19 */ 146 {9, 4, 18}, /* MFIONEGINT18 */ 147 {9, 4, 17}, /* MFIONEGINT17 */ 148 {9, 4, 16}, /* MFIONEGINT16 */ 149 {8, 4, 1}, /* MFIONEGINT1 */ 150 {8, 4, 0}, /* MFIONEGINT0 */ 151 {8, 5, 6}, /* IONEGINT6 */ 152 {8, 5, 5}, /* IONEGINT5 */ 153 {5, 7, 19}, /* IRRXCINT */ 154 {5, 7, 17}, /* IRRXEINT */ 155 #endif /* TX392X */ 156 {4, 1, 18}, /* SNDDMACNTINT */ 157 {3, 1, 17}, /* TELDMACNTINT */ 158 {2, 1, 27}, /* CHIDMACNTINT */ 159 {1, 5, 7}, /* IOPOSINT0 */ 160 {1, 5, 0} /* IONEGINT0 */ 161 }; 162 163 struct txintr_high_entry { 164 int he_set; 165 txreg_t he_mask; 166 int (*he_fun)(void *); 167 void *he_arg; 168 TAILQ_ENTRY(txintr_high_entry) he_link; 169 }; 170 171 #ifdef USE_POLL 172 struct txpoll_entry{ 173 int p_cnt; /* dispatch interval */ 174 int p_desc; 175 int (*p_fun)(void *); 176 void *p_arg; 177 TAILQ_ENTRY(txpoll_entry) p_link; 178 }; 179 int tx39_poll_intr(void *); 180 #endif /* USE_POLL */ 181 182 struct tx39icu_softc { 183 struct device sc_dev; 184 tx_chipset_tag_t sc_tc; 185 /* IRQLOW */ 186 txreg_t sc_le_mask[TX39_INTRSET_MAX + 1]; 187 int (*sc_le_fun[TX39_INTRSET_MAX + 1][32])(void *); 188 void *sc_le_arg[TX39_INTRSET_MAX + 1][32]; 189 /* IRQHIGH */ 190 TAILQ_HEAD(, txintr_high_entry) sc_he_head[TX39_IRQHIGH_MAX]; 191 /* Register */ 192 txreg_t sc_regs[TX39_INTRSET_MAX + 1]; 193 #ifdef USE_POLL 194 unsigned sc_pollcnt; 195 int sc_polling; 196 void *sc_poll_ih; 197 TAILQ_HEAD(, txpoll_entry) sc_p_head; 198 #endif /* USE_POLL */ 199 }; 200 201 int tx39icu_match(struct device *, struct cfdata *, void *); 202 void tx39icu_attach(struct device *, struct device *, void *); 203 int tx39icu_intr(u_int32_t, u_int32_t, u_int32_t, u_int32_t); 204 205 void tx39_intr_dump(struct tx39icu_softc *); 206 void tx39_intr_decode(int, int *, int *); 207 void tx39_irqhigh_disestablish(tx_chipset_tag_t, int, int, int); 208 void tx39_irqhigh_establish(tx_chipset_tag_t, int, int, int, 209 int (*)(void *), void *); 210 void tx39_irqhigh_intr(u_int32_t, u_int32_t, u_int32_t, u_int32_t); 211 int tx39_irqhigh(int, int); 212 213 CFATTACH_DECL(tx39icu, sizeof(struct tx39icu_softc), 214 tx39icu_match, tx39icu_attach, NULL, NULL); 215 216 int 217 tx39icu_match(struct device *parent, struct cfdata *cf, void *aux) 218 { 219 220 return (ATTACH_FIRST); 221 } 222 223 void 224 tx39icu_attach(struct device *parent, struct device *self, void *aux) 225 { 226 struct txsim_attach_args *ta = aux; 227 struct tx39icu_softc *sc = (void *)self; 228 tx_chipset_tag_t tc = ta->ta_tc; 229 txreg_t reg, *regs; 230 int i; 231 232 printf("\n"); 233 sc->sc_tc = ta->ta_tc; 234 235 regs = sc->sc_regs; 236 regs[0] = tx_conf_read(tc, TX39_INTRSTATUS6_REG); 237 regs[1] = tx_conf_read(tc, TX39_INTRSTATUS1_REG); 238 regs[2] = tx_conf_read(tc, TX39_INTRSTATUS2_REG); 239 regs[3] = tx_conf_read(tc, TX39_INTRSTATUS3_REG); 240 regs[4] = tx_conf_read(tc, TX39_INTRSTATUS4_REG); 241 regs[5] = tx_conf_read(tc, TX39_INTRSTATUS5_REG); 242 #ifdef TX392X 243 regs[7] = tx_conf_read(tc, TX39_INTRSTATUS7_REG); 244 regs[8] = tx_conf_read(tc, TX39_INTRSTATUS8_REG); 245 #endif 246 #ifdef TX39ICU_DEBUG 247 printf("\t[Windows CE setting]\n"); 248 tx39_intr_dump(sc); 249 #endif /* TX39ICU_DEBUG */ 250 251 #ifdef WINCE_DEFAULT_SETTING 252 #warning WINCE_DEFAULT_SETTING 253 #else /* WINCE_DEFAULT_SETTING */ 254 /* Disable IRQLOW */ 255 tx_conf_write(tc, TX39_INTRENABLE1_REG, 0); 256 tx_conf_write(tc, TX39_INTRENABLE2_REG, 0); 257 tx_conf_write(tc, TX39_INTRENABLE3_REG, 0); 258 tx_conf_write(tc, TX39_INTRENABLE4_REG, 0); 259 tx_conf_write(tc, TX39_INTRENABLE5_REG, 0); 260 #ifdef TX392X 261 tx_conf_write(tc, TX39_INTRENABLE7_REG, 0); 262 tx_conf_write(tc, TX39_INTRENABLE8_REG, 0); 263 #endif /* TX392X */ 264 265 /* Disable IRQHIGH */ 266 reg = tx_conf_read(tc, TX39_INTRENABLE6_REG); 267 reg &= ~TX39_INTRENABLE6_PRIORITYMASK_MASK; 268 tx_conf_write(tc, TX39_INTRENABLE6_REG, reg); 269 #endif /* WINCE_DEFAULT_SETTING */ 270 271 /* Clear all pending interrupts */ 272 tx_conf_write(tc, TX39_INTRCLEAR1_REG, 273 tx_conf_read(tc, TX39_INTRSTATUS1_REG)); 274 tx_conf_write(tc, TX39_INTRCLEAR2_REG, 275 tx_conf_read(tc, TX39_INTRSTATUS2_REG)); 276 tx_conf_write(tc, TX39_INTRCLEAR3_REG, 277 tx_conf_read(tc, TX39_INTRSTATUS3_REG)); 278 tx_conf_write(tc, TX39_INTRCLEAR4_REG, 279 tx_conf_read(tc, TX39_INTRSTATUS4_REG)); 280 tx_conf_write(tc, TX39_INTRCLEAR5_REG, 281 tx_conf_read(tc, TX39_INTRSTATUS5_REG)); 282 #ifdef TX392X 283 tx_conf_write(tc, TX39_INTRCLEAR7_REG, 284 tx_conf_read(tc, TX39_INTRSTATUS7_REG)); 285 tx_conf_write(tc, TX39_INTRCLEAR8_REG, 286 tx_conf_read(tc, TX39_INTRSTATUS8_REG)); 287 #endif /* TX392X */ 288 289 /* Enable global interrupts */ 290 reg = tx_conf_read(tc, TX39_INTRENABLE6_REG); 291 reg |= TX39_INTRENABLE6_GLOBALEN; 292 tx_conf_write(tc, TX39_INTRENABLE6_REG, reg); 293 294 /* Initialize IRQHIGH interrupt handler holder*/ 295 for (i = 0; i < TX39_IRQHIGH_MAX; i++) { 296 TAILQ_INIT(&sc->sc_he_head[i]); 297 } 298 #ifdef USE_POLL 299 /* Initialize polling handler holder */ 300 TAILQ_INIT(&sc->sc_p_head); 301 #endif /* USE_POLL */ 302 303 /* Register interrupt module myself */ 304 tx_conf_register_intr(tc, self); 305 } 306 307 void 308 TX_INTR(u_int32_t status, u_int32_t cause, u_int32_t pc, u_int32_t ipending) 309 { 310 struct tx39icu_softc *sc; 311 tx_chipset_tag_t tc; 312 struct cpu_info *ci; 313 txreg_t reg, pend, *regs; 314 int i, j; 315 316 ci = curcpu(); 317 ci->ci_idepth++; 318 ci->ci_data.cpu_nintr++; 319 320 #ifdef __HAVE_FAST_SOFTINTS 321 if ((ipending & MIPS_HARD_INT_MASK) == 0) 322 goto softintr; 323 #endif 324 325 tc = tx_conf_get_tag(); 326 sc = tc->tc_intrt; 327 /* 328 * Read regsiter ASAP 329 */ 330 regs = sc->sc_regs; 331 regs[0] = tx_conf_read(tc, TX39_INTRSTATUS6_REG); 332 regs[1] = tx_conf_read(tc, TX39_INTRSTATUS1_REG); 333 regs[2] = tx_conf_read(tc, TX39_INTRSTATUS2_REG); 334 regs[3] = tx_conf_read(tc, TX39_INTRSTATUS3_REG); 335 regs[4] = tx_conf_read(tc, TX39_INTRSTATUS4_REG); 336 regs[5] = tx_conf_read(tc, TX39_INTRSTATUS5_REG); 337 #ifdef TX392X 338 regs[7] = tx_conf_read(tc, TX39_INTRSTATUS7_REG); 339 regs[8] = tx_conf_read(tc, TX39_INTRSTATUS8_REG); 340 #endif 341 342 #ifdef TX39ICU_DEBUG 343 if (!(ipending & MIPS_INT_MASK_4) && !(ipending & MIPS_INT_MASK_2)) { 344 dbg_bit_print(ipending); 345 panic("bogus HwInt"); 346 } 347 if (tx39icu_debug > 1) { 348 tx39_intr_dump(sc); 349 } 350 #endif /* TX39ICU_DEBUG */ 351 352 /* IRQHIGH */ 353 if (ipending & MIPS_INT_MASK_4) { 354 tx39_irqhigh_intr(ipending, pc, status, cause); 355 356 #ifdef __HAVE_FAST_SOFTINTS 357 goto softintr; 358 #endif 359 } 360 361 /* IRQLOW */ 362 if (ipending & MIPS_INT_MASK_2) { 363 for (i = 1; i <= TX39_INTRSET_MAX; i++) { 364 int ofs; 365 #ifdef TX392X 366 if (i == 6) 367 continue; 368 #endif /* TX392X */ 369 ofs = TX39_INTRSTATUS_REG(i); 370 pend = sc->sc_regs[i]; 371 reg = sc->sc_le_mask[i] & pend; 372 /* Clear interrupts */ 373 tx_conf_write(tc, ofs, reg); 374 /* Dispatch handler */ 375 for (j = 0 ; j < 32; j++) { 376 if ((reg & (1 << j)) && 377 sc->sc_le_fun[i][j]) { 378 #ifdef TX39ICU_DEBUG 379 if (tx39icu_debug > 1) { 380 tx39intrvec = (i << 16) | j; 381 DPRINTF("IRQLOW %d:%d\n", i, j); 382 } 383 #endif /* TX39ICU_DEBUG */ 384 (*sc->sc_le_fun[i][j]) 385 (sc->sc_le_arg[i][j]); 386 387 } 388 } 389 #ifdef TX39ICU_DEBUG_PRINT_PENDING_INTERRUPT 390 pend &= ~reg; 391 if (pend) { 392 printf("%d pending:", i); 393 dbg_bit_print(pend); 394 } 395 #endif 396 397 } 398 } 399 #ifdef TX39_WATCHDOGTIMER 400 { 401 extern int tx39biu_intr(void *); 402 /* Bus error (If watch dog timer is enabled)*/ 403 if (ipending & MIPS_INT_MASK_1) { 404 tx39biu_intr(0); /* Clear bus error */ 405 } 406 } 407 #endif 408 #if 0 409 /* reset priority mask */ 410 reg = tx_conf_read(tc, TX39_INTRENABLE6_REG); 411 reg = TX39_INTRENABLE6_PRIORITYMASK_SET(reg, 0xffff); 412 tx_conf_write(tc, TX39_INTRENABLE6_REG, reg); 413 #endif 414 415 #ifdef __HAVE_FAST_SOFTINTS 416 softintr: 417 #endif 418 ci->ci_idepth--; 419 #ifdef __HAVE_FAST_SOFTINTS 420 _splset((status & ~cause & MIPS_HARD_INT_MASK) | MIPS_SR_INT_IE); 421 softintr(ipending); 422 #endif 423 } 424 425 int 426 tx39_irqhigh(int set, int bit) 427 { 428 int i, n; 429 430 n = sizeof irqhigh_list / sizeof (struct irqhigh_list); 431 for (i = 0; i < n; i++) { 432 if (irqhigh_list[i].qh_set == set && 433 irqhigh_list[i].qh_bit == bit) 434 return (irqhigh_list[i].qh_pri); 435 } 436 437 return (0); 438 } 439 440 void 441 tx39_irqhigh_intr(u_int32_t ipending, u_int32_t pc, u_int32_t status, 442 u_int32_t cause) 443 { 444 struct txintr_high_entry *he; 445 struct tx39icu_softc *sc; 446 struct clockframe cf; 447 tx_chipset_tag_t tc; 448 int i, pri, ofs, set; 449 txreg_t he_mask; 450 451 tc = tx_conf_get_tag(); 452 sc = tc->tc_intrt; 453 pri = TX39_INTRSTATUS6_INTVECT(sc->sc_regs[0]); 454 455 if (pri == TX39_INTRPRI13_TIMER_PERIODIC) { 456 tx_conf_write(tc, TX39_INTRCLEAR5_REG, 457 TX39_INTRSTATUS5_PERINT); 458 cf.pc = pc; 459 cf.sr = status; 460 hardclock(&cf); 461 462 return; 463 } 464 465 /* Handle all pending IRQHIGH interrupts */ 466 for (i = pri; i > 0; i--) { 467 TAILQ_FOREACH(he, &sc->sc_he_head[i], he_link) { 468 set = he->he_set; 469 he_mask = he->he_mask; 470 if (he_mask & (sc->sc_regs[set])) { 471 ofs = TX39_INTRSTATUS_REG(set); 472 /* Clear interrupt */ 473 tx_conf_write(tc, ofs, he_mask); 474 #ifdef TX39ICU_DEBUG 475 if (tx39icu_debug > 1) { 476 tx39intrvec = (set << 16) | 477 (ffs(he_mask) - 1); 478 DPRINTF("IRQHIGH: %d:%d\n", 479 set, ffs(he_mask) - 1); 480 } 481 #endif /* TX39ICU_DEBUG */ 482 /* Dispatch handler */ 483 (*he->he_fun)(he->he_arg); 484 } 485 } 486 } 487 } 488 489 void 490 tx39_intr_decode(int intr, int *set, int *bit) 491 { 492 if (!intr || intr >= (TX39_INTRSET_MAX + 1) * 32 493 #ifdef TX392X 494 || intr == 6 495 #endif /* TX392X */ 496 ) { 497 panic("tx39icu_decode: bogus intrrupt line. %d", intr); 498 } 499 *set = intr / 32; 500 *bit = intr % 32; 501 } 502 503 void 504 tx39_irqhigh_establish(tx_chipset_tag_t tc, int set, int bit, int pri, 505 int (*ih_fun)(void *), void *ih_arg) 506 { 507 struct tx39icu_softc *sc; 508 struct txintr_high_entry *he; 509 txreg_t reg; 510 511 sc = tc->tc_intrt; 512 /* 513 * Add new entry to `pri' priority 514 */ 515 if (!(he = malloc(sizeof(struct txintr_high_entry), 516 M_DEVBUF, M_NOWAIT))) { 517 panic ("tx39_irqhigh_establish: no memory."); 518 } 519 memset(he, 0, sizeof(struct txintr_high_entry)); 520 he->he_set = set; 521 he->he_mask= (1 << bit); 522 he->he_fun = ih_fun; 523 he->he_arg = ih_arg; 524 TAILQ_INSERT_TAIL(&sc->sc_he_head[pri], he, he_link); 525 /* 526 * Enable interrupt on this priority. 527 */ 528 reg = tx_conf_read(tc, TX39_INTRENABLE6_REG); 529 reg = TX39_INTRENABLE6_PRIORITYMASK_SET(reg, (1 << pri)); 530 tx_conf_write(tc, TX39_INTRENABLE6_REG, reg); 531 } 532 533 void 534 tx39_irqhigh_disestablish(tx_chipset_tag_t tc, int set, int bit, int pri) 535 { 536 struct tx39icu_softc *sc; 537 struct txintr_high_entry *he; 538 txreg_t reg; 539 540 sc = tc->tc_intrt; 541 TAILQ_FOREACH(he, &sc->sc_he_head[pri], he_link) { 542 if (he->he_set == set && he->he_mask == (1 << bit)) { 543 TAILQ_REMOVE(&sc->sc_he_head[pri], he, he_link); 544 free(he, M_DEVBUF); 545 break; 546 } 547 } 548 549 if (TAILQ_EMPTY(&sc->sc_he_head[pri])) { 550 reg = tx_conf_read(tc, TX39_INTRENABLE6_REG); 551 reg &= ~(1 << pri); 552 tx_conf_write(tc, TX39_INTRENABLE6_REG, reg); 553 } 554 } 555 556 557 void * 558 tx_intr_establish(tx_chipset_tag_t tc, int line, int mode, int level, 559 int (*ih_fun)(void *), void *ih_arg) 560 { 561 struct tx39icu_softc *sc; 562 txreg_t reg; 563 int bit, set, highpri, ofs; 564 565 sc = tc->tc_intrt; 566 567 tx39_intr_decode(line, &set, &bit); 568 569 sc->sc_le_fun[set][bit] = ih_fun; 570 sc->sc_le_arg[set][bit] = ih_arg; 571 DPRINTF("tx_intr_establish: %d:%d", set, bit); 572 573 if ((highpri = tx39_irqhigh(set, bit))) { 574 tx39_irqhigh_establish(tc, set, bit, highpri, 575 ih_fun, ih_arg); 576 DPRINTF("(high)\n"); 577 } else { 578 /* Set mask for acknowledge. */ 579 sc->sc_le_mask[set] |= (1 << bit); 580 /* Enable interrupt */ 581 ofs = TX39_INTRENABLE_REG(set); 582 reg = tx_conf_read(tc, ofs); 583 reg |= (1 << bit); 584 tx_conf_write(tc, ofs, reg); 585 DPRINTF("(low)\n"); 586 } 587 588 return ((void *)line); 589 } 590 591 void 592 tx_intr_disestablish(tx_chipset_tag_t tc, void *arg) 593 { 594 struct tx39icu_softc *sc; 595 int set, bit, highpri, ofs; 596 txreg_t reg; 597 598 sc = tc->tc_intrt; 599 600 tx39_intr_decode((int)arg, &set, &bit); 601 DPRINTF("tx_intr_disestablish: %d:%d", set, bit); 602 603 if ((highpri = tx39_irqhigh(set, bit))) { 604 tx39_irqhigh_disestablish(tc, set, bit, highpri); 605 DPRINTF("(high)\n"); 606 } else { 607 sc->sc_le_fun[set][bit] = 0; 608 sc->sc_le_arg[set][bit] = 0; 609 sc->sc_le_mask[set] &= ~(1 << bit); 610 ofs = TX39_INTRENABLE_REG(set); 611 reg = tx_conf_read(tc, ofs); 612 reg &= ~(1 << bit); 613 tx_conf_write(tc, ofs, reg); 614 DPRINTF("(low)\n"); 615 } 616 } 617 618 u_int32_t 619 tx_intr_status(tx_chipset_tag_t tc, int r) 620 { 621 struct tx39icu_softc *sc = tc->tc_intrt; 622 623 if (r < 0 || r >= TX39_INTRSET_MAX + 1) 624 panic("tx_intr_status: invalid index %d", r); 625 626 return (u_int32_t)(sc->sc_regs[r]); 627 } 628 629 #ifdef USE_POLL 630 void * 631 tx39_poll_establish(tx_chipset_tag_t tc, int interval, int level, 632 int (*ih_fun)(void *), void *ih_arg) 633 { 634 struct tx39icu_softc *sc; 635 struct txpoll_entry *p; 636 int s; 637 void *ret; 638 639 s = splhigh(); 640 sc = tc->tc_intrt; 641 642 if (!(p = malloc(sizeof(struct txpoll_entry), 643 M_DEVBUF, M_NOWAIT))) { 644 panic ("tx39_poll_establish: no memory."); 645 } 646 memset(p, 0, sizeof(struct txpoll_entry)); 647 648 p->p_fun = ih_fun; 649 p->p_arg = ih_arg; 650 p->p_cnt = interval; 651 652 if (!sc->sc_polling) { 653 tx39clock_alarm_set(tc, 33); /* 33 msec */ 654 655 if (!(sc->sc_poll_ih = 656 tx_intr_establish( 657 tc, MAKEINTR(5, TX39_INTRSTATUS5_ALARMINT), 658 IST_EDGE, level, tx39_poll_intr, sc))) { 659 printf("tx39_poll_establish: can't hook\n"); 660 661 splx(s); 662 return (0); 663 } 664 } 665 666 sc->sc_polling++; 667 p->p_desc = sc->sc_polling; 668 TAILQ_INSERT_TAIL(&sc->sc_p_head, p, p_link); 669 ret = (void *)p->p_desc; 670 671 splx(s); 672 return (ret); 673 } 674 675 void 676 tx39_poll_disestablish(tx_chipset_tag_t tc, void *arg) 677 { 678 struct tx39icu_softc *sc; 679 struct txpoll_entry *p; 680 int s, desc; 681 682 s = splhigh(); 683 sc = tc->tc_intrt; 684 685 desc = (int)arg; 686 TAILQ_FOREACH(p, &sc->sc_p_head, p_link) { 687 if (p->p_desc == desc) { 688 TAILQ_REMOVE(&sc->sc_p_head, p, p_link); 689 free(p, M_DEVBUF); 690 break; 691 } 692 } 693 694 if (TAILQ_EMPTY(&sc->sc_p_head)) { 695 sc->sc_polling = 0; 696 tx_intr_disestablish(tc, sc->sc_poll_ih); 697 } 698 699 splx(s); 700 return; 701 } 702 703 int 704 tx39_poll_intr(void *arg) 705 { 706 struct tx39icu_softc *sc = arg; 707 struct txpoll_entry *p; 708 709 tx39clock_alarm_refill(sc->sc_tc); 710 711 if (!sc->sc_polling) { 712 return (0); 713 } 714 sc->sc_pollcnt++; 715 TAILQ_FOREACH(p, &sc->sc_p_head, p_link) { 716 if (sc->sc_pollcnt % p->p_cnt == 0) { 717 if ((*p->p_fun)(p->p_arg) == POLL_END) 718 goto disestablish; 719 } 720 } 721 722 return (0); 723 724 disestablish: 725 TAILQ_REMOVE(&sc->sc_p_head, p, p_link); 726 free(p, M_DEVBUF); 727 if (TAILQ_EMPTY(&sc->sc_p_head)) { 728 sc->sc_polling = 0; 729 tx_intr_disestablish(sc->sc_tc, sc->sc_poll_ih); 730 } 731 732 return (0); 733 } 734 #endif /* USE_POLL */ 735 736 void 737 tx39_intr_dump(struct tx39icu_softc *sc) 738 { 739 tx_chipset_tag_t tc = sc->sc_tc; 740 int i, j, ofs; 741 txreg_t reg; 742 char msg[16]; 743 744 for (i = 1; i <= TX39_INTRSET_MAX; i++) { 745 #ifdef TX392X 746 if (i == 6) 747 continue; 748 #endif /* TX392X */ 749 for (reg = j = 0; j < 32; j++) { 750 if (tx39_irqhigh(i, j)) { 751 reg |= (1 << j); 752 } 753 } 754 sprintf(msg, "%d high", i); 755 dbg_bit_print_msg(reg, msg); 756 sprintf(msg, "%d status", i); 757 dbg_bit_print_msg(sc->sc_regs[i], msg); 758 ofs = TX39_INTRENABLE_REG(i); 759 reg = tx_conf_read(tc, ofs); 760 sprintf(msg, "%d enable", i); 761 dbg_bit_print_msg(reg, msg); 762 } 763 reg = sc->sc_regs[0]; 764 printf("<%s><%s> vector=%2d\t\t[6 status]\n", 765 reg & TX39_INTRSTATUS6_IRQHIGH ? "HI" : "--", 766 reg & TX39_INTRSTATUS6_IRQLOW ? "LO" : "--", 767 TX39_INTRSTATUS6_INTVECT(reg)); 768 reg = tx_conf_read(tc, TX39_INTRENABLE6_REG); 769 __dbg_bit_print(reg, sizeof(reg), 0, 18, "6 enable", 770 DBG_BIT_PRINT_COUNT); 771 772 } 773