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