2014-07-17 00:55:28 +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 .
*
*/
# include <linux/slab.h>
# include <linux/mutex.h>
# include "kfd_device_queue_manager.h"
# include "kfd_kernel_queue.h"
# include "kfd_priv.h"
static inline void inc_wptr ( unsigned int * wptr , unsigned int increment_bytes ,
unsigned int buffer_size_bytes )
{
unsigned int temp = * wptr + increment_bytes / sizeof ( uint32_t ) ;
2017-08-15 23:00:12 -04:00
WARN ( ( temp * sizeof ( uint32_t ) ) > buffer_size_bytes ,
" Runlist IB overflow " ) ;
2014-07-17 00:55:28 +03:00
* wptr = temp ;
}
static void pm_calc_rlib_size ( struct packet_manager * pm ,
unsigned int * rlib_size ,
bool * over_subscription )
{
2017-11-27 18:29:46 -05:00
unsigned int process_count , queue_count , compute_queue_count ;
2015-01-06 11:32:13 +02:00
unsigned int map_queue_size ;
2017-11-27 18:29:45 -05:00
unsigned int max_proc_per_quantum = 1 ;
struct kfd_dev * dev = pm - > dqm - > dev ;
2014-07-17 00:55:28 +03:00
process_count = pm - > dqm - > processes_count ;
queue_count = pm - > dqm - > queue_count ;
2017-11-27 18:29:46 -05:00
compute_queue_count = queue_count - pm - > dqm - > sdma_queue_count ;
2014-07-17 00:55:28 +03:00
2017-11-27 18:29:45 -05:00
/* check if there is over subscription
* Note : the arbitration between the number of VMIDs and
* hws_max_conc_proc has been done in
* kgd2kfd_device_init ( ) .
*/
2014-07-17 00:55:28 +03:00
* over_subscription = false ;
2017-11-27 18:29:45 -05:00
if ( dev - > max_proc_per_quantum > 1 )
max_proc_per_quantum = dev - > max_proc_per_quantum ;
if ( ( process_count > max_proc_per_quantum ) | |
2017-11-27 18:29:46 -05:00
compute_queue_count > get_queues_num ( pm - > dqm ) ) {
2014-07-17 00:55:28 +03:00
* over_subscription = true ;
2017-08-15 23:00:05 -04:00
pr_debug ( " Over subscribed runlist \n " ) ;
2014-07-17 00:55:28 +03:00
}
2018-04-10 17:33:06 -04:00
map_queue_size = pm - > pmf - > map_queues_size ;
2014-07-17 00:55:28 +03:00
/* calculate run list ib allocation size */
2018-04-10 17:33:06 -04:00
* rlib_size = process_count * pm - > pmf - > map_process_size +
2015-01-06 11:32:13 +02:00
queue_count * map_queue_size ;
2014-07-17 00:55:28 +03:00
/*
* Increase the allocation size in case we need a chained run list
* when over subscription
*/
if ( * over_subscription )
2018-04-10 17:33:06 -04:00
* rlib_size + = pm - > pmf - > runlist_size ;
2014-07-17 00:55:28 +03:00
2017-08-15 23:00:05 -04:00
pr_debug ( " runlist ib size %d \n " , * rlib_size ) ;
2014-07-17 00:55:28 +03:00
}
static int pm_allocate_runlist_ib ( struct packet_manager * pm ,
unsigned int * * rl_buffer ,
uint64_t * rl_gpu_buffer ,
unsigned int * rl_buffer_size ,
bool * is_over_subscription )
{
int retval ;
2017-08-15 23:00:12 -04:00
if ( WARN_ON ( pm - > allocated ) )
return - EINVAL ;
2014-07-17 00:55:28 +03:00
pm_calc_rlib_size ( pm , rl_buffer_size , is_over_subscription ) ;
2018-05-01 17:56:10 -04:00
mutex_lock ( & pm - > lock ) ;
2014-10-26 22:00:31 +02:00
retval = kfd_gtt_sa_allocate ( pm - > dqm - > dev , * rl_buffer_size ,
& pm - > ib_buffer_obj ) ;
2014-07-17 00:55:28 +03:00
2017-08-15 23:00:06 -04:00
if ( retval ) {
2017-08-15 23:00:05 -04:00
pr_err ( " Failed to allocate runlist IB \n " ) ;
2018-05-01 17:56:10 -04:00
goto out ;
2014-07-17 00:55:28 +03:00
}
* ( void * * ) rl_buffer = pm - > ib_buffer_obj - > cpu_ptr ;
* rl_gpu_buffer = pm - > ib_buffer_obj - > gpu_addr ;
memset ( * rl_buffer , 0 , * rl_buffer_size ) ;
pm - > allocated = true ;
2018-05-01 17:56:10 -04:00
out :
mutex_unlock ( & pm - > lock ) ;
2014-07-17 00:55:28 +03:00
return retval ;
}
static int pm_create_runlist_ib ( struct packet_manager * pm ,
struct list_head * queues ,
uint64_t * rl_gpu_addr ,
size_t * rl_size_bytes )
{
unsigned int alloc_size_bytes ;
unsigned int * rl_buffer , rl_wptr , i ;
int retval , proccesses_mapped ;
struct device_process_node * cur ;
struct qcm_process_device * qpd ;
struct queue * q ;
struct kernel_queue * kq ;
bool is_over_subscription ;
rl_wptr = retval = proccesses_mapped = 0 ;
retval = pm_allocate_runlist_ib ( pm , & rl_buffer , rl_gpu_addr ,
& alloc_size_bytes , & is_over_subscription ) ;
2017-08-15 23:00:06 -04:00
if ( retval )
2014-07-17 00:55:28 +03:00
return retval ;
* rl_size_bytes = alloc_size_bytes ;
2017-11-27 18:29:49 -05:00
pm - > ib_size_bytes = alloc_size_bytes ;
2014-07-17 00:55:28 +03:00
2017-08-15 23:00:05 -04:00
pr_debug ( " Building runlist ib process count: %d queues count %d \n " ,
2014-07-17 00:55:28 +03:00
pm - > dqm - > processes_count , pm - > dqm - > queue_count ) ;
/* build the run list ib packet */
list_for_each_entry ( cur , queues , list ) {
qpd = cur - > qpd ;
/* build map process packet */
if ( proccesses_mapped > = pm - > dqm - > processes_count ) {
2017-08-15 23:00:05 -04:00
pr_debug ( " Not enough space left in runlist IB \n " ) ;
2014-07-17 00:55:28 +03:00
pm_release_ib ( pm ) ;
return - ENOMEM ;
}
2015-05-20 13:43:04 +03:00
2018-04-10 17:33:06 -04:00
retval = pm - > pmf - > map_process ( pm , & rl_buffer [ rl_wptr ] , qpd ) ;
2017-08-15 23:00:06 -04:00
if ( retval )
2014-07-17 00:55:28 +03:00
return retval ;
2015-05-20 13:43:04 +03:00
2014-07-17 00:55:28 +03:00
proccesses_mapped + + ;
2018-04-10 17:33:06 -04:00
inc_wptr ( & rl_wptr , pm - > pmf - > map_process_size ,
2014-07-17 00:55:28 +03:00
alloc_size_bytes ) ;
list_for_each_entry ( kq , & qpd - > priv_queue_list , list ) {
2016-05-01 00:06:27 +10:00
if ( ! kq - > queue - > properties . is_active )
2014-07-17 00:55:28 +03:00
continue ;
2015-05-20 13:43:04 +03:00
2017-08-15 23:00:05 -04:00
pr_debug ( " static_queue, mapping kernel q %d, is debug status %d \n " ,
2015-05-20 13:43:04 +03:00
kq - > queue - > queue , qpd - > is_debug ) ;
2018-04-10 17:33:06 -04:00
retval = pm - > pmf - > map_queues ( pm ,
2015-01-06 11:35:50 +02:00
& rl_buffer [ rl_wptr ] ,
kq - > queue ,
qpd - > is_debug ) ;
2017-08-15 23:00:06 -04:00
if ( retval )
2014-07-17 00:55:28 +03:00
return retval ;
2015-05-20 13:43:04 +03:00
inc_wptr ( & rl_wptr ,
2018-04-10 17:33:06 -04:00
pm - > pmf - > map_queues_size ,
2015-05-20 13:43:04 +03:00
alloc_size_bytes ) ;
2014-07-17 00:55:28 +03:00
}
list_for_each_entry ( q , & qpd - > queues_list , list ) {
2016-05-01 00:06:27 +10:00
if ( ! q - > properties . is_active )
2014-07-17 00:55:28 +03:00
continue ;
2015-05-20 13:43:04 +03:00
2017-08-15 23:00:05 -04:00
pr_debug ( " static_queue, mapping user queue %d, is debug status %d \n " ,
2015-05-20 13:43:04 +03:00
q - > queue , qpd - > is_debug ) ;
2018-04-10 17:33:06 -04:00
retval = pm - > pmf - > map_queues ( pm ,
2015-01-06 11:35:50 +02:00
& rl_buffer [ rl_wptr ] ,
q ,
qpd - > is_debug ) ;
2015-05-20 13:43:04 +03:00
2017-08-15 23:00:06 -04:00
if ( retval )
2014-07-17 00:55:28 +03:00
return retval ;
2015-05-20 13:43:04 +03:00
inc_wptr ( & rl_wptr ,
2018-04-10 17:33:06 -04:00
pm - > pmf - > map_queues_size ,
2015-05-20 13:43:04 +03:00
alloc_size_bytes ) ;
2014-07-17 00:55:28 +03:00
}
}
2017-08-15 23:00:05 -04:00
pr_debug ( " Finished map process and queues to runlist \n " ) ;
2014-07-17 00:55:28 +03:00
if ( is_over_subscription )
2018-04-10 17:33:06 -04:00
retval = pm - > pmf - > runlist ( pm , & rl_buffer [ rl_wptr ] ,
2017-08-15 23:00:12 -04:00
* rl_gpu_addr ,
alloc_size_bytes / sizeof ( uint32_t ) ,
true ) ;
2014-07-17 00:55:28 +03:00
for ( i = 0 ; i < alloc_size_bytes / sizeof ( uint32_t ) ; i + + )
pr_debug ( " 0x%2X " , rl_buffer [ i ] ) ;
pr_debug ( " \n " ) ;
2017-08-15 23:00:12 -04:00
return retval ;
2014-07-17 00:55:28 +03:00
}
int pm_init ( struct packet_manager * pm , struct device_queue_manager * dqm )
{
2018-04-10 17:33:06 -04:00
switch ( dqm - > dev - > device_info - > asic_family ) {
case CHIP_KAVERI :
case CHIP_HAWAII :
/* PM4 packet structures on CIK are the same as on VI */
case CHIP_CARRIZO :
case CHIP_TONGA :
case CHIP_FIJI :
case CHIP_POLARIS10 :
case CHIP_POLARIS11 :
pm - > pmf = & kfd_vi_pm_funcs ;
break ;
2018-04-10 17:33:07 -04:00
case CHIP_VEGA10 :
2017-10-31 13:32:53 -04:00
case CHIP_VEGA20 :
2018-04-10 17:33:07 -04:00
case CHIP_RAVEN :
pm - > pmf = & kfd_v9_pm_funcs ;
break ;
2018-04-10 17:33:06 -04:00
default :
WARN ( 1 , " Unexpected ASIC family %u " ,
dqm - > dev - > device_info - > asic_family ) ;
return - EINVAL ;
}
2014-07-17 00:55:28 +03:00
pm - > dqm = dqm ;
mutex_init ( & pm - > lock ) ;
pm - > priv_queue = kernel_queue_init ( dqm - > dev , KFD_QUEUE_TYPE_HIQ ) ;
2017-08-15 23:00:06 -04:00
if ( ! pm - > priv_queue ) {
2014-07-17 00:55:28 +03:00
mutex_destroy ( & pm - > lock ) ;
return - ENOMEM ;
}
pm - > allocated = false ;
return 0 ;
}
void pm_uninit ( struct packet_manager * pm )
{
mutex_destroy ( & pm - > lock ) ;
kernel_queue_uninit ( pm - > priv_queue ) ;
}
int pm_send_set_resources ( struct packet_manager * pm ,
struct scheduling_resources * res )
{
2018-04-10 17:33:06 -04:00
uint32_t * buffer , size ;
2017-08-15 23:00:07 -04:00
int retval = 0 ;
2014-07-17 00:55:28 +03:00
2018-04-10 17:33:06 -04:00
size = pm - > pmf - > set_resources_size ;
2014-07-17 00:55:28 +03:00
mutex_lock ( & pm - > lock ) ;
2015-01-12 15:53:44 +02:00
pm - > priv_queue - > ops . acquire_packet_buffer ( pm - > priv_queue ,
2018-04-10 17:33:06 -04:00
size / sizeof ( uint32_t ) ,
( unsigned int * * ) & buffer ) ;
if ( ! buffer ) {
2017-08-15 23:00:05 -04:00
pr_err ( " Failed to allocate buffer on kernel queue \n " ) ;
2017-08-15 23:00:07 -04:00
retval = - ENOMEM ;
goto out ;
2014-07-17 00:55:28 +03:00
}
2018-04-10 17:33:06 -04:00
retval = pm - > pmf - > set_resources ( pm , buffer , res ) ;
if ( ! retval )
pm - > priv_queue - > ops . submit_packet ( pm - > priv_queue ) ;
else
pm - > priv_queue - > ops . rollback_packet ( pm - > priv_queue ) ;
2014-07-17 00:55:28 +03:00
2017-08-15 23:00:07 -04:00
out :
2014-07-17 00:55:28 +03:00
mutex_unlock ( & pm - > lock ) ;
2017-08-15 23:00:07 -04:00
return retval ;
2014-07-17 00:55:28 +03:00
}
int pm_send_runlist ( struct packet_manager * pm , struct list_head * dqm_queues )
{
uint64_t rl_gpu_ib_addr ;
uint32_t * rl_buffer ;
size_t rl_ib_size , packet_size_dwords ;
int retval ;
retval = pm_create_runlist_ib ( pm , dqm_queues , & rl_gpu_ib_addr ,
& rl_ib_size ) ;
2017-08-15 23:00:06 -04:00
if ( retval )
2014-07-17 00:55:28 +03:00
goto fail_create_runlist_ib ;
2017-08-15 23:00:05 -04:00
pr_debug ( " runlist IB address: 0x%llX \n " , rl_gpu_ib_addr ) ;
2014-07-17 00:55:28 +03:00
2018-04-10 17:33:06 -04:00
packet_size_dwords = pm - > pmf - > runlist_size / sizeof ( uint32_t ) ;
2014-07-17 00:55:28 +03:00
mutex_lock ( & pm - > lock ) ;
2015-01-12 15:53:44 +02:00
retval = pm - > priv_queue - > ops . acquire_packet_buffer ( pm - > priv_queue ,
2014-07-17 00:55:28 +03:00
packet_size_dwords , & rl_buffer ) ;
2017-08-15 23:00:06 -04:00
if ( retval )
2014-07-17 00:55:28 +03:00
goto fail_acquire_packet_buffer ;
2018-04-10 17:33:06 -04:00
retval = pm - > pmf - > runlist ( pm , rl_buffer , rl_gpu_ib_addr ,
2014-07-17 00:55:28 +03:00
rl_ib_size / sizeof ( uint32_t ) , false ) ;
2017-08-15 23:00:06 -04:00
if ( retval )
2014-07-17 00:55:28 +03:00
goto fail_create_runlist ;
2015-01-12 15:53:44 +02:00
pm - > priv_queue - > ops . submit_packet ( pm - > priv_queue ) ;
2014-07-17 00:55:28 +03:00
mutex_unlock ( & pm - > lock ) ;
return retval ;
fail_create_runlist :
2015-01-12 15:53:44 +02:00
pm - > priv_queue - > ops . rollback_packet ( pm - > priv_queue ) ;
2014-07-17 00:55:28 +03:00
fail_acquire_packet_buffer :
mutex_unlock ( & pm - > lock ) ;
fail_create_runlist_ib :
2017-08-15 23:00:04 -04:00
pm_release_ib ( pm ) ;
2014-07-17 00:55:28 +03:00
return retval ;
}
int pm_send_query_status ( struct packet_manager * pm , uint64_t fence_address ,
uint32_t fence_value )
{
2018-04-10 17:33:06 -04:00
uint32_t * buffer , size ;
int retval = 0 ;
2014-07-17 00:55:28 +03:00
2017-08-15 23:00:12 -04:00
if ( WARN_ON ( ! fence_address ) )
return - EFAULT ;
2014-07-17 00:55:28 +03:00
2018-04-10 17:33:06 -04:00
size = pm - > pmf - > query_status_size ;
2014-07-17 00:55:28 +03:00
mutex_lock ( & pm - > lock ) ;
2018-04-10 17:33:06 -04:00
pm - > priv_queue - > ops . acquire_packet_buffer ( pm - > priv_queue ,
size / sizeof ( uint32_t ) , ( unsigned int * * ) & buffer ) ;
if ( ! buffer ) {
pr_err ( " Failed to allocate buffer on kernel queue \n " ) ;
retval = - ENOMEM ;
goto out ;
}
2014-07-17 00:55:28 +03:00
2018-04-10 17:33:06 -04:00
retval = pm - > pmf - > query_status ( pm , buffer , fence_address , fence_value ) ;
if ( ! retval )
pm - > priv_queue - > ops . submit_packet ( pm - > priv_queue ) ;
else
pm - > priv_queue - > ops . rollback_packet ( pm - > priv_queue ) ;
2014-07-17 00:55:28 +03:00
2018-04-10 17:33:06 -04:00
out :
2014-07-17 00:55:28 +03:00
mutex_unlock ( & pm - > lock ) ;
return retval ;
}
int pm_send_unmap_queue ( struct packet_manager * pm , enum kfd_queue_type type ,
2017-09-27 00:09:48 -04:00
enum kfd_unmap_queues_filter filter ,
2014-07-17 00:55:28 +03:00
uint32_t filter_param , bool reset ,
unsigned int sdma_engine )
{
2018-04-10 17:33:06 -04:00
uint32_t * buffer , size ;
int retval = 0 ;
2014-07-17 00:55:28 +03:00
2018-04-10 17:33:06 -04:00
size = pm - > pmf - > unmap_queues_size ;
2014-07-17 00:55:28 +03:00
mutex_lock ( & pm - > lock ) ;
2018-04-10 17:33:06 -04:00
pm - > priv_queue - > ops . acquire_packet_buffer ( pm - > priv_queue ,
size / sizeof ( uint32_t ) , ( unsigned int * * ) & buffer ) ;
if ( ! buffer ) {
pr_err ( " Failed to allocate buffer on kernel queue \n " ) ;
retval = - ENOMEM ;
goto out ;
2014-07-17 00:55:28 +03:00
}
2018-04-10 17:33:06 -04:00
retval = pm - > pmf - > unmap_queues ( pm , buffer , type , filter , filter_param ,
reset , sdma_engine ) ;
if ( ! retval )
pm - > priv_queue - > ops . submit_packet ( pm - > priv_queue ) ;
2014-07-17 00:55:28 +03:00
else
2018-04-10 17:33:06 -04:00
pm - > priv_queue - > ops . rollback_packet ( pm - > priv_queue ) ;
2014-07-17 00:55:28 +03:00
2018-04-10 17:33:06 -04:00
out :
2014-07-17 00:55:28 +03:00
mutex_unlock ( & pm - > lock ) ;
return retval ;
}
void pm_release_ib ( struct packet_manager * pm )
{
mutex_lock ( & pm - > lock ) ;
if ( pm - > allocated ) {
2014-10-26 22:00:31 +02:00
kfd_gtt_sa_free ( pm - > dqm - > dev , pm - > ib_buffer_obj ) ;
2014-07-17 00:55:28 +03:00
pm - > allocated = false ;
}
mutex_unlock ( & pm - > lock ) ;
}
2017-11-27 18:29:49 -05:00
# if defined(CONFIG_DEBUG_FS)
int pm_debugfs_runlist ( struct seq_file * m , void * data )
{
struct packet_manager * pm = data ;
mutex_lock ( & pm - > lock ) ;
if ( ! pm - > allocated ) {
seq_puts ( m , " No active runlist \n " ) ;
goto out ;
}
seq_hex_dump ( m , " " , DUMP_PREFIX_OFFSET , 32 , 4 ,
pm - > ib_buffer_obj - > cpu_ptr , pm - > ib_size_bytes , false ) ;
out :
mutex_unlock ( & pm - > lock ) ;
return 0 ;
}
2018-07-11 22:33:04 -04:00
int pm_debugfs_hang_hws ( struct packet_manager * pm )
{
uint32_t * buffer , size ;
int r = 0 ;
size = pm - > pmf - > query_status_size ;
mutex_lock ( & pm - > lock ) ;
pm - > priv_queue - > ops . acquire_packet_buffer ( pm - > priv_queue ,
size / sizeof ( uint32_t ) , ( unsigned int * * ) & buffer ) ;
if ( ! buffer ) {
pr_err ( " Failed to allocate buffer on kernel queue \n " ) ;
r = - ENOMEM ;
goto out ;
}
memset ( buffer , 0x55 , size ) ;
pm - > priv_queue - > ops . submit_packet ( pm - > priv_queue ) ;
pr_info ( " Submitting %x %x %x %x %x %x %x to HIQ to hang the HWS. " ,
buffer [ 0 ] , buffer [ 1 ] , buffer [ 2 ] , buffer [ 3 ] ,
buffer [ 4 ] , buffer [ 5 ] , buffer [ 6 ] ) ;
out :
mutex_unlock ( & pm - > lock ) ;
return r ;
}
2017-11-27 18:29:49 -05:00
# endif