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