linux/arch/x86/events/intel/uncore_nhmex.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/* Nehalem-EX/Westmere-EX uncore support */
   3#include "uncore.h"
   4
   5/* NHM-EX event control */
   6#define NHMEX_PMON_CTL_EV_SEL_MASK      0x000000ff
   7#define NHMEX_PMON_CTL_UMASK_MASK       0x0000ff00
   8#define NHMEX_PMON_CTL_EN_BIT0          (1 << 0)
   9#define NHMEX_PMON_CTL_EDGE_DET         (1 << 18)
  10#define NHMEX_PMON_CTL_PMI_EN           (1 << 20)
  11#define NHMEX_PMON_CTL_EN_BIT22         (1 << 22)
  12#define NHMEX_PMON_CTL_INVERT           (1 << 23)
  13#define NHMEX_PMON_CTL_TRESH_MASK       0xff000000
  14#define NHMEX_PMON_RAW_EVENT_MASK       (NHMEX_PMON_CTL_EV_SEL_MASK | \
  15                                         NHMEX_PMON_CTL_UMASK_MASK | \
  16                                         NHMEX_PMON_CTL_EDGE_DET | \
  17                                         NHMEX_PMON_CTL_INVERT | \
  18                                         NHMEX_PMON_CTL_TRESH_MASK)
  19
  20/* NHM-EX Ubox */
  21#define NHMEX_U_MSR_PMON_GLOBAL_CTL             0xc00
  22#define NHMEX_U_MSR_PMON_CTR                    0xc11
  23#define NHMEX_U_MSR_PMON_EV_SEL                 0xc10
  24
  25#define NHMEX_U_PMON_GLOBAL_EN                  (1 << 0)
  26#define NHMEX_U_PMON_GLOBAL_PMI_CORE_SEL        0x0000001e
  27#define NHMEX_U_PMON_GLOBAL_EN_ALL              (1 << 28)
  28#define NHMEX_U_PMON_GLOBAL_RST_ALL             (1 << 29)
  29#define NHMEX_U_PMON_GLOBAL_FRZ_ALL             (1 << 31)
  30
  31#define NHMEX_U_PMON_RAW_EVENT_MASK             \
  32                (NHMEX_PMON_CTL_EV_SEL_MASK |   \
  33                 NHMEX_PMON_CTL_EDGE_DET)
  34
  35/* NHM-EX Cbox */
  36#define NHMEX_C0_MSR_PMON_GLOBAL_CTL            0xd00
  37#define NHMEX_C0_MSR_PMON_CTR0                  0xd11
  38#define NHMEX_C0_MSR_PMON_EV_SEL0               0xd10
  39#define NHMEX_C_MSR_OFFSET                      0x20
  40
  41/* NHM-EX Bbox */
  42#define NHMEX_B0_MSR_PMON_GLOBAL_CTL            0xc20
  43#define NHMEX_B0_MSR_PMON_CTR0                  0xc31
  44#define NHMEX_B0_MSR_PMON_CTL0                  0xc30
  45#define NHMEX_B_MSR_OFFSET                      0x40
  46#define NHMEX_B0_MSR_MATCH                      0xe45
  47#define NHMEX_B0_MSR_MASK                       0xe46
  48#define NHMEX_B1_MSR_MATCH                      0xe4d
  49#define NHMEX_B1_MSR_MASK                       0xe4e
  50
  51#define NHMEX_B_PMON_CTL_EN                     (1 << 0)
  52#define NHMEX_B_PMON_CTL_EV_SEL_SHIFT           1
  53#define NHMEX_B_PMON_CTL_EV_SEL_MASK            \
  54                (0x1f << NHMEX_B_PMON_CTL_EV_SEL_SHIFT)
  55#define NHMEX_B_PMON_CTR_SHIFT          6
  56#define NHMEX_B_PMON_CTR_MASK           \
  57                (0x3 << NHMEX_B_PMON_CTR_SHIFT)
  58#define NHMEX_B_PMON_RAW_EVENT_MASK             \
  59                (NHMEX_B_PMON_CTL_EV_SEL_MASK | \
  60                 NHMEX_B_PMON_CTR_MASK)
  61
  62/* NHM-EX Sbox */
  63#define NHMEX_S0_MSR_PMON_GLOBAL_CTL            0xc40
  64#define NHMEX_S0_MSR_PMON_CTR0                  0xc51
  65#define NHMEX_S0_MSR_PMON_CTL0                  0xc50
  66#define NHMEX_S_MSR_OFFSET                      0x80
  67#define NHMEX_S0_MSR_MM_CFG                     0xe48
  68#define NHMEX_S0_MSR_MATCH                      0xe49
  69#define NHMEX_S0_MSR_MASK                       0xe4a
  70#define NHMEX_S1_MSR_MM_CFG                     0xe58
  71#define NHMEX_S1_MSR_MATCH                      0xe59
  72#define NHMEX_S1_MSR_MASK                       0xe5a
  73
  74#define NHMEX_S_PMON_MM_CFG_EN                  (0x1ULL << 63)
  75#define NHMEX_S_EVENT_TO_R_PROG_EV              0
  76
  77/* NHM-EX Mbox */
  78#define NHMEX_M0_MSR_GLOBAL_CTL                 0xca0
  79#define NHMEX_M0_MSR_PMU_DSP                    0xca5
  80#define NHMEX_M0_MSR_PMU_ISS                    0xca6
  81#define NHMEX_M0_MSR_PMU_MAP                    0xca7
  82#define NHMEX_M0_MSR_PMU_MSC_THR                0xca8
  83#define NHMEX_M0_MSR_PMU_PGT                    0xca9
  84#define NHMEX_M0_MSR_PMU_PLD                    0xcaa
  85#define NHMEX_M0_MSR_PMU_ZDP_CTL_FVC            0xcab
  86#define NHMEX_M0_MSR_PMU_CTL0                   0xcb0
  87#define NHMEX_M0_MSR_PMU_CNT0                   0xcb1
  88#define NHMEX_M_MSR_OFFSET                      0x40
  89#define NHMEX_M0_MSR_PMU_MM_CFG                 0xe54
  90#define NHMEX_M1_MSR_PMU_MM_CFG                 0xe5c
  91
  92#define NHMEX_M_PMON_MM_CFG_EN                  (1ULL << 63)
  93#define NHMEX_M_PMON_ADDR_MATCH_MASK            0x3ffffffffULL
  94#define NHMEX_M_PMON_ADDR_MASK_MASK             0x7ffffffULL
  95#define NHMEX_M_PMON_ADDR_MASK_SHIFT            34
  96
  97#define NHMEX_M_PMON_CTL_EN                     (1 << 0)
  98#define NHMEX_M_PMON_CTL_PMI_EN                 (1 << 1)
  99#define NHMEX_M_PMON_CTL_COUNT_MODE_SHIFT       2
 100#define NHMEX_M_PMON_CTL_COUNT_MODE_MASK        \
 101        (0x3 << NHMEX_M_PMON_CTL_COUNT_MODE_SHIFT)
 102#define NHMEX_M_PMON_CTL_STORAGE_MODE_SHIFT     4
 103#define NHMEX_M_PMON_CTL_STORAGE_MODE_MASK      \
 104        (0x3 << NHMEX_M_PMON_CTL_STORAGE_MODE_SHIFT)
 105#define NHMEX_M_PMON_CTL_WRAP_MODE              (1 << 6)
 106#define NHMEX_M_PMON_CTL_FLAG_MODE              (1 << 7)
 107#define NHMEX_M_PMON_CTL_INC_SEL_SHIFT          9
 108#define NHMEX_M_PMON_CTL_INC_SEL_MASK           \
 109        (0x1f << NHMEX_M_PMON_CTL_INC_SEL_SHIFT)
 110#define NHMEX_M_PMON_CTL_SET_FLAG_SEL_SHIFT     19
 111#define NHMEX_M_PMON_CTL_SET_FLAG_SEL_MASK      \
 112        (0x7 << NHMEX_M_PMON_CTL_SET_FLAG_SEL_SHIFT)
 113#define NHMEX_M_PMON_RAW_EVENT_MASK                     \
 114                (NHMEX_M_PMON_CTL_COUNT_MODE_MASK |     \
 115                 NHMEX_M_PMON_CTL_STORAGE_MODE_MASK |   \
 116                 NHMEX_M_PMON_CTL_WRAP_MODE |           \
 117                 NHMEX_M_PMON_CTL_FLAG_MODE |           \
 118                 NHMEX_M_PMON_CTL_INC_SEL_MASK |        \
 119                 NHMEX_M_PMON_CTL_SET_FLAG_SEL_MASK)
 120
 121#define NHMEX_M_PMON_ZDP_CTL_FVC_MASK           (((1 << 11) - 1) | (1 << 23))
 122#define NHMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(n)  (0x7ULL << (11 + 3 * (n)))
 123
 124#define WSMEX_M_PMON_ZDP_CTL_FVC_MASK           (((1 << 12) - 1) | (1 << 24))
 125#define WSMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(n)  (0x7ULL << (12 + 3 * (n)))
 126
 127/*
 128 * use the 9~13 bits to select event If the 7th bit is not set,
 129 * otherwise use the 19~21 bits to select event.
 130 */
 131#define MBOX_INC_SEL(x) ((x) << NHMEX_M_PMON_CTL_INC_SEL_SHIFT)
 132#define MBOX_SET_FLAG_SEL(x) (((x) << NHMEX_M_PMON_CTL_SET_FLAG_SEL_SHIFT) | \
 133                                NHMEX_M_PMON_CTL_FLAG_MODE)
 134#define MBOX_INC_SEL_MASK (NHMEX_M_PMON_CTL_INC_SEL_MASK | \
 135                           NHMEX_M_PMON_CTL_FLAG_MODE)
 136#define MBOX_SET_FLAG_SEL_MASK (NHMEX_M_PMON_CTL_SET_FLAG_SEL_MASK | \
 137                                NHMEX_M_PMON_CTL_FLAG_MODE)
 138#define MBOX_INC_SEL_EXTAR_REG(c, r) \
 139                EVENT_EXTRA_REG(MBOX_INC_SEL(c), NHMEX_M0_MSR_PMU_##r, \
 140                                MBOX_INC_SEL_MASK, (u64)-1, NHMEX_M_##r)
 141#define MBOX_SET_FLAG_SEL_EXTRA_REG(c, r) \
 142                EVENT_EXTRA_REG(MBOX_SET_FLAG_SEL(c), NHMEX_M0_MSR_PMU_##r, \
 143                                MBOX_SET_FLAG_SEL_MASK, \
 144                                (u64)-1, NHMEX_M_##r)
 145
 146/* NHM-EX Rbox */
 147#define NHMEX_R_MSR_GLOBAL_CTL                  0xe00
 148#define NHMEX_R_MSR_PMON_CTL0                   0xe10
 149#define NHMEX_R_MSR_PMON_CNT0                   0xe11
 150#define NHMEX_R_MSR_OFFSET                      0x20
 151
 152#define NHMEX_R_MSR_PORTN_QLX_CFG(n)            \
 153                ((n) < 4 ? (0xe0c + (n)) : (0xe2c + (n) - 4))
 154#define NHMEX_R_MSR_PORTN_IPERF_CFG0(n)         (0xe04 + (n))
 155#define NHMEX_R_MSR_PORTN_IPERF_CFG1(n)         (0xe24 + (n))
 156#define NHMEX_R_MSR_PORTN_XBR_OFFSET(n)         \
 157                (((n) < 4 ? 0 : 0x10) + (n) * 4)
 158#define NHMEX_R_MSR_PORTN_XBR_SET1_MM_CFG(n)    \
 159                (0xe60 + NHMEX_R_MSR_PORTN_XBR_OFFSET(n))
 160#define NHMEX_R_MSR_PORTN_XBR_SET1_MATCH(n)     \
 161                (NHMEX_R_MSR_PORTN_XBR_SET1_MM_CFG(n) + 1)
 162#define NHMEX_R_MSR_PORTN_XBR_SET1_MASK(n)      \
 163                (NHMEX_R_MSR_PORTN_XBR_SET1_MM_CFG(n) + 2)
 164#define NHMEX_R_MSR_PORTN_XBR_SET2_MM_CFG(n)    \
 165                (0xe70 + NHMEX_R_MSR_PORTN_XBR_OFFSET(n))
 166#define NHMEX_R_MSR_PORTN_XBR_SET2_MATCH(n)     \
 167                (NHMEX_R_MSR_PORTN_XBR_SET2_MM_CFG(n) + 1)
 168#define NHMEX_R_MSR_PORTN_XBR_SET2_MASK(n)      \
 169                (NHMEX_R_MSR_PORTN_XBR_SET2_MM_CFG(n) + 2)
 170
 171#define NHMEX_R_PMON_CTL_EN                     (1 << 0)
 172#define NHMEX_R_PMON_CTL_EV_SEL_SHIFT           1
 173#define NHMEX_R_PMON_CTL_EV_SEL_MASK            \
 174                (0x1f << NHMEX_R_PMON_CTL_EV_SEL_SHIFT)
 175#define NHMEX_R_PMON_CTL_PMI_EN                 (1 << 6)
 176#define NHMEX_R_PMON_RAW_EVENT_MASK             NHMEX_R_PMON_CTL_EV_SEL_MASK
 177
 178/* NHM-EX Wbox */
 179#define NHMEX_W_MSR_GLOBAL_CTL                  0xc80
 180#define NHMEX_W_MSR_PMON_CNT0                   0xc90
 181#define NHMEX_W_MSR_PMON_EVT_SEL0               0xc91
 182#define NHMEX_W_MSR_PMON_FIXED_CTR              0x394
 183#define NHMEX_W_MSR_PMON_FIXED_CTL              0x395
 184
 185#define NHMEX_W_PMON_GLOBAL_FIXED_EN            (1ULL << 31)
 186
 187#define __BITS_VALUE(x, i, n)  ((typeof(x))(((x) >> ((i) * (n))) & \
 188                                ((1ULL << (n)) - 1)))
 189
 190DEFINE_UNCORE_FORMAT_ATTR(event, event, "config:0-7");
 191DEFINE_UNCORE_FORMAT_ATTR(event5, event, "config:1-5");
 192DEFINE_UNCORE_FORMAT_ATTR(umask, umask, "config:8-15");
 193DEFINE_UNCORE_FORMAT_ATTR(edge, edge, "config:18");
 194DEFINE_UNCORE_FORMAT_ATTR(inv, inv, "config:23");
 195DEFINE_UNCORE_FORMAT_ATTR(thresh8, thresh, "config:24-31");
 196DEFINE_UNCORE_FORMAT_ATTR(counter, counter, "config:6-7");
 197DEFINE_UNCORE_FORMAT_ATTR(match, match, "config1:0-63");
 198DEFINE_UNCORE_FORMAT_ATTR(mask, mask, "config2:0-63");
 199
 200static void nhmex_uncore_msr_init_box(struct intel_uncore_box *box)
 201{
 202        wrmsrl(NHMEX_U_MSR_PMON_GLOBAL_CTL, NHMEX_U_PMON_GLOBAL_EN_ALL);
 203}
 204
 205static void nhmex_uncore_msr_exit_box(struct intel_uncore_box *box)
 206{
 207        wrmsrl(NHMEX_U_MSR_PMON_GLOBAL_CTL, 0);
 208}
 209
 210static void nhmex_uncore_msr_disable_box(struct intel_uncore_box *box)
 211{
 212        unsigned msr = uncore_msr_box_ctl(box);
 213        u64 config;
 214
 215        if (msr) {
 216                rdmsrl(msr, config);
 217                config &= ~((1ULL << uncore_num_counters(box)) - 1);
 218                /* WBox has a fixed counter */
 219                if (uncore_msr_fixed_ctl(box))
 220                        config &= ~NHMEX_W_PMON_GLOBAL_FIXED_EN;
 221                wrmsrl(msr, config);
 222        }
 223}
 224
 225static void nhmex_uncore_msr_enable_box(struct intel_uncore_box *box)
 226{
 227        unsigned msr = uncore_msr_box_ctl(box);
 228        u64 config;
 229
 230        if (msr) {
 231                rdmsrl(msr, config);
 232                config |= (1ULL << uncore_num_counters(box)) - 1;
 233                /* WBox has a fixed counter */
 234                if (uncore_msr_fixed_ctl(box))
 235                        config |= NHMEX_W_PMON_GLOBAL_FIXED_EN;
 236                wrmsrl(msr, config);
 237        }
 238}
 239
 240static void nhmex_uncore_msr_disable_event(struct intel_uncore_box *box, struct perf_event *event)
 241{
 242        wrmsrl(event->hw.config_base, 0);
 243}
 244
 245static void nhmex_uncore_msr_enable_event(struct intel_uncore_box *box, struct perf_event *event)
 246{
 247        struct hw_perf_event *hwc = &event->hw;
 248
 249        if (hwc->idx == UNCORE_PMC_IDX_FIXED)
 250                wrmsrl(hwc->config_base, NHMEX_PMON_CTL_EN_BIT0);
 251        else if (box->pmu->type->event_mask & NHMEX_PMON_CTL_EN_BIT0)
 252                wrmsrl(hwc->config_base, hwc->config | NHMEX_PMON_CTL_EN_BIT22);
 253        else
 254                wrmsrl(hwc->config_base, hwc->config | NHMEX_PMON_CTL_EN_BIT0);
 255}
 256
 257#define NHMEX_UNCORE_OPS_COMMON_INIT()                          \
 258        .init_box       = nhmex_uncore_msr_init_box,            \
 259        .exit_box       = nhmex_uncore_msr_exit_box,            \
 260        .disable_box    = nhmex_uncore_msr_disable_box,         \
 261        .enable_box     = nhmex_uncore_msr_enable_box,          \
 262        .disable_event  = nhmex_uncore_msr_disable_event,       \
 263        .read_counter   = uncore_msr_read_counter
 264
 265static struct intel_uncore_ops nhmex_uncore_ops = {
 266        NHMEX_UNCORE_OPS_COMMON_INIT(),
 267        .enable_event   = nhmex_uncore_msr_enable_event,
 268};
 269
 270static struct attribute *nhmex_uncore_ubox_formats_attr[] = {
 271        &format_attr_event.attr,
 272        &format_attr_edge.attr,
 273        NULL,
 274};
 275
 276static const struct attribute_group nhmex_uncore_ubox_format_group = {
 277        .name           = "format",
 278        .attrs          = nhmex_uncore_ubox_formats_attr,
 279};
 280
 281static struct intel_uncore_type nhmex_uncore_ubox = {
 282        .name           = "ubox",
 283        .num_counters   = 1,
 284        .num_boxes      = 1,
 285        .perf_ctr_bits  = 48,
 286        .event_ctl      = NHMEX_U_MSR_PMON_EV_SEL,
 287        .perf_ctr       = NHMEX_U_MSR_PMON_CTR,
 288        .event_mask     = NHMEX_U_PMON_RAW_EVENT_MASK,
 289        .box_ctl        = NHMEX_U_MSR_PMON_GLOBAL_CTL,
 290        .ops            = &nhmex_uncore_ops,
 291        .format_group   = &nhmex_uncore_ubox_format_group
 292};
 293
 294static struct attribute *nhmex_uncore_cbox_formats_attr[] = {
 295        &format_attr_event.attr,
 296        &format_attr_umask.attr,
 297        &format_attr_edge.attr,
 298        &format_attr_inv.attr,
 299        &format_attr_thresh8.attr,
 300        NULL,
 301};
 302
 303static const struct attribute_group nhmex_uncore_cbox_format_group = {
 304        .name = "format",
 305        .attrs = nhmex_uncore_cbox_formats_attr,
 306};
 307
 308/* msr offset for each instance of cbox */
 309static unsigned nhmex_cbox_msr_offsets[] = {
 310        0x0, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 0x240, 0x2c0,
 311};
 312
 313static struct intel_uncore_type nhmex_uncore_cbox = {
 314        .name                   = "cbox",
 315        .num_counters           = 6,
 316        .num_boxes              = 10,
 317        .perf_ctr_bits          = 48,
 318        .event_ctl              = NHMEX_C0_MSR_PMON_EV_SEL0,
 319        .perf_ctr               = NHMEX_C0_MSR_PMON_CTR0,
 320        .event_mask             = NHMEX_PMON_RAW_EVENT_MASK,
 321        .box_ctl                = NHMEX_C0_MSR_PMON_GLOBAL_CTL,
 322        .msr_offsets            = nhmex_cbox_msr_offsets,
 323        .pair_ctr_ctl           = 1,
 324        .ops                    = &nhmex_uncore_ops,
 325        .format_group           = &nhmex_uncore_cbox_format_group
 326};
 327
 328static struct uncore_event_desc nhmex_uncore_wbox_events[] = {
 329        INTEL_UNCORE_EVENT_DESC(clockticks, "event=0xff,umask=0"),
 330        { /* end: all zeroes */ },
 331};
 332
 333static struct intel_uncore_type nhmex_uncore_wbox = {
 334        .name                   = "wbox",
 335        .num_counters           = 4,
 336        .num_boxes              = 1,
 337        .perf_ctr_bits          = 48,
 338        .event_ctl              = NHMEX_W_MSR_PMON_CNT0,
 339        .perf_ctr               = NHMEX_W_MSR_PMON_EVT_SEL0,
 340        .fixed_ctr              = NHMEX_W_MSR_PMON_FIXED_CTR,
 341        .fixed_ctl              = NHMEX_W_MSR_PMON_FIXED_CTL,
 342        .event_mask             = NHMEX_PMON_RAW_EVENT_MASK,
 343        .box_ctl                = NHMEX_W_MSR_GLOBAL_CTL,
 344        .pair_ctr_ctl           = 1,
 345        .event_descs            = nhmex_uncore_wbox_events,
 346        .ops                    = &nhmex_uncore_ops,
 347        .format_group           = &nhmex_uncore_cbox_format_group
 348};
 349
 350static int nhmex_bbox_hw_config(struct intel_uncore_box *box, struct perf_event *event)
 351{
 352        struct hw_perf_event *hwc = &event->hw;
 353        struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
 354        struct hw_perf_event_extra *reg2 = &hwc->branch_reg;
 355        int ctr, ev_sel;
 356
 357        ctr = (hwc->config & NHMEX_B_PMON_CTR_MASK) >>
 358                NHMEX_B_PMON_CTR_SHIFT;
 359        ev_sel = (hwc->config & NHMEX_B_PMON_CTL_EV_SEL_MASK) >>
 360                  NHMEX_B_PMON_CTL_EV_SEL_SHIFT;
 361
 362        /* events that do not use the match/mask registers */
 363        if ((ctr == 0 && ev_sel > 0x3) || (ctr == 1 && ev_sel > 0x6) ||
 364            (ctr == 2 && ev_sel != 0x4) || ctr == 3)
 365                return 0;
 366
 367        if (box->pmu->pmu_idx == 0)
 368                reg1->reg = NHMEX_B0_MSR_MATCH;
 369        else
 370                reg1->reg = NHMEX_B1_MSR_MATCH;
 371        reg1->idx = 0;
 372        reg1->config = event->attr.config1;
 373        reg2->config = event->attr.config2;
 374        return 0;
 375}
 376
 377static void nhmex_bbox_msr_enable_event(struct intel_uncore_box *box, struct perf_event *event)
 378{
 379        struct hw_perf_event *hwc = &event->hw;
 380        struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
 381        struct hw_perf_event_extra *reg2 = &hwc->branch_reg;
 382
 383        if (reg1->idx != EXTRA_REG_NONE) {
 384                wrmsrl(reg1->reg, reg1->config);
 385                wrmsrl(reg1->reg + 1, reg2->config);
 386        }
 387        wrmsrl(hwc->config_base, NHMEX_PMON_CTL_EN_BIT0 |
 388                (hwc->config & NHMEX_B_PMON_CTL_EV_SEL_MASK));
 389}
 390
 391/*
 392 * The Bbox has 4 counters, but each counter monitors different events.
 393 * Use bits 6-7 in the event config to select counter.
 394 */
 395static struct event_constraint nhmex_uncore_bbox_constraints[] = {
 396        EVENT_CONSTRAINT(0 , 1, 0xc0),
 397        EVENT_CONSTRAINT(0x40, 2, 0xc0),
 398        EVENT_CONSTRAINT(0x80, 4, 0xc0),
 399        EVENT_CONSTRAINT(0xc0, 8, 0xc0),
 400        EVENT_CONSTRAINT_END,
 401};
 402
 403static struct attribute *nhmex_uncore_bbox_formats_attr[] = {
 404        &format_attr_event5.attr,
 405        &format_attr_counter.attr,
 406        &format_attr_match.attr,
 407        &format_attr_mask.attr,
 408        NULL,
 409};
 410
 411static const struct attribute_group nhmex_uncore_bbox_format_group = {
 412        .name = "format",
 413        .attrs = nhmex_uncore_bbox_formats_attr,
 414};
 415
 416static struct intel_uncore_ops nhmex_uncore_bbox_ops = {
 417        NHMEX_UNCORE_OPS_COMMON_INIT(),
 418        .enable_event           = nhmex_bbox_msr_enable_event,
 419        .hw_config              = nhmex_bbox_hw_config,
 420        .get_constraint         = uncore_get_constraint,
 421        .put_constraint         = uncore_put_constraint,
 422};
 423
 424static struct intel_uncore_type nhmex_uncore_bbox = {
 425        .name                   = "bbox",
 426        .num_counters           = 4,
 427        .num_boxes              = 2,
 428        .perf_ctr_bits          = 48,
 429        .event_ctl              = NHMEX_B0_MSR_PMON_CTL0,
 430        .perf_ctr               = NHMEX_B0_MSR_PMON_CTR0,
 431        .event_mask             = NHMEX_B_PMON_RAW_EVENT_MASK,
 432        .box_ctl                = NHMEX_B0_MSR_PMON_GLOBAL_CTL,
 433        .msr_offset             = NHMEX_B_MSR_OFFSET,
 434        .pair_ctr_ctl           = 1,
 435        .num_shared_regs        = 1,
 436        .constraints            = nhmex_uncore_bbox_constraints,
 437        .ops                    = &nhmex_uncore_bbox_ops,
 438        .format_group           = &nhmex_uncore_bbox_format_group
 439};
 440
 441static int nhmex_sbox_hw_config(struct intel_uncore_box *box, struct perf_event *event)
 442{
 443        struct hw_perf_event *hwc = &event->hw;
 444        struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
 445        struct hw_perf_event_extra *reg2 = &hwc->branch_reg;
 446
 447        /* only TO_R_PROG_EV event uses the match/mask register */
 448        if ((hwc->config & NHMEX_PMON_CTL_EV_SEL_MASK) !=
 449            NHMEX_S_EVENT_TO_R_PROG_EV)
 450                return 0;
 451
 452        if (box->pmu->pmu_idx == 0)
 453                reg1->reg = NHMEX_S0_MSR_MM_CFG;
 454        else
 455                reg1->reg = NHMEX_S1_MSR_MM_CFG;
 456        reg1->idx = 0;
 457        reg1->config = event->attr.config1;
 458        reg2->config = event->attr.config2;
 459        return 0;
 460}
 461
 462static void nhmex_sbox_msr_enable_event(struct intel_uncore_box *box, struct perf_event *event)
 463{
 464        struct hw_perf_event *hwc = &event->hw;
 465        struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
 466        struct hw_perf_event_extra *reg2 = &hwc->branch_reg;
 467
 468        if (reg1->idx != EXTRA_REG_NONE) {
 469                wrmsrl(reg1->reg, 0);
 470                wrmsrl(reg1->reg + 1, reg1->config);
 471                wrmsrl(reg1->reg + 2, reg2->config);
 472                wrmsrl(reg1->reg, NHMEX_S_PMON_MM_CFG_EN);
 473        }
 474        wrmsrl(hwc->config_base, hwc->config | NHMEX_PMON_CTL_EN_BIT22);
 475}
 476
 477static struct attribute *nhmex_uncore_sbox_formats_attr[] = {
 478        &format_attr_event.attr,
 479        &format_attr_umask.attr,
 480        &format_attr_edge.attr,
 481        &format_attr_inv.attr,
 482        &format_attr_thresh8.attr,
 483        &format_attr_match.attr,
 484        &format_attr_mask.attr,
 485        NULL,
 486};
 487
 488static const struct attribute_group nhmex_uncore_sbox_format_group = {
 489        .name                   = "format",
 490        .attrs                  = nhmex_uncore_sbox_formats_attr,
 491};
 492
 493static struct intel_uncore_ops nhmex_uncore_sbox_ops = {
 494        NHMEX_UNCORE_OPS_COMMON_INIT(),
 495        .enable_event           = nhmex_sbox_msr_enable_event,
 496        .hw_config              = nhmex_sbox_hw_config,
 497        .get_constraint         = uncore_get_constraint,
 498        .put_constraint         = uncore_put_constraint,
 499};
 500
 501static struct intel_uncore_type nhmex_uncore_sbox = {
 502        .name                   = "sbox",
 503        .num_counters           = 4,
 504        .num_boxes              = 2,
 505        .perf_ctr_bits          = 48,
 506        .event_ctl              = NHMEX_S0_MSR_PMON_CTL0,
 507        .perf_ctr               = NHMEX_S0_MSR_PMON_CTR0,
 508        .event_mask             = NHMEX_PMON_RAW_EVENT_MASK,
 509        .box_ctl                = NHMEX_S0_MSR_PMON_GLOBAL_CTL,
 510        .msr_offset             = NHMEX_S_MSR_OFFSET,
 511        .pair_ctr_ctl           = 1,
 512        .num_shared_regs        = 1,
 513        .ops                    = &nhmex_uncore_sbox_ops,
 514        .format_group           = &nhmex_uncore_sbox_format_group
 515};
 516
 517enum {
 518        EXTRA_REG_NHMEX_M_FILTER,
 519        EXTRA_REG_NHMEX_M_DSP,
 520        EXTRA_REG_NHMEX_M_ISS,
 521        EXTRA_REG_NHMEX_M_MAP,
 522        EXTRA_REG_NHMEX_M_MSC_THR,
 523        EXTRA_REG_NHMEX_M_PGT,
 524        EXTRA_REG_NHMEX_M_PLD,
 525        EXTRA_REG_NHMEX_M_ZDP_CTL_FVC,
 526};
 527
 528static struct extra_reg nhmex_uncore_mbox_extra_regs[] = {
 529        MBOX_INC_SEL_EXTAR_REG(0x0, DSP),
 530        MBOX_INC_SEL_EXTAR_REG(0x4, MSC_THR),
 531        MBOX_INC_SEL_EXTAR_REG(0x5, MSC_THR),
 532        MBOX_INC_SEL_EXTAR_REG(0x9, ISS),
 533        /* event 0xa uses two extra registers */
 534        MBOX_INC_SEL_EXTAR_REG(0xa, ISS),
 535        MBOX_INC_SEL_EXTAR_REG(0xa, PLD),
 536        MBOX_INC_SEL_EXTAR_REG(0xb, PLD),
 537        /* events 0xd ~ 0x10 use the same extra register */
 538        MBOX_INC_SEL_EXTAR_REG(0xd, ZDP_CTL_FVC),
 539        MBOX_INC_SEL_EXTAR_REG(0xe, ZDP_CTL_FVC),
 540        MBOX_INC_SEL_EXTAR_REG(0xf, ZDP_CTL_FVC),
 541        MBOX_INC_SEL_EXTAR_REG(0x10, ZDP_CTL_FVC),
 542        MBOX_INC_SEL_EXTAR_REG(0x16, PGT),
 543        MBOX_SET_FLAG_SEL_EXTRA_REG(0x0, DSP),
 544        MBOX_SET_FLAG_SEL_EXTRA_REG(0x1, ISS),
 545        MBOX_SET_FLAG_SEL_EXTRA_REG(0x5, PGT),
 546        MBOX_SET_FLAG_SEL_EXTRA_REG(0x6, MAP),
 547        EVENT_EXTRA_END
 548};
 549
 550/* Nehalem-EX or Westmere-EX ? */
 551static bool uncore_nhmex;
 552
 553static bool nhmex_mbox_get_shared_reg(struct intel_uncore_box *box, int idx, u64 config)
 554{
 555        struct intel_uncore_extra_reg *er;
 556        unsigned long flags;
 557        bool ret = false;
 558        u64 mask;
 559
 560        if (idx < EXTRA_REG_NHMEX_M_ZDP_CTL_FVC) {
 561                er = &box->shared_regs[idx];
 562                raw_spin_lock_irqsave(&er->lock, flags);
 563                if (!atomic_read(&er->ref) || er->config == config) {
 564                        atomic_inc(&er->ref);
 565                        er->config = config;
 566                        ret = true;
 567                }
 568                raw_spin_unlock_irqrestore(&er->lock, flags);
 569
 570                return ret;
 571        }
 572        /*
 573         * The ZDP_CTL_FVC MSR has 4 fields which are used to control
 574         * events 0xd ~ 0x10. Besides these 4 fields, there are additional
 575         * fields which are shared.
 576         */
 577        idx -= EXTRA_REG_NHMEX_M_ZDP_CTL_FVC;
 578        if (WARN_ON_ONCE(idx >= 4))
 579                return false;
 580
 581        /* mask of the shared fields */
 582        if (uncore_nhmex)
 583                mask = NHMEX_M_PMON_ZDP_CTL_FVC_MASK;
 584        else
 585                mask = WSMEX_M_PMON_ZDP_CTL_FVC_MASK;
 586        er = &box->shared_regs[EXTRA_REG_NHMEX_M_ZDP_CTL_FVC];
 587
 588        raw_spin_lock_irqsave(&er->lock, flags);
 589        /* add mask of the non-shared field if it's in use */
 590        if (__BITS_VALUE(atomic_read(&er->ref), idx, 8)) {
 591                if (uncore_nhmex)
 592                        mask |= NHMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(idx);
 593                else
 594                        mask |= WSMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(idx);
 595        }
 596
 597        if (!atomic_read(&er->ref) || !((er->config ^ config) & mask)) {
 598                atomic_add(1 << (idx * 8), &er->ref);
 599                if (uncore_nhmex)
 600                        mask = NHMEX_M_PMON_ZDP_CTL_FVC_MASK |
 601                                NHMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(idx);
 602                else
 603                        mask = WSMEX_M_PMON_ZDP_CTL_FVC_MASK |
 604                                WSMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(idx);
 605                er->config &= ~mask;
 606                er->config |= (config & mask);
 607                ret = true;
 608        }
 609        raw_spin_unlock_irqrestore(&er->lock, flags);
 610
 611        return ret;
 612}
 613
 614static void nhmex_mbox_put_shared_reg(struct intel_uncore_box *box, int idx)
 615{
 616        struct intel_uncore_extra_reg *er;
 617
 618        if (idx < EXTRA_REG_NHMEX_M_ZDP_CTL_FVC) {
 619                er = &box->shared_regs[idx];
 620                atomic_dec(&er->ref);
 621                return;
 622        }
 623
 624        idx -= EXTRA_REG_NHMEX_M_ZDP_CTL_FVC;
 625        er = &box->shared_regs[EXTRA_REG_NHMEX_M_ZDP_CTL_FVC];
 626        atomic_sub(1 << (idx * 8), &er->ref);
 627}
 628
 629static u64 nhmex_mbox_alter_er(struct perf_event *event, int new_idx, bool modify)
 630{
 631        struct hw_perf_event *hwc = &event->hw;
 632        struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
 633        u64 idx, orig_idx = __BITS_VALUE(reg1->idx, 0, 8);
 634        u64 config = reg1->config;
 635
 636        /* get the non-shared control bits and shift them */
 637        idx = orig_idx - EXTRA_REG_NHMEX_M_ZDP_CTL_FVC;
 638        if (uncore_nhmex)
 639                config &= NHMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(idx);
 640        else
 641                config &= WSMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(idx);
 642        if (new_idx > orig_idx) {
 643                idx = new_idx - orig_idx;
 644                config <<= 3 * idx;
 645        } else {
 646                idx = orig_idx - new_idx;
 647                config >>= 3 * idx;
 648        }
 649
 650        /* add the shared control bits back */
 651        if (uncore_nhmex)
 652                config |= NHMEX_M_PMON_ZDP_CTL_FVC_MASK & reg1->config;
 653        else
 654                config |= WSMEX_M_PMON_ZDP_CTL_FVC_MASK & reg1->config;
 655        config |= NHMEX_M_PMON_ZDP_CTL_FVC_MASK & reg1->config;
 656        if (modify) {
 657                /* adjust the main event selector */
 658                if (new_idx > orig_idx)
 659                        hwc->config += idx << NHMEX_M_PMON_CTL_INC_SEL_SHIFT;
 660                else
 661                        hwc->config -= idx << NHMEX_M_PMON_CTL_INC_SEL_SHIFT;
 662                reg1->config = config;
 663                reg1->idx = ~0xff | new_idx;
 664        }
 665        return config;
 666}
 667
 668static struct event_constraint *
 669nhmex_mbox_get_constraint(struct intel_uncore_box *box, struct perf_event *event)
 670{
 671        struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
 672        struct hw_perf_event_extra *reg2 = &event->hw.branch_reg;
 673        int i, idx[2], alloc = 0;
 674        u64 config1 = reg1->config;
 675
 676        idx[0] = __BITS_VALUE(reg1->idx, 0, 8);
 677        idx[1] = __BITS_VALUE(reg1->idx, 1, 8);
 678again:
 679        for (i = 0; i < 2; i++) {
 680                if (!uncore_box_is_fake(box) && (reg1->alloc & (0x1 << i)))
 681                        idx[i] = 0xff;
 682
 683                if (idx[i] == 0xff)
 684                        continue;
 685
 686                if (!nhmex_mbox_get_shared_reg(box, idx[i],
 687                                __BITS_VALUE(config1, i, 32)))
 688                        goto fail;
 689                alloc |= (0x1 << i);
 690        }
 691
 692        /* for the match/mask registers */
 693        if (reg2->idx != EXTRA_REG_NONE &&
 694            (uncore_box_is_fake(box) || !reg2->alloc) &&
 695            !nhmex_mbox_get_shared_reg(box, reg2->idx, reg2->config))
 696                goto fail;
 697
 698        /*
 699         * If it's a fake box -- as per validate_{group,event}() we
 700         * shouldn't touch event state and we can avoid doing so
 701         * since both will only call get_event_constraints() once
 702         * on each event, this avoids the need for reg->alloc.
 703         */
 704        if (!uncore_box_is_fake(box)) {
 705                if (idx[0] != 0xff && idx[0] != __BITS_VALUE(reg1->idx, 0, 8))
 706                        nhmex_mbox_alter_er(event, idx[0], true);
 707                reg1->alloc |= alloc;
 708                if (reg2->idx != EXTRA_REG_NONE)
 709                        reg2->alloc = 1;
 710        }
 711        return NULL;
 712fail:
 713        if (idx[0] != 0xff && !(alloc & 0x1) &&
 714            idx[0] >= EXTRA_REG_NHMEX_M_ZDP_CTL_FVC) {
 715                /*
 716                 * events 0xd ~ 0x10 are functional identical, but are
 717                 * controlled by different fields in the ZDP_CTL_FVC
 718                 * register. If we failed to take one field, try the
 719                 * rest 3 choices.
 720                 */
 721                BUG_ON(__BITS_VALUE(reg1->idx, 1, 8) != 0xff);
 722                idx[0] -= EXTRA_REG_NHMEX_M_ZDP_CTL_FVC;
 723                idx[0] = (idx[0] + 1) % 4;
 724                idx[0] += EXTRA_REG_NHMEX_M_ZDP_CTL_FVC;
 725                if (idx[0] != __BITS_VALUE(reg1->idx, 0, 8)) {
 726                        config1 = nhmex_mbox_alter_er(event, idx[0], false);
 727                        goto again;
 728                }
 729        }
 730
 731        if (alloc & 0x1)
 732                nhmex_mbox_put_shared_reg(box, idx[0]);
 733        if (alloc & 0x2)
 734                nhmex_mbox_put_shared_reg(box, idx[1]);
 735        return &uncore_constraint_empty;
 736}
 737
 738static void nhmex_mbox_put_constraint(struct intel_uncore_box *box, struct perf_event *event)
 739{
 740        struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
 741        struct hw_perf_event_extra *reg2 = &event->hw.branch_reg;
 742
 743        if (uncore_box_is_fake(box))
 744                return;
 745
 746        if (reg1->alloc & 0x1)
 747                nhmex_mbox_put_shared_reg(box, __BITS_VALUE(reg1->idx, 0, 8));
 748        if (reg1->alloc & 0x2)
 749                nhmex_mbox_put_shared_reg(box, __BITS_VALUE(reg1->idx, 1, 8));
 750        reg1->alloc = 0;
 751
 752        if (reg2->alloc) {
 753                nhmex_mbox_put_shared_reg(box, reg2->idx);
 754                reg2->alloc = 0;
 755        }
 756}
 757
 758static int nhmex_mbox_extra_reg_idx(struct extra_reg *er)
 759{
 760        if (er->idx < EXTRA_REG_NHMEX_M_ZDP_CTL_FVC)
 761                return er->idx;
 762        return er->idx + (er->event >> NHMEX_M_PMON_CTL_INC_SEL_SHIFT) - 0xd;
 763}
 764
 765static int nhmex_mbox_hw_config(struct intel_uncore_box *box, struct perf_event *event)
 766{
 767        struct intel_uncore_type *type = box->pmu->type;
 768        struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
 769        struct hw_perf_event_extra *reg2 = &event->hw.branch_reg;
 770        struct extra_reg *er;
 771        unsigned msr;
 772        int reg_idx = 0;
 773        /*
 774         * The mbox events may require 2 extra MSRs at the most. But only
 775         * the lower 32 bits in these MSRs are significant, so we can use
 776         * config1 to pass two MSRs' config.
 777         */
 778        for (er = nhmex_uncore_mbox_extra_regs; er->msr; er++) {
 779                if (er->event != (event->hw.config & er->config_mask))
 780                        continue;
 781                if (event->attr.config1 & ~er->valid_mask)
 782                        return -EINVAL;
 783
 784                msr = er->msr + type->msr_offset * box->pmu->pmu_idx;
 785                if (WARN_ON_ONCE(msr >= 0xffff || er->idx >= 0xff))
 786                        return -EINVAL;
 787
 788                /* always use the 32~63 bits to pass the PLD config */
 789                if (er->idx == EXTRA_REG_NHMEX_M_PLD)
 790                        reg_idx = 1;
 791                else if (WARN_ON_ONCE(reg_idx > 0))
 792                        return -EINVAL;
 793
 794                reg1->idx &= ~(0xff << (reg_idx * 8));
 795                reg1->reg &= ~(0xffff << (reg_idx * 16));
 796                reg1->idx |= nhmex_mbox_extra_reg_idx(er) << (reg_idx * 8);
 797                reg1->reg |= msr << (reg_idx * 16);
 798                reg1->config = event->attr.config1;
 799                reg_idx++;
 800        }
 801        /*
 802         * The mbox only provides ability to perform address matching
 803         * for the PLD events.
 804         */
 805        if (reg_idx == 2) {
 806                reg2->idx = EXTRA_REG_NHMEX_M_FILTER;
 807                if (event->attr.config2 & NHMEX_M_PMON_MM_CFG_EN)
 808                        reg2->config = event->attr.config2;
 809                else
 810                        reg2->config = ~0ULL;
 811                if (box->pmu->pmu_idx == 0)
 812                        reg2->reg = NHMEX_M0_MSR_PMU_MM_CFG;
 813                else
 814                        reg2->reg = NHMEX_M1_MSR_PMU_MM_CFG;
 815        }
 816        return 0;
 817}
 818
 819static u64 nhmex_mbox_shared_reg_config(struct intel_uncore_box *box, int idx)
 820{
 821        struct intel_uncore_extra_reg *er;
 822        unsigned long flags;
 823        u64 config;
 824
 825        if (idx < EXTRA_REG_NHMEX_M_ZDP_CTL_FVC)
 826                return box->shared_regs[idx].config;
 827
 828        er = &box->shared_regs[EXTRA_REG_NHMEX_M_ZDP_CTL_FVC];
 829        raw_spin_lock_irqsave(&er->lock, flags);
 830        config = er->config;
 831        raw_spin_unlock_irqrestore(&er->lock, flags);
 832        return config;
 833}
 834
 835static void nhmex_mbox_msr_enable_event(struct intel_uncore_box *box, struct perf_event *event)
 836{
 837        struct hw_perf_event *hwc = &event->hw;
 838        struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
 839        struct hw_perf_event_extra *reg2 = &hwc->branch_reg;
 840        int idx;
 841
 842        idx = __BITS_VALUE(reg1->idx, 0, 8);
 843        if (idx != 0xff)
 844                wrmsrl(__BITS_VALUE(reg1->reg, 0, 16),
 845                        nhmex_mbox_shared_reg_config(box, idx));
 846        idx = __BITS_VALUE(reg1->idx, 1, 8);
 847        if (idx != 0xff)
 848                wrmsrl(__BITS_VALUE(reg1->reg, 1, 16),
 849                        nhmex_mbox_shared_reg_config(box, idx));
 850
 851        if (reg2->idx != EXTRA_REG_NONE) {
 852                wrmsrl(reg2->reg, 0);
 853                if (reg2->config != ~0ULL) {
 854                        wrmsrl(reg2->reg + 1,
 855                                reg2->config & NHMEX_M_PMON_ADDR_MATCH_MASK);
 856                        wrmsrl(reg2->reg + 2, NHMEX_M_PMON_ADDR_MASK_MASK &
 857                                (reg2->config >> NHMEX_M_PMON_ADDR_MASK_SHIFT));
 858                        wrmsrl(reg2->reg, NHMEX_M_PMON_MM_CFG_EN);
 859                }
 860        }
 861
 862        wrmsrl(hwc->config_base, hwc->config | NHMEX_PMON_CTL_EN_BIT0);
 863}
 864
 865DEFINE_UNCORE_FORMAT_ATTR(count_mode,           count_mode,     "config:2-3");
 866DEFINE_UNCORE_FORMAT_ATTR(storage_mode,         storage_mode,   "config:4-5");
 867DEFINE_UNCORE_FORMAT_ATTR(wrap_mode,            wrap_mode,      "config:6");
 868DEFINE_UNCORE_FORMAT_ATTR(flag_mode,            flag_mode,      "config:7");
 869DEFINE_UNCORE_FORMAT_ATTR(inc_sel,              inc_sel,        "config:9-13");
 870DEFINE_UNCORE_FORMAT_ATTR(set_flag_sel,         set_flag_sel,   "config:19-21");
 871DEFINE_UNCORE_FORMAT_ATTR(filter_cfg_en,        filter_cfg_en,  "config2:63");
 872DEFINE_UNCORE_FORMAT_ATTR(filter_match,         filter_match,   "config2:0-33");
 873DEFINE_UNCORE_FORMAT_ATTR(filter_mask,          filter_mask,    "config2:34-61");
 874DEFINE_UNCORE_FORMAT_ATTR(dsp,                  dsp,            "config1:0-31");
 875DEFINE_UNCORE_FORMAT_ATTR(thr,                  thr,            "config1:0-31");
 876DEFINE_UNCORE_FORMAT_ATTR(fvc,                  fvc,            "config1:0-31");
 877DEFINE_UNCORE_FORMAT_ATTR(pgt,                  pgt,            "config1:0-31");
 878DEFINE_UNCORE_FORMAT_ATTR(map,                  map,            "config1:0-31");
 879DEFINE_UNCORE_FORMAT_ATTR(iss,                  iss,            "config1:0-31");
 880DEFINE_UNCORE_FORMAT_ATTR(pld,                  pld,            "config1:32-63");
 881
 882static struct attribute *nhmex_uncore_mbox_formats_attr[] = {
 883        &format_attr_count_mode.attr,
 884        &format_attr_storage_mode.attr,
 885        &format_attr_wrap_mode.attr,
 886        &format_attr_flag_mode.attr,
 887        &format_attr_inc_sel.attr,
 888        &format_attr_set_flag_sel.attr,
 889        &format_attr_filter_cfg_en.attr,
 890        &format_attr_filter_match.attr,
 891        &format_attr_filter_mask.attr,
 892        &format_attr_dsp.attr,
 893        &format_attr_thr.attr,
 894        &format_attr_fvc.attr,
 895        &format_attr_pgt.attr,
 896        &format_attr_map.attr,
 897        &format_attr_iss.attr,
 898        &format_attr_pld.attr,
 899        NULL,
 900};
 901
 902static const struct attribute_group nhmex_uncore_mbox_format_group = {
 903        .name           = "format",
 904        .attrs          = nhmex_uncore_mbox_formats_attr,
 905};
 906
 907static struct uncore_event_desc nhmex_uncore_mbox_events[] = {
 908        INTEL_UNCORE_EVENT_DESC(bbox_cmds_read, "inc_sel=0xd,fvc=0x2800"),
 909        INTEL_UNCORE_EVENT_DESC(bbox_cmds_write, "inc_sel=0xd,fvc=0x2820"),
 910        { /* end: all zeroes */ },
 911};
 912
 913static struct uncore_event_desc wsmex_uncore_mbox_events[] = {
 914        INTEL_UNCORE_EVENT_DESC(bbox_cmds_read, "inc_sel=0xd,fvc=0x5000"),
 915        INTEL_UNCORE_EVENT_DESC(bbox_cmds_write, "inc_sel=0xd,fvc=0x5040"),
 916        { /* end: all zeroes */ },
 917};
 918
 919static struct intel_uncore_ops nhmex_uncore_mbox_ops = {
 920        NHMEX_UNCORE_OPS_COMMON_INIT(),
 921        .enable_event   = nhmex_mbox_msr_enable_event,
 922        .hw_config      = nhmex_mbox_hw_config,
 923        .get_constraint = nhmex_mbox_get_constraint,
 924        .put_constraint = nhmex_mbox_put_constraint,
 925};
 926
 927static struct intel_uncore_type nhmex_uncore_mbox = {
 928        .name                   = "mbox",
 929        .num_counters           = 6,
 930        .num_boxes              = 2,
 931        .perf_ctr_bits          = 48,
 932        .event_ctl              = NHMEX_M0_MSR_PMU_CTL0,
 933        .perf_ctr               = NHMEX_M0_MSR_PMU_CNT0,
 934        .event_mask             = NHMEX_M_PMON_RAW_EVENT_MASK,
 935        .box_ctl                = NHMEX_M0_MSR_GLOBAL_CTL,
 936        .msr_offset             = NHMEX_M_MSR_OFFSET,
 937        .pair_ctr_ctl           = 1,
 938        .num_shared_regs        = 8,
 939        .event_descs            = nhmex_uncore_mbox_events,
 940        .ops                    = &nhmex_uncore_mbox_ops,
 941        .format_group           = &nhmex_uncore_mbox_format_group,
 942};
 943
 944static void nhmex_rbox_alter_er(struct intel_uncore_box *box, struct perf_event *event)
 945{
 946        struct hw_perf_event *hwc = &event->hw;
 947        struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
 948
 949        /* adjust the main event selector and extra register index */
 950        if (reg1->idx % 2) {
 951                reg1->idx--;
 952                hwc->config -= 1 << NHMEX_R_PMON_CTL_EV_SEL_SHIFT;
 953        } else {
 954                reg1->idx++;
 955                hwc->config += 1 << NHMEX_R_PMON_CTL_EV_SEL_SHIFT;
 956        }
 957
 958        /* adjust extra register config */
 959        switch (reg1->idx % 6) {
 960        case 2:
 961                /* shift the 8~15 bits to the 0~7 bits */
 962                reg1->config >>= 8;
 963                break;
 964        case 3:
 965                /* shift the 0~7 bits to the 8~15 bits */
 966                reg1->config <<= 8;
 967                break;
 968        }
 969}
 970
 971/*
 972 * Each rbox has 4 event set which monitor PQI port 0~3 or 4~7.
 973 * An event set consists of 6 events, the 3rd and 4th events in
 974 * an event set use the same extra register. So an event set uses
 975 * 5 extra registers.
 976 */
 977static struct event_constraint *
 978nhmex_rbox_get_constraint(struct intel_uncore_box *box, struct perf_event *event)
 979{
 980        struct hw_perf_event *hwc = &event->hw;
 981        struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
 982        struct hw_perf_event_extra *reg2 = &hwc->branch_reg;
 983        struct intel_uncore_extra_reg *er;
 984        unsigned long flags;
 985        int idx, er_idx;
 986        u64 config1;
 987        bool ok = false;
 988
 989        if (!uncore_box_is_fake(box) && reg1->alloc)
 990                return NULL;
 991
 992        idx = reg1->idx % 6;
 993        config1 = reg1->config;
 994again:
 995        er_idx = idx;
 996        /* the 3rd and 4th events use the same extra register */
 997        if (er_idx > 2)
 998                er_idx--;
 999        er_idx += (reg1->idx / 6) * 5;
1000
1001        er = &box->shared_regs[er_idx];
1002        raw_spin_lock_irqsave(&er->lock, flags);
1003        if (idx < 2) {
1004                if (!atomic_read(&er->ref) || er->config == reg1->config) {
1005                        atomic_inc(&er->ref);
1006                        er->config = reg1->config;
1007                        ok = true;
1008                }
1009        } else if (idx == 2 || idx == 3) {
1010                /*
1011                 * these two events use different fields in a extra register,
1012                 * the 0~7 bits and the 8~15 bits respectively.
1013                 */
1014                u64 mask = 0xff << ((idx - 2) * 8);
1015                if (!__BITS_VALUE(atomic_read(&er->ref), idx - 2, 8) ||
1016                                !((er->config ^ config1) & mask)) {
1017                        atomic_add(1 << ((idx - 2) * 8), &er->ref);
1018                        er->config &= ~mask;
1019                        er->config |= config1 & mask;
1020                        ok = true;
1021                }
1022        } else {
1023                if (!atomic_read(&er->ref) ||
1024                                (er->config == (hwc->config >> 32) &&
1025                                 er->config1 == reg1->config &&
1026                                 er->config2 == reg2->config)) {
1027                        atomic_inc(&er->ref);
1028                        er->config = (hwc->config >> 32);
1029                        er->config1 = reg1->config;
1030                        er->config2 = reg2->config;
1031                        ok = true;
1032                }
1033        }
1034        raw_spin_unlock_irqrestore(&er->lock, flags);
1035
1036        if (!ok) {
1037                /*
1038                 * The Rbox events are always in pairs. The paired
1039                 * events are functional identical, but use different
1040                 * extra registers. If we failed to take an extra
1041                 * register, try the alternative.
1042                 */
1043                idx ^= 1;
1044                if (idx != reg1->idx % 6) {
1045                        if (idx == 2)
1046                                config1 >>= 8;
1047                        else if (idx == 3)
1048                                config1 <<= 8;
1049                        goto again;
1050                }
1051        } else {
1052                if (!uncore_box_is_fake(box)) {
1053                        if (idx != reg1->idx % 6)
1054                                nhmex_rbox_alter_er(box, event);
1055                        reg1->alloc = 1;
1056                }
1057                return NULL;
1058        }
1059        return &uncore_constraint_empty;
1060}
1061
1062static void nhmex_rbox_put_constraint(struct intel_uncore_box *box, struct perf_event *event)
1063{
1064        struct intel_uncore_extra_reg *er;
1065        struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
1066        int idx, er_idx;
1067
1068        if (uncore_box_is_fake(box) || !reg1->alloc)
1069                return;
1070
1071        idx = reg1->idx % 6;
1072        er_idx = idx;
1073        if (er_idx > 2)
1074                er_idx--;
1075        er_idx += (reg1->idx / 6) * 5;
1076
1077        er = &box->shared_regs[er_idx];
1078        if (idx == 2 || idx == 3)
1079                atomic_sub(1 << ((idx - 2) * 8), &er->ref);
1080        else
1081                atomic_dec(&er->ref);
1082
1083        reg1->alloc = 0;
1084}
1085
1086static int nhmex_rbox_hw_config(struct intel_uncore_box *box, struct perf_event *event)
1087{
1088        struct hw_perf_event *hwc = &event->hw;
1089        struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
1090        struct hw_perf_event_extra *reg2 = &event->hw.branch_reg;
1091        int idx;
1092
1093        idx = (event->hw.config & NHMEX_R_PMON_CTL_EV_SEL_MASK) >>
1094                NHMEX_R_PMON_CTL_EV_SEL_SHIFT;
1095        if (idx >= 0x18)
1096                return -EINVAL;
1097
1098        reg1->idx = idx;
1099        reg1->config = event->attr.config1;
1100
1101        switch (idx % 6) {
1102        case 4:
1103        case 5:
1104                hwc->config |= event->attr.config & (~0ULL << 32);
1105                reg2->config = event->attr.config2;
1106                break;
1107        }
1108        return 0;
1109}
1110
1111static void nhmex_rbox_msr_enable_event(struct intel_uncore_box *box, struct perf_event *event)
1112{
1113        struct hw_perf_event *hwc = &event->hw;
1114        struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
1115        struct hw_perf_event_extra *reg2 = &hwc->branch_reg;
1116        int idx, port;
1117
1118        idx = reg1->idx;
1119        port = idx / 6 + box->pmu->pmu_idx * 4;
1120
1121        switch (idx % 6) {
1122        case 0:
1123                wrmsrl(NHMEX_R_MSR_PORTN_IPERF_CFG0(port), reg1->config);
1124                break;
1125        case 1:
1126                wrmsrl(NHMEX_R_MSR_PORTN_IPERF_CFG1(port), reg1->config);
1127                break;
1128        case 2:
1129        case 3:
1130                wrmsrl(NHMEX_R_MSR_PORTN_QLX_CFG(port),
1131                        uncore_shared_reg_config(box, 2 + (idx / 6) * 5));
1132                break;
1133        case 4:
1134                wrmsrl(NHMEX_R_MSR_PORTN_XBR_SET1_MM_CFG(port),
1135                        hwc->config >> 32);
1136                wrmsrl(NHMEX_R_MSR_PORTN_XBR_SET1_MATCH(port), reg1->config);
1137                wrmsrl(NHMEX_R_MSR_PORTN_XBR_SET1_MASK(port), reg2->config);
1138                break;
1139        case 5:
1140                wrmsrl(NHMEX_R_MSR_PORTN_XBR_SET2_MM_CFG(port),
1141                        hwc->config >> 32);
1142                wrmsrl(NHMEX_R_MSR_PORTN_XBR_SET2_MATCH(port), reg1->config);
1143                wrmsrl(NHMEX_R_MSR_PORTN_XBR_SET2_MASK(port), reg2->config);
1144                break;
1145        }
1146
1147        wrmsrl(hwc->config_base, NHMEX_PMON_CTL_EN_BIT0 |
1148                (hwc->config & NHMEX_R_PMON_CTL_EV_SEL_MASK));
1149}
1150
1151DEFINE_UNCORE_FORMAT_ATTR(xbr_mm_cfg, xbr_mm_cfg, "config:32-63");
1152DEFINE_UNCORE_FORMAT_ATTR(xbr_match, xbr_match, "config1:0-63");
1153DEFINE_UNCORE_FORMAT_ATTR(xbr_mask, xbr_mask, "config2:0-63");
1154DEFINE_UNCORE_FORMAT_ATTR(qlx_cfg, qlx_cfg, "config1:0-15");
1155DEFINE_UNCORE_FORMAT_ATTR(iperf_cfg, iperf_cfg, "config1:0-31");
1156
1157static struct attribute *nhmex_uncore_rbox_formats_attr[] = {
1158        &format_attr_event5.attr,
1159        &format_attr_xbr_mm_cfg.attr,
1160        &format_attr_xbr_match.attr,
1161        &format_attr_xbr_mask.attr,
1162        &format_attr_qlx_cfg.attr,
1163        &format_attr_iperf_cfg.attr,
1164        NULL,
1165};
1166
1167static const struct attribute_group nhmex_uncore_rbox_format_group = {
1168        .name = "format",
1169        .attrs = nhmex_uncore_rbox_formats_attr,
1170};
1171
1172static struct uncore_event_desc nhmex_uncore_rbox_events[] = {
1173        INTEL_UNCORE_EVENT_DESC(qpi0_flit_send,         "event=0x0,iperf_cfg=0x80000000"),
1174        INTEL_UNCORE_EVENT_DESC(qpi1_filt_send,         "event=0x6,iperf_cfg=0x80000000"),
1175        INTEL_UNCORE_EVENT_DESC(qpi0_idle_filt,         "event=0x0,iperf_cfg=0x40000000"),
1176        INTEL_UNCORE_EVENT_DESC(qpi1_idle_filt,         "event=0x6,iperf_cfg=0x40000000"),
1177        INTEL_UNCORE_EVENT_DESC(qpi0_date_response,     "event=0x0,iperf_cfg=0xc4"),
1178        INTEL_UNCORE_EVENT_DESC(qpi1_date_response,     "event=0x6,iperf_cfg=0xc4"),
1179        { /* end: all zeroes */ },
1180};
1181
1182static struct intel_uncore_ops nhmex_uncore_rbox_ops = {
1183        NHMEX_UNCORE_OPS_COMMON_INIT(),
1184        .enable_event           = nhmex_rbox_msr_enable_event,
1185        .hw_config              = nhmex_rbox_hw_config,
1186        .get_constraint         = nhmex_rbox_get_constraint,
1187        .put_constraint         = nhmex_rbox_put_constraint,
1188};
1189
1190static struct intel_uncore_type nhmex_uncore_rbox = {
1191        .name                   = "rbox",
1192        .num_counters           = 8,
1193        .num_boxes              = 2,
1194        .perf_ctr_bits          = 48,
1195        .event_ctl              = NHMEX_R_MSR_PMON_CTL0,
1196        .perf_ctr               = NHMEX_R_MSR_PMON_CNT0,
1197        .event_mask             = NHMEX_R_PMON_RAW_EVENT_MASK,
1198        .box_ctl                = NHMEX_R_MSR_GLOBAL_CTL,
1199        .msr_offset             = NHMEX_R_MSR_OFFSET,
1200        .pair_ctr_ctl           = 1,
1201        .num_shared_regs        = 20,
1202        .event_descs            = nhmex_uncore_rbox_events,
1203        .ops                    = &nhmex_uncore_rbox_ops,
1204        .format_group           = &nhmex_uncore_rbox_format_group
1205};
1206
1207static struct intel_uncore_type *nhmex_msr_uncores[] = {
1208        &nhmex_uncore_ubox,
1209        &nhmex_uncore_cbox,
1210        &nhmex_uncore_bbox,
1211        &nhmex_uncore_sbox,
1212        &nhmex_uncore_mbox,
1213        &nhmex_uncore_rbox,
1214        &nhmex_uncore_wbox,
1215        NULL,
1216};
1217
1218void nhmex_uncore_cpu_init(void)
1219{
1220        if (boot_cpu_data.x86_model == 46)
1221                uncore_nhmex = true;
1222        else
1223                nhmex_uncore_mbox.event_descs = wsmex_uncore_mbox_events;
1224        if (nhmex_uncore_cbox.num_boxes > boot_cpu_data.x86_max_cores)
1225                nhmex_uncore_cbox.num_boxes = boot_cpu_data.x86_max_cores;
1226        uncore_msr_uncores = nhmex_msr_uncores;
1227}
1228/* end of Nehalem-EX uncore support */
1229