18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * Support cstate residency counters
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Copyright (C) 2015, Intel Corp.
58c2ecf20Sopenharmony_ci * Author: Kan Liang (kan.liang@intel.com)
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * This library is free software; you can redistribute it and/or
88c2ecf20Sopenharmony_ci * modify it under the terms of the GNU Library General Public
98c2ecf20Sopenharmony_ci * License as published by the Free Software Foundation; either
108c2ecf20Sopenharmony_ci * version 2 of the License, or (at your option) any later version.
118c2ecf20Sopenharmony_ci *
128c2ecf20Sopenharmony_ci * This library is distributed in the hope that it will be useful,
138c2ecf20Sopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of
148c2ecf20Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
158c2ecf20Sopenharmony_ci * Library General Public License for more details.
168c2ecf20Sopenharmony_ci *
178c2ecf20Sopenharmony_ci */
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci/*
208c2ecf20Sopenharmony_ci * This file export cstate related free running (read-only) counters
218c2ecf20Sopenharmony_ci * for perf. These counters may be use simultaneously by other tools,
228c2ecf20Sopenharmony_ci * such as turbostat. However, it still make sense to implement them
238c2ecf20Sopenharmony_ci * in perf. Because we can conveniently collect them together with
248c2ecf20Sopenharmony_ci * other events, and allow to use them from tools without special MSR
258c2ecf20Sopenharmony_ci * access code.
268c2ecf20Sopenharmony_ci *
278c2ecf20Sopenharmony_ci * The events only support system-wide mode counting. There is no
288c2ecf20Sopenharmony_ci * sampling support because it is not supported by the hardware.
298c2ecf20Sopenharmony_ci *
308c2ecf20Sopenharmony_ci * According to counters' scope and category, two PMUs are registered
318c2ecf20Sopenharmony_ci * with the perf_event core subsystem.
328c2ecf20Sopenharmony_ci *  - 'cstate_core': The counter is available for each physical core.
338c2ecf20Sopenharmony_ci *    The counters include CORE_C*_RESIDENCY.
348c2ecf20Sopenharmony_ci *  - 'cstate_pkg': The counter is available for each physical package.
358c2ecf20Sopenharmony_ci *    The counters include PKG_C*_RESIDENCY.
368c2ecf20Sopenharmony_ci *
378c2ecf20Sopenharmony_ci * All of these counters are specified in the Intel® 64 and IA-32
388c2ecf20Sopenharmony_ci * Architectures Software Developer.s Manual Vol3b.
398c2ecf20Sopenharmony_ci *
408c2ecf20Sopenharmony_ci * Model specific counters:
418c2ecf20Sopenharmony_ci *	MSR_CORE_C1_RES: CORE C1 Residency Counter
428c2ecf20Sopenharmony_ci *			 perf code: 0x00
438c2ecf20Sopenharmony_ci *			 Available model: SLM,AMT,GLM,CNL,TNT
448c2ecf20Sopenharmony_ci *			 Scope: Core (each processor core has a MSR)
458c2ecf20Sopenharmony_ci *	MSR_CORE_C3_RESIDENCY: CORE C3 Residency Counter
468c2ecf20Sopenharmony_ci *			       perf code: 0x01
478c2ecf20Sopenharmony_ci *			       Available model: NHM,WSM,SNB,IVB,HSW,BDW,SKL,GLM,
488c2ecf20Sopenharmony_ci *						CNL,KBL,CML,TNT
498c2ecf20Sopenharmony_ci *			       Scope: Core
508c2ecf20Sopenharmony_ci *	MSR_CORE_C6_RESIDENCY: CORE C6 Residency Counter
518c2ecf20Sopenharmony_ci *			       perf code: 0x02
528c2ecf20Sopenharmony_ci *			       Available model: SLM,AMT,NHM,WSM,SNB,IVB,HSW,BDW,
538c2ecf20Sopenharmony_ci *						SKL,KNL,GLM,CNL,KBL,CML,ICL,TGL,
548c2ecf20Sopenharmony_ci *						TNT
558c2ecf20Sopenharmony_ci *			       Scope: Core
568c2ecf20Sopenharmony_ci *	MSR_CORE_C7_RESIDENCY: CORE C7 Residency Counter
578c2ecf20Sopenharmony_ci *			       perf code: 0x03
588c2ecf20Sopenharmony_ci *			       Available model: SNB,IVB,HSW,BDW,SKL,CNL,KBL,CML,
598c2ecf20Sopenharmony_ci *						ICL,TGL
608c2ecf20Sopenharmony_ci *			       Scope: Core
618c2ecf20Sopenharmony_ci *	MSR_PKG_C2_RESIDENCY:  Package C2 Residency Counter.
628c2ecf20Sopenharmony_ci *			       perf code: 0x00
638c2ecf20Sopenharmony_ci *			       Available model: SNB,IVB,HSW,BDW,SKL,KNL,GLM,CNL,
648c2ecf20Sopenharmony_ci *						KBL,CML,ICL,TGL,TNT
658c2ecf20Sopenharmony_ci *			       Scope: Package (physical package)
668c2ecf20Sopenharmony_ci *	MSR_PKG_C3_RESIDENCY:  Package C3 Residency Counter.
678c2ecf20Sopenharmony_ci *			       perf code: 0x01
688c2ecf20Sopenharmony_ci *			       Available model: NHM,WSM,SNB,IVB,HSW,BDW,SKL,KNL,
698c2ecf20Sopenharmony_ci *						GLM,CNL,KBL,CML,ICL,TGL,TNT
708c2ecf20Sopenharmony_ci *			       Scope: Package (physical package)
718c2ecf20Sopenharmony_ci *	MSR_PKG_C6_RESIDENCY:  Package C6 Residency Counter.
728c2ecf20Sopenharmony_ci *			       perf code: 0x02
738c2ecf20Sopenharmony_ci *			       Available model: SLM,AMT,NHM,WSM,SNB,IVB,HSW,BDW,
748c2ecf20Sopenharmony_ci *						SKL,KNL,GLM,CNL,KBL,CML,ICL,TGL,
758c2ecf20Sopenharmony_ci *						TNT
768c2ecf20Sopenharmony_ci *			       Scope: Package (physical package)
778c2ecf20Sopenharmony_ci *	MSR_PKG_C7_RESIDENCY:  Package C7 Residency Counter.
788c2ecf20Sopenharmony_ci *			       perf code: 0x03
798c2ecf20Sopenharmony_ci *			       Available model: NHM,WSM,SNB,IVB,HSW,BDW,SKL,CNL,
808c2ecf20Sopenharmony_ci *						KBL,CML,ICL,TGL
818c2ecf20Sopenharmony_ci *			       Scope: Package (physical package)
828c2ecf20Sopenharmony_ci *	MSR_PKG_C8_RESIDENCY:  Package C8 Residency Counter.
838c2ecf20Sopenharmony_ci *			       perf code: 0x04
848c2ecf20Sopenharmony_ci *			       Available model: HSW ULT,KBL,CNL,CML,ICL,TGL
858c2ecf20Sopenharmony_ci *			       Scope: Package (physical package)
868c2ecf20Sopenharmony_ci *	MSR_PKG_C9_RESIDENCY:  Package C9 Residency Counter.
878c2ecf20Sopenharmony_ci *			       perf code: 0x05
888c2ecf20Sopenharmony_ci *			       Available model: HSW ULT,KBL,CNL,CML,ICL,TGL
898c2ecf20Sopenharmony_ci *			       Scope: Package (physical package)
908c2ecf20Sopenharmony_ci *	MSR_PKG_C10_RESIDENCY: Package C10 Residency Counter.
918c2ecf20Sopenharmony_ci *			       perf code: 0x06
928c2ecf20Sopenharmony_ci *			       Available model: HSW ULT,KBL,GLM,CNL,CML,ICL,TGL,
938c2ecf20Sopenharmony_ci *						TNT
948c2ecf20Sopenharmony_ci *			       Scope: Package (physical package)
958c2ecf20Sopenharmony_ci *
968c2ecf20Sopenharmony_ci */
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci#include <linux/module.h>
998c2ecf20Sopenharmony_ci#include <linux/slab.h>
1008c2ecf20Sopenharmony_ci#include <linux/perf_event.h>
1018c2ecf20Sopenharmony_ci#include <linux/nospec.h>
1028c2ecf20Sopenharmony_ci#include <asm/cpu_device_id.h>
1038c2ecf20Sopenharmony_ci#include <asm/intel-family.h>
1048c2ecf20Sopenharmony_ci#include "../perf_event.h"
1058c2ecf20Sopenharmony_ci#include "../probe.h"
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci#define DEFINE_CSTATE_FORMAT_ATTR(_var, _name, _format)		\
1108c2ecf20Sopenharmony_cistatic ssize_t __cstate_##_var##_show(struct device *dev,	\
1118c2ecf20Sopenharmony_ci				struct device_attribute *attr,	\
1128c2ecf20Sopenharmony_ci				char *page)			\
1138c2ecf20Sopenharmony_ci{								\
1148c2ecf20Sopenharmony_ci	BUILD_BUG_ON(sizeof(_format) >= PAGE_SIZE);		\
1158c2ecf20Sopenharmony_ci	return sprintf(page, _format "\n");			\
1168c2ecf20Sopenharmony_ci}								\
1178c2ecf20Sopenharmony_cistatic struct device_attribute format_attr_##_var =		\
1188c2ecf20Sopenharmony_ci	__ATTR(_name, 0444, __cstate_##_var##_show, NULL)
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_cistatic ssize_t cstate_get_attr_cpumask(struct device *dev,
1218c2ecf20Sopenharmony_ci				       struct device_attribute *attr,
1228c2ecf20Sopenharmony_ci				       char *buf);
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci/* Model -> events mapping */
1258c2ecf20Sopenharmony_cistruct cstate_model {
1268c2ecf20Sopenharmony_ci	unsigned long		core_events;
1278c2ecf20Sopenharmony_ci	unsigned long		pkg_events;
1288c2ecf20Sopenharmony_ci	unsigned long		quirks;
1298c2ecf20Sopenharmony_ci};
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci/* Quirk flags */
1328c2ecf20Sopenharmony_ci#define SLM_PKG_C6_USE_C7_MSR	(1UL << 0)
1338c2ecf20Sopenharmony_ci#define KNL_CORE_C6_MSR		(1UL << 1)
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_cistruct perf_cstate_msr {
1368c2ecf20Sopenharmony_ci	u64	msr;
1378c2ecf20Sopenharmony_ci	struct	perf_pmu_events_attr *attr;
1388c2ecf20Sopenharmony_ci};
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci/* cstate_core PMU */
1428c2ecf20Sopenharmony_cistatic struct pmu cstate_core_pmu;
1438c2ecf20Sopenharmony_cistatic bool has_cstate_core;
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_cienum perf_cstate_core_events {
1468c2ecf20Sopenharmony_ci	PERF_CSTATE_CORE_C1_RES = 0,
1478c2ecf20Sopenharmony_ci	PERF_CSTATE_CORE_C3_RES,
1488c2ecf20Sopenharmony_ci	PERF_CSTATE_CORE_C6_RES,
1498c2ecf20Sopenharmony_ci	PERF_CSTATE_CORE_C7_RES,
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci	PERF_CSTATE_CORE_EVENT_MAX,
1528c2ecf20Sopenharmony_ci};
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ciPMU_EVENT_ATTR_STRING(c1-residency, attr_cstate_core_c1, "event=0x00");
1558c2ecf20Sopenharmony_ciPMU_EVENT_ATTR_STRING(c3-residency, attr_cstate_core_c3, "event=0x01");
1568c2ecf20Sopenharmony_ciPMU_EVENT_ATTR_STRING(c6-residency, attr_cstate_core_c6, "event=0x02");
1578c2ecf20Sopenharmony_ciPMU_EVENT_ATTR_STRING(c7-residency, attr_cstate_core_c7, "event=0x03");
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_cistatic unsigned long core_msr_mask;
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ciPMU_EVENT_GROUP(events, cstate_core_c1);
1628c2ecf20Sopenharmony_ciPMU_EVENT_GROUP(events, cstate_core_c3);
1638c2ecf20Sopenharmony_ciPMU_EVENT_GROUP(events, cstate_core_c6);
1648c2ecf20Sopenharmony_ciPMU_EVENT_GROUP(events, cstate_core_c7);
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_cistatic bool test_msr(int idx, void *data)
1678c2ecf20Sopenharmony_ci{
1688c2ecf20Sopenharmony_ci	return test_bit(idx, (unsigned long *) data);
1698c2ecf20Sopenharmony_ci}
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_cistatic struct perf_msr core_msr[] = {
1728c2ecf20Sopenharmony_ci	[PERF_CSTATE_CORE_C1_RES] = { MSR_CORE_C1_RES,		&group_cstate_core_c1,	test_msr },
1738c2ecf20Sopenharmony_ci	[PERF_CSTATE_CORE_C3_RES] = { MSR_CORE_C3_RESIDENCY,	&group_cstate_core_c3,	test_msr },
1748c2ecf20Sopenharmony_ci	[PERF_CSTATE_CORE_C6_RES] = { MSR_CORE_C6_RESIDENCY,	&group_cstate_core_c6,	test_msr },
1758c2ecf20Sopenharmony_ci	[PERF_CSTATE_CORE_C7_RES] = { MSR_CORE_C7_RESIDENCY,	&group_cstate_core_c7,	test_msr },
1768c2ecf20Sopenharmony_ci};
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_cistatic struct attribute *attrs_empty[] = {
1798c2ecf20Sopenharmony_ci	NULL,
1808c2ecf20Sopenharmony_ci};
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci/*
1838c2ecf20Sopenharmony_ci * There are no default events, but we need to create
1848c2ecf20Sopenharmony_ci * "events" group (with empty attrs) before updating
1858c2ecf20Sopenharmony_ci * it with detected events.
1868c2ecf20Sopenharmony_ci */
1878c2ecf20Sopenharmony_cistatic struct attribute_group core_events_attr_group = {
1888c2ecf20Sopenharmony_ci	.name = "events",
1898c2ecf20Sopenharmony_ci	.attrs = attrs_empty,
1908c2ecf20Sopenharmony_ci};
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ciDEFINE_CSTATE_FORMAT_ATTR(core_event, event, "config:0-63");
1938c2ecf20Sopenharmony_cistatic struct attribute *core_format_attrs[] = {
1948c2ecf20Sopenharmony_ci	&format_attr_core_event.attr,
1958c2ecf20Sopenharmony_ci	NULL,
1968c2ecf20Sopenharmony_ci};
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_cistatic struct attribute_group core_format_attr_group = {
1998c2ecf20Sopenharmony_ci	.name = "format",
2008c2ecf20Sopenharmony_ci	.attrs = core_format_attrs,
2018c2ecf20Sopenharmony_ci};
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_cistatic cpumask_t cstate_core_cpu_mask;
2048c2ecf20Sopenharmony_cistatic DEVICE_ATTR(cpumask, S_IRUGO, cstate_get_attr_cpumask, NULL);
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_cistatic struct attribute *cstate_cpumask_attrs[] = {
2078c2ecf20Sopenharmony_ci	&dev_attr_cpumask.attr,
2088c2ecf20Sopenharmony_ci	NULL,
2098c2ecf20Sopenharmony_ci};
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_cistatic struct attribute_group cpumask_attr_group = {
2128c2ecf20Sopenharmony_ci	.attrs = cstate_cpumask_attrs,
2138c2ecf20Sopenharmony_ci};
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_cistatic const struct attribute_group *core_attr_groups[] = {
2168c2ecf20Sopenharmony_ci	&core_events_attr_group,
2178c2ecf20Sopenharmony_ci	&core_format_attr_group,
2188c2ecf20Sopenharmony_ci	&cpumask_attr_group,
2198c2ecf20Sopenharmony_ci	NULL,
2208c2ecf20Sopenharmony_ci};
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci/* cstate_pkg PMU */
2238c2ecf20Sopenharmony_cistatic struct pmu cstate_pkg_pmu;
2248c2ecf20Sopenharmony_cistatic bool has_cstate_pkg;
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_cienum perf_cstate_pkg_events {
2278c2ecf20Sopenharmony_ci	PERF_CSTATE_PKG_C2_RES = 0,
2288c2ecf20Sopenharmony_ci	PERF_CSTATE_PKG_C3_RES,
2298c2ecf20Sopenharmony_ci	PERF_CSTATE_PKG_C6_RES,
2308c2ecf20Sopenharmony_ci	PERF_CSTATE_PKG_C7_RES,
2318c2ecf20Sopenharmony_ci	PERF_CSTATE_PKG_C8_RES,
2328c2ecf20Sopenharmony_ci	PERF_CSTATE_PKG_C9_RES,
2338c2ecf20Sopenharmony_ci	PERF_CSTATE_PKG_C10_RES,
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci	PERF_CSTATE_PKG_EVENT_MAX,
2368c2ecf20Sopenharmony_ci};
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ciPMU_EVENT_ATTR_STRING(c2-residency,  attr_cstate_pkg_c2,  "event=0x00");
2398c2ecf20Sopenharmony_ciPMU_EVENT_ATTR_STRING(c3-residency,  attr_cstate_pkg_c3,  "event=0x01");
2408c2ecf20Sopenharmony_ciPMU_EVENT_ATTR_STRING(c6-residency,  attr_cstate_pkg_c6,  "event=0x02");
2418c2ecf20Sopenharmony_ciPMU_EVENT_ATTR_STRING(c7-residency,  attr_cstate_pkg_c7,  "event=0x03");
2428c2ecf20Sopenharmony_ciPMU_EVENT_ATTR_STRING(c8-residency,  attr_cstate_pkg_c8,  "event=0x04");
2438c2ecf20Sopenharmony_ciPMU_EVENT_ATTR_STRING(c9-residency,  attr_cstate_pkg_c9,  "event=0x05");
2448c2ecf20Sopenharmony_ciPMU_EVENT_ATTR_STRING(c10-residency, attr_cstate_pkg_c10, "event=0x06");
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_cistatic unsigned long pkg_msr_mask;
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ciPMU_EVENT_GROUP(events, cstate_pkg_c2);
2498c2ecf20Sopenharmony_ciPMU_EVENT_GROUP(events, cstate_pkg_c3);
2508c2ecf20Sopenharmony_ciPMU_EVENT_GROUP(events, cstate_pkg_c6);
2518c2ecf20Sopenharmony_ciPMU_EVENT_GROUP(events, cstate_pkg_c7);
2528c2ecf20Sopenharmony_ciPMU_EVENT_GROUP(events, cstate_pkg_c8);
2538c2ecf20Sopenharmony_ciPMU_EVENT_GROUP(events, cstate_pkg_c9);
2548c2ecf20Sopenharmony_ciPMU_EVENT_GROUP(events, cstate_pkg_c10);
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_cistatic struct perf_msr pkg_msr[] = {
2578c2ecf20Sopenharmony_ci	[PERF_CSTATE_PKG_C2_RES]  = { MSR_PKG_C2_RESIDENCY,	&group_cstate_pkg_c2,	test_msr },
2588c2ecf20Sopenharmony_ci	[PERF_CSTATE_PKG_C3_RES]  = { MSR_PKG_C3_RESIDENCY,	&group_cstate_pkg_c3,	test_msr },
2598c2ecf20Sopenharmony_ci	[PERF_CSTATE_PKG_C6_RES]  = { MSR_PKG_C6_RESIDENCY,	&group_cstate_pkg_c6,	test_msr },
2608c2ecf20Sopenharmony_ci	[PERF_CSTATE_PKG_C7_RES]  = { MSR_PKG_C7_RESIDENCY,	&group_cstate_pkg_c7,	test_msr },
2618c2ecf20Sopenharmony_ci	[PERF_CSTATE_PKG_C8_RES]  = { MSR_PKG_C8_RESIDENCY,	&group_cstate_pkg_c8,	test_msr },
2628c2ecf20Sopenharmony_ci	[PERF_CSTATE_PKG_C9_RES]  = { MSR_PKG_C9_RESIDENCY,	&group_cstate_pkg_c9,	test_msr },
2638c2ecf20Sopenharmony_ci	[PERF_CSTATE_PKG_C10_RES] = { MSR_PKG_C10_RESIDENCY,	&group_cstate_pkg_c10,	test_msr },
2648c2ecf20Sopenharmony_ci};
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_cistatic struct attribute_group pkg_events_attr_group = {
2678c2ecf20Sopenharmony_ci	.name = "events",
2688c2ecf20Sopenharmony_ci	.attrs = attrs_empty,
2698c2ecf20Sopenharmony_ci};
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ciDEFINE_CSTATE_FORMAT_ATTR(pkg_event, event, "config:0-63");
2728c2ecf20Sopenharmony_cistatic struct attribute *pkg_format_attrs[] = {
2738c2ecf20Sopenharmony_ci	&format_attr_pkg_event.attr,
2748c2ecf20Sopenharmony_ci	NULL,
2758c2ecf20Sopenharmony_ci};
2768c2ecf20Sopenharmony_cistatic struct attribute_group pkg_format_attr_group = {
2778c2ecf20Sopenharmony_ci	.name = "format",
2788c2ecf20Sopenharmony_ci	.attrs = pkg_format_attrs,
2798c2ecf20Sopenharmony_ci};
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_cistatic cpumask_t cstate_pkg_cpu_mask;
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_cistatic const struct attribute_group *pkg_attr_groups[] = {
2848c2ecf20Sopenharmony_ci	&pkg_events_attr_group,
2858c2ecf20Sopenharmony_ci	&pkg_format_attr_group,
2868c2ecf20Sopenharmony_ci	&cpumask_attr_group,
2878c2ecf20Sopenharmony_ci	NULL,
2888c2ecf20Sopenharmony_ci};
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_cistatic ssize_t cstate_get_attr_cpumask(struct device *dev,
2918c2ecf20Sopenharmony_ci				       struct device_attribute *attr,
2928c2ecf20Sopenharmony_ci				       char *buf)
2938c2ecf20Sopenharmony_ci{
2948c2ecf20Sopenharmony_ci	struct pmu *pmu = dev_get_drvdata(dev);
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci	if (pmu == &cstate_core_pmu)
2978c2ecf20Sopenharmony_ci		return cpumap_print_to_pagebuf(true, buf, &cstate_core_cpu_mask);
2988c2ecf20Sopenharmony_ci	else if (pmu == &cstate_pkg_pmu)
2998c2ecf20Sopenharmony_ci		return cpumap_print_to_pagebuf(true, buf, &cstate_pkg_cpu_mask);
3008c2ecf20Sopenharmony_ci	else
3018c2ecf20Sopenharmony_ci		return 0;
3028c2ecf20Sopenharmony_ci}
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_cistatic int cstate_pmu_event_init(struct perf_event *event)
3058c2ecf20Sopenharmony_ci{
3068c2ecf20Sopenharmony_ci	u64 cfg = event->attr.config;
3078c2ecf20Sopenharmony_ci	int cpu;
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci	if (event->attr.type != event->pmu->type)
3108c2ecf20Sopenharmony_ci		return -ENOENT;
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci	/* unsupported modes and filters */
3138c2ecf20Sopenharmony_ci	if (event->attr.sample_period) /* no sampling */
3148c2ecf20Sopenharmony_ci		return -EINVAL;
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci	if (event->cpu < 0)
3178c2ecf20Sopenharmony_ci		return -EINVAL;
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ci	if (event->pmu == &cstate_core_pmu) {
3208c2ecf20Sopenharmony_ci		if (cfg >= PERF_CSTATE_CORE_EVENT_MAX)
3218c2ecf20Sopenharmony_ci			return -EINVAL;
3228c2ecf20Sopenharmony_ci		cfg = array_index_nospec((unsigned long)cfg, PERF_CSTATE_CORE_EVENT_MAX);
3238c2ecf20Sopenharmony_ci		if (!(core_msr_mask & (1 << cfg)))
3248c2ecf20Sopenharmony_ci			return -EINVAL;
3258c2ecf20Sopenharmony_ci		event->hw.event_base = core_msr[cfg].msr;
3268c2ecf20Sopenharmony_ci		cpu = cpumask_any_and(&cstate_core_cpu_mask,
3278c2ecf20Sopenharmony_ci				      topology_sibling_cpumask(event->cpu));
3288c2ecf20Sopenharmony_ci	} else if (event->pmu == &cstate_pkg_pmu) {
3298c2ecf20Sopenharmony_ci		if (cfg >= PERF_CSTATE_PKG_EVENT_MAX)
3308c2ecf20Sopenharmony_ci			return -EINVAL;
3318c2ecf20Sopenharmony_ci		cfg = array_index_nospec((unsigned long)cfg, PERF_CSTATE_PKG_EVENT_MAX);
3328c2ecf20Sopenharmony_ci		if (!(pkg_msr_mask & (1 << cfg)))
3338c2ecf20Sopenharmony_ci			return -EINVAL;
3348c2ecf20Sopenharmony_ci		event->hw.event_base = pkg_msr[cfg].msr;
3358c2ecf20Sopenharmony_ci		cpu = cpumask_any_and(&cstate_pkg_cpu_mask,
3368c2ecf20Sopenharmony_ci				      topology_die_cpumask(event->cpu));
3378c2ecf20Sopenharmony_ci	} else {
3388c2ecf20Sopenharmony_ci		return -ENOENT;
3398c2ecf20Sopenharmony_ci	}
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_ci	if (cpu >= nr_cpu_ids)
3428c2ecf20Sopenharmony_ci		return -ENODEV;
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_ci	event->cpu = cpu;
3458c2ecf20Sopenharmony_ci	event->hw.config = cfg;
3468c2ecf20Sopenharmony_ci	event->hw.idx = -1;
3478c2ecf20Sopenharmony_ci	return 0;
3488c2ecf20Sopenharmony_ci}
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_cistatic inline u64 cstate_pmu_read_counter(struct perf_event *event)
3518c2ecf20Sopenharmony_ci{
3528c2ecf20Sopenharmony_ci	u64 val;
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_ci	rdmsrl(event->hw.event_base, val);
3558c2ecf20Sopenharmony_ci	return val;
3568c2ecf20Sopenharmony_ci}
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_cistatic void cstate_pmu_event_update(struct perf_event *event)
3598c2ecf20Sopenharmony_ci{
3608c2ecf20Sopenharmony_ci	struct hw_perf_event *hwc = &event->hw;
3618c2ecf20Sopenharmony_ci	u64 prev_raw_count, new_raw_count;
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ciagain:
3648c2ecf20Sopenharmony_ci	prev_raw_count = local64_read(&hwc->prev_count);
3658c2ecf20Sopenharmony_ci	new_raw_count = cstate_pmu_read_counter(event);
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ci	if (local64_cmpxchg(&hwc->prev_count, prev_raw_count,
3688c2ecf20Sopenharmony_ci			    new_raw_count) != prev_raw_count)
3698c2ecf20Sopenharmony_ci		goto again;
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_ci	local64_add(new_raw_count - prev_raw_count, &event->count);
3728c2ecf20Sopenharmony_ci}
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_cistatic void cstate_pmu_event_start(struct perf_event *event, int mode)
3758c2ecf20Sopenharmony_ci{
3768c2ecf20Sopenharmony_ci	local64_set(&event->hw.prev_count, cstate_pmu_read_counter(event));
3778c2ecf20Sopenharmony_ci}
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_cistatic void cstate_pmu_event_stop(struct perf_event *event, int mode)
3808c2ecf20Sopenharmony_ci{
3818c2ecf20Sopenharmony_ci	cstate_pmu_event_update(event);
3828c2ecf20Sopenharmony_ci}
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_cistatic void cstate_pmu_event_del(struct perf_event *event, int mode)
3858c2ecf20Sopenharmony_ci{
3868c2ecf20Sopenharmony_ci	cstate_pmu_event_stop(event, PERF_EF_UPDATE);
3878c2ecf20Sopenharmony_ci}
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_cistatic int cstate_pmu_event_add(struct perf_event *event, int mode)
3908c2ecf20Sopenharmony_ci{
3918c2ecf20Sopenharmony_ci	if (mode & PERF_EF_START)
3928c2ecf20Sopenharmony_ci		cstate_pmu_event_start(event, mode);
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_ci	return 0;
3958c2ecf20Sopenharmony_ci}
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_ci/*
3988c2ecf20Sopenharmony_ci * Check if exiting cpu is the designated reader. If so migrate the
3998c2ecf20Sopenharmony_ci * events when there is a valid target available
4008c2ecf20Sopenharmony_ci */
4018c2ecf20Sopenharmony_cistatic int cstate_cpu_exit(unsigned int cpu)
4028c2ecf20Sopenharmony_ci{
4038c2ecf20Sopenharmony_ci	unsigned int target;
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_ci	if (has_cstate_core &&
4068c2ecf20Sopenharmony_ci	    cpumask_test_and_clear_cpu(cpu, &cstate_core_cpu_mask)) {
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_ci		target = cpumask_any_but(topology_sibling_cpumask(cpu), cpu);
4098c2ecf20Sopenharmony_ci		/* Migrate events if there is a valid target */
4108c2ecf20Sopenharmony_ci		if (target < nr_cpu_ids) {
4118c2ecf20Sopenharmony_ci			cpumask_set_cpu(target, &cstate_core_cpu_mask);
4128c2ecf20Sopenharmony_ci			perf_pmu_migrate_context(&cstate_core_pmu, cpu, target);
4138c2ecf20Sopenharmony_ci		}
4148c2ecf20Sopenharmony_ci	}
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_ci	if (has_cstate_pkg &&
4178c2ecf20Sopenharmony_ci	    cpumask_test_and_clear_cpu(cpu, &cstate_pkg_cpu_mask)) {
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_ci		target = cpumask_any_but(topology_die_cpumask(cpu), cpu);
4208c2ecf20Sopenharmony_ci		/* Migrate events if there is a valid target */
4218c2ecf20Sopenharmony_ci		if (target < nr_cpu_ids) {
4228c2ecf20Sopenharmony_ci			cpumask_set_cpu(target, &cstate_pkg_cpu_mask);
4238c2ecf20Sopenharmony_ci			perf_pmu_migrate_context(&cstate_pkg_pmu, cpu, target);
4248c2ecf20Sopenharmony_ci		}
4258c2ecf20Sopenharmony_ci	}
4268c2ecf20Sopenharmony_ci	return 0;
4278c2ecf20Sopenharmony_ci}
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_cistatic int cstate_cpu_init(unsigned int cpu)
4308c2ecf20Sopenharmony_ci{
4318c2ecf20Sopenharmony_ci	unsigned int target;
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_ci	/*
4348c2ecf20Sopenharmony_ci	 * If this is the first online thread of that core, set it in
4358c2ecf20Sopenharmony_ci	 * the core cpu mask as the designated reader.
4368c2ecf20Sopenharmony_ci	 */
4378c2ecf20Sopenharmony_ci	target = cpumask_any_and(&cstate_core_cpu_mask,
4388c2ecf20Sopenharmony_ci				 topology_sibling_cpumask(cpu));
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_ci	if (has_cstate_core && target >= nr_cpu_ids)
4418c2ecf20Sopenharmony_ci		cpumask_set_cpu(cpu, &cstate_core_cpu_mask);
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_ci	/*
4448c2ecf20Sopenharmony_ci	 * If this is the first online thread of that package, set it
4458c2ecf20Sopenharmony_ci	 * in the package cpu mask as the designated reader.
4468c2ecf20Sopenharmony_ci	 */
4478c2ecf20Sopenharmony_ci	target = cpumask_any_and(&cstate_pkg_cpu_mask,
4488c2ecf20Sopenharmony_ci				 topology_die_cpumask(cpu));
4498c2ecf20Sopenharmony_ci	if (has_cstate_pkg && target >= nr_cpu_ids)
4508c2ecf20Sopenharmony_ci		cpumask_set_cpu(cpu, &cstate_pkg_cpu_mask);
4518c2ecf20Sopenharmony_ci
4528c2ecf20Sopenharmony_ci	return 0;
4538c2ecf20Sopenharmony_ci}
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_cistatic const struct attribute_group *core_attr_update[] = {
4568c2ecf20Sopenharmony_ci	&group_cstate_core_c1,
4578c2ecf20Sopenharmony_ci	&group_cstate_core_c3,
4588c2ecf20Sopenharmony_ci	&group_cstate_core_c6,
4598c2ecf20Sopenharmony_ci	&group_cstate_core_c7,
4608c2ecf20Sopenharmony_ci	NULL,
4618c2ecf20Sopenharmony_ci};
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_cistatic const struct attribute_group *pkg_attr_update[] = {
4648c2ecf20Sopenharmony_ci	&group_cstate_pkg_c2,
4658c2ecf20Sopenharmony_ci	&group_cstate_pkg_c3,
4668c2ecf20Sopenharmony_ci	&group_cstate_pkg_c6,
4678c2ecf20Sopenharmony_ci	&group_cstate_pkg_c7,
4688c2ecf20Sopenharmony_ci	&group_cstate_pkg_c8,
4698c2ecf20Sopenharmony_ci	&group_cstate_pkg_c9,
4708c2ecf20Sopenharmony_ci	&group_cstate_pkg_c10,
4718c2ecf20Sopenharmony_ci	NULL,
4728c2ecf20Sopenharmony_ci};
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_cistatic struct pmu cstate_core_pmu = {
4758c2ecf20Sopenharmony_ci	.attr_groups	= core_attr_groups,
4768c2ecf20Sopenharmony_ci	.attr_update	= core_attr_update,
4778c2ecf20Sopenharmony_ci	.name		= "cstate_core",
4788c2ecf20Sopenharmony_ci	.task_ctx_nr	= perf_invalid_context,
4798c2ecf20Sopenharmony_ci	.event_init	= cstate_pmu_event_init,
4808c2ecf20Sopenharmony_ci	.add		= cstate_pmu_event_add,
4818c2ecf20Sopenharmony_ci	.del		= cstate_pmu_event_del,
4828c2ecf20Sopenharmony_ci	.start		= cstate_pmu_event_start,
4838c2ecf20Sopenharmony_ci	.stop		= cstate_pmu_event_stop,
4848c2ecf20Sopenharmony_ci	.read		= cstate_pmu_event_update,
4858c2ecf20Sopenharmony_ci	.capabilities	= PERF_PMU_CAP_NO_INTERRUPT | PERF_PMU_CAP_NO_EXCLUDE,
4868c2ecf20Sopenharmony_ci	.module		= THIS_MODULE,
4878c2ecf20Sopenharmony_ci};
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_cistatic struct pmu cstate_pkg_pmu = {
4908c2ecf20Sopenharmony_ci	.attr_groups	= pkg_attr_groups,
4918c2ecf20Sopenharmony_ci	.attr_update	= pkg_attr_update,
4928c2ecf20Sopenharmony_ci	.name		= "cstate_pkg",
4938c2ecf20Sopenharmony_ci	.task_ctx_nr	= perf_invalid_context,
4948c2ecf20Sopenharmony_ci	.event_init	= cstate_pmu_event_init,
4958c2ecf20Sopenharmony_ci	.add		= cstate_pmu_event_add,
4968c2ecf20Sopenharmony_ci	.del		= cstate_pmu_event_del,
4978c2ecf20Sopenharmony_ci	.start		= cstate_pmu_event_start,
4988c2ecf20Sopenharmony_ci	.stop		= cstate_pmu_event_stop,
4998c2ecf20Sopenharmony_ci	.read		= cstate_pmu_event_update,
5008c2ecf20Sopenharmony_ci	.capabilities	= PERF_PMU_CAP_NO_INTERRUPT | PERF_PMU_CAP_NO_EXCLUDE,
5018c2ecf20Sopenharmony_ci	.module		= THIS_MODULE,
5028c2ecf20Sopenharmony_ci};
5038c2ecf20Sopenharmony_ci
5048c2ecf20Sopenharmony_cistatic const struct cstate_model nhm_cstates __initconst = {
5058c2ecf20Sopenharmony_ci	.core_events		= BIT(PERF_CSTATE_CORE_C3_RES) |
5068c2ecf20Sopenharmony_ci				  BIT(PERF_CSTATE_CORE_C6_RES),
5078c2ecf20Sopenharmony_ci
5088c2ecf20Sopenharmony_ci	.pkg_events		= BIT(PERF_CSTATE_PKG_C3_RES) |
5098c2ecf20Sopenharmony_ci				  BIT(PERF_CSTATE_PKG_C6_RES) |
5108c2ecf20Sopenharmony_ci				  BIT(PERF_CSTATE_PKG_C7_RES),
5118c2ecf20Sopenharmony_ci};
5128c2ecf20Sopenharmony_ci
5138c2ecf20Sopenharmony_cistatic const struct cstate_model snb_cstates __initconst = {
5148c2ecf20Sopenharmony_ci	.core_events		= BIT(PERF_CSTATE_CORE_C3_RES) |
5158c2ecf20Sopenharmony_ci				  BIT(PERF_CSTATE_CORE_C6_RES) |
5168c2ecf20Sopenharmony_ci				  BIT(PERF_CSTATE_CORE_C7_RES),
5178c2ecf20Sopenharmony_ci
5188c2ecf20Sopenharmony_ci	.pkg_events		= BIT(PERF_CSTATE_PKG_C2_RES) |
5198c2ecf20Sopenharmony_ci				  BIT(PERF_CSTATE_PKG_C3_RES) |
5208c2ecf20Sopenharmony_ci				  BIT(PERF_CSTATE_PKG_C6_RES) |
5218c2ecf20Sopenharmony_ci				  BIT(PERF_CSTATE_PKG_C7_RES),
5228c2ecf20Sopenharmony_ci};
5238c2ecf20Sopenharmony_ci
5248c2ecf20Sopenharmony_cistatic const struct cstate_model hswult_cstates __initconst = {
5258c2ecf20Sopenharmony_ci	.core_events		= BIT(PERF_CSTATE_CORE_C3_RES) |
5268c2ecf20Sopenharmony_ci				  BIT(PERF_CSTATE_CORE_C6_RES) |
5278c2ecf20Sopenharmony_ci				  BIT(PERF_CSTATE_CORE_C7_RES),
5288c2ecf20Sopenharmony_ci
5298c2ecf20Sopenharmony_ci	.pkg_events		= BIT(PERF_CSTATE_PKG_C2_RES) |
5308c2ecf20Sopenharmony_ci				  BIT(PERF_CSTATE_PKG_C3_RES) |
5318c2ecf20Sopenharmony_ci				  BIT(PERF_CSTATE_PKG_C6_RES) |
5328c2ecf20Sopenharmony_ci				  BIT(PERF_CSTATE_PKG_C7_RES) |
5338c2ecf20Sopenharmony_ci				  BIT(PERF_CSTATE_PKG_C8_RES) |
5348c2ecf20Sopenharmony_ci				  BIT(PERF_CSTATE_PKG_C9_RES) |
5358c2ecf20Sopenharmony_ci				  BIT(PERF_CSTATE_PKG_C10_RES),
5368c2ecf20Sopenharmony_ci};
5378c2ecf20Sopenharmony_ci
5388c2ecf20Sopenharmony_cistatic const struct cstate_model cnl_cstates __initconst = {
5398c2ecf20Sopenharmony_ci	.core_events		= BIT(PERF_CSTATE_CORE_C1_RES) |
5408c2ecf20Sopenharmony_ci				  BIT(PERF_CSTATE_CORE_C3_RES) |
5418c2ecf20Sopenharmony_ci				  BIT(PERF_CSTATE_CORE_C6_RES) |
5428c2ecf20Sopenharmony_ci				  BIT(PERF_CSTATE_CORE_C7_RES),
5438c2ecf20Sopenharmony_ci
5448c2ecf20Sopenharmony_ci	.pkg_events		= BIT(PERF_CSTATE_PKG_C2_RES) |
5458c2ecf20Sopenharmony_ci				  BIT(PERF_CSTATE_PKG_C3_RES) |
5468c2ecf20Sopenharmony_ci				  BIT(PERF_CSTATE_PKG_C6_RES) |
5478c2ecf20Sopenharmony_ci				  BIT(PERF_CSTATE_PKG_C7_RES) |
5488c2ecf20Sopenharmony_ci				  BIT(PERF_CSTATE_PKG_C8_RES) |
5498c2ecf20Sopenharmony_ci				  BIT(PERF_CSTATE_PKG_C9_RES) |
5508c2ecf20Sopenharmony_ci				  BIT(PERF_CSTATE_PKG_C10_RES),
5518c2ecf20Sopenharmony_ci};
5528c2ecf20Sopenharmony_ci
5538c2ecf20Sopenharmony_cistatic const struct cstate_model icl_cstates __initconst = {
5548c2ecf20Sopenharmony_ci	.core_events		= BIT(PERF_CSTATE_CORE_C6_RES) |
5558c2ecf20Sopenharmony_ci				  BIT(PERF_CSTATE_CORE_C7_RES),
5568c2ecf20Sopenharmony_ci
5578c2ecf20Sopenharmony_ci	.pkg_events		= BIT(PERF_CSTATE_PKG_C2_RES) |
5588c2ecf20Sopenharmony_ci				  BIT(PERF_CSTATE_PKG_C3_RES) |
5598c2ecf20Sopenharmony_ci				  BIT(PERF_CSTATE_PKG_C6_RES) |
5608c2ecf20Sopenharmony_ci				  BIT(PERF_CSTATE_PKG_C7_RES) |
5618c2ecf20Sopenharmony_ci				  BIT(PERF_CSTATE_PKG_C8_RES) |
5628c2ecf20Sopenharmony_ci				  BIT(PERF_CSTATE_PKG_C9_RES) |
5638c2ecf20Sopenharmony_ci				  BIT(PERF_CSTATE_PKG_C10_RES),
5648c2ecf20Sopenharmony_ci};
5658c2ecf20Sopenharmony_ci
5668c2ecf20Sopenharmony_cistatic const struct cstate_model slm_cstates __initconst = {
5678c2ecf20Sopenharmony_ci	.core_events		= BIT(PERF_CSTATE_CORE_C1_RES) |
5688c2ecf20Sopenharmony_ci				  BIT(PERF_CSTATE_CORE_C6_RES),
5698c2ecf20Sopenharmony_ci
5708c2ecf20Sopenharmony_ci	.pkg_events		= BIT(PERF_CSTATE_PKG_C6_RES),
5718c2ecf20Sopenharmony_ci	.quirks			= SLM_PKG_C6_USE_C7_MSR,
5728c2ecf20Sopenharmony_ci};
5738c2ecf20Sopenharmony_ci
5748c2ecf20Sopenharmony_ci
5758c2ecf20Sopenharmony_cistatic const struct cstate_model knl_cstates __initconst = {
5768c2ecf20Sopenharmony_ci	.core_events		= BIT(PERF_CSTATE_CORE_C6_RES),
5778c2ecf20Sopenharmony_ci
5788c2ecf20Sopenharmony_ci	.pkg_events		= BIT(PERF_CSTATE_PKG_C2_RES) |
5798c2ecf20Sopenharmony_ci				  BIT(PERF_CSTATE_PKG_C3_RES) |
5808c2ecf20Sopenharmony_ci				  BIT(PERF_CSTATE_PKG_C6_RES),
5818c2ecf20Sopenharmony_ci	.quirks			= KNL_CORE_C6_MSR,
5828c2ecf20Sopenharmony_ci};
5838c2ecf20Sopenharmony_ci
5848c2ecf20Sopenharmony_ci
5858c2ecf20Sopenharmony_cistatic const struct cstate_model glm_cstates __initconst = {
5868c2ecf20Sopenharmony_ci	.core_events		= BIT(PERF_CSTATE_CORE_C1_RES) |
5878c2ecf20Sopenharmony_ci				  BIT(PERF_CSTATE_CORE_C3_RES) |
5888c2ecf20Sopenharmony_ci				  BIT(PERF_CSTATE_CORE_C6_RES),
5898c2ecf20Sopenharmony_ci
5908c2ecf20Sopenharmony_ci	.pkg_events		= BIT(PERF_CSTATE_PKG_C2_RES) |
5918c2ecf20Sopenharmony_ci				  BIT(PERF_CSTATE_PKG_C3_RES) |
5928c2ecf20Sopenharmony_ci				  BIT(PERF_CSTATE_PKG_C6_RES) |
5938c2ecf20Sopenharmony_ci				  BIT(PERF_CSTATE_PKG_C10_RES),
5948c2ecf20Sopenharmony_ci};
5958c2ecf20Sopenharmony_ci
5968c2ecf20Sopenharmony_ci
5978c2ecf20Sopenharmony_cistatic const struct x86_cpu_id intel_cstates_match[] __initconst = {
5988c2ecf20Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(NEHALEM,		&nhm_cstates),
5998c2ecf20Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(NEHALEM_EP,		&nhm_cstates),
6008c2ecf20Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(NEHALEM_EX,		&nhm_cstates),
6018c2ecf20Sopenharmony_ci
6028c2ecf20Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(WESTMERE,		&nhm_cstates),
6038c2ecf20Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(WESTMERE_EP,		&nhm_cstates),
6048c2ecf20Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(WESTMERE_EX,		&nhm_cstates),
6058c2ecf20Sopenharmony_ci
6068c2ecf20Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(SANDYBRIDGE,		&snb_cstates),
6078c2ecf20Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(SANDYBRIDGE_X,	&snb_cstates),
6088c2ecf20Sopenharmony_ci
6098c2ecf20Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(IVYBRIDGE,		&snb_cstates),
6108c2ecf20Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(IVYBRIDGE_X,		&snb_cstates),
6118c2ecf20Sopenharmony_ci
6128c2ecf20Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(HASWELL,		&snb_cstates),
6138c2ecf20Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(HASWELL_X,		&snb_cstates),
6148c2ecf20Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(HASWELL_G,		&snb_cstates),
6158c2ecf20Sopenharmony_ci
6168c2ecf20Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(HASWELL_L,		&hswult_cstates),
6178c2ecf20Sopenharmony_ci
6188c2ecf20Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(ATOM_SILVERMONT,	&slm_cstates),
6198c2ecf20Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(ATOM_SILVERMONT_D,	&slm_cstates),
6208c2ecf20Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(ATOM_AIRMONT,	&slm_cstates),
6218c2ecf20Sopenharmony_ci
6228c2ecf20Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(BROADWELL,		&snb_cstates),
6238c2ecf20Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(BROADWELL_D,		&snb_cstates),
6248c2ecf20Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(BROADWELL_G,		&snb_cstates),
6258c2ecf20Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(BROADWELL_X,		&snb_cstates),
6268c2ecf20Sopenharmony_ci
6278c2ecf20Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE_L,		&snb_cstates),
6288c2ecf20Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE,		&snb_cstates),
6298c2ecf20Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE_X,		&snb_cstates),
6308c2ecf20Sopenharmony_ci
6318c2ecf20Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(KABYLAKE_L,		&hswult_cstates),
6328c2ecf20Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(KABYLAKE,		&hswult_cstates),
6338c2ecf20Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(COMETLAKE_L,		&hswult_cstates),
6348c2ecf20Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(COMETLAKE,		&hswult_cstates),
6358c2ecf20Sopenharmony_ci
6368c2ecf20Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(CANNONLAKE_L,	&cnl_cstates),
6378c2ecf20Sopenharmony_ci
6388c2ecf20Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(XEON_PHI_KNL,	&knl_cstates),
6398c2ecf20Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(XEON_PHI_KNM,	&knl_cstates),
6408c2ecf20Sopenharmony_ci
6418c2ecf20Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(ATOM_GOLDMONT,	&glm_cstates),
6428c2ecf20Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(ATOM_GOLDMONT_D,	&glm_cstates),
6438c2ecf20Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(ATOM_GOLDMONT_PLUS,	&glm_cstates),
6448c2ecf20Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(ATOM_TREMONT_D,	&glm_cstates),
6458c2ecf20Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(ATOM_TREMONT,	&glm_cstates),
6468c2ecf20Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(ATOM_TREMONT_L,	&glm_cstates),
6478c2ecf20Sopenharmony_ci
6488c2ecf20Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_L,		&icl_cstates),
6498c2ecf20Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(ICELAKE,		&icl_cstates),
6508c2ecf20Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(TIGERLAKE_L,		&icl_cstates),
6518c2ecf20Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(TIGERLAKE,		&icl_cstates),
6528c2ecf20Sopenharmony_ci	{ },
6538c2ecf20Sopenharmony_ci};
6548c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(x86cpu, intel_cstates_match);
6558c2ecf20Sopenharmony_ci
6568c2ecf20Sopenharmony_cistatic int __init cstate_probe(const struct cstate_model *cm)
6578c2ecf20Sopenharmony_ci{
6588c2ecf20Sopenharmony_ci	/* SLM has different MSR for PKG C6 */
6598c2ecf20Sopenharmony_ci	if (cm->quirks & SLM_PKG_C6_USE_C7_MSR)
6608c2ecf20Sopenharmony_ci		pkg_msr[PERF_CSTATE_PKG_C6_RES].msr = MSR_PKG_C7_RESIDENCY;
6618c2ecf20Sopenharmony_ci
6628c2ecf20Sopenharmony_ci	/* KNL has different MSR for CORE C6 */
6638c2ecf20Sopenharmony_ci	if (cm->quirks & KNL_CORE_C6_MSR)
6648c2ecf20Sopenharmony_ci		pkg_msr[PERF_CSTATE_CORE_C6_RES].msr = MSR_KNL_CORE_C6_RESIDENCY;
6658c2ecf20Sopenharmony_ci
6668c2ecf20Sopenharmony_ci
6678c2ecf20Sopenharmony_ci	core_msr_mask = perf_msr_probe(core_msr, PERF_CSTATE_CORE_EVENT_MAX,
6688c2ecf20Sopenharmony_ci				       true, (void *) &cm->core_events);
6698c2ecf20Sopenharmony_ci
6708c2ecf20Sopenharmony_ci	pkg_msr_mask = perf_msr_probe(pkg_msr, PERF_CSTATE_PKG_EVENT_MAX,
6718c2ecf20Sopenharmony_ci				      true, (void *) &cm->pkg_events);
6728c2ecf20Sopenharmony_ci
6738c2ecf20Sopenharmony_ci	has_cstate_core = !!core_msr_mask;
6748c2ecf20Sopenharmony_ci	has_cstate_pkg  = !!pkg_msr_mask;
6758c2ecf20Sopenharmony_ci
6768c2ecf20Sopenharmony_ci	return (has_cstate_core || has_cstate_pkg) ? 0 : -ENODEV;
6778c2ecf20Sopenharmony_ci}
6788c2ecf20Sopenharmony_ci
6798c2ecf20Sopenharmony_cistatic inline void cstate_cleanup(void)
6808c2ecf20Sopenharmony_ci{
6818c2ecf20Sopenharmony_ci	cpuhp_remove_state_nocalls(CPUHP_AP_PERF_X86_CSTATE_ONLINE);
6828c2ecf20Sopenharmony_ci	cpuhp_remove_state_nocalls(CPUHP_AP_PERF_X86_CSTATE_STARTING);
6838c2ecf20Sopenharmony_ci
6848c2ecf20Sopenharmony_ci	if (has_cstate_core)
6858c2ecf20Sopenharmony_ci		perf_pmu_unregister(&cstate_core_pmu);
6868c2ecf20Sopenharmony_ci
6878c2ecf20Sopenharmony_ci	if (has_cstate_pkg)
6888c2ecf20Sopenharmony_ci		perf_pmu_unregister(&cstate_pkg_pmu);
6898c2ecf20Sopenharmony_ci}
6908c2ecf20Sopenharmony_ci
6918c2ecf20Sopenharmony_cistatic int __init cstate_init(void)
6928c2ecf20Sopenharmony_ci{
6938c2ecf20Sopenharmony_ci	int err;
6948c2ecf20Sopenharmony_ci
6958c2ecf20Sopenharmony_ci	cpuhp_setup_state(CPUHP_AP_PERF_X86_CSTATE_STARTING,
6968c2ecf20Sopenharmony_ci			  "perf/x86/cstate:starting", cstate_cpu_init, NULL);
6978c2ecf20Sopenharmony_ci	cpuhp_setup_state(CPUHP_AP_PERF_X86_CSTATE_ONLINE,
6988c2ecf20Sopenharmony_ci			  "perf/x86/cstate:online", NULL, cstate_cpu_exit);
6998c2ecf20Sopenharmony_ci
7008c2ecf20Sopenharmony_ci	if (has_cstate_core) {
7018c2ecf20Sopenharmony_ci		err = perf_pmu_register(&cstate_core_pmu, cstate_core_pmu.name, -1);
7028c2ecf20Sopenharmony_ci		if (err) {
7038c2ecf20Sopenharmony_ci			has_cstate_core = false;
7048c2ecf20Sopenharmony_ci			pr_info("Failed to register cstate core pmu\n");
7058c2ecf20Sopenharmony_ci			cstate_cleanup();
7068c2ecf20Sopenharmony_ci			return err;
7078c2ecf20Sopenharmony_ci		}
7088c2ecf20Sopenharmony_ci	}
7098c2ecf20Sopenharmony_ci
7108c2ecf20Sopenharmony_ci	if (has_cstate_pkg) {
7118c2ecf20Sopenharmony_ci		if (topology_max_die_per_package() > 1) {
7128c2ecf20Sopenharmony_ci			err = perf_pmu_register(&cstate_pkg_pmu,
7138c2ecf20Sopenharmony_ci						"cstate_die", -1);
7148c2ecf20Sopenharmony_ci		} else {
7158c2ecf20Sopenharmony_ci			err = perf_pmu_register(&cstate_pkg_pmu,
7168c2ecf20Sopenharmony_ci						cstate_pkg_pmu.name, -1);
7178c2ecf20Sopenharmony_ci		}
7188c2ecf20Sopenharmony_ci		if (err) {
7198c2ecf20Sopenharmony_ci			has_cstate_pkg = false;
7208c2ecf20Sopenharmony_ci			pr_info("Failed to register cstate pkg pmu\n");
7218c2ecf20Sopenharmony_ci			cstate_cleanup();
7228c2ecf20Sopenharmony_ci			return err;
7238c2ecf20Sopenharmony_ci		}
7248c2ecf20Sopenharmony_ci	}
7258c2ecf20Sopenharmony_ci	return 0;
7268c2ecf20Sopenharmony_ci}
7278c2ecf20Sopenharmony_ci
7288c2ecf20Sopenharmony_cistatic int __init cstate_pmu_init(void)
7298c2ecf20Sopenharmony_ci{
7308c2ecf20Sopenharmony_ci	const struct x86_cpu_id *id;
7318c2ecf20Sopenharmony_ci	int err;
7328c2ecf20Sopenharmony_ci
7338c2ecf20Sopenharmony_ci	if (boot_cpu_has(X86_FEATURE_HYPERVISOR))
7348c2ecf20Sopenharmony_ci		return -ENODEV;
7358c2ecf20Sopenharmony_ci
7368c2ecf20Sopenharmony_ci	id = x86_match_cpu(intel_cstates_match);
7378c2ecf20Sopenharmony_ci	if (!id)
7388c2ecf20Sopenharmony_ci		return -ENODEV;
7398c2ecf20Sopenharmony_ci
7408c2ecf20Sopenharmony_ci	err = cstate_probe((const struct cstate_model *) id->driver_data);
7418c2ecf20Sopenharmony_ci	if (err)
7428c2ecf20Sopenharmony_ci		return err;
7438c2ecf20Sopenharmony_ci
7448c2ecf20Sopenharmony_ci	return cstate_init();
7458c2ecf20Sopenharmony_ci}
7468c2ecf20Sopenharmony_cimodule_init(cstate_pmu_init);
7478c2ecf20Sopenharmony_ci
7488c2ecf20Sopenharmony_cistatic void __exit cstate_pmu_exit(void)
7498c2ecf20Sopenharmony_ci{
7508c2ecf20Sopenharmony_ci	cstate_cleanup();
7518c2ecf20Sopenharmony_ci}
7528c2ecf20Sopenharmony_cimodule_exit(cstate_pmu_exit);
753