1*c456cfc2SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds * arch/sh/mm/tlb-sh4.c
41da177e4SLinus Torvalds *
51da177e4SLinus Torvalds * SH-4 specific TLB operations
61da177e4SLinus Torvalds *
71da177e4SLinus Torvalds * Copyright (C) 1999 Niibe Yutaka
8d04a0f79SPaul Mundt * Copyright (C) 2002 - 2007 Paul Mundt
91da177e4SLinus Torvalds */
1039e688a9SPaul Mundt #include <linux/kernel.h>
1139e688a9SPaul Mundt #include <linux/mm.h>
12d04a0f79SPaul Mundt #include <linux/io.h>
131da177e4SLinus Torvalds #include <asm/mmu_context.h>
1439e688a9SPaul Mundt #include <asm/cacheflush.h>
1539e688a9SPaul Mundt
__update_tlb(struct vm_area_struct * vma,unsigned long address,pte_t pte)169cef7492SPaul Mundt void __update_tlb(struct vm_area_struct *vma, unsigned long address, pte_t pte)
1739e688a9SPaul Mundt {
189cef7492SPaul Mundt unsigned long flags, pteval, vpn;
1939e688a9SPaul Mundt
209cef7492SPaul Mundt /*
219cef7492SPaul Mundt * Handle debugger faulting in for debugee.
229cef7492SPaul Mundt */
233ed6e129SPaul Mundt if (vma && current->active_mm != vma->vm_mm)
2439e688a9SPaul Mundt return;
2539e688a9SPaul Mundt
2639e688a9SPaul Mundt local_irq_save(flags);
2739e688a9SPaul Mundt
2839e688a9SPaul Mundt /* Set PTEH register */
2939e688a9SPaul Mundt vpn = (address & MMU_VPN_MASK) | get_asid();
309d56dd3bSPaul Mundt __raw_writel(vpn, MMU_PTEH);
3139e688a9SPaul Mundt
32d04a0f79SPaul Mundt pteval = pte.pte_low;
3339e688a9SPaul Mundt
3439e688a9SPaul Mundt /* Set PTEA register */
35d04a0f79SPaul Mundt #ifdef CONFIG_X2TLB
36d04a0f79SPaul Mundt /*
37d04a0f79SPaul Mundt * For the extended mode TLB this is trivial, only the ESZ and
38d04a0f79SPaul Mundt * EPR bits need to be written out to PTEA, with the remainder of
39d04a0f79SPaul Mundt * the protection bits (with the exception of the compat-mode SZ
40d04a0f79SPaul Mundt * and PR bits, which are cleared) being written out in PTEL.
41d04a0f79SPaul Mundt */
429d56dd3bSPaul Mundt __raw_writel(pte.pte_high, MMU_PTEA);
43d04a0f79SPaul Mundt #else
446503fe4aSMichael Trimarchi if (cpu_data->flags & CPU_HAS_PTEA) {
456503fe4aSMichael Trimarchi /* The last 3 bits and the first one of pteval contains
466503fe4aSMichael Trimarchi * the PTEA timing control and space attribute bits
476503fe4aSMichael Trimarchi */
489d56dd3bSPaul Mundt __raw_writel(copy_ptea_attributes(pteval), MMU_PTEA);
496503fe4aSMichael Trimarchi }
50d04a0f79SPaul Mundt #endif
5139e688a9SPaul Mundt
5239e688a9SPaul Mundt /* Set PTEL register */
5339e688a9SPaul Mundt pteval &= _PAGE_FLAGS_HARDWARE_MASK; /* drop software flags */
54e7bd34a1SPaul Mundt #ifdef CONFIG_CACHE_WRITETHROUGH
5539e688a9SPaul Mundt pteval |= _PAGE_WT;
5639e688a9SPaul Mundt #endif
5739e688a9SPaul Mundt /* conveniently, we want all the software flags to be 0 anyway */
589d56dd3bSPaul Mundt __raw_writel(pteval, MMU_PTEL);
5939e688a9SPaul Mundt
6039e688a9SPaul Mundt /* Load the TLB */
6139e688a9SPaul Mundt asm volatile("ldtlb": /* no output */ : /* no input */ : "memory");
6239e688a9SPaul Mundt local_irq_restore(flags);
6339e688a9SPaul Mundt }
641da177e4SLinus Torvalds
local_flush_tlb_one(unsigned long asid,unsigned long page)652dc2f8e0SPaul Mundt void local_flush_tlb_one(unsigned long asid, unsigned long page)
661da177e4SLinus Torvalds {
671da177e4SLinus Torvalds unsigned long addr, data;
681da177e4SLinus Torvalds
691da177e4SLinus Torvalds /*
701da177e4SLinus Torvalds * NOTE: PTEH.ASID should be set to this MM
711da177e4SLinus Torvalds * _AND_ we need to write ASID to the array.
721da177e4SLinus Torvalds *
731da177e4SLinus Torvalds * It would be simple if we didn't need to set PTEH.ASID...
741da177e4SLinus Torvalds */
751da177e4SLinus Torvalds addr = MMU_UTLB_ADDRESS_ARRAY | MMU_PAGE_ASSOC_BIT;
761da177e4SLinus Torvalds data = page | asid; /* VALID bit is off */
77cbaa118eSStuart Menefy jump_to_uncached();
789d56dd3bSPaul Mundt __raw_writel(data, addr);
79cbaa118eSStuart Menefy back_to_cached();
801da177e4SLinus Torvalds }
81be97d758SPaul Mundt
local_flush_tlb_all(void)82be97d758SPaul Mundt void local_flush_tlb_all(void)
83be97d758SPaul Mundt {
84be97d758SPaul Mundt unsigned long flags, status;
85be97d758SPaul Mundt int i;
86be97d758SPaul Mundt
87be97d758SPaul Mundt /*
88be97d758SPaul Mundt * Flush all the TLB.
89be97d758SPaul Mundt */
90be97d758SPaul Mundt local_irq_save(flags);
91be97d758SPaul Mundt jump_to_uncached();
92be97d758SPaul Mundt
93be97d758SPaul Mundt status = __raw_readl(MMUCR);
94be97d758SPaul Mundt status = ((status & MMUCR_URB) >> MMUCR_URB_SHIFT);
95be97d758SPaul Mundt
96be97d758SPaul Mundt if (status == 0)
97be97d758SPaul Mundt status = MMUCR_URB_NENTRIES;
98be97d758SPaul Mundt
99be97d758SPaul Mundt for (i = 0; i < status; i++)
100be97d758SPaul Mundt __raw_writel(0x0, MMU_UTLB_ADDRESS_ARRAY | (i << 8));
101be97d758SPaul Mundt
102be97d758SPaul Mundt for (i = 0; i < 4; i++)
103be97d758SPaul Mundt __raw_writel(0x0, MMU_ITLB_ADDRESS_ARRAY | (i << 8));
104be97d758SPaul Mundt
105be97d758SPaul Mundt back_to_cached();
106be97d758SPaul Mundt ctrl_barrier();
107be97d758SPaul Mundt local_irq_restore(flags);
108be97d758SPaul Mundt }
109