[PATCH 1/3] drm/amdkfd: Do copy_to/from_user in general kfd_ioctl()
Christian König
deathsimple at vodafone.de
Mon Dec 29 05:45:29 PST 2014
Am 29.12.2014 um 14:22 schrieb Oded Gabbay:
>
>
> On 12/29/2014 03:05 PM, Christian König wrote:
>> Am 29.12.2014 um 13:42 schrieb Oded Gabbay:
>>> This patch moves the copy_to_user() and copy_from_user() calls from the
>>> different ioctl functions in amdkfd to the general kfd_ioctl()
>>> function, as
>>> this is a common code for all ioctls.
>>>
>>> This was done according to example taken from drm_ioctl.c
>>>
>>> Signed-off-by: Oded Gabbay <oded.gabbay at amd.com>
>>
>> In general sounds like a good idea to me and the patch is "Reviewed-by:
>> Christian König <christian.koenig at amd.com>" for now.
>>
>> What really questions me is why we need all this code duplication and
>> can't
>> reuse the DRM infrastructure for this. But that's more a problem in
>> the long term.
>>
> Do you mean registering as DRM IOCTL ?
> Or do you mean something else ?
>
> If it is the former, than I think the main problem is that we use
> different devices (/dev/kfd vs. /dev/dri/)
Ah, yes of course. I simply keep forgetting that we have two device
nodes for the same physical hardware.
Christian.
>
> If it is the latter, could you give me more specifics ?
>
> Oded
>
>> Regards,
>> Christian.
>>
>>> ---
>>> drivers/gpu/drm/amd/amdkfd/kfd_chardev.c | 234
>>> +++++++++++++++----------------
>>> 1 file changed, 117 insertions(+), 117 deletions(-)
>>>
>>> diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
>>> b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
>>> index 7d4974b..5460ad2 100644
>>> --- a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
>>> +++ b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
>>> @@ -127,17 +127,14 @@ static int kfd_open(struct inode *inode,
>>> struct file
>>> *filep)
>>> return 0;
>>> }
>>> -static long kfd_ioctl_get_version(struct file *filep, struct
>>> kfd_process *p,
>>> - void __user *arg)
>>> +static int kfd_ioctl_get_version(struct file *filep, struct
>>> kfd_process *p,
>>> + void *data)
>>> {
>>> - struct kfd_ioctl_get_version_args args;
>>> + struct kfd_ioctl_get_version_args *args = data;
>>> int err = 0;
>>> - args.major_version = KFD_IOCTL_MAJOR_VERSION;
>>> - args.minor_version = KFD_IOCTL_MINOR_VERSION;
>>> -
>>> - if (copy_to_user(arg, &args, sizeof(args)))
>>> - err = -EFAULT;
>>> + args->major_version = KFD_IOCTL_MAJOR_VERSION;
>>> + args->minor_version = KFD_IOCTL_MINOR_VERSION;
>>> return err;
>>> }
>>> @@ -221,10 +218,10 @@ static int set_queue_properties_from_user(struct
>>> queue_properties *q_properties,
>>> return 0;
>>> }
>>> -static long kfd_ioctl_create_queue(struct file *filep, struct
>>> kfd_process *p,
>>> - void __user *arg)
>>> +static int kfd_ioctl_create_queue(struct file *filep, struct
>>> kfd_process *p,
>>> + void *data)
>>> {
>>> - struct kfd_ioctl_create_queue_args args;
>>> + struct kfd_ioctl_create_queue_args *args = data;
>>> struct kfd_dev *dev;
>>> int err = 0;
>>> unsigned int queue_id;
>>> @@ -233,16 +230,13 @@ static long kfd_ioctl_create_queue(struct file
>>> *filep,
>>> struct kfd_process *p,
>>> memset(&q_properties, 0, sizeof(struct queue_properties));
>>> - if (copy_from_user(&args, arg, sizeof(args)))
>>> - return -EFAULT;
>>> -
>>> pr_debug("kfd: creating queue ioctl\n");
>>> - err = set_queue_properties_from_user(&q_properties, &args);
>>> + err = set_queue_properties_from_user(&q_properties, args);
>>> if (err)
>>> return err;
>>> - dev = kfd_device_by_id(args.gpu_id);
>>> + dev = kfd_device_by_id(args->gpu_id);
>>> if (dev == NULL)
>>> return -EINVAL;
>>> @@ -250,7 +244,7 @@ static long kfd_ioctl_create_queue(struct file
>>> *filep,
>>> struct kfd_process *p,
>>> pdd = kfd_bind_process_to_device(dev, p);
>>> if (IS_ERR(pdd)) {
>>> - err = PTR_ERR(pdd);
>>> + err = -ESRCH;
>>> goto err_bind_process;
>>> }
>>> @@ -263,33 +257,26 @@ static long kfd_ioctl_create_queue(struct file
>>> *filep,
>>> struct kfd_process *p,
>>> if (err != 0)
>>> goto err_create_queue;
>>> - args.queue_id = queue_id;
>>> + args->queue_id = queue_id;
>>> /* Return gpu_id as doorbell offset for mmap usage */
>>> - args.doorbell_offset = args.gpu_id << PAGE_SHIFT;
>>> -
>>> - if (copy_to_user(arg, &args, sizeof(args))) {
>>> - err = -EFAULT;
>>> - goto err_copy_args_out;
>>> - }
>>> + args->doorbell_offset = args->gpu_id << PAGE_SHIFT;
>>> mutex_unlock(&p->mutex);
>>> - pr_debug("kfd: queue id %d was created successfully\n",
>>> args.queue_id);
>>> + pr_debug("kfd: queue id %d was created successfully\n",
>>> args->queue_id);
>>> pr_debug("ring buffer address == 0x%016llX\n",
>>> - args.ring_base_address);
>>> + args->ring_base_address);
>>> pr_debug("read ptr address == 0x%016llX\n",
>>> - args.read_pointer_address);
>>> + args->read_pointer_address);
>>> pr_debug("write ptr address == 0x%016llX\n",
>>> - args.write_pointer_address);
>>> + args->write_pointer_address);
>>> return 0;
>>> -err_copy_args_out:
>>> - pqm_destroy_queue(&p->pqm, queue_id);
>>> err_create_queue:
>>> err_bind_process:
>>> mutex_unlock(&p->mutex);
>>> @@ -297,99 +284,90 @@ err_bind_process:
>>> }
>>> static int kfd_ioctl_destroy_queue(struct file *filp, struct
>>> kfd_process *p,
>>> - void __user *arg)
>>> + void *data)
>>> {
>>> int retval;
>>> - struct kfd_ioctl_destroy_queue_args args;
>>> -
>>> - if (copy_from_user(&args, arg, sizeof(args)))
>>> - return -EFAULT;
>>> + struct kfd_ioctl_destroy_queue_args *args = data;
>>> pr_debug("kfd: destroying queue id %d for PASID %d\n",
>>> - args.queue_id,
>>> + args->queue_id,
>>> p->pasid);
>>> mutex_lock(&p->mutex);
>>> - retval = pqm_destroy_queue(&p->pqm, args.queue_id);
>>> + retval = pqm_destroy_queue(&p->pqm, args->queue_id);
>>> mutex_unlock(&p->mutex);
>>> return retval;
>>> }
>>> static int kfd_ioctl_update_queue(struct file *filp, struct
>>> kfd_process *p,
>>> - void __user *arg)
>>> + void *data)
>>> {
>>> int retval;
>>> - struct kfd_ioctl_update_queue_args args;
>>> + struct kfd_ioctl_update_queue_args *args = data;
>>> struct queue_properties properties;
>>> - if (copy_from_user(&args, arg, sizeof(args)))
>>> - return -EFAULT;
>>> -
>>> - if (args.queue_percentage > KFD_MAX_QUEUE_PERCENTAGE) {
>>> + 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) {
>>> + 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) &&
>>> + if ((args->ring_base_address) &&
>>> (!access_ok(VERIFY_WRITE,
>>> - (const void __user *) args.ring_base_address,
>>> + (const void __user *) args->ring_base_address,
>>> sizeof(uint64_t)))) {
>>> pr_err("kfd: can't access ring base address\n");
>>> return -EFAULT;
>>> }
>>> - if (!is_power_of_2(args.ring_size) && (args.ring_size != 0)) {
>>> + 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;
>>> }
>>> - properties.queue_address = args.ring_base_address;
>>> - properties.queue_size = args.ring_size;
>>> - properties.queue_percent = args.queue_percentage;
>>> - properties.priority = args.queue_priority;
>>> + properties.queue_address = args->ring_base_address;
>>> + properties.queue_size = args->ring_size;
>>> + properties.queue_percent = args->queue_percentage;
>>> + properties.priority = args->queue_priority;
>>> pr_debug("kfd: updating queue id %d for PASID %d\n",
>>> - args.queue_id, p->pasid);
>>> + args->queue_id, p->pasid);
>>> mutex_lock(&p->mutex);
>>> - retval = pqm_update_queue(&p->pqm, args.queue_id, &properties);
>>> + retval = pqm_update_queue(&p->pqm, args->queue_id, &properties);
>>> mutex_unlock(&p->mutex);
>>> return retval;
>>> }
>>> -static long kfd_ioctl_set_memory_policy(struct file *filep,
>>> - struct kfd_process *p, void __user *arg)
>>> +static int kfd_ioctl_set_memory_policy(struct file *filep,
>>> + struct kfd_process *p, void *data)
>>> {
>>> - struct kfd_ioctl_set_memory_policy_args args;
>>> + struct kfd_ioctl_set_memory_policy_args *args = data;
>>> struct kfd_dev *dev;
>>> int err = 0;
>>> struct kfd_process_device *pdd;
>>> enum cache_policy default_policy, alternate_policy;
>>> - if (copy_from_user(&args, arg, sizeof(args)))
>>> - return -EFAULT;
>>> -
>>> - if (args.default_policy != KFD_IOC_CACHE_POLICY_COHERENT
>>> - && args.default_policy != KFD_IOC_CACHE_POLICY_NONCOHERENT) {
>>> + if (args->default_policy != KFD_IOC_CACHE_POLICY_COHERENT
>>> + && args->default_policy != KFD_IOC_CACHE_POLICY_NONCOHERENT) {
>>> return -EINVAL;
>>> }
>>> - if (args.alternate_policy != KFD_IOC_CACHE_POLICY_COHERENT
>>> - && args.alternate_policy !=
>>> KFD_IOC_CACHE_POLICY_NONCOHERENT) {
>>> + if (args->alternate_policy != KFD_IOC_CACHE_POLICY_COHERENT
>>> + && args->alternate_policy !=
>>> KFD_IOC_CACHE_POLICY_NONCOHERENT) {
>>> return -EINVAL;
>>> }
>>> - dev = kfd_device_by_id(args.gpu_id);
>>> + dev = kfd_device_by_id(args->gpu_id);
>>> if (dev == NULL)
>>> return -EINVAL;
>>> @@ -397,23 +375,23 @@ static long kfd_ioctl_set_memory_policy(struct
>>> file *filep,
>>> pdd = kfd_bind_process_to_device(dev, p);
>>> if (IS_ERR(pdd)) {
>>> - err = PTR_ERR(pdd);
>>> + err = -ESRCH;
>>> goto out;
>>> }
>>> - default_policy = (args.default_policy ==
>>> KFD_IOC_CACHE_POLICY_COHERENT)
>>> + default_policy = (args->default_policy ==
>>> KFD_IOC_CACHE_POLICY_COHERENT)
>>> ? cache_policy_coherent : cache_policy_noncoherent;
>>> alternate_policy =
>>> - (args.alternate_policy == KFD_IOC_CACHE_POLICY_COHERENT)
>>> + (args->alternate_policy == KFD_IOC_CACHE_POLICY_COHERENT)
>>> ? cache_policy_coherent : cache_policy_noncoherent;
>>> if (!dev->dqm->set_cache_memory_policy(dev->dqm,
>>> &pdd->qpd,
>>> default_policy,
>>> alternate_policy,
>>> - (void __user *)args.alternate_aperture_base,
>>> - args.alternate_aperture_size))
>>> + (void __user *)args->alternate_aperture_base,
>>> + args->alternate_aperture_size))
>>> err = -EINVAL;
>>> out:
>>> @@ -422,53 +400,44 @@ out:
>>> return err;
>>> }
>>> -static long kfd_ioctl_get_clock_counters(struct file *filep,
>>> - struct kfd_process *p, void __user *arg)
>>> +static int kfd_ioctl_get_clock_counters(struct file *filep,
>>> + struct kfd_process *p, void *data)
>>> {
>>> - struct kfd_ioctl_get_clock_counters_args args;
>>> + struct kfd_ioctl_get_clock_counters_args *args = data;
>>> struct kfd_dev *dev;
>>> struct timespec time;
>>> - if (copy_from_user(&args, arg, sizeof(args)))
>>> - return -EFAULT;
>>> -
>>> - dev = kfd_device_by_id(args.gpu_id);
>>> + dev = kfd_device_by_id(args->gpu_id);
>>> if (dev == NULL)
>>> return -EINVAL;
>>> /* Reading GPU clock counter from KGD */
>>> - args.gpu_clock_counter = kfd2kgd->get_gpu_clock_counter(dev->kgd);
>>> + args->gpu_clock_counter =
>>> kfd2kgd->get_gpu_clock_counter(dev->kgd);
>>> /* No access to rdtsc. Using raw monotonic time */
>>> getrawmonotonic(&time);
>>> - args.cpu_clock_counter = (uint64_t)timespec_to_ns(&time);
>>> + args->cpu_clock_counter = (uint64_t)timespec_to_ns(&time);
>>> get_monotonic_boottime(&time);
>>> - args.system_clock_counter = (uint64_t)timespec_to_ns(&time);
>>> + args->system_clock_counter = (uint64_t)timespec_to_ns(&time);
>>> /* Since the counter is in nano-seconds we use 1GHz frequency */
>>> - args.system_clock_freq = 1000000000;
>>> -
>>> - if (copy_to_user(arg, &args, sizeof(args)))
>>> - return -EFAULT;
>>> + args->system_clock_freq = 1000000000;
>>> return 0;
>>> }
>>> static int kfd_ioctl_get_process_apertures(struct file *filp,
>>> - struct kfd_process *p, void __user *arg)
>>> + struct kfd_process *p, void *data)
>>> {
>>> - struct kfd_ioctl_get_process_apertures_args args;
>>> + struct kfd_ioctl_get_process_apertures_args *args = data;
>>> struct kfd_process_device_apertures *pAperture;
>>> struct kfd_process_device *pdd;
>>> dev_dbg(kfd_device, "get apertures for PASID %d", p->pasid);
>>> - if (copy_from_user(&args, arg, sizeof(args)))
>>> - return -EFAULT;
>>> -
>>> - args.num_of_nodes = 0;
>>> + args->num_of_nodes = 0;
>>> mutex_lock(&p->mutex);
>>> @@ -477,7 +446,8 @@ static int
>>> kfd_ioctl_get_process_apertures(struct file *filp,
>>> /* Run over all pdd of the process */
>>> pdd = kfd_get_first_process_device_data(p);
>>> do {
>>> - pAperture = &args.process_apertures[args.num_of_nodes];
>>> + pAperture =
>>> + &args->process_apertures[args->num_of_nodes];
>>> pAperture->gpu_id = pdd->dev->id;
>>> pAperture->lds_base = pdd->lds_base;
>>> pAperture->lds_limit = pdd->lds_limit;
>>> @@ -487,7 +457,7 @@ static int
>>> kfd_ioctl_get_process_apertures(struct file *filp,
>>> pAperture->scratch_limit = pdd->scratch_limit;
>>> dev_dbg(kfd_device,
>>> - "node id %u\n", args.num_of_nodes);
>>> + "node id %u\n", args->num_of_nodes);
>>> dev_dbg(kfd_device,
>>> "gpu id %u\n", pdd->dev->id);
>>> dev_dbg(kfd_device,
>>> @@ -503,23 +473,23 @@ static int
>>> kfd_ioctl_get_process_apertures(struct file
>>> *filp,
>>> dev_dbg(kfd_device,
>>> "scratch_limit %llX\n", pdd->scratch_limit);
>>> - args.num_of_nodes++;
>>> + args->num_of_nodes++;
>>> } while ((pdd = kfd_get_next_process_device_data(p, pdd))
>>> != NULL &&
>>> - (args.num_of_nodes < NUM_OF_SUPPORTED_GPUS));
>>> + (args->num_of_nodes < NUM_OF_SUPPORTED_GPUS));
>>> }
>>> mutex_unlock(&p->mutex);
>>> - if (copy_to_user(arg, &args, sizeof(args)))
>>> - return -EFAULT;
>>> -
>>> return 0;
>>> }
>>> static long kfd_ioctl(struct file *filep, unsigned int cmd,
>>> unsigned long arg)
>>> {
>>> struct kfd_process *process;
>>> - long err = -EINVAL;
>>> + char stack_kdata[128];
>>> + char *kdata = NULL;
>>> + unsigned int usize, asize;
>>> + int retcode = -EINVAL;
>>> dev_dbg(kfd_device,
>>> "ioctl cmd 0x%x (#%d), arg 0x%lx\n",
>>> @@ -529,54 +499,84 @@ static long kfd_ioctl(struct file *filep,
>>> unsigned int
>>> cmd, unsigned long arg)
>>> if (IS_ERR(process))
>>> return PTR_ERR(process);
>>> + 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);
>>> + }
>>> +
>>> + 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);
>>> + }
>>> +
>>> +
>>> switch (cmd) {
>>> case KFD_IOC_GET_VERSION:
>>> - err = kfd_ioctl_get_version(filep, process, (void __user
>>> *)arg);
>>> + retcode = kfd_ioctl_get_version(filep, process, kdata);
>>> break;
>>> case KFD_IOC_CREATE_QUEUE:
>>> - err = kfd_ioctl_create_queue(filep, process,
>>> - (void __user *)arg);
>>> + retcode = kfd_ioctl_create_queue(filep, process,
>>> + kdata);
>>> break;
>>> case KFD_IOC_DESTROY_QUEUE:
>>> - err = kfd_ioctl_destroy_queue(filep, process,
>>> - (void __user *)arg);
>>> + retcode = kfd_ioctl_destroy_queue(filep, process,
>>> + kdata);
>>> break;
>>> case KFD_IOC_SET_MEMORY_POLICY:
>>> - err = kfd_ioctl_set_memory_policy(filep, process,
>>> - (void __user *)arg);
>>> + retcode = kfd_ioctl_set_memory_policy(filep, process,
>>> + kdata);
>>> break;
>>> case KFD_IOC_GET_CLOCK_COUNTERS:
>>> - err = kfd_ioctl_get_clock_counters(filep, process,
>>> - (void __user *)arg);
>>> + retcode = kfd_ioctl_get_clock_counters(filep, process,
>>> + kdata);
>>> break;
>>> case KFD_IOC_GET_PROCESS_APERTURES:
>>> - err = kfd_ioctl_get_process_apertures(filep, process,
>>> - (void __user *)arg);
>>> + retcode = kfd_ioctl_get_process_apertures(filep, process,
>>> + kdata);
>>> break;
>>> case KFD_IOC_UPDATE_QUEUE:
>>> - err = kfd_ioctl_update_queue(filep, process,
>>> - (void __user *)arg);
>>> + retcode = kfd_ioctl_update_queue(filep, process,
>>> + kdata);
>>> break;
>>> default:
>>> - dev_err(kfd_device,
>>> + dev_dbg(kfd_device,
>>> "unknown ioctl cmd 0x%x, arg 0x%lx)\n",
>>> cmd, arg);
>>> - err = -EINVAL;
>>> + retcode = -EINVAL;
>>> break;
>>> }
>>> - if (err < 0)
>>> - dev_err(kfd_device,
>>> - "ioctl error %ld for ioctl cmd 0x%x (#%d)\n",
>>> - err, cmd, _IOC_NR(cmd));
>>> + if (cmd & IOC_OUT)
>>> + if (copy_to_user((void __user *)arg, kdata, usize) != 0)
>>> + retcode = -EFAULT;
>>> - return err;
>>> +err_i1:
>>> + if (kdata != stack_kdata)
>>> + kfree(kdata);
>>> +
>>> + if (retcode)
>>> + dev_dbg(kfd_device, "ret = %d\n", retcode);
>>> +
>>> + return retcode;
>>> }
>>> static int kfd_mmap(struct file *filp, struct vm_area_struct *vma)
>>
More information about the dri-devel
mailing list