1/*
2 * nldr.c
3 *
4 * DSP-BIOS Bridge driver support functions for TI OMAP processors.
5 *
6 * DSP/BIOS Bridge dynamic + overlay Node loader.
7 *
8 * Copyright (C) 2005-2006 Texas Instruments, Inc.
9 *
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.
13 *
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.
17 */
18
19#include <linux/types.h>
20
21#include <dspbridge/host_os.h>
22
23#include <dspbridge/dbdefs.h>
24
25#include <dspbridge/dbc.h>
26
27/* Platform manager */
28#include <dspbridge/cod.h>
29#include <dspbridge/dev.h>
30
31/* Resource manager */
32#include <dspbridge/dbll.h>
33#include <dspbridge/dbdcd.h>
34#include <dspbridge/rmm.h>
35#include <dspbridge/uuidutil.h>
36
37#include <dspbridge/nldr.h>
38#include <linux/lcm.h>
39
40/* Name of section containing dynamic load mem */
41#define DYNMEMSECT  ".dspbridge_mem"
42
43/* Name of section containing dependent library information */
44#define DEPLIBSECT  ".dspbridge_deplibs"
45
46/* Max depth of recursion for loading node's dependent libraries */
47#define MAXDEPTH	    5
48
49/* Max number of persistent libraries kept by a node */
50#define MAXLIBS	 5
51
52/*
53 *  Defines for extracting packed dynamic load memory requirements from two
54 *  masks.
55 *  These defines must match node.cdb and dynm.cdb
56 *  Format of data/code mask is:
57 *   uuuuuuuu|fueeeeee|fudddddd|fucccccc|
58 *  where
59 *      u = unused
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.
65 *
66 *  The 6 bits of the segid are interpreted as follows:
67 *
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).
75 *
76 */
77/* Maximum allowed dynamic loading memory segments */
78#define MAXMEMSEGS      32
79
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 */
86
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 */
90
91/*
92 *  Masks that define memory type.  Must match defines in dynm.cdb.
93 */
94#define DYNM_CODE	0x2
95#define DYNM_DATA	0x4
96#define DYNM_CODEDATA   (DYNM_CODE | DYNM_DATA)
97#define DYNM_INTERNAL   0x8
98#define DYNM_EXTERNAL   0x10
99
100/*
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.
105 *
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.
109 */
110#define CREATEDATAFLAGBIT   0
111#define CREATECODEFLAGBIT   1
112#define EXECUTEDATAFLAGBIT  2
113#define EXECUTECODEFLAGBIT  3
114#define DELETEDATAFLAGBIT   4
115#define DELETECODEFLAGBIT   5
116#define MAXFLAGS	    6
117
118    /*
119     *  These names may be embedded in overlay sections to identify which
120     *  node phase the section should be overlayed.
121 */
122#define PCREATE	 "create"
123#define PDELETE	 "delete"
124#define PEXECUTE	"execute"
125
126static inline bool is_equal_uuid(struct dsp_uuid *uuid1,
127							struct dsp_uuid *uuid2)
128{
129	return !memcmp(uuid1, uuid2, sizeof(struct dsp_uuid));
130}
131
132    /*
133     *  ======== mem_seg_info ========
134     *  Format of dynamic loading memory segment info in coff file.
135     *  Must match dynm.h55.
136 */
137struct mem_seg_info {
138	u32 segid;		/* Dynamic loading memory segment number */
139	u32 base;
140	u32 len;
141	u32 type;		/* Mask of DYNM_CODE, DYNM_INTERNAL, etc. */
142};
143
144/*
145 *  ======== lib_node ========
146 *  For maintaining a tree of library dependencies.
147 */
148struct lib_node {
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 */
152};
153
154/*
155 *  ======== ovly_sect ========
156 *  Information needed to overlay a section.
157 */
158struct ovly_sect {
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 */
164};
165
166/*
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.
170 */
171struct ovly_node {
172	struct dsp_uuid uuid;
173	char *node_name;
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;
178	u16 create_sects;
179	u16 delete_sects;
180	u16 execute_sects;
181	u16 other_sects;
182	u16 create_ref;
183	u16 delete_ref;
184	u16 execute_ref;
185	u16 other_ref;
186};
187
188/*
189 *  ======== nldr_object ========
190 *  Overlay loader object.
191 */
192struct nldr_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
207				 * indexed by segid
208				 */
209	u16 dsp_mau_size;	/* Size of DSP MAU */
210	u16 dsp_word_size;	/* Size of DSP word */
211};
212
213/*
214 *  ======== nldr_nodeobject ========
215 *  Dynamic node object. This object is created when a node is allocated.
216 */
217struct 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 */
234
235	/*
236	 *  Dynamic loading memory segments for data and code of each phase.
237	 */
238	u16 seg_id[MAXFLAGS];
239
240	/*
241	 *  Mask indicating whether each mem segment specified in seg_id[]
242	 *  is preferred or required.
243	 *  For example
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].
247	 */
248	u32 code_data_flag_mask;
249};
250
251/* Dynamic loader function table */
252static 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,
266};
267
268static u32 refs;		/* module reference count */
269
270static int add_ovly_info(void *handle, struct dbll_sect_info *sect_info,
271				u32 addr, u32 bytes);
272static int add_ovly_node(struct dsp_uuid *uuid_obj,
273				enum dsp_dcdobjtype obj_type, void *handle);
274static 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);
278static s32 fake_ovly_write(void *handle, u32 dsp_address, void *buf, u32 bytes,
279			   s32 mtype);
280static void free_sects(struct nldr_object *nldr_obj,
281		       struct ovly_sect *phase_sects, u16 alloc_num);
282static bool get_symbol_value(void *handle, void *parg, void *rmm_handle,
283			     char *sym_name, struct dbll_sym_val **sym);
284static int load_lib(struct nldr_nodeobject *nldr_node_obj,
285			   struct lib_node *root, struct dsp_uuid uuid,
286			   bool root_prstnt,
287			   struct dbll_library_obj **lib_path,
288			   enum nldr_phase phase, u16 depth);
289static int load_ovly(struct nldr_nodeobject *nldr_node_obj,
290			    enum nldr_phase phase);
291static int remote_alloc(void **ref, u16 mem_sect, u32 size,
292			       u32 align, u32 *dsp_address,
293			       s32 segmnt_id,
294			       s32 req, bool reserve);
295static int remote_free(void **ref, u16 space, u32 dsp_address, u32 size,
296			      bool reserve);
297
298static void unload_lib(struct nldr_nodeobject *nldr_node_obj,
299		       struct lib_node *root);
300static void unload_ovly(struct nldr_nodeobject *nldr_node_obj,
301			enum nldr_phase phase);
302static bool find_in_persistent_lib_array(struct nldr_nodeobject *nldr_node_obj,
303					 struct dbll_library_obj *lib);
304
305/*
306 *  ======== nldr_allocate ========
307 */
308int 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)
312{
313	struct nldr_nodeobject *nldr_node_obj = NULL;
314	int status = 0;
315
316	DBC_REQUIRE(refs > 0);
317	DBC_REQUIRE(node_props != NULL);
318	DBC_REQUIRE(nldr_nodeobj != NULL);
319	DBC_REQUIRE(nldr_obj);
320
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);
325
326	if (nldr_node_obj == NULL) {
327		status = -ENOMEM;
328	} else {
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;
335		/*
336		 *  Determine if node is a dynamically loaded node from
337		 *  ndb_props.
338		 */
339		if (node_props->load_type == NLDR_DYNAMICLOAD) {
340			/* Dynamic node */
341			nldr_node_obj->dynamic = true;
342			/*
343			 *  Extract memory requirements from ndb_props masks
344			 */
345			/* Create phase */
346			nldr_node_obj->seg_id[CREATEDATAFLAGBIT] = (u16)
347			    (node_props->data_mem_seg_mask >> CREATEBIT) &
348			    SEGMASK;
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;
358			/* Execute phase */
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) <<
365			    EXECUTEDATAFLAGBIT;
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) <<
372			    EXECUTECODEFLAGBIT;
373			/* Delete phase */
374			nldr_node_obj->seg_id[DELETEDATAFLAGBIT] = (u16)
375			    (node_props->data_mem_seg_mask >> DELETEBIT) &
376			    SEGMASK;
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;
386		} else {
387			/* Non-dynamically loaded nodes are part of the
388			 * base image */
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;
393
394		}
395		*nldr_nodeobj = (struct nldr_nodeobject *)nldr_node_obj;
396	}
397	/* Cleanup on failure */
398	if (status && nldr_node_obj)
399		kfree(nldr_node_obj);
400
401	DBC_ENSURE((!status && *nldr_nodeobj)
402		   || (status && *nldr_nodeobj == NULL));
403	return status;
404}
405
406/*
407 *  ======== nldr_create ========
408 */
409int nldr_create(struct nldr_object **nldr,
410		       struct dev_object *hdev_obj,
411		       const struct nldr_attrs *pattrs)
412{
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;
419	dbll_flags flags;
420	u32 ul_entry;
421	u16 dload_segs = 0;
422	struct mem_seg_info *mem_info_obj;
423	u32 ul_len = 0;
424	u32 ul_addr;
425	struct rmm_segment *rmm_segs = NULL;
426	u16 i;
427	int status = 0;
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);
434
435	/* Allocate dynamic loader object */
436	nldr_obj = kzalloc(sizeof(struct nldr_object), GFP_KERNEL);
437	if (nldr_obj) {
438		nldr_obj->dev_obj = hdev_obj;
439		/* warning, lazy status checking alert! */
440		dev_get_cod_mgr(hdev_obj, &cod_mgr);
441		if (cod_mgr) {
442			status = cod_get_loader(cod_mgr, &nldr_obj->dbll);
443			DBC_ASSERT(!status);
444			status = cod_get_base_lib(cod_mgr, &nldr_obj->base_lib);
445			DBC_ASSERT(!status);
446			status =
447			    cod_get_base_name(cod_mgr, sz_zl_file,
448							COD_MAXPATHLENGTH);
449			DBC_ASSERT(!status);
450		}
451		status = 0;
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()))
457			status = -ENOMEM;
458
459	} else {
460		status = -ENOMEM;
461	}
462	/* Create the DCD Manager */
463	if (!status)
464		status = dcd_create_manager(NULL, &nldr_obj->dcd_mgr);
465
466	/* Get dynamic loading memory sections from base lib */
467	if (!status) {
468		status =
469		    nldr_obj->ldr_fxns.get_sect_fxn(nldr_obj->base_lib,
470						    DYNMEMSECT, &ul_addr,
471						    &ul_len);
472		if (!status) {
473			psz_coff_buf =
474				kzalloc(ul_len * nldr_obj->dsp_mau_size,
475								GFP_KERNEL);
476			if (!psz_coff_buf)
477				status = -ENOMEM;
478		} else {
479			/* Ok to not have dynamic loading memory */
480			status = 0;
481			ul_len = 0;
482			dev_dbg(bridge, "%s: failed - no dynamic loading mem "
483				"segments: 0x%x\n", __func__, status);
484		}
485	}
486	if (!status && ul_len > 0) {
487		/* Read section containing dynamic load mem segments */
488		status =
489		    nldr_obj->ldr_fxns.read_sect_fxn(nldr_obj->base_lib,
490						     DYNMEMSECT, psz_coff_buf,
491						     ul_len);
492	}
493	if (!status && ul_len > 0) {
494		/* Parse memory segment data */
495		dload_segs = (u16) (*((u32 *) psz_coff_buf));
496		if (dload_segs > MAXMEMSEGS)
497			status = -EBADF;
498	}
499	/* Parse dynamic load memory segments */
500	if (!status && dload_segs > 0) {
501		rmm_segs = kzalloc(sizeof(struct rmm_segment) * dload_segs,
502								GFP_KERNEL);
503		nldr_obj->seg_table =
504				kzalloc(sizeof(u32) * dload_segs, GFP_KERNEL);
505		if (rmm_segs == NULL || nldr_obj->seg_table == NULL) {
506			status = -ENOMEM;
507		} else {
508			nldr_obj->dload_segs = dload_segs;
509			mem_info_obj = (struct mem_seg_info *)(psz_coff_buf +
510							       sizeof(u32));
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;
517				dev_dbg(bridge,
518					"(proc) DLL MEMSEGMENT: %d, "
519					"Base: 0x%x, Length: 0x%x\n", i,
520					rmm_segs[i].base, rmm_segs[i].length);
521			}
522		}
523	}
524	/* Create Remote memory manager */
525	if (!status)
526		status = rmm_create(&nldr_obj->rmm, rmm_segs, dload_segs);
527
528	if (!status) {
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;
540	}
541	kfree(rmm_segs);
542
543	kfree(psz_coff_buf);
544
545	/* Get overlay nodes */
546	if (!status) {
547		status =
548		    cod_get_base_name(cod_mgr, sz_zl_file, COD_MAXPATHLENGTH);
549		/* lazy check */
550		DBC_ASSERT(!status);
551		/* First count number of overlay nodes */
552		status =
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,
564						 add_ovly_node,
565						 (void *)nldr_obj);
566		}
567	}
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);
576	}
577	if (!status) {
578		*nldr = (struct nldr_object *)nldr_obj;
579	} else {
580		if (nldr_obj)
581			nldr_delete((struct nldr_object *)nldr_obj);
582
583		*nldr = NULL;
584	}
585	/* FIXME:Temp. Fix. Must be removed */
586	DBC_ENSURE((!status && *nldr) || (status && *nldr == NULL));
587	return status;
588}
589
590/*
591 *  ======== nldr_delete ========
592 */
593void nldr_delete(struct nldr_object *nldr_obj)
594{
595	struct ovly_sect *ovly_section;
596	struct ovly_sect *next;
597	u16 i;
598	DBC_REQUIRE(refs > 0);
599	DBC_REQUIRE(nldr_obj);
600
601	nldr_obj->ldr_fxns.exit_fxn();
602	if (nldr_obj->rmm)
603		rmm_delete(nldr_obj->rmm);
604
605	kfree(nldr_obj->seg_table);
606
607	if (nldr_obj->dcd_mgr)
608		dcd_destroy_manager(nldr_obj->dcd_mgr);
609
610	/* Free overlay node information */
611	if (nldr_obj->ovly_table) {
612		for (i = 0; i < nldr_obj->ovly_nodes; i++) {
613			ovly_section =
614			    nldr_obj->ovly_table[i].create_sects_list;
615			while (ovly_section) {
616				next = ovly_section->next_sect;
617				kfree(ovly_section);
618				ovly_section = next;
619			}
620			ovly_section =
621			    nldr_obj->ovly_table[i].delete_sects_list;
622			while (ovly_section) {
623				next = ovly_section->next_sect;
624				kfree(ovly_section);
625				ovly_section = next;
626			}
627			ovly_section =
628			    nldr_obj->ovly_table[i].execute_sects_list;
629			while (ovly_section) {
630				next = ovly_section->next_sect;
631				kfree(ovly_section);
632				ovly_section = next;
633			}
634			ovly_section = nldr_obj->ovly_table[i].other_sects_list;
635			while (ovly_section) {
636				next = ovly_section->next_sect;
637				kfree(ovly_section);
638				ovly_section = next;
639			}
640		}
641		kfree(nldr_obj->ovly_table);
642	}
643	kfree(nldr_obj);
644}
645
646/*
647 *  ======== nldr_exit ========
648 *  Discontinue usage of NLDR module.
649 */
650void nldr_exit(void)
651{
652	DBC_REQUIRE(refs > 0);
653
654	refs--;
655
656	if (refs == 0)
657		rmm_exit();
658
659	DBC_ENSURE(refs >= 0);
660}
661
662/*
663 *  ======== nldr_get_fxn_addr ========
664 */
665int nldr_get_fxn_addr(struct nldr_nodeobject *nldr_node_obj,
666			     char *str_fxn, u32 * addr)
667{
668	struct dbll_sym_val *dbll_sym;
669	struct nldr_object *nldr_obj;
670	int status = 0;
671	bool status1 = false;
672	s32 i = 0;
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);
678
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) {
683		case NLDR_CREATE:
684			root = nldr_node_obj->create_lib;
685			break;
686		case NLDR_EXECUTE:
687			root = nldr_node_obj->execute_lib;
688			break;
689		case NLDR_DELETE:
690			root = nldr_node_obj->delete_lib;
691			break;
692		default:
693			DBC_ASSERT(false);
694			break;
695		}
696	} else {
697		/* for Overlay nodes or non-split Dynamic nodes */
698		root = nldr_node_obj->root;
699	}
700	status1 =
701	    nldr_obj->ldr_fxns.get_c_addr_fxn(root.lib, str_fxn, &dbll_sym);
702	if (!status1)
703		status1 =
704		    nldr_obj->ldr_fxns.get_addr_fxn(root.lib, str_fxn,
705						    &dbll_sym);
706
707	/* If symbol not found, check dependent libraries */
708	if (!status1) {
709		for (i = 0; i < root.dep_libs; i++) {
710			status1 =
711			    nldr_obj->ldr_fxns.get_addr_fxn(root.dep_libs_tree
712							    [i].lib, str_fxn,
713							    &dbll_sym);
714			if (!status1) {
715				status1 =
716				    nldr_obj->ldr_fxns.
717				    get_c_addr_fxn(root.dep_libs_tree[i].lib,
718						   str_fxn, &dbll_sym);
719			}
720			if (status1) {
721				/* Symbol found */
722				break;
723			}
724		}
725	}
726	/* Check persistent libraries */
727	if (!status1) {
728		for (i = 0; i < nldr_node_obj->pers_libs; i++) {
729			status1 =
730			    nldr_obj->ldr_fxns.
731			    get_addr_fxn(nldr_node_obj->pers_lib_table[i].lib,
732					 str_fxn, &dbll_sym);
733			if (!status1) {
734				status1 =
735				    nldr_obj->ldr_fxns.
736				    get_c_addr_fxn(nldr_node_obj->pers_lib_table
737						   [i].lib, str_fxn, &dbll_sym);
738			}
739			if (status1) {
740				/* Symbol found */
741				break;
742			}
743		}
744	}
745
746	if (status1)
747		*addr = dbll_sym->value;
748	else
749		status = -ESPIPE;
750
751	return status;
752}
753
754/*
755 *  ======== nldr_get_rmm_manager ========
756 *  Given a NLDR object, retrieve RMM Manager Handle
757 */
758int nldr_get_rmm_manager(struct nldr_object *nldr,
759				struct rmm_target_obj **rmm_mgr)
760{
761	int status = 0;
762	struct nldr_object *nldr_obj = nldr;
763	DBC_REQUIRE(rmm_mgr != NULL);
764
765	if (nldr) {
766		*rmm_mgr = nldr_obj->rmm;
767	} else {
768		*rmm_mgr = NULL;
769		status = -EFAULT;
770	}
771
772	DBC_ENSURE(!status || (rmm_mgr != NULL && *rmm_mgr == NULL));
773
774	return status;
775}
776
777/*
778 *  ======== nldr_init ========
779 *  Initialize the NLDR module.
780 */
781bool nldr_init(void)
782{
783	DBC_REQUIRE(refs >= 0);
784
785	if (refs == 0)
786		rmm_init();
787
788	refs++;
789
790	DBC_ENSURE(refs > 0);
791	return true;
792}
793
794/*
795 *  ======== nldr_load ========
796 */
797int nldr_load(struct nldr_nodeobject *nldr_node_obj,
798		     enum nldr_phase phase)
799{
800	struct nldr_object *nldr_obj;
801	struct dsp_uuid lib_uuid;
802	int status = 0;
803
804	DBC_REQUIRE(refs > 0);
805	DBC_REQUIRE(nldr_node_obj);
806
807	nldr_obj = nldr_node_obj->nldr_obj;
808
809	if (nldr_node_obj->dynamic) {
810		nldr_node_obj->phase = phase;
811
812		lib_uuid = nldr_node_obj->uuid;
813
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. */
818
819		status =
820		    load_lib(nldr_node_obj, &nldr_node_obj->root, lib_uuid,
821			     false, nldr_node_obj->lib_path, phase, 0);
822
823		if (!status) {
824			if (*nldr_node_obj->phase_split) {
825				switch (phase) {
826				case NLDR_CREATE:
827					nldr_node_obj->create_lib =
828					    nldr_node_obj->root;
829					break;
830
831				case NLDR_EXECUTE:
832					nldr_node_obj->execute_lib =
833					    nldr_node_obj->root;
834					break;
835
836				case NLDR_DELETE:
837					nldr_node_obj->delete_lib =
838					    nldr_node_obj->root;
839					break;
840
841				default:
842					DBC_ASSERT(false);
843					break;
844				}
845			}
846		}
847	} else {
848		if (nldr_node_obj->overlay)
849			status = load_ovly(nldr_node_obj, phase);
850
851	}
852
853	return status;
854}
855
856/*
857 *  ======== nldr_unload ========
858 */
859int nldr_unload(struct nldr_nodeobject *nldr_node_obj,
860		       enum nldr_phase phase)
861{
862	int status = 0;
863	struct lib_node *root_lib = NULL;
864	s32 i = 0;
865
866	DBC_REQUIRE(refs > 0);
867	DBC_REQUIRE(nldr_node_obj);
868
869	if (nldr_node_obj != NULL) {
870		if (nldr_node_obj->dynamic) {
871			if (*nldr_node_obj->phase_split) {
872				switch (phase) {
873				case NLDR_CREATE:
874					root_lib = &nldr_node_obj->create_lib;
875					break;
876				case NLDR_EXECUTE:
877					root_lib = &nldr_node_obj->execute_lib;
878					break;
879				case NLDR_DELETE:
880					root_lib = &nldr_node_obj->delete_lib;
881					/* Unload persistent libraries */
882					for (i = 0;
883					     i < nldr_node_obj->pers_libs;
884					     i++) {
885						unload_lib(nldr_node_obj,
886							   &nldr_node_obj->
887							   pers_lib_table[i]);
888					}
889					nldr_node_obj->pers_libs = 0;
890					break;
891				default:
892					DBC_ASSERT(false);
893					break;
894				}
895			} else {
896				/* Unload main library */
897				root_lib = &nldr_node_obj->root;
898			}
899			if (root_lib)
900				unload_lib(nldr_node_obj, root_lib);
901		} else {
902			if (nldr_node_obj->overlay)
903				unload_ovly(nldr_node_obj, phase);
904
905		}
906	}
907	return status;
908}
909
910/*
911 *  ======== add_ovly_info ========
912 */
913static int add_ovly_info(void *handle, struct dbll_sect_info *sect_info,
914				u32 addr, u32 bytes)
915{
916	char *node_name;
917	char *sect_name = (char *)sect_info->name;
918	bool sect_exists = false;
919	char seps = ':';
920	char *pch;
921	u16 i;
922	struct nldr_object *nldr_obj = (struct nldr_object *)handle;
923	int status = 0;
924
925	/* Is this an overlay section (load address != run address)? */
926	if (sect_info->sect_load_addr == sect_info->sect_run_addr)
927		goto func_end;
928
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) {
934			/* Found the node */
935			break;
936		}
937	}
938	if (!(i < nldr_obj->ovly_nodes))
939		goto func_end;
940
941	/* Determine which phase this section belongs to */
942	for (pch = sect_name + 1; *pch && *pch != seps; pch++)
943		;
944
945	if (*pch) {
946		pch++;		/* Skip over the ':' */
947		if (strncmp(pch, PCREATE, strlen(PCREATE)) == 0) {
948			status =
949			    add_ovly_sect(nldr_obj,
950					  &nldr_obj->
951					  ovly_table[i].create_sects_list,
952					  sect_info, &sect_exists, addr, bytes);
953			if (!status && !sect_exists)
954				nldr_obj->ovly_table[i].create_sects++;
955
956		} else if (strncmp(pch, PDELETE, strlen(PDELETE)) == 0) {
957			status =
958			    add_ovly_sect(nldr_obj,
959					  &nldr_obj->
960					  ovly_table[i].delete_sects_list,
961					  sect_info, &sect_exists, addr, bytes);
962			if (!status && !sect_exists)
963				nldr_obj->ovly_table[i].delete_sects++;
964
965		} else if (strncmp(pch, PEXECUTE, strlen(PEXECUTE)) == 0) {
966			status =
967			    add_ovly_sect(nldr_obj,
968					  &nldr_obj->
969					  ovly_table[i].execute_sects_list,
970					  sect_info, &sect_exists, addr, bytes);
971			if (!status && !sect_exists)
972				nldr_obj->ovly_table[i].execute_sects++;
973
974		} else {
975			/* Put in "other" sectins */
976			status =
977			    add_ovly_sect(nldr_obj,
978					  &nldr_obj->
979					  ovly_table[i].other_sects_list,
980					  sect_info, &sect_exists, addr, bytes);
981			if (!status && !sect_exists)
982				nldr_obj->ovly_table[i].other_sects++;
983
984		}
985	}
986func_end:
987	return status;
988}
989
990/*
991 *  ======== add_ovly_node =========
992 *  Callback function passed to dcd_get_objects.
993 */
994static int add_ovly_node(struct dsp_uuid *uuid_obj,
995				enum dsp_dcdobjtype obj_type, void *handle)
996{
997	struct nldr_object *nldr_obj = (struct nldr_object *)handle;
998	char *node_name = NULL;
999	char *pbuf = NULL;
1000	u32 len;
1001	struct dcd_genericobj obj_def;
1002	int status = 0;
1003
1004	if (obj_type != DSP_DCDNODETYPE)
1005		goto func_end;
1006
1007	status =
1008	    dcd_get_object_def(nldr_obj->dcd_mgr, uuid_obj, obj_type,
1009			       &obj_def);
1010	if (status)
1011		goto func_end;
1012
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++;
1017		} else {
1018			/* Add node to table */
1019			nldr_obj->ovly_table[nldr_obj->ovly_nid].uuid =
1020			    *uuid_obj;
1021			DBC_REQUIRE(obj_def.obj_data.node_obj.ndb_props.
1022				    ac_name);
1023			len =
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);
1027			if (pbuf == NULL) {
1028				status = -ENOMEM;
1029			} else {
1030				strncpy(pbuf, node_name, len);
1031				nldr_obj->ovly_table[nldr_obj->ovly_nid].
1032				    node_name = pbuf;
1033				nldr_obj->ovly_nid++;
1034			}
1035		}
1036	}
1037	/* These were allocated in dcd_get_object_def */
1038	kfree(obj_def.obj_data.node_obj.str_create_phase_fxn);
1039
1040	kfree(obj_def.obj_data.node_obj.str_execute_phase_fxn);
1041
1042	kfree(obj_def.obj_data.node_obj.str_delete_phase_fxn);
1043
1044	kfree(obj_def.obj_data.node_obj.str_i_alg_name);
1045
1046func_end:
1047	return status;
1048}
1049
1050/*
1051 *  ======== add_ovly_sect ========
1052 */
1053static 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)
1057{
1058	struct ovly_sect *new_sect = NULL;
1059	struct ovly_sect *last_sect;
1060	struct ovly_sect *ovly_section;
1061	int status = 0;
1062
1063	ovly_section = last_sect = *lst;
1064	*exists = false;
1065	while (ovly_section) {
1066		/*
1067		 *  Make sure section has not already been added. Multiple
1068		 *  'write' calls may be made to load the section.
1069		 */
1070		if (ovly_section->sect_load_addr == addr) {
1071			/* Already added */
1072			*exists = true;
1073			break;
1074		}
1075		last_sect = ovly_section;
1076		ovly_section = ovly_section->next_sect;
1077	}
1078
1079	if (!ovly_section) {
1080		/* New section */
1081		new_sect = kzalloc(sizeof(struct ovly_sect), GFP_KERNEL);
1082		if (new_sect == NULL) {
1083			status = -ENOMEM;
1084		} else {
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;
1090		}
1091
1092		/* Add to the list */
1093		if (!status) {
1094			if (*lst == NULL) {
1095				/* First in the list */
1096				*lst = new_sect;
1097			} else {
1098				last_sect->next_sect = new_sect;
1099			}
1100		}
1101	}
1102
1103	return status;
1104}
1105
1106/*
1107 *  ======== fake_ovly_write ========
1108 */
1109static s32 fake_ovly_write(void *handle, u32 dsp_address, void *buf, u32 bytes,
1110			   s32 mtype)
1111{
1112	return (s32) bytes;
1113}
1114
1115/*
1116 *  ======== free_sects ========
1117 */
1118static void free_sects(struct nldr_object *nldr_obj,
1119		       struct ovly_sect *phase_sects, u16 alloc_num)
1120{
1121	struct ovly_sect *ovly_section = phase_sects;
1122	u16 i = 0;
1123	bool ret;
1124
1125	while (ovly_section && i < alloc_num) {
1126		/* 'Deallocate' */
1127		/* segid - page not supported yet */
1128		/* Reserved memory */
1129		ret =
1130		    rmm_free(nldr_obj->rmm, 0, ovly_section->sect_run_addr,
1131			     ovly_section->size, true);
1132		DBC_ASSERT(ret);
1133		ovly_section = ovly_section->next_sect;
1134		i++;
1135	}
1136}
1137
1138/*
1139 *  ======== get_symbol_value ========
1140 *  Find symbol in library's base image.  If not there, check dependent
1141 *  libraries.
1142 */
1143static bool get_symbol_value(void *handle, void *parg, void *rmm_handle,
1144			     char *sym_name, struct dbll_sym_val **sym)
1145{
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;
1150	u16 i;
1151	bool status = false;
1152
1153	/* check the base image */
1154	status = nldr_obj->ldr_fxns.get_addr_fxn(nldr_obj->base_lib,
1155						 sym_name, sym);
1156	if (!status)
1157		status =
1158		    nldr_obj->ldr_fxns.get_c_addr_fxn(nldr_obj->base_lib,
1159							sym_name, sym);
1160
1161	/*
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.
1165	 */
1166	if (!status) {
1167		status = nldr_obj->ldr_fxns.get_addr_fxn(root->lib, sym_name,
1168							 sym);
1169		if (!status) {
1170			status =
1171			    nldr_obj->ldr_fxns.get_c_addr_fxn(root->lib,
1172							      sym_name, sym);
1173		}
1174	}
1175
1176	/*
1177	 *  Check in root lib's dependent libraries, but not dependent
1178	 *  libraries' dependents.
1179	 */
1180	if (!status) {
1181		for (i = 0; i < root->dep_libs; i++) {
1182			status =
1183			    nldr_obj->ldr_fxns.get_addr_fxn(root->
1184							    dep_libs_tree
1185							    [i].lib,
1186							    sym_name, sym);
1187			if (!status) {
1188				status =
1189				    nldr_obj->ldr_fxns.
1190				    get_c_addr_fxn(root->dep_libs_tree[i].lib,
1191						   sym_name, sym);
1192			}
1193			if (status) {
1194				/* Symbol found */
1195				break;
1196			}
1197		}
1198	}
1199	/*
1200	 * Check in persistent libraries
1201	 */
1202	if (!status) {
1203		for (i = 0; i < nldr_node_obj->pers_libs; i++) {
1204			status =
1205			    nldr_obj->ldr_fxns.
1206			    get_addr_fxn(nldr_node_obj->pers_lib_table[i].lib,
1207					 sym_name, sym);
1208			if (!status) {
1209				status = nldr_obj->ldr_fxns.get_c_addr_fxn
1210				    (nldr_node_obj->pers_lib_table[i].lib,
1211				     sym_name, sym);
1212			}
1213			if (status) {
1214				/* Symbol found */
1215				break;
1216			}
1217		}
1218	}
1219
1220	return status;
1221}
1222
1223/*
1224 *  ======== load_lib ========
1225 *  Recursively load library and all its dependent libraries. The library
1226 *  we're loading is specified by a uuid.
1227 */
1228static int load_lib(struct nldr_nodeobject *nldr_node_obj,
1229			   struct lib_node *root, struct dsp_uuid uuid,
1230			   bool root_prstnt,
1231			   struct dbll_library_obj **lib_path,
1232			   enum nldr_phase phase, u16 depth)
1233{
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 */
1238	u16 i;
1239	u32 entry;
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;
1246	int status = 0;
1247	bool lib_status = false;
1248	struct lib_node *dep_lib;
1249
1250	if (depth > MAXDEPTH) {
1251		/* Error */
1252		DBC_ASSERT(false);
1253	}
1254	root->lib = NULL;
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)
1258		status = -ENOMEM;
1259
1260	if (!status) {
1261		/* Get the name of the library */
1262		if (depth == 0) {
1263			status =
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);
1268		} else {
1269			/* Dependent libraries are registered with a phase */
1270			status =
1271			    dcd_get_library_name(nldr_node_obj->nldr_obj->
1272						 dcd_mgr, &uuid, psz_file_name,
1273						 &dw_buf_size, NLDR_NOPHASE,
1274						 NULL);
1275		}
1276	}
1277	if (!status) {
1278		/* Open the library, don't load symbols */
1279		status =
1280		    nldr_obj->ldr_fxns.open_fxn(nldr_obj->dbll, psz_file_name,
1281						DBLL_NOLOAD, &root->lib);
1282	}
1283	/* Done with file name */
1284	kfree(psz_file_name);
1285
1286	/* Check to see if library not already loaded */
1287	if (!status && root_prstnt) {
1288		lib_status =
1289		    find_in_persistent_lib_array(nldr_node_obj, root->lib);
1290		/* Close library */
1291		if (lib_status) {
1292			nldr_obj->ldr_fxns.close_fxn(root->lib);
1293			return 0;
1294		}
1295	}
1296	if (!status) {
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. */
1302				status = -EILSEQ;
1303			}
1304		}
1305	}
1306	if (!status) {
1307		/* Add library to current path in dependency tree */
1308		lib_path[depth] = root->lib;
1309		depth++;
1310		/* Get number of dependent libraries */
1311		status =
1312		    dcd_get_num_dep_libs(nldr_node_obj->nldr_obj->dcd_mgr,
1313					 &uuid, &nd_libs, &np_libs, phase);
1314	}
1315	DBC_ASSERT(nd_libs >= np_libs);
1316	if (!status) {
1317		if (!(*nldr_node_obj->phase_split))
1318			np_libs = 0;
1319
1320		/* nd_libs = #of dependent libraries */
1321		root->dep_libs = nd_libs - np_libs;
1322		if (nd_libs > 0) {
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)
1328				status = -ENOMEM;
1329
1330			if (root->dep_libs > 0) {
1331				/* Allocate arrays for dependent lib UUIDs,
1332				 * lib nodes */
1333				root->dep_libs_tree = kzalloc
1334						(sizeof(struct lib_node) *
1335						(root->dep_libs), GFP_KERNEL);
1336				if (!(root->dep_libs_tree))
1337					status = -ENOMEM;
1338
1339			}
1340
1341			if (!status) {
1342				/* Get the dependent library UUIDs */
1343				status =
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,
1348						     phase);
1349			}
1350		}
1351	}
1352
1353	/*
1354	 *  Recursively load dependent libraries.
1355	 */
1356	if (!status) {
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) {
1364					status = -EILSEQ;
1365					break;
1366				}
1367
1368				/* Allocate library outside of phase */
1369				dep_lib =
1370				    &nldr_node_obj->pers_lib_table
1371				    [nldr_node_obj->pers_libs];
1372			} else {
1373				if (root_prstnt)
1374					persistent_dep_libs[i] = true;
1375
1376				/* Allocate library within phase */
1377				dep_lib = &root->dep_libs_tree[nd_libs_loaded];
1378			}
1379
1380			status = load_lib(nldr_node_obj, dep_lib,
1381					  dep_lib_uui_ds[i],
1382					  persistent_dep_libs[i], lib_path,
1383					  phase, depth);
1384
1385			if (!status) {
1386				if ((status != 0) &&
1387				    !root_prstnt && persistent_dep_libs[i] &&
1388				    *nldr_node_obj->phase_split) {
1389					(nldr_node_obj->pers_libs)++;
1390				} else {
1391					if (!persistent_dep_libs[i] ||
1392					    !(*nldr_node_obj->phase_split)) {
1393						nd_libs_loaded++;
1394					}
1395				}
1396			} else {
1397				break;
1398			}
1399		}
1400	}
1401
1402	/* Now we can load the root library */
1403	if (!status) {
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;
1409
1410		status =
1411		    nldr_obj->ldr_fxns.load_fxn(root->lib, flags, &new_attrs,
1412						&entry);
1413	}
1414
1415	/*
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)
1419	 */
1420	if (status) {
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]);
1425
1426			nldr_node_obj->pers_libs = 0;
1427		}
1428		for (i = 0; i < nd_libs_loaded; i++)
1429			unload_lib(nldr_node_obj, &root->dep_libs_tree[i]);
1430
1431		if (root->lib)
1432			nldr_obj->ldr_fxns.close_fxn(root->lib);
1433
1434	}
1435
1436	/* Going up one node in the dependency tree */
1437	depth--;
1438
1439	kfree(dep_lib_uui_ds);
1440	dep_lib_uui_ds = NULL;
1441
1442	kfree(persistent_dep_libs);
1443	persistent_dep_libs = NULL;
1444
1445	return status;
1446}
1447
1448/*
1449 *  ======== load_ovly ========
1450 */
1451static int load_ovly(struct nldr_nodeobject *nldr_node_obj,
1452			    enum nldr_phase phase)
1453{
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;
1458	u16 i;
1459	u16 alloc_num = 0;
1460	u16 other_alloc = 0;
1461	u16 *ref_count = NULL;
1462	u16 *other_ref = NULL;
1463	u32 bytes;
1464	struct ovly_sect *ovly_section;
1465	int status = 0;
1466
1467	/* Find the node in the table */
1468	for (i = 0; i < nldr_obj->ovly_nodes; i++) {
1469		if (is_equal_uuid
1470		    (&nldr_node_obj->uuid, &nldr_obj->ovly_table[i].uuid)) {
1471			/* Found it */
1472			po_node = &(nldr_obj->ovly_table[i]);
1473			break;
1474		}
1475	}
1476
1477	DBC_ASSERT(i < nldr_obj->ovly_nodes);
1478
1479	if (!po_node) {
1480		status = -ENOENT;
1481		goto func_end;
1482	}
1483
1484	switch (phase) {
1485	case NLDR_CREATE:
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;
1490		break;
1491
1492	case NLDR_EXECUTE:
1493		ref_count = &(po_node->execute_ref);
1494		phase_sects = po_node->execute_sects_list;
1495		break;
1496
1497	case NLDR_DELETE:
1498		ref_count = &(po_node->delete_ref);
1499		phase_sects = po_node->delete_sects_list;
1500		break;
1501
1502	default:
1503		DBC_ASSERT(false);
1504		break;
1505	}
1506
1507	if (ref_count == NULL)
1508		goto func_end;
1509
1510	if (*ref_count != 0)
1511		goto func_end;
1512
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);
1520		if (!status) {
1521			ovly_section = ovly_section->next_sect;
1522			alloc_num++;
1523		} else {
1524			break;
1525		}
1526	}
1527	if (other_ref && *other_ref == 0) {
1528		/* 'Allocate' memory for other overlay sections
1529		 * (create phase) */
1530		if (!status) {
1531			ovly_section = other_sects_list;
1532			while (ovly_section) {
1533				/* page not supported *//* align */
1534				/* reserve */
1535				status =
1536				    rmm_alloc(nldr_obj->rmm, 0,
1537					      ovly_section->size, 0,
1538					      &(ovly_section->sect_run_addr),
1539					      true);
1540				if (!status) {
1541					ovly_section = ovly_section->next_sect;
1542					other_alloc++;
1543				} else {
1544					break;
1545				}
1546			}
1547		}
1548	}
1549	if (*ref_count == 0) {
1550		if (!status) {
1551			/* Load sections for this phase */
1552			ovly_section = phase_sects;
1553			while (ovly_section && !status) {
1554				bytes =
1555				    (*nldr_obj->ovly_fxn) (nldr_node_obj->
1556							   priv_ref,
1557							   ovly_section->
1558							   sect_run_addr,
1559							   ovly_section->
1560							   sect_load_addr,
1561							   ovly_section->size,
1562							   ovly_section->page);
1563				if (bytes != ovly_section->size)
1564					status = -EPERM;
1565
1566				ovly_section = ovly_section->next_sect;
1567			}
1568		}
1569	}
1570	if (other_ref && *other_ref == 0) {
1571		if (!status) {
1572			/* Load other sections (create phase) */
1573			ovly_section = other_sects_list;
1574			while (ovly_section && !status) {
1575				bytes =
1576				    (*nldr_obj->ovly_fxn) (nldr_node_obj->
1577							   priv_ref,
1578							   ovly_section->
1579							   sect_run_addr,
1580							   ovly_section->
1581							   sect_load_addr,
1582							   ovly_section->size,
1583							   ovly_section->page);
1584				if (bytes != ovly_section->size)
1585					status = -EPERM;
1586
1587				ovly_section = ovly_section->next_sect;
1588			}
1589		}
1590	}
1591	if (status) {
1592		/* 'Deallocate' memory */
1593		free_sects(nldr_obj, phase_sects, alloc_num);
1594		free_sects(nldr_obj, other_sects_list, other_alloc);
1595	}
1596func_end:
1597	if (!status && (ref_count != NULL)) {
1598		*ref_count += 1;
1599		if (other_ref)
1600			*other_ref += 1;
1601
1602	}
1603
1604	return status;
1605}
1606
1607/*
1608 *  ======== remote_alloc ========
1609 */
1610static int remote_alloc(void **ref, u16 mem_sect, u32 size,
1611			       u32 align, u32 *dsp_address,
1612			       s32 segmnt_id, s32 req,
1613			       bool reserve)
1614{
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;
1619	u16 segid = 0;
1620	u16 i;
1621	u16 mem_sect_type;
1622	u32 word_size;
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 */
1626	DBC_REQUIRE(hnode);
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 */
1632	word_size =
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;
1640		segid = segmnt_id;
1641		mem_load_req = req;
1642	} else {
1643		switch (hnode->phase) {
1644		case NLDR_CREATE:
1645			mem_phase_bit = CREATEDATAFLAGBIT;
1646			break;
1647		case NLDR_DELETE:
1648			mem_phase_bit = DELETEDATAFLAGBIT;
1649			break;
1650		case NLDR_EXECUTE:
1651			mem_phase_bit = EXECUTEDATAFLAGBIT;
1652			break;
1653		default:
1654			DBC_ASSERT(false);
1655			break;
1656		}
1657		if (mem_sect == DBLL_CODE)
1658			mem_phase_bit++;
1659
1660		if (mem_phase_bit < MAXFLAGS)
1661			segid = hnode->seg_id[mem_phase_bit];
1662
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;
1666
1667	}
1668	mem_sect_type = (mem_sect == DBLL_CODE) ? DYNM_CODE : DYNM_DATA;
1669
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);
1674		goto func_cont;
1675	}
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;
1680		status =
1681		    rmm_alloc(rmm, segid, word_size, align, dsp_address, false);
1682		if (status) {
1683			dev_dbg(bridge, "%s: Unable allocate from segment %d\n",
1684				__func__, segid);
1685		}
1686	} else {
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) !=
1695			    mem_sect_type)
1696				continue;
1697
1698			status = rmm_alloc(rmm, i, word_size, align,
1699					dsp_address, false);
1700			if (!status) {
1701				/* Save segid for freeing later */
1702				rmm_addr_obj->segid = i;
1703				break;
1704			}
1705		}
1706	}
1707func_cont:
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) !=
1715			    mem_sect_type)
1716				continue;
1717
1718			status = rmm_alloc(rmm, i, word_size, align,
1719					   dsp_address, false);
1720			if (!status) {
1721				/* Save segid */
1722				rmm_addr_obj->segid = i;
1723				break;
1724			}
1725		}
1726	}
1727
1728	return status;
1729}
1730
1731static int remote_free(void **ref, u16 space, u32 dsp_address,
1732			      u32 size, bool reserve)
1733{
1734	struct nldr_object *nldr_obj = (struct nldr_object *)ref;
1735	struct rmm_target_obj *rmm;
1736	u32 word_size;
1737	int status = -ENOMEM;	/* Set to fail */
1738
1739	DBC_REQUIRE(nldr_obj);
1740
1741	rmm = nldr_obj->rmm;
1742
1743	/* Convert size to DSP words */
1744	word_size =
1745	    (size + nldr_obj->dsp_word_size -
1746	     1) / nldr_obj->dsp_word_size;
1747
1748	if (rmm_free(rmm, space, dsp_address, word_size, reserve))
1749		status = 0;
1750
1751	return status;
1752}
1753
1754/*
1755 *  ======== unload_lib ========
1756 */
1757static void unload_lib(struct nldr_nodeobject *nldr_node_obj,
1758		       struct lib_node *root)
1759{
1760	struct dbll_attrs new_attrs;
1761	struct nldr_object *nldr_obj = nldr_node_obj->nldr_obj;
1762	u16 i;
1763
1764	DBC_ASSERT(root != NULL);
1765
1766	/* Unload dependent libraries */
1767	for (i = 0; i < root->dep_libs; i++)
1768		unload_lib(nldr_node_obj, &root->dep_libs_tree[i]);
1769
1770	root->dep_libs = 0;
1771
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;
1777
1778	if (root->lib) {
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);
1782	}
1783
1784	/* Free dependent library list */
1785	kfree(root->dep_libs_tree);
1786	root->dep_libs_tree = NULL;
1787}
1788
1789/*
1790 *  ======== unload_ovly ========
1791 */
1792static void unload_ovly(struct nldr_nodeobject *nldr_node_obj,
1793			enum nldr_phase phase)
1794{
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;
1799	u16 i;
1800	u16 alloc_num = 0;
1801	u16 other_alloc = 0;
1802	u16 *ref_count = NULL;
1803	u16 *other_ref = NULL;
1804
1805	/* Find the node in the table */
1806	for (i = 0; i < nldr_obj->ovly_nodes; i++) {
1807		if (is_equal_uuid
1808		    (&nldr_node_obj->uuid, &nldr_obj->ovly_table[i].uuid)) {
1809			/* Found it */
1810			po_node = &(nldr_obj->ovly_table[i]);
1811			break;
1812		}
1813	}
1814
1815	DBC_ASSERT(i < nldr_obj->ovly_nodes);
1816
1817	if (!po_node)
1818		/* TODO: Should we print warning here? */
1819		return;
1820
1821	switch (phase) {
1822	case NLDR_CREATE:
1823		ref_count = &(po_node->create_ref);
1824		phase_sects = po_node->create_sects_list;
1825		alloc_num = po_node->create_sects;
1826		break;
1827	case NLDR_EXECUTE:
1828		ref_count = &(po_node->execute_ref);
1829		phase_sects = po_node->execute_sects_list;
1830		alloc_num = po_node->execute_sects;
1831		break;
1832	case NLDR_DELETE:
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;
1840		break;
1841	default:
1842		DBC_ASSERT(false);
1843		break;
1844	}
1845	DBC_ASSERT(ref_count && (*ref_count > 0));
1846	if (ref_count && (*ref_count > 0)) {
1847		*ref_count -= 1;
1848		if (other_ref) {
1849			DBC_ASSERT(*other_ref > 0);
1850			*other_ref -= 1;
1851		}
1852	}
1853
1854	if (ref_count && *ref_count == 0) {
1855		/* 'Deallocate' memory */
1856		free_sects(nldr_obj, phase_sects, alloc_num);
1857	}
1858	if (other_ref && *other_ref == 0)
1859		free_sects(nldr_obj, other_sects_list, other_alloc);
1860}
1861
1862/*
1863 *  ======== find_in_persistent_lib_array ========
1864 */
1865static bool find_in_persistent_lib_array(struct nldr_nodeobject *nldr_node_obj,
1866					 struct dbll_library_obj *lib)
1867{
1868	s32 i = 0;
1869
1870	for (i = 0; i < nldr_node_obj->pers_libs; i++) {
1871		if (lib == nldr_node_obj->pers_lib_table[i].lib)
1872			return true;
1873
1874	}
1875
1876	return false;
1877}
1878
1879#ifdef CONFIG_TIDSPBRIDGE_BACKTRACE
1880/**
1881 * nldr_find_addr() - Find the closest symbol to the given address based on
1882 *		dynamic node object.
1883 *
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
1889 *
1890 * 	This function finds the node library for a given address and
1891 *	retrieves the dsp symbol by calling dbll_find_dsp_symbol.
1892 */
1893int nldr_find_addr(struct nldr_nodeobject *nldr_node, u32 sym_addr,
1894			u32 offset_range, void *offset_output, char *sym_name)
1895{
1896	int status = 0;
1897	bool status1 = false;
1898	s32 i = 0;
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);
1905
1906	if (nldr_node->dynamic && *nldr_node->phase_split) {
1907		switch (nldr_node->phase) {
1908		case NLDR_CREATE:
1909			root = nldr_node->create_lib;
1910			break;
1911		case NLDR_EXECUTE:
1912			root = nldr_node->execute_lib;
1913			break;
1914		case NLDR_DELETE:
1915			root = nldr_node->delete_lib;
1916			break;
1917		default:
1918			DBC_ASSERT(false);
1919			break;
1920		}
1921	} else {
1922		/* for Overlay nodes or non-split Dynamic nodes */
1923		root = nldr_node->root;
1924	}
1925
1926	status1 = dbll_find_dsp_symbol(root.lib, sym_addr,
1927			offset_range, offset_output, sym_name);
1928
1929	/* If symbol not found, check dependent libraries */
1930	if (!status1)
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);
1935			if (status1)
1936				/* Symbol found */
1937				break;
1938		}
1939	/* Check persistent libraries */
1940	if (!status1)
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);
1945			if (status1)
1946				/* Symbol found */
1947				break;
1948		}
1949
1950	if (!status1) {
1951		pr_debug("%s: Address 0x%x not found in range %d.\n",
1952					__func__, sym_addr, offset_range);
1953		status = -ESPIPE;
1954	}
1955
1956	return status;
1957}
1958#endif
1959