Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
[pandora-kernel.git] / arch / powerpc / platforms / pseries / hvCall.S
index db7c19f..c00cfed 100644 (file)
@@ -1,7 +1,6 @@
 /*
  * This file contains the generic code to perform a call to the
  * pSeries LPAR hypervisor.
- * NOTE: this file will go away when we move to inline this work.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
 #include <asm/hvcall.h>
 #include <asm/processor.h>
 #include <asm/ppc_asm.h>
+#include <asm/asm-offsets.h>
        
 #define STK_PARM(i)     (48 + ((i)-3)*8)
 
+#ifdef CONFIG_HCALL_STATS
+/*
+ * precall must preserve all registers.  use unused STK_PARM()
+ * areas to save snapshots and opcode.
+ */
+#define HCALL_INST_PRECALL                                     \
+       std     r3,STK_PARM(r3)(r1);    /* save opcode */       \
+       mftb    r0;                     /* get timebase and */  \
+       std     r0,STK_PARM(r5)(r1);    /* save for later */    \
+BEGIN_FTR_SECTION;                                             \
+       mfspr   r0,SPRN_PURR;           /* get PURR and */      \
+       std     r0,STK_PARM(r6)(r1);    /* save for later */    \
+END_FTR_SECTION_IFCLR(CPU_FTR_PURR);
+       
+/*
+ * postcall is performed immediately before function return which
+ * allows liberal use of volatile registers.
+ */
+#define HCALL_INST_POSTCALL                                    \
+       ld      r4,STK_PARM(r3)(r1);    /* validate opcode */   \
+       cmpldi  cr7,r4,MAX_HCALL_OPCODE;                        \
+       bgt-    cr7,1f;                                         \
+                                                               \
+       /* get time and PURR snapshots after hcall */           \
+       mftb    r7;                     /* timebase after */    \
+BEGIN_FTR_SECTION;                                             \
+       mfspr   r8,SPRN_PURR;           /* PURR after */        \
+       ld      r6,STK_PARM(r6)(r1);    /* PURR before */       \
+       subf    r6,r6,r8;               /* delta */             \
+END_FTR_SECTION_IFCLR(CPU_FTR_PURR);                           \
+       ld      r5,STK_PARM(r5)(r1);    /* timebase before */   \
+       subf    r5,r5,r7;               /* time delta */        \
+                                                               \
+       /* calculate address of stat structure r4 = opcode */   \
+       srdi    r4,r4,2;                /* index into array */  \
+       mulli   r4,r4,HCALL_STAT_SIZE;                          \
+       LOAD_REG_ADDR(r7, per_cpu__hcall_stats);                \
+       add     r4,r4,r7;                                       \
+       ld      r7,PACA_DATA_OFFSET(r13); /* per cpu offset */  \
+       add     r4,r4,r7;                                       \
+                                                               \
+       /* update stats */                                      \
+       ld      r7,HCALL_STAT_CALLS(r4); /* count */            \
+       addi    r7,r7,1;                                        \
+       std     r7,HCALL_STAT_CALLS(r4);                        \
+       ld      r7,HCALL_STAT_TB(r4);   /* timebase */          \
+       add     r7,r7,r5;                                       \
+       std     r7,HCALL_STAT_TB(r4);                           \
+BEGIN_FTR_SECTION;                                             \
+       ld      r7,HCALL_STAT_PURR(r4); /* PURR */              \
+       add     r7,r7,r6;                                       \
+       std     r7,HCALL_STAT_PURR(r4);                         \
+END_FTR_SECTION_IFCLR(CPU_FTR_PURR);                           \
+1:
+#else
+#define HCALL_INST_PRECALL
+#define HCALL_INST_POSTCALL
+#endif
+
        .text
 
-/* long plpar_hcall(unsigned long opcode,              R3
-                       unsigned long arg1,             R4
-                       unsigned long arg2,             R5
-                       unsigned long arg3,             R6
-                       unsigned long arg4,             R7
-                       unsigned long *out1,            R8
-                       unsigned long *out2,            R9
-                       unsigned long *out3);           R10
- */
-_GLOBAL(plpar_hcall)
+_GLOBAL(plpar_hcall_norets)
        HMT_MEDIUM
 
        mfcr    r0
-
-       std     r8,STK_PARM(r8)(r1)     /* Save out ptrs */
-       std     r9,STK_PARM(r9)(r1)
-       std     r10,STK_PARM(r10)(r1)
-
        stw     r0,8(r1)
 
-       HVSC                            /* invoke the hypervisor */
+       HCALL_INST_PRECALL
 
-       lwz     r0,8(r1)
+       HVSC                            /* invoke the hypervisor */
 
-       ld      r8,STK_PARM(r8)(r1)     /* Fetch r4-r6 ret args */
-       ld      r9,STK_PARM(r9)(r1)
-       ld      r10,STK_PARM(r10)(r1)
-       std     r4,0(r8)
-       std     r5,0(r9)
-       std     r6,0(r10)
+       HCALL_INST_POSTCALL
 
+       lwz     r0,8(r1)
        mtcrf   0xff,r0
        blr                             /* return r3 = status */
 
-
-/* Simple interface with no output values (other than status) */
-_GLOBAL(plpar_hcall_norets)
+_GLOBAL(plpar_hcall)
        HMT_MEDIUM
 
        mfcr    r0
        stw     r0,8(r1)
 
-       HVSC                            /* invoke the hypervisor */
+       HCALL_INST_PRECALL
 
-       lwz     r0,8(r1)
-       mtcrf   0xff,r0
-       blr                             /* return r3 = status */
+       std     r4,STK_PARM(r4)(r1)     /* Save ret buffer */
 
+       mr      r4,r5
+       mr      r5,r6
+       mr      r6,r7
+       mr      r7,r8
+       mr      r8,r9
+       mr      r9,r10
 
-/* long plpar_hcall_8arg_2ret(unsigned long opcode,    R3
-                       unsigned long arg1,             R4
-                       unsigned long arg2,             R5
-                       unsigned long arg3,             R6
-                       unsigned long arg4,             R7
-                       unsigned long arg5,             R8
-                       unsigned long arg6,             R9
-                       unsigned long arg7,             R10
-                       unsigned long arg8,             112(R1)
-                       unsigned long *out1);           120(R1)
- */
-_GLOBAL(plpar_hcall_8arg_2ret)
-       HMT_MEDIUM
+       HVSC                            /* invoke the hypervisor */
 
-       mfcr    r0
-       ld      r11,STK_PARM(r11)(r1)   /* put arg8 in R11 */
-       stw     r0,8(r1)
+       ld      r12,STK_PARM(r4)(r1)
+       std     r4,  0(r12)
+       std     r5,  8(r12)
+       std     r6, 16(r12)
+       std     r7, 24(r12)
 
-       HVSC                            /* invoke the hypervisor */
+       HCALL_INST_POSTCALL
 
        lwz     r0,8(r1)
-       ld      r10,STK_PARM(r12)(r1)   /* Fetch r4 ret arg */
-       std     r4,0(r10)
        mtcrf   0xff,r0
-       blr                             /* return r3 = status */
 
+       blr                             /* return r3 = status */
 
-/* long plpar_hcall_4out(unsigned long opcode,         R3
-                       unsigned long arg1,             R4
-                       unsigned long arg2,             R5
-                       unsigned long arg3,             R6
-                       unsigned long arg4,             R7
-                       unsigned long *out1,            R8
-                       unsigned long *out2,            R9
-                       unsigned long *out3,            R10
-                       unsigned long *out4);           112(R1)
- */
-_GLOBAL(plpar_hcall_4out)
+_GLOBAL(plpar_hcall9)
        HMT_MEDIUM
 
        mfcr    r0
        stw     r0,8(r1)
 
-       std     r8,STK_PARM(r8)(r1)     /* Save out ptrs */
-       std     r9,STK_PARM(r9)(r1)
-       std     r10,STK_PARM(r10)(r1)
+       HCALL_INST_PRECALL
+
+       std     r4,STK_PARM(r4)(r1)     /* Save ret buffer */
+
+       mr      r4,r5
+       mr      r5,r6
+       mr      r6,r7
+       mr      r7,r8
+       mr      r8,r9
+       mr      r9,r10
+       ld      r10,STK_PARM(r11)(r1)    /* put arg7 in R10 */
+       ld      r11,STK_PARM(r12)(r1)    /* put arg8 in R11 */
+       ld      r12,STK_PARM(r13)(r1)    /* put arg9 in R12 */
 
        HVSC                            /* invoke the hypervisor */
 
-       lwz     r0,8(r1)
+       ld      r12,STK_PARM(r4)(r1)
+       std     r4,  0(r12)
+       std     r5,  8(r12)
+       std     r6, 16(r12)
+       std     r7, 24(r12)
+       std     r8, 32(r12)
+       std     r9, 40(r12)
+       std     r10,48(r12)
+       std     r11,56(r12)
+       std     r12,64(r12)
 
-       ld      r8,STK_PARM(r8)(r1)     /* Fetch r4-r7 ret args */
-       ld      r9,STK_PARM(r9)(r1)
-       ld      r10,STK_PARM(r10)(r1)
-       ld      r11,STK_PARM(r11)(r1)
-       std     r4,0(r8)
-       std     r5,0(r9)
-       std     r6,0(r10)
-       std     r7,0(r11)
+       HCALL_INST_POSTCALL
 
+       lwz     r0,8(r1)
        mtcrf   0xff,r0
+
        blr                             /* return r3 = status */