xref: /OK3568_Linux_fs/kernel/arch/arm/vfp/vfpmodule.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  *  linux/arch/arm/vfp/vfpmodule.c
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  *  Copyright (C) 2004 ARM Limited.
6*4882a593Smuzhiyun  *  Written by Deep Blue Solutions Limited.
7*4882a593Smuzhiyun  */
8*4882a593Smuzhiyun #include <linux/types.h>
9*4882a593Smuzhiyun #include <linux/cpu.h>
10*4882a593Smuzhiyun #include <linux/cpu_pm.h>
11*4882a593Smuzhiyun #include <linux/hardirq.h>
12*4882a593Smuzhiyun #include <linux/kernel.h>
13*4882a593Smuzhiyun #include <linux/notifier.h>
14*4882a593Smuzhiyun #include <linux/signal.h>
15*4882a593Smuzhiyun #include <linux/sched/signal.h>
16*4882a593Smuzhiyun #include <linux/smp.h>
17*4882a593Smuzhiyun #include <linux/init.h>
18*4882a593Smuzhiyun #include <linux/uaccess.h>
19*4882a593Smuzhiyun #include <linux/user.h>
20*4882a593Smuzhiyun #include <linux/export.h>
21*4882a593Smuzhiyun 
22*4882a593Smuzhiyun #include <asm/cp15.h>
23*4882a593Smuzhiyun #include <asm/cputype.h>
24*4882a593Smuzhiyun #include <asm/system_info.h>
25*4882a593Smuzhiyun #include <asm/thread_notify.h>
26*4882a593Smuzhiyun #include <asm/traps.h>
27*4882a593Smuzhiyun #include <asm/vfp.h>
28*4882a593Smuzhiyun 
29*4882a593Smuzhiyun #include "vfpinstr.h"
30*4882a593Smuzhiyun #include "vfp.h"
31*4882a593Smuzhiyun 
32*4882a593Smuzhiyun /*
33*4882a593Smuzhiyun  * Our undef handlers (in entry.S)
34*4882a593Smuzhiyun  */
35*4882a593Smuzhiyun asmlinkage void vfp_support_entry(void);
36*4882a593Smuzhiyun asmlinkage void vfp_null_entry(void);
37*4882a593Smuzhiyun 
38*4882a593Smuzhiyun asmlinkage void (*vfp_vector)(void) = vfp_null_entry;
39*4882a593Smuzhiyun 
40*4882a593Smuzhiyun /*
41*4882a593Smuzhiyun  * Dual-use variable.
42*4882a593Smuzhiyun  * Used in startup: set to non-zero if VFP checks fail
43*4882a593Smuzhiyun  * After startup, holds VFP architecture
44*4882a593Smuzhiyun  */
45*4882a593Smuzhiyun static unsigned int __initdata VFP_arch;
46*4882a593Smuzhiyun 
47*4882a593Smuzhiyun /*
48*4882a593Smuzhiyun  * The pointer to the vfpstate structure of the thread which currently
49*4882a593Smuzhiyun  * owns the context held in the VFP hardware, or NULL if the hardware
50*4882a593Smuzhiyun  * context is invalid.
51*4882a593Smuzhiyun  *
52*4882a593Smuzhiyun  * For UP, this is sufficient to tell which thread owns the VFP context.
53*4882a593Smuzhiyun  * However, for SMP, we also need to check the CPU number stored in the
54*4882a593Smuzhiyun  * saved state too to catch migrations.
55*4882a593Smuzhiyun  */
56*4882a593Smuzhiyun union vfp_state *vfp_current_hw_state[NR_CPUS];
57*4882a593Smuzhiyun 
58*4882a593Smuzhiyun /*
59*4882a593Smuzhiyun  * Is 'thread's most up to date state stored in this CPUs hardware?
60*4882a593Smuzhiyun  * Must be called from non-preemptible context.
61*4882a593Smuzhiyun  */
vfp_state_in_hw(unsigned int cpu,struct thread_info * thread)62*4882a593Smuzhiyun static bool vfp_state_in_hw(unsigned int cpu, struct thread_info *thread)
63*4882a593Smuzhiyun {
64*4882a593Smuzhiyun #ifdef CONFIG_SMP
65*4882a593Smuzhiyun 	if (thread->vfpstate.hard.cpu != cpu)
66*4882a593Smuzhiyun 		return false;
67*4882a593Smuzhiyun #endif
68*4882a593Smuzhiyun 	return vfp_current_hw_state[cpu] == &thread->vfpstate;
69*4882a593Smuzhiyun }
70*4882a593Smuzhiyun 
71*4882a593Smuzhiyun /*
72*4882a593Smuzhiyun  * Force a reload of the VFP context from the thread structure.  We do
73*4882a593Smuzhiyun  * this by ensuring that access to the VFP hardware is disabled, and
74*4882a593Smuzhiyun  * clear vfp_current_hw_state.  Must be called from non-preemptible context.
75*4882a593Smuzhiyun  */
vfp_force_reload(unsigned int cpu,struct thread_info * thread)76*4882a593Smuzhiyun static void vfp_force_reload(unsigned int cpu, struct thread_info *thread)
77*4882a593Smuzhiyun {
78*4882a593Smuzhiyun 	if (vfp_state_in_hw(cpu, thread)) {
79*4882a593Smuzhiyun 		fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_EN);
80*4882a593Smuzhiyun 		vfp_current_hw_state[cpu] = NULL;
81*4882a593Smuzhiyun 	}
82*4882a593Smuzhiyun #ifdef CONFIG_SMP
83*4882a593Smuzhiyun 	thread->vfpstate.hard.cpu = NR_CPUS;
84*4882a593Smuzhiyun #endif
85*4882a593Smuzhiyun }
86*4882a593Smuzhiyun 
87*4882a593Smuzhiyun /*
88*4882a593Smuzhiyun  * Per-thread VFP initialization.
89*4882a593Smuzhiyun  */
vfp_thread_flush(struct thread_info * thread)90*4882a593Smuzhiyun static void vfp_thread_flush(struct thread_info *thread)
91*4882a593Smuzhiyun {
92*4882a593Smuzhiyun 	union vfp_state *vfp = &thread->vfpstate;
93*4882a593Smuzhiyun 	unsigned int cpu;
94*4882a593Smuzhiyun 
95*4882a593Smuzhiyun 	/*
96*4882a593Smuzhiyun 	 * Disable VFP to ensure we initialize it first.  We must ensure
97*4882a593Smuzhiyun 	 * that the modification of vfp_current_hw_state[] and hardware
98*4882a593Smuzhiyun 	 * disable are done for the same CPU and without preemption.
99*4882a593Smuzhiyun 	 *
100*4882a593Smuzhiyun 	 * Do this first to ensure that preemption won't overwrite our
101*4882a593Smuzhiyun 	 * state saving should access to the VFP be enabled at this point.
102*4882a593Smuzhiyun 	 */
103*4882a593Smuzhiyun 	cpu = get_cpu();
104*4882a593Smuzhiyun 	if (vfp_current_hw_state[cpu] == vfp)
105*4882a593Smuzhiyun 		vfp_current_hw_state[cpu] = NULL;
106*4882a593Smuzhiyun 	fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_EN);
107*4882a593Smuzhiyun 	put_cpu();
108*4882a593Smuzhiyun 
109*4882a593Smuzhiyun 	memset(vfp, 0, sizeof(union vfp_state));
110*4882a593Smuzhiyun 
111*4882a593Smuzhiyun 	vfp->hard.fpexc = FPEXC_EN;
112*4882a593Smuzhiyun 	vfp->hard.fpscr = FPSCR_ROUND_NEAREST;
113*4882a593Smuzhiyun #ifdef CONFIG_SMP
114*4882a593Smuzhiyun 	vfp->hard.cpu = NR_CPUS;
115*4882a593Smuzhiyun #endif
116*4882a593Smuzhiyun }
117*4882a593Smuzhiyun 
vfp_thread_exit(struct thread_info * thread)118*4882a593Smuzhiyun static void vfp_thread_exit(struct thread_info *thread)
119*4882a593Smuzhiyun {
120*4882a593Smuzhiyun 	/* release case: Per-thread VFP cleanup. */
121*4882a593Smuzhiyun 	union vfp_state *vfp = &thread->vfpstate;
122*4882a593Smuzhiyun 	unsigned int cpu = get_cpu();
123*4882a593Smuzhiyun 
124*4882a593Smuzhiyun 	if (vfp_current_hw_state[cpu] == vfp)
125*4882a593Smuzhiyun 		vfp_current_hw_state[cpu] = NULL;
126*4882a593Smuzhiyun 	put_cpu();
127*4882a593Smuzhiyun }
128*4882a593Smuzhiyun 
vfp_thread_copy(struct thread_info * thread)129*4882a593Smuzhiyun static void vfp_thread_copy(struct thread_info *thread)
130*4882a593Smuzhiyun {
131*4882a593Smuzhiyun 	struct thread_info *parent = current_thread_info();
132*4882a593Smuzhiyun 
133*4882a593Smuzhiyun 	vfp_sync_hwstate(parent);
134*4882a593Smuzhiyun 	thread->vfpstate = parent->vfpstate;
135*4882a593Smuzhiyun #ifdef CONFIG_SMP
136*4882a593Smuzhiyun 	thread->vfpstate.hard.cpu = NR_CPUS;
137*4882a593Smuzhiyun #endif
138*4882a593Smuzhiyun }
139*4882a593Smuzhiyun 
140*4882a593Smuzhiyun /*
141*4882a593Smuzhiyun  * When this function is called with the following 'cmd's, the following
142*4882a593Smuzhiyun  * is true while this function is being run:
143*4882a593Smuzhiyun  *  THREAD_NOFTIFY_SWTICH:
144*4882a593Smuzhiyun  *   - the previously running thread will not be scheduled onto another CPU.
145*4882a593Smuzhiyun  *   - the next thread to be run (v) will not be running on another CPU.
146*4882a593Smuzhiyun  *   - thread->cpu is the local CPU number
147*4882a593Smuzhiyun  *   - not preemptible as we're called in the middle of a thread switch
148*4882a593Smuzhiyun  *  THREAD_NOTIFY_FLUSH:
149*4882a593Smuzhiyun  *   - the thread (v) will be running on the local CPU, so
150*4882a593Smuzhiyun  *	v === current_thread_info()
151*4882a593Smuzhiyun  *   - thread->cpu is the local CPU number at the time it is accessed,
152*4882a593Smuzhiyun  *	but may change at any time.
153*4882a593Smuzhiyun  *   - we could be preempted if tree preempt rcu is enabled, so
154*4882a593Smuzhiyun  *	it is unsafe to use thread->cpu.
155*4882a593Smuzhiyun  *  THREAD_NOTIFY_EXIT
156*4882a593Smuzhiyun  *   - we could be preempted if tree preempt rcu is enabled, so
157*4882a593Smuzhiyun  *	it is unsafe to use thread->cpu.
158*4882a593Smuzhiyun  */
vfp_notifier(struct notifier_block * self,unsigned long cmd,void * v)159*4882a593Smuzhiyun static int vfp_notifier(struct notifier_block *self, unsigned long cmd, void *v)
160*4882a593Smuzhiyun {
161*4882a593Smuzhiyun 	struct thread_info *thread = v;
162*4882a593Smuzhiyun 	u32 fpexc;
163*4882a593Smuzhiyun #ifdef CONFIG_SMP
164*4882a593Smuzhiyun 	unsigned int cpu;
165*4882a593Smuzhiyun #endif
166*4882a593Smuzhiyun 
167*4882a593Smuzhiyun 	switch (cmd) {
168*4882a593Smuzhiyun 	case THREAD_NOTIFY_SWITCH:
169*4882a593Smuzhiyun 		fpexc = fmrx(FPEXC);
170*4882a593Smuzhiyun 
171*4882a593Smuzhiyun #ifdef CONFIG_SMP
172*4882a593Smuzhiyun 		cpu = thread->cpu;
173*4882a593Smuzhiyun 
174*4882a593Smuzhiyun 		/*
175*4882a593Smuzhiyun 		 * On SMP, if VFP is enabled, save the old state in
176*4882a593Smuzhiyun 		 * case the thread migrates to a different CPU. The
177*4882a593Smuzhiyun 		 * restoring is done lazily.
178*4882a593Smuzhiyun 		 */
179*4882a593Smuzhiyun 		if ((fpexc & FPEXC_EN) && vfp_current_hw_state[cpu])
180*4882a593Smuzhiyun 			vfp_save_state(vfp_current_hw_state[cpu], fpexc);
181*4882a593Smuzhiyun #endif
182*4882a593Smuzhiyun 
183*4882a593Smuzhiyun 		/*
184*4882a593Smuzhiyun 		 * Always disable VFP so we can lazily save/restore the
185*4882a593Smuzhiyun 		 * old state.
186*4882a593Smuzhiyun 		 */
187*4882a593Smuzhiyun 		fmxr(FPEXC, fpexc & ~FPEXC_EN);
188*4882a593Smuzhiyun 		break;
189*4882a593Smuzhiyun 
190*4882a593Smuzhiyun 	case THREAD_NOTIFY_FLUSH:
191*4882a593Smuzhiyun 		vfp_thread_flush(thread);
192*4882a593Smuzhiyun 		break;
193*4882a593Smuzhiyun 
194*4882a593Smuzhiyun 	case THREAD_NOTIFY_EXIT:
195*4882a593Smuzhiyun 		vfp_thread_exit(thread);
196*4882a593Smuzhiyun 		break;
197*4882a593Smuzhiyun 
198*4882a593Smuzhiyun 	case THREAD_NOTIFY_COPY:
199*4882a593Smuzhiyun 		vfp_thread_copy(thread);
200*4882a593Smuzhiyun 		break;
201*4882a593Smuzhiyun 	}
202*4882a593Smuzhiyun 
203*4882a593Smuzhiyun 	return NOTIFY_DONE;
204*4882a593Smuzhiyun }
205*4882a593Smuzhiyun 
206*4882a593Smuzhiyun static struct notifier_block vfp_notifier_block = {
207*4882a593Smuzhiyun 	.notifier_call	= vfp_notifier,
208*4882a593Smuzhiyun };
209*4882a593Smuzhiyun 
210*4882a593Smuzhiyun /*
211*4882a593Smuzhiyun  * Raise a SIGFPE for the current process.
212*4882a593Smuzhiyun  * sicode describes the signal being raised.
213*4882a593Smuzhiyun  */
vfp_raise_sigfpe(unsigned int sicode,struct pt_regs * regs)214*4882a593Smuzhiyun static void vfp_raise_sigfpe(unsigned int sicode, struct pt_regs *regs)
215*4882a593Smuzhiyun {
216*4882a593Smuzhiyun 	/*
217*4882a593Smuzhiyun 	 * This is the same as NWFPE, because it's not clear what
218*4882a593Smuzhiyun 	 * this is used for
219*4882a593Smuzhiyun 	 */
220*4882a593Smuzhiyun 	current->thread.error_code = 0;
221*4882a593Smuzhiyun 	current->thread.trap_no = 6;
222*4882a593Smuzhiyun 
223*4882a593Smuzhiyun 	send_sig_fault(SIGFPE, sicode,
224*4882a593Smuzhiyun 		       (void __user *)(instruction_pointer(regs) - 4),
225*4882a593Smuzhiyun 		       current);
226*4882a593Smuzhiyun }
227*4882a593Smuzhiyun 
vfp_panic(char * reason,u32 inst)228*4882a593Smuzhiyun static void vfp_panic(char *reason, u32 inst)
229*4882a593Smuzhiyun {
230*4882a593Smuzhiyun 	int i;
231*4882a593Smuzhiyun 
232*4882a593Smuzhiyun 	pr_err("VFP: Error: %s\n", reason);
233*4882a593Smuzhiyun 	pr_err("VFP: EXC 0x%08x SCR 0x%08x INST 0x%08x\n",
234*4882a593Smuzhiyun 		fmrx(FPEXC), fmrx(FPSCR), inst);
235*4882a593Smuzhiyun 	for (i = 0; i < 32; i += 2)
236*4882a593Smuzhiyun 		pr_err("VFP: s%2u: 0x%08x s%2u: 0x%08x\n",
237*4882a593Smuzhiyun 		       i, vfp_get_float(i), i+1, vfp_get_float(i+1));
238*4882a593Smuzhiyun }
239*4882a593Smuzhiyun 
240*4882a593Smuzhiyun /*
241*4882a593Smuzhiyun  * Process bitmask of exception conditions.
242*4882a593Smuzhiyun  */
vfp_raise_exceptions(u32 exceptions,u32 inst,u32 fpscr,struct pt_regs * regs)243*4882a593Smuzhiyun static void vfp_raise_exceptions(u32 exceptions, u32 inst, u32 fpscr, struct pt_regs *regs)
244*4882a593Smuzhiyun {
245*4882a593Smuzhiyun 	int si_code = 0;
246*4882a593Smuzhiyun 
247*4882a593Smuzhiyun 	pr_debug("VFP: raising exceptions %08x\n", exceptions);
248*4882a593Smuzhiyun 
249*4882a593Smuzhiyun 	if (exceptions == VFP_EXCEPTION_ERROR) {
250*4882a593Smuzhiyun 		vfp_panic("unhandled bounce", inst);
251*4882a593Smuzhiyun 		vfp_raise_sigfpe(FPE_FLTINV, regs);
252*4882a593Smuzhiyun 		return;
253*4882a593Smuzhiyun 	}
254*4882a593Smuzhiyun 
255*4882a593Smuzhiyun 	/*
256*4882a593Smuzhiyun 	 * If any of the status flags are set, update the FPSCR.
257*4882a593Smuzhiyun 	 * Comparison instructions always return at least one of
258*4882a593Smuzhiyun 	 * these flags set.
259*4882a593Smuzhiyun 	 */
260*4882a593Smuzhiyun 	if (exceptions & (FPSCR_N|FPSCR_Z|FPSCR_C|FPSCR_V))
261*4882a593Smuzhiyun 		fpscr &= ~(FPSCR_N|FPSCR_Z|FPSCR_C|FPSCR_V);
262*4882a593Smuzhiyun 
263*4882a593Smuzhiyun 	fpscr |= exceptions;
264*4882a593Smuzhiyun 
265*4882a593Smuzhiyun 	fmxr(FPSCR, fpscr);
266*4882a593Smuzhiyun 
267*4882a593Smuzhiyun #define RAISE(stat,en,sig)				\
268*4882a593Smuzhiyun 	if (exceptions & stat && fpscr & en)		\
269*4882a593Smuzhiyun 		si_code = sig;
270*4882a593Smuzhiyun 
271*4882a593Smuzhiyun 	/*
272*4882a593Smuzhiyun 	 * These are arranged in priority order, least to highest.
273*4882a593Smuzhiyun 	 */
274*4882a593Smuzhiyun 	RAISE(FPSCR_DZC, FPSCR_DZE, FPE_FLTDIV);
275*4882a593Smuzhiyun 	RAISE(FPSCR_IXC, FPSCR_IXE, FPE_FLTRES);
276*4882a593Smuzhiyun 	RAISE(FPSCR_UFC, FPSCR_UFE, FPE_FLTUND);
277*4882a593Smuzhiyun 	RAISE(FPSCR_OFC, FPSCR_OFE, FPE_FLTOVF);
278*4882a593Smuzhiyun 	RAISE(FPSCR_IOC, FPSCR_IOE, FPE_FLTINV);
279*4882a593Smuzhiyun 
280*4882a593Smuzhiyun 	if (si_code)
281*4882a593Smuzhiyun 		vfp_raise_sigfpe(si_code, regs);
282*4882a593Smuzhiyun }
283*4882a593Smuzhiyun 
284*4882a593Smuzhiyun /*
285*4882a593Smuzhiyun  * Emulate a VFP instruction.
286*4882a593Smuzhiyun  */
vfp_emulate_instruction(u32 inst,u32 fpscr,struct pt_regs * regs)287*4882a593Smuzhiyun static u32 vfp_emulate_instruction(u32 inst, u32 fpscr, struct pt_regs *regs)
288*4882a593Smuzhiyun {
289*4882a593Smuzhiyun 	u32 exceptions = VFP_EXCEPTION_ERROR;
290*4882a593Smuzhiyun 
291*4882a593Smuzhiyun 	pr_debug("VFP: emulate: INST=0x%08x SCR=0x%08x\n", inst, fpscr);
292*4882a593Smuzhiyun 
293*4882a593Smuzhiyun 	if (INST_CPRTDO(inst)) {
294*4882a593Smuzhiyun 		if (!INST_CPRT(inst)) {
295*4882a593Smuzhiyun 			/*
296*4882a593Smuzhiyun 			 * CPDO
297*4882a593Smuzhiyun 			 */
298*4882a593Smuzhiyun 			if (vfp_single(inst)) {
299*4882a593Smuzhiyun 				exceptions = vfp_single_cpdo(inst, fpscr);
300*4882a593Smuzhiyun 			} else {
301*4882a593Smuzhiyun 				exceptions = vfp_double_cpdo(inst, fpscr);
302*4882a593Smuzhiyun 			}
303*4882a593Smuzhiyun 		} else {
304*4882a593Smuzhiyun 			/*
305*4882a593Smuzhiyun 			 * A CPRT instruction can not appear in FPINST2, nor
306*4882a593Smuzhiyun 			 * can it cause an exception.  Therefore, we do not
307*4882a593Smuzhiyun 			 * have to emulate it.
308*4882a593Smuzhiyun 			 */
309*4882a593Smuzhiyun 		}
310*4882a593Smuzhiyun 	} else {
311*4882a593Smuzhiyun 		/*
312*4882a593Smuzhiyun 		 * A CPDT instruction can not appear in FPINST2, nor can
313*4882a593Smuzhiyun 		 * it cause an exception.  Therefore, we do not have to
314*4882a593Smuzhiyun 		 * emulate it.
315*4882a593Smuzhiyun 		 */
316*4882a593Smuzhiyun 	}
317*4882a593Smuzhiyun 	return exceptions & ~VFP_NAN_FLAG;
318*4882a593Smuzhiyun }
319*4882a593Smuzhiyun 
320*4882a593Smuzhiyun /*
321*4882a593Smuzhiyun  * Package up a bounce condition.
322*4882a593Smuzhiyun  */
VFP_bounce(u32 trigger,u32 fpexc,struct pt_regs * regs)323*4882a593Smuzhiyun void VFP_bounce(u32 trigger, u32 fpexc, struct pt_regs *regs)
324*4882a593Smuzhiyun {
325*4882a593Smuzhiyun 	u32 fpscr, orig_fpscr, fpsid, exceptions;
326*4882a593Smuzhiyun 
327*4882a593Smuzhiyun 	pr_debug("VFP: bounce: trigger %08x fpexc %08x\n", trigger, fpexc);
328*4882a593Smuzhiyun 
329*4882a593Smuzhiyun 	/*
330*4882a593Smuzhiyun 	 * At this point, FPEXC can have the following configuration:
331*4882a593Smuzhiyun 	 *
332*4882a593Smuzhiyun 	 *  EX DEX IXE
333*4882a593Smuzhiyun 	 *  0   1   x   - synchronous exception
334*4882a593Smuzhiyun 	 *  1   x   0   - asynchronous exception
335*4882a593Smuzhiyun 	 *  1   x   1   - sychronous on VFP subarch 1 and asynchronous on later
336*4882a593Smuzhiyun 	 *  0   0   1   - synchronous on VFP9 (non-standard subarch 1
337*4882a593Smuzhiyun 	 *                implementation), undefined otherwise
338*4882a593Smuzhiyun 	 *
339*4882a593Smuzhiyun 	 * Clear various bits and enable access to the VFP so we can
340*4882a593Smuzhiyun 	 * handle the bounce.
341*4882a593Smuzhiyun 	 */
342*4882a593Smuzhiyun 	fmxr(FPEXC, fpexc & ~(FPEXC_EX|FPEXC_DEX|FPEXC_FP2V|FPEXC_VV|FPEXC_TRAP_MASK));
343*4882a593Smuzhiyun 
344*4882a593Smuzhiyun 	fpsid = fmrx(FPSID);
345*4882a593Smuzhiyun 	orig_fpscr = fpscr = fmrx(FPSCR);
346*4882a593Smuzhiyun 
347*4882a593Smuzhiyun 	/*
348*4882a593Smuzhiyun 	 * Check for the special VFP subarch 1 and FPSCR.IXE bit case
349*4882a593Smuzhiyun 	 */
350*4882a593Smuzhiyun 	if ((fpsid & FPSID_ARCH_MASK) == (1 << FPSID_ARCH_BIT)
351*4882a593Smuzhiyun 	    && (fpscr & FPSCR_IXE)) {
352*4882a593Smuzhiyun 		/*
353*4882a593Smuzhiyun 		 * Synchronous exception, emulate the trigger instruction
354*4882a593Smuzhiyun 		 */
355*4882a593Smuzhiyun 		goto emulate;
356*4882a593Smuzhiyun 	}
357*4882a593Smuzhiyun 
358*4882a593Smuzhiyun 	if (fpexc & FPEXC_EX) {
359*4882a593Smuzhiyun #ifndef CONFIG_CPU_FEROCEON
360*4882a593Smuzhiyun 		/*
361*4882a593Smuzhiyun 		 * Asynchronous exception. The instruction is read from FPINST
362*4882a593Smuzhiyun 		 * and the interrupted instruction has to be restarted.
363*4882a593Smuzhiyun 		 */
364*4882a593Smuzhiyun 		trigger = fmrx(FPINST);
365*4882a593Smuzhiyun 		regs->ARM_pc -= 4;
366*4882a593Smuzhiyun #endif
367*4882a593Smuzhiyun 	} else if (!(fpexc & FPEXC_DEX)) {
368*4882a593Smuzhiyun 		/*
369*4882a593Smuzhiyun 		 * Illegal combination of bits. It can be caused by an
370*4882a593Smuzhiyun 		 * unallocated VFP instruction but with FPSCR.IXE set and not
371*4882a593Smuzhiyun 		 * on VFP subarch 1.
372*4882a593Smuzhiyun 		 */
373*4882a593Smuzhiyun 		 vfp_raise_exceptions(VFP_EXCEPTION_ERROR, trigger, fpscr, regs);
374*4882a593Smuzhiyun 		goto exit;
375*4882a593Smuzhiyun 	}
376*4882a593Smuzhiyun 
377*4882a593Smuzhiyun 	/*
378*4882a593Smuzhiyun 	 * Modify fpscr to indicate the number of iterations remaining.
379*4882a593Smuzhiyun 	 * If FPEXC.EX is 0, FPEXC.DEX is 1 and the FPEXC.VV bit indicates
380*4882a593Smuzhiyun 	 * whether FPEXC.VECITR or FPSCR.LEN is used.
381*4882a593Smuzhiyun 	 */
382*4882a593Smuzhiyun 	if (fpexc & (FPEXC_EX | FPEXC_VV)) {
383*4882a593Smuzhiyun 		u32 len;
384*4882a593Smuzhiyun 
385*4882a593Smuzhiyun 		len = fpexc + (1 << FPEXC_LENGTH_BIT);
386*4882a593Smuzhiyun 
387*4882a593Smuzhiyun 		fpscr &= ~FPSCR_LENGTH_MASK;
388*4882a593Smuzhiyun 		fpscr |= (len & FPEXC_LENGTH_MASK) << (FPSCR_LENGTH_BIT - FPEXC_LENGTH_BIT);
389*4882a593Smuzhiyun 	}
390*4882a593Smuzhiyun 
391*4882a593Smuzhiyun 	/*
392*4882a593Smuzhiyun 	 * Handle the first FP instruction.  We used to take note of the
393*4882a593Smuzhiyun 	 * FPEXC bounce reason, but this appears to be unreliable.
394*4882a593Smuzhiyun 	 * Emulate the bounced instruction instead.
395*4882a593Smuzhiyun 	 */
396*4882a593Smuzhiyun 	exceptions = vfp_emulate_instruction(trigger, fpscr, regs);
397*4882a593Smuzhiyun 	if (exceptions)
398*4882a593Smuzhiyun 		vfp_raise_exceptions(exceptions, trigger, orig_fpscr, regs);
399*4882a593Smuzhiyun 
400*4882a593Smuzhiyun 	/*
401*4882a593Smuzhiyun 	 * If there isn't a second FP instruction, exit now. Note that
402*4882a593Smuzhiyun 	 * the FPEXC.FP2V bit is valid only if FPEXC.EX is 1.
403*4882a593Smuzhiyun 	 */
404*4882a593Smuzhiyun 	if ((fpexc & (FPEXC_EX | FPEXC_FP2V)) != (FPEXC_EX | FPEXC_FP2V))
405*4882a593Smuzhiyun 		goto exit;
406*4882a593Smuzhiyun 
407*4882a593Smuzhiyun 	/*
408*4882a593Smuzhiyun 	 * The barrier() here prevents fpinst2 being read
409*4882a593Smuzhiyun 	 * before the condition above.
410*4882a593Smuzhiyun 	 */
411*4882a593Smuzhiyun 	barrier();
412*4882a593Smuzhiyun 	trigger = fmrx(FPINST2);
413*4882a593Smuzhiyun 
414*4882a593Smuzhiyun  emulate:
415*4882a593Smuzhiyun 	exceptions = vfp_emulate_instruction(trigger, orig_fpscr, regs);
416*4882a593Smuzhiyun 	if (exceptions)
417*4882a593Smuzhiyun 		vfp_raise_exceptions(exceptions, trigger, orig_fpscr, regs);
418*4882a593Smuzhiyun  exit:
419*4882a593Smuzhiyun 	preempt_enable();
420*4882a593Smuzhiyun }
421*4882a593Smuzhiyun 
vfp_enable(void * unused)422*4882a593Smuzhiyun static void vfp_enable(void *unused)
423*4882a593Smuzhiyun {
424*4882a593Smuzhiyun 	u32 access;
425*4882a593Smuzhiyun 
426*4882a593Smuzhiyun 	BUG_ON(preemptible());
427*4882a593Smuzhiyun 	access = get_copro_access();
428*4882a593Smuzhiyun 
429*4882a593Smuzhiyun 	/*
430*4882a593Smuzhiyun 	 * Enable full access to VFP (cp10 and cp11)
431*4882a593Smuzhiyun 	 */
432*4882a593Smuzhiyun 	set_copro_access(access | CPACC_FULL(10) | CPACC_FULL(11));
433*4882a593Smuzhiyun }
434*4882a593Smuzhiyun 
435*4882a593Smuzhiyun /* Called by platforms on which we want to disable VFP because it may not be
436*4882a593Smuzhiyun  * present on all CPUs within a SMP complex. Needs to be called prior to
437*4882a593Smuzhiyun  * vfp_init().
438*4882a593Smuzhiyun  */
vfp_disable(void)439*4882a593Smuzhiyun void __init vfp_disable(void)
440*4882a593Smuzhiyun {
441*4882a593Smuzhiyun 	if (VFP_arch) {
442*4882a593Smuzhiyun 		pr_debug("%s: should be called prior to vfp_init\n", __func__);
443*4882a593Smuzhiyun 		return;
444*4882a593Smuzhiyun 	}
445*4882a593Smuzhiyun 	VFP_arch = 1;
446*4882a593Smuzhiyun }
447*4882a593Smuzhiyun 
448*4882a593Smuzhiyun #ifdef CONFIG_CPU_PM
vfp_pm_suspend(void)449*4882a593Smuzhiyun static int vfp_pm_suspend(void)
450*4882a593Smuzhiyun {
451*4882a593Smuzhiyun 	struct thread_info *ti = current_thread_info();
452*4882a593Smuzhiyun 	u32 fpexc = fmrx(FPEXC);
453*4882a593Smuzhiyun 
454*4882a593Smuzhiyun 	/* if vfp is on, then save state for resumption */
455*4882a593Smuzhiyun 	if (fpexc & FPEXC_EN) {
456*4882a593Smuzhiyun 		pr_debug("%s: saving vfp state\n", __func__);
457*4882a593Smuzhiyun 		vfp_save_state(&ti->vfpstate, fpexc);
458*4882a593Smuzhiyun 
459*4882a593Smuzhiyun 		/* disable, just in case */
460*4882a593Smuzhiyun 		fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_EN);
461*4882a593Smuzhiyun 	} else if (vfp_current_hw_state[ti->cpu]) {
462*4882a593Smuzhiyun #ifndef CONFIG_SMP
463*4882a593Smuzhiyun 		fmxr(FPEXC, fpexc | FPEXC_EN);
464*4882a593Smuzhiyun 		vfp_save_state(vfp_current_hw_state[ti->cpu], fpexc);
465*4882a593Smuzhiyun 		fmxr(FPEXC, fpexc);
466*4882a593Smuzhiyun #endif
467*4882a593Smuzhiyun 	}
468*4882a593Smuzhiyun 
469*4882a593Smuzhiyun 	/* clear any information we had about last context state */
470*4882a593Smuzhiyun 	vfp_current_hw_state[ti->cpu] = NULL;
471*4882a593Smuzhiyun 
472*4882a593Smuzhiyun 	return 0;
473*4882a593Smuzhiyun }
474*4882a593Smuzhiyun 
vfp_pm_resume(void)475*4882a593Smuzhiyun static void vfp_pm_resume(void)
476*4882a593Smuzhiyun {
477*4882a593Smuzhiyun 	/* ensure we have access to the vfp */
478*4882a593Smuzhiyun 	vfp_enable(NULL);
479*4882a593Smuzhiyun 
480*4882a593Smuzhiyun 	/* and disable it to ensure the next usage restores the state */
481*4882a593Smuzhiyun 	fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_EN);
482*4882a593Smuzhiyun }
483*4882a593Smuzhiyun 
vfp_cpu_pm_notifier(struct notifier_block * self,unsigned long cmd,void * v)484*4882a593Smuzhiyun static int vfp_cpu_pm_notifier(struct notifier_block *self, unsigned long cmd,
485*4882a593Smuzhiyun 	void *v)
486*4882a593Smuzhiyun {
487*4882a593Smuzhiyun 	switch (cmd) {
488*4882a593Smuzhiyun 	case CPU_PM_ENTER:
489*4882a593Smuzhiyun 		vfp_pm_suspend();
490*4882a593Smuzhiyun 		break;
491*4882a593Smuzhiyun 	case CPU_PM_ENTER_FAILED:
492*4882a593Smuzhiyun 	case CPU_PM_EXIT:
493*4882a593Smuzhiyun 		vfp_pm_resume();
494*4882a593Smuzhiyun 		break;
495*4882a593Smuzhiyun 	}
496*4882a593Smuzhiyun 	return NOTIFY_OK;
497*4882a593Smuzhiyun }
498*4882a593Smuzhiyun 
499*4882a593Smuzhiyun static struct notifier_block vfp_cpu_pm_notifier_block = {
500*4882a593Smuzhiyun 	.notifier_call = vfp_cpu_pm_notifier,
501*4882a593Smuzhiyun };
502*4882a593Smuzhiyun 
vfp_pm_init(void)503*4882a593Smuzhiyun static void vfp_pm_init(void)
504*4882a593Smuzhiyun {
505*4882a593Smuzhiyun 	cpu_pm_register_notifier(&vfp_cpu_pm_notifier_block);
506*4882a593Smuzhiyun }
507*4882a593Smuzhiyun 
508*4882a593Smuzhiyun #else
vfp_pm_init(void)509*4882a593Smuzhiyun static inline void vfp_pm_init(void) { }
510*4882a593Smuzhiyun #endif /* CONFIG_CPU_PM */
511*4882a593Smuzhiyun 
512*4882a593Smuzhiyun /*
513*4882a593Smuzhiyun  * Ensure that the VFP state stored in 'thread->vfpstate' is up to date
514*4882a593Smuzhiyun  * with the hardware state.
515*4882a593Smuzhiyun  */
vfp_sync_hwstate(struct thread_info * thread)516*4882a593Smuzhiyun void vfp_sync_hwstate(struct thread_info *thread)
517*4882a593Smuzhiyun {
518*4882a593Smuzhiyun 	unsigned int cpu = get_cpu();
519*4882a593Smuzhiyun 
520*4882a593Smuzhiyun 	if (vfp_state_in_hw(cpu, thread)) {
521*4882a593Smuzhiyun 		u32 fpexc = fmrx(FPEXC);
522*4882a593Smuzhiyun 
523*4882a593Smuzhiyun 		/*
524*4882a593Smuzhiyun 		 * Save the last VFP state on this CPU.
525*4882a593Smuzhiyun 		 */
526*4882a593Smuzhiyun 		fmxr(FPEXC, fpexc | FPEXC_EN);
527*4882a593Smuzhiyun 		vfp_save_state(&thread->vfpstate, fpexc | FPEXC_EN);
528*4882a593Smuzhiyun 		fmxr(FPEXC, fpexc);
529*4882a593Smuzhiyun 	}
530*4882a593Smuzhiyun 
531*4882a593Smuzhiyun 	put_cpu();
532*4882a593Smuzhiyun }
533*4882a593Smuzhiyun 
534*4882a593Smuzhiyun /* Ensure that the thread reloads the hardware VFP state on the next use. */
vfp_flush_hwstate(struct thread_info * thread)535*4882a593Smuzhiyun void vfp_flush_hwstate(struct thread_info *thread)
536*4882a593Smuzhiyun {
537*4882a593Smuzhiyun 	unsigned int cpu = get_cpu();
538*4882a593Smuzhiyun 
539*4882a593Smuzhiyun 	vfp_force_reload(cpu, thread);
540*4882a593Smuzhiyun 
541*4882a593Smuzhiyun 	put_cpu();
542*4882a593Smuzhiyun }
543*4882a593Smuzhiyun 
544*4882a593Smuzhiyun /*
545*4882a593Smuzhiyun  * Save the current VFP state into the provided structures and prepare
546*4882a593Smuzhiyun  * for entry into a new function (signal handler).
547*4882a593Smuzhiyun  */
vfp_preserve_user_clear_hwstate(struct user_vfp * ufp,struct user_vfp_exc * ufp_exc)548*4882a593Smuzhiyun int vfp_preserve_user_clear_hwstate(struct user_vfp *ufp,
549*4882a593Smuzhiyun 				    struct user_vfp_exc *ufp_exc)
550*4882a593Smuzhiyun {
551*4882a593Smuzhiyun 	struct thread_info *thread = current_thread_info();
552*4882a593Smuzhiyun 	struct vfp_hard_struct *hwstate = &thread->vfpstate.hard;
553*4882a593Smuzhiyun 
554*4882a593Smuzhiyun 	/* Ensure that the saved hwstate is up-to-date. */
555*4882a593Smuzhiyun 	vfp_sync_hwstate(thread);
556*4882a593Smuzhiyun 
557*4882a593Smuzhiyun 	/*
558*4882a593Smuzhiyun 	 * Copy the floating point registers. There can be unused
559*4882a593Smuzhiyun 	 * registers see asm/hwcap.h for details.
560*4882a593Smuzhiyun 	 */
561*4882a593Smuzhiyun 	memcpy(&ufp->fpregs, &hwstate->fpregs, sizeof(hwstate->fpregs));
562*4882a593Smuzhiyun 
563*4882a593Smuzhiyun 	/*
564*4882a593Smuzhiyun 	 * Copy the status and control register.
565*4882a593Smuzhiyun 	 */
566*4882a593Smuzhiyun 	ufp->fpscr = hwstate->fpscr;
567*4882a593Smuzhiyun 
568*4882a593Smuzhiyun 	/*
569*4882a593Smuzhiyun 	 * Copy the exception registers.
570*4882a593Smuzhiyun 	 */
571*4882a593Smuzhiyun 	ufp_exc->fpexc = hwstate->fpexc;
572*4882a593Smuzhiyun 	ufp_exc->fpinst = hwstate->fpinst;
573*4882a593Smuzhiyun 	ufp_exc->fpinst2 = hwstate->fpinst2;
574*4882a593Smuzhiyun 
575*4882a593Smuzhiyun 	/* Ensure that VFP is disabled. */
576*4882a593Smuzhiyun 	vfp_flush_hwstate(thread);
577*4882a593Smuzhiyun 
578*4882a593Smuzhiyun 	/*
579*4882a593Smuzhiyun 	 * As per the PCS, clear the length and stride bits for function
580*4882a593Smuzhiyun 	 * entry.
581*4882a593Smuzhiyun 	 */
582*4882a593Smuzhiyun 	hwstate->fpscr &= ~(FPSCR_LENGTH_MASK | FPSCR_STRIDE_MASK);
583*4882a593Smuzhiyun 	return 0;
584*4882a593Smuzhiyun }
585*4882a593Smuzhiyun 
586*4882a593Smuzhiyun /* Sanitise and restore the current VFP state from the provided structures. */
vfp_restore_user_hwstate(struct user_vfp * ufp,struct user_vfp_exc * ufp_exc)587*4882a593Smuzhiyun int vfp_restore_user_hwstate(struct user_vfp *ufp, struct user_vfp_exc *ufp_exc)
588*4882a593Smuzhiyun {
589*4882a593Smuzhiyun 	struct thread_info *thread = current_thread_info();
590*4882a593Smuzhiyun 	struct vfp_hard_struct *hwstate = &thread->vfpstate.hard;
591*4882a593Smuzhiyun 	unsigned long fpexc;
592*4882a593Smuzhiyun 
593*4882a593Smuzhiyun 	/* Disable VFP to avoid corrupting the new thread state. */
594*4882a593Smuzhiyun 	vfp_flush_hwstate(thread);
595*4882a593Smuzhiyun 
596*4882a593Smuzhiyun 	/*
597*4882a593Smuzhiyun 	 * Copy the floating point registers. There can be unused
598*4882a593Smuzhiyun 	 * registers see asm/hwcap.h for details.
599*4882a593Smuzhiyun 	 */
600*4882a593Smuzhiyun 	memcpy(&hwstate->fpregs, &ufp->fpregs, sizeof(hwstate->fpregs));
601*4882a593Smuzhiyun 	/*
602*4882a593Smuzhiyun 	 * Copy the status and control register.
603*4882a593Smuzhiyun 	 */
604*4882a593Smuzhiyun 	hwstate->fpscr = ufp->fpscr;
605*4882a593Smuzhiyun 
606*4882a593Smuzhiyun 	/*
607*4882a593Smuzhiyun 	 * Sanitise and restore the exception registers.
608*4882a593Smuzhiyun 	 */
609*4882a593Smuzhiyun 	fpexc = ufp_exc->fpexc;
610*4882a593Smuzhiyun 
611*4882a593Smuzhiyun 	/* Ensure the VFP is enabled. */
612*4882a593Smuzhiyun 	fpexc |= FPEXC_EN;
613*4882a593Smuzhiyun 
614*4882a593Smuzhiyun 	/* Ensure FPINST2 is invalid and the exception flag is cleared. */
615*4882a593Smuzhiyun 	fpexc &= ~(FPEXC_EX | FPEXC_FP2V);
616*4882a593Smuzhiyun 	hwstate->fpexc = fpexc;
617*4882a593Smuzhiyun 
618*4882a593Smuzhiyun 	hwstate->fpinst = ufp_exc->fpinst;
619*4882a593Smuzhiyun 	hwstate->fpinst2 = ufp_exc->fpinst2;
620*4882a593Smuzhiyun 
621*4882a593Smuzhiyun 	return 0;
622*4882a593Smuzhiyun }
623*4882a593Smuzhiyun 
624*4882a593Smuzhiyun /*
625*4882a593Smuzhiyun  * VFP hardware can lose all context when a CPU goes offline.
626*4882a593Smuzhiyun  * As we will be running in SMP mode with CPU hotplug, we will save the
627*4882a593Smuzhiyun  * hardware state at every thread switch.  We clear our held state when
628*4882a593Smuzhiyun  * a CPU has been killed, indicating that the VFP hardware doesn't contain
629*4882a593Smuzhiyun  * a threads VFP state.  When a CPU starts up, we re-enable access to the
630*4882a593Smuzhiyun  * VFP hardware. The callbacks below are called on the CPU which
631*4882a593Smuzhiyun  * is being offlined/onlined.
632*4882a593Smuzhiyun  */
vfp_dying_cpu(unsigned int cpu)633*4882a593Smuzhiyun static int vfp_dying_cpu(unsigned int cpu)
634*4882a593Smuzhiyun {
635*4882a593Smuzhiyun 	vfp_current_hw_state[cpu] = NULL;
636*4882a593Smuzhiyun 	return 0;
637*4882a593Smuzhiyun }
638*4882a593Smuzhiyun 
vfp_starting_cpu(unsigned int unused)639*4882a593Smuzhiyun static int vfp_starting_cpu(unsigned int unused)
640*4882a593Smuzhiyun {
641*4882a593Smuzhiyun 	vfp_enable(NULL);
642*4882a593Smuzhiyun 	return 0;
643*4882a593Smuzhiyun }
644*4882a593Smuzhiyun 
645*4882a593Smuzhiyun #ifdef CONFIG_KERNEL_MODE_NEON
646*4882a593Smuzhiyun 
vfp_kmode_exception(struct pt_regs * regs,unsigned int instr)647*4882a593Smuzhiyun static int vfp_kmode_exception(struct pt_regs *regs, unsigned int instr)
648*4882a593Smuzhiyun {
649*4882a593Smuzhiyun 	/*
650*4882a593Smuzhiyun 	 * If we reach this point, a floating point exception has been raised
651*4882a593Smuzhiyun 	 * while running in kernel mode. If the NEON/VFP unit was enabled at the
652*4882a593Smuzhiyun 	 * time, it means a VFP instruction has been issued that requires
653*4882a593Smuzhiyun 	 * software assistance to complete, something which is not currently
654*4882a593Smuzhiyun 	 * supported in kernel mode.
655*4882a593Smuzhiyun 	 * If the NEON/VFP unit was disabled, and the location pointed to below
656*4882a593Smuzhiyun 	 * is properly preceded by a call to kernel_neon_begin(), something has
657*4882a593Smuzhiyun 	 * caused the task to be scheduled out and back in again. In this case,
658*4882a593Smuzhiyun 	 * rebuilding and running with CONFIG_DEBUG_ATOMIC_SLEEP enabled should
659*4882a593Smuzhiyun 	 * be helpful in localizing the problem.
660*4882a593Smuzhiyun 	 */
661*4882a593Smuzhiyun 	if (fmrx(FPEXC) & FPEXC_EN)
662*4882a593Smuzhiyun 		pr_crit("BUG: unsupported FP instruction in kernel mode\n");
663*4882a593Smuzhiyun 	else
664*4882a593Smuzhiyun 		pr_crit("BUG: FP instruction issued in kernel mode with FP unit disabled\n");
665*4882a593Smuzhiyun 	pr_crit("FPEXC == 0x%08x\n", fmrx(FPEXC));
666*4882a593Smuzhiyun 	return 1;
667*4882a593Smuzhiyun }
668*4882a593Smuzhiyun 
669*4882a593Smuzhiyun static struct undef_hook vfp_kmode_exception_hook[] = {{
670*4882a593Smuzhiyun 	.instr_mask	= 0xfe000000,
671*4882a593Smuzhiyun 	.instr_val	= 0xf2000000,
672*4882a593Smuzhiyun 	.cpsr_mask	= MODE_MASK | PSR_T_BIT,
673*4882a593Smuzhiyun 	.cpsr_val	= SVC_MODE,
674*4882a593Smuzhiyun 	.fn		= vfp_kmode_exception,
675*4882a593Smuzhiyun }, {
676*4882a593Smuzhiyun 	.instr_mask	= 0xff100000,
677*4882a593Smuzhiyun 	.instr_val	= 0xf4000000,
678*4882a593Smuzhiyun 	.cpsr_mask	= MODE_MASK | PSR_T_BIT,
679*4882a593Smuzhiyun 	.cpsr_val	= SVC_MODE,
680*4882a593Smuzhiyun 	.fn		= vfp_kmode_exception,
681*4882a593Smuzhiyun }, {
682*4882a593Smuzhiyun 	.instr_mask	= 0xef000000,
683*4882a593Smuzhiyun 	.instr_val	= 0xef000000,
684*4882a593Smuzhiyun 	.cpsr_mask	= MODE_MASK | PSR_T_BIT,
685*4882a593Smuzhiyun 	.cpsr_val	= SVC_MODE | PSR_T_BIT,
686*4882a593Smuzhiyun 	.fn		= vfp_kmode_exception,
687*4882a593Smuzhiyun }, {
688*4882a593Smuzhiyun 	.instr_mask	= 0xff100000,
689*4882a593Smuzhiyun 	.instr_val	= 0xf9000000,
690*4882a593Smuzhiyun 	.cpsr_mask	= MODE_MASK | PSR_T_BIT,
691*4882a593Smuzhiyun 	.cpsr_val	= SVC_MODE | PSR_T_BIT,
692*4882a593Smuzhiyun 	.fn		= vfp_kmode_exception,
693*4882a593Smuzhiyun }, {
694*4882a593Smuzhiyun 	.instr_mask	= 0x0c000e00,
695*4882a593Smuzhiyun 	.instr_val	= 0x0c000a00,
696*4882a593Smuzhiyun 	.cpsr_mask	= MODE_MASK,
697*4882a593Smuzhiyun 	.cpsr_val	= SVC_MODE,
698*4882a593Smuzhiyun 	.fn		= vfp_kmode_exception,
699*4882a593Smuzhiyun }};
700*4882a593Smuzhiyun 
vfp_kmode_exception_hook_init(void)701*4882a593Smuzhiyun static int __init vfp_kmode_exception_hook_init(void)
702*4882a593Smuzhiyun {
703*4882a593Smuzhiyun 	int i;
704*4882a593Smuzhiyun 
705*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(vfp_kmode_exception_hook); i++)
706*4882a593Smuzhiyun 		register_undef_hook(&vfp_kmode_exception_hook[i]);
707*4882a593Smuzhiyun 	return 0;
708*4882a593Smuzhiyun }
709*4882a593Smuzhiyun subsys_initcall(vfp_kmode_exception_hook_init);
710*4882a593Smuzhiyun 
711*4882a593Smuzhiyun /*
712*4882a593Smuzhiyun  * Kernel-side NEON support functions
713*4882a593Smuzhiyun  */
kernel_neon_begin(void)714*4882a593Smuzhiyun void kernel_neon_begin(void)
715*4882a593Smuzhiyun {
716*4882a593Smuzhiyun 	struct thread_info *thread = current_thread_info();
717*4882a593Smuzhiyun 	unsigned int cpu;
718*4882a593Smuzhiyun 	u32 fpexc;
719*4882a593Smuzhiyun 
720*4882a593Smuzhiyun 	/*
721*4882a593Smuzhiyun 	 * Kernel mode NEON is only allowed outside of interrupt context
722*4882a593Smuzhiyun 	 * with preemption disabled. This will make sure that the kernel
723*4882a593Smuzhiyun 	 * mode NEON register contents never need to be preserved.
724*4882a593Smuzhiyun 	 */
725*4882a593Smuzhiyun 	BUG_ON(in_interrupt());
726*4882a593Smuzhiyun 	cpu = get_cpu();
727*4882a593Smuzhiyun 
728*4882a593Smuzhiyun 	fpexc = fmrx(FPEXC) | FPEXC_EN;
729*4882a593Smuzhiyun 	fmxr(FPEXC, fpexc);
730*4882a593Smuzhiyun 
731*4882a593Smuzhiyun 	/*
732*4882a593Smuzhiyun 	 * Save the userland NEON/VFP state. Under UP,
733*4882a593Smuzhiyun 	 * the owner could be a task other than 'current'
734*4882a593Smuzhiyun 	 */
735*4882a593Smuzhiyun 	if (vfp_state_in_hw(cpu, thread))
736*4882a593Smuzhiyun 		vfp_save_state(&thread->vfpstate, fpexc);
737*4882a593Smuzhiyun #ifndef CONFIG_SMP
738*4882a593Smuzhiyun 	else if (vfp_current_hw_state[cpu] != NULL)
739*4882a593Smuzhiyun 		vfp_save_state(vfp_current_hw_state[cpu], fpexc);
740*4882a593Smuzhiyun #endif
741*4882a593Smuzhiyun 	vfp_current_hw_state[cpu] = NULL;
742*4882a593Smuzhiyun }
743*4882a593Smuzhiyun EXPORT_SYMBOL(kernel_neon_begin);
744*4882a593Smuzhiyun 
kernel_neon_end(void)745*4882a593Smuzhiyun void kernel_neon_end(void)
746*4882a593Smuzhiyun {
747*4882a593Smuzhiyun 	/* Disable the NEON/VFP unit. */
748*4882a593Smuzhiyun 	fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_EN);
749*4882a593Smuzhiyun 	put_cpu();
750*4882a593Smuzhiyun }
751*4882a593Smuzhiyun EXPORT_SYMBOL(kernel_neon_end);
752*4882a593Smuzhiyun 
753*4882a593Smuzhiyun #endif /* CONFIG_KERNEL_MODE_NEON */
754*4882a593Smuzhiyun 
vfp_detect(struct pt_regs * regs,unsigned int instr)755*4882a593Smuzhiyun static int __init vfp_detect(struct pt_regs *regs, unsigned int instr)
756*4882a593Smuzhiyun {
757*4882a593Smuzhiyun 	VFP_arch = UINT_MAX;	/* mark as not present */
758*4882a593Smuzhiyun 	regs->ARM_pc += 4;
759*4882a593Smuzhiyun 	return 0;
760*4882a593Smuzhiyun }
761*4882a593Smuzhiyun 
762*4882a593Smuzhiyun static struct undef_hook vfp_detect_hook __initdata = {
763*4882a593Smuzhiyun 	.instr_mask	= 0x0c000e00,
764*4882a593Smuzhiyun 	.instr_val	= 0x0c000a00,
765*4882a593Smuzhiyun 	.cpsr_mask	= MODE_MASK,
766*4882a593Smuzhiyun 	.cpsr_val	= SVC_MODE,
767*4882a593Smuzhiyun 	.fn		= vfp_detect,
768*4882a593Smuzhiyun };
769*4882a593Smuzhiyun 
770*4882a593Smuzhiyun /*
771*4882a593Smuzhiyun  * VFP support code initialisation.
772*4882a593Smuzhiyun  */
vfp_init(void)773*4882a593Smuzhiyun static int __init vfp_init(void)
774*4882a593Smuzhiyun {
775*4882a593Smuzhiyun 	unsigned int vfpsid;
776*4882a593Smuzhiyun 	unsigned int cpu_arch = cpu_architecture();
777*4882a593Smuzhiyun 
778*4882a593Smuzhiyun 	/*
779*4882a593Smuzhiyun 	 * Enable the access to the VFP on all online CPUs so the
780*4882a593Smuzhiyun 	 * following test on FPSID will succeed.
781*4882a593Smuzhiyun 	 */
782*4882a593Smuzhiyun 	if (cpu_arch >= CPU_ARCH_ARMv6)
783*4882a593Smuzhiyun 		on_each_cpu(vfp_enable, NULL, 1);
784*4882a593Smuzhiyun 
785*4882a593Smuzhiyun 	/*
786*4882a593Smuzhiyun 	 * First check that there is a VFP that we can use.
787*4882a593Smuzhiyun 	 * The handler is already setup to just log calls, so
788*4882a593Smuzhiyun 	 * we just need to read the VFPSID register.
789*4882a593Smuzhiyun 	 */
790*4882a593Smuzhiyun 	register_undef_hook(&vfp_detect_hook);
791*4882a593Smuzhiyun 	barrier();
792*4882a593Smuzhiyun 	vfpsid = fmrx(FPSID);
793*4882a593Smuzhiyun 	barrier();
794*4882a593Smuzhiyun 	unregister_undef_hook(&vfp_detect_hook);
795*4882a593Smuzhiyun 	vfp_vector = vfp_null_entry;
796*4882a593Smuzhiyun 
797*4882a593Smuzhiyun 	pr_info("VFP support v0.3: ");
798*4882a593Smuzhiyun 	if (VFP_arch) {
799*4882a593Smuzhiyun 		pr_cont("not present\n");
800*4882a593Smuzhiyun 		return 0;
801*4882a593Smuzhiyun 	/* Extract the architecture on CPUID scheme */
802*4882a593Smuzhiyun 	} else if ((read_cpuid_id() & 0x000f0000) == 0x000f0000) {
803*4882a593Smuzhiyun 		VFP_arch = vfpsid & FPSID_CPUID_ARCH_MASK;
804*4882a593Smuzhiyun 		VFP_arch >>= FPSID_ARCH_BIT;
805*4882a593Smuzhiyun 		/*
806*4882a593Smuzhiyun 		 * Check for the presence of the Advanced SIMD
807*4882a593Smuzhiyun 		 * load/store instructions, integer and single
808*4882a593Smuzhiyun 		 * precision floating point operations. Only check
809*4882a593Smuzhiyun 		 * for NEON if the hardware has the MVFR registers.
810*4882a593Smuzhiyun 		 */
811*4882a593Smuzhiyun 		if (IS_ENABLED(CONFIG_NEON) &&
812*4882a593Smuzhiyun 		   (fmrx(MVFR1) & 0x000fff00) == 0x00011100)
813*4882a593Smuzhiyun 			elf_hwcap |= HWCAP_NEON;
814*4882a593Smuzhiyun 
815*4882a593Smuzhiyun 		if (IS_ENABLED(CONFIG_VFPv3)) {
816*4882a593Smuzhiyun 			u32 mvfr0 = fmrx(MVFR0);
817*4882a593Smuzhiyun 			if (((mvfr0 & MVFR0_DP_MASK) >> MVFR0_DP_BIT) == 0x2 ||
818*4882a593Smuzhiyun 			    ((mvfr0 & MVFR0_SP_MASK) >> MVFR0_SP_BIT) == 0x2) {
819*4882a593Smuzhiyun 				elf_hwcap |= HWCAP_VFPv3;
820*4882a593Smuzhiyun 				/*
821*4882a593Smuzhiyun 				 * Check for VFPv3 D16 and VFPv4 D16.  CPUs in
822*4882a593Smuzhiyun 				 * this configuration only have 16 x 64bit
823*4882a593Smuzhiyun 				 * registers.
824*4882a593Smuzhiyun 				 */
825*4882a593Smuzhiyun 				if ((mvfr0 & MVFR0_A_SIMD_MASK) == 1)
826*4882a593Smuzhiyun 					/* also v4-D16 */
827*4882a593Smuzhiyun 					elf_hwcap |= HWCAP_VFPv3D16;
828*4882a593Smuzhiyun 				else
829*4882a593Smuzhiyun 					elf_hwcap |= HWCAP_VFPD32;
830*4882a593Smuzhiyun 			}
831*4882a593Smuzhiyun 
832*4882a593Smuzhiyun 			if ((fmrx(MVFR1) & 0xf0000000) == 0x10000000)
833*4882a593Smuzhiyun 				elf_hwcap |= HWCAP_VFPv4;
834*4882a593Smuzhiyun 		}
835*4882a593Smuzhiyun 	/* Extract the architecture version on pre-cpuid scheme */
836*4882a593Smuzhiyun 	} else {
837*4882a593Smuzhiyun 		if (vfpsid & FPSID_NODOUBLE) {
838*4882a593Smuzhiyun 			pr_cont("no double precision support\n");
839*4882a593Smuzhiyun 			return 0;
840*4882a593Smuzhiyun 		}
841*4882a593Smuzhiyun 
842*4882a593Smuzhiyun 		VFP_arch = (vfpsid & FPSID_ARCH_MASK) >> FPSID_ARCH_BIT;
843*4882a593Smuzhiyun 	}
844*4882a593Smuzhiyun 
845*4882a593Smuzhiyun 	cpuhp_setup_state_nocalls(CPUHP_AP_ARM_VFP_STARTING,
846*4882a593Smuzhiyun 				  "arm/vfp:starting", vfp_starting_cpu,
847*4882a593Smuzhiyun 				  vfp_dying_cpu);
848*4882a593Smuzhiyun 
849*4882a593Smuzhiyun 	vfp_vector = vfp_support_entry;
850*4882a593Smuzhiyun 
851*4882a593Smuzhiyun 	thread_register_notifier(&vfp_notifier_block);
852*4882a593Smuzhiyun 	vfp_pm_init();
853*4882a593Smuzhiyun 
854*4882a593Smuzhiyun 	/*
855*4882a593Smuzhiyun 	 * We detected VFP, and the support code is
856*4882a593Smuzhiyun 	 * in place; report VFP support to userspace.
857*4882a593Smuzhiyun 	 */
858*4882a593Smuzhiyun 	elf_hwcap |= HWCAP_VFP;
859*4882a593Smuzhiyun 
860*4882a593Smuzhiyun 	pr_cont("implementor %02x architecture %d part %02x variant %x rev %x\n",
861*4882a593Smuzhiyun 		(vfpsid & FPSID_IMPLEMENTER_MASK) >> FPSID_IMPLEMENTER_BIT,
862*4882a593Smuzhiyun 		VFP_arch,
863*4882a593Smuzhiyun 		(vfpsid & FPSID_PART_MASK) >> FPSID_PART_BIT,
864*4882a593Smuzhiyun 		(vfpsid & FPSID_VARIANT_MASK) >> FPSID_VARIANT_BIT,
865*4882a593Smuzhiyun 		(vfpsid & FPSID_REV_MASK) >> FPSID_REV_BIT);
866*4882a593Smuzhiyun 
867*4882a593Smuzhiyun 	return 0;
868*4882a593Smuzhiyun }
869*4882a593Smuzhiyun 
870*4882a593Smuzhiyun core_initcall(vfp_init);
871