linux/arch/cris/arch-v10/mm/fault.c
<<
>>
Prefs
   1/*
   2 *  linux/arch/cris/mm/fault.c
   3 *
   4 *  Low level bus fault handler
   5 *
   6 *
   7 *  Copyright (C) 2000-2007  Axis Communications AB
   8 *
   9 *  Authors:  Bjorn Wesen
  10 *
  11 */
  12
  13#include <linux/mm.h>
  14#include <asm/uaccess.h>
  15#include <asm/pgtable.h>
  16#include <arch/svinto.h>
  17#include <asm/mmu_context.h>
  18
  19/* debug of low-level TLB reload */
  20#undef DEBUG
  21
  22#ifdef DEBUG
  23#define D(x) x
  24#else
  25#define D(x)
  26#endif
  27
  28extern const struct exception_table_entry
  29        *search_exception_tables(unsigned long addr);
  30
  31asmlinkage void do_page_fault(unsigned long address, struct pt_regs *regs,
  32                              int protection, int writeaccess);
  33
  34/* fast TLB-fill fault handler
  35 * this is called from entry.S with interrupts disabled
  36 */
  37
  38void
  39handle_mmu_bus_fault(struct pt_regs *regs)
  40{
  41        int cause;
  42        int select;
  43#ifdef DEBUG
  44        int index;
  45        int page_id;
  46        int acc, inv;
  47#endif
  48        pgd_t* pgd = (pgd_t*)per_cpu(current_pgd, smp_processor_id());
  49        pmd_t *pmd;
  50        pte_t pte;
  51        int miss, we, writeac;
  52        unsigned long address;
  53        unsigned long flags;
  54
  55        cause = *R_MMU_CAUSE;
  56
  57        address = cause & PAGE_MASK; /* get faulting address */
  58        select = *R_TLB_SELECT;
  59
  60#ifdef DEBUG
  61        page_id = IO_EXTRACT(R_MMU_CAUSE,  page_id,   cause);
  62        acc     = IO_EXTRACT(R_MMU_CAUSE,  acc_excp,  cause);
  63        inv     = IO_EXTRACT(R_MMU_CAUSE,  inv_excp,  cause);
  64        index   = IO_EXTRACT(R_TLB_SELECT, index,     select);
  65#endif
  66        miss    = IO_EXTRACT(R_MMU_CAUSE,  miss_excp, cause);
  67        we      = IO_EXTRACT(R_MMU_CAUSE,  we_excp,   cause);
  68        writeac = IO_EXTRACT(R_MMU_CAUSE,  wr_rd,     cause);
  69
  70        D(printk("bus_fault from IRP 0x%lx: addr 0x%lx, miss %d, inv %d, we %d, acc %d, dx %d pid %d\n",
  71                 regs->irp, address, miss, inv, we, acc, index, page_id));
  72
  73        /* leave it to the MM system fault handler */
  74        if (miss)
  75                do_page_fault(address, regs, 0, writeac);
  76        else
  77                do_page_fault(address, regs, 1, we);
  78
  79        /* Reload TLB with new entry to avoid an extra miss exception.
  80         * do_page_fault may have flushed the TLB so we have to restore
  81         * the MMU registers.
  82         */
  83        local_irq_save(flags);
  84        pmd = (pmd_t *)(pgd + pgd_index(address));
  85        if (pmd_none(*pmd))
  86                goto exit;
  87        pte = *pte_offset_kernel(pmd, address);
  88        if (!pte_present(pte))
  89                goto exit;
  90        *R_TLB_SELECT = select;
  91        *R_TLB_HI = cause;
  92        *R_TLB_LO = pte_val(pte);
  93exit:
  94        local_irq_restore(flags);
  95}
  96