]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - drivers/staging/tidspbridge/pmgr/dbll.c
Staging: tidspbridge: Use hashtable implementation
[karo-tx-linux.git] / drivers / staging / tidspbridge / pmgr / dbll.c
1 /*
2  * dbll.c
3  *
4  * DSP-BIOS Bridge driver support functions for TI OMAP processors.
5  *
6  * Copyright (C) 2005-2006 Texas Instruments, Inc.
7  *
8  * This package is free software;  you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 as
10  * published by the Free Software Foundation.
11  *
12  * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
13  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
14  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
15  */
16 #include <linux/types.h>
17
18 /*  ----------------------------------- Host OS */
19 #include <dspbridge/host_os.h>
20
21 /*  ----------------------------------- DSP/BIOS Bridge */
22 #include <dspbridge/dbdefs.h>
23
24 #include <dspbridge/gh.h>
25
26 /*  ----------------------------------- OS Adaptation Layer */
27
28 /* Dynamic loader library interface */
29 #include <dspbridge/dynamic_loader.h>
30 #include <dspbridge/getsection.h>
31
32 /*  ----------------------------------- This */
33 #include <dspbridge/dbll.h>
34 #include <dspbridge/rmm.h>
35
36 /* Max buffer length */
37 #define MAXEXPR 128
38
39 #define DOFF_ALIGN(x) (((x) + 3) & ~3UL)
40
41 /*
42  *  ======== struct dbll_tar_obj* ========
43  *  A target may have one or more libraries of symbols/code/data loaded
44  *  onto it, where a library is simply the symbols/code/data contained
45  *  in a DOFF file.
46  */
47 /*
48  *  ======== dbll_tar_obj ========
49  */
50 struct dbll_tar_obj {
51         struct dbll_attrs attrs;
52         struct dbll_library_obj *head;  /* List of all opened libraries */
53 };
54
55 /*
56  *  The following 4 typedefs are "super classes" of the dynamic loader
57  *  library types used in dynamic loader functions (dynamic_loader.h).
58  */
59 /*
60  *  ======== dbll_stream ========
61  *  Contains dynamic_loader_stream
62  */
63 struct dbll_stream {
64         struct dynamic_loader_stream dl_stream;
65         struct dbll_library_obj *lib;
66 };
67
68 /*
69  *  ======== ldr_symbol ========
70  */
71 struct ldr_symbol {
72         struct dynamic_loader_sym dl_symbol;
73         struct dbll_library_obj *lib;
74 };
75
76 /*
77  *  ======== dbll_alloc ========
78  */
79 struct dbll_alloc {
80         struct dynamic_loader_allocate dl_alloc;
81         struct dbll_library_obj *lib;
82 };
83
84 /*
85  *  ======== dbll_init_obj ========
86  */
87 struct dbll_init_obj {
88         struct dynamic_loader_initialize dl_init;
89         struct dbll_library_obj *lib;
90 };
91
92 /*
93  *  ======== DBLL_Library ========
94  *  A library handle is returned by DBLL_Open() and is passed to dbll_load()
95  *  to load symbols/code/data, and to dbll_unload(), to remove the
96  *  symbols/code/data loaded by dbll_load().
97  */
98
99 /*
100  *  ======== dbll_library_obj ========
101  */
102 struct dbll_library_obj {
103         struct dbll_library_obj *next;  /* Next library in target's list */
104         struct dbll_library_obj *prev;  /* Previous in the list */
105         struct dbll_tar_obj *target_obj;        /* target for this library */
106
107         /* Objects needed by dynamic loader */
108         struct dbll_stream stream;
109         struct ldr_symbol symbol;
110         struct dbll_alloc allocate;
111         struct dbll_init_obj init;
112         void *dload_mod_obj;
113
114         char *file_name;        /* COFF file name */
115         void *fp;               /* Opaque file handle */
116         u32 entry;              /* Entry point */
117         void *desc;     /* desc of DOFF file loaded */
118         u32 open_ref;           /* Number of times opened */
119         u32 load_ref;           /* Number of times loaded */
120         struct gh_t_hash_tab *sym_tab;  /* Hash table of symbols */
121         u32 pos;
122 };
123
124 /*
125  *  ======== dbll_symbol ========
126  */
127 struct dbll_symbol {
128         struct dbll_sym_val value;
129         char *name;
130 };
131
132 static void dof_close(struct dbll_library_obj *zl_lib);
133 static int dof_open(struct dbll_library_obj *zl_lib);
134 static s32 no_op(struct dynamic_loader_initialize *thisptr, void *bufr,
135                  ldr_addr locn, struct ldr_section_info *info,
136                  unsigned bytsize);
137
138 /*
139  *  Functions called by dynamic loader
140  *
141  */
142 /* dynamic_loader_stream */
143 static int dbll_read_buffer(struct dynamic_loader_stream *this, void *buffer,
144                             unsigned bufsize);
145 static int dbll_set_file_posn(struct dynamic_loader_stream *this,
146                               unsigned int pos);
147 /* dynamic_loader_sym */
148 static struct dynload_symbol *dbll_find_symbol(struct dynamic_loader_sym *this,
149                                                const char *name);
150 static struct dynload_symbol *dbll_add_to_symbol_table(struct dynamic_loader_sym
151                                                        *this, const char *name,
152                                                        unsigned module_id);
153 static struct dynload_symbol *find_in_symbol_table(struct dynamic_loader_sym
154                                                    *this, const char *name,
155                                                    unsigned moduleid);
156 static void dbll_purge_symbol_table(struct dynamic_loader_sym *this,
157                                     unsigned module_id);
158 static void *allocate(struct dynamic_loader_sym *this, unsigned memsize);
159 static void deallocate(struct dynamic_loader_sym *this, void *mem_ptr);
160 static void dbll_err_report(struct dynamic_loader_sym *this, const char *errstr,
161                             va_list args);
162 /* dynamic_loader_allocate */
163 static int dbll_rmm_alloc(struct dynamic_loader_allocate *this,
164                           struct ldr_section_info *info, unsigned align);
165 static void rmm_dealloc(struct dynamic_loader_allocate *this,
166                         struct ldr_section_info *info);
167
168 /* dynamic_loader_initialize */
169 static int connect(struct dynamic_loader_initialize *this);
170 static int read_mem(struct dynamic_loader_initialize *this, void *buf,
171                     ldr_addr addr, struct ldr_section_info *info,
172                     unsigned bytes);
173 static int write_mem(struct dynamic_loader_initialize *this, void *buf,
174                      ldr_addr addr, struct ldr_section_info *info,
175                      unsigned nbytes);
176 static int fill_mem(struct dynamic_loader_initialize *this, ldr_addr addr,
177                     struct ldr_section_info *info, unsigned bytes,
178                     unsigned val);
179 static int execute(struct dynamic_loader_initialize *this, ldr_addr start);
180 static void release(struct dynamic_loader_initialize *this);
181
182 /* symbol table hash functions */
183 static u32 name_hash(const void *key);
184 static bool name_match(const void *key, const void *sp);
185 static void sym_delete(void *value);
186
187 /* Symbol Redefinition */
188 static int redefined_symbol;
189 static int gbl_search = 1;
190
191 /*
192  *  ======== dbll_close ========
193  */
194 void dbll_close(struct dbll_library_obj *zl_lib)
195 {
196         struct dbll_tar_obj *zl_target;
197
198         zl_target = zl_lib->target_obj;
199         zl_lib->open_ref--;
200         if (zl_lib->open_ref == 0) {
201                 /* Remove library from list */
202                 if (zl_target->head == zl_lib)
203                         zl_target->head = zl_lib->next;
204
205                 if (zl_lib->prev)
206                         (zl_lib->prev)->next = zl_lib->next;
207
208                 if (zl_lib->next)
209                         (zl_lib->next)->prev = zl_lib->prev;
210
211                 /* Free DOF resources */
212                 dof_close(zl_lib);
213                 kfree(zl_lib->file_name);
214
215                 /* remove symbols from symbol table */
216                 if (zl_lib->sym_tab)
217                         gh_delete(zl_lib->sym_tab);
218
219                 /* remove the library object itself */
220                 kfree(zl_lib);
221                 zl_lib = NULL;
222         }
223 }
224
225 /*
226  *  ======== dbll_create ========
227  */
228 int dbll_create(struct dbll_tar_obj **target_obj,
229                        struct dbll_attrs *pattrs)
230 {
231         struct dbll_tar_obj *pzl_target;
232         int status = 0;
233
234         /* Allocate DBL target object */
235         pzl_target = kzalloc(sizeof(struct dbll_tar_obj), GFP_KERNEL);
236         if (target_obj != NULL) {
237                 if (pzl_target == NULL) {
238                         *target_obj = NULL;
239                         status = -ENOMEM;
240                 } else {
241                         pzl_target->attrs = *pattrs;
242                         *target_obj = (struct dbll_tar_obj *)pzl_target;
243                 }
244         }
245
246         return status;
247 }
248
249 /*
250  *  ======== dbll_delete ========
251  */
252 void dbll_delete(struct dbll_tar_obj *target)
253 {
254         struct dbll_tar_obj *zl_target = (struct dbll_tar_obj *)target;
255
256         kfree(zl_target);
257
258 }
259
260 /*
261  *  ======== dbll_exit ========
262  *  Discontinue usage of DBL module.
263  */
264 void dbll_exit(void)
265 {
266         /* do nothing */
267 }
268
269 /*
270  *  ======== dbll_get_addr ========
271  *  Get address of name in the specified library.
272  */
273 bool dbll_get_addr(struct dbll_library_obj *zl_lib, char *name,
274                    struct dbll_sym_val **sym_val)
275 {
276         struct dbll_symbol *sym;
277
278         sym = (struct dbll_symbol *)gh_find(zl_lib->sym_tab, name);
279         if (IS_ERR(sym))
280                 return false;
281
282         *sym_val = &sym->value;
283
284         dev_dbg(bridge, "%s: lib: %p name: %s paddr: %p\n",
285                 __func__, zl_lib, name, sym_val);
286         return true;
287 }
288
289 /*
290  *  ======== dbll_get_attrs ========
291  *  Retrieve the attributes of the target.
292  */
293 void dbll_get_attrs(struct dbll_tar_obj *target, struct dbll_attrs *pattrs)
294 {
295         struct dbll_tar_obj *zl_target = (struct dbll_tar_obj *)target;
296
297         if ((pattrs != NULL) && (zl_target != NULL))
298                 *pattrs = zl_target->attrs;
299
300 }
301
302 /*
303  *  ======== dbll_get_c_addr ========
304  *  Get address of a "C" name in the specified library.
305  */
306 bool dbll_get_c_addr(struct dbll_library_obj *zl_lib, char *name,
307                      struct dbll_sym_val **sym_val)
308 {
309         struct dbll_symbol *sym;
310         char cname[MAXEXPR + 1];
311
312         cname[0] = '_';
313
314         strncpy(cname + 1, name, sizeof(cname) - 2);
315         cname[MAXEXPR] = '\0';  /* insure '\0' string termination */
316
317         /* Check for C name, if not found */
318         sym = (struct dbll_symbol *)gh_find(zl_lib->sym_tab, cname);
319         if (IS_ERR(sym))
320                 return false;
321
322         *sym_val = &sym->value;
323
324         return true;
325 }
326
327 /*
328  *  ======== dbll_get_sect ========
329  *  Get the base address and size (in bytes) of a COFF section.
330  */
331 int dbll_get_sect(struct dbll_library_obj *lib, char *name, u32 *paddr,
332                          u32 *psize)
333 {
334         u32 byte_size;
335         bool opened_doff = false;
336         const struct ldr_section_info *sect = NULL;
337         struct dbll_library_obj *zl_lib = (struct dbll_library_obj *)lib;
338         int status = 0;
339
340         /* If DOFF file is not open, we open it. */
341         if (zl_lib != NULL) {
342                 if (zl_lib->fp == NULL) {
343                         status = dof_open(zl_lib);
344                         if (!status)
345                                 opened_doff = true;
346
347                 } else {
348                         (*(zl_lib->target_obj->attrs.fseek)) (zl_lib->fp,
349                                                               zl_lib->pos,
350                                                               SEEK_SET);
351                 }
352         } else {
353                 status = -EFAULT;
354         }
355         if (!status) {
356                 byte_size = 1;
357                 if (dload_get_section_info(zl_lib->desc, name, &sect)) {
358                         *paddr = sect->load_addr;
359                         *psize = sect->size * byte_size;
360                         /* Make sure size is even for good swap */
361                         if (*psize % 2)
362                                 (*psize)++;
363
364                         /* Align size */
365                         *psize = DOFF_ALIGN(*psize);
366                 } else {
367                         status = -ENXIO;
368                 }
369         }
370         if (opened_doff) {
371                 dof_close(zl_lib);
372                 opened_doff = false;
373         }
374
375         dev_dbg(bridge, "%s: lib: %p name: %s paddr: %p psize: %p, status 0x%x\n",
376                         __func__, lib, name, paddr, psize, status);
377
378         return status;
379 }
380
381 /*
382  *  ======== dbll_init ========
383  */
384 bool dbll_init(void)
385 {
386         /* do nothing */
387
388         return true;
389 }
390
391 /*
392  *  ======== dbll_load ========
393  */
394 int dbll_load(struct dbll_library_obj *lib, dbll_flags flags,
395                      struct dbll_attrs *attrs, u32 *entry)
396 {
397         struct dbll_library_obj *zl_lib = (struct dbll_library_obj *)lib;
398         struct dbll_tar_obj *dbzl;
399         bool got_symbols = true;
400         s32 err;
401         int status = 0;
402         bool opened_doff = false;
403
404         /*
405          *  Load if not already loaded.
406          */
407         if (zl_lib->load_ref == 0 || !(flags & DBLL_DYNAMIC)) {
408                 dbzl = zl_lib->target_obj;
409                 dbzl->attrs = *attrs;
410                 /* Create a hash table for symbols if not already created */
411                 if (zl_lib->sym_tab == NULL) {
412                         got_symbols = false;
413                         zl_lib->sym_tab = gh_create(sizeof(struct dbll_symbol),
414                                                     name_hash,
415                                                     name_match, sym_delete);
416                         if (IS_ERR(zl_lib->sym_tab)) {
417                                 status = PTR_ERR(zl_lib->sym_tab);
418                                 zl_lib->sym_tab = NULL;
419                         }
420
421                 }
422                 /*
423                  *  Set up objects needed by the dynamic loader
424                  */
425                 /* Stream */
426                 zl_lib->stream.dl_stream.read_buffer = dbll_read_buffer;
427                 zl_lib->stream.dl_stream.set_file_posn = dbll_set_file_posn;
428                 zl_lib->stream.lib = zl_lib;
429                 /* Symbol */
430                 zl_lib->symbol.dl_symbol.find_matching_symbol =
431                     dbll_find_symbol;
432                 if (got_symbols) {
433                         zl_lib->symbol.dl_symbol.add_to_symbol_table =
434                             find_in_symbol_table;
435                 } else {
436                         zl_lib->symbol.dl_symbol.add_to_symbol_table =
437                             dbll_add_to_symbol_table;
438                 }
439                 zl_lib->symbol.dl_symbol.purge_symbol_table =
440                     dbll_purge_symbol_table;
441                 zl_lib->symbol.dl_symbol.dload_allocate = allocate;
442                 zl_lib->symbol.dl_symbol.dload_deallocate = deallocate;
443                 zl_lib->symbol.dl_symbol.error_report = dbll_err_report;
444                 zl_lib->symbol.lib = zl_lib;
445                 /* Allocate */
446                 zl_lib->allocate.dl_alloc.dload_allocate = dbll_rmm_alloc;
447                 zl_lib->allocate.dl_alloc.dload_deallocate = rmm_dealloc;
448                 zl_lib->allocate.lib = zl_lib;
449                 /* Init */
450                 zl_lib->init.dl_init.connect = connect;
451                 zl_lib->init.dl_init.readmem = read_mem;
452                 zl_lib->init.dl_init.writemem = write_mem;
453                 zl_lib->init.dl_init.fillmem = fill_mem;
454                 zl_lib->init.dl_init.execute = execute;
455                 zl_lib->init.dl_init.release = release;
456                 zl_lib->init.lib = zl_lib;
457                 /* If COFF file is not open, we open it. */
458                 if (zl_lib->fp == NULL) {
459                         status = dof_open(zl_lib);
460                         if (!status)
461                                 opened_doff = true;
462
463                 }
464                 if (!status) {
465                         zl_lib->pos = (*(zl_lib->target_obj->attrs.ftell))
466                             (zl_lib->fp);
467                         /* Reset file cursor */
468                         (*(zl_lib->target_obj->attrs.fseek)) (zl_lib->fp,
469                                                               (long)0,
470                                                               SEEK_SET);
471                         symbols_reloaded = true;
472                         /* The 5th argument, DLOAD_INITBSS, tells the DLL
473                          * module to zero-init all BSS sections.  In general,
474                          * this is not necessary and also increases load time.
475                          * We may want to make this configurable by the user */
476                         err = dynamic_load_module(&zl_lib->stream.dl_stream,
477                                                   &zl_lib->symbol.dl_symbol,
478                                                   &zl_lib->allocate.dl_alloc,
479                                                   &zl_lib->init.dl_init,
480                                                   DLOAD_INITBSS,
481                                                   &zl_lib->dload_mod_obj);
482
483                         if (err != 0) {
484                                 status = -EILSEQ;
485                         } else if (redefined_symbol) {
486                                 zl_lib->load_ref++;
487                                 dbll_unload(zl_lib, (struct dbll_attrs *)attrs);
488                                 redefined_symbol = false;
489                                 status = -EILSEQ;
490                         } else {
491                                 *entry = zl_lib->entry;
492                         }
493                 }
494         }
495         if (!status)
496                 zl_lib->load_ref++;
497
498         /* Clean up DOFF resources */
499         if (opened_doff)
500                 dof_close(zl_lib);
501
502         dev_dbg(bridge, "%s: lib: %p flags: 0x%x entry: %p, status 0x%x\n",
503                 __func__, lib, flags, entry, status);
504
505         return status;
506 }
507
508 /*
509  *  ======== dbll_open ========
510  */
511 int dbll_open(struct dbll_tar_obj *target, char *file, dbll_flags flags,
512                      struct dbll_library_obj **lib_obj)
513 {
514         struct dbll_tar_obj *zl_target = (struct dbll_tar_obj *)target;
515         struct dbll_library_obj *zl_lib = NULL;
516         s32 err;
517         int status = 0;
518
519         zl_lib = zl_target->head;
520         while (zl_lib != NULL) {
521                 if (strcmp(zl_lib->file_name, file) == 0) {
522                         /* Library is already opened */
523                         zl_lib->open_ref++;
524                         break;
525                 }
526                 zl_lib = zl_lib->next;
527         }
528         if (zl_lib == NULL) {
529                 /* Allocate DBL library object */
530                 zl_lib = kzalloc(sizeof(struct dbll_library_obj), GFP_KERNEL);
531                 if (zl_lib == NULL) {
532                         status = -ENOMEM;
533                 } else {
534                         zl_lib->pos = 0;
535                         /* Increment ref count to allow close on failure
536                          * later on */
537                         zl_lib->open_ref++;
538                         zl_lib->target_obj = zl_target;
539                         /* Keep a copy of the file name */
540                         zl_lib->file_name = kzalloc(strlen(file) + 1,
541                                                         GFP_KERNEL);
542                         if (zl_lib->file_name == NULL) {
543                                 status = -ENOMEM;
544                         } else {
545                                 strncpy(zl_lib->file_name, file,
546                                         strlen(file) + 1);
547                         }
548                         zl_lib->sym_tab = NULL;
549                 }
550         }
551         /*
552          *  Set up objects needed by the dynamic loader
553          */
554         if (status)
555                 goto func_cont;
556
557         /* Stream */
558         zl_lib->stream.dl_stream.read_buffer = dbll_read_buffer;
559         zl_lib->stream.dl_stream.set_file_posn = dbll_set_file_posn;
560         zl_lib->stream.lib = zl_lib;
561         /* Symbol */
562         zl_lib->symbol.dl_symbol.add_to_symbol_table = dbll_add_to_symbol_table;
563         zl_lib->symbol.dl_symbol.find_matching_symbol = dbll_find_symbol;
564         zl_lib->symbol.dl_symbol.purge_symbol_table = dbll_purge_symbol_table;
565         zl_lib->symbol.dl_symbol.dload_allocate = allocate;
566         zl_lib->symbol.dl_symbol.dload_deallocate = deallocate;
567         zl_lib->symbol.dl_symbol.error_report = dbll_err_report;
568         zl_lib->symbol.lib = zl_lib;
569         /* Allocate */
570         zl_lib->allocate.dl_alloc.dload_allocate = dbll_rmm_alloc;
571         zl_lib->allocate.dl_alloc.dload_deallocate = rmm_dealloc;
572         zl_lib->allocate.lib = zl_lib;
573         /* Init */
574         zl_lib->init.dl_init.connect = connect;
575         zl_lib->init.dl_init.readmem = read_mem;
576         zl_lib->init.dl_init.writemem = write_mem;
577         zl_lib->init.dl_init.fillmem = fill_mem;
578         zl_lib->init.dl_init.execute = execute;
579         zl_lib->init.dl_init.release = release;
580         zl_lib->init.lib = zl_lib;
581         if (!status && zl_lib->fp == NULL)
582                 status = dof_open(zl_lib);
583
584         zl_lib->pos = (*(zl_lib->target_obj->attrs.ftell)) (zl_lib->fp);
585         (*(zl_lib->target_obj->attrs.fseek)) (zl_lib->fp, (long)0, SEEK_SET);
586         /* Create a hash table for symbols if flag is set */
587         if (zl_lib->sym_tab != NULL || !(flags & DBLL_SYMB))
588                 goto func_cont;
589
590         zl_lib->sym_tab =
591             gh_create(sizeof(struct dbll_symbol), name_hash, name_match,
592                       sym_delete);
593         if (IS_ERR(zl_lib->sym_tab)) {
594                 status = PTR_ERR(zl_lib->sym_tab);
595                 zl_lib->sym_tab = NULL;
596         } else {
597                 /* Do a fake load to get symbols - set write func to no_op */
598                 zl_lib->init.dl_init.writemem = no_op;
599                 err = dynamic_open_module(&zl_lib->stream.dl_stream,
600                                           &zl_lib->symbol.dl_symbol,
601                                           &zl_lib->allocate.dl_alloc,
602                                           &zl_lib->init.dl_init, 0,
603                                           &zl_lib->dload_mod_obj);
604                 if (err != 0) {
605                         status = -EILSEQ;
606                 } else {
607                         /* Now that we have the symbol table, we can unload */
608                         err = dynamic_unload_module(zl_lib->dload_mod_obj,
609                                                     &zl_lib->symbol.dl_symbol,
610                                                     &zl_lib->allocate.dl_alloc,
611                                                     &zl_lib->init.dl_init);
612                         if (err != 0)
613                                 status = -EILSEQ;
614
615                         zl_lib->dload_mod_obj = NULL;
616                 }
617         }
618 func_cont:
619         if (!status) {
620                 if (zl_lib->open_ref == 1) {
621                         /* First time opened - insert in list */
622                         if (zl_target->head)
623                                 (zl_target->head)->prev = zl_lib;
624
625                         zl_lib->prev = NULL;
626                         zl_lib->next = zl_target->head;
627                         zl_target->head = zl_lib;
628                 }
629                 *lib_obj = (struct dbll_library_obj *)zl_lib;
630         } else {
631                 *lib_obj = NULL;
632                 if (zl_lib != NULL)
633                         dbll_close((struct dbll_library_obj *)zl_lib);
634
635         }
636
637         dev_dbg(bridge, "%s: target: %p file: %s lib_obj: %p, status 0x%x\n",
638                 __func__, target, file, lib_obj, status);
639
640         return status;
641 }
642
643 /*
644  *  ======== dbll_read_sect ========
645  *  Get the content of a COFF section.
646  */
647 int dbll_read_sect(struct dbll_library_obj *lib, char *name,
648                           char *buf, u32 size)
649 {
650         struct dbll_library_obj *zl_lib = (struct dbll_library_obj *)lib;
651         bool opened_doff = false;
652         u32 byte_size;          /* size of bytes */
653         u32 ul_sect_size;       /* size of section */
654         const struct ldr_section_info *sect = NULL;
655         int status = 0;
656
657         /* If DOFF file is not open, we open it. */
658         if (zl_lib != NULL) {
659                 if (zl_lib->fp == NULL) {
660                         status = dof_open(zl_lib);
661                         if (!status)
662                                 opened_doff = true;
663
664                 } else {
665                         (*(zl_lib->target_obj->attrs.fseek)) (zl_lib->fp,
666                                                               zl_lib->pos,
667                                                               SEEK_SET);
668                 }
669         } else {
670                 status = -EFAULT;
671         }
672         if (status)
673                 goto func_cont;
674
675         byte_size = 1;
676         if (!dload_get_section_info(zl_lib->desc, name, &sect)) {
677                 status = -ENXIO;
678                 goto func_cont;
679         }
680         /*
681          * Ensure the supplied buffer size is sufficient to store
682          * the section buf to be read.
683          */
684         ul_sect_size = sect->size * byte_size;
685         /* Make sure size is even for good swap */
686         if (ul_sect_size % 2)
687                 ul_sect_size++;
688
689         /* Align size */
690         ul_sect_size = DOFF_ALIGN(ul_sect_size);
691         if (ul_sect_size > size) {
692                 status = -EPERM;
693         } else {
694                 if (!dload_get_section(zl_lib->desc, sect, buf))
695                         status = -EBADF;
696
697         }
698 func_cont:
699         if (opened_doff) {
700                 dof_close(zl_lib);
701                 opened_doff = false;
702         }
703
704         dev_dbg(bridge, "%s: lib: %p name: %s buf: %p size: 0x%x, status 0x%x\n",
705                         __func__, lib, name, buf, size, status);
706         return status;
707 }
708
709 /*
710  *  ======== dbll_unload ========
711  */
712 void dbll_unload(struct dbll_library_obj *lib, struct dbll_attrs *attrs)
713 {
714         struct dbll_library_obj *zl_lib = (struct dbll_library_obj *)lib;
715         s32 err = 0;
716
717         dev_dbg(bridge, "%s: lib: %p\n", __func__, lib);
718         zl_lib->load_ref--;
719         /* Unload only if reference count is 0 */
720         if (zl_lib->load_ref != 0)
721                 return;
722
723         zl_lib->target_obj->attrs = *attrs;
724         if (zl_lib->dload_mod_obj) {
725                 err = dynamic_unload_module(zl_lib->dload_mod_obj,
726                                             &zl_lib->symbol.dl_symbol,
727                                             &zl_lib->allocate.dl_alloc,
728                                             &zl_lib->init.dl_init);
729                 if (err != 0)
730                         dev_dbg(bridge, "%s: failed: 0x%x\n", __func__, err);
731         }
732         /* remove symbols from symbol table */
733         if (zl_lib->sym_tab != NULL) {
734                 gh_delete(zl_lib->sym_tab);
735                 zl_lib->sym_tab = NULL;
736         }
737         /* delete DOFF desc since it holds *lots* of host OS
738          * resources */
739         dof_close(zl_lib);
740 }
741
742 /*
743  *  ======== dof_close ========
744  */
745 static void dof_close(struct dbll_library_obj *zl_lib)
746 {
747         if (zl_lib->desc) {
748                 dload_module_close(zl_lib->desc);
749                 zl_lib->desc = NULL;
750         }
751         /* close file */
752         if (zl_lib->fp) {
753                 (zl_lib->target_obj->attrs.fclose) (zl_lib->fp);
754                 zl_lib->fp = NULL;
755         }
756 }
757
758 /*
759  *  ======== dof_open ========
760  */
761 static int dof_open(struct dbll_library_obj *zl_lib)
762 {
763         void *open = *(zl_lib->target_obj->attrs.fopen);
764         int status = 0;
765
766         /* First open the file for the dynamic loader, then open COF */
767         zl_lib->fp =
768             (void *)((dbll_f_open_fxn) (open)) (zl_lib->file_name, "rb");
769
770         /* Open DOFF module */
771         if (zl_lib->fp && zl_lib->desc == NULL) {
772                 (*(zl_lib->target_obj->attrs.fseek)) (zl_lib->fp, (long)0,
773                                                       SEEK_SET);
774                 zl_lib->desc =
775                     dload_module_open(&zl_lib->stream.dl_stream,
776                                       &zl_lib->symbol.dl_symbol);
777                 if (zl_lib->desc == NULL) {
778                         (zl_lib->target_obj->attrs.fclose) (zl_lib->fp);
779                         zl_lib->fp = NULL;
780                         status = -EBADF;
781                 }
782         } else {
783                 status = -EBADF;
784         }
785
786         return status;
787 }
788
789 /*
790  *  ======== name_hash ========
791  */
792 static u32 name_hash(const void *key)
793 {
794         u32 hash;
795         const char *name = key;
796
797         hash = 0;
798
799         while (*name) {
800                 hash <<= 1;
801                 hash ^= *name++;
802         }
803
804         return hash;
805 }
806
807 /*
808  *  ======== name_match ========
809  */
810 static bool name_match(const void *key, const void *sp)
811 {
812         if ((key != NULL) && (sp != NULL)) {
813                 if (strcmp(key, ((struct dbll_symbol *)sp)->name) == 0)
814                         return true;
815         }
816         return false;
817 }
818
819 /*
820  *  ======== no_op ========
821  */
822 static int no_op(struct dynamic_loader_initialize *thisptr, void *bufr,
823                  ldr_addr locn, struct ldr_section_info *info, unsigned bytsize)
824 {
825         return 1;
826 }
827
828 /*
829  *  ======== sym_delete ========
830  */
831 static void sym_delete(void *value)
832 {
833         struct dbll_symbol *sp = (struct dbll_symbol *)value;
834
835         kfree(sp->name);
836 }
837
838 /*
839  *  Dynamic Loader Functions
840  */
841
842 /* dynamic_loader_stream */
843 /*
844  *  ======== dbll_read_buffer ========
845  */
846 static int dbll_read_buffer(struct dynamic_loader_stream *this, void *buffer,
847                             unsigned bufsize)
848 {
849         struct dbll_stream *pstream = (struct dbll_stream *)this;
850         struct dbll_library_obj *lib;
851         int bytes_read = 0;
852
853         lib = pstream->lib;
854         if (lib != NULL) {
855                 bytes_read =
856                     (*(lib->target_obj->attrs.fread)) (buffer, 1, bufsize,
857                                                        lib->fp);
858         }
859         return bytes_read;
860 }
861
862 /*
863  *  ======== dbll_set_file_posn ========
864  */
865 static int dbll_set_file_posn(struct dynamic_loader_stream *this,
866                               unsigned int pos)
867 {
868         struct dbll_stream *pstream = (struct dbll_stream *)this;
869         struct dbll_library_obj *lib;
870         int status = 0;         /* Success */
871
872         lib = pstream->lib;
873         if (lib != NULL) {
874                 status = (*(lib->target_obj->attrs.fseek)) (lib->fp, (long)pos,
875                                                             SEEK_SET);
876         }
877
878         return status;
879 }
880
881 /* dynamic_loader_sym */
882
883 /*
884  *  ======== dbll_find_symbol ========
885  */
886 static struct dynload_symbol *dbll_find_symbol(struct dynamic_loader_sym *this,
887                                                const char *name)
888 {
889         struct dynload_symbol *ret_sym;
890         struct ldr_symbol *ldr_sym = (struct ldr_symbol *)this;
891         struct dbll_library_obj *lib;
892         struct dbll_sym_val *dbll_sym = NULL;
893         bool status = false;    /* Symbol not found yet */
894
895         lib = ldr_sym->lib;
896         if (lib != NULL) {
897                 if (lib->target_obj->attrs.sym_lookup) {
898                         /* Check current lib + base lib + dep lib +
899                          * persistent lib */
900                         status = (*(lib->target_obj->attrs.sym_lookup))
901                             (lib->target_obj->attrs.sym_handle,
902                              lib->target_obj->attrs.sym_arg,
903                              lib->target_obj->attrs.rmm_handle, name,
904                              &dbll_sym);
905                 } else {
906                         /* Just check current lib for symbol */
907                         status = dbll_get_addr((struct dbll_library_obj *)lib,
908                                                (char *)name, &dbll_sym);
909                         if (!status) {
910                                 status = dbll_get_c_addr(
911                                                 (struct dbll_library_obj *)
912                                                 lib, (char *)name,
913                                                 &dbll_sym);
914                         }
915                 }
916         }
917
918         if (!status && gbl_search)
919                 dev_dbg(bridge, "%s: Symbol not found: %s\n", __func__, name);
920
921         ret_sym = (struct dynload_symbol *)dbll_sym;
922         return ret_sym;
923 }
924
925 /*
926  *  ======== find_in_symbol_table ========
927  */
928 static struct dynload_symbol *find_in_symbol_table(struct dynamic_loader_sym
929                                                    *this, const char *name,
930                                                    unsigned moduleid)
931 {
932         struct ldr_symbol *ldr_sym = (struct ldr_symbol *)this;
933         struct dbll_library_obj *lib;
934         struct dbll_symbol *sym;
935
936         lib = ldr_sym->lib;
937         sym = (struct dbll_symbol *)gh_find(lib->sym_tab, (char *)name);
938
939         if (IS_ERR(sym))
940                 return NULL;
941
942         return (struct dynload_symbol *)&sym->value;
943 }
944
945 /*
946  *  ======== dbll_add_to_symbol_table ========
947  */
948 static struct dynload_symbol *dbll_add_to_symbol_table(struct dynamic_loader_sym
949                                                        *this, const char *name,
950                                                        unsigned module_id)
951 {
952         struct dbll_symbol *sym_ptr = NULL;
953         struct dbll_symbol symbol;
954         struct dynload_symbol *dbll_sym = NULL;
955         struct ldr_symbol *ldr_sym = (struct ldr_symbol *)this;
956         struct dbll_library_obj *lib;
957         struct dynload_symbol *ret;
958
959         lib = ldr_sym->lib;
960
961         /* Check to see if symbol is already defined in symbol table */
962         if (!(lib->target_obj->attrs.base_image)) {
963                 gbl_search = false;
964                 dbll_sym = dbll_find_symbol(this, name);
965                 gbl_search = true;
966                 if (dbll_sym) {
967                         redefined_symbol = true;
968                         dev_dbg(bridge, "%s already defined in symbol table\n",
969                                 name);
970                         return NULL;
971                 }
972         }
973         /* Allocate string to copy symbol name */
974         symbol.name = kzalloc(strlen((char *const)name) + 1, GFP_KERNEL);
975         if (symbol.name == NULL)
976                 return NULL;
977
978         if (symbol.name != NULL) {
979                 /* Just copy name (value will be filled in by dynamic loader) */
980                 strncpy(symbol.name, (char *const)name,
981                         strlen((char *const)name) + 1);
982
983                 /* Add symbol to symbol table */
984                 sym_ptr =
985                     (struct dbll_symbol *)gh_insert(lib->sym_tab, (void *)name,
986                                                     (void *)&symbol);
987                 if (IS_ERR(sym_ptr)) {
988                         kfree(symbol.name);
989                         sym_ptr = NULL;
990                 }
991
992         }
993         if (sym_ptr != NULL)
994                 ret = (struct dynload_symbol *)&sym_ptr->value;
995         else
996                 ret = NULL;
997
998         return ret;
999 }
1000
1001 /*
1002  *  ======== dbll_purge_symbol_table ========
1003  */
1004 static void dbll_purge_symbol_table(struct dynamic_loader_sym *this,
1005                                     unsigned module_id)
1006 {
1007         struct ldr_symbol *ldr_sym = (struct ldr_symbol *)this;
1008         struct dbll_library_obj *lib;
1009
1010         lib = ldr_sym->lib;
1011         /* May not need to do anything */
1012 }
1013
1014 /*
1015  *  ======== allocate ========
1016  */
1017 static void *allocate(struct dynamic_loader_sym *this, unsigned memsize)
1018 {
1019         struct ldr_symbol *ldr_sym = (struct ldr_symbol *)this;
1020         struct dbll_library_obj *lib;
1021         void *buf;
1022
1023         lib = ldr_sym->lib;
1024
1025         buf = kzalloc(memsize, GFP_KERNEL);
1026
1027         return buf;
1028 }
1029
1030 /*
1031  *  ======== deallocate ========
1032  */
1033 static void deallocate(struct dynamic_loader_sym *this, void *mem_ptr)
1034 {
1035         struct ldr_symbol *ldr_sym = (struct ldr_symbol *)this;
1036         struct dbll_library_obj *lib;
1037
1038         lib = ldr_sym->lib;
1039
1040         kfree(mem_ptr);
1041 }
1042
1043 /*
1044  *  ======== dbll_err_report ========
1045  */
1046 static void dbll_err_report(struct dynamic_loader_sym *this, const char *errstr,
1047                             va_list args)
1048 {
1049         struct ldr_symbol *ldr_sym = (struct ldr_symbol *)this;
1050         struct dbll_library_obj *lib;
1051         char temp_buf[MAXEXPR];
1052
1053         lib = ldr_sym->lib;
1054         vsnprintf((char *)temp_buf, MAXEXPR, (char *)errstr, args);
1055         dev_dbg(bridge, "%s\n", temp_buf);
1056 }
1057
1058 /* dynamic_loader_allocate */
1059
1060 /*
1061  *  ======== dbll_rmm_alloc ========
1062  */
1063 static int dbll_rmm_alloc(struct dynamic_loader_allocate *this,
1064                           struct ldr_section_info *info, unsigned align)
1065 {
1066         struct dbll_alloc *dbll_alloc_obj = (struct dbll_alloc *)this;
1067         struct dbll_library_obj *lib;
1068         int status = 0;
1069         u32 mem_sect_type;
1070         struct rmm_addr rmm_addr_obj;
1071         s32 ret = true;
1072         unsigned stype = DLOAD_SECTION_TYPE(info->type);
1073         char *token = NULL;
1074         char *sz_sec_last_token = NULL;
1075         char *sz_last_token = NULL;
1076         char *sz_sect_name = NULL;
1077         char *psz_cur;
1078         s32 token_len = 0;
1079         s32 seg_id = -1;
1080         s32 req = -1;
1081         s32 count = 0;
1082         u32 alloc_size = 0;
1083         u32 run_addr_flag = 0;
1084
1085         lib = dbll_alloc_obj->lib;
1086
1087         mem_sect_type =
1088             (stype == DLOAD_TEXT) ? DBLL_CODE : (stype ==
1089                                                  DLOAD_BSS) ? DBLL_BSS :
1090             DBLL_DATA;
1091
1092         /* Attempt to extract the segment ID and requirement information from
1093            the name of the section */
1094         token_len = strlen((char *)(info->name)) + 1;
1095
1096         sz_sect_name = kzalloc(token_len, GFP_KERNEL);
1097         sz_last_token = kzalloc(token_len, GFP_KERNEL);
1098         sz_sec_last_token = kzalloc(token_len, GFP_KERNEL);
1099
1100         if (sz_sect_name == NULL || sz_sec_last_token == NULL ||
1101             sz_last_token == NULL) {
1102                 status = -ENOMEM;
1103                 goto func_cont;
1104         }
1105         strncpy(sz_sect_name, (char *)(info->name), token_len);
1106         psz_cur = sz_sect_name;
1107         while ((token = strsep(&psz_cur, ":")) && *token != '\0') {
1108                 strncpy(sz_sec_last_token, sz_last_token,
1109                         strlen(sz_last_token) + 1);
1110                 strncpy(sz_last_token, token, strlen(token) + 1);
1111                 token = strsep(&psz_cur, ":");
1112                 count++;        /* optimizes processing */
1113         }
1114         /* If token is 0 or 1, and sz_sec_last_token is DYN_DARAM or DYN_SARAM,
1115            or DYN_EXTERNAL, then mem granularity information is present
1116            within the section name - only process if there are at least three
1117            tokens within the section name (just a minor optimization) */
1118         if (count >= 3) {
1119                 status = kstrtos32(sz_last_token, 10, &req);
1120                 if (status)
1121                         goto func_cont;
1122         }
1123
1124         if ((req == 0) || (req == 1)) {
1125                 if (strcmp(sz_sec_last_token, "DYN_DARAM") == 0) {
1126                         seg_id = 0;
1127                 } else {
1128                         if (strcmp(sz_sec_last_token, "DYN_SARAM") == 0) {
1129                                 seg_id = 1;
1130                         } else {
1131                                 if (strcmp(sz_sec_last_token,
1132                                            "DYN_EXTERNAL") == 0)
1133                                         seg_id = 2;
1134                         }
1135                 }
1136         }
1137 func_cont:
1138         kfree(sz_sect_name);
1139         sz_sect_name = NULL;
1140         kfree(sz_last_token);
1141         sz_last_token = NULL;
1142         kfree(sz_sec_last_token);
1143         sz_sec_last_token = NULL;
1144
1145         if (mem_sect_type == DBLL_CODE)
1146                 alloc_size = info->size + GEM_L1P_PREFETCH_SIZE;
1147         else
1148                 alloc_size = info->size;
1149
1150         if (info->load_addr != info->run_addr)
1151                 run_addr_flag = 1;
1152         /* TODO - ideally, we can pass the alignment requirement also
1153          * from here */
1154         if (lib != NULL) {
1155                 status =
1156                     (lib->target_obj->attrs.alloc) (lib->target_obj->attrs.
1157                                                     rmm_handle, mem_sect_type,
1158                                                     alloc_size, align,
1159                                                     (u32 *) &rmm_addr_obj,
1160                                                     seg_id, req, false);
1161         }
1162         if (status) {
1163                 ret = false;
1164         } else {
1165                 /* RMM gives word address. Need to convert to byte address */
1166                 info->load_addr = rmm_addr_obj.addr * DSPWORDSIZE;
1167                 if (!run_addr_flag)
1168                         info->run_addr = info->load_addr;
1169                 info->context = (u32) rmm_addr_obj.segid;
1170                 dev_dbg(bridge, "%s: %s base = 0x%x len = 0x%x, info->run_addr 0x%x, info->load_addr 0x%x\n",
1171                         __func__, info->name, info->load_addr / DSPWORDSIZE,
1172                         info->size / DSPWORDSIZE, info->run_addr,
1173                         info->load_addr);
1174         }
1175         return ret;
1176 }
1177
1178 /*
1179  *  ======== rmm_dealloc ========
1180  */
1181 static void rmm_dealloc(struct dynamic_loader_allocate *this,
1182                         struct ldr_section_info *info)
1183 {
1184         struct dbll_alloc *dbll_alloc_obj = (struct dbll_alloc *)this;
1185         struct dbll_library_obj *lib;
1186         u32 segid;
1187         int status = 0;
1188         unsigned stype = DLOAD_SECTION_TYPE(info->type);
1189         u32 mem_sect_type;
1190         u32 free_size = 0;
1191
1192         mem_sect_type =
1193             (stype == DLOAD_TEXT) ? DBLL_CODE : (stype ==
1194                                                  DLOAD_BSS) ? DBLL_BSS :
1195             DBLL_DATA;
1196         lib = dbll_alloc_obj->lib;
1197         /* segid was set by alloc function */
1198         segid = (u32) info->context;
1199         if (mem_sect_type == DBLL_CODE)
1200                 free_size = info->size + GEM_L1P_PREFETCH_SIZE;
1201         else
1202                 free_size = info->size;
1203         if (lib != NULL) {
1204                 status =
1205                     (lib->target_obj->attrs.free) (lib->target_obj->attrs.
1206                                                    sym_handle, segid,
1207                                                    info->load_addr /
1208                                                    DSPWORDSIZE, free_size,
1209                                                    false);
1210         }
1211 }
1212
1213 /* dynamic_loader_initialize */
1214 /*
1215  *  ======== connect ========
1216  */
1217 static int connect(struct dynamic_loader_initialize *this)
1218 {
1219         return true;
1220 }
1221
1222 /*
1223  *  ======== read_mem ========
1224  *  This function does not need to be implemented.
1225  */
1226 static int read_mem(struct dynamic_loader_initialize *this, void *buf,
1227                     ldr_addr addr, struct ldr_section_info *info,
1228                     unsigned nbytes)
1229 {
1230         struct dbll_init_obj *init_obj = (struct dbll_init_obj *)this;
1231         struct dbll_library_obj *lib;
1232         int bytes_read = 0;
1233
1234         lib = init_obj->lib;
1235         /* Need bridge_brd_read function */
1236         return bytes_read;
1237 }
1238
1239 /*
1240  *  ======== write_mem ========
1241  */
1242 static int write_mem(struct dynamic_loader_initialize *this, void *buf,
1243                      ldr_addr addr, struct ldr_section_info *info,
1244                      unsigned bytes)
1245 {
1246         struct dbll_init_obj *init_obj = (struct dbll_init_obj *)this;
1247         struct dbll_library_obj *lib;
1248         struct dbll_tar_obj *target_obj;
1249         struct dbll_sect_info sect_info;
1250         u32 mem_sect_type;
1251         bool ret = true;
1252
1253         lib = init_obj->lib;
1254         if (!lib)
1255                 return false;
1256
1257         target_obj = lib->target_obj;
1258
1259         mem_sect_type =
1260             (DLOAD_SECTION_TYPE(info->type) ==
1261              DLOAD_TEXT) ? DBLL_CODE : DBLL_DATA;
1262         if (target_obj && target_obj->attrs.write) {
1263                 ret =
1264                     (*target_obj->attrs.write) (target_obj->attrs.input_params,
1265                                                 addr, buf, bytes,
1266                                                 mem_sect_type);
1267
1268                 if (target_obj->attrs.log_write) {
1269                         sect_info.name = info->name;
1270                         sect_info.sect_run_addr = info->run_addr;
1271                         sect_info.sect_load_addr = info->load_addr;
1272                         sect_info.size = info->size;
1273                         sect_info.type = mem_sect_type;
1274                         /* Pass the information about what we've written to
1275                          * another module */
1276                         (*target_obj->attrs.log_write) (target_obj->attrs.
1277                                                         log_write_handle,
1278                                                         &sect_info, addr,
1279                                                         bytes);
1280                 }
1281         }
1282         return ret;
1283 }
1284
1285 /*
1286  *  ======== fill_mem ========
1287  *  Fill bytes of memory at a given address with a given value by
1288  *  writing from a buffer containing the given value.  Write in
1289  *  sets of MAXEXPR (128) bytes to avoid large stack buffer issues.
1290  */
1291 static int fill_mem(struct dynamic_loader_initialize *this, ldr_addr addr,
1292                     struct ldr_section_info *info, unsigned bytes, unsigned val)
1293 {
1294         bool ret = true;
1295         char *pbuf;
1296         struct dbll_library_obj *lib;
1297         struct dbll_init_obj *init_obj = (struct dbll_init_obj *)this;
1298
1299         lib = init_obj->lib;
1300         pbuf = NULL;
1301         /* Pass the NULL pointer to write_mem to get the start address of Shared
1302            memory. This is a trick to just get the start address, there is no
1303            writing taking place with this Writemem
1304          */
1305         if ((lib->target_obj->attrs.write) != (dbll_write_fxn) no_op)
1306                 write_mem(this, &pbuf, addr, info, 0);
1307         if (pbuf)
1308                 memset(pbuf, val, bytes);
1309
1310         return ret;
1311 }
1312
1313 /*
1314  *  ======== execute ========
1315  */
1316 static int execute(struct dynamic_loader_initialize *this, ldr_addr start)
1317 {
1318         struct dbll_init_obj *init_obj = (struct dbll_init_obj *)this;
1319         struct dbll_library_obj *lib;
1320         bool ret = true;
1321
1322         lib = init_obj->lib;
1323         /* Save entry point */
1324         if (lib != NULL)
1325                 lib->entry = (u32) start;
1326
1327         return ret;
1328 }
1329
1330 /*
1331  *  ======== release ========
1332  */
1333 static void release(struct dynamic_loader_initialize *this)
1334 {
1335 }
1336
1337 #ifdef CONFIG_TIDSPBRIDGE_BACKTRACE
1338 /**
1339  *  find_symbol_context - Basic symbol context structure
1340  * @address:            Symbol Address
1341  * @offset_range:               Offset range where the search for the DSP symbol
1342  *                      started.
1343  * @cur_best_offset:    Best offset to start looking for the DSP symbol
1344  * @sym_addr:           Address of the DSP symbol
1345  * @name:               Symbol name
1346  *
1347  */
1348 struct find_symbol_context {
1349         /* input */
1350         u32 address;
1351         u32 offset_range;
1352         /* state */
1353         u32 cur_best_offset;
1354         /* output */
1355         u32 sym_addr;
1356         char name[120];
1357 };
1358
1359 /**
1360  * find_symbol_callback() - Validates symbol address and copies the symbol name
1361  *                      to the user data.
1362  * @elem:               dsp library context
1363  * @user_data:          Find symbol context
1364  *
1365  */
1366 void find_symbol_callback(void *elem, void *user_data)
1367 {
1368         struct dbll_symbol *symbol = elem;
1369         struct find_symbol_context *context = user_data;
1370         u32 symbol_addr = symbol->value.value;
1371         u32 offset = context->address - symbol_addr;
1372
1373         /*
1374          * Address given should be greater than symbol address,
1375          * symbol address should be  within specified range
1376          * and the offset should be better than previous one
1377          */
1378         if (context->address >= symbol_addr && symbol_addr < (u32)-1 &&
1379                 offset < context->cur_best_offset) {
1380                 context->cur_best_offset = offset;
1381                 context->sym_addr = symbol_addr;
1382                 strlcpy(context->name, symbol->name, sizeof(context->name));
1383         }
1384
1385         return;
1386 }
1387
1388 /**
1389  * dbll_find_dsp_symbol() - This function retrieves the dsp symbol from the dsp binary.
1390  * @zl_lib:             DSP binary obj library pointer
1391  * @address:            Given address to find the dsp symbol
1392  * @offset_range:               offset range to look for dsp symbol
1393  * @sym_addr_output:    Symbol Output address
1394  * @name_output:                String with the dsp symbol
1395  *
1396  *      This function retrieves the dsp symbol from the dsp binary.
1397  */
1398 bool dbll_find_dsp_symbol(struct dbll_library_obj *zl_lib, u32 address,
1399                                 u32 offset_range, u32 *sym_addr_output,
1400                                 char *name_output)
1401 {
1402         bool status = false;
1403         struct find_symbol_context context;
1404
1405         context.address = address;
1406         context.offset_range = offset_range;
1407         context.cur_best_offset = offset_range;
1408         context.sym_addr = 0;
1409         context.name[0] = '\0';
1410
1411         gh_iterate(zl_lib->sym_tab, find_symbol_callback, &context);
1412
1413         if (context.name[0]) {
1414                 status = true;
1415                 strcpy(name_output, context.name);
1416                 *sym_addr_output = context.sym_addr;
1417         }
1418
1419         return status;
1420 }
1421 #endif