/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* Copyright (c) 2013 by Delphix. All rights reserved.
*/
#include <mdb/mdb_modapi.h>
#include <sys/evtchn_impl.h>
#include <errno.h>
#include <sys/xc_levels.h>
#include "intr_common.h"
typedef struct mdb_shared_info {
static int have_shared_info;
static int
update_tables(void)
{
mdb_warn("failed to read irq_info");
return (0);
}
mdb_warn("failed to read ipi_info");
return (0);
}
mdb_warn("failed to read autovect");
return (0);
}
mdb_warn("failed to read irq_info");
return (0);
}
mdb_warn("failed to read ipi_info");
return (0);
}
mdb_warn("failed to read virq_info");
return (0);
}
mdb_warn("failed to read evtchn_to_irq");
return (0);
}
mdb_warn("failed to read apic_irq_table");
return (0);
}
mdb_warn("failed to read apic_level_intr");
return (0);
}
mdb_warn("failed to lookup evtchn_cpus");
return (0);
}
mdb_warn("failed to read HYPERVISOR_shared_info");
return (0);
}
/*
* It's normal for this to fail with a domain dump.
*/
have_shared_info = 1;
return (1);
}
static const char *
{
int i;
for (i = 0; i < NR_VIRQS; i++) {
break;
}
switch (i) {
case VIRQ_TIMER:
return ("virq:timer");
case VIRQ_DEBUG:
return ("virq:debug");
case VIRQ_CONSOLE:
return ("virq:console");
case VIRQ_DOM_EXC:
return ("virq:dom exc");
case VIRQ_DEBUGGER:
return ("virq:debugger");
case VIRQ_MCA:
return ("virq:mca");
default:
break;
}
return ("virq:?");
}
static const char *
{
case IRQT_UNBOUND:
return ("unset");
case IRQT_PIRQ:
return ("pirq");
case IRQT_VIRQ:
if (extended)
return ("virq");
case IRQT_IPI:
return ("ipi");
case IRQT_EVTCHN:
return ("evtchn");
case IRQT_DEV_EVTCHN:
return ("device");
}
return ("?");
}
/*
* We need a non-trivial IPL lookup as the CPU poke's IRQ doesn't have ii_ipl
* set -- see evtchn.h.
*/
static int
{
int i;
for (i = 0; i < MAXIPL; i++) {
return (i);
}
}
return (0);
}
static void
{
int cpu;
case IRQT_VIRQ:
case IRQT_IPI:
mdb_printf("all ");
return;
case IRQT_DEV_EVTCHN:
mdb_printf("0 ");
return;
default:
break;
}
}
mdb_printf("- ");
return;
}
(cpuset_size * evtchn));
/*
* XXPV: we should verify this against the CPU's mask and show
* something if they don't match.
*/
}
static void
print_isr(int i)
{
} else if (irq_ipl(i) == XC_CPUPOKE_PIL) {
mdb_printf("poke_cpu");
}
}
static int
evtchn_masked(int i)
{
}
static int
evtchn_pending(int i)
{
}
typedef struct mdb_xpv_psm_autovec {
static void
{
goto fail;
goto fail;
/*
* Sigh. As a result of the perennial confusion of how you do opaque
* handles, dev_info_t has a funny old type, which means we can't use
* mdb_ctf_vread() here.
*/
goto fail;
goto fail;
goto fail;
return;
fail:
mdb_printf("- ");
}
static void
ec_interrupt_dump(int i)
{
return;
if (option_flags & INTR_DISPLAY_INTRSTAT) {
print_isr(i);
mdb_printf("\n");
return;
}
case IRQT_EVTCHN:
case IRQT_VIRQ:
} else {
}
break;
case IRQT_IPI:
break;
case IRQT_DEV_EVTCHN:
break;
}
/* IRQ */
mdb_printf("%3d ", i);
/* Vector */
mdb_printf("- ");
/* Evtchn */
/* IPL */
/* Bus */
print_bus(i);
/* Trigger */
/* Type */
/* CPU */
/* Share */
mdb_printf("- ");
mdb_printf("- ");
print_isr(i);
mdb_printf("\n");
}
/* ARGSUSED */
static int
{
int i;
option_flags = 0;
return (DCMD_USAGE);
if (!update_tables())
return (DCMD_ERR);
if (option_flags & INTR_DISPLAY_INTRSTAT) {
mdb_printf("%<u>CPU ");
} else {
mdb_printf("%<u>IRQ Vect Evtchn IPL Bus Trg Type "
}
"Driver Name(s)" : "ISR(s)");
for (i = 0; i < NR_IRQS; i++) {
continue;
continue;
continue;
}
}
return (DCMD_OK);
}
static void
evtchn_dump(int i)
{
if (irq == INVALID_IRQ) {
if (have_shared_info) {
}
mdb_printf("\n");
return;
}
/* Type */
/* Evtchn */
mdb_printf("%-7d", i);
/* IRQ */
/* IPL */
/* CPU */
if (have_shared_info) {
}
/* ISR */
mdb_printf("\n");
}
/* ARGSUSED */
static int
{
int i;
option_flags = 0;
return (DCMD_USAGE);
if (!update_tables())
return (DCMD_ERR);
if (flags & DCMD_ADDRSPEC) {
/*
* Note: we allow the invalid evtchn 0, as it can help catch if
* we incorrectly try to configure it.
*/
if ((int)addr >= NR_EVENT_CHANNELS) {
return (DCMD_ERR);
}
}
mdb_printf("%<u>Type Evtchn IRQ IPL CPU ");
if (have_shared_info)
mdb_printf("Masked Pending ");
"Driver Name(s)" : "ISR(s)");
if (flags & DCMD_ADDRSPEC) {
evtchn_dump((int)addr);
return (DCMD_OK);
}
for (i = 0; i < NR_EVENT_CHANNELS; i++) {
if (evtchn_tbl[i] == INVALID_IRQ)
continue;
evtchn_dump(i);
}
return (DCMD_OK);
}
static void
evtchns_help(void)
{
mdb_printf("Print valid event channels\n"
"If %<u>addr%</u> is given, interpret it as an evtchn to print "
"details of.\n"
"By default, only interrupt service routine names are printed.\n\n"
"Switches:\n"
" -d instead of ISR, print <driver_name><instance#>\n");
}
evtchns_help },
{ NULL }
};
const mdb_modinfo_t *
_mdb_init(void)
{
return (&modinfo);
}