1909Segillett /* 2909Segillett * CDDL HEADER START 3909Segillett * 4909Segillett * The contents of this file are subject to the terms of the 5909Segillett * Common Development and Distribution License, Version 1.0 only 6909Segillett * (the "License"). You may not use this file except in compliance 7909Segillett * with the License. 8909Segillett * 9909Segillett * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10909Segillett * or http://www.opensolaris.org/os/licensing. 11909Segillett * See the License for the specific language governing permissions 12909Segillett * and limitations under the License. 13909Segillett * 14909Segillett * When distributing Covered Code, include this CDDL HEADER in each 15909Segillett * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16909Segillett * If applicable, add the following below this CDDL HEADER, with the 17909Segillett * fields enclosed by brackets "[]" replaced with your own identifying 18909Segillett * information: Portions Copyright [yyyy] [name of copyright owner] 19909Segillett * 20909Segillett * CDDL HEADER END 21909Segillett */ 22909Segillett /* 23909Segillett * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24909Segillett * Use is subject to license terms. 25909Segillett */ 26909Segillett 27909Segillett #pragma ident "%Z%%M% %I% %E% SMI" 28909Segillett 29909Segillett #include <sys/mdb_modapi.h> 30909Segillett #include <mdb/mdb_ks.h> 31909Segillett #include <sys/async.h> /* ecc_flt for pci_ecc.h */ 32909Segillett #include <sys/ddi_subrdefs.h> 33909Segillett #include <sys/pci/pci_obj.h> 34909Segillett #include "px_obj.h" 35909Segillett 36909Segillett static int intr_pci_walk_step(mdb_walk_state_t *); 37909Segillett static int intr_px_walk_step(mdb_walk_state_t *); 38909Segillett static void intr_pci_print_items(mdb_walk_state_t *); 39909Segillett static void intr_px_print_items(mdb_walk_state_t *); 40909Segillett static char *intr_get_intr_type(msiq_rec_type_t); 41909Segillett static void intr_print_banner(void); 42909Segillett 43909Segillett typedef struct intr_info { 44909Segillett uint32_t cpuid; 45909Segillett uint32_t inum; 46909Segillett uint32_t num; 47909Segillett uint32_t pil; 48909Segillett uint16_t mondo; 49909Segillett uint8_t ino_ino; 50909Segillett uint_t intr_state; 51909Segillett int instance; 52909Segillett int shared; 53909Segillett msiq_rec_type_t intr_type; 54909Segillett char driver_name[12]; 55909Segillett char pathname[MAXNAMELEN]; 56909Segillett } 57909Segillett intr_info_t; 58909Segillett 59909Segillett static void intr_print_elements(intr_info_t); 60909Segillett static int detailed = 0; /* Print detailed view */ 61909Segillett 62909Segillett 63909Segillett static int 64909Segillett intr_walk_init(mdb_walk_state_t *wsp) 65909Segillett { 66909Segillett wsp->walk_addr = NULL; 67909Segillett 68909Segillett return (WALK_NEXT); 69909Segillett } 70909Segillett 71909Segillett static int 72909Segillett intr_walk_step(mdb_walk_state_t *wsp) 73909Segillett { 74909Segillett pci_t *pci_per_p; 75909Segillett px_t *px_state_p; 76909Segillett 77909Segillett /* read globally declared structures in the pci driver */ 78909Segillett if (mdb_readvar(&pci_per_p, "per_pci_state") != -1) { 79909Segillett wsp->walk_addr = (uintptr_t)pci_per_p; 80909Segillett intr_pci_walk_step(wsp); 81909Segillett } 82909Segillett 83909Segillett /* read globally declared structures in the px driver */ 84909Segillett if (mdb_readvar(&px_state_p, "px_state_p") != -1) { 85909Segillett wsp->walk_addr = (uintptr_t)px_state_p; 86909Segillett intr_px_walk_step(wsp); 87909Segillett } 88909Segillett 89909Segillett return (WALK_DONE); 90909Segillett } 91909Segillett 92909Segillett static int 93909Segillett intr_pci_walk_step(mdb_walk_state_t *wsp) 94909Segillett { 95909Segillett pci_t *pci_per_p; 96909Segillett pci_t pci_per; 97909Segillett uintptr_t start_addr; 98909Segillett 99909Segillett /* Read start of state structure array */ 100909Segillett if (mdb_vread(&pci_per_p, sizeof (uintptr_t), 101909Segillett (uintptr_t)wsp->walk_addr) == -1) { 102909Segillett mdb_warn("intr: failed to read the initial pci_per_p " 103909Segillett "structure\n"); 104909Segillett return (WALK_ERR); 105909Segillett } 106909Segillett 107909Segillett /* Figure out how many items are here */ 108909Segillett start_addr = (uintptr_t)pci_per_p; 109909Segillett 110*965Sgovinda intr_print_banner(); 111*965Sgovinda 112909Segillett while (mdb_vread(&pci_per_p, sizeof (uintptr_t), 113909Segillett (uintptr_t)start_addr) != -1) { 114909Segillett /* Read until nothing is left */ 115909Segillett if (mdb_vread(&pci_per, sizeof (pci_t), 116909Segillett (uintptr_t)pci_per_p) == -1) { 117909Segillett return (WALK_DONE); 118909Segillett } 119909Segillett 120909Segillett wsp->walk_addr = (uintptr_t)pci_per.pci_ib_p; 121909Segillett intr_pci_print_items(wsp); 122909Segillett 123909Segillett start_addr += sizeof (uintptr_t); 124909Segillett } 125909Segillett 126909Segillett return (WALK_DONE); 127909Segillett } 128909Segillett 129909Segillett static int 130909Segillett intr_px_walk_step(mdb_walk_state_t *wsp) 131909Segillett { 132909Segillett px_t *px_state_p; 133909Segillett px_t px_state; 134909Segillett uintptr_t start_addr; 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 147*965Sgovinda intr_print_banner(); 148*965Sgovinda 149909Segillett while (mdb_vread(&px_state_p, sizeof (uintptr_t), 150909Segillett (uintptr_t)start_addr) != -1) { 151909Segillett /* Read until nothing is left */ 152909Segillett if (mdb_vread(&px_state, sizeof (px_t), 153909Segillett (uintptr_t)px_state_p) == -1) { 154909Segillett return (WALK_DONE); 155909Segillett } 156909Segillett 157909Segillett wsp->walk_addr = (uintptr_t)px_state.px_ib_p; 158909Segillett intr_px_print_items(wsp); 159909Segillett 160909Segillett start_addr += sizeof (uintptr_t); 161909Segillett } 162909Segillett 163909Segillett return (WALK_DONE); 164909Segillett } 165909Segillett 166909Segillett static void 167909Segillett intr_pci_print_items(mdb_walk_state_t *wsp) 168909Segillett { 169909Segillett ib_t pci_ib; 170909Segillett ib_ino_info_t *ib_ino_lst; 171909Segillett ib_ino_info_t list; 172909Segillett ih_t ih; 173909Segillett int count; 174909Segillett char name[MODMAXNAMELEN + 1]; 175909Segillett struct dev_info devinfo; 176909Segillett intr_info_t info; 177909Segillett 178909Segillett if (mdb_vread(&pci_ib, sizeof (ib_t), 179909Segillett (uintptr_t)wsp->walk_addr) == -1) { 180909Segillett mdb_warn("intr: failed to read pci interrupt block " 181909Segillett "structure\n"); 182909Segillett return; 183909Segillett } 184909Segillett 185909Segillett /* Read in ib_ino_info_t structure at address */ 186909Segillett ib_ino_lst = pci_ib.ib_ino_lst; 187909Segillett if (mdb_vread(&list, sizeof (ib_ino_info_t), 188909Segillett (uintptr_t)ib_ino_lst) == -1) { 189909Segillett /* Nothing here to read from */ 190909Segillett return; 191909Segillett } 192909Segillett 193909Segillett do { 194909Segillett if (mdb_vread(&ih, sizeof (ih_t), 195909Segillett (uintptr_t)list.ino_ih_start) == -1) { 196909Segillett mdb_warn("intr: failed to read pci interrupt entry " 197909Segillett "structure\n"); 198909Segillett return; 199909Segillett } 200909Segillett 201909Segillett count = 0; 202909Segillett 203909Segillett do { 204909Segillett bzero((void *)&info, sizeof (intr_info_t)); 205909Segillett 206909Segillett if (list.ino_ih_size > 1) { 207909Segillett info.shared = 1; 208909Segillett } 209909Segillett 210909Segillett (void) mdb_devinfo2driver((uintptr_t)ih.ih_dip, 211909Segillett name, sizeof (name)); 212909Segillett 213909Segillett (void) mdb_ddi_pathname((uintptr_t)ih.ih_dip, 214909Segillett info.pathname, sizeof (info.pathname)); 215909Segillett 216909Segillett /* Get instance */ 217909Segillett if (mdb_vread(&devinfo, sizeof (struct dev_info), 218909Segillett (uintptr_t)ih.ih_dip) == -1) { 219909Segillett mdb_warn("intr: failed to read DIP " 220909Segillett "structure\n"); 221909Segillett return; 222909Segillett } 223909Segillett 224909Segillett /* Make sure the name doesn't over run */ 225909Segillett (void) mdb_snprintf(info.driver_name, 226909Segillett sizeof (info.driver_name), "%s", name); 227909Segillett 228909Segillett info.instance = devinfo.devi_instance; 229909Segillett info.inum = ih.ih_inum; 230909Segillett info.intr_type = INTX_REC; 231909Segillett info.num = 0; 232909Segillett info.intr_state = ih.ih_intr_state; 233909Segillett info.ino_ino = list.ino_ino; 234909Segillett info.mondo = list.ino_mondo; 235909Segillett info.pil = list.ino_pil; 236909Segillett info.cpuid = list.ino_cpuid; 237909Segillett 238909Segillett intr_print_elements(info); 239909Segillett count++; 240909Segillett 241909Segillett (void) mdb_vread(&ih, sizeof (ih_t), 242909Segillett (uintptr_t)ih.ih_next); 243909Segillett 244909Segillett } while (count < list.ino_ih_size); 245909Segillett 246909Segillett } while (mdb_vread(&list, sizeof (ib_ino_info_t), 247909Segillett (uintptr_t)list.ino_next) != -1); 248909Segillett } 249909Segillett 250909Segillett static void 251909Segillett intr_px_print_items(mdb_walk_state_t *wsp) 252909Segillett { 253909Segillett px_ib_t px_ib; 254909Segillett px_ib_ino_info_t *px_ib_ino_lst; 255909Segillett px_ib_ino_info_t px_list; 256909Segillett px_ih_t px_ih; 257909Segillett int count; 258909Segillett char name[MODMAXNAMELEN + 1]; 259909Segillett struct dev_info devinfo; 260909Segillett intr_info_t info; 261909Segillett 262909Segillett if (mdb_vread(&px_ib, sizeof (px_ib_t), wsp->walk_addr) == -1) { 263909Segillett mdb_warn("intr: failed to read px interrupt block " 264909Segillett "structure\n"); 265909Segillett return; 266909Segillett } 267909Segillett 268909Segillett /* Read in px_ib_ino_info_t structure at address */ 269909Segillett px_ib_ino_lst = px_ib.ib_ino_lst; 270909Segillett if (mdb_vread(&px_list, sizeof (px_ib_ino_info_t), 271909Segillett (uintptr_t)px_ib_ino_lst) == -1) { 272909Segillett /* Nothing here to read from */ 273909Segillett return; 274909Segillett } 275909Segillett 276909Segillett do { 277909Segillett if (mdb_vread(&px_ih, sizeof (px_ih_t), 278909Segillett (uintptr_t)px_list.ino_ih_start) == -1) { 279909Segillett mdb_warn("intr: failed to read px interrupt entry " 280909Segillett "structure\n"); 281909Segillett return; 282909Segillett } 283909Segillett 284909Segillett count = 0; 285909Segillett 286909Segillett do { 287909Segillett bzero((void *)&info, sizeof (intr_info_t)); 288909Segillett 289909Segillett if (px_list.ino_ih_size > 1) { 290909Segillett info.shared = 1; 291909Segillett } 292909Segillett 293909Segillett (void) mdb_devinfo2driver((uintptr_t)px_ih.ih_dip, 294909Segillett name, sizeof (name)); 295909Segillett 296909Segillett (void) mdb_ddi_pathname((uintptr_t)px_ih.ih_dip, 297909Segillett info.pathname, sizeof (info.pathname)); 298909Segillett 299909Segillett /* Get instance */ 300909Segillett if (mdb_vread(&devinfo, sizeof (struct dev_info), 301909Segillett (uintptr_t)px_ih.ih_dip) == -1) { 302909Segillett mdb_warn("intr: failed to read DIP " 303909Segillett "structure\n"); 304909Segillett return; 305909Segillett } 306909Segillett 307909Segillett /* Make sure the name doesn't over run */ 308909Segillett (void) mdb_snprintf(info.driver_name, 309909Segillett sizeof (info.driver_name), "%s", name); 310909Segillett 311909Segillett info.instance = devinfo.devi_instance; 312909Segillett info.inum = px_ih.ih_inum; 313909Segillett info.intr_type = px_ih.ih_rec_type; 314909Segillett info.num = px_ih.ih_msg_code; 315909Segillett info.intr_state = px_ih.ih_intr_state; 316909Segillett info.ino_ino = px_list.ino_ino; 317909Segillett info.mondo = px_list.ino_sysino; 318909Segillett info.pil = px_list.ino_pil; 319909Segillett info.cpuid = px_list.ino_cpuid; 320909Segillett 321909Segillett intr_print_elements(info); 322909Segillett count++; 323909Segillett 324909Segillett (void) mdb_vread(&px_ih, sizeof (ih_t), 325909Segillett (uintptr_t)px_ih.ih_next); 326909Segillett 327909Segillett } while (count < px_list.ino_ih_size); 328909Segillett 329909Segillett } while (mdb_vread(&px_list, sizeof (px_ib_ino_info_t), 330909Segillett (uintptr_t)px_list.ino_next) != -1); 331909Segillett } 332909Segillett 333909Segillett static char * 334909Segillett intr_get_intr_type(msiq_rec_type_t rec_type) 335909Segillett { 336909Segillett switch (rec_type) { 337909Segillett case MSG_REC: 338909Segillett return ("PCIe"); 339909Segillett case MSI32_REC: 340909Segillett case MSI64_REC: 341909Segillett return ("MSI"); 342909Segillett case INTX_REC: 343909Segillett default: 344909Segillett return ("Fixed"); 345909Segillett } 346909Segillett } 347909Segillett 348909Segillett static void 349909Segillett intr_print_banner(void) 350909Segillett { 351909Segillett if (!detailed) { 352*965Sgovinda mdb_printf("\n%<u>\tDevice\t" 353*965Sgovinda " Shared\t" 354*965Sgovinda " Type\t" 355*965Sgovinda " MSG #\t" 356*965Sgovinda " State\t" 357*965Sgovinda " INO\t" 358*965Sgovinda " Mondo\t" 359*965Sgovinda " Pil\t" 360*965Sgovinda " CPU %</u>" 361*965Sgovinda "\n"); 362909Segillett } 363909Segillett } 364909Segillett 365909Segillett static void 366909Segillett intr_print_elements(intr_info_t info) 367909Segillett { 368909Segillett if (!detailed) { 369*965Sgovinda mdb_printf(" %11s#%d\t", info.driver_name, info.instance); 370*965Sgovinda mdb_printf(" %5s\t", 371909Segillett info.shared ? "yes" : "no"); 372*965Sgovinda mdb_printf(" %s\t", intr_get_intr_type(info.intr_type)); 373909Segillett if (strcmp("Fixed", intr_get_intr_type(info.intr_type)) == 0) { 374*965Sgovinda mdb_printf(" --- \t"); 375909Segillett } else { 376*965Sgovinda mdb_printf(" %4d\t", info.num); 377909Segillett } 378909Segillett 379*965Sgovinda mdb_printf(" %2s\t", 380909Segillett info.intr_state ? "enbl" : "disbl"); 381*965Sgovinda mdb_printf(" 0x%x\t", info.ino_ino); 382*965Sgovinda mdb_printf(" 0x%x\t", info.mondo); 383*965Sgovinda mdb_printf(" %4d\t", info.pil); 384*965Sgovinda mdb_printf(" %3d \n", info.cpuid); 385909Segillett } else { 386909Segillett mdb_printf("\n-------------------------------------------\n"); 387909Segillett mdb_printf("Device:\t\t%s\n", info.driver_name); 388909Segillett mdb_printf("Instance:\t%d\n", info.instance); 389909Segillett mdb_printf("Path:\t\t%s\n", info.pathname); 390909Segillett mdb_printf("Inum:\t\t%d\n", info.inum); 391909Segillett mdb_printf("Interrupt Type:\t%s\n", 392909Segillett intr_get_intr_type(info.intr_type)); 393909Segillett if (strcmp("MSI", intr_get_intr_type(info.intr_type)) == 0) 394909Segillett mdb_printf("MSI/X Number:\t%s\n", info.num); 395909Segillett 396909Segillett mdb_printf("Shared Intr:\t%s\n", 397909Segillett info.shared ? "yes" : "no"); 398909Segillett mdb_printf("State:\t\t%d (%s)\n", info.intr_state, 399909Segillett info.intr_state ? "Enabled" : "Disabled"); 400909Segillett mdb_printf("INO:\t\t0x%x\n", info.ino_ino); 401909Segillett mdb_printf("Mondo:\t\t0x%x\n", info.mondo); 402909Segillett mdb_printf("Pil:\t\t%d\n", info.pil); 403909Segillett mdb_printf("CPU:\t\t%d\n", info.cpuid); 404909Segillett } 405909Segillett } 406909Segillett 407909Segillett /*ARGSUSED*/ 408909Segillett static void 409909Segillett intr_walk_fini(mdb_walk_state_t *wsp) 410909Segillett { 411909Segillett /* Nothing to do here */ 412909Segillett } 413909Segillett 414909Segillett /*ARGSUSED*/ 415909Segillett static int 416909Segillett intr_intr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 417909Segillett { 418909Segillett detailed = 0; 419909Segillett 420909Segillett if (mdb_getopts(argc, argv, 'd', MDB_OPT_SETBITS, TRUE, &detailed, 421909Segillett NULL) != argc) 422909Segillett return (DCMD_USAGE); 423909Segillett 424909Segillett if (!(flags & DCMD_ADDRSPEC)) { 425909Segillett if (mdb_walk_dcmd("interrupts", "interrupts", argc, argv) 426909Segillett == -1) { 427909Segillett mdb_warn("can't walk pci/px buffer entries\n"); 428909Segillett return (DCMD_ERR); 429909Segillett } 430909Segillett return (DCMD_OK); 431909Segillett } 432909Segillett 433909Segillett return (DCMD_OK); 434909Segillett } 435909Segillett 436909Segillett /* 437909Segillett * MDB module linkage information: 438909Segillett */ 439909Segillett 440909Segillett static const mdb_dcmd_t dcmds[] = { 441909Segillett { "interrupts", "[-d]", "display the interrupt info registered with " 442909Segillett "the PCI/PX nexus drivers", intr_intr }, 443909Segillett { NULL } 444909Segillett }; 445909Segillett 446909Segillett static const mdb_walker_t walkers[] = { 447909Segillett { "interrupts", "walk PCI/PX interrupt structures", 448909Segillett intr_walk_init, intr_walk_step, intr_walk_fini }, 449909Segillett { NULL } 450909Segillett }; 451909Segillett 452909Segillett static const mdb_modinfo_t modinfo = { 453909Segillett MDB_API_VERSION, dcmds, walkers 454909Segillett }; 455909Segillett 456909Segillett const mdb_modinfo_t * 457909Segillett _mdb_init(void) 458909Segillett { 459909Segillett return (&modinfo); 460909Segillett } 461