xref: /qemu/hw/virtio/vhost-backend.c (revision 9b1d929adb24bc4e613447c0fcc70479154e488f)
11a1bfac9SNikolay Nikolaev /*
21a1bfac9SNikolay Nikolaev  * vhost-backend
31a1bfac9SNikolay Nikolaev  *
41a1bfac9SNikolay Nikolaev  * Copyright (c) 2013 Virtual Open Systems Sarl.
51a1bfac9SNikolay Nikolaev  *
61a1bfac9SNikolay Nikolaev  * This work is licensed under the terms of the GNU GPL, version 2 or later.
71a1bfac9SNikolay Nikolaev  * See the COPYING file in the top-level directory.
81a1bfac9SNikolay Nikolaev  *
91a1bfac9SNikolay Nikolaev  */
101a1bfac9SNikolay Nikolaev 
119b8bfe21SPeter Maydell #include "qemu/osdep.h"
121a1bfac9SNikolay Nikolaev #include "hw/virtio/vhost.h"
131a1bfac9SNikolay Nikolaev #include "hw/virtio/vhost-backend.h"
141a1bfac9SNikolay Nikolaev #include "qemu/error-report.h"
15db725815SMarkus Armbruster #include "qemu/main-loop.h"
1618658a3cSPaolo Bonzini #include "standard-headers/linux/vhost_types.h"
1718658a3cSPaolo Bonzini 
18108a6481SCindy Lu #include "hw/virtio/vhost-vdpa.h"
19299e6f19SPaolo Bonzini #ifdef CONFIG_VHOST_KERNEL
2018658a3cSPaolo Bonzini #include <linux/vhost.h>
2118658a3cSPaolo Bonzini #include <sys/ioctl.h>
221a1bfac9SNikolay Nikolaev 
231a1bfac9SNikolay Nikolaev static int vhost_kernel_call(struct vhost_dev *dev, unsigned long int request,
241a1bfac9SNikolay Nikolaev                              void *arg)
251a1bfac9SNikolay Nikolaev {
261a1bfac9SNikolay Nikolaev     int fd = (uintptr_t) dev->opaque;
27f2a6e6c4SKevin Wolf     int ret;
281a1bfac9SNikolay Nikolaev 
291a1bfac9SNikolay Nikolaev     assert(dev->vhost_ops->backend_type == VHOST_BACKEND_TYPE_KERNEL);
301a1bfac9SNikolay Nikolaev 
31f2a6e6c4SKevin Wolf     ret = ioctl(fd, request, arg);
32f2a6e6c4SKevin Wolf     return ret < 0 ? -errno : ret;
331a1bfac9SNikolay Nikolaev }
341a1bfac9SNikolay Nikolaev 
3528770ff9SKevin Wolf static int vhost_kernel_init(struct vhost_dev *dev, void *opaque, Error **errp)
361a1bfac9SNikolay Nikolaev {
371a1bfac9SNikolay Nikolaev     assert(dev->vhost_ops->backend_type == VHOST_BACKEND_TYPE_KERNEL);
381a1bfac9SNikolay Nikolaev 
391a1bfac9SNikolay Nikolaev     dev->opaque = opaque;
401a1bfac9SNikolay Nikolaev 
411a1bfac9SNikolay Nikolaev     return 0;
421a1bfac9SNikolay Nikolaev }
431a1bfac9SNikolay Nikolaev 
441a1bfac9SNikolay Nikolaev static int vhost_kernel_cleanup(struct vhost_dev *dev)
451a1bfac9SNikolay Nikolaev {
461a1bfac9SNikolay Nikolaev     int fd = (uintptr_t) dev->opaque;
471a1bfac9SNikolay Nikolaev 
481a1bfac9SNikolay Nikolaev     assert(dev->vhost_ops->backend_type == VHOST_BACKEND_TYPE_KERNEL);
491a1bfac9SNikolay Nikolaev 
501a1bfac9SNikolay Nikolaev     return close(fd);
511a1bfac9SNikolay Nikolaev }
521a1bfac9SNikolay Nikolaev 
532ce68e4cSIgor Mammedov static int vhost_kernel_memslots_limit(struct vhost_dev *dev)
542ce68e4cSIgor Mammedov {
552ce68e4cSIgor Mammedov     int limit = 64;
562ce68e4cSIgor Mammedov     char *s;
572ce68e4cSIgor Mammedov 
582ce68e4cSIgor Mammedov     if (g_file_get_contents("/sys/module/vhost/parameters/max_mem_regions",
592ce68e4cSIgor Mammedov                             &s, NULL, NULL)) {
602ce68e4cSIgor Mammedov         uint64_t val = g_ascii_strtoull(s, NULL, 10);
612ce68e4cSIgor Mammedov         if (!((val == G_MAXUINT64 || !val) && errno)) {
6208b9e0baSPeng Hao             g_free(s);
632ce68e4cSIgor Mammedov             return val;
642ce68e4cSIgor Mammedov         }
652ce68e4cSIgor Mammedov         error_report("ignoring invalid max_mem_regions value in vhost module:"
662ce68e4cSIgor Mammedov                      " %s", s);
672ce68e4cSIgor Mammedov     }
6808b9e0baSPeng Hao     g_free(s);
692ce68e4cSIgor Mammedov     return limit;
702ce68e4cSIgor Mammedov }
712ce68e4cSIgor Mammedov 
7221e70425SMarc-André Lureau static int vhost_kernel_net_set_backend(struct vhost_dev *dev,
7321e70425SMarc-André Lureau                                         struct vhost_vring_file *file)
7421e70425SMarc-André Lureau {
7521e70425SMarc-André Lureau     return vhost_kernel_call(dev, VHOST_NET_SET_BACKEND, file);
7621e70425SMarc-André Lureau }
7721e70425SMarc-André Lureau 
7821e70425SMarc-André Lureau static int vhost_kernel_scsi_set_endpoint(struct vhost_dev *dev,
7921e70425SMarc-André Lureau                                           struct vhost_scsi_target *target)
8021e70425SMarc-André Lureau {
8121e70425SMarc-André Lureau     return vhost_kernel_call(dev, VHOST_SCSI_SET_ENDPOINT, target);
8221e70425SMarc-André Lureau }
8321e70425SMarc-André Lureau 
8421e70425SMarc-André Lureau static int vhost_kernel_scsi_clear_endpoint(struct vhost_dev *dev,
8521e70425SMarc-André Lureau                                             struct vhost_scsi_target *target)
8621e70425SMarc-André Lureau {
8721e70425SMarc-André Lureau     return vhost_kernel_call(dev, VHOST_SCSI_CLEAR_ENDPOINT, target);
8821e70425SMarc-André Lureau }
8921e70425SMarc-André Lureau 
9021e70425SMarc-André Lureau static int vhost_kernel_scsi_get_abi_version(struct vhost_dev *dev, int *version)
9121e70425SMarc-André Lureau {
9221e70425SMarc-André Lureau     return vhost_kernel_call(dev, VHOST_SCSI_GET_ABI_VERSION, version);
9321e70425SMarc-André Lureau }
9421e70425SMarc-André Lureau 
9521e70425SMarc-André Lureau static int vhost_kernel_set_log_base(struct vhost_dev *dev, uint64_t base,
969a78a5ddSMarc-André Lureau                                      struct vhost_log *log)
97c2bea314SMarc-André Lureau {
98c2bea314SMarc-André Lureau     return vhost_kernel_call(dev, VHOST_SET_LOG_BASE, &base);
99c2bea314SMarc-André Lureau }
100c2bea314SMarc-André Lureau 
10121e70425SMarc-André Lureau static int vhost_kernel_set_mem_table(struct vhost_dev *dev,
10221e70425SMarc-André Lureau                                       struct vhost_memory *mem)
10321e70425SMarc-André Lureau {
10421e70425SMarc-André Lureau     return vhost_kernel_call(dev, VHOST_SET_MEM_TABLE, mem);
10521e70425SMarc-André Lureau }
10621e70425SMarc-André Lureau 
10721e70425SMarc-André Lureau static int vhost_kernel_set_vring_addr(struct vhost_dev *dev,
10821e70425SMarc-André Lureau                                        struct vhost_vring_addr *addr)
10921e70425SMarc-André Lureau {
11021e70425SMarc-André Lureau     return vhost_kernel_call(dev, VHOST_SET_VRING_ADDR, addr);
11121e70425SMarc-André Lureau }
11221e70425SMarc-André Lureau 
11321e70425SMarc-André Lureau static int vhost_kernel_set_vring_endian(struct vhost_dev *dev,
11421e70425SMarc-André Lureau                                          struct vhost_vring_state *ring)
11521e70425SMarc-André Lureau {
11621e70425SMarc-André Lureau     return vhost_kernel_call(dev, VHOST_SET_VRING_ENDIAN, ring);
11721e70425SMarc-André Lureau }
11821e70425SMarc-André Lureau 
11921e70425SMarc-André Lureau static int vhost_kernel_set_vring_num(struct vhost_dev *dev,
12021e70425SMarc-André Lureau                                       struct vhost_vring_state *ring)
12121e70425SMarc-André Lureau {
12221e70425SMarc-André Lureau     return vhost_kernel_call(dev, VHOST_SET_VRING_NUM, ring);
12321e70425SMarc-André Lureau }
12421e70425SMarc-André Lureau 
12521e70425SMarc-André Lureau static int vhost_kernel_set_vring_base(struct vhost_dev *dev,
12621e70425SMarc-André Lureau                                        struct vhost_vring_state *ring)
12721e70425SMarc-André Lureau {
12821e70425SMarc-André Lureau     return vhost_kernel_call(dev, VHOST_SET_VRING_BASE, ring);
12921e70425SMarc-André Lureau }
13021e70425SMarc-André Lureau 
13121e70425SMarc-André Lureau static int vhost_kernel_get_vring_base(struct vhost_dev *dev,
13221e70425SMarc-André Lureau                                        struct vhost_vring_state *ring)
13321e70425SMarc-André Lureau {
13421e70425SMarc-André Lureau     return vhost_kernel_call(dev, VHOST_GET_VRING_BASE, ring);
13521e70425SMarc-André Lureau }
13621e70425SMarc-André Lureau 
13721e70425SMarc-André Lureau static int vhost_kernel_set_vring_kick(struct vhost_dev *dev,
13821e70425SMarc-André Lureau                                        struct vhost_vring_file *file)
13921e70425SMarc-André Lureau {
14021e70425SMarc-André Lureau     return vhost_kernel_call(dev, VHOST_SET_VRING_KICK, file);
14121e70425SMarc-André Lureau }
14221e70425SMarc-André Lureau 
14321e70425SMarc-André Lureau static int vhost_kernel_set_vring_call(struct vhost_dev *dev,
14421e70425SMarc-André Lureau                                        struct vhost_vring_file *file)
14521e70425SMarc-André Lureau {
14621e70425SMarc-André Lureau     return vhost_kernel_call(dev, VHOST_SET_VRING_CALL, file);
14721e70425SMarc-André Lureau }
14821e70425SMarc-André Lureau 
14969e87b32SJason Wang static int vhost_kernel_set_vring_busyloop_timeout(struct vhost_dev *dev,
15069e87b32SJason Wang                                                    struct vhost_vring_state *s)
15169e87b32SJason Wang {
15269e87b32SJason Wang     return vhost_kernel_call(dev, VHOST_SET_VRING_BUSYLOOP_TIMEOUT, s);
15369e87b32SJason Wang }
15469e87b32SJason Wang 
15521e70425SMarc-André Lureau static int vhost_kernel_set_features(struct vhost_dev *dev,
15621e70425SMarc-André Lureau                                      uint64_t features)
15721e70425SMarc-André Lureau {
15821e70425SMarc-André Lureau     return vhost_kernel_call(dev, VHOST_SET_FEATURES, &features);
15921e70425SMarc-André Lureau }
16021e70425SMarc-André Lureau 
161b37556edSJason Wang static int vhost_kernel_set_backend_cap(struct vhost_dev *dev)
162b37556edSJason Wang {
163b37556edSJason Wang     uint64_t features;
164b37556edSJason Wang     uint64_t f = 0x1ULL << VHOST_BACKEND_F_IOTLB_MSG_V2;
165b37556edSJason Wang     int r;
166b37556edSJason Wang 
167b37556edSJason Wang     if (vhost_kernel_call(dev, VHOST_GET_BACKEND_FEATURES, &features)) {
168b37556edSJason Wang         return 0;
169b37556edSJason Wang     }
170b37556edSJason Wang 
171b37556edSJason Wang     features &= f;
172b37556edSJason Wang     r = vhost_kernel_call(dev, VHOST_SET_BACKEND_FEATURES,
173b37556edSJason Wang                               &features);
174b37556edSJason Wang     if (r) {
175b37556edSJason Wang         return 0;
176b37556edSJason Wang     }
177b37556edSJason Wang 
178b37556edSJason Wang     dev->backend_cap = features;
179b37556edSJason Wang 
180b37556edSJason Wang     return 0;
181b37556edSJason Wang }
182b37556edSJason Wang 
18321e70425SMarc-André Lureau static int vhost_kernel_get_features(struct vhost_dev *dev,
18421e70425SMarc-André Lureau                                      uint64_t *features)
18521e70425SMarc-André Lureau {
18621e70425SMarc-André Lureau     return vhost_kernel_call(dev, VHOST_GET_FEATURES, features);
18721e70425SMarc-André Lureau }
18821e70425SMarc-André Lureau 
18921e70425SMarc-André Lureau static int vhost_kernel_set_owner(struct vhost_dev *dev)
19021e70425SMarc-André Lureau {
19121e70425SMarc-André Lureau     return vhost_kernel_call(dev, VHOST_SET_OWNER, NULL);
19221e70425SMarc-André Lureau }
19321e70425SMarc-André Lureau 
19421e70425SMarc-André Lureau static int vhost_kernel_reset_device(struct vhost_dev *dev)
19521e70425SMarc-André Lureau {
19660915dc4SYuanhan Liu     return vhost_kernel_call(dev, VHOST_RESET_OWNER, NULL);
19721e70425SMarc-André Lureau }
19821e70425SMarc-André Lureau 
19921e70425SMarc-André Lureau static int vhost_kernel_get_vq_index(struct vhost_dev *dev, int idx)
20021e70425SMarc-André Lureau {
20121e70425SMarc-André Lureau     assert(idx >= dev->vq_index && idx < dev->vq_index + dev->nvqs);
20221e70425SMarc-André Lureau 
20321e70425SMarc-André Lureau     return idx - dev->vq_index;
20421e70425SMarc-André Lureau }
20521e70425SMarc-André Lureau 
206fc0b9b0eSStefan Hajnoczi #ifdef CONFIG_VHOST_VSOCK
207fc0b9b0eSStefan Hajnoczi static int vhost_kernel_vsock_set_guest_cid(struct vhost_dev *dev,
208fc0b9b0eSStefan Hajnoczi                                             uint64_t guest_cid)
209fc0b9b0eSStefan Hajnoczi {
210fc0b9b0eSStefan Hajnoczi     return vhost_kernel_call(dev, VHOST_VSOCK_SET_GUEST_CID, &guest_cid);
211fc0b9b0eSStefan Hajnoczi }
212fc0b9b0eSStefan Hajnoczi 
213fc0b9b0eSStefan Hajnoczi static int vhost_kernel_vsock_set_running(struct vhost_dev *dev, int start)
214fc0b9b0eSStefan Hajnoczi {
215fc0b9b0eSStefan Hajnoczi     return vhost_kernel_call(dev, VHOST_VSOCK_SET_RUNNING, &start);
216fc0b9b0eSStefan Hajnoczi }
217fc0b9b0eSStefan Hajnoczi #endif /* CONFIG_VHOST_VSOCK */
218fc0b9b0eSStefan Hajnoczi 
219c471ad0eSJason Wang static void vhost_kernel_iotlb_read(void *opaque)
220c471ad0eSJason Wang {
221c471ad0eSJason Wang     struct vhost_dev *dev = opaque;
222c471ad0eSJason Wang     ssize_t len;
223c471ad0eSJason Wang 
224b37556edSJason Wang     if (dev->backend_cap &
225b37556edSJason Wang         (0x1ULL << VHOST_BACKEND_F_IOTLB_MSG_V2)) {
226b37556edSJason Wang         struct vhost_msg_v2 msg;
227b37556edSJason Wang 
228b37556edSJason Wang         while ((len = read((uintptr_t)dev->opaque, &msg, sizeof msg)) > 0) {
229b37556edSJason Wang             if (len < sizeof msg) {
230b37556edSJason Wang                 error_report("Wrong vhost message len: %d", (int)len);
231b37556edSJason Wang                 break;
232b37556edSJason Wang             }
233b37556edSJason Wang             if (msg.type != VHOST_IOTLB_MSG_V2) {
234b37556edSJason Wang                 error_report("Unknown vhost iotlb message type");
235b37556edSJason Wang                 break;
236b37556edSJason Wang             }
237b37556edSJason Wang 
238b37556edSJason Wang             vhost_backend_handle_iotlb_msg(dev, &msg.iotlb);
239b37556edSJason Wang         }
240b37556edSJason Wang     } else {
241b37556edSJason Wang         struct vhost_msg msg;
242b37556edSJason Wang 
243c471ad0eSJason Wang         while ((len = read((uintptr_t)dev->opaque, &msg, sizeof msg)) > 0) {
244c471ad0eSJason Wang             if (len < sizeof msg) {
245c471ad0eSJason Wang                 error_report("Wrong vhost message len: %d", (int)len);
246c471ad0eSJason Wang                 break;
247c471ad0eSJason Wang             }
248c471ad0eSJason Wang             if (msg.type != VHOST_IOTLB_MSG) {
249c471ad0eSJason Wang                 error_report("Unknown vhost iotlb message type");
250c471ad0eSJason Wang                 break;
251c471ad0eSJason Wang             }
252020e571bSMaxime Coquelin 
253020e571bSMaxime Coquelin             vhost_backend_handle_iotlb_msg(dev, &msg.iotlb);
254c471ad0eSJason Wang         }
255c471ad0eSJason Wang     }
256b37556edSJason Wang }
257c471ad0eSJason Wang 
258020e571bSMaxime Coquelin static int vhost_kernel_send_device_iotlb_msg(struct vhost_dev *dev,
259020e571bSMaxime Coquelin                                               struct vhost_iotlb_msg *imsg)
260c471ad0eSJason Wang {
261b37556edSJason Wang     if (dev->backend_cap & (1ULL << VHOST_BACKEND_F_IOTLB_MSG_V2)) {
2628faf2f1dSPhilippe Mathieu-Daudé         struct vhost_msg_v2 msg = {};
263b37556edSJason Wang 
264b37556edSJason Wang         msg.type = VHOST_IOTLB_MSG_V2;
265b37556edSJason Wang         msg.iotlb = *imsg;
266b37556edSJason Wang 
267b37556edSJason Wang         if (write((uintptr_t)dev->opaque, &msg, sizeof msg) != sizeof msg) {
268b37556edSJason Wang             error_report("Fail to update device iotlb");
269b37556edSJason Wang             return -EFAULT;
270b37556edSJason Wang         }
271b37556edSJason Wang     } else {
2728faf2f1dSPhilippe Mathieu-Daudé         struct vhost_msg msg = {};
273c471ad0eSJason Wang 
274020e571bSMaxime Coquelin         msg.type = VHOST_IOTLB_MSG;
275020e571bSMaxime Coquelin         msg.iotlb = *imsg;
276c471ad0eSJason Wang 
277c471ad0eSJason Wang         if (write((uintptr_t)dev->opaque, &msg, sizeof msg) != sizeof msg) {
278c471ad0eSJason Wang             error_report("Fail to update device iotlb");
279c471ad0eSJason Wang             return -EFAULT;
280c471ad0eSJason Wang         }
281b37556edSJason Wang     }
282c471ad0eSJason Wang 
283c471ad0eSJason Wang     return 0;
284c471ad0eSJason Wang }
285c471ad0eSJason Wang 
286c471ad0eSJason Wang static void vhost_kernel_set_iotlb_callback(struct vhost_dev *dev,
287c471ad0eSJason Wang                                            int enabled)
288c471ad0eSJason Wang {
289c471ad0eSJason Wang     if (enabled)
290c471ad0eSJason Wang         qemu_set_fd_handler((uintptr_t)dev->opaque,
291c471ad0eSJason Wang                             vhost_kernel_iotlb_read, NULL, dev);
292c471ad0eSJason Wang     else
293c471ad0eSJason Wang         qemu_set_fd_handler((uintptr_t)dev->opaque, NULL, NULL, NULL);
294c471ad0eSJason Wang }
295c471ad0eSJason Wang 
296*9b1d929aSTiberiu Georgescu const VhostOps kernel_ops = {
2971a1bfac9SNikolay Nikolaev         .backend_type = VHOST_BACKEND_TYPE_KERNEL,
2981a1bfac9SNikolay Nikolaev         .vhost_backend_init = vhost_kernel_init,
299fc57fd99SYuanhan Liu         .vhost_backend_cleanup = vhost_kernel_cleanup,
3002ce68e4cSIgor Mammedov         .vhost_backend_memslots_limit = vhost_kernel_memslots_limit,
30121e70425SMarc-André Lureau         .vhost_net_set_backend = vhost_kernel_net_set_backend,
30221e70425SMarc-André Lureau         .vhost_scsi_set_endpoint = vhost_kernel_scsi_set_endpoint,
30321e70425SMarc-André Lureau         .vhost_scsi_clear_endpoint = vhost_kernel_scsi_clear_endpoint,
30421e70425SMarc-André Lureau         .vhost_scsi_get_abi_version = vhost_kernel_scsi_get_abi_version,
30521e70425SMarc-André Lureau         .vhost_set_log_base = vhost_kernel_set_log_base,
30621e70425SMarc-André Lureau         .vhost_set_mem_table = vhost_kernel_set_mem_table,
30721e70425SMarc-André Lureau         .vhost_set_vring_addr = vhost_kernel_set_vring_addr,
30821e70425SMarc-André Lureau         .vhost_set_vring_endian = vhost_kernel_set_vring_endian,
30921e70425SMarc-André Lureau         .vhost_set_vring_num = vhost_kernel_set_vring_num,
31021e70425SMarc-André Lureau         .vhost_set_vring_base = vhost_kernel_set_vring_base,
31121e70425SMarc-André Lureau         .vhost_get_vring_base = vhost_kernel_get_vring_base,
31221e70425SMarc-André Lureau         .vhost_set_vring_kick = vhost_kernel_set_vring_kick,
31321e70425SMarc-André Lureau         .vhost_set_vring_call = vhost_kernel_set_vring_call,
31469e87b32SJason Wang         .vhost_set_vring_busyloop_timeout =
31569e87b32SJason Wang                                 vhost_kernel_set_vring_busyloop_timeout,
31621e70425SMarc-André Lureau         .vhost_set_features = vhost_kernel_set_features,
31721e70425SMarc-André Lureau         .vhost_get_features = vhost_kernel_get_features,
318b37556edSJason Wang         .vhost_set_backend_cap = vhost_kernel_set_backend_cap,
31921e70425SMarc-André Lureau         .vhost_set_owner = vhost_kernel_set_owner,
32021e70425SMarc-André Lureau         .vhost_reset_device = vhost_kernel_reset_device,
32121e70425SMarc-André Lureau         .vhost_get_vq_index = vhost_kernel_get_vq_index,
322fc0b9b0eSStefan Hajnoczi #ifdef CONFIG_VHOST_VSOCK
323fc0b9b0eSStefan Hajnoczi         .vhost_vsock_set_guest_cid = vhost_kernel_vsock_set_guest_cid,
324fc0b9b0eSStefan Hajnoczi         .vhost_vsock_set_running = vhost_kernel_vsock_set_running,
325fc0b9b0eSStefan Hajnoczi #endif /* CONFIG_VHOST_VSOCK */
326c471ad0eSJason Wang         .vhost_set_iotlb_callback = vhost_kernel_set_iotlb_callback,
327020e571bSMaxime Coquelin         .vhost_send_device_iotlb_msg = vhost_kernel_send_device_iotlb_msg,
3281a1bfac9SNikolay Nikolaev };
32918658a3cSPaolo Bonzini #endif
3301a1bfac9SNikolay Nikolaev 
331020e571bSMaxime Coquelin int vhost_backend_update_device_iotlb(struct vhost_dev *dev,
332020e571bSMaxime Coquelin                                              uint64_t iova, uint64_t uaddr,
333020e571bSMaxime Coquelin                                              uint64_t len,
334020e571bSMaxime Coquelin                                              IOMMUAccessFlags perm)
335020e571bSMaxime Coquelin {
336020e571bSMaxime Coquelin     struct vhost_iotlb_msg imsg;
337020e571bSMaxime Coquelin 
338020e571bSMaxime Coquelin     imsg.iova =  iova;
339020e571bSMaxime Coquelin     imsg.uaddr = uaddr;
340020e571bSMaxime Coquelin     imsg.size = len;
341020e571bSMaxime Coquelin     imsg.type = VHOST_IOTLB_UPDATE;
342020e571bSMaxime Coquelin 
343020e571bSMaxime Coquelin     switch (perm) {
344020e571bSMaxime Coquelin     case IOMMU_RO:
345020e571bSMaxime Coquelin         imsg.perm = VHOST_ACCESS_RO;
346020e571bSMaxime Coquelin         break;
347020e571bSMaxime Coquelin     case IOMMU_WO:
348020e571bSMaxime Coquelin         imsg.perm = VHOST_ACCESS_WO;
349020e571bSMaxime Coquelin         break;
350020e571bSMaxime Coquelin     case IOMMU_RW:
351020e571bSMaxime Coquelin         imsg.perm = VHOST_ACCESS_RW;
352020e571bSMaxime Coquelin         break;
353020e571bSMaxime Coquelin     default:
354020e571bSMaxime Coquelin         return -EINVAL;
355020e571bSMaxime Coquelin     }
356020e571bSMaxime Coquelin 
357384b557dSMaxime Coquelin     if (dev->vhost_ops && dev->vhost_ops->vhost_send_device_iotlb_msg)
358020e571bSMaxime Coquelin         return dev->vhost_ops->vhost_send_device_iotlb_msg(dev, &imsg);
359384b557dSMaxime Coquelin 
360384b557dSMaxime Coquelin     return -ENODEV;
361020e571bSMaxime Coquelin }
362020e571bSMaxime Coquelin 
363020e571bSMaxime Coquelin int vhost_backend_invalidate_device_iotlb(struct vhost_dev *dev,
364020e571bSMaxime Coquelin                                                  uint64_t iova, uint64_t len)
365020e571bSMaxime Coquelin {
366020e571bSMaxime Coquelin     struct vhost_iotlb_msg imsg;
367020e571bSMaxime Coquelin 
368020e571bSMaxime Coquelin     imsg.iova = iova;
369020e571bSMaxime Coquelin     imsg.size = len;
370020e571bSMaxime Coquelin     imsg.type = VHOST_IOTLB_INVALIDATE;
371020e571bSMaxime Coquelin 
372384b557dSMaxime Coquelin     if (dev->vhost_ops && dev->vhost_ops->vhost_send_device_iotlb_msg)
373020e571bSMaxime Coquelin         return dev->vhost_ops->vhost_send_device_iotlb_msg(dev, &imsg);
374384b557dSMaxime Coquelin 
375384b557dSMaxime Coquelin     return -ENODEV;
376020e571bSMaxime Coquelin }
377020e571bSMaxime Coquelin 
378020e571bSMaxime Coquelin int vhost_backend_handle_iotlb_msg(struct vhost_dev *dev,
379020e571bSMaxime Coquelin                                           struct vhost_iotlb_msg *imsg)
380020e571bSMaxime Coquelin {
381020e571bSMaxime Coquelin     int ret = 0;
382020e571bSMaxime Coquelin 
3834d1ccc17SEugenio Pérez     if (unlikely(!dev->vdev)) {
3844d1ccc17SEugenio Pérez         error_report("Unexpected IOTLB message when virtio device is stopped");
3854d1ccc17SEugenio Pérez         return -EINVAL;
3864d1ccc17SEugenio Pérez     }
3874d1ccc17SEugenio Pérez 
388020e571bSMaxime Coquelin     switch (imsg->type) {
389020e571bSMaxime Coquelin     case VHOST_IOTLB_MISS:
390020e571bSMaxime Coquelin         ret = vhost_device_iotlb_miss(dev, imsg->iova,
391020e571bSMaxime Coquelin                                       imsg->perm != VHOST_ACCESS_RO);
392020e571bSMaxime Coquelin         break;
393020e571bSMaxime Coquelin     case VHOST_IOTLB_ACCESS_FAIL:
394020e571bSMaxime Coquelin         /* FIXME: report device iotlb error */
395020e571bSMaxime Coquelin         error_report("Access failure IOTLB message type not supported");
396020e571bSMaxime Coquelin         ret = -ENOTSUP;
397020e571bSMaxime Coquelin         break;
398020e571bSMaxime Coquelin     case VHOST_IOTLB_UPDATE:
399020e571bSMaxime Coquelin     case VHOST_IOTLB_INVALIDATE:
400020e571bSMaxime Coquelin     default:
401020e571bSMaxime Coquelin         error_report("Unexpected IOTLB message type");
402020e571bSMaxime Coquelin         ret = -EINVAL;
403020e571bSMaxime Coquelin         break;
404020e571bSMaxime Coquelin     }
405020e571bSMaxime Coquelin 
406020e571bSMaxime Coquelin     return ret;
407020e571bSMaxime Coquelin }
408