2019-05-29 07:17:56 -07:00
// SPDX-License-Identifier: GPL-2.0-only
2017-11-29 14:48:35 +02:00
/*
* Copyright ( c ) 2015 , Linaro Limited
* Copyright ( c ) 2017 , EPAM Systems
*/
# include <linux/device.h>
# include <linux/dma-buf.h>
# include <linux/genalloc.h>
# include <linux/slab.h>
# include <linux/tee_drv.h>
# include "optee_private.h"
# include "optee_smc.h"
# include "shm_pool.h"
static int pool_op_alloc ( struct tee_shm_pool_mgr * poolm ,
struct tee_shm * shm , size_t size )
{
unsigned int order = get_order ( size ) ;
struct page * page ;
2019-11-08 16:57:14 +05:30
int rc = 0 ;
2017-11-29 14:48:35 +02:00
page = alloc_pages ( GFP_KERNEL | __GFP_ZERO , order ) ;
if ( ! page )
return - ENOMEM ;
shm - > kaddr = page_address ( page ) ;
shm - > paddr = page_to_phys ( page ) ;
shm - > size = PAGE_SIZE < < order ;
2019-11-08 16:57:14 +05:30
if ( shm - > flags & TEE_SHM_DMA_BUF ) {
2019-12-30 18:52:40 +05:30
unsigned int nr_pages = 1 < < order , i ;
struct page * * pages ;
pages = kcalloc ( nr_pages , sizeof ( pages ) , GFP_KERNEL ) ;
if ( ! pages )
return - ENOMEM ;
for ( i = 0 ; i < nr_pages ; i + + ) {
pages [ i ] = page ;
page + + ;
}
2019-11-08 16:57:14 +05:30
shm - > flags | = TEE_SHM_REGISTER ;
2019-12-30 18:52:40 +05:30
rc = optee_shm_register ( shm - > ctx , shm , pages , nr_pages ,
2019-11-08 16:57:14 +05:30
( unsigned long ) shm - > kaddr ) ;
2019-12-30 18:52:40 +05:30
kfree ( pages ) ;
2019-11-08 16:57:14 +05:30
}
return rc ;
2017-11-29 14:48:35 +02:00
}
static void pool_op_free ( struct tee_shm_pool_mgr * poolm ,
struct tee_shm * shm )
{
2019-11-08 16:57:14 +05:30
if ( shm - > flags & TEE_SHM_DMA_BUF )
optee_shm_unregister ( shm - > ctx , shm ) ;
2017-11-29 14:48:35 +02:00
free_pages ( ( unsigned long ) shm - > kaddr , get_order ( shm - > size ) ) ;
shm - > kaddr = NULL ;
}
static void pool_op_destroy_poolmgr ( struct tee_shm_pool_mgr * poolm )
{
kfree ( poolm ) ;
}
static const struct tee_shm_pool_mgr_ops pool_ops = {
. alloc = pool_op_alloc ,
. free = pool_op_free ,
. destroy_poolmgr = pool_op_destroy_poolmgr ,
} ;
/**
* optee_shm_pool_alloc_pages ( ) - create page - based allocator pool
*
* This pool is used when OP - TEE supports dymanic SHM . In this case
* command buffers and such are allocated from kernel ' s own memory .
*/
struct tee_shm_pool_mgr * optee_shm_pool_alloc_pages ( void )
{
struct tee_shm_pool_mgr * mgr = kzalloc ( sizeof ( * mgr ) , GFP_KERNEL ) ;
if ( ! mgr )
return ERR_PTR ( - ENOMEM ) ;
mgr - > ops = & pool_ops ;
return mgr ;
}