From: Leon Romanovsky <[email protected]>

Exporters keep the &struct p2pdma_provider backing a buffer in their own
private data. An importer cannot reach it, so it has no way to learn how
its own peer-to-peer traffic would be routed before it programs its
hardware.

Add an optional @p2pdma_provider callback for an exporter to hand that
provider out, and dma_buf_p2pdma_map_type() for an importer to ask by TLP
class. Exporters keep the provider where it already lives, so this adds an
operation rather than changing any existing signature or structure.

Tested-by: Tushar Dave <[email protected]>
Signed-off-by: Leon Romanovsky <[email protected]>
---
 drivers/dma-buf/dma-buf-mapping.c | 39 +++++++++++++++++++++++++++++++++++++++
 include/linux/dma-buf-mapping.h   |  3 +++
 include/linux/dma-buf.h           | 19 +++++++++++++++++++
 3 files changed, 61 insertions(+)

diff --git a/drivers/dma-buf/dma-buf-mapping.c 
b/drivers/dma-buf/dma-buf-mapping.c
index 794acff2546a..41702045f803 100644
--- a/drivers/dma-buf/dma-buf-mapping.c
+++ b/drivers/dma-buf/dma-buf-mapping.c
@@ -6,6 +6,45 @@
 #include <linux/dma-buf-mapping.h>
 #include <linux/dma-resv.h>
 
+/**
+ * dma_buf_p2pdma_map_type - How peer-to-peer traffic to a buffer is routed
+ * @attach:    attachment of the importer that will issue the traffic
+ * @tlp_flags: &enum pci_p2pdma_tlp_flags describing the TLPs it will issue
+ *
+ * Reports how the PCIe fabric routes @tlp_flags traffic between the buffer
+ * behind @attach and the importer attached to it, so that an importer can
+ * choose the TLP attributes that earn it a direct route before it programs
+ * its hardware.
+ *
+ * The caller must hold the reservation lock. The provider is owned by the
+ * exporter's driver binding, and exporters revoke under that lock before
+ * letting an unbind proceed, so dropping it any earlier would leave this
+ * racing a teardown that frees the provider.
+ *
+ * Return: the mapping type for @tlp_flags traffic, or PCI_P2PDMA_MAP_NONE
+ * when the exporter names no &struct p2pdma_provider and nothing is known
+ * about the route.
+ */
+enum pci_p2pdma_map_type
+dma_buf_p2pdma_map_type(struct dma_buf_attachment *attach,
+                       unsigned int tlp_flags)
+{
+       struct dma_buf *dmabuf = attach->dmabuf;
+       struct p2pdma_provider *provider;
+
+       dma_resv_assert_held(dmabuf->resv);
+
+       if (!dmabuf->ops->p2pdma_provider)
+               return PCI_P2PDMA_MAP_NONE;
+
+       provider = dmabuf->ops->p2pdma_provider(dmabuf);
+       if (!provider)
+               return PCI_P2PDMA_MAP_NONE;
+
+       return pci_p2pdma_map_type_tlp(provider, attach->dev, tlp_flags);
+}
+EXPORT_SYMBOL_NS_GPL(dma_buf_p2pdma_map_type, "DMA_BUF");
+
 static struct scatterlist *fill_sg_entry(struct scatterlist *sgl, size_t 
length,
                                         dma_addr_t addr)
 {
diff --git a/include/linux/dma-buf-mapping.h b/include/linux/dma-buf-mapping.h
index 09bde3f748e4..37b3da10b17a 100644
--- a/include/linux/dma-buf-mapping.h
+++ b/include/linux/dma-buf-mapping.h
@@ -7,6 +7,9 @@
 #define __DMA_BUF_MAPPING_H__
 #include <linux/dma-buf.h>
 
+enum pci_p2pdma_map_type
+dma_buf_p2pdma_map_type(struct dma_buf_attachment *attach,
+                       unsigned int tlp_flags);
 struct sg_table *dma_buf_phys_vec_to_sgt(struct dma_buf_attachment *attach,
                                         struct p2pdma_provider *provider,
                                         struct phys_vec *phys_vec,
diff --git a/include/linux/dma-buf.h b/include/linux/dma-buf.h
index d1203da56fc5..d56a48d41215 100644
--- a/include/linux/dma-buf.h
+++ b/include/linux/dma-buf.h
@@ -186,6 +186,25 @@ struct dma_buf_ops {
         * if the call would block.
         */
 
+       /**
+        * @p2pdma_provider:
+        *
+        * Returns the &struct p2pdma_provider backing this buffer, so that an
+        * importer can ask how its peer-to-peer traffic would be routed before
+        * it programs its hardware. Importers reach this through
+        * dma_buf_p2pdma_map_type() rather than calling it directly.
+        *
+        * Exporters of MMIO memory that is reachable peer-to-peer should
+        * implement this. Called with the &dma_buf.resv reservation lock held,
+        * which is what lets an exporter refuse once it has revoked the buffer
+        * and started tearing the provider down. This callback is optional.
+        *
+        * Returns:
+        *
+        * The provider backing the buffer.
+        */
+       struct p2pdma_provider *(*p2pdma_provider)(struct dma_buf *dmabuf);
+
        /**
         * @release:
         *

-- 
2.55.0

Reply via email to