18263a67eSPaul Mundt /*
28263a67eSPaul Mundt * arch/sh/mm/tlb-pteaex.c
38263a67eSPaul Mundt *
48263a67eSPaul Mundt * TLB operations for SH-X3 CPUs featuring PTE ASID Extensions.
58263a67eSPaul Mundt *
68263a67eSPaul Mundt * Copyright (C) 2009 Paul Mundt
78263a67eSPaul Mundt *
88263a67eSPaul Mundt * This file is subject to the terms and conditions of the GNU General Public
98263a67eSPaul Mundt * License. See the file "COPYING" in the main directory of this archive
108263a67eSPaul Mundt * for more details.
118263a67eSPaul Mundt */
128263a67eSPaul Mundt #include <linux/kernel.h>
138263a67eSPaul Mundt #include <linux/mm.h>
148263a67eSPaul Mundt #include <linux/io.h>
158263a67eSPaul Mundt #include <asm/mmu_context.h>
168263a67eSPaul Mundt #include <asm/cacheflush.h>
178263a67eSPaul Mundt
__update_tlb(struct vm_area_struct * vma,unsigned long address,pte_t pte)189cef7492SPaul Mundt void __update_tlb(struct vm_area_struct *vma, unsigned long address, pte_t pte)
198263a67eSPaul Mundt {
209cef7492SPaul Mundt unsigned long flags, pteval, vpn;
218263a67eSPaul Mundt
229cef7492SPaul Mundt /*
239cef7492SPaul Mundt * Handle debugger faulting in for debugee.
249cef7492SPaul Mundt */
253ed6e129SPaul Mundt if (vma && current->active_mm != vma->vm_mm)
268263a67eSPaul Mundt return;
278263a67eSPaul Mundt
288263a67eSPaul Mundt local_irq_save(flags);
298263a67eSPaul Mundt
308263a67eSPaul Mundt /* Set PTEH register */
318263a67eSPaul Mundt vpn = address & MMU_VPN_MASK;
328263a67eSPaul Mundt __raw_writel(vpn, MMU_PTEH);
338263a67eSPaul Mundt
348263a67eSPaul Mundt /* Set PTEAEX */
358263a67eSPaul Mundt __raw_writel(get_asid(), MMU_PTEAEX);
368263a67eSPaul Mundt
378263a67eSPaul Mundt pteval = pte.pte_low;
388263a67eSPaul Mundt
398263a67eSPaul Mundt /* Set PTEA register */
408263a67eSPaul Mundt #ifdef CONFIG_X2TLB
418263a67eSPaul Mundt /*
428263a67eSPaul Mundt * For the extended mode TLB this is trivial, only the ESZ and
438263a67eSPaul Mundt * EPR bits need to be written out to PTEA, with the remainder of
448263a67eSPaul Mundt * the protection bits (with the exception of the compat-mode SZ
458263a67eSPaul Mundt * and PR bits, which are cleared) being written out in PTEL.
468263a67eSPaul Mundt */
478263a67eSPaul Mundt __raw_writel(pte.pte_high, MMU_PTEA);
488263a67eSPaul Mundt #endif
498263a67eSPaul Mundt
508263a67eSPaul Mundt /* Set PTEL register */
518263a67eSPaul Mundt pteval &= _PAGE_FLAGS_HARDWARE_MASK; /* drop software flags */
528263a67eSPaul Mundt #ifdef CONFIG_CACHE_WRITETHROUGH
538263a67eSPaul Mundt pteval |= _PAGE_WT;
548263a67eSPaul Mundt #endif
558263a67eSPaul Mundt /* conveniently, we want all the software flags to be 0 anyway */
568263a67eSPaul Mundt __raw_writel(pteval, MMU_PTEL);
578263a67eSPaul Mundt
588263a67eSPaul Mundt /* Load the TLB */
598263a67eSPaul Mundt asm volatile("ldtlb": /* no output */ : /* no input */ : "memory");
608263a67eSPaul Mundt local_irq_restore(flags);
618263a67eSPaul Mundt }
628263a67eSPaul Mundt
638263a67eSPaul Mundt /*
648263a67eSPaul Mundt * While SH-X2 extended TLB mode splits out the memory-mapped I/UTLB
658263a67eSPaul Mundt * data arrays, SH-X3 cores with PTEAEX split out the memory-mapped
668263a67eSPaul Mundt * address arrays. In compat mode the second array is inaccessible, while
678263a67eSPaul Mundt * in extended mode, the legacy 8-bit ASID field in address array 1 has
688263a67eSPaul Mundt * undefined behaviour.
698263a67eSPaul Mundt */
local_flush_tlb_one(unsigned long asid,unsigned long page)702dc2f8e0SPaul Mundt void local_flush_tlb_one(unsigned long asid, unsigned long page)
718263a67eSPaul Mundt {
728263a67eSPaul Mundt jump_to_uncached();
738263a67eSPaul Mundt __raw_writel(page, MMU_UTLB_ADDRESS_ARRAY | MMU_PAGE_ASSOC_BIT);
748263a67eSPaul Mundt __raw_writel(asid, MMU_UTLB_ADDRESS_ARRAY2 | MMU_PAGE_ASSOC_BIT);
75a9eb4f6dSMatt Fleming __raw_writel(page, MMU_ITLB_ADDRESS_ARRAY | MMU_PAGE_ASSOC_BIT);
76a9eb4f6dSMatt Fleming __raw_writel(asid, MMU_ITLB_ADDRESS_ARRAY2 | MMU_PAGE_ASSOC_BIT);
778263a67eSPaul Mundt back_to_cached();
788263a67eSPaul Mundt }
79*be97d758SPaul Mundt
local_flush_tlb_all(void)80*be97d758SPaul Mundt void local_flush_tlb_all(void)
81*be97d758SPaul Mundt {
82*be97d758SPaul Mundt unsigned long flags, status;
83*be97d758SPaul Mundt int i;
84*be97d758SPaul Mundt
85*be97d758SPaul Mundt /*
86*be97d758SPaul Mundt * Flush all the TLB.
87*be97d758SPaul Mundt */
88*be97d758SPaul Mundt local_irq_save(flags);
89*be97d758SPaul Mundt jump_to_uncached();
90*be97d758SPaul Mundt
91*be97d758SPaul Mundt status = __raw_readl(MMUCR);
92*be97d758SPaul Mundt status = ((status & MMUCR_URB) >> MMUCR_URB_SHIFT);
93*be97d758SPaul Mundt
94*be97d758SPaul Mundt if (status == 0)
95*be97d758SPaul Mundt status = MMUCR_URB_NENTRIES;
96*be97d758SPaul Mundt
97*be97d758SPaul Mundt for (i = 0; i < status; i++)
98*be97d758SPaul Mundt __raw_writel(0x0, MMU_UTLB_ADDRESS_ARRAY | (i << 8));
99*be97d758SPaul Mundt
100*be97d758SPaul Mundt for (i = 0; i < 4; i++)
101*be97d758SPaul Mundt __raw_writel(0x0, MMU_ITLB_ADDRESS_ARRAY | (i << 8));
102*be97d758SPaul Mundt
103*be97d758SPaul Mundt back_to_cached();
104*be97d758SPaul Mundt ctrl_barrier();
105*be97d758SPaul Mundt local_irq_restore(flags);
106*be97d758SPaul Mundt }
107