2021-09-24 18:10:19 +03:00
/* SPDX-License-Identifier: MIT */
/*
* Copyright © 2019 Intel Corporation
* Copyright © 2021 Advanced Micro Devices , Inc .
*/
# include <linux/slab.h>
# include <linux/spinlock.h>
# include <linux/dma-resv.h>
# include "selftest.h"
static struct spinlock fence_lock ;
static const char * fence_name ( struct dma_fence * f )
{
return " selftest " ;
}
static const struct dma_fence_ops fence_ops = {
. get_driver_name = fence_name ,
. get_timeline_name = fence_name ,
} ;
static struct dma_fence * alloc_fence ( void )
{
struct dma_fence * f ;
f = kmalloc ( sizeof ( * f ) , GFP_KERNEL ) ;
if ( ! f )
return NULL ;
dma_fence_init ( f , & fence_ops , & fence_lock , 0 , 0 ) ;
return f ;
}
static int sanitycheck ( void * arg )
{
struct dma_resv resv ;
struct dma_fence * f ;
int r ;
f = alloc_fence ( ) ;
if ( ! f )
return - ENOMEM ;
2022-09-14 19:43:18 +03:00
dma_fence_enable_sw_signaling ( f ) ;
2021-09-24 18:10:19 +03:00
dma_fence_signal ( f ) ;
dma_fence_put ( f ) ;
dma_resv_init ( & resv ) ;
r = dma_resv_lock ( & resv , NULL ) ;
if ( r )
pr_err ( " Resv locking failed \n " ) ;
else
dma_resv_unlock ( & resv ) ;
dma_resv_fini ( & resv ) ;
return r ;
}
2021-11-09 13:08:18 +03:00
static int test_signaling ( void * arg )
2021-09-24 18:10:19 +03:00
{
2021-11-09 13:08:18 +03:00
enum dma_resv_usage usage = ( unsigned long ) arg ;
2021-09-24 18:10:19 +03:00
struct dma_resv resv ;
struct dma_fence * f ;
int r ;
f = alloc_fence ( ) ;
if ( ! f )
return - ENOMEM ;
2022-09-14 19:43:18 +03:00
dma_fence_enable_sw_signaling ( f ) ;
2021-09-24 18:10:19 +03:00
dma_resv_init ( & resv ) ;
r = dma_resv_lock ( & resv , NULL ) ;
if ( r ) {
pr_err ( " Resv locking failed \n " ) ;
goto err_free ;
}
2021-11-16 17:20:45 +03:00
r = dma_resv_reserve_fences ( & resv , 1 ) ;
if ( r ) {
pr_err ( " Resv shared slot allocation failed \n " ) ;
goto err_unlock ;
}
2021-09-24 18:10:19 +03:00
2021-11-09 13:08:18 +03:00
dma_resv_add_fence ( & resv , f , usage ) ;
2021-11-09 13:08:18 +03:00
if ( dma_resv_test_signaled ( & resv , usage ) ) {
2021-09-24 18:10:19 +03:00
pr_err ( " Resv unexpectedly signaled \n " ) ;
r = - EINVAL ;
goto err_unlock ;
}
dma_fence_signal ( f ) ;
2021-11-09 13:08:18 +03:00
if ( ! dma_resv_test_signaled ( & resv , usage ) ) {
2021-09-24 18:10:19 +03:00
pr_err ( " Resv not reporting signaled \n " ) ;
r = - EINVAL ;
goto err_unlock ;
}
err_unlock :
dma_resv_unlock ( & resv ) ;
err_free :
dma_resv_fini ( & resv ) ;
dma_fence_put ( f ) ;
return r ;
}
2021-11-09 13:08:18 +03:00
static int test_for_each ( void * arg )
2021-09-24 18:10:19 +03:00
{
2021-11-09 13:08:18 +03:00
enum dma_resv_usage usage = ( unsigned long ) arg ;
2021-09-24 18:10:19 +03:00
struct dma_resv_iter cursor ;
struct dma_fence * f , * fence ;
struct dma_resv resv ;
int r ;
f = alloc_fence ( ) ;
if ( ! f )
return - ENOMEM ;
2022-09-14 19:43:18 +03:00
dma_fence_enable_sw_signaling ( f ) ;
2021-09-24 18:10:19 +03:00
dma_resv_init ( & resv ) ;
r = dma_resv_lock ( & resv , NULL ) ;
if ( r ) {
pr_err ( " Resv locking failed \n " ) ;
goto err_free ;
}
2021-11-16 17:20:45 +03:00
r = dma_resv_reserve_fences ( & resv , 1 ) ;
if ( r ) {
pr_err ( " Resv shared slot allocation failed \n " ) ;
goto err_unlock ;
}
2021-09-24 18:10:19 +03:00
2021-11-09 13:08:18 +03:00
dma_resv_add_fence ( & resv , f , usage ) ;
2021-09-24 18:10:19 +03:00
r = - ENOENT ;
2021-11-09 13:08:18 +03:00
dma_resv_for_each_fence ( & cursor , & resv , usage , fence ) {
2021-09-24 18:10:19 +03:00
if ( ! r ) {
pr_err ( " More than one fence found \n " ) ;
r = - EINVAL ;
goto err_unlock ;
}
if ( f ! = fence ) {
pr_err ( " Unexpected fence \n " ) ;
r = - EINVAL ;
goto err_unlock ;
}
2021-11-09 13:08:18 +03:00
if ( dma_resv_iter_usage ( & cursor ) ! = usage ) {
2021-09-24 18:10:19 +03:00
pr_err ( " Unexpected fence usage \n " ) ;
r = - EINVAL ;
goto err_unlock ;
}
r = 0 ;
}
if ( r ) {
pr_err ( " No fence found \n " ) ;
goto err_unlock ;
}
dma_fence_signal ( f ) ;
err_unlock :
dma_resv_unlock ( & resv ) ;
err_free :
dma_resv_fini ( & resv ) ;
dma_fence_put ( f ) ;
return r ;
}
2021-11-09 13:08:18 +03:00
static int test_for_each_unlocked ( void * arg )
2021-09-24 18:10:19 +03:00
{
2021-11-09 13:08:18 +03:00
enum dma_resv_usage usage = ( unsigned long ) arg ;
2021-09-24 18:10:19 +03:00
struct dma_resv_iter cursor ;
struct dma_fence * f , * fence ;
struct dma_resv resv ;
int r ;
f = alloc_fence ( ) ;
if ( ! f )
return - ENOMEM ;
2022-09-14 19:43:18 +03:00
dma_fence_enable_sw_signaling ( f ) ;
2021-09-24 18:10:19 +03:00
dma_resv_init ( & resv ) ;
r = dma_resv_lock ( & resv , NULL ) ;
if ( r ) {
pr_err ( " Resv locking failed \n " ) ;
goto err_free ;
}
2021-11-16 17:20:45 +03:00
r = dma_resv_reserve_fences ( & resv , 1 ) ;
if ( r ) {
pr_err ( " Resv shared slot allocation failed \n " ) ;
dma_resv_unlock ( & resv ) ;
goto err_free ;
}
2021-09-24 18:10:19 +03:00
2021-11-09 13:08:18 +03:00
dma_resv_add_fence ( & resv , f , usage ) ;
2021-09-24 18:10:19 +03:00
dma_resv_unlock ( & resv ) ;
r = - ENOENT ;
2021-11-09 13:08:18 +03:00
dma_resv_iter_begin ( & cursor , & resv , usage ) ;
2021-09-24 18:10:19 +03:00
dma_resv_for_each_fence_unlocked ( & cursor , fence ) {
if ( ! r ) {
pr_err ( " More than one fence found \n " ) ;
r = - EINVAL ;
goto err_iter_end ;
}
if ( ! dma_resv_iter_is_restarted ( & cursor ) ) {
pr_err ( " No restart flag \n " ) ;
goto err_iter_end ;
}
if ( f ! = fence ) {
pr_err ( " Unexpected fence \n " ) ;
r = - EINVAL ;
goto err_iter_end ;
}
2021-11-09 13:08:18 +03:00
if ( dma_resv_iter_usage ( & cursor ) ! = usage ) {
2021-09-24 18:10:19 +03:00
pr_err ( " Unexpected fence usage \n " ) ;
r = - EINVAL ;
goto err_iter_end ;
}
/* We use r as state here */
if ( r = = - ENOENT ) {
r = - EINVAL ;
/* That should trigger an restart */
2022-04-04 15:58:37 +03:00
cursor . fences = ( void * ) ~ 0 ;
2021-09-24 18:10:19 +03:00
} else if ( r = = - EINVAL ) {
r = 0 ;
}
}
if ( r )
pr_err ( " No fence found \n " ) ;
err_iter_end :
dma_resv_iter_end ( & cursor ) ;
dma_fence_signal ( f ) ;
err_free :
dma_resv_fini ( & resv ) ;
dma_fence_put ( f ) ;
return r ;
}
2021-11-09 13:08:18 +03:00
static int test_get_fences ( void * arg )
2021-09-24 18:10:19 +03:00
{
2021-11-09 13:08:18 +03:00
enum dma_resv_usage usage = ( unsigned long ) arg ;
2021-10-28 14:19:22 +03:00
struct dma_fence * f , * * fences = NULL ;
2021-09-24 18:10:19 +03:00
struct dma_resv resv ;
int r , i ;
f = alloc_fence ( ) ;
if ( ! f )
return - ENOMEM ;
2022-09-14 19:43:18 +03:00
dma_fence_enable_sw_signaling ( f ) ;
2021-09-24 18:10:19 +03:00
dma_resv_init ( & resv ) ;
r = dma_resv_lock ( & resv , NULL ) ;
if ( r ) {
pr_err ( " Resv locking failed \n " ) ;
2021-10-26 11:34:37 +03:00
goto err_resv ;
2021-09-24 18:10:19 +03:00
}
2021-11-16 17:20:45 +03:00
r = dma_resv_reserve_fences ( & resv , 1 ) ;
if ( r ) {
pr_err ( " Resv shared slot allocation failed \n " ) ;
dma_resv_unlock ( & resv ) ;
goto err_resv ;
}
2021-09-24 18:10:19 +03:00
2021-11-09 13:08:18 +03:00
dma_resv_add_fence ( & resv , f , usage ) ;
2021-09-24 18:10:19 +03:00
dma_resv_unlock ( & resv ) ;
2021-11-09 13:08:18 +03:00
r = dma_resv_get_fences ( & resv , usage , & i , & fences ) ;
2021-09-24 18:10:19 +03:00
if ( r ) {
pr_err ( " get_fences failed \n " ) ;
goto err_free ;
}
2021-10-28 14:19:22 +03:00
if ( i ! = 1 | | fences [ 0 ] ! = f ) {
pr_err ( " get_fences returned unexpected fence \n " ) ;
goto err_free ;
2021-09-24 18:10:19 +03:00
}
dma_fence_signal ( f ) ;
err_free :
while ( i - - )
dma_fence_put ( fences [ i ] ) ;
kfree ( fences ) ;
2021-10-26 11:34:37 +03:00
err_resv :
2021-09-24 18:10:19 +03:00
dma_resv_fini ( & resv ) ;
dma_fence_put ( f ) ;
return r ;
}
int dma_resv ( void )
{
static const struct subtest tests [ ] = {
SUBTEST ( sanitycheck ) ,
2021-11-09 13:08:18 +03:00
SUBTEST ( test_signaling ) ,
SUBTEST ( test_for_each ) ,
SUBTEST ( test_for_each_unlocked ) ,
SUBTEST ( test_get_fences ) ,
2021-09-24 18:10:19 +03:00
} ;
2021-11-09 13:08:18 +03:00
enum dma_resv_usage usage ;
int r ;
2021-09-24 18:10:19 +03:00
spin_lock_init ( & fence_lock ) ;
2021-11-09 13:08:18 +03:00
for ( usage = DMA_RESV_USAGE_KERNEL ; usage < = DMA_RESV_USAGE_BOOKKEEP ;
2021-11-09 13:08:18 +03:00
+ + usage ) {
r = subtests ( tests , ( void * ) ( unsigned long ) usage ) ;
if ( r )
return r ;
}
return 0 ;
2021-09-24 18:10:19 +03:00
}