1/* $NetBSD: tx39icu.c,v 1.30 2011/02/26 12:54:41 tsutsui 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.30 2011/02/26 12:54:41 tsutsui 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 71void 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 79uint32_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 */ 85const 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 */ 102static 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 163struct 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 172struct 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}; 179int tx39_poll_intr(void *); 180#endif /* USE_POLL */ 181 182struct 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 201int tx39icu_match(struct device *, struct cfdata *, void *); 202void tx39icu_attach(struct device *, struct device *, void *); 203 204void tx39_intr_dump(struct tx39icu_softc *); 205void tx39_intr_decode(int, int *, int *); 206void tx39_irqhigh_disestablish(tx_chipset_tag_t, int, int, int); 207void tx39_irqhigh_establish(tx_chipset_tag_t, int, int, int, 208 int (*)(void *), void *); 209void tx39_irqhigh_intr(uint32_t, vaddr_t, uint32_t); 210int tx39_irqhigh(int, int); 211 212CFATTACH_DECL(tx39icu, sizeof(struct tx39icu_softc), 213 tx39icu_match, tx39icu_attach, NULL, NULL); 214 215int 216tx39icu_match(struct device *parent, struct cfdata *cf, void *aux) 217{ 218 219 return (ATTACH_FIRST); 220} 221 222void 223tx39icu_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 306void 307TX_INTR(int ppl, vaddr_t pc, uint32_t status) 308{ 309 uint32_t ipending; 310 int ipl; 311 struct tx39icu_softc *sc; 312 tx_chipset_tag_t tc; 313 txreg_t reg, pend, *regs; 314 int i, j; 315 316 tc = tx_conf_get_tag(); 317 sc = tc->tc_intrt; 318 /* 319 * Read regsiter ASAP 320 */ 321 regs = sc->sc_regs; 322 regs[0] = tx_conf_read(tc, TX39_INTRSTATUS6_REG); 323 regs[1] = tx_conf_read(tc, TX39_INTRSTATUS1_REG); 324 regs[2] = tx_conf_read(tc, TX39_INTRSTATUS2_REG); 325 regs[3] = tx_conf_read(tc, TX39_INTRSTATUS3_REG); 326 regs[4] = tx_conf_read(tc, TX39_INTRSTATUS4_REG); 327 regs[5] = tx_conf_read(tc, TX39_INTRSTATUS5_REG); 328#ifdef TX392X 329 regs[7] = tx_conf_read(tc, TX39_INTRSTATUS7_REG); 330 regs[8] = tx_conf_read(tc, TX39_INTRSTATUS8_REG); 331#endif 332 333 while (ppl < (ipl = splintr(&ipending))) { 334#ifdef TX39ICU_DEBUG 335 if (!(ipending & MIPS_INT_MASK_4) && 336 !(ipending & MIPS_INT_MASK_2)) { 337 dbg_bit_print(ipending); 338 panic("bogus HwInt"); 339 } 340 if (tx39icu_debug > 1) { 341 tx39_intr_dump(sc); 342 } 343#endif /* TX39ICU_DEBUG */ 344 345 /* IRQHIGH */ 346 if (ipending & MIPS_INT_MASK_4) { 347 tx39_irqhigh_intr(ipending, pc, status); 348 } 349 350 /* IRQLOW */ 351 if (ipending & MIPS_INT_MASK_2) { 352 for (i = 1; i <= TX39_INTRSET_MAX; i++) { 353 int ofs; 354#ifdef TX392X 355 if (i == 6) 356 continue; 357#endif /* TX392X */ 358 ofs = TX39_INTRSTATUS_REG(i); 359 pend = sc->sc_regs[i]; 360 reg = sc->sc_le_mask[i] & pend; 361 /* Clear interrupts */ 362 tx_conf_write(tc, ofs, reg); 363 /* Dispatch handler */ 364 for (j = 0 ; j < 32; j++) { 365 if ((reg & (1 << j)) && 366 sc->sc_le_fun[i][j]) { 367#ifdef TX39ICU_DEBUG 368 if (tx39icu_debug > 1) { 369 tx39intrvec = 370 (i << 16) | j; 371 DPRINTF("IRQLOW " 372 "%d:%d\n", i, j); 373 } 374#endif /* TX39ICU_DEBUG */ 375 (*sc->sc_le_fun[i][j]) 376 (sc->sc_le_arg[i][j]); 377 378 } 379 } 380#ifdef TX39ICU_DEBUG_PRINT_PENDING_INTERRUPT 381 pend &= ~reg; 382 if (pend) { 383 printf("%d pending:", i); 384 dbg_bit_print(pend); 385 } 386#endif 387 388 } 389 } 390#ifdef TX39_WATCHDOGTIMER 391 { 392 extern int tx39biu_intr(void *); 393 /* Bus error (If watch dog timer is enabled)*/ 394 if (ipending & MIPS_INT_MASK_1) { 395 tx39biu_intr(0); /* Clear bus error */ 396 } 397 } 398 /* 399 * Read regsiter again 400 */ 401 regs[0] = tx_conf_read(tc, TX39_INTRSTATUS6_REG); 402 regs[1] = tx_conf_read(tc, TX39_INTRSTATUS1_REG); 403 regs[2] = tx_conf_read(tc, TX39_INTRSTATUS2_REG); 404 regs[3] = tx_conf_read(tc, TX39_INTRSTATUS3_REG); 405 regs[4] = tx_conf_read(tc, TX39_INTRSTATUS4_REG); 406 regs[5] = tx_conf_read(tc, TX39_INTRSTATUS5_REG); 407#ifdef TX392X 408 regs[7] = tx_conf_read(tc, TX39_INTRSTATUS7_REG); 409 regs[8] = tx_conf_read(tc, TX39_INTRSTATUS8_REG); 410#endif 411#endif 412 } 413#if 0 414 /* reset priority mask */ 415 reg = tx_conf_read(tc, TX39_INTRENABLE6_REG); 416 reg = TX39_INTRENABLE6_PRIORITYMASK_SET(reg, 0xffff); 417 tx_conf_write(tc, TX39_INTRENABLE6_REG, reg); 418#endif 419} 420 421int 422tx39_irqhigh(int set, int bit) 423{ 424 int i, n; 425 426 n = sizeof irqhigh_list / sizeof (struct irqhigh_list); 427 for (i = 0; i < n; i++) { 428 if (irqhigh_list[i].qh_set == set && 429 irqhigh_list[i].qh_bit == bit) 430 return (irqhigh_list[i].qh_pri); 431 } 432 433 return (0); 434} 435 436void 437tx39_irqhigh_intr(uint32_t ipending, vaddr_t pc, uint32_t status) 438{ 439 struct txintr_high_entry *he; 440 struct tx39icu_softc *sc; 441 struct clockframe cf; 442 tx_chipset_tag_t tc; 443 int i, pri, ofs, set; 444 txreg_t he_mask; 445 446 tc = tx_conf_get_tag(); 447 sc = tc->tc_intrt; 448 pri = TX39_INTRSTATUS6_INTVECT(sc->sc_regs[0]); 449 450 if (pri == TX39_INTRPRI13_TIMER_PERIODIC) { 451 tx_conf_write(tc, TX39_INTRCLEAR5_REG, 452 TX39_INTRSTATUS5_PERINT); 453 cf.pc = pc; 454 cf.sr = status; 455 cf.intr = (curcpu()->ci_idepth > 1); 456 hardclock(&cf); 457 458 return; 459 } 460 461 /* Handle all pending IRQHIGH interrupts */ 462 for (i = pri; i > 0; i--) { 463 TAILQ_FOREACH(he, &sc->sc_he_head[i], he_link) { 464 set = he->he_set; 465 he_mask = he->he_mask; 466 if (he_mask & (sc->sc_regs[set])) { 467 ofs = TX39_INTRSTATUS_REG(set); 468 /* Clear interrupt */ 469 tx_conf_write(tc, ofs, he_mask); 470#ifdef TX39ICU_DEBUG 471 if (tx39icu_debug > 1) { 472 tx39intrvec = (set << 16) | 473 (ffs(he_mask) - 1); 474 DPRINTF("IRQHIGH: %d:%d\n", 475 set, ffs(he_mask) - 1); 476 } 477#endif /* TX39ICU_DEBUG */ 478 /* Dispatch handler */ 479 (*he->he_fun)(he->he_arg); 480 } 481 } 482 } 483} 484 485void 486tx39_intr_decode(int intr, int *set, int *bit) 487{ 488 if (!intr || intr >= (TX39_INTRSET_MAX + 1) * 32 489#ifdef TX392X 490 || intr == 6 491#endif /* TX392X */ 492 ) { 493 panic("tx39icu_decode: bogus intrrupt line. %d", intr); 494 } 495 *set = intr / 32; 496 *bit = intr % 32; 497} 498 499void 500tx39_irqhigh_establish(tx_chipset_tag_t tc, int set, int bit, int pri, 501 int (*ih_fun)(void *), void *ih_arg) 502{ 503 struct tx39icu_softc *sc; 504 struct txintr_high_entry *he; 505 txreg_t reg; 506 507 sc = tc->tc_intrt; 508 /* 509 * Add new entry to `pri' priority 510 */ 511 if (!(he = malloc(sizeof(struct txintr_high_entry), 512 M_DEVBUF, M_NOWAIT))) { 513 panic ("tx39_irqhigh_establish: no memory."); 514 } 515 memset(he, 0, sizeof(struct txintr_high_entry)); 516 he->he_set = set; 517 he->he_mask= (1 << bit); 518 he->he_fun = ih_fun; 519 he->he_arg = ih_arg; 520 TAILQ_INSERT_TAIL(&sc->sc_he_head[pri], he, he_link); 521 /* 522 * Enable interrupt on this priority. 523 */ 524 reg = tx_conf_read(tc, TX39_INTRENABLE6_REG); 525 reg = TX39_INTRENABLE6_PRIORITYMASK_SET(reg, (1 << pri)); 526 tx_conf_write(tc, TX39_INTRENABLE6_REG, reg); 527} 528 529void 530tx39_irqhigh_disestablish(tx_chipset_tag_t tc, int set, int bit, int pri) 531{ 532 struct tx39icu_softc *sc; 533 struct txintr_high_entry *he; 534 txreg_t reg; 535 536 sc = tc->tc_intrt; 537 TAILQ_FOREACH(he, &sc->sc_he_head[pri], he_link) { 538 if (he->he_set == set && he->he_mask == (1 << bit)) { 539 TAILQ_REMOVE(&sc->sc_he_head[pri], he, he_link); 540 free(he, M_DEVBUF); 541 break; 542 } 543 } 544 545 if (TAILQ_EMPTY(&sc->sc_he_head[pri])) { 546 reg = tx_conf_read(tc, TX39_INTRENABLE6_REG); 547 reg &= ~(1 << pri); 548 tx_conf_write(tc, TX39_INTRENABLE6_REG, reg); 549 } 550} 551 552 553void * 554tx_intr_establish(tx_chipset_tag_t tc, int line, int mode, int level, 555 int (*ih_fun)(void *), void *ih_arg) 556{ 557 struct tx39icu_softc *sc; 558 txreg_t reg; 559 int bit, set, highpri, ofs; 560 561 sc = tc->tc_intrt; 562 563 tx39_intr_decode(line, &set, &bit); 564 565 sc->sc_le_fun[set][bit] = ih_fun; 566 sc->sc_le_arg[set][bit] = ih_arg; 567 DPRINTF("tx_intr_establish: %d:%d", set, bit); 568 569 if ((highpri = tx39_irqhigh(set, bit))) { 570 tx39_irqhigh_establish(tc, set, bit, highpri, 571 ih_fun, ih_arg); 572 DPRINTF("(high)\n"); 573 } else { 574 /* Set mask for acknowledge. */ 575 sc->sc_le_mask[set] |= (1 << bit); 576 /* Enable interrupt */ 577 ofs = TX39_INTRENABLE_REG(set); 578 reg = tx_conf_read(tc, ofs); 579 reg |= (1 << bit); 580 tx_conf_write(tc, ofs, reg); 581 DPRINTF("(low)\n"); 582 } 583 584 return ((void *)line); 585} 586 587void 588tx_intr_disestablish(tx_chipset_tag_t tc, void *arg) 589{ 590 struct tx39icu_softc *sc; 591 int set, bit, highpri, ofs; 592 txreg_t reg; 593 594 sc = tc->tc_intrt; 595 596 tx39_intr_decode((int)arg, &set, &bit); 597 DPRINTF("tx_intr_disestablish: %d:%d", set, bit); 598 599 if ((highpri = tx39_irqhigh(set, bit))) { 600 tx39_irqhigh_disestablish(tc, set, bit, highpri); 601 DPRINTF("(high)\n"); 602 } else { 603 sc->sc_le_fun[set][bit] = 0; 604 sc->sc_le_arg[set][bit] = 0; 605 sc->sc_le_mask[set] &= ~(1 << bit); 606 ofs = TX39_INTRENABLE_REG(set); 607 reg = tx_conf_read(tc, ofs); 608 reg &= ~(1 << bit); 609 tx_conf_write(tc, ofs, reg); 610 DPRINTF("(low)\n"); 611 } 612} 613 614uint32_t 615tx_intr_status(tx_chipset_tag_t tc, int r) 616{ 617 struct tx39icu_softc *sc = tc->tc_intrt; 618 619 if (r < 0 || r >= TX39_INTRSET_MAX + 1) 620 panic("tx_intr_status: invalid index %d", r); 621 622 return (uint32_t)(sc->sc_regs[r]); 623} 624 625#ifdef USE_POLL 626void * 627tx39_poll_establish(tx_chipset_tag_t tc, int interval, int level, 628 int (*ih_fun)(void *), void *ih_arg) 629{ 630 struct tx39icu_softc *sc; 631 struct txpoll_entry *p; 632 int s; 633 void *ret; 634 635 s = splhigh(); 636 sc = tc->tc_intrt; 637 638 if (!(p = malloc(sizeof(struct txpoll_entry), 639 M_DEVBUF, M_NOWAIT))) { 640 panic ("tx39_poll_establish: no memory."); 641 } 642 memset(p, 0, sizeof(struct txpoll_entry)); 643 644 p->p_fun = ih_fun; 645 p->p_arg = ih_arg; 646 p->p_cnt = interval; 647 648 if (!sc->sc_polling) { 649 tx39clock_alarm_set(tc, 33); /* 33 msec */ 650 651 if (!(sc->sc_poll_ih = 652 tx_intr_establish( 653 tc, MAKEINTR(5, TX39_INTRSTATUS5_ALARMINT), 654 IST_EDGE, level, tx39_poll_intr, sc))) { 655 printf("tx39_poll_establish: can't hook\n"); 656 657 splx(s); 658 return (0); 659 } 660 } 661 662 sc->sc_polling++; 663 p->p_desc = sc->sc_polling; 664 TAILQ_INSERT_TAIL(&sc->sc_p_head, p, p_link); 665 ret = (void *)p->p_desc; 666 667 splx(s); 668 return (ret); 669} 670 671void 672tx39_poll_disestablish(tx_chipset_tag_t tc, void *arg) 673{ 674 struct tx39icu_softc *sc; 675 struct txpoll_entry *p; 676 int s, desc; 677 678 s = splhigh(); 679 sc = tc->tc_intrt; 680 681 desc = (int)arg; 682 TAILQ_FOREACH(p, &sc->sc_p_head, p_link) { 683 if (p->p_desc == desc) { 684 TAILQ_REMOVE(&sc->sc_p_head, p, p_link); 685 free(p, M_DEVBUF); 686 break; 687 } 688 } 689 690 if (TAILQ_EMPTY(&sc->sc_p_head)) { 691 sc->sc_polling = 0; 692 tx_intr_disestablish(tc, sc->sc_poll_ih); 693 } 694 695 splx(s); 696 return; 697} 698 699int 700tx39_poll_intr(void *arg) 701{ 702 struct tx39icu_softc *sc = arg; 703 struct txpoll_entry *p; 704 705 tx39clock_alarm_refill(sc->sc_tc); 706 707 if (!sc->sc_polling) { 708 return (0); 709 } 710 sc->sc_pollcnt++; 711 TAILQ_FOREACH(p, &sc->sc_p_head, p_link) { 712 if (sc->sc_pollcnt % p->p_cnt == 0) { 713 if ((*p->p_fun)(p->p_arg) == POLL_END) 714 goto disestablish; 715 } 716 } 717 718 return (0); 719 720 disestablish: 721 TAILQ_REMOVE(&sc->sc_p_head, p, p_link); 722 free(p, M_DEVBUF); 723 if (TAILQ_EMPTY(&sc->sc_p_head)) { 724 sc->sc_polling = 0; 725 tx_intr_disestablish(sc->sc_tc, sc->sc_poll_ih); 726 } 727 728 return (0); 729} 730#endif /* USE_POLL */ 731 732void 733tx39_intr_dump(struct tx39icu_softc *sc) 734{ 735 tx_chipset_tag_t tc = sc->sc_tc; 736 int i, j, ofs; 737 txreg_t reg; 738 char msg[16]; 739 740 for (i = 1; i <= TX39_INTRSET_MAX; i++) { 741#ifdef TX392X 742 if (i == 6) 743 continue; 744#endif /* TX392X */ 745 for (reg = j = 0; j < 32; j++) { 746 if (tx39_irqhigh(i, j)) { 747 reg |= (1 << j); 748 } 749 } 750 sprintf(msg, "%d high", i); 751 dbg_bit_print_msg(reg, msg); 752 sprintf(msg, "%d status", i); 753 dbg_bit_print_msg(sc->sc_regs[i], msg); 754 ofs = TX39_INTRENABLE_REG(i); 755 reg = tx_conf_read(tc, ofs); 756 sprintf(msg, "%d enable", i); 757 dbg_bit_print_msg(reg, msg); 758 } 759 reg = sc->sc_regs[0]; 760 printf("<%s><%s> vector=%2d\t\t[6 status]\n", 761 reg & TX39_INTRSTATUS6_IRQHIGH ? "HI" : "--", 762 reg & TX39_INTRSTATUS6_IRQLOW ? "LO" : "--", 763 TX39_INTRSTATUS6_INTVECT(reg)); 764 reg = tx_conf_read(tc, TX39_INTRENABLE6_REG); 765 __dbg_bit_print(reg, sizeof(reg), 0, 18, "6 enable", 766 DBG_BIT_PRINT_COUNT); 767 768} 769