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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <stddef.h> 30 #include <sys/mdb_modapi.h> 31 #include <mdb/mdb_ks.h> 32 #include <sys/modctl.h> 33 #include <sys/avintr.h> 34 #include <sys/psm_common.h> 35 #include <sys/pic.h> 36 37 static struct av_head avec_tbl[256]; 38 static uint16_t shared_tbl[MAX_ISA_IRQ + 1]; 39 40 static char * 41 interrupt_print_bus(uintptr_t dip_addr) 42 { 43 char bind_name[MODMAXNAMELEN + 1]; 44 struct dev_info dev_info; 45 46 if (mdb_vread(&dev_info, sizeof (dev_info), dip_addr) == -1) { 47 mdb_warn("failed to read child dip"); 48 return ("-"); 49 } 50 51 while (dev_info.devi_parent != 0) { 52 if (mdb_vread(&dev_info, sizeof (dev_info), 53 (uintptr_t)dev_info.devi_parent) == -1) 54 break; 55 56 (void) mdb_readstr(bind_name, sizeof (bind_name), 57 (uintptr_t)dev_info.devi_binding_name); 58 if (strcmp(bind_name, "isa") == 0) 59 return ("ISA"); 60 else if (strcmp(bind_name, "pci") == 0 || 61 strcmp(bind_name, "npe") == 0) 62 return ("PCI"); 63 } 64 return ("-"); 65 } 66 67 68 static void 69 interrupt_print_isr(struct autovec avhp) 70 { 71 char driver_name[MODMAXNAMELEN + 1]; 72 uintptr_t dip_addr = (uintptr_t)avhp.av_dip; 73 struct dev_info dev_info; 74 75 if (dip_addr && mdb_devinfo2driver(dip_addr, driver_name, 76 sizeof (driver_name)) == 0) { 77 (void) mdb_vread(&dev_info, sizeof (dev_info), dip_addr); 78 mdb_printf("%s#%d", driver_name, dev_info.devi_instance); 79 } else 80 mdb_printf("%a", avhp.av_vector); 81 } 82 83 /* 84 * uppc_interrupt_dump: 85 * Dump uppc(7d) interrupt information. 86 */ 87 /* ARGSUSED */ 88 int 89 uppc_interrupt_dump(uintptr_t addr, uint_t flags, int argc, 90 const mdb_arg_t *argv) 91 { 92 int i, share_cnt; 93 boolean_t found = B_FALSE; 94 struct autovec avhp; 95 96 if (mdb_readvar(&avec_tbl, "autovect") == -1) { 97 mdb_warn("failed to read autovect"); 98 return (DCMD_ERR); 99 } 100 101 if (mdb_readvar(&shared_tbl, "uppc_irq_shared_table") == -1) { 102 mdb_warn("failed to read uppc_irq_shared_table"); 103 return (DCMD_ERR); 104 } 105 106 /* 107 * All x86 systems load uppc(7d) by default. 108 * Now, this becomes interesting on APIC based systems. 109 * 'interrupts' dcmd is supported by both the .so modules 110 * So, uppc(7d) needs to be unloaded somehow on APIC based systems 111 * Here a check for shared_tbl[i] and returning NULL takes care of that 112 */ 113 for (i = 0; i < MAX_ISA_IRQ + 1; i++) 114 if (shared_tbl[i]) { 115 found = B_TRUE; 116 break; 117 } 118 119 if (found == B_FALSE) { 120 if (mdb_lookup_by_obj("pcplusmp", "apic_irq_table", 121 NULL) == 0) { 122 return (mdb_call_dcmd("pcplusmp`interrupts", 123 addr, flags, argc, argv)); 124 } 125 } 126 127 /* Print the header first */ 128 mdb_printf("%<u>IRQ Vector IPL(lo/hi) Bus Share " 129 "Driver Name(s)/ISR(s)%</u>\n"); 130 131 /* Walk all the entries */ 132 for (i = 0; i < MAX_ISA_IRQ + 1; i++) { 133 /* Read the entry, if invalid continue */ 134 if (mdb_vread(&avhp, sizeof (struct autovec), 135 (uintptr_t)avec_tbl[i].avh_link) == -1) 136 continue; 137 138 /* Print each interrupt entry */ 139 share_cnt = shared_tbl[i]; 140 mdb_printf("%3d 0x%2x %4d/%-2d %-4s %3d ", 141 i, i + PIC_VECTBASE, 142 avec_tbl[i].avh_lo_pri, avec_tbl[i].avh_hi_pri, 143 avhp.av_dip ? interrupt_print_bus((uintptr_t)avhp.av_dip) : 144 " - ", share_cnt); 145 146 if (share_cnt) 147 interrupt_print_isr(avhp); 148 149 while (share_cnt-- > 0) { 150 if (mdb_vread(&avhp, sizeof (struct autovec), 151 (uintptr_t)avhp.av_link) != -1) { 152 mdb_printf(", "); 153 interrupt_print_isr(avhp); 154 } 155 } 156 mdb_printf("\n"); 157 } 158 159 return (DCMD_OK); 160 } 161 162 163 /* 164 * MDB module linkage information: 165 */ 166 static const mdb_dcmd_t dcmds[] = { 167 { "interrupts", NULL, "print interrupts", uppc_interrupt_dump, NULL}, 168 { NULL } 169 }; 170 171 static const mdb_modinfo_t modinfo = { MDB_API_VERSION, dcmds, NULL }; 172 173 const mdb_modinfo_t * 174 _mdb_init(void) 175 { 176 return (&modinfo); 177 } 178