1108a6481SCindy Lu /* 2108a6481SCindy Lu * vhost-vdpa 3108a6481SCindy Lu * 4108a6481SCindy Lu * Copyright(c) 2017-2018 Intel Corporation. 5108a6481SCindy Lu * Copyright(c) 2020 Red Hat, Inc. 6108a6481SCindy Lu * 7108a6481SCindy Lu * This work is licensed under the terms of the GNU GPL, version 2 or later. 8108a6481SCindy Lu * See the COPYING file in the top-level directory. 9108a6481SCindy Lu * 10108a6481SCindy Lu */ 11108a6481SCindy Lu 12108a6481SCindy Lu #include "qemu/osdep.h" 13108a6481SCindy Lu #include <linux/vhost.h> 14108a6481SCindy Lu #include <linux/vfio.h> 15108a6481SCindy Lu #include <sys/eventfd.h> 16108a6481SCindy Lu #include <sys/ioctl.h> 17108a6481SCindy Lu #include "hw/virtio/vhost.h" 18108a6481SCindy Lu #include "hw/virtio/vhost-backend.h" 19108a6481SCindy Lu #include "hw/virtio/virtio-net.h" 20108a6481SCindy Lu #include "hw/virtio/vhost-vdpa.h" 21108a6481SCindy Lu #include "qemu/main-loop.h" 224dc5acc0SCindy Lu #include "cpu.h" 23778e67deSLaurent Vivier #include "trace.h" 24778e67deSLaurent Vivier #include "qemu-common.h" 25108a6481SCindy Lu 26108a6481SCindy Lu static bool vhost_vdpa_listener_skipped_section(MemoryRegionSection *section) 27108a6481SCindy Lu { 28108a6481SCindy Lu return (!memory_region_is_ram(section->mr) && 29108a6481SCindy Lu !memory_region_is_iommu(section->mr)) || 30108a6481SCindy Lu /* 31108a6481SCindy Lu * Sizing an enabled 64-bit BAR can cause spurious mappings to 32108a6481SCindy Lu * addresses in the upper part of the 64-bit address space. These 33108a6481SCindy Lu * are never accessed by the CPU and beyond the address width of 34108a6481SCindy Lu * some IOMMU hardware. TODO: VDPA should tell us the IOMMU width. 35108a6481SCindy Lu */ 36108a6481SCindy Lu section->offset_within_address_space & (1ULL << 63); 37108a6481SCindy Lu } 38108a6481SCindy Lu 39108a6481SCindy Lu static int vhost_vdpa_dma_map(struct vhost_vdpa *v, hwaddr iova, hwaddr size, 40108a6481SCindy Lu void *vaddr, bool readonly) 41108a6481SCindy Lu { 42386494f2SCindy Lu struct vhost_msg_v2 msg = {}; 43108a6481SCindy Lu int fd = v->device_fd; 44108a6481SCindy Lu int ret = 0; 45108a6481SCindy Lu 46108a6481SCindy Lu msg.type = v->msg_type; 47108a6481SCindy Lu msg.iotlb.iova = iova; 48108a6481SCindy Lu msg.iotlb.size = size; 49108a6481SCindy Lu msg.iotlb.uaddr = (uint64_t)(uintptr_t)vaddr; 50108a6481SCindy Lu msg.iotlb.perm = readonly ? VHOST_ACCESS_RO : VHOST_ACCESS_RW; 51108a6481SCindy Lu msg.iotlb.type = VHOST_IOTLB_UPDATE; 52108a6481SCindy Lu 53778e67deSLaurent Vivier trace_vhost_vdpa_dma_map(v, fd, msg.type, msg.iotlb.iova, msg.iotlb.size, 54778e67deSLaurent Vivier msg.iotlb.uaddr, msg.iotlb.perm, msg.iotlb.type); 55778e67deSLaurent Vivier 56108a6481SCindy Lu if (write(fd, &msg, sizeof(msg)) != sizeof(msg)) { 57108a6481SCindy Lu error_report("failed to write, fd=%d, errno=%d (%s)", 58108a6481SCindy Lu fd, errno, strerror(errno)); 59108a6481SCindy Lu return -EIO ; 60108a6481SCindy Lu } 61108a6481SCindy Lu 62108a6481SCindy Lu return ret; 63108a6481SCindy Lu } 64108a6481SCindy Lu 65108a6481SCindy Lu static int vhost_vdpa_dma_unmap(struct vhost_vdpa *v, hwaddr iova, 66108a6481SCindy Lu hwaddr size) 67108a6481SCindy Lu { 68386494f2SCindy Lu struct vhost_msg_v2 msg = {}; 69108a6481SCindy Lu int fd = v->device_fd; 70108a6481SCindy Lu int ret = 0; 71108a6481SCindy Lu 72108a6481SCindy Lu msg.type = v->msg_type; 73108a6481SCindy Lu msg.iotlb.iova = iova; 74108a6481SCindy Lu msg.iotlb.size = size; 75108a6481SCindy Lu msg.iotlb.type = VHOST_IOTLB_INVALIDATE; 76108a6481SCindy Lu 77778e67deSLaurent Vivier trace_vhost_vdpa_dma_unmap(v, fd, msg.type, msg.iotlb.iova, 78778e67deSLaurent Vivier msg.iotlb.size, msg.iotlb.type); 79778e67deSLaurent Vivier 80108a6481SCindy Lu if (write(fd, &msg, sizeof(msg)) != sizeof(msg)) { 81108a6481SCindy Lu error_report("failed to write, fd=%d, errno=%d (%s)", 82108a6481SCindy Lu fd, errno, strerror(errno)); 83108a6481SCindy Lu return -EIO ; 84108a6481SCindy Lu } 85108a6481SCindy Lu 86108a6481SCindy Lu return ret; 87108a6481SCindy Lu } 88108a6481SCindy Lu 89a5bd0580SJason Wang static void vhost_vdpa_listener_begin(MemoryListener *listener) 90a5bd0580SJason Wang { 91a5bd0580SJason Wang struct vhost_vdpa *v = container_of(listener, struct vhost_vdpa, listener); 92a5bd0580SJason Wang struct vhost_dev *dev = v->dev; 938acb3218SPhilippe Mathieu-Daudé struct vhost_msg_v2 msg = {}; 94a5bd0580SJason Wang int fd = v->device_fd; 95a5bd0580SJason Wang 96a5bd0580SJason Wang if (!(dev->backend_cap & (0x1ULL << VHOST_BACKEND_F_IOTLB_BATCH))) { 97a5bd0580SJason Wang return; 98a5bd0580SJason Wang } 99a5bd0580SJason Wang 100a5bd0580SJason Wang msg.type = v->msg_type; 101a5bd0580SJason Wang msg.iotlb.type = VHOST_IOTLB_BATCH_BEGIN; 102a5bd0580SJason Wang 103a5bd0580SJason Wang if (write(fd, &msg, sizeof(msg)) != sizeof(msg)) { 104a5bd0580SJason Wang error_report("failed to write, fd=%d, errno=%d (%s)", 105a5bd0580SJason Wang fd, errno, strerror(errno)); 106a5bd0580SJason Wang } 107a5bd0580SJason Wang } 108a5bd0580SJason Wang 109a5bd0580SJason Wang static void vhost_vdpa_listener_commit(MemoryListener *listener) 110a5bd0580SJason Wang { 111a5bd0580SJason Wang struct vhost_vdpa *v = container_of(listener, struct vhost_vdpa, listener); 112a5bd0580SJason Wang struct vhost_dev *dev = v->dev; 1138acb3218SPhilippe Mathieu-Daudé struct vhost_msg_v2 msg = {}; 114a5bd0580SJason Wang int fd = v->device_fd; 115a5bd0580SJason Wang 116a5bd0580SJason Wang if (!(dev->backend_cap & (0x1ULL << VHOST_BACKEND_F_IOTLB_BATCH))) { 117a5bd0580SJason Wang return; 118a5bd0580SJason Wang } 119a5bd0580SJason Wang 120a5bd0580SJason Wang msg.type = v->msg_type; 121a5bd0580SJason Wang msg.iotlb.type = VHOST_IOTLB_BATCH_END; 122a5bd0580SJason Wang 123a5bd0580SJason Wang if (write(fd, &msg, sizeof(msg)) != sizeof(msg)) { 124a5bd0580SJason Wang error_report("failed to write, fd=%d, errno=%d (%s)", 125a5bd0580SJason Wang fd, errno, strerror(errno)); 126a5bd0580SJason Wang } 127a5bd0580SJason Wang } 128a5bd0580SJason Wang 129108a6481SCindy Lu static void vhost_vdpa_listener_region_add(MemoryListener *listener, 130108a6481SCindy Lu MemoryRegionSection *section) 131108a6481SCindy Lu { 132108a6481SCindy Lu struct vhost_vdpa *v = container_of(listener, struct vhost_vdpa, listener); 133108a6481SCindy Lu hwaddr iova; 134108a6481SCindy Lu Int128 llend, llsize; 135108a6481SCindy Lu void *vaddr; 136108a6481SCindy Lu int ret; 137108a6481SCindy Lu 138108a6481SCindy Lu if (vhost_vdpa_listener_skipped_section(section)) { 139108a6481SCindy Lu return; 140108a6481SCindy Lu } 141108a6481SCindy Lu 142108a6481SCindy Lu if (unlikely((section->offset_within_address_space & ~TARGET_PAGE_MASK) != 143108a6481SCindy Lu (section->offset_within_region & ~TARGET_PAGE_MASK))) { 144108a6481SCindy Lu error_report("%s received unaligned region", __func__); 145108a6481SCindy Lu return; 146108a6481SCindy Lu } 147108a6481SCindy Lu 148108a6481SCindy Lu iova = TARGET_PAGE_ALIGN(section->offset_within_address_space); 149108a6481SCindy Lu llend = int128_make64(section->offset_within_address_space); 150108a6481SCindy Lu llend = int128_add(llend, section->size); 151108a6481SCindy Lu llend = int128_and(llend, int128_exts64(TARGET_PAGE_MASK)); 152108a6481SCindy Lu 153108a6481SCindy Lu if (int128_ge(int128_make64(iova), llend)) { 154108a6481SCindy Lu return; 155108a6481SCindy Lu } 156108a6481SCindy Lu 157108a6481SCindy Lu memory_region_ref(section->mr); 158108a6481SCindy Lu 159108a6481SCindy Lu /* Here we assume that memory_region_is_ram(section->mr)==true */ 160108a6481SCindy Lu 161108a6481SCindy Lu vaddr = memory_region_get_ram_ptr(section->mr) + 162108a6481SCindy Lu section->offset_within_region + 163108a6481SCindy Lu (iova - section->offset_within_address_space); 164108a6481SCindy Lu 165778e67deSLaurent Vivier trace_vhost_vdpa_listener_region_add(v, iova, int128_get64(llend), 166778e67deSLaurent Vivier vaddr, section->readonly); 167778e67deSLaurent Vivier 168108a6481SCindy Lu llsize = int128_sub(llend, int128_make64(iova)); 169108a6481SCindy Lu 170108a6481SCindy Lu ret = vhost_vdpa_dma_map(v, iova, int128_get64(llsize), 171108a6481SCindy Lu vaddr, section->readonly); 172108a6481SCindy Lu if (ret) { 173108a6481SCindy Lu error_report("vhost vdpa map fail!"); 174108a6481SCindy Lu if (memory_region_is_ram_device(section->mr)) { 175108a6481SCindy Lu /* Allow unexpected mappings not to be fatal for RAM devices */ 176108a6481SCindy Lu error_report("map ram fail!"); 177108a6481SCindy Lu return ; 178108a6481SCindy Lu } 179108a6481SCindy Lu goto fail; 180108a6481SCindy Lu } 181108a6481SCindy Lu 182108a6481SCindy Lu return; 183108a6481SCindy Lu 184108a6481SCindy Lu fail: 185108a6481SCindy Lu if (memory_region_is_ram_device(section->mr)) { 186108a6481SCindy Lu error_report("failed to vdpa_dma_map. pci p2p may not work"); 187108a6481SCindy Lu return; 188108a6481SCindy Lu 189108a6481SCindy Lu } 190108a6481SCindy Lu /* 191108a6481SCindy Lu * On the initfn path, store the first error in the container so we 192108a6481SCindy Lu * can gracefully fail. Runtime, there's not much we can do other 193108a6481SCindy Lu * than throw a hardware error. 194108a6481SCindy Lu */ 195108a6481SCindy Lu error_report("vhost-vdpa: DMA mapping failed, unable to continue"); 196108a6481SCindy Lu return; 197108a6481SCindy Lu 198108a6481SCindy Lu } 199108a6481SCindy Lu 200108a6481SCindy Lu static void vhost_vdpa_listener_region_del(MemoryListener *listener, 201108a6481SCindy Lu MemoryRegionSection *section) 202108a6481SCindy Lu { 203108a6481SCindy Lu struct vhost_vdpa *v = container_of(listener, struct vhost_vdpa, listener); 204108a6481SCindy Lu hwaddr iova; 205108a6481SCindy Lu Int128 llend, llsize; 206108a6481SCindy Lu int ret; 207108a6481SCindy Lu 208108a6481SCindy Lu if (vhost_vdpa_listener_skipped_section(section)) { 209108a6481SCindy Lu return; 210108a6481SCindy Lu } 211108a6481SCindy Lu 212108a6481SCindy Lu if (unlikely((section->offset_within_address_space & ~TARGET_PAGE_MASK) != 213108a6481SCindy Lu (section->offset_within_region & ~TARGET_PAGE_MASK))) { 214108a6481SCindy Lu error_report("%s received unaligned region", __func__); 215108a6481SCindy Lu return; 216108a6481SCindy Lu } 217108a6481SCindy Lu 218108a6481SCindy Lu iova = TARGET_PAGE_ALIGN(section->offset_within_address_space); 219108a6481SCindy Lu llend = int128_make64(section->offset_within_address_space); 220108a6481SCindy Lu llend = int128_add(llend, section->size); 221108a6481SCindy Lu llend = int128_and(llend, int128_exts64(TARGET_PAGE_MASK)); 222108a6481SCindy Lu 223778e67deSLaurent Vivier trace_vhost_vdpa_listener_region_del(v, iova, int128_get64(llend)); 224778e67deSLaurent Vivier 225108a6481SCindy Lu if (int128_ge(int128_make64(iova), llend)) { 226108a6481SCindy Lu return; 227108a6481SCindy Lu } 228108a6481SCindy Lu 229108a6481SCindy Lu llsize = int128_sub(llend, int128_make64(iova)); 230108a6481SCindy Lu 231108a6481SCindy Lu ret = vhost_vdpa_dma_unmap(v, iova, int128_get64(llsize)); 232108a6481SCindy Lu if (ret) { 233108a6481SCindy Lu error_report("vhost_vdpa dma unmap error!"); 234108a6481SCindy Lu } 235108a6481SCindy Lu 236108a6481SCindy Lu memory_region_unref(section->mr); 237108a6481SCindy Lu } 238108a6481SCindy Lu /* 239108a6481SCindy Lu * IOTLB API is used by vhost-vpda which requires incremental updating 240108a6481SCindy Lu * of the mapping. So we can not use generic vhost memory listener which 241108a6481SCindy Lu * depends on the addnop(). 242108a6481SCindy Lu */ 243108a6481SCindy Lu static const MemoryListener vhost_vdpa_memory_listener = { 244a5bd0580SJason Wang .begin = vhost_vdpa_listener_begin, 245a5bd0580SJason Wang .commit = vhost_vdpa_listener_commit, 246108a6481SCindy Lu .region_add = vhost_vdpa_listener_region_add, 247108a6481SCindy Lu .region_del = vhost_vdpa_listener_region_del, 248108a6481SCindy Lu }; 249108a6481SCindy Lu 250108a6481SCindy Lu static int vhost_vdpa_call(struct vhost_dev *dev, unsigned long int request, 251108a6481SCindy Lu void *arg) 252108a6481SCindy Lu { 253108a6481SCindy Lu struct vhost_vdpa *v = dev->opaque; 254108a6481SCindy Lu int fd = v->device_fd; 255108a6481SCindy Lu 256108a6481SCindy Lu assert(dev->vhost_ops->backend_type == VHOST_BACKEND_TYPE_VDPA); 257108a6481SCindy Lu 258108a6481SCindy Lu return ioctl(fd, request, arg); 259108a6481SCindy Lu } 260108a6481SCindy Lu 261108a6481SCindy Lu static void vhost_vdpa_add_status(struct vhost_dev *dev, uint8_t status) 262108a6481SCindy Lu { 263108a6481SCindy Lu uint8_t s; 264108a6481SCindy Lu 265778e67deSLaurent Vivier trace_vhost_vdpa_add_status(dev, status); 266108a6481SCindy Lu if (vhost_vdpa_call(dev, VHOST_VDPA_GET_STATUS, &s)) { 267108a6481SCindy Lu return; 268108a6481SCindy Lu } 269108a6481SCindy Lu 270108a6481SCindy Lu s |= status; 271108a6481SCindy Lu 272108a6481SCindy Lu vhost_vdpa_call(dev, VHOST_VDPA_SET_STATUS, &s); 273108a6481SCindy Lu } 274108a6481SCindy Lu 275108a6481SCindy Lu static int vhost_vdpa_init(struct vhost_dev *dev, void *opaque) 276108a6481SCindy Lu { 277108a6481SCindy Lu struct vhost_vdpa *v; 278108a6481SCindy Lu uint64_t features; 279108a6481SCindy Lu assert(dev->vhost_ops->backend_type == VHOST_BACKEND_TYPE_VDPA); 280778e67deSLaurent Vivier trace_vhost_vdpa_init(dev, opaque); 281108a6481SCindy Lu 282108a6481SCindy Lu v = opaque; 283a5bd0580SJason Wang v->dev = dev; 284108a6481SCindy Lu dev->opaque = opaque ; 285108a6481SCindy Lu vhost_vdpa_call(dev, VHOST_GET_FEATURES, &features); 286108a6481SCindy Lu dev->backend_features = features; 287108a6481SCindy Lu v->listener = vhost_vdpa_memory_listener; 288108a6481SCindy Lu v->msg_type = VHOST_IOTLB_MSG_V2; 289108a6481SCindy Lu 290108a6481SCindy Lu vhost_vdpa_add_status(dev, VIRTIO_CONFIG_S_ACKNOWLEDGE | 291108a6481SCindy Lu VIRTIO_CONFIG_S_DRIVER); 292108a6481SCindy Lu 293108a6481SCindy Lu return 0; 294108a6481SCindy Lu } 295108a6481SCindy Lu 296108a6481SCindy Lu static int vhost_vdpa_cleanup(struct vhost_dev *dev) 297108a6481SCindy Lu { 298108a6481SCindy Lu struct vhost_vdpa *v; 299108a6481SCindy Lu assert(dev->vhost_ops->backend_type == VHOST_BACKEND_TYPE_VDPA); 300108a6481SCindy Lu v = dev->opaque; 301778e67deSLaurent Vivier trace_vhost_vdpa_cleanup(dev, v); 302108a6481SCindy Lu memory_listener_unregister(&v->listener); 303108a6481SCindy Lu 304108a6481SCindy Lu dev->opaque = NULL; 305108a6481SCindy Lu return 0; 306108a6481SCindy Lu } 307108a6481SCindy Lu 308108a6481SCindy Lu static int vhost_vdpa_memslots_limit(struct vhost_dev *dev) 309108a6481SCindy Lu { 310778e67deSLaurent Vivier trace_vhost_vdpa_memslots_limit(dev, INT_MAX); 311108a6481SCindy Lu return INT_MAX; 312108a6481SCindy Lu } 313108a6481SCindy Lu 314108a6481SCindy Lu static int vhost_vdpa_set_mem_table(struct vhost_dev *dev, 315108a6481SCindy Lu struct vhost_memory *mem) 316108a6481SCindy Lu { 317778e67deSLaurent Vivier trace_vhost_vdpa_set_mem_table(dev, mem->nregions, mem->padding); 318778e67deSLaurent Vivier if (trace_event_get_state_backends(TRACE_VHOST_VDPA_SET_MEM_TABLE) && 319778e67deSLaurent Vivier trace_event_get_state_backends(TRACE_VHOST_VDPA_DUMP_REGIONS)) { 320778e67deSLaurent Vivier int i; 321778e67deSLaurent Vivier for (i = 0; i < mem->nregions; i++) { 322778e67deSLaurent Vivier trace_vhost_vdpa_dump_regions(dev, i, 323778e67deSLaurent Vivier mem->regions[i].guest_phys_addr, 324778e67deSLaurent Vivier mem->regions[i].memory_size, 325778e67deSLaurent Vivier mem->regions[i].userspace_addr, 326778e67deSLaurent Vivier mem->regions[i].flags_padding); 327778e67deSLaurent Vivier } 328778e67deSLaurent Vivier } 329108a6481SCindy Lu if (mem->padding) { 330108a6481SCindy Lu return -1; 331108a6481SCindy Lu } 332108a6481SCindy Lu 333108a6481SCindy Lu return 0; 334108a6481SCindy Lu } 335108a6481SCindy Lu 336108a6481SCindy Lu static int vhost_vdpa_set_features(struct vhost_dev *dev, 337108a6481SCindy Lu uint64_t features) 338108a6481SCindy Lu { 339108a6481SCindy Lu int ret; 340778e67deSLaurent Vivier trace_vhost_vdpa_set_features(dev, features); 341108a6481SCindy Lu ret = vhost_vdpa_call(dev, VHOST_SET_FEATURES, &features); 342108a6481SCindy Lu uint8_t status = 0; 343108a6481SCindy Lu if (ret) { 344108a6481SCindy Lu return ret; 345108a6481SCindy Lu } 346108a6481SCindy Lu vhost_vdpa_add_status(dev, VIRTIO_CONFIG_S_FEATURES_OK); 347108a6481SCindy Lu vhost_vdpa_call(dev, VHOST_VDPA_GET_STATUS, &status); 348108a6481SCindy Lu 349108a6481SCindy Lu return !(status & VIRTIO_CONFIG_S_FEATURES_OK); 350108a6481SCindy Lu } 351108a6481SCindy Lu 352a5bd0580SJason Wang static int vhost_vdpa_set_backend_cap(struct vhost_dev *dev) 353a5bd0580SJason Wang { 354a5bd0580SJason Wang uint64_t features; 355a5bd0580SJason Wang uint64_t f = 0x1ULL << VHOST_BACKEND_F_IOTLB_MSG_V2 | 356a5bd0580SJason Wang 0x1ULL << VHOST_BACKEND_F_IOTLB_BATCH; 357a5bd0580SJason Wang int r; 358a5bd0580SJason Wang 359a5bd0580SJason Wang if (vhost_vdpa_call(dev, VHOST_GET_BACKEND_FEATURES, &features)) { 360a5bd0580SJason Wang return 0; 361a5bd0580SJason Wang } 362a5bd0580SJason Wang 363a5bd0580SJason Wang features &= f; 364a5bd0580SJason Wang r = vhost_vdpa_call(dev, VHOST_SET_BACKEND_FEATURES, &features); 365a5bd0580SJason Wang if (r) { 366a5bd0580SJason Wang return 0; 367a5bd0580SJason Wang } 368a5bd0580SJason Wang 369a5bd0580SJason Wang dev->backend_cap = features; 370a5bd0580SJason Wang 371a5bd0580SJason Wang return 0; 372a5bd0580SJason Wang } 373a5bd0580SJason Wang 374*c232b8f4SZenghui Yu static int vhost_vdpa_get_device_id(struct vhost_dev *dev, 375108a6481SCindy Lu uint32_t *device_id) 376108a6481SCindy Lu { 377778e67deSLaurent Vivier int ret; 378778e67deSLaurent Vivier ret = vhost_vdpa_call(dev, VHOST_VDPA_GET_DEVICE_ID, device_id); 379778e67deSLaurent Vivier trace_vhost_vdpa_get_device_id(dev, *device_id); 380778e67deSLaurent Vivier return ret; 381108a6481SCindy Lu } 382108a6481SCindy Lu 383108a6481SCindy Lu static int vhost_vdpa_reset_device(struct vhost_dev *dev) 384108a6481SCindy Lu { 385778e67deSLaurent Vivier int ret; 386108a6481SCindy Lu uint8_t status = 0; 387108a6481SCindy Lu 388778e67deSLaurent Vivier ret = vhost_vdpa_call(dev, VHOST_VDPA_SET_STATUS, &status); 389778e67deSLaurent Vivier trace_vhost_vdpa_reset_device(dev, status); 390778e67deSLaurent Vivier return ret; 391108a6481SCindy Lu } 392108a6481SCindy Lu 393108a6481SCindy Lu static int vhost_vdpa_get_vq_index(struct vhost_dev *dev, int idx) 394108a6481SCindy Lu { 395108a6481SCindy Lu assert(idx >= dev->vq_index && idx < dev->vq_index + dev->nvqs); 396108a6481SCindy Lu 397778e67deSLaurent Vivier trace_vhost_vdpa_get_vq_index(dev, idx, idx - dev->vq_index); 398108a6481SCindy Lu return idx - dev->vq_index; 399108a6481SCindy Lu } 400108a6481SCindy Lu 401108a6481SCindy Lu static int vhost_vdpa_set_vring_ready(struct vhost_dev *dev) 402108a6481SCindy Lu { 403108a6481SCindy Lu int i; 404778e67deSLaurent Vivier trace_vhost_vdpa_set_vring_ready(dev); 405108a6481SCindy Lu for (i = 0; i < dev->nvqs; ++i) { 406108a6481SCindy Lu struct vhost_vring_state state = { 407108a6481SCindy Lu .index = dev->vq_index + i, 408108a6481SCindy Lu .num = 1, 409108a6481SCindy Lu }; 410108a6481SCindy Lu vhost_vdpa_call(dev, VHOST_VDPA_SET_VRING_ENABLE, &state); 411108a6481SCindy Lu } 412108a6481SCindy Lu return 0; 413108a6481SCindy Lu } 414108a6481SCindy Lu 415778e67deSLaurent Vivier static void vhost_vdpa_dump_config(struct vhost_dev *dev, const uint8_t *config, 416778e67deSLaurent Vivier uint32_t config_len) 417778e67deSLaurent Vivier { 418778e67deSLaurent Vivier int b, len; 419778e67deSLaurent Vivier char line[QEMU_HEXDUMP_LINE_LEN]; 420778e67deSLaurent Vivier 421778e67deSLaurent Vivier for (b = 0; b < config_len; b += 16) { 422778e67deSLaurent Vivier len = config_len - b; 423778e67deSLaurent Vivier qemu_hexdump_line(line, b, config, len, false); 424778e67deSLaurent Vivier trace_vhost_vdpa_dump_config(dev, line); 425778e67deSLaurent Vivier } 426778e67deSLaurent Vivier } 427778e67deSLaurent Vivier 428108a6481SCindy Lu static int vhost_vdpa_set_config(struct vhost_dev *dev, const uint8_t *data, 429108a6481SCindy Lu uint32_t offset, uint32_t size, 430108a6481SCindy Lu uint32_t flags) 431108a6481SCindy Lu { 432108a6481SCindy Lu struct vhost_vdpa_config *config; 433108a6481SCindy Lu int ret; 434108a6481SCindy Lu unsigned long config_size = offsetof(struct vhost_vdpa_config, buf); 435986d4f78SLi Qiang 436778e67deSLaurent Vivier trace_vhost_vdpa_set_config(dev, offset, size, flags); 437108a6481SCindy Lu config = g_malloc(size + config_size); 438108a6481SCindy Lu config->off = offset; 439108a6481SCindy Lu config->len = size; 440108a6481SCindy Lu memcpy(config->buf, data, size); 441778e67deSLaurent Vivier if (trace_event_get_state_backends(TRACE_VHOST_VDPA_SET_CONFIG) && 442778e67deSLaurent Vivier trace_event_get_state_backends(TRACE_VHOST_VDPA_DUMP_CONFIG)) { 443778e67deSLaurent Vivier vhost_vdpa_dump_config(dev, data, size); 444778e67deSLaurent Vivier } 445108a6481SCindy Lu ret = vhost_vdpa_call(dev, VHOST_VDPA_SET_CONFIG, config); 446108a6481SCindy Lu g_free(config); 447108a6481SCindy Lu return ret; 448108a6481SCindy Lu } 449108a6481SCindy Lu 450108a6481SCindy Lu static int vhost_vdpa_get_config(struct vhost_dev *dev, uint8_t *config, 451108a6481SCindy Lu uint32_t config_len) 452108a6481SCindy Lu { 453108a6481SCindy Lu struct vhost_vdpa_config *v_config; 454108a6481SCindy Lu unsigned long config_size = offsetof(struct vhost_vdpa_config, buf); 455108a6481SCindy Lu int ret; 456108a6481SCindy Lu 457778e67deSLaurent Vivier trace_vhost_vdpa_get_config(dev, config, config_len); 458108a6481SCindy Lu v_config = g_malloc(config_len + config_size); 459108a6481SCindy Lu v_config->len = config_len; 460108a6481SCindy Lu v_config->off = 0; 461108a6481SCindy Lu ret = vhost_vdpa_call(dev, VHOST_VDPA_GET_CONFIG, v_config); 462108a6481SCindy Lu memcpy(config, v_config->buf, config_len); 463108a6481SCindy Lu g_free(v_config); 464778e67deSLaurent Vivier if (trace_event_get_state_backends(TRACE_VHOST_VDPA_GET_CONFIG) && 465778e67deSLaurent Vivier trace_event_get_state_backends(TRACE_VHOST_VDPA_DUMP_CONFIG)) { 466778e67deSLaurent Vivier vhost_vdpa_dump_config(dev, config, config_len); 467778e67deSLaurent Vivier } 468108a6481SCindy Lu return ret; 469108a6481SCindy Lu } 470108a6481SCindy Lu 471108a6481SCindy Lu static int vhost_vdpa_dev_start(struct vhost_dev *dev, bool started) 472108a6481SCindy Lu { 473108a6481SCindy Lu struct vhost_vdpa *v = dev->opaque; 474778e67deSLaurent Vivier trace_vhost_vdpa_dev_start(dev, started); 475108a6481SCindy Lu if (started) { 476108a6481SCindy Lu uint8_t status = 0; 477108a6481SCindy Lu memory_listener_register(&v->listener, &address_space_memory); 478108a6481SCindy Lu vhost_vdpa_set_vring_ready(dev); 479108a6481SCindy Lu vhost_vdpa_add_status(dev, VIRTIO_CONFIG_S_DRIVER_OK); 480108a6481SCindy Lu vhost_vdpa_call(dev, VHOST_VDPA_GET_STATUS, &status); 481108a6481SCindy Lu 482108a6481SCindy Lu return !(status & VIRTIO_CONFIG_S_DRIVER_OK); 483108a6481SCindy Lu } else { 484108a6481SCindy Lu vhost_vdpa_reset_device(dev); 485108a6481SCindy Lu vhost_vdpa_add_status(dev, VIRTIO_CONFIG_S_ACKNOWLEDGE | 486108a6481SCindy Lu VIRTIO_CONFIG_S_DRIVER); 487108a6481SCindy Lu memory_listener_unregister(&v->listener); 488108a6481SCindy Lu 489108a6481SCindy Lu return 0; 490108a6481SCindy Lu } 491108a6481SCindy Lu } 492108a6481SCindy Lu 493108a6481SCindy Lu static int vhost_vdpa_set_log_base(struct vhost_dev *dev, uint64_t base, 494108a6481SCindy Lu struct vhost_log *log) 495108a6481SCindy Lu { 496778e67deSLaurent Vivier trace_vhost_vdpa_set_log_base(dev, base, log->size, log->refcnt, log->fd, 497778e67deSLaurent Vivier log->log); 498108a6481SCindy Lu return vhost_vdpa_call(dev, VHOST_SET_LOG_BASE, &base); 499108a6481SCindy Lu } 500108a6481SCindy Lu 501108a6481SCindy Lu static int vhost_vdpa_set_vring_addr(struct vhost_dev *dev, 502108a6481SCindy Lu struct vhost_vring_addr *addr) 503108a6481SCindy Lu { 504778e67deSLaurent Vivier trace_vhost_vdpa_set_vring_addr(dev, addr->index, addr->flags, 505778e67deSLaurent Vivier addr->desc_user_addr, addr->used_user_addr, 506778e67deSLaurent Vivier addr->avail_user_addr, 507778e67deSLaurent Vivier addr->log_guest_addr); 508108a6481SCindy Lu return vhost_vdpa_call(dev, VHOST_SET_VRING_ADDR, addr); 509108a6481SCindy Lu } 510108a6481SCindy Lu 511108a6481SCindy Lu static int vhost_vdpa_set_vring_num(struct vhost_dev *dev, 512108a6481SCindy Lu struct vhost_vring_state *ring) 513108a6481SCindy Lu { 514778e67deSLaurent Vivier trace_vhost_vdpa_set_vring_num(dev, ring->index, ring->num); 515108a6481SCindy Lu return vhost_vdpa_call(dev, VHOST_SET_VRING_NUM, ring); 516108a6481SCindy Lu } 517108a6481SCindy Lu 518108a6481SCindy Lu static int vhost_vdpa_set_vring_base(struct vhost_dev *dev, 519108a6481SCindy Lu struct vhost_vring_state *ring) 520108a6481SCindy Lu { 521778e67deSLaurent Vivier trace_vhost_vdpa_set_vring_base(dev, ring->index, ring->num); 522108a6481SCindy Lu return vhost_vdpa_call(dev, VHOST_SET_VRING_BASE, ring); 523108a6481SCindy Lu } 524108a6481SCindy Lu 525108a6481SCindy Lu static int vhost_vdpa_get_vring_base(struct vhost_dev *dev, 526108a6481SCindy Lu struct vhost_vring_state *ring) 527108a6481SCindy Lu { 528778e67deSLaurent Vivier int ret; 529778e67deSLaurent Vivier 530778e67deSLaurent Vivier ret = vhost_vdpa_call(dev, VHOST_GET_VRING_BASE, ring); 531778e67deSLaurent Vivier trace_vhost_vdpa_get_vring_base(dev, ring->index, ring->num); 532778e67deSLaurent Vivier return ret; 533108a6481SCindy Lu } 534108a6481SCindy Lu 535108a6481SCindy Lu static int vhost_vdpa_set_vring_kick(struct vhost_dev *dev, 536108a6481SCindy Lu struct vhost_vring_file *file) 537108a6481SCindy Lu { 538778e67deSLaurent Vivier trace_vhost_vdpa_set_vring_kick(dev, file->index, file->fd); 539108a6481SCindy Lu return vhost_vdpa_call(dev, VHOST_SET_VRING_KICK, file); 540108a6481SCindy Lu } 541108a6481SCindy Lu 542108a6481SCindy Lu static int vhost_vdpa_set_vring_call(struct vhost_dev *dev, 543108a6481SCindy Lu struct vhost_vring_file *file) 544108a6481SCindy Lu { 545778e67deSLaurent Vivier trace_vhost_vdpa_set_vring_call(dev, file->index, file->fd); 546108a6481SCindy Lu return vhost_vdpa_call(dev, VHOST_SET_VRING_CALL, file); 547108a6481SCindy Lu } 548108a6481SCindy Lu 549108a6481SCindy Lu static int vhost_vdpa_get_features(struct vhost_dev *dev, 550108a6481SCindy Lu uint64_t *features) 551108a6481SCindy Lu { 552778e67deSLaurent Vivier int ret; 553778e67deSLaurent Vivier 554778e67deSLaurent Vivier ret = vhost_vdpa_call(dev, VHOST_GET_FEATURES, features); 555778e67deSLaurent Vivier trace_vhost_vdpa_get_features(dev, *features); 556778e67deSLaurent Vivier return ret; 557108a6481SCindy Lu } 558108a6481SCindy Lu 559108a6481SCindy Lu static int vhost_vdpa_set_owner(struct vhost_dev *dev) 560108a6481SCindy Lu { 561778e67deSLaurent Vivier trace_vhost_vdpa_set_owner(dev); 562108a6481SCindy Lu return vhost_vdpa_call(dev, VHOST_SET_OWNER, NULL); 563108a6481SCindy Lu } 564108a6481SCindy Lu 565108a6481SCindy Lu static int vhost_vdpa_vq_get_addr(struct vhost_dev *dev, 566108a6481SCindy Lu struct vhost_vring_addr *addr, struct vhost_virtqueue *vq) 567108a6481SCindy Lu { 568108a6481SCindy Lu assert(dev->vhost_ops->backend_type == VHOST_BACKEND_TYPE_VDPA); 569108a6481SCindy Lu addr->desc_user_addr = (uint64_t)(unsigned long)vq->desc_phys; 570108a6481SCindy Lu addr->avail_user_addr = (uint64_t)(unsigned long)vq->avail_phys; 571108a6481SCindy Lu addr->used_user_addr = (uint64_t)(unsigned long)vq->used_phys; 572778e67deSLaurent Vivier trace_vhost_vdpa_vq_get_addr(dev, vq, addr->desc_user_addr, 573778e67deSLaurent Vivier addr->avail_user_addr, addr->used_user_addr); 574108a6481SCindy Lu return 0; 575108a6481SCindy Lu } 576108a6481SCindy Lu 577108a6481SCindy Lu static bool vhost_vdpa_force_iommu(struct vhost_dev *dev) 578108a6481SCindy Lu { 579108a6481SCindy Lu return true; 580108a6481SCindy Lu } 581108a6481SCindy Lu 582108a6481SCindy Lu const VhostOps vdpa_ops = { 583108a6481SCindy Lu .backend_type = VHOST_BACKEND_TYPE_VDPA, 584108a6481SCindy Lu .vhost_backend_init = vhost_vdpa_init, 585108a6481SCindy Lu .vhost_backend_cleanup = vhost_vdpa_cleanup, 586108a6481SCindy Lu .vhost_set_log_base = vhost_vdpa_set_log_base, 587108a6481SCindy Lu .vhost_set_vring_addr = vhost_vdpa_set_vring_addr, 588108a6481SCindy Lu .vhost_set_vring_num = vhost_vdpa_set_vring_num, 589108a6481SCindy Lu .vhost_set_vring_base = vhost_vdpa_set_vring_base, 590108a6481SCindy Lu .vhost_get_vring_base = vhost_vdpa_get_vring_base, 591108a6481SCindy Lu .vhost_set_vring_kick = vhost_vdpa_set_vring_kick, 592108a6481SCindy Lu .vhost_set_vring_call = vhost_vdpa_set_vring_call, 593108a6481SCindy Lu .vhost_get_features = vhost_vdpa_get_features, 594a5bd0580SJason Wang .vhost_set_backend_cap = vhost_vdpa_set_backend_cap, 595108a6481SCindy Lu .vhost_set_owner = vhost_vdpa_set_owner, 596108a6481SCindy Lu .vhost_set_vring_endian = NULL, 597108a6481SCindy Lu .vhost_backend_memslots_limit = vhost_vdpa_memslots_limit, 598108a6481SCindy Lu .vhost_set_mem_table = vhost_vdpa_set_mem_table, 599108a6481SCindy Lu .vhost_set_features = vhost_vdpa_set_features, 600108a6481SCindy Lu .vhost_reset_device = vhost_vdpa_reset_device, 601108a6481SCindy Lu .vhost_get_vq_index = vhost_vdpa_get_vq_index, 602108a6481SCindy Lu .vhost_get_config = vhost_vdpa_get_config, 603108a6481SCindy Lu .vhost_set_config = vhost_vdpa_set_config, 604108a6481SCindy Lu .vhost_requires_shm_log = NULL, 605108a6481SCindy Lu .vhost_migration_done = NULL, 606108a6481SCindy Lu .vhost_backend_can_merge = NULL, 607108a6481SCindy Lu .vhost_net_set_mtu = NULL, 608108a6481SCindy Lu .vhost_set_iotlb_callback = NULL, 609108a6481SCindy Lu .vhost_send_device_iotlb_msg = NULL, 610108a6481SCindy Lu .vhost_dev_start = vhost_vdpa_dev_start, 611108a6481SCindy Lu .vhost_get_device_id = vhost_vdpa_get_device_id, 612108a6481SCindy Lu .vhost_vq_get_addr = vhost_vdpa_vq_get_addr, 613108a6481SCindy Lu .vhost_force_iommu = vhost_vdpa_force_iommu, 614108a6481SCindy Lu }; 615