1cc7a88b5Smrj /*
2cc7a88b5Smrj  * CDDL HEADER START
3cc7a88b5Smrj  *
4cc7a88b5Smrj  * The contents of this file are subject to the terms of the
5cc7a88b5Smrj  * Common Development and Distribution License (the "License").
6cc7a88b5Smrj  * You may not use this file except in compliance with the License.
7cc7a88b5Smrj  *
8cc7a88b5Smrj  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9cc7a88b5Smrj  * or http://www.opensolaris.org/os/licensing.
10cc7a88b5Smrj  * See the License for the specific language governing permissions
11cc7a88b5Smrj  * and limitations under the License.
12cc7a88b5Smrj  *
13cc7a88b5Smrj  * When distributing Covered Code, include this CDDL HEADER in each
14cc7a88b5Smrj  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15cc7a88b5Smrj  * If applicable, add the following below this CDDL HEADER, with the
16cc7a88b5Smrj  * fields enclosed by brackets "[]" replaced with your own identifying
17cc7a88b5Smrj  * information: Portions Copyright [yyyy] [name of copyright owner]
18cc7a88b5Smrj  *
19cc7a88b5Smrj  * CDDL HEADER END
20cc7a88b5Smrj  */
21cc7a88b5Smrj /*
22cc7a88b5Smrj  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23cc7a88b5Smrj  * Use is subject to license terms.
24cc7a88b5Smrj  */
2528e4da25SMatthew Ahrens /*
2628e4da25SMatthew Ahrens  * Copyright (c) 2013 by Delphix. All rights reserved.
2728e4da25SMatthew Ahrens  */
28cc7a88b5Smrj 
29cc7a88b5Smrj #include <mdb/mdb_modapi.h>
30cc7a88b5Smrj #include <mdb/mdb_ks.h>
31cc7a88b5Smrj #include <mdb/mdb_ctf.h>
32cc7a88b5Smrj #include <sys/evtchn_impl.h>
33cc7a88b5Smrj 
34cc7a88b5Smrj #include "intr_common.h"
35cc7a88b5Smrj 
3628e4da25SMatthew Ahrens typedef struct mdb_shared_info {
3728e4da25SMatthew Ahrens 	unsigned long evtchn_pending[sizeof (unsigned long) * NBBY];
3828e4da25SMatthew Ahrens 	unsigned long evtchn_mask[sizeof (unsigned long) * NBBY];
3928e4da25SMatthew Ahrens } mdb_shared_info_t;
4028e4da25SMatthew Ahrens 
4128e4da25SMatthew Ahrens static mdb_shared_info_t	shared_info;
42cc7a88b5Smrj static struct av_head	avec_tbl[NR_IRQS];
43cc7a88b5Smrj static uint16_t		shared_tbl[MAX_ISA_IRQ + 1];
44cc7a88b5Smrj static irq_info_t	irq_tbl[NR_IRQS];
45cc7a88b5Smrj static mec_info_t	virq_tbl[NR_VIRQS];
46cc7a88b5Smrj static short		evtchn_tbl[NR_EVENT_CHANNELS];
47cc7a88b5Smrj 
48cc7a88b5Smrj static int
update_tables(void)49cc7a88b5Smrj update_tables(void)
50cc7a88b5Smrj {
51cc7a88b5Smrj 	uintptr_t shared_info_addr;
52cc7a88b5Smrj 
53cc7a88b5Smrj 	if (mdb_readvar(&irq_tbl, "irq_info") == -1) {
54cc7a88b5Smrj 		mdb_warn("failed to read irq_info");
55cc7a88b5Smrj 		return (0);
56cc7a88b5Smrj 	}
57cc7a88b5Smrj 
58cc7a88b5Smrj 	if (mdb_readvar(&virq_tbl, "virq_info") == -1) {
59cc7a88b5Smrj 		mdb_warn("failed to read virq_info");
60cc7a88b5Smrj 		return (0);
61cc7a88b5Smrj 	}
62cc7a88b5Smrj 
63cc7a88b5Smrj 	if (mdb_readvar(&evtchn_tbl, "evtchn_to_irq") == -1) {
64cc7a88b5Smrj 		mdb_warn("failed to read evtchn_to_irq");
65cc7a88b5Smrj 		return (0);
66cc7a88b5Smrj 	}
67cc7a88b5Smrj 
68cc7a88b5Smrj 	if (mdb_readvar(&avec_tbl, "autovect") == -1) {
69cc7a88b5Smrj 		mdb_warn("failed to read autovect");
70cc7a88b5Smrj 		return (0);
71cc7a88b5Smrj 	}
72cc7a88b5Smrj 
73cc7a88b5Smrj 	if (mdb_readvar(&shared_tbl, "xen_uppc_irq_shared_table") == -1) {
74cc7a88b5Smrj 		mdb_warn("failed to read xen_uppc_irq_shared_table");
75cc7a88b5Smrj 		return (0);
76cc7a88b5Smrj 	}
77cc7a88b5Smrj 
78cc7a88b5Smrj 	if (mdb_readvar(&shared_info_addr, "HYPERVISOR_shared_info") == -1) {
79cc7a88b5Smrj 		mdb_warn("failed to read HYPERVISOR_shared_info");
80cc7a88b5Smrj 		return (0);
81cc7a88b5Smrj 	}
82cc7a88b5Smrj 
8328e4da25SMatthew Ahrens 	if (mdb_ctf_vread(&shared_info, "shared_info_t", "mdb_shared_info_t",
8428e4da25SMatthew Ahrens 	    shared_info_addr, 0) == -1)
85cc7a88b5Smrj 		return (0);
86cc7a88b5Smrj 
87cc7a88b5Smrj 	return (1);
88cc7a88b5Smrj }
89cc7a88b5Smrj 
90cc7a88b5Smrj 
91cc7a88b5Smrj static char *
interrupt_print_bus(uintptr_t dip_addr)92cc7a88b5Smrj interrupt_print_bus(uintptr_t dip_addr)
93cc7a88b5Smrj {
94cc7a88b5Smrj 	char		bind_name[MAXPATHLEN + 1];
95cc7a88b5Smrj 	struct dev_info	dev_info;
96cc7a88b5Smrj 
97cc7a88b5Smrj 	if (mdb_vread(&dev_info, sizeof (dev_info), dip_addr) == -1) {
98cc7a88b5Smrj 		mdb_warn("failed to read child dip");
99cc7a88b5Smrj 		return ("-");
100cc7a88b5Smrj 	}
101cc7a88b5Smrj 
102cc7a88b5Smrj 	while (dev_info.devi_parent != 0) {
103cc7a88b5Smrj 		if (mdb_vread(&dev_info, sizeof (dev_info),
104cc7a88b5Smrj 		    (uintptr_t)dev_info.devi_parent) == -1)
105cc7a88b5Smrj 			break;
106cc7a88b5Smrj 
107cc7a88b5Smrj 		(void) mdb_readstr(bind_name, sizeof (bind_name),
108cc7a88b5Smrj 		    (uintptr_t)dev_info.devi_binding_name);
109cc7a88b5Smrj 		if (strcmp(bind_name, "isa") == 0)
110cc7a88b5Smrj 			return ("ISA");
111cc7a88b5Smrj 		else if (strcmp(bind_name, "pci") == 0 ||
112cc7a88b5Smrj 		    strcmp(bind_name, "npe") == 0)
113cc7a88b5Smrj 			return ("PCI");
114cc7a88b5Smrj 	}
115cc7a88b5Smrj 	return ("-");
116cc7a88b5Smrj }
117cc7a88b5Smrj 
118cc7a88b5Smrj static const char *
virq_type(int irq)119cc7a88b5Smrj virq_type(int irq)
120cc7a88b5Smrj {
121cc7a88b5Smrj 	int i;
122cc7a88b5Smrj 
123cc7a88b5Smrj 	for (i = 0; i < NR_VIRQS; i++) {
124cc7a88b5Smrj 		if (virq_tbl[i].mi_irq == irq)
125cc7a88b5Smrj 			break;
126cc7a88b5Smrj 	}
127cc7a88b5Smrj 
128cc7a88b5Smrj 	switch (i) {
129cc7a88b5Smrj 	case VIRQ_TIMER:
130cc7a88b5Smrj 		return ("virq:timer");
131cc7a88b5Smrj 	case VIRQ_DEBUG:
132cc7a88b5Smrj 		return ("virq:debug");
133cc7a88b5Smrj 	case VIRQ_CONSOLE:
134cc7a88b5Smrj 		return ("virq:console");
135cc7a88b5Smrj 	case VIRQ_DOM_EXC:
136cc7a88b5Smrj 		return ("virq:dom exc");
137cc7a88b5Smrj 	case VIRQ_DEBUGGER:
138cc7a88b5Smrj 		return ("virq:debugger");
139cc7a88b5Smrj 	default:
140cc7a88b5Smrj 		break;
141cc7a88b5Smrj 	}
142cc7a88b5Smrj 
143cc7a88b5Smrj 	return ("virq:?");
144cc7a88b5Smrj }
145cc7a88b5Smrj 
146cc7a88b5Smrj static const char *
irq_type(int irq,int extended)147cc7a88b5Smrj irq_type(int irq, int extended)
148cc7a88b5Smrj {
149cc7a88b5Smrj 	switch (irq_tbl[irq].ii_type) {
150cc7a88b5Smrj 	case IRQT_UNBOUND:
151cc7a88b5Smrj 		return ("unset");
152cc7a88b5Smrj 	case IRQT_PIRQ:
153cc7a88b5Smrj 		return ("pirq");
154cc7a88b5Smrj 	case IRQT_VIRQ:
155cc7a88b5Smrj 		if (extended)
156cc7a88b5Smrj 			return (virq_type(irq));
157cc7a88b5Smrj 		return ("virq");
158cc7a88b5Smrj 	case IRQT_IPI:
159cc7a88b5Smrj 		return ("ipi");
160cc7a88b5Smrj 	case IRQT_EVTCHN:
161cc7a88b5Smrj 		return ("evtchn");
162cc7a88b5Smrj 	case IRQT_DEV_EVTCHN:
163cc7a88b5Smrj 		return ("device");
164cc7a88b5Smrj 	}
165cc7a88b5Smrj 
166cc7a88b5Smrj 	return ("?");
167cc7a88b5Smrj }
168cc7a88b5Smrj 
169cc7a88b5Smrj static void
print_isr(int i)170cc7a88b5Smrj print_isr(int i)
171cc7a88b5Smrj {
172cc7a88b5Smrj 	struct autovec avhp;
173cc7a88b5Smrj 
174cc7a88b5Smrj 	if (avec_tbl[i].avh_link == NULL)
175cc7a88b5Smrj 		return;
176cc7a88b5Smrj 
177cc7a88b5Smrj 	(void) mdb_vread(&avhp, sizeof (struct autovec),
178cc7a88b5Smrj 	    (uintptr_t)avec_tbl[i].avh_link);
179cc7a88b5Smrj 
180cc7a88b5Smrj 	interrupt_print_isr((uintptr_t)avhp.av_vector,
181cc7a88b5Smrj 	    (uintptr_t)avhp.av_intarg1, (uintptr_t)avhp.av_dip);
182cc7a88b5Smrj 
183cc7a88b5Smrj 	while (avhp.av_link != NULL &&
184cc7a88b5Smrj 	    mdb_vread(&avhp, sizeof (struct autovec),
185cc7a88b5Smrj 	    (uintptr_t)avhp.av_link) != -1) {
186cc7a88b5Smrj 		mdb_printf(", ");
187cc7a88b5Smrj 		interrupt_print_isr((uintptr_t)avhp.av_vector,
188cc7a88b5Smrj 		    (uintptr_t)avhp.av_intarg1, (uintptr_t)avhp.av_dip);
189cc7a88b5Smrj 	}
190cc7a88b5Smrj }
191cc7a88b5Smrj 
192cc7a88b5Smrj static int
evtchn_masked(int i)193cc7a88b5Smrj evtchn_masked(int i)
194cc7a88b5Smrj {
195cc7a88b5Smrj 	return (TEST_EVTCHN_BIT(i, &shared_info.evtchn_mask[0]) != 0);
196cc7a88b5Smrj }
197cc7a88b5Smrj 
198cc7a88b5Smrj static int
evtchn_pending(int i)199cc7a88b5Smrj evtchn_pending(int i)
200cc7a88b5Smrj {
201cc7a88b5Smrj 	return (TEST_EVTCHN_BIT(i, &shared_info.evtchn_pending[0]) != 0);
202cc7a88b5Smrj }
203cc7a88b5Smrj 
204cc7a88b5Smrj static void
pic_interrupt_dump(int i,struct autovec * avhp,int evtchn)205cc7a88b5Smrj pic_interrupt_dump(int i, struct autovec *avhp, int evtchn)
206cc7a88b5Smrj {
207cc7a88b5Smrj 	if (option_flags & INTR_DISPLAY_INTRSTAT) {
208cc7a88b5Smrj 		mdb_printf("%-3d ", 0);
209cc7a88b5Smrj 		print_isr(i);
210cc7a88b5Smrj 		mdb_printf("\n");
211cc7a88b5Smrj 		return;
212cc7a88b5Smrj 	}
213cc7a88b5Smrj 
214cc7a88b5Smrj 	mdb_printf("%-3d  0x%2x %-6d %6d/%-2d  %-3s %-6s %-5d ",
215cc7a88b5Smrj 	    i, i + PIC_VECTBASE, evtchn, avec_tbl[i].avh_lo_pri,
216cc7a88b5Smrj 	    avec_tbl[i].avh_hi_pri, avhp->av_dip ?
217cc7a88b5Smrj 	    interrupt_print_bus((uintptr_t)avhp->av_dip) : "-",
218cc7a88b5Smrj 	    irq_type(i, 0), shared_tbl[i]);
219cc7a88b5Smrj 
220cc7a88b5Smrj 	print_isr(i);
221cc7a88b5Smrj 
222cc7a88b5Smrj 	mdb_printf("\n");
223cc7a88b5Smrj }
224cc7a88b5Smrj 
225cc7a88b5Smrj static void
ec_interrupt_dump(int i)226cc7a88b5Smrj ec_interrupt_dump(int i)
227cc7a88b5Smrj {
228cc7a88b5Smrj 	irq_info_t *irqp = &irq_tbl[i];
229cc7a88b5Smrj 	struct autovec avhp;
230cc7a88b5Smrj 	char evtchn[8];
231cc7a88b5Smrj 
232cc7a88b5Smrj 	if (irqp->ii_type == IRQT_UNBOUND)
233cc7a88b5Smrj 		return;
234cc7a88b5Smrj 
235cc7a88b5Smrj 	if (option_flags & INTR_DISPLAY_INTRSTAT) {
236cc7a88b5Smrj 		mdb_printf("%-3d ", 0);
237cc7a88b5Smrj 		print_isr(i);
238cc7a88b5Smrj 		mdb_printf("\n");
239cc7a88b5Smrj 		return;
240cc7a88b5Smrj 	}
241cc7a88b5Smrj 
242cc7a88b5Smrj 
243cc7a88b5Smrj 	memset(&avhp, 0, sizeof (avhp));
244cc7a88b5Smrj 	if (avec_tbl[i].avh_link != NULL)
245cc7a88b5Smrj 		(void) mdb_vread(&avhp, sizeof (struct autovec),
246cc7a88b5Smrj 		    (uintptr_t)avec_tbl[i].avh_link);
247cc7a88b5Smrj 
248cc7a88b5Smrj 	switch (irqp->ii_type) {
249cc7a88b5Smrj 	case IRQT_EVTCHN:
250cc7a88b5Smrj 	case IRQT_VIRQ:
251cc7a88b5Smrj 		if (irqp->ii_u.index == VIRQ_TIMER) {
252cc7a88b5Smrj 			strcpy(evtchn, "T");
253cc7a88b5Smrj 		} else {
254cc7a88b5Smrj 			mdb_snprintf(evtchn, sizeof (evtchn), "%-7d",
255cc7a88b5Smrj 			    irqp->ii_u.evtchn);
256cc7a88b5Smrj 		}
257cc7a88b5Smrj 		break;
258cc7a88b5Smrj 	case IRQT_IPI:
259cc7a88b5Smrj 		strcpy(evtchn, "I");
260cc7a88b5Smrj 		break;
261cc7a88b5Smrj 	case IRQT_DEV_EVTCHN:
262cc7a88b5Smrj 		strcpy(evtchn, "D");
263cc7a88b5Smrj 		break;
264cc7a88b5Smrj 	}
265cc7a88b5Smrj 
266cc7a88b5Smrj 	/* IRQ */
267cc7a88b5Smrj 	mdb_printf("%3d  ", i);
268cc7a88b5Smrj 	/* Vector */
269cc7a88b5Smrj 	mdb_printf("-    ");
270cc7a88b5Smrj 	/* Evtchn */
271cc7a88b5Smrj 	mdb_printf("%-7s", evtchn);
272cc7a88b5Smrj 	/* IPL */
273cc7a88b5Smrj 	mdb_printf("%6d/%-2d  ", irq_tbl[i].ii_u2.ipl, irq_tbl[i].ii_u2.ipl);
274cc7a88b5Smrj 	/* Bus */
275cc7a88b5Smrj 	mdb_printf("%-3s ", avhp.av_dip
276cc7a88b5Smrj 	    ? interrupt_print_bus((uintptr_t)avhp.av_dip) : "-");
277cc7a88b5Smrj 	/* Type */
278cc7a88b5Smrj 	mdb_printf("%-6s ", irq_type(i, 0));
279cc7a88b5Smrj 	/* Share */
280cc7a88b5Smrj 	mdb_printf("-     ");
281cc7a88b5Smrj 
282cc7a88b5Smrj 	print_isr(i);
283cc7a88b5Smrj 
284cc7a88b5Smrj 	mdb_printf("\n");
285cc7a88b5Smrj }
286cc7a88b5Smrj 
287cc7a88b5Smrj /*
288cc7a88b5Smrj  * uppc_interrupt_dump:
289*bbf21555SRichard Lowe  *	Dump uppc(4D) interrupt information.
290cc7a88b5Smrj  */
291cc7a88b5Smrj /* ARGSUSED */
292cc7a88b5Smrj int
xen_uppc_interrupt_dump(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)293cc7a88b5Smrj xen_uppc_interrupt_dump(uintptr_t addr, uint_t flags, int argc,
294cc7a88b5Smrj     const mdb_arg_t *argv)
295cc7a88b5Smrj {
296cc7a88b5Smrj 	int		i;
297cc7a88b5Smrj 	boolean_t	found = B_FALSE;
298cc7a88b5Smrj 	struct autovec	avhp;
299cc7a88b5Smrj 
300cc7a88b5Smrj 	option_flags = 0;
301cc7a88b5Smrj 	if (mdb_getopts(argc, argv,
302cc7a88b5Smrj 	    'd', MDB_OPT_SETBITS, INTR_DISPLAY_DRVR_INST, &option_flags,
303cc7a88b5Smrj 	    'i', MDB_OPT_SETBITS, INTR_DISPLAY_INTRSTAT, &option_flags,
304cc7a88b5Smrj 	    NULL) != argc)
305cc7a88b5Smrj 		return (DCMD_USAGE);
306cc7a88b5Smrj 
307cc7a88b5Smrj 	if (!update_tables())
308cc7a88b5Smrj 		return (DCMD_ERR);
309cc7a88b5Smrj 
310cc7a88b5Smrj 	/*
311*bbf21555SRichard Lowe 	 * By default, on all x86 systems ::interrupts from xen_uppc(4D) gets
312*bbf21555SRichard Lowe 	 * loaded first. For APIC systems the ::interrupts from xpv_psm(4D)
313cc7a88b5Smrj 	 * ought to be executed. Confusion stems as both modules export the
314cc7a88b5Smrj 	 * same dcmd.
315cc7a88b5Smrj 	 */
316cc7a88b5Smrj 	for (i = 0; i < MAX_ISA_IRQ + 1; i++)
317cc7a88b5Smrj 		if (shared_tbl[i]) {
318cc7a88b5Smrj 			found = B_TRUE;
319cc7a88b5Smrj 			break;
320cc7a88b5Smrj 		}
321cc7a88b5Smrj 
322cc7a88b5Smrj 	if (found == B_FALSE) {
323cc7a88b5Smrj 		if (mdb_lookup_by_obj("xpv_psm", "apic_irq_table",
324cc7a88b5Smrj 		    NULL) == 0) {
325cc7a88b5Smrj 			return (mdb_call_dcmd("xpv_psm`interrupts",
326cc7a88b5Smrj 			    addr, flags, argc, argv));
327cc7a88b5Smrj 		}
328cc7a88b5Smrj 	}
329cc7a88b5Smrj 
330cc7a88b5Smrj 	/* Print the header first */
331cc7a88b5Smrj 	if (option_flags & INTR_DISPLAY_INTRSTAT)
332cc7a88b5Smrj 		mdb_printf("%<u>CPU ");
333cc7a88b5Smrj 	else
334cc7a88b5Smrj 		mdb_printf("%<u>IRQ  Vect Evtchn IPL(lo/hi) Bus Type   Share ");
335cc7a88b5Smrj 	mdb_printf("%s %</u>\n", option_flags & INTR_DISPLAY_DRVR_INST ?
336cc7a88b5Smrj 	    "Driver Name(s)" : "ISR(s)");
337cc7a88b5Smrj 
338cc7a88b5Smrj 	for (i = 0; i < NR_IRQS; i++) {
339cc7a88b5Smrj 		if (irq_tbl[i].ii_type == IRQT_PIRQ) {
340cc7a88b5Smrj 			if (irq_tbl[i].ii_u.evtchn == 0)
341cc7a88b5Smrj 				continue;
342cc7a88b5Smrj 
343cc7a88b5Smrj 			/* Read the entry, if invalid continue */
344cc7a88b5Smrj 			if (mdb_vread(&avhp, sizeof (struct autovec),
345cc7a88b5Smrj 			    (uintptr_t)avec_tbl[i].avh_link) == -1)
346cc7a88b5Smrj 				continue;
347cc7a88b5Smrj 
348cc7a88b5Smrj 			pic_interrupt_dump(i, &avhp, irq_tbl[i].ii_u.evtchn);
349cc7a88b5Smrj 			continue;
350cc7a88b5Smrj 		}
351cc7a88b5Smrj 
352cc7a88b5Smrj 		ec_interrupt_dump(i);
353cc7a88b5Smrj 	}
354cc7a88b5Smrj 
355cc7a88b5Smrj 	return (DCMD_OK);
356cc7a88b5Smrj }
357cc7a88b5Smrj 
358cc7a88b5Smrj 
359cc7a88b5Smrj static void
evtchn_dump(int i)360cc7a88b5Smrj evtchn_dump(int i)
361cc7a88b5Smrj {
362cc7a88b5Smrj 	int irq = evtchn_tbl[i];
363cc7a88b5Smrj 
364cc7a88b5Smrj 	if (irq == INVALID_IRQ) {
365cc7a88b5Smrj 		mdb_printf("%-14s%-7d%-4s%-7s", "unassigned", i, "-", "-");
366cc7a88b5Smrj 		mdb_printf("%-4d", 0);
367cc7a88b5Smrj 		mdb_printf("%-7d", evtchn_masked(i));
368cc7a88b5Smrj 		mdb_printf("%-8d", evtchn_pending(i));
369cc7a88b5Smrj 		mdb_printf("\n");
370cc7a88b5Smrj 		return;
371cc7a88b5Smrj 	}
372cc7a88b5Smrj 
373cc7a88b5Smrj 	/* Type */
374cc7a88b5Smrj 	mdb_printf("%-14s", irq_type(irq, 1));
375cc7a88b5Smrj 	/* Evtchn */
376cc7a88b5Smrj 	mdb_printf("%-7d", i);
377cc7a88b5Smrj 	/* IRQ */
378cc7a88b5Smrj 	mdb_printf("%-4d", irq);
379cc7a88b5Smrj 	/* IPL */
380cc7a88b5Smrj 	mdb_printf("%6d/%-2d  ", irq_tbl[irq].ii_u2.ipl,
381cc7a88b5Smrj 	    irq_tbl[irq].ii_u2.ipl);
382cc7a88b5Smrj 	/* CPU */
383cc7a88b5Smrj 	mdb_printf("%-4d", 0);
384cc7a88b5Smrj 	/* Masked/Pending */
385cc7a88b5Smrj 	mdb_printf("%-7d", evtchn_masked(i));
386cc7a88b5Smrj 	mdb_printf("%-8d", evtchn_pending(i));
387cc7a88b5Smrj 	/* ISR */
388cc7a88b5Smrj 	print_isr(irq);
389cc7a88b5Smrj 
390cc7a88b5Smrj 	mdb_printf("\n");
391cc7a88b5Smrj }
392cc7a88b5Smrj 
393cc7a88b5Smrj /* ARGSUSED */
394cc7a88b5Smrj static int
evtchns_dump(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)395cc7a88b5Smrj evtchns_dump(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
396cc7a88b5Smrj {
397cc7a88b5Smrj 	int		i;
398cc7a88b5Smrj 	boolean_t	found = B_FALSE;
399cc7a88b5Smrj 
400cc7a88b5Smrj 	option_flags = 0;
401cc7a88b5Smrj 	if (mdb_getopts(argc, argv,
402cc7a88b5Smrj 	    'd', MDB_OPT_SETBITS, INTR_DISPLAY_DRVR_INST, &option_flags,
403cc7a88b5Smrj 	    NULL) != argc)
404cc7a88b5Smrj 		return (DCMD_USAGE);
405cc7a88b5Smrj 
406cc7a88b5Smrj 	if (!update_tables())
407cc7a88b5Smrj 		return (DCMD_ERR);
408cc7a88b5Smrj 
409cc7a88b5Smrj 	/*
410*bbf21555SRichard Lowe 	 * By default, on all x86 systems ::evtchns from xen_uppc(4D) gets
411*bbf21555SRichard Lowe 	 * loaded first. For APIC systems the ::evtchns from xpv_psm(4D)
412cc7a88b5Smrj 	 * ought to be executed. Confusion stems as both modules export the
413cc7a88b5Smrj 	 * same dcmd.
414cc7a88b5Smrj 	 */
415cc7a88b5Smrj 	for (i = 0; i < MAX_ISA_IRQ + 1; i++)
416cc7a88b5Smrj 		if (shared_tbl[i]) {
417cc7a88b5Smrj 			found = B_TRUE;
418cc7a88b5Smrj 			break;
419cc7a88b5Smrj 		}
420cc7a88b5Smrj 
421cc7a88b5Smrj 	if (found == B_FALSE) {
422cc7a88b5Smrj 		if (mdb_lookup_by_obj("xpv_psm", "apic_irq_table",
423cc7a88b5Smrj 		    NULL) == 0) {
424cc7a88b5Smrj 			return (mdb_call_dcmd("xpv_psm`evtchns",
425cc7a88b5Smrj 			    addr, flags, argc, argv));
426cc7a88b5Smrj 		}
427cc7a88b5Smrj 	}
428cc7a88b5Smrj 
429cc7a88b5Smrj 	if (flags & DCMD_ADDRSPEC) {
430cc7a88b5Smrj 		/*
431cc7a88b5Smrj 		 * Note: we allow the invalid evtchn 0, as it can help catch if
432cc7a88b5Smrj 		 * we incorrectly try to configure it.
433cc7a88b5Smrj 		 */
434cc7a88b5Smrj 		if ((int)addr >= NR_EVENT_CHANNELS) {
435cc7a88b5Smrj 			mdb_warn("Invalid event channel %d.\n", (int)addr);
436cc7a88b5Smrj 			return (DCMD_ERR);
437cc7a88b5Smrj 		}
438cc7a88b5Smrj 	}
439cc7a88b5Smrj 
440cc7a88b5Smrj 	mdb_printf("%<u>Type          Evtchn IRQ IPL(lo/hi) CPU "
441cc7a88b5Smrj 	    "Masked Pending ");
442cc7a88b5Smrj 	mdb_printf("%s %</u>\n", option_flags & INTR_DISPLAY_DRVR_INST ?
443cc7a88b5Smrj 	    "Driver Name(s)" : "ISR(s)");
444cc7a88b5Smrj 
445cc7a88b5Smrj 	if (flags & DCMD_ADDRSPEC) {
446cc7a88b5Smrj 		evtchn_dump((int)addr);
447cc7a88b5Smrj 		return (DCMD_OK);
448cc7a88b5Smrj 	}
449cc7a88b5Smrj 
450cc7a88b5Smrj 	for (i = 0; i < NR_EVENT_CHANNELS; i++) {
451cc7a88b5Smrj 		if (evtchn_tbl[i] == INVALID_IRQ)
452cc7a88b5Smrj 			continue;
453cc7a88b5Smrj 
454cc7a88b5Smrj 		evtchn_dump(i);
455cc7a88b5Smrj 	}
456cc7a88b5Smrj 
457cc7a88b5Smrj 	return (DCMD_OK);
458cc7a88b5Smrj }
459cc7a88b5Smrj 
460cc7a88b5Smrj static void
evtchns_help(void)461cc7a88b5Smrj evtchns_help(void)
462cc7a88b5Smrj {
463cc7a88b5Smrj 	mdb_printf("Print valid event channels\n"
464cc7a88b5Smrj 	    "If %<u>addr%</u> is given, interpret it as an evtchn to print "
465cc7a88b5Smrj 	    "details of.\n"
466cc7a88b5Smrj 	    "By default, only interrupt service routine names are printed.\n\n"
467cc7a88b5Smrj 	    "Switches:\n"
468cc7a88b5Smrj 	    "  -d   instead of ISR, print <driver_name><instance#>\n");
469cc7a88b5Smrj }
470cc7a88b5Smrj 
471cc7a88b5Smrj /*
472cc7a88b5Smrj  * MDB module linkage information:
473cc7a88b5Smrj  */
474cc7a88b5Smrj static const mdb_dcmd_t dcmds[] = {
475cc7a88b5Smrj 	{ "interrupts", "?[-di]", "print interrupts", xen_uppc_interrupt_dump,
476cc7a88b5Smrj 	    interrupt_help},
477cc7a88b5Smrj 	{ "evtchns", "?[-d]", "print event channels", evtchns_dump,
478cc7a88b5Smrj 	    evtchns_help },
479cc7a88b5Smrj 	{ "softint", "?[-d]", "print soft interrupts", soft_interrupt_dump,
480cc7a88b5Smrj 	    soft_interrupt_help},
481cc7a88b5Smrj 	{ NULL }
482cc7a88b5Smrj };
483cc7a88b5Smrj 
484cc7a88b5Smrj static const mdb_modinfo_t modinfo = { MDB_API_VERSION, dcmds, NULL };
485cc7a88b5Smrj 
486cc7a88b5Smrj const mdb_modinfo_t *
_mdb_init(void)487cc7a88b5Smrj _mdb_init(void)
488cc7a88b5Smrj {
489cc7a88b5Smrj 	GElf_Sym	sym;
490cc7a88b5Smrj 
491cc7a88b5Smrj 	if (mdb_lookup_by_name("gld_intr", &sym) != -1)
492cc7a88b5Smrj 		if (GELF_ST_TYPE(sym.st_info) == STT_FUNC)
493cc7a88b5Smrj 			gld_intr_addr = (uintptr_t)sym.st_value;
494cc7a88b5Smrj 
495cc7a88b5Smrj 	return (&modinfo);
496cc7a88b5Smrj }
497