fpu.c 2.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * fpu.c - save/restore of Floating Point Unit Registers on task switch
  4. *
  5. * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com)
  6. */
  7. #include <linux/sched.h>
  8. #include <asm/fpu.h>
  9. #ifdef CONFIG_ISA_ARCOMPACT
  10. /*
  11. * To save/restore FPU regs, simplest scheme would use LR/SR insns.
  12. * However since SR serializes the pipeline, an alternate "hack" can be used
  13. * which uses the FPU Exchange insn (DEXCL) to r/w FPU regs.
  14. *
  15. * Store to 64bit dpfp1 reg from a pair of core regs:
  16. * dexcl1 0, r1, r0 ; where r1:r0 is the 64 bit val
  17. *
  18. * Read from dpfp1 into pair of core regs (w/o clobbering dpfp1)
  19. * mov_s r3, 0
  20. * daddh11 r1, r3, r3 ; get "hi" into r1 (dpfp1 unchanged)
  21. * dexcl1 r0, r1, r3 ; get "low" into r0 (dpfp1 low clobbered)
  22. * dexcl1 0, r1, r0 ; restore dpfp1 to orig value
  23. *
  24. * However we can tweak the read, so that read-out of outgoing task's FPU regs
  25. * and write of incoming task's regs happen in one shot. So all the work is
  26. * done before context switch
  27. */
  28. void fpu_save_restore(struct task_struct *prev, struct task_struct *next)
  29. {
  30. unsigned int *saveto = &prev->thread.fpu.aux_dpfp[0].l;
  31. unsigned int *readfrom = &next->thread.fpu.aux_dpfp[0].l;
  32. const unsigned int zero = 0;
  33. __asm__ __volatile__(
  34. "daddh11 %0, %2, %2\n"
  35. "dexcl1 %1, %3, %4\n"
  36. : "=&r" (*(saveto + 1)), /* early clobber must here */
  37. "=&r" (*(saveto))
  38. : "r" (zero), "r" (*(readfrom + 1)), "r" (*(readfrom))
  39. );
  40. __asm__ __volatile__(
  41. "daddh22 %0, %2, %2\n"
  42. "dexcl2 %1, %3, %4\n"
  43. : "=&r"(*(saveto + 3)), /* early clobber must here */
  44. "=&r"(*(saveto + 2))
  45. : "r" (zero), "r" (*(readfrom + 3)), "r" (*(readfrom + 2))
  46. );
  47. }
  48. #else
  49. void fpu_init_task(struct pt_regs *regs)
  50. {
  51. const unsigned int fwe = 0x80000000;
  52. /* default rounding mode */
  53. write_aux_reg(ARC_REG_FPU_CTRL, 0x100);
  54. /* Initialize to zero: setting requires FWE be set */
  55. write_aux_reg(ARC_REG_FPU_STATUS, fwe);
  56. }
  57. void fpu_save_restore(struct task_struct *prev, struct task_struct *next)
  58. {
  59. struct arc_fpu *save = &prev->thread.fpu;
  60. struct arc_fpu *restore = &next->thread.fpu;
  61. const unsigned int fwe = 0x80000000;
  62. save->ctrl = read_aux_reg(ARC_REG_FPU_CTRL);
  63. save->status = read_aux_reg(ARC_REG_FPU_STATUS);
  64. write_aux_reg(ARC_REG_FPU_CTRL, restore->ctrl);
  65. write_aux_reg(ARC_REG_FPU_STATUS, (fwe | restore->status));
  66. }
  67. #endif