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 * Copyright 2018 Joyent, Inc. 24 */ 25 26 #include "intr_common.h" 27 #include <sys/multidata.h> 28 #include <sys/gld.h> 29 #include <sys/gldpriv.h> 30 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]; 35 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 " " 57 }; 58 59 void 60 interrupt_help(void) 61 { 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"); 67 } 68 69 void 70 soft_interrupt_help(void) 71 { 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"); 76 } 77 78 /* 79 * This is copied from avintr.c 80 * NOTE: Ensure that this definition stays in sync 81 */ 82 typedef struct av_softinfo { 83 cpuset_t av_pending; /* pending bitmasks */ 84 } av_softinfo_t; 85 86 /* ARGSUSED */ 87 int 88 soft_interrupt_dump(uintptr_t addr, uint_t flags, int argc, 89 const mdb_arg_t *argv) 90 { 91 int i; 92 av_softinfo_t avsoftinfo; 93 struct autovec avhp; 94 ddi_softint_hdl_impl_t hdlp; 95 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); 100 101 if (mdb_readvar(&softvec_tbl, "softvect") == -1) { 102 mdb_warn("failed to read autovect"); 103 return (DCMD_ERR); 104 } 105 106 /* Print the header first */ 107 mdb_printf("%<u>ADDR PEND PIL ARG1 " 108 "ARG2 ISR(s)%</u>\n"); 109 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; 116 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; 124 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); 135 } 136 137 return (DCMD_OK); 138 } 139 140 void 141 interrupt_print_isr(uintptr_t vector, uintptr_t arg1, uintptr_t dip) 142 { 143 uintptr_t isr_addr = vector; 144 struct dev_info dev_info; 145 146 /* 147 * figure out the real ISR function name from gld_intr() 148 */ 149 if (isr_addr == gld_intr_addr) { 150 gld_mac_info_t macinfo; 151 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; 156 } 157 } 158 159 if ((option_flags & INTR_DISPLAY_DRVR_INST) && dip) { 160 char drvr_name[MODMAXNAMELEN + 1]; 161 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); 168 } 169 170 } else { 171 mdb_printf("%a", isr_addr); 172 } 173 } 174 175 /* 176 * get_interrupt_type: 177 * 178 * Get some interrupt related useful information 179 * 180 * NOTE: a0 is clock, c0/d0/e0 are x-calls, e1 is apic_error_intr 181 * d1/d3 are cbe_fire interrupts 182 */ 183 static char * 184 get_interrupt_type(short index) 185 { 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"); 196 } 197 198 static char * 199 get_apix_interrupt_type(short type) 200 { 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"); 211 } 212 213 void 214 apic_interrupt_dump(apic_irq_t *irqp, struct av_head *avp, 215 int i, ushort_t *evtchnp, char level) 216 { 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; 226 227 /* If invalid index; continue */ 228 if (!irqp->airq_mps_intr_index || 229 irqp->airq_mps_intr_index == FREE_INDEX) 230 return; 231 232 /* Figure out interrupt type and trigger information */ 233 intr_type = get_interrupt_type(irqp->airq_mps_intr_index); 234 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); 251 } 252 253 evtchn[0] = '\0'; 254 if (evtchnp != NULL) 255 (void) mdb_snprintf(evtchn, 8, "%-7hd", *evtchnp); 256 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; 261 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); 268 } 269 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); 279 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); 284 285 /* 286 * Loop thru all the shared IRQs 287 */ 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); 291 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; 302 } 303 } 304 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"); 312 } 313 } else if (mdb_vread(&avhp, sizeof (struct autovec), 314 (uintptr_t)avp->avh_link) != -1) { 315 mdb_printf("%a", avhp.av_vector); 316 } 317 } 318 mdb_printf("\n"); 319 } 320 321 void 322 apix_interrupt_dump(apix_vector_t *vectp, apic_irq_t *irqp, 323 struct autovec *avp, ushort_t *evtchnp, char level) 324 { 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]; 334 335 336 /* If invalid vector state; continue */ 337 if (vectp->v_state == APIX_STATE_FREED || 338 vectp->v_state == APIX_STATE_OBSOLETED) 339 return; 340 341 /* use apic_interrupt_ipi_dump for IPIs */ 342 if (vectp->v_type == APIX_TYPE_IPI) 343 return; 344 345 /* Figure out interrupt type and trigger information */ 346 intr_type = get_apix_interrupt_type(vectp->v_type); 347 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); 371 } 372 373 evtchn[0] = '\0'; 374 if (evtchnp != NULL) 375 (void) mdb_snprintf(evtchn, 8, "%-7hd", *evtchnp); 376 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); 380 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; 390 } 391 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); 402 403 interrupt_print_isr((uintptr_t)avp->av_vector, 404 (uintptr_t)avp->av_intarg1, (uintptr_t)avp->av_dip); 405 mdb_printf("\n"); 406 407 if (++j == vectp->v_share) 408 break; /* done */ 409 410 if (mdb_vread(avp, sizeof (struct autovec), 411 (uintptr_t)avp->av_link) == -1) 412 break; 413 } 414 } 415 416 void 417 apix_interrupt_ipi_dump(apix_vector_t *vectp, struct autovec *avp, 418 ushort_t *evtchnp) 419 { 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]; 426 427 /* If invalid vector state; continue */ 428 if (vectp->v_state == APIX_STATE_FREED || 429 vectp->v_state == APIX_STATE_OBSOLETED) 430 return; 431 432 if (vectp->v_type != APIX_TYPE_IPI) 433 return; 434 435 /* No IOAPIC number and ILINE number info */ 436 (void) mdb_snprintf(ioapic_iline, 10, "- "); 437 438 evtchn[0] = '\0'; 439 if (evtchnp != NULL) 440 (void) mdb_snprintf(evtchn, 8, "%-7hd", *evtchnp); 441 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); 448 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"); 461 } 462 } else { 463 mdb_printf("%a", avp->av_vector); 464 } 465 466 mdb_printf("\n"); 467 } 468