162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * Support cstate residency counters
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Copyright (C) 2015, Intel Corp.
562306a36Sopenharmony_ci * Author: Kan Liang (kan.liang@intel.com)
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * This library is free software; you can redistribute it and/or
862306a36Sopenharmony_ci * modify it under the terms of the GNU Library General Public
962306a36Sopenharmony_ci * License as published by the Free Software Foundation; either
1062306a36Sopenharmony_ci * version 2 of the License, or (at your option) any later version.
1162306a36Sopenharmony_ci *
1262306a36Sopenharmony_ci * This library is distributed in the hope that it will be useful,
1362306a36Sopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of
1462306a36Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
1562306a36Sopenharmony_ci * Library General Public License for more details.
1662306a36Sopenharmony_ci *
1762306a36Sopenharmony_ci */
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci/*
2062306a36Sopenharmony_ci * This file export cstate related free running (read-only) counters
2162306a36Sopenharmony_ci * for perf. These counters may be use simultaneously by other tools,
2262306a36Sopenharmony_ci * such as turbostat. However, it still make sense to implement them
2362306a36Sopenharmony_ci * in perf. Because we can conveniently collect them together with
2462306a36Sopenharmony_ci * other events, and allow to use them from tools without special MSR
2562306a36Sopenharmony_ci * access code.
2662306a36Sopenharmony_ci *
2762306a36Sopenharmony_ci * The events only support system-wide mode counting. There is no
2862306a36Sopenharmony_ci * sampling support because it is not supported by the hardware.
2962306a36Sopenharmony_ci *
3062306a36Sopenharmony_ci * According to counters' scope and category, two PMUs are registered
3162306a36Sopenharmony_ci * with the perf_event core subsystem.
3262306a36Sopenharmony_ci *  - 'cstate_core': The counter is available for each physical core.
3362306a36Sopenharmony_ci *    The counters include CORE_C*_RESIDENCY.
3462306a36Sopenharmony_ci *  - 'cstate_pkg': The counter is available for each physical package.
3562306a36Sopenharmony_ci *    The counters include PKG_C*_RESIDENCY.
3662306a36Sopenharmony_ci *
3762306a36Sopenharmony_ci * All of these counters are specified in the Intel® 64 and IA-32
3862306a36Sopenharmony_ci * Architectures Software Developer.s Manual Vol3b.
3962306a36Sopenharmony_ci *
4062306a36Sopenharmony_ci * Model specific counters:
4162306a36Sopenharmony_ci *	MSR_CORE_C1_RES: CORE C1 Residency Counter
4262306a36Sopenharmony_ci *			 perf code: 0x00
4362306a36Sopenharmony_ci *			 Available model: SLM,AMT,GLM,CNL,ICX,TNT,ADL,RPL
4462306a36Sopenharmony_ci *					  MTL
4562306a36Sopenharmony_ci *			 Scope: Core (each processor core has a MSR)
4662306a36Sopenharmony_ci *	MSR_CORE_C3_RESIDENCY: CORE C3 Residency Counter
4762306a36Sopenharmony_ci *			       perf code: 0x01
4862306a36Sopenharmony_ci *			       Available model: NHM,WSM,SNB,IVB,HSW,BDW,SKL,GLM,
4962306a36Sopenharmony_ci *						CNL,KBL,CML,TNT
5062306a36Sopenharmony_ci *			       Scope: Core
5162306a36Sopenharmony_ci *	MSR_CORE_C6_RESIDENCY: CORE C6 Residency Counter
5262306a36Sopenharmony_ci *			       perf code: 0x02
5362306a36Sopenharmony_ci *			       Available model: SLM,AMT,NHM,WSM,SNB,IVB,HSW,BDW,
5462306a36Sopenharmony_ci *						SKL,KNL,GLM,CNL,KBL,CML,ICL,ICX,
5562306a36Sopenharmony_ci *						TGL,TNT,RKL,ADL,RPL,SPR,MTL
5662306a36Sopenharmony_ci *			       Scope: Core
5762306a36Sopenharmony_ci *	MSR_CORE_C7_RESIDENCY: CORE C7 Residency Counter
5862306a36Sopenharmony_ci *			       perf code: 0x03
5962306a36Sopenharmony_ci *			       Available model: SNB,IVB,HSW,BDW,SKL,CNL,KBL,CML,
6062306a36Sopenharmony_ci *						ICL,TGL,RKL,ADL,RPL,MTL
6162306a36Sopenharmony_ci *			       Scope: Core
6262306a36Sopenharmony_ci *	MSR_PKG_C2_RESIDENCY:  Package C2 Residency Counter.
6362306a36Sopenharmony_ci *			       perf code: 0x00
6462306a36Sopenharmony_ci *			       Available model: SNB,IVB,HSW,BDW,SKL,KNL,GLM,CNL,
6562306a36Sopenharmony_ci *						KBL,CML,ICL,ICX,TGL,TNT,RKL,ADL,
6662306a36Sopenharmony_ci *						RPL,SPR,MTL
6762306a36Sopenharmony_ci *			       Scope: Package (physical package)
6862306a36Sopenharmony_ci *	MSR_PKG_C3_RESIDENCY:  Package C3 Residency Counter.
6962306a36Sopenharmony_ci *			       perf code: 0x01
7062306a36Sopenharmony_ci *			       Available model: NHM,WSM,SNB,IVB,HSW,BDW,SKL,KNL,
7162306a36Sopenharmony_ci *						GLM,CNL,KBL,CML,ICL,TGL,TNT,RKL,
7262306a36Sopenharmony_ci *						ADL,RPL,MTL
7362306a36Sopenharmony_ci *			       Scope: Package (physical package)
7462306a36Sopenharmony_ci *	MSR_PKG_C6_RESIDENCY:  Package C6 Residency Counter.
7562306a36Sopenharmony_ci *			       perf code: 0x02
7662306a36Sopenharmony_ci *			       Available model: SLM,AMT,NHM,WSM,SNB,IVB,HSW,BDW,
7762306a36Sopenharmony_ci *						SKL,KNL,GLM,CNL,KBL,CML,ICL,ICX,
7862306a36Sopenharmony_ci *						TGL,TNT,RKL,ADL,RPL,SPR,MTL
7962306a36Sopenharmony_ci *			       Scope: Package (physical package)
8062306a36Sopenharmony_ci *	MSR_PKG_C7_RESIDENCY:  Package C7 Residency Counter.
8162306a36Sopenharmony_ci *			       perf code: 0x03
8262306a36Sopenharmony_ci *			       Available model: NHM,WSM,SNB,IVB,HSW,BDW,SKL,CNL,
8362306a36Sopenharmony_ci *						KBL,CML,ICL,TGL,RKL,ADL,RPL,MTL
8462306a36Sopenharmony_ci *			       Scope: Package (physical package)
8562306a36Sopenharmony_ci *	MSR_PKG_C8_RESIDENCY:  Package C8 Residency Counter.
8662306a36Sopenharmony_ci *			       perf code: 0x04
8762306a36Sopenharmony_ci *			       Available model: HSW ULT,KBL,CNL,CML,ICL,TGL,RKL,
8862306a36Sopenharmony_ci *						ADL,RPL,MTL
8962306a36Sopenharmony_ci *			       Scope: Package (physical package)
9062306a36Sopenharmony_ci *	MSR_PKG_C9_RESIDENCY:  Package C9 Residency Counter.
9162306a36Sopenharmony_ci *			       perf code: 0x05
9262306a36Sopenharmony_ci *			       Available model: HSW ULT,KBL,CNL,CML,ICL,TGL,RKL,
9362306a36Sopenharmony_ci *						ADL,RPL,MTL
9462306a36Sopenharmony_ci *			       Scope: Package (physical package)
9562306a36Sopenharmony_ci *	MSR_PKG_C10_RESIDENCY: Package C10 Residency Counter.
9662306a36Sopenharmony_ci *			       perf code: 0x06
9762306a36Sopenharmony_ci *			       Available model: HSW ULT,KBL,GLM,CNL,CML,ICL,TGL,
9862306a36Sopenharmony_ci *						TNT,RKL,ADL,RPL,MTL
9962306a36Sopenharmony_ci *			       Scope: Package (physical package)
10062306a36Sopenharmony_ci *
10162306a36Sopenharmony_ci */
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci#include <linux/module.h>
10462306a36Sopenharmony_ci#include <linux/slab.h>
10562306a36Sopenharmony_ci#include <linux/perf_event.h>
10662306a36Sopenharmony_ci#include <linux/nospec.h>
10762306a36Sopenharmony_ci#include <asm/cpu_device_id.h>
10862306a36Sopenharmony_ci#include <asm/intel-family.h>
10962306a36Sopenharmony_ci#include "../perf_event.h"
11062306a36Sopenharmony_ci#include "../probe.h"
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ciMODULE_LICENSE("GPL");
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci#define DEFINE_CSTATE_FORMAT_ATTR(_var, _name, _format)		\
11562306a36Sopenharmony_cistatic ssize_t __cstate_##_var##_show(struct device *dev,	\
11662306a36Sopenharmony_ci				struct device_attribute *attr,	\
11762306a36Sopenharmony_ci				char *page)			\
11862306a36Sopenharmony_ci{								\
11962306a36Sopenharmony_ci	BUILD_BUG_ON(sizeof(_format) >= PAGE_SIZE);		\
12062306a36Sopenharmony_ci	return sprintf(page, _format "\n");			\
12162306a36Sopenharmony_ci}								\
12262306a36Sopenharmony_cistatic struct device_attribute format_attr_##_var =		\
12362306a36Sopenharmony_ci	__ATTR(_name, 0444, __cstate_##_var##_show, NULL)
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_cistatic ssize_t cstate_get_attr_cpumask(struct device *dev,
12662306a36Sopenharmony_ci				       struct device_attribute *attr,
12762306a36Sopenharmony_ci				       char *buf);
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci/* Model -> events mapping */
13062306a36Sopenharmony_cistruct cstate_model {
13162306a36Sopenharmony_ci	unsigned long		core_events;
13262306a36Sopenharmony_ci	unsigned long		pkg_events;
13362306a36Sopenharmony_ci	unsigned long		quirks;
13462306a36Sopenharmony_ci};
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci/* Quirk flags */
13762306a36Sopenharmony_ci#define SLM_PKG_C6_USE_C7_MSR	(1UL << 0)
13862306a36Sopenharmony_ci#define KNL_CORE_C6_MSR		(1UL << 1)
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_cistruct perf_cstate_msr {
14162306a36Sopenharmony_ci	u64	msr;
14262306a36Sopenharmony_ci	struct	perf_pmu_events_attr *attr;
14362306a36Sopenharmony_ci};
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci/* cstate_core PMU */
14762306a36Sopenharmony_cistatic struct pmu cstate_core_pmu;
14862306a36Sopenharmony_cistatic bool has_cstate_core;
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_cienum perf_cstate_core_events {
15162306a36Sopenharmony_ci	PERF_CSTATE_CORE_C1_RES = 0,
15262306a36Sopenharmony_ci	PERF_CSTATE_CORE_C3_RES,
15362306a36Sopenharmony_ci	PERF_CSTATE_CORE_C6_RES,
15462306a36Sopenharmony_ci	PERF_CSTATE_CORE_C7_RES,
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	PERF_CSTATE_CORE_EVENT_MAX,
15762306a36Sopenharmony_ci};
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ciPMU_EVENT_ATTR_STRING(c1-residency, attr_cstate_core_c1, "event=0x00");
16062306a36Sopenharmony_ciPMU_EVENT_ATTR_STRING(c3-residency, attr_cstate_core_c3, "event=0x01");
16162306a36Sopenharmony_ciPMU_EVENT_ATTR_STRING(c6-residency, attr_cstate_core_c6, "event=0x02");
16262306a36Sopenharmony_ciPMU_EVENT_ATTR_STRING(c7-residency, attr_cstate_core_c7, "event=0x03");
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_cistatic unsigned long core_msr_mask;
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ciPMU_EVENT_GROUP(events, cstate_core_c1);
16762306a36Sopenharmony_ciPMU_EVENT_GROUP(events, cstate_core_c3);
16862306a36Sopenharmony_ciPMU_EVENT_GROUP(events, cstate_core_c6);
16962306a36Sopenharmony_ciPMU_EVENT_GROUP(events, cstate_core_c7);
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_cistatic bool test_msr(int idx, void *data)
17262306a36Sopenharmony_ci{
17362306a36Sopenharmony_ci	return test_bit(idx, (unsigned long *) data);
17462306a36Sopenharmony_ci}
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_cistatic struct perf_msr core_msr[] = {
17762306a36Sopenharmony_ci	[PERF_CSTATE_CORE_C1_RES] = { MSR_CORE_C1_RES,		&group_cstate_core_c1,	test_msr },
17862306a36Sopenharmony_ci	[PERF_CSTATE_CORE_C3_RES] = { MSR_CORE_C3_RESIDENCY,	&group_cstate_core_c3,	test_msr },
17962306a36Sopenharmony_ci	[PERF_CSTATE_CORE_C6_RES] = { MSR_CORE_C6_RESIDENCY,	&group_cstate_core_c6,	test_msr },
18062306a36Sopenharmony_ci	[PERF_CSTATE_CORE_C7_RES] = { MSR_CORE_C7_RESIDENCY,	&group_cstate_core_c7,	test_msr },
18162306a36Sopenharmony_ci};
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_cistatic struct attribute *attrs_empty[] = {
18462306a36Sopenharmony_ci	NULL,
18562306a36Sopenharmony_ci};
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci/*
18862306a36Sopenharmony_ci * There are no default events, but we need to create
18962306a36Sopenharmony_ci * "events" group (with empty attrs) before updating
19062306a36Sopenharmony_ci * it with detected events.
19162306a36Sopenharmony_ci */
19262306a36Sopenharmony_cistatic struct attribute_group core_events_attr_group = {
19362306a36Sopenharmony_ci	.name = "events",
19462306a36Sopenharmony_ci	.attrs = attrs_empty,
19562306a36Sopenharmony_ci};
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ciDEFINE_CSTATE_FORMAT_ATTR(core_event, event, "config:0-63");
19862306a36Sopenharmony_cistatic struct attribute *core_format_attrs[] = {
19962306a36Sopenharmony_ci	&format_attr_core_event.attr,
20062306a36Sopenharmony_ci	NULL,
20162306a36Sopenharmony_ci};
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_cistatic struct attribute_group core_format_attr_group = {
20462306a36Sopenharmony_ci	.name = "format",
20562306a36Sopenharmony_ci	.attrs = core_format_attrs,
20662306a36Sopenharmony_ci};
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_cistatic cpumask_t cstate_core_cpu_mask;
20962306a36Sopenharmony_cistatic DEVICE_ATTR(cpumask, S_IRUGO, cstate_get_attr_cpumask, NULL);
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_cistatic struct attribute *cstate_cpumask_attrs[] = {
21262306a36Sopenharmony_ci	&dev_attr_cpumask.attr,
21362306a36Sopenharmony_ci	NULL,
21462306a36Sopenharmony_ci};
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_cistatic struct attribute_group cpumask_attr_group = {
21762306a36Sopenharmony_ci	.attrs = cstate_cpumask_attrs,
21862306a36Sopenharmony_ci};
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_cistatic const struct attribute_group *core_attr_groups[] = {
22162306a36Sopenharmony_ci	&core_events_attr_group,
22262306a36Sopenharmony_ci	&core_format_attr_group,
22362306a36Sopenharmony_ci	&cpumask_attr_group,
22462306a36Sopenharmony_ci	NULL,
22562306a36Sopenharmony_ci};
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci/* cstate_pkg PMU */
22862306a36Sopenharmony_cistatic struct pmu cstate_pkg_pmu;
22962306a36Sopenharmony_cistatic bool has_cstate_pkg;
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_cienum perf_cstate_pkg_events {
23262306a36Sopenharmony_ci	PERF_CSTATE_PKG_C2_RES = 0,
23362306a36Sopenharmony_ci	PERF_CSTATE_PKG_C3_RES,
23462306a36Sopenharmony_ci	PERF_CSTATE_PKG_C6_RES,
23562306a36Sopenharmony_ci	PERF_CSTATE_PKG_C7_RES,
23662306a36Sopenharmony_ci	PERF_CSTATE_PKG_C8_RES,
23762306a36Sopenharmony_ci	PERF_CSTATE_PKG_C9_RES,
23862306a36Sopenharmony_ci	PERF_CSTATE_PKG_C10_RES,
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci	PERF_CSTATE_PKG_EVENT_MAX,
24162306a36Sopenharmony_ci};
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ciPMU_EVENT_ATTR_STRING(c2-residency,  attr_cstate_pkg_c2,  "event=0x00");
24462306a36Sopenharmony_ciPMU_EVENT_ATTR_STRING(c3-residency,  attr_cstate_pkg_c3,  "event=0x01");
24562306a36Sopenharmony_ciPMU_EVENT_ATTR_STRING(c6-residency,  attr_cstate_pkg_c6,  "event=0x02");
24662306a36Sopenharmony_ciPMU_EVENT_ATTR_STRING(c7-residency,  attr_cstate_pkg_c7,  "event=0x03");
24762306a36Sopenharmony_ciPMU_EVENT_ATTR_STRING(c8-residency,  attr_cstate_pkg_c8,  "event=0x04");
24862306a36Sopenharmony_ciPMU_EVENT_ATTR_STRING(c9-residency,  attr_cstate_pkg_c9,  "event=0x05");
24962306a36Sopenharmony_ciPMU_EVENT_ATTR_STRING(c10-residency, attr_cstate_pkg_c10, "event=0x06");
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_cistatic unsigned long pkg_msr_mask;
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ciPMU_EVENT_GROUP(events, cstate_pkg_c2);
25462306a36Sopenharmony_ciPMU_EVENT_GROUP(events, cstate_pkg_c3);
25562306a36Sopenharmony_ciPMU_EVENT_GROUP(events, cstate_pkg_c6);
25662306a36Sopenharmony_ciPMU_EVENT_GROUP(events, cstate_pkg_c7);
25762306a36Sopenharmony_ciPMU_EVENT_GROUP(events, cstate_pkg_c8);
25862306a36Sopenharmony_ciPMU_EVENT_GROUP(events, cstate_pkg_c9);
25962306a36Sopenharmony_ciPMU_EVENT_GROUP(events, cstate_pkg_c10);
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_cistatic struct perf_msr pkg_msr[] = {
26262306a36Sopenharmony_ci	[PERF_CSTATE_PKG_C2_RES]  = { MSR_PKG_C2_RESIDENCY,	&group_cstate_pkg_c2,	test_msr },
26362306a36Sopenharmony_ci	[PERF_CSTATE_PKG_C3_RES]  = { MSR_PKG_C3_RESIDENCY,	&group_cstate_pkg_c3,	test_msr },
26462306a36Sopenharmony_ci	[PERF_CSTATE_PKG_C6_RES]  = { MSR_PKG_C6_RESIDENCY,	&group_cstate_pkg_c6,	test_msr },
26562306a36Sopenharmony_ci	[PERF_CSTATE_PKG_C7_RES]  = { MSR_PKG_C7_RESIDENCY,	&group_cstate_pkg_c7,	test_msr },
26662306a36Sopenharmony_ci	[PERF_CSTATE_PKG_C8_RES]  = { MSR_PKG_C8_RESIDENCY,	&group_cstate_pkg_c8,	test_msr },
26762306a36Sopenharmony_ci	[PERF_CSTATE_PKG_C9_RES]  = { MSR_PKG_C9_RESIDENCY,	&group_cstate_pkg_c9,	test_msr },
26862306a36Sopenharmony_ci	[PERF_CSTATE_PKG_C10_RES] = { MSR_PKG_C10_RESIDENCY,	&group_cstate_pkg_c10,	test_msr },
26962306a36Sopenharmony_ci};
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_cistatic struct attribute_group pkg_events_attr_group = {
27262306a36Sopenharmony_ci	.name = "events",
27362306a36Sopenharmony_ci	.attrs = attrs_empty,
27462306a36Sopenharmony_ci};
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ciDEFINE_CSTATE_FORMAT_ATTR(pkg_event, event, "config:0-63");
27762306a36Sopenharmony_cistatic struct attribute *pkg_format_attrs[] = {
27862306a36Sopenharmony_ci	&format_attr_pkg_event.attr,
27962306a36Sopenharmony_ci	NULL,
28062306a36Sopenharmony_ci};
28162306a36Sopenharmony_cistatic struct attribute_group pkg_format_attr_group = {
28262306a36Sopenharmony_ci	.name = "format",
28362306a36Sopenharmony_ci	.attrs = pkg_format_attrs,
28462306a36Sopenharmony_ci};
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_cistatic cpumask_t cstate_pkg_cpu_mask;
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_cistatic const struct attribute_group *pkg_attr_groups[] = {
28962306a36Sopenharmony_ci	&pkg_events_attr_group,
29062306a36Sopenharmony_ci	&pkg_format_attr_group,
29162306a36Sopenharmony_ci	&cpumask_attr_group,
29262306a36Sopenharmony_ci	NULL,
29362306a36Sopenharmony_ci};
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_cistatic ssize_t cstate_get_attr_cpumask(struct device *dev,
29662306a36Sopenharmony_ci				       struct device_attribute *attr,
29762306a36Sopenharmony_ci				       char *buf)
29862306a36Sopenharmony_ci{
29962306a36Sopenharmony_ci	struct pmu *pmu = dev_get_drvdata(dev);
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci	if (pmu == &cstate_core_pmu)
30262306a36Sopenharmony_ci		return cpumap_print_to_pagebuf(true, buf, &cstate_core_cpu_mask);
30362306a36Sopenharmony_ci	else if (pmu == &cstate_pkg_pmu)
30462306a36Sopenharmony_ci		return cpumap_print_to_pagebuf(true, buf, &cstate_pkg_cpu_mask);
30562306a36Sopenharmony_ci	else
30662306a36Sopenharmony_ci		return 0;
30762306a36Sopenharmony_ci}
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_cistatic int cstate_pmu_event_init(struct perf_event *event)
31062306a36Sopenharmony_ci{
31162306a36Sopenharmony_ci	u64 cfg = event->attr.config;
31262306a36Sopenharmony_ci	int cpu;
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	if (event->attr.type != event->pmu->type)
31562306a36Sopenharmony_ci		return -ENOENT;
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci	/* unsupported modes and filters */
31862306a36Sopenharmony_ci	if (event->attr.sample_period) /* no sampling */
31962306a36Sopenharmony_ci		return -EINVAL;
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci	if (event->cpu < 0)
32262306a36Sopenharmony_ci		return -EINVAL;
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci	if (event->pmu == &cstate_core_pmu) {
32562306a36Sopenharmony_ci		if (cfg >= PERF_CSTATE_CORE_EVENT_MAX)
32662306a36Sopenharmony_ci			return -EINVAL;
32762306a36Sopenharmony_ci		cfg = array_index_nospec((unsigned long)cfg, PERF_CSTATE_CORE_EVENT_MAX);
32862306a36Sopenharmony_ci		if (!(core_msr_mask & (1 << cfg)))
32962306a36Sopenharmony_ci			return -EINVAL;
33062306a36Sopenharmony_ci		event->hw.event_base = core_msr[cfg].msr;
33162306a36Sopenharmony_ci		cpu = cpumask_any_and(&cstate_core_cpu_mask,
33262306a36Sopenharmony_ci				      topology_sibling_cpumask(event->cpu));
33362306a36Sopenharmony_ci	} else if (event->pmu == &cstate_pkg_pmu) {
33462306a36Sopenharmony_ci		if (cfg >= PERF_CSTATE_PKG_EVENT_MAX)
33562306a36Sopenharmony_ci			return -EINVAL;
33662306a36Sopenharmony_ci		cfg = array_index_nospec((unsigned long)cfg, PERF_CSTATE_PKG_EVENT_MAX);
33762306a36Sopenharmony_ci		if (!(pkg_msr_mask & (1 << cfg)))
33862306a36Sopenharmony_ci			return -EINVAL;
33962306a36Sopenharmony_ci		event->hw.event_base = pkg_msr[cfg].msr;
34062306a36Sopenharmony_ci		cpu = cpumask_any_and(&cstate_pkg_cpu_mask,
34162306a36Sopenharmony_ci				      topology_die_cpumask(event->cpu));
34262306a36Sopenharmony_ci	} else {
34362306a36Sopenharmony_ci		return -ENOENT;
34462306a36Sopenharmony_ci	}
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci	if (cpu >= nr_cpu_ids)
34762306a36Sopenharmony_ci		return -ENODEV;
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci	event->cpu = cpu;
35062306a36Sopenharmony_ci	event->hw.config = cfg;
35162306a36Sopenharmony_ci	event->hw.idx = -1;
35262306a36Sopenharmony_ci	return 0;
35362306a36Sopenharmony_ci}
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_cistatic inline u64 cstate_pmu_read_counter(struct perf_event *event)
35662306a36Sopenharmony_ci{
35762306a36Sopenharmony_ci	u64 val;
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	rdmsrl(event->hw.event_base, val);
36062306a36Sopenharmony_ci	return val;
36162306a36Sopenharmony_ci}
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_cistatic void cstate_pmu_event_update(struct perf_event *event)
36462306a36Sopenharmony_ci{
36562306a36Sopenharmony_ci	struct hw_perf_event *hwc = &event->hw;
36662306a36Sopenharmony_ci	u64 prev_raw_count, new_raw_count;
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ci	prev_raw_count = local64_read(&hwc->prev_count);
36962306a36Sopenharmony_ci	do {
37062306a36Sopenharmony_ci		new_raw_count = cstate_pmu_read_counter(event);
37162306a36Sopenharmony_ci	} while (!local64_try_cmpxchg(&hwc->prev_count,
37262306a36Sopenharmony_ci				      &prev_raw_count, new_raw_count));
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci	local64_add(new_raw_count - prev_raw_count, &event->count);
37562306a36Sopenharmony_ci}
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_cistatic void cstate_pmu_event_start(struct perf_event *event, int mode)
37862306a36Sopenharmony_ci{
37962306a36Sopenharmony_ci	local64_set(&event->hw.prev_count, cstate_pmu_read_counter(event));
38062306a36Sopenharmony_ci}
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_cistatic void cstate_pmu_event_stop(struct perf_event *event, int mode)
38362306a36Sopenharmony_ci{
38462306a36Sopenharmony_ci	cstate_pmu_event_update(event);
38562306a36Sopenharmony_ci}
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_cistatic void cstate_pmu_event_del(struct perf_event *event, int mode)
38862306a36Sopenharmony_ci{
38962306a36Sopenharmony_ci	cstate_pmu_event_stop(event, PERF_EF_UPDATE);
39062306a36Sopenharmony_ci}
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_cistatic int cstate_pmu_event_add(struct perf_event *event, int mode)
39362306a36Sopenharmony_ci{
39462306a36Sopenharmony_ci	if (mode & PERF_EF_START)
39562306a36Sopenharmony_ci		cstate_pmu_event_start(event, mode);
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci	return 0;
39862306a36Sopenharmony_ci}
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci/*
40162306a36Sopenharmony_ci * Check if exiting cpu is the designated reader. If so migrate the
40262306a36Sopenharmony_ci * events when there is a valid target available
40362306a36Sopenharmony_ci */
40462306a36Sopenharmony_cistatic int cstate_cpu_exit(unsigned int cpu)
40562306a36Sopenharmony_ci{
40662306a36Sopenharmony_ci	unsigned int target;
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci	if (has_cstate_core &&
40962306a36Sopenharmony_ci	    cpumask_test_and_clear_cpu(cpu, &cstate_core_cpu_mask)) {
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci		target = cpumask_any_but(topology_sibling_cpumask(cpu), cpu);
41262306a36Sopenharmony_ci		/* Migrate events if there is a valid target */
41362306a36Sopenharmony_ci		if (target < nr_cpu_ids) {
41462306a36Sopenharmony_ci			cpumask_set_cpu(target, &cstate_core_cpu_mask);
41562306a36Sopenharmony_ci			perf_pmu_migrate_context(&cstate_core_pmu, cpu, target);
41662306a36Sopenharmony_ci		}
41762306a36Sopenharmony_ci	}
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci	if (has_cstate_pkg &&
42062306a36Sopenharmony_ci	    cpumask_test_and_clear_cpu(cpu, &cstate_pkg_cpu_mask)) {
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci		target = cpumask_any_but(topology_die_cpumask(cpu), cpu);
42362306a36Sopenharmony_ci		/* Migrate events if there is a valid target */
42462306a36Sopenharmony_ci		if (target < nr_cpu_ids) {
42562306a36Sopenharmony_ci			cpumask_set_cpu(target, &cstate_pkg_cpu_mask);
42662306a36Sopenharmony_ci			perf_pmu_migrate_context(&cstate_pkg_pmu, cpu, target);
42762306a36Sopenharmony_ci		}
42862306a36Sopenharmony_ci	}
42962306a36Sopenharmony_ci	return 0;
43062306a36Sopenharmony_ci}
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_cistatic int cstate_cpu_init(unsigned int cpu)
43362306a36Sopenharmony_ci{
43462306a36Sopenharmony_ci	unsigned int target;
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci	/*
43762306a36Sopenharmony_ci	 * If this is the first online thread of that core, set it in
43862306a36Sopenharmony_ci	 * the core cpu mask as the designated reader.
43962306a36Sopenharmony_ci	 */
44062306a36Sopenharmony_ci	target = cpumask_any_and(&cstate_core_cpu_mask,
44162306a36Sopenharmony_ci				 topology_sibling_cpumask(cpu));
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ci	if (has_cstate_core && target >= nr_cpu_ids)
44462306a36Sopenharmony_ci		cpumask_set_cpu(cpu, &cstate_core_cpu_mask);
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci	/*
44762306a36Sopenharmony_ci	 * If this is the first online thread of that package, set it
44862306a36Sopenharmony_ci	 * in the package cpu mask as the designated reader.
44962306a36Sopenharmony_ci	 */
45062306a36Sopenharmony_ci	target = cpumask_any_and(&cstate_pkg_cpu_mask,
45162306a36Sopenharmony_ci				 topology_die_cpumask(cpu));
45262306a36Sopenharmony_ci	if (has_cstate_pkg && target >= nr_cpu_ids)
45362306a36Sopenharmony_ci		cpumask_set_cpu(cpu, &cstate_pkg_cpu_mask);
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci	return 0;
45662306a36Sopenharmony_ci}
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_cistatic const struct attribute_group *core_attr_update[] = {
45962306a36Sopenharmony_ci	&group_cstate_core_c1,
46062306a36Sopenharmony_ci	&group_cstate_core_c3,
46162306a36Sopenharmony_ci	&group_cstate_core_c6,
46262306a36Sopenharmony_ci	&group_cstate_core_c7,
46362306a36Sopenharmony_ci	NULL,
46462306a36Sopenharmony_ci};
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_cistatic const struct attribute_group *pkg_attr_update[] = {
46762306a36Sopenharmony_ci	&group_cstate_pkg_c2,
46862306a36Sopenharmony_ci	&group_cstate_pkg_c3,
46962306a36Sopenharmony_ci	&group_cstate_pkg_c6,
47062306a36Sopenharmony_ci	&group_cstate_pkg_c7,
47162306a36Sopenharmony_ci	&group_cstate_pkg_c8,
47262306a36Sopenharmony_ci	&group_cstate_pkg_c9,
47362306a36Sopenharmony_ci	&group_cstate_pkg_c10,
47462306a36Sopenharmony_ci	NULL,
47562306a36Sopenharmony_ci};
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_cistatic struct pmu cstate_core_pmu = {
47862306a36Sopenharmony_ci	.attr_groups	= core_attr_groups,
47962306a36Sopenharmony_ci	.attr_update	= core_attr_update,
48062306a36Sopenharmony_ci	.name		= "cstate_core",
48162306a36Sopenharmony_ci	.task_ctx_nr	= perf_invalid_context,
48262306a36Sopenharmony_ci	.event_init	= cstate_pmu_event_init,
48362306a36Sopenharmony_ci	.add		= cstate_pmu_event_add,
48462306a36Sopenharmony_ci	.del		= cstate_pmu_event_del,
48562306a36Sopenharmony_ci	.start		= cstate_pmu_event_start,
48662306a36Sopenharmony_ci	.stop		= cstate_pmu_event_stop,
48762306a36Sopenharmony_ci	.read		= cstate_pmu_event_update,
48862306a36Sopenharmony_ci	.capabilities	= PERF_PMU_CAP_NO_INTERRUPT | PERF_PMU_CAP_NO_EXCLUDE,
48962306a36Sopenharmony_ci	.module		= THIS_MODULE,
49062306a36Sopenharmony_ci};
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_cistatic struct pmu cstate_pkg_pmu = {
49362306a36Sopenharmony_ci	.attr_groups	= pkg_attr_groups,
49462306a36Sopenharmony_ci	.attr_update	= pkg_attr_update,
49562306a36Sopenharmony_ci	.name		= "cstate_pkg",
49662306a36Sopenharmony_ci	.task_ctx_nr	= perf_invalid_context,
49762306a36Sopenharmony_ci	.event_init	= cstate_pmu_event_init,
49862306a36Sopenharmony_ci	.add		= cstate_pmu_event_add,
49962306a36Sopenharmony_ci	.del		= cstate_pmu_event_del,
50062306a36Sopenharmony_ci	.start		= cstate_pmu_event_start,
50162306a36Sopenharmony_ci	.stop		= cstate_pmu_event_stop,
50262306a36Sopenharmony_ci	.read		= cstate_pmu_event_update,
50362306a36Sopenharmony_ci	.capabilities	= PERF_PMU_CAP_NO_INTERRUPT | PERF_PMU_CAP_NO_EXCLUDE,
50462306a36Sopenharmony_ci	.module		= THIS_MODULE,
50562306a36Sopenharmony_ci};
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_cistatic const struct cstate_model nhm_cstates __initconst = {
50862306a36Sopenharmony_ci	.core_events		= BIT(PERF_CSTATE_CORE_C3_RES) |
50962306a36Sopenharmony_ci				  BIT(PERF_CSTATE_CORE_C6_RES),
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci	.pkg_events		= BIT(PERF_CSTATE_PKG_C3_RES) |
51262306a36Sopenharmony_ci				  BIT(PERF_CSTATE_PKG_C6_RES) |
51362306a36Sopenharmony_ci				  BIT(PERF_CSTATE_PKG_C7_RES),
51462306a36Sopenharmony_ci};
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_cistatic const struct cstate_model snb_cstates __initconst = {
51762306a36Sopenharmony_ci	.core_events		= BIT(PERF_CSTATE_CORE_C3_RES) |
51862306a36Sopenharmony_ci				  BIT(PERF_CSTATE_CORE_C6_RES) |
51962306a36Sopenharmony_ci				  BIT(PERF_CSTATE_CORE_C7_RES),
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci	.pkg_events		= BIT(PERF_CSTATE_PKG_C2_RES) |
52262306a36Sopenharmony_ci				  BIT(PERF_CSTATE_PKG_C3_RES) |
52362306a36Sopenharmony_ci				  BIT(PERF_CSTATE_PKG_C6_RES) |
52462306a36Sopenharmony_ci				  BIT(PERF_CSTATE_PKG_C7_RES),
52562306a36Sopenharmony_ci};
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_cistatic const struct cstate_model hswult_cstates __initconst = {
52862306a36Sopenharmony_ci	.core_events		= BIT(PERF_CSTATE_CORE_C3_RES) |
52962306a36Sopenharmony_ci				  BIT(PERF_CSTATE_CORE_C6_RES) |
53062306a36Sopenharmony_ci				  BIT(PERF_CSTATE_CORE_C7_RES),
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_ci	.pkg_events		= BIT(PERF_CSTATE_PKG_C2_RES) |
53362306a36Sopenharmony_ci				  BIT(PERF_CSTATE_PKG_C3_RES) |
53462306a36Sopenharmony_ci				  BIT(PERF_CSTATE_PKG_C6_RES) |
53562306a36Sopenharmony_ci				  BIT(PERF_CSTATE_PKG_C7_RES) |
53662306a36Sopenharmony_ci				  BIT(PERF_CSTATE_PKG_C8_RES) |
53762306a36Sopenharmony_ci				  BIT(PERF_CSTATE_PKG_C9_RES) |
53862306a36Sopenharmony_ci				  BIT(PERF_CSTATE_PKG_C10_RES),
53962306a36Sopenharmony_ci};
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_cistatic const struct cstate_model cnl_cstates __initconst = {
54262306a36Sopenharmony_ci	.core_events		= BIT(PERF_CSTATE_CORE_C1_RES) |
54362306a36Sopenharmony_ci				  BIT(PERF_CSTATE_CORE_C3_RES) |
54462306a36Sopenharmony_ci				  BIT(PERF_CSTATE_CORE_C6_RES) |
54562306a36Sopenharmony_ci				  BIT(PERF_CSTATE_CORE_C7_RES),
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ci	.pkg_events		= BIT(PERF_CSTATE_PKG_C2_RES) |
54862306a36Sopenharmony_ci				  BIT(PERF_CSTATE_PKG_C3_RES) |
54962306a36Sopenharmony_ci				  BIT(PERF_CSTATE_PKG_C6_RES) |
55062306a36Sopenharmony_ci				  BIT(PERF_CSTATE_PKG_C7_RES) |
55162306a36Sopenharmony_ci				  BIT(PERF_CSTATE_PKG_C8_RES) |
55262306a36Sopenharmony_ci				  BIT(PERF_CSTATE_PKG_C9_RES) |
55362306a36Sopenharmony_ci				  BIT(PERF_CSTATE_PKG_C10_RES),
55462306a36Sopenharmony_ci};
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_cistatic const struct cstate_model icl_cstates __initconst = {
55762306a36Sopenharmony_ci	.core_events		= BIT(PERF_CSTATE_CORE_C6_RES) |
55862306a36Sopenharmony_ci				  BIT(PERF_CSTATE_CORE_C7_RES),
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_ci	.pkg_events		= BIT(PERF_CSTATE_PKG_C2_RES) |
56162306a36Sopenharmony_ci				  BIT(PERF_CSTATE_PKG_C3_RES) |
56262306a36Sopenharmony_ci				  BIT(PERF_CSTATE_PKG_C6_RES) |
56362306a36Sopenharmony_ci				  BIT(PERF_CSTATE_PKG_C7_RES) |
56462306a36Sopenharmony_ci				  BIT(PERF_CSTATE_PKG_C8_RES) |
56562306a36Sopenharmony_ci				  BIT(PERF_CSTATE_PKG_C9_RES) |
56662306a36Sopenharmony_ci				  BIT(PERF_CSTATE_PKG_C10_RES),
56762306a36Sopenharmony_ci};
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_cistatic const struct cstate_model icx_cstates __initconst = {
57062306a36Sopenharmony_ci	.core_events		= BIT(PERF_CSTATE_CORE_C1_RES) |
57162306a36Sopenharmony_ci				  BIT(PERF_CSTATE_CORE_C6_RES),
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci	.pkg_events		= BIT(PERF_CSTATE_PKG_C2_RES) |
57462306a36Sopenharmony_ci				  BIT(PERF_CSTATE_PKG_C6_RES),
57562306a36Sopenharmony_ci};
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_cistatic const struct cstate_model adl_cstates __initconst = {
57862306a36Sopenharmony_ci	.core_events		= BIT(PERF_CSTATE_CORE_C1_RES) |
57962306a36Sopenharmony_ci				  BIT(PERF_CSTATE_CORE_C6_RES) |
58062306a36Sopenharmony_ci				  BIT(PERF_CSTATE_CORE_C7_RES),
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_ci	.pkg_events		= BIT(PERF_CSTATE_PKG_C2_RES) |
58362306a36Sopenharmony_ci				  BIT(PERF_CSTATE_PKG_C3_RES) |
58462306a36Sopenharmony_ci				  BIT(PERF_CSTATE_PKG_C6_RES) |
58562306a36Sopenharmony_ci				  BIT(PERF_CSTATE_PKG_C7_RES) |
58662306a36Sopenharmony_ci				  BIT(PERF_CSTATE_PKG_C8_RES) |
58762306a36Sopenharmony_ci				  BIT(PERF_CSTATE_PKG_C9_RES) |
58862306a36Sopenharmony_ci				  BIT(PERF_CSTATE_PKG_C10_RES),
58962306a36Sopenharmony_ci};
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_cistatic const struct cstate_model slm_cstates __initconst = {
59262306a36Sopenharmony_ci	.core_events		= BIT(PERF_CSTATE_CORE_C1_RES) |
59362306a36Sopenharmony_ci				  BIT(PERF_CSTATE_CORE_C6_RES),
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_ci	.pkg_events		= BIT(PERF_CSTATE_PKG_C6_RES),
59662306a36Sopenharmony_ci	.quirks			= SLM_PKG_C6_USE_C7_MSR,
59762306a36Sopenharmony_ci};
59862306a36Sopenharmony_ci
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_cistatic const struct cstate_model knl_cstates __initconst = {
60162306a36Sopenharmony_ci	.core_events		= BIT(PERF_CSTATE_CORE_C6_RES),
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_ci	.pkg_events		= BIT(PERF_CSTATE_PKG_C2_RES) |
60462306a36Sopenharmony_ci				  BIT(PERF_CSTATE_PKG_C3_RES) |
60562306a36Sopenharmony_ci				  BIT(PERF_CSTATE_PKG_C6_RES),
60662306a36Sopenharmony_ci	.quirks			= KNL_CORE_C6_MSR,
60762306a36Sopenharmony_ci};
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_cistatic const struct cstate_model glm_cstates __initconst = {
61162306a36Sopenharmony_ci	.core_events		= BIT(PERF_CSTATE_CORE_C1_RES) |
61262306a36Sopenharmony_ci				  BIT(PERF_CSTATE_CORE_C3_RES) |
61362306a36Sopenharmony_ci				  BIT(PERF_CSTATE_CORE_C6_RES),
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_ci	.pkg_events		= BIT(PERF_CSTATE_PKG_C2_RES) |
61662306a36Sopenharmony_ci				  BIT(PERF_CSTATE_PKG_C3_RES) |
61762306a36Sopenharmony_ci				  BIT(PERF_CSTATE_PKG_C6_RES) |
61862306a36Sopenharmony_ci				  BIT(PERF_CSTATE_PKG_C10_RES),
61962306a36Sopenharmony_ci};
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_cistatic const struct x86_cpu_id intel_cstates_match[] __initconst = {
62362306a36Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(NEHALEM,		&nhm_cstates),
62462306a36Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(NEHALEM_EP,		&nhm_cstates),
62562306a36Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(NEHALEM_EX,		&nhm_cstates),
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(WESTMERE,		&nhm_cstates),
62862306a36Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(WESTMERE_EP,		&nhm_cstates),
62962306a36Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(WESTMERE_EX,		&nhm_cstates),
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(SANDYBRIDGE,		&snb_cstates),
63262306a36Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(SANDYBRIDGE_X,	&snb_cstates),
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(IVYBRIDGE,		&snb_cstates),
63562306a36Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(IVYBRIDGE_X,		&snb_cstates),
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(HASWELL,		&snb_cstates),
63862306a36Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(HASWELL_X,		&snb_cstates),
63962306a36Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(HASWELL_G,		&snb_cstates),
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(HASWELL_L,		&hswult_cstates),
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(ATOM_SILVERMONT,	&slm_cstates),
64462306a36Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(ATOM_SILVERMONT_D,	&slm_cstates),
64562306a36Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(ATOM_AIRMONT,	&slm_cstates),
64662306a36Sopenharmony_ci
64762306a36Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(BROADWELL,		&snb_cstates),
64862306a36Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(BROADWELL_D,		&snb_cstates),
64962306a36Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(BROADWELL_G,		&snb_cstates),
65062306a36Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(BROADWELL_X,		&snb_cstates),
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE_L,		&snb_cstates),
65362306a36Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE,		&snb_cstates),
65462306a36Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE_X,		&snb_cstates),
65562306a36Sopenharmony_ci
65662306a36Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(KABYLAKE_L,		&hswult_cstates),
65762306a36Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(KABYLAKE,		&hswult_cstates),
65862306a36Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(COMETLAKE_L,		&hswult_cstates),
65962306a36Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(COMETLAKE,		&hswult_cstates),
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(CANNONLAKE_L,	&cnl_cstates),
66262306a36Sopenharmony_ci
66362306a36Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(XEON_PHI_KNL,	&knl_cstates),
66462306a36Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(XEON_PHI_KNM,	&knl_cstates),
66562306a36Sopenharmony_ci
66662306a36Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(ATOM_GOLDMONT,	&glm_cstates),
66762306a36Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(ATOM_GOLDMONT_D,	&glm_cstates),
66862306a36Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(ATOM_GOLDMONT_PLUS,	&glm_cstates),
66962306a36Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(ATOM_TREMONT_D,	&glm_cstates),
67062306a36Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(ATOM_TREMONT,	&glm_cstates),
67162306a36Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(ATOM_TREMONT_L,	&glm_cstates),
67262306a36Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(ATOM_GRACEMONT,	&adl_cstates),
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_L,		&icl_cstates),
67562306a36Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(ICELAKE,		&icl_cstates),
67662306a36Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_X,		&icx_cstates),
67762306a36Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_D,		&icx_cstates),
67862306a36Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(SAPPHIRERAPIDS_X,	&icx_cstates),
67962306a36Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(EMERALDRAPIDS_X,	&icx_cstates),
68062306a36Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(GRANITERAPIDS_X,	&icx_cstates),
68162306a36Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(GRANITERAPIDS_D,	&icx_cstates),
68262306a36Sopenharmony_ci
68362306a36Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(TIGERLAKE_L,		&icl_cstates),
68462306a36Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(TIGERLAKE,		&icl_cstates),
68562306a36Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(ROCKETLAKE,		&icl_cstates),
68662306a36Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(ALDERLAKE,		&adl_cstates),
68762306a36Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(ALDERLAKE_L,		&adl_cstates),
68862306a36Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(RAPTORLAKE,		&adl_cstates),
68962306a36Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(RAPTORLAKE_P,	&adl_cstates),
69062306a36Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(RAPTORLAKE_S,	&adl_cstates),
69162306a36Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(METEORLAKE,		&adl_cstates),
69262306a36Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(METEORLAKE_L,	&adl_cstates),
69362306a36Sopenharmony_ci	{ },
69462306a36Sopenharmony_ci};
69562306a36Sopenharmony_ciMODULE_DEVICE_TABLE(x86cpu, intel_cstates_match);
69662306a36Sopenharmony_ci
69762306a36Sopenharmony_cistatic int __init cstate_probe(const struct cstate_model *cm)
69862306a36Sopenharmony_ci{
69962306a36Sopenharmony_ci	/* SLM has different MSR for PKG C6 */
70062306a36Sopenharmony_ci	if (cm->quirks & SLM_PKG_C6_USE_C7_MSR)
70162306a36Sopenharmony_ci		pkg_msr[PERF_CSTATE_PKG_C6_RES].msr = MSR_PKG_C7_RESIDENCY;
70262306a36Sopenharmony_ci
70362306a36Sopenharmony_ci	/* KNL has different MSR for CORE C6 */
70462306a36Sopenharmony_ci	if (cm->quirks & KNL_CORE_C6_MSR)
70562306a36Sopenharmony_ci		pkg_msr[PERF_CSTATE_CORE_C6_RES].msr = MSR_KNL_CORE_C6_RESIDENCY;
70662306a36Sopenharmony_ci
70762306a36Sopenharmony_ci
70862306a36Sopenharmony_ci	core_msr_mask = perf_msr_probe(core_msr, PERF_CSTATE_CORE_EVENT_MAX,
70962306a36Sopenharmony_ci				       true, (void *) &cm->core_events);
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_ci	pkg_msr_mask = perf_msr_probe(pkg_msr, PERF_CSTATE_PKG_EVENT_MAX,
71262306a36Sopenharmony_ci				      true, (void *) &cm->pkg_events);
71362306a36Sopenharmony_ci
71462306a36Sopenharmony_ci	has_cstate_core = !!core_msr_mask;
71562306a36Sopenharmony_ci	has_cstate_pkg  = !!pkg_msr_mask;
71662306a36Sopenharmony_ci
71762306a36Sopenharmony_ci	return (has_cstate_core || has_cstate_pkg) ? 0 : -ENODEV;
71862306a36Sopenharmony_ci}
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_cistatic inline void cstate_cleanup(void)
72162306a36Sopenharmony_ci{
72262306a36Sopenharmony_ci	cpuhp_remove_state_nocalls(CPUHP_AP_PERF_X86_CSTATE_ONLINE);
72362306a36Sopenharmony_ci	cpuhp_remove_state_nocalls(CPUHP_AP_PERF_X86_CSTATE_STARTING);
72462306a36Sopenharmony_ci
72562306a36Sopenharmony_ci	if (has_cstate_core)
72662306a36Sopenharmony_ci		perf_pmu_unregister(&cstate_core_pmu);
72762306a36Sopenharmony_ci
72862306a36Sopenharmony_ci	if (has_cstate_pkg)
72962306a36Sopenharmony_ci		perf_pmu_unregister(&cstate_pkg_pmu);
73062306a36Sopenharmony_ci}
73162306a36Sopenharmony_ci
73262306a36Sopenharmony_cistatic int __init cstate_init(void)
73362306a36Sopenharmony_ci{
73462306a36Sopenharmony_ci	int err;
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_ci	cpuhp_setup_state(CPUHP_AP_PERF_X86_CSTATE_STARTING,
73762306a36Sopenharmony_ci			  "perf/x86/cstate:starting", cstate_cpu_init, NULL);
73862306a36Sopenharmony_ci	cpuhp_setup_state(CPUHP_AP_PERF_X86_CSTATE_ONLINE,
73962306a36Sopenharmony_ci			  "perf/x86/cstate:online", NULL, cstate_cpu_exit);
74062306a36Sopenharmony_ci
74162306a36Sopenharmony_ci	if (has_cstate_core) {
74262306a36Sopenharmony_ci		err = perf_pmu_register(&cstate_core_pmu, cstate_core_pmu.name, -1);
74362306a36Sopenharmony_ci		if (err) {
74462306a36Sopenharmony_ci			has_cstate_core = false;
74562306a36Sopenharmony_ci			pr_info("Failed to register cstate core pmu\n");
74662306a36Sopenharmony_ci			cstate_cleanup();
74762306a36Sopenharmony_ci			return err;
74862306a36Sopenharmony_ci		}
74962306a36Sopenharmony_ci	}
75062306a36Sopenharmony_ci
75162306a36Sopenharmony_ci	if (has_cstate_pkg) {
75262306a36Sopenharmony_ci		if (topology_max_die_per_package() > 1) {
75362306a36Sopenharmony_ci			err = perf_pmu_register(&cstate_pkg_pmu,
75462306a36Sopenharmony_ci						"cstate_die", -1);
75562306a36Sopenharmony_ci		} else {
75662306a36Sopenharmony_ci			err = perf_pmu_register(&cstate_pkg_pmu,
75762306a36Sopenharmony_ci						cstate_pkg_pmu.name, -1);
75862306a36Sopenharmony_ci		}
75962306a36Sopenharmony_ci		if (err) {
76062306a36Sopenharmony_ci			has_cstate_pkg = false;
76162306a36Sopenharmony_ci			pr_info("Failed to register cstate pkg pmu\n");
76262306a36Sopenharmony_ci			cstate_cleanup();
76362306a36Sopenharmony_ci			return err;
76462306a36Sopenharmony_ci		}
76562306a36Sopenharmony_ci	}
76662306a36Sopenharmony_ci	return 0;
76762306a36Sopenharmony_ci}
76862306a36Sopenharmony_ci
76962306a36Sopenharmony_cistatic int __init cstate_pmu_init(void)
77062306a36Sopenharmony_ci{
77162306a36Sopenharmony_ci	const struct x86_cpu_id *id;
77262306a36Sopenharmony_ci	int err;
77362306a36Sopenharmony_ci
77462306a36Sopenharmony_ci	if (boot_cpu_has(X86_FEATURE_HYPERVISOR))
77562306a36Sopenharmony_ci		return -ENODEV;
77662306a36Sopenharmony_ci
77762306a36Sopenharmony_ci	id = x86_match_cpu(intel_cstates_match);
77862306a36Sopenharmony_ci	if (!id)
77962306a36Sopenharmony_ci		return -ENODEV;
78062306a36Sopenharmony_ci
78162306a36Sopenharmony_ci	err = cstate_probe((const struct cstate_model *) id->driver_data);
78262306a36Sopenharmony_ci	if (err)
78362306a36Sopenharmony_ci		return err;
78462306a36Sopenharmony_ci
78562306a36Sopenharmony_ci	return cstate_init();
78662306a36Sopenharmony_ci}
78762306a36Sopenharmony_cimodule_init(cstate_pmu_init);
78862306a36Sopenharmony_ci
78962306a36Sopenharmony_cistatic void __exit cstate_pmu_exit(void)
79062306a36Sopenharmony_ci{
79162306a36Sopenharmony_ci	cstate_cleanup();
79262306a36Sopenharmony_ci}
79362306a36Sopenharmony_cimodule_exit(cstate_pmu_exit);
794