Split out the ioctl implementation for VCHIQ_IOC_QUEUE_BULK_TRANSMIT into a separate function so it can be shared with the compat implementation. Here, the input data is converted separately in the compat handler, while the output data is passed as a __user pointer to thec vchiq_queue_bulk_transfer->mode word that is compatible. Signed-off-by: Arnd Bergmann <arnd@xxxxxxxx> --- .../interface/vchiq_arm/vchiq_arm.c | 220 +++++++++--------- 1 file changed, 109 insertions(+), 111 deletions(-) diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c index cbe9583a0114..50af7f4a1b7c 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c @@ -938,6 +938,95 @@ static int vchiq_ioc_dequeue_message(struct vchiq_instance *instance, return ret; } +static int vchiq_irq_queue_bulk_tx_rx(struct vchiq_instance *instance, + struct vchiq_queue_bulk_transfer *args, + enum vchiq_bulk_dir dir, + enum vchiq_bulk_mode __user *mode) +{ + struct vchiq_service *service; + struct bulk_waiter_node *waiter = NULL; + int status = 0; + int ret; + + service = find_service_for_instance(instance, args->handle); + if (!service) + return -EINVAL; + + if (args->mode == VCHIQ_BULK_MODE_BLOCKING) { + waiter = kzalloc(sizeof(struct bulk_waiter_node), + GFP_KERNEL); + if (!waiter) { + ret = -ENOMEM; + goto out; + } + + args->userdata = &waiter->bulk_waiter; + } else if (args->mode == VCHIQ_BULK_MODE_WAITING) { + mutex_lock(&instance->bulk_waiter_list_mutex); + list_for_each_entry(waiter, &instance->bulk_waiter_list, + list) { + if (waiter->pid == current->pid) { + list_del(&waiter->list); + break; + } + } + mutex_unlock(&instance->bulk_waiter_list_mutex); + if (!waiter) { + vchiq_log_error(vchiq_arm_log_level, + "no bulk_waiter found for pid %d", + current->pid); + ret = -ESRCH; + goto out; + } + vchiq_log_info(vchiq_arm_log_level, + "found bulk_waiter %pK for pid %d", waiter, + current->pid); + args->userdata = &waiter->bulk_waiter; + } + + status = vchiq_bulk_transfer(args->handle, args->data, args->size, + args->userdata, args->mode, dir); + + if (!waiter) { + ret = 0; + goto out; + } + + if ((status != VCHIQ_RETRY) || fatal_signal_pending(current) || + !waiter->bulk_waiter.bulk) { + if (waiter->bulk_waiter.bulk) { + /* Cancel the signal when the transfer + ** completes. */ + spin_lock(&bulk_waiter_spinlock); + waiter->bulk_waiter.bulk->userdata = NULL; + spin_unlock(&bulk_waiter_spinlock); + } + kfree(waiter); + ret = 0; + } else { + const enum vchiq_bulk_mode mode_waiting = + VCHIQ_BULK_MODE_WAITING; + waiter->pid = current->pid; + mutex_lock(&instance->bulk_waiter_list_mutex); + list_add(&waiter->list, &instance->bulk_waiter_list); + mutex_unlock(&instance->bulk_waiter_list_mutex); + vchiq_log_info(vchiq_arm_log_level, + "saved bulk_waiter %pK for pid %d", + waiter, current->pid); + + ret = put_user(mode_waiting, mode); + } +out: + unlock_service(service); + if (ret) + return ret; + else if (status == VCHIQ_ERROR) + return -EIO; + else if (status == VCHIQ_RETRY) + return -EINTR; + return 0; +} + /**************************************************************************** * * vchiq_ioctl @@ -1118,90 +1207,20 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg) case VCHIQ_IOC_QUEUE_BULK_TRANSMIT: case VCHIQ_IOC_QUEUE_BULK_RECEIVE: { struct vchiq_queue_bulk_transfer args; - struct bulk_waiter_node *waiter = NULL; + struct vchiq_queue_bulk_transfer __user *argp; enum vchiq_bulk_dir dir = (cmd == VCHIQ_IOC_QUEUE_BULK_TRANSMIT) ? VCHIQ_BULK_TRANSMIT : VCHIQ_BULK_RECEIVE; - if (copy_from_user(&args, (const void __user *)arg, - sizeof(args))) { + argp = (void __user *)arg; + if (copy_from_user(&args, argp, sizeof(args))) { ret = -EFAULT; break; } - service = find_service_for_instance(instance, args.handle); - if (!service) { - ret = -EINVAL; - break; - } - - if (args.mode == VCHIQ_BULK_MODE_BLOCKING) { - waiter = kzalloc(sizeof(struct bulk_waiter_node), - GFP_KERNEL); - if (!waiter) { - ret = -ENOMEM; - break; - } - - args.userdata = &waiter->bulk_waiter; - } else if (args.mode == VCHIQ_BULK_MODE_WAITING) { - mutex_lock(&instance->bulk_waiter_list_mutex); - list_for_each_entry(waiter, &instance->bulk_waiter_list, - list) { - if (waiter->pid == current->pid) { - list_del(&waiter->list); - break; - } - } - mutex_unlock(&instance->bulk_waiter_list_mutex); - if (!waiter) { - vchiq_log_error(vchiq_arm_log_level, - "no bulk_waiter found for pid %d", - current->pid); - ret = -ESRCH; - break; - } - vchiq_log_info(vchiq_arm_log_level, - "found bulk_waiter %pK for pid %d", waiter, - current->pid); - args.userdata = &waiter->bulk_waiter; - } - - status = vchiq_bulk_transfer(args.handle, args.data, args.size, - args.userdata, args.mode, dir); - - if (!waiter) - break; - - if ((status != VCHIQ_RETRY) || fatal_signal_pending(current) || - !waiter->bulk_waiter.bulk) { - if (waiter->bulk_waiter.bulk) { - /* Cancel the signal when the transfer - ** completes. */ - spin_lock(&bulk_waiter_spinlock); - waiter->bulk_waiter.bulk->userdata = NULL; - spin_unlock(&bulk_waiter_spinlock); - } - kfree(waiter); - } else { - const enum vchiq_bulk_mode mode_waiting = - VCHIQ_BULK_MODE_WAITING; - waiter->pid = current->pid; - mutex_lock(&instance->bulk_waiter_list_mutex); - list_add(&waiter->list, &instance->bulk_waiter_list); - mutex_unlock(&instance->bulk_waiter_list_mutex); - vchiq_log_info(vchiq_arm_log_level, - "saved bulk_waiter %pK for pid %d", - waiter, current->pid); - - if (copy_to_user((void __user *) - &(((struct vchiq_queue_bulk_transfer __user *) - arg)->mode), - (const void *)&mode_waiting, - sizeof(mode_waiting))) - ret = -EFAULT; - } + ret = vchiq_irq_queue_bulk_tx_rx(instance, &args, + dir, &argp->mode); } break; case VCHIQ_IOC_AWAIT_COMPLETION: { @@ -1620,47 +1639,26 @@ struct vchiq_queue_bulk_transfer32 { static long vchiq_compat_ioctl_queue_bulk(struct file *file, unsigned int cmd, - unsigned long arg) + struct vchiq_queue_bulk_transfer32 __user *argp) { - struct vchiq_queue_bulk_transfer __user *args; struct vchiq_queue_bulk_transfer32 args32; - struct vchiq_queue_bulk_transfer32 __user *ptrargs32 = - (struct vchiq_queue_bulk_transfer32 __user *)arg; - long ret; - - args = compat_alloc_user_space(sizeof(*args)); - if (!args) - return -EFAULT; - - if (copy_from_user(&args32, ptrargs32, sizeof(args32))) - return -EFAULT; - - if (put_user(args32.handle, &args->handle) || - put_user(compat_ptr(args32.data), &args->data) || - put_user(args32.size, &args->size) || - put_user(compat_ptr(args32.userdata), &args->userdata) || - put_user(args32.mode, &args->mode)) - return -EFAULT; - - if (cmd == VCHIQ_IOC_QUEUE_BULK_TRANSMIT32) - cmd = VCHIQ_IOC_QUEUE_BULK_TRANSMIT; - else - cmd = VCHIQ_IOC_QUEUE_BULK_RECEIVE; - - ret = vchiq_ioctl(file, cmd, (unsigned long)args); + struct vchiq_queue_bulk_transfer args; + enum vchiq_bulk_dir dir = (cmd == VCHIQ_IOC_QUEUE_BULK_TRANSMIT) ? + VCHIQ_BULK_TRANSMIT : VCHIQ_BULK_RECEIVE; - if (ret < 0) - return ret; - - if (get_user(args32.mode, &args->mode)) + if (copy_from_user(&args32, argp, sizeof(args32))) return -EFAULT; - if (copy_to_user(&ptrargs32->mode, - &args32.mode, - sizeof(args32.mode))) - return -EFAULT; + args = (struct vchiq_queue_bulk_transfer) { + .handle = args32.handle, + .data = compat_ptr(args32.data), + .size = args32.size, + .userdata = compat_ptr(args32.userdata), + .mode = args32.mode, + }; - return 0; + return vchiq_irq_queue_bulk_tx_rx(file->private_data, &args, + dir, &argp->mode); } struct vchiq_completion_data32 { @@ -1893,7 +1891,7 @@ vchiq_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) return vchiq_compat_ioctl_queue_message(file, cmd, argp); case VCHIQ_IOC_QUEUE_BULK_TRANSMIT32: case VCHIQ_IOC_QUEUE_BULK_RECEIVE32: - return vchiq_compat_ioctl_queue_bulk(file, cmd, arg); + return vchiq_compat_ioctl_queue_bulk(file, cmd, argp); case VCHIQ_IOC_AWAIT_COMPLETION32: return vchiq_compat_ioctl_await_completion(file, cmd, arg); case VCHIQ_IOC_DEQUEUE_MESSAGE32: -- 2.27.0 _______________________________________________ devel mailing list devel@xxxxxxxxxxxxxxxxxxxxxx http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel