oprofile, x86: Add support for IBS periodic op counter extension
authorRobert Richter <robert.richter@amd.com>
Wed, 22 Sep 2010 15:45:39 +0000 (17:45 +0200)
committerRobert Richter <robert.richter@amd.com>
Fri, 15 Oct 2010 10:50:43 +0000 (12:50 +0200)
The count value for IBS op sampling has been extended by 7 bits. The
feature is reflected in bit 6 (OpCntExt) of the IBS capability
register (CPUID Fn8000_001B_EAX).

Signed-off-by: Robert Richter <robert.richter@amd.com>
arch/x86/include/asm/perf_event.h
arch/x86/oprofile/op_model_amd.c

index 6e742cc4251b49b2474830107da0378951c874be..550e26b1dbb3593f324910f0197402966ae91299 100644 (file)
@@ -111,17 +111,18 @@ union cpuid10_edx {
 #define X86_PMC_IDX_FIXED_BTS                          (X86_PMC_IDX_FIXED + 16)
 
 /* 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
+#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
+#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
+#define IBS_OP_MAX_CNT_EXT     0x007FFFFFULL   /* not a register bit mask */
 
 #ifdef CONFIG_PERF_EVENTS
 extern void init_hw_perf_events(void);
index 9de33fa9531ad529ad4806e7786f20de6d07db44..65f0a1eb6b86ed956880a05102b50a7f8e948ee3 100644 (file)
@@ -83,6 +83,7 @@ static struct ibs_state ibs_state;
 #define IBS_CAPS_RDWROPCNT             (1U<<3)
 #define IBS_CAPS_OPCNT                 (1U<<4)
 #define IBS_CAPS_BRNTRGT               (1U<<5)
+#define IBS_CAPS_OPCNTEXT              (1U<<6)
 
 #define IBS_CAPS_DEFAULT               (IBS_CAPS_AVAIL         \
                                         | IBS_CAPS_FETCHSAM    \
@@ -246,8 +247,16 @@ static inline void op_amd_start_ibs(void)
 
        memset(&ibs_state, 0, sizeof(ibs_state));
 
+       /*
+        * Note: Since the max count settings may out of range we
+        * write back the actual used values so that userland can read
+        * it.
+        */
+
        if (ibs_config.fetch_enabled) {
-               val = (ibs_config.max_cnt_fetch >> 4) & IBS_FETCH_MAX_CNT;
+               val = ibs_config.max_cnt_fetch >> 4;
+               val = min(val, IBS_FETCH_MAX_CNT);
+               ibs_config.max_cnt_fetch = val << 4;
                val |= ibs_config.rand_en ? IBS_FETCH_RAND_EN : 0;
                val |= IBS_FETCH_ENABLE;
                wrmsrl(MSR_AMD64_IBSFETCHCTL, val);
@@ -261,6 +270,7 @@ static inline void op_amd_start_ibs(void)
                         * op_amd_randomize_ibs_op() for details.
                         */
                        val = clamp(val, 0x0081ULL, 0xFF80ULL);
+                       ibs_config.max_cnt_op = val << 4;
                } else {
                        /*
                         * The start value is randomized with a
@@ -268,9 +278,15 @@ static inline void op_amd_start_ibs(void)
                         * with the half of the randomized range. Also
                         * avoid underflows.
                         */
-                       val = min(val + IBS_RANDOM_MAXCNT_OFFSET,
-                                 IBS_OP_MAX_CNT);
+                       val += IBS_RANDOM_MAXCNT_OFFSET;
+                       if (ibs_caps & IBS_CAPS_OPCNTEXT)
+                               val = min(val, IBS_OP_MAX_CNT_EXT);
+                       else
+                               val = min(val, IBS_OP_MAX_CNT);
+                       ibs_config.max_cnt_op =
+                               (val - IBS_RANDOM_MAXCNT_OFFSET) << 4;
                }
+               val = ((val & ~IBS_OP_MAX_CNT) << 4) | (val & IBS_OP_MAX_CNT);
                val |= ibs_config.dispatched_ops ? IBS_OP_CNT_CTL : 0;
                val |= IBS_OP_ENABLE;
                ibs_state.ibs_op_ctl = val;