/* Feature bits */
 #define VHOST_USER_F_PROTOCOL_FEATURES 30
 /* Protocol feature bits */
-#define VHOST_USER_PROTOCOL_F_CONFIG   9
+#define VHOST_USER_PROTOCOL_F_SLAVE_REQ                5
+#define VHOST_USER_PROTOCOL_F_CONFIG           9
 /* Vring state index masks */
 #define VHOST_USER_VRING_INDEX_MASK    0xff
 #define VHOST_USER_VRING_POLL_MASK     BIT(8)
 /* Supported transport features */
 #define VHOST_USER_SUPPORTED_F         BIT_ULL(VHOST_USER_F_PROTOCOL_FEATURES)
 /* Supported protocol features */
-#define VHOST_USER_SUPPORTED_PROTOCOL_F        BIT_ULL(VHOST_USER_PROTOCOL_F_CONFIG)
+#define VHOST_USER_SUPPORTED_PROTOCOL_F        (BIT_ULL(VHOST_USER_PROTOCOL_F_SLAVE_REQ) | \
+                                        BIT_ULL(VHOST_USER_PROTOCOL_F_CONFIG))
 
 enum vhost_user_request {
        VHOST_USER_GET_FEATURES = 1,
        VHOST_USER_SET_CONFIG = 25,
 };
 
+enum vhost_user_slave_request {
+       VHOST_USER_SLAVE_IOTLB_MSG = 1,
+       VHOST_USER_SLAVE_CONFIG_CHANGE_MSG = 2,
+       VHOST_USER_SLAVE_VRING_HOST_NOTIFIER_MSG = 3,
+};
+
 struct vhost_user_header {
-       u32 request; /* Use enum vhost_user_request */
+       /*
+        * Use enum vhost_user_request for outgoing messages,
+        * uses enum vhost_user_slave_request for incoming ones.
+        */
+       u32 request;
        u32 flags;
        u32 size;
 } __packed;
 
        struct virtio_device vdev;
        struct platform_device *pdev;
 
-       int sock;
+       int sock, req_fd;
        u64 features;
        u64 protocol_features;
        u8 status;
        return 0;
 }
 
-static int vhost_user_recv_header(struct virtio_uml_device *vu_dev,
-                                 struct vhost_user_msg *msg)
+static int vhost_user_recv_header(int fd, struct vhost_user_msg *msg)
 {
-       size_t size = sizeof(msg->header);
-       int rc;
-
-       rc = full_read(vu_dev->sock, (void *) msg, size);
-       if (rc)
-               return rc;
-       if (msg->header.flags != (VHOST_USER_FLAG_REPLY | VHOST_USER_VERSION))
-               return -EPROTO;
-       return 0;
+       return full_read(fd, msg, sizeof(msg->header));
 }
 
-static int vhost_user_recv(struct virtio_uml_device *vu_dev,
-                          struct vhost_user_msg *msg,
+static int vhost_user_recv(int fd, struct vhost_user_msg *msg,
                           size_t max_payload_size)
 {
        size_t size;
-       int rc = vhost_user_recv_header(vu_dev, msg);
+       int rc = vhost_user_recv_header(fd, msg);
 
        if (rc)
                return rc;
        size = msg->header.size;
        if (size > max_payload_size)
                return -EPROTO;
-       return full_read(vu_dev->sock, (void *) &msg->payload, size);
+       return full_read(fd, &msg->payload, size);
+}
+
+static int vhost_user_recv_resp(struct virtio_uml_device *vu_dev,
+                               struct vhost_user_msg *msg,
+                               size_t max_payload_size)
+{
+       int rc = vhost_user_recv(vu_dev->sock, msg, max_payload_size);
+
+       if (rc)
+               return rc;
+
+       if (msg->header.flags != (VHOST_USER_FLAG_REPLY | VHOST_USER_VERSION))
+               return -EPROTO;
+
+       return 0;
 }
 
 static int vhost_user_recv_u64(struct virtio_uml_device *vu_dev,
                               u64 *value)
 {
        struct vhost_user_msg msg;
-       int rc = vhost_user_recv(vu_dev, &msg, sizeof(msg.payload.integer));
+       int rc = vhost_user_recv_resp(vu_dev, &msg,
+                                     sizeof(msg.payload.integer));
 
        if (rc)
                return rc;
        return 0;
 }
 
+static int vhost_user_recv_req(struct virtio_uml_device *vu_dev,
+                              struct vhost_user_msg *msg,
+                              size_t max_payload_size)
+{
+       int rc = vhost_user_recv(vu_dev->req_fd, msg, max_payload_size);
+
+       if (rc)
+               return rc;
+
+       if (msg->header.flags != VHOST_USER_VERSION)
+               return -EPROTO;
+
+       return 0;
+}
+
 static int vhost_user_send(struct virtio_uml_device *vu_dev,
                           struct vhost_user_msg *msg,
                           int *fds, size_t num_fds)
        return vhost_user_send(vu_dev, &msg, NULL, 0);
 }
 
+static int vhost_user_send_no_payload_fd(struct virtio_uml_device *vu_dev,
+                                        u32 request, int fd)
+{
+       struct vhost_user_msg msg = {
+               .header.request = request,
+       };
+
+       return vhost_user_send(vu_dev, &msg, &fd, 1);
+}
+
 static int vhost_user_send_u64(struct virtio_uml_device *vu_dev,
                               u32 request, u64 value)
 {
                                   protocol_features);
 }
 
+static irqreturn_t vu_req_interrupt(int irq, void *data)
+{
+       struct virtio_uml_device *vu_dev = data;
+       struct {
+               struct vhost_user_msg msg;
+               u8 extra_payload[512];
+       } msg;
+       int rc;
+
+       rc = vhost_user_recv_req(vu_dev, &msg.msg,
+                                sizeof(msg.msg.payload) +
+                                sizeof(msg.extra_payload));
+
+       if (rc)
+               return IRQ_NONE;
+
+       switch (msg.msg.header.request) {
+       case VHOST_USER_SLAVE_CONFIG_CHANGE_MSG:
+               virtio_config_changed(&vu_dev->vdev);
+               break;
+       case VHOST_USER_SLAVE_IOTLB_MSG:
+               /* not supported - VIRTIO_F_IOMMU_PLATFORM */
+       case VHOST_USER_SLAVE_VRING_HOST_NOTIFIER_MSG:
+               /* not supported - VHOST_USER_PROTOCOL_F_HOST_NOTIFIER */
+       default:
+               vu_err(vu_dev, "unexpected slave request %d\n",
+                      msg.msg.header.request);
+       }
+
+       return IRQ_HANDLED;
+}
+
+static int vhost_user_init_slave_req(struct virtio_uml_device *vu_dev)
+{
+       int rc, req_fds[2];
+
+       /* Use a pipe for slave req fd, SIGIO is not supported for eventfd */
+       rc = os_pipe(req_fds, true, true);
+       if (rc < 0)
+               return rc;
+       vu_dev->req_fd = req_fds[0];
+
+       rc = um_request_irq(VIRTIO_IRQ, vu_dev->req_fd, IRQ_READ,
+                           vu_req_interrupt, IRQF_SHARED,
+                           vu_dev->pdev->name, vu_dev);
+       if (rc)
+               goto err_close;
+
+       rc = vhost_user_send_no_payload_fd(vu_dev, VHOST_USER_SET_SLAVE_REQ_FD,
+                                          req_fds[1]);
+       if (rc)
+               goto err_free_irq;
+
+       goto out;
+
+err_free_irq:
+       um_free_irq(VIRTIO_IRQ, vu_dev);
+err_close:
+       os_close_file(req_fds[0]);
+out:
+       /* Close unused write end of request fds */
+       os_close_file(req_fds[1]);
+       return rc;
+}
+
 static int vhost_user_init(struct virtio_uml_device *vu_dev)
 {
        int rc = vhost_user_set_owner(vu_dev);
                vu_dev->protocol_features &= VHOST_USER_SUPPORTED_PROTOCOL_F;
                rc = vhost_user_set_protocol_features(vu_dev,
                                vu_dev->protocol_features);
+               if (rc)
+                       return rc;
        }
-       return rc;
+
+       if (vu_dev->protocol_features &
+                       BIT_ULL(VHOST_USER_PROTOCOL_F_SLAVE_REQ)) {
+               rc = vhost_user_init_slave_req(vu_dev);
+               if (rc)
+                       return rc;
+       }
+
+       return 0;
 }
 
 static void vhost_user_get_config(struct virtio_uml_device *vu_dev,
                goto free;
        }
 
-       rc = vhost_user_recv(vu_dev, msg, msg_size);
+       rc = vhost_user_recv_resp(vu_dev, msg, msg_size);
        if (rc) {
                vu_err(vu_dev,
                       "receiving VHOST_USER_GET_CONFIG response failed: %d\n",
        .bus_name = vu_bus_name,
 };
 
-
 static void virtio_uml_release_dev(struct device *d)
 {
        struct virtio_device *vdev =
                        container_of(d, struct virtio_device, dev);
        struct virtio_uml_device *vu_dev = to_virtio_uml_device(vdev);
 
+       /* might not have been opened due to not negotiating the feature */
+       if (vu_dev->req_fd >= 0) {
+               um_free_irq(VIRTIO_IRQ, vu_dev);
+               os_close_file(vu_dev->req_fd);
+       }
+
        os_close_file(vu_dev->sock);
 }
 
        vu_dev->vdev.id.device = pdata->virtio_device_id;
        vu_dev->vdev.id.vendor = VIRTIO_DEV_ANY_ID;
        vu_dev->pdev = pdev;
+       vu_dev->req_fd = -1;
 
        do {
                rc = os_connect_socket(pdata->socket_path);