[virtio_magma][virtio_wl] Support for magma_import
Change-Id: I72b488d6302bfd65f375a9aec2d9bcd5ba4ec725
diff --git a/drivers/virtio/virtio_magma.c b/drivers/virtio/virtio_magma.c
index 7f49cb9..dc655cd 100644
--- a/drivers/virtio/virtio_magma.c
+++ b/drivers/virtio/virtio_magma.c
@@ -1508,8 +1508,11 @@
#if IS_ENABLED(CONFIG_VIRTIO_WL)
/* use the implementation in the virtio_wl module */
extern int virtwl_create_fd_for_vfd(void *filp_private_data, uint32_t vfd_id);
+extern int virtwl_get_vfd_from_fd(void *filp_private_data, int fd,
+ uint32_t *vfd_id);
#else
#define virtwl_create_fd_for_vfd(a, b) (-ENODEV)
+#define virtwl_get_vfd_from_fd(a, b, c) (-ENODEV)
#endif
static int
@@ -1554,6 +1557,77 @@
return 0;
}
+static int
+ virtmagma_command_magma_import(struct virtmagma_instance *instance,
+ struct virtmagma_virtio_command *command)
+{
+ int ret;
+ struct virtmagma_connection *connection;
+ struct virtio_magma_import_ctrl *request = command->request_ptr;
+ struct virtio_magma_import_resp *response = command->response_ptr;
+ uint32_t vfd;
+ uint64_t buffer_size;
+
+ if (!instance->wayland_device_private_data)
+ return -ENODEV;
+
+ if (!COMMAND_OK(command, request, response))
+ return -EINVAL;
+
+ connection = get_connection(instance, request->connection);
+ if (!connection)
+ return -EINVAL;
+
+ {
+ int fd = request->buffer_handle;
+ ret = virtwl_get_vfd_from_fd(
+ instance->wayland_device_private_data, fd, &vfd);
+ if (ret < 0) {
+ pr_err("virtmagma: failed to get vfd from fd %u", fd);
+ return ret;
+ }
+ }
+
+ request->buffer_handle = vfd;
+
+ ret = vq_out_send_sync(instance->vi, command);
+ if (ret)
+ return ret;
+
+ ret = virtmagma_check_expected_response_type(request, response);
+ if (ret)
+ return ret;
+
+ /* pass on magma errors without creating a vfd */
+ if (response->result_return) {
+ pr_warn("virtmagma: magma_import returned %d",
+ (int32_t)response->result_return);
+ return 0; /* the ioctl is still successful */
+ }
+
+ ret = get_buffer_size(instance, response->buffer_out, &buffer_size);
+ if (ret)
+ return ret;
+
+ {
+ struct virtmagma_connection_object *object =
+ kzalloc(sizeof(*object), GFP_KERNEL);
+ if (!object)
+ return -ENOMEM;
+
+ object->parent_connection = connection;
+ object->host_value = response->buffer_out;
+ object->type = MAGMA_BUFFER;
+ object->buffer.size_requested = buffer_size;
+ object->buffer.size_allocated = buffer_size;
+
+ hash_add(connection->objects, &object->node,
+ object->host_value);
+ }
+
+ return 0;
+}
+
static int virtmagma_command_magma_get_buffer_handle(
struct virtmagma_instance *instance,
struct virtmagma_virtio_command *command)
@@ -1733,6 +1807,9 @@
case VIRTIO_MAGMA_CMD_EXPORT:
ret = virtmagma_command_magma_export(instance, &command);
break;
+ case VIRTIO_MAGMA_CMD_IMPORT:
+ ret = virtmagma_command_magma_import(instance, &command);
+ break;
case VIRTIO_MAGMA_CMD_GET_BUFFER_HANDLE:
ret = virtmagma_command_magma_get_buffer_handle(instance,
&command);
diff --git a/drivers/virtio/virtio_wl.c b/drivers/virtio/virtio_wl.c
index 3ee6225..5fdf9b7c 100644
--- a/drivers/virtio/virtio_wl.c
+++ b/drivers/virtio/virtio_wl.c
@@ -946,6 +946,21 @@
virtwl_vfd_file_flags(vfd) | O_CLOEXEC);
}
+int virtwl_get_vfd_from_fd(void *filp_private_data, int fd, uint32_t* vfd_id_out) {
+ struct fd f = fdget(fd);
+
+ if (!f.file)
+ return -ENOENT;
+
+ {
+ struct virtwl_vfd *vfd = f.file->private_data;
+ *vfd_id_out = vfd->id;
+ }
+
+ fdput(f);
+ return 0;
+}
+
static int virtwl_open(struct inode *inodep, struct file *filp)
{
struct virtwl_info *vi = container_of(inodep->i_cdev,