cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

uncore_nhmex.c (37513B)


      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 */