1 /* $NetBSD: extintr.c,v 1.19 2009/03/14 14:46:05 dsl Exp $ */
4 * Copyright (c) 2002 Allegro Networks, Inc., Wasabi Systems, Inc.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed for the NetBSD Project by
18 * Allegro Networks, Inc., and Wasabi Systems, Inc.
19 * 4. The name of Allegro Networks, Inc. may not be used to endorse
20 * or promote products derived from this software without specific prior
22 * 5. The name of Wasabi Systems, Inc. may not be used to endorse
23 * or promote products derived from this software without specific prior
26 * THIS SOFTWARE IS PROVIDED BY ALLEGRO NETWORKS, INC. AND
27 * WASABI SYSTEMS, INC. ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
28 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
29 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
30 * IN NO EVENT SHALL EITHER ALLEGRO NETWORKS, INC. OR WASABI SYSTEMS, INC.
31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37 * POSSIBILITY OF SUCH DAMAGE.
41 * extintr.c - external interrupt management for discovery
43 * Interrupts are software-prioritized and preempting,
44 * they are only actually masked when pending.
45 * this allows avoiding slow, off-CPU mask reprogramming for spl/splx.
46 * When a lower priority interrupt preempts a high one,
47 * it is pended and masked. Masks are re-enabled after service.
49 * `ci->ci_cpl' is a "priority level" not a bitmask.
50 * `irq' is a bit number in the 128 bit imask_t which reflects
51 * the GT-64260 Main Cause register pair (64 bits), and
52 * GPP Cause register (32 bits) interrupts.
54 * Intra IPL dispatch order is defined in cause_irq()
56 * Summary bits in cause registers are not valid IRQs
58 * Within a cause register bit vector ISRs are called in
59 * order of IRQ (descending).
61 * When IRQs are shared, ISRs are called in order on the queue
62 * (which is arbitrarily first-established-first-served).
64 * GT64260 GPP setup is for edge-triggered interrupts.
65 * We maintain a mask of level-triggered type IRQs
66 * and gather unlatched level from the GPP Value register.
68 * Software interrupts are just like regular IRQs,
69 * they are established, pended, and dispatched exactly the
70 * same as HW interrupts.
72 * 128 bit imask_t operations could be implemented with Altivec
73 * ("vand", "vor", etc however no "vcntlzw" or "vffs"....)
75 * creation Tue Feb 6 17:27:18 PST 2001 cliff
78 #include <sys/cdefs.h>
79 __KERNEL_RCSID(0, "$NetBSD: extintr.c,v 1.19 2009/03/14 14:46:05 dsl Exp $");
81 #include "opt_marvell.h"
84 #include <sys/param.h>
85 #include <sys/systm.h>
86 #include <sys/types.h>
87 #include <sys/malloc.h>
88 #include <sys/kernel.h>
90 #include <machine/psl.h>
91 #include <machine/bus.h>
92 #include <machine/cpu.h>
93 #include <machine/intr.h>
95 #include <machine/db_machdep.h>
97 #include <dev/marvell/gtreg.h>
98 #include <dev/marvell/gtvar.h>
99 #include <dev/marvell/gtintrreg.h>
101 #include <net/netisr.h>
103 #include <uvm/uvm_extern.h>
105 #if defined(DEBUG) && defined(DDB)
111 # define DPRINTF(x) do { if (intrdebug) printf x ; } while (0)
112 # define DPRINTFN(n, x) do { if (intrdebug > (n)) printf x ; } while (0)
114 # define STATIC static
116 # define DPRINTFN(n, x)
120 # define DIAGPRF(x) printf x
125 #define ILLEGAL_IRQ(x) (((x) < 0) || ((x) >= NIRQ) || \
126 ((1<<((x)&IMASK_BITMASK)) & imres.bits[(x)>>IMASK_WORDSHIFT]))
128 extern struct powerpc_bus_space gt_mem_bs_tag
;
129 extern bus_space_handle_t gt_memh
;
133 struct intrhand
*is_hand
;
134 struct evcnt is_evcnt
;
142 * Interrupt handler chains. intr_establish() inserts a handler into
143 * the list. The handler is called with its (single) argument.
146 int (*ih_fun
)(void *);
148 struct intrhand
*ih_next
;
149 struct intrsource
*ih_source
;
151 int ih_level
; /* sanity only */
155 #define IH_ACTIVE 0x01
157 struct intrsource intr_sources
[NIRQ
];
159 struct intrhand
*softnet_handlers
[32];
161 const char intr_source_strings
[NIRQ
][16] = {
162 "unknown 0", "dev", "dma", "cpu",
163 "idma 01", "idma 23", "idma 45", "idma 67",
164 "timer 01", "timer 23", "timer 45", "timer 67",
165 "pci0-0", "pci0-1", "pci0-2", "pci0-3",
166 /*16*/ "pci1-0", "ecc", "pci1-1", "pci1-2",
167 "pci1-3", "pci0-outl", "pci0-outh", "pci1-outl",
168 "pci1-outh", "unknown 25", "pci0-inl", "pci0-inh",
169 "pci1-inl", "pci1-inh", "unknown 30", "unknown 31",
170 /*32*/ "ether 0", "ether 1", "ether 2", "unknown 35",
171 "sdma", "iic", "unknown 38", "brg",
172 "mpsc 0", "unknown 41", "mpsc 1", "comm",
173 "unknown 44", "unknown 45", "unknown 46", "unknown 47",
174 /*48*/ "unknown 48", "unknown 49", "unknown 50", "unknown 51",
175 "unknown 52", "unknown 53", "unknown 54", "unknown 55",
176 "gppsum 0", "gppsum 1", "gppsum 2", "gppsum 3",
177 "unknown 60", "unknown 61", "unknown 62", "unknown 63",
178 /*64*/ "gpp 0", "gpp 1", "gpp 2", "gpp 3",
179 "gpp 4", "gpp 5", "gpp 6", "gpp 7",
180 "gpp 8", "gpp 9", "gpp 10", "gpp 11",
181 "gpp 12", "gpp 13", "gpp 14", "gpp 15",
182 /*80*/ "gpp 16", "gpp 17", "gpp 18", "gpp 19",
183 "gpp 20", "gpp 21", "gpp 22", "gpp 23",
184 "gpp 24", "gpp 25", "gpp 26", "gpp 27",
185 "gpp 28", "gpp 29", "gpp 30", "gpp 31",
186 /*96*/ "soft 0", "soft 1", "soft 2", "soft 3",
187 "soft 4", "soft 5", "soft 6", "soft 7",
188 "soft 8", "soft 9", "soft 10", "soft 11",
189 "soft 12", "soft 13", "soft 14", "soft 15",
190 /*112*/ "soft 16", "soft 17", "soft 18", "soft 19",
191 "soft 20", "soft 21", "soft 22", "soft 23",
192 "soft 24", "soft 25", "soft 26", "soft clock",
193 "soft net", "soft iic", "soft serial", "hwclock",
196 #ifdef EXT_INTR_STATS
197 #define EXT_INTR_STAT_HISTSZ 4096
198 ext_intr_stat_t ext_intr_stats
[NIRQ
] = {{0},};
199 ext_intr_hist_t ext_intr_hist
[NIRQ
][EXT_INTR_STAT_HISTSZ
];
203 #define GPP_RES ~GT_MPP_INTERRUPTS /* from config */
206 * ipending and imen HW IRQs require MSR[EE]=0 protection
208 volatile imask_t ipending
__attribute__ ((aligned(CACHELINESIZE
)));
209 volatile imask_t imen
__attribute__ ((aligned(CACHELINESIZE
)));
210 imask_t imask
[NIPL
] __attribute__ ((aligned(CACHELINESIZE
)));
211 const imask_t imres
=
212 { { (IML_RES
|IML_SUM
), (IMH_RES
|IMH_GPP_SUM
), GPP_RES
, SIR_RES
} };
215 struct intrframe
*intrframe
= 0;
216 static int intr_depth
;
217 #define EXTINTR_SANITY_SZ 16
221 } extintr_sanity
[EXTINTR_SANITY_SZ
] = {{ 0, }};
223 #define EXTINTR_SANITY() \
224 if (intr_depth < EXTINTR_SANITY_SZ) { \
225 extintr_sanity[intr_depth].ipl = ci->ci_cpl; \
226 imask_dup_v(&extintr_sanity[intr_depth].oimen, &imen); \
230 #define EXTINTR_SANITY()
233 const char * const intr_typename_strings
[NIST
] = {
241 u_int32_t gpp_intrtype_level_mask
= 0;
243 STATIC
void write_intr_mask(volatile imask_t
*);
244 STATIC
void intr_calculatemasks(void);
245 STATIC
int ext_intr_cause(volatile imask_t
*, volatile imask_t
*,
247 STATIC
int cause_irq(const imask_t
*, const imask_t
*);
250 imask_print(char *str
, volatile imask_t
*imp
)
252 DPRINTF(("%s: %#10x %#10x %#10x %#10x\n",
254 imp
->bits
[IMASK_ICU_LO
],
255 imp
->bits
[IMASK_ICU_HI
],
256 imp
->bits
[IMASK_ICU_GPP
],
257 imp
->bits
[IMASK_SOFTINT
]));
261 * initialize interrupt subsystem
267 intr_calculatemasks();
268 EXT_INTR_STATS_INIT();
273 intr_typename(int type
)
277 return intr_typename_strings
[type
];
281 * intr_establish - register an interrupt handler.
288 int (*ih_fun
)(void *),
291 struct intrsource
*is
= &intr_sources
[irq
];
292 struct intrhand
**p
, *ih
;
295 if (ILLEGAL_IRQ(irq
)) {
296 DIAGPRF(("intr_establish: illegal irq 0x%x", irq
));
299 if (level
<= IPL_NONE
|| level
>= IPL_HIGH
) {
300 DIAGPRF(("intr_establish: illegal level %d\n", level
));
303 if (type
<= IST_NONE
|| type
>= NIST
) {
304 DIAGPRF(("intr_establish: illegal type 0x%x", type
));
307 if (((irq
>= SIR_BASE
) && (type
!= IST_SOFT
))
308 || ((irq
< SIR_BASE
) && (type
== IST_SOFT
))) {
309 DIAGPRF(("intr_establish: irq %d out of range for type %s\n",
310 irq
, intr_typename_strings
[type
]));
313 if (is
->is_type
!= IST_NONE
&& is
->is_type
!= type
) {
314 DIAGPRF(("intr_establish: irq %d: can't share %s with %s",
315 irq
, intr_typename_strings
[is
->is_type
],
316 intr_typename_strings
[type
]));
319 if (is
->is_level
!= IPL_NONE
&& is
->is_level
!= level
) {
320 DIAGPRF(("intr_establish: irq %d conflicting levels %d, %d\n",
321 irq
, is
->is_level
, level
));
325 ih
= malloc(sizeof *ih
, M_DEVBUF
, cold
? M_NOWAIT
: M_WAITOK
);
327 DIAGPRF(("intr_establish: can't malloc handler info"));
331 omsr
= extintr_disable();
333 if (is
->is_hand
== NULL
) {
334 is
->is_evcnt
.ev_count
= 0;
335 evcnt_attach_dynamic(&is
->is_evcnt
, EVCNT_TYPE_INTR
,
336 NULL
, "discovery", intr_source_strings
[irq
]);
340 is
->is_level
= level
;
342 if ((IRQ_IS_GPP(irq
)) && type
== IST_LEVEL
)
343 gpp_intrtype_level_mask
|= (1 << (irq
- IRQ_GPP_BASE
));
345 for (p
= &is
->is_hand
; *p
!= NULL
; p
= &(*p
)->ih_next
)
349 ih
->ih_level
= level
;
353 if (irq
>= SIR_BASE
) {
355 ih
->ih_softimask
= SIBIT(irq
);
357 ih
->ih_flags
= IH_ACTIVE
;
358 ih
->ih_softimask
= 0;
362 intr_calculatemasks();
364 extintr_restore(omsr
);
370 * intr_disestablish - deregister an interrupt handler.
373 intr_disestablish(void *arg
)
375 struct intrhand
*ih
= arg
;
376 struct intrsource
*is
= ih
->ih_source
;
377 int irq
= is
- intr_sources
;
381 if (ILLEGAL_IRQ(irq
))
382 panic("intr_disestablish: bogus irq %d", irq
);
385 * Remove the handler from the chain.
386 * This is O(n^2), too.
388 omsr
= extintr_disable();
389 for (p
= &is
->is_hand
; *p
!= NULL
&& (*p
) != ih
; p
= &(*p
)->ih_next
)
394 panic("intr_disestablish: handler not registered");
395 free((void *)ih
, M_DEVBUF
);
397 intr_calculatemasks();
399 if (is
->is_hand
== NULL
) {
400 evcnt_detach(&is
->is_evcnt
);
401 if ((IRQ_IS_GPP(irq
)) && (is
->is_type
== IST_LEVEL
))
402 gpp_intrtype_level_mask
&= ~(1 << (irq
- IRQ_GPP_BASE
));
403 is
->is_level
= IPL_NONE
;
404 is
->is_type
= IST_NONE
;
406 extintr_restore(omsr
);
412 return intr_source_strings
[irq
];
418 return &intr_sources
[irq
].is_evcnt
;
422 * write_intr_mask - update GT-64260 ICU Mask registers
424 * - IRQs already pending are always disabled
425 * - ICU summary bits are always enabled
427 * always called with interrupts disabled
430 write_intr_mask(volatile imask_t
*imp
)
436 imask_andnot_icu_vv(imp
, &ipending
);
438 lo
= imp
->bits
[IMASK_ICU_LO
];
439 hi
= imp
->bits
[IMASK_ICU_HI
];
440 gpp
= imp
->bits
[IMASK_ICU_GPP
];
445 bus_space_write_4(>_mem_bs_tag
, gt_memh
, ICR_CIM_LO
, lo
);
446 bus_space_write_4(>_mem_bs_tag
, gt_memh
, ICR_CIM_HI
, hi
);
447 bus_space_write_4(>_mem_bs_tag
, gt_memh
, GT_GPP_Interrupt_Mask
, gpp
);
448 (void)bus_space_read_4(>_mem_bs_tag
, gt_memh
,
449 GT_GPP_Interrupt_Mask
); /* R.A.W. */
453 * intr_calculatemasks - generate dispatch tables based on established IRQs
455 * enforces uniform level and intrtype for all handlers of shared IRQ
456 * in case of conflict simply create a new IPL
458 * always called with interrupts disabled
461 intr_calculatemasks(void)
465 struct intrsource
*is
;
468 * level to use for each IRQ is defined by first to claim it
469 * if the IRQ is shared, level cannot vary
471 for (irq
= 0, is
= intr_sources
; irq
< NIRQ
; irq
++, is
++) {
472 for (q
= is
->is_hand
; q
; q
= q
->ih_next
)
473 if (q
->ih_level
!= is
->is_level
)
474 panic("intr_calculatemasks: irq %d "
475 "conflicting levels %d, %d\n",
476 irq
, q
->ih_level
, is
->is_level
);
480 * imask[] indicates IRQs enabled at each level.
482 for (level
= 0; level
< NIPL
; level
++) {
483 imask_t
*imp
= &imask
[level
];
485 for (irq
= 0, is
= intr_sources
; irq
< NIRQ
; irq
++, is
++) {
486 if (level
< is
->is_level
) {
487 imask_orbit(imp
, irq
);
492 /* enable IRQs with handlers */
494 for (irq
= 0, is
= intr_sources
; irq
< NIRQ
; irq
++, is
++) {
496 imask_orbit_v(&imen
, irq
);
501 * enable all live interrupts
503 write_intr_mask(&imen
);
507 * ext_intr_cause - collect, ack (GPP), pend and mask ICU causes
509 * set (OR-in) current ICU causes in impendp
511 * read GT-64260 Main Interrupt Cause and
512 * GPP Interrupt Cause and Value registers
514 * always called with interrupts disabled
518 volatile imask_t
*impendp
,
519 volatile imask_t
*imenp
,
520 const imask_t
*imresp
)
527 lo
= bus_space_read_4(>_mem_bs_tag
, gt_memh
, ICR_MIC_LO
);
528 lo
&= ~(imresp
->bits
[IMASK_ICU_LO
] | impendp
->bits
[IMASK_ICU_LO
]);
529 imenp
->bits
[IMASK_ICU_LO
] &= ~lo
;
531 hi
= bus_space_read_4(>_mem_bs_tag
, gt_memh
, ICR_MIC_HI
);
533 if (hi
& IMH_GPP_SUM
) {
534 gpp
= bus_space_read_4(>_mem_bs_tag
, gt_memh
, GT_GPP_Interrupt_Cause
);
535 gpp
&= ~imresp
->bits
[IMASK_ICU_GPP
];
536 bus_space_write_4(>_mem_bs_tag
, gt_memh
, GT_GPP_Interrupt_Cause
, ~gpp
);
539 gpp_v
= bus_space_read_4(>_mem_bs_tag
, gt_memh
, GT_GPP_Value
);
540 KASSERT((gpp_intrtype_level_mask
& imresp
->bits
[IMASK_ICU_GPP
]) == 0);
541 gpp_v
&= (gpp_intrtype_level_mask
& imenp
->bits
[IMASK_ICU_GPP
]);
544 gpp
&= ~impendp
->bits
[IMASK_ICU_GPP
];
545 imenp
->bits
[IMASK_ICU_GPP
] &= ~gpp
;
547 hi
&= ~(imresp
->bits
[IMASK_ICU_HI
] | impendp
->bits
[IMASK_ICU_HI
]);
548 imenp
->bits
[IMASK_ICU_HI
] &= ~hi
;
550 write_intr_mask(imenp
);
552 EXT_INTR_STATS_CAUSE(lo
, hi
, gpp
, 0);
554 if ((lo
| hi
| gpp
) == 0) {
555 return 0; /* nothing left */
559 * post pending IRQs in caller's imask
561 impendp
->bits
[IMASK_ICU_LO
] |= lo
;
562 impendp
->bits
[IMASK_ICU_HI
] |= hi
;
563 impendp
->bits
[IMASK_ICU_GPP
] |= gpp
;
564 EXT_INTR_STATS_PEND(lo
, hi
, gpp
, 0);
570 * cause_irq - find a qualified irq
572 * `cause' indicates pending interrupt causes
573 * `mask' indicates what interrupts are enabled
575 * dispatch order is: lo, hi, gpp, soft
577 * return -1 if no qualified interrupts are pending.
580 cause_irq(const imask_t
*cause
, const imask_t
*mask
)
582 u_int32_t clo
= cause
->bits
[IMASK_ICU_LO
];
583 u_int32_t chi
= cause
->bits
[IMASK_ICU_HI
];
584 u_int32_t cgpp
= cause
->bits
[IMASK_ICU_GPP
];
585 u_int32_t csft
= cause
->bits
[IMASK_SOFTINT
];
586 u_int32_t mlo
= mask
->bits
[IMASK_ICU_LO
];
587 u_int32_t mhi
= mask
->bits
[IMASK_ICU_HI
];
588 u_int32_t mgpp
= mask
->bits
[IMASK_ICU_GPP
];
589 u_int32_t msft
= mask
->bits
[IMASK_SOFTINT
];
596 if ((clo
| chi
| cgpp
| csft
) == 0)
598 if ((irq
= 31 - cntlzw(clo
)) >= 0)
600 if ((irq
= 31 - cntlzw(chi
)) >= 0)
602 if ((irq
= 31 - cntlzw(cgpp
)) >= 0)
603 return irq
+ IRQ_GPP_BASE
;
604 if ((irq
= 31 - cntlzw(csft
)) >= 0)
605 return (irq
+ SIR_BASE
);
610 * ext_intr - external interrupt service routine
612 * collect and post filtered causes, then have a go at dispatch
613 * always called (from locore.S) with interrupts disabled
616 ext_intr(struct intrframe
*frame
)
618 struct cpu_info
* const ci
= curcpu();
620 struct intrframe
*oframe
;
623 #ifdef __HAVE_FAST_SOFTINTS
624 #error don't count soft interrupts here
628 EXT_INTR_STATS_DECL(tstart);
629 EXT_INTR_STATS_DEPTH();
632 if (extintr_disable() & PSL_EE)
633 panic("ext_intr: PSL_EE");
639 if (ext_intr_cause(&ipending, &imen, &imres) == 0) {
640 DIAGPRF(("ext_intr: stray interrupt\n"));
642 DPRINTF(("cpl %d\n", ci->ci_cpl));
643 imask_print("imask[cpl]", (volatile imask_t *)&imask[ci->ci_cpl]);
644 imask_print("ipending ", &ipending);
645 imask_print("imen ", &imen);
650 } while (ext_intr_cause(&ipending, &imen, &imres) != 0);
660 * intr_dispatch - process pending and soft interrupts
662 * always called with interrupts disabled
663 * pending interrupts must be masked off in ICU
668 struct cpu_info * const ci = curcpu();
675 EXT_INTR_STATS_DECL(tstart);
677 KASSERT((extintr_disable() & PSL_EE) == 0);
678 KASSERT(ci->ci_cpl < IPL_HIGH);
679 KASSERT(ci->ci_cpl >= IPL_NONE);
681 if (ci->ci_cpl >= IPL_HIGH)
686 * process pending irpts that are not masked at ocpl and above
687 * copy and clear these from ipending while irpts are disabled
690 imask_dup_v(&imdisp, &ipending);
691 imask_and(&imdisp, &imask[ocpl]);
693 imdisp.bits[IMASK_SOFTINT] &= imen.bits[IMASK_SOFTINT];
694 imen.bits[IMASK_SOFTINT] &= ~imdisp.bits[IMASK_SOFTINT];
696 if (imask_empty(&imdisp)) {
698 SPL_STATS_LOG(ocpl, 0);
702 imask_andnot_v(&ipending, &imdisp);
703 EXT_INTR_STATS_COMMIT_M(&imdisp);
705 imp = &imask[IPL_HIGH-1];
706 for (ipl=IPL_HIGH; ipl > ocpl; ipl--) {
708 SPL_STATS_LOG(ipl, 0);
709 while ((irq = cause_irq(&imdisp, imp)) >= 0) {
710 struct intrsource *is = &intr_sources[irq];
712 if (imask_andbit_v(&imen, irq) != 0)
713 panic("intr_dispatch(a): irq %d enabled", irq);
715 is->is_evcnt.ev_count++;
716 EXT_INTR_STATS_PRE(irq, tstart);
717 for (ih = is->is_hand; ih != NULL; ih = ih->ih_next) {
718 if (ih->ih_flags & IH_ACTIVE) {
722 ih->ih_flags &= ~IH_ACTIVE;
723 (void)extintr_enable();
724 rv = (*ih->ih_fun)(ih->ih_arg);
725 (void)extintr_disable();
730 KASSERT(ci->ci_cpl == ipl);
732 EXT_INTR_STATS_POST(irq, tstart);
736 if (imask_andbit_v(&imen, irq) != 0)
737 panic("intr_dispatch(b): irq %d enabled", irq);
739 imask_clrbit(&imdisp, irq);
740 imask_orbit_v(&imen, irq);
743 write_intr_mask(&imen);
746 if (imask_empty(&imdisp))
753 #ifdef EXT_INTR_STATS
755 * ISR counts, pended, prempted, timing stats
758 int intr_depth_max = 0;
759 int ext_intr_stats_enb = 1;
760 ext_intr_stat_t ext_intr_stats[NIRQ] = {{0},};
761 ext_intr_stat_t *ext_intr_statp = 0;
763 #define EXT_INTR_STAT_HISTSZ 4096
764 ext_intr_hist_t ext_intr_hist[NIRQ][EXT_INTR_STAT_HISTSZ];
766 static inline u_int64_t
772 __asm volatile ("1: mftbu %0; mftb %0+1; mftbu %1; cmpw 0,%0,%1; bne 1b"
773 : "=r"(tb), "=r"(scratch));
778 _ext_intr_stats_cause(u_int64_t tcause, u_int32_t cause, u_int32_t irqbase)
783 ext_intr_stat_t *statp;
784 ext_intr_hist_t *histp;
788 while ((irq = 31 - cntlzw(cause)) >= 0) {
791 statp = &ext_intr_stats[irq + irqbase];
794 if (ix >= EXT_INTR_STAT_HISTSZ)
797 histp = &statp->histp[ix];
798 memset(histp, 0, sizeof(ext_intr_hist_t));
799 histp->tcause = tcause;
805 ext_intr_stats_cause(u_int32_t lo, u_int32_t hi, u_int32_t gpp, u_int32_t soft)
811 _ext_intr_stats_cause(tcause, lo, 0);
812 _ext_intr_stats_cause(tcause, hi, 32);
813 _ext_intr_stats_cause(tcause, gpp, IRQ_GPP_BASE);
814 _ext_intr_stats_cause(tcause, soft, SIR_BASE);
818 _ext_intr_stats_pend(u_int64_t tpend, u_int32_t cause, u_int32_t irqbase)
822 ext_intr_stat_t *statp;
823 ext_intr_hist_t *histp;
827 while ((irq = 31 - cntlzw(cause)) >= 0) {
830 EXT_INTR_STATS_PEND_IRQ(irq);
836 ext_intr_stats_pend(u_int32_t lo, u_int32_t hi, u_int32_t gpp, u_int32_t soft)
839 ext_intr_stat_t *statp;
840 ext_intr_hist_t *histp;
846 _ext_intr_stats_pend(tpend, lo, 0);
847 _ext_intr_stats_pend(tpend, hi, 32);
848 _ext_intr_stats_pend(tpend, gpp, IRQ_GPP_BASE);
849 _ext_intr_stats_pend(tpend, soft, SIR_BASE);
853 _ext_intr_stats_commit(u_int64_t tcommit, u_int32_t cause, u_int32_t irqbase)
857 ext_intr_stat_t *statp;
858 ext_intr_hist_t *histp;
862 while ((irq = 31 - cntlzw(cause)) >= 0) {
865 statp = &ext_intr_stats[irq + irqbase];
866 histp = &statp->histp[statp->histix];
867 histp->tcommit = tcommit;
873 ext_intr_stats_commit_m(imask_t *imp)
876 ext_intr_stat_t *statp;
877 ext_intr_hist_t *histp;
883 _ext_intr_stats_commit(tcommit, (*imp)[IMASK_ICU_LO], 0);
884 _ext_intr_stats_commit(tcommit, (*imp)[IMASK_ICU_HI], 32);
885 _ext_intr_stats_commit(tcommit, (*imp)[IMASK_ICU_GPP], IRQ_GPP_BASE);
886 _ext_intr_stats_commit(tcommit, (*imp)[IMASK_SOFTINT], SIR_BASE);
890 ext_intr_stats_commit_irq(u_int irq)
893 ext_intr_stat_t *statp;
894 ext_intr_hist_t *histp;
899 _ext_intr_stats_commit(tcommit, irq & (32-1), irq & ~(32-1));
903 ext_intr_stats_pre(int irq)
905 ext_intr_stat_t *statp;
907 statp = &ext_intr_stats[irq];
909 if (statp == ext_intr_statp)
910 panic("ext_intr_stats_pre: statp == ext_intr_statp");
912 statp->save = ext_intr_statp;
914 ext_intr_statp = statp;
919 ext_intr_stats_post(int irq, u_int64_t tstart)
923 ext_intr_stat_t *statp=NULL;
924 ext_intr_hist_t *histp=NULL;
928 if (ext_intr_stats_enb <= 0) {
929 if (ext_intr_stats_enb == -1)
930 ext_intr_stats_enb = 1;
931 ext_intr_statp = statp->save;
936 statp = &ext_intr_stats[irq];
937 histp = &statp->histp[statp->histix];
938 histp->tstart = tstart;
947 panic("ext_intr_stats_post: statp == sp");
949 sp->preempted[irq]++;
952 dt -= statp->borrowed;
956 if ((dt < statp->min) || (statp->min == 0))
958 if ((dt > statp->max) || (statp->max == 0))
965 ext_intr_stats_print(void)
968 ext_intr_stat_t *statp;
973 struct intrsource *is;
975 printf("intr_depth_max %d\n", intr_depth_max);
976 statp = ext_intr_stats;
977 for (irq = 0, is = intr_sources; irq < NIRQ; irq++, is++) {
982 avg = statp->sum / statp->cnt;
983 level = is->is_level;
984 printf("irq %d ", irq);
985 printf("lvl %d ", level);
986 printf("cnt %lld ", statp->cnt);
987 printf("avg %lld ", avg);
988 printf("min %lld ", statp->min);
989 printf("max %lld ", statp->max);
990 printf("pnd %lld\n", statp->pnd);
992 for (i=0; i < NIRQ; i++) {
993 if (statp->preempted[i]) {
996 printf("preemption: ");
998 printf("%d:%ld, ", i,
999 statp->preempted[i]);
1008 printf("%p, ", ih->ih_fun);
1019 ext_intr_hist_prsubr(int irq)
1022 ext_intr_stat_t *statp;
1023 ext_intr_hist_t *histp;
1024 struct intrhand *ih;
1028 ih = intr_sources[irq].is_hand;
1029 statp = &ext_intr_stats[irq];
1030 histp = statp->histp;
1032 cnt = (statp->cnt < EXT_INTR_STAT_HISTSZ) ?
1033 statp->cnt : EXT_INTR_STAT_HISTSZ;
1034 printf("irq %d: %d samples:\n", irq, cnt);
1036 printf("%llu %llu %llu %llu\n",
1037 histp->tcause, histp->tcommit,
1038 histp->tstart, histp->tfin);
1045 ext_intr_hist_print(u_int32_t lo, u_int32_t hi, u_int32_t gpp, u_int32_t soft)
1051 omsr = extintr_disable();
1053 while ((irq = 31 - cntlzw(lo)) >= 0) {
1056 ext_intr_hist_prsubr(irq);
1059 while ((irq = 31 - cntlzw(hi)) >= 0) {
1062 ext_intr_hist_prsubr(irq + 32);
1065 while ((irq = 31 - cntlzw(gpp)) >= 0) {
1068 ext_intr_hist_prsubr(irq + IRQ_GPP_BASE);
1071 while ((irq = 31 - cntlzw(soft)) >= 0) {
1074 ext_intr_hist_prsubr(irq + SIR_BASE);
1077 extintr_restore(omsr);
1081 ext_intr_stats_init(void)
1085 memset(ext_intr_stats, 0, sizeof(ext_intr_stats));
1086 memset(ext_intr_hist, 0, sizeof(ext_intr_hist));
1087 for (irq=0; irq < NIRQ; irq++) {
1088 ext_intr_stats[irq].histp = &ext_intr_hist[irq][0];
1089 ext_intr_stats[irq].histix = EXT_INTR_STAT_HISTSZ-1;
1092 #endif /* EXT_INTR_STATS */
1095 #define SPL_STATS_HISTSZ EXT_INTR_STAT_HISTSZ
1096 spl_hist_t spl_stats_hist[SPL_STATS_HISTSZ];
1097 unsigned int spl_stats_histix = 0;
1098 unsigned int spl_stats_enb = 1;
1102 spl_stats_init(void)
1104 spl_stats_histix = 0;
1108 spl_stats_log(int ipl, int cc)
1110 unsigned int ix = spl_stats_histix;
1115 if (spl_stats_enb == 0)
1117 histp = &spl_stats_hist[ix];
1120 /* log our calling address */
1121 __asm volatile ("mflr %0;" : "=r"(pc));
1124 /* log our caller's calling address */
1125 __asm
volatile ("mr %0,1;" : "=r"(fp
));
1126 fp
= (register_t
*)*fp
;
1127 pc
= (register_t
*)(fp
[1] - sizeof(register_t
));
1131 histp
->addr
= (void *)pc
;
1132 histp
->time
= _mftb();
1133 if (++ix
>= SPL_STATS_HISTSZ
)
1135 spl_stats_histix
= ix
;
1139 spl_stats_print(void)
1144 printf("spl stats:\n");
1145 histp
= &spl_stats_hist
[0];
1146 for (i
=SPL_STATS_HISTSZ
; --i
; ) {
1147 printf("%llu %d %p\n", histp
->time
, histp
->level
, histp
->addr
);
1152 #endif /* SPL_STATS */
1158 struct cpu_info
* const ci
= curcpu();
1162 omsr
= extintr_disable();
1164 if (ncpl
> ci
->ci_cpl
) {
1165 SPL_STATS_LOG(ncpl
, 1);
1167 if ((ncpl
== IPL_HIGH
) && ((omsr
& PSL_EE
) != 0)) {
1168 /* leave external interrupts disabled */
1169 return (ocpl
| IPL_EE
);
1172 extintr_restore(omsr
);
1179 struct cpu_info
* const ci
= curcpu();
1182 int ncpl
= xcpl
& IPL_PRIMASK
;
1184 int ocpl
= ci
->ci_cpl
;
1187 omsr
= extintr_disable();
1188 if (ci
->ci_cpl
< ncpl
) {
1189 printf("ci->ci_cpl = %d, ncpl = %d\n", ci
->ci_cpl
, ncpl
);
1191 KASSERT(ncpl
<= ci
->ci_cpl
);
1192 if (ncpl
< ci
->ci_cpl
) {
1194 ncplp
= &imask
[ncpl
];
1195 SPL_STATS_LOG(ncpl
, 1);
1196 if (imask_test_v(&ipending
, ncplp
))
1199 if (xcpl
& IPL_EE
) {
1200 KASSERT(ocpl
== IPL_HIGH
);
1201 KASSERT((omsr
& PSL_EE
) == 0);
1204 extintr_restore(omsr
);
1210 struct cpu_info
* const ci
= curcpu();
1215 ncpl
&= IPL_PRIMASK
;
1216 ncplp
= &imask
[ncpl
];
1218 omsr
= extintr_disable();
1221 SPL_STATS_LOG(ncpl
, 1);
1222 #ifdef EXT_INTR_STATS
1225 if (imask_test_v(&ipending
, ncplp
))
1228 if (ncpl
< IPL_HIGH
)
1230 extintr_restore(omsr
);