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 pci_ib; 169 ib_ino_info_t *ib_ino_lst; 170 ib_ino_info_t list; 171 ih_t ih; 172 int count; 173 char name[MODMAXNAMELEN + 1]; 174 struct dev_info devinfo; 175 intr_info_t info; 176 177 if (mdb_vread(&pci_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 ib_ino_lst = pci_ib.ib_ino_lst; 186 if (mdb_vread(&list, sizeof (ib_ino_info_t), 187 (uintptr_t)ib_ino_lst) == -1) { 188 /* Nothing here to read from */ 189 return; 190 } 191 192 do { 193 if (mdb_vread(&ih, sizeof (ih_t), 194 (uintptr_t)list.ino_ih_start) == -1) { 195 mdb_warn("intr: failed to read pci interrupt entry " 196 "structure\n"); 197 return; 198 } 199 200 count = 0; 201 202 do { 203 bzero((void *)&info, sizeof (intr_info_t)); 204 205 if (list.ino_ih_size > 1) { 206 info.shared = 1; 207 } 208 209 (void) mdb_devinfo2driver((uintptr_t)ih.ih_dip, 210 name, sizeof (name)); 211 212 (void) mdb_ddi_pathname((uintptr_t)ih.ih_dip, 213 info.pathname, sizeof (info.pathname)); 214 215 /* Get instance */ 216 if (mdb_vread(&devinfo, sizeof (struct dev_info), 217 (uintptr_t)ih.ih_dip) == -1) { 218 mdb_warn("intr: failed to read DIP " 219 "structure\n"); 220 return; 221 } 222 223 /* Make sure the name doesn't over run */ 224 (void) mdb_snprintf(info.driver_name, 225 sizeof (info.driver_name), "%s", name); 226 227 info.instance = devinfo.devi_instance; 228 info.inum = ih.ih_inum; 229 info.intr_type = DDI_INTR_TYPE_FIXED; 230 info.num = 0; 231 info.intr_state = ih.ih_intr_state; 232 info.ino_ino = list.ino_ino; 233 info.mondo = list.ino_mondo; 234 info.pil = list.ino_pil; 235 info.cpuid = list.ino_cpuid; 236 237 intr_print_elements(info); 238 count++; 239 240 (void) mdb_vread(&ih, sizeof (ih_t), 241 (uintptr_t)ih.ih_next); 242 243 } while (count < list.ino_ih_size); 244 245 } while (mdb_vread(&list, sizeof (ib_ino_info_t), 246 (uintptr_t)list.ino_next) != -1); 247 } 248 249 static void 250 intr_px_print_items(mdb_walk_state_t *wsp) 251 { 252 px_ib_t px_ib; 253 px_ib_ino_info_t *px_ib_ino_lst; 254 px_ib_ino_info_t px_list; 255 px_ih_t px_ih; 256 int count; 257 char name[MODMAXNAMELEN + 1]; 258 struct dev_info devinfo; 259 intr_info_t info; 260 devinfo_intr_t intr_p; 261 262 if (mdb_vread(&px_ib, sizeof (px_ib_t), wsp->walk_addr) == -1) { 263 mdb_warn("intr: failed to read px interrupt block " 264 "structure\n"); 265 return; 266 } 267 268 /* Read in px_ib_ino_info_t structure at address */ 269 px_ib_ino_lst = px_ib.ib_ino_lst; 270 if (mdb_vread(&px_list, sizeof (px_ib_ino_info_t), 271 (uintptr_t)px_ib_ino_lst) == -1) { 272 /* Nothing here to read from */ 273 return; 274 } 275 276 do { 277 if (mdb_vread(&px_ih, sizeof (px_ih_t), 278 (uintptr_t)px_list.ino_ih_start) == -1) { 279 mdb_warn("intr: failed to read px interrupt entry " 280 "structure\n"); 281 return; 282 } 283 284 count = 0; 285 286 do { 287 bzero((void *)&info, sizeof (intr_info_t)); 288 289 if (px_list.ino_ih_size > 1) { 290 info.shared = 1; 291 } 292 293 (void) mdb_devinfo2driver((uintptr_t)px_ih.ih_dip, 294 name, sizeof (name)); 295 296 (void) mdb_ddi_pathname((uintptr_t)px_ih.ih_dip, 297 info.pathname, sizeof (info.pathname)); 298 299 /* Get instance */ 300 if (mdb_vread(&devinfo, sizeof (struct dev_info), 301 (uintptr_t)px_ih.ih_dip) == -1) { 302 mdb_warn("intr: failed to read DIP " 303 "structure\n"); 304 return; 305 } 306 307 /* Make sure the name doesn't over run */ 308 (void) mdb_snprintf(info.driver_name, 309 sizeof (info.driver_name), "%s", name); 310 311 info.instance = devinfo.devi_instance; 312 info.inum = px_ih.ih_inum; 313 314 /* Read the type used, keep PCIe messages separate */ 315 (void) mdb_vread(&intr_p, sizeof (devinfo_intr_t), 316 (uintptr_t)devinfo.devi_intr_p); 317 if (px_ih.ih_rec_type != MSG_REC) { 318 info.intr_type = intr_p.devi_intr_curr_type; 319 } 320 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 340 static char * 341 intr_get_intr_type(uint16_t type) 342 { 343 switch (type) { 344 case DDI_INTR_TYPE_FIXED: 345 return ("Fixed"); 346 case DDI_INTR_TYPE_MSI: 347 return ("MSI"); 348 case DDI_INTR_TYPE_MSIX: 349 return ("MSI-X"); 350 default: 351 return ("PCIe"); 352 } 353 } 354 355 static void 356 intr_print_banner(void) 357 { 358 if (!detailed) { 359 mdb_printf("\n%<u>\tDevice\t" 360 " Shared\t" 361 " Type\t" 362 " MSG #\t" 363 " State\t" 364 " INO\t" 365 " Mondo\t" 366 " Pil\t" 367 " CPU %</u>" 368 "\n"); 369 } 370 } 371 372 static void 373 intr_print_elements(intr_info_t info) 374 { 375 if (!detailed) { 376 mdb_printf(" %11s#%d\t", info.driver_name, info.instance); 377 mdb_printf(" %5s\t", 378 info.shared ? "yes" : "no"); 379 mdb_printf(" %s\t", intr_get_intr_type(info.intr_type)); 380 if (info.intr_type == DDI_INTR_TYPE_FIXED) { 381 mdb_printf(" --- \t"); 382 } else { 383 mdb_printf(" %4d\t", info.num); 384 } 385 386 mdb_printf(" %2s\t", 387 info.intr_state ? "enbl" : "disbl"); 388 mdb_printf(" 0x%x\t", info.ino_ino); 389 mdb_printf(" 0x%x\t", info.mondo); 390 mdb_printf(" %4d\t", info.pil); 391 mdb_printf(" %3d \n", info.cpuid); 392 } else { 393 mdb_printf("\n-------------------------------------------\n"); 394 mdb_printf("Device:\t\t%s\n", info.driver_name); 395 mdb_printf("Instance:\t%d\n", info.instance); 396 mdb_printf("Path:\t\t%s\n", info.pathname); 397 mdb_printf("Inum:\t\t%d\n", info.inum); 398 mdb_printf("Interrupt Type:\t%s\n", 399 intr_get_intr_type(info.intr_type)); 400 if (info.intr_type == DDI_INTR_TYPE_MSI) { 401 mdb_printf("MSI Number:\t%d\n", info.num); 402 } else if (info.intr_type == DDI_INTR_TYPE_MSIX) { 403 mdb_printf("MSI-X Number:\t%d\n", info.num); 404 } else if (!info.intr_type) { 405 mdb_printf("PCIe Message #:\t%d\n", info.num); 406 } 407 408 mdb_printf("Shared Intr:\t%s\n", 409 info.shared ? "yes" : "no"); 410 mdb_printf("State:\t\t%d (%s)\n", info.intr_state, 411 info.intr_state ? "Enabled" : "Disabled"); 412 mdb_printf("INO:\t\t0x%x\n", info.ino_ino); 413 mdb_printf("Mondo:\t\t0x%x\n", info.mondo); 414 mdb_printf("Pil:\t\t%d\n", info.pil); 415 mdb_printf("CPU:\t\t%d\n", info.cpuid); 416 } 417 } 418 419 /*ARGSUSED*/ 420 static void 421 intr_walk_fini(mdb_walk_state_t *wsp) 422 { 423 /* Nothing to do here */ 424 } 425 426 /*ARGSUSED*/ 427 static int 428 intr_intr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 429 { 430 detailed = 0; 431 432 if (mdb_getopts(argc, argv, 'd', MDB_OPT_SETBITS, TRUE, &detailed, 433 NULL) != argc) 434 return (DCMD_USAGE); 435 436 if (!(flags & DCMD_ADDRSPEC)) { 437 if (mdb_walk_dcmd("interrupts", "interrupts", argc, argv) 438 == -1) { 439 mdb_warn("can't walk pci/px buffer entries\n"); 440 return (DCMD_ERR); 441 } 442 return (DCMD_OK); 443 } 444 445 return (DCMD_OK); 446 } 447 448 /* 449 * MDB module linkage information: 450 */ 451 452 static const mdb_dcmd_t dcmds[] = { 453 { "interrupts", "[-d]", "display the interrupt info registered with " 454 "the PCI/PX nexus drivers", intr_intr }, 455 { NULL } 456 }; 457 458 static const mdb_walker_t walkers[] = { 459 { "interrupts", "walk PCI/PX interrupt structures", 460 intr_walk_init, intr_walk_step, intr_walk_fini }, 461 { NULL } 462 }; 463 464 static const mdb_modinfo_t modinfo = { 465 MDB_API_VERSION, dcmds, walkers 466 }; 467 468 const mdb_modinfo_t * 469 _mdb_init(void) 470 { 471 return (&modinfo); 472 } 473