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