yeahuh / rpms / qemu-kvm

Forked from rpms/qemu-kvm 2 years ago
Clone
76daa3
From 03c5ff306ec5657a91c17cee12ff710025921190 Mon Sep 17 00:00:00 2001
76daa3
From: Maxime Coquelin <maxime.coquelin@redhat.com>
76daa3
Date: Tue, 6 Jun 2017 12:05:24 +0200
76daa3
Subject: [PATCH 13/17] spec/vhost-user spec: Add IOMMU support
76daa3
76daa3
RH-Author: Maxime Coquelin <maxime.coquelin@redhat.com>
76daa3
Message-id: <20170606120524.3050-6-maxime.coquelin@redhat.com>
76daa3
Patchwork-id: 75498
76daa3
O-Subject: [RHV-7.4 qemu-kvm-rhev PATCH 5/5] spec/vhost-user spec: Add IOMMU support
76daa3
Bugzilla: 1451862
76daa3
RH-Acked-by: Peter Xu <peterx@redhat.com>
76daa3
RH-Acked-by: Xiao Wang <jasowang@redhat.com>
76daa3
RH-Acked-by: Jens Freimann <jfreiman@redhat.com>
76daa3
76daa3
This patch specifies and implements the master/slave communication
76daa3
to support device IOTLB in slave.
76daa3
76daa3
The vhost_iotlb_msg structure introduced for kernel backends is
76daa3
re-used, making the design close between the two backends.
76daa3
76daa3
An exception is the use of the secondary channel to enable the
76daa3
slave to send IOTLB miss requests to the master.
76daa3
76daa3
Signed-off-by: Maxime Coquelin <maxime.coquelin@redhat.com>
76daa3
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
76daa3
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
76daa3
(cherry picked from commit 6dcdd06e3b0d0c5651219013ec975348e2050041)
76daa3
Signed-off-by: Maxime Coquelin <maxime.coquelin@redhat.com>
76daa3
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
76daa3
---
76daa3
 docs/specs/vhost-user.txt | 84 +++++++++++++++++++++++++++++++++++++++++++++++
76daa3
 hw/net/vhost_net.c        |  1 +
76daa3
 hw/virtio/vhost-user.c    | 48 +++++++++++++++++++++++++--
76daa3
 3 files changed, 130 insertions(+), 3 deletions(-)
76daa3
76daa3
diff --git a/docs/specs/vhost-user.txt b/docs/specs/vhost-user.txt
76daa3
index 5fa7016..481ab56 100644
76daa3
--- a/docs/specs/vhost-user.txt
76daa3
+++ b/docs/specs/vhost-user.txt
76daa3
@@ -97,6 +97,25 @@ Depending on the request type, payload can be:
76daa3
    log offset: offset from start of supplied file descriptor
76daa3
        where logging starts (i.e. where guest address 0 would be logged)
76daa3
 
76daa3
+ * An IOTLB message
76daa3
+   ---------------------------------------------------------
76daa3
+   | iova | size | user address | permissions flags | type |
76daa3
+   ---------------------------------------------------------
76daa3
+
76daa3
+   IOVA: a 64-bit I/O virtual address programmed by the guest
76daa3
+   Size: a 64-bit size
76daa3
+   User address: a 64-bit user address
76daa3
+   Permissions: a 8-bit value:
76daa3
+    - 0: No access
76daa3
+    - 1: Read access
76daa3
+    - 2: Write access
76daa3
+    - 3: Read/Write access
76daa3
+   Type: a 8-bit IOTLB message type:
76daa3
+    - 1: IOTLB miss
76daa3
+    - 2: IOTLB update
76daa3
+    - 3: IOTLB invalidate
76daa3
+    - 4: IOTLB access fail
76daa3
+
76daa3
 In QEMU the vhost-user message is implemented with the following struct:
76daa3
 
76daa3
 typedef struct VhostUserMsg {
76daa3
@@ -109,6 +128,7 @@ typedef struct VhostUserMsg {
76daa3
         struct vhost_vring_addr addr;
76daa3
         VhostUserMemory memory;
76daa3
         VhostUserLog log;
76daa3
+        struct vhost_iotlb_msg iotlb;
76daa3
     };
76daa3
 } QEMU_PACKED VhostUserMsg;
76daa3
 
76daa3
@@ -253,6 +273,38 @@ Once the source has finished migration, rings will be stopped by
76daa3
 the source. No further update must be done before rings are
76daa3
 restarted.
76daa3
 
76daa3
+IOMMU support
76daa3
+-------------
76daa3
+
76daa3
+When the VIRTIO_F_IOMMU_PLATFORM feature has been negotiated, the master
76daa3
+sends IOTLB entries update & invalidation by sending VHOST_USER_IOTLB_MSG
76daa3
+requests to the slave with a struct vhost_iotlb_msg as payload. For update
76daa3
+events, the iotlb payload has to be filled with the update message type (2),
76daa3
+the I/O virtual address, the size, the user virtual address, and the
76daa3
+permissions flags. Addresses and size must be within vhost memory regions set
76daa3
+via the VHOST_USER_SET_MEM_TABLE request. For invalidation events, the iotlb
76daa3
+payload has to be filled with the invalidation message type (3), the I/O virtual
76daa3
+address and the size. On success, the slave is expected to reply with a zero
76daa3
+payload, non-zero otherwise.
76daa3
+
76daa3
+The slave relies on the slave communcation channel (see "Slave communication"
76daa3
+section below) to send IOTLB miss and access failure events, by sending
76daa3
+VHOST_USER_SLAVE_IOTLB_MSG requests to the master with a struct vhost_iotlb_msg
76daa3
+as payload. For miss events, the iotlb payload has to be filled with the miss
76daa3
+message type (1), the I/O virtual address and the permissions flags. For access
76daa3
+failure event, the iotlb payload has to be filled with the access failure
76daa3
+message type (4), the I/O virtual address and the permissions flags.
76daa3
+For synchronization purpose, the slave may rely on the reply-ack feature,
76daa3
+so the master may send a reply when operation is completed if the reply-ack
76daa3
+feature is negotiated and slaves requests a reply. For miss events, completed
76daa3
+operation means either master sent an update message containing the IOTLB entry
76daa3
+containing requested address and permission, or master sent nothing if the IOTLB
76daa3
+miss message is invalid (invalid IOVA or permission).
76daa3
+
76daa3
+The master isn't expected to take the initiative to send IOTLB update messages,
76daa3
+as the slave sends IOTLB miss messages for the guest virtual memory areas it
76daa3
+needs to access.
76daa3
+
76daa3
 Slave communication
76daa3
 -------------------
76daa3
 
76daa3
@@ -514,6 +566,38 @@ Master message types
76daa3
       If VHOST_USER_PROTOCOL_F_REPLY_ACK is negotiated, slave must respond
76daa3
       with zero for success, non-zero otherwise.
76daa3
 
76daa3
+ * VHOST_USER_IOTLB_MSG
76daa3
+
76daa3
+      Id: 22
76daa3
+      Equivalent ioctl: N/A (equivalent to VHOST_IOTLB_MSG message type)
76daa3
+      Master payload: struct vhost_iotlb_msg
76daa3
+      Slave payload: u64
76daa3
+
76daa3
+      Send IOTLB messages with struct vhost_iotlb_msg as payload.
76daa3
+      Master sends such requests to update and invalidate entries in the device
76daa3
+      IOTLB. The slave has to acknowledge the request with sending zero as u64
76daa3
+      payload for success, non-zero otherwise.
76daa3
+      This request should be send only when VIRTIO_F_IOMMU_PLATFORM feature
76daa3
+      has been successfully negotiated.
76daa3
+
76daa3
+Slave message types
76daa3
+-------------------
76daa3
+
76daa3
+ * VHOST_USER_SLAVE_IOTLB_MSG
76daa3
+
76daa3
+      Id: 1
76daa3
+      Equivalent ioctl: N/A (equivalent to VHOST_IOTLB_MSG message type)
76daa3
+      Slave payload: struct vhost_iotlb_msg
76daa3
+      Master payload: N/A
76daa3
+
76daa3
+      Send IOTLB messages with struct vhost_iotlb_msg as payload.
76daa3
+      Slave sends such requests to notify of an IOTLB miss, or an IOTLB
76daa3
+      access failure. If VHOST_USER_PROTOCOL_F_REPLY_ACK is negotiated,
76daa3
+      and slave set the VHOST_USER_NEED_REPLY flag, master must respond with
76daa3
+      zero when operation is successfully completed, or non-zero otherwise.
76daa3
+      This request should be send only when VIRTIO_F_IOMMU_PLATFORM feature
76daa3
+      has been successfully negotiated.
76daa3
+
76daa3
 VHOST_USER_PROTOCOL_F_REPLY_ACK:
76daa3
 -------------------------------
76daa3
 The original vhost-user specification only demands replies for certain
76daa3
diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c
76daa3
index 22874a9..e037db6 100644
76daa3
--- a/hw/net/vhost_net.c
76daa3
+++ b/hw/net/vhost_net.c
76daa3
@@ -77,6 +77,7 @@ static const int user_feature_bits[] = {
76daa3
     VIRTIO_NET_F_HOST_UFO,
76daa3
     VIRTIO_NET_F_MRG_RXBUF,
76daa3
     VIRTIO_NET_F_MTU,
76daa3
+    VIRTIO_F_IOMMU_PLATFORM,
76daa3
 
76daa3
     /* This bit implies RARP isn't sent by QEMU out of band */
76daa3
     VIRTIO_NET_F_GUEST_ANNOUNCE,
76daa3
diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c
76daa3
index 0faf5df..c44bbad 100644
76daa3
--- a/hw/virtio/vhost-user.c
76daa3
+++ b/hw/virtio/vhost-user.c
76daa3
@@ -63,11 +63,13 @@ typedef enum VhostUserRequest {
76daa3
     VHOST_USER_SEND_RARP = 19,
76daa3
     VHOST_USER_NET_SET_MTU = 20,
76daa3
     VHOST_USER_SET_SLAVE_REQ_FD = 21,
76daa3
+    VHOST_USER_IOTLB_MSG = 22,
76daa3
     VHOST_USER_MAX
76daa3
 } VhostUserRequest;
76daa3
 
76daa3
 typedef enum VhostUserSlaveRequest {
76daa3
     VHOST_USER_SLAVE_NONE = 0,
76daa3
+    VHOST_USER_SLAVE_IOTLB_MSG = 1,
76daa3
     VHOST_USER_SLAVE_MAX
76daa3
 }  VhostUserSlaveRequest;
76daa3
 
76daa3
@@ -105,6 +107,7 @@ typedef struct VhostUserMsg {
76daa3
         struct vhost_vring_addr addr;
76daa3
         VhostUserMemory memory;
76daa3
         VhostUserLog log;
76daa3
+        struct vhost_iotlb_msg iotlb;
76daa3
     } payload;
76daa3
 } QEMU_PACKED VhostUserMsg;
76daa3
 
76daa3
@@ -616,6 +619,9 @@ static void slave_read(void *opaque)
76daa3
     }
76daa3
 
76daa3
     switch (msg.request) {
76daa3
+    case VHOST_USER_SLAVE_IOTLB_MSG:
76daa3
+        ret = vhost_backend_handle_iotlb_msg(dev, &msg.payload.iotlb);
76daa3
+        break;
76daa3
     default:
76daa3
         error_report("Received unexpected msg type.");
76daa3
         ret = -EINVAL;
76daa3
@@ -698,7 +704,7 @@ out:
76daa3
 
76daa3
 static int vhost_user_init(struct vhost_dev *dev, void *opaque)
76daa3
 {
76daa3
-    uint64_t features;
76daa3
+    uint64_t features, protocol_features;
76daa3
     struct vhost_user *u;
76daa3
     int err;
76daa3
 
76daa3
@@ -718,12 +724,13 @@ static int vhost_user_init(struct vhost_dev *dev, void *opaque)
76daa3
         dev->backend_features |= 1ULL << VHOST_USER_F_PROTOCOL_FEATURES;
76daa3
 
76daa3
         err = vhost_user_get_u64(dev, VHOST_USER_GET_PROTOCOL_FEATURES,
76daa3
-                                 &features);
76daa3
+                                 &protocol_features);
76daa3
         if (err < 0) {
76daa3
             return err;
76daa3
         }
76daa3
 
76daa3
-        dev->protocol_features = features & VHOST_USER_PROTOCOL_FEATURE_MASK;
76daa3
+        dev->protocol_features =
76daa3
+            protocol_features & VHOST_USER_PROTOCOL_FEATURE_MASK;
76daa3
         err = vhost_user_set_protocol_features(dev, dev->protocol_features);
76daa3
         if (err < 0) {
76daa3
             return err;
76daa3
@@ -737,6 +744,16 @@ static int vhost_user_init(struct vhost_dev *dev, void *opaque)
76daa3
                 return err;
76daa3
             }
76daa3
         }
76daa3
+
76daa3
+        if (virtio_has_feature(features, VIRTIO_F_IOMMU_PLATFORM) &&
76daa3
+                !(virtio_has_feature(dev->protocol_features,
76daa3
+                    VHOST_USER_PROTOCOL_F_SLAVE_REQ) &&
76daa3
+                 virtio_has_feature(dev->protocol_features,
76daa3
+                    VHOST_USER_PROTOCOL_F_REPLY_ACK))) {
76daa3
+            error_report("IOMMU support requires reply-ack and "
76daa3
+                         "slave-req protocol features.");
76daa3
+            return -1;
76daa3
+        }
76daa3
     }
76daa3
 
76daa3
     if (dev->migration_blocker == NULL &&
76daa3
@@ -863,6 +880,29 @@ static int vhost_user_net_set_mtu(struct vhost_dev *dev, uint16_t mtu)
76daa3
     return 0;
76daa3
 }
76daa3
 
76daa3
+static int vhost_user_send_device_iotlb_msg(struct vhost_dev *dev,
76daa3
+                                            struct vhost_iotlb_msg *imsg)
76daa3
+{
76daa3
+    VhostUserMsg msg = {
76daa3
+        .request = VHOST_USER_IOTLB_MSG,
76daa3
+        .size = sizeof(msg.payload.iotlb),
76daa3
+        .flags = VHOST_USER_VERSION | VHOST_USER_NEED_REPLY_MASK,
76daa3
+        .payload.iotlb = *imsg,
76daa3
+    };
76daa3
+
76daa3
+    if (vhost_user_write(dev, &msg, NULL, 0) < 0) {
76daa3
+        return -EFAULT;
76daa3
+    }
76daa3
+
76daa3
+    return process_message_reply(dev, &msg;;
76daa3
+}
76daa3
+
76daa3
+
76daa3
+static void vhost_user_set_iotlb_callback(struct vhost_dev *dev, int enabled)
76daa3
+{
76daa3
+    /* No-op as the receive channel is not dedicated to IOTLB messages. */
76daa3
+}
76daa3
+
76daa3
 const VhostOps user_ops = {
76daa3
         .backend_type = VHOST_BACKEND_TYPE_USER,
76daa3
         .vhost_backend_init = vhost_user_init,
76daa3
@@ -887,4 +927,6 @@ const VhostOps user_ops = {
76daa3
         .vhost_migration_done = vhost_user_migration_done,
76daa3
         .vhost_backend_can_merge = vhost_user_can_merge,
76daa3
         .vhost_net_set_mtu = vhost_user_net_set_mtu,
76daa3
+        .vhost_set_iotlb_callback = vhost_user_set_iotlb_callback,
76daa3
+        .vhost_send_device_iotlb_msg = vhost_user_send_device_iotlb_msg,
76daa3
 };
76daa3
-- 
76daa3
1.8.3.1
76daa3