2012-04-10 13:19:55 -05:00
/*
2013-02-11 12:43:09 -05:00
* drivers / gpu / drm / omapdrm / omap_gem_dmabuf . c
2012-04-10 13:19:55 -05:00
*
* Copyright ( C ) 2011 Texas Instruments
* Author : Rob Clark < rob . clark @ linaro . org >
*
* 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/>.
*/
# include "omap_drv.h"
# include <linux/dma-buf.h>
static struct sg_table * omap_gem_map_dma_buf (
struct dma_buf_attachment * attachment ,
enum dma_data_direction dir )
{
struct drm_gem_object * obj = attachment - > dmabuf - > priv ;
struct sg_table * sg ;
dma_addr_t paddr ;
int ret ;
sg = kzalloc ( sizeof ( * sg ) , GFP_KERNEL ) ;
if ( ! sg )
return ERR_PTR ( - ENOMEM ) ;
/* camera, etc, need physically contiguous.. but we need a
* better way to know this . .
*/
ret = omap_gem_get_paddr ( obj , & paddr , true ) ;
if ( ret )
goto out ;
ret = sg_alloc_table ( sg , 1 , GFP_KERNEL ) ;
if ( ret )
goto out ;
sg_init_table ( sg - > sgl , 1 ) ;
sg_dma_len ( sg - > sgl ) = obj - > size ;
sg_set_page ( sg - > sgl , pfn_to_page ( PFN_DOWN ( paddr ) ) , obj - > size , 0 ) ;
sg_dma_address ( sg - > sgl ) = paddr ;
2012-05-17 02:37:25 -06:00
/* this should be after _get_paddr() to ensure we have pages attached */
omap_gem_dma_sync ( obj , dir ) ;
2012-04-10 13:19:55 -05:00
return sg ;
2013-01-15 20:46:50 +01:00
out :
kfree ( sg ) ;
return ERR_PTR ( ret ) ;
2012-04-10 13:19:55 -05:00
}
static void omap_gem_unmap_dma_buf ( struct dma_buf_attachment * attachment ,
struct sg_table * sg , enum dma_data_direction dir )
{
struct drm_gem_object * obj = attachment - > dmabuf - > priv ;
omap_gem_put_paddr ( obj ) ;
sg_free_table ( sg ) ;
kfree ( sg ) ;
}
static void omap_gem_dmabuf_release ( struct dma_buf * buffer )
{
struct drm_gem_object * obj = buffer - > priv ;
/* release reference that was taken when dmabuf was exported
* in omap_gem_prime_set ( ) . .
*/
drm_gem_object_unreference_unlocked ( obj ) ;
}
static int omap_gem_dmabuf_begin_cpu_access ( struct dma_buf * buffer ,
size_t start , size_t len , enum dma_data_direction dir )
{
struct drm_gem_object * obj = buffer - > priv ;
struct page * * pages ;
if ( omap_gem_flags ( obj ) & OMAP_BO_TILED ) {
/* TODO we would need to pin at least part of the buffer to
* get de - tiled view . For now just reject it .
*/
return - ENOMEM ;
}
/* make sure we have the pages: */
return omap_gem_get_pages ( obj , & pages , true ) ;
}
static void omap_gem_dmabuf_end_cpu_access ( struct dma_buf * buffer ,
size_t start , size_t len , enum dma_data_direction dir )
{
struct drm_gem_object * obj = buffer - > priv ;
omap_gem_put_pages ( obj ) ;
}
static void * omap_gem_dmabuf_kmap_atomic ( struct dma_buf * buffer ,
unsigned long page_num )
{
struct drm_gem_object * obj = buffer - > priv ;
struct page * * pages ;
omap_gem_get_pages ( obj , & pages , false ) ;
2012-05-17 02:37:25 -06:00
omap_gem_cpu_sync ( obj , page_num ) ;
2012-04-10 13:19:55 -05:00
return kmap_atomic ( pages [ page_num ] ) ;
}
static void omap_gem_dmabuf_kunmap_atomic ( struct dma_buf * buffer ,
unsigned long page_num , void * addr )
{
kunmap_atomic ( addr ) ;
}
static void * omap_gem_dmabuf_kmap ( struct dma_buf * buffer ,
unsigned long page_num )
{
struct drm_gem_object * obj = buffer - > priv ;
struct page * * pages ;
omap_gem_get_pages ( obj , & pages , false ) ;
2012-05-17 02:37:25 -06:00
omap_gem_cpu_sync ( obj , page_num ) ;
2012-04-10 13:19:55 -05:00
return kmap ( pages [ page_num ] ) ;
}
static void omap_gem_dmabuf_kunmap ( struct dma_buf * buffer ,
unsigned long page_num , void * addr )
{
struct drm_gem_object * obj = buffer - > priv ;
struct page * * pages ;
omap_gem_get_pages ( obj , & pages , false ) ;
kunmap ( pages [ page_num ] ) ;
}
2012-05-17 02:37:25 -06:00
static int omap_gem_dmabuf_mmap ( struct dma_buf * buffer ,
struct vm_area_struct * vma )
{
struct drm_gem_object * obj = buffer - > priv ;
2013-06-27 08:39:58 +09:00
struct drm_device * dev = obj - > dev ;
2012-05-17 02:37:25 -06:00
int ret = 0 ;
if ( WARN_ON ( ! obj - > filp ) )
return - EINVAL ;
2013-06-27 08:39:58 +09:00
mutex_lock ( & dev - > struct_mutex ) ;
2013-04-16 14:21:23 +02:00
ret = drm_gem_mmap_obj ( obj , omap_gem_mmap_size ( obj ) , vma ) ;
2013-06-27 08:39:58 +09:00
mutex_unlock ( & dev - > struct_mutex ) ;
2013-04-16 14:21:23 +02:00
if ( ret < 0 )
return ret ;
2012-05-17 02:37:25 -06:00
return omap_gem_mmap_obj ( obj , vma ) ;
}
2013-04-10 10:44:00 +03:00
static struct dma_buf_ops omap_dmabuf_ops = {
2012-04-10 13:19:55 -05:00
. map_dma_buf = omap_gem_map_dma_buf ,
. unmap_dma_buf = omap_gem_unmap_dma_buf ,
. release = omap_gem_dmabuf_release ,
. begin_cpu_access = omap_gem_dmabuf_begin_cpu_access ,
. end_cpu_access = omap_gem_dmabuf_end_cpu_access ,
. kmap_atomic = omap_gem_dmabuf_kmap_atomic ,
. kunmap_atomic = omap_gem_dmabuf_kunmap_atomic ,
. kmap = omap_gem_dmabuf_kmap ,
. kunmap = omap_gem_dmabuf_kunmap ,
2012-05-17 02:37:25 -06:00
. mmap = omap_gem_dmabuf_mmap ,
2012-04-10 13:19:55 -05:00
} ;
2012-11-14 19:40:14 +09:00
struct dma_buf * omap_gem_prime_export ( struct drm_device * dev ,
2012-04-10 13:19:55 -05:00
struct drm_gem_object * obj , int flags )
{
2014-07-01 12:57:26 +02:00
return dma_buf_export ( obj , & omap_dmabuf_ops , obj - > size , flags , NULL ) ;
2012-04-10 13:19:55 -05:00
}
2012-05-17 02:37:26 -06:00
2012-11-14 19:40:14 +09:00
struct drm_gem_object * omap_gem_prime_import ( struct drm_device * dev ,
2012-05-17 02:37:26 -06:00
struct dma_buf * buffer )
{
struct drm_gem_object * obj ;
/* is this one of own objects? */
if ( buffer - > ops = = & omap_dmabuf_ops ) {
obj = buffer - > priv ;
/* is it from our device? */
if ( obj - > dev = = dev ) {
2012-09-27 15:30:06 +09:00
/*
* Importing dmabuf exported from out own gem increases
* refcount on gem itself instead of f_count of dmabuf .
*/
2012-05-17 02:37:26 -06:00
drm_gem_object_reference ( obj ) ;
return obj ;
}
}
/*
* TODO add support for importing buffers from other devices . .
* for now we don ' t need this but would be nice to add eventually
*/
return ERR_PTR ( - EINVAL ) ;
}