|
@@ -27,6 +27,7 @@
|
|
|
#include <linux/iova.h>
|
|
|
#include <linux/irq.h>
|
|
|
#include <linux/mm.h>
|
|
|
+#include <linux/pci.h>
|
|
|
#include <linux/scatterlist.h>
|
|
|
#include <linux/vmalloc.h>
|
|
|
|
|
@@ -103,18 +104,38 @@ void iommu_put_dma_cookie(struct iommu_domain *domain)
|
|
|
}
|
|
|
EXPORT_SYMBOL(iommu_put_dma_cookie);
|
|
|
|
|
|
+static void iova_reserve_pci_windows(struct pci_dev *dev,
|
|
|
+ struct iova_domain *iovad)
|
|
|
+{
|
|
|
+ struct pci_host_bridge *bridge = pci_find_host_bridge(dev->bus);
|
|
|
+ struct resource_entry *window;
|
|
|
+ unsigned long lo, hi;
|
|
|
+
|
|
|
+ resource_list_for_each_entry(window, &bridge->windows) {
|
|
|
+ if (resource_type(window->res) != IORESOURCE_MEM &&
|
|
|
+ resource_type(window->res) != IORESOURCE_IO)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ lo = iova_pfn(iovad, window->res->start - window->offset);
|
|
|
+ hi = iova_pfn(iovad, window->res->end - window->offset);
|
|
|
+ reserve_iova(iovad, lo, hi);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* iommu_dma_init_domain - Initialise a DMA mapping domain
|
|
|
* @domain: IOMMU domain previously prepared by iommu_get_dma_cookie()
|
|
|
* @base: IOVA at which the mappable address space starts
|
|
|
* @size: Size of IOVA space
|
|
|
+ * @dev: Device the domain is being initialised for
|
|
|
*
|
|
|
* @base and @size should be exact multiples of IOMMU page granularity to
|
|
|
* avoid rounding surprises. If necessary, we reserve the page at address 0
|
|
|
* to ensure it is an invalid IOVA. It is safe to reinitialise a domain, but
|
|
|
* any change which could make prior IOVAs invalid will fail.
|
|
|
*/
|
|
|
-int iommu_dma_init_domain(struct iommu_domain *domain, dma_addr_t base, u64 size)
|
|
|
+int iommu_dma_init_domain(struct iommu_domain *domain, dma_addr_t base,
|
|
|
+ u64 size, struct device *dev)
|
|
|
{
|
|
|
struct iova_domain *iovad = cookie_iovad(domain);
|
|
|
unsigned long order, base_pfn, end_pfn;
|
|
@@ -152,6 +173,8 @@ int iommu_dma_init_domain(struct iommu_domain *domain, dma_addr_t base, u64 size
|
|
|
iovad->dma_32bit_pfn = end_pfn;
|
|
|
} else {
|
|
|
init_iova_domain(iovad, 1UL << order, base_pfn, end_pfn);
|
|
|
+ if (dev && dev_is_pci(dev))
|
|
|
+ iova_reserve_pci_windows(to_pci_dev(dev), iovad);
|
|
|
}
|
|
|
return 0;
|
|
|
}
|