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
*/
2017-04-24 13:50:21 +09:00
# include <drm/ttm/ttm_bo_api.h>
# include <drm/ttm/ttm_bo_driver.h>
# include <drm/ttm/ttm_placement.h>
# include <drm/ttm/ttm_module.h>
# include <drm/ttm/ttm_page_alloc.h>
2015-04-20 16:55:21 -04:00
# include <drm/drmP.h>
# include <drm/amdgpu_drm.h>
# include <linux/seq_file.h>
# include <linux/slab.h>
# include <linux/swiotlb.h>
# include <linux/swap.h>
# include <linux/pagemap.h>
# include <linux/debugfs.h>
2017-09-18 07:28:14 -04:00
# include <linux/iommu.h>
2015-04-20 16:55:21 -04:00
# include "amdgpu.h"
2017-09-15 21:05:19 -04:00
# include "amdgpu_object.h"
2017-07-31 09:35:24 -04:00
# include "amdgpu_trace.h"
2018-02-06 20:32:35 -05:00
# include "amdgpu_amdkfd.h"
2018-08-02 17:23:33 +08:00
# include "amdgpu_sdma.h"
2015-04-20 16:55:21 -04:00
# include "bif/bif_4_1_d.h"
2017-06-30 11:05:54 +02:00
static int amdgpu_map_buffer ( struct ttm_buffer_object * bo ,
struct ttm_mem_reg * mem , unsigned num_pages ,
uint64_t offset , unsigned window ,
struct amdgpu_ring * ring ,
uint64_t * addr ) ;
2015-04-20 16:55:21 -04:00
static int amdgpu_ttm_debugfs_init ( struct amdgpu_device * adev ) ;
static void amdgpu_ttm_debugfs_fini ( struct amdgpu_device * adev ) ;
static int amdgpu_invalidate_caches ( struct ttm_bo_device * bdev , uint32_t flags )
{
return 0 ;
}
2018-05-09 14:22:29 -04:00
/**
2018-07-26 14:08:03 +08:00
* amdgpu_init_mem_type - Initialize a memory manager for a specific type of
* memory request .
2018-05-09 14:22:29 -04:00
*
2018-07-26 14:08:03 +08:00
* @ bdev : The TTM BO device object ( contains a reference to amdgpu_device )
* @ type : The type of memory requested
* @ man : The memory type manager for each domain
2018-05-09 14:22:29 -04:00
*
* This is called by ttm_bo_init_mm ( ) when a buffer object is being
* initialized .
*/
2015-04-20 16:55:21 -04:00
static int amdgpu_init_mem_type ( struct ttm_bo_device * bdev , uint32_t type ,
struct ttm_mem_type_manager * man )
{
struct amdgpu_device * adev ;
2016-09-15 14:58:48 +02:00
adev = amdgpu_ttm_adev ( bdev ) ;
2015-04-20 16:55:21 -04:00
switch ( type ) {
case TTM_PL_SYSTEM :
/* System memory */
man - > flags = TTM_MEMTYPE_FLAG_MAPPABLE ;
man - > available_caching = TTM_PL_MASK_CACHING ;
man - > default_caching = TTM_PL_FLAG_CACHED ;
break ;
case TTM_PL_TT :
2018-05-09 14:22:29 -04:00
/* GTT memory */
2016-09-09 16:32:33 +02:00
man - > func = & amdgpu_gtt_mgr_func ;
2018-09-14 12:54:33 +02:00
man - > gpu_offset = adev - > gmc . gart_start ;
2015-04-20 16:55:21 -04:00
man - > available_caching = TTM_PL_MASK_CACHING ;
man - > default_caching = TTM_PL_FLAG_CACHED ;
man - > flags = TTM_MEMTYPE_FLAG_MAPPABLE | TTM_MEMTYPE_FLAG_CMA ;
break ;
case TTM_PL_VRAM :
/* "On-card" video ram */
2016-08-24 15:51:49 +02:00
man - > func = & amdgpu_vram_mgr_func ;
2018-01-12 14:52:22 +01:00
man - > gpu_offset = adev - > gmc . vram_start ;
2015-04-20 16:55:21 -04:00
man - > flags = TTM_MEMTYPE_FLAG_FIXED |
TTM_MEMTYPE_FLAG_MAPPABLE ;
man - > available_caching = TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_WC ;
man - > default_caching = TTM_PL_FLAG_WC ;
break ;
case AMDGPU_PL_GDS :
case AMDGPU_PL_GWS :
case AMDGPU_PL_OA :
/* On-chip GDS memory*/
man - > func = & ttm_bo_manager_func ;
man - > gpu_offset = 0 ;
man - > flags = TTM_MEMTYPE_FLAG_FIXED | TTM_MEMTYPE_FLAG_CMA ;
man - > available_caching = TTM_PL_FLAG_UNCACHED ;
man - > default_caching = TTM_PL_FLAG_UNCACHED ;
break ;
default :
DRM_ERROR ( " Unsupported memory type %u \n " , ( unsigned ) type ) ;
return - EINVAL ;
}
return 0 ;
}
2018-05-09 14:22:29 -04:00
/**
* amdgpu_evict_flags - Compute placement flags
*
* @ bo : The buffer object to evict
* @ placement : Possible destination ( s ) for evicted BO
*
* Fill in placement data when ttm_bo_evict ( ) is called
*/
2015-04-20 16:55:21 -04:00
static void amdgpu_evict_flags ( struct ttm_buffer_object * bo ,
struct ttm_placement * placement )
{
2016-09-15 14:58:48 +02:00
struct amdgpu_device * adev = amdgpu_ttm_adev ( bo - > bdev ) ;
2016-09-15 15:06:50 +02:00
struct amdgpu_bo * abo ;
2017-07-02 14:43:58 +05:30
static const struct ttm_place placements = {
2015-04-20 16:55:21 -04:00
. fpfn = 0 ,
. lpfn = 0 ,
. flags = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM
} ;
2018-05-09 14:22:29 -04:00
/* Don't handle scatter gather BOs */
2018-02-20 19:09:56 +01:00
if ( bo - > type = = ttm_bo_type_sg ) {
placement - > num_placement = 0 ;
placement - > num_busy_placement = 0 ;
return ;
}
2018-05-09 14:22:29 -04:00
/* Object isn't an AMDGPU object so ignore */
2018-07-16 16:12:24 +02:00
if ( ! amdgpu_bo_is_amdgpu_bo ( bo ) ) {
2015-04-20 16:55:21 -04:00
placement - > placement = & placements ;
placement - > busy_placement = & placements ;
placement - > num_placement = 1 ;
placement - > num_busy_placement = 1 ;
return ;
}
2018-05-09 14:22:29 -04:00
2017-09-15 21:05:19 -04:00
abo = ttm_to_amdgpu_bo ( bo ) ;
2015-04-20 16:55:21 -04:00
switch ( bo - > mem . mem_type ) {
2018-09-14 20:44:17 +02:00
case AMDGPU_PL_GDS :
case AMDGPU_PL_GWS :
case AMDGPU_PL_OA :
placement - > num_placement = 0 ;
placement - > num_busy_placement = 0 ;
return ;
2015-04-20 16:55:21 -04:00
case TTM_PL_VRAM :
2018-03-01 11:09:15 +01:00
if ( ! adev - > mman . buffer_funcs_enabled ) {
2018-05-09 14:22:29 -04:00
/* Move to system memory */
2018-07-16 16:12:24 +02:00
amdgpu_bo_placement_from_domain ( abo , AMDGPU_GEM_DOMAIN_CPU ) ;
2018-06-12 14:28:20 -04:00
} else if ( ! amdgpu_gmc_vram_full_visible ( & adev - > gmc ) & &
2018-04-05 16:42:03 +02:00
! ( abo - > flags & AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED ) & &
amdgpu_bo_in_cpu_visible_vram ( abo ) ) {
2017-07-04 17:16:42 +09:00
/* Try evicting to the CPU inaccessible part of VRAM
* first , but only set GTT as busy placement , so this
* BO will be evicted to GTT rather than causing other
* BOs to be evicted from VRAM
*/
2018-07-16 16:12:24 +02:00
amdgpu_bo_placement_from_domain ( abo , AMDGPU_GEM_DOMAIN_VRAM |
2017-07-04 17:16:42 +09:00
AMDGPU_GEM_DOMAIN_GTT ) ;
2018-04-05 16:42:03 +02:00
abo - > placements [ 0 ] . fpfn = adev - > gmc . visible_vram_size > > PAGE_SHIFT ;
2017-07-04 17:16:42 +09:00
abo - > placements [ 0 ] . lpfn = 0 ;
abo - > placement . busy_placement = & abo - > placements [ 1 ] ;
abo - > placement . num_busy_placement = 1 ;
2016-09-12 16:06:18 +02:00
} else {
2018-05-09 14:22:29 -04:00
/* Move to GTT memory */
2018-07-16 16:12:24 +02:00
amdgpu_bo_placement_from_domain ( abo , AMDGPU_GEM_DOMAIN_GTT ) ;
2016-09-12 16:06:18 +02:00
}
2015-04-20 16:55:21 -04:00
break ;
case TTM_PL_TT :
default :
2018-07-16 16:12:24 +02:00
amdgpu_bo_placement_from_domain ( abo , AMDGPU_GEM_DOMAIN_CPU ) ;
2018-09-14 20:44:17 +02:00
break ;
2015-04-20 16:55:21 -04:00
}
2016-09-15 15:06:50 +02:00
* placement = abo - > placement ;
2015-04-20 16:55:21 -04:00
}
2018-05-09 14:22:29 -04:00
/**
* amdgpu_verify_access - Verify access for a mmap call
*
2018-07-26 14:08:03 +08:00
* @ bo : The buffer object to map
* @ filp : The file pointer from the process performing the mmap
2018-05-09 14:22:29 -04:00
*
* This is called by ttm_bo_mmap ( ) to verify whether a process
* has the right to mmap a BO to their process space .
*/
2015-04-20 16:55:21 -04:00
static int amdgpu_verify_access ( struct ttm_buffer_object * bo , struct file * filp )
{
2017-09-15 21:05:19 -04:00
struct amdgpu_bo * abo = ttm_to_amdgpu_bo ( bo ) ;
2015-04-20 16:55:21 -04:00
2018-02-06 20:32:38 -05:00
/*
* Don ' t verify access for KFD BOs . They don ' t have a GEM
* object associated with them .
*/
if ( abo - > kfd_bo )
return 0 ;
2016-04-19 09:07:51 -04:00
if ( amdgpu_ttm_tt_get_usermm ( bo - > ttm ) )
return - EPERM ;
2016-09-30 13:18:26 +10:00
return drm_vma_node_verify_access ( & abo - > gem_base . vma_node ,
2016-09-01 14:48:33 +02:00
filp - > private_data ) ;
2015-04-20 16:55:21 -04:00
}
2018-05-09 14:22:29 -04:00
/**
* amdgpu_move_null - Register memory for a buffer object
*
2018-07-26 14:08:03 +08:00
* @ bo : The bo to assign the memory to
* @ new_mem : The memory to be assigned .
2018-05-09 14:22:29 -04:00
*
2018-07-26 14:08:03 +08:00
* Assign the memory from new_mem to the memory of the buffer object bo .
2018-05-09 14:22:29 -04:00
*/
2015-04-20 16:55:21 -04:00
static void amdgpu_move_null ( struct ttm_buffer_object * bo ,
struct ttm_mem_reg * new_mem )
{
struct ttm_mem_reg * old_mem = & bo - > mem ;
BUG_ON ( old_mem - > mm_node ! = NULL ) ;
* old_mem = * new_mem ;
new_mem - > mm_node = NULL ;
}
2018-05-09 14:22:29 -04:00
/**
2018-07-26 14:08:03 +08:00
* amdgpu_mm_node_addr - Compute the GPU relative offset of a GTT buffer .
*
* @ bo : The bo to assign the memory to .
* @ mm_node : Memory manager node for drm allocator .
* @ mem : The region where the bo resides .
*
2018-05-09 14:22:29 -04:00
*/
2017-06-29 10:44:39 +02:00
static uint64_t amdgpu_mm_node_addr ( struct ttm_buffer_object * bo ,
struct drm_mm_node * mm_node ,
struct ttm_mem_reg * mem )
2015-04-20 16:55:21 -04:00
{
2017-06-30 11:05:54 +02:00
uint64_t addr = 0 ;
2016-09-05 17:00:57 +02:00
2018-08-27 13:51:27 +02:00
if ( mm_node - > start ! = AMDGPU_BO_INVALID_OFFSET ) {
2017-06-30 11:05:54 +02:00
addr = mm_node - > start < < PAGE_SHIFT ;
addr + = bo - > bdev - > man [ mem - > mem_type ] . gpu_offset ;
}
2017-06-29 10:44:39 +02:00
return addr ;
2016-08-17 10:46:52 +02:00
}
2017-10-03 15:41:56 -04:00
/**
2018-07-26 14:08:03 +08:00
* amdgpu_find_mm_node - Helper function finds the drm_mm_node corresponding to
* @ offset . It also modifies the offset to be within the drm_mm_node returned
*
* @ mem : The region where the bo resides .
* @ offset : The offset that drm_mm_node is used for finding .
*
2017-10-06 17:36:35 -04:00
*/
static struct drm_mm_node * amdgpu_find_mm_node ( struct ttm_mem_reg * mem ,
unsigned long * offset )
2016-08-17 10:46:52 +02:00
{
2017-10-06 17:36:35 -04:00
struct drm_mm_node * mm_node = mem - > mm_node ;
2016-08-17 10:46:52 +02:00
2017-10-06 17:36:35 -04:00
while ( * offset > = ( mm_node - > size < < PAGE_SHIFT ) ) {
* offset - = ( mm_node - > size < < PAGE_SHIFT ) ;
+ + mm_node ;
}
return mm_node ;
}
2016-08-17 10:46:52 +02:00
2017-10-06 17:36:35 -04:00
/**
* amdgpu_copy_ttm_mem_to_mem - Helper function for copy
2017-10-03 15:41:56 -04:00
*
* The function copies @ size bytes from { src - > mem + src - > offset } to
* { dst - > mem + dst - > offset } . src - > bo and dst - > bo could be same BO for a
* move and different for a BO to BO copy .
*
* @ f : Returns the last fence if multiple jobs are submitted .
*/
int amdgpu_ttm_copy_mem_to_mem ( struct amdgpu_device * adev ,
struct amdgpu_copy_mem * src ,
struct amdgpu_copy_mem * dst ,
uint64_t size ,
struct reservation_object * resv ,
struct dma_fence * * f )
2016-08-17 10:46:52 +02:00
{
struct amdgpu_ring * ring = adev - > mman . buffer_funcs_ring ;
2017-10-03 15:41:56 -04:00
struct drm_mm_node * src_mm , * dst_mm ;
uint64_t src_node_start , dst_node_start , src_node_size ,
dst_node_size , src_page_offset , dst_page_offset ;
2016-10-28 11:33:52 +10:00
struct dma_fence * fence = NULL ;
2017-10-03 15:41:56 -04:00
int r = 0 ;
const uint64_t GTT_MAX_BYTES = ( AMDGPU_GTT_MAX_TRANSFER_SIZE *
AMDGPU_GPU_PAGE_SIZE ) ;
2016-08-17 10:46:52 +02:00
2018-03-01 11:09:15 +01:00
if ( ! adev - > mman . buffer_funcs_enabled ) {
2015-04-20 16:55:21 -04:00
DRM_ERROR ( " Trying to move memory with ring turned off. \n " ) ;
return - EINVAL ;
}
2017-10-06 17:36:35 -04:00
src_mm = amdgpu_find_mm_node ( src - > mem , & src - > offset ) ;
2017-10-03 15:41:56 -04:00
src_node_start = amdgpu_mm_node_addr ( src - > bo , src_mm , src - > mem ) +
src - > offset ;
src_node_size = ( src_mm - > size < < PAGE_SHIFT ) - src - > offset ;
src_page_offset = src_node_start & ( PAGE_SIZE - 1 ) ;
2016-08-17 10:46:52 +02:00
2017-10-06 17:36:35 -04:00
dst_mm = amdgpu_find_mm_node ( dst - > mem , & dst - > offset ) ;
2017-10-03 15:41:56 -04:00
dst_node_start = amdgpu_mm_node_addr ( dst - > bo , dst_mm , dst - > mem ) +
dst - > offset ;
dst_node_size = ( dst_mm - > size < < PAGE_SHIFT ) - dst - > offset ;
dst_page_offset = dst_node_start & ( PAGE_SIZE - 1 ) ;
2016-08-17 10:46:52 +02:00
2017-06-30 11:05:54 +02:00
mutex_lock ( & adev - > mman . gtt_window_lock ) ;
2017-10-03 15:41:56 -04:00
while ( size ) {
unsigned long cur_size ;
uint64_t from = src_node_start , to = dst_node_start ;
2016-10-28 11:33:52 +10:00
struct dma_fence * next ;
2016-08-17 10:46:52 +02:00
2017-10-03 15:41:56 -04:00
/* Copy size cannot exceed GTT_MAX_BYTES. So if src or dst
* begins at an offset , then adjust the size accordingly
*/
cur_size = min3 ( min ( src_node_size , dst_node_size ) , size ,
GTT_MAX_BYTES ) ;
if ( cur_size + src_page_offset > GTT_MAX_BYTES | |
cur_size + dst_page_offset > GTT_MAX_BYTES )
cur_size - = max ( src_page_offset , dst_page_offset ) ;
/* Map only what needs to be accessed. Map src to window 0 and
* dst to window 1
*/
2018-08-27 13:51:27 +02:00
if ( src - > mem - > start = = AMDGPU_BO_INVALID_OFFSET ) {
2017-10-03 15:41:56 -04:00
r = amdgpu_map_buffer ( src - > bo , src - > mem ,
PFN_UP ( cur_size + src_page_offset ) ,
src_node_start , 0 , ring ,
& from ) ;
2017-06-30 11:05:54 +02:00
if ( r )
goto error ;
2017-10-03 15:41:56 -04:00
/* Adjust the offset because amdgpu_map_buffer returns
* start of mapped page
*/
from + = src_page_offset ;
2017-06-30 11:05:54 +02:00
}
2018-08-27 13:51:27 +02:00
if ( dst - > mem - > start = = AMDGPU_BO_INVALID_OFFSET ) {
2017-10-03 15:41:56 -04:00
r = amdgpu_map_buffer ( dst - > bo , dst - > mem ,
PFN_UP ( cur_size + dst_page_offset ) ,
dst_node_start , 1 , ring ,
& to ) ;
2017-06-30 11:05:54 +02:00
if ( r )
goto error ;
2017-10-03 15:41:56 -04:00
to + = dst_page_offset ;
2017-06-30 11:05:54 +02:00
}
2017-10-03 15:41:56 -04:00
r = amdgpu_copy_buffer ( ring , from , to , cur_size ,
resv , & next , false , true ) ;
2016-08-17 10:46:52 +02:00
if ( r )
goto error ;
2016-10-28 11:33:52 +10:00
dma_fence_put ( fence ) ;
2016-08-17 10:46:52 +02:00
fence = next ;
2017-10-03 15:41:56 -04:00
size - = cur_size ;
if ( ! size )
2016-08-17 10:46:52 +02:00
break ;
2017-10-03 15:41:56 -04:00
src_node_size - = cur_size ;
if ( ! src_node_size ) {
src_node_start = amdgpu_mm_node_addr ( src - > bo , + + src_mm ,
src - > mem ) ;
src_node_size = ( src_mm - > size < < PAGE_SHIFT ) ;
2016-08-17 10:46:52 +02:00
} else {
2017-10-03 15:41:56 -04:00
src_node_start + = cur_size ;
src_page_offset = src_node_start & ( PAGE_SIZE - 1 ) ;
2016-08-17 10:46:52 +02:00
}
2017-10-03 15:41:56 -04:00
dst_node_size - = cur_size ;
if ( ! dst_node_size ) {
dst_node_start = amdgpu_mm_node_addr ( dst - > bo , + + dst_mm ,
dst - > mem ) ;
dst_node_size = ( dst_mm - > size < < PAGE_SHIFT ) ;
2016-08-17 10:46:52 +02:00
} else {
2017-10-03 15:41:56 -04:00
dst_node_start + = cur_size ;
dst_page_offset = dst_node_start & ( PAGE_SIZE - 1 ) ;
2016-08-17 10:46:52 +02:00
}
}
2017-10-03 15:41:56 -04:00
error :
2017-06-30 11:05:54 +02:00
mutex_unlock ( & adev - > mman . gtt_window_lock ) ;
2017-10-03 15:41:56 -04:00
if ( f )
* f = dma_fence_get ( fence ) ;
dma_fence_put ( fence ) ;
return r ;
}
2018-05-09 14:22:29 -04:00
/**
* amdgpu_move_blit - Copy an entire buffer to another buffer
*
2018-07-26 14:08:03 +08:00
* This is a helper called by amdgpu_bo_move ( ) and amdgpu_move_vram_ram ( ) to
* help move buffers to and from VRAM .
2018-05-09 14:22:29 -04:00
*/
2017-10-03 15:41:56 -04:00
static int amdgpu_move_blit ( struct ttm_buffer_object * bo ,
bool evict , bool no_wait_gpu ,
struct ttm_mem_reg * new_mem ,
struct ttm_mem_reg * old_mem )
{
struct amdgpu_device * adev = amdgpu_ttm_adev ( bo - > bdev ) ;
struct amdgpu_copy_mem src , dst ;
struct dma_fence * fence = NULL ;
int r ;
src . bo = bo ;
dst . bo = bo ;
src . mem = old_mem ;
dst . mem = new_mem ;
src . offset = 0 ;
dst . offset = 0 ;
r = amdgpu_ttm_copy_mem_to_mem ( adev , & src , & dst ,
new_mem - > num_pages < < PAGE_SHIFT ,
bo - > resv , & fence ) ;
if ( r )
goto error ;
2016-06-15 13:44:05 +02:00
2018-09-11 09:30:46 +02:00
/* Always block for VM page tables before committing the new location */
if ( bo - > type = = ttm_bo_type_kernel )
r = ttm_bo_move_accel_cleanup ( bo , fence , true , new_mem ) ;
else
r = ttm_bo_pipeline_move ( bo , fence , evict , new_mem ) ;
2016-10-25 13:00:45 +01:00
dma_fence_put ( fence ) ;
2015-04-20 16:55:21 -04:00
return r ;
2016-08-17 10:46:52 +02:00
error :
if ( fence )
2016-10-28 11:33:52 +10:00
dma_fence_wait ( fence , false ) ;
dma_fence_put ( fence ) ;
2016-08-17 10:46:52 +02:00
return r ;
2015-04-20 16:55:21 -04:00
}
2018-05-09 14:22:29 -04:00
/**
* amdgpu_move_vram_ram - Copy VRAM buffer to RAM buffer
*
* Called by amdgpu_bo_move ( ) .
*/
2017-04-26 16:44:41 +02:00
static int amdgpu_move_vram_ram ( struct ttm_buffer_object * bo , bool evict ,
struct ttm_operation_ctx * ctx ,
2015-04-20 16:55:21 -04:00
struct ttm_mem_reg * new_mem )
{
struct amdgpu_device * adev ;
struct ttm_mem_reg * old_mem = & bo - > mem ;
struct ttm_mem_reg tmp_mem ;
struct ttm_place placements ;
struct ttm_placement placement ;
int r ;
2016-09-15 14:58:48 +02:00
adev = amdgpu_ttm_adev ( bo - > bdev ) ;
2018-05-09 14:22:29 -04:00
/* create space/pages for new_mem in GTT space */
2015-04-20 16:55:21 -04:00
tmp_mem = * new_mem ;
tmp_mem . mm_node = NULL ;
placement . num_placement = 1 ;
placement . placement = & placements ;
placement . num_busy_placement = 1 ;
placement . busy_placement = & placements ;
placements . fpfn = 0 ;
2017-06-30 12:19:42 +02:00
placements . lpfn = 0 ;
2015-04-20 16:55:21 -04:00
placements . flags = TTM_PL_MASK_CACHING | TTM_PL_FLAG_TT ;
2017-04-26 16:44:41 +02:00
r = ttm_bo_mem_space ( bo , & placement , & tmp_mem , ctx ) ;
2015-04-20 16:55:21 -04:00
if ( unlikely ( r ) ) {
return r ;
}
2018-05-09 14:22:29 -04:00
/* set caching flags */
2015-04-20 16:55:21 -04:00
r = ttm_tt_set_placement_caching ( bo - > ttm , tmp_mem . placement ) ;
if ( unlikely ( r ) ) {
goto out_cleanup ;
}
2018-05-09 14:22:29 -04:00
/* Bind the memory to the GTT space */
2017-12-21 17:42:51 +08:00
r = ttm_tt_bind ( bo - > ttm , & tmp_mem , ctx ) ;
2015-04-20 16:55:21 -04:00
if ( unlikely ( r ) ) {
goto out_cleanup ;
}
2018-05-09 14:22:29 -04:00
/* blit VRAM to GTT */
2018-07-26 18:00:13 +08:00
r = amdgpu_move_blit ( bo , evict , ctx - > no_wait_gpu , & tmp_mem , old_mem ) ;
2015-04-20 16:55:21 -04:00
if ( unlikely ( r ) ) {
goto out_cleanup ;
}
2018-05-09 14:22:29 -04:00
/* move BO (in tmp_mem) to new_mem */
2017-12-08 20:19:32 +08:00
r = ttm_bo_move_ttm ( bo , ctx , new_mem ) ;
2015-04-20 16:55:21 -04:00
out_cleanup :
ttm_bo_mem_put ( bo , & tmp_mem ) ;
return r ;
}
2018-05-09 14:22:29 -04:00
/**
* amdgpu_move_ram_vram - Copy buffer from RAM to VRAM
*
* Called by amdgpu_bo_move ( ) .
*/
2017-04-26 16:44:41 +02:00
static int amdgpu_move_ram_vram ( struct ttm_buffer_object * bo , bool evict ,
struct ttm_operation_ctx * ctx ,
2015-04-20 16:55:21 -04:00
struct ttm_mem_reg * new_mem )
{
struct amdgpu_device * adev ;
struct ttm_mem_reg * old_mem = & bo - > mem ;
struct ttm_mem_reg tmp_mem ;
struct ttm_placement placement ;
struct ttm_place placements ;
int r ;
2016-09-15 14:58:48 +02:00
adev = amdgpu_ttm_adev ( bo - > bdev ) ;
2018-05-09 14:22:29 -04:00
/* make space in GTT for old_mem buffer */
2015-04-20 16:55:21 -04:00
tmp_mem = * new_mem ;
tmp_mem . mm_node = NULL ;
placement . num_placement = 1 ;
placement . placement = & placements ;
placement . num_busy_placement = 1 ;
placement . busy_placement = & placements ;
placements . fpfn = 0 ;
2017-06-30 12:19:42 +02:00
placements . lpfn = 0 ;
2015-04-20 16:55:21 -04:00
placements . flags = TTM_PL_MASK_CACHING | TTM_PL_FLAG_TT ;
2017-04-26 16:44:41 +02:00
r = ttm_bo_mem_space ( bo , & placement , & tmp_mem , ctx ) ;
2015-04-20 16:55:21 -04:00
if ( unlikely ( r ) ) {
return r ;
}
2018-05-09 14:22:29 -04:00
/* move/bind old memory to GTT space */
2017-12-08 20:19:32 +08:00
r = ttm_bo_move_ttm ( bo , ctx , & tmp_mem ) ;
2015-04-20 16:55:21 -04:00
if ( unlikely ( r ) ) {
goto out_cleanup ;
}
2018-05-09 14:22:29 -04:00
/* copy to VRAM */
2018-07-26 18:00:13 +08:00
r = amdgpu_move_blit ( bo , evict , ctx - > no_wait_gpu , new_mem , old_mem ) ;
2015-04-20 16:55:21 -04:00
if ( unlikely ( r ) ) {
goto out_cleanup ;
}
out_cleanup :
ttm_bo_mem_put ( bo , & tmp_mem ) ;
return r ;
}
2018-05-09 14:22:29 -04:00
/**
* amdgpu_bo_move - Move a buffer object to a new memory location
*
* Called by ttm_bo_handle_move_mem ( )
*/
2017-04-26 16:31:14 +02:00
static int amdgpu_bo_move ( struct ttm_buffer_object * bo , bool evict ,
struct ttm_operation_ctx * ctx ,
struct ttm_mem_reg * new_mem )
2015-04-20 16:55:21 -04:00
{
struct amdgpu_device * adev ;
2016-03-28 12:53:02 +09:00
struct amdgpu_bo * abo ;
2015-04-20 16:55:21 -04:00
struct ttm_mem_reg * old_mem = & bo - > mem ;
int r ;
2016-03-28 12:53:02 +09:00
/* Can't move a pinned BO */
2017-09-15 21:05:19 -04:00
abo = ttm_to_amdgpu_bo ( bo ) ;
2016-03-28 12:53:02 +09:00
if ( WARN_ON_ONCE ( abo - > pin_count > 0 ) )
return - EINVAL ;
2016-09-15 14:58:48 +02:00
adev = amdgpu_ttm_adev ( bo - > bdev ) ;
2016-06-21 16:28:14 +02:00
2015-04-20 16:55:21 -04:00
if ( old_mem - > mem_type = = TTM_PL_SYSTEM & & bo - > ttm = = NULL ) {
amdgpu_move_null ( bo , new_mem ) ;
return 0 ;
}
if ( ( old_mem - > mem_type = = TTM_PL_TT & &
new_mem - > mem_type = = TTM_PL_SYSTEM ) | |
( old_mem - > mem_type = = TTM_PL_SYSTEM & &
new_mem - > mem_type = = TTM_PL_TT ) ) {
/* bind is enough */
amdgpu_move_null ( bo , new_mem ) ;
return 0 ;
}
2018-09-14 20:44:17 +02:00
if ( old_mem - > mem_type = = AMDGPU_PL_GDS | |
old_mem - > mem_type = = AMDGPU_PL_GWS | |
old_mem - > mem_type = = AMDGPU_PL_OA | |
new_mem - > mem_type = = AMDGPU_PL_GDS | |
new_mem - > mem_type = = AMDGPU_PL_GWS | |
new_mem - > mem_type = = AMDGPU_PL_OA ) {
/* Nothing to save here */
amdgpu_move_null ( bo , new_mem ) ;
return 0 ;
}
2018-03-01 11:09:15 +01:00
if ( ! adev - > mman . buffer_funcs_enabled )
2015-04-20 16:55:21 -04:00
goto memcpy ;
if ( old_mem - > mem_type = = TTM_PL_VRAM & &
new_mem - > mem_type = = TTM_PL_SYSTEM ) {
2017-04-26 16:44:41 +02:00
r = amdgpu_move_vram_ram ( bo , evict , ctx , new_mem ) ;
2015-04-20 16:55:21 -04:00
} else if ( old_mem - > mem_type = = TTM_PL_SYSTEM & &
new_mem - > mem_type = = TTM_PL_VRAM ) {
2017-04-26 16:44:41 +02:00
r = amdgpu_move_ram_vram ( bo , evict , ctx , new_mem ) ;
2015-04-20 16:55:21 -04:00
} else {
2017-04-26 16:31:14 +02:00
r = amdgpu_move_blit ( bo , evict , ctx - > no_wait_gpu ,
new_mem , old_mem ) ;
2015-04-20 16:55:21 -04:00
}
if ( r ) {
memcpy :
2017-12-08 20:19:32 +08:00
r = ttm_bo_move_memcpy ( bo , ctx , new_mem ) ;
2015-04-20 16:55:21 -04:00
if ( r ) {
return r ;
}
}
2017-06-30 11:31:08 -04:00
if ( bo - > type = = ttm_bo_type_device & &
new_mem - > mem_type = = TTM_PL_VRAM & &
old_mem - > mem_type ! = TTM_PL_VRAM ) {
/* amdgpu_bo_fault_reserve_notify will re-set this if the CPU
* accesses the BO after it ' s moved .
*/
abo - > flags & = ~ AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED ;
}
2015-04-20 16:55:21 -04:00
/* update statistics */
atomic64_add ( ( u64 ) bo - > num_pages < < PAGE_SHIFT , & adev - > num_bytes_moved ) ;
return 0 ;
}
2018-05-09 14:22:29 -04:00
/**
* amdgpu_ttm_io_mem_reserve - Reserve a block of memory during a fault
*
* Called by ttm_mem_io_reserve ( ) ultimately via ttm_bo_vm_fault ( )
*/
2015-04-20 16:55:21 -04:00
static int amdgpu_ttm_io_mem_reserve ( struct ttm_bo_device * bdev , struct ttm_mem_reg * mem )
{
struct ttm_mem_type_manager * man = & bdev - > man [ mem - > mem_type ] ;
2016-09-15 14:58:48 +02:00
struct amdgpu_device * adev = amdgpu_ttm_adev ( bdev ) ;
2018-02-27 10:01:59 -05:00
struct drm_mm_node * mm_node = mem - > mm_node ;
2015-04-20 16:55:21 -04:00
mem - > bus . addr = NULL ;
mem - > bus . offset = 0 ;
mem - > bus . size = mem - > num_pages < < PAGE_SHIFT ;
mem - > bus . base = 0 ;
mem - > bus . is_iomem = false ;
if ( ! ( man - > flags & TTM_MEMTYPE_FLAG_MAPPABLE ) )
return - EINVAL ;
switch ( mem - > mem_type ) {
case TTM_PL_SYSTEM :
/* system memory */
return 0 ;
case TTM_PL_TT :
break ;
case TTM_PL_VRAM :
mem - > bus . offset = mem - > start < < PAGE_SHIFT ;
/* check if it's visible */
2018-01-12 14:52:22 +01:00
if ( ( mem - > bus . offset + mem - > bus . size ) > adev - > gmc . visible_vram_size )
2015-04-20 16:55:21 -04:00
return - EINVAL ;
2018-02-27 10:01:59 -05:00
/* Only physically contiguous buffers apply. In a contiguous
* buffer , size of the first mm_node would match the number of
* pages in ttm_mem_reg .
*/
if ( adev - > mman . aper_base_kaddr & &
( mm_node - > size = = mem - > num_pages ) )
mem - > bus . addr = ( u8 * ) adev - > mman . aper_base_kaddr +
mem - > bus . offset ;
2018-01-12 14:52:22 +01:00
mem - > bus . base = adev - > gmc . aper_base ;
2015-04-20 16:55:21 -04:00
mem - > bus . is_iomem = true ;
break ;
default :
return - EINVAL ;
}
return 0 ;
}
static void amdgpu_ttm_io_mem_free ( struct ttm_bo_device * bdev , struct ttm_mem_reg * mem )
{
}
2017-03-29 11:16:05 +02:00
static unsigned long amdgpu_ttm_io_mem_pfn ( struct ttm_buffer_object * bo ,
unsigned long page_offset )
{
2017-10-06 17:36:35 -04:00
struct drm_mm_node * mm ;
unsigned long offset = ( page_offset < < PAGE_SHIFT ) ;
2017-03-29 11:16:05 +02:00
2017-10-06 17:36:35 -04:00
mm = amdgpu_find_mm_node ( & bo - > mem , & offset ) ;
return ( bo - > mem . bus . base > > PAGE_SHIFT ) + mm - > start +
( offset > > PAGE_SHIFT ) ;
2017-03-29 11:16:05 +02:00
}
2015-04-20 16:55:21 -04:00
/*
* TTM backend functions .
*/
2019-03-28 10:15:26 -05:00
struct amdgpu_ttm_gup_task_list {
struct list_head list ;
struct task_struct * task ;
} ;
2015-04-20 16:55:21 -04:00
struct amdgpu_ttm_tt {
2016-03-03 14:24:57 +01:00
struct ttm_dma_tt ttm ;
u64 offset ;
uint64_t userptr ;
2018-03-23 15:32:29 -04:00
struct task_struct * usertask ;
2016-03-03 14:24:57 +01:00
uint32_t userflags ;
2019-03-28 10:15:26 -05:00
spinlock_t guptasklock ;
struct list_head guptasks ;
atomic_t mmu_invalidations ;
uint32_t last_set_pages ;
2015-04-20 16:55:21 -04:00
} ;
2018-05-09 14:22:29 -04:00
/**
2019-03-28 10:15:26 -05:00
* amdgpu_ttm_tt_get_user_pages - Pin pages of memory pointed to by a USERPTR
* pointer to memory
2018-05-09 14:22:29 -04:00
*
2019-03-28 10:15:26 -05:00
* Called by amdgpu_gem_userptr_ioctl ( ) and amdgpu_cs_parser_bos ( ) .
* This provides a wrapper around the get_user_pages ( ) call to provide
* device accessible pages that back user memory .
2018-05-09 14:22:29 -04:00
*/
2016-02-23 12:36:59 +01:00
int amdgpu_ttm_tt_get_user_pages ( struct ttm_tt * ttm , struct page * * pages )
2015-04-20 16:55:21 -04:00
{
struct amdgpu_ttm_tt * gtt = ( void * ) ttm ;
2018-03-23 15:32:29 -04:00
struct mm_struct * mm = gtt - > usertask - > mm ;
2019-03-28 10:15:26 -05:00
unsigned int flags = 0 ;
unsigned pinned = 0 ;
int r ;
2015-04-20 16:55:21 -04:00
2018-03-23 15:32:29 -04:00
if ( ! mm ) /* Happens during process shutdown */
return - ESRCH ;
2019-03-28 10:15:26 -05:00
if ( ! ( gtt - > userflags & AMDGPU_GEM_USERPTR_READONLY ) )
flags | = FOLL_WRITE ;
2019-03-04 14:41:03 -05:00
2019-03-28 10:14:03 -05:00
down_read ( & mm - > mmap_sem ) ;
2019-03-04 14:41:03 -05:00
2019-03-28 10:15:26 -05:00
if ( gtt - > userflags & AMDGPU_GEM_USERPTR_ANONONLY ) {
/*
* check that we only use anonymous memory to prevent problems
* with writeback
*/
unsigned long end = gtt - > userptr + ttm - > num_pages * PAGE_SIZE ;
struct vm_area_struct * vma ;
2015-04-20 16:55:21 -04:00
2019-03-28 10:15:26 -05:00
vma = find_vma ( mm , gtt - > userptr ) ;
if ( ! vma | | vma - > vm_file | | vma - > vm_end < end ) {
up_read ( & mm - > mmap_sem ) ;
return - EPERM ;
}
2015-04-20 16:55:21 -04:00
}
2019-03-28 10:15:26 -05:00
/* loop enough times using contiguous pages of memory */
do {
unsigned num_pages = ttm - > num_pages - pinned ;
uint64_t userptr = gtt - > userptr + pinned * PAGE_SIZE ;
struct page * * p = pages + pinned ;
struct amdgpu_ttm_gup_task_list guptask ;
2016-03-03 14:24:57 +01:00
2019-03-28 10:15:26 -05:00
guptask . task = current ;
spin_lock ( & gtt - > guptasklock ) ;
list_add ( & guptask . list , & gtt - > guptasks ) ;
spin_unlock ( & gtt - > guptasklock ) ;
2015-04-20 16:55:21 -04:00
2019-03-28 10:15:26 -05:00
if ( mm = = current - > mm )
r = get_user_pages ( userptr , num_pages , flags , p , NULL ) ;
else
r = get_user_pages_remote ( gtt - > usertask ,
mm , userptr , num_pages ,
flags , p , NULL , NULL ) ;
2016-03-03 14:24:57 +01:00
2019-03-28 10:15:26 -05:00
spin_lock ( & gtt - > guptasklock ) ;
list_del ( & guptask . list ) ;
spin_unlock ( & gtt - > guptasklock ) ;
2015-04-20 16:55:21 -04:00
2019-03-28 10:15:26 -05:00
if ( r < 0 )
goto release_pages ;
2015-04-20 16:55:21 -04:00
2019-03-28 10:15:26 -05:00
pinned + = r ;
2015-04-20 16:55:21 -04:00
2019-03-28 10:15:26 -05:00
} while ( pinned < ttm - > num_pages ) ;
drm/amdgpu: replace get_user_pages with HMM mirror helpers
Use HMM helper function hmm_vma_fault() to get physical pages backing
userptr and start CPU page table update track of those pages. Then use
hmm_vma_range_done() to check if those pages are updated before
amdgpu_cs_submit for gfx or before user queues are resumed for kfd.
If userptr pages are updated, for gfx, amdgpu_cs_ioctl will restart
from scratch, for kfd, restore worker is rescheduled to retry.
HMM simplify the CPU page table concurrent update check, so remove
guptasklock, mmu_invalidations, last_set_pages fields from
amdgpu_ttm_tt struct.
HMM does not pin the page (increase page ref count), so remove related
operations like release_pages(), put_page(), mark_page_dirty().
Signed-off-by: Philip Yang <Philip.Yang@amd.com>
Reviewed-by: Felix Kuehling <Felix.Kuehling@amd.com>
Reviewed-by: Christian König <christian.koenig@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
2018-12-13 15:35:28 -05:00
2019-03-28 10:15:26 -05:00
up_read ( & mm - > mmap_sem ) ;
return 0 ;
2016-02-23 12:36:59 +01:00
2019-03-28 10:15:26 -05:00
release_pages :
release_pages ( pages , pinned ) ;
up_read ( & mm - > mmap_sem ) ;
2016-02-23 12:36:59 +01:00
return r ;
}
2018-05-09 14:22:29 -04:00
/**
2018-07-26 14:08:03 +08:00
* amdgpu_ttm_tt_set_user_pages - Copy pages in , putting old pages as necessary .
2018-05-09 14:22:29 -04:00
*
2018-07-26 14:08:03 +08:00
* Called by amdgpu_cs_list_validate ( ) . This creates the page list
2018-05-09 14:22:29 -04:00
* that backs user memory and will ultimately be mapped into the device
* address space .
*/
2017-09-02 13:21:31 +02:00
void amdgpu_ttm_tt_set_user_pages ( struct ttm_tt * ttm , struct page * * pages )
2017-07-31 09:35:24 -04:00
{
2019-03-28 10:15:26 -05:00
struct amdgpu_ttm_tt * gtt = ( void * ) ttm ;
2017-07-31 09:35:24 -04:00
unsigned i ;
2019-03-28 10:15:26 -05:00
gtt - > last_set_pages = atomic_read ( & gtt - > mmu_invalidations ) ;
for ( i = 0 ; i < ttm - > num_pages ; + + i ) {
if ( ttm - > pages [ i ] )
put_page ( ttm - > pages [ i ] ) ;
2017-09-02 13:21:31 +02:00
ttm - > pages [ i ] = pages ? pages [ i ] : NULL ;
2019-03-28 10:15:26 -05:00
}
2017-07-31 09:35:24 -04:00
}
2019-03-28 10:15:03 -05:00
/**
* amdgpu_ttm_tt_mark_user_page - Mark pages as dirty
*
* Called while unpinning userptr pages
*/
void amdgpu_ttm_tt_mark_user_pages ( struct ttm_tt * ttm )
{
struct amdgpu_ttm_tt * gtt = ( void * ) ttm ;
unsigned i ;
for ( i = 0 ; i < ttm - > num_pages ; + + i ) {
struct page * page = ttm - > pages [ i ] ;
if ( ! page )
continue ;
if ( ! ( gtt - > userflags & AMDGPU_GEM_USERPTR_READONLY ) )
set_page_dirty ( page ) ;
mark_page_accessed ( page ) ;
}
}
2018-05-09 14:22:29 -04:00
/**
2018-07-26 14:08:03 +08:00
* amdgpu_ttm_tt_pin_userptr - prepare the sg table with the user pages
2018-05-09 14:22:29 -04:00
*
* Called by amdgpu_ttm_backend_bind ( )
* */
2016-02-23 12:36:59 +01:00
static int amdgpu_ttm_tt_pin_userptr ( struct ttm_tt * ttm )
{
2016-09-15 14:58:48 +02:00
struct amdgpu_device * adev = amdgpu_ttm_adev ( ttm - > bdev ) ;
2016-02-23 12:36:59 +01:00
struct amdgpu_ttm_tt * gtt = ( void * ) ttm ;
unsigned nents ;
int r ;
int write = ! ( gtt - > userflags & AMDGPU_GEM_USERPTR_READONLY ) ;
enum dma_data_direction direction = write ?
DMA_BIDIRECTIONAL : DMA_TO_DEVICE ;
2018-05-09 14:22:29 -04:00
/* Allocate an SG array and squash pages into it */
2015-04-20 16:55:21 -04:00
r = sg_alloc_table_from_pages ( ttm - > sg , ttm - > pages , ttm - > num_pages , 0 ,
ttm - > num_pages < < PAGE_SHIFT ,
GFP_KERNEL ) ;
if ( r )
goto release_sg ;
2018-05-09 14:22:29 -04:00
/* Map SG to device */
2015-04-20 16:55:21 -04:00
r = - ENOMEM ;
nents = dma_map_sg ( adev - > dev , ttm - > sg - > sgl , ttm - > sg - > nents , direction ) ;
if ( nents ! = ttm - > sg - > nents )
goto release_sg ;
2018-05-09 14:22:29 -04:00
/* convert SG to linear array of pages and dma addresses */
2015-04-20 16:55:21 -04:00
drm_prime_sg_to_page_addr_arrays ( ttm - > sg , ttm - > pages ,
gtt - > ttm . dma_address , ttm - > num_pages ) ;
return 0 ;
release_sg :
kfree ( ttm - > sg ) ;
return r ;
}
2018-05-09 14:22:29 -04:00
/**
* amdgpu_ttm_tt_unpin_userptr - Unpin and unmap userptr pages
*/
2015-04-20 16:55:21 -04:00
static void amdgpu_ttm_tt_unpin_userptr ( struct ttm_tt * ttm )
{
2016-09-15 14:58:48 +02:00
struct amdgpu_device * adev = amdgpu_ttm_adev ( ttm - > bdev ) ;
2015-04-20 16:55:21 -04:00
struct amdgpu_ttm_tt * gtt = ( void * ) ttm ;
int write = ! ( gtt - > userflags & AMDGPU_GEM_USERPTR_READONLY ) ;
enum dma_data_direction direction = write ?
DMA_BIDIRECTIONAL : DMA_TO_DEVICE ;
/* double check that we don't free the table twice */
if ( ! ttm - > sg - > sgl )
return ;
2018-05-09 14:22:29 -04:00
/* unmap the pages mapped to the device */
2015-04-20 16:55:21 -04:00
dma_unmap_sg ( adev - > dev , ttm - > sg - > sgl , ttm - > sg - > nents , direction ) ;
2019-03-28 10:15:26 -05:00
/* mark the pages as dirty */
amdgpu_ttm_tt_mark_user_pages ( ttm ) ;
drm/amdgpu: replace get_user_pages with HMM mirror helpers
Use HMM helper function hmm_vma_fault() to get physical pages backing
userptr and start CPU page table update track of those pages. Then use
hmm_vma_range_done() to check if those pages are updated before
amdgpu_cs_submit for gfx or before user queues are resumed for kfd.
If userptr pages are updated, for gfx, amdgpu_cs_ioctl will restart
from scratch, for kfd, restore worker is rescheduled to retry.
HMM simplify the CPU page table concurrent update check, so remove
guptasklock, mmu_invalidations, last_set_pages fields from
amdgpu_ttm_tt struct.
HMM does not pin the page (increase page ref count), so remove related
operations like release_pages(), put_page(), mark_page_dirty().
Signed-off-by: Philip Yang <Philip.Yang@amd.com>
Reviewed-by: Felix Kuehling <Felix.Kuehling@amd.com>
Reviewed-by: Christian König <christian.koenig@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
2018-12-13 15:35:28 -05:00
2019-03-28 10:15:26 -05:00
sg_free_table ( ttm - > sg ) ;
2015-04-20 16:55:21 -04:00
}
2018-05-14 12:15:27 -04:00
int amdgpu_ttm_gart_bind ( struct amdgpu_device * adev ,
struct ttm_buffer_object * tbo ,
uint64_t flags )
{
struct amdgpu_bo * abo = ttm_to_amdgpu_bo ( tbo ) ;
struct ttm_tt * ttm = tbo - > ttm ;
struct amdgpu_ttm_tt * gtt = ( void * ) ttm ;
int r ;
if ( abo - > flags & AMDGPU_GEM_CREATE_MQD_GFX9 ) {
uint64_t page_idx = 1 ;
r = amdgpu_gart_bind ( adev , gtt - > offset , page_idx ,
ttm - > pages , gtt - > ttm . dma_address , flags ) ;
if ( r )
goto gart_bind_fail ;
/* Patch mtype of the second part BO */
flags & = ~ AMDGPU_PTE_MTYPE_MASK ;
flags | = AMDGPU_PTE_MTYPE ( AMDGPU_MTYPE_NC ) ;
r = amdgpu_gart_bind ( adev ,
gtt - > offset + ( page_idx < < PAGE_SHIFT ) ,
ttm - > num_pages - page_idx ,
& ttm - > pages [ page_idx ] ,
& ( gtt - > ttm . dma_address [ page_idx ] ) , flags ) ;
} else {
r = amdgpu_gart_bind ( adev , gtt - > offset , ttm - > num_pages ,
ttm - > pages , gtt - > ttm . dma_address , flags ) ;
}
gart_bind_fail :
if ( r )
DRM_ERROR ( " failed to bind %lu pages at 0x%08llX \n " ,
ttm - > num_pages , gtt - > offset ) ;
return r ;
}
2018-05-09 14:22:29 -04:00
/**
* amdgpu_ttm_backend_bind - Bind GTT memory
*
* Called by ttm_tt_bind ( ) on behalf of ttm_bo_handle_move_mem ( ) .
* This handles binding GTT memory to the device address space .
*/
2015-04-20 16:55:21 -04:00
static int amdgpu_ttm_backend_bind ( struct ttm_tt * ttm ,
struct ttm_mem_reg * bo_mem )
{
2018-02-28 09:35:39 +01:00
struct amdgpu_device * adev = amdgpu_ttm_adev ( ttm - > bdev ) ;
2015-04-20 16:55:21 -04:00
struct amdgpu_ttm_tt * gtt = ( void * ) ttm ;
2017-08-22 21:04:47 +02:00
uint64_t flags ;
2017-08-09 13:30:46 +03:00
int r = 0 ;
2015-04-20 16:55:21 -04:00
2015-11-26 16:33:58 +08:00
if ( gtt - > userptr ) {
r = amdgpu_ttm_tt_pin_userptr ( ttm ) ;
if ( r ) {
DRM_ERROR ( " failed to pin userptr \n " ) ;
return r ;
}
}
2015-04-20 16:55:21 -04:00
if ( ! ttm - > num_pages ) {
WARN ( 1 , " nothing to bind %lu pages for mreg %p back %p! \n " ,
ttm - > num_pages , bo_mem , ttm ) ;
}
if ( bo_mem - > mem_type = = AMDGPU_PL_GDS | |
bo_mem - > mem_type = = AMDGPU_PL_GWS | |
bo_mem - > mem_type = = AMDGPU_PL_OA )
return - EINVAL ;
2017-10-27 14:17:09 +02:00
if ( ! amdgpu_gtt_mgr_has_gart_addr ( bo_mem ) ) {
gtt - > offset = AMDGPU_BO_INVALID_OFFSET ;
2017-08-22 21:04:47 +02:00
return 0 ;
2017-10-27 14:17:09 +02:00
}
2017-08-22 21:04:47 +02:00
2018-05-09 14:22:29 -04:00
/* compute PTE flags relevant to this BO memory */
2018-02-28 09:35:39 +01:00
flags = amdgpu_ttm_tt_pte_flags ( adev , ttm , bo_mem ) ;
2018-05-09 14:22:29 -04:00
/* bind pages into GART page tables */
2018-09-14 12:54:33 +02:00
gtt - > offset = ( u64 ) bo_mem - > start < < PAGE_SHIFT ;
2018-02-28 09:35:39 +01:00
r = amdgpu_gart_bind ( adev , gtt - > offset , ttm - > num_pages ,
2017-08-22 21:04:47 +02:00
ttm - > pages , gtt - > ttm . dma_address , flags ) ;
2017-10-16 16:50:32 +02:00
if ( r )
2017-08-22 21:04:47 +02:00
DRM_ERROR ( " failed to bind %lu pages at 0x%08llX \n " ,
ttm - > num_pages , gtt - > offset ) ;
2017-06-30 10:41:07 +02:00
return r ;
2016-09-05 17:00:57 +02:00
}
2018-05-09 14:22:29 -04:00
/**
* amdgpu_ttm_alloc_gart - Allocate GART memory for buffer object
*/
2017-10-27 15:43:14 +02:00
int amdgpu_ttm_alloc_gart ( struct ttm_buffer_object * bo )
2016-09-05 17:00:57 +02:00
{
2017-08-22 16:58:07 +02:00
struct amdgpu_device * adev = amdgpu_ttm_adev ( bo - > bdev ) ;
2017-04-12 15:33:00 +02:00
struct ttm_operation_ctx ctx = { false , false } ;
2017-10-26 17:54:12 +02:00
struct amdgpu_ttm_tt * gtt = ( void * ) bo - > ttm ;
2017-08-22 16:58:07 +02:00
struct ttm_mem_reg tmp ;
struct ttm_placement placement ;
struct ttm_place placements ;
2018-08-27 18:19:48 +02:00
uint64_t addr , flags ;
2016-09-05 17:00:57 +02:00
int r ;
2018-08-27 13:51:27 +02:00
if ( bo - > mem . start ! = AMDGPU_BO_INVALID_OFFSET )
2016-09-05 17:00:57 +02:00
return 0 ;
2018-08-27 18:19:48 +02:00
addr = amdgpu_gmc_agp_addr ( bo ) ;
if ( addr ! = AMDGPU_BO_INVALID_OFFSET ) {
bo - > mem . start = addr > > PAGE_SHIFT ;
} else {
2017-08-22 16:58:07 +02:00
2018-08-27 18:19:48 +02:00
/* allocate GART space */
tmp = bo - > mem ;
tmp . mm_node = NULL ;
placement . num_placement = 1 ;
placement . placement = & placements ;
placement . num_busy_placement = 1 ;
placement . busy_placement = & placements ;
placements . fpfn = 0 ;
placements . lpfn = adev - > gmc . gart_size > > PAGE_SHIFT ;
placements . flags = ( bo - > mem . placement & ~ TTM_PL_MASK_MEM ) |
TTM_PL_FLAG_TT ;
r = ttm_bo_mem_space ( bo , & placement , & tmp , & ctx ) ;
if ( unlikely ( r ) )
return r ;
2016-09-09 16:32:33 +02:00
2018-08-27 18:19:48 +02:00
/* compute PTE flags for this buffer object */
flags = amdgpu_ttm_tt_pte_flags ( adev , bo - > ttm , & tmp ) ;
2018-05-09 14:22:29 -04:00
2018-08-27 18:19:48 +02:00
/* Bind pages */
2018-09-14 12:54:33 +02:00
gtt - > offset = ( u64 ) tmp . start < < PAGE_SHIFT ;
2018-08-27 18:19:48 +02:00
r = amdgpu_ttm_gart_bind ( adev , bo , flags ) ;
if ( unlikely ( r ) ) {
ttm_bo_mem_put ( bo , & tmp ) ;
return r ;
}
ttm_bo_mem_put ( bo , & bo - > mem ) ;
bo - > mem = tmp ;
2017-10-26 17:54:12 +02:00
}
2017-08-22 16:58:07 +02:00
2017-10-26 17:54:12 +02:00
bo - > offset = ( bo - > mem . start < < PAGE_SHIFT ) +
bo - > bdev - > man [ bo - > mem . mem_type ] . gpu_offset ;
return 0 ;
2015-04-20 16:55:21 -04:00
}
2018-05-09 14:22:29 -04:00
/**
* amdgpu_ttm_recover_gart - Rebind GTT pages
*
* Called by amdgpu_gtt_mgr_recover ( ) from amdgpu_device_reset ( ) to
* rebind GTT pages during a GPU reset .
*/
2017-10-16 16:50:32 +02:00
int amdgpu_ttm_recover_gart ( struct ttm_buffer_object * tbo )
2016-08-30 16:36:25 +08:00
{
2017-10-16 16:50:32 +02:00
struct amdgpu_device * adev = amdgpu_ttm_adev ( tbo - > bdev ) ;
2017-04-27 17:14:57 +08:00
uint64_t flags ;
2016-08-30 16:36:25 +08:00
int r ;
2018-05-14 12:15:27 -04:00
if ( ! tbo - > ttm )
2017-10-16 16:50:32 +02:00
return 0 ;
2018-05-14 12:15:27 -04:00
flags = amdgpu_ttm_tt_pte_flags ( adev , tbo - > ttm , & tbo - > mem ) ;
r = amdgpu_ttm_gart_bind ( adev , tbo , flags ) ;
2017-10-16 16:50:32 +02:00
return r ;
2016-08-30 16:36:25 +08:00
}
2018-05-09 14:22:29 -04:00
/**
* amdgpu_ttm_backend_unbind - Unbind GTT mapped pages
*
* Called by ttm_tt_unbind ( ) on behalf of ttm_bo_move_ttm ( ) and
* ttm_tt_destroy ( ) .
*/
2015-04-20 16:55:21 -04:00
static int amdgpu_ttm_backend_unbind ( struct ttm_tt * ttm )
{
2018-02-28 09:35:39 +01:00
struct amdgpu_device * adev = amdgpu_ttm_adev ( ttm - > bdev ) ;
2015-04-20 16:55:21 -04:00
struct amdgpu_ttm_tt * gtt = ( void * ) ttm ;
2017-05-05 13:27:10 +08:00
int r ;
2015-04-20 16:55:21 -04:00
2018-05-09 14:22:29 -04:00
/* if the pages have userptr pinning then clear that first */
2016-09-22 14:19:50 +02:00
if ( gtt - > userptr )
amdgpu_ttm_tt_unpin_userptr ( ttm ) ;
2017-10-27 14:17:09 +02:00
if ( gtt - > offset = = AMDGPU_BO_INVALID_OFFSET )
2016-09-09 15:39:08 +02:00
return 0 ;
2015-04-20 16:55:21 -04:00
/* unbind shouldn't be done for GDS/GWS/OA in ttm_bo_clean_mm */
2018-02-28 09:35:39 +01:00
r = amdgpu_gart_unbind ( adev , gtt - > offset , ttm - > num_pages ) ;
2017-10-16 16:50:32 +02:00
if ( r )
2017-05-05 13:27:10 +08:00
DRM_ERROR ( " failed to unbind %lu pages at 0x%08llX \n " ,
gtt - > ttm . ttm . num_pages , gtt - > offset ) ;
return r ;
2015-04-20 16:55:21 -04:00
}
static void amdgpu_ttm_backend_destroy ( struct ttm_tt * ttm )
{
struct amdgpu_ttm_tt * gtt = ( void * ) ttm ;
2018-03-23 15:32:29 -04:00
if ( gtt - > usertask )
put_task_struct ( gtt - > usertask ) ;
2015-04-20 16:55:21 -04:00
ttm_dma_tt_fini ( & gtt - > ttm ) ;
kfree ( gtt ) ;
}
static struct ttm_backend_func amdgpu_backend_func = {
. bind = & amdgpu_ttm_backend_bind ,
. unbind = & amdgpu_ttm_backend_unbind ,
. destroy = & amdgpu_ttm_backend_destroy ,
} ;
2018-05-09 14:22:29 -04:00
/**
* amdgpu_ttm_tt_create - Create a ttm_tt object for a given BO
*
* @ bo : The buffer object to create a GTT ttm_tt object around
*
* Called by ttm_tt_create ( ) .
*/
2018-02-22 10:18:14 +01:00
static struct ttm_tt * amdgpu_ttm_tt_create ( struct ttm_buffer_object * bo ,
uint32_t page_flags )
2015-04-20 16:55:21 -04:00
{
struct amdgpu_device * adev ;
struct amdgpu_ttm_tt * gtt ;
2018-02-22 10:18:14 +01:00
adev = amdgpu_ttm_adev ( bo - > bdev ) ;
2015-04-20 16:55:21 -04:00
gtt = kzalloc ( sizeof ( struct amdgpu_ttm_tt ) , GFP_KERNEL ) ;
if ( gtt = = NULL ) {
return NULL ;
}
gtt - > ttm . ttm . func = & amdgpu_backend_func ;
2018-05-09 14:22:29 -04:00
/* allocate space for the uninitialized page entries */
2018-02-22 10:18:14 +01:00
if ( ttm_sg_tt_init ( & gtt - > ttm , bo , page_flags ) ) {
2015-04-20 16:55:21 -04:00
kfree ( gtt ) ;
return NULL ;
}
return & gtt - > ttm . ttm ;
}
2018-05-09 14:22:29 -04:00
/**
* amdgpu_ttm_tt_populate - Map GTT pages visible to the device
*
* Map the pages of a ttm_tt object to an address space visible
* to the underlying device .
*/
2017-12-21 17:42:50 +08:00
static int amdgpu_ttm_tt_populate ( struct ttm_tt * ttm ,
struct ttm_operation_ctx * ctx )
2015-04-20 16:55:21 -04:00
{
2017-07-31 09:35:24 -04:00
struct amdgpu_device * adev = amdgpu_ttm_adev ( ttm - > bdev ) ;
2015-04-20 16:55:21 -04:00
struct amdgpu_ttm_tt * gtt = ( void * ) ttm ;
bool slave = ! ! ( ttm - > page_flags & TTM_PAGE_FLAG_SG ) ;
2018-05-09 14:22:29 -04:00
/* user pages are bound by amdgpu_ttm_tt_pin_userptr() */
2015-04-20 16:55:21 -04:00
if ( gtt & & gtt - > userptr ) {
2015-06-26 13:28:50 +05:30
ttm - > sg = kzalloc ( sizeof ( struct sg_table ) , GFP_KERNEL ) ;
2015-04-20 16:55:21 -04:00
if ( ! ttm - > sg )
return - ENOMEM ;
ttm - > page_flags | = TTM_PAGE_FLAG_SG ;
ttm - > state = tt_unbound ;
return 0 ;
}
if ( slave & & ttm - > sg ) {
drm_prime_sg_to_page_addr_arrays ( ttm - > sg , ttm - > pages ,
2018-02-23 16:08:51 +01:00
gtt - > ttm . dma_address ,
ttm - > num_pages ) ;
2015-04-20 16:55:21 -04:00
ttm - > state = tt_unbound ;
2017-09-18 08:10:00 -04:00
return 0 ;
2015-04-20 16:55:21 -04:00
}
# ifdef CONFIG_SWIOTLB
2018-02-09 10:44:09 +08:00
if ( adev - > need_swiotlb & & swiotlb_nr_tbl ( ) ) {
2017-12-21 17:42:50 +08:00
return ttm_dma_populate ( & gtt - > ttm , adev - > dev , ctx ) ;
2015-04-20 16:55:21 -04:00
}
# endif
2018-05-09 14:22:29 -04:00
/* fall back to generic helper to populate the page array
* and map them to the device */
2017-12-21 17:42:50 +08:00
return ttm_populate_and_map_pages ( adev - > dev , & gtt - > ttm , ctx ) ;
2015-04-20 16:55:21 -04:00
}
2018-05-09 14:22:29 -04:00
/**
* amdgpu_ttm_tt_unpopulate - unmap GTT pages and unpopulate page arrays
*
* Unmaps pages of a ttm_tt object from the device address space and
* unpopulates the page array backing it .
*/
2015-04-20 16:55:21 -04:00
static void amdgpu_ttm_tt_unpopulate ( struct ttm_tt * ttm )
{
struct amdgpu_device * adev ;
struct amdgpu_ttm_tt * gtt = ( void * ) ttm ;
bool slave = ! ! ( ttm - > page_flags & TTM_PAGE_FLAG_SG ) ;
if ( gtt & & gtt - > userptr ) {
2017-09-02 13:21:31 +02:00
amdgpu_ttm_tt_set_user_pages ( ttm , NULL ) ;
2015-04-20 16:55:21 -04:00
kfree ( ttm - > sg ) ;
ttm - > page_flags & = ~ TTM_PAGE_FLAG_SG ;
return ;
}
if ( slave )
return ;
2016-09-15 14:58:48 +02:00
adev = amdgpu_ttm_adev ( ttm - > bdev ) ;
2015-04-20 16:55:21 -04:00
# ifdef CONFIG_SWIOTLB
2018-02-09 10:44:09 +08:00
if ( adev - > need_swiotlb & & swiotlb_nr_tbl ( ) ) {
2015-04-20 16:55:21 -04:00
ttm_dma_unpopulate ( & gtt - > ttm , adev - > dev ) ;
return ;
}
# endif
2018-05-09 14:22:29 -04:00
/* fall back to generic helper to unmap and unpopulate array */
2017-08-18 10:05:48 -04:00
ttm_unmap_and_unpopulate_pages ( adev - > dev , & gtt - > ttm ) ;
2015-04-20 16:55:21 -04:00
}
2018-05-09 14:22:29 -04:00
/**
2018-07-26 14:08:03 +08:00
* amdgpu_ttm_tt_set_userptr - Initialize userptr GTT ttm_tt for the current
* task
2018-05-09 14:22:29 -04:00
*
* @ ttm : The ttm_tt object to bind this userptr object to
* @ addr : The address in the current tasks VM space to use
* @ flags : Requirements of userptr object .
*
* Called by amdgpu_gem_userptr_ioctl ( ) to bind userptr pages
* to current task
*/
2015-04-20 16:55:21 -04:00
int amdgpu_ttm_tt_set_userptr ( struct ttm_tt * ttm , uint64_t addr ,
uint32_t flags )
{
struct amdgpu_ttm_tt * gtt = ( void * ) ttm ;
if ( gtt = = NULL )
return - EINVAL ;
gtt - > userptr = addr ;
gtt - > userflags = flags ;
2018-03-23 15:32:29 -04:00
if ( gtt - > usertask )
put_task_struct ( gtt - > usertask ) ;
gtt - > usertask = current - > group_leader ;
get_task_struct ( gtt - > usertask ) ;
2019-03-28 10:15:26 -05:00
spin_lock_init ( & gtt - > guptasklock ) ;
INIT_LIST_HEAD ( & gtt - > guptasks ) ;
atomic_set ( & gtt - > mmu_invalidations , 0 ) ;
gtt - > last_set_pages = 0 ;
2015-04-20 16:55:21 -04:00
return 0 ;
}
2018-05-09 14:22:29 -04:00
/**
* amdgpu_ttm_tt_get_usermm - Return memory manager for ttm_tt object
*/
2016-02-08 11:08:35 +01:00
struct mm_struct * amdgpu_ttm_tt_get_usermm ( struct ttm_tt * ttm )
2015-04-20 16:55:21 -04:00
{
struct amdgpu_ttm_tt * gtt = ( void * ) ttm ;
if ( gtt = = NULL )
2016-02-08 11:08:35 +01:00
return NULL ;
2015-04-20 16:55:21 -04:00
2018-03-23 15:32:29 -04:00
if ( gtt - > usertask = = NULL )
return NULL ;
return gtt - > usertask - > mm ;
2015-04-20 16:55:21 -04:00
}
2018-05-09 14:22:29 -04:00
/**
2018-07-26 14:08:03 +08:00
* amdgpu_ttm_tt_affect_userptr - Determine if a ttm_tt object lays inside an
* address range for the current task .
2018-05-09 14:22:29 -04:00
*
*/
2016-02-08 10:57:22 +01:00
bool amdgpu_ttm_tt_affect_userptr ( struct ttm_tt * ttm , unsigned long start ,
unsigned long end )
{
struct amdgpu_ttm_tt * gtt = ( void * ) ttm ;
2019-03-28 10:15:26 -05:00
struct amdgpu_ttm_gup_task_list * entry ;
2016-02-08 10:57:22 +01:00
unsigned long size ;
2016-03-03 14:24:57 +01:00
if ( gtt = = NULL | | ! gtt - > userptr )
2016-02-08 10:57:22 +01:00
return false ;
2018-05-09 14:22:29 -04:00
/* Return false if no part of the ttm_tt object lies within
* the range
*/
2016-02-08 10:57:22 +01:00
size = ( unsigned long ) gtt - > ttm . ttm . num_pages * PAGE_SIZE ;
if ( gtt - > userptr > end | | gtt - > userptr + size < = start )
return false ;
2019-03-28 10:15:26 -05:00
/* Search the lists of tasks that hold this mapping and see
* if current is one of them . If it is return false .
*/
spin_lock ( & gtt - > guptasklock ) ;
list_for_each_entry ( entry , & gtt - > guptasks , list ) {
if ( entry - > task = = current ) {
spin_unlock ( & gtt - > guptasklock ) ;
return false ;
}
}
spin_unlock ( & gtt - > guptasklock ) ;
atomic_inc ( & gtt - > mmu_invalidations ) ;
2016-02-08 10:57:22 +01:00
return true ;
}
2018-05-09 14:22:29 -04:00
/**
2019-03-28 10:15:26 -05:00
* amdgpu_ttm_tt_userptr_invalidated - Has the ttm_tt object been invalidated ?
*/
bool amdgpu_ttm_tt_userptr_invalidated ( struct ttm_tt * ttm ,
int * last_invalidated )
{
struct amdgpu_ttm_tt * gtt = ( void * ) ttm ;
int prev_invalidated = * last_invalidated ;
* last_invalidated = atomic_read ( & gtt - > mmu_invalidations ) ;
return prev_invalidated ! = * last_invalidated ;
}
/**
* amdgpu_ttm_tt_userptr_needs_pages - Have the pages backing this ttm_tt object
* been invalidated since the last time they ' ve been set ?
2018-05-09 14:22:29 -04:00
*/
2019-03-28 10:15:26 -05:00
bool amdgpu_ttm_tt_userptr_needs_pages ( struct ttm_tt * ttm )
2017-09-05 14:30:05 +02:00
{
struct amdgpu_ttm_tt * gtt = ( void * ) ttm ;
if ( gtt = = NULL | | ! gtt - > userptr )
return false ;
2019-03-28 10:15:26 -05:00
return atomic_read ( & gtt - > mmu_invalidations ) ! = gtt - > last_set_pages ;
2017-09-05 14:30:05 +02:00
}
2018-05-09 14:22:29 -04:00
/**
* amdgpu_ttm_tt_is_readonly - Is the ttm_tt object read only ?
*/
2015-04-20 16:55:21 -04:00
bool amdgpu_ttm_tt_is_readonly ( struct ttm_tt * ttm )
{
struct amdgpu_ttm_tt * gtt = ( void * ) ttm ;
if ( gtt = = NULL )
return false ;
return ! ! ( gtt - > userflags & AMDGPU_GEM_USERPTR_READONLY ) ;
}
2018-05-09 14:22:29 -04:00
/**
2018-08-22 14:11:19 +02:00
* amdgpu_ttm_tt_pde_flags - Compute PDE flags for ttm_tt object
2018-05-09 14:22:29 -04:00
*
* @ ttm : The ttm_tt object to compute the flags for
* @ mem : The memory registry backing this ttm_tt object
2018-08-22 14:11:19 +02:00
*
* Figure out the flags to use for a VM PDE ( Page Directory Entry ) .
2018-05-09 14:22:29 -04:00
*/
2018-08-22 14:11:19 +02:00
uint64_t amdgpu_ttm_tt_pde_flags ( struct ttm_tt * ttm , struct ttm_mem_reg * mem )
2015-04-20 16:55:21 -04:00
{
2016-09-21 16:19:19 +08:00
uint64_t flags = 0 ;
2015-04-20 16:55:21 -04:00
if ( mem & & mem - > mem_type ! = TTM_PL_SYSTEM )
flags | = AMDGPU_PTE_VALID ;
2015-12-04 13:32:55 +01:00
if ( mem & & mem - > mem_type = = TTM_PL_TT ) {
2015-04-20 16:55:21 -04:00
flags | = AMDGPU_PTE_SYSTEM ;
2015-12-04 13:32:55 +01:00
if ( ttm - > caching_state = = tt_cached )
flags | = AMDGPU_PTE_SNOOPED ;
}
2015-04-20 16:55:21 -04:00
2018-08-22 14:11:19 +02:00
return flags ;
}
/**
* amdgpu_ttm_tt_pte_flags - Compute PTE flags for ttm_tt object
*
* @ ttm : The ttm_tt object to compute the flags for
* @ mem : The memory registry backing this ttm_tt object
* Figure out the flags to use for a VM PTE ( Page Table Entry ) .
*/
uint64_t amdgpu_ttm_tt_pte_flags ( struct amdgpu_device * adev , struct ttm_tt * ttm ,
struct ttm_mem_reg * mem )
{
uint64_t flags = amdgpu_ttm_tt_pde_flags ( ttm , mem ) ;
2017-02-14 12:31:36 -05:00
flags | = adev - > gart . gart_pte_flags ;
2015-04-20 16:55:21 -04:00
flags | = AMDGPU_PTE_READABLE ;
if ( ! amdgpu_ttm_tt_is_readonly ( ttm ) )
flags | = AMDGPU_PTE_WRITEABLE ;
return flags ;
}
2018-05-09 14:22:29 -04:00
/**
2018-07-26 14:08:03 +08:00
* amdgpu_ttm_bo_eviction_valuable - Check to see if we can evict a buffer
* object .
2018-05-09 14:22:29 -04:00
*
2018-07-26 14:08:03 +08:00
* Return true if eviction is sensible . Called by ttm_mem_evict_first ( ) on
* behalf of ttm_bo_mem_force_space ( ) which tries to evict buffer objects until
* it can find space for a new object and by ttm_bo_force_list_clean ( ) which is
2018-05-09 14:22:29 -04:00
* used to clean out a memory space .
*/
2016-10-19 14:44:22 +02:00
static bool amdgpu_ttm_bo_eviction_valuable ( struct ttm_buffer_object * bo ,
const struct ttm_place * place )
{
2017-04-20 12:11:47 +02:00
unsigned long num_pages = bo - > mem . num_pages ;
struct drm_mm_node * node = bo - > mem . mm_node ;
2018-02-06 20:32:35 -05:00
struct reservation_object_list * flist ;
struct dma_fence * f ;
int i ;
2018-11-07 13:55:01 +01:00
/* Don't evict VM page tables while they are busy, otherwise we can't
* cleanly handle page faults .
*/
if ( bo - > type = = ttm_bo_type_kernel & &
! reservation_object_test_signaled_rcu ( bo - > resv , true ) )
return false ;
2018-02-06 20:32:35 -05:00
/* If bo is a KFD BO, check if the bo belongs to the current process.
* If true , then return false as any KFD process needs all its BOs to
* be resident to run successfully
*/
flist = reservation_object_get_list ( bo - > resv ) ;
if ( flist ) {
for ( i = 0 ; i < flist - > shared_count ; + + i ) {
f = rcu_dereference_protected ( flist - > shared [ i ] ,
reservation_object_held ( bo - > resv ) ) ;
if ( amdkfd_fence_check_mm ( f , current - > mm ) )
return false ;
}
}
2016-10-19 14:44:22 +02:00
2017-04-20 12:11:47 +02:00
switch ( bo - > mem . mem_type ) {
case TTM_PL_TT :
return true ;
2016-10-19 14:44:22 +02:00
2017-04-20 12:11:47 +02:00
case TTM_PL_VRAM :
2016-10-19 14:44:22 +02:00
/* Check each drm MM node individually */
while ( num_pages ) {
if ( place - > fpfn < ( node - > start + node - > size ) & &
! ( place - > lpfn & & place - > lpfn < = node - > start ) )
return true ;
num_pages - = node - > size ;
+ + node ;
}
2017-11-02 13:14:27 +08:00
return false ;
2016-10-19 14:44:22 +02:00
2017-04-20 12:11:47 +02:00
default :
break ;
2016-10-19 14:44:22 +02:00
}
return ttm_bo_eviction_valuable ( bo , place ) ;
}
2018-05-09 14:22:29 -04:00
/**
2018-07-26 14:08:03 +08:00
* amdgpu_ttm_access_memory - Read or Write memory that backs a buffer object .
2018-05-09 14:22:29 -04:00
*
* @ bo : The buffer object to read / write
* @ offset : Offset into buffer object
* @ buf : Secondary buffer to write / read from
* @ len : Length in bytes of access
* @ write : true if writing
*
* This is used to access VRAM that backs a buffer object via MMIO
* access for debugging purposes .
*/
2017-07-03 14:18:27 -04:00
static int amdgpu_ttm_access_memory ( struct ttm_buffer_object * bo ,
unsigned long offset ,
void * buf , int len , int write )
{
2017-09-15 21:05:19 -04:00
struct amdgpu_bo * abo = ttm_to_amdgpu_bo ( bo ) ;
2017-07-03 14:18:27 -04:00
struct amdgpu_device * adev = amdgpu_ttm_adev ( abo - > tbo . bdev ) ;
2017-10-06 17:36:35 -04:00
struct drm_mm_node * nodes ;
2017-07-03 14:18:27 -04:00
uint32_t value = 0 ;
int ret = 0 ;
uint64_t pos ;
unsigned long flags ;
if ( bo - > mem . mem_type ! = TTM_PL_VRAM )
return - EIO ;
2017-10-06 17:36:35 -04:00
nodes = amdgpu_find_mm_node ( & abo - > tbo . mem , & offset ) ;
2017-07-03 14:18:27 -04:00
pos = ( nodes - > start < < PAGE_SHIFT ) + offset ;
2018-01-12 14:52:22 +01:00
while ( len & & pos < adev - > gmc . mc_vram_size ) {
2017-07-03 14:18:27 -04:00
uint64_t aligned_pos = pos & ~ ( uint64_t ) 3 ;
uint32_t bytes = 4 - ( pos & 3 ) ;
uint32_t shift = ( pos & 3 ) * 8 ;
uint32_t mask = 0xffffffff < < shift ;
if ( len < bytes ) {
mask & = 0xffffffff > > ( bytes - len ) * 8 ;
bytes = len ;
}
spin_lock_irqsave ( & adev - > mmio_idx_lock , flags ) ;
2017-09-14 08:57:26 -04:00
WREG32_NO_KIQ ( mmMM_INDEX , ( ( uint32_t ) aligned_pos ) | 0x80000000 ) ;
WREG32_NO_KIQ ( mmMM_INDEX_HI , aligned_pos > > 31 ) ;
2017-07-03 14:18:27 -04:00
if ( ! write | | mask ! = 0xffffffff )
2017-09-14 08:57:26 -04:00
value = RREG32_NO_KIQ ( mmMM_DATA ) ;
2017-07-03 14:18:27 -04:00
if ( write ) {
value & = ~ mask ;
value | = ( * ( uint32_t * ) buf < < shift ) & mask ;
2017-09-14 08:57:26 -04:00
WREG32_NO_KIQ ( mmMM_DATA , value ) ;
2017-07-03 14:18:27 -04:00
}
spin_unlock_irqrestore ( & adev - > mmio_idx_lock , flags ) ;
if ( ! write ) {
value = ( value & mask ) > > shift ;
memcpy ( buf , & value , bytes ) ;
}
ret + = bytes ;
buf = ( uint8_t * ) buf + bytes ;
pos + = bytes ;
len - = bytes ;
if ( pos > = ( nodes - > start + nodes - > size ) < < PAGE_SHIFT ) {
+ + nodes ;
pos = ( nodes - > start < < PAGE_SHIFT ) ;
}
}
return ret ;
}
2015-04-20 16:55:21 -04:00
static struct ttm_bo_driver amdgpu_bo_driver = {
. ttm_tt_create = & amdgpu_ttm_tt_create ,
. ttm_tt_populate = & amdgpu_ttm_tt_populate ,
. ttm_tt_unpopulate = & amdgpu_ttm_tt_unpopulate ,
. invalidate_caches = & amdgpu_invalidate_caches ,
. init_mem_type = & amdgpu_init_mem_type ,
2016-10-19 14:44:22 +02:00
. eviction_valuable = amdgpu_ttm_bo_eviction_valuable ,
2015-04-20 16:55:21 -04:00
. evict_flags = & amdgpu_evict_flags ,
. move = & amdgpu_bo_move ,
. verify_access = & amdgpu_verify_access ,
. move_notify = & amdgpu_bo_move_notify ,
. fault_reserve_notify = & amdgpu_bo_fault_reserve_notify ,
. io_mem_reserve = & amdgpu_ttm_io_mem_reserve ,
. io_mem_free = & amdgpu_ttm_io_mem_free ,
2017-03-29 11:16:05 +02:00
. io_mem_pfn = amdgpu_ttm_io_mem_pfn ,
2019-01-10 15:49:54 +08:00
. access_memory = & amdgpu_ttm_access_memory ,
. del_from_lru_notify = & amdgpu_vm_del_from_lru_notify
2015-04-20 16:55:21 -04:00
} ;
2017-12-14 16:39:02 -05:00
/*
* Firmware Reservation functions
*/
/**
* amdgpu_ttm_fw_reserve_vram_fini - free fw reserved vram
*
* @ adev : amdgpu_device pointer
*
* free fw reserved vram if it has been reserved .
*/
static void amdgpu_ttm_fw_reserve_vram_fini ( struct amdgpu_device * adev )
{
amdgpu_bo_free_kernel ( & adev - > fw_vram_usage . reserved_bo ,
NULL , & adev - > fw_vram_usage . va ) ;
}
/**
* amdgpu_ttm_fw_reserve_vram_init - create bo vram reservation from fw
*
* @ adev : amdgpu_device pointer
*
* create bo vram reservation from fw .
*/
static int amdgpu_ttm_fw_reserve_vram_init ( struct amdgpu_device * adev )
{
struct ttm_operation_ctx ctx = { false , false } ;
2018-04-16 18:27:50 +08:00
struct amdgpu_bo_param bp ;
2017-12-14 16:39:02 -05:00
int r = 0 ;
int i ;
2018-01-12 14:52:22 +01:00
u64 vram_size = adev - > gmc . visible_vram_size ;
2017-12-14 16:39:02 -05:00
u64 offset = adev - > fw_vram_usage . start_offset ;
u64 size = adev - > fw_vram_usage . size ;
struct amdgpu_bo * bo ;
2018-04-16 18:27:50 +08:00
memset ( & bp , 0 , sizeof ( bp ) ) ;
bp . size = adev - > fw_vram_usage . size ;
bp . byte_align = PAGE_SIZE ;
bp . domain = AMDGPU_GEM_DOMAIN_VRAM ;
bp . flags = AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED |
AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS ;
bp . type = ttm_bo_type_kernel ;
bp . resv = NULL ;
2017-12-14 16:39:02 -05:00
adev - > fw_vram_usage . va = NULL ;
adev - > fw_vram_usage . reserved_bo = NULL ;
if ( adev - > fw_vram_usage . size > 0 & &
adev - > fw_vram_usage . size < = vram_size ) {
2018-04-16 18:27:50 +08:00
r = amdgpu_bo_create ( adev , & bp ,
2018-03-14 14:48:17 -05:00
& adev - > fw_vram_usage . reserved_bo ) ;
2017-12-14 16:39:02 -05:00
if ( r )
goto error_create ;
r = amdgpu_bo_reserve ( adev - > fw_vram_usage . reserved_bo , false ) ;
if ( r )
goto error_reserve ;
/* remove the original mem node and create a new one at the
* request position
*/
bo = adev - > fw_vram_usage . reserved_bo ;
offset = ALIGN ( offset , PAGE_SIZE ) ;
for ( i = 0 ; i < bo - > placement . num_placement ; + + i ) {
bo - > placements [ i ] . fpfn = offset > > PAGE_SHIFT ;
bo - > placements [ i ] . lpfn = ( offset + size ) > > PAGE_SHIFT ;
}
ttm_bo_mem_put ( & bo - > tbo , & bo - > tbo . mem ) ;
r = ttm_bo_mem_space ( & bo - > tbo , & bo - > placement ,
& bo - > tbo . mem , & ctx ) ;
if ( r )
goto error_pin ;
r = amdgpu_bo_pin_restricted ( adev - > fw_vram_usage . reserved_bo ,
AMDGPU_GEM_DOMAIN_VRAM ,
adev - > fw_vram_usage . start_offset ,
( adev - > fw_vram_usage . start_offset +
2018-06-25 12:51:14 +08:00
adev - > fw_vram_usage . size ) ) ;
2017-12-14 16:39:02 -05:00
if ( r )
goto error_pin ;
r = amdgpu_bo_kmap ( adev - > fw_vram_usage . reserved_bo ,
& adev - > fw_vram_usage . va ) ;
if ( r )
goto error_kmap ;
amdgpu_bo_unreserve ( adev - > fw_vram_usage . reserved_bo ) ;
}
return r ;
error_kmap :
amdgpu_bo_unpin ( adev - > fw_vram_usage . reserved_bo ) ;
error_pin :
amdgpu_bo_unreserve ( adev - > fw_vram_usage . reserved_bo ) ;
error_reserve :
amdgpu_bo_unref ( & adev - > fw_vram_usage . reserved_bo ) ;
error_create :
adev - > fw_vram_usage . va = NULL ;
adev - > fw_vram_usage . reserved_bo = NULL ;
return r ;
}
2018-05-09 14:22:29 -04:00
/**
2018-07-26 14:08:03 +08:00
* amdgpu_ttm_init - Init the memory management ( ttm ) as well as various
* gtt / vram related fields .
2018-05-09 14:22:29 -04:00
*
* This initializes all of the memory space pools that the TTM layer
* will need such as the GTT space ( system memory mapped to the device ) ,
* VRAM ( on - board memory ) , and on - chip memories ( GDS , GWS , OA ) which
* can be mapped per VMID .
*/
2015-04-20 16:55:21 -04:00
int amdgpu_ttm_init ( struct amdgpu_device * adev )
{
2017-07-07 13:17:45 +02:00
uint64_t gtt_size ;
2015-04-20 16:55:21 -04:00
int r ;
2017-06-27 22:33:17 -04:00
u64 vis_vram_limit ;
2015-04-20 16:55:21 -04:00
2018-10-19 16:55:26 +02:00
mutex_init ( & adev - > mman . gtt_window_lock ) ;
2015-04-20 16:55:21 -04:00
/* No others user of address space so set it to 0 */
r = ttm_bo_device_init ( & adev - > mman . bdev ,
& amdgpu_bo_driver ,
adev - > ddev - > anon_inode - > i_mapping ,
adev - > need_dma32 ) ;
if ( r ) {
DRM_ERROR ( " failed initializing buffer object driver(%d). \n " , r ) ;
return r ;
}
adev - > mman . initialized = true ;
2018-01-16 10:06:36 -05:00
/* We opt to avoid OOM on system pages allocations */
adev - > mman . bdev . no_retry = true ;
2018-05-09 14:22:29 -04:00
/* Initialize VRAM pool with all of VRAM divided into pages */
2015-04-20 16:55:21 -04:00
r = ttm_bo_init_mm ( & adev - > mman . bdev , TTM_PL_VRAM ,
2018-01-12 14:52:22 +01:00
adev - > gmc . real_vram_size > > PAGE_SHIFT ) ;
2015-04-20 16:55:21 -04:00
if ( r ) {
DRM_ERROR ( " Failed initializing VRAM heap. \n " ) ;
return r ;
}
2017-06-27 22:33:17 -04:00
/* Reduce size of CPU-visible VRAM if requested */
vis_vram_limit = ( u64 ) amdgpu_vis_vram_limit * 1024 * 1024 ;
if ( amdgpu_vis_vram_limit > 0 & &
2018-01-12 14:52:22 +01:00
vis_vram_limit < = adev - > gmc . visible_vram_size )
adev - > gmc . visible_vram_size = vis_vram_limit ;
2017-06-27 22:33:17 -04:00
2015-04-20 16:55:21 -04:00
/* Change the size here instead of the init above so only lpfn is affected */
2018-03-01 11:01:52 +01:00
amdgpu_ttm_set_buffer_funcs_status ( adev , false ) ;
2018-02-27 10:01:59 -05:00
# ifdef CONFIG_64BIT
adev - > mman . aper_base_kaddr = ioremap_wc ( adev - > gmc . aper_base ,
adev - > gmc . visible_vram_size ) ;
# endif
2015-04-20 16:55:21 -04:00
2017-09-29 14:41:57 +08:00
/*
* The reserved vram for firmware must be pinned to the specified
* place on the VRAM , so reserve it early .
*/
2017-12-14 16:39:02 -05:00
r = amdgpu_ttm_fw_reserve_vram_init ( adev ) ;
2017-09-29 14:41:57 +08:00
if ( r ) {
return r ;
}
2018-05-09 14:22:29 -04:00
/* allocate memory as required for VGA
* This is used for VGA emulation and pre - OS scanout buffers to
* avoid display artifacts while transitioning between pre - OS
* and driver . */
2018-09-14 21:06:50 +02:00
r = amdgpu_bo_create_kernel ( adev , adev - > gmc . stolen_size , PAGE_SIZE ,
AMDGPU_GEM_DOMAIN_VRAM ,
& adev - > stolen_vga_memory ,
NULL , NULL ) ;
if ( r )
return r ;
2015-04-20 16:55:21 -04:00
DRM_INFO ( " amdgpu: %uM of VRAM memory ready \n " ,
2018-01-12 14:52:22 +01:00
( unsigned ) ( adev - > gmc . real_vram_size / ( 1024 * 1024 ) ) ) ;
2017-07-07 13:17:45 +02:00
2018-05-09 14:22:29 -04:00
/* Compute GTT size, either bsaed on 3/4th the size of RAM size
* or whatever the user passed on module init */
2017-11-10 19:05:13 +08:00
if ( amdgpu_gtt_size = = - 1 ) {
struct sysinfo si ;
si_meminfo ( & si ) ;
2017-12-15 12:09:16 -05:00
gtt_size = min ( max ( ( AMDGPU_DEFAULT_GTT_SIZE_MB < < 20 ) ,
2018-01-12 14:52:22 +01:00
adev - > gmc . mc_vram_size ) ,
2017-12-15 12:09:16 -05:00
( ( uint64_t ) si . totalram * si . mem_unit * 3 / 4 ) ) ;
}
else
2017-07-07 13:17:45 +02:00
gtt_size = ( uint64_t ) amdgpu_gtt_size < < 20 ;
2018-05-09 14:22:29 -04:00
/* Initialize GTT memory pool */
2017-07-07 13:17:45 +02:00
r = ttm_bo_init_mm ( & adev - > mman . bdev , TTM_PL_TT , gtt_size > > PAGE_SHIFT ) ;
2015-04-20 16:55:21 -04:00
if ( r ) {
DRM_ERROR ( " Failed initializing GTT heap. \n " ) ;
return r ;
}
DRM_INFO ( " amdgpu: %uM of GTT memory ready. \n " ,
2017-07-07 13:17:45 +02:00
( unsigned ) ( gtt_size / ( 1024 * 1024 ) ) ) ;
2015-04-20 16:55:21 -04:00
2018-05-09 14:22:29 -04:00
/* Initialize various on-chip memory pools */
2018-09-14 20:59:27 +02:00
r = ttm_bo_init_mm ( & adev - > mman . bdev , AMDGPU_PL_GDS ,
2019-05-10 19:56:30 +02:00
adev - > gds . gds_size ) ;
2018-09-14 20:59:27 +02:00
if ( r ) {
DRM_ERROR ( " Failed initializing GDS heap. \n " ) ;
return r ;
2015-04-20 16:55:21 -04:00
}
2018-09-14 20:59:27 +02:00
r = ttm_bo_init_mm ( & adev - > mman . bdev , AMDGPU_PL_GWS ,
2019-05-10 19:56:30 +02:00
adev - > gds . gws_size ) ;
2018-09-14 20:59:27 +02:00
if ( r ) {
DRM_ERROR ( " Failed initializing gws heap. \n " ) ;
return r ;
2015-04-20 16:55:21 -04:00
}
2018-09-14 20:59:27 +02:00
r = ttm_bo_init_mm ( & adev - > mman . bdev , AMDGPU_PL_OA ,
2019-05-10 19:56:30 +02:00
adev - > gds . oa_size ) ;
2018-09-14 20:59:27 +02:00
if ( r ) {
DRM_ERROR ( " Failed initializing oa heap. \n " ) ;
return r ;
2015-04-20 16:55:21 -04:00
}
2018-05-09 14:22:29 -04:00
/* Register debugfs entries for amdgpu_ttm */
2015-04-20 16:55:21 -04:00
r = amdgpu_ttm_debugfs_init ( adev ) ;
if ( r ) {
DRM_ERROR ( " Failed to init debugfs \n " ) ;
return r ;
}
return 0 ;
}
2018-05-09 14:22:29 -04:00
/**
2018-07-26 14:08:03 +08:00
* amdgpu_ttm_late_init - Handle any late initialization for amdgpu_ttm
2018-05-09 14:22:29 -04:00
*/
2018-04-06 14:54:10 -05:00
void amdgpu_ttm_late_init ( struct amdgpu_device * adev )
{
2018-05-09 14:22:29 -04:00
/* return the VGA stolen memory (if any) back to VRAM */
2018-04-06 14:54:10 -05:00
amdgpu_bo_free_kernel ( & adev - > stolen_vga_memory , NULL , NULL ) ;
}
2018-05-09 14:22:29 -04:00
/**
* amdgpu_ttm_fini - De - initialize the TTM memory pools
*/
2015-04-20 16:55:21 -04:00
void amdgpu_ttm_fini ( struct amdgpu_device * adev )
{
if ( ! adev - > mman . initialized )
return ;
2017-11-13 20:41:56 +08:00
2015-04-20 16:55:21 -04:00
amdgpu_ttm_debugfs_fini ( adev ) ;
2017-12-14 16:39:02 -05:00
amdgpu_ttm_fw_reserve_vram_fini ( adev ) ;
2018-02-27 10:01:59 -05:00
if ( adev - > mman . aper_base_kaddr )
iounmap ( adev - > mman . aper_base_kaddr ) ;
adev - > mman . aper_base_kaddr = NULL ;
2017-11-13 20:41:56 +08:00
2015-04-20 16:55:21 -04:00
ttm_bo_clean_mm ( & adev - > mman . bdev , TTM_PL_VRAM ) ;
ttm_bo_clean_mm ( & adev - > mman . bdev , TTM_PL_TT ) ;
2018-09-14 20:59:27 +02:00
ttm_bo_clean_mm ( & adev - > mman . bdev , AMDGPU_PL_GDS ) ;
ttm_bo_clean_mm ( & adev - > mman . bdev , AMDGPU_PL_GWS ) ;
ttm_bo_clean_mm ( & adev - > mman . bdev , AMDGPU_PL_OA ) ;
2015-04-20 16:55:21 -04:00
ttm_bo_device_release ( & adev - > mman . bdev ) ;
adev - > mman . initialized = false ;
DRM_INFO ( " amdgpu: ttm finalized \n " ) ;
}
2018-03-01 11:01:52 +01:00
/**
* amdgpu_ttm_set_buffer_funcs_status - enable / disable use of buffer functions
*
* @ adev : amdgpu_device pointer
* @ enable : true when we can use buffer functions .
*
* Enable / disable use of buffer functions during suspend / resume . This should
* only be called at bootup or when userspace isn ' t running .
*/
void amdgpu_ttm_set_buffer_funcs_status ( struct amdgpu_device * adev , bool enable )
2015-04-20 16:55:21 -04:00
{
2018-03-01 11:01:52 +01:00
struct ttm_mem_type_manager * man = & adev - > mman . bdev . man [ TTM_PL_VRAM ] ;
uint64_t size ;
2018-07-12 14:31:25 +02:00
int r ;
2015-04-20 16:55:21 -04:00
2018-07-12 14:31:25 +02:00
if ( ! adev - > mman . initialized | | adev - > in_gpu_reset | |
adev - > mman . buffer_funcs_enabled = = enable )
2015-04-20 16:55:21 -04:00
return ;
2018-07-12 14:31:25 +02:00
if ( enable ) {
struct amdgpu_ring * ring ;
struct drm_sched_rq * rq ;
ring = adev - > mman . buffer_funcs_ring ;
rq = & ring - > sched . sched_rq [ DRM_SCHED_PRIORITY_KERNEL ] ;
2018-07-13 15:21:14 +05:30
r = drm_sched_entity_init ( & adev - > mman . entity , & rq , 1 , NULL ) ;
2018-07-12 14:31:25 +02:00
if ( r ) {
DRM_ERROR ( " Failed setting up TTM BO move entity (%d) \n " ,
r ) ;
return ;
}
} else {
2018-07-20 17:51:05 +05:30
drm_sched_entity_destroy ( & adev - > mman . entity ) ;
2018-07-20 11:42:24 -04:00
dma_fence_put ( man - > move ) ;
man - > move = NULL ;
2018-07-12 14:31:25 +02:00
}
2015-04-20 16:55:21 -04:00
/* this just adjusts TTM size idea, which sets lpfn to the correct value */
2018-03-01 11:01:52 +01:00
if ( enable )
size = adev - > gmc . real_vram_size ;
else
size = adev - > gmc . visible_vram_size ;
2015-04-20 16:55:21 -04:00
man - > size = size > > PAGE_SHIFT ;
2018-03-01 11:09:15 +01:00
adev - > mman . buffer_funcs_enabled = enable ;
2015-04-20 16:55:21 -04:00
}
int amdgpu_mmap ( struct file * filp , struct vm_area_struct * vma )
{
2019-02-07 09:59:30 +01:00
struct drm_file * file_priv = filp - > private_data ;
struct amdgpu_device * adev = file_priv - > minor - > dev - > dev_private ;
2015-04-20 16:55:21 -04:00
2015-05-27 10:22:47 +02:00
if ( adev = = NULL )
2015-04-20 16:55:21 -04:00
return - EINVAL ;
2015-05-27 10:22:47 +02:00
return ttm_bo_mmap ( filp , vma , & adev - > mman . bdev ) ;
2015-04-20 16:55:21 -04:00
}
2017-06-30 11:05:54 +02:00
static int amdgpu_map_buffer ( struct ttm_buffer_object * bo ,
struct ttm_mem_reg * mem , unsigned num_pages ,
uint64_t offset , unsigned window ,
struct amdgpu_ring * ring ,
uint64_t * addr )
{
struct amdgpu_ttm_tt * gtt = ( void * ) bo - > ttm ;
struct amdgpu_device * adev = ring - > adev ;
struct ttm_tt * ttm = bo - > ttm ;
struct amdgpu_job * job ;
unsigned num_dw , num_bytes ;
dma_addr_t * dma_address ;
struct dma_fence * fence ;
uint64_t src_addr , dst_addr ;
uint64_t flags ;
int r ;
BUG_ON ( adev - > mman . buffer_funcs - > copy_max_bytes <
AMDGPU_GTT_MAX_TRANSFER_SIZE * 8 ) ;
2018-01-12 14:52:22 +01:00
* addr = adev - > gmc . gart_start ;
2017-06-30 11:05:54 +02:00
* addr + = ( u64 ) window * AMDGPU_GTT_MAX_TRANSFER_SIZE *
AMDGPU_GPU_PAGE_SIZE ;
num_dw = adev - > mman . buffer_funcs - > copy_num_dw ;
while ( num_dw & 0x7 )
num_dw + + ;
num_bytes = num_pages * 8 ;
r = amdgpu_job_alloc_with_ib ( adev , num_dw * 4 + num_bytes , & job ) ;
if ( r )
return r ;
src_addr = num_dw * 4 ;
src_addr + = job - > ibs [ 0 ] . gpu_addr ;
2018-08-21 17:18:22 +02:00
dst_addr = amdgpu_bo_gpu_offset ( adev - > gart . bo ) ;
2017-06-30 11:05:54 +02:00
dst_addr + = window * AMDGPU_GTT_MAX_TRANSFER_SIZE * 8 ;
amdgpu_emit_copy_buffer ( adev , & job - > ibs [ 0 ] , src_addr ,
dst_addr , num_bytes ) ;
amdgpu_ring_pad_ib ( ring , & job - > ibs [ 0 ] ) ;
WARN_ON ( job - > ibs [ 0 ] . length_dw > num_dw ) ;
dma_address = & gtt - > ttm . dma_address [ offset > > PAGE_SHIFT ] ;
flags = amdgpu_ttm_tt_pte_flags ( adev , ttm , mem ) ;
r = amdgpu_gart_map ( adev , 0 , num_pages , dma_address , flags ,
& job - > ibs [ 0 ] . ptr [ num_dw ] ) ;
if ( r )
goto error_free ;
2018-07-13 13:54:56 +02:00
r = amdgpu_job_submit ( job , & adev - > mman . entity ,
2017-06-30 11:05:54 +02:00
AMDGPU_FENCE_OWNER_UNDEFINED , & fence ) ;
if ( r )
goto error_free ;
dma_fence_put ( fence ) ;
return r ;
error_free :
amdgpu_job_free ( job ) ;
return r ;
}
2017-06-29 11:46:15 +02:00
int amdgpu_copy_buffer ( struct amdgpu_ring * ring , uint64_t src_offset ,
uint64_t dst_offset , uint32_t byte_count ,
2015-04-20 16:55:21 -04:00
struct reservation_object * resv ,
2017-06-29 11:46:15 +02:00
struct dma_fence * * fence , bool direct_submit ,
bool vm_needs_flush )
2015-04-20 16:55:21 -04:00
{
struct amdgpu_device * adev = ring - > adev ;
2016-02-01 12:20:25 +01:00
struct amdgpu_job * job ;
2015-04-20 16:55:21 -04:00
uint32_t max_bytes ;
unsigned num_loops , num_dw ;
unsigned i ;
int r ;
2018-10-19 16:22:48 -04:00
if ( direct_submit & & ! ring - > sched . ready ) {
2018-03-01 11:09:15 +01:00
DRM_ERROR ( " Trying to move memory with ring turned off. \n " ) ;
return - EINVAL ;
}
2015-04-20 16:55:21 -04:00
max_bytes = adev - > mman . buffer_funcs - > copy_max_bytes ;
num_loops = DIV_ROUND_UP ( byte_count , max_bytes ) ;
num_dw = num_loops * adev - > mman . buffer_funcs - > copy_num_dw ;
2015-08-25 17:23:45 +08:00
/* for IB padding */
while ( num_dw & 0x7 )
num_dw + + ;
2016-02-01 12:20:25 +01:00
r = amdgpu_job_alloc_with_ib ( adev , num_dw * 4 , & job ) ;
if ( r )
2015-08-25 15:12:26 +08:00
return r ;
2015-08-25 17:23:45 +08:00
2018-08-21 16:47:01 +02:00
if ( vm_needs_flush ) {
2018-08-22 12:22:14 +02:00
job - > vm_pd_addr = amdgpu_gmc_pd_addr ( adev - > gart . bo ) ;
2018-08-21 16:47:01 +02:00
job - > vm_needs_flush = true ;
}
2015-08-25 17:23:45 +08:00
if ( resv ) {
2016-02-08 12:13:05 +01:00
r = amdgpu_sync_resv ( adev , & job - > sync , resv ,
2017-09-15 20:44:06 -04:00
AMDGPU_FENCE_OWNER_UNDEFINED ,
false ) ;
2015-08-25 17:23:45 +08:00
if ( r ) {
DRM_ERROR ( " sync failed (%d). \n " , r ) ;
goto error_free ;
}
2015-04-20 16:55:21 -04:00
}
for ( i = 0 ; i < num_loops ; i + + ) {
uint32_t cur_size_in_bytes = min ( byte_count , max_bytes ) ;
2016-02-01 12:20:25 +01:00
amdgpu_emit_copy_buffer ( adev , & job - > ibs [ 0 ] , src_offset ,
dst_offset , cur_size_in_bytes ) ;
2015-04-20 16:55:21 -04:00
src_offset + = cur_size_in_bytes ;
dst_offset + = cur_size_in_bytes ;
byte_count - = cur_size_in_bytes ;
}
2016-02-01 12:20:25 +01:00
amdgpu_ring_pad_ib ( ring , & job - > ibs [ 0 ] ) ;
WARN_ON ( job - > ibs [ 0 ] . length_dw > num_dw ) ;
2018-07-13 16:29:10 +02:00
if ( direct_submit )
r = amdgpu_job_submit_direct ( job , ring , fence ) ;
else
2018-07-13 13:54:56 +02:00
r = amdgpu_job_submit ( job , & adev - > mman . entity ,
2016-08-15 10:46:04 +08:00
AMDGPU_FENCE_OWNER_UNDEFINED , fence ) ;
2018-07-13 16:29:10 +02:00
if ( r )
goto error_free ;
2015-04-20 16:55:21 -04:00
2016-08-15 10:46:04 +08:00
return r ;
2016-02-01 12:20:25 +01:00
2015-08-25 17:23:45 +08:00
error_free :
2016-02-01 12:20:25 +01:00
amdgpu_job_free ( job ) ;
2018-07-13 16:29:10 +02:00
DRM_ERROR ( " Error scheduling IBs (%d) \n " , r ) ;
2015-08-25 17:23:45 +08:00
return r ;
2015-04-20 16:55:21 -04:00
}
2016-07-19 16:48:22 +08:00
int amdgpu_fill_buffer ( struct amdgpu_bo * bo ,
2018-01-24 19:58:45 +01:00
uint32_t src_data ,
2016-11-17 12:06:38 +01:00
struct reservation_object * resv ,
struct dma_fence * * fence )
2016-07-19 16:48:22 +08:00
{
2016-09-15 14:58:48 +02:00
struct amdgpu_device * adev = amdgpu_ttm_adev ( bo - > tbo . bdev ) ;
2018-01-24 19:58:45 +01:00
uint32_t max_bytes = adev - > mman . buffer_funcs - > fill_max_bytes ;
2016-07-19 16:48:22 +08:00
struct amdgpu_ring * ring = adev - > mman . buffer_funcs_ring ;
2016-11-17 12:06:38 +01:00
struct drm_mm_node * mm_node ;
unsigned long num_pages ;
2016-07-19 16:48:22 +08:00
unsigned int num_loops , num_dw ;
2016-11-17 12:06:38 +01:00
struct amdgpu_job * job ;
2016-07-19 16:48:22 +08:00
int r ;
2018-03-01 11:09:15 +01:00
if ( ! adev - > mman . buffer_funcs_enabled ) {
2016-11-17 12:06:38 +01:00
DRM_ERROR ( " Trying to clear memory with ring turned off. \n " ) ;
return - EINVAL ;
}
2017-06-29 10:44:39 +02:00
if ( bo - > tbo . mem . mem_type = = TTM_PL_TT ) {
2017-10-27 15:43:14 +02:00
r = amdgpu_ttm_alloc_gart ( & bo - > tbo ) ;
2017-06-29 10:44:39 +02:00
if ( r )
return r ;
}
2016-11-17 12:06:38 +01:00
num_pages = bo - > tbo . num_pages ;
mm_node = bo - > tbo . mem . mm_node ;
num_loops = 0 ;
while ( num_pages ) {
uint32_t byte_count = mm_node - > size < < PAGE_SHIFT ;
num_loops + = DIV_ROUND_UP ( byte_count , max_bytes ) ;
num_pages - = mm_node - > size ;
+ + mm_node ;
}
2018-01-24 19:58:45 +01:00
num_dw = num_loops * adev - > mman . buffer_funcs - > fill_num_dw ;
2016-07-19 16:48:22 +08:00
/* for IB padding */
2016-11-17 12:06:38 +01:00
num_dw + = 64 ;
2016-07-19 16:48:22 +08:00
r = amdgpu_job_alloc_with_ib ( adev , num_dw * 4 , & job ) ;
if ( r )
return r ;
if ( resv ) {
r = amdgpu_sync_resv ( adev , & job - > sync , resv ,
2017-09-15 20:44:06 -04:00
AMDGPU_FENCE_OWNER_UNDEFINED , false ) ;
2016-07-19 16:48:22 +08:00
if ( r ) {
DRM_ERROR ( " sync failed (%d). \n " , r ) ;
goto error_free ;
}
}
2016-11-17 12:06:38 +01:00
num_pages = bo - > tbo . num_pages ;
mm_node = bo - > tbo . mem . mm_node ;
2016-07-19 16:48:22 +08:00
2016-11-17 12:06:38 +01:00
while ( num_pages ) {
uint32_t byte_count = mm_node - > size < < PAGE_SHIFT ;
uint64_t dst_addr ;
2016-07-19 16:48:22 +08:00
2017-06-29 10:44:39 +02:00
dst_addr = amdgpu_mm_node_addr ( & bo - > tbo , mm_node , & bo - > tbo . mem ) ;
2016-11-17 12:06:38 +01:00
while ( byte_count ) {
uint32_t cur_size_in_bytes = min ( byte_count , max_bytes ) ;
2018-01-24 19:58:45 +01:00
amdgpu_emit_fill_buffer ( adev , & job - > ibs [ 0 ] , src_data ,
dst_addr , cur_size_in_bytes ) ;
2016-11-17 12:06:38 +01:00
dst_addr + = cur_size_in_bytes ;
byte_count - = cur_size_in_bytes ;
}
num_pages - = mm_node - > size ;
+ + mm_node ;
2016-07-19 16:48:22 +08:00
}
amdgpu_ring_pad_ib ( ring , & job - > ibs [ 0 ] ) ;
WARN_ON ( job - > ibs [ 0 ] . length_dw > num_dw ) ;
2018-07-13 13:54:56 +02:00
r = amdgpu_job_submit ( job , & adev - > mman . entity ,
2016-11-17 12:06:38 +01:00
AMDGPU_FENCE_OWNER_UNDEFINED , fence ) ;
2016-07-19 16:48:22 +08:00
if ( r )
goto error_free ;
return 0 ;
error_free :
amdgpu_job_free ( job ) ;
return r ;
}
2015-04-20 16:55:21 -04:00
# if defined(CONFIG_DEBUG_FS)
static int amdgpu_mm_dump_table ( struct seq_file * m , void * data )
{
struct drm_info_node * node = ( struct drm_info_node * ) m - > private ;
2018-09-14 15:43:57 +02:00
unsigned ttm_pl = ( uintptr_t ) node - > info_ent - > data ;
2015-04-20 16:55:21 -04:00
struct drm_device * dev = node - > minor - > dev ;
struct amdgpu_device * adev = dev - > dev_private ;
2017-08-07 14:07:43 +02:00
struct ttm_mem_type_manager * man = & adev - > mman . bdev . man [ ttm_pl ] ;
2016-12-29 12:09:24 +01:00
struct drm_printer p = drm_seq_file_printer ( m ) ;
2015-04-20 16:55:21 -04:00
2017-08-07 14:07:43 +02:00
man - > func - > debug ( man , & p ) ;
2016-12-29 12:09:24 +01:00
return 0 ;
2015-04-20 16:55:21 -04:00
}
2016-05-02 12:46:15 -04:00
static const struct drm_info_list amdgpu_ttm_debugfs_list [ ] = {
2018-09-14 15:43:57 +02:00
{ " amdgpu_vram_mm " , amdgpu_mm_dump_table , 0 , ( void * ) TTM_PL_VRAM } ,
{ " amdgpu_gtt_mm " , amdgpu_mm_dump_table , 0 , ( void * ) TTM_PL_TT } ,
{ " amdgpu_gds_mm " , amdgpu_mm_dump_table , 0 , ( void * ) AMDGPU_PL_GDS } ,
{ " amdgpu_gws_mm " , amdgpu_mm_dump_table , 0 , ( void * ) AMDGPU_PL_GWS } ,
{ " amdgpu_oa_mm " , amdgpu_mm_dump_table , 0 , ( void * ) AMDGPU_PL_OA } ,
2015-04-20 16:55:21 -04:00
{ " ttm_page_pool " , ttm_page_alloc_debugfs , 0 , NULL } ,
# ifdef CONFIG_SWIOTLB
{ " ttm_dma_page_pool " , ttm_dma_page_alloc_debugfs , 0 , NULL }
# endif
} ;
2018-05-09 14:22:29 -04:00
/**
* amdgpu_ttm_vram_read - Linear read access to VRAM
*
* Accesses VRAM via MMIO for debugging purposes .
*/
2015-04-20 16:55:21 -04:00
static ssize_t amdgpu_ttm_vram_read ( struct file * f , char __user * buf ,
size_t size , loff_t * pos )
{
2016-12-04 18:24:56 -05:00
struct amdgpu_device * adev = file_inode ( f ) - > i_private ;
2015-04-20 16:55:21 -04:00
ssize_t result = 0 ;
int r ;
if ( size & 0x3 | | * pos & 0x3 )
return - EINVAL ;
2018-01-12 14:52:22 +01:00
if ( * pos > = adev - > gmc . mc_vram_size )
2017-05-23 11:35:22 -04:00
return - ENXIO ;
2015-04-20 16:55:21 -04:00
while ( size ) {
unsigned long flags ;
uint32_t value ;
2018-01-12 14:52:22 +01:00
if ( * pos > = adev - > gmc . mc_vram_size )
2015-04-20 16:55:21 -04:00
return result ;
spin_lock_irqsave ( & adev - > mmio_idx_lock , flags ) ;
2017-09-13 12:35:15 -04:00
WREG32_NO_KIQ ( mmMM_INDEX , ( ( uint32_t ) * pos ) | 0x80000000 ) ;
WREG32_NO_KIQ ( mmMM_INDEX_HI , * pos > > 31 ) ;
value = RREG32_NO_KIQ ( mmMM_DATA ) ;
2015-04-20 16:55:21 -04:00
spin_unlock_irqrestore ( & adev - > mmio_idx_lock , flags ) ;
r = put_user ( value , ( uint32_t * ) buf ) ;
if ( r )
return r ;
result + = 4 ;
buf + = 4 ;
* pos + = 4 ;
size - = 4 ;
}
return result ;
}
2018-05-09 14:22:29 -04:00
/**
* amdgpu_ttm_vram_write - Linear write access to VRAM
*
* Accesses VRAM via MMIO for debugging purposes .
*/
2017-08-29 08:36:52 -04:00
static ssize_t amdgpu_ttm_vram_write ( struct file * f , const char __user * buf ,
size_t size , loff_t * pos )
{
struct amdgpu_device * adev = file_inode ( f ) - > i_private ;
ssize_t result = 0 ;
int r ;
if ( size & 0x3 | | * pos & 0x3 )
return - EINVAL ;
2018-01-12 14:52:22 +01:00
if ( * pos > = adev - > gmc . mc_vram_size )
2017-08-29 08:36:52 -04:00
return - ENXIO ;
while ( size ) {
unsigned long flags ;
uint32_t value ;
2018-01-12 14:52:22 +01:00
if ( * pos > = adev - > gmc . mc_vram_size )
2017-08-29 08:36:52 -04:00
return result ;
r = get_user ( value , ( uint32_t * ) buf ) ;
if ( r )
return r ;
spin_lock_irqsave ( & adev - > mmio_idx_lock , flags ) ;
2017-09-13 12:35:15 -04:00
WREG32_NO_KIQ ( mmMM_INDEX , ( ( uint32_t ) * pos ) | 0x80000000 ) ;
WREG32_NO_KIQ ( mmMM_INDEX_HI , * pos > > 31 ) ;
WREG32_NO_KIQ ( mmMM_DATA , value ) ;
2017-08-29 08:36:52 -04:00
spin_unlock_irqrestore ( & adev - > mmio_idx_lock , flags ) ;
result + = 4 ;
buf + = 4 ;
* pos + = 4 ;
size - = 4 ;
}
return result ;
}
2015-04-20 16:55:21 -04:00
static const struct file_operations amdgpu_ttm_vram_fops = {
. owner = THIS_MODULE ,
. read = amdgpu_ttm_vram_read ,
2017-08-29 08:36:52 -04:00
. write = amdgpu_ttm_vram_write ,
. llseek = default_llseek ,
2015-04-20 16:55:21 -04:00
} ;
2016-03-30 14:42:57 +02:00
# ifdef CONFIG_DRM_AMDGPU_GART_DEBUGFS
2018-05-09 14:22:29 -04:00
/**
* amdgpu_ttm_gtt_read - Linear read access to GTT memory
*/
2015-04-20 16:55:21 -04:00
static ssize_t amdgpu_ttm_gtt_read ( struct file * f , char __user * buf ,
size_t size , loff_t * pos )
{
2016-12-04 18:24:56 -05:00
struct amdgpu_device * adev = file_inode ( f ) - > i_private ;
2015-04-20 16:55:21 -04:00
ssize_t result = 0 ;
int r ;
while ( size ) {
loff_t p = * pos / PAGE_SIZE ;
unsigned off = * pos & ~ PAGE_MASK ;
size_t cur_size = min_t ( size_t , size , PAGE_SIZE - off ) ;
struct page * page ;
void * ptr ;
if ( p > = adev - > gart . num_cpu_pages )
return result ;
page = adev - > gart . pages [ p ] ;
if ( page ) {
ptr = kmap ( page ) ;
ptr + = off ;
r = copy_to_user ( buf , ptr , cur_size ) ;
kunmap ( adev - > gart . pages [ p ] ) ;
} else
r = clear_user ( buf , cur_size ) ;
if ( r )
return - EFAULT ;
result + = cur_size ;
buf + = cur_size ;
* pos + = cur_size ;
size - = cur_size ;
}
return result ;
}
static const struct file_operations amdgpu_ttm_gtt_fops = {
. owner = THIS_MODULE ,
. read = amdgpu_ttm_gtt_read ,
. llseek = default_llseek
} ;
# endif
2018-05-09 14:22:29 -04:00
/**
* amdgpu_iomem_read - Virtual read access to GPU mapped memory
*
* This function is used to read memory that has been mapped to the
* GPU and the known addresses are not physical addresses but instead
* bus addresses ( e . g . , what you ' d put in an IB or ring buffer ) .
*/
2018-02-23 09:46:23 -05:00
static ssize_t amdgpu_iomem_read ( struct file * f , char __user * buf ,
size_t size , loff_t * pos )
2017-09-18 07:28:14 -04:00
{
struct amdgpu_device * adev = file_inode ( f ) - > i_private ;
struct iommu_domain * dom ;
2018-02-23 09:46:23 -05:00
ssize_t result = 0 ;
int r ;
2017-09-18 07:28:14 -04:00
2018-05-09 14:22:29 -04:00
/* retrieve the IOMMU domain if any for this device */
2018-02-23 09:46:23 -05:00
dom = iommu_get_domain_for_dev ( adev - > dev ) ;
2017-09-18 07:28:14 -04:00
2018-02-23 09:46:23 -05:00
while ( size ) {
phys_addr_t addr = * pos & PAGE_MASK ;
loff_t off = * pos & ~ PAGE_MASK ;
size_t bytes = PAGE_SIZE - off ;
unsigned long pfn ;
struct page * p ;
void * ptr ;
bytes = bytes < size ? bytes : size ;
2018-05-09 14:22:29 -04:00
/* Translate the bus address to a physical address. If
* the domain is NULL it means there is no IOMMU active
* and the address translation is the identity
*/
2018-02-23 09:46:23 -05:00
addr = dom ? iommu_iova_to_phys ( dom , addr ) : addr ;
pfn = addr > > PAGE_SHIFT ;
if ( ! pfn_valid ( pfn ) )
return - EPERM ;
p = pfn_to_page ( pfn ) ;
if ( p - > mapping ! = adev - > mman . bdev . dev_mapping )
return - EPERM ;
ptr = kmap ( p ) ;
2018-03-20 09:13:08 -04:00
r = copy_to_user ( buf , ptr + off , bytes ) ;
2018-02-23 09:46:23 -05:00
kunmap ( p ) ;
if ( r )
return - EFAULT ;
size - = bytes ;
* pos + = bytes ;
result + = bytes ;
}
return result ;
}
2018-05-09 14:22:29 -04:00
/**
* amdgpu_iomem_write - Virtual write access to GPU mapped memory
*
* This function is used to write memory that has been mapped to the
* GPU and the known addresses are not physical addresses but instead
* bus addresses ( e . g . , what you ' d put in an IB or ring buffer ) .
*/
2018-02-23 09:46:23 -05:00
static ssize_t amdgpu_iomem_write ( struct file * f , const char __user * buf ,
size_t size , loff_t * pos )
{
struct amdgpu_device * adev = file_inode ( f ) - > i_private ;
struct iommu_domain * dom ;
ssize_t result = 0 ;
int r ;
2017-09-18 07:28:14 -04:00
dom = iommu_get_domain_for_dev ( adev - > dev ) ;
2017-09-18 07:14:56 -04:00
2018-02-23 09:46:23 -05:00
while ( size ) {
phys_addr_t addr = * pos & PAGE_MASK ;
loff_t off = * pos & ~ PAGE_MASK ;
size_t bytes = PAGE_SIZE - off ;
unsigned long pfn ;
struct page * p ;
void * ptr ;
bytes = bytes < size ? bytes : size ;
2017-09-18 07:28:14 -04:00
2018-02-23 09:46:23 -05:00
addr = dom ? iommu_iova_to_phys ( dom , addr ) : addr ;
pfn = addr > > PAGE_SHIFT ;
if ( ! pfn_valid ( pfn ) )
return - EPERM ;
p = pfn_to_page ( pfn ) ;
if ( p - > mapping ! = adev - > mman . bdev . dev_mapping )
return - EPERM ;
ptr = kmap ( p ) ;
2018-03-20 09:13:08 -04:00
r = copy_from_user ( ptr + off , buf , bytes ) ;
2018-02-23 09:46:23 -05:00
kunmap ( p ) ;
if ( r )
return - EFAULT ;
size - = bytes ;
* pos + = bytes ;
result + = bytes ;
}
return result ;
2017-09-18 07:28:14 -04:00
}
2018-02-23 09:46:23 -05:00
static const struct file_operations amdgpu_ttm_iomem_fops = {
2017-09-18 07:28:14 -04:00
. owner = THIS_MODULE ,
2018-02-23 09:46:23 -05:00
. read = amdgpu_iomem_read ,
. write = amdgpu_iomem_write ,
2017-09-18 07:28:14 -04:00
. llseek = default_llseek
} ;
2017-09-18 07:14:56 -04:00
static const struct {
char * name ;
const struct file_operations * fops ;
int domain ;
} ttm_debugfs_entries [ ] = {
{ " amdgpu_vram " , & amdgpu_ttm_vram_fops , TTM_PL_VRAM } ,
# ifdef CONFIG_DRM_AMDGPU_GART_DEBUGFS
{ " amdgpu_gtt " , & amdgpu_ttm_gtt_fops , TTM_PL_TT } ,
# endif
2018-02-23 09:46:23 -05:00
{ " amdgpu_iomem " , & amdgpu_ttm_iomem_fops , TTM_PL_SYSTEM } ,
2017-09-18 07:14:56 -04:00
} ;
2016-03-30 14:42:57 +02:00
# endif
2015-04-20 16:55:21 -04:00
static int amdgpu_ttm_debugfs_init ( struct amdgpu_device * adev )
{
# if defined(CONFIG_DEBUG_FS)
unsigned count ;
struct drm_minor * minor = adev - > ddev - > primary ;
struct dentry * ent , * root = minor - > debugfs_root ;
2017-09-18 07:14:56 -04:00
for ( count = 0 ; count < ARRAY_SIZE ( ttm_debugfs_entries ) ; count + + ) {
ent = debugfs_create_file (
ttm_debugfs_entries [ count ] . name ,
S_IFREG | S_IRUGO , root ,
adev ,
ttm_debugfs_entries [ count ] . fops ) ;
if ( IS_ERR ( ent ) )
return PTR_ERR ( ent ) ;
if ( ttm_debugfs_entries [ count ] . domain = = TTM_PL_VRAM )
2018-01-12 14:52:22 +01:00
i_size_write ( ent - > d_inode , adev - > gmc . mc_vram_size ) ;
2017-09-18 07:14:56 -04:00
else if ( ttm_debugfs_entries [ count ] . domain = = TTM_PL_TT )
2018-01-12 14:52:22 +01:00
i_size_write ( ent - > d_inode , adev - > gmc . gart_size ) ;
2017-09-18 07:14:56 -04:00
adev - > mman . debugfs_entries [ count ] = ent ;
}
2015-04-20 16:55:21 -04:00
count = ARRAY_SIZE ( amdgpu_ttm_debugfs_list ) ;
# ifdef CONFIG_SWIOTLB
2018-02-09 10:44:09 +08:00
if ( ! ( adev - > need_swiotlb & & swiotlb_nr_tbl ( ) ) )
2015-04-20 16:55:21 -04:00
- - count ;
# endif
return amdgpu_debugfs_add_files ( adev , amdgpu_ttm_debugfs_list , count ) ;
# else
return 0 ;
# endif
}
static void amdgpu_ttm_debugfs_fini ( struct amdgpu_device * adev )
{
# if defined(CONFIG_DEBUG_FS)
2017-09-18 07:14:56 -04:00
unsigned i ;
2015-04-20 16:55:21 -04:00
2017-09-18 07:14:56 -04:00
for ( i = 0 ; i < ARRAY_SIZE ( ttm_debugfs_entries ) ; i + + )
debugfs_remove ( adev - > mman . debugfs_entries [ i ] ) ;
2016-03-30 14:42:57 +02:00
# endif
2015-04-20 16:55:21 -04:00
}