| From 4fda230ecddc2573ed88632e98b69b0b9b68c0ad Mon Sep 17 00:00:00 2001 |
| From: Jon Derrick <jonathan.derrick@intel.com> |
| Date: Wed, 27 May 2020 10:56:16 -0600 |
| Subject: iommu/vt-d: Allocate domain info for real DMA sub-devices |
| |
| From: Jon Derrick <jonathan.derrick@intel.com> |
| |
| commit 4fda230ecddc2573ed88632e98b69b0b9b68c0ad upstream. |
| |
| Sub-devices of a real DMA device might exist on a separate segment than |
| the real DMA device and its IOMMU. These devices should still have a |
| valid device_domain_info, but the current dma alias model won't |
| allocate info for the subdevice. |
| |
| This patch adds a segment member to struct device_domain_info and uses |
| the sub-device's BDF so that these sub-devices won't alias to other |
| devices. |
| |
| Fixes: 2b0140c69637e ("iommu/vt-d: Use pci_real_dma_dev() for mapping") |
| Cc: stable@vger.kernel.org # v5.6+ |
| Signed-off-by: Jon Derrick <jonathan.derrick@intel.com> |
| Acked-by: Lu Baolu <baolu.lu@linux.intel.com> |
| Link: https://lore.kernel.org/r/20200527165617.297470-3-jonathan.derrick@intel.com |
| Signed-off-by: Joerg Roedel <jroedel@suse.de> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/iommu/intel-iommu.c | 19 +++++++++++++++---- |
| include/linux/intel-iommu.h | 1 + |
| 2 files changed, 16 insertions(+), 4 deletions(-) |
| |
| --- a/drivers/iommu/intel-iommu.c |
| +++ b/drivers/iommu/intel-iommu.c |
| @@ -2545,7 +2545,7 @@ dmar_search_domain_by_dev_info(int segme |
| struct device_domain_info *info; |
| |
| list_for_each_entry(info, &device_domain_list, global) |
| - if (info->iommu->segment == segment && info->bus == bus && |
| + if (info->segment == segment && info->bus == bus && |
| info->devfn == devfn) |
| return info; |
| |
| @@ -2602,8 +2602,18 @@ static struct dmar_domain *dmar_insert_o |
| if (!info) |
| return NULL; |
| |
| - info->bus = bus; |
| - info->devfn = devfn; |
| + if (!dev_is_real_dma_subdevice(dev)) { |
| + info->bus = bus; |
| + info->devfn = devfn; |
| + info->segment = iommu->segment; |
| + } else { |
| + struct pci_dev *pdev = to_pci_dev(dev); |
| + |
| + info->bus = pdev->bus->number; |
| + info->devfn = pdev->devfn; |
| + info->segment = pci_domain_nr(pdev->bus); |
| + } |
| + |
| info->ats_supported = info->pasid_supported = info->pri_supported = 0; |
| info->ats_enabled = info->pasid_enabled = info->pri_enabled = 0; |
| info->ats_qdep = 0; |
| @@ -2643,7 +2653,8 @@ static struct dmar_domain *dmar_insert_o |
| |
| if (!found) { |
| struct device_domain_info *info2; |
| - info2 = dmar_search_domain_by_dev_info(iommu->segment, bus, devfn); |
| + info2 = dmar_search_domain_by_dev_info(info->segment, info->bus, |
| + info->devfn); |
| if (info2) { |
| found = info2->domain; |
| info2->dev = dev; |
| --- a/include/linux/intel-iommu.h |
| +++ b/include/linux/intel-iommu.h |
| @@ -571,6 +571,7 @@ struct device_domain_info { |
| struct list_head auxiliary_domains; /* auxiliary domains |
| * attached to this device |
| */ |
| + u32 segment; /* PCI segment number */ |
| u8 bus; /* PCI bus number */ |
| u8 devfn; /* PCI devfn number */ |
| u16 pfsid; /* SRIOV physical function source ID */ |