First Support on Ginger and OMAP TI
[linux-ginger.git] / arch / powerpc / platforms / pseries / hvCall.S
blobc1427b3634ec8341206d575e4643c7633ffc977d
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)
17 #ifdef CONFIG_HCALL_STATS
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         
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);                            \
76 #else
77 #define HCALL_INST_PRECALL
78 #define HCALL_INST_POSTCALL
79 #endif
81         .text
83 _GLOBAL(plpar_hcall_norets)
84         HMT_MEDIUM
86         mfcr    r0
87         stw     r0,8(r1)
89         HCALL_INST_PRECALL
91         HVSC                            /* invoke the hypervisor */
93         HCALL_INST_POSTCALL
95         lwz     r0,8(r1)
96         mtcrf   0xff,r0
97         blr                             /* return r3 = status */
99 _GLOBAL(plpar_hcall)
100         HMT_MEDIUM
102         mfcr    r0
103         stw     r0,8(r1)
105         HCALL_INST_PRECALL
107         std     r4,STK_PARM(r4)(r1)     /* Save ret buffer */
109         mr      r4,r5
110         mr      r5,r6
111         mr      r6,r7
112         mr      r7,r8
113         mr      r8,r9
114         mr      r9,r10
116         HVSC                            /* invoke the hypervisor */
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)
124         HCALL_INST_POSTCALL
126         lwz     r0,8(r1)
127         mtcrf   0xff,r0
129         blr                             /* return r3 = status */
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
140         mfcr    r0
141         stw     r0,8(r1)
143         std     r4,STK_PARM(r4)(r1)     /* Save ret buffer */
145         mr      r4,r5
146         mr      r5,r6
147         mr      r6,r7
148         mr      r7,r8
149         mr      r8,r9
150         mr      r9,r10
152         HVSC                            /* invoke the hypervisor */
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)
160         lwz     r0,8(r1)
161         mtcrf   0xff,r0
163         blr                             /* return r3 = status */
165 _GLOBAL(plpar_hcall9)
166         HMT_MEDIUM
168         mfcr    r0
169         stw     r0,8(r1)
171         HCALL_INST_PRECALL
173         std     r4,STK_PARM(r4)(r1)     /* Save ret buffer */
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 */
185         HVSC                            /* invoke the hypervisor */
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)
199         HCALL_INST_POSTCALL
201         lwz     r0,8(r1)
202         mtcrf   0xff,r0
204         blr                             /* return r3 = status */