xref: /OK3568_Linux_fs/kernel/arch/nds32/mm/proc.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun // Copyright (C) 2005-2017 Andes Technology Corporation
3*4882a593Smuzhiyun 
4*4882a593Smuzhiyun #include <linux/module.h>
5*4882a593Smuzhiyun #include <linux/sched.h>
6*4882a593Smuzhiyun #include <linux/mm.h>
7*4882a593Smuzhiyun #include <asm/nds32.h>
8*4882a593Smuzhiyun #include <asm/tlbflush.h>
9*4882a593Smuzhiyun #include <asm/cacheflush.h>
10*4882a593Smuzhiyun #include <asm/l2_cache.h>
11*4882a593Smuzhiyun #include <nds32_intrinsic.h>
12*4882a593Smuzhiyun 
13*4882a593Smuzhiyun #include <asm/cache_info.h>
14*4882a593Smuzhiyun extern struct cache_info L1_cache_info[2];
15*4882a593Smuzhiyun 
va_kernel_present(unsigned long addr)16*4882a593Smuzhiyun int va_kernel_present(unsigned long addr)
17*4882a593Smuzhiyun {
18*4882a593Smuzhiyun 	pmd_t *pmd;
19*4882a593Smuzhiyun 	pte_t *ptep, pte;
20*4882a593Smuzhiyun 
21*4882a593Smuzhiyun 	pmd = pmd_off_k(addr);
22*4882a593Smuzhiyun 	if (!pmd_none(*pmd)) {
23*4882a593Smuzhiyun 		ptep = pte_offset_map(pmd, addr);
24*4882a593Smuzhiyun 		pte = *ptep;
25*4882a593Smuzhiyun 		if (pte_present(pte))
26*4882a593Smuzhiyun 			return pte;
27*4882a593Smuzhiyun 	}
28*4882a593Smuzhiyun 	return 0;
29*4882a593Smuzhiyun }
30*4882a593Smuzhiyun 
va_present(struct mm_struct * mm,unsigned long addr)31*4882a593Smuzhiyun pte_t va_present(struct mm_struct * mm, unsigned long addr)
32*4882a593Smuzhiyun {
33*4882a593Smuzhiyun 	pgd_t *pgd;
34*4882a593Smuzhiyun 	p4d_t *p4d;
35*4882a593Smuzhiyun 	pud_t *pud;
36*4882a593Smuzhiyun 	pmd_t *pmd;
37*4882a593Smuzhiyun 	pte_t *ptep, pte;
38*4882a593Smuzhiyun 
39*4882a593Smuzhiyun 	pgd = pgd_offset(mm, addr);
40*4882a593Smuzhiyun 	if (!pgd_none(*pgd)) {
41*4882a593Smuzhiyun 		p4d = p4d_offset(pgd, addr);
42*4882a593Smuzhiyun 		if (!p4d_none(*p4d)) {
43*4882a593Smuzhiyun 			pud = pud_offset(p4d, addr);
44*4882a593Smuzhiyun 			if (!pud_none(*pud)) {
45*4882a593Smuzhiyun 				pmd = pmd_offset(pud, addr);
46*4882a593Smuzhiyun 				if (!pmd_none(*pmd)) {
47*4882a593Smuzhiyun 					ptep = pte_offset_map(pmd, addr);
48*4882a593Smuzhiyun 					pte = *ptep;
49*4882a593Smuzhiyun 					if (pte_present(pte))
50*4882a593Smuzhiyun 						return pte;
51*4882a593Smuzhiyun 				}
52*4882a593Smuzhiyun 			}
53*4882a593Smuzhiyun 		}
54*4882a593Smuzhiyun 	}
55*4882a593Smuzhiyun 	return 0;
56*4882a593Smuzhiyun 
57*4882a593Smuzhiyun }
58*4882a593Smuzhiyun 
va_readable(struct pt_regs * regs,unsigned long addr)59*4882a593Smuzhiyun int va_readable(struct pt_regs *regs, unsigned long addr)
60*4882a593Smuzhiyun {
61*4882a593Smuzhiyun 	struct mm_struct *mm = current->mm;
62*4882a593Smuzhiyun 	pte_t pte;
63*4882a593Smuzhiyun 	int ret = 0;
64*4882a593Smuzhiyun 
65*4882a593Smuzhiyun 	if (user_mode(regs)) {
66*4882a593Smuzhiyun 		/* user mode */
67*4882a593Smuzhiyun 		pte = va_present(mm, addr);
68*4882a593Smuzhiyun 		if (!pte && pte_read(pte))
69*4882a593Smuzhiyun 			ret = 1;
70*4882a593Smuzhiyun 	} else {
71*4882a593Smuzhiyun 		/* superuser mode is always readable, so we can only
72*4882a593Smuzhiyun 		 * check it is present or not*/
73*4882a593Smuzhiyun 		return (! !va_kernel_present(addr));
74*4882a593Smuzhiyun 	}
75*4882a593Smuzhiyun 	return ret;
76*4882a593Smuzhiyun }
77*4882a593Smuzhiyun 
va_writable(struct pt_regs * regs,unsigned long addr)78*4882a593Smuzhiyun int va_writable(struct pt_regs *regs, unsigned long addr)
79*4882a593Smuzhiyun {
80*4882a593Smuzhiyun 	struct mm_struct *mm = current->mm;
81*4882a593Smuzhiyun 	pte_t pte;
82*4882a593Smuzhiyun 	int ret = 0;
83*4882a593Smuzhiyun 
84*4882a593Smuzhiyun 	if (user_mode(regs)) {
85*4882a593Smuzhiyun 		/* user mode */
86*4882a593Smuzhiyun 		pte = va_present(mm, addr);
87*4882a593Smuzhiyun 		if (!pte && pte_write(pte))
88*4882a593Smuzhiyun 			ret = 1;
89*4882a593Smuzhiyun 	} else {
90*4882a593Smuzhiyun 		/* superuser mode */
91*4882a593Smuzhiyun 		pte = va_kernel_present(addr);
92*4882a593Smuzhiyun 		if (!pte && pte_kernel_write(pte))
93*4882a593Smuzhiyun 			ret = 1;
94*4882a593Smuzhiyun 	}
95*4882a593Smuzhiyun 	return ret;
96*4882a593Smuzhiyun }
97*4882a593Smuzhiyun 
98*4882a593Smuzhiyun /*
99*4882a593Smuzhiyun  * All
100*4882a593Smuzhiyun  */
cpu_icache_inval_all(void)101*4882a593Smuzhiyun void cpu_icache_inval_all(void)
102*4882a593Smuzhiyun {
103*4882a593Smuzhiyun 	unsigned long end, line_size;
104*4882a593Smuzhiyun 
105*4882a593Smuzhiyun 	line_size = L1_cache_info[ICACHE].line_size;
106*4882a593Smuzhiyun 	end =
107*4882a593Smuzhiyun 	    line_size * L1_cache_info[ICACHE].ways * L1_cache_info[ICACHE].sets;
108*4882a593Smuzhiyun 
109*4882a593Smuzhiyun 	do {
110*4882a593Smuzhiyun 		end -= line_size;
111*4882a593Smuzhiyun 		__asm__ volatile ("\n\tcctl %0, L1I_IX_INVAL"::"r" (end));
112*4882a593Smuzhiyun 		end -= line_size;
113*4882a593Smuzhiyun 		__asm__ volatile ("\n\tcctl %0, L1I_IX_INVAL"::"r" (end));
114*4882a593Smuzhiyun 		end -= line_size;
115*4882a593Smuzhiyun 		__asm__ volatile ("\n\tcctl %0, L1I_IX_INVAL"::"r" (end));
116*4882a593Smuzhiyun 		end -= line_size;
117*4882a593Smuzhiyun 		__asm__ volatile ("\n\tcctl %0, L1I_IX_INVAL"::"r" (end));
118*4882a593Smuzhiyun 	} while (end > 0);
119*4882a593Smuzhiyun 	__nds32__isb();
120*4882a593Smuzhiyun }
121*4882a593Smuzhiyun 
cpu_dcache_inval_all(void)122*4882a593Smuzhiyun void cpu_dcache_inval_all(void)
123*4882a593Smuzhiyun {
124*4882a593Smuzhiyun 	__nds32__cctl_l1d_invalall();
125*4882a593Smuzhiyun }
126*4882a593Smuzhiyun 
127*4882a593Smuzhiyun #ifdef CONFIG_CACHE_L2
dcache_wb_all_level(void)128*4882a593Smuzhiyun void dcache_wb_all_level(void)
129*4882a593Smuzhiyun {
130*4882a593Smuzhiyun 	unsigned long flags, cmd;
131*4882a593Smuzhiyun 	local_irq_save(flags);
132*4882a593Smuzhiyun 	__nds32__cctl_l1d_wball_alvl();
133*4882a593Smuzhiyun 	/* Section 1: Ensure the section 2 & 3 program code execution after */
134*4882a593Smuzhiyun 	__nds32__cctlidx_read(NDS32_CCTL_L1D_IX_RWD,0);
135*4882a593Smuzhiyun 
136*4882a593Smuzhiyun 	/* Section 2: Confirm the writeback all level is done in CPU and L2C */
137*4882a593Smuzhiyun 	cmd = CCTL_CMD_L2_SYNC;
138*4882a593Smuzhiyun 	L2_CMD_RDY();
139*4882a593Smuzhiyun 	L2C_W_REG(L2_CCTL_CMD_OFF, cmd);
140*4882a593Smuzhiyun 	L2_CMD_RDY();
141*4882a593Smuzhiyun 
142*4882a593Smuzhiyun 	/* Section 3: Writeback whole L2 cache */
143*4882a593Smuzhiyun 	cmd = CCTL_ALL_CMD | CCTL_CMD_L2_IX_WB;
144*4882a593Smuzhiyun 	L2_CMD_RDY();
145*4882a593Smuzhiyun 	L2C_W_REG(L2_CCTL_CMD_OFF, cmd);
146*4882a593Smuzhiyun 	L2_CMD_RDY();
147*4882a593Smuzhiyun 	__nds32__msync_all();
148*4882a593Smuzhiyun 	local_irq_restore(flags);
149*4882a593Smuzhiyun }
150*4882a593Smuzhiyun EXPORT_SYMBOL(dcache_wb_all_level);
151*4882a593Smuzhiyun #endif
152*4882a593Smuzhiyun 
cpu_dcache_wb_all(void)153*4882a593Smuzhiyun void cpu_dcache_wb_all(void)
154*4882a593Smuzhiyun {
155*4882a593Smuzhiyun 	__nds32__cctl_l1d_wball_one_lvl();
156*4882a593Smuzhiyun 	__nds32__cctlidx_read(NDS32_CCTL_L1D_IX_RWD,0);
157*4882a593Smuzhiyun }
158*4882a593Smuzhiyun 
cpu_dcache_wbinval_all(void)159*4882a593Smuzhiyun void cpu_dcache_wbinval_all(void)
160*4882a593Smuzhiyun {
161*4882a593Smuzhiyun #ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
162*4882a593Smuzhiyun 	unsigned long flags;
163*4882a593Smuzhiyun 	local_irq_save(flags);
164*4882a593Smuzhiyun #endif
165*4882a593Smuzhiyun 	cpu_dcache_wb_all();
166*4882a593Smuzhiyun 	cpu_dcache_inval_all();
167*4882a593Smuzhiyun #ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
168*4882a593Smuzhiyun 	local_irq_restore(flags);
169*4882a593Smuzhiyun #endif
170*4882a593Smuzhiyun }
171*4882a593Smuzhiyun 
172*4882a593Smuzhiyun /*
173*4882a593Smuzhiyun  * Page
174*4882a593Smuzhiyun  */
cpu_icache_inval_page(unsigned long start)175*4882a593Smuzhiyun void cpu_icache_inval_page(unsigned long start)
176*4882a593Smuzhiyun {
177*4882a593Smuzhiyun 	unsigned long line_size, end;
178*4882a593Smuzhiyun 
179*4882a593Smuzhiyun 	line_size = L1_cache_info[ICACHE].line_size;
180*4882a593Smuzhiyun 	end = start + PAGE_SIZE;
181*4882a593Smuzhiyun 
182*4882a593Smuzhiyun 	do {
183*4882a593Smuzhiyun 		end -= line_size;
184*4882a593Smuzhiyun 		__asm__ volatile ("\n\tcctl %0, L1I_VA_INVAL"::"r" (end));
185*4882a593Smuzhiyun 		end -= line_size;
186*4882a593Smuzhiyun 		__asm__ volatile ("\n\tcctl %0, L1I_VA_INVAL"::"r" (end));
187*4882a593Smuzhiyun 		end -= line_size;
188*4882a593Smuzhiyun 		__asm__ volatile ("\n\tcctl %0, L1I_VA_INVAL"::"r" (end));
189*4882a593Smuzhiyun 		end -= line_size;
190*4882a593Smuzhiyun 		__asm__ volatile ("\n\tcctl %0, L1I_VA_INVAL"::"r" (end));
191*4882a593Smuzhiyun 	} while (end != start);
192*4882a593Smuzhiyun 	__nds32__isb();
193*4882a593Smuzhiyun }
194*4882a593Smuzhiyun 
cpu_dcache_inval_page(unsigned long start)195*4882a593Smuzhiyun void cpu_dcache_inval_page(unsigned long start)
196*4882a593Smuzhiyun {
197*4882a593Smuzhiyun 	unsigned long line_size, end;
198*4882a593Smuzhiyun 
199*4882a593Smuzhiyun 	line_size = L1_cache_info[DCACHE].line_size;
200*4882a593Smuzhiyun 	end = start + PAGE_SIZE;
201*4882a593Smuzhiyun 
202*4882a593Smuzhiyun 	do {
203*4882a593Smuzhiyun 		end -= line_size;
204*4882a593Smuzhiyun 		__asm__ volatile ("\n\tcctl %0, L1D_VA_INVAL"::"r" (end));
205*4882a593Smuzhiyun 		end -= line_size;
206*4882a593Smuzhiyun 		__asm__ volatile ("\n\tcctl %0, L1D_VA_INVAL"::"r" (end));
207*4882a593Smuzhiyun 		end -= line_size;
208*4882a593Smuzhiyun 		__asm__ volatile ("\n\tcctl %0, L1D_VA_INVAL"::"r" (end));
209*4882a593Smuzhiyun 		end -= line_size;
210*4882a593Smuzhiyun 		__asm__ volatile ("\n\tcctl %0, L1D_VA_INVAL"::"r" (end));
211*4882a593Smuzhiyun 	} while (end != start);
212*4882a593Smuzhiyun }
213*4882a593Smuzhiyun 
cpu_dcache_wb_page(unsigned long start)214*4882a593Smuzhiyun void cpu_dcache_wb_page(unsigned long start)
215*4882a593Smuzhiyun {
216*4882a593Smuzhiyun #ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
217*4882a593Smuzhiyun 	unsigned long line_size, end;
218*4882a593Smuzhiyun 
219*4882a593Smuzhiyun 	line_size = L1_cache_info[DCACHE].line_size;
220*4882a593Smuzhiyun 	end = start + PAGE_SIZE;
221*4882a593Smuzhiyun 
222*4882a593Smuzhiyun 	do {
223*4882a593Smuzhiyun 		end -= line_size;
224*4882a593Smuzhiyun 		__asm__ volatile ("\n\tcctl %0, L1D_VA_WB"::"r" (end));
225*4882a593Smuzhiyun 		end -= line_size;
226*4882a593Smuzhiyun 		__asm__ volatile ("\n\tcctl %0, L1D_VA_WB"::"r" (end));
227*4882a593Smuzhiyun 		end -= line_size;
228*4882a593Smuzhiyun 		__asm__ volatile ("\n\tcctl %0, L1D_VA_WB"::"r" (end));
229*4882a593Smuzhiyun 		end -= line_size;
230*4882a593Smuzhiyun 		__asm__ volatile ("\n\tcctl %0, L1D_VA_WB"::"r" (end));
231*4882a593Smuzhiyun 	} while (end != start);
232*4882a593Smuzhiyun 	__nds32__cctlidx_read(NDS32_CCTL_L1D_IX_RWD,0);
233*4882a593Smuzhiyun #endif
234*4882a593Smuzhiyun }
235*4882a593Smuzhiyun 
cpu_dcache_wbinval_page(unsigned long start)236*4882a593Smuzhiyun void cpu_dcache_wbinval_page(unsigned long start)
237*4882a593Smuzhiyun {
238*4882a593Smuzhiyun 	unsigned long line_size, end;
239*4882a593Smuzhiyun 
240*4882a593Smuzhiyun 	line_size = L1_cache_info[DCACHE].line_size;
241*4882a593Smuzhiyun 	end = start + PAGE_SIZE;
242*4882a593Smuzhiyun 
243*4882a593Smuzhiyun 	do {
244*4882a593Smuzhiyun 		end -= line_size;
245*4882a593Smuzhiyun #ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
246*4882a593Smuzhiyun 		__asm__ volatile ("\n\tcctl %0, L1D_VA_WB"::"r" (end));
247*4882a593Smuzhiyun #endif
248*4882a593Smuzhiyun 		__asm__ volatile ("\n\tcctl %0, L1D_VA_INVAL"::"r" (end));
249*4882a593Smuzhiyun 		end -= line_size;
250*4882a593Smuzhiyun #ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
251*4882a593Smuzhiyun 		__asm__ volatile ("\n\tcctl %0, L1D_VA_WB"::"r" (end));
252*4882a593Smuzhiyun #endif
253*4882a593Smuzhiyun 		__asm__ volatile ("\n\tcctl %0, L1D_VA_INVAL"::"r" (end));
254*4882a593Smuzhiyun 		end -= line_size;
255*4882a593Smuzhiyun #ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
256*4882a593Smuzhiyun 		__asm__ volatile ("\n\tcctl %0, L1D_VA_WB"::"r" (end));
257*4882a593Smuzhiyun #endif
258*4882a593Smuzhiyun 		__asm__ volatile ("\n\tcctl %0, L1D_VA_INVAL"::"r" (end));
259*4882a593Smuzhiyun 		end -= line_size;
260*4882a593Smuzhiyun #ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
261*4882a593Smuzhiyun 		__asm__ volatile ("\n\tcctl %0, L1D_VA_WB"::"r" (end));
262*4882a593Smuzhiyun #endif
263*4882a593Smuzhiyun 		__asm__ volatile ("\n\tcctl %0, L1D_VA_INVAL"::"r" (end));
264*4882a593Smuzhiyun 	} while (end != start);
265*4882a593Smuzhiyun 	__nds32__cctlidx_read(NDS32_CCTL_L1D_IX_RWD,0);
266*4882a593Smuzhiyun }
267*4882a593Smuzhiyun 
cpu_cache_wbinval_page(unsigned long page,int flushi)268*4882a593Smuzhiyun void cpu_cache_wbinval_page(unsigned long page, int flushi)
269*4882a593Smuzhiyun {
270*4882a593Smuzhiyun 	cpu_dcache_wbinval_page(page);
271*4882a593Smuzhiyun 	if (flushi)
272*4882a593Smuzhiyun 		cpu_icache_inval_page(page);
273*4882a593Smuzhiyun }
274*4882a593Smuzhiyun 
275*4882a593Smuzhiyun /*
276*4882a593Smuzhiyun  * Range
277*4882a593Smuzhiyun  */
cpu_icache_inval_range(unsigned long start,unsigned long end)278*4882a593Smuzhiyun void cpu_icache_inval_range(unsigned long start, unsigned long end)
279*4882a593Smuzhiyun {
280*4882a593Smuzhiyun 	unsigned long line_size;
281*4882a593Smuzhiyun 
282*4882a593Smuzhiyun 	line_size = L1_cache_info[ICACHE].line_size;
283*4882a593Smuzhiyun 
284*4882a593Smuzhiyun 	while (end > start) {
285*4882a593Smuzhiyun 		__asm__ volatile ("\n\tcctl %0, L1I_VA_INVAL"::"r" (start));
286*4882a593Smuzhiyun 		start += line_size;
287*4882a593Smuzhiyun 	}
288*4882a593Smuzhiyun 	__nds32__isb();
289*4882a593Smuzhiyun }
290*4882a593Smuzhiyun 
cpu_dcache_inval_range(unsigned long start,unsigned long end)291*4882a593Smuzhiyun void cpu_dcache_inval_range(unsigned long start, unsigned long end)
292*4882a593Smuzhiyun {
293*4882a593Smuzhiyun 	unsigned long line_size;
294*4882a593Smuzhiyun 
295*4882a593Smuzhiyun 	line_size = L1_cache_info[DCACHE].line_size;
296*4882a593Smuzhiyun 
297*4882a593Smuzhiyun 	while (end > start) {
298*4882a593Smuzhiyun 		__asm__ volatile ("\n\tcctl %0, L1D_VA_INVAL"::"r" (start));
299*4882a593Smuzhiyun 		start += line_size;
300*4882a593Smuzhiyun 	}
301*4882a593Smuzhiyun }
302*4882a593Smuzhiyun 
cpu_dcache_wb_range(unsigned long start,unsigned long end)303*4882a593Smuzhiyun void cpu_dcache_wb_range(unsigned long start, unsigned long end)
304*4882a593Smuzhiyun {
305*4882a593Smuzhiyun #ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
306*4882a593Smuzhiyun 	unsigned long line_size;
307*4882a593Smuzhiyun 
308*4882a593Smuzhiyun 	line_size = L1_cache_info[DCACHE].line_size;
309*4882a593Smuzhiyun 
310*4882a593Smuzhiyun 	while (end > start) {
311*4882a593Smuzhiyun 		__asm__ volatile ("\n\tcctl %0, L1D_VA_WB"::"r" (start));
312*4882a593Smuzhiyun 		start += line_size;
313*4882a593Smuzhiyun 	}
314*4882a593Smuzhiyun 	__nds32__cctlidx_read(NDS32_CCTL_L1D_IX_RWD,0);
315*4882a593Smuzhiyun #endif
316*4882a593Smuzhiyun }
317*4882a593Smuzhiyun 
cpu_dcache_wbinval_range(unsigned long start,unsigned long end)318*4882a593Smuzhiyun void cpu_dcache_wbinval_range(unsigned long start, unsigned long end)
319*4882a593Smuzhiyun {
320*4882a593Smuzhiyun 	unsigned long line_size;
321*4882a593Smuzhiyun 
322*4882a593Smuzhiyun 	line_size = L1_cache_info[DCACHE].line_size;
323*4882a593Smuzhiyun 
324*4882a593Smuzhiyun 	while (end > start) {
325*4882a593Smuzhiyun #ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
326*4882a593Smuzhiyun 		__asm__ volatile ("\n\tcctl %0, L1D_VA_WB"::"r" (start));
327*4882a593Smuzhiyun #endif
328*4882a593Smuzhiyun 		__asm__ volatile ("\n\tcctl %0, L1D_VA_INVAL"::"r" (start));
329*4882a593Smuzhiyun 		start += line_size;
330*4882a593Smuzhiyun 	}
331*4882a593Smuzhiyun 	__nds32__cctlidx_read(NDS32_CCTL_L1D_IX_RWD,0);
332*4882a593Smuzhiyun }
333*4882a593Smuzhiyun 
cpu_cache_wbinval_range(unsigned long start,unsigned long end,int flushi)334*4882a593Smuzhiyun void cpu_cache_wbinval_range(unsigned long start, unsigned long end, int flushi)
335*4882a593Smuzhiyun {
336*4882a593Smuzhiyun 	unsigned long line_size, align_start, align_end;
337*4882a593Smuzhiyun 
338*4882a593Smuzhiyun 	line_size = L1_cache_info[DCACHE].line_size;
339*4882a593Smuzhiyun 	align_start = start & ~(line_size - 1);
340*4882a593Smuzhiyun 	align_end = (end + line_size - 1) & ~(line_size - 1);
341*4882a593Smuzhiyun 	cpu_dcache_wbinval_range(align_start, align_end);
342*4882a593Smuzhiyun 
343*4882a593Smuzhiyun 	if (flushi) {
344*4882a593Smuzhiyun 		line_size = L1_cache_info[ICACHE].line_size;
345*4882a593Smuzhiyun 		align_start = start & ~(line_size - 1);
346*4882a593Smuzhiyun 		align_end = (end + line_size - 1) & ~(line_size - 1);
347*4882a593Smuzhiyun 		cpu_icache_inval_range(align_start, align_end);
348*4882a593Smuzhiyun 	}
349*4882a593Smuzhiyun }
350*4882a593Smuzhiyun 
cpu_cache_wbinval_range_check(struct vm_area_struct * vma,unsigned long start,unsigned long end,bool flushi,bool wbd)351*4882a593Smuzhiyun void cpu_cache_wbinval_range_check(struct vm_area_struct *vma,
352*4882a593Smuzhiyun 				   unsigned long start, unsigned long end,
353*4882a593Smuzhiyun 				   bool flushi, bool wbd)
354*4882a593Smuzhiyun {
355*4882a593Smuzhiyun 	unsigned long line_size, t_start, t_end;
356*4882a593Smuzhiyun 
357*4882a593Smuzhiyun 	if (!flushi && !wbd)
358*4882a593Smuzhiyun 		return;
359*4882a593Smuzhiyun 	line_size = L1_cache_info[DCACHE].line_size;
360*4882a593Smuzhiyun 	start = start & ~(line_size - 1);
361*4882a593Smuzhiyun 	end = (end + line_size - 1) & ~(line_size - 1);
362*4882a593Smuzhiyun 
363*4882a593Smuzhiyun 	if ((end - start) > (8 * PAGE_SIZE)) {
364*4882a593Smuzhiyun 		if (wbd)
365*4882a593Smuzhiyun 			cpu_dcache_wbinval_all();
366*4882a593Smuzhiyun 		if (flushi)
367*4882a593Smuzhiyun 			cpu_icache_inval_all();
368*4882a593Smuzhiyun 		return;
369*4882a593Smuzhiyun 	}
370*4882a593Smuzhiyun 
371*4882a593Smuzhiyun 	t_start = (start + PAGE_SIZE) & PAGE_MASK;
372*4882a593Smuzhiyun 	t_end = ((end - 1) & PAGE_MASK);
373*4882a593Smuzhiyun 
374*4882a593Smuzhiyun 	if ((start & PAGE_MASK) == t_end) {
375*4882a593Smuzhiyun 		if (va_present(vma->vm_mm, start)) {
376*4882a593Smuzhiyun 			if (wbd)
377*4882a593Smuzhiyun 				cpu_dcache_wbinval_range(start, end);
378*4882a593Smuzhiyun 			if (flushi)
379*4882a593Smuzhiyun 				cpu_icache_inval_range(start, end);
380*4882a593Smuzhiyun 		}
381*4882a593Smuzhiyun 		return;
382*4882a593Smuzhiyun 	}
383*4882a593Smuzhiyun 
384*4882a593Smuzhiyun 	if (va_present(vma->vm_mm, start)) {
385*4882a593Smuzhiyun 		if (wbd)
386*4882a593Smuzhiyun 			cpu_dcache_wbinval_range(start, t_start);
387*4882a593Smuzhiyun 		if (flushi)
388*4882a593Smuzhiyun 			cpu_icache_inval_range(start, t_start);
389*4882a593Smuzhiyun 	}
390*4882a593Smuzhiyun 
391*4882a593Smuzhiyun 	if (va_present(vma->vm_mm, end - 1)) {
392*4882a593Smuzhiyun 		if (wbd)
393*4882a593Smuzhiyun 			cpu_dcache_wbinval_range(t_end, end);
394*4882a593Smuzhiyun 		if (flushi)
395*4882a593Smuzhiyun 			cpu_icache_inval_range(t_end, end);
396*4882a593Smuzhiyun 	}
397*4882a593Smuzhiyun 
398*4882a593Smuzhiyun 	while (t_start < t_end) {
399*4882a593Smuzhiyun 		if (va_present(vma->vm_mm, t_start)) {
400*4882a593Smuzhiyun 			if (wbd)
401*4882a593Smuzhiyun 				cpu_dcache_wbinval_page(t_start);
402*4882a593Smuzhiyun 			if (flushi)
403*4882a593Smuzhiyun 				cpu_icache_inval_page(t_start);
404*4882a593Smuzhiyun 		}
405*4882a593Smuzhiyun 		t_start += PAGE_SIZE;
406*4882a593Smuzhiyun 	}
407*4882a593Smuzhiyun }
408*4882a593Smuzhiyun 
409*4882a593Smuzhiyun #ifdef CONFIG_CACHE_L2
cpu_l2cache_op(unsigned long start,unsigned long end,unsigned long op)410*4882a593Smuzhiyun static inline void cpu_l2cache_op(unsigned long start, unsigned long end, unsigned long op)
411*4882a593Smuzhiyun {
412*4882a593Smuzhiyun 	if (atl2c_base) {
413*4882a593Smuzhiyun 		unsigned long p_start = __pa(start);
414*4882a593Smuzhiyun 		unsigned long p_end = __pa(end);
415*4882a593Smuzhiyun 		unsigned long cmd;
416*4882a593Smuzhiyun 		unsigned long line_size;
417*4882a593Smuzhiyun 		/* TODO Can Use PAGE Mode to optimize if range large than PAGE_SIZE */
418*4882a593Smuzhiyun 		line_size = L2_CACHE_LINE_SIZE();
419*4882a593Smuzhiyun 		p_start = p_start & (~(line_size - 1));
420*4882a593Smuzhiyun 		p_end = (p_end + line_size - 1) & (~(line_size - 1));
421*4882a593Smuzhiyun 		cmd =
422*4882a593Smuzhiyun 		    (p_start & ~(line_size - 1)) | op |
423*4882a593Smuzhiyun 		    CCTL_SINGLE_CMD;
424*4882a593Smuzhiyun 		do {
425*4882a593Smuzhiyun 			L2_CMD_RDY();
426*4882a593Smuzhiyun 			L2C_W_REG(L2_CCTL_CMD_OFF, cmd);
427*4882a593Smuzhiyun 			cmd += line_size;
428*4882a593Smuzhiyun 			p_start += line_size;
429*4882a593Smuzhiyun 		} while (p_end > p_start);
430*4882a593Smuzhiyun 		cmd = CCTL_CMD_L2_SYNC;
431*4882a593Smuzhiyun 		L2_CMD_RDY();
432*4882a593Smuzhiyun 		L2C_W_REG(L2_CCTL_CMD_OFF, cmd);
433*4882a593Smuzhiyun 		L2_CMD_RDY();
434*4882a593Smuzhiyun 	}
435*4882a593Smuzhiyun }
436*4882a593Smuzhiyun #else
437*4882a593Smuzhiyun #define cpu_l2cache_op(start,end,op) do { } while (0)
438*4882a593Smuzhiyun #endif
439*4882a593Smuzhiyun /*
440*4882a593Smuzhiyun  * DMA
441*4882a593Smuzhiyun  */
cpu_dma_wb_range(unsigned long start,unsigned long end)442*4882a593Smuzhiyun void cpu_dma_wb_range(unsigned long start, unsigned long end)
443*4882a593Smuzhiyun {
444*4882a593Smuzhiyun 	unsigned long line_size;
445*4882a593Smuzhiyun 	unsigned long flags;
446*4882a593Smuzhiyun 	line_size = L1_cache_info[DCACHE].line_size;
447*4882a593Smuzhiyun 	start = start & (~(line_size - 1));
448*4882a593Smuzhiyun 	end = (end + line_size - 1) & (~(line_size - 1));
449*4882a593Smuzhiyun 	if (unlikely(start == end))
450*4882a593Smuzhiyun 		return;
451*4882a593Smuzhiyun 
452*4882a593Smuzhiyun 	local_irq_save(flags);
453*4882a593Smuzhiyun 	cpu_dcache_wb_range(start, end);
454*4882a593Smuzhiyun 	cpu_l2cache_op(start, end, CCTL_CMD_L2_PA_WB);
455*4882a593Smuzhiyun 	__nds32__msync_all();
456*4882a593Smuzhiyun 	local_irq_restore(flags);
457*4882a593Smuzhiyun }
458*4882a593Smuzhiyun 
cpu_dma_inval_range(unsigned long start,unsigned long end)459*4882a593Smuzhiyun void cpu_dma_inval_range(unsigned long start, unsigned long end)
460*4882a593Smuzhiyun {
461*4882a593Smuzhiyun 	unsigned long line_size;
462*4882a593Smuzhiyun 	unsigned long old_start = start;
463*4882a593Smuzhiyun 	unsigned long old_end = end;
464*4882a593Smuzhiyun 	unsigned long flags;
465*4882a593Smuzhiyun 	line_size = L1_cache_info[DCACHE].line_size;
466*4882a593Smuzhiyun 	start = start & (~(line_size - 1));
467*4882a593Smuzhiyun 	end = (end + line_size - 1) & (~(line_size - 1));
468*4882a593Smuzhiyun 	if (unlikely(start == end))
469*4882a593Smuzhiyun 		return;
470*4882a593Smuzhiyun 	local_irq_save(flags);
471*4882a593Smuzhiyun 	if (start != old_start) {
472*4882a593Smuzhiyun 		cpu_dcache_wbinval_range(start, start + line_size);
473*4882a593Smuzhiyun 		cpu_l2cache_op(start, start + line_size, CCTL_CMD_L2_PA_WBINVAL);
474*4882a593Smuzhiyun 	}
475*4882a593Smuzhiyun 	if (end != old_end) {
476*4882a593Smuzhiyun 		cpu_dcache_wbinval_range(end - line_size, end);
477*4882a593Smuzhiyun 		cpu_l2cache_op(end - line_size, end, CCTL_CMD_L2_PA_WBINVAL);
478*4882a593Smuzhiyun 	}
479*4882a593Smuzhiyun 	cpu_dcache_inval_range(start, end);
480*4882a593Smuzhiyun 	cpu_l2cache_op(start, end, CCTL_CMD_L2_PA_INVAL);
481*4882a593Smuzhiyun 	__nds32__msync_all();
482*4882a593Smuzhiyun 	local_irq_restore(flags);
483*4882a593Smuzhiyun 
484*4882a593Smuzhiyun }
485*4882a593Smuzhiyun 
cpu_dma_wbinval_range(unsigned long start,unsigned long end)486*4882a593Smuzhiyun void cpu_dma_wbinval_range(unsigned long start, unsigned long end)
487*4882a593Smuzhiyun {
488*4882a593Smuzhiyun 	unsigned long line_size;
489*4882a593Smuzhiyun 	unsigned long flags;
490*4882a593Smuzhiyun 	line_size = L1_cache_info[DCACHE].line_size;
491*4882a593Smuzhiyun 	start = start & (~(line_size - 1));
492*4882a593Smuzhiyun 	end = (end + line_size - 1) & (~(line_size - 1));
493*4882a593Smuzhiyun 	if (unlikely(start == end))
494*4882a593Smuzhiyun 		return;
495*4882a593Smuzhiyun 
496*4882a593Smuzhiyun 	local_irq_save(flags);
497*4882a593Smuzhiyun 	cpu_dcache_wbinval_range(start, end);
498*4882a593Smuzhiyun 	cpu_l2cache_op(start, end, CCTL_CMD_L2_PA_WBINVAL);
499*4882a593Smuzhiyun 	__nds32__msync_all();
500*4882a593Smuzhiyun 	local_irq_restore(flags);
501*4882a593Smuzhiyun }
502*4882a593Smuzhiyun 
cpu_proc_init(void)503*4882a593Smuzhiyun void cpu_proc_init(void)
504*4882a593Smuzhiyun {
505*4882a593Smuzhiyun }
506*4882a593Smuzhiyun 
cpu_proc_fin(void)507*4882a593Smuzhiyun void cpu_proc_fin(void)
508*4882a593Smuzhiyun {
509*4882a593Smuzhiyun }
510*4882a593Smuzhiyun 
cpu_do_idle(void)511*4882a593Smuzhiyun void cpu_do_idle(void)
512*4882a593Smuzhiyun {
513*4882a593Smuzhiyun 	__nds32__standby_no_wake_grant();
514*4882a593Smuzhiyun }
515*4882a593Smuzhiyun 
cpu_reset(unsigned long reset)516*4882a593Smuzhiyun void cpu_reset(unsigned long reset)
517*4882a593Smuzhiyun {
518*4882a593Smuzhiyun 	u32 tmp;
519*4882a593Smuzhiyun 	GIE_DISABLE();
520*4882a593Smuzhiyun 	tmp = __nds32__mfsr(NDS32_SR_CACHE_CTL);
521*4882a593Smuzhiyun 	tmp &= ~(CACHE_CTL_mskIC_EN | CACHE_CTL_mskDC_EN);
522*4882a593Smuzhiyun 	__nds32__mtsr_isb(tmp, NDS32_SR_CACHE_CTL);
523*4882a593Smuzhiyun 	cpu_dcache_wbinval_all();
524*4882a593Smuzhiyun 	cpu_icache_inval_all();
525*4882a593Smuzhiyun 
526*4882a593Smuzhiyun 	__asm__ __volatile__("jr.toff %0\n\t"::"r"(reset));
527*4882a593Smuzhiyun }
528*4882a593Smuzhiyun 
cpu_switch_mm(struct mm_struct * mm)529*4882a593Smuzhiyun void cpu_switch_mm(struct mm_struct *mm)
530*4882a593Smuzhiyun {
531*4882a593Smuzhiyun 	unsigned long cid;
532*4882a593Smuzhiyun 	cid = __nds32__mfsr(NDS32_SR_TLB_MISC);
533*4882a593Smuzhiyun 	cid = (cid & ~TLB_MISC_mskCID) | mm->context.id;
534*4882a593Smuzhiyun 	__nds32__mtsr_dsb(cid, NDS32_SR_TLB_MISC);
535*4882a593Smuzhiyun 	__nds32__mtsr_isb(__pa(mm->pgd), NDS32_SR_L1_PPTB);
536*4882a593Smuzhiyun }
537