162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * cap_audit.h - audit iommu capabilities header
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2021 Intel Corporation
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Author: Kyung Min Park <kyung.min.park@intel.com>
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci/*
1162306a36Sopenharmony_ci * Capability Register Mask
1262306a36Sopenharmony_ci */
1362306a36Sopenharmony_ci#define CAP_FL5LP_MASK		BIT_ULL(60)
1462306a36Sopenharmony_ci#define CAP_PI_MASK		BIT_ULL(59)
1562306a36Sopenharmony_ci#define CAP_FL1GP_MASK		BIT_ULL(56)
1662306a36Sopenharmony_ci#define CAP_RD_MASK		BIT_ULL(55)
1762306a36Sopenharmony_ci#define CAP_WD_MASK		BIT_ULL(54)
1862306a36Sopenharmony_ci#define CAP_MAMV_MASK		GENMASK_ULL(53, 48)
1962306a36Sopenharmony_ci#define CAP_NFR_MASK		GENMASK_ULL(47, 40)
2062306a36Sopenharmony_ci#define CAP_PSI_MASK		BIT_ULL(39)
2162306a36Sopenharmony_ci#define CAP_SLLPS_MASK		GENMASK_ULL(37, 34)
2262306a36Sopenharmony_ci#define CAP_FRO_MASK		GENMASK_ULL(33, 24)
2362306a36Sopenharmony_ci#define CAP_ZLR_MASK		BIT_ULL(22)
2462306a36Sopenharmony_ci#define CAP_MGAW_MASK		GENMASK_ULL(21, 16)
2562306a36Sopenharmony_ci#define CAP_SAGAW_MASK		GENMASK_ULL(12, 8)
2662306a36Sopenharmony_ci#define CAP_CM_MASK		BIT_ULL(7)
2762306a36Sopenharmony_ci#define CAP_PHMR_MASK		BIT_ULL(6)
2862306a36Sopenharmony_ci#define CAP_PLMR_MASK		BIT_ULL(5)
2962306a36Sopenharmony_ci#define CAP_RWBF_MASK		BIT_ULL(4)
3062306a36Sopenharmony_ci#define CAP_AFL_MASK		BIT_ULL(3)
3162306a36Sopenharmony_ci#define CAP_NDOMS_MASK		GENMASK_ULL(2, 0)
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci/*
3462306a36Sopenharmony_ci * Extended Capability Register Mask
3562306a36Sopenharmony_ci */
3662306a36Sopenharmony_ci#define ECAP_RPS_MASK		BIT_ULL(49)
3762306a36Sopenharmony_ci#define ECAP_SMPWC_MASK		BIT_ULL(48)
3862306a36Sopenharmony_ci#define ECAP_FLTS_MASK		BIT_ULL(47)
3962306a36Sopenharmony_ci#define ECAP_SLTS_MASK		BIT_ULL(46)
4062306a36Sopenharmony_ci#define ECAP_SLADS_MASK		BIT_ULL(45)
4162306a36Sopenharmony_ci#define ECAP_VCS_MASK		BIT_ULL(44)
4262306a36Sopenharmony_ci#define ECAP_SMTS_MASK		BIT_ULL(43)
4362306a36Sopenharmony_ci#define ECAP_PDS_MASK		BIT_ULL(42)
4462306a36Sopenharmony_ci#define ECAP_DIT_MASK		BIT_ULL(41)
4562306a36Sopenharmony_ci#define ECAP_PASID_MASK		BIT_ULL(40)
4662306a36Sopenharmony_ci#define ECAP_PSS_MASK		GENMASK_ULL(39, 35)
4762306a36Sopenharmony_ci#define ECAP_EAFS_MASK		BIT_ULL(34)
4862306a36Sopenharmony_ci#define ECAP_NWFS_MASK		BIT_ULL(33)
4962306a36Sopenharmony_ci#define ECAP_SRS_MASK		BIT_ULL(31)
5062306a36Sopenharmony_ci#define ECAP_ERS_MASK		BIT_ULL(30)
5162306a36Sopenharmony_ci#define ECAP_PRS_MASK		BIT_ULL(29)
5262306a36Sopenharmony_ci#define ECAP_NEST_MASK		BIT_ULL(26)
5362306a36Sopenharmony_ci#define ECAP_MTS_MASK		BIT_ULL(25)
5462306a36Sopenharmony_ci#define ECAP_MHMV_MASK		GENMASK_ULL(23, 20)
5562306a36Sopenharmony_ci#define ECAP_IRO_MASK		GENMASK_ULL(17, 8)
5662306a36Sopenharmony_ci#define ECAP_SC_MASK		BIT_ULL(7)
5762306a36Sopenharmony_ci#define ECAP_PT_MASK		BIT_ULL(6)
5862306a36Sopenharmony_ci#define ECAP_EIM_MASK		BIT_ULL(4)
5962306a36Sopenharmony_ci#define ECAP_DT_MASK		BIT_ULL(2)
6062306a36Sopenharmony_ci#define ECAP_QI_MASK		BIT_ULL(1)
6162306a36Sopenharmony_ci#define ECAP_C_MASK		BIT_ULL(0)
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci/*
6462306a36Sopenharmony_ci * u64 intel_iommu_cap_sanity, intel_iommu_ecap_sanity will be adjusted as each
6562306a36Sopenharmony_ci * IOMMU gets audited.
6662306a36Sopenharmony_ci */
6762306a36Sopenharmony_ci#define DO_CHECK_FEATURE_MISMATCH(a, b, cap, feature, MASK) \
6862306a36Sopenharmony_cido { \
6962306a36Sopenharmony_ci	if (cap##_##feature(a) != cap##_##feature(b)) { \
7062306a36Sopenharmony_ci		intel_iommu_##cap##_sanity &= ~(MASK); \
7162306a36Sopenharmony_ci		pr_info("IOMMU feature %s inconsistent", #feature); \
7262306a36Sopenharmony_ci	} \
7362306a36Sopenharmony_ci} while (0)
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci#define CHECK_FEATURE_MISMATCH(a, b, cap, feature, MASK) \
7662306a36Sopenharmony_ci	DO_CHECK_FEATURE_MISMATCH((a)->cap, (b)->cap, cap, feature, MASK)
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci#define CHECK_FEATURE_MISMATCH_HOTPLUG(b, cap, feature, MASK) \
7962306a36Sopenharmony_cido { \
8062306a36Sopenharmony_ci	if (cap##_##feature(intel_iommu_##cap##_sanity)) \
8162306a36Sopenharmony_ci		DO_CHECK_FEATURE_MISMATCH(intel_iommu_##cap##_sanity, \
8262306a36Sopenharmony_ci					  (b)->cap, cap, feature, MASK); \
8362306a36Sopenharmony_ci} while (0)
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci#define MINIMAL_FEATURE_IOMMU(iommu, cap, MASK) \
8662306a36Sopenharmony_cido { \
8762306a36Sopenharmony_ci	u64 min_feature = intel_iommu_##cap##_sanity & (MASK); \
8862306a36Sopenharmony_ci	min_feature = min_t(u64, min_feature, (iommu)->cap & (MASK)); \
8962306a36Sopenharmony_ci	intel_iommu_##cap##_sanity = (intel_iommu_##cap##_sanity & ~(MASK)) | \
9062306a36Sopenharmony_ci				     min_feature; \
9162306a36Sopenharmony_ci} while (0)
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci#define MINIMAL_FEATURE_HOTPLUG(iommu, cap, feature, MASK, mismatch) \
9462306a36Sopenharmony_cido { \
9562306a36Sopenharmony_ci	if ((intel_iommu_##cap##_sanity & (MASK)) > \
9662306a36Sopenharmony_ci	    (cap##_##feature((iommu)->cap))) \
9762306a36Sopenharmony_ci		mismatch = true; \
9862306a36Sopenharmony_ci	else \
9962306a36Sopenharmony_ci		(iommu)->cap = ((iommu)->cap & ~(MASK)) | \
10062306a36Sopenharmony_ci		(intel_iommu_##cap##_sanity & (MASK)); \
10162306a36Sopenharmony_ci} while (0)
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_cienum cap_audit_type {
10462306a36Sopenharmony_ci	CAP_AUDIT_STATIC_DMAR,
10562306a36Sopenharmony_ci	CAP_AUDIT_STATIC_IRQR,
10662306a36Sopenharmony_ci	CAP_AUDIT_HOTPLUG_DMAR,
10762306a36Sopenharmony_ci	CAP_AUDIT_HOTPLUG_IRQR,
10862306a36Sopenharmony_ci};
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_cibool intel_cap_smts_sanity(void);
11162306a36Sopenharmony_cibool intel_cap_pasid_sanity(void);
11262306a36Sopenharmony_cibool intel_cap_nest_sanity(void);
11362306a36Sopenharmony_cibool intel_cap_flts_sanity(void);
11462306a36Sopenharmony_cibool intel_cap_slts_sanity(void);
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_cistatic inline bool scalable_mode_support(void)
11762306a36Sopenharmony_ci{
11862306a36Sopenharmony_ci	return (intel_iommu_sm && intel_cap_smts_sanity());
11962306a36Sopenharmony_ci}
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_cistatic inline bool pasid_mode_support(void)
12262306a36Sopenharmony_ci{
12362306a36Sopenharmony_ci	return scalable_mode_support() && intel_cap_pasid_sanity();
12462306a36Sopenharmony_ci}
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_cistatic inline bool nested_mode_support(void)
12762306a36Sopenharmony_ci{
12862306a36Sopenharmony_ci	return scalable_mode_support() && intel_cap_nest_sanity();
12962306a36Sopenharmony_ci}
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ciint intel_cap_audit(enum cap_audit_type type, struct intel_iommu *iommu);
132