]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blame - drivers/media/pci/intel/ipu6/ipu-resources.c
UBUNTU: SAUCE: IPU6 driver release for kernel 5.14 on 2021-11-01
[mirror_ubuntu-jammy-kernel.git] / drivers / media / pci / intel / ipu6 / ipu-resources.c
CommitLineData
f2efa4ee
WY
1// SPDX-License-Identifier: GPL-2.0
2// Copyright (C) 2015 - 2020 Intel Corporation
3
4#include <linux/bitmap.h>
5#include <linux/errno.h>
6#include <linux/gfp.h>
7#include <linux/slab.h>
8#include <linux/device.h>
9
10#include <uapi/linux/ipu-psys.h>
11
12#include "ipu-fw-psys.h"
13#include "ipu-psys.h"
14
15struct ipu6_psys_hw_res_variant hw_var;
16void ipu6_psys_hw_res_variant_init(void)
17{
18 if (ipu_ver == IPU_VER_6SE) {
19 hw_var.queue_num = IPU6SE_FW_PSYS_N_PSYS_CMD_QUEUE_ID;
20 hw_var.cell_num = IPU6SE_FW_PSYS_N_CELL_ID;
f2efa4ee
WY
21 } else if (ipu_ver == IPU_VER_6) {
22 hw_var.queue_num = IPU6_FW_PSYS_N_PSYS_CMD_QUEUE_ID;
23 hw_var.cell_num = IPU6_FW_PSYS_N_CELL_ID;
eaffc3a7
WY
24 } else if (ipu_ver == IPU_VER_6EP) {
25 hw_var.queue_num = IPU6_FW_PSYS_N_PSYS_CMD_QUEUE_ID;
26 hw_var.cell_num = IPU6EP_FW_PSYS_N_CELL_ID;
fad9119b
WY
27 } else {
28 WARN(1, "ipu6 psys res var is not initialised correctly.");
f2efa4ee
WY
29 }
30
fad9119b
WY
31 hw_var.set_proc_dev_chn = ipu6_fw_psys_set_proc_dev_chn;
32 hw_var.set_proc_dfm_bitmap = ipu6_fw_psys_set_proc_dfm_bitmap;
33 hw_var.set_proc_ext_mem = ipu6_fw_psys_set_process_ext_mem;
34 hw_var.get_pgm_by_proc =
35 ipu6_fw_psys_get_program_manifest_by_process;
36 return;
f2efa4ee
WY
37}
38
39static const struct ipu_fw_resource_definitions *get_res(void)
40{
41 if (ipu_ver == IPU_VER_6SE)
42 return ipu6se_res_defs;
eaffc3a7
WY
43
44 if (ipu_ver == IPU_VER_6EP)
45 return ipu6ep_res_defs;
f2efa4ee
WY
46
47 return ipu6_res_defs;
48}
49
50static int ipu_resource_init(struct ipu_resource *res, u32 id, int elements)
51{
52 if (elements <= 0) {
53 res->bitmap = NULL;
54 return 0;
55 }
56
57 res->bitmap = bitmap_zalloc(elements, GFP_KERNEL);
58 if (!res->bitmap)
59 return -ENOMEM;
60 res->elements = elements;
61 res->id = id;
62 return 0;
63}
64
65static unsigned long
66ipu_resource_alloc_with_pos(struct ipu_resource *res, int n,
67 int pos,
68 struct ipu_resource_alloc *alloc,
69 enum ipu_resource_type type)
70{
71 unsigned long p;
72
73 if (n <= 0) {
74 alloc->elements = 0;
75 return 0;
76 }
77
78 if (!res->bitmap || pos >= res->elements)
79 return (unsigned long)(-ENOSPC);
80
81 p = bitmap_find_next_zero_area(res->bitmap, res->elements, pos, n, 0);
82 alloc->resource = NULL;
83
84 if (p != pos)
85 return (unsigned long)(-ENOSPC);
86 bitmap_set(res->bitmap, p, n);
87 alloc->resource = res;
88 alloc->elements = n;
89 alloc->pos = p;
90 alloc->type = type;
91
92 return pos;
93}
94
95static unsigned long
96ipu_resource_alloc(struct ipu_resource *res, int n,
97 struct ipu_resource_alloc *alloc,
98 enum ipu_resource_type type)
99{
100 unsigned long p;
101
102 if (n <= 0) {
103 alloc->elements = 0;
104 return 0;
105 }
106
107 if (!res->bitmap)
108 return (unsigned long)(-ENOSPC);
109
110 p = bitmap_find_next_zero_area(res->bitmap, res->elements, 0, n, 0);
111 alloc->resource = NULL;
112
113 if (p >= res->elements)
114 return (unsigned long)(-ENOSPC);
115 bitmap_set(res->bitmap, p, n);
116 alloc->resource = res;
117 alloc->elements = n;
118 alloc->pos = p;
119 alloc->type = type;
120
121 return p;
122}
123
124static void ipu_resource_free(struct ipu_resource_alloc *alloc)
125{
126 if (alloc->elements <= 0)
127 return;
128
129 if (alloc->type == IPU_RESOURCE_DFM)
130 *alloc->resource->bitmap &= ~(unsigned long)(alloc->elements);
131 else
132 bitmap_clear(alloc->resource->bitmap, alloc->pos,
133 alloc->elements);
134 alloc->resource = NULL;
135}
136
137static void ipu_resource_cleanup(struct ipu_resource *res)
138{
139 bitmap_free(res->bitmap);
140 res->bitmap = NULL;
141}
142
143/********** IPU PSYS-specific resource handling **********/
5a771b35 144int ipu_psys_resource_pool_init(struct ipu_psys_resource_pool *pool)
f2efa4ee
WY
145{
146 int i, j, k, ret;
147 const struct ipu_fw_resource_definitions *res_defs;
148
149 res_defs = get_res();
150
5a771b35 151 spin_lock_init(&pool->queues_lock);
f2efa4ee
WY
152 pool->cells = 0;
153
154 for (i = 0; i < res_defs->num_dev_channels; i++) {
155 ret = ipu_resource_init(&pool->dev_channels[i], i,
156 res_defs->dev_channels[i]);
157 if (ret)
158 goto error;
159 }
160
161 for (j = 0; j < res_defs->num_ext_mem_ids; j++) {
162 ret = ipu_resource_init(&pool->ext_memory[j], j,
163 res_defs->ext_mem_ids[j]);
164 if (ret)
165 goto memory_error;
166 }
167
168 for (k = 0; k < res_defs->num_dfm_ids; k++) {
169 ret = ipu_resource_init(&pool->dfms[k], k, res_defs->dfms[k]);
170 if (ret)
171 goto dfm_error;
172 }
173
5a771b35 174 spin_lock(&pool->queues_lock);
f2efa4ee
WY
175 if (ipu_ver == IPU_VER_6SE)
176 bitmap_zero(pool->cmd_queues,
177 IPU6SE_FW_PSYS_N_PSYS_CMD_QUEUE_ID);
178 else
179 bitmap_zero(pool->cmd_queues,
180 IPU6_FW_PSYS_N_PSYS_CMD_QUEUE_ID);
5a771b35 181 spin_unlock(&pool->queues_lock);
f2efa4ee
WY
182
183 return 0;
184
185dfm_error:
186 for (k--; k >= 0; k--)
187 ipu_resource_cleanup(&pool->dfms[k]);
188
189memory_error:
190 for (j--; j >= 0; j--)
191 ipu_resource_cleanup(&pool->ext_memory[j]);
192
193error:
194 for (i--; i >= 0; i--)
195 ipu_resource_cleanup(&pool->dev_channels[i]);
196 return ret;
197}
198
199void ipu_psys_resource_copy(struct ipu_psys_resource_pool *src,
200 struct ipu_psys_resource_pool *dest)
201{
202 int i;
203 const struct ipu_fw_resource_definitions *res_defs;
204
205 res_defs = get_res();
206
207 dest->cells = src->cells;
208 for (i = 0; i < res_defs->num_dev_channels; i++)
209 *dest->dev_channels[i].bitmap = *src->dev_channels[i].bitmap;
210
211 for (i = 0; i < res_defs->num_ext_mem_ids; i++)
212 *dest->ext_memory[i].bitmap = *src->ext_memory[i].bitmap;
213
214 for (i = 0; i < res_defs->num_dfm_ids; i++)
215 *dest->dfms[i].bitmap = *src->dfms[i].bitmap;
216}
217
218void ipu_psys_resource_pool_cleanup(struct ipu_psys_resource_pool
219 *pool)
220{
221 u32 i;
222 const struct ipu_fw_resource_definitions *res_defs;
223
224 res_defs = get_res();
225 for (i = 0; i < res_defs->num_dev_channels; i++)
226 ipu_resource_cleanup(&pool->dev_channels[i]);
227
228 for (i = 0; i < res_defs->num_ext_mem_ids; i++)
229 ipu_resource_cleanup(&pool->ext_memory[i]);
230
231 for (i = 0; i < res_defs->num_dfm_ids; i++)
232 ipu_resource_cleanup(&pool->dfms[i]);
233}
234
235static int __alloc_one_resrc(const struct device *dev,
236 struct ipu_fw_psys_process *process,
237 struct ipu_resource *resource,
238 struct ipu_fw_generic_program_manifest *pm,
239 u32 resource_id,
240 struct ipu_psys_resource_alloc *alloc)
241{
242 const u16 resource_req = pm->dev_chn_size[resource_id];
243 const u16 resource_offset_req = pm->dev_chn_offset[resource_id];
244 unsigned long retl;
f2efa4ee
WY
245
246 if (resource_req <= 0)
247 return 0;
248
249 if (alloc->resources >= IPU_MAX_RESOURCES) {
250 dev_err(dev, "out of resource handles\n");
251 return -ENOSPC;
252 }
f2efa4ee
WY
253 if (resource_offset_req != (u16)(-1))
254 retl = ipu_resource_alloc_with_pos
255 (resource,
256 resource_req,
257 resource_offset_req,
258 &alloc->resource_alloc[alloc->resources],
259 IPU_RESOURCE_DEV_CHN);
260 else
261 retl = ipu_resource_alloc
262 (resource, resource_req,
263 &alloc->resource_alloc[alloc->resources],
264 IPU_RESOURCE_DEV_CHN);
265 if (IS_ERR_VALUE(retl)) {
266 dev_dbg(dev, "out of device channel resources\n");
267 return (int)retl;
268 }
269 alloc->resources++;
270
271 return 0;
272}
273
f2efa4ee
WY
274static int ipu_psys_allocate_one_dfm(const struct device *dev,
275 struct ipu_fw_psys_process *process,
276 struct ipu_resource *resource,
277 struct ipu_fw_generic_program_manifest *pm,
278 u32 resource_id,
279 struct ipu_psys_resource_alloc *alloc)
280{
281 u32 dfm_bitmap_req = pm->dfm_port_bitmap[resource_id];
282 u32 active_dfm_bitmap_req = pm->dfm_active_port_bitmap[resource_id];
283 const u8 is_relocatable = pm->is_dfm_relocatable[resource_id];
284 struct ipu_resource_alloc *alloc_resource;
285 unsigned long p = 0;
286
287 if (dfm_bitmap_req == 0)
288 return 0;
289
290 if (alloc->resources >= IPU_MAX_RESOURCES) {
291 dev_err(dev, "out of resource handles\n");
292 return -ENOSPC;
293 }
294
295 if (!resource->bitmap)
296 return -ENOSPC;
297
298 if (!is_relocatable) {
299 if (*resource->bitmap & dfm_bitmap_req) {
300 dev_warn(dev,
301 "out of dfm resources, req 0x%x, get 0x%lx\n",
302 dfm_bitmap_req, *resource->bitmap);
303 return -ENOSPC;
304 }
305 *resource->bitmap |= dfm_bitmap_req;
306 } else {
5a771b35 307 unsigned int n = hweight32(dfm_bitmap_req);
f2efa4ee
WY
308
309 p = bitmap_find_next_zero_area(resource->bitmap,
310 resource->elements, 0, n, 0);
311
312 if (p >= resource->elements)
313 return -ENOSPC;
314
315 bitmap_set(resource->bitmap, p, n);
316 dfm_bitmap_req = dfm_bitmap_req << p;
317 active_dfm_bitmap_req = active_dfm_bitmap_req << p;
318 }
319
320 alloc_resource = &alloc->resource_alloc[alloc->resources];
321 alloc_resource->resource = resource;
322 /* Using elements to indicate the bitmap */
323 alloc_resource->elements = dfm_bitmap_req;
324 alloc_resource->pos = p;
325 alloc_resource->type = IPU_RESOURCE_DFM;
326
327 alloc->resources++;
328
329 return 0;
330}
331
332/*
333 * ext_mem_type_id is a generic type id for memory (like DMEM, VMEM)
334 * ext_mem_bank_id is detailed type id for memory (like DMEM0, DMEM1 etc.)
335 */
336static int __alloc_mem_resrc(const struct device *dev,
337 struct ipu_fw_psys_process *process,
338 struct ipu_resource *resource,
339 struct ipu_fw_generic_program_manifest *pm,
340 u32 ext_mem_type_id, u32 ext_mem_bank_id,
341 struct ipu_psys_resource_alloc *alloc)
342{
343 const u16 memory_resource_req = pm->ext_mem_size[ext_mem_type_id];
344 const u16 memory_offset_req = pm->ext_mem_offset[ext_mem_type_id];
345
346 unsigned long retl;
347
348 if (memory_resource_req <= 0)
349 return 0;
350
351 if (alloc->resources >= IPU_MAX_RESOURCES) {
352 dev_err(dev, "out of resource handles\n");
353 return -ENOSPC;
354 }
355 if (memory_offset_req != (u16)(-1))
356 retl = ipu_resource_alloc_with_pos
357 (resource,
358 memory_resource_req, memory_offset_req,
359 &alloc->resource_alloc[alloc->resources],
360 IPU_RESOURCE_EXT_MEM);
361 else
362 retl = ipu_resource_alloc
363 (resource, memory_resource_req,
364 &alloc->resource_alloc[alloc->resources],
365 IPU_RESOURCE_EXT_MEM);
366 if (IS_ERR_VALUE(retl)) {
367 dev_dbg(dev, "out of memory resources\n");
368 return (int)retl;
369 }
370
371 alloc->resources++;
372
373 return 0;
374}
375
376int ipu_psys_allocate_cmd_queue_resource(struct ipu_psys_resource_pool *pool)
377{
378 unsigned long p;
379 int size, start;
380
381 size = IPU6_FW_PSYS_N_PSYS_CMD_QUEUE_ID;
382 start = IPU6_FW_PSYS_CMD_QUEUE_PPG0_COMMAND_ID;
383
384 if (ipu_ver == IPU_VER_6SE) {
385 size = IPU6SE_FW_PSYS_N_PSYS_CMD_QUEUE_ID;
386 start = IPU6SE_FW_PSYS_CMD_QUEUE_PPG0_COMMAND_ID;
387 }
388
5a771b35 389 spin_lock(&pool->queues_lock);
f2efa4ee
WY
390 /* find available cmd queue from ppg0_cmd_id */
391 p = bitmap_find_next_zero_area(pool->cmd_queues, size, start, 1, 0);
392
af60d6fc 393 if (p >= size) {
5a771b35 394 spin_unlock(&pool->queues_lock);
f2efa4ee 395 return -ENOSPC;
af60d6fc 396 }
f2efa4ee
WY
397
398 bitmap_set(pool->cmd_queues, p, 1);
5a771b35 399 spin_unlock(&pool->queues_lock);
f2efa4ee
WY
400
401 return p;
402}
403
404void ipu_psys_free_cmd_queue_resource(struct ipu_psys_resource_pool *pool,
405 u8 queue_id)
406{
5a771b35 407 spin_lock(&pool->queues_lock);
f2efa4ee 408 bitmap_clear(pool->cmd_queues, queue_id, 1);
5a771b35 409 spin_unlock(&pool->queues_lock);
f2efa4ee
WY
410}
411
412int ipu_psys_try_allocate_resources(struct device *dev,
413 struct ipu_fw_psys_process_group *pg,
414 void *pg_manifest,
415 struct ipu_psys_resource_pool *pool)
416{
417 u32 id, idx;
418 u32 mem_type_id;
419 int ret, i;
420 u16 *process_offset_table;
421 u8 processes;
422 u32 cells = 0;
423 struct ipu_psys_resource_alloc *alloc;
424 const struct ipu_fw_resource_definitions *res_defs;
425
426 if (!pg)
427 return -EINVAL;
428 process_offset_table = (u16 *)((u8 *)pg + pg->processes_offset);
429 processes = pg->process_count;
430
431 alloc = kzalloc(sizeof(*alloc), GFP_KERNEL);
432 if (!alloc)
433 return -ENOMEM;
434
435 res_defs = get_res();
436 for (i = 0; i < processes; i++) {
437 u32 cell;
438 struct ipu_fw_psys_process *process =
439 (struct ipu_fw_psys_process *)
440 ((char *)pg + process_offset_table[i]);
441 struct ipu_fw_generic_program_manifest pm;
442
443 memset(&pm, 0, sizeof(pm));
444
445 if (!process) {
446 dev_err(dev, "can not get process\n");
447 ret = -ENOENT;
448 goto free_out;
449 }
450
451 ret = ipu_fw_psys_get_program_manifest_by_process
452 (&pm, pg_manifest, process);
453 if (ret < 0) {
454 dev_err(dev, "can not get manifest\n");
455 goto free_out;
456 }
457
458 if (pm.cell_id == res_defs->num_cells &&
459 pm.cell_type_id == res_defs->num_cells_type) {
460 cell = res_defs->num_cells;
461 } else if ((pm.cell_id != res_defs->num_cells &&
462 pm.cell_type_id == res_defs->num_cells_type)) {
463 cell = pm.cell_id;
464 } else {
465 /* Find a free cell of desired type */
466 u32 type = pm.cell_type_id;
467
468 for (cell = 0; cell < res_defs->num_cells; cell++)
469 if (res_defs->cells[cell] == type &&
470 ((pool->cells | cells) & (1 << cell)) == 0)
471 break;
472 if (cell >= res_defs->num_cells) {
473 dev_dbg(dev, "no free cells of right type\n");
474 ret = -ENOSPC;
475 goto free_out;
476 }
477 }
478 if (cell < res_defs->num_cells)
479 cells |= 1 << cell;
480 if (pool->cells & cells) {
481 dev_dbg(dev, "out of cell resources\n");
482 ret = -ENOSPC;
483 goto free_out;
484 }
485
486 if (pm.dev_chn_size) {
487 for (id = 0; id < res_defs->num_dev_channels; id++) {
488 ret = __alloc_one_resrc(dev, process,
489 &pool->dev_channels[id],
490 &pm, id, alloc);
491 if (ret)
492 goto free_out;
493 }
494 }
495
496 if (pm.dfm_port_bitmap) {
497 for (id = 0; id < res_defs->num_dfm_ids; id++) {
498 ret = ipu_psys_allocate_one_dfm
499 (dev, process,
500 &pool->dfms[id], &pm, id, alloc);
501 if (ret)
502 goto free_out;
503 }
504 }
505
506 if (pm.ext_mem_size) {
507 for (mem_type_id = 0;
508 mem_type_id < res_defs->num_ext_mem_types;
509 mem_type_id++) {
510 u32 bank = res_defs->num_ext_mem_ids;
511
512 if (cell != res_defs->num_cells) {
513 idx = res_defs->cell_mem_row * cell +
514 mem_type_id;
515 bank = res_defs->cell_mem[idx];
516 }
517
518 if (bank == res_defs->num_ext_mem_ids)
519 continue;
520
521 ret = __alloc_mem_resrc(dev, process,
522 &pool->ext_memory[bank],
523 &pm, mem_type_id, bank,
524 alloc);
525 if (ret)
526 goto free_out;
527 }
528 }
529 }
530 alloc->cells |= cells;
531 pool->cells |= cells;
532
533 kfree(alloc);
534 return 0;
535
536free_out:
537 dev_dbg(dev, "failed to try_allocate resource\n");
538 kfree(alloc);
539 return ret;
540}
541
542/*
543 * Allocate resources for pg from `pool'. Mark the allocated
544 * resources into `alloc'. Returns 0 on success, -ENOSPC
545 * if there are no enough resources, in which cases resources
546 * are not allocated at all, or some other error on other conditions.
547 */
548int ipu_psys_allocate_resources(const struct device *dev,
549 struct ipu_fw_psys_process_group *pg,
550 void *pg_manifest,
551 struct ipu_psys_resource_alloc
552 *alloc, struct ipu_psys_resource_pool
553 *pool)
554{
555 u32 id;
556 u32 mem_type_id;
557 int ret, i;
558 u16 *process_offset_table;
559 u8 processes;
560 u32 cells = 0;
561 int p, idx;
562 u32 bmp, a_bmp;
563 const struct ipu_fw_resource_definitions *res_defs;
564
565 if (!pg)
566 return -EINVAL;
567
568 res_defs = get_res();
569 process_offset_table = (u16 *)((u8 *)pg + pg->processes_offset);
570 processes = pg->process_count;
571
572 for (i = 0; i < processes; i++) {
573 u32 cell;
574 struct ipu_fw_psys_process *process =
575 (struct ipu_fw_psys_process *)
576 ((char *)pg + process_offset_table[i]);
577 struct ipu_fw_generic_program_manifest pm;
578
579 memset(&pm, 0, sizeof(pm));
580 if (!process) {
581 dev_err(dev, "can not get process\n");
582 ret = -ENOENT;
583 goto free_out;
584 }
585
586 ret = ipu_fw_psys_get_program_manifest_by_process
587 (&pm, pg_manifest, process);
588 if (ret < 0) {
589 dev_err(dev, "can not get manifest\n");
590 goto free_out;
591 }
592
593 if (pm.cell_id == res_defs->num_cells &&
594 pm.cell_type_id == res_defs->num_cells_type) {
595 cell = res_defs->num_cells;
596 } else if ((pm.cell_id != res_defs->num_cells &&
597 pm.cell_type_id == res_defs->num_cells_type)) {
598 cell = pm.cell_id;
599 } else {
600 /* Find a free cell of desired type */
601 u32 type = pm.cell_type_id;
602
603 for (cell = 0; cell < res_defs->num_cells; cell++)
604 if (res_defs->cells[cell] == type &&
605 ((pool->cells | cells) & (1 << cell)) == 0)
606 break;
607 if (cell >= res_defs->num_cells) {
608 dev_dbg(dev, "no free cells of right type\n");
609 ret = -ENOSPC;
610 goto free_out;
611 }
612 ret = ipu_fw_psys_set_process_cell_id(process, 0, cell);
613 if (ret)
614 goto free_out;
615 }
616 if (cell < res_defs->num_cells)
617 cells |= 1 << cell;
618 if (pool->cells & cells) {
619 dev_dbg(dev, "out of cell resources\n");
620 ret = -ENOSPC;
621 goto free_out;
622 }
623
624 if (pm.dev_chn_size) {
625 for (id = 0; id < res_defs->num_dev_channels; id++) {
626 ret = __alloc_one_resrc(dev, process,
627 &pool->dev_channels[id],
628 &pm, id, alloc);
629 if (ret)
630 goto free_out;
631
632 idx = alloc->resources - 1;
633 p = alloc->resource_alloc[idx].pos;
634 ret = ipu_fw_psys_set_proc_dev_chn(process, id,
635 p);
636 if (ret)
637 goto free_out;
638 }
639 }
640
641 if (pm.dfm_port_bitmap) {
642 for (id = 0; id < res_defs->num_dfm_ids; id++) {
643 ret = ipu_psys_allocate_one_dfm(dev, process,
644 &pool->dfms[id],
645 &pm, id, alloc);
646 if (ret)
647 goto free_out;
648
649 idx = alloc->resources - 1;
650 p = alloc->resource_alloc[idx].pos;
651 bmp = pm.dfm_port_bitmap[id];
652 bmp = bmp << p;
653 a_bmp = pm.dfm_active_port_bitmap[id];
654 a_bmp = a_bmp << p;
655 ret = ipu_fw_psys_set_proc_dfm_bitmap(process,
656 id, bmp,
657 a_bmp);
658 if (ret)
659 goto free_out;
660 }
661 }
662
663 if (pm.ext_mem_size) {
664 for (mem_type_id = 0;
665 mem_type_id < res_defs->num_ext_mem_types;
666 mem_type_id++) {
667 u32 bank = res_defs->num_ext_mem_ids;
668
669 if (cell != res_defs->num_cells) {
670 idx = res_defs->cell_mem_row * cell +
671 mem_type_id;
672 bank = res_defs->cell_mem[idx];
673 }
674 if (bank == res_defs->num_ext_mem_ids)
675 continue;
676
677 ret = __alloc_mem_resrc(dev, process,
678 &pool->ext_memory[bank],
679 &pm, mem_type_id,
680 bank, alloc);
681 if (ret)
682 goto free_out;
fad9119b 683
f2efa4ee
WY
684 /* no return value check here because fw api
685 * will do some checks, and would return
686 * non-zero except mem_type_id == 0.
687 * This maybe caused by that above flow of
688 * allocating mem_bank_id is improper.
689 */
690 idx = alloc->resources - 1;
691 p = alloc->resource_alloc[idx].pos;
692 ipu_fw_psys_set_process_ext_mem(process,
693 mem_type_id,
694 bank, p);
695 }
696 }
697 }
698 alloc->cells |= cells;
699 pool->cells |= cells;
700 return 0;
701
702free_out:
f2efa4ee 703 dev_err(dev, "failed to allocate resources, ret %d\n", ret);
af60d6fc 704 ipu_psys_reset_process_cell(dev, pg, pg_manifest, i + 1);
f2efa4ee
WY
705 ipu_psys_free_resources(alloc, pool);
706 return ret;
707}
708
709int ipu_psys_move_resources(const struct device *dev,
710 struct ipu_psys_resource_alloc *alloc,
711 struct ipu_psys_resource_pool
712 *source_pool, struct ipu_psys_resource_pool
713 *target_pool)
714{
715 int i;
716
717 if (target_pool->cells & alloc->cells) {
718 dev_dbg(dev, "out of cell resources\n");
719 return -ENOSPC;
720 }
721
722 for (i = 0; i < alloc->resources; i++) {
723 unsigned long bitmap = 0;
724 unsigned int id = alloc->resource_alloc[i].resource->id;
725 unsigned long fbit, end;
726
727 switch (alloc->resource_alloc[i].type) {
728 case IPU_RESOURCE_DEV_CHN:
729 bitmap_set(&bitmap, alloc->resource_alloc[i].pos,
730 alloc->resource_alloc[i].elements);
731 if (*target_pool->dev_channels[id].bitmap & bitmap)
732 return -ENOSPC;
733 break;
734 case IPU_RESOURCE_EXT_MEM:
735 end = alloc->resource_alloc[i].elements +
736 alloc->resource_alloc[i].pos;
737
738 fbit = find_next_bit(target_pool->ext_memory[id].bitmap,
739 end, alloc->resource_alloc[i].pos);
740 /* if find_next_bit returns "end" it didn't find 1bit */
741 if (end != fbit)
742 return -ENOSPC;
743 break;
744 case IPU_RESOURCE_DFM:
745 bitmap = alloc->resource_alloc[i].elements;
746 if (*target_pool->dfms[id].bitmap & bitmap)
747 return -ENOSPC;
748 break;
749 default:
750 dev_err(dev, "Illegal resource type\n");
751 return -EINVAL;
752 }
753 }
754
755 for (i = 0; i < alloc->resources; i++) {
756 u32 id = alloc->resource_alloc[i].resource->id;
757
758 switch (alloc->resource_alloc[i].type) {
759 case IPU_RESOURCE_DEV_CHN:
760 bitmap_set(target_pool->dev_channels[id].bitmap,
761 alloc->resource_alloc[i].pos,
762 alloc->resource_alloc[i].elements);
763 ipu_resource_free(&alloc->resource_alloc[i]);
764 alloc->resource_alloc[i].resource =
765 &target_pool->dev_channels[id];
766 break;
767 case IPU_RESOURCE_EXT_MEM:
768 bitmap_set(target_pool->ext_memory[id].bitmap,
769 alloc->resource_alloc[i].pos,
770 alloc->resource_alloc[i].elements);
771 ipu_resource_free(&alloc->resource_alloc[i]);
772 alloc->resource_alloc[i].resource =
773 &target_pool->ext_memory[id];
774 break;
775 case IPU_RESOURCE_DFM:
776 *target_pool->dfms[id].bitmap |=
777 alloc->resource_alloc[i].elements;
778 *alloc->resource_alloc[i].resource->bitmap &=
779 ~(alloc->resource_alloc[i].elements);
780 alloc->resource_alloc[i].resource =
781 &target_pool->dfms[id];
782 break;
783 default:
784 /*
785 * Just keep compiler happy. This case failed already
786 * in above loop.
787 */
788 break;
789 }
790 }
791
792 target_pool->cells |= alloc->cells;
793 source_pool->cells &= ~alloc->cells;
794
795 return 0;
796}
797
af60d6fc
WY
798void ipu_psys_reset_process_cell(const struct device *dev,
799 struct ipu_fw_psys_process_group *pg,
800 void *pg_manifest,
801 int process_count)
802{
803 int i;
804 u16 *process_offset_table;
805 const struct ipu_fw_resource_definitions *res_defs;
806
807 if (!pg)
808 return;
809
810 res_defs = get_res();
811 process_offset_table = (u16 *)((u8 *)pg + pg->processes_offset);
812 for (i = 0; i < process_count; i++) {
813 struct ipu_fw_psys_process *process =
814 (struct ipu_fw_psys_process *)
815 ((char *)pg + process_offset_table[i]);
816 struct ipu_fw_generic_program_manifest pm;
817 int ret;
818
819 if (!process)
820 break;
821
822 ret = ipu_fw_psys_get_program_manifest_by_process(&pm,
823 pg_manifest,
824 process);
825 if (ret < 0) {
826 dev_err(dev, "can not get manifest\n");
827 break;
828 }
829 if ((pm.cell_id != res_defs->num_cells &&
830 pm.cell_type_id == res_defs->num_cells_type))
831 continue;
832 /* no return value check here because if finding free cell
833 * failed, process cell would not set then calling clear_cell
834 * will return non-zero.
835 */
836 ipu_fw_psys_clear_process_cell(process);
837 }
838}
839
f2efa4ee
WY
840/* Free resources marked in `alloc' from `resources' */
841void ipu_psys_free_resources(struct ipu_psys_resource_alloc
842 *alloc, struct ipu_psys_resource_pool *pool)
843{
844 unsigned int i;
845
846 pool->cells &= ~alloc->cells;
847 alloc->cells = 0;
848 for (i = 0; i < alloc->resources; i++)
849 ipu_resource_free(&alloc->resource_alloc[i]);
850 alloc->resources = 0;
851}