env.sh: use --dirty in git describe
[unleashed.git] / usr / src / cmd / mdb / i86pc / modules / common / intr_common.c
blob86c24040fa8ea5eafcbfa0dcb15f2cfa934b8ac6
1 /*
2 * CDDL HEADER START
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]
19 * CDDL HEADER END
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>
28 #include <sys/gld.h>
29 #include <sys/gldpriv.h>
31 int option_flags;
32 uintptr_t gld_intr_addr;
33 int apic_pir_vect;
34 static struct av_head softvec_tbl[LOCK_LEVEL + 1];
36 static char *businfo_array[] = {
37 " ",
38 "CBUS",
39 "CBUSII",
40 "EISA",
41 "FUTURE",
42 "INTERN",
43 "ISA",
44 "MBI",
45 "MBII",
46 "PCIe",
47 "MPI",
48 "MPSA",
49 "NUBUS",
50 "PCI",
51 "PCMCIA",
52 "TC",
53 "VL",
54 "VME",
55 "XPRESS",
56 " "
59 void
60 interrupt_help(void)
62 mdb_printf("Prints the interrupt usage on the system.\n"
63 "By default, only interrupt service routine names are printed.\n\n"
64 "Switches:\n"
65 " -d instead of ISR, print <driver_name><instance#>\n"
66 " -i show like intrstat, cpu# ISR/<driver_name><instance#>\n");
69 void
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"
74 "Switch:\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 */
84 } av_softinfo_t;
86 /* ARGSUSED */
87 int
88 soft_interrupt_dump(uintptr_t addr, uint_t flags, int argc,
89 const mdb_arg_t *argv)
91 int i;
92 av_softinfo_t avsoftinfo;
93 struct autovec avhp;
94 ddi_softint_hdl_impl_t hdlp;
96 option_flags = 0;
97 if (mdb_getopts(argc, argv, 'd', MDB_OPT_SETBITS,
98 INTR_DISPLAY_DRVR_INST, &option_flags, NULL) != argc)
99 return (DCMD_USAGE);
101 if (mdb_readvar(&softvec_tbl, "softvect") == -1) {
102 mdb_warn("failed to read autovect");
103 return (DCMD_ERR);
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)
115 continue;
117 do {
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))
123 continue;
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);
132 mdb_printf("\n");
133 } while (mdb_vread(&avhp, sizeof (struct autovec),
134 (uintptr_t)avhp.av_link) != -1);
137 return (DCMD_OK);
140 void
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);
166 } else {
167 mdb_printf("%a", isr_addr);
170 } else {
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
183 static char *
184 get_interrupt_type(short index)
186 if (index == RESERVE_INDEX)
187 return ("IPI");
188 else if (index == ACPI_INDEX)
189 return ("Fixed");
190 else if (index == MSI_INDEX)
191 return ("MSI");
192 else if (index == MSIX_INDEX)
193 return ("MSI-X");
194 else
195 return ("Fixed");
198 static char *
199 get_apix_interrupt_type(short type)
201 if (type == APIX_TYPE_IPI)
202 return ("IPI");
203 else if (type == APIX_TYPE_FIXED)
204 return ("Fixed");
205 else if (type == APIX_TYPE_MSI)
206 return ("MSI");
207 else if (type == APIX_TYPE_MSIX)
208 return ("MSI-X");
209 else
210 return ("Fixed");
213 void
214 apic_interrupt_dump(apic_irq_t *irqp, struct av_head *avp,
215 int i, ushort_t *evtchnp, char level)
217 int bus_type;
218 int j;
219 char *intr_type;
220 char ioapic_iline[10];
221 char ipl[3];
222 char cpu_assigned[4];
223 char evtchn[8];
224 uint32_t assigned_cpu;
225 struct autovec avhp;
227 /* If invalid index; continue */
228 if (!irqp->airq_mps_intr_index ||
229 irqp->airq_mps_intr_index == FREE_INDEX)
230 return;
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, "- ");
238 else {
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, "- ");
246 else
247 (void) mdb_snprintf(ioapic_iline, 10, " ");
248 } else
249 (void) mdb_snprintf(ioapic_iline, 10, "0x%x/0x%x",
250 irqp->airq_ioapicindex, irqp->airq_intin_no);
253 evtchn[0] = '\0';
254 if (evtchnp != NULL)
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);
265 } else {
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);
273 else
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) {
296 mdb_printf(", ");
297 interrupt_print_isr((uintptr_t)avhp.av_vector,
298 (uintptr_t)avhp.av_intarg1,
299 (uintptr_t)avhp.av_dip);
300 } else {
301 break;
305 } else {
306 if (irqp->airq_mps_intr_index == RESERVE_INDEX &&
307 !irqp->airq_share) {
308 if (irqp->airq_vector == apic_pir_vect) {
309 mdb_printf("pir_ipi");
310 } else {
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);
318 mdb_printf("\n");
321 void
322 apix_interrupt_dump(apix_vector_t *vectp, apic_irq_t *irqp,
323 struct autovec *avp, ushort_t *evtchnp, char level)
325 int j;
326 int bus_type;
327 char *intr_type;
328 char irq[4];
329 char ioapic_iline[10];
330 char ipl[3];
331 char cpu_assigned[4];
332 char cpu_vector[10];
333 char evtchn[8];
336 /* If invalid vector state; continue */
337 if (vectp->v_state == APIX_STATE_FREED ||
338 vectp->v_state == APIX_STATE_OBSOLETED)
339 return;
341 /* use apic_interrupt_ipi_dump for IPIs */
342 if (vectp->v_type == APIX_TYPE_IPI)
343 return;
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;
355 else
356 /* statically assign MSI/X with "PCI" */
357 bus_type = BUSTYPE_PCI;
358 } else {
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);
366 else
367 (void) mdb_snprintf(ioapic_iline, 10, "- ");
368 } else
369 (void) mdb_snprintf(ioapic_iline, 10, "0x%x/0x%x",
370 irqp->airq_ioapicindex, irqp->airq_intin_no);
373 evtchn[0] = '\0';
374 if (evtchnp != NULL)
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)
387 break;
388 else
389 continue;
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);
396 else
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);
405 mdb_printf("\n");
407 if (++j == vectp->v_share)
408 break; /* done */
410 if (mdb_vread(avp, sizeof (struct autovec),
411 (uintptr_t)avp->av_link) == -1)
412 break;
416 void
417 apix_interrupt_ipi_dump(apix_vector_t *vectp, struct autovec *avp,
418 ushort_t *evtchnp)
420 char *intr_type = "IPI";
421 char ioapic_iline[10];
422 char ipl[3];
423 char cpu_assigned[4];
424 char cpu_vector[10];
425 char evtchn[8];
427 /* If invalid vector state; continue */
428 if (vectp->v_state == APIX_STATE_FREED ||
429 vectp->v_state == APIX_STATE_OBSOLETED)
430 return;
432 if (vectp->v_type != APIX_TYPE_IPI)
433 return;
435 /* No IOAPIC number and ILINE number info */
436 (void) mdb_snprintf(ioapic_iline, 10, "- ");
438 evtchn[0] = '\0';
439 if (evtchnp != NULL)
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);
452 else
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");
459 } else {
460 mdb_printf("poke_cpu");
462 } else {
463 mdb_printf("%a", avp->av_vector);
466 mdb_printf("\n");