--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * cap_audit.c - audit iommu capabilities for boot time and hot plug
+ *
+ * Copyright (C) 2021 Intel Corporation
+ *
+ * Author: Kyung Min Park <kyung.min.park@intel.com>
+ *         Lu Baolu <baolu.lu@linux.intel.com>
+ */
+
+#define pr_fmt(fmt)    "DMAR: " fmt
+
+#include <linux/intel-iommu.h>
+#include "cap_audit.h"
+
+static u64 intel_iommu_cap_sanity;
+static u64 intel_iommu_ecap_sanity;
+
+static inline void check_irq_capabilities(struct intel_iommu *a,
+                                         struct intel_iommu *b)
+{
+       CHECK_FEATURE_MISMATCH(a, b, cap, pi_support, CAP_PI_MASK);
+       CHECK_FEATURE_MISMATCH(a, b, ecap, eim_support, ECAP_EIM_MASK);
+}
+
+static inline void check_dmar_capabilities(struct intel_iommu *a,
+                                          struct intel_iommu *b)
+{
+       MINIMAL_FEATURE_IOMMU(b, cap, CAP_MAMV_MASK);
+       MINIMAL_FEATURE_IOMMU(b, cap, CAP_NFR_MASK);
+       MINIMAL_FEATURE_IOMMU(b, cap, CAP_SLLPS_MASK);
+       MINIMAL_FEATURE_IOMMU(b, cap, CAP_FRO_MASK);
+       MINIMAL_FEATURE_IOMMU(b, cap, CAP_MGAW_MASK);
+       MINIMAL_FEATURE_IOMMU(b, cap, CAP_SAGAW_MASK);
+       MINIMAL_FEATURE_IOMMU(b, cap, CAP_NDOMS_MASK);
+       MINIMAL_FEATURE_IOMMU(b, ecap, ECAP_PSS_MASK);
+       MINIMAL_FEATURE_IOMMU(b, ecap, ECAP_MHMV_MASK);
+       MINIMAL_FEATURE_IOMMU(b, ecap, ECAP_IRO_MASK);
+
+       CHECK_FEATURE_MISMATCH(a, b, cap, 5lp_support, CAP_FL5LP_MASK);
+       CHECK_FEATURE_MISMATCH(a, b, cap, fl1gp_support, CAP_FL1GP_MASK);
+       CHECK_FEATURE_MISMATCH(a, b, cap, read_drain, CAP_RD_MASK);
+       CHECK_FEATURE_MISMATCH(a, b, cap, write_drain, CAP_WD_MASK);
+       CHECK_FEATURE_MISMATCH(a, b, cap, pgsel_inv, CAP_PSI_MASK);
+       CHECK_FEATURE_MISMATCH(a, b, cap, zlr, CAP_ZLR_MASK);
+       CHECK_FEATURE_MISMATCH(a, b, cap, caching_mode, CAP_CM_MASK);
+       CHECK_FEATURE_MISMATCH(a, b, cap, phmr, CAP_PHMR_MASK);
+       CHECK_FEATURE_MISMATCH(a, b, cap, plmr, CAP_PLMR_MASK);
+       CHECK_FEATURE_MISMATCH(a, b, cap, rwbf, CAP_RWBF_MASK);
+       CHECK_FEATURE_MISMATCH(a, b, cap, afl, CAP_AFL_MASK);
+       CHECK_FEATURE_MISMATCH(a, b, ecap, rps, ECAP_RPS_MASK);
+       CHECK_FEATURE_MISMATCH(a, b, ecap, smpwc, ECAP_SMPWC_MASK);
+       CHECK_FEATURE_MISMATCH(a, b, ecap, flts, ECAP_FLTS_MASK);
+       CHECK_FEATURE_MISMATCH(a, b, ecap, slts, ECAP_SLTS_MASK);
+       CHECK_FEATURE_MISMATCH(a, b, ecap, nwfs, ECAP_NWFS_MASK);
+       CHECK_FEATURE_MISMATCH(a, b, ecap, slads, ECAP_SLADS_MASK);
+       CHECK_FEATURE_MISMATCH(a, b, ecap, vcs, ECAP_VCS_MASK);
+       CHECK_FEATURE_MISMATCH(a, b, ecap, smts, ECAP_SMTS_MASK);
+       CHECK_FEATURE_MISMATCH(a, b, ecap, pds, ECAP_PDS_MASK);
+       CHECK_FEATURE_MISMATCH(a, b, ecap, dit, ECAP_DIT_MASK);
+       CHECK_FEATURE_MISMATCH(a, b, ecap, pasid, ECAP_PASID_MASK);
+       CHECK_FEATURE_MISMATCH(a, b, ecap, eafs, ECAP_EAFS_MASK);
+       CHECK_FEATURE_MISMATCH(a, b, ecap, srs, ECAP_SRS_MASK);
+       CHECK_FEATURE_MISMATCH(a, b, ecap, ers, ECAP_ERS_MASK);
+       CHECK_FEATURE_MISMATCH(a, b, ecap, prs, ECAP_PRS_MASK);
+       CHECK_FEATURE_MISMATCH(a, b, ecap, nest, ECAP_NEST_MASK);
+       CHECK_FEATURE_MISMATCH(a, b, ecap, mts, ECAP_MTS_MASK);
+       CHECK_FEATURE_MISMATCH(a, b, ecap, sc_support, ECAP_SC_MASK);
+       CHECK_FEATURE_MISMATCH(a, b, ecap, pass_through, ECAP_PT_MASK);
+       CHECK_FEATURE_MISMATCH(a, b, ecap, dev_iotlb_support, ECAP_DT_MASK);
+       CHECK_FEATURE_MISMATCH(a, b, ecap, qis, ECAP_QI_MASK);
+       CHECK_FEATURE_MISMATCH(a, b, ecap, coherent, ECAP_C_MASK);
+}
+
+static int cap_audit_hotplug(struct intel_iommu *iommu, enum cap_audit_type type)
+{
+       bool mismatch = false;
+       u64 old_cap = intel_iommu_cap_sanity;
+       u64 old_ecap = intel_iommu_ecap_sanity;
+
+       if (type == CAP_AUDIT_HOTPLUG_IRQR) {
+               CHECK_FEATURE_MISMATCH_HOTPLUG(iommu, cap, pi_support, CAP_PI_MASK);
+               CHECK_FEATURE_MISMATCH_HOTPLUG(iommu, ecap, eim_support, ECAP_EIM_MASK);
+               goto out;
+       }
+
+       CHECK_FEATURE_MISMATCH_HOTPLUG(iommu, cap, 5lp_support, CAP_FL5LP_MASK);
+       CHECK_FEATURE_MISMATCH_HOTPLUG(iommu, cap, fl1gp_support, CAP_FL1GP_MASK);
+       CHECK_FEATURE_MISMATCH_HOTPLUG(iommu, cap, read_drain, CAP_RD_MASK);
+       CHECK_FEATURE_MISMATCH_HOTPLUG(iommu, cap, write_drain, CAP_WD_MASK);
+       CHECK_FEATURE_MISMATCH_HOTPLUG(iommu, cap, pgsel_inv, CAP_PSI_MASK);
+       CHECK_FEATURE_MISMATCH_HOTPLUG(iommu, cap, zlr, CAP_ZLR_MASK);
+       CHECK_FEATURE_MISMATCH_HOTPLUG(iommu, cap, caching_mode, CAP_CM_MASK);
+       CHECK_FEATURE_MISMATCH_HOTPLUG(iommu, cap, phmr, CAP_PHMR_MASK);
+       CHECK_FEATURE_MISMATCH_HOTPLUG(iommu, cap, plmr, CAP_PLMR_MASK);
+       CHECK_FEATURE_MISMATCH_HOTPLUG(iommu, cap, rwbf, CAP_RWBF_MASK);
+       CHECK_FEATURE_MISMATCH_HOTPLUG(iommu, cap, afl, CAP_AFL_MASK);
+       CHECK_FEATURE_MISMATCH_HOTPLUG(iommu, ecap, rps, ECAP_RPS_MASK);
+       CHECK_FEATURE_MISMATCH_HOTPLUG(iommu, ecap, smpwc, ECAP_SMPWC_MASK);
+       CHECK_FEATURE_MISMATCH_HOTPLUG(iommu, ecap, flts, ECAP_FLTS_MASK);
+       CHECK_FEATURE_MISMATCH_HOTPLUG(iommu, ecap, slts, ECAP_SLTS_MASK);
+       CHECK_FEATURE_MISMATCH_HOTPLUG(iommu, ecap, nwfs, ECAP_NWFS_MASK);
+       CHECK_FEATURE_MISMATCH_HOTPLUG(iommu, ecap, slads, ECAP_SLADS_MASK);
+       CHECK_FEATURE_MISMATCH_HOTPLUG(iommu, ecap, vcs, ECAP_VCS_MASK);
+       CHECK_FEATURE_MISMATCH_HOTPLUG(iommu, ecap, smts, ECAP_SMTS_MASK);
+       CHECK_FEATURE_MISMATCH_HOTPLUG(iommu, ecap, pds, ECAP_PDS_MASK);
+       CHECK_FEATURE_MISMATCH_HOTPLUG(iommu, ecap, dit, ECAP_DIT_MASK);
+       CHECK_FEATURE_MISMATCH_HOTPLUG(iommu, ecap, pasid, ECAP_PASID_MASK);
+       CHECK_FEATURE_MISMATCH_HOTPLUG(iommu, ecap, eafs, ECAP_EAFS_MASK);
+       CHECK_FEATURE_MISMATCH_HOTPLUG(iommu, ecap, srs, ECAP_SRS_MASK);
+       CHECK_FEATURE_MISMATCH_HOTPLUG(iommu, ecap, ers, ECAP_ERS_MASK);
+       CHECK_FEATURE_MISMATCH_HOTPLUG(iommu, ecap, prs, ECAP_PRS_MASK);
+       CHECK_FEATURE_MISMATCH_HOTPLUG(iommu, ecap, nest, ECAP_NEST_MASK);
+       CHECK_FEATURE_MISMATCH_HOTPLUG(iommu, ecap, mts, ECAP_MTS_MASK);
+       CHECK_FEATURE_MISMATCH_HOTPLUG(iommu, ecap, sc_support, ECAP_SC_MASK);
+       CHECK_FEATURE_MISMATCH_HOTPLUG(iommu, ecap, pass_through, ECAP_PT_MASK);
+       CHECK_FEATURE_MISMATCH_HOTPLUG(iommu, ecap, dev_iotlb_support, ECAP_DT_MASK);
+       CHECK_FEATURE_MISMATCH_HOTPLUG(iommu, ecap, qis, ECAP_QI_MASK);
+       CHECK_FEATURE_MISMATCH_HOTPLUG(iommu, ecap, coherent, ECAP_C_MASK);
+
+       /* Abort hot plug if the hot plug iommu feature is smaller than global */
+       MINIMAL_FEATURE_HOTPLUG(iommu, cap, max_amask_val, CAP_MAMV_MASK, mismatch);
+       MINIMAL_FEATURE_HOTPLUG(iommu, cap, num_fault_regs, CAP_NFR_MASK, mismatch);
+       MINIMAL_FEATURE_HOTPLUG(iommu, cap, super_page_val, CAP_SLLPS_MASK, mismatch);
+       MINIMAL_FEATURE_HOTPLUG(iommu, cap, fault_reg_offset, CAP_FRO_MASK, mismatch);
+       MINIMAL_FEATURE_HOTPLUG(iommu, cap, mgaw, CAP_MGAW_MASK, mismatch);
+       MINIMAL_FEATURE_HOTPLUG(iommu, cap, sagaw, CAP_SAGAW_MASK, mismatch);
+       MINIMAL_FEATURE_HOTPLUG(iommu, cap, ndoms, CAP_NDOMS_MASK, mismatch);
+       MINIMAL_FEATURE_HOTPLUG(iommu, ecap, pss, ECAP_PSS_MASK, mismatch);
+       MINIMAL_FEATURE_HOTPLUG(iommu, ecap, max_handle_mask, ECAP_MHMV_MASK, mismatch);
+       MINIMAL_FEATURE_HOTPLUG(iommu, ecap, iotlb_offset, ECAP_IRO_MASK, mismatch);
+
+out:
+       if (mismatch) {
+               intel_iommu_cap_sanity = old_cap;
+               intel_iommu_ecap_sanity = old_ecap;
+               return -EFAULT;
+       }
+
+       return 0;
+}
+
+static int cap_audit_static(struct intel_iommu *iommu, enum cap_audit_type type)
+{
+       struct dmar_drhd_unit *d;
+       struct intel_iommu *i;
+
+       rcu_read_lock();
+       if (list_empty(&dmar_drhd_units))
+               goto out;
+
+       for_each_active_iommu(i, d) {
+               if (!iommu) {
+                       intel_iommu_ecap_sanity = i->ecap;
+                       intel_iommu_cap_sanity = i->cap;
+                       iommu = i;
+                       continue;
+               }
+
+               if (type == CAP_AUDIT_STATIC_DMAR)
+                       check_dmar_capabilities(iommu, i);
+               else
+                       check_irq_capabilities(iommu, i);
+       }
+
+out:
+       rcu_read_unlock();
+       return 0;
+}
+
+int intel_cap_audit(enum cap_audit_type type, struct intel_iommu *iommu)
+{
+       switch (type) {
+       case CAP_AUDIT_STATIC_DMAR:
+       case CAP_AUDIT_STATIC_IRQR:
+               return cap_audit_static(iommu, type);
+       case CAP_AUDIT_HOTPLUG_DMAR:
+       case CAP_AUDIT_HOTPLUG_IRQR:
+               return cap_audit_hotplug(iommu, type);
+       default:
+               break;
+       }
+
+       return -EFAULT;
+}
 
--- /dev/null
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * cap_audit.h - audit iommu capabilities header
+ *
+ * Copyright (C) 2021 Intel Corporation
+ *
+ * Author: Kyung Min Park <kyung.min.park@intel.com>
+ */
+
+/*
+ * Capability Register Mask
+ */
+#define CAP_FL5LP_MASK         BIT_ULL(60)
+#define CAP_PI_MASK            BIT_ULL(59)
+#define CAP_FL1GP_MASK         BIT_ULL(56)
+#define CAP_RD_MASK            BIT_ULL(55)
+#define CAP_WD_MASK            BIT_ULL(54)
+#define CAP_MAMV_MASK          GENMASK_ULL(53, 48)
+#define CAP_NFR_MASK           GENMASK_ULL(47, 40)
+#define CAP_PSI_MASK           BIT_ULL(39)
+#define CAP_SLLPS_MASK         GENMASK_ULL(37, 34)
+#define CAP_FRO_MASK           GENMASK_ULL(33, 24)
+#define CAP_ZLR_MASK           BIT_ULL(22)
+#define CAP_MGAW_MASK          GENMASK_ULL(21, 16)
+#define CAP_SAGAW_MASK         GENMASK_ULL(12, 8)
+#define CAP_CM_MASK            BIT_ULL(7)
+#define CAP_PHMR_MASK          BIT_ULL(6)
+#define CAP_PLMR_MASK          BIT_ULL(5)
+#define CAP_RWBF_MASK          BIT_ULL(4)
+#define CAP_AFL_MASK           BIT_ULL(3)
+#define CAP_NDOMS_MASK         GENMASK_ULL(2, 0)
+
+/*
+ * Extended Capability Register Mask
+ */
+#define ECAP_RPS_MASK          BIT_ULL(49)
+#define ECAP_SMPWC_MASK                BIT_ULL(48)
+#define ECAP_FLTS_MASK         BIT_ULL(47)
+#define ECAP_SLTS_MASK         BIT_ULL(46)
+#define ECAP_SLADS_MASK                BIT_ULL(45)
+#define ECAP_VCS_MASK          BIT_ULL(44)
+#define ECAP_SMTS_MASK         BIT_ULL(43)
+#define ECAP_PDS_MASK          BIT_ULL(42)
+#define ECAP_DIT_MASK          BIT_ULL(41)
+#define ECAP_PASID_MASK                BIT_ULL(40)
+#define ECAP_PSS_MASK          GENMASK_ULL(39, 35)
+#define ECAP_EAFS_MASK         BIT_ULL(34)
+#define ECAP_NWFS_MASK         BIT_ULL(33)
+#define ECAP_SRS_MASK          BIT_ULL(31)
+#define ECAP_ERS_MASK          BIT_ULL(30)
+#define ECAP_PRS_MASK          BIT_ULL(29)
+#define ECAP_NEST_MASK         BIT_ULL(26)
+#define ECAP_MTS_MASK          BIT_ULL(25)
+#define ECAP_MHMV_MASK         GENMASK_ULL(23, 20)
+#define ECAP_IRO_MASK          GENMASK_ULL(17, 8)
+#define ECAP_SC_MASK           BIT_ULL(7)
+#define ECAP_PT_MASK           BIT_ULL(6)
+#define ECAP_EIM_MASK          BIT_ULL(4)
+#define ECAP_DT_MASK           BIT_ULL(2)
+#define ECAP_QI_MASK           BIT_ULL(1)
+#define ECAP_C_MASK            BIT_ULL(0)
+
+/*
+ * u64 intel_iommu_cap_sanity, intel_iommu_ecap_sanity will be adjusted as each
+ * IOMMU gets audited.
+ */
+#define DO_CHECK_FEATURE_MISMATCH(a, b, cap, feature, MASK) \
+do { \
+       if (cap##_##feature(a) != cap##_##feature(b)) { \
+               intel_iommu_##cap##_sanity &= ~(MASK); \
+               pr_info("IOMMU feature %s inconsistent", #feature); \
+       } \
+} while (0)
+
+#define CHECK_FEATURE_MISMATCH(a, b, cap, feature, MASK) \
+       DO_CHECK_FEATURE_MISMATCH((a)->cap, (b)->cap, cap, feature, MASK)
+
+#define CHECK_FEATURE_MISMATCH_HOTPLUG(b, cap, feature, MASK) \
+do { \
+       if (cap##_##feature(intel_iommu_##cap##_sanity)) \
+               DO_CHECK_FEATURE_MISMATCH(intel_iommu_##cap##_sanity, \
+                                         (b)->cap, cap, feature, MASK); \
+} while (0)
+
+#define MINIMAL_FEATURE_IOMMU(iommu, cap, MASK) \
+do { \
+       u64 min_feature = intel_iommu_##cap##_sanity & (MASK); \
+       min_feature = min_t(u64, min_feature, (iommu)->cap & (MASK)); \
+       intel_iommu_##cap##_sanity = (intel_iommu_##cap##_sanity & ~(MASK)) | \
+                                    min_feature; \
+} while (0)
+
+#define MINIMAL_FEATURE_HOTPLUG(iommu, cap, feature, MASK, mismatch) \
+do { \
+       if ((intel_iommu_##cap##_sanity & (MASK)) > \
+           (cap##_##feature((iommu)->cap))) \
+               mismatch = true; \
+       else \
+               (iommu)->cap = ((iommu)->cap & ~(MASK)) | \
+               (intel_iommu_##cap##_sanity & (MASK)); \
+} while (0)
+
+enum cap_audit_type {
+       CAP_AUDIT_STATIC_DMAR,
+       CAP_AUDIT_STATIC_IRQR,
+       CAP_AUDIT_HOTPLUG_DMAR,
+       CAP_AUDIT_HOTPLUG_IRQR,
+};
+
+int intel_cap_audit(enum cap_audit_type type, struct intel_iommu *iommu);
 
  * Extended Capability Register
  */
 
+#define        ecap_rps(e)             (((e) >> 49) & 0x1)
 #define ecap_smpwc(e)          (((e) >> 48) & 0x1)
 #define ecap_flts(e)           (((e) >> 47) & 0x1)
 #define ecap_slts(e)           (((e) >> 46) & 0x1)
+#define ecap_slads(e)          (((e) >> 45) & 0x1)
 #define ecap_vcs(e)            (((e) >> 44) & 0x1)
 #define ecap_smts(e)           (((e) >> 43) & 0x1)
-#define ecap_dit(e)            ((e >> 41) & 0x1)
-#define ecap_pasid(e)          ((e >> 40) & 0x1)
-#define ecap_pss(e)            ((e >> 35) & 0x1f)
-#define ecap_eafs(e)           ((e >> 34) & 0x1)
-#define ecap_nwfs(e)           ((e >> 33) & 0x1)
-#define ecap_srs(e)            ((e >> 31) & 0x1)
-#define ecap_ers(e)            ((e >> 30) & 0x1)
-#define ecap_prs(e)            ((e >> 29) & 0x1)
-#define ecap_broken_pasid(e)   ((e >> 28) & 0x1)
-#define ecap_dis(e)            ((e >> 27) & 0x1)
-#define ecap_nest(e)           ((e >> 26) & 0x1)
-#define ecap_mts(e)            ((e >> 25) & 0x1)
-#define ecap_ecs(e)            ((e >> 24) & 0x1)
+#define ecap_dit(e)            (((e) >> 41) & 0x1)
+#define ecap_pds(e)            (((e) >> 42) & 0x1)
+#define ecap_pasid(e)          (((e) >> 40) & 0x1)
+#define ecap_pss(e)            (((e) >> 35) & 0x1f)
+#define ecap_eafs(e)           (((e) >> 34) & 0x1)
+#define ecap_nwfs(e)           (((e) >> 33) & 0x1)
+#define ecap_srs(e)            (((e) >> 31) & 0x1)
+#define ecap_ers(e)            (((e) >> 30) & 0x1)
+#define ecap_prs(e)            (((e) >> 29) & 0x1)
+#define ecap_broken_pasid(e)   (((e) >> 28) & 0x1)
+#define ecap_dis(e)            (((e) >> 27) & 0x1)
+#define ecap_nest(e)           (((e) >> 26) & 0x1)
+#define ecap_mts(e)            (((e) >> 25) & 0x1)
+#define ecap_ecs(e)            (((e) >> 24) & 0x1)
 #define ecap_iotlb_offset(e)   ((((e) >> 8) & 0x3ff) * 16)
 #define ecap_max_iotlb_offset(e) (ecap_iotlb_offset(e) + 16)
 #define ecap_coherent(e)       ((e) & 0x1)
 #define ecap_qis(e)            ((e) & 0x2)
-#define ecap_pass_through(e)   ((e >> 6) & 0x1)
-#define ecap_eim_support(e)    ((e >> 4) & 0x1)
-#define ecap_ir_support(e)     ((e >> 3) & 0x1)
+#define ecap_pass_through(e)   (((e) >> 6) & 0x1)
+#define ecap_eim_support(e)    (((e) >> 4) & 0x1)
+#define ecap_ir_support(e)     (((e) >> 3) & 0x1)
 #define ecap_dev_iotlb_support(e)      (((e) >> 2) & 0x1)
-#define ecap_max_handle_mask(e) ((e >> 20) & 0xf)
-#define ecap_sc_support(e)     ((e >> 7) & 0x1) /* Snooping Control */
+#define ecap_max_handle_mask(e) (((e) >> 20) & 0xf)
+#define ecap_sc_support(e)     (((e) >> 7) & 0x1) /* Snooping Control */
 
 /* Virtual command interface capability */
 #define vccap_pasid(v)         (((v) & DMA_VCS_PAS)) /* PASID allocation */