Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+66 −76
Original line number Diff line number Diff line
@@ -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,66 +2069,15 @@ 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);
		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);
	if (dmar_insert_dev_info(segment, pdev->bus->number, pdev->devfn,
				 pdev, &domain) == 0)
		return domain;
error:
	/* recheck it here, maybe others set it */