11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  linux/arch/cris/mm/fault.c
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  Low level bus fault handler
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
740316c1fadfcd7856e43029fdbac5df6a1d57063Jesper Nilsson *  Copyright (C) 2000-2007  Axis Communications AB
840316c1fadfcd7856e43029fdbac5df6a1d57063Jesper Nilsson *
940316c1fadfcd7856e43029fdbac5df6a1d57063Jesper Nilsson *  Authors:  Bjorn Wesen
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mm.h>
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/uaccess.h>
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/pgtable.h>
16556dcee7b829e5c350c3ffdbdb87a8b15aa3c5d3Jesper Nilsson#include <arch/svinto.h>
178d20a541b089ecb67a88a673548161b686ed7b85Mikael Starvik#include <asm/mmu_context.h>
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* debug of low-level TLB reload */
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef DEBUG
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef DEBUG
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define D(x) x
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define D(x)
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsextern const struct exception_table_entry
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*search_exception_tables(unsigned long addr);
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsasmlinkage void do_page_fault(unsigned long address, struct pt_regs *regs,
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                              int protection, int writeaccess);
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* fast TLB-fill fault handler
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * this is called from entry.S with interrupts disabled
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldshandle_mmu_bus_fault(struct pt_regs *regs)
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int cause;
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int select;
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef DEBUG
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int index;
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int page_id;
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int acc, inv;
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
488d20a541b089ecb67a88a673548161b686ed7b85Mikael Starvik	pgd_t* pgd = (pgd_t*)per_cpu(current_pgd, smp_processor_id());
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pmd_t *pmd;
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pte_t pte;
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int miss, we, writeac;
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long address;
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cause = *R_MMU_CAUSE;
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	address = cause & PAGE_MASK; /* get faulting address */
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	select = *R_TLB_SELECT;
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef DEBUG
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	page_id = IO_EXTRACT(R_MMU_CAUSE,  page_id,   cause);
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	acc     = IO_EXTRACT(R_MMU_CAUSE,  acc_excp,  cause);
6340316c1fadfcd7856e43029fdbac5df6a1d57063Jesper Nilsson	inv     = IO_EXTRACT(R_MMU_CAUSE,  inv_excp,  cause);
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	index   = IO_EXTRACT(R_TLB_SELECT, index,     select);
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	miss    = IO_EXTRACT(R_MMU_CAUSE,  miss_excp, cause);
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	we      = IO_EXTRACT(R_MMU_CAUSE,  we_excp,   cause);
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	writeac = IO_EXTRACT(R_MMU_CAUSE,  wr_rd,     cause);
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	D(printk("bus_fault from IRP 0x%lx: addr 0x%lx, miss %d, inv %d, we %d, acc %d, dx %d pid %d\n",
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 regs->irp, address, miss, inv, we, acc, index, page_id));
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* leave it to the MM system fault handler */
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (miss)
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		do_page_fault(address, regs, 0, writeac);
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        else
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		do_page_fault(address, regs, 1, we);
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        /* Reload TLB with new entry to avoid an extra miss exception.
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * do_page_fault may have flushed the TLB so we have to restore
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * the MMU registers.
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
8384a3098f1ff8b42f2fdcfda25d1a83ea4a53b021Jiri Kosina	local_irq_save(flags);
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pmd = (pmd_t *)(pgd + pgd_index(address));
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (pmd_none(*pmd))
8640316c1fadfcd7856e43029fdbac5df6a1d57063Jesper Nilsson		goto exit;
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pte = *pte_offset_kernel(pmd, address);
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!pte_present(pte))
8940316c1fadfcd7856e43029fdbac5df6a1d57063Jesper Nilsson		goto exit;
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*R_TLB_SELECT = select;
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*R_TLB_HI = cause;
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*R_TLB_LO = pte_val(pte);
9340316c1fadfcd7856e43029fdbac5df6a1d57063Jesper Nilssonexit:
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	local_irq_restore(flags);
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
96