1909Segillett /* 2909Segillett * CDDL HEADER START 3909Segillett * 4909Segillett * The contents of this file are subject to the terms of the 51725Segillett * Common Development and Distribution License (the "License"). 61725Segillett * You may not use this file except in compliance with the License. 7909Segillett * 8909Segillett * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9909Segillett * or http://www.opensolaris.org/os/licensing. 10909Segillett * See the License for the specific language governing permissions 11909Segillett * and limitations under the License. 12909Segillett * 13909Segillett * When distributing Covered Code, include this CDDL HEADER in each 14909Segillett * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15909Segillett * If applicable, add the following below this CDDL HEADER, with the 16909Segillett * fields enclosed by brackets "[]" replaced with your own identifying 17909Segillett * information: Portions Copyright [yyyy] [name of copyright owner] 18909Segillett * 19909Segillett * CDDL HEADER END 20909Segillett */ 21909Segillett /* 221725Segillett * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23909Segillett * Use is subject to license terms. 24909Segillett */ 25909Segillett 26909Segillett #pragma ident "%Z%%M% %I% %E% SMI" 27909Segillett 28909Segillett #include <sys/mdb_modapi.h> 29909Segillett #include <mdb/mdb_ks.h> 30909Segillett #include <sys/async.h> /* ecc_flt for pci_ecc.h */ 31909Segillett #include <sys/ddi_subrdefs.h> 32909Segillett #include <sys/pci/pci_obj.h> 33909Segillett #include "px_obj.h" 34909Segillett 35909Segillett static int intr_pci_walk_step(mdb_walk_state_t *); 36909Segillett static int intr_px_walk_step(mdb_walk_state_t *); 37909Segillett static void intr_pci_print_items(mdb_walk_state_t *); 38909Segillett static void intr_px_print_items(mdb_walk_state_t *); 391725Segillett static char *intr_get_intr_type(uint16_t type); 40909Segillett static void intr_print_banner(void); 41909Segillett 42909Segillett typedef struct intr_info { 43909Segillett uint32_t cpuid; 44909Segillett uint32_t inum; 45909Segillett uint32_t num; 46909Segillett uint32_t pil; 471725Segillett uint16_t intr_type; 48909Segillett uint16_t mondo; 49909Segillett uint8_t ino_ino; 50909Segillett uint_t intr_state; 51909Segillett int instance; 52909Segillett int shared; 53909Segillett char driver_name[12]; 54909Segillett char pathname[MAXNAMELEN]; 55909Segillett } 56909Segillett intr_info_t; 57909Segillett 58909Segillett static void intr_print_elements(intr_info_t); 59909Segillett static int detailed = 0; /* Print detailed view */ 60909Segillett 61909Segillett 62909Segillett static int 63909Segillett intr_walk_init(mdb_walk_state_t *wsp) 64909Segillett { 65909Segillett wsp->walk_addr = NULL; 66909Segillett 67909Segillett return (WALK_NEXT); 68909Segillett } 69909Segillett 70909Segillett static int 71909Segillett intr_walk_step(mdb_walk_state_t *wsp) 72909Segillett { 73909Segillett pci_t *pci_per_p; 74909Segillett px_t *px_state_p; 75909Segillett 76909Segillett /* read globally declared structures in the pci driver */ 77909Segillett if (mdb_readvar(&pci_per_p, "per_pci_state") != -1) { 78909Segillett wsp->walk_addr = (uintptr_t)pci_per_p; 79909Segillett intr_pci_walk_step(wsp); 80909Segillett } 81909Segillett 82909Segillett /* read globally declared structures in the px driver */ 83909Segillett if (mdb_readvar(&px_state_p, "px_state_p") != -1) { 84909Segillett wsp->walk_addr = (uintptr_t)px_state_p; 85909Segillett intr_px_walk_step(wsp); 86909Segillett } 87909Segillett 88909Segillett return (WALK_DONE); 89909Segillett } 90909Segillett 91909Segillett static int 92909Segillett intr_pci_walk_step(mdb_walk_state_t *wsp) 93909Segillett { 94909Segillett pci_t *pci_per_p; 95909Segillett pci_t pci_per; 96909Segillett uintptr_t start_addr; 97909Segillett 98909Segillett /* Read start of state structure array */ 99909Segillett if (mdb_vread(&pci_per_p, sizeof (uintptr_t), 100909Segillett (uintptr_t)wsp->walk_addr) == -1) { 101909Segillett mdb_warn("intr: failed to read the initial pci_per_p " 102909Segillett "structure\n"); 103909Segillett return (WALK_ERR); 104909Segillett } 105909Segillett 106909Segillett /* Figure out how many items are here */ 107909Segillett start_addr = (uintptr_t)pci_per_p; 108909Segillett 109965Sgovinda intr_print_banner(); 110965Sgovinda 111909Segillett while (mdb_vread(&pci_per_p, sizeof (uintptr_t), 112909Segillett (uintptr_t)start_addr) != -1) { 113909Segillett /* Read until nothing is left */ 114909Segillett if (mdb_vread(&pci_per, sizeof (pci_t), 115909Segillett (uintptr_t)pci_per_p) == -1) { 116909Segillett return (WALK_DONE); 117909Segillett } 118909Segillett 119909Segillett wsp->walk_addr = (uintptr_t)pci_per.pci_ib_p; 120909Segillett intr_pci_print_items(wsp); 121909Segillett 122909Segillett start_addr += sizeof (uintptr_t); 123909Segillett } 124909Segillett 125909Segillett return (WALK_DONE); 126909Segillett } 127909Segillett 128909Segillett static int 129909Segillett intr_px_walk_step(mdb_walk_state_t *wsp) 130909Segillett { 131909Segillett px_t *px_state_p; 132909Segillett px_t px_state; 133909Segillett uintptr_t start_addr; 134909Segillett 135909Segillett /* Read start of state structure array */ 136909Segillett if (mdb_vread(&px_state_p, sizeof (uintptr_t), 137909Segillett (uintptr_t)wsp->walk_addr) == -1) { 138909Segillett mdb_warn("intr: failed to read the initial px_per_p " 139909Segillett "structure\n"); 140909Segillett return (WALK_ERR); 141909Segillett } 142909Segillett 143909Segillett /* Figure out how many items are here */ 144909Segillett start_addr = (uintptr_t)px_state_p; 145909Segillett 146965Sgovinda intr_print_banner(); 147965Sgovinda 148909Segillett while (mdb_vread(&px_state_p, sizeof (uintptr_t), 149909Segillett (uintptr_t)start_addr) != -1) { 150909Segillett /* Read until nothing is left */ 151909Segillett if (mdb_vread(&px_state, sizeof (px_t), 152909Segillett (uintptr_t)px_state_p) == -1) { 153909Segillett return (WALK_DONE); 154909Segillett } 155909Segillett 156909Segillett wsp->walk_addr = (uintptr_t)px_state.px_ib_p; 157909Segillett intr_px_print_items(wsp); 158909Segillett 159909Segillett start_addr += sizeof (uintptr_t); 160909Segillett } 161909Segillett 162909Segillett return (WALK_DONE); 163909Segillett } 164909Segillett 165909Segillett static void 166909Segillett intr_pci_print_items(mdb_walk_state_t *wsp) 167909Segillett { 168*2973Sgovinda ib_t ib; 169*2973Sgovinda ib_ino_info_t ino; 170*2973Sgovinda ib_ino_pil_t ipil; 171909Segillett ih_t ih; 172909Segillett int count; 173909Segillett char name[MODMAXNAMELEN + 1]; 174*2973Sgovinda struct dev_info dev; 175909Segillett intr_info_t info; 176909Segillett 177*2973Sgovinda if (mdb_vread(&ib, sizeof (ib_t), 178909Segillett (uintptr_t)wsp->walk_addr) == -1) { 179909Segillett mdb_warn("intr: failed to read pci interrupt block " 180909Segillett "structure\n"); 181909Segillett return; 182909Segillett } 183909Segillett 184909Segillett /* Read in ib_ino_info_t structure at address */ 185*2973Sgovinda if (mdb_vread(&ino, sizeof (ib_ino_info_t), 186*2973Sgovinda (uintptr_t)ib.ib_ino_lst) == -1) { 187909Segillett /* Nothing here to read from */ 188909Segillett return; 189909Segillett } 190909Segillett 191909Segillett do { 192*2973Sgovinda if (mdb_vread(&ipil, sizeof (ib_ino_pil_t), 193*2973Sgovinda (uintptr_t)ino.ino_ipil_p) == -1) { 194*2973Sgovinda mdb_warn("intr: failed to read pci interrupt " 195*2973Sgovinda "ib_ino_pil_t structure\n"); 196909Segillett return; 197909Segillett } 198909Segillett 199909Segillett do { 200*2973Sgovinda if (mdb_vread(&ih, sizeof (ih_t), 201*2973Sgovinda (uintptr_t)ipil.ipil_ih_start) == -1) { 202*2973Sgovinda mdb_warn("intr: failed to read pci interrupt " 203*2973Sgovinda "ih_t structure\n"); 204909Segillett return; 205909Segillett } 206909Segillett 207*2973Sgovinda count = 0; 208*2973Sgovinda 209*2973Sgovinda do { 210*2973Sgovinda bzero((void *)&info, sizeof (intr_info_t)); 211*2973Sgovinda 212*2973Sgovinda if ((ino.ino_ipil_size > 1) || 213*2973Sgovinda (ipil.ipil_ih_size > 1)) { 214*2973Sgovinda info.shared = 1; 215*2973Sgovinda } 216*2973Sgovinda 217*2973Sgovinda (void) mdb_devinfo2driver((uintptr_t)ih.ih_dip, 218*2973Sgovinda name, sizeof (name)); 219*2973Sgovinda 220*2973Sgovinda (void) mdb_ddi_pathname((uintptr_t)ih.ih_dip, 221*2973Sgovinda info.pathname, sizeof (info.pathname)); 222*2973Sgovinda 223*2973Sgovinda /* Get instance */ 224*2973Sgovinda if (mdb_vread(&dev, sizeof (struct dev_info), 225*2973Sgovinda (uintptr_t)ih.ih_dip) == -1) { 226*2973Sgovinda mdb_warn("intr: failed to read DIP " 227*2973Sgovinda "structure\n"); 228*2973Sgovinda return; 229*2973Sgovinda } 230909Segillett 231*2973Sgovinda /* Make sure the name doesn't over run */ 232*2973Sgovinda (void) mdb_snprintf(info.driver_name, 233*2973Sgovinda sizeof (info.driver_name), "%s", name); 234*2973Sgovinda 235*2973Sgovinda info.instance = dev.devi_instance; 236*2973Sgovinda info.inum = ih.ih_inum; 237*2973Sgovinda info.intr_type = DDI_INTR_TYPE_FIXED; 238*2973Sgovinda info.num = 0; 239*2973Sgovinda info.intr_state = ih.ih_intr_state; 240*2973Sgovinda info.ino_ino = ino.ino_ino; 241*2973Sgovinda info.mondo = ino.ino_mondo; 242*2973Sgovinda info.pil = ipil.ipil_pil; 243*2973Sgovinda info.cpuid = ino.ino_cpuid; 244909Segillett 245*2973Sgovinda intr_print_elements(info); 246*2973Sgovinda count++; 247*2973Sgovinda 248*2973Sgovinda (void) mdb_vread(&ih, sizeof (ih_t), 249*2973Sgovinda (uintptr_t)ih.ih_next); 250909Segillett 251*2973Sgovinda } while (count < ipil.ipil_ih_size); 252909Segillett 253*2973Sgovinda } while (mdb_vread(&ipil, sizeof (ib_ino_pil_t), 254*2973Sgovinda (uintptr_t)ipil.ipil_next_p) != -1); 255909Segillett 256*2973Sgovinda } while (mdb_vread(&ino, sizeof (ib_ino_info_t), 257*2973Sgovinda (uintptr_t)ino.ino_next_p) != -1); 258909Segillett } 259909Segillett 260909Segillett static void 261909Segillett intr_px_print_items(mdb_walk_state_t *wsp) 262909Segillett { 263*2973Sgovinda px_ib_t ib; 264*2973Sgovinda px_ino_t ino; 265*2973Sgovinda px_ino_pil_t ipil; 266*2973Sgovinda px_ih_t ih; 267*2973Sgovinda int count; 268*2973Sgovinda char name[MODMAXNAMELEN + 1]; 269*2973Sgovinda struct dev_info dev; 270*2973Sgovinda intr_info_t info; 271*2973Sgovinda devinfo_intr_t intr_p; 272909Segillett 273*2973Sgovinda if (mdb_vread(&ib, sizeof (px_ib_t), wsp->walk_addr) == -1) { 274909Segillett mdb_warn("intr: failed to read px interrupt block " 275909Segillett "structure\n"); 276909Segillett return; 277909Segillett } 278909Segillett 279*2973Sgovinda /* Read in px_ino_t structure at address */ 280*2973Sgovinda if (mdb_vread(&ino, sizeof (px_ino_t), 281*2973Sgovinda (uintptr_t)ib.ib_ino_lst) == -1) { 282909Segillett /* Nothing here to read from */ 283909Segillett return; 284909Segillett } 285909Segillett 286909Segillett do { 287*2973Sgovinda if (mdb_vread(&ipil, sizeof (px_ino_pil_t), 288*2973Sgovinda (uintptr_t)ino.ino_ipil_p) == -1) { 289*2973Sgovinda mdb_warn("intr: failed to read px interrupt " 290*2973Sgovinda "px_ino_pil_t structure\n"); 291909Segillett return; 292909Segillett } 293909Segillett 294909Segillett do { 295*2973Sgovinda if (mdb_vread(&ih, sizeof (px_ih_t), 296*2973Sgovinda (uintptr_t)ipil.ipil_ih_start) == -1) { 297*2973Sgovinda mdb_warn("intr: failed to read px interrupt " 298*2973Sgovinda "px_ih_t structure\n"); 299909Segillett return; 300909Segillett } 301909Segillett 302*2973Sgovinda count = 0; 303*2973Sgovinda 304*2973Sgovinda do { 305*2973Sgovinda bzero((void *)&info, sizeof (intr_info_t)); 306909Segillett 307*2973Sgovinda (void) mdb_devinfo2driver((uintptr_t)ih.ih_dip, 308*2973Sgovinda name, sizeof (name)); 309*2973Sgovinda 310*2973Sgovinda (void) mdb_ddi_pathname((uintptr_t)ih.ih_dip, 311*2973Sgovinda info.pathname, sizeof (info.pathname)); 3121725Segillett 313*2973Sgovinda /* Get instance */ 314*2973Sgovinda if (mdb_vread(&dev, sizeof (struct dev_info), 315*2973Sgovinda (uintptr_t)ih.ih_dip) == -1) { 316*2973Sgovinda mdb_warn("intr: failed to read DIP " 317*2973Sgovinda "structure\n"); 318*2973Sgovinda return; 319*2973Sgovinda } 320*2973Sgovinda 321*2973Sgovinda /* Make sure the name doesn't over run */ 322*2973Sgovinda (void) mdb_snprintf(info.driver_name, 323*2973Sgovinda sizeof (info.driver_name), "%s", name); 324*2973Sgovinda 325*2973Sgovinda info.instance = dev.devi_instance; 326*2973Sgovinda info.inum = ih.ih_inum; 3271725Segillett 328*2973Sgovinda /* 329*2973Sgovinda * Read the type used, keep PCIe messages 330*2973Sgovinda * separate. 331*2973Sgovinda */ 332*2973Sgovinda (void) mdb_vread(&intr_p, 333*2973Sgovinda sizeof (devinfo_intr_t), 334*2973Sgovinda (uintptr_t)dev.devi_intr_p); 335*2973Sgovinda 336*2973Sgovinda if (ih.ih_rec_type != MSG_REC) { 337*2973Sgovinda info.intr_type = 338*2973Sgovinda intr_p.devi_intr_curr_type; 339*2973Sgovinda } 340*2973Sgovinda 341*2973Sgovinda if ((info.intr_type == DDI_INTR_TYPE_FIXED) && 342*2973Sgovinda ((ino.ino_ipil_size > 1) || 343*2973Sgovinda (ipil.ipil_ih_size > 1))) { 344*2973Sgovinda info.shared = 1; 345*2973Sgovinda } 346909Segillett 347*2973Sgovinda info.num = ih.ih_msg_code; 348*2973Sgovinda info.intr_state = ih.ih_intr_state; 349*2973Sgovinda info.ino_ino = ino.ino_ino; 350*2973Sgovinda info.mondo = ino.ino_sysino; 351*2973Sgovinda info.pil = ipil.ipil_pil; 352*2973Sgovinda info.cpuid = ino.ino_cpuid; 353*2973Sgovinda 354*2973Sgovinda intr_print_elements(info); 355*2973Sgovinda count++; 356909Segillett 357*2973Sgovinda (void) mdb_vread(&ih, sizeof (px_ih_t), 358*2973Sgovinda (uintptr_t)ih.ih_next); 359*2973Sgovinda 360*2973Sgovinda } while (count < ipil.ipil_ih_size); 361909Segillett 362*2973Sgovinda } while (mdb_vread(&ipil, sizeof (px_ino_pil_t), 363*2973Sgovinda (uintptr_t)ipil.ipil_next_p) != -1); 364909Segillett 365*2973Sgovinda } while (mdb_vread(&ino, sizeof (px_ino_t), 366*2973Sgovinda (uintptr_t)ino.ino_next_p) != -1); 367909Segillett } 368909Segillett 369909Segillett static char * 3701725Segillett intr_get_intr_type(uint16_t type) 371909Segillett { 3721725Segillett switch (type) { 3731725Segillett case DDI_INTR_TYPE_FIXED: 3741725Segillett return ("Fixed"); 3751725Segillett case DDI_INTR_TYPE_MSI: 3761725Segillett return ("MSI"); 3771725Segillett case DDI_INTR_TYPE_MSIX: 3781725Segillett return ("MSI-X"); 3791725Segillett default: 380909Segillett return ("PCIe"); 381909Segillett } 382909Segillett } 383909Segillett 384909Segillett static void 385909Segillett intr_print_banner(void) 386909Segillett { 387909Segillett if (!detailed) { 388965Sgovinda mdb_printf("\n%<u>\tDevice\t" 389965Sgovinda " Shared\t" 390965Sgovinda " Type\t" 391965Sgovinda " MSG #\t" 392965Sgovinda " State\t" 393965Sgovinda " INO\t" 394965Sgovinda " Mondo\t" 395965Sgovinda " Pil\t" 396965Sgovinda " CPU %</u>" 397965Sgovinda "\n"); 398909Segillett } 399909Segillett } 400909Segillett 401909Segillett static void 402909Segillett intr_print_elements(intr_info_t info) 403909Segillett { 404909Segillett if (!detailed) { 405965Sgovinda mdb_printf(" %11s#%d\t", info.driver_name, info.instance); 406965Sgovinda mdb_printf(" %5s\t", 407909Segillett info.shared ? "yes" : "no"); 408965Sgovinda mdb_printf(" %s\t", intr_get_intr_type(info.intr_type)); 4091725Segillett if (info.intr_type == DDI_INTR_TYPE_FIXED) { 410965Sgovinda mdb_printf(" --- \t"); 411909Segillett } else { 412965Sgovinda mdb_printf(" %4d\t", info.num); 413909Segillett } 414909Segillett 415965Sgovinda mdb_printf(" %2s\t", 416909Segillett info.intr_state ? "enbl" : "disbl"); 417965Sgovinda mdb_printf(" 0x%x\t", info.ino_ino); 418965Sgovinda mdb_printf(" 0x%x\t", info.mondo); 419965Sgovinda mdb_printf(" %4d\t", info.pil); 420965Sgovinda mdb_printf(" %3d \n", info.cpuid); 421909Segillett } else { 422909Segillett mdb_printf("\n-------------------------------------------\n"); 423909Segillett mdb_printf("Device:\t\t%s\n", info.driver_name); 424909Segillett mdb_printf("Instance:\t%d\n", info.instance); 425909Segillett mdb_printf("Path:\t\t%s\n", info.pathname); 426909Segillett mdb_printf("Inum:\t\t%d\n", info.inum); 427909Segillett mdb_printf("Interrupt Type:\t%s\n", 428909Segillett intr_get_intr_type(info.intr_type)); 4291725Segillett if (info.intr_type == DDI_INTR_TYPE_MSI) { 4301725Segillett mdb_printf("MSI Number:\t%d\n", info.num); 4311725Segillett } else if (info.intr_type == DDI_INTR_TYPE_MSIX) { 4321725Segillett mdb_printf("MSI-X Number:\t%d\n", info.num); 4331725Segillett } else if (!info.intr_type) { 4341725Segillett mdb_printf("PCIe Message #:\t%d\n", info.num); 4351725Segillett } 436909Segillett 437909Segillett mdb_printf("Shared Intr:\t%s\n", 438909Segillett info.shared ? "yes" : "no"); 439909Segillett mdb_printf("State:\t\t%d (%s)\n", info.intr_state, 440909Segillett info.intr_state ? "Enabled" : "Disabled"); 441909Segillett mdb_printf("INO:\t\t0x%x\n", info.ino_ino); 442909Segillett mdb_printf("Mondo:\t\t0x%x\n", info.mondo); 443909Segillett mdb_printf("Pil:\t\t%d\n", info.pil); 444909Segillett mdb_printf("CPU:\t\t%d\n", info.cpuid); 445909Segillett } 446909Segillett } 447909Segillett 448909Segillett /*ARGSUSED*/ 449909Segillett static void 450909Segillett intr_walk_fini(mdb_walk_state_t *wsp) 451909Segillett { 452909Segillett /* Nothing to do here */ 453909Segillett } 454909Segillett 455909Segillett /*ARGSUSED*/ 456909Segillett static int 457909Segillett intr_intr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 458909Segillett { 459909Segillett detailed = 0; 460909Segillett 461909Segillett if (mdb_getopts(argc, argv, 'd', MDB_OPT_SETBITS, TRUE, &detailed, 462909Segillett NULL) != argc) 463909Segillett return (DCMD_USAGE); 464909Segillett 465909Segillett if (!(flags & DCMD_ADDRSPEC)) { 466909Segillett if (mdb_walk_dcmd("interrupts", "interrupts", argc, argv) 467909Segillett == -1) { 468909Segillett mdb_warn("can't walk pci/px buffer entries\n"); 469909Segillett return (DCMD_ERR); 470909Segillett } 471909Segillett return (DCMD_OK); 472909Segillett } 473909Segillett 474909Segillett return (DCMD_OK); 475909Segillett } 476909Segillett 477909Segillett /* 478909Segillett * MDB module linkage information: 479909Segillett */ 480909Segillett 481909Segillett static const mdb_dcmd_t dcmds[] = { 482909Segillett { "interrupts", "[-d]", "display the interrupt info registered with " 483909Segillett "the PCI/PX nexus drivers", intr_intr }, 484909Segillett { NULL } 485909Segillett }; 486909Segillett 487909Segillett static const mdb_walker_t walkers[] = { 488909Segillett { "interrupts", "walk PCI/PX interrupt structures", 489909Segillett intr_walk_init, intr_walk_step, intr_walk_fini }, 490909Segillett { NULL } 491909Segillett }; 492909Segillett 493909Segillett static const mdb_modinfo_t modinfo = { 494909Segillett MDB_API_VERSION, dcmds, walkers 495909Segillett }; 496909Segillett 497909Segillett const mdb_modinfo_t * 498909Segillett _mdb_init(void) 499909Segillett { 500909Segillett return (&modinfo); 501909Segillett } 502