]> Git Repo - linux.git/commitdiff
Merge branches 'intel/vt-d', 'amd/amd-vi' and 'iommufd/arm-smmuv3-nested' into next
authorJoerg Roedel <[email protected]>
Fri, 15 Nov 2024 08:27:43 +0000 (09:27 +0100)
committerJoerg Roedel <[email protected]>
Fri, 15 Nov 2024 08:27:43 +0000 (09:27 +0100)
1  2  3  4 
drivers/iommu/Kconfig
drivers/iommu/amd/amd_iommu.h
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
drivers/iommu/arm/arm-smmu/arm-smmu.c
drivers/iommu/intel/iommu.c
drivers/iommu/iommu.c
include/linux/iommu.h
include/uapi/linux/iommufd.h

diff --combined drivers/iommu/Kconfig
index ade4e8cf2a3e12c559d6a87165a8d81585befdc3,b3aa1f5d53218b0468e2b646289c82396f6ed4aa,b3aa1f5d53218b0468e2b646289c82396f6ed4aa,0c9bceb1653d5f6019396ab1d87d921f20ec1ffb..47c46e4b739ef32ff6aea519c6024a765956f002
@@@@@ -195,7 -195,6 -195,6 -195,6 +195,7 @@@@@ config MSM_IOMM
    source "drivers/iommu/amd/Kconfig"
    source "drivers/iommu/intel/Kconfig"
    source "drivers/iommu/iommufd/Kconfig"
 +++source "drivers/iommu/riscv/Kconfig"
    
    config IRQ_REMAP
        bool "Support for Interrupt Remapping"
@@@@@ -416,6 -415,6 -415,6 -415,15 +416,15 @@@@@ config ARM_SMMU_V3_SV
          Say Y here if your system supports SVA extensions such as PCIe PASID
          and PRI.
    
+++ config ARM_SMMU_V3_IOMMUFD
+++     bool "Enable IOMMUFD features for ARM SMMUv3 (EXPERIMENTAL)"
+++     depends on IOMMUFD
+++     help
+++       Support for IOMMUFD features intended to support virtual machines
+++       with accelerated virtual IOMMUs.
+++ 
+++       Say Y here if you are doing development and testing on this feature.
+++ 
    config ARM_SMMU_V3_KUNIT_TEST
        tristate "KUnit tests for arm-smmu-v3 driver"  if !KUNIT_ALL_TESTS
        depends on KUNIT
index 38509e1019e9332f6b7dae78b8ba32e244cdebcc,b11b014fa82d18d6bfcb1b6a4d74d6e5a2d77f96,38509e1019e9332f6b7dae78b8ba32e244cdebcc,6386fa4556d9b8060544264d98b6af30c8d4de46..1bef5d55b2f9dd496397bfd11c4a99f03a645d06
@@@@@ -46,14 -46,14 -46,14 -46,13 +46,15 @@@@@ extern int amd_iommu_gpt_level
    extern unsigned long amd_iommu_pgsize_bitmap;
    
    /* Protection domain ops */
 + +void amd_iommu_init_identity_domain(void);
    struct protection_domain *protection_domain_alloc(unsigned int type, int nid);
    void protection_domain_free(struct protection_domain *domain);
    struct iommu_domain *amd_iommu_domain_alloc_sva(struct device *dev,
                                                struct mm_struct *mm);
    void amd_iommu_domain_free(struct iommu_domain *dom);
    int iommu_sva_set_dev_pasid(struct iommu_domain *domain,
- --                        struct device *dev, ioasid_t pasid);
+ ++                        struct device *dev, ioasid_t pasid,
+ ++                        struct iommu_domain *old);
    void amd_iommu_remove_dev_pasid(struct device *dev, ioasid_t pasid,
                                struct iommu_domain *domain);
    
@@@@@ -119,14 -119,9 -119,14 -118,9 +120,14 @@@@@ static inline bool check_feature2(u64 m
        return (amd_iommu_efr2 & mask);
    }
    
 + +static inline bool amd_iommu_v2_pgtbl_supported(void)
 + +{
 + +    return (check_feature(FEATURE_GIOSUP) && check_feature(FEATURE_GT));
 + +}
 + +
    static inline bool amd_iommu_gt_ppr_supported(void)
    {
 - -    return (check_feature(FEATURE_GT) &&
 + +    return (amd_iommu_v2_pgtbl_supported() &&
                check_feature(FEATURE_PPR) &&
                check_feature(FEATURE_EPHSUP));
    }
index 826db8894fb76ede48d27451fbefb1988663c21a,f70165f544dfa79feaaf0350ff31963cfa74f25f,8a193141f003d7fa1beaf8848b268d3fd5939fae,b4b03206afbf488ad6d69e2af89a1cae8cec3519..7ee3cbbe3744b3c12ea3ce37182744d1befc75dc
@@@@@ -1420,7 -1420,7 -1420,7 -1420,7 +1420,7 @@@@@ static int arm_smmu_alloc_cd_tables(str
                cd_table->s1fmt = STRTAB_STE_0_S1FMT_LINEAR;
                cd_table->linear.num_ents = max_contexts;
    
 ---            l1size = max_contexts * sizeof(struct arm_smmu_cd),
 +++            l1size = max_contexts * sizeof(struct arm_smmu_cd);
                cd_table->linear.table = dma_alloc_coherent(smmu->dev, l1size,
                                                            &cd_table->cdtab_dma,
                                                            GFP_KERNEL);
@@@@@ -1549,7 -1549,7 -1549,7 -1549,6 +1549,6 @@@@@ static void arm_smmu_write_ste(struct a
        }
    }
    
--- VISIBLE_IF_KUNIT
    void arm_smmu_make_abort_ste(struct arm_smmu_ste *target)
    {
        memset(target, 0, sizeof(*target));
@@@@@ -1632,7 -1632,7 -1632,7 -1631,6 +1631,6 @@@@@ void arm_smmu_make_cdtable_ste(struct a
    }
    EXPORT_SYMBOL_IF_KUNIT(arm_smmu_make_cdtable_ste);
    
--- VISIBLE_IF_KUNIT
    void arm_smmu_make_s2_domain_ste(struct arm_smmu_ste *target,
                                 struct arm_smmu_master *master,
                                 struct arm_smmu_domain *smmu_domain,
@@@@@ -2293,6 -2293,6 -2293,6 -2291,8 +2291,8 @@@@@ static bool arm_smmu_capable(struct dev
        case IOMMU_CAP_CACHE_COHERENCY:
                /* Assume that a coherent TCU implies coherent TBUs */
                return master->smmu->features & ARM_SMMU_FEAT_COHERENCY;
+++     case IOMMU_CAP_ENFORCE_CACHE_COHERENCY:
+++             return arm_smmu_master_canwbs(master);
        case IOMMU_CAP_NOEXEC:
        case IOMMU_CAP_DEFERRED_FLUSH:
                return true;
        }
    }
    
+++ static bool arm_smmu_enforce_cache_coherency(struct iommu_domain *domain)
+++ {
+++     struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
+++     struct arm_smmu_master_domain *master_domain;
+++     unsigned long flags;
+++     bool ret = true;
+++ 
+++     spin_lock_irqsave(&smmu_domain->devices_lock, flags);
+++     list_for_each_entry(master_domain, &smmu_domain->devices,
+++                         devices_elm) {
+++             if (!arm_smmu_master_canwbs(master_domain->master)) {
+++                     ret = false;
+++                     break;
+++             }
+++     }
+++     smmu_domain->enforce_cache_coherency = ret;
+++     spin_unlock_irqrestore(&smmu_domain->devices_lock, flags);
+++     return ret;
+++ }
+++ 
    struct arm_smmu_domain *arm_smmu_domain_alloc(void)
    {
        struct arm_smmu_domain *smmu_domain;
@@@@@ -2483,8 -2483,8 -2483,8 -2503,8 +2503,8 @@@@@ arm_smmu_get_step_for_sid(struct arm_sm
        }
    }
    
--- static void arm_smmu_install_ste_for_dev(struct arm_smmu_master *master,
---                                      const struct arm_smmu_ste *target)
+++ void arm_smmu_install_ste_for_dev(struct arm_smmu_master *master,
+++                               const struct arm_smmu_ste *target)
    {
        int i, j;
        struct arm_smmu_device *smmu = master->smmu;
@@@@@ -2649,16 -2649,16 -2649,16 -2669,6 +2669,6 @@@@@ static void arm_smmu_remove_master_doma
        spin_unlock_irqrestore(&smmu_domain->devices_lock, flags);
    }
    
--- struct arm_smmu_attach_state {
---     /* Inputs */
---     struct iommu_domain *old_domain;
---     struct arm_smmu_master *master;
---     bool cd_needs_ats;
---     ioasid_t ssid;
---     /* Resulting state */
---     bool ats_enabled;
--- };
--- 
    /*
     * Start the sequence to attach a domain to a master. The sequence contains three
     * steps:
     * new_domain can be a non-paging domain. In this case ATS will not be enabled,
     * and invalidations won't be tracked.
     */
--- static int arm_smmu_attach_prepare(struct arm_smmu_attach_state *state,
---                                struct iommu_domain *new_domain)
+++ int arm_smmu_attach_prepare(struct arm_smmu_attach_state *state,
+++                         struct iommu_domain *new_domain)
    {
        struct arm_smmu_master *master = state->master;
        struct arm_smmu_master_domain *master_domain;
                 * one of them.
                 */
                spin_lock_irqsave(&smmu_domain->devices_lock, flags);
+++             if (smmu_domain->enforce_cache_coherency &&
+++                 !arm_smmu_master_canwbs(master)) {
+++                     spin_unlock_irqrestore(&smmu_domain->devices_lock,
+++                                            flags);
+++                     kfree(master_domain);
+++                     return -EINVAL;
+++             }
+++ 
                if (state->ats_enabled)
                        atomic_inc(&smmu_domain->nr_ats_masters);
                list_add(&master_domain->devices_elm, &smmu_domain->devices);
     * completes synchronizing the PCI device's ATC and finishes manipulating the
     * smmu_domain->devices list.
     */
--- static void arm_smmu_attach_commit(struct arm_smmu_attach_state *state)
+++ void arm_smmu_attach_commit(struct arm_smmu_attach_state *state)
    {
        struct arm_smmu_master *master = state->master;
    
@@@@@ -2856,7 -2856,8 -2856,7 -2874,7 +2874,8 @@@@@ static int arm_smmu_attach_dev(struct i
    }
    
    static int arm_smmu_s1_set_dev_pasid(struct iommu_domain *domain,
- --                                  struct device *dev, ioasid_t id)
+ ++                                 struct device *dev, ioasid_t id,
+ ++                                 struct iommu_domain *old)
    {
        struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
        struct arm_smmu_master *master = dev_iommu_priv_get(dev);
         */
        arm_smmu_make_s1_cd(&target_cd, master, smmu_domain);
        return arm_smmu_set_pasid(master, to_smmu_domain(domain), id,
- --                              &target_cd);
+ ++                              &target_cd, old);
    }
    
    static void arm_smmu_update_ste(struct arm_smmu_master *master,
    
    int arm_smmu_set_pasid(struct arm_smmu_master *master,
                       struct arm_smmu_domain *smmu_domain, ioasid_t pasid,
- --                   struct arm_smmu_cd *cd)
+ ++                   struct arm_smmu_cd *cd, struct iommu_domain *old)
    {
        struct iommu_domain *sid_domain = iommu_get_domain_for_dev(master->dev);
        struct arm_smmu_attach_state state = {
                .master = master,
- --            /*
- --             * For now the core code prevents calling this when a domain is
- --             * already attached, no need to set old_domain.
- --             */
                .ssid = pasid,
+ ++            .old_domain = old,
        };
        struct arm_smmu_cd *cdptr;
        int ret;
@@@@@ -3084,8 -3082,7 -3084,8 -3102,8 +3100,9 @@@@@ arm_smmu_domain_alloc_user(struct devic
                           const struct iommu_user_data *user_data)
    {
        struct arm_smmu_master *master = dev_iommu_priv_get(dev);
 -      const u32 PAGING_FLAGS = IOMMU_HWPT_ALLOC_DIRTY_TRACKING;
 +      const u32 PAGING_FLAGS = IOMMU_HWPT_ALLOC_DIRTY_TRACKING |
- -                                     IOMMU_HWPT_ALLOC_PASID;
++++                             IOMMU_HWPT_ALLOC_PASID |
+++                              IOMMU_HWPT_ALLOC_NEST_PARENT;
        struct arm_smmu_domain *smmu_domain;
        int ret;
    
        if (parent || user_data)
                return ERR_PTR(-EOPNOTSUPP);
    
 + +    if (flags & IOMMU_HWPT_ALLOC_PASID)
 + +            return arm_smmu_domain_alloc_paging(dev);
 + +
        smmu_domain = arm_smmu_domain_alloc();
        if (IS_ERR(smmu_domain))
                return ERR_CAST(smmu_domain);
    
+++     if (flags & IOMMU_HWPT_ALLOC_NEST_PARENT) {
+++             if (!(master->smmu->features & ARM_SMMU_FEAT_NESTING)) {
+++                     ret = -EOPNOTSUPP;
+++                     goto err_free;
+++             }
+++             smmu_domain->stage = ARM_SMMU_DOMAIN_S2;
+++     }
+++ 
        smmu_domain->domain.type = IOMMU_DOMAIN_UNMANAGED;
        smmu_domain->domain.ops = arm_smmu_ops.default_domain_ops;
        ret = arm_smmu_domain_finalise(smmu_domain, master->smmu, flags);
@@@@@ -3382,21 -3376,21 -3382,21 -3405,6 +3407,6 @@@@@ static struct iommu_group *arm_smmu_dev
        return group;
    }
    
--- static int arm_smmu_enable_nesting(struct iommu_domain *domain)
--- {
---     struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
---     int ret = 0;
--- 
---     mutex_lock(&smmu_domain->init_mutex);
---     if (smmu_domain->smmu)
---             ret = -EPERM;
---     else
---             smmu_domain->stage = ARM_SMMU_DOMAIN_S2;
---     mutex_unlock(&smmu_domain->init_mutex);
--- 
---     return ret;
--- }
--- 
    static int arm_smmu_of_xlate(struct device *dev,
                             const struct of_phandle_args *args)
    {
@@@@@ -3495,6 -3489,6 -3495,6 -3503,7 +3505,7 @@@@@ static struct iommu_ops arm_smmu_ops = 
        .identity_domain        = &arm_smmu_identity_domain,
        .blocked_domain         = &arm_smmu_blocked_domain,
        .capable                = arm_smmu_capable,
+++     .hw_info                = arm_smmu_hw_info,
        .domain_alloc_paging    = arm_smmu_domain_alloc_paging,
        .domain_alloc_sva       = arm_smmu_sva_domain_alloc,
        .domain_alloc_user      = arm_smmu_domain_alloc_user,
        .owner                  = THIS_MODULE,
        .default_domain_ops = &(const struct iommu_domain_ops) {
                .attach_dev             = arm_smmu_attach_dev,
+++             .enforce_cache_coherency = arm_smmu_enforce_cache_coherency,
                .set_dev_pasid          = arm_smmu_s1_set_dev_pasid,
                .map_pages              = arm_smmu_map_pages,
                .unmap_pages            = arm_smmu_unmap_pages,
                .flush_iotlb_all        = arm_smmu_flush_iotlb_all,
                .iotlb_sync             = arm_smmu_iotlb_sync,
                .iova_to_phys           = arm_smmu_iova_to_phys,
---             .enable_nesting         = arm_smmu_enable_nesting,
                .free                   = arm_smmu_domain_free_paging,
        }
    };
@@@@@ -3629,7 -3623,7 -3629,7 -3638,7 +3640,7 @@@@@ static int arm_smmu_init_strtab_2lvl(st
        u32 l1size;
        struct arm_smmu_strtab_cfg *cfg = &smmu->strtab_cfg;
        unsigned int last_sid_idx =
 ---            arm_smmu_strtab_l1_idx((1 << smmu->sid_bits) - 1);
 +++            arm_smmu_strtab_l1_idx((1ULL << smmu->sid_bits) - 1);
    
        /* Calculate the L1 size, capped to the SIDSIZE. */
        cfg->l2.num_l1_ents = min(last_sid_idx + 1, STRTAB_MAX_L1_ENTRIES);
index 1e9952ca989f87957197f4d4b400f9d74bb685ac,52eaa0bedee1df9304530a56c5737dedf21aa7cd,1e9952ca989f87957197f4d4b400f9d74bb685ac,c9e5290e995a64f3b2f8b5b45235064ef35c7c4f..1e96d4af03f89d86d50e75f2577e65b690901fb6
@@@@@ -81,6 -81,6 -81,6 -81,8 +81,8 @@@@@ struct arm_smmu_device
    #define IIDR_REVISION                       GENMASK(15, 12)
    #define IIDR_IMPLEMENTER            GENMASK(11, 0)
    
+++ #define ARM_SMMU_AIDR                       0x1C
+++ 
    #define ARM_SMMU_CR0                        0x20
    #define CR0_ATSCHK                  (1 << 4)
    #define CR0_CMDQEN                  (1 << 3)
@@@@@ -811,6 -811,6 -811,6 -813,7 +813,7 @@@@@ struct arm_smmu_domain 
        /* List of struct arm_smmu_master_domain */
        struct list_head                devices;
        spinlock_t                      devices_lock;
+++     bool                            enforce_cache_coherency : 1;
    
        struct mmu_notifier             mmu_notifier;
    };
@@@@@ -827,21 -827,21 -827,21 -830,22 +830,22 @@@@@ struct arm_smmu_entry_writer_ops 
        void (*sync)(struct arm_smmu_entry_writer *writer);
    };
    
+++ void arm_smmu_make_abort_ste(struct arm_smmu_ste *target);
+++ void arm_smmu_make_s2_domain_ste(struct arm_smmu_ste *target,
+++                              struct arm_smmu_master *master,
+++                              struct arm_smmu_domain *smmu_domain,
+++                              bool ats_enabled);
+++ 
    #if IS_ENABLED(CONFIG_KUNIT)
    void arm_smmu_get_ste_used(const __le64 *ent, __le64 *used_bits);
    void arm_smmu_write_entry(struct arm_smmu_entry_writer *writer, __le64 *cur,
                          const __le64 *target);
    void arm_smmu_get_cd_used(const __le64 *ent, __le64 *used_bits);
--- void arm_smmu_make_abort_ste(struct arm_smmu_ste *target);
    void arm_smmu_make_bypass_ste(struct arm_smmu_device *smmu,
                              struct arm_smmu_ste *target);
    void arm_smmu_make_cdtable_ste(struct arm_smmu_ste *target,
                               struct arm_smmu_master *master, bool ats_enabled,
                               unsigned int s1dss);
--- void arm_smmu_make_s2_domain_ste(struct arm_smmu_ste *target,
---                              struct arm_smmu_master *master,
---                              struct arm_smmu_domain *smmu_domain,
---                              bool ats_enabled);
    void arm_smmu_make_sva_cd(struct arm_smmu_cd *target,
                          struct arm_smmu_master *master, struct mm_struct *mm,
                          u16 asid);
@@@@@ -875,7 -875,7 -875,7 -879,7 +879,7 @@@@@ void arm_smmu_write_cd_entry(struct arm
    
    int arm_smmu_set_pasid(struct arm_smmu_master *master,
                       struct arm_smmu_domain *smmu_domain, ioasid_t pasid,
- --                   struct arm_smmu_cd *cd);
+ ++                   struct arm_smmu_cd *cd, struct iommu_domain *old);
    
    void arm_smmu_tlb_inv_asid(struct arm_smmu_device *smmu, u16 asid);
    void arm_smmu_tlb_inv_range_asid(unsigned long iova, size_t size, int asid,
@@@@@ -893,6 -893,6 -893,6 -897,28 +897,28 @@@@@ int arm_smmu_init_one_queue(struct arm_
    int arm_smmu_cmdq_init(struct arm_smmu_device *smmu,
                       struct arm_smmu_cmdq *cmdq);
    
+++ static inline bool arm_smmu_master_canwbs(struct arm_smmu_master *master)
+++ {
+++     return dev_iommu_fwspec_get(master->dev)->flags &
+++            IOMMU_FWSPEC_PCI_RC_CANWBS;
+++ }
+++ 
+++ struct arm_smmu_attach_state {
+++     /* Inputs */
+++     struct iommu_domain *old_domain;
+++     struct arm_smmu_master *master;
+++     bool cd_needs_ats;
+++     ioasid_t ssid;
+++     /* Resulting state */
+++     bool ats_enabled;
+++ };
+++ 
+++ int arm_smmu_attach_prepare(struct arm_smmu_attach_state *state,
+++                         struct iommu_domain *new_domain);
+++ void arm_smmu_attach_commit(struct arm_smmu_attach_state *state);
+++ void arm_smmu_install_ste_for_dev(struct arm_smmu_master *master,
+++                               const struct arm_smmu_ste *target);
+++ 
    #ifdef CONFIG_ARM_SMMU_V3_SVA
    bool arm_smmu_sva_supported(struct arm_smmu_device *smmu);
    bool arm_smmu_master_sva_supported(struct arm_smmu_master *master);
@@@@@ -949,4 -949,4 -949,4 -975,11 +975,11 @@@@@ tegra241_cmdqv_probe(struct arm_smmu_de
        return ERR_PTR(-ENODEV);
    }
    #endif /* CONFIG_TEGRA241_CMDQV */
+++ 
+++ #if IS_ENABLED(CONFIG_ARM_SMMU_V3_IOMMUFD)
+++ void *arm_smmu_hw_info(struct device *dev, u32 *length, u32 *type);
+++ #else
+++ #define arm_smmu_hw_info NULL
+++ #endif /* CONFIG_ARM_SMMU_V3_IOMMUFD */
+++ 
    #endif /* _ARM_SMMU_V3_H */
index 14618772a3d6e47ceab3f8666dc11271157f8f74,8321962b37148bae0db9aa161cb96395ed740320,8321962b37148bae0db9aa161cb96395ed740320,12b173eec4540d47a81729989488aaedf87cb57b..ade4684c14c9b2724a71e2457288dbfaf7562c83
@@@@@ -1437,17 -1437,6 -1437,6 -1437,6 +1437,17 @@@@@ static struct iommu_device *arm_smmu_pr
                        goto out_free;
        } else {
                smmu = arm_smmu_get_by_fwnode(fwspec->iommu_fwnode);
 +++
 +++            /*
 +++             * Defer probe if the relevant SMMU instance hasn't finished
 +++             * probing yet. This is a fragile hack and we'd ideally
 +++             * avoid this race in the core code. Until that's ironed
 +++             * out, however, this is the most pragmatic option on the
 +++             * table.
 +++             */
 +++            if (!smmu)
 +++                    return ERR_PTR(dev_err_probe(dev, -EPROBE_DEFER,
 +++                                            "smmu dev has not bound yet\n"));
        }
    
        ret = -EINVAL;
@@@@@ -1569,21 -1558,21 -1558,21 -1558,6 +1569,6 @@@@@ static struct iommu_group *arm_smmu_dev
        return group;
    }
    
--- static int arm_smmu_enable_nesting(struct iommu_domain *domain)
--- {
---     struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
---     int ret = 0;
--- 
---     mutex_lock(&smmu_domain->init_mutex);
---     if (smmu_domain->smmu)
---             ret = -EPERM;
---     else
---             smmu_domain->stage = ARM_SMMU_DOMAIN_NESTED;
---     mutex_unlock(&smmu_domain->init_mutex);
--- 
---     return ret;
--- }
--- 
    static int arm_smmu_set_pgtable_quirks(struct iommu_domain *domain,
                unsigned long quirks)
    {
@@@@@ -1667,7 -1656,7 -1656,7 -1641,6 +1652,6 @@@@@ static struct iommu_ops arm_smmu_ops = 
                .flush_iotlb_all        = arm_smmu_flush_iotlb_all,
                .iotlb_sync             = arm_smmu_iotlb_sync,
                .iova_to_phys           = arm_smmu_iova_to_phys,
---             .enable_nesting         = arm_smmu_enable_nesting,
                .set_pgtable_quirks     = arm_smmu_set_pgtable_quirks,
                .free                   = arm_smmu_domain_free,
        }
index e860bc9439a28358b04d11682c6a877af3b71d85,b380b38315b2ae66c5714953f51ac4f346a98474,9f6b0780f2ef5e7347d702b5337d99edbcc92292,9f6b0780f2ef5e7347d702b5337d99edbcc92292..527f6f89d8a1f56d48d98e2c3b2a8a3ebedffaa4
@@@@@ -352,89 -352,6 -352,89 -352,89 +352,6 @@@@@ static bool iommu_paging_structure_cohe
                        ecap_smpwc(iommu->ecap) : ecap_coherent(iommu->ecap);
    }
    
- --static void domain_update_iommu_coherency(struct dmar_domain *domain)
- --{
- --    struct iommu_domain_info *info;
- --    struct dmar_drhd_unit *drhd;
- --    struct intel_iommu *iommu;
- --    bool found = false;
- --    unsigned long i;
- --
- --    domain->iommu_coherency = true;
- --    xa_for_each(&domain->iommu_array, i, info) {
- --            found = true;
- --            if (!iommu_paging_structure_coherency(info->iommu)) {
- --                    domain->iommu_coherency = false;
- --                    break;
- --            }
- --    }
- --    if (found)
- --            return;
- --
- --    /* No hardware attached; use lowest common denominator */
- --    rcu_read_lock();
- --    for_each_active_iommu(iommu, drhd) {
- --            if (!iommu_paging_structure_coherency(iommu)) {
- --                    domain->iommu_coherency = false;
- --                    break;
- --            }
- --    }
- --    rcu_read_unlock();
- --}
- --
- --static int domain_update_iommu_superpage(struct dmar_domain *domain,
- --                                     struct intel_iommu *skip)
- --{
- --    struct dmar_drhd_unit *drhd;
- --    struct intel_iommu *iommu;
- --    int mask = 0x3;
- --
- --    if (!intel_iommu_superpage)
- --            return 0;
- --
- --    /* set iommu_superpage to the smallest common denominator */
- --    rcu_read_lock();
- --    for_each_active_iommu(iommu, drhd) {
- --            if (iommu != skip) {
- --                    if (domain && domain->use_first_level) {
- --                            if (!cap_fl1gp_support(iommu->cap))
- --                                    mask = 0x1;
- --                    } else {
- --                            mask &= cap_super_page_val(iommu->cap);
- --                    }
- --
- --                    if (!mask)
- --                            break;
- --            }
- --    }
- --    rcu_read_unlock();
- --
- --    return fls(mask);
- --}
- --
- --static int domain_update_device_node(struct dmar_domain *domain)
- --{
- --    struct device_domain_info *info;
- --    int nid = NUMA_NO_NODE;
- --    unsigned long flags;
- --
- --    spin_lock_irqsave(&domain->lock, flags);
- --    list_for_each_entry(info, &domain->devices, link) {
- --            /*
- --             * There could possibly be multiple device numa nodes as devices
- --             * within the same domain may sit behind different IOMMUs. There
- --             * isn't perfect answer in such situation, so we select first
- --             * come first served policy.
- --             */
- --            nid = dev_to_node(info->dev);
- --            if (nid != NUMA_NO_NODE)
- --                    break;
- --    }
- --    spin_unlock_irqrestore(&domain->lock, flags);
- --
- --    return nid;
- --}
- --
    /* Return the super pagesize bitmap if supported. */
    static unsigned long domain_super_pgsize_bitmap(struct dmar_domain *domain)
    {
        return bitmap;
    }
    
- --/* Some capabilities may be different across iommus */
- --void domain_update_iommu_cap(struct dmar_domain *domain)
- --{
- --    domain_update_iommu_coherency(domain);
- --    domain->iommu_superpage = domain_update_iommu_superpage(domain, NULL);
- --
- --    /*
- --     * If RHSA is missing, we should default to the device numa domain
- --     * as fall back.
- --     */
- --    if (domain->nid == NUMA_NO_NODE)
- --            domain->nid = domain_update_device_node(domain);
- --
- --    /*
- --     * First-level translation restricts the input-address to a
- --     * canonical address (i.e., address bits 63:N have the same
- --     * value as address bit [N-1], where N is 48-bits with 4-level
- --     * paging and 57-bits with 5-level paging). Hence, skip bit
- --     * [N-1].
- --     */
- --    if (domain->use_first_level)
- --            domain->domain.geometry.aperture_end = __DOMAIN_MAX_ADDR(domain->gaw - 1);
- --    else
- --            domain->domain.geometry.aperture_end = __DOMAIN_MAX_ADDR(domain->gaw);
- --
- --    domain->domain.pgsize_bitmap |= domain_super_pgsize_bitmap(domain);
- --}
- --
    struct context_entry *iommu_context_addr(struct intel_iommu *iommu, u8 bus,
                                         u8 devfn, int alloc)
    {
@@@@@ -707,14 -596,15 -707,14 -707,14 +596,15 @@@@@ static void pgtable_walk(struct intel_i
        while (1) {
                offset = pfn_level_offset(pfn, level);
                pte = &parent[offset];
- --            if (!pte || (dma_pte_superpage(pte) || !dma_pte_present(pte))) {
- --                    pr_info("PTE not present at level %d\n", level);
- --                    break;
- --            }
    
                pr_info("pte level: %d, pte value: 0x%016llx\n", level, pte->val);
    
- --            if (level == 1)
+ ++            if (!dma_pte_present(pte)) {
+ ++                    pr_info("page table not present at level %d\n", level - 1);
+ ++                    break;
+ ++            }
+ ++
+ ++            if (level == 1 || dma_pte_superpage(pte))
                        break;
    
                parent = phys_to_virt(dma_pte_addr(pte));
@@@@@ -737,11 -627,11 -737,11 -737,11 +627,11 @@@@@ void dmar_fault_dump_ptes(struct intel_
        pr_info("Dump %s table entries for IOVA 0x%llx\n", iommu->name, addr);
    
        /* root entry dump */
- --    rt_entry = &iommu->root_entry[bus];
- --    if (!rt_entry) {
- --            pr_info("root table entry is not present\n");
+ ++    if (!iommu->root_entry) {
+ ++            pr_info("root table is not present\n");
                return;
        }
+ ++    rt_entry = &iommu->root_entry[bus];
    
        if (sm_supported(iommu))
                pr_info("scalable mode root entry: hi 0x%016llx, low 0x%016llx\n",
        /* context entry dump */
        ctx_entry = iommu_context_addr(iommu, bus, devfn, 0);
        if (!ctx_entry) {
- --            pr_info("context table entry is not present\n");
+ ++            pr_info("context table is not present\n");
                return;
        }
    
    
        /* legacy mode does not require PASID entries */
        if (!sm_supported(iommu)) {
+ ++            if (!context_present(ctx_entry)) {
+ ++                    pr_info("legacy mode page table is not present\n");
+ ++                    return;
+ ++            }
                level = agaw_to_level(ctx_entry->hi & 7);
                pgtable = phys_to_virt(ctx_entry->lo & VTD_PAGE_MASK);
                goto pgtable_walk;
        }
    
- --    /* get the pointer to pasid directory entry */
- --    dir = phys_to_virt(ctx_entry->lo & VTD_PAGE_MASK);
- --    if (!dir) {
- --            pr_info("pasid directory entry is not present\n");
+ ++    if (!context_present(ctx_entry)) {
+ ++            pr_info("pasid directory table is not present\n");
                return;
        }
+ ++
+ ++    /* get the pointer to pasid directory entry */
+ ++    dir = phys_to_virt(ctx_entry->lo & VTD_PAGE_MASK);
+ ++
        /* For request-without-pasid, get the pasid from context entry */
        if (intel_iommu_sm && pasid == IOMMU_PASID_INVALID)
                pasid = IOMMU_NO_PASID;
        /* get the pointer to the pasid table entry */
        entries = get_pasid_table_from_pde(pde);
        if (!entries) {
- --            pr_info("pasid table entry is not present\n");
+ ++            pr_info("pasid table is not present\n");
                return;
        }
        index = pasid & PASID_PTE_MASK;
        for (i = 0; i < ARRAY_SIZE(pte->val); i++)
                pr_info("pasid table entry[%d]: 0x%016llx\n", i, pte->val[i]);
    
+ ++    if (!pasid_pte_is_present(pte)) {
+ ++            pr_info("scalable mode page table is not present\n");
+ ++            return;
+ ++    }
+ ++
        if (pasid_pte_get_pgtt(pte) == PASID_ENTRY_PGTT_FL_ONLY) {
                level = pte->val[2] & BIT_ULL(2) ? 5 : 4;
                pgtable = phys_to_virt(pte->val[2] & VTD_PAGE_MASK);
@@@@@ -1428,51 -1329,25 -1428,51 -1428,51 +1329,25 @@@@@ static void free_dmar_iommu(struct inte
        /* free context mapping */
        free_context_table(iommu);
    
- --#ifdef CONFIG_INTEL_IOMMU_SVM
- --    if (pasid_supported(iommu)) {
- --            if (ecap_prs(iommu->ecap))
- --                    intel_svm_finish_prq(iommu);
- --    }
- --#endif
+ ++    if (ecap_prs(iommu->ecap))
+ ++            intel_iommu_finish_prq(iommu);
    }
    
    /*
     * Check and return whether first level is used by default for
     * DMA translation.
     */
- --static bool first_level_by_default(unsigned int type)
+ ++static bool first_level_by_default(struct intel_iommu *iommu)
    {
        /* Only SL is available in legacy mode */
- --    if (!scalable_mode_support())
+ ++    if (!sm_supported(iommu))
                return false;
    
        /* Only level (either FL or SL) is available, just use it */
- --    if (intel_cap_flts_sanity() ^ intel_cap_slts_sanity())
- --            return intel_cap_flts_sanity();
- --
- --    /* Both levels are available, decide it based on domain type */
- --    return type != IOMMU_DOMAIN_UNMANAGED;
- --}
+ ++    if (ecap_flts(iommu->ecap) ^ ecap_slts(iommu->ecap))
+ ++            return ecap_flts(iommu->ecap);
    
- --static struct dmar_domain *alloc_domain(unsigned int type)
- --{
- --    struct dmar_domain *domain;
- --
- --    domain = kzalloc(sizeof(*domain), GFP_KERNEL);
- --    if (!domain)
- --            return NULL;
- --
- --    domain->nid = NUMA_NO_NODE;
- --    if (first_level_by_default(type))
- --            domain->use_first_level = true;
- --    INIT_LIST_HEAD(&domain->devices);
- --    INIT_LIST_HEAD(&domain->dev_pasids);
- --    INIT_LIST_HEAD(&domain->cache_tags);
- --    spin_lock_init(&domain->lock);
- --    spin_lock_init(&domain->cache_lock);
- --    xa_init(&domain->iommu_array);
- --
- --    return domain;
+ ++    return true;
    }
    
    int domain_attach_iommu(struct dmar_domain *domain, struct intel_iommu *iommu)
                ret = xa_err(curr) ? : -EBUSY;
                goto err_clear;
        }
- --    domain_update_iommu_cap(domain);
    
        spin_unlock(&iommu->lock);
        return 0;
@@@@@ -1540,26 -1414,11 -1540,26 -1540,26 +1414,11 @@@@@ void domain_detach_iommu(struct dmar_do
                clear_bit(info->did, iommu->domain_ids);
                xa_erase(&domain->iommu_array, iommu->seq_id);
                domain->nid = NUMA_NO_NODE;
- --            domain_update_iommu_cap(domain);
                kfree(info);
        }
        spin_unlock(&iommu->lock);
    }
    
- --static int guestwidth_to_adjustwidth(int gaw)
- --{
- --    int agaw;
- --    int r = (gaw - 12) % 9;
- --
- --    if (r == 0)
- --            agaw = gaw;
- --    else
- --            agaw = gaw + 9 - r;
- --    if (agaw > 64)
- --            agaw = 64;
- --    return agaw;
- --}
- --
    static void domain_exit(struct dmar_domain *domain)
    {
        if (domain->pgd) {
@@@@@ -1601,7 -1460,7 -1601,7 -1601,7 +1460,7 @@@@@ static void copied_context_tear_down(st
    
        if (did_old < cap_ndoms(iommu->cap)) {
                iommu->flush.flush_context(iommu, did_old,
- --                                       (((u16)bus) << 8) | devfn,
+ ++                                       PCI_DEVID(bus, devfn),
                                           DMA_CCMD_MASK_NOBIT,
                                           DMA_CCMD_DEVICE_INVL);
                iommu->flush.flush_iotlb(iommu, did_old, 0, 0,
@@@@@ -1622,7 -1481,7 -1622,7 -1622,7 +1481,7 @@@@@ static void context_present_cache_flush
    {
        if (cap_caching_mode(iommu->cap)) {
                iommu->flush.flush_context(iommu, 0,
- --                                       (((u16)bus) << 8) | devfn,
+ ++                                       PCI_DEVID(bus, devfn),
                                           DMA_CCMD_MASK_NOBIT,
                                           DMA_CCMD_DEVICE_INVL);
                iommu->flush.flush_iotlb(iommu, did, 0, 0, DMA_TLB_DSI_FLUSH);
@@@@@ -1641,7 -1500,7 -1641,7 -1641,7 +1500,7 @@@@@ static int domain_context_mapping_one(s
        int translation = CONTEXT_TT_MULTI_LEVEL;
        struct dma_pte *pgd = domain->pgd;
        struct context_entry *context;
- --    int agaw, ret;
+ ++    int ret;
    
        pr_debug("Set context mapping for %02x:%02x.%d\n",
                bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
    
        copied_context_tear_down(iommu, context, bus, devfn);
        context_clear_entry(context);
- --
        context_set_domain_id(context, did);
    
- --    /*
- --     * Skip top levels of page tables for iommu which has
- --     * less agaw than default. Unnecessary for PT mode.
- --     */
- --    for (agaw = domain->agaw; agaw > iommu->agaw; agaw--) {
- --            ret = -ENOMEM;
- --            pgd = phys_to_virt(dma_pte_addr(pgd));
- --            if (!dma_pte_present(pgd))
- --                    goto out_unlock;
- --    }
- --
        if (info && info->ats_supported)
                translation = CONTEXT_TT_DEV_IOTLB;
        else
                translation = CONTEXT_TT_MULTI_LEVEL;
    
        context_set_address_root(context, virt_to_phys(pgd));
- --    context_set_address_width(context, agaw);
+ ++    context_set_address_width(context, domain->agaw);
        context_set_translation_type(context, translation);
        context_set_fault_enable(context);
        context_set_present(context);
@@@@@ -1905,26 -1752,52 -1905,26 -1905,26 +1752,52 @@@@@ static void domain_context_clear_one(st
        intel_context_flush_present(info, context, did, true);
    }
    
+ ++int __domain_setup_first_level(struct intel_iommu *iommu,
+ ++                           struct device *dev, ioasid_t pasid,
+ ++                           u16 did, pgd_t *pgd, int flags,
+ ++                           struct iommu_domain *old)
+ ++{
+ ++    if (!old)
+ ++            return intel_pasid_setup_first_level(iommu, dev, pgd,
+ ++                                                 pasid, did, flags);
+ ++    return intel_pasid_replace_first_level(iommu, dev, pgd, pasid, did,
+ ++                                           iommu_domain_did(old, iommu),
+ ++                                           flags);
+ ++}
+ ++
+ ++static int domain_setup_second_level(struct intel_iommu *iommu,
+ ++                                 struct dmar_domain *domain,
+ ++                                 struct device *dev, ioasid_t pasid,
+ ++                                 struct iommu_domain *old)
+ ++{
+ ++    if (!old)
+ ++            return intel_pasid_setup_second_level(iommu, domain,
+ ++                                                  dev, pasid);
+ ++    return intel_pasid_replace_second_level(iommu, domain, dev,
+ ++                                            iommu_domain_did(old, iommu),
+ ++                                            pasid);
+ ++}
+ ++
+ ++static int domain_setup_passthrough(struct intel_iommu *iommu,
+ ++                                struct device *dev, ioasid_t pasid,
+ ++                                struct iommu_domain *old)
+ ++{
+ ++    if (!old)
+ ++            return intel_pasid_setup_pass_through(iommu, dev, pasid);
+ ++    return intel_pasid_replace_pass_through(iommu, dev,
+ ++                                            iommu_domain_did(old, iommu),
+ ++                                            pasid);
+ ++}
+ ++
    static int domain_setup_first_level(struct intel_iommu *iommu,
                                    struct dmar_domain *domain,
                                    struct device *dev,
- --                                u32 pasid)
+ ++                                u32 pasid, struct iommu_domain *old)
    {
        struct dma_pte *pgd = domain->pgd;
- --    int agaw, level;
- --    int flags = 0;
-   
-       /*
-        * Skip top levels of page tables for iommu which has
-        * less agaw than default. Unnecessary for PT mode.
-        */
-       for (agaw = domain->agaw; agaw > iommu->agaw; agaw--) {
-               pgd = phys_to_virt(dma_pte_addr(pgd));
-               if (!dma_pte_present(pgd))
-                       return -ENOMEM;
-       }
+ ++    int level, flags = 0;
    
  --    /*
  --     * Skip top levels of page tables for iommu which has
  --     * less agaw than default. Unnecessary for PT mode.
  --     */
  --    for (agaw = domain->agaw; agaw > iommu->agaw; agaw--) {
  --            pgd = phys_to_virt(dma_pte_addr(pgd));
  --            if (!dma_pte_present(pgd))
  --                    return -ENOMEM;
  --    }
  --
- --    level = agaw_to_level(agaw);
+ ++    level = agaw_to_level(domain->agaw);
        if (level != 4 && level != 5)
                return -EINVAL;
    
        if (domain->force_snooping)
                flags |= PASID_FLAG_PAGE_SNOOP;
    
- --    return intel_pasid_setup_first_level(iommu, dev, (pgd_t *)pgd, pasid,
- --                                         domain_id_iommu(domain, iommu),
- --                                         flags);
- --}
- --
- --static bool dev_is_real_dma_subdevice(struct device *dev)
- --{
- --    return dev && dev_is_pci(dev) &&
- --           pci_real_dma_dev(to_pci_dev(dev)) != to_pci_dev(dev);
+ ++    return __domain_setup_first_level(iommu, dev, pasid,
+ ++                                      domain_id_iommu(domain, iommu),
+ ++                                      (pgd_t *)pgd, flags, old);
    }
    
    static int dmar_domain_attach_device(struct dmar_domain *domain,
        if (!sm_supported(iommu))
                ret = domain_context_mapping(domain, dev);
        else if (domain->use_first_level)
- --            ret = domain_setup_first_level(iommu, domain, dev, IOMMU_NO_PASID);
+ ++            ret = domain_setup_first_level(iommu, domain, dev,
+ ++                                           IOMMU_NO_PASID, NULL);
        else
- --            ret = intel_pasid_setup_second_level(iommu, domain, dev, IOMMU_NO_PASID);
+ ++            ret = domain_setup_second_level(iommu, domain, dev,
+ ++                                            IOMMU_NO_PASID, NULL);
    
        if (ret)
                goto out_block_translation;
@@@@@ -2354,19 -2223,18 -2354,19 -2354,19 +2223,18 @@@@@ static int __init init_dmars(void
    
                iommu_flush_write_buffer(iommu);
    
- --#ifdef CONFIG_INTEL_IOMMU_SVM
- --            if (pasid_supported(iommu) && ecap_prs(iommu->ecap)) {
+ ++            if (ecap_prs(iommu->ecap)) {
                        /*
                         * Call dmar_alloc_hwirq() with dmar_global_lock held,
                         * could cause possible lock race condition.
                         */
                        up_write(&dmar_global_lock);
- --                    ret = intel_svm_enable_prq(iommu);
+ ++                    ret = intel_iommu_enable_prq(iommu);
                        down_write(&dmar_global_lock);
                        if (ret)
                                goto free_iommu;
                }
- --#endif
+ ++
                ret = dmar_set_interrupt(iommu);
                if (ret)
                        goto free_iommu;
@@@@@ -2746,20 -2614,13 -2746,20 -2746,20 +2614,13 @@@@@ int dmar_parse_one_satc(struct acpi_dma
    
    static int intel_iommu_add(struct dmar_drhd_unit *dmaru)
    {
- --    int sp, ret;
        struct intel_iommu *iommu = dmaru->iommu;
+ ++    int ret;
    
        ret = intel_cap_audit(CAP_AUDIT_HOTPLUG_DMAR, iommu);
        if (ret)
                goto out;
    
- --    sp = domain_update_iommu_superpage(NULL, iommu) - 1;
- --    if (sp >= 0 && !(cap_super_page_val(iommu->cap) & (1 << sp))) {
- --            pr_warn("%s: Doesn't support large page.\n",
- --                    iommu->name);
- --            return -ENXIO;
- --    }
- --
        /*
         * Disable translation if already enabled prior to OS handover.
         */
        intel_iommu_init_qi(iommu);
        iommu_flush_write_buffer(iommu);
    
- --#ifdef CONFIG_INTEL_IOMMU_SVM
- --    if (pasid_supported(iommu) && ecap_prs(iommu->ecap)) {
- --            ret = intel_svm_enable_prq(iommu);
+ ++    if (ecap_prs(iommu->ecap)) {
+ ++            ret = intel_iommu_enable_prq(iommu);
                if (ret)
                        goto disable_iommu;
        }
- --#endif
+ ++
        ret = dmar_set_interrupt(iommu);
        if (ret)
                goto disable_iommu;
@@@@@ -3288,7 -3148,7 -3288,7 -3288,7 +3148,7 @@@@@ int __init intel_iommu_init(void
                 * the virtual and physical IOMMU page-tables.
                 */
                if (cap_caching_mode(iommu->cap) &&
- --                !first_level_by_default(IOMMU_DOMAIN_DMA)) {
+ ++                !first_level_by_default(iommu)) {
                        pr_info_once("IOMMU batching disallowed due to virtualization\n");
                        iommu_set_dma_strict();
                }
@@@@@ -3340,10 -3200,8 -3340,8 -3340,8 +3200,10 @@@@@ static int domain_context_clear_one_cb(
     */
    static void domain_context_clear(struct device_domain_info *info)
    {
 ---    if (!dev_is_pci(info->dev))
 +++    if (!dev_is_pci(info->dev)) {
                domain_context_clear_one(info, info->bus, info->devfn);
 +++            return;
 +++    }
    
        pci_for_each_dma_alias(to_pci_dev(info->dev),
                               &domain_context_clear_one_cb, info);
@@@@@ -3381,27 -3239,6 -3379,27 -3379,27 +3241,6 @@@@@ void device_block_translation(struct de
        info->domain = NULL;
    }
    
- --static int md_domain_init(struct dmar_domain *domain, int guest_width)
- --{
- --    int adjust_width;
- --
- --    /* calculate AGAW */
- --    domain->gaw = guest_width;
- --    adjust_width = guestwidth_to_adjustwidth(guest_width);
- --    domain->agaw = width_to_agaw(adjust_width);
- --
- --    domain->iommu_coherency = false;
- --    domain->iommu_superpage = 0;
- --    domain->max_addr = 0;
- --
- --    /* always allocate the top pgd */
- --    domain->pgd = iommu_alloc_page_node(domain->nid, GFP_ATOMIC);
- --    if (!domain->pgd)
- --            return -ENOMEM;
- --    domain_flush_cache(domain, domain->pgd, PAGE_SIZE);
- --    return 0;
- --}
- --
    static int blocking_domain_attach_dev(struct iommu_domain *domain,
                                      struct device *dev)
    {
@@@@@ -3488,39 -3325,6 -3486,39 -3486,39 +3327,6 @@@@@ static struct dmar_domain *paging_domai
        return domain;
    }
    
- --static struct iommu_domain *intel_iommu_domain_alloc(unsigned type)
- --{
- --    struct dmar_domain *dmar_domain;
- --    struct iommu_domain *domain;
- --
- --    switch (type) {
- --    case IOMMU_DOMAIN_DMA:
- --    case IOMMU_DOMAIN_UNMANAGED:
- --            dmar_domain = alloc_domain(type);
- --            if (!dmar_domain) {
- --                    pr_err("Can't allocate dmar_domain\n");
- --                    return NULL;
- --            }
- --            if (md_domain_init(dmar_domain, DEFAULT_DOMAIN_ADDRESS_WIDTH)) {
- --                    pr_err("Domain initialization failed\n");
- --                    domain_exit(dmar_domain);
- --                    return NULL;
- --            }
- --
- --            domain = &dmar_domain->domain;
- --            domain->geometry.aperture_start = 0;
- --            domain->geometry.aperture_end   =
- --                            __DOMAIN_MAX_ADDR(dmar_domain->gaw);
- --            domain->geometry.force_aperture = true;
- --
- --            return domain;
- --    default:
- --            return NULL;
- --    }
- --
- --    return NULL;
- --}
- --
    static struct iommu_domain *
    intel_iommu_domain_alloc_user(struct device *dev, u32 flags,
                              struct iommu_domain *parent,
        struct intel_iommu *iommu = info->iommu;
        struct dmar_domain *dmar_domain;
        struct iommu_domain *domain;
+ ++    bool first_stage;
    
        /* Must be NESTING domain */
        if (parent) {
        }
    
        if (flags &
- --        (~(IOMMU_HWPT_ALLOC_NEST_PARENT | IOMMU_HWPT_ALLOC_DIRTY_TRACKING)))
+ ++        (~(IOMMU_HWPT_ALLOC_NEST_PARENT | IOMMU_HWPT_ALLOC_DIRTY_TRACKING
+ ++           | IOMMU_HWPT_FAULT_ID_VALID)))
                return ERR_PTR(-EOPNOTSUPP);
        if (nested_parent && !nested_supported(iommu))
                return ERR_PTR(-EOPNOTSUPP);
        if (user_data || (dirty_tracking && !ssads_supported(iommu)))
                return ERR_PTR(-EOPNOTSUPP);
    
- --    /* Do not use first stage for user domain translation. */
- --    dmar_domain = paging_domain_alloc(dev, false);
+ ++    /*
+ ++     * Always allocate the guest compatible page table unless
+ ++     * IOMMU_HWPT_ALLOC_NEST_PARENT or IOMMU_HWPT_ALLOC_DIRTY_TRACKING
+ ++     * is specified.
+ ++     */
+ ++    if (nested_parent || dirty_tracking) {
+ ++            if (!sm_supported(iommu) || !ecap_slts(iommu->ecap))
+ ++                    return ERR_PTR(-EOPNOTSUPP);
+ ++            first_stage = false;
+ ++    } else {
+ ++            first_stage = first_level_by_default(iommu);
+ ++    }
+ ++
+ ++    dmar_domain = paging_domain_alloc(dev, first_stage);
        if (IS_ERR(dmar_domain))
                return ERR_CAST(dmar_domain);
        domain = &dmar_domain->domain;
@@@@@ -3583,42 -3401,41 -3581,42 -3581,42 +3403,41 @@@@@ static void intel_iommu_domain_free(str
        domain_exit(dmar_domain);
    }
    
- --int prepare_domain_attach_device(struct iommu_domain *domain,
- --                             struct device *dev)
+ ++int paging_domain_compatible(struct iommu_domain *domain, struct device *dev)
    {
        struct device_domain_info *info = dev_iommu_priv_get(dev);
        struct dmar_domain *dmar_domain = to_dmar_domain(domain);
        struct intel_iommu *iommu = info->iommu;
        int addr_width;
    
+ ++    if (WARN_ON_ONCE(!(domain->type & __IOMMU_DOMAIN_PAGING)))
+ ++            return -EPERM;
+ ++
        if (dmar_domain->force_snooping && !ecap_sc_support(iommu->ecap))
                return -EINVAL;
    
        if (domain->dirty_ops && !ssads_supported(iommu))
                return -EINVAL;
    
+ ++    if (dmar_domain->iommu_coherency !=
+ ++                    iommu_paging_structure_coherency(iommu))
+ ++            return -EINVAL;
+ ++
+ ++    if (dmar_domain->iommu_superpage !=
+ ++                    iommu_superpage_capability(iommu, dmar_domain->use_first_level))
+ ++            return -EINVAL;
+ ++
+ ++    if (dmar_domain->use_first_level &&
+ ++        (!sm_supported(iommu) || !ecap_flts(iommu->ecap)))
+ ++            return -EINVAL;
+ ++
        /* check if this iommu agaw is sufficient for max mapped address */
        addr_width = agaw_to_width(iommu->agaw);
        if (addr_width > cap_mgaw(iommu->cap))
                addr_width = cap_mgaw(iommu->cap);
    
- --    if (dmar_domain->max_addr > (1LL << addr_width))
+ ++    if (dmar_domain->gaw > addr_width || dmar_domain->agaw > iommu->agaw)
                return -EINVAL;
- --    dmar_domain->gaw = addr_width;
- --
- --    /*
- --     * Knock out extra levels of page tables if necessary
- --     */
- --    while (iommu->agaw < dmar_domain->agaw) {
- --            struct dma_pte *pte;
- --
- --            pte = dmar_domain->pgd;
- --            if (dma_pte_present(pte)) {
- --                    dmar_domain->pgd = phys_to_virt(dma_pte_addr(pte));
- --                    iommu_free_page(pte);
- --            }
- --            dmar_domain->agaw--;
- --    }
    
        if (sm_supported(iommu) && !dev_is_real_dma_subdevice(dev) &&
            context_copied(iommu, info->bus, info->devfn))
@@@@@ -3634,7 -3451,7 -3632,7 -3632,7 +3453,7 @@@@@ static int intel_iommu_attach_device(st
    
        device_block_translation(dev);
    
- --    ret = prepare_domain_attach_device(domain, dev);
+ ++    ret = paging_domain_compatible(domain, dev);
        if (ret)
                return ret;
    
@@@@@ -4252,8 -4069,8 -4250,8 -4250,8 +4071,8 @@@@@ static int intel_iommu_iotlb_sync_map(s
        return 0;
    }
    
- --static void intel_iommu_remove_dev_pasid(struct device *dev, ioasid_t pasid,
- --                                     struct iommu_domain *domain)
+ ++void domain_remove_dev_pasid(struct iommu_domain *domain,
+ ++                         struct device *dev, ioasid_t pasid)
    {
        struct device_domain_info *info = dev_iommu_priv_get(dev);
        struct dev_pasid_info *curr, *dev_pasid = NULL;
        struct dmar_domain *dmar_domain;
        unsigned long flags;
    
- --    if (domain->type == IOMMU_DOMAIN_IDENTITY) {
- --            intel_pasid_tear_down_entry(iommu, dev, pasid, false);
+ ++    if (!domain)
+ ++            return;
+ ++
+ ++    /* Identity domain has no meta data for pasid. */
+ ++    if (domain->type == IOMMU_DOMAIN_IDENTITY)
                return;
- --    }
    
        dmar_domain = to_dmar_domain(domain);
        spin_lock_irqsave(&dmar_domain->lock, flags);
        domain_detach_iommu(dmar_domain, iommu);
        intel_iommu_debugfs_remove_dev_pasid(dev_pasid);
        kfree(dev_pasid);
- --    intel_pasid_tear_down_entry(iommu, dev, pasid, false);
- --    intel_drain_pasid_prq(dev, pasid);
    }
    
- --static int intel_iommu_set_dev_pasid(struct iommu_domain *domain,
- --                                 struct device *dev, ioasid_t pasid)
+ ++static void intel_iommu_remove_dev_pasid(struct device *dev, ioasid_t pasid,
+ ++                                     struct iommu_domain *domain)
+ ++{
+ ++    struct device_domain_info *info = dev_iommu_priv_get(dev);
+ ++
+ ++    intel_pasid_tear_down_entry(info->iommu, dev, pasid, false);
+ ++    domain_remove_dev_pasid(domain, dev, pasid);
+ ++}
+ ++
+ ++struct dev_pasid_info *
+ ++domain_add_dev_pasid(struct iommu_domain *domain,
+ ++                 struct device *dev, ioasid_t pasid)
    {
        struct device_domain_info *info = dev_iommu_priv_get(dev);
        struct dmar_domain *dmar_domain = to_dmar_domain(domain);
        unsigned long flags;
        int ret;
    
- --    if (!pasid_supported(iommu) || dev_is_real_dma_subdevice(dev))
- --            return -EOPNOTSUPP;
- --
- --    if (domain->dirty_ops)
- --            return -EINVAL;
- --
- --    if (context_copied(iommu, info->bus, info->devfn))
- --            return -EBUSY;
- --
- --    ret = prepare_domain_attach_device(domain, dev);
- --    if (ret)
- --            return ret;
- --
        dev_pasid = kzalloc(sizeof(*dev_pasid), GFP_KERNEL);
        if (!dev_pasid)
- --            return -ENOMEM;
+ ++            return ERR_PTR(-ENOMEM);
    
        ret = domain_attach_iommu(dmar_domain, iommu);
        if (ret)
        if (ret)
                goto out_detach_iommu;
    
- --    if (dmar_domain->use_first_level)
- --            ret = domain_setup_first_level(iommu, dmar_domain,
- --                                           dev, pasid);
- --    else
- --            ret = intel_pasid_setup_second_level(iommu, dmar_domain,
- --                                                 dev, pasid);
- --    if (ret)
- --            goto out_unassign_tag;
- --
        dev_pasid->dev = dev;
        dev_pasid->pasid = pasid;
        spin_lock_irqsave(&dmar_domain->lock, flags);
        list_add(&dev_pasid->link_domain, &dmar_domain->dev_pasids);
        spin_unlock_irqrestore(&dmar_domain->lock, flags);
    
- --    if (domain->type & __IOMMU_DOMAIN_PAGING)
- --            intel_iommu_debugfs_create_dev_pasid(dev_pasid);
- --
- --    return 0;
- --out_unassign_tag:
- --    cache_tag_unassign_domain(dmar_domain, dev, pasid);
+ ++    return dev_pasid;
    out_detach_iommu:
        domain_detach_iommu(dmar_domain, iommu);
    out_free:
        kfree(dev_pasid);
+ ++    return ERR_PTR(ret);
+ ++}
+ ++
+ ++static int intel_iommu_set_dev_pasid(struct iommu_domain *domain,
+ ++                                 struct device *dev, ioasid_t pasid,
+ ++                                 struct iommu_domain *old)
+ ++{
+ ++    struct device_domain_info *info = dev_iommu_priv_get(dev);
+ ++    struct dmar_domain *dmar_domain = to_dmar_domain(domain);
+ ++    struct intel_iommu *iommu = info->iommu;
+ ++    struct dev_pasid_info *dev_pasid;
+ ++    int ret;
+ ++
+ ++    if (WARN_ON_ONCE(!(domain->type & __IOMMU_DOMAIN_PAGING)))
+ ++            return -EINVAL;
+ ++
+ ++    if (!pasid_supported(iommu) || dev_is_real_dma_subdevice(dev))
+ ++            return -EOPNOTSUPP;
+ ++
+ ++    if (domain->dirty_ops)
+ ++            return -EINVAL;
+ ++
+ ++    if (context_copied(iommu, info->bus, info->devfn))
+ ++            return -EBUSY;
+ ++
+ ++    ret = paging_domain_compatible(domain, dev);
+ ++    if (ret)
+ ++            return ret;
+ ++
+ ++    dev_pasid = domain_add_dev_pasid(domain, dev, pasid);
+ ++    if (IS_ERR(dev_pasid))
+ ++            return PTR_ERR(dev_pasid);
+ ++
+ ++    if (dmar_domain->use_first_level)
+ ++            ret = domain_setup_first_level(iommu, dmar_domain,
+ ++                                           dev, pasid, old);
+ ++    else
+ ++            ret = domain_setup_second_level(iommu, dmar_domain,
+ ++                                            dev, pasid, old);
+ ++    if (ret)
+ ++            goto out_remove_dev_pasid;
+ ++
+ ++    domain_remove_dev_pasid(old, dev, pasid);
+ ++
+ ++    intel_iommu_debugfs_create_dev_pasid(dev_pasid);
+ ++
+ ++    return 0;
+ ++
+ ++out_remove_dev_pasid:
+ ++    domain_remove_dev_pasid(domain, dev, pasid);
        return ret;
    }
    
@@@@@ -4573,15 -4423,22 -4571,15 -4571,15 +4425,22 @@@@@ static int identity_domain_attach_dev(s
    }
    
    static int identity_domain_set_dev_pasid(struct iommu_domain *domain,
- --                                     struct device *dev, ioasid_t pasid)
+ ++                                     struct device *dev, ioasid_t pasid,
+ ++                                     struct iommu_domain *old)
    {
        struct device_domain_info *info = dev_iommu_priv_get(dev);
        struct intel_iommu *iommu = info->iommu;
+ ++    int ret;
    
        if (!pasid_supported(iommu) || dev_is_real_dma_subdevice(dev))
                return -EOPNOTSUPP;
    
- --    return intel_pasid_setup_pass_through(iommu, dev, pasid);
+ ++    ret = domain_setup_passthrough(iommu, dev, pasid, old);
+ ++    if (ret)
+ ++            return ret;
+ ++
+ ++    domain_remove_dev_pasid(old, dev, pasid);
+ ++    return 0;
    }
    
    static struct iommu_domain identity_domain = {
        },
    };
    
+ ++static struct iommu_domain *intel_iommu_domain_alloc_paging(struct device *dev)
+ ++{
+ ++    struct device_domain_info *info = dev_iommu_priv_get(dev);
+ ++    struct intel_iommu *iommu = info->iommu;
+ ++    struct dmar_domain *dmar_domain;
+ ++    bool first_stage;
+ ++
+ ++    first_stage = first_level_by_default(iommu);
+ ++    dmar_domain = paging_domain_alloc(dev, first_stage);
+ ++    if (IS_ERR(dmar_domain))
+ ++            return ERR_CAST(dmar_domain);
+ ++
+ ++    return &dmar_domain->domain;
+ ++}
+ ++
    const struct iommu_ops intel_iommu_ops = {
        .blocked_domain         = &blocking_domain,
        .release_domain         = &blocking_domain,
        .identity_domain        = &identity_domain,
        .capable                = intel_iommu_capable,
        .hw_info                = intel_iommu_hw_info,
- --    .domain_alloc           = intel_iommu_domain_alloc,
        .domain_alloc_user      = intel_iommu_domain_alloc_user,
        .domain_alloc_sva       = intel_svm_domain_alloc,
+ ++    .domain_alloc_paging    = intel_iommu_domain_alloc_paging,
        .probe_device           = intel_iommu_probe_device,
        .release_device         = intel_iommu_release_device,
        .get_resv_regions       = intel_iommu_get_resv_regions,
        .def_domain_type        = device_def_domain_type,
        .remove_dev_pasid       = intel_iommu_remove_dev_pasid,
        .pgsize_bitmap          = SZ_4K,
- --#ifdef CONFIG_INTEL_IOMMU_SVM
- --    .page_response          = intel_svm_page_response,
- --#endif
+ ++    .page_response          = intel_iommu_page_response,
        .default_domain_ops = &(const struct iommu_domain_ops) {
                .attach_dev             = intel_iommu_attach_device,
                .set_dev_pasid          = intel_iommu_set_dev_pasid,
diff --combined drivers/iommu/iommu.c
index 87a0721c7b6d7c9ee63a6b144b86bba5f23382c8,f3f81c04b8fbfceed66ac6620740ef87e527924d,0d08a32560857edfd1803eb439a2813214c3aa5d,dbd70d5a4702cc563352ca0cdebbd54e9229956b..7618e9c65d3fa8c7c6753a0999def021548a6d8d
    #include <trace/events/iommu.h>
    #include <linux/sched/mm.h>
    #include <linux/msi.h>
 + +#include <uapi/linux/iommufd.h>
    
    #include "dma-iommu.h"
    #include "iommu-priv.h"
@@@@@ -91,17 -90,15 -91,16 -90,15 +91,17 @@@@@ static const char * const iommu_group_r
    #define IOMMU_CMD_LINE_DMA_API              BIT(0)
    #define IOMMU_CMD_LINE_STRICT               BIT(1)
    
 +++static int bus_iommu_probe(const struct bus_type *bus);
    static int iommu_bus_notifier(struct notifier_block *nb,
                              unsigned long action, void *data);
    static void iommu_release_device(struct device *dev);
 - -static struct iommu_domain *
 - -__iommu_group_domain_alloc(struct iommu_group *group, unsigned int type);
    static int __iommu_attach_device(struct iommu_domain *domain,
                                 struct device *dev);
    static int __iommu_attach_group(struct iommu_domain *domain,
                                struct iommu_group *group);
 + +static struct iommu_domain *__iommu_paging_domain_alloc_flags(struct device *dev,
 + +                                                   unsigned int type,
 + +                                                   unsigned int flags);
    
    enum {
        IOMMU_SET_DOMAIN_MUST_SUCCEED = 1 << 0,
@@@@@ -136,8 -133,6 -135,8 -133,6 +136,8 @@@@@ static struct group_device *iommu_group
                                                     struct device *dev);
    static void __iommu_group_free_device(struct iommu_group *group,
                                      struct group_device *grp_dev);
 + +static void iommu_domain_init(struct iommu_domain *domain, unsigned int type,
 + +                          const struct iommu_ops *ops);
    
    #define IOMMU_GROUP_ATTR(_name, _mode, _show, _store)               \
    struct iommu_group_attribute iommu_group_attr_##_name =             \
@@@@@ -1146,6 -1141,10 -1145,6 -1141,10 +1146,6 @@@@@ map_end
                }
    
        }
 - -
 - -    if (!list_empty(&mappings) && iommu_is_dma_domain(domain))
 - -            iommu_flush_iotlb_all(domain);
 - -
    out:
        iommu_put_resv_regions(dev, &mappings);
    
@@@@@ -1587,59 -1586,12 -1586,59 -1586,12 +1587,59 @@@@@ struct iommu_group *fsl_mc_device_group
    }
    EXPORT_SYMBOL_GPL(fsl_mc_device_group);
    
 + +static struct iommu_domain *__iommu_alloc_identity_domain(struct device *dev)
 + +{
 + +    const struct iommu_ops *ops = dev_iommu_ops(dev);
 + +    struct iommu_domain *domain;
 + +
 + +    if (ops->identity_domain)
 + +            return ops->identity_domain;
 + +
 + +    /* Older drivers create the identity domain via ops->domain_alloc() */
 + +    if (!ops->domain_alloc)
 + +            return ERR_PTR(-EOPNOTSUPP);
 + +
 + +    domain = ops->domain_alloc(IOMMU_DOMAIN_IDENTITY);
 + +    if (IS_ERR(domain))
 + +            return domain;
 + +    if (!domain)
 + +            return ERR_PTR(-ENOMEM);
 + +
 + +    iommu_domain_init(domain, IOMMU_DOMAIN_IDENTITY, ops);
 + +    return domain;
 + +}
 + +
    static struct iommu_domain *
    __iommu_group_alloc_default_domain(struct iommu_group *group, int req_type)
    {
 + +    struct device *dev = iommu_group_first_dev(group);
 + +    struct iommu_domain *dom;
 + +
        if (group->default_domain && group->default_domain->type == req_type)
                return group->default_domain;
 - -    return __iommu_group_domain_alloc(group, req_type);
 + +
 + +    /*
 + +     * When allocating the DMA API domain assume that the driver is going to
 + +     * use PASID and make sure the RID's domain is PASID compatible.
 + +     */
 + +    if (req_type & __IOMMU_DOMAIN_PAGING) {
 + +            dom = __iommu_paging_domain_alloc_flags(dev, req_type,
 + +                       dev->iommu->max_pasids ? IOMMU_HWPT_ALLOC_PASID : 0);
 + +
 + +            /*
 + +             * If driver does not support PASID feature then
 + +             * try to allocate non-PASID domain
 + +             */
 + +            if (PTR_ERR(dom) == -EOPNOTSUPP)
 + +                    dom = __iommu_paging_domain_alloc_flags(dev, req_type, 0);
 + +
 + +            return dom;
 + +    }
 + +
 + +    if (req_type == IOMMU_DOMAIN_IDENTITY)
 + +            return __iommu_alloc_identity_domain(dev);
 + +
 + +    return ERR_PTR(-EINVAL);
    }
    
    /*
@@@@@ -1843,7 -1795,7 -1842,7 -1795,7 +1843,7 @@@@@ static void iommu_group_do_probe_finali
                ops->probe_finalize(dev);
    }
    
 ---int bus_iommu_probe(const struct bus_type *bus)
 +++static int bus_iommu_probe(const struct bus_type *bus)
    {
        struct iommu_group *group, *next;
        LIST_HEAD(group_list);
        return 0;
    }
    
 - -/**
 - - * iommu_present() - make platform-specific assumptions about an IOMMU
 - - * @bus: bus to check
 - - *
 - - * Do not use this function. You want device_iommu_mapped() instead.
 - - *
 - - * Return: true if some IOMMU is present and aware of devices on the given bus;
 - - * in general it may not be the only IOMMU, and it may not have anything to do
 - - * with whatever device you are ultimately interested in.
 - - */
 - -bool iommu_present(const struct bus_type *bus)
 - -{
 - -    bool ret = false;
 - -
 - -    for (int i = 0; i < ARRAY_SIZE(iommu_buses); i++) {
 - -            if (iommu_buses[i] == bus) {
 - -                    spin_lock(&iommu_device_lock);
 - -                    ret = !list_empty(&iommu_device_list);
 - -                    spin_unlock(&iommu_device_lock);
 - -            }
 - -    }
 - -    return ret;
 - -}
 - -EXPORT_SYMBOL_GPL(iommu_present);
 - -
    /**
     * device_iommu_capable() - check for a general IOMMU capability
     * @dev: device to which the capability would be relevant, if available
@@@@@ -1957,67 -1934,117 -1956,67 -1934,117 +1957,67 @@@@@ void iommu_set_fault_handler(struct iom
    }
    EXPORT_SYMBOL_GPL(iommu_set_fault_handler);
    
 - -static struct iommu_domain *__iommu_domain_alloc(const struct iommu_ops *ops,
 - -                                             struct device *dev,
 - -                                             unsigned int type)
 + +static void iommu_domain_init(struct iommu_domain *domain, unsigned int type,
 + +                          const struct iommu_ops *ops)
    {
 - -    struct iommu_domain *domain;
 - -    unsigned int alloc_type = type & IOMMU_DOMAIN_ALLOC_FLAGS;
 - -
 - -    if (alloc_type == IOMMU_DOMAIN_IDENTITY && ops->identity_domain)
 - -            return ops->identity_domain;
 - -    else if (alloc_type == IOMMU_DOMAIN_BLOCKED && ops->blocked_domain)
 - -            return ops->blocked_domain;
 - -    else if (type & __IOMMU_DOMAIN_PAGING && ops->domain_alloc_paging)
 - -            domain = ops->domain_alloc_paging(dev);
 - -    else if (ops->domain_alloc)
 - -            domain = ops->domain_alloc(alloc_type);
 - -    else
 - -            return ERR_PTR(-EOPNOTSUPP);
 - -
 - -    /*
 - -     * Many domain_alloc ops now return ERR_PTR, make things easier for the
 - -     * driver by accepting ERR_PTR from all domain_alloc ops instead of
 - -     * having two rules.
 - -     */
 - -    if (IS_ERR(domain))
 - -            return domain;
 - -    if (!domain)
 - -            return ERR_PTR(-ENOMEM);
 - -
        domain->type = type;
        domain->owner = ops;
 + +    if (!domain->ops)
 + +            domain->ops = ops->default_domain_ops;
 + +
        /*
         * If not already set, assume all sizes by default; the driver
         * may override this later
         */
        if (!domain->pgsize_bitmap)
                domain->pgsize_bitmap = ops->pgsize_bitmap;
 - -
 - -    if (!domain->ops)
 - -            domain->ops = ops->default_domain_ops;
 - -
 - -    if (iommu_is_dma_domain(domain)) {
 - -            int rc;
 - -
 - -            rc = iommu_get_dma_cookie(domain);
 - -            if (rc) {
 - -                    iommu_domain_free(domain);
 - -                    return ERR_PTR(rc);
 - -            }
 - -    }
 - -    return domain;
    }
    
    static struct iommu_domain *
 - -__iommu_group_domain_alloc(struct iommu_group *group, unsigned int type)
 - -{
 - -    struct device *dev = iommu_group_first_dev(group);
 - -
 - -    return __iommu_domain_alloc(dev_iommu_ops(dev), dev, type);
 - -}
 - -
 - -static int __iommu_domain_alloc_dev(struct device *dev, void *data)
 + +__iommu_paging_domain_alloc_flags(struct device *dev, unsigned int type,
 + +                              unsigned int flags)
    {
 - -    const struct iommu_ops **ops = data;
 + +    const struct iommu_ops *ops;
 + +    struct iommu_domain *domain;
    
        if (!dev_has_iommu(dev))
 - -            return 0;
 - -
 - -    if (WARN_ONCE(*ops && *ops != dev_iommu_ops(dev),
 - -                  "Multiple IOMMU drivers present for bus %s, which the public IOMMU API can't fully support yet. You will still need to disable one or more for this to work, sorry!\n",
 - -                  dev_bus_name(dev)))
 - -            return -EBUSY;
 - -
 - -    *ops = dev_iommu_ops(dev);
 - -    return 0;
 - -}
 + +            return ERR_PTR(-ENODEV);
    
 - -/*
 - - * The iommu ops in bus has been retired. Do not use this interface in
 - - * new drivers.
 - - */
 - -struct iommu_domain *iommu_domain_alloc(const struct bus_type *bus)
 - -{
 - -    const struct iommu_ops *ops = NULL;
 - -    int err = bus_for_each_dev(bus, NULL, &ops, __iommu_domain_alloc_dev);
 - -    struct iommu_domain *domain;
 + +    ops = dev_iommu_ops(dev);
    
 - -    if (err || !ops)
 - -            return NULL;
 + +    if (ops->domain_alloc_paging && !flags)
 + +            domain = ops->domain_alloc_paging(dev);
 + +    else if (ops->domain_alloc_user)
 + +            domain = ops->domain_alloc_user(dev, flags, NULL, NULL);
 + +    else if (ops->domain_alloc && !flags)
 + +            domain = ops->domain_alloc(IOMMU_DOMAIN_UNMANAGED);
 + +    else
 + +            return ERR_PTR(-EOPNOTSUPP);
    
 - -    domain = __iommu_domain_alloc(ops, NULL, IOMMU_DOMAIN_UNMANAGED);
        if (IS_ERR(domain))
 - -            return NULL;
 + +            return domain;
 + +    if (!domain)
 + +            return ERR_PTR(-ENOMEM);
 + +
 + +    iommu_domain_init(domain, type, ops);
        return domain;
    }
 - -EXPORT_SYMBOL_GPL(iommu_domain_alloc);
    
    /**
 - - * iommu_paging_domain_alloc() - Allocate a paging domain
 + + * iommu_paging_domain_alloc_flags() - Allocate a paging domain
     * @dev: device for which the domain is allocated
 + + * @flags: Bitmap of iommufd_hwpt_alloc_flags
     *
     * Allocate a paging domain which will be managed by a kernel driver. Return
 - - * allocated domain if successful, or a ERR pointer for failure.
 + + * allocated domain if successful, or an ERR pointer for failure.
     */
 - -struct iommu_domain *iommu_paging_domain_alloc(struct device *dev)
 + +struct iommu_domain *iommu_paging_domain_alloc_flags(struct device *dev,
 + +                                                 unsigned int flags)
    {
 - -    if (!dev_has_iommu(dev))
 - -            return ERR_PTR(-ENODEV);
 - -
 - -    return __iommu_domain_alloc(dev_iommu_ops(dev), dev, IOMMU_DOMAIN_UNMANAGED);
 + +    return __iommu_paging_domain_alloc_flags(dev,
 + +                                     IOMMU_DOMAIN_UNMANAGED, flags);
    }
 - -EXPORT_SYMBOL_GPL(iommu_paging_domain_alloc);
 + +EXPORT_SYMBOL_GPL(iommu_paging_domain_alloc_flags);
    
    void iommu_domain_free(struct iommu_domain *domain)
    {
@@@@@ -2189,8 -2216,8 -2188,8 -2216,8 +2189,8 @@@@@ EXPORT_SYMBOL_GPL(iommu_attach_group)
    
    /**
     * iommu_group_replace_domain - replace the domain that a group is attached to
 - - * @new_domain: new IOMMU domain to replace with
     * @group: IOMMU group that will be attached to the new domain
 + + * @new_domain: new IOMMU domain to replace with
     *
     * This API allows the group to switch domains without being forced to go to
     * the blocking domain in-between.
@@@@@ -2559,20 -2586,6 -2558,6 -2586,6 +2559,20 @@@@@ static size_t __iommu_unmap(struct iomm
        return unmapped;
    }
    
 +++/**
 +++ * iommu_unmap() - Remove mappings from a range of IOVA
 +++ * @domain: Domain to manipulate
 +++ * @iova: IO virtual address to start
 +++ * @size: Length of the range starting from @iova
 +++ *
 +++ * iommu_unmap() will remove a translation created by iommu_map(). It cannot
 +++ * subdivide a mapping created by iommu_map(), so it should be called with IOVA
 +++ * ranges that match what was passed to iommu_map(). The range can aggregate
 +++ * contiguous iommu_map() calls so long as no individual range is split.
 +++ *
 +++ * Returns: Number of bytes of IOVA unmapped. iova + res will be the point
 +++ * unmapping stopped.
 +++ */
    size_t iommu_unmap(struct iommu_domain *domain,
                   unsigned long iova, size_t size)
    {
@@@@@ -2710,16 -2723,16 -2695,16 -2723,6 +2710,6 @@@@@ static int __init iommu_init(void
    }
    core_initcall(iommu_init);
    
--- int iommu_enable_nesting(struct iommu_domain *domain)
--- {
---     if (domain->type != IOMMU_DOMAIN_UNMANAGED)
---             return -EINVAL;
---     if (!domain->ops->enable_nesting)
---             return -EINVAL;
---     return domain->ops->enable_nesting(domain);
--- }
--- EXPORT_SYMBOL_GPL(iommu_enable_nesting);
--- 
    int iommu_set_pgtable_quirks(struct iommu_domain *domain,
                unsigned long quirk)
    {
@@@@@ -2952,14 -2965,6 -2937,14 -2955,6 +2942,14 @@@@@ static int iommu_setup_default_domain(s
        if (group->default_domain == dom)
                return 0;
    
 + +    if (iommu_is_dma_domain(dom)) {
 + +            ret = iommu_get_dma_cookie(dom);
 + +            if (ret) {
 + +                    iommu_domain_free(dom);
 + +                    return ret;
 + +            }
 + +    }
 + +
        /*
         * IOMMU_RESV_DIRECT and IOMMU_RESV_DIRECT_RELAXABLE regions must be
         * mapped before their device is attached, in order to guarantee
@@@@@ -3147,25 -3152,22 -3132,25 -3142,22 +3137,25 @@@@@ void iommu_device_unuse_default_domain(
    
    static int __iommu_group_alloc_blocking_domain(struct iommu_group *group)
    {
 + +    struct device *dev = iommu_group_first_dev(group);
 + +    const struct iommu_ops *ops = dev_iommu_ops(dev);
        struct iommu_domain *domain;
    
        if (group->blocking_domain)
                return 0;
    
 - -    domain = __iommu_group_domain_alloc(group, IOMMU_DOMAIN_BLOCKED);
 - -    if (IS_ERR(domain)) {
 - -            /*
 - -             * For drivers that do not yet understand IOMMU_DOMAIN_BLOCKED
 - -             * create an empty domain instead.
 - -             */
 - -            domain = __iommu_group_domain_alloc(group,
 - -                                                IOMMU_DOMAIN_UNMANAGED);
 - -            if (IS_ERR(domain))
 - -                    return PTR_ERR(domain);
 + +    if (ops->blocked_domain) {
 + +            group->blocking_domain = ops->blocked_domain;
 + +            return 0;
        }
 + +
 + +    /*
 + +     * For drivers that do not yet understand IOMMU_DOMAIN_BLOCKED create an
 + +     * empty PAGING domain instead.
 + +     */
 + +    domain = iommu_paging_domain_alloc(dev);
 + +    if (IS_ERR(domain))
 + +            return PTR_ERR(domain);
        group->blocking_domain = domain;
        return 0;
    }
@@@@@ -3329,7 -3331,8 -3314,7 -3321,7 +3319,8 @@@@@ static int __iommu_set_group_pasid(stru
        int ret;
    
        for_each_group_device(group, device) {
- --            ret = domain->ops->set_dev_pasid(domain, device->dev, pasid);
+ ++            ret = domain->ops->set_dev_pasid(domain, device->dev,
+ ++                                             pasid, NULL);
                if (ret)
                        goto err_revert;
        }
diff --combined include/linux/iommu.h
index 9a3215b5c1e5d46f5fb000b2d32c352b818ee553,27f923450a7c8fde27968e922d744c4141b9fd38,8cce372a33f10f5c0a91c2a01ae4f6f19deafd38,4ad9b9ec6c9b2713fa8663fc1885949dbf5e1fe0..0c3bfb66dc7c3287c647a7a95f2c651cbe4cffea
@@@@@ -511,6 -511,8 -511,6 -511,8 +511,6 @@@@@ static inline int __iommu_copy_struct_f
     *                the caller iommu_domain_alloc() returns.
     * @domain_alloc_user: Allocate an iommu domain corresponding to the input
     *                     parameters as defined in include/uapi/linux/iommufd.h.
 - - *                     Unlike @domain_alloc, it is called only by IOMMUFD and
 - - *                     must fully initialize the new domain before return.
     *                     Upon success, if the @user_data is valid and the @parent
     *                     points to a kernel-managed domain, the new domain must be
     *                     IOMMU_DOMAIN_NESTED type; otherwise, the @parent must be
@@@@@ -614,7 -616,8 -614,7 -616,7 +614,8 @@@@@ struct iommu_ops 
     * * EBUSY  - device is attached to a domain and cannot be changed
     * * ENODEV - device specific errors, not able to be attached
     * * <others>       - treated as ENODEV by the caller. Use is discouraged
- -- * @set_dev_pasid: set an iommu domain to a pasid of device
+ ++ * @set_dev_pasid: set or replace an iommu domain to a pasid of device. The pasid of
+ ++ *                 the device should be left in the old config in error case.
     * @map_pages: map a physically contiguous set of pages of the same size to
     *             an iommu domain.
     * @unmap_pages: unmap a number of pages of the same size from an iommu domain
     * @enforce_cache_coherency: Prevent any kind of DMA from bypassing IOMMU_CACHE,
     *                           including no-snoop TLPs on PCIe or other platform
     *                           specific mechanisms.
---  * @enable_nesting: Enable nesting
     * @set_pgtable_quirks: Set io page table quirks (IO_PGTABLE_QUIRK_*)
     * @free: Release the domain after use.
     */
    struct iommu_domain_ops {
        int (*attach_dev)(struct iommu_domain *domain, struct device *dev);
        int (*set_dev_pasid)(struct iommu_domain *domain, struct device *dev,
- --                         ioasid_t pasid);
+ ++                         ioasid_t pasid, struct iommu_domain *old);
    
        int (*map_pages)(struct iommu_domain *domain, unsigned long iova,
                         phys_addr_t paddr, size_t pgsize, size_t pgcount,
                                    dma_addr_t iova);
    
        bool (*enforce_cache_coherency)(struct iommu_domain *domain);
---     int (*enable_nesting)(struct iommu_domain *domain);
        int (*set_pgtable_quirks)(struct iommu_domain *domain,
                                  unsigned long quirks);
    
@@@@@ -782,14 -785,12 -782,14 -782,12 +781,14 @@@@@ static inline void iommu_iotlb_gather_i
        };
    }
    
 ---extern int bus_iommu_probe(const struct bus_type *bus);
  + extern bool iommu_present(const struct bus_type *bus);
    extern bool device_iommu_capable(struct device *dev, enum iommu_cap cap);
    extern bool iommu_group_has_isolated_msi(struct iommu_group *group);
 - -extern struct iommu_domain *iommu_domain_alloc(const struct bus_type *bus);
 - -struct iommu_domain *iommu_paging_domain_alloc(struct device *dev);
 + +struct iommu_domain *iommu_paging_domain_alloc_flags(struct device *dev, unsigned int flags);
 + +static inline struct iommu_domain *iommu_paging_domain_alloc(struct device *dev)
 + +{
 + +    return iommu_paging_domain_alloc_flags(dev, 0);
 + +}
    extern void iommu_domain_free(struct iommu_domain *domain);
    extern int iommu_attach_device(struct iommu_domain *domain,
                               struct device *dev);
@@@@@ -844,7 -845,7 -844,7 -842,6 +843,6 @@@@@ extern void iommu_group_put(struct iomm
    extern int iommu_group_id(struct iommu_group *group);
    extern struct iommu_domain *iommu_group_default_domain(struct iommu_group *);
    
--- int iommu_enable_nesting(struct iommu_domain *domain);
    int iommu_set_pgtable_quirks(struct iommu_domain *domain,
                unsigned long quirks);
    
@@@@@ -994,6 -995,6 -994,6 -991,8 +992,8 @@@@@ struct iommu_fwspec 
    
    /* ATS is supported */
    #define IOMMU_FWSPEC_PCI_RC_ATS                     (1 << 0)
+++ /* CANWBS is supported */
+++ #define IOMMU_FWSPEC_PCI_RC_CANWBS          (1 << 1)
    
    /*
     * An iommu attach handle represents a relationship between an iommu domain
@@@@@ -1081,15 -1082,19 -1081,15 -1080,19 +1081,15 @@@@@ struct iommu_iotlb_gather {}
    struct iommu_dirty_bitmap {};
    struct iommu_dirty_ops {};
    
 - -static inline bool iommu_present(const struct bus_type *bus)
 - -{
 - -    return false;
 - -}
 - -
    static inline bool device_iommu_capable(struct device *dev, enum iommu_cap cap)
    {
        return false;
    }
    
 - -static inline struct iommu_domain *iommu_domain_alloc(const struct bus_type *bus)
 + +static inline struct iommu_domain *iommu_paging_domain_alloc_flags(struct device *dev,
 + +                                                 unsigned int flags)
    {
 - -    return NULL;
 + +    return ERR_PTR(-ENODEV);
    }
    
    static inline struct iommu_domain *iommu_paging_domain_alloc(struct device *dev)
index 0c0ed28ee11377e1c1d1896670507ed73d1789c4,72010f71c5e479e26be02435fdc45e990832b687,0c0ed28ee11377e1c1d1896670507ed73d1789c4,b5c94fecb94ca5f09a85184c3f009b55582179f4..cc1b94f4353820ef0a69c1041dffb14c9369d763
@@@@@ -359,19 -359,11 -359,19 -359,11 +359,19 @@@@@ struct iommu_vfio_ioas 
     *                                   enforced on device attachment
     * @IOMMU_HWPT_FAULT_ID_VALID: The fault_id field of hwpt allocation data is
     *                             valid.
 + + * @IOMMU_HWPT_ALLOC_PASID: Requests a domain that can be used with PASID. The
 + + *                          domain can be attached to any PASID on the device.
 + + *                          Any domain attached to the non-PASID part of the
 + + *                          device must also be flaged, otherwise attaching a
 + + *                          PASID will blocked.
 + + *                          If IOMMU does not support PASID it will return
 + + *                          error (-EOPNOTSUPP).
     */
    enum iommufd_hwpt_alloc_flags {
        IOMMU_HWPT_ALLOC_NEST_PARENT = 1 << 0,
        IOMMU_HWPT_ALLOC_DIRTY_TRACKING = 1 << 1,
        IOMMU_HWPT_FAULT_ID_VALID = 1 << 2,
 + +    IOMMU_HWPT_ALLOC_PASID = 1 << 3,
    };
    
    /**
@@@@@ -492,15 -484,15 -492,15 -484,50 +492,50 @@@@@ struct iommu_hw_info_vtd 
        __aligned_u64 ecap_reg;
    };
    
+++ /**
+++  * struct iommu_hw_info_arm_smmuv3 - ARM SMMUv3 hardware information
+++  *                                   (IOMMU_HW_INFO_TYPE_ARM_SMMUV3)
+++  *
+++  * @flags: Must be set to 0
+++  * @__reserved: Must be 0
+++  * @idr: Implemented features for ARM SMMU Non-secure programming interface
+++  * @iidr: Information about the implementation and implementer of ARM SMMU,
+++  *        and architecture version supported
+++  * @aidr: ARM SMMU architecture version
+++  *
+++  * For the details of @idr, @iidr and @aidr, please refer to the chapters
+++  * from 6.3.1 to 6.3.6 in the SMMUv3 Spec.
+++  *
+++  * User space should read the underlying ARM SMMUv3 hardware information for
+++  * the list of supported features.
+++  *
+++  * Note that these values reflect the raw HW capability, without any insight if
+++  * any required kernel driver support is present. Bits may be set indicating the
+++  * HW has functionality that is lacking kernel software support, such as BTM. If
+++  * a VMM is using this information to construct emulated copies of these
+++  * registers it should only forward bits that it knows it can support.
+++  *
+++  * In future, presence of required kernel support will be indicated in flags.
+++  */
+++ struct iommu_hw_info_arm_smmuv3 {
+++     __u32 flags;
+++     __u32 __reserved;
+++     __u32 idr[6];
+++     __u32 iidr;
+++     __u32 aidr;
+++ };
+++ 
    /**
     * enum iommu_hw_info_type - IOMMU Hardware Info Types
     * @IOMMU_HW_INFO_TYPE_NONE: Used by the drivers that do not report hardware
     *                           info
     * @IOMMU_HW_INFO_TYPE_INTEL_VTD: Intel VT-d iommu info type
+++  * @IOMMU_HW_INFO_TYPE_ARM_SMMUV3: ARM SMMUv3 iommu info type
     */
    enum iommu_hw_info_type {
        IOMMU_HW_INFO_TYPE_NONE = 0,
        IOMMU_HW_INFO_TYPE_INTEL_VTD = 1,
+++     IOMMU_HW_INFO_TYPE_ARM_SMMUV3 = 2,
    };
    
    /**
This page took 0.148611 seconds and 4 git commands to generate.