12874c5fdSThomas Gleixner/* SPDX-License-Identifier: GPL-2.0-or-later */ 2963cf3dcSAlexander Graf/* 3963cf3dcSAlexander Graf * FPU helper code to use FPU operations from inside the kernel 4963cf3dcSAlexander Graf * 5963cf3dcSAlexander Graf * Copyright (C) 2010 Alexander Graf (agraf@suse.de) 6963cf3dcSAlexander Graf */ 7963cf3dcSAlexander Graf 865fddcfcSMike Rapoport#include <linux/pgtable.h> 9*2da37761SChristophe Leroy#include <linux/linkage.h> 10*2da37761SChristophe Leroy 11963cf3dcSAlexander Graf#include <asm/reg.h> 12963cf3dcSAlexander Graf#include <asm/page.h> 13963cf3dcSAlexander Graf#include <asm/mmu.h> 14963cf3dcSAlexander Graf#include <asm/cputable.h> 15963cf3dcSAlexander Graf#include <asm/cache.h> 16963cf3dcSAlexander Graf#include <asm/thread_info.h> 17963cf3dcSAlexander Graf#include <asm/ppc_asm.h> 18963cf3dcSAlexander Graf#include <asm/asm-offsets.h> 19963cf3dcSAlexander Graf 20963cf3dcSAlexander Graf/* Instructions operating on single parameters */ 21963cf3dcSAlexander Graf 22963cf3dcSAlexander Graf/* 23963cf3dcSAlexander Graf * Single operation with one input operand 24963cf3dcSAlexander Graf * 25963cf3dcSAlexander Graf * R3 = (double*)&fpscr 26963cf3dcSAlexander Graf * R4 = (short*)&result 27963cf3dcSAlexander Graf * R5 = (short*)¶m1 28963cf3dcSAlexander Graf */ 29963cf3dcSAlexander Graf#define FPS_ONE_IN(name) \ 30963cf3dcSAlexander Graf_GLOBAL(fps_ ## name); \ 31963cf3dcSAlexander Graf lfd 0,0(r3); /* load up fpscr value */ \ 32963cf3dcSAlexander Graf MTFSF_L(0); \ 33963cf3dcSAlexander Graf lfs 0,0(r5); \ 34963cf3dcSAlexander Graf \ 35963cf3dcSAlexander Graf name 0,0; \ 36963cf3dcSAlexander Graf \ 37963cf3dcSAlexander Graf stfs 0,0(r4); \ 38963cf3dcSAlexander Graf mffs 0; \ 39963cf3dcSAlexander Graf stfd 0,0(r3); /* save new fpscr value */ \ 40963cf3dcSAlexander Graf blr 41963cf3dcSAlexander Graf 42963cf3dcSAlexander Graf/* 43963cf3dcSAlexander Graf * Single operation with two input operands 44963cf3dcSAlexander Graf * 45963cf3dcSAlexander Graf * R3 = (double*)&fpscr 46963cf3dcSAlexander Graf * R4 = (short*)&result 47963cf3dcSAlexander Graf * R5 = (short*)¶m1 48963cf3dcSAlexander Graf * R6 = (short*)¶m2 49963cf3dcSAlexander Graf */ 50963cf3dcSAlexander Graf#define FPS_TWO_IN(name) \ 51963cf3dcSAlexander Graf_GLOBAL(fps_ ## name); \ 52963cf3dcSAlexander Graf lfd 0,0(r3); /* load up fpscr value */ \ 53963cf3dcSAlexander Graf MTFSF_L(0); \ 54963cf3dcSAlexander Graf lfs 0,0(r5); \ 55963cf3dcSAlexander Graf lfs 1,0(r6); \ 56963cf3dcSAlexander Graf \ 57963cf3dcSAlexander Graf name 0,0,1; \ 58963cf3dcSAlexander Graf \ 59963cf3dcSAlexander Graf stfs 0,0(r4); \ 60963cf3dcSAlexander Graf mffs 0; \ 61963cf3dcSAlexander Graf stfd 0,0(r3); /* save new fpscr value */ \ 62963cf3dcSAlexander Graf blr 63963cf3dcSAlexander Graf 64963cf3dcSAlexander Graf/* 65963cf3dcSAlexander Graf * Single operation with three input operands 66963cf3dcSAlexander Graf * 67963cf3dcSAlexander Graf * R3 = (double*)&fpscr 68963cf3dcSAlexander Graf * R4 = (short*)&result 69963cf3dcSAlexander Graf * R5 = (short*)¶m1 70963cf3dcSAlexander Graf * R6 = (short*)¶m2 71963cf3dcSAlexander Graf * R7 = (short*)¶m3 72963cf3dcSAlexander Graf */ 73963cf3dcSAlexander Graf#define FPS_THREE_IN(name) \ 74963cf3dcSAlexander Graf_GLOBAL(fps_ ## name); \ 75963cf3dcSAlexander Graf lfd 0,0(r3); /* load up fpscr value */ \ 76963cf3dcSAlexander Graf MTFSF_L(0); \ 77963cf3dcSAlexander Graf lfs 0,0(r5); \ 78963cf3dcSAlexander Graf lfs 1,0(r6); \ 79963cf3dcSAlexander Graf lfs 2,0(r7); \ 80963cf3dcSAlexander Graf \ 81963cf3dcSAlexander Graf name 0,0,1,2; \ 82963cf3dcSAlexander Graf \ 83963cf3dcSAlexander Graf stfs 0,0(r4); \ 84963cf3dcSAlexander Graf mffs 0; \ 85963cf3dcSAlexander Graf stfd 0,0(r3); /* save new fpscr value */ \ 86963cf3dcSAlexander Graf blr 87963cf3dcSAlexander Graf 88963cf3dcSAlexander GrafFPS_ONE_IN(fres) 89963cf3dcSAlexander GrafFPS_ONE_IN(frsqrte) 90963cf3dcSAlexander GrafFPS_ONE_IN(fsqrts) 91963cf3dcSAlexander GrafFPS_TWO_IN(fadds) 92963cf3dcSAlexander GrafFPS_TWO_IN(fdivs) 93963cf3dcSAlexander GrafFPS_TWO_IN(fmuls) 94963cf3dcSAlexander GrafFPS_TWO_IN(fsubs) 95963cf3dcSAlexander GrafFPS_THREE_IN(fmadds) 96963cf3dcSAlexander GrafFPS_THREE_IN(fmsubs) 97963cf3dcSAlexander GrafFPS_THREE_IN(fnmadds) 98963cf3dcSAlexander GrafFPS_THREE_IN(fnmsubs) 99963cf3dcSAlexander GrafFPS_THREE_IN(fsel) 100963cf3dcSAlexander Graf 101963cf3dcSAlexander Graf 102963cf3dcSAlexander Graf/* Instructions operating on double parameters */ 103963cf3dcSAlexander Graf 104963cf3dcSAlexander Graf/* 105963cf3dcSAlexander Graf * Beginning of double instruction processing 106963cf3dcSAlexander Graf * 107963cf3dcSAlexander Graf * R3 = (double*)&fpscr 108963cf3dcSAlexander Graf * R4 = (u32*)&cr 109963cf3dcSAlexander Graf * R5 = (double*)&result 110963cf3dcSAlexander Graf * R6 = (double*)¶m1 111963cf3dcSAlexander Graf * R7 = (double*)¶m2 [load_two] 112963cf3dcSAlexander Graf * R8 = (double*)¶m3 [load_three] 113963cf3dcSAlexander Graf * LR = instruction call function 114963cf3dcSAlexander Graf */ 115*2da37761SChristophe LeroySYM_FUNC_START_LOCAL(fpd_load_three) 116963cf3dcSAlexander Graf lfd 2,0(r8) /* load param3 */ 117*2da37761SChristophe LeroySYM_FUNC_START_LOCAL(fpd_load_two) 118963cf3dcSAlexander Graf lfd 1,0(r7) /* load param2 */ 119*2da37761SChristophe LeroySYM_FUNC_START_LOCAL(fpd_load_one) 120963cf3dcSAlexander Graf lfd 0,0(r6) /* load param1 */ 121*2da37761SChristophe LeroySYM_FUNC_START_LOCAL(fpd_load_none) 122963cf3dcSAlexander Graf lfd 3,0(r3) /* load up fpscr value */ 123963cf3dcSAlexander Graf MTFSF_L(3) 124963cf3dcSAlexander Graf lwz r6, 0(r4) /* load cr */ 125963cf3dcSAlexander Graf mtcr r6 126963cf3dcSAlexander Graf blr 127*2da37761SChristophe LeroySYM_FUNC_END(fpd_load_none) 128*2da37761SChristophe LeroySYM_FUNC_END(fpd_load_one) 129*2da37761SChristophe LeroySYM_FUNC_END(fpd_load_two) 130*2da37761SChristophe LeroySYM_FUNC_END(fpd_load_three) 131963cf3dcSAlexander Graf 132963cf3dcSAlexander Graf/* 133963cf3dcSAlexander Graf * End of double instruction processing 134963cf3dcSAlexander Graf * 135963cf3dcSAlexander Graf * R3 = (double*)&fpscr 136963cf3dcSAlexander Graf * R4 = (u32*)&cr 137963cf3dcSAlexander Graf * R5 = (double*)&result 138963cf3dcSAlexander Graf * LR = caller of instruction call function 139963cf3dcSAlexander Graf */ 140*2da37761SChristophe LeroySYM_FUNC_START_LOCAL(fpd_return) 141963cf3dcSAlexander Graf mfcr r6 142963cf3dcSAlexander Graf stfd 0,0(r5) /* save result */ 143963cf3dcSAlexander Graf mffs 0 144963cf3dcSAlexander Graf stfd 0,0(r3) /* save new fpscr value */ 145963cf3dcSAlexander Graf stw r6,0(r4) /* save new cr value */ 146963cf3dcSAlexander Graf blr 147*2da37761SChristophe LeroySYM_FUNC_END(fpd_return) 148963cf3dcSAlexander Graf 149963cf3dcSAlexander Graf/* 150963cf3dcSAlexander Graf * Double operation with no input operand 151963cf3dcSAlexander Graf * 152963cf3dcSAlexander Graf * R3 = (double*)&fpscr 153963cf3dcSAlexander Graf * R4 = (u32*)&cr 154963cf3dcSAlexander Graf * R5 = (double*)&result 155963cf3dcSAlexander Graf */ 156963cf3dcSAlexander Graf#define FPD_NONE_IN(name) \ 157963cf3dcSAlexander Graf_GLOBAL(fpd_ ## name); \ 158963cf3dcSAlexander Graf mflr r12; \ 159963cf3dcSAlexander Graf bl fpd_load_none; \ 160963cf3dcSAlexander Graf mtlr r12; \ 161963cf3dcSAlexander Graf \ 162963cf3dcSAlexander Graf name. 0; /* call instruction */ \ 163963cf3dcSAlexander Graf b fpd_return 164963cf3dcSAlexander Graf 165963cf3dcSAlexander Graf/* 166963cf3dcSAlexander Graf * Double operation with one input operand 167963cf3dcSAlexander Graf * 168963cf3dcSAlexander Graf * R3 = (double*)&fpscr 169963cf3dcSAlexander Graf * R4 = (u32*)&cr 170963cf3dcSAlexander Graf * R5 = (double*)&result 171963cf3dcSAlexander Graf * R6 = (double*)¶m1 172963cf3dcSAlexander Graf */ 173963cf3dcSAlexander Graf#define FPD_ONE_IN(name) \ 174963cf3dcSAlexander Graf_GLOBAL(fpd_ ## name); \ 175963cf3dcSAlexander Graf mflr r12; \ 176963cf3dcSAlexander Graf bl fpd_load_one; \ 177963cf3dcSAlexander Graf mtlr r12; \ 178963cf3dcSAlexander Graf \ 179963cf3dcSAlexander Graf name. 0,0; /* call instruction */ \ 180963cf3dcSAlexander Graf b fpd_return 181963cf3dcSAlexander Graf 182963cf3dcSAlexander Graf/* 183963cf3dcSAlexander Graf * Double operation with two input operands 184963cf3dcSAlexander Graf * 185963cf3dcSAlexander Graf * R3 = (double*)&fpscr 186963cf3dcSAlexander Graf * R4 = (u32*)&cr 187963cf3dcSAlexander Graf * R5 = (double*)&result 188963cf3dcSAlexander Graf * R6 = (double*)¶m1 189963cf3dcSAlexander Graf * R7 = (double*)¶m2 190963cf3dcSAlexander Graf * R8 = (double*)¶m3 191963cf3dcSAlexander Graf */ 192963cf3dcSAlexander Graf#define FPD_TWO_IN(name) \ 193963cf3dcSAlexander Graf_GLOBAL(fpd_ ## name); \ 194963cf3dcSAlexander Graf mflr r12; \ 195963cf3dcSAlexander Graf bl fpd_load_two; \ 196963cf3dcSAlexander Graf mtlr r12; \ 197963cf3dcSAlexander Graf \ 198963cf3dcSAlexander Graf name. 0,0,1; /* call instruction */ \ 199963cf3dcSAlexander Graf b fpd_return 200963cf3dcSAlexander Graf 201963cf3dcSAlexander Graf/* 202963cf3dcSAlexander Graf * CR Double operation with two input operands 203963cf3dcSAlexander Graf * 204963cf3dcSAlexander Graf * R3 = (double*)&fpscr 205963cf3dcSAlexander Graf * R4 = (u32*)&cr 206963cf3dcSAlexander Graf * R5 = (double*)¶m1 207963cf3dcSAlexander Graf * R6 = (double*)¶m2 208963cf3dcSAlexander Graf * R7 = (double*)¶m3 209963cf3dcSAlexander Graf */ 210963cf3dcSAlexander Graf#define FPD_TWO_IN_CR(name) \ 211963cf3dcSAlexander Graf_GLOBAL(fpd_ ## name); \ 212963cf3dcSAlexander Graf lfd 1,0(r6); /* load param2 */ \ 213963cf3dcSAlexander Graf lfd 0,0(r5); /* load param1 */ \ 214963cf3dcSAlexander Graf lfd 3,0(r3); /* load up fpscr value */ \ 215963cf3dcSAlexander Graf MTFSF_L(3); \ 216963cf3dcSAlexander Graf lwz r6, 0(r4); /* load cr */ \ 217963cf3dcSAlexander Graf mtcr r6; \ 218963cf3dcSAlexander Graf \ 219963cf3dcSAlexander Graf name 0,0,1; /* call instruction */ \ 220963cf3dcSAlexander Graf mfcr r6; \ 221963cf3dcSAlexander Graf mffs 0; \ 222963cf3dcSAlexander Graf stfd 0,0(r3); /* save new fpscr value */ \ 223963cf3dcSAlexander Graf stw r6,0(r4); /* save new cr value */ \ 224963cf3dcSAlexander Graf blr 225963cf3dcSAlexander Graf 226963cf3dcSAlexander Graf/* 227963cf3dcSAlexander Graf * Double operation with three input operands 228963cf3dcSAlexander Graf * 229963cf3dcSAlexander Graf * R3 = (double*)&fpscr 230963cf3dcSAlexander Graf * R4 = (u32*)&cr 231963cf3dcSAlexander Graf * R5 = (double*)&result 232963cf3dcSAlexander Graf * R6 = (double*)¶m1 233963cf3dcSAlexander Graf * R7 = (double*)¶m2 234963cf3dcSAlexander Graf * R8 = (double*)¶m3 235963cf3dcSAlexander Graf */ 236963cf3dcSAlexander Graf#define FPD_THREE_IN(name) \ 237963cf3dcSAlexander Graf_GLOBAL(fpd_ ## name); \ 238963cf3dcSAlexander Graf mflr r12; \ 239963cf3dcSAlexander Graf bl fpd_load_three; \ 240963cf3dcSAlexander Graf mtlr r12; \ 241963cf3dcSAlexander Graf \ 242963cf3dcSAlexander Graf name. 0,0,1,2; /* call instruction */ \ 243963cf3dcSAlexander Graf b fpd_return 244963cf3dcSAlexander Graf 245963cf3dcSAlexander GrafFPD_ONE_IN(fsqrts) 246963cf3dcSAlexander GrafFPD_ONE_IN(frsqrtes) 247963cf3dcSAlexander GrafFPD_ONE_IN(fres) 248963cf3dcSAlexander GrafFPD_ONE_IN(frsp) 249963cf3dcSAlexander GrafFPD_ONE_IN(fctiw) 250963cf3dcSAlexander GrafFPD_ONE_IN(fctiwz) 251963cf3dcSAlexander GrafFPD_ONE_IN(fsqrt) 252963cf3dcSAlexander GrafFPD_ONE_IN(fre) 253963cf3dcSAlexander GrafFPD_ONE_IN(frsqrte) 254963cf3dcSAlexander GrafFPD_ONE_IN(fneg) 255963cf3dcSAlexander GrafFPD_ONE_IN(fabs) 256963cf3dcSAlexander GrafFPD_TWO_IN(fadds) 257963cf3dcSAlexander GrafFPD_TWO_IN(fsubs) 258963cf3dcSAlexander GrafFPD_TWO_IN(fdivs) 259963cf3dcSAlexander GrafFPD_TWO_IN(fmuls) 260963cf3dcSAlexander GrafFPD_TWO_IN_CR(fcmpu) 261963cf3dcSAlexander GrafFPD_TWO_IN(fcpsgn) 262963cf3dcSAlexander GrafFPD_TWO_IN(fdiv) 263963cf3dcSAlexander GrafFPD_TWO_IN(fadd) 264963cf3dcSAlexander GrafFPD_TWO_IN(fmul) 265963cf3dcSAlexander GrafFPD_TWO_IN_CR(fcmpo) 266963cf3dcSAlexander GrafFPD_TWO_IN(fsub) 267963cf3dcSAlexander GrafFPD_THREE_IN(fmsubs) 268963cf3dcSAlexander GrafFPD_THREE_IN(fmadds) 269963cf3dcSAlexander GrafFPD_THREE_IN(fnmsubs) 270963cf3dcSAlexander GrafFPD_THREE_IN(fnmadds) 271963cf3dcSAlexander GrafFPD_THREE_IN(fsel) 272963cf3dcSAlexander GrafFPD_THREE_IN(fmsub) 273963cf3dcSAlexander GrafFPD_THREE_IN(fmadd) 274963cf3dcSAlexander GrafFPD_THREE_IN(fnmsub) 275963cf3dcSAlexander GrafFPD_THREE_IN(fnmadd) 27649f6be8eSAndreas Schwab 27749f6be8eSAndreas Schwab_GLOBAL(kvm_cvt_fd) 27849f6be8eSAndreas Schwab lfs 0,0(r3) 27949f6be8eSAndreas Schwab stfd 0,0(r4) 28049f6be8eSAndreas Schwab blr 28149f6be8eSAndreas Schwab 28249f6be8eSAndreas Schwab_GLOBAL(kvm_cvt_df) 28349f6be8eSAndreas Schwab lfd 0,0(r3) 28449f6be8eSAndreas Schwab stfs 0,0(r4) 28549f6be8eSAndreas Schwab blr 286