* [RFC 1/8] dma-buf: Add support for map/unmap APIs for interconnects
2025-10-14 7:08 [RFC 0/8] dma-buf: Add support for mapping dmabufs via interconnects Vivek Kasireddy
@ 2025-10-14 7:08 ` Vivek Kasireddy
2025-10-20 9:34 ` Thomas Hellström
2025-10-28 13:58 ` Christian König
2025-10-14 7:08 ` [RFC 2/8] dma-buf: Add a helper to match interconnects between exporter/importer Vivek Kasireddy
` (6 subsequent siblings)
7 siblings, 2 replies; 16+ messages in thread
From: Vivek Kasireddy @ 2025-10-14 7:08 UTC (permalink / raw)
To: dri-devel, intel-xe, linux-media, linaro-mm-sig
Cc: Vivek Kasireddy, Jason Gunthorpe, Christian Koenig, Sumit Semwal,
Thomas Hellström, Simona Vetter
For the map operation, the dma-buf core will create an xarray but
the exporter is expected to populate it with the interconnect
specific addresses. And, similarly for unmap, the exporter is
expected to cleanup the individual entries of the xarray.
Cc: Jason Gunthorpe <jgg@nvidia.com>
Cc: Christian Koenig <christian.koenig@amd.com>
Cc: Sumit Semwal <sumit.semwal@linaro.org>
Cc: Thomas Hellström <thomas.hellstrom@linux.intel.com>
Cc: Simona Vetter <simona.vetter@ffwll.ch>
Signed-off-by: Vivek Kasireddy <vivek.kasireddy@intel.com>
---
drivers/dma-buf/dma-buf.c | 68 ++++++++++++++++++++++++++++
include/linux/dma-buf-interconnect.h | 29 ++++++++++++
include/linux/dma-buf.h | 11 +++++
3 files changed, 108 insertions(+)
create mode 100644 include/linux/dma-buf-interconnect.h
diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c
index 2bcf9ceca997..162642bd53e8 100644
--- a/drivers/dma-buf/dma-buf.c
+++ b/drivers/dma-buf/dma-buf.c
@@ -1612,6 +1612,74 @@ void dma_buf_vunmap_unlocked(struct dma_buf *dmabuf, struct iosys_map *map)
}
EXPORT_SYMBOL_NS_GPL(dma_buf_vunmap_unlocked, "DMA_BUF");
+struct dma_buf_ranges *
+dma_buf_map_interconnect(struct dma_buf_attachment *attach)
+{
+ const struct dma_buf_interconnect_ops *ic_ops;
+ struct dma_buf *dmabuf = attach->dmabuf;
+ struct dma_buf_ranges *ranges;
+ int ret;
+
+ might_sleep();
+
+ if (WARN_ON(!attach || !attach->dmabuf))
+ return ERR_PTR(-EINVAL);
+
+ if (!dma_buf_attachment_is_dynamic(attach))
+ return ERR_PTR(-EINVAL);
+
+ if (!attach->allow_ic)
+ return ERR_PTR(-EOPNOTSUPP);
+
+ dma_resv_assert_held(attach->dmabuf->resv);
+
+ ic_ops = dmabuf->ops->interconnect_ops;
+ if (!ic_ops || !ic_ops->map_interconnect)
+ return ERR_PTR(-EINVAL);
+
+ ranges = kzalloc(sizeof(*ranges), GFP_KERNEL);
+ if (!ranges)
+ return ERR_PTR(-ENOMEM);
+
+ xa_init(&ranges->ranges);
+ ret = ic_ops->map_interconnect(attach, ranges);
+ if (ret)
+ goto err_free_ranges;
+
+ return ranges;
+
+err_free_ranges:
+ xa_destroy(&ranges->ranges);
+ kfree(ranges);
+ return ERR_PTR(ret);
+}
+EXPORT_SYMBOL_NS_GPL(dma_buf_map_interconnect, "DMA_BUF");
+
+void dma_buf_unmap_interconnect(struct dma_buf_attachment *attach,
+ struct dma_buf_ranges *ranges)
+{
+ const struct dma_buf_interconnect_ops *ic_ops;
+ struct dma_buf *dmabuf = attach->dmabuf;
+
+ if (WARN_ON(!attach || !attach->dmabuf || !ranges))
+ return;
+
+ if (!attach->allow_ic)
+ return;
+
+ ic_ops = dmabuf->ops->interconnect_ops;
+ if (!ic_ops || !ic_ops->unmap_interconnect)
+ return;
+
+ dma_resv_assert_held(attach->dmabuf->resv);
+
+ ic_ops->unmap_interconnect(attach, ranges);
+
+ xa_destroy(&ranges->ranges);
+ kfree(ranges);
+}
+EXPORT_SYMBOL_NS_GPL(dma_buf_unmap_interconnect, "DMA_BUF");
+
#ifdef CONFIG_DEBUG_FS
static int dma_buf_debug_show(struct seq_file *s, void *unused)
{
diff --git a/include/linux/dma-buf-interconnect.h b/include/linux/dma-buf-interconnect.h
new file mode 100644
index 000000000000..17504dea9691
--- /dev/null
+++ b/include/linux/dma-buf-interconnect.h
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: MIT */
+
+#ifndef __DMA_BUF_INTERCONNECT_H__
+#define __DMA_BUF_INTERCONNECT_H__
+
+#include <linux/xarray.h>
+
+struct dma_buf_attachment;
+
+struct dma_buf_ranges {
+ struct xarray ranges;
+ unsigned int nranges;
+};
+
+enum dma_buf_interconnect_type {
+ DMA_BUF_INTERCONNECT_NONE = 0,
+};
+
+struct dma_buf_interconnect {
+ enum dma_buf_interconnect_type type;
+};
+
+struct dma_buf_interconnect_ops {
+ int (*map_interconnect)(struct dma_buf_attachment *attach,
+ struct dma_buf_ranges *ranges);
+ void (*unmap_interconnect)(struct dma_buf_attachment *attach,
+ struct dma_buf_ranges *ranges);
+};
+#endif
diff --git a/include/linux/dma-buf.h b/include/linux/dma-buf.h
index d58e329ac0e7..db91c67c00d6 100644
--- a/include/linux/dma-buf.h
+++ b/include/linux/dma-buf.h
@@ -23,6 +23,8 @@
#include <linux/dma-fence.h>
#include <linux/wait.h>
+#include <linux/dma-buf-interconnect.h>
+
struct device;
struct dma_buf;
struct dma_buf_attachment;
@@ -276,6 +278,8 @@ struct dma_buf_ops {
int (*vmap)(struct dma_buf *dmabuf, struct iosys_map *map);
void (*vunmap)(struct dma_buf *dmabuf, struct iosys_map *map);
+
+ const struct dma_buf_interconnect_ops *interconnect_ops;
};
/**
@@ -502,7 +506,9 @@ struct dma_buf_attachment {
struct device *dev;
struct list_head node;
bool peer2peer;
+ bool allow_ic;
const struct dma_buf_attach_ops *importer_ops;
+ struct dma_buf_interconnect interconnect;
void *importer_priv;
void *priv;
};
@@ -589,6 +595,11 @@ struct sg_table *dma_buf_map_attachment(struct dma_buf_attachment *,
enum dma_data_direction);
void dma_buf_unmap_attachment(struct dma_buf_attachment *, struct sg_table *,
enum dma_data_direction);
+
+struct dma_buf_ranges *dma_buf_map_interconnect(struct dma_buf_attachment *);
+void dma_buf_unmap_interconnect(struct dma_buf_attachment *,
+ struct dma_buf_ranges *);
+
void dma_buf_move_notify(struct dma_buf *dma_buf);
int dma_buf_begin_cpu_access(struct dma_buf *dma_buf,
enum dma_data_direction dir);
--
2.50.1
^ permalink raw reply related [flat|nested] 16+ messages in thread* Re: [RFC 1/8] dma-buf: Add support for map/unmap APIs for interconnects
2025-10-14 7:08 ` [RFC 1/8] dma-buf: Add support for map/unmap APIs for interconnects Vivek Kasireddy
@ 2025-10-20 9:34 ` Thomas Hellström
2025-10-21 5:45 ` Kasireddy, Vivek
2025-10-28 13:58 ` Christian König
1 sibling, 1 reply; 16+ messages in thread
From: Thomas Hellström @ 2025-10-20 9:34 UTC (permalink / raw)
To: Vivek Kasireddy, dri-devel, intel-xe, linux-media, linaro-mm-sig
Cc: Jason Gunthorpe, Christian Koenig, Sumit Semwal, Simona Vetter
Hi, Vivek,
On Tue, 2025-10-14 at 00:08 -0700, Vivek Kasireddy wrote:
> For the map operation, the dma-buf core will create an xarray but
> the exporter is expected to populate it with the interconnect
> specific addresses. And, similarly for unmap, the exporter is
> expected to cleanup the individual entries of the xarray.
>
> Cc: Jason Gunthorpe <jgg@nvidia.com>
> Cc: Christian Koenig <christian.koenig@amd.com>
> Cc: Sumit Semwal <sumit.semwal@linaro.org>
> Cc: Thomas Hellström <thomas.hellstrom@linux.intel.com>
> Cc: Simona Vetter <simona.vetter@ffwll.ch>
> Signed-off-by: Vivek Kasireddy <vivek.kasireddy@intel.com>
> ---
> drivers/dma-buf/dma-buf.c | 68
> ++++++++++++++++++++++++++++
> include/linux/dma-buf-interconnect.h | 29 ++++++++++++
> include/linux/dma-buf.h | 11 +++++
> 3 files changed, 108 insertions(+)
> create mode 100644 include/linux/dma-buf-interconnect.h
>
> diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c
> index 2bcf9ceca997..162642bd53e8 100644
> --- a/drivers/dma-buf/dma-buf.c
> +++ b/drivers/dma-buf/dma-buf.c
> @@ -1612,6 +1612,74 @@ void dma_buf_vunmap_unlocked(struct dma_buf
> *dmabuf, struct iosys_map *map)
> }
> EXPORT_SYMBOL_NS_GPL(dma_buf_vunmap_unlocked, "DMA_BUF");
>
> +struct dma_buf_ranges *
> +dma_buf_map_interconnect(struct dma_buf_attachment *attach)
Even if this is an RFC, please add kerneldoc so that the way the
interface is intended to be used becomes completely clear. Both for
functions and structs.
> +{
> + const struct dma_buf_interconnect_ops *ic_ops;
> + struct dma_buf *dmabuf = attach->dmabuf;
> + struct dma_buf_ranges *ranges;
> + int ret;
> +
> + might_sleep();
> +
> + if (WARN_ON(!attach || !attach->dmabuf))
> + return ERR_PTR(-EINVAL);
> +
> + if (!dma_buf_attachment_is_dynamic(attach))
> + return ERR_PTR(-EINVAL);
> +
> + if (!attach->allow_ic)
> + return ERR_PTR(-EOPNOTSUPP);
> +
> + dma_resv_assert_held(attach->dmabuf->resv);
> +
> + ic_ops = dmabuf->ops->interconnect_ops;
> + if (!ic_ops || !ic_ops->map_interconnect)
> + return ERR_PTR(-EINVAL);
> +
> + ranges = kzalloc(sizeof(*ranges), GFP_KERNEL);
> + if (!ranges)
> + return ERR_PTR(-ENOMEM);
> +
> + xa_init(&ranges->ranges);
> + ret = ic_ops->map_interconnect(attach, ranges);
> + if (ret)
> + goto err_free_ranges;
> +
> + return ranges;
> +
> +err_free_ranges:
> + xa_destroy(&ranges->ranges);
> + kfree(ranges);
> + return ERR_PTR(ret);
> +}
> +EXPORT_SYMBOL_NS_GPL(dma_buf_map_interconnect, "DMA_BUF");
> +
> +void dma_buf_unmap_interconnect(struct dma_buf_attachment *attach,
> + struct dma_buf_ranges *ranges)
> +{
> + const struct dma_buf_interconnect_ops *ic_ops;
> + struct dma_buf *dmabuf = attach->dmabuf;
> +
> + if (WARN_ON(!attach || !attach->dmabuf || !ranges))
> + return;
> +
> + if (!attach->allow_ic)
> + return;
> +
> + ic_ops = dmabuf->ops->interconnect_ops;
> + if (!ic_ops || !ic_ops->unmap_interconnect)
> + return;
> +
> + dma_resv_assert_held(attach->dmabuf->resv);
> +
> + ic_ops->unmap_interconnect(attach, ranges);
> +
> + xa_destroy(&ranges->ranges);
> + kfree(ranges);
> +}
> +EXPORT_SYMBOL_NS_GPL(dma_buf_unmap_interconnect, "DMA_BUF");
> +
> #ifdef CONFIG_DEBUG_FS
> static int dma_buf_debug_show(struct seq_file *s, void *unused)
> {
> diff --git a/include/linux/dma-buf-interconnect.h
> b/include/linux/dma-buf-interconnect.h
> new file mode 100644
> index 000000000000..17504dea9691
> --- /dev/null
> +++ b/include/linux/dma-buf-interconnect.h
> @@ -0,0 +1,29 @@
> +/* SPDX-License-Identifier: MIT */
> +
> +#ifndef __DMA_BUF_INTERCONNECT_H__
> +#define __DMA_BUF_INTERCONNECT_H__
> +
> +#include <linux/xarray.h>
> +
> +struct dma_buf_attachment;
> +
> +struct dma_buf_ranges {
> + struct xarray ranges;
> + unsigned int nranges;
IIUC this would replace the sg-table right? I guess Jason or Christian
would need to comment on whether this is generic enough or whether it
needs to be interconnect-dependent.
> +};
> +
> +enum dma_buf_interconnect_type {
> + DMA_BUF_INTERCONNECT_NONE = 0,
> +};
This calls for registering all known interconnects with the dma-buf
layer even if the interconnects are completely driver-private. I'd
suggest using a pointer to identify interconnect and whatever entity
defines the interconnect provides a unique pointer. For globally
visible interconnects this could be done in dma-buf.c or a dma-buf-
interconnect.c
> +
> +struct dma_buf_interconnect {
> + enum dma_buf_interconnect_type type;
> +};
> +
> +struct dma_buf_interconnect_ops {
> + int (*map_interconnect)(struct dma_buf_attachment *attach,
> + struct dma_buf_ranges *ranges);
> + void (*unmap_interconnect)(struct dma_buf_attachment
> *attach,
> + struct dma_buf_ranges *ranges);
> +};
> +#endif
> diff --git a/include/linux/dma-buf.h b/include/linux/dma-buf.h
> index d58e329ac0e7..db91c67c00d6 100644
> --- a/include/linux/dma-buf.h
> +++ b/include/linux/dma-buf.h
> @@ -23,6 +23,8 @@
> #include <linux/dma-fence.h>
> #include <linux/wait.h>
>
> +#include <linux/dma-buf-interconnect.h>
> +
> struct device;
> struct dma_buf;
> struct dma_buf_attachment;
> @@ -276,6 +278,8 @@ struct dma_buf_ops {
>
> int (*vmap)(struct dma_buf *dmabuf, struct iosys_map *map);
> void (*vunmap)(struct dma_buf *dmabuf, struct iosys_map
> *map);
> +
> + const struct dma_buf_interconnect_ops *interconnect_ops;
> };
>
> /**
> @@ -502,7 +506,9 @@ struct dma_buf_attachment {
> struct device *dev;
> struct list_head node;
> bool peer2peer;
> + bool allow_ic;
> const struct dma_buf_attach_ops *importer_ops;
> + struct dma_buf_interconnect interconnect;
Hmm. Could we have a pointer to the interconnect here? Let's say the
interconnect implementation would want to subclass with additional
information?
> void *importer_priv;
> void *priv;
> };
> @@ -589,6 +595,11 @@ struct sg_table *dma_buf_map_attachment(struct
> dma_buf_attachment *,
> enum dma_data_direction);
> void dma_buf_unmap_attachment(struct dma_buf_attachment *, struct
> sg_table *,
> enum dma_data_direction);
> +
> +struct dma_buf_ranges *dma_buf_map_interconnect(struct
> dma_buf_attachment *);
> +void dma_buf_unmap_interconnect(struct dma_buf_attachment *,
> + struct dma_buf_ranges *);
> +
> void dma_buf_move_notify(struct dma_buf *dma_buf);
> int dma_buf_begin_cpu_access(struct dma_buf *dma_buf,
> enum dma_data_direction dir);
Thanks,
Thomas
^ permalink raw reply [flat|nested] 16+ messages in thread* RE: [RFC 1/8] dma-buf: Add support for map/unmap APIs for interconnects
2025-10-20 9:34 ` Thomas Hellström
@ 2025-10-21 5:45 ` Kasireddy, Vivek
0 siblings, 0 replies; 16+ messages in thread
From: Kasireddy, Vivek @ 2025-10-21 5:45 UTC (permalink / raw)
To: Thomas Hellström, Jason Gunthorpe, Christian Koenig,
Sumit Semwal, Simona Vetter
Cc: dri-devel@lists.freedesktop.org, intel-xe@lists.freedesktop.org,
linux-media@vger.kernel.org, linaro-mm-sig@lists.linaro.org
Hi Thomas,
> Subject: Re: [RFC 1/8] dma-buf: Add support for map/unmap APIs for
> interconnects
>
> Hi, Vivek,
>
> On Tue, 2025-10-14 at 00:08 -0700, Vivek Kasireddy wrote:
> > For the map operation, the dma-buf core will create an xarray but
> > the exporter is expected to populate it with the interconnect
> > specific addresses. And, similarly for unmap, the exporter is
> > expected to cleanup the individual entries of the xarray.
> >
> > Cc: Jason Gunthorpe <jgg@nvidia.com>
> > Cc: Christian Koenig <christian.koenig@amd.com>
> > Cc: Sumit Semwal <sumit.semwal@linaro.org>
> > Cc: Thomas Hellström <thomas.hellstrom@linux.intel.com>
> > Cc: Simona Vetter <simona.vetter@ffwll.ch>
> > Signed-off-by: Vivek Kasireddy <vivek.kasireddy@intel.com>
> > ---
> > drivers/dma-buf/dma-buf.c | 68
> > ++++++++++++++++++++++++++++
> > include/linux/dma-buf-interconnect.h | 29 ++++++++++++
> > include/linux/dma-buf.h | 11 +++++
> > 3 files changed, 108 insertions(+)
> > create mode 100644 include/linux/dma-buf-interconnect.h
> >
> > diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c
> > index 2bcf9ceca997..162642bd53e8 100644
> > --- a/drivers/dma-buf/dma-buf.c
> > +++ b/drivers/dma-buf/dma-buf.c
> > @@ -1612,6 +1612,74 @@ void dma_buf_vunmap_unlocked(struct
> dma_buf
> > *dmabuf, struct iosys_map *map)
> > }
> > EXPORT_SYMBOL_NS_GPL(dma_buf_vunmap_unlocked, "DMA_BUF");
> >
> > +struct dma_buf_ranges *
> > +dma_buf_map_interconnect(struct dma_buf_attachment *attach)
>
> Even if this is an RFC, please add kerneldoc so that the way the
> interface is intended to be used becomes completely clear. Both for
> functions and structs.
Ok, will add documentation in the next version.
>
>
> > +{
> > + const struct dma_buf_interconnect_ops *ic_ops;
> > + struct dma_buf *dmabuf = attach->dmabuf;
> > + struct dma_buf_ranges *ranges;
> > + int ret;
> > +
> > + might_sleep();
> > +
> > + if (WARN_ON(!attach || !attach->dmabuf))
> > + return ERR_PTR(-EINVAL);
> > +
> > + if (!dma_buf_attachment_is_dynamic(attach))
> > + return ERR_PTR(-EINVAL);
> > +
> > + if (!attach->allow_ic)
> > + return ERR_PTR(-EOPNOTSUPP);
> > +
> > + dma_resv_assert_held(attach->dmabuf->resv);
> > +
> > + ic_ops = dmabuf->ops->interconnect_ops;
> > + if (!ic_ops || !ic_ops->map_interconnect)
> > + return ERR_PTR(-EINVAL);
> > +
> > + ranges = kzalloc(sizeof(*ranges), GFP_KERNEL);
> > + if (!ranges)
> > + return ERR_PTR(-ENOMEM);
> > +
> > + xa_init(&ranges->ranges);
> > + ret = ic_ops->map_interconnect(attach, ranges);
> > + if (ret)
> > + goto err_free_ranges;
> > +
> > + return ranges;
> > +
> > +err_free_ranges:
> > + xa_destroy(&ranges->ranges);
> > + kfree(ranges);
> > + return ERR_PTR(ret);
> > +}
> > +EXPORT_SYMBOL_NS_GPL(dma_buf_map_interconnect, "DMA_BUF");
> > +
> > +void dma_buf_unmap_interconnect(struct dma_buf_attachment *attach,
> > + struct dma_buf_ranges *ranges)
> > +{
> > + const struct dma_buf_interconnect_ops *ic_ops;
> > + struct dma_buf *dmabuf = attach->dmabuf;
> > +
> > + if (WARN_ON(!attach || !attach->dmabuf || !ranges))
> > + return;
> > +
> > + if (!attach->allow_ic)
> > + return;
> > +
> > + ic_ops = dmabuf->ops->interconnect_ops;
> > + if (!ic_ops || !ic_ops->unmap_interconnect)
> > + return;
> > +
> > + dma_resv_assert_held(attach->dmabuf->resv);
> > +
> > + ic_ops->unmap_interconnect(attach, ranges);
> > +
> > + xa_destroy(&ranges->ranges);
> > + kfree(ranges);
> > +}
> > +EXPORT_SYMBOL_NS_GPL(dma_buf_unmap_interconnect, "DMA_BUF");
> > +
> > #ifdef CONFIG_DEBUG_FS
> > static int dma_buf_debug_show(struct seq_file *s, void *unused)
> > {
> > diff --git a/include/linux/dma-buf-interconnect.h
> > b/include/linux/dma-buf-interconnect.h
> > new file mode 100644
> > index 000000000000..17504dea9691
> > --- /dev/null
> > +++ b/include/linux/dma-buf-interconnect.h
> > @@ -0,0 +1,29 @@
> > +/* SPDX-License-Identifier: MIT */
> > +
> > +#ifndef __DMA_BUF_INTERCONNECT_H__
> > +#define __DMA_BUF_INTERCONNECT_H__
> > +
> > +#include <linux/xarray.h>
> > +
> > +struct dma_buf_attachment;
> > +
> > +struct dma_buf_ranges {
> > + struct xarray ranges;
> > + unsigned int nranges;
>
> IIUC this would replace the sg-table right?
Yes, that is the intended goal.
> I guess Jason or Christian
> would need to comment on whether this is generic enough or whether it
> needs to be interconnect-dependent.
AFAIU, the individual entries of the xarray could be of any type that is
interconnect-specific and shared between exporter and importer.
For example, for IOV interconnect, I have picked struct range as the
type (to represent individual entries of the xarray) to share addresses
between exporter and importer.
>
> > +};
> > +
> > +enum dma_buf_interconnect_type {
> > + DMA_BUF_INTERCONNECT_NONE = 0,
> > +};
>
> This calls for registering all known interconnects with the dma-buf
> layer even if the interconnects are completely driver-private. I'd
> suggest using a pointer to identify interconnect and whatever entity
> defines the interconnect provides a unique pointer. For globally
> visible interconnects this could be done in dma-buf.c or a dma-buf-
> interconnect.c
Thank you for your suggestion. I'll explore the idea in more detail.
>
> > +
> > +struct dma_buf_interconnect {
> > + enum dma_buf_interconnect_type type;
> > +};
> > +
> > +struct dma_buf_interconnect_ops {
> > + int (*map_interconnect)(struct dma_buf_attachment *attach,
> > + struct dma_buf_ranges *ranges);
> > + void (*unmap_interconnect)(struct dma_buf_attachment
> > *attach,
> > + struct dma_buf_ranges *ranges);
> > +};
> > +#endif
> > diff --git a/include/linux/dma-buf.h b/include/linux/dma-buf.h
> > index d58e329ac0e7..db91c67c00d6 100644
> > --- a/include/linux/dma-buf.h
> > +++ b/include/linux/dma-buf.h
> > @@ -23,6 +23,8 @@
> > #include <linux/dma-fence.h>
> > #include <linux/wait.h>
> >
> > +#include <linux/dma-buf-interconnect.h>
> > +
> > struct device;
> > struct dma_buf;
> > struct dma_buf_attachment;
> > @@ -276,6 +278,8 @@ struct dma_buf_ops {
> >
> > int (*vmap)(struct dma_buf *dmabuf, struct iosys_map *map);
> > void (*vunmap)(struct dma_buf *dmabuf, struct iosys_map
> > *map);
> > +
> > + const struct dma_buf_interconnect_ops *interconnect_ops;
> > };
> >
> > /**
> > @@ -502,7 +506,9 @@ struct dma_buf_attachment {
> > struct device *dev;
> > struct list_head node;
> > bool peer2peer;
> > + bool allow_ic;
> > const struct dma_buf_attach_ops *importer_ops;
> > + struct dma_buf_interconnect interconnect;
>
> Hmm. Could we have a pointer to the interconnect here? Let's say the
> interconnect implementation would want to subclass with additional
> information?
Sure. I was going to do that in the next version.
Thanks,
Vivek
>
>
> > void *importer_priv;
> > void *priv;
> > };
> > @@ -589,6 +595,11 @@ struct sg_table
> *dma_buf_map_attachment(struct
> > dma_buf_attachment *,
> > enum dma_data_direction);
> > void dma_buf_unmap_attachment(struct dma_buf_attachment *, struct
> > sg_table *,
> > enum dma_data_direction);
> > +
> > +struct dma_buf_ranges *dma_buf_map_interconnect(struct
> > dma_buf_attachment *);
> > +void dma_buf_unmap_interconnect(struct dma_buf_attachment *,
> > + struct dma_buf_ranges *);
> > +
> > void dma_buf_move_notify(struct dma_buf *dma_buf);
> > int dma_buf_begin_cpu_access(struct dma_buf *dma_buf,
> > enum dma_data_direction dir);
>
> Thanks,
> Thomas
>
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [RFC 1/8] dma-buf: Add support for map/unmap APIs for interconnects
2025-10-14 7:08 ` [RFC 1/8] dma-buf: Add support for map/unmap APIs for interconnects Vivek Kasireddy
2025-10-20 9:34 ` Thomas Hellström
@ 2025-10-28 13:58 ` Christian König
2025-10-28 14:05 ` Jason Gunthorpe
1 sibling, 1 reply; 16+ messages in thread
From: Christian König @ 2025-10-28 13:58 UTC (permalink / raw)
To: Vivek Kasireddy, dri-devel, intel-xe, linux-media, linaro-mm-sig
Cc: Jason Gunthorpe, Sumit Semwal, Thomas Hellström,
Simona Vetter
On 10/14/25 09:08, Vivek Kasireddy wrote:
> For the map operation, the dma-buf core will create an xarray but
> the exporter is expected to populate it with the interconnect
> specific addresses. And, similarly for unmap, the exporter is
> expected to cleanup the individual entries of the xarray.
>
> Cc: Jason Gunthorpe <jgg@nvidia.com>
> Cc: Christian Koenig <christian.koenig@amd.com>
> Cc: Sumit Semwal <sumit.semwal@linaro.org>
> Cc: Thomas Hellström <thomas.hellstrom@linux.intel.com>
> Cc: Simona Vetter <simona.vetter@ffwll.ch>
> Signed-off-by: Vivek Kasireddy <vivek.kasireddy@intel.com>
> ---
> drivers/dma-buf/dma-buf.c | 68 ++++++++++++++++++++++++++++
> include/linux/dma-buf-interconnect.h | 29 ++++++++++++
> include/linux/dma-buf.h | 11 +++++
> 3 files changed, 108 insertions(+)
> create mode 100644 include/linux/dma-buf-interconnect.h
>
> diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c
> index 2bcf9ceca997..162642bd53e8 100644
> --- a/drivers/dma-buf/dma-buf.c
> +++ b/drivers/dma-buf/dma-buf.c
> @@ -1612,6 +1612,74 @@ void dma_buf_vunmap_unlocked(struct dma_buf *dmabuf, struct iosys_map *map)
> }
> EXPORT_SYMBOL_NS_GPL(dma_buf_vunmap_unlocked, "DMA_BUF");
>
> +struct dma_buf_ranges *
> +dma_buf_map_interconnect(struct dma_buf_attachment *attach)
> +{
> + const struct dma_buf_interconnect_ops *ic_ops;
> + struct dma_buf *dmabuf = attach->dmabuf;
> + struct dma_buf_ranges *ranges;
> + int ret;
> +
> + might_sleep();
> +
> + if (WARN_ON(!attach || !attach->dmabuf))
> + return ERR_PTR(-EINVAL);
> +
> + if (!dma_buf_attachment_is_dynamic(attach))
> + return ERR_PTR(-EINVAL);
> +
> + if (!attach->allow_ic)
> + return ERR_PTR(-EOPNOTSUPP);
> +
> + dma_resv_assert_held(attach->dmabuf->resv);
> +
> + ic_ops = dmabuf->ops->interconnect_ops;
> + if (!ic_ops || !ic_ops->map_interconnect)
> + return ERR_PTR(-EINVAL);
> +
> + ranges = kzalloc(sizeof(*ranges), GFP_KERNEL);
> + if (!ranges)
> + return ERR_PTR(-ENOMEM);
> +
> + xa_init(&ranges->ranges);
> + ret = ic_ops->map_interconnect(attach, ranges);
> + if (ret)
> + goto err_free_ranges;
> +
> + return ranges;
> +
> +err_free_ranges:
> + xa_destroy(&ranges->ranges);
> + kfree(ranges);
> + return ERR_PTR(ret);
> +}
> +EXPORT_SYMBOL_NS_GPL(dma_buf_map_interconnect, "DMA_BUF");
> +
> +void dma_buf_unmap_interconnect(struct dma_buf_attachment *attach,
> + struct dma_buf_ranges *ranges)
> +{
> + const struct dma_buf_interconnect_ops *ic_ops;
> + struct dma_buf *dmabuf = attach->dmabuf;
> +
> + if (WARN_ON(!attach || !attach->dmabuf || !ranges))
> + return;
> +
> + if (!attach->allow_ic)
> + return;
> +
> + ic_ops = dmabuf->ops->interconnect_ops;
> + if (!ic_ops || !ic_ops->unmap_interconnect)
> + return;
> +
> + dma_resv_assert_held(attach->dmabuf->resv);
> +
> + ic_ops->unmap_interconnect(attach, ranges);
> +
> + xa_destroy(&ranges->ranges);
> + kfree(ranges);
> +}
> +EXPORT_SYMBOL_NS_GPL(dma_buf_unmap_interconnect, "DMA_BUF");
> +
> #ifdef CONFIG_DEBUG_FS
> static int dma_buf_debug_show(struct seq_file *s, void *unused)
> {
> diff --git a/include/linux/dma-buf-interconnect.h b/include/linux/dma-buf-interconnect.h
> new file mode 100644
> index 000000000000..17504dea9691
> --- /dev/null
> +++ b/include/linux/dma-buf-interconnect.h
> @@ -0,0 +1,29 @@
> +/* SPDX-License-Identifier: MIT */
> +
> +#ifndef __DMA_BUF_INTERCONNECT_H__
> +#define __DMA_BUF_INTERCONNECT_H__
> +
> +#include <linux/xarray.h>
> +
> +struct dma_buf_attachment;
> +
> +struct dma_buf_ranges {
> + struct xarray ranges;
> + unsigned int nranges;
> +};
Hui? How is that supposed to work? Should the exporter fill in the xarray with values?
That clearly needs more description.
And IIRC xarray can only contain pointers because the lower bits are used for internal handling.
Some kind of iterator like interface would be preferred where you have first and next callbacks.
> +
> +enum dma_buf_interconnect_type {
> + DMA_BUF_INTERCONNECT_NONE = 0,
Let's start with a DMA_BUF_DMA_ADDR type.
> +};
> +
> +struct dma_buf_interconnect {
> + enum dma_buf_interconnect_type type;
> +};
> +
> +struct dma_buf_interconnect_ops {
> + int (*map_interconnect)(struct dma_buf_attachment *attach,
> + struct dma_buf_ranges *ranges);
> + void (*unmap_interconnect)(struct dma_buf_attachment *attach,
> + struct dma_buf_ranges *ranges);
> +};
Please put those directly into the dma_buf_ops structure, I don't really see a value in separating them.
Additional to that I'm not sure if the "interconnect" is a good naming, essentially we want to use the new mapping functions to replace the sg_table as well.
Regards,
Christian.
> +#endif
> diff --git a/include/linux/dma-buf.h b/include/linux/dma-buf.h
> index d58e329ac0e7..db91c67c00d6 100644
> --- a/include/linux/dma-buf.h
> +++ b/include/linux/dma-buf.h
> @@ -23,6 +23,8 @@
> #include <linux/dma-fence.h>
> #include <linux/wait.h>
>
> +#include <linux/dma-buf-interconnect.h>
> +
> struct device;
> struct dma_buf;
> struct dma_buf_attachment;
> @@ -276,6 +278,8 @@ struct dma_buf_ops {
>
> int (*vmap)(struct dma_buf *dmabuf, struct iosys_map *map);
> void (*vunmap)(struct dma_buf *dmabuf, struct iosys_map *map);
> +
> + const struct dma_buf_interconnect_ops *interconnect_ops;
> };
>
> /**
> @@ -502,7 +506,9 @@ struct dma_buf_attachment {
> struct device *dev;
> struct list_head node;
> bool peer2peer;
> + bool allow_ic;
> const struct dma_buf_attach_ops *importer_ops;
> + struct dma_buf_interconnect interconnect;
> void *importer_priv;
> void *priv;
> };
> @@ -589,6 +595,11 @@ struct sg_table *dma_buf_map_attachment(struct dma_buf_attachment *,
> enum dma_data_direction);
> void dma_buf_unmap_attachment(struct dma_buf_attachment *, struct sg_table *,
> enum dma_data_direction);
> +
> +struct dma_buf_ranges *dma_buf_map_interconnect(struct dma_buf_attachment *);
> +void dma_buf_unmap_interconnect(struct dma_buf_attachment *,
> + struct dma_buf_ranges *);
> +
> void dma_buf_move_notify(struct dma_buf *dma_buf);
> int dma_buf_begin_cpu_access(struct dma_buf *dma_buf,
> enum dma_data_direction dir);
^ permalink raw reply [flat|nested] 16+ messages in thread* Re: [RFC 1/8] dma-buf: Add support for map/unmap APIs for interconnects
2025-10-28 13:58 ` Christian König
@ 2025-10-28 14:05 ` Jason Gunthorpe
2025-10-28 14:14 ` Christian König
0 siblings, 1 reply; 16+ messages in thread
From: Jason Gunthorpe @ 2025-10-28 14:05 UTC (permalink / raw)
To: Christian König
Cc: Vivek Kasireddy, dri-devel, intel-xe, linux-media, linaro-mm-sig,
Sumit Semwal, Thomas Hellström, Simona Vetter
On Tue, Oct 28, 2025 at 02:58:57PM +0100, Christian König wrote:
> Some kind of iterator like interface would be preferred where you
> have first and next callbacks.
That's what I thought you were asking for..
Are you sure that is what you want? It will make mapping of fragments
alot slower..
> Additional to that I'm not sure if the "interconnect" is a good
> naming, essentially we want to use the new mapping functions to
> replace the sg_table as well.
'mapping type' ?
Jason
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [RFC 1/8] dma-buf: Add support for map/unmap APIs for interconnects
2025-10-28 14:05 ` Jason Gunthorpe
@ 2025-10-28 14:14 ` Christian König
2025-10-28 14:44 ` Jason Gunthorpe
0 siblings, 1 reply; 16+ messages in thread
From: Christian König @ 2025-10-28 14:14 UTC (permalink / raw)
To: Jason Gunthorpe
Cc: Vivek Kasireddy, dri-devel, intel-xe, linux-media, linaro-mm-sig,
Sumit Semwal, Thomas Hellström, Simona Vetter
On 10/28/25 15:05, Jason Gunthorpe wrote:
> On Tue, Oct 28, 2025 at 02:58:57PM +0100, Christian König wrote:
>
>> Some kind of iterator like interface would be preferred where you
>> have first and next callbacks.
>
> That's what I thought you were asking for..
>
> Are you sure that is what you want? It will make mapping of fragments
> alot slower..
Well the first function should have a start parameter and both return offset and length.
Alternatively we could come up with some container, but yeah then we would need to convert into the container format again.
>
>> Additional to that I'm not sure if the "interconnect" is a good
>> naming, essentially we want to use the new mapping functions to
>> replace the sg_table as well.
>
> 'mapping type' ?
+1
Christian.>
> Jason
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [RFC 1/8] dma-buf: Add support for map/unmap APIs for interconnects
2025-10-28 14:14 ` Christian König
@ 2025-10-28 14:44 ` Jason Gunthorpe
0 siblings, 0 replies; 16+ messages in thread
From: Jason Gunthorpe @ 2025-10-28 14:44 UTC (permalink / raw)
To: Christian König
Cc: Vivek Kasireddy, dri-devel, intel-xe, linux-media, linaro-mm-sig,
Sumit Semwal, Thomas Hellström, Simona Vetter
On Tue, Oct 28, 2025 at 03:14:32PM +0100, Christian König wrote:
> On 10/28/25 15:05, Jason Gunthorpe wrote:
> > On Tue, Oct 28, 2025 at 02:58:57PM +0100, Christian König wrote:
> >
> >> Some kind of iterator like interface would be preferred where you
> >> have first and next callbacks.
> >
> > That's what I thought you were asking for..
> >
> > Are you sure that is what you want? It will make mapping of fragments
> > alot slower..
>
> Well the first function should have a start parameter and both
> return offset and length.
At least RDMA doesn't want this, we need to see the whole list to make
calculations on the shape of the HW page table to allocate.
> Alternatively we could come up with some container, but yeah then we
> would need to convert into the container format again.
Well, given we won't get away from scatterlist in the near term lets
start out by having per "mapping type" functions that return something
natural and type-correct for their types and see where that brings
us. Starting with scatterlist..
Once we have the new interface people can propose alternative "mapping
types" and we can see benchmarks.
For this vfio stuff a kvalloc() flat array is likely good enough. Most
use case will be single range.
Jason
^ permalink raw reply [flat|nested] 16+ messages in thread
* [RFC 2/8] dma-buf: Add a helper to match interconnects between exporter/importer
2025-10-14 7:08 [RFC 0/8] dma-buf: Add support for mapping dmabufs via interconnects Vivek Kasireddy
2025-10-14 7:08 ` [RFC 1/8] dma-buf: Add support for map/unmap APIs for interconnects Vivek Kasireddy
@ 2025-10-14 7:08 ` Vivek Kasireddy
2025-10-17 15:58 ` Kasireddy, Vivek
2025-10-14 7:08 ` [RFC 3/8] dma-buf: Add support for IOV interconnect Vivek Kasireddy
` (5 subsequent siblings)
7 siblings, 1 reply; 16+ messages in thread
From: Vivek Kasireddy @ 2025-10-14 7:08 UTC (permalink / raw)
To: dri-devel, intel-xe, linux-media, linaro-mm-sig
Cc: Vivek Kasireddy, Jason Gunthorpe, Christian Koenig, Sumit Semwal,
Thomas Hellström, Simona Vetter
If the importer provides an op for supports_interconnects(), the
exporter starts the matching (or negotiation) process (during
attach) by invoking the supports_interconnects() which would then
call this helper to identify the first common interconnect
supported by both exporter and importer.
Note that whether an interconnect is supported between an
exporter/importer is ultimately determined by the exporter via
the match op it is expected to provide.
Cc: Jason Gunthorpe <jgg@nvidia.com>
Cc: Christian Koenig <christian.koenig@amd.com>
Cc: Sumit Semwal <sumit.semwal@linaro.org>
Cc: Thomas Hellström <thomas.hellstrom@linux.intel.com>
Cc: Simona Vetter <simona.vetter@ffwll.ch>
Signed-off-by: Vivek Kasireddy <vivek.kasireddy@intel.com>
---
drivers/dma-buf/dma-buf.c | 45 +++++++++++++++++++++++++++-
include/linux/dma-buf-interconnect.h | 6 ++++
include/linux/dma-buf.h | 9 ++++++
3 files changed, 59 insertions(+), 1 deletion(-)
diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c
index 162642bd53e8..ed48540d1c1d 100644
--- a/drivers/dma-buf/dma-buf.c
+++ b/drivers/dma-buf/dma-buf.c
@@ -965,8 +965,11 @@ dma_buf_dynamic_attach(struct dma_buf *dmabuf, struct device *dev,
attach->dev = dev;
attach->dmabuf = dmabuf;
- if (importer_ops)
+ if (importer_ops) {
attach->peer2peer = importer_ops->allow_peer2peer;
+ if (importer_ops->supports_interconnects)
+ attach->allow_ic = true;
+ }
attach->importer_ops = importer_ops;
attach->importer_priv = importer_priv;
@@ -1680,6 +1683,46 @@ void dma_buf_unmap_interconnect(struct dma_buf_attachment *attach,
}
EXPORT_SYMBOL_NS_GPL(dma_buf_unmap_interconnect, "DMA_BUF");
+bool dma_buf_match_interconnects(struct dma_buf_attachment *attach,
+ const struct dma_buf_interconnect_match *exp,
+ unsigned int exp_ics,
+ const struct dma_buf_interconnect_match *imp,
+ unsigned int imp_ics)
+{
+ const struct dma_buf_interconnect *exp_ic, *imp_ic;
+ const struct dma_buf_interconnect_ops *ic_ops;
+ struct dma_buf *dmabuf = attach->dmabuf;
+ unsigned int i, j;
+
+ if (!exp || !imp)
+ return false;
+
+ if (!attach->allow_ic)
+ return false;
+
+ ic_ops = dmabuf->ops->interconnect_ops;
+ if (!ic_ops || !ic_ops->match_interconnect)
+ return false;
+
+ for (i = 0; i < exp_ics; i++) {
+ for (j = 0; j < imp_ics; j++) {
+ exp_ic = exp[i].interconnect;
+ imp_ic = imp[j].interconnect;
+
+ if (exp_ic->type == imp_ic->type) {
+ if (ic_ops->match_interconnect(exp_ic, imp_ic)) {
+ attach->interconnect.type = exp_ic->type;
+ return true;
+ }
+ }
+ }
+ }
+
+ attach->allow_ic = false;
+ return false;
+}
+EXPORT_SYMBOL_NS_GPL(dma_buf_match_interconnects, "DMA_BUF");
+
#ifdef CONFIG_DEBUG_FS
static int dma_buf_debug_show(struct seq_file *s, void *unused)
{
diff --git a/include/linux/dma-buf-interconnect.h b/include/linux/dma-buf-interconnect.h
index 17504dea9691..a72f65ed4806 100644
--- a/include/linux/dma-buf-interconnect.h
+++ b/include/linux/dma-buf-interconnect.h
@@ -20,10 +20,16 @@ struct dma_buf_interconnect {
enum dma_buf_interconnect_type type;
};
+struct dma_buf_interconnect_match {
+ const struct dma_buf_interconnect *interconnect;
+};
+
struct dma_buf_interconnect_ops {
int (*map_interconnect)(struct dma_buf_attachment *attach,
struct dma_buf_ranges *ranges);
void (*unmap_interconnect)(struct dma_buf_attachment *attach,
struct dma_buf_ranges *ranges);
+ bool (*match_interconnect)(const struct dma_buf_interconnect *exp_ic,
+ const struct dma_buf_interconnect *imp_ic);
};
#endif
diff --git a/include/linux/dma-buf.h b/include/linux/dma-buf.h
index db91c67c00d6..3e6124387f3c 100644
--- a/include/linux/dma-buf.h
+++ b/include/linux/dma-buf.h
@@ -479,6 +479,10 @@ struct dma_buf_attach_ops {
* point to the new location of the DMA-buf.
*/
void (*move_notify)(struct dma_buf_attachment *attach);
+
+ bool (*supports_interconnects)(struct dma_buf_attachment *attach,
+ const struct dma_buf_interconnect_match *,
+ unsigned int num_ics);
};
/**
@@ -599,6 +603,11 @@ void dma_buf_unmap_attachment(struct dma_buf_attachment *, struct sg_table *,
struct dma_buf_ranges *dma_buf_map_interconnect(struct dma_buf_attachment *);
void dma_buf_unmap_interconnect(struct dma_buf_attachment *,
struct dma_buf_ranges *);
+bool dma_buf_match_interconnects(struct dma_buf_attachment *attach,
+ const struct dma_buf_interconnect_match *,
+ unsigned int exp_ics,
+ const struct dma_buf_interconnect_match *,
+ unsigned int imp_ics);
void dma_buf_move_notify(struct dma_buf *dma_buf);
int dma_buf_begin_cpu_access(struct dma_buf *dma_buf,
--
2.50.1
^ permalink raw reply related [flat|nested] 16+ messages in thread* RE: [RFC 2/8] dma-buf: Add a helper to match interconnects between exporter/importer
2025-10-14 7:08 ` [RFC 2/8] dma-buf: Add a helper to match interconnects between exporter/importer Vivek Kasireddy
@ 2025-10-17 15:58 ` Kasireddy, Vivek
0 siblings, 0 replies; 16+ messages in thread
From: Kasireddy, Vivek @ 2025-10-17 15:58 UTC (permalink / raw)
To: Jason Gunthorpe, Christian Koenig, Thomas Hellström
Cc: Simona Vetter, Sumit Semwal, dri-devel@lists.freedesktop.org,
intel-xe@lists.freedesktop.org, linux-media@vger.kernel.org,
linaro-mm-sig@lists.linaro.org
Hi Jason, Thomas, Christian,
> If the importer provides an op for supports_interconnects(), the
> exporter starts the matching (or negotiation) process (during
> attach) by invoking the supports_interconnects() which would then
> call this helper to identify the first common interconnect
> supported by both exporter and importer.
>
> Note that whether an interconnect is supported between an
> exporter/importer is ultimately determined by the exporter via
> the match op it is expected to provide.
Does this design look OK to you?
Thanks,
Vivek
>
> Cc: Jason Gunthorpe <jgg@nvidia.com>
> Cc: Christian Koenig <christian.koenig@amd.com>
> Cc: Sumit Semwal <sumit.semwal@linaro.org>
> Cc: Thomas Hellström <thomas.hellstrom@linux.intel.com>
> Cc: Simona Vetter <simona.vetter@ffwll.ch>
> Signed-off-by: Vivek Kasireddy <vivek.kasireddy@intel.com>
> ---
> drivers/dma-buf/dma-buf.c | 45 +++++++++++++++++++++++++++-
> include/linux/dma-buf-interconnect.h | 6 ++++
> include/linux/dma-buf.h | 9 ++++++
> 3 files changed, 59 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c
> index 162642bd53e8..ed48540d1c1d 100644
> --- a/drivers/dma-buf/dma-buf.c
> +++ b/drivers/dma-buf/dma-buf.c
> @@ -965,8 +965,11 @@ dma_buf_dynamic_attach(struct dma_buf *dmabuf,
> struct device *dev,
>
> attach->dev = dev;
> attach->dmabuf = dmabuf;
> - if (importer_ops)
> + if (importer_ops) {
> attach->peer2peer = importer_ops->allow_peer2peer;
> + if (importer_ops->supports_interconnects)
> + attach->allow_ic = true;
> + }
> attach->importer_ops = importer_ops;
> attach->importer_priv = importer_priv;
>
> @@ -1680,6 +1683,46 @@ void dma_buf_unmap_interconnect(struct
> dma_buf_attachment *attach,
> }
> EXPORT_SYMBOL_NS_GPL(dma_buf_unmap_interconnect, "DMA_BUF");
>
> +bool dma_buf_match_interconnects(struct dma_buf_attachment *attach,
> + const struct dma_buf_interconnect_match
> *exp,
> + unsigned int exp_ics,
> + const struct dma_buf_interconnect_match
> *imp,
> + unsigned int imp_ics)
> +{
> + const struct dma_buf_interconnect *exp_ic, *imp_ic;
> + const struct dma_buf_interconnect_ops *ic_ops;
> + struct dma_buf *dmabuf = attach->dmabuf;
> + unsigned int i, j;
> +
> + if (!exp || !imp)
> + return false;
> +
> + if (!attach->allow_ic)
> + return false;
> +
> + ic_ops = dmabuf->ops->interconnect_ops;
> + if (!ic_ops || !ic_ops->match_interconnect)
> + return false;
> +
> + for (i = 0; i < exp_ics; i++) {
> + for (j = 0; j < imp_ics; j++) {
> + exp_ic = exp[i].interconnect;
> + imp_ic = imp[j].interconnect;
> +
> + if (exp_ic->type == imp_ic->type) {
> + if (ic_ops->match_interconnect(exp_ic, imp_ic)) {
> + attach->interconnect.type = exp_ic-
> >type;
> + return true;
> + }
> + }
> + }
> + }
> +
> + attach->allow_ic = false;
> + return false;
> +}
> +EXPORT_SYMBOL_NS_GPL(dma_buf_match_interconnects, "DMA_BUF");
> +
> #ifdef CONFIG_DEBUG_FS
> static int dma_buf_debug_show(struct seq_file *s, void *unused)
> {
> diff --git a/include/linux/dma-buf-interconnect.h b/include/linux/dma-buf-
> interconnect.h
> index 17504dea9691..a72f65ed4806 100644
> --- a/include/linux/dma-buf-interconnect.h
> +++ b/include/linux/dma-buf-interconnect.h
> @@ -20,10 +20,16 @@ struct dma_buf_interconnect {
> enum dma_buf_interconnect_type type;
> };
>
> +struct dma_buf_interconnect_match {
> + const struct dma_buf_interconnect *interconnect;
> +};
> +
> struct dma_buf_interconnect_ops {
> int (*map_interconnect)(struct dma_buf_attachment *attach,
> struct dma_buf_ranges *ranges);
> void (*unmap_interconnect)(struct dma_buf_attachment *attach,
> struct dma_buf_ranges *ranges);
> + bool (*match_interconnect)(const struct dma_buf_interconnect
> *exp_ic,
> + const struct dma_buf_interconnect *imp_ic);
> };
> #endif
> diff --git a/include/linux/dma-buf.h b/include/linux/dma-buf.h
> index db91c67c00d6..3e6124387f3c 100644
> --- a/include/linux/dma-buf.h
> +++ b/include/linux/dma-buf.h
> @@ -479,6 +479,10 @@ struct dma_buf_attach_ops {
> * point to the new location of the DMA-buf.
> */
> void (*move_notify)(struct dma_buf_attachment *attach);
> +
> + bool (*supports_interconnects)(struct dma_buf_attachment *attach,
> + const struct dma_buf_interconnect_match *,
> + unsigned int num_ics);
> };
>
> /**
> @@ -599,6 +603,11 @@ void dma_buf_unmap_attachment(struct
> dma_buf_attachment *, struct sg_table *,
> struct dma_buf_ranges *dma_buf_map_interconnect(struct
> dma_buf_attachment *);
> void dma_buf_unmap_interconnect(struct dma_buf_attachment *,
> struct dma_buf_ranges *);
> +bool dma_buf_match_interconnects(struct dma_buf_attachment *attach,
> + const struct dma_buf_interconnect_match *,
> + unsigned int exp_ics,
> + const struct dma_buf_interconnect_match *,
> + unsigned int imp_ics);
>
> void dma_buf_move_notify(struct dma_buf *dma_buf);
> int dma_buf_begin_cpu_access(struct dma_buf *dma_buf,
> --
> 2.50.1
^ permalink raw reply [flat|nested] 16+ messages in thread
* [RFC 3/8] dma-buf: Add support for IOV interconnect
2025-10-14 7:08 [RFC 0/8] dma-buf: Add support for mapping dmabufs via interconnects Vivek Kasireddy
2025-10-14 7:08 ` [RFC 1/8] dma-buf: Add support for map/unmap APIs for interconnects Vivek Kasireddy
2025-10-14 7:08 ` [RFC 2/8] dma-buf: Add a helper to match interconnects between exporter/importer Vivek Kasireddy
@ 2025-10-14 7:08 ` Vivek Kasireddy
2025-10-14 7:08 ` [RFC 4/8] vfio/pci/dmabuf: " Vivek Kasireddy
` (4 subsequent siblings)
7 siblings, 0 replies; 16+ messages in thread
From: Vivek Kasireddy @ 2025-10-14 7:08 UTC (permalink / raw)
To: dri-devel, intel-xe, linux-media, linaro-mm-sig
Cc: Vivek Kasireddy, Jason Gunthorpe, Christian Koenig, Sumit Semwal,
Thomas Hellström, Simona Vetter
The IOV interconnect is a virtual interconnect between an SRIOV
physical function (PF) and its virtual functions (VFs). In order
for negotiation (or match) to succeed, the exporter is expected
to be a VF while the importer is expected to be the PF.
Cc: Jason Gunthorpe <jgg@nvidia.com>
Cc: Christian Koenig <christian.koenig@amd.com>
Cc: Sumit Semwal <sumit.semwal@linaro.org>
Cc: Thomas Hellström <thomas.hellstrom@linux.intel.com>
Cc: Simona Vetter <simona.vetter@ffwll.ch>
Signed-off-by: Vivek Kasireddy <vivek.kasireddy@intel.com>
---
include/linux/dma-buf-interconnect.h | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/include/linux/dma-buf-interconnect.h b/include/linux/dma-buf-interconnect.h
index a72f65ed4806..b569dcab86ce 100644
--- a/include/linux/dma-buf-interconnect.h
+++ b/include/linux/dma-buf-interconnect.h
@@ -3,8 +3,17 @@
#ifndef __DMA_BUF_INTERCONNECT_H__
#define __DMA_BUF_INTERCONNECT_H__
+#include <linux/pci.h>
#include <linux/xarray.h>
+#define CREATE_IOV_INTERCONNECT(pdev, bar) { \
+ &(const struct dma_buf_iov_interconnect) { \
+ .base.type = DMA_BUF_INTERCONNECT_IOV, \
+ .pdev = (pdev), \
+ .bar = (bar), \
+ }.base \
+}
+
struct dma_buf_attachment;
struct dma_buf_ranges {
@@ -14,6 +23,7 @@ struct dma_buf_ranges {
enum dma_buf_interconnect_type {
DMA_BUF_INTERCONNECT_NONE = 0,
+ DMA_BUF_INTERCONNECT_IOV,
};
struct dma_buf_interconnect {
@@ -24,6 +34,12 @@ struct dma_buf_interconnect_match {
const struct dma_buf_interconnect *interconnect;
};
+struct dma_buf_iov_interconnect {
+ struct dma_buf_interconnect base;
+ struct pci_dev *pdev;
+ unsigned int bar;
+};
+
struct dma_buf_interconnect_ops {
int (*map_interconnect)(struct dma_buf_attachment *attach,
struct dma_buf_ranges *ranges);
--
2.50.1
^ permalink raw reply related [flat|nested] 16+ messages in thread* [RFC 4/8] vfio/pci/dmabuf: Add support for IOV interconnect
2025-10-14 7:08 [RFC 0/8] dma-buf: Add support for mapping dmabufs via interconnects Vivek Kasireddy
` (2 preceding siblings ...)
2025-10-14 7:08 ` [RFC 3/8] dma-buf: Add support for IOV interconnect Vivek Kasireddy
@ 2025-10-14 7:08 ` Vivek Kasireddy
2025-10-14 7:08 ` [RFC 5/8] drm/xe/dma_buf: " Vivek Kasireddy
` (3 subsequent siblings)
7 siblings, 0 replies; 16+ messages in thread
From: Vivek Kasireddy @ 2025-10-14 7:08 UTC (permalink / raw)
To: dri-devel, intel-xe, linux-media, linaro-mm-sig
Cc: Vivek Kasireddy, Jason Gunthorpe, Christian Koenig, Sumit Semwal,
Thomas Hellström, Simona Vetter
Add support for IOV interconnect by provding ops for map/unmap and
match interconnect. Note that the xarray is populated with entries
of type struct range. The range struct contains the start and end
address of the memory region.
Cc: Jason Gunthorpe <jgg@nvidia.com>
Cc: Christian Koenig <christian.koenig@amd.com>
Cc: Sumit Semwal <sumit.semwal@linaro.org>
Cc: Thomas Hellström <thomas.hellstrom@linux.intel.com>
Cc: Simona Vetter <simona.vetter@ffwll.ch>
Signed-off-by: Vivek Kasireddy <vivek.kasireddy@intel.com>
---
drivers/vfio/pci/vfio_pci_dmabuf.c | 141 ++++++++++++++++++++++++++++-
1 file changed, 140 insertions(+), 1 deletion(-)
diff --git a/drivers/vfio/pci/vfio_pci_dmabuf.c b/drivers/vfio/pci/vfio_pci_dmabuf.c
index eaba010777f3..c45c1a7923f8 100644
--- a/drivers/vfio/pci/vfio_pci_dmabuf.c
+++ b/drivers/vfio/pci/vfio_pci_dmabuf.c
@@ -4,6 +4,7 @@
#include <linux/dma-buf.h>
#include <linux/pci-p2pdma.h>
#include <linux/dma-resv.h>
+#include <linux/range.h>
#include "vfio_pci_priv.h"
@@ -16,15 +17,138 @@ struct vfio_pci_dma_buf {
size_t size;
struct phys_vec *phys_vec;
struct p2pdma_provider *provider;
+ struct dma_buf_iov_interconnect *iov_ic;
u32 nr_ranges;
u8 revoked : 1;
};
+static int
+vfio_pci_create_iov_match(struct vfio_pci_dma_buf *priv,
+ struct vfio_device_feature_dma_buf *dma_buf)
+{
+ struct dma_buf_iov_interconnect *iov_ic;
+
+ iov_ic = kzalloc(sizeof(*iov_ic), GFP_KERNEL);
+ if (!iov_ic)
+ return -ENOMEM;
+
+ iov_ic->base.type = DMA_BUF_INTERCONNECT_IOV;
+ iov_ic->pdev = priv->vdev->pdev;
+ iov_ic->bar = dma_buf->region_index;
+
+ priv->iov_ic = iov_ic;
+ return 0;
+}
+
+static int vfio_pci_map_iov_interconnect(struct vfio_pci_dma_buf *priv,
+ struct xarray *ranges)
+{
+ struct phys_vec *phys_vec = priv->phys_vec;
+ struct range *range;
+ unsigned long i;
+ void *entry;
+ int ret;
+
+ range = kmalloc_array(priv->nr_ranges, sizeof(*range), GFP_KERNEL);
+ if (!range)
+ return -ENOMEM;
+
+ for (i = 0; i < priv->nr_ranges; i++) {
+ entry = &range[i];
+ range[i].start = phys_vec[i].paddr;
+ range[i].end = phys_vec[i].paddr + phys_vec[i].len - 1;
+
+ entry = xa_store(ranges, i, entry, GFP_KERNEL);
+ if (xa_is_err(entry)) {
+ ret = xa_err(entry);
+ goto err_free_range;
+ }
+ }
+ return 0;
+
+err_free_range:
+ kfree(range);
+ return ret;
+}
+
+static int vfio_pci_map_interconnect(struct dma_buf_attachment *attachment,
+ struct dma_buf_ranges *ranges)
+{
+ enum dma_buf_interconnect_type type = attachment->interconnect.type;
+ struct vfio_pci_dma_buf *priv = attachment->dmabuf->priv;
+ int ret = -EINVAL;
+
+ ranges->nranges = priv->nr_ranges;
+
+ if (type == DMA_BUF_INTERCONNECT_IOV)
+ ret = vfio_pci_map_iov_interconnect(priv, &ranges->ranges);
+ return ret;
+}
+
+static void vfio_pci_unmap_interconnect(struct dma_buf_attachment *attachment,
+ struct dma_buf_ranges *ranges)
+{
+ void *entry;
+
+ entry = xa_load(&ranges->ranges, 0);
+ kfree(entry);
+}
+
+static bool
+vfio_pci_match_iov_interconnect(const struct dma_buf_interconnect *exp,
+ const struct dma_buf_interconnect *imp)
+{
+ const struct dma_buf_iov_interconnect *exp_ic =
+ container_of(exp, struct dma_buf_iov_interconnect, base);
+ const struct dma_buf_iov_interconnect *imp_ic =
+ container_of(imp, struct dma_buf_iov_interconnect, base);
+
+ return imp_ic->pdev == pci_physfn(exp_ic->pdev) &&
+ imp_ic->bar == exp_ic->bar;
+}
+
+static bool
+vfio_pci_match_interconnect(const struct dma_buf_interconnect *exp,
+ const struct dma_buf_interconnect *imp)
+{
+ enum dma_buf_interconnect_type type = exp->type;
+
+ switch (type) {
+ case DMA_BUF_INTERCONNECT_IOV:
+ return vfio_pci_match_iov_interconnect(exp, imp);
+ default:
+ return false;
+ }
+}
+
+static bool
+vfio_pci_match_interconnects(struct vfio_pci_dma_buf *priv,
+ struct dma_buf_attachment *attachment)
+{
+ const struct dma_buf_attach_ops *aops = attachment->importer_ops;
+ struct pci_dev *pdev = priv->vdev->pdev;
+ unsigned int bar = priv->iov_ic->bar;
+ const struct dma_buf_interconnect_match supports_ics[] = {
+ CREATE_IOV_INTERCONNECT(pdev, bar),
+ };
+
+ if (attachment->allow_ic) {
+ if (aops->supports_interconnects(attachment, supports_ics,
+ ARRAY_SIZE(supports_ics)))
+ return true;
+ }
+ return false;
+}
+
static int vfio_pci_dma_buf_attach(struct dma_buf *dmabuf,
struct dma_buf_attachment *attachment)
{
struct vfio_pci_dma_buf *priv = dmabuf->priv;
+ if (vfio_pci_match_interconnects(priv, attachment)) {
+ return 0;
+ }
+
if (!attachment->peer2peer)
return -EOPNOTSUPP;
@@ -189,6 +313,7 @@ vfio_pci_dma_buf_map(struct dma_buf_attachment *attachment,
return ERR_PTR(ret);
}
+
static void vfio_pci_dma_buf_unmap(struct dma_buf_attachment *attachment,
struct sg_table *sgt,
enum dma_data_direction dir)
@@ -228,15 +353,23 @@ static void vfio_pci_dma_buf_release(struct dma_buf *dmabuf)
vfio_device_put_registration(&priv->vdev->vdev);
}
kfree(priv->phys_vec);
+ kfree(priv->iov_ic);
kfree(priv);
}
+static const struct dma_buf_interconnect_ops vfio_pci_interconnect_ops = {
+ .match_interconnect = vfio_pci_match_interconnect,
+ .map_interconnect = vfio_pci_map_interconnect,
+ .unmap_interconnect = vfio_pci_unmap_interconnect,
+};
+
static const struct dma_buf_ops vfio_pci_dmabuf_ops = {
.attach = vfio_pci_dma_buf_attach,
.detach = vfio_pci_dma_buf_detach,
.map_dma_buf = vfio_pci_dma_buf_map,
.release = vfio_pci_dma_buf_release,
.unmap_dma_buf = vfio_pci_dma_buf_unmap,
+ .interconnect_ops = &vfio_pci_interconnect_ops,
};
static void dma_ranges_to_p2p_phys(struct vfio_pci_dma_buf *priv,
@@ -365,6 +498,10 @@ int vfio_pci_core_feature_dma_buf(struct vfio_pci_core_device *vdev, u32 flags,
goto err_free_phys;
}
+ ret = vfio_pci_create_iov_match(priv, &get_dma_buf);
+ if (ret)
+ goto err_dev_put;
+
exp_info.ops = &vfio_pci_dmabuf_ops;
exp_info.size = priv->size;
exp_info.flags = get_dma_buf.open_flags;
@@ -373,7 +510,7 @@ int vfio_pci_core_feature_dma_buf(struct vfio_pci_core_device *vdev, u32 flags,
priv->dmabuf = dma_buf_export(&exp_info);
if (IS_ERR(priv->dmabuf)) {
ret = PTR_ERR(priv->dmabuf);
- goto err_dev_put;
+ goto err_free_iov;
}
/* dma_buf_put() now frees priv */
@@ -391,6 +528,8 @@ int vfio_pci_core_feature_dma_buf(struct vfio_pci_core_device *vdev, u32 flags,
*/
return dma_buf_fd(priv->dmabuf, get_dma_buf.open_flags);
+err_free_iov:
+ kfree(priv->iov_ic);
err_dev_put:
vfio_device_put_registration(&vdev->vdev);
err_free_phys:
--
2.50.1
^ permalink raw reply related [flat|nested] 16+ messages in thread* [RFC 5/8] drm/xe/dma_buf: Add support for IOV interconnect
2025-10-14 7:08 [RFC 0/8] dma-buf: Add support for mapping dmabufs via interconnects Vivek Kasireddy
` (3 preceding siblings ...)
2025-10-14 7:08 ` [RFC 4/8] vfio/pci/dmabuf: " Vivek Kasireddy
@ 2025-10-14 7:08 ` Vivek Kasireddy
2025-10-14 7:08 ` [RFC 6/8] drm/xe/pf: Add a helper function to get a VF's backing object in LMEM Vivek Kasireddy
` (2 subsequent siblings)
7 siblings, 0 replies; 16+ messages in thread
From: Vivek Kasireddy @ 2025-10-14 7:08 UTC (permalink / raw)
To: dri-devel, intel-xe, linux-media, linaro-mm-sig
Cc: Vivek Kasireddy, Jason Gunthorpe, Christian Koenig, Sumit Semwal,
Thomas Hellström, Simona Vetter
Provide an op for supports_interconnects() to indicate to the
dma-buf core and to the exporter that Xe supports interconnects.
Note that Xe would support IOV interconnect only if the buffer
is located in LMEM region.
Cc: Jason Gunthorpe <jgg@nvidia.com>
Cc: Christian Koenig <christian.koenig@amd.com>
Cc: Sumit Semwal <sumit.semwal@linaro.org>
Cc: Thomas Hellström <thomas.hellstrom@linux.intel.com>
Cc: Simona Vetter <simona.vetter@ffwll.ch>
Signed-off-by: Vivek Kasireddy <vivek.kasireddy@intel.com>
---
drivers/gpu/drm/xe/xe_dma_buf.c | 19 ++++++++++++++++++-
1 file changed, 18 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/xe/xe_dma_buf.c b/drivers/gpu/drm/xe/xe_dma_buf.c
index a7d67725c3ee..2d63dd86a249 100644
--- a/drivers/gpu/drm/xe/xe_dma_buf.c
+++ b/drivers/gpu/drm/xe/xe_dma_buf.c
@@ -13,6 +13,7 @@
#include <drm/drm_prime.h>
#include <drm/ttm/ttm_tt.h>
+#include "regs/xe_bars.h"
#include "tests/xe_test.h"
#include "xe_bo.h"
#include "xe_device.h"
@@ -274,9 +275,25 @@ static void xe_dma_buf_move_notify(struct dma_buf_attachment *attach)
XE_WARN_ON(xe_bo_evict(bo, exec));
}
+static bool
+xe_dma_buf_supports_interconnects(struct dma_buf_attachment *attach,
+ const struct dma_buf_interconnect_match *exp,
+ unsigned int exp_ics)
+{
+ struct pci_dev *pdev = to_pci_dev(attach->dev);
+ unsigned int bar = LMEM_BAR;
+ const struct dma_buf_interconnect_match supports_ics[] = {
+ CREATE_IOV_INTERCONNECT(pdev, bar),
+ };
+
+ return dma_buf_match_interconnects(attach, exp, exp_ics, supports_ics,
+ ARRAY_SIZE(supports_ics));
+}
+
static const struct dma_buf_attach_ops xe_dma_buf_attach_ops = {
.allow_peer2peer = true,
- .move_notify = xe_dma_buf_move_notify
+ .move_notify = xe_dma_buf_move_notify,
+ .supports_interconnects = xe_dma_buf_supports_interconnects,
};
#if IS_ENABLED(CONFIG_DRM_XE_KUNIT_TEST)
--
2.50.1
^ permalink raw reply related [flat|nested] 16+ messages in thread* [RFC 6/8] drm/xe/pf: Add a helper function to get a VF's backing object in LMEM
2025-10-14 7:08 [RFC 0/8] dma-buf: Add support for mapping dmabufs via interconnects Vivek Kasireddy
` (4 preceding siblings ...)
2025-10-14 7:08 ` [RFC 5/8] drm/xe/dma_buf: " Vivek Kasireddy
@ 2025-10-14 7:08 ` Vivek Kasireddy
2025-10-14 7:08 ` [RFC 7/8] drm/xe/bo: Create new dma_addr array for dmabuf BOs associated with VFs Vivek Kasireddy
2025-10-14 7:08 ` [RFC 8/8] drm/xe/pt: Add an additional check for dmabuf BOs while doing bind Vivek Kasireddy
7 siblings, 0 replies; 16+ messages in thread
From: Vivek Kasireddy @ 2025-10-14 7:08 UTC (permalink / raw)
To: dri-devel, intel-xe, linux-media, linaro-mm-sig; +Cc: Vivek Kasireddy
To properly import a dmabuf that is associated with a VF (or that
originates in a Guest VM that includes a VF), we need to know where
in LMEM the VF's allocated regions exist. Therefore, introduce a
new helper to return the object that backs the VF's regions in LMEM.
v2:
- Make the helper return the LMEM object instead of the start address
v3:
- Move the declaration of the helper under other lmem helpers (Michal)
Signed-off-by: Vivek Kasireddy <vivek.kasireddy@intel.com>
---
drivers/gpu/drm/xe/xe_gt_sriov_pf_config.c | 23 ++++++++++++++++++++++
drivers/gpu/drm/xe/xe_gt_sriov_pf_config.h | 1 +
2 files changed, 24 insertions(+)
diff --git a/drivers/gpu/drm/xe/xe_gt_sriov_pf_config.c b/drivers/gpu/drm/xe/xe_gt_sriov_pf_config.c
index 6344b5205c08..1bfcd35cc8ef 100644
--- a/drivers/gpu/drm/xe/xe_gt_sriov_pf_config.c
+++ b/drivers/gpu/drm/xe/xe_gt_sriov_pf_config.c
@@ -1535,6 +1535,29 @@ u64 xe_gt_sriov_pf_config_get_lmem(struct xe_gt *gt, unsigned int vfid)
return size;
}
+/**
+ * xe_gt_sriov_pf_config_get_lmem_obj - Get VF's LMEM BO.
+ * @gt: the &xe_gt
+ * @vfid: the VF identifier
+ *
+ * This function can only be called on PF.
+ *
+ * Return: BO that is backing VF's quota in LMEM.
+ */
+struct xe_bo *xe_gt_sriov_pf_config_get_lmem_obj(struct xe_gt *gt,
+ unsigned int vfid)
+{
+ struct xe_gt_sriov_config *config;
+ struct xe_bo *lmem_obj;
+
+ mutex_lock(xe_gt_sriov_pf_master_mutex(gt));
+ config = pf_pick_vf_config(gt, vfid);
+ lmem_obj = config->lmem_obj;
+ mutex_unlock(xe_gt_sriov_pf_master_mutex(gt));
+
+ return lmem_obj;
+}
+
/**
* xe_gt_sriov_pf_config_set_lmem - Provision VF with LMEM.
* @gt: the &xe_gt (can't be media)
diff --git a/drivers/gpu/drm/xe/xe_gt_sriov_pf_config.h b/drivers/gpu/drm/xe/xe_gt_sriov_pf_config.h
index 513e6512a575..bbc5c238cbf6 100644
--- a/drivers/gpu/drm/xe/xe_gt_sriov_pf_config.h
+++ b/drivers/gpu/drm/xe/xe_gt_sriov_pf_config.h
@@ -36,6 +36,7 @@ int xe_gt_sriov_pf_config_set_lmem(struct xe_gt *gt, unsigned int vfid, u64 size
int xe_gt_sriov_pf_config_set_fair_lmem(struct xe_gt *gt, unsigned int vfid, unsigned int num_vfs);
int xe_gt_sriov_pf_config_bulk_set_lmem(struct xe_gt *gt, unsigned int vfid, unsigned int num_vfs,
u64 size);
+struct xe_bo *xe_gt_sriov_pf_config_get_lmem_obj(struct xe_gt *gt, unsigned int vfid);
u32 xe_gt_sriov_pf_config_get_exec_quantum(struct xe_gt *gt, unsigned int vfid);
int xe_gt_sriov_pf_config_set_exec_quantum(struct xe_gt *gt, unsigned int vfid, u32 exec_quantum);
--
2.50.1
^ permalink raw reply related [flat|nested] 16+ messages in thread* [RFC 7/8] drm/xe/bo: Create new dma_addr array for dmabuf BOs associated with VFs
2025-10-14 7:08 [RFC 0/8] dma-buf: Add support for mapping dmabufs via interconnects Vivek Kasireddy
` (5 preceding siblings ...)
2025-10-14 7:08 ` [RFC 6/8] drm/xe/pf: Add a helper function to get a VF's backing object in LMEM Vivek Kasireddy
@ 2025-10-14 7:08 ` Vivek Kasireddy
2025-10-14 7:08 ` [RFC 8/8] drm/xe/pt: Add an additional check for dmabuf BOs while doing bind Vivek Kasireddy
7 siblings, 0 replies; 16+ messages in thread
From: Vivek Kasireddy @ 2025-10-14 7:08 UTC (permalink / raw)
To: dri-devel, intel-xe, linux-media, linaro-mm-sig
Cc: Vivek Kasireddy, Matthew Brost, Thomas Hellström
For BOs of type ttm_bo_type_sg, that are backed by PCI BAR addresses
associated with a VF, we need to adjust and translate these addresses
to LMEM addresses to make the BOs usable by the PF. Otherwise, the
BOs (i.e, PCI BAR addresses) are only accessible by the CPU and not
by the GPU.
In order to do the above, we first need to identify if the addresses
associated with an imported BO (type ttm_bo_type_sg) belong to System
RAM or a VF or other PCI devices. After we confirm that they belong to
a VF, we convert the BAR addresses to DPAs and create a new dma_addr
array (of type drm_pagemap_dma_addr) and populate it with the new
addresses along with the segment sizes.
Note that, all the above is only done if we are able to map the
dmabuf via the IOV interconnect. If not, we fallback to the legacy
mapping route using the sg table.
v2:
- Use dma_addr array instead of sg table to store translated addresses
(Matt)
v3:
- Remove the usage of iommu_iova_to_phys() as the imported BO would no
longer contain IOVAs and would instead have BAR addresses.
v4:
- Take a reference on the VF's backing object in LMEM (Michal)
- Create a new type for storing dma data
Cc: Matthew Brost <matthew.brost@intel.com>
Cc: Thomas Hellström <thomas.hellstrom@linux.intel.com>
Signed-off-by: Vivek Kasireddy <vivek.kasireddy@intel.com>
---
drivers/gpu/drm/xe/xe_bo.c | 148 +++++++++++++++++++++++--
drivers/gpu/drm/xe/xe_bo_types.h | 12 ++
drivers/gpu/drm/xe/xe_sriov_pf_types.h | 19 ++++
3 files changed, 167 insertions(+), 12 deletions(-)
diff --git a/drivers/gpu/drm/xe/xe_bo.c b/drivers/gpu/drm/xe/xe_bo.c
index 4410e28dee54..e05b7eace784 100644
--- a/drivers/gpu/drm/xe/xe_bo.c
+++ b/drivers/gpu/drm/xe/xe_bo.c
@@ -21,11 +21,13 @@
#include <trace/events/gpu_mem.h>
+#include "regs/xe_bars.h"
#include "xe_device.h"
#include "xe_dma_buf.h"
#include "xe_drm_client.h"
#include "xe_ggtt.h"
#include "xe_gt.h"
+#include "xe_gt_sriov_pf_config.h"
#include "xe_map.h"
#include "xe_migrate.h"
#include "xe_pm.h"
@@ -34,6 +36,7 @@
#include "xe_res_cursor.h"
#include "xe_shrinker.h"
#include "xe_sriov_vf_ccs.h"
+#include "xe_sriov_pf_helpers.h"
#include "xe_trace_bo.h"
#include "xe_ttm_stolen_mgr.h"
#include "xe_vm.h"
@@ -679,6 +682,99 @@ static int xe_bo_trigger_rebind(struct xe_device *xe, struct xe_bo *bo,
return ret;
}
+static struct pci_dev *xe_find_vf_dev(struct xe_device *xe,
+ phys_addr_t phys)
+{
+ struct pci_dev *pdev, *pf_pdev = to_pci_dev(xe->drm.dev);
+ resource_size_t io_start, io_size;
+
+ list_for_each_entry(pdev, &pf_pdev->bus->devices, bus_list) {
+ if (pdev->is_physfn)
+ continue;
+
+ io_start = pci_resource_start(pdev, LMEM_BAR);
+ io_size = pci_resource_len(pdev, LMEM_BAR);
+
+ if (phys >= io_start &&
+ phys < (io_start + io_size - PAGE_SIZE))
+ return pdev;
+ }
+
+ return NULL;
+}
+
+static void xe_bo_translate_io_xarray_to_dpa(struct xe_bo *bo,
+ struct xarray *ranges,
+ resource_size_t io_start,
+ int vfid)
+{
+ struct xe_device *xe = xe_bo_device(bo);
+ struct xe_gt *gt = xe_root_mmio_gt(xe);
+ struct xe_bo *lmem_obj;
+ struct range *range;
+ phys_addr_t phys;
+ unsigned long i;
+ dma_addr_t addr;
+ u64 offset;
+ void *entry;
+
+ lmem_obj = xe_gt_sriov_pf_config_get_lmem_obj(gt, ++vfid);
+ bo->dma_data.lmem_obj = xe_bo_get(lmem_obj);
+
+ xa_for_each(ranges, i, entry) {
+ range = entry;
+ phys = range->start;
+ offset = phys - io_start;
+ addr = xe_bo_addr(lmem_obj, offset, range_len(range));
+
+ bo->dma_data.dma_addr[i] = drm_pagemap_addr_encode(addr,
+ DRM_INTERCONNECT_DRIVER,
+ get_order(range_len(range)),
+ DMA_BIDIRECTIONAL);
+ }
+}
+
+
+static int xe_bo_xarray_to_dma_addr(struct dma_buf_ranges *ranges,
+ struct xe_bo *bo)
+{
+ struct xe_device *xe = xe_bo_device(bo);
+ struct drm_pagemap_addr *dma_addr;
+ resource_size_t io_start;
+ struct pci_dev *pdev;
+ struct range *range;
+ void *entry;
+ int vfid;
+
+ if (!IS_SRIOV_PF(xe))
+ return 0;
+
+ entry = xa_load(&ranges->ranges, 0);
+ range = entry;
+ if (page_is_ram(PFN_DOWN(range->start)))
+ return 0;
+
+ pdev = xe_find_vf_dev(xe, range->start);
+ if (!pdev)
+ return 0;
+
+ vfid = pci_iov_vf_id(pdev);
+ if (vfid < 0)
+ return 0;
+
+ dma_addr = kmalloc_array(ranges->nranges, sizeof(*dma_addr),
+ GFP_KERNEL);
+ if (!dma_addr)
+ return -ENOMEM;
+
+ bo->is_devmem_external = true;
+ bo->dma_data.dma_addr = dma_addr;
+ io_start = pci_resource_start(pdev, LMEM_BAR);
+ xe_bo_translate_io_xarray_to_dpa(bo, &ranges->ranges, io_start, vfid);
+
+ return 0;
+}
+
/*
* The dma-buf map_attachment() / unmap_attachment() is hooked up here.
* Note that unmapping the attachment is deferred to the next
@@ -696,7 +792,10 @@ static int xe_bo_move_dmabuf(struct ttm_buffer_object *ttm_bo,
ttm);
struct xe_device *xe = ttm_to_xe_device(ttm_bo->bdev);
bool device_unplugged = drm_dev_is_unplugged(&xe->drm);
- struct sg_table *sg;
+ struct dma_buf_ranges *ranges;
+ struct sg_table *sg = NULL;
+ bool allow_ic = false;
+ int ret = 0;
xe_assert(xe, attach);
xe_assert(xe, ttm_bo->ttm);
@@ -717,9 +816,27 @@ static int xe_bo_move_dmabuf(struct ttm_buffer_object *ttm_bo,
ttm_bo->sg = NULL;
}
- sg = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL);
- if (IS_ERR(sg))
- return PTR_ERR(sg);
+ if (attach->allow_ic &&
+ attach->interconnect.type == DMA_BUF_INTERCONNECT_IOV) {
+ allow_ic = true;
+
+ ranges = dma_buf_map_interconnect(attach);
+ if (IS_ERR(ranges)) {
+ allow_ic = false;
+ } else {
+ if (xe_bo_xarray_to_dma_addr(ranges,
+ ttm_to_xe_bo(ttm_bo))) {
+ dma_buf_unmap_interconnect(attach, ranges);
+ allow_ic = false;
+ }
+ }
+ attach->allow_ic = allow_ic;
+ }
+ if (!allow_ic) {
+ sg = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL);
+ if (IS_ERR(sg))
+ return PTR_ERR(sg);
+ }
ttm_bo->sg = sg;
xe_tt->sg = sg;
@@ -727,7 +844,7 @@ static int xe_bo_move_dmabuf(struct ttm_buffer_object *ttm_bo,
out:
ttm_bo_move_null(ttm_bo, new_res);
- return 0;
+ return ret;
}
/**
@@ -1548,14 +1665,21 @@ static void xe_ttm_bo_delete_mem_notify(struct ttm_buffer_object *ttm_bo)
* Object is idle and about to be destroyed. Release the
* dma-buf attachment.
*/
- if (ttm_bo->type == ttm_bo_type_sg && ttm_bo->sg) {
- struct xe_ttm_tt *xe_tt = container_of(ttm_bo->ttm,
- struct xe_ttm_tt, ttm);
+ if (ttm_bo->type == ttm_bo_type_sg) {
+ if (ttm_bo->sg) {
+ struct xe_ttm_tt *xe_tt = container_of(ttm_bo->ttm,
+ struct xe_ttm_tt,
+ ttm);
- dma_buf_unmap_attachment(ttm_bo->base.import_attach, ttm_bo->sg,
- DMA_BIDIRECTIONAL);
- ttm_bo->sg = NULL;
- xe_tt->sg = NULL;
+ dma_buf_unmap_attachment(ttm_bo->base.import_attach,
+ ttm_bo->sg, DMA_BIDIRECTIONAL);
+ ttm_bo->sg = NULL;
+ xe_tt->sg = NULL;
+ }
+ if (bo->is_devmem_external) {
+ xe_bo_put(bo->dma_data.lmem_obj);
+ kfree(bo->dma_data.dma_addr);
+ }
}
}
diff --git a/drivers/gpu/drm/xe/xe_bo_types.h b/drivers/gpu/drm/xe/xe_bo_types.h
index d4fe3c8dca5b..8e416c4ffbca 100644
--- a/drivers/gpu/drm/xe/xe_bo_types.h
+++ b/drivers/gpu/drm/xe/xe_bo_types.h
@@ -108,6 +108,18 @@ struct xe_bo {
* from default
*/
u64 min_align;
+
+ /**
+ * @is_devmem_external: Whether this BO is an imported dma-buf that
+ * is LMEM based.
+ */
+ bool is_devmem_external;
+
+ /**
+ * @dma_data: DMA related data for an imported dmabuf BO that is LMEM
+ * based.
+ */
+ struct xe_sriov_dma_data dma_data;
};
#endif
diff --git a/drivers/gpu/drm/xe/xe_sriov_pf_types.h b/drivers/gpu/drm/xe/xe_sriov_pf_types.h
index 956a88f9f213..6d5f923f7fc4 100644
--- a/drivers/gpu/drm/xe/xe_sriov_pf_types.h
+++ b/drivers/gpu/drm/xe/xe_sriov_pf_types.h
@@ -11,6 +11,8 @@
#include "xe_sriov_pf_service_types.h"
+struct xe_bo;
+
/**
* struct xe_sriov_metadata - per-VF device level metadata
*/
@@ -42,4 +44,21 @@ struct xe_device_pf {
struct xe_sriov_metadata *vfs;
};
+/**
+ * struct xe_sriov_dma_data - DMA related data for LMEM based imported dmabuf
+ * BOs that are associated with a sriov VF.
+ *
+ * The data in this structure is valid only if driver is running in the
+ * @XE_SRIOV_MODE_PF mode.
+ */
+struct xe_sriov_dma_data {
+ /**
+ * @dma_addr: An array to store DMA addresses (DPAs) for imported
+ * dmabuf BOs that are LMEM based.
+ */
+ struct drm_pagemap_addr *dma_addr;
+
+ /** @lmem_obj: Ref taken on the LMEM obj that backs a VF's quota */
+ struct xe_bo *lmem_obj;
+};
#endif
--
2.50.1
^ permalink raw reply related [flat|nested] 16+ messages in thread* [RFC 8/8] drm/xe/pt: Add an additional check for dmabuf BOs while doing bind
2025-10-14 7:08 [RFC 0/8] dma-buf: Add support for mapping dmabufs via interconnects Vivek Kasireddy
` (6 preceding siblings ...)
2025-10-14 7:08 ` [RFC 7/8] drm/xe/bo: Create new dma_addr array for dmabuf BOs associated with VFs Vivek Kasireddy
@ 2025-10-14 7:08 ` Vivek Kasireddy
7 siblings, 0 replies; 16+ messages in thread
From: Vivek Kasireddy @ 2025-10-14 7:08 UTC (permalink / raw)
To: dri-devel, intel-xe, linux-media, linaro-mm-sig; +Cc: Vivek Kasireddy
If a BO's is_devmem_external flag is set, it means that it is an
imported dmabuf BO that has a backing store in VRAM. Therefore, in
this case, need to iterate over its dma_addr array.
v2:
- Use a cursor to iterate over the entries in the dma_addr array
instead of relying on SG iterator (Matt)
v3:
- Since XE_PPGTT_PTE_DM is added to the PTE flags in all cases,
remove the bo->is_devmem_external check added in v2
Signed-off-by: Vivek Kasireddy <vivek.kasireddy@intel.com>
---
drivers/gpu/drm/xe/xe_pt.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/drivers/gpu/drm/xe/xe_pt.c b/drivers/gpu/drm/xe/xe_pt.c
index a1c88f9a6c76..5cc3775a3a12 100644
--- a/drivers/gpu/drm/xe/xe_pt.c
+++ b/drivers/gpu/drm/xe/xe_pt.c
@@ -759,6 +759,10 @@ xe_pt_stage_bind(struct xe_tile *tile, struct xe_vma *vma,
xe_walk.default_vram_pte |= XE_PPGTT_PTE_DM;
xe_walk.dma_offset = bo ? vram_region_gpu_offset(bo->ttm.resource) : 0;
+
+ if (bo && bo->is_devmem_external)
+ xe_walk.dma_offset = 0;
+
if (!range)
xe_bo_assert_held(bo);
@@ -769,6 +773,10 @@ xe_pt_stage_bind(struct xe_tile *tile, struct xe_vma *vma,
else if (xe_bo_is_vram(bo) || xe_bo_is_stolen(bo))
xe_res_first(bo->ttm.resource, xe_vma_bo_offset(vma),
xe_vma_size(vma), &curs);
+ else if (bo && bo->is_devmem_external)
+ xe_res_first_dma(bo->dma_data.dma_addr,
+ xe_vma_bo_offset(vma),
+ xe_vma_size(vma), &curs);
else
xe_res_first_sg(xe_bo_sg(bo), xe_vma_bo_offset(vma),
xe_vma_size(vma), &curs);
--
2.50.1
^ permalink raw reply related [flat|nested] 16+ messages in thread