1ad3d1902SKyung Min Park // SPDX-License-Identifier: GPL-2.0 2ad3d1902SKyung Min Park /* 3ad3d1902SKyung Min Park * cap_audit.c - audit iommu capabilities for boot time and hot plug 4ad3d1902SKyung Min Park * 5ad3d1902SKyung Min Park * Copyright (C) 2021 Intel Corporation 6ad3d1902SKyung Min Park * 7ad3d1902SKyung Min Park * Author: Kyung Min Park <kyung.min.park@intel.com> 8ad3d1902SKyung Min Park * Lu Baolu <baolu.lu@linux.intel.com> 9ad3d1902SKyung Min Park */ 10ad3d1902SKyung Min Park 11ad3d1902SKyung Min Park #define pr_fmt(fmt) "DMAR: " fmt 12ad3d1902SKyung Min Park 132585a279SLu Baolu #include "iommu.h" 14ad3d1902SKyung Min Park #include "cap_audit.h" 15ad3d1902SKyung Min Park 16ad3d1902SKyung Min Park static u64 intel_iommu_cap_sanity; 17ad3d1902SKyung Min Park static u64 intel_iommu_ecap_sanity; 18ad3d1902SKyung Min Park 19ad3d1902SKyung Min Park static inline void check_irq_capabilities(struct intel_iommu *a, 20ad3d1902SKyung Min Park struct intel_iommu *b) 21ad3d1902SKyung Min Park { 22ad3d1902SKyung Min Park CHECK_FEATURE_MISMATCH(a, b, cap, pi_support, CAP_PI_MASK); 23ad3d1902SKyung Min Park CHECK_FEATURE_MISMATCH(a, b, ecap, eim_support, ECAP_EIM_MASK); 24ad3d1902SKyung Min Park } 25ad3d1902SKyung Min Park 26ad3d1902SKyung Min Park static inline void check_dmar_capabilities(struct intel_iommu *a, 27ad3d1902SKyung Min Park struct intel_iommu *b) 28ad3d1902SKyung Min Park { 29ad3d1902SKyung Min Park MINIMAL_FEATURE_IOMMU(b, cap, CAP_MAMV_MASK); 30ad3d1902SKyung Min Park MINIMAL_FEATURE_IOMMU(b, cap, CAP_NFR_MASK); 31ad3d1902SKyung Min Park MINIMAL_FEATURE_IOMMU(b, cap, CAP_SLLPS_MASK); 32ad3d1902SKyung Min Park MINIMAL_FEATURE_IOMMU(b, cap, CAP_FRO_MASK); 33ad3d1902SKyung Min Park MINIMAL_FEATURE_IOMMU(b, cap, CAP_MGAW_MASK); 34ad3d1902SKyung Min Park MINIMAL_FEATURE_IOMMU(b, cap, CAP_SAGAW_MASK); 35ad3d1902SKyung Min Park MINIMAL_FEATURE_IOMMU(b, cap, CAP_NDOMS_MASK); 36ad3d1902SKyung Min Park MINIMAL_FEATURE_IOMMU(b, ecap, ECAP_PSS_MASK); 37ad3d1902SKyung Min Park MINIMAL_FEATURE_IOMMU(b, ecap, ECAP_MHMV_MASK); 38ad3d1902SKyung Min Park MINIMAL_FEATURE_IOMMU(b, ecap, ECAP_IRO_MASK); 39ad3d1902SKyung Min Park 40*b722cb32SYi Liu CHECK_FEATURE_MISMATCH(a, b, cap, fl5lp_support, CAP_FL5LP_MASK); 41ad3d1902SKyung Min Park CHECK_FEATURE_MISMATCH(a, b, cap, fl1gp_support, CAP_FL1GP_MASK); 42ad3d1902SKyung Min Park CHECK_FEATURE_MISMATCH(a, b, cap, read_drain, CAP_RD_MASK); 43ad3d1902SKyung Min Park CHECK_FEATURE_MISMATCH(a, b, cap, write_drain, CAP_WD_MASK); 44ad3d1902SKyung Min Park CHECK_FEATURE_MISMATCH(a, b, cap, pgsel_inv, CAP_PSI_MASK); 45ad3d1902SKyung Min Park CHECK_FEATURE_MISMATCH(a, b, cap, zlr, CAP_ZLR_MASK); 46ad3d1902SKyung Min Park CHECK_FEATURE_MISMATCH(a, b, cap, caching_mode, CAP_CM_MASK); 47ad3d1902SKyung Min Park CHECK_FEATURE_MISMATCH(a, b, cap, phmr, CAP_PHMR_MASK); 48ad3d1902SKyung Min Park CHECK_FEATURE_MISMATCH(a, b, cap, plmr, CAP_PLMR_MASK); 49ad3d1902SKyung Min Park CHECK_FEATURE_MISMATCH(a, b, cap, rwbf, CAP_RWBF_MASK); 50ad3d1902SKyung Min Park CHECK_FEATURE_MISMATCH(a, b, cap, afl, CAP_AFL_MASK); 51ad3d1902SKyung Min Park CHECK_FEATURE_MISMATCH(a, b, ecap, rps, ECAP_RPS_MASK); 52ad3d1902SKyung Min Park CHECK_FEATURE_MISMATCH(a, b, ecap, smpwc, ECAP_SMPWC_MASK); 53ad3d1902SKyung Min Park CHECK_FEATURE_MISMATCH(a, b, ecap, flts, ECAP_FLTS_MASK); 54ad3d1902SKyung Min Park CHECK_FEATURE_MISMATCH(a, b, ecap, slts, ECAP_SLTS_MASK); 55ad3d1902SKyung Min Park CHECK_FEATURE_MISMATCH(a, b, ecap, nwfs, ECAP_NWFS_MASK); 56ad3d1902SKyung Min Park CHECK_FEATURE_MISMATCH(a, b, ecap, slads, ECAP_SLADS_MASK); 57ad3d1902SKyung Min Park CHECK_FEATURE_MISMATCH(a, b, ecap, vcs, ECAP_VCS_MASK); 58ad3d1902SKyung Min Park CHECK_FEATURE_MISMATCH(a, b, ecap, smts, ECAP_SMTS_MASK); 59ad3d1902SKyung Min Park CHECK_FEATURE_MISMATCH(a, b, ecap, pds, ECAP_PDS_MASK); 60ad3d1902SKyung Min Park CHECK_FEATURE_MISMATCH(a, b, ecap, dit, ECAP_DIT_MASK); 61ad3d1902SKyung Min Park CHECK_FEATURE_MISMATCH(a, b, ecap, pasid, ECAP_PASID_MASK); 62ad3d1902SKyung Min Park CHECK_FEATURE_MISMATCH(a, b, ecap, eafs, ECAP_EAFS_MASK); 63ad3d1902SKyung Min Park CHECK_FEATURE_MISMATCH(a, b, ecap, srs, ECAP_SRS_MASK); 64ad3d1902SKyung Min Park CHECK_FEATURE_MISMATCH(a, b, ecap, ers, ECAP_ERS_MASK); 65ad3d1902SKyung Min Park CHECK_FEATURE_MISMATCH(a, b, ecap, prs, ECAP_PRS_MASK); 66ad3d1902SKyung Min Park CHECK_FEATURE_MISMATCH(a, b, ecap, nest, ECAP_NEST_MASK); 67ad3d1902SKyung Min Park CHECK_FEATURE_MISMATCH(a, b, ecap, mts, ECAP_MTS_MASK); 68ad3d1902SKyung Min Park CHECK_FEATURE_MISMATCH(a, b, ecap, sc_support, ECAP_SC_MASK); 69ad3d1902SKyung Min Park CHECK_FEATURE_MISMATCH(a, b, ecap, pass_through, ECAP_PT_MASK); 70ad3d1902SKyung Min Park CHECK_FEATURE_MISMATCH(a, b, ecap, dev_iotlb_support, ECAP_DT_MASK); 71ad3d1902SKyung Min Park CHECK_FEATURE_MISMATCH(a, b, ecap, qis, ECAP_QI_MASK); 72ad3d1902SKyung Min Park CHECK_FEATURE_MISMATCH(a, b, ecap, coherent, ECAP_C_MASK); 73ad3d1902SKyung Min Park } 74ad3d1902SKyung Min Park 75ad3d1902SKyung Min Park static int cap_audit_hotplug(struct intel_iommu *iommu, enum cap_audit_type type) 76ad3d1902SKyung Min Park { 77ad3d1902SKyung Min Park bool mismatch = false; 78ad3d1902SKyung Min Park u64 old_cap = intel_iommu_cap_sanity; 79ad3d1902SKyung Min Park u64 old_ecap = intel_iommu_ecap_sanity; 80ad3d1902SKyung Min Park 81ad3d1902SKyung Min Park if (type == CAP_AUDIT_HOTPLUG_IRQR) { 82ad3d1902SKyung Min Park CHECK_FEATURE_MISMATCH_HOTPLUG(iommu, cap, pi_support, CAP_PI_MASK); 83ad3d1902SKyung Min Park CHECK_FEATURE_MISMATCH_HOTPLUG(iommu, ecap, eim_support, ECAP_EIM_MASK); 84ad3d1902SKyung Min Park goto out; 85ad3d1902SKyung Min Park } 86ad3d1902SKyung Min Park 87*b722cb32SYi Liu CHECK_FEATURE_MISMATCH_HOTPLUG(iommu, cap, fl5lp_support, CAP_FL5LP_MASK); 88ad3d1902SKyung Min Park CHECK_FEATURE_MISMATCH_HOTPLUG(iommu, cap, fl1gp_support, CAP_FL1GP_MASK); 89ad3d1902SKyung Min Park CHECK_FEATURE_MISMATCH_HOTPLUG(iommu, cap, read_drain, CAP_RD_MASK); 90ad3d1902SKyung Min Park CHECK_FEATURE_MISMATCH_HOTPLUG(iommu, cap, write_drain, CAP_WD_MASK); 91ad3d1902SKyung Min Park CHECK_FEATURE_MISMATCH_HOTPLUG(iommu, cap, pgsel_inv, CAP_PSI_MASK); 92ad3d1902SKyung Min Park CHECK_FEATURE_MISMATCH_HOTPLUG(iommu, cap, zlr, CAP_ZLR_MASK); 93ad3d1902SKyung Min Park CHECK_FEATURE_MISMATCH_HOTPLUG(iommu, cap, caching_mode, CAP_CM_MASK); 94ad3d1902SKyung Min Park CHECK_FEATURE_MISMATCH_HOTPLUG(iommu, cap, phmr, CAP_PHMR_MASK); 95ad3d1902SKyung Min Park CHECK_FEATURE_MISMATCH_HOTPLUG(iommu, cap, plmr, CAP_PLMR_MASK); 96ad3d1902SKyung Min Park CHECK_FEATURE_MISMATCH_HOTPLUG(iommu, cap, rwbf, CAP_RWBF_MASK); 97ad3d1902SKyung Min Park CHECK_FEATURE_MISMATCH_HOTPLUG(iommu, cap, afl, CAP_AFL_MASK); 98ad3d1902SKyung Min Park CHECK_FEATURE_MISMATCH_HOTPLUG(iommu, ecap, rps, ECAP_RPS_MASK); 99ad3d1902SKyung Min Park CHECK_FEATURE_MISMATCH_HOTPLUG(iommu, ecap, smpwc, ECAP_SMPWC_MASK); 100ad3d1902SKyung Min Park CHECK_FEATURE_MISMATCH_HOTPLUG(iommu, ecap, flts, ECAP_FLTS_MASK); 101ad3d1902SKyung Min Park CHECK_FEATURE_MISMATCH_HOTPLUG(iommu, ecap, slts, ECAP_SLTS_MASK); 102ad3d1902SKyung Min Park CHECK_FEATURE_MISMATCH_HOTPLUG(iommu, ecap, nwfs, ECAP_NWFS_MASK); 103ad3d1902SKyung Min Park CHECK_FEATURE_MISMATCH_HOTPLUG(iommu, ecap, slads, ECAP_SLADS_MASK); 104ad3d1902SKyung Min Park CHECK_FEATURE_MISMATCH_HOTPLUG(iommu, ecap, vcs, ECAP_VCS_MASK); 105ad3d1902SKyung Min Park CHECK_FEATURE_MISMATCH_HOTPLUG(iommu, ecap, smts, ECAP_SMTS_MASK); 106ad3d1902SKyung Min Park CHECK_FEATURE_MISMATCH_HOTPLUG(iommu, ecap, pds, ECAP_PDS_MASK); 107ad3d1902SKyung Min Park CHECK_FEATURE_MISMATCH_HOTPLUG(iommu, ecap, dit, ECAP_DIT_MASK); 108ad3d1902SKyung Min Park CHECK_FEATURE_MISMATCH_HOTPLUG(iommu, ecap, pasid, ECAP_PASID_MASK); 109ad3d1902SKyung Min Park CHECK_FEATURE_MISMATCH_HOTPLUG(iommu, ecap, eafs, ECAP_EAFS_MASK); 110ad3d1902SKyung Min Park CHECK_FEATURE_MISMATCH_HOTPLUG(iommu, ecap, srs, ECAP_SRS_MASK); 111ad3d1902SKyung Min Park CHECK_FEATURE_MISMATCH_HOTPLUG(iommu, ecap, ers, ECAP_ERS_MASK); 112ad3d1902SKyung Min Park CHECK_FEATURE_MISMATCH_HOTPLUG(iommu, ecap, prs, ECAP_PRS_MASK); 113ad3d1902SKyung Min Park CHECK_FEATURE_MISMATCH_HOTPLUG(iommu, ecap, nest, ECAP_NEST_MASK); 114ad3d1902SKyung Min Park CHECK_FEATURE_MISMATCH_HOTPLUG(iommu, ecap, mts, ECAP_MTS_MASK); 115ad3d1902SKyung Min Park CHECK_FEATURE_MISMATCH_HOTPLUG(iommu, ecap, sc_support, ECAP_SC_MASK); 116ad3d1902SKyung Min Park CHECK_FEATURE_MISMATCH_HOTPLUG(iommu, ecap, pass_through, ECAP_PT_MASK); 117ad3d1902SKyung Min Park CHECK_FEATURE_MISMATCH_HOTPLUG(iommu, ecap, dev_iotlb_support, ECAP_DT_MASK); 118ad3d1902SKyung Min Park CHECK_FEATURE_MISMATCH_HOTPLUG(iommu, ecap, qis, ECAP_QI_MASK); 119ad3d1902SKyung Min Park CHECK_FEATURE_MISMATCH_HOTPLUG(iommu, ecap, coherent, ECAP_C_MASK); 120ad3d1902SKyung Min Park 121ad3d1902SKyung Min Park /* Abort hot plug if the hot plug iommu feature is smaller than global */ 122ad3d1902SKyung Min Park MINIMAL_FEATURE_HOTPLUG(iommu, cap, max_amask_val, CAP_MAMV_MASK, mismatch); 123ad3d1902SKyung Min Park MINIMAL_FEATURE_HOTPLUG(iommu, cap, num_fault_regs, CAP_NFR_MASK, mismatch); 124ad3d1902SKyung Min Park MINIMAL_FEATURE_HOTPLUG(iommu, cap, super_page_val, CAP_SLLPS_MASK, mismatch); 125ad3d1902SKyung Min Park MINIMAL_FEATURE_HOTPLUG(iommu, cap, fault_reg_offset, CAP_FRO_MASK, mismatch); 126ad3d1902SKyung Min Park MINIMAL_FEATURE_HOTPLUG(iommu, cap, mgaw, CAP_MGAW_MASK, mismatch); 127ad3d1902SKyung Min Park MINIMAL_FEATURE_HOTPLUG(iommu, cap, sagaw, CAP_SAGAW_MASK, mismatch); 128ad3d1902SKyung Min Park MINIMAL_FEATURE_HOTPLUG(iommu, cap, ndoms, CAP_NDOMS_MASK, mismatch); 129ad3d1902SKyung Min Park MINIMAL_FEATURE_HOTPLUG(iommu, ecap, pss, ECAP_PSS_MASK, mismatch); 130ad3d1902SKyung Min Park MINIMAL_FEATURE_HOTPLUG(iommu, ecap, max_handle_mask, ECAP_MHMV_MASK, mismatch); 131ad3d1902SKyung Min Park MINIMAL_FEATURE_HOTPLUG(iommu, ecap, iotlb_offset, ECAP_IRO_MASK, mismatch); 132ad3d1902SKyung Min Park 133ad3d1902SKyung Min Park out: 134ad3d1902SKyung Min Park if (mismatch) { 135ad3d1902SKyung Min Park intel_iommu_cap_sanity = old_cap; 136ad3d1902SKyung Min Park intel_iommu_ecap_sanity = old_ecap; 137ad3d1902SKyung Min Park return -EFAULT; 138ad3d1902SKyung Min Park } 139ad3d1902SKyung Min Park 140ad3d1902SKyung Min Park return 0; 141ad3d1902SKyung Min Park } 142ad3d1902SKyung Min Park 143ad3d1902SKyung Min Park static int cap_audit_static(struct intel_iommu *iommu, enum cap_audit_type type) 144ad3d1902SKyung Min Park { 145ad3d1902SKyung Min Park struct dmar_drhd_unit *d; 146ad3d1902SKyung Min Park struct intel_iommu *i; 1474e5973ddSChristophe JAILLET int rc = 0; 148ad3d1902SKyung Min Park 149ad3d1902SKyung Min Park rcu_read_lock(); 150ad3d1902SKyung Min Park if (list_empty(&dmar_drhd_units)) 151ad3d1902SKyung Min Park goto out; 152ad3d1902SKyung Min Park 153ad3d1902SKyung Min Park for_each_active_iommu(i, d) { 154ad3d1902SKyung Min Park if (!iommu) { 155ad3d1902SKyung Min Park intel_iommu_ecap_sanity = i->ecap; 156ad3d1902SKyung Min Park intel_iommu_cap_sanity = i->cap; 157ad3d1902SKyung Min Park iommu = i; 158ad3d1902SKyung Min Park continue; 159ad3d1902SKyung Min Park } 160ad3d1902SKyung Min Park 161ad3d1902SKyung Min Park if (type == CAP_AUDIT_STATIC_DMAR) 162ad3d1902SKyung Min Park check_dmar_capabilities(iommu, i); 163ad3d1902SKyung Min Park else 164ad3d1902SKyung Min Park check_irq_capabilities(iommu, i); 165ad3d1902SKyung Min Park } 166ad3d1902SKyung Min Park 1677afd7f6aSLu Baolu /* 1687afd7f6aSLu Baolu * If the system is sane to support scalable mode, either SL or FL 1697afd7f6aSLu Baolu * should be sane. 1707afd7f6aSLu Baolu */ 1717afd7f6aSLu Baolu if (intel_cap_smts_sanity() && 1727afd7f6aSLu Baolu !intel_cap_flts_sanity() && !intel_cap_slts_sanity()) 1734e5973ddSChristophe JAILLET rc = -EOPNOTSUPP; 1747afd7f6aSLu Baolu 175ad3d1902SKyung Min Park out: 176ad3d1902SKyung Min Park rcu_read_unlock(); 1774e5973ddSChristophe JAILLET return rc; 178ad3d1902SKyung Min Park } 179ad3d1902SKyung Min Park 180ad3d1902SKyung Min Park int intel_cap_audit(enum cap_audit_type type, struct intel_iommu *iommu) 181ad3d1902SKyung Min Park { 182ad3d1902SKyung Min Park switch (type) { 183ad3d1902SKyung Min Park case CAP_AUDIT_STATIC_DMAR: 184ad3d1902SKyung Min Park case CAP_AUDIT_STATIC_IRQR: 185ad3d1902SKyung Min Park return cap_audit_static(iommu, type); 186ad3d1902SKyung Min Park case CAP_AUDIT_HOTPLUG_DMAR: 187ad3d1902SKyung Min Park case CAP_AUDIT_HOTPLUG_IRQR: 188ad3d1902SKyung Min Park return cap_audit_hotplug(iommu, type); 189ad3d1902SKyung Min Park default: 190ad3d1902SKyung Min Park break; 191ad3d1902SKyung Min Park } 192ad3d1902SKyung Min Park 193ad3d1902SKyung Min Park return -EFAULT; 194ad3d1902SKyung Min Park } 195010bf565SKyung Min Park 196010bf565SKyung Min Park bool intel_cap_smts_sanity(void) 197010bf565SKyung Min Park { 198010bf565SKyung Min Park return ecap_smts(intel_iommu_ecap_sanity); 199010bf565SKyung Min Park } 200010bf565SKyung Min Park 201010bf565SKyung Min Park bool intel_cap_pasid_sanity(void) 202010bf565SKyung Min Park { 203010bf565SKyung Min Park return ecap_pasid(intel_iommu_ecap_sanity); 204010bf565SKyung Min Park } 205010bf565SKyung Min Park 206010bf565SKyung Min Park bool intel_cap_nest_sanity(void) 207010bf565SKyung Min Park { 208010bf565SKyung Min Park return ecap_nest(intel_iommu_ecap_sanity); 209010bf565SKyung Min Park } 210010bf565SKyung Min Park 211010bf565SKyung Min Park bool intel_cap_flts_sanity(void) 212010bf565SKyung Min Park { 213010bf565SKyung Min Park return ecap_flts(intel_iommu_ecap_sanity); 214010bf565SKyung Min Park } 2157afd7f6aSLu Baolu 2167afd7f6aSLu Baolu bool intel_cap_slts_sanity(void) 2177afd7f6aSLu Baolu { 2187afd7f6aSLu Baolu return ecap_slts(intel_iommu_ecap_sanity); 2197afd7f6aSLu Baolu } 220