2013-03-22 16:34:03 +02:00
/*
* Tegra host1x Channel
*
* Copyright ( c ) 2010 - 2013 , NVIDIA Corporation .
*
* This program is free software ; you can redistribute it and / or modify it
* under the terms and conditions of the GNU General Public License ,
* version 2 , as published by the Free Software Foundation .
*
* This program is distributed in the hope 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/>.
*/
# include <linux/slab.h>
# include <linux/module.h>
# include "channel.h"
# include "dev.h"
# include "job.h"
/* Constructor for the host1x device list */
int host1x_channel_list_init ( struct host1x * host )
{
INIT_LIST_HEAD ( & host - > chlist . list ) ;
mutex_init ( & host - > chlist_mutex ) ;
if ( host - > info - > nb_channels > BITS_PER_LONG ) {
WARN ( 1 , " host1x hardware has more channels than supported by the driver \n " ) ;
return - ENOSYS ;
}
return 0 ;
}
int host1x_job_submit ( struct host1x_job * job )
{
struct host1x * host = dev_get_drvdata ( job - > channel - > dev - > parent ) ;
return host1x_hw_channel_submit ( host , job ) ;
}
2013-11-08 11:41:42 +01:00
EXPORT_SYMBOL ( host1x_job_submit ) ;
2013-03-22 16:34:03 +02:00
struct host1x_channel * host1x_channel_get ( struct host1x_channel * channel )
{
int err = 0 ;
mutex_lock ( & channel - > reflock ) ;
if ( channel - > refcount = = 0 )
err = host1x_cdma_init ( & channel - > cdma ) ;
if ( ! err )
channel - > refcount + + ;
mutex_unlock ( & channel - > reflock ) ;
return err ? NULL : channel ;
}
2013-11-08 11:41:42 +01:00
EXPORT_SYMBOL ( host1x_channel_get ) ;
2013-03-22 16:34:03 +02:00
void host1x_channel_put ( struct host1x_channel * channel )
{
mutex_lock ( & channel - > reflock ) ;
if ( channel - > refcount = = 1 ) {
struct host1x * host = dev_get_drvdata ( channel - > dev - > parent ) ;
host1x_hw_cdma_stop ( host , & channel - > cdma ) ;
host1x_cdma_deinit ( & channel - > cdma ) ;
}
channel - > refcount - - ;
mutex_unlock ( & channel - > reflock ) ;
}
2013-11-08 11:41:42 +01:00
EXPORT_SYMBOL ( host1x_channel_put ) ;
2013-03-22 16:34:03 +02:00
struct host1x_channel * host1x_channel_request ( struct device * dev )
{
struct host1x * host = dev_get_drvdata ( dev - > parent ) ;
int max_channels = host - > info - > nb_channels ;
struct host1x_channel * channel = NULL ;
int index , err ;
mutex_lock ( & host - > chlist_mutex ) ;
index = find_first_zero_bit ( & host - > allocated_channels , max_channels ) ;
if ( index > = max_channels )
goto fail ;
channel = kzalloc ( sizeof ( * channel ) , GFP_KERNEL ) ;
if ( ! channel )
goto fail ;
err = host1x_hw_channel_init ( host , channel , index ) ;
if ( err < 0 )
goto fail ;
/* Link device to host1x_channel */
channel - > dev = dev ;
/* Add to channel list */
list_add_tail ( & channel - > list , & host - > chlist . list ) ;
host - > allocated_channels | = BIT ( index ) ;
mutex_unlock ( & host - > chlist_mutex ) ;
return channel ;
fail :
dev_err ( dev , " failed to init channel \n " ) ;
kfree ( channel ) ;
mutex_unlock ( & host - > chlist_mutex ) ;
return NULL ;
}
2013-11-08 11:41:42 +01:00
EXPORT_SYMBOL ( host1x_channel_request ) ;
2013-03-22 16:34:03 +02:00
void host1x_channel_free ( struct host1x_channel * channel )
{
struct host1x * host = dev_get_drvdata ( channel - > dev - > parent ) ;
host - > allocated_channels & = ~ BIT ( channel - > id ) ;
list_del ( & channel - > list ) ;
kfree ( channel ) ;
}
2013-11-08 11:41:42 +01:00
EXPORT_SYMBOL ( host1x_channel_free ) ;