[RFC 3/7] IB/core: Helpers for mapping DMA-BUF in MRs

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



DMA-BUF API allows devices to export buffers for other devices to
access. This can provide a means to implement peer to peer communication
for RDMA. A device with internal memory would expose its memory to the
PCIe BAR, and export that region as a DMA-BUF object. Then, the user or
ULP would register a memory region that is backed by the DMA-BUF object.

Signed-off-by: Haggai Eran <haggaie@xxxxxxxxxxxx>
---
 drivers/infiniband/core/verbs.c | 60 +++++++++++++++++++++++++++++++++++++++++
 include/rdma/ib_verbs.h         |  9 +++++++
 2 files changed, 69 insertions(+)

diff --git a/drivers/infiniband/core/verbs.c b/drivers/infiniband/core/verbs.c
index 6298f54b4137..633831e77a62 100644
--- a/drivers/infiniband/core/verbs.c
+++ b/drivers/infiniband/core/verbs.c
@@ -44,6 +44,7 @@
 #include <linux/in.h>
 #include <linux/in6.h>
 #include <net/addrconf.h>
+#include <linux/dma-buf.h>
 
 #include <rdma/ib_verbs.h>
 #include <rdma/ib_cache.h>
@@ -1922,3 +1923,62 @@ void ib_drain_qp(struct ib_qp *qp)
 		ib_drain_rq(qp);
 }
 EXPORT_SYMBOL(ib_drain_qp);
+
+int ib_mr_attach_dmabuf(struct ib_mr *mr, struct dma_buf *dmabuf, int access)
+{
+	struct device *dev = mr->device->dma_device;
+	struct dma_buf_attachment *attach;
+	struct sg_table *sg;
+	int err;
+	int n;
+
+	get_dma_buf(dmabuf);
+
+	attach = dma_buf_attach(dmabuf, dev);
+	if (IS_ERR(attach)) {
+		dev_err(dev, "unable to attach to DMA-BUF object (from %s): %ld",
+			dmabuf->exp_name, PTR_ERR(attach));
+		err = PTR_ERR(attach);
+		goto put_dma_buf;
+	}
+
+	sg = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL);
+	if (IS_ERR(sg)) {
+		dev_err(dev, "unable to map a DMA-BUF object (from %s): %ld",
+			dmabuf->exp_name, PTR_ERR(sg));
+		err = PTR_ERR(sg);
+		goto detach;
+	}
+
+	n = ib_map_mr_sg_zbva(mr, sg->sgl, sg->nents, NULL, PAGE_SIZE);
+	if (unlikely(n != sg->nents)) {
+		dev_err(dev, "failed to map sg (%d/%d) of DMA-BUF object (from %s)\n",
+			n, sg->nents, dmabuf->exp_name);
+		err = n < 0 ? n : -EINVAL;
+		goto unmap;
+	}
+
+	mr->attach = attach;
+	mr->sg = sg;
+	return 0;
+
+unmap:
+	dma_buf_unmap_attachment(attach, sg, DMA_BIDIRECTIONAL);
+detach:
+	dma_buf_detach(dmabuf, attach);
+put_dma_buf:
+	dma_buf_put(dmabuf);
+	return err;
+}
+EXPORT_SYMBOL(ib_mr_attach_dmabuf);
+
+void ib_mr_detach_dmabuf(struct dma_buf_attachment *attach,
+			 struct sg_table *sg)
+{
+	struct dma_buf *dmabuf = attach->dmabuf;
+
+	dma_buf_unmap_attachment(attach, sg, DMA_BIDIRECTIONAL);
+	dma_buf_detach(dmabuf, attach);
+	dma_buf_put(dmabuf);
+}
+EXPORT_SYMBOL(ib_mr_detach_dmabuf);
diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h
index 7e440d41487a..da23ec0a06d7 100644
--- a/include/rdma/ib_verbs.h
+++ b/include/rdma/ib_verbs.h
@@ -1465,6 +1465,9 @@ struct ib_mr {
 		struct ib_uobject	*uobject;	/* user */
 		struct list_head	qp_entry;	/* FR */
 	};
+	/* For MRs that expose a DMA-BUF */
+	struct dma_buf_attachment *attach;
+	struct sg_table *sg;
 };
 
 struct ib_mw {
@@ -3189,4 +3192,10 @@ int ib_sg_to_pages(struct ib_mr *mr, struct scatterlist *sgl, int sg_nents,
 void ib_drain_rq(struct ib_qp *qp);
 void ib_drain_sq(struct ib_qp *qp);
 void ib_drain_qp(struct ib_qp *qp);
+
+struct dma_buf;
+int ib_mr_attach_dmabuf(struct ib_mr *mr, struct dma_buf *dmabuf, int access);
+void ib_mr_detach_dmabuf(struct dma_buf_attachment *attach,
+			 struct sg_table *sg);
+
 #endif /* IB_VERBS_H */
-- 
1.7.11.2

--
To unsubscribe from this list: send the line "unsubscribe linux-pci" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [DMA Engine]     [Linux Coverity]     [Linux USB]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Greybus]

  Powered by Linux