Two patches to implement a generic framework for dma-buf to support local private interconnects. The interconnect support is negotiated as part of an attachment and is not a property of the dma-buf itself. Just like pcie p2p support.
The first patch adds members to the dma_buf_attach_ops and to the dma_buf_attachment structure. These are needed for generic check of interconnect support, typically when an interconnect is shared between drivers. For truly driver-private interconnects they are not strictly needed, but still could be convenient.
The second patch implements an interconnect negotiation for xe, without actually changing the protocol itself from pcie_p2p. Just as an example.
Thomas Hellström (2): dma-buf: Add support for private interconnects drm/xe/dma-buf: Add generic interconnect support framework
drivers/gpu/drm/xe/tests/xe_dma_buf.c | 12 +++--- drivers/gpu/drm/xe/xe_dma_buf.c | 54 +++++++++++++++++++++++---- drivers/gpu/drm/xe/xe_dma_buf.h | 1 - drivers/gpu/drm/xe/xe_interconnect.h | 22 +++++++++++ include/linux/dma-buf.h | 15 ++++++++ 5 files changed, 90 insertions(+), 14 deletions(-) create mode 100644 drivers/gpu/drm/xe/xe_interconnect.h
Add a function to the dma_buf_attach_ops to indicate whether the connection is a private interconnect. If so the function returns the address to an interconnect-defined structure that can be used for further negotiating.
Also add a field to the dma_buf_attachment that indicates whether a private interconnect is used by the attachment.
Signed-off-by: Thomas Hellström thomas.hellstrom@linux.intel.com --- include/linux/dma-buf.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+)
diff --git a/include/linux/dma-buf.h b/include/linux/dma-buf.h index d58e329ac0e7..e7191edb2125 100644 --- a/include/linux/dma-buf.h +++ b/include/linux/dma-buf.h @@ -475,6 +475,19 @@ struct dma_buf_attach_ops { * point to the new location of the DMA-buf. */ void (*move_notify)(struct dma_buf_attachment *attach); + + /** + * @supports_interconnect: [optional] - Does the driver support a local interconnect? + * + * Does the importer support a private interconnect? The interconnect is + * identified using a unique address defined by the exporter and declared + * in a protocol header. (RFC: Should this be a struct instead). + * + * Return: A pointer to the interconnect-private attach_ops structure if supported, + * %NULL otherwise. + */ + const void *(*supports_interconnect)(struct dma_buf_attachment *attach, + const void *interconnect); };
/** @@ -484,6 +497,7 @@ struct dma_buf_attach_ops { * @node: list of dma_buf_attachment, protected by dma_resv lock of the dmabuf. * @peer2peer: true if the importer can handle peer resources without pages. * @priv: exporter specific attachment data. + * @interconnect: Private interconnect to use if any, NULL otherwise. * @importer_ops: importer operations for this attachment, if provided * dma_buf_map/unmap_attachment() must be called with the dma_resv lock held. * @importer_priv: importer specific attachment data. @@ -503,6 +517,7 @@ struct dma_buf_attachment { struct list_head node; bool peer2peer; const struct dma_buf_attach_ops *importer_ops; + const void *interconnect; void *importer_priv; void *priv; };
On Thu, 2025-09-25 at 15:08 +0200, Thomas Hellström wrote:
Add a function to the dma_buf_attach_ops to indicate whether the connection is a private interconnect. If so the function returns the address to an interconnect-defined structure that can be used for further negotiating.
Also add a field to the dma_buf_attachment that indicates whether a private interconnect is used by the attachment.
Signed-off-by: Thomas Hellström thomas.hellstrom@linux.intel.com
include/linux/dma-buf.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+)
diff --git a/include/linux/dma-buf.h b/include/linux/dma-buf.h index d58e329ac0e7..e7191edb2125 100644 --- a/include/linux/dma-buf.h +++ b/include/linux/dma-buf.h @@ -475,6 +475,19 @@ struct dma_buf_attach_ops { * point to the new location of the DMA-buf. */ void (*move_notify)(struct dma_buf_attachment *attach);
- /**
* @supports_interconnect: [optional] - Does the driver
support a local interconnect?
*
* Does the importer support a private interconnect? The
interconnect is
* identified using a unique address defined by the exporter
and declared
* in a protocol header.
Actually we'd probably want to use something like a
struct dma_buf_interconnect { const char *name; };
Here, and for globally known interconnects have them instantiated somewhere common since there could be multiple exporters.
(RFC: Should this be a struct instead).
*
* Return: A pointer to the interconnect-private attach_ops
structure if supported,
* %NULL otherwise.
*/
- const void *(*supports_interconnect)(struct
dma_buf_attachment *attach,
const void
*interconnect);
And similarly for stricter type-checking the return value could be a struct dma_buf_interconnect_attach_ops { };
which is subclassed for each interconnect-private attach ops.
}; /** @@ -484,6 +497,7 @@ struct dma_buf_attach_ops { * @node: list of dma_buf_attachment, protected by dma_resv lock of the dmabuf. * @peer2peer: true if the importer can handle peer resources without pages. * @priv: exporter specific attachment data.
- @interconnect: Private interconnect to use if any, NULL
otherwise. * @importer_ops: importer operations for this attachment, if provided * dma_buf_map/unmap_attachment() must be called with the dma_resv lock held. * @importer_priv: importer specific attachment data. @@ -503,6 +517,7 @@ struct dma_buf_attachment { struct list_head node; bool peer2peer; const struct dma_buf_attach_ops *importer_ops;
- const void *interconnect;
const struct dma_buf_interconnect *interconnect;
void *importer_priv; void *priv; };
/Thomas
Negotiate to use an xe-specific interconnect.
Signed-off-by: Thomas Hellström thomas.hellstrom@linux.intel.com --- drivers/gpu/drm/xe/tests/xe_dma_buf.c | 12 +++--- drivers/gpu/drm/xe/xe_dma_buf.c | 54 +++++++++++++++++++++++---- drivers/gpu/drm/xe/xe_dma_buf.h | 1 - drivers/gpu/drm/xe/xe_interconnect.h | 22 +++++++++++ 4 files changed, 75 insertions(+), 14 deletions(-) create mode 100644 drivers/gpu/drm/xe/xe_interconnect.h
diff --git a/drivers/gpu/drm/xe/tests/xe_dma_buf.c b/drivers/gpu/drm/xe/tests/xe_dma_buf.c index 5df98de5ba3c..8eaea6c2a3b7 100644 --- a/drivers/gpu/drm/xe/tests/xe_dma_buf.c +++ b/drivers/gpu/drm/xe/tests/xe_dma_buf.c @@ -210,9 +210,9 @@ static const struct dma_buf_attach_ops nop2p_attach_ops = { */ static const struct dma_buf_test_params test_params[] = { {.mem_mask = XE_BO_FLAG_VRAM0, - .attach_ops = &xe_dma_buf_attach_ops}, + .attach_ops = &xe_dma_buf_attach_ops.dma_ops}, {.mem_mask = XE_BO_FLAG_VRAM0 | XE_BO_FLAG_NEEDS_CPU_ACCESS, - .attach_ops = &xe_dma_buf_attach_ops, + .attach_ops = &xe_dma_buf_attach_ops.dma_ops, .force_different_devices = true},
{.mem_mask = XE_BO_FLAG_VRAM0, @@ -226,9 +226,9 @@ static const struct dma_buf_test_params test_params[] = { .force_different_devices = true},
{.mem_mask = XE_BO_FLAG_SYSTEM, - .attach_ops = &xe_dma_buf_attach_ops}, + .attach_ops = &xe_dma_buf_attach_ops.dma_ops}, {.mem_mask = XE_BO_FLAG_SYSTEM, - .attach_ops = &xe_dma_buf_attach_ops, + .attach_ops = &xe_dma_buf_attach_ops.dma_ops, .force_different_devices = true},
{.mem_mask = XE_BO_FLAG_SYSTEM, @@ -242,10 +242,10 @@ static const struct dma_buf_test_params test_params[] = { .force_different_devices = true},
{.mem_mask = XE_BO_FLAG_SYSTEM | XE_BO_FLAG_VRAM0, - .attach_ops = &xe_dma_buf_attach_ops}, + .attach_ops = &xe_dma_buf_attach_ops.dma_ops}, {.mem_mask = XE_BO_FLAG_SYSTEM | XE_BO_FLAG_VRAM0 | XE_BO_FLAG_NEEDS_CPU_ACCESS, - .attach_ops = &xe_dma_buf_attach_ops, + .attach_ops = &xe_dma_buf_attach_ops.dma_ops, .force_different_devices = true},
{.mem_mask = XE_BO_FLAG_SYSTEM | XE_BO_FLAG_VRAM0, diff --git a/drivers/gpu/drm/xe/xe_dma_buf.c b/drivers/gpu/drm/xe/xe_dma_buf.c index 54e42960daad..40e9a28eaf64 100644 --- a/drivers/gpu/drm/xe/xe_dma_buf.c +++ b/drivers/gpu/drm/xe/xe_dma_buf.c @@ -16,19 +16,40 @@ #include "tests/xe_test.h" #include "xe_bo.h" #include "xe_device.h" +#include "xe_interconnect.h" #include "xe_pm.h" #include "xe_ttm_vram_mgr.h" #include "xe_vm.h"
MODULE_IMPORT_NS("DMA_BUF");
+struct xe_dma_buf_attach_ops { + struct dma_buf_attach_ops dma_ops; + struct xe_interconnect_attach_ops ic_ops; +}; + +static const struct xe_dma_buf_attach_ops * +to_xe_dma_buf_attach_ops(struct dma_buf_attachment *attach) +{ + const struct dma_buf_attach_ops *aops = attach->importer_ops; + + if (!aops || !aops->supports_interconnect) + return NULL; + + return aops->supports_interconnect(attach, xe_interconnect); +} + static int xe_dma_buf_attach(struct dma_buf *dmabuf, struct dma_buf_attachment *attach) { struct drm_gem_object *obj = attach->dmabuf->priv; + const struct xe_dma_buf_attach_ops *xe_attach_ops = + to_xe_dma_buf_attach_ops(attach);
- if (attach->peer2peer && - pci_p2pdma_distance(to_pci_dev(obj->dev->dev), attach->dev, false) < 0) + if (xe_attach_ops && xe_attach_ops->ic_ops.allow_ic) + attach->interconnect = xe_interconnect; + else if (attach->peer2peer && + pci_p2pdma_distance(to_pci_dev(obj->dev->dev), attach->dev, false) < 0) attach->peer2peer = false;
if (!attach->peer2peer && !xe_bo_can_migrate(gem_to_xe_bo(obj), XE_PL_TT)) @@ -285,9 +306,27 @@ static void xe_dma_buf_move_notify(struct dma_buf_attachment *attach) XE_WARN_ON(xe_bo_evict(bo, exec)); }
-static const struct dma_buf_attach_ops xe_dma_buf_attach_ops = { - .allow_peer2peer = true, - .move_notify = xe_dma_buf_move_notify +static const void *xe_dma_buf_supports_interconnect(struct dma_buf_attachment *attach, + const void *interconnect) +{ + if (interconnect == xe_interconnect) { + return &container_of(attach->importer_ops, + const struct xe_dma_buf_attach_ops, + dma_ops)->ic_ops; + } + + return NULL; +} + +static const struct xe_dma_buf_attach_ops xe_dma_buf_attach_ops = { + .dma_ops = { + .allow_peer2peer = true, + .move_notify = xe_dma_buf_move_notify, + .supports_interconnect = xe_dma_buf_supports_interconnect, + }, + .ic_ops = { + .allow_ic = true, + } };
#if IS_ENABLED(CONFIG_DRM_XE_KUNIT_TEST) @@ -336,12 +375,11 @@ struct drm_gem_object *xe_gem_prime_import(struct drm_device *dev, if (IS_ERR(bo)) return ERR_CAST(bo);
- attach_ops = &xe_dma_buf_attach_ops; + attach_ops = &xe_dma_buf_attach_ops.dma_ops; #if IS_ENABLED(CONFIG_DRM_XE_KUNIT_TEST) if (test) attach_ops = test->attach_ops; #endif - attach = dma_buf_dynamic_attach(dma_buf, dev->dev, attach_ops, &bo->ttm.base); if (IS_ERR(attach)) { obj = ERR_CAST(attach); @@ -364,6 +402,8 @@ struct drm_gem_object *xe_gem_prime_import(struct drm_device *dev, return obj; }
+void *xe_interconnect = "XE_INTERCONNECT"; + #if IS_ENABLED(CONFIG_DRM_XE_KUNIT_TEST) #include "tests/xe_dma_buf.c" #endif diff --git a/drivers/gpu/drm/xe/xe_dma_buf.h b/drivers/gpu/drm/xe/xe_dma_buf.h index 861dd28a862c..6b381ce4b7c1 100644 --- a/drivers/gpu/drm/xe/xe_dma_buf.h +++ b/drivers/gpu/drm/xe/xe_dma_buf.h @@ -11,5 +11,4 @@ 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); - #endif diff --git a/drivers/gpu/drm/xe/xe_interconnect.h b/drivers/gpu/drm/xe/xe_interconnect.h new file mode 100644 index 000000000000..1fa052623d05 --- /dev/null +++ b/drivers/gpu/drm/xe/xe_interconnect.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2025 Intel Corporation + */ +#ifndef _XE_INTERCONNECT_H_ +#define _XE_INTERCONNECT_H_ + +#include <linux/types.h> + +/* This file needs to be shared between the importer and exporter of the interconnect */ + +extern void *xe_interconnect; + +struct xe_interconnect_attach_ops { + /* + * Here interconnect-private stuff can be added. + * Like a function to check interconnect possibility. + */ + bool allow_ic; +}; + +#endif
linaro-mm-sig@lists.linaro.org