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 /*
225cd376e8SJimmy 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 *
interrupt_print_bus(uintptr_t dip_addr)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
uppc_interrupt_dump(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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 /*
89*7ff178cdSJimmy Vetayases * By default, on all x86 systems ::interrupts from uppc gets
90*7ff178cdSJimmy Vetayases * loaded first. For APIC systems the ::interrupts from either
91*7ff178cdSJimmy Vetayases * apix or pcplusmp ought to be executed. Confusion stems as
92*7ff178cdSJimmy 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) {
101*7ff178cdSJimmy Vetayases if (mdb_lookup_by_obj("apix", "apixs", NULL) == 0) {
102*7ff178cdSJimmy Vetayases return (mdb_call_dcmd("apix`interrupts",
103*7ff178cdSJimmy Vetayases addr, flags, argc, argv));
104*7ff178cdSJimmy 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 *
_mdb_init(void)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