1488570ebSJim Harris /* SPDX-License-Identifier: BSD-3-Clause
2a6dbe372Spaul luse * Copyright (C) 2020 Intel Corporation.
370b31195SChangpeng Liu * All rights reserved.
470b31195SChangpeng Liu */
570b31195SChangpeng Liu
670b31195SChangpeng Liu /*
770b31195SChangpeng Liu * vfio-user transport for PCI devices.
870b31195SChangpeng Liu */
970b31195SChangpeng Liu
1070b31195SChangpeng Liu #include "spdk/stdinc.h"
1170b31195SChangpeng Liu #include "spdk/log.h"
1270b31195SChangpeng Liu #include "spdk/env.h"
1370b31195SChangpeng Liu #include "spdk/queue.h"
1470b31195SChangpeng Liu #include "spdk/util.h"
1570b31195SChangpeng Liu #include "spdk/vfio_user_pci.h"
1670b31195SChangpeng Liu
1770b31195SChangpeng Liu #include "vfio_user_internal.h"
1870b31195SChangpeng Liu
1970b31195SChangpeng Liu static uint32_t g_vfio_dev_id;
2070b31195SChangpeng Liu
2170b31195SChangpeng Liu int
spdk_vfio_user_pci_bar_access(struct vfio_device * dev,uint32_t index,uint64_t offset,size_t len,void * buf,bool is_write)2270b31195SChangpeng Liu spdk_vfio_user_pci_bar_access(struct vfio_device *dev, uint32_t index, uint64_t offset,
2370b31195SChangpeng Liu size_t len, void *buf, bool is_write)
2470b31195SChangpeng Liu {
2570b31195SChangpeng Liu struct vfio_pci_region *region = &dev->regions[index];
2670b31195SChangpeng Liu uint32_t i;
2770b31195SChangpeng Liu
2870b31195SChangpeng Liu if (offset + len > region->size) {
2970b31195SChangpeng Liu return -EINVAL;
3070b31195SChangpeng Liu }
3170b31195SChangpeng Liu
3270b31195SChangpeng Liu if (!region->nr_mmaps || (offset < region->mmaps[0].offset)) {
3370b31195SChangpeng Liu return vfio_user_dev_mmio_access(dev, index, offset, len, buf, is_write);
3470b31195SChangpeng Liu }
3570b31195SChangpeng Liu
3670b31195SChangpeng Liu /* SPARSE MMAP */
3770b31195SChangpeng Liu for (i = 0; i < region->nr_mmaps; i++) {
3870b31195SChangpeng Liu if ((offset >= region->mmaps[i].offset) &&
3970b31195SChangpeng Liu (offset + len <= region->mmaps[i].offset + region->mmaps[i].size)) {
4070b31195SChangpeng Liu assert(region->mmaps[i].mem != NULL);
41a773ed9aSJun Zeng void *bar_addr = region->mmaps[i].mem + offset - region->mmaps[i].offset;
4270b31195SChangpeng Liu if (is_write) {
4370b31195SChangpeng Liu memcpy(bar_addr, buf, len);
4470b31195SChangpeng Liu } else {
4570b31195SChangpeng Liu memcpy(buf, bar_addr, len);
4670b31195SChangpeng Liu }
4770b31195SChangpeng Liu return 0;
4870b31195SChangpeng Liu }
4970b31195SChangpeng Liu }
5070b31195SChangpeng Liu
5170b31195SChangpeng Liu return -EFAULT;
5270b31195SChangpeng Liu }
5370b31195SChangpeng Liu
5470b31195SChangpeng Liu static int
vfio_add_mr(struct vfio_device * dev,struct vfio_memory_region * mr)5570b31195SChangpeng Liu vfio_add_mr(struct vfio_device *dev, struct vfio_memory_region *mr)
5670b31195SChangpeng Liu {
5770b31195SChangpeng Liu if (dev->nr_mrs == VFIO_MAXIMUM_MEMORY_REGIONS) {
5870b31195SChangpeng Liu SPDK_ERRLOG("Maximum supported memory regions %d\n", VFIO_MAXIMUM_MEMORY_REGIONS);
5970b31195SChangpeng Liu return -EINVAL;
6070b31195SChangpeng Liu }
6170b31195SChangpeng Liu
6270b31195SChangpeng Liu TAILQ_INSERT_TAIL(&dev->mrs_head, mr, link);
6370b31195SChangpeng Liu dev->nr_mrs++;
6470b31195SChangpeng Liu
6570b31195SChangpeng Liu SPDK_DEBUGLOG(vfio_pci, "Add memory region: FD %d, VADDR 0x%lx, IOVA 0x%lx, Size 0x%lx\n",
6670b31195SChangpeng Liu mr->fd, mr->vaddr, mr->iova, mr->size);
6770b31195SChangpeng Liu
6870b31195SChangpeng Liu return 0;
6970b31195SChangpeng Liu }
7070b31195SChangpeng Liu
7170b31195SChangpeng Liu static struct vfio_memory_region *
vfio_get_mr(struct vfio_device * dev,uint64_t addr,size_t len)7270b31195SChangpeng Liu vfio_get_mr(struct vfio_device *dev, uint64_t addr, size_t len)
7370b31195SChangpeng Liu {
7470b31195SChangpeng Liu struct vfio_memory_region *mr, *tmp_mr;
7570b31195SChangpeng Liu
7670b31195SChangpeng Liu if (dev->nr_mrs == 0) {
7770b31195SChangpeng Liu return false;
7870b31195SChangpeng Liu }
7970b31195SChangpeng Liu
8070b31195SChangpeng Liu TAILQ_FOREACH_SAFE(mr, &dev->mrs_head, link, tmp_mr) {
8170b31195SChangpeng Liu if ((mr->vaddr == addr) || (mr->iova == addr)) {
8270b31195SChangpeng Liu return mr;
8370b31195SChangpeng Liu }
8470b31195SChangpeng Liu }
8570b31195SChangpeng Liu
8670b31195SChangpeng Liu return false;
8770b31195SChangpeng Liu }
8870b31195SChangpeng Liu
8970b31195SChangpeng Liu static void
vfio_remove_mr(struct vfio_device * dev,uint64_t addr,size_t len)9070b31195SChangpeng Liu vfio_remove_mr(struct vfio_device *dev, uint64_t addr, size_t len)
9170b31195SChangpeng Liu {
9270b31195SChangpeng Liu struct vfio_memory_region *mr, *tmp_mr;
9370b31195SChangpeng Liu
9470b31195SChangpeng Liu TAILQ_FOREACH_SAFE(mr, &dev->mrs_head, link, tmp_mr) {
9570b31195SChangpeng Liu if ((mr->vaddr == addr) || (mr->iova == addr)) {
9670b31195SChangpeng Liu SPDK_DEBUGLOG(vfio_pci, "Remove memory region: FD %d, VADDR 0x%lx, IOVA 0x%lx, Size 0x%lx\n",
9770b31195SChangpeng Liu mr->fd, mr->vaddr, mr->iova, mr->size);
9870b31195SChangpeng Liu TAILQ_REMOVE(&dev->mrs_head, mr, link);
9970b31195SChangpeng Liu assert(dev->nr_mrs > 0);
10070b31195SChangpeng Liu dev->nr_mrs--;
10170b31195SChangpeng Liu free(mr);
10270b31195SChangpeng Liu return;
10370b31195SChangpeng Liu }
10470b31195SChangpeng Liu }
10570b31195SChangpeng Liu }
10670b31195SChangpeng Liu
10770b31195SChangpeng Liu static int
vfio_mr_map_notify(void * cb_ctx,struct spdk_mem_map * map,enum spdk_mem_map_notify_action action,void * vaddr,size_t size)10870b31195SChangpeng Liu vfio_mr_map_notify(void *cb_ctx, struct spdk_mem_map *map,
10970b31195SChangpeng Liu enum spdk_mem_map_notify_action action,
11070b31195SChangpeng Liu void *vaddr, size_t size)
11170b31195SChangpeng Liu {
11270b31195SChangpeng Liu int ret;
11370b31195SChangpeng Liu struct vfio_device *dev = cb_ctx;
11470b31195SChangpeng Liu struct vfio_memory_region *mr;
11570b31195SChangpeng Liu uint64_t offset;
11670b31195SChangpeng Liu
11770b31195SChangpeng Liu mr = vfio_get_mr(dev, (uint64_t)vaddr, size);
11870b31195SChangpeng Liu if (action == SPDK_MEM_MAP_NOTIFY_UNREGISTER) {
11970b31195SChangpeng Liu if (!mr) {
12070b31195SChangpeng Liu SPDK_ERRLOG("Memory region VADDR %p doesn't exist\n", vaddr);
12170b31195SChangpeng Liu return -EEXIST;
12270b31195SChangpeng Liu }
12370b31195SChangpeng Liu
12470b31195SChangpeng Liu ret = vfio_user_dev_dma_map_unmap(dev, mr, false);
12570b31195SChangpeng Liu /* remove the memory region */
12670b31195SChangpeng Liu vfio_remove_mr(dev, (uint64_t)vaddr, size);
12770b31195SChangpeng Liu return ret;
12870b31195SChangpeng Liu }
12970b31195SChangpeng Liu
13070b31195SChangpeng Liu /* SPDK_MEM_MAP_NOTIFY_REGISTER */
13170b31195SChangpeng Liu if (mr != NULL) {
13270b31195SChangpeng Liu SPDK_ERRLOG("Memory region VADDR 0x%lx already exist\n", mr->vaddr);
13370b31195SChangpeng Liu return -EEXIST;
13470b31195SChangpeng Liu }
13570b31195SChangpeng Liu
13670b31195SChangpeng Liu mr = calloc(1, sizeof(*mr));
13770b31195SChangpeng Liu if (mr == NULL) {
13870b31195SChangpeng Liu return -ENOMEM;
13970b31195SChangpeng Liu }
14070b31195SChangpeng Liu mr->vaddr = (uint64_t)(uintptr_t)vaddr;
14170b31195SChangpeng Liu mr->iova = mr->vaddr;
14270b31195SChangpeng Liu mr->size = size;
14370b31195SChangpeng Liu mr->fd = spdk_mem_get_fd_and_offset(vaddr, &offset);
14470b31195SChangpeng Liu if (mr->fd < 0) {
14570b31195SChangpeng Liu SPDK_ERRLOG("Error to get the memory map offset\n");
14670b31195SChangpeng Liu free(mr);
14770b31195SChangpeng Liu return -EFAULT;
14870b31195SChangpeng Liu }
14970b31195SChangpeng Liu mr->offset = offset;
15070b31195SChangpeng Liu
15170b31195SChangpeng Liu ret = vfio_add_mr(dev, mr);
15270b31195SChangpeng Liu if (ret) {
15370b31195SChangpeng Liu free(mr);
15470b31195SChangpeng Liu return ret;
15570b31195SChangpeng Liu }
15670b31195SChangpeng Liu
15770b31195SChangpeng Liu return vfio_user_dev_dma_map_unmap(dev, mr, true);
15870b31195SChangpeng Liu }
15970b31195SChangpeng Liu
16070b31195SChangpeng Liu static int
vfio_device_dma_map(struct vfio_device * device)16170b31195SChangpeng Liu vfio_device_dma_map(struct vfio_device *device)
16270b31195SChangpeng Liu {
16370b31195SChangpeng Liu const struct spdk_mem_map_ops vfio_map_ops = {
16470b31195SChangpeng Liu .notify_cb = vfio_mr_map_notify,
16570b31195SChangpeng Liu .are_contiguous = NULL,
16670b31195SChangpeng Liu };
16770b31195SChangpeng Liu
16870b31195SChangpeng Liu device->map = spdk_mem_map_alloc((uint64_t)NULL, &vfio_map_ops, device);
16970b31195SChangpeng Liu if (device->map == NULL) {
17070b31195SChangpeng Liu SPDK_ERRLOG("Failed to allocate memory map structure\n");
17170b31195SChangpeng Liu return -EFAULT;
17270b31195SChangpeng Liu }
17370b31195SChangpeng Liu
17470b31195SChangpeng Liu return 0;
17570b31195SChangpeng Liu }
17670b31195SChangpeng Liu
17770b31195SChangpeng Liu static struct vfio_info_cap_header *
vfio_device_get_info_cap(struct vfio_region_info * info,int cap)17870b31195SChangpeng Liu vfio_device_get_info_cap(struct vfio_region_info *info, int cap)
17970b31195SChangpeng Liu {
18070b31195SChangpeng Liu struct vfio_info_cap_header *h;
18170b31195SChangpeng Liu size_t offset;
18270b31195SChangpeng Liu
18370b31195SChangpeng Liu if ((info->flags & VFIO_REGION_INFO_FLAG_CAPS) == 0) {
18470b31195SChangpeng Liu return NULL;
18570b31195SChangpeng Liu }
18670b31195SChangpeng Liu
18770b31195SChangpeng Liu offset = info->cap_offset;
18870b31195SChangpeng Liu while (offset != 0) {
18970b31195SChangpeng Liu h = (struct vfio_info_cap_header *)((uintptr_t)info + offset);
19070b31195SChangpeng Liu if (h->id == cap) {
19170b31195SChangpeng Liu return h;
19270b31195SChangpeng Liu }
19370b31195SChangpeng Liu offset = h->next;
19470b31195SChangpeng Liu }
19570b31195SChangpeng Liu
19670b31195SChangpeng Liu return NULL;
19770b31195SChangpeng Liu }
19870b31195SChangpeng Liu
19970b31195SChangpeng Liu static int
vfio_device_setup_sparse_mmaps(struct vfio_device * device,int index,struct vfio_region_info * info,int * fds)20070b31195SChangpeng Liu vfio_device_setup_sparse_mmaps(struct vfio_device *device, int index,
20170b31195SChangpeng Liu struct vfio_region_info *info, int *fds)
20270b31195SChangpeng Liu {
20370b31195SChangpeng Liu struct vfio_info_cap_header *hdr;
20470b31195SChangpeng Liu struct vfio_region_info_cap_sparse_mmap *sparse;
20570b31195SChangpeng Liu struct vfio_pci_region *region = &device->regions[index];
20670b31195SChangpeng Liu uint32_t i, j = 0;
207*fad37e09SKonrad Sztyber int rc = 0, prot = 0;
20870b31195SChangpeng Liu
20970b31195SChangpeng Liu hdr = vfio_device_get_info_cap(info, VFIO_REGION_INFO_CAP_SPARSE_MMAP);
21070b31195SChangpeng Liu if (!hdr) {
21170b31195SChangpeng Liu SPDK_NOTICELOG("Device doesn't have sparse mmap\n");
21270b31195SChangpeng Liu return -EEXIST;
21370b31195SChangpeng Liu }
21470b31195SChangpeng Liu
21570b31195SChangpeng Liu sparse = SPDK_CONTAINEROF(hdr, struct vfio_region_info_cap_sparse_mmap, header);
21670b31195SChangpeng Liu for (i = 0; i < sparse->nr_areas; i++) {
21770b31195SChangpeng Liu if (sparse->areas[i].size) {
21870b31195SChangpeng Liu region->mmaps[j].offset = sparse->areas[i].offset;
21970b31195SChangpeng Liu region->mmaps[j].size = sparse->areas[i].size;
22070b31195SChangpeng Liu prot |= info->flags & VFIO_REGION_INFO_FLAG_READ ? PROT_READ : 0;
22170b31195SChangpeng Liu prot |= info->flags & VFIO_REGION_INFO_FLAG_WRITE ? PROT_WRITE : 0;
22270b31195SChangpeng Liu if (*fds) {
22370b31195SChangpeng Liu region->mmaps[j].mem = mmap(NULL, region->mmaps[j].size, prot, MAP_SHARED,
22470b31195SChangpeng Liu fds[i], region->offset + region->mmaps[j].offset);
22570b31195SChangpeng Liu if (region->mmaps[j].mem == MAP_FAILED) {
22670b31195SChangpeng Liu SPDK_ERRLOG("Device SPARSE MMAP failed\n");
227*fad37e09SKonrad Sztyber rc = -EIO;
228*fad37e09SKonrad Sztyber goto out;
22970b31195SChangpeng Liu }
23070b31195SChangpeng Liu } else {
23170b31195SChangpeng Liu SPDK_DEBUGLOG(vfio_pci, "No valid fd, skip mmap for bar %d region %u\n", index, i);
23270b31195SChangpeng Liu }
23370b31195SChangpeng Liu SPDK_DEBUGLOG(vfio_pci, "Sparse region %u, Size 0x%llx, Offset 0x%llx, Map addr %p\n",
23470b31195SChangpeng Liu i, sparse->areas[i].size, sparse->areas[i].offset,
23570b31195SChangpeng Liu region->mmaps[j].mem);
23670b31195SChangpeng Liu j++;
23770b31195SChangpeng Liu }
23870b31195SChangpeng Liu }
23970b31195SChangpeng Liu device->regions[index].nr_mmaps = j;
240*fad37e09SKonrad Sztyber out:
241*fad37e09SKonrad Sztyber for (i = 0; i < sparse->nr_areas; i++) {
242*fad37e09SKonrad Sztyber close(fds[i]);
243*fad37e09SKonrad Sztyber }
24470b31195SChangpeng Liu
245*fad37e09SKonrad Sztyber return rc;
24670b31195SChangpeng Liu }
24770b31195SChangpeng Liu
24870b31195SChangpeng Liu static int
vfio_device_map_region(struct vfio_device * device,struct vfio_pci_region * region,int fd)24970b31195SChangpeng Liu vfio_device_map_region(struct vfio_device *device, struct vfio_pci_region *region, int fd)
25070b31195SChangpeng Liu {
25170b31195SChangpeng Liu int prot = 0;
25270b31195SChangpeng Liu
25370b31195SChangpeng Liu prot |= region->flags & VFIO_REGION_INFO_FLAG_READ ? PROT_READ : 0;
25470b31195SChangpeng Liu prot |= region->flags & VFIO_REGION_INFO_FLAG_WRITE ? PROT_WRITE : 0;
25570b31195SChangpeng Liu
25670b31195SChangpeng Liu region->mmaps[0].offset = 0;
25770b31195SChangpeng Liu region->mmaps[0].size = region->size;
25870b31195SChangpeng Liu
25970b31195SChangpeng Liu region->mmaps[0].mem = mmap(NULL, region->size, prot, MAP_SHARED,
26070b31195SChangpeng Liu fd, region->offset);
261*fad37e09SKonrad Sztyber close(fd);
26270b31195SChangpeng Liu if (region->mmaps[0].mem == MAP_FAILED) {
26370b31195SChangpeng Liu SPDK_ERRLOG("Device Region MMAP failed\n");
26470b31195SChangpeng Liu return -EFAULT;
26570b31195SChangpeng Liu }
26670b31195SChangpeng Liu SPDK_DEBUGLOG(vfio_pci, "Memory mapped to %p\n", region->mmaps[0].mem);
26770b31195SChangpeng Liu region->nr_mmaps = 1;
26870b31195SChangpeng Liu
26970b31195SChangpeng Liu return 0;
27070b31195SChangpeng Liu }
27170b31195SChangpeng Liu
27270b31195SChangpeng Liu static int
vfio_device_map_bars_and_config_region(struct vfio_device * device)27370b31195SChangpeng Liu vfio_device_map_bars_and_config_region(struct vfio_device *device)
27470b31195SChangpeng Liu {
27570b31195SChangpeng Liu uint32_t i;
27670b31195SChangpeng Liu int ret;
27770b31195SChangpeng Liu size_t len = 4096;
27870b31195SChangpeng Liu int fds[VFIO_MAXIMUM_SPARSE_MMAP_REGIONS];
27970b31195SChangpeng Liu struct vfio_region_info *info;
28070b31195SChangpeng Liu uint8_t *buf;
28170b31195SChangpeng Liu
28270b31195SChangpeng Liu buf = calloc(1, len);
28370b31195SChangpeng Liu if (!buf) {
28470b31195SChangpeng Liu return -ENOMEM;
28570b31195SChangpeng Liu }
28670b31195SChangpeng Liu
28770b31195SChangpeng Liu info = (struct vfio_region_info *)buf;
28870b31195SChangpeng Liu for (i = 0; i < device->pci_regions; i++) {
28970b31195SChangpeng Liu memset(info, 0, len);
29070b31195SChangpeng Liu memset(fds, 0, sizeof(fds));
29170b31195SChangpeng Liu
29270b31195SChangpeng Liu info->index = i;
29370b31195SChangpeng Liu ret = vfio_user_get_dev_region_info(device, info, len, fds, VFIO_MAXIMUM_SPARSE_MMAP_REGIONS);
29470b31195SChangpeng Liu if (ret) {
29570b31195SChangpeng Liu SPDK_ERRLOG("Device setup bar %d failed\n", ret);
29670b31195SChangpeng Liu free(buf);
29770b31195SChangpeng Liu return ret;
29870b31195SChangpeng Liu }
29970b31195SChangpeng Liu
30070b31195SChangpeng Liu device->regions[i].size = info->size;
30170b31195SChangpeng Liu device->regions[i].offset = info->offset;
30270b31195SChangpeng Liu device->regions[i].flags = info->flags;
30370b31195SChangpeng Liu
30470b31195SChangpeng Liu SPDK_DEBUGLOG(vfio_pci, "Bar %d, Size 0x%llx, Offset 0x%llx, Flags 0x%x, Cap offset %u\n",
30570b31195SChangpeng Liu i, info->size, info->offset, info->flags, info->cap_offset);
30670b31195SChangpeng Liu
30770b31195SChangpeng Liu /* Setup MMAP if any */
30870b31195SChangpeng Liu if (info->size && (info->flags & VFIO_REGION_INFO_FLAG_MMAP)) {
30970b31195SChangpeng Liu /* try to map sparse memory region first */
31070b31195SChangpeng Liu ret = vfio_device_setup_sparse_mmaps(device, i, info, fds);
31170b31195SChangpeng Liu if (ret < 0) {
31270b31195SChangpeng Liu ret = vfio_device_map_region(device, &device->regions[i], fds[0]);
31370b31195SChangpeng Liu }
31470b31195SChangpeng Liu
31570b31195SChangpeng Liu if (ret != 0) {
31670b31195SChangpeng Liu SPDK_ERRLOG("Setup Device %s region %d failed\n", device->name, i);
31770b31195SChangpeng Liu free(buf);
31870b31195SChangpeng Liu return ret;
31970b31195SChangpeng Liu }
32070b31195SChangpeng Liu }
32170b31195SChangpeng Liu }
32270b31195SChangpeng Liu
32370b31195SChangpeng Liu free(buf);
32470b31195SChangpeng Liu return 0;
32570b31195SChangpeng Liu }
32670b31195SChangpeng Liu
32770b31195SChangpeng Liu static void
vfio_device_unmap_bars(struct vfio_device * dev)32870b31195SChangpeng Liu vfio_device_unmap_bars(struct vfio_device *dev)
32970b31195SChangpeng Liu {
33070b31195SChangpeng Liu uint32_t i, j;
33170b31195SChangpeng Liu struct vfio_pci_region *region;
33270b31195SChangpeng Liu
33370b31195SChangpeng Liu for (i = 0; i < dev->pci_regions; i++) {
33470b31195SChangpeng Liu region = &dev->regions[i];
33570b31195SChangpeng Liu for (j = 0; j < region->nr_mmaps; j++) {
33670b31195SChangpeng Liu if (region->mmaps[j].mem) {
33770b31195SChangpeng Liu munmap(region->mmaps[j].mem, region->mmaps[j].size);
33870b31195SChangpeng Liu }
33970b31195SChangpeng Liu }
34070b31195SChangpeng Liu }
34170b31195SChangpeng Liu memset(dev->regions, 0, sizeof(dev->regions));
34270b31195SChangpeng Liu }
34370b31195SChangpeng Liu
34470b31195SChangpeng Liu struct vfio_device *
spdk_vfio_user_setup(const char * path)34570b31195SChangpeng Liu spdk_vfio_user_setup(const char *path)
34670b31195SChangpeng Liu {
34770b31195SChangpeng Liu int ret;
34870b31195SChangpeng Liu struct vfio_device *device = NULL;
34970b31195SChangpeng Liu struct vfio_user_device_info dev_info = {};
35070b31195SChangpeng Liu
35170b31195SChangpeng Liu device = calloc(1, sizeof(*device));
35270b31195SChangpeng Liu if (!device) {
35370b31195SChangpeng Liu return NULL;
35470b31195SChangpeng Liu }
35570b31195SChangpeng Liu TAILQ_INIT(&device->mrs_head);
35670b31195SChangpeng Liu snprintf(device->path, PATH_MAX, "%s", path);
35770b31195SChangpeng Liu snprintf(device->name, sizeof(device->name), "vfio-user%u", g_vfio_dev_id++);
35870b31195SChangpeng Liu
35970b31195SChangpeng Liu ret = vfio_user_dev_setup(device);
36070b31195SChangpeng Liu if (ret) {
36170b31195SChangpeng Liu free(device);
36270b31195SChangpeng Liu SPDK_ERRLOG("Error to setup vfio-user via path %s\n", path);
36370b31195SChangpeng Liu return NULL;
36470b31195SChangpeng Liu }
36570b31195SChangpeng Liu
36670b31195SChangpeng Liu ret = vfio_user_get_dev_info(device, &dev_info, sizeof(dev_info));
36770b31195SChangpeng Liu if (ret) {
36870b31195SChangpeng Liu SPDK_ERRLOG("Device get info failed\n");
36970b31195SChangpeng Liu goto cleanup;
37070b31195SChangpeng Liu }
37170b31195SChangpeng Liu device->pci_regions = dev_info.num_regions;
37270b31195SChangpeng Liu device->flags = dev_info.flags;
37370b31195SChangpeng Liu
37470b31195SChangpeng Liu ret = vfio_device_map_bars_and_config_region(device);
37570b31195SChangpeng Liu if (ret) {
37670b31195SChangpeng Liu goto cleanup;
37770b31195SChangpeng Liu }
37870b31195SChangpeng Liu
37970b31195SChangpeng Liu /* Register DMA Region */
38070b31195SChangpeng Liu ret = vfio_device_dma_map(device);
38170b31195SChangpeng Liu if (ret) {
38270b31195SChangpeng Liu SPDK_ERRLOG("Container DMA map failed\n");
38370b31195SChangpeng Liu goto cleanup;
38470b31195SChangpeng Liu }
38570b31195SChangpeng Liu
38670b31195SChangpeng Liu SPDK_DEBUGLOG(vfio_pci, "Device %s, Path %s Setup Successfully\n", device->name, device->path);
38770b31195SChangpeng Liu
38870b31195SChangpeng Liu return device;
38970b31195SChangpeng Liu
39070b31195SChangpeng Liu cleanup:
39170b31195SChangpeng Liu close(device->fd);
39270b31195SChangpeng Liu free(device);
39370b31195SChangpeng Liu return NULL;
39470b31195SChangpeng Liu }
39570b31195SChangpeng Liu
39670b31195SChangpeng Liu void
spdk_vfio_user_release(struct vfio_device * dev)39770b31195SChangpeng Liu spdk_vfio_user_release(struct vfio_device *dev)
39870b31195SChangpeng Liu {
39970b31195SChangpeng Liu SPDK_DEBUGLOG(vfio_pci, "Release file %s\n", dev->path);
40070b31195SChangpeng Liu
40170b31195SChangpeng Liu vfio_device_unmap_bars(dev);
40270b31195SChangpeng Liu if (dev->map) {
40370b31195SChangpeng Liu spdk_mem_map_free(&dev->map);
40470b31195SChangpeng Liu }
40570b31195SChangpeng Liu close(dev->fd);
40670b31195SChangpeng Liu
40770b31195SChangpeng Liu free(dev);
40870b31195SChangpeng Liu }
40970b31195SChangpeng Liu
41070b31195SChangpeng Liu void *
spdk_vfio_user_get_bar_addr(struct vfio_device * dev,uint32_t index,uint64_t offset,uint32_t len)41170b31195SChangpeng Liu spdk_vfio_user_get_bar_addr(struct vfio_device *dev, uint32_t index, uint64_t offset, uint32_t len)
41270b31195SChangpeng Liu {
41370b31195SChangpeng Liu struct vfio_pci_region *region = &dev->regions[index];
41470b31195SChangpeng Liu uint32_t i;
41570b31195SChangpeng Liu
41670b31195SChangpeng Liu if (!region->size || !(region->flags & VFIO_REGION_INFO_FLAG_MMAP)) {
41770b31195SChangpeng Liu return NULL;
41870b31195SChangpeng Liu }
41970b31195SChangpeng Liu
42070b31195SChangpeng Liu for (i = 0; i < region->nr_mmaps; i++) {
42170b31195SChangpeng Liu if (region->mmaps[i].mem && (region->mmaps[i].offset <= offset) &&
42270b31195SChangpeng Liu ((offset + len) <= (region->mmaps[i].offset + region->mmaps[i].size))) {
42370b31195SChangpeng Liu return (void *)((uintptr_t)region->mmaps[i].mem + offset - region->mmaps[i].offset);
42470b31195SChangpeng Liu }
42570b31195SChangpeng Liu }
42670b31195SChangpeng Liu
42770b31195SChangpeng Liu return NULL;
42870b31195SChangpeng Liu }
42970b31195SChangpeng Liu
4305fb57441SSebastian Brzezinka /* For fuzzing only */
4315fb57441SSebastian Brzezinka int
spdk_vfio_user_dev_send_request(struct vfio_device * dev,enum vfio_user_command command,void * arg,size_t arg_len,size_t buf_len,int * fds,int max_fds)4325fb57441SSebastian Brzezinka spdk_vfio_user_dev_send_request(struct vfio_device *dev, enum vfio_user_command command,
4335fb57441SSebastian Brzezinka void *arg, size_t arg_len, size_t buf_len, int *fds,
4345fb57441SSebastian Brzezinka int max_fds)
4355fb57441SSebastian Brzezinka {
4365fb57441SSebastian Brzezinka return vfio_user_dev_send_request(dev, command, arg, arg_len, buf_len, fds, max_fds);
4375fb57441SSebastian Brzezinka }
4385fb57441SSebastian Brzezinka
43970b31195SChangpeng Liu SPDK_LOG_REGISTER_COMPONENT(vfio_pci)
440