diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2026-06-17 10:21:00 +0100 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2026-06-17 10:21:00 +0100 |
| commit | 4b99990cdf9560e8a071640baf19f312e6ae02f4 (patch) | |
| tree | ba3c58e860666130caf5ae3bf386b6dbfbe59b04 /drivers/dma-buf | |
| parent | 9c87e61e3c5797277407ba5eae4eac8a52be3fa3 (diff) | |
| parent | 52d4ab1ca790a668cc8f2c27017138b1c467168c (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/.kunitconfig | 2 | ||||
| -rw-r--r-- | drivers/dma-buf/Kconfig | 11 | ||||
| -rw-r--r-- | drivers/dma-buf/Makefile | 5 | ||||
| -rw-r--r-- | drivers/dma-buf/dma-fence-array.c | 13 | ||||
| -rw-r--r-- | drivers/dma-buf/dma-fence-unwrap.c | 3 | ||||
| -rw-r--r-- | drivers/dma-buf/dma-fence.c | 3 | ||||
| -rw-r--r-- | drivers/dma-buf/dma-heap.c | 1 | ||||
| -rw-r--r-- | drivers/dma-buf/dma-resv.c | 3 | ||||
| -rw-r--r-- | drivers/dma-buf/heaps/Kconfig | 12 | ||||
| -rw-r--r-- | drivers/dma-buf/heaps/cma_heap.c | 3 | ||||
| -rw-r--r-- | drivers/dma-buf/heaps/system_heap.c | 21 | ||||
| -rw-r--r-- | drivers/dma-buf/selftest.c | 167 | ||||
| -rw-r--r-- | drivers/dma-buf/selftest.h | 30 | ||||
| -rw-r--r-- | drivers/dma-buf/selftests.h | 16 | ||||
| -rw-r--r-- | drivers/dma-buf/st-dma-fence-chain.c | 213 | ||||
| -rw-r--r-- | drivers/dma-buf/st-dma-fence-unwrap.c | 294 | ||||
| -rw-r--r-- | drivers/dma-buf/st-dma-fence.c | 200 | ||||
| -rw-r--r-- | drivers/dma-buf/st-dma-resv.c | 145 | ||||
| -rw-r--r-- | drivers/dma-buf/udmabuf.c | 58 |
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) |
