* [PATCH 16/22] powerpc/eeh: Emulate RTAS call ibm,configure-pe
From: Gavin Shan @ 2014-05-05 1:28 UTC (permalink / raw)
To: linuxppc-dev, kvm, kvm-ppc; +Cc: aik, alex.williamson, qiudayu, Gavin Shan
In-Reply-To: <1399253291-3975-1-git-send-email-gwshan@linux.vnet.ibm.com>
The RTAS call "ibm,configure-pe" is being used to restore everything
after PE reset. The patch implements the backend to emulate the
RTAS call. In that, we restores BARs for the affected PCI device in
host side because the guest might not have full access to the config
space.
Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
---
arch/powerpc/platforms/powernv/eeh-rtas.c | 49 +++++++++++++++++++++++++++++++
1 file changed, 49 insertions(+)
diff --git a/arch/powerpc/platforms/powernv/eeh-rtas.c b/arch/powerpc/platforms/powernv/eeh-rtas.c
index 8934564..a663cd8 100644
--- a/arch/powerpc/platforms/powernv/eeh-rtas.c
+++ b/arch/powerpc/platforms/powernv/eeh-rtas.c
@@ -462,6 +462,52 @@ out:
return ret;
}
+static int kvmppc_eeh_configure_pe(struct kvm_vcpu *vcpu,
+ struct rtas_args *args)
+{
+ struct pci_controller *hose;
+ struct pnv_phb *phb;
+ struct eeh_dev *edev;
+ struct eeh_pe *pe;
+ struct eeh_vfio_pci_addr addr;
+ int ret = 0;
+
+ /* Sanity check on parameter */
+ if (args->nargs != 3 || args->nret != 1) {
+ pr_warn("%s: Non-matched arguments (%d, %d) - (3, 1)\n",
+ __func__, args->nargs, args->nret);
+ ret = -3;
+ goto out;
+ }
+
+ /* Figure out the address */
+ if (kvmppc_eeh_format_addr(vcpu, args, &addr, false, &edev, &pe)) {
+ ret = -3;
+ goto out;
+ }
+
+ /* Make sure that the EEH stuff has been initialized */
+ hose = pe->phb;
+ phb = hose->private_data;
+ if (!(phb->flags & PNV_PHB_FLAG_EEH)) {
+ pr_warn("%s: EEH disabled on PHB#%x\n",
+ __func__, hose->global_number);
+ ret = -3;
+ goto out;
+ }
+
+ /*
+ * The access to PCI config space on VFIO device has some
+ * limitations. Part of PCI config space, including BAR
+ * registers are not readable and writable. So the guest
+ * should have stale values for those registers and we have
+ * to restore them in host side.
+ */
+ eeh_pe_restore_bars(pe);
+out:
+ return ret;
+}
+
/**
* kvmppc_eeh_rtas - Backend for EEH RTAS emulation
* @vcpu: KVM virtual CPU
@@ -493,6 +539,9 @@ void kvmppc_eeh_rtas(struct kvm_vcpu *vcpu, struct rtas_args *args, int op)
case eeh_rtas_slot_error_detail:
ret = kvmppc_eeh_get_error(vcpu, args);
break;
+ case eeh_rtas_configure_pe:
+ ret = kvmppc_eeh_configure_pe(vcpu, args);
+ break;
default:
pr_warn("%s: Unsupported EEH RTAS service#%d\n",
__func__, op);
--
1.8.3.2
^ permalink raw reply related
* [PATCH 14/22] powerpc/eeh: Emulate RTAS call ibm, get-config-addr-info2
From: Gavin Shan @ 2014-05-05 1:28 UTC (permalink / raw)
To: linuxppc-dev, kvm, kvm-ppc; +Cc: aik, alex.williamson, qiudayu, Gavin Shan
In-Reply-To: <1399253291-3975-1-git-send-email-gwshan@linux.vnet.ibm.com>
The RTAS call "ibm,get-config-addr-info2" is being used by guest
to retrieve the corresponding PE number for the specified PCI device.
The patch implements the backend to support the emulation of the
RTAS call.
Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
---
arch/powerpc/platforms/powernv/eeh-rtas.c | 59 +++++++++++++++++++++++++++++++
1 file changed, 59 insertions(+)
diff --git a/arch/powerpc/platforms/powernv/eeh-rtas.c b/arch/powerpc/platforms/powernv/eeh-rtas.c
index 031ee8c..4a9c2c7 100644
--- a/arch/powerpc/platforms/powernv/eeh-rtas.c
+++ b/arch/powerpc/platforms/powernv/eeh-rtas.c
@@ -334,6 +334,62 @@ out:
return ret;
}
+static int kvmppc_eeh_get_addr2(struct kvm_vcpu *vcpu,
+ struct rtas_args *args)
+{
+ struct pci_controller *hose;
+ struct pnv_phb *phb;
+ struct eeh_dev *edev;
+ struct eeh_pe *pe;
+ struct eeh_vfio_pci_addr addr;
+ int opcode;
+ int ret = 0;
+
+ /* Sanity check on parameter */
+ if (args->nargs != 4 || args->nret != 2) {
+ pr_warn("%s: Non-matched arguments (%d, %d) - (4, 2)\n",
+ __func__, args->nargs, args->nret);
+ ret = -3;
+ goto out;
+ }
+
+ /* Check on the operation code */
+ opcode = args->args[3];
+ if (opcode != 0 && opcode != 1) {
+ pr_warn("%s: opcode %d out of range (0, 1)\n",
+ __func__, opcode);
+ ret = -3;
+ goto out;
+ }
+
+ /* Figure out address */
+ if (kvmppc_eeh_format_addr(vcpu, args, &addr, true, &edev, &pe)) {
+ ret = -3;
+ goto out;
+ }
+
+ /* Insure that the EEH stuff has been initialized */
+ hose = pe->phb;
+ phb = hose->private_data;
+ if (!(phb->flags & PNV_PHB_FLAG_EEH)) {
+ pr_warn("%s: EEH disabled on PHB#%d\n",
+ __func__, hose->global_number);
+ ret = -3;
+ goto out;
+ }
+
+ /*
+ * Fill result according to opcode. We don't differentiate
+ * PCI bus and device sensitive PE here.
+ */
+ if (opcode == 0)
+ args->rets[1] = pe->gaddr.pe_addr;
+ else
+ args->rets[1] = 1;
+out:
+ return ret;
+}
+
/**
* kvmppc_eeh_rtas - Backend for EEH RTAS emulation
* @vcpu: KVM virtual CPU
@@ -359,6 +415,9 @@ void kvmppc_eeh_rtas(struct kvm_vcpu *vcpu, struct rtas_args *args, int op)
case eeh_rtas_read_slot_reset_state2:
ret = kvmppc_eeh_get_state2(vcpu, args);
break;
+ case eeh_rtas_get_config_addr_info2:
+ ret = kvmppc_eeh_get_addr2(vcpu, args);
+ break;
default:
pr_warn("%s: Unsupported EEH RTAS service#%d\n",
__func__, op);
--
1.8.3.2
^ permalink raw reply related
* [PATCH 18/22] powerpc/eeh: Avoid event on passed PE
From: Gavin Shan @ 2014-05-05 1:28 UTC (permalink / raw)
To: linuxppc-dev, kvm, kvm-ppc; +Cc: aik, alex.williamson, qiudayu, Gavin Shan
In-Reply-To: <1399253291-3975-1-git-send-email-gwshan@linux.vnet.ibm.com>
If we detects frozen state on PE that has been passed to guest, we
needn't handle it. Instead, we rely on the guest to detect and recover
it. The patch avoid EEH event on the frozen passed PE so that the guest
can have chance to handle that.
Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
---
arch/powerpc/kernel/eeh.c | 8 ++++++++
arch/powerpc/platforms/powernv/eeh-ioda.c | 3 ++-
2 files changed, 10 insertions(+), 1 deletion(-)
diff --git a/arch/powerpc/kernel/eeh.c b/arch/powerpc/kernel/eeh.c
index 33d683a..a2121e8 100644
--- a/arch/powerpc/kernel/eeh.c
+++ b/arch/powerpc/kernel/eeh.c
@@ -399,6 +399,14 @@ int eeh_dev_check_failure(struct eeh_dev *edev)
if (ret > 0)
return ret;
+ /*
+ * If the PE has been passed to guest, we won't check the
+ * state. Instead, let the guest handle it if the PE has
+ * been frozen.
+ */
+ if (eeh_pe_passed(pe))
+ return 0;
+
/* If we already have a pending isolation event for this
* slot, we know it's bad already, we don't need to check.
* Do this checking under a lock; as multiple PCI devices
diff --git a/arch/powerpc/platforms/powernv/eeh-ioda.c b/arch/powerpc/platforms/powernv/eeh-ioda.c
index 1b5982f..03a3ed2 100644
--- a/arch/powerpc/platforms/powernv/eeh-ioda.c
+++ b/arch/powerpc/platforms/powernv/eeh-ioda.c
@@ -890,7 +890,8 @@ static int ioda_eeh_next_error(struct eeh_pe **pe)
opal_pci_eeh_freeze_clear(phb->opal_id, frozen_pe_no,
OPAL_EEH_ACTION_CLEAR_FREEZE_ALL);
ret = EEH_NEXT_ERR_NONE;
- } else if ((*pe)->state & EEH_PE_ISOLATED) {
+ } else if ((*pe)->state & EEH_PE_ISOLATED ||
+ eeh_pe_passed(*pe)) {
ret = EEH_NEXT_ERR_NONE;
} else {
pr_err("EEH: Frozen PHB#%x-PE#%x (%s) detected\n",
--
1.8.3.2
^ permalink raw reply related
* [PATCH 17/22] powerpc/kvm: Connect EEH RTAS emulation backend
From: Gavin Shan @ 2014-05-05 1:28 UTC (permalink / raw)
To: linuxppc-dev, kvm, kvm-ppc; +Cc: aik, alex.williamson, qiudayu, Gavin Shan
In-Reply-To: <1399253291-3975-1-git-send-email-gwshan@linux.vnet.ibm.com>
The patch intends to connect the KVM module with the backend for
EEH RTAS emulation. In turn, we can handle the EEH RTAS services
from the guest.
Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
---
arch/powerpc/include/asm/kvm_ppc.h | 7 +++++++
arch/powerpc/kvm/book3s_rtas.c | 40 ++++++++++++++++++++++++++++++++++++++
2 files changed, 47 insertions(+)
diff --git a/arch/powerpc/include/asm/kvm_ppc.h b/arch/powerpc/include/asm/kvm_ppc.h
index 4096f16..18b51a1 100644
--- a/arch/powerpc/include/asm/kvm_ppc.h
+++ b/arch/powerpc/include/asm/kvm_ppc.h
@@ -29,6 +29,9 @@
#include <linux/kvm_types.h>
#include <linux/kvm_host.h>
#include <linux/bug.h>
+#ifdef CONFIG_KVM_EEH
+#include <asm/rtas.h>
+#endif
#ifdef CONFIG_PPC_BOOK3S
#include <asm/kvm_book3s.h>
#else
@@ -166,6 +169,10 @@ int kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu, struct kvm_interrupt *irq);
extern int kvm_vm_ioctl_rtas_define_token(struct kvm *kvm, void __user *argp);
extern int kvmppc_rtas_hcall(struct kvm_vcpu *vcpu);
extern void kvmppc_rtas_tokens_free(struct kvm *kvm);
+#ifdef CONFIG_KVM_EEH
+extern void kvmppc_eeh_rtas(struct kvm_vcpu *vcpu,
+ struct rtas_args *args, int flag);
+#endif
extern int kvmppc_xics_set_xive(struct kvm *kvm, u32 irq, u32 server,
u32 priority);
extern int kvmppc_xics_get_xive(struct kvm *kvm, u32 irq, u32 *server,
diff --git a/arch/powerpc/kvm/book3s_rtas.c b/arch/powerpc/kvm/book3s_rtas.c
index 7a05315..17bdb4a 100644
--- a/arch/powerpc/kvm/book3s_rtas.c
+++ b/arch/powerpc/kvm/book3s_rtas.c
@@ -16,6 +16,8 @@
#include <asm/kvm_ppc.h>
#include <asm/hvcall.h>
#include <asm/rtas.h>
+#include <asm/ppc-pci.h>
+#include <asm/eeh.h>
#ifdef CONFIG_KVM_XICS
static void kvm_rtas_set_xive(struct kvm_vcpu *vcpu, struct rtas_args *args)
@@ -103,6 +105,24 @@ out:
}
#endif /* CONFIG_KVM_XICS */
+#ifdef CONFIG_KVM_EEH
+
+#define KVM_RTAS_EEH_FUNC(name, flag) \
+static void kvm_rtas_eeh_##name(struct kvm_vcpu *vcpu, \
+ struct rtas_args *args) \
+{ \
+ kvmppc_eeh_rtas(vcpu, args, flag); \
+}
+
+KVM_RTAS_EEH_FUNC(set_option, eeh_rtas_set_option)
+KVM_RTAS_EEH_FUNC(set_reset, eeh_rtas_set_slot_reset)
+KVM_RTAS_EEH_FUNC(read_state2, eeh_rtas_read_slot_reset_state2)
+KVM_RTAS_EEH_FUNC(addr_info2, eeh_rtas_get_config_addr_info2)
+KVM_RTAS_EEH_FUNC(error_detail, eeh_rtas_slot_error_detail)
+KVM_RTAS_EEH_FUNC(configure_pe, eeh_rtas_configure_pe)
+
+#endif /* CONFIG_KVM_EEH */
+
struct rtas_handler {
void (*handler)(struct kvm_vcpu *vcpu, struct rtas_args *args);
char *name;
@@ -115,6 +135,26 @@ static struct rtas_handler rtas_handlers[] = {
{ .name = "ibm,int-off", .handler = kvm_rtas_int_off },
{ .name = "ibm,int-on", .handler = kvm_rtas_int_on },
#endif
+#ifdef CONFIG_KVM_EEH
+ { .name = "ibm,set-eeh-option",
+ .handler = kvm_rtas_eeh_set_option
+ },
+ { .name = "ibm,set-slot-reset",
+ .handler = kvm_rtas_eeh_set_reset
+ },
+ { .name = "ibm,read-slot-reset-state2",
+ .handler = kvm_rtas_eeh_read_state2
+ },
+ { .name = "ibm,get-config-addr-info2",
+ .handler = kvm_rtas_eeh_addr_info2
+ },
+ { .name = "ibm,slot-error-detail",
+ .handler = kvm_rtas_eeh_error_detail
+ },
+ { .name = "ibm,configure-pe",
+ .handler = kvm_rtas_eeh_configure_pe
+ }
+#endif /* CONFIG_KVM_EEH */
};
struct rtas_token_definition {
--
1.8.3.2
^ permalink raw reply related
* [PATCH 20/22] powerpc/kvm: Infrastructure for error injection
From: Gavin Shan @ 2014-05-05 1:28 UTC (permalink / raw)
To: linuxppc-dev, kvm, kvm-ppc; +Cc: aik, alex.williamson, qiudayu, Gavin Shan
In-Reply-To: <1399253291-3975-1-git-send-email-gwshan@linux.vnet.ibm.com>
The patch intends to implements the infrastructure for error injection.
RTAS calls "ibm,{open-errinjct, close-errinjct, errinjct}" are handled
in the host directly. Each VM is allowed to have one opened token at
once.
There're multiple types of error injection to be supported by the system.
So we maintain an array of handlers with error type as index. The array
supports dynamic registration.
Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
---
arch/powerpc/include/asm/book3s_errinjct.h | 78 +++++++
arch/powerpc/kvm/Makefile | 3 +
arch/powerpc/kvm/book3s_errinjct.c | 329 +++++++++++++++++++++++++++++
arch/powerpc/kvm/book3s_rtas.c | 29 ++-
4 files changed, 438 insertions(+), 1 deletion(-)
create mode 100644 arch/powerpc/include/asm/book3s_errinjct.h
create mode 100644 arch/powerpc/kvm/book3s_errinjct.c
diff --git a/arch/powerpc/include/asm/book3s_errinjct.h b/arch/powerpc/include/asm/book3s_errinjct.h
new file mode 100644
index 0000000..35712be
--- /dev/null
+++ b/arch/powerpc/include/asm/book3s_errinjct.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright Benjamin Herrenschmidt & Gavin Shan, IBM Corporation 2014.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __POWERPC_BOOK3S_ERRINJCT_H__
+#define __POWERPC_BOOK3S_ERRINJCT_H__
+
+/* Error injection handler */
+typedef int (*kvm_errinjct_func)(struct kvm_vcpu *vcpu, rtas_arg_t buf);
+
+#ifdef CONFIG_KVM_ERRINJCT
+
+/* RTAS services for error injection */
+enum {
+ kvm_errinjct_open_token,
+ kvm_errinjct_close_token,
+ kvm_errinjct_errinjct
+};
+
+/* Supported types of error injection */
+enum {
+ kvm_errinjct_min = 0,
+ kvm_errinjct_fatal,
+ kvm_errinjct_recover_random_evt,
+ kvm_errinjct_recover_special_evt,
+ kvm_errinjct_corrupted_page,
+ kvm_errinjct_corrupted_slb,
+ kvm_errinjct_translator_failure,
+ kvm_errinjct_ioa_bus_error,
+ kvm_errinjct_ioa_bus_error_64,
+ kvm_errinjct_platform_specific,
+ kvm_errinjct_corrupted_dcache_start,
+ kvm_errinjct_corrupted_dcache_end,
+ kvm_errinjct_corrupted_icache_start,
+ kvm_errinjct_corrupted_icache_end,
+ kvm_errinjct_corrupted_tlb_start,
+ kvm_errinjct_corrupted_tlb_end,
+ kvm_errinjct_upstream_io_error,
+ kvm_errinjct_max
+};
+
+/* Handler for specific type of error injection */
+struct kvm_errinjct_handler {
+ int opcode;
+ kvm_errinjct_func handler;
+};
+
+/* Tokens that have been opened */
+struct kvm_errinjct_token {
+ struct kvm *kvm;
+ int token;
+ struct list_head list;
+};
+
+int kvm_errinjct_register(int opcode, kvm_errinjct_func handler);
+int kvm_errinjct_unregister(int opcode);
+void kvmppc_errinjct_rtas(struct kvm_vcpu *vcpu,
+ struct rtas_args *args, int flag);
+
+#else
+
+static inline int kvm_errinjct_register(int opcode,
+ kvm_errinjct_func handler)
+{
+ return 0;
+}
+
+static inline int kvm_errinjct_unregister(int opcode);
+{
+ return 0;
+}
+
+#endif /* CONFIG_KVM_ERRINJCT */
+#endif /* __POWERPC_BOOK3S_ERRINJCT_H__ */
diff --git a/arch/powerpc/kvm/Makefile b/arch/powerpc/kvm/Makefile
index 673038d..f221f66 100644
--- a/arch/powerpc/kvm/Makefile
+++ b/arch/powerpc/kvm/Makefile
@@ -97,6 +97,9 @@ endif
kvm-book3s_64-objs-$(CONFIG_KVM_XICS) += \
book3s_xics.o
+kvm-book3s_64-objs-$(CONFIG_KVM_ERRINJCT) += \
+ book3s_errinjct.o
+
kvm-book3s_64-objs-$(CONFIG_KVM_VFIO) += \
$(addprefix ../../../virt/kvm/, vfio.o)
diff --git a/arch/powerpc/kvm/book3s_errinjct.c b/arch/powerpc/kvm/book3s_errinjct.c
new file mode 100644
index 0000000..27a49ab
--- /dev/null
+++ b/arch/powerpc/kvm/book3s_errinjct.c
@@ -0,0 +1,329 @@
+/*
+ * The file intends to implement RTAS errinjct functionality for book3s
+ * architecture. Due to the individual errors injected to the system
+ * are defined by device tree node, it's reasonable to introduce the
+ * mechanism to register the supported errors and their corresponding
+ * handlers.
+ *
+ * Copyright Benjamin Herrenschmidt & Gavin Shan, IBM Corporation 2014.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/kvm_host.h>
+#include <linux/kvm.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+
+#include <asm/uaccess.h>
+#include <asm/kvm_book3s.h>
+#include <asm/kvm_ppc.h>
+#include <asm/book3s_errinjct.h>
+#include <asm/hvcall.h>
+
+static struct kvm_errinjct_handler handlers[kvm_errinjct_max];
+static DEFINE_SPINLOCK(handler_lock);
+static LIST_HEAD(open_token_list);
+static DEFINE_SPINLOCK(token_lock);
+static unsigned long *token_bitmap = NULL;
+static int token_max = 1024;
+
+/**
+ * kvm_errinjct_register - Register error injection handler
+ * @opcode: to idenfity the error type to be injected
+ * @handler: function to handler the error type
+ *
+ * Register function handler for the specified type of error.
+ */
+int kvm_errinjct_register(int opcode, kvm_errinjct_func handler)
+{
+ spin_lock(&handler_lock);
+ if (!opcode || !handler) {
+ spin_unlock(&handler_lock);
+ pr_warn("%s: Invalid argument\n", __func__);
+ return -EINVAL;
+ }
+
+ if (opcode <= kvm_errinjct_min ||
+ opcode >= kvm_errinjct_max) {
+ spin_unlock(&handler_lock);
+ pr_warn("%s: Opcode %d out of range (%d, %d)\n",
+ __func__, opcode, kvm_errinjct_min, kvm_errinjct_max);
+ return -ERANGE;
+ }
+
+ if (handlers[opcode].handler) {
+ spin_unlock(&handler_lock);
+ pr_warn("%s: Opcode %d had attached handler\n",
+ __func__, opcode);
+ return -EBUSY;
+ }
+
+ handlers[opcode].opcode = opcode;
+ handlers[opcode].handler = handler;
+ spin_unlock(&handler_lock);
+
+ return 0;
+}
+
+/**
+ * kvm_errinjct_unregister - Unregister error injection handler
+ * @opcode: to identify the error type
+ *
+ * Unregister function handler for the specified type of error.
+ */
+int kvm_errinjct_unregister(int opcode)
+{
+ spin_lock(&handler_lock);
+
+ if (opcode <= kvm_errinjct_min ||
+ opcode >= kvm_errinjct_max) {
+ spin_unlock(&handler_lock);
+ pr_warn("%s: Opcode %d out of range (%d, %d)\n",
+ __func__, opcode, kvm_errinjct_min, kvm_errinjct_max);
+ return -ERANGE;
+ }
+
+ handlers[opcode].opcode = 0;
+ handlers[opcode].handler = NULL;
+ spin_unlock(&handler_lock);
+
+ return 0;
+}
+
+/* Allocate token from the bitmap */
+static int kvm_errinjct_token_alloc(void)
+{
+ int token;
+
+ /* The token bitmap isn't initialized yet */
+ if (unlikely(!token_bitmap)) {
+ unsigned long size;
+ unsigned long *mem;
+
+ size = _ALIGN_UP(token_max, sizeof(unsigned long));
+ mem = kzalloc(size, GFP_KERNEL);
+ if (!mem) {
+ pr_err("%s: Out of memory!\n", __func__);
+ return -ENOMEM;
+ }
+
+ /* In case some body else did it */
+ if (unlikely(token_bitmap))
+ kfree(mem);
+ else
+ token_bitmap = mem;
+ }
+
+ /* Allocate token */
+ do {
+ token = find_next_zero_bit(token_bitmap, token_max, 0);
+ if (token >= token_max)
+ return -ERANGE;
+ } while(test_and_set_bit(token, token_bitmap));
+
+ return token;
+}
+
+/* Free token to the bitmap */
+static void kvm_errinjct_token_free(int token)
+{
+ if (unlikely(!token_bitmap))
+ return;
+ if (unlikely(token >= token_max))
+ return;
+
+ clear_bit(token, token_bitmap);
+}
+
+/* Check if the specified VM has opened token or not */
+static bool kvm_errinjct_token_get(struct kvm *kvm,
+ struct kvm_errinjct_token **token)
+{
+ struct kvm_errinjct_token *t;
+
+ list_for_each_entry(t, &open_token_list, list) {
+ if (t->kvm == kvm) {
+ if (token)
+ *token = t;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/* Emulation handler for opening token */
+static int kvmppc_errinjct_open(struct kvm_vcpu *vcpu,
+ struct rtas_args *args)
+{
+ struct kvm_errinjct_token *t;
+ int token;
+ int ret = 0;
+
+ /* Check the parameters */
+ if (args->nargs != 0 || args->nret != 2) {
+ pr_warn("%s: Breaking rule (#args: 0, #rets: 2)\n",
+ __func__);
+ ret = -1;
+ goto out;
+ }
+
+ /* Check if the guest has opened token */
+ spin_lock(&token_lock);
+ if (kvm_errinjct_token_get(vcpu->kvm, NULL)) {
+ ret = -4;
+ spin_unlock(&token_lock);
+ goto out;
+ }
+
+ /* Allocate token */
+ token = kvm_errinjct_token_alloc();
+ if (token > token_max) {
+ ret = -1;
+ spin_unlock(&token_lock);
+ goto out;
+ }
+
+ /* Attach open token */
+ t = kzalloc(sizeof(*t), GFP_KERNEL);
+ if (!t) {
+ ret = -2;
+ pr_warn("%s: Out of memory !\n", __func__);
+ kvm_errinjct_token_free(token);
+ spin_unlock(&token_lock);
+ goto out;
+ }
+ t->kvm = vcpu->kvm;
+ t->token = token;
+ INIT_LIST_HEAD(&t->list);
+ list_add_tail(&t->list, &open_token_list);
+ spin_unlock(&token_lock);
+out:
+ args->rets[1] = ret;
+ return ret == 0 ? token : -1;
+}
+
+/* Emulation handler for closing token */
+static int kvmppc_errinjct_close(struct kvm_vcpu *vcpu,
+ struct rtas_args *args)
+{
+ struct kvm_errinjct_token *t;
+ int ret = 0;
+
+ /* Check the parameters */
+ if (args->nargs != 1 || args->nret != 1) {
+ pr_warn("%s: Breaking rule (#args: 1, #rets: 1)\n",
+ __func__);
+ ret = -1;
+ goto out;
+ }
+
+ /* Search the opened token */
+ spin_lock(&token_lock);
+ if (!kvm_errinjct_token_get(vcpu->kvm, &t)) {
+ ret = -4;
+ spin_unlock(&token_lock);
+ goto out;
+ }
+
+ /* Detach and free it */
+ list_del(&t->list);
+ kvm_errinjct_token_free(t->token);
+ spin_unlock(&token_lock);
+
+ kfree(t);
+out:
+ return ret;
+}
+
+/*
+ * Emulation handler for error injection. After checking
+ * the arguments, we will dispatch the request to the
+ * dynamically registered handler if possible.
+ */
+static int kvmppc_errinjct(struct kvm_vcpu *vcpu,
+ struct rtas_args *args)
+{
+ struct kvm_errinjct_token *t;
+ int token, opcode, ret = 0;
+ rtas_arg_t buf;
+
+ /* Check the parameters */
+ if (args->nargs != 3 || args->nret != 1) {
+ pr_warn("%s: Breaking rule (#args: 3, #rets: 1)\n",
+ __func__);
+ ret = -3;
+ goto out;
+ }
+
+ /* Check opcode and buffer */
+ opcode = args->args[0];
+ token = args->args[1];
+ buf = args->args[2];
+ if (opcode < kvm_errinjct_min ||
+ opcode >= kvm_errinjct_max ||
+ (buf & 0x3fful)) {
+ ret = -3;
+ goto out;
+ }
+
+ /* Check if the VM has the opened token */
+ spin_lock(&token_lock);
+ if (!kvm_errinjct_token_get(vcpu->kvm, &t) ||
+ t->token != token) {
+ ret = -4;
+ spin_unlock(&token_lock);
+ goto out;
+ }
+ spin_unlock(&token_lock);
+
+ /* Dispatch the request */
+ spin_lock(&handler_lock);
+ if (handlers[opcode].handler)
+ ret = handlers[opcode].handler(vcpu, buf);
+ else
+ ret = -3;
+ spin_unlock(&handler_lock);
+out:
+ return ret;
+}
+
+/**
+ * kvmppc_errinjct_rtas - Common handler for error injection emulation
+ * @vcpu: KVM virtual CPU
+ * @args: RTAS call arguments
+ * @flag: error injection service indicator
+ *
+ * The function is the common handler to emulate error injection RTAS.
+ * All error injection requests will trigger the function and in turn,
+ * the requests will be distributed to individual handler.
+ */
+void kvmppc_errinjct_rtas(struct kvm_vcpu *vcpu,
+ struct rtas_args *args, int flag)
+{
+ int ret = -1;
+
+ /* Parse the requested service */
+ switch (flag) {
+ case kvm_errinjct_open_token:
+ ret = kvmppc_errinjct_open(vcpu, args);
+ break;
+ case kvm_errinjct_close_token:
+ ret = kvmppc_errinjct_close(vcpu, args);
+ break;
+ case kvm_errinjct_errinjct:
+ ret = kvmppc_errinjct(vcpu, args);
+ break;
+ default:
+ pr_warn("%s: Unsupported option %d\n",
+ __func__, flag);
+ }
+
+ /* Update the return value */
+ args->rets[0] = ret;
+}
diff --git a/arch/powerpc/kvm/book3s_rtas.c b/arch/powerpc/kvm/book3s_rtas.c
index 17bdb4a..030b006 100644
--- a/arch/powerpc/kvm/book3s_rtas.c
+++ b/arch/powerpc/kvm/book3s_rtas.c
@@ -18,6 +18,7 @@
#include <asm/rtas.h>
#include <asm/ppc-pci.h>
#include <asm/eeh.h>
+#include <asm/book3s_errinjct.h>
#ifdef CONFIG_KVM_XICS
static void kvm_rtas_set_xive(struct kvm_vcpu *vcpu, struct rtas_args *args)
@@ -123,6 +124,21 @@ KVM_RTAS_EEH_FUNC(configure_pe, eeh_rtas_configure_pe)
#endif /* CONFIG_KVM_EEH */
+#ifdef CONFIG_KVM_ERRINJCT
+
+#define KVM_RTAS_ERRINJCT_FUNC(name, flag) \
+static void kvm_rtas_errinjct_##name(struct kvm_vcpu *vcpu, \
+ struct rtas_args *args) \
+{ \
+ kvmppc_errinjct_rtas(vcpu, args, flag); \
+}
+
+KVM_RTAS_ERRINJCT_FUNC(open_token, kvm_errinjct_open_token);
+KVM_RTAS_ERRINJCT_FUNC(close_token, kvm_errinjct_close_token);
+KVM_RTAS_ERRINJCT_FUNC(errinjct, kvm_errinjct_errinjct);
+
+#endif /* CONFIG_KVM_ERRINJCT */
+
struct rtas_handler {
void (*handler)(struct kvm_vcpu *vcpu, struct rtas_args *args);
char *name;
@@ -153,8 +169,19 @@ static struct rtas_handler rtas_handlers[] = {
},
{ .name = "ibm,configure-pe",
.handler = kvm_rtas_eeh_configure_pe
- }
+ },
#endif /* CONFIG_KVM_EEH */
+#ifdef CONFIG_KVM_ERRINJCT
+ { .name = "ibm,open-errinjct",
+ .handler = kvm_rtas_errinjct_open_token
+ },
+ { .name = "ibm,close-errinjct",
+ .handler = kvm_rtas_errinjct_close_token
+ },
+ { .name = "ibm,errinjct",
+ .handler = kvm_rtas_errinjct_errinjct
+ },
+#endif /* CONFIG_KVM_ERRINJCT */
};
struct rtas_token_definition {
--
1.8.3.2
^ permalink raw reply related
* [PATCH 21/22] powerpc/powernv: Sync OPAL header file with firmware
From: Gavin Shan @ 2014-05-05 1:28 UTC (permalink / raw)
To: linuxppc-dev, kvm, kvm-ppc; +Cc: aik, alex.williamson, qiudayu, Gavin Shan
In-Reply-To: <1399253291-3975-1-git-send-email-gwshan@linux.vnet.ibm.com>
The patch synchronizes OPAL header file with firmware so that the
host kernel can make OPAL call to do error injection.
Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
---
arch/powerpc/include/asm/opal.h | 65 ++++++++++++++++++++++++++
arch/powerpc/platforms/powernv/opal-wrappers.S | 1 +
2 files changed, 66 insertions(+)
diff --git a/arch/powerpc/include/asm/opal.h b/arch/powerpc/include/asm/opal.h
index 66ad7a7..ca55d9c 100644
--- a/arch/powerpc/include/asm/opal.h
+++ b/arch/powerpc/include/asm/opal.h
@@ -175,6 +175,7 @@ extern int opal_enter_rtas(struct rtas_args *args,
#define OPAL_SET_PARAM 90
#define OPAL_DUMP_RESEND 91
#define OPAL_DUMP_INFO2 94
+#define OPAL_ERR_INJECT 96
#ifndef __ASSEMBLY__
@@ -219,6 +220,69 @@ enum OpalPciErrorSeverity {
OPAL_EEH_SEV_INF = 5
};
+enum OpalErrinjctType {
+ OpalErrinjctTypeFirst = 0,
+ OpalErrinjctTypeFatal = 1,
+ OpalErrinjctTypeRecoverRandomEvent = 2,
+ OpalErrinjctTypeRecoverSpecialEvent = 3,
+ OpalErrinjctTypeCorruptedPage = 4,
+ OpalErrinjctTypeCorruptedSlb = 5,
+ OpalErrinjctTypeTranslatorFailure = 6,
+ OpalErrinjctTypeIoaBusError = 7,
+ OpalErrinjctTypeIoaBusError64 = 8,
+ OpalErrinjctTypePlatformSpecific = 9,
+ OpalErrinjctTypeDcacheStart = 10,
+ OpalErrinjctTypeDcacheEnd = 11,
+ OpalErrinjctTypeIcacheStart = 12,
+ OpalErrinjctTypeIcacheEnd = 13,
+ OpalErrinjctTypeTlbStart = 14,
+ OpalErrinjctTypeTlbEnd = 15,
+ OpalErrinjctTypeUpstreamIoError = 16,
+ OpalErrinjctTypeLast = 17,
+
+ /* IoaBusError & IoaBusError64 */
+ OpalEjtIoaLoadMemAddr = 0,
+ OpalEjtIoaLoadMemData = 1,
+ OpalEjtIoaLoadIoAddr = 2,
+ OpalEjtIoaLoadIoData = 3,
+ OpalEjtIoaLoadConfigAddr = 4,
+ OpalEjtIoaLoadConfigData = 5,
+ OpalEjtIoaStoreMemAddr = 6,
+ OpalEjtIoaStoreMemData = 7,
+ OpalEjtIoaStoreIoAddr = 8,
+ OpalEjtIoaStoreIoData = 9,
+ OpalEjtIoaStoreConfigAddr = 10,
+ OpalEjtIoaStoreConfigData = 11,
+ OpalEjtIoaDmaReadMemAddr = 12,
+ OpalEjtIoaDmaReadMemData = 13,
+ OpalEjtIoaDmaReadMemMaster = 14,
+ OpalEjtIoaDmaReadMemTarget = 15,
+ OpalEjtIoaDmaWriteMemAddr = 16,
+ OpalEjtIoaDmaWriteMemData = 17,
+ OpalEjtIoaDmaWriteMemMaster = 18,
+ OpalEjtIoaDmaWriteMemTarget = 19,
+};
+
+struct OpalErrinjct {
+ int32_t type;
+ union {
+ struct {
+ uint32_t addr;
+ uint32_t mask;
+ uint64_t phb_id;
+ uint32_t pe;
+ uint32_t function;
+ }ioa;
+ struct {
+ uint64_t addr;
+ uint64_t mask;
+ uint64_t phb_id;
+ uint32_t pe;
+ uint32_t function;
+ }ioa64;
+ };
+};
+
enum OpalShpcAction {
OPAL_SHPC_GET_LINK_STATE = 0,
OPAL_SHPC_GET_SLOT_STATE = 1
@@ -839,6 +903,7 @@ int64_t opal_pci_get_phb_diag_data(uint64_t phb_id, void *diag_buffer,
uint64_t diag_buffer_len);
int64_t opal_pci_get_phb_diag_data2(uint64_t phb_id, void *diag_buffer,
uint64_t diag_buffer_len);
+int64_t opal_err_injct(void *data);
int64_t opal_pci_fence_phb(uint64_t phb_id);
int64_t opal_pci_reinit(uint64_t phb_id, uint64_t reinit_scope, uint64_t data);
int64_t opal_pci_mask_pe_error(uint64_t phb_id, uint16_t pe_number, uint8_t error_type, uint8_t mask_action);
diff --git a/arch/powerpc/platforms/powernv/opal-wrappers.S b/arch/powerpc/platforms/powernv/opal-wrappers.S
index f531ffe..46265de 100644
--- a/arch/powerpc/platforms/powernv/opal-wrappers.S
+++ b/arch/powerpc/platforms/powernv/opal-wrappers.S
@@ -119,6 +119,7 @@ OPAL_CALL(opal_pci_next_error, OPAL_PCI_NEXT_ERROR);
OPAL_CALL(opal_pci_poll, OPAL_PCI_POLL);
OPAL_CALL(opal_pci_msi_eoi, OPAL_PCI_MSI_EOI);
OPAL_CALL(opal_pci_get_phb_diag_data2, OPAL_PCI_GET_PHB_DIAG_DATA2);
+OPAL_CALL(opal_err_injct, OPAL_ERR_INJECT);
OPAL_CALL(opal_xscom_read, OPAL_XSCOM_READ);
OPAL_CALL(opal_xscom_write, OPAL_XSCOM_WRITE);
OPAL_CALL(opal_lpc_read, OPAL_LPC_READ);
--
1.8.3.2
^ permalink raw reply related
* [PATCH 19/22] powerpc: Introduce CONFIG_KVM_ERRINJCT
From: Gavin Shan @ 2014-05-05 1:28 UTC (permalink / raw)
To: linuxppc-dev, kvm, kvm-ppc; +Cc: aik, alex.williamson, qiudayu, Gavin Shan
In-Reply-To: <1399253291-3975-1-git-send-email-gwshan@linux.vnet.ibm.com>
The patch introduces kernel configuration option KVM_ERRINJCT. It
enables emulating error injection RTAS services used on IBM POWER
(pSeries) servers.
Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
---
arch/powerpc/kvm/Kconfig | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/arch/powerpc/kvm/Kconfig b/arch/powerpc/kvm/Kconfig
index 6764fc5..914ab05 100644
--- a/arch/powerpc/kvm/Kconfig
+++ b/arch/powerpc/kvm/Kconfig
@@ -198,6 +198,14 @@ config KVM_EEH
Enable support for emulating EEH RTAS services used on IBM
POWER (pSeries) servers.
+config KVM_ERRINJCT
+ bool "KVM in-kernel error injection emulation"
+ depends on KVM_EEH
+ default y
+ ---help---
+ Enable support for emulating error injection services used
+ on IBM POWER (pSeries) servers
+
source drivers/vhost/Kconfig
endif # VIRTUALIZATION
--
1.8.3.2
^ permalink raw reply related
* [PATCH 22/22] powerpc/powernv: Support PCI error injection
From: Gavin Shan @ 2014-05-05 1:28 UTC (permalink / raw)
To: linuxppc-dev, kvm, kvm-ppc; +Cc: aik, alex.williamson, qiudayu, Gavin Shan
In-Reply-To: <1399253291-3975-1-git-send-email-gwshan@linux.vnet.ibm.com>
The patch introduces the infrastructure of error injection backend
for PowerNV platform. For now, we just implement logic to inject
PCI errors. We need support injecting other types of errors in
future.
Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
---
arch/powerpc/include/asm/book3s_errinjct.h | 19 +++
arch/powerpc/platforms/powernv/Makefile | 1 +
arch/powerpc/platforms/powernv/errinjct.c | 215 +++++++++++++++++++++++++++++
3 files changed, 235 insertions(+)
create mode 100644 arch/powerpc/platforms/powernv/errinjct.c
diff --git a/arch/powerpc/include/asm/book3s_errinjct.h b/arch/powerpc/include/asm/book3s_errinjct.h
index 35712be..75443ad 100644
--- a/arch/powerpc/include/asm/book3s_errinjct.h
+++ b/arch/powerpc/include/asm/book3s_errinjct.h
@@ -56,6 +56,25 @@ struct kvm_errinjct_token {
struct list_head list;
};
+/* Argument buffer for various operations */
+struct kvm_errinjct_ioa_bus {
+ uint32_t addr;
+ uint32_t mask;
+ uint32_t cfg_addr;
+ uint32_t buid_hi;
+ uint32_t buid_lo;
+ uint32_t op;
+};
+
+struct kvm_errinjct_ioa_bus64 {
+ uint64_t addr;
+ uint64_t mask;
+ uint32_t cfg_addr;
+ uint32_t buid_hi;
+ uint32_t buid_lo;
+ uint32_t op;
+};
+
int kvm_errinjct_register(int opcode, kvm_errinjct_func handler);
int kvm_errinjct_unregister(int opcode);
void kvmppc_errinjct_rtas(struct kvm_vcpu *vcpu,
diff --git a/arch/powerpc/platforms/powernv/Makefile b/arch/powerpc/platforms/powernv/Makefile
index d8ea670..d096b18 100644
--- a/arch/powerpc/platforms/powernv/Makefile
+++ b/arch/powerpc/platforms/powernv/Makefile
@@ -7,5 +7,6 @@ obj-$(CONFIG_SMP) += smp.o
obj-$(CONFIG_PCI) += pci.o pci-p5ioc2.o pci-ioda.o
obj-$(CONFIG_EEH) += eeh-ioda.o eeh-powernv.o
obj-$(CONFIG_KVM_EEH) += eeh-rtas.o
+obj-$(CONFIG_KVM_ERRINJCT) += errinjct.o
obj-$(CONFIG_PPC_SCOM) += opal-xscom.o
obj-$(CONFIG_MEMORY_FAILURE) += opal-memory-errors.o
diff --git a/arch/powerpc/platforms/powernv/errinjct.c b/arch/powerpc/platforms/powernv/errinjct.c
new file mode 100644
index 0000000..ccc7853
--- /dev/null
+++ b/arch/powerpc/platforms/powernv/errinjct.c
@@ -0,0 +1,215 @@
+/*
+ * Backend for error injection implemented on PowerNV platform.
+ *
+ * Copyright Benjamin Herrenschmidt & Gavin Shan, IBM Corporation 2014.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/kvm_host.h>
+#include <linux/kvm.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+
+
+#include <asm/uaccess.h>
+#include <asm/pci-bridge.h>
+#include <asm/iommu.h>
+#include <asm/eeh.h>
+#include <asm/kvm_book3s.h>
+#include <asm/kvm_ppc.h>
+#include <asm/book3s_errinjct.h>
+#include <asm/hvcall.h>
+#include <asm/msi_bitmap.h>
+#include <asm/opal.h>
+
+#include "powernv.h"
+#include "pci.h"
+
+static int powernv_errinjct_ioa(struct kvm_vcpu *vcpu, rtas_arg_t buf)
+{
+ struct OpalErrinjct ej;
+ struct kvm_errinjct_ioa_bus args;
+ struct eeh_vfio_pci_addr addr;
+ struct eeh_pe *pe;
+ struct pnv_phb *phb;
+ long rc;
+ int ret = 0;
+
+ /* Word aligned buffer */
+ if (buf & 0x3) {
+ ret = -3;
+ goto out;
+ }
+
+ /* Copy over argument */
+ ret = kvm_read_guest(vcpu->kvm, buf, &args, sizeof(args));
+ if (ret) {
+ pr_warn("%s: Can't copyover arguments (%d)\n",
+ __func__, ret);
+ ret = -3;
+ goto out;
+ }
+
+ /*
+ * Sanity check on operation. We don't support optional
+ * operation (20) and last one (21) for now.
+ */
+ if (args.op < 0 || args.op > 21) {
+ ret = -3;
+ goto out;
+ } else if (args.op >= 20) {
+ ret = -1;
+ goto out;
+ }
+
+ /*
+ * Only do error injection on passthrou PE. It's notable
+ * the "cfg_addr" is guest PE address
+ */
+ addr.kvm = vcpu->kvm;
+ addr.buid_hi = args.buid_hi;
+ addr.buid_lo = args.buid_lo;
+ addr.pe_addr = args.cfg_addr;
+ pe = eeh_vfio_pe_get(&addr);
+ if (!pe) {
+ pr_warn("%s: Can't find passed PE (%08x-%08x-%08x)\n",
+ __func__, args.buid_hi, args.buid_lo, args.cfg_addr);
+ ret = -3;
+ goto out;
+ }
+
+ /*
+ * Calling to OPAL API. We need host PE address
+ * and PHB host BUID.
+ */
+ phb = pe->phb->private_data;
+
+ ej.type = OpalErrinjctTypeIoaBusError;
+ ej.ioa.addr = args.addr;
+ ej.ioa.mask = args.mask;
+ ej.ioa.phb_id = phb->opal_id;
+ ej.ioa.pe = pe->addr;
+ ej.ioa.function = args.op;
+ rc = opal_err_injct(&ej);
+ if (rc != OPAL_SUCCESS) {
+ pr_warn("%s: OPAL API returns %ld\n", __func__, rc);
+ ret = -1;
+ goto out;
+ }
+
+ ret = 0;
+out:
+ return ret;
+}
+
+static int powernv_errinjct_ioa64(struct kvm_vcpu *vcpu, rtas_arg_t buf)
+{
+ struct OpalErrinjct ej;
+ struct kvm_errinjct_ioa_bus64 args;
+ struct eeh_vfio_pci_addr addr;
+ struct eeh_pe *pe;
+ struct pnv_phb *phb;
+ long rc;
+ int ret = 0;
+
+ /* Double word aligned buffer */
+ if (buf & 0x7) {
+ ret = -3;
+ goto out;
+ }
+
+ /* Copy over argument */
+ ret = kvm_read_guest(vcpu->kvm, buf, &args, sizeof(args));
+ if (ret) {
+ pr_warn("%s: Can't copyover arguments (%d)\n",
+ __func__, ret);
+ ret = -3;
+ goto out;
+ }
+
+ /*
+ * Sanity check on operation. We don't support optional
+ * operation (20) and last one (21) for now.
+ */
+ if (args.op < 0 || args.op > 21) {
+ ret = -3;
+ goto out;
+ } else if (args.op >= 20) {
+ ret = -1;
+ goto out;
+ }
+
+ /*
+ * Only do error injection on passthrou PE. It's notable
+ * that "cfg_addr" is guest PE address
+ */
+ addr.kvm = vcpu->kvm;
+ addr.buid_hi = args.buid_hi;
+ addr.buid_lo = args.buid_lo;
+ addr.pe_addr = args.cfg_addr;
+ pe = eeh_vfio_pe_get(&addr);
+ if (!pe) {
+ pr_warn("%s: Can't find passed PE (%08x-%08x-%08x)\n",
+ __func__, args.buid_hi, args.buid_lo, args.cfg_addr);
+ ret = -3;
+ goto out;
+ }
+
+ /*
+ * Calling to OPAL API. We need host PE address
+ * and PHB host BUID.
+ */
+ phb = pe->phb->private_data;
+
+ ej.type = OpalErrinjctTypeIoaBusError64;
+ ej.ioa64.addr = args.addr;
+ ej.ioa64.mask = args.mask;
+ ej.ioa64.phb_id = phb->opal_id;
+ ej.ioa64.pe = pe->addr;
+ ej.ioa64.function = args.op;
+ rc = opal_err_injct(&ej);
+ if (rc != OPAL_SUCCESS) {
+ pr_warn("%s: OPAL API returns %ld\n", __func__, rc);
+ ret = -1;
+ goto out;
+ }
+
+ /* Success */
+ ret = 0;
+out:
+ return ret;
+}
+
+static struct kvm_errinjct_handler handlers[] = {
+ { .opcode = kvm_errinjct_ioa_bus_error,
+ .handler = powernv_errinjct_ioa
+ },
+ { .opcode = kvm_errinjct_ioa_bus_error_64,
+ .handler = powernv_errinjct_ioa64
+ }
+};
+
+static int __init powernv_errinjct_init(void)
+{
+ int i, ret;
+
+ for (i = 0; i < ARRAY_SIZE(handlers); i++) {
+ ret = kvm_errinjct_register(handlers[i].opcode,
+ handlers[i].handler);
+ if (ret) {
+ pr_warn("%s: Failure registering handler %d (%d)\n",
+ __func__, handlers[i].opcode, ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+module_init(powernv_errinjct_init);
--
1.8.3.2
^ permalink raw reply related
* [PATCH] powerpc/eeh: Fix build error for celleb
From: Gavin Shan @ 2014-05-05 2:09 UTC (permalink / raw)
To: benh; +Cc: linuxppc-dev, Gavin Shan
Commit 7f52a526f ("powerpc/eeh: Allow to disable EEH") caused
following build error with "celleb_defconfig" as being catched
by Mikey on linux-next.
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
Reported-by: Michael Neuling <mikey@neuling.org>
Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
---
arch/powerpc/kernel/eeh.c | 1 +
1 file changed, 1 insertion(+)
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>
#include <linux/atomic.h>
+#include <asm/debug.h>
#include <asm/eeh.h>
#include <asm/eeh_event.h>
#include <asm/io.h>
--
1.8.3.2
^ permalink raw reply related
* [PATCH V5] KVM: PPC: BOOK3S: PR: Enable Little Endian PR guest
From: Aneesh Kumar K.V @ 2014-05-05 3:09 UTC (permalink / raw)
To: agraf, benh, paulus; +Cc: linuxppc-dev, kvm, kvm-ppc, Aneesh Kumar K.V
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>
---
Changes from V4:
* Don't check for MSR_LE bit while setting LPCR.
arch/powerpc/include/asm/kvm_host.h | 2 +-
arch/powerpc/kernel/asm-offsets.c | 2 +-
arch/powerpc/kvm/book3s_64_mmu.c | 2 +-
arch/powerpc/kvm/book3s_pr.c | 23 ++++++++++++++++++++++-
4 files changed, 25 insertions(+), 4 deletions(-)
diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h
index 1eaea2dea174..d342f8efc843 100644
--- a/arch/powerpc/include/asm/kvm_host.h
+++ b/arch/powerpc/include/asm/kvm_host.h
@@ -562,6 +562,7 @@ struct kvm_vcpu_arch {
#ifdef CONFIG_PPC_BOOK3S
ulong fault_dar;
u32 fault_dsisr;
+ unsigned long intr_msr;
#endif
#ifdef CONFIG_BOOKE
@@ -654,7 +655,6 @@ struct kvm_vcpu_arch {
spinlock_t tbacct_lock;
u64 busy_stolen;
u64 busy_preempt;
- unsigned long intr_msr;
#endif
};
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c
index dba8140ebc20..6a4b77d197f3 100644
--- a/arch/powerpc/kernel/asm-offsets.c
+++ b/arch/powerpc/kernel/asm-offsets.c
@@ -493,7 +493,6 @@ int main(void)
DEFINE(VCPU_DAR, offsetof(struct kvm_vcpu, arch.shregs.dar));
DEFINE(VCPU_VPA, offsetof(struct kvm_vcpu, arch.vpa.pinned_addr));
DEFINE(VCPU_VPA_DIRTY, offsetof(struct kvm_vcpu, arch.vpa.dirty));
- DEFINE(VCPU_INTR_MSR, offsetof(struct kvm_vcpu, arch.intr_msr));
#endif
#ifdef CONFIG_PPC_BOOK3S
DEFINE(VCPU_VCPUID, offsetof(struct kvm_vcpu, vcpu_id));
@@ -528,6 +527,7 @@ int main(void)
DEFINE(VCPU_SLB_NR, offsetof(struct kvm_vcpu, arch.slb_nr));
DEFINE(VCPU_FAULT_DSISR, offsetof(struct kvm_vcpu, arch.fault_dsisr));
DEFINE(VCPU_FAULT_DAR, offsetof(struct kvm_vcpu, arch.fault_dar));
+ DEFINE(VCPU_INTR_MSR, offsetof(struct kvm_vcpu, arch.intr_msr));
DEFINE(VCPU_LAST_INST, offsetof(struct kvm_vcpu, arch.last_inst));
DEFINE(VCPU_TRAP, offsetof(struct kvm_vcpu, arch.trap));
DEFINE(VCPU_CFAR, offsetof(struct kvm_vcpu, arch.cfar));
diff --git a/arch/powerpc/kvm/book3s_64_mmu.c b/arch/powerpc/kvm/book3s_64_mmu.c
index 83da1f868fd5..8231b83c493b 100644
--- a/arch/powerpc/kvm/book3s_64_mmu.c
+++ b/arch/powerpc/kvm/book3s_64_mmu.c
@@ -38,7 +38,7 @@
static void kvmppc_mmu_book3s_64_reset_msr(struct kvm_vcpu *vcpu)
{
- kvmppc_set_msr(vcpu, MSR_SF);
+ kvmppc_set_msr(vcpu, vcpu->arch.intr_msr);
}
static struct kvmppc_slb *kvmppc_mmu_book3s_64_find_slbe(
diff --git a/arch/powerpc/kvm/book3s_pr.c b/arch/powerpc/kvm/book3s_pr.c
index f30cdfee800d..01a7156d055c 100644
--- a/arch/powerpc/kvm/book3s_pr.c
+++ b/arch/powerpc/kvm/book3s_pr.c
@@ -249,7 +249,7 @@ static void kvmppc_recalc_shadow_msr(struct kvm_vcpu *vcpu)
ulong smsr = vcpu->arch.shared->msr;
/* Guest MSR values */
- smsr &= MSR_FE0 | MSR_FE1 | MSR_SF | MSR_SE | MSR_BE;
+ smsr &= MSR_FE0 | MSR_FE1 | MSR_SF | MSR_SE | MSR_BE | MSR_LE;
/* Process MSR values */
smsr |= MSR_ME | MSR_RI | MSR_IR | MSR_DR | MSR_PR | MSR_EE;
/* External providers the guest reserved */
@@ -1118,6 +1118,15 @@ static int kvmppc_get_one_reg_pr(struct kvm_vcpu *vcpu, u64 id,
case KVM_REG_PPC_HIOR:
*val = get_reg_val(id, to_book3s(vcpu)->hior);
break;
+ case KVM_REG_PPC_LPCR:
+ /*
+ * We are only interested in the LPCR_ILE bit
+ */
+ if (vcpu->arch.intr_msr & MSR_LE)
+ *val = get_reg_val(id, LPCR_ILE);
+ else
+ *val = get_reg_val(id, 0);
+ break;
default:
r = -EINVAL;
break;
@@ -1126,6 +1135,14 @@ static int kvmppc_get_one_reg_pr(struct kvm_vcpu *vcpu, u64 id,
return r;
}
+static void kvmppc_set_lpcr_pr(struct kvm_vcpu *vcpu, u64 new_lpcr)
+{
+ if (new_lpcr & LPCR_ILE)
+ vcpu->arch.intr_msr |= MSR_LE;
+ else
+ vcpu->arch.intr_msr &= ~MSR_LE;
+}
+
static int kvmppc_set_one_reg_pr(struct kvm_vcpu *vcpu, u64 id,
union kvmppc_one_reg *val)
{
@@ -1136,6 +1153,9 @@ static int kvmppc_set_one_reg_pr(struct kvm_vcpu *vcpu, u64 id,
to_book3s(vcpu)->hior = set_reg_val(id, *val);
to_book3s(vcpu)->hior_explicit = true;
break;
+ case KVM_REG_PPC_LPCR:
+ kvmppc_set_lpcr_pr(vcpu, set_reg_val(id, *val));
+ break;
default:
r = -EINVAL;
break;
@@ -1188,6 +1208,7 @@ static struct kvm_vcpu *kvmppc_core_vcpu_create_pr(struct kvm *kvm,
vcpu->arch.pvr = 0x3C0301;
if (mmu_has_feature(MMU_FTR_1T_SEGMENT))
vcpu->arch.pvr = mfspr(SPRN_PVR);
+ vcpu->arch.intr_msr = MSR_SF;
#else
/* default to book3s_32 (750) */
vcpu->arch.pvr = 0x84202;
--
1.9.1
^ permalink raw reply related
* [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
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