1 /* $NetBSD: tx39icu.c,v 1.35 2015/07/11 10:32:45 kamil 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.35 2015/07/11 10:32:45 kamil 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 #define __INTR_PRIVATE 43 44 #include <sys/param.h> 45 #include <sys/systm.h> 46 #include <sys/device.h> 47 #include <sys/malloc.h> 48 #include <sys/queue.h> 49 #include <sys/cpu.h> 50 51 #include <uvm/uvm_extern.h> 52 53 #include <mips/cpuregs.h> 54 #include <machine/bus.h> 55 #include <machine/intr.h> 56 57 #include <hpcmips/tx/tx39var.h> 58 #include <hpcmips/tx/tx39icureg.h> 59 #include <hpcmips/tx/tx39clockvar.h> 60 61 #include <machine/cpu.h> 62 #include <dev/dec/clockvar.h> 63 64 #undef TX39ICU_DEBUG_PRINT_PENDING_INTERRUPT /* For explorer. good luck! */ 65 66 #if defined(VR41XX) && defined(TX39XX) 67 #define TX_INTR tx_intr 68 #else 69 #define TX_INTR cpu_intr /* locore_mips3 directly call this */ 70 #endif 71 void TX_INTR(int, vaddr_t, uint32_t); 72 73 #ifdef TX39ICU_DEBUG 74 #define DPRINTF_ENABLE 75 #define DPRINTF_DEBUG tx39icu_debug 76 #endif 77 #include <machine/debug.h> 78 79 uint32_t tx39intrvec; 80 81 /* 82 * This is a mask of bits to clear in the SR when we go to a 83 * given interrupt priority level. 84 */ 85 const struct ipl_sr_map __ipl_sr_map_tx = { 86 .sr_bits = { 87 [IPL_NONE] = 0, 88 [IPL_SOFTCLOCK] = MIPS_SOFT_INT_MASK_0, 89 [IPL_SOFTNET] = MIPS_SOFT_INT_MASK, 90 [IPL_VM] = MIPS_SOFT_INT_MASK 91 | MIPS_INT_MASK_2 92 | MIPS_INT_MASK_4, 93 [IPL_SCHED] = MIPS_SOFT_INT_MASK 94 | MIPS_INT_MASK_2 95 | MIPS_INT_MASK_4, 96 [IPL_DDB] = MIPS_INT_MASK, 97 [IPL_HIGH] = MIPS_INT_MASK, 98 }, 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 tx_chipset_tag_t sc_tc; 184 /* IRQLOW */ 185 txreg_t sc_le_mask[TX39_INTRSET_MAX + 1]; 186 int (*sc_le_fun[TX39_INTRSET_MAX + 1][32])(void *); 187 void *sc_le_arg[TX39_INTRSET_MAX + 1][32]; 188 /* IRQHIGH */ 189 TAILQ_HEAD(, txintr_high_entry) sc_he_head[TX39_IRQHIGH_MAX]; 190 /* Register */ 191 txreg_t sc_regs[TX39_INTRSET_MAX + 1]; 192 #ifdef USE_POLL 193 unsigned sc_pollcnt; 194 int sc_polling; 195 void *sc_poll_ih; 196 TAILQ_HEAD(, txpoll_entry) sc_p_head; 197 #endif /* USE_POLL */ 198 }; 199 200 int tx39icu_match(device_t, cfdata_t, void *); 201 void tx39icu_attach(device_t, device_t, void *); 202 203 void tx39_intr_dump(struct tx39icu_softc *); 204 void tx39_intr_decode(int, int *, int *); 205 void tx39_irqhigh_disestablish(tx_chipset_tag_t, int, int, int); 206 void tx39_irqhigh_establish(tx_chipset_tag_t, int, int, int, 207 int (*)(void *), void *); 208 void tx39_irqhigh_intr(uint32_t, vaddr_t, uint32_t); 209 int tx39_irqhigh(int, int); 210 211 CFATTACH_DECL_NEW(tx39icu, sizeof(struct tx39icu_softc), 212 tx39icu_match, tx39icu_attach, NULL, NULL); 213 214 int 215 tx39icu_match(device_t parent, cfdata_t cf, void *aux) 216 { 217 218 return (ATTACH_FIRST); 219 } 220 221 void 222 tx39icu_attach(device_t parent, device_t self, void *aux) 223 { 224 struct txsim_attach_args *ta = aux; 225 struct tx39icu_softc *sc = device_private(self); 226 tx_chipset_tag_t tc = ta->ta_tc; 227 txreg_t reg, *regs; 228 int i; 229 230 printf("\n"); 231 sc->sc_tc = ta->ta_tc; 232 233 regs = sc->sc_regs; 234 regs[0] = tx_conf_read(tc, TX39_INTRSTATUS6_REG); 235 regs[1] = tx_conf_read(tc, TX39_INTRSTATUS1_REG); 236 regs[2] = tx_conf_read(tc, TX39_INTRSTATUS2_REG); 237 regs[3] = tx_conf_read(tc, TX39_INTRSTATUS3_REG); 238 regs[4] = tx_conf_read(tc, TX39_INTRSTATUS4_REG); 239 regs[5] = tx_conf_read(tc, TX39_INTRSTATUS5_REG); 240 #ifdef TX392X 241 regs[7] = tx_conf_read(tc, TX39_INTRSTATUS7_REG); 242 regs[8] = tx_conf_read(tc, TX39_INTRSTATUS8_REG); 243 #endif 244 #ifdef TX39ICU_DEBUG 245 printf("\t[Windows CE setting]\n"); 246 tx39_intr_dump(sc); 247 #endif /* TX39ICU_DEBUG */ 248 249 #ifdef WINCE_DEFAULT_SETTING 250 #warning WINCE_DEFAULT_SETTING 251 #else /* WINCE_DEFAULT_SETTING */ 252 /* Disable IRQLOW */ 253 tx_conf_write(tc, TX39_INTRENABLE1_REG, 0); 254 tx_conf_write(tc, TX39_INTRENABLE2_REG, 0); 255 tx_conf_write(tc, TX39_INTRENABLE3_REG, 0); 256 tx_conf_write(tc, TX39_INTRENABLE4_REG, 0); 257 tx_conf_write(tc, TX39_INTRENABLE5_REG, 0); 258 #ifdef TX392X 259 tx_conf_write(tc, TX39_INTRENABLE7_REG, 0); 260 tx_conf_write(tc, TX39_INTRENABLE8_REG, 0); 261 #endif /* TX392X */ 262 263 /* Disable IRQHIGH */ 264 reg = tx_conf_read(tc, TX39_INTRENABLE6_REG); 265 reg &= ~TX39_INTRENABLE6_PRIORITYMASK_MASK; 266 tx_conf_write(tc, TX39_INTRENABLE6_REG, reg); 267 #endif /* WINCE_DEFAULT_SETTING */ 268 269 /* Clear all pending interrupts */ 270 tx_conf_write(tc, TX39_INTRCLEAR1_REG, 271 tx_conf_read(tc, TX39_INTRSTATUS1_REG)); 272 tx_conf_write(tc, TX39_INTRCLEAR2_REG, 273 tx_conf_read(tc, TX39_INTRSTATUS2_REG)); 274 tx_conf_write(tc, TX39_INTRCLEAR3_REG, 275 tx_conf_read(tc, TX39_INTRSTATUS3_REG)); 276 tx_conf_write(tc, TX39_INTRCLEAR4_REG, 277 tx_conf_read(tc, TX39_INTRSTATUS4_REG)); 278 tx_conf_write(tc, TX39_INTRCLEAR5_REG, 279 tx_conf_read(tc, TX39_INTRSTATUS5_REG)); 280 #ifdef TX392X 281 tx_conf_write(tc, TX39_INTRCLEAR7_REG, 282 tx_conf_read(tc, TX39_INTRSTATUS7_REG)); 283 tx_conf_write(tc, TX39_INTRCLEAR8_REG, 284 tx_conf_read(tc, TX39_INTRSTATUS8_REG)); 285 #endif /* TX392X */ 286 287 /* Enable global interrupts */ 288 reg = tx_conf_read(tc, TX39_INTRENABLE6_REG); 289 reg |= TX39_INTRENABLE6_GLOBALEN; 290 tx_conf_write(tc, TX39_INTRENABLE6_REG, reg); 291 292 /* Initialize IRQHIGH interrupt handler holder*/ 293 for (i = 0; i < TX39_IRQHIGH_MAX; i++) { 294 TAILQ_INIT(&sc->sc_he_head[i]); 295 } 296 #ifdef USE_POLL 297 /* Initialize polling handler holder */ 298 TAILQ_INIT(&sc->sc_p_head); 299 #endif /* USE_POLL */ 300 301 /* Register interrupt module myself */ 302 tx_conf_register_intr(tc, self); 303 } 304 305 void 306 TX_INTR(int ppl, vaddr_t pc, uint32_t status) 307 { 308 uint32_t ipending; 309 int ipl; 310 struct tx39icu_softc *sc; 311 tx_chipset_tag_t tc; 312 txreg_t reg, pend, *regs; 313 int i, j; 314 315 tc = tx_conf_get_tag(); 316 sc = tc->tc_intrt; 317 /* 318 * Read register ASAP 319 */ 320 regs = sc->sc_regs; 321 regs[0] = tx_conf_read(tc, TX39_INTRSTATUS6_REG); 322 regs[1] = tx_conf_read(tc, TX39_INTRSTATUS1_REG); 323 regs[2] = tx_conf_read(tc, TX39_INTRSTATUS2_REG); 324 regs[3] = tx_conf_read(tc, TX39_INTRSTATUS3_REG); 325 regs[4] = tx_conf_read(tc, TX39_INTRSTATUS4_REG); 326 regs[5] = tx_conf_read(tc, TX39_INTRSTATUS5_REG); 327 #ifdef TX392X 328 regs[7] = tx_conf_read(tc, TX39_INTRSTATUS7_REG); 329 regs[8] = tx_conf_read(tc, TX39_INTRSTATUS8_REG); 330 #endif 331 332 while (ppl < (ipl = splintr(&ipending))) { 333 #ifdef TX39ICU_DEBUG 334 if (!(ipending & MIPS_INT_MASK_4) && 335 !(ipending & MIPS_INT_MASK_2)) { 336 dbg_bit_print(ipending); 337 panic("bogus HwInt"); 338 } 339 if (tx39icu_debug > 1) { 340 tx39_intr_dump(sc); 341 } 342 #endif /* TX39ICU_DEBUG */ 343 344 /* IRQHIGH */ 345 if (ipending & MIPS_INT_MASK_4) { 346 tx39_irqhigh_intr(ipending, pc, status); 347 } 348 349 /* IRQLOW */ 350 if (ipending & MIPS_INT_MASK_2) { 351 for (i = 1; i <= TX39_INTRSET_MAX; i++) { 352 int ofs; 353 #ifdef TX392X 354 if (i == 6) 355 continue; 356 #endif /* TX392X */ 357 ofs = TX39_INTRSTATUS_REG(i); 358 pend = sc->sc_regs[i]; 359 reg = sc->sc_le_mask[i] & pend; 360 /* Clear interrupts */ 361 tx_conf_write(tc, ofs, reg); 362 /* Dispatch handler */ 363 for (j = 0 ; j < 32; j++) { 364 if ((reg & (1 << j)) && 365 sc->sc_le_fun[i][j]) { 366 #ifdef TX39ICU_DEBUG 367 if (tx39icu_debug > 1) { 368 tx39intrvec = 369 (i << 16) | j; 370 DPRINTF("IRQLOW " 371 "%d:%d\n", i, j); 372 } 373 #endif /* TX39ICU_DEBUG */ 374 (*sc->sc_le_fun[i][j]) 375 (sc->sc_le_arg[i][j]); 376 377 } 378 } 379 #ifdef TX39ICU_DEBUG_PRINT_PENDING_INTERRUPT 380 pend &= ~reg; 381 if (pend) { 382 printf("%d pending:", i); 383 dbg_bit_print(pend); 384 } 385 #endif 386 387 } 388 } 389 #ifdef TX39_WATCHDOGTIMER 390 { 391 extern int tx39biu_intr(void *); 392 /* Bus error (If watch dog timer is enabled)*/ 393 if (ipending & MIPS_INT_MASK_1) { 394 tx39biu_intr(0); /* Clear bus error */ 395 } 396 } 397 /* 398 * Read register again 399 */ 400 regs[0] = tx_conf_read(tc, TX39_INTRSTATUS6_REG); 401 regs[1] = tx_conf_read(tc, TX39_INTRSTATUS1_REG); 402 regs[2] = tx_conf_read(tc, TX39_INTRSTATUS2_REG); 403 regs[3] = tx_conf_read(tc, TX39_INTRSTATUS3_REG); 404 regs[4] = tx_conf_read(tc, TX39_INTRSTATUS4_REG); 405 regs[5] = tx_conf_read(tc, TX39_INTRSTATUS5_REG); 406 #ifdef TX392X 407 regs[7] = tx_conf_read(tc, TX39_INTRSTATUS7_REG); 408 regs[8] = tx_conf_read(tc, TX39_INTRSTATUS8_REG); 409 #endif 410 #endif 411 } 412 #if 0 413 /* reset priority mask */ 414 reg = tx_conf_read(tc, TX39_INTRENABLE6_REG); 415 reg = TX39_INTRENABLE6_PRIORITYMASK_SET(reg, 0xffff); 416 tx_conf_write(tc, TX39_INTRENABLE6_REG, reg); 417 #endif 418 } 419 420 int 421 tx39_irqhigh(int set, int bit) 422 { 423 int i, n; 424 425 n = sizeof irqhigh_list / sizeof (struct irqhigh_list); 426 for (i = 0; i < n; i++) { 427 if (irqhigh_list[i].qh_set == set && 428 irqhigh_list[i].qh_bit == bit) 429 return (irqhigh_list[i].qh_pri); 430 } 431 432 return (0); 433 } 434 435 void 436 tx39_irqhigh_intr(uint32_t ipending, vaddr_t pc, uint32_t status) 437 { 438 struct txintr_high_entry *he; 439 struct tx39icu_softc *sc; 440 struct clockframe cf; 441 tx_chipset_tag_t tc; 442 int i, pri, ofs, set; 443 txreg_t he_mask; 444 445 tc = tx_conf_get_tag(); 446 sc = tc->tc_intrt; 447 pri = TX39_INTRSTATUS6_INTVECT(sc->sc_regs[0]); 448 449 if (pri == TX39_INTRPRI13_TIMER_PERIODIC) { 450 tx_conf_write(tc, TX39_INTRCLEAR5_REG, 451 TX39_INTRSTATUS5_PERINT); 452 cf.pc = pc; 453 cf.sr = status; 454 cf.intr = (curcpu()->ci_idepth > 1); 455 hardclock(&cf); 456 457 return; 458 } 459 460 /* Handle all pending IRQHIGH interrupts */ 461 for (i = pri; i > 0; i--) { 462 TAILQ_FOREACH(he, &sc->sc_he_head[i], he_link) { 463 set = he->he_set; 464 he_mask = he->he_mask; 465 if (he_mask & (sc->sc_regs[set])) { 466 ofs = TX39_INTRSTATUS_REG(set); 467 /* Clear interrupt */ 468 tx_conf_write(tc, ofs, he_mask); 469 #ifdef TX39ICU_DEBUG 470 if (tx39icu_debug > 1) { 471 tx39intrvec = (set << 16) | 472 (ffs(he_mask) - 1); 473 DPRINTF("IRQHIGH: %d:%d\n", 474 set, ffs(he_mask) - 1); 475 } 476 #endif /* TX39ICU_DEBUG */ 477 /* Dispatch handler */ 478 (*he->he_fun)(he->he_arg); 479 } 480 } 481 } 482 } 483 484 void 485 tx39_intr_decode(int intr, int *set, int *bit) 486 { 487 if (!intr || intr >= (TX39_INTRSET_MAX + 1) * 32 488 #ifdef TX392X 489 || intr == 6 490 #endif /* TX392X */ 491 ) { 492 panic("tx39icu_decode: bogus intrrupt line. %d", intr); 493 } 494 *set = intr / 32; 495 *bit = intr % 32; 496 } 497 498 void 499 tx39_irqhigh_establish(tx_chipset_tag_t tc, int set, int bit, int pri, 500 int (*ih_fun)(void *), void *ih_arg) 501 { 502 struct tx39icu_softc *sc; 503 struct txintr_high_entry *he; 504 txreg_t reg; 505 506 sc = tc->tc_intrt; 507 /* 508 * Add new entry to `pri' priority 509 */ 510 if (!(he = malloc(sizeof(struct txintr_high_entry), 511 M_DEVBUF, M_NOWAIT))) { 512 panic ("tx39_irqhigh_establish: no memory."); 513 } 514 memset(he, 0, sizeof(struct txintr_high_entry)); 515 he->he_set = set; 516 he->he_mask= (1 << bit); 517 he->he_fun = ih_fun; 518 he->he_arg = ih_arg; 519 TAILQ_INSERT_TAIL(&sc->sc_he_head[pri], he, he_link); 520 /* 521 * Enable interrupt on this priority. 522 */ 523 reg = tx_conf_read(tc, TX39_INTRENABLE6_REG); 524 reg = TX39_INTRENABLE6_PRIORITYMASK_SET(reg, (1 << pri)); 525 tx_conf_write(tc, TX39_INTRENABLE6_REG, reg); 526 } 527 528 void 529 tx39_irqhigh_disestablish(tx_chipset_tag_t tc, int set, int bit, int pri) 530 { 531 struct tx39icu_softc *sc; 532 struct txintr_high_entry *he; 533 txreg_t reg; 534 535 sc = tc->tc_intrt; 536 TAILQ_FOREACH(he, &sc->sc_he_head[pri], he_link) { 537 if (he->he_set == set && he->he_mask == (1 << bit)) { 538 TAILQ_REMOVE(&sc->sc_he_head[pri], he, he_link); 539 free(he, M_DEVBUF); 540 break; 541 } 542 } 543 544 if (TAILQ_EMPTY(&sc->sc_he_head[pri])) { 545 reg = tx_conf_read(tc, TX39_INTRENABLE6_REG); 546 reg &= ~(1 << pri); 547 tx_conf_write(tc, TX39_INTRENABLE6_REG, reg); 548 } 549 } 550 551 552 void * 553 tx_intr_establish(tx_chipset_tag_t tc, int line, int mode, int level, 554 int (*ih_fun)(void *), void *ih_arg) 555 { 556 struct tx39icu_softc *sc; 557 txreg_t reg; 558 int bit, set, highpri, ofs; 559 560 sc = tc->tc_intrt; 561 562 tx39_intr_decode(line, &set, &bit); 563 564 sc->sc_le_fun[set][bit] = ih_fun; 565 sc->sc_le_arg[set][bit] = ih_arg; 566 DPRINTF("tx_intr_establish: %d:%d", set, bit); 567 568 if ((highpri = tx39_irqhigh(set, bit))) { 569 tx39_irqhigh_establish(tc, set, bit, highpri, 570 ih_fun, ih_arg); 571 DPRINTF("(high)\n"); 572 } else { 573 /* Set mask for acknowledge. */ 574 sc->sc_le_mask[set] |= (1 << bit); 575 /* Enable interrupt */ 576 ofs = TX39_INTRENABLE_REG(set); 577 reg = tx_conf_read(tc, ofs); 578 reg |= (1 << bit); 579 tx_conf_write(tc, ofs, reg); 580 DPRINTF("(low)\n"); 581 } 582 583 return ((void *)line); 584 } 585 586 void 587 tx_intr_disestablish(tx_chipset_tag_t tc, void *arg) 588 { 589 struct tx39icu_softc *sc; 590 int set, bit, highpri, ofs; 591 txreg_t reg; 592 593 sc = tc->tc_intrt; 594 595 tx39_intr_decode((int)arg, &set, &bit); 596 DPRINTF("tx_intr_disestablish: %d:%d", set, bit); 597 598 if ((highpri = tx39_irqhigh(set, bit))) { 599 tx39_irqhigh_disestablish(tc, set, bit, highpri); 600 DPRINTF("(high)\n"); 601 } else { 602 sc->sc_le_fun[set][bit] = 0; 603 sc->sc_le_arg[set][bit] = 0; 604 sc->sc_le_mask[set] &= ~(1 << bit); 605 ofs = TX39_INTRENABLE_REG(set); 606 reg = tx_conf_read(tc, ofs); 607 reg &= ~(1 << bit); 608 tx_conf_write(tc, ofs, reg); 609 DPRINTF("(low)\n"); 610 } 611 } 612 613 uint32_t 614 tx_intr_status(tx_chipset_tag_t tc, int r) 615 { 616 struct tx39icu_softc *sc = tc->tc_intrt; 617 618 if (r < 0 || r >= TX39_INTRSET_MAX + 1) 619 panic("tx_intr_status: invalid index %d", r); 620 621 return (uint32_t)(sc->sc_regs[r]); 622 } 623 624 #ifdef USE_POLL 625 void * 626 tx39_poll_establish(tx_chipset_tag_t tc, int interval, int level, 627 int (*ih_fun)(void *), void *ih_arg) 628 { 629 struct tx39icu_softc *sc; 630 struct txpoll_entry *p; 631 int s; 632 void *ret; 633 634 s = splhigh(); 635 sc = tc->tc_intrt; 636 637 if (!(p = malloc(sizeof(*p), M_DEVBUF, M_NOWAIT | M_ZERO))) { 638 panic ("tx39_poll_establish: no memory."); 639 } 640 641 p->p_fun = ih_fun; 642 p->p_arg = ih_arg; 643 p->p_cnt = interval; 644 645 if (!sc->sc_polling) { 646 tx39clock_alarm_set(tc, 33); /* 33 msec */ 647 648 if (!(sc->sc_poll_ih = tx_intr_establish( 649 tc, MAKEINTR(5, TX39_INTRSTATUS5_ALARMINT), 650 IST_EDGE, level, tx39_poll_intr, sc))) { 651 printf("tx39_poll_establish: can't hook\n"); 652 653 splx(s); 654 free(p, M_DEVBUF); 655 return (0); 656 } 657 } 658 659 sc->sc_polling++; 660 p->p_desc = sc->sc_polling; 661 TAILQ_INSERT_TAIL(&sc->sc_p_head, p, p_link); 662 ret = (void *)p->p_desc; 663 664 splx(s); 665 return (ret); 666 } 667 668 void 669 tx39_poll_disestablish(tx_chipset_tag_t tc, void *arg) 670 { 671 struct tx39icu_softc *sc; 672 struct txpoll_entry *p; 673 int s, desc; 674 675 s = splhigh(); 676 sc = tc->tc_intrt; 677 678 desc = (int)arg; 679 TAILQ_FOREACH(p, &sc->sc_p_head, p_link) { 680 if (p->p_desc == desc) { 681 TAILQ_REMOVE(&sc->sc_p_head, p, p_link); 682 free(p, M_DEVBUF); 683 break; 684 } 685 } 686 687 if (TAILQ_EMPTY(&sc->sc_p_head)) { 688 sc->sc_polling = 0; 689 tx_intr_disestablish(tc, sc->sc_poll_ih); 690 } 691 692 splx(s); 693 return; 694 } 695 696 int 697 tx39_poll_intr(void *arg) 698 { 699 struct tx39icu_softc *sc = arg; 700 struct txpoll_entry *p; 701 702 tx39clock_alarm_refill(sc->sc_tc); 703 704 if (!sc->sc_polling) { 705 return (0); 706 } 707 sc->sc_pollcnt++; 708 TAILQ_FOREACH(p, &sc->sc_p_head, p_link) { 709 if (sc->sc_pollcnt % p->p_cnt == 0) { 710 if ((*p->p_fun)(p->p_arg) == POLL_END) 711 goto disestablish; 712 } 713 } 714 715 return (0); 716 717 disestablish: 718 TAILQ_REMOVE(&sc->sc_p_head, p, p_link); 719 free(p, M_DEVBUF); 720 if (TAILQ_EMPTY(&sc->sc_p_head)) { 721 sc->sc_polling = 0; 722 tx_intr_disestablish(sc->sc_tc, sc->sc_poll_ih); 723 } 724 725 return (0); 726 } 727 #endif /* USE_POLL */ 728 729 void 730 tx39_intr_dump(struct tx39icu_softc *sc) 731 { 732 tx_chipset_tag_t tc = sc->sc_tc; 733 int i, j, ofs; 734 txreg_t reg; 735 char msg[16]; 736 737 for (i = 1; i <= TX39_INTRSET_MAX; i++) { 738 #ifdef TX392X 739 if (i == 6) 740 continue; 741 #endif /* TX392X */ 742 for (reg = j = 0; j < 32; j++) { 743 if (tx39_irqhigh(i, j)) { 744 reg |= (1 << j); 745 } 746 } 747 snprintf(msg, sizeof(msg), "%d high", i); 748 dbg_bit_print_msg(reg, msg); 749 snprintf(msg, sizeof(msg), "%d status", i); 750 dbg_bit_print_msg(sc->sc_regs[i], msg); 751 ofs = TX39_INTRENABLE_REG(i); 752 reg = tx_conf_read(tc, ofs); 753 snprintf(msg, sizeof(msg), "%d enable", i); 754 dbg_bit_print_msg(reg, msg); 755 } 756 reg = sc->sc_regs[0]; 757 printf("<%s><%s> vector=%2d\t\t[6 status]\n", 758 reg & TX39_INTRSTATUS6_IRQHIGH ? "HI" : "--", 759 reg & TX39_INTRSTATUS6_IRQLOW ? "LO" : "--", 760 TX39_INTRSTATUS6_INTVECT(reg)); 761 reg = tx_conf_read(tc, TX39_INTRENABLE6_REG); 762 __dbg_bit_print(reg, sizeof(reg), 0, 18, "6 enable", 763 DBG_BIT_PRINT_COUNT); 764 765 } 766