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