From: Boris Ostrovsky <boris.ostrovsky@oracle.com>
To: david.vrabel@citrix.com, konrad.wilk@oracle.com
Cc: boris.ostrovsky@oracle.com, kevin.tian@intel.com,
dietmar.hahn@ts.fujitsu.com, JBeulich@suse.com,
xen-devel@lists.xen.org
Subject: [PATCH v2 6/6] xen/PMU: PMU emulation code
Date: Fri, 6 Jun 2014 13:44:46 -0400 [thread overview]
Message-ID: <1402076686-26586-7-git-send-email-boris.ostrovsky@oracle.com> (raw)
In-Reply-To: <1402076686-26586-1-git-send-email-boris.ostrovsky@oracle.com>
Add PMU emulation code that runs when we are processing a PMU interrupt. This code
will allow us not to trap to hypervisor on each MSR/LVTPC access (of which there
may be quite a few in the handler).
Signed-off-by: Boris Ostrovsky <boris.ostrovsky@oracle.com>
---
arch/x86/xen/pmu.c | 209 ++++++++++++++++++++++++++++++++++++-----
include/xen/interface/xenpmu.h | 1 +
2 files changed, 187 insertions(+), 23 deletions(-)
diff --git a/arch/x86/xen/pmu.c b/arch/x86/xen/pmu.c
index f92d406..e543629 100644
--- a/arch/x86/xen/pmu.c
+++ b/arch/x86/xen/pmu.c
@@ -13,11 +13,22 @@
/* x86_pmu.handle_irq definition */
#include <../kernel/cpu/perf_event.h>
+#define XENPMU_IRQ_PROCESSING 1
+struct xenpmu {
+ /* Shared page between hypervisor and domain */
+ struct xen_pmu_data *xenpmu_data;
-/* Shared page between hypervisor and domain */
-DEFINE_PER_CPU(struct xen_pmu_data *, xenpmu_shared);
-#define get_xenpmu_data() per_cpu(xenpmu_shared, smp_processor_id());
+ uint8_t flags;
+};
+DEFINE_PER_CPU(struct xenpmu, xenpmu_shared);
+#define get_xenpmu_data() ((per_cpu(xenpmu_shared, \
+ smp_processor_id())).xenpmu_data)
+#define get_xenpmu_flags() ((per_cpu(xenpmu_shared, \
+ smp_processor_id())).flags)
+/* Macro for computing address of a PMU MSR bank */
+#define field_offset(ctxt, field) ((void *)((uintptr_t)ctxt + \
+ (uintptr_t)ctxt->field))
/* AMD PMU */
#define F15H_NUM_COUNTERS 6
@@ -160,18 +171,124 @@ static bool is_intel_pmu_msr(u32 msr_index, int *type, int *index)
return false;
}
-bool pmu_msr_read(unsigned int msr, uint64_t *val, int *err)
+static bool xen_intel_pmu_emulate(unsigned int msr, u64 *val, int type,
+ int index, bool is_read)
+{
+ uint64_t *reg = NULL;
+ struct xen_pmu_intel_ctxt *ctxt;
+ uint64_t *fix_counters;
+ struct xen_pmu_cntr_pair *arch_cntr_pair;
+ struct xen_pmu_data *xenpmu_data = get_xenpmu_data();
+ uint8_t xenpmu_flags = get_xenpmu_flags();
+
+
+ if (!xenpmu_data || !(xenpmu_flags & XENPMU_IRQ_PROCESSING))
+ return false;
+
+ ctxt = &xenpmu_data->pmu.intel;
+
+ switch (msr) {
+ case MSR_CORE_PERF_GLOBAL_OVF_CTRL:
+ reg = &ctxt->global_ovf_ctrl;
+ break;
+ case MSR_CORE_PERF_GLOBAL_STATUS:
+ reg = &ctxt->global_status;
+ break;
+ case MSR_CORE_PERF_GLOBAL_CTRL:
+ reg = &ctxt->global_ctrl;
+ break;
+ case MSR_CORE_PERF_FIXED_CTR_CTRL:
+ reg = &ctxt->fixed_ctrl;
+ break;
+ default:
+ switch (type) {
+ case MSR_TYPE_COUNTER:
+ fix_counters = field_offset(ctxt, fixed_counters);
+ reg = &fix_counters[index];
+ break;
+ case MSR_TYPE_ARCH_COUNTER:
+ arch_cntr_pair = field_offset(ctxt, arch_counters);
+ reg = &arch_cntr_pair[index].counter;
+ break;
+ case MSR_TYPE_ARCH_CTRL:
+ arch_cntr_pair = field_offset(ctxt, arch_counters);
+ reg = &arch_cntr_pair[index].control;
+ break;
+ default:
+ return false;
+ }
+ }
+
+ if (reg) {
+ if (is_read)
+ *val = *reg;
+ else {
+ *reg = *val;
+
+ if (msr == MSR_CORE_PERF_GLOBAL_OVF_CTRL)
+ ctxt->global_status &= (~(*val));
+ }
+ return true;
+ }
+
+ return false;
+}
+
+static bool xen_amd_pmu_emulate(unsigned int msr, u64 *val, bool is_read)
{
+ uint64_t *reg = NULL;
+ int i, off = 0;
+ struct xen_pmu_amd_ctxt *ctxt;
+ uint64_t *counter_regs, *ctrl_regs;
+ struct xen_pmu_data *xenpmu_data = get_xenpmu_data();
+ uint8_t xenpmu_flags = get_xenpmu_flags();
+
+ if (!xenpmu_data || !(xenpmu_flags & XENPMU_IRQ_PROCESSING))
+ return false;
+
+ if (k7_counters_mirrored &&
+ ((msr >= MSR_K7_EVNTSEL0) && (msr <= MSR_K7_PERFCTR3)))
+ msr = get_fam15h_addr(msr);
+ ctxt = &xenpmu_data->pmu.amd;
+ for (i = 0; i < amd_num_counters; i++) {
+ if (msr == amd_ctrls_base + off) {
+ ctrl_regs = field_offset(ctxt, ctrls);
+ reg = &ctrl_regs[i];
+ break;
+ } else if (msr == amd_counters_base + off) {
+ counter_regs = field_offset(ctxt, counters);
+ reg = &counter_regs[i];
+ break;
+ }
+ off += amd_msr_step;
+ }
+
+ if (reg) {
+ if (is_read)
+ *val = *reg;
+ else
+ *reg = *val;
+
+ return true;
+ }
+ return false;
+}
+
+bool pmu_msr_read(unsigned int msr, uint64_t *val, int *err)
+{
if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) {
if (is_amd_pmu_msr(msr)) {
- *val = native_read_msr_safe(msr, err);
+ if (!xen_amd_pmu_emulate(msr, val, 1))
+ *val = native_read_msr_safe(msr, err);
return true;
}
} else {
int type, index;
+
if (is_intel_pmu_msr(msr, &type, &index)) {
- *val = native_read_msr_safe(msr, err);
+ if (!xen_intel_pmu_emulate(msr, val, type, index, 1))
+ *val = native_read_msr_safe(msr, err);
return true;
}
}
@@ -181,16 +298,20 @@ bool pmu_msr_read(unsigned int msr, uint64_t *val, int *err)
bool pmu_msr_write(unsigned int msr, uint32_t low, uint32_t high, int *err)
{
+ uint64_t val = ((uint64_t)high << 32) | low;
+
if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) {
if (is_amd_pmu_msr(msr)) {
- *err = native_write_msr_safe(msr, low, high);
+ if (!xen_amd_pmu_emulate(msr, &val, 0))
+ *err = native_write_msr_safe(msr, low, high);
return true;
}
} else {
int type, index;
if (is_intel_pmu_msr(msr, &type, &index)) {
- *err = native_write_msr_safe(msr, low, high);
+ if (!xen_intel_pmu_emulate(msr, &val, type, index, 0))
+ *err = native_write_msr_safe(msr, low, high);
return true;
}
}
@@ -200,24 +321,52 @@ bool pmu_msr_write(unsigned int msr, uint32_t low, uint32_t high, int *err)
unsigned long long xen_amd_read_pmc(int counter)
{
- uint32_t msr;
- int err;
+ struct xen_pmu_amd_ctxt *ctxt;
+ uint64_t *counter_regs;
+ struct xen_pmu_data *xenpmu_data = get_xenpmu_data();
+ uint8_t xenpmu_flags = get_xenpmu_flags();
+
+ if (!xenpmu_data || !(xenpmu_flags & XENPMU_IRQ_PROCESSING)) {
+ uint32_t msr;
+ int err;
+
+ msr = amd_counters_base + (counter * amd_msr_step);
+ return native_read_msr_safe(msr, &err);
+ }
- msr = amd_counters_base + (counter * amd_msr_step);
- return native_read_msr_safe(msr, &err);
+ ctxt = &xenpmu_data->pmu.amd;
+ counter_regs = field_offset(ctxt, counters);
+ return counter_regs[counter];
}
unsigned long long xen_intel_read_pmc(int counter)
{
- int err;
- uint32_t msr;
+ struct xen_pmu_intel_ctxt *ctxt;
+ uint64_t *fixed_counters;
+ struct xen_pmu_cntr_pair *arch_cntr_pair;
+ struct xen_pmu_data *xenpmu_data = get_xenpmu_data();
+ uint8_t xenpmu_flags = get_xenpmu_flags();
- if (counter & (1<<30))
- msr = MSR_CORE_PERF_FIXED_CTR0 + (counter & 0xffff);
- else
- msr = MSR_IA32_PERFCTR0 + counter;
+ if (!xenpmu_data || !(xenpmu_flags & XENPMU_IRQ_PROCESSING)) {
+ uint32_t msr;
+ int err;
+
+ if (counter & (1<<30))
+ msr = MSR_CORE_PERF_FIXED_CTR0 + (counter & 0xffff);
+ else
+ msr = MSR_IA32_PERFCTR0 + counter;
- return native_read_msr_safe(msr, &err);
+ return native_read_msr_safe(msr, &err);
+ }
+
+ ctxt = &xenpmu_data->pmu.intel;
+ if (counter & (1<<30)) {
+ fixed_counters = field_offset(ctxt, fixed_counters);
+ return fixed_counters[counter & 0xffff];
+ } else {
+ arch_cntr_pair = field_offset(ctxt, arch_counters);
+ return arch_cntr_pair[counter].counter;
+ }
}
unsigned long long xen_read_pmc(int counter)
@@ -302,24 +451,37 @@ static void xen_convert_regs(struct cpu_user_regs *xen_regs,
irqreturn_t xen_pmu_irq_handler(int irq, void *dev_id)
{
int ret = IRQ_NONE;
+ int err;
struct pt_regs regs;
struct xen_pmu_data *xenpmu_data = get_xenpmu_data();
+ uint8_t xenpmu_flags = get_xenpmu_flags();
if (!xenpmu_data) {
WARN_ONCE(1, "%s: pmudata not initialized\n", __func__);
return ret;
}
+ per_cpu(xenpmu_shared, smp_processor_id()).flags =
+ xenpmu_flags | XENPMU_IRQ_PROCESSING;
+
xen_convert_regs(&xenpmu_data->pmu.regs, ®s);
if (x86_pmu.handle_irq(®s))
ret = IRQ_HANDLED;
+ /* Write out cached context to HW */
+ err = HYPERVISOR_xenpmu_op(XENPMU_flush, NULL);
+ per_cpu(xenpmu_shared, smp_processor_id()).flags = xenpmu_flags;
+ if (err) {
+ WARN_ONCE(1, "%s failed hypercall, err: %d\n", __func__, err);
+ return IRQ_NONE;
+ }
+
return ret;
}
bool is_xen_pmu(int cpu)
{
- return (per_cpu(xenpmu_shared, cpu) != NULL);
+ return (get_xenpmu_data() != NULL);
}
int xen_pmu_init(int cpu)
@@ -345,7 +507,8 @@ int xen_pmu_init(int cpu)
if (ret)
goto fail;
- per_cpu(xenpmu_shared, cpu) = xenpmu_data;
+ per_cpu(xenpmu_shared, cpu).xenpmu_data = xenpmu_data;
+ per_cpu(xenpmu_shared, cpu).flags = 0;
if (cpu == 0) {
perf_register_guest_info_callbacks(&xen_guest_cbs);
@@ -369,6 +532,6 @@ void xen_pmu_finish(int cpu)
(void)HYPERVISOR_xenpmu_op(XENPMU_finish, &xp);
- vfree(per_cpu(xenpmu_shared, cpu));
- per_cpu(xenpmu_shared, cpu) = NULL;
+ vfree(per_cpu(xenpmu_shared, cpu).xenpmu_data);
+ per_cpu(xenpmu_shared, cpu).xenpmu_data = NULL;
}
diff --git a/include/xen/interface/xenpmu.h b/include/xen/interface/xenpmu.h
index 79384e4..ec90673 100644
--- a/include/xen/interface/xenpmu.h
+++ b/include/xen/interface/xenpmu.h
@@ -14,6 +14,7 @@
#define XENPMU_init 4
#define XENPMU_finish 5
#define XENPMU_lvtpc_set 6
+#define XENPMU_flush 7 /* Write cached MSR values to HW */
/* Parameter structure for HYPERVISOR_xenpmu_op call */
struct xen_pmu_params {
--
1.8.1.4
next prev parent reply other threads:[~2014-06-06 17:44 UTC|newest]
Thread overview: 30+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-06-06 17:44 [PATCH v2 0/6] xen/PMU: PMU support for Xen PV guests Boris Ostrovsky
2014-06-06 17:44 ` [PATCH v2 1/6] xen: xensyms support Boris Ostrovsky
2014-06-10 13:31 ` David Vrabel
2014-06-10 14:49 ` Boris Ostrovsky
2014-06-10 14:51 ` Jan Beulich
2014-06-10 15:03 ` Boris Ostrovsky
2014-06-10 15:21 ` Jan Beulich
2014-06-10 15:45 ` Boris Ostrovsky
2014-06-10 16:13 ` Jan Beulich
2014-06-11 9:37 ` Dietmar Hahn
2014-06-06 17:44 ` [PATCH v2 2/6] xen/PMU: Sysfs interface for setting Xen PMU mode Boris Ostrovsky
2014-06-06 20:19 ` Konrad Rzeszutek Wilk
2014-06-10 13:33 ` David Vrabel
2014-06-10 13:48 ` David Vrabel
2014-06-10 14:52 ` Boris Ostrovsky
2014-06-11 10:13 ` Dietmar Hahn
2014-06-11 12:53 ` Boris Ostrovsky
2014-06-11 13:12 ` Dietmar Hahn
2014-06-06 17:44 ` [PATCH v2 3/6] xen/PMU: Initialization code for Xen PMU Boris Ostrovsky
2014-06-06 18:57 ` Andrew Cooper
2014-06-06 19:51 ` Boris Ostrovsky
2014-06-06 17:44 ` [PATCH v2 4/6] xen/PMU: Describe vendor-specific PMU registers Boris Ostrovsky
2014-06-10 14:11 ` David Vrabel
2014-06-10 15:29 ` Boris Ostrovsky
2014-06-06 17:44 ` [PATCH v2 5/6] xen/PMU: Intercept PMU-related MSR and APIC accesses Boris Ostrovsky
2014-06-12 6:56 ` Dietmar Hahn
2014-06-12 14:50 ` Boris Ostrovsky
2014-06-06 17:44 ` Boris Ostrovsky [this message]
2014-06-10 13:57 ` [PATCH v2 0/6] xen/PMU: PMU support for Xen PV guests David Vrabel
2014-06-10 15:27 ` Boris Ostrovsky
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1402076686-26586-7-git-send-email-boris.ostrovsky@oracle.com \
--to=boris.ostrovsky@oracle.com \
--cc=JBeulich@suse.com \
--cc=david.vrabel@citrix.com \
--cc=dietmar.hahn@ts.fujitsu.com \
--cc=kevin.tian@intel.com \
--cc=konrad.wilk@oracle.com \
--cc=xen-devel@lists.xen.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).