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 /* 22*10053SEvan.Yan@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23909Segillett * Use is subject to license terms. 24909Segillett */ 25909Segillett 26909Segillett #include <sys/mdb_modapi.h> 27909Segillett #include <mdb/mdb_ks.h> 28909Segillett #include <sys/async.h> /* ecc_flt for pci_ecc.h */ 29909Segillett #include <sys/ddi_subrdefs.h> 30909Segillett #include <sys/pci/pci_obj.h> 31909Segillett #include "px_obj.h" 32909Segillett 33909Segillett static int intr_pci_walk_step(mdb_walk_state_t *); 34909Segillett static int intr_px_walk_step(mdb_walk_state_t *); 35909Segillett static void intr_pci_print_items(mdb_walk_state_t *); 36909Segillett static void intr_px_print_items(mdb_walk_state_t *); 371725Segillett static char *intr_get_intr_type(uint16_t type); 38909Segillett static void intr_print_banner(void); 39909Segillett 40909Segillett typedef struct intr_info { 41909Segillett uint32_t cpuid; 42909Segillett uint32_t inum; 43909Segillett uint32_t num; 44909Segillett uint32_t pil; 451725Segillett uint16_t intr_type; 46909Segillett uint16_t mondo; 47909Segillett uint8_t ino_ino; 48909Segillett uint_t intr_state; 49909Segillett int instance; 50909Segillett int shared; 51909Segillett char driver_name[12]; 52909Segillett char pathname[MAXNAMELEN]; 53909Segillett } 54909Segillett intr_info_t; 55909Segillett 563830Segillett #define PX_MAX_ENTRIES 32 573830Segillett 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; 1343830Segillett int x; 135909Segillett 136909Segillett /* Read start of state structure array */ 137909Segillett if (mdb_vread(&px_state_p, sizeof (uintptr_t), 138909Segillett (uintptr_t)wsp->walk_addr) == -1) { 139909Segillett mdb_warn("intr: failed to read the initial px_per_p " 140909Segillett "structure\n"); 141909Segillett return (WALK_ERR); 142909Segillett } 143909Segillett 144909Segillett /* Figure out how many items are here */ 145909Segillett start_addr = (uintptr_t)px_state_p; 146909Segillett 147965Sgovinda intr_print_banner(); 148965Sgovinda 1493830Segillett for (x = 0; x < PX_MAX_ENTRIES; x++) { 1503830Segillett (void) mdb_vread(&px_state_p, sizeof (uintptr_t), 1513830Segillett (uintptr_t)start_addr); 1523830Segillett 1533830Segillett start_addr += sizeof (uintptr_t); 1543830Segillett 1553830Segillett /* Read if anything is there */ 156909Segillett if (mdb_vread(&px_state, sizeof (px_t), 157909Segillett (uintptr_t)px_state_p) == -1) { 1583830Segillett continue; 159909Segillett } 160909Segillett 161909Segillett wsp->walk_addr = (uintptr_t)px_state.px_ib_p; 162909Segillett intr_px_print_items(wsp); 163909Segillett } 164909Segillett 165909Segillett return (WALK_DONE); 166909Segillett } 167909Segillett 168909Segillett static void 169909Segillett intr_pci_print_items(mdb_walk_state_t *wsp) 170909Segillett { 1712973Sgovinda ib_t ib; 1722973Sgovinda ib_ino_info_t ino; 1732973Sgovinda ib_ino_pil_t ipil; 174909Segillett ih_t ih; 175909Segillett int count; 176909Segillett char name[MODMAXNAMELEN + 1]; 1772973Sgovinda struct dev_info dev; 178909Segillett intr_info_t info; 179909Segillett 1802973Sgovinda if (mdb_vread(&ib, sizeof (ib_t), 181909Segillett (uintptr_t)wsp->walk_addr) == -1) { 182909Segillett mdb_warn("intr: failed to read pci interrupt block " 183909Segillett "structure\n"); 184909Segillett return; 185909Segillett } 186909Segillett 187909Segillett /* Read in ib_ino_info_t structure at address */ 1882973Sgovinda if (mdb_vread(&ino, sizeof (ib_ino_info_t), 1892973Sgovinda (uintptr_t)ib.ib_ino_lst) == -1) { 190909Segillett /* Nothing here to read from */ 191909Segillett return; 192909Segillett } 193909Segillett 194909Segillett do { 1952973Sgovinda if (mdb_vread(&ipil, sizeof (ib_ino_pil_t), 1962973Sgovinda (uintptr_t)ino.ino_ipil_p) == -1) { 1972973Sgovinda mdb_warn("intr: failed to read pci interrupt " 1982973Sgovinda "ib_ino_pil_t structure\n"); 199909Segillett return; 200909Segillett } 201909Segillett 202909Segillett do { 2032973Sgovinda if (mdb_vread(&ih, sizeof (ih_t), 2042973Sgovinda (uintptr_t)ipil.ipil_ih_start) == -1) { 2052973Sgovinda mdb_warn("intr: failed to read pci interrupt " 2062973Sgovinda "ih_t structure\n"); 207909Segillett return; 208909Segillett } 209909Segillett 2102973Sgovinda count = 0; 2112973Sgovinda 2122973Sgovinda do { 2132973Sgovinda bzero((void *)&info, sizeof (intr_info_t)); 2142973Sgovinda 2152973Sgovinda if ((ino.ino_ipil_size > 1) || 2162973Sgovinda (ipil.ipil_ih_size > 1)) { 2172973Sgovinda info.shared = 1; 2182973Sgovinda } 2192973Sgovinda 2202973Sgovinda (void) mdb_devinfo2driver((uintptr_t)ih.ih_dip, 2212973Sgovinda name, sizeof (name)); 2222973Sgovinda 2232973Sgovinda (void) mdb_ddi_pathname((uintptr_t)ih.ih_dip, 2242973Sgovinda info.pathname, sizeof (info.pathname)); 2252973Sgovinda 2262973Sgovinda /* Get instance */ 2272973Sgovinda if (mdb_vread(&dev, sizeof (struct dev_info), 2282973Sgovinda (uintptr_t)ih.ih_dip) == -1) { 2292973Sgovinda mdb_warn("intr: failed to read DIP " 2302973Sgovinda "structure\n"); 2312973Sgovinda return; 2322973Sgovinda } 233909Segillett 2342973Sgovinda /* Make sure the name doesn't over run */ 2352973Sgovinda (void) mdb_snprintf(info.driver_name, 2362973Sgovinda sizeof (info.driver_name), "%s", name); 2372973Sgovinda 2382973Sgovinda info.instance = dev.devi_instance; 2392973Sgovinda info.inum = ih.ih_inum; 2402973Sgovinda info.intr_type = DDI_INTR_TYPE_FIXED; 2412973Sgovinda info.num = 0; 2422973Sgovinda info.intr_state = ih.ih_intr_state; 2432973Sgovinda info.ino_ino = ino.ino_ino; 2442973Sgovinda info.mondo = ino.ino_mondo; 2452973Sgovinda info.pil = ipil.ipil_pil; 2462973Sgovinda info.cpuid = ino.ino_cpuid; 247909Segillett 2482973Sgovinda intr_print_elements(info); 2492973Sgovinda count++; 2502973Sgovinda 2512973Sgovinda (void) mdb_vread(&ih, sizeof (ih_t), 2522973Sgovinda (uintptr_t)ih.ih_next); 253909Segillett 2542973Sgovinda } while (count < ipil.ipil_ih_size); 255909Segillett 2562973Sgovinda } while (mdb_vread(&ipil, sizeof (ib_ino_pil_t), 2572973Sgovinda (uintptr_t)ipil.ipil_next_p) != -1); 258909Segillett 2592973Sgovinda } while (mdb_vread(&ino, sizeof (ib_ino_info_t), 2602973Sgovinda (uintptr_t)ino.ino_next_p) != -1); 261909Segillett } 262909Segillett 263909Segillett static void 264909Segillett intr_px_print_items(mdb_walk_state_t *wsp) 265909Segillett { 2662973Sgovinda px_ib_t ib; 2672973Sgovinda px_ino_t ino; 2682973Sgovinda px_ino_pil_t ipil; 2692973Sgovinda px_ih_t ih; 2702973Sgovinda int count; 2712973Sgovinda char name[MODMAXNAMELEN + 1]; 2722973Sgovinda struct dev_info dev; 2732973Sgovinda intr_info_t info; 2742973Sgovinda devinfo_intr_t intr_p; 275909Segillett 2762973Sgovinda if (mdb_vread(&ib, sizeof (px_ib_t), wsp->walk_addr) == -1) { 277909Segillett return; 278909Segillett } 279909Segillett 2802973Sgovinda /* Read in px_ino_t structure at address */ 2812973Sgovinda if (mdb_vread(&ino, sizeof (px_ino_t), 2822973Sgovinda (uintptr_t)ib.ib_ino_lst) == -1) { 283909Segillett /* Nothing here to read from */ 284909Segillett return; 285909Segillett } 286909Segillett 2873830Segillett do { /* ino_next_p loop */ 2882973Sgovinda if (mdb_vread(&ipil, sizeof (px_ino_pil_t), 2892973Sgovinda (uintptr_t)ino.ino_ipil_p) == -1) { 290*10053SEvan.Yan@Sun.COM continue; 291909Segillett } 292909Segillett 2933830Segillett do { /* ipil_next_p loop */ 2942973Sgovinda if (mdb_vread(&ih, sizeof (px_ih_t), 2952973Sgovinda (uintptr_t)ipil.ipil_ih_start) == -1) { 296*10053SEvan.Yan@Sun.COM continue; 297909Segillett } 298909Segillett 2992973Sgovinda count = 0; 3002973Sgovinda 3013830Segillett do { /* ipil_ih_size loop */ 3022973Sgovinda bzero((void *)&info, sizeof (intr_info_t)); 303909Segillett 3042973Sgovinda (void) mdb_devinfo2driver((uintptr_t)ih.ih_dip, 3052973Sgovinda name, sizeof (name)); 3062973Sgovinda 3072973Sgovinda (void) mdb_ddi_pathname((uintptr_t)ih.ih_dip, 3082973Sgovinda info.pathname, sizeof (info.pathname)); 3091725Segillett 3102973Sgovinda /* Get instance */ 3112973Sgovinda if (mdb_vread(&dev, sizeof (struct dev_info), 3122973Sgovinda (uintptr_t)ih.ih_dip) == -1) { 3132973Sgovinda mdb_warn("intr: failed to read DIP " 3142973Sgovinda "structure\n"); 3152973Sgovinda return; 3162973Sgovinda } 3172973Sgovinda 3182973Sgovinda /* Make sure the name doesn't over run */ 3192973Sgovinda (void) mdb_snprintf(info.driver_name, 3202973Sgovinda sizeof (info.driver_name), "%s", name); 3212973Sgovinda 3222973Sgovinda info.instance = dev.devi_instance; 3232973Sgovinda info.inum = ih.ih_inum; 3241725Segillett 3252973Sgovinda /* 3262973Sgovinda * Read the type used, keep PCIe messages 3272973Sgovinda * separate. 3282973Sgovinda */ 3292973Sgovinda (void) mdb_vread(&intr_p, 3302973Sgovinda sizeof (devinfo_intr_t), 3312973Sgovinda (uintptr_t)dev.devi_intr_p); 3322973Sgovinda 3332973Sgovinda if (ih.ih_rec_type != MSG_REC) { 3342973Sgovinda info.intr_type = 3352973Sgovinda intr_p.devi_intr_curr_type; 3362973Sgovinda } 3372973Sgovinda 3382973Sgovinda if ((info.intr_type == DDI_INTR_TYPE_FIXED) && 3392973Sgovinda ((ino.ino_ipil_size > 1) || 3402973Sgovinda (ipil.ipil_ih_size > 1))) { 3412973Sgovinda info.shared = 1; 3422973Sgovinda } 343909Segillett 3442973Sgovinda info.num = ih.ih_msg_code; 3452973Sgovinda info.intr_state = ih.ih_intr_state; 3462973Sgovinda info.ino_ino = ino.ino_ino; 3472973Sgovinda info.mondo = ino.ino_sysino; 3482973Sgovinda info.pil = ipil.ipil_pil; 3492973Sgovinda info.cpuid = ino.ino_cpuid; 3502973Sgovinda 3512973Sgovinda intr_print_elements(info); 3522973Sgovinda count++; 353909Segillett 3542973Sgovinda (void) mdb_vread(&ih, sizeof (px_ih_t), 3552973Sgovinda (uintptr_t)ih.ih_next); 3562973Sgovinda 3572973Sgovinda } while (count < ipil.ipil_ih_size); 358909Segillett 359*10053SEvan.Yan@Sun.COM } while ((ipil.ipil_next_p != NULL) && 360*10053SEvan.Yan@Sun.COM (mdb_vread(&ipil, sizeof (px_ino_pil_t), 361*10053SEvan.Yan@Sun.COM (uintptr_t)ipil.ipil_next_p) != -1)); 362909Segillett 363*10053SEvan.Yan@Sun.COM } while ((ino.ino_next_p != NULL) && (mdb_vread(&ino, sizeof (px_ino_t), 364*10053SEvan.Yan@Sun.COM (uintptr_t)ino.ino_next_p) != -1)); 365909Segillett } 366909Segillett 367909Segillett static char * 3681725Segillett intr_get_intr_type(uint16_t type) 369909Segillett { 3701725Segillett switch (type) { 3711725Segillett case DDI_INTR_TYPE_FIXED: 3721725Segillett return ("Fixed"); 3731725Segillett case DDI_INTR_TYPE_MSI: 3741725Segillett return ("MSI"); 3751725Segillett case DDI_INTR_TYPE_MSIX: 3761725Segillett return ("MSI-X"); 3771725Segillett default: 378909Segillett return ("PCIe"); 379909Segillett } 380909Segillett } 381909Segillett 382909Segillett static void 383909Segillett intr_print_banner(void) 384909Segillett { 385909Segillett if (!detailed) { 386965Sgovinda mdb_printf("\n%<u>\tDevice\t" 387965Sgovinda " Shared\t" 388965Sgovinda " Type\t" 389965Sgovinda " MSG #\t" 390965Sgovinda " State\t" 391965Sgovinda " INO\t" 392965Sgovinda " Mondo\t" 393965Sgovinda " Pil\t" 394965Sgovinda " CPU %</u>" 395965Sgovinda "\n"); 396909Segillett } 397909Segillett } 398909Segillett 399909Segillett static void 400909Segillett intr_print_elements(intr_info_t info) 401909Segillett { 402909Segillett if (!detailed) { 403965Sgovinda mdb_printf(" %11s#%d\t", info.driver_name, info.instance); 404965Sgovinda mdb_printf(" %5s\t", 405909Segillett info.shared ? "yes" : "no"); 406965Sgovinda mdb_printf(" %s\t", intr_get_intr_type(info.intr_type)); 4071725Segillett if (info.intr_type == DDI_INTR_TYPE_FIXED) { 408965Sgovinda mdb_printf(" --- \t"); 409909Segillett } else { 410965Sgovinda mdb_printf(" %4d\t", info.num); 411909Segillett } 412909Segillett 413965Sgovinda mdb_printf(" %2s\t", 414909Segillett info.intr_state ? "enbl" : "disbl"); 415965Sgovinda mdb_printf(" 0x%x\t", info.ino_ino); 416965Sgovinda mdb_printf(" 0x%x\t", info.mondo); 417965Sgovinda mdb_printf(" %4d\t", info.pil); 418965Sgovinda mdb_printf(" %3d \n", info.cpuid); 419909Segillett } else { 420909Segillett mdb_printf("\n-------------------------------------------\n"); 421909Segillett mdb_printf("Device:\t\t%s\n", info.driver_name); 422909Segillett mdb_printf("Instance:\t%d\n", info.instance); 423909Segillett mdb_printf("Path:\t\t%s\n", info.pathname); 424909Segillett mdb_printf("Inum:\t\t%d\n", info.inum); 425909Segillett mdb_printf("Interrupt Type:\t%s\n", 426909Segillett intr_get_intr_type(info.intr_type)); 4271725Segillett if (info.intr_type == DDI_INTR_TYPE_MSI) { 4281725Segillett mdb_printf("MSI Number:\t%d\n", info.num); 4291725Segillett } else if (info.intr_type == DDI_INTR_TYPE_MSIX) { 4301725Segillett mdb_printf("MSI-X Number:\t%d\n", info.num); 4311725Segillett } else if (!info.intr_type) { 4321725Segillett mdb_printf("PCIe Message #:\t%d\n", info.num); 4331725Segillett } 434909Segillett 435909Segillett mdb_printf("Shared Intr:\t%s\n", 436909Segillett info.shared ? "yes" : "no"); 437909Segillett mdb_printf("State:\t\t%d (%s)\n", info.intr_state, 438909Segillett info.intr_state ? "Enabled" : "Disabled"); 439909Segillett mdb_printf("INO:\t\t0x%x\n", info.ino_ino); 440909Segillett mdb_printf("Mondo:\t\t0x%x\n", info.mondo); 441909Segillett mdb_printf("Pil:\t\t%d\n", info.pil); 442909Segillett mdb_printf("CPU:\t\t%d\n", info.cpuid); 443909Segillett } 444909Segillett } 445909Segillett 446909Segillett /*ARGSUSED*/ 447909Segillett static void 448909Segillett intr_walk_fini(mdb_walk_state_t *wsp) 449909Segillett { 450909Segillett /* Nothing to do here */ 451909Segillett } 452909Segillett 453909Segillett /*ARGSUSED*/ 454909Segillett static int 455909Segillett intr_intr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 456909Segillett { 457909Segillett detailed = 0; 458909Segillett 459909Segillett if (mdb_getopts(argc, argv, 'd', MDB_OPT_SETBITS, TRUE, &detailed, 460909Segillett NULL) != argc) 461909Segillett return (DCMD_USAGE); 462909Segillett 463909Segillett if (!(flags & DCMD_ADDRSPEC)) { 464909Segillett if (mdb_walk_dcmd("interrupts", "interrupts", argc, argv) 465909Segillett == -1) { 466909Segillett mdb_warn("can't walk pci/px buffer entries\n"); 467909Segillett return (DCMD_ERR); 468909Segillett } 469909Segillett return (DCMD_OK); 470909Segillett } 471909Segillett 472909Segillett return (DCMD_OK); 473909Segillett } 474909Segillett 475909Segillett /* 476909Segillett * MDB module linkage information: 477909Segillett */ 478909Segillett 479909Segillett static const mdb_dcmd_t dcmds[] = { 480909Segillett { "interrupts", "[-d]", "display the interrupt info registered with " 481909Segillett "the PCI/PX nexus drivers", intr_intr }, 482909Segillett { NULL } 483909Segillett }; 484909Segillett 485909Segillett static const mdb_walker_t walkers[] = { 486909Segillett { "interrupts", "walk PCI/PX interrupt structures", 487909Segillett intr_walk_init, intr_walk_step, intr_walk_fini }, 488909Segillett { NULL } 489909Segillett }; 490909Segillett 491909Segillett static const mdb_modinfo_t modinfo = { 492909Segillett MDB_API_VERSION, dcmds, walkers 493909Segillett }; 494909Segillett 495909Segillett const mdb_modinfo_t * 496909Segillett _mdb_init(void) 497909Segillett { 498909Segillett return (&modinfo); 499909Segillett } 500