From nobody Tue Dec 16 05:36:39 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=intel.com Return-Path: Received: from lists.gnu.org (208.118.235.17 [208.118.235.17]) by mx.zohomail.com with SMTPS id 1527158160291524.1588608632645; Thu, 24 May 2018 03:36:00 -0700 (PDT) Received: from localhost ([::1]:37668 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fLnb2-0004k7-Kd for importer@patchew.org; Thu, 24 May 2018 06:35:48 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:38415) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fLnYn-0003Sg-Pj for qemu-devel@nongnu.org; Thu, 24 May 2018 06:33:31 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fLnYm-00054d-CA for qemu-devel@nongnu.org; Thu, 24 May 2018 06:33:29 -0400 Received: from mga17.intel.com ([192.55.52.151]:6501) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fLnYm-00053t-1R for qemu-devel@nongnu.org; Thu, 24 May 2018 06:33:28 -0400 Received: from orsmga002.jf.intel.com ([10.7.209.21]) by fmsmga107.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 24 May 2018 03:33:27 -0700 Received: from debian.sh.intel.com ([10.67.104.203]) by orsmga002.jf.intel.com with ESMTP; 24 May 2018 03:33:26 -0700 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.49,436,1520924400"; d="scan'208";a="61316262" From: Tiwei Bie To: mst@redhat.com, jasowang@redhat.com, qemu-devel@nongnu.org, virtio-dev@lists.oasis-open.org Date: Thu, 24 May 2018 18:33:34 +0800 Message-Id: <20180524103336.21233-5-tiwei.bie@intel.com> X-Mailer: git-send-email 2.17.0 In-Reply-To: <20180524103336.21233-1-tiwei.bie@intel.com> References: <20180524103336.21233-1-tiwei.bie@intel.com> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 192.55.52.151 Subject: [Qemu-devel] [PATCH 4/6] vhost-user: support registering external host notifiers X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: tiwei.bie@intel.com Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" This patch introduces VHOST_USER_PROTOCOL_F_HOST_NOTIFIER. With this feature negotiated, vhost-user backend can register memory region based host notifiers. And it will allow the guest driver in the VM to notify the hardware accelerator at the vhost-user backend directly. Signed-off-by: Tiwei Bie --- docs/interop/vhost-user.txt | 33 ++++++++++ hw/virtio/vhost-user.c | 113 +++++++++++++++++++++++++++++++++ include/hw/virtio/vhost-user.h | 8 +++ 3 files changed, 154 insertions(+) diff --git a/docs/interop/vhost-user.txt b/docs/interop/vhost-user.txt index 682a683eb4..d51fd58242 100644 --- a/docs/interop/vhost-user.txt +++ b/docs/interop/vhost-user.txt @@ -132,6 +132,16 @@ Depending on the request type, payload can be: Payload: Size bytes array holding the contents of the virtio device's configuration space =20 + * Vring area description + ----------------------- + | u64 | size | offset | + ----------------------- + + u64: a 64-bit integer contains vring index and flags + Size: a 64-bit size of this area + Offset: a 64-bit offset of this area from the start of the + supplied file descriptor + In QEMU the vhost-user message is implemented with the following struct: =20 typedef struct VhostUserMsg { @@ -146,6 +156,7 @@ typedef struct VhostUserMsg { VhostUserLog log; struct vhost_iotlb_msg iotlb; VhostUserConfig config; + VhostUserVringArea area; }; } QEMU_PACKED VhostUserMsg; =20 @@ -385,6 +396,7 @@ Protocol features #define VHOST_USER_PROTOCOL_F_PAGEFAULT 8 #define VHOST_USER_PROTOCOL_F_CONFIG 9 #define VHOST_USER_PROTOCOL_F_SLAVE_SEND_FD 10 +#define VHOST_USER_PROTOCOL_F_HOST_NOTIFIER 11 =20 Master message types -------------------- @@ -782,6 +794,27 @@ Slave message types the VHOST_USER_NEED_REPLY flag, master must respond with zero when operation is successfully completed, or non-zero otherwise. =20 + * VHOST_USER_SLAVE_VRING_HOST_NOTIFIER_MSG + + Id: 3 + Equivalent ioctl: N/A + Slave payload: vring area description + Master payload: N/A + + Sets host notifier for a specified queue. The queue index is contain= ed + in the u64 field of the vring area description. The host notifier is + described by the file descriptor (typically it's a VFIO device fd) w= hich + is passed as ancillary data and the size (which is mmap size and sho= uld + be the same as host page size) and offset (which is mmap offset) car= ried + in the vring area description. QEMU can mmap the file descriptor bas= ed + on the size and offset to get a memory range. Registering a host not= ifier + means mapping this memory range to the VM as the specified queue's n= otify + MMIO region. Slave sends this request to tell QEMU to de-register the + existing notifier if any and register the new notifier if the reques= t is + sent with a file descriptor. + This request should be sent only when VHOST_USER_PROTOCOL_F_HOST_NOT= IFIER + protocol feature has been successfully negotiated. + VHOST_USER_PROTOCOL_F_REPLY_ACK: ------------------------------- The original vhost-user specification only demands replies for certain diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c index 70b9610c87..b041343632 100644 --- a/hw/virtio/vhost-user.c +++ b/hw/virtio/vhost-user.c @@ -13,6 +13,7 @@ #include "hw/virtio/vhost.h" #include "hw/virtio/vhost-user.h" #include "hw/virtio/vhost-backend.h" +#include "hw/virtio/virtio.h" #include "hw/virtio/virtio-net.h" #include "chardev/char-fe.h" #include "sysemu/kvm.h" @@ -50,6 +51,7 @@ enum VhostUserProtocolFeature { VHOST_USER_PROTOCOL_F_PAGEFAULT =3D 8, VHOST_USER_PROTOCOL_F_CONFIG =3D 9, VHOST_USER_PROTOCOL_F_SLAVE_SEND_FD =3D 10, + VHOST_USER_PROTOCOL_F_HOST_NOTIFIER =3D 11, VHOST_USER_PROTOCOL_F_MAX }; =20 @@ -94,6 +96,7 @@ typedef enum VhostUserSlaveRequest { VHOST_USER_SLAVE_NONE =3D 0, VHOST_USER_SLAVE_IOTLB_MSG =3D 1, VHOST_USER_SLAVE_CONFIG_CHANGE_MSG =3D 2, + VHOST_USER_SLAVE_VRING_HOST_NOTIFIER_MSG =3D 3, VHOST_USER_SLAVE_MAX } VhostUserSlaveRequest; =20 @@ -138,6 +141,12 @@ static VhostUserConfig c __attribute__ ((unused)); + sizeof(c.size) \ + sizeof(c.flags)) =20 +typedef struct VhostUserVringArea { + uint64_t u64; + uint64_t size; + uint64_t offset; +} VhostUserVringArea; + typedef struct { VhostUserRequest request; =20 @@ -159,6 +168,7 @@ typedef union { struct vhost_iotlb_msg iotlb; VhostUserConfig config; VhostUserCryptoSession session; + VhostUserVringArea area; } VhostUserPayload; =20 typedef struct VhostUserMsg { @@ -640,9 +650,37 @@ static int vhost_user_set_vring_num(struct vhost_dev *= dev, return vhost_set_vring(dev, VHOST_USER_SET_VRING_NUM, ring); } =20 +static void vhost_user_host_notifier_restore(struct vhost_dev *dev, + int queue_idx) +{ + struct vhost_user *u =3D dev->opaque; + VhostUserHostNotifier *n =3D &u->user->notifier[queue_idx]; + VirtIODevice *vdev =3D dev->vdev; + + if (n->addr && !n->set) { + virtio_queue_set_host_notifier_mr(vdev, queue_idx, &n->mr, true); + n->set =3D true; + } +} + +static void vhost_user_host_notifier_remove(struct vhost_dev *dev, + int queue_idx) +{ + struct vhost_user *u =3D dev->opaque; + VhostUserHostNotifier *n =3D &u->user->notifier[queue_idx]; + VirtIODevice *vdev =3D dev->vdev; + + if (n->addr && n->set) { + virtio_queue_set_host_notifier_mr(vdev, queue_idx, &n->mr, false); + n->set =3D false; + } +} + static int vhost_user_set_vring_base(struct vhost_dev *dev, struct vhost_vring_state *ring) { + vhost_user_host_notifier_restore(dev, ring->index); + return vhost_set_vring(dev, VHOST_USER_SET_VRING_BASE, ring); } =20 @@ -676,6 +714,8 @@ static int vhost_user_get_vring_base(struct vhost_dev *= dev, .hdr.size =3D sizeof(msg.payload.state), }; =20 + vhost_user_host_notifier_remove(dev, ring->index); + if (vhost_user_write(dev, &msg, NULL, 0) < 0) { return -1; } @@ -849,6 +889,66 @@ static int vhost_user_slave_handle_config_change(struc= t vhost_dev *dev) return ret; } =20 +static int vhost_user_slave_handle_vring_host_notifier(struct vhost_dev *d= ev, + VhostUserVringArea = *area, + int fd) +{ + int queue_idx =3D area->u64 & VHOST_USER_VRING_IDX_MASK; + size_t page_size =3D qemu_real_host_page_size; + struct vhost_user *u =3D dev->opaque; + VhostUserState *user =3D u->user; + VirtIODevice *vdev =3D dev->vdev; + VhostUserHostNotifier *n; + void *addr; + char *name; + + if (!virtio_has_feature(dev->protocol_features, + VHOST_USER_PROTOCOL_F_HOST_NOTIFIER) || + vdev =3D=3D NULL || queue_idx >=3D virtio_get_num_queues(vdev)) { + return -1; + } + + n =3D &user->notifier[queue_idx]; + + if (n->addr) { + virtio_queue_set_host_notifier_mr(vdev, queue_idx, &n->mr, false); + object_unparent(OBJECT(&n->mr)); + munmap(n->addr, page_size); + n->addr =3D NULL; + } + + if (area->u64 & VHOST_USER_VRING_NOFD_MASK) { + return 0; + } + + /* Sanity check. */ + if (area->size !=3D page_size) { + return -1; + } + + addr =3D mmap(NULL, page_size, PROT_READ | PROT_WRITE, MAP_SHARED, + fd, area->offset); + if (addr =3D=3D MAP_FAILED) { + return -1; + } + + name =3D g_strdup_printf("vhost-user/host-notifier@%p mmaps[%d]", + user, queue_idx); + memory_region_init_ram_device_ptr(&n->mr, OBJECT(vdev), name, + page_size, addr); + g_free(name); + + if (virtio_queue_set_host_notifier_mr(vdev, queue_idx, &n->mr, true)) { + munmap(addr, page_size); + return -1; + } + + n->addr =3D addr; + n->set =3D true; + + return 0; +} + static void slave_read(void *opaque) { struct vhost_dev *dev =3D opaque; @@ -917,6 +1017,10 @@ static void slave_read(void *opaque) case VHOST_USER_SLAVE_CONFIG_CHANGE_MSG : ret =3D vhost_user_slave_handle_config_change(dev); break; + case VHOST_USER_SLAVE_VRING_HOST_NOTIFIER_MSG: + ret =3D vhost_user_slave_handle_vring_host_notifier(dev, &payload.= area, + fd[0]); + break; default: error_report("Received unexpected msg type."); ret =3D -EINVAL; @@ -1648,6 +1752,15 @@ VhostUserState *vhost_user_init(void) =20 void vhost_user_cleanup(VhostUserState *user) { + int i; + + for (i =3D 0; i < VIRTIO_QUEUE_MAX; i++) { + if (user->notifier[i].addr) { + object_unparent(OBJECT(&user->notifier[i].mr)); + munmap(user->notifier[i].addr, qemu_real_host_page_size); + user->notifier[i].addr =3D NULL; + } + } } =20 const VhostOps user_ops =3D { diff --git a/include/hw/virtio/vhost-user.h b/include/hw/virtio/vhost-user.h index eb8bc0d90d..fd660393a0 100644 --- a/include/hw/virtio/vhost-user.h +++ b/include/hw/virtio/vhost-user.h @@ -9,9 +9,17 @@ #define HW_VIRTIO_VHOST_USER_H =20 #include "chardev/char-fe.h" +#include "hw/virtio/virtio.h" + +typedef struct VhostUserHostNotifier { + MemoryRegion mr; + void *addr; + bool set; +} VhostUserHostNotifier; =20 typedef struct VhostUserState { CharBackend *chr; + VhostUserHostNotifier notifier[VIRTIO_QUEUE_MAX]; } VhostUserState; =20 VhostUserState *vhost_user_init(void); --=20 2.17.0