• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
2 /*
3  *
4  * (C) COPYRIGHT 2019-2021 ARM Limited. All rights reserved.
5  *
6  * This program is free software and is provided to you under the terms of the
7  * GNU General Public License version 2 as published by the Free Software
8  * Foundation, and any use by you of this program is subject to the terms
9  * of such GNU license.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, you can access it online at
18  * http://www.gnu.org/licenses/gpl-2.0.html.
19  *
20  */
21 
22 #include <tl/mali_kbase_tracepoints.h>
23 
24 #include "mali_kbase_csf_tiler_heap.h"
25 #include "mali_kbase_csf_tiler_heap_def.h"
26 #include "mali_kbase_csf_heap_context_alloc.h"
27 
28 /**
29  * encode_chunk_ptr - Encode the address and size of a chunk as an integer.
30  *
31  * @chunk_size: Size of a tiler heap chunk, in bytes.
32  * @chunk_addr: GPU virtual address of the same tiler heap chunk.
33  *
34  * The size and address of the next chunk in a list are packed into a single
35  * 64-bit value for storage in a chunk's header. This function returns that
36  * value.
37  *
38  * Return: Next chunk pointer suitable for writing into a chunk header.
39  */
encode_chunk_ptr(u32 const chunk_size,u64 const chunk_addr)40 static u64 encode_chunk_ptr(u32 const chunk_size, u64 const chunk_addr)
41 {
42 	u64 encoded_size, encoded_addr;
43 
44 	WARN_ON(chunk_size & ~CHUNK_SIZE_MASK);
45 	WARN_ON(chunk_addr & ~CHUNK_ADDR_MASK);
46 
47 	encoded_size =
48 		(u64)(chunk_size >> CHUNK_HDR_NEXT_SIZE_ENCODE_SHIFT) <<
49 		CHUNK_HDR_NEXT_SIZE_POS;
50 
51 	encoded_addr =
52 		(chunk_addr >> CHUNK_HDR_NEXT_ADDR_ENCODE_SHIFT) <<
53 		CHUNK_HDR_NEXT_ADDR_POS;
54 
55 	return (encoded_size & CHUNK_HDR_NEXT_SIZE_MASK) |
56 		(encoded_addr & CHUNK_HDR_NEXT_ADDR_MASK);
57 }
58 
59 /**
60  * get_last_chunk - Get the last chunk of a tiler heap
61  *
62  * @heap:  Pointer to the tiler heap.
63  *
64  * Return: The address of the most recently-linked chunk, or NULL if none.
65  */
get_last_chunk(struct kbase_csf_tiler_heap * const heap)66 static struct kbase_csf_tiler_heap_chunk *get_last_chunk(
67 	struct kbase_csf_tiler_heap *const heap)
68 {
69 	if (list_empty(&heap->chunks_list))
70 		return NULL;
71 
72 	return list_last_entry(&heap->chunks_list,
73 		struct kbase_csf_tiler_heap_chunk, link);
74 }
75 
76 /**
77  * link_chunk - Link a chunk into a tiler heap
78  *
79  * @heap:  Pointer to the tiler heap.
80  * @chunk: Pointer to the heap chunk to be linked.
81  *
82  * Unless the @chunk is the first in the kernel's list of chunks belonging to
83  * a given tiler heap, this function stores the size and address of the @chunk
84  * in the header of the preceding chunk. This requires the GPU memory region
85  * containing the header to be be mapped temporarily, which can fail.
86  *
87  * Return: 0 if successful or a negative error code on failure.
88  */
link_chunk(struct kbase_csf_tiler_heap * const heap,struct kbase_csf_tiler_heap_chunk * const chunk)89 static int link_chunk(struct kbase_csf_tiler_heap *const heap,
90 	struct kbase_csf_tiler_heap_chunk *const chunk)
91 {
92 	struct kbase_csf_tiler_heap_chunk *const prev = get_last_chunk(heap);
93 
94 	if (prev) {
95 		struct kbase_context *const kctx = heap->kctx;
96 		struct kbase_vmap_struct map;
97 		u64 *const prev_hdr = kbase_vmap_prot(kctx, prev->gpu_va,
98 			sizeof(*prev_hdr), KBASE_REG_CPU_WR, &map);
99 
100 		if (unlikely(!prev_hdr)) {
101 			dev_err(kctx->kbdev->dev,
102 				"Failed to map tiler heap chunk 0x%llX\n",
103 				prev->gpu_va);
104 			return -ENOMEM;
105 		}
106 
107 		*prev_hdr = encode_chunk_ptr(heap->chunk_size, chunk->gpu_va);
108 		kbase_vunmap(kctx, &map);
109 
110 		dev_dbg(kctx->kbdev->dev,
111 			"Linked tiler heap chunks, 0x%llX -> 0x%llX\n",
112 			prev->gpu_va, chunk->gpu_va);
113 	}
114 
115 	return 0;
116 }
117 
118 /**
119  * init_chunk - Initialize and link a tiler heap chunk
120  *
121  * @heap:  Pointer to the tiler heap.
122  * @chunk: Pointer to the heap chunk to be initialized and linked.
123  * @link_with_prev: Flag to indicate if the new chunk needs to be linked with
124  *                  the previously allocated chunk.
125  *
126  * Zero-initialize a new chunk's header (including its pointer to the next
127  * chunk, which doesn't exist yet) and then update the previous chunk's
128  * header to link the new chunk into the chunk list.
129  *
130  * Return: 0 if successful or a negative error code on failure.
131  */
init_chunk(struct kbase_csf_tiler_heap * const heap,struct kbase_csf_tiler_heap_chunk * const chunk,bool link_with_prev)132 static int init_chunk(struct kbase_csf_tiler_heap *const heap,
133 	struct kbase_csf_tiler_heap_chunk *const chunk, bool link_with_prev)
134 {
135 	struct kbase_vmap_struct map;
136 	struct u64 *chunk_hdr = NULL;
137 	struct kbase_context *const kctx = heap->kctx;
138 
139 	if (unlikely(chunk->gpu_va & ~CHUNK_ADDR_MASK)) {
140 		dev_err(kctx->kbdev->dev,
141 			"Tiler heap chunk address is unusable\n");
142 		return -EINVAL;
143 	}
144 
145 	chunk_hdr = kbase_vmap_prot(kctx,
146 		chunk->gpu_va, CHUNK_HDR_SIZE, KBASE_REG_CPU_WR, &map);
147 
148 	if (unlikely(!chunk_hdr)) {
149 		dev_err(kctx->kbdev->dev,
150 			"Failed to map a tiler heap chunk header\n");
151 		return -ENOMEM;
152 	}
153 
154 	memset(chunk_hdr, 0, CHUNK_HDR_SIZE);
155 	kbase_vunmap(kctx, &map);
156 
157 	if (link_with_prev)
158 		return link_chunk(heap, chunk);
159 	else
160 		return 0;
161 }
162 
163 /**
164  * create_chunk - Create a tiler heap chunk
165  *
166  * @heap: Pointer to the tiler heap for which to allocate memory.
167  * @link_with_prev: Flag to indicate if the chunk to be allocated needs to be
168  *                  linked with the previously allocated chunk.
169  *
170  * This function allocates a chunk of memory for a tiler heap and adds it to
171  * the end of the list of chunks associated with that heap. The size of the
172  * chunk is not a parameter because it is configured per-heap not per-chunk.
173  *
174  * Return: 0 if successful or a negative error code on failure.
175  */
create_chunk(struct kbase_csf_tiler_heap * const heap,bool link_with_prev)176 static int create_chunk(struct kbase_csf_tiler_heap *const heap,
177 			bool link_with_prev)
178 {
179 	int err = 0;
180 	struct kbase_context *const kctx = heap->kctx;
181 	u64 nr_pages = PFN_UP(heap->chunk_size);
182 	u64 flags = BASE_MEM_PROT_GPU_RD | BASE_MEM_PROT_GPU_WR |
183 		BASE_MEM_PROT_CPU_WR | BASEP_MEM_NO_USER_FREE |
184 		BASE_MEM_COHERENT_LOCAL;
185 	struct kbase_csf_tiler_heap_chunk *chunk = NULL;
186 
187 	/* Calls to this function are inherently synchronous, with respect to
188 	 * MMU operations.
189 	 */
190 	const enum kbase_caller_mmu_sync_info mmu_sync_info = CALLER_MMU_SYNC;
191 
192 	flags |= kbase_mem_group_id_set(kctx->jit_group_id);
193 
194 #if defined(CONFIG_MALI_BIFROST_DEBUG) || defined(CONFIG_MALI_VECTOR_DUMP)
195 	flags |= BASE_MEM_PROT_CPU_RD;
196 #endif
197 
198 	chunk = kzalloc(sizeof(*chunk), GFP_KERNEL);
199 	if (unlikely(!chunk)) {
200 		dev_err(kctx->kbdev->dev,
201 			"No kernel memory for a new tiler heap chunk\n");
202 		return -ENOMEM;
203 	}
204 
205 	/* Allocate GPU memory for the new chunk. */
206 	INIT_LIST_HEAD(&chunk->link);
207 	chunk->region = kbase_mem_alloc(kctx, nr_pages, nr_pages, 0, &flags,
208 					&chunk->gpu_va, mmu_sync_info);
209 
210 	if (unlikely(!chunk->region)) {
211 		dev_err(kctx->kbdev->dev,
212 			"Failed to allocate a tiler heap chunk\n");
213 		err = -ENOMEM;
214 	} else {
215 		err = init_chunk(heap, chunk, link_with_prev);
216 		if (unlikely(err)) {
217 			kbase_gpu_vm_lock(kctx);
218 			chunk->region->flags &= ~KBASE_REG_NO_USER_FREE;
219 			kbase_mem_free_region(kctx, chunk->region);
220 			kbase_gpu_vm_unlock(kctx);
221 		}
222 	}
223 
224 	if (unlikely(err)) {
225 		kfree(chunk);
226 	} else {
227 		list_add_tail(&chunk->link, &heap->chunks_list);
228 		heap->chunk_count++;
229 
230 		dev_dbg(kctx->kbdev->dev, "Created tiler heap chunk 0x%llX\n",
231 			chunk->gpu_va);
232 	}
233 
234 	return err;
235 }
236 
237 /**
238  * delete_chunk - Delete a tiler heap chunk
239  *
240  * @heap:  Pointer to the tiler heap for which @chunk was allocated.
241  * @chunk: Pointer to a chunk to be deleted.
242  *
243  * This function frees a tiler heap chunk previously allocated by @create_chunk
244  * and removes it from the list of chunks associated with the heap.
245  *
246  * WARNING: The deleted chunk is not unlinked from the list of chunks used by
247  *          the GPU, therefore it is only safe to use this function when
248  *          deleting a heap.
249  */
delete_chunk(struct kbase_csf_tiler_heap * const heap,struct kbase_csf_tiler_heap_chunk * const chunk)250 static void delete_chunk(struct kbase_csf_tiler_heap *const heap,
251 	struct kbase_csf_tiler_heap_chunk *const chunk)
252 {
253 	struct kbase_context *const kctx = heap->kctx;
254 
255 	kbase_gpu_vm_lock(kctx);
256 	chunk->region->flags &= ~KBASE_REG_NO_USER_FREE;
257 	kbase_mem_free_region(kctx, chunk->region);
258 	kbase_gpu_vm_unlock(kctx);
259 	list_del(&chunk->link);
260 	heap->chunk_count--;
261 	kfree(chunk);
262 }
263 
264 /**
265  * delete_all_chunks - Delete all chunks belonging to a tiler heap
266  *
267  * @heap: Pointer to a tiler heap.
268  *
269  * This function empties the list of chunks associated with a tiler heap by
270  * freeing all chunks previously allocated by @create_chunk.
271  */
delete_all_chunks(struct kbase_csf_tiler_heap * heap)272 static void delete_all_chunks(struct kbase_csf_tiler_heap *heap)
273 {
274 	struct list_head *entry = NULL, *tmp = NULL;
275 
276 	list_for_each_safe(entry, tmp, &heap->chunks_list) {
277 		struct kbase_csf_tiler_heap_chunk *chunk = list_entry(
278 			entry, struct kbase_csf_tiler_heap_chunk, link);
279 
280 		delete_chunk(heap, chunk);
281 	}
282 }
283 
284 /**
285  * create_initial_chunks - Create the initial list of chunks for a tiler heap
286  *
287  * @heap:    Pointer to the tiler heap for which to allocate memory.
288  * @nchunks: Number of chunks to create.
289  *
290  * This function allocates a given number of chunks for a tiler heap and
291  * adds them to the list of chunks associated with that heap.
292  *
293  * Return: 0 if successful or a negative error code on failure.
294  */
create_initial_chunks(struct kbase_csf_tiler_heap * const heap,u32 const nchunks)295 static int create_initial_chunks(struct kbase_csf_tiler_heap *const heap,
296 	u32 const nchunks)
297 {
298 	int err = 0;
299 	u32 i;
300 
301 	for (i = 0; (i < nchunks) && likely(!err); i++)
302 		err = create_chunk(heap, true);
303 
304 	if (unlikely(err))
305 		delete_all_chunks(heap);
306 
307 	return err;
308 }
309 
310 /**
311  * delete_heap - Delete a tiler heap
312  *
313  * @heap: Pointer to a tiler heap to be deleted.
314  *
315  * This function frees any chunks allocated for a tiler heap previously
316  * initialized by @kbase_csf_tiler_heap_init and removes it from the list of
317  * heaps associated with the kbase context. The heap context structure used by
318  * the firmware is also freed.
319  */
delete_heap(struct kbase_csf_tiler_heap * heap)320 static void delete_heap(struct kbase_csf_tiler_heap *heap)
321 {
322 	struct kbase_context *const kctx = heap->kctx;
323 
324 	dev_dbg(kctx->kbdev->dev, "Deleting tiler heap 0x%llX\n", heap->gpu_va);
325 
326 	lockdep_assert_held(&kctx->csf.tiler_heaps.lock);
327 
328 	delete_all_chunks(heap);
329 
330 	/* We could optimize context destruction by not freeing leaked heap
331 	 * contexts but it doesn't seem worth the extra complexity.
332 	 */
333 	kbase_csf_heap_context_allocator_free(&kctx->csf.tiler_heaps.ctx_alloc,
334 		heap->gpu_va);
335 
336 	list_del(&heap->link);
337 
338 	WARN_ON(heap->chunk_count);
339 	KBASE_TLSTREAM_AUX_TILER_HEAP_STATS(kctx->kbdev, kctx->id,
340 		heap->heap_id, 0, 0, heap->max_chunks, heap->chunk_size, 0,
341 		heap->target_in_flight, 0);
342 
343 	kfree(heap);
344 }
345 
346 /**
347  * find_tiler_heap - Find a tiler heap from the address of its heap context
348  *
349  * @kctx:        Pointer to the kbase context to search for a tiler heap.
350  * @heap_gpu_va: GPU virtual address of a heap context structure.
351  *
352  * Each tiler heap managed by the kernel has an associated heap context
353  * structure used by the firmware. This function finds a tiler heap object from
354  * the GPU virtual address of its associated heap context. The heap context
355  * should have been allocated by @kbase_csf_heap_context_allocator_alloc in the
356  * same @kctx.
357  *
358  * Return: pointer to the tiler heap object, or NULL if not found.
359  */
find_tiler_heap(struct kbase_context * const kctx,u64 const heap_gpu_va)360 static struct kbase_csf_tiler_heap *find_tiler_heap(
361 	struct kbase_context *const kctx, u64 const heap_gpu_va)
362 {
363 	struct kbase_csf_tiler_heap *heap = NULL;
364 
365 	lockdep_assert_held(&kctx->csf.tiler_heaps.lock);
366 
367 	list_for_each_entry(heap, &kctx->csf.tiler_heaps.list, link) {
368 		if (heap_gpu_va == heap->gpu_va)
369 			return heap;
370 	}
371 
372 	dev_dbg(kctx->kbdev->dev, "Tiler heap 0x%llX was not found\n",
373 		heap_gpu_va);
374 
375 	return NULL;
376 }
377 
kbase_csf_tiler_heap_context_init(struct kbase_context * const kctx)378 int kbase_csf_tiler_heap_context_init(struct kbase_context *const kctx)
379 {
380 	int err = kbase_csf_heap_context_allocator_init(
381 		&kctx->csf.tiler_heaps.ctx_alloc, kctx);
382 
383 	if (unlikely(err))
384 		return err;
385 
386 	INIT_LIST_HEAD(&kctx->csf.tiler_heaps.list);
387 	mutex_init(&kctx->csf.tiler_heaps.lock);
388 
389 	dev_dbg(kctx->kbdev->dev, "Initialized a context for tiler heaps\n");
390 
391 	return 0;
392 }
393 
kbase_csf_tiler_heap_context_term(struct kbase_context * const kctx)394 void kbase_csf_tiler_heap_context_term(struct kbase_context *const kctx)
395 {
396 	struct list_head *entry = NULL, *tmp = NULL;
397 
398 	dev_dbg(kctx->kbdev->dev, "Terminating a context for tiler heaps\n");
399 
400 	mutex_lock(&kctx->csf.tiler_heaps.lock);
401 
402 	list_for_each_safe(entry, tmp, &kctx->csf.tiler_heaps.list) {
403 		struct kbase_csf_tiler_heap *heap = list_entry(
404 			entry, struct kbase_csf_tiler_heap, link);
405 		delete_heap(heap);
406 	}
407 
408 	mutex_unlock(&kctx->csf.tiler_heaps.lock);
409 	mutex_destroy(&kctx->csf.tiler_heaps.lock);
410 
411 	kbase_csf_heap_context_allocator_term(&kctx->csf.tiler_heaps.ctx_alloc);
412 }
413 
kbase_csf_tiler_heap_init(struct kbase_context * const kctx,u32 const chunk_size,u32 const initial_chunks,u32 const max_chunks,u16 const target_in_flight,u64 * const heap_gpu_va,u64 * const first_chunk_va)414 int kbase_csf_tiler_heap_init(struct kbase_context *const kctx,
415 	u32 const chunk_size, u32 const initial_chunks, u32 const max_chunks,
416 	u16 const target_in_flight, u64 *const heap_gpu_va,
417 	u64 *const first_chunk_va)
418 {
419 	int err = 0;
420 	struct kbase_csf_tiler_heap *heap = NULL;
421 	struct kbase_csf_heap_context_allocator *const ctx_alloc =
422 		&kctx->csf.tiler_heaps.ctx_alloc;
423 
424 	dev_dbg(kctx->kbdev->dev,
425 		"Creating a tiler heap with %u chunks (limit: %u) of size %u\n",
426 		initial_chunks, max_chunks, chunk_size);
427 
428 	if (!kbase_mem_allow_alloc(kctx))
429 		return -EINVAL;
430 
431 	if (chunk_size == 0)
432 		return -EINVAL;
433 
434 	if (chunk_size & ~CHUNK_SIZE_MASK)
435 		return -EINVAL;
436 
437 	if (initial_chunks == 0)
438 		return -EINVAL;
439 
440 	if (initial_chunks > max_chunks)
441 		return -EINVAL;
442 
443 	if (target_in_flight == 0)
444 		return -EINVAL;
445 
446 	heap = kzalloc(sizeof(*heap), GFP_KERNEL);
447 	if (unlikely(!heap)) {
448 		dev_err(kctx->kbdev->dev,
449 			"No kernel memory for a new tiler heap\n");
450 		return -ENOMEM;
451 	}
452 
453 	heap->kctx = kctx;
454 	heap->chunk_size = chunk_size;
455 	heap->max_chunks = max_chunks;
456 	heap->target_in_flight = target_in_flight;
457 	INIT_LIST_HEAD(&heap->chunks_list);
458 
459 	heap->gpu_va = kbase_csf_heap_context_allocator_alloc(ctx_alloc);
460 
461 	if (unlikely(!heap->gpu_va)) {
462 		dev_dbg(kctx->kbdev->dev,
463 			"Failed to allocate a tiler heap context");
464 		err = -ENOMEM;
465 	} else {
466 		err = create_initial_chunks(heap, initial_chunks);
467 		if (unlikely(err)) {
468 			kbase_csf_heap_context_allocator_free(ctx_alloc,
469 				heap->gpu_va);
470 		}
471 	}
472 
473 	if (unlikely(err)) {
474 		kfree(heap);
475 	} else {
476 		struct kbase_csf_tiler_heap_chunk const *first_chunk =
477 			list_first_entry(&heap->chunks_list,
478 				struct kbase_csf_tiler_heap_chunk, link);
479 
480 		*heap_gpu_va = heap->gpu_va;
481 		*first_chunk_va = first_chunk->gpu_va;
482 
483 		mutex_lock(&kctx->csf.tiler_heaps.lock);
484 		kctx->csf.tiler_heaps.nr_of_heaps++;
485 		heap->heap_id = kctx->csf.tiler_heaps.nr_of_heaps;
486 		list_add(&heap->link, &kctx->csf.tiler_heaps.list);
487 
488 		KBASE_TLSTREAM_AUX_TILER_HEAP_STATS(
489 			kctx->kbdev, kctx->id, heap->heap_id,
490 			PFN_UP(heap->chunk_size * heap->max_chunks),
491 			PFN_UP(heap->chunk_size * heap->chunk_count),
492 			heap->max_chunks, heap->chunk_size, heap->chunk_count,
493 			heap->target_in_flight, 0);
494 
495 		dev_dbg(kctx->kbdev->dev, "Created tiler heap 0x%llX\n",
496 			heap->gpu_va);
497 		mutex_unlock(&kctx->csf.tiler_heaps.lock);
498 		kctx->running_total_tiler_heap_nr_chunks += heap->chunk_count;
499 		kctx->running_total_tiler_heap_memory += heap->chunk_size * heap->chunk_count;
500 		if (kctx->running_total_tiler_heap_memory > kctx->peak_total_tiler_heap_memory)
501 			kctx->peak_total_tiler_heap_memory = kctx->running_total_tiler_heap_memory;
502 	}
503 	return err;
504 }
505 
kbase_csf_tiler_heap_term(struct kbase_context * const kctx,u64 const heap_gpu_va)506 int kbase_csf_tiler_heap_term(struct kbase_context *const kctx,
507 	u64 const heap_gpu_va)
508 {
509 	int err = 0;
510 	struct kbase_csf_tiler_heap *heap = NULL;
511 	u32 chunk_count = 0;
512 	u64 heap_size = 0;
513 
514 	mutex_lock(&kctx->csf.tiler_heaps.lock);
515 
516 	heap = find_tiler_heap(kctx, heap_gpu_va);
517 	if (likely(heap)) {
518 		chunk_count = heap->chunk_count;
519 		heap_size = heap->chunk_size * chunk_count;
520 		delete_heap(heap);
521 	} else
522 		err = -EINVAL;
523 
524 	mutex_unlock(&kctx->csf.tiler_heaps.lock);
525 	if (likely(kctx->running_total_tiler_heap_memory >= heap_size))
526 		kctx->running_total_tiler_heap_memory -= heap_size;
527 	else
528 		dev_warn(kctx->kbdev->dev,
529 			 "Running total tiler heap memory lower than expected!");
530 	if (likely(kctx->running_total_tiler_heap_nr_chunks >= chunk_count))
531 		kctx->running_total_tiler_heap_nr_chunks -= chunk_count;
532 	else
533 		dev_warn(kctx->kbdev->dev,
534 			 "Running total tiler chunk count lower than expected!");
535 	return err;
536 }
537 
538 /**
539  * alloc_new_chunk - Allocate a new chunk for the tiler heap.
540  *
541  * @heap:               Pointer to the tiler heap.
542  * @nr_in_flight:       Number of render passes that are in-flight, must not be zero.
543  * @pending_frag_count: Number of render passes in-flight with completed vertex/tiler stage.
544  *                      The minimum value is zero but it must be less or equal to
545  *                      the total number of render passes in flight
546  * @new_chunk_ptr:      Where to store the GPU virtual address & size of the new
547  *                      chunk allocated for the heap.
548  *
549  * This function will allocate a new chunk for the chunked tiler heap depending
550  * on the settings provided by userspace when the heap was created and the
551  * heap's statistics (like number of render passes in-flight).
552  *
553  * Return: 0 if a new chunk was allocated otherwise an appropriate negative
554  *         error code.
555  */
alloc_new_chunk(struct kbase_csf_tiler_heap * heap,u32 nr_in_flight,u32 pending_frag_count,u64 * new_chunk_ptr)556 static int alloc_new_chunk(struct kbase_csf_tiler_heap *heap,
557 		u32 nr_in_flight, u32 pending_frag_count, u64 *new_chunk_ptr)
558 {
559 	int err = -ENOMEM;
560 
561 	lockdep_assert_held(&heap->kctx->csf.tiler_heaps.lock);
562 
563 	if (WARN_ON(!nr_in_flight) ||
564 		WARN_ON(pending_frag_count > nr_in_flight))
565 		return -EINVAL;
566 
567 	if (nr_in_flight <= heap->target_in_flight) {
568 		if (heap->chunk_count < heap->max_chunks) {
569 			/* Not exceeded the target number of render passes yet so be
570 			 * generous with memory.
571 			 */
572 			err = create_chunk(heap, false);
573 
574 			if (likely(!err)) {
575 				struct kbase_csf_tiler_heap_chunk *new_chunk =
576 								get_last_chunk(heap);
577 				if (!WARN_ON(!new_chunk)) {
578 					*new_chunk_ptr =
579 						encode_chunk_ptr(heap->chunk_size,
580 								 new_chunk->gpu_va);
581 					return 0;
582 				}
583 			}
584 		} else if (pending_frag_count > 0) {
585 			err = -EBUSY;
586 		} else {
587 			err = -ENOMEM;
588 		}
589 	} else {
590 		/* Reached target number of render passes in flight.
591 		 * Wait for some of them to finish
592 		 */
593 		err = -EBUSY;
594 	}
595 
596 	return err;
597 }
598 
kbase_csf_tiler_heap_alloc_new_chunk(struct kbase_context * kctx,u64 gpu_heap_va,u32 nr_in_flight,u32 pending_frag_count,u64 * new_chunk_ptr)599 int kbase_csf_tiler_heap_alloc_new_chunk(struct kbase_context *kctx,
600 	u64 gpu_heap_va, u32 nr_in_flight, u32 pending_frag_count, u64 *new_chunk_ptr)
601 {
602 	struct kbase_csf_tiler_heap *heap;
603 	int err = -EINVAL;
604 
605 	mutex_lock(&kctx->csf.tiler_heaps.lock);
606 
607 	heap = find_tiler_heap(kctx, gpu_heap_va);
608 
609 	if (likely(heap)) {
610 		err = alloc_new_chunk(heap, nr_in_flight, pending_frag_count,
611 			new_chunk_ptr);
612 
613 		KBASE_TLSTREAM_AUX_TILER_HEAP_STATS(
614 			kctx->kbdev, kctx->id, heap->heap_id,
615 			PFN_UP(heap->chunk_size * heap->max_chunks),
616 			PFN_UP(heap->chunk_size * heap->chunk_count),
617 			heap->max_chunks, heap->chunk_size, heap->chunk_count,
618 			heap->target_in_flight, nr_in_flight);
619 	}
620 
621 	mutex_unlock(&kctx->csf.tiler_heaps.lock);
622 
623 	return err;
624 }
625