summary refs log tree commit diff
path: root/arch/avr32/kernel
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2008-01-25 08:40:02 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2008-01-25 08:40:02 -0800
commit7556afa0e0e436cad4f560ee83e5fbd5dac9359a (patch)
treec1500918b4b7c8b760feab1c8eeb8a815d2135ca /arch/avr32/kernel
parente07dd2ad305f6b29b47d713600aa8b722ef2a9f7 (diff)
parentd6c49a7a78fc841418bbd58bda504076f80ec51d (diff)
downloadlinux-7556afa0e0e436cad4f560ee83e5fbd5dac9359a.tar.gz
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/hskinnemoen/avr32-2.6
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/hskinnemoen/avr32-2.6:
  [AVR32] extint: Set initial irq type to low level
  [AVR32] extint: change set_irq_type() handling
  [AVR32] NMI debugging
  [AVR32] constify function pointer tables
  [AVR32] ATNGW100: Update defconfig
  [AVR32] ATSTK1002: Update defconfig
  [AVR32] Kconfig: Choose daughterboard instead of CPU
  [AVR32] Add support for ATSTK1003 and ATSTK1004
  [AVR32] Clean up external DAC setup code
  [AVR32] ATSTK1000: Move gpio-leds setup to setup.c
  [AVR32] Add support for AT32AP7001 and AT32AP7002
  [AVR32] Provide more CPU information in /proc/cpuinfo and dmesg
  [AVR32] Oprofile support
  [AVR32] Include instrumentation menu
  Disable VGA text console for AVR32 architecture
  [AVR32] Enable debugging only when needed
  ptrace: Call arch_ptrace_attach() when request=PTRACE_TRACEME
  [AVR32] Remove redundant try_to_freeze() call from do_signal()
  [AVR32] Drop GFP_COMP for DMA memory allocations
Diffstat (limited to 'arch/avr32/kernel')
-rw-r--r--arch/avr32/kernel/Makefile3
-rw-r--r--arch/avr32/kernel/cpu.c96
-rw-r--r--arch/avr32/kernel/irq.c11
-rw-r--r--arch/avr32/kernel/kprobes.c5
-rw-r--r--arch/avr32/kernel/nmi_debug.c82
-rw-r--r--arch/avr32/kernel/ocd.c163
-rw-r--r--arch/avr32/kernel/process.c5
-rw-r--r--arch/avr32/kernel/ptrace.c5
-rw-r--r--arch/avr32/kernel/signal.c7
-rw-r--r--arch/avr32/kernel/traps.c21
10 files changed, 352 insertions, 46 deletions
diff --git a/arch/avr32/kernel/Makefile b/arch/avr32/kernel/Makefile
index 2d6d48f35f69..e4b6d122b033 100644
--- a/arch/avr32/kernel/Makefile
+++ b/arch/avr32/kernel/Makefile
@@ -6,9 +6,10 @@ extra-y				:= head.o vmlinux.lds
 
 obj-$(CONFIG_SUBARCH_AVR32B)	+= entry-avr32b.o
 obj-y				+= syscall_table.o syscall-stubs.o irq.o
-obj-y				+= setup.o traps.o semaphore.o ptrace.o
+obj-y				+= setup.o traps.o semaphore.o ocd.o ptrace.o
 obj-y				+= signal.o sys_avr32.o process.o time.o
 obj-y				+= init_task.o switch_to.o cpu.o
 obj-$(CONFIG_MODULES)		+= module.o avr32_ksyms.o
 obj-$(CONFIG_KPROBES)		+= kprobes.o
 obj-$(CONFIG_STACKTRACE)	+= stacktrace.o
+obj-$(CONFIG_NMI_DEBUGGING)	+= nmi_debug.o
diff --git a/arch/avr32/kernel/cpu.c b/arch/avr32/kernel/cpu.c
index 2714cf6452b5..b8409caeb23d 100644
--- a/arch/avr32/kernel/cpu.c
+++ b/arch/avr32/kernel/cpu.c
@@ -13,6 +13,7 @@
 #include <linux/percpu.h>
 #include <linux/param.h>
 #include <linux/errno.h>
+#include <linux/clk.h>
 
 #include <asm/setup.h>
 #include <asm/sysreg.h>
@@ -187,9 +188,20 @@ static int __init topology_init(void)
 
 subsys_initcall(topology_init);
 
+struct chip_id_map {
+	u16	mid;
+	u16	pn;
+	const char *name;
+};
+
+static const struct chip_id_map chip_names[] = {
+	{ .mid = 0x1f, .pn = 0x1e82, .name = "AT32AP700x" },
+};
+#define NR_CHIP_NAMES ARRAY_SIZE(chip_names)
+
 static const char *cpu_names[] = {
 	"Morgan",
-	"AP7000",
+	"AP7",
 };
 #define NR_CPU_NAMES ARRAY_SIZE(cpu_names)
 
@@ -206,12 +218,32 @@ static const char *mmu_types[] = {
 	"MPU"
 };
 
+static const char *cpu_feature_flags[] = {
+	"rmw", "dsp", "simd", "ocd", "perfctr", "java", "fpu",
+};
+
+static const char *get_chip_name(struct avr32_cpuinfo *cpu)
+{
+	unsigned int i;
+	unsigned int mid = avr32_get_manufacturer_id(cpu);
+	unsigned int pn = avr32_get_product_number(cpu);
+
+	for (i = 0; i < NR_CHIP_NAMES; i++) {
+		if (chip_names[i].mid == mid && chip_names[i].pn == pn)
+			return chip_names[i].name;
+	}
+
+	return "(unknown)";
+}
+
 void __init setup_processor(void)
 {
 	unsigned long config0, config1;
 	unsigned long features;
 	unsigned cpu_id, cpu_rev, arch_id, arch_rev, mmu_type;
+	unsigned device_id;
 	unsigned tmp;
+	unsigned i;
 
 	config0 = sysreg_read(CONFIG0);
 	config1 = sysreg_read(CONFIG1);
@@ -221,11 +253,14 @@ void __init setup_processor(void)
 	arch_rev = SYSREG_BFEXT(AR, config0);
 	mmu_type = SYSREG_BFEXT(MMUT, config0);
 
+	device_id = ocd_read(DID);
+
 	boot_cpu_data.arch_type = arch_id;
 	boot_cpu_data.cpu_type = cpu_id;
 	boot_cpu_data.arch_revision = arch_rev;
 	boot_cpu_data.cpu_revision = cpu_rev;
 	boot_cpu_data.tlb_config = mmu_type;
+	boot_cpu_data.device_id = device_id;
 
 	tmp = SYSREG_BFEXT(ILSZ, config1);
 	if (tmp) {
@@ -247,41 +282,34 @@ void __init setup_processor(void)
 		return;
 	}
 
-	printk ("CPU: %s [%02x] revision %d (%s revision %d)\n",
+	printk ("CPU: %s chip revision %c\n", get_chip_name(&boot_cpu_data),
+			avr32_get_chip_revision(&boot_cpu_data) + 'A');
+	printk ("CPU: %s [%02x] core revision %d (%s arch revision %d)\n",
 		cpu_names[cpu_id], cpu_id, cpu_rev,
 		arch_names[arch_id], arch_rev);
 	printk ("CPU: MMU configuration: %s\n", mmu_types[mmu_type]);
 
 	printk ("CPU: features:");
 	features = 0;
-	if (config0 & SYSREG_BIT(CONFIG0_R)) {
+	if (config0 & SYSREG_BIT(CONFIG0_R))
 		features |= AVR32_FEATURE_RMW;
-		printk(" rmw");
-	}
-	if (config0 & SYSREG_BIT(CONFIG0_D)) {
+	if (config0 & SYSREG_BIT(CONFIG0_D))
 		features |= AVR32_FEATURE_DSP;
-		printk(" dsp");
-	}
-	if (config0 & SYSREG_BIT(CONFIG0_S)) {
+	if (config0 & SYSREG_BIT(CONFIG0_S))
 		features |= AVR32_FEATURE_SIMD;
-		printk(" simd");
-	}
-	if (config0 & SYSREG_BIT(CONFIG0_O)) {
+	if (config0 & SYSREG_BIT(CONFIG0_O))
 		features |= AVR32_FEATURE_OCD;
-		printk(" ocd");
-	}
-	if (config0 & SYSREG_BIT(CONFIG0_P)) {
+	if (config0 & SYSREG_BIT(CONFIG0_P))
 		features |= AVR32_FEATURE_PCTR;
-		printk(" perfctr");
-	}
-	if (config0 & SYSREG_BIT(CONFIG0_J)) {
+	if (config0 & SYSREG_BIT(CONFIG0_J))
 		features |= AVR32_FEATURE_JAVA;
-		printk(" java");
-	}
-	if (config0 & SYSREG_BIT(CONFIG0_F)) {
+	if (config0 & SYSREG_BIT(CONFIG0_F))
 		features |= AVR32_FEATURE_FPU;
-		printk(" fpu");
-	}
+
+	for (i = 0; i < ARRAY_SIZE(cpu_feature_flags); i++)
+		if (features & (1 << i))
+			printk(" %s", cpu_feature_flags[i]);
+
 	printk("\n");
 	boot_cpu_data.features = features;
 }
@@ -291,6 +319,8 @@ static int c_show(struct seq_file *m, void *v)
 {
 	unsigned int icache_size, dcache_size;
 	unsigned int cpu = smp_processor_id();
+	unsigned int freq;
+	unsigned int i;
 
 	icache_size = boot_cpu_data.icache.ways *
 		boot_cpu_data.icache.sets *
@@ -301,15 +331,21 @@ static int c_show(struct seq_file *m, void *v)
 
 	seq_printf(m, "processor\t: %d\n", cpu);
 
+	seq_printf(m, "chip type\t: %s revision %c\n",
+			get_chip_name(&boot_cpu_data),
+			avr32_get_chip_revision(&boot_cpu_data) + 'A');
 	if (boot_cpu_data.arch_type < NR_ARCH_NAMES)
-		seq_printf(m, "cpu family\t: %s revision %d\n",
+		seq_printf(m, "cpu arch\t: %s revision %d\n",
 			   arch_names[boot_cpu_data.arch_type],
 			   boot_cpu_data.arch_revision);
 	if (boot_cpu_data.cpu_type < NR_CPU_NAMES)
-		seq_printf(m, "cpu type\t: %s revision %d\n",
+		seq_printf(m, "cpu core\t: %s revision %d\n",
 			   cpu_names[boot_cpu_data.cpu_type],
 			   boot_cpu_data.cpu_revision);
 
+	freq = (clk_get_rate(boot_cpu_data.clk) + 500) / 1000;
+	seq_printf(m, "cpu MHz\t\t: %u.%03u\n", freq / 1000, freq % 1000);
+
 	seq_printf(m, "i-cache\t\t: %dK (%u ways x %u sets x %u)\n",
 		   icache_size >> 10,
 		   boot_cpu_data.icache.ways,
@@ -320,7 +356,13 @@ static int c_show(struct seq_file *m, void *v)
 		   boot_cpu_data.dcache.ways,
 		   boot_cpu_data.dcache.sets,
 		   boot_cpu_data.dcache.linesz);
-	seq_printf(m, "bogomips\t: %lu.%02lu\n",
+
+	seq_printf(m, "features\t:");
+	for (i = 0; i < ARRAY_SIZE(cpu_feature_flags); i++)
+		if (boot_cpu_data.features & (1 << i))
+			seq_printf(m, " %s", cpu_feature_flags[i]);
+
+	seq_printf(m, "\nbogomips\t: %lu.%02lu\n",
 		   boot_cpu_data.loops_per_jiffy / (500000/HZ),
 		   (boot_cpu_data.loops_per_jiffy / (5000/HZ)) % 100);
 
@@ -343,7 +385,7 @@ static void c_stop(struct seq_file *m, void *v)
 
 }
 
-struct seq_operations cpuinfo_op = {
+const struct seq_operations cpuinfo_op = {
 	.start	= c_start,
 	.next	= c_next,
 	.stop	= c_stop,
diff --git a/arch/avr32/kernel/irq.c b/arch/avr32/kernel/irq.c
index 61f2de266f62..a8e767d836aa 100644
--- a/arch/avr32/kernel/irq.c
+++ b/arch/avr32/kernel/irq.c
@@ -25,6 +25,17 @@ void ack_bad_irq(unsigned int irq)
 	printk("unexpected IRQ %u\n", irq);
 }
 
+/* May be overridden by platform code */
+int __weak nmi_enable(void)
+{
+	return -ENOSYS;
+}
+
+void __weak nmi_disable(void)
+{
+
+}
+
 #ifdef CONFIG_PROC_FS
 int show_interrupts(struct seq_file *p, void *v)
 {
diff --git a/arch/avr32/kernel/kprobes.c b/arch/avr32/kernel/kprobes.c
index 799ba89b07a8..f820e9f25520 100644
--- a/arch/avr32/kernel/kprobes.c
+++ b/arch/avr32/kernel/kprobes.c
@@ -48,6 +48,7 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p)
 void __kprobes arch_arm_kprobe(struct kprobe *p)
 {
 	pr_debug("arming kprobe at %p\n", p->addr);
+	ocd_enable(NULL);
 	*p->addr = BREAKPOINT_INSTRUCTION;
 	flush_icache_range((unsigned long)p->addr,
 			   (unsigned long)p->addr + sizeof(kprobe_opcode_t));
@@ -56,6 +57,7 @@ void __kprobes arch_arm_kprobe(struct kprobe *p)
 void __kprobes arch_disarm_kprobe(struct kprobe *p)
 {
 	pr_debug("disarming kprobe at %p\n", p->addr);
+	ocd_disable(NULL);
 	*p->addr = p->opcode;
 	flush_icache_range((unsigned long)p->addr,
 			   (unsigned long)p->addr + sizeof(kprobe_opcode_t));
@@ -260,9 +262,6 @@ int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
 
 int __init arch_init_kprobes(void)
 {
-	printk("KPROBES: Enabling monitor mode (MM|DBE)...\n");
-	ocd_write(DC, (1 << OCD_DC_MM_BIT) | (1 << OCD_DC_DBE_BIT));
-
 	/* TODO: Register kretprobe trampoline */
 	return 0;
 }
diff --git a/arch/avr32/kernel/nmi_debug.c b/arch/avr32/kernel/nmi_debug.c
new file mode 100644
index 000000000000..3414b8566c29
--- /dev/null
+++ b/arch/avr32/kernel/nmi_debug.c
@@ -0,0 +1,82 @@
+/*
+ * 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 <asm/irq.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 (nmi_enable()) {
+		printk(KERN_WARNING "Unable to enable NMI.\n");
+		return 0;
+	}
+
+	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);
diff --git a/arch/avr32/kernel/ocd.c b/arch/avr32/kernel/ocd.c
new file mode 100644
index 000000000000..c4f023294d75
--- /dev/null
+++ b/arch/avr32/kernel/ocd.c
@@ -0,0 +1,163 @@
+/*
+ * 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/init.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+
+#include <asm/ocd.h>
+
+static long ocd_count;
+static spinlock_t ocd_lock;
+
+/**
+ * ocd_enable - enable on-chip debugging
+ * @child: task to be debugged
+ *
+ * If @child is non-NULL, ocd_enable() first checks if debugging has
+ * already been enabled for @child, and if it has, does nothing.
+ *
+ * If @child is NULL (e.g. when debugging the kernel), or debugging
+ * has not already been enabled for it, ocd_enable() increments the
+ * reference count and enables the debugging hardware.
+ */
+void ocd_enable(struct task_struct *child)
+{
+	u32 dc;
+
+	if (child)
+		pr_debug("ocd_enable: child=%s [%u]\n",
+				child->comm, child->pid);
+	else
+		pr_debug("ocd_enable (no child)\n");
+
+	if (!child || !test_and_set_tsk_thread_flag(child, TIF_DEBUG)) {
+		spin_lock(&ocd_lock);
+		ocd_count++;
+		dc = ocd_read(DC);
+		dc |= (1 << OCD_DC_MM_BIT) | (1 << OCD_DC_DBE_BIT);
+		ocd_write(DC, dc);
+		spin_unlock(&ocd_lock);
+	}
+}
+
+/**
+ * ocd_disable - disable on-chip debugging
+ * @child: task that was being debugged, but isn't anymore
+ *
+ * If @child is non-NULL, ocd_disable() checks if debugging is enabled
+ * for @child, and if it isn't, does nothing.
+ *
+ * If @child is NULL (e.g. when debugging the kernel), or debugging is
+ * enabled, ocd_disable() decrements the reference count, and if it
+ * reaches zero, disables the debugging hardware.
+ */
+void ocd_disable(struct task_struct *child)
+{
+	u32 dc;
+
+	if (!child)
+		pr_debug("ocd_disable (no child)\n");
+	else if (test_tsk_thread_flag(child, TIF_DEBUG))
+		pr_debug("ocd_disable: child=%s [%u]\n",
+				child->comm, child->pid);
+
+	if (!child || test_and_clear_tsk_thread_flag(child, TIF_DEBUG)) {
+		spin_lock(&ocd_lock);
+		ocd_count--;
+
+		WARN_ON(ocd_count < 0);
+
+		if (ocd_count <= 0) {
+			dc = ocd_read(DC);
+			dc &= ~((1 << OCD_DC_MM_BIT) | (1 << OCD_DC_DBE_BIT));
+			ocd_write(DC, dc);
+		}
+		spin_unlock(&ocd_lock);
+	}
+}
+
+#ifdef CONFIG_DEBUG_FS
+#include <linux/debugfs.h>
+#include <linux/module.h>
+
+static struct dentry *ocd_debugfs_root;
+static struct dentry *ocd_debugfs_DC;
+static struct dentry *ocd_debugfs_DS;
+static struct dentry *ocd_debugfs_count;
+
+static u64 ocd_DC_get(void *data)
+{
+	return ocd_read(DC);
+}
+static void ocd_DC_set(void *data, u64 val)
+{
+	ocd_write(DC, val);
+}
+DEFINE_SIMPLE_ATTRIBUTE(fops_DC, ocd_DC_get, ocd_DC_set, "0x%08llx\n");
+
+static u64 ocd_DS_get(void *data)
+{
+	return ocd_read(DS);
+}
+DEFINE_SIMPLE_ATTRIBUTE(fops_DS, ocd_DS_get, NULL, "0x%08llx\n");
+
+static u64 ocd_count_get(void *data)
+{
+	return ocd_count;
+}
+DEFINE_SIMPLE_ATTRIBUTE(fops_count, ocd_count_get, NULL, "%lld\n");
+
+static void ocd_debugfs_init(void)
+{
+	struct dentry *root;
+
+	root = debugfs_create_dir("ocd", NULL);
+	if (IS_ERR(root) || !root)
+		goto err_root;
+	ocd_debugfs_root = root;
+
+	ocd_debugfs_DC = debugfs_create_file("DC", S_IRUSR | S_IWUSR,
+				root, NULL, &fops_DC);
+	if (!ocd_debugfs_DC)
+		goto err_DC;
+
+	ocd_debugfs_DS = debugfs_create_file("DS", S_IRUSR, root,
+				NULL, &fops_DS);
+	if (!ocd_debugfs_DS)
+		goto err_DS;
+
+	ocd_debugfs_count = debugfs_create_file("count", S_IRUSR, root,
+				NULL, &fops_count);
+	if (!ocd_debugfs_count)
+		goto err_count;
+
+	return;
+
+err_count:
+	debugfs_remove(ocd_debugfs_DS);
+err_DS:
+	debugfs_remove(ocd_debugfs_DC);
+err_DC:
+	debugfs_remove(ocd_debugfs_root);
+err_root:
+	printk(KERN_WARNING "OCD: Failed to create debugfs entries\n");
+}
+#else
+static inline void ocd_debugfs_init(void)
+{
+
+}
+#endif
+
+static int __init ocd_init(void)
+{
+	spin_lock_init(&ocd_lock);
+	ocd_debugfs_init();
+	return 0;
+}
+arch_initcall(ocd_init);
diff --git a/arch/avr32/kernel/process.c b/arch/avr32/kernel/process.c
index 9d6dac8af7a2..eaaa69bbdc38 100644
--- a/arch/avr32/kernel/process.c
+++ b/arch/avr32/kernel/process.c
@@ -103,7 +103,7 @@ EXPORT_SYMBOL(kernel_thread);
  */
 void exit_thread(void)
 {
-	/* nothing to do */
+	ocd_disable(current);
 }
 
 void flush_thread(void)
@@ -345,6 +345,9 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
 	p->thread.cpu_context.ksp = (unsigned long)childregs;
 	p->thread.cpu_context.pc = (unsigned long)ret_from_fork;
 
+	if ((clone_flags & CLONE_PTRACE) && test_thread_flag(TIF_DEBUG))
+		ocd_enable(p);
+
 	return 0;
 }
 
diff --git a/arch/avr32/kernel/ptrace.c b/arch/avr32/kernel/ptrace.c
index 002369e44093..1fed38fcf594 100644
--- a/arch/avr32/kernel/ptrace.c
+++ b/arch/avr32/kernel/ptrace.c
@@ -58,6 +58,7 @@ void ptrace_disable(struct task_struct *child)
 {
 	clear_tsk_thread_flag(child, TIF_SINGLE_STEP);
 	clear_tsk_thread_flag(child, TIF_BREAKPOINT);
+	ocd_disable(child);
 }
 
 /*
@@ -144,10 +145,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
 {
 	int ret;
 
-	pr_debug("ptrace: Enabling monitor mode...\n");
-	ocd_write(DC, ocd_read(DC) | (1 << OCD_DC_MM_BIT)
-			| (1 << OCD_DC_DBE_BIT));
-
 	switch (request) {
 	/* Read the word at location addr in the child process */
 	case PTRACE_PEEKTEXT:
diff --git a/arch/avr32/kernel/signal.c b/arch/avr32/kernel/signal.c
index 0ec14854a200..5616a00c10ba 100644
--- a/arch/avr32/kernel/signal.c
+++ b/arch/avr32/kernel/signal.c
@@ -270,19 +270,12 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset, int syscall)
 	if (!user_mode(regs))
 		return 0;
 
-	if (try_to_freeze()) {
-		signr = 0;
-		if (!signal_pending(current))
-			goto no_signal;
-	}
-
 	if (test_thread_flag(TIF_RESTORE_SIGMASK))
 		oldset = &current->saved_sigmask;
 	else if (!oldset)
 		oldset = &current->blocked;
 
 	signr = get_signal_to_deliver(&info, &ka, regs, NULL);
-no_signal:
 	if (syscall) {
 		switch (regs->r12) {
 		case -ERESTART_RESTARTBLOCK:
diff --git a/arch/avr32/kernel/traps.c b/arch/avr32/kernel/traps.c
index 870c075e6314..cf6f686d9b0b 100644
--- a/arch/avr32/kernel/traps.c
+++ b/arch/avr32/kernel/traps.c
@@ -9,6 +9,7 @@
 #include <linux/bug.h>
 #include <linux/init.h>
 #include <linux/kallsyms.h>
+#include <linux/kdebug.h>
 #include <linux/module.h>
 #include <linux/notifier.h>
 #include <linux/sched.h>
@@ -107,9 +108,23 @@ void _exception(long signr, struct pt_regs *regs, int code,
 
 asmlinkage void do_nmi(unsigned long ecr, struct pt_regs *regs)
 {
-	printk(KERN_ALERT "Got Non-Maskable Interrupt, dumping regs\n");
-	show_regs_log_lvl(regs, KERN_ALERT);
-	show_stack_log_lvl(current, regs->sp, regs, KERN_ALERT);
+	int ret;
+
+	nmi_enter();
+
+	ret = notify_die(DIE_NMI, "NMI", regs, 0, ecr, SIGINT);
+	switch (ret) {
+	case NOTIFY_OK:
+	case NOTIFY_STOP:
+		return;
+	case NOTIFY_BAD:
+		die("Fatal Non-Maskable Interrupt", regs, SIGINT);
+	default:
+		break;
+	}
+
+	printk(KERN_ALERT "Got NMI, but nobody cared. Disabling...\n");
+	nmi_disable();
 }
 
 asmlinkage void do_critical_exception(unsigned long ecr, struct pt_regs *regs)