Hi all,
The goal of this series is to enable userspace driver designs that use
VFIO to export DMABUFs representing subsets of PCI device BARs, and
"vend" those buffers from a primary process to other subordinate
processes by fd. This is achieved by allowing the processes to mmap()
the DMABUFs; their access to the device is isolated to the exported
ranges. The primary userspace driver process can forcibly revoke
access to previously-shared buffers upon cleanup (without requiring
cooperation from the subordinate processes). This is an improvement
on sharing the VFIO device fd to subordinate processes, which would
allow global access. See the RFCs for background.
The existing VFIO PCI BAR mmap() becomes backed by a DMABUF too,
keeping common vm_ops and fault handler for VMAs from the VFIO device
and explicitly-exported DMABUFs. This will help future iommufd
emulation of VFIO Type1 peer-to-peer, making it easier to get a DMABUF
for a VFIO BAR as a DMA target.
Below are per-patch notes & background info, and at the bottom are
several related questions that reviewers may like to consider (worth
at least skipping to #1, a possible bug).
Notes on patches
================
mmap() conversion to use DMABUF underneath has been done for vfio-pci,
but not sub-drivers: nvgrace-gpu's mmap() override path is unchanged;
I kept this out of scope for now not least because I don't have a
thorough test setup for this system. I would prefer to help the
nvgrace-gpu maintainers enable BAR mmap() DMABUFs themselves.
vfio/pci: Remove DMABUF export dependency on vdev->memory_lock
In v5 of this series we discover that doing an export from the VFIO
mmap() path (fundamental!) adds a dependency between mmap_lock and
vdev->memory_lock(W) because export was using memory_lock(W) to
protect the vdev->dmabufs list and state within, and a deadlock
scenario leapt out to bite:
https://lore.kernel.org/kvm/9a615f22-c0d4-46ae-9654-db11e94e5fec@ozlabs.org/
The suggestion was to add a dedicated mutex/rwsem specifically for
the DMABUFs/list, which is cleaner than overloading memory_lock(W).
But whilst export could now downgrade to holding memory_lock(R) to
test __vfio_pci_memory_enabled(), a very similar deadlock can still
arise due to a memory_lock(W) elsewhere depending on a prior
memory_lock(R) to be released, and attempting to take
memory_lock(R) will queue behind the (W) for fairness (effectively
an R->R dependency). I'd overlooked that rwsem cannot guarantee
multiple readers.
To be able to export while holding mmap_lock, export cannot hold
memory_lock at all. Instead of testing __vfio_pci_memory_enabled()
(which tracks PCI_COMMAND.MSE and PM state), this patch tracks
device-global DMABUF revocation state in a new vdev->bars_revoked
flag updated by vfio_pci_dma_buf_move(). If an mmap() is somehow
performed during a period when DMABUFs are all revoked, then the
DMABUF is created revoked. Move() already bookends reset, PM
transitions etc., so subsequent revocation state changes work
as-is. This flag is also protected by the dmabuf_lock and thus
memory_lock is not required to export.
vfio/pci: Un-revoke DMABUFs in LOW_POWER_ENTRY_WITH_WAKEUP resume
On LOW_POWER entry, DMABUFs have a move(revoke=true), but the
runtime resume path didn't un-revoke. This adds a corresponding
move(revoke=false), which will later turn into
vfio_pci_unrevoke_bars().
NOTE: the unrevoke is reordered _before_ the eventfd_signal() in
vfio_pci_core_runtime_resume() to remove a window in which a waking
waiter could have observed the DMABUF state as still revoked (or
pm_runtime_engaged = true). (The UAPI docs state the event means
the resume's complete, so observing otherwise seemed unintended.)
Also, when DMABUFs are later mmap()ed, a waiter waking and taking a
fault could have seen the unrevoked state and SIGBUS just before
taking the memory_lock. (If the handler gets to acquire the lock,
though, the resume sequence is complete, and the handler observes
pm_runtime_engaged = false.)
This fix is in this series because the issue will impact CPU access
to the VMA as well (once they use DMABUFs), and so it's a strict
dependency of later commits.
dma-buf: Provide dma_buf_set_name()
Makes dma_buf_set_name() available for use (by helper patch),
taking a kernel-allocated string. The pre-existing local helper
becomes a wrapper copying a __user string for the set-name ioctl.
vfio/pci: Add a helper to look up PFNs for DMABUFs
Adds a DMABUF VMA fault handler helper to determine arbitrary-sized
PFNs from ranges in DMABUF.
vfio/pci: Add a helper to create a DMABUF for a BAR-map VMA
Refactors DMABUF export for use by the existing export feature, and
adds a helper that creates a DMABUF corresponding to a VFIO BAR
mmap() request.
There was a request for decent debug naming in /proc/<pid>/maps
etc. comparable to the existing VFIO names: since the VMAs are
DMABUFs, they have a "dmabuf:" prefix and can't be 100% identical
to before. This is a user-visible change, but this patch at least
now gives us extra info on the BDF & BAR being mmap()ed. The name
is installed with the new dma_buf_set_name() above.
vfio/pci: Convert BAR mmap() to use a DMABUF
The vfio-pci core mmap() creates a DMABUF with the helper above,
and the vm_ops fault handler uses the other helper to resolve the
fault. Because this depends on DMABUF structs/code,
CONFIG_VFIO_PCI_CORE needs to depend on CONFIG_DMA_SHARED_BUFFER.
The CONFIG_VFIO_PCI_DMABUF still conditionally enables the export
support code.
NOTE: The user mmap()s a device fd, but the resulting VMA's vm_file
becomes that of the DMABUF. The DMABUF takes ownership of the
device file and put()s it on release, which maintains the existing
behaviour of a VMA keeping the VFIO device open.
BAR zapping then happens via the existing vfio_pci_dma_buf_move()
path, which now needs to unmap PTEs in the DMABUF's address_space.
NOTE: As local LLM reviews did, Sashiko might falsely worry about
the DMABUF fd being obtained through /proc/pid/map_files and
remapped, but the file is an anon inode and doesn't support the
open op (-ENXIO) so AFAICT this is currently impossible.
NOTE: A side-effect of this is that is_mergeable_vma() will be
false between adjacent mappings of VFIO BARs; merging would require
rebuilding a larger DMABUF representing the union, not just
plugging the VMAs together.
The DMABUF backing the BAR is an implicit/internal export, even
when the CONFIG_VFIO_PCI_DMABUF feature is not included because
CONFIG_PCI_P2PDMA is not available. Without P2PDMA, it's
acceptable for the DMABUF to not have a P2PDMA provider. In this
configuration, the VFIO DMABUF .attach prohibits any import, which
avoids getting as far as a WARN in dma_buf_map_attachment(), which
would fail without P2PDMA anyway.
vfio/pci: Clean up BAR zap and revocation
In general (see NOTE!) the vfio_pci_zap_bars() is now obsolete,
since it unmaps PTEs in the VFIO device address_space which is now
unused. This consolidates all calls (e.g. around reset) with the
neighbouring vfio_pci_dma_buf_move()s into new functions, to
revoke/unrevoke (making the steps clearer).
NOTE: Because drivers can use their own vm_ops and override .mmap,
the core must conservatively assume an overridden .mmap might still
add PTEs to the VFIO device address_space and therefore still does
the zap. A new flag, zap_bars_on_revoke, enables the zap when
.mmap is overridden. A driver that does not need the zap can clear
this to opt-out, e.g. if the driver calls down to the common mmap
(and so uses DMABUFs). hisi-acc-vfio-pci does just this, and thus
sets the opt-out flag.
vfio/pci: Support mmap() of a VFIO DMABUF
Adds mmap() for a DMABUF fd exported from vfio-pci.
It was a goal to keep the VFIO device fd lifetime behaviour
unchanged with respect to the DMABUFs. An application can close
all device fds, and this will revoke/clean up all DMABUFs; then, no
mappings or other access can be performed. When enabling mmap() of
the DMABUFs, this means access through the VMA is also revoked.
This complicates the fault handler because whilst the DMABUF
exists, it has no guarantee that the corresponding VFIO device is
still alive. Adds synchronisation ensuring the vdev is available
before the locks in vdev are touched; this holds the device
registration so that even if the buffer has been cleaned up, vdev
hasn't been freed and so the locks can be safely taken.
vfio/pci: Revoke a DMABUF on request from userspace
This is mostly a rename of `revoked` to an enum, `status`, and
adding a third state for a buffer: usable, revoked temporary,
revoked permanent. A new VFIO feature is added,
VFIO_DEVICE_FEATURE_DMA_BUF_REVOKE, which takes a DMABUF (exported
from the same device) and permanently revokes it. Thus a userspace
driver can guarantee any downstream consumers of a shared fd are
prevented from accessing a BAR range, and that range can be reused.
NOTE: This might block userspace, waiting on importers to detach.
The code doing revocation in vfio_pci_dma_buf_move() is moved, to a
common function used by ..._move() and this new feature.
Testing
=======
(The [RFC ONLY] userspace test program, which drives a QEMU
bochs-display function, can be found in the GitHub branch below. It
at least illustrates how the export, map, revoke, and close semantics
interoperate. WIP on a follow-up with a proper vfio-selftests style
test based on this -- this won't be part of this series.)
This code has been tested in mapping DMABUFs of single/multiple ranges
from multiple BARs, aliasing mmap()s, aliasing ranges across DMABUFs,
vm_pgoff > 0, revocation, shutdown/cleanup scenarios, and hugepage
mappings. No regressions observed on the VFIO selftests, or on our
internal vfio-pci applications. VFIO on i386 has been build-tested.
Thanks to Alex Mastro for building a (WIP) testcase for the
prior mmap_lock->memory_lock issue.
Dear Reviewers,
===============
Along the way several related issues came up that warrant more
eyes, and I'd be grateful for your input:
1. If VFIO fd is opened O_RDONLY, it currently can't be mmap()ed
(because PROT_WRITE is rejected in do_mmap(), and PROT_READ alone
drops the VM_SHARED so VFIO's mmap rejects it). BUT it seems we
can export a DMABUF from it, and then pass the resulting fd around
for P2P writes.
I don't know if this is intentional/relied on/a known limitation,
or a bug?
a) We could reject export w/ -EPERM unless the device fd's f_mode
has O_RDWR, to reflect the RW abilities of P2P
If we agree it's a bug, I want to do this fix (a), as we can now
export a DMABUF RW from an O_RDONLY device fd and then succeed to
mmap() the DMABUF with RW. (That said, even with an O_RDONLY
device fd, the device state can still be changed/reset. But it
feels cleaner to prevent export for a O_RDONLY device fd, and match
the device fd mmap() behaviour.)
In future, we could consider finer-grained RD/WR if there's a
future goal to tie DMABUF permissions to, say, iommufd
IOMMU_READ/IOMMU_WRITE permissions:
b) Instead of just failing if !O_RDWR, we could limit the
get_dma_buf.open_flags to the VFIO device fd's f_mode, such as:
VFIO device fd perms: Export flags: Result:
O_RDWR O_RDWR, O_RDONLY OK
O_RDONLY O_RDONLY OK
O_RDONLY O_RDWR -EPERM
O_WRONLY * -EPERM
* O_WRONLY -EPERM
(Skipping WRONLY because a PROT_WRITE-only mmap() won't work,
though it probably should be included for P2P.)
2. The mmap fault handler takes a bunch of locks non-interruptibly,
and potentially depends on a lot of DMABUF-related activities
completing. I'd had a go at converting them to
interruptible/killable forms, but that revealed there seems to be a
wider issue if move/revoke doesn't complete in a timely fashion
(due to buggy importers). Where I got to was that just updating
the fault handler won't fix the user experience of an unkillable
task, and move()/revocation will need thought too. I don't intend
to fix this here but wanted to start discussion so we can address
it in a follow up. There's now a dependency between mmap_lock in
the fault handler and the DMABUF resv (which might take a while to
resolve), though revocation will be rare in practice.
3. vfio_basic_config_write() has an error path if
vfio_default_config_write() fails that releases memory_lock but
doesn't un-revoke BARs in the case of PCI_COMMAND.MSE being
cleared. When can the write fail, in practice, perhaps surprise
removal?
The effect on this series would be: a write of MSE=0 revokes BARs,
vconfig[PCI_COMMAND]'s MSE becomes 0, but if the physical write
fails then the physical MSE remains 1 and BAR VMAs stay revoked.
This seemed a mess; fixing isn't as simple as un-revoking on the
error path since vfio_default_config_write() has already trampled
vconfig so that'd need unwinding. It felt like a catastrophic
scenario where BARs staying revoked isn't a bad outcome, but want
to hear your experience of the likelihood of this issue.
4. The exchange of a VFIO fd mmap()'s vma->vm_file with an implicitly
created DMABUF's file has implications on LSM. For example, an
mmap will be checked against the policy for a VFIO fd, but a
subsequent mprotect() relates to the policy of the DMABUF file
(which is anon/unique to the mapping). This is pretty confusing.
END
===
This is based on v7.3-rc4
These commits are on GitHub for easier browsing, along with
"[RFC ONLY] selftests: vfio: Add standalone vfio_dmabuf_mmap_test":
https://github.com/metamev/linux/compare/v7.3-rc4...dev/mev/vfio-dmabuf-mma…
Thanks for reading,
Matt
================================================================================
Changelog:
v7:
- Rebased, v7.3-rc4
- "dma-buf: Export dma_buf_set_name()" is now "dma-buf: Provide
dma_buf_set_name()": reworded commit message with rationale, and
indicate it is only expected to be used by exporters. Remove static
helper for user ioctl & copy from user inline in the ioctl.
- "vfio/pci: Permanently revoke a DMABUF on request" is now
"vfio/pci: Revoke a DMABUF on request from userspace", with a
clarified commit message, and removal of "temporary/permanent"
language. This still replaces the priv->revoked flag with an
enum/third state, named OK/REVOKED for the existing two. The new
state, DEAD, is "sticky" from the VFIO-internal perspective, meaning
it prevents any of the move-style transitions from REVOKED back to
OK, guaranteeing that a DEAD buffer cannot ever be attached/mapped
by a new or existing importer. Clarified language around attach vs
map to not imply a racing import will be detached; it might attach,
but cannot map (and has no existing maps) after the ioctl returns.
- Reworded several commit messages for more clarity/brevity.
- "vfio/pci: Add a helper to create a DMABUF for a BAR-map VMA":
As of the recent e8efdf02d3a97 ("vfio: Enable cdev noiommu mode
under iommufd") dev_name() can be much larger
(e.g. noiommu_vfio1048575) and the discovery that
drivers/pci/controller/vmd.c (others?) could create a domain up to
MAX_INT means there isn't a nice way to guarantee a debug name is
available across all cdev names and maximum sizes of all properties
(e.g. 1M cdevs, 4G domains). So, removed the cdev name from the
debug name construction, which now looks like 'vfio:0001:02:03.4/5'.
The cdev can be fished out of sysfs given the domain+BDF, and it's
still useful debug. Adjusted comments & commit message.
v6: https://lore.kernel.org/all/20260911214200.33793-1-matt@ozlabs.org/
v5: https://lore.kernel.org/all/20260715174737.15287-1-matt@ozlabs.org/
v4: https://lore.kernel.org/all/20260701171245.90111-1-matt@ozlabs.org/
v3: https://lore.kernel.org/all/20260610154327.37758-1-matt@ozlabs.org/
v2: https://lore.kernel.org/all/20260527102319.100128-1-mattev@meta.com/
v1: https://lore.kernel.org/kvm/20260416131815.2729131-1-mattev@meta.com/
RFCv2: https://lore.kernel.org/kvm/20260312184613.3710705-1-mattev@meta.com/
RFCv1: https://lore.kernel.org/all/20260226202211.929005-1-mattev@meta.com/
Tech topic: https://lore.kernel.org/linux-iommu/20250918214425.2677057-1-amastro@fb.com/
Matt Evans (9):
vfio/pci: Remove DMABUF export dependency on vdev->memory_lock
vfio/pci: Un-revoke DMABUFs in LOW_POWER_ENTRY_WITH_WAKEUP resume
dma-buf: Provide dma_buf_set_name()
vfio/pci: Add a helper to look up PFNs for DMABUFs
vfio/pci: Add a helper to create a DMABUF for a BAR-map VMA
vfio/pci: Convert BAR mmap() to use a DMABUF
vfio/pci: Clean up BAR zap and revocation
vfio/pci: Support mmap() of a VFIO DMABUF
vfio/pci: Revoke a DMABUF on request from userspace
drivers/dma-buf/dma-buf.c | 78 ++-
drivers/vfio/pci/Kconfig | 4 +-
drivers/vfio/pci/Makefile | 3 +-
.../vfio/pci/hisilicon/hisi_acc_vfio_pci.c | 14 +-
drivers/vfio/pci/vfio_pci_config.c | 30 +-
drivers/vfio/pci/vfio_pci_core.c | 222 +++++--
drivers/vfio/pci/vfio_pci_dmabuf.c | 609 +++++++++++++++---
drivers/vfio/pci/vfio_pci_priv.h | 54 +-
include/linux/dma-buf.h | 2 +
include/linux/vfio_pci_core.h | 3 +
include/uapi/linux/vfio.h | 24 +
11 files changed, 856 insertions(+), 187 deletions(-)
--
2.50.1 (Apple Git-155)
Hi Longfang,
On 22/09/2026 10:16, liulongfang wrote:
> On 2026/9/21 21:24, Matt Evans wrote:
>> Hi Longfang,
>>
>> On 15/09/2026 13:16, liulongfang wrote:
>>> On 2026/9/12 5:41, Matt Evans wrote:
>>>> [snip]
>>>> +
>>>> + /*
>>>> + * The DMABUF begins from the mmap()'s BAR offset, i.e. the
>>>> + * start of the VMA corresponds to byte 0 of the DMABUF and
>>>> + * byte (vma_pgoff << PAGE_SHIFT) of the BAR.
>>>> + *
>>>> + * vfio_pci_dma_buf_find_pfn() reverses this offset using
>>>> + * vma_pgoff_adjust, so that ultimately a fault's offset from
>>>> + * the start of the _VMA_ has a consistent usage whether the
>>>> + * VMA originates from an mmap() of the VFIO device here or a
>>>> + * direct DMABUF mmap(). Note vma_pgoff_adjust also includes
>>>> + * the encoded VFIO region index, which cancels out the index
>>>> + * encoded in vm_pgoff.
>>>> + */
>>>> + priv->vdev = vdev;
>>>> + priv->size = req_len;
>>>> + priv->nr_ranges = 1;
>>>> + priv->vma_pgoff_adjust = vma->vm_pgoff;
>>>> +
>>>> + priv->provider = pcim_p2pdma_provider(vdev->pdev, res_index);
>>>> + if (!priv->provider) {
>>>> + ret = -EINVAL;
>>>> + goto err_free_name;
>>>> + }
>>>> +
>>>> + priv->phys_vec[0].paddr = phys_start + ((u64)vma_pgoff << PAGE_SHIFT);
>>>> + priv->phys_vec[0].len = priv->size;
>>>> +
>>>> + ret = vfio_pci_dmabuf_export(vdev, priv, O_RDWR);
>>>> + if (ret)
>>>> + goto err_free_name;
>>>> +
>>>
>>> In the current patch, the PCIe device's BAR2 configuration space can be mapped as a DMABUF.
>>> However, on an OS with a 64K page size, if a VF device's BAR2 is smaller than 64K,
>>> a problem arises where the space is forced to page-align to 64K, it will causing the VM to
>>> access memory beyond the actual size of the VF device's BAR2 space.
>>>
>>> How does your solution handle these cases where the BAR2 space is smaller than the Host OS's page size?
>>
>> Even on a 4K host, there can be BARs < PAGE_SIZE so 64K (or 16K) hosts
>> aren't a new case. These small BARs cannot be mmap()ed and DMABUFs
>> cannot be exported from them. (vfio_pci_core_mmap() errors out when
>> !bar_mmap_supported[index]. And, a DMABUF needs to be an aligned
>> multiple of PAGE_SIZE, plus vfio_pci_core_fill_phys_vec() won't allow a
>> DMABUF to be created off the end of a BAR.)
>>
>> So, although this series allows a DMABUF to be mmap()ed, the preexisting
>> checks prevent a sub-page DMABUF from existing and so there is no new
>> route to mapping a sub-page BAR.
>>
>> What's the concern on BAR2 specifically, out of interest? This logic is
>> applied to all resources equally, and tests pci_resource_len(...) so
>> there shouldn't be a PF/VF distinction either.
>>
>
> However, the typical boundary check found in VFIO, such as:
>
> if (req_start + req_len > phys_len)
> return -EINVAL;
>
> seems to be missing here.
Isn't it covered by that statement in vfio_pci_core_mmap() just before
this function is called? This helper is intended to do as it's told by
a caller that has validated the range is correct (it doesn't duplicate
the checks already done by vfio_pci_core_mmap()).
Thanks,
Matt
This series tightens the alignment requirements for buffers that are shared
between confidential-computing guests and the host, and adds a common
allocator for host-shared memory.
When a guest runs with private memory, buffers shared with the hypervisor
are not only accessed by the guest. They are also accessed by the host
kernel, and the host may manage the corresponding shared/private state at a
granularity larger than the guest page size.
This matters for CCA systems where the Realm stage-2 mappings managed by
the RMM can still operate at 4K granularity, while the non-secure host may
manage the IPA state change at a larger page size, for example 64K. In that
case, allowing a guest to convert and share only a 4K subrange of a
host-managed granule is unsafe.
Architectures such as Arm can detect incorrect accesses to Realm physical
address space PFNs through GPC faults. However, relying on that as the only
line of defence is fragile and can still lead to kernel crashes. The risk
is especially visible for shared buffers that are later mmapped into
userspace, such as guest_memfd or dma-buf backed allocations. Once
userspace can access the mapping, the kernel cannot guarantee that
applications will only touch the intended 4K region rather than the whole
host page mapped into their address space. Those userspace addresses may
also be passed back into the kernel and accessed through the linear map,
resulting in a GPC fault.
To avoid this, host-shared buffers must satisfy two constraints:
- the address must be aligned to the CoCo shared-granule size
- the size must be a multiple of that granule size
The series adds a common CoCo shared-memory layer for enforcing these
constraints. It provides shared-granule geometry and range-validation
helpers, byte-oriented private/shared transition helpers, and
alloc_cc_shared_pages() with a node-aware variant. The allocator rounds a
request to the architecture shared granule, allocates suitably aligned
contiguous pages, transitions the complete allocation to shared state, and
returns the transitioned size alongside the page.
The corresponding free helper restores the complete allocation to private
state before returning it to the buddy allocator. If private state cannot
be restored safely, the allocation is deliberately leaked rather than
returning potentially shared memory for unrelated use. Since a
private-to-shared transition may modify memory contents, __GFP_ZERO is
applied after the transition.
The generic shared-granule size defaults to PAGE_SIZE. For arm64 CCA, the
series queries the host IPA state change alignment through the Realm Host
Interface, caches it during Realm initialization, and exposes it through
the arm64 memory-encryption operations.
The common allocator is used for host-shared allocations whose backing is
owned by an individual caller:
- GIC ITS command queues and tables
- dma-direct allocations backed by CMA or the page allocator
- backing allocations for the CoCo atomic DMA pools
- dma-buf system_cc_shared heap allocations
Hyper-V users of set_memory_encrypted() and set_memory_decrypted() are not
changed by this series. Those paths are not currently used by the arm64 CCA
code path, and therefore are not part of the arm64 CCA IPA state change
alignment problem addressed here.
NOTE: I have not added explicit MAINTAINERS entries for mm/cc_shared.c and
include/linux/cc_shared.h, as I am unsure whether we need a separate section
for common CoCo-related files. I will add the entries based on feedback.
Changes from v7:
https://lore.kernel.org/all/20260921144847.501151-1-aneesh.kumar@kernel.org
* Add the following new patches:
* "irqchip/gic-v3-its: Preallocate VPE L1 tables"
* "mm: Assert CoCo shared allocations may sleep"
* "mm: Zero memory during shared memory transitions"
* Drop the arm64 RHI and shared granule size patches so that the series can
be rebased on top of upstream to enable Shashiko review.
Changes from v6:
https://lore.kernel.org/all/20260904103452.1197239-1-aneesh.kumar@kernel.org
* Add a common allocator and geometry/transition helpers for CoCo host-shared
memory.
* Convert GIC ITS, dma-direct, atomic DMA pools, and the dma-buf
system_cc_shared heap to the common allocator.
* Limit dma-buf scatterlist entries to the requested buffer size so rounded
backing is not exposed to importers.
Changes from v5:
https://lore.kernel.org/all/20260706060432.1375570-1-aneesh.kumar@kernel.org
* Rebased to latest kernel
* Drop patch arm64: realm: Move Realm memory encryption ops to RSI code
Changes from v4:
https://lore.kernel.org/all/20260427063108.909019-1-aneesh.kumar@kernel.org
* Rename the helpers to use CoCo terminology
(mem_cc_shared_granule_size() / mem_cc_align_to_shared_granule() instead of
mem_decrypt_granule_size() / mem_decrypt_align()).
* Use __DMA_ATTR_ALLOC_CC_SHARED to pass CoCo shared allocation requirements
down to CMA-based allocation helpers.
* Add validation for restricted DMA pools to reject pools that are not aligned
to the shared granule size.
* Add dma-buf system heap handling for cc-shared buffers.
* Split the previous combined DMA/SWIOTLB/ITS change into smaller subsystem
patches covering ITS, DMA direct, SWIOTLB, restricted DMA pools, dma-buf
system heap, and arm64 Realm support.
* Rework arm64 Realm support by moving Realm memory encryption ops into RSI
code and exposing the CCA shared granule size through arm64_mem_crypt_ops.
Changes from v3:
https://lore.kernel.org/all/20260309102625.2315725-1-aneesh.kumar@kernel.org
* Fix build error reported by kernel test robot <lkp(a)intel.com>
Changes from v2:
https://lore.kernel.org/all/20251221160920.297689-1-aneesh.kumar@kernel.org
* Rebase to latest kernel
* Consider swiotlb always decrypted and don't align when allocating from swiotlb.
Changes from v1:
* Rename the helper to mem_encrypt_align
* Improve the commit message
* Handle DMA allocations from contiguous memory
* Handle DMA allocations from the pool
* swiotlb is still considered unencrypted. Support for an encrypted swiotlb pool
is left as TODO and is independent of this series.
Cc: Andrew Morton <akpm(a)linux-foundation.org>
Cc: Baoquan He <baoquan.he(a)linux.dev>
Cc: Mike Rapoport <rppt(a)kernel.org>
Cc: Pasha Tatashin <pasha.tatashin(a)soleen.com>
Cc: Pratyush Yadav <pratyush(a)kernel.org>
Cc: Catalin Marinas <catalin.marinas(a)arm.com>
Cc: "Christian König" <christian.koenig(a)amd.com>
Cc: Jason Gunthorpe <jgg(a)ziepe.ca>
Cc: Joerg Roedel (AMD) <joro(a)8bytes.org>
Cc: Marc Zyngier <maz(a)kernel.org>
Cc: Marek Szyprowski <m.szyprowski(a)samsung.com>
Cc: Robin Murphy <robin.murphy(a)arm.com>
Cc: Steven Price <steven.price(a)arm.com>
Cc: Sumit Semwal <sumit.semwal(a)linaro.org>
Cc: Suzuki K Poulose <suzuki.poulose(a)arm.com>
Cc: Thomas Gleixner <tglx(a)kernel.org>
Cc: Will Deacon <will(a)kernel.org>
Cc: Russell King <linux(a)armlinux.org.uk>
Cc: Benjamin Gaignard <benjamin.gaignard(a)collabora.com>
Cc: Brian Starkey <Brian.Starkey(a)arm.com>
Cc: John Stultz <jstultz(a)google.com>
Cc: Mark Rutland <mark.rutland(a)arm.com>
Cc: Radu Rendec <radu(a)rendec.net>
Cc: "T.J. Mercier" <tjmercier(a)google.com>
Cc: Madhavan Srinivasan <maddy(a)linux.ibm.com>
Cc: Michael Ellerman <mpe(a)ellerman.id.au>
Cc: Nicholas Piggin <npiggin(a)gmail.com>
Cc: Christophe Leroy (CS GROUP) <chleroy(a)kernel.org>
Cc: Ritesh Harjani (IBM) <ritesh.list(a)gmail.com>
Cc: Shrikanth Hegde <sshegde(a)linux.ibm.com>
Cc: Alexander Gordeev <agordeev(a)linux.ibm.com>
Cc: Gerald Schaefer <gerald.schaefer(a)linux.ibm.com>
Cc: Heiko Carstens <hca(a)linux.ibm.com>
Cc: Vasily Gorbik <gor(a)linux.ibm.com>
Cc: Christian Borntraeger <borntraeger(a)linux.ibm.com>
Cc: Sven Schnelle <svens(a)linux.ibm.com>
Cc: Ingo Molnar <mingo(a)redhat.com>
Cc: Borislav Petkov <bp(a)alien8.de>
Cc: Dave Hansen <dave.hansen(a)linux.intel.com>
Cc: x86(a)kernel.org
Cc: H. Peter Anvin <hpa(a)zytor.com>
Cc: Kiryl Shutsemau <kas(a)kernel.org>
Cc: Rick Edgecombe <rick.p.edgecombe(a)intel.com>
Cc: K. Y. Srinivasan <kys(a)microsoft.com>
Cc: Haiyang Zhang <haiyangz(a)microsoft.com>
Cc: Wei Liu <wei.liu(a)kernel.org>
Cc: Dexuan Cui <decui(a)microsoft.com>
Cc: Long Li <longli(a)microsoft.com>
Cc: Paolo Bonzini <pbonzini(a)redhat.com>
Cc: Vitaly Kuznetsov <vkuznets(a)redhat.com>
Cc: Andy Lutomirski <luto(a)kernel.org>
Cc: Peter Zijlstra <peterz(a)infradead.org>
Cc: dri-devel(a)lists.freedesktop.org
Cc: iommu(a)lists.linux.dev
Cc: linaro-mm-sig(a)lists.linaro.org
Cc: linux-arm-kernel(a)lists.infradead.org
Cc: linux-kernel(a)vger.kernel.org
Cc: linux-media(a)vger.kernel.org
Cc: linux-mm(a)kvack.org
Aneesh Kumar K.V (Arm) (14):
mm: Add an allocator for CoCo shared memory
mm: Zero memory during shared memory transitions
irqchip/gic-v3-its: Resolve the default NUMA node explicitly
irqchip/gic-v3-its: Allocate shared tables using CoCo shared memory
allocator
dma-contiguous: Derive shared alignment from DMA attributes
dma-pool: Allocate CoCo atomic pools using CoCo shared memory
allocator
dma-direct: Align CoCo shared DMA allocations to the shared granule
size
swiotlb: Align shared IO TLB pools to the shared granule size
swiotlb: Reject misaligned restricted DMA pools for CoCo guests
dma-buf: system_heap: Limit scatterlist entries to the buffer size
dma-buf: system_heap: Allocate shared buffers using CoCo shared memory
allocator
swiotlb: Make rounded shared pool capacity allocatable
mm: Assert CoCo shared allocations may sleep
irqchip/gic-v3-its: Preallocate VPE L1 tables
arch/arm/mm/dma-mapping.c | 5 +-
arch/arm64/mm/pageattr.c | 3 +
arch/powerpc/platforms/pseries/svm.c | 2 +
arch/s390/mm/init.c | 3 +
arch/x86/coco/tdx/tdx.c | 3 +
arch/x86/hyperv/hv_init.c | 6 +-
arch/x86/hyperv/ivm.c | 4 +
arch/x86/kernel/kvmclock.c | 6 +-
arch/x86/mm/mem_encrypt_amd.c | 4 +
drivers/dma-buf/heaps/system_heap.c | 128 +++++-----
drivers/hv/connection.c | 41 ++--
drivers/hv/hv.c | 11 +-
drivers/hv/hv_common.c | 2 -
drivers/iommu/dma-iommu.c | 2 +-
drivers/irqchip/irq-gic-v3-its.c | 153 +++++++++---
drivers/irqchip/irq-gic-v3.c | 4 +-
drivers/virt/coco/pkvm-guest/arm-pkvm-guest.c | 3 +
include/linux/cc_shared.h | 39 +++
include/linux/dma-map-ops.h | 9 +-
include/linux/irqchip/arm-gic-v3.h | 3 +-
kernel/dma/contiguous.c | 41 +++-
kernel/dma/direct.c | 73 ++++--
kernel/dma/ops_helpers.c | 2 +-
kernel/dma/pool.c | 25 +-
kernel/dma/swiotlb.c | 80 ++++--
kernel/kexec_file.c | 3 +-
mm/Makefile | 1 +
mm/cc_shared.c | 232 ++++++++++++++++++
28 files changed, 682 insertions(+), 206 deletions(-)
create mode 100644 include/linux/cc_shared.h
create mode 100644 mm/cc_shared.c
base-commit: 704340f1cd0dcef829eb62f5b48ae95a2ce17bdf
--
2.43.0
On Wed, Sep 23, 2026 at 09:28:54AM -0700, Kameron Carr wrote:
> On 9/23/2026 8:21 AM, Jason Gunthorpe wrote:
> > On Wed, Sep 23, 2026 at 08:28:57PM +0530, Aneesh Kumar K.V wrote:
> >
> >> I'm also considering requiring the address passed to cc_make_shared() to
> >> be in the linear map. This is currently required by both TDX and CCA,
> >> while AMD SNP appears to support vmalloc addresses. The only user of
> >> that vmalloc support is Hyper-V VMBus GPADL setup
> >> (vmbus_establish_gpadl()). How should the generic CoCo shared-memory
> >> allocator handle this?
> >
> > vmbus_establish_gpadl() is the the same wrong abstraction as the arch
> > code. Get rid of it and use vmbus_establish_gpadl_caller_decrypted():
> >
> > pdata->recv_buf = vzalloc(RECV_BUFFER_SIZE);
> > if (!pdata->recv_buf) {
> > ret = -ENOMEM;
> > goto fail_free_ring;
> > }
> >
> > ret = vmbus_establish_gpadl(channel, pdata->recv_buf,
> > RECV_BUFFER_SIZE, &pdata->recv_gpadl);
> >
> >
> > So you made an allocator that returns folios, now you just need to
> > use that allocator to implement a kvzalloc wrapper. ARM can call vmap
> > on decrypted memory with pgprot_decrypted(), right?
> >
> > Or maybe this can use vmbus_alloc_buffer(), it already does it.
>
> Michael Kelley recently proposed [1] moving all ring buffer allocations
> to use vmbus_alloc_buffer(). If we move forward with this, it should
> remove the dependency on vmalloc support.
Even better vmbus_alloc_buffer() can use the new allocator API
directly so it doesn't need to open code the set_memory_decrypted arch
call.
Lets do it!
Jaon
On Tue, Sep 22, 2026 at 03:31:07PM -0700, Alex Mastro wrote:
> So I empathize with Matt's contention that the _existing_ behavior that the
> priv->revoked flag represents is actually "temporarily revoked": the importer
> can use the same dma-buf again, later, without having to re-import
> it!
mlx5 isn't a revoking importer, it is move capable. So the above
sequence isn't a revoke, it is a move with an unmapped placement for a
while.
This is why "temporarily revoked" is a confusing phrase.
The API is such that move and revoke importers can co-exist like this
but they experiance a different version of things..
We probably should not have made it have this move compatible
restoration and had things more consistent. User space can't know if
the importer is move capable or not so it has to assume revoke and it
has to go and unmap things before resetting/etc.
> This series doesn't intend to change the behavior of either. Is the confusion
> about whether the current behavior is intentional and/or desirable? If the
> answer to both is "no", then IMO this series paves the way nicely towards making
> PERM_REVOKED the only supported semantic later.
Right, I think the only concern is language.
Jason
Hi,
This series tightens the alignment requirements for buffers that are shared
between confidential-computing guests and the host, and adds a common
allocator for host-shared memory.
When a guest runs with private memory, buffers shared with the hypervisor
are not only accessed by the guest. They are also accessed by the host
kernel, and the host may manage the corresponding shared/private state at a
granularity larger than the guest page size.
This matters for CCA systems where the Realm stage-2 mappings managed by
the RMM can still operate at 4K granularity, while the non-secure host may
manage the IPA state change at a larger page size, for example 64K. In that
case, allowing a guest to convert and share only a 4K subrange of a
host-managed granule is unsafe.
Architectures such as Arm can detect incorrect accesses to Realm physical
address space PFNs through GPC faults. However, relying on that as the only
line of defence is fragile and can still lead to kernel crashes. The risk
is especially visible for shared buffers that are later mmapped into
userspace, such as guest_memfd or dma-buf backed allocations. Once
userspace can access the mapping, the kernel cannot guarantee that
applications will only touch the intended 4K region rather than the whole
host page mapped into their address space. Those userspace addresses may
also be passed back into the kernel and accessed through the linear map,
resulting in a GPC fault.
To avoid this, host-shared buffers must satisfy two constraints:
- the address must be aligned to the CoCo shared-granule size
- the size must be a multiple of that granule size
The series adds a common CoCo shared-memory layer for enforcing these
constraints. It provides shared-granule geometry and range-validation
helpers, byte-oriented private/shared transition helpers, and
alloc_cc_shared_pages() with a node-aware variant. The allocator rounds a
request to the architecture shared granule, allocates suitably aligned
contiguous pages, transitions the complete allocation to shared state, and
returns the transitioned size alongside the page.
The corresponding free helper restores the complete allocation to private
state before returning it to the buddy allocator. If private state cannot
be restored safely, the allocation is deliberately leaked rather than
returning potentially shared memory for unrelated use. Since a
private-to-shared transition may modify memory contents, __GFP_ZERO is
applied after the transition.
The generic shared-granule size defaults to PAGE_SIZE. For arm64 CCA, the
series queries the host IPA state change alignment through the Realm Host
Interface, caches it during Realm initialization, and exposes it through
the arm64 memory-encryption operations.
The common allocator is used for host-shared allocations whose backing is
owned by an individual caller:
- GIC ITS command queues and tables
- dma-direct allocations backed by CMA or the page allocator
- backing allocations for the CoCo atomic DMA pools
- dma-buf system_cc_shared heap allocations
Hyper-V users of set_memory_encrypted() and set_memory_decrypted() are not
changed by this series. Those paths are not currently used by the arm64 CCA
code path, and therefore are not part of the arm64 CCA IPA state change
alignment problem addressed here.
NOTE: I have not added explicit MAINTAINERS entries for mm/cc_shared.c and
include/linux/cc_shared.h, as I am unsure whether we need a separate section
for common CoCo-related files. I will add the entries based on feedback.
The series is based on:
- https://lore.kernel.org/all/20260921053807.354802-1-aneesh.kumar@kernel.org
Changes from v6:
https://lore.kernel.org/all/20260904103452.1197239-1-aneesh.kumar@kernel.org
* Add a common allocator and geometry/transition helpers for CoCo host-shared
memory.
* Convert GIC ITS, dma-direct, atomic DMA pools, and the dma-buf
system_cc_shared heap to the common allocator.
* Limit dma-buf scatterlist entries to the requested buffer size so rounded
backing is not exposed to importers.
Changes from v5:
https://lore.kernel.org/all/20260706060432.1375570-1-aneesh.kumar@kernel.org
* Rebased to latest kernel
* Drop patch arm64: realm: Move Realm memory encryption ops to RSI code
Changes from v4:
https://lore.kernel.org/all/20260427063108.909019-1-aneesh.kumar@kernel.org
* Rename the helpers to use CoCo terminology
(mem_cc_shared_granule_size() / mem_cc_align_to_shared_granule() instead of
mem_decrypt_granule_size() / mem_decrypt_align()).
* Use __DMA_ATTR_ALLOC_CC_SHARED to pass CoCo shared allocation requirements
down to CMA-based allocation helpers.
* Add validation for restricted DMA pools to reject pools that are not aligned
to the shared granule size.
* Add dma-buf system heap handling for cc-shared buffers.
* Split the previous combined DMA/SWIOTLB/ITS change into smaller subsystem
patches covering ITS, DMA direct, SWIOTLB, restricted DMA pools, dma-buf
system heap, and arm64 Realm support.
* Rework arm64 Realm support by moving Realm memory encryption ops into RSI
code and exposing the CCA shared granule size through arm64_mem_crypt_ops.
Changes from v3:
https://lore.kernel.org/all/20260309102625.2315725-1-aneesh.kumar@kernel.org
* Fix build error reported by kernel test robot <lkp(a)intel.com>
Changes from v2:
https://lore.kernel.org/all/20251221160920.297689-1-aneesh.kumar@kernel.org
* Rebase to latest kernel
* Consider swiotlb always decrypted and don't align when allocating from swiotlb.
Changes from v1:
* Rename the helper to mem_encrypt_align
* Improve the commit message
* Handle DMA allocations from contiguous memory
* Handle DMA allocations from the pool
* swiotlb is still considered unencrypted. Support for an encrypted swiotlb pool
is left as TODO and is independent of this series.
Cc: Andrew Morton <akpm(a)linux-foundation.org>
Cc: Catalin Marinas <catalin.marinas(a)arm.com>
Cc: christian.koenig(a)amd.com
Cc: Jason Gunthorpe <jgg(a)ziepe.ca>
Cc: Joerg Roedel (AMD) <joro(a)8bytes.org>
Cc: Marc Zyngier <maz(a)kernel.org>
Cc: Marek Szyprowski <m.szyprowski(a)samsung.com>
Cc: Robin Murphy <robin.murphy(a)arm.com>
Cc: Steven Price <steven.price(a)arm.com>
Cc: Sumit Semwal <sumit.semwal(a)linaro.org>
Cc: Suzuki K Poulose <suzuki.poulose(a)arm.com>
Cc: Thomas Gleixner <tglx(a)kernel.org>
Cc: Will Deacon <will(a)kernel.org>
Cc: dri-devel(a)lists.freedesktop.org
Cc: iommu(a)lists.linux.dev
Cc: linaro-mm-sig(a)lists.linaro.org
Cc: linux-arm-kernel(a)lists.infradead.org
Cc: linux-kernel(a)vger.kernel.org
Cc: linux-media(a)vger.kernel.org
Cc: linux-mm(a)kvack.org
Aneesh Kumar K.V (Arm) (13):
arm64: realm: Add RHI helper to query IPA state change alignment
mm: Add an allocator for CoCo shared memory
arm64: realm: Expose the CCA shared granule size through mem_encrypt
ops
irqchip/gic-v3-its: Resolve the default NUMA node explicitly
irqchip/gic-v3-its: Allocate shared tables using CoCo shared memory
allocator
dma-contiguous: Accept an explicit minimum alignment
dma-pool: Allocate CoCo atomic pools using CoCo shared memory
allocator
dma-direct: Align CoCo shared DMA allocations to the shared granule
size
swiotlb: Align shared IO TLB pools to the shared granule size
swiotlb: Reject misaligned restricted DMA pools for CoCo guests
dma-buf: system_heap: Limit scatterlist entries to the buffer size
dma-buf: system_heap: Allocate shared buffers using CoCo shared memory
allocator
swiotlb: Make rounded shared pool capacity allocatable
MAINTAINERS | 1 +
arch/arm/mm/dma-mapping.c | 5 +-
arch/arm64/include/asm/mem_encrypt.h | 1 +
arch/arm64/mm/mem_encrypt.c | 13 +-
drivers/dma-buf/heaps/system_heap.c | 126 +++++++++-----------
drivers/firmware/arm_rmm/rsi.c | 58 +++++++++
drivers/iommu/dma-iommu.c | 2 +-
drivers/irqchip/irq-gic-v3-its.c | 43 +++----
include/linux/arm-rsi-cmds.h | 10 ++
include/linux/arm-smccc-rhi.h | 25 ++++
include/linux/arm-smccc-rsi.h | 7 ++
include/linux/cc_shared.h | 39 ++++++
include/linux/dma-map-ops.h | 10 +-
kernel/dma/contiguous.c | 33 +++--
kernel/dma/direct.c | 55 +++++++--
kernel/dma/ops_helpers.c | 2 +-
kernel/dma/pool.c | 23 +++-
kernel/dma/swiotlb.c | 81 +++++++++----
kernel/kexec_file.c | 3 +-
mm/Makefile | 1 +
mm/cc_shared.c | 172 +++++++++++++++++++++++++++
21 files changed, 552 insertions(+), 158 deletions(-)
create mode 100644 include/linux/arm-smccc-rhi.h
create mode 100644 include/linux/cc_shared.h
create mode 100644 mm/cc_shared.c
--
2.43.0
On 9/23/26 09:42, Jianfeng Liu wrote:
> [Sie erhalten nicht häufig E-Mails von liujianfeng1994(a)gmail.com. Weitere Informationen, warum dies wichtig ist, finden Sie unter https://aka.ms/LearnAboutSenderIdentification ]
>
> Commit 143755bdabaa9 ("dma-buf: Make DMABUF_DEBUG default to y on
> DEBUG_KERNEL kernels") fixed a dangling reference in the DMABUF_DEBUG
> default, which had the side effect of enabling the option (and with it
> the page-stripping sg_table wrapper handed to importers) on every
> kernel with DEBUG_KERNEL=y - i.e. virtually every distro kernel.
>
> drm/msm is broken by this: it maps imported dma-bufs into the GPU's
> own pagetables with iommu_map_sgtable(), which needs the struct page
> of the attachment sg_table, and it fills the GEM object's page array
> through drm_prime_sg_to_page_array(). With the debug wrapper in
> place both silently produce garbage (the wrapper zeroes sg->length,
Interesting point, we should probably change that.
> so the page iterator yields nothing and an uninitialized array is
> kept). The VM_BIND map job then fails asynchronously after userspace
> has already enqueued GPU work referencing the mapping, which shows up
> as an arm-smmu translation fault from UCHE, e.g.:
>
> gpu fault: ttbr0=000000088a889000 iova=000000010741c000 dir=READ
> type=TRANSLATION source=UCHE
>
> This breaks hardware video decode (clapper, chromium) on Adreno
> systems; bisected on a Snapdragon laptop as v7.3-rc3 good,
> v7.3-rc4 bad, culprit 143755bdabaa9.
>
> Revert the default until importers that legitimately need to build
> phys-based mappings have been converted.
Well that won't work like this, pointing those things out is exactly what DMABUF_DEBUG is made for.
What MSM is doing here is not allowed at all and can break badly. We gave drivers 5 years to get that fixed and I'm now pushing for completely deprecating that hack.
See patch 84335675f2223cbd25d0de7d38ecc7d40b95bd4a:
Author: Simona Vetter <simona.vetter(a)ffwll.ch>
Date: Fri Jan 15 17:47:39 2021 +0100
dma-buf: Add debug option
When MSM needs the struct page then it must import a shmemfd and not a DMA-buf. What we could do is to either fix MSM or mark it as broken.
Regards,
Christian.
>
> Fixes: 143755bdabaa9 ("dma-buf: Make DMABUF_DEBUG default to y on DEBUG_KERNEL kernels")
> Signed-off-by: Jianfeng Liu <liujianfeng1994(a)gmail.com>
> ---
>
> drivers/dma-buf/Kconfig | 9 ++++++++-
> 1 file changed, 8 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/dma-buf/Kconfig b/drivers/dma-buf/Kconfig
> index e4f078a326a41..b3c581ef4c987 100644
> --- a/drivers/dma-buf/Kconfig
> +++ b/drivers/dma-buf/Kconfig
> @@ -43,7 +43,14 @@ config UDMABUF
> config DMABUF_DEBUG
> bool "DMA-BUF debug checks"
> depends on DMA_SHARED_BUFFER
> - default y if DEBUG_KERNEL
> + # NOTE: keep this default n. The page-stripping sg_table wrapper that
> + # this option installs for importers breaks drivers that build a
> + # second-stage IOMMU mapping (phys -> iova) from the attachment sg_table
> + # and therefore still need the struct page, e.g. drm/msm with its
> + # per-process GPU pagetables. Until those importers are fixed, making
> + # this default y breaks hardware video decode and GPU workloads out of
> + # the box on affected systems.
> + default n
> help
> This option enables additional checks for DMA-BUF importers and
> exporters. Specifically it validates that importers do not peek at the
> --
> 2.47.3
>
On 9/22/26 18:57, Jeffrey Boody wrote:
> The set_deadline callback is currently skipped if the fence has already
> been signaled. This prevents GPU drivers from performing power
> management adjustments when the deadline hint arrives after fence
> completion.
>
> In triple-buffered rendering, a staged frame may be completed well
> ahead of the vblank deadline. When a display driver delivers the
> deadline hint, the fence has already been signaled and the callback is
> silently dropped. This leaves the GPU driver unable to evaluate the
> headroom between the fence signal time and the vblank deadline, and
> therefore unable to reduce GPU frequency when the target headroom is
> exceeded.
>
> Remove the dma_fence_is_signaled() guard from dma_fence_set_deadline()
> so that the callback is invoked unconditionally when ops->set_deadline
> is present. Implementations of set_deadline must already tolerate
> concurrent and repeated calls; handling a post-signal invocation
> requires no additional locking. The fence signaler can compare the fence
> signal time against the supplied deadline to determine whether frequency
> scaling is warranted.
Sorry but I have to clearly reject that patch.
No callback whatsoever is allowed to be used after the fence has signaled or otherwise we break module unloading for the originator of the fence.
So that approach you want to have here simply doesn't work at all.
Regards,
Christian.
>
> Signed-off-by: Jeffrey Boody <jeffrey.boody(a)oss.qualcomm.com>
> ---
> Signed-off-by: Jeff Boody <jeffrey.boody(a)oss.qualcomm.com>
> ---
> drivers/dma-buf/dma-fence.c | 22 ++++++++++++++++++++--
> drivers/gpu/drm/msm/msm_fence.c | 3 +++
> include/linux/dma-fence.h | 11 ++++++++++-
> 3 files changed, 33 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/dma-buf/dma-fence.c b/drivers/dma-buf/dma-fence.c
> index bd58688b81a7..ebc7c5ca6f69 100644
> --- a/drivers/dma-buf/dma-fence.c
> +++ b/drivers/dma-buf/dma-fence.c
> @@ -999,8 +999,19 @@ EXPORT_SYMBOL(dma_fence_wait_any_timeout);
> * Multiple deadlines may be set on a given fence, even in parallel. See the
> * documentation for &dma_fence_ops.set_deadline.
> *
> + * The deadline hint may also be delivered *after* the fence has already been
> + * signaled. This is intentional and supports the case where a fence signaler
> + * aware of a periodic deadline (e.g. vblank) and the fence's signal time can
> + * evaluate the headroom between the two. In triple-buffered rendering, for
> + * example, a staged frame that is completed well ahead of the vblank deadline
> + * represents excess headroom; delivering the deadline hint post-signal allows
> + * the fence signaler to consider reducing frequency for subsequent workloads,
> + * rather than holding an unnecessarily high frequency. Implementations
> + * of &dma_fence_ops.set_deadline must therefore tolerate invocation on
> + * already-signaled fences.
> + *
> * The deadline hint is just that, a hint. The driver that created the fence
> - * may react by increasing frequency, making different scheduling choices, etc.
> + * may react by changing frequency, making different scheduling choices, etc.
> * Or doing nothing at all.
> */
>
> @@ -1016,6 +1027,13 @@ EXPORT_SYMBOL(dma_fence_wait_any_timeout);
> * to aid in power management decisions, such as boosting GPU frequency
> * if a periodic vblank deadline is approaching but the fence is not
> * yet signaled..
> + *
> + * This function may also be called after the fence has already been
> + * signaled. In that case the fence signaler can compare the fence's signal
> + * time against the deadline to determine the available headroom. If the
> + * fence was signaled significantly ahead of the deadline, the fence
> + * signaler may choose to reduce frequency for subsequent workloads to
> + * avoid unnecessarily high power consumption.
> */
> void dma_fence_set_deadline(struct dma_fence *fence, ktime_t deadline)
> {
> @@ -1023,7 +1041,7 @@ void dma_fence_set_deadline(struct dma_fence *fence, ktime_t deadline)
>
> rcu_read_lock();
> ops = rcu_dereference(fence->ops);
> - if (ops && ops->set_deadline && !dma_fence_is_signaled(fence))
> + if (ops && ops->set_deadline)
> ops->set_deadline(fence, deadline);
> rcu_read_unlock();
> }
> diff --git a/drivers/gpu/drm/msm/msm_fence.c b/drivers/gpu/drm/msm/msm_fence.c
> index 3dca8e09c192..3c5de96d4092 100644
> --- a/drivers/gpu/drm/msm/msm_fence.c
> +++ b/drivers/gpu/drm/msm/msm_fence.c
> @@ -136,6 +136,9 @@ static void msm_fence_set_deadline(struct dma_fence *fence, ktime_t deadline)
> unsigned long flags;
> ktime_t now;
>
> + if (dma_fence_is_signaled(fence))
> + return;
> +
> spin_lock_irqsave(&fctx->spinlock, flags);
> now = ktime_get();
>
> diff --git a/include/linux/dma-fence.h b/include/linux/dma-fence.h
> index ffa99b930843..839ef2e5dad9 100644
> --- a/include/linux/dma-fence.h
> +++ b/include/linux/dma-fence.h
> @@ -264,7 +264,16 @@ struct dma_fence_ops {
> * an upcoming deadline, such as vblank, by which point the waiter
> * would prefer the fence to be signaled by. This is intended to
> * give feedback to the fence signaler to aid in power management
> - * decisions, such as boosting GPU frequency.
> + * decisions, such as boosting GPU frequency if the deadline has
> + * not yet been met, or reducing GPU frequency if the fence was
> + * signaled significantly ahead of the deadline.
> + *
> + * This callback may be invoked even after the fence has been
> + * signaled. In this case, the signaler may use the deadline and
> + * the fence's signal time to evaluate whether the GPU frequency
> + * should be adjusted for future workloads. Implementations must
> + * therefore be prepared to handle calls on already-signaled fences
> + * without error.
> *
> * This is called without &dma_fence.lock held, it can be called
> * multiple times and from any context. Locking is up to the callee
>
> ---
> base-commit: f0100363d8c374bd8e9ea7c9ba02744f0b802ca4
> change-id: 20260917-dma-fence-set-deadline-a778746e9abd
>
> Best regards,
> --
> Jeff Boody <jeffrey.boody(a)oss.qualcomm.com>
>
On Tue, Sep 22, 2026 at 02:37:08PM +0100, Pavel Begunkov wrote:
>> Sashiko had a few comments, which I think are correct - if we use
>> dma_map_sg to map the data, we need to use the sync_sg APIs to
>> transfer ownership. That only matters on non-coherent architectures
>> with MMU, but we need to get it right.
>
> I've seen that and fixed everything locally that should be fixed,
> apart from the sync. I wonder what we can do about that? I can
> somehow replace it with the sg variant for now, but sync'ing the
> entire possibly multi-GB mapping for, let's say, a 512B I/O, sounds
> not wise.
If we'd want to fix this for real we'd need to add an offset to the
sync by sg methods. Or move away from scatterlists in dma-buf, given
that they are a horrible API. All of these are bigger projects,
though. So for now I think you'd want to do the sync all, and have
the people who run high-performance io_uring code on non-coherent
platforms suffer.
> And I can think of another place that does mix sync_single
> with sgs.
Which one?
On Tue, Sep 22, 2026 at 02:54:25PM +0100, Pavel Begunkov wrote:
>>
>> Can you please expland on the splitting considerations a bit? Preferably
>> both in a comment for the details, and in the commit log for how we
>> arrived at them and why they are fine for now?
>
> I'll add something to the commit log, but not sure which specific
> details in comments you mean. Do you want me to expand the comment
> above limiting the number of segments? Maybe I should add there that
> it's stricter than necessary and might cause more splitting than
> necessary? This one:
Yes, explain why we apply a relatively arbitrary limit not fully
exploiting the hardware capabilities, and why we thing that is okay.