]> err.no Git - linux-2.6/blob - arch/powerpc/platforms/pseries/hvCall.S
[POWERPC] Avoid hypervisor statistics calculation in real mode
[linux-2.6] / arch / powerpc / platforms / pseries / hvCall.S
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 */    \
26 BEGIN_FTR_SECTION;                                              \
27         mfspr   r0,SPRN_PURR;           /* get PURR and */      \
28         std     r0,STK_PARM(r6)(r1);    /* save for later */    \
29 END_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 */    \
42 BEGIN_FTR_SECTION;                                              \
43         mfspr   r8,SPRN_PURR;           /* PURR after */        \
44         ld      r6,STK_PARM(r6)(r1);    /* PURR before */       \
45         subf    r6,r6,r8;               /* delta */             \
46 END_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);                           \
65 BEGIN_FTR_SECTION;                                              \
66         ld      r7,HCALL_STAT_PURR(r4); /* PURR */              \
67         add     r7,r7,r6;                                       \
68         std     r7,HCALL_STAT_PURR(r4);                         \
69 END_FTR_SECTION_IFSET(CPU_FTR_PURR);                            \
70 1:
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 /*
127  * plpar_hcall_raw can be called in real mode. kexec/kdump need some
128  * hypervisor calls to be executed in real mode. So plpar_hcall_raw
129  * does not access the per cpu hypervisor call statistics variables,
130  * since these variables may not be present in the RMO region.
131  */
132 _GLOBAL(plpar_hcall_raw)
133         HMT_MEDIUM
134
135         mfcr    r0
136         stw     r0,8(r1)
137
138         std     r4,STK_PARM(r4)(r1)     /* Save ret buffer */
139
140         mr      r4,r5
141         mr      r5,r6
142         mr      r6,r7
143         mr      r7,r8
144         mr      r8,r9
145         mr      r9,r10
146
147         HVSC                            /* invoke the hypervisor */
148
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
155         lwz     r0,8(r1)
156         mtcrf   0xff,r0
157
158         blr                             /* return r3 = status */
159
160 _GLOBAL(plpar_hcall9)
161         HMT_MEDIUM
162
163         mfcr    r0
164         stw     r0,8(r1)
165
166         HCALL_INST_PRECALL
167
168         std     r4,STK_PARM(r4)(r1)     /* Save ret buffer */
169
170         mr      r4,r5
171         mr      r5,r6
172         mr      r6,r7
173         mr      r7,r8
174         mr      r8,r9
175         mr      r9,r10
176         ld      r10,STK_PARM(r11)(r1)    /* put arg7 in R10 */
177         ld      r11,STK_PARM(r12)(r1)    /* put arg8 in R11 */
178         ld      r12,STK_PARM(r13)(r1)    /* put arg9 in R12 */
179
180         HVSC                            /* invoke the hypervisor */
181
182         mr      r0,r12
183         ld      r12,STK_PARM(r4)(r1)
184         std     r4,  0(r12)
185         std     r5,  8(r12)
186         std     r6, 16(r12)
187         std     r7, 24(r12)
188         std     r8, 32(r12)
189         std     r9, 40(r12)
190         std     r10,48(r12)
191         std     r11,56(r12)
192         std     r0, 64(r12)
193
194         HCALL_INST_POSTCALL
195
196         lwz     r0,8(r1)
197         mtcrf   0xff,r0
198
199         blr                             /* return r3 = status */