1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19#include <linux/types.h>
20
21#include <dspbridge/host_os.h>
22
23#include <dspbridge/dbdefs.h>
24
25
26#include <dspbridge/cod.h>
27#include <dspbridge/dev.h>
28
29
30#include <dspbridge/dbll.h>
31#include <dspbridge/dbdcd.h>
32#include <dspbridge/rmm.h>
33#include <dspbridge/uuidutil.h>
34
35#include <dspbridge/nldr.h>
36#include <linux/lcm.h>
37
38
39#define DYNMEMSECT ".dspbridge_mem"
40
41
42#define DEPLIBSECT ".dspbridge_deplibs"
43
44
45#define MAXDEPTH 5
46
47
48#define MAXLIBS 5
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76#define MAXMEMSEGS 32
77
78#define MAXSEGID 3
79#define MEMINTERNALID 32
80#define MEMEXTERNALID 33
81#define NULLID 63
82#define FLAGBIT 7
83#define SEGMASK 0x3f
84
85#define CREATEBIT 0
86#define DELETEBIT 8
87#define EXECUTEBIT 16
88
89
90
91
92#define DYNM_CODE 0x2
93#define DYNM_DATA 0x4
94#define DYNM_CODEDATA (DYNM_CODE | DYNM_DATA)
95#define DYNM_INTERNAL 0x8
96#define DYNM_EXTERNAL 0x10
97
98
99
100
101
102
103
104
105
106
107
108#define CREATEDATAFLAGBIT 0
109#define CREATECODEFLAGBIT 1
110#define EXECUTEDATAFLAGBIT 2
111#define EXECUTECODEFLAGBIT 3
112#define DELETEDATAFLAGBIT 4
113#define DELETECODEFLAGBIT 5
114#define MAXFLAGS 6
115
116
117
118
119
120#define PCREATE "create"
121#define PDELETE "delete"
122#define PEXECUTE "execute"
123
124static inline bool is_equal_uuid(struct dsp_uuid *uuid1,
125 struct dsp_uuid *uuid2)
126{
127 return !memcmp(uuid1, uuid2, sizeof(struct dsp_uuid));
128}
129
130
131
132
133
134
135struct mem_seg_info {
136 u32 segid;
137 u32 base;
138 u32 len;
139 u32 type;
140};
141
142
143
144
145
146struct lib_node {
147 struct dbll_library_obj *lib;
148 u16 dep_libs;
149 struct lib_node *dep_libs_tree;
150};
151
152
153
154
155
156struct ovly_sect {
157 struct ovly_sect *next_sect;
158 u32 sect_load_addr;
159 u32 sect_run_addr;
160 u32 size;
161 u16 page;
162};
163
164
165
166
167
168
169struct ovly_node {
170 struct dsp_uuid uuid;
171 char *node_name;
172 struct ovly_sect *create_sects_list;
173 struct ovly_sect *delete_sects_list;
174 struct ovly_sect *execute_sects_list;
175 struct ovly_sect *other_sects_list;
176 u16 create_sects;
177 u16 delete_sects;
178 u16 execute_sects;
179 u16 other_sects;
180 u16 create_ref;
181 u16 delete_ref;
182 u16 execute_ref;
183 u16 other_ref;
184};
185
186
187
188
189
190struct nldr_object {
191 struct dev_object *dev_obj;
192 struct dcd_manager *dcd_mgr;
193 struct dbll_tar_obj *dbll;
194 struct dbll_library_obj *base_lib;
195 struct rmm_target_obj *rmm;
196 struct dbll_fxns ldr_fxns;
197 struct dbll_attrs ldr_attrs;
198 nldr_ovlyfxn ovly_fxn;
199 nldr_writefxn write_fxn;
200 struct ovly_node *ovly_table;
201 u16 ovly_nodes;
202 u16 ovly_nid;
203 u16 dload_segs;
204 u32 *seg_table;
205
206
207 u16 dsp_mau_size;
208 u16 dsp_word_size;
209};
210
211
212
213
214
215struct nldr_nodeobject {
216 struct nldr_object *nldr_obj;
217 void *priv_ref;
218 struct dsp_uuid uuid;
219 bool dynamic;
220 bool overlay;
221 bool *phase_split;
222 struct lib_node root;
223 struct lib_node create_lib;
224 struct lib_node execute_lib;
225 struct lib_node delete_lib;
226
227 struct lib_node pers_lib_table[MAXLIBS];
228 s32 pers_libs;
229
230 struct dbll_library_obj *lib_path[MAXDEPTH + 1];
231 enum nldr_phase phase;
232
233
234
235
236 u16 seg_id[MAXFLAGS];
237
238
239
240
241
242
243
244
245
246 u32 code_data_flag_mask;
247};
248
249
250static struct dbll_fxns ldr_fxns = {
251 (dbll_close_fxn) dbll_close,
252 (dbll_create_fxn) dbll_create,
253 (dbll_delete_fxn) dbll_delete,
254 (dbll_exit_fxn) dbll_exit,
255 (dbll_get_attrs_fxn) dbll_get_attrs,
256 (dbll_get_addr_fxn) dbll_get_addr,
257 (dbll_get_c_addr_fxn) dbll_get_c_addr,
258 (dbll_get_sect_fxn) dbll_get_sect,
259 (dbll_init_fxn) dbll_init,
260 (dbll_load_fxn) dbll_load,
261 (dbll_open_fxn) dbll_open,
262 (dbll_read_sect_fxn) dbll_read_sect,
263 (dbll_unload_fxn) dbll_unload,
264};
265
266static int add_ovly_info(void *handle, struct dbll_sect_info *sect_info,
267 u32 addr, u32 bytes);
268static int add_ovly_node(struct dsp_uuid *uuid_obj,
269 enum dsp_dcdobjtype obj_type, void *handle);
270static int add_ovly_sect(struct nldr_object *nldr_obj,
271 struct ovly_sect **lst,
272 struct dbll_sect_info *sect_inf,
273 bool *exists, u32 addr, u32 bytes);
274static s32 fake_ovly_write(void *handle, u32 dsp_address, void *buf, u32 bytes,
275 s32 mtype);
276static void free_sects(struct nldr_object *nldr_obj,
277 struct ovly_sect *phase_sects, u16 alloc_num);
278static bool get_symbol_value(void *handle, void *parg, void *rmm_handle,
279 char *sym_name, struct dbll_sym_val **sym);
280static int load_lib(struct nldr_nodeobject *nldr_node_obj,
281 struct lib_node *root, struct dsp_uuid uuid,
282 bool root_prstnt,
283 struct dbll_library_obj **lib_path,
284 enum nldr_phase phase, u16 depth);
285static int load_ovly(struct nldr_nodeobject *nldr_node_obj,
286 enum nldr_phase phase);
287static int remote_alloc(void **ref, u16 mem_sect, u32 size,
288 u32 align, u32 *dsp_address,
289 s32 segmnt_id,
290 s32 req, bool reserve);
291static int remote_free(void **ref, u16 space, u32 dsp_address, u32 size,
292 bool reserve);
293
294static void unload_lib(struct nldr_nodeobject *nldr_node_obj,
295 struct lib_node *root);
296static void unload_ovly(struct nldr_nodeobject *nldr_node_obj,
297 enum nldr_phase phase);
298static bool find_in_persistent_lib_array(struct nldr_nodeobject *nldr_node_obj,
299 struct dbll_library_obj *lib);
300
301
302
303
304int nldr_allocate(struct nldr_object *nldr_obj, void *priv_ref,
305 const struct dcd_nodeprops *node_props,
306 struct nldr_nodeobject **nldr_nodeobj,
307 bool *pf_phase_split)
308{
309 struct nldr_nodeobject *nldr_node_obj = NULL;
310 int status = 0;
311
312
313 *nldr_nodeobj = NULL;
314
315 nldr_node_obj = kzalloc(sizeof(struct nldr_nodeobject), GFP_KERNEL);
316
317 if (nldr_node_obj == NULL) {
318 status = -ENOMEM;
319 } else {
320 nldr_node_obj->phase_split = pf_phase_split;
321 nldr_node_obj->pers_libs = 0;
322 nldr_node_obj->nldr_obj = nldr_obj;
323 nldr_node_obj->priv_ref = priv_ref;
324
325 nldr_node_obj->uuid = node_props->ndb_props.ui_node_id;
326
327
328
329
330 if (node_props->load_type == NLDR_DYNAMICLOAD) {
331
332 nldr_node_obj->dynamic = true;
333
334
335
336
337 nldr_node_obj->seg_id[CREATEDATAFLAGBIT] = (u16)
338 (node_props->data_mem_seg_mask >> CREATEBIT) &
339 SEGMASK;
340 nldr_node_obj->code_data_flag_mask |=
341 ((node_props->data_mem_seg_mask >>
342 (CREATEBIT + FLAGBIT)) & 1) << CREATEDATAFLAGBIT;
343 nldr_node_obj->seg_id[CREATECODEFLAGBIT] = (u16)
344 (node_props->code_mem_seg_mask >>
345 CREATEBIT) & SEGMASK;
346 nldr_node_obj->code_data_flag_mask |=
347 ((node_props->code_mem_seg_mask >>
348 (CREATEBIT + FLAGBIT)) & 1) << CREATECODEFLAGBIT;
349
350 nldr_node_obj->seg_id[EXECUTEDATAFLAGBIT] = (u16)
351 (node_props->data_mem_seg_mask >>
352 EXECUTEBIT) & SEGMASK;
353 nldr_node_obj->code_data_flag_mask |=
354 ((node_props->data_mem_seg_mask >>
355 (EXECUTEBIT + FLAGBIT)) & 1) <<
356 EXECUTEDATAFLAGBIT;
357 nldr_node_obj->seg_id[EXECUTECODEFLAGBIT] = (u16)
358 (node_props->code_mem_seg_mask >>
359 EXECUTEBIT) & SEGMASK;
360 nldr_node_obj->code_data_flag_mask |=
361 ((node_props->code_mem_seg_mask >>
362 (EXECUTEBIT + FLAGBIT)) & 1) <<
363 EXECUTECODEFLAGBIT;
364
365 nldr_node_obj->seg_id[DELETEDATAFLAGBIT] = (u16)
366 (node_props->data_mem_seg_mask >> DELETEBIT) &
367 SEGMASK;
368 nldr_node_obj->code_data_flag_mask |=
369 ((node_props->data_mem_seg_mask >>
370 (DELETEBIT + FLAGBIT)) & 1) << DELETEDATAFLAGBIT;
371 nldr_node_obj->seg_id[DELETECODEFLAGBIT] = (u16)
372 (node_props->code_mem_seg_mask >>
373 DELETEBIT) & SEGMASK;
374 nldr_node_obj->code_data_flag_mask |=
375 ((node_props->code_mem_seg_mask >>
376 (DELETEBIT + FLAGBIT)) & 1) << DELETECODEFLAGBIT;
377 } else {
378
379
380 nldr_node_obj->root.lib = nldr_obj->base_lib;
381
382 if (node_props->load_type == NLDR_OVLYLOAD)
383 nldr_node_obj->overlay = true;
384
385 }
386 *nldr_nodeobj = (struct nldr_nodeobject *)nldr_node_obj;
387 }
388
389 if (status && nldr_node_obj)
390 kfree(nldr_node_obj);
391
392 return status;
393}
394
395
396
397
398int nldr_create(struct nldr_object **nldr,
399 struct dev_object *hdev_obj,
400 const struct nldr_attrs *pattrs)
401{
402 struct cod_manager *cod_mgr;
403 char *psz_coff_buf = NULL;
404 char sz_zl_file[COD_MAXPATHLENGTH];
405 struct nldr_object *nldr_obj = NULL;
406 struct dbll_attrs save_attrs;
407 struct dbll_attrs new_attrs;
408 dbll_flags flags;
409 u32 ul_entry;
410 u16 dload_segs = 0;
411 struct mem_seg_info *mem_info_obj;
412 u32 ul_len = 0;
413 u32 ul_addr;
414 struct rmm_segment *rmm_segs = NULL;
415 u16 i;
416 int status = 0;
417
418
419 nldr_obj = kzalloc(sizeof(struct nldr_object), GFP_KERNEL);
420 if (nldr_obj) {
421 nldr_obj->dev_obj = hdev_obj;
422
423 dev_get_cod_mgr(hdev_obj, &cod_mgr);
424 if (cod_mgr) {
425 status = cod_get_loader(cod_mgr, &nldr_obj->dbll);
426 status = cod_get_base_lib(cod_mgr, &nldr_obj->base_lib);
427 status =
428 cod_get_base_name(cod_mgr, sz_zl_file,
429 COD_MAXPATHLENGTH);
430 }
431 status = 0;
432
433 nldr_obj->dsp_mau_size = pattrs->dsp_mau_size;
434 nldr_obj->dsp_word_size = pattrs->dsp_word_size;
435 nldr_obj->ldr_fxns = ldr_fxns;
436 if (!(nldr_obj->ldr_fxns.init_fxn()))
437 status = -ENOMEM;
438
439 } else {
440 status = -ENOMEM;
441 }
442
443 if (!status)
444 status = dcd_create_manager(NULL, &nldr_obj->dcd_mgr);
445
446
447 if (!status) {
448 status =
449 nldr_obj->ldr_fxns.get_sect_fxn(nldr_obj->base_lib,
450 DYNMEMSECT, &ul_addr,
451 &ul_len);
452 if (!status) {
453 psz_coff_buf =
454 kzalloc(ul_len * nldr_obj->dsp_mau_size,
455 GFP_KERNEL);
456 if (!psz_coff_buf)
457 status = -ENOMEM;
458 } else {
459
460 status = 0;
461 ul_len = 0;
462 dev_dbg(bridge, "%s: failed - no dynamic loading mem "
463 "segments: 0x%x\n", __func__, status);
464 }
465 }
466 if (!status && ul_len > 0) {
467
468 status =
469 nldr_obj->ldr_fxns.read_sect_fxn(nldr_obj->base_lib,
470 DYNMEMSECT, psz_coff_buf,
471 ul_len);
472 }
473 if (!status && ul_len > 0) {
474
475 dload_segs = (u16) (*((u32 *) psz_coff_buf));
476 if (dload_segs > MAXMEMSEGS)
477 status = -EBADF;
478 }
479
480 if (!status && dload_segs > 0) {
481 rmm_segs = kzalloc(sizeof(struct rmm_segment) * dload_segs,
482 GFP_KERNEL);
483 nldr_obj->seg_table =
484 kzalloc(sizeof(u32) * dload_segs, GFP_KERNEL);
485 if (rmm_segs == NULL || nldr_obj->seg_table == NULL) {
486 status = -ENOMEM;
487 } else {
488 nldr_obj->dload_segs = dload_segs;
489 mem_info_obj = (struct mem_seg_info *)(psz_coff_buf +
490 sizeof(u32));
491 for (i = 0; i < dload_segs; i++) {
492 rmm_segs[i].base = (mem_info_obj + i)->base;
493 rmm_segs[i].length = (mem_info_obj + i)->len;
494 rmm_segs[i].space = 0;
495 nldr_obj->seg_table[i] =
496 (mem_info_obj + i)->type;
497 dev_dbg(bridge,
498 "(proc) DLL MEMSEGMENT: %d, "
499 "Base: 0x%x, Length: 0x%x\n", i,
500 rmm_segs[i].base, rmm_segs[i].length);
501 }
502 }
503 }
504
505 if (!status)
506 status = rmm_create(&nldr_obj->rmm, rmm_segs, dload_segs);
507
508 if (!status) {
509
510 nldr_obj->ldr_fxns.get_attrs_fxn(nldr_obj->dbll, &save_attrs);
511 new_attrs = save_attrs;
512 new_attrs.alloc = (dbll_alloc_fxn) remote_alloc;
513 new_attrs.free = (dbll_free_fxn) remote_free;
514 new_attrs.sym_lookup = (dbll_sym_lookup) get_symbol_value;
515 new_attrs.sym_handle = nldr_obj;
516 new_attrs.write = (dbll_write_fxn) pattrs->write;
517 nldr_obj->ovly_fxn = pattrs->ovly;
518 nldr_obj->write_fxn = pattrs->write;
519 nldr_obj->ldr_attrs = new_attrs;
520 }
521 kfree(rmm_segs);
522
523 kfree(psz_coff_buf);
524
525
526 if (!status) {
527 status =
528 cod_get_base_name(cod_mgr, sz_zl_file, COD_MAXPATHLENGTH);
529
530
531 status =
532 dcd_get_objects(nldr_obj->dcd_mgr, sz_zl_file,
533 add_ovly_node, (void *)nldr_obj);
534
535 if (!status && nldr_obj->ovly_nodes > 0) {
536
537 nldr_obj->ovly_table =
538 kzalloc(sizeof(struct ovly_node) *
539 nldr_obj->ovly_nodes, GFP_KERNEL);
540
541 nldr_obj->ovly_nid = 0;
542 status = dcd_get_objects(nldr_obj->dcd_mgr, sz_zl_file,
543 add_ovly_node,
544 (void *)nldr_obj);
545 }
546 }
547
548 if (!status && nldr_obj->ovly_nodes > 0) {
549 save_attrs.write = fake_ovly_write;
550 save_attrs.log_write = add_ovly_info;
551 save_attrs.log_write_handle = nldr_obj;
552 flags = DBLL_CODE | DBLL_DATA | DBLL_SYMB;
553 status = nldr_obj->ldr_fxns.load_fxn(nldr_obj->base_lib, flags,
554 &save_attrs, &ul_entry);
555 }
556 if (!status) {
557 *nldr = (struct nldr_object *)nldr_obj;
558 } else {
559 if (nldr_obj)
560 nldr_delete((struct nldr_object *)nldr_obj);
561
562 *nldr = NULL;
563 }
564
565 return status;
566}
567
568
569
570
571void nldr_delete(struct nldr_object *nldr_obj)
572{
573 struct ovly_sect *ovly_section;
574 struct ovly_sect *next;
575 u16 i;
576
577 nldr_obj->ldr_fxns.exit_fxn();
578 if (nldr_obj->rmm)
579 rmm_delete(nldr_obj->rmm);
580
581 kfree(nldr_obj->seg_table);
582
583 if (nldr_obj->dcd_mgr)
584 dcd_destroy_manager(nldr_obj->dcd_mgr);
585
586
587 if (nldr_obj->ovly_table) {
588 for (i = 0; i < nldr_obj->ovly_nodes; i++) {
589 ovly_section =
590 nldr_obj->ovly_table[i].create_sects_list;
591 while (ovly_section) {
592 next = ovly_section->next_sect;
593 kfree(ovly_section);
594 ovly_section = next;
595 }
596 ovly_section =
597 nldr_obj->ovly_table[i].delete_sects_list;
598 while (ovly_section) {
599 next = ovly_section->next_sect;
600 kfree(ovly_section);
601 ovly_section = next;
602 }
603 ovly_section =
604 nldr_obj->ovly_table[i].execute_sects_list;
605 while (ovly_section) {
606 next = ovly_section->next_sect;
607 kfree(ovly_section);
608 ovly_section = next;
609 }
610 ovly_section = nldr_obj->ovly_table[i].other_sects_list;
611 while (ovly_section) {
612 next = ovly_section->next_sect;
613 kfree(ovly_section);
614 ovly_section = next;
615 }
616 }
617 kfree(nldr_obj->ovly_table);
618 }
619 kfree(nldr_obj);
620}
621
622
623
624
625int nldr_get_fxn_addr(struct nldr_nodeobject *nldr_node_obj,
626 char *str_fxn, u32 * addr)
627{
628 struct dbll_sym_val *dbll_sym;
629 struct nldr_object *nldr_obj;
630 int status = 0;
631 bool status1 = false;
632 s32 i = 0;
633 struct lib_node root = { NULL, 0, NULL };
634
635 nldr_obj = nldr_node_obj->nldr_obj;
636
637 if (nldr_node_obj->dynamic && *nldr_node_obj->phase_split) {
638 switch (nldr_node_obj->phase) {
639 case NLDR_CREATE:
640 root = nldr_node_obj->create_lib;
641 break;
642 case NLDR_EXECUTE:
643 root = nldr_node_obj->execute_lib;
644 break;
645 case NLDR_DELETE:
646 root = nldr_node_obj->delete_lib;
647 break;
648 default:
649 break;
650 }
651 } else {
652
653 root = nldr_node_obj->root;
654 }
655 status1 =
656 nldr_obj->ldr_fxns.get_c_addr_fxn(root.lib, str_fxn, &dbll_sym);
657 if (!status1)
658 status1 =
659 nldr_obj->ldr_fxns.get_addr_fxn(root.lib, str_fxn,
660 &dbll_sym);
661
662
663 if (!status1) {
664 for (i = 0; i < root.dep_libs; i++) {
665 status1 =
666 nldr_obj->ldr_fxns.get_addr_fxn(root.dep_libs_tree
667 [i].lib, str_fxn,
668 &dbll_sym);
669 if (!status1) {
670 status1 =
671 nldr_obj->ldr_fxns.
672 get_c_addr_fxn(root.dep_libs_tree[i].lib,
673 str_fxn, &dbll_sym);
674 }
675 if (status1) {
676
677 break;
678 }
679 }
680 }
681
682 if (!status1) {
683 for (i = 0; i < nldr_node_obj->pers_libs; i++) {
684 status1 =
685 nldr_obj->ldr_fxns.
686 get_addr_fxn(nldr_node_obj->pers_lib_table[i].lib,
687 str_fxn, &dbll_sym);
688 if (!status1) {
689 status1 =
690 nldr_obj->ldr_fxns.
691 get_c_addr_fxn(nldr_node_obj->pers_lib_table
692 [i].lib, str_fxn, &dbll_sym);
693 }
694 if (status1) {
695
696 break;
697 }
698 }
699 }
700
701 if (status1)
702 *addr = dbll_sym->value;
703 else
704 status = -ESPIPE;
705
706 return status;
707}
708
709
710
711
712
713int nldr_get_rmm_manager(struct nldr_object *nldr,
714 struct rmm_target_obj **rmm_mgr)
715{
716 int status = 0;
717 struct nldr_object *nldr_obj = nldr;
718
719 if (nldr) {
720 *rmm_mgr = nldr_obj->rmm;
721 } else {
722 *rmm_mgr = NULL;
723 status = -EFAULT;
724 }
725
726 return status;
727}
728
729
730
731
732int nldr_load(struct nldr_nodeobject *nldr_node_obj,
733 enum nldr_phase phase)
734{
735 struct nldr_object *nldr_obj;
736 struct dsp_uuid lib_uuid;
737 int status = 0;
738
739 nldr_obj = nldr_node_obj->nldr_obj;
740
741 if (nldr_node_obj->dynamic) {
742 nldr_node_obj->phase = phase;
743
744 lib_uuid = nldr_node_obj->uuid;
745
746
747
748
749
750
751 status =
752 load_lib(nldr_node_obj, &nldr_node_obj->root, lib_uuid,
753 false, nldr_node_obj->lib_path, phase, 0);
754
755 if (!status) {
756 if (*nldr_node_obj->phase_split) {
757 switch (phase) {
758 case NLDR_CREATE:
759 nldr_node_obj->create_lib =
760 nldr_node_obj->root;
761 break;
762
763 case NLDR_EXECUTE:
764 nldr_node_obj->execute_lib =
765 nldr_node_obj->root;
766 break;
767
768 case NLDR_DELETE:
769 nldr_node_obj->delete_lib =
770 nldr_node_obj->root;
771 break;
772
773 default:
774 break;
775 }
776 }
777 }
778 } else {
779 if (nldr_node_obj->overlay)
780 status = load_ovly(nldr_node_obj, phase);
781
782 }
783
784 return status;
785}
786
787
788
789
790int nldr_unload(struct nldr_nodeobject *nldr_node_obj,
791 enum nldr_phase phase)
792{
793 int status = 0;
794 struct lib_node *root_lib = NULL;
795 s32 i = 0;
796
797 if (nldr_node_obj != NULL) {
798 if (nldr_node_obj->dynamic) {
799 if (*nldr_node_obj->phase_split) {
800 switch (phase) {
801 case NLDR_CREATE:
802 root_lib = &nldr_node_obj->create_lib;
803 break;
804 case NLDR_EXECUTE:
805 root_lib = &nldr_node_obj->execute_lib;
806 break;
807 case NLDR_DELETE:
808 root_lib = &nldr_node_obj->delete_lib;
809
810 for (i = 0;
811 i < nldr_node_obj->pers_libs;
812 i++) {
813 unload_lib(nldr_node_obj,
814 &nldr_node_obj->
815 pers_lib_table[i]);
816 }
817 nldr_node_obj->pers_libs = 0;
818 break;
819 default:
820 break;
821 }
822 } else {
823
824 root_lib = &nldr_node_obj->root;
825 }
826 if (root_lib)
827 unload_lib(nldr_node_obj, root_lib);
828 } else {
829 if (nldr_node_obj->overlay)
830 unload_ovly(nldr_node_obj, phase);
831
832 }
833 }
834 return status;
835}
836
837
838
839
840static int add_ovly_info(void *handle, struct dbll_sect_info *sect_info,
841 u32 addr, u32 bytes)
842{
843 char *node_name;
844 char *sect_name = (char *)sect_info->name;
845 bool sect_exists = false;
846 char seps = ':';
847 char *pch;
848 u16 i;
849 struct nldr_object *nldr_obj = (struct nldr_object *)handle;
850 int status = 0;
851
852
853 if (sect_info->sect_load_addr == sect_info->sect_run_addr)
854 goto func_end;
855
856
857 for (i = 0; i < nldr_obj->ovly_nodes; i++) {
858 node_name = nldr_obj->ovly_table[i].node_name;
859 if (strncmp(node_name, sect_name + 1, strlen(node_name)) == 0) {
860
861 break;
862 }
863 }
864 if (!(i < nldr_obj->ovly_nodes))
865 goto func_end;
866
867
868 for (pch = sect_name + 1; *pch && *pch != seps; pch++)
869 ;
870
871 if (*pch) {
872 pch++;
873 if (strncmp(pch, PCREATE, strlen(PCREATE)) == 0) {
874 status =
875 add_ovly_sect(nldr_obj,
876 &nldr_obj->
877 ovly_table[i].create_sects_list,
878 sect_info, §_exists, addr, bytes);
879 if (!status && !sect_exists)
880 nldr_obj->ovly_table[i].create_sects++;
881
882 } else if (strncmp(pch, PDELETE, strlen(PDELETE)) == 0) {
883 status =
884 add_ovly_sect(nldr_obj,
885 &nldr_obj->
886 ovly_table[i].delete_sects_list,
887 sect_info, §_exists, addr, bytes);
888 if (!status && !sect_exists)
889 nldr_obj->ovly_table[i].delete_sects++;
890
891 } else if (strncmp(pch, PEXECUTE, strlen(PEXECUTE)) == 0) {
892 status =
893 add_ovly_sect(nldr_obj,
894 &nldr_obj->
895 ovly_table[i].execute_sects_list,
896 sect_info, §_exists, addr, bytes);
897 if (!status && !sect_exists)
898 nldr_obj->ovly_table[i].execute_sects++;
899
900 } else {
901
902 status =
903 add_ovly_sect(nldr_obj,
904 &nldr_obj->
905 ovly_table[i].other_sects_list,
906 sect_info, §_exists, addr, bytes);
907 if (!status && !sect_exists)
908 nldr_obj->ovly_table[i].other_sects++;
909
910 }
911 }
912func_end:
913 return status;
914}
915
916
917
918
919
920static int add_ovly_node(struct dsp_uuid *uuid_obj,
921 enum dsp_dcdobjtype obj_type, void *handle)
922{
923 struct nldr_object *nldr_obj = (struct nldr_object *)handle;
924 char *node_name = NULL;
925 char *pbuf = NULL;
926 u32 len;
927 struct dcd_genericobj obj_def;
928 int status = 0;
929
930 if (obj_type != DSP_DCDNODETYPE)
931 goto func_end;
932
933 status =
934 dcd_get_object_def(nldr_obj->dcd_mgr, uuid_obj, obj_type,
935 &obj_def);
936 if (status)
937 goto func_end;
938
939
940 if (obj_def.obj_data.node_obj.load_type == NLDR_OVLYLOAD) {
941 if (nldr_obj->ovly_table == NULL) {
942 nldr_obj->ovly_nodes++;
943 } else {
944
945 nldr_obj->ovly_table[nldr_obj->ovly_nid].uuid =
946 *uuid_obj;
947 len =
948 strlen(obj_def.obj_data.node_obj.ndb_props.ac_name);
949 node_name = obj_def.obj_data.node_obj.ndb_props.ac_name;
950 pbuf = kzalloc(len + 1, GFP_KERNEL);
951 if (pbuf == NULL) {
952 status = -ENOMEM;
953 } else {
954 strncpy(pbuf, node_name, len);
955 nldr_obj->ovly_table[nldr_obj->ovly_nid].
956 node_name = pbuf;
957 nldr_obj->ovly_nid++;
958 }
959 }
960 }
961
962 kfree(obj_def.obj_data.node_obj.str_create_phase_fxn);
963
964 kfree(obj_def.obj_data.node_obj.str_execute_phase_fxn);
965
966 kfree(obj_def.obj_data.node_obj.str_delete_phase_fxn);
967
968 kfree(obj_def.obj_data.node_obj.str_i_alg_name);
969
970func_end:
971 return status;
972}
973
974
975
976
977static int add_ovly_sect(struct nldr_object *nldr_obj,
978 struct ovly_sect **lst,
979 struct dbll_sect_info *sect_inf,
980 bool *exists, u32 addr, u32 bytes)
981{
982 struct ovly_sect *new_sect = NULL;
983 struct ovly_sect *last_sect;
984 struct ovly_sect *ovly_section;
985 int status = 0;
986
987 ovly_section = last_sect = *lst;
988 *exists = false;
989 while (ovly_section) {
990
991
992
993
994 if (ovly_section->sect_load_addr == addr) {
995
996 *exists = true;
997 break;
998 }
999 last_sect = ovly_section;
1000 ovly_section = ovly_section->next_sect;
1001 }
1002
1003 if (!ovly_section) {
1004
1005 new_sect = kzalloc(sizeof(struct ovly_sect), GFP_KERNEL);
1006 if (new_sect == NULL) {
1007 status = -ENOMEM;
1008 } else {
1009 new_sect->sect_load_addr = addr;
1010 new_sect->sect_run_addr = sect_inf->sect_run_addr +
1011 (addr - sect_inf->sect_load_addr);
1012 new_sect->size = bytes;
1013 new_sect->page = sect_inf->type;
1014 }
1015
1016
1017 if (!status) {
1018 if (*lst == NULL) {
1019
1020 *lst = new_sect;
1021 } else {
1022 last_sect->next_sect = new_sect;
1023 }
1024 }
1025 }
1026
1027 return status;
1028}
1029
1030
1031
1032
1033static s32 fake_ovly_write(void *handle, u32 dsp_address, void *buf, u32 bytes,
1034 s32 mtype)
1035{
1036 return (s32) bytes;
1037}
1038
1039
1040
1041
1042static void free_sects(struct nldr_object *nldr_obj,
1043 struct ovly_sect *phase_sects, u16 alloc_num)
1044{
1045 struct ovly_sect *ovly_section = phase_sects;
1046 u16 i = 0;
1047 bool ret;
1048
1049 while (ovly_section && i < alloc_num) {
1050
1051
1052
1053 ret =
1054 rmm_free(nldr_obj->rmm, 0, ovly_section->sect_run_addr,
1055 ovly_section->size, true);
1056 ovly_section = ovly_section->next_sect;
1057 i++;
1058 }
1059}
1060
1061
1062
1063
1064
1065
1066static bool get_symbol_value(void *handle, void *parg, void *rmm_handle,
1067 char *sym_name, struct dbll_sym_val **sym)
1068{
1069 struct nldr_object *nldr_obj = (struct nldr_object *)handle;
1070 struct nldr_nodeobject *nldr_node_obj =
1071 (struct nldr_nodeobject *)rmm_handle;
1072 struct lib_node *root = (struct lib_node *)parg;
1073 u16 i;
1074 bool status = false;
1075
1076
1077 status = nldr_obj->ldr_fxns.get_addr_fxn(nldr_obj->base_lib,
1078 sym_name, sym);
1079 if (!status)
1080 status =
1081 nldr_obj->ldr_fxns.get_c_addr_fxn(nldr_obj->base_lib,
1082 sym_name, sym);
1083
1084
1085
1086
1087
1088
1089 if (!status) {
1090 status = nldr_obj->ldr_fxns.get_addr_fxn(root->lib, sym_name,
1091 sym);
1092 if (!status) {
1093 status =
1094 nldr_obj->ldr_fxns.get_c_addr_fxn(root->lib,
1095 sym_name, sym);
1096 }
1097 }
1098
1099
1100
1101
1102
1103 if (!status) {
1104 for (i = 0; i < root->dep_libs; i++) {
1105 status =
1106 nldr_obj->ldr_fxns.get_addr_fxn(root->
1107 dep_libs_tree
1108 [i].lib,
1109 sym_name, sym);
1110 if (!status) {
1111 status =
1112 nldr_obj->ldr_fxns.
1113 get_c_addr_fxn(root->dep_libs_tree[i].lib,
1114 sym_name, sym);
1115 }
1116 if (status) {
1117
1118 break;
1119 }
1120 }
1121 }
1122
1123
1124
1125 if (!status) {
1126 for (i = 0; i < nldr_node_obj->pers_libs; i++) {
1127 status =
1128 nldr_obj->ldr_fxns.
1129 get_addr_fxn(nldr_node_obj->pers_lib_table[i].lib,
1130 sym_name, sym);
1131 if (!status) {
1132 status = nldr_obj->ldr_fxns.get_c_addr_fxn
1133 (nldr_node_obj->pers_lib_table[i].lib,
1134 sym_name, sym);
1135 }
1136 if (status) {
1137
1138 break;
1139 }
1140 }
1141 }
1142
1143 return status;
1144}
1145
1146
1147
1148
1149
1150
1151static int load_lib(struct nldr_nodeobject *nldr_node_obj,
1152 struct lib_node *root, struct dsp_uuid uuid,
1153 bool root_prstnt,
1154 struct dbll_library_obj **lib_path,
1155 enum nldr_phase phase, u16 depth)
1156{
1157 struct nldr_object *nldr_obj = nldr_node_obj->nldr_obj;
1158 u16 nd_libs = 0;
1159 u16 np_libs = 0;
1160 u16 nd_libs_loaded = 0;
1161 u16 i;
1162 u32 entry;
1163 u32 dw_buf_size = NLDR_MAXPATHLENGTH;
1164 dbll_flags flags = DBLL_SYMB | DBLL_CODE | DBLL_DATA | DBLL_DYNAMIC;
1165 struct dbll_attrs new_attrs;
1166 char *psz_file_name = NULL;
1167 struct dsp_uuid *dep_lib_uui_ds = NULL;
1168 bool *persistent_dep_libs = NULL;
1169 int status = 0;
1170 bool lib_status = false;
1171 struct lib_node *dep_lib;
1172
1173 if (depth > MAXDEPTH) {
1174
1175 }
1176 root->lib = NULL;
1177
1178 psz_file_name = kzalloc(DBLL_MAXPATHLENGTH, GFP_KERNEL);
1179 if (psz_file_name == NULL)
1180 status = -ENOMEM;
1181
1182 if (!status) {
1183
1184 if (depth == 0) {
1185 status =
1186 dcd_get_library_name(nldr_node_obj->nldr_obj->
1187 dcd_mgr, &uuid, psz_file_name,
1188 &dw_buf_size, phase,
1189 nldr_node_obj->phase_split);
1190 } else {
1191
1192 status =
1193 dcd_get_library_name(nldr_node_obj->nldr_obj->
1194 dcd_mgr, &uuid, psz_file_name,
1195 &dw_buf_size, NLDR_NOPHASE,
1196 NULL);
1197 }
1198 }
1199 if (!status) {
1200
1201 status =
1202 nldr_obj->ldr_fxns.open_fxn(nldr_obj->dbll, psz_file_name,
1203 DBLL_NOLOAD, &root->lib);
1204 }
1205
1206 kfree(psz_file_name);
1207
1208
1209 if (!status && root_prstnt) {
1210 lib_status =
1211 find_in_persistent_lib_array(nldr_node_obj, root->lib);
1212
1213 if (lib_status) {
1214 nldr_obj->ldr_fxns.close_fxn(root->lib);
1215 return 0;
1216 }
1217 }
1218 if (!status) {
1219
1220 for (i = 0; i < depth; i++) {
1221 if (root->lib == lib_path[i]) {
1222
1223
1224 status = -EILSEQ;
1225 }
1226 }
1227 }
1228 if (!status) {
1229
1230 lib_path[depth] = root->lib;
1231 depth++;
1232
1233 status =
1234 dcd_get_num_dep_libs(nldr_node_obj->nldr_obj->dcd_mgr,
1235 &uuid, &nd_libs, &np_libs, phase);
1236 }
1237 if (!status) {
1238 if (!(*nldr_node_obj->phase_split))
1239 np_libs = 0;
1240
1241
1242 root->dep_libs = nd_libs - np_libs;
1243 if (nd_libs > 0) {
1244 dep_lib_uui_ds = kzalloc(sizeof(struct dsp_uuid) *
1245 nd_libs, GFP_KERNEL);
1246 persistent_dep_libs =
1247 kzalloc(sizeof(bool) * nd_libs, GFP_KERNEL);
1248 if (!dep_lib_uui_ds || !persistent_dep_libs)
1249 status = -ENOMEM;
1250
1251 if (root->dep_libs > 0) {
1252
1253
1254 root->dep_libs_tree = kzalloc
1255 (sizeof(struct lib_node) *
1256 (root->dep_libs), GFP_KERNEL);
1257 if (!(root->dep_libs_tree))
1258 status = -ENOMEM;
1259
1260 }
1261
1262 if (!status) {
1263
1264 status =
1265 dcd_get_dep_libs(nldr_node_obj->
1266 nldr_obj->dcd_mgr, &uuid,
1267 nd_libs, dep_lib_uui_ds,
1268 persistent_dep_libs,
1269 phase);
1270 }
1271 }
1272 }
1273
1274
1275
1276
1277 if (!status) {
1278 for (i = 0; i < nd_libs; i++) {
1279
1280
1281
1282 if (!root_prstnt && persistent_dep_libs[i] &&
1283 *nldr_node_obj->phase_split) {
1284 if ((nldr_node_obj->pers_libs) >= MAXLIBS) {
1285 status = -EILSEQ;
1286 break;
1287 }
1288
1289
1290 dep_lib =
1291 &nldr_node_obj->pers_lib_table
1292 [nldr_node_obj->pers_libs];
1293 } else {
1294 if (root_prstnt)
1295 persistent_dep_libs[i] = true;
1296
1297
1298 dep_lib = &root->dep_libs_tree[nd_libs_loaded];
1299 }
1300
1301 status = load_lib(nldr_node_obj, dep_lib,
1302 dep_lib_uui_ds[i],
1303 persistent_dep_libs[i], lib_path,
1304 phase, depth);
1305
1306 if (!status) {
1307 if ((status != 0) &&
1308 !root_prstnt && persistent_dep_libs[i] &&
1309 *nldr_node_obj->phase_split) {
1310 (nldr_node_obj->pers_libs)++;
1311 } else {
1312 if (!persistent_dep_libs[i] ||
1313 !(*nldr_node_obj->phase_split)) {
1314 nd_libs_loaded++;
1315 }
1316 }
1317 } else {
1318 break;
1319 }
1320 }
1321 }
1322
1323
1324 if (!status) {
1325 new_attrs = nldr_obj->ldr_attrs;
1326 new_attrs.sym_arg = root;
1327 new_attrs.rmm_handle = nldr_node_obj;
1328 new_attrs.input_params = nldr_node_obj->priv_ref;
1329 new_attrs.base_image = false;
1330
1331 status =
1332 nldr_obj->ldr_fxns.load_fxn(root->lib, flags, &new_attrs,
1333 &entry);
1334 }
1335
1336
1337
1338
1339
1340
1341 if (status) {
1342 if (phase != NLDR_EXECUTE) {
1343 for (i = 0; i < nldr_node_obj->pers_libs; i++)
1344 unload_lib(nldr_node_obj,
1345 &nldr_node_obj->pers_lib_table[i]);
1346
1347 nldr_node_obj->pers_libs = 0;
1348 }
1349 for (i = 0; i < nd_libs_loaded; i++)
1350 unload_lib(nldr_node_obj, &root->dep_libs_tree[i]);
1351
1352 if (root->lib)
1353 nldr_obj->ldr_fxns.close_fxn(root->lib);
1354
1355 }
1356
1357
1358 depth--;
1359
1360 kfree(dep_lib_uui_ds);
1361 dep_lib_uui_ds = NULL;
1362
1363 kfree(persistent_dep_libs);
1364 persistent_dep_libs = NULL;
1365
1366 return status;
1367}
1368
1369
1370
1371
1372static int load_ovly(struct nldr_nodeobject *nldr_node_obj,
1373 enum nldr_phase phase)
1374{
1375 struct nldr_object *nldr_obj = nldr_node_obj->nldr_obj;
1376 struct ovly_node *po_node = NULL;
1377 struct ovly_sect *phase_sects = NULL;
1378 struct ovly_sect *other_sects_list = NULL;
1379 u16 i;
1380 u16 alloc_num = 0;
1381 u16 other_alloc = 0;
1382 u16 *ref_count = NULL;
1383 u16 *other_ref = NULL;
1384 u32 bytes;
1385 struct ovly_sect *ovly_section;
1386 int status = 0;
1387
1388
1389 for (i = 0; i < nldr_obj->ovly_nodes; i++) {
1390 if (is_equal_uuid
1391 (&nldr_node_obj->uuid, &nldr_obj->ovly_table[i].uuid)) {
1392
1393 po_node = &(nldr_obj->ovly_table[i]);
1394 break;
1395 }
1396 }
1397
1398
1399 if (!po_node) {
1400 status = -ENOENT;
1401 goto func_end;
1402 }
1403
1404 switch (phase) {
1405 case NLDR_CREATE:
1406 ref_count = &(po_node->create_ref);
1407 other_ref = &(po_node->other_ref);
1408 phase_sects = po_node->create_sects_list;
1409 other_sects_list = po_node->other_sects_list;
1410 break;
1411
1412 case NLDR_EXECUTE:
1413 ref_count = &(po_node->execute_ref);
1414 phase_sects = po_node->execute_sects_list;
1415 break;
1416
1417 case NLDR_DELETE:
1418 ref_count = &(po_node->delete_ref);
1419 phase_sects = po_node->delete_sects_list;
1420 break;
1421
1422 default:
1423 break;
1424 }
1425
1426 if (ref_count == NULL)
1427 goto func_end;
1428
1429 if (*ref_count != 0)
1430 goto func_end;
1431
1432
1433 ovly_section = phase_sects;
1434 while (ovly_section) {
1435
1436
1437 status = rmm_alloc(nldr_obj->rmm, 0, ovly_section->size, 0,
1438 &(ovly_section->sect_run_addr), true);
1439 if (!status) {
1440 ovly_section = ovly_section->next_sect;
1441 alloc_num++;
1442 } else {
1443 break;
1444 }
1445 }
1446 if (other_ref && *other_ref == 0) {
1447
1448
1449 if (!status) {
1450 ovly_section = other_sects_list;
1451 while (ovly_section) {
1452
1453
1454 status =
1455 rmm_alloc(nldr_obj->rmm, 0,
1456 ovly_section->size, 0,
1457 &(ovly_section->sect_run_addr),
1458 true);
1459 if (!status) {
1460 ovly_section = ovly_section->next_sect;
1461 other_alloc++;
1462 } else {
1463 break;
1464 }
1465 }
1466 }
1467 }
1468 if (*ref_count == 0) {
1469 if (!status) {
1470
1471 ovly_section = phase_sects;
1472 while (ovly_section && !status) {
1473 bytes =
1474 (*nldr_obj->ovly_fxn) (nldr_node_obj->
1475 priv_ref,
1476 ovly_section->
1477 sect_run_addr,
1478 ovly_section->
1479 sect_load_addr,
1480 ovly_section->size,
1481 ovly_section->page);
1482 if (bytes != ovly_section->size)
1483 status = -EPERM;
1484
1485 ovly_section = ovly_section->next_sect;
1486 }
1487 }
1488 }
1489 if (other_ref && *other_ref == 0) {
1490 if (!status) {
1491
1492 ovly_section = other_sects_list;
1493 while (ovly_section && !status) {
1494 bytes =
1495 (*nldr_obj->ovly_fxn) (nldr_node_obj->
1496 priv_ref,
1497 ovly_section->
1498 sect_run_addr,
1499 ovly_section->
1500 sect_load_addr,
1501 ovly_section->size,
1502 ovly_section->page);
1503 if (bytes != ovly_section->size)
1504 status = -EPERM;
1505
1506 ovly_section = ovly_section->next_sect;
1507 }
1508 }
1509 }
1510 if (status) {
1511
1512 free_sects(nldr_obj, phase_sects, alloc_num);
1513 free_sects(nldr_obj, other_sects_list, other_alloc);
1514 }
1515func_end:
1516 if (!status && (ref_count != NULL)) {
1517 *ref_count += 1;
1518 if (other_ref)
1519 *other_ref += 1;
1520
1521 }
1522
1523 return status;
1524}
1525
1526
1527
1528
1529static int remote_alloc(void **ref, u16 mem_sect, u32 size,
1530 u32 align, u32 *dsp_address,
1531 s32 segmnt_id, s32 req,
1532 bool reserve)
1533{
1534 struct nldr_nodeobject *hnode = (struct nldr_nodeobject *)ref;
1535 struct nldr_object *nldr_obj;
1536 struct rmm_target_obj *rmm;
1537 u16 mem_phase_bit = MAXFLAGS;
1538 u16 segid = 0;
1539 u16 i;
1540 u16 mem_sect_type;
1541 u32 word_size;
1542 struct rmm_addr *rmm_addr_obj = (struct rmm_addr *)dsp_address;
1543 bool mem_load_req = false;
1544 int status = -ENOMEM;
1545 nldr_obj = hnode->nldr_obj;
1546 rmm = nldr_obj->rmm;
1547
1548 word_size =
1549 (size + nldr_obj->dsp_word_size -
1550 1) / nldr_obj->dsp_word_size;
1551
1552 align = lcm(GEM_CACHE_LINE_SIZE, align);
1553 dev_dbg(bridge, "%s: memory align to 0x%x\n", __func__, align);
1554 if (segmnt_id != -1) {
1555 rmm_addr_obj->segid = segmnt_id;
1556 segid = segmnt_id;
1557 mem_load_req = req;
1558 } else {
1559 switch (hnode->phase) {
1560 case NLDR_CREATE:
1561 mem_phase_bit = CREATEDATAFLAGBIT;
1562 break;
1563 case NLDR_DELETE:
1564 mem_phase_bit = DELETEDATAFLAGBIT;
1565 break;
1566 case NLDR_EXECUTE:
1567 mem_phase_bit = EXECUTEDATAFLAGBIT;
1568 break;
1569 default:
1570 break;
1571 }
1572 if (mem_sect == DBLL_CODE)
1573 mem_phase_bit++;
1574
1575 if (mem_phase_bit < MAXFLAGS)
1576 segid = hnode->seg_id[mem_phase_bit];
1577
1578
1579 if ((hnode->code_data_flag_mask >> mem_phase_bit) & 0x1)
1580 mem_load_req = true;
1581
1582 }
1583 mem_sect_type = (mem_sect == DBLL_CODE) ? DYNM_CODE : DYNM_DATA;
1584
1585
1586 if (segid == NULLID) {
1587
1588 goto func_cont;
1589 }
1590 if (segid <= MAXSEGID) {
1591
1592 rmm_addr_obj->segid = segid;
1593 status =
1594 rmm_alloc(rmm, segid, word_size, align, dsp_address, false);
1595 if (status) {
1596 dev_dbg(bridge, "%s: Unable allocate from segment %d\n",
1597 __func__, segid);
1598 }
1599 } else {
1600
1601
1602
1603 mem_sect_type |= segid == MEMINTERNALID ?
1604 DYNM_INTERNAL : DYNM_EXTERNAL;
1605 for (i = 0; i < nldr_obj->dload_segs; i++) {
1606 if ((nldr_obj->seg_table[i] & mem_sect_type) !=
1607 mem_sect_type)
1608 continue;
1609
1610 status = rmm_alloc(rmm, i, word_size, align,
1611 dsp_address, false);
1612 if (!status) {
1613
1614 rmm_addr_obj->segid = i;
1615 break;
1616 }
1617 }
1618 }
1619func_cont:
1620
1621 if (status == -ENOMEM && !mem_load_req) {
1622 dev_dbg(bridge, "%s: Preferred segment unavailable, trying "
1623 "another\n", __func__);
1624 for (i = 0; i < nldr_obj->dload_segs; i++) {
1625
1626 if ((nldr_obj->seg_table[i] & mem_sect_type) !=
1627 mem_sect_type)
1628 continue;
1629
1630 status = rmm_alloc(rmm, i, word_size, align,
1631 dsp_address, false);
1632 if (!status) {
1633
1634 rmm_addr_obj->segid = i;
1635 break;
1636 }
1637 }
1638 }
1639
1640 return status;
1641}
1642
1643static int remote_free(void **ref, u16 space, u32 dsp_address,
1644 u32 size, bool reserve)
1645{
1646 struct nldr_object *nldr_obj = (struct nldr_object *)ref;
1647 struct rmm_target_obj *rmm;
1648 u32 word_size;
1649 int status = -ENOMEM;
1650
1651 rmm = nldr_obj->rmm;
1652
1653
1654 word_size =
1655 (size + nldr_obj->dsp_word_size -
1656 1) / nldr_obj->dsp_word_size;
1657
1658 if (rmm_free(rmm, space, dsp_address, word_size, reserve))
1659 status = 0;
1660
1661 return status;
1662}
1663
1664
1665
1666
1667static void unload_lib(struct nldr_nodeobject *nldr_node_obj,
1668 struct lib_node *root)
1669{
1670 struct dbll_attrs new_attrs;
1671 struct nldr_object *nldr_obj = nldr_node_obj->nldr_obj;
1672 u16 i;
1673
1674
1675
1676 for (i = 0; i < root->dep_libs; i++)
1677 unload_lib(nldr_node_obj, &root->dep_libs_tree[i]);
1678
1679 root->dep_libs = 0;
1680
1681 new_attrs = nldr_obj->ldr_attrs;
1682 new_attrs.rmm_handle = nldr_obj->rmm;
1683 new_attrs.input_params = nldr_node_obj->priv_ref;
1684 new_attrs.base_image = false;
1685 new_attrs.sym_arg = root;
1686
1687 if (root->lib) {
1688
1689 nldr_obj->ldr_fxns.unload_fxn(root->lib, &new_attrs);
1690 nldr_obj->ldr_fxns.close_fxn(root->lib);
1691 }
1692
1693
1694 kfree(root->dep_libs_tree);
1695 root->dep_libs_tree = NULL;
1696}
1697
1698
1699
1700
1701static void unload_ovly(struct nldr_nodeobject *nldr_node_obj,
1702 enum nldr_phase phase)
1703{
1704 struct nldr_object *nldr_obj = nldr_node_obj->nldr_obj;
1705 struct ovly_node *po_node = NULL;
1706 struct ovly_sect *phase_sects = NULL;
1707 struct ovly_sect *other_sects_list = NULL;
1708 u16 i;
1709 u16 alloc_num = 0;
1710 u16 other_alloc = 0;
1711 u16 *ref_count = NULL;
1712 u16 *other_ref = NULL;
1713
1714
1715 for (i = 0; i < nldr_obj->ovly_nodes; i++) {
1716 if (is_equal_uuid
1717 (&nldr_node_obj->uuid, &nldr_obj->ovly_table[i].uuid)) {
1718
1719 po_node = &(nldr_obj->ovly_table[i]);
1720 break;
1721 }
1722 }
1723
1724
1725 if (!po_node)
1726
1727 return;
1728
1729 switch (phase) {
1730 case NLDR_CREATE:
1731 ref_count = &(po_node->create_ref);
1732 phase_sects = po_node->create_sects_list;
1733 alloc_num = po_node->create_sects;
1734 break;
1735 case NLDR_EXECUTE:
1736 ref_count = &(po_node->execute_ref);
1737 phase_sects = po_node->execute_sects_list;
1738 alloc_num = po_node->execute_sects;
1739 break;
1740 case NLDR_DELETE:
1741 ref_count = &(po_node->delete_ref);
1742 other_ref = &(po_node->other_ref);
1743 phase_sects = po_node->delete_sects_list;
1744
1745 other_sects_list = po_node->other_sects_list;
1746 alloc_num = po_node->delete_sects;
1747 other_alloc = po_node->other_sects;
1748 break;
1749 default:
1750 break;
1751 }
1752 if (ref_count && (*ref_count > 0)) {
1753 *ref_count -= 1;
1754 if (other_ref) {
1755 *other_ref -= 1;
1756 }
1757 }
1758
1759 if (ref_count && *ref_count == 0) {
1760
1761 free_sects(nldr_obj, phase_sects, alloc_num);
1762 }
1763 if (other_ref && *other_ref == 0)
1764 free_sects(nldr_obj, other_sects_list, other_alloc);
1765}
1766
1767
1768
1769
1770static bool find_in_persistent_lib_array(struct nldr_nodeobject *nldr_node_obj,
1771 struct dbll_library_obj *lib)
1772{
1773 s32 i = 0;
1774
1775 for (i = 0; i < nldr_node_obj->pers_libs; i++) {
1776 if (lib == nldr_node_obj->pers_lib_table[i].lib)
1777 return true;
1778
1779 }
1780
1781 return false;
1782}
1783
1784#ifdef CONFIG_TIDSPBRIDGE_BACKTRACE
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798int nldr_find_addr(struct nldr_nodeobject *nldr_node, u32 sym_addr,
1799 u32 offset_range, void *offset_output, char *sym_name)
1800{
1801 int status = 0;
1802 bool status1 = false;
1803 s32 i = 0;
1804 struct lib_node root = { NULL, 0, NULL };
1805
1806 if (nldr_node->dynamic && *nldr_node->phase_split) {
1807 switch (nldr_node->phase) {
1808 case NLDR_CREATE:
1809 root = nldr_node->create_lib;
1810 break;
1811 case NLDR_EXECUTE:
1812 root = nldr_node->execute_lib;
1813 break;
1814 case NLDR_DELETE:
1815 root = nldr_node->delete_lib;
1816 break;
1817 default:
1818 break;
1819 }
1820 } else {
1821
1822 root = nldr_node->root;
1823 }
1824
1825 status1 = dbll_find_dsp_symbol(root.lib, sym_addr,
1826 offset_range, offset_output, sym_name);
1827
1828
1829 if (!status1)
1830 for (i = 0; i < root.dep_libs; i++) {
1831 status1 = dbll_find_dsp_symbol(
1832 root.dep_libs_tree[i].lib, sym_addr,
1833 offset_range, offset_output, sym_name);
1834 if (status1)
1835
1836 break;
1837 }
1838
1839 if (!status1)
1840 for (i = 0; i < nldr_node->pers_libs; i++) {
1841 status1 = dbll_find_dsp_symbol(
1842 nldr_node->pers_lib_table[i].lib, sym_addr,
1843 offset_range, offset_output, sym_name);
1844 if (status1)
1845
1846 break;
1847 }
1848
1849 if (!status1) {
1850 pr_debug("%s: Address 0x%x not found in range %d.\n",
1851 __func__, sym_addr, offset_range);
1852 status = -ESPIPE;
1853 } else {
1854 pr_debug("%s(0x%x, 0x%x, 0x%x, 0x%x, %s)\n",
1855 __func__, (u32) nldr_node, sym_addr, offset_range,
1856 (u32) offset_output, sym_name);
1857 }
1858
1859 return status;
1860}
1861#endif
1862