xref: /qemu/util/iova-tree.c (revision a89b34be5e2550949979c3184d00d5ab3e8dd707)
1eecf5eedSPeter Xu /*
2eecf5eedSPeter Xu  * IOVA tree implementation based on GTree.
3eecf5eedSPeter Xu  *
4eecf5eedSPeter Xu  * Copyright 2018 Red Hat, Inc.
5eecf5eedSPeter Xu  *
6eecf5eedSPeter Xu  * Authors:
7eecf5eedSPeter Xu  *  Peter Xu <peterx@redhat.com>
8eecf5eedSPeter Xu  *
9eecf5eedSPeter Xu  * This work is licensed under the terms of the GNU GPL, version 2 or later.
10eecf5eedSPeter Xu  */
11eecf5eedSPeter Xu 
12c5f1d0c4SDaniel P. Berrangé #include "qemu/osdep.h"
13eecf5eedSPeter Xu #include "qemu/iova-tree.h"
14eecf5eedSPeter Xu 
15eecf5eedSPeter Xu struct IOVATree {
16eecf5eedSPeter Xu     GTree *tree;
17eecf5eedSPeter Xu };
18eecf5eedSPeter Xu 
19eecf5eedSPeter Xu static int iova_tree_compare(gconstpointer a, gconstpointer b, gpointer data)
20eecf5eedSPeter Xu {
21eecf5eedSPeter Xu     const DMAMap *m1 = a, *m2 = b;
22eecf5eedSPeter Xu 
23eecf5eedSPeter Xu     if (m1->iova > m2->iova + m2->size) {
24eecf5eedSPeter Xu         return 1;
25eecf5eedSPeter Xu     }
26eecf5eedSPeter Xu 
27eecf5eedSPeter Xu     if (m1->iova + m1->size < m2->iova) {
28eecf5eedSPeter Xu         return -1;
29eecf5eedSPeter Xu     }
30eecf5eedSPeter Xu 
31eecf5eedSPeter Xu     /* Overlapped */
32eecf5eedSPeter Xu     return 0;
33eecf5eedSPeter Xu }
34eecf5eedSPeter Xu 
35eecf5eedSPeter Xu IOVATree *iova_tree_new(void)
36eecf5eedSPeter Xu {
37eecf5eedSPeter Xu     IOVATree *iova_tree = g_new0(IOVATree, 1);
38eecf5eedSPeter Xu 
39eecf5eedSPeter Xu     /* We don't have values actually, no need to free */
40eecf5eedSPeter Xu     iova_tree->tree = g_tree_new_full(iova_tree_compare, NULL, g_free, NULL);
41eecf5eedSPeter Xu 
42eecf5eedSPeter Xu     return iova_tree;
43eecf5eedSPeter Xu }
44eecf5eedSPeter Xu 
45*a89b34beSEugenio Pérez const DMAMap *iova_tree_find(const IOVATree *tree, const DMAMap *map)
46eecf5eedSPeter Xu {
47eecf5eedSPeter Xu     return g_tree_lookup(tree->tree, map);
48eecf5eedSPeter Xu }
49eecf5eedSPeter Xu 
50*a89b34beSEugenio Pérez const DMAMap *iova_tree_find_address(const IOVATree *tree, hwaddr iova)
51eecf5eedSPeter Xu {
52*a89b34beSEugenio Pérez     const DMAMap map = { .iova = iova, .size = 0 };
53eecf5eedSPeter Xu 
54eecf5eedSPeter Xu     return iova_tree_find(tree, &map);
55eecf5eedSPeter Xu }
56eecf5eedSPeter Xu 
57eecf5eedSPeter Xu static inline void iova_tree_insert_internal(GTree *gtree, DMAMap *range)
58eecf5eedSPeter Xu {
59eecf5eedSPeter Xu     /* Key and value are sharing the same range data */
60eecf5eedSPeter Xu     g_tree_insert(gtree, range, range);
61eecf5eedSPeter Xu }
62eecf5eedSPeter Xu 
63*a89b34beSEugenio Pérez int iova_tree_insert(IOVATree *tree, const DMAMap *map)
64eecf5eedSPeter Xu {
65eecf5eedSPeter Xu     DMAMap *new;
66eecf5eedSPeter Xu 
67eecf5eedSPeter Xu     if (map->iova + map->size < map->iova || map->perm == IOMMU_NONE) {
68eecf5eedSPeter Xu         return IOVA_ERR_INVALID;
69eecf5eedSPeter Xu     }
70eecf5eedSPeter Xu 
71eecf5eedSPeter Xu     /* We don't allow to insert range that overlaps with existings */
72eecf5eedSPeter Xu     if (iova_tree_find(tree, map)) {
73eecf5eedSPeter Xu         return IOVA_ERR_OVERLAP;
74eecf5eedSPeter Xu     }
75eecf5eedSPeter Xu 
76eecf5eedSPeter Xu     new = g_new0(DMAMap, 1);
77eecf5eedSPeter Xu     memcpy(new, map, sizeof(*new));
78eecf5eedSPeter Xu     iova_tree_insert_internal(tree->tree, new);
79eecf5eedSPeter Xu 
80eecf5eedSPeter Xu     return IOVA_OK;
81eecf5eedSPeter Xu }
82eecf5eedSPeter Xu 
83eecf5eedSPeter Xu static gboolean iova_tree_traverse(gpointer key, gpointer value,
84eecf5eedSPeter Xu                                 gpointer data)
85eecf5eedSPeter Xu {
86eecf5eedSPeter Xu     iova_tree_iterator iterator = data;
87eecf5eedSPeter Xu     DMAMap *map = key;
88eecf5eedSPeter Xu 
89eecf5eedSPeter Xu     g_assert(key == value);
90eecf5eedSPeter Xu 
91eecf5eedSPeter Xu     return iterator(map);
92eecf5eedSPeter Xu }
93eecf5eedSPeter Xu 
94eecf5eedSPeter Xu void iova_tree_foreach(IOVATree *tree, iova_tree_iterator iterator)
95eecf5eedSPeter Xu {
96eecf5eedSPeter Xu     g_tree_foreach(tree->tree, iova_tree_traverse, iterator);
97eecf5eedSPeter Xu }
98eecf5eedSPeter Xu 
99*a89b34beSEugenio Pérez int iova_tree_remove(IOVATree *tree, const DMAMap *map)
100eecf5eedSPeter Xu {
101*a89b34beSEugenio Pérez     const DMAMap *overlap;
102eecf5eedSPeter Xu 
103eecf5eedSPeter Xu     while ((overlap = iova_tree_find(tree, map))) {
104eecf5eedSPeter Xu         g_tree_remove(tree->tree, overlap);
105eecf5eedSPeter Xu     }
106eecf5eedSPeter Xu 
107eecf5eedSPeter Xu     return IOVA_OK;
108eecf5eedSPeter Xu }
109eecf5eedSPeter Xu 
110eecf5eedSPeter Xu void iova_tree_destroy(IOVATree *tree)
111eecf5eedSPeter Xu {
112eecf5eedSPeter Xu     g_tree_destroy(tree->tree);
113eecf5eedSPeter Xu     g_free(tree);
114eecf5eedSPeter Xu }
115