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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <sys/mdb_modapi.h> 30 #include <mdb/mdb_ks.h> 31 #include <sys/async.h> /* ecc_flt for pci_ecc.h */ 32 #include <sys/ddi_subrdefs.h> 33 #include <sys/pci/pci_obj.h> 34 #include "px_obj.h" 35 36 static int intr_pci_walk_step(mdb_walk_state_t *); 37 static int intr_px_walk_step(mdb_walk_state_t *); 38 static void intr_pci_print_items(mdb_walk_state_t *); 39 static void intr_px_print_items(mdb_walk_state_t *); 40 static char *intr_get_intr_type(msiq_rec_type_t); 41 static void intr_print_banner(void); 42 43 typedef struct intr_info { 44 uint32_t cpuid; 45 uint32_t inum; 46 uint32_t num; 47 uint32_t pil; 48 uint16_t mondo; 49 uint8_t ino_ino; 50 uint_t intr_state; 51 int instance; 52 int shared; 53 msiq_rec_type_t intr_type; 54 char driver_name[12]; 55 char pathname[MAXNAMELEN]; 56 } 57 intr_info_t; 58 59 static void intr_print_elements(intr_info_t); 60 static int detailed = 0; /* Print detailed view */ 61 62 63 static int 64 intr_walk_init(mdb_walk_state_t *wsp) 65 { 66 wsp->walk_addr = NULL; 67 68 return (WALK_NEXT); 69 } 70 71 static int 72 intr_walk_step(mdb_walk_state_t *wsp) 73 { 74 pci_t *pci_per_p; 75 px_t *px_state_p; 76 77 /* read globally declared structures in the pci driver */ 78 if (mdb_readvar(&pci_per_p, "per_pci_state") != -1) { 79 wsp->walk_addr = (uintptr_t)pci_per_p; 80 intr_pci_walk_step(wsp); 81 } 82 83 /* read globally declared structures in the px driver */ 84 if (mdb_readvar(&px_state_p, "px_state_p") != -1) { 85 wsp->walk_addr = (uintptr_t)px_state_p; 86 intr_px_walk_step(wsp); 87 } 88 89 return (WALK_DONE); 90 } 91 92 static int 93 intr_pci_walk_step(mdb_walk_state_t *wsp) 94 { 95 pci_t *pci_per_p; 96 pci_t pci_per; 97 uintptr_t start_addr; 98 99 /* Read start of state structure array */ 100 if (mdb_vread(&pci_per_p, sizeof (uintptr_t), 101 (uintptr_t)wsp->walk_addr) == -1) { 102 mdb_warn("intr: failed to read the initial pci_per_p " 103 "structure\n"); 104 return (WALK_ERR); 105 } 106 107 /* Figure out how many items are here */ 108 start_addr = (uintptr_t)pci_per_p; 109 110 intr_print_banner(); 111 112 while (mdb_vread(&pci_per_p, sizeof (uintptr_t), 113 (uintptr_t)start_addr) != -1) { 114 /* Read until nothing is left */ 115 if (mdb_vread(&pci_per, sizeof (pci_t), 116 (uintptr_t)pci_per_p) == -1) { 117 return (WALK_DONE); 118 } 119 120 wsp->walk_addr = (uintptr_t)pci_per.pci_ib_p; 121 intr_pci_print_items(wsp); 122 123 start_addr += sizeof (uintptr_t); 124 } 125 126 return (WALK_DONE); 127 } 128 129 static int 130 intr_px_walk_step(mdb_walk_state_t *wsp) 131 { 132 px_t *px_state_p; 133 px_t px_state; 134 uintptr_t start_addr; 135 136 /* Read start of state structure array */ 137 if (mdb_vread(&px_state_p, sizeof (uintptr_t), 138 (uintptr_t)wsp->walk_addr) == -1) { 139 mdb_warn("intr: failed to read the initial px_per_p " 140 "structure\n"); 141 return (WALK_ERR); 142 } 143 144 /* Figure out how many items are here */ 145 start_addr = (uintptr_t)px_state_p; 146 147 intr_print_banner(); 148 149 while (mdb_vread(&px_state_p, sizeof (uintptr_t), 150 (uintptr_t)start_addr) != -1) { 151 /* Read until nothing is left */ 152 if (mdb_vread(&px_state, sizeof (px_t), 153 (uintptr_t)px_state_p) == -1) { 154 return (WALK_DONE); 155 } 156 157 wsp->walk_addr = (uintptr_t)px_state.px_ib_p; 158 intr_px_print_items(wsp); 159 160 start_addr += sizeof (uintptr_t); 161 } 162 163 return (WALK_DONE); 164 } 165 166 static void 167 intr_pci_print_items(mdb_walk_state_t *wsp) 168 { 169 ib_t pci_ib; 170 ib_ino_info_t *ib_ino_lst; 171 ib_ino_info_t list; 172 ih_t ih; 173 int count; 174 char name[MODMAXNAMELEN + 1]; 175 struct dev_info devinfo; 176 intr_info_t info; 177 178 if (mdb_vread(&pci_ib, sizeof (ib_t), 179 (uintptr_t)wsp->walk_addr) == -1) { 180 mdb_warn("intr: failed to read pci interrupt block " 181 "structure\n"); 182 return; 183 } 184 185 /* Read in ib_ino_info_t structure at address */ 186 ib_ino_lst = pci_ib.ib_ino_lst; 187 if (mdb_vread(&list, sizeof (ib_ino_info_t), 188 (uintptr_t)ib_ino_lst) == -1) { 189 /* Nothing here to read from */ 190 return; 191 } 192 193 do { 194 if (mdb_vread(&ih, sizeof (ih_t), 195 (uintptr_t)list.ino_ih_start) == -1) { 196 mdb_warn("intr: failed to read pci interrupt entry " 197 "structure\n"); 198 return; 199 } 200 201 count = 0; 202 203 do { 204 bzero((void *)&info, sizeof (intr_info_t)); 205 206 if (list.ino_ih_size > 1) { 207 info.shared = 1; 208 } 209 210 (void) mdb_devinfo2driver((uintptr_t)ih.ih_dip, 211 name, sizeof (name)); 212 213 (void) mdb_ddi_pathname((uintptr_t)ih.ih_dip, 214 info.pathname, sizeof (info.pathname)); 215 216 /* Get instance */ 217 if (mdb_vread(&devinfo, sizeof (struct dev_info), 218 (uintptr_t)ih.ih_dip) == -1) { 219 mdb_warn("intr: failed to read DIP " 220 "structure\n"); 221 return; 222 } 223 224 /* Make sure the name doesn't over run */ 225 (void) mdb_snprintf(info.driver_name, 226 sizeof (info.driver_name), "%s", name); 227 228 info.instance = devinfo.devi_instance; 229 info.inum = ih.ih_inum; 230 info.intr_type = INTX_REC; 231 info.num = 0; 232 info.intr_state = ih.ih_intr_state; 233 info.ino_ino = list.ino_ino; 234 info.mondo = list.ino_mondo; 235 info.pil = list.ino_pil; 236 info.cpuid = list.ino_cpuid; 237 238 intr_print_elements(info); 239 count++; 240 241 (void) mdb_vread(&ih, sizeof (ih_t), 242 (uintptr_t)ih.ih_next); 243 244 } while (count < list.ino_ih_size); 245 246 } while (mdb_vread(&list, sizeof (ib_ino_info_t), 247 (uintptr_t)list.ino_next) != -1); 248 } 249 250 static void 251 intr_px_print_items(mdb_walk_state_t *wsp) 252 { 253 px_ib_t px_ib; 254 px_ib_ino_info_t *px_ib_ino_lst; 255 px_ib_ino_info_t px_list; 256 px_ih_t px_ih; 257 int count; 258 char name[MODMAXNAMELEN + 1]; 259 struct dev_info devinfo; 260 intr_info_t info; 261 262 if (mdb_vread(&px_ib, sizeof (px_ib_t), wsp->walk_addr) == -1) { 263 mdb_warn("intr: failed to read px interrupt block " 264 "structure\n"); 265 return; 266 } 267 268 /* Read in px_ib_ino_info_t structure at address */ 269 px_ib_ino_lst = px_ib.ib_ino_lst; 270 if (mdb_vread(&px_list, sizeof (px_ib_ino_info_t), 271 (uintptr_t)px_ib_ino_lst) == -1) { 272 /* Nothing here to read from */ 273 return; 274 } 275 276 do { 277 if (mdb_vread(&px_ih, sizeof (px_ih_t), 278 (uintptr_t)px_list.ino_ih_start) == -1) { 279 mdb_warn("intr: failed to read px interrupt entry " 280 "structure\n"); 281 return; 282 } 283 284 count = 0; 285 286 do { 287 bzero((void *)&info, sizeof (intr_info_t)); 288 289 if (px_list.ino_ih_size > 1) { 290 info.shared = 1; 291 } 292 293 (void) mdb_devinfo2driver((uintptr_t)px_ih.ih_dip, 294 name, sizeof (name)); 295 296 (void) mdb_ddi_pathname((uintptr_t)px_ih.ih_dip, 297 info.pathname, sizeof (info.pathname)); 298 299 /* Get instance */ 300 if (mdb_vread(&devinfo, sizeof (struct dev_info), 301 (uintptr_t)px_ih.ih_dip) == -1) { 302 mdb_warn("intr: failed to read DIP " 303 "structure\n"); 304 return; 305 } 306 307 /* Make sure the name doesn't over run */ 308 (void) mdb_snprintf(info.driver_name, 309 sizeof (info.driver_name), "%s", name); 310 311 info.instance = devinfo.devi_instance; 312 info.inum = px_ih.ih_inum; 313 info.intr_type = px_ih.ih_rec_type; 314 info.num = px_ih.ih_msg_code; 315 info.intr_state = px_ih.ih_intr_state; 316 info.ino_ino = px_list.ino_ino; 317 info.mondo = px_list.ino_sysino; 318 info.pil = px_list.ino_pil; 319 info.cpuid = px_list.ino_cpuid; 320 321 intr_print_elements(info); 322 count++; 323 324 (void) mdb_vread(&px_ih, sizeof (ih_t), 325 (uintptr_t)px_ih.ih_next); 326 327 } while (count < px_list.ino_ih_size); 328 329 } while (mdb_vread(&px_list, sizeof (px_ib_ino_info_t), 330 (uintptr_t)px_list.ino_next) != -1); 331 } 332 333 static char * 334 intr_get_intr_type(msiq_rec_type_t rec_type) 335 { 336 switch (rec_type) { 337 case MSG_REC: 338 return ("PCIe"); 339 case MSI32_REC: 340 case MSI64_REC: 341 return ("MSI"); 342 case INTX_REC: 343 default: 344 return ("Fixed"); 345 } 346 } 347 348 static void 349 intr_print_banner(void) 350 { 351 if (!detailed) { 352 mdb_printf("\n%<u>\tDevice\t" 353 " Shared\t" 354 " Type\t" 355 " MSG #\t" 356 " State\t" 357 " INO\t" 358 " Mondo\t" 359 " Pil\t" 360 " CPU %</u>" 361 "\n"); 362 } 363 } 364 365 static void 366 intr_print_elements(intr_info_t info) 367 { 368 if (!detailed) { 369 mdb_printf(" %11s#%d\t", info.driver_name, info.instance); 370 mdb_printf(" %5s\t", 371 info.shared ? "yes" : "no"); 372 mdb_printf(" %s\t", intr_get_intr_type(info.intr_type)); 373 if (strcmp("Fixed", intr_get_intr_type(info.intr_type)) == 0) { 374 mdb_printf(" --- \t"); 375 } else { 376 mdb_printf(" %4d\t", info.num); 377 } 378 379 mdb_printf(" %2s\t", 380 info.intr_state ? "enbl" : "disbl"); 381 mdb_printf(" 0x%x\t", info.ino_ino); 382 mdb_printf(" 0x%x\t", info.mondo); 383 mdb_printf(" %4d\t", info.pil); 384 mdb_printf(" %3d \n", info.cpuid); 385 } else { 386 mdb_printf("\n-------------------------------------------\n"); 387 mdb_printf("Device:\t\t%s\n", info.driver_name); 388 mdb_printf("Instance:\t%d\n", info.instance); 389 mdb_printf("Path:\t\t%s\n", info.pathname); 390 mdb_printf("Inum:\t\t%d\n", info.inum); 391 mdb_printf("Interrupt Type:\t%s\n", 392 intr_get_intr_type(info.intr_type)); 393 if (strcmp("MSI", intr_get_intr_type(info.intr_type)) == 0) 394 mdb_printf("MSI/X Number:\t%s\n", info.num); 395 396 mdb_printf("Shared Intr:\t%s\n", 397 info.shared ? "yes" : "no"); 398 mdb_printf("State:\t\t%d (%s)\n", info.intr_state, 399 info.intr_state ? "Enabled" : "Disabled"); 400 mdb_printf("INO:\t\t0x%x\n", info.ino_ino); 401 mdb_printf("Mondo:\t\t0x%x\n", info.mondo); 402 mdb_printf("Pil:\t\t%d\n", info.pil); 403 mdb_printf("CPU:\t\t%d\n", info.cpuid); 404 } 405 } 406 407 /*ARGSUSED*/ 408 static void 409 intr_walk_fini(mdb_walk_state_t *wsp) 410 { 411 /* Nothing to do here */ 412 } 413 414 /*ARGSUSED*/ 415 static int 416 intr_intr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 417 { 418 detailed = 0; 419 420 if (mdb_getopts(argc, argv, 'd', MDB_OPT_SETBITS, TRUE, &detailed, 421 NULL) != argc) 422 return (DCMD_USAGE); 423 424 if (!(flags & DCMD_ADDRSPEC)) { 425 if (mdb_walk_dcmd("interrupts", "interrupts", argc, argv) 426 == -1) { 427 mdb_warn("can't walk pci/px buffer entries\n"); 428 return (DCMD_ERR); 429 } 430 return (DCMD_OK); 431 } 432 433 return (DCMD_OK); 434 } 435 436 /* 437 * MDB module linkage information: 438 */ 439 440 static const mdb_dcmd_t dcmds[] = { 441 { "interrupts", "[-d]", "display the interrupt info registered with " 442 "the PCI/PX nexus drivers", intr_intr }, 443 { NULL } 444 }; 445 446 static const mdb_walker_t walkers[] = { 447 { "interrupts", "walk PCI/PX interrupt structures", 448 intr_walk_init, intr_walk_step, intr_walk_fini }, 449 { NULL } 450 }; 451 452 static const mdb_modinfo_t modinfo = { 453 MDB_API_VERSION, dcmds, walkers 454 }; 455 456 const mdb_modinfo_t * 457 _mdb_init(void) 458 { 459 return (&modinfo); 460 } 461