linux/drivers/staging/tidspbridge/rmgr/nldr.c
<<
>>
Prefs
   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
 124static inline bool is_equal_uuid(struct dsp_uuid *uuid1,
 125                                                        struct dsp_uuid *uuid2)
 126{
 127        return !memcmp(uuid1, uuid2, sizeof(struct dsp_uuid));
 128}
 129
 130    /*
 131     *  ======== mem_seg_info ========
 132     *  Format of dynamic loading memory segment info in coff file.
 133     *  Must match dynm.h55.
 134 */
 135struct 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 */
 146struct 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 */
 156struct 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 */
 169struct ovly_node {
 170        struct dsp_uuid uuid;
 171        char *node_name;
 172        struct ovly_sect *create_sects_list;
 173        struct ovly_sect *delete_sects_list;
 174        struct ovly_sect *execute_sects_list;
 175        struct ovly_sect *other_sects_list;
 176        u16 create_sects;
 177        u16 delete_sects;
 178        u16 execute_sects;
 179        u16 other_sects;
 180        u16 create_ref;
 181        u16 delete_ref;
 182        u16 execute_ref;
 183        u16 other_ref;
 184};
 185
 186/*
 187 *  ======== nldr_object ========
 188 *  Overlay loader object.
 189 */
 190struct 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 */
 215struct 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 */
 250static struct dbll_fxns ldr_fxns = {
 251        (dbll_close_fxn) dbll_close,
 252        (dbll_create_fxn) dbll_create,
 253        (dbll_delete_fxn) dbll_delete,
 254        (dbll_exit_fxn) dbll_exit,
 255        (dbll_get_attrs_fxn) dbll_get_attrs,
 256        (dbll_get_addr_fxn) dbll_get_addr,
 257        (dbll_get_c_addr_fxn) dbll_get_c_addr,
 258        (dbll_get_sect_fxn) dbll_get_sect,
 259        (dbll_init_fxn) dbll_init,
 260        (dbll_load_fxn) dbll_load,
 261        (dbll_open_fxn) dbll_open,
 262        (dbll_read_sect_fxn) dbll_read_sect,
 263        (dbll_unload_fxn) dbll_unload,
 264};
 265
 266static int add_ovly_info(void *handle, struct dbll_sect_info *sect_info,
 267                                u32 addr, u32 bytes);
 268static int add_ovly_node(struct dsp_uuid *uuid_obj,
 269                                enum dsp_dcdobjtype obj_type, void *handle);
 270static int add_ovly_sect(struct nldr_object *nldr_obj,
 271                                struct ovly_sect **lst,
 272                                struct dbll_sect_info *sect_inf,
 273                                bool *exists, u32 addr, u32 bytes);
 274static s32 fake_ovly_write(void *handle, u32 dsp_address, void *buf, u32 bytes,
 275                           s32 mtype);
 276static void free_sects(struct nldr_object *nldr_obj,
 277                       struct ovly_sect *phase_sects, u16 alloc_num);
 278static bool get_symbol_value(void *handle, void *parg, void *rmm_handle,
 279                             char *sym_name, struct dbll_sym_val **sym);
 280static int load_lib(struct nldr_nodeobject *nldr_node_obj,
 281                           struct lib_node *root, struct dsp_uuid uuid,
 282                           bool root_prstnt,
 283                           struct dbll_library_obj **lib_path,
 284                           enum nldr_phase phase, u16 depth);
 285static int load_ovly(struct nldr_nodeobject *nldr_node_obj,
 286                            enum nldr_phase phase);
 287static int remote_alloc(void **ref, u16 mem_sect, u32 size,
 288                               u32 align, u32 *dsp_address,
 289                               s32 segmnt_id,
 290                               s32 req, bool reserve);
 291static int remote_free(void **ref, u16 space, u32 dsp_address, u32 size,
 292                              bool reserve);
 293
 294static void unload_lib(struct nldr_nodeobject *nldr_node_obj,
 295                       struct lib_node *root);
 296static void unload_ovly(struct nldr_nodeobject *nldr_node_obj,
 297                        enum nldr_phase phase);
 298static bool find_in_persistent_lib_array(struct nldr_nodeobject *nldr_node_obj,
 299                                         struct dbll_library_obj *lib);
 300
 301/*
 302 *  ======== nldr_allocate ========
 303 */
 304int nldr_allocate(struct nldr_object *nldr_obj, void *priv_ref,
 305                         const struct dcd_nodeprops *node_props,
 306                         struct nldr_nodeobject **nldr_nodeobj,
 307                         bool *pf_phase_split)
 308{
 309        struct nldr_nodeobject *nldr_node_obj = NULL;
 310        int status = 0;
 311
 312        /* 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 */
 398int nldr_create(struct nldr_object **nldr,
 399                       struct dev_object *hdev_obj,
 400                       const struct nldr_attrs *pattrs)
 401{
 402        struct cod_manager *cod_mgr;    /* 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 */
 571void nldr_delete(struct nldr_object *nldr_obj)
 572{
 573        struct ovly_sect *ovly_section;
 574        struct ovly_sect *next;
 575        u16 i;
 576
 577        nldr_obj->ldr_fxns.exit_fxn();
 578        if (nldr_obj->rmm)
 579                rmm_delete(nldr_obj->rmm);
 580
 581        kfree(nldr_obj->seg_table);
 582
 583        if (nldr_obj->dcd_mgr)
 584                dcd_destroy_manager(nldr_obj->dcd_mgr);
 585
 586        /* 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 */
 625int nldr_get_fxn_addr(struct nldr_nodeobject *nldr_node_obj,
 626                             char *str_fxn, u32 * addr)
 627{
 628        struct dbll_sym_val *dbll_sym;
 629        struct nldr_object *nldr_obj;
 630        int status = 0;
 631        bool status1 = false;
 632        s32 i = 0;
 633        struct lib_node root = { NULL, 0, NULL };
 634
 635        nldr_obj = nldr_node_obj->nldr_obj;
 636        /* 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 */
 713int nldr_get_rmm_manager(struct nldr_object *nldr,
 714                                struct rmm_target_obj **rmm_mgr)
 715{
 716        int status = 0;
 717        struct nldr_object *nldr_obj = nldr;
 718
 719        if (nldr) {
 720                *rmm_mgr = nldr_obj->rmm;
 721        } else {
 722                *rmm_mgr = NULL;
 723                status = -EFAULT;
 724        }
 725
 726        return status;
 727}
 728
 729/*
 730 *  ======== nldr_load ========
 731 */
 732int nldr_load(struct nldr_nodeobject *nldr_node_obj,
 733                     enum nldr_phase phase)
 734{
 735        struct nldr_object *nldr_obj;
 736        struct dsp_uuid lib_uuid;
 737        int status = 0;
 738
 739        nldr_obj = nldr_node_obj->nldr_obj;
 740
 741        if (nldr_node_obj->dynamic) {
 742                nldr_node_obj->phase = phase;
 743
 744                lib_uuid = nldr_node_obj->uuid;
 745
 746                /* 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 */
 790int nldr_unload(struct nldr_nodeobject *nldr_node_obj,
 791                       enum nldr_phase phase)
 792{
 793        int status = 0;
 794        struct lib_node *root_lib = NULL;
 795        s32 i = 0;
 796
 797        if (nldr_node_obj != NULL) {
 798                if (nldr_node_obj->dynamic) {
 799                        if (*nldr_node_obj->phase_split) {
 800                                switch (phase) {
 801                                case NLDR_CREATE:
 802                                        root_lib = &nldr_node_obj->create_lib;
 803                                        break;
 804                                case NLDR_EXECUTE:
 805                                        root_lib = &nldr_node_obj->execute_lib;
 806                                        break;
 807                                case NLDR_DELETE:
 808                                        root_lib = &nldr_node_obj->delete_lib;
 809                                        /* 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 */
 840static int add_ovly_info(void *handle, struct dbll_sect_info *sect_info,
 841                                u32 addr, u32 bytes)
 842{
 843        char *node_name;
 844        char *sect_name = (char *)sect_info->name;
 845        bool sect_exists = false;
 846        char seps = ':';
 847        char *pch;
 848        u16 i;
 849        struct nldr_object *nldr_obj = (struct nldr_object *)handle;
 850        int status = 0;
 851
 852        /* 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" sections */
 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        }
 912func_end:
 913        return status;
 914}
 915
 916/*
 917 *  ======== add_ovly_node =========
 918 *  Callback function passed to dcd_get_objects.
 919 */
 920static int add_ovly_node(struct dsp_uuid *uuid_obj,
 921                                enum dsp_dcdobjtype obj_type, void *handle)
 922{
 923        struct nldr_object *nldr_obj = (struct nldr_object *)handle;
 924        char *node_name = NULL;
 925        char *pbuf = NULL;
 926        u32 len;
 927        struct dcd_genericobj obj_def;
 928        int status = 0;
 929
 930        if (obj_type != DSP_DCDNODETYPE)
 931                goto func_end;
 932
 933        status =
 934            dcd_get_object_def(nldr_obj->dcd_mgr, uuid_obj, obj_type,
 935                               &obj_def);
 936        if (status)
 937                goto func_end;
 938
 939        /* 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
 970func_end:
 971        return status;
 972}
 973
 974/*
 975 *  ======== add_ovly_sect ========
 976 */
 977static int add_ovly_sect(struct nldr_object *nldr_obj,
 978                                struct ovly_sect **lst,
 979                                struct dbll_sect_info *sect_inf,
 980                                bool *exists, u32 addr, u32 bytes)
 981{
 982        struct ovly_sect *new_sect = NULL;
 983        struct ovly_sect *last_sect;
 984        struct ovly_sect *ovly_section;
 985        int status = 0;
 986
 987        ovly_section = last_sect = *lst;
 988        *exists = false;
 989        while (ovly_section) {
 990                /*
 991                 *  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 */
1033static s32 fake_ovly_write(void *handle, u32 dsp_address, void *buf, u32 bytes,
1034                           s32 mtype)
1035{
1036        return (s32) bytes;
1037}
1038
1039/*
1040 *  ======== free_sects ========
1041 */
1042static void free_sects(struct nldr_object *nldr_obj,
1043                       struct ovly_sect *phase_sects, u16 alloc_num)
1044{
1045        struct ovly_sect *ovly_section = phase_sects;
1046        u16 i = 0;
1047        bool ret;
1048
1049        while (ovly_section && i < alloc_num) {
1050                /* '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 */
1066static bool get_symbol_value(void *handle, void *parg, void *rmm_handle,
1067                             char *sym_name, struct dbll_sym_val **sym)
1068{
1069        struct nldr_object *nldr_obj = (struct nldr_object *)handle;
1070        struct nldr_nodeobject *nldr_node_obj =
1071            (struct nldr_nodeobject *)rmm_handle;
1072        struct lib_node *root = (struct lib_node *)parg;
1073        u16 i;
1074        bool status = false;
1075
1076        /* 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 */
1151static int load_lib(struct nldr_nodeobject *nldr_node_obj,
1152                           struct lib_node *root, struct dsp_uuid uuid,
1153                           bool root_prstnt,
1154                           struct dbll_library_obj **lib_path,
1155                           enum nldr_phase phase, u16 depth)
1156{
1157        struct nldr_object *nldr_obj = nldr_node_obj->nldr_obj;
1158        u16 nd_libs = 0;        /* 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 */
1372static int load_ovly(struct nldr_nodeobject *nldr_node_obj,
1373                            enum nldr_phase phase)
1374{
1375        struct nldr_object *nldr_obj = nldr_node_obj->nldr_obj;
1376        struct ovly_node *po_node = NULL;
1377        struct ovly_sect *phase_sects = NULL;
1378        struct ovly_sect *other_sects_list = NULL;
1379        u16 i;
1380        u16 alloc_num = 0;
1381        u16 other_alloc = 0;
1382        u16 *ref_count = NULL;
1383        u16 *other_ref = NULL;
1384        u32 bytes;
1385        struct ovly_sect *ovly_section;
1386        int status = 0;
1387
1388        /* 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        }
1515func_end:
1516        if (!status && (ref_count != NULL)) {
1517                *ref_count += 1;
1518                if (other_ref)
1519                        *other_ref += 1;
1520
1521        }
1522
1523        return status;
1524}
1525
1526/*
1527 *  ======== remote_alloc ========
1528 */
1529static int remote_alloc(void **ref, u16 mem_sect, u32 size,
1530                               u32 align, u32 *dsp_address,
1531                               s32 segmnt_id, s32 req,
1532                               bool reserve)
1533{
1534        struct nldr_nodeobject *hnode = (struct nldr_nodeobject *)ref;
1535        struct nldr_object *nldr_obj;
1536        struct rmm_target_obj *rmm;
1537        u16 mem_phase_bit = MAXFLAGS;
1538        u16 segid = 0;
1539        u16 i;
1540        u16 mem_sect_type;
1541        u32 word_size;
1542        struct rmm_addr *rmm_addr_obj = (struct rmm_addr *)dsp_address;
1543        bool mem_load_req = false;
1544        int status = -ENOMEM;   /* 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        }
1619func_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
1643static int remote_free(void **ref, u16 space, u32 dsp_address,
1644                              u32 size, bool reserve)
1645{
1646        struct nldr_object *nldr_obj = (struct nldr_object *)ref;
1647        struct rmm_target_obj *rmm;
1648        u32 word_size;
1649        int status = -ENOMEM;   /* 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 */
1667static void unload_lib(struct nldr_nodeobject *nldr_node_obj,
1668                       struct lib_node *root)
1669{
1670        struct dbll_attrs new_attrs;
1671        struct nldr_object *nldr_obj = nldr_node_obj->nldr_obj;
1672        u16 i;
1673
1674
1675        /* 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 */
1701static void unload_ovly(struct nldr_nodeobject *nldr_node_obj,
1702                        enum nldr_phase phase)
1703{
1704        struct nldr_object *nldr_obj = nldr_node_obj->nldr_obj;
1705        struct ovly_node *po_node = NULL;
1706        struct ovly_sect *phase_sects = NULL;
1707        struct ovly_sect *other_sects_list = NULL;
1708        u16 i;
1709        u16 alloc_num = 0;
1710        u16 other_alloc = 0;
1711        u16 *ref_count = NULL;
1712        u16 *other_ref = NULL;
1713
1714        /* 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 */
1770static bool find_in_persistent_lib_array(struct nldr_nodeobject *nldr_node_obj,
1771                                         struct dbll_library_obj *lib)
1772{
1773        s32 i = 0;
1774
1775        for (i = 0; i < nldr_node_obj->pers_libs; i++) {
1776                if (lib == nldr_node_obj->pers_lib_table[i].lib)
1777                        return true;
1778
1779        }
1780
1781        return false;
1782}
1783
1784#ifdef CONFIG_TIDSPBRIDGE_BACKTRACE
1785/**
1786 * 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 */
1798int nldr_find_addr(struct nldr_nodeobject *nldr_node, u32 sym_addr,
1799                        u32 offset_range, void *offset_output, char *sym_name)
1800{
1801        int status = 0;
1802        bool status1 = false;
1803        s32 i = 0;
1804        struct lib_node root = { NULL, 0, NULL };
1805
1806        if (nldr_node->dynamic && *nldr_node->phase_split) {
1807                switch (nldr_node->phase) {
1808                case NLDR_CREATE:
1809                        root = nldr_node->create_lib;
1810                        break;
1811                case NLDR_EXECUTE:
1812                        root = nldr_node->execute_lib;
1813                        break;
1814                case NLDR_DELETE:
1815                        root = nldr_node->delete_lib;
1816                        break;
1817                default:
1818                        break;
1819                }
1820        } else {
1821                /* for Overlay nodes or non-split Dynamic nodes */
1822                root = nldr_node->root;
1823        }
1824
1825        status1 = dbll_find_dsp_symbol(root.lib, sym_addr,
1826                        offset_range, offset_output, sym_name);
1827
1828        /* If symbol not found, check dependent libraries */
1829        if (!status1)
1830                for (i = 0; i < root.dep_libs; i++) {
1831                        status1 = dbll_find_dsp_symbol(
1832                                root.dep_libs_tree[i].lib, sym_addr,
1833                                offset_range, offset_output, sym_name);
1834                        if (status1)
1835                                /* Symbol found */
1836                                break;
1837                }
1838        /* Check persistent libraries */
1839        if (!status1)
1840                for (i = 0; i < nldr_node->pers_libs; i++) {
1841                        status1 = dbll_find_dsp_symbol(
1842                                nldr_node->pers_lib_table[i].lib, sym_addr,
1843                                offset_range, offset_output, sym_name);
1844                        if (status1)
1845                                /* Symbol found */
1846                                break;
1847                }
1848
1849        if (!status1) {
1850                pr_debug("%s: Address 0x%x not found in range %d.\n",
1851                                        __func__, sym_addr, offset_range);
1852                status = -ESPIPE;
1853        } else {
1854                pr_debug("%s(0x%x, 0x%x, 0x%x, 0x%x,  %s)\n",
1855                         __func__, (u32) nldr_node, sym_addr, offset_range,
1856                         (u32) offset_output, sym_name);
1857        }
1858
1859        return status;
1860}
1861#endif
1862