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