2014-07-17 01:27:00 +03:00
/*
* Copyright 2014 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 .
*
*/
2018-02-06 20:32:45 -05:00
# include <linux/ratelimit.h>
# include <linux/printk.h>
2014-07-17 01:27:00 +03:00
# include <linux/slab.h>
# include <linux/list.h>
# include <linux/types.h>
# include <linux/bitops.h>
2015-01-15 12:01:10 +02:00
# include <linux/sched.h>
2014-07-17 01:27:00 +03:00
# include "kfd_priv.h"
# include "kfd_device_queue_manager.h"
# include "kfd_mqd_manager.h"
# include "cik_regs.h"
# include "kfd_kernel_queue.h"
2018-10-16 11:36:15 -04:00
# include "amdgpu_amdkfd.h"
2014-07-17 01:27:00 +03:00
/* Size of the per-pipe EOP queue */
# define CIK_HPD_EOP_BYTES_LOG2 11
# define CIK_HPD_EOP_BYTES (1U << CIK_HPD_EOP_BYTES_LOG2)
static int set_pasid_vmid_mapping ( struct device_queue_manager * dqm ,
unsigned int pasid , unsigned int vmid ) ;
2017-09-27 00:09:51 -04:00
static int execute_queues_cpsch ( struct device_queue_manager * dqm ,
enum kfd_unmap_queues_filter filter ,
uint32_t filter_param ) ;
2017-09-27 00:09:48 -04:00
static int unmap_queues_cpsch ( struct device_queue_manager * dqm ,
2017-10-08 14:57:52 +03:00
enum kfd_unmap_queues_filter filter ,
uint32_t filter_param ) ;
2014-07-17 01:27:00 +03:00
2017-09-27 00:09:50 -04:00
static int map_queues_cpsch ( struct device_queue_manager * dqm ) ;
2015-01-03 22:12:32 +02:00
static void deallocate_sdma_queue ( struct device_queue_manager * dqm ,
2019-02-07 14:02:27 -06:00
struct queue * q ) ;
2014-07-17 01:27:00 +03:00
2019-05-31 16:05:59 -05:00
static inline void deallocate_hqd ( struct device_queue_manager * dqm ,
struct queue * q ) ;
static int allocate_hqd ( struct device_queue_manager * dqm , struct queue * q ) ;
static int allocate_sdma_queue ( struct device_queue_manager * dqm ,
struct queue * q ) ;
2018-07-11 22:32:58 -04:00
static void kfd_process_hw_exception ( struct work_struct * work ) ;
2015-01-03 22:12:32 +02:00
static inline
enum KFD_MQD_TYPE get_mqd_type_from_queue_type ( enum kfd_queue_type type )
2014-07-17 01:27:00 +03:00
{
2019-02-07 14:02:27 -06:00
if ( type = = KFD_QUEUE_TYPE_SDMA | | type = = KFD_QUEUE_TYPE_SDMA_XGMI )
2015-01-04 10:36:30 +02:00
return KFD_MQD_TYPE_SDMA ;
return KFD_MQD_TYPE_CP ;
2014-07-17 01:27:00 +03:00
}
2017-02-03 16:28:48 -05:00
static bool is_pipe_enabled ( struct device_queue_manager * dqm , int mec , int pipe )
{
int i ;
int pipe_offset = mec * dqm - > dev - > shared_resources . num_pipe_per_mec
+ pipe * dqm - > dev - > shared_resources . num_queue_per_pipe ;
/* queue is available for KFD usage if bit is 1 */
for ( i = 0 ; i < dqm - > dev - > shared_resources . num_queue_per_pipe ; + + i )
if ( test_bit ( pipe_offset + i ,
dqm - > dev - > shared_resources . queue_bitmap ) )
return true ;
return false ;
}
unsigned int get_queues_num ( struct device_queue_manager * dqm )
2015-02-17 11:30:31 +02:00
{
2017-02-03 16:28:48 -05:00
return bitmap_weight ( dqm - > dev - > shared_resources . queue_bitmap ,
KGD_MAX_QUEUES ) ;
2015-02-17 11:30:31 +02:00
}
2017-02-03 16:28:48 -05:00
unsigned int get_queues_per_pipe ( struct device_queue_manager * dqm )
2014-07-17 01:27:00 +03:00
{
2017-02-03 16:28:48 -05:00
return dqm - > dev - > shared_resources . num_queue_per_pipe ;
}
unsigned int get_pipes_per_mec ( struct device_queue_manager * dqm )
{
return dqm - > dev - > shared_resources . num_pipe_per_mec ;
2014-07-17 01:27:00 +03:00
}
2018-07-13 16:17:44 -04:00
static unsigned int get_num_sdma_engines ( struct device_queue_manager * dqm )
{
return dqm - > dev - > device_info - > num_sdma_engines ;
}
2019-02-07 14:02:27 -06:00
static unsigned int get_num_xgmi_sdma_engines ( struct device_queue_manager * dqm )
{
return dqm - > dev - > device_info - > num_xgmi_sdma_engines ;
}
2018-07-13 16:17:44 -04:00
unsigned int get_num_sdma_queues ( struct device_queue_manager * dqm )
{
return dqm - > dev - > device_info - > num_sdma_engines
2018-02-09 16:29:14 -05:00
* dqm - > dev - > device_info - > num_sdma_queues_per_engine ;
2018-07-13 16:17:44 -04:00
}
2019-02-07 14:02:27 -06:00
unsigned int get_num_xgmi_sdma_queues ( struct device_queue_manager * dqm )
{
return dqm - > dev - > device_info - > num_xgmi_sdma_engines
* dqm - > dev - > device_info - > num_sdma_queues_per_engine ;
}
2015-01-12 14:28:46 +02:00
void program_sh_mem_settings ( struct device_queue_manager * dqm ,
2014-07-17 01:27:00 +03:00
struct qcm_process_device * qpd )
{
2015-03-17 19:32:53 +08:00
return dqm - > dev - > kfd2kgd - > program_sh_mem_settings (
dqm - > dev - > kgd , qpd - > vmid ,
2014-07-17 01:27:00 +03:00
qpd - > sh_mem_config ,
qpd - > sh_mem_ape1_base ,
qpd - > sh_mem_ape1_limit ,
qpd - > sh_mem_bases ) ;
}
2018-04-10 17:33:05 -04:00
static int allocate_doorbell ( struct qcm_process_device * qpd , struct queue * q )
{
struct kfd_dev * dev = qpd - > dqm - > dev ;
if ( ! KFD_IS_SOC15 ( dev - > device_info - > asic_family ) ) {
/* On pre-SOC15 chips we need to use the queue ID to
* preserve the user mode ABI .
*/
q - > doorbell_id = q - > properties . queue_id ;
2019-02-07 14:02:27 -06:00
} else if ( q - > properties . type = = KFD_QUEUE_TYPE_SDMA | |
q - > properties . type = = KFD_QUEUE_TYPE_SDMA_XGMI ) {
2019-01-09 23:31:14 -05:00
/* For SDMA queues on SOC15 with 8-byte doorbell, use static
* doorbell assignments based on the engine and queue id .
* The doobell index distance between RLC ( 2 * i ) and ( 2 * i + 1 )
* for a SDMA engine is 512.
2018-04-10 17:33:05 -04:00
*/
2019-01-09 23:31:14 -05:00
uint32_t * idx_offset =
dev - > shared_resources . sdma_doorbell_idx ;
q - > doorbell_id = idx_offset [ q - > properties . sdma_engine_id ]
+ ( q - > properties . sdma_queue_id & 1 )
* KFD_QUEUE_DOORBELL_MIRROR_OFFSET
+ ( q - > properties . sdma_queue_id > > 1 ) ;
2018-04-10 17:33:05 -04:00
} else {
/* For CP queues on SOC15 reserve a free doorbell ID */
unsigned int found ;
found = find_first_zero_bit ( qpd - > doorbell_bitmap ,
KFD_MAX_NUM_OF_QUEUES_PER_PROCESS ) ;
if ( found > = KFD_MAX_NUM_OF_QUEUES_PER_PROCESS ) {
pr_debug ( " No doorbells available " ) ;
return - EBUSY ;
}
set_bit ( found , qpd - > doorbell_bitmap ) ;
q - > doorbell_id = found ;
}
q - > properties . doorbell_off =
2019-01-15 13:16:34 -05:00
kfd_get_doorbell_dw_offset_in_bar ( dev , q - > process ,
2018-04-10 17:33:05 -04:00
q - > doorbell_id ) ;
return 0 ;
}
static void deallocate_doorbell ( struct qcm_process_device * qpd ,
struct queue * q )
{
unsigned int old ;
struct kfd_dev * dev = qpd - > dqm - > dev ;
if ( ! KFD_IS_SOC15 ( dev - > device_info - > asic_family ) | |
2019-02-07 14:02:27 -06:00
q - > properties . type = = KFD_QUEUE_TYPE_SDMA | |
q - > properties . type = = KFD_QUEUE_TYPE_SDMA_XGMI )
2018-04-10 17:33:05 -04:00
return ;
old = test_and_clear_bit ( q - > doorbell_id , qpd - > doorbell_bitmap ) ;
WARN_ON ( ! old ) ;
}
2014-07-17 01:27:00 +03:00
static int allocate_vmid ( struct device_queue_manager * dqm ,
struct qcm_process_device * qpd ,
struct queue * q )
{
2019-09-25 23:49:46 -04:00
int allocated_vmid = - 1 , i ;
2014-07-17 01:27:00 +03:00
2019-09-25 23:49:46 -04:00
for ( i = dqm - > dev - > vm_info . first_vmid_kfd ;
i < = dqm - > dev - > vm_info . last_vmid_kfd ; i + + ) {
if ( ! dqm - > vmid_pasid [ i ] ) {
allocated_vmid = i ;
break ;
}
}
if ( allocated_vmid < 0 ) {
pr_err ( " no more vmid to allocate \n " ) ;
return - ENOSPC ;
}
pr_debug ( " vmid allocated: %d \n " , allocated_vmid ) ;
dqm - > vmid_pasid [ allocated_vmid ] = q - > process - > pasid ;
2014-07-17 01:27:00 +03:00
2019-09-25 23:49:46 -04:00
set_pasid_vmid_mapping ( dqm , q - > process - > pasid , allocated_vmid ) ;
2014-07-17 01:27:00 +03:00
qpd - > vmid = allocated_vmid ;
q - > properties . vmid = allocated_vmid ;
program_sh_mem_settings ( dqm , qpd ) ;
2018-02-06 20:32:44 -05:00
/* qpd->page_table_base is set earlier when register_process()
* is called , i . e . when the first queue is created .
*/
dqm - > dev - > kfd2kgd - > set_vm_context_page_table_base ( dqm - > dev - > kgd ,
qpd - > vmid ,
qpd - > page_table_base ) ;
/* invalidate the VM context after pasid and vmid mapping is set up */
kfd_flush_tlb ( qpd_to_pdd ( qpd ) ) ;
2019-09-18 18:17:57 -04:00
if ( dqm - > dev - > kfd2kgd - > set_scratch_backing_va )
dqm - > dev - > kfd2kgd - > set_scratch_backing_va ( dqm - > dev - > kgd ,
qpd - > sh_hidden_private_base , qpd - > vmid ) ;
2019-05-31 16:05:59 -05:00
2014-07-17 01:27:00 +03:00
return 0 ;
}
2018-03-15 17:27:50 -04:00
static int flush_texture_cache_nocpsch ( struct kfd_dev * kdev ,
struct qcm_process_device * qpd )
{
2018-04-10 17:33:06 -04:00
const struct packet_manager_funcs * pmf = qpd - > dqm - > packets . pmf ;
int ret ;
2018-03-15 17:27:50 -04:00
if ( ! qpd - > ib_kaddr )
return - ENOMEM ;
2018-04-10 17:33:06 -04:00
ret = pmf - > release_mem ( qpd - > ib_base , ( uint32_t * ) qpd - > ib_kaddr ) ;
if ( ret )
return ret ;
2018-03-15 17:27:50 -04:00
2018-10-16 11:36:15 -04:00
return amdgpu_amdkfd_submit_ib ( kdev - > kgd , KGD_ENGINE_MEC1 , qpd - > vmid ,
2018-04-10 17:33:06 -04:00
qpd - > ib_base , ( uint32_t * ) qpd - > ib_kaddr ,
pmf - > release_mem_size / sizeof ( uint32_t ) ) ;
2018-03-15 17:27:50 -04:00
}
2014-07-17 01:27:00 +03:00
static void deallocate_vmid ( struct device_queue_manager * dqm ,
struct qcm_process_device * qpd ,
struct queue * q )
{
2018-03-15 17:27:50 -04:00
/* On GFX v7, CP doesn't flush TC at dequeue */
if ( q - > device - > device_info - > asic_family = = CHIP_HAWAII )
if ( flush_texture_cache_nocpsch ( q - > device , qpd ) )
pr_err ( " Failed to flush TC \n " ) ;
2018-02-06 20:32:44 -05:00
kfd_flush_tlb ( qpd_to_pdd ( qpd ) ) ;
2015-01-05 15:48:28 +02:00
/* Release the vmid mapping */
set_pasid_vmid_mapping ( dqm , 0 , qpd - > vmid ) ;
2019-09-25 23:49:46 -04:00
dqm - > vmid_pasid [ qpd - > vmid ] = 0 ;
2015-01-05 15:48:28 +02:00
2014-07-17 01:27:00 +03:00
qpd - > vmid = 0 ;
q - > properties . vmid = 0 ;
}
static int create_queue_nocpsch ( struct device_queue_manager * dqm ,
struct queue * q ,
2017-11-24 18:10:54 -05:00
struct qcm_process_device * qpd )
2014-07-17 01:27:00 +03:00
{
2019-05-31 16:05:59 -05:00
struct mqd_manager * mqd_mgr ;
2014-07-17 01:27:00 +03:00
int retval ;
print_queue ( q ) ;
2018-07-11 22:32:44 -04:00
dqm_lock ( dqm ) ;
2014-07-17 01:27:00 +03:00
2015-01-18 13:18:01 +02:00
if ( dqm - > total_queue_count > = max_num_of_queues_per_device ) {
2017-08-15 23:00:05 -04:00
pr_warn ( " Can't create new usermode queue because %d queues were already created \n " ,
2015-01-18 13:18:01 +02:00
dqm - > total_queue_count ) ;
2017-08-15 23:00:07 -04:00
retval = - EPERM ;
goto out_unlock ;
2015-01-18 13:18:01 +02:00
}
2014-07-17 01:27:00 +03:00
if ( list_empty ( & qpd - > queues_list ) ) {
retval = allocate_vmid ( dqm , qpd , q ) ;
2017-08-15 23:00:07 -04:00
if ( retval )
goto out_unlock ;
2014-07-17 01:27:00 +03:00
}
q - > properties . vmid = qpd - > vmid ;
2018-02-06 20:32:45 -05:00
/*
2019-05-01 18:20:13 -04:00
* Eviction state logic : mark all queues as evicted , even ones
* not currently active . Restoring inactive queues later only
* updates the is_evicted flag but is a no - op otherwise .
2018-02-06 20:32:45 -05:00
*/
2019-05-01 18:20:13 -04:00
q - > properties . is_evicted = ! ! qpd - > evicted ;
2014-07-17 01:27:00 +03:00
2017-11-14 16:41:19 -05:00
q - > properties . tba_addr = qpd - > tba_addr ;
q - > properties . tma_addr = qpd - > tma_addr ;
2019-06-14 19:39:55 -05:00
mqd_mgr = dqm - > mqd_mgrs [ get_mqd_type_from_queue_type (
q - > properties . type ) ] ;
2019-05-31 16:05:59 -05:00
if ( q - > properties . type = = KFD_QUEUE_TYPE_COMPUTE ) {
retval = allocate_hqd ( dqm , q ) ;
if ( retval )
goto deallocate_vmid ;
pr_debug ( " Loading mqd to hqd on pipe %d, queue %d \n " ,
q - > pipe , q - > queue ) ;
} else if ( q - > properties . type = = KFD_QUEUE_TYPE_SDMA | |
q - > properties . type = = KFD_QUEUE_TYPE_SDMA_XGMI ) {
retval = allocate_sdma_queue ( dqm , q ) ;
if ( retval )
goto deallocate_vmid ;
dqm - > asic_ops . init_sdma_vm ( dqm , q , qpd ) ;
}
retval = allocate_doorbell ( qpd , q ) ;
if ( retval )
goto out_deallocate_hqd ;
2019-06-14 20:10:45 -05:00
/* Temporarily release dqm lock to avoid a circular lock dependency */
dqm_unlock ( dqm ) ;
2019-06-14 19:39:55 -05:00
q - > mqd_mem_obj = mqd_mgr - > allocate_mqd ( mqd_mgr - > dev , & q - > properties ) ;
2019-06-14 20:10:45 -05:00
dqm_lock ( dqm ) ;
2019-06-14 19:39:55 -05:00
if ( ! q - > mqd_mem_obj ) {
retval = - ENOMEM ;
goto out_deallocate_doorbell ;
}
2019-06-03 21:25:52 -05:00
mqd_mgr - > init_mqd ( mqd_mgr , & q - > mqd , q - > mqd_mem_obj ,
& q - > gart_mqd_addr , & q - > properties ) ;
2019-05-31 16:05:59 -05:00
if ( q - > properties . is_active ) {
2019-10-18 10:15:21 -04:00
if ( ! dqm - > sched_running ) {
WARN_ONCE ( 1 , " Load non-HWS mqd while stopped \n " ) ;
goto add_queue_to_list ;
}
2019-05-31 16:05:59 -05:00
if ( WARN ( q - > process - > mm ! = current - > mm ,
" should only run in user thread " ) )
retval = - EFAULT ;
else
retval = mqd_mgr - > load_mqd ( mqd_mgr , q - > mqd , q - > pipe ,
q - > queue , & q - > properties , current - > mm ) ;
if ( retval )
2019-06-14 19:39:55 -05:00
goto out_free_mqd ;
2014-07-17 01:27:00 +03:00
}
2019-10-18 10:15:21 -04:00
add_queue_to_list :
2014-07-17 01:27:00 +03:00
list_add ( & q - > list , & qpd - > queues_list ) ;
2017-09-27 00:09:54 -04:00
qpd - > queue_count + + ;
2015-01-19 16:08:14 -06:00
if ( q - > properties . is_active )
dqm - > queue_count + + ;
2014-07-17 01:27:00 +03:00
2015-01-03 22:12:32 +02:00
if ( q - > properties . type = = KFD_QUEUE_TYPE_SDMA )
dqm - > sdma_queue_count + + ;
2019-02-07 14:02:27 -06:00
else if ( q - > properties . type = = KFD_QUEUE_TYPE_SDMA_XGMI )
dqm - > xgmi_sdma_queue_count + + ;
2014-07-17 01:27:00 +03:00
2015-01-18 13:18:01 +02:00
/*
* Unconditionally increment this counter , regardless of the queue ' s
* type or whether the queue is active .
*/
dqm - > total_queue_count + + ;
pr_debug ( " Total of %d queues are accountable so far \n " ,
dqm - > total_queue_count ) ;
2019-06-14 19:39:55 -05:00
goto out_unlock ;
2015-01-18 13:18:01 +02:00
2019-06-14 19:39:55 -05:00
out_free_mqd :
mqd_mgr - > free_mqd ( mqd_mgr , q - > mqd , q - > mqd_mem_obj ) ;
2019-05-31 16:05:59 -05:00
out_deallocate_doorbell :
deallocate_doorbell ( qpd , q ) ;
out_deallocate_hqd :
if ( q - > properties . type = = KFD_QUEUE_TYPE_COMPUTE )
deallocate_hqd ( dqm , q ) ;
else if ( q - > properties . type = = KFD_QUEUE_TYPE_SDMA | |
q - > properties . type = = KFD_QUEUE_TYPE_SDMA_XGMI )
deallocate_sdma_queue ( dqm , q ) ;
deallocate_vmid :
if ( list_empty ( & qpd - > queues_list ) )
deallocate_vmid ( dqm , qpd , q ) ;
2017-08-15 23:00:07 -04:00
out_unlock :
2018-07-11 22:32:44 -04:00
dqm_unlock ( dqm ) ;
2017-08-15 23:00:07 -04:00
return retval ;
2014-07-17 01:27:00 +03:00
}
static int allocate_hqd ( struct device_queue_manager * dqm , struct queue * q )
{
bool set ;
2015-01-13 11:18:06 +02:00
int pipe , bit , i ;
2014-07-17 01:27:00 +03:00
set = false ;
2017-08-15 23:00:04 -04:00
for ( pipe = dqm - > next_pipe_to_allocate , i = 0 ;
i < get_pipes_per_mec ( dqm ) ;
2017-02-03 16:28:48 -05:00
pipe = ( ( pipe + 1 ) % get_pipes_per_mec ( dqm ) ) , + + i ) {
if ( ! is_pipe_enabled ( dqm , 0 , pipe ) )
continue ;
2014-07-17 01:27:00 +03:00
if ( dqm - > allocated_queues [ pipe ] ! = 0 ) {
2018-02-06 20:32:42 -05:00
bit = ffs ( dqm - > allocated_queues [ pipe ] ) - 1 ;
dqm - > allocated_queues [ pipe ] & = ~ ( 1 < < bit ) ;
2014-07-17 01:27:00 +03:00
q - > pipe = pipe ;
q - > queue = bit ;
set = true ;
break ;
}
}
2016-05-01 00:06:27 +10:00
if ( ! set )
2014-07-17 01:27:00 +03:00
return - EBUSY ;
2017-08-15 23:00:05 -04:00
pr_debug ( " hqd slot - pipe %d, queue %d \n " , q - > pipe , q - > queue ) ;
2014-07-17 01:27:00 +03:00
/* horizontal hqd allocation */
2017-02-03 16:28:48 -05:00
dqm - > next_pipe_to_allocate = ( pipe + 1 ) % get_pipes_per_mec ( dqm ) ;
2014-07-17 01:27:00 +03:00
return 0 ;
}
static inline void deallocate_hqd ( struct device_queue_manager * dqm ,
struct queue * q )
{
2018-02-06 20:32:42 -05:00
dqm - > allocated_queues [ q - > pipe ] | = ( 1 < < q - > queue ) ;
2014-07-17 01:27:00 +03:00
}
2017-09-27 00:09:52 -04:00
/* Access to DQM has to be locked before calling destroy_queue_nocpsch_locked
* to avoid asynchronized access
*/
static int destroy_queue_nocpsch_locked ( struct device_queue_manager * dqm ,
2014-07-17 01:27:00 +03:00
struct qcm_process_device * qpd ,
struct queue * q )
{
int retval ;
2018-07-11 22:33:07 -04:00
struct mqd_manager * mqd_mgr ;
2014-07-17 01:27:00 +03:00
2018-12-05 10:15:27 -06:00
mqd_mgr = dqm - > mqd_mgrs [ get_mqd_type_from_queue_type (
q - > properties . type ) ] ;
2014-07-17 01:27:00 +03:00
2014-08-18 14:55:59 +03:00
if ( q - > properties . type = = KFD_QUEUE_TYPE_COMPUTE ) {
deallocate_hqd ( dqm , q ) ;
} else if ( q - > properties . type = = KFD_QUEUE_TYPE_SDMA ) {
dqm - > sdma_queue_count - - ;
2019-02-07 14:02:27 -06:00
deallocate_sdma_queue ( dqm , q ) ;
} else if ( q - > properties . type = = KFD_QUEUE_TYPE_SDMA_XGMI ) {
dqm - > xgmi_sdma_queue_count - - ;
deallocate_sdma_queue ( dqm , q ) ;
2015-01-22 11:40:06 +02:00
} else {
2017-08-15 23:00:05 -04:00
pr_debug ( " q->properties.type %d is invalid \n " ,
2015-01-22 11:40:06 +02:00
q - > properties . type ) ;
2017-09-27 00:09:52 -04:00
return - EINVAL ;
2014-07-17 01:27:00 +03:00
}
2017-09-27 00:09:52 -04:00
dqm - > total_queue_count - - ;
2014-07-17 01:27:00 +03:00
2018-04-10 17:33:05 -04:00
deallocate_doorbell ( qpd , q ) ;
2019-10-18 10:15:21 -04:00
if ( ! dqm - > sched_running ) {
WARN_ONCE ( 1 , " Destroy non-HWS queue while stopped \n " ) ;
return 0 ;
}
2018-07-11 22:33:07 -04:00
retval = mqd_mgr - > destroy_mqd ( mqd_mgr , q - > mqd ,
2014-08-18 14:55:59 +03:00
KFD_PREEMPT_TYPE_WAVEFRONT_RESET ,
2017-09-20 18:10:16 -04:00
KFD_UNMAP_LATENCY_MS ,
2014-07-17 01:27:00 +03:00
q - > pipe , q - > queue ) ;
2017-09-27 00:09:52 -04:00
if ( retval = = - ETIME )
qpd - > reset_wavefronts = true ;
2014-07-17 01:27:00 +03:00
2019-06-03 21:25:52 -05:00
mqd_mgr - > free_mqd ( mqd_mgr , q - > mqd , q - > mqd_mem_obj ) ;
2014-07-17 01:27:00 +03:00
list_del ( & q - > list ) ;
2017-09-27 00:09:52 -04:00
if ( list_empty ( & qpd - > queues_list ) ) {
if ( qpd - > reset_wavefronts ) {
pr_warn ( " Resetting wave fronts (nocpsch) on dev %p \n " ,
dqm - > dev ) ;
/* dbgdev_wave_reset_wavefronts has to be called before
* deallocate_vmid ( ) , i . e . when vmid is still in use .
*/
dbgdev_wave_reset_wavefronts ( dqm - > dev ,
qpd - > pqm - > process ) ;
qpd - > reset_wavefronts = false ;
}
2014-07-17 01:27:00 +03:00
deallocate_vmid ( dqm , qpd , q ) ;
2017-09-27 00:09:52 -04:00
}
2017-09-27 00:09:54 -04:00
qpd - > queue_count - - ;
2015-01-19 16:08:14 -06:00
if ( q - > properties . is_active )
dqm - > queue_count - - ;
2015-01-18 13:18:01 +02:00
2017-09-27 00:09:52 -04:00
return retval ;
}
2015-01-18 13:18:01 +02:00
2017-09-27 00:09:52 -04:00
static int destroy_queue_nocpsch ( struct device_queue_manager * dqm ,
struct qcm_process_device * qpd ,
struct queue * q )
{
int retval ;
2018-07-11 22:32:44 -04:00
dqm_lock ( dqm ) ;
2017-09-27 00:09:52 -04:00
retval = destroy_queue_nocpsch_locked ( dqm , qpd , q ) ;
2018-07-11 22:32:44 -04:00
dqm_unlock ( dqm ) ;
2017-09-27 00:09:52 -04:00
2014-07-17 01:27:00 +03:00
return retval ;
}
static int update_queue ( struct device_queue_manager * dqm , struct queue * q )
{
2019-06-03 21:25:52 -05:00
int retval = 0 ;
2018-07-11 22:33:07 -04:00
struct mqd_manager * mqd_mgr ;
2018-02-06 20:32:45 -05:00
struct kfd_process_device * pdd ;
2014-12-07 22:27:24 +02:00
bool prev_active = false ;
2014-07-17 01:27:00 +03:00
2018-07-11 22:32:44 -04:00
dqm_lock ( dqm ) ;
2018-02-06 20:32:45 -05:00
pdd = kfd_get_process_device_data ( q - > device , q - > process ) ;
if ( ! pdd ) {
retval = - ENODEV ;
goto out_unlock ;
}
2018-12-05 10:15:27 -06:00
mqd_mgr = dqm - > mqd_mgrs [ get_mqd_type_from_queue_type (
q - > properties . type ) ] ;
2014-07-17 01:27:00 +03:00
2017-09-27 00:09:50 -04:00
/* Save previous activity state for counters */
prev_active = q - > properties . is_active ;
/* Make sure the queue is unmapped before updating the MQD */
2018-01-04 17:17:43 -05:00
if ( dqm - > sched_policy ! = KFD_SCHED_POLICY_NO_HWS ) {
2017-09-27 00:09:50 -04:00
retval = unmap_queues_cpsch ( dqm ,
KFD_UNMAP_QUEUES_FILTER_DYNAMIC_QUEUES , 0 ) ;
2017-11-01 19:21:33 -04:00
if ( retval ) {
2017-09-27 00:09:50 -04:00
pr_err ( " unmap queue failed \n " ) ;
goto out_unlock ;
}
2017-11-01 19:21:33 -04:00
} else if ( prev_active & &
2017-09-27 00:09:50 -04:00
( q - > properties . type = = KFD_QUEUE_TYPE_COMPUTE | |
2019-02-07 14:02:27 -06:00
q - > properties . type = = KFD_QUEUE_TYPE_SDMA | |
q - > properties . type = = KFD_QUEUE_TYPE_SDMA_XGMI ) ) {
2019-10-18 10:15:21 -04:00
if ( ! dqm - > sched_running ) {
WARN_ONCE ( 1 , " Update non-HWS queue while stopped \n " ) ;
goto out_unlock ;
}
2018-07-11 22:33:07 -04:00
retval = mqd_mgr - > destroy_mqd ( mqd_mgr , q - > mqd ,
2017-09-27 00:09:50 -04:00
KFD_PREEMPT_TYPE_WAVEFRONT_DRAIN ,
KFD_UNMAP_LATENCY_MS , q - > pipe , q - > queue ) ;
if ( retval ) {
pr_err ( " destroy mqd failed \n " ) ;
goto out_unlock ;
}
}
2019-06-03 21:25:52 -05:00
mqd_mgr - > update_mqd ( mqd_mgr , q - > mqd , & q - > properties ) ;
2017-09-27 00:09:50 -04:00
2017-11-01 19:21:32 -04:00
/*
* check active state vs . the previous state and modify
* counter accordingly . map_queues_cpsch uses the
* dqm - > queue_count to determine whether a new runlist must be
* uploaded .
*/
if ( q - > properties . is_active & & ! prev_active )
dqm - > queue_count + + ;
else if ( ! q - > properties . is_active & & prev_active )
dqm - > queue_count - - ;
2018-01-04 17:17:43 -05:00
if ( dqm - > sched_policy ! = KFD_SCHED_POLICY_NO_HWS )
2017-09-27 00:09:50 -04:00
retval = map_queues_cpsch ( dqm ) ;
2017-11-01 19:21:33 -04:00
else if ( q - > properties . is_active & &
2017-09-27 00:09:50 -04:00
( q - > properties . type = = KFD_QUEUE_TYPE_COMPUTE | |
2019-02-07 14:02:27 -06:00
q - > properties . type = = KFD_QUEUE_TYPE_SDMA | |
q - > properties . type = = KFD_QUEUE_TYPE_SDMA_XGMI ) ) {
2018-08-22 15:28:44 -04:00
if ( WARN ( q - > process - > mm ! = current - > mm ,
" should only run in user thread " ) )
retval = - EFAULT ;
else
retval = mqd_mgr - > load_mqd ( mqd_mgr , q - > mqd ,
q - > pipe , q - > queue ,
& q - > properties , current - > mm ) ;
}
2014-12-07 22:27:24 +02:00
2017-08-15 23:00:07 -04:00
out_unlock :
2018-07-11 22:32:44 -04:00
dqm_unlock ( dqm ) ;
2014-07-17 01:27:00 +03:00
return retval ;
}
2018-02-06 20:32:45 -05:00
static int evict_process_queues_nocpsch ( struct device_queue_manager * dqm ,
struct qcm_process_device * qpd )
{
struct queue * q ;
2018-07-11 22:33:07 -04:00
struct mqd_manager * mqd_mgr ;
2018-02-06 20:32:45 -05:00
struct kfd_process_device * pdd ;
2019-05-01 18:20:13 -04:00
int retval , ret = 0 ;
2018-02-06 20:32:45 -05:00
2018-07-11 22:32:44 -04:00
dqm_lock ( dqm ) ;
2018-02-06 20:32:45 -05:00
if ( qpd - > evicted + + > 0 ) /* already evicted, do nothing */
goto out ;
pdd = qpd_to_pdd ( qpd ) ;
2019-09-25 17:00:59 -04:00
pr_info_ratelimited ( " Evicting PASID 0x%x queues \n " ,
2018-02-06 20:32:45 -05:00
pdd - > process - > pasid ) ;
2019-05-01 18:20:13 -04:00
/* Mark all queues as evicted. Deactivate all active queues on
* the qpd .
*/
2018-02-06 20:32:45 -05:00
list_for_each_entry ( q , & qpd - > queues_list , list ) {
2019-05-01 18:20:13 -04:00
q - > properties . is_evicted = true ;
2018-02-06 20:32:45 -05:00
if ( ! q - > properties . is_active )
continue ;
2019-05-01 18:20:13 -04:00
2018-12-05 10:15:27 -06:00
mqd_mgr = dqm - > mqd_mgrs [ get_mqd_type_from_queue_type (
q - > properties . type ) ] ;
2018-02-06 20:32:45 -05:00
q - > properties . is_active = false ;
2019-10-18 10:15:21 -04:00
dqm - > queue_count - - ;
if ( WARN_ONCE ( ! dqm - > sched_running , " Evict when stopped \n " ) )
continue ;
2018-07-11 22:33:07 -04:00
retval = mqd_mgr - > destroy_mqd ( mqd_mgr , q - > mqd ,
2018-02-06 20:32:45 -05:00
KFD_PREEMPT_TYPE_WAVEFRONT_DRAIN ,
KFD_UNMAP_LATENCY_MS , q - > pipe , q - > queue ) ;
2019-05-01 18:20:13 -04:00
if ( retval & & ! ret )
/* Return the first error, but keep going to
* maintain a consistent eviction state
*/
ret = retval ;
2018-02-06 20:32:45 -05:00
}
out :
2018-07-11 22:32:44 -04:00
dqm_unlock ( dqm ) ;
2019-05-01 18:20:13 -04:00
return ret ;
2018-02-06 20:32:45 -05:00
}
static int evict_process_queues_cpsch ( struct device_queue_manager * dqm ,
struct qcm_process_device * qpd )
{
struct queue * q ;
struct kfd_process_device * pdd ;
int retval = 0 ;
2018-07-11 22:32:44 -04:00
dqm_lock ( dqm ) ;
2018-02-06 20:32:45 -05:00
if ( qpd - > evicted + + > 0 ) /* already evicted, do nothing */
goto out ;
pdd = qpd_to_pdd ( qpd ) ;
2019-09-25 17:00:59 -04:00
pr_info_ratelimited ( " Evicting PASID 0x%x queues \n " ,
2018-02-06 20:32:45 -05:00
pdd - > process - > pasid ) ;
2019-05-01 18:20:13 -04:00
/* Mark all queues as evicted. Deactivate all active queues on
* the qpd .
*/
2018-02-06 20:32:45 -05:00
list_for_each_entry ( q , & qpd - > queues_list , list ) {
2019-05-01 18:20:13 -04:00
q - > properties . is_evicted = true ;
2018-02-06 20:32:45 -05:00
if ( ! q - > properties . is_active )
continue ;
2019-05-01 18:20:13 -04:00
2018-02-06 20:32:45 -05:00
q - > properties . is_active = false ;
dqm - > queue_count - - ;
}
retval = execute_queues_cpsch ( dqm ,
qpd - > is_debug ?
KFD_UNMAP_QUEUES_FILTER_ALL_QUEUES :
KFD_UNMAP_QUEUES_FILTER_DYNAMIC_QUEUES , 0 ) ;
out :
2018-07-11 22:32:44 -04:00
dqm_unlock ( dqm ) ;
2018-02-06 20:32:45 -05:00
return retval ;
}
static int restore_process_queues_nocpsch ( struct device_queue_manager * dqm ,
struct qcm_process_device * qpd )
{
2018-08-22 15:28:44 -04:00
struct mm_struct * mm = NULL ;
2018-02-06 20:32:45 -05:00
struct queue * q ;
2018-07-11 22:33:07 -04:00
struct mqd_manager * mqd_mgr ;
2018-02-06 20:32:45 -05:00
struct kfd_process_device * pdd ;
2018-03-13 17:44:09 -04:00
uint64_t pd_base ;
2019-05-01 18:20:13 -04:00
int retval , ret = 0 ;
2018-02-06 20:32:45 -05:00
pdd = qpd_to_pdd ( qpd ) ;
/* Retrieve PD base */
2018-10-16 11:36:15 -04:00
pd_base = amdgpu_amdkfd_gpuvm_get_process_page_dir ( pdd - > vm ) ;
2018-02-06 20:32:45 -05:00
2018-07-11 22:32:44 -04:00
dqm_lock ( dqm ) ;
2018-02-06 20:32:45 -05:00
if ( WARN_ON_ONCE ( ! qpd - > evicted ) ) /* already restored, do nothing */
goto out ;
if ( qpd - > evicted > 1 ) { /* ref count still > 0, decrement & quit */
qpd - > evicted - - ;
goto out ;
}
2019-09-25 17:00:59 -04:00
pr_info_ratelimited ( " Restoring PASID 0x%x queues \n " ,
2018-02-06 20:32:45 -05:00
pdd - > process - > pasid ) ;
/* Update PD Base in QPD */
qpd - > page_table_base = pd_base ;
2018-03-13 17:44:09 -04:00
pr_debug ( " Updated PD address to 0x%llx \n " , pd_base ) ;
2018-02-06 20:32:45 -05:00
if ( ! list_empty ( & qpd - > queues_list ) ) {
dqm - > dev - > kfd2kgd - > set_vm_context_page_table_base (
dqm - > dev - > kgd ,
qpd - > vmid ,
qpd - > page_table_base ) ;
kfd_flush_tlb ( pdd ) ;
}
2018-08-22 15:28:44 -04:00
/* Take a safe reference to the mm_struct, which may otherwise
* disappear even while the kfd_process is still referenced .
*/
mm = get_task_mm ( pdd - > process - > lead_thread ) ;
if ( ! mm ) {
2019-05-01 18:20:13 -04:00
ret = - EFAULT ;
2018-08-22 15:28:44 -04:00
goto out ;
}
2019-05-01 18:20:13 -04:00
/* Remove the eviction flags. Activate queues that are not
* inactive for other reasons .
*/
2018-02-06 20:32:45 -05:00
list_for_each_entry ( q , & qpd - > queues_list , list ) {
2019-05-01 18:20:13 -04:00
q - > properties . is_evicted = false ;
if ( ! QUEUE_IS_ACTIVE ( q - > properties ) )
2018-02-06 20:32:45 -05:00
continue ;
2019-05-01 18:20:13 -04:00
2018-12-05 10:15:27 -06:00
mqd_mgr = dqm - > mqd_mgrs [ get_mqd_type_from_queue_type (
q - > properties . type ) ] ;
2018-02-06 20:32:45 -05:00
q - > properties . is_active = true ;
2019-10-18 10:15:21 -04:00
dqm - > queue_count + + ;
if ( WARN_ONCE ( ! dqm - > sched_running , " Restore when stopped \n " ) )
continue ;
2018-07-11 22:33:07 -04:00
retval = mqd_mgr - > load_mqd ( mqd_mgr , q - > mqd , q - > pipe ,
2018-08-22 15:28:44 -04:00
q - > queue , & q - > properties , mm ) ;
2019-05-01 18:20:13 -04:00
if ( retval & & ! ret )
/* Return the first error, but keep going to
* maintain a consistent eviction state
*/
ret = retval ;
2018-02-06 20:32:45 -05:00
}
qpd - > evicted = 0 ;
out :
2018-08-22 15:28:44 -04:00
if ( mm )
mmput ( mm ) ;
2018-07-11 22:32:44 -04:00
dqm_unlock ( dqm ) ;
2019-05-01 18:20:13 -04:00
return ret ;
2018-02-06 20:32:45 -05:00
}
static int restore_process_queues_cpsch ( struct device_queue_manager * dqm ,
struct qcm_process_device * qpd )
{
struct queue * q ;
struct kfd_process_device * pdd ;
2018-03-13 17:44:09 -04:00
uint64_t pd_base ;
2018-02-06 20:32:45 -05:00
int retval = 0 ;
pdd = qpd_to_pdd ( qpd ) ;
/* Retrieve PD base */
2018-10-16 11:36:15 -04:00
pd_base = amdgpu_amdkfd_gpuvm_get_process_page_dir ( pdd - > vm ) ;
2018-02-06 20:32:45 -05:00
2018-07-11 22:32:44 -04:00
dqm_lock ( dqm ) ;
2018-02-06 20:32:45 -05:00
if ( WARN_ON_ONCE ( ! qpd - > evicted ) ) /* already restored, do nothing */
goto out ;
if ( qpd - > evicted > 1 ) { /* ref count still > 0, decrement & quit */
qpd - > evicted - - ;
goto out ;
}
2019-09-25 17:00:59 -04:00
pr_info_ratelimited ( " Restoring PASID 0x%x queues \n " ,
2018-02-06 20:32:45 -05:00
pdd - > process - > pasid ) ;
/* Update PD Base in QPD */
qpd - > page_table_base = pd_base ;
2018-03-13 17:44:09 -04:00
pr_debug ( " Updated PD address to 0x%llx \n " , pd_base ) ;
2018-02-06 20:32:45 -05:00
/* activate all active queues on the qpd */
list_for_each_entry ( q , & qpd - > queues_list , list ) {
q - > properties . is_evicted = false ;
2019-05-01 18:20:13 -04:00
if ( ! QUEUE_IS_ACTIVE ( q - > properties ) )
continue ;
2018-02-06 20:32:45 -05:00
q - > properties . is_active = true ;
dqm - > queue_count + + ;
}
retval = execute_queues_cpsch ( dqm ,
KFD_UNMAP_QUEUES_FILTER_DYNAMIC_QUEUES , 0 ) ;
2019-05-01 18:20:13 -04:00
qpd - > evicted = 0 ;
2018-02-06 20:32:45 -05:00
out :
2018-07-11 22:32:44 -04:00
dqm_unlock ( dqm ) ;
2018-02-06 20:32:45 -05:00
return retval ;
}
2017-09-20 18:10:20 -04:00
static int register_process ( struct device_queue_manager * dqm ,
2014-07-17 01:27:00 +03:00
struct qcm_process_device * qpd )
{
struct device_process_node * n ;
2018-02-06 20:32:44 -05:00
struct kfd_process_device * pdd ;
2018-03-13 17:44:09 -04:00
uint64_t pd_base ;
2015-01-12 14:28:46 +02:00
int retval ;
2014-07-17 01:27:00 +03:00
2017-08-15 23:00:08 -04:00
n = kzalloc ( sizeof ( * n ) , GFP_KERNEL ) ;
2014-07-17 01:27:00 +03:00
if ( ! n )
return - ENOMEM ;
n - > qpd = qpd ;
2018-02-06 20:32:44 -05:00
pdd = qpd_to_pdd ( qpd ) ;
/* Retrieve PD base */
2018-10-16 11:36:15 -04:00
pd_base = amdgpu_amdkfd_gpuvm_get_process_page_dir ( pdd - > vm ) ;
2018-02-06 20:32:44 -05:00
2018-07-11 22:32:44 -04:00
dqm_lock ( dqm ) ;
2014-07-17 01:27:00 +03:00
list_add ( & n - > list , & dqm - > queues ) ;
2018-02-06 20:32:44 -05:00
/* Update PD Base in QPD */
qpd - > page_table_base = pd_base ;
2018-03-13 17:44:09 -04:00
pr_debug ( " Updated PD address to 0x%llx \n " , pd_base ) ;
2018-02-06 20:32:44 -05:00
2017-11-01 19:21:31 -04:00
retval = dqm - > asic_ops . update_qpd ( dqm , qpd ) ;
2015-01-12 14:28:46 +02:00
2019-01-25 16:35:35 -05:00
dqm - > processes_count + + ;
2014-07-17 01:27:00 +03:00
2018-07-11 22:32:44 -04:00
dqm_unlock ( dqm ) ;
2014-07-17 01:27:00 +03:00
2019-04-23 23:32:56 -04:00
/* Outside the DQM lock because under the DQM lock we can't do
* reclaim or take other locks that others hold while reclaiming .
*/
kfd_inc_compute_active ( dqm - > dev ) ;
2015-01-12 14:28:46 +02:00
return retval ;
2014-07-17 01:27:00 +03:00
}
2017-09-20 18:10:20 -04:00
static int unregister_process ( struct device_queue_manager * dqm ,
2014-07-17 01:27:00 +03:00
struct qcm_process_device * qpd )
{
int retval ;
struct device_process_node * cur , * next ;
2015-04-14 14:13:18 +03:00
pr_debug ( " qpd->queues_list is %s \n " ,
list_empty ( & qpd - > queues_list ) ? " empty " : " not empty " ) ;
2014-07-17 01:27:00 +03:00
retval = 0 ;
2018-07-11 22:32:44 -04:00
dqm_lock ( dqm ) ;
2014-07-17 01:27:00 +03:00
list_for_each_entry_safe ( cur , next , & dqm - > queues , list ) {
if ( qpd = = cur - > qpd ) {
list_del ( & cur - > list ) ;
2014-11-20 11:52:16 -06:00
kfree ( cur ) ;
2019-01-25 16:35:35 -05:00
dqm - > processes_count - - ;
2014-07-17 01:27:00 +03:00
goto out ;
}
}
/* qpd not found in dqm list */
retval = 1 ;
out :
2018-07-11 22:32:44 -04:00
dqm_unlock ( dqm ) ;
2019-04-23 23:32:56 -04:00
/* Outside the DQM lock because under the DQM lock we can't do
* reclaim or take other locks that others hold while reclaiming .
*/
if ( ! retval )
kfd_dec_compute_active ( dqm - > dev ) ;
2014-07-17 01:27:00 +03:00
return retval ;
}
static int
set_pasid_vmid_mapping ( struct device_queue_manager * dqm , unsigned int pasid ,
unsigned int vmid )
{
2015-03-17 19:32:53 +08:00
return dqm - > dev - > kfd2kgd - > set_pasid_vmid_mapping (
2018-10-14 16:25:07 -04:00
dqm - > dev - > kgd , pasid , vmid ) ;
2014-07-17 01:27:00 +03:00
}
2014-07-17 01:37:30 +03:00
static void init_interrupts ( struct device_queue_manager * dqm )
{
unsigned int i ;
2017-02-03 16:28:48 -05:00
for ( i = 0 ; i < get_pipes_per_mec ( dqm ) ; i + + )
if ( is_pipe_enabled ( dqm , 0 , i ) )
dqm - > dev - > kfd2kgd - > init_interrupts ( dqm - > dev - > kgd , i ) ;
2014-07-17 01:37:30 +03:00
}
2014-07-17 01:27:00 +03:00
static int initialize_nocpsch ( struct device_queue_manager * dqm )
{
2017-08-15 23:00:02 -04:00
int pipe , queue ;
2014-07-17 01:27:00 +03:00
2017-08-15 23:00:05 -04:00
pr_debug ( " num of pipes: %d \n " , get_pipes_per_mec ( dqm ) ) ;
2014-07-17 01:27:00 +03:00
2017-08-15 23:00:07 -04:00
dqm - > allocated_queues = kcalloc ( get_pipes_per_mec ( dqm ) ,
sizeof ( unsigned int ) , GFP_KERNEL ) ;
if ( ! dqm - > allocated_queues )
return - ENOMEM ;
2018-07-11 22:32:44 -04:00
mutex_init ( & dqm - > lock_hidden ) ;
2014-07-17 01:27:00 +03:00
INIT_LIST_HEAD ( & dqm - > queues ) ;
dqm - > queue_count = dqm - > next_pipe_to_allocate = 0 ;
2015-01-03 22:12:32 +02:00
dqm - > sdma_queue_count = 0 ;
2019-02-07 14:02:27 -06:00
dqm - > xgmi_sdma_queue_count = 0 ;
2014-07-17 01:27:00 +03:00
2017-08-15 23:00:02 -04:00
for ( pipe = 0 ; pipe < get_pipes_per_mec ( dqm ) ; pipe + + ) {
int pipe_offset = pipe * get_queues_per_pipe ( dqm ) ;
for ( queue = 0 ; queue < get_queues_per_pipe ( dqm ) ; queue + + )
if ( test_bit ( pipe_offset + queue ,
dqm - > dev - > shared_resources . queue_bitmap ) )
dqm - > allocated_queues [ pipe ] | = 1 < < queue ;
}
2014-07-17 01:27:00 +03:00
2019-09-25 23:49:46 -04:00
memset ( dqm - > vmid_pasid , 0 , sizeof ( dqm - > vmid_pasid ) ) ;
2019-07-09 09:40:15 -05:00
dqm - > sdma_bitmap = ~ 0ULL > > ( 64 - get_num_sdma_queues ( dqm ) ) ;
dqm - > xgmi_sdma_bitmap = ~ 0ULL > > ( 64 - get_num_xgmi_sdma_queues ( dqm ) ) ;
2014-07-17 01:27:00 +03:00
return 0 ;
}
2017-09-20 18:10:20 -04:00
static void uninitialize ( struct device_queue_manager * dqm )
2014-07-17 01:27:00 +03:00
{
2014-11-25 15:16:38 +02:00
int i ;
2017-08-15 23:00:12 -04:00
WARN_ON ( dqm - > queue_count > 0 | | dqm - > processes_count > 0 ) ;
2014-07-17 01:27:00 +03:00
kfree ( dqm - > allocated_queues ) ;
2014-11-25 15:16:38 +02:00
for ( i = 0 ; i < KFD_MQD_TYPE_MAX ; i + + )
2018-07-11 22:33:07 -04:00
kfree ( dqm - > mqd_mgrs [ i ] ) ;
2018-07-11 22:32:44 -04:00
mutex_destroy ( & dqm - > lock_hidden ) ;
2014-07-17 01:27:00 +03:00
}
static int start_nocpsch ( struct device_queue_manager * dqm )
{
2020-01-10 14:15:52 -05:00
pr_info ( " SW scheduler is used " ) ;
2014-07-17 01:37:30 +03:00
init_interrupts ( dqm ) ;
2019-01-22 20:09:17 -05:00
if ( dqm - > dev - > device_info - > asic_family = = CHIP_HAWAII )
return pm_init ( & dqm - > packets , dqm ) ;
2019-10-18 10:15:21 -04:00
dqm - > sched_running = true ;
2019-01-22 20:09:17 -05:00
return 0 ;
2014-07-17 01:27:00 +03:00
}
static int stop_nocpsch ( struct device_queue_manager * dqm )
{
2019-01-22 20:09:17 -05:00
if ( dqm - > dev - > device_info - > asic_family = = CHIP_HAWAII )
2019-12-20 02:46:55 -05:00
pm_uninit ( & dqm - > packets , false ) ;
2019-10-18 10:15:21 -04:00
dqm - > sched_running = false ;
2014-07-17 01:27:00 +03:00
return 0 ;
}
2019-12-20 02:07:54 -05:00
static void pre_reset ( struct device_queue_manager * dqm )
{
dqm_lock ( dqm ) ;
dqm - > is_resetting = true ;
dqm_unlock ( dqm ) ;
}
2015-01-03 22:12:32 +02:00
static int allocate_sdma_queue ( struct device_queue_manager * dqm ,
2019-01-14 17:36:26 -05:00
struct queue * q )
2015-01-03 22:12:32 +02:00
{
int bit ;
2019-02-07 14:02:27 -06:00
if ( q - > properties . type = = KFD_QUEUE_TYPE_SDMA ) {
if ( dqm - > sdma_bitmap = = 0 )
return - ENOMEM ;
bit = __ffs64 ( dqm - > sdma_bitmap ) ;
dqm - > sdma_bitmap & = ~ ( 1ULL < < bit ) ;
q - > sdma_id = bit ;
q - > properties . sdma_engine_id = q - > sdma_id %
get_num_sdma_engines ( dqm ) ;
q - > properties . sdma_queue_id = q - > sdma_id /
get_num_sdma_engines ( dqm ) ;
} else if ( q - > properties . type = = KFD_QUEUE_TYPE_SDMA_XGMI ) {
if ( dqm - > xgmi_sdma_bitmap = = 0 )
return - ENOMEM ;
bit = __ffs64 ( dqm - > xgmi_sdma_bitmap ) ;
dqm - > xgmi_sdma_bitmap & = ~ ( 1ULL < < bit ) ;
q - > sdma_id = bit ;
/* sdma_engine_id is sdma id including
* both PCIe - optimized SDMAs and XGMI -
* optimized SDMAs . The calculation below
* assumes the first N engines are always
* PCIe - optimized ones
*/
q - > properties . sdma_engine_id = get_num_sdma_engines ( dqm ) +
q - > sdma_id % get_num_xgmi_sdma_engines ( dqm ) ;
q - > properties . sdma_queue_id = q - > sdma_id /
get_num_xgmi_sdma_engines ( dqm ) ;
}
2019-01-14 17:36:26 -05:00
pr_debug ( " SDMA engine id: %d \n " , q - > properties . sdma_engine_id ) ;
pr_debug ( " SDMA queue id: %d \n " , q - > properties . sdma_queue_id ) ;
2015-01-03 22:12:32 +02:00
return 0 ;
}
static void deallocate_sdma_queue ( struct device_queue_manager * dqm ,
2019-02-07 14:02:27 -06:00
struct queue * q )
2015-01-03 22:12:32 +02:00
{
2019-02-07 14:02:27 -06:00
if ( q - > properties . type = = KFD_QUEUE_TYPE_SDMA ) {
if ( q - > sdma_id > = get_num_sdma_queues ( dqm ) )
return ;
dqm - > sdma_bitmap | = ( 1ULL < < q - > sdma_id ) ;
} else if ( q - > properties . type = = KFD_QUEUE_TYPE_SDMA_XGMI ) {
if ( q - > sdma_id > = get_num_xgmi_sdma_queues ( dqm ) )
return ;
dqm - > xgmi_sdma_bitmap | = ( 1ULL < < q - > sdma_id ) ;
}
2015-01-03 22:12:32 +02:00
}
2014-07-17 01:27:00 +03:00
/*
* Device Queue Manager implementation for cp scheduler
*/
static int set_sched_resources ( struct device_queue_manager * dqm )
{
2017-02-03 16:28:48 -05:00
int i , mec ;
2014-07-17 01:27:00 +03:00
struct scheduling_resources res ;
2017-09-20 18:10:18 -04:00
res . vmid_mask = dqm - > dev - > shared_resources . compute_vmid_bitmap ;
2017-02-03 16:28:48 -05:00
res . queue_mask = 0 ;
for ( i = 0 ; i < KGD_MAX_QUEUES ; + + i ) {
mec = ( i / dqm - > dev - > shared_resources . num_queue_per_pipe )
/ dqm - > dev - > shared_resources . num_pipe_per_mec ;
if ( ! test_bit ( i , dqm - > dev - > shared_resources . queue_bitmap ) )
continue ;
/* only acquire queues from the first MEC */
if ( mec > 0 )
continue ;
/* This situation may be hit in the future if a new HW
* generation exposes more than 64 queues . If so , the
2017-08-15 23:00:04 -04:00
* definition of res . queue_mask needs updating
*/
2017-07-11 22:53:29 +03:00
if ( WARN_ON ( i > = ( sizeof ( res . queue_mask ) * 8 ) ) ) {
2017-02-03 16:28:48 -05:00
pr_err ( " Invalid queue enabled by amdgpu: %d \n " , i ) ;
break ;
}
res . queue_mask | = ( 1ull < < i ) ;
}
2019-06-14 10:55:50 -05:00
res . gws_mask = ~ 0ull ;
res . oac_mask = res . gds_heap_base = res . gds_heap_size = 0 ;
2014-07-17 01:27:00 +03:00
2017-08-15 23:00:05 -04:00
pr_debug ( " Scheduling resources: \n "
" vmid mask: 0x%8X \n "
" queue mask: 0x%8llX \n " ,
2014-07-17 01:27:00 +03:00
res . vmid_mask , res . queue_mask ) ;
return pm_send_set_resources ( & dqm - > packets , & res ) ;
}
static int initialize_cpsch ( struct device_queue_manager * dqm )
{
2017-08-15 23:00:05 -04:00
pr_debug ( " num of pipes: %d \n " , get_pipes_per_mec ( dqm ) ) ;
2014-07-17 01:27:00 +03:00
2018-07-11 22:32:44 -04:00
mutex_init ( & dqm - > lock_hidden ) ;
2014-07-17 01:27:00 +03:00
INIT_LIST_HEAD ( & dqm - > queues ) ;
dqm - > queue_count = dqm - > processes_count = 0 ;
2015-01-03 22:12:32 +02:00
dqm - > sdma_queue_count = 0 ;
2019-02-07 14:02:27 -06:00
dqm - > xgmi_sdma_queue_count = 0 ;
2014-07-17 01:27:00 +03:00
dqm - > active_runlist = false ;
2019-07-09 09:40:15 -05:00
dqm - > sdma_bitmap = ~ 0ULL > > ( 64 - get_num_sdma_queues ( dqm ) ) ;
dqm - > xgmi_sdma_bitmap = ~ 0ULL > > ( 64 - get_num_xgmi_sdma_queues ( dqm ) ) ;
2014-07-17 01:27:00 +03:00
2018-07-11 22:32:58 -04:00
INIT_WORK ( & dqm - > hw_exception_work , kfd_process_hw_exception ) ;
2017-11-01 19:21:31 -04:00
return 0 ;
2014-07-17 01:27:00 +03:00
}
static int start_cpsch ( struct device_queue_manager * dqm )
{
int retval ;
retval = 0 ;
retval = pm_init ( & dqm - > packets , dqm ) ;
2017-08-15 23:00:06 -04:00
if ( retval )
2014-07-17 01:27:00 +03:00
goto fail_packet_manager_init ;
retval = set_sched_resources ( dqm ) ;
2017-08-15 23:00:06 -04:00
if ( retval )
2014-07-17 01:27:00 +03:00
goto fail_set_sched_resources ;
2017-08-15 23:00:05 -04:00
pr_debug ( " Allocating fence memory \n " ) ;
2014-07-17 01:27:00 +03:00
/* allocate fence memory on the gart */
2014-10-26 22:00:31 +02:00
retval = kfd_gtt_sa_allocate ( dqm - > dev , sizeof ( * dqm - > fence_addr ) ,
& dqm - > fence_mem ) ;
2014-07-17 01:27:00 +03:00
2017-08-15 23:00:06 -04:00
if ( retval )
2014-07-17 01:27:00 +03:00
goto fail_allocate_vidmem ;
dqm - > fence_addr = dqm - > fence_mem - > cpu_ptr ;
dqm - > fence_gpu_addr = dqm - > fence_mem - > gpu_addr ;
2014-07-17 01:37:30 +03:00
init_interrupts ( dqm ) ;
2018-07-11 22:32:44 -04:00
dqm_lock ( dqm ) ;
2018-07-11 22:32:58 -04:00
/* clear hang status when driver try to start the hw scheduler */
dqm - > is_hws_hang = false ;
2019-12-20 02:07:54 -05:00
dqm - > is_resetting = false ;
2019-10-18 10:15:21 -04:00
dqm - > sched_running = true ;
2017-09-27 00:09:51 -04:00
execute_queues_cpsch ( dqm , KFD_UNMAP_QUEUES_FILTER_DYNAMIC_QUEUES , 0 ) ;
2018-07-11 22:32:44 -04:00
dqm_unlock ( dqm ) ;
2014-07-17 01:27:00 +03:00
return 0 ;
fail_allocate_vidmem :
fail_set_sched_resources :
2019-12-20 02:46:55 -05:00
pm_uninit ( & dqm - > packets , false ) ;
2014-07-17 01:27:00 +03:00
fail_packet_manager_init :
return retval ;
}
static int stop_cpsch ( struct device_queue_manager * dqm )
{
2019-12-20 02:46:55 -05:00
bool hanging ;
2018-07-11 22:32:44 -04:00
dqm_lock ( dqm ) ;
2019-12-20 02:46:55 -05:00
if ( ! dqm - > is_hws_hang )
unmap_queues_cpsch ( dqm , KFD_UNMAP_QUEUES_FILTER_ALL_QUEUES , 0 ) ;
hanging = dqm - > is_hws_hang | | dqm - > is_resetting ;
2019-10-18 10:15:21 -04:00
dqm - > sched_running = false ;
2018-07-11 22:32:44 -04:00
dqm_unlock ( dqm ) ;
2014-07-17 01:27:00 +03:00
2014-10-26 22:00:31 +02:00
kfd_gtt_sa_free ( dqm - > dev , dqm - > fence_mem ) ;
2019-12-20 02:46:55 -05:00
pm_uninit ( & dqm - > packets , hanging ) ;
2014-07-17 01:27:00 +03:00
return 0 ;
}
static int create_kernel_queue_cpsch ( struct device_queue_manager * dqm ,
struct kernel_queue * kq ,
struct qcm_process_device * qpd )
{
2018-07-11 22:32:44 -04:00
dqm_lock ( dqm ) ;
2015-01-18 13:18:01 +02:00
if ( dqm - > total_queue_count > = max_num_of_queues_per_device ) {
2017-08-15 23:00:05 -04:00
pr_warn ( " Can't create new kernel queue because %d queues were already created \n " ,
2015-01-18 13:18:01 +02:00
dqm - > total_queue_count ) ;
2018-07-11 22:32:44 -04:00
dqm_unlock ( dqm ) ;
2015-01-18 13:18:01 +02:00
return - EPERM ;
}
/*
* Unconditionally increment this counter , regardless of the queue ' s
* type or whether the queue is active .
*/
dqm - > total_queue_count + + ;
pr_debug ( " Total of %d queues are accountable so far \n " ,
dqm - > total_queue_count ) ;
2014-07-17 01:27:00 +03:00
list_add ( & kq - > list , & qpd - > priv_queue_list ) ;
dqm - > queue_count + + ;
qpd - > is_debug = true ;
2017-09-27 00:09:51 -04:00
execute_queues_cpsch ( dqm , KFD_UNMAP_QUEUES_FILTER_DYNAMIC_QUEUES , 0 ) ;
2018-07-11 22:32:44 -04:00
dqm_unlock ( dqm ) ;
2014-07-17 01:27:00 +03:00
return 0 ;
}
static void destroy_kernel_queue_cpsch ( struct device_queue_manager * dqm ,
struct kernel_queue * kq ,
struct qcm_process_device * qpd )
{
2018-07-11 22:32:44 -04:00
dqm_lock ( dqm ) ;
2014-07-17 01:27:00 +03:00
list_del ( & kq - > list ) ;
dqm - > queue_count - - ;
qpd - > is_debug = false ;
2017-09-27 00:09:51 -04:00
execute_queues_cpsch ( dqm , KFD_UNMAP_QUEUES_FILTER_ALL_QUEUES , 0 ) ;
2015-01-18 13:18:01 +02:00
/*
* Unconditionally decrement this counter , regardless of the queue ' s
* type .
*/
2015-01-29 10:32:25 +02:00
dqm - > total_queue_count - - ;
2015-01-18 13:18:01 +02:00
pr_debug ( " Total of %d queues are accountable so far \n " ,
dqm - > total_queue_count ) ;
2018-07-11 22:32:44 -04:00
dqm_unlock ( dqm ) ;
2014-07-17 01:27:00 +03:00
}
static int create_queue_cpsch ( struct device_queue_manager * dqm , struct queue * q ,
2017-11-24 18:10:54 -05:00
struct qcm_process_device * qpd )
2014-07-17 01:27:00 +03:00
{
int retval ;
2018-07-11 22:33:07 -04:00
struct mqd_manager * mqd_mgr ;
2014-07-17 01:27:00 +03:00
2015-01-18 13:18:01 +02:00
if ( dqm - > total_queue_count > = max_num_of_queues_per_device ) {
2017-08-15 23:00:05 -04:00
pr_warn ( " Can't create new usermode queue because %d queues were already created \n " ,
2015-01-18 13:18:01 +02:00
dqm - > total_queue_count ) ;
2019-06-14 19:32:51 -05:00
retval = - EPERM ;
goto out ;
2015-01-18 13:18:01 +02:00
}
2019-02-07 14:02:27 -06:00
if ( q - > properties . type = = KFD_QUEUE_TYPE_SDMA | |
q - > properties . type = = KFD_QUEUE_TYPE_SDMA_XGMI ) {
2019-06-14 19:27:58 -05:00
dqm_lock ( dqm ) ;
2019-01-14 17:36:26 -05:00
retval = allocate_sdma_queue ( dqm , q ) ;
2019-06-14 19:27:58 -05:00
dqm_unlock ( dqm ) ;
2017-11-01 19:21:33 -04:00
if ( retval )
2019-06-14 19:32:51 -05:00
goto out ;
2017-09-27 00:09:56 -04:00
}
2018-04-10 17:33:05 -04:00
retval = allocate_doorbell ( qpd , q ) ;
if ( retval )
goto out_deallocate_sdma_queue ;
2019-06-14 19:32:51 -05:00
mqd_mgr = dqm - > mqd_mgrs [ get_mqd_type_from_queue_type (
q - > properties . type ) ] ;
2019-07-09 15:33:53 -04:00
2019-05-31 15:07:42 -05:00
if ( q - > properties . type = = KFD_QUEUE_TYPE_SDMA | |
q - > properties . type = = KFD_QUEUE_TYPE_SDMA_XGMI )
dqm - > asic_ops . init_sdma_vm ( dqm , q , qpd ) ;
2017-11-14 16:41:19 -05:00
q - > properties . tba_addr = qpd - > tba_addr ;
q - > properties . tma_addr = qpd - > tma_addr ;
2019-06-14 19:32:51 -05:00
q - > mqd_mem_obj = mqd_mgr - > allocate_mqd ( mqd_mgr - > dev , & q - > properties ) ;
if ( ! q - > mqd_mem_obj ) {
retval = - ENOMEM ;
goto out_deallocate_doorbell ;
}
2019-07-09 15:33:53 -04:00
dqm_lock ( dqm ) ;
/*
* Eviction state logic : mark all queues as evicted , even ones
* not currently active . Restoring inactive queues later only
* updates the is_evicted flag but is a no - op otherwise .
*/
q - > properties . is_evicted = ! ! qpd - > evicted ;
2019-06-03 21:25:52 -05:00
mqd_mgr - > init_mqd ( mqd_mgr , & q - > mqd , q - > mqd_mem_obj ,
& q - > gart_mqd_addr , & q - > properties ) ;
2018-12-05 14:03:43 -05:00
2014-07-17 01:27:00 +03:00
list_add ( & q - > list , & qpd - > queues_list ) ;
2017-09-27 00:09:54 -04:00
qpd - > queue_count + + ;
2020-01-29 19:55:47 -05:00
if ( q - > properties . type = = KFD_QUEUE_TYPE_SDMA )
dqm - > sdma_queue_count + + ;
else if ( q - > properties . type = = KFD_QUEUE_TYPE_SDMA_XGMI )
dqm - > xgmi_sdma_queue_count + + ;
2014-07-17 01:27:00 +03:00
if ( q - > properties . is_active ) {
dqm - > queue_count + + ;
2017-09-27 00:09:51 -04:00
retval = execute_queues_cpsch ( dqm ,
KFD_UNMAP_QUEUES_FILTER_DYNAMIC_QUEUES , 0 ) ;
2014-07-17 01:27:00 +03:00
}
2015-01-18 13:18:01 +02:00
/*
* Unconditionally increment this counter , regardless of the queue ' s
* type or whether the queue is active .
*/
dqm - > total_queue_count + + ;
pr_debug ( " Total of %d queues are accountable so far \n " ,
dqm - > total_queue_count ) ;
2018-07-11 22:32:44 -04:00
dqm_unlock ( dqm ) ;
2018-03-23 15:30:34 -04:00
return retval ;
2019-06-14 19:32:51 -05:00
out_deallocate_doorbell :
deallocate_doorbell ( qpd , q ) ;
2018-03-23 15:30:34 -04:00
out_deallocate_sdma_queue :
2019-02-07 14:02:27 -06:00
if ( q - > properties . type = = KFD_QUEUE_TYPE_SDMA | |
2019-06-14 19:27:58 -05:00
q - > properties . type = = KFD_QUEUE_TYPE_SDMA_XGMI ) {
dqm_lock ( dqm ) ;
2019-02-07 14:02:27 -06:00
deallocate_sdma_queue ( dqm , q ) ;
2019-06-14 19:27:58 -05:00
dqm_unlock ( dqm ) ;
}
2019-06-14 19:32:51 -05:00
out :
2014-07-17 01:27:00 +03:00
return retval ;
}
2015-05-20 13:58:12 +03:00
int amdkfd_fence_wait_timeout ( unsigned int * fence_addr ,
2014-11-20 15:54:05 +02:00
unsigned int fence_value ,
2017-09-20 18:10:15 -04:00
unsigned int timeout_ms )
2014-07-17 01:27:00 +03:00
{
2017-09-20 18:10:15 -04:00
unsigned long end_jiffies = msecs_to_jiffies ( timeout_ms ) + jiffies ;
2014-07-17 01:27:00 +03:00
while ( * fence_addr ! = fence_value ) {
2017-09-20 18:10:15 -04:00
if ( time_after ( jiffies , end_jiffies ) ) {
2017-08-15 23:00:05 -04:00
pr_err ( " qcm fence wait loop timeout expired \n " ) ;
2018-07-11 22:33:05 -04:00
/* In HWS case, this is used to halt the driver thread
* in order not to mess up CP states before doing
* scandumps for FW debugging .
*/
while ( halt_if_hws_hang )
schedule ( ) ;
2014-07-17 01:27:00 +03:00
return - ETIME ;
}
2015-01-15 12:01:10 +02:00
schedule ( ) ;
2014-07-17 01:27:00 +03:00
}
return 0 ;
}
2019-02-08 15:44:35 -06:00
static int unmap_sdma_queues ( struct device_queue_manager * dqm )
2015-01-03 22:12:32 +02:00
{
2019-02-08 15:44:35 -06:00
int i , retval = 0 ;
2019-02-07 14:02:27 -06:00
for ( i = 0 ; i < dqm - > dev - > device_info - > num_sdma_engines +
dqm - > dev - > device_info - > num_xgmi_sdma_engines ; i + + ) {
2019-02-08 15:44:35 -06:00
retval = pm_send_unmap_queue ( & dqm - > packets , KFD_QUEUE_TYPE_SDMA ,
KFD_UNMAP_QUEUES_FILTER_DYNAMIC_QUEUES , 0 , false , i ) ;
if ( retval )
return retval ;
}
return retval ;
2015-01-03 22:12:32 +02:00
}
2017-09-27 00:09:50 -04:00
/* dqm->lock mutex has to be locked before calling this function */
static int map_queues_cpsch ( struct device_queue_manager * dqm )
{
int retval ;
2019-10-18 10:15:21 -04:00
if ( ! dqm - > sched_running )
return 0 ;
2017-09-27 00:09:50 -04:00
if ( dqm - > queue_count < = 0 | | dqm - > processes_count < = 0 )
return 0 ;
if ( dqm - > active_runlist )
return 0 ;
retval = pm_send_runlist ( & dqm - > packets , & dqm - > queues ) ;
2019-05-29 23:03:45 -05:00
pr_debug ( " %s sent runlist \n " , __func__ ) ;
2017-09-27 00:09:50 -04:00
if ( retval ) {
pr_err ( " failed to execute runlist \n " ) ;
return retval ;
}
dqm - > active_runlist = true ;
return retval ;
}
2017-10-08 14:57:18 +03:00
/* dqm->lock mutex has to be locked before calling this function */
2017-09-27 00:09:48 -04:00
static int unmap_queues_cpsch ( struct device_queue_manager * dqm ,
2017-10-08 14:57:52 +03:00
enum kfd_unmap_queues_filter filter ,
uint32_t filter_param )
2014-07-17 01:27:00 +03:00
{
2017-09-27 00:09:52 -04:00
int retval = 0 ;
2014-07-17 01:27:00 +03:00
2019-10-18 10:15:21 -04:00
if ( ! dqm - > sched_running )
return 0 ;
2018-07-11 22:32:58 -04:00
if ( dqm - > is_hws_hang )
return - EIO ;
2016-05-01 00:06:27 +10:00
if ( ! dqm - > active_runlist )
2017-10-08 14:57:18 +03:00
return retval ;
2015-01-03 22:12:32 +02:00
2019-02-07 14:02:27 -06:00
pr_debug ( " Before destroying queues, sdma queue count is : %u, xgmi sdma queue count is : %u \n " ,
dqm - > sdma_queue_count , dqm - > xgmi_sdma_queue_count ) ;
2015-01-03 22:12:32 +02:00
2019-02-07 14:02:27 -06:00
if ( dqm - > sdma_queue_count > 0 | | dqm - > xgmi_sdma_queue_count )
2019-02-08 15:44:35 -06:00
unmap_sdma_queues ( dqm ) ;
2015-01-03 22:12:32 +02:00
2014-07-17 01:27:00 +03:00
retval = pm_send_unmap_queue ( & dqm - > packets , KFD_QUEUE_TYPE_COMPUTE ,
2017-10-08 14:57:52 +03:00
filter , filter_param , false , 0 ) ;
2017-08-15 23:00:06 -04:00
if ( retval )
2017-10-08 14:57:18 +03:00
return retval ;
2014-07-17 01:27:00 +03:00
* dqm - > fence_addr = KFD_FENCE_INIT ;
pm_send_query_status ( & dqm - > packets , dqm - > fence_gpu_addr ,
KFD_FENCE_COMPLETED ) ;
/* should be timed out */
2015-05-20 18:05:44 +03:00
retval = amdkfd_fence_wait_timeout ( dqm - > fence_addr , KFD_FENCE_COMPLETED ,
2019-05-29 23:03:45 -05:00
queue_preemption_timeout_ms ) ;
2019-12-20 02:07:54 -05:00
if ( retval ) {
pr_err ( " The cp might be in an unrecoverable state due to an unsuccessful queues preemption \n " ) ;
dqm - > is_hws_hang = true ;
/* It's possible we're detecting a HWS hang in the
* middle of a GPU reset . No need to schedule another
* reset in this case .
*/
if ( ! dqm - > is_resetting )
schedule_work ( & dqm - > hw_exception_work ) ;
2017-10-08 14:57:18 +03:00
return retval ;
2019-12-20 02:07:54 -05:00
}
2017-09-27 00:09:52 -04:00
2014-07-17 01:27:00 +03:00
pm_release_ib ( & dqm - > packets ) ;
dqm - > active_runlist = false ;
return retval ;
}
2017-10-08 14:57:18 +03:00
/* dqm->lock mutex has to be locked before calling this function */
2017-09-27 00:09:51 -04:00
static int execute_queues_cpsch ( struct device_queue_manager * dqm ,
enum kfd_unmap_queues_filter filter ,
uint32_t filter_param )
2014-07-17 01:27:00 +03:00
{
int retval ;
2018-07-11 22:32:58 -04:00
if ( dqm - > is_hws_hang )
return - EIO ;
2017-09-27 00:09:51 -04:00
retval = unmap_queues_cpsch ( dqm , filter , filter_param ) ;
2019-12-20 02:07:54 -05:00
if ( retval )
2017-10-08 14:57:18 +03:00
return retval ;
2014-07-17 01:27:00 +03:00
2017-09-27 00:09:50 -04:00
return map_queues_cpsch ( dqm ) ;
2014-07-17 01:27:00 +03:00
}
static int destroy_queue_cpsch ( struct device_queue_manager * dqm ,
struct qcm_process_device * qpd ,
struct queue * q )
{
int retval ;
2018-07-11 22:33:07 -04:00
struct mqd_manager * mqd_mgr ;
2015-05-20 13:43:04 +03:00
2014-07-17 01:27:00 +03:00
retval = 0 ;
/* remove queue from list to prevent rescheduling after preemption */
2018-07-11 22:32:44 -04:00
dqm_lock ( dqm ) ;
2015-05-20 13:43:04 +03:00
if ( qpd - > is_debug ) {
/*
* error , currently we do not allow to destroy a queue
* of a currently debugged process
*/
retval = - EBUSY ;
goto failed_try_destroy_debugged_queue ;
}
2018-12-05 10:15:27 -06:00
mqd_mgr = dqm - > mqd_mgrs [ get_mqd_type_from_queue_type (
q - > properties . type ) ] ;
2014-07-17 01:27:00 +03:00
2018-04-10 17:33:05 -04:00
deallocate_doorbell ( qpd , q ) ;
2017-09-27 00:09:56 -04:00
if ( q - > properties . type = = KFD_QUEUE_TYPE_SDMA ) {
2015-01-03 22:12:32 +02:00
dqm - > sdma_queue_count - - ;
2019-02-07 14:02:27 -06:00
deallocate_sdma_queue ( dqm , q ) ;
} else if ( q - > properties . type = = KFD_QUEUE_TYPE_SDMA_XGMI ) {
dqm - > xgmi_sdma_queue_count - - ;
deallocate_sdma_queue ( dqm , q ) ;
2017-09-27 00:09:56 -04:00
}
2015-01-03 22:12:32 +02:00
2014-07-17 01:27:00 +03:00
list_del ( & q - > list ) ;
2017-09-27 00:09:54 -04:00
qpd - > queue_count - - ;
2018-01-02 13:10:50 -05:00
if ( q - > properties . is_active ) {
2015-01-19 16:08:14 -06:00
dqm - > queue_count - - ;
2018-01-02 13:10:50 -05:00
retval = execute_queues_cpsch ( dqm ,
2017-09-27 00:09:52 -04:00
KFD_UNMAP_QUEUES_FILTER_DYNAMIC_QUEUES , 0 ) ;
2018-01-02 13:10:50 -05:00
if ( retval = = - ETIME )
qpd - > reset_wavefronts = true ;
}
2014-07-17 01:27:00 +03:00
2015-01-18 13:18:01 +02:00
/*
* Unconditionally decrement this counter , regardless of the queue ' s
* type
*/
dqm - > total_queue_count - - ;
pr_debug ( " Total of %d queues are accountable so far \n " ,
dqm - > total_queue_count ) ;
2014-07-17 01:27:00 +03:00
2018-07-11 22:32:44 -04:00
dqm_unlock ( dqm ) ;
2014-07-17 01:27:00 +03:00
2019-06-03 21:25:52 -05:00
/* Do free_mqd after dqm_unlock(dqm) to avoid circular locking */
mqd_mgr - > free_mqd ( mqd_mgr , q - > mqd , q - > mqd_mem_obj ) ;
2018-12-05 14:03:43 -05:00
2018-01-02 13:10:49 -05:00
return retval ;
2014-07-17 01:27:00 +03:00
2015-05-20 13:43:04 +03:00
failed_try_destroy_debugged_queue :
2018-07-11 22:32:44 -04:00
dqm_unlock ( dqm ) ;
2014-07-17 01:27:00 +03:00
return retval ;
}
/*
* Low bits must be 0000 / FFFF as required by HW , high bits must be 0 to
* stay in user mode .
*/
# define APE1_FIXED_BITS_MASK 0xFFFF80000000FFFFULL
/* APE1 limit is inclusive and 64K aligned. */
# define APE1_LIMIT_ALIGNMENT 0xFFFF
static bool set_cache_memory_policy ( struct device_queue_manager * dqm ,
struct qcm_process_device * qpd ,
enum cache_policy default_policy ,
enum cache_policy alternate_policy ,
void __user * alternate_aperture_base ,
uint64_t alternate_aperture_size )
{
2018-04-10 17:33:09 -04:00
bool retval = true ;
if ( ! dqm - > asic_ops . set_cache_memory_policy )
return retval ;
2014-07-17 01:27:00 +03:00
2018-07-11 22:32:44 -04:00
dqm_lock ( dqm ) ;
2014-07-17 01:27:00 +03:00
if ( alternate_aperture_size = = 0 ) {
/* base > limit disables APE1 */
qpd - > sh_mem_ape1_base = 1 ;
qpd - > sh_mem_ape1_limit = 0 ;
} else {
/*
* In FSA64 , APE1_Base [ 63 : 0 ] = { 16 { SH_MEM_APE1_BASE [ 31 ] } ,
* SH_MEM_APE1_BASE [ 31 : 0 ] , 0x0000 }
* APE1_Limit [ 63 : 0 ] = { 16 { SH_MEM_APE1_LIMIT [ 31 ] } ,
* SH_MEM_APE1_LIMIT [ 31 : 0 ] , 0xFFFF }
* Verify that the base and size parameters can be
* represented in this format and convert them .
* Additionally restrict APE1 to user - mode addresses .
*/
uint64_t base = ( uintptr_t ) alternate_aperture_base ;
uint64_t limit = base + alternate_aperture_size - 1 ;
2017-08-15 23:00:07 -04:00
if ( limit < = base | | ( base & APE1_FIXED_BITS_MASK ) ! = 0 | |
( limit & APE1_FIXED_BITS_MASK ) ! = APE1_LIMIT_ALIGNMENT ) {
retval = false ;
2014-07-17 01:27:00 +03:00
goto out ;
2017-08-15 23:00:07 -04:00
}
2014-07-17 01:27:00 +03:00
qpd - > sh_mem_ape1_base = base > > 16 ;
qpd - > sh_mem_ape1_limit = limit > > 16 ;
}
2017-11-01 19:21:31 -04:00
retval = dqm - > asic_ops . set_cache_memory_policy (
2015-01-12 14:28:46 +02:00
dqm ,
qpd ,
default_policy ,
alternate_policy ,
alternate_aperture_base ,
alternate_aperture_size ) ;
2014-07-17 01:27:00 +03:00
2018-01-04 17:17:43 -05:00
if ( ( dqm - > sched_policy = = KFD_SCHED_POLICY_NO_HWS ) & & ( qpd - > vmid ! = 0 ) )
2014-07-17 01:27:00 +03:00
program_sh_mem_settings ( dqm , qpd ) ;
2017-08-15 23:00:05 -04:00
pr_debug ( " sh_mem_config: 0x%x, ape1_base: 0x%x, ape1_limit: 0x%x \n " ,
2014-07-17 01:27:00 +03:00
qpd - > sh_mem_config , qpd - > sh_mem_ape1_base ,
qpd - > sh_mem_ape1_limit ) ;
out :
2018-07-11 22:32:44 -04:00
dqm_unlock ( dqm ) ;
2017-08-15 23:00:07 -04:00
return retval ;
2014-07-17 01:27:00 +03:00
}
2017-11-14 16:41:20 -05:00
static int set_trap_handler ( struct device_queue_manager * dqm ,
struct qcm_process_device * qpd ,
uint64_t tba_addr ,
uint64_t tma_addr )
{
uint64_t * tma ;
if ( dqm - > dev - > cwsr_enabled ) {
/* Jump from CWSR trap handler to user trap */
tma = ( uint64_t * ) ( qpd - > cwsr_kaddr + KFD_CWSR_TMA_OFFSET ) ;
tma [ 0 ] = tba_addr ;
tma [ 1 ] = tma_addr ;
} else {
qpd - > tba_addr = tba_addr ;
qpd - > tma_addr = tma_addr ;
}
return 0 ;
}
2017-09-27 00:09:52 -04:00
static int process_termination_nocpsch ( struct device_queue_manager * dqm ,
struct qcm_process_device * qpd )
{
struct queue * q , * next ;
struct device_process_node * cur , * next_dpn ;
int retval = 0 ;
2019-04-23 23:32:56 -04:00
bool found = false ;
2017-09-27 00:09:52 -04:00
2018-07-11 22:32:44 -04:00
dqm_lock ( dqm ) ;
2017-09-27 00:09:52 -04:00
/* Clear all user mode queues */
list_for_each_entry_safe ( q , next , & qpd - > queues_list , list ) {
int ret ;
ret = destroy_queue_nocpsch_locked ( dqm , qpd , q ) ;
if ( ret )
retval = ret ;
}
/* Unregister process */
list_for_each_entry_safe ( cur , next_dpn , & dqm - > queues , list ) {
if ( qpd = = cur - > qpd ) {
list_del ( & cur - > list ) ;
kfree ( cur ) ;
dqm - > processes_count - - ;
2019-04-23 23:32:56 -04:00
found = true ;
2017-09-27 00:09:52 -04:00
break ;
}
}
2018-07-11 22:32:44 -04:00
dqm_unlock ( dqm ) ;
2019-04-23 23:32:56 -04:00
/* Outside the DQM lock because under the DQM lock we can't do
* reclaim or take other locks that others hold while reclaiming .
*/
if ( found )
kfd_dec_compute_active ( dqm - > dev ) ;
2017-09-27 00:09:52 -04:00
return retval ;
}
2017-05-02 17:39:37 -05:00
static int get_wave_state ( struct device_queue_manager * dqm ,
struct queue * q ,
void __user * ctl_stack ,
u32 * ctl_stack_used_size ,
u32 * save_area_used_size )
{
2018-06-04 14:33:13 -04:00
struct mqd_manager * mqd_mgr ;
2017-05-02 17:39:37 -05:00
int r ;
dqm_lock ( dqm ) ;
if ( q - > properties . type ! = KFD_QUEUE_TYPE_COMPUTE | |
q - > properties . is_active | | ! q - > device - > cwsr_enabled ) {
r = - EINVAL ;
goto dqm_unlock ;
}
2019-11-08 23:57:37 -05:00
mqd_mgr = dqm - > mqd_mgrs [ KFD_MQD_TYPE_CP ] ;
2017-05-02 17:39:37 -05:00
2018-06-04 14:33:13 -04:00
if ( ! mqd_mgr - > get_wave_state ) {
2017-05-02 17:39:37 -05:00
r = - EINVAL ;
goto dqm_unlock ;
}
2018-06-04 14:33:13 -04:00
r = mqd_mgr - > get_wave_state ( mqd_mgr , q - > mqd , ctl_stack ,
ctl_stack_used_size , save_area_used_size ) ;
2017-05-02 17:39:37 -05:00
dqm_unlock :
dqm_unlock ( dqm ) ;
return r ;
}
2017-09-27 00:09:52 -04:00
static int process_termination_cpsch ( struct device_queue_manager * dqm ,
struct qcm_process_device * qpd )
{
int retval ;
struct queue * q , * next ;
struct kernel_queue * kq , * kq_next ;
2018-07-11 22:33:07 -04:00
struct mqd_manager * mqd_mgr ;
2017-09-27 00:09:52 -04:00
struct device_process_node * cur , * next_dpn ;
enum kfd_unmap_queues_filter filter =
KFD_UNMAP_QUEUES_FILTER_DYNAMIC_QUEUES ;
2019-04-23 23:32:56 -04:00
bool found = false ;
2017-09-27 00:09:52 -04:00
retval = 0 ;
2018-07-11 22:32:44 -04:00
dqm_lock ( dqm ) ;
2017-09-27 00:09:52 -04:00
/* Clean all kernel queues */
list_for_each_entry_safe ( kq , kq_next , & qpd - > priv_queue_list , list ) {
list_del ( & kq - > list ) ;
dqm - > queue_count - - ;
qpd - > is_debug = false ;
dqm - > total_queue_count - - ;
filter = KFD_UNMAP_QUEUES_FILTER_ALL_QUEUES ;
}
/* Clear all user mode queues */
list_for_each_entry ( q , & qpd - > queues_list , list ) {
2018-03-23 15:30:34 -04:00
if ( q - > properties . type = = KFD_QUEUE_TYPE_SDMA ) {
2017-09-27 00:09:52 -04:00
dqm - > sdma_queue_count - - ;
2019-02-07 14:02:27 -06:00
deallocate_sdma_queue ( dqm , q ) ;
} else if ( q - > properties . type = = KFD_QUEUE_TYPE_SDMA_XGMI ) {
dqm - > xgmi_sdma_queue_count - - ;
deallocate_sdma_queue ( dqm , q ) ;
2018-03-23 15:30:34 -04:00
}
2017-09-27 00:09:52 -04:00
if ( q - > properties . is_active )
dqm - > queue_count - - ;
dqm - > total_queue_count - - ;
}
/* Unregister process */
list_for_each_entry_safe ( cur , next_dpn , & dqm - > queues , list ) {
if ( qpd = = cur - > qpd ) {
list_del ( & cur - > list ) ;
kfree ( cur ) ;
dqm - > processes_count - - ;
2019-04-23 23:32:56 -04:00
found = true ;
2017-09-27 00:09:52 -04:00
break ;
}
}
retval = execute_queues_cpsch ( dqm , filter , 0 ) ;
2018-07-11 22:32:58 -04:00
if ( ( ! dqm - > is_hws_hang ) & & ( retval | | qpd - > reset_wavefronts ) ) {
2017-09-27 00:09:52 -04:00
pr_warn ( " Resetting wave fronts (cpsch) on dev %p \n " , dqm - > dev ) ;
dbgdev_wave_reset_wavefronts ( dqm - > dev , qpd - > pqm - > process ) ;
qpd - > reset_wavefronts = false ;
}
2018-12-05 14:03:43 -05:00
dqm_unlock ( dqm ) ;
2019-04-23 23:32:56 -04:00
/* Outside the DQM lock because under the DQM lock we can't do
* reclaim or take other locks that others hold while reclaiming .
*/
if ( found )
kfd_dec_compute_active ( dqm - > dev ) ;
2018-12-05 14:03:43 -05:00
/* Lastly, free mqd resources.
2019-06-03 21:25:52 -05:00
* Do free_mqd ( ) after dqm_unlock to avoid circular locking .
2018-12-05 14:03:43 -05:00
*/
2017-09-27 00:09:52 -04:00
list_for_each_entry_safe ( q , next , & qpd - > queues_list , list ) {
2018-12-05 10:15:27 -06:00
mqd_mgr = dqm - > mqd_mgrs [ get_mqd_type_from_queue_type (
q - > properties . type ) ] ;
2017-09-27 00:09:52 -04:00
list_del ( & q - > list ) ;
2017-09-27 00:09:54 -04:00
qpd - > queue_count - - ;
2019-06-03 21:25:52 -05:00
mqd_mgr - > free_mqd ( mqd_mgr , q - > mqd , q - > mqd_mem_obj ) ;
2017-09-27 00:09:52 -04:00
}
return retval ;
}
2018-12-05 10:15:27 -06:00
static int init_mqd_managers ( struct device_queue_manager * dqm )
{
int i , j ;
struct mqd_manager * mqd_mgr ;
for ( i = 0 ; i < KFD_MQD_TYPE_MAX ; i + + ) {
mqd_mgr = dqm - > asic_ops . mqd_manager_init ( i , dqm - > dev ) ;
if ( ! mqd_mgr ) {
pr_err ( " mqd manager [%d] initialization failed \n " , i ) ;
goto out_free ;
}
dqm - > mqd_mgrs [ i ] = mqd_mgr ;
}
return 0 ;
out_free :
for ( j = 0 ; j < i ; j + + ) {
kfree ( dqm - > mqd_mgrs [ j ] ) ;
dqm - > mqd_mgrs [ j ] = NULL ;
}
return - ENOMEM ;
}
2018-11-27 21:58:54 -06:00
/* Allocate one hiq mqd (HWS) and all SDMA mqd in a continuous trunk*/
static int allocate_hiq_sdma_mqd ( struct device_queue_manager * dqm )
{
int retval ;
struct kfd_dev * dev = dqm - > dev ;
struct kfd_mem_obj * mem_obj = & dqm - > hiq_sdma_mqd ;
uint32_t size = dqm - > mqd_mgrs [ KFD_MQD_TYPE_SDMA ] - > mqd_size *
2019-10-04 09:28:21 -05:00
( dev - > device_info - > num_sdma_engines +
dev - > device_info - > num_xgmi_sdma_engines ) *
2018-11-27 21:58:54 -06:00
dev - > device_info - > num_sdma_queues_per_engine +
dqm - > mqd_mgrs [ KFD_MQD_TYPE_HIQ ] - > mqd_size ;
retval = amdgpu_amdkfd_alloc_gtt_mem ( dev - > kgd , size ,
& ( mem_obj - > gtt_mem ) , & ( mem_obj - > gpu_addr ) ,
( void * ) & ( mem_obj - > cpu_ptr ) , true ) ;
return retval ;
}
2014-07-17 01:27:00 +03:00
struct device_queue_manager * device_queue_manager_init ( struct kfd_dev * dev )
{
struct device_queue_manager * dqm ;
2017-08-15 23:00:05 -04:00
pr_debug ( " Loading device queue manager \n " ) ;
2015-01-12 14:28:46 +02:00
2017-08-15 23:00:08 -04:00
dqm = kzalloc ( sizeof ( * dqm ) , GFP_KERNEL ) ;
2014-07-17 01:27:00 +03:00
if ( ! dqm )
return NULL ;
2018-01-04 17:17:43 -05:00
switch ( dev - > device_info - > asic_family ) {
/* HWS is not available on Hawaii. */
case CHIP_HAWAII :
/* HWS depends on CWSR for timely dequeue. CWSR is not
* available on Tonga .
*
* FIXME : This argument also applies to Kaveri .
*/
case CHIP_TONGA :
dqm - > sched_policy = KFD_SCHED_POLICY_NO_HWS ;
break ;
default :
dqm - > sched_policy = sched_policy ;
break ;
}
2014-07-17 01:27:00 +03:00
dqm - > dev = dev ;
2018-01-04 17:17:43 -05:00
switch ( dqm - > sched_policy ) {
2014-07-17 01:27:00 +03:00
case KFD_SCHED_POLICY_HWS :
case KFD_SCHED_POLICY_HWS_NO_OVERSUBSCRIPTION :
/* initialize dqm for cp scheduling */
2015-01-12 14:26:10 +02:00
dqm - > ops . create_queue = create_queue_cpsch ;
dqm - > ops . initialize = initialize_cpsch ;
dqm - > ops . start = start_cpsch ;
dqm - > ops . stop = stop_cpsch ;
2019-12-20 02:07:54 -05:00
dqm - > ops . pre_reset = pre_reset ;
2015-01-12 14:26:10 +02:00
dqm - > ops . destroy_queue = destroy_queue_cpsch ;
dqm - > ops . update_queue = update_queue ;
2017-09-20 18:10:20 -04:00
dqm - > ops . register_process = register_process ;
dqm - > ops . unregister_process = unregister_process ;
dqm - > ops . uninitialize = uninitialize ;
2015-01-12 14:26:10 +02:00
dqm - > ops . create_kernel_queue = create_kernel_queue_cpsch ;
dqm - > ops . destroy_kernel_queue = destroy_kernel_queue_cpsch ;
dqm - > ops . set_cache_memory_policy = set_cache_memory_policy ;
2017-11-14 16:41:20 -05:00
dqm - > ops . set_trap_handler = set_trap_handler ;
2017-09-27 00:09:52 -04:00
dqm - > ops . process_termination = process_termination_cpsch ;
2018-02-06 20:32:45 -05:00
dqm - > ops . evict_process_queues = evict_process_queues_cpsch ;
dqm - > ops . restore_process_queues = restore_process_queues_cpsch ;
2017-05-02 17:39:37 -05:00
dqm - > ops . get_wave_state = get_wave_state ;
2014-07-17 01:27:00 +03:00
break ;
case KFD_SCHED_POLICY_NO_HWS :
/* initialize dqm for no cp scheduling */
2015-01-12 14:26:10 +02:00
dqm - > ops . start = start_nocpsch ;
dqm - > ops . stop = stop_nocpsch ;
2019-12-20 02:07:54 -05:00
dqm - > ops . pre_reset = pre_reset ;
2015-01-12 14:26:10 +02:00
dqm - > ops . create_queue = create_queue_nocpsch ;
dqm - > ops . destroy_queue = destroy_queue_nocpsch ;
dqm - > ops . update_queue = update_queue ;
2017-09-20 18:10:20 -04:00
dqm - > ops . register_process = register_process ;
dqm - > ops . unregister_process = unregister_process ;
2015-01-12 14:26:10 +02:00
dqm - > ops . initialize = initialize_nocpsch ;
2017-09-20 18:10:20 -04:00
dqm - > ops . uninitialize = uninitialize ;
2015-01-12 14:26:10 +02:00
dqm - > ops . set_cache_memory_policy = set_cache_memory_policy ;
2017-11-14 16:41:20 -05:00
dqm - > ops . set_trap_handler = set_trap_handler ;
2017-09-27 00:09:52 -04:00
dqm - > ops . process_termination = process_termination_nocpsch ;
2018-02-06 20:32:45 -05:00
dqm - > ops . evict_process_queues = evict_process_queues_nocpsch ;
dqm - > ops . restore_process_queues =
restore_process_queues_nocpsch ;
2017-05-02 17:39:37 -05:00
dqm - > ops . get_wave_state = get_wave_state ;
2014-07-17 01:27:00 +03:00
break ;
default :
2018-01-04 17:17:43 -05:00
pr_err ( " Invalid scheduling policy %d \n " , dqm - > sched_policy ) ;
2017-08-15 23:00:12 -04:00
goto out_free ;
2014-07-17 01:27:00 +03:00
}
2015-01-12 14:28:46 +02:00
switch ( dev - > device_info - > asic_family ) {
case CHIP_CARRIZO :
2017-11-01 19:21:31 -04:00
device_queue_manager_init_vi ( & dqm - > asic_ops ) ;
2015-01-22 11:15:51 +02:00
break ;
2015-01-12 14:28:46 +02:00
case CHIP_KAVERI :
2017-11-01 19:21:31 -04:00
device_queue_manager_init_cik ( & dqm - > asic_ops ) ;
2015-01-22 11:15:51 +02:00
break ;
2018-01-04 17:17:44 -05:00
case CHIP_HAWAII :
device_queue_manager_init_cik_hawaii ( & dqm - > asic_ops ) ;
break ;
case CHIP_TONGA :
case CHIP_FIJI :
case CHIP_POLARIS10 :
case CHIP_POLARIS11 :
2018-09-05 11:27:14 -04:00
case CHIP_POLARIS12 :
2019-03-21 08:08:17 -04:00
case CHIP_VEGAM :
2018-01-04 17:17:44 -05:00
device_queue_manager_init_vi_tonga ( & dqm - > asic_ops ) ;
break ;
2018-04-10 17:33:09 -04:00
case CHIP_VEGA10 :
2018-09-05 11:27:14 -04:00
case CHIP_VEGA12 :
2017-10-31 13:32:53 -04:00
case CHIP_VEGA20 :
2018-04-10 17:33:09 -04:00
case CHIP_RAVEN :
2019-09-02 23:10:52 +08:00
case CHIP_RENOIR :
2019-07-09 09:37:04 -05:00
case CHIP_ARCTURUS :
2018-04-10 17:33:09 -04:00
device_queue_manager_init_v9 ( & dqm - > asic_ops ) ;
break ;
2019-05-29 23:03:45 -05:00
case CHIP_NAVI10 :
2019-09-25 17:07:38 -04:00
case CHIP_NAVI12 :
2019-08-13 17:13:27 -04:00
case CHIP_NAVI14 :
2019-05-29 23:03:45 -05:00
device_queue_manager_init_v10_navi10 ( & dqm - > asic_ops ) ;
break ;
2017-09-20 18:10:19 -04:00
default :
WARN ( 1 , " Unexpected ASIC family %u " ,
dev - > device_info - > asic_family ) ;
goto out_free ;
2015-01-12 14:28:46 +02:00
}
2018-12-05 10:15:27 -06:00
if ( init_mqd_managers ( dqm ) )
goto out_free ;
2018-11-27 21:58:54 -06:00
if ( allocate_hiq_sdma_mqd ( dqm ) ) {
pr_err ( " Failed to allocate hiq sdma mqd trunk buffer \n " ) ;
goto out_free ;
}
2017-08-15 23:00:12 -04:00
if ( ! dqm - > ops . initialize ( dqm ) )
return dqm ;
2014-07-17 01:27:00 +03:00
2017-08-15 23:00:12 -04:00
out_free :
kfree ( dqm ) ;
return NULL ;
2014-07-17 01:27:00 +03:00
}
2019-05-25 20:51:09 +08:00
static void deallocate_hiq_sdma_mqd ( struct kfd_dev * dev ,
struct kfd_mem_obj * mqd )
2018-11-27 21:58:54 -06:00
{
WARN ( ! mqd , " No hiq sdma mqd trunk to free " ) ;
amdgpu_amdkfd_free_gtt_mem ( dev - > kgd , mqd - > gtt_mem ) ;
}
2014-07-17 01:27:00 +03:00
void device_queue_manager_uninit ( struct device_queue_manager * dqm )
{
2015-01-12 14:26:10 +02:00
dqm - > ops . uninitialize ( dqm ) ;
2018-11-27 21:58:54 -06:00
deallocate_hiq_sdma_mqd ( dqm - > dev , & dqm - > hiq_sdma_mqd ) ;
2014-07-17 01:27:00 +03:00
kfree ( dqm ) ;
}
2017-11-27 18:29:49 -05:00
2018-07-11 22:32:50 -04:00
int kfd_process_vm_fault ( struct device_queue_manager * dqm ,
unsigned int pasid )
{
struct kfd_process_device * pdd ;
struct kfd_process * p = kfd_lookup_process_by_pasid ( pasid ) ;
int ret = 0 ;
if ( ! p )
return - EINVAL ;
pdd = kfd_get_process_device_data ( dqm - > dev , p ) ;
if ( pdd )
ret = dqm - > ops . evict_process_queues ( dqm , & pdd - > qpd ) ;
kfd_unref_process ( p ) ;
return ret ;
}
2018-07-11 22:32:58 -04:00
static void kfd_process_hw_exception ( struct work_struct * work )
{
struct device_queue_manager * dqm = container_of ( work ,
struct device_queue_manager , hw_exception_work ) ;
2018-10-16 11:36:15 -04:00
amdgpu_amdkfd_gpu_reset ( dqm - > dev - > kgd ) ;
2018-07-11 22:32:58 -04:00
}
2017-11-27 18:29:49 -05:00
# if defined(CONFIG_DEBUG_FS)
static void seq_reg_dump ( struct seq_file * m ,
uint32_t ( * dump ) [ 2 ] , uint32_t n_regs )
{
uint32_t i , count ;
for ( i = 0 , count = 0 ; i < n_regs ; i + + ) {
if ( count = = 0 | |
dump [ i - 1 ] [ 0 ] + sizeof ( uint32_t ) ! = dump [ i ] [ 0 ] ) {
seq_printf ( m , " %s %08x: %08x " ,
i ? " \n " : " " ,
dump [ i ] [ 0 ] , dump [ i ] [ 1 ] ) ;
count = 7 ;
} else {
seq_printf ( m , " %08x " , dump [ i ] [ 1 ] ) ;
count - - ;
}
}
seq_puts ( m , " \n " ) ;
}
int dqm_debugfs_hqds ( struct seq_file * m , void * data )
{
struct device_queue_manager * dqm = data ;
uint32_t ( * dump ) [ 2 ] , n_regs ;
int pipe , queue ;
int r = 0 ;
2019-10-18 10:15:21 -04:00
if ( ! dqm - > sched_running ) {
seq_printf ( m , " Device is stopped \n " ) ;
return 0 ;
}
2018-05-01 17:56:01 -04:00
r = dqm - > dev - > kfd2kgd - > hqd_dump ( dqm - > dev - > kgd ,
2019-05-29 23:03:45 -05:00
KFD_CIK_HIQ_PIPE , KFD_CIK_HIQ_QUEUE ,
& dump , & n_regs ) ;
2018-05-01 17:56:01 -04:00
if ( ! r ) {
seq_printf ( m , " HIQ on MEC %d Pipe %d Queue %d \n " ,
2019-05-29 23:03:45 -05:00
KFD_CIK_HIQ_PIPE / get_pipes_per_mec ( dqm ) + 1 ,
KFD_CIK_HIQ_PIPE % get_pipes_per_mec ( dqm ) ,
KFD_CIK_HIQ_QUEUE ) ;
2018-05-01 17:56:01 -04:00
seq_reg_dump ( m , dump , n_regs ) ;
kfree ( dump ) ;
}
2017-11-27 18:29:49 -05:00
for ( pipe = 0 ; pipe < get_pipes_per_mec ( dqm ) ; pipe + + ) {
int pipe_offset = pipe * get_queues_per_pipe ( dqm ) ;
for ( queue = 0 ; queue < get_queues_per_pipe ( dqm ) ; queue + + ) {
if ( ! test_bit ( pipe_offset + queue ,
dqm - > dev - > shared_resources . queue_bitmap ) )
continue ;
r = dqm - > dev - > kfd2kgd - > hqd_dump (
dqm - > dev - > kgd , pipe , queue , & dump , & n_regs ) ;
if ( r )
break ;
seq_printf ( m , " CP Pipe %d, Queue %d \n " ,
pipe , queue ) ;
seq_reg_dump ( m , dump , n_regs ) ;
kfree ( dump ) ;
}
}
2019-10-04 09:34:29 -05:00
for ( pipe = 0 ; pipe < get_num_sdma_engines ( dqm ) +
get_num_xgmi_sdma_engines ( dqm ) ; pipe + + ) {
2018-02-09 16:29:14 -05:00
for ( queue = 0 ;
queue < dqm - > dev - > device_info - > num_sdma_queues_per_engine ;
queue + + ) {
2017-11-27 18:29:49 -05:00
r = dqm - > dev - > kfd2kgd - > hqd_sdma_dump (
dqm - > dev - > kgd , pipe , queue , & dump , & n_regs ) ;
if ( r )
break ;
seq_printf ( m , " SDMA Engine %d, RLC %d \n " ,
pipe , queue ) ;
seq_reg_dump ( m , dump , n_regs ) ;
kfree ( dump ) ;
}
}
return r ;
}
2018-07-11 22:33:04 -04:00
int dqm_debugfs_execute_queues ( struct device_queue_manager * dqm )
{
int r = 0 ;
dqm_lock ( dqm ) ;
dqm - > active_runlist = true ;
r = execute_queues_cpsch ( dqm , KFD_UNMAP_QUEUES_FILTER_ALL_QUEUES , 0 ) ;
dqm_unlock ( dqm ) ;
return r ;
}
2017-11-27 18:29:49 -05:00
# endif