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

Commit 156baca8 authored by David Woodhouse's avatar David Woodhouse
Browse files

iommu/vt-d: Make device_to_iommu() cope with non-PCI devices



Pass the struct device to it, and also make it return the bus/devfn to use,
since that is also stored in the DMAR table.

Signed-off-by: default avatarDavid Woodhouse <David.Woodhouse@intel.com>
parent 9b226624
Loading
Loading
Loading
Loading
+46 −32
Original line number Diff line number Diff line
@@ -664,35 +664,51 @@ static void domain_update_iommu_cap(struct dmar_domain *domain)
	domain_update_iommu_superpage(domain);
}

static struct intel_iommu *device_to_iommu(int segment, u8 bus, u8 devfn)
static struct intel_iommu *device_to_iommu(struct device *dev, u8 *bus, u8 *devfn)
{
	struct dmar_drhd_unit *drhd = NULL;
	struct intel_iommu *iommu;
	struct device *dev;
	struct pci_dev *pdev;
	struct device *tmp;
	struct pci_dev *ptmp, *pdev = NULL;
	u16 segment;
	int i;

	if (dev_is_pci(dev)) {
		pdev = to_pci_dev(dev);
		segment = pci_domain_nr(pdev->bus);
	} else if (ACPI_COMPANION(dev))
		dev = &ACPI_COMPANION(dev)->dev;

	rcu_read_lock();
	for_each_active_iommu(iommu, drhd) {
		if (segment != drhd->segment)
		if (pdev && segment != drhd->segment)
			continue;

		for_each_active_dev_scope(drhd->devices,
					  drhd->devices_cnt, i, dev) {
			if (!dev_is_pci(dev))
				continue;
			pdev = to_pci_dev(dev);
			if (pdev->bus->number == bus && pdev->devfn == devfn)
				goto out;
			if (pdev->subordinate &&
			    pdev->subordinate->number <= bus &&
			    pdev->subordinate->busn_res.end >= bus)
					  drhd->devices_cnt, i, tmp) {
			if (tmp == dev) {
				*bus = drhd->devices[i].bus;
				*devfn = drhd->devices[i].devfn;
				goto out;
			}

		if (drhd->include_all)
			if (!pdev || !dev_is_pci(tmp))
				continue;

			ptmp = to_pci_dev(tmp);
			if (ptmp->subordinate &&
			    ptmp->subordinate->number <= pdev->bus->number &&
			    ptmp->subordinate->busn_res.end >= pdev->bus->number)
				goto got_pdev;
		}

		if (pdev && drhd->include_all) {
		got_pdev:
			*bus = pdev->bus->number;
			*devfn = pdev->devfn;
			goto out;
		}
	}
	iommu = NULL;
 out:
	rcu_read_unlock();
@@ -1830,14 +1846,13 @@ domain_context_mapping(struct dmar_domain *domain, struct pci_dev *pdev,
	int ret;
	struct pci_dev *tmp, *parent;
	struct intel_iommu *iommu;
	u8 bus, devfn;

	iommu = device_to_iommu(pci_domain_nr(pdev->bus), pdev->bus->number,
				pdev->devfn);
	iommu = device_to_iommu(&pdev->dev, &bus, &devfn);
	if (!iommu)
		return -ENODEV;

	ret = domain_context_mapping_one(domain, iommu,
					 pdev->bus->number, pdev->devfn,
	ret = domain_context_mapping_one(domain, iommu, bus, devfn,
					 translation);
	if (ret)
		return ret;
@@ -1872,13 +1887,13 @@ static int domain_context_mapped(struct pci_dev *pdev)
	int ret;
	struct pci_dev *tmp, *parent;
	struct intel_iommu *iommu;
	u8 bus, devfn;

	iommu = device_to_iommu(pci_domain_nr(pdev->bus), pdev->bus->number,
				pdev->devfn);
	iommu = device_to_iommu(&pdev->dev, &bus, &devfn);
	if (!iommu)
		return -ENODEV;

	ret = device_context_mapped(iommu, pdev->bus->number, pdev->devfn);
	ret = device_context_mapped(iommu, bus, devfn);
	if (!ret)
		return ret;
	/* dependent device mapping */
@@ -2459,15 +2474,14 @@ static int domain_add_dev_info(struct dmar_domain *domain,
{
	struct dmar_domain *ndomain;
	struct intel_iommu *iommu;
	u8 bus, devfn;
	int ret;

	iommu = device_to_iommu(pci_domain_nr(pdev->bus),
				pdev->bus->number, pdev->devfn);
	iommu = device_to_iommu(&pdev->dev, &bus, &devfn);
	if (!iommu)
		return -ENODEV;

	ndomain = dmar_insert_dev_info(iommu, pdev->bus->number, pdev->devfn,
				       &pdev->dev, domain);
	ndomain = dmar_insert_dev_info(iommu, bus, devfn, &pdev->dev, domain);
	if (ndomain != domain)
		return -EBUSY;

@@ -4020,9 +4034,9 @@ static void domain_remove_one_dev_info(struct dmar_domain *domain,
	struct intel_iommu *iommu;
	unsigned long flags;
	int found = 0;
	u8 bus, devfn;

	iommu = device_to_iommu(pci_domain_nr(pdev->bus), pdev->bus->number,
				pdev->devfn);
	iommu = device_to_iommu(&pdev->dev, &bus, &devfn);
	if (!iommu)
		return;

@@ -4142,6 +4156,7 @@ static int intel_iommu_attach_device(struct iommu_domain *domain,
	struct pci_dev *pdev = to_pci_dev(dev);
	struct intel_iommu *iommu;
	int addr_width;
	u8 bus, devfn;

	/* normally pdev is not mapped */
	if (unlikely(domain_context_mapped(pdev))) {
@@ -4157,8 +4172,7 @@ static int intel_iommu_attach_device(struct iommu_domain *domain,
		}
	}

	iommu = device_to_iommu(pci_domain_nr(pdev->bus), pdev->bus->number,
				pdev->devfn);
	iommu = device_to_iommu(dev, &bus, &devfn);
	if (!iommu)
		return -ENODEV;

@@ -4324,9 +4338,9 @@ static int intel_iommu_add_device(struct device *dev)
	struct pci_dev *bridge, *dma_pdev = NULL;
	struct iommu_group *group;
	int ret;
	u8 bus, devfn;

	if (!device_to_iommu(pci_domain_nr(pdev->bus),
			     pdev->bus->number, pdev->devfn))
	if (!device_to_iommu(dev, &bus, &devfn))
		return -ENODEV;

	bridge = pci_find_upstream_pcie_bridge(pdev);