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) 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 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 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 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 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 * 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 * 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 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 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 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