aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGreg Ungerer <gerg@uclinux.org>2011-10-19 00:10:03 -0400
committerGreg Ungerer <gerg@uclinux.org>2011-12-29 19:20:47 -0500
commit0a2796da1182a7dcfba41f796f45986237bc1688 (patch)
treef3a09049fd2f554241ede9e2c2d8a979ffe1e730
parente9fcffa49376b37518baf71a47adc15e74b2434c (diff)
m68k: add ColdFire FPU support for the V4e ColdFire CPUs
The V4e ColdFire CPU family also has an integrated FPU (as well as the MMU). So add code to support this hardware along side the existing m68k FPU code. The ColdFire FPU is of course different to all previous 68k FP units. It is close in operation to the 68060, but not completely compatible. The biggest issue to deal with is that the ColdFire FPU multi-move instructions are different. It does not support multi-moving the FP control registers, and the multi-move of the FP data registers uses a different instruction mnemonic. Signed-off-by: Greg Ungerer <gerg@uclinux.org> Acked-by: Matt Waddel <mwaddel@yahoo.com> Acked-by: Kurt Mahan <kmahan@xmission.com>
-rw-r--r--arch/m68k/include/asm/fpu.h2
-rw-r--r--arch/m68k/kernel/process_mm.c59
-rw-r--r--arch/m68k/kernel/setup_mm.c2
-rw-r--r--arch/m68k/kernel/signal_mm.c187
4 files changed, 184 insertions, 66 deletions
diff --git a/arch/m68k/include/asm/fpu.h b/arch/m68k/include/asm/fpu.h
index ffb6b8cfc6d5..526db9da9e43 100644
--- a/arch/m68k/include/asm/fpu.h
+++ b/arch/m68k/include/asm/fpu.h
@@ -12,6 +12,8 @@
12#define FPSTATESIZE (96) 12#define FPSTATESIZE (96)
13#elif defined(CONFIG_M68KFPU_EMU) 13#elif defined(CONFIG_M68KFPU_EMU)
14#define FPSTATESIZE (28) 14#define FPSTATESIZE (28)
15#elif defined(CONFIG_COLDFIRE) && defined(CONFIG_MMU)
16#define FPSTATESIZE (16)
15#elif defined(CONFIG_M68060) 17#elif defined(CONFIG_M68060)
16#define FPSTATESIZE (12) 18#define FPSTATESIZE (12)
17#else 19#else
diff --git a/arch/m68k/kernel/process_mm.c b/arch/m68k/kernel/process_mm.c
index 58a3253f3eb9..125f34e00bf0 100644
--- a/arch/m68k/kernel/process_mm.c
+++ b/arch/m68k/kernel/process_mm.c
@@ -172,9 +172,7 @@ void flush_thread(void)
172 172
173 current->thread.fs = __USER_DS; 173 current->thread.fs = __USER_DS;
174 if (!FPU_IS_EMU) 174 if (!FPU_IS_EMU)
175 asm volatile (".chip 68k/68881\n\t" 175 asm volatile ("frestore %0@" : : "a" (&zero) : "memory");
176 "frestore %0@\n\t"
177 ".chip 68k" : : "a" (&zero));
178} 176}
179 177
180/* 178/*
@@ -248,11 +246,28 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
248 /* Copy the current fpu state */ 246 /* Copy the current fpu state */
249 asm volatile ("fsave %0" : : "m" (p->thread.fpstate[0]) : "memory"); 247 asm volatile ("fsave %0" : : "m" (p->thread.fpstate[0]) : "memory");
250 248
251 if (!CPU_IS_060 ? p->thread.fpstate[0] : p->thread.fpstate[2]) 249 if (!CPU_IS_060 ? p->thread.fpstate[0] : p->thread.fpstate[2]) {
252 asm volatile ("fmovemx %/fp0-%/fp7,%0\n\t" 250 if (CPU_IS_COLDFIRE) {
253 "fmoveml %/fpiar/%/fpcr/%/fpsr,%1" 251 asm volatile ("fmovemd %/fp0-%/fp7,%0\n\t"
254 : : "m" (p->thread.fp[0]), "m" (p->thread.fpcntl[0]) 252 "fmovel %/fpiar,%1\n\t"
255 : "memory"); 253 "fmovel %/fpcr,%2\n\t"
254 "fmovel %/fpsr,%3"
255 :
256 : "m" (p->thread.fp[0]),
257 "m" (p->thread.fpcntl[0]),
258 "m" (p->thread.fpcntl[1]),
259 "m" (p->thread.fpcntl[2])
260 : "memory");
261 } else {
262 asm volatile ("fmovemx %/fp0-%/fp7,%0\n\t"
263 "fmoveml %/fpiar/%/fpcr/%/fpsr,%1"
264 :
265 : "m" (p->thread.fp[0]),
266 "m" (p->thread.fpcntl[0])
267 : "memory");
268 }
269 }
270
256 /* Restore the state in case the fpu was busy */ 271 /* Restore the state in case the fpu was busy */
257 asm volatile ("frestore %0" : : "m" (p->thread.fpstate[0])); 272 asm volatile ("frestore %0" : : "m" (p->thread.fpstate[0]));
258 } 273 }
@@ -285,12 +300,28 @@ int dump_fpu (struct pt_regs *regs, struct user_m68kfp_struct *fpu)
285 if (!CPU_IS_060 ? !fpustate[0] : !fpustate[2]) 300 if (!CPU_IS_060 ? !fpustate[0] : !fpustate[2])
286 return 0; 301 return 0;
287 302
288 asm volatile ("fmovem %/fpiar/%/fpcr/%/fpsr,%0" 303 if (CPU_IS_COLDFIRE) {
289 :: "m" (fpu->fpcntl[0]) 304 asm volatile ("fmovel %/fpiar,%0\n\t"
290 : "memory"); 305 "fmovel %/fpcr,%1\n\t"
291 asm volatile ("fmovemx %/fp0-%/fp7,%0" 306 "fmovel %/fpsr,%2\n\t"
292 :: "m" (fpu->fpregs[0]) 307 "fmovemd %/fp0-%/fp7,%3"
293 : "memory"); 308 :
309 : "m" (fpu->fpcntl[0]),
310 "m" (fpu->fpcntl[1]),
311 "m" (fpu->fpcntl[2]),
312 "m" (fpu->fpregs[0])
313 : "memory");
314 } else {
315 asm volatile ("fmovem %/fpiar/%/fpcr/%/fpsr,%0"
316 :
317 : "m" (fpu->fpcntl[0])
318 : "memory");
319 asm volatile ("fmovemx %/fp0-%/fp7,%0"
320 :
321 : "m" (fpu->fpregs[0])
322 : "memory");
323 }
324
294 return 1; 325 return 1;
295} 326}
296EXPORT_SYMBOL(dump_fpu); 327EXPORT_SYMBOL(dump_fpu);
diff --git a/arch/m68k/kernel/setup_mm.c b/arch/m68k/kernel/setup_mm.c
index b3938adeabea..d872ce4807c9 100644
--- a/arch/m68k/kernel/setup_mm.c
+++ b/arch/m68k/kernel/setup_mm.c
@@ -236,7 +236,7 @@ void __init setup_arch(char **cmdline_p)
236 * with them, we should add a test to check_bugs() below] */ 236 * with them, we should add a test to check_bugs() below] */
237#ifndef CONFIG_M68KFPU_EMU_ONLY 237#ifndef CONFIG_M68KFPU_EMU_ONLY
238 /* clear the fpu if we have one */ 238 /* clear the fpu if we have one */
239 if (m68k_fputype & (FPU_68881|FPU_68882|FPU_68040|FPU_68060)) { 239 if (m68k_fputype & (FPU_68881|FPU_68882|FPU_68040|FPU_68060|FPU_COLDFIRE)) {
240 volatile int zero = 0; 240 volatile int zero = 0;
241 asm volatile ("frestore %0" : : "m" (zero)); 241 asm volatile ("frestore %0" : : "m" (zero));
242 } 242 }
diff --git a/arch/m68k/kernel/signal_mm.c b/arch/m68k/kernel/signal_mm.c
index 5f6b3d0fcd16..cb856f9da655 100644
--- a/arch/m68k/kernel/signal_mm.c
+++ b/arch/m68k/kernel/signal_mm.c
@@ -203,7 +203,8 @@ static inline int restore_fpu_state(struct sigcontext *sc)
203 203
204 if (CPU_IS_060 ? sc->sc_fpstate[2] : sc->sc_fpstate[0]) { 204 if (CPU_IS_060 ? sc->sc_fpstate[2] : sc->sc_fpstate[0]) {
205 /* Verify the frame format. */ 205 /* Verify the frame format. */
206 if (!CPU_IS_060 && (sc->sc_fpstate[0] != fpu_version)) 206 if (!(CPU_IS_060 || CPU_IS_COLDFIRE) &&
207 (sc->sc_fpstate[0] != fpu_version))
207 goto out; 208 goto out;
208 if (CPU_IS_020_OR_030) { 209 if (CPU_IS_020_OR_030) {
209 if (m68k_fputype & FPU_68881 && 210 if (m68k_fputype & FPU_68881 &&
@@ -222,19 +223,43 @@ static inline int restore_fpu_state(struct sigcontext *sc)
222 sc->sc_fpstate[3] == 0x60 || 223 sc->sc_fpstate[3] == 0x60 ||
223 sc->sc_fpstate[3] == 0xe0)) 224 sc->sc_fpstate[3] == 0xe0))
224 goto out; 225 goto out;
226 } else if (CPU_IS_COLDFIRE) {
227 if (!(sc->sc_fpstate[0] == 0x00 ||
228 sc->sc_fpstate[0] == 0x05 ||
229 sc->sc_fpstate[0] == 0xe5))
230 goto out;
225 } else 231 } else
226 goto out; 232 goto out;
227 233
228 __asm__ volatile (".chip 68k/68881\n\t" 234 if (CPU_IS_COLDFIRE) {
229 "fmovemx %0,%%fp0-%%fp1\n\t" 235 __asm__ volatile ("fmovemd %0,%%fp0-%%fp1\n\t"
230 "fmoveml %1,%%fpcr/%%fpsr/%%fpiar\n\t" 236 "fmovel %1,%%fpcr\n\t"
231 ".chip 68k" 237 "fmovel %2,%%fpsr\n\t"
232 : /* no outputs */ 238 "fmovel %3,%%fpiar"
233 : "m" (*sc->sc_fpregs), "m" (*sc->sc_fpcntl)); 239 : /* no outputs */
240 : "m" (sc->sc_fpregs[0]),
241 "m" (sc->sc_fpcntl[0]),
242 "m" (sc->sc_fpcntl[1]),
243 "m" (sc->sc_fpcntl[2]));
244 } else {
245 __asm__ volatile (".chip 68k/68881\n\t"
246 "fmovemx %0,%%fp0-%%fp1\n\t"
247 "fmoveml %1,%%fpcr/%%fpsr/%%fpiar\n\t"
248 ".chip 68k"
249 : /* no outputs */
250 : "m" (*sc->sc_fpregs),
251 "m" (*sc->sc_fpcntl));
252 }
253 }
254
255 if (CPU_IS_COLDFIRE) {
256 __asm__ volatile ("frestore %0" : : "m" (*sc->sc_fpstate));
257 } else {
258 __asm__ volatile (".chip 68k/68881\n\t"
259 "frestore %0\n\t"
260 ".chip 68k"
261 : : "m" (*sc->sc_fpstate));
234 } 262 }
235 __asm__ volatile (".chip 68k/68881\n\t"
236 "frestore %0\n\t"
237 ".chip 68k" : : "m" (*sc->sc_fpstate));
238 err = 0; 263 err = 0;
239 264
240out: 265out:
@@ -249,7 +274,7 @@ out:
249static inline int rt_restore_fpu_state(struct ucontext __user *uc) 274static inline int rt_restore_fpu_state(struct ucontext __user *uc)
250{ 275{
251 unsigned char fpstate[FPCONTEXT_SIZE]; 276 unsigned char fpstate[FPCONTEXT_SIZE];
252 int context_size = CPU_IS_060 ? 8 : 0; 277 int context_size = CPU_IS_060 ? 8 : (CPU_IS_COLDFIRE ? 12 : 0);
253 fpregset_t fpregs; 278 fpregset_t fpregs;
254 int err = 1; 279 int err = 1;
255 280
@@ -268,10 +293,11 @@ static inline int rt_restore_fpu_state(struct ucontext __user *uc)
268 if (__get_user(*(long *)fpstate, (long __user *)&uc->uc_fpstate)) 293 if (__get_user(*(long *)fpstate, (long __user *)&uc->uc_fpstate))
269 goto out; 294 goto out;
270 if (CPU_IS_060 ? fpstate[2] : fpstate[0]) { 295 if (CPU_IS_060 ? fpstate[2] : fpstate[0]) {
271 if (!CPU_IS_060) 296 if (!(CPU_IS_060 || CPU_IS_COLDFIRE))
272 context_size = fpstate[1]; 297 context_size = fpstate[1];
273 /* Verify the frame format. */ 298 /* Verify the frame format. */
274 if (!CPU_IS_060 && (fpstate[0] != fpu_version)) 299 if (!(CPU_IS_060 || CPU_IS_COLDFIRE) &&
300 (fpstate[0] != fpu_version))
275 goto out; 301 goto out;
276 if (CPU_IS_020_OR_030) { 302 if (CPU_IS_020_OR_030) {
277 if (m68k_fputype & FPU_68881 && 303 if (m68k_fputype & FPU_68881 &&
@@ -290,26 +316,50 @@ static inline int rt_restore_fpu_state(struct ucontext __user *uc)
290 fpstate[3] == 0x60 || 316 fpstate[3] == 0x60 ||
291 fpstate[3] == 0xe0)) 317 fpstate[3] == 0xe0))
292 goto out; 318 goto out;
319 } else if (CPU_IS_COLDFIRE) {
320 if (!(fpstate[3] == 0x00 ||
321 fpstate[3] == 0x05 ||
322 fpstate[3] == 0xe5))
323 goto out;
293 } else 324 } else
294 goto out; 325 goto out;
295 if (__copy_from_user(&fpregs, &uc->uc_mcontext.fpregs, 326 if (__copy_from_user(&fpregs, &uc->uc_mcontext.fpregs,
296 sizeof(fpregs))) 327 sizeof(fpregs)))
297 goto out; 328 goto out;
298 __asm__ volatile (".chip 68k/68881\n\t" 329
299 "fmovemx %0,%%fp0-%%fp7\n\t" 330 if (CPU_IS_COLDFIRE) {
300 "fmoveml %1,%%fpcr/%%fpsr/%%fpiar\n\t" 331 __asm__ volatile ("fmovemd %0,%%fp0-%%fp7\n\t"
301 ".chip 68k" 332 "fmovel %1,%%fpcr\n\t"
302 : /* no outputs */ 333 "fmovel %2,%%fpsr\n\t"
303 : "m" (*fpregs.f_fpregs), 334 "fmovel %3,%%fpiar"
304 "m" (*fpregs.f_fpcntl)); 335 : /* no outputs */
336 : "m" (fpregs.f_fpregs[0]),
337 "m" (fpregs.f_fpcntl[0]),
338 "m" (fpregs.f_fpcntl[1]),
339 "m" (fpregs.f_fpcntl[2]));
340 } else {
341 __asm__ volatile (".chip 68k/68881\n\t"
342 "fmovemx %0,%%fp0-%%fp7\n\t"
343 "fmoveml %1,%%fpcr/%%fpsr/%%fpiar\n\t"
344 ".chip 68k"
345 : /* no outputs */
346 : "m" (*fpregs.f_fpregs),
347 "m" (*fpregs.f_fpcntl));
348 }
305 } 349 }
306 if (context_size && 350 if (context_size &&
307 __copy_from_user(fpstate + 4, (long __user *)&uc->uc_fpstate + 1, 351 __copy_from_user(fpstate + 4, (long __user *)&uc->uc_fpstate + 1,
308 context_size)) 352 context_size))
309 goto out; 353 goto out;
310 __asm__ volatile (".chip 68k/68881\n\t" 354
311 "frestore %0\n\t" 355 if (CPU_IS_COLDFIRE) {
312 ".chip 68k" : : "m" (*fpstate)); 356 __asm__ volatile ("frestore %0" : : "m" (*fpstate));
357 } else {
358 __asm__ volatile (".chip 68k/68881\n\t"
359 "frestore %0\n\t"
360 ".chip 68k"
361 : : "m" (*fpstate));
362 }
313 err = 0; 363 err = 0;
314 364
315out: 365out:
@@ -529,10 +579,15 @@ static inline void save_fpu_state(struct sigcontext *sc, struct pt_regs *regs)
529 return; 579 return;
530 } 580 }
531 581
532 __asm__ volatile (".chip 68k/68881\n\t" 582 if (CPU_IS_COLDFIRE) {
533 "fsave %0\n\t" 583 __asm__ volatile ("fsave %0"
534 ".chip 68k" 584 : : "m" (*sc->sc_fpstate) : "memory");
535 : : "m" (*sc->sc_fpstate) : "memory"); 585 } else {
586 __asm__ volatile (".chip 68k/68881\n\t"
587 "fsave %0\n\t"
588 ".chip 68k"
589 : : "m" (*sc->sc_fpstate) : "memory");
590 }
536 591
537 if (CPU_IS_060 ? sc->sc_fpstate[2] : sc->sc_fpstate[0]) { 592 if (CPU_IS_060 ? sc->sc_fpstate[2] : sc->sc_fpstate[0]) {
538 fpu_version = sc->sc_fpstate[0]; 593 fpu_version = sc->sc_fpstate[0];
@@ -543,21 +598,35 @@ static inline void save_fpu_state(struct sigcontext *sc, struct pt_regs *regs)
543 if (*(unsigned short *) sc->sc_fpstate == 0x1f38) 598 if (*(unsigned short *) sc->sc_fpstate == 0x1f38)
544 sc->sc_fpstate[0x38] |= 1 << 3; 599 sc->sc_fpstate[0x38] |= 1 << 3;
545 } 600 }
546 __asm__ volatile (".chip 68k/68881\n\t" 601
547 "fmovemx %%fp0-%%fp1,%0\n\t" 602 if (CPU_IS_COLDFIRE) {
548 "fmoveml %%fpcr/%%fpsr/%%fpiar,%1\n\t" 603 __asm__ volatile ("fmovemd %%fp0-%%fp1,%0\n\t"
549 ".chip 68k" 604 "fmovel %%fpcr,%1\n\t"
550 : "=m" (*sc->sc_fpregs), 605 "fmovel %%fpsr,%2\n\t"
551 "=m" (*sc->sc_fpcntl) 606 "fmovel %%fpiar,%3"
552 : /* no inputs */ 607 : "=m" (sc->sc_fpregs[0]),
553 : "memory"); 608 "=m" (sc->sc_fpcntl[0]),
609 "=m" (sc->sc_fpcntl[1]),
610 "=m" (sc->sc_fpcntl[2])
611 : /* no inputs */
612 : "memory");
613 } else {
614 __asm__ volatile (".chip 68k/68881\n\t"
615 "fmovemx %%fp0-%%fp1,%0\n\t"
616 "fmoveml %%fpcr/%%fpsr/%%fpiar,%1\n\t"
617 ".chip 68k"
618 : "=m" (*sc->sc_fpregs),
619 "=m" (*sc->sc_fpcntl)
620 : /* no inputs */
621 : "memory");
622 }
554 } 623 }
555} 624}
556 625
557static inline int rt_save_fpu_state(struct ucontext __user *uc, struct pt_regs *regs) 626static inline int rt_save_fpu_state(struct ucontext __user *uc, struct pt_regs *regs)
558{ 627{
559 unsigned char fpstate[FPCONTEXT_SIZE]; 628 unsigned char fpstate[FPCONTEXT_SIZE];
560 int context_size = CPU_IS_060 ? 8 : 0; 629 int context_size = CPU_IS_060 ? 8 : (CPU_IS_COLDFIRE ? 12 : 0);
561 int err = 0; 630 int err = 0;
562 631
563 if (FPU_IS_EMU) { 632 if (FPU_IS_EMU) {
@@ -570,15 +639,19 @@ static inline int rt_save_fpu_state(struct ucontext __user *uc, struct pt_regs *
570 return err; 639 return err;
571 } 640 }
572 641
573 __asm__ volatile (".chip 68k/68881\n\t" 642 if (CPU_IS_COLDFIRE) {
574 "fsave %0\n\t" 643 __asm__ volatile ("fsave %0" : : "m" (*fpstate) : "memory");
575 ".chip 68k" 644 } else {
576 : : "m" (*fpstate) : "memory"); 645 __asm__ volatile (".chip 68k/68881\n\t"
646 "fsave %0\n\t"
647 ".chip 68k"
648 : : "m" (*fpstate) : "memory");
649 }
577 650
578 err |= __put_user(*(long *)fpstate, (long __user *)&uc->uc_fpstate); 651 err |= __put_user(*(long *)fpstate, (long __user *)&uc->uc_fpstate);
579 if (CPU_IS_060 ? fpstate[2] : fpstate[0]) { 652 if (CPU_IS_060 ? fpstate[2] : fpstate[0]) {
580 fpregset_t fpregs; 653 fpregset_t fpregs;
581 if (!CPU_IS_060) 654 if (!(CPU_IS_060 || CPU_IS_COLDFIRE))
582 context_size = fpstate[1]; 655 context_size = fpstate[1];
583 fpu_version = fpstate[0]; 656 fpu_version = fpstate[0];
584 if (CPU_IS_020_OR_030 && 657 if (CPU_IS_020_OR_030 &&
@@ -588,14 +661,27 @@ static inline int rt_save_fpu_state(struct ucontext __user *uc, struct pt_regs *
588 if (*(unsigned short *) fpstate == 0x1f38) 661 if (*(unsigned short *) fpstate == 0x1f38)
589 fpstate[0x38] |= 1 << 3; 662 fpstate[0x38] |= 1 << 3;
590 } 663 }
591 __asm__ volatile (".chip 68k/68881\n\t" 664 if (CPU_IS_COLDFIRE) {
592 "fmovemx %%fp0-%%fp7,%0\n\t" 665 __asm__ volatile ("fmovemd %%fp0-%%fp7,%0\n\t"
593 "fmoveml %%fpcr/%%fpsr/%%fpiar,%1\n\t" 666 "fmovel %%fpcr,%1\n\t"
594 ".chip 68k" 667 "fmovel %%fpsr,%2\n\t"
595 : "=m" (*fpregs.f_fpregs), 668 "fmovel %%fpiar,%3"
596 "=m" (*fpregs.f_fpcntl) 669 : "=m" (fpregs.f_fpregs[0]),
597 : /* no inputs */ 670 "=m" (fpregs.f_fpcntl[0]),
598 : "memory"); 671 "=m" (fpregs.f_fpcntl[1]),
672 "=m" (fpregs.f_fpcntl[2])
673 : /* no inputs */
674 : "memory");
675 } else {
676 __asm__ volatile (".chip 68k/68881\n\t"
677 "fmovemx %%fp0-%%fp7,%0\n\t"
678 "fmoveml %%fpcr/%%fpsr/%%fpiar,%1\n\t"
679 ".chip 68k"
680 : "=m" (*fpregs.f_fpregs),
681 "=m" (*fpregs.f_fpcntl)
682 : /* no inputs */
683 : "memory");
684 }
599 err |= copy_to_user(&uc->uc_mcontext.fpregs, &fpregs, 685 err |= copy_to_user(&uc->uc_mcontext.fpregs, &fpregs,
600 sizeof(fpregs)); 686 sizeof(fpregs));
601 } 687 }
@@ -692,8 +778,7 @@ static inline void push_cache (unsigned long vaddr)
692 "cpushl %%bc,(%0)\n\t" 778 "cpushl %%bc,(%0)\n\t"
693 ".chip 68k" 779 ".chip 68k"
694 : : "a" (temp)); 780 : : "a" (temp));
695 } 781 } else if (!CPU_IS_COLDFIRE) {
696 else {
697 /* 782 /*
698 * 68030/68020 have no writeback cache; 783 * 68030/68020 have no writeback cache;
699 * still need to clear icache. 784 * still need to clear icache.