2016-03-15 15:35:08 -04:00
/*
* Copyright ( C ) 2013 - 2016 Red Hat
* Author : Rob Clark < robdclark @ gmail . 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 .
*
* You should have received a copy of the GNU General Public License along with
* this program . If not , see < http : //www.gnu.org/licenses/>.
*/
2016-10-25 13:00:45 +01:00
# include <linux/dma-fence.h>
2016-03-15 17:22:13 -04:00
2016-03-15 15:35:08 -04:00
# include "msm_drv.h"
# include "msm_fence.h"
2016-03-15 17:22:13 -04:00
struct msm_fence_context *
msm_fence_context_alloc ( struct drm_device * dev , const char * name )
2016-03-15 15:35:08 -04:00
{
2016-03-15 17:22:13 -04:00
struct msm_fence_context * fctx ;
fctx = kzalloc ( sizeof ( * fctx ) , GFP_KERNEL ) ;
if ( ! fctx )
return ERR_PTR ( - ENOMEM ) ;
fctx - > dev = dev ;
2017-10-20 11:06:57 -06:00
strncpy ( fctx - > name , name , sizeof ( fctx - > name ) ) ;
2016-10-25 13:00:45 +01:00
fctx - > context = dma_fence_context_alloc ( 1 ) ;
2016-03-15 17:22:13 -04:00
init_waitqueue_head ( & fctx - > event ) ;
2016-03-15 18:26:28 -04:00
spin_lock_init ( & fctx - > spinlock ) ;
2016-03-15 17:22:13 -04:00
return fctx ;
2016-03-15 15:35:08 -04:00
}
2016-03-15 17:22:13 -04:00
void msm_fence_context_free ( struct msm_fence_context * fctx )
2016-03-15 15:35:08 -04:00
{
2016-03-15 17:22:13 -04:00
kfree ( fctx ) ;
}
static inline bool fence_completed ( struct msm_fence_context * fctx , uint32_t fence )
{
return ( int32_t ) ( fctx - > completed_fence - fence ) > = 0 ;
}
2016-03-15 15:35:08 -04:00
2016-03-15 18:26:28 -04:00
/* legacy path for WAIT_FENCE ioctl: */
2016-03-15 17:22:13 -04:00
int msm_wait_fence ( struct msm_fence_context * fctx , uint32_t fence ,
ktime_t * timeout , bool interruptible )
{
int ret ;
2016-03-15 15:35:08 -04:00
2016-03-15 17:22:13 -04:00
if ( fence > fctx - > last_fence ) {
DRM_ERROR ( " %s: waiting on invalid fence: %u (of %u) \n " ,
fctx - > name , fence , fctx - > last_fence ) ;
2016-03-15 15:35:08 -04:00
return - EINVAL ;
}
if ( ! timeout ) {
/* no-wait: */
2016-03-15 17:22:13 -04:00
ret = fence_completed ( fctx , fence ) ? 0 : - EBUSY ;
2016-03-15 15:35:08 -04:00
} else {
2016-03-16 14:57:22 -04:00
unsigned long remaining_jiffies = timeout_to_jiffies ( timeout ) ;
2016-03-15 15:35:08 -04:00
if ( interruptible )
2016-03-15 17:22:13 -04:00
ret = wait_event_interruptible_timeout ( fctx - > event ,
fence_completed ( fctx , fence ) ,
2016-03-15 15:35:08 -04:00
remaining_jiffies ) ;
else
2016-03-15 17:22:13 -04:00
ret = wait_event_timeout ( fctx - > event ,
fence_completed ( fctx , fence ) ,
2016-03-15 15:35:08 -04:00
remaining_jiffies ) ;
if ( ret = = 0 ) {
DBG ( " timeout waiting for fence: %u (completed: %u) " ,
2016-03-15 17:22:13 -04:00
fence , fctx - > completed_fence ) ;
2016-03-15 15:35:08 -04:00
ret = - ETIMEDOUT ;
} else if ( ret ! = - ERESTARTSYS ) {
ret = 0 ;
}
}
return ret ;
}
/* called from workqueue */
2016-03-15 17:22:13 -04:00
void msm_update_fence ( struct msm_fence_context * fctx , uint32_t fence )
2016-03-15 15:35:08 -04:00
{
2016-03-15 18:26:28 -04:00
spin_lock ( & fctx - > spinlock ) ;
2016-03-15 17:22:13 -04:00
fctx - > completed_fence = max ( fence , fctx - > completed_fence ) ;
2016-03-15 18:26:28 -04:00
spin_unlock ( & fctx - > spinlock ) ;
2016-03-15 15:35:08 -04:00
2016-03-15 17:22:13 -04:00
wake_up_all ( & fctx - > event ) ;
2016-03-15 15:35:08 -04:00
}
2016-03-15 18:26:28 -04:00
struct msm_fence {
2016-10-25 13:00:45 +01:00
struct dma_fence base ;
2017-04-12 12:12:00 -07:00
struct msm_fence_context * fctx ;
2016-03-15 18:26:28 -04:00
} ;
2016-10-25 13:00:45 +01:00
static inline struct msm_fence * to_msm_fence ( struct dma_fence * fence )
2016-03-15 18:26:28 -04:00
{
return container_of ( fence , struct msm_fence , base ) ;
}
2016-10-25 13:00:45 +01:00
static const char * msm_fence_get_driver_name ( struct dma_fence * fence )
2016-03-15 18:26:28 -04:00
{
return " msm " ;
}
2016-10-25 13:00:45 +01:00
static const char * msm_fence_get_timeline_name ( struct dma_fence * fence )
2016-03-15 18:26:28 -04:00
{
struct msm_fence * f = to_msm_fence ( fence ) ;
return f - > fctx - > name ;
}
2016-10-25 13:00:45 +01:00
static bool msm_fence_signaled ( struct dma_fence * fence )
2016-03-15 18:26:28 -04:00
{
struct msm_fence * f = to_msm_fence ( fence ) ;
return fence_completed ( f - > fctx , f - > base . seqno ) ;
}
2016-10-25 13:00:45 +01:00
static const struct dma_fence_ops msm_fence_ops = {
2016-03-15 18:26:28 -04:00
. get_driver_name = msm_fence_get_driver_name ,
. get_timeline_name = msm_fence_get_timeline_name ,
. signaled = msm_fence_signaled ,
} ;
2016-10-25 13:00:45 +01:00
struct dma_fence *
2016-03-15 18:26:28 -04:00
msm_fence_alloc ( struct msm_fence_context * fctx )
{
struct msm_fence * f ;
f = kzalloc ( sizeof ( * f ) , GFP_KERNEL ) ;
if ( ! f )
return ERR_PTR ( - ENOMEM ) ;
f - > fctx = fctx ;
2016-10-25 13:00:45 +01:00
dma_fence_init ( & f - > base , & msm_fence_ops , & fctx - > spinlock ,
fctx - > context , + + fctx - > last_fence ) ;
2016-03-15 18:26:28 -04:00
return & f - > base ;
}