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