On 7/5/26 17:16, Alexey Kardashevskiy wrote:
> On 6/5/26 23:16, Jason Gunthorpe wrote:
>> On Wed, May 06, 2026 at 12:35:42PM +1000, Alexey Kardashevskiy wrote:
>>> Hi!
>>>
>>> Let's reignite this topic.
>>>
>>> I've been using these patches + QEMU side hacks for 6+ months. And it's been fine until I got a device where MSIX BAR is in a middle of another BAR marked as TEE in the TDISP interface report. And no trusted MSIX yet.
>>>
>>> Every time QEMU mmaps a BAR - I request a dmabuf fd from VFIO in QEMU. Since mapping of an entire MSIX BAR is allowed by default, VFIORegion::nr_mmaps==1 and it is an entire BAR.
>>>
>>> Problem: KVM memslot mismatches the dmabuf fd size
>>
>> Huh? kvm does not care about dmabuf at all? Are you running other
>> patches to hook kvm and dmabuf?
>
> yup, 06/12 of this patchset.
>
>> Putting a slice in a dmabuf is a well understood need for MSI, so I
>> expect whatever kvm dmabuf interface that gets merged to accomodate
>> this?
>
> good to know.
>
>>> Solution2: modify logic in VFIO dmabuf to allow multiple KVM memory
>>> slots per dmabuf. Now it is kvm_memory_slot::dmabuf_attach with no
>>> offset into the dmabuf and one kvm_vfio_dmabuf per dma_buf.
>>
>> Yes, when kvm learns to take in a dmabuf it needs to take in a slice,
>> not the whole buf. Or you need to create multiple dmabufs with the
>> necessary slices from the VFIO. The upstream vfio dmabuf creation
>> allows creating it with a slice.
>
> true but either way dmabuf slicing will be directed by QEMU's msix-table emulation MR and this slicing needs to match the TDISP report so I'll have to teach QEMU these reports, right?
Or TDISP devices are going to align MSIX BARs to 4K, and QEMU will do the same and it should "just work", and if it does not - the host won't crash. Can this work? Thanks,
> I am worried if I miss something obvious, again. Thanks,
>
>
> ps. I like nntp.lore.kernel.org very much for ability to dig out old stuff and then just reply to it :)
>
>>
>> Jason
>
--
Alexey
virtio_gpu_cursor_plane_update() calls virtio_gpu_array_lock_resv()
but ignores its return value. The function can fail in two ways:
- dma_resv_lock_interruptible() returns -ERESTARTSYS when a signal
is delivered while waiting for the reservation lock.
- dma_resv_reserve_fences() returns -ENOMEM if it fails to allocate
a fence slot; in this case lock_resv unlocks before returning.
In both cases the resv lock is not held on return. The cursor path
proceeds to queue a fenced transfer command. The queue path then
walks the object array and calls dma_resv_add_fence() on the cursor
BO's reservation. dma_resv_add_fence() requires the resv lock to be
held; with lockdep enabled the missing lock trips
dma_resv_assert_held():
WARNING: drivers/dma-buf/dma-resv.c:296 at dma_resv_add_fence+0x71e/0x840
Call Trace:
virtio_gpu_array_add_fence+0xcd/0x140
virtio_gpu_queue_ctrl_sgs
virtio_gpu_queue_fenced_ctrl_buffer+0x578/0xfb0
virtio_gpu_cursor_plane_update+0x411/0xbc0
drm_atomic_helper_commit_planes+0x497/0xf10
...
drm_mode_cursor_ioctl+0xd4/0x110
drm_ioctl+0x5e6/0xc60
__x64_sys_ioctl+0x18e/0x210
Beyond the WARN, mutating the dma_resv fence list without the lock
races with concurrent readers/writers and can corrupt the list.
Check the return value of virtio_gpu_array_lock_resv(). On failure,
drop the references taken by virtio_gpu_array_add_obj() with
virtio_gpu_array_put_free() (which does not unlock, matching the
not-locked state) and return without queueing the command. A
skipped cursor frame is harmless; the WARN and the underlying race
are not.
The bug was reported by syzbot, triggered via fault injection
(fail_nth) on the DRM_IOCTL_MODE_CURSOR path, which forces the
-ENOMEM branch in dma_resv_reserve_fences().
Reported-by: syzbot+72bd3dd3a5d5f39a0271(a)syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=72bd3dd3a5d5f39a0271
Fixes: 5cfd31c5b3a3 ("drm/virtio: fix virtio_gpu_cursor_plane_update().")
Cc: stable(a)vger.kernel.org
Signed-off-by: Deepanshu Kartikey <kartikey406(a)gmail.com>
---
drivers/gpu/drm/virtio/virtgpu_plane.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/virtio/virtgpu_plane.c b/drivers/gpu/drm/virtio/virtgpu_plane.c
index a126d1b25f46..ca379b08b9ec 100644
--- a/drivers/gpu/drm/virtio/virtgpu_plane.c
+++ b/drivers/gpu/drm/virtio/virtgpu_plane.c
@@ -459,7 +459,10 @@ static void virtio_gpu_cursor_plane_update(struct drm_plane *plane,
if (!objs)
return;
virtio_gpu_array_add_obj(objs, vgfb->base.obj[0]);
- virtio_gpu_array_lock_resv(objs);
+ if (virtio_gpu_array_lock_resv(objs)) {
+ virtio_gpu_array_put_free(objs);
+ return;
+ }
virtio_gpu_cmd_transfer_to_host_2d
(vgdev, 0,
plane->state->crtc_w,
--
2.43.0
On Sat, May 09, 2026 at 01:31:56PM +0800, Xu Yilun wrote:
> > Would you be open to an in-between? The exporter and importer both
> > have information that should not leak into each other's drivers.
> >
> > What if the dmabuf mapping type core code was the only thing that had
> > access to *BOTH*? The exporter provides the address data, the importer
> > provides the iommu_domain. The core code, and only the core code, has
> > both and does the required operation?
>
> I think that may not work for KVM. On IOMMU side, IOMMUFD acts as the
> address space (iova) manager and dma_api/IOMMU driver acts as the
> actual page table mapper. But for KVM, it is both. KVM doesn't allow
> another component to provide an unknown address space (GPA space) and
> say "map it", so doesn't expose to other components about "KVM domain".
>
> Even if we expose "KVM domain", KVM still acts as the importer and the
> mapper, is it wierd to say we trust KVM-the-mapper, but don't trust
> KVM-the-as-manager?
>
> Is it also wierd that we trust IOMMU-the-mapper, but don't trust
> IOMMUFD-the-as-manager? There are more IOMMU drivers than IOMMUFD...
Yeah, it doesn't work well for kvm, and yes it is really weird and
worse that phys in every way..
Jason
On Thu, May 07, 2026 at 05:16:56PM +1000, Alexey Kardashevskiy wrote:
> true but either way dmabuf slicing will be directed by QEMU's
> msix-table emulation MR and this slicing needs to match the TDISP
> report so I'll have to teach QEMU these reports, right? I am worried
> if I miss something obvious, again. Thanks,
I don't think so.. It just needs to slice it into the MSI page
blindly. When the VM goes to validate the TDISP report against the
mappings it will fail to accept the device if there is a mismatch.
The only thing qemu could do is fail sooner, but I don't know that is
worth the complexity as we do expect all devices to have their MSI
range unprotected.
Jason
Hi,
This is a patch series covering the support for protected mode execution in
Mali Panthor CSF kernel driver.
It builds on the initial RFC posted by Florent Tomasin back in January of 2025.
The initial RFC can be found here:
https://lore.kernel.org/lkml/cover.1738228114.git.florent.tomasin@arm.com/
The Mali CSF GPUs come with the support for protected mode execution at the
HW level. This feature requires two main changes in the kernel driver:
1) Configure the GPU with a protected buffer. The system must provide a DMA
heap from which the driver can allocate a protected buffer.
It can be a carved-out memory or dynamically allocated protected memory region.
Some system includes a trusted FW which is in charge of the protected memory.
Since this problem is integration specific, the Mali Panthor CSF kernel
driver must import the protected memory from a device specific exporter.
2) Handle enter and exit of the GPU HW from normal to protected mode of execution.
FW sends a request for protected mode entry to the kernel driver.
The acknowledgment of that request is a scheduling decision. Effectively,
protected mode execution should not overrule normal mode of execution.
A fair distribution of execution time will guaranty the overall performance
of the device, including the UI (usually executing in normal mode),
will not regress when a protected mode job is submitted by an application.
Background
----------
Current Mali Panthor CSF driver does not allow a user space application to
execute protected jobs on the GPU. This use case is quite common on end-user-device.
A user may want to watch a video or render content that is under a "Digital Right
Management" protection, or launch an application with user private data.
1) User-space:
In order for an application to execute protected jobs on a Mali CSF GPU the
user space application must submit jobs to the GPU within a "protected regions"
(range of commands to execute in protected mode).
Find here an example of a command buffer that contains protected commands:
```
<--- Normal mode ---><--- Protected mode ---><--- Normal mode --->
+-------------------------------------------------------------------------+
| ... | CMD_0 | ... | CMD_N | PROT_REGION | CMD_N+1 | ... | CMD_N+M | ... |
+-------------------------------------------------------------------------+
```
The PROT_REGION command acts as a barrier to notify the HW of upcoming
protected jobs. It also defines the number of commands to execute in protected
mode.
The Mesa definition of the opcode can be found here:
https://gitlab.freedesktop.org/mesa/mesa/-/blob/main/src/panfrost/lib/genxm…
2) Kernel-space:
When loading the FW image, the Kernel driver must also load the data section of
CSF FW that comes from the protected memory, in order to allow FW to execute in
protected mode.
Important: this memory is not owned by any process. It is a GPU device level
protected memory.
In addition, when a CSG (group) is created, it must have a protected suspend buffer.
This memory is allocated within the kernel but bound to a specific CSG that belongs
to a process. The kernel owns this allocation and does not allow user space mapping.
The format of the data in this buffer is only known by the FW and does not need to
be shared with other entities. The purpose of this buffer is the same as the normal
suspend buffer but for protected mode. FW will use it to suspend the execution of
PROT_REGION before returning to normal mode of execution.
Design decisions
----------------
The Mali Panthor CSF kernel driver will allocate protected DMA buffers
using a global protected DMA heap. The name of the heap can vary on
the system and is integration specific. Therefore, the kernel driver
will retrieve it using the DTB entry: "protected-heap-name".
The Mali Panthor CSF kernel driver will handle enter/exit of protected
mode with a fair consideration of the job scheduling.
If the system integrator does not provide a protected DMA heap, the driver
will not allow any protected mode execution.
Patch series
------------
[PATCHES 1-2]:
Thees patches comes from the following patch series:
https://lore.kernel.org/lkml/20240720071606.27930-1-yunfei.dong@mediatek.co…
These extend the DMA-buf heap API to allow other kernel drivers to Find
and allocate memory from dma heaps.
Note: This patch series do not include a protected DMA heap, as this is
platform specific.
* dma-heap: Add proper kref handling on dma-buf heaps
* dma-heap: Provide accessors so that in-kernel drivers can allocate dmabufs from specific heaps
[PATCHES 3, 5 and 6]:
These are refactoring to aid the implementation of the protected rendering
feature itself.
* drm/panthor: De-duplicate FW memory section sync
* drm/panthor: Minor scheduler refactoring
* drm/panthor: Explicit expansion of locked VM region
[Patch 4]:
This introduces allocation of protected memory inside the Panthor driver.
It also ensures the protected FW sections are loaded.
* drm/panthor: Add support for protected memory allocation in panthor
[PATCH 7]:
This patch implements the logic to handle enter/exit of the GPU protected
mode in Panthor CSF driver.
Note: to prevent scheduler priority inversion, only a single CSG is allowed
to execute while in protected mode. It must be the top priority one.
* drm/panthor: Add support for entering and exiting protected mode
[PATCH 8]:
The final patch exposes this feature via the uAPI.
* drm/panthor: Expose protected rendering features
Testing
-------
1) Platform and development environment
Any platform containing a Mali CSF type of GPU and a protected memory allocator
that is based on DMA Heap can be used. For example, it can be a physical platform
or a simulator such as Arm Total Compute FVPs platforms. Reference to the latter:
https://developer.arm.com/Tools%20and%20Software/Fixed%20Virtual%20Platform…
2) Mesa:
PanVK support can be found here:
https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/40044
This is still work in progress.
Constraints
-----------
At the time of developing the feature, Linux kernel does not have a generic
way of implementing protected DMA heaps. The patch series relies on previous
work to expose the DMA heap API to the kernel drivers.
The Mali CSF GPU requires device level allocated protected memory, which do
not belong to a process. The current Linux implementation of DMA heap only
allows a user space program to allocate from such heap. Having the ability
to allocate this memory at the kernel level via the DMA heap API would allow
support for protected mode on Mali CSF GPUs.
Florent Tomasin (3):
drm/panthor: Add support for protected memory allocation in panthor
drm/panthor: Minor scheduler refactoring
drm/panthor: Add support for entering and exiting protected mode
John Stultz (2):
dma-heap: Add proper kref handling on dma-buf heaps
dma-heap: Provide accessors so that in-kernel drivers can allocate dmabufs from specific heaps
Ketil Johnsen (3):
drm/panthor: De-duplicate FW memory section sync
drm/panthor: Explicit expansion of locked VM region
drm/panthor: Expose protected rendering features
Documentation/gpu/panthor.rst | 47 +++
drivers/dma-buf/dma-heap.c | 109 ++++++-
drivers/gpu/drm/panthor/Kconfig | 1 +
drivers/gpu/drm/panthor/panthor_device.c | 29 +-
drivers/gpu/drm/panthor/panthor_device.h | 15 +
drivers/gpu/drm/panthor/panthor_drv.c | 21 +-
drivers/gpu/drm/panthor/panthor_fw.c | 137 ++++++--
drivers/gpu/drm/panthor/panthor_fw.h | 7 +
drivers/gpu/drm/panthor/panthor_gem.c | 77 ++++-
drivers/gpu/drm/panthor/panthor_gem.h | 16 +-
drivers/gpu/drm/panthor/panthor_gpu.c | 14 +-
drivers/gpu/drm/panthor/panthor_gpu.h | 6 +
drivers/gpu/drm/panthor/panthor_heap.c | 2 +
drivers/gpu/drm/panthor/panthor_mmu.c | 79 +++--
drivers/gpu/drm/panthor/panthor_sched.c | 387 ++++++++++++++++++-----
include/linux/dma-heap.h | 8 +
include/uapi/drm/panthor_drm.h | 45 ++-
17 files changed, 864 insertions(+), 136 deletions(-)
--
2.43.0
RAM is not, in fact, cheap. Especially on embedded systems with a low
amount of memory, but known and well-defined userspace, more explicit
resource management can lead to better utilisation patterns. As an
example, a resource manager process on a purpose-built device may wish
to launch, and then explicitly swap out, memory of processes that are
kept "warm", to improve perceived startup latency of individual
full-screen applications without making the kernel figure out the usage
pattern from observation alone in order to swap out the right pages.
To allow for this explicit control in the context of panthor's GPU
memory, add two new sysfs knobs. The first, mem_reclaim, runs an
explicit priv BO reclaim cycle on the TGID written to it.
The second, mem_claim, does the opposite: it swaps BOs back into active
memory.
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli(a)collabora.com>
---
Nicolas Frattaroli (4):
drm/panthor: Add freed_sz parameter to reclaim_priv_bos
MAINTAINERS: Add sysfs ABI docs to list of panthor files
drm/panthor: Add explicit memory reclaim sysfs knob
drm/panthor: Add explicit memory claim sysfs knob
Documentation/ABI/testing/sysfs-driver-panthor-mem | 34 ++++++++
MAINTAINERS | 1 +
drivers/gpu/drm/panthor/panthor_drv.c | 93 ++++++++++++++++++++++
drivers/gpu/drm/panthor/panthor_gem.c | 7 +-
drivers/gpu/drm/panthor/panthor_gem.h | 1 +
drivers/gpu/drm/panthor/panthor_mmu.c | 70 +++++++++++++++-
drivers/gpu/drm/panthor/panthor_mmu.h | 4 +
7 files changed, 205 insertions(+), 5 deletions(-)
---
base-commit: 2c4b906cd135bbb44855287d0d0eff0ee0b47afe
change-id: 20260506-panthor-explicit-reclaim-3dffed028d8c
Best regards,
--
Nicolas Frattaroli <nicolas.frattaroli(a)collabora.com>
From: Thierry Reding <treding(a)nvidia.com>
Hi,
This series adds support for the video protection region (VPR) used on
Tegra SoC devices. It's a special region of memory that is protected
from accesses by the CPU and used to store DRM protected content (both
decrypted stream data as well as decoded video frames).
Patches 1 and 2 add DT binding documentation for the VPR and add the VPR
to the list of memory-region items for display and host1x.
Patch 3 adds bitmap_allocate(), which is like bitmap_allocate_region()
but works on sizes that are not a power of two.
Patch 4 introduces new APIs needed by the Tegra VPR implementation that
allow CMA areas to be dynamically created at runtime rather than using
the fixed, system-wide list. This is used in this driver specifically
because it can use an arbitrary number of these areas (though they are
currently limited to 4).
Patch 5 adds some infrastructure for DMA heap implementations to provide
information through debugfs.
The Tegra VPR implementation is added in patch 6. See its commit message
for more details about the specifics of this implementation.
Finally, patches 7-10 add the VPR placeholder node on Tegra234 and hook
it up to the host1x and GPU nodes so that they can make use of this
region.
Changes in v2:
- Tegra VPR implementation is now more optimized to reduce the number of
(very slow) resize operations, and allows cross-chunk allocations
- dynamic CMA areas are now trackd separately from static ones, but the
global number of CMA pages accounts for all areas
Thierry
Thierry Reding (10):
dt-bindings: reserved-memory: Document Tegra VPR
dt-bindings: display: tegra: Document memory regions
bitmap: Add bitmap_allocate() function
mm/cma: Allow dynamically creating CMA areas
dma-buf: heaps: Add debugfs support
dma-buf: heaps: Add support for Tegra VPR
arm64: tegra: Add VPR placeholder node on Tegra234
arm64: tegra: Add GPU node on Tegra234
arm64: tegra: Hook up VPR to host1x
arm64: tegra: Hook up VPR to the GPU
.../display/tegra/nvidia,tegra186-dc.yaml | 10 +
.../display/tegra/nvidia,tegra20-dc.yaml | 10 +-
.../display/tegra/nvidia,tegra20-host1x.yaml | 7 +
.../nvidia,tegra-video-protection-region.yaml | 55 +
arch/arm/mm/dma-mapping.c | 2 +-
arch/arm64/boot/dts/nvidia/tegra234.dtsi | 60 +
arch/s390/mm/init.c | 2 +-
drivers/dma-buf/dma-heap.c | 56 +
drivers/dma-buf/heaps/Kconfig | 7 +
drivers/dma-buf/heaps/Makefile | 1 +
drivers/dma-buf/heaps/cma_heap.c | 2 +-
drivers/dma-buf/heaps/tegra-vpr.c | 1265 +++++++++++++++++
include/linux/bitmap.h | 25 +-
include/linux/cma.h | 7 +-
include/linux/dma-heap.h | 2 +
include/trace/events/tegra_vpr.h | 57 +
mm/cma.c | 187 ++-
mm/cma.h | 5 +-
18 files changed, 1713 insertions(+), 47 deletions(-)
create mode 100644 Documentation/devicetree/bindings/reserved-memory/nvidia,tegra-video-protection-region.yaml
create mode 100644 drivers/dma-buf/heaps/tegra-vpr.c
create mode 100644 include/trace/events/tegra_vpr.h
--
2.52.0
Removing the signal on any feature allows to simplfy the dma_fence_array
code a lot and saves us from the need to install a callback on all fences
at the same time.
This results is less memory and CPU overhead.
v2: fix potential double locking pointed out by Tvrtko
Signed-off-by: Christian König <christian.koenig(a)amd.com>
---
drivers/dma-buf/dma-fence-array.c | 134 +++++++++++++-----------------
drivers/gpu/drm/xe/xe_vm.c | 2 +-
include/linux/dma-fence-array.h | 22 ++---
3 files changed, 66 insertions(+), 92 deletions(-)
diff --git a/drivers/dma-buf/dma-fence-array.c b/drivers/dma-buf/dma-fence-array.c
index 5e10e8df372f..8b94c6287482 100644
--- a/drivers/dma-buf/dma-fence-array.c
+++ b/drivers/dma-buf/dma-fence-array.c
@@ -42,97 +42,88 @@ static void dma_fence_array_clear_pending_error(struct dma_fence_array *array)
cmpxchg(&array->base.error, PENDING_ERROR, 0);
}
-static void irq_dma_fence_array_work(struct irq_work *wrk)
+static void dma_fence_array_cb_func(struct dma_fence *f,
+ struct dma_fence_cb *cb)
{
- struct dma_fence_array *array = container_of(wrk, typeof(*array), work);
-
- dma_fence_array_clear_pending_error(array);
+ struct dma_fence_array *array =
+ container_of(cb, struct dma_fence_array, callback);
- dma_fence_signal(&array->base);
- dma_fence_put(&array->base);
+ irq_work_queue(&array->work);
}
-static void dma_fence_array_cb_func(struct dma_fence *f,
- struct dma_fence_cb *cb)
+static bool dma_fence_array_try_add_cb(struct dma_fence_array *array)
{
- struct dma_fence_array_cb *array_cb =
- container_of(cb, struct dma_fence_array_cb, cb);
- struct dma_fence_array *array = array_cb->array;
+ while (array->num_pending) {
+ struct dma_fence *f = array->fences[array->num_pending - 1];
- dma_fence_array_set_pending_error(array, f->error);
+ if (!dma_fence_add_callback(f, &array->callback,
+ dma_fence_array_cb_func))
+ return true;
- if (atomic_dec_and_test(&array->num_pending))
- irq_work_queue(&array->work);
- else
+ dma_fence_array_set_pending_error(array, f->error);
+ --array->num_pending;
+ }
+ return false;
+}
+
+static void dma_fence_array_irq_work(struct irq_work *wrk)
+{
+ struct dma_fence_array *array = container_of(wrk, typeof(*array), work);
+
+ --array->num_pending;
+ if (!dma_fence_array_try_add_cb(array)) {
+ dma_fence_signal(&array->base);
dma_fence_put(&array->base);
+ }
}
static bool dma_fence_array_enable_signaling(struct dma_fence *fence)
{
struct dma_fence_array *array = to_dma_fence_array(fence);
- struct dma_fence_array_cb *cb = array->callbacks;
- unsigned i;
- for (i = 0; i < array->num_fences; ++i) {
- cb[i].array = array;
+ /*
+ * As we may report that the fence is signaled before all
+ * callbacks are complete, we need to take an additional
+ * reference count on the array so that we do not free it too
+ * early. The core fence handling will only hold the reference
+ * until we signal the array as complete (but that is now
+ * insufficient).
+ */
+ dma_fence_get(&array->base);
+ if (!dma_fence_array_try_add_cb(array)) {
/*
- * As we may report that the fence is signaled before all
- * callbacks are complete, we need to take an additional
- * reference count on the array so that we do not free it too
- * early. The core fence handling will only hold the reference
- * until we signal the array as complete (but that is now
- * insufficient).
+ * When all fences are already signaled we can drop the reference again
+ * and report to the caller that the array can be signaled as well.
*/
- dma_fence_get(&array->base);
- if (dma_fence_add_callback(array->fences[i], &cb[i].cb,
- dma_fence_array_cb_func)) {
- int error = array->fences[i]->error;
-
- dma_fence_array_set_pending_error(array, error);
- dma_fence_put(&array->base);
- if (atomic_dec_and_test(&array->num_pending)) {
- dma_fence_array_clear_pending_error(array);
- return false;
- }
- }
+ dma_fence_put(&array->base);
+ return false;
}
-
return true;
}
static bool dma_fence_array_signaled(struct dma_fence *fence)
{
struct dma_fence_array *array = to_dma_fence_array(fence);
- int num_pending;
+ int num_pending, error = 0;
unsigned int i;
/*
- * We need to read num_pending before checking the enable_signal bit
- * to avoid racing with the enable_signaling() implementation, which
- * might decrement the counter, and cause a partial check.
- * atomic_read_acquire() pairs with atomic_dec_and_test() in
- * dma_fence_array_enable_signaling()
- *
- * The !--num_pending check is here to account for the any_signaled case
- * if we race with enable_signaling(), that means the !num_pending check
- * in the is_signalling_enabled branch might be outdated (num_pending
- * might have been decremented), but that's fine. The user will get the
- * right value when testing again later.
+ * Reading num_pending without a memory barrier here is correct since
+ * that is only for optimization, it is perfectly acceptable to have a
+ * stale value for it. In all other cases num_pending is accessed by a
+ * single call chain.
*/
- num_pending = atomic_read_acquire(&array->num_pending);
- if (test_bit(DMA_FENCE_FLAG_ENABLE_SIGNAL_BIT, &array->base.flags)) {
- if (num_pending <= 0)
- goto signal;
- return false;
- }
+ num_pending = READ_ONCE(array->num_pending);
+ for (i = 0; i < num_pending; ++i) {
+ struct dma_fence *f = array->fences[i];
- for (i = 0; i < array->num_fences; ++i) {
- if (dma_fence_is_signaled(array->fences[i]) && !--num_pending)
- goto signal;
- }
- return false;
+ if (!dma_fence_is_signaled(f))
+ return false;
-signal:
+ if (!error)
+ error = f->error;
+ }
+ dma_fence_array_set_pending_error(array, error);
dma_fence_array_clear_pending_error(array);
return true;
}
@@ -171,15 +162,12 @@ EXPORT_SYMBOL(dma_fence_array_ops);
/**
* dma_fence_array_alloc - Allocate a custom fence array
- * @num_fences: [in] number of fences to add in the array
*
* Return dma fence array on success, NULL on failure
*/
-struct dma_fence_array *dma_fence_array_alloc(int num_fences)
+struct dma_fence_array *dma_fence_array_alloc(void)
{
- struct dma_fence_array *array;
-
- return kzalloc_flex(*array, callbacks, num_fences);
+ return kzalloc_obj(struct dma_fence_array);
}
EXPORT_SYMBOL(dma_fence_array_alloc);
@@ -203,10 +191,13 @@ void dma_fence_array_init(struct dma_fence_array *array,
WARN_ON(!num_fences || !fences);
array->num_fences = num_fences;
+ array->num_pending = num_fences;
+ array->fences = fences;
+ array->base.error = PENDING_ERROR;
dma_fence_init(&array->base, &dma_fence_array_ops, NULL, context,
seqno);
- init_irq_work(&array->work, irq_dma_fence_array_work);
+ init_irq_work(&array->work, dma_fence_array_irq_work);
/*
* dma_fence_array_enable_signaling() is invoked while holding
@@ -220,11 +211,6 @@ void dma_fence_array_init(struct dma_fence_array *array,
*/
lockdep_set_class(&array->base.inline_lock, &dma_fence_array_lock_key);
- atomic_set(&array->num_pending, num_fences);
- array->fences = fences;
-
- array->base.error = PENDING_ERROR;
-
/*
* dma_fence_array objects should never contain any other fence
* containers or otherwise we run into recursion and potential kernel
@@ -265,7 +251,7 @@ struct dma_fence_array *dma_fence_array_create(int num_fences,
{
struct dma_fence_array *array;
- array = dma_fence_array_alloc(num_fences);
+ array = dma_fence_array_alloc();
if (!array)
return NULL;
diff --git a/drivers/gpu/drm/xe/xe_vm.c b/drivers/gpu/drm/xe/xe_vm.c
index 62a87a051be7..8f472911469d 100644
--- a/drivers/gpu/drm/xe/xe_vm.c
+++ b/drivers/gpu/drm/xe/xe_vm.c
@@ -3370,7 +3370,7 @@ static struct dma_fence *ops_execute(struct xe_vm *vm,
goto err_trace;
}
- cf = dma_fence_array_alloc(n_fence);
+ cf = dma_fence_array_alloc();
if (!cf) {
fence = ERR_PTR(-ENOMEM);
goto err_out;
diff --git a/include/linux/dma-fence-array.h b/include/linux/dma-fence-array.h
index 1b1d87579c38..3ee55c0e2fa4 100644
--- a/include/linux/dma-fence-array.h
+++ b/include/linux/dma-fence-array.h
@@ -15,16 +15,6 @@
#include <linux/dma-fence.h>
#include <linux/irq_work.h>
-/**
- * struct dma_fence_array_cb - callback helper for fence array
- * @cb: fence callback structure for signaling
- * @array: reference to the parent fence array object
- */
-struct dma_fence_array_cb {
- struct dma_fence_cb cb;
- struct dma_fence_array *array;
-};
-
/**
* struct dma_fence_array - fence to represent an array of fences
* @base: fence base class
@@ -33,18 +23,17 @@ struct dma_fence_array_cb {
* @num_pending: fences in the array still pending
* @fences: array of the fences
* @work: internal irq_work function
- * @callbacks: array of callback helpers
+ * @callback: callback structure for signaling
*/
struct dma_fence_array {
struct dma_fence base;
- unsigned num_fences;
- atomic_t num_pending;
+ unsigned int num_fences;
+ unsigned int num_pending;
struct dma_fence **fences;
struct irq_work work;
-
- struct dma_fence_array_cb callbacks[] __counted_by(num_fences);
+ struct dma_fence_cb callback;
};
/**
@@ -78,11 +67,10 @@ to_dma_fence_array(struct dma_fence *fence)
for (index = 0, fence = dma_fence_array_first(head); fence; \
++(index), fence = dma_fence_array_next(head, index))
-struct dma_fence_array *dma_fence_array_alloc(int num_fences);
+struct dma_fence_array *dma_fence_array_alloc(void);
void dma_fence_array_init(struct dma_fence_array *array,
int num_fences, struct dma_fence **fences,
u64 context, unsigned seqno);
-
struct dma_fence_array *dma_fence_array_create(int num_fences,
struct dma_fence **fences,
u64 context, unsigned seqno);
--
2.43.0