summaryrefslogtreecommitdiff
path: root/arch/powerpc/platforms/pseries/hvCall.S
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/platforms/pseries/hvCall.S')
-rw-r--r--arch/powerpc/platforms/pseries/hvCall.S72
1 files changed, 72 insertions, 0 deletions
diff --git a/arch/powerpc/platforms/pseries/hvCall.S b/arch/powerpc/platforms/pseries/hvCall.S
index 9a99b056bd27..c00cfed7af2c 100644
--- a/arch/powerpc/platforms/pseries/hvCall.S
+++ b/arch/powerpc/platforms/pseries/hvCall.S
@@ -10,9 +10,69 @@
#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
_GLOBAL(plpar_hcall_norets)
@@ -21,8 +81,12 @@ _GLOBAL(plpar_hcall_norets)
mfcr r0
stw r0,8(r1)
+ HCALL_INST_PRECALL
+
HVSC /* invoke the hypervisor */
+ HCALL_INST_POSTCALL
+
lwz r0,8(r1)
mtcrf 0xff,r0
blr /* return r3 = status */
@@ -33,6 +97,8 @@ _GLOBAL(plpar_hcall)
mfcr r0
stw r0,8(r1)
+ HCALL_INST_PRECALL
+
std r4,STK_PARM(r4)(r1) /* Save ret buffer */
mr r4,r5
@@ -50,6 +116,8 @@ _GLOBAL(plpar_hcall)
std r6, 16(r12)
std r7, 24(r12)
+ HCALL_INST_POSTCALL
+
lwz r0,8(r1)
mtcrf 0xff,r0
@@ -61,6 +129,8 @@ _GLOBAL(plpar_hcall9)
mfcr r0
stw r0,8(r1)
+ HCALL_INST_PRECALL
+
std r4,STK_PARM(r4)(r1) /* Save ret buffer */
mr r4,r5
@@ -86,6 +156,8 @@ _GLOBAL(plpar_hcall9)
std r11,56(r12)
std r12,64(r12)
+ HCALL_INST_POSTCALL
+
lwz r0,8(r1)
mtcrf 0xff,r0