#include <linux/mm.h>
#include <linux/hardirq.h>
#include <linux/kprobes.h>
+#include <asm/io_trapped.h>
#include <asm/system.h>
#include <asm/mmu_context.h>
#include <asm/tlbflush.h>
int fault;
siginfo_t info;
- trace_hardirqs_on();
- local_irq_enable();
-
#ifdef CONFIG_SH_KGDB
if (kgdb_nofault && kgdb_bus_err_hook)
kgdb_bus_err_hook();
#endif
tsk = current;
- mm = tsk->mm;
si_code = SEGV_MAPERR;
if (unlikely(address >= TASK_SIZE)) {
return;
}
+ /* Only enable interrupts if they were on before the fault */
+ if ((regs->sr & SR_IMASK) != SR_IMASK) {
+ trace_hardirqs_on();
+ local_irq_enable();
+ }
+
+ mm = tsk->mm;
+
/*
* If we're in an interrupt or have no user
* context, we must not take the fault..
if (fixup_exception(regs))
return;
+ if (handle_trapped_io(regs, address))
+ return;
/*
* Oops. The kernel tried to access some bad page. We'll have to
* terminate things with extreme prejudice.
entry = pte_mkdirty(entry);
entry = pte_mkyoung(entry);
+#if defined(CONFIG_CPU_SH4) && !defined(CONFIG_SMP)
+ /*
+ * ITLB is not affected by "ldtlb" instruction.
+ * So, we need to flush the entry by ourselves.
+ */
+ local_flush_tlb_one(get_asid(), address & PAGE_MASK);
+#endif
+
set_pte(pte, entry);
update_mmu_cache(NULL, address, entry);