xref: /openbmc/linux/arch/sh/mm/tlb-pteaex.c (revision e5451c8f8330e03ad3cfa16048b4daf961af434f)
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