|
@@ -2452,20 +2452,15 @@ static int get_last_alias(struct pci_dev *pdev, u16 alias, void *opaque)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-/* domain is initialized */
|
|
|
-static struct dmar_domain *get_domain_for_dev(struct device *dev, int gaw)
|
|
|
+static struct dmar_domain *find_or_alloc_domain(struct device *dev, int gaw)
|
|
|
{
|
|
|
struct device_domain_info *info = NULL;
|
|
|
- struct dmar_domain *domain, *tmp;
|
|
|
+ struct dmar_domain *domain = NULL;
|
|
|
struct intel_iommu *iommu;
|
|
|
u16 req_id, dma_alias;
|
|
|
unsigned long flags;
|
|
|
u8 bus, devfn;
|
|
|
|
|
|
- domain = find_domain(dev);
|
|
|
- if (domain)
|
|
|
- return domain;
|
|
|
-
|
|
|
iommu = device_to_iommu(dev, &bus, &devfn);
|
|
|
if (!iommu)
|
|
|
return NULL;
|
|
@@ -2487,9 +2482,9 @@ static struct dmar_domain *get_domain_for_dev(struct device *dev, int gaw)
|
|
|
}
|
|
|
spin_unlock_irqrestore(&device_domain_lock, flags);
|
|
|
|
|
|
- /* DMA alias already has a domain, uses it */
|
|
|
+ /* DMA alias already has a domain, use it */
|
|
|
if (info)
|
|
|
- goto found_domain;
|
|
|
+ goto out;
|
|
|
}
|
|
|
|
|
|
/* Allocate and initialize new domain for the device */
|
|
@@ -2501,28 +2496,67 @@ static struct dmar_domain *get_domain_for_dev(struct device *dev, int gaw)
|
|
|
return NULL;
|
|
|
}
|
|
|
|
|
|
- /* register PCI DMA alias device */
|
|
|
- if (dev_is_pci(dev) && req_id != dma_alias) {
|
|
|
- tmp = dmar_insert_one_dev_info(iommu, PCI_BUS_NUM(dma_alias),
|
|
|
- dma_alias & 0xff, NULL, domain);
|
|
|
+out:
|
|
|
|
|
|
- if (!tmp || tmp != domain) {
|
|
|
- domain_exit(domain);
|
|
|
- domain = tmp;
|
|
|
- }
|
|
|
+ return domain;
|
|
|
+}
|
|
|
|
|
|
- if (!domain)
|
|
|
- return NULL;
|
|
|
+static struct dmar_domain *set_domain_for_dev(struct device *dev,
|
|
|
+ struct dmar_domain *domain)
|
|
|
+{
|
|
|
+ struct intel_iommu *iommu;
|
|
|
+ struct dmar_domain *tmp;
|
|
|
+ u16 req_id, dma_alias;
|
|
|
+ u8 bus, devfn;
|
|
|
+
|
|
|
+ iommu = device_to_iommu(dev, &bus, &devfn);
|
|
|
+ if (!iommu)
|
|
|
+ return NULL;
|
|
|
+
|
|
|
+ req_id = ((u16)bus << 8) | devfn;
|
|
|
+
|
|
|
+ if (dev_is_pci(dev)) {
|
|
|
+ struct pci_dev *pdev = to_pci_dev(dev);
|
|
|
+
|
|
|
+ pci_for_each_dma_alias(pdev, get_last_alias, &dma_alias);
|
|
|
+
|
|
|
+ /* register PCI DMA alias device */
|
|
|
+ if (req_id != dma_alias) {
|
|
|
+ tmp = dmar_insert_one_dev_info(iommu, PCI_BUS_NUM(dma_alias),
|
|
|
+ dma_alias & 0xff, NULL, domain);
|
|
|
+
|
|
|
+ if (!tmp || tmp != domain)
|
|
|
+ return tmp;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
-found_domain:
|
|
|
tmp = dmar_insert_one_dev_info(iommu, bus, devfn, dev, domain);
|
|
|
+ if (!tmp || tmp != domain)
|
|
|
+ return tmp;
|
|
|
+
|
|
|
+ return domain;
|
|
|
+}
|
|
|
|
|
|
- if (!tmp || tmp != domain) {
|
|
|
+static struct dmar_domain *get_domain_for_dev(struct device *dev, int gaw)
|
|
|
+{
|
|
|
+ struct dmar_domain *domain, *tmp;
|
|
|
+
|
|
|
+ domain = find_domain(dev);
|
|
|
+ if (domain)
|
|
|
+ goto out;
|
|
|
+
|
|
|
+ domain = find_or_alloc_domain(dev, gaw);
|
|
|
+ if (!domain)
|
|
|
+ goto out;
|
|
|
+
|
|
|
+ tmp = set_domain_for_dev(dev, domain);
|
|
|
+ if (!tmp || domain != tmp) {
|
|
|
domain_exit(domain);
|
|
|
domain = tmp;
|
|
|
}
|
|
|
|
|
|
+out:
|
|
|
+
|
|
|
return domain;
|
|
|
}
|
|
|
|