]> git.proxmox.com Git - mirror_qemu.git/blame - hw/virtio/vhost-iova-tree.c
Merge tag 'pull-maintainer-may24-160524-2' of https://gitlab.com/stsquad/qemu into...
[mirror_qemu.git] / hw / virtio / vhost-iova-tree.c
CommitLineData
ec6122d8
EP
1/*
2 * vhost software live migration iova tree
3 *
4 * SPDX-FileCopyrightText: Red Hat, Inc. 2021
5 * SPDX-FileContributor: Author: Eugenio Pérez <eperezma@redhat.com>
6 *
7 * SPDX-License-Identifier: GPL-2.0-or-later
8 */
9
10#include "qemu/osdep.h"
11#include "qemu/iova-tree.h"
12#include "vhost-iova-tree.h"
13
8e3b0cbb 14#define iova_min_addr qemu_real_host_page_size()
ec6122d8
EP
15
16/**
17 * VhostIOVATree, able to:
18 * - Translate iova address
19 * - Reverse translate iova address (from translated to iova)
20 * - Allocate IOVA regions for translated range (linear operation)
21 */
22struct VhostIOVATree {
23 /* First addressable iova address in the device */
24 uint64_t iova_first;
25
26 /* Last addressable iova address in the device */
27 uint64_t iova_last;
28
29 /* IOVA address to qemu memory maps. */
30 IOVATree *iova_taddr_map;
31};
32
33/**
34 * Create a new IOVA tree
35 *
36 * Returns the new IOVA tree
37 */
38VhostIOVATree *vhost_iova_tree_new(hwaddr iova_first, hwaddr iova_last)
39{
40 VhostIOVATree *tree = g_new(VhostIOVATree, 1);
41
42 /* Some devices do not like 0 addresses */
43 tree->iova_first = MAX(iova_first, iova_min_addr);
44 tree->iova_last = iova_last;
45
46 tree->iova_taddr_map = iova_tree_new();
47 return tree;
48}
49
50/**
51 * Delete an iova tree
52 */
53void vhost_iova_tree_delete(VhostIOVATree *iova_tree)
54{
55 iova_tree_destroy(iova_tree->iova_taddr_map);
56 g_free(iova_tree);
57}
58
59/**
60 * Find the IOVA address stored from a memory address
61 *
62 * @tree: The iova tree
63 * @map: The map with the memory address
64 *
65 * Return the stored mapping, or NULL if not found.
66 */
67const DMAMap *vhost_iova_tree_find_iova(const VhostIOVATree *tree,
68 const DMAMap *map)
69{
70 return iova_tree_find_iova(tree->iova_taddr_map, map);
71}
72
73/**
74 * Allocate a new mapping
75 *
76 * @tree: The iova tree
77 * @map: The iova map
78 *
79 * Returns:
80 * - IOVA_OK if the map fits in the container
81 * - IOVA_ERR_INVALID if the map does not make sense (like size overflow)
82 * - IOVA_ERR_NOMEM if tree cannot allocate more space.
83 *
84 * It returns assignated iova in map->iova if return value is VHOST_DMA_MAP_OK.
85 */
86int vhost_iova_tree_map_alloc(VhostIOVATree *tree, DMAMap *map)
87{
88 /* Some vhost devices do not like addr 0. Skip first page */
8e3b0cbb 89 hwaddr iova_first = tree->iova_first ?: qemu_real_host_page_size();
ec6122d8
EP
90
91 if (map->translated_addr + map->size < map->translated_addr ||
92 map->perm == IOMMU_NONE) {
93 return IOVA_ERR_INVALID;
94 }
95
96 /* Allocate a node in IOVA address */
97 return iova_tree_alloc_map(tree->iova_taddr_map, map, iova_first,
98 tree->iova_last);
99}
100
101/**
102 * Remove existing mappings from iova tree
103 *
104 * @iova_tree: The vhost iova tree
105 * @map: The map to remove
106 */
69292a8e 107void vhost_iova_tree_remove(VhostIOVATree *iova_tree, DMAMap map)
ec6122d8
EP
108{
109 iova_tree_remove(iova_tree->iova_taddr_map, map);
110}