[virtio_magma] Add semaphore import and export

Partial implementation that doesn't satisfy Vulkan
requirements for external semaphore, but is still
useful for benchmarking.  Tracking completion with
fxbug.dev/67565.

Change-Id: I7fbbfded3c18ec94ce413ea435e4e8468099275e
diff --git a/drivers/virtio/virtio_magma.c b/drivers/virtio/virtio_magma.c
index e8f4f45..7a9cfa4 100644
--- a/drivers/virtio/virtio_magma.c
+++ b/drivers/virtio/virtio_magma.c
@@ -1100,6 +1100,89 @@
 	return 0;
 }
 
+static int virtmagma_command_magma_import_semaphore(
+	struct virtmagma_instance *instance,
+	struct virtmagma_virtio_command *command)
+{
+	int ret;
+	struct virtmagma_connection *connection;
+	struct virtmagma_connection_object *object;
+	struct virtio_magma_import_semaphore_ctrl *request =
+		command->request_ptr;
+	struct virtio_magma_import_semaphore_resp *response =
+		command->response_ptr;
+
+	if (!COMMAND_OK(command, request, response))
+		return -EINVAL;
+
+	connection = get_connection(instance, request->connection);
+	if (!connection)
+		return -EINVAL;
+
+	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 semaphore object */
+	if (response->result_return) {
+		pr_warn("virtmagma: magma_import_semaphore returned %d",
+			(int32_t)response->result_return);
+		return 0; /* the ioctl is still successful */
+	}
+
+	object = kzalloc(sizeof(*object), GFP_KERNEL);
+	if (!object)
+		return -ENOMEM;
+
+	object->parent_connection = connection;
+	object->host_value = response->semaphore_out;
+	object->type = MAGMA_SEMAPHORE;
+
+	hash_add(connection->objects, &object->node, object->host_value);
+
+	return 0;
+}
+
+static int virtmagma_command_magma_export_semaphore(
+	struct virtmagma_instance *instance,
+	struct virtmagma_virtio_command *command)
+{
+	int ret;
+	struct virtmagma_connection *connection;
+	struct virtmagma_connection_object *object;
+	struct virtio_magma_export_semaphore_ctrl *request =
+		command->request_ptr;
+	struct virtio_magma_export_semaphore_resp *response =
+		command->response_ptr;
+	struct virtmagma_semaphore_fd_priv *priv;
+
+	if (!COMMAND_OK(command, request, response))
+		return -EINVAL;
+
+	connection = get_connection(instance, request->connection);
+	if (!connection)
+		return -EINVAL;
+
+	ret = vq_out_send_sync(instance->vi, command);
+	if (ret)
+		return ret;
+
+	ret = virtmagma_check_expected_response_type(request, response);
+	if (ret)
+		return ret;
+
+	/* TODO(fxbug.dev/67565):
+	 * Create an anon file here that points to the zircon handle, return
+	 * the fd to userspace.  For now we return the zircon handle itself.
+	 */
+
+	return 0;
+}
+
 static int
 	virtmagma_command_magma_poll(struct virtmagma_instance *instance,
 				     struct virtmagma_virtio_command *command)
@@ -1441,6 +1524,14 @@
 		ret = virtmagma_command_magma_release_semaphore(instance,
 								&command);
 		break;
+	case VIRTIO_MAGMA_CMD_IMPORT_SEMAPHORE:
+		ret = virtmagma_command_magma_import_semaphore(instance,
+							       &command);
+		break;
+	case VIRTIO_MAGMA_CMD_EXPORT_SEMAPHORE:
+		ret = virtmagma_command_magma_export_semaphore(instance,
+							       &command);
+		break;
 	case VIRTIO_MAGMA_CMD_POLL:
 		ret = virtmagma_command_magma_poll(instance, &command);
 		break;