]>
Commit | Line | Data |
---|---|---|
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 | */ | |
22 | struct 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 | */ | |
38 | VhostIOVATree *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 | */ | |
53 | void 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 | */ | |
67 | const 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 | */ | |
86 | int 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 | 107 | void vhost_iova_tree_remove(VhostIOVATree *iova_tree, DMAMap map) |
ec6122d8 EP |
108 | { |
109 | iova_tree_remove(iova_tree->iova_taddr_map, map); | |
110 | } |