xref: /illumos-gate/usr/src/cmd/mdb/i86pc/modules/uppc/uppc.c (revision 1a220b56b93ff1dc80855691548503117af4cc10)
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 "intr_common.h"
29 
30 static struct av_head	avec_tbl[APIC_MAX_VECTOR+1];
31 static uint16_t		shared_tbl[MAX_ISA_IRQ + 1];
32 
33 static char *
34 interrupt_print_bus(uintptr_t dip_addr)
35 {
36 	char		bind_name[MODMAXNAMELEN + 1];
37 	struct dev_info	dev_info;
38 
39 	if (mdb_vread(&dev_info, sizeof (dev_info), dip_addr) == -1) {
40 		mdb_warn("failed to read child dip");
41 		return ("-");
42 	}
43 
44 	while (dev_info.devi_parent != 0) {
45 		if (mdb_vread(&dev_info, sizeof (dev_info),
46 		    (uintptr_t)dev_info.devi_parent) == -1)
47 			break;
48 
49 		(void) mdb_readstr(bind_name, sizeof (bind_name),
50 		    (uintptr_t)dev_info.devi_binding_name);
51 		if (strcmp(bind_name, "isa") == 0)
52 			return ("ISA");
53 		else if (strcmp(bind_name, "pci") == 0 ||
54 		    strcmp(bind_name, "npe") == 0)
55 			return ("PCI");
56 	}
57 	return ("-");
58 }
59 
60 
61 /*
62  * uppc_interrupt_dump:
63  *	Dump uppc(7d) interrupt information.
64  */
65 /* ARGSUSED */
66 int
67 uppc_interrupt_dump(uintptr_t addr, uint_t flags, int argc,
68     const mdb_arg_t *argv)
69 {
70 	int		i, j;
71 	boolean_t	found = B_FALSE;
72 	struct autovec	avhp;
73 
74 	option_flags = 0;
75 	if (mdb_getopts(argc, argv,
76 	    'd', MDB_OPT_SETBITS, INTR_DISPLAY_DRVR_INST, &option_flags,
77 	    'i', MDB_OPT_SETBITS, INTR_DISPLAY_INTRSTAT, &option_flags,
78 	    NULL) != argc)
79 		return (DCMD_USAGE);
80 
81 	if (mdb_readvar(&avec_tbl, "autovect") == -1) {
82 		mdb_warn("failed to read autovect");
83 		return (DCMD_ERR);
84 	}
85 
86 	if (mdb_readvar(&shared_tbl, "uppc_irq_shared_table") == -1) {
87 		mdb_warn("failed to read uppc_irq_shared_table");
88 		return (DCMD_ERR);
89 	}
90 
91 	/*
92 	 * By default, on all x86 systems ::interrupts from uppc(7d) gets
93 	 * loaded first. For APIC systems the ::interrupts from pcplusmp(7d)
94 	 * ought to be executed. Confusion stems as both modules export the
95 	 * same dcmd.
96 	 */
97 	for (i = 0; i < MAX_ISA_IRQ + 1; i++)
98 		if (shared_tbl[i]) {
99 			found = B_TRUE;
100 			break;
101 		}
102 
103 	if (found == B_FALSE) {
104 		if (mdb_lookup_by_obj("pcplusmp", "apic_irq_table",
105 		    NULL) == 0) {
106 			return (mdb_call_dcmd("pcplusmp`interrupts",
107 			    addr, flags, argc, argv));
108 		}
109 	}
110 
111 	/* Print the header first */
112 	if (option_flags & INTR_DISPLAY_INTRSTAT)
113 		mdb_printf("%<u>CPU\t ");
114 	else
115 		mdb_printf("%<u>IRQ  Vector IPL(lo/hi) Bus Share ");
116 	mdb_printf("%s %</u>\n", option_flags & INTR_DISPLAY_DRVR_INST ?
117 	    "Driver Name(s)" : "ISR(s)");
118 
119 	/* Walk all the entries */
120 	for (i = 0; i < MAX_ISA_IRQ + 1; i++) {
121 		/* Read the entry, if invalid continue */
122 		if (mdb_vread(&avhp, sizeof (struct autovec),
123 		    (uintptr_t)avec_tbl[i].avh_link) == -1)
124 			continue;
125 
126 		/* Print each interrupt entry */
127 		if (option_flags & INTR_DISPLAY_INTRSTAT)
128 			mdb_printf("cpu0\t");
129 		else
130 			mdb_printf("%-3d   0x%2x   %4d/%-2d   %-4s %-3d  ",
131 			    i, i + PIC_VECTBASE, avec_tbl[i].avh_lo_pri,
132 			    avec_tbl[i].avh_hi_pri, avhp.av_dip ?
133 			    interrupt_print_bus((uintptr_t)avhp.av_dip) : " - ",
134 			    shared_tbl[i]);
135 
136 		if (shared_tbl[i])
137 			interrupt_print_isr((uintptr_t)avhp.av_vector,
138 			    (uintptr_t)avhp.av_intarg1, (uintptr_t)avhp.av_dip);
139 
140 		for (j = 1; j < shared_tbl[i]; j++) {
141 			if (mdb_vread(&avhp, sizeof (struct autovec),
142 			    (uintptr_t)avhp.av_link) != -1)  {
143 				mdb_printf(", ");
144 				interrupt_print_isr((uintptr_t)avhp.av_vector,
145 				    (uintptr_t)avhp.av_intarg1,
146 				    (uintptr_t)avhp.av_dip);
147 			} else {
148 				break;
149 			}
150 		}
151 		mdb_printf("\n");
152 	}
153 
154 	return (DCMD_OK);
155 }
156 
157 
158 /*
159  * MDB module linkage information:
160  */
161 static const mdb_dcmd_t dcmds[] = {
162 	{ "interrupts", "?[-di]", "print interrupts", uppc_interrupt_dump,
163 	    interrupt_help},
164 	{ "softint", "?[-d]", "print soft interrupts", soft_interrupt_dump,
165 	    soft_interrupt_help},
166 	{ NULL }
167 };
168 
169 static const mdb_modinfo_t modinfo = { MDB_API_VERSION, dcmds, NULL };
170 
171 const mdb_modinfo_t *
172 _mdb_init(void)
173 {
174 	GElf_Sym	sym;
175 
176 	if (mdb_lookup_by_name("gld_intr", &sym) != -1)
177 		if (GELF_ST_TYPE(sym.st_info) == STT_FUNC)
178 			gld_intr_addr = (uintptr_t)sym.st_value;
179 
180 	return (&modinfo);
181 }
182