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