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