Pull misc into release branch
[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.  We branch around this
34  * in early init (eg when populating the MMU hashtable) by using an
35  * unconditional cpu feature.
36  */
37 #define HCALL_INST_POSTCALL                                     \
38 BEGIN_FTR_SECTION;                                              \
39         b       1f;                                             \
40 END_FTR_SECTION(0, 1);                                          \
41         ld      r4,STK_PARM(r3)(r1);    /* validate opcode */   \
42         cmpldi  cr7,r4,MAX_HCALL_OPCODE;                        \
43         bgt-    cr7,1f;                                         \
44                                                                 \
45         /* get time and PURR snapshots after hcall */           \
46         mftb    r7;                     /* timebase after */    \
47 BEGIN_FTR_SECTION;                                              \
48         mfspr   r8,SPRN_PURR;           /* PURR after */        \
49         ld      r6,STK_PARM(r6)(r1);    /* PURR before */       \
50         subf    r6,r6,r8;               /* delta */             \
51 END_FTR_SECTION_IFSET(CPU_FTR_PURR);                            \
52         ld      r5,STK_PARM(r5)(r1);    /* timebase before */   \
53         subf    r5,r5,r7;               /* time delta */        \
54                                                                 \
55         /* calculate address of stat structure r4 = opcode */   \
56         srdi    r4,r4,2;                /* index into array */  \
57         mulli   r4,r4,HCALL_STAT_SIZE;                          \
58         LOAD_REG_ADDR(r7, per_cpu__hcall_stats);                \
59         add     r4,r4,r7;                                       \
60         ld      r7,PACA_DATA_OFFSET(r13); /* per cpu offset */  \
61         add     r4,r4,r7;                                       \
62                                                                 \
63         /* update stats */                                      \
64         ld      r7,HCALL_STAT_CALLS(r4); /* count */            \
65         addi    r7,r7,1;                                        \
66         std     r7,HCALL_STAT_CALLS(r4);                        \
67         ld      r7,HCALL_STAT_TB(r4);   /* timebase */          \
68         add     r7,r7,r5;                                       \
69         std     r7,HCALL_STAT_TB(r4);                           \
70 BEGIN_FTR_SECTION;                                              \
71         ld      r7,HCALL_STAT_PURR(r4); /* PURR */              \
72         add     r7,r7,r6;                                       \
73         std     r7,HCALL_STAT_PURR(r4);                         \
74 END_FTR_SECTION_IFSET(CPU_FTR_PURR);                            \
75 1:
76 #else
77 #define HCALL_INST_PRECALL
78 #define HCALL_INST_POSTCALL
79 #endif
80
81         .text
82
83 _GLOBAL(plpar_hcall_norets)
84         HMT_MEDIUM
85
86         mfcr    r0
87         stw     r0,8(r1)
88
89         HCALL_INST_PRECALL
90
91         HVSC                            /* invoke the hypervisor */
92
93         HCALL_INST_POSTCALL
94
95         lwz     r0,8(r1)
96         mtcrf   0xff,r0
97         blr                             /* return r3 = status */
98
99 _GLOBAL(plpar_hcall)
100         HMT_MEDIUM
101
102         mfcr    r0
103         stw     r0,8(r1)
104
105         HCALL_INST_PRECALL
106
107         std     r4,STK_PARM(r4)(r1)     /* Save ret buffer */
108
109         mr      r4,r5
110         mr      r5,r6
111         mr      r6,r7
112         mr      r7,r8
113         mr      r8,r9
114         mr      r9,r10
115
116         HVSC                            /* invoke the hypervisor */
117
118         ld      r12,STK_PARM(r4)(r1)
119         std     r4,  0(r12)
120         std     r5,  8(r12)
121         std     r6, 16(r12)
122         std     r7, 24(r12)
123
124         HCALL_INST_POSTCALL
125
126         lwz     r0,8(r1)
127         mtcrf   0xff,r0
128
129         blr                             /* return r3 = status */
130
131 /*
132  * plpar_hcall_raw can be called in real mode. kexec/kdump need some
133  * hypervisor calls to be executed in real mode. So plpar_hcall_raw
134  * does not access the per cpu hypervisor call statistics variables,
135  * since these variables may not be present in the RMO region.
136  */
137 _GLOBAL(plpar_hcall_raw)
138         HMT_MEDIUM
139
140         mfcr    r0
141         stw     r0,8(r1)
142
143         std     r4,STK_PARM(r4)(r1)     /* Save ret buffer */
144
145         mr      r4,r5
146         mr      r5,r6
147         mr      r6,r7
148         mr      r7,r8
149         mr      r8,r9
150         mr      r9,r10
151
152         HVSC                            /* invoke the hypervisor */
153
154         ld      r12,STK_PARM(r4)(r1)
155         std     r4,  0(r12)
156         std     r5,  8(r12)
157         std     r6, 16(r12)
158         std     r7, 24(r12)
159
160         lwz     r0,8(r1)
161         mtcrf   0xff,r0
162
163         blr                             /* return r3 = status */
164
165 _GLOBAL(plpar_hcall9)
166         HMT_MEDIUM
167
168         mfcr    r0
169         stw     r0,8(r1)
170
171         HCALL_INST_PRECALL
172
173         std     r4,STK_PARM(r4)(r1)     /* Save ret buffer */
174
175         mr      r4,r5
176         mr      r5,r6
177         mr      r6,r7
178         mr      r7,r8
179         mr      r8,r9
180         mr      r9,r10
181         ld      r10,STK_PARM(r11)(r1)    /* put arg7 in R10 */
182         ld      r11,STK_PARM(r12)(r1)    /* put arg8 in R11 */
183         ld      r12,STK_PARM(r13)(r1)    /* put arg9 in R12 */
184
185         HVSC                            /* invoke the hypervisor */
186
187         mr      r0,r12
188         ld      r12,STK_PARM(r4)(r1)
189         std     r4,  0(r12)
190         std     r5,  8(r12)
191         std     r6, 16(r12)
192         std     r7, 24(r12)
193         std     r8, 32(r12)
194         std     r9, 40(r12)
195         std     r10,48(r12)
196         std     r11,56(r12)
197         std     r0, 64(r12)
198
199         HCALL_INST_POSTCALL
200
201         lwz     r0,8(r1)
202         mtcrf   0xff,r0
203
204         blr                             /* return r3 = status */