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