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