aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sh/mm/tlb-sh5.c
diff options
context:
space:
mode:
authorPaul Mundt <lethal@linux-sh.org>2012-05-14 15:52:28 +0900
committerPaul Mundt <lethal@linux-sh.org>2012-05-14 15:52:28 +0900
commitc06fd28387a3da2cc4763f7f471f735ccdd61b88 (patch)
treee2d95ffa04f7e5b17958831e29935a231e094d09 /arch/sh/mm/tlb-sh5.c
parentsh: Enable shared page fault handler for _32/_64. (diff)
downloadlinux-dev-c06fd28387a3da2cc4763f7f471f735ccdd61b88.tar.xz
linux-dev-c06fd28387a3da2cc4763f7f471f735ccdd61b88.zip
sh64: Migrate to __update_tlb() API.
Now that we have a method for finding out if we're handling an ITLB fault or not without passing it all the way down the chain, it's possible to use the __update_tlb() interface in place of a special __do_tlb_refill(). Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'arch/sh/mm/tlb-sh5.c')
-rw-r--r--arch/sh/mm/tlb-sh5.c40
1 files changed, 40 insertions, 0 deletions
diff --git a/arch/sh/mm/tlb-sh5.c b/arch/sh/mm/tlb-sh5.c
index f27dbe1c1599..3aea25dc431a 100644
--- a/arch/sh/mm/tlb-sh5.c
+++ b/arch/sh/mm/tlb-sh5.c
@@ -182,3 +182,43 @@ void tlb_unwire_entry(void)
local_irq_restore(flags);
}
+
+void __update_tlb(struct vm_area_struct *vma, unsigned long address, pte_t pte)
+{
+ unsigned long long ptel;
+ unsigned long long pteh=0;
+ struct tlb_info *tlbp;
+ unsigned long long next;
+ unsigned int fault_code = get_thread_fault_code();
+
+ /* Get PTEL first */
+ ptel = pte.pte_low;
+
+ /*
+ * Set PTEH register
+ */
+ pteh = neff_sign_extend(address & MMU_VPN_MASK);
+
+ /* 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 */
+
+ if (fault_code & FAULT_CODE_ITLB)
+ tlbp = &cpu_data->itlb;
+ else
+ tlbp = &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;
+}