1 /*
2 * CDDL HEADER START
3 *
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.
7 *
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.
12 *
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]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
23 */
24
25 #include "intr_common.h"
26 #include <sys/multidata.h>
27 #include <sys/gld.h>
28 #include <sys/gldpriv.h>
29
30 int option_flags;
31 uintptr_t gld_intr_addr;
32 static struct av_head softvec_tbl[LOCK_LEVEL + 1];
33
34 static char *businfo_array[] = {
35 " ",
36 "CBUS",
37 "CBUSII",
38 "EISA",
39 "FUTURE",
40 "INTERN",
41 "ISA",
42 "MBI",
43 "MBII",
44 "PCIe",
45 "MPI",
46 "MPSA",
47 "NUBUS",
48 "PCI",
49 "PCMCIA",
50 "TC",
51 "VL",
52 "VME",
53 "XPRESS",
54 " "
55 };
56
57 void
interrupt_help(void)58 interrupt_help(void)
59 {
60 mdb_printf("Prints the interrupt usage on the system.\n"
61 "By default, only interrupt service routine names are printed.\n\n"
62 "Switches:\n"
63 " -d instead of ISR, print <driver_name><instance#>\n"
64 " -i show like intrstat, cpu# ISR/<driver_name><instance#>\n");
65 }
66
67 void
soft_interrupt_help(void)68 soft_interrupt_help(void)
69 {
70 mdb_printf("Prints the soft interrupt usage on the system.\n"
71 "By default, only interrupt service routine names are printed.\n\n"
72 "Switch:\n"
73 " -d instead of ISR, print <driver_name><instance#>\n");
74 }
75
76 /*
77 * This is copied from avintr.c
78 * NOTE: Ensure that this definition stays in sync
79 */
80 typedef struct av_softinfo {
81 cpuset_t av_pending; /* pending bitmasks */
82 } av_softinfo_t;
83
84 /* ARGSUSED */
85 int
soft_interrupt_dump(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)86 soft_interrupt_dump(uintptr_t addr, uint_t flags, int argc,
87 const mdb_arg_t *argv)
88 {
89 int i;
90 av_softinfo_t avsoftinfo;
91 struct autovec avhp;
92 ddi_softint_hdl_impl_t hdlp;
93
94 option_flags = 0;
95 if (mdb_getopts(argc, argv, 'd', MDB_OPT_SETBITS,
96 INTR_DISPLAY_DRVR_INST, &option_flags, NULL) != argc)
97 return (DCMD_USAGE);
98
99 if (mdb_readvar(&softvec_tbl, "softvect") == -1) {
100 mdb_warn("failed to read autovect");
101 return (DCMD_ERR);
102 }
103
104 /* Print the header first */
105 mdb_printf("%<u>ADDR PEND PIL ARG1 "
106 "ARG2 ISR(s)%</u>\n");
107
108 /* Walk all the entries */
109 for (i = 0; i < LOCK_LEVEL + 1; i++) {
110 /* Read the entry, if invalid continue */
111 if (mdb_vread(&avhp, sizeof (struct autovec),
112 (uintptr_t)softvec_tbl[i].avh_link) == -1)
113 continue;
114
115 do {
116 if (!avhp.av_vector ||
117 (mdb_vread(&hdlp, sizeof (ddi_softint_hdl_impl_t),
118 (uintptr_t)avhp.av_intr_id) == -1) ||
119 (mdb_vread(&avsoftinfo, sizeof (av_softinfo_t),
120 (uintptr_t)hdlp.ih_pending) == -1))
121 continue;
122
123 /* Print each soft interrupt entry */
124 mdb_printf("%-16p %-2d %-2d %-16p %-16p",
125 avhp.av_intr_id, mdb_cpuset_find(
126 (uintptr_t)&avsoftinfo.av_pending) != -1 ? 1 : 0,
127 avhp.av_prilevel, avhp.av_intarg1, avhp.av_intarg2);
128 interrupt_print_isr((uintptr_t)avhp.av_vector,
129 (uintptr_t)avhp.av_intarg1, (uintptr_t)hdlp.ih_dip);
130 mdb_printf("\n");
131 } while (mdb_vread(&avhp, sizeof (struct autovec),
132 (uintptr_t)avhp.av_link) != -1);
133 }
134
135 return (DCMD_OK);
136 }
137
138 void
interrupt_print_isr(uintptr_t vector,uintptr_t arg1,uintptr_t dip)139 interrupt_print_isr(uintptr_t vector, uintptr_t arg1, uintptr_t dip)
140 {
141 uintptr_t isr_addr = vector;
142 struct dev_info dev_info;
143
144 /*
145 * figure out the real ISR function name from gld_intr()
146 */
147 if (isr_addr == gld_intr_addr) {
148 gld_mac_info_t macinfo;
149
150 if (mdb_vread(&macinfo, sizeof (gld_mac_info_t), arg1) != -1) {
151 /* verify gld data structure and get the real ISR */
152 if (macinfo.gldm_GLD_version == GLD_VERSION)
153 isr_addr = (uintptr_t)macinfo.gldm_intr;
154 }
155 }
156
157 if ((option_flags & INTR_DISPLAY_DRVR_INST) && dip) {
158 char drvr_name[MODMAXNAMELEN + 1];
159
160 if (dip && mdb_devinfo2driver(dip, drvr_name,
161 sizeof (drvr_name)) == 0) {
162 (void) mdb_vread(&dev_info, sizeof (dev_info), dip);
163 mdb_printf("%s#%d", drvr_name, dev_info.devi_instance);
164 } else {
165 mdb_printf("%a", isr_addr);
166 }
167
168 } else {
169 mdb_printf("%a", isr_addr);
170 }
171 }
172
173 /*
174 * get_interrupt_type:
175 *
176 * Get some interrupt related useful information
177 *
178 * NOTE: a0 is clock, c0/d0/e0 are x-calls, e1 is apic_error_intr
179 * d1/d3 are cbe_fire interrupts
180 */
181 static char *
get_interrupt_type(short index)182 get_interrupt_type(short index)
183 {
184 if (index == RESERVE_INDEX)
185 return ("IPI");
186 else if (index == ACPI_INDEX)
187 return ("Fixed");
188 else if (index == MSI_INDEX)
189 return ("MSI");
190 else if (index == MSIX_INDEX)
191 return ("MSI-X");
192 else
193 return ("Fixed");
194 }
195
196 static char *
get_apix_interrupt_type(short type)197 get_apix_interrupt_type(short type)
198 {
199 if (type == APIX_TYPE_IPI)
200 return ("IPI");
201 else if (type == APIX_TYPE_FIXED)
202 return ("Fixed");
203 else if (type == APIX_TYPE_MSI)
204 return ("MSI");
205 else if (type == APIX_TYPE_MSIX)
206 return ("MSI-X");
207 else
208 return ("Fixed");
209 }
210
211 void
apic_interrupt_dump(apic_irq_t * irqp,struct av_head * avp,int i,ushort_t * evtchnp,char level)212 apic_interrupt_dump(apic_irq_t *irqp, struct av_head *avp,
213 int i, ushort_t *evtchnp, char level)
214 {
215 int bus_type;
216 int j;
217 char *intr_type;
218 char ioapic_iline[10];
219 char ipl[3];
220 char cpu_assigned[4];
221 char evtchn[8];
222 uint32_t assigned_cpu;
223 struct autovec avhp;
224
225 /* If invalid index; continue */
226 if (!irqp->airq_mps_intr_index ||
227 irqp->airq_mps_intr_index == FREE_INDEX)
228 return;
229
230 /* Figure out interrupt type and trigger information */
231 intr_type = get_interrupt_type(irqp->airq_mps_intr_index);
232
233 /* Figure out IOAPIC number and ILINE number */
234 if (APIC_IS_MSI_OR_MSIX_INDEX(irqp->airq_mps_intr_index))
235 (void) mdb_snprintf(ioapic_iline, 10, "- ");
236 else {
237 if (!irqp->airq_ioapicindex && !irqp->airq_intin_no) {
238 if (strcmp(intr_type, "Fixed") == 0)
239 (void) mdb_snprintf(ioapic_iline, 10,
240 "0x%x/0x%x", irqp->airq_ioapicindex,
241 irqp->airq_intin_no);
242 else if (irqp->airq_mps_intr_index == RESERVE_INDEX)
243 (void) mdb_snprintf(ioapic_iline, 10, "- ");
244 else
245 (void) mdb_snprintf(ioapic_iline, 10, " ");
246 } else
247 (void) mdb_snprintf(ioapic_iline, 10, "0x%x/0x%x",
248 irqp->airq_ioapicindex, irqp->airq_intin_no);
249 }
250
251 evtchn[0] = '\0';
252 if (evtchnp != NULL)
253 (void) mdb_snprintf(evtchn, 8, "%-7hd", *evtchnp);
254
255 assigned_cpu = irqp->airq_temp_cpu;
256 if (assigned_cpu == IRQ_UNINIT || assigned_cpu == IRQ_UNBOUND)
257 assigned_cpu = irqp->airq_cpu;
258 bus_type = irqp->airq_iflag.bustype;
259
260 if (irqp->airq_mps_intr_index == RESERVE_INDEX) {
261 (void) mdb_snprintf(cpu_assigned, 4, "all");
262 (void) mdb_snprintf(ipl, 3, "%d", avp->avh_hi_pri);
263 } else {
264 (void) mdb_snprintf(cpu_assigned, 4, "%d", assigned_cpu);
265 (void) mdb_snprintf(ipl, 3, "%d", irqp->airq_ipl);
266 }
267
268 /* Print each interrupt entry */
269 if (option_flags & INTR_DISPLAY_INTRSTAT)
270 mdb_printf("%-4s", cpu_assigned);
271 else
272 mdb_printf("%-3d 0x%x %s%-3s %-6s %-3s %-6s %-4s%-3d %-9s ",
273 i, irqp->airq_vector, evtchn, ipl,
274 (bus_type ? businfo_array[bus_type] : " "),
275 (level ? "Lvl" : "Edg"),
276 intr_type, cpu_assigned, irqp->airq_share, ioapic_iline);
277
278 /* If valid dip found; print driver name */
279 if (irqp->airq_dip) {
280 (void) mdb_vread(&avhp, sizeof (struct autovec),
281 (uintptr_t)avp->avh_link);
282
283 /*
284 * Loop thru all the shared IRQs
285 */
286 if (irqp->airq_share)
287 interrupt_print_isr((uintptr_t)avhp.av_vector,
288 (uintptr_t)avhp.av_intarg1, (uintptr_t)avhp.av_dip);
289
290 for (j = 1; irqp->airq_mps_intr_index != FREE_INDEX &&
291 j < irqp->airq_share; j++) {
292 if (mdb_vread(&avhp, sizeof (struct autovec),
293 (uintptr_t)avhp.av_link) != -1) {
294 mdb_printf(", ");
295 interrupt_print_isr((uintptr_t)avhp.av_vector,
296 (uintptr_t)avhp.av_intarg1,
297 (uintptr_t)avhp.av_dip);
298 } else {
299 break;
300 }
301 }
302
303 } else {
304 if (irqp->airq_mps_intr_index == RESERVE_INDEX &&
305 !irqp->airq_share)
306 mdb_printf("poke_cpu");
307 else if (mdb_vread(&avhp, sizeof (struct autovec),
308 (uintptr_t)avp->avh_link) != -1)
309 mdb_printf("%a", avhp.av_vector);
310 }
311 mdb_printf("\n");
312 }
313
314 void
apix_interrupt_dump(apix_vector_t * vectp,apic_irq_t * irqp,struct autovec * avp,ushort_t * evtchnp,char level)315 apix_interrupt_dump(apix_vector_t *vectp, apic_irq_t *irqp,
316 struct autovec *avp, ushort_t *evtchnp, char level)
317 {
318 int j;
319 int bus_type;
320 char *intr_type;
321 char irq[4];
322 char ioapic_iline[10];
323 char ipl[3];
324 char cpu_assigned[4];
325 char cpu_vector[10];
326 char evtchn[8];
327
328
329 /* If invalid vector state; continue */
330 if (vectp->v_state == APIX_STATE_FREED ||
331 vectp->v_state == APIX_STATE_OBSOLETED)
332 return;
333
334 /* use apic_interrupt_ipi_dump for IPIs */
335 if (vectp->v_type == APIX_TYPE_IPI)
336 return;
337
338 /* Figure out interrupt type and trigger information */
339 intr_type = get_apix_interrupt_type(vectp->v_type);
340
341 /* Figure out IOAPIC number and ILINE number */
342 if (vectp->v_type != APIX_TYPE_FIXED) {
343 level = 0; /* MSI/MSI-X are Edge trigger */
344 (void) mdb_snprintf(irq, 4, "- ");
345 (void) mdb_snprintf(ioapic_iline, 10, "- ");
346 if (vectp->v_type == APIX_TYPE_IPI)
347 bus_type = BUSTYPE_NONE;
348 else
349 /* statically assign MSI/X with "PCI" */
350 bus_type = BUSTYPE_PCI;
351 } else {
352 (void) mdb_snprintf(irq, 4, "%d", vectp->v_inum);
353 bus_type = irqp->airq_iflag.bustype;
354 if (!irqp->airq_ioapicindex && !irqp->airq_intin_no) {
355 if (strcmp(intr_type, "Fixed") == 0)
356 (void) mdb_snprintf(ioapic_iline, 10,
357 "0x%x/0x%x", irqp->airq_ioapicindex,
358 irqp->airq_intin_no);
359 else
360 (void) mdb_snprintf(ioapic_iline, 10, "- ");
361 } else
362 (void) mdb_snprintf(ioapic_iline, 10, "0x%x/0x%x",
363 irqp->airq_ioapicindex, irqp->airq_intin_no);
364 }
365
366 evtchn[0] = '\0';
367 if (evtchnp != NULL)
368 (void) mdb_snprintf(evtchn, 8, "%-7hd", *evtchnp);
369
370 (void) mdb_snprintf(cpu_assigned, 4, "%d", vectp->v_cpuid);
371 (void) mdb_snprintf(cpu_vector, 10, "%d/0x%x",
372 vectp->v_cpuid, vectp->v_vector);
373
374 /* Loop all the shared vectors */
375 for (j = 0; j < vectp->v_share; ) {
376 /* shared interrupts with one or more ISR removed afterwards */
377 if (avp->av_vector == NULL) {
378 if (mdb_vread(avp, sizeof (struct autovec),
379 (uintptr_t)avp->av_link) == -1)
380 break;
381 else
382 continue;
383 }
384
385 (void) mdb_snprintf(ipl, 3, "%d", avp->av_prilevel);
386 /* Print each interrupt entry */
387 if (option_flags & INTR_DISPLAY_INTRSTAT)
388 mdb_printf("%-4s", cpu_assigned);
389 else
390 mdb_printf("%-9s %-3s %s%-3s %-6s %-3s %-6s %-3d "
391 "%-9s ", cpu_vector, irq, evtchn, ipl,
392 (bus_type ? businfo_array[bus_type] : "-"),
393 (level ? "Lvl" : "Edg"),
394 intr_type, vectp->v_share, ioapic_iline);
395
396 interrupt_print_isr((uintptr_t)avp->av_vector,
397 (uintptr_t)avp->av_intarg1, (uintptr_t)avp->av_dip);
398 mdb_printf("\n");
399
400 if (++j == vectp->v_share)
401 break; /* done */
402
403 if (mdb_vread(avp, sizeof (struct autovec),
404 (uintptr_t)avp->av_link) == -1)
405 break;
406 }
407 }
408
409 void
apix_interrupt_ipi_dump(apix_vector_t * vectp,struct autovec * avp,ushort_t * evtchnp)410 apix_interrupt_ipi_dump(apix_vector_t *vectp, struct autovec *avp,
411 ushort_t *evtchnp)
412 {
413 char *intr_type = "IPI";
414 char ioapic_iline[10];
415 char ipl[3];
416 char cpu_assigned[4];
417 char cpu_vector[10];
418 char evtchn[8];
419
420 /* If invalid vector state; continue */
421 if (vectp->v_state == APIX_STATE_FREED ||
422 vectp->v_state == APIX_STATE_OBSOLETED)
423 return;
424
425 if (vectp->v_type != APIX_TYPE_IPI)
426 return;
427
428 /* No IOAPIC number and ILINE number info */
429 (void) mdb_snprintf(ioapic_iline, 10, "- ");
430
431 evtchn[0] = '\0';
432 if (evtchnp != NULL)
433 (void) mdb_snprintf(evtchn, 8, "%-7hd", *evtchnp);
434
435 /* IPI targeted ALL cpus */
436 mdb_snprintf(cpu_assigned, 4, "all");
437 (void) mdb_snprintf(cpu_vector, 10, "%s/0x%x",
438 "all", vectp->v_vector);
439 /* IPI is not shared interrupt, so we can get the IPL from v_pri */
440 (void) mdb_snprintf(ipl, 3, "%d", vectp->v_pri);
441
442 /* Print each interrupt entry */
443 if (option_flags & INTR_DISPLAY_INTRSTAT)
444 mdb_printf("%-4s", cpu_assigned);
445 else
446 mdb_printf("%-9s %-3s %s%-3s %-6s %-3s %-6s %-3d %-9s ",
447 cpu_vector, "- ", evtchn, ipl, "- ", "Edg",
448 intr_type, vectp->v_share, ioapic_iline);
449 if (!vectp->v_share)
450 mdb_printf("poke_cpu");
451 else
452 mdb_printf("%a", avp->av_vector);
453
454 mdb_printf("\n");
455 }
456