[PATCH V2 3/7] staging: vchiq_arm: Add compat ioctl for queue bulk
Michael Zoran
mzoran at crowfest.net
Sat Jan 21 09:48:12 PST 2017
Add compat ioctl for queue bulk
Signed-off-by: Michael Zoran <mzoran at crowfest.net>
---
.../vc04_services/interface/vchiq_arm/vchiq_arm.c | 274 ++++++++++++++-------
1 file changed, 180 insertions(+), 94 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 a42ae448e519..60f4d92dede5 100644
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
@@ -848,6 +848,178 @@ vchiq_ioctl_compat_queue_message(struct vchiq_ioctl_ctxt *ctxt)
#endif
+static long
+vchiq_ioctl_do_queue_bulk(struct vchiq_ioctl_ctxt *ctxt,
+ VCHIQ_BULK_DIR_T dir)
+{
+ VCHIQ_QUEUE_BULK_TRANSFER_T *args = ctxt->args;
+ VCHIQ_INSTANCE_T instance = ctxt->instance;
+ struct bulk_waiter_node *waiter = NULL;
+
+ ctxt->service = find_service_for_instance(instance, args->handle);
+ if (!ctxt->service)
+ return -EINVAL;
+
+ if (args->mode == VCHIQ_BULK_MODE_BLOCKING) {
+ waiter = kzalloc(sizeof(*waiter), GFP_KERNEL);
+
+ if (!waiter)
+ return -ENOMEM;
+
+ args->userdata = &waiter->bulk_waiter;
+ } else if (args->mode == VCHIQ_BULK_MODE_WAITING) {
+ struct bulk_waiter_node *index;
+
+ mutex_lock(&instance->bulk_waiter_list_mutex);
+ list_for_each_entry(index, &instance->bulk_waiter_list, list) {
+ if (index->pid == current->pid) {
+ waiter = index;
+ list_del(&index->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);
+ return -ESRCH;
+ }
+
+ vchiq_log_info(vchiq_arm_log_level,
+ "found bulk_waiter %pK for pid %d", waiter,
+ current->pid);
+ args->userdata = &waiter->bulk_waiter;
+ }
+
+ ctxt->status =
+ vchiq_bulk_transfer(args->handle,
+ VCHI_MEM_HANDLE_INVALID,
+ args->data,
+ args->size,
+ args->userdata,
+ args->mode,
+ dir);
+
+ if (!waiter)
+ return vchiq_map_status(ctxt->status);
+
+ if ((ctxt->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 {
+ 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);
+
+ args->mode = VCHIQ_BULK_MODE_WAITING;
+ if (ctxt->cpyret_handler(ctxt))
+ return -EFAULT;
+ }
+
+ return vchiq_map_status(ctxt->status);
+}
+
+static long
+vchiq_ioctl_queue_bulk_cpyret(struct vchiq_ioctl_ctxt *ctxt)
+{
+ VCHIQ_QUEUE_BULK_TRANSFER_T __user *puargs =
+ (VCHIQ_QUEUE_BULK_TRANSFER_T __user *)ctxt->arg;
+ VCHIQ_QUEUE_BULK_TRANSFER_T *args = ctxt->args;
+
+ return copy_to_user(&puargs->mode,
+ &args->mode,
+ sizeof(args->mode));
+}
+
+static long
+vchiq_ioctl_queue_bulk(struct vchiq_ioctl_ctxt *ctxt)
+{
+ VCHIQ_QUEUE_BULK_TRANSFER_T __user *puargs =
+ (VCHIQ_QUEUE_BULK_TRANSFER_T __user *)ctxt->arg;
+ VCHIQ_QUEUE_BULK_TRANSFER_T args;
+ VCHIQ_BULK_DIR_T dir =
+ (ctxt->cmd == VCHIQ_IOC_QUEUE_BULK_TRANSMIT) ?
+ VCHIQ_BULK_TRANSMIT : VCHIQ_BULK_RECEIVE;
+
+ if (copy_from_user(&args, puargs, sizeof(args)))
+ return -EFAULT;
+
+ ctxt->args = &args;
+ ctxt->cpyret_handler = vchiq_ioctl_queue_bulk_cpyret;
+
+ return vchiq_ioctl_do_queue_bulk(ctxt, dir);
+}
+
+#if defined(CONFIG_COMPAT)
+
+struct vchiq_queue_bulk_transfer32 {
+ unsigned int handle;
+ compat_uptr_t data;
+ unsigned int size;
+ compat_uptr_t userdata;
+ VCHIQ_BULK_MODE_T mode;
+};
+
+#define VCHIQ_IOC_QUEUE_BULK_TRANSMIT32 \
+ _IOWR(VCHIQ_IOC_MAGIC, 5, struct vchiq_queue_bulk_transfer32)
+#define VCHIQ_IOC_QUEUE_BULK_RECEIVE32 \
+ _IOWR(VCHIQ_IOC_MAGIC, 6, struct vchiq_queue_bulk_transfer32)
+
+static long
+vchiq_ioctl_compat_queue_bulk_cpyret(struct vchiq_ioctl_ctxt *ctxt)
+{
+ struct vchiq_queue_bulk_transfer32 __user *puargs =
+ (struct vchiq_queue_bulk_transfer32 __user *)ctxt->arg;
+ VCHIQ_QUEUE_BULK_TRANSFER_T *args = ctxt->args;
+
+ return copy_to_user(&puargs->mode,
+ &args->mode,
+ sizeof(args->mode));
+}
+
+static long
+vchiq_ioctl_compat_queue_bulk(struct vchiq_ioctl_ctxt *ctxt)
+{
+ struct vchiq_queue_bulk_transfer32 __user *puargs32 =
+ (struct vchiq_queue_bulk_transfer32 __user *)ctxt->arg;
+ VCHIQ_QUEUE_BULK_TRANSFER_T args;
+ struct vchiq_queue_bulk_transfer32 args32;
+ VCHIQ_BULK_DIR_T dir =
+ (ctxt->cmd == VCHIQ_IOC_QUEUE_BULK_TRANSMIT32) ?
+ VCHIQ_BULK_TRANSMIT : VCHIQ_BULK_RECEIVE;
+
+ if (copy_from_user(&args32, puargs32, sizeof(args32)))
+ return -EFAULT;
+
+ args.handle = args32.handle;
+ args.data = compat_ptr(args32.data);
+ args.size = args32.size;
+ args.userdata = compat_ptr(args32.userdata);
+ args.mode = args32.mode;
+
+ ctxt->args = &args;
+ ctxt->cpyret_handler = vchiq_ioctl_compat_queue_bulk_cpyret;
+
+ return vchiq_ioctl_do_queue_bulk(ctxt, dir);
+}
+
+#endif
+
/****************************************************************************
*
* vchiq_ioctl
@@ -870,6 +1042,10 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
case VCHIQ_IOC_QUEUE_MESSAGE:
return vchiq_dispatch_ioctl(vchiq_ioctl_queue_message,
file, cmd, arg);
+ case VCHIQ_IOC_QUEUE_BULK_TRANSMIT:
+ case VCHIQ_IOC_QUEUE_BULK_RECEIVE:
+ return vchiq_dispatch_ioctl(vchiq_ioctl_queue_bulk,
+ file, cmd, arg);
default:
break;
}
@@ -1008,100 +1184,6 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
ret = -EINVAL;
} break;
- case VCHIQ_IOC_QUEUE_BULK_TRANSMIT:
- case VCHIQ_IOC_QUEUE_BULK_RECEIVE: {
- VCHIQ_QUEUE_BULK_TRANSFER_T args;
- struct bulk_waiter_node *waiter = NULL;
- VCHIQ_BULK_DIR_T dir =
- (cmd == VCHIQ_IOC_QUEUE_BULK_TRANSMIT) ?
- VCHIQ_BULK_TRANSMIT : VCHIQ_BULK_RECEIVE;
-
- if (copy_from_user
- (&args, (const void __user *)arg,
- sizeof(args)) != 0) {
- 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) {
- struct list_head *pos;
- mutex_lock(&instance->bulk_waiter_list_mutex);
- list_for_each(pos, &instance->bulk_waiter_list) {
- if (list_entry(pos, struct bulk_waiter_node,
- list)->pid == current->pid) {
- waiter = list_entry(pos,
- struct bulk_waiter_node,
- list);
- list_del(pos);
- 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,
- VCHI_MEM_HANDLE_INVALID,
- 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 VCHIQ_BULK_MODE_T 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 *)
- &(((VCHIQ_QUEUE_BULK_TRANSFER_T __user *)
- arg)->mode),
- (const void *)&mode_waiting,
- sizeof(mode_waiting)) != 0)
- ret = -EFAULT;
- }
- } break;
-
case VCHIQ_IOC_AWAIT_COMPLETION: {
VCHIQ_AWAIT_COMPLETION_T args;
@@ -1473,6 +1555,10 @@ vchiq_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg)
case VCHIQ_IOC_QUEUE_MESSAGE32:
return vchiq_dispatch_ioctl(vchiq_ioctl_compat_queue_message,
file, cmd, arg);
+ case VCHIQ_IOC_QUEUE_BULK_TRANSMIT32:
+ case VCHIQ_IOC_QUEUE_BULK_RECEIVE32:
+ return vchiq_dispatch_ioctl(vchiq_ioctl_compat_queue_bulk,
+ file, cmd, arg);
default:
return vchiq_ioctl(file, cmd, arg);
}
--
2.11.0
More information about the linux-rpi-kernel
mailing list