1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32#include <drm/ttm/ttm_bo_driver.h>
33#include <drm/ttm/ttm_placement.h>
34#include <drm/drm_mm.h>
35#include <linux/slab.h>
36#include <linux/spinlock.h>
37#include <linux/module.h>
38
39
40
41
42
43
44
45struct ttm_range_manager {
46 struct ttm_resource_manager manager;
47 struct drm_mm mm;
48 spinlock_t lock;
49};
50
51static inline struct ttm_range_manager *to_range_manager(struct ttm_resource_manager *man)
52{
53 return container_of(man, struct ttm_range_manager, manager);
54}
55
56static int ttm_range_man_alloc(struct ttm_resource_manager *man,
57 struct ttm_buffer_object *bo,
58 const struct ttm_place *place,
59 struct ttm_resource *mem)
60{
61 struct ttm_range_manager *rman = to_range_manager(man);
62 struct drm_mm *mm = &rman->mm;
63 struct drm_mm_node *node;
64 enum drm_mm_insert_mode mode;
65 unsigned long lpfn;
66 int ret;
67
68 lpfn = place->lpfn;
69 if (!lpfn)
70 lpfn = man->size;
71
72 node = kzalloc(sizeof(*node), GFP_KERNEL);
73 if (!node)
74 return -ENOMEM;
75
76 mode = DRM_MM_INSERT_BEST;
77 if (place->flags & TTM_PL_FLAG_TOPDOWN)
78 mode = DRM_MM_INSERT_HIGH;
79
80 spin_lock(&rman->lock);
81 ret = drm_mm_insert_node_in_range(mm, node,
82 mem->num_pages,
83 mem->page_alignment, 0,
84 place->fpfn, lpfn, mode);
85 spin_unlock(&rman->lock);
86
87 if (unlikely(ret)) {
88 kfree(node);
89 } else {
90 mem->mm_node = node;
91 mem->start = node->start;
92 }
93
94 return ret;
95}
96
97static void ttm_range_man_free(struct ttm_resource_manager *man,
98 struct ttm_resource *mem)
99{
100 struct ttm_range_manager *rman = to_range_manager(man);
101
102 if (mem->mm_node) {
103 spin_lock(&rman->lock);
104 drm_mm_remove_node(mem->mm_node);
105 spin_unlock(&rman->lock);
106
107 kfree(mem->mm_node);
108 mem->mm_node = NULL;
109 }
110}
111
112static const struct ttm_resource_manager_func ttm_range_manager_func;
113
114int ttm_range_man_init(struct ttm_device *bdev,
115 unsigned type, bool use_tt,
116 unsigned long p_size)
117{
118 struct ttm_resource_manager *man;
119 struct ttm_range_manager *rman;
120
121 rman = kzalloc(sizeof(*rman), GFP_KERNEL);
122 if (!rman)
123 return -ENOMEM;
124
125 man = &rman->manager;
126 man->use_tt = use_tt;
127
128 man->func = &ttm_range_manager_func;
129
130 ttm_resource_manager_init(man, p_size);
131
132 drm_mm_init(&rman->mm, 0, p_size);
133 spin_lock_init(&rman->lock);
134
135 ttm_set_driver_manager(bdev, type, &rman->manager);
136 ttm_resource_manager_set_used(man, true);
137 return 0;
138}
139EXPORT_SYMBOL(ttm_range_man_init);
140
141int ttm_range_man_fini(struct ttm_device *bdev,
142 unsigned type)
143{
144 struct ttm_resource_manager *man = ttm_manager_type(bdev, type);
145 struct ttm_range_manager *rman = to_range_manager(man);
146 struct drm_mm *mm = &rman->mm;
147 int ret;
148
149 ttm_resource_manager_set_used(man, false);
150
151 ret = ttm_resource_manager_evict_all(bdev, man);
152 if (ret)
153 return ret;
154
155 spin_lock(&rman->lock);
156 drm_mm_clean(mm);
157 drm_mm_takedown(mm);
158 spin_unlock(&rman->lock);
159
160 ttm_resource_manager_cleanup(man);
161 ttm_set_driver_manager(bdev, type, NULL);
162 kfree(rman);
163 return 0;
164}
165EXPORT_SYMBOL(ttm_range_man_fini);
166
167static void ttm_range_man_debug(struct ttm_resource_manager *man,
168 struct drm_printer *printer)
169{
170 struct ttm_range_manager *rman = to_range_manager(man);
171
172 spin_lock(&rman->lock);
173 drm_mm_print(&rman->mm, printer);
174 spin_unlock(&rman->lock);
175}
176
177static const struct ttm_resource_manager_func ttm_range_manager_func = {
178 .alloc = ttm_range_man_alloc,
179 .free = ttm_range_man_free,
180 .debug = ttm_range_man_debug
181};
182