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 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include "intr_common.h" 29 #include <sys/multidata.h> 30 #include <sys/gld.h> 31 #include <sys/gldpriv.h> 32 33 int option_flags; 34 uintptr_t gld_intr_addr; 35 static struct av_head softvec_tbl[LOCK_LEVEL + 1]; 36 37 static char *businfo_array[] = { 38 " ", 39 "CBUS", 40 "CBUSII", 41 "EISA", 42 "FUTURE", 43 "INTERN", 44 "ISA", 45 "MBI", 46 "MBII", 47 "PCIe", 48 "MPI", 49 "MPSA", 50 "NUBUS", 51 "PCI", 52 "PCMCIA", 53 "TC", 54 "VL", 55 "VME", 56 "XPRESS", 57 " " 58 }; 59 60 void 61 interrupt_help(void) 62 { 63 mdb_printf("Prints the interrupt usage on the system.\n" 64 "By default, only interrupt service routine names are printed.\n\n" 65 "Switches:\n" 66 " -d instead of ISR, print <driver_name><instance#>\n" 67 " -i show like intrstat, cpu# ISR/<driver_name><instance#>\n"); 68 } 69 70 void 71 soft_interrupt_help(void) 72 { 73 mdb_printf("Prints the soft interrupt usage on the system.\n" 74 "By default, only interrupt service routine names are printed.\n\n" 75 "Switch:\n" 76 " -d instead of ISR, print <driver_name><instance#>\n"); 77 } 78 79 /* 80 * This is copied from avintr.c 81 * NOTE: Ensure that this definition stays in sync 82 */ 83 typedef struct av_softinfo { 84 cpuset_t av_pending; /* pending bitmasks */ 85 } av_softinfo_t; 86 87 /* ARGSUSED */ 88 int 89 soft_interrupt_dump(uintptr_t addr, uint_t flags, int argc, 90 const mdb_arg_t *argv) 91 { 92 int i; 93 av_softinfo_t avsoftinfo; 94 struct autovec avhp; 95 ddi_softint_hdl_impl_t hdlp; 96 97 option_flags = 0; 98 if (mdb_getopts(argc, argv, 'd', MDB_OPT_SETBITS, 99 INTR_DISPLAY_DRVR_INST, &option_flags, NULL) != argc) 100 return (DCMD_USAGE); 101 102 if (mdb_readvar(&softvec_tbl, "softvect") == -1) { 103 mdb_warn("failed to read autovect"); 104 return (DCMD_ERR); 105 } 106 107 /* Print the header first */ 108 mdb_printf("%<u>ADDR PEND PIL ARG1 " 109 "ARG2 ISR(s)%</u>\n"); 110 111 /* Walk all the entries */ 112 for (i = 0; i < LOCK_LEVEL + 1; i++) { 113 /* Read the entry, if invalid continue */ 114 if (mdb_vread(&avhp, sizeof (struct autovec), 115 (uintptr_t)softvec_tbl[i].avh_link) == -1) 116 continue; 117 118 do { 119 if (!avhp.av_vector || 120 (mdb_vread(&hdlp, sizeof (ddi_softint_hdl_impl_t), 121 (uintptr_t)avhp.av_intr_id) == -1) || 122 (mdb_vread(&avsoftinfo, sizeof (av_softinfo_t), 123 (uintptr_t)hdlp.ih_pending) == -1)) 124 continue; 125 126 /* Print each soft interrupt entry */ 127 mdb_printf("%-16p %-2d %-2d %-16p %-16p", 128 avhp.av_intr_id, mdb_cpuset_find( 129 (uintptr_t)&avsoftinfo.av_pending) != -1 ? 1 : 0, 130 avhp.av_prilevel, avhp.av_intarg1, avhp.av_intarg2); 131 interrupt_print_isr((uintptr_t)avhp.av_vector, 132 (uintptr_t)avhp.av_intarg1, (uintptr_t)hdlp.ih_dip); 133 mdb_printf("\n"); 134 } while (mdb_vread(&avhp, sizeof (struct autovec), 135 (uintptr_t)avhp.av_link) != -1); 136 } 137 138 return (DCMD_OK); 139 } 140 141 void 142 interrupt_print_isr(uintptr_t vector, uintptr_t arg1, uintptr_t dip) 143 { 144 uintptr_t isr_addr = vector; 145 struct dev_info dev_info; 146 147 /* 148 * figure out the real ISR function name from gld_intr() 149 */ 150 if (isr_addr == gld_intr_addr) { 151 gld_mac_info_t macinfo; 152 153 if (mdb_vread(&macinfo, sizeof (gld_mac_info_t), arg1) != -1) { 154 /* verify gld data structure and get the real ISR */ 155 if (macinfo.gldm_GLD_version == GLD_VERSION) 156 isr_addr = (uintptr_t)macinfo.gldm_intr; 157 } 158 } 159 160 if ((option_flags & INTR_DISPLAY_DRVR_INST) && dip) { 161 char drvr_name[MODMAXNAMELEN + 1]; 162 163 if (dip && mdb_devinfo2driver(dip, drvr_name, 164 sizeof (drvr_name)) == 0) { 165 (void) mdb_vread(&dev_info, sizeof (dev_info), dip); 166 mdb_printf("%s#%d", drvr_name, dev_info.devi_instance); 167 } else { 168 mdb_printf("%a", isr_addr); 169 } 170 171 } else { 172 mdb_printf("%a", isr_addr); 173 } 174 } 175 176 /* 177 * get_interrupt_type: 178 * 179 * Get some interrupt related useful information 180 * 181 * NOTE: a0 is clock, c0/d0/e0 are x-calls, e1 is apic_error_intr 182 * d1/d3 are cbe_fire interrupts 183 */ 184 static char * 185 get_interrupt_type(short index) 186 { 187 if (index == RESERVE_INDEX) 188 return ("IPI"); 189 else if (index == ACPI_INDEX) 190 return ("Fixed"); 191 else if (index == MSI_INDEX) 192 return ("MSI"); 193 else if (index == MSIX_INDEX) 194 return ("MSI-X"); 195 else 196 return ("Fixed"); 197 } 198 199 void 200 apic_interrupt_dump(apic_irq_t *irqp, struct av_head *avp, 201 int i, ushort_t *evtchnp, char level) 202 { 203 int bus_type; 204 int j; 205 char *intr_type; 206 char ioapic_iline[10]; 207 char ipl[3]; 208 char cpu_assigned[4]; 209 char evtchn[8]; 210 uint32_t assigned_cpu; 211 struct autovec avhp; 212 213 /* If invalid index; continue */ 214 if (!irqp->airq_mps_intr_index || 215 irqp->airq_mps_intr_index == FREE_INDEX) 216 return; 217 218 /* Figure out interrupt type and trigger information */ 219 intr_type = get_interrupt_type(irqp->airq_mps_intr_index); 220 221 /* Figure out IOAPIC number and ILINE number */ 222 if (APIC_IS_MSI_OR_MSIX_INDEX(irqp->airq_mps_intr_index)) 223 (void) mdb_snprintf(ioapic_iline, 10, "- "); 224 else { 225 if (!irqp->airq_ioapicindex && !irqp->airq_intin_no) { 226 if (strcmp(intr_type, "Fixed") == 0) 227 (void) mdb_snprintf(ioapic_iline, 10, 228 "0x%x/0x%x", irqp->airq_ioapicindex, 229 irqp->airq_intin_no); 230 else if (irqp->airq_mps_intr_index == RESERVE_INDEX) 231 (void) mdb_snprintf(ioapic_iline, 10, "- "); 232 else 233 (void) mdb_snprintf(ioapic_iline, 10, " "); 234 } else 235 (void) mdb_snprintf(ioapic_iline, 10, "0x%x/0x%x", 236 irqp->airq_ioapicindex, irqp->airq_intin_no); 237 } 238 239 evtchn[0] = '\0'; 240 if (evtchnp != NULL) 241 (void) mdb_snprintf(evtchn, 8, "%-7hd", *evtchnp); 242 243 assigned_cpu = irqp->airq_temp_cpu; 244 if (assigned_cpu == IRQ_UNINIT || assigned_cpu == IRQ_UNBOUND) 245 assigned_cpu = irqp->airq_cpu; 246 bus_type = irqp->airq_iflag.bustype; 247 248 if (irqp->airq_mps_intr_index == RESERVE_INDEX) { 249 (void) mdb_snprintf(cpu_assigned, 4, "all"); 250 (void) mdb_snprintf(ipl, 3, "%d", avp->avh_hi_pri); 251 } else { 252 (void) mdb_snprintf(cpu_assigned, 4, "%d", assigned_cpu); 253 (void) mdb_snprintf(ipl, 3, "%d", irqp->airq_ipl); 254 } 255 256 /* Print each interrupt entry */ 257 if (option_flags & INTR_DISPLAY_INTRSTAT) 258 mdb_printf("%-4s", cpu_assigned); 259 else 260 mdb_printf("%-3d 0x%x %s%-3s %-6s %-3s %-6s %-4s%-3d %-9s ", 261 i, irqp->airq_vector, evtchn, ipl, 262 (bus_type ? businfo_array[bus_type] : " "), 263 (level ? "Lvl" : "Edg"), 264 intr_type, cpu_assigned, irqp->airq_share, ioapic_iline); 265 266 /* If valid dip found; print driver name */ 267 if (irqp->airq_dip) { 268 (void) mdb_vread(&avhp, sizeof (struct autovec), 269 (uintptr_t)avp->avh_link); 270 271 /* 272 * Loop thru all the shared IRQs 273 */ 274 if (irqp->airq_share) 275 interrupt_print_isr((uintptr_t)avhp.av_vector, 276 (uintptr_t)avhp.av_intarg1, (uintptr_t)avhp.av_dip); 277 278 for (j = 1; irqp->airq_mps_intr_index != FREE_INDEX && 279 j < irqp->airq_share; j++) { 280 if (mdb_vread(&avhp, sizeof (struct autovec), 281 (uintptr_t)avhp.av_link) != -1) { 282 mdb_printf(", "); 283 interrupt_print_isr((uintptr_t)avhp.av_vector, 284 (uintptr_t)avhp.av_intarg1, 285 (uintptr_t)avhp.av_dip); 286 } else { 287 break; 288 } 289 } 290 291 } else { 292 if (irqp->airq_mps_intr_index == RESERVE_INDEX && 293 !irqp->airq_share) 294 mdb_printf("poke_cpu"); 295 else if (mdb_vread(&avhp, sizeof (struct autovec), 296 (uintptr_t)avp->avh_link) != -1) 297 mdb_printf("%a", avhp.av_vector); 298 } 299 mdb_printf("\n"); 300 } 301