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