2016-06-01 16:10:03 +03:00
/*
2016-10-25 15:00:45 +03:00
* dma - fence - array : aggregate fences to be waited together
2016-06-01 16:10:03 +03:00
*
* Copyright ( C ) 2016 Collabora Ltd
* Copyright ( C ) 2016 Advanced Micro Devices , Inc .
* Authors :
* Gustavo Padovan < gustavo @ padovan . org >
* Christian König < christian . koenig @ amd . com >
*
* This program is free software ; you can redistribute it and / or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation .
*
* This program is distributed in the hope that it will be useful , but WITHOUT
* ANY WARRANTY ; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE . See the GNU General Public License for
* more details .
*/
# include <linux/export.h>
# include <linux/slab.h>
2016-10-25 15:00:45 +03:00
# include <linux/dma-fence-array.h>
2016-06-01 16:10:03 +03:00
2016-10-25 15:00:45 +03:00
static const char * dma_fence_array_get_driver_name ( struct dma_fence * fence )
2016-06-01 16:10:03 +03:00
{
2016-10-25 15:00:45 +03:00
return " dma_fence_array " ;
2016-06-01 16:10:03 +03:00
}
2016-10-25 15:00:45 +03:00
static const char * dma_fence_array_get_timeline_name ( struct dma_fence * fence )
2016-06-01 16:10:03 +03:00
{
return " unbound " ;
}
2016-10-25 15:00:45 +03:00
static void dma_fence_array_cb_func ( struct dma_fence * f ,
struct dma_fence_cb * cb )
2016-06-01 16:10:03 +03:00
{
2016-10-25 15:00:45 +03:00
struct dma_fence_array_cb * array_cb =
container_of ( cb , struct dma_fence_array_cb , cb ) ;
struct dma_fence_array * array = array_cb - > array ;
2016-06-01 16:10:03 +03:00
if ( atomic_dec_and_test ( & array - > num_pending ) )
2016-10-25 15:00:45 +03:00
dma_fence_signal ( & array - > base ) ;
dma_fence_put ( & array - > base ) ;
2016-06-01 16:10:03 +03:00
}
2016-10-25 15:00:45 +03:00
static bool dma_fence_array_enable_signaling ( struct dma_fence * fence )
2016-06-01 16:10:03 +03:00
{
2016-10-25 15:00:45 +03:00
struct dma_fence_array * array = to_dma_fence_array ( fence ) ;
struct dma_fence_array_cb * cb = ( void * ) ( & array [ 1 ] ) ;
2016-06-01 16:10:03 +03:00
unsigned i ;
for ( i = 0 ; i < array - > num_fences ; + + i ) {
cb [ i ] . array = array ;
2016-06-01 16:10:04 +03:00
/*
* As we may report that the fence is signaled before all
* callbacks are complete , we need to take an additional
* reference count on the array so that we do not free it too
* early . The core fence handling will only hold the reference
* until we signal the array as complete ( but that is now
* insufficient ) .
*/
2016-10-25 15:00:45 +03:00
dma_fence_get ( & array - > base ) ;
if ( dma_fence_add_callback ( array - > fences [ i ] , & cb [ i ] . cb ,
dma_fence_array_cb_func ) ) {
dma_fence_put ( & array - > base ) ;
2016-06-01 16:10:03 +03:00
if ( atomic_dec_and_test ( & array - > num_pending ) )
return false ;
2016-06-01 16:10:04 +03:00
}
2016-06-01 16:10:03 +03:00
}
return true ;
}
2016-10-25 15:00:45 +03:00
static bool dma_fence_array_signaled ( struct dma_fence * fence )
2016-06-01 16:10:03 +03:00
{
2016-10-25 15:00:45 +03:00
struct dma_fence_array * array = to_dma_fence_array ( fence ) ;
2016-06-01 16:10:03 +03:00
2016-06-01 16:10:04 +03:00
return atomic_read ( & array - > num_pending ) < = 0 ;
2016-06-01 16:10:03 +03:00
}
2016-10-25 15:00:45 +03:00
static void dma_fence_array_release ( struct dma_fence * fence )
2016-06-01 16:10:03 +03:00
{
2016-10-25 15:00:45 +03:00
struct dma_fence_array * array = to_dma_fence_array ( fence ) ;
2016-06-01 16:10:03 +03:00
unsigned i ;
for ( i = 0 ; i < array - > num_fences ; + + i )
2016-10-25 15:00:45 +03:00
dma_fence_put ( array - > fences [ i ] ) ;
2016-06-01 16:10:03 +03:00
kfree ( array - > fences ) ;
2016-10-25 15:00:45 +03:00
dma_fence_free ( fence ) ;
2016-06-01 16:10:03 +03:00
}
2016-10-25 15:00:45 +03:00
const struct dma_fence_ops dma_fence_array_ops = {
. get_driver_name = dma_fence_array_get_driver_name ,
. get_timeline_name = dma_fence_array_get_timeline_name ,
. enable_signaling = dma_fence_array_enable_signaling ,
. signaled = dma_fence_array_signaled ,
. wait = dma_fence_default_wait ,
. release = dma_fence_array_release ,
2016-06-01 16:10:03 +03:00
} ;
2016-10-25 15:00:45 +03:00
EXPORT_SYMBOL ( dma_fence_array_ops ) ;
2016-06-01 16:10:03 +03:00
/**
2016-10-25 15:00:45 +03:00
* dma_fence_array_create - Create a custom fence array
2016-06-01 16:10:04 +03:00
* @ num_fences : [ in ] number of fences to add in the array
* @ fences : [ in ] array containing the fences
* @ context : [ in ] fence context to use
* @ seqno : [ in ] sequence number to use
2016-08-17 02:31:00 +03:00
* @ signal_on_any : [ in ] signal on any fence in the array
2016-06-01 16:10:03 +03:00
*
2016-10-25 15:00:45 +03:00
* Allocate a dma_fence_array object and initialize the base fence with
* dma_fence_init ( ) .
2016-06-01 16:10:03 +03:00
* In case of error it returns NULL .
*
2016-08-17 02:31:00 +03:00
* The caller should allocate the fences array with num_fences size
2016-06-01 16:10:03 +03:00
* and fill it with the fences it wants to add to the object . Ownership of this
2016-10-25 15:00:45 +03:00
* array is taken and dma_fence_put ( ) is used on each fence on release .
2016-06-01 16:10:04 +03:00
*
* If @ signal_on_any is true the fence array signals if any fence in the array
* signals , otherwise it signals when all fences in the array signal .
2016-06-01 16:10:03 +03:00
*/
2016-10-25 15:00:45 +03:00
struct dma_fence_array * dma_fence_array_create ( int num_fences ,
struct dma_fence * * fences ,
u64 context , unsigned seqno ,
bool signal_on_any )
2016-06-01 16:10:03 +03:00
{
2016-10-25 15:00:45 +03:00
struct dma_fence_array * array ;
2016-06-01 16:10:03 +03:00
size_t size = sizeof ( * array ) ;
/* Allocate the callback structures behind the array. */
2016-10-25 15:00:45 +03:00
size + = num_fences * sizeof ( struct dma_fence_array_cb ) ;
2016-06-01 16:10:03 +03:00
array = kzalloc ( size , GFP_KERNEL ) ;
if ( ! array )
return NULL ;
spin_lock_init ( & array - > lock ) ;
2016-10-25 15:00:45 +03:00
dma_fence_init ( & array - > base , & dma_fence_array_ops , & array - > lock ,
context , seqno ) ;
2016-06-01 16:10:03 +03:00
array - > num_fences = num_fences ;
2016-06-01 16:10:04 +03:00
atomic_set ( & array - > num_pending , signal_on_any ? 1 : num_fences ) ;
2016-06-01 16:10:03 +03:00
array - > fences = fences ;
return array ;
}
2016-10-25 15:00:45 +03:00
EXPORT_SYMBOL ( dma_fence_array_create ) ;
2017-03-17 19:34:49 +03:00
/**
* dma_fence_match_context - Check if all fences are from the given context
* @ fence : [ in ] fence or fence array
* @ context : [ in ] fence context to check all fences against
*
* Checks the provided fence or , for a fence array , all fences in the array
* against the given context . Returns false if any fence is from a different
* context .
*/
bool dma_fence_match_context ( struct dma_fence * fence , u64 context )
{
struct dma_fence_array * array = to_dma_fence_array ( fence ) ;
unsigned i ;
if ( ! dma_fence_is_array ( fence ) )
return fence - > context = = context ;
for ( i = 0 ; i < array - > num_fences ; i + + ) {
if ( array - > fences [ i ] - > context ! = context )
return false ;
}
return true ;
}
EXPORT_SYMBOL ( dma_fence_match_context ) ;