2017-10-20 11:06:55 -06:00
/* Copyright (c) 2017 The Linux Foundation. All rights reserved.
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 and
* only 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/kref.h>
# include "msm_gpu.h"
void msm_submitqueue_destroy ( struct kref * kref )
{
struct msm_gpu_submitqueue * queue = container_of ( kref ,
struct msm_gpu_submitqueue , ref ) ;
kfree ( queue ) ;
}
struct msm_gpu_submitqueue * msm_submitqueue_get ( struct msm_file_private * ctx ,
u32 id )
{
struct msm_gpu_submitqueue * entry ;
if ( ! ctx )
return NULL ;
read_lock ( & ctx - > queuelock ) ;
list_for_each_entry ( entry , & ctx - > submitqueues , node ) {
if ( entry - > id = = id ) {
kref_get ( & entry - > ref ) ;
read_unlock ( & ctx - > queuelock ) ;
return entry ;
}
}
read_unlock ( & ctx - > queuelock ) ;
return NULL ;
}
void msm_submitqueue_close ( struct msm_file_private * ctx )
{
struct msm_gpu_submitqueue * entry , * tmp ;
if ( ! ctx )
return ;
/*
* No lock needed in close and there won ' t
* be any more user ioctls coming our way
*/
list_for_each_entry_safe ( entry , tmp , & ctx - > submitqueues , node )
msm_submitqueue_put ( entry ) ;
}
2017-10-20 11:06:57 -06:00
int msm_submitqueue_create ( struct drm_device * drm , struct msm_file_private * ctx ,
u32 prio , u32 flags , u32 * id )
2017-10-20 11:06:55 -06:00
{
2017-10-20 11:06:57 -06:00
struct msm_drm_private * priv = drm - > dev_private ;
2017-10-20 11:06:55 -06:00
struct msm_gpu_submitqueue * queue ;
if ( ! ctx )
return - ENODEV ;
queue = kzalloc ( sizeof ( * queue ) , GFP_KERNEL ) ;
if ( ! queue )
return - ENOMEM ;
kref_init ( & queue - > ref ) ;
queue - > flags = flags ;
2017-10-20 11:06:57 -06:00
if ( priv - > gpu ) {
if ( prio > = priv - > gpu - > nr_rings )
return - EINVAL ;
queue - > prio = prio ;
}
2017-10-20 11:06:55 -06:00
write_lock ( & ctx - > queuelock ) ;
queue - > id = ctx - > queueid + + ;
if ( id )
* id = queue - > id ;
list_add_tail ( & queue - > node , & ctx - > submitqueues ) ;
write_unlock ( & ctx - > queuelock ) ;
return 0 ;
}
2017-10-20 11:06:57 -06:00
int msm_submitqueue_init ( struct drm_device * drm , struct msm_file_private * ctx )
2017-10-20 11:06:55 -06:00
{
2017-10-20 11:06:57 -06:00
struct msm_drm_private * priv = drm - > dev_private ;
int default_prio ;
2017-10-20 11:06:55 -06:00
if ( ! ctx )
return 0 ;
2017-10-20 11:06:57 -06:00
/*
* Select priority 2 as the " default priority " unless nr_rings is less
* than 2 and then pick the lowest pirority
*/
default_prio = priv - > gpu ?
clamp_t ( uint32_t , 2 , 0 , priv - > gpu - > nr_rings - 1 ) : 0 ;
2017-10-20 11:06:55 -06:00
INIT_LIST_HEAD ( & ctx - > submitqueues ) ;
rwlock_init ( & ctx - > queuelock ) ;
2017-10-20 11:06:57 -06:00
return msm_submitqueue_create ( drm , ctx , default_prio , 0 , NULL ) ;
2017-10-20 11:06:55 -06:00
}
int msm_submitqueue_remove ( struct msm_file_private * ctx , u32 id )
{
struct msm_gpu_submitqueue * entry ;
if ( ! ctx )
return 0 ;
/*
* id 0 is the " default " queue and can ' t be destroyed
* by the user
*/
if ( ! id )
return - ENOENT ;
write_lock ( & ctx - > queuelock ) ;
list_for_each_entry ( entry , & ctx - > submitqueues , node ) {
if ( entry - > id = = id ) {
list_del ( & entry - > node ) ;
write_unlock ( & ctx - > queuelock ) ;
msm_submitqueue_put ( entry ) ;
return 0 ;
}
}
write_unlock ( & ctx - > queuelock ) ;
return - ENOENT ;
}