2011-12-29 16:09:51 +04:00
/*
* Contiguous Memory Allocator for DMA mapping framework
* Copyright ( c ) 2010 - 2011 by Samsung Electronics .
* Written by :
* Marek Szyprowski < m . szyprowski @ samsung . com >
* Michal Nazarewicz < mina86 @ mina86 . com >
*
* 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 optional ) any later version of the license .
*/
# define pr_fmt(fmt) "cma: " fmt
# ifdef CONFIG_CMA_DEBUG
# ifndef DEBUG
# define DEBUG
# endif
# endif
# include <asm/page.h>
# include <asm/dma-contiguous.h>
# include <linux/memblock.h>
# include <linux/err.h>
2012-10-18 11:29:44 +04:00
# include <linux/sizes.h>
2011-12-29 16:09:51 +04:00
# include <linux/dma-contiguous.h>
2014-08-07 03:05:25 +04:00
# include <linux/cma.h>
2011-12-29 16:09:51 +04:00
# ifdef CONFIG_CMA_SIZE_MBYTES
# define CMA_SIZE_MBYTES CONFIG_CMA_SIZE_MBYTES
# else
# define CMA_SIZE_MBYTES 0
# endif
2014-08-07 03:05:25 +04:00
struct cma * dma_contiguous_default_area ;
2011-12-29 16:09:51 +04:00
/*
* Default global CMA area size can be defined in kernel ' s . config .
2013-09-18 08:04:48 +04:00
* This is useful mainly for distro maintainers to create a kernel
2011-12-29 16:09:51 +04:00
* that works correctly for most supported systems .
* The size can be set in bytes or as a percentage of the total memory
* in the system .
*
* Users , who want to set the size of global CMA area for their system
* should use cma = kernel parameter .
*/
2012-12-05 18:29:25 +04:00
static const phys_addr_t size_bytes = CMA_SIZE_MBYTES * SZ_1M ;
static phys_addr_t size_cmdline = - 1 ;
2014-06-05 03:06:54 +04:00
static phys_addr_t base_cmdline ;
static phys_addr_t limit_cmdline ;
2011-12-29 16:09:51 +04:00
static int __init early_cma ( char * p )
{
pr_debug ( " %s(%s) \n " , __func__ , p ) ;
size_cmdline = memparse ( p , & p ) ;
2014-06-05 03:06:54 +04:00
if ( * p ! = ' @ ' )
return 0 ;
base_cmdline = memparse ( p + 1 , & p ) ;
if ( * p ! = ' - ' ) {
limit_cmdline = base_cmdline + size_cmdline ;
return 0 ;
}
limit_cmdline = memparse ( p + 1 , & p ) ;
2011-12-29 16:09:51 +04:00
return 0 ;
}
early_param ( " cma " , early_cma ) ;
# ifdef CONFIG_CMA_SIZE_PERCENTAGE
2012-12-05 18:29:25 +04:00
static phys_addr_t __init __maybe_unused cma_early_percent_memory ( void )
2011-12-29 16:09:51 +04:00
{
struct memblock_region * reg ;
unsigned long total_pages = 0 ;
/*
* We cannot use memblock_phys_mem_size ( ) here , because
* memblock_analyze ( ) has not been called yet .
*/
for_each_memblock ( memory , reg )
total_pages + = memblock_region_memory_end_pfn ( reg ) -
memblock_region_memory_base_pfn ( reg ) ;
return ( total_pages * CONFIG_CMA_SIZE_PERCENTAGE / 100 ) < < PAGE_SHIFT ;
}
# else
2012-12-05 18:29:25 +04:00
static inline __maybe_unused phys_addr_t cma_early_percent_memory ( void )
2011-12-29 16:09:51 +04:00
{
return 0 ;
}
# endif
/**
2013-07-29 16:31:45 +04:00
* dma_contiguous_reserve ( ) - reserve area ( s ) for contiguous memory handling
2011-12-29 16:09:51 +04:00
* @ limit : End address of the reserved memory ( optional , 0 for any ) .
*
* This function reserves memory from early allocator . It should be
* called by arch specific code once the early allocator ( memblock or bootmem )
* has been activated and all other subsystems have already allocated / reserved
* memory .
*/
void __init dma_contiguous_reserve ( phys_addr_t limit )
{
2012-12-05 18:29:25 +04:00
phys_addr_t selected_size = 0 ;
2014-06-05 03:06:54 +04:00
phys_addr_t selected_base = 0 ;
phys_addr_t selected_limit = limit ;
bool fixed = false ;
2011-12-29 16:09:51 +04:00
pr_debug ( " %s(limit %08lx) \n " , __func__ , ( unsigned long ) limit ) ;
if ( size_cmdline ! = - 1 ) {
selected_size = size_cmdline ;
2014-06-05 03:06:54 +04:00
selected_base = base_cmdline ;
selected_limit = min_not_zero ( limit_cmdline , limit ) ;
if ( base_cmdline + size_cmdline = = limit_cmdline )
fixed = true ;
2011-12-29 16:09:51 +04:00
} else {
# ifdef CONFIG_CMA_SIZE_SEL_MBYTES
selected_size = size_bytes ;
# elif defined(CONFIG_CMA_SIZE_SEL_PERCENTAGE)
selected_size = cma_early_percent_memory ( ) ;
# elif defined(CONFIG_CMA_SIZE_SEL_MIN)
selected_size = min ( size_bytes , cma_early_percent_memory ( ) ) ;
# elif defined(CONFIG_CMA_SIZE_SEL_MAX)
selected_size = max ( size_bytes , cma_early_percent_memory ( ) ) ;
# endif
}
2013-07-29 16:31:45 +04:00
if ( selected_size & & ! dma_contiguous_default_area ) {
2011-12-29 16:09:51 +04:00
pr_debug ( " %s: reserving %ld MiB for global area \n " , __func__ ,
2012-12-05 18:29:25 +04:00
( unsigned long ) selected_size / SZ_1M ) ;
2011-12-29 16:09:51 +04:00
2014-06-05 03:06:54 +04:00
dma_contiguous_reserve_area ( selected_size , selected_base ,
selected_limit ,
& dma_contiguous_default_area ,
fixed ) ;
2011-12-29 16:09:51 +04:00
}
2014-06-05 03:06:54 +04:00
}
2011-12-29 16:09:51 +04:00
2014-08-07 03:05:19 +04:00
/**
* dma_contiguous_reserve_area ( ) - reserve custom contiguous area
* @ size : Size of the reserved area ( in bytes ) ,
* @ base : Base address of the reserved area optional , use 0 for any
* @ limit : End address of the reserved memory ( optional , 0 for any ) .
* @ res_cma : Pointer to store the created cma region .
* @ fixed : hint about where to place the reserved area
*
* This function reserves memory from early allocator . It should be
* called by arch specific code once the early allocator ( memblock or bootmem )
* has been activated and all other subsystems have already allocated / reserved
* memory . This function allows to create custom reserved areas for specific
* devices .
*
* If @ fixed is true , reserve contiguous area at exactly @ base . If false ,
* reserve in range from @ base to @ limit .
*/
int __init dma_contiguous_reserve_area ( phys_addr_t size , phys_addr_t base ,
phys_addr_t limit , struct cma * * res_cma ,
bool fixed )
{
int ret ;
2014-08-07 03:05:32 +04:00
ret = cma_declare_contiguous ( base , size , limit , 0 , 0 , fixed , res_cma ) ;
2014-08-07 03:05:19 +04:00
if ( ret )
return ret ;
/* Architecture specific contiguous memory fixup. */
2014-08-07 03:05:25 +04:00
dma_contiguous_early_fixup ( cma_get_base ( * res_cma ) ,
cma_get_size ( * res_cma ) ) ;
2014-08-07 03:05:19 +04:00
return 0 ;
}
2011-12-29 16:09:51 +04:00
/**
2014-08-07 03:05:19 +04:00
* dma_alloc_from_contiguous ( ) - allocate pages from contiguous area
* @ dev : Pointer to device for which the allocation is performed .
* @ count : Requested number of pages .
* @ align : Requested alignment of pages ( in PAGE_SIZE order ) .
2011-12-29 16:09:51 +04:00
*
2014-08-07 03:05:19 +04:00
* This function allocates memory buffer for specified device . It uses
* device specific contiguous memory area if available or the default
* global one . Requires architecture specific dev_get_cma_area ( ) helper
* function .
2011-12-29 16:09:51 +04:00
*/
2014-08-07 03:05:19 +04:00
struct page * dma_alloc_from_contiguous ( struct device * dev , int count ,
unsigned int align )
2011-12-29 16:09:51 +04:00
{
2014-08-07 03:05:19 +04:00
if ( align > CONFIG_CMA_ALIGNMENT )
align = CONFIG_CMA_ALIGNMENT ;
2014-08-07 03:05:25 +04:00
return cma_alloc ( dev_get_cma_area ( dev ) , count , align ) ;
2011-12-29 16:09:51 +04:00
}
2014-08-07 03:05:19 +04:00
/**
* dma_release_from_contiguous ( ) - release allocated pages
* @ dev : Pointer to device for which the pages were allocated .
* @ pages : Allocated pages .
* @ count : Number of allocated pages .
*
* This function releases memory allocated by dma_alloc_from_contiguous ( ) .
* It returns false when provided pages do not belong to contiguous area and
* true otherwise .
*/
bool dma_release_from_contiguous ( struct device * dev , struct page * pages ,
int count )
{
2014-08-07 03:05:25 +04:00
return cma_release ( dev_get_cma_area ( dev ) , pages , count ) ;
2014-08-07 03:05:19 +04:00
}
2014-10-14 02:51:09 +04:00
/*
* Support for reserved memory regions defined in device tree
*/
# ifdef CONFIG_OF_RESERVED_MEM
# include <linux/of.h>
# include <linux/of_fdt.h>
# include <linux/of_reserved_mem.h>
# undef pr_fmt
# define pr_fmt(fmt) fmt
2014-10-30 00:50:29 +03:00
static int rmem_cma_device_init ( struct reserved_mem * rmem , struct device * dev )
2014-10-14 02:51:09 +04:00
{
dev_set_cma_area ( dev , rmem - > priv ) ;
2014-10-30 00:50:29 +03:00
return 0 ;
2014-10-14 02:51:09 +04:00
}
static void rmem_cma_device_release ( struct reserved_mem * rmem ,
struct device * dev )
{
dev_set_cma_area ( dev , NULL ) ;
}
static const struct reserved_mem_ops rmem_cma_ops = {
. device_init = rmem_cma_device_init ,
. device_release = rmem_cma_device_release ,
} ;
static int __init rmem_cma_setup ( struct reserved_mem * rmem )
{
phys_addr_t align = PAGE_SIZE < < max ( MAX_ORDER - 1 , pageblock_order ) ;
phys_addr_t mask = align - 1 ;
unsigned long node = rmem - > fdt_node ;
struct cma * cma ;
int err ;
if ( ! of_get_flat_dt_prop ( node , " reusable " , NULL ) | |
of_get_flat_dt_prop ( node , " no-map " , NULL ) )
return - EINVAL ;
if ( ( rmem - > base & mask ) | | ( rmem - > size & mask ) ) {
pr_err ( " Reserved memory: incorrect alignment of CMA region \n " ) ;
return - EINVAL ;
}
err = cma_init_reserved_mem ( rmem - > base , rmem - > size , 0 , & cma ) ;
if ( err ) {
pr_err ( " Reserved memory: unable to setup CMA region \n " ) ;
return err ;
}
/* Architecture specific contiguous memory fixup. */
dma_contiguous_early_fixup ( rmem - > base , rmem - > size ) ;
if ( of_get_flat_dt_prop ( node , " linux,cma-default " , NULL ) )
dma_contiguous_set_default ( cma ) ;
rmem - > ops = & rmem_cma_ops ;
rmem - > priv = cma ;
pr_info ( " Reserved memory: created CMA memory pool at %pa, size %ld MiB \n " ,
& rmem - > base , ( unsigned long ) rmem - > size / SZ_1M ) ;
return 0 ;
}
RESERVEDMEM_OF_DECLARE ( cma , " shared-dma-pool " , rmem_cma_setup ) ;
# endif