2019-03-18 13:16:03 +01:00
/*
* Copyright 2019 Advanced Micro Devices , Inc .
*
* 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 .
*/
# include "amdgpu_vm.h"
# include "amdgpu_job.h"
# include "amdgpu_object.h"
# include "amdgpu_trace.h"
# define AMDGPU_VM_SDMA_MIN_NUM_DW 256u
# define AMDGPU_VM_SDMA_MAX_NUM_DW (16u * 1024u)
2019-03-21 16:34:18 +01:00
/**
* amdgpu_vm_sdma_map_table - make sure new PDs / PTs are GTT mapped
*
* @ table : newly allocated or validated PD / PT
*/
static int amdgpu_vm_sdma_map_table ( struct amdgpu_bo * table )
{
int r ;
r = amdgpu_ttm_alloc_gart ( & table - > tbo ) ;
if ( r )
return r ;
if ( table - > shadow )
r = amdgpu_ttm_alloc_gart ( & table - > shadow - > tbo ) ;
return r ;
}
2019-03-18 13:16:03 +01:00
/**
* amdgpu_vm_sdma_prepare - prepare SDMA command submission
*
* @ p : see amdgpu_vm_update_params definition
* @ owner : owner we need to sync to
* @ exclusive : exclusive move fence we need to sync to
*
* Returns :
* Negativ errno , 0 for success .
*/
static int amdgpu_vm_sdma_prepare ( struct amdgpu_vm_update_params * p ,
2020-01-23 14:49:45 +01:00
struct dma_resv * resv ,
enum amdgpu_sync_mode sync_mode )
2019-03-18 13:16:03 +01:00
{
unsigned int ndw = AMDGPU_VM_SDMA_MIN_NUM_DW ;
int r ;
r = amdgpu_job_alloc_with_ib ( p - > adev , ndw * 4 , & p - > job ) ;
if ( r )
return r ;
2019-09-16 10:33:28 -05:00
p - > num_dw_left = ndw ;
2020-01-23 14:49:45 +01:00
if ( ! resv )
2019-09-16 10:33:28 -05:00
return 0 ;
2019-03-18 13:16:03 +01:00
2020-01-23 14:49:45 +01:00
return amdgpu_sync_resv ( p - > adev , & p - > job - > sync , resv , sync_mode , p - > vm ) ;
2019-03-18 13:16:03 +01:00
}
/**
* amdgpu_vm_sdma_commit - commit SDMA command submission
*
* @ p : see amdgpu_vm_update_params definition
* @ fence : resulting fence
*
* Returns :
* Negativ errno , 0 for success .
*/
static int amdgpu_vm_sdma_commit ( struct amdgpu_vm_update_params * p ,
struct dma_fence * * fence )
{
2019-03-21 16:43:39 +01:00
struct amdgpu_ib * ib = p - > job - > ibs ;
2019-09-16 10:33:28 -05:00
struct drm_sched_entity * entity ;
2019-11-29 12:44:07 +01:00
struct dma_fence * f , * tmp ;
2019-03-18 13:16:03 +01:00
struct amdgpu_ring * ring ;
int r ;
2019-09-16 10:33:28 -05:00
entity = p - > direct ? & p - > vm - > direct : & p - > vm - > delayed ;
ring = container_of ( entity - > rq - > sched , struct amdgpu_ring , sched ) ;
2019-03-18 13:16:03 +01:00
2019-03-21 16:43:39 +01:00
WARN_ON ( ib - > length_dw = = 0 ) ;
amdgpu_ring_pad_ib ( ring , ib ) ;
WARN_ON ( ib - > length_dw > p - > num_dw_left ) ;
2019-09-16 10:33:28 -05:00
r = amdgpu_job_submit ( p - > job , entity , AMDGPU_FENCE_OWNER_VM , & f ) ;
2019-03-18 13:16:03 +01:00
if ( r )
goto error ;
2019-11-29 12:44:07 +01:00
tmp = dma_fence_get ( f ) ;
if ( p - > direct )
swap ( p - > vm - > last_direct , tmp ) ;
else
swap ( p - > vm - > last_delayed , tmp ) ;
dma_fence_put ( tmp ) ;
2019-09-16 10:33:28 -05:00
if ( fence & & ! p - > direct )
2019-03-18 13:16:03 +01:00
swap ( * fence , f ) ;
dma_fence_put ( f ) ;
return 0 ;
error :
amdgpu_job_free ( p - > job ) ;
return r ;
}
/**
* amdgpu_vm_sdma_copy_ptes - copy the PTEs from mapping
*
* @ p : see amdgpu_vm_update_params definition
* @ bo : PD / PT to update
* @ pe : addr of the page entry
* @ count : number of page entries to copy
*
* Traces the parameters and calls the DMA function to copy the PTEs .
*/
static void amdgpu_vm_sdma_copy_ptes ( struct amdgpu_vm_update_params * p ,
struct amdgpu_bo * bo , uint64_t pe ,
unsigned count )
{
2019-03-21 16:43:39 +01:00
struct amdgpu_ib * ib = p - > job - > ibs ;
uint64_t src = ib - > gpu_addr ;
2019-03-18 13:16:03 +01:00
src + = p - > num_dw_left * 4 ;
2019-12-06 12:28:47 +01:00
pe + = amdgpu_gmc_sign_extend ( bo - > tbo . offset ) ;
2019-04-03 13:30:56 +02:00
trace_amdgpu_vm_copy_ptes ( pe , src , count , p - > direct ) ;
2019-03-18 13:16:03 +01:00
2019-03-21 16:43:39 +01:00
amdgpu_vm_copy_pte ( p - > adev , ib , pe , src , count ) ;
2019-03-18 13:16:03 +01:00
}
/**
* amdgpu_vm_sdma_set_ptes - helper to call the right asic function
*
* @ p : see amdgpu_vm_update_params definition
* @ bo : PD / PT to update
* @ 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 .
*/
static void amdgpu_vm_sdma_set_ptes ( struct amdgpu_vm_update_params * p ,
struct amdgpu_bo * bo , uint64_t pe ,
uint64_t addr , unsigned count ,
uint32_t incr , uint64_t flags )
{
2019-03-21 16:43:39 +01:00
struct amdgpu_ib * ib = p - > job - > ibs ;
2019-12-06 12:28:47 +01:00
pe + = amdgpu_gmc_sign_extend ( bo - > tbo . offset ) ;
2019-04-03 13:30:56 +02:00
trace_amdgpu_vm_set_ptes ( pe , addr , count , incr , flags , p - > direct ) ;
2019-03-18 13:16:03 +01:00
if ( count < 3 ) {
2019-03-21 16:43:39 +01:00
amdgpu_vm_write_pte ( p - > adev , ib , pe , addr | flags ,
2019-03-18 13:16:03 +01:00
count , incr ) ;
} else {
2019-03-21 16:43:39 +01:00
amdgpu_vm_set_pte_pde ( p - > adev , ib , pe , addr ,
2019-03-18 13:16:03 +01:00
count , incr , flags ) ;
}
}
/**
* amdgpu_vm_sdma_update - execute VM update
*
* @ p : see amdgpu_vm_update_params definition
* @ bo : PD / PT to update
* @ 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
*
* Reserve space in the IB , setup mapping buffer on demand and write commands to
* the IB .
*/
static int amdgpu_vm_sdma_update ( struct amdgpu_vm_update_params * p ,
struct amdgpu_bo * bo , uint64_t pe ,
uint64_t addr , unsigned count , uint32_t incr ,
uint64_t flags )
{
unsigned int i , ndw , nptes ;
uint64_t * pte ;
int r ;
2019-12-16 14:22:35 +01:00
/* Wait for PD/PT moves to be completed */
r = amdgpu_sync_fence ( & p - > job - > sync , bo - > tbo . moving , false ) ;
if ( r )
return r ;
2019-03-18 13:16:03 +01:00
do {
ndw = p - > num_dw_left ;
2019-03-21 16:43:39 +01:00
ndw - = p - > job - > ibs - > length_dw ;
2019-03-18 13:16:03 +01:00
if ( ndw < 32 ) {
r = amdgpu_vm_sdma_commit ( p , NULL ) ;
if ( r )
return r ;
/* estimate how many dw we need */
ndw = 32 ;
if ( p - > pages_addr )
ndw + = count * 2 ;
ndw = max ( ndw , AMDGPU_VM_SDMA_MIN_NUM_DW ) ;
ndw = min ( ndw , AMDGPU_VM_SDMA_MAX_NUM_DW ) ;
r = amdgpu_job_alloc_with_ib ( p - > adev , ndw * 4 , & p - > job ) ;
if ( r )
return r ;
p - > num_dw_left = ndw ;
}
if ( ! p - > pages_addr ) {
/* set page commands needed */
if ( bo - > shadow )
amdgpu_vm_sdma_set_ptes ( p , bo - > shadow , pe , addr ,
count , incr , flags ) ;
amdgpu_vm_sdma_set_ptes ( p , bo , pe , addr , count ,
incr , flags ) ;
return 0 ;
}
/* copy commands needed */
ndw - = p - > adev - > vm_manager . vm_pte_funcs - > copy_pte_num_dw *
( bo - > shadow ? 2 : 1 ) ;
/* for padding */
ndw - = 7 ;
nptes = min ( count , ndw / 2 ) ;
/* Put the PTEs at the end of the IB. */
p - > num_dw_left - = nptes * 2 ;
2019-03-21 16:43:39 +01:00
pte = ( uint64_t * ) & ( p - > job - > ibs - > ptr [ p - > num_dw_left ] ) ;
2019-03-18 13:16:03 +01:00
for ( i = 0 ; i < nptes ; + + i , addr + = incr ) {
pte [ i ] = amdgpu_vm_map_gart ( p - > pages_addr , addr ) ;
pte [ i ] | = flags ;
}
if ( bo - > shadow )
amdgpu_vm_sdma_copy_ptes ( p , bo - > shadow , pe , nptes ) ;
amdgpu_vm_sdma_copy_ptes ( p , bo , pe , nptes ) ;
pe + = nptes * 8 ;
count - = nptes ;
} while ( count ) ;
return 0 ;
}
const struct amdgpu_vm_update_funcs amdgpu_vm_sdma_funcs = {
2019-03-21 16:34:18 +01:00
. map_table = amdgpu_vm_sdma_map_table ,
2019-03-18 13:16:03 +01:00
. prepare = amdgpu_vm_sdma_prepare ,
. update = amdgpu_vm_sdma_update ,
. commit = amdgpu_vm_sdma_commit
} ;