Branch data Line data Source code
1 : : // SPDX-License-Identifier: MIT
2 : : /*
3 : : * Copyright © 2019 Intel Corporation
4 : : */
5 : :
6 : : #include "intel_memory_region.h"
7 : : #include "i915_drv.h"
8 : :
9 : : /* XXX: Hysterical raisins. BIT(inst) needs to just be (inst) at some point. */
10 : : #define REGION_MAP(type, inst) \
11 : : BIT((type) + INTEL_MEMORY_TYPE_SHIFT) | BIT(inst)
12 : :
13 : : const u32 intel_region_map[] = {
14 : : [INTEL_REGION_SMEM] = REGION_MAP(INTEL_MEMORY_SYSTEM, 0),
15 : : [INTEL_REGION_LMEM] = REGION_MAP(INTEL_MEMORY_LOCAL, 0),
16 : : [INTEL_REGION_STOLEN] = REGION_MAP(INTEL_MEMORY_STOLEN, 0),
17 : : };
18 : :
19 : : struct intel_memory_region *
20 : 0 : intel_memory_region_by_type(struct drm_i915_private *i915,
21 : : enum intel_memory_type mem_type)
22 : : {
23 : 0 : struct intel_memory_region *mr;
24 : 0 : int id;
25 : :
26 [ # # # # ]: 0 : for_each_memory_region(mr, i915, id)
27 [ # # ]: 0 : if (mr->type == mem_type)
28 : 0 : return mr;
29 : :
30 : : return NULL;
31 : : }
32 : :
33 : : static u64
34 : 0 : intel_memory_region_free_pages(struct intel_memory_region *mem,
35 : : struct list_head *blocks)
36 : : {
37 : 0 : struct i915_buddy_block *block, *on;
38 : 0 : u64 size = 0;
39 : :
40 [ # # ]: 0 : list_for_each_entry_safe(block, on, blocks, link) {
41 : 0 : size += i915_buddy_block_size(&mem->mm, block);
42 : 0 : i915_buddy_free(&mem->mm, block);
43 : : }
44 : 0 : INIT_LIST_HEAD(blocks);
45 : :
46 : 0 : return size;
47 : : }
48 : :
49 : : void
50 : 0 : __intel_memory_region_put_pages_buddy(struct intel_memory_region *mem,
51 : : struct list_head *blocks)
52 : : {
53 : 0 : mutex_lock(&mem->mm_lock);
54 : 0 : mem->avail += intel_memory_region_free_pages(mem, blocks);
55 : 0 : mutex_unlock(&mem->mm_lock);
56 : 0 : }
57 : :
58 : : void
59 : 0 : __intel_memory_region_put_block_buddy(struct i915_buddy_block *block)
60 : : {
61 : 0 : struct list_head blocks;
62 : :
63 : 0 : INIT_LIST_HEAD(&blocks);
64 : 0 : list_add(&block->link, &blocks);
65 : 0 : __intel_memory_region_put_pages_buddy(block->private, &blocks);
66 : 0 : }
67 : :
68 : : int
69 : 0 : __intel_memory_region_get_pages_buddy(struct intel_memory_region *mem,
70 : : resource_size_t size,
71 : : unsigned int flags,
72 : : struct list_head *blocks)
73 : : {
74 : 0 : unsigned int min_order = 0;
75 : 0 : unsigned long n_pages;
76 : :
77 : 0 : GEM_BUG_ON(!IS_ALIGNED(size, mem->mm.chunk_size));
78 : 0 : GEM_BUG_ON(!list_empty(blocks));
79 : :
80 [ # # ]: 0 : if (flags & I915_ALLOC_MIN_PAGE_SIZE) {
81 [ # # # # : 0 : min_order = ilog2(mem->min_page_size) -
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # ]
82 [ # # # # : 0 : ilog2(mem->mm.chunk_size);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # ]
83 : : }
84 : :
85 [ # # ]: 0 : if (flags & I915_ALLOC_CONTIGUOUS) {
86 [ # # # # : 0 : size = roundup_pow_of_two(size);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # ]
87 [ # # # # : 0 : min_order = ilog2(size) - ilog2(mem->mm.chunk_size);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # ]
88 : : }
89 : :
90 [ # # ]: 0 : if (size > BIT(mem->mm.max_order) * mem->mm.chunk_size)
91 : : return -E2BIG;
92 : :
93 [ # # # # : 0 : n_pages = size >> ilog2(mem->mm.chunk_size);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # ]
94 : :
95 : 0 : mutex_lock(&mem->mm_lock);
96 : :
97 : 0 : do {
98 : 0 : struct i915_buddy_block *block;
99 : 0 : unsigned int order;
100 : :
101 : 0 : order = fls(n_pages) - 1;
102 : 0 : GEM_BUG_ON(order > mem->mm.max_order);
103 : 0 : GEM_BUG_ON(order < min_order);
104 : :
105 : 0 : do {
106 : 0 : block = i915_buddy_alloc(&mem->mm, order);
107 [ # # ]: 0 : if (!IS_ERR(block))
108 : : break;
109 : :
110 [ # # ]: 0 : if (order-- == min_order)
111 : 0 : goto err_free_blocks;
112 : : } while (1);
113 : :
114 : 0 : n_pages -= BIT(order);
115 : :
116 : 0 : block->private = mem;
117 [ # # ]: 0 : list_add(&block->link, blocks);
118 : :
119 [ # # ]: 0 : if (!n_pages)
120 : : break;
121 : : } while (1);
122 : :
123 : 0 : mem->avail -= size;
124 : 0 : mutex_unlock(&mem->mm_lock);
125 : 0 : return 0;
126 : :
127 : : err_free_blocks:
128 : 0 : intel_memory_region_free_pages(mem, blocks);
129 : 0 : mutex_unlock(&mem->mm_lock);
130 : 0 : return -ENXIO;
131 : : }
132 : :
133 : : struct i915_buddy_block *
134 : 0 : __intel_memory_region_get_block_buddy(struct intel_memory_region *mem,
135 : : resource_size_t size,
136 : : unsigned int flags)
137 : : {
138 : 0 : struct i915_buddy_block *block;
139 : 0 : LIST_HEAD(blocks);
140 : 0 : int ret;
141 : :
142 : 0 : ret = __intel_memory_region_get_pages_buddy(mem, size, flags, &blocks);
143 [ # # ]: 0 : if (ret)
144 : 0 : return ERR_PTR(ret);
145 : :
146 : 0 : block = list_first_entry(&blocks, typeof(*block), link);
147 : 0 : list_del_init(&block->link);
148 : 0 : return block;
149 : : }
150 : :
151 : 0 : int intel_memory_region_init_buddy(struct intel_memory_region *mem)
152 : : {
153 : 0 : return i915_buddy_init(&mem->mm, resource_size(&mem->region),
154 : : PAGE_SIZE);
155 : : }
156 : :
157 : 0 : void intel_memory_region_release_buddy(struct intel_memory_region *mem)
158 : : {
159 : 0 : i915_buddy_fini(&mem->mm);
160 : 0 : }
161 : :
162 : : struct intel_memory_region *
163 : 0 : intel_memory_region_create(struct drm_i915_private *i915,
164 : : resource_size_t start,
165 : : resource_size_t size,
166 : : resource_size_t min_page_size,
167 : : resource_size_t io_start,
168 : : const struct intel_memory_region_ops *ops)
169 : : {
170 : 0 : struct intel_memory_region *mem;
171 : 0 : int err;
172 : :
173 : 0 : mem = kzalloc(sizeof(*mem), GFP_KERNEL);
174 [ # # ]: 0 : if (!mem)
175 : : return ERR_PTR(-ENOMEM);
176 : :
177 : 0 : mem->i915 = i915;
178 : 0 : mem->region = (struct resource)DEFINE_RES_MEM(start, size);
179 : 0 : mem->io_start = io_start;
180 : 0 : mem->min_page_size = min_page_size;
181 : 0 : mem->ops = ops;
182 : 0 : mem->total = size;
183 : 0 : mem->avail = mem->total;
184 : :
185 : 0 : mutex_init(&mem->objects.lock);
186 : 0 : INIT_LIST_HEAD(&mem->objects.list);
187 : 0 : INIT_LIST_HEAD(&mem->objects.purgeable);
188 : :
189 : 0 : mutex_init(&mem->mm_lock);
190 : :
191 [ # # ]: 0 : if (ops->init) {
192 : 0 : err = ops->init(mem);
193 [ # # ]: 0 : if (err)
194 : 0 : goto err_free;
195 : : }
196 : :
197 : 0 : kref_init(&mem->kref);
198 : 0 : return mem;
199 : :
200 : : err_free:
201 : 0 : kfree(mem);
202 : 0 : return ERR_PTR(err);
203 : : }
204 : :
205 : 0 : void intel_memory_region_set_name(struct intel_memory_region *mem,
206 : : const char *fmt, ...)
207 : : {
208 : 0 : va_list ap;
209 : :
210 : 0 : va_start(ap, fmt);
211 : 0 : vsnprintf(mem->name, sizeof(mem->name), fmt, ap);
212 : 0 : va_end(ap);
213 : 0 : }
214 : :
215 : 0 : static void __intel_memory_region_destroy(struct kref *kref)
216 : : {
217 : 0 : struct intel_memory_region *mem =
218 : 0 : container_of(kref, typeof(*mem), kref);
219 : :
220 [ # # ]: 0 : if (mem->ops->release)
221 : 0 : mem->ops->release(mem);
222 : :
223 : 0 : mutex_destroy(&mem->mm_lock);
224 : 0 : mutex_destroy(&mem->objects.lock);
225 : 0 : kfree(mem);
226 : 0 : }
227 : :
228 : : struct intel_memory_region *
229 : 0 : intel_memory_region_get(struct intel_memory_region *mem)
230 : : {
231 : 0 : kref_get(&mem->kref);
232 : 0 : return mem;
233 : : }
234 : :
235 : 0 : void intel_memory_region_put(struct intel_memory_region *mem)
236 : : {
237 : 0 : kref_put(&mem->kref, __intel_memory_region_destroy);
238 : 0 : }
239 : :
240 : : /* Global memory region registration -- only slight layer inversions! */
241 : :
242 : 0 : int intel_memory_regions_hw_probe(struct drm_i915_private *i915)
243 : : {
244 : 0 : int err, i;
245 : :
246 [ # # ]: 0 : for (i = 0; i < ARRAY_SIZE(i915->mm.regions); i++) {
247 [ # # ]: 0 : struct intel_memory_region *mem = ERR_PTR(-ENODEV);
248 : 0 : u32 type;
249 : :
250 [ # # ]: 0 : if (!HAS_REGION(i915, BIT(i)))
251 : 0 : continue;
252 : :
253 [ # # # # : 0 : type = MEMORY_TYPE_FROM_REGION(intel_region_map[i]);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # ]
254 [ # # # # ]: 0 : switch (type) {
255 : 0 : case INTEL_MEMORY_SYSTEM:
256 : 0 : mem = i915_gem_shmem_setup(i915);
257 : 0 : break;
258 : 0 : case INTEL_MEMORY_STOLEN:
259 : 0 : mem = i915_gem_stolen_setup(i915);
260 : 0 : break;
261 : 0 : case INTEL_MEMORY_LOCAL:
262 : 0 : mem = intel_setup_fake_lmem(i915);
263 : 0 : break;
264 : : }
265 : :
266 [ # # ]: 0 : if (IS_ERR(mem)) {
267 : 0 : err = PTR_ERR(mem);
268 : 0 : DRM_ERROR("Failed to setup region(%d) type=%d\n", err, type);
269 : 0 : goto out_cleanup;
270 : : }
271 : :
272 : 0 : mem->id = intel_region_map[i];
273 : 0 : mem->type = type;
274 [ # # # # : 0 : mem->instance = MEMORY_INSTANCE_FROM_REGION(intel_region_map[i]);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # ]
275 : :
276 : 0 : i915->mm.regions[i] = mem;
277 : : }
278 : :
279 : : return 0;
280 : :
281 : : out_cleanup:
282 : 0 : intel_memory_regions_driver_release(i915);
283 : : return err;
284 : : }
285 : :
286 : 0 : void intel_memory_regions_driver_release(struct drm_i915_private *i915)
287 : : {
288 : 0 : int i;
289 : :
290 [ # # # # ]: 0 : for (i = 0; i < ARRAY_SIZE(i915->mm.regions); i++) {
291 : 0 : struct intel_memory_region *region =
292 : 0 : fetch_and_zero(&i915->mm.regions[i]);
293 : :
294 [ # # # # ]: 0 : if (region)
295 : 0 : intel_memory_region_put(region);
296 : : }
297 : 0 : }
298 : :
299 : : #if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)
300 : : #include "selftests/intel_memory_region.c"
301 : : #include "selftests/mock_region.c"
302 : : #endif
|