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