[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