From: Leon Romanovsky <leon@kernel.org>
To: "Sumit Semwal" <sumit.semwal@linaro.org>,
"Christian König" <christian.koenig@amd.com>,
"Jonathan Corbet" <corbet@lwn.net>,
"Shuah Khan" <skhan@linuxfoundation.org>
Cc: Logan Gunthorpe <logang@deltatee.com>,
linux-media@vger.kernel.org, dri-devel@lists.freedesktop.org,
linaro-mm-sig@lists.linaro.org, linux-doc@vger.kernel.org,
linux-kernel@vger.kernel.org, Jason Gunthorpe <jgg@ziepe.ca>
Subject: [PATCH v2] dma-buf: Document how exporters and importers agree on mapping lifetime
Date: Sun, 6 Sep 2026 15:40:54 +0300 [thread overview]
Message-ID: <20260906-document-dma-buf-v2-1-942710fe82c6@nvidia.com> (raw)
From: Leon Romanovsky <leonro@nvidia.com>
Nothing in DMA-buf declares whether a mapping may be moved or taken away.
Nearly every callback on both sides is optional, so the answer follows
from which ones are implemented and from whether dma_buf_pin() succeeds.
Documentation/ says none of this, and the rules sit in the kdoc of
dma_buf_ops.pin, dma_buf_attach_ops.invalidate_mappings and
dma_buf_invalidate_mappings(), which a driver author has to know by name
before finding them.
Describe the three flows an importer has to handle, the callbacks each
one asks of both sides, and dma_buf_pin() as the runtime negotiation.
Signed-off-by: Leon Romanovsky <leonro@nvidia.com>
---
Let's try this variant from importer POV.
Thanks
Changes in v2:
- Split pci p2p documentation patch to separate series
- Improved dma-buf documentation patch.
- Link to v1: https://patch.msgid.link/20260825-document-dma-buf-v1-0-5ecfb3e1371c@nvidia.com
---
Documentation/driver-api/dma-buf.rst | 6 ++++
drivers/dma-buf/dma-buf.c | 69 +++++++++++++++++++++++++++++++++++-
2 files changed, 74 insertions(+), 1 deletion(-)
diff --git a/Documentation/driver-api/dma-buf.rst b/Documentation/driver-api/dma-buf.rst
index 2f36c21d9948..39c201f38aa6 100644
--- a/Documentation/driver-api/dma-buf.rst
+++ b/Documentation/driver-api/dma-buf.rst
@@ -113,6 +113,12 @@ Basic Operation and Device DMA Access
.. kernel-doc:: drivers/dma-buf/dma-buf.c
:doc: dma buf device access
+Mapping Lifetime Negotiation
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. kernel-doc:: drivers/dma-buf/dma-buf.c
+ :doc: mapping lifetime negotiation
+
CPU Access to DMA Buffer Objects
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c
index d504c636dc29..aa47142cd9ed 100644
--- a/drivers/dma-buf/dma-buf.c
+++ b/drivers/dma-buf/dma-buf.c
@@ -684,7 +684,74 @@ static struct file *dma_buf_getfile(size_t size, int flags)
* reference acquired with dma_buf_get() by calling dma_buf_put().
*
* For the detailed semantics exporters are expected to implement see
- * &dma_buf_ops.
+ * &dma_buf_ops. Whether the exporter may still move or take away the backing
+ * storage after step 3 depends on what both sides implement. See the mapping
+ * lifetime negotiation section below.
+ */
+
+/**
+ * DOC: mapping lifetime negotiation
+ *
+ * Nearly everything in DMA-buf is optional. No flag or enum says whether the
+ * exporter may move or take away the backing storage while an importer holds
+ * a mapping. Each side simply implements the callbacks it can offer, and
+ * dma_buf_pin() settles the result at runtime.
+ *
+ * Out of that optionality the importer sees three main flows. They are named
+ * from the importer's point of view, because each one demands a different
+ * capability of its hardware:
+ *
+ * - Pinned: the memory is never taken away. The importer offers no way
+ * to stop DMA.
+ * - Revoked: the storage never moves, but the exporter may take it away. The
+ * importer must be able to stop DMA, and may hit user visible errors while
+ * doing so.
+ * - Movable: the exporter may relocate the storage at any time. The importer
+ * must be able to pause DMA, and must raise no error while the storage is
+ * moving.
+ *
+ * An importer reaches its flow like this:
+ *
+ * 1. Attach with dma_buf_dynamic_attach(). Leaving out the optional
+ * &dma_buf_attach_ops.invalidate_mappings callback pins the buffer for as
+ * long as the attachment exists.
+ * 2. Call dma_buf_pin() under the reservation lock.
+ * 3. On failure, run the movable flow or give up.
+ * 4. On success, the flow is the revoked one if the optional
+ * &dma_buf_attach_ops.invalidate_mappings is implemented, and the pinned
+ * one if it is not.
+ *
+ * Pinned flow:
+ *
+ * - Exporter: implement &dma_buf_ops.pin and &dma_buf_ops.unpin to hold the
+ * storage still on request. An exporter whose storage never moves implements
+ * neither, and dma_buf_pin() then succeeds on its own. An exporter which
+ * refuses to be pinned implements &dma_buf_ops.pin and fails it.
+ * - Importer: nothing more. The mapping stays valid until the importer unmaps.
+ *
+ * Revoked flow:
+ *
+ * - Exporter: answer dma_buf_pin() as above. Call
+ * dma_buf_invalidate_mappings() when the storage goes away and fail
+ * &dma_buf_ops.map_dma_buf while it is gone. The two waits which complete a
+ * revocation are described in dma_buf_invalidate_mappings().
+ * - Importer: &dma_buf_attach_ops.invalidate_mappings has to unmap within
+ * bounded time and drop the pin.
+ *
+ * Movable flow:
+ *
+ * - Exporter: call dma_buf_invalidate_mappings() before each move, then wait
+ * for the &dma_buf.resv fences. &dma_buf_ops.pin and &dma_buf_ops.unpin play
+ * no part here.
+ * - Importer: hold no pin. &dma_buf_attach_ops.invalidate_mappings drops the
+ * cached mapping and has to lead to dma_buf_unmap_attachment() within
+ * bounded time. It need not stop the hardware, because access runs until the
+ * importer's &dma_buf.resv fences retire. The importer maps again before the
+ * next DMA.
+ *
+ * &dma_buf_ops.attach is the best place for an exporter to turn an importer
+ * away, because the importer can still fall back to another flow and attach
+ * again.
*/
/**
---
base-commit: 63367df6e7255067ad6a83abe0d2799dfa491876
change-id: 20260820-document-dma-buf-3f8b41e32f57
Best regards,
--
Leon Romanovsky <leonro@nvidia.com>
reply other threads:[~2026-09-06 12:41 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
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=20260906-document-dma-buf-v2-1-942710fe82c6@nvidia.com \
--to=leon@kernel.org \
--cc=christian.koenig@amd.com \
--cc=corbet@lwn.net \
--cc=dri-devel@lists.freedesktop.org \
--cc=jgg@ziepe.ca \
--cc=linaro-mm-sig@lists.linaro.org \
--cc=linux-doc@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-media@vger.kernel.org \
--cc=logang@deltatee.com \
--cc=skhan@linuxfoundation.org \
--cc=sumit.semwal@linaro.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.