xref: /openbmc/linux/drivers/iommu/intel/perfmon.c (revision aeddf9a2731de8235b2b433533d06ee7dc73d233)
1a6a5006dSKan Liang // SPDX-License-Identifier: GPL-2.0-only
2a6a5006dSKan Liang /*
3a6a5006dSKan Liang  * Support Intel IOMMU PerfMon
4a6a5006dSKan Liang  * Copyright(c) 2023 Intel Corporation.
5a6a5006dSKan Liang  */
6a6a5006dSKan Liang #define pr_fmt(fmt)	"DMAR: " fmt
7a6a5006dSKan Liang #define dev_fmt(fmt)	pr_fmt(fmt)
8a6a5006dSKan Liang 
9a6a5006dSKan Liang #include <linux/dmar.h>
10a6a5006dSKan Liang #include "iommu.h"
11a6a5006dSKan Liang #include "perfmon.h"
12a6a5006dSKan Liang 
137232ab8bSKan Liang PMU_FORMAT_ATTR(event,		"config:0-27");		/* ES: Events Select */
147232ab8bSKan Liang PMU_FORMAT_ATTR(event_group,	"config:28-31");	/* EGI: Event Group Index */
157232ab8bSKan Liang 
167232ab8bSKan Liang static struct attribute *iommu_pmu_format_attrs[] = {
177232ab8bSKan Liang 	&format_attr_event_group.attr,
187232ab8bSKan Liang 	&format_attr_event.attr,
197232ab8bSKan Liang 	NULL
207232ab8bSKan Liang };
217232ab8bSKan Liang 
227232ab8bSKan Liang static struct attribute_group iommu_pmu_format_attr_group = {
237232ab8bSKan Liang 	.name = "format",
247232ab8bSKan Liang 	.attrs = iommu_pmu_format_attrs,
257232ab8bSKan Liang };
267232ab8bSKan Liang 
277232ab8bSKan Liang /* The available events are added in attr_update later */
287232ab8bSKan Liang static struct attribute *attrs_empty[] = {
297232ab8bSKan Liang 	NULL
307232ab8bSKan Liang };
317232ab8bSKan Liang 
327232ab8bSKan Liang static struct attribute_group iommu_pmu_events_attr_group = {
337232ab8bSKan Liang 	.name = "events",
347232ab8bSKan Liang 	.attrs = attrs_empty,
357232ab8bSKan Liang };
367232ab8bSKan Liang 
3746284c6cSKan Liang static cpumask_t iommu_pmu_cpu_mask;
3846284c6cSKan Liang 
3946284c6cSKan Liang static ssize_t
cpumask_show(struct device * dev,struct device_attribute * attr,char * buf)4046284c6cSKan Liang cpumask_show(struct device *dev, struct device_attribute *attr, char *buf)
4146284c6cSKan Liang {
4246284c6cSKan Liang 	return cpumap_print_to_pagebuf(true, buf, &iommu_pmu_cpu_mask);
4346284c6cSKan Liang }
4446284c6cSKan Liang static DEVICE_ATTR_RO(cpumask);
4546284c6cSKan Liang 
4646284c6cSKan Liang static struct attribute *iommu_pmu_cpumask_attrs[] = {
4746284c6cSKan Liang 	&dev_attr_cpumask.attr,
4846284c6cSKan Liang 	NULL
4946284c6cSKan Liang };
5046284c6cSKan Liang 
5146284c6cSKan Liang static struct attribute_group iommu_pmu_cpumask_attr_group = {
5246284c6cSKan Liang 	.attrs = iommu_pmu_cpumask_attrs,
5346284c6cSKan Liang };
5446284c6cSKan Liang 
557232ab8bSKan Liang static const struct attribute_group *iommu_pmu_attr_groups[] = {
567232ab8bSKan Liang 	&iommu_pmu_format_attr_group,
577232ab8bSKan Liang 	&iommu_pmu_events_attr_group,
5846284c6cSKan Liang 	&iommu_pmu_cpumask_attr_group,
597232ab8bSKan Liang 	NULL
607232ab8bSKan Liang };
617232ab8bSKan Liang 
dev_to_iommu_pmu(struct device * dev)627232ab8bSKan Liang static inline struct iommu_pmu *dev_to_iommu_pmu(struct device *dev)
637232ab8bSKan Liang {
647232ab8bSKan Liang 	/*
657232ab8bSKan Liang 	 * The perf_event creates its own dev for each PMU.
667232ab8bSKan Liang 	 * See pmu_dev_alloc()
677232ab8bSKan Liang 	 */
687232ab8bSKan Liang 	return container_of(dev_get_drvdata(dev), struct iommu_pmu, pmu);
697232ab8bSKan Liang }
707232ab8bSKan Liang 
717232ab8bSKan Liang #define IOMMU_PMU_ATTR(_name, _format, _filter)				\
727232ab8bSKan Liang 	PMU_FORMAT_ATTR(_name, _format);				\
737232ab8bSKan Liang 									\
747232ab8bSKan Liang static struct attribute *_name##_attr[] = {				\
757232ab8bSKan Liang 	&format_attr_##_name.attr,					\
767232ab8bSKan Liang 	NULL								\
777232ab8bSKan Liang };									\
787232ab8bSKan Liang 									\
797232ab8bSKan Liang static umode_t								\
807232ab8bSKan Liang _name##_is_visible(struct kobject *kobj, struct attribute *attr, int i)	\
817232ab8bSKan Liang {									\
827232ab8bSKan Liang 	struct device *dev = kobj_to_dev(kobj);				\
837232ab8bSKan Liang 	struct iommu_pmu *iommu_pmu = dev_to_iommu_pmu(dev);		\
847232ab8bSKan Liang 									\
857232ab8bSKan Liang 	if (!iommu_pmu)							\
867232ab8bSKan Liang 		return 0;						\
877232ab8bSKan Liang 	return (iommu_pmu->filter & _filter) ? attr->mode : 0;		\
887232ab8bSKan Liang }									\
897232ab8bSKan Liang 									\
907232ab8bSKan Liang static struct attribute_group _name = {					\
917232ab8bSKan Liang 	.name		= "format",					\
927232ab8bSKan Liang 	.attrs		= _name##_attr,					\
937232ab8bSKan Liang 	.is_visible	= _name##_is_visible,				\
947232ab8bSKan Liang };
957232ab8bSKan Liang 
967232ab8bSKan Liang IOMMU_PMU_ATTR(filter_requester_id_en,	"config1:0",		IOMMU_PMU_FILTER_REQUESTER_ID);
977232ab8bSKan Liang IOMMU_PMU_ATTR(filter_domain_en,	"config1:1",		IOMMU_PMU_FILTER_DOMAIN);
987232ab8bSKan Liang IOMMU_PMU_ATTR(filter_pasid_en,		"config1:2",		IOMMU_PMU_FILTER_PASID);
997232ab8bSKan Liang IOMMU_PMU_ATTR(filter_ats_en,		"config1:3",		IOMMU_PMU_FILTER_ATS);
1007232ab8bSKan Liang IOMMU_PMU_ATTR(filter_page_table_en,	"config1:4",		IOMMU_PMU_FILTER_PAGE_TABLE);
1017232ab8bSKan Liang IOMMU_PMU_ATTR(filter_requester_id,	"config1:16-31",	IOMMU_PMU_FILTER_REQUESTER_ID);
1027232ab8bSKan Liang IOMMU_PMU_ATTR(filter_domain,		"config1:32-47",	IOMMU_PMU_FILTER_DOMAIN);
1037232ab8bSKan Liang IOMMU_PMU_ATTR(filter_pasid,		"config2:0-21",		IOMMU_PMU_FILTER_PASID);
1047232ab8bSKan Liang IOMMU_PMU_ATTR(filter_ats,		"config2:24-28",	IOMMU_PMU_FILTER_ATS);
1057232ab8bSKan Liang IOMMU_PMU_ATTR(filter_page_table,	"config2:32-36",	IOMMU_PMU_FILTER_PAGE_TABLE);
1067232ab8bSKan Liang 
1077232ab8bSKan Liang #define iommu_pmu_en_requester_id(e)		((e) & 0x1)
1087232ab8bSKan Liang #define iommu_pmu_en_domain(e)			(((e) >> 1) & 0x1)
1097232ab8bSKan Liang #define iommu_pmu_en_pasid(e)			(((e) >> 2) & 0x1)
1107232ab8bSKan Liang #define iommu_pmu_en_ats(e)			(((e) >> 3) & 0x1)
1117232ab8bSKan Liang #define iommu_pmu_en_page_table(e)		(((e) >> 4) & 0x1)
1127232ab8bSKan Liang #define iommu_pmu_get_requester_id(filter)	(((filter) >> 16) & 0xffff)
1137232ab8bSKan Liang #define iommu_pmu_get_domain(filter)		(((filter) >> 32) & 0xffff)
1147232ab8bSKan Liang #define iommu_pmu_get_pasid(filter)		((filter) & 0x3fffff)
1157232ab8bSKan Liang #define iommu_pmu_get_ats(filter)		(((filter) >> 24) & 0x1f)
1167232ab8bSKan Liang #define iommu_pmu_get_page_table(filter)	(((filter) >> 32) & 0x1f)
1177232ab8bSKan Liang 
1187232ab8bSKan Liang #define iommu_pmu_set_filter(_name, _config, _filter, _idx, _econfig)		\
1197232ab8bSKan Liang {										\
1207232ab8bSKan Liang 	if ((iommu_pmu->filter & _filter) && iommu_pmu_en_##_name(_econfig)) {	\
1217232ab8bSKan Liang 		dmar_writel(iommu_pmu->cfg_reg + _idx * IOMMU_PMU_CFG_OFFSET +	\
1227232ab8bSKan Liang 			    IOMMU_PMU_CFG_SIZE +				\
1237232ab8bSKan Liang 			    (ffs(_filter) - 1) * IOMMU_PMU_CFG_FILTERS_OFFSET,	\
1247232ab8bSKan Liang 			    iommu_pmu_get_##_name(_config) | IOMMU_PMU_FILTER_EN);\
1257232ab8bSKan Liang 	}									\
1267232ab8bSKan Liang }
1277232ab8bSKan Liang 
1287232ab8bSKan Liang #define iommu_pmu_clear_filter(_filter, _idx)					\
1297232ab8bSKan Liang {										\
1307232ab8bSKan Liang 	if (iommu_pmu->filter & _filter) {					\
1317232ab8bSKan Liang 		dmar_writel(iommu_pmu->cfg_reg + _idx * IOMMU_PMU_CFG_OFFSET +	\
1327232ab8bSKan Liang 			    IOMMU_PMU_CFG_SIZE +				\
1337232ab8bSKan Liang 			    (ffs(_filter) - 1) * IOMMU_PMU_CFG_FILTERS_OFFSET,	\
1347232ab8bSKan Liang 			    0);							\
1357232ab8bSKan Liang 	}									\
1367232ab8bSKan Liang }
1377232ab8bSKan Liang 
1387232ab8bSKan Liang /*
1397232ab8bSKan Liang  * Define the event attr related functions
1407232ab8bSKan Liang  * Input: _name: event attr name
1417232ab8bSKan Liang  *        _string: string of the event in sysfs
1427232ab8bSKan Liang  *        _g_idx: event group encoding
1437232ab8bSKan Liang  *        _event: event encoding
1447232ab8bSKan Liang  */
1457232ab8bSKan Liang #define IOMMU_PMU_EVENT_ATTR(_name, _string, _g_idx, _event)			\
1467232ab8bSKan Liang 	PMU_EVENT_ATTR_STRING(_name, event_attr_##_name, _string)		\
1477232ab8bSKan Liang 										\
1487232ab8bSKan Liang static struct attribute *_name##_attr[] = {					\
1497232ab8bSKan Liang 	&event_attr_##_name.attr.attr,						\
1507232ab8bSKan Liang 	NULL									\
1517232ab8bSKan Liang };										\
1527232ab8bSKan Liang 										\
1537232ab8bSKan Liang static umode_t									\
1547232ab8bSKan Liang _name##_is_visible(struct kobject *kobj, struct attribute *attr, int i)		\
1557232ab8bSKan Liang {										\
1567232ab8bSKan Liang 	struct device *dev = kobj_to_dev(kobj);					\
1577232ab8bSKan Liang 	struct iommu_pmu *iommu_pmu = dev_to_iommu_pmu(dev);			\
1587232ab8bSKan Liang 										\
1597232ab8bSKan Liang 	if (!iommu_pmu)								\
1607232ab8bSKan Liang 		return 0;							\
1617232ab8bSKan Liang 	return (iommu_pmu->evcap[_g_idx] & _event) ? attr->mode : 0;		\
1627232ab8bSKan Liang }										\
1637232ab8bSKan Liang 										\
1647232ab8bSKan Liang static struct attribute_group _name = {						\
1657232ab8bSKan Liang 	.name		= "events",						\
1667232ab8bSKan Liang 	.attrs		= _name##_attr,						\
1677232ab8bSKan Liang 	.is_visible	= _name##_is_visible,					\
1687232ab8bSKan Liang };
1697232ab8bSKan Liang 
1707232ab8bSKan Liang IOMMU_PMU_EVENT_ATTR(iommu_clocks,		"event_group=0x0,event=0x001", 0x0, 0x001)
1717232ab8bSKan Liang IOMMU_PMU_EVENT_ATTR(iommu_requests,		"event_group=0x0,event=0x002", 0x0, 0x002)
1727232ab8bSKan Liang IOMMU_PMU_EVENT_ATTR(pw_occupancy,		"event_group=0x0,event=0x004", 0x0, 0x004)
1737232ab8bSKan Liang IOMMU_PMU_EVENT_ATTR(ats_blocked,		"event_group=0x0,event=0x008", 0x0, 0x008)
1747232ab8bSKan Liang IOMMU_PMU_EVENT_ATTR(iommu_mrds,		"event_group=0x1,event=0x001", 0x1, 0x001)
1757232ab8bSKan Liang IOMMU_PMU_EVENT_ATTR(iommu_mem_blocked,		"event_group=0x1,event=0x020", 0x1, 0x020)
1767232ab8bSKan Liang IOMMU_PMU_EVENT_ATTR(pg_req_posted,		"event_group=0x1,event=0x040", 0x1, 0x040)
1777232ab8bSKan Liang IOMMU_PMU_EVENT_ATTR(ctxt_cache_lookup,		"event_group=0x2,event=0x001", 0x2, 0x001)
1787232ab8bSKan Liang IOMMU_PMU_EVENT_ATTR(ctxt_cache_hit,		"event_group=0x2,event=0x002", 0x2, 0x002)
1797232ab8bSKan Liang IOMMU_PMU_EVENT_ATTR(pasid_cache_lookup,	"event_group=0x2,event=0x004", 0x2, 0x004)
1807232ab8bSKan Liang IOMMU_PMU_EVENT_ATTR(pasid_cache_hit,		"event_group=0x2,event=0x008", 0x2, 0x008)
1817232ab8bSKan Liang IOMMU_PMU_EVENT_ATTR(ss_nonleaf_lookup,		"event_group=0x2,event=0x010", 0x2, 0x010)
1827232ab8bSKan Liang IOMMU_PMU_EVENT_ATTR(ss_nonleaf_hit,		"event_group=0x2,event=0x020", 0x2, 0x020)
1837232ab8bSKan Liang IOMMU_PMU_EVENT_ATTR(fs_nonleaf_lookup,		"event_group=0x2,event=0x040", 0x2, 0x040)
1847232ab8bSKan Liang IOMMU_PMU_EVENT_ATTR(fs_nonleaf_hit,		"event_group=0x2,event=0x080", 0x2, 0x080)
1857232ab8bSKan Liang IOMMU_PMU_EVENT_ATTR(hpt_nonleaf_lookup,	"event_group=0x2,event=0x100", 0x2, 0x100)
1867232ab8bSKan Liang IOMMU_PMU_EVENT_ATTR(hpt_nonleaf_hit,		"event_group=0x2,event=0x200", 0x2, 0x200)
1877232ab8bSKan Liang IOMMU_PMU_EVENT_ATTR(iotlb_lookup,		"event_group=0x3,event=0x001", 0x3, 0x001)
1887232ab8bSKan Liang IOMMU_PMU_EVENT_ATTR(iotlb_hit,			"event_group=0x3,event=0x002", 0x3, 0x002)
1897232ab8bSKan Liang IOMMU_PMU_EVENT_ATTR(hpt_leaf_lookup,		"event_group=0x3,event=0x004", 0x3, 0x004)
1907232ab8bSKan Liang IOMMU_PMU_EVENT_ATTR(hpt_leaf_hit,		"event_group=0x3,event=0x008", 0x3, 0x008)
1917232ab8bSKan Liang IOMMU_PMU_EVENT_ATTR(int_cache_lookup,		"event_group=0x4,event=0x001", 0x4, 0x001)
1927232ab8bSKan Liang IOMMU_PMU_EVENT_ATTR(int_cache_hit_nonposted,	"event_group=0x4,event=0x002", 0x4, 0x002)
1937232ab8bSKan Liang IOMMU_PMU_EVENT_ATTR(int_cache_hit_posted,	"event_group=0x4,event=0x004", 0x4, 0x004)
1947232ab8bSKan Liang 
1957232ab8bSKan Liang static const struct attribute_group *iommu_pmu_attr_update[] = {
1967232ab8bSKan Liang 	&filter_requester_id_en,
1977232ab8bSKan Liang 	&filter_domain_en,
1987232ab8bSKan Liang 	&filter_pasid_en,
1997232ab8bSKan Liang 	&filter_ats_en,
2007232ab8bSKan Liang 	&filter_page_table_en,
2017232ab8bSKan Liang 	&filter_requester_id,
2027232ab8bSKan Liang 	&filter_domain,
2037232ab8bSKan Liang 	&filter_pasid,
2047232ab8bSKan Liang 	&filter_ats,
2057232ab8bSKan Liang 	&filter_page_table,
2067232ab8bSKan Liang 	&iommu_clocks,
2077232ab8bSKan Liang 	&iommu_requests,
2087232ab8bSKan Liang 	&pw_occupancy,
2097232ab8bSKan Liang 	&ats_blocked,
2107232ab8bSKan Liang 	&iommu_mrds,
2117232ab8bSKan Liang 	&iommu_mem_blocked,
2127232ab8bSKan Liang 	&pg_req_posted,
2137232ab8bSKan Liang 	&ctxt_cache_lookup,
2147232ab8bSKan Liang 	&ctxt_cache_hit,
2157232ab8bSKan Liang 	&pasid_cache_lookup,
2167232ab8bSKan Liang 	&pasid_cache_hit,
2177232ab8bSKan Liang 	&ss_nonleaf_lookup,
2187232ab8bSKan Liang 	&ss_nonleaf_hit,
2197232ab8bSKan Liang 	&fs_nonleaf_lookup,
2207232ab8bSKan Liang 	&fs_nonleaf_hit,
2217232ab8bSKan Liang 	&hpt_nonleaf_lookup,
2227232ab8bSKan Liang 	&hpt_nonleaf_hit,
2237232ab8bSKan Liang 	&iotlb_lookup,
2247232ab8bSKan Liang 	&iotlb_hit,
2257232ab8bSKan Liang 	&hpt_leaf_lookup,
2267232ab8bSKan Liang 	&hpt_leaf_hit,
2277232ab8bSKan Liang 	&int_cache_lookup,
2287232ab8bSKan Liang 	&int_cache_hit_nonposted,
2297232ab8bSKan Liang 	&int_cache_hit_posted,
2307232ab8bSKan Liang 	NULL
2317232ab8bSKan Liang };
2327232ab8bSKan Liang 
2337232ab8bSKan Liang static inline void __iomem *
iommu_event_base(struct iommu_pmu * iommu_pmu,int idx)2347232ab8bSKan Liang iommu_event_base(struct iommu_pmu *iommu_pmu, int idx)
2357232ab8bSKan Liang {
2367232ab8bSKan Liang 	return iommu_pmu->cntr_reg + idx * iommu_pmu->cntr_stride;
2377232ab8bSKan Liang }
2387232ab8bSKan Liang 
2397232ab8bSKan Liang static inline void __iomem *
iommu_config_base(struct iommu_pmu * iommu_pmu,int idx)2407232ab8bSKan Liang iommu_config_base(struct iommu_pmu *iommu_pmu, int idx)
2417232ab8bSKan Liang {
2427232ab8bSKan Liang 	return iommu_pmu->cfg_reg + idx * IOMMU_PMU_CFG_OFFSET;
2437232ab8bSKan Liang }
2447232ab8bSKan Liang 
iommu_event_to_pmu(struct perf_event * event)2457232ab8bSKan Liang static inline struct iommu_pmu *iommu_event_to_pmu(struct perf_event *event)
2467232ab8bSKan Liang {
2477232ab8bSKan Liang 	return container_of(event->pmu, struct iommu_pmu, pmu);
2487232ab8bSKan Liang }
2497232ab8bSKan Liang 
iommu_event_config(struct perf_event * event)2507232ab8bSKan Liang static inline u64 iommu_event_config(struct perf_event *event)
2517232ab8bSKan Liang {
2527232ab8bSKan Liang 	u64 config = event->attr.config;
2537232ab8bSKan Liang 
2547232ab8bSKan Liang 	return (iommu_event_select(config) << IOMMU_EVENT_CFG_ES_SHIFT) |
2557232ab8bSKan Liang 	       (iommu_event_group(config) << IOMMU_EVENT_CFG_EGI_SHIFT) |
2567232ab8bSKan Liang 	       IOMMU_EVENT_CFG_INT;
2577232ab8bSKan Liang }
2587232ab8bSKan Liang 
is_iommu_pmu_event(struct iommu_pmu * iommu_pmu,struct perf_event * event)2597232ab8bSKan Liang static inline bool is_iommu_pmu_event(struct iommu_pmu *iommu_pmu,
2607232ab8bSKan Liang 				      struct perf_event *event)
2617232ab8bSKan Liang {
2627232ab8bSKan Liang 	return event->pmu == &iommu_pmu->pmu;
2637232ab8bSKan Liang }
2647232ab8bSKan Liang 
iommu_pmu_validate_event(struct perf_event * event)2657232ab8bSKan Liang static int iommu_pmu_validate_event(struct perf_event *event)
2667232ab8bSKan Liang {
2677232ab8bSKan Liang 	struct iommu_pmu *iommu_pmu = iommu_event_to_pmu(event);
2687232ab8bSKan Liang 	u32 event_group = iommu_event_group(event->attr.config);
2697232ab8bSKan Liang 
2707232ab8bSKan Liang 	if (event_group >= iommu_pmu->num_eg)
2717232ab8bSKan Liang 		return -EINVAL;
2727232ab8bSKan Liang 
2737232ab8bSKan Liang 	return 0;
2747232ab8bSKan Liang }
2757232ab8bSKan Liang 
iommu_pmu_validate_group(struct perf_event * event)2767232ab8bSKan Liang static int iommu_pmu_validate_group(struct perf_event *event)
2777232ab8bSKan Liang {
2787232ab8bSKan Liang 	struct iommu_pmu *iommu_pmu = iommu_event_to_pmu(event);
2797232ab8bSKan Liang 	struct perf_event *sibling;
2807232ab8bSKan Liang 	int nr = 0;
2817232ab8bSKan Liang 
2827232ab8bSKan Liang 	/*
2837232ab8bSKan Liang 	 * All events in a group must be scheduled simultaneously.
2847232ab8bSKan Liang 	 * Check whether there is enough counters for all the events.
2857232ab8bSKan Liang 	 */
2867232ab8bSKan Liang 	for_each_sibling_event(sibling, event->group_leader) {
2877232ab8bSKan Liang 		if (!is_iommu_pmu_event(iommu_pmu, sibling) ||
2887232ab8bSKan Liang 		    sibling->state <= PERF_EVENT_STATE_OFF)
2897232ab8bSKan Liang 			continue;
2907232ab8bSKan Liang 
2917232ab8bSKan Liang 		if (++nr > iommu_pmu->num_cntr)
2927232ab8bSKan Liang 			return -EINVAL;
2937232ab8bSKan Liang 	}
2947232ab8bSKan Liang 
2957232ab8bSKan Liang 	return 0;
2967232ab8bSKan Liang }
2977232ab8bSKan Liang 
iommu_pmu_event_init(struct perf_event * event)2987232ab8bSKan Liang static int iommu_pmu_event_init(struct perf_event *event)
2997232ab8bSKan Liang {
3007232ab8bSKan Liang 	struct hw_perf_event *hwc = &event->hw;
3017232ab8bSKan Liang 
3027232ab8bSKan Liang 	if (event->attr.type != event->pmu->type)
3037232ab8bSKan Liang 		return -ENOENT;
3047232ab8bSKan Liang 
3057232ab8bSKan Liang 	/* sampling not supported */
3067232ab8bSKan Liang 	if (event->attr.sample_period)
3077232ab8bSKan Liang 		return -EINVAL;
3087232ab8bSKan Liang 
3097232ab8bSKan Liang 	if (event->cpu < 0)
3107232ab8bSKan Liang 		return -EINVAL;
3117232ab8bSKan Liang 
3127232ab8bSKan Liang 	if (iommu_pmu_validate_event(event))
3137232ab8bSKan Liang 		return -EINVAL;
3147232ab8bSKan Liang 
3157232ab8bSKan Liang 	hwc->config = iommu_event_config(event);
3167232ab8bSKan Liang 
3177232ab8bSKan Liang 	return iommu_pmu_validate_group(event);
3187232ab8bSKan Liang }
3197232ab8bSKan Liang 
iommu_pmu_event_update(struct perf_event * event)3207232ab8bSKan Liang static void iommu_pmu_event_update(struct perf_event *event)
3217232ab8bSKan Liang {
3227232ab8bSKan Liang 	struct iommu_pmu *iommu_pmu = iommu_event_to_pmu(event);
3237232ab8bSKan Liang 	struct hw_perf_event *hwc = &event->hw;
3247232ab8bSKan Liang 	u64 prev_count, new_count, delta;
3257232ab8bSKan Liang 	int shift = 64 - iommu_pmu->cntr_width;
3267232ab8bSKan Liang 
3277232ab8bSKan Liang again:
3287232ab8bSKan Liang 	prev_count = local64_read(&hwc->prev_count);
3297232ab8bSKan Liang 	new_count = dmar_readq(iommu_event_base(iommu_pmu, hwc->idx));
3307232ab8bSKan Liang 	if (local64_xchg(&hwc->prev_count, new_count) != prev_count)
3317232ab8bSKan Liang 		goto again;
3327232ab8bSKan Liang 
3337232ab8bSKan Liang 	/*
3347232ab8bSKan Liang 	 * The counter width is enumerated. Always shift the counter
3357232ab8bSKan Liang 	 * before using it.
3367232ab8bSKan Liang 	 */
3377232ab8bSKan Liang 	delta = (new_count << shift) - (prev_count << shift);
3387232ab8bSKan Liang 	delta >>= shift;
3397232ab8bSKan Liang 
3407232ab8bSKan Liang 	local64_add(delta, &event->count);
3417232ab8bSKan Liang }
3427232ab8bSKan Liang 
iommu_pmu_start(struct perf_event * event,int flags)3437232ab8bSKan Liang static void iommu_pmu_start(struct perf_event *event, int flags)
3447232ab8bSKan Liang {
3457232ab8bSKan Liang 	struct iommu_pmu *iommu_pmu = iommu_event_to_pmu(event);
3467232ab8bSKan Liang 	struct intel_iommu *iommu = iommu_pmu->iommu;
3477232ab8bSKan Liang 	struct hw_perf_event *hwc = &event->hw;
3487232ab8bSKan Liang 	u64 count;
3497232ab8bSKan Liang 
3507232ab8bSKan Liang 	if (WARN_ON_ONCE(!(hwc->state & PERF_HES_STOPPED)))
3517232ab8bSKan Liang 		return;
3527232ab8bSKan Liang 
3537232ab8bSKan Liang 	if (WARN_ON_ONCE(hwc->idx < 0 || hwc->idx >= IOMMU_PMU_IDX_MAX))
3547232ab8bSKan Liang 		return;
3557232ab8bSKan Liang 
3567232ab8bSKan Liang 	if (flags & PERF_EF_RELOAD)
3577232ab8bSKan Liang 		WARN_ON_ONCE(!(event->hw.state & PERF_HES_UPTODATE));
3587232ab8bSKan Liang 
3597232ab8bSKan Liang 	hwc->state = 0;
3607232ab8bSKan Liang 
3617232ab8bSKan Liang 	/* Always reprogram the period */
3627232ab8bSKan Liang 	count = dmar_readq(iommu_event_base(iommu_pmu, hwc->idx));
3637232ab8bSKan Liang 	local64_set((&hwc->prev_count), count);
3647232ab8bSKan Liang 
3657232ab8bSKan Liang 	/*
3667232ab8bSKan Liang 	 * The error of ecmd will be ignored.
3677232ab8bSKan Liang 	 * - The existing perf_event subsystem doesn't handle the error.
3687232ab8bSKan Liang 	 *   Only IOMMU PMU returns runtime HW error. We don't want to
3697232ab8bSKan Liang 	 *   change the existing generic interfaces for the specific case.
3707232ab8bSKan Liang 	 * - It's a corner case caused by HW, which is very unlikely to
3717232ab8bSKan Liang 	 *   happen. There is nothing SW can do.
3727232ab8bSKan Liang 	 * - The worst case is that the user will get <not count> with
3737232ab8bSKan Liang 	 *   perf command, which can give the user some hints.
3747232ab8bSKan Liang 	 */
3757232ab8bSKan Liang 	ecmd_submit_sync(iommu, DMA_ECMD_ENABLE, hwc->idx, 0);
3767232ab8bSKan Liang 
3777232ab8bSKan Liang 	perf_event_update_userpage(event);
3787232ab8bSKan Liang }
3797232ab8bSKan Liang 
iommu_pmu_stop(struct perf_event * event,int flags)3807232ab8bSKan Liang static void iommu_pmu_stop(struct perf_event *event, int flags)
3817232ab8bSKan Liang {
3827232ab8bSKan Liang 	struct iommu_pmu *iommu_pmu = iommu_event_to_pmu(event);
3837232ab8bSKan Liang 	struct intel_iommu *iommu = iommu_pmu->iommu;
3847232ab8bSKan Liang 	struct hw_perf_event *hwc = &event->hw;
3857232ab8bSKan Liang 
3867232ab8bSKan Liang 	if (!(hwc->state & PERF_HES_STOPPED)) {
3877232ab8bSKan Liang 		ecmd_submit_sync(iommu, DMA_ECMD_DISABLE, hwc->idx, 0);
3887232ab8bSKan Liang 
3897232ab8bSKan Liang 		iommu_pmu_event_update(event);
3907232ab8bSKan Liang 
3917232ab8bSKan Liang 		hwc->state |= PERF_HES_STOPPED | PERF_HES_UPTODATE;
3927232ab8bSKan Liang 	}
3937232ab8bSKan Liang }
3947232ab8bSKan Liang 
3957232ab8bSKan Liang static inline int
iommu_pmu_validate_per_cntr_event(struct iommu_pmu * iommu_pmu,int idx,struct perf_event * event)3967232ab8bSKan Liang iommu_pmu_validate_per_cntr_event(struct iommu_pmu *iommu_pmu,
3977232ab8bSKan Liang 				  int idx, struct perf_event *event)
3987232ab8bSKan Liang {
3997232ab8bSKan Liang 	u32 event_group = iommu_event_group(event->attr.config);
4007232ab8bSKan Liang 	u32 select = iommu_event_select(event->attr.config);
4017232ab8bSKan Liang 
4027232ab8bSKan Liang 	if (!(iommu_pmu->cntr_evcap[idx][event_group] & select))
4037232ab8bSKan Liang 		return -EINVAL;
4047232ab8bSKan Liang 
4057232ab8bSKan Liang 	return 0;
4067232ab8bSKan Liang }
4077232ab8bSKan Liang 
iommu_pmu_assign_event(struct iommu_pmu * iommu_pmu,struct perf_event * event)4087232ab8bSKan Liang static int iommu_pmu_assign_event(struct iommu_pmu *iommu_pmu,
4097232ab8bSKan Liang 				  struct perf_event *event)
4107232ab8bSKan Liang {
4117232ab8bSKan Liang 	struct hw_perf_event *hwc = &event->hw;
4127232ab8bSKan Liang 	int idx;
4137232ab8bSKan Liang 
4147232ab8bSKan Liang 	/*
4157232ab8bSKan Liang 	 * The counters which support limited events are usually at the end.
4167232ab8bSKan Liang 	 * Schedule them first to accommodate more events.
4177232ab8bSKan Liang 	 */
4187232ab8bSKan Liang 	for (idx = iommu_pmu->num_cntr - 1; idx >= 0; idx--) {
4197232ab8bSKan Liang 		if (test_and_set_bit(idx, iommu_pmu->used_mask))
4207232ab8bSKan Liang 			continue;
4217232ab8bSKan Liang 		/* Check per-counter event capabilities */
4227232ab8bSKan Liang 		if (!iommu_pmu_validate_per_cntr_event(iommu_pmu, idx, event))
4237232ab8bSKan Liang 			break;
4247232ab8bSKan Liang 		clear_bit(idx, iommu_pmu->used_mask);
4257232ab8bSKan Liang 	}
4267232ab8bSKan Liang 	if (idx < 0)
4277232ab8bSKan Liang 		return -EINVAL;
4287232ab8bSKan Liang 
4297232ab8bSKan Liang 	iommu_pmu->event_list[idx] = event;
4307232ab8bSKan Liang 	hwc->idx = idx;
4317232ab8bSKan Liang 
4327232ab8bSKan Liang 	/* config events */
4337232ab8bSKan Liang 	dmar_writeq(iommu_config_base(iommu_pmu, idx), hwc->config);
4347232ab8bSKan Liang 
4357232ab8bSKan Liang 	iommu_pmu_set_filter(requester_id, event->attr.config1,
4367232ab8bSKan Liang 			     IOMMU_PMU_FILTER_REQUESTER_ID, idx,
4377232ab8bSKan Liang 			     event->attr.config1);
4387232ab8bSKan Liang 	iommu_pmu_set_filter(domain, event->attr.config1,
4397232ab8bSKan Liang 			     IOMMU_PMU_FILTER_DOMAIN, idx,
4407232ab8bSKan Liang 			     event->attr.config1);
441*f3ccbb6bSXuchun Shang 	iommu_pmu_set_filter(pasid, event->attr.config2,
4427232ab8bSKan Liang 			     IOMMU_PMU_FILTER_PASID, idx,
4437232ab8bSKan Liang 			     event->attr.config1);
4447232ab8bSKan Liang 	iommu_pmu_set_filter(ats, event->attr.config2,
4457232ab8bSKan Liang 			     IOMMU_PMU_FILTER_ATS, idx,
4467232ab8bSKan Liang 			     event->attr.config1);
4477232ab8bSKan Liang 	iommu_pmu_set_filter(page_table, event->attr.config2,
4487232ab8bSKan Liang 			     IOMMU_PMU_FILTER_PAGE_TABLE, idx,
4497232ab8bSKan Liang 			     event->attr.config1);
4507232ab8bSKan Liang 
4517232ab8bSKan Liang 	return 0;
4527232ab8bSKan Liang }
4537232ab8bSKan Liang 
iommu_pmu_add(struct perf_event * event,int flags)4547232ab8bSKan Liang static int iommu_pmu_add(struct perf_event *event, int flags)
4557232ab8bSKan Liang {
4567232ab8bSKan Liang 	struct iommu_pmu *iommu_pmu = iommu_event_to_pmu(event);
4577232ab8bSKan Liang 	struct hw_perf_event *hwc = &event->hw;
4587232ab8bSKan Liang 	int ret;
4597232ab8bSKan Liang 
4607232ab8bSKan Liang 	ret = iommu_pmu_assign_event(iommu_pmu, event);
4617232ab8bSKan Liang 	if (ret < 0)
4627232ab8bSKan Liang 		return ret;
4637232ab8bSKan Liang 
4647232ab8bSKan Liang 	hwc->state = PERF_HES_UPTODATE | PERF_HES_STOPPED;
4657232ab8bSKan Liang 
4667232ab8bSKan Liang 	if (flags & PERF_EF_START)
4677232ab8bSKan Liang 		iommu_pmu_start(event, 0);
4687232ab8bSKan Liang 
4697232ab8bSKan Liang 	return 0;
4707232ab8bSKan Liang }
4717232ab8bSKan Liang 
iommu_pmu_del(struct perf_event * event,int flags)4727232ab8bSKan Liang static void iommu_pmu_del(struct perf_event *event, int flags)
4737232ab8bSKan Liang {
4747232ab8bSKan Liang 	struct iommu_pmu *iommu_pmu = iommu_event_to_pmu(event);
4757232ab8bSKan Liang 	int idx = event->hw.idx;
4767232ab8bSKan Liang 
4777232ab8bSKan Liang 	iommu_pmu_stop(event, PERF_EF_UPDATE);
4787232ab8bSKan Liang 
4797232ab8bSKan Liang 	iommu_pmu_clear_filter(IOMMU_PMU_FILTER_REQUESTER_ID, idx);
4807232ab8bSKan Liang 	iommu_pmu_clear_filter(IOMMU_PMU_FILTER_DOMAIN, idx);
4817232ab8bSKan Liang 	iommu_pmu_clear_filter(IOMMU_PMU_FILTER_PASID, idx);
4827232ab8bSKan Liang 	iommu_pmu_clear_filter(IOMMU_PMU_FILTER_ATS, idx);
4837232ab8bSKan Liang 	iommu_pmu_clear_filter(IOMMU_PMU_FILTER_PAGE_TABLE, idx);
4847232ab8bSKan Liang 
4857232ab8bSKan Liang 	iommu_pmu->event_list[idx] = NULL;
4867232ab8bSKan Liang 	event->hw.idx = -1;
4877232ab8bSKan Liang 	clear_bit(idx, iommu_pmu->used_mask);
4887232ab8bSKan Liang 
4897232ab8bSKan Liang 	perf_event_update_userpage(event);
4907232ab8bSKan Liang }
4917232ab8bSKan Liang 
iommu_pmu_enable(struct pmu * pmu)4927232ab8bSKan Liang static void iommu_pmu_enable(struct pmu *pmu)
4937232ab8bSKan Liang {
4947232ab8bSKan Liang 	struct iommu_pmu *iommu_pmu = container_of(pmu, struct iommu_pmu, pmu);
4957232ab8bSKan Liang 	struct intel_iommu *iommu = iommu_pmu->iommu;
4967232ab8bSKan Liang 
4977232ab8bSKan Liang 	ecmd_submit_sync(iommu, DMA_ECMD_UNFREEZE, 0, 0);
4987232ab8bSKan Liang }
4997232ab8bSKan Liang 
iommu_pmu_disable(struct pmu * pmu)5007232ab8bSKan Liang static void iommu_pmu_disable(struct pmu *pmu)
5017232ab8bSKan Liang {
5027232ab8bSKan Liang 	struct iommu_pmu *iommu_pmu = container_of(pmu, struct iommu_pmu, pmu);
5037232ab8bSKan Liang 	struct intel_iommu *iommu = iommu_pmu->iommu;
5047232ab8bSKan Liang 
5057232ab8bSKan Liang 	ecmd_submit_sync(iommu, DMA_ECMD_FREEZE, 0, 0);
5067232ab8bSKan Liang }
5077232ab8bSKan Liang 
iommu_pmu_counter_overflow(struct iommu_pmu * iommu_pmu)5084a0d4265SKan Liang static void iommu_pmu_counter_overflow(struct iommu_pmu *iommu_pmu)
5094a0d4265SKan Liang {
5104a0d4265SKan Liang 	struct perf_event *event;
5114a0d4265SKan Liang 	u64 status;
5124a0d4265SKan Liang 	int i;
5134a0d4265SKan Liang 
5144a0d4265SKan Liang 	/*
5154a0d4265SKan Liang 	 * Two counters may be overflowed very close. Always check
5164a0d4265SKan Liang 	 * whether there are more to handle.
5174a0d4265SKan Liang 	 */
5184a0d4265SKan Liang 	while ((status = dmar_readq(iommu_pmu->overflow))) {
5194a0d4265SKan Liang 		for_each_set_bit(i, (unsigned long *)&status, iommu_pmu->num_cntr) {
5204a0d4265SKan Liang 			/*
5214a0d4265SKan Liang 			 * Find the assigned event of the counter.
5224a0d4265SKan Liang 			 * Accumulate the value into the event->count.
5234a0d4265SKan Liang 			 */
5244a0d4265SKan Liang 			event = iommu_pmu->event_list[i];
5254a0d4265SKan Liang 			if (!event) {
5264a0d4265SKan Liang 				pr_warn_once("Cannot find the assigned event for counter %d\n", i);
5274a0d4265SKan Liang 				continue;
5284a0d4265SKan Liang 			}
5294a0d4265SKan Liang 			iommu_pmu_event_update(event);
5304a0d4265SKan Liang 		}
5314a0d4265SKan Liang 
5324a0d4265SKan Liang 		dmar_writeq(iommu_pmu->overflow, status);
5334a0d4265SKan Liang 	}
5344a0d4265SKan Liang }
5354a0d4265SKan Liang 
iommu_pmu_irq_handler(int irq,void * dev_id)5364a0d4265SKan Liang static irqreturn_t iommu_pmu_irq_handler(int irq, void *dev_id)
5374a0d4265SKan Liang {
5384a0d4265SKan Liang 	struct intel_iommu *iommu = dev_id;
5394a0d4265SKan Liang 
5404a0d4265SKan Liang 	if (!dmar_readl(iommu->reg + DMAR_PERFINTRSTS_REG))
5414a0d4265SKan Liang 		return IRQ_NONE;
5424a0d4265SKan Liang 
5434a0d4265SKan Liang 	iommu_pmu_counter_overflow(iommu->pmu);
5444a0d4265SKan Liang 
5454a0d4265SKan Liang 	/* Clear the status bit */
5464a0d4265SKan Liang 	dmar_writel(iommu->reg + DMAR_PERFINTRSTS_REG, DMA_PERFINTRSTS_PIS);
5474a0d4265SKan Liang 
5484a0d4265SKan Liang 	return IRQ_HANDLED;
5494a0d4265SKan Liang }
5504a0d4265SKan Liang 
__iommu_pmu_register(struct intel_iommu * iommu)5517232ab8bSKan Liang static int __iommu_pmu_register(struct intel_iommu *iommu)
5527232ab8bSKan Liang {
5537232ab8bSKan Liang 	struct iommu_pmu *iommu_pmu = iommu->pmu;
5547232ab8bSKan Liang 
5557232ab8bSKan Liang 	iommu_pmu->pmu.name		= iommu->name;
5567232ab8bSKan Liang 	iommu_pmu->pmu.task_ctx_nr	= perf_invalid_context;
5577232ab8bSKan Liang 	iommu_pmu->pmu.event_init	= iommu_pmu_event_init;
5587232ab8bSKan Liang 	iommu_pmu->pmu.pmu_enable	= iommu_pmu_enable;
5597232ab8bSKan Liang 	iommu_pmu->pmu.pmu_disable	= iommu_pmu_disable;
5607232ab8bSKan Liang 	iommu_pmu->pmu.add		= iommu_pmu_add;
5617232ab8bSKan Liang 	iommu_pmu->pmu.del		= iommu_pmu_del;
5627232ab8bSKan Liang 	iommu_pmu->pmu.start		= iommu_pmu_start;
5637232ab8bSKan Liang 	iommu_pmu->pmu.stop		= iommu_pmu_stop;
5647232ab8bSKan Liang 	iommu_pmu->pmu.read		= iommu_pmu_event_update;
5657232ab8bSKan Liang 	iommu_pmu->pmu.attr_groups	= iommu_pmu_attr_groups;
5667232ab8bSKan Liang 	iommu_pmu->pmu.attr_update	= iommu_pmu_attr_update;
5677232ab8bSKan Liang 	iommu_pmu->pmu.capabilities	= PERF_PMU_CAP_NO_EXCLUDE;
5687232ab8bSKan Liang 	iommu_pmu->pmu.module		= THIS_MODULE;
5697232ab8bSKan Liang 
5707232ab8bSKan Liang 	return perf_pmu_register(&iommu_pmu->pmu, iommu_pmu->pmu.name, -1);
5717232ab8bSKan Liang }
5727232ab8bSKan Liang 
573a6a5006dSKan Liang static inline void __iomem *
get_perf_reg_address(struct intel_iommu * iommu,u32 offset)574a6a5006dSKan Liang get_perf_reg_address(struct intel_iommu *iommu, u32 offset)
575a6a5006dSKan Liang {
576a6a5006dSKan Liang 	u32 off = dmar_readl(iommu->reg + offset);
577a6a5006dSKan Liang 
578a6a5006dSKan Liang 	return iommu->reg + off;
579a6a5006dSKan Liang }
580a6a5006dSKan Liang 
alloc_iommu_pmu(struct intel_iommu * iommu)581a6a5006dSKan Liang int alloc_iommu_pmu(struct intel_iommu *iommu)
582a6a5006dSKan Liang {
583a6a5006dSKan Liang 	struct iommu_pmu *iommu_pmu;
584a6a5006dSKan Liang 	int i, j, ret;
585a6a5006dSKan Liang 	u64 perfcap;
586a6a5006dSKan Liang 	u32 cap;
587a6a5006dSKan Liang 
588a6a5006dSKan Liang 	if (!ecap_pms(iommu->ecap))
589a6a5006dSKan Liang 		return 0;
590a6a5006dSKan Liang 
591a6a5006dSKan Liang 	/* The IOMMU PMU requires the ECMD support as well */
592a6a5006dSKan Liang 	if (!cap_ecmds(iommu->cap))
593a6a5006dSKan Liang 		return -ENODEV;
594a6a5006dSKan Liang 
595a6a5006dSKan Liang 	perfcap = dmar_readq(iommu->reg + DMAR_PERFCAP_REG);
596a6a5006dSKan Liang 	/* The performance monitoring is not supported. */
597a6a5006dSKan Liang 	if (!perfcap)
598a6a5006dSKan Liang 		return -ENODEV;
599a6a5006dSKan Liang 
600a6a5006dSKan Liang 	/* Sanity check for the number of the counters and event groups */
601a6a5006dSKan Liang 	if (!pcap_num_cntr(perfcap) || !pcap_num_event_group(perfcap))
602a6a5006dSKan Liang 		return -ENODEV;
603a6a5006dSKan Liang 
604a6a5006dSKan Liang 	/* The interrupt on overflow is required */
605a6a5006dSKan Liang 	if (!pcap_interrupt(perfcap))
606a6a5006dSKan Liang 		return -ENODEV;
607a6a5006dSKan Liang 
6087232ab8bSKan Liang 	/* Check required Enhanced Command Capability */
6097232ab8bSKan Liang 	if (!ecmd_has_pmu_essential(iommu))
6107232ab8bSKan Liang 		return -ENODEV;
6117232ab8bSKan Liang 
612a6a5006dSKan Liang 	iommu_pmu = kzalloc(sizeof(*iommu_pmu), GFP_KERNEL);
613a6a5006dSKan Liang 	if (!iommu_pmu)
614a6a5006dSKan Liang 		return -ENOMEM;
615a6a5006dSKan Liang 
616a6a5006dSKan Liang 	iommu_pmu->num_cntr = pcap_num_cntr(perfcap);
6177232ab8bSKan Liang 	if (iommu_pmu->num_cntr > IOMMU_PMU_IDX_MAX) {
6187232ab8bSKan Liang 		pr_warn_once("The number of IOMMU counters %d > max(%d), clipping!",
6197232ab8bSKan Liang 			     iommu_pmu->num_cntr, IOMMU_PMU_IDX_MAX);
6207232ab8bSKan Liang 		iommu_pmu->num_cntr = IOMMU_PMU_IDX_MAX;
6217232ab8bSKan Liang 	}
6227232ab8bSKan Liang 
623a6a5006dSKan Liang 	iommu_pmu->cntr_width = pcap_cntr_width(perfcap);
624a6a5006dSKan Liang 	iommu_pmu->filter = pcap_filters_mask(perfcap);
625a6a5006dSKan Liang 	iommu_pmu->cntr_stride = pcap_cntr_stride(perfcap);
626a6a5006dSKan Liang 	iommu_pmu->num_eg = pcap_num_event_group(perfcap);
627a6a5006dSKan Liang 
628a6a5006dSKan Liang 	iommu_pmu->evcap = kcalloc(iommu_pmu->num_eg, sizeof(u64), GFP_KERNEL);
629a6a5006dSKan Liang 	if (!iommu_pmu->evcap) {
630a6a5006dSKan Liang 		ret = -ENOMEM;
631a6a5006dSKan Liang 		goto free_pmu;
632a6a5006dSKan Liang 	}
633a6a5006dSKan Liang 
634a6a5006dSKan Liang 	/* Parse event group capabilities */
635a6a5006dSKan Liang 	for (i = 0; i < iommu_pmu->num_eg; i++) {
636a6a5006dSKan Liang 		u64 pcap;
637a6a5006dSKan Liang 
638a6a5006dSKan Liang 		pcap = dmar_readq(iommu->reg + DMAR_PERFEVNTCAP_REG +
639a6a5006dSKan Liang 				  i * IOMMU_PMU_CAP_REGS_STEP);
640a6a5006dSKan Liang 		iommu_pmu->evcap[i] = pecap_es(pcap);
641a6a5006dSKan Liang 	}
642a6a5006dSKan Liang 
643a6a5006dSKan Liang 	iommu_pmu->cntr_evcap = kcalloc(iommu_pmu->num_cntr, sizeof(u32 *), GFP_KERNEL);
644a6a5006dSKan Liang 	if (!iommu_pmu->cntr_evcap) {
645a6a5006dSKan Liang 		ret = -ENOMEM;
646a6a5006dSKan Liang 		goto free_pmu_evcap;
647a6a5006dSKan Liang 	}
648a6a5006dSKan Liang 	for (i = 0; i < iommu_pmu->num_cntr; i++) {
649a6a5006dSKan Liang 		iommu_pmu->cntr_evcap[i] = kcalloc(iommu_pmu->num_eg, sizeof(u32), GFP_KERNEL);
650a6a5006dSKan Liang 		if (!iommu_pmu->cntr_evcap[i]) {
651a6a5006dSKan Liang 			ret = -ENOMEM;
652a6a5006dSKan Liang 			goto free_pmu_cntr_evcap;
653a6a5006dSKan Liang 		}
654a6a5006dSKan Liang 		/*
655a6a5006dSKan Liang 		 * Set to the global capabilities, will adjust according
656a6a5006dSKan Liang 		 * to per-counter capabilities later.
657a6a5006dSKan Liang 		 */
658a6a5006dSKan Liang 		for (j = 0; j < iommu_pmu->num_eg; j++)
659a6a5006dSKan Liang 			iommu_pmu->cntr_evcap[i][j] = (u32)iommu_pmu->evcap[j];
660a6a5006dSKan Liang 	}
661a6a5006dSKan Liang 
662a6a5006dSKan Liang 	iommu_pmu->cfg_reg = get_perf_reg_address(iommu, DMAR_PERFCFGOFF_REG);
663a6a5006dSKan Liang 	iommu_pmu->cntr_reg = get_perf_reg_address(iommu, DMAR_PERFCNTROFF_REG);
664a6a5006dSKan Liang 	iommu_pmu->overflow = get_perf_reg_address(iommu, DMAR_PERFOVFOFF_REG);
665a6a5006dSKan Liang 
666a6a5006dSKan Liang 	/*
667a6a5006dSKan Liang 	 * Check per-counter capabilities. All counters should have the
668a6a5006dSKan Liang 	 * same capabilities on Interrupt on Overflow Support and Counter
669a6a5006dSKan Liang 	 * Width.
670a6a5006dSKan Liang 	 */
671a6a5006dSKan Liang 	for (i = 0; i < iommu_pmu->num_cntr; i++) {
672a6a5006dSKan Liang 		cap = dmar_readl(iommu_pmu->cfg_reg +
673a6a5006dSKan Liang 				 i * IOMMU_PMU_CFG_OFFSET +
674a6a5006dSKan Liang 				 IOMMU_PMU_CFG_CNTRCAP_OFFSET);
675a6a5006dSKan Liang 		if (!iommu_cntrcap_pcc(cap))
676a6a5006dSKan Liang 			continue;
677a6a5006dSKan Liang 
678a6a5006dSKan Liang 		/*
679a6a5006dSKan Liang 		 * It's possible that some counters have a different
680a6a5006dSKan Liang 		 * capability because of e.g., HW bug. Check the corner
681a6a5006dSKan Liang 		 * case here and simply drop those counters.
682a6a5006dSKan Liang 		 */
683a6a5006dSKan Liang 		if ((iommu_cntrcap_cw(cap) != iommu_pmu->cntr_width) ||
684a6a5006dSKan Liang 		    !iommu_cntrcap_ios(cap)) {
685a6a5006dSKan Liang 			iommu_pmu->num_cntr = i;
686a6a5006dSKan Liang 			pr_warn("PMU counter capability inconsistent, counter number reduced to %d\n",
687a6a5006dSKan Liang 				iommu_pmu->num_cntr);
688a6a5006dSKan Liang 		}
689a6a5006dSKan Liang 
690a6a5006dSKan Liang 		/* Clear the pre-defined events group */
691a6a5006dSKan Liang 		for (j = 0; j < iommu_pmu->num_eg; j++)
692a6a5006dSKan Liang 			iommu_pmu->cntr_evcap[i][j] = 0;
693a6a5006dSKan Liang 
694a6a5006dSKan Liang 		/* Override with per-counter event capabilities */
695a6a5006dSKan Liang 		for (j = 0; j < iommu_cntrcap_egcnt(cap); j++) {
696a6a5006dSKan Liang 			cap = dmar_readl(iommu_pmu->cfg_reg + i * IOMMU_PMU_CFG_OFFSET +
697a6a5006dSKan Liang 					 IOMMU_PMU_CFG_CNTREVCAP_OFFSET +
698a6a5006dSKan Liang 					 (j * IOMMU_PMU_OFF_REGS_STEP));
699a6a5006dSKan Liang 			iommu_pmu->cntr_evcap[i][iommu_event_group(cap)] = iommu_event_select(cap);
700a6a5006dSKan Liang 			/*
701a6a5006dSKan Liang 			 * Some events may only be supported by a specific counter.
702a6a5006dSKan Liang 			 * Track them in the evcap as well.
703a6a5006dSKan Liang 			 */
704a6a5006dSKan Liang 			iommu_pmu->evcap[iommu_event_group(cap)] |= iommu_event_select(cap);
705a6a5006dSKan Liang 		}
706a6a5006dSKan Liang 	}
707a6a5006dSKan Liang 
708a6a5006dSKan Liang 	iommu_pmu->iommu = iommu;
709a6a5006dSKan Liang 	iommu->pmu = iommu_pmu;
710a6a5006dSKan Liang 
711a6a5006dSKan Liang 	return 0;
712a6a5006dSKan Liang 
713a6a5006dSKan Liang free_pmu_cntr_evcap:
714a6a5006dSKan Liang 	for (i = 0; i < iommu_pmu->num_cntr; i++)
715a6a5006dSKan Liang 		kfree(iommu_pmu->cntr_evcap[i]);
716a6a5006dSKan Liang 	kfree(iommu_pmu->cntr_evcap);
717a6a5006dSKan Liang free_pmu_evcap:
718a6a5006dSKan Liang 	kfree(iommu_pmu->evcap);
719a6a5006dSKan Liang free_pmu:
720a6a5006dSKan Liang 	kfree(iommu_pmu);
721a6a5006dSKan Liang 
722a6a5006dSKan Liang 	return ret;
723a6a5006dSKan Liang }
724a6a5006dSKan Liang 
free_iommu_pmu(struct intel_iommu * iommu)725a6a5006dSKan Liang void free_iommu_pmu(struct intel_iommu *iommu)
726a6a5006dSKan Liang {
727a6a5006dSKan Liang 	struct iommu_pmu *iommu_pmu = iommu->pmu;
728a6a5006dSKan Liang 
729a6a5006dSKan Liang 	if (!iommu_pmu)
730a6a5006dSKan Liang 		return;
731a6a5006dSKan Liang 
732a6a5006dSKan Liang 	if (iommu_pmu->evcap) {
733a6a5006dSKan Liang 		int i;
734a6a5006dSKan Liang 
735a6a5006dSKan Liang 		for (i = 0; i < iommu_pmu->num_cntr; i++)
736a6a5006dSKan Liang 			kfree(iommu_pmu->cntr_evcap[i]);
737a6a5006dSKan Liang 		kfree(iommu_pmu->cntr_evcap);
738a6a5006dSKan Liang 	}
739a6a5006dSKan Liang 	kfree(iommu_pmu->evcap);
740a6a5006dSKan Liang 	kfree(iommu_pmu);
741a6a5006dSKan Liang 	iommu->pmu = NULL;
742a6a5006dSKan Liang }
7437232ab8bSKan Liang 
iommu_pmu_set_interrupt(struct intel_iommu * iommu)7444a0d4265SKan Liang static int iommu_pmu_set_interrupt(struct intel_iommu *iommu)
7454a0d4265SKan Liang {
7464a0d4265SKan Liang 	struct iommu_pmu *iommu_pmu = iommu->pmu;
7474a0d4265SKan Liang 	int irq, ret;
7484a0d4265SKan Liang 
7494a0d4265SKan Liang 	irq = dmar_alloc_hwirq(IOMMU_IRQ_ID_OFFSET_PERF + iommu->seq_id, iommu->node, iommu);
7504a0d4265SKan Liang 	if (irq <= 0)
7514a0d4265SKan Liang 		return -EINVAL;
7524a0d4265SKan Liang 
7534a0d4265SKan Liang 	snprintf(iommu_pmu->irq_name, sizeof(iommu_pmu->irq_name), "dmar%d-perf", iommu->seq_id);
7544a0d4265SKan Liang 
7554a0d4265SKan Liang 	iommu->perf_irq = irq;
7564a0d4265SKan Liang 	ret = request_threaded_irq(irq, NULL, iommu_pmu_irq_handler,
7574a0d4265SKan Liang 				   IRQF_ONESHOT, iommu_pmu->irq_name, iommu);
7584a0d4265SKan Liang 	if (ret) {
7594a0d4265SKan Liang 		dmar_free_hwirq(irq);
7604a0d4265SKan Liang 		iommu->perf_irq = 0;
7614a0d4265SKan Liang 		return ret;
7624a0d4265SKan Liang 	}
7634a0d4265SKan Liang 	return 0;
7644a0d4265SKan Liang }
7654a0d4265SKan Liang 
iommu_pmu_unset_interrupt(struct intel_iommu * iommu)7664a0d4265SKan Liang static void iommu_pmu_unset_interrupt(struct intel_iommu *iommu)
7674a0d4265SKan Liang {
7684a0d4265SKan Liang 	if (!iommu->perf_irq)
7694a0d4265SKan Liang 		return;
7704a0d4265SKan Liang 
7714a0d4265SKan Liang 	free_irq(iommu->perf_irq, iommu);
7724a0d4265SKan Liang 	dmar_free_hwirq(iommu->perf_irq);
7734a0d4265SKan Liang 	iommu->perf_irq = 0;
7744a0d4265SKan Liang }
7754a0d4265SKan Liang 
iommu_pmu_cpu_online(unsigned int cpu,struct hlist_node * node)77616812c96SKan Liang static int iommu_pmu_cpu_online(unsigned int cpu, struct hlist_node *node)
7777232ab8bSKan Liang {
77816812c96SKan Liang 	struct iommu_pmu *iommu_pmu = hlist_entry_safe(node, typeof(*iommu_pmu), cpuhp_node);
77916812c96SKan Liang 
78046284c6cSKan Liang 	if (cpumask_empty(&iommu_pmu_cpu_mask))
78146284c6cSKan Liang 		cpumask_set_cpu(cpu, &iommu_pmu_cpu_mask);
78246284c6cSKan Liang 
78316812c96SKan Liang 	if (cpumask_test_cpu(cpu, &iommu_pmu_cpu_mask))
78416812c96SKan Liang 		iommu_pmu->cpu = cpu;
78516812c96SKan Liang 
78646284c6cSKan Liang 	return 0;
78746284c6cSKan Liang }
78846284c6cSKan Liang 
iommu_pmu_cpu_offline(unsigned int cpu,struct hlist_node * node)78916812c96SKan Liang static int iommu_pmu_cpu_offline(unsigned int cpu, struct hlist_node *node)
79046284c6cSKan Liang {
79116812c96SKan Liang 	struct iommu_pmu *iommu_pmu = hlist_entry_safe(node, typeof(*iommu_pmu), cpuhp_node);
79216812c96SKan Liang 	int target = cpumask_first(&iommu_pmu_cpu_mask);
79316812c96SKan Liang 
79416812c96SKan Liang 	/*
79516812c96SKan Liang 	 * The iommu_pmu_cpu_mask has been updated when offline the CPU
79616812c96SKan Liang 	 * for the first iommu_pmu. Migrate the other iommu_pmu to the
79716812c96SKan Liang 	 * new target.
79816812c96SKan Liang 	 */
79916812c96SKan Liang 	if (target < nr_cpu_ids && target != iommu_pmu->cpu) {
80016812c96SKan Liang 		perf_pmu_migrate_context(&iommu_pmu->pmu, cpu, target);
80116812c96SKan Liang 		iommu_pmu->cpu = target;
80216812c96SKan Liang 		return 0;
80316812c96SKan Liang 	}
80446284c6cSKan Liang 
80546284c6cSKan Liang 	if (!cpumask_test_and_clear_cpu(cpu, &iommu_pmu_cpu_mask))
80646284c6cSKan Liang 		return 0;
80746284c6cSKan Liang 
80846284c6cSKan Liang 	target = cpumask_any_but(cpu_online_mask, cpu);
80946284c6cSKan Liang 
81046284c6cSKan Liang 	if (target < nr_cpu_ids)
81146284c6cSKan Liang 		cpumask_set_cpu(target, &iommu_pmu_cpu_mask);
81246284c6cSKan Liang 	else
81316812c96SKan Liang 		return 0;
81446284c6cSKan Liang 
81516812c96SKan Liang 	perf_pmu_migrate_context(&iommu_pmu->pmu, cpu, target);
81616812c96SKan Liang 	iommu_pmu->cpu = target;
81746284c6cSKan Liang 
81846284c6cSKan Liang 	return 0;
81946284c6cSKan Liang }
82046284c6cSKan Liang 
82146284c6cSKan Liang static int nr_iommu_pmu;
82216812c96SKan Liang static enum cpuhp_state iommu_cpuhp_slot;
82346284c6cSKan Liang 
iommu_pmu_cpuhp_setup(struct iommu_pmu * iommu_pmu)82446284c6cSKan Liang static int iommu_pmu_cpuhp_setup(struct iommu_pmu *iommu_pmu)
82546284c6cSKan Liang {
82646284c6cSKan Liang 	int ret;
82746284c6cSKan Liang 
82816812c96SKan Liang 	if (!nr_iommu_pmu) {
82916812c96SKan Liang 		ret = cpuhp_setup_state_multi(CPUHP_AP_ONLINE_DYN,
83046284c6cSKan Liang 					      "driver/iommu/intel/perfmon:online",
83146284c6cSKan Liang 					      iommu_pmu_cpu_online,
83246284c6cSKan Liang 					      iommu_pmu_cpu_offline);
83316812c96SKan Liang 		if (ret < 0)
83446284c6cSKan Liang 			return ret;
83516812c96SKan Liang 		iommu_cpuhp_slot = ret;
83616812c96SKan Liang 	}
83716812c96SKan Liang 
83816812c96SKan Liang 	ret = cpuhp_state_add_instance(iommu_cpuhp_slot, &iommu_pmu->cpuhp_node);
83916812c96SKan Liang 	if (ret) {
84016812c96SKan Liang 		if (!nr_iommu_pmu)
84116812c96SKan Liang 			cpuhp_remove_multi_state(iommu_cpuhp_slot);
84216812c96SKan Liang 		return ret;
84316812c96SKan Liang 	}
84416812c96SKan Liang 	nr_iommu_pmu++;
84516812c96SKan Liang 
84616812c96SKan Liang 	return 0;
84746284c6cSKan Liang }
84846284c6cSKan Liang 
iommu_pmu_cpuhp_free(struct iommu_pmu * iommu_pmu)84946284c6cSKan Liang static void iommu_pmu_cpuhp_free(struct iommu_pmu *iommu_pmu)
85046284c6cSKan Liang {
85116812c96SKan Liang 	cpuhp_state_remove_instance(iommu_cpuhp_slot, &iommu_pmu->cpuhp_node);
85216812c96SKan Liang 
85346284c6cSKan Liang 	if (--nr_iommu_pmu)
8547232ab8bSKan Liang 		return;
8557232ab8bSKan Liang 
85616812c96SKan Liang 	cpuhp_remove_multi_state(iommu_cpuhp_slot);
8577232ab8bSKan Liang }
85846284c6cSKan Liang 
iommu_pmu_register(struct intel_iommu * iommu)85946284c6cSKan Liang void iommu_pmu_register(struct intel_iommu *iommu)
86046284c6cSKan Liang {
86146284c6cSKan Liang 	struct iommu_pmu *iommu_pmu = iommu->pmu;
86246284c6cSKan Liang 
86346284c6cSKan Liang 	if (!iommu_pmu)
86446284c6cSKan Liang 		return;
86546284c6cSKan Liang 
86646284c6cSKan Liang 	if (__iommu_pmu_register(iommu))
86746284c6cSKan Liang 		goto err;
86846284c6cSKan Liang 
86946284c6cSKan Liang 	if (iommu_pmu_cpuhp_setup(iommu_pmu))
87046284c6cSKan Liang 		goto unregister;
87146284c6cSKan Liang 
8724a0d4265SKan Liang 	/* Set interrupt for overflow */
8734a0d4265SKan Liang 	if (iommu_pmu_set_interrupt(iommu))
8744a0d4265SKan Liang 		goto cpuhp_free;
8754a0d4265SKan Liang 
87646284c6cSKan Liang 	return;
87746284c6cSKan Liang 
8784a0d4265SKan Liang cpuhp_free:
8794a0d4265SKan Liang 	iommu_pmu_cpuhp_free(iommu_pmu);
88046284c6cSKan Liang unregister:
88146284c6cSKan Liang 	perf_pmu_unregister(&iommu_pmu->pmu);
88246284c6cSKan Liang err:
88346284c6cSKan Liang 	pr_err("Failed to register PMU for iommu (seq_id = %d)\n", iommu->seq_id);
88446284c6cSKan Liang 	free_iommu_pmu(iommu);
8857232ab8bSKan Liang }
8867232ab8bSKan Liang 
iommu_pmu_unregister(struct intel_iommu * iommu)8877232ab8bSKan Liang void iommu_pmu_unregister(struct intel_iommu *iommu)
8887232ab8bSKan Liang {
88946284c6cSKan Liang 	struct iommu_pmu *iommu_pmu = iommu->pmu;
89046284c6cSKan Liang 
89146284c6cSKan Liang 	if (!iommu_pmu)
89246284c6cSKan Liang 		return;
89346284c6cSKan Liang 
8944a0d4265SKan Liang 	iommu_pmu_unset_interrupt(iommu);
89546284c6cSKan Liang 	iommu_pmu_cpuhp_free(iommu_pmu);
89646284c6cSKan Liang 	perf_pmu_unregister(&iommu_pmu->pmu);
8977232ab8bSKan Liang }
898