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