summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/iommu/amd/iommu.c52
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);