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