[virtio-magma] Add magma_read_notification_channel2
Change-Id: I07edfa0beefd32dd31dfa8f8524baea43c42027b
diff --git a/drivers/virtio/virtio_magma.c b/drivers/virtio/virtio_magma.c
index efa3e08..e8f4f45 100644
--- a/drivers/virtio/virtio_magma.c
+++ b/drivers/virtio/virtio_magma.c
@@ -1187,6 +1187,54 @@
response->buffer_size_out);
}
+static int virtmagma_command_magma_read_notification_channel2(
+ struct virtmagma_instance *instance,
+ struct virtmagma_virtio_command *command)
+{
+ int ret;
+ struct virtio_magma_read_notification_channel2_ctrl *request =
+ command->request_ptr;
+ struct virtio_magma_read_notification_channel2_resp *response =
+ command->response_ptr;
+
+ if (!COMMAND_OK(command, request, response))
+ return -EINVAL;
+
+ /* reallocate response buffer with additional space for notification data.
+ note that the size is not modified, as we only want the response struct
+ itself to be copied back to the user by our caller */
+
+ command->response_ptr = response =
+ kzalloc(sizeof(*response) + NOTIFICATION_MAX_BYTES, GFP_KERNEL);
+ if (!command->response_ptr)
+ return -ENOMEM;
+
+ 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 writing to the buffer */
+ if (response->result_return) {
+ pr_warn("virtmagma: magma_read_notification_channel2 returned %d",
+ (int32_t)response->result_return);
+ return 0; /* the ioctl is still successful */
+ }
+
+ if (response->buffer_size_out > request->buffer_size) {
+ pr_err("virtmagma: magma_read_notification_channel2 returned buffer_size_out (%lld) larger than buffer_size (%lld)",
+ response->buffer_size_out, request->buffer_size);
+ return -EIO;
+ }
+
+ return copy_to_user((void *)request->buffer,
+ (char *)command->response_ptr + sizeof(*response),
+ response->buffer_size_out);
+}
+
#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);
@@ -1400,6 +1448,10 @@
ret = virtmagma_command_magma_read_notification_channel(
instance, &command);
break;
+ case VIRTIO_MAGMA_CMD_READ_NOTIFICATION_CHANNEL2:
+ ret = virtmagma_command_magma_read_notification_channel2(
+ instance, &command);
+ break;
case VIRTIO_MAGMA_CMD_EXPORT:
ret = virtmagma_command_magma_export(instance, &command);
break;
diff --git a/include/uapi/linux/virtio_magma.h b/include/uapi/linux/virtio_magma.h
index aaf5e0e..3430b83 100644
--- a/include/uapi/linux/virtio_magma.h
+++ b/include/uapi/linux/virtio_magma.h
@@ -70,6 +70,7 @@
VIRTIO_MAGMA_CMD_BUFFER_RANGE_OP = 0x1041,
VIRTIO_MAGMA_CMD_BUFFER_GET_INFO = 0x1042,
VIRTIO_MAGMA_CMD_GET_BUFFER_HANDLE = 0x1043,
+ VIRTIO_MAGMA_CMD_READ_NOTIFICATION_CHANNEL2 = 0x1046,
VIRTIO_MAGMA_CMD_INTERNAL_MAP = 0x1044,
VIRTIO_MAGMA_CMD_INTERNAL_UNMAP = 0x1045,
/* magma success responses
@@ -123,6 +124,7 @@
VIRTIO_MAGMA_RESP_BUFFER_RANGE_OP = 0x2041,
VIRTIO_MAGMA_RESP_BUFFER_GET_INFO = 0x2042,
VIRTIO_MAGMA_RESP_GET_BUFFER_HANDLE = 0x2043,
+ VIRTIO_MAGMA_RESP_READ_NOTIFICATION_CHANNEL2 = 0x2046,
VIRTIO_MAGMA_RESP_INTERNAL_MAP = 0x2044,
VIRTIO_MAGMA_RESP_INTERNAL_UNMAP = 0x2045,
/* magma error responses
@@ -235,6 +237,8 @@
case VIRTIO_MAGMA_RESP_BUFFER_GET_INFO: return "VIRTIO_MAGMA_RESP_BUFFER_GET_INFO";
case VIRTIO_MAGMA_CMD_GET_BUFFER_HANDLE: return "VIRTIO_MAGMA_CMD_GET_BUFFER_HANDLE";
case VIRTIO_MAGMA_RESP_GET_BUFFER_HANDLE: return "VIRTIO_MAGMA_RESP_GET_BUFFER_HANDLE";
+ case VIRTIO_MAGMA_CMD_READ_NOTIFICATION_CHANNEL2: return "VIRTIO_MAGMA_CMD_READ_NOTIFICATION_CHANNEL2";
+ case VIRTIO_MAGMA_RESP_READ_NOTIFICATION_CHANNEL2: return "VIRTIO_MAGMA_RESP_READ_NOTIFICATION_CHANNEL2";
case VIRTIO_MAGMA_CMD_INTERNAL_MAP: return "VIRTIO_MAGMA_CMD_INTERNAL_MAP";
case VIRTIO_MAGMA_RESP_INTERNAL_MAP: return "VIRTIO_MAGMA_RESP_INTERNAL_MAP";
case VIRTIO_MAGMA_CMD_INTERNAL_UNMAP: return "VIRTIO_MAGMA_CMD_INTERNAL_UNMAP";
@@ -300,6 +304,7 @@
case VIRTIO_MAGMA_CMD_BUFFER_RANGE_OP: return VIRTIO_MAGMA_RESP_BUFFER_RANGE_OP;
case VIRTIO_MAGMA_CMD_BUFFER_GET_INFO: return VIRTIO_MAGMA_RESP_BUFFER_GET_INFO;
case VIRTIO_MAGMA_CMD_GET_BUFFER_HANDLE: return VIRTIO_MAGMA_RESP_GET_BUFFER_HANDLE;
+ case VIRTIO_MAGMA_CMD_READ_NOTIFICATION_CHANNEL2: return VIRTIO_MAGMA_RESP_READ_NOTIFICATION_CHANNEL2;
case VIRTIO_MAGMA_CMD_INTERNAL_MAP: return VIRTIO_MAGMA_RESP_INTERNAL_MAP;
case VIRTIO_MAGMA_CMD_INTERNAL_UNMAP: return VIRTIO_MAGMA_RESP_INTERNAL_UNMAP;
default: return VIRTIO_MAGMA_RESP_ERR_INVALID_COMMAND;
@@ -869,6 +874,20 @@
__le64 result_return;
} __attribute((packed));
+struct virtio_magma_read_notification_channel2_ctrl {
+ struct virtio_magma_ctrl_hdr hdr;
+ __le64 connection;
+ __le64 buffer;
+ __le64 buffer_size;
+} __attribute((packed));
+
+struct virtio_magma_read_notification_channel2_resp {
+ struct virtio_magma_ctrl_hdr hdr;
+ __le64 buffer_size_out;
+ __le64 more_data_out;
+ __le64 result_return;
+} __attribute((packed));
+
struct virtio_magma_internal_map_ctrl {
struct virtio_magma_ctrl_hdr hdr;
__le64 connection;