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 ((info.intr_type == DDI_INTR_TYPE_FIXED) && 339 ((ino.ino_ipil_size > 1) || 340 (ipil.ipil_ih_size > 1))) { 341 info.shared = 1; 342 } 343 344 info.num = ih.ih_msg_code; 345 info.intr_state = ih.ih_intr_state; 346 info.ino_ino = ino.ino_ino; 347 info.mondo = ino.ino_sysino; 348 info.pil = ipil.ipil_pil; 349 info.cpuid = ino.ino_cpuid; 350 351 intr_print_elements(info); 352 count++; 353 354 (void) mdb_vread(&ih, sizeof (px_ih_t), 355 (uintptr_t)ih.ih_next); 356 357 } while (count < ipil.ipil_ih_size); 358 359 } while ((ipil.ipil_next_p != NULL) && 360 (mdb_vread(&ipil, sizeof (px_ino_pil_t), 361 (uintptr_t)ipil.ipil_next_p) != -1)); 362 363 } while ((ino.ino_next_p != NULL) && (mdb_vread(&ino, sizeof (px_ino_t), 364 (uintptr_t)ino.ino_next_p) != -1)); 365 } 366 367 static char * 368 intr_get_intr_type(uint16_t type) 369 { 370 switch (type) { 371 case DDI_INTR_TYPE_FIXED: 372 return ("Fixed"); 373 case DDI_INTR_TYPE_MSI: 374 return ("MSI"); 375 case DDI_INTR_TYPE_MSIX: 376 return ("MSI-X"); 377 default: 378 return ("PCIe"); 379 } 380 } 381 382 static void 383 intr_print_banner(void) 384 { 385 if (!detailed) { 386 mdb_printf("\n%<u>\tDevice\t" 387 " Shared\t" 388 " Type\t" 389 " MSG #\t" 390 " State\t" 391 " INO\t" 392 " Mondo\t" 393 " Pil\t" 394 " CPU %</u>" 395 "\n"); 396 } 397 } 398 399 static void 400 intr_print_elements(intr_info_t info) 401 { 402 if (!detailed) { 403 mdb_printf(" %11s#%d\t", info.driver_name, info.instance); 404 mdb_printf(" %5s\t", 405 info.shared ? "yes" : "no"); 406 mdb_printf(" %s\t", intr_get_intr_type(info.intr_type)); 407 if (info.intr_type == DDI_INTR_TYPE_FIXED) { 408 mdb_printf(" --- \t"); 409 } else { 410 mdb_printf(" %4d\t", info.num); 411 } 412 413 mdb_printf(" %2s\t", 414 info.intr_state ? "enbl" : "disbl"); 415 mdb_printf(" 0x%x\t", info.ino_ino); 416 mdb_printf(" 0x%x\t", info.mondo); 417 mdb_printf(" %4d\t", info.pil); 418 mdb_printf(" %3d \n", info.cpuid); 419 } else { 420 mdb_printf("\n-------------------------------------------\n"); 421 mdb_printf("Device:\t\t%s\n", info.driver_name); 422 mdb_printf("Instance:\t%d\n", info.instance); 423 mdb_printf("Path:\t\t%s\n", info.pathname); 424 mdb_printf("Inum:\t\t%d\n", info.inum); 425 mdb_printf("Interrupt Type:\t%s\n", 426 intr_get_intr_type(info.intr_type)); 427 if (info.intr_type == DDI_INTR_TYPE_MSI) { 428 mdb_printf("MSI Number:\t%d\n", info.num); 429 } else if (info.intr_type == DDI_INTR_TYPE_MSIX) { 430 mdb_printf("MSI-X Number:\t%d\n", info.num); 431 } else if (!info.intr_type) { 432 mdb_printf("PCIe Message #:\t%d\n", info.num); 433 } 434 435 mdb_printf("Shared Intr:\t%s\n", 436 info.shared ? "yes" : "no"); 437 mdb_printf("State:\t\t%d (%s)\n", info.intr_state, 438 info.intr_state ? "Enabled" : "Disabled"); 439 mdb_printf("INO:\t\t0x%x\n", info.ino_ino); 440 mdb_printf("Mondo:\t\t0x%x\n", info.mondo); 441 mdb_printf("Pil:\t\t%d\n", info.pil); 442 mdb_printf("CPU:\t\t%d\n", info.cpuid); 443 } 444 } 445 446 /*ARGSUSED*/ 447 static void 448 intr_walk_fini(mdb_walk_state_t *wsp) 449 { 450 /* Nothing to do here */ 451 } 452 453 /*ARGSUSED*/ 454 static int 455 intr_intr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 456 { 457 detailed = 0; 458 459 if (mdb_getopts(argc, argv, 'd', MDB_OPT_SETBITS, TRUE, &detailed, 460 NULL) != argc) 461 return (DCMD_USAGE); 462 463 if (!(flags & DCMD_ADDRSPEC)) { 464 if (mdb_walk_dcmd("interrupts", "interrupts", argc, argv) 465 == -1) { 466 mdb_warn("can't walk pci/px buffer entries\n"); 467 return (DCMD_ERR); 468 } 469 return (DCMD_OK); 470 } 471 472 return (DCMD_OK); 473 } 474 475 /* 476 * MDB module linkage information: 477 */ 478 479 static const mdb_dcmd_t dcmds[] = { 480 { "interrupts", "[-d]", "display the interrupt info registered with " 481 "the PCI/PX nexus drivers", intr_intr }, 482 { NULL } 483 }; 484 485 static const mdb_walker_t walkers[] = { 486 { "interrupts", "walk PCI/PX interrupt structures", 487 intr_walk_init, intr_walk_step, intr_walk_fini }, 488 { NULL } 489 }; 490 491 static const mdb_modinfo_t modinfo = { 492 MDB_API_VERSION, dcmds, walkers 493 }; 494 495 const mdb_modinfo_t * 496 _mdb_init(void) 497 { 498 return (&modinfo); 499 } 500