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