@@ -8,6 +8,8 @@
#include <linux/hardirq.h>
#include <asm/unwinder.h>
#include <asm/system.h>
+#include <asm/dma.h>
+#include <asm/dma-sh.h>
#ifdef CONFIG_GENERIC_BUG
static void handle_BUG(struct pt_regs *regs)
@@ -95,11 +97,13 @@ BUILD_TRAP_HANDLER(bug)
BUILD_TRAP_HANDLER(nmi)
{
+ unsigned long dmaor;
unsigned int cpu = smp_processor_id();
TRAP_HANDLER_DECL;
nmi_enter();
nmi_count(cpu)++;
+
switch (notify_die(DIE_NMI, "NMI", regs, 0, vec & 0xff, SIGINT)) {
case NOTIFY_OK:
@@ -111,6 +115,22 @@ BUILD_TRAP_HANDLER(nmi)
printk(KERN_ALERT "Got NMI, but nobody cared. Ignoring...\n");
break;
}
-
+
+/* every NMI usually stops all active DMA transfers. These lines simply reanimate the */
+/* DMA channels so that the transfers are resumed */
+#if defined(CONFIG_SH_HICO7723) || defined(CONFIG_SH_HICO7724)
+ dmaor = __raw_readw(SH_DMAC_BASE0 + DMAOR);
+ dmaor &= ~(DMAOR_NMIF | DMAOR_AE); // resetting NMI flag and address error flag
+ __raw_writew( dmaor, SH_DMAC_BASE0 + DMAOR );
+ dmaor |= DMAOR_INIT; // restarting DMA
+ __raw_writew( dmaor, SH_DMAC_BASE0 + DMAOR );
+
+ dmaor = __raw_readw(SH_DMAC_BASE1 + DMAOR);
+ dmaor &= ~(DMAOR_NMIF | DMAOR_AE); // resetting NMI flag and address error flag
+ __raw_writew( dmaor, SH_DMAC_BASE1 + DMAOR );
+ dmaor |= DMAOR_INIT; // restarting DMA
+ __raw_writew( dmaor, SH_DMAC_BASE1 + DMAOR );
+#endif
+
nmi_exit();
}