Intel-XE Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: Maarten Lankhorst <dev@lankhorst.se>
To: intel-xe@lists.freedesktop.org
Cc: dri-devel@lists.freedesktop.org, Maarten Lankhorst <dev@lankhorst.se>
Subject: [RFC PATCH 8/8] drm/xe: Allow mapping DMA-BUF buffer objects connected through IAF
Date: Fri, 13 Jun 2025 15:45:27 +0200	[thread overview]
Message-ID: <20250613134520.2458175-18-dev@lankhorst.se> (raw)
In-Reply-To: <20250613134520.2458175-10-dev@lankhorst.se>

IAF allows multiple xe devices to import VRAM from each other.
It's mapped as local VRAM, but outside the local device range.

To support this, Xe is changed to allow a special case of
same-implementation importing with direction = DMA_NONE.

If this DMA direction is used, the physical VRAM addresses are exported,
and can be imported into a xe_vm with the device memory bit set.

In order to prevent bugs, we ensure that this is only allowed for
xe <-> xe imports/exports, and only when the VRAM flag is set.

If any of the steps required fails for IAF-import, the default
non-IAF import path is attempted.

Signed-off-by: Maarten Lankhorst <dev@lankhorst.se>
---
 drivers/gpu/drm/xe/xe_bo.c           | 85 ++++++++++++++++++++++++----
 drivers/gpu/drm/xe/xe_bo.h           |  2 +
 drivers/gpu/drm/xe/xe_dma_buf.c      | 27 ++++++++-
 drivers/gpu/drm/xe/xe_dma_buf.h      |  1 +
 drivers/gpu/drm/xe/xe_ggtt.c         |  4 +-
 drivers/gpu/drm/xe/xe_iaf.c          | 42 ++++++++++++++
 drivers/gpu/drm/xe/xe_iaf.h          | 16 ++++++
 drivers/gpu/drm/xe/xe_pt.c           |  4 ++
 drivers/gpu/drm/xe/xe_ttm_vram_mgr.c | 23 +++++---
 drivers/gpu/drm/xe/xe_vm.c           |  2 +-
 10 files changed, 184 insertions(+), 22 deletions(-)

diff --git a/drivers/gpu/drm/xe/xe_bo.c b/drivers/gpu/drm/xe/xe_bo.c
index 4e39188a021ab..13f0c685a012f 100644
--- a/drivers/gpu/drm/xe/xe_bo.c
+++ b/drivers/gpu/drm/xe/xe_bo.c
@@ -24,6 +24,7 @@
 #include "xe_drm_client.h"
 #include "xe_ggtt.h"
 #include "xe_gt.h"
+#include "xe_iaf.h"
 #include "xe_map.h"
 #include "xe_migrate.h"
 #include "xe_pm.h"
@@ -82,6 +83,11 @@ bool mem_type_is_vram(u32 mem_type)
 	return mem_type >= XE_PL_VRAM0 && mem_type != XE_PL_STOLEN;
 }
 
+bool xe_bo_is_iaf(struct xe_bo *bo)
+{
+	return bo->flags & XE_BO_FLAG_IAF;
+}
+
 static bool resource_is_stolen_vram(struct xe_device *xe, struct ttm_resource *res)
 {
 	return res->mem_type == XE_PL_STOLEN && IS_DGFX(xe);
@@ -656,6 +662,68 @@ static int xe_bo_trigger_rebind(struct xe_device *xe, struct xe_bo *bo,
 	return ret;
 }
 
+static void bo_unmap_dma_buf(struct xe_bo *bo)
+{
+	enum dma_data_direction dir = DMA_BIDIRECTIONAL;
+	struct dma_buf_attachment *attach = bo->ttm.base.import_attach;
+	struct dma_buf *dmabuf;
+
+	if (xe_bo_is_iaf(bo))
+		dir = DMA_NONE;
+
+	dma_buf_unmap_attachment(attach, bo->ttm.sg, dir);
+	bo->ttm.sg = NULL;
+
+	if (xe_bo_is_iaf(bo)) {
+		/* Cleanup IAF bindings */
+		dmabuf = attach->dmabuf;
+		xe_iaf_mapping_put(xe_bo_device(gem_to_xe_bo(dmabuf->priv))->iaf);
+		xe_iaf_mapping_put(xe_bo_device(bo)->iaf);
+		bo->flags &= ~XE_BO_FLAG_IAF;
+	}
+}
+
+static struct sg_table *bo_map_dma_buf(struct xe_bo *bo)
+{
+	struct dma_buf_attachment *attach = bo->ttm.base.import_attach;
+	struct dma_buf *dmabuf = attach->dmabuf;
+	struct sg_table *sg;
+
+	if (is_xe_dma_buf(dmabuf)) {
+		struct xe_device *src = xe_bo_device(gem_to_xe_bo(dmabuf->priv));
+		struct xe_device *dst = xe_bo_device(bo);
+		int err;
+
+		if (!xe_iaf_fabrics_connected(dst->iaf, src->iaf))
+			goto no_iaf;
+
+		err = xe_iaf_mapping_get(dst->iaf);
+		if (err) {
+			drm_warn(&dst->drm, "Getting DST IAF mapping ref failed with %pe", ERR_PTR(err));
+			goto no_iaf;
+		}
+
+		err = xe_iaf_mapping_get(src->iaf);
+		if (err) {
+			drm_warn(&src->drm, "Getting SRC IAF mapping ref failed with %pe", ERR_PTR(err));
+			goto err_put_dst;
+		}
+
+		sg = dma_buf_map_attachment(attach, DMA_NONE);
+		if (!IS_ERR(sg)) {
+			bo->flags |= XE_BO_FLAG_IAF;
+			return sg;
+		}
+
+		xe_iaf_mapping_put(src->iaf);
+err_put_dst:
+		xe_iaf_mapping_put(dst->iaf);
+	}
+
+no_iaf:
+	return dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL);
+}
+
 /*
  * The dma-buf map_attachment() / unmap_attachment() is hooked up here.
  * Note that unmapping the attachment is deferred to the next
@@ -665,9 +733,9 @@ static int xe_bo_trigger_rebind(struct xe_device *xe, struct xe_bo *bo,
  * backing store out. Should that assumption not hold, then we will be able
  * to unconditionally call unmap_attachment() when moving out to system.
  */
-static int xe_bo_move_dmabuf(struct ttm_buffer_object *ttm_bo,
-			     struct ttm_resource *new_res)
+static int xe_bo_move_dmabuf(struct xe_bo *bo, struct ttm_resource *new_res)
 {
+	struct ttm_buffer_object *ttm_bo = &bo->ttm;
 	struct dma_buf_attachment *attach = ttm_bo->base.import_attach;
 	struct xe_ttm_tt *xe_tt = container_of(ttm_bo->ttm, struct xe_ttm_tt,
 					       ttm);
@@ -682,19 +750,16 @@ static int xe_bo_move_dmabuf(struct ttm_buffer_object *ttm_bo,
 	    ttm_bo->sg) {
 		dma_resv_wait_timeout(ttm_bo->base.resv, DMA_RESV_USAGE_BOOKKEEP,
 				      false, MAX_SCHEDULE_TIMEOUT);
-		dma_buf_unmap_attachment(attach, ttm_bo->sg, DMA_BIDIRECTIONAL);
-		ttm_bo->sg = NULL;
+		bo_unmap_dma_buf(bo);
 	}
 
 	if (new_res->mem_type == XE_PL_SYSTEM)
 		goto out;
 
-	if (ttm_bo->sg) {
-		dma_buf_unmap_attachment(attach, ttm_bo->sg, DMA_BIDIRECTIONAL);
-		ttm_bo->sg = NULL;
-	}
+	if (ttm_bo->sg)
+		bo_unmap_dma_buf(bo);
 
-	sg = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL);
+	sg = bo_map_dma_buf(bo);
 	if (IS_ERR(sg))
 		return PTR_ERR(sg);
 
@@ -797,7 +862,7 @@ static int xe_bo_move(struct ttm_buffer_object *ttm_bo, bool evict,
 	if (ttm_bo->type == ttm_bo_type_sg) {
 		ret = xe_bo_move_notify(bo, ctx);
 		if (!ret)
-			ret = xe_bo_move_dmabuf(ttm_bo, new_mem);
+			ret = xe_bo_move_dmabuf(bo, new_mem);
 		return ret;
 	}
 
diff --git a/drivers/gpu/drm/xe/xe_bo.h b/drivers/gpu/drm/xe/xe_bo.h
index ecb5fe3b1c1dc..210ee49d6a04d 100644
--- a/drivers/gpu/drm/xe/xe_bo.h
+++ b/drivers/gpu/drm/xe/xe_bo.h
@@ -44,6 +44,7 @@
 #define XE_BO_FLAG_GGTT2		BIT(22)
 #define XE_BO_FLAG_GGTT3		BIT(23)
 #define XE_BO_FLAG_CPU_ADDR_MIRROR	BIT(24)
+#define XE_BO_FLAG_IAF			BIT(25)
 
 /* this one is trigger internally only */
 #define XE_BO_FLAG_INTERNAL_TEST	BIT(30)
@@ -262,6 +263,7 @@ void xe_bo_vunmap(struct xe_bo *bo);
 int xe_bo_read(struct xe_bo *bo, u64 offset, void *dst, int size);
 
 bool mem_type_is_vram(u32 mem_type);
+bool xe_bo_is_iaf(struct xe_bo *bo);
 bool xe_bo_is_vram(struct xe_bo *bo);
 bool xe_bo_is_stolen(struct xe_bo *bo);
 bool xe_bo_is_stolen_devmem(struct xe_bo *bo);
diff --git a/drivers/gpu/drm/xe/xe_dma_buf.c b/drivers/gpu/drm/xe/xe_dma_buf.c
index 346f857f38374..2e8aca5d572ae 100644
--- a/drivers/gpu/drm/xe/xe_dma_buf.c
+++ b/drivers/gpu/drm/xe/xe_dma_buf.c
@@ -86,6 +86,8 @@ static void xe_dma_buf_unpin(struct dma_buf_attachment *attach)
 	xe_bo_unpin_external(bo);
 }
 
+static const struct dma_buf_attach_ops xe_dma_buf_attach_ops;
+
 static struct sg_table *xe_dma_buf_map(struct dma_buf_attachment *attach,
 				       enum dma_data_direction dir)
 {
@@ -94,12 +96,21 @@ static struct sg_table *xe_dma_buf_map(struct dma_buf_attachment *attach,
 	struct xe_bo *bo = gem_to_xe_bo(obj);
 	struct sg_table *sgt;
 	int r = 0;
+	bool iaf = false;
+
+	if (dir == DMA_NONE) {
+		if (attach->importer_ops != &xe_dma_buf_attach_ops)
+			return ERR_PTR(-EOPNOTSUPP);
+
+		iaf = true;
+	}
 
-	if (!attach->peer2peer && !xe_bo_can_migrate(bo, XE_PL_TT))
+	if (!attach->peer2peer && !iaf &&
+	    !xe_bo_can_migrate(bo, XE_PL_TT))
 		return ERR_PTR(-EOPNOTSUPP);
 
 	if (!xe_bo_is_pinned(bo)) {
-		if (!attach->peer2peer)
+		if (!attach->peer2peer && !iaf)
 			r = xe_bo_migrate(bo, XE_PL_TT);
 		else
 			r = xe_bo_validate(bo, NULL, false);
@@ -109,6 +120,10 @@ static struct sg_table *xe_dma_buf_map(struct dma_buf_attachment *attach,
 
 	switch (bo->ttm.resource->mem_type) {
 	case XE_PL_TT:
+		/* IAF only available for VRAM */
+		if (iaf)
+			return ERR_PTR(-EOPNOTSUPP);
+
 		sgt = drm_prime_pages_to_sg(obj->dev,
 					    bo->ttm.ttm->pages,
 					    bo->ttm.ttm->num_pages);
@@ -146,7 +161,8 @@ static void xe_dma_buf_unmap(struct dma_buf_attachment *attach,
 			     enum dma_data_direction dir)
 {
 	if (sg_page(sgt->sgl)) {
-		dma_unmap_sgtable(attach->dev, sgt, dir, 0);
+		if (dir != DMA_NONE)
+			dma_unmap_sgtable(attach->dev, sgt, dir, 0);
 		sg_free_table(sgt);
 		kfree(sgt);
 	} else {
@@ -187,6 +203,11 @@ static const struct dma_buf_ops xe_dmabuf_ops = {
 	.vunmap = drm_gem_dmabuf_vunmap,
 };
 
+bool is_xe_dma_buf(struct dma_buf *dma_buf)
+{
+	return dma_buf->ops == &xe_dmabuf_ops;
+}
+
 struct dma_buf *xe_gem_prime_export(struct drm_gem_object *obj, int flags)
 {
 	struct xe_bo *bo = gem_to_xe_bo(obj);
diff --git a/drivers/gpu/drm/xe/xe_dma_buf.h b/drivers/gpu/drm/xe/xe_dma_buf.h
index 861dd28a862c7..80d12c624b921 100644
--- a/drivers/gpu/drm/xe/xe_dma_buf.h
+++ b/drivers/gpu/drm/xe/xe_dma_buf.h
@@ -11,5 +11,6 @@
 struct dma_buf *xe_gem_prime_export(struct drm_gem_object *obj, int flags);
 struct drm_gem_object *xe_gem_prime_import(struct drm_device *dev,
 					   struct dma_buf *dma_buf);
+bool is_xe_dma_buf(struct dma_buf *dma_buf);
 
 #endif
diff --git a/drivers/gpu/drm/xe/xe_ggtt.c b/drivers/gpu/drm/xe/xe_ggtt.c
index b8e1b44452e4d..c6ff18deb9db1 100644
--- a/drivers/gpu/drm/xe/xe_ggtt.c
+++ b/drivers/gpu/drm/xe/xe_ggtt.c
@@ -122,7 +122,9 @@ static u64 xelp_ggtt_pte_flags(struct xe_bo *bo, u16 pat_index)
 {
 	u64 pte = XE_PAGE_PRESENT;
 
-	if (xe_bo_is_vram(bo) || xe_bo_is_stolen_devmem(bo))
+	if (xe_bo_is_vram(bo) || xe_bo_is_stolen_devmem(bo) ||
+	    /* It's likely legal to map IAF to GGTT, but it should be impossible? */
+	    drm_WARN_ON(bo->ttm.base.dev, xe_bo_is_iaf(bo)))
 		pte |= XE_GGTT_PTE_DM;
 
 	return pte;
diff --git a/drivers/gpu/drm/xe/xe_iaf.c b/drivers/gpu/drm/xe/xe_iaf.c
index 431d20fea5369..af2a8d045b593 100644
--- a/drivers/gpu/drm/xe/xe_iaf.c
+++ b/drivers/gpu/drm/xe/xe_iaf.c
@@ -416,3 +416,45 @@ struct query_info *xe_iaf_connectivity_query(struct xe_iaf *iaf, u32 fabric_id)
 
 	return iaf->ops->connectivity_query(iaf->handle, fabric_id);
 }
+
+bool xe_iaf_fabrics_connected(struct xe_iaf *src, struct xe_iaf *dst)
+{
+	struct query_info *qi;
+	bool connected;
+
+	if (!src || !dst || !src->ops || !dst->ops)
+		return false;
+
+	qi = xe_iaf_connectivity_query(src, dst->fabric_id);
+	if (IS_ERR(qi))
+		return false;
+
+	if (WARN_ON_ONCE(!qi))
+		return true;
+
+	connected = true;
+	for (int i = 0, n = qi->src_cnt * qi->dst_cnt; i < n; i++)
+		if (!qi->sd2sd[i].bandwidth) {
+			connected = false;
+			break;
+		}
+
+	kfree(qi);
+	return connected;
+}
+
+int xe_iaf_mapping_get(struct xe_iaf *iaf)
+{
+	if (!iaf || !iaf->ops)
+		return -ENODEV;
+
+	return iaf->ops->parent_event(iaf->handle, IAF_PARENT_MAPPING_GET);
+}
+
+void xe_iaf_mapping_put(struct xe_iaf *iaf)
+{
+	if (!iaf || !iaf->ops)
+		return;
+
+	iaf->ops->parent_event(iaf->handle, IAF_PARENT_MAPPING_PUT);
+}
diff --git a/drivers/gpu/drm/xe/xe_iaf.h b/drivers/gpu/drm/xe/xe_iaf.h
index df6b8f9f2bc5f..b8e75640e8967 100644
--- a/drivers/gpu/drm/xe/xe_iaf.h
+++ b/drivers/gpu/drm/xe/xe_iaf.h
@@ -38,6 +38,9 @@ int xe_iaf_init(struct xe_device *xe);
 int xe_iaf_init_aux(struct xe_device *xe);
 u64 xe_iaf_dpa_base(struct xe_device *xe);
 struct query_info *xe_iaf_connectivity_query(struct xe_iaf *iaf, u32 fabric_id);
+bool xe_iaf_fabrics_connected(struct xe_iaf *src, struct xe_iaf *dst);
+int xe_iaf_mapping_get(struct xe_iaf *iaf);
+void xe_iaf_mapping_put(struct xe_iaf *iaf);
 
 #else
 
@@ -61,6 +64,19 @@ struct query_info *xe_iaf_connectivity_query(struct xe_iaf *iaf, u32 fabric_id)
 	return ERR_PTR(-ENODEV);
 }
 
+static inline int xe_iaf_mapping_get(struct xe_iaf *iaf)
+{
+	return -ENODEV;
+}
+
+static inline void xe_iaf_mapping_put(struct xe_iaf *iaf)
+{}
+
+static inline bool xe_iaf_fabrics_connected(struct xe_iaf *src, struct xe_iaf *dst)
+{
+	return false;
+}
+
 #endif
 
 #endif
diff --git a/drivers/gpu/drm/xe/xe_pt.c b/drivers/gpu/drm/xe/xe_pt.c
index f39d5cc9f411e..2231882b2bc45 100644
--- a/drivers/gpu/drm/xe/xe_pt.c
+++ b/drivers/gpu/drm/xe/xe_pt.c
@@ -764,6 +764,10 @@ xe_pt_stage_bind(struct xe_tile *tile, struct xe_vma *vma,
 		else
 			xe_res_first_sg(xe_bo_sg(bo), xe_vma_bo_offset(vma),
 					xe_vma_size(vma), &curs);
+
+		/* When IAF is used, the bo requires the DM flag */
+		if (xe_bo_is_iaf(bo))
+			curs.mem_type = XE_PL_VRAM0;
 	} else if (!range) {
 		curs.size = xe_vma_size(vma);
 	}
diff --git a/drivers/gpu/drm/xe/xe_ttm_vram_mgr.c b/drivers/gpu/drm/xe/xe_ttm_vram_mgr.c
index 9e375a40aee90..94a572693e139 100644
--- a/drivers/gpu/drm/xe/xe_ttm_vram_mgr.c
+++ b/drivers/gpu/drm/xe/xe_ttm_vram_mgr.c
@@ -396,11 +396,16 @@ int xe_ttm_vram_mgr_alloc_sgt(struct xe_device *xe,
 		size_t size = min_t(u64, cursor.size, SZ_2G);
 		dma_addr_t addr;
 
-		addr = dma_map_resource(dev, phys, size, dir,
-					DMA_ATTR_SKIP_CPU_SYNC);
-		r = dma_mapping_error(dev, addr);
-		if (r)
-			goto error_unmap;
+		if (valid_dma_direction(dir)) {
+			addr = dma_map_resource(dev, phys, size, dir,
+						DMA_ATTR_SKIP_CPU_SYNC);
+			r = dma_mapping_error(dev, addr);
+			if (r)
+				goto error_unmap;
+		} else {
+			/* Only want the SG table for fabric */
+			addr = cursor.start + tile->mem.vram.dpa_base;
+		}
 
 		sg_set_page(sg, NULL, size, 0);
 		sg_dma_address(sg) = addr;
@@ -413,7 +418,7 @@ int xe_ttm_vram_mgr_alloc_sgt(struct xe_device *xe,
 
 error_unmap:
 	for_each_sgtable_sg((*sgt), sg, i) {
-		if (!sg->length)
+		if (!sg->length || !valid_dma_direction(dir))
 			continue;
 
 		dma_unmap_resource(dev, sg->dma_address,
@@ -433,10 +438,14 @@ void xe_ttm_vram_mgr_free_sgt(struct device *dev, enum dma_data_direction dir,
 	struct scatterlist *sg;
 	int i;
 
-	for_each_sgtable_sg(sgt, sg, i)
+	for_each_sgtable_sg(sgt, sg, i) {
+		if (!valid_dma_direction(dir))
+			continue;
+
 		dma_unmap_resource(dev, sg->dma_address,
 				   sg->length, dir,
 				   DMA_ATTR_SKIP_CPU_SYNC);
+	}
 	sg_free_table(sgt);
 	kfree(sgt);
 }
diff --git a/drivers/gpu/drm/xe/xe_vm.c b/drivers/gpu/drm/xe/xe_vm.c
index 18f967ce1f1a6..f3dd38c95deb5 100644
--- a/drivers/gpu/drm/xe/xe_vm.c
+++ b/drivers/gpu/drm/xe/xe_vm.c
@@ -1534,7 +1534,7 @@ static u64 xelp_pte_encode_bo(struct xe_bo *bo, u64 bo_offset,
 	pte |= pte_encode_pat_index(pat_index, pt_level);
 	pte |= pte_encode_ps(pt_level);
 
-	if (xe_bo_is_vram(bo) || xe_bo_is_stolen_devmem(bo))
+	if (xe_bo_is_vram(bo) || xe_bo_is_stolen_devmem(bo) || xe_bo_is_iaf(bo))
 		pte |= XE_PPGTT_PTE_DM;
 
 	return pte;
-- 
2.45.2


  parent reply	other threads:[~2025-06-13 13:45 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-06-13 13:45 [RFC PATCH 0/8] RFC enable IAF support on PVC Maarten Lankhorst
2025-06-13 13:45 ` [RFC PATCH 1/8] drm/xe: Add PSC region for PVC Maarten Lankhorst
2025-06-13 13:45 ` [RFC PATCH 2/8] include/drm/i915_component: Add IAF type Maarten Lankhorst
2025-06-13 13:45 ` [RFC PATCH 3/8] mei: Add IAF mei component Maarten Lankhorst
2025-06-13 13:45 ` [RFC PATCH 4/8] drm/xe: Add fabric code from i915 backport repository Maarten Lankhorst
2025-06-13 13:45 ` [RFC PATCH 5/8] drm/xe: Add support for IAF devices Maarten Lankhorst
2025-06-13 13:45 ` [RFC PATCH 6/8] drm/xe/uapi: Add query ioctl for fabric connectivity Maarten Lankhorst
2025-06-13 13:45 ` [RFC PATCH 7/8] drm/xe: Remove unused XE_DEFAULT_GTT_SIZE_MB definition Maarten Lankhorst
2025-06-13 13:45 ` Maarten Lankhorst [this message]
2025-06-18 13:57   ` [RFC PATCH 8/8] drm/xe: Allow mapping DMA-BUF buffer objects connected through IAF Simona Vetter

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20250613134520.2458175-18-dev@lankhorst.se \
    --to=dev@lankhorst.se \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=intel-xe@lists.freedesktop.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox