]> 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.13
[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 **********/
af60d6fc 144static DEFINE_SPINLOCK(cq_bitmap_lock);
f2efa4ee
WY
145int ipu_psys_resource_pool_init(struct ipu_psys_resource_pool
146 *pool)
147{
148 int i, j, k, ret;
149 const struct ipu_fw_resource_definitions *res_defs;
150
151 res_defs = get_res();
152
153 pool->cells = 0;
154
155 for (i = 0; i < res_defs->num_dev_channels; i++) {
156 ret = ipu_resource_init(&pool->dev_channels[i], i,
157 res_defs->dev_channels[i]);
158 if (ret)
159 goto error;
160 }
161
162 for (j = 0; j < res_defs->num_ext_mem_ids; j++) {
163 ret = ipu_resource_init(&pool->ext_memory[j], j,
164 res_defs->ext_mem_ids[j]);
165 if (ret)
166 goto memory_error;
167 }
168
169 for (k = 0; k < res_defs->num_dfm_ids; k++) {
170 ret = ipu_resource_init(&pool->dfms[k], k, res_defs->dfms[k]);
171 if (ret)
172 goto dfm_error;
173 }
174
af60d6fc 175 spin_lock(&cq_bitmap_lock);
f2efa4ee
WY
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);
af60d6fc 182 spin_unlock(&cq_bitmap_lock);
f2efa4ee
WY
183
184 return 0;
185
186dfm_error:
187 for (k--; k >= 0; k--)
188 ipu_resource_cleanup(&pool->dfms[k]);
189
190memory_error:
191 for (j--; j >= 0; j--)
192 ipu_resource_cleanup(&pool->ext_memory[j]);
193
194error:
195 for (i--; i >= 0; i--)
196 ipu_resource_cleanup(&pool->dev_channels[i]);
197 return ret;
198}
199
200void ipu_psys_resource_copy(struct ipu_psys_resource_pool *src,
201 struct ipu_psys_resource_pool *dest)
202{
203 int i;
204 const struct ipu_fw_resource_definitions *res_defs;
205
206 res_defs = get_res();
207
208 dest->cells = src->cells;
209 for (i = 0; i < res_defs->num_dev_channels; i++)
210 *dest->dev_channels[i].bitmap = *src->dev_channels[i].bitmap;
211
212 for (i = 0; i < res_defs->num_ext_mem_ids; i++)
213 *dest->ext_memory[i].bitmap = *src->ext_memory[i].bitmap;
214
215 for (i = 0; i < res_defs->num_dfm_ids; i++)
216 *dest->dfms[i].bitmap = *src->dfms[i].bitmap;
217}
218
219void ipu_psys_resource_pool_cleanup(struct ipu_psys_resource_pool
220 *pool)
221{
222 u32 i;
223 const struct ipu_fw_resource_definitions *res_defs;
224
225 res_defs = get_res();
226 for (i = 0; i < res_defs->num_dev_channels; i++)
227 ipu_resource_cleanup(&pool->dev_channels[i]);
228
229 for (i = 0; i < res_defs->num_ext_mem_ids; i++)
230 ipu_resource_cleanup(&pool->ext_memory[i]);
231
232 for (i = 0; i < res_defs->num_dfm_ids; i++)
233 ipu_resource_cleanup(&pool->dfms[i]);
234}
235
236static int __alloc_one_resrc(const struct device *dev,
237 struct ipu_fw_psys_process *process,
238 struct ipu_resource *resource,
239 struct ipu_fw_generic_program_manifest *pm,
240 u32 resource_id,
241 struct ipu_psys_resource_alloc *alloc)
242{
243 const u16 resource_req = pm->dev_chn_size[resource_id];
244 const u16 resource_offset_req = pm->dev_chn_offset[resource_id];
245 unsigned long retl;
f2efa4ee
WY
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 }
f2efa4ee
WY
254 if (resource_offset_req != (u16)(-1))
255 retl = ipu_resource_alloc_with_pos
256 (resource,
257 resource_req,
258 resource_offset_req,
259 &alloc->resource_alloc[alloc->resources],
260 IPU_RESOURCE_DEV_CHN);
261 else
262 retl = ipu_resource_alloc
263 (resource, resource_req,
264 &alloc->resource_alloc[alloc->resources],
265 IPU_RESOURCE_DEV_CHN);
266 if (IS_ERR_VALUE(retl)) {
267 dev_dbg(dev, "out of device channel resources\n");
268 return (int)retl;
269 }
270 alloc->resources++;
271
272 return 0;
273}
274
275static inline unsigned int bit_count(unsigned int n)
276{
277 unsigned int counter = 0;
278
279 while (n) {
280 counter++;
281 n &= (n - 1);
282 }
283 return counter;
284}
285
286static int ipu_psys_allocate_one_dfm(const struct device *dev,
287 struct ipu_fw_psys_process *process,
288 struct ipu_resource *resource,
289 struct ipu_fw_generic_program_manifest *pm,
290 u32 resource_id,
291 struct ipu_psys_resource_alloc *alloc)
292{
293 u32 dfm_bitmap_req = pm->dfm_port_bitmap[resource_id];
294 u32 active_dfm_bitmap_req = pm->dfm_active_port_bitmap[resource_id];
295 const u8 is_relocatable = pm->is_dfm_relocatable[resource_id];
296 struct ipu_resource_alloc *alloc_resource;
297 unsigned long p = 0;
298
299 if (dfm_bitmap_req == 0)
300 return 0;
301
302 if (alloc->resources >= IPU_MAX_RESOURCES) {
303 dev_err(dev, "out of resource handles\n");
304 return -ENOSPC;
305 }
306
307 if (!resource->bitmap)
308 return -ENOSPC;
309
310 if (!is_relocatable) {
311 if (*resource->bitmap & dfm_bitmap_req) {
312 dev_warn(dev,
313 "out of dfm resources, req 0x%x, get 0x%lx\n",
314 dfm_bitmap_req, *resource->bitmap);
315 return -ENOSPC;
316 }
317 *resource->bitmap |= dfm_bitmap_req;
318 } else {
319 unsigned int n = bit_count(dfm_bitmap_req);
320
321 p = bitmap_find_next_zero_area(resource->bitmap,
322 resource->elements, 0, n, 0);
323
324 if (p >= resource->elements)
325 return -ENOSPC;
326
327 bitmap_set(resource->bitmap, p, n);
328 dfm_bitmap_req = dfm_bitmap_req << p;
329 active_dfm_bitmap_req = active_dfm_bitmap_req << p;
330 }
331
332 alloc_resource = &alloc->resource_alloc[alloc->resources];
333 alloc_resource->resource = resource;
334 /* Using elements to indicate the bitmap */
335 alloc_resource->elements = dfm_bitmap_req;
336 alloc_resource->pos = p;
337 alloc_resource->type = IPU_RESOURCE_DFM;
338
339 alloc->resources++;
340
341 return 0;
342}
343
344/*
345 * ext_mem_type_id is a generic type id for memory (like DMEM, VMEM)
346 * ext_mem_bank_id is detailed type id for memory (like DMEM0, DMEM1 etc.)
347 */
348static int __alloc_mem_resrc(const struct device *dev,
349 struct ipu_fw_psys_process *process,
350 struct ipu_resource *resource,
351 struct ipu_fw_generic_program_manifest *pm,
352 u32 ext_mem_type_id, u32 ext_mem_bank_id,
353 struct ipu_psys_resource_alloc *alloc)
354{
355 const u16 memory_resource_req = pm->ext_mem_size[ext_mem_type_id];
356 const u16 memory_offset_req = pm->ext_mem_offset[ext_mem_type_id];
357
358 unsigned long retl;
359
360 if (memory_resource_req <= 0)
361 return 0;
362
363 if (alloc->resources >= IPU_MAX_RESOURCES) {
364 dev_err(dev, "out of resource handles\n");
365 return -ENOSPC;
366 }
367 if (memory_offset_req != (u16)(-1))
368 retl = ipu_resource_alloc_with_pos
369 (resource,
370 memory_resource_req, memory_offset_req,
371 &alloc->resource_alloc[alloc->resources],
372 IPU_RESOURCE_EXT_MEM);
373 else
374 retl = ipu_resource_alloc
375 (resource, memory_resource_req,
376 &alloc->resource_alloc[alloc->resources],
377 IPU_RESOURCE_EXT_MEM);
378 if (IS_ERR_VALUE(retl)) {
379 dev_dbg(dev, "out of memory resources\n");
380 return (int)retl;
381 }
382
383 alloc->resources++;
384
385 return 0;
386}
387
388int ipu_psys_allocate_cmd_queue_resource(struct ipu_psys_resource_pool *pool)
389{
390 unsigned long p;
391 int size, start;
392
393 size = IPU6_FW_PSYS_N_PSYS_CMD_QUEUE_ID;
394 start = IPU6_FW_PSYS_CMD_QUEUE_PPG0_COMMAND_ID;
395
396 if (ipu_ver == IPU_VER_6SE) {
397 size = IPU6SE_FW_PSYS_N_PSYS_CMD_QUEUE_ID;
398 start = IPU6SE_FW_PSYS_CMD_QUEUE_PPG0_COMMAND_ID;
399 }
400
af60d6fc 401 spin_lock(&cq_bitmap_lock);
f2efa4ee
WY
402 /* find available cmd queue from ppg0_cmd_id */
403 p = bitmap_find_next_zero_area(pool->cmd_queues, size, start, 1, 0);
404
af60d6fc
WY
405 if (p >= size) {
406 spin_unlock(&cq_bitmap_lock);
f2efa4ee 407 return -ENOSPC;
af60d6fc 408 }
f2efa4ee
WY
409
410 bitmap_set(pool->cmd_queues, p, 1);
af60d6fc 411 spin_unlock(&cq_bitmap_lock);
f2efa4ee
WY
412
413 return p;
414}
415
416void ipu_psys_free_cmd_queue_resource(struct ipu_psys_resource_pool *pool,
417 u8 queue_id)
418{
af60d6fc 419 spin_lock(&cq_bitmap_lock);
f2efa4ee 420 bitmap_clear(pool->cmd_queues, queue_id, 1);
af60d6fc 421 spin_unlock(&cq_bitmap_lock);
f2efa4ee
WY
422}
423
424int ipu_psys_try_allocate_resources(struct device *dev,
425 struct ipu_fw_psys_process_group *pg,
426 void *pg_manifest,
427 struct ipu_psys_resource_pool *pool)
428{
429 u32 id, idx;
430 u32 mem_type_id;
431 int ret, i;
432 u16 *process_offset_table;
433 u8 processes;
434 u32 cells = 0;
435 struct ipu_psys_resource_alloc *alloc;
436 const struct ipu_fw_resource_definitions *res_defs;
437
438 if (!pg)
439 return -EINVAL;
440 process_offset_table = (u16 *)((u8 *)pg + pg->processes_offset);
441 processes = pg->process_count;
442
443 alloc = kzalloc(sizeof(*alloc), GFP_KERNEL);
444 if (!alloc)
445 return -ENOMEM;
446
447 res_defs = get_res();
448 for (i = 0; i < processes; i++) {
449 u32 cell;
450 struct ipu_fw_psys_process *process =
451 (struct ipu_fw_psys_process *)
452 ((char *)pg + process_offset_table[i]);
453 struct ipu_fw_generic_program_manifest pm;
454
455 memset(&pm, 0, sizeof(pm));
456
457 if (!process) {
458 dev_err(dev, "can not get process\n");
459 ret = -ENOENT;
460 goto free_out;
461 }
462
463 ret = ipu_fw_psys_get_program_manifest_by_process
464 (&pm, pg_manifest, process);
465 if (ret < 0) {
466 dev_err(dev, "can not get manifest\n");
467 goto free_out;
468 }
469
470 if (pm.cell_id == res_defs->num_cells &&
471 pm.cell_type_id == res_defs->num_cells_type) {
472 cell = res_defs->num_cells;
473 } else if ((pm.cell_id != res_defs->num_cells &&
474 pm.cell_type_id == res_defs->num_cells_type)) {
475 cell = pm.cell_id;
476 } else {
477 /* Find a free cell of desired type */
478 u32 type = pm.cell_type_id;
479
480 for (cell = 0; cell < res_defs->num_cells; cell++)
481 if (res_defs->cells[cell] == type &&
482 ((pool->cells | cells) & (1 << cell)) == 0)
483 break;
484 if (cell >= res_defs->num_cells) {
485 dev_dbg(dev, "no free cells of right type\n");
486 ret = -ENOSPC;
487 goto free_out;
488 }
489 }
490 if (cell < res_defs->num_cells)
491 cells |= 1 << cell;
492 if (pool->cells & cells) {
493 dev_dbg(dev, "out of cell resources\n");
494 ret = -ENOSPC;
495 goto free_out;
496 }
497
498 if (pm.dev_chn_size) {
499 for (id = 0; id < res_defs->num_dev_channels; id++) {
500 ret = __alloc_one_resrc(dev, process,
501 &pool->dev_channels[id],
502 &pm, id, alloc);
503 if (ret)
504 goto free_out;
505 }
506 }
507
508 if (pm.dfm_port_bitmap) {
509 for (id = 0; id < res_defs->num_dfm_ids; id++) {
510 ret = ipu_psys_allocate_one_dfm
511 (dev, process,
512 &pool->dfms[id], &pm, id, alloc);
513 if (ret)
514 goto free_out;
515 }
516 }
517
518 if (pm.ext_mem_size) {
519 for (mem_type_id = 0;
520 mem_type_id < res_defs->num_ext_mem_types;
521 mem_type_id++) {
522 u32 bank = res_defs->num_ext_mem_ids;
523
524 if (cell != res_defs->num_cells) {
525 idx = res_defs->cell_mem_row * cell +
526 mem_type_id;
527 bank = res_defs->cell_mem[idx];
528 }
529
530 if (bank == res_defs->num_ext_mem_ids)
531 continue;
532
533 ret = __alloc_mem_resrc(dev, process,
534 &pool->ext_memory[bank],
535 &pm, mem_type_id, bank,
536 alloc);
537 if (ret)
538 goto free_out;
539 }
540 }
541 }
542 alloc->cells |= cells;
543 pool->cells |= cells;
544
545 kfree(alloc);
546 return 0;
547
548free_out:
549 dev_dbg(dev, "failed to try_allocate resource\n");
550 kfree(alloc);
551 return ret;
552}
553
554/*
555 * Allocate resources for pg from `pool'. Mark the allocated
556 * resources into `alloc'. Returns 0 on success, -ENOSPC
557 * if there are no enough resources, in which cases resources
558 * are not allocated at all, or some other error on other conditions.
559 */
560int ipu_psys_allocate_resources(const struct device *dev,
561 struct ipu_fw_psys_process_group *pg,
562 void *pg_manifest,
563 struct ipu_psys_resource_alloc
564 *alloc, struct ipu_psys_resource_pool
565 *pool)
566{
567 u32 id;
568 u32 mem_type_id;
569 int ret, i;
570 u16 *process_offset_table;
571 u8 processes;
572 u32 cells = 0;
573 int p, idx;
574 u32 bmp, a_bmp;
575 const struct ipu_fw_resource_definitions *res_defs;
576
577 if (!pg)
578 return -EINVAL;
579
580 res_defs = get_res();
581 process_offset_table = (u16 *)((u8 *)pg + pg->processes_offset);
582 processes = pg->process_count;
583
584 for (i = 0; i < processes; i++) {
585 u32 cell;
586 struct ipu_fw_psys_process *process =
587 (struct ipu_fw_psys_process *)
588 ((char *)pg + process_offset_table[i]);
589 struct ipu_fw_generic_program_manifest pm;
590
591 memset(&pm, 0, sizeof(pm));
592 if (!process) {
593 dev_err(dev, "can not get process\n");
594 ret = -ENOENT;
595 goto free_out;
596 }
597
598 ret = ipu_fw_psys_get_program_manifest_by_process
599 (&pm, pg_manifest, process);
600 if (ret < 0) {
601 dev_err(dev, "can not get manifest\n");
602 goto free_out;
603 }
604
605 if (pm.cell_id == res_defs->num_cells &&
606 pm.cell_type_id == res_defs->num_cells_type) {
607 cell = res_defs->num_cells;
608 } else if ((pm.cell_id != res_defs->num_cells &&
609 pm.cell_type_id == res_defs->num_cells_type)) {
610 cell = pm.cell_id;
611 } else {
612 /* Find a free cell of desired type */
613 u32 type = pm.cell_type_id;
614
615 for (cell = 0; cell < res_defs->num_cells; cell++)
616 if (res_defs->cells[cell] == type &&
617 ((pool->cells | cells) & (1 << cell)) == 0)
618 break;
619 if (cell >= res_defs->num_cells) {
620 dev_dbg(dev, "no free cells of right type\n");
621 ret = -ENOSPC;
622 goto free_out;
623 }
624 ret = ipu_fw_psys_set_process_cell_id(process, 0, cell);
625 if (ret)
626 goto free_out;
627 }
628 if (cell < res_defs->num_cells)
629 cells |= 1 << cell;
630 if (pool->cells & cells) {
631 dev_dbg(dev, "out of cell resources\n");
632 ret = -ENOSPC;
633 goto free_out;
634 }
635
636 if (pm.dev_chn_size) {
637 for (id = 0; id < res_defs->num_dev_channels; id++) {
638 ret = __alloc_one_resrc(dev, process,
639 &pool->dev_channels[id],
640 &pm, id, alloc);
641 if (ret)
642 goto free_out;
643
644 idx = alloc->resources - 1;
645 p = alloc->resource_alloc[idx].pos;
646 ret = ipu_fw_psys_set_proc_dev_chn(process, id,
647 p);
648 if (ret)
649 goto free_out;
650 }
651 }
652
653 if (pm.dfm_port_bitmap) {
654 for (id = 0; id < res_defs->num_dfm_ids; id++) {
655 ret = ipu_psys_allocate_one_dfm(dev, process,
656 &pool->dfms[id],
657 &pm, id, alloc);
658 if (ret)
659 goto free_out;
660
661 idx = alloc->resources - 1;
662 p = alloc->resource_alloc[idx].pos;
663 bmp = pm.dfm_port_bitmap[id];
664 bmp = bmp << p;
665 a_bmp = pm.dfm_active_port_bitmap[id];
666 a_bmp = a_bmp << p;
667 ret = ipu_fw_psys_set_proc_dfm_bitmap(process,
668 id, bmp,
669 a_bmp);
670 if (ret)
671 goto free_out;
672 }
673 }
674
675 if (pm.ext_mem_size) {
676 for (mem_type_id = 0;
677 mem_type_id < res_defs->num_ext_mem_types;
678 mem_type_id++) {
679 u32 bank = res_defs->num_ext_mem_ids;
680
681 if (cell != res_defs->num_cells) {
682 idx = res_defs->cell_mem_row * cell +
683 mem_type_id;
684 bank = res_defs->cell_mem[idx];
685 }
686 if (bank == res_defs->num_ext_mem_ids)
687 continue;
688
689 ret = __alloc_mem_resrc(dev, process,
690 &pool->ext_memory[bank],
691 &pm, mem_type_id,
692 bank, alloc);
693 if (ret)
694 goto free_out;
fad9119b 695
f2efa4ee
WY
696 /* no return value check here because fw api
697 * will do some checks, and would return
698 * non-zero except mem_type_id == 0.
699 * This maybe caused by that above flow of
700 * allocating mem_bank_id is improper.
701 */
702 idx = alloc->resources - 1;
703 p = alloc->resource_alloc[idx].pos;
704 ipu_fw_psys_set_process_ext_mem(process,
705 mem_type_id,
706 bank, p);
707 }
708 }
709 }
710 alloc->cells |= cells;
711 pool->cells |= cells;
712 return 0;
713
714free_out:
f2efa4ee 715 dev_err(dev, "failed to allocate resources, ret %d\n", ret);
af60d6fc 716 ipu_psys_reset_process_cell(dev, pg, pg_manifest, i + 1);
f2efa4ee
WY
717 ipu_psys_free_resources(alloc, pool);
718 return ret;
719}
720
721int ipu_psys_move_resources(const struct device *dev,
722 struct ipu_psys_resource_alloc *alloc,
723 struct ipu_psys_resource_pool
724 *source_pool, struct ipu_psys_resource_pool
725 *target_pool)
726{
727 int i;
728
729 if (target_pool->cells & alloc->cells) {
730 dev_dbg(dev, "out of cell resources\n");
731 return -ENOSPC;
732 }
733
734 for (i = 0; i < alloc->resources; i++) {
735 unsigned long bitmap = 0;
736 unsigned int id = alloc->resource_alloc[i].resource->id;
737 unsigned long fbit, end;
738
739 switch (alloc->resource_alloc[i].type) {
740 case IPU_RESOURCE_DEV_CHN:
741 bitmap_set(&bitmap, alloc->resource_alloc[i].pos,
742 alloc->resource_alloc[i].elements);
743 if (*target_pool->dev_channels[id].bitmap & bitmap)
744 return -ENOSPC;
745 break;
746 case IPU_RESOURCE_EXT_MEM:
747 end = alloc->resource_alloc[i].elements +
748 alloc->resource_alloc[i].pos;
749
750 fbit = find_next_bit(target_pool->ext_memory[id].bitmap,
751 end, alloc->resource_alloc[i].pos);
752 /* if find_next_bit returns "end" it didn't find 1bit */
753 if (end != fbit)
754 return -ENOSPC;
755 break;
756 case IPU_RESOURCE_DFM:
757 bitmap = alloc->resource_alloc[i].elements;
758 if (*target_pool->dfms[id].bitmap & bitmap)
759 return -ENOSPC;
760 break;
761 default:
762 dev_err(dev, "Illegal resource type\n");
763 return -EINVAL;
764 }
765 }
766
767 for (i = 0; i < alloc->resources; i++) {
768 u32 id = alloc->resource_alloc[i].resource->id;
769
770 switch (alloc->resource_alloc[i].type) {
771 case IPU_RESOURCE_DEV_CHN:
772 bitmap_set(target_pool->dev_channels[id].bitmap,
773 alloc->resource_alloc[i].pos,
774 alloc->resource_alloc[i].elements);
775 ipu_resource_free(&alloc->resource_alloc[i]);
776 alloc->resource_alloc[i].resource =
777 &target_pool->dev_channels[id];
778 break;
779 case IPU_RESOURCE_EXT_MEM:
780 bitmap_set(target_pool->ext_memory[id].bitmap,
781 alloc->resource_alloc[i].pos,
782 alloc->resource_alloc[i].elements);
783 ipu_resource_free(&alloc->resource_alloc[i]);
784 alloc->resource_alloc[i].resource =
785 &target_pool->ext_memory[id];
786 break;
787 case IPU_RESOURCE_DFM:
788 *target_pool->dfms[id].bitmap |=
789 alloc->resource_alloc[i].elements;
790 *alloc->resource_alloc[i].resource->bitmap &=
791 ~(alloc->resource_alloc[i].elements);
792 alloc->resource_alloc[i].resource =
793 &target_pool->dfms[id];
794 break;
795 default:
796 /*
797 * Just keep compiler happy. This case failed already
798 * in above loop.
799 */
800 break;
801 }
802 }
803
804 target_pool->cells |= alloc->cells;
805 source_pool->cells &= ~alloc->cells;
806
807 return 0;
808}
809
af60d6fc
WY
810void ipu_psys_reset_process_cell(const struct device *dev,
811 struct ipu_fw_psys_process_group *pg,
812 void *pg_manifest,
813 int process_count)
814{
815 int i;
816 u16 *process_offset_table;
817 const struct ipu_fw_resource_definitions *res_defs;
818
819 if (!pg)
820 return;
821
822 res_defs = get_res();
823 process_offset_table = (u16 *)((u8 *)pg + pg->processes_offset);
824 for (i = 0; i < process_count; i++) {
825 struct ipu_fw_psys_process *process =
826 (struct ipu_fw_psys_process *)
827 ((char *)pg + process_offset_table[i]);
828 struct ipu_fw_generic_program_manifest pm;
829 int ret;
830
831 if (!process)
832 break;
833
834 ret = ipu_fw_psys_get_program_manifest_by_process(&pm,
835 pg_manifest,
836 process);
837 if (ret < 0) {
838 dev_err(dev, "can not get manifest\n");
839 break;
840 }
841 if ((pm.cell_id != res_defs->num_cells &&
842 pm.cell_type_id == res_defs->num_cells_type))
843 continue;
844 /* no return value check here because if finding free cell
845 * failed, process cell would not set then calling clear_cell
846 * will return non-zero.
847 */
848 ipu_fw_psys_clear_process_cell(process);
849 }
850}
851
f2efa4ee
WY
852/* Free resources marked in `alloc' from `resources' */
853void ipu_psys_free_resources(struct ipu_psys_resource_alloc
854 *alloc, struct ipu_psys_resource_pool *pool)
855{
856 unsigned int i;
857
858 pool->cells &= ~alloc->cells;
859 alloc->cells = 0;
860 for (i = 0; i < alloc->resources; i++)
861 ipu_resource_free(&alloc->resource_alloc[i]);
862 alloc->resources = 0;
863}