Commit 745f2586 authored by Jiang Liu's avatar Jiang Liu Committed by Joerg Roedel

iommu/vt-d: Simplify function get_domain_for_dev()

Function get_domain_for_dev() is a little complex, simplify it
by factoring out dmar_search_domain_by_dev_info() and
dmar_insert_dev_info().
Signed-off-by: default avatarJiang Liu <jiang.liu@linux.intel.com>
Signed-off-by: default avatarJoerg Roedel <joro@8bytes.org>
parent b94e4117
...@@ -1957,18 +1957,71 @@ find_domain(struct pci_dev *pdev) ...@@ -1957,18 +1957,71 @@ find_domain(struct pci_dev *pdev)
return NULL; return NULL;
} }
static inline struct dmar_domain *
dmar_search_domain_by_dev_info(int segment, int bus, int devfn)
{
struct device_domain_info *info;
list_for_each_entry(info, &device_domain_list, global)
if (info->segment == segment && info->bus == bus &&
info->devfn == devfn)
return info->domain;
return NULL;
}
static int dmar_insert_dev_info(int segment, int bus, int devfn,
struct pci_dev *dev, struct dmar_domain **domp)
{
struct dmar_domain *found, *domain = *domp;
struct device_domain_info *info;
unsigned long flags;
info = alloc_devinfo_mem();
if (!info)
return -ENOMEM;
info->segment = segment;
info->bus = bus;
info->devfn = devfn;
info->dev = dev;
info->domain = domain;
if (!dev)
domain->flags |= DOMAIN_FLAG_P2P_MULTIPLE_DEVICES;
spin_lock_irqsave(&device_domain_lock, flags);
if (dev)
found = find_domain(dev);
else
found = dmar_search_domain_by_dev_info(segment, bus, devfn);
if (found) {
spin_unlock_irqrestore(&device_domain_lock, flags);
free_devinfo_mem(info);
if (found != domain) {
domain_exit(domain);
*domp = found;
}
} else {
list_add(&info->link, &domain->devices);
list_add(&info->global, &device_domain_list);
if (dev)
dev->dev.archdata.iommu = info;
spin_unlock_irqrestore(&device_domain_lock, flags);
}
return 0;
}
/* domain is initialized */ /* domain is initialized */
static struct dmar_domain *get_domain_for_dev(struct pci_dev *pdev, int gaw) static struct dmar_domain *get_domain_for_dev(struct pci_dev *pdev, int gaw)
{ {
struct dmar_domain *domain, *found = NULL; struct dmar_domain *domain;
struct intel_iommu *iommu; struct intel_iommu *iommu;
struct dmar_drhd_unit *drhd; struct dmar_drhd_unit *drhd;
struct device_domain_info *info, *tmp;
struct pci_dev *dev_tmp; struct pci_dev *dev_tmp;
unsigned long flags; unsigned long flags;
int bus = 0, devfn = 0; int bus = 0, devfn = 0;
int segment; int segment;
int ret;
domain = find_domain(pdev); domain = find_domain(pdev);
if (domain) if (domain)
...@@ -1986,41 +2039,29 @@ static struct dmar_domain *get_domain_for_dev(struct pci_dev *pdev, int gaw) ...@@ -1986,41 +2039,29 @@ static struct dmar_domain *get_domain_for_dev(struct pci_dev *pdev, int gaw)
devfn = dev_tmp->devfn; devfn = dev_tmp->devfn;
} }
spin_lock_irqsave(&device_domain_lock, flags); spin_lock_irqsave(&device_domain_lock, flags);
list_for_each_entry(info, &device_domain_list, global) { domain = dmar_search_domain_by_dev_info(segment, bus, devfn);
if (info->segment == segment &&
info->bus == bus && info->devfn == devfn) {
found = info->domain;
break;
}
}
spin_unlock_irqrestore(&device_domain_lock, flags); spin_unlock_irqrestore(&device_domain_lock, flags);
/* pcie-pci bridge already has a domain, uses it */ /* pcie-pci bridge already has a domain, uses it */
if (found) { if (domain)
domain = found;
goto found_domain; goto found_domain;
} }
}
domain = alloc_domain();
if (!domain)
goto error;
/* Allocate new domain for the device */
drhd = dmar_find_matched_drhd_unit(pdev); drhd = dmar_find_matched_drhd_unit(pdev);
if (!drhd) { if (!drhd) {
printk(KERN_ERR "IOMMU: can't find DMAR for device %s\n", printk(KERN_ERR "IOMMU: can't find DMAR for device %s\n",
pci_name(pdev)); pci_name(pdev));
free_domain_mem(domain);
return NULL; return NULL;
} }
iommu = drhd->iommu; iommu = drhd->iommu;
ret = iommu_attach_domain(domain, iommu); /* Allocate and intialize new domain for the device */
if (ret) { domain = alloc_domain();
if (!domain)
goto error;
if (iommu_attach_domain(domain, iommu)) {
free_domain_mem(domain); free_domain_mem(domain);
goto error; goto error;
} }
if (domain_init(domain, gaw)) { if (domain_init(domain, gaw)) {
domain_exit(domain); domain_exit(domain);
goto error; goto error;
...@@ -2028,66 +2069,15 @@ static struct dmar_domain *get_domain_for_dev(struct pci_dev *pdev, int gaw) ...@@ -2028,66 +2069,15 @@ static struct dmar_domain *get_domain_for_dev(struct pci_dev *pdev, int gaw)
/* register pcie-to-pci device */ /* register pcie-to-pci device */
if (dev_tmp) { if (dev_tmp) {
info = alloc_devinfo_mem(); if (dmar_insert_dev_info(segment, bus, devfn, NULL, &domain)) {
if (!info) {
domain_exit(domain); domain_exit(domain);
goto error; goto error;
} }
info->segment = segment;
info->bus = bus;
info->devfn = devfn;
info->dev = NULL;
info->domain = domain;
/* This domain is shared by devices under p2p bridge */
domain->flags |= DOMAIN_FLAG_P2P_MULTIPLE_DEVICES;
/* pcie-to-pci bridge already has a domain, uses it */
found = NULL;
spin_lock_irqsave(&device_domain_lock, flags);
list_for_each_entry(tmp, &device_domain_list, global) {
if (tmp->segment == segment &&
tmp->bus == bus && tmp->devfn == devfn) {
found = tmp->domain;
break;
}
}
if (found) {
spin_unlock_irqrestore(&device_domain_lock, flags);
free_devinfo_mem(info);
domain_exit(domain);
domain = found;
} else {
list_add(&info->link, &domain->devices);
list_add(&info->global, &device_domain_list);
spin_unlock_irqrestore(&device_domain_lock, flags);
}
} }
found_domain: found_domain:
info = alloc_devinfo_mem(); if (dmar_insert_dev_info(segment, pdev->bus->number, pdev->devfn,
if (!info) pdev, &domain) == 0)
goto error;
info->segment = segment;
info->bus = pdev->bus->number;
info->devfn = pdev->devfn;
info->dev = pdev;
info->domain = domain;
spin_lock_irqsave(&device_domain_lock, flags);
/* somebody is fast */
found = find_domain(pdev);
if (found != NULL) {
spin_unlock_irqrestore(&device_domain_lock, flags);
if (found != domain) {
domain_exit(domain);
domain = found;
}
free_devinfo_mem(info);
return domain;
}
list_add(&info->link, &domain->devices);
list_add(&info->global, &device_domain_list);
pdev->dev.archdata.iommu = info;
spin_unlock_irqrestore(&device_domain_lock, flags);
return domain; return domain;
error: error:
/* recheck it here, maybe others set it */ /* recheck it here, maybe others set it */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment