xref: /openbmc/linux/arch/csky/mm/tlb.c (revision 4e562c11664c0e0e84bb8495894b8637acc1c095)
100a9730eSGuo Ren // SPDX-License-Identifier: GPL-2.0
200a9730eSGuo Ren // Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd.
300a9730eSGuo Ren 
400a9730eSGuo Ren #include <linux/init.h>
500a9730eSGuo Ren #include <linux/mm.h>
600a9730eSGuo Ren #include <linux/module.h>
700a9730eSGuo Ren #include <linux/sched.h>
800a9730eSGuo Ren 
900a9730eSGuo Ren #include <asm/mmu_context.h>
1000a9730eSGuo Ren #include <asm/pgtable.h>
1100a9730eSGuo Ren #include <asm/setup.h>
1200a9730eSGuo Ren 
13*4e562c11SGuo Ren /*
14*4e562c11SGuo Ren  * One C-SKY MMU TLB entry contain two PFN/page entry, ie:
15*4e562c11SGuo Ren  * 1VPN -> 2PFN
16*4e562c11SGuo Ren  */
17*4e562c11SGuo Ren #define TLB_ENTRY_SIZE		(PAGE_SIZE * 2)
18*4e562c11SGuo Ren #define TLB_ENTRY_SIZE_MASK	(PAGE_MASK << 1)
19*4e562c11SGuo Ren 
2000a9730eSGuo Ren void flush_tlb_all(void)
2100a9730eSGuo Ren {
2200a9730eSGuo Ren 	tlb_invalid_all();
2300a9730eSGuo Ren }
2400a9730eSGuo Ren 
2500a9730eSGuo Ren void flush_tlb_mm(struct mm_struct *mm)
2600a9730eSGuo Ren {
27*4e562c11SGuo Ren #ifdef CONFIG_CPU_HAS_TLBI
28*4e562c11SGuo Ren 	asm volatile("tlbi.asids %0"::"r"(cpu_asid(mm)));
29*4e562c11SGuo Ren #else
3000a9730eSGuo Ren 	tlb_invalid_all();
31*4e562c11SGuo Ren #endif
3200a9730eSGuo Ren }
3300a9730eSGuo Ren 
34*4e562c11SGuo Ren /*
35*4e562c11SGuo Ren  * MMU operation regs only could invalid tlb entry in jtlb and we
36*4e562c11SGuo Ren  * need change asid field to invalid I-utlb & D-utlb.
37*4e562c11SGuo Ren  */
38*4e562c11SGuo Ren #ifndef CONFIG_CPU_HAS_TLBI
39*4e562c11SGuo Ren #define restore_asid_inv_utlb(oldpid, newpid) \
40*4e562c11SGuo Ren do { \
41*4e562c11SGuo Ren 	if (oldpid == newpid) \
42*4e562c11SGuo Ren 		write_mmu_entryhi(oldpid + 1); \
43*4e562c11SGuo Ren 	write_mmu_entryhi(oldpid); \
44*4e562c11SGuo Ren } while (0)
45*4e562c11SGuo Ren #endif
46*4e562c11SGuo Ren 
4700a9730eSGuo Ren void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
4800a9730eSGuo Ren 			unsigned long end)
4900a9730eSGuo Ren {
50*4e562c11SGuo Ren 	unsigned long newpid = cpu_asid(vma->vm_mm);
51*4e562c11SGuo Ren 
52*4e562c11SGuo Ren 	start &= TLB_ENTRY_SIZE_MASK;
53*4e562c11SGuo Ren 	end   += TLB_ENTRY_SIZE - 1;
54*4e562c11SGuo Ren 	end   &= TLB_ENTRY_SIZE_MASK;
55*4e562c11SGuo Ren 
56*4e562c11SGuo Ren #ifdef CONFIG_CPU_HAS_TLBI
57*4e562c11SGuo Ren 	while (start < end) {
58*4e562c11SGuo Ren 		asm volatile("tlbi.vas %0"::"r"(start | newpid));
59*4e562c11SGuo Ren 		start += 2*PAGE_SIZE;
60*4e562c11SGuo Ren 	}
61*4e562c11SGuo Ren 	sync_is();
62*4e562c11SGuo Ren #else
63*4e562c11SGuo Ren 	{
64*4e562c11SGuo Ren 	unsigned long flags, oldpid;
65*4e562c11SGuo Ren 
66*4e562c11SGuo Ren 	local_irq_save(flags);
67*4e562c11SGuo Ren 	oldpid = read_mmu_entryhi() & ASID_MASK;
68*4e562c11SGuo Ren 	while (start < end) {
69*4e562c11SGuo Ren 		int idx;
70*4e562c11SGuo Ren 
71*4e562c11SGuo Ren 		write_mmu_entryhi(start | newpid);
72*4e562c11SGuo Ren 		start += 2*PAGE_SIZE;
73*4e562c11SGuo Ren 		tlb_probe();
74*4e562c11SGuo Ren 		idx = read_mmu_index();
75*4e562c11SGuo Ren 		if (idx >= 0)
76*4e562c11SGuo Ren 			tlb_invalid_indexed();
77*4e562c11SGuo Ren 	}
78*4e562c11SGuo Ren 	restore_asid_inv_utlb(oldpid, newpid);
79*4e562c11SGuo Ren 	local_irq_restore(flags);
80*4e562c11SGuo Ren 	}
81*4e562c11SGuo Ren #endif
8200a9730eSGuo Ren }
8300a9730eSGuo Ren 
8400a9730eSGuo Ren void flush_tlb_kernel_range(unsigned long start, unsigned long end)
8500a9730eSGuo Ren {
86*4e562c11SGuo Ren 	start &= TLB_ENTRY_SIZE_MASK;
87*4e562c11SGuo Ren 	end   += TLB_ENTRY_SIZE - 1;
88*4e562c11SGuo Ren 	end   &= TLB_ENTRY_SIZE_MASK;
89*4e562c11SGuo Ren 
90*4e562c11SGuo Ren #ifdef CONFIG_CPU_HAS_TLBI
91*4e562c11SGuo Ren 	while (start < end) {
92*4e562c11SGuo Ren 		asm volatile("tlbi.vaas %0"::"r"(start));
93*4e562c11SGuo Ren 		start += 2*PAGE_SIZE;
94*4e562c11SGuo Ren 	}
95*4e562c11SGuo Ren 	sync_is();
96*4e562c11SGuo Ren #else
97*4e562c11SGuo Ren 	{
98*4e562c11SGuo Ren 	unsigned long flags, oldpid;
99*4e562c11SGuo Ren 
100*4e562c11SGuo Ren 	local_irq_save(flags);
101*4e562c11SGuo Ren 	oldpid = read_mmu_entryhi() & ASID_MASK;
102*4e562c11SGuo Ren 	while (start < end) {
103*4e562c11SGuo Ren 		int idx;
104*4e562c11SGuo Ren 
105*4e562c11SGuo Ren 		write_mmu_entryhi(start | oldpid);
106*4e562c11SGuo Ren 		start += 2*PAGE_SIZE;
107*4e562c11SGuo Ren 		tlb_probe();
108*4e562c11SGuo Ren 		idx = read_mmu_index();
109*4e562c11SGuo Ren 		if (idx >= 0)
110*4e562c11SGuo Ren 			tlb_invalid_indexed();
111*4e562c11SGuo Ren 	}
112*4e562c11SGuo Ren 	restore_asid_inv_utlb(oldpid, oldpid);
113*4e562c11SGuo Ren 	local_irq_restore(flags);
114*4e562c11SGuo Ren 	}
115*4e562c11SGuo Ren #endif
11600a9730eSGuo Ren }
1179d35dc30SGuo Ren 
1189d35dc30SGuo Ren void flush_tlb_page(struct vm_area_struct *vma, unsigned long addr)
11900a9730eSGuo Ren {
120*4e562c11SGuo Ren 	int newpid = cpu_asid(vma->vm_mm);
121*4e562c11SGuo Ren 
122*4e562c11SGuo Ren 	addr &= TLB_ENTRY_SIZE_MASK;
123*4e562c11SGuo Ren 
124*4e562c11SGuo Ren #ifdef CONFIG_CPU_HAS_TLBI
125*4e562c11SGuo Ren 	asm volatile("tlbi.vas %0"::"r"(addr | newpid));
126*4e562c11SGuo Ren 	sync_is();
127*4e562c11SGuo Ren #else
128*4e562c11SGuo Ren 	{
129*4e562c11SGuo Ren 	int oldpid, idx;
130*4e562c11SGuo Ren 	unsigned long flags;
131*4e562c11SGuo Ren 
132*4e562c11SGuo Ren 	local_irq_save(flags);
133*4e562c11SGuo Ren 	oldpid = read_mmu_entryhi() & ASID_MASK;
134*4e562c11SGuo Ren 	write_mmu_entryhi(addr | newpid);
135*4e562c11SGuo Ren 	tlb_probe();
136*4e562c11SGuo Ren 	idx = read_mmu_index();
137*4e562c11SGuo Ren 	if (idx >= 0)
138*4e562c11SGuo Ren 		tlb_invalid_indexed();
139*4e562c11SGuo Ren 
140*4e562c11SGuo Ren 	restore_asid_inv_utlb(oldpid, newpid);
141*4e562c11SGuo Ren 	local_irq_restore(flags);
142*4e562c11SGuo Ren 	}
143*4e562c11SGuo Ren #endif
14400a9730eSGuo Ren }
14500a9730eSGuo Ren 
1469d35dc30SGuo Ren void flush_tlb_one(unsigned long addr)
14700a9730eSGuo Ren {
148*4e562c11SGuo Ren 	addr &= TLB_ENTRY_SIZE_MASK;
149*4e562c11SGuo Ren 
150*4e562c11SGuo Ren #ifdef CONFIG_CPU_HAS_TLBI
151*4e562c11SGuo Ren 	asm volatile("tlbi.vaas %0"::"r"(addr));
152*4e562c11SGuo Ren 	sync_is();
153*4e562c11SGuo Ren #else
154*4e562c11SGuo Ren 	{
155*4e562c11SGuo Ren 	int oldpid, idx;
156*4e562c11SGuo Ren 	unsigned long flags;
157*4e562c11SGuo Ren 
158*4e562c11SGuo Ren 	local_irq_save(flags);
159*4e562c11SGuo Ren 	oldpid = read_mmu_entryhi() & ASID_MASK;
160*4e562c11SGuo Ren 	write_mmu_entryhi(addr | oldpid);
161*4e562c11SGuo Ren 	tlb_probe();
162*4e562c11SGuo Ren 	idx = read_mmu_index();
163*4e562c11SGuo Ren 	if (idx >= 0)
164*4e562c11SGuo Ren 		tlb_invalid_indexed();
165*4e562c11SGuo Ren 
166*4e562c11SGuo Ren 	restore_asid_inv_utlb(oldpid, oldpid);
167*4e562c11SGuo Ren 	local_irq_restore(flags);
168*4e562c11SGuo Ren 	}
169*4e562c11SGuo Ren #endif
17000a9730eSGuo Ren }
17100a9730eSGuo Ren EXPORT_SYMBOL(flush_tlb_one);
172