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