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