1c69906bdSanish /* 2c69906bdSanish * CDDL HEADER START 3c69906bdSanish * 4c69906bdSanish * The contents of this file are subject to the terms of the 5abf601c9Sanish * Common Development and Distribution License (the "License"). 6abf601c9Sanish * You may not use this file except in compliance with the License. 7c69906bdSanish * 8c69906bdSanish * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9c69906bdSanish * or http://www.opensolaris.org/os/licensing. 10c69906bdSanish * See the License for the specific language governing permissions 11c69906bdSanish * and limitations under the License. 12c69906bdSanish * 13c69906bdSanish * When distributing Covered Code, include this CDDL HEADER in each 14c69906bdSanish * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15c69906bdSanish * If applicable, add the following below this CDDL HEADER, with the 16c69906bdSanish * fields enclosed by brackets "[]" replaced with your own identifying 17c69906bdSanish * information: Portions Copyright [yyyy] [name of copyright owner] 18c69906bdSanish * 19c69906bdSanish * CDDL HEADER END 20c69906bdSanish */ 21c69906bdSanish /* 22*5cd376e8SJimmy Vetayases * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 23c69906bdSanish */ 24c69906bdSanish 25d7b41ca4Sanish #include "intr_common.h" 26c69906bdSanish 27d7b41ca4Sanish static struct av_head avec_tbl[APIC_MAX_VECTOR+1]; 28c69906bdSanish static uint16_t shared_tbl[MAX_ISA_IRQ + 1]; 29c69906bdSanish 30c69906bdSanish static char * 31c69906bdSanish interrupt_print_bus(uintptr_t dip_addr) 32c69906bdSanish { 33f4da9be0Scth char bind_name[MAXPATHLEN + 1]; 34c69906bdSanish struct dev_info dev_info; 35c69906bdSanish 36c69906bdSanish if (mdb_vread(&dev_info, sizeof (dev_info), dip_addr) == -1) { 37c69906bdSanish mdb_warn("failed to read child dip"); 38c69906bdSanish return ("-"); 39c69906bdSanish } 40c69906bdSanish 41c69906bdSanish while (dev_info.devi_parent != 0) { 42c69906bdSanish if (mdb_vread(&dev_info, sizeof (dev_info), 43c69906bdSanish (uintptr_t)dev_info.devi_parent) == -1) 44c69906bdSanish break; 45c69906bdSanish 46c69906bdSanish (void) mdb_readstr(bind_name, sizeof (bind_name), 47c69906bdSanish (uintptr_t)dev_info.devi_binding_name); 48c69906bdSanish if (strcmp(bind_name, "isa") == 0) 49c69906bdSanish return ("ISA"); 50c69906bdSanish else if (strcmp(bind_name, "pci") == 0 || 51c69906bdSanish strcmp(bind_name, "npe") == 0) 52c69906bdSanish return ("PCI"); 53c69906bdSanish } 54c69906bdSanish return ("-"); 55c69906bdSanish } 56c69906bdSanish 57c69906bdSanish 58c69906bdSanish /* 59c69906bdSanish * uppc_interrupt_dump: 60c69906bdSanish * Dump uppc(7d) interrupt information. 61c69906bdSanish */ 62c69906bdSanish /* ARGSUSED */ 63c69906bdSanish int 64c69906bdSanish uppc_interrupt_dump(uintptr_t addr, uint_t flags, int argc, 65c69906bdSanish const mdb_arg_t *argv) 66c69906bdSanish { 67d7b41ca4Sanish int i, j; 68c69906bdSanish boolean_t found = B_FALSE; 69c69906bdSanish struct autovec avhp; 70c69906bdSanish 71abf601c9Sanish option_flags = 0; 72abf601c9Sanish if (mdb_getopts(argc, argv, 73abf601c9Sanish 'd', MDB_OPT_SETBITS, INTR_DISPLAY_DRVR_INST, &option_flags, 74abf601c9Sanish 'i', MDB_OPT_SETBITS, INTR_DISPLAY_INTRSTAT, &option_flags, 75abf601c9Sanish NULL) != argc) 76abf601c9Sanish return (DCMD_USAGE); 77abf601c9Sanish 78c69906bdSanish if (mdb_readvar(&avec_tbl, "autovect") == -1) { 79c69906bdSanish mdb_warn("failed to read autovect"); 80c69906bdSanish return (DCMD_ERR); 81c69906bdSanish } 82c69906bdSanish 83c69906bdSanish if (mdb_readvar(&shared_tbl, "uppc_irq_shared_table") == -1) { 84c69906bdSanish mdb_warn("failed to read uppc_irq_shared_table"); 85c69906bdSanish return (DCMD_ERR); 86c69906bdSanish } 87c69906bdSanish 88c69906bdSanish /* 897ff178cdSJimmy Vetayases * By default, on all x86 systems ::interrupts from uppc gets 907ff178cdSJimmy Vetayases * loaded first. For APIC systems the ::interrupts from either 917ff178cdSJimmy Vetayases * apix or pcplusmp ought to be executed. Confusion stems as 927ff178cdSJimmy Vetayases * these three modules export the same dcmd. 93c69906bdSanish */ 94c69906bdSanish for (i = 0; i < MAX_ISA_IRQ + 1; i++) 95c69906bdSanish if (shared_tbl[i]) { 96c69906bdSanish found = B_TRUE; 97c69906bdSanish break; 98c69906bdSanish } 99c69906bdSanish 100c69906bdSanish if (found == B_FALSE) { 1017ff178cdSJimmy Vetayases if (mdb_lookup_by_obj("apix", "apixs", NULL) == 0) { 1027ff178cdSJimmy Vetayases return (mdb_call_dcmd("apix`interrupts", 1037ff178cdSJimmy Vetayases addr, flags, argc, argv)); 1047ff178cdSJimmy Vetayases } else if (mdb_lookup_by_obj("pcplusmp", "apic_irq_table", 105c69906bdSanish NULL) == 0) { 106c69906bdSanish return (mdb_call_dcmd("pcplusmp`interrupts", 107c69906bdSanish addr, flags, argc, argv)); 108c69906bdSanish } 109c69906bdSanish } 110c69906bdSanish 111c69906bdSanish /* Print the header first */ 112abf601c9Sanish if (option_flags & INTR_DISPLAY_INTRSTAT) 113ae115bc7Smrj mdb_printf("%<u>CPU "); 114abf601c9Sanish else 115abf601c9Sanish mdb_printf("%<u>IRQ Vector IPL(lo/hi) Bus Share "); 116abf601c9Sanish mdb_printf("%s %</u>\n", option_flags & INTR_DISPLAY_DRVR_INST ? 117abf601c9Sanish "Driver Name(s)" : "ISR(s)"); 118c69906bdSanish 119c69906bdSanish /* Walk all the entries */ 120c69906bdSanish for (i = 0; i < MAX_ISA_IRQ + 1; i++) { 121c69906bdSanish /* Read the entry, if invalid continue */ 122c69906bdSanish if (mdb_vread(&avhp, sizeof (struct autovec), 123c69906bdSanish (uintptr_t)avec_tbl[i].avh_link) == -1) 124c69906bdSanish continue; 125c69906bdSanish 126c69906bdSanish /* Print each interrupt entry */ 127abf601c9Sanish if (option_flags & INTR_DISPLAY_INTRSTAT) 128abf601c9Sanish mdb_printf("cpu0\t"); 129abf601c9Sanish else 130d7b41ca4Sanish mdb_printf("%-3d 0x%2x %4d/%-2d %-4s %-3d ", 131abf601c9Sanish i, i + PIC_VECTBASE, avec_tbl[i].avh_lo_pri, 132abf601c9Sanish avec_tbl[i].avh_hi_pri, avhp.av_dip ? 133abf601c9Sanish interrupt_print_bus((uintptr_t)avhp.av_dip) : " - ", 134d7b41ca4Sanish shared_tbl[i]); 135c69906bdSanish 136d7b41ca4Sanish if (shared_tbl[i]) 137d7b41ca4Sanish interrupt_print_isr((uintptr_t)avhp.av_vector, 138d7b41ca4Sanish (uintptr_t)avhp.av_intarg1, (uintptr_t)avhp.av_dip); 139c69906bdSanish 140d7b41ca4Sanish for (j = 1; j < shared_tbl[i]; j++) { 141c69906bdSanish if (mdb_vread(&avhp, sizeof (struct autovec), 142c69906bdSanish (uintptr_t)avhp.av_link) != -1) { 143c69906bdSanish mdb_printf(", "); 144d7b41ca4Sanish interrupt_print_isr((uintptr_t)avhp.av_vector, 145d7b41ca4Sanish (uintptr_t)avhp.av_intarg1, 146d7b41ca4Sanish (uintptr_t)avhp.av_dip); 147d7b41ca4Sanish } else { 148d7b41ca4Sanish break; 149c69906bdSanish } 150c69906bdSanish } 151c69906bdSanish mdb_printf("\n"); 152c69906bdSanish } 153c69906bdSanish 154c69906bdSanish return (DCMD_OK); 155c69906bdSanish } 156c69906bdSanish 157c69906bdSanish 158c69906bdSanish /* 159c69906bdSanish * MDB module linkage information: 160c69906bdSanish */ 161c69906bdSanish static const mdb_dcmd_t dcmds[] = { 162abf601c9Sanish { "interrupts", "?[-di]", "print interrupts", uppc_interrupt_dump, 163abf601c9Sanish interrupt_help}, 164774ef820Sanish { "softint", "?[-d]", "print soft interrupts", soft_interrupt_dump, 165774ef820Sanish soft_interrupt_help}, 166c69906bdSanish { NULL } 167c69906bdSanish }; 168c69906bdSanish 169c69906bdSanish static const mdb_modinfo_t modinfo = { MDB_API_VERSION, dcmds, NULL }; 170c69906bdSanish 171c69906bdSanish const mdb_modinfo_t * 172c69906bdSanish _mdb_init(void) 173c69906bdSanish { 174d7b41ca4Sanish GElf_Sym sym; 175d7b41ca4Sanish 176d7b41ca4Sanish if (mdb_lookup_by_name("gld_intr", &sym) != -1) 177d7b41ca4Sanish if (GELF_ST_TYPE(sym.st_info) == STT_FUNC) 178d7b41ca4Sanish gld_intr_addr = (uintptr_t)sym.st_value; 179d7b41ca4Sanish 180c69906bdSanish return (&modinfo); 181c69906bdSanish } 182