2015-04-20 16:55:21 -04:00
/*
* Copyright 2009 Jerome Glisse .
* 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 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 .
*
* The above copyright notice and this permission notice ( including the
* next paragraph ) shall be included in all copies or substantial portions
* of the Software .
*
*/
/*
* Authors :
* Jerome Glisse < glisse @ freedesktop . org >
* Thomas Hellstrom < thomas - at - tungstengraphics - dot - com >
* Dave Airlie
*/
# include <linux/list.h>
# include <linux/slab.h>
# include <drm/drmP.h>
# include <drm/amdgpu_drm.h>
2016-01-30 07:59:34 +02:00
# include <drm/drm_cache.h>
2015-04-20 16:55:21 -04:00
# include "amdgpu.h"
# include "amdgpu_trace.h"
int amdgpu_ttm_init ( struct amdgpu_device * adev ) ;
void amdgpu_ttm_fini ( struct amdgpu_device * adev ) ;
static u64 amdgpu_get_vis_part_size ( struct amdgpu_device * adev ,
2015-04-24 17:37:30 +08:00
struct ttm_mem_reg * mem )
2015-04-20 16:55:21 -04:00
{
2016-08-12 16:50:12 +02:00
if ( mem - > start < < PAGE_SHIFT > = adev - > mc . visible_vram_size )
return 0 ;
return ( ( mem - > start < < PAGE_SHIFT ) + mem - > size ) >
adev - > mc . visible_vram_size ?
adev - > mc . visible_vram_size - ( mem - > start < < PAGE_SHIFT ) :
mem - > size ;
2015-04-20 16:55:21 -04:00
}
static void amdgpu_update_memory_usage ( struct amdgpu_device * adev ,
struct ttm_mem_reg * old_mem ,
struct ttm_mem_reg * new_mem )
{
u64 vis_size ;
if ( ! adev )
return ;
if ( new_mem ) {
switch ( new_mem - > mem_type ) {
case TTM_PL_TT :
atomic64_add ( new_mem - > size , & adev - > gtt_usage ) ;
break ;
case TTM_PL_VRAM :
atomic64_add ( new_mem - > size , & adev - > vram_usage ) ;
vis_size = amdgpu_get_vis_part_size ( adev , new_mem ) ;
atomic64_add ( vis_size , & adev - > vram_vis_usage ) ;
break ;
}
}
if ( old_mem ) {
switch ( old_mem - > mem_type ) {
case TTM_PL_TT :
atomic64_sub ( old_mem - > size , & adev - > gtt_usage ) ;
break ;
case TTM_PL_VRAM :
atomic64_sub ( old_mem - > size , & adev - > vram_usage ) ;
vis_size = amdgpu_get_vis_part_size ( adev , old_mem ) ;
atomic64_sub ( vis_size , & adev - > vram_vis_usage ) ;
break ;
}
}
}
static void amdgpu_ttm_bo_destroy ( struct ttm_buffer_object * tbo )
{
struct amdgpu_bo * bo ;
bo = container_of ( tbo , struct amdgpu_bo , tbo ) ;
amdgpu_update_memory_usage ( bo - > adev , & bo - > tbo . mem , NULL ) ;
drm_gem_object_release ( & bo - > gem_base ) ;
2015-11-27 16:49:00 +01:00
amdgpu_bo_unref ( & bo - > parent ) ;
2016-08-17 11:41:30 +08:00
if ( ! list_empty ( & bo - > shadow_list ) ) {
mutex_lock ( & bo - > adev - > shadow_list_lock ) ;
list_del_init ( & bo - > shadow_list ) ;
mutex_unlock ( & bo - > adev - > shadow_list_lock ) ;
}
2015-04-20 16:55:21 -04:00
kfree ( bo - > metadata ) ;
kfree ( bo ) ;
}
bool amdgpu_ttm_bo_is_amdgpu_bo ( struct ttm_buffer_object * bo )
{
if ( bo - > destroy = = & amdgpu_ttm_bo_destroy )
return true ;
return false ;
}
2015-04-24 17:37:30 +08:00
static void amdgpu_ttm_placement_init ( struct amdgpu_device * adev ,
struct ttm_placement * placement ,
2016-08-15 14:06:50 +02:00
struct ttm_place * places ,
2015-04-24 17:37:30 +08:00
u32 domain , u64 flags )
2015-04-20 16:55:21 -04:00
{
2016-08-15 14:08:54 +02:00
u32 c = 0 ;
2015-04-24 17:37:30 +08:00
2015-04-20 16:55:21 -04:00
if ( domain & AMDGPU_GEM_DOMAIN_VRAM ) {
2016-08-15 14:06:50 +02:00
unsigned visible_pfn = adev - > mc . visible_vram_size > > PAGE_SHIFT ;
2015-04-24 17:37:30 +08:00
if ( flags & AMDGPU_GEM_CREATE_NO_CPU_ACCESS & &
2016-08-15 14:08:54 +02:00
! ( flags & AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED ) & &
2016-08-15 14:06:50 +02:00
adev - > mc . visible_vram_size < adev - > mc . real_vram_size ) {
places [ c ] . fpfn = visible_pfn ;
2016-08-15 14:08:54 +02:00
places [ c ] . lpfn = 0 ;
2016-08-15 14:06:50 +02:00
places [ c ] . flags = TTM_PL_FLAG_WC |
2016-08-12 16:50:12 +02:00
TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_VRAM |
TTM_PL_FLAG_TOPDOWN ;
2016-08-15 14:06:50 +02:00
c + + ;
2015-04-20 16:55:21 -04:00
}
2016-08-15 14:06:50 +02:00
places [ c ] . fpfn = 0 ;
places [ c ] . lpfn = 0 ;
places [ c ] . flags = TTM_PL_FLAG_WC | TTM_PL_FLAG_UNCACHED |
2015-04-24 17:37:30 +08:00
TTM_PL_FLAG_VRAM ;
2016-08-15 14:06:50 +02:00
if ( flags & AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED )
places [ c ] . lpfn = visible_pfn ;
else
places [ c ] . flags | = TTM_PL_FLAG_TOPDOWN ;
c + + ;
2015-04-20 16:55:21 -04:00
}
if ( domain & AMDGPU_GEM_DOMAIN_GTT ) {
2016-08-15 14:06:50 +02:00
places [ c ] . fpfn = 0 ;
places [ c ] . lpfn = 0 ;
places [ c ] . flags = TTM_PL_FLAG_TT ;
if ( flags & AMDGPU_GEM_CREATE_CPU_GTT_USWC )
places [ c ] . flags | = TTM_PL_FLAG_WC |
TTM_PL_FLAG_UNCACHED ;
else
places [ c ] . flags | = TTM_PL_FLAG_CACHED ;
c + + ;
2015-04-20 16:55:21 -04:00
}
if ( domain & AMDGPU_GEM_DOMAIN_CPU ) {
2016-08-15 14:06:50 +02:00
places [ c ] . fpfn = 0 ;
places [ c ] . lpfn = 0 ;
places [ c ] . flags = TTM_PL_FLAG_SYSTEM ;
if ( flags & AMDGPU_GEM_CREATE_CPU_GTT_USWC )
places [ c ] . flags | = TTM_PL_FLAG_WC |
TTM_PL_FLAG_UNCACHED ;
else
places [ c ] . flags | = TTM_PL_FLAG_CACHED ;
c + + ;
2015-04-20 16:55:21 -04:00
}
if ( domain & AMDGPU_GEM_DOMAIN_GDS ) {
2016-08-15 14:06:50 +02:00
places [ c ] . fpfn = 0 ;
places [ c ] . lpfn = 0 ;
places [ c ] . flags = TTM_PL_FLAG_UNCACHED | AMDGPU_PL_FLAG_GDS ;
c + + ;
2015-04-20 16:55:21 -04:00
}
2016-08-15 14:06:50 +02:00
2015-04-20 16:55:21 -04:00
if ( domain & AMDGPU_GEM_DOMAIN_GWS ) {
2016-08-15 14:06:50 +02:00
places [ c ] . fpfn = 0 ;
places [ c ] . lpfn = 0 ;
places [ c ] . flags = TTM_PL_FLAG_UNCACHED | AMDGPU_PL_FLAG_GWS ;
c + + ;
2015-04-20 16:55:21 -04:00
}
2016-08-15 14:06:50 +02:00
2015-04-20 16:55:21 -04:00
if ( domain & AMDGPU_GEM_DOMAIN_OA ) {
2016-08-15 14:06:50 +02:00
places [ c ] . fpfn = 0 ;
places [ c ] . lpfn = 0 ;
places [ c ] . flags = TTM_PL_FLAG_UNCACHED | AMDGPU_PL_FLAG_OA ;
c + + ;
2015-04-20 16:55:21 -04:00
}
if ( ! c ) {
2016-08-15 14:06:50 +02:00
places [ c ] . fpfn = 0 ;
places [ c ] . lpfn = 0 ;
places [ c ] . flags = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM ;
c + + ;
2015-04-20 16:55:21 -04:00
}
2016-08-15 14:06:50 +02:00
2015-04-24 17:37:30 +08:00
placement - > num_placement = c ;
2016-08-15 14:06:50 +02:00
placement - > placement = places ;
2015-04-20 16:55:21 -04:00
2016-08-15 14:06:50 +02:00
placement - > num_busy_placement = c ;
placement - > busy_placement = places ;
2015-04-20 16:55:21 -04:00
}
2015-04-24 17:37:30 +08:00
void amdgpu_ttm_placement_from_domain ( struct amdgpu_bo * rbo , u32 domain )
{
amdgpu_ttm_placement_init ( rbo - > adev , & rbo - > placement ,
rbo - > placements , domain , rbo - > flags ) ;
}
static void amdgpu_fill_placement_to_bo ( struct amdgpu_bo * bo ,
struct ttm_placement * placement )
{
BUG_ON ( placement - > num_placement > ( AMDGPU_GEM_DOMAIN_MAX + 1 ) ) ;
memcpy ( bo - > placements , placement - > placement ,
placement - > num_placement * sizeof ( struct ttm_place ) ) ;
bo - > placement . num_placement = placement - > num_placement ;
bo - > placement . num_busy_placement = placement - > num_busy_placement ;
bo - > placement . placement = bo - > placements ;
bo - > placement . busy_placement = bo - > placements ;
}
2015-12-14 13:18:01 +01:00
/**
* amdgpu_bo_create_kernel - create BO for kernel use
*
* @ adev : amdgpu device object
* @ size : size for the new BO
* @ align : alignment for the new BO
* @ domain : where to place it
* @ bo_ptr : resulting BO
* @ gpu_addr : GPU addr of the pinned BO
* @ cpu_addr : optional CPU address mapping
*
* Allocates and pins a BO for kernel internal use .
*
* Returns 0 on success , negative error code otherwise .
*/
int amdgpu_bo_create_kernel ( struct amdgpu_device * adev ,
unsigned long size , int align ,
u32 domain , struct amdgpu_bo * * bo_ptr ,
u64 * gpu_addr , void * * cpu_addr )
{
int r ;
r = amdgpu_bo_create ( adev , size , align , true , domain ,
AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED ,
NULL , NULL , bo_ptr ) ;
if ( r ) {
dev_err ( adev - > dev , " (%d) failed to allocate kernel bo \n " , r ) ;
return r ;
}
r = amdgpu_bo_reserve ( * bo_ptr , false ) ;
if ( r ) {
dev_err ( adev - > dev , " (%d) failed to reserve kernel bo \n " , r ) ;
goto error_free ;
}
r = amdgpu_bo_pin ( * bo_ptr , domain , gpu_addr ) ;
if ( r ) {
dev_err ( adev - > dev , " (%d) kernel bo pin failed \n " , r ) ;
goto error_unreserve ;
}
if ( cpu_addr ) {
r = amdgpu_bo_kmap ( * bo_ptr , cpu_addr ) ;
if ( r ) {
dev_err ( adev - > dev , " (%d) kernel bo map failed \n " , r ) ;
goto error_unreserve ;
}
}
amdgpu_bo_unreserve ( * bo_ptr ) ;
return 0 ;
error_unreserve :
amdgpu_bo_unreserve ( * bo_ptr ) ;
error_free :
amdgpu_bo_unref ( bo_ptr ) ;
return r ;
}
2016-09-08 10:13:32 +08:00
/**
* amdgpu_bo_free_kernel - free BO for kernel use
*
* @ bo : amdgpu BO to free
*
* unmaps and unpin a BO for kernel internal use .
*/
void amdgpu_bo_free_kernel ( struct amdgpu_bo * * bo , u64 * gpu_addr ,
void * * cpu_addr )
{
if ( * bo = = NULL )
return ;
if ( likely ( amdgpu_bo_reserve ( * bo , false ) = = 0 ) ) {
if ( cpu_addr )
amdgpu_bo_kunmap ( * bo ) ;
amdgpu_bo_unpin ( * bo ) ;
amdgpu_bo_unreserve ( * bo ) ;
}
amdgpu_bo_unref ( bo ) ;
if ( gpu_addr )
* gpu_addr = 0 ;
if ( cpu_addr )
* cpu_addr = NULL ;
}
2015-04-24 17:37:30 +08:00
int amdgpu_bo_create_restricted ( struct amdgpu_device * adev ,
unsigned long size , int byte_align ,
bool kernel , u32 domain , u64 flags ,
struct sg_table * sg ,
struct ttm_placement * placement ,
2015-09-03 17:34:59 +02:00
struct reservation_object * resv ,
2015-04-24 17:37:30 +08:00
struct amdgpu_bo * * bo_ptr )
2015-04-20 16:55:21 -04:00
{
struct amdgpu_bo * bo ;
enum ttm_bo_type type ;
unsigned long page_align ;
size_t acc_size ;
int r ;
page_align = roundup ( byte_align , PAGE_SIZE ) > > PAGE_SHIFT ;
size = ALIGN ( size , PAGE_SIZE ) ;
if ( kernel ) {
type = ttm_bo_type_kernel ;
} else if ( sg ) {
type = ttm_bo_type_sg ;
} else {
type = ttm_bo_type_device ;
}
* bo_ptr = NULL ;
acc_size = ttm_bo_dma_acc_size ( & adev - > mman . bdev , size ,
sizeof ( struct amdgpu_bo ) ) ;
bo = kzalloc ( sizeof ( struct amdgpu_bo ) , GFP_KERNEL ) ;
if ( bo = = NULL )
return - ENOMEM ;
r = drm_gem_object_init ( adev - > ddev , & bo - > gem_base , size ) ;
if ( unlikely ( r ) ) {
kfree ( bo ) ;
return r ;
}
bo - > adev = adev ;
INIT_LIST_HEAD ( & bo - > list ) ;
2016-08-17 11:41:30 +08:00
INIT_LIST_HEAD ( & bo - > shadow_list ) ;
2015-04-20 16:55:21 -04:00
INIT_LIST_HEAD ( & bo - > va ) ;
2015-12-18 22:13:12 +01:00
bo - > prefered_domains = domain & ( AMDGPU_GEM_DOMAIN_VRAM |
AMDGPU_GEM_DOMAIN_GTT |
AMDGPU_GEM_DOMAIN_CPU |
AMDGPU_GEM_DOMAIN_GDS |
AMDGPU_GEM_DOMAIN_GWS |
AMDGPU_GEM_DOMAIN_OA ) ;
bo - > allowed_domains = bo - > prefered_domains ;
if ( ! kernel & & bo - > allowed_domains = = AMDGPU_GEM_DOMAIN_VRAM )
bo - > allowed_domains | = AMDGPU_GEM_DOMAIN_GTT ;
2015-04-20 16:55:21 -04:00
bo - > flags = flags ;
2016-01-30 07:59:34 +02:00
/* For architectures that don't support WC memory,
* mask out the WC flag from the BO
*/
if ( ! drm_arch_can_wc_memory ( ) )
bo - > flags & = ~ AMDGPU_GEM_CREATE_CPU_GTT_USWC ;
2015-04-24 17:37:30 +08:00
amdgpu_fill_placement_to_bo ( bo , placement ) ;
2015-04-20 16:55:21 -04:00
/* Kernel allocation are uninterruptible */
r = ttm_bo_init ( & adev - > mman . bdev , & bo - > tbo , size , type ,
& bo - > placement , page_align , ! kernel , NULL ,
2015-09-03 17:34:59 +02:00
acc_size , sg , resv , & amdgpu_ttm_bo_destroy ) ;
2015-04-20 16:55:21 -04:00
if ( unlikely ( r ! = 0 ) ) {
return r ;
}
2016-07-20 14:44:38 +08:00
if ( flags & AMDGPU_GEM_CREATE_VRAM_CLEARED & &
bo - > tbo . mem . placement & TTM_PL_FLAG_VRAM ) {
struct fence * fence ;
if ( adev - > mman . buffer_funcs_ring = = NULL | |
! adev - > mman . buffer_funcs_ring - > ready ) {
r = - EBUSY ;
goto fail_free ;
}
r = amdgpu_bo_reserve ( bo , false ) ;
if ( unlikely ( r ! = 0 ) )
goto fail_free ;
amdgpu_ttm_placement_from_domain ( bo , AMDGPU_GEM_DOMAIN_VRAM ) ;
r = ttm_bo_validate ( & bo - > tbo , & bo - > placement , false , false ) ;
if ( unlikely ( r ! = 0 ) )
goto fail_unreserve ;
amdgpu_fill_buffer ( bo , 0 , bo - > tbo . resv , & fence ) ;
amdgpu_bo_fence ( bo , fence , false ) ;
amdgpu_bo_unreserve ( bo ) ;
fence_put ( bo - > tbo . moving ) ;
bo - > tbo . moving = fence_get ( fence ) ;
fence_put ( fence ) ;
}
2015-04-20 16:55:21 -04:00
* bo_ptr = bo ;
trace_amdgpu_bo_create ( bo ) ;
return 0 ;
2016-07-20 14:44:38 +08:00
fail_unreserve :
amdgpu_bo_unreserve ( bo ) ;
fail_free :
amdgpu_bo_unref ( & bo ) ;
return r ;
2015-04-20 16:55:21 -04:00
}
2016-07-26 14:13:21 +08:00
static int amdgpu_bo_create_shadow ( struct amdgpu_device * adev ,
unsigned long size , int byte_align ,
struct amdgpu_bo * bo )
{
struct ttm_placement placement = { 0 } ;
struct ttm_place placements [ AMDGPU_GEM_DOMAIN_MAX + 1 ] ;
int r ;
if ( bo - > shadow )
return 0 ;
bo - > flags | = AMDGPU_GEM_CREATE_SHADOW ;
memset ( & placements , 0 ,
( AMDGPU_GEM_DOMAIN_MAX + 1 ) * sizeof ( struct ttm_place ) ) ;
amdgpu_ttm_placement_init ( adev , & placement ,
placements , AMDGPU_GEM_DOMAIN_GTT ,
AMDGPU_GEM_CREATE_CPU_GTT_USWC ) ;
r = amdgpu_bo_create_restricted ( adev , size , byte_align , true ,
AMDGPU_GEM_DOMAIN_GTT ,
AMDGPU_GEM_CREATE_CPU_GTT_USWC ,
NULL , & placement ,
bo - > tbo . resv ,
& bo - > shadow ) ;
2016-08-17 11:41:30 +08:00
if ( ! r ) {
2016-07-26 14:13:21 +08:00
bo - > shadow - > parent = amdgpu_bo_ref ( bo ) ;
2016-08-17 11:41:30 +08:00
mutex_lock ( & adev - > shadow_list_lock ) ;
list_add_tail ( & bo - > shadow_list , & adev - > shadow_list ) ;
mutex_unlock ( & adev - > shadow_list_lock ) ;
}
2016-07-26 14:13:21 +08:00
return r ;
}
2015-04-24 17:37:30 +08:00
int amdgpu_bo_create ( struct amdgpu_device * adev ,
unsigned long size , int byte_align ,
bool kernel , u32 domain , u64 flags ,
2015-09-03 17:34:59 +02:00
struct sg_table * sg ,
struct reservation_object * resv ,
struct amdgpu_bo * * bo_ptr )
2015-04-24 17:37:30 +08:00
{
struct ttm_placement placement = { 0 } ;
struct ttm_place placements [ AMDGPU_GEM_DOMAIN_MAX + 1 ] ;
2016-07-26 14:13:21 +08:00
int r ;
2015-04-24 17:37:30 +08:00
memset ( & placements , 0 ,
( AMDGPU_GEM_DOMAIN_MAX + 1 ) * sizeof ( struct ttm_place ) ) ;
amdgpu_ttm_placement_init ( adev , & placement ,
placements , domain , flags ) ;
2016-07-26 14:13:21 +08:00
r = amdgpu_bo_create_restricted ( adev , size , byte_align , kernel ,
domain , flags , sg , & placement ,
resv , bo_ptr ) ;
if ( r )
return r ;
2016-08-05 17:30:17 +08:00
if ( amdgpu_need_backup ( adev ) & & ( flags & AMDGPU_GEM_CREATE_SHADOW ) ) {
2016-07-26 14:13:21 +08:00
r = amdgpu_bo_create_shadow ( adev , size , byte_align , ( * bo_ptr ) ) ;
if ( r )
amdgpu_bo_unref ( bo_ptr ) ;
}
return r ;
2015-04-24 17:37:30 +08:00
}
2016-08-04 16:51:18 +08:00
int amdgpu_bo_backup_to_shadow ( struct amdgpu_device * adev ,
struct amdgpu_ring * ring ,
struct amdgpu_bo * bo ,
struct reservation_object * resv ,
struct fence * * fence ,
bool direct )
{
struct amdgpu_bo * shadow = bo - > shadow ;
uint64_t bo_addr , shadow_addr ;
int r ;
if ( ! shadow )
return - EINVAL ;
bo_addr = amdgpu_bo_gpu_offset ( bo ) ;
shadow_addr = amdgpu_bo_gpu_offset ( bo - > shadow ) ;
r = reservation_object_reserve_shared ( bo - > tbo . resv ) ;
if ( r )
goto err ;
r = amdgpu_copy_buffer ( ring , bo_addr , shadow_addr ,
amdgpu_bo_size ( bo ) , resv , fence ,
direct ) ;
if ( ! r )
amdgpu_bo_fence ( bo , * fence , true ) ;
err :
return r ;
}
int amdgpu_bo_restore_from_shadow ( struct amdgpu_device * adev ,
struct amdgpu_ring * ring ,
struct amdgpu_bo * bo ,
struct reservation_object * resv ,
struct fence * * fence ,
bool direct )
{
struct amdgpu_bo * shadow = bo - > shadow ;
uint64_t bo_addr , shadow_addr ;
int r ;
if ( ! shadow )
return - EINVAL ;
bo_addr = amdgpu_bo_gpu_offset ( bo ) ;
shadow_addr = amdgpu_bo_gpu_offset ( bo - > shadow ) ;
r = reservation_object_reserve_shared ( bo - > tbo . resv ) ;
if ( r )
goto err ;
r = amdgpu_copy_buffer ( ring , shadow_addr , bo_addr ,
amdgpu_bo_size ( bo ) , resv , fence ,
direct ) ;
if ( ! r )
amdgpu_bo_fence ( bo , * fence , true ) ;
err :
return r ;
}
2015-04-20 16:55:21 -04:00
int amdgpu_bo_kmap ( struct amdgpu_bo * bo , void * * ptr )
{
bool is_iomem ;
2016-03-10 16:21:04 +01:00
long r ;
2015-04-20 16:55:21 -04:00
2015-05-13 14:30:53 +02:00
if ( bo - > flags & AMDGPU_GEM_CREATE_NO_CPU_ACCESS )
return - EPERM ;
2015-04-20 16:55:21 -04:00
if ( bo - > kptr ) {
if ( ptr ) {
* ptr = bo - > kptr ;
}
return 0 ;
}
2016-03-10 16:21:04 +01:00
r = reservation_object_wait_timeout_rcu ( bo - > tbo . resv , false , false ,
MAX_SCHEDULE_TIMEOUT ) ;
if ( r < 0 )
return r ;
2015-04-20 16:55:21 -04:00
r = ttm_bo_kmap ( & bo - > tbo , 0 , bo - > tbo . num_pages , & bo - > kmap ) ;
2016-03-10 16:21:04 +01:00
if ( r )
2015-04-20 16:55:21 -04:00
return r ;
2016-03-10 16:21:04 +01:00
2015-04-20 16:55:21 -04:00
bo - > kptr = ttm_kmap_obj_virtual ( & bo - > kmap , & is_iomem ) ;
2016-03-10 16:21:04 +01:00
if ( ptr )
2015-04-20 16:55:21 -04:00
* ptr = bo - > kptr ;
2016-03-10 16:21:04 +01:00
2015-04-20 16:55:21 -04:00
return 0 ;
}
void amdgpu_bo_kunmap ( struct amdgpu_bo * bo )
{
if ( bo - > kptr = = NULL )
return ;
bo - > kptr = NULL ;
ttm_bo_kunmap ( & bo - > kmap ) ;
}
struct amdgpu_bo * amdgpu_bo_ref ( struct amdgpu_bo * bo )
{
if ( bo = = NULL )
return NULL ;
ttm_bo_reference ( & bo - > tbo ) ;
return bo ;
}
void amdgpu_bo_unref ( struct amdgpu_bo * * bo )
{
struct ttm_buffer_object * tbo ;
if ( ( * bo ) = = NULL )
return ;
tbo = & ( ( * bo ) - > tbo ) ;
ttm_bo_unref ( & tbo ) ;
if ( tbo = = NULL )
* bo = NULL ;
}
2015-04-24 17:37:30 +08:00
int amdgpu_bo_pin_restricted ( struct amdgpu_bo * bo , u32 domain ,
u64 min_offset , u64 max_offset ,
2015-04-20 16:55:21 -04:00
u64 * gpu_addr )
{
int r , i ;
2015-04-24 17:37:30 +08:00
unsigned fpfn , lpfn ;
2015-04-20 16:55:21 -04:00
2016-02-08 11:08:35 +01:00
if ( amdgpu_ttm_tt_get_usermm ( bo - > tbo . ttm ) )
2015-04-20 16:55:21 -04:00
return - EPERM ;
2015-04-24 17:37:30 +08:00
if ( WARN_ON_ONCE ( min_offset > max_offset ) )
return - EINVAL ;
2015-04-20 16:55:21 -04:00
if ( bo - > pin_count ) {
2016-08-18 12:55:13 +08:00
uint32_t mem_type = bo - > tbo . mem . mem_type ;
if ( domain ! = amdgpu_mem_type_to_domain ( mem_type ) )
return - EINVAL ;
2015-04-20 16:55:21 -04:00
bo - > pin_count + + ;
if ( gpu_addr )
* gpu_addr = amdgpu_bo_gpu_offset ( bo ) ;
if ( max_offset ! = 0 ) {
2016-08-18 13:18:09 +08:00
u64 domain_start = bo - > tbo . bdev - > man [ mem_type ] . gpu_offset ;
2015-04-20 16:55:21 -04:00
WARN_ON_ONCE ( max_offset <
( amdgpu_bo_gpu_offset ( bo ) - domain_start ) ) ;
}
return 0 ;
}
amdgpu_ttm_placement_from_domain ( bo , domain ) ;
for ( i = 0 ; i < bo - > placement . num_placement ; i + + ) {
/* force to pin into visible video ram */
if ( ( bo - > placements [ i ] . flags & TTM_PL_FLAG_VRAM ) & &
2015-04-24 17:37:30 +08:00
! ( bo - > flags & AMDGPU_GEM_CREATE_NO_CPU_ACCESS ) & &
2016-08-12 16:50:12 +02:00
( ! max_offset | | max_offset >
bo - > adev - > mc . visible_vram_size ) ) {
2015-04-24 17:37:30 +08:00
if ( WARN_ON_ONCE ( min_offset >
bo - > adev - > mc . visible_vram_size ) )
return - EINVAL ;
fpfn = min_offset > > PAGE_SHIFT ;
lpfn = bo - > adev - > mc . visible_vram_size > > PAGE_SHIFT ;
} else {
fpfn = min_offset > > PAGE_SHIFT ;
lpfn = max_offset > > PAGE_SHIFT ;
}
if ( fpfn > bo - > placements [ i ] . fpfn )
bo - > placements [ i ] . fpfn = fpfn ;
2016-01-19 12:48:14 +01:00
if ( ! bo - > placements [ i ] . lpfn | |
( lpfn & & lpfn < bo - > placements [ i ] . lpfn ) )
2015-04-24 17:37:30 +08:00
bo - > placements [ i ] . lpfn = lpfn ;
2015-04-20 16:55:21 -04:00
bo - > placements [ i ] . flags | = TTM_PL_FLAG_NO_EVICT ;
}
r = ttm_bo_validate ( & bo - > tbo , & bo - > placement , false , false ) ;
2016-08-12 16:50:12 +02:00
if ( unlikely ( r ) ) {
2015-04-20 16:55:21 -04:00
dev_err ( bo - > adev - > dev , " %p pin failed \n " , bo ) ;
2016-08-12 16:50:12 +02:00
goto error ;
}
bo - > pin_count = 1 ;
if ( gpu_addr ! = NULL )
* gpu_addr = amdgpu_bo_gpu_offset ( bo ) ;
if ( domain = = AMDGPU_GEM_DOMAIN_VRAM ) {
bo - > adev - > vram_pin_size + = amdgpu_bo_size ( bo ) ;
if ( bo - > flags & AMDGPU_GEM_CREATE_NO_CPU_ACCESS )
bo - > adev - > invisible_pin_size + = amdgpu_bo_size ( bo ) ;
2016-08-18 13:17:07 +08:00
} else if ( domain = = AMDGPU_GEM_DOMAIN_GTT ) {
2016-08-12 16:50:12 +02:00
bo - > adev - > gart_pin_size + = amdgpu_bo_size ( bo ) ;
2015-04-20 16:55:21 -04:00
}
2016-08-12 16:50:12 +02:00
error :
2015-04-20 16:55:21 -04:00
return r ;
}
int amdgpu_bo_pin ( struct amdgpu_bo * bo , u32 domain , u64 * gpu_addr )
{
2015-04-24 17:37:30 +08:00
return amdgpu_bo_pin_restricted ( bo , domain , 0 , 0 , gpu_addr ) ;
2015-04-20 16:55:21 -04:00
}
int amdgpu_bo_unpin ( struct amdgpu_bo * bo )
{
int r , i ;
if ( ! bo - > pin_count ) {
dev_warn ( bo - > adev - > dev , " %p unpin not necessary \n " , bo ) ;
return 0 ;
}
bo - > pin_count - - ;
if ( bo - > pin_count )
return 0 ;
for ( i = 0 ; i < bo - > placement . num_placement ; i + + ) {
bo - > placements [ i ] . lpfn = 0 ;
bo - > placements [ i ] . flags & = ~ TTM_PL_FLAG_NO_EVICT ;
}
r = ttm_bo_validate ( & bo - > tbo , & bo - > placement , false , false ) ;
2016-08-12 16:50:12 +02:00
if ( unlikely ( r ) ) {
2015-04-20 16:55:21 -04:00
dev_err ( bo - > adev - > dev , " %p validate failed for unpin \n " , bo ) ;
2016-08-12 16:50:12 +02:00
goto error ;
2015-04-20 16:55:21 -04:00
}
2016-08-12 16:50:12 +02:00
if ( bo - > tbo . mem . mem_type = = TTM_PL_VRAM ) {
bo - > adev - > vram_pin_size - = amdgpu_bo_size ( bo ) ;
if ( bo - > flags & AMDGPU_GEM_CREATE_NO_CPU_ACCESS )
bo - > adev - > invisible_pin_size - = amdgpu_bo_size ( bo ) ;
} else {
bo - > adev - > gart_pin_size - = amdgpu_bo_size ( bo ) ;
}
error :
2015-04-20 16:55:21 -04:00
return r ;
}
int amdgpu_bo_evict_vram ( struct amdgpu_device * adev )
{
/* late 2.6.33 fix IGP hibernate - we need pm ops to do this correct */
2015-07-22 11:29:01 +08:00
if ( 0 & & ( adev - > flags & AMD_IS_APU ) ) {
2015-04-20 16:55:21 -04:00
/* Useless to evict on IGP chips */
return 0 ;
}
return ttm_bo_evict_mm ( & adev - > mman . bdev , TTM_PL_VRAM ) ;
}
2016-03-31 16:56:22 -04:00
static const char * amdgpu_vram_names [ ] = {
" UNKNOWN " ,
" GDDR1 " ,
" DDR2 " ,
" GDDR3 " ,
" GDDR4 " ,
" GDDR5 " ,
" HBM " ,
" DDR3 "
} ;
2015-04-20 16:55:21 -04:00
int amdgpu_bo_init ( struct amdgpu_device * adev )
{
/* Add an MTRR for the VRAM */
adev - > mc . vram_mtrr = arch_phys_wc_add ( adev - > mc . aper_base ,
adev - > mc . aper_size ) ;
DRM_INFO ( " Detected VRAM RAM=%lluM, BAR=%lluM \n " ,
adev - > mc . mc_vram_size > > 20 ,
( unsigned long long ) adev - > mc . aper_size > > 20 ) ;
2016-03-31 16:56:22 -04:00
DRM_INFO ( " RAM width %dbits %s \n " ,
adev - > mc . vram_width , amdgpu_vram_names [ adev - > mc . vram_type ] ) ;
2015-04-20 16:55:21 -04:00
return amdgpu_ttm_init ( adev ) ;
}
void amdgpu_bo_fini ( struct amdgpu_device * adev )
{
amdgpu_ttm_fini ( adev ) ;
arch_phys_wc_del ( adev - > mc . vram_mtrr ) ;
}
int amdgpu_bo_fbdev_mmap ( struct amdgpu_bo * bo ,
struct vm_area_struct * vma )
{
return ttm_fbdev_mmap ( vma , & bo - > tbo ) ;
}
int amdgpu_bo_set_tiling_flags ( struct amdgpu_bo * bo , u64 tiling_flags )
{
2015-05-14 23:48:26 +02:00
if ( AMDGPU_TILING_GET ( tiling_flags , TILE_SPLIT ) > 6 )
2015-04-20 16:55:21 -04:00
return - EINVAL ;
bo - > tiling_flags = tiling_flags ;
return 0 ;
}
void amdgpu_bo_get_tiling_flags ( struct amdgpu_bo * bo , u64 * tiling_flags )
{
lockdep_assert_held ( & bo - > tbo . resv - > lock . base ) ;
if ( tiling_flags )
* tiling_flags = bo - > tiling_flags ;
}
int amdgpu_bo_set_metadata ( struct amdgpu_bo * bo , void * metadata ,
uint32_t metadata_size , uint64_t flags )
{
void * buffer ;
if ( ! metadata_size ) {
if ( bo - > metadata_size ) {
kfree ( bo - > metadata ) ;
2016-05-03 12:44:29 +10:00
bo - > metadata = NULL ;
2015-04-20 16:55:21 -04:00
bo - > metadata_size = 0 ;
}
return 0 ;
}
if ( metadata = = NULL )
return - EINVAL ;
2015-09-21 17:34:39 -04:00
buffer = kmemdup ( metadata , metadata_size , GFP_KERNEL ) ;
2015-04-20 16:55:21 -04:00
if ( buffer = = NULL )
return - ENOMEM ;
kfree ( bo - > metadata ) ;
bo - > metadata_flags = flags ;
bo - > metadata = buffer ;
bo - > metadata_size = metadata_size ;
return 0 ;
}
int amdgpu_bo_get_metadata ( struct amdgpu_bo * bo , void * buffer ,
size_t buffer_size , uint32_t * metadata_size ,
uint64_t * flags )
{
if ( ! buffer & & ! metadata_size )
return - EINVAL ;
if ( buffer ) {
if ( buffer_size < bo - > metadata_size )
return - EINVAL ;
if ( bo - > metadata_size )
memcpy ( buffer , bo - > metadata , bo - > metadata_size ) ;
}
if ( metadata_size )
* metadata_size = bo - > metadata_size ;
if ( flags )
* flags = bo - > metadata_flags ;
return 0 ;
}
void amdgpu_bo_move_notify ( struct ttm_buffer_object * bo ,
struct ttm_mem_reg * new_mem )
{
struct amdgpu_bo * rbo ;
2016-06-07 17:48:52 +08:00
struct ttm_mem_reg * old_mem = & bo - > mem ;
2015-04-20 16:55:21 -04:00
if ( ! amdgpu_ttm_bo_is_amdgpu_bo ( bo ) )
return ;
rbo = container_of ( bo , struct amdgpu_bo , tbo ) ;
amdgpu_vm_bo_invalidate ( rbo - > adev , rbo ) ;
/* update statistics */
if ( ! new_mem )
return ;
/* move_notify is called before move happens */
amdgpu_update_memory_usage ( rbo - > adev , & bo - > mem , new_mem ) ;
2016-06-07 17:48:52 +08:00
trace_amdgpu_ttm_bo_move ( rbo , new_mem - > mem_type , old_mem - > mem_type ) ;
2015-04-20 16:55:21 -04:00
}
int amdgpu_bo_fault_reserve_notify ( struct ttm_buffer_object * bo )
{
struct amdgpu_device * adev ;
2015-05-21 17:03:46 +02:00
struct amdgpu_bo * abo ;
unsigned long offset , size , lpfn ;
int i , r ;
2015-04-20 16:55:21 -04:00
if ( ! amdgpu_ttm_bo_is_amdgpu_bo ( bo ) )
return 0 ;
2015-05-21 17:03:46 +02:00
abo = container_of ( bo , struct amdgpu_bo , tbo ) ;
adev = abo - > adev ;
if ( bo - > mem . mem_type ! = TTM_PL_VRAM )
return 0 ;
size = bo - > mem . num_pages < < PAGE_SHIFT ;
offset = bo - > mem . start < < PAGE_SHIFT ;
if ( ( offset + size ) < = adev - > mc . visible_vram_size )
return 0 ;
2016-03-28 12:53:02 +09:00
/* Can't move a pinned BO to visible VRAM */
if ( abo - > pin_count > 0 )
return - EINVAL ;
2015-05-21 17:03:46 +02:00
/* hurrah the memory is not visible ! */
amdgpu_ttm_placement_from_domain ( abo , AMDGPU_GEM_DOMAIN_VRAM ) ;
lpfn = adev - > mc . visible_vram_size > > PAGE_SHIFT ;
for ( i = 0 ; i < abo - > placement . num_placement ; i + + ) {
/* Force into visible VRAM */
if ( ( abo - > placements [ i ] . flags & TTM_PL_FLAG_VRAM ) & &
2016-08-12 16:50:12 +02:00
( ! abo - > placements [ i ] . lpfn | |
abo - > placements [ i ] . lpfn > lpfn ) )
2015-05-21 17:03:46 +02:00
abo - > placements [ i ] . lpfn = lpfn ;
}
r = ttm_bo_validate ( bo , & abo - > placement , false , false ) ;
if ( unlikely ( r = = - ENOMEM ) ) {
amdgpu_ttm_placement_from_domain ( abo , AMDGPU_GEM_DOMAIN_GTT ) ;
return ttm_bo_validate ( bo , & abo - > placement , false , false ) ;
} else if ( unlikely ( r ! = 0 ) ) {
return r ;
2015-04-20 16:55:21 -04:00
}
2015-05-21 17:03:46 +02:00
offset = bo - > mem . start < < PAGE_SHIFT ;
/* this should never happen */
if ( ( offset + size ) > adev - > mc . visible_vram_size )
return - EINVAL ;
2015-04-20 16:55:21 -04:00
return 0 ;
}
/**
* amdgpu_bo_fence - add fence to buffer object
*
* @ bo : buffer object in question
* @ fence : fence to add
* @ shared : true if fence should be added shared
*
*/
2015-08-03 11:38:09 +08:00
void amdgpu_bo_fence ( struct amdgpu_bo * bo , struct fence * fence ,
2015-04-20 16:55:21 -04:00
bool shared )
{
struct reservation_object * resv = bo - > tbo . resv ;
if ( shared )
2015-08-03 11:38:09 +08:00
reservation_object_add_shared_fence ( resv , fence ) ;
2015-04-20 16:55:21 -04:00
else
2015-08-03 11:38:09 +08:00
reservation_object_add_excl_fence ( resv , fence ) ;
2015-04-20 16:55:21 -04:00
}
2016-07-25 17:56:18 +02:00
/**
* amdgpu_bo_gpu_offset - return GPU offset of bo
* @ bo : amdgpu object for which we query the offset
*
* Returns current GPU offset of the object .
*
* Note : object should either be pinned or reserved when calling this
* function , it might be useful to add check for this for debugging .
*/
u64 amdgpu_bo_gpu_offset ( struct amdgpu_bo * bo )
{
WARN_ON_ONCE ( bo - > tbo . mem . mem_type = = TTM_PL_SYSTEM ) ;
WARN_ON_ONCE ( ! ww_mutex_is_locked ( & bo - > tbo . resv - > lock ) & &
! bo - > pin_count ) ;
return bo - > tbo . offset ;
}