]> www.infradead.org Git - users/dwmw2/linux.git/commitdiff
iommu/arm-smmu-v3: Make smmu_domain->devices into an allocated list
authorJason Gunthorpe <jgg@nvidia.com>
Tue, 25 Jun 2024 12:37:34 +0000 (09:37 -0300)
committerWill Deacon <will@kernel.org>
Tue, 2 Jul 2024 14:39:47 +0000 (15:39 +0100)
The next patch will need to store the same master twice (with different
SSIDs), so allocate memory for each list element.

Tested-by: Nicolin Chen <nicolinc@nvidia.com>
Tested-by: Shameer Kolothum <shameerali.kolothum.thodi@huawei.com>
Reviewed-by: Michael Shavit <mshavit@google.com>
Reviewed-by: Nicolin Chen <nicolinc@nvidia.com>
Reviewed-by: Jerry Snitselaar <jsnitsel@redhat.com>
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
Link: https://lore.kernel.org/r/3-v9-5cd718286059+79186-smmuv3_newapi_p2b_jgg@nvidia.com
Signed-off-by: Will Deacon <will@kernel.org>
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h

index 71ca87c2c5c3b6e0f8da3c96be33b0cd0f425a1c..cb3a0e4143c84a8ca4ee127b4a0ed6fd034acb72 100644 (file)
@@ -38,12 +38,13 @@ static DEFINE_MUTEX(sva_lock);
 static void
 arm_smmu_update_s1_domain_cd_entry(struct arm_smmu_domain *smmu_domain)
 {
-       struct arm_smmu_master *master;
+       struct arm_smmu_master_domain *master_domain;
        struct arm_smmu_cd target_cd;
        unsigned long flags;
 
        spin_lock_irqsave(&smmu_domain->devices_lock, flags);
-       list_for_each_entry(master, &smmu_domain->devices, domain_head) {
+       list_for_each_entry(master_domain, &smmu_domain->devices, devices_elm) {
+               struct arm_smmu_master *master = master_domain->master;
                struct arm_smmu_cd *cdptr;
 
                /* S1 domains only support RID attachment right now */
@@ -301,7 +302,7 @@ static void arm_smmu_mm_release(struct mmu_notifier *mn, struct mm_struct *mm)
 {
        struct arm_smmu_mmu_notifier *smmu_mn = mn_to_smmu(mn);
        struct arm_smmu_domain *smmu_domain = smmu_mn->domain;
-       struct arm_smmu_master *master;
+       struct arm_smmu_master_domain *master_domain;
        unsigned long flags;
 
        mutex_lock(&sva_lock);
@@ -315,7 +316,9 @@ static void arm_smmu_mm_release(struct mmu_notifier *mn, struct mm_struct *mm)
         * but disable translation.
         */
        spin_lock_irqsave(&smmu_domain->devices_lock, flags);
-       list_for_each_entry(master, &smmu_domain->devices, domain_head) {
+       list_for_each_entry(master_domain, &smmu_domain->devices,
+                           devices_elm) {
+               struct arm_smmu_master *master = master_domain->master;
                struct arm_smmu_cd target;
                struct arm_smmu_cd *cdptr;
 
index fc78156f9d977e091a9403ec7124fedf5923f538..cee97372af0dbf83eaf7aaba4d53ec576162ce40 100644 (file)
@@ -2015,10 +2015,10 @@ static int arm_smmu_atc_inv_master(struct arm_smmu_master *master)
 int arm_smmu_atc_inv_domain(struct arm_smmu_domain *smmu_domain, int ssid,
                            unsigned long iova, size_t size)
 {
+       struct arm_smmu_master_domain *master_domain;
        int i;
        unsigned long flags;
        struct arm_smmu_cmdq_ent cmd;
-       struct arm_smmu_master *master;
        struct arm_smmu_cmdq_batch cmds;
 
        if (!(smmu_domain->smmu->features & ARM_SMMU_FEAT_ATS))
@@ -2046,7 +2046,10 @@ int arm_smmu_atc_inv_domain(struct arm_smmu_domain *smmu_domain, int ssid,
        cmds.num = 0;
 
        spin_lock_irqsave(&smmu_domain->devices_lock, flags);
-       list_for_each_entry(master, &smmu_domain->devices, domain_head) {
+       list_for_each_entry(master_domain, &smmu_domain->devices,
+                           devices_elm) {
+               struct arm_smmu_master *master = master_domain->master;
+
                if (!master->ats_enabled)
                        continue;
 
@@ -2534,9 +2537,26 @@ static void arm_smmu_disable_pasid(struct arm_smmu_master *master)
        pci_disable_pasid(pdev);
 }
 
+static struct arm_smmu_master_domain *
+arm_smmu_find_master_domain(struct arm_smmu_domain *smmu_domain,
+                           struct arm_smmu_master *master)
+{
+       struct arm_smmu_master_domain *master_domain;
+
+       lockdep_assert_held(&smmu_domain->devices_lock);
+
+       list_for_each_entry(master_domain, &smmu_domain->devices,
+                           devices_elm) {
+               if (master_domain->master == master)
+                       return master_domain;
+       }
+       return NULL;
+}
+
 static void arm_smmu_detach_dev(struct arm_smmu_master *master)
 {
        struct iommu_domain *domain = iommu_get_domain_for_dev(master->dev);
+       struct arm_smmu_master_domain *master_domain;
        struct arm_smmu_domain *smmu_domain;
        unsigned long flags;
 
@@ -2547,7 +2567,11 @@ static void arm_smmu_detach_dev(struct arm_smmu_master *master)
        arm_smmu_disable_ats(master, smmu_domain);
 
        spin_lock_irqsave(&smmu_domain->devices_lock, flags);
-       list_del_init(&master->domain_head);
+       master_domain = arm_smmu_find_master_domain(smmu_domain, master);
+       if (master_domain) {
+               list_del(&master_domain->devices_elm);
+               kfree(master_domain);
+       }
        spin_unlock_irqrestore(&smmu_domain->devices_lock, flags);
 
        master->ats_enabled = false;
@@ -2561,6 +2585,7 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
        struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
        struct arm_smmu_device *smmu;
        struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
+       struct arm_smmu_master_domain *master_domain;
        struct arm_smmu_master *master;
        struct arm_smmu_cd *cdptr;
 
@@ -2597,6 +2622,11 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
                        return -ENOMEM;
        }
 
+       master_domain = kzalloc(sizeof(*master_domain), GFP_KERNEL);
+       if (!master_domain)
+               return -ENOMEM;
+       master_domain->master = master;
+
        /*
         * Prevent arm_smmu_share_asid() from trying to change the ASID
         * of either the old or new domain while we are working on it.
@@ -2610,7 +2640,7 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
        master->ats_enabled = arm_smmu_ats_supported(master);
 
        spin_lock_irqsave(&smmu_domain->devices_lock, flags);
-       list_add(&master->domain_head, &smmu_domain->devices);
+       list_add(&master_domain->devices_elm, &smmu_domain->devices);
        spin_unlock_irqrestore(&smmu_domain->devices_lock, flags);
 
        switch (smmu_domain->stage) {
@@ -2925,7 +2955,6 @@ static struct iommu_device *arm_smmu_probe_device(struct device *dev)
        master->dev = dev;
        master->smmu = smmu;
        INIT_LIST_HEAD(&master->bonds);
-       INIT_LIST_HEAD(&master->domain_head);
        dev_iommu_priv_set(dev, master);
 
        ret = arm_smmu_insert_master(smmu, master);
index 6a74d3d884fe8d9821b8976ed4ee55b0c2bd89eb..01769b5286a83a4bbba374e9381679a67c3dd1e0 100644 (file)
@@ -697,7 +697,6 @@ struct arm_smmu_stream {
 struct arm_smmu_master {
        struct arm_smmu_device          *smmu;
        struct device                   *dev;
-       struct list_head                domain_head;
        struct arm_smmu_stream          *streams;
        /* Locked by the iommu core using the group mutex */
        struct arm_smmu_ctx_desc_cfg    cd_table;
@@ -731,6 +730,7 @@ struct arm_smmu_domain {
 
        struct iommu_domain             domain;
 
+       /* List of struct arm_smmu_master_domain */
        struct list_head                devices;
        spinlock_t                      devices_lock;
 
@@ -767,6 +767,11 @@ void arm_smmu_make_sva_cd(struct arm_smmu_cd *target,
                          u16 asid);
 #endif
 
+struct arm_smmu_master_domain {
+       struct list_head devices_elm;
+       struct arm_smmu_master *master;
+};
+
 static inline struct arm_smmu_domain *to_smmu_domain(struct iommu_domain *dom)
 {
        return container_of(dom, struct arm_smmu_domain, domain);