]> www.infradead.org Git - users/hch/block.git/commitdiff
iommu/dma: Add check if IOVA can be used
authorLeon Romanovsky <leonro@nvidia.com>
Thu, 18 Jul 2024 18:16:04 +0000 (21:16 +0300)
committerLeon Romanovsky <leon@kernel.org>
Thu, 3 Oct 2024 16:05:52 +0000 (19:05 +0300)
This patch adds a check if IOVA can be used for the page and size.

Signed-off-by: Leon Romanovsky <leonro@nvidia.com>
drivers/iommu/dma-iommu.c
drivers/pci/p2pdma.c
include/linux/dma-map-ops.h
include/linux/iommu-dma.h

index 87bd706075d18aa2d5c01a2356961832e2947a14..99af34871e9f804599a57fffefe6c33309cb14be 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/acpi_iort.h>
 #include <linux/atomic.h>
 #include <linux/crash_dump.h>
+#include <linux/cc_platform.h>
 #include <linux/device.h>
 #include <linux/dma-direct.h>
 #include <linux/dma-map-ops.h>
@@ -1863,6 +1864,26 @@ void iommu_dma_unlink_range(struct device *dev, dma_addr_t start, size_t size,
                iommu_iotlb_sync(domain, &iotlb_gather);
 }
 
+bool iommu_can_use_iova(struct device *dev, struct page *page, size_t size,
+                       enum dma_data_direction dir)
+{
+       enum pci_p2pdma_map_type map;
+
+       if (is_swiotlb_force_bounce(dev) || dev_use_swiotlb(dev, size, dir))
+               return false;
+
+       /* TODO: Rewrite this check to rely on specific struct page flags */
+       if (cc_platform_has(CC_ATTR_MEM_ENCRYPT))
+               return false;
+
+       if (page && is_pci_p2pdma_page(page)) {
+               map = pci_p2pdma_map_type(page->pgmap, dev);
+               return map == PCI_P2PDMA_MAP_THRU_HOST_BRIDGE;
+       }
+
+       return true;
+}
+
 void iommu_setup_dma_ops(struct device *dev)
 {
        struct iommu_domain *domain = iommu_get_domain_for_dev(dev);
index 4f47a13cb500ff5339cde426b6ccb020fcd74ae7..6ceea32bb041be410b1819b8dc9b96c362078137 100644 (file)
@@ -964,8 +964,8 @@ void pci_p2pmem_publish(struct pci_dev *pdev, bool publish)
 }
 EXPORT_SYMBOL_GPL(pci_p2pmem_publish);
 
-static enum pci_p2pdma_map_type pci_p2pdma_map_type(struct dev_pagemap *pgmap,
-                                                   struct device *dev)
+enum pci_p2pdma_map_type pci_p2pdma_map_type(struct dev_pagemap *pgmap,
+                                            struct device *dev)
 {
        enum pci_p2pdma_map_type type = PCI_P2PDMA_MAP_NOT_SUPPORTED;
        struct pci_dev *provider = to_p2p_pgmap(pgmap)->provider;
index b7773201414c27d2941ef4c2ae6ff9d15a2a560d..894e74ba178bf222484d7f0bbff59d6403038d4c 100644 (file)
@@ -479,6 +479,8 @@ struct pci_p2pdma_map_state {
 enum pci_p2pdma_map_type
 pci_p2pdma_map_segment(struct pci_p2pdma_map_state *state, struct device *dev,
                       struct scatterlist *sg);
+enum pci_p2pdma_map_type pci_p2pdma_map_type(struct dev_pagemap *pgmap,
+                                            struct device *dev);
 #else /* CONFIG_PCI_P2PDMA */
 static inline enum pci_p2pdma_map_type
 pci_p2pdma_map_segment(struct pci_p2pdma_map_state *state, struct device *dev,
@@ -486,6 +488,11 @@ pci_p2pdma_map_segment(struct pci_p2pdma_map_state *state, struct device *dev,
 {
        return PCI_P2PDMA_MAP_NOT_SUPPORTED;
 }
+static inline enum pci_p2pdma_map_type
+pci_p2pdma_map_type(struct dev_pagemap *pgmap, struct device *dev)
+{
+       return PCI_P2PDMA_MAP_NOT_SUPPORTED;
+}
 #endif /* CONFIG_PCI_P2PDMA */
 
 #endif /* _LINUX_DMA_MAP_OPS_H */
index 4e0a8e38237e7f24324edb841ea03498767572db..0832b115a43684eb5a789e94b903fb8ed13cb8f8 100644 (file)
@@ -75,4 +75,6 @@ dma_addr_t iommu_dma_link_range(struct dma_iova_state *state, phys_addr_t phys,
                size_t size, unsigned long attrs);
 void iommu_dma_unlink_range(struct device *dev, dma_addr_t start, size_t size,
                enum dma_data_direction dir, unsigned long attrs);
+bool iommu_can_use_iova(struct device *dev, struct page *page, size_t size,
+               enum dma_data_direction dir);
 #endif /* _LINUX_IOMMU_DMA_H */