2015-04-20 16:55:21 -04:00
/*
* Copyright 2008 Advanced Micro Devices , Inc .
* Copyright 2008 Red Hat Inc .
* Copyright 2009 Jerome Glisse .
*
* 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 , sublicense ,
* and / or sell copies of the Software , and to permit persons to whom the
* Software is furnished to do so , subject to the following conditions :
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software .
*
* THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND , EXPRESS OR
* IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY ,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT . IN NO EVENT SHALL
* THE COPYRIGHT HOLDER ( S ) OR AUTHOR ( S ) BE LIABLE FOR ANY CLAIM , DAMAGES OR
* OTHER LIABILITY , WHETHER IN AN ACTION OF CONTRACT , TORT OR OTHERWISE ,
* ARISING FROM , OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE .
*
* Authors : Dave Airlie
* Alex Deucher
* Jerome Glisse
*/
2016-10-25 13:00:45 +01:00
# include <linux/dma-fence-array.h>
2015-04-20 16:55:21 -04:00
# include <drm/drmP.h>
# include <drm/amdgpu_drm.h>
# include "amdgpu.h"
# include "amdgpu_trace.h"
/*
* GPUVM
* GPUVM is similar to the legacy gart on older asics , however
* rather than there being a single global gart table
* for the entire GPU , there are multiple VM page tables active
* at any given time . The VM page tables can contain a mix
* vram pages and system memory pages and system memory pages
* can be mapped as snooped ( cached system pages ) or unsnooped
* ( uncached system pages ) .
* Each VM has an ID associated with it and there is a page table
* associated with each VMID . When execting a command buffer ,
* the kernel tells the the ring what VMID to use for that command
* buffer . VMIDs are allocated dynamically as commands are submitted .
* The userspace drivers maintain their own address space and the kernel
* sets up their pages tables accordingly when they submit their
* command buffers and a VMID is assigned .
* Cayman / Trinity support up to 8 active VMs at any given time ;
* SI supports 16.
*/
2016-04-21 10:40:18 -04:00
/* Local structure. Encapsulate some VM table update parameters to reduce
* the number of function parameters
*/
2016-08-04 14:52:50 +02:00
struct amdgpu_pte_update_params {
2016-08-04 15:02:49 +02:00
/* amdgpu device we do this update for */
struct amdgpu_device * adev ;
2016-04-21 10:40:18 -04:00
/* address where to copy page table entries from */
uint64_t src ;
/* indirect buffer to fill with commands */
struct amdgpu_ib * ib ;
2016-08-12 13:29:18 +02:00
/* Function which actually does the update */
void ( * func ) ( struct amdgpu_pte_update_params * params , uint64_t pe ,
uint64_t addr , unsigned count , uint32_t incr ,
2016-09-21 16:19:19 +08:00
uint64_t flags ) ;
2016-08-15 11:46:21 +08:00
/* indicate update pt or its shadow */
bool shadow ;
2016-04-21 10:40:18 -04:00
} ;
2017-01-30 11:09:31 +01:00
/* Helper to disable partial resident texture feature from a fence callback */
struct amdgpu_prt_cb {
struct amdgpu_device * adev ;
struct dma_fence_cb cb ;
} ;
2015-04-20 16:55:21 -04:00
/**
* amdgpu_vm_num_pde - return the number of page directory entries
*
* @ adev : amdgpu_device pointer
*
2016-01-26 12:17:11 +01:00
* Calculate the number of page directory entries .
2015-04-20 16:55:21 -04:00
*/
static unsigned amdgpu_vm_num_pdes ( struct amdgpu_device * adev )
{
return adev - > vm_manager . max_pfn > > amdgpu_vm_block_size ;
}
/**
* amdgpu_vm_directory_size - returns the size of the page directory in bytes
*
* @ adev : amdgpu_device pointer
*
2016-01-26 12:17:11 +01:00
* Calculate the size of the page directory in bytes .
2015-04-20 16:55:21 -04:00
*/
static unsigned amdgpu_vm_directory_size ( struct amdgpu_device * adev )
{
return AMDGPU_GPU_PAGE_ALIGN ( amdgpu_vm_num_pdes ( adev ) * 8 ) ;
}
/**
2015-12-11 15:16:32 +01:00
* amdgpu_vm_get_pd_bo - add the VM PD to a validation list
2015-04-20 16:55:21 -04:00
*
* @ vm : vm providing the BOs
2015-12-11 14:39:05 +01:00
* @ validated : head of validation list
2015-12-11 15:16:32 +01:00
* @ entry : entry to add
2015-04-20 16:55:21 -04:00
*
* Add the page directory to the list of BOs to
2015-12-11 15:16:32 +01:00
* validate for command submission .
2015-04-20 16:55:21 -04:00
*/
2015-12-11 15:16:32 +01:00
void amdgpu_vm_get_pd_bo ( struct amdgpu_vm * vm ,
struct list_head * validated ,
struct amdgpu_bo_list_entry * entry )
2015-04-20 16:55:21 -04:00
{
2015-12-11 15:16:32 +01:00
entry - > robj = vm - > page_directory ;
entry - > priority = 0 ;
entry - > tv . bo = & vm - > page_directory - > tbo ;
entry - > tv . shared = true ;
2016-02-23 12:36:59 +01:00
entry - > user_pages = NULL ;
2015-12-11 15:16:32 +01:00
list_add ( & entry - > tv . head , validated ) ;
}
2015-04-20 16:55:21 -04:00
2015-12-11 15:16:32 +01:00
/**
2016-09-28 12:03:04 +02:00
* amdgpu_vm_validate_pt_bos - validate the page table BOs
2015-12-11 15:16:32 +01:00
*
2016-06-21 16:28:15 +02:00
* @ adev : amdgpu device pointer
2015-12-11 15:16:32 +01:00
* @ vm : vm providing the BOs
2016-09-28 12:03:04 +02:00
* @ validate : callback to do the validation
* @ param : parameter for the validation callback
2015-04-20 16:55:21 -04:00
*
2016-09-28 12:03:04 +02:00
* Validate the page table BOs on command submission if neccessary .
2015-04-20 16:55:21 -04:00
*/
2016-09-28 12:03:04 +02:00
int amdgpu_vm_validate_pt_bos ( struct amdgpu_device * adev , struct amdgpu_vm * vm ,
int ( * validate ) ( void * p , struct amdgpu_bo * bo ) ,
void * param )
2015-04-20 16:55:21 -04:00
{
2016-06-21 16:28:15 +02:00
uint64_t num_evictions ;
2015-12-11 21:01:23 +01:00
unsigned i ;
2016-09-28 12:03:04 +02:00
int r ;
2015-04-20 16:55:21 -04:00
2016-06-21 16:28:15 +02:00
/* We only need to validate the page tables
* if they aren ' t already valid .
*/
num_evictions = atomic64_read ( & adev - > num_evictions ) ;
if ( num_evictions = = vm - > last_eviction_counter )
2016-09-28 12:03:04 +02:00
return 0 ;
2016-06-21 16:28:15 +02:00
2015-04-20 16:55:21 -04:00
/* add the vm page table to the list */
2015-12-11 21:01:23 +01:00
for ( i = 0 ; i < = vm - > max_pde_used ; + + i ) {
2016-09-28 12:27:37 +02:00
struct amdgpu_bo * bo = vm - > page_tables [ i ] . bo ;
2015-12-11 21:01:23 +01:00
2016-09-28 12:27:37 +02:00
if ( ! bo )
2015-04-20 16:55:21 -04:00
continue ;
2016-09-28 12:27:37 +02:00
r = validate ( param , bo ) ;
2016-09-28 12:03:04 +02:00
if ( r )
return r ;
2015-04-20 16:55:21 -04:00
}
2016-01-11 15:35:21 +01:00
2016-09-28 12:03:04 +02:00
return 0 ;
2016-01-11 15:35:21 +01:00
}
/**
* amdgpu_vm_move_pt_bos_in_lru - move the PT BOs to the LRU tail
*
* @ adev : amdgpu device instance
* @ vm : vm providing the BOs
*
* Move the PT BOs to the tail of the LRU .
*/
void amdgpu_vm_move_pt_bos_in_lru ( struct amdgpu_device * adev ,
struct amdgpu_vm * vm )
{
struct ttm_bo_global * glob = adev - > mman . bdev . glob ;
unsigned i ;
spin_lock ( & glob - > lru_lock ) ;
for ( i = 0 ; i < = vm - > max_pde_used ; + + i ) {
2016-09-28 12:27:37 +02:00
struct amdgpu_bo * bo = vm - > page_tables [ i ] . bo ;
2016-01-11 15:35:21 +01:00
2016-09-28 12:27:37 +02:00
if ( ! bo )
2016-01-11 15:35:21 +01:00
continue ;
2016-09-28 12:27:37 +02:00
ttm_bo_move_to_lru_tail ( & bo - > tbo ) ;
2016-01-11 15:35:21 +01:00
}
spin_unlock ( & glob - > lru_lock ) ;
2015-04-20 16:55:21 -04:00
}
2017-03-13 10:13:37 +01:00
/**
* amdgpu_vm_alloc_pts - Allocate page tables .
*
* @ adev : amdgpu_device pointer
* @ vm : VM to allocate page tables for
* @ saddr : Start address which needs to be allocated
* @ size : Size from start address we need .
*
* Make sure the page tables are allocated .
*/
int amdgpu_vm_alloc_pts ( struct amdgpu_device * adev ,
struct amdgpu_vm * vm ,
uint64_t saddr , uint64_t size )
{
unsigned last_pfn , pt_idx ;
uint64_t eaddr ;
int r ;
/* validate the parameters */
if ( saddr & AMDGPU_GPU_PAGE_MASK | | size & AMDGPU_GPU_PAGE_MASK )
return - EINVAL ;
eaddr = saddr + size - 1 ;
last_pfn = eaddr / AMDGPU_GPU_PAGE_SIZE ;
if ( last_pfn > = adev - > vm_manager . max_pfn ) {
dev_err ( adev - > dev , " va above limit (0x%08X >= 0x%08X) \n " ,
last_pfn , adev - > vm_manager . max_pfn ) ;
return - EINVAL ;
}
saddr / = AMDGPU_GPU_PAGE_SIZE ;
eaddr / = AMDGPU_GPU_PAGE_SIZE ;
saddr > > = amdgpu_vm_block_size ;
eaddr > > = amdgpu_vm_block_size ;
BUG_ON ( eaddr > = amdgpu_vm_num_pdes ( adev ) ) ;
if ( eaddr > vm - > max_pde_used )
vm - > max_pde_used = eaddr ;
/* walk over the address space and allocate the page tables */
for ( pt_idx = saddr ; pt_idx < = eaddr ; + + pt_idx ) {
struct reservation_object * resv = vm - > page_directory - > tbo . resv ;
struct amdgpu_bo * pt ;
if ( vm - > page_tables [ pt_idx ] . bo )
continue ;
r = amdgpu_bo_create ( adev , AMDGPU_VM_PTE_COUNT * 8 ,
AMDGPU_GPU_PAGE_SIZE , true ,
AMDGPU_GEM_DOMAIN_VRAM ,
AMDGPU_GEM_CREATE_NO_CPU_ACCESS |
AMDGPU_GEM_CREATE_SHADOW |
AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS |
AMDGPU_GEM_CREATE_VRAM_CLEARED ,
NULL , resv , & pt ) ;
if ( r )
return r ;
/* Keep a reference to the page table to avoid freeing
* them up in the wrong order .
*/
pt - > parent = amdgpu_bo_ref ( vm - > page_directory ) ;
vm - > page_tables [ pt_idx ] . bo = pt ;
vm - > page_tables [ pt_idx ] . addr = 0 ;
}
return 0 ;
}
2016-06-29 14:01:15 +08:00
static bool amdgpu_vm_is_gpu_reset ( struct amdgpu_device * adev ,
struct amdgpu_vm_id * id )
{
return id - > current_gpu_reset_count ! =
atomic_read ( & adev - > gpu_reset_counter ) ? true : false ;
}
2015-04-20 16:55:21 -04:00
/**
* amdgpu_vm_grab_id - allocate the next free VMID
*
* @ vm : vm to allocate id for
2015-07-20 16:09:40 +02:00
* @ ring : ring we want to submit job to
* @ sync : sync object where we add dependencies
2016-01-18 17:01:42 +01:00
* @ fence : fence protecting ID from reuse
2015-04-20 16:55:21 -04:00
*
2015-07-20 16:09:40 +02:00
* Allocate an id for the vm , adding fences to the sync obj as necessary .
2015-04-20 16:55:21 -04:00
*/
2015-07-20 16:09:40 +02:00
int amdgpu_vm_grab_id ( struct amdgpu_vm * vm , struct amdgpu_ring * ring ,
2016-10-25 13:00:45 +01:00
struct amdgpu_sync * sync , struct dma_fence * fence ,
2016-07-01 17:59:01 +08:00
struct amdgpu_job * job )
2015-04-20 16:55:21 -04:00
{
struct amdgpu_device * adev = ring - > adev ;
2016-07-08 10:21:02 +02:00
uint64_t fence_context = adev - > fence_context + ring - > idx ;
2016-10-25 13:00:45 +01:00
struct dma_fence * updates = sync - > last_vm_update ;
2016-05-23 16:00:32 +02:00
struct amdgpu_vm_id * id , * idle ;
2016-10-25 13:00:45 +01:00
struct dma_fence * * fences ;
2016-06-01 10:47:36 +02:00
unsigned i ;
int r = 0 ;
fences = kmalloc_array ( sizeof ( void * ) , adev - > vm_manager . num_ids ,
GFP_KERNEL ) ;
if ( ! fences )
return - ENOMEM ;
2015-04-20 16:55:21 -04:00
2016-01-18 17:01:42 +01:00
mutex_lock ( & adev - > vm_manager . lock ) ;
2016-05-23 15:30:08 +02:00
/* Check if we have an idle VMID */
2016-06-01 10:47:36 +02:00
i = 0 ;
2016-05-23 16:00:32 +02:00
list_for_each_entry ( idle , & adev - > vm_manager . ids_lru , list ) {
2016-06-01 10:47:36 +02:00
fences [ i ] = amdgpu_sync_peek_fence ( & idle - > active , ring ) ;
if ( ! fences [ i ] )
2016-05-23 15:30:08 +02:00
break ;
2016-06-01 10:47:36 +02:00
+ + i ;
2016-05-23 15:30:08 +02:00
}
2016-06-01 10:47:36 +02:00
/* If we can't find a idle VMID to use, wait till one becomes available */
2016-05-23 16:00:32 +02:00
if ( & idle - > list = = & adev - > vm_manager . ids_lru ) {
2016-06-01 10:47:36 +02:00
u64 fence_context = adev - > vm_manager . fence_context + ring - > idx ;
unsigned seqno = + + adev - > vm_manager . seqno [ ring - > idx ] ;
2016-10-25 13:00:45 +01:00
struct dma_fence_array * array ;
2016-06-01 10:47:36 +02:00
unsigned j ;
for ( j = 0 ; j < i ; + + j )
2016-10-25 13:00:45 +01:00
dma_fence_get ( fences [ j ] ) ;
2016-06-01 10:47:36 +02:00
2016-10-25 13:00:45 +01:00
array = dma_fence_array_create ( i , fences , fence_context ,
2016-06-01 10:47:36 +02:00
seqno , true ) ;
if ( ! array ) {
for ( j = 0 ; j < i ; + + j )
2016-10-25 13:00:45 +01:00
dma_fence_put ( fences [ j ] ) ;
2016-06-01 10:47:36 +02:00
kfree ( fences ) ;
r = - ENOMEM ;
goto error ;
}
r = amdgpu_sync_fence ( ring - > adev , sync , & array - > base ) ;
2016-10-25 13:00:45 +01:00
dma_fence_put ( & array - > base ) ;
2016-06-01 10:47:36 +02:00
if ( r )
goto error ;
mutex_unlock ( & adev - > vm_manager . lock ) ;
return 0 ;
}
kfree ( fences ) ;
2016-07-01 17:59:01 +08:00
job - > vm_needs_flush = true ;
2016-06-01 10:47:36 +02:00
/* Check if we can use a VMID already assigned to this VM */
i = ring - > idx ;
do {
2016-10-25 13:00:45 +01:00
struct dma_fence * flushed ;
2016-06-01 10:47:36 +02:00
id = vm - > ids [ i + + ] ;
if ( i = = AMDGPU_MAX_RINGS )
i = 0 ;
2016-05-23 16:00:32 +02:00
2016-06-01 10:47:36 +02:00
/* Check all the prerequisites to using this VMID */
if ( ! id )
continue ;
2016-06-29 14:01:15 +08:00
if ( amdgpu_vm_is_gpu_reset ( adev , id ) )
2016-06-27 17:06:01 +08:00
continue ;
2016-06-01 10:47:36 +02:00
if ( atomic64_read ( & id - > owner ) ! = vm - > client_id )
continue ;
2016-07-01 17:59:01 +08:00
if ( job - > vm_pd_addr ! = id - > pd_gpu_addr )
2016-06-01 10:47:36 +02:00
continue ;
2016-07-08 10:21:02 +02:00
if ( ! id - > last_flush )
continue ;
if ( id - > last_flush - > context ! = fence_context & &
2016-10-25 13:00:45 +01:00
! dma_fence_is_signaled ( id - > last_flush ) )
2016-06-01 10:47:36 +02:00
continue ;
flushed = id - > flushed_updates ;
if ( updates & &
2016-10-25 13:00:45 +01:00
( ! flushed | | dma_fence_is_later ( updates , flushed ) ) )
2016-06-01 10:47:36 +02:00
continue ;
2016-06-01 13:31:17 +02:00
/* Good we can use this VMID. Remember this submission as
* user of the VMID .
*/
2016-06-01 10:47:36 +02:00
r = amdgpu_sync_fence ( ring - > adev , & id - > active , fence ) ;
if ( r )
goto error ;
2016-05-23 16:00:32 +02:00
2016-06-27 17:06:01 +08:00
id - > current_gpu_reset_count = atomic_read ( & adev - > gpu_reset_counter ) ;
2016-06-01 10:47:36 +02:00
list_move_tail ( & id - > list , & adev - > vm_manager . ids_lru ) ;
vm - > ids [ ring - > idx ] = id ;
2016-05-23 16:00:32 +02:00
2016-07-01 17:59:01 +08:00
job - > vm_id = id - adev - > vm_manager . ids ;
job - > vm_needs_flush = false ;
2016-07-08 10:48:24 +02:00
trace_amdgpu_vm_grab_id ( vm , ring - > idx , job ) ;
2016-05-23 16:00:32 +02:00
2016-06-01 10:47:36 +02:00
mutex_unlock ( & adev - > vm_manager . lock ) ;
return 0 ;
2016-05-23 16:00:32 +02:00
2016-06-01 10:47:36 +02:00
} while ( i ! = ring - > idx ) ;
2016-05-23 16:00:32 +02:00
2016-06-01 10:47:36 +02:00
/* Still no ID to use? Then use the idle one found earlier */
id = idle ;
2016-03-17 11:41:37 +08:00
2016-06-01 10:47:36 +02:00
/* Remember this submission as user of the VMID */
r = amdgpu_sync_fence ( ring - > adev , & id - > active , fence ) ;
2016-02-15 12:33:02 +01:00
if ( r )
goto error ;
2016-01-18 17:01:42 +01:00
2016-10-25 13:00:45 +01:00
dma_fence_put ( id - > first ) ;
id - > first = dma_fence_get ( fence ) ;
2016-01-18 17:01:42 +01:00
2016-10-25 13:00:45 +01:00
dma_fence_put ( id - > last_flush ) ;
2016-03-01 16:46:18 +01:00
id - > last_flush = NULL ;
2016-10-25 13:00:45 +01:00
dma_fence_put ( id - > flushed_updates ) ;
id - > flushed_updates = dma_fence_get ( updates ) ;
2016-01-18 17:01:42 +01:00
2016-07-01 17:59:01 +08:00
id - > pd_gpu_addr = job - > vm_pd_addr ;
2016-06-27 17:04:23 +08:00
id - > current_gpu_reset_count = atomic_read ( & adev - > gpu_reset_counter ) ;
2016-02-15 12:33:02 +01:00
list_move_tail ( & id - > list , & adev - > vm_manager . ids_lru ) ;
2016-05-04 10:20:01 +02:00
atomic64_set ( & id - > owner , vm - > client_id ) ;
2016-02-15 12:33:02 +01:00
vm - > ids [ ring - > idx ] = id ;
2015-04-20 16:55:21 -04:00
2016-07-01 17:59:01 +08:00
job - > vm_id = id - adev - > vm_manager . ids ;
2016-07-08 10:48:24 +02:00
trace_amdgpu_vm_grab_id ( vm , ring - > idx , job ) ;
2016-02-15 12:33:02 +01:00
error :
2016-01-18 17:01:42 +01:00
mutex_unlock ( & adev - > vm_manager . lock ) ;
2016-01-21 10:19:11 +01:00
return r ;
2015-04-20 16:55:21 -04:00
}
2016-06-17 17:05:15 -04:00
static bool amdgpu_vm_ring_has_compute_vm_bug ( struct amdgpu_ring * ring )
{
struct amdgpu_device * adev = ring - > adev ;
2016-10-13 17:41:13 -04:00
const struct amdgpu_ip_block * ip_block ;
2016-06-17 17:05:15 -04:00
2016-10-05 15:36:39 +02:00
if ( ring - > funcs - > type ! = AMDGPU_RING_TYPE_COMPUTE )
2016-06-17 17:05:15 -04:00
/* only compute rings */
return false ;
ip_block = amdgpu_get_ip_block ( adev , AMD_IP_BLOCK_TYPE_GFX ) ;
if ( ! ip_block )
return false ;
2016-10-13 17:41:13 -04:00
if ( ip_block - > version - > major < = 7 ) {
2016-06-17 17:05:15 -04:00
/* gfx7 has no workaround */
return true ;
2016-10-13 17:41:13 -04:00
} else if ( ip_block - > version - > major = = 8 ) {
2016-06-17 17:05:15 -04:00
if ( adev - > gfx . mec_fw_version > = 673 )
/* gfx8 is fixed in MEC firmware 673 */
return false ;
else
return true ;
}
return false ;
}
2017-03-09 11:36:26 -05:00
static u64 amdgpu_vm_adjust_mc_addr ( struct amdgpu_device * adev , u64 mc_addr )
{
u64 addr = mc_addr ;
if ( adev - > mc . mc_funcs & & adev - > mc . mc_funcs - > adjust_mc_addr )
addr = adev - > mc . mc_funcs - > adjust_mc_addr ( adev , addr ) ;
return addr ;
}
2015-04-20 16:55:21 -04:00
/**
* amdgpu_vm_flush - hardware flush the vm
*
* @ ring : ring to use for flush
2016-03-01 13:34:49 +01:00
* @ vm_id : vmid number to use
2016-02-26 16:18:26 +01:00
* @ pd_addr : address of the page directory
2015-04-20 16:55:21 -04:00
*
2016-02-26 16:18:26 +01:00
* Emit a VM flush when it is necessary .
2015-04-20 16:55:21 -04:00
*/
2016-07-01 17:59:01 +08:00
int amdgpu_vm_flush ( struct amdgpu_ring * ring , struct amdgpu_job * job )
2015-04-20 16:55:21 -04:00
{
2016-03-01 15:09:25 +01:00
struct amdgpu_device * adev = ring - > adev ;
2016-07-01 17:59:01 +08:00
struct amdgpu_vm_id * id = & adev - > vm_manager . ids [ job - > vm_id ] ;
2016-03-01 15:51:53 +01:00
bool gds_switch_needed = ring - > funcs - > emit_gds_switch & & (
2016-07-01 17:59:01 +08:00
id - > gds_base ! = job - > gds_base | |
id - > gds_size ! = job - > gds_size | |
id - > gws_base ! = job - > gws_base | |
id - > gws_size ! = job - > gws_size | |
id - > oa_base ! = job - > oa_base | |
id - > oa_size ! = job - > oa_size ) ;
2016-03-01 16:46:18 +01:00
int r ;
2016-03-01 15:51:53 +01:00
if ( ring - > funcs - > emit_pipeline_sync & & (
2016-07-01 17:59:01 +08:00
job - > vm_needs_flush | | gds_switch_needed | |
2016-06-17 17:05:15 -04:00
amdgpu_vm_ring_has_compute_vm_bug ( ring ) ) )
2016-03-01 15:51:53 +01:00
amdgpu_ring_emit_pipeline_sync ( ring ) ;
2016-03-01 15:09:25 +01:00
2016-06-30 13:56:02 +08:00
if ( ring - > funcs - > emit_vm_flush & & ( job - > vm_needs_flush | |
amdgpu_vm_is_gpu_reset ( adev , id ) ) ) {
2016-10-25 13:00:45 +01:00
struct dma_fence * fence ;
2017-03-09 11:36:26 -05:00
u64 pd_addr = amdgpu_vm_adjust_mc_addr ( adev , job - > vm_pd_addr ) ;
2016-03-01 16:46:18 +01:00
2017-03-09 11:36:26 -05:00
trace_amdgpu_vm_flush ( pd_addr , ring - > idx , job - > vm_id ) ;
amdgpu_ring_emit_vm_flush ( ring , job - > vm_id , pd_addr ) ;
2016-03-01 16:46:18 +01:00
2016-06-01 13:31:17 +02:00
r = amdgpu_fence_emit ( ring , & fence ) ;
if ( r )
return r ;
2016-03-01 16:46:18 +01:00
mutex_lock ( & adev - > vm_manager . lock ) ;
2016-10-25 13:00:45 +01:00
dma_fence_put ( id - > last_flush ) ;
2016-06-01 13:31:17 +02:00
id - > last_flush = fence ;
2016-03-01 16:46:18 +01:00
mutex_unlock ( & adev - > vm_manager . lock ) ;
2015-04-20 16:55:21 -04:00
}
2016-03-01 13:34:49 +01:00
2016-03-01 15:51:53 +01:00
if ( gds_switch_needed ) {
2016-07-01 17:59:01 +08:00
id - > gds_base = job - > gds_base ;
id - > gds_size = job - > gds_size ;
id - > gws_base = job - > gws_base ;
id - > gws_size = job - > gws_size ;
id - > oa_base = job - > oa_base ;
id - > oa_size = job - > oa_size ;
amdgpu_ring_emit_gds_switch ( ring , job - > vm_id ,
job - > gds_base , job - > gds_size ,
job - > gws_base , job - > gws_size ,
job - > oa_base , job - > oa_size ) ;
2016-03-01 15:09:25 +01:00
}
2016-03-01 16:46:18 +01:00
return 0 ;
2016-03-01 15:09:25 +01:00
}
/**
* amdgpu_vm_reset_id - reset VMID to zero
*
* @ adev : amdgpu device structure
* @ vm_id : vmid number to use
*
* Reset saved GDW , GWS and OA to force switch on next flush .
*/
void amdgpu_vm_reset_id ( struct amdgpu_device * adev , unsigned vm_id )
{
2016-03-08 15:40:11 +01:00
struct amdgpu_vm_id * id = & adev - > vm_manager . ids [ vm_id ] ;
id - > gds_base = 0 ;
id - > gds_size = 0 ;
id - > gws_base = 0 ;
id - > gws_size = 0 ;
id - > oa_base = 0 ;
id - > oa_size = 0 ;
2015-04-20 16:55:21 -04:00
}
/**
* amdgpu_vm_bo_find - find the bo_va for a specific vm & bo
*
* @ vm : requested vm
* @ bo : requested buffer object
*
2016-01-26 12:17:11 +01:00
* Find @ bo inside the requested vm .
2015-04-20 16:55:21 -04:00
* Search inside the @ bos vm list for the requested vm
* Returns the found bo_va or NULL if none is found
*
* Object has to be reserved !
*/
struct amdgpu_bo_va * amdgpu_vm_bo_find ( struct amdgpu_vm * vm ,
struct amdgpu_bo * bo )
{
struct amdgpu_bo_va * bo_va ;
list_for_each_entry ( bo_va , & bo - > va , bo_list ) {
if ( bo_va - > vm = = vm ) {
return bo_va ;
}
}
return NULL ;
}
/**
2016-08-12 13:29:18 +02:00
* amdgpu_vm_do_set_ptes - helper to call the right asic function
2015-04-20 16:55:21 -04:00
*
2016-08-04 14:52:50 +02:00
* @ params : see amdgpu_pte_update_params definition
2015-04-20 16:55:21 -04:00
* @ pe : addr of the page entry
* @ addr : dst addr to write into pe
* @ count : number of page entries to update
* @ incr : increase next addr by incr bytes
* @ flags : hw access flags
*
* Traces the parameters and calls the right asic functions
* to setup the page table using the DMA .
*/
2016-08-12 13:29:18 +02:00
static void amdgpu_vm_do_set_ptes ( struct amdgpu_pte_update_params * params ,
uint64_t pe , uint64_t addr ,
unsigned count , uint32_t incr ,
2016-09-21 16:19:19 +08:00
uint64_t flags )
2015-04-20 16:55:21 -04:00
{
2016-09-25 16:11:52 +02:00
trace_amdgpu_vm_set_ptes ( pe , addr , count , incr , flags ) ;
2015-04-20 16:55:21 -04:00
2016-08-12 13:29:18 +02:00
if ( count < 3 ) {
2016-08-12 11:33:30 +02:00
amdgpu_vm_write_pte ( params - > adev , params - > ib , pe ,
addr | flags , count , incr ) ;
2015-04-20 16:55:21 -04:00
} else {
2016-08-04 15:02:49 +02:00
amdgpu_vm_set_pte_pde ( params - > adev , params - > ib , pe , addr ,
2015-04-20 16:55:21 -04:00
count , incr , flags ) ;
}
}
2016-08-12 13:29:18 +02:00
/**
* amdgpu_vm_do_copy_ptes - copy the PTEs from the GART
*
* @ params : see amdgpu_pte_update_params definition
* @ pe : addr of the page entry
* @ addr : dst addr to write into pe
* @ count : number of page entries to update
* @ incr : increase next addr by incr bytes
* @ flags : hw access flags
*
* Traces the parameters and calls the DMA function to copy the PTEs .
*/
static void amdgpu_vm_do_copy_ptes ( struct amdgpu_pte_update_params * params ,
uint64_t pe , uint64_t addr ,
unsigned count , uint32_t incr ,
2016-09-21 16:19:19 +08:00
uint64_t flags )
2016-08-12 13:29:18 +02:00
{
2016-09-25 16:11:52 +02:00
uint64_t src = ( params - > src + ( addr > > 12 ) * 8 ) ;
2016-08-12 13:29:18 +02:00
2016-09-25 16:11:52 +02:00
trace_amdgpu_vm_copy_ptes ( pe , src , count ) ;
amdgpu_vm_copy_pte ( params - > adev , params - > ib , pe , src , count ) ;
2016-08-12 13:29:18 +02:00
}
2015-04-20 16:55:21 -04:00
/**
2015-11-30 13:26:07 +01:00
* amdgpu_vm_map_gart - Resolve gart mapping of addr
2015-04-20 16:55:21 -04:00
*
2015-11-30 13:26:07 +01:00
* @ pages_addr : optional DMA address to use for lookup
2015-04-20 16:55:21 -04:00
* @ addr : the unmapped addr
*
* Look up the physical address of the page that the pte resolves
2015-11-30 13:26:07 +01:00
* to and return the pointer for the page table entry .
2015-04-20 16:55:21 -04:00
*/
2016-08-12 11:33:30 +02:00
static uint64_t amdgpu_vm_map_gart ( const dma_addr_t * pages_addr , uint64_t addr )
2015-04-20 16:55:21 -04:00
{
uint64_t result ;
2016-08-12 11:33:30 +02:00
/* page table offset */
result = pages_addr [ addr > > PAGE_SHIFT ] ;
2015-11-30 13:26:07 +01:00
2016-08-12 11:33:30 +02:00
/* in case cpu page size != gpu page size*/
result | = addr & ( ~ PAGE_MASK ) ;
2015-04-20 16:55:21 -04:00
2015-11-30 13:26:07 +01:00
result & = 0xFFFFFFFFFFFFF000ULL ;
2015-04-20 16:55:21 -04:00
return result ;
}
2016-09-16 15:36:49 +02:00
/*
* amdgpu_vm_update_pdes - make sure that page directory is valid
*
* @ adev : amdgpu_device pointer
* @ vm : requested vm
* @ start : start of GPU address range
* @ end : end of GPU address range
*
* Allocates new page tables if necessary
* and updates the page directory .
* Returns 0 for success , error for failure .
*/
int amdgpu_vm_update_page_directory ( struct amdgpu_device * adev ,
struct amdgpu_vm * vm )
2015-04-20 16:55:21 -04:00
{
2016-09-16 15:36:49 +02:00
struct amdgpu_bo * shadow ;
2016-02-08 17:37:38 +01:00
struct amdgpu_ring * ring ;
2016-09-16 15:36:49 +02:00
uint64_t pd_addr , shadow_addr ;
2015-04-20 16:55:21 -04:00
uint32_t incr = AMDGPU_VM_PTE_COUNT * 8 ;
2016-09-16 15:36:49 +02:00
uint64_t last_pde = ~ 0 , last_pt = ~ 0 , last_shadow = ~ 0 ;
2015-04-20 16:55:21 -04:00
unsigned count = 0 , pt_idx , ndw ;
2016-02-01 12:20:25 +01:00
struct amdgpu_job * job ;
2016-08-04 14:52:50 +02:00
struct amdgpu_pte_update_params params ;
2016-10-25 13:00:45 +01:00
struct dma_fence * fence = NULL ;
2015-07-21 16:52:10 +08:00
2015-04-20 16:55:21 -04:00
int r ;
2016-02-08 17:37:38 +01:00
ring = container_of ( vm - > entity . sched , struct amdgpu_ring , sched ) ;
2016-09-16 15:36:49 +02:00
shadow = vm - > page_directory - > shadow ;
2016-02-08 17:37:38 +01:00
2015-04-20 16:55:21 -04:00
/* padding, etc. */
ndw = 64 ;
/* assume the worst case */
ndw + = vm - > max_pde_used * 6 ;
2016-09-16 15:36:49 +02:00
pd_addr = amdgpu_bo_gpu_offset ( vm - > page_directory ) ;
if ( shadow ) {
r = amdgpu_ttm_bind ( & shadow - > tbo , & shadow - > tbo . mem ) ;
if ( r )
return r ;
shadow_addr = amdgpu_bo_gpu_offset ( shadow ) ;
ndw * = 2 ;
} else {
shadow_addr = 0 ;
}
2016-02-01 12:20:25 +01:00
r = amdgpu_job_alloc_with_ib ( adev , ndw * 4 , & job ) ;
if ( r )
2015-04-20 16:55:21 -04:00
return r ;
2016-02-01 12:20:25 +01:00
2016-08-04 15:02:49 +02:00
memset ( & params , 0 , sizeof ( params ) ) ;
params . adev = adev ;
2016-08-04 14:52:50 +02:00
params . ib = & job - > ibs [ 0 ] ;
2015-04-20 16:55:21 -04:00
/* walk over the address space and update the page directory */
for ( pt_idx = 0 ; pt_idx < = vm - > max_pde_used ; + + pt_idx ) {
2016-09-28 12:27:37 +02:00
struct amdgpu_bo * bo = vm - > page_tables [ pt_idx ] . bo ;
2015-04-20 16:55:21 -04:00
uint64_t pde , pt ;
if ( bo = = NULL )
continue ;
2016-09-16 11:46:23 +02:00
if ( bo - > shadow ) {
2016-09-16 15:36:49 +02:00
struct amdgpu_bo * pt_shadow = bo - > shadow ;
2016-09-16 11:46:23 +02:00
2016-09-16 15:36:49 +02:00
r = amdgpu_ttm_bind ( & pt_shadow - > tbo ,
& pt_shadow - > tbo . mem ) ;
2016-09-16 11:46:23 +02:00
if ( r )
return r ;
}
2015-04-20 16:55:21 -04:00
pt = amdgpu_bo_gpu_offset ( bo ) ;
2016-09-16 15:36:49 +02:00
if ( vm - > page_tables [ pt_idx ] . addr = = pt )
continue ;
vm - > page_tables [ pt_idx ] . addr = pt ;
2015-04-20 16:55:21 -04:00
pde = pd_addr + pt_idx * 8 ;
if ( ( ( last_pde + 8 * count ) ! = pde ) | |
2016-08-12 12:59:59 +02:00
( ( last_pt + incr * count ) ! = pt ) | |
( count = = AMDGPU_VM_MAX_UPDATE_SIZE ) ) {
2015-04-20 16:55:21 -04:00
if ( count ) {
2017-03-09 11:36:26 -05:00
uint64_t pt_addr =
amdgpu_vm_adjust_mc_addr ( adev , last_pt ) ;
2016-09-16 15:36:49 +02:00
if ( shadow )
amdgpu_vm_do_set_ptes ( & params ,
last_shadow ,
2017-03-09 11:36:26 -05:00
pt_addr , count ,
2016-09-16 15:36:49 +02:00
incr ,
AMDGPU_PTE_VALID ) ;
2016-08-12 13:29:18 +02:00
amdgpu_vm_do_set_ptes ( & params , last_pde ,
2017-03-09 11:36:26 -05:00
pt_addr , count , incr ,
2016-08-12 13:29:18 +02:00
AMDGPU_PTE_VALID ) ;
2015-04-20 16:55:21 -04:00
}
count = 1 ;
last_pde = pde ;
2016-09-16 15:36:49 +02:00
last_shadow = shadow_addr + pt_idx * 8 ;
2015-04-20 16:55:21 -04:00
last_pt = pt ;
} else {
+ + count ;
}
}
2016-09-16 15:36:49 +02:00
if ( count ) {
2017-03-09 11:36:26 -05:00
uint64_t pt_addr = amdgpu_vm_adjust_mc_addr ( adev , last_pt ) ;
2016-09-16 15:36:49 +02:00
if ( vm - > page_directory - > shadow )
2017-03-09 11:36:26 -05:00
amdgpu_vm_do_set_ptes ( & params , last_shadow , pt_addr ,
2016-09-16 15:36:49 +02:00
count , incr , AMDGPU_PTE_VALID ) ;
2017-03-09 11:36:26 -05:00
amdgpu_vm_do_set_ptes ( & params , last_pde , pt_addr ,
2016-08-12 13:29:18 +02:00
count , incr , AMDGPU_PTE_VALID ) ;
2016-09-16 15:36:49 +02:00
}
2015-04-20 16:55:21 -04:00
2016-09-16 15:36:49 +02:00
if ( params . ib - > length_dw = = 0 ) {
amdgpu_job_free ( job ) ;
return 0 ;
}
amdgpu_ring_pad_ib ( ring , params . ib ) ;
amdgpu_sync_resv ( adev , & job - > sync , vm - > page_directory - > tbo . resv ,
AMDGPU_FENCE_OWNER_VM ) ;
if ( shadow )
amdgpu_sync_resv ( adev , & job - > sync , shadow - > tbo . resv ,
2016-02-08 12:13:05 +01:00
AMDGPU_FENCE_OWNER_VM ) ;
2015-08-14 20:08:40 +02:00
2016-09-16 15:36:49 +02:00
WARN_ON ( params . ib - > length_dw > ndw ) ;
r = amdgpu_job_submit ( job , ring , & vm - > entity ,
AMDGPU_FENCE_OWNER_VM , & fence ) ;
if ( r )
goto error_free ;
2015-07-21 16:52:10 +08:00
2016-09-16 15:36:49 +02:00
amdgpu_bo_fence ( vm - > page_directory , fence , true ) ;
2016-10-28 11:33:52 +10:00
dma_fence_put ( vm - > page_directory_fence ) ;
vm - > page_directory_fence = dma_fence_get ( fence ) ;
dma_fence_put ( fence ) ;
2015-04-20 16:55:21 -04:00
return 0 ;
2015-07-21 16:52:10 +08:00
error_free :
2016-02-01 12:20:25 +01:00
amdgpu_job_free ( job ) ;
2015-08-03 12:57:31 +08:00
return r ;
2015-04-20 16:55:21 -04:00
}
/**
* amdgpu_vm_update_ptes - make sure that page tables are valid
*
2016-08-04 14:52:50 +02:00
* @ params : see amdgpu_pte_update_params definition
2015-04-20 16:55:21 -04:00
* @ vm : requested vm
* @ start : start of GPU address range
* @ end : end of GPU address range
2016-06-06 18:13:26 -04:00
* @ dst : destination address to map to , the next dst inside the function
2015-04-20 16:55:21 -04:00
* @ flags : mapping flags
*
2016-01-26 12:17:11 +01:00
* Update the page tables in the range @ start - @ end .
2015-04-20 16:55:21 -04:00
*/
2016-08-04 15:02:49 +02:00
static void amdgpu_vm_update_ptes ( struct amdgpu_pte_update_params * params ,
2016-01-26 11:40:46 +01:00
struct amdgpu_vm * vm ,
uint64_t start , uint64_t end ,
2016-09-21 16:19:19 +08:00
uint64_t dst , uint64_t flags )
2015-04-20 16:55:21 -04:00
{
2016-01-26 12:37:49 +01:00
const uint64_t mask = AMDGPU_VM_PTE_COUNT - 1 ;
2016-08-05 13:56:35 +02:00
uint64_t cur_pe_start , cur_nptes , cur_dst ;
2016-06-06 18:13:26 -04:00
uint64_t addr ; /* next GPU address to be updated */
2016-06-06 18:21:09 -04:00
uint64_t pt_idx ;
struct amdgpu_bo * pt ;
unsigned nptes ; /* next number of ptes to be updated */
uint64_t next_pe_start ;
/* initialize the variables */
addr = start ;
pt_idx = addr > > amdgpu_vm_block_size ;
2016-09-28 12:27:37 +02:00
pt = vm - > page_tables [ pt_idx ] . bo ;
2016-08-15 11:46:21 +08:00
if ( params - > shadow ) {
if ( ! pt - > shadow )
return ;
2016-09-28 12:27:37 +02:00
pt = pt - > shadow ;
2016-08-15 11:46:21 +08:00
}
2016-06-06 18:21:09 -04:00
if ( ( addr & ~ mask ) = = ( end & ~ mask ) )
nptes = end - addr ;
else
nptes = AMDGPU_VM_PTE_COUNT - ( addr & mask ) ;
cur_pe_start = amdgpu_bo_gpu_offset ( pt ) ;
cur_pe_start + = ( addr & mask ) * 8 ;
2016-08-05 13:56:35 +02:00
cur_nptes = nptes ;
2016-06-06 18:21:09 -04:00
cur_dst = dst ;
/* for next ptb*/
addr + = nptes ;
dst + = nptes * AMDGPU_GPU_PAGE_SIZE ;
2015-04-20 16:55:21 -04:00
/* walk over the address space and update the page tables */
2016-06-06 18:21:09 -04:00
while ( addr < end ) {
pt_idx = addr > > amdgpu_vm_block_size ;
2016-09-28 12:27:37 +02:00
pt = vm - > page_tables [ pt_idx ] . bo ;
2016-08-15 11:46:21 +08:00
if ( params - > shadow ) {
if ( ! pt - > shadow )
return ;
2016-09-28 12:27:37 +02:00
pt = pt - > shadow ;
2016-08-15 11:46:21 +08:00
}
2015-04-20 16:55:21 -04:00
if ( ( addr & ~ mask ) = = ( end & ~ mask ) )
nptes = end - addr ;
else
nptes = AMDGPU_VM_PTE_COUNT - ( addr & mask ) ;
2016-06-06 18:13:26 -04:00
next_pe_start = amdgpu_bo_gpu_offset ( pt ) ;
next_pe_start + = ( addr & mask ) * 8 ;
2015-04-20 16:55:21 -04:00
2016-08-12 12:59:59 +02:00
if ( ( cur_pe_start + 8 * cur_nptes ) = = next_pe_start & &
( ( cur_nptes + nptes ) < = AMDGPU_VM_MAX_UPDATE_SIZE ) ) {
2016-06-06 18:14:57 -04:00
/* The next ptb is consecutive to current ptb.
2016-08-12 13:29:18 +02:00
* Don ' t call the update function now .
2016-06-06 18:14:57 -04:00
* Will update two ptbs together in future .
*/
2016-08-05 13:56:35 +02:00
cur_nptes + = nptes ;
2016-06-06 18:14:57 -04:00
} else {
2016-08-12 13:29:18 +02:00
params - > func ( params , cur_pe_start , cur_dst , cur_nptes ,
AMDGPU_GPU_PAGE_SIZE , flags ) ;
2015-04-20 16:55:21 -04:00
2016-06-06 18:13:26 -04:00
cur_pe_start = next_pe_start ;
2016-08-05 13:56:35 +02:00
cur_nptes = nptes ;
2016-06-06 18:13:26 -04:00
cur_dst = dst ;
2015-04-20 16:55:21 -04:00
}
2016-06-06 18:21:09 -04:00
/* for next ptb*/
2015-04-20 16:55:21 -04:00
addr + = nptes ;
dst + = nptes * AMDGPU_GPU_PAGE_SIZE ;
}
2016-08-12 13:29:18 +02:00
params - > func ( params , cur_pe_start , cur_dst , cur_nptes ,
AMDGPU_GPU_PAGE_SIZE , flags ) ;
2016-08-05 13:56:35 +02:00
}
/*
* amdgpu_vm_frag_ptes - add fragment information to PTEs
*
* @ params : see amdgpu_pte_update_params definition
* @ vm : requested vm
* @ start : first PTE to handle
* @ end : last PTE to handle
* @ dst : addr those PTEs should point to
* @ flags : hw mapping flags
*/
static void amdgpu_vm_frag_ptes ( struct amdgpu_pte_update_params * params ,
struct amdgpu_vm * vm ,
uint64_t start , uint64_t end ,
2016-09-21 16:19:19 +08:00
uint64_t dst , uint64_t flags )
2016-08-05 13:56:35 +02:00
{
/**
* The MC L1 TLB supports variable sized pages , based on a fragment
* field in the PTE . When this field is set to a non - zero value , page
* granularity is increased from 4 KB to ( 1 < < ( 12 + frag ) ) . The PTE
* flags are considered valid for all PTEs within the fragment range
* and corresponding mappings are assumed to be physically contiguous .
*
* The L1 TLB can store a single PTE for the whole fragment ,
* significantly increasing the space available for translation
* caching . This leads to large improvements in throughput when the
* TLB is under pressure .
*
* The L2 TLB distributes small and large fragments into two
* asymmetric partitions . The large fragment cache is significantly
* larger . Thus , we try to use large fragments wherever possible .
* Userspace can support this by aligning virtual base address and
* allocation size to the fragment size .
*/
2016-10-04 13:39:43 +02:00
/* SI and newer are optimized for 64KB */
uint64_t frag_flags = AMDGPU_PTE_FRAG ( AMDGPU_LOG2_PAGES_PER_FRAG ) ;
uint64_t frag_align = 1 < < AMDGPU_LOG2_PAGES_PER_FRAG ;
2016-08-05 13:56:35 +02:00
uint64_t frag_start = ALIGN ( start , frag_align ) ;
uint64_t frag_end = end & ~ ( frag_align - 1 ) ;
/* system pages are non continuously */
2016-08-11 16:44:15 +02:00
if ( params - > src | | ! ( flags & AMDGPU_PTE_VALID ) | |
2016-08-05 13:56:35 +02:00
( frag_start > = frag_end ) ) {
amdgpu_vm_update_ptes ( params , vm , start , end , dst , flags ) ;
return ;
}
/* handle the 4K area at the beginning */
if ( start ! = frag_start ) {
amdgpu_vm_update_ptes ( params , vm , start , frag_start ,
dst , flags ) ;
dst + = ( frag_start - start ) * AMDGPU_GPU_PAGE_SIZE ;
}
/* handle the area in the middle */
amdgpu_vm_update_ptes ( params , vm , frag_start , frag_end , dst ,
2016-10-04 13:39:43 +02:00
flags | frag_flags ) ;
2016-08-05 13:56:35 +02:00
/* handle the 4K area at the end */
if ( frag_end ! = end ) {
dst + = ( frag_end - frag_start ) * AMDGPU_GPU_PAGE_SIZE ;
amdgpu_vm_update_ptes ( params , vm , frag_end , end , dst , flags ) ;
}
2015-04-20 16:55:21 -04:00
}
/**
* amdgpu_vm_bo_update_mapping - update a mapping in the vm page table
*
* @ adev : amdgpu_device pointer
2016-06-06 10:17:58 +02:00
* @ exclusive : fence we need to sync to
2016-03-18 21:00:35 +01:00
* @ src : address where to copy page table entries from
* @ pages_addr : DMA addresses to use for mapping
2015-04-20 16:55:21 -04:00
* @ vm : requested vm
2016-01-25 14:27:31 +01:00
* @ start : start of mapped range
* @ last : last mapped entry
* @ flags : flags for the entries
2015-04-20 16:55:21 -04:00
* @ addr : addr to set the area to
* @ fence : optional resulting fence
*
2016-01-25 14:27:31 +01:00
* Fill in the page table entries between @ start and @ last .
2015-04-20 16:55:21 -04:00
* Returns 0 for success , - EINVAL for failure .
*/
static int amdgpu_vm_bo_update_mapping ( struct amdgpu_device * adev ,
2016-10-25 13:00:45 +01:00
struct dma_fence * exclusive ,
2016-03-18 21:00:35 +01:00
uint64_t src ,
dma_addr_t * pages_addr ,
2015-04-20 16:55:21 -04:00
struct amdgpu_vm * vm ,
2016-01-25 14:27:31 +01:00
uint64_t start , uint64_t last ,
2016-09-21 16:19:19 +08:00
uint64_t flags , uint64_t addr ,
2016-10-25 13:00:45 +01:00
struct dma_fence * * fence )
2015-04-20 16:55:21 -04:00
{
2016-02-08 17:37:38 +01:00
struct amdgpu_ring * ring ;
2016-01-26 11:40:46 +01:00
void * owner = AMDGPU_FENCE_OWNER_VM ;
2015-04-20 16:55:21 -04:00
unsigned nptes , ncmds , ndw ;
2016-02-01 12:20:25 +01:00
struct amdgpu_job * job ;
2016-08-04 14:52:50 +02:00
struct amdgpu_pte_update_params params ;
2016-10-25 13:00:45 +01:00
struct dma_fence * f = NULL ;
2015-04-20 16:55:21 -04:00
int r ;
2016-08-12 13:29:18 +02:00
memset ( & params , 0 , sizeof ( params ) ) ;
params . adev = adev ;
params . src = src ;
2016-02-08 17:37:38 +01:00
ring = container_of ( vm - > entity . sched , struct amdgpu_ring , sched ) ;
2016-08-04 15:02:49 +02:00
2016-01-26 11:40:46 +01:00
/* sync to everything on unmapping */
if ( ! ( flags & AMDGPU_PTE_VALID ) )
owner = AMDGPU_FENCE_OWNER_UNDEFINED ;
2016-01-25 14:27:31 +01:00
nptes = last - start + 1 ;
2015-04-20 16:55:21 -04:00
/*
* reserve space for one command every ( 1 < < BLOCK_SIZE )
* entries or 2 k dwords ( whatever is smaller )
*/
ncmds = ( nptes > > min ( amdgpu_vm_block_size , 11 ) ) + 1 ;
/* padding, etc. */
ndw = 64 ;
2016-08-11 14:06:54 +02:00
if ( src ) {
2015-04-20 16:55:21 -04:00
/* only copy commands needed */
ndw + = ncmds * 7 ;
2016-08-12 13:29:18 +02:00
params . func = amdgpu_vm_do_copy_ptes ;
2016-08-11 14:06:54 +02:00
} else if ( pages_addr ) {
/* copy commands needed */
ndw + = ncmds * 7 ;
2015-04-20 16:55:21 -04:00
2016-08-11 14:06:54 +02:00
/* and also PTEs */
2015-04-20 16:55:21 -04:00
ndw + = nptes * 2 ;
2016-08-12 13:29:18 +02:00
params . func = amdgpu_vm_do_copy_ptes ;
2015-04-20 16:55:21 -04:00
} else {
/* set page commands needed */
ndw + = ncmds * 10 ;
/* two extra commands for begin/end of fragment */
ndw + = 2 * 10 ;
2016-08-12 13:29:18 +02:00
params . func = amdgpu_vm_do_set_ptes ;
2015-04-20 16:55:21 -04:00
}
2016-02-01 12:20:25 +01:00
r = amdgpu_job_alloc_with_ib ( adev , ndw * 4 , & job ) ;
if ( r )
2015-04-20 16:55:21 -04:00
return r ;
2016-02-01 12:20:25 +01:00
2016-08-04 14:52:50 +02:00
params . ib = & job - > ibs [ 0 ] ;
2015-07-21 16:52:10 +08:00
2016-08-11 14:06:54 +02:00
if ( ! src & & pages_addr ) {
uint64_t * pte ;
unsigned i ;
/* Put the PTEs at the end of the IB. */
i = ndw - nptes * 2 ;
pte = ( uint64_t * ) & ( job - > ibs - > ptr [ i ] ) ;
params . src = job - > ibs - > gpu_addr + i * 4 ;
for ( i = 0 ; i < nptes ; + + i ) {
pte [ i ] = amdgpu_vm_map_gart ( pages_addr , addr + i *
AMDGPU_GPU_PAGE_SIZE ) ;
pte [ i ] | = flags ;
}
2016-09-25 11:54:00 +02:00
addr = 0 ;
2016-08-11 14:06:54 +02:00
}
2016-06-06 10:17:58 +02:00
r = amdgpu_sync_fence ( adev , & job - > sync , exclusive ) ;
if ( r )
goto error_free ;
2016-02-08 12:13:05 +01:00
r = amdgpu_sync_resv ( adev , & job - > sync , vm - > page_directory - > tbo . resv ,
2016-01-26 11:40:46 +01:00
owner ) ;
if ( r )
goto error_free ;
2015-04-20 16:55:21 -04:00
2016-01-26 11:40:46 +01:00
r = reservation_object_reserve_shared ( vm - > page_directory - > tbo . resv ) ;
if ( r )
goto error_free ;
2016-08-15 11:46:21 +08:00
params . shadow = true ;
amdgpu_vm_frag_ptes ( & params , vm , start , last + 1 , addr , flags ) ;
params . shadow = false ;
2016-08-05 13:56:35 +02:00
amdgpu_vm_frag_ptes ( & params , vm , start , last + 1 , addr , flags ) ;
2015-04-20 16:55:21 -04:00
2016-08-04 14:52:50 +02:00
amdgpu_ring_pad_ib ( ring , params . ib ) ;
WARN_ON ( params . ib - > length_dw > ndw ) ;
2016-02-01 12:53:58 +01:00
r = amdgpu_job_submit ( job , ring , & vm - > entity ,
AMDGPU_FENCE_OWNER_VM , & f ) ;
2015-08-03 12:57:31 +08:00
if ( r )
goto error_free ;
2015-04-20 16:55:21 -04:00
2015-09-04 10:47:56 +02:00
amdgpu_bo_fence ( vm - > page_directory , f , true ) ;
2017-01-30 11:09:31 +01:00
dma_fence_put ( * fence ) ;
* fence = f ;
2015-04-20 16:55:21 -04:00
return 0 ;
2015-07-21 16:52:10 +08:00
error_free :
2016-02-01 12:20:25 +01:00
amdgpu_job_free ( job ) ;
2015-08-03 12:57:31 +08:00
return r ;
2015-04-20 16:55:21 -04:00
}
2016-01-25 14:27:31 +01:00
/**
* amdgpu_vm_bo_split_mapping - split a mapping into smaller chunks
*
* @ adev : amdgpu_device pointer
2016-06-06 10:17:58 +02:00
* @ exclusive : fence we need to sync to
2016-03-30 10:50:25 +02:00
* @ gtt_flags : flags as they are used for GTT
* @ pages_addr : DMA addresses to use for mapping
2016-01-25 14:27:31 +01:00
* @ vm : requested vm
* @ mapping : mapped range and flags to use for the update
2016-03-30 10:50:25 +02:00
* @ flags : HW flags for the mapping
2016-08-16 17:38:37 +02:00
* @ nodes : array of drm_mm_nodes with the MC addresses
2016-01-25 14:27:31 +01:00
* @ fence : optional resulting fence
*
* Split the mapping into smaller chunks so that each update fits
* into a SDMA IB .
* Returns 0 for success , - EINVAL for failure .
*/
static int amdgpu_vm_bo_split_mapping ( struct amdgpu_device * adev ,
2016-10-25 13:00:45 +01:00
struct dma_fence * exclusive ,
2016-09-21 16:19:19 +08:00
uint64_t gtt_flags ,
2016-03-30 10:50:25 +02:00
dma_addr_t * pages_addr ,
2016-01-25 14:27:31 +01:00
struct amdgpu_vm * vm ,
struct amdgpu_bo_va_mapping * mapping ,
2016-09-21 16:19:19 +08:00
uint64_t flags ,
2016-08-16 17:38:37 +02:00
struct drm_mm_node * nodes ,
2016-10-25 13:00:45 +01:00
struct dma_fence * * fence )
2016-01-25 14:27:31 +01:00
{
2016-08-16 17:38:37 +02:00
uint64_t pfn , src = 0 , start = mapping - > it . start ;
2016-01-25 14:27:31 +01:00
int r ;
/* normally,bo_va->flags only contians READABLE and WIRTEABLE bit go here
* but in case of something , we filter the flags in first place
*/
if ( ! ( mapping - > flags & AMDGPU_PTE_READABLE ) )
flags & = ~ AMDGPU_PTE_READABLE ;
if ( ! ( mapping - > flags & AMDGPU_PTE_WRITEABLE ) )
flags & = ~ AMDGPU_PTE_WRITEABLE ;
2017-03-03 16:47:11 -05:00
flags & = ~ AMDGPU_PTE_EXECUTABLE ;
flags | = mapping - > flags & AMDGPU_PTE_EXECUTABLE ;
2017-03-03 16:49:39 -05:00
flags & = ~ AMDGPU_PTE_MTYPE_MASK ;
flags | = ( mapping - > flags & AMDGPU_PTE_MTYPE_MASK ) ;
2016-01-25 14:27:31 +01:00
trace_amdgpu_vm_bo_update ( mapping ) ;
2016-08-16 17:38:37 +02:00
pfn = mapping - > offset > > PAGE_SHIFT ;
if ( nodes ) {
while ( pfn > = nodes - > size ) {
pfn - = nodes - > size ;
+ + nodes ;
}
2016-03-18 21:00:35 +01:00
}
2016-01-25 14:27:31 +01:00
2016-08-16 17:38:37 +02:00
do {
uint64_t max_entries ;
uint64_t addr , last ;
2016-01-25 14:27:31 +01:00
2016-08-16 17:38:37 +02:00
if ( nodes ) {
addr = nodes - > start < < PAGE_SHIFT ;
max_entries = ( nodes - > size - pfn ) *
( PAGE_SIZE / AMDGPU_GPU_PAGE_SIZE ) ;
} else {
addr = 0 ;
max_entries = S64_MAX ;
}
2016-01-25 14:27:31 +01:00
2016-08-16 17:38:37 +02:00
if ( pages_addr ) {
if ( flags = = gtt_flags )
src = adev - > gart . table_addr +
( addr > > AMDGPU_GPU_PAGE_SHIFT ) * 8 ;
else
max_entries = min ( max_entries , 16ull * 1024ull ) ;
addr = 0 ;
} else if ( flags & AMDGPU_PTE_VALID ) {
addr + = adev - > vm_manager . vram_base_offset ;
}
addr + = pfn < < PAGE_SHIFT ;
last = min ( ( uint64_t ) mapping - > it . last , start + max_entries - 1 ) ;
2016-06-06 10:17:58 +02:00
r = amdgpu_vm_bo_update_mapping ( adev , exclusive ,
src , pages_addr , vm ,
2016-01-25 14:27:31 +01:00
start , last , flags , addr ,
fence ) ;
if ( r )
return r ;
2016-08-16 17:38:37 +02:00
pfn + = last - start + 1 ;
if ( nodes & & nodes - > size = = pfn ) {
pfn = 0 ;
+ + nodes ;
}
2016-01-25 14:27:31 +01:00
start = last + 1 ;
2016-08-16 17:38:37 +02:00
} while ( unlikely ( start ! = mapping - > it . last + 1 ) ) ;
2016-01-25 14:27:31 +01:00
return 0 ;
}
2015-04-20 16:55:21 -04:00
/**
* amdgpu_vm_bo_update - update all BO mappings in the vm page table
*
* @ adev : amdgpu_device pointer
* @ bo_va : requested BO and VM object
2016-08-16 14:43:17 +02:00
* @ clear : if true clear the entries
2015-04-20 16:55:21 -04:00
*
* Fill in the page table entries for @ bo_va .
* Returns 0 for success , - EINVAL for failure .
*/
int amdgpu_vm_bo_update ( struct amdgpu_device * adev ,
struct amdgpu_bo_va * bo_va ,
2016-08-16 14:43:17 +02:00
bool clear )
2015-04-20 16:55:21 -04:00
{
struct amdgpu_vm * vm = bo_va - > vm ;
struct amdgpu_bo_va_mapping * mapping ;
2016-03-30 10:50:25 +02:00
dma_addr_t * pages_addr = NULL ;
2016-09-21 16:19:19 +08:00
uint64_t gtt_flags , flags ;
2016-08-16 14:43:17 +02:00
struct ttm_mem_reg * mem ;
2016-08-16 17:38:37 +02:00
struct drm_mm_node * nodes ;
2016-10-25 13:00:45 +01:00
struct dma_fence * exclusive ;
2015-04-20 16:55:21 -04:00
int r ;
2017-01-30 11:01:38 +01:00
if ( clear | | ! bo_va - > bo ) {
2016-08-16 14:43:17 +02:00
mem = NULL ;
2016-08-16 17:38:37 +02:00
nodes = NULL ;
2016-08-16 14:43:17 +02:00
exclusive = NULL ;
} else {
2016-03-30 10:50:25 +02:00
struct ttm_dma_tt * ttm ;
2016-08-16 14:43:17 +02:00
mem = & bo_va - > bo - > tbo . mem ;
2016-08-16 17:38:37 +02:00
nodes = mem - > mm_node ;
if ( mem - > mem_type = = TTM_PL_TT ) {
2016-03-30 10:50:25 +02:00
ttm = container_of ( bo_va - > bo - > tbo . ttm , struct
ttm_dma_tt , ttm ) ;
pages_addr = ttm - > dma_address ;
2015-11-30 14:19:26 +01:00
}
2016-06-06 10:17:58 +02:00
exclusive = reservation_object_get_excl ( bo_va - > bo - > tbo . resv ) ;
2015-04-20 16:55:21 -04:00
}
2017-01-30 11:01:38 +01:00
if ( bo_va - > bo ) {
flags = amdgpu_ttm_tt_pte_flags ( adev , bo_va - > bo - > tbo . ttm , mem ) ;
gtt_flags = ( amdgpu_ttm_is_bound ( bo_va - > bo - > tbo . ttm ) & &
adev = = amdgpu_ttm_adev ( bo_va - > bo - > tbo . bdev ) ) ?
flags : 0 ;
} else {
flags = 0x0 ;
gtt_flags = ~ 0x0 ;
}
2015-04-20 16:55:21 -04:00
2015-07-30 11:53:42 +02:00
spin_lock ( & vm - > status_lock ) ;
if ( ! list_empty ( & bo_va - > vm_status ) )
list_splice_init ( & bo_va - > valids , & bo_va - > invalids ) ;
spin_unlock ( & vm - > status_lock ) ;
list_for_each_entry ( mapping , & bo_va - > invalids , list ) {
2016-06-06 10:17:58 +02:00
r = amdgpu_vm_bo_split_mapping ( adev , exclusive ,
gtt_flags , pages_addr , vm ,
2016-08-16 17:38:37 +02:00
mapping , flags , nodes ,
2016-03-30 10:50:25 +02:00
& bo_va - > last_pt_update ) ;
2015-04-20 16:55:21 -04:00
if ( r )
return r ;
}
2015-09-28 12:00:23 +02:00
if ( trace_amdgpu_vm_bo_mapping_enabled ( ) ) {
list_for_each_entry ( mapping , & bo_va - > valids , list )
trace_amdgpu_vm_bo_mapping ( mapping ) ;
list_for_each_entry ( mapping , & bo_va - > invalids , list )
trace_amdgpu_vm_bo_mapping ( mapping ) ;
}
2015-04-20 16:55:21 -04:00
spin_lock ( & vm - > status_lock ) ;
2015-08-14 13:36:41 +08:00
list_splice_init ( & bo_va - > invalids , & bo_va - > valids ) ;
2015-04-20 16:55:21 -04:00
list_del_init ( & bo_va - > vm_status ) ;
2016-08-16 14:43:17 +02:00
if ( clear )
2015-07-30 11:53:42 +02:00
list_add ( & bo_va - > vm_status , & vm - > cleared ) ;
2015-04-20 16:55:21 -04:00
spin_unlock ( & vm - > status_lock ) ;
return 0 ;
}
2017-01-30 11:09:31 +01:00
/**
* amdgpu_vm_update_prt_state - update the global PRT state
*/
static void amdgpu_vm_update_prt_state ( struct amdgpu_device * adev )
{
unsigned long flags ;
bool enable ;
spin_lock_irqsave ( & adev - > vm_manager . prt_lock , flags ) ;
2017-02-14 16:02:52 +01:00
enable = ! ! atomic_read ( & adev - > vm_manager . num_prt_users ) ;
2017-01-30 11:09:31 +01:00
adev - > gart . gart_funcs - > set_prt ( adev , enable ) ;
spin_unlock_irqrestore ( & adev - > vm_manager . prt_lock , flags ) ;
}
2017-02-14 16:02:52 +01:00
/**
2017-03-13 10:13:36 +01:00
* amdgpu_vm_prt_get - add a PRT user
2017-02-14 16:02:52 +01:00
*/
static void amdgpu_vm_prt_get ( struct amdgpu_device * adev )
{
2017-03-13 10:13:36 +01:00
if ( ! adev - > gart . gart_funcs - > set_prt )
return ;
2017-02-14 16:02:52 +01:00
if ( atomic_inc_return ( & adev - > vm_manager . num_prt_users ) = = 1 )
amdgpu_vm_update_prt_state ( adev ) ;
}
2017-02-14 15:47:03 +01:00
/**
* amdgpu_vm_prt_put - drop a PRT user
*/
static void amdgpu_vm_prt_put ( struct amdgpu_device * adev )
{
2017-02-14 16:02:52 +01:00
if ( atomic_dec_return ( & adev - > vm_manager . num_prt_users ) = = 0 )
2017-02-14 15:47:03 +01:00
amdgpu_vm_update_prt_state ( adev ) ;
}
2017-01-30 11:09:31 +01:00
/**
2017-02-14 16:02:52 +01:00
* amdgpu_vm_prt_cb - callback for updating the PRT status
2017-01-30 11:09:31 +01:00
*/
static void amdgpu_vm_prt_cb ( struct dma_fence * fence , struct dma_fence_cb * _cb )
{
struct amdgpu_prt_cb * cb = container_of ( _cb , struct amdgpu_prt_cb , cb ) ;
2017-02-14 15:47:03 +01:00
amdgpu_vm_prt_put ( cb - > adev ) ;
2017-01-30 11:09:31 +01:00
kfree ( cb ) ;
}
2017-02-14 16:02:52 +01:00
/**
* amdgpu_vm_add_prt_cb - add callback for updating the PRT status
*/
static void amdgpu_vm_add_prt_cb ( struct amdgpu_device * adev ,
struct dma_fence * fence )
{
2017-03-13 10:13:36 +01:00
struct amdgpu_prt_cb * cb ;
2017-02-14 16:02:52 +01:00
2017-03-13 10:13:36 +01:00
if ( ! adev - > gart . gart_funcs - > set_prt )
return ;
cb = kmalloc ( sizeof ( struct amdgpu_prt_cb ) , GFP_KERNEL ) ;
2017-02-14 16:02:52 +01:00
if ( ! cb ) {
/* Last resort when we are OOM */
if ( fence )
dma_fence_wait ( fence , false ) ;
amdgpu_vm_prt_put ( cb - > adev ) ;
} else {
cb - > adev = adev ;
if ( ! fence | | dma_fence_add_callback ( fence , & cb - > cb ,
amdgpu_vm_prt_cb ) )
amdgpu_vm_prt_cb ( fence , & cb - > cb ) ;
}
}
2017-01-30 11:09:31 +01:00
/**
* amdgpu_vm_free_mapping - free a mapping
*
* @ adev : amdgpu_device pointer
* @ vm : requested vm
* @ mapping : mapping to be freed
* @ fence : fence of the unmap operation
*
* Free a mapping and make sure we decrease the PRT usage count if applicable .
*/
static void amdgpu_vm_free_mapping ( struct amdgpu_device * adev ,
struct amdgpu_vm * vm ,
struct amdgpu_bo_va_mapping * mapping ,
struct dma_fence * fence )
{
2017-02-14 16:02:52 +01:00
if ( mapping - > flags & AMDGPU_PTE_PRT )
amdgpu_vm_add_prt_cb ( adev , fence ) ;
kfree ( mapping ) ;
}
2017-01-30 11:09:31 +01:00
2017-02-14 16:02:52 +01:00
/**
* amdgpu_vm_prt_fini - finish all prt mappings
*
* @ adev : amdgpu_device pointer
* @ vm : requested vm
*
* Register a cleanup callback to disable PRT support after VM dies .
*/
static void amdgpu_vm_prt_fini ( struct amdgpu_device * adev , struct amdgpu_vm * vm )
{
struct reservation_object * resv = vm - > page_directory - > tbo . resv ;
struct dma_fence * excl , * * shared ;
unsigned i , shared_count ;
int r ;
2017-02-14 15:47:03 +01:00
2017-02-14 16:02:52 +01:00
r = reservation_object_get_fences_rcu ( resv , & excl ,
& shared_count , & shared ) ;
if ( r ) {
/* Not enough memory to grab the fence list, as last resort
* block for all the fences to complete .
*/
reservation_object_wait_timeout_rcu ( resv , true , false ,
MAX_SCHEDULE_TIMEOUT ) ;
return ;
2017-01-30 11:09:31 +01:00
}
2017-02-14 16:02:52 +01:00
/* Add a callback for each fence in the reservation object */
amdgpu_vm_prt_get ( adev ) ;
amdgpu_vm_add_prt_cb ( adev , excl ) ;
for ( i = 0 ; i < shared_count ; + + i ) {
amdgpu_vm_prt_get ( adev ) ;
amdgpu_vm_add_prt_cb ( adev , shared [ i ] ) ;
}
kfree ( shared ) ;
2017-01-30 11:09:31 +01:00
}
2015-04-20 16:55:21 -04:00
/**
* amdgpu_vm_clear_freed - clear freed BOs in the PT
*
* @ adev : amdgpu_device pointer
* @ vm : requested vm
2017-03-23 19:36:31 +01:00
* @ fence : optional resulting fence ( unchanged if no work needed to be done
* or if an error occurred )
2015-04-20 16:55:21 -04:00
*
* Make sure all freed BOs are cleared in the PT .
* Returns 0 for success .
*
* PTs have to be reserved and mutex must be locked !
*/
int amdgpu_vm_clear_freed ( struct amdgpu_device * adev ,
2017-03-23 19:36:31 +01:00
struct amdgpu_vm * vm ,
struct dma_fence * * fence )
2015-04-20 16:55:21 -04:00
{
struct amdgpu_bo_va_mapping * mapping ;
2017-03-23 19:36:31 +01:00
struct dma_fence * f = NULL ;
2015-04-20 16:55:21 -04:00
int r ;
while ( ! list_empty ( & vm - > freed ) ) {
mapping = list_first_entry ( & vm - > freed ,
struct amdgpu_bo_va_mapping , list ) ;
list_del ( & mapping - > list ) ;
2016-03-08 17:52:01 +01:00
2016-06-06 10:17:58 +02:00
r = amdgpu_vm_bo_split_mapping ( adev , NULL , 0 , NULL , vm , mapping ,
2017-03-23 19:36:31 +01:00
0 , 0 , & f ) ;
amdgpu_vm_free_mapping ( adev , vm , mapping , f ) ;
2017-01-30 11:09:31 +01:00
if ( r ) {
2017-03-23 19:36:31 +01:00
dma_fence_put ( f ) ;
2015-04-20 16:55:21 -04:00
return r ;
2017-01-30 11:09:31 +01:00
}
2017-03-23 19:36:31 +01:00
}
2015-04-20 16:55:21 -04:00
2017-03-23 19:36:31 +01:00
if ( fence & & f ) {
dma_fence_put ( * fence ) ;
* fence = f ;
} else {
dma_fence_put ( f ) ;
2015-04-20 16:55:21 -04:00
}
2017-03-23 19:36:31 +01:00
2015-04-20 16:55:21 -04:00
return 0 ;
}
/**
* amdgpu_vm_clear_invalids - clear invalidated BOs in the PT
*
* @ adev : amdgpu_device pointer
* @ vm : requested vm
*
* Make sure all invalidated BOs are cleared in the PT .
* Returns 0 for success .
*
* PTs have to be reserved and mutex must be locked !
*/
int amdgpu_vm_clear_invalids ( struct amdgpu_device * adev ,
2015-05-26 15:01:54 +08:00
struct amdgpu_vm * vm , struct amdgpu_sync * sync )
2015-04-20 16:55:21 -04:00
{
2015-05-26 15:01:54 +08:00
struct amdgpu_bo_va * bo_va = NULL ;
2015-07-06 22:06:40 +02:00
int r = 0 ;
2015-04-20 16:55:21 -04:00
spin_lock ( & vm - > status_lock ) ;
while ( ! list_empty ( & vm - > invalidated ) ) {
bo_va = list_first_entry ( & vm - > invalidated ,
struct amdgpu_bo_va , vm_status ) ;
spin_unlock ( & vm - > status_lock ) ;
2016-03-08 18:03:27 +01:00
2016-08-16 14:43:17 +02:00
r = amdgpu_vm_bo_update ( adev , bo_va , true ) ;
2015-04-20 16:55:21 -04:00
if ( r )
return r ;
spin_lock ( & vm - > status_lock ) ;
}
spin_unlock ( & vm - > status_lock ) ;
2015-05-26 15:01:54 +08:00
if ( bo_va )
2015-08-03 18:19:38 +08:00
r = amdgpu_sync_fence ( adev , sync , bo_va - > last_pt_update ) ;
2015-07-06 22:06:40 +02:00
return r ;
2015-04-20 16:55:21 -04:00
}
/**
* amdgpu_vm_bo_add - add a bo to a specific vm
*
* @ adev : amdgpu_device pointer
* @ vm : requested vm
* @ bo : amdgpu buffer object
*
2016-01-26 12:17:11 +01:00
* Add @ bo into the requested vm .
2015-04-20 16:55:21 -04:00
* Add @ bo to the list of bos associated with the vm
* Returns newly added bo_va or NULL for failure
*
* Object has to be reserved !
*/
struct amdgpu_bo_va * amdgpu_vm_bo_add ( struct amdgpu_device * adev ,
struct amdgpu_vm * vm ,
struct amdgpu_bo * bo )
{
struct amdgpu_bo_va * bo_va ;
bo_va = kzalloc ( sizeof ( struct amdgpu_bo_va ) , GFP_KERNEL ) ;
if ( bo_va = = NULL ) {
return NULL ;
}
bo_va - > vm = vm ;
bo_va - > bo = bo ;
bo_va - > ref_count = 1 ;
INIT_LIST_HEAD ( & bo_va - > bo_list ) ;
2015-07-30 11:53:42 +02:00
INIT_LIST_HEAD ( & bo_va - > valids ) ;
INIT_LIST_HEAD ( & bo_va - > invalids ) ;
2015-04-20 16:55:21 -04:00
INIT_LIST_HEAD ( & bo_va - > vm_status ) ;
2016-03-08 18:03:27 +01:00
2017-01-30 11:01:38 +01:00
if ( bo )
list_add_tail ( & bo_va - > bo_list , & bo - > va ) ;
2015-04-20 16:55:21 -04:00
return bo_va ;
}
/**
* amdgpu_vm_bo_map - map bo inside a vm
*
* @ adev : amdgpu_device pointer
* @ bo_va : bo_va to store the address
* @ saddr : where to map the BO
* @ offset : requested offset in the BO
* @ flags : attributes of pages ( read / write / valid / etc . )
*
* Add a mapping of the BO at the specefied addr into the VM .
* Returns 0 for success , error for failure .
*
2015-11-13 14:18:38 +08:00
* Object has to be reserved and unreserved outside !
2015-04-20 16:55:21 -04:00
*/
int amdgpu_vm_bo_map ( struct amdgpu_device * adev ,
struct amdgpu_bo_va * bo_va ,
uint64_t saddr , uint64_t offset ,
2017-01-18 14:49:43 +01:00
uint64_t size , uint64_t flags )
2015-04-20 16:55:21 -04:00
{
struct amdgpu_bo_va_mapping * mapping ;
struct amdgpu_vm * vm = bo_va - > vm ;
struct interval_tree_node * it ;
uint64_t eaddr ;
2015-05-18 14:37:27 +02:00
/* validate the parameters */
if ( saddr & AMDGPU_GPU_PAGE_MASK | | offset & AMDGPU_GPU_PAGE_MASK | |
2015-11-13 14:18:38 +08:00
size = = 0 | | size & AMDGPU_GPU_PAGE_MASK )
2015-05-18 14:37:27 +02:00
return - EINVAL ;
2015-04-20 16:55:21 -04:00
/* make sure object fit at this offset */
2015-11-23 17:43:48 -05:00
eaddr = saddr + size - 1 ;
2017-01-30 11:01:38 +01:00
if ( saddr > = eaddr | |
( bo_va - > bo & & offset + size > amdgpu_bo_size ( bo_va - > bo ) ) )
2015-04-20 16:55:21 -04:00
return - EINVAL ;
saddr / = AMDGPU_GPU_PAGE_SIZE ;
eaddr / = AMDGPU_GPU_PAGE_SIZE ;
2015-11-23 17:43:48 -05:00
it = interval_tree_iter_first ( & vm - > va , saddr , eaddr ) ;
2015-04-20 16:55:21 -04:00
if ( it ) {
struct amdgpu_bo_va_mapping * tmp ;
tmp = container_of ( it , struct amdgpu_bo_va_mapping , it ) ;
/* bo and tmp overlap, invalid addr */
dev_err ( adev - > dev , " bo %p va 0x%010Lx-0x%010Lx conflict with "
" 0x%010lx-0x%010lx \n " , bo_va - > bo , saddr , eaddr ,
tmp - > it . start , tmp - > it . last + 1 ) ;
2017-03-13 10:13:37 +01:00
return - EINVAL ;
2015-04-20 16:55:21 -04:00
}
mapping = kmalloc ( sizeof ( * mapping ) , GFP_KERNEL ) ;
2017-03-13 10:13:37 +01:00
if ( ! mapping )
return - ENOMEM ;
2015-04-20 16:55:21 -04:00
INIT_LIST_HEAD ( & mapping - > list ) ;
mapping - > it . start = saddr ;
2015-11-23 17:43:48 -05:00
mapping - > it . last = eaddr ;
2015-04-20 16:55:21 -04:00
mapping - > offset = offset ;
mapping - > flags = flags ;
2015-07-30 11:53:42 +02:00
list_add ( & mapping - > list , & bo_va - > invalids ) ;
2015-04-20 16:55:21 -04:00
interval_tree_insert ( & mapping - > it , & vm - > va ) ;
2017-03-13 10:13:39 +01:00
if ( flags & AMDGPU_PTE_PRT )
amdgpu_vm_prt_get ( adev ) ;
return 0 ;
}
/**
* amdgpu_vm_bo_replace_map - map bo inside a vm , replacing existing mappings
*
* @ adev : amdgpu_device pointer
* @ bo_va : bo_va to store the address
* @ saddr : where to map the BO
* @ offset : requested offset in the BO
* @ flags : attributes of pages ( read / write / valid / etc . )
*
* Add a mapping of the BO at the specefied addr into the VM . Replace existing
* mappings as we do so .
* Returns 0 for success , error for failure .
*
* Object has to be reserved and unreserved outside !
*/
int amdgpu_vm_bo_replace_map ( struct amdgpu_device * adev ,
struct amdgpu_bo_va * bo_va ,
uint64_t saddr , uint64_t offset ,
uint64_t size , uint64_t flags )
{
struct amdgpu_bo_va_mapping * mapping ;
struct amdgpu_vm * vm = bo_va - > vm ;
uint64_t eaddr ;
int r ;
/* validate the parameters */
if ( saddr & AMDGPU_GPU_PAGE_MASK | | offset & AMDGPU_GPU_PAGE_MASK | |
size = = 0 | | size & AMDGPU_GPU_PAGE_MASK )
return - EINVAL ;
/* make sure object fit at this offset */
eaddr = saddr + size - 1 ;
if ( saddr > = eaddr | |
( bo_va - > bo & & offset + size > amdgpu_bo_size ( bo_va - > bo ) ) )
return - EINVAL ;
/* Allocate all the needed memory */
mapping = kmalloc ( sizeof ( * mapping ) , GFP_KERNEL ) ;
if ( ! mapping )
return - ENOMEM ;
r = amdgpu_vm_bo_clear_mappings ( adev , bo_va - > vm , saddr , size ) ;
if ( r ) {
kfree ( mapping ) ;
return r ;
}
saddr / = AMDGPU_GPU_PAGE_SIZE ;
eaddr / = AMDGPU_GPU_PAGE_SIZE ;
mapping - > it . start = saddr ;
mapping - > it . last = eaddr ;
mapping - > offset = offset ;
mapping - > flags = flags ;
list_add ( & mapping - > list , & bo_va - > invalids ) ;
interval_tree_insert ( & mapping - > it , & vm - > va ) ;
2015-04-20 16:55:21 -04:00
2017-03-13 10:13:36 +01:00
if ( flags & AMDGPU_PTE_PRT )
amdgpu_vm_prt_get ( adev ) ;
2015-04-20 16:55:21 -04:00
return 0 ;
}
/**
* amdgpu_vm_bo_unmap - remove bo mapping from vm
*
* @ adev : amdgpu_device pointer
* @ bo_va : bo_va to remove the address from
* @ saddr : where to the BO is mapped
*
* Remove a mapping of the BO at the specefied addr from the VM .
* Returns 0 for success , error for failure .
*
2015-11-13 14:18:38 +08:00
* Object has to be reserved and unreserved outside !
2015-04-20 16:55:21 -04:00
*/
int amdgpu_vm_bo_unmap ( struct amdgpu_device * adev ,
struct amdgpu_bo_va * bo_va ,
uint64_t saddr )
{
struct amdgpu_bo_va_mapping * mapping ;
struct amdgpu_vm * vm = bo_va - > vm ;
2015-07-30 11:53:42 +02:00
bool valid = true ;
2015-04-20 16:55:21 -04:00
2015-06-05 20:56:17 +02:00
saddr / = AMDGPU_GPU_PAGE_SIZE ;
2016-03-08 18:03:27 +01:00
2015-07-30 11:53:42 +02:00
list_for_each_entry ( mapping , & bo_va - > valids , list ) {
2015-04-20 16:55:21 -04:00
if ( mapping - > it . start = = saddr )
break ;
}
2015-07-30 11:53:42 +02:00
if ( & mapping - > list = = & bo_va - > valids ) {
valid = false ;
list_for_each_entry ( mapping , & bo_va - > invalids , list ) {
if ( mapping - > it . start = = saddr )
break ;
}
2016-03-08 18:03:27 +01:00
if ( & mapping - > list = = & bo_va - > invalids )
2015-07-30 11:53:42 +02:00
return - ENOENT ;
2015-04-20 16:55:21 -04:00
}
2016-03-08 18:03:27 +01:00
2015-04-20 16:55:21 -04:00
list_del ( & mapping - > list ) ;
interval_tree_remove ( & mapping - > it , & vm - > va ) ;
2015-06-09 16:58:33 +02:00
trace_amdgpu_vm_bo_unmap ( bo_va , mapping ) ;
2015-04-20 16:55:21 -04:00
2016-03-08 17:52:01 +01:00
if ( valid )
2015-04-20 16:55:21 -04:00
list_add ( & mapping - > list , & vm - > freed ) ;
2016-03-08 17:52:01 +01:00
else
2017-01-30 11:09:31 +01:00
amdgpu_vm_free_mapping ( adev , vm , mapping ,
bo_va - > last_pt_update ) ;
2015-04-20 16:55:21 -04:00
return 0 ;
}
2017-03-13 10:13:38 +01:00
/**
* amdgpu_vm_bo_clear_mappings - remove all mappings in a specific range
*
* @ adev : amdgpu_device pointer
* @ vm : VM structure to use
* @ saddr : start of the range
* @ size : size of the range
*
* Remove all mappings in a range , split them as appropriate .
* Returns 0 for success , error for failure .
*/
int amdgpu_vm_bo_clear_mappings ( struct amdgpu_device * adev ,
struct amdgpu_vm * vm ,
uint64_t saddr , uint64_t size )
{
struct amdgpu_bo_va_mapping * before , * after , * tmp , * next ;
struct interval_tree_node * it ;
LIST_HEAD ( removed ) ;
uint64_t eaddr ;
eaddr = saddr + size - 1 ;
saddr / = AMDGPU_GPU_PAGE_SIZE ;
eaddr / = AMDGPU_GPU_PAGE_SIZE ;
/* Allocate all the needed memory */
before = kzalloc ( sizeof ( * before ) , GFP_KERNEL ) ;
if ( ! before )
return - ENOMEM ;
2017-03-16 16:09:24 +08:00
INIT_LIST_HEAD ( & before - > list ) ;
2017-03-13 10:13:38 +01:00
after = kzalloc ( sizeof ( * after ) , GFP_KERNEL ) ;
if ( ! after ) {
kfree ( before ) ;
return - ENOMEM ;
}
2017-03-16 16:09:24 +08:00
INIT_LIST_HEAD ( & after - > list ) ;
2017-03-13 10:13:38 +01:00
/* Now gather all removed mappings */
it = interval_tree_iter_first ( & vm - > va , saddr , eaddr ) ;
while ( it ) {
tmp = container_of ( it , struct amdgpu_bo_va_mapping , it ) ;
it = interval_tree_iter_next ( it , saddr , eaddr ) ;
/* Remember mapping split at the start */
if ( tmp - > it . start < saddr ) {
2017-03-16 16:09:24 +08:00
before - > it . start = tmp - > it . start ;
2017-03-13 10:13:38 +01:00
before - > it . last = saddr - 1 ;
before - > offset = tmp - > offset ;
before - > flags = tmp - > flags ;
list_add ( & before - > list , & tmp - > list ) ;
}
/* Remember mapping split at the end */
if ( tmp - > it . last > eaddr ) {
after - > it . start = eaddr + 1 ;
after - > it . last = tmp - > it . last ;
after - > offset = tmp - > offset ;
after - > offset + = after - > it . start - tmp - > it . start ;
after - > flags = tmp - > flags ;
list_add ( & after - > list , & tmp - > list ) ;
}
list_del ( & tmp - > list ) ;
list_add ( & tmp - > list , & removed ) ;
}
/* And free them up */
list_for_each_entry_safe ( tmp , next , & removed , list ) {
interval_tree_remove ( & tmp - > it , & vm - > va ) ;
list_del ( & tmp - > list ) ;
if ( tmp - > it . start < saddr )
tmp - > it . start = saddr ;
if ( tmp - > it . last > eaddr )
tmp - > it . last = eaddr ;
list_add ( & tmp - > list , & vm - > freed ) ;
trace_amdgpu_vm_bo_unmap ( NULL , tmp ) ;
}
2017-03-16 16:09:24 +08:00
/* Insert partial mapping before the range */
if ( ! list_empty ( & before - > list ) ) {
2017-03-13 10:13:38 +01:00
interval_tree_insert ( & before - > it , & vm - > va ) ;
if ( before - > flags & AMDGPU_PTE_PRT )
amdgpu_vm_prt_get ( adev ) ;
} else {
kfree ( before ) ;
}
/* Insert partial mapping after the range */
2017-03-16 16:09:24 +08:00
if ( ! list_empty ( & after - > list ) ) {
2017-03-13 10:13:38 +01:00
interval_tree_insert ( & after - > it , & vm - > va ) ;
if ( after - > flags & AMDGPU_PTE_PRT )
amdgpu_vm_prt_get ( adev ) ;
} else {
kfree ( after ) ;
}
return 0 ;
}
2015-04-20 16:55:21 -04:00
/**
* amdgpu_vm_bo_rmv - remove a bo to a specific vm
*
* @ adev : amdgpu_device pointer
* @ bo_va : requested bo_va
*
2016-01-26 12:17:11 +01:00
* Remove @ bo_va - > bo from the requested vm .
2015-04-20 16:55:21 -04:00
*
* Object have to be reserved !
*/
void amdgpu_vm_bo_rmv ( struct amdgpu_device * adev ,
struct amdgpu_bo_va * bo_va )
{
struct amdgpu_bo_va_mapping * mapping , * next ;
struct amdgpu_vm * vm = bo_va - > vm ;
list_del ( & bo_va - > bo_list ) ;
spin_lock ( & vm - > status_lock ) ;
list_del ( & bo_va - > vm_status ) ;
spin_unlock ( & vm - > status_lock ) ;
2015-07-30 11:53:42 +02:00
list_for_each_entry_safe ( mapping , next , & bo_va - > valids , list ) {
2015-04-20 16:55:21 -04:00
list_del ( & mapping - > list ) ;
interval_tree_remove ( & mapping - > it , & vm - > va ) ;
2015-06-09 16:58:33 +02:00
trace_amdgpu_vm_bo_unmap ( bo_va , mapping ) ;
2015-07-30 11:53:42 +02:00
list_add ( & mapping - > list , & vm - > freed ) ;
}
list_for_each_entry_safe ( mapping , next , & bo_va - > invalids , list ) {
list_del ( & mapping - > list ) ;
interval_tree_remove ( & mapping - > it , & vm - > va ) ;
2017-01-30 11:09:31 +01:00
amdgpu_vm_free_mapping ( adev , vm , mapping ,
bo_va - > last_pt_update ) ;
2015-04-20 16:55:21 -04:00
}
2016-03-08 18:03:27 +01:00
2016-10-25 13:00:45 +01:00
dma_fence_put ( bo_va - > last_pt_update ) ;
2015-04-20 16:55:21 -04:00
kfree ( bo_va ) ;
}
/**
* amdgpu_vm_bo_invalidate - mark the bo as invalid
*
* @ adev : amdgpu_device pointer
* @ vm : requested vm
* @ bo : amdgpu buffer object
*
2016-01-26 12:17:11 +01:00
* Mark @ bo as invalid .
2015-04-20 16:55:21 -04:00
*/
void amdgpu_vm_bo_invalidate ( struct amdgpu_device * adev ,
struct amdgpu_bo * bo )
{
struct amdgpu_bo_va * bo_va ;
list_for_each_entry ( bo_va , & bo - > va , bo_list ) {
2015-07-30 11:53:42 +02:00
spin_lock ( & bo_va - > vm - > status_lock ) ;
if ( list_empty ( & bo_va - > vm_status ) )
2015-04-20 16:55:21 -04:00
list_add ( & bo_va - > vm_status , & bo_va - > vm - > invalidated ) ;
2015-07-30 11:53:42 +02:00
spin_unlock ( & bo_va - > vm - > status_lock ) ;
2015-04-20 16:55:21 -04:00
}
}
/**
* amdgpu_vm_init - initialize a vm instance
*
* @ adev : amdgpu_device pointer
* @ vm : requested vm
*
2016-01-26 12:17:11 +01:00
* Init @ vm fields .
2015-04-20 16:55:21 -04:00
*/
int amdgpu_vm_init ( struct amdgpu_device * adev , struct amdgpu_vm * vm )
{
const unsigned align = min ( AMDGPU_VM_PTB_ALIGN_SIZE ,
AMDGPU_VM_PTE_COUNT * 8 ) ;
2016-01-19 17:59:46 +09:00
unsigned pd_size , pd_entries ;
2016-02-08 17:37:38 +01:00
unsigned ring_instance ;
struct amdgpu_ring * ring ;
2016-02-01 12:53:58 +01:00
struct amd_sched_rq * rq ;
2015-04-20 16:55:21 -04:00
int i , r ;
2016-03-08 15:40:11 +01:00
for ( i = 0 ; i < AMDGPU_MAX_RINGS ; + + i )
vm - > ids [ i ] = NULL ;
2015-04-20 16:55:21 -04:00
vm - > va = RB_ROOT ;
2016-04-25 10:19:13 +08:00
vm - > client_id = atomic64_inc_return ( & adev - > vm_manager . client_counter ) ;
2015-04-20 16:55:21 -04:00
spin_lock_init ( & vm - > status_lock ) ;
INIT_LIST_HEAD ( & vm - > invalidated ) ;
2015-07-30 11:53:42 +02:00
INIT_LIST_HEAD ( & vm - > cleared ) ;
2015-04-20 16:55:21 -04:00
INIT_LIST_HEAD ( & vm - > freed ) ;
2016-03-08 17:58:35 +01:00
2015-04-20 16:55:21 -04:00
pd_size = amdgpu_vm_directory_size ( adev ) ;
pd_entries = amdgpu_vm_num_pdes ( adev ) ;
/* allocate page table array */
2016-01-19 17:59:46 +09:00
vm - > page_tables = drm_calloc_large ( pd_entries , sizeof ( struct amdgpu_vm_pt ) ) ;
2015-04-20 16:55:21 -04:00
if ( vm - > page_tables = = NULL ) {
DRM_ERROR ( " Cannot allocate memory for page table array \n " ) ;
return - ENOMEM ;
}
2016-02-01 12:53:58 +01:00
/* create scheduler entity for page table updates */
2016-02-08 17:37:38 +01:00
ring_instance = atomic_inc_return ( & adev - > vm_manager . vm_pte_next_ring ) ;
ring_instance % = adev - > vm_manager . vm_pte_num_rings ;
ring = adev - > vm_manager . vm_pte_rings [ ring_instance ] ;
2016-02-01 12:53:58 +01:00
rq = & ring - > sched . sched_rq [ AMD_SCHED_PRIORITY_KERNEL ] ;
r = amd_sched_entity_init ( & ring - > sched , & vm - > entity ,
rq , amdgpu_sched_jobs ) ;
if ( r )
2016-07-28 17:20:32 +08:00
goto err ;
2016-02-01 12:53:58 +01:00
2015-08-14 20:08:40 +02:00
vm - > page_directory_fence = NULL ;
2015-04-20 16:55:21 -04:00
r = amdgpu_bo_create ( adev , pd_size , align , true ,
2015-08-27 00:14:16 -04:00
AMDGPU_GEM_DOMAIN_VRAM ,
2016-08-04 13:59:32 +08:00
AMDGPU_GEM_CREATE_NO_CPU_ACCESS |
2016-08-15 17:00:22 +02:00
AMDGPU_GEM_CREATE_SHADOW |
2016-11-17 15:40:02 +01:00
AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS |
AMDGPU_GEM_CREATE_VRAM_CLEARED ,
2015-09-03 17:34:59 +02:00
NULL , NULL , & vm - > page_directory ) ;
2015-04-20 16:55:21 -04:00
if ( r )
2016-02-01 12:53:58 +01:00
goto error_free_sched_entity ;
2015-11-13 13:43:22 +08:00
r = amdgpu_bo_reserve ( vm - > page_directory , false ) ;
2016-02-01 12:53:58 +01:00
if ( r )
goto error_free_page_directory ;
2016-06-21 16:28:15 +02:00
vm - > last_eviction_counter = atomic64_read ( & adev - > num_evictions ) ;
2016-09-16 13:11:45 +02:00
amdgpu_bo_unreserve ( vm - > page_directory ) ;
2015-04-20 16:55:21 -04:00
return 0 ;
2016-02-01 12:53:58 +01:00
error_free_page_directory :
2016-09-16 13:06:09 +02:00
amdgpu_bo_unref ( & vm - > page_directory - > shadow ) ;
2016-02-01 12:53:58 +01:00
amdgpu_bo_unref ( & vm - > page_directory ) ;
vm - > page_directory = NULL ;
error_free_sched_entity :
amd_sched_entity_fini ( & ring - > sched , & vm - > entity ) ;
2016-07-28 17:20:32 +08:00
err :
drm_free_large ( vm - > page_tables ) ;
2016-02-01 12:53:58 +01:00
return r ;
2015-04-20 16:55:21 -04:00
}
/**
* amdgpu_vm_fini - tear down a vm instance
*
* @ adev : amdgpu_device pointer
* @ vm : requested vm
*
2016-01-26 12:17:11 +01:00
* Tear down @ vm .
2015-04-20 16:55:21 -04:00
* Unbind the VM and remove all bos from the vm bo list
*/
void amdgpu_vm_fini ( struct amdgpu_device * adev , struct amdgpu_vm * vm )
{
struct amdgpu_bo_va_mapping * mapping , * tmp ;
2017-03-13 10:13:36 +01:00
bool prt_fini_needed = ! ! adev - > gart . gart_funcs - > set_prt ;
2015-04-20 16:55:21 -04:00
int i ;
2016-02-08 17:37:38 +01:00
amd_sched_entity_fini ( vm - > entity . sched , & vm - > entity ) ;
2016-02-01 12:53:58 +01:00
2015-04-20 16:55:21 -04:00
if ( ! RB_EMPTY_ROOT ( & vm - > va ) ) {
dev_err ( adev - > dev , " still active bo inside vm \n " ) ;
}
rbtree_postorder_for_each_entry_safe ( mapping , tmp , & vm - > va , it . rb ) {
list_del ( & mapping - > list ) ;
interval_tree_remove ( & mapping - > it , & vm - > va ) ;
kfree ( mapping ) ;
}
list_for_each_entry_safe ( mapping , tmp , & vm - > freed , list ) {
2017-03-13 10:13:36 +01:00
if ( mapping - > flags & AMDGPU_PTE_PRT & & prt_fini_needed ) {
2017-02-14 16:02:52 +01:00
amdgpu_vm_prt_fini ( adev , vm ) ;
2017-03-13 10:13:36 +01:00
prt_fini_needed = false ;
2017-02-14 16:02:52 +01:00
}
2017-01-30 11:09:31 +01:00
2015-04-20 16:55:21 -04:00
list_del ( & mapping - > list ) ;
2017-02-14 16:02:52 +01:00
amdgpu_vm_free_mapping ( adev , vm , mapping , NULL ) ;
2015-04-20 16:55:21 -04:00
}
2016-08-04 13:59:32 +08:00
for ( i = 0 ; i < amdgpu_vm_num_pdes ( adev ) ; i + + ) {
2016-09-28 12:27:37 +02:00
struct amdgpu_bo * pt = vm - > page_tables [ i ] . bo ;
2016-09-16 13:06:09 +02:00
if ( ! pt )
continue ;
amdgpu_bo_unref ( & pt - > shadow ) ;
amdgpu_bo_unref ( & pt ) ;
2016-08-04 13:59:32 +08:00
}
2016-01-19 17:59:46 +09:00
drm_free_large ( vm - > page_tables ) ;
2015-04-20 16:55:21 -04:00
2016-09-16 13:06:09 +02:00
amdgpu_bo_unref ( & vm - > page_directory - > shadow ) ;
2015-04-20 16:55:21 -04:00
amdgpu_bo_unref ( & vm - > page_directory ) ;
2016-10-25 13:00:45 +01:00
dma_fence_put ( vm - > page_directory_fence ) ;
2015-04-20 16:55:21 -04:00
}
2015-11-15 20:52:06 +01:00
2016-01-21 10:19:11 +01:00
/**
* amdgpu_vm_manager_init - init the VM manager
*
* @ adev : amdgpu_device pointer
*
* Initialize the VM manager structures
*/
void amdgpu_vm_manager_init ( struct amdgpu_device * adev )
{
unsigned i ;
INIT_LIST_HEAD ( & adev - > vm_manager . ids_lru ) ;
/* skip over VMID 0, since it is the system VM */
2016-03-01 15:09:25 +01:00
for ( i = 1 ; i < adev - > vm_manager . num_ids ; + + i ) {
amdgpu_vm_reset_id ( adev , i ) ;
2016-02-15 12:33:02 +01:00
amdgpu_sync_create ( & adev - > vm_manager . ids [ i ] . active ) ;
2016-01-21 10:19:11 +01:00
list_add_tail ( & adev - > vm_manager . ids [ i ] . list ,
& adev - > vm_manager . ids_lru ) ;
2016-03-01 15:09:25 +01:00
}
2016-02-08 17:37:38 +01:00
2016-10-25 13:00:45 +01:00
adev - > vm_manager . fence_context =
dma_fence_context_alloc ( AMDGPU_MAX_RINGS ) ;
2016-06-01 10:47:36 +02:00
for ( i = 0 ; i < AMDGPU_MAX_RINGS ; + + i )
adev - > vm_manager . seqno [ i ] = 0 ;
2016-02-08 17:37:38 +01:00
atomic_set ( & adev - > vm_manager . vm_pte_next_ring , 0 ) ;
2016-05-04 10:34:03 +02:00
atomic64_set ( & adev - > vm_manager . client_counter , 0 ) ;
2017-01-30 11:09:31 +01:00
spin_lock_init ( & adev - > vm_manager . prt_lock ) ;
2017-02-14 16:02:52 +01:00
atomic_set ( & adev - > vm_manager . num_prt_users , 0 ) ;
2016-01-21 10:19:11 +01:00
}
2015-11-15 20:52:06 +01:00
/**
* amdgpu_vm_manager_fini - cleanup VM manager
*
* @ adev : amdgpu_device pointer
*
* Cleanup the VM manager and free resources .
*/
void amdgpu_vm_manager_fini ( struct amdgpu_device * adev )
{
unsigned i ;
2016-03-08 15:40:11 +01:00
for ( i = 0 ; i < AMDGPU_NUM_VM ; + + i ) {
struct amdgpu_vm_id * id = & adev - > vm_manager . ids [ i ] ;
2016-10-25 13:00:45 +01:00
dma_fence_put ( adev - > vm_manager . ids [ i ] . first ) ;
2016-02-15 12:33:02 +01:00
amdgpu_sync_free ( & adev - > vm_manager . ids [ i ] . active ) ;
2016-10-25 13:00:45 +01:00
dma_fence_put ( id - > flushed_updates ) ;
2016-11-07 09:37:09 +10:00
dma_fence_put ( id - > last_flush ) ;
2016-03-08 15:40:11 +01:00
}
2015-11-15 20:52:06 +01:00
}