xref: /onnv-gate/usr/src/cmd/mdb/i86xpv/modules/xpv_psm/xpv_psm.c (revision 9489:7aad39a516b4)
15084Sjohnlev /*
25084Sjohnlev  * CDDL HEADER START
35084Sjohnlev  *
45084Sjohnlev  * The contents of this file are subject to the terms of the
55084Sjohnlev  * Common Development and Distribution License (the "License").
65084Sjohnlev  * You may not use this file except in compliance with the License.
75084Sjohnlev  *
85084Sjohnlev  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
95084Sjohnlev  * or http://www.opensolaris.org/os/licensing.
105084Sjohnlev  * See the License for the specific language governing permissions
115084Sjohnlev  * and limitations under the License.
125084Sjohnlev  *
135084Sjohnlev  * When distributing Covered Code, include this CDDL HEADER in each
145084Sjohnlev  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
155084Sjohnlev  * If applicable, add the following below this CDDL HEADER, with the
165084Sjohnlev  * fields enclosed by brackets "[]" replaced with your own identifying
175084Sjohnlev  * information: Portions Copyright [yyyy] [name of copyright owner]
185084Sjohnlev  *
195084Sjohnlev  * CDDL HEADER END
205084Sjohnlev  */
215084Sjohnlev /*
22*9489SJoe.Bonasera@sun.com  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
235084Sjohnlev  * Use is subject to license terms.
245084Sjohnlev  */
255084Sjohnlev 
265084Sjohnlev #include <mdb/mdb_modapi.h>
275084Sjohnlev #include <mdb/mdb_ks.h>
285084Sjohnlev #include <mdb/mdb_ctf.h>
295084Sjohnlev #include <sys/evtchn_impl.h>
305084Sjohnlev #include <errno.h>
31*9489SJoe.Bonasera@sun.com #include <sys/xc_levels.h>
325084Sjohnlev 
335084Sjohnlev #include "intr_common.h"
345084Sjohnlev 
355084Sjohnlev static shared_info_t shared_info;
365084Sjohnlev static int have_shared_info;
375084Sjohnlev static uintptr_t evtchn_cpus_addr;
385084Sjohnlev static struct av_head avec_tbl[NR_IRQS];
395084Sjohnlev static irq_info_t irq_tbl[NR_IRQS];
405084Sjohnlev static mec_info_t ipi_tbl[MAXIPL];
415084Sjohnlev static mec_info_t virq_tbl[NR_VIRQS];
425084Sjohnlev static short evtchn_tbl[NR_EVENT_CHANNELS];
435084Sjohnlev static apic_irq_t *apic_irq_tbl[APIC_MAX_VECTOR+1];
445084Sjohnlev static char level_tbl[APIC_MAX_VECTOR+1];
455084Sjohnlev 
465084Sjohnlev static int
update_tables(void)475084Sjohnlev update_tables(void)
485084Sjohnlev {
495084Sjohnlev 	GElf_Sym sym;
505084Sjohnlev 	uintptr_t shared_info_addr;
515084Sjohnlev 
525084Sjohnlev 	if (mdb_readvar(&irq_tbl, "irq_info") == -1) {
535084Sjohnlev 		mdb_warn("failed to read irq_info");
545084Sjohnlev 		return (0);
555084Sjohnlev 	}
565084Sjohnlev 
575084Sjohnlev 	if (mdb_readvar(&ipi_tbl, "ipi_info") == -1) {
585084Sjohnlev 		mdb_warn("failed to read ipi_info");
595084Sjohnlev 		return (0);
605084Sjohnlev 	}
615084Sjohnlev 
625084Sjohnlev 	if (mdb_readvar(&avec_tbl, "autovect") == -1) {
635084Sjohnlev 		mdb_warn("failed to read autovect");
645084Sjohnlev 		return (0);
655084Sjohnlev 	}
665084Sjohnlev 
675084Sjohnlev 	if (mdb_readvar(&irq_tbl, "irq_info") == -1) {
685084Sjohnlev 		mdb_warn("failed to read irq_info");
695084Sjohnlev 		return (0);
705084Sjohnlev 	}
715084Sjohnlev 
725084Sjohnlev 	if (mdb_readvar(&ipi_tbl, "ipi_info") == -1) {
735084Sjohnlev 		mdb_warn("failed to read ipi_info");
745084Sjohnlev 		return (0);
755084Sjohnlev 	}
765084Sjohnlev 
775084Sjohnlev 	if (mdb_readvar(&virq_tbl, "virq_info") == -1) {
785084Sjohnlev 		mdb_warn("failed to read virq_info");
795084Sjohnlev 		return (0);
805084Sjohnlev 	}
815084Sjohnlev 
825084Sjohnlev 	if (mdb_readvar(&evtchn_tbl, "evtchn_to_irq") == -1) {
835084Sjohnlev 		mdb_warn("failed to read evtchn_to_irq");
845084Sjohnlev 		return (0);
855084Sjohnlev 	}
865084Sjohnlev 
875084Sjohnlev 	if (mdb_readvar(&apic_irq_tbl, "apic_irq_table") == -1) {
885084Sjohnlev 		mdb_warn("failed to read apic_irq_table");
895084Sjohnlev 		return (0);
905084Sjohnlev 	}
915084Sjohnlev 
925084Sjohnlev 	if (mdb_readvar(&level_tbl, "apic_level_intr") == -1) {
935084Sjohnlev 		mdb_warn("failed to read apic_level_intr");
945084Sjohnlev 		return (0);
955084Sjohnlev 	}
965084Sjohnlev 
975084Sjohnlev 	if (mdb_lookup_by_name("evtchn_cpus", &sym) == -1) {
985084Sjohnlev 		mdb_warn("failed to lookup evtchn_cpus");
995084Sjohnlev 		return (0);
1005084Sjohnlev 	}
1015084Sjohnlev 
1025084Sjohnlev 	evtchn_cpus_addr = sym.st_value;
1035084Sjohnlev 
1045084Sjohnlev 	if (mdb_readvar(&shared_info_addr, "HYPERVISOR_shared_info") == -1) {
1055084Sjohnlev 		mdb_warn("failed to read HYPERVISOR_shared_info");
1065084Sjohnlev 		return (0);
1075084Sjohnlev 	}
1085084Sjohnlev 
1095084Sjohnlev 	/*
1105084Sjohnlev 	 * It's normal for this to fail with a domain dump.
1115084Sjohnlev 	 */
1125084Sjohnlev 	if (mdb_ctf_vread(&shared_info, "shared_info_t",
1135084Sjohnlev 	    shared_info_addr, 0) != -1)
1145084Sjohnlev 		have_shared_info = 1;
1155084Sjohnlev 
1165084Sjohnlev 	return (1);
1175084Sjohnlev }
1185084Sjohnlev 
1195084Sjohnlev static const char *
virq_type(int irq)1205084Sjohnlev virq_type(int irq)
1215084Sjohnlev {
1225084Sjohnlev 	int i;
1235084Sjohnlev 
1245084Sjohnlev 	for (i = 0; i < NR_VIRQS; i++) {
1255084Sjohnlev 		if (virq_tbl[i].mi_irq == irq)
1265084Sjohnlev 			break;
1275084Sjohnlev 	}
1285084Sjohnlev 
1295084Sjohnlev 	switch (i) {
1305084Sjohnlev 	case VIRQ_TIMER:
1315084Sjohnlev 		return ("virq:timer");
1325084Sjohnlev 	case VIRQ_DEBUG:
1335084Sjohnlev 		return ("virq:debug");
1345084Sjohnlev 	case VIRQ_CONSOLE:
1355084Sjohnlev 		return ("virq:console");
1365084Sjohnlev 	case VIRQ_DOM_EXC:
1375084Sjohnlev 		return ("virq:dom exc");
1385084Sjohnlev 	case VIRQ_DEBUGGER:
1395084Sjohnlev 		return ("virq:debugger");
1407532SSean.Ye@Sun.COM 	case VIRQ_MCA:
1417532SSean.Ye@Sun.COM 		return ("virq:mca");
1425084Sjohnlev 	default:
1435084Sjohnlev 		break;
1445084Sjohnlev 	}
1455084Sjohnlev 
1465084Sjohnlev 	return ("virq:?");
1475084Sjohnlev }
1485084Sjohnlev 
1495084Sjohnlev static const char *
irq_type(int irq,int extended)1505084Sjohnlev irq_type(int irq, int extended)
1515084Sjohnlev {
1525084Sjohnlev 	switch (irq_tbl[irq].ii_type) {
1535084Sjohnlev 	case IRQT_UNBOUND:
1545084Sjohnlev 		return ("unset");
1555084Sjohnlev 	case IRQT_PIRQ:
1565084Sjohnlev 		return ("pirq");
1575084Sjohnlev 	case IRQT_VIRQ:
1585084Sjohnlev 		if (extended)
1595084Sjohnlev 			return (virq_type(irq));
1605084Sjohnlev 		return ("virq");
1615084Sjohnlev 	case IRQT_IPI:
1625084Sjohnlev 		return ("ipi");
1635084Sjohnlev 	case IRQT_EVTCHN:
1645084Sjohnlev 		return ("evtchn");
1655084Sjohnlev 	case IRQT_DEV_EVTCHN:
1665084Sjohnlev 		return ("device");
1675084Sjohnlev 	}
1685084Sjohnlev 
1695084Sjohnlev 	return ("?");
1705084Sjohnlev }
1715084Sjohnlev 
1725084Sjohnlev /*
1735084Sjohnlev  * We need a non-trivial IPL lookup as the CPU poke's IRQ doesn't have ii_ipl
1745084Sjohnlev  * set -- see evtchn.h.
1755084Sjohnlev  */
1765084Sjohnlev static int
irq_ipl(int irq)1775084Sjohnlev irq_ipl(int irq)
1785084Sjohnlev {
1795084Sjohnlev 	int i;
1805084Sjohnlev 
1815084Sjohnlev 	if (irq_tbl[irq].ii_u2.ipl != 0)
1825084Sjohnlev 		return (irq_tbl[irq].ii_u2.ipl);
1835084Sjohnlev 
1845084Sjohnlev 	for (i = 0; i < MAXIPL; i++) {
1855084Sjohnlev 		if (ipi_tbl[i].mi_irq == irq) {
1865084Sjohnlev 			return (i);
1875084Sjohnlev 		}
1885084Sjohnlev 	}
1895084Sjohnlev 
1905084Sjohnlev 	return (0);
1915084Sjohnlev }
1925084Sjohnlev 
1935084Sjohnlev static void
print_cpu(irq_info_t * irqp,int evtchn)1945084Sjohnlev print_cpu(irq_info_t *irqp, int evtchn)
1955084Sjohnlev {
1965084Sjohnlev 	size_t cpuset_size = BT_BITOUL(NCPU) * sizeof (ulong_t);
1975084Sjohnlev 	int cpu;
1985084Sjohnlev 
1995084Sjohnlev 	if (irqp != NULL) {
2005084Sjohnlev 		switch (irqp->ii_type) {
2015084Sjohnlev 		case IRQT_VIRQ:
2025084Sjohnlev 		case IRQT_IPI:
2035084Sjohnlev 			mdb_printf("all ");
2045084Sjohnlev 			return;
2055084Sjohnlev 
2065084Sjohnlev 		case IRQT_DEV_EVTCHN:
2075084Sjohnlev 			mdb_printf("0   ");
2085084Sjohnlev 			return;
2095084Sjohnlev 
2105084Sjohnlev 		default:
2115084Sjohnlev 			break;
2125084Sjohnlev 		}
2135084Sjohnlev 	}
2145084Sjohnlev 
2155084Sjohnlev 	if (evtchn >= NR_EVENT_CHANNELS || evtchn == 0) {
2165084Sjohnlev 		mdb_printf("-   ");
2175084Sjohnlev 		return;
2185084Sjohnlev 	}
2195084Sjohnlev 
2205084Sjohnlev 	cpu = mdb_cpuset_find(evtchn_cpus_addr +
2215084Sjohnlev 	    (cpuset_size * evtchn));
2225084Sjohnlev 
2235084Sjohnlev 	/*
2245084Sjohnlev 	 * XXPV: we should verify this against the CPU's mask and show
2255084Sjohnlev 	 * something if they don't match.
2265084Sjohnlev 	 */
2275084Sjohnlev 	mdb_printf("%-4d", cpu);
2285084Sjohnlev }
2295084Sjohnlev 
2305084Sjohnlev static void
print_isr(int i)2315084Sjohnlev print_isr(int i)
2325084Sjohnlev {
2335084Sjohnlev 	if (avec_tbl[i].avh_link != NULL) {
2345084Sjohnlev 		struct autovec avhp;
2355084Sjohnlev 
2365084Sjohnlev 		(void) mdb_vread(&avhp, sizeof (struct autovec),
2375084Sjohnlev 		    (uintptr_t)avec_tbl[i].avh_link);
2385084Sjohnlev 
2395084Sjohnlev 		interrupt_print_isr((uintptr_t)avhp.av_vector,
2405084Sjohnlev 		    (uintptr_t)avhp.av_intarg1, (uintptr_t)avhp.av_dip);
2415084Sjohnlev 	} else if (irq_ipl(i) == XC_CPUPOKE_PIL) {
2425084Sjohnlev 		mdb_printf("poke_cpu");
2435084Sjohnlev 	}
2445084Sjohnlev }
2455084Sjohnlev 
2465084Sjohnlev static int
evtchn_masked(int i)2475084Sjohnlev evtchn_masked(int i)
2485084Sjohnlev {
2495084Sjohnlev 	return (!!TEST_EVTCHN_BIT(i, &shared_info.evtchn_mask[0]));
2505084Sjohnlev }
2515084Sjohnlev 
2525084Sjohnlev static int
evtchn_pending(int i)2535084Sjohnlev evtchn_pending(int i)
2545084Sjohnlev {
2555084Sjohnlev 	return (!!TEST_EVTCHN_BIT(i, &shared_info.evtchn_pending[0]));
2565084Sjohnlev }
2575084Sjohnlev 
2585084Sjohnlev static void
print_bus(int irq)2595084Sjohnlev print_bus(int irq)
2605084Sjohnlev {
2615084Sjohnlev 	char parent[7];
2625084Sjohnlev 	uintptr_t dip_addr;
2635084Sjohnlev 	struct dev_info	dev_info;
2645084Sjohnlev 	struct autovec avhp;
2655084Sjohnlev 
2665084Sjohnlev 	bzero(&avhp, sizeof (avhp));
2675084Sjohnlev 
2685084Sjohnlev 	if (mdb_ctf_vread(&avhp, "struct autovec",
2695084Sjohnlev 	    (uintptr_t)avec_tbl[irq].avh_link, 0) == -1)
2705084Sjohnlev 		goto fail;
2715084Sjohnlev 
2725084Sjohnlev 	dip_addr = (uintptr_t)avhp.av_dip;
2735084Sjohnlev 
2745084Sjohnlev 	if (dip_addr == NULL)
2755084Sjohnlev 		goto fail;
2765084Sjohnlev 
2775084Sjohnlev 	/*
2785084Sjohnlev 	 * Sigh.  As a result of the perennial confusion of how you do opaque
2795084Sjohnlev 	 * handles, dev_info_t has a funny old type, which means we can't use
2805084Sjohnlev 	 * mdb_ctf_vread() here.
2815084Sjohnlev 	 */
2825084Sjohnlev 
2835084Sjohnlev 	if (mdb_vread(&dev_info, sizeof (struct dev_info), dip_addr) == -1)
2845084Sjohnlev 		goto fail;
2855084Sjohnlev 
2865084Sjohnlev 	dip_addr = (uintptr_t)dev_info.devi_parent;
2875084Sjohnlev 
2885084Sjohnlev 	if (mdb_vread(&dev_info, sizeof (struct dev_info), dip_addr) == -1)
2895084Sjohnlev 		goto fail;
2905084Sjohnlev 
2915084Sjohnlev 	if (mdb_readstr(parent, 7, (uintptr_t)dev_info.devi_node_name) == -1)
2925084Sjohnlev 		goto fail;
2935084Sjohnlev 
2945084Sjohnlev 	mdb_printf("%-6s ", parent);
2955084Sjohnlev 	return;
2965084Sjohnlev 
2975084Sjohnlev fail:
2985084Sjohnlev 	mdb_printf("-      ");
2995084Sjohnlev }
3005084Sjohnlev 
3015084Sjohnlev static void
ec_interrupt_dump(int i)3025084Sjohnlev ec_interrupt_dump(int i)
3035084Sjohnlev {
3045084Sjohnlev 	irq_info_t *irqp = &irq_tbl[i];
3055084Sjohnlev 	char evtchn[8];
3065084Sjohnlev 
3075084Sjohnlev 	if (irqp->ii_type == IRQT_UNBOUND)
3085084Sjohnlev 		return;
3095084Sjohnlev 
3105084Sjohnlev 	if (option_flags & INTR_DISPLAY_INTRSTAT) {
3115084Sjohnlev 		print_cpu(irqp, irqp->ii_u.evtchn);
3125084Sjohnlev 		print_isr(i);
3135084Sjohnlev 		mdb_printf("\n");
3145084Sjohnlev 		return;
3155084Sjohnlev 	}
3165084Sjohnlev 
3175084Sjohnlev 	switch (irqp->ii_type) {
3185084Sjohnlev 	case IRQT_EVTCHN:
3195084Sjohnlev 	case IRQT_VIRQ:
3205084Sjohnlev 		if (irqp->ii_u.index == VIRQ_TIMER) {
3215084Sjohnlev 			strcpy(evtchn, "T");
3225084Sjohnlev 		} else {
3235084Sjohnlev 			mdb_snprintf(evtchn, sizeof (evtchn), "%-7d",
3245084Sjohnlev 			    irqp->ii_u.evtchn);
3255084Sjohnlev 		}
3265084Sjohnlev 		break;
3275084Sjohnlev 	case IRQT_IPI:
3285084Sjohnlev 		strcpy(evtchn, "I");
3295084Sjohnlev 		break;
3305084Sjohnlev 	case IRQT_DEV_EVTCHN:
3315084Sjohnlev 		strcpy(evtchn, "D");
3325084Sjohnlev 		break;
3335084Sjohnlev 	}
3345084Sjohnlev 
3355084Sjohnlev 	/* IRQ */
3365084Sjohnlev 	mdb_printf("%3d  ", i);
3375084Sjohnlev 	/* Vector */
3385084Sjohnlev 	mdb_printf("-    ");
3395084Sjohnlev 	/* Evtchn */
3405084Sjohnlev 	mdb_printf("%-7s", evtchn);
3415084Sjohnlev 	/* IPL */
3425084Sjohnlev 	mdb_printf("%-4d", irq_ipl(i));
3435084Sjohnlev 	/* Bus */
3445084Sjohnlev 	print_bus(i);
3455084Sjohnlev 	/* Trigger */
3465084Sjohnlev 	mdb_printf("%-4s", "Edg");
3475084Sjohnlev 	/* Type */
3485084Sjohnlev 	mdb_printf("%-7s", irq_type(i, 0));
3495084Sjohnlev 	/* CPU */
3505084Sjohnlev 	print_cpu(irqp, irqp->ii_u.evtchn);
3515084Sjohnlev 	/* Share */
3525084Sjohnlev 	mdb_printf("-     ");
3535084Sjohnlev 	/* APIC/INT# */
3545084Sjohnlev 	mdb_printf("-         ");
3555084Sjohnlev 
3565084Sjohnlev 	print_isr(i);
3575084Sjohnlev 
3585084Sjohnlev 	mdb_printf("\n");
3595084Sjohnlev }
3605084Sjohnlev 
3615084Sjohnlev /* ARGSUSED */
3625084Sjohnlev static int
interrupts_dump(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)3635084Sjohnlev interrupts_dump(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
3645084Sjohnlev {
3655084Sjohnlev 	int i;
3665084Sjohnlev 
3675084Sjohnlev 	option_flags = 0;
3685084Sjohnlev 	if (mdb_getopts(argc, argv,
3695084Sjohnlev 	    'd', MDB_OPT_SETBITS, INTR_DISPLAY_DRVR_INST, &option_flags,
3705084Sjohnlev 	    'i', MDB_OPT_SETBITS, INTR_DISPLAY_INTRSTAT, &option_flags,
3715084Sjohnlev 	    NULL) != argc)
3725084Sjohnlev 		return (DCMD_USAGE);
3735084Sjohnlev 
3745084Sjohnlev 	if (!update_tables())
3755084Sjohnlev 		return (DCMD_ERR);
3765084Sjohnlev 
3775084Sjohnlev 	if (option_flags & INTR_DISPLAY_INTRSTAT) {
3785084Sjohnlev 		mdb_printf("%<u>CPU ");
3795084Sjohnlev 	} else {
3805084Sjohnlev 		mdb_printf("%<u>IRQ  Vect Evtchn IPL Bus    Trg Type   "
3815084Sjohnlev 		    "CPU Share APIC/INT# ");
3825084Sjohnlev 	}
3835084Sjohnlev 	mdb_printf("%s %</u>\n", option_flags & INTR_DISPLAY_DRVR_INST ?
3845084Sjohnlev 	    "Driver Name(s)" : "ISR(s)");
3855084Sjohnlev 
3865084Sjohnlev 	for (i = 0; i < NR_IRQS; i++) {
3875084Sjohnlev 		if (irq_tbl[i].ii_type == IRQT_PIRQ) {
3885084Sjohnlev 			apic_irq_t airq;
3895084Sjohnlev 
3905084Sjohnlev 			if (irq_tbl[i].ii_u.evtchn == 0)
3915084Sjohnlev 				continue;
3925084Sjohnlev 
3935084Sjohnlev 			if (mdb_vread(&airq, sizeof (apic_irq_t),
3945084Sjohnlev 			    (uintptr_t)apic_irq_tbl[i]) == -1)
3955084Sjohnlev 				continue;
3965084Sjohnlev 
3975084Sjohnlev 			apic_interrupt_dump(&airq, &avec_tbl[i], i,
3985084Sjohnlev 			    &irq_tbl[i].ii_u.evtchn, level_tbl[i]);
3995084Sjohnlev 			continue;
4005084Sjohnlev 		}
4015084Sjohnlev 
4025084Sjohnlev 		ec_interrupt_dump(i);
4035084Sjohnlev 	}
4045084Sjohnlev 
4055084Sjohnlev 	return (DCMD_OK);
4065084Sjohnlev }
4075084Sjohnlev 
4085084Sjohnlev static void
evtchn_dump(int i)4095084Sjohnlev evtchn_dump(int i)
4105084Sjohnlev {
4115084Sjohnlev 	int irq = evtchn_tbl[i];
4125084Sjohnlev 
4135084Sjohnlev 	if (irq == INVALID_IRQ) {
4145084Sjohnlev 		mdb_printf("%-14s%-7d%-4s%-4s", "unassigned", i, "-", "-");
4155084Sjohnlev 		print_cpu(NULL, i);
4165084Sjohnlev 		if (have_shared_info) {
4175084Sjohnlev 			mdb_printf("%-7d", evtchn_masked(i));
4185084Sjohnlev 			mdb_printf("%-8d", evtchn_pending(i));
4195084Sjohnlev 		}
4205084Sjohnlev 		mdb_printf("\n");
4215084Sjohnlev 		return;
4225084Sjohnlev 	}
4235084Sjohnlev 
4245084Sjohnlev 	/* Type */
4255084Sjohnlev 	mdb_printf("%-14s", irq_type(irq, 1));
4265084Sjohnlev 	/* Evtchn */
4275084Sjohnlev 	mdb_printf("%-7d", i);
4285084Sjohnlev 	/* IRQ */
4295084Sjohnlev 	mdb_printf("%-4d", irq);
4305084Sjohnlev 	/* IPL */
4315084Sjohnlev 	mdb_printf("%-4d", irq_ipl(irq));
4325084Sjohnlev 	/* CPU */
4335084Sjohnlev 	print_cpu(NULL, i);
4345084Sjohnlev 	if (have_shared_info) {
4355084Sjohnlev 		/* Masked/Pending */
4365084Sjohnlev 		mdb_printf("%-7d", evtchn_masked(i));
4375084Sjohnlev 		mdb_printf("%-8d", evtchn_pending(i));
4385084Sjohnlev 	}
4395084Sjohnlev 	/* ISR */
4405084Sjohnlev 	print_isr(irq);
4415084Sjohnlev 
4425084Sjohnlev 	mdb_printf("\n");
4435084Sjohnlev }
4445084Sjohnlev 
4455084Sjohnlev /* ARGSUSED */
4465084Sjohnlev static int
evtchns_dump(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)4475084Sjohnlev evtchns_dump(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
4485084Sjohnlev {
4495084Sjohnlev 	int i;
4505084Sjohnlev 
4515084Sjohnlev 	option_flags = 0;
4525084Sjohnlev 	if (mdb_getopts(argc, argv,
4535084Sjohnlev 	    'd', MDB_OPT_SETBITS, INTR_DISPLAY_DRVR_INST, &option_flags,
4545084Sjohnlev 	    NULL) != argc)
4555084Sjohnlev 		return (DCMD_USAGE);
4565084Sjohnlev 
4575084Sjohnlev 	if (!update_tables())
4585084Sjohnlev 		return (DCMD_ERR);
4595084Sjohnlev 
4605084Sjohnlev 	if (flags & DCMD_ADDRSPEC) {
4615084Sjohnlev 		/*
4625084Sjohnlev 		 * Note: we allow the invalid evtchn 0, as it can help catch if
4635084Sjohnlev 		 * we incorrectly try to configure it.
4645084Sjohnlev 		 */
4655084Sjohnlev 		if ((int)addr >= NR_EVENT_CHANNELS) {
4665084Sjohnlev 			mdb_warn("Invalid event channel %d.\n", (int)addr);
4675084Sjohnlev 			return (DCMD_ERR);
4685084Sjohnlev 		}
4695084Sjohnlev 	}
4705084Sjohnlev 
4715084Sjohnlev 	mdb_printf("%<u>Type          Evtchn IRQ IPL CPU ");
4725084Sjohnlev 	if (have_shared_info)
4735084Sjohnlev 		mdb_printf("Masked Pending ");
4745084Sjohnlev 
4755084Sjohnlev 	mdb_printf("%s %</u>\n", option_flags & INTR_DISPLAY_DRVR_INST ?
4765084Sjohnlev 	    "Driver Name(s)" : "ISR(s)");
4775084Sjohnlev 
4785084Sjohnlev 	if (flags & DCMD_ADDRSPEC) {
4795084Sjohnlev 		evtchn_dump((int)addr);
4805084Sjohnlev 		return (DCMD_OK);
4815084Sjohnlev 	}
4825084Sjohnlev 
4835084Sjohnlev 	for (i = 0; i < NR_EVENT_CHANNELS; i++) {
4845084Sjohnlev 		if (evtchn_tbl[i] == INVALID_IRQ)
4855084Sjohnlev 			continue;
4865084Sjohnlev 
4875084Sjohnlev 		evtchn_dump(i);
4885084Sjohnlev 	}
4895084Sjohnlev 
4905084Sjohnlev 	return (DCMD_OK);
4915084Sjohnlev }
4925084Sjohnlev 
4935084Sjohnlev static void
evtchns_help(void)4945084Sjohnlev evtchns_help(void)
4955084Sjohnlev {
4965084Sjohnlev 	mdb_printf("Print valid event channels\n"
4975084Sjohnlev 	    "If %<u>addr%</u> is given, interpret it as an evtchn to print "
4985084Sjohnlev 	    "details of.\n"
4995084Sjohnlev 	    "By default, only interrupt service routine names are printed.\n\n"
5005084Sjohnlev 	    "Switches:\n"
5015084Sjohnlev 	    "  -d   instead of ISR, print <driver_name><instance#>\n");
5025084Sjohnlev }
5035084Sjohnlev 
5045084Sjohnlev static const mdb_dcmd_t dcmds[] = {
5055084Sjohnlev 	{ "interrupts", "?[-di]", "print interrupts", interrupts_dump,
5065084Sjohnlev 	    interrupt_help },
5075084Sjohnlev 	{ "evtchns", "?[-d]", "print event channels", evtchns_dump,
5085084Sjohnlev 	    evtchns_help },
5095084Sjohnlev 	{ "softint", "?[-d]", "print soft interrupts", soft_interrupt_dump,
5105084Sjohnlev 	    soft_interrupt_help},
5115084Sjohnlev 	{ NULL }
5125084Sjohnlev };
5135084Sjohnlev 
5145084Sjohnlev static const mdb_modinfo_t modinfo = { MDB_API_VERSION, dcmds, NULL };
5155084Sjohnlev 
5165084Sjohnlev const mdb_modinfo_t *
_mdb_init(void)5175084Sjohnlev _mdb_init(void)
5185084Sjohnlev {
5195084Sjohnlev 	GElf_Sym sym;
5205084Sjohnlev 
5215084Sjohnlev 	if (mdb_lookup_by_name("gld_intr", &sym) != -1)
5225084Sjohnlev 		if (GELF_ST_TYPE(sym.st_info) == STT_FUNC)
5235084Sjohnlev 			gld_intr_addr = (uintptr_t)sym.st_value;
5245084Sjohnlev 
5255084Sjohnlev 	return (&modinfo);
5265084Sjohnlev }
527