[virtio-magma] Add magma_execute_command_buffer_with_resources
Copies the user memory blocks into a single buffer.
Change-Id: I959ee174b19e92fde68220af9c420f21975f54f9
diff --git a/drivers/virtio/virtio_magma.c b/drivers/virtio/virtio_magma.c
index cd6da57..0a35ff8 100644
--- a/drivers/virtio/virtio_magma.c
+++ b/drivers/virtio/virtio_magma.c
@@ -1025,6 +1025,81 @@ static int virtmagma_command_magma_submit_command_buffer(
return 0;
}
+static int virtmagma_command_magma_execute_command_buffer_with_resources(
+ struct virtmagma_instance *instance,
+ struct virtmagma_virtio_command *command)
+{
+ struct virtio_magma_execute_command_buffer_with_resources_ctrl *request =
+ command->request_ptr;
+ struct virtio_magma_execute_command_buffer_with_resources_resp
+ *response = command->response_ptr;
+ struct virtmagma_connection *connection;
+ struct virtmagma_command_buffer virt_command_buffer;
+ char *dst_ptr;
+ int ret;
+
+ if (!COMMAND_OK(command, request, response))
+ return -EINVAL;
+
+ connection = get_connection(instance, request->connection);
+ if (!connection)
+ return -EINVAL;
+
+ if (!get_connection_object(connection, request->context_id,
+ MAGMA_CONTEXT))
+ return -EINVAL;
+
+ /* The virtmagma_comand_buffer includes the resources and semaphore data
+ and their lengths, so we ignore the corresponding members of the request. */
+ ret = copy_from_user(&virt_command_buffer,
+ (void *)request->command_buffer,
+ sizeof(virt_command_buffer));
+ if (ret)
+ return ret;
+
+ /* reallocate request buffer with enough space for the structures */
+ command->request_size = sizeof(*request) +
+ virt_command_buffer.command_buffer_size +
+ virt_command_buffer.resource_size +
+ virt_command_buffer.semaphore_size;
+ /* memory will be freed by the caller */
+ dst_ptr = kzalloc(command->request_size, GFP_KERNEL);
+ if (!dst_ptr)
+ return -ENOMEM;
+
+ memcpy(dst_ptr, request, sizeof(*request));
+ command->request_ptr = dst_ptr;
+
+ dst_ptr += sizeof(*request);
+ ret = copy_from_user(dst_ptr,
+ (void *)virt_command_buffer.command_buffer,
+ virt_command_buffer.command_buffer_size);
+ if (ret)
+ return ret;
+
+ dst_ptr += virt_command_buffer.command_buffer_size;
+ ret = copy_from_user(dst_ptr, (void *)virt_command_buffer.resources,
+ virt_command_buffer.resource_size);
+ if (ret)
+ return ret;
+
+ dst_ptr += virt_command_buffer.resource_size;
+ ret = copy_from_user(dst_ptr, (void *)virt_command_buffer.semaphores,
+ virt_command_buffer.semaphore_size);
+ if (ret)
+ return ret;
+
+ ret = vq_out_send_sync(instance->vi, command);
+ if (ret)
+ return ret;
+
+ ret = virtmagma_check_expected_response_type(request, response);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
static int virtmagma_command_magma_create_semaphore(
struct virtmagma_instance *instance,
struct virtmagma_virtio_command *command)
@@ -1411,6 +1486,10 @@ int virtmagma_ioctl_magma_command(struct file *filp, void __user *ptr)
ret = virtmagma_command_magma_submit_command_buffer(instance,
&command);
break;
+ case VIRTIO_MAGMA_CMD_EXECUTE_COMMAND_BUFFER_WITH_RESOURCES:
+ ret = virtmagma_command_magma_execute_command_buffer_with_resources(
+ instance, &command);
+ break;
case VIRTIO_MAGMA_CMD_CREATE_SEMAPHORE:
ret = virtmagma_command_magma_create_semaphore(instance,
&command);
diff --git a/include/uapi/linux/virtmagma.h b/include/uapi/linux/virtmagma.h
index 5da7a3a..01bf455 100644
--- a/include/uapi/linux/virtmagma.h
+++ b/include/uapi/linux/virtmagma.h
@@ -39,6 +39,15 @@ struct virtmagma_ioctl_args_magma_command {
__u64 response_size;
};
+struct virtmagma_command_buffer {
+ __u64 command_buffer_size;
+ __u64 command_buffer;
+ __u64 resource_size;
+ __u64 resources;
+ __u64 semaphore_size;
+ __u64 semaphores;
+};
+
#define VIRTMAGMA_IOCTL_HANDSHAKE VIRTMAGMA_IOWR(0x00, struct virtmagma_ioctl_args_handshake)
#define VIRTMAGMA_IOCTL_GET_MMFD VIRTMAGMA_IOWR(0x01, struct virtmagma_ioctl_args_get_mmfd)
#define VIRTMAGMA_IOCTL_MAGMA_COMMAND VIRTMAGMA_IOWR(0x02, struct virtmagma_ioctl_args_magma_command)