xref: /openbmc/linux/drivers/gpu/drm/ttm/ttm_resource.c (revision 1d61d359)
1 /*
2  * Copyright 2020 Advanced Micro Devices, Inc.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20  * OTHER DEALINGS IN THE SOFTWARE.
21  *
22  * Authors: Christian König
23  */
24 
25 #include <linux/dma-buf-map.h>
26 #include <linux/io-mapping.h>
27 #include <linux/scatterlist.h>
28 
29 #include <drm/ttm/ttm_resource.h>
30 #include <drm/ttm/ttm_bo_driver.h>
31 
32 /**
33  * ttm_resource_init - resource object constructure
34  * @bo: buffer object this resources is allocated for
35  * @place: placement of the resource
36  * @res: the resource object to inistilize
37  *
38  * Initialize a new resource object. Counterpart of &ttm_resource_fini.
39  */
40 void ttm_resource_init(struct ttm_buffer_object *bo,
41                        const struct ttm_place *place,
42                        struct ttm_resource *res)
43 {
44 	res->start = 0;
45 	res->num_pages = PFN_UP(bo->base.size);
46 	res->mem_type = place->mem_type;
47 	res->placement = place->flags;
48 	res->bus.addr = NULL;
49 	res->bus.offset = 0;
50 	res->bus.is_iomem = false;
51 	res->bus.caching = ttm_cached;
52 	res->bo = bo;
53 }
54 EXPORT_SYMBOL(ttm_resource_init);
55 
56 /**
57  * ttm_resource_fini - resource destructor
58  * @man: the resource manager this resource belongs to
59  * @res: the resource to clean up
60  *
61  * Should be used by resource manager backends to clean up the TTM resource
62  * objects before freeing the underlying structure. Counterpart of
63  * &ttm_resource_init
64  */
65 void ttm_resource_fini(struct ttm_resource_manager *man,
66 		       struct ttm_resource *res)
67 {
68 }
69 EXPORT_SYMBOL(ttm_resource_fini);
70 
71 int ttm_resource_alloc(struct ttm_buffer_object *bo,
72 		       const struct ttm_place *place,
73 		       struct ttm_resource **res_ptr)
74 {
75 	struct ttm_resource_manager *man =
76 		ttm_manager_type(bo->bdev, place->mem_type);
77 
78 	return man->func->alloc(man, bo, place, res_ptr);
79 }
80 
81 void ttm_resource_free(struct ttm_buffer_object *bo, struct ttm_resource **res)
82 {
83 	struct ttm_resource_manager *man;
84 
85 	if (!*res)
86 		return;
87 
88 	man = ttm_manager_type(bo->bdev, (*res)->mem_type);
89 	man->func->free(man, *res);
90 	*res = NULL;
91 }
92 EXPORT_SYMBOL(ttm_resource_free);
93 
94 static bool ttm_resource_places_compat(struct ttm_resource *res,
95 				       const struct ttm_place *places,
96 				       unsigned num_placement)
97 {
98 	unsigned i;
99 
100 	if (res->placement & TTM_PL_FLAG_TEMPORARY)
101 		return false;
102 
103 	for (i = 0; i < num_placement; i++) {
104 		const struct ttm_place *heap = &places[i];
105 
106 		if (res->start < heap->fpfn || (heap->lpfn &&
107 		    (res->start + res->num_pages) > heap->lpfn))
108 			continue;
109 
110 		if ((res->mem_type == heap->mem_type) &&
111 		    (!(heap->flags & TTM_PL_FLAG_CONTIGUOUS) ||
112 		     (res->placement & TTM_PL_FLAG_CONTIGUOUS)))
113 			return true;
114 	}
115 	return false;
116 }
117 
118 /**
119  * ttm_resource_compat - check if resource is compatible with placement
120  *
121  * @res: the resource to check
122  * @placement: the placement to check against
123  *
124  * Returns true if the placement is compatible.
125  */
126 bool ttm_resource_compat(struct ttm_resource *res,
127 			 struct ttm_placement *placement)
128 {
129 	if (ttm_resource_places_compat(res, placement->placement,
130 				       placement->num_placement))
131 		return true;
132 
133 	if ((placement->busy_placement != placement->placement ||
134 	     placement->num_busy_placement > placement->num_placement) &&
135 	    ttm_resource_places_compat(res, placement->busy_placement,
136 				       placement->num_busy_placement))
137 		return true;
138 
139 	return false;
140 }
141 EXPORT_SYMBOL(ttm_resource_compat);
142 
143 void ttm_resource_set_bo(struct ttm_resource *res,
144 			 struct ttm_buffer_object *bo)
145 {
146 	spin_lock(&bo->bdev->lru_lock);
147 	res->bo = bo;
148 	spin_unlock(&bo->bdev->lru_lock);
149 }
150 
151 /**
152  * ttm_resource_manager_init
153  *
154  * @man: memory manager object to init
155  * @bdev: ttm device this manager belongs to
156  * @p_size: size managed area in pages.
157  *
158  * Initialise core parts of a manager object.
159  */
160 void ttm_resource_manager_init(struct ttm_resource_manager *man,
161 			       struct ttm_device *bdev,
162 			       unsigned long p_size)
163 {
164 	unsigned i;
165 
166 	spin_lock_init(&man->move_lock);
167 	man->bdev = bdev;
168 	man->size = p_size;
169 
170 	for (i = 0; i < TTM_MAX_BO_PRIORITY; ++i)
171 		INIT_LIST_HEAD(&man->lru[i]);
172 	man->move = NULL;
173 }
174 EXPORT_SYMBOL(ttm_resource_manager_init);
175 
176 /*
177  * ttm_resource_manager_evict_all
178  *
179  * @bdev - device to use
180  * @man - manager to use
181  *
182  * Evict all the objects out of a memory manager until it is empty.
183  * Part of memory manager cleanup sequence.
184  */
185 int ttm_resource_manager_evict_all(struct ttm_device *bdev,
186 				   struct ttm_resource_manager *man)
187 {
188 	struct ttm_operation_ctx ctx = {
189 		.interruptible = false,
190 		.no_wait_gpu = false,
191 		.force_alloc = true
192 	};
193 	struct dma_fence *fence;
194 	int ret;
195 	unsigned i;
196 
197 	/*
198 	 * Can't use standard list traversal since we're unlocking.
199 	 */
200 
201 	spin_lock(&bdev->lru_lock);
202 	for (i = 0; i < TTM_MAX_BO_PRIORITY; ++i) {
203 		while (!list_empty(&man->lru[i])) {
204 			spin_unlock(&bdev->lru_lock);
205 			ret = ttm_mem_evict_first(bdev, man, NULL, &ctx,
206 						  NULL);
207 			if (ret)
208 				return ret;
209 			spin_lock(&bdev->lru_lock);
210 		}
211 	}
212 	spin_unlock(&bdev->lru_lock);
213 
214 	spin_lock(&man->move_lock);
215 	fence = dma_fence_get(man->move);
216 	spin_unlock(&man->move_lock);
217 
218 	if (fence) {
219 		ret = dma_fence_wait(fence, false);
220 		dma_fence_put(fence);
221 		if (ret)
222 			return ret;
223 	}
224 
225 	return 0;
226 }
227 EXPORT_SYMBOL(ttm_resource_manager_evict_all);
228 
229 /**
230  * ttm_resource_manager_debug
231  *
232  * @man: manager type to dump.
233  * @p: printer to use for debug.
234  */
235 void ttm_resource_manager_debug(struct ttm_resource_manager *man,
236 				struct drm_printer *p)
237 {
238 	drm_printf(p, "  use_type: %d\n", man->use_type);
239 	drm_printf(p, "  use_tt: %d\n", man->use_tt);
240 	drm_printf(p, "  size: %llu\n", man->size);
241 	if (man->func->debug)
242 		man->func->debug(man, p);
243 }
244 EXPORT_SYMBOL(ttm_resource_manager_debug);
245 
246 static void ttm_kmap_iter_iomap_map_local(struct ttm_kmap_iter *iter,
247 					  struct dma_buf_map *dmap,
248 					  pgoff_t i)
249 {
250 	struct ttm_kmap_iter_iomap *iter_io =
251 		container_of(iter, typeof(*iter_io), base);
252 	void __iomem *addr;
253 
254 retry:
255 	while (i >= iter_io->cache.end) {
256 		iter_io->cache.sg = iter_io->cache.sg ?
257 			sg_next(iter_io->cache.sg) : iter_io->st->sgl;
258 		iter_io->cache.i = iter_io->cache.end;
259 		iter_io->cache.end += sg_dma_len(iter_io->cache.sg) >>
260 			PAGE_SHIFT;
261 		iter_io->cache.offs = sg_dma_address(iter_io->cache.sg) -
262 			iter_io->start;
263 	}
264 
265 	if (i < iter_io->cache.i) {
266 		iter_io->cache.end = 0;
267 		iter_io->cache.sg = NULL;
268 		goto retry;
269 	}
270 
271 	addr = io_mapping_map_local_wc(iter_io->iomap, iter_io->cache.offs +
272 				       (((resource_size_t)i - iter_io->cache.i)
273 					<< PAGE_SHIFT));
274 	dma_buf_map_set_vaddr_iomem(dmap, addr);
275 }
276 
277 static void ttm_kmap_iter_iomap_unmap_local(struct ttm_kmap_iter *iter,
278 					    struct dma_buf_map *map)
279 {
280 	io_mapping_unmap_local(map->vaddr_iomem);
281 }
282 
283 static const struct ttm_kmap_iter_ops ttm_kmap_iter_io_ops = {
284 	.map_local =  ttm_kmap_iter_iomap_map_local,
285 	.unmap_local = ttm_kmap_iter_iomap_unmap_local,
286 	.maps_tt = false,
287 };
288 
289 /**
290  * ttm_kmap_iter_iomap_init - Initialize a struct ttm_kmap_iter_iomap
291  * @iter_io: The struct ttm_kmap_iter_iomap to initialize.
292  * @iomap: The struct io_mapping representing the underlying linear io_memory.
293  * @st: sg_table into @iomap, representing the memory of the struct
294  * ttm_resource.
295  * @start: Offset that needs to be subtracted from @st to make
296  * sg_dma_address(st->sgl) - @start == 0 for @iomap start.
297  *
298  * Return: Pointer to the embedded struct ttm_kmap_iter.
299  */
300 struct ttm_kmap_iter *
301 ttm_kmap_iter_iomap_init(struct ttm_kmap_iter_iomap *iter_io,
302 			 struct io_mapping *iomap,
303 			 struct sg_table *st,
304 			 resource_size_t start)
305 {
306 	iter_io->base.ops = &ttm_kmap_iter_io_ops;
307 	iter_io->iomap = iomap;
308 	iter_io->st = st;
309 	iter_io->start = start;
310 	memset(&iter_io->cache, 0, sizeof(iter_io->cache));
311 
312 	return &iter_io->base;
313 }
314 EXPORT_SYMBOL(ttm_kmap_iter_iomap_init);
315 
316 /**
317  * DOC: Linear io iterator
318  *
319  * This code should die in the not too near future. Best would be if we could
320  * make io-mapping use memremap for all io memory, and have memremap
321  * implement a kmap_local functionality. We could then strip a huge amount of
322  * code. These linear io iterators are implemented to mimic old functionality,
323  * and they don't use kmap_local semantics at all internally. Rather ioremap or
324  * friends, and at least on 32-bit they add global TLB flushes and points
325  * of failure.
326  */
327 
328 static void ttm_kmap_iter_linear_io_map_local(struct ttm_kmap_iter *iter,
329 					      struct dma_buf_map *dmap,
330 					      pgoff_t i)
331 {
332 	struct ttm_kmap_iter_linear_io *iter_io =
333 		container_of(iter, typeof(*iter_io), base);
334 
335 	*dmap = iter_io->dmap;
336 	dma_buf_map_incr(dmap, i * PAGE_SIZE);
337 }
338 
339 static const struct ttm_kmap_iter_ops ttm_kmap_iter_linear_io_ops = {
340 	.map_local =  ttm_kmap_iter_linear_io_map_local,
341 	.maps_tt = false,
342 };
343 
344 /**
345  * ttm_kmap_iter_linear_io_init - Initialize an iterator for linear io memory
346  * @iter_io: The iterator to initialize
347  * @bdev: The TTM device
348  * @mem: The ttm resource representing the iomap.
349  *
350  * This function is for internal TTM use only. It sets up a memcpy kmap iterator
351  * pointing at a linear chunk of io memory.
352  *
353  * Return: A pointer to the embedded struct ttm_kmap_iter or error pointer on
354  * failure.
355  */
356 struct ttm_kmap_iter *
357 ttm_kmap_iter_linear_io_init(struct ttm_kmap_iter_linear_io *iter_io,
358 			     struct ttm_device *bdev,
359 			     struct ttm_resource *mem)
360 {
361 	int ret;
362 
363 	ret = ttm_mem_io_reserve(bdev, mem);
364 	if (ret)
365 		goto out_err;
366 	if (!mem->bus.is_iomem) {
367 		ret = -EINVAL;
368 		goto out_io_free;
369 	}
370 
371 	if (mem->bus.addr) {
372 		dma_buf_map_set_vaddr(&iter_io->dmap, mem->bus.addr);
373 		iter_io->needs_unmap = false;
374 	} else {
375 		size_t bus_size = (size_t)mem->num_pages << PAGE_SHIFT;
376 
377 		iter_io->needs_unmap = true;
378 		memset(&iter_io->dmap, 0, sizeof(iter_io->dmap));
379 		if (mem->bus.caching == ttm_write_combined)
380 			dma_buf_map_set_vaddr_iomem(&iter_io->dmap,
381 						    ioremap_wc(mem->bus.offset,
382 							       bus_size));
383 		else if (mem->bus.caching == ttm_cached)
384 			dma_buf_map_set_vaddr(&iter_io->dmap,
385 					      memremap(mem->bus.offset, bus_size,
386 						       MEMREMAP_WB |
387 						       MEMREMAP_WT |
388 						       MEMREMAP_WC));
389 
390 		/* If uncached requested or if mapping cached or wc failed */
391 		if (dma_buf_map_is_null(&iter_io->dmap))
392 			dma_buf_map_set_vaddr_iomem(&iter_io->dmap,
393 						    ioremap(mem->bus.offset,
394 							    bus_size));
395 
396 		if (dma_buf_map_is_null(&iter_io->dmap)) {
397 			ret = -ENOMEM;
398 			goto out_io_free;
399 		}
400 	}
401 
402 	iter_io->base.ops = &ttm_kmap_iter_linear_io_ops;
403 	return &iter_io->base;
404 
405 out_io_free:
406 	ttm_mem_io_free(bdev, mem);
407 out_err:
408 	return ERR_PTR(ret);
409 }
410 
411 /**
412  * ttm_kmap_iter_linear_io_fini - Clean up an iterator for linear io memory
413  * @iter_io: The iterator to initialize
414  * @bdev: The TTM device
415  * @mem: The ttm resource representing the iomap.
416  *
417  * This function is for internal TTM use only. It cleans up a memcpy kmap
418  * iterator initialized by ttm_kmap_iter_linear_io_init.
419  */
420 void
421 ttm_kmap_iter_linear_io_fini(struct ttm_kmap_iter_linear_io *iter_io,
422 			     struct ttm_device *bdev,
423 			     struct ttm_resource *mem)
424 {
425 	if (iter_io->needs_unmap && dma_buf_map_is_set(&iter_io->dmap)) {
426 		if (iter_io->dmap.is_iomem)
427 			iounmap(iter_io->dmap.vaddr_iomem);
428 		else
429 			memunmap(iter_io->dmap.vaddr);
430 	}
431 
432 	ttm_mem_io_free(bdev, mem);
433 }
434