xen-devel.lists.xenproject.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/2] xenoprofile: Add IBS support
@ 2010-07-30 13:28 Wei Wang2
  0 siblings, 0 replies; only message in thread
From: Wei Wang2 @ 2010-07-30 13:28 UTC (permalink / raw)
  To: xen-devel@lists.xensource.com

[-- Attachment #1: Type: text/plain, Size: 385 bytes --]

Patch for Xen.

Signed-off-by: Wei Wang <wei.wang2@amd.com>
-- 
AMD GmbH, Germany
Operating System Research Center

Legal Information:
Advanced Micro Devices GmbH
Karl-Hammerschmidt-Str. 34
85609 Dornach b. München

Geschäftsführer: Andrew Bowd, Thomas M. McCoy, Giuliano Meroni
Sitz: Dornach, Gemeinde Aschheim, Landkreis München
Registergericht München, HRB Nr. 43632

[-- Attachment #2: ibs_xen.patch --]
[-- Type: text/x-diff, Size: 15526 bytes --]

diff -r 4514d5890692 xen/arch/x86/oprofile/nmi_int.c
--- a/xen/arch/x86/oprofile/nmi_int.c	Fri Jul 16 17:44:04 2010 +0100
+++ b/xen/arch/x86/oprofile/nmi_int.c	Fri Jul 30 12:28:48 2010 +0200
@@ -28,6 +28,7 @@
 #include "op_x86_model.h"
  
 struct op_counter_config counter_config[OP_MAX_COUNTER];
+struct op_ibs_config ibs_config;
 
 static struct op_x86_model_spec const *__read_mostly model;
 static struct op_msrs cpu_msrs[NR_CPUS];
@@ -430,6 +431,7 @@ static int __init nmi_init(void)
 			case 0x10:
 				model = &op_athlon_spec;
 				cpu_type = "x86-64/family10";
+				ibs_caps = ibs_init();
 				break;
 			case 0x11:
 				model = &op_athlon_spec;
diff -r 4514d5890692 xen/arch/x86/oprofile/op_counter.h
--- a/xen/arch/x86/oprofile/op_counter.h	Fri Jul 16 17:44:04 2010 +0100
+++ b/xen/arch/x86/oprofile/op_counter.h	Fri Jul 30 12:28:48 2010 +0200
@@ -26,4 +26,16 @@ struct op_counter_config {
 
 extern struct op_counter_config counter_config[];
 
+/* AMD IBS configuration */
+struct op_ibs_config {
+    unsigned long op_enabled;
+    unsigned long fetch_enabled;
+    unsigned long max_cnt_fetch;
+    unsigned long max_cnt_op;
+    unsigned long rand_en;
+    unsigned long dispatched_ops;
+};
+
+extern struct op_ibs_config ibs_config;
+
 #endif /* OP_COUNTER_H */
diff -r 4514d5890692 xen/arch/x86/oprofile/op_model_athlon.c
--- a/xen/arch/x86/oprofile/op_model_athlon.c	Fri Jul 16 17:44:04 2010 +0100
+++ b/xen/arch/x86/oprofile/op_model_athlon.c	Fri Jul 30 12:28:48 2010 +0200
@@ -19,6 +19,7 @@
 #include <asm/regs.h>
 #include <asm/current.h>
 #include <asm/hvm/support.h>
+#include <xen/pci_regs.h>
  
 #include "op_x86_model.h"
 #include "op_counter.h"
@@ -47,6 +48,116 @@ static unsigned long reset_value[NUM_COU
 
 extern char svm_stgi_label[];
 
+u32 ibs_caps = 0;
+static u64 ibs_op_ctl;
+
+/* IBS cpuid feature detection */
+#define IBS_CPUID_FEATURES              0x8000001b
+
+/* IBS MSRs */
+#define MSR_AMD64_IBSFETCHCTL           0xc0011030
+#define MSR_AMD64_IBSFETCHLINAD         0xc0011031
+#define MSR_AMD64_IBSFETCHPHYSAD        0xc0011032
+#define MSR_AMD64_IBSOPCTL              0xc0011033
+#define MSR_AMD64_IBSOPRIP              0xc0011034
+#define MSR_AMD64_IBSOPDATA             0xc0011035
+#define MSR_AMD64_IBSOPDATA2            0xc0011036
+#define MSR_AMD64_IBSOPDATA3            0xc0011037
+#define MSR_AMD64_IBSDCLINAD            0xc0011038
+#define MSR_AMD64_IBSDCPHYSAD           0xc0011039
+#define MSR_AMD64_IBSCTL                0xc001103a
+
+/*
+ * Same bit mask as for IBS cpuid feature flags (Fn8000_001B_EAX), but
+ * bit 0 is used to indicate the existence of IBS.
+ */
+#define IBS_CAPS_AVAIL                  (1LL<<0)
+#define IBS_CAPS_RDWROPCNT              (1LL<<3)
+#define IBS_CAPS_OPCNT                  (1LL<<4)
+
+/* IBS randomization macros */
+#define IBS_RANDOM_BITS                 12
+#define IBS_RANDOM_MASK                 ((1ULL << IBS_RANDOM_BITS) - 1)
+#define IBS_RANDOM_MAXCNT_OFFSET        (1ULL << (IBS_RANDOM_BITS - 5))
+
+/* IbsFetchCtl bits/masks */
+#define IBS_FETCH_RAND_EN               (1ULL<<57)
+#define IBS_FETCH_VAL                   (1ULL<<49)
+#define IBS_FETCH_ENABLE                (1ULL<<48)
+#define IBS_FETCH_CNT                   0xFFFF0000ULL
+#define IBS_FETCH_MAX_CNT               0x0000FFFFULL
+
+/* IbsOpCtl bits */
+#define IBS_OP_CNT_CTL                  (1ULL<<19)
+#define IBS_OP_VAL                      (1ULL<<18)
+#define IBS_OP_ENABLE                   (1ULL<<17)
+#define IBS_OP_MAX_CNT                  0x0000FFFFULL
+
+/* IBS sample identifier */
+#define IBS_FETCH_CODE                  13
+#define IBS_OP_CODE                     14
+
+#define clamp(val, min, max) ({			\
+	typeof(val) __val = (val);		\
+	typeof(min) __min = (min);		\
+	typeof(max) __max = (max);		\
+	(void) (&__val == &__min);		\
+	(void) (&__val == &__max);		\
+	__val = __val < __min ? __min: __val;	\
+	__val > __max ? __max: __val; })
+
+/*
+ * 16-bit Linear Feedback Shift Register (LFSR)
+ */
+static unsigned int lfsr_random(void)
+{
+    static unsigned int lfsr_value = 0xF00D;
+    unsigned int bit;
+
+    /* Compute next bit to shift in */
+    bit = ((lfsr_value >> 0) ^
+           (lfsr_value >> 2) ^
+           (lfsr_value >> 3) ^
+           (lfsr_value >> 5)) & 0x0001;
+
+    /* Advance to next register value */
+    lfsr_value = (lfsr_value >> 1) | (bit << 15);
+
+    return lfsr_value;
+}
+
+/*
+ * IBS software randomization
+ *
+ * The IBS periodic op counter is randomized in software. The lower 12
+ * bits of the 20 bit counter are randomized. IbsOpCurCnt is
+ * initialized with a 12 bit random value.
+ */
+static inline u64 op_amd_randomize_ibs_op(u64 val)
+{
+    unsigned int random = lfsr_random();
+
+    if (!(ibs_caps & IBS_CAPS_RDWROPCNT))
+        /*
+         * Work around if the hw can not write to IbsOpCurCnt
+         *
+         * Randomize the lower 8 bits of the 16 bit
+         * IbsOpMaxCnt [15:0] value in the range of -128 to
+         * +127 by adding/subtracting an offset to the
+         * maximum count (IbsOpMaxCnt).
+         *
+         * To avoid over or underflows and protect upper bits
+         * starting at bit 16, the initial value for
+         * IbsOpMaxCnt must fit in the range from 0x0081 to
+         * 0xff80.
+         */
+        val += (s8)(random >> 4);
+    else
+        val |= (u64)(random & IBS_RANDOM_MASK) << 32;
+
+    return val;
+}
+
 static void athlon_fill_in_addresses(struct op_msrs * const msrs)
 {
 	msrs->counters[0].addr = MSR_K7_PERFCTR0;
@@ -101,6 +212,78 @@ static void athlon_setup_ctrs(struct op_
 	}
 }
 
+static inline void
+ibs_log_event(u64 data, struct cpu_user_regs * const regs, int mode)
+{
+	struct vcpu *v = current;
+	u32 temp = 0;
+
+	temp = data & 0xFFFFFFFF;
+	xenoprof_log_event(v, regs, temp, mode, 0);
+	
+	temp = (data >> 32) & 0xFFFFFFFF;
+	xenoprof_log_event(v, regs, temp, mode, 0);
+	
+}
+
+static inline int handle_ibs(int mode, struct cpu_user_regs * const regs)
+{
+	u64 val, ctl;
+	struct vcpu *v = current;
+
+	if (!ibs_caps)
+		return 1;
+
+	if (ibs_config.fetch_enabled) {
+		rdmsrl(MSR_AMD64_IBSFETCHCTL, ctl);
+		if (ctl & IBS_FETCH_VAL) {
+			rdmsrl(MSR_AMD64_IBSFETCHLINAD, val);
+			xenoprof_log_event(v, regs, IBS_FETCH_CODE, mode, 0);
+			xenoprof_log_event(v, regs, val, mode, 0);
+
+			ibs_log_event(val, regs, mode);
+			ibs_log_event(ctl, regs, mode);
+
+			rdmsrl(MSR_AMD64_IBSFETCHPHYSAD, val);
+			ibs_log_event(val, regs, mode);
+		
+			/* reenable the IRQ */
+			ctl &= ~(IBS_FETCH_VAL | IBS_FETCH_CNT);
+			ctl |= IBS_FETCH_ENABLE;
+			wrmsrl(MSR_AMD64_IBSFETCHCTL, ctl);
+		}
+	}
+
+	if (ibs_config.op_enabled) {
+		rdmsrl(MSR_AMD64_IBSOPCTL, ctl);
+		if (ctl & IBS_OP_VAL) {
+
+			rdmsrl(MSR_AMD64_IBSOPRIP, val);
+			xenoprof_log_event(v, regs, IBS_OP_CODE, mode, 0);
+			xenoprof_log_event(v, regs, val, mode, 0);
+			
+			ibs_log_event(val, regs, mode);
+
+			rdmsrl(MSR_AMD64_IBSOPDATA, val);
+			ibs_log_event(val, regs, mode);
+			rdmsrl(MSR_AMD64_IBSOPDATA2, val);
+			ibs_log_event(val, regs, mode);
+			rdmsrl(MSR_AMD64_IBSOPDATA3, val);
+			ibs_log_event(val, regs, mode);
+			rdmsrl(MSR_AMD64_IBSDCLINAD, val);
+			ibs_log_event(val, regs, mode);
+			rdmsrl(MSR_AMD64_IBSDCPHYSAD, val);
+			ibs_log_event(val, regs, mode);
+
+			/* reenable the IRQ */
+			ctl = op_amd_randomize_ibs_op(ibs_op_ctl);
+			wrmsrl(MSR_AMD64_IBSOPCTL, ctl);
+		}
+	}
+
+    return 1;
+}
+
 static int athlon_check_ctrs(unsigned int const cpu,
 			     struct op_msrs const * const msrs,
 			     struct cpu_user_regs * const regs)
@@ -134,10 +317,51 @@ static int athlon_check_ctrs(unsigned in
 		}
 	}
 
+	ovf = handle_ibs(mode, regs);
 	/* See op_model_ppro.c */
 	return ovf;
 }
 
+static inline void start_ibs(void)
+{
+	u64 val = 0;
+
+	if (!ibs_caps)
+		return;
+
+	if (ibs_config.fetch_enabled) {
+		val = (ibs_config.max_cnt_fetch >> 4) & IBS_FETCH_MAX_CNT;
+		val |= ibs_config.rand_en ? IBS_FETCH_RAND_EN : 0;
+		val |= IBS_FETCH_ENABLE;
+		wrmsrl(MSR_AMD64_IBSFETCHCTL, val);
+	}
+
+	if (ibs_config.op_enabled) {
+		ibs_op_ctl = ibs_config.max_cnt_op >> 4;
+		if (!(ibs_caps & IBS_CAPS_RDWROPCNT)) {
+			/*
+			 * IbsOpCurCnt not supported.  See
+			 * op_amd_randomize_ibs_op() for details.
+			 */
+			ibs_op_ctl = clamp((unsigned long long)ibs_op_ctl, 
+							0x0081ULL, 0xFF80ULL);
+		} else {
+			/*
+			 * The start value is randomized with a
+			 * positive offset, we need to compensate it
+			 * with the half of the randomized range. Also
+			 * avoid underflows.
+			 */
+		ibs_op_ctl = min(ibs_op_ctl + IBS_RANDOM_MAXCNT_OFFSET,
+					IBS_OP_MAX_CNT);
+		}
+		if (ibs_caps & IBS_CAPS_OPCNT && ibs_config.dispatched_ops)
+			ibs_op_ctl |= IBS_OP_CNT_CTL;
+		ibs_op_ctl |= IBS_OP_ENABLE;
+		val = op_amd_randomize_ibs_op(ibs_op_ctl);
+		wrmsrl(MSR_AMD64_IBSOPCTL, val);
+	}
+}
  
 static void athlon_start(struct op_msrs const * const msrs)
 {
@@ -150,8 +374,22 @@ static void athlon_start(struct op_msrs 
 			CTRL_WRITE(msr_content, msrs, i);
 		}
 	}
-}
-
+	start_ibs();
+}
+
+static void stop_ibs(void)
+{
+	if (!ibs_caps)
+		return;
+
+	if (ibs_config.fetch_enabled)
+		/* clear max count and enable */
+		wrmsrl(MSR_AMD64_IBSFETCHCTL, 0);
+
+	if (ibs_config.op_enabled)
+		/* clear max count and enable */
+		wrmsrl(MSR_AMD64_IBSOPCTL, 0);
+}
 
 static void athlon_stop(struct op_msrs const * const msrs)
 {
@@ -165,8 +403,114 @@ static void athlon_stop(struct op_msrs c
 		CTRL_SET_INACTIVE(msr_content);
 		CTRL_WRITE(msr_content, msrs, i);
 	}
-}
-
+
+	stop_ibs();
+}
+
+#define IBSCTL_LVTOFFSETVAL             (1 << 8)
+#define APIC_EILVT_MSG_NMI              0x4
+#define APIC_EILVT_LVTOFF_IBS           1
+#define APIC_EILVTn(n)                  (0x500 + 0x10 * n)
+static inline void init_ibs_nmi_per_cpu(void *arg)
+{
+	unsigned long reg;
+
+	reg = (APIC_EILVT_LVTOFF_IBS << 4) + APIC_EILVTn(0);
+	apic_write(reg, APIC_EILVT_MSG_NMI << 8);
+}
+
+#define PCI_VENDOR_ID_AMD               0x1022
+#define PCI_DEVICE_ID_AMD_10H_NB_MISC   0x1203
+#define IBSCTL                          0x1cc
+static int init_ibs_nmi(void)
+{
+	int bus, dev, func;
+	u32 id, value;
+	u16 vendor_id, dev_id;
+	int nodes;
+
+	/* per CPU setup */
+	on_each_cpu(init_ibs_nmi_per_cpu, NULL, 1);
+
+	nodes = 0;
+	for (bus = 0; bus < 256; bus++) {
+		for (dev = 0; dev < 32; dev++) {
+			for (func = 0; func < 8; func++) {
+				id = pci_conf_read32(bus, dev, func, PCI_VENDOR_ID);
+
+				if ((id == 0xffffffff) || (id == 0x00000000) ||
+					(id == 0x0000ffff) || (id == 0xffff0000))
+					continue;
+
+				vendor_id = id & 0xffff;
+				dev_id = (id >> 16) & 0xffff;
+
+				if ((vendor_id == PCI_VENDOR_ID_AMD) &&
+					(dev_id == PCI_DEVICE_ID_AMD_10H_NB_MISC)) {
+
+					pci_conf_write32(bus, dev, func, IBSCTL,
+						IBSCTL_LVTOFFSETVAL | APIC_EILVT_LVTOFF_IBS);
+
+					value = pci_conf_read32(bus, dev, func, IBSCTL);
+
+					if (value != (IBSCTL_LVTOFFSETVAL |
+						APIC_EILVT_LVTOFF_IBS)) {
+						printk("Xenoprofile: Failed to setup IBS LVT offset, "
+							"IBSCTL = 0x%08x", value);
+						return 1;
+					}
+					nodes++;
+				}
+			}
+		}
+	}
+
+	if (!nodes) {
+		printk("Xenoprofile: No CPU node configured for IBS");
+		return 1;
+	}
+
+	return 0;
+}
+
+static u32 get_ibs_caps(void)
+{
+	unsigned int max_level;
+
+	if (!boot_cpu_has(X86_FEATURE_IBS))
+		return 0;
+
+    /* check IBS cpuid feature flags */
+	max_level = cpuid_eax(0x80000000);
+	if (max_level < IBS_CPUID_FEATURES)
+		return IBS_CAPS_AVAIL;
+
+	ibs_caps = cpuid_eax(IBS_CPUID_FEATURES);
+	if (!(ibs_caps & IBS_CAPS_AVAIL))
+		/* cpuid flags not valid */
+		return IBS_CAPS_AVAIL;
+
+	return ibs_caps;
+}
+
+u32 ibs_init(void)
+{
+	u32 ibs_caps = 0;
+
+	ibs_caps = get_ibs_caps();
+
+	if ( !ibs_caps )
+		return 0;
+
+	if (init_ibs_nmi()) {
+		ibs_caps = 0;
+		return 0;
+	}
+
+	printk("Xenoprofile: AMD IBS detected (0x%08x)\n",
+		(unsigned)ibs_caps);
+	return ibs_caps;
+}
 
 struct op_x86_model_spec const op_athlon_spec = {
 	.num_counters = NUM_COUNTERS,
diff -r 4514d5890692 xen/arch/x86/oprofile/xenoprof.c
--- a/xen/arch/x86/oprofile/xenoprof.c	Fri Jul 16 17:44:04 2010 +0100
+++ b/xen/arch/x86/oprofile/xenoprof.c	Fri Jul 30 12:28:48 2010 +0200
@@ -34,6 +34,23 @@ int xenoprof_arch_counter(XEN_GUEST_HAND
     counter_config[counter.ind].kernel    = counter.kernel;
     counter_config[counter.ind].user      = counter.user;
     counter_config[counter.ind].unit_mask = counter.unit_mask;
+
+    return 0;
+}
+
+int xenoprof_arch_ibs_counter(XEN_GUEST_HANDLE(void) arg)
+{
+    struct xenoprof_ibs_counter ibs_counter;
+
+    if ( copy_from_guest(&ibs_counter, arg, 1) )
+        return -EFAULT;
+
+    ibs_config.op_enabled = ibs_counter.op_enabled;
+    ibs_config.fetch_enabled = ibs_counter.fetch_enabled;
+    ibs_config.max_cnt_fetch = ibs_counter.max_cnt_fetch;
+    ibs_config.max_cnt_op = ibs_counter.max_cnt_op;
+    ibs_config.rand_en = ibs_counter.rand_en;
+    ibs_config.dispatched_ops = ibs_counter.dispatched_ops;
 
     return 0;
 }
diff -r 4514d5890692 xen/common/xenoprof.c
--- a/xen/common/xenoprof.c	Fri Jul 16 17:44:04 2010 +0100
+++ b/xen/common/xenoprof.c	Fri Jul 30 12:28:48 2010 +0200
@@ -48,6 +48,9 @@ static u64 passive_samples;
 static u64 passive_samples;
 static u64 idle_samples;
 static u64 others_samples;
+
+/* AMD IBS support */
+extern u32 ibs_caps;
 
 int acquire_pmu_ownership(int pmu_ownship)
 {
@@ -881,6 +884,20 @@ int do_xenoprof_op(int op, XEN_GUEST_HAN
             ret = -EFAULT;
         break;
 
+    case XENOPROF_ibs_counter:
+        if ( (xenoprof_state != XENOPROF_COUNTERS_RESERVED) ||
+             (adomains == 0) )
+        {
+            ret = -EPERM;
+            break;
+        }
+        ret = xenoprof_arch_ibs_counter(arg);
+        break;
+
+    case XENOPROF_get_ibs_caps:
+        ret = ibs_caps;
+        break;
+
     default:
         ret = -ENOSYS;
     }
diff -r 4514d5890692 xen/include/asm-x86/xenoprof.h
--- a/xen/include/asm-x86/xenoprof.h	Fri Jul 16 17:44:04 2010 +0100
+++ b/xen/include/asm-x86/xenoprof.h	Fri Jul 30 12:28:48 2010 +0200
@@ -42,9 +42,14 @@ int xenoprof_arch_init(int *num_events, 
 
 int xenoprof_arch_counter(XEN_GUEST_HANDLE(void) arg);
 int compat_oprof_arch_counter(XEN_GUEST_HANDLE(void) arg);
+int xenoprof_arch_ibs_counter(XEN_GUEST_HANDLE(void) arg);
 
 struct vcpu;
 struct cpu_user_regs;
+
+/* AMD IBS support */
+u32 ibs_init(void);
+extern u32 ibs_caps;
 
 int xenoprofile_get_mode(struct vcpu *v, struct cpu_user_regs * const regs);
 
diff -r 4514d5890692 xen/include/public/xenoprof.h
--- a/xen/include/public/xenoprof.h	Fri Jul 16 17:44:04 2010 +0100
+++ b/xen/include/public/xenoprof.h	Fri Jul 30 12:28:48 2010 +0200
@@ -50,7 +50,11 @@
 #define XENOPROF_shutdown           13
 #define XENOPROF_get_buffer         14
 #define XENOPROF_set_backtrace      15
-#define XENOPROF_last_op            15
+
+/* AMD IBS support */
+#define XENOPROF_get_ibs_caps       16
+#define XENOPROF_ibs_counter        17
+#define XENOPROF_last_op            17
 
 #define MAX_OPROF_EVENTS    32
 #define MAX_OPROF_DOMAINS   25
@@ -124,6 +128,16 @@ typedef struct xenoprof_passive {
 } xenoprof_passive_t;
 DEFINE_XEN_GUEST_HANDLE(xenoprof_passive_t);
 
+struct xenoprof_ibs_counter {
+    uint64_t op_enabled;
+    uint64_t fetch_enabled;
+    uint64_t max_cnt_fetch;
+    uint64_t max_cnt_op;
+    uint64_t rand_en;
+    uint64_t dispatched_ops;
+};
+typedef struct xenoprof_ibs_counter xenoprof_ibs_counter_t;
+DEFINE_XEN_GUEST_HANDLE(xenoprof_ibs_counter_t);
 
 #endif /* __XEN_PUBLIC_XENOPROF_H__ */
 

[-- Attachment #3: Type: text/plain, Size: 138 bytes --]

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xensource.com
http://lists.xensource.com/xen-devel

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2010-07-30 13:28 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-07-30 13:28 [PATCH 1/2] xenoprofile: Add IBS support Wei Wang2

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).