* [PATCH] powerpc: Fix comment around arch specific definition of RECLAIM_DISTANCE
From: Preeti U Murthy @ 2014-05-05 5:17 UTC (permalink / raw)
To: linuxppc-dev; +Cc: anton, kosaki.motohiro
Commit 32e45ff43eaf5c17f changed the default value of
RECLAIM_DISTANCE to 30. However the comment around arch
specifc definition of RECLAIM_DISTANCE is not updated to
reflect the same. Correct the value mentioned in the comment.
Signed-off-by: Preeti U Murthy <preeti@linux.vnet.ibm.com>
Cc: Anton Blanchard <anton@samba.org>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
---
arch/powerpc/include/asm/topology.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/powerpc/include/asm/topology.h b/arch/powerpc/include/asm/topology.h
index c920215..356546d 100644
--- a/arch/powerpc/include/asm/topology.h
+++ b/arch/powerpc/include/asm/topology.h
@@ -12,7 +12,7 @@ struct device_node;
* Before going off node we want the VM to try and reclaim from the local
* node. It does this if the remote distance is larger than RECLAIM_DISTANCE.
* With the default REMOTE_DISTANCE of 20 and the default RECLAIM_DISTANCE of
- * 20, we never reclaim and go off node straight away.
+ * 30, we never reclaim and go off node straight away.
*
* To fix this we choose a smaller value of RECLAIM_DISTANCE.
*/
^ permalink raw reply related
* Re: Boot problems with a PA6T board
From: Michael Ellerman @ 2014-05-05 5:48 UTC (permalink / raw)
To: Christian Zigotzky; +Cc: linuxppc-dev
In-Reply-To: <5366649E.4030102@xenosoft.de>
On Sun, 2014-05-04 at 18:02 +0200, Christian Zigotzky wrote:
> Hi All,
>
> The RC 1, 2, and 3 of the kernel 3.15 don't boot on my PA6T board with a
> Radeon HD 6870 graphics card.
>
> Screenshot:
> http://forum.hyperion-entertainment.biz/download/file.php?id=1060&mode=view
>
> The kernel 3.14 starts without any problems. Has anyone a tip for me,
> please?
The line that says "starting cpu hw idx 0... failed" looks a little worrying.
Do you see that on 3.14 as well?
Otherwise bisection is probably your best bet.
cheers
^ permalink raw reply
* Re: [PATCH] powerpc/eeh: Fix build error for celleb
From: Michael Neuling @ 2014-05-05 6:12 UTC (permalink / raw)
To: Gavin Shan; +Cc: linuxppc-dev, Stephen Rothwell
In-Reply-To: <1399255745-2745-1-git-send-email-gwshan@linux.vnet.ibm.com>
On Mon, 2014-05-05 at 12:09 +1000, Gavin Shan wrote:
> Commit 7f52a526f ("powerpc/eeh: Allow to disable EEH") caused
> following build error with "celleb_defconfig" as being catched
> by Mikey on linux-next.
>=20
> arch/powerpc/kernel/eeh.c: In function 'eeh_init_proc':
> arch/powerpc/kernel/eeh.c:1173:37: error: 'powerpc_debugfs_root' \
> undeclared (first use in this function)
> arch/powerpc/kernel/eeh.c:1173:37: note: each undeclared identifier \
> is reported only once for each function it appears in
>=20
> Reported-by: Michael Neuling <mikey@neuling.org>
> Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
Thanks.
> ---
> arch/powerpc/kernel/eeh.c | 1 +
> 1 file changed, 1 insertion(+)
>=20
> diff --git a/arch/powerpc/kernel/eeh.c b/arch/powerpc/kernel/eeh.c
> index 33d683a..9c6b899 100644
> --- a/arch/powerpc/kernel/eeh.c
> +++ b/arch/powerpc/kernel/eeh.c
> @@ -36,6 +36,7 @@
> #include <linux/of.h>
> =20
> #include <linux/atomic.h>
> +#include <asm/debug.h>
> #include <asm/eeh.h>
> #include <asm/eeh_event.h>
> #include <asm/io.h>
^ permalink raw reply
* [PATCH V2 0/3] Add new PowerPC specific ELF core notes
From: Anshuman Khandual @ 2014-05-05 7:54 UTC (permalink / raw)
To: linuxppc-dev, linux-kernel
Cc: mikey, avagin, palves, oleg, michael, roland, Anshuman Khandual
This patch series adds five new ELF core note sections which can be
used with existing ptrace request PTRACE_GETREGSET/SETREGSET for accessing
various transactional memory and miscellaneous register sets on PowerPC
platform. Please find a test program exploiting these new ELF core note
types on a POWER8 system.
RFC: https://lkml.org/lkml/2014/4/1/292
V1: https://lkml.org/lkml/2014/4/2/43
Changes in V2
=============
(1) Removed all the power specific ptrace requests corresponding to new NT_PPC_*
elf core note types. Now all the register sets can be accessed from ptrace
through PTRACE_GETREGSET/PTRACE_SETREGSET using the individual NT_PPC* core
note type instead
(2) Fixed couple of attribute values for REGSET_TM_CGPR register set
(3) Renamed flush_tmreg_to_thread as flush_tmregs_to_thread
(4) Fixed 32 bit checkpointed GPR support
(5) Changed commit messages accordingly
Outstanding Issues
==================
(1) Running DSCR register value inside a transaction does not seem to be saved
at thread.dscr when the process stops for ptrace examination.
Test programs
=============
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
#include <errno.h>
#include <sys/ptrace.h>
#include <sys/uio.h>
#include <sys/types.h>
#include <sys/signal.h>
#include <sys/user.h>
#include <linux/elf.h>
#include <linux/types.h>
#include <linux/ptrace.h>
typedef long long u64;
typedef unsigned int u32;
typedef __vector128 vector128;
/* TM CFPR */
struct tm_cfpr {
u64 fpr[32];
u64 fpscr;
};
/* TM CVMX */
struct tm_cvmx {
vector128 vr[32] __attribute__((aligned(16)));
vector128 vscr __attribute__((aligned(16)));
u32 vrsave;
};
/* TM SPR */
struct tm_spr_regs {
u64 tm_tfhar;
u64 tm_texasr;
u64 tm_tfiar;
u64 tm_orig_msr;
u64 tm_tar;
u64 tm_ppr;
u64 tm_dscr;
};
/* Miscellaneous registers */
struct misc_regs {
u64 dscr;
u64 ppr;
u64 tar;
};
/* TM instructions */
#define TBEGIN ".long 0x7C00051D ;"
#define TEND ".long 0x7C00055D ;"
/* SPR number */
#define SPRN_DSCR 0x3
#define SPRN_TAR 815
/* ELF core notes */
#define NT_PPC_TM_SPR 0x103 /* PowerPC transactional memory special registers */
#define NT_PPC_TM_CGPR 0x104 /* PowerpC transactional memory checkpointed GPR */
#define NT_PPC_TM_CFPR 0x105 /* PowerPC transactional memory checkpointed FPR */
#define NT_PPC_TM_CVMX 0x106 /* PowerPC transactional memory checkpointed VMX */
#define NT_PPC_MISC 0x107 /* PowerPC miscellaneous registers */
#define VAL1 1
#define VAL2 2
#define VAL3 3
#define VAL4 4
int main(int argc, char *argv[])
{
struct tm_spr_regs *tmr1;
struct pt_regs *pregs1, *pregs2;
struct tm_cfpr *fpr, *fpr1;
struct misc_regs *dbr1;
struct iovec iov;
pid_t child;
int ret = 0, status = 0, i = 0, flag = 1;
pregs2 = (struct pt_regs *) malloc(sizeof(struct pt_regs));
fpr = (struct tm_cfpr *) malloc(sizeof(struct tm_cfpr));
child = fork();
if (child < 0) {
printf("fork() failed \n");
exit(-1);
}
/* Child code */
if (child == 0) {
asm __volatile__(
"6: ;" /* TM checkpointed values */
"li 1, %[val1];" /* GPR[1] */
".long 0x7C210166;" /* FPR[1] */
"li 2, %[val2];" /* GPR[2] */
".long 0x7C420166;" /* FPR[2] */
"mtspr %[tar], 1;" /* TAR */
"mtspr %[dscr], 2;" /* DSCR */
"1: ;"
TBEGIN /* TM running values */
"beq 2f ;"
"li 1, %[val3];" /* GPR[1] */
".long 0x7C210166;" /* FPR[1] */
"li 2, %[val4];" /* GPR[2] */
".long 0x7C420166;" /* FPR[2] */
"mtspr %[tar], 1;" /* TAR */
"mtspr %[dscr], 2;" /* DSCR */
"b .;"
TEND
"2: ;" /* Abort handler */
"b 1b;" /* Start from TBEGIN */
"3: ;"
"b 6b;" /* Start all over again */
:: [dscr]"i"(SPRN_DSCR), [tar]"i"(SPRN_TAR), [val1]"i"(VAL1), [val2]"i"(VAL2), [val3]"i"(VAL3), [val4]"i"(VAL4)
: "memory", "r7");
}
/* Parent */
if (child) {
do {
memset(pregs2, 0 , sizeof(struct pt_regs));
memset(fpr, 0 , sizeof(struct tm_cfpr));
/* Wait till child hits "b ." instruction */
sleep(3);
/* Attach tracee */
ret = ptrace(PTRACE_ATTACH, child, NULL, NULL);
if (ret == -1) {
printf("PTRACE_ATTACH failed: %s\n", strerror(errno));
exit(-1);
}
ret = waitpid(child, NULL, 0);
if (ret != child) {
printf("PID does not match\n");
exit(-1);
}
/* TM specific SPR */
iov.iov_base = (struct tm_spr_regs *) malloc(sizeof(struct tm_spr_regs));
iov.iov_len = sizeof(struct tm_spr_regs);
ret = ptrace(PTRACE_GETREGSET, child, NT_PPC_TM_SPR, &iov);
if (ret == -1) {
printf("PTRACE_GETREGSET: NT_PPC_TM_SPR failed %s\n", strerror(errno));
exit(-1);
}
if (iov.iov_len != sizeof(struct tm_spr_regs)) {
printf("NT_PPC_TM_SPR: Length returned is wrong\n");
exit(-1);
}
tmr1 = iov.iov_base;
printf("-------TM specific SPR------\n");
printf("TM TFHAR: %llx\n", tmr1->tm_tfhar);
printf("TM TEXASR: %llx\n", tmr1->tm_texasr);
printf("TM TFIAR: %llx\n", tmr1->tm_tfiar);
printf("TM CH ORIG_MSR: %llx\n", tmr1->tm_orig_msr);
printf("TM CH TAR: %llx\n", tmr1->tm_tar);
printf("TM CH PPR: %llx\n", tmr1->tm_ppr);
printf("TM CH DSCR: %llx\n", tmr1->tm_dscr);
if (tmr1->tm_tar == VAL1)
printf("TAR PASSED\n");
else
printf("TAR FAILED\n");
if (tmr1->tm_dscr == VAL2)
printf("DSCR PASSED\n");
else
printf("DSCR FAILED\n");
/* TM checkpointed GPR */
iov.iov_base = (struct pt_regs *) malloc(sizeof(struct pt_regs));;
iov.iov_len = sizeof(struct pt_regs);
ret = ptrace(PTRACE_GETREGSET, child, NT_PPC_TM_CGPR, &iov);
if (ret == -1) {
printf("PTRACE_GETREGSET: NT_PPC_TM_CGPR failed: %s\n", strerror(errno));
exit(-1);
}
if (iov.iov_len != sizeof(struct pt_regs)) {
printf("NT_PPC_TM_CGPR: Length returned is wrong\n");
exit(-1);
}
pregs1 = iov.iov_base;
printf("-------TM checkpointed GPR-----\n");
printf("TM CH GPR[1]: %x\n", pregs1->gpr[1]);
printf("TM CH GPR[2]: %x\n", pregs1->gpr[2]);
printf("TM CH NIP: %x\n", pregs1->nip);
printf("TM CH LINK: %x\n", pregs1->link);
printf("TM CH CCR: %x\n", pregs1->ccr);
if (pregs1->gpr[1] == VAL1)
printf("GPR[1] PASSED\n");
else
printf("GPR[1] FAILED\n");
if (pregs1->gpr[2] == VAL2)
printf("GPR[2] PASSED\n");
else
printf("GPR[2] FAILED\n");
/* TM running GPR */
ret = ptrace(PTRACE_GETREGS, child, NULL, pregs2);
if (ret == -1) {
printf("PTRACE_GETREGS fail: %s\n", strerror(errno));
exit(-1);
}
printf("-------TM running GPR-----\n");
printf("TM RN GPR[1]: %x\n", pregs2->gpr[1]);
printf("TM RN GPR[2]: %x\n", pregs2->gpr[2]);
printf("TM RN NIP: %x\n", pregs2->nip);
printf("TM RN LINK: %x\n", pregs2->link);
printf("TM RN CCR: %x\n", pregs2->ccr);
if (pregs2->gpr[1] == VAL3)
printf("GPR[1] PASSED\n");
else
printf("GPR[1] FAILED\n");
if (pregs2->gpr[2] == VAL4)
printf("GPR[2] PASSED\n");
else
printf("GPR[2] FAILED\n");
/* TM checkpointed FPR */
iov.iov_base = (struct tm_cfpr *) malloc(sizeof(struct tm_cfpr));;
iov.iov_len = sizeof(struct tm_cfpr);
ret = ptrace(PTRACE_GETREGSET, child, NT_PPC_TM_CFPR, &iov);
if (ret == -1) {
printf("PTRACE_GETREGSET: NT_PPC_TM_CFPR: Failed: %s\n", strerror(errno));
exit(-1);
}
if (iov.iov_len != sizeof(struct tm_cfpr)) {
printf("NT_PPC_TM_CFPR: Length returned is wrong\n");
exit(-1);
}
fpr1 = iov.iov_base;
printf("-------TM checkpointed FPR-----\n");
printf("TM CH FPR[1]: %llx\n", fpr1->fpr[1]);
printf("TM CH FPR[2]: %llx\n", fpr1->fpr[2]);
printf("TM CH FPSCR: %llx\n", fpr1->fpscr);
if (fpr1->fpr[1] == VAL1)
printf("FPR[1] PASSED\n");
else
printf("FPR[1] FAILED\n");
if (fpr1->fpr[2] == VAL2)
printf("FPR[2] PASSED\n");
else
printf("FPR[2] FAILED\n");
/* TM running FPR */
ret = ptrace(PTRACE_GETFPREGS, child, NULL, fpr);
if (ret == -1) {
printf("PTRACE_GETFPREGS failed: %s\n", strerror(errno));
exit(-1);
}
printf("-------TM running FPR-----\n");
printf("TM RN FPR[1]: %llx\n", fpr->fpr[1]);
printf("TM RN FPR[2]: %llx\n", fpr->fpr[2]);
printf("TM RN FPSCR: %llx\n", fpr->fpscr);
if (fpr->fpr[1] == VAL3)
printf("FPR[1] PASSED\n");
else
printf("FPR[1] FAILED\n");
if (fpr->fpr[2] == VAL4)
printf("FPR[2] PASSED\n");
else
printf("FPR[2] FAILED\n");
/* Misc registers */
iov.iov_base = (struct misc_regs *) malloc(sizeof(struct misc_regs));
iov.iov_len = sizeof(struct misc_regs);
ret = ptrace(PTRACE_GETREGSET, child, NT_PPC_MISC, &iov);
if (ret == -1) {
printf("PTRACE_GETREGSET: NT_PPC_MISC: Failed: %s\n", strerror(errno));
exit(-1);
}
if (iov.iov_len != sizeof(struct misc_regs)) {
printf("NT_PPC_TM_MISC: Length returned is wrong\n");
exit(-1);
}
dbr1 = iov.iov_base;
printf("-------Running miscellaneous registers-------\n");
printf("TM RN DSCR: %llx\n", dbr1->dscr);
printf("TM RN PPR: %llx\n", dbr1->ppr);
printf("TM RN TAR: %llx\n", dbr1->tar);
if (dbr1->tar == VAL3)
printf("TAR PASSED\n");
else
printf("TAR FAILED\n");
if (dbr1->dscr == VAL4)
printf("DSCR PASSED\n");
else
printf("DSCR FAILED\n");
/* Detach tracee */
ret = ptrace(PTRACE_DETACH, child, NULL, NULL);
if (ret == -1) {
printf("PTRACE_DETACH failed: %s\n", strerror(errno));
exit(-1);
}
} while (0);
}
return 0;
}
Test Results
============
(1) 64 bit application ==>
-------TM specific SPR------
TM TFHAR: 10000960
TM TEXASR: de000001ac000001
TM TFIAR: c00000000003f9a6
TM CH ORIG_MSR: 900000050000f032
TM CH TAR: 1
TM CH PPR: c000000000000
TM CH DSCR: 2
TAR PASSED
DSCR PASSED
-------TM checkpointed GPR-----
TM CH GPR[1]: 1
TM CH GPR[2]: 2
TM CH NIP: 10000960
TM CH LINK: 10000904
TM CH CCR: 22000022
GPR[1] PASSED
GPR[2] PASSED
-------TM running GPR-----
TM RN GPR[1]: 3
TM RN GPR[2]: 4
TM RN NIP: 1000097c
TM RN LINK: 10000904
TM RN CCR: 2000022
GPR[1] PASSED
GPR[2] PASSED
-------TM checkpointed FPR-----
TM CH FPR[1]: 1
TM CH FPR[2]: 2
TM CH FPSCR: 0
FPR[1] PASSED
FPR[2] PASSED
-------TM running FPR-----
TM RN FPR[1]: 3
TM RN FPR[2]: 4
TM RN FPSCR: 0
FPR[1] PASSED
FPR[2] PASSED
-------Running miscellaneous registers-------
TM RN DSCR: 0
TM RN PPR: c000000000000
TM RN TAR: 3
TAR PASSED
DSCR FAILED
(2) 32 bit application ==>
-------TM specific SPR------
TM TFHAR: 100006b8
TM TEXASR: de000001ac000001
TM TFIAR: c00000000003f9a6
TM CH ORIG_MSR: 100000050000f032
TM CH TAR: 1
TM CH PPR: c000000000000
TM CH DSCR: 2
TAR PASSED
DSCR PASSED
-------TM checkpointed GPR-----
TM CH GPR[1]: 1
TM CH GPR[2]: 2
TM CH NIP: 100006b8
TM CH LINK: 1000066c
TM CH CCR: 22000022
GPR[1] PASSED
GPR[2] PASSED
-------TM running GPR-----
TM RN GPR[1]: 3
TM RN GPR[2]: 4
TM RN NIP: 100006d4
TM RN LINK: 1000066c
TM RN CCR: 2000022
GPR[1] PASSED
GPR[2] PASSED
TM CH FPR[2]: 2
TM CH FPSCR: 0
FPR[1] PASSED
FPR[2] PASSED
-------TM running FPR-----
TM RN FPR[1]: 3
TM RN FPR[2]: 4
TM RN FPSCR: 0
FPR[1] PASSED
FPR[2] PASSED
-------Running miscellaneous registers-------
TM RN DSCR: 0
TM RN PPR: c000000000000
TM RN TAR: 3
TAR PASSED
DSCR FAILED
Anshuman Khandual (3):
elf: Add some new PowerPC specifc note sections
powerpc, ptrace: Enable support for transactional memory register sets
powerpc, ptrace: Enable support for miscellaneous registers
arch/powerpc/include/asm/switch_to.h | 8 +
arch/powerpc/kernel/process.c | 24 ++
arch/powerpc/kernel/ptrace.c | 764 +++++++++++++++++++++++++++++++++--
include/uapi/linux/elf.h | 5 +
4 files changed, 773 insertions(+), 28 deletions(-)
--
1.7.11.7
^ permalink raw reply
* [PATCH V2 1/3] elf: Add some new PowerPC specifc note sections
From: Anshuman Khandual @ 2014-05-05 7:54 UTC (permalink / raw)
To: linuxppc-dev, linux-kernel
Cc: mikey, avagin, palves, oleg, michael, roland, Anshuman Khandual
In-Reply-To: <1399276469-13541-1-git-send-email-khandual@linux.vnet.ibm.com>
This patch adds four new note sections for transactional memory
and one note section for some miscellaneous registers. This addition
of new elf note sections extends the existing elf ABI without affecting
it in any manner.
Signed-off-by: Anshuman Khandual <khandual@linux.vnet.ibm.com>
---
include/uapi/linux/elf.h | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/include/uapi/linux/elf.h b/include/uapi/linux/elf.h
index ef6103b..4040124 100644
--- a/include/uapi/linux/elf.h
+++ b/include/uapi/linux/elf.h
@@ -379,6 +379,11 @@ typedef struct elf64_shdr {
#define NT_PPC_VMX 0x100 /* PowerPC Altivec/VMX registers */
#define NT_PPC_SPE 0x101 /* PowerPC SPE/EVR registers */
#define NT_PPC_VSX 0x102 /* PowerPC VSX registers */
+#define NT_PPC_TM_SPR 0x103 /* PowerPC TM special registers */
+#define NT_PPC_TM_CGPR 0x104 /* PowerpC TM checkpointed GPR */
+#define NT_PPC_TM_CFPR 0x105 /* PowerPC TM checkpointed FPR */
+#define NT_PPC_TM_CVMX 0x106 /* PowerPC TM checkpointed VMX */
+#define NT_PPC_MISC 0x107 /* PowerPC miscellaneous registers */
#define NT_386_TLS 0x200 /* i386 TLS slots (struct user_desc) */
#define NT_386_IOPERM 0x201 /* x86 io permission bitmap (1=deny) */
#define NT_X86_XSTATE 0x202 /* x86 extended state using xsave */
--
1.7.11.7
^ permalink raw reply related
* [PATCH V2 2/3] powerpc, ptrace: Enable support for transactional memory register sets
From: Anshuman Khandual @ 2014-05-05 7:54 UTC (permalink / raw)
To: linuxppc-dev, linux-kernel
Cc: mikey, avagin, palves, oleg, michael, roland, Anshuman Khandual
In-Reply-To: <1399276469-13541-1-git-send-email-khandual@linux.vnet.ibm.com>
This patch enables get and set of transactional memory related register
sets through PTRACE_GETREGSET/PTRACE_SETREGSET interface by implementing
four new powerpc specific register sets i.e REGSET_TM_SPR, REGSET_TM_CGPR,
REGSET_TM_CFPR, REGSET_CVMX support corresponding to these following new
ELF core note types added previously in this regard.
(1) NT_PPC_TM_SPR
(2) NT_PPC_TM_CGPR
(3) NT_PPC_TM_CFPR
(4) NT_PPC_TM_CVMX
Signed-off-by: Anshuman Khandual <khandual@linux.vnet.ibm.com>
---
arch/powerpc/include/asm/switch_to.h | 8 +
arch/powerpc/kernel/process.c | 24 ++
arch/powerpc/kernel/ptrace.c | 683 +++++++++++++++++++++++++++++++++--
3 files changed, 687 insertions(+), 28 deletions(-)
diff --git a/arch/powerpc/include/asm/switch_to.h b/arch/powerpc/include/asm/switch_to.h
index 0e83e7d..2737f46 100644
--- a/arch/powerpc/include/asm/switch_to.h
+++ b/arch/powerpc/include/asm/switch_to.h
@@ -80,6 +80,14 @@ static inline void flush_spe_to_thread(struct task_struct *t)
}
#endif
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+extern void flush_tmregs_to_thread(struct task_struct *);
+#else
+static inline void flush_tmregs_to_thread(struct task_struct *t)
+{
+}
+#endif /* CONFIG_PPC_TRANSACTIONAL_MEM */
+
static inline void clear_task_ebb(struct task_struct *t)
{
#ifdef CONFIG_PPC_BOOK3S_64
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index 31d0215..e247898 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -695,6 +695,30 @@ static inline void __switch_to_tm(struct task_struct *prev)
}
}
+void flush_tmregs_to_thread(struct task_struct *tsk)
+{
+ /*
+ * If task is not current, it should have been flushed
+ * already to it's thread_struct during __switch_to().
+ */
+ if (tsk != current)
+ return;
+
+ preempt_disable();
+ if (tsk->thread.regs) {
+ /*
+ * If we are still current, the TM state need to
+ * be flushed to thread_struct as it will be still
+ * present in the current cpu.
+ */
+ if (MSR_TM_ACTIVE(tsk->thread.regs->msr)) {
+ __switch_to_tm(tsk);
+ tm_recheckpoint_new_task(tsk);
+ }
+ }
+ preempt_enable();
+}
+
/*
* This is called if we are on the way out to userspace and the
* TIF_RESTORE_TM flag is set. It checks if we need to reload
diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c
index 2e3d2bf..92faded 100644
--- a/arch/powerpc/kernel/ptrace.c
+++ b/arch/powerpc/kernel/ptrace.c
@@ -357,6 +357,17 @@ static int gpr_set(struct task_struct *target, const struct user_regset *regset,
return ret;
}
+/*
+ * When any transaction is active, "thread_struct->transact_fp" holds
+ * the current running value of all FPR registers and "thread_struct->
+ * fp_state" holds the last checkpointed FPR registers state for the
+ * current transaction.
+ *
+ * struct data {
+ * u64 fpr[32];
+ * u64 fpscr;
+ * };
+ */
static int fpr_get(struct task_struct *target, const struct user_regset *regset,
unsigned int pos, unsigned int count,
void *kbuf, void __user *ubuf)
@@ -365,21 +376,41 @@ static int fpr_get(struct task_struct *target, const struct user_regset *regset,
u64 buf[33];
int i;
#endif
- flush_fp_to_thread(target);
+ if (MSR_TM_ACTIVE(target->thread.regs->msr)) {
+ flush_fp_to_thread(target);
+ flush_altivec_to_thread(target);
+ flush_tmregs_to_thread(target);
+ } else {
+ flush_fp_to_thread(target);
+ }
#ifdef CONFIG_VSX
/* copy to local buffer then write that out */
- for (i = 0; i < 32 ; i++)
- buf[i] = target->thread.TS_FPR(i);
- buf[32] = target->thread.fp_state.fpscr;
+ if (MSR_TM_ACTIVE(target->thread.regs->msr)) {
+ for (i = 0; i < 32 ; i++)
+ buf[i] = target->thread.TS_TRANS_FPR(i);
+ buf[32] = target->thread.transact_fp.fpscr;
+ } else {
+ for (i = 0; i < 32 ; i++)
+ buf[i] = target->thread.TS_FPR(i);
+ buf[32] = target->thread.fp_state.fpscr;
+ }
return user_regset_copyout(&pos, &count, &kbuf, &ubuf, buf, 0, -1);
#else
- BUILD_BUG_ON(offsetof(struct thread_fp_state, fpscr) !=
- offsetof(struct thread_fp_state, fpr[32][0]));
+ if (MSR_TM_ACTIVE(tsk->thread.regs->msr)) {
+ BUILD_BUG_ON(offsetof(struct transact_fp, fpscr) !=
+ offsetof(struct transact_fp, fpr[32][0]));
- return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+ return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+ &target->thread.transact_fp, 0, -1);
+ } esle {
+ BUILD_BUG_ON(offsetof(struct thread_fp_state, fpscr) !=
+ offsetof(struct thread_fp_state, fpr[32][0]));
+
+ return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
&target->thread.fp_state, 0, -1);
+ }
#endif
}
@@ -391,23 +422,44 @@ static int fpr_set(struct task_struct *target, const struct user_regset *regset,
u64 buf[33];
int i;
#endif
- flush_fp_to_thread(target);
+ if (MSR_TM_ACTIVE(target->thread.regs->msr)) {
+ flush_fp_to_thread(target);
+ flush_altivec_to_thread(target);
+ flush_tmregs_to_thread(target);
+ } else {
+ flush_fp_to_thread(target);
+ }
#ifdef CONFIG_VSX
/* copy to local buffer then write that out */
i = user_regset_copyin(&pos, &count, &kbuf, &ubuf, buf, 0, -1);
if (i)
return i;
- for (i = 0; i < 32 ; i++)
- target->thread.TS_FPR(i) = buf[i];
- target->thread.fp_state.fpscr = buf[32];
+ for (i = 0; i < 32 ; i++) {
+ if (MSR_TM_ACTIVE(target->thread.regs->msr))
+ target->thread.TS_TRANS_FPR(i) = buf[i];
+ else
+ target->thread.TS_FPR(i) = buf[i];
+ }
+ if (MSR_TM_ACTIVE(target->thread.regs->msr))
+ target->thread.transact_fp.fpscr = buf[32];
+ else
+ target->thread.fp_state.fpscr = buf[32];
return 0;
#else
- BUILD_BUG_ON(offsetof(struct thread_fp_state, fpscr) !=
- offsetof(struct thread_fp_state, fpr[32][0]));
+ if (MSR_TM_ACTIVE(target->thread.regs->msr)) {
+ BUILD_BUG_ON(offsetof(struct transact_fp, fpscr) !=
+ offsetof(struct transact_fp, fpr[32][0]));
- return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
- &target->thread.fp_state, 0, -1);
+ return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+ &target->thread.transact_fp, 0, -1);
+ } else {
+ BUILD_BUG_ON(offsetof(struct thread_fp_state, fpscr) !=
+ offsetof(struct thread_fp_state, fpr[32][0]));
+
+ return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+ &target->thread.fp_state, 0, -1);
+ }
#endif
}
@@ -432,20 +484,44 @@ static int vr_active(struct task_struct *target,
return target->thread.used_vr ? regset->n : 0;
}
+/*
+ * When any transaction is active, "thread_struct->transact_vr" holds
+ * the current running value of all VMX registers and "thread_struct->
+ * vr_state" holds the last checkpointed value of VMX registers for the
+ * current transaction.
+ *
+ * struct data {
+ * vector128 vr[32];
+ * vector128 vscr;
+ * vector128 vrsave;
+ * };
+ */
static int vr_get(struct task_struct *target, const struct user_regset *regset,
unsigned int pos, unsigned int count,
void *kbuf, void __user *ubuf)
{
int ret;
+ struct thread_vr_state *addr;
- flush_altivec_to_thread(target);
+ if (MSR_TM_ACTIVE(target->thread.regs->msr)) {
+ flush_fp_to_thread(target);
+ flush_altivec_to_thread(target);
+ flush_tmregs_to_thread(target);
+ } else {
+ flush_altivec_to_thread(target);
+ }
BUILD_BUG_ON(offsetof(struct thread_vr_state, vscr) !=
offsetof(struct thread_vr_state, vr[32]));
+ if (MSR_TM_ACTIVE(target->thread.regs->msr))
+ addr = &target->thread.transact_vr;
+ else
+ addr = &target->thread.vr_state;
+
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
- &target->thread.vr_state, 0,
- 33 * sizeof(vector128));
+ addr, 0, 33 * sizeof(vector128));
+
if (!ret) {
/*
* Copy out only the low-order word of vrsave.
@@ -455,11 +531,14 @@ static int vr_get(struct task_struct *target, const struct user_regset *regset,
u32 word;
} vrsave;
memset(&vrsave, 0, sizeof(vrsave));
- vrsave.word = target->thread.vrsave;
+ if (MSR_TM_ACTIVE(target->thread.regs->msr))
+ vrsave.word = target->thread.transact_vrsave;
+ else
+ vrsave.word = target->thread.vrsave;
+
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &vrsave,
33 * sizeof(vector128), -1);
}
-
return ret;
}
@@ -467,16 +546,27 @@ static int vr_set(struct task_struct *target, const struct user_regset *regset,
unsigned int pos, unsigned int count,
const void *kbuf, const void __user *ubuf)
{
+ struct thread_vr_state *addr;
int ret;
- flush_altivec_to_thread(target);
+ if (MSR_TM_ACTIVE(target->thread.regs->msr)) {
+ flush_fp_to_thread(target);
+ flush_altivec_to_thread(target);
+ flush_tmregs_to_thread(target);
+ } else {
+ flush_altivec_to_thread(target);
+ }
BUILD_BUG_ON(offsetof(struct thread_vr_state, vscr) !=
offsetof(struct thread_vr_state, vr[32]));
+ if (MSR_TM_ACTIVE(target->thread.regs->msr))
+ addr = &target->thread.transact_vr;
+ else
+ addr = &target->thread.vr_state;
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
- &target->thread.vr_state, 0,
- 33 * sizeof(vector128));
+ addr, 0, 33 * sizeof(vector128));
+
if (!ret && count > 0) {
/*
* We use only the first word of vrsave.
@@ -486,13 +576,21 @@ static int vr_set(struct task_struct *target, const struct user_regset *regset,
u32 word;
} vrsave;
memset(&vrsave, 0, sizeof(vrsave));
- vrsave.word = target->thread.vrsave;
+
+ if (MSR_TM_ACTIVE(target->thread.regs->msr))
+ vrsave.word = target->thread.transact_vrsave;
+ else
+ vrsave.word = target->thread.vrsave;
+
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &vrsave,
33 * sizeof(vector128), -1);
- if (!ret)
- target->thread.vrsave = vrsave.word;
+ if (!ret) {
+ if (MSR_TM_ACTIVE(target->thread.regs->msr))
+ target->thread.transact_vrsave = vrsave.word;
+ else
+ target->thread.vrsave = vrsave.word;
+ }
}
-
return ret;
}
#endif /* CONFIG_ALTIVEC */
@@ -613,6 +711,347 @@ static int evr_set(struct task_struct *target, const struct user_regset *regset,
}
#endif /* CONFIG_SPE */
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+
+/*
+ * Transactional memory SPR
+ *
+ * struct {
+ * u64 tm_tfhar;
+ * u64 tm_texasr;
+ * u64 tm_tfiar;
+ * unsigned long tm_orig_msr;
+ * unsigned long tm_tar;
+ * unsigned long tm_ppr;
+ * unsigned long tm_dscr;
+ * };
+ */
+static int tm_spr_get(struct task_struct *target, const struct user_regset *regset,
+ unsigned int pos, unsigned int count,
+ void *kbuf, void __user *ubuf)
+{
+ int ret;
+
+ flush_fp_to_thread(target);
+ flush_altivec_to_thread(target);
+ flush_tmregs_to_thread(target);
+
+ /* TFHAR register */
+ ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+ &target->thread.tm_tfhar, 0, sizeof(u64));
+
+ BUILD_BUG_ON(offsetof(struct thread_struct, tm_tfhar) +
+ sizeof(u64) != offsetof(struct thread_struct, tm_texasr));
+
+ /* TEXASR register */
+ if (!ret)
+ ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+ &target->thread.tm_texasr, sizeof(u64), 2 * sizeof(u64));
+
+ BUILD_BUG_ON(offsetof(struct thread_struct, tm_texasr) +
+ sizeof(u64) != offsetof(struct thread_struct, tm_tfiar));
+
+ /* TFIAR register */
+ if (!ret)
+ ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+ &target->thread.tm_tfiar, 2 * sizeof(u64), 3 * sizeof(u64));
+
+ BUILD_BUG_ON(offsetof(struct thread_struct, tm_tfiar) +
+ sizeof(u64) != offsetof(struct thread_struct, tm_orig_msr));
+
+ /* TM checkpointed original MSR */
+ if (!ret)
+ ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+ &target->thread.tm_orig_msr, 3 * sizeof(u64),
+ 3 * sizeof(u64) + sizeof(unsigned long));
+
+ BUILD_BUG_ON(offsetof(struct thread_struct, tm_orig_msr) +
+ sizeof(unsigned long) + sizeof(struct pt_regs)
+ != offsetof(struct thread_struct, tm_tar));
+
+ /* TM checkpointed TAR register */
+ if (!ret)
+ ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+ &target->thread.tm_tar, 3 * sizeof(u64) +
+ sizeof(unsigned long) , 3 * sizeof(u64) +
+ 2 * sizeof(unsigned long));
+
+ BUILD_BUG_ON(offsetof(struct thread_struct, tm_tar)
+ + sizeof(unsigned long) !=
+ offsetof(struct thread_struct, tm_ppr));
+
+ /* TM checkpointed PPR register */
+ if (!ret)
+ ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+ &target->thread.tm_ppr, 3 * sizeof(u64) +
+ 2 * sizeof(unsigned long), 3 * sizeof(u64) +
+ 3 * sizeof(unsigned long));
+
+ BUILD_BUG_ON(offsetof(struct thread_struct, tm_ppr) +
+ sizeof(unsigned long) !=
+ offsetof(struct thread_struct, tm_dscr));
+
+ /* TM checkpointed DSCR register */
+ if (!ret)
+ ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+ &target->thread.tm_dscr, 3 * sizeof(u64)
+ + 3 * sizeof(unsigned long), 3 * sizeof(u64)
+ + 4 * sizeof(unsigned long));
+ return ret;
+}
+
+static int tm_spr_set(struct task_struct *target, const struct user_regset *regset,
+ unsigned int pos, unsigned int count,
+ const void *kbuf, const void __user *ubuf)
+{
+ int ret;
+
+ flush_fp_to_thread(target);
+ flush_altivec_to_thread(target);
+ flush_tmregs_to_thread(target);
+
+ /* TFHAR register */
+ ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+ &target->thread.tm_tfhar, 0, sizeof(u64));
+
+ BUILD_BUG_ON(offsetof(struct thread_struct, tm_tfhar)
+ + sizeof(u64) != offsetof(struct thread_struct, tm_texasr));
+
+ /* TEXASR register */
+ if (!ret)
+ ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+ &target->thread.tm_texasr, sizeof(u64), 2 * sizeof(u64));
+
+ BUILD_BUG_ON(offsetof(struct thread_struct, tm_texasr)
+ + sizeof(u64) != offsetof(struct thread_struct, tm_tfiar));
+
+ /* TFIAR register */
+ if (!ret)
+ ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+ &target->thread.tm_tfiar, 2 * sizeof(u64), 3 * sizeof(u64));
+
+ BUILD_BUG_ON(offsetof(struct thread_struct, tm_tfiar)
+ + sizeof(u64) != offsetof(struct thread_struct, tm_orig_msr));
+
+ /* TM checkpointed orig MSR */
+ if (!ret)
+ ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+ &target->thread.tm_orig_msr, 3 * sizeof(u64),
+ 3 * sizeof(u64) + sizeof(unsigned long));
+
+ BUILD_BUG_ON(offsetof(struct thread_struct, tm_orig_msr)
+ + sizeof(unsigned long) + sizeof(struct pt_regs) !=
+ offsetof(struct thread_struct, tm_tar));
+
+ /* TM checkpointed TAR register */
+ if (!ret)
+ ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+ &target->thread.tm_tar, 3 * sizeof(u64) +
+ sizeof(unsigned long), 3 * sizeof(u64) +
+ 2 * sizeof(unsigned long));
+
+ BUILD_BUG_ON(offsetof(struct thread_struct, tm_tar)
+ + sizeof(unsigned long) != offsetof(struct thread_struct, tm_ppr));
+
+ /* TM checkpointed PPR register */
+ if (!ret)
+ ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+ &target->thread.tm_ppr, 3 * sizeof(u64)
+ + 2 * sizeof(unsigned long), 3 * sizeof(u64)
+ + 3 * sizeof(unsigned long));
+
+ BUILD_BUG_ON(offsetof(struct thread_struct, tm_ppr) +
+ sizeof(unsigned long) !=
+ offsetof(struct thread_struct, tm_dscr));
+
+ /* TM checkpointed DSCR register */
+ if (!ret)
+ ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+ &target->thread.tm_dscr,
+ 3 * sizeof(u64) + 3 * sizeof(unsigned long),
+ 3 * sizeof(u64) + 4 * sizeof(unsigned long));
+
+ return ret;
+}
+
+/*
+ * TM Checkpointed GPR
+ *
+ * struct data {
+ * struct pt_regs ckpt_regs;
+ * };
+ */
+static int tm_cgpr_get(struct task_struct *target, const struct user_regset *regset,
+ unsigned int pos, unsigned int count,
+ void *kbuf, void __user *ubuf)
+{
+ int ret;
+
+ flush_fp_to_thread(target);
+ flush_altivec_to_thread(target);
+ flush_tmregs_to_thread(target);
+ ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+ &target->thread.ckpt_regs, 0,
+ sizeof(struct pt_regs));
+ return ret;
+}
+
+static int tm_cgpr_set(struct task_struct *target, const struct user_regset *regset,
+ unsigned int pos, unsigned int count,
+ const void *kbuf, const void __user *ubuf)
+{
+ int ret;
+
+ flush_fp_to_thread(target);
+ flush_altivec_to_thread(target);
+ flush_tmregs_to_thread(target);
+ ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+ &target->thread.ckpt_regs, 0,
+ sizeof(struct pt_regs));
+ return ret;
+}
+
+/*
+ * TM Checkpointed FPR
+ *
+ * struct data {
+ * u64 fpr[32];
+ * u64 fpscr;
+ * };
+ */
+static int tm_cfpr_get(struct task_struct *target, const struct user_regset *regset,
+ unsigned int pos, unsigned int count,
+ void *kbuf, void __user *ubuf)
+{
+#ifdef CONFIG_VSX
+ u64 buf[33];
+ int i;
+#endif
+ flush_fp_to_thread(target);
+ flush_altivec_to_thread(target);
+ flush_tmregs_to_thread(target);
+
+#ifdef CONFIG_VSX
+ /* copy to local buffer then write that out */
+ for (i = 0; i < 32 ; i++)
+ buf[i] = target->thread.TS_FPR(i);
+ buf[32] = target->thread.fp_state.fpscr;
+ return user_regset_copyout(&pos, &count, &kbuf, &ubuf, buf, 0, -1);
+
+#else
+ BUILD_BUG_ON(offsetof(struct thread_fp_state, fpscr) !=
+ offsetof(struct thread_fp_state, fpr[32][0]));
+
+ return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+ &target->thread.thread_fp_state, 0, -1);
+#endif
+}
+
+static int tm_cfpr_set(struct task_struct *target, const struct user_regset *regset,
+ unsigned int pos, unsigned int count,
+ const void *kbuf, const void __user *ubuf)
+{
+#ifdef CONFIG_VSX
+ u64 buf[33];
+ int i;
+#endif
+ flush_fp_to_thread(target);
+ flush_altivec_to_thread(target);
+ flush_tmregs_to_thread(target);
+
+#ifdef CONFIG_VSX
+ /* copy to local buffer then write that out */
+ i = user_regset_copyin(&pos, &count, &kbuf, &ubuf, buf, 0, -1);
+ if (i)
+ return i;
+ for (i = 0; i < 32 ; i++)
+ target->thread.TS_FPR(i) = buf[i];
+ target->thread.fp_state.fpscr = buf[32];
+ return 0;
+#else
+ BUILD_BUG_ON(offsetof(struct thread_fp_state, fpscr) !=
+ offsetof(struct thread_fp_state, fpr[32][0]));
+
+ return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+ &target->thread.fp_state, 0, -1);
+#endif
+}
+
+/*
+ * TM Checkpointed VMX
+ *
+ * struct data {
+ * vector128 vr[32];
+ * vector128 vscr;
+ * vector128 vrsave;
+ *};
+ */
+static int tm_cvmx_get(struct task_struct *target, const struct user_regset *regset,
+ unsigned int pos, unsigned int count,
+ void *kbuf, void __user *ubuf)
+{
+ int ret;
+
+ flush_fp_to_thread(target);
+ flush_altivec_to_thread(target);
+ flush_tmregs_to_thread(target);
+
+ BUILD_BUG_ON(offsetof(struct thread_vr_state, vscr) !=
+ offsetof(struct thread_vr_state, vr[32]));
+
+ ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+ &target->thread.vr_state, 0,
+ 33 * sizeof(vector128));
+ if (!ret) {
+ /*
+ * Copy out only the low-order word of vrsave.
+ */
+ union {
+ elf_vrreg_t reg;
+ u32 word;
+ } vrsave;
+ memset(&vrsave, 0, sizeof(vrsave));
+ vrsave.word = target->thread.vrsave;
+ ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &vrsave,
+ 33 * sizeof(vector128), -1);
+ }
+ return ret;
+}
+
+static int tm_cvmx_set(struct task_struct *target, const struct user_regset *regset,
+ unsigned int pos, unsigned int count,
+ const void *kbuf, const void __user *ubuf)
+{
+ int ret;
+
+ flush_fp_to_thread(target);
+ flush_altivec_to_thread(target);
+ flush_tmregs_to_thread(target);
+
+ BUILD_BUG_ON(offsetof(struct thread_vr_state, vscr) !=
+ offsetof(struct thread_vr_state, vr[32]));
+
+ ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+ &target->thread.vr_state, 0,
+ 33 * sizeof(vector128));
+ if (!ret && count > 0) {
+ /*
+ * We use only the first word of vrsave.
+ */
+ union {
+ elf_vrreg_t reg;
+ u32 word;
+ } vrsave;
+ memset(&vrsave, 0, sizeof(vrsave));
+ vrsave.word = target->thread.vrsave;
+ ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &vrsave,
+ 33 * sizeof(vector128), -1);
+ if (!ret)
+ target->thread.vrsave = vrsave.word;
+ }
+ return ret;
+}
+#endif /* CONFIG_PPC_TRANSACTIONAL_MEM */
/*
* These are our native regset flavors.
@@ -629,6 +1068,12 @@ enum powerpc_regset {
#ifdef CONFIG_SPE
REGSET_SPE,
#endif
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+ REGSET_TM_SPR, /* TM specific SPR */
+ REGSET_TM_CGPR, /* TM checkpointed GPR */
+ REGSET_TM_CFPR, /* TM checkpointed FPR */
+ REGSET_TM_CVMX, /* TM checkpointed VMX */
+#endif
};
static const struct user_regset native_regsets[] = {
@@ -663,6 +1108,28 @@ static const struct user_regset native_regsets[] = {
.active = evr_active, .get = evr_get, .set = evr_set
},
#endif
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+ [REGSET_TM_SPR] = {
+ .core_note_type = NT_PPC_TM_SPR, .n = 7,
+ .size = sizeof(u64), .align = sizeof(u64),
+ .get = tm_spr_get, .set = tm_spr_set
+ },
+ [REGSET_TM_CGPR] = {
+ .core_note_type = NT_PPC_TM_CGPR, .n = ELF_NGREG,
+ .size = sizeof(long), .align = sizeof(long),
+ .get = tm_cgpr_get, .set = tm_cgpr_set
+ },
+ [REGSET_TM_CFPR] = {
+ .core_note_type = NT_PPC_TM_CFPR, .n = ELF_NFPREG,
+ .size = sizeof(double), .align = sizeof(double),
+ .get = tm_cfpr_get, .set = tm_cfpr_set
+ },
+ [REGSET_TM_CVMX] = {
+ .core_note_type = NT_PPC_TM_CVMX, .n = 34,
+ .size = sizeof(vector128), .align = sizeof(vector128),
+ .get = tm_cvmx_get, .set = tm_cvmx_set
+ },
+#endif
};
static const struct user_regset_view user_ppc_native_view = {
@@ -803,6 +1270,145 @@ static int gpr32_set(struct task_struct *target,
(PT_TRAP + 1) * sizeof(reg), -1);
}
+static int tm_cgpr32_get(struct task_struct *target,
+ const struct user_regset *regset,
+ unsigned int pos, unsigned int count,
+ void *kbuf, void __user *ubuf)
+{
+ const unsigned long *regs = &target->thread.ckpt_regs.gpr[0];
+ compat_ulong_t *k = kbuf;
+ compat_ulong_t __user *u = ubuf;
+ compat_ulong_t reg;
+ int i;
+
+ flush_fp_to_thread(target);
+ flush_altivec_to_thread(target);
+ flush_tmregs_to_thread(target);
+
+ if (target->thread.regs == NULL)
+ return -EIO;
+
+ if (!FULL_REGS(target->thread.regs)) {
+ /* We have a partial register set. Fill 14-31 with bogus values */
+ for (i = 14; i < 32; i++)
+ target->thread.regs->gpr[i] = NV_REG_POISON;
+ }
+
+ pos /= sizeof(reg);
+ count /= sizeof(reg);
+
+ if (kbuf)
+ for (; count > 0 && pos < PT_MSR; --count)
+ *k++ = regs[pos++];
+ else
+ for (; count > 0 && pos < PT_MSR; --count)
+ if (__put_user((compat_ulong_t) regs[pos++], u++))
+ return -EFAULT;
+
+ if (count > 0 && pos == PT_MSR) {
+ reg = get_user_msr(target);
+ if (kbuf)
+ *k++ = reg;
+ else if (__put_user(reg, u++))
+ return -EFAULT;
+ ++pos;
+ --count;
+ }
+
+ if (kbuf)
+ for (; count > 0 && pos < PT_REGS_COUNT; --count)
+ *k++ = regs[pos++];
+ else
+ for (; count > 0 && pos < PT_REGS_COUNT; --count)
+ if (__put_user((compat_ulong_t) regs[pos++], u++))
+ return -EFAULT;
+
+ kbuf = k;
+ ubuf = u;
+ pos *= sizeof(reg);
+ count *= sizeof(reg);
+ return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
+ PT_REGS_COUNT * sizeof(reg), -1);
+}
+
+static int tm_cgpr32_set(struct task_struct *target,
+ const struct user_regset *regset,
+ unsigned int pos, unsigned int count,
+ const void *kbuf, const void __user *ubuf)
+{
+ unsigned long *regs = &target->thread.ckpt_regs.gpr[0];
+ const compat_ulong_t *k = kbuf;
+ const compat_ulong_t __user *u = ubuf;
+ compat_ulong_t reg;
+
+ flush_fp_to_thread(target);
+ flush_altivec_to_thread(target);
+ flush_tmregs_to_thread(target);
+
+ if (target->thread.regs == NULL)
+ return -EIO;
+
+ CHECK_FULL_REGS(target->thread.regs);
+
+ pos /= sizeof(reg);
+ count /= sizeof(reg);
+
+ if (kbuf)
+ for (; count > 0 && pos < PT_MSR; --count)
+ regs[pos++] = *k++;
+ else
+ for (; count > 0 && pos < PT_MSR; --count) {
+ if (__get_user(reg, u++))
+ return -EFAULT;
+ regs[pos++] = reg;
+ }
+
+
+ if (count > 0 && pos == PT_MSR) {
+ if (kbuf)
+ reg = *k++;
+ else if (__get_user(reg, u++))
+ return -EFAULT;
+ set_user_msr(target, reg);
+ ++pos;
+ --count;
+ }
+
+ if (kbuf) {
+ for (; count > 0 && pos <= PT_MAX_PUT_REG; --count)
+ regs[pos++] = *k++;
+ for (; count > 0 && pos < PT_TRAP; --count, ++pos)
+ ++k;
+ } else {
+ for (; count > 0 && pos <= PT_MAX_PUT_REG; --count) {
+ if (__get_user(reg, u++))
+ return -EFAULT;
+ regs[pos++] = reg;
+ }
+ for (; count > 0 && pos < PT_TRAP; --count, ++pos)
+ if (__get_user(reg, u++))
+ return -EFAULT;
+ }
+
+ if (count > 0 && pos == PT_TRAP) {
+ if (kbuf)
+ reg = *k++;
+ else if (__get_user(reg, u++))
+ return -EFAULT;
+ set_user_trap(target, reg);
+ ++pos;
+ --count;
+ }
+
+ kbuf = k;
+ ubuf = u;
+ pos *= sizeof(reg);
+ count *= sizeof(reg);
+ return user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
+ (PT_TRAP + 1) * sizeof(reg), -1);
+}
+
+
/*
* These are the regset flavors matching the CONFIG_PPC32 native set.
*/
@@ -831,6 +1437,28 @@ static const struct user_regset compat_regsets[] = {
.active = evr_active, .get = evr_get, .set = evr_set
},
#endif
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+ [REGSET_TM_SPR] = {
+ .core_note_type = NT_PPC_TM_SPR, .n = 7,
+ .size = sizeof(u64), .align = sizeof(u64),
+ .get = tm_spr_get, .set = tm_spr_set
+ },
+ [REGSET_TM_CGPR] = {
+ .core_note_type = NT_PPC_TM_CGPR, .n = ELF_NGREG,
+ .size = sizeof(long), .align = sizeof(long),
+ .get = tm_cgpr32_get, .set = tm_cgpr32_set
+ },
+ [REGSET_TM_CFPR] = {
+ .core_note_type = NT_PPC_TM_CFPR, .n = ELF_NFPREG,
+ .size = sizeof(double), .align = sizeof(double),
+ .get = tm_cfpr_get, .set = tm_cfpr_set
+ },
+ [REGSET_TM_CVMX] = {
+ .core_note_type = NT_PPC_TM_CVMX, .n = 34,
+ .size = sizeof(vector128), .align = sizeof(vector128),
+ .get = tm_cvmx_get, .set = tm_cvmx_set
+ },
+#endif
};
static const struct user_regset_view user_ppc_compat_view = {
@@ -1754,7 +2382,6 @@ long arch_ptrace(struct task_struct *child, long request,
REGSET_SPE, 0, 35 * sizeof(u32),
datavp);
#endif
-
default:
ret = ptrace_request(child, request, addr, data);
break;
--
1.7.11.7
^ permalink raw reply related
* [PATCH V2 3/3] powerpc, ptrace: Enable support for miscellaneous registers
From: Anshuman Khandual @ 2014-05-05 7:54 UTC (permalink / raw)
To: linuxppc-dev, linux-kernel
Cc: mikey, avagin, palves, oleg, michael, roland, Anshuman Khandual
In-Reply-To: <1399276469-13541-1-git-send-email-khandual@linux.vnet.ibm.com>
This patch enables get and set of miscellaneous registers through ptrace
PTRACE_GETREGSET/PTRACE_SETREGSET interface by implementing new powerpc
specific register set REGSET_MISC support corresponding to the new ELF
core note NT_PPC_MISC added previously in this regard.
Signed-off-by: Anshuman Khandual <khandual@linux.vnet.ibm.com>
---
arch/powerpc/kernel/ptrace.c | 81 ++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 81 insertions(+)
diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c
index 92faded..3332dd8 100644
--- a/arch/powerpc/kernel/ptrace.c
+++ b/arch/powerpc/kernel/ptrace.c
@@ -1054,6 +1054,76 @@ static int tm_cvmx_set(struct task_struct *target, const struct user_regset *reg
#endif /* CONFIG_PPC_TRANSACTIONAL_MEM */
/*
+ * Miscellaneous Registers
+ *
+ * struct {
+ * unsigned long dscr;
+ * unsigned long ppr;
+ * unsigned long tar;
+ * };
+ */
+static int misc_get(struct task_struct *target, const struct user_regset *regset,
+ unsigned int pos, unsigned int count,
+ void *kbuf, void __user *ubuf)
+{
+ int ret;
+
+ /* DSCR register */
+ ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+ &target->thread.dscr, 0,
+ sizeof(unsigned long));
+
+ BUILD_BUG_ON(offsetof(struct thread_struct, dscr) + sizeof(unsigned long) +
+ sizeof(unsigned long) != offsetof(struct thread_struct, ppr));
+
+ /* PPR register */
+ if (!ret)
+ ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+ &target->thread.ppr, sizeof(unsigned long),
+ 2 * sizeof(unsigned long));
+
+ BUILD_BUG_ON(offsetof(struct thread_struct, ppr) + sizeof(unsigned long)
+ != offsetof(struct thread_struct, tar));
+ /* TAR register */
+ if (!ret)
+ ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+ &target->thread.tar, 2 * sizeof(unsigned long),
+ 3 * sizeof(unsigned long));
+ return ret;
+}
+
+static int misc_set(struct task_struct *target, const struct user_regset *regset,
+ unsigned int pos, unsigned int count,
+ const void *kbuf, const void __user *ubuf)
+{
+ int ret;
+
+ /* DSCR register */
+ ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+ &target->thread.dscr, 0,
+ sizeof(unsigned long));
+
+ BUILD_BUG_ON(offsetof(struct thread_struct, dscr) + sizeof(unsigned long) +
+ sizeof(unsigned long) != offsetof(struct thread_struct, ppr));
+
+ /* PPR register */
+ if (!ret)
+ ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+ &target->thread.ppr, sizeof(unsigned long),
+ 2 * sizeof(unsigned long));
+
+ BUILD_BUG_ON(offsetof(struct thread_struct, ppr) + sizeof(unsigned long)
+ != offsetof(struct thread_struct, tar));
+
+ /* TAR register */
+ if (!ret)
+ ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+ &target->thread.tar, 2 * sizeof(unsigned long),
+ 3 * sizeof(unsigned long));
+ return ret;
+}
+
+/*
* These are our native regset flavors.
*/
enum powerpc_regset {
@@ -1074,6 +1144,7 @@ enum powerpc_regset {
REGSET_TM_CFPR, /* TM checkpointed FPR */
REGSET_TM_CVMX, /* TM checkpointed VMX */
#endif
+ REGSET_MISC /* Miscellaneous */
};
static const struct user_regset native_regsets[] = {
@@ -1130,6 +1201,11 @@ static const struct user_regset native_regsets[] = {
.get = tm_cvmx_get, .set = tm_cvmx_set
},
#endif
+ [REGSET_MISC] = {
+ .core_note_type = NT_PPC_MISC, .n = 3,
+ .size = sizeof(u64), .align = sizeof(u64),
+ .get = misc_get, .set = misc_set
+ },
};
static const struct user_regset_view user_ppc_native_view = {
@@ -1459,6 +1535,11 @@ static const struct user_regset compat_regsets[] = {
.get = tm_cvmx_get, .set = tm_cvmx_set
},
#endif
+ [REGSET_MISC] = {
+ .core_note_type = NT_PPC_MISC, .n = 3,
+ .size = sizeof(u64), .align = sizeof(u64),
+ .get = misc_get, .set = misc_set
+ },
};
static const struct user_regset_view user_ppc_compat_view = {
--
1.7.11.7
^ permalink raw reply related
* [V6 08/11] powerpc, lib: Add new branch analysis support functions
From: Anshuman Khandual @ 2014-05-05 9:09 UTC (permalink / raw)
To: linuxppc-dev, linux-kernel
Cc: mikey, ak, eranian, michael, acme, sukadev, mingo
In-Reply-To: <1399280953-31442-1-git-send-email-khandual@linux.vnet.ibm.com>
Generic powerpc branch analysis support added in the code patching
library which will help the subsequent patch on SW based filtering
of branch records in perf.
Signed-off-by: Anshuman Khandual <khandual@linux.vnet.ibm.com>
---
arch/powerpc/include/asm/code-patching.h | 16 +++++++
arch/powerpc/lib/code-patching.c | 80 ++++++++++++++++++++++++++++++++
2 files changed, 96 insertions(+)
diff --git a/arch/powerpc/include/asm/code-patching.h b/arch/powerpc/include/asm/code-patching.h
index 97e02f9..39919d4 100644
--- a/arch/powerpc/include/asm/code-patching.h
+++ b/arch/powerpc/include/asm/code-patching.h
@@ -22,6 +22,16 @@
#define BRANCH_SET_LINK 0x1
#define BRANCH_ABSOLUTE 0x2
+#define XL_FORM_LR 0x4C000020
+#define XL_FORM_CTR 0x4C000420
+#define XL_FORM_TAR 0x4C000460
+
+#define BO_ALWAYS 0x02800000
+#define BO_CTR 0x02000000
+#define BO_CRBI_OFF 0x00800000
+#define BO_CRBI_ON 0x01800000
+#define BO_CRBI_HINT 0x00400000
+
unsigned int create_branch(const unsigned int *addr,
unsigned long target, int flags);
unsigned int create_cond_branch(const unsigned int *addr,
@@ -56,4 +66,10 @@ static inline unsigned long ppc_function_entry(void *func)
#endif
}
+/* Perf branch filters */
+bool instr_is_return_branch(unsigned int instr);
+bool instr_is_conditional_branch(unsigned int instr);
+bool instr_is_func_call(unsigned int instr);
+bool instr_is_indirect_func_call(unsigned int instr);
+
#endif /* _ASM_POWERPC_CODE_PATCHING_H */
diff --git a/arch/powerpc/lib/code-patching.c b/arch/powerpc/lib/code-patching.c
index d5edbeb..a06f8b3 100644
--- a/arch/powerpc/lib/code-patching.c
+++ b/arch/powerpc/lib/code-patching.c
@@ -77,6 +77,7 @@ static unsigned int branch_opcode(unsigned int instr)
return (instr >> 26) & 0x3F;
}
+/* Forms of branch instruction */
static int instr_is_branch_iform(unsigned int instr)
{
return branch_opcode(instr) == 18;
@@ -87,6 +88,85 @@ static int instr_is_branch_bform(unsigned int instr)
return branch_opcode(instr) == 16;
}
+static int instr_is_branch_xlform(unsigned int instr)
+{
+ return branch_opcode(instr) == 19;
+}
+
+/* Classification of XL-form instruction */
+static int is_xlform_lr(unsigned int instr)
+{
+ return (instr & XL_FORM_LR) == XL_FORM_LR;
+}
+
+/* BO field analysis (B-form or XL-form) */
+static int is_bo_always(unsigned int instr)
+{
+ return (instr & BO_ALWAYS) == BO_ALWAYS;
+}
+
+/* Link bit is set */
+static int is_branch_link_set(unsigned int instr)
+{
+ return (instr & BRANCH_SET_LINK) == BRANCH_SET_LINK;
+}
+
+/*
+ * Generic software implemented branch filters used
+ * by perf branch stack sampling when PMU does not
+ * process them for some reason.
+ */
+
+/* PERF_SAMPLE_BRANCH_ANY_RETURN */
+bool instr_is_return_branch(unsigned int instr)
+{
+ /*
+ * Conditional and unconditional branch to LR register
+ * without seting the link register.
+ */
+ if (is_xlform_lr(instr) && !is_branch_link_set(instr))
+ return true;
+
+ return false;
+}
+
+/* PERF_SAMPLE_BRANCH_COND */
+bool instr_is_conditional_branch(unsigned int instr)
+{
+ /* I-form instruction - excluded */
+ if (instr_is_branch_iform(instr))
+ return false;
+
+ /* B-form or XL-form instruction */
+ if (instr_is_branch_bform(instr) || instr_is_branch_xlform(instr)) {
+
+ /* Not branch always */
+ if (!is_bo_always(instr))
+ return true;
+ }
+ return false;
+}
+
+/* PERF_SAMPLE_BRANCH_ANY_CALL */
+bool instr_is_func_call(unsigned int instr)
+{
+ /* LR should be set */
+ if (is_branch_link_set(instr))
+ return true;
+
+ return false;
+}
+
+/* PERF_SAMPLE_BRANCH_IND_CALL */
+bool instr_is_indirect_func_call(unsigned int instr)
+{
+ /* XL-form instruction with LR set */
+ if (instr_is_branch_xlform(instr) && is_branch_link_set(instr))
+ return true;
+
+ return false;
+}
+
int instr_is_relative_branch(unsigned int instr)
{
if (instr & BRANCH_ABSOLUTE)
--
1.7.11.7
^ permalink raw reply related
* [V6 02/11] perf, tool: Conditional branch filter 'cond' added to perf record
From: Anshuman Khandual @ 2014-05-05 9:09 UTC (permalink / raw)
To: linuxppc-dev, linux-kernel
Cc: mikey, ak, eranian, michael, acme, sukadev, mingo
In-Reply-To: <1399280953-31442-1-git-send-email-khandual@linux.vnet.ibm.com>
Adding perf record support for new branch stack filter criteria
PERF_SAMPLE_BRANCH_COND.
Signed-off-by: Anshuman Khandual <khandual@linux.vnet.ibm.com>
Reviewed-by: Stephane Eranian <eranian@google.com>
Reviewed-by: Andi Kleen <ak@linux.intel.com>
---
tools/perf/builtin-record.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 8ce62ef..dfe6b9d 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -583,6 +583,7 @@ static const struct branch_mode branch_modes[] = {
BRANCH_OPT("abort_tx", PERF_SAMPLE_BRANCH_ABORT_TX),
BRANCH_OPT("in_tx", PERF_SAMPLE_BRANCH_IN_TX),
BRANCH_OPT("no_tx", PERF_SAMPLE_BRANCH_NO_TX),
+ BRANCH_OPT("cond", PERF_SAMPLE_BRANCH_COND),
BRANCH_END
};
--
1.7.11.7
^ permalink raw reply related
* [V6 03/11] x86, perf: Add conditional branch filtering support
From: Anshuman Khandual @ 2014-05-05 9:09 UTC (permalink / raw)
To: linuxppc-dev, linux-kernel
Cc: mikey, ak, eranian, michael, acme, sukadev, mingo
In-Reply-To: <1399280953-31442-1-git-send-email-khandual@linux.vnet.ibm.com>
This patch adds conditional branch filtering support,
enabling it for PERF_SAMPLE_BRANCH_COND in perf branch
stack sampling framework by utilizing an available
software filter X86_BR_JCC.
Signed-off-by: Anshuman Khandual <khandual@linux.vnet.ibm.com>
Reviewed-by: Stephane Eranian <eranian@google.com>
Reviewed-by: Andi Kleen <ak@linux.intel.com>
---
arch/x86/kernel/cpu/perf_event_intel_lbr.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/arch/x86/kernel/cpu/perf_event_intel_lbr.c b/arch/x86/kernel/cpu/perf_event_intel_lbr.c
index d82d155..9dd2459 100644
--- a/arch/x86/kernel/cpu/perf_event_intel_lbr.c
+++ b/arch/x86/kernel/cpu/perf_event_intel_lbr.c
@@ -384,6 +384,9 @@ static void intel_pmu_setup_sw_lbr_filter(struct perf_event *event)
if (br_type & PERF_SAMPLE_BRANCH_NO_TX)
mask |= X86_BR_NO_TX;
+ if (br_type & PERF_SAMPLE_BRANCH_COND)
+ mask |= X86_BR_JCC;
+
/*
* stash actual user request into reg, it may
* be used by fixup code for some CPU
@@ -678,6 +681,7 @@ static const int nhm_lbr_sel_map[PERF_SAMPLE_BRANCH_MAX] = {
* NHM/WSM erratum: must include IND_JMP to capture IND_CALL
*/
[PERF_SAMPLE_BRANCH_IND_CALL] = LBR_IND_CALL | LBR_IND_JMP,
+ [PERF_SAMPLE_BRANCH_COND] = LBR_JCC,
};
static const int snb_lbr_sel_map[PERF_SAMPLE_BRANCH_MAX] = {
@@ -689,6 +693,7 @@ static const int snb_lbr_sel_map[PERF_SAMPLE_BRANCH_MAX] = {
[PERF_SAMPLE_BRANCH_ANY_CALL] = LBR_REL_CALL | LBR_IND_CALL
| LBR_FAR,
[PERF_SAMPLE_BRANCH_IND_CALL] = LBR_IND_CALL,
+ [PERF_SAMPLE_BRANCH_COND] = LBR_JCC,
};
/* core */
--
1.7.11.7
^ permalink raw reply related
* [V6 09/11] powerpc, perf: Enable SW filtering in branch stack sampling framework
From: Anshuman Khandual @ 2014-05-05 9:09 UTC (permalink / raw)
To: linuxppc-dev, linux-kernel
Cc: mikey, ak, eranian, michael, acme, sukadev, mingo
In-Reply-To: <1399280953-31442-1-git-send-email-khandual@linux.vnet.ibm.com>
This patch enables SW based post processing of BHRB captured branches
to be able to meet more user defined branch filtration criteria in perf
branch stack sampling framework. These changes increase the number of
branch filters and their valid combinations on any powerpc64 server
platform with BHRB support. Find the summary of code changes here.
(1) struct cpu_hw_events
Introduced two new variables track various filter values and mask
(a) bhrb_sw_filter Tracks SW implemented branch filter flags
(b) bhrb_filter Tracks both (SW and HW) branch filter flags
(2) Event creation
Kernel will figure out supported BHRB branch filters through a PMU call
back 'bhrb_filter_map'. This function will find out how many of the
requested branch filters can be supported in the PMU HW. It will not
try to invalidate any branch filter combinations. Event creation will not
error out because of lack of HW based branch filters. Meanwhile it will
track the overall supported branch filters in the 'bhrb_filter' variable.
Once the PMU call back returns kernel will process the user branch filter
request against available SW filters (bhrb_sw_filter_map) while looking
at the 'bhrb_filter'. During this phase all the branch filters which are
still pending from the user requested list will have to be supported in
SW failing which the event creation will error out.
(3) SW branch filter
During the BHRB data capture inside the PMU interrupt context, each
of the captured 'perf_branch_entry.from' will be checked for compliance
with applicable SW branch filters. If the entry does not conform to the
filter requirements, it will be discarded from the final perf branch
stack buffer.
(4) Supported SW based branch filters
(a) PERF_SAMPLE_BRANCH_ANY_RETURN
(b) PERF_SAMPLE_BRANCH_IND_CALL
(c) PERF_SAMPLE_BRANCH_ANY_CALL
(d) PERF_SAMPLE_BRANCH_COND
Please refer the patch to understand the classification of instructions
into these branch filter categories.
(5) Multiple branch filter semantics
Book3 sever implementation follows the same OR semantics (as implemented in
x86) while dealing with multiple branch filters at any point of time. SW
branch filter analysis is carried on the data set captured in the PMU HW.
So the resulting set of data (after applying the SW filters) will inherently
be an AND with the HW captured set. Hence any combination of HW and SW branch
filters will be invalid. HW based branch filters are more efficient and faster
compared to SW implemented branch filters. So at first the PMU should decide
whether it can support all the requested branch filters itself or not. In case
it can support all the branch filters in an OR manner, we dont apply any SW
branch filter on top of the HW captured set (which is the final set). This
preserves the OR semantic of multiple branch filters as required. But in case
where the PMU cannot support all the requested branch filters in an OR manner,
it should not apply any it's filters and leave it upto the SW to handle them
all. Its the PMU code's responsibility to uphold this protocol to be able to
conform to the overall OR semantic of perf branch stack sampling framework.
Signed-off-by: Anshuman Khandual <khandual@linux.vnet.ibm.com>
---
arch/powerpc/include/asm/perf_event_server.h | 6 +-
arch/powerpc/perf/core-book3s.c | 188 ++++++++++++++++++++++++++-
arch/powerpc/perf/power8-pmu.c | 2 +-
3 files changed, 187 insertions(+), 9 deletions(-)
diff --git a/arch/powerpc/include/asm/perf_event_server.h b/arch/powerpc/include/asm/perf_event_server.h
index 9ed73714..93a9a8a 100644
--- a/arch/powerpc/include/asm/perf_event_server.h
+++ b/arch/powerpc/include/asm/perf_event_server.h
@@ -19,6 +19,10 @@
#define MAX_EVENT_ALTERNATIVES 8
#define MAX_LIMITED_HWCOUNTERS 2
+#define for_each_branch_sample_type(x) \
+ for ((x) = PERF_SAMPLE_BRANCH_USER; \
+ (x) < PERF_SAMPLE_BRANCH_MAX; (x) <<= 1)
+
/*
* This struct provides the constants and functions needed to
* describe the PMU on a particular POWER-family CPU.
@@ -35,7 +39,7 @@ struct power_pmu {
unsigned long *valp);
int (*get_alternatives)(u64 event_id, unsigned int flags,
u64 alt[]);
- u64 (*bhrb_filter_map)(u64 branch_sample_type);
+ u64 (*bhrb_filter_map)(u64 branch_sample_type, u64 *bhrb_filter);
void (*config_bhrb)(u64 pmu_bhrb_filter);
void (*disable_pmc)(unsigned int pmc, unsigned long mmcr[]);
int (*limited_pmc_event)(u64 event_id);
diff --git a/arch/powerpc/perf/core-book3s.c b/arch/powerpc/perf/core-book3s.c
index 1d7e909..a94cc43 100644
--- a/arch/powerpc/perf/core-book3s.c
+++ b/arch/powerpc/perf/core-book3s.c
@@ -46,8 +46,9 @@ struct cpu_hw_events {
unsigned int group_flag;
int n_txn_start;
- /* BHRB bits */
u64 bhrb_hw_filter; /* BHRB HW branch filter */
+ u64 bhrb_sw_filter; /* BHRB SW branch filter */
+ u64 bhrb_filter; /* Branch filter mask */
int bhrb_users;
void *bhrb_context;
struct perf_branch_stack bhrb_stack;
@@ -412,6 +413,152 @@ void update_branch_entry(struct cpu_hw_events *cpuhw, int u_index, u64 from, u64
return;
}
+/*
+ * Instruction opcode analysis
+ *
+ * Analyse instruction opcodes and classify them
+ * into various branch filter options available.
+ * This follows the standard semantics of OR which
+ * means that instructions which conforms to `any`
+ * of the requested branch filters get picked up.
+ */
+static bool check_instruction(unsigned int *addr, u64 sw_filter)
+{
+ if (sw_filter & PERF_SAMPLE_BRANCH_ANY_RETURN) {
+ if (instr_is_return_branch(*addr))
+ return true;
+ }
+
+ if (sw_filter & PERF_SAMPLE_BRANCH_IND_CALL) {
+ if (instr_is_indirect_func_call(*addr))
+ return true;
+ }
+
+ if (sw_filter & PERF_SAMPLE_BRANCH_ANY_CALL) {
+ if (instr_is_func_call(*addr))
+ return true;
+ }
+
+ if (sw_filter & PERF_SAMPLE_BRANCH_COND) {
+ if (instr_is_conditional_branch(*addr))
+ return true;
+ }
+ return false;
+}
+
+/*
+ * Access the instruction contained in the address and check
+ * whether it complies with the applicable SW branch filters.
+ */
+static bool keep_branch(u64 from, u64 sw_filter)
+{
+ unsigned int instr;
+ bool ret;
+
+ /*
+ * The "from" branch for every branch record has to go
+ * through this filter verification. So this quick check
+ * here for no SW filters will improve performance.
+ */
+ if (sw_filter == 0)
+ return true;
+
+ if (is_kernel_addr(from)) {
+ return check_instruction((unsigned int *) from, sw_filter);
+ } else {
+ /*
+ * Userspace address needs to be
+ * copied first before analysis.
+ */
+ pagefault_disable();
+ ret = __get_user_inatomic(instr, (unsigned int __user *) from);
+
+ /*
+ * If the instruction could not be accessible
+ * from user space, we still 'okay' the entry.
+ */
+ if (ret) {
+ pagefault_enable();
+ return true;
+ }
+ pagefault_enable();
+ return check_instruction(&instr, sw_filter);
+ }
+}
+
+/*
+ * Validate whether all the requested branch filters
+ * are getting processed either in the PMU or in SW.
+ */
+static int all_filters_covered(u64 branch_sample_type, u64 bhrb_filter)
+{
+ u64 x;
+
+ if (bhrb_filter == PERF_SAMPLE_BRANCH_ANY)
+ return true;
+
+ for_each_branch_sample_type(x) {
+ if (!(branch_sample_type & x))
+ continue;
+ /*
+ * Privilege filter requests have been already
+ * taken care during the base PMU configuration.
+ */
+ if ((x == PERF_SAMPLE_BRANCH_USER)
+ || (x == PERF_SAMPLE_BRANCH_KERNEL)
+ || (x == PERF_SAMPLE_BRANCH_HV))
+ continue;
+
+ /*
+ * Requested filter not available either
+ * in PMU or in SW.
+ */
+ if (!(bhrb_filter & x))
+ return false;
+ }
+ return true;
+}
+
+/* SW implemented branch filters */
+static unsigned int power_sw_filter[] = { PERF_SAMPLE_BRANCH_ANY_CALL,
+ PERF_SAMPLE_BRANCH_COND,
+ PERF_SAMPLE_BRANCH_ANY_RETURN,
+ PERF_SAMPLE_BRANCH_IND_CALL };
+
+/*
+ * Required SW based branch filters
+ *
+ * This is called after figuring out what all branch filters the
+ * PMU HW supports for the requested branch filter set. Here we
+ * will go through all the SW implemented branch filters one by
+ * one and pick them up if its not already supported in the PMU.
+ */
+static u64 bhrb_sw_filter_map(u64 branch_sample_type, u64 *bhrb_filter)
+{
+ u64 branch_sw_filter = 0;
+ unsigned int i;
+
+ if (branch_sample_type & PERF_SAMPLE_BRANCH_ANY) {
+ WARN_ON(*bhrb_filter != PERF_SAMPLE_BRANCH_ANY);
+ return branch_sw_filter;
+ }
+
+ /*
+ * PMU supported branch filters must be implemented in SW
+ * when the PMU is unable to process them for some reason.
+ */
+ for (i = 0; i < ARRAY_SIZE(power_sw_filter); i++) {
+ if (branch_sample_type & power_sw_filter[i]) {
+ if (!(*bhrb_filter & power_sw_filter[i])) {
+ branch_sw_filter |= power_sw_filter[i];
+ *bhrb_filter |= power_sw_filter[i];
+ }
+ }
+ }
+
+ return branch_sw_filter;
+}
+
/* Processing BHRB entries */
void power_pmu_bhrb_read(struct cpu_hw_events *cpuhw)
{
@@ -474,6 +621,11 @@ void power_pmu_bhrb_read(struct cpu_hw_events *cpuhw)
tmp = power_pmu_bhrb_to(addr);
update_branch_entry(cpuhw, u_index, addr, tmp, pred);
}
+
+ /* Apply SW branch filters and drop the entry if required */
+ if (!keep_branch(cpuhw->bhrb_entries[u_index].from,
+ cpuhw->bhrb_sw_filter))
+ u_index--;
u_index++;
}
cpuhw->bhrb_stack.nr = u_index;
@@ -1297,6 +1449,8 @@ static void power_pmu_enable(struct pmu *pmu)
mmcr0 = ebb_switch_in(ebb, cpuhw->mmcr[0]);
mb();
+
+ /* Enable PMU based branch filters */
if (cpuhw->bhrb_users)
ppmu->config_bhrb(cpuhw->bhrb_hw_filter);
@@ -1405,8 +1559,12 @@ nocheck:
out:
if (has_branch_stack(event)) {
power_pmu_bhrb_enable(event);
- cpuhw->bhrb_hw_filter = ppmu->bhrb_filter_map(
- event->attr.branch_sample_type);
+ cpuhw->bhrb_hw_filter = ppmu->bhrb_filter_map
+ (event->attr.branch_sample_type,
+ &cpuhw->bhrb_filter);
+ cpuhw->bhrb_sw_filter = bhrb_sw_filter_map
+ (event->attr.branch_sample_type,
+ &cpuhw->bhrb_filter);
}
perf_pmu_enable(event->pmu);
@@ -1787,11 +1945,27 @@ static int power_pmu_event_init(struct perf_event *event)
cpuhw = &get_cpu_var(cpu_hw_events);
err = power_check_constraints(cpuhw, events, cflags, n + 1);
+ /*
+ * BHRB branch filters implemented in PMU will take
+ * effect when we enable the event and data set
+ * collected thereafter will be compliant with those
+ * branch filters. Where as the SW branch filters will
+ * be applied during the post processing of BHRB data.
+ */
if (has_branch_stack(event)) {
- cpuhw->bhrb_hw_filter = ppmu->bhrb_filter_map(
- event->attr.branch_sample_type);
-
- if(cpuhw->bhrb_hw_filter == -1)
+ /* Query available PMU branch filter support */
+ cpuhw->bhrb_hw_filter = ppmu->bhrb_filter_map
+ (event->attr.branch_sample_type,
+ &cpuhw->bhrb_filter);
+
+ /* Query available SW branch filter support */
+ cpuhw->bhrb_sw_filter = bhrb_sw_filter_map
+ (event->attr.branch_sample_type,
+ &cpuhw->bhrb_filter);
+
+ /* Check overall coverage of branch filter request */
+ if(!all_filters_covered(event->attr.branch_sample_type,
+ cpuhw->bhrb_filter))
return -EOPNOTSUPP;
}
diff --git a/arch/powerpc/perf/power8-pmu.c b/arch/powerpc/perf/power8-pmu.c
index 13f47f5..699b1dd 100644
--- a/arch/powerpc/perf/power8-pmu.c
+++ b/arch/powerpc/perf/power8-pmu.c
@@ -633,7 +633,7 @@ static int power8_generic_events[] = {
[PERF_COUNT_HW_CACHE_MISSES] = PM_LD_MISS_L1,
};
-static u64 power8_bhrb_filter_map(u64 branch_sample_type)
+static u64 power8_bhrb_filter_map(u64 branch_sample_type, u64 *bhrb_filter)
{
/* BHRB and regular PMU events share the same privilege state
* filter configuration. BHRB is always recorded along with a
--
1.7.11.7
^ permalink raw reply related
* [V6 00/11] perf: New conditional branch filter
From: Anshuman Khandual @ 2014-05-05 9:09 UTC (permalink / raw)
To: linuxppc-dev, linux-kernel
Cc: mikey, ak, eranian, michael, acme, sukadev, mingo
This patchset is the re-spin of the original branch stack sampling
patchset which introduced new PERF_SAMPLE_BRANCH_COND branch filter. This patchset
also enables SW based branch filtering support for book3s powerpc platforms which
have PMU HW backed branch stack sampling support.
Summary of code changes in this patchset:
(1) Introduces a new PERF_SAMPLE_BRANCH_COND branch filter
(2) Add the "cond" branch filter options in the "perf record" tool
(3) Enable PERF_SAMPLE_BRANCH_COND in X86 platforms
(4) Enable PERF_SAMPLE_BRANCH_COND in POWER8 platform
(5) Update the documentation regarding "perf record" tool
(6) Add some new powerpc instruction analysis functions in code-patching library
(7) Enable SW based branch filter support for powerpc book3s
(8) Changed BHRB configuration in POWER8 to accommodate SW branch filters
With this new SW enablement, the branch filter support for book3s platforms have
been extended to include all these combinations discussed below with a sample test
application program (included here).
Changes in V2
=============
(1) Enabled PPC64 SW branch filtering support
(2) Incorporated changes required for all previous comments
Changes in V3
=============
(1) Split the SW branch filter enablement into multiple patches
(2) Added PMU neutral SW branch filtering code, PMU specific HW branch filtering code
(3) Added new instruction analysis functionality into powerpc code-patching library
(4) Changed name for some of the functions
(5) Fixed couple of spelling mistakes
(6) Changed code documentation in multiple places
Changes in V4
=============
(1) Changed the commit message for patch (01/10)
(2) Changed the patch (02/10) to accommodate review comments from Michael Ellerman
(3) Rebased the patchset against latest Linus's tree
Changes in V5
=============
(1) Added a precursor patch to cleanup the indentation problem in power_pmu_bhrb_read
(2) Added a precursor patch to re-arrange P8 PMU BHRB filter config which improved the clarity
(3) Merged the previous 10th patch into the 8th patch
(4) Moved SW based branch analysis code from core perf into code-patching library as suggested by Michael
(5) Simplified the logic in branch analysis library
(6) Fixed some ambiguities in documentation at various places
(7) Added some more in-code documentation blocks at various places
(8) Renamed some local variable and function names
(9) Fixed some indentation and white space errors in the code
(10) Implemented almost all the review comments and suggestions made by Michael Ellerman on V4 patchset
(11) Enabled privilege mode SW branch filter
(12) Simplified and generalized the SW implemented conditional branch filter
(13) PERF_SAMPLE_BRANCH_COND filter is now supported only through SW implementation
(14) Adjusted other patches to deal with the above changes
Changes in V6
=============
(1) Rebased the patchset against the master
(2) Added "Reviewed-by: Andi Kleen" in the first four patches in the series which changes the
generic or X86 perf code. [https://lkml.org/lkml/2014/4/7/130]
HW implemented branch filters
=============================
(1) perf record -j any_call -e branch-misses:u ./cprog
# Overhead Command Source Shared Object Source Symbol Target Shared Object Target Symbol
# ........ ....... .................... ....................... .................... ....................
#
7.85% cprog cprog [.] sw_3_1 cprog [.] success_3_1_2
5.66% cprog cprog [.] sw_3_1 cprog [.] sw_3_1_2
5.65% cprog cprog [.] hw_1_1 cprog [.] symbol1
5.42% cprog cprog [.] sw_3_1 cprog [.] sw_3_1_3
5.40% cprog cprog [.] callme cprog [.] hw_1_1
5.40% cprog cprog [.] sw_3_1 cprog [.] success_3_1_1
5.40% cprog cprog [.] sw_3_1 cprog [.] sw_3_1_1
5.39% cprog cprog [.] sw_4_2 cprog [.] lr_addr
5.39% cprog cprog [.] callme cprog [.] sw_4_2
5.39% cprog [unknown] [.] 00000000 cprog [.] ctr_addr
5.38% cprog cprog [.] hw_1_2 cprog [.] symbol2
5.38% cprog cprog [.] callme cprog [.] hw_1_2
5.16% cprog cprog [.] sw_3_1 cprog [.] success_3_1_3
5.15% cprog cprog [.] callme cprog [.] sw_3_2
5.14% cprog cprog [.] callme cprog [.] hw_2_2
2.96% cprog cprog [.] callme cprog [.] sw_3_1
2.94% cprog cprog [.] callme cprog [.] hw_2_1
2.71% cprog cprog [.] main cprog [.] callme
2.71% cprog [unknown] [.] 00000000 cprog [.] lr_addr
2.70% cprog cprog [.] sw_4_1 cprog [.] ctr_addr
2.70% cprog cprog [.] callme cprog [.] sw_4_1
0.09% cprog [unknown] [.] 0xf7ad76c4 [unknown] [.] 0xf7ac22c0
0.00% cprog libc-2.11.2.so [.] vfprintf libc-2.11.2.so [.] __errno_location
0.00% cprog libc-2.11.2.so [.] printf libc-2.11.2.so [.] vfprintf
0.00% cprog libc-2.11.2.so [.] _IO_file_doallocate libc-2.11.2.so [.] isatty
0.00% cprog libc-2.11.2.so [.] _IO_file_doallocate libc-2.11.2.so [.] mmap
0.00% cprog libc-2.11.2.so [.] isatty libc-2.11.2.so [.] tcgetattr
0.00% cprog cprog [.] main [unknown] [.] 0x10000950
0.00% cprog [unknown] [.] 00000000 libc-2.11.2.so [.] _IO_file_stat
0.00% cprog [unknown] [.] 0xf7acfca4 cprog [.] _fini
0.00% cprog [unknown] [k] 00000000 cprog [k] ctr_addr
0.00% cprog [unknown] [k] 00000000 cprog [k] lr_addr
SW implemented branch filters
=============================
(2) perf record -j cond -e branch-misses:u ./cprog
# Overhead Command Source Shared Object Source Symbol Target Shared Object Target Symbol
# ........ ....... .................... ...................... .................... ......................
#
25.82% cprog [unknown] [.] 00000000 cprog [.] sw_3_1
12.66% cprog cprog [.] sw_4_2 cprog [.] lr_addr
12.63% cprog [unknown] [.] 00000000 cprog [.] callme
9.42% cprog cprog [.] hw_2_2 cprog [.] address2
9.39% cprog cprog [.] sw_3_1 cprog [.] success_3_1_2
4.91% cprog cprog [.] sw_3_1 cprog [.] success_3_1_1
4.91% cprog cprog [.] sw_3_1 cprog [.] success_3_1_3
3.35% cprog cprog [.] sw_3_1_3 cprog [.] sw_3_1
3.34% cprog cprog [.] sw_3_1_1 cprog [.] sw_3_1
3.31% cprog cprog [.] hw_1_2 cprog [.] symbol2
3.31% cprog cprog [.] sw_4_1 cprog [.] ctr_addr
3.29% cprog cprog [.] hw_2_1 cprog [.] address1
3.27% cprog cprog [.] sw_3_1_2 cprog [.] sw_3_1
0.32% cprog [unknown] [.] 0xf7c62328 [unknown] [.] 0xf7c62320
0.01% cprog libc-2.11.2.so [.] vfprintf libc-2.11.2.so [.] vfprintf
0.01% cprog libc-2.11.2.so [.] _IO_file_xsputn libc-2.11.2.so [.] _IO_file_xsputn
0.01% cprog libc-2.11.2.so [.] _IO_default_xsputn libc-2.11.2.so [.] _IO_default_xsputn
0.01% cprog libc-2.11.2.so [.] strchrnul libc-2.11.2.so [.] strchrnul
0.01% cprog [unknown] [.] 00000000 libc-2.11.2.so [.] _IO_file_xsputn
0.01% cprog [unknown] [k] 00000000 cprog [k] callme
(3) perf record -j any_ret -e branch-misses:u ./cprog
# Overhead Command Source Shared Object Source Symbol Target Shared Object Target Symbol
# ........ ....... .................... ..................... .................... .....................
#
15.61% cprog [unknown] [.] 00000000 cprog [.] sw_3_1
6.28% cprog cprog [.] symbol2 cprog [.] hw_1_2
6.28% cprog cprog [.] ctr_addr cprog [.] sw_4_1
6.26% cprog cprog [.] success_3_1_3 cprog [.] sw_3_1
6.24% cprog cprog [.] symbol1 cprog [.] hw_1_1
6.24% cprog cprog [.] sw_4_2 cprog [.] callme
6.21% cprog [unknown] [.] 00000000 cprog [.] callme
6.19% cprog cprog [.] lr_addr cprog [.] sw_4_2
3.16% cprog cprog [.] hw_1_2 cprog [.] callme
3.15% cprog cprog [.] success_3_1_1 cprog [.] sw_3_1
3.15% cprog cprog [.] sw_4_1 cprog [.] callme
3.14% cprog cprog [.] callme cprog [.] main
3.13% cprog cprog [.] hw_1_1 cprog [.] callme
3.13% cprog cprog [.] sw_3_1_1 cprog [.] sw_3_1
3.12% cprog cprog [.] back2 cprog [.] callme
3.12% cprog cprog [.] sw_3_1 cprog [.] callme
3.11% cprog cprog [.] back1 cprog [.] callme
3.11% cprog cprog [.] sw_3_1_2 cprog [.] sw_3_1
3.11% cprog cprog [.] sw_3_1_3 cprog [.] sw_3_1
3.10% cprog cprog [.] sw_3_2 cprog [.] callme
3.09% cprog cprog [.] success_3_1_2 cprog [.] sw_3_1
0.03% cprog [unknown] [.] 0x100009b0 [unknown] [.] 0xf7d5581c
0.01% cprog libc-2.11.2.so [.] _IO_file_overflow libc-2.11.2.so [.] _IO_file_xsputn
0.01% cprog libc-2.11.2.so [.] _IO_file_setbuf [unknown] [.] 0x0fee1084
0.01% cprog [unknown] [.] 0xf7d5589c libc-2.11.2.so [.] printf
0.01% cprog [unknown] [.] 00000000 libc-2.11.2.so [.] _IO_file_overflow
0.01% cprog [unknown] [.] 00000000 libc-2.11.2.so [.] _IO_file_setbuf
0.01% cprog [unknown] [k] 00000000 cprog [k] callme
(4) perf record -j ind_call -e branch-misses:u ./cprog
# Overhead Command Source Shared Object Source Symbol Target Shared Object Target Symbol
# ........ ....... .................... .............. .................... .....................
#
42.59% cprog [unknown] [.] 00000000 cprog [.] sw_3_1
25.88% cprog cprog [.] sw_4_2 cprog [.] lr_addr
25.65% cprog [unknown] [.] 00000000 cprog [.] callme
5.58% cprog cprog [.] sw_4_1 cprog [.] ctr_addr
0.23% cprog [unknown] [k] 00000000 cprog [k] callme
0.05% cprog [unknown] [.] 00000000 [unknown] [.] 0xf79fd740
0.03% cprog [unknown] [.] 00000000 libc-2.11.2.so [.] _IO_file_overflow
(5) perf record -j any_call,any_ret -e branch-misses:u ./cprog
# Overhead Command Source Shared Object Source Symbol Target Shared Object Target Symbol
# ........ ....... .................... ......................... .................... .....................
#
10.00% cprog [unknown] [.] 00000000 cprog [.] sw_3_1
4.20% cprog cprog [.] sw_4_2 cprog [.] lr_addr
4.17% cprog cprog [.] lr_addr cprog [.] sw_4_2
4.16% cprog cprog [.] symbol1 cprog [.] hw_1_1
4.12% cprog [unknown] [.] 00000000 cprog [.] callme
4.12% cprog cprog [.] symbol2 cprog [.] hw_1_2
4.11% cprog cprog [.] success_3_1_3 cprog [.] sw_3_1
4.11% cprog cprog [.] ctr_addr cprog [.] sw_4_1
4.10% cprog cprog [.] sw_4_2 cprog [.] callme
2.42% cprog cprog [.] callme cprog [.] sw_4_2
2.40% cprog cprog [.] sw_3_1_3 cprog [.] sw_3_1
2.40% cprog cprog [.] sw_3_1 cprog [.] sw_3_1_3
2.39% cprog cprog [.] hw_1_2 cprog [.] symbol2
2.39% cprog cprog [.] back1 cprog [.] callme
2.39% cprog cprog [.] sw_3_1_1 cprog [.] sw_3_1
2.39% cprog cprog [.] sw_3_1 cprog [.] sw_3_1_1
2.39% cprog cprog [.] sw_3_1 cprog [.] callme
2.39% cprog cprog [.] sw_4_1 cprog [.] ctr_addr
2.39% cprog cprog [.] callme cprog [.] hw_1_2
2.39% cprog cprog [.] callme cprog [.] sw_3_1
2.39% cprog cprog [.] sw_3_1_2 cprog [.] sw_3_1
2.39% cprog cprog [.] sw_3_1 cprog [.] sw_3_1_2
2.38% cprog cprog [.] hw_1_1 cprog [.] symbol1
2.38% cprog cprog [.] callme cprog [.] hw_1_1
1.78% cprog cprog [.] back2 cprog [.] callme
1.78% cprog cprog [.] hw_1_1 cprog [.] callme
1.76% cprog cprog [.] success_3_1_2 cprog [.] sw_3_1
1.76% cprog cprog [.] sw_3_1 cprog [.] success_3_1_2
1.76% cprog cprog [.] sw_3_2 cprog [.] callme
1.76% cprog cprog [.] callme cprog [.] sw_3_2
1.73% cprog cprog [.] success_3_1_1 cprog [.] sw_3_1
1.73% cprog cprog [.] sw_3_1 cprog [.] success_3_1_1
1.73% cprog cprog [.] hw_1_2 cprog [.] callme
1.71% cprog cprog [.] sw_3_1 cprog [.] success_3_1_3
1.71% cprog cprog [.] sw_4_1 cprog [.] callme
1.71% cprog cprog [.] callme cprog [.] main
0.05% cprog [unknown] [k] 00000000 cprog [k] callme
0.03% cprog [unknown] [.] 0xf7aa9d4c [unknown] [.] 0xf7aa5f80
0.01% cprog libc-2.11.2.so [.] __errno_location libc-2.11.2.so [.] vfprintf
0.01% cprog libc-2.11.2.so [.] vfprintf libc-2.11.2.so [.] __errno_location
0.01% cprog libc-2.11.2.so [.] _IO_doallocbuf libc-2.11.2.so [.] _IO_file_overflow
0.01% cprog cprog [.] __do_global_dtors_aux [unknown] [.] 0xf7a9fc74
0.01% cprog [unknown] [.] 0xf7a9fca4 cprog [.] _fini
(6) perf record -j any_call,ind_call -e branch-misses:u ./cprog
# Overhead Command Source Shared Object Source Symbol Target Shared Object Target Symbol
# ........ ....... .................... ...................... .................... ......................
#
17.38% cprog [unknown] [.] 00000000 cprog [.] sw_3_1
7.76% cprog cprog [.] sw_4_2 cprog [.] lr_addr
7.64% cprog [unknown] [.] 00000000 cprog [.] callme
6.00% cprog cprog [.] sw_3_1 cprog [.] sw_3_1_1
6.00% cprog cprog [.] callme cprog [.] sw_3_1
5.98% cprog cprog [.] sw_4_1 cprog [.] ctr_addr
5.97% cprog cprog [.] hw_1_1 cprog [.] symbol1
5.97% cprog cprog [.] hw_1_2 cprog [.] symbol2
5.97% cprog cprog [.] sw_3_1 cprog [.] sw_3_1_3
5.97% cprog cprog [.] callme cprog [.] hw_1_1
5.97% cprog cprog [.] callme cprog [.] hw_1_2
5.96% cprog cprog [.] callme cprog [.] sw_4_2
5.95% cprog cprog [.] sw_3_1 cprog [.] sw_3_1_2
1.83% cprog cprog [.] sw_3_1 cprog [.] success_3_1_2
1.82% cprog cprog [.] sw_3_1 cprog [.] success_3_1_1
1.82% cprog cprog [.] sw_3_1 cprog [.] success_3_1_3
1.82% cprog cprog [.] callme cprog [.] sw_3_2
0.14% cprog [unknown] [k] 00000000 cprog [k] callme
0.01% cprog libc-2.11.2.so [.] vfprintf libc-2.11.2.so [.] strchrnul
0.01% cprog libc-2.11.2.so [.] _IO_file_xsputn libc-2.11.2.so [.] _IO_default_xsputn
0.01% cprog libc-2.11.2.so [.] _IO_default_xsputn libc-2.11.2.so [.] _IO_file_overflow
0.01% cprog ld-2.11.2.so [.] calloc [unknown] [.] 0xf795b390
0.01% cprog [unknown] [.] 0x0fee00fc libc-2.11.2.so [.] _IO_file_overflow
0.01% cprog [unknown] [.] 00000000 ld-2.11.2.so [.] calloc
0.01% cprog [unknown] [.] 0xf794b41c [unknown] [.] 0xf794ab70
(7) perf record -j cond,any_ret -e branch-misses:u ./cprog
# Overhead Command Source Shared Object Source Symbol Target Shared Object Target Symbol
# ........ ....... .................... ...................... .................... ......................
#
12.43% cprog [unknown] [.] 00000000 cprog [.] sw_3_1
4.91% cprog cprog [.] lr_addr cprog [.] sw_4_2
4.89% cprog [unknown] [.] 00000000 cprog [.] callme
4.87% cprog cprog [.] sw_4_2 cprog [.] lr_addr
4.87% cprog cprog [.] symbol1 cprog [.] hw_1_1
4.19% cprog cprog [.] hw_2_2 cprog [.] address2
4.19% cprog cprog [.] back2 cprog [.] callme
4.19% cprog cprog [.] sw_3_2 cprog [.] callme
4.18% cprog cprog [.] hw_1_1 cprog [.] callme
4.18% cprog cprog [.] success_3_1_2 cprog [.] sw_3_1
4.18% cprog cprog [.] sw_3_1 cprog [.] success_3_1_2
4.16% cprog cprog [.] sw_4_2 cprog [.] callme
4.13% cprog cprog [.] ctr_addr cprog [.] sw_4_1
4.12% cprog cprog [.] symbol2 cprog [.] hw_1_2
4.12% cprog cprog [.] success_3_1_3 cprog [.] sw_3_1
3.43% cprog cprog [.] callme cprog [.] main
3.42% cprog cprog [.] sw_3_1 cprog [.] success_3_1_3
3.41% cprog cprog [.] success_3_1_1 cprog [.] sw_3_1
3.41% cprog cprog [.] sw_3_1 cprog [.] success_3_1_1
3.41% cprog cprog [.] sw_4_1 cprog [.] callme
3.40% cprog cprog [.] hw_1_2 cprog [.] callme
0.73% cprog cprog [.] sw_3_1_3 cprog [.] sw_3_1
0.73% cprog cprog [.] sw_4_1 cprog [.] ctr_addr
0.72% cprog cprog [.] hw_1_2 cprog [.] symbol2
0.72% cprog cprog [.] sw_3_1_1 cprog [.] sw_3_1
0.70% cprog cprog [.] hw_2_1 cprog [.] address1
0.70% cprog cprog [.] back1 cprog [.] callme
0.70% cprog cprog [.] sw_3_1_2 cprog [.] sw_3_1
0.70% cprog cprog [.] sw_3_1 cprog [.] callme
0.19% cprog [unknown] [.] 0xf7c12328 [unknown] [.] 0xf7c12320
0.01% cprog libc-2.11.2.so [.] __errno_location libc-2.11.2.so [.] vfprintf
0.01% cprog libc-2.11.2.so [.] vfprintf libc-2.11.2.so [.] vfprintf
0.01% cprog libc-2.11.2.so [.] _IO_file_overflow [unknown] [.] 0x0fee0100
0.01% cprog libc-2.11.2.so [.] _IO_default_xsputn libc-2.11.2.so [.] _IO_default_xsputn
0.01% cprog [unknown] [.] 00000000 libc-2.11.2.so [.] _IO_file_overflow
(8) perf record -j cond,ind_call -e branch-misses:u ./cprog
# Overhead Command Source Shared Object Source Symbol Target Shared Object Target Symbol
# ........ ....... .................... .............. .................... .................
#
20.70% cprog [unknown] [.] 00000000 cprog [.] sw_3_1
9.99% cprog cprog [.] sw_4_2 cprog [.] lr_addr
9.91% cprog [unknown] [.] 00000000 cprog [.] callme
9.45% cprog cprog [.] sw_3_1_3 cprog [.] sw_3_1
9.44% cprog cprog [.] hw_2_1 cprog [.] address1
9.43% cprog cprog [.] sw_3_1_1 cprog [.] sw_3_1
9.42% cprog cprog [.] hw_1_2 cprog [.] symbol2
9.42% cprog cprog [.] sw_3_1_2 cprog [.] sw_3_1
9.42% cprog cprog [.] sw_4_1 cprog [.] ctr_addr
0.65% cprog cprog [.] sw_3_1 cprog [.] success_3_1_1
0.62% cprog cprog [.] sw_3_1 cprog [.] success_3_1_3
0.56% cprog cprog [.] hw_2_2 cprog [.] address2
0.55% cprog cprog [.] sw_3_1 cprog [.] success_3_1_2
0.29% cprog [unknown] [.] 0xf7f72328 [unknown] [.] 0xf7f72320
0.10% cprog [unknown] [k] 00000000 cprog [k] callme
0.02% cprog libc-2.11.2.so [.] _IO_setb libc-2.11.2.so [.] _IO_setb
(9) perf record -e branch-misses:u -j any_call,any_ret,ind_call,cond ./cprog
# Overhead Command Source Shared Object Source Symbol Target Shared Object Target Symbol
# ........ ....... .................... .................. .................... .......................
#
9.31% cprog [unknown] [.] 00000000 cprog [.] sw_3_1
4.04% cprog cprog [.] symbol1 cprog [.] hw_1_1
4.03% cprog cprog [.] lr_addr cprog [.] sw_4_2
4.03% cprog cprog [.] sw_4_2 cprog [.] lr_addr
4.00% cprog [unknown] [.] 00000000 cprog [.] callme
3.88% cprog cprog [.] ctr_addr cprog [.] sw_4_1
3.87% cprog cprog [.] sw_4_2 cprog [.] callme
3.86% cprog cprog [.] symbol2 cprog [.] hw_1_2
3.86% cprog cprog [.] success_3_1_3 cprog [.] sw_3_1
2.49% cprog cprog [.] sw_4_1 cprog [.] ctr_addr
2.47% cprog cprog [.] hw_1_1 cprog [.] symbol1
2.47% cprog cprog [.] sw_3_1_1 cprog [.] sw_3_1
2.47% cprog cprog [.] sw_3_1 cprog [.] sw_3_1_1
2.47% cprog cprog [.] callme cprog [.] hw_1_1
2.47% cprog cprog [.] callme cprog [.] sw_3_1
2.47% cprog cprog [.] hw_1_2 cprog [.] symbol2
2.47% cprog cprog [.] hw_2_1 cprog [.] address1
2.47% cprog cprog [.] back1 cprog [.] callme
2.47% cprog cprog [.] sw_3_1_3 cprog [.] sw_3_1
2.47% cprog cprog [.] sw_3_1 cprog [.] sw_3_1_3
2.47% cprog cprog [.] sw_3_1 cprog [.] callme
2.47% cprog cprog [.] callme cprog [.] hw_1_2
2.47% cprog cprog [.] callme cprog [.] sw_4_2
2.46% cprog cprog [.] sw_3_1_2 cprog [.] sw_3_1
2.46% cprog cprog [.] sw_3_1 cprog [.] sw_3_1_2
1.57% cprog cprog [.] success_3_1_2 cprog [.] sw_3_1
1.57% cprog cprog [.] sw_3_1 cprog [.] success_3_1_2
1.57% cprog cprog [.] hw_1_1 cprog [.] callme
1.56% cprog cprog [.] hw_2_2 cprog [.] address2
1.56% cprog cprog [.] back2 cprog [.] callme
1.56% cprog cprog [.] sw_3_2 cprog [.] callme
1.56% cprog cprog [.] callme cprog [.] sw_3_2
1.41% cprog cprog [.] success_3_1_1 cprog [.] sw_3_1
1.41% cprog cprog [.] sw_3_1 cprog [.] success_3_1_1
1.40% cprog cprog [.] sw_4_1 cprog [.] callme
1.39% cprog cprog [.] hw_1_2 cprog [.] callme
1.39% cprog cprog [.] sw_3_1 cprog [.] success_3_1_3
1.39% cprog cprog [.] callme cprog [.] main
0.14% cprog [unknown] [.] 0xf7d72328 [unknown] [.] 0xf7d72320
0.03% cprog [unknown] [k] 00000000 cprog [k] callme
0.01% cprog libc-2.11.2.so [.] _IO_doallocbuf libc-2.11.2.so [.] _IO_doallocbuf
0.01% cprog libc-2.11.2.so [.] printf cprog [.] main
0.01% cprog libc-2.11.2.so [.] _IO_doallocbuf libc-2.11.2.so [.] _IO_file_doallocate
0.01% cprog ld-2.11.2.so [.] malloc [unknown] [.] 0xf7d8b380
0.01% cprog cprog [.] main [unknown] [.] 0x0fe7f63c
0.01% cprog [unknown] [.] 0xf7d8b388 ld-2.11.2.so [.] __libc_memalign
0.01% cprog [unknown] [.] 00000000 ld-2.11.2.so [.] malloc
Please refer to the V4 version of the patchset to learn about the sample test case and it's makefile.
Anshuman Khandual (11):
perf: Add PERF_SAMPLE_BRANCH_COND
perf, tool: Conditional branch filter 'cond' added to perf record
x86, perf: Add conditional branch filtering support
perf, documentation: Description for conditional branch filter
powerpc, perf: Re-arrange BHRB processing
powerpc, perf: Re-arrange PMU based branch filter processing in POWER8
powerpc, perf: Change the name of HW PMU branch filter tracking variable
powerpc, lib: Add new branch analysis support functions
powerpc, perf: Enable SW filtering in branch stack sampling framework
power8, perf: Adapt BHRB PMU configuration to work with SW filters
powerpc, perf: Enable privilege mode SW branch filters
arch/powerpc/include/asm/code-patching.h | 16 ++
arch/powerpc/include/asm/perf_event_server.h | 6 +-
arch/powerpc/lib/code-patching.c | 80 +++++++
arch/powerpc/perf/core-book3s.c | 323 ++++++++++++++++++++++-----
arch/powerpc/perf/power8-pmu.c | 70 ++++--
arch/x86/kernel/cpu/perf_event_intel_lbr.c | 5 +
include/uapi/linux/perf_event.h | 3 +-
tools/perf/Documentation/perf-record.txt | 3 +-
tools/perf/builtin-record.c | 1 +
9 files changed, 429 insertions(+), 78 deletions(-)
--
1.7.11.7
^ permalink raw reply
* [V6 07/11] powerpc, perf: Change the name of HW PMU branch filter tracking variable
From: Anshuman Khandual @ 2014-05-05 9:09 UTC (permalink / raw)
To: linuxppc-dev, linux-kernel
Cc: mikey, ak, eranian, michael, acme, sukadev, mingo
In-Reply-To: <1399280953-31442-1-git-send-email-khandual@linux.vnet.ibm.com>
This patch simply changes the name of the variable from 'bhrb_filter' to
'bhrb_hw_filter' in order to add one more variable which will track SW
filters in generic powerpc book3s code which will be implemented in the
subsequent patch. This patch does not change any functionality.
Signed-off-by: Anshuman Khandual <khandual@linux.vnet.ibm.com>
---
arch/powerpc/perf/core-book3s.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/arch/powerpc/perf/core-book3s.c b/arch/powerpc/perf/core-book3s.c
index 66bea54..1d7e909 100644
--- a/arch/powerpc/perf/core-book3s.c
+++ b/arch/powerpc/perf/core-book3s.c
@@ -47,7 +47,7 @@ struct cpu_hw_events {
int n_txn_start;
/* BHRB bits */
- u64 bhrb_filter; /* BHRB HW branch filter */
+ u64 bhrb_hw_filter; /* BHRB HW branch filter */
int bhrb_users;
void *bhrb_context;
struct perf_branch_stack bhrb_stack;
@@ -1298,7 +1298,7 @@ static void power_pmu_enable(struct pmu *pmu)
mb();
if (cpuhw->bhrb_users)
- ppmu->config_bhrb(cpuhw->bhrb_filter);
+ ppmu->config_bhrb(cpuhw->bhrb_hw_filter);
write_mmcr0(cpuhw, mmcr0);
@@ -1405,7 +1405,7 @@ nocheck:
out:
if (has_branch_stack(event)) {
power_pmu_bhrb_enable(event);
- cpuhw->bhrb_filter = ppmu->bhrb_filter_map(
+ cpuhw->bhrb_hw_filter = ppmu->bhrb_filter_map(
event->attr.branch_sample_type);
}
@@ -1788,10 +1788,10 @@ static int power_pmu_event_init(struct perf_event *event)
err = power_check_constraints(cpuhw, events, cflags, n + 1);
if (has_branch_stack(event)) {
- cpuhw->bhrb_filter = ppmu->bhrb_filter_map(
+ cpuhw->bhrb_hw_filter = ppmu->bhrb_filter_map(
event->attr.branch_sample_type);
- if(cpuhw->bhrb_filter == -1)
+ if(cpuhw->bhrb_hw_filter == -1)
return -EOPNOTSUPP;
}
--
1.7.11.7
^ permalink raw reply related
* [V6 04/11] perf, documentation: Description for conditional branch filter
From: Anshuman Khandual @ 2014-05-05 9:09 UTC (permalink / raw)
To: linuxppc-dev, linux-kernel
Cc: mikey, ak, eranian, michael, acme, sukadev, mingo
In-Reply-To: <1399280953-31442-1-git-send-email-khandual@linux.vnet.ibm.com>
Adding documentation support for conditional branch filter.
Signed-off-by: Anshuman Khandual <khandual@linux.vnet.ibm.com>
Reviewed-by: Stephane Eranian <eranian@google.com>
Reviewed-by: Andi Kleen <ak@linux.intel.com>
---
tools/perf/Documentation/perf-record.txt | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt
index c71b0f3..d460049 100644
--- a/tools/perf/Documentation/perf-record.txt
+++ b/tools/perf/Documentation/perf-record.txt
@@ -184,9 +184,10 @@ following filters are defined:
- in_tx: only when the target is in a hardware transaction
- no_tx: only when the target is not in a hardware transaction
- abort_tx: only when the target is a hardware transaction abort
+ - cond: conditional branches
+
-The option requires at least one branch type among any, any_call, any_ret, ind_call.
+The option requires at least one branch type among any, any_call, any_ret, ind_call, cond.
The privilege levels may be omitted, in which case, the privilege levels of the associated
event are applied to the branch filter. Both kernel (k) and hypervisor (hv) privilege
levels are subject to permissions. When sampling on multiple events, branch stack sampling
--
1.7.11.7
^ permalink raw reply related
* [V6 11/11] powerpc, perf: Enable privilege mode SW branch filters
From: Anshuman Khandual @ 2014-05-05 9:09 UTC (permalink / raw)
To: linuxppc-dev, linux-kernel
Cc: mikey, ak, eranian, michael, acme, sukadev, mingo
In-Reply-To: <1399280953-31442-1-git-send-email-khandual@linux.vnet.ibm.com>
This patch enables privilege mode SW branch filters. Also modifies
POWER8 PMU branch filter configuration so that the privilege mode
branch filter implemented as part of base PMU event configuration
is reflected in bhrb filter mask. As a result, the SW will skip and
not try to process the privilege mode branch filters itself.
Signed-off-by: Anshuman Khandual <khandual@linux.vnet.ibm.com>
---
arch/powerpc/perf/core-book3s.c | 53 +++++++++++++++++++++++++++++++----------
arch/powerpc/perf/power8-pmu.c | 13 ++++++++--
2 files changed, 52 insertions(+), 14 deletions(-)
diff --git a/arch/powerpc/perf/core-book3s.c b/arch/powerpc/perf/core-book3s.c
index a94cc43..297cddb 100644
--- a/arch/powerpc/perf/core-book3s.c
+++ b/arch/powerpc/perf/core-book3s.c
@@ -26,6 +26,9 @@
#define BHRB_PREDICTION 0x0000000000000001
#define BHRB_EA 0xFFFFFFFFFFFFFFFCUL
+#define POWER_ADDR_USER 0
+#define POWER_ADDR_KERNEL 1
+
struct cpu_hw_events {
int n_events;
int n_percpu;
@@ -450,10 +453,10 @@ static bool check_instruction(unsigned int *addr, u64 sw_filter)
* Access the instruction contained in the address and check
* whether it complies with the applicable SW branch filters.
*/
-static bool keep_branch(u64 from, u64 sw_filter)
+static bool keep_branch(u64 from, u64 to, u64 sw_filter)
{
unsigned int instr;
- bool ret;
+ bool to_plm, ret, flag;
/*
* The "from" branch for every branch record has to go
@@ -463,6 +466,37 @@ static bool keep_branch(u64 from, u64 sw_filter)
if (sw_filter == 0)
return true;
+ to_plm = is_kernel_addr(to) ? POWER_ADDR_KERNEL : POWER_ADDR_USER;
+
+ /*
+ * Applying privilege mode SW branch filters first on the
+ * 'to' address makes an AND semantic with the SW generic
+ * branch filters (OR with each other) being applied on the
+ * from address there after.
+ */
+
+ /* Ignore PERF_SAMPLE_BRANCH_HV */
+ sw_filter &= ~PERF_SAMPLE_BRANCH_HV;
+
+ /* Privilege mode branch filters for "TO" address */
+ if (sw_filter & PERF_SAMPLE_BRANCH_PLM_ALL) {
+ flag = false;
+
+ if (sw_filter & PERF_SAMPLE_BRANCH_USER) {
+ if(to_plm == POWER_ADDR_USER)
+ flag = true;
+ }
+
+ if (sw_filter & PERF_SAMPLE_BRANCH_KERNEL) {
+ if(to_plm == POWER_ADDR_KERNEL)
+ flag = true;
+ }
+
+ if (!flag)
+ return false;
+ }
+
+ /* Generic branch filters for "FROM" address */
if (is_kernel_addr(from)) {
return check_instruction((unsigned int *) from, sw_filter);
} else {
@@ -501,15 +535,6 @@ static int all_filters_covered(u64 branch_sample_type, u64 bhrb_filter)
if (!(branch_sample_type & x))
continue;
/*
- * Privilege filter requests have been already
- * taken care during the base PMU configuration.
- */
- if ((x == PERF_SAMPLE_BRANCH_USER)
- || (x == PERF_SAMPLE_BRANCH_KERNEL)
- || (x == PERF_SAMPLE_BRANCH_HV))
- continue;
-
- /*
* Requested filter not available either
* in PMU or in SW.
*/
@@ -520,7 +545,10 @@ static int all_filters_covered(u64 branch_sample_type, u64 bhrb_filter)
}
/* SW implemented branch filters */
-static unsigned int power_sw_filter[] = { PERF_SAMPLE_BRANCH_ANY_CALL,
+static unsigned int power_sw_filter[] = { PERF_SAMPLE_BRANCH_USER,
+ PERF_SAMPLE_BRANCH_KERNEL,
+ PERF_SAMPLE_BRANCH_HV,
+ PERF_SAMPLE_BRANCH_ANY_CALL,
PERF_SAMPLE_BRANCH_COND,
PERF_SAMPLE_BRANCH_ANY_RETURN,
PERF_SAMPLE_BRANCH_IND_CALL };
@@ -624,6 +652,7 @@ void power_pmu_bhrb_read(struct cpu_hw_events *cpuhw)
/* Apply SW branch filters and drop the entry if required */
if (!keep_branch(cpuhw->bhrb_entries[u_index].from,
+ cpuhw->bhrb_entries[u_index].to,
cpuhw->bhrb_sw_filter))
u_index--;
u_index++;
diff --git a/arch/powerpc/perf/power8-pmu.c b/arch/powerpc/perf/power8-pmu.c
index 4743bde..b6e21da 100644
--- a/arch/powerpc/perf/power8-pmu.c
+++ b/arch/powerpc/perf/power8-pmu.c
@@ -649,9 +649,19 @@ static u64 power8_bhrb_filter_map(u64 branch_sample_type, u64 *bhrb_filter)
* filter configuration. BHRB is always recorded along with a
* regular PMU event. As the privilege state filter is handled
* in the basic PMC configuration of the accompanying regular
- * PMU event, we ignore any separate BHRB specific request.
+ * PMU event, we ignore any separate BHRB specific request. But
+ * this needs to be communicated with the branch filter mask.
*/
+ if (branch_sample_type & PERF_SAMPLE_BRANCH_USER)
+ *bhrb_filter |= PERF_SAMPLE_BRANCH_USER;
+
+ if (branch_sample_type & PERF_SAMPLE_BRANCH_KERNEL)
+ *bhrb_filter |= PERF_SAMPLE_BRANCH_KERNEL;
+
+ if (branch_sample_type & PERF_SAMPLE_BRANCH_HV)
+ *bhrb_filter |= PERF_SAMPLE_BRANCH_HV;
+
/* Ignore user, kernel, hv bits */
branch_sample_type &= ~PERF_SAMPLE_BRANCH_PLM_ALL;
@@ -679,7 +689,6 @@ static u64 power8_bhrb_filter_map(u64 branch_sample_type, u64 *bhrb_filter)
if (branch_sample_type) {
/* Multiple branch filters will be processed in SW */
pmu_bhrb_filter = 0;
- *bhrb_filter = 0;
return pmu_bhrb_filter;
} else {
/* Individual branch filter will be processed in PMU */
--
1.7.11.7
^ permalink raw reply related
* [V6 10/11] power8, perf: Adapt BHRB PMU configuration to work with SW filters
From: Anshuman Khandual @ 2014-05-05 9:09 UTC (permalink / raw)
To: linuxppc-dev, linux-kernel
Cc: mikey, ak, eranian, michael, acme, sukadev, mingo
In-Reply-To: <1399280953-31442-1-git-send-email-khandual@linux.vnet.ibm.com>
Powerpc kernel now supports SW based branch filters for book3s systems with some
specifc requirements while dealing with HW supported branch filters in order to
achieve overall OR semantics prevailing in perf branch stack sampling framework.
This patch adapts the BHRB branch filter configuration to meet those protocols.
POWER8 PMU can only handle one HW based branch filter request at any point of time.
For all other combinations PMU will pass it on to the SW.
Signed-off-by: Anshuman Khandual <khandual@linux.vnet.ibm.com>
---
arch/powerpc/perf/power8-pmu.c | 50 ++++++++++++++++++++++++++++++++++++------
1 file changed, 43 insertions(+), 7 deletions(-)
diff --git a/arch/powerpc/perf/power8-pmu.c b/arch/powerpc/perf/power8-pmu.c
index 699b1dd..4743bde 100644
--- a/arch/powerpc/perf/power8-pmu.c
+++ b/arch/powerpc/perf/power8-pmu.c
@@ -635,6 +635,16 @@ static int power8_generic_events[] = {
static u64 power8_bhrb_filter_map(u64 branch_sample_type, u64 *bhrb_filter)
{
+ u64 x, pmu_bhrb_filter;
+ pmu_bhrb_filter = 0;
+ *bhrb_filter = 0;
+
+ /* No branch filter requested */
+ if (branch_sample_type & PERF_SAMPLE_BRANCH_ANY) {
+ *bhrb_filter = PERF_SAMPLE_BRANCH_ANY;
+ return pmu_bhrb_filter;
+ }
+
/* BHRB and regular PMU events share the same privilege state
* filter configuration. BHRB is always recorded along with a
* regular PMU event. As the privilege state filter is handled
@@ -645,16 +655,42 @@ static u64 power8_bhrb_filter_map(u64 branch_sample_type, u64 *bhrb_filter)
/* Ignore user, kernel, hv bits */
branch_sample_type &= ~PERF_SAMPLE_BRANCH_PLM_ALL;
- /* No branch filter requested */
- if (branch_sample_type == PERF_SAMPLE_BRANCH_ANY)
- return 0;
+ /*
+ * P8 does not support oring of PMU HW branch filters. Hence
+ * if multiple branch filters are requested which includes filters
+ * supported in PMU, still go ahead and clear the PMU based HW branch
+ * filter component as in this case all the filters will be processed
+ * in SW.
+ */
- if (branch_sample_type == PERF_SAMPLE_BRANCH_ANY_CALL) {
- return POWER8_MMCRA_IFM1;
+ for_each_branch_sample_type(x) {
+ /* Ignore privilege branch filters */
+ if ((x == PERF_SAMPLE_BRANCH_USER)
+ || (x == PERF_SAMPLE_BRANCH_KERNEL)
+ || (x == PERF_SAMPLE_BRANCH_HV))
+ continue;
+
+ if (!(branch_sample_type & x))
+ continue;
+
+ /* Supported individual PMU branch filters */
+ if (branch_sample_type & PERF_SAMPLE_BRANCH_ANY_CALL) {
+ branch_sample_type &= ~PERF_SAMPLE_BRANCH_ANY_CALL;
+ if (branch_sample_type) {
+ /* Multiple branch filters will be processed in SW */
+ pmu_bhrb_filter = 0;
+ *bhrb_filter = 0;
+ return pmu_bhrb_filter;
+ } else {
+ /* Individual branch filter will be processed in PMU */
+ pmu_bhrb_filter |= POWER8_MMCRA_IFM1;
+ *bhrb_filter |= PERF_SAMPLE_BRANCH_ANY_CALL;
+ return pmu_bhrb_filter;
+ }
+ }
}
- /* Every thing else is unsupported */
- return -1;
+ return pmu_bhrb_filter;
}
static void power8_config_bhrb(u64 pmu_bhrb_filter)
--
1.7.11.7
^ permalink raw reply related
* [V6 01/11] perf: Add PERF_SAMPLE_BRANCH_COND
From: Anshuman Khandual @ 2014-05-05 9:09 UTC (permalink / raw)
To: linuxppc-dev, linux-kernel
Cc: mikey, ak, eranian, michael, acme, sukadev, mingo
In-Reply-To: <1399280953-31442-1-git-send-email-khandual@linux.vnet.ibm.com>
This patch introduces new branch filter PERF_SAMPLE_BRANCH_COND which
will extend the existing perf ABI. Various architectures can provide
this functionality with either with HW filtering support (if present)
or with SW filtering of captured branch instructions.
Signed-off-by: Anshuman Khandual <khandual@linux.vnet.ibm.com>
Reviewed-by: Stephane Eranian <eranian@google.com>
Reviewed-by: Andi Kleen <ak@linux.intel.com>
---
include/uapi/linux/perf_event.h | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/include/uapi/linux/perf_event.h b/include/uapi/linux/perf_event.h
index 853bc1c..696f69b4 100644
--- a/include/uapi/linux/perf_event.h
+++ b/include/uapi/linux/perf_event.h
@@ -163,8 +163,9 @@ enum perf_branch_sample_type {
PERF_SAMPLE_BRANCH_ABORT_TX = 1U << 7, /* transaction aborts */
PERF_SAMPLE_BRANCH_IN_TX = 1U << 8, /* in transaction */
PERF_SAMPLE_BRANCH_NO_TX = 1U << 9, /* not in transaction */
+ PERF_SAMPLE_BRANCH_COND = 1U << 10, /* conditional branches */
- PERF_SAMPLE_BRANCH_MAX = 1U << 10, /* non-ABI */
+ PERF_SAMPLE_BRANCH_MAX = 1U << 11, /* non-ABI */
};
#define PERF_SAMPLE_BRANCH_PLM_ALL \
--
1.7.11.7
^ permalink raw reply related
* [V6 05/11] powerpc, perf: Re-arrange BHRB processing
From: Anshuman Khandual @ 2014-05-05 9:09 UTC (permalink / raw)
To: linuxppc-dev, linux-kernel
Cc: mikey, ak, eranian, michael, acme, sukadev, mingo
In-Reply-To: <1399280953-31442-1-git-send-email-khandual@linux.vnet.ibm.com>
This patch cleans up some existing indentation problem and
re-organizes the BHRB processing code with an helper function
named `update_branch_entry` making it more readable. This patch
does not change any functionality.
Signed-off-by: Anshuman Khandual <khandual@linux.vnet.ibm.com>
---
arch/powerpc/perf/core-book3s.c | 102 ++++++++++++++++++++--------------------
1 file changed, 52 insertions(+), 50 deletions(-)
diff --git a/arch/powerpc/perf/core-book3s.c b/arch/powerpc/perf/core-book3s.c
index 4520c93..66bea54 100644
--- a/arch/powerpc/perf/core-book3s.c
+++ b/arch/powerpc/perf/core-book3s.c
@@ -402,11 +402,21 @@ static __u64 power_pmu_bhrb_to(u64 addr)
return target - (unsigned long)&instr + addr;
}
+/* Update individual branch entry */
+void update_branch_entry(struct cpu_hw_events *cpuhw, int u_index, u64 from, u64 to, int pred)
+{
+ cpuhw->bhrb_entries[u_index].from = from;
+ cpuhw->bhrb_entries[u_index].to = to;
+ cpuhw->bhrb_entries[u_index].mispred = pred;
+ cpuhw->bhrb_entries[u_index].predicted = ~pred;
+ return;
+}
+
/* Processing BHRB entries */
void power_pmu_bhrb_read(struct cpu_hw_events *cpuhw)
{
u64 val;
- u64 addr;
+ u64 addr, tmp;
int r_index, u_index, pred;
r_index = 0;
@@ -417,62 +427,54 @@ void power_pmu_bhrb_read(struct cpu_hw_events *cpuhw)
if (!val)
/* Terminal marker: End of valid BHRB entries */
break;
- else {
- addr = val & BHRB_EA;
- pred = val & BHRB_PREDICTION;
- if (!addr)
- /* invalid entry */
- continue;
+ addr = val & BHRB_EA;
+ pred = val & BHRB_PREDICTION;
- /* Branches are read most recent first (ie. mfbhrb 0 is
- * the most recent branch).
- * There are two types of valid entries:
- * 1) a target entry which is the to address of a
- * computed goto like a blr,bctr,btar. The next
- * entry read from the bhrb will be branch
- * corresponding to this target (ie. the actual
- * blr/bctr/btar instruction).
- * 2) a from address which is an actual branch. If a
- * target entry proceeds this, then this is the
- * matching branch for that target. If this is not
- * following a target entry, then this is a branch
- * where the target is given as an immediate field
- * in the instruction (ie. an i or b form branch).
- * In this case we need to read the instruction from
- * memory to determine the target/to address.
+ if (!addr)
+ /* invalid entry */
+ continue;
+
+ /* Branches are read most recent first (ie. mfbhrb 0 is
+ * the most recent branch).
+ * There are two types of valid entries:
+ * 1) a target entry which is the to address of a
+ * computed goto like a blr,bctr,btar. The next
+ * entry read from the bhrb will be branch
+ * corresponding to this target (ie. the actual
+ * blr/bctr/btar instruction).
+ * 2) a from address which is an actual branch. If a
+ * target entry proceeds this, then this is the
+ * matching branch for that target. If this is not
+ * following a target entry, then this is a branch
+ * where the target is given as an immediate field
+ * in the instruction (ie. an i or b form branch).
+ * In this case we need to read the instruction from
+ * memory to determine the target/to address.
+ */
+ if (val & BHRB_TARGET) {
+ /* Target branches use two entries
+ * (ie. computed gotos/XL form)
*/
+ tmp = addr;
+ /* Get from address in next entry */
+ val = read_bhrb(r_index++);
+ addr = val & BHRB_EA;
if (val & BHRB_TARGET) {
- /* Target branches use two entries
- * (ie. computed gotos/XL form)
- */
- cpuhw->bhrb_entries[u_index].to = addr;
- cpuhw->bhrb_entries[u_index].mispred = pred;
- cpuhw->bhrb_entries[u_index].predicted = ~pred;
-
- /* Get from address in next entry */
- val = read_bhrb(r_index++);
- addr = val & BHRB_EA;
- if (val & BHRB_TARGET) {
- /* Shouldn't have two targets in a
- row.. Reset index and try again */
- r_index--;
- addr = 0;
- }
- cpuhw->bhrb_entries[u_index].from = addr;
- } else {
- /* Branches to immediate field
- (ie I or B form) */
- cpuhw->bhrb_entries[u_index].from = addr;
- cpuhw->bhrb_entries[u_index].to =
- power_pmu_bhrb_to(addr);
- cpuhw->bhrb_entries[u_index].mispred = pred;
- cpuhw->bhrb_entries[u_index].predicted = ~pred;
+ /* Shouldn't have two targets in a
+ row.. Reset index and try again */
+ r_index--;
+ addr = 0;
}
- u_index++;
-
+ update_branch_entry(cpuhw, u_index, addr, tmp, pred);
+ } else {
+ /* Branches to immediate field
+ (ie I or B form) */
+ tmp = power_pmu_bhrb_to(addr);
+ update_branch_entry(cpuhw, u_index, addr, tmp, pred);
}
+ u_index++;
}
cpuhw->bhrb_stack.nr = u_index;
return;
--
1.7.11.7
^ permalink raw reply related
* [V6 06/11] powerpc, perf: Re-arrange PMU based branch filter processing in POWER8
From: Anshuman Khandual @ 2014-05-05 9:09 UTC (permalink / raw)
To: linuxppc-dev, linux-kernel
Cc: mikey, ak, eranian, michael, acme, sukadev, mingo
In-Reply-To: <1399280953-31442-1-git-send-email-khandual@linux.vnet.ibm.com>
This patch does some code re-arrangements to make it clear that
it ignores any separate privilege level branch filter request
and does not support any combinations of HW PMU branch filters.
Signed-off-by: Anshuman Khandual <khandual@linux.vnet.ibm.com>
---
arch/powerpc/perf/power8-pmu.c | 21 +++++++--------------
1 file changed, 7 insertions(+), 14 deletions(-)
diff --git a/arch/powerpc/perf/power8-pmu.c b/arch/powerpc/perf/power8-pmu.c
index fe2763b..13f47f5 100644
--- a/arch/powerpc/perf/power8-pmu.c
+++ b/arch/powerpc/perf/power8-pmu.c
@@ -635,8 +635,6 @@ static int power8_generic_events[] = {
static u64 power8_bhrb_filter_map(u64 branch_sample_type)
{
- u64 pmu_bhrb_filter = 0;
-
/* BHRB and regular PMU events share the same privilege state
* filter configuration. BHRB is always recorded along with a
* regular PMU event. As the privilege state filter is handled
@@ -644,20 +642,15 @@ static u64 power8_bhrb_filter_map(u64 branch_sample_type)
* PMU event, we ignore any separate BHRB specific request.
*/
- /* No branch filter requested */
- if (branch_sample_type & PERF_SAMPLE_BRANCH_ANY)
- return pmu_bhrb_filter;
-
- /* Invalid branch filter options - HW does not support */
- if (branch_sample_type & PERF_SAMPLE_BRANCH_ANY_RETURN)
- return -1;
+ /* Ignore user, kernel, hv bits */
+ branch_sample_type &= ~PERF_SAMPLE_BRANCH_PLM_ALL;
- if (branch_sample_type & PERF_SAMPLE_BRANCH_IND_CALL)
- return -1;
+ /* No branch filter requested */
+ if (branch_sample_type == PERF_SAMPLE_BRANCH_ANY)
+ return 0;
- if (branch_sample_type & PERF_SAMPLE_BRANCH_ANY_CALL) {
- pmu_bhrb_filter |= POWER8_MMCRA_IFM1;
- return pmu_bhrb_filter;
+ if (branch_sample_type == PERF_SAMPLE_BRANCH_ANY_CALL) {
+ return POWER8_MMCRA_IFM1;
}
/* Every thing else is unsupported */
--
1.7.11.7
^ permalink raw reply related
* Re: Boot problems with a PA6T board
From: Christian Zigotzky @ 2014-05-05 9:41 UTC (permalink / raw)
To: Michael Ellerman, linuxppc-dev
In-Reply-To: <1399268891.4600.3.camel@concordia>
Hi Michael,
Thanks a lot for your answer. They reasoned that "starting cpu hw idx
0... failed" is reported because that core of the CPU is already up and
running.
I have built a git kernel from 2014-04-02.
-> git clone
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git linux-git
-> git show 3e75c6de1ac33fe3500f44573d9212dc82c99f59
-> git checkout -f 3e75c6de1ac33fe3500f44573d9212dc82c99f59; git clean -fdx
This kernel booted and showed a Kernel Panic with the following error
message:
Oops: Machine check, sig: 7 [#1]
Rgds,
Christian
On 05.05.2014 07:48, Michael Ellerman wrote:
> On Sun, 2014-05-04 at 18:02 +0200, Christian Zigotzky wrote:
>> Hi All,
>>
>> The RC 1, 2, and 3 of the kernel 3.15 don't boot on my PA6T board with a
>> Radeon HD 6870 graphics card.
>>
>> Screenshot:
>> http://forum.hyperion-entertainment.biz/download/file.php?id=1060&mode=view
>>
>> The kernel 3.14 starts without any problems. Has anyone a tip for me,
>> please?
> The line that says "starting cpu hw idx 0... failed" looks a little worrying.
> Do you see that on 3.14 as well?
>
> Otherwise bisection is probably your best bet.
>
> cheers
>
>
>
^ permalink raw reply
* Re: [PATCH V5] KVM: PPC: BOOK3S: PR: Enable Little Endian PR guest
From: Alexander Graf @ 2014-05-05 11:17 UTC (permalink / raw)
To: Aneesh Kumar K.V; +Cc: paulus, linuxppc-dev, kvm-ppc, kvm
In-Reply-To: <1399259384-6623-1-git-send-email-aneesh.kumar@linux.vnet.ibm.com>
On 05/05/2014 05:09 AM, Aneesh Kumar K.V wrote:
> This patch make sure we inherit the LE bit correctly in different case
> so that we can run Little Endian distro in PR mode
>
> Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
Thanks, applied to kvm-ppc-queue.
Alex
^ permalink raw reply
* Re: [PATCH V4] POWERPC: BOOK3S: KVM: Use the saved dar value and generic make_dsisr
From: Alexander Graf @ 2014-05-05 11:19 UTC (permalink / raw)
To: Aneesh Kumar K.V; +Cc: paulus, linuxppc-dev, kvm-ppc, kvm
In-Reply-To: <1399224075-18041-1-git-send-email-aneesh.kumar@linux.vnet.ibm.com>
On 05/04/2014 07:21 PM, Aneesh Kumar K.V wrote:
> Although it's optional IBM POWER cpus always had DAR value set on
> alignment interrupt. So don't try to compute these values.
>
> Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
> ---
> Changes from V3:
> * Use make_dsisr instead of checking feature flag to decide whether to use
> saved dsisr or not
>
> arch/powerpc/include/asm/disassemble.h | 34 +++++++++++++++++++++++++++
> arch/powerpc/kernel/align.c | 34 +--------------------------
> arch/powerpc/kvm/book3s_emulate.c | 43 ++++------------------------------
> 3 files changed, 40 insertions(+), 71 deletions(-)
>
> diff --git a/arch/powerpc/include/asm/disassemble.h b/arch/powerpc/include/asm/disassemble.h
> index 856f8deb557a..6330a61b875a 100644
> --- a/arch/powerpc/include/asm/disassemble.h
> +++ b/arch/powerpc/include/asm/disassemble.h
> @@ -81,4 +81,38 @@ static inline unsigned int get_oc(u32 inst)
> {
> return (inst >> 11) & 0x7fff;
> }
> +
> +#define IS_XFORM(inst) (get_op(inst) == 31)
> +#define IS_DSFORM(inst) (get_op(inst) >= 56)
> +
> +/*
> + * Create a DSISR value from the instruction
> + */
> +static inline unsigned make_dsisr(unsigned instr)
> +{
> + unsigned dsisr;
> +
> +
> + /* bits 6:15 --> 22:31 */
> + dsisr = (instr & 0x03ff0000) >> 16;
> +
> + if (IS_XFORM(instr)) {
> + /* bits 29:30 --> 15:16 */
> + dsisr |= (instr & 0x00000006) << 14;
> + /* bit 25 --> 17 */
> + dsisr |= (instr & 0x00000040) << 8;
> + /* bits 21:24 --> 18:21 */
> + dsisr |= (instr & 0x00000780) << 3;
> + } else {
> + /* bit 5 --> 17 */
> + dsisr |= (instr & 0x04000000) >> 12;
> + /* bits 1: 4 --> 18:21 */
> + dsisr |= (instr & 0x78000000) >> 17;
> + /* bits 30:31 --> 12:13 */
> + if (IS_DSFORM(instr))
> + dsisr |= (instr & 0x00000003) << 18;
> + }
> +
> + return dsisr;
> +}
> #endif /* __ASM_PPC_DISASSEMBLE_H__ */
> diff --git a/arch/powerpc/kernel/align.c b/arch/powerpc/kernel/align.c
> index 94908af308d8..34f55524d456 100644
> --- a/arch/powerpc/kernel/align.c
> +++ b/arch/powerpc/kernel/align.c
> @@ -25,14 +25,13 @@
> #include <asm/cputable.h>
> #include <asm/emulated_ops.h>
> #include <asm/switch_to.h>
> +#include <asm/disassemble.h>
>
> struct aligninfo {
> unsigned char len;
> unsigned char flags;
> };
>
> -#define IS_XFORM(inst) (((inst) >> 26) == 31)
> -#define IS_DSFORM(inst) (((inst) >> 26) >= 56)
>
> #define INVALID { 0, 0 }
>
> @@ -192,37 +191,6 @@ static struct aligninfo aligninfo[128] = {
> };
>
> /*
> - * Create a DSISR value from the instruction
> - */
> -static inline unsigned make_dsisr(unsigned instr)
> -{
> - unsigned dsisr;
> -
> -
> - /* bits 6:15 --> 22:31 */
> - dsisr = (instr & 0x03ff0000) >> 16;
> -
> - if (IS_XFORM(instr)) {
> - /* bits 29:30 --> 15:16 */
> - dsisr |= (instr & 0x00000006) << 14;
> - /* bit 25 --> 17 */
> - dsisr |= (instr & 0x00000040) << 8;
> - /* bits 21:24 --> 18:21 */
> - dsisr |= (instr & 0x00000780) << 3;
> - } else {
> - /* bit 5 --> 17 */
> - dsisr |= (instr & 0x04000000) >> 12;
> - /* bits 1: 4 --> 18:21 */
> - dsisr |= (instr & 0x78000000) >> 17;
> - /* bits 30:31 --> 12:13 */
> - if (IS_DSFORM(instr))
> - dsisr |= (instr & 0x00000003) << 18;
> - }
> -
> - return dsisr;
> -}
> -
> -/*
> * The dcbz (data cache block zero) instruction
> * gives an alignment fault if used on non-cacheable
> * memory. We handle the fault mainly for the
> diff --git a/arch/powerpc/kvm/book3s_emulate.c b/arch/powerpc/kvm/book3s_emulate.c
> index 99d40f8977e8..04c38f049dfd 100644
> --- a/arch/powerpc/kvm/book3s_emulate.c
> +++ b/arch/powerpc/kvm/book3s_emulate.c
> @@ -569,48 +569,14 @@ unprivileged:
>
> u32 kvmppc_alignment_dsisr(struct kvm_vcpu *vcpu, unsigned int inst)
> {
> - u32 dsisr = 0;
> -
> - /*
> - * This is what the spec says about DSISR bits (not mentioned = 0):
> - *
> - * 12:13 [DS] Set to bits 30:31
> - * 15:16 [X] Set to bits 29:30
> - * 17 [X] Set to bit 25
> - * [D/DS] Set to bit 5
> - * 18:21 [X] Set to bits 21:24
> - * [D/DS] Set to bits 1:4
> - * 22:26 Set to bits 6:10 (RT/RS/FRT/FRS)
> - * 27:31 Set to bits 11:15 (RA)
> - */
> -
> - switch (get_op(inst)) {
> - /* D-form */
> - case OP_LFS:
> - case OP_LFD:
> - case OP_STFD:
> - case OP_STFS:
> - dsisr |= (inst >> 12) & 0x4000; /* bit 17 */
> - dsisr |= (inst >> 17) & 0x3c00; /* bits 18:21 */
> - break;
> - /* X-form */
> - case 31:
> - dsisr |= (inst << 14) & 0x18000; /* bits 15:16 */
> - dsisr |= (inst << 8) & 0x04000; /* bit 17 */
> - dsisr |= (inst << 3) & 0x03c00; /* bits 18:21 */
> - break;
> - default:
> - printk(KERN_INFO "KVM: Unaligned instruction 0x%x\n", inst);
> - break;
> - }
> -
> - dsisr |= (inst >> 16) & 0x03ff; /* bits 22:31 */
> -
> - return dsisr;
> + return make_dsisr(inst);
> }
>
> ulong kvmppc_alignment_dar(struct kvm_vcpu *vcpu, unsigned int inst)
> {
> +#ifdef CONFIG_PPC_BOOK3S_64
> + return vcpu->arch.fault_dar;
How about PA6T and G5s?
Alex
^ permalink raw reply
* Re: [PATCH] KVM: PPC: BOOK3S: HV: Don't try to allocate from kernel page allocator for hash page table.
From: Alexander Graf @ 2014-05-05 11:26 UTC (permalink / raw)
To: Aneesh Kumar K.V; +Cc: paulus, linuxppc-dev, kvm-ppc, kvm
In-Reply-To: <1399224322-22028-1-git-send-email-aneesh.kumar@linux.vnet.ibm.com>
On 05/04/2014 07:25 PM, Aneesh Kumar K.V wrote:
> We reserve 5% of total ram for CMA allocation and not using that can
> result in us running out of numa node memory with specific
> configuration. One caveat is we may not have node local hpt with pinned
> vcpu configuration. But currently libvirt also pins the vcpu to cpuset
> after creating hash page table.
I don't understand the problem. Can you please elaborate?
Alex
>
> Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
> ---
> arch/powerpc/kvm/book3s_64_mmu_hv.c | 23 ++++++-----------------
> 1 file changed, 6 insertions(+), 17 deletions(-)
>
> diff --git a/arch/powerpc/kvm/book3s_64_mmu_hv.c b/arch/powerpc/kvm/book3s_64_mmu_hv.c
> index fb25ebc0af0c..f32896ffd784 100644
> --- a/arch/powerpc/kvm/book3s_64_mmu_hv.c
> +++ b/arch/powerpc/kvm/book3s_64_mmu_hv.c
> @@ -52,7 +52,7 @@ static void kvmppc_rmap_reset(struct kvm *kvm);
>
> long kvmppc_alloc_hpt(struct kvm *kvm, u32 *htab_orderp)
> {
> - unsigned long hpt;
> + unsigned long hpt = 0;
> struct revmap_entry *rev;
> struct page *page = NULL;
> long order = KVM_DEFAULT_HPT_ORDER;
> @@ -64,22 +64,11 @@ long kvmppc_alloc_hpt(struct kvm *kvm, u32 *htab_orderp)
> }
>
> kvm->arch.hpt_cma_alloc = 0;
> - /*
> - * try first to allocate it from the kernel page allocator.
> - * We keep the CMA reserved for failed allocation.
> - */
> - hpt = __get_free_pages(GFP_KERNEL | __GFP_ZERO | __GFP_REPEAT |
> - __GFP_NOWARN, order - PAGE_SHIFT);
> -
> - /* Next try to allocate from the preallocated pool */
> - if (!hpt) {
> - VM_BUG_ON(order < KVM_CMA_CHUNK_ORDER);
> - page = kvm_alloc_hpt(1 << (order - PAGE_SHIFT));
> - if (page) {
> - hpt = (unsigned long)pfn_to_kaddr(page_to_pfn(page));
> - kvm->arch.hpt_cma_alloc = 1;
> - } else
> - --order;
> + VM_BUG_ON(order < KVM_CMA_CHUNK_ORDER);
> + page = kvm_alloc_hpt(1 << (order - PAGE_SHIFT));
> + if (page) {
> + hpt = (unsigned long)pfn_to_kaddr(page_to_pfn(page));
> + kvm->arch.hpt_cma_alloc = 1;
> }
>
> /* Lastly try successively smaller sizes from the page allocator */
^ permalink raw reply
* Re: [PATCH] KVM: PPC: BOOK3S: PR: Fix WARN_ON with debug options on
From: Alexander Graf @ 2014-05-05 11:29 UTC (permalink / raw)
To: Aneesh Kumar K.V; +Cc: paulus, linuxppc-dev, kvm-ppc, kvm
In-Reply-To: <1399224368-22122-1-git-send-email-aneesh.kumar@linux.vnet.ibm.com>
On 05/04/2014 07:26 PM, Aneesh Kumar K.V wrote:
> With debug option "sleep inside atomic section checking" enabled we get
> the below WARN_ON during a PR KVM boot. This is because upstream now
> have PREEMPT_COUNT enabled even if we have preempt disabled. Fix the
> warning by adding preempt_disable/enable around floating point and altivec
> enable.
>
> WARNING: at arch/powerpc/kernel/process.c:156
> Modules linked in: kvm_pr kvm
> CPU: 1 PID: 3990 Comm: qemu-system-ppc Tainted: G W 3.15.0-rc1+ #4
> task: c0000000eb85b3a0 ti: c0000000ec59c000 task.ti: c0000000ec59c000
> NIP: c000000000015c84 LR: d000000003334644 CTR: c000000000015c00
> REGS: c0000000ec59f140 TRAP: 0700 Tainted: G W (3.15.0-rc1+)
> MSR: 8000000000029032 <SF,EE,ME,IR,DR,RI> CR: 42000024 XER: 20000000
> CFAR: c000000000015c24 SOFTE: 1
> GPR00: d000000003334644 c0000000ec59f3c0 c000000000e2fa40 c0000000e2f80000
> GPR04: 0000000000000800 0000000000002000 0000000000000001 8000000000000000
> GPR08: 0000000000000001 0000000000000001 0000000000002000 c000000000015c00
> GPR12: d00000000333da18 c00000000fb80900 0000000000000000 0000000000000000
> GPR16: 0000000000000000 0000000000000000 0000000000000000 00003fffce4e0fa1
> GPR20: 0000000000000010 0000000000000001 0000000000000002 00000000100b9a38
> GPR24: 0000000000000002 0000000000000000 0000000000000000 0000000000000013
> GPR28: 0000000000000000 c0000000eb85b3a0 0000000000002000 c0000000e2f80000
> NIP [c000000000015c84] .enable_kernel_fp+0x84/0x90
> LR [d000000003334644] .kvmppc_handle_ext+0x134/0x190 [kvm_pr]
> Call Trace:
> [c0000000ec59f3c0] [0000000000000010] 0x10 (unreliable)
> [c0000000ec59f430] [d000000003334644] .kvmppc_handle_ext+0x134/0x190 [kvm_pr]
> [c0000000ec59f4c0] [d00000000324b380] .kvmppc_set_msr+0x30/0x50 [kvm]
> [c0000000ec59f530] [d000000003337cac] .kvmppc_core_emulate_op_pr+0x16c/0x5e0 [kvm_pr]
> [c0000000ec59f5f0] [d00000000324a944] .kvmppc_emulate_instruction+0x284/0xa80 [kvm]
> [c0000000ec59f6c0] [d000000003336888] .kvmppc_handle_exit_pr+0x488/0xb70 [kvm_pr]
> [c0000000ec59f790] [d000000003338d34] kvm_start_lightweight+0xcc/0xdc [kvm_pr]
> [c0000000ec59f960] [d000000003336288] .kvmppc_vcpu_run_pr+0xc8/0x190 [kvm_pr]
> [c0000000ec59f9f0] [d00000000324c880] .kvmppc_vcpu_run+0x30/0x50 [kvm]
> [c0000000ec59fa60] [d000000003249e74] .kvm_arch_vcpu_ioctl_run+0x54/0x1b0 [kvm]
> [c0000000ec59faf0] [d000000003244948] .kvm_vcpu_ioctl+0x478/0x760 [kvm]
> [c0000000ec59fcb0] [c000000000224e34] .do_vfs_ioctl+0x4d4/0x790
> [c0000000ec59fd90] [c000000000225148] .SyS_ioctl+0x58/0xb0
> [c0000000ec59fe30] [c00000000000a1e4] syscall_exit+0x0/0x98
>
> Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
Thanks, applied to kvm-ppc-queue.
Alex
^ permalink raw reply
* Re: [RFC PATCH] KVM: PPC: BOOK3S: HV: THP support for guest
From: Alexander Graf @ 2014-05-05 11:38 UTC (permalink / raw)
To: Aneesh Kumar K.V; +Cc: paulus, linuxppc-dev, kvm-ppc, kvm
In-Reply-To: <1399224616-25142-1-git-send-email-aneesh.kumar@linux.vnet.ibm.com>
On 05/04/2014 07:30 PM, Aneesh Kumar K.V wrote:
> Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
No patch description, no proper explanations anywhere why you're doing
what. All of that in a pretty sensitive piece of code. There's no way
this patch can go upstream in its current form.
Alex
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox