[PATCH 5/9] VC04_SERVICES: Add compat ioctl handler for "queue bulk"

Michael Zoran mzoran at crowfest.net
Wed Jan 18 07:04:49 PST 2017


Add compat handler for "queue bulk" ioctls and move
parts in common with the regular ioctls to vchiq_ioctl_queue_bulk

Signed-off-by: Michael Zoran <mzoran at crowfest.net>
---
 .../vc04_services/interface/vchiq_arm/vchiq_arm.c  | 206 ++++++++++++++-------
 1 file changed, 141 insertions(+), 65 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 1c0afa318036..7067bd3f4bd5 100644
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
@@ -572,6 +572,87 @@ vchiq_ioctl_create_service(VCHIQ_INSTANCE_T instance,
 	return 0;
 }
 
+static long
+vchiq_ioctl_queue_bulk(VCHIQ_INSTANCE_T instance,
+		       VCHIQ_QUEUE_BULK_TRANSFER_T *args,
+		       VCHIQ_BULK_DIR_T dir,
+		       VCHIQ_STATUS_T *status,
+		       bool *needs_ret_mode_waiting)
+{
+	struct bulk_waiter_node *waiter = NULL;
+	*needs_ret_mode_waiting = false;
+
+	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 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);
+			return -ESRCH;
+		}
+
+		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)
+		return 0;
+
+	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 {
+		*needs_ret_mode_waiting  = true;
+		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);
+	}
+
+	return 0;
+}
+
 /****************************************************************************
 *
 *   vchiq_ioctl
@@ -774,7 +855,7 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 	case VCHIQ_IOC_QUEUE_BULK_TRANSMIT:
 	case VCHIQ_IOC_QUEUE_BULK_RECEIVE: {
 		VCHIQ_QUEUE_BULK_TRANSFER_T args;
-		struct bulk_waiter_node *waiter = NULL;
+		bool needs_ret_mode_waiting = false;
 		VCHIQ_BULK_DIR_T dir =
 			(cmd == VCHIQ_IOC_QUEUE_BULK_TRANSMIT) ?
 			VCHIQ_BULK_TRANSMIT : VCHIQ_BULK_RECEIVE;
@@ -792,75 +873,21 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 			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;
-				}
+		ret = vchiq_ioctl_queue_bulk(instance,
+					     &args,
+					     dir,
+					     &status,
+					     &needs_ret_mode_waiting);
 
-			}
-			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 {
+		if (needs_ret_mode_waiting) {
 			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)
+					 &(((VCHIQ_QUEUE_BULK_TRANSFER_T __user *)
+					 arg)->mode),
+					(const void *)&mode_waiting,
+					sizeof(mode_waiting)))
 				ret = -EFAULT;
 		}
 	} break;
@@ -1306,6 +1333,53 @@ vchiq_ioctl_compat_internal(
 						 elements, args32.count);
 	} break;
 
+	case VCHIQ_IOC_QUEUE_BULK_TRANSMIT32:
+	case VCHIQ_IOC_QUEUE_BULK_RECEIVE32: {
+		VCHIQ_QUEUE_BULK_TRANSFER_T args;
+		struct vchiq_queue_bulk_transfer32 args32;
+		bool needs_ret_mode_waiting = false;
+		VCHIQ_BULK_DIR_T dir =
+			(cmd == VCHIQ_IOC_QUEUE_BULK_TRANSMIT32) ?
+			VCHIQ_BULK_TRANSMIT : VCHIQ_BULK_RECEIVE;
+
+		if (copy_from_user
+			(&args32, (const void __user *)arg,
+			sizeof(args32))) {
+			ret = -EFAULT;
+			break;
+		}
+
+		args.handle   = args32.handle;
+		args.data     = compat_ptr(args32.data);
+		args.size     = args32.size;
+		args.userdata = compat_ptr(args32.userdata);
+		args.mode     = args32.mode;
+
+		service = find_service_for_instance(instance, args.handle);
+		if (!service) {
+			ret = -EINVAL;
+			break;
+		}
+
+		ret = vchiq_ioctl_queue_bulk(instance,
+					     &args,
+					     dir,
+					     &status,
+					     &needs_ret_mode_waiting);
+
+		if (needs_ret_mode_waiting) {
+			const VCHIQ_BULK_MODE_T mode_waiting =
+				VCHIQ_BULK_MODE_WAITING;
+
+			if (copy_to_user((void __user *)
+					 &(((struct vchiq_queue_bulk_transfer32 __user *)
+					 arg)->mode),
+					(const void *)&mode_waiting,
+					sizeof(mode_waiting)))
+				ret = -EFAULT;
+		}
+	} break;
+
 	default:
 		ret = -ENOTTY;
 		break;
@@ -1348,6 +1422,8 @@ vchiq_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg)
 	switch (cmd) {
 	case VCHIQ_IOC_CREATE_SERVICE32:
 	case VCHIQ_IOC_QUEUE_MESSAGE32:
+	case VCHIQ_IOC_QUEUE_BULK_TRANSMIT32:
+	case VCHIQ_IOC_QUEUE_BULK_RECEIVE32:
 		return vchiq_ioctl_compat_internal(file, cmd, arg);
 	default:
 		return vchiq_ioctl(file, cmd, arg);
-- 
2.11.0




More information about the linux-rpi-kernel mailing list