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 2010 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <sys/mdb_modapi.h> 27 #include <mdb/mdb_ks.h> 28 #include <sys/async.h> /* ecc_flt for pci_ecc.h */ 29 #include <sys/ddi_subrdefs.h> 30 #include <sys/pci/pci_obj.h> 31 #include "niumx_var.h" 32 #include "px_obj.h" 33 34 static int intr_pci_walk_step(mdb_walk_state_t *); 35 static int intr_px_walk_step(mdb_walk_state_t *); 36 static int intr_niumx_walk_step(mdb_walk_state_t *); 37 static void intr_pci_print_items(mdb_walk_state_t *); 38 static void intr_px_print_items(mdb_walk_state_t *); 39 static char *intr_get_intr_type(uint16_t type); 40 static void intr_print_banner(void); 41 42 typedef struct intr_info { 43 uint32_t cpuid; 44 uint32_t inum; 45 uint32_t num; 46 uint32_t pil; 47 uint16_t intr_type; 48 uint16_t mondo; 49 uint8_t ino_ino; 50 uint_t intr_state; 51 int instance; 52 int shared; 53 char driver_name[12]; 54 char pathname[MAXNAMELEN]; 55 } 56 intr_info_t; 57 58 #define PX_MAX_ENTRIES 32 59 60 static void intr_print_elements(intr_info_t); 61 static int detailed = 0; /* Print detailed view */ 62 63 64 static int 65 intr_walk_init(mdb_walk_state_t *wsp) 66 { 67 wsp->walk_addr = NULL; 68 69 return (WALK_NEXT); 70 } 71 72 static int 73 intr_walk_step(mdb_walk_state_t *wsp) 74 { 75 pci_t *pci_per_p; 76 px_t *px_state_p; 77 niumx_devstate_t *niumx_state_p; 78 79 /* read globally declared structures in the pci driver */ 80 if (mdb_readvar(&pci_per_p, "per_pci_state") != -1) { 81 wsp->walk_addr = (uintptr_t)pci_per_p; 82 intr_pci_walk_step(wsp); 83 } 84 85 /* read globally declared structures in the px driver */ 86 if (mdb_readvar(&px_state_p, "px_state_p") != -1) { 87 wsp->walk_addr = (uintptr_t)px_state_p; 88 intr_px_walk_step(wsp); 89 } 90 91 /* read globally declared structures in the niumx driver */ 92 if (mdb_readvar(&niumx_state_p, "niumx_state") != -1) { 93 wsp->walk_addr = (uintptr_t)niumx_state_p; 94 intr_niumx_walk_step(wsp); 95 } 96 97 return (WALK_DONE); 98 } 99 100 static int 101 intr_pci_walk_step(mdb_walk_state_t *wsp) 102 { 103 pci_t *pci_per_p; 104 pci_t pci_per; 105 uintptr_t start_addr; 106 107 /* Read start of state structure array */ 108 if (mdb_vread(&pci_per_p, sizeof (uintptr_t), 109 (uintptr_t)wsp->walk_addr) == -1) { 110 mdb_warn("intr: failed to read the initial pci_per_p " 111 "structure\n"); 112 return (WALK_ERR); 113 } 114 115 /* Figure out how many items are here */ 116 start_addr = (uintptr_t)pci_per_p; 117 118 intr_print_banner(); 119 120 while (mdb_vread(&pci_per_p, sizeof (uintptr_t), 121 (uintptr_t)start_addr) != -1) { 122 /* Read until nothing is left */ 123 if (mdb_vread(&pci_per, sizeof (pci_t), 124 (uintptr_t)pci_per_p) == -1) { 125 return (WALK_DONE); 126 } 127 128 wsp->walk_addr = (uintptr_t)pci_per.pci_ib_p; 129 intr_pci_print_items(wsp); 130 131 start_addr += sizeof (uintptr_t); 132 } 133 134 return (WALK_DONE); 135 } 136 137 static int 138 intr_px_walk_step(mdb_walk_state_t *wsp) 139 { 140 px_t *px_state_p; 141 px_t px_state; 142 uintptr_t start_addr; 143 int x; 144 145 /* Read start of state structure array */ 146 if (mdb_vread(&px_state_p, sizeof (uintptr_t), 147 (uintptr_t)wsp->walk_addr) == -1) { 148 mdb_warn("intr: failed to read the initial px_per_p " 149 "structure\n"); 150 return (WALK_ERR); 151 } 152 153 /* Figure out how many items are here */ 154 start_addr = (uintptr_t)px_state_p; 155 156 intr_print_banner(); 157 158 for (x = 0; x < PX_MAX_ENTRIES; x++) { 159 (void) mdb_vread(&px_state_p, sizeof (uintptr_t), 160 (uintptr_t)start_addr); 161 162 start_addr += sizeof (uintptr_t); 163 164 /* Read if anything is there */ 165 if (mdb_vread(&px_state, sizeof (px_t), 166 (uintptr_t)px_state_p) == -1) { 167 continue; 168 } 169 170 wsp->walk_addr = (uintptr_t)px_state.px_ib_p; 171 intr_px_print_items(wsp); 172 } 173 174 return (WALK_DONE); 175 } 176 177 static int 178 intr_niumx_walk_step(mdb_walk_state_t *wsp) 179 { 180 niumx_devstate_t *niumx_state_p; 181 niumx_devstate_t niumx_state; 182 uintptr_t start_addr; 183 char name[MODMAXNAMELEN + 1]; 184 struct dev_info dev; 185 intr_info_t info; 186 int i; 187 188 /* Read start of state structure array */ 189 if (mdb_vread(&niumx_state_p, sizeof (uintptr_t), 190 (uintptr_t)wsp->walk_addr) == -1) { 191 mdb_warn("intr: failed to read the initial niumx_state_p " 192 "structure\n"); 193 return (WALK_ERR); 194 } 195 196 /* Figure out how many items are here */ 197 start_addr = (uintptr_t)niumx_state_p; 198 199 while (mdb_vread(&niumx_state_p, sizeof (uintptr_t), 200 (uintptr_t)start_addr) >= 0) { 201 202 start_addr += sizeof (uintptr_t); 203 204 /* Read if anything is there */ 205 if (mdb_vread(&niumx_state, sizeof (niumx_devstate_t), 206 (uintptr_t)niumx_state_p) == -1) { 207 return (WALK_DONE); 208 } 209 210 for (i = 0; i < NIUMX_MAX_INTRS; i++) { 211 if (niumx_state.niumx_ihtable[i].ih_sysino == 0) 212 continue; 213 214 if (niumx_state.niumx_ihtable[i].ih_dip == 0) 215 continue; 216 217 bzero((void *)&info, sizeof (intr_info_t)); 218 219 info.shared = 0; 220 221 (void) mdb_devinfo2driver( 222 (uintptr_t)niumx_state.niumx_ihtable[i].ih_dip, 223 name, sizeof (name)); 224 225 (void) mdb_ddi_pathname( 226 (uintptr_t)niumx_state.niumx_ihtable[i].ih_dip, 227 info.pathname, sizeof (info.pathname)); 228 229 /* Get instance */ 230 if (mdb_vread(&dev, sizeof (struct dev_info), 231 (uintptr_t)niumx_state.niumx_ihtable[i].ih_dip) == 232 -1) { 233 mdb_warn("intr: failed to read DIP " 234 "structure\n"); 235 236 return (WALK_DONE); 237 } 238 239 /* Make sure the name doesn't over run */ 240 (void) mdb_snprintf(info.driver_name, 241 sizeof (info.driver_name), "%s", name); 242 243 info.instance = dev.devi_instance; 244 info.inum = niumx_state.niumx_ihtable[i].ih_inum; 245 info.intr_type = DDI_INTR_TYPE_FIXED; 246 info.num = 0; 247 info.intr_state = niumx_state.niumx_ihtable[i].ih_state; 248 info.ino_ino = i; 249 info.mondo = niumx_state.niumx_ihtable[i].ih_sysino; 250 info.pil = niumx_state.niumx_ihtable[i].ih_pri; 251 info.cpuid = niumx_state.niumx_ihtable[i].ih_cpuid; 252 253 intr_print_elements(info); 254 } 255 } 256 257 return (WALK_DONE); 258 } 259 260 static void 261 intr_pci_print_items(mdb_walk_state_t *wsp) 262 { 263 ib_t ib; 264 ib_ino_info_t ino; 265 ib_ino_pil_t ipil; 266 ih_t ih; 267 int count; 268 char name[MODMAXNAMELEN + 1]; 269 struct dev_info dev; 270 intr_info_t info; 271 272 if (mdb_vread(&ib, sizeof (ib_t), 273 (uintptr_t)wsp->walk_addr) == -1) { 274 mdb_warn("intr: failed to read pci interrupt block " 275 "structure\n"); 276 return; 277 } 278 279 /* Read in ib_ino_info_t structure at address */ 280 if (mdb_vread(&ino, sizeof (ib_ino_info_t), 281 (uintptr_t)ib.ib_ino_lst) == -1) { 282 /* Nothing here to read from */ 283 return; 284 } 285 286 do { 287 if (mdb_vread(&ipil, sizeof (ib_ino_pil_t), 288 (uintptr_t)ino.ino_ipil_p) == -1) { 289 mdb_warn("intr: failed to read pci interrupt " 290 "ib_ino_pil_t structure\n"); 291 return; 292 } 293 294 do { 295 if (mdb_vread(&ih, sizeof (ih_t), 296 (uintptr_t)ipil.ipil_ih_start) == -1) { 297 mdb_warn("intr: failed to read pci interrupt " 298 "ih_t structure\n"); 299 return; 300 } 301 302 count = 0; 303 304 do { 305 bzero((void *)&info, sizeof (intr_info_t)); 306 307 if ((ino.ino_ipil_size > 1) || 308 (ipil.ipil_ih_size > 1)) { 309 info.shared = 1; 310 } 311 312 (void) mdb_devinfo2driver((uintptr_t)ih.ih_dip, 313 name, sizeof (name)); 314 315 (void) mdb_ddi_pathname((uintptr_t)ih.ih_dip, 316 info.pathname, sizeof (info.pathname)); 317 318 /* Get instance */ 319 if (mdb_vread(&dev, sizeof (struct dev_info), 320 (uintptr_t)ih.ih_dip) == -1) { 321 mdb_warn("intr: failed to read DIP " 322 "structure\n"); 323 return; 324 } 325 326 /* Make sure the name doesn't over run */ 327 (void) mdb_snprintf(info.driver_name, 328 sizeof (info.driver_name), "%s", name); 329 330 info.instance = dev.devi_instance; 331 info.inum = ih.ih_inum; 332 info.intr_type = DDI_INTR_TYPE_FIXED; 333 info.num = 0; 334 info.intr_state = ih.ih_intr_state; 335 info.ino_ino = ino.ino_ino; 336 info.mondo = ino.ino_mondo; 337 info.pil = ipil.ipil_pil; 338 info.cpuid = ino.ino_cpuid; 339 340 intr_print_elements(info); 341 count++; 342 343 (void) mdb_vread(&ih, sizeof (ih_t), 344 (uintptr_t)ih.ih_next); 345 346 } while (count < ipil.ipil_ih_size); 347 348 } while (mdb_vread(&ipil, sizeof (ib_ino_pil_t), 349 (uintptr_t)ipil.ipil_next_p) != -1); 350 351 } while (mdb_vread(&ino, sizeof (ib_ino_info_t), 352 (uintptr_t)ino.ino_next_p) != -1); 353 } 354 355 static void 356 intr_px_print_items(mdb_walk_state_t *wsp) 357 { 358 px_ib_t ib; 359 px_ino_t ino; 360 px_ino_pil_t ipil; 361 px_ih_t ih; 362 int count; 363 char name[MODMAXNAMELEN + 1]; 364 struct dev_info dev; 365 intr_info_t info; 366 devinfo_intr_t intr_p; 367 368 if (mdb_vread(&ib, sizeof (px_ib_t), wsp->walk_addr) == -1) { 369 return; 370 } 371 372 /* Read in px_ino_t structure at address */ 373 if (mdb_vread(&ino, sizeof (px_ino_t), 374 (uintptr_t)ib.ib_ino_lst) == -1) { 375 /* Nothing here to read from */ 376 return; 377 } 378 379 do { /* ino_next_p loop */ 380 if (mdb_vread(&ipil, sizeof (px_ino_pil_t), 381 (uintptr_t)ino.ino_ipil_p) == -1) { 382 continue; 383 } 384 385 do { /* ipil_next_p loop */ 386 if (mdb_vread(&ih, sizeof (px_ih_t), 387 (uintptr_t)ipil.ipil_ih_start) == -1) { 388 continue; 389 } 390 391 count = 0; 392 393 do { /* ipil_ih_size loop */ 394 bzero((void *)&info, sizeof (intr_info_t)); 395 396 (void) mdb_devinfo2driver((uintptr_t)ih.ih_dip, 397 name, sizeof (name)); 398 399 (void) mdb_ddi_pathname((uintptr_t)ih.ih_dip, 400 info.pathname, sizeof (info.pathname)); 401 402 /* Get instance */ 403 if (mdb_vread(&dev, sizeof (struct dev_info), 404 (uintptr_t)ih.ih_dip) == -1) { 405 mdb_warn("intr: failed to read DIP " 406 "structure\n"); 407 return; 408 } 409 410 /* Make sure the name doesn't over run */ 411 (void) mdb_snprintf(info.driver_name, 412 sizeof (info.driver_name), "%s", name); 413 414 info.instance = dev.devi_instance; 415 info.inum = ih.ih_inum; 416 417 /* 418 * Read the type used, keep PCIe messages 419 * separate. 420 */ 421 (void) mdb_vread(&intr_p, 422 sizeof (devinfo_intr_t), 423 (uintptr_t)dev.devi_intr_p); 424 425 if (ih.ih_rec_type != MSG_REC) { 426 info.intr_type = 427 intr_p.devi_intr_curr_type; 428 } 429 430 if ((ino.ino_ipil_size > 1) || 431 (ipil.ipil_ih_size > 1)) { 432 info.shared = 1; 433 } 434 435 info.num = ih.ih_msg_code; 436 info.intr_state = ih.ih_intr_state; 437 info.ino_ino = ino.ino_ino; 438 info.mondo = ino.ino_sysino; 439 info.pil = ipil.ipil_pil; 440 info.cpuid = ino.ino_cpuid; 441 442 intr_print_elements(info); 443 count++; 444 445 (void) mdb_vread(&ih, sizeof (px_ih_t), 446 (uintptr_t)ih.ih_next); 447 448 } while (count < ipil.ipil_ih_size); 449 450 } while ((ipil.ipil_next_p != NULL) && 451 (mdb_vread(&ipil, sizeof (px_ino_pil_t), 452 (uintptr_t)ipil.ipil_next_p) != -1)); 453 454 } while ((ino.ino_next_p != NULL) && (mdb_vread(&ino, sizeof (px_ino_t), 455 (uintptr_t)ino.ino_next_p) != -1)); 456 } 457 458 static char * 459 intr_get_intr_type(uint16_t type) 460 { 461 switch (type) { 462 case DDI_INTR_TYPE_FIXED: 463 return ("Fixed"); 464 case DDI_INTR_TYPE_MSI: 465 return ("MSI"); 466 case DDI_INTR_TYPE_MSIX: 467 return ("MSI-X"); 468 default: 469 return ("PCIe"); 470 } 471 } 472 473 static void 474 intr_print_banner(void) 475 { 476 if (!detailed) { 477 mdb_printf("\n%<u>\tDevice\t" 478 " Type\t" 479 " MSG #\t" 480 " State\t" 481 " INO\t" 482 " Mondo\t" 483 " Shared\t" 484 " Pil\t" 485 " CPU %</u>" 486 "\n"); 487 } 488 } 489 490 static void 491 intr_print_elements(intr_info_t info) 492 { 493 if (!detailed) { 494 mdb_printf(" %11s#%d\t", info.driver_name, info.instance); 495 mdb_printf(" %s\t", intr_get_intr_type(info.intr_type)); 496 if (info.intr_type == DDI_INTR_TYPE_FIXED) { 497 mdb_printf(" --- \t"); 498 } else { 499 mdb_printf(" %4d\t", info.num); 500 } 501 mdb_printf(" %2s\t", 502 info.intr_state ? "enbl" : "disbl"); 503 mdb_printf(" 0x%x\t", info.ino_ino); 504 mdb_printf(" 0x%x\t", info.mondo); 505 mdb_printf(" %5s\t", 506 info.shared ? "yes" : "no"); 507 mdb_printf(" %4d\t", info.pil); 508 mdb_printf(" %3d \n", info.cpuid); 509 } else { 510 mdb_printf("\n-------------------------------------------\n"); 511 mdb_printf("Device:\t\t%s\n", info.driver_name); 512 mdb_printf("Instance:\t%d\n", info.instance); 513 mdb_printf("Path:\t\t%s\n", info.pathname); 514 mdb_printf("Inum:\t\t%d\n", info.inum); 515 mdb_printf("Interrupt Type:\t%s\n", 516 intr_get_intr_type(info.intr_type)); 517 if (info.intr_type == DDI_INTR_TYPE_MSI) { 518 mdb_printf("MSI Number:\t%d\n", info.num); 519 } else if (info.intr_type == DDI_INTR_TYPE_MSIX) { 520 mdb_printf("MSI-X Number:\t%d\n", info.num); 521 } else if (!info.intr_type) { 522 mdb_printf("PCIe Message #:\t%d\n", info.num); 523 } 524 525 mdb_printf("Shared Intr:\t%s\n", 526 info.shared ? "yes" : "no"); 527 mdb_printf("State:\t\t%d (%s)\n", info.intr_state, 528 info.intr_state ? "Enabled" : "Disabled"); 529 mdb_printf("INO:\t\t0x%x\n", info.ino_ino); 530 mdb_printf("Mondo:\t\t0x%x\n", info.mondo); 531 mdb_printf("Pil:\t\t%d\n", info.pil); 532 mdb_printf("CPU:\t\t%d\n", info.cpuid); 533 } 534 } 535 536 /*ARGSUSED*/ 537 static void 538 intr_walk_fini(mdb_walk_state_t *wsp) 539 { 540 /* Nothing to do here */ 541 } 542 543 /*ARGSUSED*/ 544 static int 545 intr_intr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 546 { 547 detailed = 0; 548 549 if (mdb_getopts(argc, argv, 'd', MDB_OPT_SETBITS, TRUE, &detailed, 550 NULL) != argc) 551 return (DCMD_USAGE); 552 553 if (!(flags & DCMD_ADDRSPEC)) { 554 if (mdb_walk_dcmd("interrupts", "interrupts", argc, argv) 555 == -1) { 556 mdb_warn("can't walk pci/px buffer entries\n"); 557 return (DCMD_ERR); 558 } 559 return (DCMD_OK); 560 } 561 562 return (DCMD_OK); 563 } 564 565 /* 566 * MDB module linkage information: 567 */ 568 569 static const mdb_dcmd_t dcmds[] = { 570 { "interrupts", "[-d]", "display the interrupt info registered with " 571 "the PCI/PX nexus drivers", intr_intr }, 572 { NULL } 573 }; 574 575 static const mdb_walker_t walkers[] = { 576 { "interrupts", "walk PCI/PX interrupt structures", 577 intr_walk_init, intr_walk_step, intr_walk_fini }, 578 { NULL } 579 }; 580 581 static const mdb_modinfo_t modinfo = { 582 MDB_API_VERSION, dcmds, walkers 583 }; 584 585 const mdb_modinfo_t * 586 _mdb_init(void) 587 { 588 return (&modinfo); 589 } 590