1/* 2 * This file contains the generic code to perform a call to the 3 * pSeries LPAR hypervisor. 4 * 5 * This program is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU General Public License 7 * as published by the Free Software Foundation; either version 8 * 2 of the License, or (at your option) any later version. 9 */ 10#include <asm/hvcall.h> 11#include <asm/processor.h> 12#include <asm/ppc_asm.h> 13#include <asm/asm-offsets.h> 14 15#define STK_PARM(i) (48 + ((i)-3)*8) 16 17#ifdef CONFIG_HCALL_STATS 18/* 19 * precall must preserve all registers. use unused STK_PARM() 20 * areas to save snapshots and opcode. 21 */ 22#define HCALL_INST_PRECALL \ 23 std r3,STK_PARM(r3)(r1); /* save opcode */ \ 24 mftb r0; /* get timebase and */ \ 25 std r0,STK_PARM(r5)(r1); /* save for later */ \ 26BEGIN_FTR_SECTION; \ 27 mfspr r0,SPRN_PURR; /* get PURR and */ \ 28 std r0,STK_PARM(r6)(r1); /* save for later */ \ 29END_FTR_SECTION_IFSET(CPU_FTR_PURR); 30 31/* 32 * postcall is performed immediately before function return which 33 * allows liberal use of volatile registers. 34 */ 35#define HCALL_INST_POSTCALL \ 36 ld r4,STK_PARM(r3)(r1); /* validate opcode */ \ 37 cmpldi cr7,r4,MAX_HCALL_OPCODE; \ 38 bgt- cr7,1f; \ 39 \ 40 /* get time and PURR snapshots after hcall */ \ 41 mftb r7; /* timebase after */ \ 42BEGIN_FTR_SECTION; \ 43 mfspr r8,SPRN_PURR; /* PURR after */ \ 44 ld r6,STK_PARM(r6)(r1); /* PURR before */ \ 45 subf r6,r6,r8; /* delta */ \ 46END_FTR_SECTION_IFSET(CPU_FTR_PURR); \ 47 ld r5,STK_PARM(r5)(r1); /* timebase before */ \ 48 subf r5,r5,r7; /* time delta */ \ 49 \ 50 /* calculate address of stat structure r4 = opcode */ \ 51 srdi r4,r4,2; /* index into array */ \ 52 mulli r4,r4,HCALL_STAT_SIZE; \ 53 LOAD_REG_ADDR(r7, per_cpu__hcall_stats); \ 54 add r4,r4,r7; \ 55 ld r7,PACA_DATA_OFFSET(r13); /* per cpu offset */ \ 56 add r4,r4,r7; \ 57 \ 58 /* update stats */ \ 59 ld r7,HCALL_STAT_CALLS(r4); /* count */ \ 60 addi r7,r7,1; \ 61 std r7,HCALL_STAT_CALLS(r4); \ 62 ld r7,HCALL_STAT_TB(r4); /* timebase */ \ 63 add r7,r7,r5; \ 64 std r7,HCALL_STAT_TB(r4); \ 65BEGIN_FTR_SECTION; \ 66 ld r7,HCALL_STAT_PURR(r4); /* PURR */ \ 67 add r7,r7,r6; \ 68 std r7,HCALL_STAT_PURR(r4); \ 69END_FTR_SECTION_IFSET(CPU_FTR_PURR); \ 701: 71#else 72#define HCALL_INST_PRECALL 73#define HCALL_INST_POSTCALL 74#endif 75 76 .text 77 78_GLOBAL(plpar_hcall_norets) 79 HMT_MEDIUM 80 81 mfcr r0 82 stw r0,8(r1) 83 84 HCALL_INST_PRECALL 85 86 HVSC /* invoke the hypervisor */ 87 88 HCALL_INST_POSTCALL 89 90 lwz r0,8(r1) 91 mtcrf 0xff,r0 92 blr /* return r3 = status */ 93 94_GLOBAL(plpar_hcall) 95 HMT_MEDIUM 96 97 mfcr r0 98 stw r0,8(r1) 99 100 HCALL_INST_PRECALL 101 102 std r4,STK_PARM(r4)(r1) /* Save ret buffer */ 103 104 mr r4,r5 105 mr r5,r6 106 mr r6,r7 107 mr r7,r8 108 mr r8,r9 109 mr r9,r10 110 111 HVSC /* invoke the hypervisor */ 112 113 ld r12,STK_PARM(r4)(r1) 114 std r4, 0(r12) 115 std r5, 8(r12) 116 std r6, 16(r12) 117 std r7, 24(r12) 118 119 HCALL_INST_POSTCALL 120 121 lwz r0,8(r1) 122 mtcrf 0xff,r0 123 124 blr /* return r3 = status */ 125 126_GLOBAL(plpar_hcall9) 127 HMT_MEDIUM 128 129 mfcr r0 130 stw r0,8(r1) 131 132 HCALL_INST_PRECALL 133 134 std r4,STK_PARM(r4)(r1) /* Save ret buffer */ 135 136 mr r4,r5 137 mr r5,r6 138 mr r6,r7 139 mr r7,r8 140 mr r8,r9 141 mr r9,r10 142 ld r10,STK_PARM(r11)(r1) /* put arg7 in R10 */ 143 ld r11,STK_PARM(r12)(r1) /* put arg8 in R11 */ 144 ld r12,STK_PARM(r13)(r1) /* put arg9 in R12 */ 145 146 HVSC /* invoke the hypervisor */ 147 148 mr r0,r12 149 ld r12,STK_PARM(r4)(r1) 150 std r4, 0(r12) 151 std r5, 8(r12) 152 std r6, 16(r12) 153 std r7, 24(r12) 154 std r8, 32(r12) 155 std r9, 40(r12) 156 std r10,48(r12) 157 std r11,56(r12) 158 std r0, 64(r12) 159 160 HCALL_INST_POSTCALL 161 162 lwz r0,8(r1) 163 mtcrf 0xff,r0 164 165 blr /* return r3 = status */ 166