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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox