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