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