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: Jiang Liu <jiang.liu@linux.intel.com> Signed-off-by: Joerg Roedel <joro@8bytes.org>
This commit is contained in:
parent
b94e4117f8
commit
745f2586e7
|
@ -1957,18 +1957,71 @@ find_domain(struct pci_dev *pdev)
|
|||
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 */
|
||||
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 dmar_drhd_unit *drhd;
|
||||
struct device_domain_info *info, *tmp;
|
||||
struct pci_dev *dev_tmp;
|
||||
unsigned long flags;
|
||||
int bus = 0, devfn = 0;
|
||||
int segment;
|
||||
int ret;
|
||||
|
||||
domain = find_domain(pdev);
|
||||
if (domain)
|
||||
|
@ -1986,41 +2039,29 @@ static struct dmar_domain *get_domain_for_dev(struct pci_dev *pdev, int gaw)
|
|||
devfn = dev_tmp->devfn;
|
||||
}
|
||||
spin_lock_irqsave(&device_domain_lock, flags);
|
||||
list_for_each_entry(info, &device_domain_list, global) {
|
||||
if (info->segment == segment &&
|
||||
info->bus == bus && info->devfn == devfn) {
|
||||
found = info->domain;
|
||||
break;
|
||||
}
|
||||
}
|
||||
domain = dmar_search_domain_by_dev_info(segment, bus, devfn);
|
||||
spin_unlock_irqrestore(&device_domain_lock, flags);
|
||||
/* pcie-pci bridge already has a domain, uses it */
|
||||
if (found) {
|
||||
domain = found;
|
||||
if (domain)
|
||||
goto found_domain;
|
||||
}
|
||||
}
|
||||
|
||||
domain = alloc_domain();
|
||||
if (!domain)
|
||||
goto error;
|
||||
|
||||
/* Allocate new domain for the device */
|
||||
drhd = dmar_find_matched_drhd_unit(pdev);
|
||||
if (!drhd) {
|
||||
printk(KERN_ERR "IOMMU: can't find DMAR for device %s\n",
|
||||
pci_name(pdev));
|
||||
free_domain_mem(domain);
|
||||
return NULL;
|
||||
}
|
||||
iommu = drhd->iommu;
|
||||
|
||||
ret = iommu_attach_domain(domain, iommu);
|
||||
if (ret) {
|
||||
/* Allocate and intialize new domain for the device */
|
||||
domain = alloc_domain();
|
||||
if (!domain)
|
||||
goto error;
|
||||
if (iommu_attach_domain(domain, iommu)) {
|
||||
free_domain_mem(domain);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (domain_init(domain, gaw)) {
|
||||
domain_exit(domain);
|
||||
goto error;
|
||||
|
@ -2028,67 +2069,16 @@ static struct dmar_domain *get_domain_for_dev(struct pci_dev *pdev, int gaw)
|
|||
|
||||
/* register pcie-to-pci device */
|
||||
if (dev_tmp) {
|
||||
info = alloc_devinfo_mem();
|
||||
if (!info) {
|
||||
if (dmar_insert_dev_info(segment, bus, devfn, NULL, &domain)) {
|
||||
domain_exit(domain);
|
||||
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:
|
||||
info = alloc_devinfo_mem();
|
||||
if (!info)
|
||||
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);
|
||||
if (dmar_insert_dev_info(segment, pdev->bus->number, pdev->devfn,
|
||||
pdev, &domain) == 0)
|
||||
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;
|
||||
error:
|
||||
/* recheck it here, maybe others set it */
|
||||
return find_domain(pdev);
|
||||
|
|
Loading…
Reference in a new issue