2010-08-05 04:48:18 +04:00
/**************************************************************************
*
2010-10-29 12:46:45 +04:00
* Copyright ( c ) 2007 - 2010 VMware , Inc . , Palo Alto , CA . , USA
2010-08-05 04:48:18 +04:00
* All Rights Reserved .
*
* Permission is hereby granted , free of charge , to any person obtaining a
* copy of this software and associated documentation files ( the
* " Software " ) , to deal in the Software without restriction , including
* without limitation the rights to use , copy , modify , merge , publish ,
* distribute , sub license , and / or sell copies of the Software , and to
* permit persons to whom the Software is furnished to do so , subject to
* the following conditions :
*
* The above copyright notice and this permission notice ( including the
* next paragraph ) shall be included in all copies or substantial portions
* of the Software .
*
* THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND , EXPRESS OR
* IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY ,
* FITNESS FOR A PARTICULAR PURPOSE AND NON - INFRINGEMENT . IN NO EVENT SHALL
* THE COPYRIGHT HOLDERS , AUTHORS AND / OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM ,
* DAMAGES OR OTHER LIABILITY , WHETHER IN AN ACTION OF CONTRACT , TORT OR
* OTHERWISE , ARISING FROM , OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
* USE OR OTHER DEALINGS IN THE SOFTWARE .
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*
* Authors : Thomas Hellstrom < thellstrom - at - vmware - dot - com >
*/
2012-10-02 21:01:07 +04:00
# include <drm/ttm/ttm_module.h>
# include <drm/ttm/ttm_bo_driver.h>
# include <drm/ttm/ttm_placement.h>
# include <drm/drm_mm.h>
2010-08-05 04:48:18 +04:00
# include <linux/slab.h>
2010-10-29 12:46:45 +04:00
# include <linux/spinlock.h>
2010-08-05 04:48:18 +04:00
# include <linux/module.h>
2010-10-29 12:46:45 +04:00
/**
* Currently we use a spinlock for the lock , but a mutex * may * be
* more appropriate to reduce scheduling latency if the range manager
* ends up with very fragmented allocation patterns .
*/
struct ttm_range_manager {
struct drm_mm mm ;
spinlock_t lock ;
} ;
2010-08-05 04:48:18 +04:00
static int ttm_bo_man_get_node ( struct ttm_mem_type_manager * man ,
struct ttm_buffer_object * bo ,
2014-08-27 15:16:04 +04:00
const struct ttm_place * place ,
2010-08-05 04:48:18 +04:00
struct ttm_mem_reg * mem )
{
2010-10-29 12:46:45 +04:00
struct ttm_range_manager * rman = ( struct ttm_range_manager * ) man - > priv ;
struct drm_mm * mm = & rman - > mm ;
2010-08-05 04:48:18 +04:00
struct drm_mm_node * node = NULL ;
2014-10-28 12:35:03 +03:00
enum drm_mm_search_flags sflags = DRM_MM_SEARCH_BEST ;
2014-04-02 21:03:57 +04:00
enum drm_mm_allocator_flags aflags = DRM_MM_CREATE_DEFAULT ;
2010-08-05 04:48:18 +04:00
unsigned long lpfn ;
int ret ;
2014-08-27 15:16:04 +04:00
lpfn = place - > lpfn ;
2010-08-05 04:48:18 +04:00
if ( ! lpfn )
lpfn = man - > size ;
2013-07-27 15:37:59 +04:00
node = kzalloc ( sizeof ( * node ) , GFP_KERNEL ) ;
if ( ! node )
return - ENOMEM ;
2014-10-28 12:35:03 +03:00
if ( place - > flags & TTM_PL_FLAG_TOPDOWN ) {
2014-10-28 12:35:04 +03:00
sflags = DRM_MM_SEARCH_BELOW ;
2014-04-02 21:03:57 +04:00
aflags = DRM_MM_CREATE_TOP ;
2014-10-28 12:35:03 +03:00
}
2014-04-02 21:03:57 +04:00
2013-07-27 15:37:59 +04:00
spin_lock ( & rman - > lock ) ;
2014-04-02 21:03:57 +04:00
ret = drm_mm_insert_node_in_range_generic ( mm , node , mem - > num_pages ,
mem - > page_alignment , 0 ,
2014-08-27 15:16:04 +04:00
place - > fpfn , lpfn ,
2014-10-28 12:35:03 +03:00
sflags , aflags ) ;
2013-07-27 15:37:59 +04:00
spin_unlock ( & rman - > lock ) ;
if ( unlikely ( ret ) ) {
kfree ( node ) ;
} else {
mem - > mm_node = node ;
mem - > start = node - > start ;
}
2010-08-05 04:48:18 +04:00
return 0 ;
}
static void ttm_bo_man_put_node ( struct ttm_mem_type_manager * man ,
struct ttm_mem_reg * mem )
{
2010-10-29 12:46:45 +04:00
struct ttm_range_manager * rman = ( struct ttm_range_manager * ) man - > priv ;
2010-08-05 04:48:18 +04:00
if ( mem - > mm_node ) {
2010-10-29 12:46:45 +04:00
spin_lock ( & rman - > lock ) ;
2013-07-27 15:37:59 +04:00
drm_mm_remove_node ( mem - > mm_node ) ;
2010-10-29 12:46:45 +04:00
spin_unlock ( & rman - > lock ) ;
2013-07-27 15:37:59 +04:00
kfree ( mem - > mm_node ) ;
2010-08-05 04:48:18 +04:00
mem - > mm_node = NULL ;
}
}
static int ttm_bo_man_init ( struct ttm_mem_type_manager * man ,
unsigned long p_size )
{
2010-10-29 12:46:45 +04:00
struct ttm_range_manager * rman ;
2010-08-05 04:48:18 +04:00
2010-10-29 12:46:45 +04:00
rman = kzalloc ( sizeof ( * rman ) , GFP_KERNEL ) ;
if ( ! rman )
2010-08-05 04:48:18 +04:00
return - ENOMEM ;
2013-07-01 22:32:58 +04:00
drm_mm_init ( & rman - > mm , 0 , p_size ) ;
2010-10-29 12:46:45 +04:00
spin_lock_init ( & rman - > lock ) ;
man - > priv = rman ;
2010-08-05 04:48:18 +04:00
return 0 ;
}
static int ttm_bo_man_takedown ( struct ttm_mem_type_manager * man )
{
2010-10-29 12:46:45 +04:00
struct ttm_range_manager * rman = ( struct ttm_range_manager * ) man - > priv ;
struct drm_mm * mm = & rman - > mm ;
2010-08-05 04:48:18 +04:00
2010-10-29 12:46:45 +04:00
spin_lock ( & rman - > lock ) ;
2010-08-05 04:48:18 +04:00
if ( drm_mm_clean ( mm ) ) {
drm_mm_takedown ( mm ) ;
2010-10-29 12:46:45 +04:00
spin_unlock ( & rman - > lock ) ;
kfree ( rman ) ;
2010-08-05 04:48:18 +04:00
man - > priv = NULL ;
2010-10-29 12:46:45 +04:00
return 0 ;
}
spin_unlock ( & rman - > lock ) ;
return - EBUSY ;
2010-08-05 04:48:18 +04:00
}
static void ttm_bo_man_debug ( struct ttm_mem_type_manager * man ,
const char * prefix )
{
2010-10-29 12:46:45 +04:00
struct ttm_range_manager * rman = ( struct ttm_range_manager * ) man - > priv ;
2010-08-05 04:48:18 +04:00
2010-10-29 12:46:45 +04:00
spin_lock ( & rman - > lock ) ;
drm_mm_debug_table ( & rman - > mm , prefix ) ;
spin_unlock ( & rman - > lock ) ;
2010-08-05 04:48:18 +04:00
}
const struct ttm_mem_type_manager_func ttm_bo_manager_func = {
ttm_bo_man_init ,
ttm_bo_man_takedown ,
ttm_bo_man_get_node ,
ttm_bo_man_put_node ,
ttm_bo_man_debug
} ;
EXPORT_SYMBOL ( ttm_bo_manager_func ) ;