4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright 2018 Joyent, Inc.
26 #include "intr_common.h"
27 #include <sys/multidata.h>
29 #include <sys/gldpriv.h>
32 uintptr_t gld_intr_addr
;
34 static struct av_head softvec_tbl
[LOCK_LEVEL
+ 1];
36 static char *businfo_array
[] = {
62 mdb_printf("Prints the interrupt usage on the system.\n"
63 "By default, only interrupt service routine names are printed.\n\n"
65 " -d instead of ISR, print <driver_name><instance#>\n"
66 " -i show like intrstat, cpu# ISR/<driver_name><instance#>\n");
70 soft_interrupt_help(void)
72 mdb_printf("Prints the soft interrupt usage on the system.\n"
73 "By default, only interrupt service routine names are printed.\n\n"
75 " -d instead of ISR, print <driver_name><instance#>\n");
79 * This is copied from avintr.c
80 * NOTE: Ensure that this definition stays in sync
82 typedef struct av_softinfo
{
83 cpuset_t av_pending
; /* pending bitmasks */
88 soft_interrupt_dump(uintptr_t addr
, uint_t flags
, int argc
,
89 const mdb_arg_t
*argv
)
92 av_softinfo_t avsoftinfo
;
94 ddi_softint_hdl_impl_t hdlp
;
97 if (mdb_getopts(argc
, argv
, 'd', MDB_OPT_SETBITS
,
98 INTR_DISPLAY_DRVR_INST
, &option_flags
, NULL
) != argc
)
101 if (mdb_readvar(&softvec_tbl
, "softvect") == -1) {
102 mdb_warn("failed to read autovect");
106 /* Print the header first */
107 mdb_printf("%<u>ADDR PEND PIL ARG1 "
108 "ARG2 ISR(s)%</u>\n");
110 /* Walk all the entries */
111 for (i
= 0; i
< LOCK_LEVEL
+ 1; i
++) {
112 /* Read the entry, if invalid continue */
113 if (mdb_vread(&avhp
, sizeof (struct autovec
),
114 (uintptr_t)softvec_tbl
[i
].avh_link
) == -1)
118 if (!avhp
.av_vector
||
119 (mdb_vread(&hdlp
, sizeof (ddi_softint_hdl_impl_t
),
120 (uintptr_t)avhp
.av_intr_id
) == -1) ||
121 (mdb_vread(&avsoftinfo
, sizeof (av_softinfo_t
),
122 (uintptr_t)hdlp
.ih_pending
) == -1))
125 /* Print each soft interrupt entry */
126 mdb_printf("%-16p %-2d %-2d %-16p %-16p",
127 avhp
.av_intr_id
, mdb_cpuset_find(
128 (uintptr_t)&avsoftinfo
.av_pending
) != -1 ? 1 : 0,
129 avhp
.av_prilevel
, avhp
.av_intarg1
, avhp
.av_intarg2
);
130 interrupt_print_isr((uintptr_t)avhp
.av_vector
,
131 (uintptr_t)avhp
.av_intarg1
, (uintptr_t)hdlp
.ih_dip
);
133 } while (mdb_vread(&avhp
, sizeof (struct autovec
),
134 (uintptr_t)avhp
.av_link
) != -1);
141 interrupt_print_isr(uintptr_t vector
, uintptr_t arg1
, uintptr_t dip
)
143 uintptr_t isr_addr
= vector
;
144 struct dev_info dev_info
;
147 * figure out the real ISR function name from gld_intr()
149 if (isr_addr
== gld_intr_addr
) {
150 gld_mac_info_t macinfo
;
152 if (mdb_vread(&macinfo
, sizeof (gld_mac_info_t
), arg1
) != -1) {
153 /* verify gld data structure and get the real ISR */
154 if (macinfo
.gldm_GLD_version
== GLD_VERSION
)
155 isr_addr
= (uintptr_t)macinfo
.gldm_intr
;
159 if ((option_flags
& INTR_DISPLAY_DRVR_INST
) && dip
) {
160 char drvr_name
[MODMAXNAMELEN
+ 1];
162 if (dip
&& mdb_devinfo2driver(dip
, drvr_name
,
163 sizeof (drvr_name
)) == 0) {
164 (void) mdb_vread(&dev_info
, sizeof (dev_info
), dip
);
165 mdb_printf("%s#%d", drvr_name
, dev_info
.devi_instance
);
167 mdb_printf("%a", isr_addr
);
171 mdb_printf("%a", isr_addr
);
176 * get_interrupt_type:
178 * Get some interrupt related useful information
180 * NOTE: a0 is clock, c0/d0/e0 are x-calls, e1 is apic_error_intr
181 * d1/d3 are cbe_fire interrupts
184 get_interrupt_type(short index
)
186 if (index
== RESERVE_INDEX
)
188 else if (index
== ACPI_INDEX
)
190 else if (index
== MSI_INDEX
)
192 else if (index
== MSIX_INDEX
)
199 get_apix_interrupt_type(short type
)
201 if (type
== APIX_TYPE_IPI
)
203 else if (type
== APIX_TYPE_FIXED
)
205 else if (type
== APIX_TYPE_MSI
)
207 else if (type
== APIX_TYPE_MSIX
)
214 apic_interrupt_dump(apic_irq_t
*irqp
, struct av_head
*avp
,
215 int i
, ushort_t
*evtchnp
, char level
)
220 char ioapic_iline
[10];
222 char cpu_assigned
[4];
224 uint32_t assigned_cpu
;
227 /* If invalid index; continue */
228 if (!irqp
->airq_mps_intr_index
||
229 irqp
->airq_mps_intr_index
== FREE_INDEX
)
232 /* Figure out interrupt type and trigger information */
233 intr_type
= get_interrupt_type(irqp
->airq_mps_intr_index
);
235 /* Figure out IOAPIC number and ILINE number */
236 if (APIC_IS_MSI_OR_MSIX_INDEX(irqp
->airq_mps_intr_index
))
237 (void) mdb_snprintf(ioapic_iline
, 10, "- ");
239 if (!irqp
->airq_ioapicindex
&& !irqp
->airq_intin_no
) {
240 if (strcmp(intr_type
, "Fixed") == 0)
241 (void) mdb_snprintf(ioapic_iline
, 10,
242 "0x%x/0x%x", irqp
->airq_ioapicindex
,
243 irqp
->airq_intin_no
);
244 else if (irqp
->airq_mps_intr_index
== RESERVE_INDEX
)
245 (void) mdb_snprintf(ioapic_iline
, 10, "- ");
247 (void) mdb_snprintf(ioapic_iline
, 10, " ");
249 (void) mdb_snprintf(ioapic_iline
, 10, "0x%x/0x%x",
250 irqp
->airq_ioapicindex
, irqp
->airq_intin_no
);
255 (void) mdb_snprintf(evtchn
, 8, "%-7hd", *evtchnp
);
257 assigned_cpu
= irqp
->airq_temp_cpu
;
258 if (assigned_cpu
== IRQ_UNINIT
|| assigned_cpu
== IRQ_UNBOUND
)
259 assigned_cpu
= irqp
->airq_cpu
;
260 bus_type
= irqp
->airq_iflag
.bustype
;
262 if (irqp
->airq_mps_intr_index
== RESERVE_INDEX
) {
263 (void) mdb_snprintf(cpu_assigned
, 4, "all");
264 (void) mdb_snprintf(ipl
, 3, "%d", avp
->avh_hi_pri
);
266 (void) mdb_snprintf(cpu_assigned
, 4, "%d", assigned_cpu
);
267 (void) mdb_snprintf(ipl
, 3, "%d", irqp
->airq_ipl
);
270 /* Print each interrupt entry */
271 if (option_flags
& INTR_DISPLAY_INTRSTAT
)
272 mdb_printf("%-4s", cpu_assigned
);
274 mdb_printf("%-3d 0x%x %s%-3s %-6s %-3s %-6s %-4s%-3d %-9s ",
275 i
, irqp
->airq_vector
, evtchn
, ipl
,
276 (bus_type
? businfo_array
[bus_type
] : " "),
277 (level
? "Lvl" : "Edg"),
278 intr_type
, cpu_assigned
, irqp
->airq_share
, ioapic_iline
);
280 /* If valid dip found; print driver name */
281 if (irqp
->airq_dip
) {
282 (void) mdb_vread(&avhp
, sizeof (struct autovec
),
283 (uintptr_t)avp
->avh_link
);
286 * Loop thru all the shared IRQs
288 if (irqp
->airq_share
)
289 interrupt_print_isr((uintptr_t)avhp
.av_vector
,
290 (uintptr_t)avhp
.av_intarg1
, (uintptr_t)avhp
.av_dip
);
292 for (j
= 1; irqp
->airq_mps_intr_index
!= FREE_INDEX
&&
293 j
< irqp
->airq_share
; j
++) {
294 if (mdb_vread(&avhp
, sizeof (struct autovec
),
295 (uintptr_t)avhp
.av_link
) != -1) {
297 interrupt_print_isr((uintptr_t)avhp
.av_vector
,
298 (uintptr_t)avhp
.av_intarg1
,
299 (uintptr_t)avhp
.av_dip
);
306 if (irqp
->airq_mps_intr_index
== RESERVE_INDEX
&&
308 if (irqp
->airq_vector
== apic_pir_vect
) {
309 mdb_printf("pir_ipi");
311 mdb_printf("poke_cpu");
313 } else if (mdb_vread(&avhp
, sizeof (struct autovec
),
314 (uintptr_t)avp
->avh_link
) != -1) {
315 mdb_printf("%a", avhp
.av_vector
);
322 apix_interrupt_dump(apix_vector_t
*vectp
, apic_irq_t
*irqp
,
323 struct autovec
*avp
, ushort_t
*evtchnp
, char level
)
329 char ioapic_iline
[10];
331 char cpu_assigned
[4];
336 /* If invalid vector state; continue */
337 if (vectp
->v_state
== APIX_STATE_FREED
||
338 vectp
->v_state
== APIX_STATE_OBSOLETED
)
341 /* use apic_interrupt_ipi_dump for IPIs */
342 if (vectp
->v_type
== APIX_TYPE_IPI
)
345 /* Figure out interrupt type and trigger information */
346 intr_type
= get_apix_interrupt_type(vectp
->v_type
);
348 /* Figure out IOAPIC number and ILINE number */
349 if (vectp
->v_type
!= APIX_TYPE_FIXED
) {
350 level
= 0; /* MSI/MSI-X are Edge trigger */
351 (void) mdb_snprintf(irq
, 4, "- ");
352 (void) mdb_snprintf(ioapic_iline
, 10, "- ");
353 if (vectp
->v_type
== APIX_TYPE_IPI
)
354 bus_type
= BUSTYPE_NONE
;
356 /* statically assign MSI/X with "PCI" */
357 bus_type
= BUSTYPE_PCI
;
359 (void) mdb_snprintf(irq
, 4, "%d", vectp
->v_inum
);
360 bus_type
= irqp
->airq_iflag
.bustype
;
361 if (!irqp
->airq_ioapicindex
&& !irqp
->airq_intin_no
) {
362 if (strcmp(intr_type
, "Fixed") == 0)
363 (void) mdb_snprintf(ioapic_iline
, 10,
364 "0x%x/0x%x", irqp
->airq_ioapicindex
,
365 irqp
->airq_intin_no
);
367 (void) mdb_snprintf(ioapic_iline
, 10, "- ");
369 (void) mdb_snprintf(ioapic_iline
, 10, "0x%x/0x%x",
370 irqp
->airq_ioapicindex
, irqp
->airq_intin_no
);
375 (void) mdb_snprintf(evtchn
, 8, "%-7hd", *evtchnp
);
377 (void) mdb_snprintf(cpu_assigned
, 4, "%d", vectp
->v_cpuid
);
378 (void) mdb_snprintf(cpu_vector
, 10, "%d/0x%x",
379 vectp
->v_cpuid
, vectp
->v_vector
);
381 /* Loop all the shared vectors */
382 for (j
= 0; j
< vectp
->v_share
; ) {
383 /* shared interrupts with one or more ISR removed afterwards */
384 if (avp
->av_vector
== NULL
) {
385 if (mdb_vread(avp
, sizeof (struct autovec
),
386 (uintptr_t)avp
->av_link
) == -1)
392 (void) mdb_snprintf(ipl
, 3, "%d", avp
->av_prilevel
);
393 /* Print each interrupt entry */
394 if (option_flags
& INTR_DISPLAY_INTRSTAT
)
395 mdb_printf("%-4s", cpu_assigned
);
397 mdb_printf("%-9s %-3s %s%-3s %-6s %-3s %-6s %-3d "
398 "%-9s ", cpu_vector
, irq
, evtchn
, ipl
,
399 (bus_type
? businfo_array
[bus_type
] : "-"),
400 (level
? "Lvl" : "Edg"),
401 intr_type
, vectp
->v_share
, ioapic_iline
);
403 interrupt_print_isr((uintptr_t)avp
->av_vector
,
404 (uintptr_t)avp
->av_intarg1
, (uintptr_t)avp
->av_dip
);
407 if (++j
== vectp
->v_share
)
410 if (mdb_vread(avp
, sizeof (struct autovec
),
411 (uintptr_t)avp
->av_link
) == -1)
417 apix_interrupt_ipi_dump(apix_vector_t
*vectp
, struct autovec
*avp
,
420 char *intr_type
= "IPI";
421 char ioapic_iline
[10];
423 char cpu_assigned
[4];
427 /* If invalid vector state; continue */
428 if (vectp
->v_state
== APIX_STATE_FREED
||
429 vectp
->v_state
== APIX_STATE_OBSOLETED
)
432 if (vectp
->v_type
!= APIX_TYPE_IPI
)
435 /* No IOAPIC number and ILINE number info */
436 (void) mdb_snprintf(ioapic_iline
, 10, "- ");
440 (void) mdb_snprintf(evtchn
, 8, "%-7hd", *evtchnp
);
442 /* IPI targeted ALL cpus */
443 mdb_snprintf(cpu_assigned
, 4, "all");
444 (void) mdb_snprintf(cpu_vector
, 10, "%s/0x%x",
445 "all", vectp
->v_vector
);
446 /* IPI is not shared interrupt, so we can get the IPL from v_pri */
447 (void) mdb_snprintf(ipl
, 3, "%d", vectp
->v_pri
);
449 /* Print each interrupt entry */
450 if (option_flags
& INTR_DISPLAY_INTRSTAT
)
451 mdb_printf("%-4s", cpu_assigned
);
453 mdb_printf("%-9s %-3s %s%-3s %-6s %-3s %-6s %-3d %-9s ",
454 cpu_vector
, "- ", evtchn
, ipl
, "- ", "Edg",
455 intr_type
, vectp
->v_share
, ioapic_iline
);
456 if (!vectp
->v_share
) {
457 if (vectp
->v_vector
== apic_pir_vect
) {
458 mdb_printf("pir_ipi");
460 mdb_printf("poke_cpu");
463 mdb_printf("%a", avp
->av_vector
);