2014-07-16 21:08:55 +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/device.h>
# include <linux/export.h>
# include <linux/err.h>
# include <linux/fs.h>
# include <linux/sched.h>
# include <linux/slab.h>
# include <linux/uaccess.h>
# include <linux/compat.h>
# include <uapi/linux/kfd_ioctl.h>
# include <linux/time.h>
# include <linux/mm.h>
# include <uapi/asm-generic/mman-common.h>
# include <asm/processor.h>
# include "kfd_priv.h"
2014-07-17 01:46:17 +03:00
# include "kfd_device_queue_manager.h"
2014-07-16 21:08:55 +03:00
static long kfd_ioctl ( struct file * , unsigned int , unsigned long ) ;
static int kfd_open ( struct inode * , struct file * ) ;
2014-07-16 23:25:31 +03:00
static int kfd_mmap ( struct file * , struct vm_area_struct * ) ;
2014-07-16 21:08:55 +03:00
static const char kfd_dev_name [ ] = " kfd " ;
static const struct file_operations kfd_fops = {
. owner = THIS_MODULE ,
. unlocked_ioctl = kfd_ioctl ,
. compat_ioctl = kfd_ioctl ,
. open = kfd_open ,
2014-07-16 23:25:31 +03:00
. mmap = kfd_mmap ,
2014-07-16 21:08:55 +03:00
} ;
static int kfd_char_dev_major = - 1 ;
static struct class * kfd_class ;
struct device * kfd_device ;
int kfd_chardev_init ( void )
{
int err = 0 ;
kfd_char_dev_major = register_chrdev ( 0 , kfd_dev_name , & kfd_fops ) ;
err = kfd_char_dev_major ;
if ( err < 0 )
goto err_register_chrdev ;
kfd_class = class_create ( THIS_MODULE , kfd_dev_name ) ;
err = PTR_ERR ( kfd_class ) ;
if ( IS_ERR ( kfd_class ) )
goto err_class_create ;
kfd_device = device_create ( kfd_class , NULL ,
MKDEV ( kfd_char_dev_major , 0 ) ,
NULL , kfd_dev_name ) ;
err = PTR_ERR ( kfd_device ) ;
if ( IS_ERR ( kfd_device ) )
goto err_device_create ;
return 0 ;
err_device_create :
class_destroy ( kfd_class ) ;
err_class_create :
unregister_chrdev ( kfd_char_dev_major , kfd_dev_name ) ;
err_register_chrdev :
return err ;
}
void kfd_chardev_exit ( void )
{
device_destroy ( kfd_class , MKDEV ( kfd_char_dev_major , 0 ) ) ;
class_destroy ( kfd_class ) ;
unregister_chrdev ( kfd_char_dev_major , kfd_dev_name ) ;
}
struct device * kfd_chardev ( void )
{
return kfd_device ;
}
static int kfd_open ( struct inode * inode , struct file * filep )
{
2014-07-16 23:25:31 +03:00
struct kfd_process * process ;
2014-12-05 10:40:34 +02:00
bool is_32bit_user_mode ;
2014-07-16 23:25:31 +03:00
2014-07-16 21:08:55 +03:00
if ( iminor ( inode ) ! = 0 )
return - ENODEV ;
2014-12-05 10:40:34 +02:00
is_32bit_user_mode = is_compat_task ( ) ;
if ( is_32bit_user_mode = = true ) {
dev_warn ( kfd_device ,
" Process %d (32-bit) failed to open /dev/kfd \n "
" 32-bit processes are not supported by amdkfd \n " ,
current - > pid ) ;
return - EPERM ;
}
2014-07-16 23:25:31 +03:00
process = kfd_create_process ( current ) ;
if ( IS_ERR ( process ) )
return PTR_ERR ( process ) ;
dev_dbg ( kfd_device , " process %d opened, compat mode (32 bit) - %d \n " ,
process - > pasid , process - > is_32bit_user_mode ) ;
2014-07-16 21:08:55 +03:00
return 0 ;
}
2014-12-29 13:52:22 +02:00
static int kfd_ioctl_get_version ( struct file * filep , struct kfd_process * p ,
void * data )
2014-07-16 21:08:55 +03:00
{
2014-12-29 13:52:22 +02:00
struct kfd_ioctl_get_version_args * args = data ;
2014-11-02 12:18:29 +02:00
int err = 0 ;
2014-12-29 13:52:22 +02:00
args - > major_version = KFD_IOCTL_MAJOR_VERSION ;
args - > minor_version = KFD_IOCTL_MINOR_VERSION ;
2014-11-02 12:18:29 +02:00
return err ;
2014-07-16 21:08:55 +03:00
}
2014-10-19 23:46:40 +03:00
static int set_queue_properties_from_user ( struct queue_properties * q_properties ,
struct kfd_ioctl_create_queue_args * args )
{
if ( args - > queue_percentage > KFD_MAX_QUEUE_PERCENTAGE ) {
pr_err ( " kfd: queue percentage must be between 0 to KFD_MAX_QUEUE_PERCENTAGE \n " ) ;
return - EINVAL ;
}
if ( args - > queue_priority > KFD_MAX_QUEUE_PRIORITY ) {
pr_err ( " kfd: queue priority must be between 0 to KFD_MAX_QUEUE_PRIORITY \n " ) ;
return - EINVAL ;
}
if ( ( args - > ring_base_address ) & &
2014-11-20 15:37:13 +02:00
( ! access_ok ( VERIFY_WRITE ,
( const void __user * ) args - > ring_base_address ,
sizeof ( uint64_t ) ) ) ) {
2014-10-19 23:46:40 +03:00
pr_err ( " kfd: can't access ring base address \n " ) ;
return - EFAULT ;
}
if ( ! is_power_of_2 ( args - > ring_size ) & & ( args - > ring_size ! = 0 ) ) {
pr_err ( " kfd: ring size must be a power of 2 or 0 \n " ) ;
return - EINVAL ;
}
2014-11-20 15:37:13 +02:00
if ( ! access_ok ( VERIFY_WRITE ,
( const void __user * ) args - > read_pointer_address ,
sizeof ( uint32_t ) ) ) {
2014-10-19 23:46:40 +03:00
pr_err ( " kfd: can't access read pointer \n " ) ;
return - EFAULT ;
}
2014-11-20 15:37:13 +02:00
if ( ! access_ok ( VERIFY_WRITE ,
( const void __user * ) args - > write_pointer_address ,
sizeof ( uint32_t ) ) ) {
2014-10-19 23:46:40 +03:00
pr_err ( " kfd: can't access write pointer \n " ) ;
return - EFAULT ;
}
2015-01-22 13:42:28 +02:00
if ( args - > eop_buffer_address & &
! access_ok ( VERIFY_WRITE ,
( const void __user * ) args - > eop_buffer_address ,
sizeof ( uint32_t ) ) ) {
2015-01-04 10:37:18 +02:00
pr_debug ( " kfd: can't access eop buffer " ) ;
return - EFAULT ;
}
2015-01-22 13:42:28 +02:00
if ( args - > ctx_save_restore_address & &
! access_ok ( VERIFY_WRITE ,
( const void __user * ) args - > ctx_save_restore_address ,
sizeof ( uint32_t ) ) ) {
2015-01-04 10:37:18 +02:00
pr_debug ( " kfd: can't access ctx save restore buffer " ) ;
return - EFAULT ;
}
2014-10-19 23:46:40 +03:00
q_properties - > is_interop = false ;
q_properties - > queue_percent = args - > queue_percentage ;
q_properties - > priority = args - > queue_priority ;
q_properties - > queue_address = args - > ring_base_address ;
q_properties - > queue_size = args - > ring_size ;
q_properties - > read_ptr = ( uint32_t * ) args - > read_pointer_address ;
q_properties - > write_ptr = ( uint32_t * ) args - > write_pointer_address ;
2015-01-04 10:37:18 +02:00
q_properties - > eop_ring_buffer_address = args - > eop_buffer_address ;
q_properties - > eop_ring_buffer_size = args - > eop_buffer_size ;
q_properties - > ctx_save_restore_area_address =
args - > ctx_save_restore_address ;
q_properties - > ctx_save_restore_area_size = args - > ctx_save_restore_size ;
2014-10-19 23:46:40 +03:00
if ( args - > queue_type = = KFD_IOC_QUEUE_TYPE_COMPUTE | |
args - > queue_type = = KFD_IOC_QUEUE_TYPE_COMPUTE_AQL )
q_properties - > type = KFD_QUEUE_TYPE_COMPUTE ;
2015-01-03 22:12:33 +02:00
else if ( args - > queue_type = = KFD_IOC_QUEUE_TYPE_SDMA )
q_properties - > type = KFD_QUEUE_TYPE_SDMA ;
2014-10-19 23:46:40 +03:00
else
return - ENOTSUPP ;
if ( args - > queue_type = = KFD_IOC_QUEUE_TYPE_COMPUTE_AQL )
q_properties - > format = KFD_QUEUE_FORMAT_AQL ;
else
q_properties - > format = KFD_QUEUE_FORMAT_PM4 ;
pr_debug ( " Queue Percentage (%d, %d) \n " ,
q_properties - > queue_percent , args - > queue_percentage ) ;
pr_debug ( " Queue Priority (%d, %d) \n " ,
q_properties - > priority , args - > queue_priority ) ;
pr_debug ( " Queue Address (0x%llX, 0x%llX) \n " ,
q_properties - > queue_address , args - > ring_base_address ) ;
pr_debug ( " Queue Size (0x%llX, %u) \n " ,
q_properties - > queue_size , args - > ring_size ) ;
pr_debug ( " Queue r/w Pointers (0x%llX, 0x%llX) \n " ,
( uint64_t ) q_properties - > read_ptr ,
( uint64_t ) q_properties - > write_ptr ) ;
pr_debug ( " Queue Format (%d) \n " , q_properties - > format ) ;
2015-01-04 10:37:18 +02:00
pr_debug ( " Queue EOP (0x%llX) \n " , q_properties - > eop_ring_buffer_address ) ;
pr_debug ( " Queue CTX save arex (0x%llX) \n " ,
q_properties - > ctx_save_restore_area_address ) ;
2014-10-19 23:46:40 +03:00
return 0 ;
}
2014-12-29 13:52:22 +02:00
static int kfd_ioctl_create_queue ( struct file * filep , struct kfd_process * p ,
void * data )
2014-07-16 21:08:55 +03:00
{
2014-12-29 13:52:22 +02:00
struct kfd_ioctl_create_queue_args * args = data ;
2014-10-19 23:46:40 +03:00
struct kfd_dev * dev ;
int err = 0 ;
unsigned int queue_id ;
struct kfd_process_device * pdd ;
struct queue_properties q_properties ;
memset ( & q_properties , 0 , sizeof ( struct queue_properties ) ) ;
pr_debug ( " kfd: creating queue ioctl \n " ) ;
2014-12-29 13:52:22 +02:00
err = set_queue_properties_from_user ( & q_properties , args ) ;
2014-10-19 23:46:40 +03:00
if ( err )
return err ;
2015-01-22 10:44:41 +10:00
pr_debug ( " kfd: looking for gpu id 0x%x \n " , args - > gpu_id ) ;
2014-12-29 13:52:22 +02:00
dev = kfd_device_by_id ( args - > gpu_id ) ;
2015-01-04 10:37:18 +02:00
if ( dev = = NULL ) {
2015-01-22 10:44:41 +10:00
pr_debug ( " kfd: gpu id 0x%x was not found \n " , args - > gpu_id ) ;
2014-10-19 23:46:40 +03:00
return - EINVAL ;
2015-01-04 10:37:18 +02:00
}
2014-10-19 23:46:40 +03:00
mutex_lock ( & p - > mutex ) ;
pdd = kfd_bind_process_to_device ( dev , p ) ;
2014-11-25 13:21:30 +03:00
if ( IS_ERR ( pdd ) ) {
2014-12-29 13:52:22 +02:00
err = - ESRCH ;
2014-10-19 23:46:40 +03:00
goto err_bind_process ;
}
pr_debug ( " kfd: creating queue for PASID %d on GPU 0x%x \n " ,
p - > pasid ,
dev - > id ) ;
2015-01-03 22:12:34 +02:00
err = pqm_create_queue ( & p - > pqm , dev , filep , & q_properties ,
0 , q_properties . type , & queue_id ) ;
2014-10-19 23:46:40 +03:00
if ( err ! = 0 )
goto err_create_queue ;
2014-12-29 13:52:22 +02:00
args - > queue_id = queue_id ;
2014-10-19 23:46:40 +03:00
/* Return gpu_id as doorbell offset for mmap usage */
2014-12-29 13:52:22 +02:00
args - > doorbell_offset = args - > gpu_id < < PAGE_SHIFT ;
2014-10-19 23:46:40 +03:00
mutex_unlock ( & p - > mutex ) ;
2014-12-29 13:52:22 +02:00
pr_debug ( " kfd: queue id %d was created successfully \n " , args - > queue_id ) ;
2014-10-19 23:46:40 +03:00
pr_debug ( " ring buffer address == 0x%016llX \n " ,
2014-12-29 13:52:22 +02:00
args - > ring_base_address ) ;
2014-10-19 23:46:40 +03:00
pr_debug ( " read ptr address == 0x%016llX \n " ,
2014-12-29 13:52:22 +02:00
args - > read_pointer_address ) ;
2014-10-19 23:46:40 +03:00
pr_debug ( " write ptr address == 0x%016llX \n " ,
2014-12-29 13:52:22 +02:00
args - > write_pointer_address ) ;
2014-10-19 23:46:40 +03:00
return 0 ;
err_create_queue :
err_bind_process :
mutex_unlock ( & p - > mutex ) ;
return err ;
2014-07-16 21:08:55 +03:00
}
static int kfd_ioctl_destroy_queue ( struct file * filp , struct kfd_process * p ,
2014-12-29 13:52:22 +02:00
void * data )
2014-07-16 21:08:55 +03:00
{
2014-10-19 23:46:40 +03:00
int retval ;
2014-12-29 13:52:22 +02:00
struct kfd_ioctl_destroy_queue_args * args = data ;
2014-10-19 23:46:40 +03:00
pr_debug ( " kfd: destroying queue id %d for PASID %d \n " ,
2014-12-29 13:52:22 +02:00
args - > queue_id ,
2014-10-19 23:46:40 +03:00
p - > pasid ) ;
mutex_lock ( & p - > mutex ) ;
2014-12-29 13:52:22 +02:00
retval = pqm_destroy_queue ( & p - > pqm , args - > queue_id ) ;
2014-10-19 23:46:40 +03:00
mutex_unlock ( & p - > mutex ) ;
return retval ;
2014-07-16 21:08:55 +03:00
}
static int kfd_ioctl_update_queue ( struct file * filp , struct kfd_process * p ,
2014-12-29 13:52:22 +02:00
void * data )
2014-07-16 21:08:55 +03:00
{
2014-10-19 23:46:40 +03:00
int retval ;
2014-12-29 13:52:22 +02:00
struct kfd_ioctl_update_queue_args * args = data ;
2014-10-19 23:46:40 +03:00
struct queue_properties properties ;
2014-12-29 13:52:22 +02:00
if ( args - > queue_percentage > KFD_MAX_QUEUE_PERCENTAGE ) {
2014-10-19 23:46:40 +03:00
pr_err ( " kfd: queue percentage must be between 0 to KFD_MAX_QUEUE_PERCENTAGE \n " ) ;
return - EINVAL ;
}
2014-12-29 13:52:22 +02:00
if ( args - > queue_priority > KFD_MAX_QUEUE_PRIORITY ) {
2014-10-19 23:46:40 +03:00
pr_err ( " kfd: queue priority must be between 0 to KFD_MAX_QUEUE_PRIORITY \n " ) ;
return - EINVAL ;
}
2014-12-29 13:52:22 +02:00
if ( ( args - > ring_base_address ) & &
2014-11-20 15:37:13 +02:00
( ! access_ok ( VERIFY_WRITE ,
2014-12-29 13:52:22 +02:00
( const void __user * ) args - > ring_base_address ,
2014-11-20 15:37:13 +02:00
sizeof ( uint64_t ) ) ) ) {
2014-10-19 23:46:40 +03:00
pr_err ( " kfd: can't access ring base address \n " ) ;
return - EFAULT ;
}
2014-12-29 13:52:22 +02:00
if ( ! is_power_of_2 ( args - > ring_size ) & & ( args - > ring_size ! = 0 ) ) {
2014-10-19 23:46:40 +03:00
pr_err ( " kfd: ring size must be a power of 2 or 0 \n " ) ;
return - EINVAL ;
}
2014-12-29 13:52:22 +02:00
properties . queue_address = args - > ring_base_address ;
properties . queue_size = args - > ring_size ;
properties . queue_percent = args - > queue_percentage ;
properties . priority = args - > queue_priority ;
2014-10-19 23:46:40 +03:00
pr_debug ( " kfd: updating queue id %d for PASID %d \n " ,
2014-12-29 13:52:22 +02:00
args - > queue_id , p - > pasid ) ;
2014-10-19 23:46:40 +03:00
mutex_lock ( & p - > mutex ) ;
2014-12-29 13:52:22 +02:00
retval = pqm_update_queue ( & p - > pqm , args - > queue_id , & properties ) ;
2014-10-19 23:46:40 +03:00
mutex_unlock ( & p - > mutex ) ;
return retval ;
2014-07-16 21:08:55 +03:00
}
2014-12-29 13:52:22 +02:00
static int kfd_ioctl_set_memory_policy ( struct file * filep ,
struct kfd_process * p , void * data )
2014-07-16 21:08:55 +03:00
{
2014-12-29 13:52:22 +02:00
struct kfd_ioctl_set_memory_policy_args * args = data ;
2014-07-17 01:46:17 +03:00
struct kfd_dev * dev ;
int err = 0 ;
struct kfd_process_device * pdd ;
enum cache_policy default_policy , alternate_policy ;
2014-12-29 13:52:22 +02:00
if ( args - > default_policy ! = KFD_IOC_CACHE_POLICY_COHERENT
& & args - > default_policy ! = KFD_IOC_CACHE_POLICY_NONCOHERENT ) {
2014-07-17 01:46:17 +03:00
return - EINVAL ;
}
2014-12-29 13:52:22 +02:00
if ( args - > alternate_policy ! = KFD_IOC_CACHE_POLICY_COHERENT
& & args - > alternate_policy ! = KFD_IOC_CACHE_POLICY_NONCOHERENT ) {
2014-07-17 01:46:17 +03:00
return - EINVAL ;
}
2014-12-29 13:52:22 +02:00
dev = kfd_device_by_id ( args - > gpu_id ) ;
2014-07-17 01:46:17 +03:00
if ( dev = = NULL )
return - EINVAL ;
mutex_lock ( & p - > mutex ) ;
pdd = kfd_bind_process_to_device ( dev , p ) ;
2014-11-25 13:21:30 +03:00
if ( IS_ERR ( pdd ) ) {
2014-12-29 13:52:22 +02:00
err = - ESRCH ;
2014-07-17 01:46:17 +03:00
goto out ;
}
2014-12-29 13:52:22 +02:00
default_policy = ( args - > default_policy = = KFD_IOC_CACHE_POLICY_COHERENT )
2014-07-17 01:46:17 +03:00
? cache_policy_coherent : cache_policy_noncoherent ;
alternate_policy =
2014-12-29 13:52:22 +02:00
( args - > alternate_policy = = KFD_IOC_CACHE_POLICY_COHERENT )
2014-07-17 01:46:17 +03:00
? cache_policy_coherent : cache_policy_noncoherent ;
2015-01-12 14:26:10 +02:00
if ( ! dev - > dqm - > ops . set_cache_memory_policy ( dev - > dqm ,
2014-07-17 01:46:17 +03:00
& pdd - > qpd ,
default_policy ,
alternate_policy ,
2014-12-29 13:52:22 +02:00
( void __user * ) args - > alternate_aperture_base ,
args - > alternate_aperture_size ) )
2014-07-17 01:46:17 +03:00
err = - EINVAL ;
out :
mutex_unlock ( & p - > mutex ) ;
return err ;
2014-07-16 21:08:55 +03:00
}
2014-12-29 13:52:22 +02:00
static int kfd_ioctl_get_clock_counters ( struct file * filep ,
struct kfd_process * p , void * data )
2014-07-16 21:08:55 +03:00
{
2014-12-29 13:52:22 +02:00
struct kfd_ioctl_get_clock_counters_args * args = data ;
2014-07-17 01:47:58 +03:00
struct kfd_dev * dev ;
struct timespec time ;
2014-12-29 13:52:22 +02:00
dev = kfd_device_by_id ( args - > gpu_id ) ;
2014-07-17 01:47:58 +03:00
if ( dev = = NULL )
return - EINVAL ;
/* Reading GPU clock counter from KGD */
2014-12-29 13:52:22 +02:00
args - > gpu_clock_counter = kfd2kgd - > get_gpu_clock_counter ( dev - > kgd ) ;
2014-07-17 01:47:58 +03:00
/* No access to rdtsc. Using raw monotonic time */
getrawmonotonic ( & time ) ;
2014-12-29 13:52:22 +02:00
args - > cpu_clock_counter = ( uint64_t ) timespec_to_ns ( & time ) ;
2014-07-17 01:47:58 +03:00
get_monotonic_boottime ( & time ) ;
2014-12-29 13:52:22 +02:00
args - > system_clock_counter = ( uint64_t ) timespec_to_ns ( & time ) ;
2014-07-17 01:47:58 +03:00
/* Since the counter is in nano-seconds we use 1GHz frequency */
2014-12-29 13:52:22 +02:00
args - > system_clock_freq = 1000000000 ;
2014-07-17 01:47:58 +03:00
return 0 ;
2014-07-16 21:08:55 +03:00
}
static int kfd_ioctl_get_process_apertures ( struct file * filp ,
2014-12-29 13:52:22 +02:00
struct kfd_process * p , void * data )
2014-07-16 21:08:55 +03:00
{
2014-12-29 13:52:22 +02:00
struct kfd_ioctl_get_process_apertures_args * args = data ;
2014-07-17 01:49:36 +03:00
struct kfd_process_device_apertures * pAperture ;
struct kfd_process_device * pdd ;
dev_dbg ( kfd_device , " get apertures for PASID %d " , p - > pasid ) ;
2014-12-29 13:52:22 +02:00
args - > num_of_nodes = 0 ;
2014-07-17 01:49:36 +03:00
mutex_lock ( & p - > mutex ) ;
/*if the process-device list isn't empty*/
if ( kfd_has_process_device_data ( p ) ) {
/* Run over all pdd of the process */
pdd = kfd_get_first_process_device_data ( p ) ;
do {
2014-12-29 13:52:22 +02:00
pAperture =
& args - > process_apertures [ args - > num_of_nodes ] ;
2014-07-17 01:49:36 +03:00
pAperture - > gpu_id = pdd - > dev - > id ;
pAperture - > lds_base = pdd - > lds_base ;
pAperture - > lds_limit = pdd - > lds_limit ;
pAperture - > gpuvm_base = pdd - > gpuvm_base ;
pAperture - > gpuvm_limit = pdd - > gpuvm_limit ;
pAperture - > scratch_base = pdd - > scratch_base ;
pAperture - > scratch_limit = pdd - > scratch_limit ;
dev_dbg ( kfd_device ,
2014-12-29 13:52:22 +02:00
" node id %u \n " , args - > num_of_nodes ) ;
2014-07-17 01:49:36 +03:00
dev_dbg ( kfd_device ,
" gpu id %u \n " , pdd - > dev - > id ) ;
dev_dbg ( kfd_device ,
" lds_base %llX \n " , pdd - > lds_base ) ;
dev_dbg ( kfd_device ,
" lds_limit %llX \n " , pdd - > lds_limit ) ;
dev_dbg ( kfd_device ,
" gpuvm_base %llX \n " , pdd - > gpuvm_base ) ;
dev_dbg ( kfd_device ,
" gpuvm_limit %llX \n " , pdd - > gpuvm_limit ) ;
dev_dbg ( kfd_device ,
" scratch_base %llX \n " , pdd - > scratch_base ) ;
dev_dbg ( kfd_device ,
" scratch_limit %llX \n " , pdd - > scratch_limit ) ;
2014-12-29 13:52:22 +02:00
args - > num_of_nodes + + ;
2014-07-17 01:49:36 +03:00
} while ( ( pdd = kfd_get_next_process_device_data ( p , pdd ) ) ! = NULL & &
2014-12-29 13:52:22 +02:00
( args - > num_of_nodes < NUM_OF_SUPPORTED_GPUS ) ) ;
2014-07-17 01:49:36 +03:00
}
mutex_unlock ( & p - > mutex ) ;
return 0 ;
2014-07-16 21:08:55 +03:00
}
2014-12-29 14:20:05 +02:00
# define AMDKFD_IOCTL_DEF(ioctl, _func, _flags) \
[ _IOC_NR ( ioctl ) ] = { . cmd = ioctl , . func = _func , . flags = _flags , . cmd_drv = 0 , . name = # ioctl }
/** Ioctl table */
static const struct amdkfd_ioctl_desc amdkfd_ioctls [ ] = {
AMDKFD_IOCTL_DEF ( AMDKFD_IOC_GET_VERSION ,
kfd_ioctl_get_version , 0 ) ,
AMDKFD_IOCTL_DEF ( AMDKFD_IOC_CREATE_QUEUE ,
kfd_ioctl_create_queue , 0 ) ,
AMDKFD_IOCTL_DEF ( AMDKFD_IOC_DESTROY_QUEUE ,
kfd_ioctl_destroy_queue , 0 ) ,
AMDKFD_IOCTL_DEF ( AMDKFD_IOC_SET_MEMORY_POLICY ,
kfd_ioctl_set_memory_policy , 0 ) ,
AMDKFD_IOCTL_DEF ( AMDKFD_IOC_GET_CLOCK_COUNTERS ,
kfd_ioctl_get_clock_counters , 0 ) ,
AMDKFD_IOCTL_DEF ( AMDKFD_IOC_GET_PROCESS_APERTURES ,
kfd_ioctl_get_process_apertures , 0 ) ,
AMDKFD_IOCTL_DEF ( AMDKFD_IOC_UPDATE_QUEUE ,
kfd_ioctl_update_queue , 0 ) ,
} ;
# define AMDKFD_CORE_IOCTL_COUNT ARRAY_SIZE(amdkfd_ioctls)
2014-07-16 21:08:55 +03:00
static long kfd_ioctl ( struct file * filep , unsigned int cmd , unsigned long arg )
{
struct kfd_process * process ;
2014-12-29 14:20:05 +02:00
amdkfd_ioctl_t * func ;
const struct amdkfd_ioctl_desc * ioctl = NULL ;
unsigned int nr = _IOC_NR ( cmd ) ;
2014-12-29 13:52:22 +02:00
char stack_kdata [ 128 ] ;
char * kdata = NULL ;
unsigned int usize , asize ;
int retcode = - EINVAL ;
2014-07-16 21:08:55 +03:00
2014-12-29 14:20:05 +02:00
if ( nr > = AMDKFD_CORE_IOCTL_COUNT )
goto err_i1 ;
if ( ( nr > = AMDKFD_COMMAND_START ) & & ( nr < AMDKFD_COMMAND_END ) ) {
u32 amdkfd_size ;
ioctl = & amdkfd_ioctls [ nr ] ;
amdkfd_size = _IOC_SIZE ( ioctl - > cmd ) ;
usize = asize = _IOC_SIZE ( cmd ) ;
if ( amdkfd_size > asize )
asize = amdkfd_size ;
cmd = ioctl - > cmd ;
} else
goto err_i1 ;
dev_dbg ( kfd_device , " ioctl cmd 0x%x (#%d), arg 0x%lx \n " , cmd , nr , arg ) ;
2014-07-16 21:08:55 +03:00
2014-07-16 23:25:31 +03:00
process = kfd_get_process ( current ) ;
2014-12-29 14:20:05 +02:00
if ( IS_ERR ( process ) ) {
dev_dbg ( kfd_device , " no process \n " ) ;
goto err_i1 ;
}
2014-07-16 21:08:55 +03:00
2014-12-29 14:20:05 +02:00
/* Do not trust userspace, use our own definition */
func = ioctl - > func ;
if ( unlikely ( ! func ) ) {
dev_dbg ( kfd_device , " no function \n " ) ;
retcode = - EINVAL ;
goto err_i1 ;
2014-07-16 21:08:55 +03:00
}
2014-12-29 13:52:22 +02:00
if ( cmd & ( IOC_IN | IOC_OUT ) ) {
if ( asize < = sizeof ( stack_kdata ) ) {
kdata = stack_kdata ;
} else {
kdata = kmalloc ( asize , GFP_KERNEL ) ;
if ( ! kdata ) {
retcode = - ENOMEM ;
goto err_i1 ;
}
}
if ( asize > usize )
memset ( kdata + usize , 0 , asize - usize ) ;
}
2014-07-16 21:08:55 +03:00
2014-12-29 13:52:22 +02:00
if ( cmd & IOC_IN ) {
if ( copy_from_user ( kdata , ( void __user * ) arg , usize ) ! = 0 ) {
retcode = - EFAULT ;
goto err_i1 ;
}
} else if ( cmd & IOC_OUT ) {
memset ( kdata , 0 , usize ) ;
}
2014-12-29 14:20:05 +02:00
retcode = func ( filep , process , kdata ) ;
2014-07-16 21:08:55 +03:00
2014-12-29 13:52:22 +02:00
if ( cmd & IOC_OUT )
if ( copy_to_user ( ( void __user * ) arg , kdata , usize ) ! = 0 )
retcode = - EFAULT ;
2014-07-16 21:08:55 +03:00
2014-12-29 13:52:22 +02:00
err_i1 :
2014-12-29 14:20:05 +02:00
if ( ! ioctl )
dev_dbg ( kfd_device , " invalid ioctl: pid=%d, cmd=0x%02x, nr=0x%02x \n " ,
task_pid_nr ( current ) , cmd , nr ) ;
2014-12-29 13:52:22 +02:00
if ( kdata ! = stack_kdata )
kfree ( kdata ) ;
if ( retcode )
dev_dbg ( kfd_device , " ret = %d \n " , retcode ) ;
return retcode ;
2014-07-16 21:08:55 +03:00
}
2014-07-16 23:25:31 +03:00
static int kfd_mmap ( struct file * filp , struct vm_area_struct * vma )
{
struct kfd_process * process ;
process = kfd_get_process ( current ) ;
if ( IS_ERR ( process ) )
return PTR_ERR ( process ) ;
return kfd_doorbell_mmap ( process , vma ) ;
}