4 * DSP-BIOS Bridge driver support functions for TI OMAP processors.
6 * DSP/BIOS Bridge dynamic + overlay Node loader.
8 * Copyright (C) 2005-2006 Texas Instruments, Inc.
10 * This package is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
14 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
16 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19 #include <linux/types.h>
21 #include <dspbridge/host_os.h>
23 #include <dspbridge/dbdefs.h>
25 #include <dspbridge/dbc.h>
27 /* Platform manager */
28 #include <dspbridge/cod.h>
29 #include <dspbridge/dev.h>
31 /* Resource manager */
32 #include <dspbridge/dbll.h>
33 #include <dspbridge/dbdcd.h>
34 #include <dspbridge/rmm.h>
35 #include <dspbridge/uuidutil.h>
37 #include <dspbridge/nldr.h>
38 #include <linux/lcm.h>
40 /* Name of section containing dynamic load mem */
41 #define DYNMEMSECT ".dspbridge_mem"
43 /* Name of section containing dependent library information */
44 #define DEPLIBSECT ".dspbridge_deplibs"
46 /* Max depth of recursion for loading node's dependent libraries */
49 /* Max number of persistent libraries kept by a node */
53 * Defines for extracting packed dynamic load memory requirements from two
55 * These defines must match node.cdb and dynm.cdb
56 * Format of data/code mask is:
57 * uuuuuuuu|fueeeeee|fudddddd|fucccccc|
60 * cccccc = preferred/required dynamic mem segid for create phase data/code
61 * dddddd = preferred/required dynamic mem segid for delete phase data/code
62 * eeeeee = preferred/req. dynamic mem segid for execute phase data/code
63 * f = flag indicating if memory is preferred or required:
64 * f = 1 if required, f = 0 if preferred.
66 * The 6 bits of the segid are interpreted as follows:
68 * If the 6th bit (bit 5) is not set, then this specifies a memory segment
69 * between 0 and 31 (a maximum of 32 dynamic loading memory segments).
70 * If the 6th bit (bit 5) is set, segid has the following interpretation:
71 * segid = 32 - Any internal memory segment can be used.
72 * segid = 33 - Any external memory segment can be used.
73 * segid = 63 - Any memory segment can be used (in this case the
74 * required/preferred flag is irrelevant).
77 /* Maximum allowed dynamic loading memory segments */
80 #define MAXSEGID 3 /* Largest possible (real) segid */
81 #define MEMINTERNALID 32 /* Segid meaning use internal mem */
82 #define MEMEXTERNALID 33 /* Segid meaning use external mem */
83 #define NULLID 63 /* Segid meaning no memory req/pref */
84 #define FLAGBIT 7 /* 7th bit is pref./req. flag */
85 #define SEGMASK 0x3f /* Bits 0 - 5 */
87 #define CREATEBIT 0 /* Create segid starts at bit 0 */
88 #define DELETEBIT 8 /* Delete segid starts at bit 8 */
89 #define EXECUTEBIT 16 /* Execute segid starts at bit 16 */
92 * Masks that define memory type. Must match defines in dynm.cdb.
96 #define DYNM_CODEDATA (DYNM_CODE | DYNM_DATA)
97 #define DYNM_INTERNAL 0x8
98 #define DYNM_EXTERNAL 0x10
101 * Defines for packing memory requirement/preference flags for code and
102 * data of each of the node's phases into one mask.
103 * The bit is set if the segid is required for loading code/data of the
104 * given phase. The bit is not set, if the segid is preferred only.
106 * These defines are also used as indeces into a segid array for the node.
107 * eg node's segid[CREATEDATAFLAGBIT] is the memory segment id that the
108 * create phase data is required or preferred to be loaded into.
110 #define CREATEDATAFLAGBIT 0
111 #define CREATECODEFLAGBIT 1
112 #define EXECUTEDATAFLAGBIT 2
113 #define EXECUTECODEFLAGBIT 3
114 #define DELETEDATAFLAGBIT 4
115 #define DELETECODEFLAGBIT 5
119 * These names may be embedded in overlay sections to identify which
120 * node phase the section should be overlayed.
122 #define PCREATE "create"
123 #define PDELETE "delete"
124 #define PEXECUTE "execute"
126 static inline bool is_equal_uuid(struct dsp_uuid
*uuid1
,
127 struct dsp_uuid
*uuid2
)
129 return !memcmp(uuid1
, uuid2
, sizeof(struct dsp_uuid
));
133 * ======== mem_seg_info ========
134 * Format of dynamic loading memory segment info in coff file.
135 * Must match dynm.h55.
137 struct mem_seg_info
{
138 u32 segid
; /* Dynamic loading memory segment number */
141 u32 type
; /* Mask of DYNM_CODE, DYNM_INTERNAL, etc. */
145 * ======== lib_node ========
146 * For maintaining a tree of library dependencies.
149 struct dbll_library_obj
*lib
; /* The library */
150 u16 dep_libs
; /* Number of dependent libraries */
151 struct lib_node
*dep_libs_tree
; /* Dependent libraries of lib */
155 * ======== ovly_sect ========
156 * Information needed to overlay a section.
159 struct ovly_sect
*next_sect
;
160 u32 sect_load_addr
; /* Load address of section */
161 u32 sect_run_addr
; /* Run address of section */
162 u32 size
; /* Size of section */
163 u16 page
; /* DBL_CODE, DBL_DATA */
167 * ======== ovly_node ========
168 * For maintaining a list of overlay nodes, with sections that need to be
169 * overlayed for each of the nodes phases.
172 struct dsp_uuid uuid
;
174 struct ovly_sect
*create_sects_list
;
175 struct ovly_sect
*delete_sects_list
;
176 struct ovly_sect
*execute_sects_list
;
177 struct ovly_sect
*other_sects_list
;
189 * ======== nldr_object ========
190 * Overlay loader object.
193 struct dev_object
*dev_obj
; /* Device object */
194 struct dcd_manager
*dcd_mgr
; /* Proc/Node data manager */
195 struct dbll_tar_obj
*dbll
; /* The DBL loader */
196 struct dbll_library_obj
*base_lib
; /* Base image library */
197 struct rmm_target_obj
*rmm
; /* Remote memory manager for DSP */
198 struct dbll_fxns ldr_fxns
; /* Loader function table */
199 struct dbll_attrs ldr_attrs
; /* attrs to pass to loader functions */
200 nldr_ovlyfxn ovly_fxn
; /* "write" for overlay nodes */
201 nldr_writefxn write_fxn
; /* "write" for dynamic nodes */
202 struct ovly_node
*ovly_table
; /* Table of overlay nodes */
203 u16 ovly_nodes
; /* Number of overlay nodes in base */
204 u16 ovly_nid
; /* Index for tracking overlay nodes */
205 u16 dload_segs
; /* Number of dynamic load mem segs */
206 u32
*seg_table
; /* memtypes of dynamic memory segs
209 u16 dsp_mau_size
; /* Size of DSP MAU */
210 u16 dsp_word_size
; /* Size of DSP word */
214 * ======== nldr_nodeobject ========
215 * Dynamic node object. This object is created when a node is allocated.
217 struct nldr_nodeobject
{
218 struct nldr_object
*nldr_obj
; /* Dynamic loader handle */
219 void *priv_ref
; /* Handle to pass to dbl_write_fxn */
220 struct dsp_uuid uuid
; /* Node's UUID */
221 bool dynamic
; /* Dynamically loaded node? */
222 bool overlay
; /* Overlay node? */
223 bool *phase_split
; /* Multiple phase libraries? */
224 struct lib_node root
; /* Library containing node phase */
225 struct lib_node create_lib
; /* Library with create phase lib */
226 struct lib_node execute_lib
; /* Library with execute phase lib */
227 struct lib_node delete_lib
; /* Library with delete phase lib */
228 /* libs remain loaded until Delete */
229 struct lib_node pers_lib_table
[MAXLIBS
];
230 s32 pers_libs
; /* Number of persistent libraries */
231 /* Path in lib dependency tree */
232 struct dbll_library_obj
*lib_path
[MAXDEPTH
+ 1];
233 enum nldr_phase phase
; /* Node phase currently being loaded */
236 * Dynamic loading memory segments for data and code of each phase.
238 u16 seg_id
[MAXFLAGS
];
241 * Mask indicating whether each mem segment specified in seg_id[]
242 * is preferred or required.
244 * if (code_data_flag_mask & (1 << EXECUTEDATAFLAGBIT)) != 0,
245 * then it is required to load execute phase data into the memory
246 * specified by seg_id[EXECUTEDATAFLAGBIT].
248 u32 code_data_flag_mask
;
251 /* Dynamic loader function table */
252 static struct dbll_fxns ldr_fxns
= {
253 (dbll_close_fxn
) dbll_close
,
254 (dbll_create_fxn
) dbll_create
,
255 (dbll_delete_fxn
) dbll_delete
,
256 (dbll_exit_fxn
) dbll_exit
,
257 (dbll_get_attrs_fxn
) dbll_get_attrs
,
258 (dbll_get_addr_fxn
) dbll_get_addr
,
259 (dbll_get_c_addr_fxn
) dbll_get_c_addr
,
260 (dbll_get_sect_fxn
) dbll_get_sect
,
261 (dbll_init_fxn
) dbll_init
,
262 (dbll_load_fxn
) dbll_load
,
263 (dbll_open_fxn
) dbll_open
,
264 (dbll_read_sect_fxn
) dbll_read_sect
,
265 (dbll_unload_fxn
) dbll_unload
,
268 static u32 refs
; /* module reference count */
270 static int add_ovly_info(void *handle
, struct dbll_sect_info
*sect_info
,
271 u32 addr
, u32 bytes
);
272 static int add_ovly_node(struct dsp_uuid
*uuid_obj
,
273 enum dsp_dcdobjtype obj_type
, void *handle
);
274 static int add_ovly_sect(struct nldr_object
*nldr_obj
,
275 struct ovly_sect
**lst
,
276 struct dbll_sect_info
*sect_inf
,
277 bool *exists
, u32 addr
, u32 bytes
);
278 static s32
fake_ovly_write(void *handle
, u32 dsp_address
, void *buf
, u32 bytes
,
280 static void free_sects(struct nldr_object
*nldr_obj
,
281 struct ovly_sect
*phase_sects
, u16 alloc_num
);
282 static bool get_symbol_value(void *handle
, void *parg
, void *rmm_handle
,
283 char *sym_name
, struct dbll_sym_val
**sym
);
284 static int load_lib(struct nldr_nodeobject
*nldr_node_obj
,
285 struct lib_node
*root
, struct dsp_uuid uuid
,
287 struct dbll_library_obj
**lib_path
,
288 enum nldr_phase phase
, u16 depth
);
289 static int load_ovly(struct nldr_nodeobject
*nldr_node_obj
,
290 enum nldr_phase phase
);
291 static int remote_alloc(void **ref
, u16 mem_sect
, u32 size
,
292 u32 align
, u32
*dsp_address
,
294 s32 req
, bool reserve
);
295 static int remote_free(void **ref
, u16 space
, u32 dsp_address
, u32 size
,
298 static void unload_lib(struct nldr_nodeobject
*nldr_node_obj
,
299 struct lib_node
*root
);
300 static void unload_ovly(struct nldr_nodeobject
*nldr_node_obj
,
301 enum nldr_phase phase
);
302 static bool find_in_persistent_lib_array(struct nldr_nodeobject
*nldr_node_obj
,
303 struct dbll_library_obj
*lib
);
306 * ======== nldr_allocate ========
308 int nldr_allocate(struct nldr_object
*nldr_obj
, void *priv_ref
,
309 const struct dcd_nodeprops
*node_props
,
310 struct nldr_nodeobject
**nldr_nodeobj
,
311 bool *pf_phase_split
)
313 struct nldr_nodeobject
*nldr_node_obj
= NULL
;
316 DBC_REQUIRE(refs
> 0);
317 DBC_REQUIRE(node_props
!= NULL
);
318 DBC_REQUIRE(nldr_nodeobj
!= NULL
);
319 DBC_REQUIRE(nldr_obj
);
321 /* Initialize handle in case of failure */
322 *nldr_nodeobj
= NULL
;
323 /* Allocate node object */
324 nldr_node_obj
= kzalloc(sizeof(struct nldr_nodeobject
), GFP_KERNEL
);
326 if (nldr_node_obj
== NULL
) {
329 nldr_node_obj
->phase_split
= pf_phase_split
;
330 nldr_node_obj
->pers_libs
= 0;
331 nldr_node_obj
->nldr_obj
= nldr_obj
;
332 nldr_node_obj
->priv_ref
= priv_ref
;
333 /* Save node's UUID. */
334 nldr_node_obj
->uuid
= node_props
->ndb_props
.ui_node_id
;
336 * Determine if node is a dynamically loaded node from
339 if (node_props
->load_type
== NLDR_DYNAMICLOAD
) {
341 nldr_node_obj
->dynamic
= true;
343 * Extract memory requirements from ndb_props masks
346 nldr_node_obj
->seg_id
[CREATEDATAFLAGBIT
] = (u16
)
347 (node_props
->data_mem_seg_mask
>> CREATEBIT
) &
349 nldr_node_obj
->code_data_flag_mask
|=
350 ((node_props
->data_mem_seg_mask
>>
351 (CREATEBIT
+ FLAGBIT
)) & 1) << CREATEDATAFLAGBIT
;
352 nldr_node_obj
->seg_id
[CREATECODEFLAGBIT
] = (u16
)
353 (node_props
->code_mem_seg_mask
>>
354 CREATEBIT
) & SEGMASK
;
355 nldr_node_obj
->code_data_flag_mask
|=
356 ((node_props
->code_mem_seg_mask
>>
357 (CREATEBIT
+ FLAGBIT
)) & 1) << CREATECODEFLAGBIT
;
359 nldr_node_obj
->seg_id
[EXECUTEDATAFLAGBIT
] = (u16
)
360 (node_props
->data_mem_seg_mask
>>
361 EXECUTEBIT
) & SEGMASK
;
362 nldr_node_obj
->code_data_flag_mask
|=
363 ((node_props
->data_mem_seg_mask
>>
364 (EXECUTEBIT
+ FLAGBIT
)) & 1) <<
366 nldr_node_obj
->seg_id
[EXECUTECODEFLAGBIT
] = (u16
)
367 (node_props
->code_mem_seg_mask
>>
368 EXECUTEBIT
) & SEGMASK
;
369 nldr_node_obj
->code_data_flag_mask
|=
370 ((node_props
->code_mem_seg_mask
>>
371 (EXECUTEBIT
+ FLAGBIT
)) & 1) <<
374 nldr_node_obj
->seg_id
[DELETEDATAFLAGBIT
] = (u16
)
375 (node_props
->data_mem_seg_mask
>> DELETEBIT
) &
377 nldr_node_obj
->code_data_flag_mask
|=
378 ((node_props
->data_mem_seg_mask
>>
379 (DELETEBIT
+ FLAGBIT
)) & 1) << DELETEDATAFLAGBIT
;
380 nldr_node_obj
->seg_id
[DELETECODEFLAGBIT
] = (u16
)
381 (node_props
->code_mem_seg_mask
>>
382 DELETEBIT
) & SEGMASK
;
383 nldr_node_obj
->code_data_flag_mask
|=
384 ((node_props
->code_mem_seg_mask
>>
385 (DELETEBIT
+ FLAGBIT
)) & 1) << DELETECODEFLAGBIT
;
387 /* Non-dynamically loaded nodes are part of the
389 nldr_node_obj
->root
.lib
= nldr_obj
->base_lib
;
390 /* Check for overlay node */
391 if (node_props
->load_type
== NLDR_OVLYLOAD
)
392 nldr_node_obj
->overlay
= true;
395 *nldr_nodeobj
= (struct nldr_nodeobject
*)nldr_node_obj
;
397 /* Cleanup on failure */
398 if (status
&& nldr_node_obj
)
399 kfree(nldr_node_obj
);
401 DBC_ENSURE((!status
&& *nldr_nodeobj
)
402 || (status
&& *nldr_nodeobj
== NULL
));
407 * ======== nldr_create ========
409 int nldr_create(struct nldr_object
**nldr
,
410 struct dev_object
*hdev_obj
,
411 const struct nldr_attrs
*pattrs
)
413 struct cod_manager
*cod_mgr
; /* COD manager */
414 char *psz_coff_buf
= NULL
;
415 char sz_zl_file
[COD_MAXPATHLENGTH
];
416 struct nldr_object
*nldr_obj
= NULL
;
417 struct dbll_attrs save_attrs
;
418 struct dbll_attrs new_attrs
;
422 struct mem_seg_info
*mem_info_obj
;
425 struct rmm_segment
*rmm_segs
= NULL
;
428 DBC_REQUIRE(refs
> 0);
429 DBC_REQUIRE(nldr
!= NULL
);
430 DBC_REQUIRE(hdev_obj
!= NULL
);
431 DBC_REQUIRE(pattrs
!= NULL
);
432 DBC_REQUIRE(pattrs
->ovly
!= NULL
);
433 DBC_REQUIRE(pattrs
->write
!= NULL
);
435 /* Allocate dynamic loader object */
436 nldr_obj
= kzalloc(sizeof(struct nldr_object
), GFP_KERNEL
);
438 nldr_obj
->dev_obj
= hdev_obj
;
439 /* warning, lazy status checking alert! */
440 dev_get_cod_mgr(hdev_obj
, &cod_mgr
);
442 status
= cod_get_loader(cod_mgr
, &nldr_obj
->dbll
);
444 status
= cod_get_base_lib(cod_mgr
, &nldr_obj
->base_lib
);
447 cod_get_base_name(cod_mgr
, sz_zl_file
,
452 /* end lazy status checking */
453 nldr_obj
->dsp_mau_size
= pattrs
->dsp_mau_size
;
454 nldr_obj
->dsp_word_size
= pattrs
->dsp_word_size
;
455 nldr_obj
->ldr_fxns
= ldr_fxns
;
456 if (!(nldr_obj
->ldr_fxns
.init_fxn()))
462 /* Create the DCD Manager */
464 status
= dcd_create_manager(NULL
, &nldr_obj
->dcd_mgr
);
466 /* Get dynamic loading memory sections from base lib */
469 nldr_obj
->ldr_fxns
.get_sect_fxn(nldr_obj
->base_lib
,
470 DYNMEMSECT
, &ul_addr
,
474 kzalloc(ul_len
* nldr_obj
->dsp_mau_size
,
479 /* Ok to not have dynamic loading memory */
482 dev_dbg(bridge
, "%s: failed - no dynamic loading mem "
483 "segments: 0x%x\n", __func__
, status
);
486 if (!status
&& ul_len
> 0) {
487 /* Read section containing dynamic load mem segments */
489 nldr_obj
->ldr_fxns
.read_sect_fxn(nldr_obj
->base_lib
,
490 DYNMEMSECT
, psz_coff_buf
,
493 if (!status
&& ul_len
> 0) {
494 /* Parse memory segment data */
495 dload_segs
= (u16
) (*((u32
*) psz_coff_buf
));
496 if (dload_segs
> MAXMEMSEGS
)
499 /* Parse dynamic load memory segments */
500 if (!status
&& dload_segs
> 0) {
501 rmm_segs
= kzalloc(sizeof(struct rmm_segment
) * dload_segs
,
503 nldr_obj
->seg_table
=
504 kzalloc(sizeof(u32
) * dload_segs
, GFP_KERNEL
);
505 if (rmm_segs
== NULL
|| nldr_obj
->seg_table
== NULL
) {
508 nldr_obj
->dload_segs
= dload_segs
;
509 mem_info_obj
= (struct mem_seg_info
*)(psz_coff_buf
+
511 for (i
= 0; i
< dload_segs
; i
++) {
512 rmm_segs
[i
].base
= (mem_info_obj
+ i
)->base
;
513 rmm_segs
[i
].length
= (mem_info_obj
+ i
)->len
;
514 rmm_segs
[i
].space
= 0;
515 nldr_obj
->seg_table
[i
] =
516 (mem_info_obj
+ i
)->type
;
518 "(proc) DLL MEMSEGMENT: %d, "
519 "Base: 0x%x, Length: 0x%x\n", i
,
520 rmm_segs
[i
].base
, rmm_segs
[i
].length
);
524 /* Create Remote memory manager */
526 status
= rmm_create(&nldr_obj
->rmm
, rmm_segs
, dload_segs
);
529 /* set the alloc, free, write functions for loader */
530 nldr_obj
->ldr_fxns
.get_attrs_fxn(nldr_obj
->dbll
, &save_attrs
);
531 new_attrs
= save_attrs
;
532 new_attrs
.alloc
= (dbll_alloc_fxn
) remote_alloc
;
533 new_attrs
.free
= (dbll_free_fxn
) remote_free
;
534 new_attrs
.sym_lookup
= (dbll_sym_lookup
) get_symbol_value
;
535 new_attrs
.sym_handle
= nldr_obj
;
536 new_attrs
.write
= (dbll_write_fxn
) pattrs
->write
;
537 nldr_obj
->ovly_fxn
= pattrs
->ovly
;
538 nldr_obj
->write_fxn
= pattrs
->write
;
539 nldr_obj
->ldr_attrs
= new_attrs
;
545 /* Get overlay nodes */
548 cod_get_base_name(cod_mgr
, sz_zl_file
, COD_MAXPATHLENGTH
);
551 /* First count number of overlay nodes */
553 dcd_get_objects(nldr_obj
->dcd_mgr
, sz_zl_file
,
554 add_ovly_node
, (void *)nldr_obj
);
555 /* Now build table of overlay nodes */
556 if (!status
&& nldr_obj
->ovly_nodes
> 0) {
557 /* Allocate table for overlay nodes */
558 nldr_obj
->ovly_table
=
559 kzalloc(sizeof(struct ovly_node
) *
560 nldr_obj
->ovly_nodes
, GFP_KERNEL
);
561 /* Put overlay nodes in the table */
562 nldr_obj
->ovly_nid
= 0;
563 status
= dcd_get_objects(nldr_obj
->dcd_mgr
, sz_zl_file
,
568 /* Do a fake reload of the base image to get overlay section info */
569 if (!status
&& nldr_obj
->ovly_nodes
> 0) {
570 save_attrs
.write
= fake_ovly_write
;
571 save_attrs
.log_write
= add_ovly_info
;
572 save_attrs
.log_write_handle
= nldr_obj
;
573 flags
= DBLL_CODE
| DBLL_DATA
| DBLL_SYMB
;
574 status
= nldr_obj
->ldr_fxns
.load_fxn(nldr_obj
->base_lib
, flags
,
575 &save_attrs
, &ul_entry
);
578 *nldr
= (struct nldr_object
*)nldr_obj
;
581 nldr_delete((struct nldr_object
*)nldr_obj
);
585 /* FIXME:Temp. Fix. Must be removed */
586 DBC_ENSURE((!status
&& *nldr
) || (status
&& *nldr
== NULL
));
591 * ======== nldr_delete ========
593 void nldr_delete(struct nldr_object
*nldr_obj
)
595 struct ovly_sect
*ovly_section
;
596 struct ovly_sect
*next
;
598 DBC_REQUIRE(refs
> 0);
599 DBC_REQUIRE(nldr_obj
);
601 nldr_obj
->ldr_fxns
.exit_fxn();
603 rmm_delete(nldr_obj
->rmm
);
605 kfree(nldr_obj
->seg_table
);
607 if (nldr_obj
->dcd_mgr
)
608 dcd_destroy_manager(nldr_obj
->dcd_mgr
);
610 /* Free overlay node information */
611 if (nldr_obj
->ovly_table
) {
612 for (i
= 0; i
< nldr_obj
->ovly_nodes
; i
++) {
614 nldr_obj
->ovly_table
[i
].create_sects_list
;
615 while (ovly_section
) {
616 next
= ovly_section
->next_sect
;
621 nldr_obj
->ovly_table
[i
].delete_sects_list
;
622 while (ovly_section
) {
623 next
= ovly_section
->next_sect
;
628 nldr_obj
->ovly_table
[i
].execute_sects_list
;
629 while (ovly_section
) {
630 next
= ovly_section
->next_sect
;
634 ovly_section
= nldr_obj
->ovly_table
[i
].other_sects_list
;
635 while (ovly_section
) {
636 next
= ovly_section
->next_sect
;
641 kfree(nldr_obj
->ovly_table
);
647 * ======== nldr_exit ========
648 * Discontinue usage of NLDR module.
652 DBC_REQUIRE(refs
> 0);
659 DBC_ENSURE(refs
>= 0);
663 * ======== nldr_get_fxn_addr ========
665 int nldr_get_fxn_addr(struct nldr_nodeobject
*nldr_node_obj
,
666 char *str_fxn
, u32
* addr
)
668 struct dbll_sym_val
*dbll_sym
;
669 struct nldr_object
*nldr_obj
;
671 bool status1
= false;
673 struct lib_node root
= { NULL
, 0, NULL
};
674 DBC_REQUIRE(refs
> 0);
675 DBC_REQUIRE(nldr_node_obj
);
676 DBC_REQUIRE(addr
!= NULL
);
677 DBC_REQUIRE(str_fxn
!= NULL
);
679 nldr_obj
= nldr_node_obj
->nldr_obj
;
680 /* Called from node_create(), node_delete(), or node_run(). */
681 if (nldr_node_obj
->dynamic
&& *nldr_node_obj
->phase_split
) {
682 switch (nldr_node_obj
->phase
) {
684 root
= nldr_node_obj
->create_lib
;
687 root
= nldr_node_obj
->execute_lib
;
690 root
= nldr_node_obj
->delete_lib
;
697 /* for Overlay nodes or non-split Dynamic nodes */
698 root
= nldr_node_obj
->root
;
701 nldr_obj
->ldr_fxns
.get_c_addr_fxn(root
.lib
, str_fxn
, &dbll_sym
);
704 nldr_obj
->ldr_fxns
.get_addr_fxn(root
.lib
, str_fxn
,
707 /* If symbol not found, check dependent libraries */
709 for (i
= 0; i
< root
.dep_libs
; i
++) {
711 nldr_obj
->ldr_fxns
.get_addr_fxn(root
.dep_libs_tree
717 get_c_addr_fxn(root
.dep_libs_tree
[i
].lib
,
726 /* Check persistent libraries */
728 for (i
= 0; i
< nldr_node_obj
->pers_libs
; i
++) {
731 get_addr_fxn(nldr_node_obj
->pers_lib_table
[i
].lib
,
736 get_c_addr_fxn(nldr_node_obj
->pers_lib_table
737 [i
].lib
, str_fxn
, &dbll_sym
);
747 *addr
= dbll_sym
->value
;
755 * ======== nldr_get_rmm_manager ========
756 * Given a NLDR object, retrieve RMM Manager Handle
758 int nldr_get_rmm_manager(struct nldr_object
*nldr
,
759 struct rmm_target_obj
**rmm_mgr
)
762 struct nldr_object
*nldr_obj
= nldr
;
763 DBC_REQUIRE(rmm_mgr
!= NULL
);
766 *rmm_mgr
= nldr_obj
->rmm
;
772 DBC_ENSURE(!status
|| (rmm_mgr
!= NULL
&& *rmm_mgr
== NULL
));
778 * ======== nldr_init ========
779 * Initialize the NLDR module.
783 DBC_REQUIRE(refs
>= 0);
790 DBC_ENSURE(refs
> 0);
795 * ======== nldr_load ========
797 int nldr_load(struct nldr_nodeobject
*nldr_node_obj
,
798 enum nldr_phase phase
)
800 struct nldr_object
*nldr_obj
;
801 struct dsp_uuid lib_uuid
;
804 DBC_REQUIRE(refs
> 0);
805 DBC_REQUIRE(nldr_node_obj
);
807 nldr_obj
= nldr_node_obj
->nldr_obj
;
809 if (nldr_node_obj
->dynamic
) {
810 nldr_node_obj
->phase
= phase
;
812 lib_uuid
= nldr_node_obj
->uuid
;
814 /* At this point, we may not know if node is split into
815 * different libraries. So we'll go ahead and load the
816 * library, and then save the pointer to the appropriate
817 * location after we know. */
820 load_lib(nldr_node_obj
, &nldr_node_obj
->root
, lib_uuid
,
821 false, nldr_node_obj
->lib_path
, phase
, 0);
824 if (*nldr_node_obj
->phase_split
) {
827 nldr_node_obj
->create_lib
=
832 nldr_node_obj
->execute_lib
=
837 nldr_node_obj
->delete_lib
=
848 if (nldr_node_obj
->overlay
)
849 status
= load_ovly(nldr_node_obj
, phase
);
857 * ======== nldr_unload ========
859 int nldr_unload(struct nldr_nodeobject
*nldr_node_obj
,
860 enum nldr_phase phase
)
863 struct lib_node
*root_lib
= NULL
;
866 DBC_REQUIRE(refs
> 0);
867 DBC_REQUIRE(nldr_node_obj
);
869 if (nldr_node_obj
!= NULL
) {
870 if (nldr_node_obj
->dynamic
) {
871 if (*nldr_node_obj
->phase_split
) {
874 root_lib
= &nldr_node_obj
->create_lib
;
877 root_lib
= &nldr_node_obj
->execute_lib
;
880 root_lib
= &nldr_node_obj
->delete_lib
;
881 /* Unload persistent libraries */
883 i
< nldr_node_obj
->pers_libs
;
885 unload_lib(nldr_node_obj
,
889 nldr_node_obj
->pers_libs
= 0;
896 /* Unload main library */
897 root_lib
= &nldr_node_obj
->root
;
900 unload_lib(nldr_node_obj
, root_lib
);
902 if (nldr_node_obj
->overlay
)
903 unload_ovly(nldr_node_obj
, phase
);
911 * ======== add_ovly_info ========
913 static int add_ovly_info(void *handle
, struct dbll_sect_info
*sect_info
,
917 char *sect_name
= (char *)sect_info
->name
;
918 bool sect_exists
= false;
922 struct nldr_object
*nldr_obj
= (struct nldr_object
*)handle
;
925 /* Is this an overlay section (load address != run address)? */
926 if (sect_info
->sect_load_addr
== sect_info
->sect_run_addr
)
929 /* Find the node it belongs to */
930 for (i
= 0; i
< nldr_obj
->ovly_nodes
; i
++) {
931 node_name
= nldr_obj
->ovly_table
[i
].node_name
;
932 DBC_REQUIRE(node_name
);
933 if (strncmp(node_name
, sect_name
+ 1, strlen(node_name
)) == 0) {
938 if (!(i
< nldr_obj
->ovly_nodes
))
941 /* Determine which phase this section belongs to */
942 for (pch
= sect_name
+ 1; *pch
&& *pch
!= seps
; pch
++)
946 pch
++; /* Skip over the ':' */
947 if (strncmp(pch
, PCREATE
, strlen(PCREATE
)) == 0) {
949 add_ovly_sect(nldr_obj
,
951 ovly_table
[i
].create_sects_list
,
952 sect_info
, §_exists
, addr
, bytes
);
953 if (!status
&& !sect_exists
)
954 nldr_obj
->ovly_table
[i
].create_sects
++;
956 } else if (strncmp(pch
, PDELETE
, strlen(PDELETE
)) == 0) {
958 add_ovly_sect(nldr_obj
,
960 ovly_table
[i
].delete_sects_list
,
961 sect_info
, §_exists
, addr
, bytes
);
962 if (!status
&& !sect_exists
)
963 nldr_obj
->ovly_table
[i
].delete_sects
++;
965 } else if (strncmp(pch
, PEXECUTE
, strlen(PEXECUTE
)) == 0) {
967 add_ovly_sect(nldr_obj
,
969 ovly_table
[i
].execute_sects_list
,
970 sect_info
, §_exists
, addr
, bytes
);
971 if (!status
&& !sect_exists
)
972 nldr_obj
->ovly_table
[i
].execute_sects
++;
975 /* Put in "other" sectins */
977 add_ovly_sect(nldr_obj
,
979 ovly_table
[i
].other_sects_list
,
980 sect_info
, §_exists
, addr
, bytes
);
981 if (!status
&& !sect_exists
)
982 nldr_obj
->ovly_table
[i
].other_sects
++;
991 * ======== add_ovly_node =========
992 * Callback function passed to dcd_get_objects.
994 static int add_ovly_node(struct dsp_uuid
*uuid_obj
,
995 enum dsp_dcdobjtype obj_type
, void *handle
)
997 struct nldr_object
*nldr_obj
= (struct nldr_object
*)handle
;
998 char *node_name
= NULL
;
1001 struct dcd_genericobj obj_def
;
1004 if (obj_type
!= DSP_DCDNODETYPE
)
1008 dcd_get_object_def(nldr_obj
->dcd_mgr
, uuid_obj
, obj_type
,
1013 /* If overlay node, add to the list */
1014 if (obj_def
.obj_data
.node_obj
.load_type
== NLDR_OVLYLOAD
) {
1015 if (nldr_obj
->ovly_table
== NULL
) {
1016 nldr_obj
->ovly_nodes
++;
1018 /* Add node to table */
1019 nldr_obj
->ovly_table
[nldr_obj
->ovly_nid
].uuid
=
1021 DBC_REQUIRE(obj_def
.obj_data
.node_obj
.ndb_props
.
1024 strlen(obj_def
.obj_data
.node_obj
.ndb_props
.ac_name
);
1025 node_name
= obj_def
.obj_data
.node_obj
.ndb_props
.ac_name
;
1026 pbuf
= kzalloc(len
+ 1, GFP_KERNEL
);
1030 strncpy(pbuf
, node_name
, len
);
1031 nldr_obj
->ovly_table
[nldr_obj
->ovly_nid
].
1033 nldr_obj
->ovly_nid
++;
1037 /* These were allocated in dcd_get_object_def */
1038 kfree(obj_def
.obj_data
.node_obj
.str_create_phase_fxn
);
1040 kfree(obj_def
.obj_data
.node_obj
.str_execute_phase_fxn
);
1042 kfree(obj_def
.obj_data
.node_obj
.str_delete_phase_fxn
);
1044 kfree(obj_def
.obj_data
.node_obj
.str_i_alg_name
);
1051 * ======== add_ovly_sect ========
1053 static int add_ovly_sect(struct nldr_object
*nldr_obj
,
1054 struct ovly_sect
**lst
,
1055 struct dbll_sect_info
*sect_inf
,
1056 bool *exists
, u32 addr
, u32 bytes
)
1058 struct ovly_sect
*new_sect
= NULL
;
1059 struct ovly_sect
*last_sect
;
1060 struct ovly_sect
*ovly_section
;
1063 ovly_section
= last_sect
= *lst
;
1065 while (ovly_section
) {
1067 * Make sure section has not already been added. Multiple
1068 * 'write' calls may be made to load the section.
1070 if (ovly_section
->sect_load_addr
== addr
) {
1075 last_sect
= ovly_section
;
1076 ovly_section
= ovly_section
->next_sect
;
1079 if (!ovly_section
) {
1081 new_sect
= kzalloc(sizeof(struct ovly_sect
), GFP_KERNEL
);
1082 if (new_sect
== NULL
) {
1085 new_sect
->sect_load_addr
= addr
;
1086 new_sect
->sect_run_addr
= sect_inf
->sect_run_addr
+
1087 (addr
- sect_inf
->sect_load_addr
);
1088 new_sect
->size
= bytes
;
1089 new_sect
->page
= sect_inf
->type
;
1092 /* Add to the list */
1095 /* First in the list */
1098 last_sect
->next_sect
= new_sect
;
1107 * ======== fake_ovly_write ========
1109 static s32
fake_ovly_write(void *handle
, u32 dsp_address
, void *buf
, u32 bytes
,
1116 * ======== free_sects ========
1118 static void free_sects(struct nldr_object
*nldr_obj
,
1119 struct ovly_sect
*phase_sects
, u16 alloc_num
)
1121 struct ovly_sect
*ovly_section
= phase_sects
;
1125 while (ovly_section
&& i
< alloc_num
) {
1127 /* segid - page not supported yet */
1128 /* Reserved memory */
1130 rmm_free(nldr_obj
->rmm
, 0, ovly_section
->sect_run_addr
,
1131 ovly_section
->size
, true);
1133 ovly_section
= ovly_section
->next_sect
;
1139 * ======== get_symbol_value ========
1140 * Find symbol in library's base image. If not there, check dependent
1143 static bool get_symbol_value(void *handle
, void *parg
, void *rmm_handle
,
1144 char *sym_name
, struct dbll_sym_val
**sym
)
1146 struct nldr_object
*nldr_obj
= (struct nldr_object
*)handle
;
1147 struct nldr_nodeobject
*nldr_node_obj
=
1148 (struct nldr_nodeobject
*)rmm_handle
;
1149 struct lib_node
*root
= (struct lib_node
*)parg
;
1151 bool status
= false;
1153 /* check the base image */
1154 status
= nldr_obj
->ldr_fxns
.get_addr_fxn(nldr_obj
->base_lib
,
1158 nldr_obj
->ldr_fxns
.get_c_addr_fxn(nldr_obj
->base_lib
,
1162 * Check in root lib itself. If the library consists of
1163 * multiple object files linked together, some symbols in the
1164 * library may need to be resolved.
1167 status
= nldr_obj
->ldr_fxns
.get_addr_fxn(root
->lib
, sym_name
,
1171 nldr_obj
->ldr_fxns
.get_c_addr_fxn(root
->lib
,
1177 * Check in root lib's dependent libraries, but not dependent
1178 * libraries' dependents.
1181 for (i
= 0; i
< root
->dep_libs
; i
++) {
1183 nldr_obj
->ldr_fxns
.get_addr_fxn(root
->
1190 get_c_addr_fxn(root
->dep_libs_tree
[i
].lib
,
1200 * Check in persistent libraries
1203 for (i
= 0; i
< nldr_node_obj
->pers_libs
; i
++) {
1206 get_addr_fxn(nldr_node_obj
->pers_lib_table
[i
].lib
,
1209 status
= nldr_obj
->ldr_fxns
.get_c_addr_fxn
1210 (nldr_node_obj
->pers_lib_table
[i
].lib
,
1224 * ======== load_lib ========
1225 * Recursively load library and all its dependent libraries. The library
1226 * we're loading is specified by a uuid.
1228 static int load_lib(struct nldr_nodeobject
*nldr_node_obj
,
1229 struct lib_node
*root
, struct dsp_uuid uuid
,
1231 struct dbll_library_obj
**lib_path
,
1232 enum nldr_phase phase
, u16 depth
)
1234 struct nldr_object
*nldr_obj
= nldr_node_obj
->nldr_obj
;
1235 u16 nd_libs
= 0; /* Number of dependent libraries */
1236 u16 np_libs
= 0; /* Number of persistent libraries */
1237 u16 nd_libs_loaded
= 0; /* Number of dep. libraries loaded */
1240 u32 dw_buf_size
= NLDR_MAXPATHLENGTH
;
1241 dbll_flags flags
= DBLL_SYMB
| DBLL_CODE
| DBLL_DATA
| DBLL_DYNAMIC
;
1242 struct dbll_attrs new_attrs
;
1243 char *psz_file_name
= NULL
;
1244 struct dsp_uuid
*dep_lib_uui_ds
= NULL
;
1245 bool *persistent_dep_libs
= NULL
;
1247 bool lib_status
= false;
1248 struct lib_node
*dep_lib
;
1250 if (depth
> MAXDEPTH
) {
1255 /* Allocate a buffer for library file name of size DBL_MAXPATHLENGTH */
1256 psz_file_name
= kzalloc(DBLL_MAXPATHLENGTH
, GFP_KERNEL
);
1257 if (psz_file_name
== NULL
)
1261 /* Get the name of the library */
1264 dcd_get_library_name(nldr_node_obj
->nldr_obj
->
1265 dcd_mgr
, &uuid
, psz_file_name
,
1266 &dw_buf_size
, phase
,
1267 nldr_node_obj
->phase_split
);
1269 /* Dependent libraries are registered with a phase */
1271 dcd_get_library_name(nldr_node_obj
->nldr_obj
->
1272 dcd_mgr
, &uuid
, psz_file_name
,
1273 &dw_buf_size
, NLDR_NOPHASE
,
1278 /* Open the library, don't load symbols */
1280 nldr_obj
->ldr_fxns
.open_fxn(nldr_obj
->dbll
, psz_file_name
,
1281 DBLL_NOLOAD
, &root
->lib
);
1283 /* Done with file name */
1284 kfree(psz_file_name
);
1286 /* Check to see if library not already loaded */
1287 if (!status
&& root_prstnt
) {
1289 find_in_persistent_lib_array(nldr_node_obj
, root
->lib
);
1292 nldr_obj
->ldr_fxns
.close_fxn(root
->lib
);
1297 /* Check for circular dependencies. */
1298 for (i
= 0; i
< depth
; i
++) {
1299 if (root
->lib
== lib_path
[i
]) {
1300 /* This condition could be checked by a
1301 * tool at build time. */
1307 /* Add library to current path in dependency tree */
1308 lib_path
[depth
] = root
->lib
;
1310 /* Get number of dependent libraries */
1312 dcd_get_num_dep_libs(nldr_node_obj
->nldr_obj
->dcd_mgr
,
1313 &uuid
, &nd_libs
, &np_libs
, phase
);
1315 DBC_ASSERT(nd_libs
>= np_libs
);
1317 if (!(*nldr_node_obj
->phase_split
))
1320 /* nd_libs = #of dependent libraries */
1321 root
->dep_libs
= nd_libs
- np_libs
;
1323 dep_lib_uui_ds
= kzalloc(sizeof(struct dsp_uuid
) *
1324 nd_libs
, GFP_KERNEL
);
1325 persistent_dep_libs
=
1326 kzalloc(sizeof(bool) * nd_libs
, GFP_KERNEL
);
1327 if (!dep_lib_uui_ds
|| !persistent_dep_libs
)
1330 if (root
->dep_libs
> 0) {
1331 /* Allocate arrays for dependent lib UUIDs,
1333 root
->dep_libs_tree
= kzalloc
1334 (sizeof(struct lib_node
) *
1335 (root
->dep_libs
), GFP_KERNEL
);
1336 if (!(root
->dep_libs_tree
))
1342 /* Get the dependent library UUIDs */
1344 dcd_get_dep_libs(nldr_node_obj
->
1345 nldr_obj
->dcd_mgr
, &uuid
,
1346 nd_libs
, dep_lib_uui_ds
,
1347 persistent_dep_libs
,
1354 * Recursively load dependent libraries.
1357 for (i
= 0; i
< nd_libs
; i
++) {
1358 /* If root library is NOT persistent, and dep library
1359 * is, then record it. If root library IS persistent,
1360 * the deplib is already included */
1361 if (!root_prstnt
&& persistent_dep_libs
[i
] &&
1362 *nldr_node_obj
->phase_split
) {
1363 if ((nldr_node_obj
->pers_libs
) >= MAXLIBS
) {
1368 /* Allocate library outside of phase */
1370 &nldr_node_obj
->pers_lib_table
1371 [nldr_node_obj
->pers_libs
];
1374 persistent_dep_libs
[i
] = true;
1376 /* Allocate library within phase */
1377 dep_lib
= &root
->dep_libs_tree
[nd_libs_loaded
];
1380 status
= load_lib(nldr_node_obj
, dep_lib
,
1382 persistent_dep_libs
[i
], lib_path
,
1386 if ((status
!= 0) &&
1387 !root_prstnt
&& persistent_dep_libs
[i
] &&
1388 *nldr_node_obj
->phase_split
) {
1389 (nldr_node_obj
->pers_libs
)++;
1391 if (!persistent_dep_libs
[i
] ||
1392 !(*nldr_node_obj
->phase_split
)) {
1402 /* Now we can load the root library */
1404 new_attrs
= nldr_obj
->ldr_attrs
;
1405 new_attrs
.sym_arg
= root
;
1406 new_attrs
.rmm_handle
= nldr_node_obj
;
1407 new_attrs
.input_params
= nldr_node_obj
->priv_ref
;
1408 new_attrs
.base_image
= false;
1411 nldr_obj
->ldr_fxns
.load_fxn(root
->lib
, flags
, &new_attrs
,
1416 * In case of failure, unload any dependent libraries that
1417 * were loaded, and close the root library.
1418 * (Persistent libraries are unloaded from the very top)
1421 if (phase
!= NLDR_EXECUTE
) {
1422 for (i
= 0; i
< nldr_node_obj
->pers_libs
; i
++)
1423 unload_lib(nldr_node_obj
,
1424 &nldr_node_obj
->pers_lib_table
[i
]);
1426 nldr_node_obj
->pers_libs
= 0;
1428 for (i
= 0; i
< nd_libs_loaded
; i
++)
1429 unload_lib(nldr_node_obj
, &root
->dep_libs_tree
[i
]);
1432 nldr_obj
->ldr_fxns
.close_fxn(root
->lib
);
1436 /* Going up one node in the dependency tree */
1439 kfree(dep_lib_uui_ds
);
1440 dep_lib_uui_ds
= NULL
;
1442 kfree(persistent_dep_libs
);
1443 persistent_dep_libs
= NULL
;
1449 * ======== load_ovly ========
1451 static int load_ovly(struct nldr_nodeobject
*nldr_node_obj
,
1452 enum nldr_phase phase
)
1454 struct nldr_object
*nldr_obj
= nldr_node_obj
->nldr_obj
;
1455 struct ovly_node
*po_node
= NULL
;
1456 struct ovly_sect
*phase_sects
= NULL
;
1457 struct ovly_sect
*other_sects_list
= NULL
;
1460 u16 other_alloc
= 0;
1461 u16
*ref_count
= NULL
;
1462 u16
*other_ref
= NULL
;
1464 struct ovly_sect
*ovly_section
;
1467 /* Find the node in the table */
1468 for (i
= 0; i
< nldr_obj
->ovly_nodes
; i
++) {
1470 (&nldr_node_obj
->uuid
, &nldr_obj
->ovly_table
[i
].uuid
)) {
1472 po_node
= &(nldr_obj
->ovly_table
[i
]);
1477 DBC_ASSERT(i
< nldr_obj
->ovly_nodes
);
1486 ref_count
= &(po_node
->create_ref
);
1487 other_ref
= &(po_node
->other_ref
);
1488 phase_sects
= po_node
->create_sects_list
;
1489 other_sects_list
= po_node
->other_sects_list
;
1493 ref_count
= &(po_node
->execute_ref
);
1494 phase_sects
= po_node
->execute_sects_list
;
1498 ref_count
= &(po_node
->delete_ref
);
1499 phase_sects
= po_node
->delete_sects_list
;
1507 if (ref_count
== NULL
)
1510 if (*ref_count
!= 0)
1513 /* 'Allocate' memory for overlay sections of this phase */
1514 ovly_section
= phase_sects
;
1515 while (ovly_section
) {
1516 /* allocate *//* page not supported yet */
1517 /* reserve *//* align */
1518 status
= rmm_alloc(nldr_obj
->rmm
, 0, ovly_section
->size
, 0,
1519 &(ovly_section
->sect_run_addr
), true);
1521 ovly_section
= ovly_section
->next_sect
;
1527 if (other_ref
&& *other_ref
== 0) {
1528 /* 'Allocate' memory for other overlay sections
1531 ovly_section
= other_sects_list
;
1532 while (ovly_section
) {
1533 /* page not supported *//* align */
1536 rmm_alloc(nldr_obj
->rmm
, 0,
1537 ovly_section
->size
, 0,
1538 &(ovly_section
->sect_run_addr
),
1541 ovly_section
= ovly_section
->next_sect
;
1549 if (*ref_count
== 0) {
1551 /* Load sections for this phase */
1552 ovly_section
= phase_sects
;
1553 while (ovly_section
&& !status
) {
1555 (*nldr_obj
->ovly_fxn
) (nldr_node_obj
->
1562 ovly_section
->page
);
1563 if (bytes
!= ovly_section
->size
)
1566 ovly_section
= ovly_section
->next_sect
;
1570 if (other_ref
&& *other_ref
== 0) {
1572 /* Load other sections (create phase) */
1573 ovly_section
= other_sects_list
;
1574 while (ovly_section
&& !status
) {
1576 (*nldr_obj
->ovly_fxn
) (nldr_node_obj
->
1583 ovly_section
->page
);
1584 if (bytes
!= ovly_section
->size
)
1587 ovly_section
= ovly_section
->next_sect
;
1592 /* 'Deallocate' memory */
1593 free_sects(nldr_obj
, phase_sects
, alloc_num
);
1594 free_sects(nldr_obj
, other_sects_list
, other_alloc
);
1597 if (!status
&& (ref_count
!= NULL
)) {
1608 * ======== remote_alloc ========
1610 static int remote_alloc(void **ref
, u16 mem_sect
, u32 size
,
1611 u32 align
, u32
*dsp_address
,
1612 s32 segmnt_id
, s32 req
,
1615 struct nldr_nodeobject
*hnode
= (struct nldr_nodeobject
*)ref
;
1616 struct nldr_object
*nldr_obj
;
1617 struct rmm_target_obj
*rmm
;
1618 u16 mem_phase_bit
= MAXFLAGS
;
1623 struct rmm_addr
*rmm_addr_obj
= (struct rmm_addr
*)dsp_address
;
1624 bool mem_load_req
= false;
1625 int status
= -ENOMEM
; /* Set to fail */
1627 DBC_REQUIRE(mem_sect
== DBLL_CODE
|| mem_sect
== DBLL_DATA
||
1628 mem_sect
== DBLL_BSS
);
1629 nldr_obj
= hnode
->nldr_obj
;
1630 rmm
= nldr_obj
->rmm
;
1631 /* Convert size to DSP words */
1633 (size
+ nldr_obj
->dsp_word_size
-
1634 1) / nldr_obj
->dsp_word_size
;
1635 /* Modify memory 'align' to account for DSP cache line size */
1636 align
= lcm(GEM_CACHE_LINE_SIZE
, align
);
1637 dev_dbg(bridge
, "%s: memory align to 0x%x\n", __func__
, align
);
1638 if (segmnt_id
!= -1) {
1639 rmm_addr_obj
->segid
= segmnt_id
;
1643 switch (hnode
->phase
) {
1645 mem_phase_bit
= CREATEDATAFLAGBIT
;
1648 mem_phase_bit
= DELETEDATAFLAGBIT
;
1651 mem_phase_bit
= EXECUTEDATAFLAGBIT
;
1657 if (mem_sect
== DBLL_CODE
)
1660 if (mem_phase_bit
< MAXFLAGS
)
1661 segid
= hnode
->seg_id
[mem_phase_bit
];
1663 /* Determine if there is a memory loading requirement */
1664 if ((hnode
->code_data_flag_mask
>> mem_phase_bit
) & 0x1)
1665 mem_load_req
= true;
1668 mem_sect_type
= (mem_sect
== DBLL_CODE
) ? DYNM_CODE
: DYNM_DATA
;
1670 /* Find an appropriate segment based on mem_sect */
1671 if (segid
== NULLID
) {
1672 /* No memory requirements of preferences */
1673 DBC_ASSERT(!mem_load_req
);
1676 if (segid
<= MAXSEGID
) {
1677 DBC_ASSERT(segid
< nldr_obj
->dload_segs
);
1678 /* Attempt to allocate from segid first. */
1679 rmm_addr_obj
->segid
= segid
;
1681 rmm_alloc(rmm
, segid
, word_size
, align
, dsp_address
, false);
1683 dev_dbg(bridge
, "%s: Unable allocate from segment %d\n",
1687 /* segid > MAXSEGID ==> Internal or external memory */
1688 DBC_ASSERT(segid
== MEMINTERNALID
|| segid
== MEMEXTERNALID
);
1689 /* Check for any internal or external memory segment,
1690 * depending on segid. */
1691 mem_sect_type
|= segid
== MEMINTERNALID
?
1692 DYNM_INTERNAL
: DYNM_EXTERNAL
;
1693 for (i
= 0; i
< nldr_obj
->dload_segs
; i
++) {
1694 if ((nldr_obj
->seg_table
[i
] & mem_sect_type
) !=
1698 status
= rmm_alloc(rmm
, i
, word_size
, align
,
1699 dsp_address
, false);
1701 /* Save segid for freeing later */
1702 rmm_addr_obj
->segid
= i
;
1708 /* Haven't found memory yet, attempt to find any segment that works */
1709 if (status
== -ENOMEM
&& !mem_load_req
) {
1710 dev_dbg(bridge
, "%s: Preferred segment unavailable, trying "
1711 "another\n", __func__
);
1712 for (i
= 0; i
< nldr_obj
->dload_segs
; i
++) {
1713 /* All bits of mem_sect_type must be set */
1714 if ((nldr_obj
->seg_table
[i
] & mem_sect_type
) !=
1718 status
= rmm_alloc(rmm
, i
, word_size
, align
,
1719 dsp_address
, false);
1722 rmm_addr_obj
->segid
= i
;
1731 static int remote_free(void **ref
, u16 space
, u32 dsp_address
,
1732 u32 size
, bool reserve
)
1734 struct nldr_object
*nldr_obj
= (struct nldr_object
*)ref
;
1735 struct rmm_target_obj
*rmm
;
1737 int status
= -ENOMEM
; /* Set to fail */
1739 DBC_REQUIRE(nldr_obj
);
1741 rmm
= nldr_obj
->rmm
;
1743 /* Convert size to DSP words */
1745 (size
+ nldr_obj
->dsp_word_size
-
1746 1) / nldr_obj
->dsp_word_size
;
1748 if (rmm_free(rmm
, space
, dsp_address
, word_size
, reserve
))
1755 * ======== unload_lib ========
1757 static void unload_lib(struct nldr_nodeobject
*nldr_node_obj
,
1758 struct lib_node
*root
)
1760 struct dbll_attrs new_attrs
;
1761 struct nldr_object
*nldr_obj
= nldr_node_obj
->nldr_obj
;
1764 DBC_ASSERT(root
!= NULL
);
1766 /* Unload dependent libraries */
1767 for (i
= 0; i
< root
->dep_libs
; i
++)
1768 unload_lib(nldr_node_obj
, &root
->dep_libs_tree
[i
]);
1772 new_attrs
= nldr_obj
->ldr_attrs
;
1773 new_attrs
.rmm_handle
= nldr_obj
->rmm
;
1774 new_attrs
.input_params
= nldr_node_obj
->priv_ref
;
1775 new_attrs
.base_image
= false;
1776 new_attrs
.sym_arg
= root
;
1779 /* Unload the root library */
1780 nldr_obj
->ldr_fxns
.unload_fxn(root
->lib
, &new_attrs
);
1781 nldr_obj
->ldr_fxns
.close_fxn(root
->lib
);
1784 /* Free dependent library list */
1785 kfree(root
->dep_libs_tree
);
1786 root
->dep_libs_tree
= NULL
;
1790 * ======== unload_ovly ========
1792 static void unload_ovly(struct nldr_nodeobject
*nldr_node_obj
,
1793 enum nldr_phase phase
)
1795 struct nldr_object
*nldr_obj
= nldr_node_obj
->nldr_obj
;
1796 struct ovly_node
*po_node
= NULL
;
1797 struct ovly_sect
*phase_sects
= NULL
;
1798 struct ovly_sect
*other_sects_list
= NULL
;
1801 u16 other_alloc
= 0;
1802 u16
*ref_count
= NULL
;
1803 u16
*other_ref
= NULL
;
1805 /* Find the node in the table */
1806 for (i
= 0; i
< nldr_obj
->ovly_nodes
; i
++) {
1808 (&nldr_node_obj
->uuid
, &nldr_obj
->ovly_table
[i
].uuid
)) {
1810 po_node
= &(nldr_obj
->ovly_table
[i
]);
1815 DBC_ASSERT(i
< nldr_obj
->ovly_nodes
);
1818 /* TODO: Should we print warning here? */
1823 ref_count
= &(po_node
->create_ref
);
1824 phase_sects
= po_node
->create_sects_list
;
1825 alloc_num
= po_node
->create_sects
;
1828 ref_count
= &(po_node
->execute_ref
);
1829 phase_sects
= po_node
->execute_sects_list
;
1830 alloc_num
= po_node
->execute_sects
;
1833 ref_count
= &(po_node
->delete_ref
);
1834 other_ref
= &(po_node
->other_ref
);
1835 phase_sects
= po_node
->delete_sects_list
;
1836 /* 'Other' overlay sections are unloaded in the delete phase */
1837 other_sects_list
= po_node
->other_sects_list
;
1838 alloc_num
= po_node
->delete_sects
;
1839 other_alloc
= po_node
->other_sects
;
1845 DBC_ASSERT(ref_count
&& (*ref_count
> 0));
1846 if (ref_count
&& (*ref_count
> 0)) {
1849 DBC_ASSERT(*other_ref
> 0);
1854 if (ref_count
&& *ref_count
== 0) {
1855 /* 'Deallocate' memory */
1856 free_sects(nldr_obj
, phase_sects
, alloc_num
);
1858 if (other_ref
&& *other_ref
== 0)
1859 free_sects(nldr_obj
, other_sects_list
, other_alloc
);
1863 * ======== find_in_persistent_lib_array ========
1865 static bool find_in_persistent_lib_array(struct nldr_nodeobject
*nldr_node_obj
,
1866 struct dbll_library_obj
*lib
)
1870 for (i
= 0; i
< nldr_node_obj
->pers_libs
; i
++) {
1871 if (lib
== nldr_node_obj
->pers_lib_table
[i
].lib
)
1879 #ifdef CONFIG_TIDSPBRIDGE_BACKTRACE
1881 * nldr_find_addr() - Find the closest symbol to the given address based on
1882 * dynamic node object.
1884 * @nldr_node: Dynamic node object
1885 * @sym_addr: Given address to find the dsp symbol
1886 * @offset_range: offset range to look for dsp symbol
1887 * @offset_output: Symbol Output address
1888 * @sym_name: String with the dsp symbol
1890 * This function finds the node library for a given address and
1891 * retrieves the dsp symbol by calling dbll_find_dsp_symbol.
1893 int nldr_find_addr(struct nldr_nodeobject
*nldr_node
, u32 sym_addr
,
1894 u32 offset_range
, void *offset_output
, char *sym_name
)
1897 bool status1
= false;
1899 struct lib_node root
= { NULL
, 0, NULL
};
1900 DBC_REQUIRE(refs
> 0);
1901 DBC_REQUIRE(offset_output
!= NULL
);
1902 DBC_REQUIRE(sym_name
!= NULL
);
1903 pr_debug("%s(0x%x, 0x%x, 0x%x, 0x%x, %s)\n", __func__
, (u32
) nldr_node
,
1904 sym_addr
, offset_range
, (u32
) offset_output
, sym_name
);
1906 if (nldr_node
->dynamic
&& *nldr_node
->phase_split
) {
1907 switch (nldr_node
->phase
) {
1909 root
= nldr_node
->create_lib
;
1912 root
= nldr_node
->execute_lib
;
1915 root
= nldr_node
->delete_lib
;
1922 /* for Overlay nodes or non-split Dynamic nodes */
1923 root
= nldr_node
->root
;
1926 status1
= dbll_find_dsp_symbol(root
.lib
, sym_addr
,
1927 offset_range
, offset_output
, sym_name
);
1929 /* If symbol not found, check dependent libraries */
1931 for (i
= 0; i
< root
.dep_libs
; i
++) {
1932 status1
= dbll_find_dsp_symbol(
1933 root
.dep_libs_tree
[i
].lib
, sym_addr
,
1934 offset_range
, offset_output
, sym_name
);
1939 /* Check persistent libraries */
1941 for (i
= 0; i
< nldr_node
->pers_libs
; i
++) {
1942 status1
= dbll_find_dsp_symbol(
1943 nldr_node
->pers_lib_table
[i
].lib
, sym_addr
,
1944 offset_range
, offset_output
, sym_name
);
1951 pr_debug("%s: Address 0x%x not found in range %d.\n",
1952 __func__
, sym_addr
, offset_range
);