2011-10-04 19:19:01 +09:00
/* exynos_drm_gem.c
*
* Copyright ( c ) 2011 Samsung Electronics Co . , Ltd .
* Author : Inki Dae < inki . dae @ samsung . com >
*
2012-12-18 02:30:17 +09:00
* This program is free software ; you can redistribute it and / or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation ; either version 2 of the License , or ( at your
* option ) any later version .
2011-10-04 19:19:01 +09:00
*/
2012-10-02 18:01:07 +01:00
# include <drm/drmP.h>
2013-07-24 21:07:52 +02:00
# include <drm/drm_vma_manager.h>
2011-10-04 19:19:01 +09:00
2012-03-16 18:47:05 +09:00
# include <linux/shmem_fs.h>
2015-08-16 14:33:08 +09:00
# include <linux/dma-buf.h>
2016-01-15 16:56:40 -08:00
# include <linux/pfn_t.h>
2011-10-04 19:19:01 +09:00
# include <drm/exynos_drm.h>
# include "exynos_drm_drv.h"
# include "exynos_drm_gem.h"
2013-08-23 12:05:06 +05:30
# include "exynos_drm_iommu.h"
2011-10-04 19:19:01 +09:00
2015-10-02 09:33:47 +09:00
static int exynos_drm_alloc_buf ( struct exynos_drm_gem * exynos_gem )
2015-08-16 14:38:49 +09:00
{
2015-10-02 09:33:47 +09:00
struct drm_device * dev = exynos_gem - > base . dev ;
2016-08-03 13:46:00 -07:00
unsigned long attr ;
2015-08-16 14:38:49 +09:00
unsigned int nr_pages ;
2015-10-13 13:47:20 +02:00
struct sg_table sgt ;
int ret = - ENOMEM ;
2015-08-16 14:38:49 +09:00
2015-10-02 09:33:47 +09:00
if ( exynos_gem - > dma_addr ) {
2015-08-16 14:38:49 +09:00
DRM_DEBUG_KMS ( " already allocated. \n " ) ;
return 0 ;
}
2016-08-03 13:46:00 -07:00
exynos_gem - > dma_attrs = 0 ;
2015-08-16 14:38:49 +09:00
/*
* if EXYNOS_BO_CONTIG , fully physically contiguous memory
* region will be allocated else physically contiguous
* as possible .
*/
2015-10-02 09:33:47 +09:00
if ( ! ( exynos_gem - > flags & EXYNOS_BO_NONCONTIG ) )
2016-08-03 13:46:00 -07:00
exynos_gem - > dma_attrs | = DMA_ATTR_FORCE_CONTIGUOUS ;
2015-08-16 14:38:49 +09:00
/*
* if EXYNOS_BO_WC or EXYNOS_BO_NONCACHABLE , writecombine mapping
* else cachable mapping .
*/
2015-10-02 09:33:47 +09:00
if ( exynos_gem - > flags & EXYNOS_BO_WC | |
! ( exynos_gem - > flags & EXYNOS_BO_CACHABLE ) )
2015-08-16 14:38:49 +09:00
attr = DMA_ATTR_WRITE_COMBINE ;
else
attr = DMA_ATTR_NON_CONSISTENT ;
2016-08-03 13:46:00 -07:00
exynos_gem - > dma_attrs | = attr ;
exynos_gem - > dma_attrs | = DMA_ATTR_NO_KERNEL_MAPPING ;
2015-08-16 14:38:49 +09:00
2015-10-02 09:33:47 +09:00
nr_pages = exynos_gem - > size > > PAGE_SHIFT ;
2015-08-16 14:38:49 +09:00
2017-05-17 14:23:12 +02:00
exynos_gem - > pages = kvmalloc_array ( nr_pages , sizeof ( struct page * ) ,
GFP_KERNEL | __GFP_ZERO ) ;
2015-10-13 13:47:20 +02:00
if ( ! exynos_gem - > pages ) {
DRM_ERROR ( " failed to allocate pages. \n " ) ;
return - ENOMEM ;
2015-09-16 14:29:34 +09:00
}
2015-08-16 14:38:49 +09:00
2016-02-29 17:50:53 +09:00
exynos_gem - > cookie = dma_alloc_attrs ( to_dma_dev ( dev ) , exynos_gem - > size ,
2015-10-02 09:33:47 +09:00
& exynos_gem - > dma_addr , GFP_KERNEL ,
2016-08-03 13:46:00 -07:00
exynos_gem - > dma_attrs ) ;
2015-10-02 09:33:47 +09:00
if ( ! exynos_gem - > cookie ) {
2015-09-16 14:29:34 +09:00
DRM_ERROR ( " failed to allocate buffer. \n " ) ;
2015-10-13 13:47:20 +02:00
goto err_free ;
}
2016-02-29 17:50:53 +09:00
ret = dma_get_sgtable_attrs ( to_dma_dev ( dev ) , & sgt , exynos_gem - > cookie ,
2015-10-13 13:47:20 +02:00
exynos_gem - > dma_addr , exynos_gem - > size ,
2016-08-03 13:46:00 -07:00
exynos_gem - > dma_attrs ) ;
2015-10-13 13:47:20 +02:00
if ( ret < 0 ) {
DRM_ERROR ( " failed to get sgtable. \n " ) ;
goto err_dma_free ;
2015-09-16 14:29:34 +09:00
}
2015-10-13 13:47:20 +02:00
if ( drm_prime_sg_to_page_addr_arrays ( & sgt , exynos_gem - > pages , NULL ,
nr_pages ) ) {
DRM_ERROR ( " invalid sgtable. \n " ) ;
ret = - EINVAL ;
goto err_sgt_free ;
2015-08-16 14:38:49 +09:00
}
2015-10-13 13:47:20 +02:00
sg_free_table ( & sgt ) ;
2015-08-16 14:38:49 +09:00
DRM_DEBUG_KMS ( " dma_addr(0x%lx), size(0x%lx) \n " ,
2015-10-02 09:33:47 +09:00
( unsigned long ) exynos_gem - > dma_addr , exynos_gem - > size ) ;
2015-08-16 14:38:49 +09:00
return 0 ;
2015-10-13 13:47:20 +02:00
err_sgt_free :
sg_free_table ( & sgt ) ;
err_dma_free :
2016-02-29 17:50:53 +09:00
dma_free_attrs ( to_dma_dev ( dev ) , exynos_gem - > size , exynos_gem - > cookie ,
2016-08-03 13:46:00 -07:00
exynos_gem - > dma_addr , exynos_gem - > dma_attrs ) ;
2015-10-13 13:47:20 +02:00
err_free :
2017-05-17 14:23:12 +02:00
kvfree ( exynos_gem - > pages ) ;
2015-10-13 13:47:20 +02:00
return ret ;
2015-08-16 14:38:49 +09:00
}
2015-10-02 09:33:47 +09:00
static void exynos_drm_free_buf ( struct exynos_drm_gem * exynos_gem )
2015-08-16 14:38:49 +09:00
{
2015-10-02 09:33:47 +09:00
struct drm_device * dev = exynos_gem - > base . dev ;
2015-08-16 14:38:49 +09:00
2015-10-02 09:33:47 +09:00
if ( ! exynos_gem - > dma_addr ) {
2015-08-16 14:38:49 +09:00
DRM_DEBUG_KMS ( " dma_addr is invalid. \n " ) ;
return ;
}
DRM_DEBUG_KMS ( " dma_addr(0x%lx), size(0x%lx) \n " ,
2015-10-02 09:33:47 +09:00
( unsigned long ) exynos_gem - > dma_addr , exynos_gem - > size ) ;
2015-08-16 14:38:49 +09:00
2016-02-29 17:50:53 +09:00
dma_free_attrs ( to_dma_dev ( dev ) , exynos_gem - > size , exynos_gem - > cookie ,
2015-10-02 09:33:47 +09:00
( dma_addr_t ) exynos_gem - > dma_addr ,
2016-08-03 13:46:00 -07:00
exynos_gem - > dma_attrs ) ;
2015-09-16 14:29:34 +09:00
2017-05-17 14:23:12 +02:00
kvfree ( exynos_gem - > pages ) ;
2015-08-16 14:38:49 +09:00
}
2011-12-13 14:39:13 +09:00
static int exynos_drm_gem_handle_create ( struct drm_gem_object * obj ,
struct drm_file * file_priv ,
unsigned int * handle )
2011-10-04 19:19:01 +09:00
{
int ret ;
/*
* allocate a id of idr table where the obj is registered
* and handle has the id what user can see .
*/
ret = drm_gem_handle_create ( file_priv , obj , handle ) ;
if ( ret )
2011-12-13 14:39:13 +09:00
return ret ;
2011-10-04 19:19:01 +09:00
DRM_DEBUG_KMS ( " gem handle = 0x%x \n " , * handle ) ;
/* drop reference from allocate - handle holds it now. */
drm_gem_object_unreference_unlocked ( obj ) ;
2011-12-13 14:39:13 +09:00
return 0 ;
}
2015-10-02 09:33:47 +09:00
void exynos_drm_gem_destroy ( struct exynos_drm_gem * exynos_gem )
2011-12-13 14:39:13 +09:00
{
2015-10-02 09:33:47 +09:00
struct drm_gem_object * obj = & exynos_gem - > base ;
2011-12-13 14:39:13 +09:00
2013-08-15 00:02:37 +02:00
DRM_DEBUG_KMS ( " handle count = %d \n " , obj - > handle_count ) ;
2011-10-04 19:19:01 +09:00
2012-06-12 16:52:54 +09:00
/*
* do not release memory region from exporter .
*
* the region will be released by exporter
* once dmabuf ' s refcount becomes 0.
*/
if ( obj - > import_attach )
2015-10-02 09:33:47 +09:00
drm_prime_gem_destroy ( obj , exynos_gem - > sgt ) ;
2015-09-16 14:14:54 +09:00
else
2015-10-02 09:33:47 +09:00
exynos_drm_free_buf ( exynos_gem ) ;
2012-03-16 18:47:05 +09:00
2011-12-13 14:39:13 +09:00
/* release file pointer to gem object. */
2011-10-04 19:19:01 +09:00
drm_gem_object_release ( obj ) ;
2015-10-02 09:33:47 +09:00
kfree ( exynos_gem ) ;
2011-12-13 14:39:13 +09:00
}
2013-03-11 21:15:59 +09:00
unsigned long exynos_drm_gem_get_size ( struct drm_device * dev ,
unsigned int gem_handle ,
struct drm_file * file_priv )
{
2015-10-02 09:33:47 +09:00
struct exynos_drm_gem * exynos_gem ;
2013-03-11 21:15:59 +09:00
struct drm_gem_object * obj ;
2016-05-09 11:04:54 +01:00
obj = drm_gem_object_lookup ( file_priv , gem_handle ) ;
2013-03-11 21:15:59 +09:00
if ( ! obj ) {
DRM_ERROR ( " failed to lookup gem object. \n " ) ;
return 0 ;
}
2015-10-02 09:33:47 +09:00
exynos_gem = to_exynos_gem ( obj ) ;
2013-03-11 21:15:59 +09:00
drm_gem_object_unreference_unlocked ( obj ) ;
2015-10-02 09:33:47 +09:00
return exynos_gem - > size ;
2013-03-11 21:15:59 +09:00
}
2015-10-02 09:33:47 +09:00
static struct exynos_drm_gem * exynos_drm_gem_init ( struct drm_device * dev ,
unsigned long size )
2011-12-13 14:39:13 +09:00
{
2015-10-02 09:33:47 +09:00
struct exynos_drm_gem * exynos_gem ;
2011-12-13 14:39:13 +09:00
struct drm_gem_object * obj ;
int ret ;
2015-10-02 09:33:47 +09:00
exynos_gem = kzalloc ( sizeof ( * exynos_gem ) , GFP_KERNEL ) ;
if ( ! exynos_gem )
2015-07-28 17:53:22 +09:00
return ERR_PTR ( - ENOMEM ) ;
2011-12-13 14:39:13 +09:00
2015-10-02 09:33:47 +09:00
exynos_gem - > size = size ;
obj = & exynos_gem - > base ;
2011-12-13 14:39:13 +09:00
ret = drm_gem_object_init ( dev , obj , size ) ;
if ( ret < 0 ) {
DRM_ERROR ( " failed to initialize gem object \n " ) ;
2015-10-02 09:33:47 +09:00
kfree ( exynos_gem ) ;
2015-07-28 17:53:22 +09:00
return ERR_PTR ( ret ) ;
2011-12-13 14:39:13 +09:00
}
2015-07-28 17:53:23 +09:00
ret = drm_gem_create_mmap_offset ( obj ) ;
if ( ret < 0 ) {
drm_gem_object_release ( obj ) ;
2015-10-02 09:33:47 +09:00
kfree ( exynos_gem ) ;
2015-07-28 17:53:23 +09:00
return ERR_PTR ( ret ) ;
}
2017-03-14 20:38:04 +02:00
DRM_DEBUG_KMS ( " created file object = %pK \n " , obj - > filp ) ;
2011-12-13 14:39:13 +09:00
2015-10-02 09:33:47 +09:00
return exynos_gem ;
2011-10-04 19:19:01 +09:00
}
2015-10-02 09:33:47 +09:00
struct exynos_drm_gem * exynos_drm_gem_create ( struct drm_device * dev ,
unsigned int flags ,
unsigned long size )
2011-11-12 14:51:23 +09:00
{
2015-10-02 09:33:47 +09:00
struct exynos_drm_gem * exynos_gem ;
2012-03-16 18:47:05 +09:00
int ret ;
2011-11-12 14:51:23 +09:00
2015-08-16 14:15:06 +09:00
if ( flags & ~ ( EXYNOS_BO_MASK ) ) {
2016-08-10 11:30:36 -06:00
DRM_ERROR ( " invalid GEM buffer flags: %u \n " , flags ) ;
2015-08-16 14:15:06 +09:00
return ERR_PTR ( - EINVAL ) ;
}
2012-04-03 21:27:58 +09:00
if ( ! size ) {
2016-08-10 11:30:36 -06:00
DRM_ERROR ( " invalid GEM buffer size: %lu \n " , size ) ;
2012-04-03 21:27:58 +09:00
return ERR_PTR ( - EINVAL ) ;
}
2015-07-28 17:53:27 +09:00
size = roundup ( size , PAGE_SIZE ) ;
2011-11-12 14:51:23 +09:00
2015-10-02 09:33:47 +09:00
exynos_gem = exynos_drm_gem_init ( dev , size ) ;
if ( IS_ERR ( exynos_gem ) )
return exynos_gem ;
2012-03-16 18:47:05 +09:00
/* set memory type and cache attribute from user side. */
2015-10-02 09:33:47 +09:00
exynos_gem - > flags = flags ;
2012-03-16 18:47:05 +09:00
2015-10-02 09:33:47 +09:00
ret = exynos_drm_alloc_buf ( exynos_gem ) ;
2015-08-16 14:38:49 +09:00
if ( ret < 0 ) {
2015-10-02 09:33:47 +09:00
drm_gem_object_release ( & exynos_gem - > base ) ;
kfree ( exynos_gem ) ;
2015-08-16 14:38:49 +09:00
return ERR_PTR ( ret ) ;
}
2011-11-12 14:51:23 +09:00
2015-10-02 09:33:47 +09:00
return exynos_gem ;
2011-11-12 14:51:23 +09:00
}
2011-10-04 19:19:01 +09:00
int exynos_drm_gem_create_ioctl ( struct drm_device * dev , void * data ,
2011-12-13 14:20:23 +09:00
struct drm_file * file_priv )
2011-10-04 19:19:01 +09:00
{
struct drm_exynos_gem_create * args = data ;
2015-10-02 09:33:47 +09:00
struct exynos_drm_gem * exynos_gem ;
2011-12-13 14:39:13 +09:00
int ret ;
2011-10-04 19:19:01 +09:00
2015-10-02 09:33:47 +09:00
exynos_gem = exynos_drm_gem_create ( dev , args - > flags , args - > size ) ;
if ( IS_ERR ( exynos_gem ) )
return PTR_ERR ( exynos_gem ) ;
2011-10-04 19:19:01 +09:00
2015-10-02 09:33:47 +09:00
ret = exynos_drm_gem_handle_create ( & exynos_gem - > base , file_priv ,
& args - > handle ) ;
2011-12-13 14:39:13 +09:00
if ( ret ) {
2015-10-02 09:33:47 +09:00
exynos_drm_gem_destroy ( exynos_gem ) ;
2011-12-13 14:39:13 +09:00
return ret ;
}
2011-10-04 19:19:01 +09:00
return 0 ;
}
2016-03-08 14:12:59 +09:00
int exynos_drm_gem_map_ioctl ( struct drm_device * dev , void * data ,
struct drm_file * file_priv )
{
struct drm_exynos_gem_map * args = data ;
return exynos_drm_gem_dumb_map_offset ( file_priv , dev , args - > handle ,
& args - > offset ) ;
}
2012-11-03 21:53:24 -07:00
dma_addr_t * exynos_drm_gem_get_dma_addr ( struct drm_device * dev ,
2012-03-16 18:47:06 +09:00
unsigned int gem_handle ,
2012-11-03 21:53:24 -07:00
struct drm_file * filp )
2012-03-16 18:47:06 +09:00
{
2015-10-02 09:33:47 +09:00
struct exynos_drm_gem * exynos_gem ;
2012-03-16 18:47:06 +09:00
struct drm_gem_object * obj ;
2016-05-09 11:04:54 +01:00
obj = drm_gem_object_lookup ( filp , gem_handle ) ;
2012-03-16 18:47:06 +09:00
if ( ! obj ) {
DRM_ERROR ( " failed to lookup gem object. \n " ) ;
return ERR_PTR ( - EINVAL ) ;
}
2015-10-02 09:33:47 +09:00
exynos_gem = to_exynos_gem ( obj ) ;
2012-03-16 18:47:06 +09:00
2015-10-02 09:33:47 +09:00
return & exynos_gem - > dma_addr ;
2012-03-16 18:47:06 +09:00
}
void exynos_drm_gem_put_dma_addr ( struct drm_device * dev ,
unsigned int gem_handle ,
2012-11-03 21:53:24 -07:00
struct drm_file * filp )
2012-03-16 18:47:06 +09:00
{
struct drm_gem_object * obj ;
2016-05-09 11:04:54 +01:00
obj = drm_gem_object_lookup ( filp , gem_handle ) ;
2012-03-16 18:47:06 +09:00
if ( ! obj ) {
DRM_ERROR ( " failed to lookup gem object. \n " ) ;
return ;
}
drm_gem_object_unreference_unlocked ( obj ) ;
/*
* decrease obj - > refcount one more time because we has already
* increased it at exynos_drm_gem_get_dma_addr ( ) .
*/
drm_gem_object_unreference_unlocked ( obj ) ;
}
2015-10-02 09:33:47 +09:00
static int exynos_drm_gem_mmap_buffer ( struct exynos_drm_gem * exynos_gem ,
2011-12-13 14:20:23 +09:00
struct vm_area_struct * vma )
2011-10-04 19:19:01 +09:00
{
2015-10-02 09:33:47 +09:00
struct drm_device * drm_dev = exynos_gem - > base . dev ;
2012-10-20 07:53:42 -07:00
unsigned long vm_size ;
2012-11-08 21:52:54 +09:00
int ret ;
2011-10-04 19:19:01 +09:00
2014-09-18 14:19:01 +09:00
vma - > vm_flags & = ~ VM_PFNMAP ;
vma - > vm_pgoff = 0 ;
2011-10-04 19:19:01 +09:00
2012-10-20 07:53:42 -07:00
vm_size = vma - > vm_end - vma - > vm_start ;
2012-03-16 18:47:05 +09:00
2011-10-04 19:19:01 +09:00
/* check if user-requested size is valid. */
2015-10-02 09:33:47 +09:00
if ( vm_size > exynos_gem - > size )
2011-10-04 19:19:01 +09:00
return - EINVAL ;
2016-02-29 17:50:53 +09:00
ret = dma_mmap_attrs ( to_dma_dev ( drm_dev ) , vma , exynos_gem - > cookie ,
2015-10-02 09:33:47 +09:00
exynos_gem - > dma_addr , exynos_gem - > size ,
2016-08-03 13:46:00 -07:00
exynos_gem - > dma_attrs ) ;
2012-11-08 21:52:54 +09:00
if ( ret < 0 ) {
DRM_ERROR ( " failed to mmap. \n " ) ;
return ret ;
}
2011-10-04 19:19:01 +09:00
return 0 ;
}
2012-05-04 15:51:17 +09:00
int exynos_drm_gem_get_ioctl ( struct drm_device * dev , void * data ,
struct drm_file * file_priv )
2015-09-16 14:29:35 +09:00
{
2015-10-02 09:33:47 +09:00
struct exynos_drm_gem * exynos_gem ;
2012-05-04 15:51:17 +09:00
struct drm_exynos_gem_info * args = data ;
struct drm_gem_object * obj ;
2016-05-09 11:04:54 +01:00
obj = drm_gem_object_lookup ( file_priv , args - > handle ) ;
2012-05-04 15:51:17 +09:00
if ( ! obj ) {
DRM_ERROR ( " failed to lookup gem object. \n " ) ;
return - EINVAL ;
}
2015-10-02 09:33:47 +09:00
exynos_gem = to_exynos_gem ( obj ) ;
2012-05-04 15:51:17 +09:00
2015-10-02 09:33:47 +09:00
args - > flags = exynos_gem - > flags ;
args - > size = exynos_gem - > size ;
2012-05-04 15:51:17 +09:00
2016-03-30 11:40:47 +02:00
drm_gem_object_unreference_unlocked ( obj ) ;
2012-05-04 15:51:17 +09:00
return 0 ;
}
2011-12-13 14:20:23 +09:00
void exynos_drm_gem_free_object ( struct drm_gem_object * obj )
2011-10-04 19:19:01 +09:00
{
2015-10-02 09:33:47 +09:00
exynos_drm_gem_destroy ( to_exynos_gem ( obj ) ) ;
2011-10-04 19:19:01 +09:00
}
int exynos_drm_gem_dumb_create ( struct drm_file * file_priv ,
2011-12-13 14:20:23 +09:00
struct drm_device * dev ,
struct drm_mode_create_dumb * args )
2011-10-04 19:19:01 +09:00
{
2015-10-02 09:33:47 +09:00
struct exynos_drm_gem * exynos_gem ;
2015-09-16 14:29:34 +09:00
unsigned int flags ;
2011-12-13 14:39:13 +09:00
int ret ;
2011-10-04 19:19:01 +09:00
/*
2013-10-24 16:02:57 +09:00
* allocate memory to be used for framebuffer .
2011-10-04 19:19:01 +09:00
* - this callback would be called by user application
* with DRM_IOCTL_MODE_CREATE_DUMB command .
*/
2012-06-29 11:49:45 +09:00
args - > pitch = args - > width * ( ( args - > bpp + 7 ) / 8 ) ;
2012-08-17 15:24:03 +09:00
args - > size = args - > pitch * args - > height ;
2011-10-04 19:19:01 +09:00
2015-09-16 14:29:34 +09:00
if ( is_drm_iommu_supported ( dev ) )
flags = EXYNOS_BO_NONCONTIG | EXYNOS_BO_WC ;
else
flags = EXYNOS_BO_CONTIG | EXYNOS_BO_WC ;
2013-08-23 12:05:06 +05:30
2015-10-02 09:33:47 +09:00
exynos_gem = exynos_drm_gem_create ( dev , flags , args - > size ) ;
if ( IS_ERR ( exynos_gem ) ) {
2014-05-07 17:21:29 +05:30
dev_warn ( dev - > dev , " FB allocation failed. \n " ) ;
2015-10-02 09:33:47 +09:00
return PTR_ERR ( exynos_gem ) ;
2014-05-07 17:21:29 +05:30
}
2011-10-04 19:19:01 +09:00
2015-10-02 09:33:47 +09:00
ret = exynos_drm_gem_handle_create ( & exynos_gem - > base , file_priv ,
& args - > handle ) ;
2011-12-13 14:39:13 +09:00
if ( ret ) {
2015-10-02 09:33:47 +09:00
exynos_drm_gem_destroy ( exynos_gem ) ;
2011-12-13 14:39:13 +09:00
return ret ;
}
2011-10-04 19:19:01 +09:00
return 0 ;
}
int exynos_drm_gem_dumb_map_offset ( struct drm_file * file_priv ,
2011-12-13 14:20:23 +09:00
struct drm_device * dev , uint32_t handle ,
uint64_t * offset )
2011-10-04 19:19:01 +09:00
{
struct drm_gem_object * obj ;
2011-12-13 14:32:24 +09:00
int ret = 0 ;
2011-10-04 19:19:01 +09:00
/*
* get offset of memory allocated for drm framebuffer .
* - this callback would be called by user application
* with DRM_IOCTL_MODE_MAP_DUMB command .
*/
2016-05-09 11:04:54 +01:00
obj = drm_gem_object_lookup ( file_priv , handle ) ;
2011-10-04 19:19:01 +09:00
if ( ! obj ) {
DRM_ERROR ( " failed to lookup gem object. \n " ) ;
2016-03-30 11:40:45 +02:00
return - EINVAL ;
2011-10-04 19:19:01 +09:00
}
2013-07-24 21:07:52 +02:00
* offset = drm_vma_node_offset_addr ( & obj - > vma_node ) ;
2011-10-04 19:19:01 +09:00
DRM_DEBUG_KMS ( " offset = 0x%lx \n " , ( unsigned long ) * offset ) ;
2016-03-30 11:40:45 +02:00
drm_gem_object_unreference_unlocked ( obj ) ;
2011-12-13 14:32:24 +09:00
return ret ;
2011-10-04 19:19:01 +09:00
}
2017-02-24 14:56:41 -08:00
int exynos_drm_gem_fault ( struct vm_fault * vmf )
2011-10-04 19:19:01 +09:00
{
2017-02-24 14:56:41 -08:00
struct vm_area_struct * vma = vmf - > vma ;
2011-10-04 19:19:01 +09:00
struct drm_gem_object * obj = vma - > vm_private_data ;
2015-10-02 09:33:47 +09:00
struct exynos_drm_gem * exynos_gem = to_exynos_gem ( obj ) ;
2015-07-28 17:53:19 +09:00
unsigned long pfn ;
2011-10-04 19:19:01 +09:00
pgoff_t page_offset ;
int ret ;
2016-12-14 15:07:01 -08:00
page_offset = ( vmf - > address - vma - > vm_start ) > > PAGE_SHIFT ;
2011-10-04 19:19:01 +09:00
2015-10-02 09:33:47 +09:00
if ( page_offset > = ( exynos_gem - > size > > PAGE_SHIFT ) ) {
2015-07-28 17:53:19 +09:00
DRM_ERROR ( " invalid page offset \n " ) ;
ret = - EINVAL ;
goto out ;
}
2011-10-04 19:19:01 +09:00
2015-10-02 09:33:47 +09:00
pfn = page_to_pfn ( exynos_gem - > pages [ page_offset ] ) ;
2016-12-14 15:07:01 -08:00
ret = vm_insert_mixed ( vma , vmf - > address , __pfn_to_pfn_t ( pfn , PFN_DEV ) ) ;
2015-07-28 17:53:19 +09:00
out :
2015-07-28 17:53:17 +09:00
switch ( ret ) {
case 0 :
case - ERESTARTSYS :
case - EINTR :
return VM_FAULT_NOPAGE ;
case - ENOMEM :
return VM_FAULT_OOM ;
default :
return VM_FAULT_SIGBUS ;
}
2011-10-04 19:19:01 +09:00
}
2016-04-22 16:30:47 +09:00
static int exynos_drm_gem_mmap_obj ( struct drm_gem_object * obj ,
struct vm_area_struct * vma )
2011-10-04 19:19:01 +09:00
{
2016-04-22 16:30:47 +09:00
struct exynos_drm_gem * exynos_gem = to_exynos_gem ( obj ) ;
2011-10-04 19:19:01 +09:00
int ret ;
2015-10-02 09:33:47 +09:00
DRM_DEBUG_KMS ( " flags = 0x%x \n " , exynos_gem - > flags ) ;
2015-08-16 14:16:49 +09:00
/* non-cachable as default. */
2015-10-02 09:33:47 +09:00
if ( exynos_gem - > flags & EXYNOS_BO_CACHABLE )
2015-08-16 14:16:49 +09:00
vma - > vm_page_prot = vm_get_page_prot ( vma - > vm_flags ) ;
2015-10-02 09:33:47 +09:00
else if ( exynos_gem - > flags & EXYNOS_BO_WC )
2015-08-16 14:16:49 +09:00
vma - > vm_page_prot =
pgprot_writecombine ( vm_get_page_prot ( vma - > vm_flags ) ) ;
else
vma - > vm_page_prot =
pgprot_noncached ( vm_get_page_prot ( vma - > vm_flags ) ) ;
2012-04-23 19:26:34 +09:00
2015-10-02 09:33:47 +09:00
ret = exynos_drm_gem_mmap_buffer ( exynos_gem , vma ) ;
2014-09-18 14:19:01 +09:00
if ( ret )
goto err_close_vm ;
return ret ;
err_close_vm :
drm_gem_vm_close ( vma ) ;
2011-10-04 19:19:01 +09:00
return ret ;
}
2015-08-16 14:33:08 +09:00
2016-04-22 16:30:47 +09:00
int exynos_drm_gem_mmap ( struct file * filp , struct vm_area_struct * vma )
{
struct drm_gem_object * obj ;
int ret ;
/* set vm_area_struct. */
ret = drm_gem_mmap ( filp , vma ) ;
if ( ret < 0 ) {
DRM_ERROR ( " failed to mmap. \n " ) ;
return ret ;
}
obj = vma - > vm_private_data ;
2016-04-22 16:30:48 +09:00
if ( obj - > import_attach )
return dma_buf_mmap ( obj - > dma_buf , vma , 0 ) ;
2016-04-22 16:30:47 +09:00
return exynos_drm_gem_mmap_obj ( obj , vma ) ;
}
2015-08-16 14:33:08 +09:00
/* low-level interface prime helpers */
struct sg_table * exynos_drm_gem_prime_get_sg_table ( struct drm_gem_object * obj )
{
2015-10-02 09:33:47 +09:00
struct exynos_drm_gem * exynos_gem = to_exynos_gem ( obj ) ;
2015-08-16 14:33:08 +09:00
int npages ;
2015-10-02 09:33:47 +09:00
npages = exynos_gem - > size > > PAGE_SHIFT ;
2015-08-16 14:33:08 +09:00
2015-10-02 09:33:47 +09:00
return drm_prime_pages_to_sg ( exynos_gem - > pages , npages ) ;
2015-08-16 14:33:08 +09:00
}
struct drm_gem_object *
exynos_drm_gem_prime_import_sg_table ( struct drm_device * dev ,
struct dma_buf_attachment * attach ,
struct sg_table * sgt )
{
2015-10-02 09:33:47 +09:00
struct exynos_drm_gem * exynos_gem ;
2015-08-16 14:33:08 +09:00
int npages ;
int ret ;
2015-10-02 09:33:47 +09:00
exynos_gem = exynos_drm_gem_init ( dev , attach - > dmabuf - > size ) ;
if ( IS_ERR ( exynos_gem ) ) {
ret = PTR_ERR ( exynos_gem ) ;
2015-08-31 01:11:53 +09:00
return ERR_PTR ( ret ) ;
2015-08-16 14:38:49 +09:00
}
2015-08-16 14:33:08 +09:00
2015-10-02 09:33:47 +09:00
exynos_gem - > dma_addr = sg_dma_address ( sgt - > sgl ) ;
2015-08-16 14:33:08 +09:00
2015-10-02 09:33:47 +09:00
npages = exynos_gem - > size > > PAGE_SHIFT ;
2017-05-17 14:23:12 +02:00
exynos_gem - > pages = kvmalloc_array ( npages , sizeof ( struct page * ) , GFP_KERNEL ) ;
2015-10-02 09:33:47 +09:00
if ( ! exynos_gem - > pages ) {
2015-08-16 14:33:08 +09:00
ret = - ENOMEM ;
goto err ;
}
2015-10-02 09:33:47 +09:00
ret = drm_prime_sg_to_page_addr_arrays ( sgt , exynos_gem - > pages , NULL ,
npages ) ;
2015-08-16 14:33:08 +09:00
if ( ret < 0 )
goto err_free_large ;
2015-10-02 09:33:47 +09:00
exynos_gem - > sgt = sgt ;
2015-09-16 14:14:54 +09:00
2015-08-16 14:33:08 +09:00
if ( sgt - > nents = = 1 ) {
/* always physically continuous memory if sgt->nents is 1. */
2015-10-02 09:33:47 +09:00
exynos_gem - > flags | = EXYNOS_BO_CONTIG ;
2015-08-16 14:33:08 +09:00
} else {
/*
* this case could be CONTIG or NONCONTIG type but for now
* sets NONCONTIG .
* TODO . we have to find a way that exporter can notify
* the type of its own buffer to importer .
*/
2015-10-02 09:33:47 +09:00
exynos_gem - > flags | = EXYNOS_BO_NONCONTIG ;
2015-08-16 14:33:08 +09:00
}
2015-10-02 09:33:47 +09:00
return & exynos_gem - > base ;
2015-08-16 14:33:08 +09:00
err_free_large :
2017-05-17 14:23:12 +02:00
kvfree ( exynos_gem - > pages ) ;
2015-08-16 14:33:08 +09:00
err :
2015-10-02 09:33:47 +09:00
drm_gem_object_release ( & exynos_gem - > base ) ;
kfree ( exynos_gem ) ;
2015-08-16 14:33:08 +09:00
return ERR_PTR ( ret ) ;
}
void * exynos_drm_gem_prime_vmap ( struct drm_gem_object * obj )
{
return NULL ;
}
void exynos_drm_gem_prime_vunmap ( struct drm_gem_object * obj , void * vaddr )
{
/* Nothing to do */
}
2016-04-22 16:30:47 +09:00
int exynos_drm_gem_prime_mmap ( struct drm_gem_object * obj ,
struct vm_area_struct * vma )
{
int ret ;
ret = drm_gem_mmap_obj ( obj , obj - > size , vma ) ;
if ( ret < 0 )
return ret ;
return exynos_drm_gem_mmap_obj ( obj , vma ) ;
}