1 // SPDX-License-Identifier: GPL-2.0 AND MIT
2 /*
3 * Copyright © 2023 Intel Corporation
4 */
5
6 #include <linux/export.h>
7 #include <linux/module.h>
8
9 #include <drm/ttm/ttm_resource.h>
10 #include <drm/ttm/ttm_device.h>
11 #include <drm/ttm/ttm_placement.h>
12
13 #include "ttm_mock_manager.h"
14
15 static inline struct ttm_mock_manager *
to_mock_mgr(struct ttm_resource_manager * man)16 to_mock_mgr(struct ttm_resource_manager *man)
17 {
18 return container_of(man, struct ttm_mock_manager, man);
19 }
20
21 static inline struct ttm_mock_resource *
to_mock_mgr_resource(struct ttm_resource * res)22 to_mock_mgr_resource(struct ttm_resource *res)
23 {
24 return container_of(res, struct ttm_mock_resource, base);
25 }
26
ttm_mock_manager_alloc(struct ttm_resource_manager * man,struct ttm_buffer_object * bo,const struct ttm_place * place,struct ttm_resource ** res)27 static int ttm_mock_manager_alloc(struct ttm_resource_manager *man,
28 struct ttm_buffer_object *bo,
29 const struct ttm_place *place,
30 struct ttm_resource **res)
31 {
32 struct ttm_mock_manager *manager = to_mock_mgr(man);
33 struct ttm_mock_resource *mock_res;
34 struct drm_buddy *mm = &manager->mm;
35 u64 lpfn, fpfn, alloc_size;
36 int err;
37
38 mock_res = kzalloc_obj(*mock_res);
39
40 if (!mock_res)
41 return -ENOMEM;
42
43 fpfn = 0;
44 lpfn = man->size;
45
46 ttm_resource_init(bo, place, &mock_res->base);
47 INIT_LIST_HEAD(&mock_res->blocks);
48
49 if (place->flags & TTM_PL_FLAG_TOPDOWN)
50 mock_res->flags |= DRM_BUDDY_TOPDOWN_ALLOCATION;
51
52 if (place->flags & TTM_PL_FLAG_CONTIGUOUS)
53 mock_res->flags |= DRM_BUDDY_CONTIGUOUS_ALLOCATION;
54
55 alloc_size = (uint64_t)mock_res->base.size;
56 mutex_lock(&manager->lock);
57 err = drm_buddy_alloc_blocks(mm, fpfn, lpfn, alloc_size,
58 manager->default_page_size,
59 &mock_res->blocks,
60 mock_res->flags);
61
62 if (err)
63 goto error_free_blocks;
64 mutex_unlock(&manager->lock);
65
66 *res = &mock_res->base;
67 return 0;
68
69 error_free_blocks:
70 drm_buddy_free_list(mm, &mock_res->blocks, 0);
71 ttm_resource_fini(man, &mock_res->base);
72 mutex_unlock(&manager->lock);
73
74 return err;
75 }
76
ttm_mock_manager_free(struct ttm_resource_manager * man,struct ttm_resource * res)77 static void ttm_mock_manager_free(struct ttm_resource_manager *man,
78 struct ttm_resource *res)
79 {
80 struct ttm_mock_manager *manager = to_mock_mgr(man);
81 struct ttm_mock_resource *mock_res = to_mock_mgr_resource(res);
82 struct drm_buddy *mm = &manager->mm;
83
84 mutex_lock(&manager->lock);
85 drm_buddy_free_list(mm, &mock_res->blocks, 0);
86 mutex_unlock(&manager->lock);
87
88 ttm_resource_fini(man, res);
89 kfree(mock_res);
90 }
91
92 static const struct ttm_resource_manager_func ttm_mock_manager_funcs = {
93 .alloc = ttm_mock_manager_alloc,
94 .free = ttm_mock_manager_free,
95 };
96
ttm_mock_manager_init(struct ttm_device * bdev,u32 mem_type,u32 size)97 int ttm_mock_manager_init(struct ttm_device *bdev, u32 mem_type, u32 size)
98 {
99 struct ttm_mock_manager *manager;
100 struct ttm_resource_manager *base;
101 int err;
102
103 manager = kzalloc_obj(*manager);
104 if (!manager)
105 return -ENOMEM;
106
107 mutex_init(&manager->lock);
108
109 err = drm_buddy_init(&manager->mm, size, PAGE_SIZE);
110
111 if (err) {
112 kfree(manager);
113 return err;
114 }
115
116 manager->default_page_size = PAGE_SIZE;
117 base = &manager->man;
118 base->func = &ttm_mock_manager_funcs;
119 base->use_tt = true;
120
121 ttm_resource_manager_init(base, bdev, size);
122 ttm_set_driver_manager(bdev, mem_type, base);
123 ttm_resource_manager_set_used(base, true);
124
125 return 0;
126 }
127 EXPORT_SYMBOL_GPL(ttm_mock_manager_init);
128
ttm_mock_manager_fini(struct ttm_device * bdev,u32 mem_type)129 void ttm_mock_manager_fini(struct ttm_device *bdev, u32 mem_type)
130 {
131 struct ttm_resource_manager *man;
132 struct ttm_mock_manager *mock_man;
133 int err;
134
135 man = ttm_manager_type(bdev, mem_type);
136 mock_man = to_mock_mgr(man);
137
138 err = ttm_resource_manager_evict_all(bdev, man);
139 if (err)
140 return;
141
142 ttm_resource_manager_set_used(man, false);
143
144 mutex_lock(&mock_man->lock);
145 drm_buddy_fini(&mock_man->mm);
146 mutex_unlock(&mock_man->lock);
147
148 ttm_set_driver_manager(bdev, mem_type, NULL);
149 }
150 EXPORT_SYMBOL_GPL(ttm_mock_manager_fini);
151
ttm_bad_manager_alloc(struct ttm_resource_manager * man,struct ttm_buffer_object * bo,const struct ttm_place * place,struct ttm_resource ** res)152 static int ttm_bad_manager_alloc(struct ttm_resource_manager *man,
153 struct ttm_buffer_object *bo,
154 const struct ttm_place *place,
155 struct ttm_resource **res)
156 {
157 return -ENOSPC;
158 }
159
ttm_busy_manager_alloc(struct ttm_resource_manager * man,struct ttm_buffer_object * bo,const struct ttm_place * place,struct ttm_resource ** res)160 static int ttm_busy_manager_alloc(struct ttm_resource_manager *man,
161 struct ttm_buffer_object *bo,
162 const struct ttm_place *place,
163 struct ttm_resource **res)
164 {
165 return -EBUSY;
166 }
167
ttm_bad_manager_free(struct ttm_resource_manager * man,struct ttm_resource * res)168 static void ttm_bad_manager_free(struct ttm_resource_manager *man,
169 struct ttm_resource *res)
170 {
171 }
172
ttm_bad_manager_compatible(struct ttm_resource_manager * man,struct ttm_resource * res,const struct ttm_place * place,size_t size)173 static bool ttm_bad_manager_compatible(struct ttm_resource_manager *man,
174 struct ttm_resource *res,
175 const struct ttm_place *place,
176 size_t size)
177 {
178 return true;
179 }
180
181 static const struct ttm_resource_manager_func ttm_bad_manager_funcs = {
182 .alloc = ttm_bad_manager_alloc,
183 .free = ttm_bad_manager_free,
184 .compatible = ttm_bad_manager_compatible
185 };
186
187 static const struct ttm_resource_manager_func ttm_bad_busy_manager_funcs = {
188 .alloc = ttm_busy_manager_alloc,
189 .free = ttm_bad_manager_free,
190 .compatible = ttm_bad_manager_compatible
191 };
192
ttm_bad_manager_init(struct ttm_device * bdev,u32 mem_type,u32 size)193 int ttm_bad_manager_init(struct ttm_device *bdev, u32 mem_type, u32 size)
194 {
195 struct ttm_resource_manager *man;
196
197 man = kzalloc_obj(*man);
198 if (!man)
199 return -ENOMEM;
200
201 man->func = &ttm_bad_manager_funcs;
202
203 ttm_resource_manager_init(man, bdev, size);
204 ttm_set_driver_manager(bdev, mem_type, man);
205 ttm_resource_manager_set_used(man, true);
206
207 return 0;
208 }
209 EXPORT_SYMBOL_GPL(ttm_bad_manager_init);
210
ttm_busy_manager_init(struct ttm_device * bdev,u32 mem_type,u32 size)211 int ttm_busy_manager_init(struct ttm_device *bdev, u32 mem_type, u32 size)
212 {
213 struct ttm_resource_manager *man;
214
215 ttm_bad_manager_init(bdev, mem_type, size);
216 man = ttm_manager_type(bdev, mem_type);
217
218 man->func = &ttm_bad_busy_manager_funcs;
219
220 return 0;
221 }
222 EXPORT_SYMBOL_GPL(ttm_busy_manager_init);
223
ttm_bad_manager_fini(struct ttm_device * bdev,uint32_t mem_type)224 void ttm_bad_manager_fini(struct ttm_device *bdev, uint32_t mem_type)
225 {
226 struct ttm_resource_manager *man;
227
228 man = ttm_manager_type(bdev, mem_type);
229
230 ttm_resource_manager_set_used(man, false);
231 ttm_set_driver_manager(bdev, mem_type, NULL);
232
233 kfree(man);
234 }
235 EXPORT_SYMBOL_GPL(ttm_bad_manager_fini);
236
237 MODULE_DESCRIPTION("KUnit tests for ttm with mock resource managers");
238 MODULE_LICENSE("GPL and additional rights");
239