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