summaryrefslogtreecommitdiff
path: root/drivers/dma-buf
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2026-06-17 10:21:00 +0100
committerLinus Torvalds <torvalds@linux-foundation.org>2026-06-17 10:21:00 +0100
commit4b99990cdf9560e8a071640baf19f312e6ae02f4 (patch)
treeba3c58e860666130caf5ae3bf386b6dbfbe59b04 /drivers/dma-buf
parent9c87e61e3c5797277407ba5eae4eac8a52be3fa3 (diff)
parent52d4ab1ca790a668cc8f2c27017138b1c467168c (diff)
Merge tag 'drm-next-2026-06-17' of https://gitlab.freedesktop.org/drm/kernel
Pull drm updates from Dave Airlie: "Highlights: - xe: add initial CRI platform support - amdgpu: initial HDMI 2.1 FRL support - rust: add some new type concepts for device lifetimes - scheduler: moves to a fair algorithm and lots of cleanups But it's mostly the usual mountain of changes across the board. core: - add docbook for DRM_IOCTL_SYNCOBJ_EVENTFD - change signature of drm_connector_attach_hdr_output_metadata_property - dedup counter and timestamp retrieval in vblank code - parse AMD VSDB v3 in CTA extension blocks - add P230, Y7, XYYY2101010, T430, XVUY210101010 formats - don't call drop master on file close if not master - use drm_printf_indent in atomic / bridge - fix 32b format descriptions - docs: fix toctree - hdmi: add common TMDS character rates - fix drm_syncobj_find_fence leak rust: - introduce Higher-Ranked lifetime types - replace drvdata with scoped registration data - add GPUVM immediate mode abstraction for rust GPU drivers - introduce DeviceContext type state for drm::Device bridge: - clarify drm_bridge_get/put - create drm_get_bridge_by_endpoint and use it - analogix_dp: add panel probing - ite-it6211 - use drm audio hdmi helpers buddy: - add lockdep annotations dp: - add PR and VRR updates - mst: fix buffer overflows - add Adaptive Sync SDP decoding support - fix OOB reads in dp-mst ttm: - bump fpfn/lpfn to 64-bit scheduler: - change default to fair scheduler - map runqueue 1:1 with scheduler dma-buf: - port selftests to kunit - convert dma-buf system/heap allocators to module - add separate DMABUF_HEAPS_SYSTEM_CC_SHARED Kconfig udmabuf: - revert hugetlb support - fix error with CONFIG_DMA_API_DEBUG dma-fence: - fix tracepoints lifetime - remove unused signal on any support ras: - add clear error counter netlink command to drm ras gpusvm: - reject VMAs with VM_IO or VM_PFNMAP when creating SVM ranges - use IOVA allocations pagemap: - use IOVA allocations panels: - update to use ref counts - add support for CSW PNB601LS1-2, LGD LP116WHA-SPB1 - add support for waveshare panels - CMN N116BCN-EA1, CMN N140HCA-EEK, IVO M140NWFQ R5, - IVO, R140NWFW R0, BOE NT140*, BOE NV133FHM-N4F, - AUO B140*, AUO B133HAN06.6 and AUO B116XTN02.3 eDP panels - Surface Pro 12 Panel xe: - add CRI PCI-IDs - debugfs add multi-lrc info - engine init cleanup - PF fair scheduling auto provisioning - system controller support for CRI/Xe3p - PXP state machine fixes - Reset/wedge/unload corner case fixes - Wedge path memory allocation fixes - PAT type cleanups - Reject unsafe PAT for CPU cached memory - OA improvements for CRI device memory - kernel doc syntax in xe headers - xe_drm.h documentation fixes - include guard cleanups - VF CCS memory pool - i915/xe step unification - Xe3p GT tuning fixes - forcewake cleanup in GT and GuC - admin-only PF mode - enable hwmon energy attributes for CRI - enable GT_MI_USER_INTERRUPT - refactor emit functions - oa workarounds - multi_queue: allow QUEUE_TIMESTAMP register - convert stolen memory to ttm range manager - use xe2 style blitter as a feature flag - make drm_driver const - add/use IRQ page to HW engine definition - fix oops when display disabled i915: - enable PIPEDMC_ERROR interrupt - more common display code refactoring - restructure DP/HDMI sink format handling - eliminate FB usage from lowlevel pinning code - panel replay bw optimization - integrate sharpness filter into the scaler - new fb_pin abstraction for xe/i915 fb transparent handling - skip inactive MST connectors on HDCP - start switching to display specific registers - use polling when irq unavailable - Adaptive-sync SDP prep amdgpu: - use drm_display_info for AMD VSDB data - Initial HDMI 2.1 FRL support - Initial DCN 4.2.1 support - GART fixes for non-4k pages - GC 11.5.6/SDMA 6.4.0/and other new IPs - GFX9/DCE6/Hawaii/SDMA4/GART/Userq fixes - Finish support for using multiple SDMA queues for TTM operations - SWSMU updates - GC 12.1 updates - SMU 15.0.8 updates - DCN 4.2 updates - DC type conversion fixes - Enable DC power module - Replay/PSR updates - SMU 13.x updates - Compute queue quantum MQD updates - ASPM fix - Align VKMS with common implementation - DC analog support fixes - UVD 3 fixes - TCC harvesting fixes for SI - GC 11 APU module reload fix - NBIO 6.3.2 support - IH 7.1 updates - DC cursor fixes - VCN/JPEG user fence fixes - DC support for connectors without DDC - Prefer ROM BAR for default VGA device - DC bandwidth fixes - Add PTL support for profiler - Introduce dc_plane_cm and migrate surface update color path - Add FRL registers for HDMI 2.1 - Restructure VM state machine - Auxless ALPM support - GEM_OP locking/warning fixes - switch to system_dfl_wq amdkfd: - GPUVM TLB flush fix - Hotplug fix - Boundary check fixes - SVM fixes - CRIU fixes - add profiler API - MES 12.1 updates msm: - core: - fix shrinker documentation - IFPC enabled for gen8 - PERFCNTR_CONFIG ioctl support - GPU: - reworked UBWC handling - a810 support - MDSS: - add support for Milos platform - reworked UBWC handling - DisplayPort: - reworked HPD handling as prep for MST - DPU: - Milos platform support - reworked UBWC handling - DSI: - Milos platform support nova: - Hopper/Blackwell enablement (GH100/GB100/GB202) - FSP support - 32-bit firmware support - HAL functions - refactor GSP boot/unload - GA100 support - VBIOS hardening/refactoring - Adopt higher order lifetime types tyr: - define register blocks - add shmem backed GEM objects - adopt higher order lifetime types - move clock cleanup into Drop radeon: - Hawaii SMU fixes - CS parser fix - use struct drm_edid instead of edid amdxdna: - export per-client BO memory via fdinfo - AIE4 device support - support medium/lower power modes - expandable device heap support - revert read-only user-pointer BO mappings ivpu: - support frequency limiting panthor: - enable GEM shrinker support - add eviction and reclaim info to fdinfo v3d: - enable runtime PM mgag200: - support XRGB1555 + C8 ast: - support XRGB1555 + C8 - use constants for lots of registers - fix register handling imagination: - fence handling refactoring nouveau: - fix sched double call - expose VBIOS on GSP-RM systems - add GA100 support virtio: - add VIRTIO_GPU_F_BLOB_ALIGNMENT flag - add deferred mapping support gud: - add RCade Display Adapter hibmc: - fix no connectors usage mediatek: - hdmi: convert error handling - simplify mtk_crtc allocation exynos: - move fbdev emulation to drm client buffers - use drm format helpers for geometry/size - adopt core DMA tracking - fix framebuffer offset handling renesas: - add RZ/T2H SOC support versilicon: - add cursor plane support tegra: - use drm client for framebuffer" * tag 'drm-next-2026-06-17' of https://gitlab.freedesktop.org/drm/kernel: (1731 commits) dma-buf: move system_cc_shared heap under separate Kconfig accel/amdxdna: Clear sva pointer after unbind agp/amd64: Fix broken error propagation in agp_amd64_probe() accel/amdxdna: Require carveout when PASID and force_iova are disabled drm/amdkfd: always resume_all after suspend_all drm/amdgpu/gfx: move fault and EOP IRQ get/put to hw_init/hw_fini drm/amd/display: Consult MCCS FreeSync cap only if requested & supported drm/amd/pm: Use strscpy in profile mode parsing drm/amdkfd: Fix infinite loop parsing CRAT with zero subtype length drm/amdkfd: fix sysfs topology prop length on buffer truncation drm/amdgpu: drop retry loop in amdgpu_hmm_range_get_pages drm/amd/pm: bound OD parameter parsing to stack array size drm/amd/pm: Stop pp_od_clk_voltage emit at PAGE_SIZE drm/amdkfd: Unwind debug trap enable on copy_to_user failure drm/amdgpu: validate the mes firmware version for gfx12.1 drm/amdgpu: validate the mes firmware version for gfx12 drm/amdgpu: compare MES firmware version ucode for gfx11 drm/amdkfd: Add bounds check for AMDKFD_IOC_WAIT_EVENTS drm/amdgpu: restart the CS if some parts of the VM are still invalidated drm/amd/display: use unsigned types for local pipe and REG_GET counters ...
Diffstat (limited to 'drivers/dma-buf')
-rw-r--r--drivers/dma-buf/.kunitconfig2
-rw-r--r--drivers/dma-buf/Kconfig11
-rw-r--r--drivers/dma-buf/Makefile5
-rw-r--r--drivers/dma-buf/dma-fence-array.c13
-rw-r--r--drivers/dma-buf/dma-fence-unwrap.c3
-rw-r--r--drivers/dma-buf/dma-fence.c3
-rw-r--r--drivers/dma-buf/dma-heap.c1
-rw-r--r--drivers/dma-buf/dma-resv.c3
-rw-r--r--drivers/dma-buf/heaps/Kconfig12
-rw-r--r--drivers/dma-buf/heaps/cma_heap.c3
-rw-r--r--drivers/dma-buf/heaps/system_heap.c21
-rw-r--r--drivers/dma-buf/selftest.c167
-rw-r--r--drivers/dma-buf/selftest.h30
-rw-r--r--drivers/dma-buf/selftests.h16
-rw-r--r--drivers/dma-buf/st-dma-fence-chain.c213
-rw-r--r--drivers/dma-buf/st-dma-fence-unwrap.c294
-rw-r--r--drivers/dma-buf/st-dma-fence.c200
-rw-r--r--drivers/dma-buf/st-dma-resv.c145
-rw-r--r--drivers/dma-buf/udmabuf.c58
19 files changed, 449 insertions, 751 deletions
diff --git a/drivers/dma-buf/.kunitconfig b/drivers/dma-buf/.kunitconfig
new file mode 100644
index 000000000000..1ce5fb7e6cf9
--- /dev/null
+++ b/drivers/dma-buf/.kunitconfig
@@ -0,0 +1,2 @@
+CONFIG_KUNIT=y
+CONFIG_DMABUF_KUNIT_TEST=y
diff --git a/drivers/dma-buf/Kconfig b/drivers/dma-buf/Kconfig
index 8d4f2f89f24e..7efc0f0d0712 100644
--- a/drivers/dma-buf/Kconfig
+++ b/drivers/dma-buf/Kconfig
@@ -49,10 +49,13 @@ config DMABUF_DEBUG
exporters. Specifically it validates that importers do not peek at the
underlying struct page when they import a buffer.
-config DMABUF_SELFTESTS
- tristate "Selftests for the dma-buf interfaces"
- default n
- depends on DMA_SHARED_BUFFER
+config DMABUF_KUNIT_TEST
+ tristate "KUnit tests for DMA-BUF" if !KUNIT_ALL_TESTS
+ depends on KUNIT
+ select DMA_SHARED_BUFFER
+ default KUNIT_ALL_TESTS
+ help
+ Enable kunit tests for DMA-BUF
menuconfig DMABUF_HEAPS
bool "DMA-BUF Userland Memory Heaps"
diff --git a/drivers/dma-buf/Makefile b/drivers/dma-buf/Makefile
index 7a85565d906b..b25d7550bacf 100644
--- a/drivers/dma-buf/Makefile
+++ b/drivers/dma-buf/Makefile
@@ -7,11 +7,10 @@ obj-$(CONFIG_SYNC_FILE) += sync_file.o
obj-$(CONFIG_SW_SYNC) += sw_sync.o sync_debug.o
obj-$(CONFIG_UDMABUF) += udmabuf.o
-dmabuf_selftests-y := \
- selftest.o \
+dmabuf_kunit-y := \
st-dma-fence.o \
st-dma-fence-chain.o \
st-dma-fence-unwrap.o \
st-dma-resv.o
-obj-$(CONFIG_DMABUF_SELFTESTS) += dmabuf_selftests.o
+obj-$(CONFIG_DMABUF_KUNIT_TEST) += dmabuf_kunit.o
diff --git a/drivers/dma-buf/dma-fence-array.c b/drivers/dma-buf/dma-fence-array.c
index 089f69469524..5e10e8df372f 100644
--- a/drivers/dma-buf/dma-fence-array.c
+++ b/drivers/dma-buf/dma-fence-array.c
@@ -190,15 +190,13 @@ EXPORT_SYMBOL(dma_fence_array_alloc);
* @fences: [in] array containing the fences
* @context: [in] fence context to use
* @seqno: [in] sequence number to use
- * @signal_on_any: [in] signal on any fence in the array
*
* Implementation of @dma_fence_array_create without allocation. Useful to init
* a preallocated dma fence array in the path of reclaim or dma fence signaling.
*/
void dma_fence_array_init(struct dma_fence_array *array,
int num_fences, struct dma_fence **fences,
- u64 context, unsigned seqno,
- bool signal_on_any)
+ u64 context, unsigned seqno)
{
static struct lock_class_key dma_fence_array_lock_key;
@@ -222,7 +220,7 @@ 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, signal_on_any ? 1 : num_fences);
+ atomic_set(&array->num_pending, num_fences);
array->fences = fences;
array->base.error = PENDING_ERROR;
@@ -249,7 +247,6 @@ EXPORT_SYMBOL(dma_fence_array_init);
* @fences: [in] array containing the fences
* @context: [in] fence context to use
* @seqno: [in] sequence number to use
- * @signal_on_any: [in] signal on any fence in the array
*
* Allocate a dma_fence_array object and initialize the base fence with
* dma_fence_init().
@@ -264,8 +261,7 @@ EXPORT_SYMBOL(dma_fence_array_init);
*/
struct dma_fence_array *dma_fence_array_create(int num_fences,
struct dma_fence **fences,
- u64 context, unsigned seqno,
- bool signal_on_any)
+ u64 context, unsigned seqno)
{
struct dma_fence_array *array;
@@ -273,8 +269,7 @@ struct dma_fence_array *dma_fence_array_create(int num_fences,
if (!array)
return NULL;
- dma_fence_array_init(array, num_fences, fences,
- context, seqno, signal_on_any);
+ dma_fence_array_init(array, num_fences, fences, context, seqno);
return array;
}
diff --git a/drivers/dma-buf/dma-fence-unwrap.c b/drivers/dma-buf/dma-fence-unwrap.c
index 07fe9bf45aea..53bb40e70b27 100644
--- a/drivers/dma-buf/dma-fence-unwrap.c
+++ b/drivers/dma-buf/dma-fence-unwrap.c
@@ -180,8 +180,7 @@ struct dma_fence *__dma_fence_unwrap_merge(unsigned int num_fences,
if (count > 1) {
result = dma_fence_array_create(count, array,
- dma_fence_context_alloc(1),
- 1, false);
+ dma_fence_context_alloc(1), 1);
if (!result) {
for (i = 0; i < count; i++)
dma_fence_put(array[i]);
diff --git a/drivers/dma-buf/dma-fence.c b/drivers/dma-buf/dma-fence.c
index a2aa82f4eedd..b3bfa6943a8e 100644
--- a/drivers/dma-buf/dma-fence.c
+++ b/drivers/dma-buf/dma-fence.c
@@ -363,6 +363,8 @@ void dma_fence_signal_timestamp_locked(struct dma_fence *fence,
&fence->flags)))
return;
+ trace_dma_fence_signaled(fence);
+
/*
* When neither a release nor a wait operation is specified set the ops
* pointer to NULL to allow the fence structure to become independent
@@ -377,7 +379,6 @@ void dma_fence_signal_timestamp_locked(struct dma_fence *fence,
fence->timestamp = timestamp;
set_bit(DMA_FENCE_FLAG_TIMESTAMP_BIT, &fence->flags);
- trace_dma_fence_signaled(fence);
list_for_each_entry_safe(cur, tmp, &cb_list, node) {
INIT_LIST_HEAD(&cur->node);
diff --git a/drivers/dma-buf/dma-heap.c b/drivers/dma-buf/dma-heap.c
index ac5f8685a649..a76bf3f8b071 100644
--- a/drivers/dma-buf/dma-heap.c
+++ b/drivers/dma-buf/dma-heap.c
@@ -53,6 +53,7 @@ bool __read_mostly mem_accounting;
module_param(mem_accounting, bool, 0444);
MODULE_PARM_DESC(mem_accounting,
"Enable cgroup-based memory accounting for dma-buf heap allocations (default=false).");
+EXPORT_SYMBOL_NS_GPL(mem_accounting, "DMA_BUF_HEAP");
static int dma_heap_buffer_alloc(struct dma_heap *heap, size_t len,
u32 fd_flags,
diff --git a/drivers/dma-buf/dma-resv.c b/drivers/dma-buf/dma-resv.c
index ce9e6c04897f..39a92d9f2413 100644
--- a/drivers/dma-buf/dma-resv.c
+++ b/drivers/dma-buf/dma-resv.c
@@ -648,8 +648,7 @@ int dma_resv_get_singleton(struct dma_resv *obj, enum dma_resv_usage usage,
}
array = dma_fence_array_create(count, fences,
- dma_fence_context_alloc(1),
- 1, false);
+ dma_fence_context_alloc(1), 1);
if (!array) {
while (count--)
dma_fence_put(fences[count]);
diff --git a/drivers/dma-buf/heaps/Kconfig b/drivers/dma-buf/heaps/Kconfig
index a5eef06c4226..bb729e91545c 100644
--- a/drivers/dma-buf/heaps/Kconfig
+++ b/drivers/dma-buf/heaps/Kconfig
@@ -1,12 +1,20 @@
config DMABUF_HEAPS_SYSTEM
- bool "DMA-BUF System Heap"
+ tristate "DMA-BUF System Heap"
depends on DMABUF_HEAPS
help
Choose this option to enable the system dmabuf heap. The system heap
is backed by pages from the buddy allocator. If in doubt, say Y.
+config DMABUF_HEAPS_SYSTEM_CC_SHARED
+ bool "DMA-BUF System Heap for decrypted CoCo VMs"
+ depends on DMABUF_HEAPS && ARCH_HAS_MEM_ENCRYPT && DMABUF_HEAPS_SYSTEM=y
+ help
+ Choose this option to enable the system_cc_shared dmabuf heap. This
+ allows allocating shared (decrypted) memory for confidential computing
+ (CoCo) VMs.
+
config DMABUF_HEAPS_CMA
- bool "DMA-BUF CMA Heap"
+ tristate "DMA-BUF CMA Heap"
depends on DMABUF_HEAPS && DMA_CMA
help
Choose this option to enable dma-buf CMA heap. This heap is backed
diff --git a/drivers/dma-buf/heaps/cma_heap.c b/drivers/dma-buf/heaps/cma_heap.c
index a359aac45579..3fb4b946c91a 100644
--- a/drivers/dma-buf/heaps/cma_heap.c
+++ b/drivers/dma-buf/heaps/cma_heap.c
@@ -420,3 +420,6 @@ static int __init add_cma_heaps(void)
}
module_init(add_cma_heaps);
MODULE_DESCRIPTION("DMA-BUF CMA Heap");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("DMA_BUF");
+MODULE_IMPORT_NS("DMA_BUF_HEAP");
diff --git a/drivers/dma-buf/heaps/system_heap.c b/drivers/dma-buf/heaps/system_heap.c
index 03c2b87cb111..c8959eadc71d 100644
--- a/drivers/dma-buf/heaps/system_heap.c
+++ b/drivers/dma-buf/heaps/system_heap.c
@@ -48,6 +48,9 @@ struct dma_heap_attachment {
bool cc_shared;
};
+#define cc_shared_buffer(b) (IS_ENABLED(CONFIG_DMABUF_HEAPS_SYSTEM_CC_SHARED) && \
+ (b)->cc_shared)
+
#define LOW_ORDER_GFP (GFP_HIGHUSER | __GFP_ZERO)
#define HIGH_ORDER_GFP (((GFP_HIGHUSER | __GFP_ZERO | __GFP_NOWARN \
| __GFP_NORETRY) & ~__GFP_RECLAIM) \
@@ -161,7 +164,7 @@ static struct sg_table *system_heap_map_dma_buf(struct dma_buf_attachment *attac
unsigned long attrs;
int ret;
- attrs = a->cc_shared ? DMA_ATTR_CC_SHARED : 0;
+ attrs = cc_shared_buffer(a) ? DMA_ATTR_CC_SHARED : 0;
ret = dma_map_sgtable(attachment->dev, table, direction, attrs);
if (ret)
return ERR_PTR(ret);
@@ -233,7 +236,7 @@ static int system_heap_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma)
int i, ret;
prot = vma->vm_page_prot;
- if (buffer->cc_shared)
+ if (cc_shared_buffer(buffer))
prot = pgprot_decrypted(prot);
for_each_sgtable_sg(table, sg, i) {
@@ -282,7 +285,7 @@ static void *system_heap_do_vmap(struct system_heap_buffer *buffer)
}
prot = PAGE_KERNEL;
- if (buffer->cc_shared)
+ if (cc_shared_buffer(buffer))
prot = pgprot_decrypted(prot);
vaddr = vmap(pages, npages, VM_MAP, prot);
vfree(pages);
@@ -349,7 +352,7 @@ static void system_heap_dma_buf_release(struct dma_buf *dmabuf)
* Intentionally leak pages that cannot be re-encrypted
* to prevent shared memory from being reused.
*/
- if (buffer->cc_shared &&
+ if (cc_shared_buffer(buffer) &&
system_heap_set_page_encrypted(page))
continue;
@@ -456,7 +459,7 @@ static struct dma_buf *system_heap_allocate(struct dma_heap *heap,
list_del(&page->lru);
}
- if (cc_shared) {
+ if (cc_shared_buffer(buffer)) {
for_each_sgtable_sg(table, sg, i) {
ret = system_heap_set_page_decrypted(sg_page(sg));
if (ret)
@@ -485,7 +488,7 @@ free_pages:
* Intentionally leak pages that cannot be re-encrypted
* to prevent shared memory from being reused.
*/
- if (buffer->cc_shared &&
+ if (cc_shared_buffer(buffer) &&
system_heap_set_page_encrypted(p))
continue;
__free_pages(p, compound_order(p));
@@ -525,6 +528,7 @@ static int __init system_heap_create(void)
return PTR_ERR(sys_heap);
if (IS_ENABLED(CONFIG_HIGHMEM) ||
+ !IS_ENABLED(CONFIG_DMABUF_HEAPS_SYSTEM_CC_SHARED) ||
!cc_platform_has(CC_ATTR_MEM_ENCRYPT))
return 0;
@@ -537,3 +541,8 @@ static int __init system_heap_create(void)
return 0;
}
module_init(system_heap_create);
+
+MODULE_DESCRIPTION("DMA-BUF System Heap");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("DMA_BUF");
+MODULE_IMPORT_NS("DMA_BUF_HEAP");
diff --git a/drivers/dma-buf/selftest.c b/drivers/dma-buf/selftest.c
deleted file mode 100644
index c60b6944b4bd..000000000000
--- a/drivers/dma-buf/selftest.c
+++ /dev/null
@@ -1,167 +0,0 @@
-/* SPDX-License-Identifier: MIT */
-
-/*
- * Copyright © 2019 Intel Corporation
- */
-
-#include <linux/compiler.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/sched/signal.h>
-#include <linux/slab.h>
-
-#include "selftest.h"
-
-enum {
-#define selftest(n, func) __idx_##n,
-#include "selftests.h"
-#undef selftest
-};
-
-#define selftest(n, f) [__idx_##n] = { .name = #n, .func = f },
-static struct selftest {
- bool enabled;
- const char *name;
- int (*func)(void);
-} selftests[] = {
-#include "selftests.h"
-};
-#undef selftest
-
-/* Embed the line number into the parameter name so that we can order tests */
-#define param(n) __PASTE(igt__, __PASTE(__PASTE(__LINE__, __), n))
-#define selftest_0(n, func, id) \
-module_param_named(id, selftests[__idx_##n].enabled, bool, 0400);
-#define selftest(n, func) selftest_0(n, func, param(n))
-#include "selftests.h"
-#undef selftest
-
-int __sanitycheck__(void)
-{
- pr_debug("Hello World!\n");
- return 0;
-}
-
-static char *__st_filter;
-
-static bool apply_subtest_filter(const char *caller, const char *name)
-{
- char *filter, *sep, *tok;
- bool result = true;
-
- filter = kstrdup(__st_filter, GFP_KERNEL);
- for (sep = filter; (tok = strsep(&sep, ","));) {
- bool allow = true;
- char *sl;
-
- if (*tok == '!') {
- allow = false;
- tok++;
- }
-
- if (*tok == '\0')
- continue;
-
- sl = strchr(tok, '/');
- if (sl) {
- *sl++ = '\0';
- if (strcmp(tok, caller)) {
- if (allow)
- result = false;
- continue;
- }
- tok = sl;
- }
-
- if (strcmp(tok, name)) {
- if (allow)
- result = false;
- continue;
- }
-
- result = allow;
- break;
- }
- kfree(filter);
-
- return result;
-}
-
-int
-__subtests(const char *caller, const struct subtest *st, int count, void *data)
-{
- int err;
-
- for (; count--; st++) {
- cond_resched();
- if (signal_pending(current))
- return -EINTR;
-
- if (!apply_subtest_filter(caller, st->name))
- continue;
-
- pr_info("dma-buf: Running %s/%s\n", caller, st->name);
-
- err = st->func(data);
- if (err && err != -EINTR) {
- pr_err("dma-buf/%s: %s failed with error %d\n",
- caller, st->name, err);
- return err;
- }
- }
-
- return 0;
-}
-
-static void set_default_test_all(struct selftest *st, unsigned long count)
-{
- unsigned long i;
-
- for (i = 0; i < count; i++)
- if (st[i].enabled)
- return;
-
- for (i = 0; i < count; i++)
- st[i].enabled = true;
-}
-
-static int run_selftests(struct selftest *st, unsigned long count)
-{
- int err = 0;
-
- set_default_test_all(st, count);
-
- /* Tests are listed in natural order in selftests.h */
- for (; count--; st++) {
- if (!st->enabled)
- continue;
-
- pr_info("dma-buf: Running %s\n", st->name);
- err = st->func();
- if (err)
- break;
- }
-
- if (WARN(err > 0 || err == -ENOTTY,
- "%s returned %d, conflicting with selftest's magic values!\n",
- st->name, err))
- err = -1;
-
- return err;
-}
-
-static int __init st_init(void)
-{
- return run_selftests(selftests, ARRAY_SIZE(selftests));
-}
-
-static void __exit st_exit(void)
-{
-}
-
-module_param_named(st_filter, __st_filter, charp, 0400);
-module_init(st_init);
-module_exit(st_exit);
-
-MODULE_DESCRIPTION("Self-test harness for dma-buf");
-MODULE_LICENSE("GPL and additional rights");
diff --git a/drivers/dma-buf/selftest.h b/drivers/dma-buf/selftest.h
deleted file mode 100644
index 45793aff6142..000000000000
--- a/drivers/dma-buf/selftest.h
+++ /dev/null
@@ -1,30 +0,0 @@
-// SPDX-License-Identifier: MIT
-
-/*
- * Copyright © 2019 Intel Corporation
- */
-
-#ifndef __SELFTEST_H__
-#define __SELFTEST_H__
-
-#include <linux/compiler.h>
-
-#define selftest(name, func) int func(void);
-#include "selftests.h"
-#undef selftest
-
-struct subtest {
- int (*func)(void *data);
- const char *name;
-};
-
-int __subtests(const char *caller,
- const struct subtest *st,
- int count,
- void *data);
-#define subtests(T, data) \
- __subtests(__func__, T, ARRAY_SIZE(T), data)
-
-#define SUBTEST(x) { x, #x }
-
-#endif /* __SELFTEST_H__ */
diff --git a/drivers/dma-buf/selftests.h b/drivers/dma-buf/selftests.h
deleted file mode 100644
index 851965867d9c..000000000000
--- a/drivers/dma-buf/selftests.h
+++ /dev/null
@@ -1,16 +0,0 @@
-/* SPDX-License-Identifier: MIT */
-/* List each unit test as selftest(name, function)
- *
- * The name is used as both an enum and expanded as subtest__name to create
- * a module parameter. It must be unique and legal for a C identifier.
- *
- * The function should be of type int function(void). It may be conditionally
- * compiled using #if IS_ENABLED(CONFIG_DRM_I915_SELFTEST).
- *
- * Tests are executed in order by igt/dmabuf_selftest
- */
-selftest(sanitycheck, __sanitycheck__) /* keep first (igt selfcheck) */
-selftest(dma_fence, dma_fence)
-selftest(dma_fence_chain, dma_fence_chain)
-selftest(dma_fence_unwrap, dma_fence_unwrap)
-selftest(dma_resv, dma_resv)
diff --git a/drivers/dma-buf/st-dma-fence-chain.c b/drivers/dma-buf/st-dma-fence-chain.c
index 821023dd34df..a3023d3fedc9 100644
--- a/drivers/dma-buf/st-dma-fence-chain.c
+++ b/drivers/dma-buf/st-dma-fence-chain.c
@@ -4,6 +4,7 @@
* Copyright © 2019 Intel Corporation
*/
+#include <kunit/test.h>
#include <linux/delay.h>
#include <linux/dma-fence.h>
#include <linux/dma-fence-chain.h>
@@ -15,8 +16,6 @@
#include <linux/spinlock.h>
#include <linux/random.h>
-#include "selftest.h"
-
#define CHAIN_SZ (4 << 10)
static struct kmem_cache *slab_fences;
@@ -74,27 +73,23 @@ static struct dma_fence *mock_chain(struct dma_fence *prev,
return &f->base;
}
-static int sanitycheck(void *arg)
+static void test_sanitycheck(struct kunit *test)
{
struct dma_fence *f, *chain;
- int err = 0;
f = mock_fence();
- if (!f)
- return -ENOMEM;
+ KUNIT_ASSERT_NOT_NULL(test, f);
chain = mock_chain(NULL, f, 1);
if (chain)
dma_fence_enable_sw_signaling(chain);
else
- err = -ENOMEM;
+ KUNIT_FAIL(test, "Failed to create chain");
dma_fence_signal(f);
dma_fence_put(f);
dma_fence_put(chain);
-
- return err;
}
struct fence_chains {
@@ -176,7 +171,7 @@ static void fence_chains_fini(struct fence_chains *fc)
kvfree(fc->chains);
}
-static int find_seqno(void *arg)
+static void test_find_seqno(struct kunit *test)
{
struct fence_chains fc;
struct dma_fence *fence;
@@ -184,14 +179,13 @@ static int find_seqno(void *arg)
int i;
err = fence_chains_init(&fc, 64, seqno_inc);
- if (err)
- return err;
+ KUNIT_ASSERT_EQ_MSG(test, err, 0, "Failed to init fence chains");
fence = dma_fence_get(fc.tail);
err = dma_fence_chain_find_seqno(&fence, 0);
dma_fence_put(fence);
if (err) {
- pr_err("Reported %d for find_seqno(0)!\n", err);
+ KUNIT_FAIL(test, "Reported %d for find_seqno(0)!", err);
goto err;
}
@@ -200,14 +194,13 @@ static int find_seqno(void *arg)
err = dma_fence_chain_find_seqno(&fence, i + 1);
dma_fence_put(fence);
if (err) {
- pr_err("Reported %d for find_seqno(%d:%d)!\n",
- err, fc.chain_length + 1, i + 1);
+ KUNIT_FAIL(test, "Reported %d for find_seqno(%d:%d)!",
+ err, fc.chain_length + 1, i + 1);
goto err;
}
if (fence != fc.chains[i]) {
- pr_err("Incorrect fence reported by find_seqno(%d:%d)\n",
- fc.chain_length + 1, i + 1);
- err = -EINVAL;
+ KUNIT_FAIL(test, "Incorrect fence reported by find_seqno(%d:%d)",
+ fc.chain_length + 1, i + 1);
goto err;
}
@@ -215,12 +208,11 @@ static int find_seqno(void *arg)
err = dma_fence_chain_find_seqno(&fence, i + 1);
dma_fence_put(fence);
if (err) {
- pr_err("Error reported for finding self\n");
+ KUNIT_FAIL(test, "Error reported for finding self");
goto err;
}
if (fence != fc.chains[i]) {
- pr_err("Incorrect fence reported by find self\n");
- err = -EINVAL;
+ KUNIT_FAIL(test, "Incorrect fence reported by find self");
goto err;
}
@@ -228,9 +220,8 @@ static int find_seqno(void *arg)
err = dma_fence_chain_find_seqno(&fence, i + 2);
dma_fence_put(fence);
if (!err) {
- pr_err("Error not reported for future fence: find_seqno(%d:%d)!\n",
- i + 1, i + 2);
- err = -EINVAL;
+ KUNIT_FAIL(test, "Error not reported for future fence: find_seqno(%d:%d)!",
+ i + 1, i + 2);
goto err;
}
@@ -238,31 +229,28 @@ static int find_seqno(void *arg)
err = dma_fence_chain_find_seqno(&fence, i);
dma_fence_put(fence);
if (err) {
- pr_err("Error reported for previous fence!\n");
+ KUNIT_FAIL(test, "Error reported for previous fence!");
goto err;
}
if (i > 0 && fence != fc.chains[i - 1]) {
- pr_err("Incorrect fence reported by find_seqno(%d:%d)\n",
- i + 1, i);
- err = -EINVAL;
+ KUNIT_FAIL(test, "Incorrect fence reported by find_seqno(%d:%d)",
+ i + 1, i);
goto err;
}
}
err:
fence_chains_fini(&fc);
- return err;
}
-static int find_signaled(void *arg)
+static void test_find_signaled(struct kunit *test)
{
struct fence_chains fc;
struct dma_fence *fence;
int err;
err = fence_chains_init(&fc, 2, seqno_inc);
- if (err)
- return err;
+ KUNIT_ASSERT_EQ_MSG(test, err, 0, "Failed to init fence chains");
dma_fence_signal(fc.fences[0]);
@@ -270,37 +258,33 @@ static int find_signaled(void *arg)
err = dma_fence_chain_find_seqno(&fence, 1);
dma_fence_put(fence);
if (err) {
- pr_err("Reported %d for find_seqno()!\n", err);
+ KUNIT_FAIL(test, "Reported %d for find_seqno()!", err);
goto err;
}
if (fence && fence != fc.chains[0]) {
- pr_err("Incorrect chain-fence.seqno:%lld reported for completed seqno:1\n",
- fence->seqno);
+ KUNIT_FAIL(test, "Incorrect chain-fence.seqno:%lld reported for completed seqno:1",
+ fence->seqno);
dma_fence_get(fence);
err = dma_fence_chain_find_seqno(&fence, 1);
dma_fence_put(fence);
if (err)
- pr_err("Reported %d for finding self!\n", err);
-
- err = -EINVAL;
+ KUNIT_FAIL(test, "Reported %d for finding self!", err);
}
err:
fence_chains_fini(&fc);
- return err;
}
-static int find_out_of_order(void *arg)
+static void test_find_out_of_order(struct kunit *test)
{
struct fence_chains fc;
struct dma_fence *fence;
int err;
err = fence_chains_init(&fc, 3, seqno_inc);
- if (err)
- return err;
+ KUNIT_ASSERT_EQ_MSG(test, err, 0, "Failed to init fence chains");
dma_fence_signal(fc.fences[1]);
@@ -308,7 +292,7 @@ static int find_out_of_order(void *arg)
err = dma_fence_chain_find_seqno(&fence, 2);
dma_fence_put(fence);
if (err) {
- pr_err("Reported %d for find_seqno()!\n", err);
+ KUNIT_FAIL(test, "Reported %d for find_seqno()!", err);
goto err;
}
@@ -319,16 +303,12 @@ static int find_out_of_order(void *arg)
* we should get as fence to wait upon (fence 2 being garbage
* collected during the traversal of the chain).
*/
- if (fence != fc.chains[0]) {
- pr_err("Incorrect chain-fence.seqno:%lld reported for completed seqno:2\n",
- fence ? fence->seqno : 0);
-
- err = -EINVAL;
- }
+ if (fence != fc.chains[0])
+ KUNIT_FAIL(test, "Incorrect chain-fence.seqno:%lld reported for completed seqno:2",
+ fence ? fence->seqno : 0);
err:
fence_chains_fini(&fc);
- return err;
}
static uint64_t seqno_inc2(unsigned int i)
@@ -336,7 +316,7 @@ static uint64_t seqno_inc2(unsigned int i)
return 2 * i + 2;
}
-static int find_gap(void *arg)
+static void test_find_gap(struct kunit *test)
{
struct fence_chains fc;
struct dma_fence *fence;
@@ -344,24 +324,22 @@ static int find_gap(void *arg)
int i;
err = fence_chains_init(&fc, 64, seqno_inc2);
- if (err)
- return err;
+ KUNIT_ASSERT_EQ_MSG(test, err, 0, "Failed to init fence chains");
for (i = 0; i < fc.chain_length; i++) {
fence = dma_fence_get(fc.tail);
err = dma_fence_chain_find_seqno(&fence, 2 * i + 1);
dma_fence_put(fence);
if (err) {
- pr_err("Reported %d for find_seqno(%d:%d)!\n",
- err, fc.chain_length + 1, 2 * i + 1);
+ KUNIT_FAIL(test, "Reported %d for find_seqno(%d:%d)!",
+ err, fc.chain_length + 1, 2 * i + 1);
goto err;
}
if (fence != fc.chains[i]) {
- pr_err("Incorrect fence.seqno:%lld reported by find_seqno(%d:%d)\n",
- fence->seqno,
- fc.chain_length + 1,
- 2 * i + 1);
- err = -EINVAL;
+ KUNIT_FAIL(test, "Incorrect fence.seqno:%lld reported by find_seqno(%d:%d)",
+ fence->seqno,
+ fc.chain_length + 1,
+ 2 * i + 1);
goto err;
}
@@ -369,19 +347,17 @@ static int find_gap(void *arg)
err = dma_fence_chain_find_seqno(&fence, 2 * i + 2);
dma_fence_put(fence);
if (err) {
- pr_err("Error reported for finding self\n");
+ KUNIT_FAIL(test, "Error reported for finding self");
goto err;
}
if (fence != fc.chains[i]) {
- pr_err("Incorrect fence reported by find self\n");
- err = -EINVAL;
+ KUNIT_FAIL(test, "Incorrect fence reported by find self");
goto err;
}
}
err:
fence_chains_fini(&fc);
- return err;
}
struct find_race {
@@ -437,7 +413,7 @@ signal:
return err;
}
-static int find_race(void *arg)
+static void test_find_race(struct kunit *test)
{
struct find_race data;
int ncpus = num_online_cpus();
@@ -447,12 +423,11 @@ static int find_race(void *arg)
int i;
err = fence_chains_init(&data.fc, CHAIN_SZ, seqno_inc);
- if (err)
- return err;
+ KUNIT_ASSERT_EQ_MSG(test, err, 0, "Failed to init fence chains");
threads = kmalloc_objs(*threads, ncpus);
if (!threads) {
- err = -ENOMEM;
+ KUNIT_FAIL(test, "Failed to allocate threads array");
goto err;
}
@@ -486,74 +461,67 @@ static int find_race(void *arg)
count++;
pr_info("Completed %lu cycles\n", count);
+ KUNIT_EXPECT_EQ(test, err, 0);
+
err:
fence_chains_fini(&data.fc);
- return err;
}
-static int signal_forward(void *arg)
+static void test_signal_forward(struct kunit *test)
{
struct fence_chains fc;
int err;
int i;
err = fence_chains_init(&fc, 64, seqno_inc);
- if (err)
- return err;
+ KUNIT_ASSERT_EQ_MSG(test, err, 0, "Failed to init fence chains");
for (i = 0; i < fc.chain_length; i++) {
dma_fence_signal(fc.fences[i]);
if (!dma_fence_is_signaled(fc.chains[i])) {
- pr_err("chain[%d] not signaled!\n", i);
- err = -EINVAL;
+ KUNIT_FAIL(test, "chain[%d] not signaled!", i);
goto err;
}
if (i + 1 < fc.chain_length &&
dma_fence_is_signaled(fc.chains[i + 1])) {
- pr_err("chain[%d] is signaled!\n", i);
- err = -EINVAL;
+ KUNIT_FAIL(test, "chain[%d] is signaled!", i);
goto err;
}
}
err:
fence_chains_fini(&fc);
- return err;
}
-static int signal_backward(void *arg)
+static void test_signal_backward(struct kunit *test)
{
struct fence_chains fc;
int err;
int i;
err = fence_chains_init(&fc, 64, seqno_inc);
- if (err)
- return err;
+ KUNIT_ASSERT_EQ_MSG(test, err, 0, "Failed to init fence chains");
for (i = fc.chain_length; i--; ) {
dma_fence_signal(fc.fences[i]);
if (i > 0 && dma_fence_is_signaled(fc.chains[i])) {
- pr_err("chain[%d] is signaled!\n", i);
- err = -EINVAL;
+ KUNIT_FAIL(test, "chain[%d] is signaled!", i);
goto err;
}
}
for (i = 0; i < fc.chain_length; i++) {
if (!dma_fence_is_signaled(fc.chains[i])) {
- pr_err("chain[%d] was not signaled!\n", i);
- err = -EINVAL;
+ KUNIT_FAIL(test, "chain[%d] was not signaled!", i);
goto err;
}
}
err:
fence_chains_fini(&fc);
- return err;
}
static int __wait_fence_chains(void *arg)
@@ -566,7 +534,7 @@ static int __wait_fence_chains(void *arg)
return 0;
}
-static int wait_forward(void *arg)
+static void test_wait_forward(struct kunit *test)
{
struct fence_chains fc;
struct task_struct *tsk;
@@ -574,12 +542,11 @@ static int wait_forward(void *arg)
int i;
err = fence_chains_init(&fc, CHAIN_SZ, seqno_inc);
- if (err)
- return err;
+ KUNIT_ASSERT_EQ_MSG(test, err, 0, "Failed to init fence chains");
tsk = kthread_run(__wait_fence_chains, &fc, "dmabuf/wait");
if (IS_ERR(tsk)) {
- err = PTR_ERR(tsk);
+ KUNIT_FAIL(test, "Failed to create kthread");
goto err;
}
get_task_struct(tsk);
@@ -589,13 +556,13 @@ static int wait_forward(void *arg)
dma_fence_signal(fc.fences[i]);
err = kthread_stop_put(tsk);
+ KUNIT_EXPECT_EQ(test, err, 0);
err:
fence_chains_fini(&fc);
- return err;
}
-static int wait_backward(void *arg)
+static void test_wait_backward(struct kunit *test)
{
struct fence_chains fc;
struct task_struct *tsk;
@@ -603,12 +570,11 @@ static int wait_backward(void *arg)
int i;
err = fence_chains_init(&fc, CHAIN_SZ, seqno_inc);
- if (err)
- return err;
+ KUNIT_ASSERT_EQ_MSG(test, err, 0, "Failed to init fence chains");
tsk = kthread_run(__wait_fence_chains, &fc, "dmabuf/wait");
if (IS_ERR(tsk)) {
- err = PTR_ERR(tsk);
+ KUNIT_FAIL(test, "Failed to create kthread");
goto err;
}
get_task_struct(tsk);
@@ -618,10 +584,10 @@ static int wait_backward(void *arg)
dma_fence_signal(fc.fences[i]);
err = kthread_stop_put(tsk);
+ KUNIT_EXPECT_EQ(test, err, 0);
err:
fence_chains_fini(&fc);
- return err;
}
static void randomise_fences(struct fence_chains *fc)
@@ -640,7 +606,7 @@ static void randomise_fences(struct fence_chains *fc)
}
}
-static int wait_random(void *arg)
+static void test_wait_random(struct kunit *test)
{
struct fence_chains fc;
struct task_struct *tsk;
@@ -648,14 +614,13 @@ static int wait_random(void *arg)
int i;
err = fence_chains_init(&fc, CHAIN_SZ, seqno_inc);
- if (err)
- return err;
+ KUNIT_ASSERT_EQ_MSG(test, err, 0, "Failed to init fence chains");
randomise_fences(&fc);
tsk = kthread_run(__wait_fence_chains, &fc, "dmabuf/wait");
if (IS_ERR(tsk)) {
- err = PTR_ERR(tsk);
+ KUNIT_FAIL(test, "Failed to create kthread");
goto err;
}
get_task_struct(tsk);
@@ -665,29 +630,14 @@ static int wait_random(void *arg)
dma_fence_signal(fc.fences[i]);
err = kthread_stop_put(tsk);
+ KUNIT_EXPECT_EQ(test, err, 0);
err:
fence_chains_fini(&fc);
- return err;
}
-int dma_fence_chain(void)
+static int dma_fence_chain_suite_init(struct kunit_suite *suite)
{
- static const struct subtest tests[] = {
- SUBTEST(sanitycheck),
- SUBTEST(find_seqno),
- SUBTEST(find_signaled),
- SUBTEST(find_out_of_order),
- SUBTEST(find_gap),
- SUBTEST(find_race),
- SUBTEST(signal_forward),
- SUBTEST(signal_backward),
- SUBTEST(wait_forward),
- SUBTEST(wait_backward),
- SUBTEST(wait_random),
- };
- int ret;
-
pr_info("sizeof(dma_fence_chain)=%zu\n",
sizeof(struct dma_fence_chain));
@@ -696,9 +646,34 @@ int dma_fence_chain(void)
SLAB_HWCACHE_ALIGN);
if (!slab_fences)
return -ENOMEM;
+ return 0;
+}
- ret = subtests(tests, NULL);
-
+static void dma_fence_chain_suite_exit(struct kunit_suite *suite)
+{
kmem_cache_destroy(slab_fences);
- return ret;
}
+
+static struct kunit_case dma_fence_chain_cases[] = {
+ KUNIT_CASE(test_sanitycheck),
+ KUNIT_CASE(test_find_seqno),
+ KUNIT_CASE(test_find_signaled),
+ KUNIT_CASE(test_find_out_of_order),
+ KUNIT_CASE(test_find_gap),
+ KUNIT_CASE(test_find_race),
+ KUNIT_CASE(test_signal_forward),
+ KUNIT_CASE(test_signal_backward),
+ KUNIT_CASE(test_wait_forward),
+ KUNIT_CASE(test_wait_backward),
+ KUNIT_CASE(test_wait_random),
+ {}
+};
+
+static struct kunit_suite dma_fence_chain_test_suite = {
+ .name = "dma-buf-fence-chain",
+ .suite_init = dma_fence_chain_suite_init,
+ .suite_exit = dma_fence_chain_suite_exit,
+ .test_cases = dma_fence_chain_cases,
+};
+
+kunit_test_suite(dma_fence_chain_test_suite);
diff --git a/drivers/dma-buf/st-dma-fence-unwrap.c b/drivers/dma-buf/st-dma-fence-unwrap.c
index 9c74195f47fd..4e7ee25372ba 100644
--- a/drivers/dma-buf/st-dma-fence-unwrap.c
+++ b/drivers/dma-buf/st-dma-fence-unwrap.c
@@ -4,13 +4,12 @@
* Copyright (C) 2022 Advanced Micro Devices, Inc.
*/
+#include <kunit/test.h>
#include <linux/dma-fence.h>
#include <linux/dma-fence-array.h>
#include <linux/dma-fence-chain.h>
#include <linux/dma-fence-unwrap.h>
-#include "selftest.h"
-
#define CHAIN_SZ (4 << 10)
struct mock_fence {
@@ -65,7 +64,7 @@ static struct dma_fence *mock_array(unsigned int num_fences, ...)
array = dma_fence_array_create(num_fences, fences,
dma_fence_context_alloc(1),
- 1, false);
+ 1);
if (!array)
goto error_free;
return &array->base;
@@ -97,52 +96,45 @@ static struct dma_fence *mock_chain(struct dma_fence *prev,
return &f->base;
}
-static int sanitycheck(void *arg)
+static void test_sanitycheck(struct kunit *test)
{
struct dma_fence *f, *chain, *array;
- int err = 0;
f = mock_fence();
- if (!f)
- return -ENOMEM;
+ KUNIT_ASSERT_NOT_NULL(test, f);
dma_fence_enable_sw_signaling(f);
array = mock_array(1, f);
- if (!array)
- return -ENOMEM;
+ KUNIT_ASSERT_NOT_NULL(test, array);
chain = mock_chain(NULL, array);
- if (!chain)
- return -ENOMEM;
+ KUNIT_ASSERT_NOT_NULL(test, chain);
dma_fence_put(chain);
- return err;
}
-static int unwrap_array(void *arg)
+static void test_unwrap_array(struct kunit *test)
{
struct dma_fence *fence, *f1, *f2, *array;
struct dma_fence_unwrap iter;
- int err = 0;
f1 = mock_fence();
- if (!f1)
- return -ENOMEM;
+ KUNIT_ASSERT_NOT_NULL(test, f1);
dma_fence_enable_sw_signaling(f1);
f2 = mock_fence();
if (!f2) {
+ KUNIT_FAIL(test, "Failed to create mock fence");
dma_fence_put(f1);
- return -ENOMEM;
+ return;
}
dma_fence_enable_sw_signaling(f2);
array = mock_array(2, f1, f2);
- if (!array)
- return -ENOMEM;
+ KUNIT_ASSERT_NOT_NULL(test, array);
dma_fence_unwrap_for_each(fence, &iter, array) {
if (fence == f1) {
@@ -150,43 +142,37 @@ static int unwrap_array(void *arg)
} else if (fence == f2) {
f2 = NULL;
} else {
- pr_err("Unexpected fence!\n");
- err = -EINVAL;
+ KUNIT_FAIL(test, "Unexpected fence!");
}
}
- if (f1 || f2) {
- pr_err("Not all fences seen!\n");
- err = -EINVAL;
- }
+ if (f1 || f2)
+ KUNIT_FAIL(test, "Not all fences seen!");
dma_fence_put(array);
- return err;
}
-static int unwrap_chain(void *arg)
+static void test_unwrap_chain(struct kunit *test)
{
struct dma_fence *fence, *f1, *f2, *chain;
struct dma_fence_unwrap iter;
- int err = 0;
f1 = mock_fence();
- if (!f1)
- return -ENOMEM;
+ KUNIT_ASSERT_NOT_NULL(test, f1);
dma_fence_enable_sw_signaling(f1);
f2 = mock_fence();
if (!f2) {
+ KUNIT_FAIL(test, "Failed to create mock fence");
dma_fence_put(f1);
- return -ENOMEM;
+ return;
}
dma_fence_enable_sw_signaling(f2);
chain = mock_chain(f1, f2);
- if (!chain)
- return -ENOMEM;
+ KUNIT_ASSERT_NOT_NULL(test, chain);
dma_fence_unwrap_for_each(fence, &iter, chain) {
if (fence == f1) {
@@ -194,47 +180,40 @@ static int unwrap_chain(void *arg)
} else if (fence == f2) {
f2 = NULL;
} else {
- pr_err("Unexpected fence!\n");
- err = -EINVAL;
+ KUNIT_FAIL(test, "Unexpected fence!");
}
}
- if (f1 || f2) {
- pr_err("Not all fences seen!\n");
- err = -EINVAL;
- }
+ if (f1 || f2)
+ KUNIT_FAIL(test, "Not all fences seen!");
dma_fence_put(chain);
- return err;
}
-static int unwrap_chain_array(void *arg)
+static void test_unwrap_chain_array(struct kunit *test)
{
struct dma_fence *fence, *f1, *f2, *array, *chain;
struct dma_fence_unwrap iter;
- int err = 0;
f1 = mock_fence();
- if (!f1)
- return -ENOMEM;
+ KUNIT_ASSERT_NOT_NULL(test, f1);
dma_fence_enable_sw_signaling(f1);
f2 = mock_fence();
if (!f2) {
+ KUNIT_FAIL(test, "Failed to create mock fence");
dma_fence_put(f1);
- return -ENOMEM;
+ return;
}
dma_fence_enable_sw_signaling(f2);
array = mock_array(2, f1, f2);
- if (!array)
- return -ENOMEM;
+ KUNIT_ASSERT_NOT_NULL(test, array);
chain = mock_chain(NULL, array);
- if (!chain)
- return -ENOMEM;
+ KUNIT_ASSERT_NOT_NULL(test, chain);
dma_fence_unwrap_for_each(fence, &iter, chain) {
if (fence == f1) {
@@ -242,35 +221,29 @@ static int unwrap_chain_array(void *arg)
} else if (fence == f2) {
f2 = NULL;
} else {
- pr_err("Unexpected fence!\n");
- err = -EINVAL;
+ KUNIT_FAIL(test, "Unexpected fence!");
}
}
- if (f1 || f2) {
- pr_err("Not all fences seen!\n");
- err = -EINVAL;
- }
+ if (f1 || f2)
+ KUNIT_FAIL(test, "Not all fences seen!");
dma_fence_put(chain);
- return err;
}
-static int unwrap_merge(void *arg)
+static void test_unwrap_merge(struct kunit *test)
{
struct dma_fence *fence, *f1, *f2, *f3;
struct dma_fence_unwrap iter;
- int err = 0;
f1 = mock_fence();
- if (!f1)
- return -ENOMEM;
+ KUNIT_ASSERT_NOT_NULL(test, f1);
dma_fence_enable_sw_signaling(f1);
f2 = mock_fence();
if (!f2) {
- err = -ENOMEM;
+ KUNIT_FAIL(test, "Failed to create mock fence");
goto error_put_f1;
}
@@ -278,7 +251,7 @@ static int unwrap_merge(void *arg)
f3 = dma_fence_unwrap_merge(f1, f2);
if (!f3) {
- err = -ENOMEM;
+ KUNIT_FAIL(test, "Failed to merge fences");
goto error_put_f2;
}
@@ -290,39 +263,33 @@ static int unwrap_merge(void *arg)
dma_fence_put(f2);
f2 = NULL;
} else {
- pr_err("Unexpected fence!\n");
- err = -EINVAL;
+ KUNIT_FAIL(test, "Unexpected fence!");
}
}
- if (f1 || f2) {
- pr_err("Not all fences seen!\n");
- err = -EINVAL;
- }
+ if (f1 || f2)
+ KUNIT_FAIL(test, "Not all fences seen!");
dma_fence_put(f3);
error_put_f2:
dma_fence_put(f2);
error_put_f1:
dma_fence_put(f1);
- return err;
}
-static int unwrap_merge_duplicate(void *arg)
+static void test_unwrap_merge_duplicate(struct kunit *test)
{
struct dma_fence *fence, *f1, *f2;
struct dma_fence_unwrap iter;
- int err = 0;
f1 = mock_fence();
- if (!f1)
- return -ENOMEM;
+ KUNIT_ASSERT_NOT_NULL(test, f1);
dma_fence_enable_sw_signaling(f1);
f2 = dma_fence_unwrap_merge(f1, f1);
if (!f2) {
- err = -ENOMEM;
+ KUNIT_FAIL(test, "Failed to merge fences");
goto error_put_f1;
}
@@ -331,41 +298,35 @@ static int unwrap_merge_duplicate(void *arg)
dma_fence_put(f1);
f1 = NULL;
} else {
- pr_err("Unexpected fence!\n");
- err = -EINVAL;
+ KUNIT_FAIL(test, "Unexpected fence!");
}
}
- if (f1) {
- pr_err("Not all fences seen!\n");
- err = -EINVAL;
- }
+ if (f1)
+ KUNIT_FAIL(test, "Not all fences seen!");
dma_fence_put(f2);
error_put_f1:
dma_fence_put(f1);
- return err;
}
-static int unwrap_merge_seqno(void *arg)
+static void test_unwrap_merge_seqno(struct kunit *test)
{
struct dma_fence *fence, *f1, *f2, *f3, *f4;
struct dma_fence_unwrap iter;
- int err = 0;
u64 ctx[2];
ctx[0] = dma_fence_context_alloc(1);
ctx[1] = dma_fence_context_alloc(1);
f1 = __mock_fence(ctx[1], 1);
- if (!f1)
- return -ENOMEM;
+ KUNIT_ASSERT_NOT_NULL(test, f1);
dma_fence_enable_sw_signaling(f1);
f2 = __mock_fence(ctx[1], 2);
if (!f2) {
- err = -ENOMEM;
+ KUNIT_FAIL(test, "Failed to create mock fence");
goto error_put_f1;
}
@@ -373,7 +334,7 @@ static int unwrap_merge_seqno(void *arg)
f3 = __mock_fence(ctx[0], 1);
if (!f3) {
- err = -ENOMEM;
+ KUNIT_FAIL(test, "Failed to create mock fence");
goto error_put_f2;
}
@@ -381,7 +342,7 @@ static int unwrap_merge_seqno(void *arg)
f4 = dma_fence_unwrap_merge(f1, f2, f3);
if (!f4) {
- err = -ENOMEM;
+ KUNIT_FAIL(test, "Failed to merge fences");
goto error_put_f3;
}
@@ -393,15 +354,12 @@ static int unwrap_merge_seqno(void *arg)
dma_fence_put(f2);
f2 = NULL;
} else {
- pr_err("Unexpected fence!\n");
- err = -EINVAL;
+ KUNIT_FAIL(test, "Unexpected fence!");
}
}
- if (f2 || f3) {
- pr_err("Not all fences seen!\n");
- err = -EINVAL;
- }
+ if (f2 || f3)
+ KUNIT_FAIL(test, "Not all fences seen!");
dma_fence_put(f4);
error_put_f3:
@@ -410,40 +368,41 @@ error_put_f2:
dma_fence_put(f2);
error_put_f1:
dma_fence_put(f1);
- return err;
}
-static int unwrap_merge_order(void *arg)
+static void test_unwrap_merge_order(struct kunit *test)
{
struct dma_fence *fence, *f1, *f2, *a1, *a2, *c1, *c2;
struct dma_fence_unwrap iter;
- int err = 0;
f1 = mock_fence();
- if (!f1)
- return -ENOMEM;
+ KUNIT_ASSERT_NOT_NULL(test, f1);
dma_fence_enable_sw_signaling(f1);
f2 = mock_fence();
if (!f2) {
+ KUNIT_FAIL(test, "Failed to create mock fence");
dma_fence_put(f1);
- return -ENOMEM;
+ return;
}
dma_fence_enable_sw_signaling(f2);
a1 = mock_array(2, f1, f2);
- if (!a1)
- return -ENOMEM;
+ KUNIT_ASSERT_NOT_NULL(test, a1);
c1 = mock_chain(NULL, dma_fence_get(f1));
- if (!c1)
+ if (!c1) {
+ KUNIT_FAIL(test, "Failed to create chain");
goto error_put_a1;
+ }
c2 = mock_chain(c1, dma_fence_get(f2));
- if (!c2)
+ if (!c2) {
+ KUNIT_FAIL(test, "Failed to create chain");
goto error_put_a1;
+ }
/*
* The fences in the chain are the same as in a1 but in oposite order,
@@ -455,63 +414,64 @@ static int unwrap_merge_order(void *arg)
if (fence == f1) {
f1 = NULL;
if (!f2)
- pr_err("Unexpected order!\n");
+ KUNIT_FAIL(test, "Unexpected order!");
} else if (fence == f2) {
f2 = NULL;
if (f1)
- pr_err("Unexpected order!\n");
+ KUNIT_FAIL(test, "Unexpected order!");
} else {
- pr_err("Unexpected fence!\n");
- err = -EINVAL;
+ KUNIT_FAIL(test, "Unexpected fence!");
}
}
- if (f1 || f2) {
- pr_err("Not all fences seen!\n");
- err = -EINVAL;
- }
+ if (f1 || f2)
+ KUNIT_FAIL(test, "Not all fences seen!");
dma_fence_put(a2);
- return err;
+ return;
error_put_a1:
dma_fence_put(a1);
- return -ENOMEM;
}
-static int unwrap_merge_complex(void *arg)
+static void test_unwrap_merge_complex(struct kunit *test)
{
struct dma_fence *fence, *f1, *f2, *f3, *f4, *f5;
struct dma_fence_unwrap iter;
- int err = -ENOMEM;
f1 = mock_fence();
- if (!f1)
- return -ENOMEM;
+ KUNIT_ASSERT_NOT_NULL(test, f1);
dma_fence_enable_sw_signaling(f1);
f2 = mock_fence();
- if (!f2)
+ if (!f2) {
+ KUNIT_FAIL(test, "Failed to create mock fence");
goto error_put_f1;
+ }
dma_fence_enable_sw_signaling(f2);
f3 = dma_fence_unwrap_merge(f1, f2);
- if (!f3)
+ if (!f3) {
+ KUNIT_FAIL(test, "Failed to merge fences");
goto error_put_f2;
+ }
/* The resulting array has the fences in reverse */
f4 = mock_array(2, dma_fence_get(f2), dma_fence_get(f1));
- if (!f4)
+ if (!f4) {
+ KUNIT_FAIL(test, "Failed to create array");
goto error_put_f3;
+ }
/* Signaled fences should be filtered, the two arrays merged. */
f5 = dma_fence_unwrap_merge(f3, f4, dma_fence_get_stub());
- if (!f5)
+ if (!f5) {
+ KUNIT_FAIL(test, "Failed to merge fences");
goto error_put_f4;
+ }
- err = 0;
dma_fence_unwrap_for_each(fence, &iter, f5) {
if (fence == f1) {
dma_fence_put(f1);
@@ -520,15 +480,12 @@ static int unwrap_merge_complex(void *arg)
dma_fence_put(f2);
f2 = NULL;
} else {
- pr_err("Unexpected fence!\n");
- err = -EINVAL;
+ KUNIT_FAIL(test, "Unexpected fence!");
}
}
- if (f1 || f2) {
- pr_err("Not all fences seen!\n");
- err = -EINVAL;
- }
+ if (f1 || f2)
+ KUNIT_FAIL(test, "Not all fences seen!");
dma_fence_put(f5);
error_put_f4:
@@ -539,56 +496,64 @@ error_put_f2:
dma_fence_put(f2);
error_put_f1:
dma_fence_put(f1);
- return err;
}
-static int unwrap_merge_complex_seqno(void *arg)
+static void test_unwrap_merge_complex_seqno(struct kunit *test)
{
struct dma_fence *fence, *f1, *f2, *f3, *f4, *f5, *f6, *f7;
struct dma_fence_unwrap iter;
- int err = -ENOMEM;
u64 ctx[2];
ctx[0] = dma_fence_context_alloc(1);
ctx[1] = dma_fence_context_alloc(1);
f1 = __mock_fence(ctx[0], 2);
- if (!f1)
- return -ENOMEM;
+ KUNIT_ASSERT_NOT_NULL(test, f1);
dma_fence_enable_sw_signaling(f1);
f2 = __mock_fence(ctx[1], 1);
- if (!f2)
+ if (!f2) {
+ KUNIT_FAIL(test, "Failed to create mock fence");
goto error_put_f1;
+ }
dma_fence_enable_sw_signaling(f2);
f3 = __mock_fence(ctx[0], 1);
- if (!f3)
+ if (!f3) {
+ KUNIT_FAIL(test, "Failed to create mock fence");
goto error_put_f2;
+ }
dma_fence_enable_sw_signaling(f3);
f4 = __mock_fence(ctx[1], 2);
- if (!f4)
+ if (!f4) {
+ KUNIT_FAIL(test, "Failed to create mock fence");
goto error_put_f3;
+ }
dma_fence_enable_sw_signaling(f4);
f5 = mock_array(2, dma_fence_get(f1), dma_fence_get(f2));
- if (!f5)
+ if (!f5) {
+ KUNIT_FAIL(test, "Failed to create array");
goto error_put_f4;
+ }
f6 = mock_array(2, dma_fence_get(f3), dma_fence_get(f4));
- if (!f6)
+ if (!f6) {
+ KUNIT_FAIL(test, "Failed to create array");
goto error_put_f5;
+ }
f7 = dma_fence_unwrap_merge(f5, f6);
- if (!f7)
+ if (!f7) {
+ KUNIT_FAIL(test, "Failed to merge fences");
goto error_put_f6;
+ }
- err = 0;
dma_fence_unwrap_for_each(fence, &iter, f7) {
if (fence == f1 && f4) {
dma_fence_put(f1);
@@ -597,15 +562,12 @@ static int unwrap_merge_complex_seqno(void *arg)
dma_fence_put(f4);
f4 = NULL;
} else {
- pr_err("Unexpected fence!\n");
- err = -EINVAL;
+ KUNIT_FAIL(test, "Unexpected fence!");
}
}
- if (f1 || f4) {
- pr_err("Not all fences seen!\n");
- err = -EINVAL;
- }
+ if (f1 || f4)
+ KUNIT_FAIL(test, "Not all fences seen!");
dma_fence_put(f7);
error_put_f6:
@@ -620,23 +582,25 @@ error_put_f2:
dma_fence_put(f2);
error_put_f1:
dma_fence_put(f1);
- return err;
}
-int dma_fence_unwrap(void)
-{
- static const struct subtest tests[] = {
- SUBTEST(sanitycheck),
- SUBTEST(unwrap_array),
- SUBTEST(unwrap_chain),
- SUBTEST(unwrap_chain_array),
- SUBTEST(unwrap_merge),
- SUBTEST(unwrap_merge_duplicate),
- SUBTEST(unwrap_merge_seqno),
- SUBTEST(unwrap_merge_order),
- SUBTEST(unwrap_merge_complex),
- SUBTEST(unwrap_merge_complex_seqno),
- };
-
- return subtests(tests, NULL);
-}
+static struct kunit_case dma_fence_unwrap_cases[] = {
+ KUNIT_CASE(test_sanitycheck),
+ KUNIT_CASE(test_unwrap_array),
+ KUNIT_CASE(test_unwrap_chain),
+ KUNIT_CASE(test_unwrap_chain_array),
+ KUNIT_CASE(test_unwrap_merge),
+ KUNIT_CASE(test_unwrap_merge_duplicate),
+ KUNIT_CASE(test_unwrap_merge_seqno),
+ KUNIT_CASE(test_unwrap_merge_order),
+ KUNIT_CASE(test_unwrap_merge_complex),
+ KUNIT_CASE(test_unwrap_merge_complex_seqno),
+ {}
+};
+
+static struct kunit_suite dma_fence_unwrap_test_suite = {
+ .name = "dma-buf-fence-unwrap",
+ .test_cases = dma_fence_unwrap_cases,
+};
+
+kunit_test_suite(dma_fence_unwrap_test_suite);
diff --git a/drivers/dma-buf/st-dma-fence.c b/drivers/dma-buf/st-dma-fence.c
index 0d9d524d79b6..499272229696 100644
--- a/drivers/dma-buf/st-dma-fence.c
+++ b/drivers/dma-buf/st-dma-fence.c
@@ -4,6 +4,7 @@
* Copyright © 2019 Intel Corporation
*/
+#include <kunit/test.h>
#include <linux/delay.h>
#include <linux/dma-fence.h>
#include <linux/kernel.h>
@@ -12,8 +13,6 @@
#include <linux/slab.h>
#include <linux/spinlock.h>
-#include "selftest.h"
-
static const char *mock_name(struct dma_fence *f)
{
return "mock";
@@ -36,62 +35,55 @@ static struct dma_fence *mock_fence(void)
return f;
}
-static int sanitycheck(void *arg)
+static void test_sanitycheck(struct kunit *test)
{
struct dma_fence *f;
f = mock_fence();
- if (!f)
- return -ENOMEM;
+ KUNIT_ASSERT_NOT_NULL(test, f);
dma_fence_enable_sw_signaling(f);
dma_fence_signal(f);
dma_fence_put(f);
-
- return 0;
}
-static int test_signaling(void *arg)
+static void test_signaling(struct kunit *test)
{
struct dma_fence *f;
- int err = -EINVAL;
f = mock_fence();
- if (!f)
- return -ENOMEM;
+ KUNIT_ASSERT_NOT_NULL(test, f);
dma_fence_enable_sw_signaling(f);
if (dma_fence_is_signaled(f)) {
- pr_err("Fence unexpectedly signaled on creation\n");
+ KUNIT_FAIL(test, "Fence unexpectedly signaled on creation");
goto err_free;
}
if (dma_fence_check_and_signal(f)) {
- pr_err("Fence reported being already signaled\n");
+ KUNIT_FAIL(test, "Fence reported being already signaled");
goto err_free;
}
if (!dma_fence_is_signaled(f)) {
- pr_err("Fence not reporting signaled\n");
+ KUNIT_FAIL(test, "Fence not reporting signaled");
goto err_free;
}
if (!dma_fence_test_signaled_flag(f)) {
- pr_err("Fence reported not being already signaled\n");
+ KUNIT_FAIL(test, "Fence reported not being already signaled");
goto err_free;
}
if (rcu_dereference_protected(f->ops, true)) {
- pr_err("Fence ops not cleared on signal\n");
+ KUNIT_FAIL(test, "Fence ops not cleared on signal");
goto err_free;
}
- err = 0;
err_free:
dma_fence_put(f);
- return err;
}
struct simple_cb {
@@ -104,215 +96,187 @@ static void simple_callback(struct dma_fence *f, struct dma_fence_cb *cb)
smp_store_mb(container_of(cb, struct simple_cb, cb)->seen, true);
}
-static int test_add_callback(void *arg)
+static void test_add_callback(struct kunit *test)
{
struct simple_cb cb = {};
struct dma_fence *f;
- int err = -EINVAL;
f = mock_fence();
- if (!f)
- return -ENOMEM;
+ KUNIT_ASSERT_NOT_NULL(test, f);
if (dma_fence_add_callback(f, &cb.cb, simple_callback)) {
- pr_err("Failed to add callback, fence already signaled!\n");
+ KUNIT_FAIL(test, "Failed to add callback, fence already signaled!");
goto err_free;
}
dma_fence_signal(f);
if (!cb.seen) {
- pr_err("Callback failed!\n");
+ KUNIT_FAIL(test, "Callback failed!");
goto err_free;
}
- err = 0;
err_free:
dma_fence_put(f);
- return err;
}
-static int test_late_add_callback(void *arg)
+static void test_late_add_callback(struct kunit *test)
{
struct simple_cb cb = {};
struct dma_fence *f;
- int err = -EINVAL;
f = mock_fence();
- if (!f)
- return -ENOMEM;
+ KUNIT_ASSERT_NOT_NULL(test, f);
dma_fence_enable_sw_signaling(f);
dma_fence_signal(f);
if (!dma_fence_add_callback(f, &cb.cb, simple_callback)) {
- pr_err("Added callback, but fence was already signaled!\n");
+ KUNIT_FAIL(test, "Added callback, but fence was already signaled!");
goto err_free;
}
dma_fence_signal(f);
if (cb.seen) {
- pr_err("Callback called after failed attachment !\n");
+ KUNIT_FAIL(test, "Callback called after failed attachment!");
goto err_free;
}
- err = 0;
err_free:
dma_fence_put(f);
- return err;
}
-static int test_rm_callback(void *arg)
+static void test_rm_callback(struct kunit *test)
{
struct simple_cb cb = {};
struct dma_fence *f;
- int err = -EINVAL;
f = mock_fence();
- if (!f)
- return -ENOMEM;
+ KUNIT_ASSERT_NOT_NULL(test, f);
if (dma_fence_add_callback(f, &cb.cb, simple_callback)) {
- pr_err("Failed to add callback, fence already signaled!\n");
+ KUNIT_FAIL(test, "Failed to add callback, fence already signaled!");
goto err_free;
}
if (!dma_fence_remove_callback(f, &cb.cb)) {
- pr_err("Failed to remove callback!\n");
+ KUNIT_FAIL(test, "Failed to remove callback!");
goto err_free;
}
dma_fence_signal(f);
if (cb.seen) {
- pr_err("Callback still signaled after removal!\n");
+ KUNIT_FAIL(test, "Callback still signaled after removal!");
goto err_free;
}
- err = 0;
err_free:
dma_fence_put(f);
- return err;
}
-static int test_late_rm_callback(void *arg)
+static void test_late_rm_callback(struct kunit *test)
{
struct simple_cb cb = {};
struct dma_fence *f;
- int err = -EINVAL;
f = mock_fence();
- if (!f)
- return -ENOMEM;
+ KUNIT_ASSERT_NOT_NULL(test, f);
if (dma_fence_add_callback(f, &cb.cb, simple_callback)) {
- pr_err("Failed to add callback, fence already signaled!\n");
+ KUNIT_FAIL(test, "Failed to add callback, fence already signaled!");
goto err_free;
}
dma_fence_signal(f);
if (!cb.seen) {
- pr_err("Callback failed!\n");
+ KUNIT_FAIL(test, "Callback failed!");
goto err_free;
}
if (dma_fence_remove_callback(f, &cb.cb)) {
- pr_err("Callback removal succeed after being executed!\n");
+ KUNIT_FAIL(test, "Callback removal succeeded after being executed!");
goto err_free;
}
- err = 0;
err_free:
dma_fence_put(f);
- return err;
}
-static int test_status(void *arg)
+static void test_status(struct kunit *test)
{
struct dma_fence *f;
- int err = -EINVAL;
f = mock_fence();
- if (!f)
- return -ENOMEM;
+ KUNIT_ASSERT_NOT_NULL(test, f);
dma_fence_enable_sw_signaling(f);
if (dma_fence_get_status(f)) {
- pr_err("Fence unexpectedly has signaled status on creation\n");
+ KUNIT_FAIL(test, "Fence unexpectedly has signaled status on creation");
goto err_free;
}
dma_fence_signal(f);
if (!dma_fence_get_status(f)) {
- pr_err("Fence not reporting signaled status\n");
+ KUNIT_FAIL(test, "Fence not reporting signaled status");
goto err_free;
}
- err = 0;
err_free:
dma_fence_put(f);
- return err;
}
-static int test_error(void *arg)
+static void test_error(struct kunit *test)
{
struct dma_fence *f;
- int err = -EINVAL;
f = mock_fence();
- if (!f)
- return -ENOMEM;
+ KUNIT_ASSERT_NOT_NULL(test, f);
dma_fence_enable_sw_signaling(f);
dma_fence_set_error(f, -EIO);
if (dma_fence_get_status(f)) {
- pr_err("Fence unexpectedly has error status before signal\n");
+ KUNIT_FAIL(test, "Fence unexpectedly has error status before signal");
goto err_free;
}
dma_fence_signal(f);
if (dma_fence_get_status(f) != -EIO) {
- pr_err("Fence not reporting error status, got %d\n",
- dma_fence_get_status(f));
+ KUNIT_FAIL(test, "Fence not reporting error status, got %d",
+ dma_fence_get_status(f));
goto err_free;
}
- err = 0;
err_free:
dma_fence_put(f);
- return err;
}
-static int test_wait(void *arg)
+static void test_wait(struct kunit *test)
{
struct dma_fence *f;
- int err = -EINVAL;
f = mock_fence();
- if (!f)
- return -ENOMEM;
+ KUNIT_ASSERT_NOT_NULL(test, f);
dma_fence_enable_sw_signaling(f);
if (dma_fence_wait_timeout(f, false, 0) != 0) {
- pr_err("Wait reported complete before being signaled\n");
+ KUNIT_FAIL(test, "Wait reported complete before being signaled");
goto err_free;
}
dma_fence_signal(f);
if (dma_fence_wait_timeout(f, false, 0) != 1) {
- pr_err("Wait reported incomplete after being signaled\n");
+ KUNIT_FAIL(test, "Wait reported incomplete after being signaled");
goto err_free;
}
- err = 0;
err_free:
dma_fence_signal(f);
dma_fence_put(f);
- return err;
}
struct wait_timer {
@@ -327,21 +291,19 @@ static void wait_timer(struct timer_list *timer)
dma_fence_signal(wt->f);
}
-static int test_wait_timeout(void *arg)
+static void test_wait_timeout(struct kunit *test)
{
struct wait_timer wt;
- int err = -EINVAL;
timer_setup_on_stack(&wt.timer, wait_timer, 0);
wt.f = mock_fence();
- if (!wt.f)
- return -ENOMEM;
+ KUNIT_ASSERT_NOT_NULL(test, wt.f);
dma_fence_enable_sw_signaling(wt.f);
if (dma_fence_wait_timeout(wt.f, false, 1) != 0) {
- pr_err("Wait reported complete before being signaled\n");
+ KUNIT_FAIL(test, "Wait reported complete before being signaled");
goto err_free;
}
@@ -349,42 +311,38 @@ static int test_wait_timeout(void *arg)
if (dma_fence_wait_timeout(wt.f, false, HZ) == 0) {
if (timer_pending(&wt.timer)) {
- pr_notice("Timer did not fire within one HZ!\n");
- err = 0; /* not our fault! */
+ kunit_mark_skipped(
+ test, "Timer did not fire within on HZ!\n");
} else {
- pr_err("Wait reported incomplete after timeout\n");
+ KUNIT_FAIL(test,
+ "Wait reported incomplete after timeout");
}
goto err_free;
}
- err = 0;
err_free:
timer_delete_sync(&wt.timer);
timer_destroy_on_stack(&wt.timer);
dma_fence_signal(wt.f);
dma_fence_put(wt.f);
- return err;
}
-static int test_stub(void *arg)
+static void test_stub(struct kunit *test)
{
struct dma_fence *f[64];
- int err = -EINVAL;
int i;
for (i = 0; i < ARRAY_SIZE(f); i++) {
f[i] = dma_fence_get_stub();
if (!dma_fence_is_signaled(f[i])) {
- pr_err("Obtained unsignaled stub fence!\n");
+ KUNIT_FAIL(test, "Obtained unsignaled stub fence!");
goto err;
}
}
- err = 0;
err:
while (i--)
dma_fence_put(f[i]);
- return err;
}
/* Now off to the races! */
@@ -473,12 +431,19 @@ static int thread_signal_callback(void *arg)
return err;
}
-static int race_signal_callback(void *arg)
+static void test_race_signal_callback(struct kunit *test)
{
struct dma_fence __rcu *f[2] = {};
int ret = 0;
int pass;
+ /*
+ * thread_signal_callback() spins under RCU and it cannot make forward
+ * progress unless the threads are truly running concurrently.
+ */
+ if (num_online_cpus() < 2)
+ kunit_skip(test, "requires at least 2 CPUs");
+
for (pass = 0; !ret && pass <= 1; pass++) {
struct race_thread t[2];
int i;
@@ -490,10 +455,10 @@ static int race_signal_callback(void *arg)
t[i].task = kthread_run(thread_signal_callback, &t[i],
"dma-fence:%d", i);
if (IS_ERR(t[i].task)) {
- ret = PTR_ERR(t[i].task);
+ KUNIT_FAIL(test, "Failed to create kthread");
while (--i >= 0)
kthread_stop_put(t[i].task);
- return ret;
+ return;
}
get_task_struct(t[i].task);
}
@@ -509,26 +474,35 @@ static int race_signal_callback(void *arg)
}
}
- return ret;
+ KUNIT_EXPECT_EQ(test, ret, 0);
}
-int dma_fence(void)
+static int dma_fence_suite_init(struct kunit_suite *suite)
{
- static const struct subtest tests[] = {
- SUBTEST(sanitycheck),
- SUBTEST(test_signaling),
- SUBTEST(test_add_callback),
- SUBTEST(test_late_add_callback),
- SUBTEST(test_rm_callback),
- SUBTEST(test_late_rm_callback),
- SUBTEST(test_status),
- SUBTEST(test_error),
- SUBTEST(test_wait),
- SUBTEST(test_wait_timeout),
- SUBTEST(test_stub),
- SUBTEST(race_signal_callback),
- };
-
pr_info("sizeof(dma_fence)=%zu\n", sizeof(struct dma_fence));
- return subtests(tests, NULL);
+ return 0;
}
+
+static struct kunit_case dma_fence_cases[] = {
+ KUNIT_CASE(test_sanitycheck),
+ KUNIT_CASE(test_signaling),
+ KUNIT_CASE(test_add_callback),
+ KUNIT_CASE(test_late_add_callback),
+ KUNIT_CASE(test_rm_callback),
+ KUNIT_CASE(test_late_rm_callback),
+ KUNIT_CASE(test_status),
+ KUNIT_CASE(test_error),
+ KUNIT_CASE(test_wait),
+ KUNIT_CASE(test_wait_timeout),
+ KUNIT_CASE(test_stub),
+ KUNIT_CASE(test_race_signal_callback),
+ {}
+};
+
+static struct kunit_suite dma_fence_test_suite = {
+ .name = "dma-buf-fence",
+ .suite_init = dma_fence_suite_init,
+ .test_cases = dma_fence_cases,
+};
+
+kunit_test_suite(dma_fence_test_suite);
diff --git a/drivers/dma-buf/st-dma-resv.c b/drivers/dma-buf/st-dma-resv.c
index ad4dfb49dcd9..95a4becdb892 100644
--- a/drivers/dma-buf/st-dma-resv.c
+++ b/drivers/dma-buf/st-dma-resv.c
@@ -5,13 +5,17 @@
* Copyright © 2021 Advanced Micro Devices, Inc.
*/
+#include <kunit/test.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/dma-resv.h>
-#include "selftest.h"
+static DEFINE_SPINLOCK(fence_lock);
-static struct spinlock fence_lock;
+struct dma_resv_usage_param {
+ enum dma_resv_usage usage;
+ const char *desc;
+};
static const char *fence_name(struct dma_fence *f)
{
@@ -35,15 +39,14 @@ static struct dma_fence *alloc_fence(void)
return f;
}
-static int sanitycheck(void *arg)
+static void test_sanitycheck(struct kunit *test)
{
struct dma_resv resv;
struct dma_fence *f;
int r;
f = alloc_fence();
- if (!f)
- return -ENOMEM;
+ KUNIT_ASSERT_NOT_NULL(test, f);
dma_fence_enable_sw_signaling(f);
@@ -53,49 +56,46 @@ static int sanitycheck(void *arg)
dma_resv_init(&resv);
r = dma_resv_lock(&resv, NULL);
if (r)
- pr_err("Resv locking failed\n");
+ KUNIT_FAIL(test, "Resv locking failed\n");
else
dma_resv_unlock(&resv);
dma_resv_fini(&resv);
- return r;
}
-static int test_signaling(void *arg)
+static void test_signaling(struct kunit *test)
{
- enum dma_resv_usage usage = (unsigned long)arg;
+ const struct dma_resv_usage_param *param = test->param_value;
+ enum dma_resv_usage usage = param->usage;
struct dma_resv resv;
struct dma_fence *f;
int r;
f = alloc_fence();
- if (!f)
- return -ENOMEM;
+ KUNIT_ASSERT_NOT_NULL(test, f);
dma_fence_enable_sw_signaling(f);
dma_resv_init(&resv);
r = dma_resv_lock(&resv, NULL);
if (r) {
- pr_err("Resv locking failed\n");
+ KUNIT_FAIL(test, "Resv locking failed");
goto err_free;
}
r = dma_resv_reserve_fences(&resv, 1);
if (r) {
- pr_err("Resv shared slot allocation failed\n");
+ KUNIT_FAIL(test, "Resv shared slot allocation failed");
goto err_unlock;
}
dma_resv_add_fence(&resv, f, usage);
if (dma_resv_test_signaled(&resv, usage)) {
- pr_err("Resv unexpectedly signaled\n");
- r = -EINVAL;
+ KUNIT_FAIL(test, "Resv unexpectedly signaled");
goto err_unlock;
}
dma_fence_signal(f);
if (!dma_resv_test_signaled(&resv, usage)) {
- pr_err("Resv not reporting signaled\n");
- r = -EINVAL;
+ KUNIT_FAIL(test, "Resv not reporting signaled");
goto err_unlock;
}
err_unlock:
@@ -103,33 +103,32 @@ err_unlock:
err_free:
dma_resv_fini(&resv);
dma_fence_put(f);
- return r;
}
-static int test_for_each(void *arg)
+static void test_for_each(struct kunit *test)
{
- enum dma_resv_usage usage = (unsigned long)arg;
+ const struct dma_resv_usage_param *param = test->param_value;
+ enum dma_resv_usage usage = param->usage;
struct dma_resv_iter cursor;
struct dma_fence *f, *fence;
struct dma_resv resv;
int r;
f = alloc_fence();
- if (!f)
- return -ENOMEM;
+ KUNIT_ASSERT_NOT_NULL(test, f);
dma_fence_enable_sw_signaling(f);
dma_resv_init(&resv);
r = dma_resv_lock(&resv, NULL);
if (r) {
- pr_err("Resv locking failed\n");
+ KUNIT_FAIL(test, "Resv locking failed");
goto err_free;
}
r = dma_resv_reserve_fences(&resv, 1);
if (r) {
- pr_err("Resv shared slot allocation failed\n");
+ KUNIT_FAIL(test, "Resv shared slot allocation failed");
goto err_unlock;
}
@@ -138,24 +137,23 @@ static int test_for_each(void *arg)
r = -ENOENT;
dma_resv_for_each_fence(&cursor, &resv, usage, fence) {
if (!r) {
- pr_err("More than one fence found\n");
- r = -EINVAL;
+ KUNIT_FAIL(test, "More than one fence found");
goto err_unlock;
}
if (f != fence) {
- pr_err("Unexpected fence\n");
+ KUNIT_FAIL(test, "Unexpected fence");
r = -EINVAL;
goto err_unlock;
}
if (dma_resv_iter_usage(&cursor) != usage) {
- pr_err("Unexpected fence usage\n");
+ KUNIT_FAIL(test, "Unexpected fence usage");
r = -EINVAL;
goto err_unlock;
}
r = 0;
}
if (r) {
- pr_err("No fence found\n");
+ KUNIT_FAIL(test, "No fence found");
goto err_unlock;
}
dma_fence_signal(f);
@@ -164,33 +162,32 @@ err_unlock:
err_free:
dma_resv_fini(&resv);
dma_fence_put(f);
- return r;
}
-static int test_for_each_unlocked(void *arg)
+static void test_for_each_unlocked(struct kunit *test)
{
- enum dma_resv_usage usage = (unsigned long)arg;
+ const struct dma_resv_usage_param *param = test->param_value;
+ enum dma_resv_usage usage = param->usage;
struct dma_resv_iter cursor;
struct dma_fence *f, *fence;
struct dma_resv resv;
int r;
f = alloc_fence();
- if (!f)
- return -ENOMEM;
+ KUNIT_ASSERT_NOT_NULL(test, f);
dma_fence_enable_sw_signaling(f);
dma_resv_init(&resv);
r = dma_resv_lock(&resv, NULL);
if (r) {
- pr_err("Resv locking failed\n");
+ KUNIT_FAIL(test, "Resv locking failed");
goto err_free;
}
r = dma_resv_reserve_fences(&resv, 1);
if (r) {
- pr_err("Resv shared slot allocation failed\n");
+ KUNIT_FAIL(test, "Resv shared slot allocation failed");
dma_resv_unlock(&resv);
goto err_free;
}
@@ -202,21 +199,20 @@ static int test_for_each_unlocked(void *arg)
dma_resv_iter_begin(&cursor, &resv, usage);
dma_resv_for_each_fence_unlocked(&cursor, fence) {
if (!r) {
- pr_err("More than one fence found\n");
- r = -EINVAL;
+ KUNIT_FAIL(test, "More than one fence found");
goto err_iter_end;
}
if (!dma_resv_iter_is_restarted(&cursor)) {
- pr_err("No restart flag\n");
+ KUNIT_FAIL(test, "No restart flag");
goto err_iter_end;
}
if (f != fence) {
- pr_err("Unexpected fence\n");
+ KUNIT_FAIL(test, "Unexpected fence");
r = -EINVAL;
goto err_iter_end;
}
if (dma_resv_iter_usage(&cursor) != usage) {
- pr_err("Unexpected fence usage\n");
+ KUNIT_FAIL(test, "Unexpected fence usage");
r = -EINVAL;
goto err_iter_end;
}
@@ -230,40 +226,38 @@ static int test_for_each_unlocked(void *arg)
r = 0;
}
}
- if (r)
- pr_err("No fence found\n");
+ KUNIT_EXPECT_EQ(test, r, 0);
err_iter_end:
dma_resv_iter_end(&cursor);
dma_fence_signal(f);
err_free:
dma_resv_fini(&resv);
dma_fence_put(f);
- return r;
}
-static int test_get_fences(void *arg)
+static void test_get_fences(struct kunit *test)
{
- enum dma_resv_usage usage = (unsigned long)arg;
+ const struct dma_resv_usage_param *param = test->param_value;
+ enum dma_resv_usage usage = param->usage;
struct dma_fence *f, **fences = NULL;
struct dma_resv resv;
int r, i;
f = alloc_fence();
- if (!f)
- return -ENOMEM;
+ KUNIT_ASSERT_NOT_NULL(test, f);
dma_fence_enable_sw_signaling(f);
dma_resv_init(&resv);
r = dma_resv_lock(&resv, NULL);
if (r) {
- pr_err("Resv locking failed\n");
+ KUNIT_FAIL(test, "Resv locking failed");
goto err_resv;
}
r = dma_resv_reserve_fences(&resv, 1);
if (r) {
- pr_err("Resv shared slot allocation failed\n");
+ KUNIT_FAIL(test, "Resv shared slot allocation failed");
dma_resv_unlock(&resv);
goto err_resv;
}
@@ -273,12 +267,12 @@ static int test_get_fences(void *arg)
r = dma_resv_get_fences(&resv, usage, &i, &fences);
if (r) {
- pr_err("get_fences failed\n");
+ KUNIT_FAIL(test, "get_fences failed");
goto err_free;
}
if (i != 1 || fences[0] != f) {
- pr_err("get_fences returned unexpected fence\n");
+ KUNIT_FAIL(test, "get_fences returned unexpected fence");
goto err_free;
}
@@ -290,27 +284,32 @@ err_free:
err_resv:
dma_resv_fini(&resv);
dma_fence_put(f);
- return r;
}
-int dma_resv(void)
-{
- static const struct subtest tests[] = {
- SUBTEST(sanitycheck),
- SUBTEST(test_signaling),
- SUBTEST(test_for_each),
- SUBTEST(test_for_each_unlocked),
- SUBTEST(test_get_fences),
- };
- enum dma_resv_usage usage;
- int r;
+static const struct dma_resv_usage_param dma_resv_usage_params[] = {
+ { DMA_RESV_USAGE_KERNEL, "kernel" },
+ { DMA_RESV_USAGE_WRITE, "write" },
+ { DMA_RESV_USAGE_READ, "read" },
+ { DMA_RESV_USAGE_BOOKKEEP, "bookkeep" },
+};
- spin_lock_init(&fence_lock);
- for (usage = DMA_RESV_USAGE_KERNEL; usage <= DMA_RESV_USAGE_BOOKKEEP;
- ++usage) {
- r = subtests(tests, (void *)(unsigned long)usage);
- if (r)
- return r;
- }
- return 0;
-}
+KUNIT_ARRAY_PARAM_DESC(dma_resv_usage, dma_resv_usage_params, desc);
+
+static struct kunit_case dma_resv_cases[] = {
+ KUNIT_CASE(test_sanitycheck),
+ KUNIT_CASE_PARAM(test_signaling, dma_resv_usage_gen_params),
+ KUNIT_CASE_PARAM(test_for_each, dma_resv_usage_gen_params),
+ KUNIT_CASE_PARAM(test_for_each_unlocked, dma_resv_usage_gen_params),
+ KUNIT_CASE_PARAM(test_get_fences, dma_resv_usage_gen_params),
+ {}
+};
+
+static struct kunit_suite dma_resv_test_suite = {
+ .name = "dma-buf-resv",
+ .test_cases = dma_resv_cases,
+};
+
+kunit_test_suite(dma_resv_test_suite);
+
+MODULE_DESCRIPTION("KUnit tests for DMA-BUF");
+MODULE_LICENSE("GPL");
diff --git a/drivers/dma-buf/udmabuf.c b/drivers/dma-buf/udmabuf.c
index 94b8ecb892bb..bced421c0d65 100644
--- a/drivers/dma-buf/udmabuf.c
+++ b/drivers/dma-buf/udmabuf.c
@@ -26,10 +26,10 @@ MODULE_PARM_DESC(size_limit_mb, "Max size of a dmabuf, in megabytes. Default is
struct udmabuf {
pgoff_t pagecount;
- struct folio **folios;
+ struct page **pages;
/**
- * Unlike folios, pinned_folios is only used for unpin.
+ * Unlike pages, pinned_folios is only used for unpin.
* So, nr_pinned is not the same to pagecount, the pinned_folios
* only set each folio which already pinned when udmabuf_create.
* Note that, since a folio may be pinned multiple times, each folio
@@ -40,8 +40,8 @@ struct udmabuf {
struct folio **pinned_folios;
struct sg_table *sg;
+ enum dma_data_direction sg_dir;
struct miscdevice *device;
- pgoff_t *offsets;
};
static vm_fault_t udmabuf_vm_fault(struct vm_fault *vmf)
@@ -55,8 +55,7 @@ static vm_fault_t udmabuf_vm_fault(struct vm_fault *vmf)
if (pgoff >= ubuf->pagecount)
return VM_FAULT_SIGBUS;
- pfn = folio_pfn(ubuf->folios[pgoff]);
- pfn += ubuf->offsets[pgoff] >> PAGE_SHIFT;
+ pfn = page_to_pfn(ubuf->pages[pgoff]);
ret = vmf_insert_pfn(vma, vmf->address, pfn);
if (ret & VM_FAULT_ERROR)
@@ -73,8 +72,7 @@ static vm_fault_t udmabuf_vm_fault(struct vm_fault *vmf)
if (WARN_ON(pgoff >= ubuf->pagecount))
break;
- pfn = folio_pfn(ubuf->folios[pgoff]);
- pfn += ubuf->offsets[pgoff] >> PAGE_SHIFT;
+ pfn = page_to_pfn(ubuf->pages[pgoff]);
/**
* If the below vmf_insert_pfn() fails, we do not return an
@@ -109,22 +107,11 @@ static int mmap_udmabuf(struct dma_buf *buf, struct vm_area_struct *vma)
static int vmap_udmabuf(struct dma_buf *buf, struct iosys_map *map)
{
struct udmabuf *ubuf = buf->priv;
- struct page **pages;
void *vaddr;
- pgoff_t pg;
dma_resv_assert_held(buf->resv);
- pages = kvmalloc_objs(*pages, ubuf->pagecount);
- if (!pages)
- return -ENOMEM;
-
- for (pg = 0; pg < ubuf->pagecount; pg++)
- pages[pg] = folio_page(ubuf->folios[pg],
- ubuf->offsets[pg] >> PAGE_SHIFT);
-
- vaddr = vm_map_ram(pages, ubuf->pagecount, -1);
- kvfree(pages);
+ vaddr = vm_map_ram(ubuf->pages, ubuf->pagecount, -1);
if (!vaddr)
return -EINVAL;
@@ -146,23 +133,19 @@ static struct sg_table *get_sg_table(struct device *dev, struct dma_buf *buf,
{
struct udmabuf *ubuf = buf->priv;
struct sg_table *sg;
- struct scatterlist *sgl;
- unsigned int i = 0;
int ret;
sg = kzalloc_obj(*sg);
if (!sg)
return ERR_PTR(-ENOMEM);
- ret = sg_alloc_table(sg, ubuf->pagecount, GFP_KERNEL);
+ ret = sg_alloc_table_from_pages(sg, ubuf->pages, ubuf->pagecount, 0,
+ ubuf->pagecount << PAGE_SHIFT,
+ GFP_KERNEL);
if (ret < 0)
goto err_alloc;
- for_each_sg(sg->sgl, sgl, ubuf->pagecount, i)
- sg_set_folio(sgl, ubuf->folios[i], PAGE_SIZE,
- ubuf->offsets[i]);
-
- ret = dma_map_sgtable(dev, sg, direction, 0);
+ ret = dma_map_sgtable(dev, sg, direction, DMA_ATTR_SKIP_CPU_SYNC);
if (ret < 0)
goto err_map;
return sg;
@@ -177,7 +160,7 @@ err_alloc:
static void put_sg_table(struct device *dev, struct sg_table *sg,
enum dma_data_direction direction)
{
- dma_unmap_sgtable(dev, sg, direction, 0);
+ dma_unmap_sgtable(dev, sg, direction, DMA_ATTR_SKIP_CPU_SYNC);
sg_free_table(sg);
kfree(sg);
}
@@ -207,12 +190,8 @@ static void unpin_all_folios(struct udmabuf *ubuf)
static __always_inline int init_udmabuf(struct udmabuf *ubuf, pgoff_t pgcnt)
{
- ubuf->folios = kvmalloc_objs(*ubuf->folios, pgcnt);
- if (!ubuf->folios)
- return -ENOMEM;
-
- ubuf->offsets = kvzalloc_objs(*ubuf->offsets, pgcnt);
- if (!ubuf->offsets)
+ ubuf->pages = kvmalloc_objs(*ubuf->pages, pgcnt);
+ if (!ubuf->pages)
return -ENOMEM;
ubuf->pinned_folios = kvmalloc_objs(*ubuf->pinned_folios, pgcnt);
@@ -225,8 +204,7 @@ static __always_inline int init_udmabuf(struct udmabuf *ubuf, pgoff_t pgcnt)
static __always_inline void deinit_udmabuf(struct udmabuf *ubuf)
{
unpin_all_folios(ubuf);
- kvfree(ubuf->offsets);
- kvfree(ubuf->folios);
+ kvfree(ubuf->pages);
}
static void release_udmabuf(struct dma_buf *buf)
@@ -235,7 +213,7 @@ static void release_udmabuf(struct dma_buf *buf)
struct device *dev = ubuf->device->this_device;
if (ubuf->sg)
- put_sg_table(dev, ubuf->sg, DMA_BIDIRECTIONAL);
+ put_sg_table(dev, ubuf->sg, ubuf->sg_dir);
deinit_udmabuf(ubuf);
kfree(ubuf);
@@ -253,6 +231,8 @@ static int begin_cpu_udmabuf(struct dma_buf *buf,
if (IS_ERR(ubuf->sg)) {
ret = PTR_ERR(ubuf->sg);
ubuf->sg = NULL;
+ } else {
+ ubuf->sg_dir = direction;
}
} else {
dma_sync_sgtable_for_cpu(dev, ubuf->sg, direction);
@@ -344,8 +324,8 @@ static long udmabuf_pin_folios(struct udmabuf *ubuf, struct file *memfd,
ubuf->pinned_folios[nr_pinned++] = folios[cur_folio];
for (; subpgoff < fsize; subpgoff += PAGE_SIZE) {
- ubuf->folios[upgcnt] = folios[cur_folio];
- ubuf->offsets[upgcnt] = subpgoff;
+ ubuf->pages[upgcnt] = folio_page(folios[cur_folio],
+ subpgoff >> PAGE_SHIFT);
++upgcnt;
if (++cur_pgcnt >= pgcnt)