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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <sys/mdb_modapi.h> 30 #include <mdb/mdb_ks.h> 31 #include <sys/async.h> /* ecc_flt for pci_ecc.h */ 32 #include <sys/ddi_subrdefs.h> 33 #include <sys/pci/pci_obj.h> 34 #include "px_obj.h" 35 36 static int intr_pci_walk_step(mdb_walk_state_t *); 37 static int intr_px_walk_step(mdb_walk_state_t *); 38 static void intr_pci_print_items(mdb_walk_state_t *); 39 static void intr_px_print_items(mdb_walk_state_t *); 40 static char *intr_get_intr_type(msiq_rec_type_t); 41 static void intr_print_line(int); 42 static void intr_print_banner(void); 43 44 typedef struct intr_info { 45 uint32_t cpuid; 46 uint32_t inum; 47 uint32_t num; 48 uint32_t pil; 49 uint16_t mondo; 50 uint8_t ino_ino; 51 uint_t intr_state; 52 int instance; 53 int shared; 54 msiq_rec_type_t intr_type; 55 char driver_name[12]; 56 char pathname[MAXNAMELEN]; 57 } 58 intr_info_t; 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 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 while (mdb_vread(&px_state_p, sizeof (uintptr_t), 147 (uintptr_t)start_addr) != -1) { 148 /* Read until nothing is left */ 149 if (mdb_vread(&px_state, sizeof (px_t), 150 (uintptr_t)px_state_p) == -1) { 151 return (WALK_DONE); 152 } 153 154 wsp->walk_addr = (uintptr_t)px_state.px_ib_p; 155 intr_px_print_items(wsp); 156 157 start_addr += sizeof (uintptr_t); 158 } 159 160 return (WALK_DONE); 161 } 162 163 static void 164 intr_pci_print_items(mdb_walk_state_t *wsp) 165 { 166 ib_t pci_ib; 167 ib_ino_info_t *ib_ino_lst; 168 ib_ino_info_t list; 169 ih_t ih; 170 int count; 171 char name[MODMAXNAMELEN + 1]; 172 struct dev_info devinfo; 173 intr_info_t info; 174 175 if (mdb_vread(&pci_ib, sizeof (ib_t), 176 (uintptr_t)wsp->walk_addr) == -1) { 177 mdb_warn("intr: failed to read pci interrupt block " 178 "structure\n"); 179 return; 180 } 181 182 /* Read in ib_ino_info_t structure at address */ 183 ib_ino_lst = pci_ib.ib_ino_lst; 184 if (mdb_vread(&list, sizeof (ib_ino_info_t), 185 (uintptr_t)ib_ino_lst) == -1) { 186 /* Nothing here to read from */ 187 return; 188 } 189 190 intr_print_line(77); 191 intr_print_banner(); 192 intr_print_line(77); 193 194 do { 195 if (mdb_vread(&ih, sizeof (ih_t), 196 (uintptr_t)list.ino_ih_start) == -1) { 197 mdb_warn("intr: failed to read pci interrupt entry " 198 "structure\n"); 199 return; 200 } 201 202 count = 0; 203 204 do { 205 bzero((void *)&info, sizeof (intr_info_t)); 206 207 if (list.ino_ih_size > 1) { 208 info.shared = 1; 209 } 210 211 (void) mdb_devinfo2driver((uintptr_t)ih.ih_dip, 212 name, sizeof (name)); 213 214 (void) mdb_ddi_pathname((uintptr_t)ih.ih_dip, 215 info.pathname, sizeof (info.pathname)); 216 217 /* Get instance */ 218 if (mdb_vread(&devinfo, sizeof (struct dev_info), 219 (uintptr_t)ih.ih_dip) == -1) { 220 mdb_warn("intr: failed to read DIP " 221 "structure\n"); 222 return; 223 } 224 225 /* Make sure the name doesn't over run */ 226 (void) mdb_snprintf(info.driver_name, 227 sizeof (info.driver_name), "%s", name); 228 229 info.instance = devinfo.devi_instance; 230 info.inum = ih.ih_inum; 231 info.intr_type = INTX_REC; 232 info.num = 0; 233 info.intr_state = ih.ih_intr_state; 234 info.ino_ino = list.ino_ino; 235 info.mondo = list.ino_mondo; 236 info.pil = list.ino_pil; 237 info.cpuid = list.ino_cpuid; 238 239 intr_print_elements(info); 240 count++; 241 242 (void) mdb_vread(&ih, sizeof (ih_t), 243 (uintptr_t)ih.ih_next); 244 245 } while (count < list.ino_ih_size); 246 247 } while (mdb_vread(&list, sizeof (ib_ino_info_t), 248 (uintptr_t)list.ino_next) != -1); 249 250 intr_print_line(77); 251 } 252 253 static void 254 intr_px_print_items(mdb_walk_state_t *wsp) 255 { 256 px_ib_t px_ib; 257 px_ib_ino_info_t *px_ib_ino_lst; 258 px_ib_ino_info_t px_list; 259 px_ih_t px_ih; 260 int count; 261 char name[MODMAXNAMELEN + 1]; 262 struct dev_info devinfo; 263 intr_info_t info; 264 265 if (mdb_vread(&px_ib, sizeof (px_ib_t), wsp->walk_addr) == -1) { 266 mdb_warn("intr: failed to read px interrupt block " 267 "structure\n"); 268 return; 269 } 270 271 /* Read in px_ib_ino_info_t structure at address */ 272 px_ib_ino_lst = px_ib.ib_ino_lst; 273 if (mdb_vread(&px_list, sizeof (px_ib_ino_info_t), 274 (uintptr_t)px_ib_ino_lst) == -1) { 275 /* Nothing here to read from */ 276 return; 277 } 278 279 intr_print_line(77); 280 intr_print_banner(); 281 intr_print_line(77); 282 283 do { 284 if (mdb_vread(&px_ih, sizeof (px_ih_t), 285 (uintptr_t)px_list.ino_ih_start) == -1) { 286 mdb_warn("intr: failed to read px interrupt entry " 287 "structure\n"); 288 return; 289 } 290 291 count = 0; 292 293 do { 294 bzero((void *)&info, sizeof (intr_info_t)); 295 296 if (px_list.ino_ih_size > 1) { 297 info.shared = 1; 298 } 299 300 (void) mdb_devinfo2driver((uintptr_t)px_ih.ih_dip, 301 name, sizeof (name)); 302 303 (void) mdb_ddi_pathname((uintptr_t)px_ih.ih_dip, 304 info.pathname, sizeof (info.pathname)); 305 306 /* Get instance */ 307 if (mdb_vread(&devinfo, sizeof (struct dev_info), 308 (uintptr_t)px_ih.ih_dip) == -1) { 309 mdb_warn("intr: failed to read DIP " 310 "structure\n"); 311 return; 312 } 313 314 /* Make sure the name doesn't over run */ 315 (void) mdb_snprintf(info.driver_name, 316 sizeof (info.driver_name), "%s", name); 317 318 info.instance = devinfo.devi_instance; 319 info.inum = px_ih.ih_inum; 320 info.intr_type = px_ih.ih_rec_type; 321 info.num = px_ih.ih_msg_code; 322 info.intr_state = px_ih.ih_intr_state; 323 info.ino_ino = px_list.ino_ino; 324 info.mondo = px_list.ino_sysino; 325 info.pil = px_list.ino_pil; 326 info.cpuid = px_list.ino_cpuid; 327 328 intr_print_elements(info); 329 count++; 330 331 (void) mdb_vread(&px_ih, sizeof (ih_t), 332 (uintptr_t)px_ih.ih_next); 333 334 } while (count < px_list.ino_ih_size); 335 336 } while (mdb_vread(&px_list, sizeof (px_ib_ino_info_t), 337 (uintptr_t)px_list.ino_next) != -1); 338 339 intr_print_line(77); 340 } 341 342 static char * 343 intr_get_intr_type(msiq_rec_type_t rec_type) 344 { 345 switch (rec_type) { 346 case MSG_REC: 347 return ("PCIe"); 348 case MSI32_REC: 349 case MSI64_REC: 350 return ("MSI"); 351 case INTX_REC: 352 default: 353 return ("Fixed"); 354 } 355 } 356 357 static void 358 intr_print_line(int cnt) 359 { 360 int x; 361 362 if (!detailed) { 363 mdb_printf("+"); 364 for (x = 0; x < cnt; x++) { 365 mdb_printf("-"); 366 } 367 mdb_printf("+\n"); 368 } 369 } 370 371 static void 372 intr_print_banner(void) 373 { 374 if (!detailed) { 375 mdb_printf("| Device\t" 376 "| Shard\t" 377 "| Type\t" 378 "| MSG #\t" 379 "| State " 380 "| INO\t" 381 "| Mondo\t" 382 "| Pil\t" 383 "| CPU " 384 "|\n"); 385 } 386 } 387 388 static void 389 intr_print_elements(intr_info_t info) 390 { 391 if (!detailed) { 392 mdb_printf("| %11s#%d\t", info.driver_name, info.instance); 393 mdb_printf("| %s\t", 394 info.shared ? "yes" : "no"); 395 mdb_printf("| %s\t", intr_get_intr_type(info.intr_type)); 396 if (strcmp("Fixed", intr_get_intr_type(info.intr_type)) == 0) { 397 mdb_printf("| --- \t"); 398 } else { 399 mdb_printf("| %4d\t", info.num); 400 } 401 402 mdb_printf("| %2s\t", 403 info.intr_state ? "enbl" : "disbl"); 404 mdb_printf("| 0x%x\t", info.ino_ino); 405 mdb_printf("| 0x%x", info.mondo); 406 if (!(info.mondo & 0xF000)) { /* Don't overrun table width */ 407 mdb_printf("\t"); 408 } 409 mdb_printf("| %4d\t", info.pil); 410 mdb_printf("| %3d |\n", info.cpuid); 411 } else { 412 mdb_printf("\n-------------------------------------------\n"); 413 mdb_printf("Device:\t\t%s\n", info.driver_name); 414 mdb_printf("Instance:\t%d\n", info.instance); 415 mdb_printf("Path:\t\t%s\n", info.pathname); 416 mdb_printf("Inum:\t\t%d\n", info.inum); 417 mdb_printf("Interrupt Type:\t%s\n", 418 intr_get_intr_type(info.intr_type)); 419 if (strcmp("MSI", intr_get_intr_type(info.intr_type)) == 0) 420 mdb_printf("MSI/X Number:\t%s\n", info.num); 421 422 mdb_printf("Shared Intr:\t%s\n", 423 info.shared ? "yes" : "no"); 424 mdb_printf("State:\t\t%d (%s)\n", info.intr_state, 425 info.intr_state ? "Enabled" : "Disabled"); 426 mdb_printf("INO:\t\t0x%x\n", info.ino_ino); 427 mdb_printf("Mondo:\t\t0x%x\n", info.mondo); 428 mdb_printf("Pil:\t\t%d\n", info.pil); 429 mdb_printf("CPU:\t\t%d\n", info.cpuid); 430 } 431 } 432 433 /*ARGSUSED*/ 434 static void 435 intr_walk_fini(mdb_walk_state_t *wsp) 436 { 437 /* Nothing to do here */ 438 } 439 440 /*ARGSUSED*/ 441 static int 442 intr_intr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 443 { 444 detailed = 0; 445 446 if (mdb_getopts(argc, argv, 'd', MDB_OPT_SETBITS, TRUE, &detailed, 447 NULL) != argc) 448 return (DCMD_USAGE); 449 450 if (!(flags & DCMD_ADDRSPEC)) { 451 if (mdb_walk_dcmd("interrupts", "interrupts", argc, argv) 452 == -1) { 453 mdb_warn("can't walk pci/px buffer entries\n"); 454 return (DCMD_ERR); 455 } 456 return (DCMD_OK); 457 } 458 459 return (DCMD_OK); 460 } 461 462 /* 463 * MDB module linkage information: 464 */ 465 466 static const mdb_dcmd_t dcmds[] = { 467 { "interrupts", "[-d]", "display the interrupt info registered with " 468 "the PCI/PX nexus drivers", intr_intr }, 469 { NULL } 470 }; 471 472 static const mdb_walker_t walkers[] = { 473 { "interrupts", "walk PCI/PX interrupt structures", 474 intr_walk_init, intr_walk_step, intr_walk_fini }, 475 { NULL } 476 }; 477 478 static const mdb_modinfo_t modinfo = { 479 MDB_API_VERSION, dcmds, walkers 480 }; 481 482 const mdb_modinfo_t * 483 _mdb_init(void) 484 { 485 return (&modinfo); 486 } 487