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"
2015-04-20 16:55:21 -04:00
# include "bif/bif_4_1_d.h"
# define DRM_FILE_PAGE_OFFSET (0x100000000ULL >> PAGE_SHIFT)
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 ) ;
/*
* Global memory .
*/
static int amdgpu_ttm_mem_global_init ( struct drm_global_reference * ref )
{
return ttm_mem_global_init ( ref - > object ) ;
}
static void amdgpu_ttm_mem_global_release ( struct drm_global_reference * ref )
{
ttm_mem_global_release ( ref - > object ) ;
}
2016-11-15 16:55:53 -05:00
static int amdgpu_ttm_global_init ( struct amdgpu_device * adev )
2015-04-20 16:55:21 -04:00
{
struct drm_global_reference * global_ref ;
2016-02-10 14:20:50 +01:00
struct amdgpu_ring * ring ;
struct amd_sched_rq * rq ;
2015-04-20 16:55:21 -04:00
int r ;
adev - > mman . mem_global_referenced = false ;
global_ref = & adev - > mman . mem_global_ref ;
global_ref - > global_type = DRM_GLOBAL_TTM_MEM ;
global_ref - > size = sizeof ( struct ttm_mem_global ) ;
global_ref - > init = & amdgpu_ttm_mem_global_init ;
global_ref - > release = & amdgpu_ttm_mem_global_release ;
r = drm_global_item_ref ( global_ref ) ;
2016-09-07 20:55:42 +08:00
if ( r ) {
2015-04-20 16:55:21 -04:00
DRM_ERROR ( " Failed setting up TTM memory accounting "
" subsystem. \n " ) ;
2016-09-07 20:55:42 +08:00
goto error_mem ;
2015-04-20 16:55:21 -04:00
}
adev - > mman . bo_global_ref . mem_glob =
adev - > mman . mem_global_ref . object ;
global_ref = & adev - > mman . bo_global_ref . ref ;
global_ref - > global_type = DRM_GLOBAL_TTM_BO ;
global_ref - > size = sizeof ( struct ttm_bo_global ) ;
global_ref - > init = & ttm_bo_global_init ;
global_ref - > release = & ttm_bo_global_release ;
r = drm_global_item_ref ( global_ref ) ;
2016-09-07 20:55:42 +08:00
if ( r ) {
2015-04-20 16:55:21 -04:00
DRM_ERROR ( " Failed setting up TTM BO subsystem. \n " ) ;
2016-09-07 20:55:42 +08:00
goto error_bo ;
2015-04-20 16:55:21 -04:00
}
2017-06-30 11:05:54 +02:00
mutex_init ( & adev - > mman . gtt_window_lock ) ;
2016-02-10 14:20:50 +01:00
ring = adev - > mman . buffer_funcs_ring ;
rq = & ring - > sched . sched_rq [ AMD_SCHED_PRIORITY_KERNEL ] ;
r = amd_sched_entity_init ( & ring - > sched , & adev - > mman . entity ,
2017-10-23 12:23:29 +08:00
rq , amdgpu_sched_jobs , NULL ) ;
2016-09-07 20:55:42 +08:00
if ( r ) {
2016-02-10 14:20:50 +01:00
DRM_ERROR ( " Failed setting up TTM BO move run queue. \n " ) ;
2016-09-07 20:55:42 +08:00
goto error_entity ;
2016-02-10 14:20:50 +01:00
}
2015-04-20 16:55:21 -04:00
adev - > mman . mem_global_referenced = true ;
2016-02-10 14:20:50 +01:00
2015-04-20 16:55:21 -04:00
return 0 ;
2016-09-07 20:55:42 +08:00
error_entity :
drm_global_item_unref ( & adev - > mman . bo_global_ref . ref ) ;
error_bo :
drm_global_item_unref ( & adev - > mman . mem_global_ref ) ;
error_mem :
return r ;
2015-04-20 16:55:21 -04:00
}
static void amdgpu_ttm_global_fini ( struct amdgpu_device * adev )
{
if ( adev - > mman . mem_global_referenced ) {
2016-02-10 14:20:50 +01:00
amd_sched_entity_fini ( adev - > mman . entity . sched ,
& adev - > mman . entity ) ;
2017-06-30 11:05:54 +02:00
mutex_destroy ( & adev - > mman . gtt_window_lock ) ;
2015-04-20 16:55:21 -04:00
drm_global_item_unref ( & adev - > mman . bo_global_ref . ref ) ;
drm_global_item_unref ( & adev - > mman . mem_global_ref ) ;
adev - > mman . mem_global_referenced = false ;
}
}
static int amdgpu_invalidate_caches ( struct ttm_bo_device * bdev , uint32_t flags )
{
return 0 ;
}
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 :
2016-09-09 16:32:33 +02:00
man - > func = & amdgpu_gtt_mgr_func ;
2017-07-07 11:56:59 +02:00
man - > gpu_offset = adev - > mc . 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 ;
2015-04-20 16:55:21 -04:00
man - > gpu_offset = adev - > mc . vram_start ;
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 ;
}
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
} ;
if ( ! amdgpu_ttm_bo_is_amdgpu_bo ( bo ) ) {
placement - > placement = & placements ;
placement - > busy_placement = & placements ;
placement - > num_placement = 1 ;
placement - > num_busy_placement = 1 ;
return ;
}
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 ) {
case TTM_PL_VRAM :
2017-04-11 09:24:56 +08:00
if ( adev - > mman . buffer_funcs & &
adev - > mman . buffer_funcs_ring & &
adev - > mman . buffer_funcs_ring - > ready = = false ) {
2016-09-15 15:06:50 +02:00
amdgpu_ttm_placement_from_domain ( abo , AMDGPU_GEM_DOMAIN_CPU ) ;
2017-07-04 17:16:42 +09:00
} else if ( adev - > mc . visible_vram_size < adev - > mc . real_vram_size & &
! ( abo - > flags & AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED ) ) {
unsigned fpfn = adev - > mc . visible_vram_size > > PAGE_SHIFT ;
struct drm_mm_node * node = bo - > mem . mm_node ;
unsigned long pages_left ;
for ( pages_left = bo - > mem . num_pages ;
pages_left ;
pages_left - = node - > size , node + + ) {
if ( node - > start < fpfn )
break ;
}
if ( ! pages_left )
goto gtt ;
/* 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
*/
amdgpu_ttm_placement_from_domain ( abo , AMDGPU_GEM_DOMAIN_VRAM |
AMDGPU_GEM_DOMAIN_GTT ) ;
abo - > placements [ 0 ] . fpfn = fpfn ;
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 {
2017-07-04 17:16:42 +09:00
gtt :
2016-09-15 15:06:50 +02:00
amdgpu_ttm_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 :
2016-09-15 15:06:50 +02:00
amdgpu_ttm_placement_from_domain ( abo , AMDGPU_GEM_DOMAIN_CPU ) ;
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
}
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
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
}
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 ;
}
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
2017-10-27 14:17:09 +02:00
if ( mem - > mem_type ! = TTM_PL_TT | | amdgpu_gtt_mgr_has_gart_addr ( mem ) ) {
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
/**
2017-10-06 17:36:35 -04: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
*/
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
2015-04-20 16:55:21 -04:00
if ( ! ring - > ready ) {
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
*/
if ( src - > mem - > mem_type = = TTM_PL_TT & &
2017-10-27 14:17:09 +02:00
! amdgpu_gtt_mgr_has_gart_addr ( src - > mem ) ) {
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
}
2017-10-03 15:41:56 -04:00
if ( dst - > mem - > mem_type = = TTM_PL_TT & &
2017-10-27 14:17:09 +02:00
! amdgpu_gtt_mgr_has_gart_addr ( dst - > mem ) ) {
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 ;
}
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
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
}
static int amdgpu_move_vram_ram ( struct ttm_buffer_object * bo ,
bool evict , bool interruptible ,
bool no_wait_gpu ,
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 ) ;
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 ;
r = ttm_bo_mem_space ( bo , & placement , & tmp_mem ,
interruptible , no_wait_gpu ) ;
if ( unlikely ( r ) ) {
return r ;
}
r = ttm_tt_set_placement_caching ( bo - > ttm , tmp_mem . placement ) ;
if ( unlikely ( r ) ) {
goto out_cleanup ;
}
r = ttm_tt_bind ( bo - > ttm , & tmp_mem ) ;
if ( unlikely ( r ) ) {
goto out_cleanup ;
}
r = amdgpu_move_blit ( bo , true , no_wait_gpu , & tmp_mem , old_mem ) ;
if ( unlikely ( r ) ) {
goto out_cleanup ;
}
2016-08-08 12:28:25 +09:00
r = ttm_bo_move_ttm ( bo , interruptible , no_wait_gpu , new_mem ) ;
2015-04-20 16:55:21 -04:00
out_cleanup :
ttm_bo_mem_put ( bo , & tmp_mem ) ;
return r ;
}
static int amdgpu_move_ram_vram ( struct ttm_buffer_object * bo ,
bool evict , bool interruptible ,
bool no_wait_gpu ,
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 ) ;
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 ;
r = ttm_bo_mem_space ( bo , & placement , & tmp_mem ,
interruptible , no_wait_gpu ) ;
if ( unlikely ( r ) ) {
return r ;
}
2016-08-08 12:28:25 +09:00
r = ttm_bo_move_ttm ( bo , interruptible , no_wait_gpu , & tmp_mem ) ;
2015-04-20 16:55:21 -04:00
if ( unlikely ( r ) ) {
goto out_cleanup ;
}
r = amdgpu_move_blit ( bo , true , no_wait_gpu , new_mem , old_mem ) ;
if ( unlikely ( r ) ) {
goto out_cleanup ;
}
out_cleanup :
ttm_bo_mem_put ( bo , & tmp_mem ) ;
return r ;
}
static int amdgpu_bo_move ( struct ttm_buffer_object * bo ,
bool evict , bool interruptible ,
bool no_wait_gpu ,
struct ttm_mem_reg * new_mem )
{
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 ;
}
if ( adev - > mman . buffer_funcs = = NULL | |
adev - > mman . buffer_funcs_ring = = NULL | |
! adev - > mman . buffer_funcs_ring - > ready ) {
/* use memcpy */
goto memcpy ;
}
if ( old_mem - > mem_type = = TTM_PL_VRAM & &
new_mem - > mem_type = = TTM_PL_SYSTEM ) {
r = amdgpu_move_vram_ram ( bo , evict , interruptible ,
no_wait_gpu , new_mem ) ;
} else if ( old_mem - > mem_type = = TTM_PL_SYSTEM & &
new_mem - > mem_type = = TTM_PL_VRAM ) {
r = amdgpu_move_ram_vram ( bo , evict , interruptible ,
no_wait_gpu , new_mem ) ;
} else {
r = amdgpu_move_blit ( bo , evict , no_wait_gpu , new_mem , old_mem ) ;
}
if ( r ) {
memcpy :
2016-08-08 12:28:26 +09:00
r = ttm_bo_move_memcpy ( bo , interruptible , no_wait_gpu , 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 ;
}
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 ) ;
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 */
if ( ( mem - > bus . offset + mem - > bus . size ) > adev - > mc . visible_vram_size )
return - EINVAL ;
mem - > bus . base = adev - > mc . aper_base ;
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 .
*/
2016-03-03 14:24:57 +01: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 ;
struct amdgpu_device * adev ;
u64 offset ;
uint64_t userptr ;
struct mm_struct * usermm ;
uint32_t userflags ;
spinlock_t guptasklock ;
struct list_head guptasks ;
2016-02-23 12:36:59 +01:00
atomic_t mmu_invalidations ;
2017-09-05 14:30:05 +02:00
uint32_t last_set_pages ;
2015-04-20 16:55:21 -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 ;
2016-10-13 01:20:16 +01:00
unsigned int flags = 0 ;
2016-02-23 12:36:59 +01:00
unsigned pinned = 0 ;
int r ;
2015-04-20 16:55:21 -04:00
2016-10-13 01:20:16 +01:00
if ( ! ( gtt - > userflags & AMDGPU_GEM_USERPTR_READONLY ) )
flags | = FOLL_WRITE ;
2017-09-03 15:22:06 +02:00
down_read ( & current - > mm - > mmap_sem ) ;
2015-04-20 16:55:21 -04:00
if ( gtt - > userflags & AMDGPU_GEM_USERPTR_ANONONLY ) {
2016-02-23 12:36:59 +01:00
/* check that we only use anonymous memory
2015-04-20 16:55:21 -04:00
to prevent problems with writeback */
unsigned long end = gtt - > userptr + ttm - > num_pages * PAGE_SIZE ;
struct vm_area_struct * vma ;
vma = find_vma ( gtt - > usermm , gtt - > userptr ) ;
2017-09-03 15:22:06 +02:00
if ( ! vma | | vma - > vm_file | | vma - > vm_end < end ) {
up_read ( & current - > mm - > mmap_sem ) ;
2015-04-20 16:55:21 -04:00
return - EPERM ;
2017-09-03 15:22:06 +02:00
}
2015-04-20 16:55:21 -04:00
}
do {
unsigned num_pages = ttm - > num_pages - pinned ;
uint64_t userptr = gtt - > userptr + pinned * PAGE_SIZE ;
2016-02-23 12:36:59 +01:00
struct page * * p = pages + pinned ;
2016-03-03 14:24:57 +01:00
struct amdgpu_ttm_gup_task_list guptask ;
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
2016-10-13 01:20:16 +01:00
r = get_user_pages ( userptr , num_pages , flags , p , NULL ) ;
2016-03-03 14:24:57 +01:00
spin_lock ( & gtt - > guptasklock ) ;
list_del ( & guptask . list ) ;
spin_unlock ( & gtt - > guptasklock ) ;
2015-04-20 16:55:21 -04:00
if ( r < 0 )
goto release_pages ;
pinned + = r ;
} while ( pinned < ttm - > num_pages ) ;
2017-09-03 15:22:06 +02:00
up_read ( & current - > mm - > mmap_sem ) ;
2016-02-23 12:36:59 +01:00
return 0 ;
release_pages :
2017-11-15 17:37:55 -08:00
release_pages ( pages , pinned ) ;
2017-09-03 15:22:06 +02:00
up_read ( & current - > mm - > mmap_sem ) ;
2016-02-23 12:36:59 +01:00
return r ;
}
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
{
struct amdgpu_ttm_tt * gtt = ( void * ) ttm ;
unsigned i ;
2017-09-05 14:30:05 +02:00
gtt - > last_set_pages = atomic_read ( & gtt - > mmu_invalidations ) ;
2017-09-02 13:21:31 +02:00
for ( i = 0 ; i < ttm - > num_pages ; + + i ) {
if ( ttm - > pages [ i ] )
put_page ( ttm - > pages [ i ] ) ;
ttm - > pages [ i ] = pages ? pages [ i ] : NULL ;
2017-07-31 09:35:24 -04:00
}
}
2017-09-05 14:36:44 +02:00
void amdgpu_ttm_tt_mark_user_pages ( struct ttm_tt * ttm )
2017-07-31 09:35:24 -04:00
{
struct amdgpu_ttm_tt * gtt = ( void * ) ttm ;
unsigned i ;
2017-09-05 14:36:44 +02:00
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 ) ;
2017-07-31 09:35:24 -04:00
}
}
2016-02-23 12:36:59 +01:00
/* prepare the sg table with the user pages */
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 ;
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 ;
r = - ENOMEM ;
nents = dma_map_sg ( adev - > dev , ttm - > sg - > sgl , ttm - > sg - > nents , direction ) ;
if ( nents ! = ttm - > sg - > nents )
goto release_sg ;
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 ;
}
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 ;
/* free the sg table and pages again */
dma_unmap_sg ( adev - > dev , ttm - > sg - > sgl , ttm - > sg - > nents , direction ) ;
2017-09-05 14:36:44 +02:00
amdgpu_ttm_tt_mark_user_pages ( ttm ) ;
2017-07-31 09:35:24 -04:00
2015-04-20 16:55:21 -04:00
sg_free_table ( ttm - > sg ) ;
}
static int amdgpu_ttm_backend_bind ( struct ttm_tt * ttm ,
struct ttm_mem_reg * bo_mem )
{
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
flags = amdgpu_ttm_tt_pte_flags ( gtt - > adev , ttm , bo_mem ) ;
gtt - > offset = ( u64 ) bo_mem - > start < < PAGE_SHIFT ;
r = amdgpu_gart_bind ( gtt - > adev , gtt - > offset , ttm - > num_pages ,
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
}
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-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 ;
2017-10-26 17:54:12 +02:00
uint64_t flags ;
2016-09-05 17:00:57 +02:00
int r ;
2017-10-27 14:17:09 +02:00
if ( bo - > mem . mem_type ! = TTM_PL_TT | |
amdgpu_gtt_mgr_has_gart_addr ( & bo - > mem ) )
2016-09-05 17:00:57 +02:00
return 0 ;
2017-08-22 16:58:07 +02:00
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 - > mc . gart_size > > PAGE_SHIFT ;
2017-10-16 13:47:15 +02:00
placements . flags = ( bo - > mem . placement & ~ TTM_PL_MASK_MEM ) |
TTM_PL_FLAG_TT ;
2017-08-22 16:58:07 +02:00
2017-10-25 21:37:35 +02:00
r = ttm_bo_mem_space ( bo , & placement , & tmp , false , false ) ;
2017-08-22 16:58:07 +02:00
if ( unlikely ( r ) )
2016-09-09 16:32:33 +02:00
return r ;
2017-10-26 17:54:12 +02:00
flags = amdgpu_ttm_tt_pte_flags ( adev , bo - > ttm , & tmp ) ;
gtt - > offset = ( u64 ) tmp . start < < PAGE_SHIFT ;
r = amdgpu_gart_bind ( adev , gtt - > offset , bo - > ttm - > num_pages ,
bo - > ttm - > pages , gtt - > ttm . dma_address , flags ) ;
if ( unlikely ( r ) ) {
2017-08-22 16:58:07 +02:00
ttm_bo_mem_put ( bo , & tmp ) ;
2017-10-26 17:54:12 +02:00
return r ;
}
2017-08-22 16:58:07 +02:00
2017-10-26 17:54:12 +02:00
ttm_bo_mem_put ( bo , & bo - > mem ) ;
bo - > mem = tmp ;
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
}
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 ) ;
struct amdgpu_ttm_tt * gtt = ( void * ) tbo - > ttm ;
2017-04-27 17:14:57 +08:00
uint64_t flags ;
2016-08-30 16:36:25 +08:00
int r ;
2017-10-16 16:50:32 +02:00
if ( ! gtt )
return 0 ;
flags = amdgpu_ttm_tt_pte_flags ( adev , & gtt - > ttm . ttm , & tbo - > mem ) ;
r = amdgpu_gart_bind ( adev , gtt - > offset , gtt - > ttm . ttm . num_pages ,
gtt - > ttm . ttm . pages , gtt - > ttm . dma_address , flags ) ;
if ( r )
DRM_ERROR ( " failed to bind %lu pages at 0x%08llX \n " ,
gtt - > ttm . ttm . num_pages , gtt - > offset ) ;
return r ;
2016-08-30 16:36:25 +08:00
}
2015-04-20 16:55:21 -04:00
static int amdgpu_ttm_backend_unbind ( struct ttm_tt * ttm )
{
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
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 */
2017-05-05 13:27:10 +08:00
r = amdgpu_gart_unbind ( gtt - > 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 ;
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 ,
} ;
static struct ttm_tt * amdgpu_ttm_tt_create ( struct ttm_bo_device * bdev ,
unsigned long size , uint32_t page_flags ,
struct page * dummy_read_page )
{
struct amdgpu_device * adev ;
struct amdgpu_ttm_tt * gtt ;
2016-09-15 14:58:48 +02:00
adev = amdgpu_ttm_adev ( 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 ;
gtt - > adev = adev ;
if ( ttm_dma_tt_init ( & gtt - > ttm , bdev , size , page_flags , dummy_read_page ) ) {
kfree ( gtt ) ;
return NULL ;
}
return & gtt - > ttm . ttm ;
}
static int amdgpu_ttm_tt_populate ( struct ttm_tt * ttm )
{
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 ) ;
if ( ttm - > state ! = tt_unpopulated )
return 0 ;
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 ,
gtt - > ttm . dma_address , ttm - > num_pages ) ;
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
if ( swiotlb_nr_tbl ( ) ) {
2017-09-18 08:10:00 -04:00
return ttm_dma_populate ( & gtt - > ttm , adev - > dev ) ;
2015-04-20 16:55:21 -04:00
}
# endif
2017-09-18 08:10:00 -04:00
return ttm_populate_and_map_pages ( adev - > dev , & gtt - > ttm ) ;
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
if ( swiotlb_nr_tbl ( ) ) {
ttm_dma_unpopulate ( & gtt - > ttm , adev - > dev ) ;
return ;
}
# endif
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
}
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 - > usermm = current - > mm ;
gtt - > userflags = flags ;
2016-03-03 14:24:57 +01:00
spin_lock_init ( & gtt - > guptasklock ) ;
INIT_LIST_HEAD ( & gtt - > guptasks ) ;
2016-02-23 12:36:59 +01:00
atomic_set ( & gtt - > mmu_invalidations , 0 ) ;
2017-09-05 14:30:05 +02:00
gtt - > last_set_pages = 0 ;
2016-03-03 14:24:57 +01:00
2015-04-20 16:55:21 -04:00
return 0 ;
}
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
2016-02-08 11:08:35 +01:00
return gtt - > usermm ;
2015-04-20 16:55:21 -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 ;
2016-03-03 14:24:57 +01: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 ;
size = ( unsigned long ) gtt - > ttm . ttm . num_pages * PAGE_SIZE ;
if ( gtt - > userptr > end | | gtt - > userptr + size < = start )
return false ;
2016-03-03 14:24:57 +01:00
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 ) ;
2016-02-23 12:36:59 +01:00
atomic_inc ( & gtt - > mmu_invalidations ) ;
2016-02-08 10:57:22 +01:00
return true ;
}
2016-02-23 12:36:59 +01:00
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 ;
}
2017-09-05 14:30:05 +02:00
bool amdgpu_ttm_tt_userptr_needs_pages ( struct ttm_tt * ttm )
{
struct amdgpu_ttm_tt * gtt = ( void * ) ttm ;
if ( gtt = = NULL | | ! gtt - > userptr )
return false ;
return atomic_read ( & gtt - > mmu_invalidations ) ! = gtt - > last_set_pages ;
}
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 ) ;
}
2016-09-21 16:19:19 +08:00
uint64_t amdgpu_ttm_tt_pte_flags ( struct amdgpu_device * adev , struct ttm_tt * ttm ,
2015-04-20 16:55:21 -04:00
struct ttm_mem_reg * mem )
{
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
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 ;
}
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 ;
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 ) ;
}
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 ;
while ( len & & pos < adev - > mc . mc_vram_size ) {
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 ,
2017-07-03 14:18:27 -04:00
. access_memory = & amdgpu_ttm_access_memory
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
2016-11-15 16:55:53 -05:00
r = amdgpu_ttm_global_init ( adev ) ;
if ( r ) {
return r ;
}
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 ,
adev - > mman . bo_global_ref . ref . object ,
& amdgpu_bo_driver ,
adev - > ddev - > anon_inode - > i_mapping ,
DRM_FILE_PAGE_OFFSET ,
adev - > need_dma32 ) ;
if ( r ) {
DRM_ERROR ( " failed initializing buffer object driver(%d). \n " , r ) ;
return r ;
}
adev - > mman . initialized = true ;
r = ttm_bo_init_mm ( & adev - > mman . bdev , TTM_PL_VRAM ,
adev - > mc . real_vram_size > > PAGE_SHIFT ) ;
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 & &
vis_vram_limit < = adev - > mc . visible_vram_size )
adev - > mc . visible_vram_size = vis_vram_limit ;
2015-04-20 16:55:21 -04:00
/* Change the size here instead of the init above so only lpfn is affected */
amdgpu_ttm_set_active_vram_size ( adev , adev - > mc . visible_vram_size ) ;
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 .
*/
r = amdgpu_fw_reserve_vram_init ( adev ) ;
if ( r ) {
return r ;
}
2017-07-27 17:24:36 +02:00
r = amdgpu_bo_create_kernel ( adev , adev - > mc . stolen_size , PAGE_SIZE ,
AMDGPU_GEM_DOMAIN_VRAM ,
2017-08-08 07:48:01 -04:00
& adev - > stolen_vga_memory ,
2017-07-27 17:24:36 +02:00
NULL , NULL ) ;
2015-04-20 16:55:21 -04:00
if ( r )
return r ;
DRM_INFO ( " amdgpu: %uM of VRAM memory ready \n " ,
( unsigned ) ( adev - > mc . real_vram_size / ( 1024 * 1024 ) ) ) ;
2017-07-07 13:17:45 +02:00
2017-11-10 19:05:13 +08:00
if ( amdgpu_gtt_size = = - 1 ) {
struct sysinfo si ;
si_meminfo ( & si ) ;
gtt_size = min ( max ( ( AMDGPU_DEFAULT_GTT_SIZE_MB < < 20 ) ,
adev - > mc . mc_vram_size ) ,
( ( uint64_t ) si . totalram * si . mem_unit * 3 / 4 ) ) ;
}
2017-07-07 13:17:45 +02:00
else
gtt_size = ( uint64_t ) amdgpu_gtt_size < < 20 ;
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
adev - > gds . mem . total_size = adev - > gds . mem . total_size < < AMDGPU_GDS_SHIFT ;
adev - > gds . mem . gfx_partition_size = adev - > gds . mem . gfx_partition_size < < AMDGPU_GDS_SHIFT ;
adev - > gds . mem . cs_partition_size = adev - > gds . mem . cs_partition_size < < AMDGPU_GDS_SHIFT ;
adev - > gds . gws . total_size = adev - > gds . gws . total_size < < AMDGPU_GWS_SHIFT ;
adev - > gds . gws . gfx_partition_size = adev - > gds . gws . gfx_partition_size < < AMDGPU_GWS_SHIFT ;
adev - > gds . gws . cs_partition_size = adev - > gds . gws . cs_partition_size < < AMDGPU_GWS_SHIFT ;
adev - > gds . oa . total_size = adev - > gds . oa . total_size < < AMDGPU_OA_SHIFT ;
adev - > gds . oa . gfx_partition_size = adev - > gds . oa . gfx_partition_size < < AMDGPU_OA_SHIFT ;
adev - > gds . oa . cs_partition_size = adev - > gds . oa . cs_partition_size < < AMDGPU_OA_SHIFT ;
/* GDS Memory */
2017-03-15 09:45:48 -04:00
if ( adev - > gds . mem . total_size ) {
r = ttm_bo_init_mm ( & adev - > mman . bdev , AMDGPU_PL_GDS ,
adev - > gds . mem . total_size > > PAGE_SHIFT ) ;
if ( r ) {
DRM_ERROR ( " Failed initializing GDS heap. \n " ) ;
return r ;
}
2015-04-20 16:55:21 -04:00
}
/* GWS */
2017-03-15 09:45:48 -04:00
if ( adev - > gds . gws . total_size ) {
r = ttm_bo_init_mm ( & adev - > mman . bdev , AMDGPU_PL_GWS ,
adev - > gds . gws . total_size > > PAGE_SHIFT ) ;
if ( r ) {
DRM_ERROR ( " Failed initializing gws heap. \n " ) ;
return r ;
}
2015-04-20 16:55:21 -04:00
}
/* OA */
2017-03-15 09:45:48 -04:00
if ( adev - > gds . oa . total_size ) {
r = ttm_bo_init_mm ( & adev - > mman . bdev , AMDGPU_PL_OA ,
adev - > gds . oa . total_size > > PAGE_SHIFT ) ;
if ( r ) {
DRM_ERROR ( " Failed initializing oa heap. \n " ) ;
return r ;
}
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 ;
}
void amdgpu_ttm_fini ( struct amdgpu_device * adev )
{
int r ;
if ( ! adev - > mman . initialized )
return ;
amdgpu_ttm_debugfs_fini ( adev ) ;
2017-08-08 07:48:01 -04:00
if ( adev - > stolen_vga_memory ) {
r = amdgpu_bo_reserve ( adev - > stolen_vga_memory , true ) ;
2015-04-20 16:55:21 -04:00
if ( r = = 0 ) {
2017-08-08 07:48:01 -04:00
amdgpu_bo_unpin ( adev - > stolen_vga_memory ) ;
amdgpu_bo_unreserve ( adev - > stolen_vga_memory ) ;
2015-04-20 16:55:21 -04:00
}
2017-08-08 07:48:01 -04:00
amdgpu_bo_unref ( & adev - > stolen_vga_memory ) ;
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 ) ;
2017-03-15 09:45:48 -04:00
if ( adev - > gds . mem . total_size )
ttm_bo_clean_mm ( & adev - > mman . bdev , AMDGPU_PL_GDS ) ;
if ( adev - > gds . gws . total_size )
ttm_bo_clean_mm ( & adev - > mman . bdev , AMDGPU_PL_GWS ) ;
if ( adev - > gds . oa . total_size )
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 ) ;
amdgpu_gart_fini ( adev ) ;
amdgpu_ttm_global_fini ( adev ) ;
adev - > mman . initialized = false ;
DRM_INFO ( " amdgpu: ttm finalized \n " ) ;
}
/* this should only be called at bootup or when userspace
* isn ' t running */
void amdgpu_ttm_set_active_vram_size ( struct amdgpu_device * adev , u64 size )
{
struct ttm_mem_type_manager * man ;
if ( ! adev - > mman . initialized )
return ;
man = & adev - > mman . bdev . man [ TTM_PL_VRAM ] ;
/* this just adjusts TTM size idea, which sets lpfn to the correct value */
man - > size = size > > PAGE_SHIFT ;
}
int amdgpu_mmap ( struct file * filp , struct vm_area_struct * vma )
{
struct drm_file * file_priv ;
struct amdgpu_device * adev ;
2015-05-27 10:22:47 +02:00
if ( unlikely ( vma - > vm_pgoff < DRM_FILE_PAGE_OFFSET ) )
2015-04-20 16:55:21 -04:00
return - EINVAL ;
file_priv = filp - > private_data ;
adev = file_priv - > minor - > dev - > dev_private ;
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 ) ;
2017-07-07 11:56:59 +02:00
* addr = adev - > mc . 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 ;
dst_addr = adev - > gart . table_addr ;
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 ;
r = amdgpu_job_submit ( job , ring , & adev - > mman . entity ,
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 ;
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
2017-06-29 11:46:15 +02:00
job - > vm_needs_flush = vm_needs_flush ;
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 ) ;
2016-08-15 10:46:04 +08:00
if ( direct_submit ) {
r = amdgpu_ib_schedule ( ring , job - > num_ibs , job - > ibs ,
2017-01-23 16:30:38 +08:00
NULL , fence ) ;
2016-10-25 13:00:45 +01:00
job - > fence = dma_fence_get ( * fence ) ;
2016-08-15 10:46:04 +08:00
if ( r )
DRM_ERROR ( " Error scheduling IBs (%d) \n " , r ) ;
amdgpu_job_free ( job ) ;
} else {
r = amdgpu_job_submit ( job , ring , & adev - > mman . entity ,
AMDGPU_FENCE_OWNER_UNDEFINED , fence ) ;
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 ) ;
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 ,
2017-07-20 18:44:10 -04:00
uint64_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 ) ;
2017-09-15 18:20:37 -04:00
uint32_t max_bytes = 8 *
adev - > vm_manager . vm_pte_funcs - > set_max_nums_pte_pde ;
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 ;
2016-11-17 12:06:38 +01:00
if ( ! ring - > ready ) {
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 ;
}
2017-07-20 18:44:10 -04:00
2017-09-15 18:20:37 -04:00
/* num of dwords for each SDMA_OP_PTEPDE cmd */
num_dw = num_loops * adev - > vm_manager . vm_pte_funcs - > set_pte_pde_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-07-20 18:44:10 -04:00
WARN_ONCE ( byte_count & 0x7 , " size should be a multiple of 8 " ) ;
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 ) ;
2017-07-20 18:44:10 -04:00
amdgpu_vm_set_pte_pde ( adev , & job - > ibs [ 0 ] ,
dst_addr , 0 ,
cur_size_in_bytes > > 3 , 0 ,
src_data ) ;
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 ) ;
r = amdgpu_job_submit ( job , ring , & 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 ;
unsigned ttm_pl = * ( int * ) node - > info_ent - > data ;
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
}
static int ttm_pl_vram = TTM_PL_VRAM ;
static int ttm_pl_tt = TTM_PL_TT ;
2016-05-02 12:46:15 -04:00
static const struct drm_info_list amdgpu_ttm_debugfs_list [ ] = {
2015-04-20 16:55:21 -04:00
{ " amdgpu_vram_mm " , amdgpu_mm_dump_table , 0 , & ttm_pl_vram } ,
{ " amdgpu_gtt_mm " , amdgpu_mm_dump_table , 0 , & ttm_pl_tt } ,
{ " ttm_page_pool " , ttm_page_alloc_debugfs , 0 , NULL } ,
# ifdef CONFIG_SWIOTLB
{ " ttm_dma_page_pool " , ttm_dma_page_alloc_debugfs , 0 , NULL }
# endif
} ;
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 ;
2017-05-23 11:35:22 -04:00
if ( * pos > = adev - > mc . mc_vram_size )
return - ENXIO ;
2015-04-20 16:55:21 -04:00
while ( size ) {
unsigned long flags ;
uint32_t value ;
if ( * pos > = adev - > mc . mc_vram_size )
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 ;
}
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 ;
if ( * pos > = adev - > mc . mc_vram_size )
return - ENXIO ;
while ( size ) {
unsigned long flags ;
uint32_t value ;
if ( * pos > = adev - > mc . mc_vram_size )
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
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
2017-09-18 07:28:14 -04:00
static ssize_t amdgpu_iova_to_phys_read ( struct file * f , char __user * buf ,
size_t size , loff_t * pos )
{
struct amdgpu_device * adev = file_inode ( f ) - > i_private ;
int r ;
uint64_t phys ;
struct iommu_domain * dom ;
2017-09-19 11:29:04 -04:00
// always return 8 bytes
if ( size ! = 8 )
return - EINVAL ;
2017-09-18 07:28:14 -04:00
2017-09-19 11:29:04 -04:00
// only accept page addresses
if ( * pos & 0xFFF )
return - EINVAL ;
2017-09-18 07:28:14 -04:00
dom = iommu_get_domain_for_dev ( adev - > dev ) ;
2017-09-19 11:29:04 -04:00
if ( dom )
2017-09-18 07:28:14 -04:00
phys = iommu_iova_to_phys ( dom , * pos ) ;
2017-09-19 11:29:04 -04:00
else
phys = * pos ;
2017-09-18 07:14:56 -04:00
2017-09-19 11:29:04 -04:00
r = copy_to_user ( buf , & phys , 8 ) ;
if ( r )
return - EFAULT ;
2017-09-18 07:28:14 -04:00
2017-09-19 11:29:04 -04:00
return 8 ;
2017-09-18 07:28:14 -04:00
}
static const struct file_operations amdgpu_ttm_iova_fops = {
. owner = THIS_MODULE ,
. read = amdgpu_iova_to_phys_read ,
. 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
2017-09-18 07:28:14 -04:00
{ " amdgpu_iova " , & amdgpu_ttm_iova_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 )
i_size_write ( ent - > d_inode , adev - > mc . mc_vram_size ) ;
else if ( ttm_debugfs_entries [ count ] . domain = = TTM_PL_TT )
i_size_write ( ent - > d_inode , adev - > mc . gart_size ) ;
adev - > mman . debugfs_entries [ count ] = ent ;
}
2015-04-20 16:55:21 -04:00
count = ARRAY_SIZE ( amdgpu_ttm_debugfs_list ) ;
# ifdef CONFIG_SWIOTLB
if ( ! swiotlb_nr_tbl ( ) )
- - 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
}