Logo Search packages:      
Sourcecode: linux version File versions  Download package

fault.c

/*
 *  linux/arch/cris/mm/fault.c
 *
 *  Low level bus fault handler
 *
 *
 *  Copyright (C) 2000-2007  Axis Communications AB
 *
 *  Authors:  Bjorn Wesen
 *
 */

#include <linux/mm.h>
#include <asm/uaccess.h>
#include <asm/pgtable.h>
#include <asm/arch/svinto.h>
#include <asm/mmu_context.h>

/* debug of low-level TLB reload */
#undef DEBUG

#ifdef DEBUG
#define D(x) x
#else
#define D(x)
#endif

extern const struct exception_table_entry
      *search_exception_tables(unsigned long addr);

asmlinkage void do_page_fault(unsigned long address, struct pt_regs *regs,
                              int protection, int writeaccess);

/* fast TLB-fill fault handler
 * this is called from entry.S with interrupts disabled
 */

void
handle_mmu_bus_fault(struct pt_regs *regs)
{
      int cause;
      int select;
#ifdef DEBUG
      int index;
      int page_id;
      int acc, inv;
#endif
      pgd_t* pgd = (pgd_t*)per_cpu(current_pgd, smp_processor_id());
      pmd_t *pmd;
      pte_t pte;
      int miss, we, writeac;
      unsigned long address;
      unsigned long flags;

      cause = *R_MMU_CAUSE;

      address = cause & PAGE_MASK; /* get faulting address */
      select = *R_TLB_SELECT;

#ifdef DEBUG
      page_id = IO_EXTRACT(R_MMU_CAUSE,  page_id,   cause);
      acc     = IO_EXTRACT(R_MMU_CAUSE,  acc_excp,  cause);
      inv     = IO_EXTRACT(R_MMU_CAUSE,  inv_excp,  cause);
      index   = IO_EXTRACT(R_TLB_SELECT, index,     select);
#endif
      miss    = IO_EXTRACT(R_MMU_CAUSE,  miss_excp, cause);
      we      = IO_EXTRACT(R_MMU_CAUSE,  we_excp,   cause);
      writeac = IO_EXTRACT(R_MMU_CAUSE,  wr_rd,     cause);

      D(printk("bus_fault from IRP 0x%lx: addr 0x%lx, miss %d, inv %d, we %d, acc %d, dx %d pid %d\n",
             regs->irp, address, miss, inv, we, acc, index, page_id));

      /* leave it to the MM system fault handler */
      if (miss)
            do_page_fault(address, regs, 0, writeac);
        else
            do_page_fault(address, regs, 1, we);

        /* Reload TLB with new entry to avoid an extra miss exception.
       * do_page_fault may have flushed the TLB so we have to restore
       * the MMU registers.
       */
      local_save_flags(flags);
      local_irq_disable();
      pmd = (pmd_t *)(pgd + pgd_index(address));
      if (pmd_none(*pmd))
            goto exit;
      pte = *pte_offset_kernel(pmd, address);
      if (!pte_present(pte))
            goto exit;
      *R_TLB_SELECT = select;
      *R_TLB_HI = cause;
      *R_TLB_LO = pte_val(pte);
exit:
      local_irq_restore(flags);
}

Generated by  Doxygen 1.6.0   Back to index