sh: Move in the SH-5 TLB miss.
[pandora-kernel.git] / arch / sh64 / mm / tlbmiss.c
diff --git a/arch/sh64/mm/tlbmiss.c b/arch/sh64/mm/tlbmiss.c
deleted file mode 100644 (file)
index b767d6c..0000000
+++ /dev/null
@@ -1,279 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * arch/sh64/mm/tlbmiss.c
- *
- * Original code from fault.c
- * Copyright (C) 2000, 2001  Paolo Alberelli
- *
- * Fast PTE->TLB refill path
- * Copyright (C) 2003 Richard.Curnow@superh.com
- *
- * IMPORTANT NOTES :
- * The do_fast_page_fault function is called from a context in entry.S where very few registers
- * have been saved.  In particular, the code in this file must be compiled not to use ANY
- * caller-save registers that are not part of the restricted save set.  Also, it means that
- * code in this file must not make calls to functions elsewhere in the kernel, or else the
- * excepting context will see corruption in its caller-save registers.  Plus, the entry.S save
- * area is non-reentrant, so this code has to run with SR.BL==1, i.e. no interrupts taken inside
- * it and panic on any exception.
- *
- */
-
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/types.h>
-#include <linux/ptrace.h>
-#include <linux/mman.h>
-#include <linux/mm.h>
-#include <linux/smp.h>
-#include <linux/interrupt.h>
-
-#include <asm/system.h>
-#include <asm/tlb.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <asm/pgalloc.h>
-#include <asm/mmu_context.h>
-#include <asm/registers.h>             /* required by inline asm statements */
-
-/* Callable from fault.c, so not static */
-inline void __do_tlb_refill(unsigned long address,
-                            unsigned long long is_text_not_data, pte_t *pte)
-{
-       unsigned long long ptel;
-       unsigned long long pteh=0;
-       struct tlb_info *tlbp;
-       unsigned long long next;
-
-       /* Get PTEL first */
-       ptel = pte_val(*pte);
-
-       /*
-        * Set PTEH register
-        */
-       pteh = address & MMU_VPN_MASK;
-
-       /* Sign extend based on neff. */
-#if (NEFF == 32)
-       /* Faster sign extension */
-       pteh = (unsigned long long)(signed long long)(signed long)pteh;
-#else
-       /* General case */
-       pteh = (pteh & NEFF_SIGN) ? (pteh | NEFF_MASK) : pteh;
-#endif
-
-       /* Set the ASID. */
-       pteh |= get_asid() << PTEH_ASID_SHIFT;
-       pteh |= PTEH_VALID;
-
-       /* Set PTEL register, set_pte has performed the sign extension */
-       ptel &= _PAGE_FLAGS_HARDWARE_MASK; /* drop software flags */
-
-       tlbp = is_text_not_data ? &(cpu_data->itlb) : &(cpu_data->dtlb);
-       next = tlbp->next;
-       __flush_tlb_slot(next);
-       asm volatile ("putcfg %0,1,%2\n\n\t"
-                     "putcfg %0,0,%1\n"
-                     :  : "r" (next), "r" (pteh), "r" (ptel) );
-
-       next += TLB_STEP;
-       if (next > tlbp->last) next = tlbp->first;
-       tlbp->next = next;
-
-}
-
-static int handle_vmalloc_fault(struct mm_struct *mm, unsigned long protection_flags,
-                                unsigned long long textaccess,
-                               unsigned long address)
-{
-       pgd_t *dir;
-       pmd_t *pmd;
-       static pte_t *pte;
-       pte_t entry;
-
-       dir = pgd_offset_k(address);
-       pmd = pmd_offset(dir, address);
-
-       if (pmd_none(*pmd)) {
-               return 0;
-       }
-
-       if (pmd_bad(*pmd)) {
-               pmd_clear(pmd);
-               return 0;
-       }
-
-       pte = pte_offset_kernel(pmd, address);
-       entry = *pte;
-
-       if (pte_none(entry) || !pte_present(entry)) {
-               return 0;
-       }
-
-       if ((pte_val(entry) & protection_flags) != protection_flags) {
-               return 0;
-       }
-
-        __do_tlb_refill(address, textaccess, pte);
-
-       return 1;
-}
-
-static int handle_tlbmiss(struct mm_struct *mm, unsigned long long protection_flags,
-                       unsigned long long textaccess,
-                       unsigned long address)
-{
-       pgd_t *dir;
-       pmd_t *pmd;
-       pte_t *pte;
-       pte_t entry;
-
-       /* NB. The PGD currently only contains a single entry - there is no
-          page table tree stored for the top half of the address space since
-          virtual pages in that region should never be mapped in user mode.
-          (In kernel mode, the only things in that region are the 512Mb super
-          page (locked in), and vmalloc (modules) +  I/O device pages (handled
-          by handle_vmalloc_fault), so no PGD for the upper half is required
-          by kernel mode either).
-
-          See how mm->pgd is allocated and initialised in pgd_alloc to see why
-          the next test is necessary.  - RPC */
-       if (address >= (unsigned long) TASK_SIZE) {
-               /* upper half - never has page table entries. */
-               return 0;
-       }
-       dir = pgd_offset(mm, address);
-       if (pgd_none(*dir)) {
-               return 0;
-       }
-       if (!pgd_present(*dir)) {
-               return 0;
-       }
-
-       pmd = pmd_offset(dir, address);
-       if (pmd_none(*pmd)) {
-               return 0;
-       }
-       if (!pmd_present(*pmd)) {
-               return 0;
-       }
-       pte = pte_offset_kernel(pmd, address);
-       entry = *pte;
-       if (pte_none(entry)) {
-               return 0;
-       }
-       if (!pte_present(entry)) {
-               return 0;
-       }
-
-       /* If the page doesn't have sufficient protection bits set to service the
-          kind of fault being handled, there's not much point doing the TLB refill.
-          Punt the fault to the general handler. */
-       if ((pte_val(entry) & protection_flags) != protection_flags) {
-               return 0;
-       }
-
-        __do_tlb_refill(address, textaccess, pte);
-
-       return 1;
-}
-
-/* Put all this information into one structure so that everything is just arithmetic
-   relative to a single base address.  This reduces the number of movi/shori pairs needed
-   just to load addresses of static data. */
-struct expevt_lookup {
-       unsigned short protection_flags[8];
-       unsigned char  is_text_access[8];
-       unsigned char  is_write_access[8];
-};
-
-#define PRU (1<<9)
-#define PRW (1<<8)
-#define PRX (1<<7)
-#define PRR (1<<6)
-
-#define DIRTY (_PAGE_DIRTY | _PAGE_ACCESSED)
-#define YOUNG (_PAGE_ACCESSED)
-
-/* Sized as 8 rather than 4 to allow checking the PTE's PRU bit against whether
-   the fault happened in user mode or privileged mode. */
-static struct expevt_lookup expevt_lookup_table = {
-       .protection_flags = {PRX, PRX, 0, 0, PRR, PRR, PRW, PRW},
-       .is_text_access   = {1,   1,   0, 0, 0,   0,   0,   0}
-};
-
-/*
-   This routine handles page faults that can be serviced just by refilling a
-   TLB entry from an existing page table entry.  (This case represents a very
-   large majority of page faults.) Return 1 if the fault was successfully
-   handled.  Return 0 if the fault could not be handled.  (This leads into the
-   general fault handling in fault.c which deals with mapping file-backed
-   pages, stack growth, segmentation faults, swapping etc etc)
- */
-asmlinkage int do_fast_page_fault(unsigned long long ssr_md, unsigned long long expevt,
-                                 unsigned long address)
-{
-       struct task_struct *tsk;
-       struct mm_struct *mm;
-       unsigned long long textaccess;
-       unsigned long long protection_flags;
-       unsigned long long index;
-       unsigned long long expevt4;
-
-       /* The next few lines implement a way of hashing EXPEVT into a small array index
-          which can be used to lookup parameters specific to the type of TLBMISS being
-          handled.  Note:
-          ITLBMISS has EXPEVT==0xa40
-          RTLBMISS has EXPEVT==0x040
-          WTLBMISS has EXPEVT==0x060
-       */
-
-       expevt4 = (expevt >> 4);
-       /* TODO : xor ssr_md into this expression too.  Then we can check that PRU is set
-          when it needs to be. */
-       index = expevt4 ^ (expevt4 >> 5);
-       index &= 7;
-       protection_flags = expevt_lookup_table.protection_flags[index];
-       textaccess       = expevt_lookup_table.is_text_access[index];
-
-#ifdef CONFIG_SH64_PROC_TLB
-       ++calls_to_do_fast_page_fault;
-#endif
-
-       /* SIM
-        * Note this is now called with interrupts still disabled
-        * This is to cope with being called for a missing IO port
-        * address with interrupts disabled. This should be fixed as
-        * soon as we have a better 'fast path' miss handler.
-        *
-        * Plus take care how you try and debug this stuff.
-        * For example, writing debug data to a port which you
-        * have just faulted on is not going to work.
-        */
-
-       tsk = current;
-       mm = tsk->mm;
-
-       if ((address >= VMALLOC_START && address < VMALLOC_END) ||
-           (address >= IOBASE_VADDR  && address < IOBASE_END)) {
-               if (ssr_md) {
-                       /* Process-contexts can never have this address range mapped */
-                       if (handle_vmalloc_fault(mm, protection_flags, textaccess, address)) {
-                               return 1;
-                       }
-               }
-       } else if (!in_interrupt() && mm) {
-               if (handle_tlbmiss(mm, protection_flags, textaccess, address)) {
-                       return 1;
-               }
-       }
-
-       return 0;
-}
-