1e1030dccb
This implements support for NMI debugging that was shamelessly copied from the avr32 port. A bit of special magic is needed in the interrupt exception path given that the NMI exception handler is stubbed in to the regular exception handling table despite being reported in INTEVT. So we mangle the lookup and kick off an EXPEVT-style exception dispatch from the INTEVT path for exceptions that do_IRQ() has no chance of handling. As a result, we also drop the evt2irq() conversion from the do_IRQ() path and just do it in assembly. Signed-off-by: Paul Mundt <lethal@linux-sh.org>
77 lines
1.6 KiB
C
77 lines
1.6 KiB
C
/*
|
|
* Copyright (C) 2007 Atmel Corporation
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
* published by the Free Software Foundation.
|
|
*/
|
|
#include <linux/delay.h>
|
|
#include <linux/kdebug.h>
|
|
#include <linux/notifier.h>
|
|
#include <linux/sched.h>
|
|
#include <linux/hardirq.h>
|
|
|
|
enum nmi_action {
|
|
NMI_SHOW_STATE = 1 << 0,
|
|
NMI_SHOW_REGS = 1 << 1,
|
|
NMI_DIE = 1 << 2,
|
|
NMI_DEBOUNCE = 1 << 3,
|
|
};
|
|
|
|
static unsigned long nmi_actions;
|
|
|
|
static int nmi_debug_notify(struct notifier_block *self,
|
|
unsigned long val, void *data)
|
|
{
|
|
struct die_args *args = data;
|
|
|
|
if (likely(val != DIE_NMI))
|
|
return NOTIFY_DONE;
|
|
|
|
if (nmi_actions & NMI_SHOW_STATE)
|
|
show_state();
|
|
if (nmi_actions & NMI_SHOW_REGS)
|
|
show_regs(args->regs);
|
|
if (nmi_actions & NMI_DEBOUNCE)
|
|
mdelay(10);
|
|
if (nmi_actions & NMI_DIE)
|
|
return NOTIFY_BAD;
|
|
|
|
return NOTIFY_OK;
|
|
}
|
|
|
|
static struct notifier_block nmi_debug_nb = {
|
|
.notifier_call = nmi_debug_notify,
|
|
};
|
|
|
|
static int __init nmi_debug_setup(char *str)
|
|
{
|
|
char *p, *sep;
|
|
|
|
register_die_notifier(&nmi_debug_nb);
|
|
|
|
if (*str != '=')
|
|
return 0;
|
|
|
|
for (p = str + 1; *p; p = sep + 1) {
|
|
sep = strchr(p, ',');
|
|
if (sep)
|
|
*sep = 0;
|
|
if (strcmp(p, "state") == 0)
|
|
nmi_actions |= NMI_SHOW_STATE;
|
|
else if (strcmp(p, "regs") == 0)
|
|
nmi_actions |= NMI_SHOW_REGS;
|
|
else if (strcmp(p, "debounce") == 0)
|
|
nmi_actions |= NMI_DEBOUNCE;
|
|
else if (strcmp(p, "die") == 0)
|
|
nmi_actions |= NMI_DIE;
|
|
else
|
|
printk(KERN_WARNING "NMI: Unrecognized action `%s'\n",
|
|
p);
|
|
if (!sep)
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
__setup("nmi_debug", nmi_debug_setup);
|