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) >>