diff options
-rw-r--r-- | drivers/iommu/amd/iommu.c | 52 |
1 files changed, 30 insertions, 22 deletions
diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c index 1219e1555fc2..7412e0bba2cd 100644 --- a/drivers/iommu/amd/iommu.c +++ b/drivers/iommu/amd/iommu.c @@ -2020,16 +2020,23 @@ static int pdom_attach_iommu(struct amd_iommu *iommu, struct protection_domain *pdom) { struct pdom_iommu_info *pdom_iommu_info, *curr; + struct io_pgtable_cfg *cfg = &pdom->iop.pgtbl.cfg; + unsigned long flags; + int ret = 0; + + spin_lock_irqsave(&pdom->lock, flags); pdom_iommu_info = xa_load(&pdom->iommu_array, iommu->index); if (pdom_iommu_info) { pdom_iommu_info->refcnt++; - return 0; + goto out_unlock; } pdom_iommu_info = kzalloc(sizeof(*pdom_iommu_info), GFP_ATOMIC); - if (!pdom_iommu_info) - return -ENOMEM; + if (!pdom_iommu_info) { + ret = -ENOMEM; + goto out_unlock; + } pdom_iommu_info->iommu = iommu; pdom_iommu_info->refcnt = 1; @@ -2038,43 +2045,52 @@ static int pdom_attach_iommu(struct amd_iommu *iommu, NULL, pdom_iommu_info, GFP_ATOMIC); if (curr) { kfree(pdom_iommu_info); - return -ENOSPC; + ret = -ENOSPC; + goto out_unlock; } - return 0; + /* Update NUMA Node ID */ + if (cfg->amd.nid == NUMA_NO_NODE) + cfg->amd.nid = dev_to_node(&iommu->dev->dev); + +out_unlock: + spin_unlock_irqrestore(&pdom->lock, flags); + return ret; } static void pdom_detach_iommu(struct amd_iommu *iommu, struct protection_domain *pdom) { struct pdom_iommu_info *pdom_iommu_info; + unsigned long flags; + + spin_lock_irqsave(&pdom->lock, flags); pdom_iommu_info = xa_load(&pdom->iommu_array, iommu->index); - if (!pdom_iommu_info) + if (!pdom_iommu_info) { + spin_unlock_irqrestore(&pdom->lock, flags); return; + } pdom_iommu_info->refcnt--; if (pdom_iommu_info->refcnt == 0) { xa_erase(&pdom->iommu_array, iommu->index); kfree(pdom_iommu_info); } + + spin_unlock_irqrestore(&pdom->lock, flags); } static int do_attach(struct iommu_dev_data *dev_data, struct protection_domain *domain) { struct amd_iommu *iommu = get_amd_iommu_from_dev_data(dev_data); - struct io_pgtable_cfg *cfg = &domain->iop.pgtbl.cfg; int ret = 0; /* Update data structures */ dev_data->domain = domain; list_add(&dev_data->list, &domain->dev_list); - /* Update NUMA Node ID */ - if (cfg->amd.nid == NUMA_NO_NODE) - cfg->amd.nid = dev_to_node(dev_data->dev); - /* Do reference counting */ ret = pdom_attach_iommu(iommu, domain); if (ret) @@ -2096,12 +2112,15 @@ static void do_detach(struct iommu_dev_data *dev_data) { struct protection_domain *domain = dev_data->domain; struct amd_iommu *iommu = get_amd_iommu_from_dev_data(dev_data); + unsigned long flags; /* Clear DTE and flush the entry */ dev_update_dte(dev_data, false); /* Flush IOTLB and wait for the flushes to finish */ + spin_lock_irqsave(&domain->lock, flags); amd_iommu_domain_flush_all(domain); + spin_unlock_irqrestore(&domain->lock, flags); /* Clear GCR3 table */ if (pdom_is_sva_capable(domain)) @@ -2123,11 +2142,8 @@ static int attach_device(struct device *dev, struct protection_domain *domain) { struct iommu_dev_data *dev_data; - unsigned long flags; int ret = 0; - spin_lock_irqsave(&domain->lock, flags); - dev_data = dev_iommu_priv_get(dev); spin_lock(&dev_data->lock); @@ -2142,8 +2158,6 @@ static int attach_device(struct device *dev, out: spin_unlock(&dev_data->lock); - spin_unlock_irqrestore(&domain->lock, flags); - return ret; } @@ -2153,13 +2167,9 @@ out: static void detach_device(struct device *dev) { struct iommu_dev_data *dev_data = dev_iommu_priv_get(dev); - struct protection_domain *domain = dev_data->domain; struct amd_iommu *iommu = get_amd_iommu_from_dev_data(dev_data); - unsigned long flags; bool ppr = dev_data->ppr; - spin_lock_irqsave(&domain->lock, flags); - spin_lock(&dev_data->lock); /* @@ -2183,8 +2193,6 @@ static void detach_device(struct device *dev) out: spin_unlock(&dev_data->lock); - spin_unlock_irqrestore(&domain->lock, flags); - /* Remove IOPF handler */ if (ppr) amd_iommu_iopf_remove_device(iommu, dev_data); |