1 /*
2 * dbdcd.c
3 *
4 * DSP-BIOS Bridge driver support functions for TI OMAP processors.
5 *
6 * This file contains the implementation of the DSP/BIOS Bridge
7 * Configuration Database (DCD).
8 *
9 * Notes:
10 * The fxn dcd_get_objects can apply a callback fxn to each DCD object
11 * that is located in a specified COFF file. At the moment,
12 * dcd_auto_register, dcd_auto_unregister, and NLDR module all use
13 * dcd_get_objects.
14 *
15 * Copyright (C) 2005-2006 Texas Instruments, Inc.
16 *
17 * This package is free software; you can redistribute it and/or modify
18 * it under the terms of the GNU General Public License version 2 as
19 * published by the Free Software Foundation.
20 *
21 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
23 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
24 */
25 #include <linux/types.h>
26
27 /* ----------------------------------- Host OS */
28 #include <dspbridge/host_os.h>
29
30 /* ----------------------------------- DSP/BIOS Bridge */
31 #include <dspbridge/dbdefs.h>
32
33 /* ----------------------------------- Platform Manager */
34 #include <dspbridge/cod.h>
35
36 /* ----------------------------------- Others */
37 #include <dspbridge/uuidutil.h>
38
39 /* ----------------------------------- This */
40 #include <dspbridge/dbdcd.h>
41
42 /* ----------------------------------- Global defines. */
43 #define MAX_INT2CHAR_LENGTH 16 /* Max int2char len of 32 bit int */
44
45 /* Name of section containing dependent libraries */
46 #define DEPLIBSECT ".dspbridge_deplibs"
47
48 /* DCD specific structures. */
49 struct dcd_manager {
50 struct cod_manager *cod_mgr; /* Handle to COD manager object. */
51 };
52
53 /* Pointer to the registry support key */
54 static struct list_head reg_key_list;
55 static DEFINE_SPINLOCK(dbdcd_lock);
56
57 /* Global reference variables. */
58 static u32 refs;
59 static u32 enum_refs;
60
61 /* Helper function prototypes. */
62 static s32 atoi(char *psz_buf);
63 static int get_attrs_from_buf(char *psz_buf, u32 ul_buf_size,
64 enum dsp_dcdobjtype obj_type,
65 struct dcd_genericobj *gen_obj);
66 static void compress_buf(char *psz_buf, u32 ul_buf_size, s32 char_size);
67 static char dsp_char2_gpp_char(char *word, s32 dsp_char_size);
68 static int get_dep_lib_info(struct dcd_manager *hdcd_mgr,
69 struct dsp_uuid *uuid_obj,
70 u16 *num_libs,
71 u16 *num_pers_libs,
72 struct dsp_uuid *dep_lib_uuids,
73 bool *prstnt_dep_libs,
74 enum nldr_phase phase);
75
76 /*
77 * ======== dcd_auto_register ========
78 * Purpose:
79 * Parses the supplied image and resigsters with DCD.
80 */
dcd_auto_register(struct dcd_manager * hdcd_mgr,char * sz_coff_path)81 int dcd_auto_register(struct dcd_manager *hdcd_mgr,
82 char *sz_coff_path)
83 {
84 int status = 0;
85
86 if (hdcd_mgr)
87 status = dcd_get_objects(hdcd_mgr, sz_coff_path,
88 (dcd_registerfxn) dcd_register_object,
89 (void *)sz_coff_path);
90 else
91 status = -EFAULT;
92
93 return status;
94 }
95
96 /*
97 * ======== dcd_auto_unregister ========
98 * Purpose:
99 * Parses the supplied DSP image and unresiters from DCD.
100 */
dcd_auto_unregister(struct dcd_manager * hdcd_mgr,char * sz_coff_path)101 int dcd_auto_unregister(struct dcd_manager *hdcd_mgr,
102 char *sz_coff_path)
103 {
104 int status = 0;
105
106 if (hdcd_mgr)
107 status = dcd_get_objects(hdcd_mgr, sz_coff_path,
108 (dcd_registerfxn) dcd_register_object,
109 NULL);
110 else
111 status = -EFAULT;
112
113 return status;
114 }
115
116 /*
117 * ======== dcd_create_manager ========
118 * Purpose:
119 * Creates DCD manager.
120 */
dcd_create_manager(char * sz_zl_dll_name,struct dcd_manager ** dcd_mgr)121 int dcd_create_manager(char *sz_zl_dll_name,
122 struct dcd_manager **dcd_mgr)
123 {
124 struct cod_manager *cod_mgr; /* COD manager handle */
125 struct dcd_manager *dcd_mgr_obj = NULL; /* DCD Manager pointer */
126 int status = 0;
127
128 status = cod_create(&cod_mgr, sz_zl_dll_name);
129 if (status)
130 goto func_end;
131
132 /* Create a DCD object. */
133 dcd_mgr_obj = kzalloc(sizeof(struct dcd_manager), GFP_KERNEL);
134 if (dcd_mgr_obj != NULL) {
135 /* Fill out the object. */
136 dcd_mgr_obj->cod_mgr = cod_mgr;
137
138 /* Return handle to this DCD interface. */
139 *dcd_mgr = dcd_mgr_obj;
140 } else {
141 status = -ENOMEM;
142
143 /*
144 * If allocation of DcdManager object failed, delete the
145 * COD manager.
146 */
147 cod_delete(cod_mgr);
148 }
149
150 func_end:
151 return status;
152 }
153
154 /*
155 * ======== dcd_destroy_manager ========
156 * Purpose:
157 * Frees DCD Manager object.
158 */
dcd_destroy_manager(struct dcd_manager * hdcd_mgr)159 int dcd_destroy_manager(struct dcd_manager *hdcd_mgr)
160 {
161 struct dcd_manager *dcd_mgr_obj = hdcd_mgr;
162 int status = -EFAULT;
163
164 if (hdcd_mgr) {
165 /* Delete the COD manager. */
166 cod_delete(dcd_mgr_obj->cod_mgr);
167
168 /* Deallocate a DCD manager object. */
169 kfree(dcd_mgr_obj);
170
171 status = 0;
172 }
173
174 return status;
175 }
176
177 /*
178 * ======== dcd_enumerate_object ========
179 * Purpose:
180 * Enumerates objects in the DCD.
181 */
dcd_enumerate_object(s32 index,enum dsp_dcdobjtype obj_type,struct dsp_uuid * uuid_obj)182 int dcd_enumerate_object(s32 index, enum dsp_dcdobjtype obj_type,
183 struct dsp_uuid *uuid_obj)
184 {
185 int status = 0;
186 char sz_reg_key[DCD_MAXPATHLENGTH];
187 char sz_value[DCD_MAXPATHLENGTH];
188 struct dsp_uuid dsp_uuid_obj;
189 char sz_obj_type[MAX_INT2CHAR_LENGTH]; /* str. rep. of obj_type. */
190 u32 dw_key_len = 0;
191 struct dcd_key_elem *dcd_key;
192 int len;
193
194 if ((index != 0) && (enum_refs == 0)) {
195 /*
196 * If an enumeration is being performed on an index greater
197 * than zero, then the current enum_refs must have been
198 * incremented to greater than zero.
199 */
200 status = -EIDRM;
201 } else {
202 /*
203 * Pre-determine final key length. It's length of DCD_REGKEY +
204 * "_\0" + length of sz_obj_type string + terminating NULL.
205 */
206 dw_key_len = strlen(DCD_REGKEY) + 1 + sizeof(sz_obj_type) + 1;
207
208 /* Create proper REG key; concatenate DCD_REGKEY with
209 * obj_type. */
210 strncpy(sz_reg_key, DCD_REGKEY, strlen(DCD_REGKEY) + 1);
211 if ((strlen(sz_reg_key) + strlen("_\0")) <
212 DCD_MAXPATHLENGTH) {
213 strncat(sz_reg_key, "_\0", 2);
214 } else {
215 status = -EPERM;
216 }
217
218 /* This snprintf is guaranteed not to exceed max size of an
219 * integer. */
220 status = snprintf(sz_obj_type, MAX_INT2CHAR_LENGTH, "%d",
221 obj_type);
222
223 if (status == -1) {
224 status = -EPERM;
225 } else {
226 status = 0;
227 if ((strlen(sz_reg_key) + strlen(sz_obj_type)) <
228 DCD_MAXPATHLENGTH) {
229 strncat(sz_reg_key, sz_obj_type,
230 strlen(sz_obj_type) + 1);
231 } else {
232 status = -EPERM;
233 }
234 }
235
236 if (!status) {
237 len = strlen(sz_reg_key);
238 spin_lock(&dbdcd_lock);
239 list_for_each_entry(dcd_key, ®_key_list, link) {
240 if (!strncmp(dcd_key->name, sz_reg_key, len)
241 && !index--) {
242 strncpy(sz_value, &dcd_key->name[len],
243 strlen(&dcd_key->name[len]) + 1);
244 break;
245 }
246 }
247 spin_unlock(&dbdcd_lock);
248
249 if (&dcd_key->link == ®_key_list)
250 status = -ENODATA;
251 }
252
253 if (!status) {
254 /* Create UUID value using string retrieved from
255 * registry. */
256 uuid_uuid_from_string(sz_value, &dsp_uuid_obj);
257
258 *uuid_obj = dsp_uuid_obj;
259
260 /* Increment enum_refs to update reference count. */
261 enum_refs++;
262
263 status = 0;
264 } else if (status == -ENODATA) {
265 /* At the end of enumeration. Reset enum_refs. */
266 enum_refs = 0;
267
268 /*
269 * TODO: Revisit, this is not an error case but code
270 * expects non-zero value.
271 */
272 status = ENODATA;
273 } else {
274 status = -EPERM;
275 }
276 }
277
278 return status;
279 }
280
281 /*
282 * ======== dcd_exit ========
283 * Purpose:
284 * Discontinue usage of the DCD module.
285 */
dcd_exit(void)286 void dcd_exit(void)
287 {
288 struct dcd_key_elem *rv, *rv_tmp;
289
290 refs--;
291 if (refs == 0) {
292 list_for_each_entry_safe(rv, rv_tmp, ®_key_list, link) {
293 list_del(&rv->link);
294 kfree(rv->path);
295 kfree(rv);
296 }
297 }
298
299 }
300
301 /*
302 * ======== dcd_get_dep_libs ========
303 */
dcd_get_dep_libs(struct dcd_manager * hdcd_mgr,struct dsp_uuid * uuid_obj,u16 num_libs,struct dsp_uuid * dep_lib_uuids,bool * prstnt_dep_libs,enum nldr_phase phase)304 int dcd_get_dep_libs(struct dcd_manager *hdcd_mgr,
305 struct dsp_uuid *uuid_obj,
306 u16 num_libs, struct dsp_uuid *dep_lib_uuids,
307 bool *prstnt_dep_libs,
308 enum nldr_phase phase)
309 {
310 int status = 0;
311
312 status =
313 get_dep_lib_info(hdcd_mgr, uuid_obj, &num_libs, NULL, dep_lib_uuids,
314 prstnt_dep_libs, phase);
315
316 return status;
317 }
318
319 /*
320 * ======== dcd_get_num_dep_libs ========
321 */
dcd_get_num_dep_libs(struct dcd_manager * hdcd_mgr,struct dsp_uuid * uuid_obj,u16 * num_libs,u16 * num_pers_libs,enum nldr_phase phase)322 int dcd_get_num_dep_libs(struct dcd_manager *hdcd_mgr,
323 struct dsp_uuid *uuid_obj,
324 u16 *num_libs, u16 *num_pers_libs,
325 enum nldr_phase phase)
326 {
327 int status = 0;
328
329 status = get_dep_lib_info(hdcd_mgr, uuid_obj, num_libs, num_pers_libs,
330 NULL, NULL, phase);
331
332 return status;
333 }
334
335 /*
336 * ======== dcd_get_object_def ========
337 * Purpose:
338 * Retrieves the properties of a node or processor based on the UUID and
339 * object type.
340 */
dcd_get_object_def(struct dcd_manager * hdcd_mgr,struct dsp_uuid * obj_uuid,enum dsp_dcdobjtype obj_type,struct dcd_genericobj * obj_def)341 int dcd_get_object_def(struct dcd_manager *hdcd_mgr,
342 struct dsp_uuid *obj_uuid,
343 enum dsp_dcdobjtype obj_type,
344 struct dcd_genericobj *obj_def)
345 {
346 struct dcd_manager *dcd_mgr_obj = hdcd_mgr; /* ptr to DCD mgr */
347 struct cod_libraryobj *lib = NULL;
348 int status = 0;
349 u32 ul_addr = 0; /* Used by cod_get_section */
350 u32 ul_len = 0; /* Used by cod_get_section */
351 u32 dw_buf_size; /* Used by REG functions */
352 char sz_reg_key[DCD_MAXPATHLENGTH];
353 char *sz_uuid; /*[MAXUUIDLEN]; */
354 struct dcd_key_elem *dcd_key = NULL;
355 char sz_sect_name[MAXUUIDLEN + 2]; /* ".[UUID]\0" */
356 char *psz_coff_buf;
357 u32 dw_key_len; /* Len of REG key. */
358 char sz_obj_type[MAX_INT2CHAR_LENGTH]; /* str. rep. of obj_type. */
359
360 sz_uuid = kzalloc(MAXUUIDLEN, GFP_KERNEL);
361 if (!sz_uuid) {
362 status = -ENOMEM;
363 goto func_end;
364 }
365
366 if (!hdcd_mgr) {
367 status = -EFAULT;
368 goto func_end;
369 }
370
371 /* Pre-determine final key length. It's length of DCD_REGKEY +
372 * "_\0" + length of sz_obj_type string + terminating NULL */
373 dw_key_len = strlen(DCD_REGKEY) + 1 + sizeof(sz_obj_type) + 1;
374
375 /* Create proper REG key; concatenate DCD_REGKEY with obj_type. */
376 strncpy(sz_reg_key, DCD_REGKEY, strlen(DCD_REGKEY) + 1);
377
378 if ((strlen(sz_reg_key) + strlen("_\0")) < DCD_MAXPATHLENGTH)
379 strncat(sz_reg_key, "_\0", 2);
380 else
381 status = -EPERM;
382
383 status = snprintf(sz_obj_type, MAX_INT2CHAR_LENGTH, "%d", obj_type);
384 if (status == -1) {
385 status = -EPERM;
386 } else {
387 status = 0;
388
389 if ((strlen(sz_reg_key) + strlen(sz_obj_type)) <
390 DCD_MAXPATHLENGTH) {
391 strncat(sz_reg_key, sz_obj_type,
392 strlen(sz_obj_type) + 1);
393 } else {
394 status = -EPERM;
395 }
396
397 /* Create UUID value to set in registry. */
398 uuid_uuid_to_string(obj_uuid, sz_uuid, MAXUUIDLEN);
399
400 if ((strlen(sz_reg_key) + MAXUUIDLEN) < DCD_MAXPATHLENGTH)
401 strncat(sz_reg_key, sz_uuid, MAXUUIDLEN);
402 else
403 status = -EPERM;
404
405 /* Retrieve paths from the registry based on struct dsp_uuid */
406 dw_buf_size = DCD_MAXPATHLENGTH;
407 }
408 if (!status) {
409 spin_lock(&dbdcd_lock);
410 list_for_each_entry(dcd_key, ®_key_list, link) {
411 if (!strncmp(dcd_key->name, sz_reg_key,
412 strlen(sz_reg_key) + 1))
413 break;
414 }
415 spin_unlock(&dbdcd_lock);
416 if (&dcd_key->link == ®_key_list) {
417 status = -ENOKEY;
418 goto func_end;
419 }
420 }
421
422
423 /* Open COFF file. */
424 status = cod_open(dcd_mgr_obj->cod_mgr, dcd_key->path,
425 COD_NOLOAD, &lib);
426 if (status) {
427 status = -EACCES;
428 goto func_end;
429 }
430
431 /* Ensure sz_uuid + 1 is not greater than sizeof sz_sect_name. */
432
433 /* Create section name based on node UUID. A period is
434 * pre-pended to the UUID string to form the section name.
435 * I.e. ".24BC8D90_BB45_11d4_B756_006008BDB66F" */
436 strncpy(sz_sect_name, ".", 2);
437 strncat(sz_sect_name, sz_uuid, strlen(sz_uuid));
438
439 /* Get section information. */
440 status = cod_get_section(lib, sz_sect_name, &ul_addr, &ul_len);
441 if (status) {
442 status = -EACCES;
443 goto func_end;
444 }
445
446 /* Allocate zeroed buffer. */
447 psz_coff_buf = kzalloc(ul_len + 4, GFP_KERNEL);
448 if (psz_coff_buf == NULL) {
449 status = -ENOMEM;
450 goto func_end;
451 }
452 #ifdef _DB_TIOMAP
453 if (strstr(dcd_key->path, "iva") == NULL) {
454 /* Locate section by objectID and read its content. */
455 status =
456 cod_read_section(lib, sz_sect_name, psz_coff_buf, ul_len);
457 } else {
458 status =
459 cod_read_section(lib, sz_sect_name, psz_coff_buf, ul_len);
460 dev_dbg(bridge, "%s: Skipped Byte swap for IVA!!\n", __func__);
461 }
462 #else
463 status = cod_read_section(lib, sz_sect_name, psz_coff_buf, ul_len);
464 #endif
465 if (!status) {
466 /* Compres DSP buffer to conform to PC format. */
467 if (strstr(dcd_key->path, "iva") == NULL) {
468 compress_buf(psz_coff_buf, ul_len, DSPWORDSIZE);
469 } else {
470 compress_buf(psz_coff_buf, ul_len, 1);
471 dev_dbg(bridge, "%s: Compressing IVA COFF buffer by 1 "
472 "for IVA!!\n", __func__);
473 }
474
475 /* Parse the content of the COFF buffer. */
476 status =
477 get_attrs_from_buf(psz_coff_buf, ul_len, obj_type, obj_def);
478 if (status)
479 status = -EACCES;
480 } else {
481 status = -EACCES;
482 }
483
484 /* Free the previously allocated dynamic buffer. */
485 kfree(psz_coff_buf);
486 func_end:
487 if (lib)
488 cod_close(lib);
489
490 kfree(sz_uuid);
491
492 return status;
493 }
494
495 /*
496 * ======== dcd_get_objects ========
497 */
dcd_get_objects(struct dcd_manager * hdcd_mgr,char * sz_coff_path,dcd_registerfxn register_fxn,void * handle)498 int dcd_get_objects(struct dcd_manager *hdcd_mgr,
499 char *sz_coff_path, dcd_registerfxn register_fxn,
500 void *handle)
501 {
502 struct dcd_manager *dcd_mgr_obj = hdcd_mgr;
503 int status = 0;
504 char *psz_coff_buf;
505 char *psz_cur;
506 struct cod_libraryobj *lib = NULL;
507 u32 ul_addr = 0; /* Used by cod_get_section */
508 u32 ul_len = 0; /* Used by cod_get_section */
509 char seps[] = ":, ";
510 char *token = NULL;
511 struct dsp_uuid dsp_uuid_obj;
512 s32 object_type;
513
514 if (!hdcd_mgr) {
515 status = -EFAULT;
516 goto func_end;
517 }
518
519 /* Open DSP coff file, don't load symbols. */
520 status = cod_open(dcd_mgr_obj->cod_mgr, sz_coff_path, COD_NOLOAD, &lib);
521 if (status) {
522 status = -EACCES;
523 goto func_cont;
524 }
525
526 /* Get DCD_RESIGER_SECTION section information. */
527 status = cod_get_section(lib, DCD_REGISTER_SECTION, &ul_addr, &ul_len);
528 if (status || !(ul_len > 0)) {
529 status = -EACCES;
530 goto func_cont;
531 }
532
533 /* Allocate zeroed buffer. */
534 psz_coff_buf = kzalloc(ul_len + 4, GFP_KERNEL);
535 if (psz_coff_buf == NULL) {
536 status = -ENOMEM;
537 goto func_cont;
538 }
539 #ifdef _DB_TIOMAP
540 if (strstr(sz_coff_path, "iva") == NULL) {
541 /* Locate section by objectID and read its content. */
542 status = cod_read_section(lib, DCD_REGISTER_SECTION,
543 psz_coff_buf, ul_len);
544 } else {
545 dev_dbg(bridge, "%s: Skipped Byte swap for IVA!!\n", __func__);
546 status = cod_read_section(lib, DCD_REGISTER_SECTION,
547 psz_coff_buf, ul_len);
548 }
549 #else
550 status =
551 cod_read_section(lib, DCD_REGISTER_SECTION, psz_coff_buf, ul_len);
552 #endif
553 if (!status) {
554 /* Compress DSP buffer to conform to PC format. */
555 if (strstr(sz_coff_path, "iva") == NULL) {
556 compress_buf(psz_coff_buf, ul_len, DSPWORDSIZE);
557 } else {
558 compress_buf(psz_coff_buf, ul_len, 1);
559 dev_dbg(bridge, "%s: Compress COFF buffer with 1 word "
560 "for IVA!!\n", __func__);
561 }
562
563 /* Read from buffer and register object in buffer. */
564 psz_cur = psz_coff_buf;
565 while ((token = strsep(&psz_cur, seps)) && *token != '\0') {
566 /* Retrieve UUID string. */
567 uuid_uuid_from_string(token, &dsp_uuid_obj);
568
569 /* Retrieve object type */
570 token = strsep(&psz_cur, seps);
571
572 /* Retrieve object type */
573 object_type = atoi(token);
574
575 /*
576 * Apply register_fxn to the found DCD object.
577 * Possible actions include:
578 *
579 * 1) Register found DCD object.
580 * 2) Unregister found DCD object (when handle == NULL)
581 * 3) Add overlay node.
582 */
583 status =
584 register_fxn(&dsp_uuid_obj, object_type, handle);
585 if (status) {
586 /* if error occurs, break from while loop. */
587 break;
588 }
589 }
590 } else {
591 status = -EACCES;
592 }
593
594 /* Free the previously allocated dynamic buffer. */
595 kfree(psz_coff_buf);
596 func_cont:
597 if (lib)
598 cod_close(lib);
599
600 func_end:
601 return status;
602 }
603
604 /*
605 * ======== dcd_get_library_name ========
606 * Purpose:
607 * Retrieves the library name for the given UUID.
608 *
609 */
dcd_get_library_name(struct dcd_manager * hdcd_mgr,struct dsp_uuid * uuid_obj,char * str_lib_name,u32 * buff_size,enum nldr_phase phase,bool * phase_split)610 int dcd_get_library_name(struct dcd_manager *hdcd_mgr,
611 struct dsp_uuid *uuid_obj,
612 char *str_lib_name,
613 u32 *buff_size,
614 enum nldr_phase phase, bool *phase_split)
615 {
616 char sz_reg_key[DCD_MAXPATHLENGTH];
617 char sz_uuid[MAXUUIDLEN];
618 u32 dw_key_len; /* Len of REG key. */
619 char sz_obj_type[MAX_INT2CHAR_LENGTH]; /* str. rep. of obj_type. */
620 int status = 0;
621 struct dcd_key_elem *dcd_key = NULL;
622
623 dev_dbg(bridge, "%s: hdcd_mgr %p, uuid_obj %p, str_lib_name %p,"
624 " buff_size %p\n", __func__, hdcd_mgr, uuid_obj, str_lib_name,
625 buff_size);
626
627 /*
628 * Pre-determine final key length. It's length of DCD_REGKEY +
629 * "_\0" + length of sz_obj_type string + terminating NULL.
630 */
631 dw_key_len = strlen(DCD_REGKEY) + 1 + sizeof(sz_obj_type) + 1;
632
633 /* Create proper REG key; concatenate DCD_REGKEY with obj_type. */
634 strncpy(sz_reg_key, DCD_REGKEY, strlen(DCD_REGKEY) + 1);
635 if ((strlen(sz_reg_key) + strlen("_\0")) < DCD_MAXPATHLENGTH)
636 strncat(sz_reg_key, "_\0", 2);
637 else
638 status = -EPERM;
639
640 switch (phase) {
641 case NLDR_CREATE:
642 /* create phase type */
643 sprintf(sz_obj_type, "%d", DSP_DCDCREATELIBTYPE);
644 break;
645 case NLDR_EXECUTE:
646 /* execute phase type */
647 sprintf(sz_obj_type, "%d", DSP_DCDEXECUTELIBTYPE);
648 break;
649 case NLDR_DELETE:
650 /* delete phase type */
651 sprintf(sz_obj_type, "%d", DSP_DCDDELETELIBTYPE);
652 break;
653 case NLDR_NOPHASE:
654 /* known to be a dependent library */
655 sprintf(sz_obj_type, "%d", DSP_DCDLIBRARYTYPE);
656 break;
657 default:
658 status = -EINVAL;
659 }
660 if (!status) {
661 if ((strlen(sz_reg_key) + strlen(sz_obj_type)) <
662 DCD_MAXPATHLENGTH) {
663 strncat(sz_reg_key, sz_obj_type,
664 strlen(sz_obj_type) + 1);
665 } else {
666 status = -EPERM;
667 }
668 /* Create UUID value to find match in registry. */
669 uuid_uuid_to_string(uuid_obj, sz_uuid, MAXUUIDLEN);
670 if ((strlen(sz_reg_key) + MAXUUIDLEN) < DCD_MAXPATHLENGTH)
671 strncat(sz_reg_key, sz_uuid, MAXUUIDLEN);
672 else
673 status = -EPERM;
674 }
675 if (!status) {
676 spin_lock(&dbdcd_lock);
677 list_for_each_entry(dcd_key, ®_key_list, link) {
678 /* See if the name matches. */
679 if (!strncmp(dcd_key->name, sz_reg_key,
680 strlen(sz_reg_key) + 1))
681 break;
682 }
683 spin_unlock(&dbdcd_lock);
684 }
685
686 if (&dcd_key->link == ®_key_list)
687 status = -ENOKEY;
688
689 /* If can't find, phases might be registered as generic LIBRARYTYPE */
690 if (status && phase != NLDR_NOPHASE) {
691 if (phase_split)
692 *phase_split = false;
693
694 strncpy(sz_reg_key, DCD_REGKEY, strlen(DCD_REGKEY) + 1);
695 if ((strlen(sz_reg_key) + strlen("_\0")) <
696 DCD_MAXPATHLENGTH) {
697 strncat(sz_reg_key, "_\0", 2);
698 } else {
699 status = -EPERM;
700 }
701 sprintf(sz_obj_type, "%d", DSP_DCDLIBRARYTYPE);
702 if ((strlen(sz_reg_key) + strlen(sz_obj_type))
703 < DCD_MAXPATHLENGTH) {
704 strncat(sz_reg_key, sz_obj_type,
705 strlen(sz_obj_type) + 1);
706 } else {
707 status = -EPERM;
708 }
709 uuid_uuid_to_string(uuid_obj, sz_uuid, MAXUUIDLEN);
710 if ((strlen(sz_reg_key) + MAXUUIDLEN) < DCD_MAXPATHLENGTH)
711 strncat(sz_reg_key, sz_uuid, MAXUUIDLEN);
712 else
713 status = -EPERM;
714
715 spin_lock(&dbdcd_lock);
716 list_for_each_entry(dcd_key, ®_key_list, link) {
717 /* See if the name matches. */
718 if (!strncmp(dcd_key->name, sz_reg_key,
719 strlen(sz_reg_key) + 1))
720 break;
721 }
722 spin_unlock(&dbdcd_lock);
723
724 status = (&dcd_key->link != ®_key_list) ?
725 0 : -ENOKEY;
726 }
727
728 if (!status)
729 memcpy(str_lib_name, dcd_key->path, strlen(dcd_key->path) + 1);
730 return status;
731 }
732
733 /*
734 * ======== dcd_init ========
735 * Purpose:
736 * Initialize the DCD module.
737 */
dcd_init(void)738 bool dcd_init(void)
739 {
740 bool ret = true;
741
742 if (refs == 0)
743 INIT_LIST_HEAD(®_key_list);
744
745 if (ret)
746 refs++;
747
748 return ret;
749 }
750
751 /*
752 * ======== dcd_register_object ========
753 * Purpose:
754 * Registers a node or a processor with the DCD.
755 * If psz_path_name == NULL, unregister the specified DCD object.
756 */
dcd_register_object(struct dsp_uuid * uuid_obj,enum dsp_dcdobjtype obj_type,char * psz_path_name)757 int dcd_register_object(struct dsp_uuid *uuid_obj,
758 enum dsp_dcdobjtype obj_type,
759 char *psz_path_name)
760 {
761 int status = 0;
762 char sz_reg_key[DCD_MAXPATHLENGTH];
763 char sz_uuid[MAXUUIDLEN + 1];
764 u32 dw_path_size = 0;
765 u32 dw_key_len; /* Len of REG key. */
766 char sz_obj_type[MAX_INT2CHAR_LENGTH]; /* str. rep. of obj_type. */
767 struct dcd_key_elem *dcd_key = NULL;
768
769 dev_dbg(bridge, "%s: object UUID %p, obj_type %d, szPathName %s\n",
770 __func__, uuid_obj, obj_type, psz_path_name);
771
772 /*
773 * Pre-determine final key length. It's length of DCD_REGKEY +
774 * "_\0" + length of sz_obj_type string + terminating NULL.
775 */
776 dw_key_len = strlen(DCD_REGKEY) + 1 + sizeof(sz_obj_type) + 1;
777
778 /* Create proper REG key; concatenate DCD_REGKEY with obj_type. */
779 strncpy(sz_reg_key, DCD_REGKEY, strlen(DCD_REGKEY) + 1);
780 if ((strlen(sz_reg_key) + strlen("_\0")) < DCD_MAXPATHLENGTH)
781 strncat(sz_reg_key, "_\0", 2);
782 else {
783 status = -EPERM;
784 goto func_end;
785 }
786
787 status = snprintf(sz_obj_type, MAX_INT2CHAR_LENGTH, "%d", obj_type);
788 if (status == -1) {
789 status = -EPERM;
790 } else {
791 status = 0;
792 if ((strlen(sz_reg_key) + strlen(sz_obj_type)) <
793 DCD_MAXPATHLENGTH) {
794 strncat(sz_reg_key, sz_obj_type,
795 strlen(sz_obj_type) + 1);
796 } else
797 status = -EPERM;
798
799 /* Create UUID value to set in registry. */
800 uuid_uuid_to_string(uuid_obj, sz_uuid, MAXUUIDLEN);
801 if ((strlen(sz_reg_key) + MAXUUIDLEN) < DCD_MAXPATHLENGTH)
802 strncat(sz_reg_key, sz_uuid, MAXUUIDLEN);
803 else
804 status = -EPERM;
805 }
806
807 if (status)
808 goto func_end;
809
810 /*
811 * If psz_path_name != NULL, perform registration, otherwise,
812 * perform unregistration.
813 */
814
815 if (psz_path_name) {
816 dw_path_size = strlen(psz_path_name) + 1;
817 spin_lock(&dbdcd_lock);
818 list_for_each_entry(dcd_key, ®_key_list, link) {
819 /* See if the name matches. */
820 if (!strncmp(dcd_key->name, sz_reg_key,
821 strlen(sz_reg_key) + 1))
822 break;
823 }
824 spin_unlock(&dbdcd_lock);
825 if (&dcd_key->link == ®_key_list) {
826 /*
827 * Add new reg value (UUID+obj_type)
828 * with COFF path info
829 */
830
831 dcd_key = kmalloc(sizeof(struct dcd_key_elem),
832 GFP_KERNEL);
833 if (!dcd_key) {
834 status = -ENOMEM;
835 goto func_end;
836 }
837
838 dcd_key->path = kmalloc(strlen(sz_reg_key) + 1,
839 GFP_KERNEL);
840
841 if (!dcd_key->path) {
842 kfree(dcd_key);
843 status = -ENOMEM;
844 goto func_end;
845 }
846
847 strncpy(dcd_key->name, sz_reg_key,
848 strlen(sz_reg_key) + 1);
849 strncpy(dcd_key->path, psz_path_name ,
850 dw_path_size);
851 spin_lock(&dbdcd_lock);
852 list_add_tail(&dcd_key->link, ®_key_list);
853 spin_unlock(&dbdcd_lock);
854 } else {
855 /* Make sure the new data is the same. */
856 if (strncmp(dcd_key->path, psz_path_name,
857 dw_path_size)) {
858 /* The caller needs a different data size! */
859 kfree(dcd_key->path);
860 dcd_key->path = kmalloc(dw_path_size,
861 GFP_KERNEL);
862 if (dcd_key->path == NULL) {
863 status = -ENOMEM;
864 goto func_end;
865 }
866 }
867
868 /* We have a match! Copy out the data. */
869 memcpy(dcd_key->path, psz_path_name, dw_path_size);
870 }
871 dev_dbg(bridge, "%s: psz_path_name=%s, dw_path_size=%d\n",
872 __func__, psz_path_name, dw_path_size);
873 } else {
874 /* Deregister an existing object */
875 spin_lock(&dbdcd_lock);
876 list_for_each_entry(dcd_key, ®_key_list, link) {
877 if (!strncmp(dcd_key->name, sz_reg_key,
878 strlen(sz_reg_key) + 1)) {
879 list_del(&dcd_key->link);
880 kfree(dcd_key->path);
881 kfree(dcd_key);
882 break;
883 }
884 }
885 spin_unlock(&dbdcd_lock);
886 if (&dcd_key->link == ®_key_list)
887 status = -EPERM;
888 }
889
890 if (!status) {
891 /*
892 * Because the node database has been updated through a
893 * successful object registration/de-registration operation,
894 * we need to reset the object enumeration counter to allow
895 * current enumerations to reflect this update in the node
896 * database.
897 */
898 enum_refs = 0;
899 }
900 func_end:
901 return status;
902 }
903
904 /*
905 * ======== dcd_unregister_object ========
906 * Call DCD_Register object with psz_path_name set to NULL to
907 * perform actual object de-registration.
908 */
dcd_unregister_object(struct dsp_uuid * uuid_obj,enum dsp_dcdobjtype obj_type)909 int dcd_unregister_object(struct dsp_uuid *uuid_obj,
910 enum dsp_dcdobjtype obj_type)
911 {
912 int status = 0;
913
914 /*
915 * When dcd_register_object is called with NULL as pathname,
916 * it indicates an unregister object operation.
917 */
918 status = dcd_register_object(uuid_obj, obj_type, NULL);
919
920 return status;
921 }
922
923 /*
924 **********************************************************************
925 * DCD Helper Functions
926 **********************************************************************
927 */
928
929 /*
930 * ======== atoi ========
931 * Purpose:
932 * This function converts strings in decimal or hex format to integers.
933 */
atoi(char * psz_buf)934 static s32 atoi(char *psz_buf)
935 {
936 char *pch = psz_buf;
937 s32 base = 0;
938
939 while (isspace(*pch))
940 pch++;
941
942 if (*pch == '-' || *pch == '+') {
943 base = 10;
944 pch++;
945 } else if (*pch && tolower(pch[strlen(pch) - 1]) == 'h') {
946 base = 16;
947 }
948
949 return simple_strtoul(pch, NULL, base);
950 }
951
952 /*
953 * ======== get_attrs_from_buf ========
954 * Purpose:
955 * Parse the content of a buffer filled with DSP-side data and
956 * retrieve an object's attributes from it. IMPORTANT: Assume the
957 * buffer has been converted from DSP format to GPP format.
958 */
get_attrs_from_buf(char * psz_buf,u32 ul_buf_size,enum dsp_dcdobjtype obj_type,struct dcd_genericobj * gen_obj)959 static int get_attrs_from_buf(char *psz_buf, u32 ul_buf_size,
960 enum dsp_dcdobjtype obj_type,
961 struct dcd_genericobj *gen_obj)
962 {
963 int status = 0;
964 char seps[] = ", ";
965 char *psz_cur;
966 char *token;
967 s32 token_len = 0;
968 u32 i = 0;
969 #ifdef _DB_TIOMAP
970 s32 entry_id;
971 #endif
972
973 switch (obj_type) {
974 case DSP_DCDNODETYPE:
975 /*
976 * Parse COFF sect buffer to retrieve individual tokens used
977 * to fill in object attrs.
978 */
979 psz_cur = psz_buf;
980 token = strsep(&psz_cur, seps);
981
982 /* u32 cb_struct */
983 gen_obj->obj_data.node_obj.ndb_props.cb_struct =
984 (u32) atoi(token);
985 token = strsep(&psz_cur, seps);
986
987 /* dsp_uuid ui_node_id */
988 uuid_uuid_from_string(token,
989 &gen_obj->obj_data.node_obj.ndb_props.
990 ui_node_id);
991 token = strsep(&psz_cur, seps);
992
993 /* ac_name */
994 token_len = strlen(token);
995 if (token_len > DSP_MAXNAMELEN - 1)
996 token_len = DSP_MAXNAMELEN - 1;
997
998 strncpy(gen_obj->obj_data.node_obj.ndb_props.ac_name,
999 token, token_len);
1000 gen_obj->obj_data.node_obj.ndb_props.ac_name[token_len] = '\0';
1001 token = strsep(&psz_cur, seps);
1002 /* u32 ntype */
1003 gen_obj->obj_data.node_obj.ndb_props.ntype = atoi(token);
1004 token = strsep(&psz_cur, seps);
1005 /* u32 cache_on_gpp */
1006 gen_obj->obj_data.node_obj.ndb_props.cache_on_gpp = atoi(token);
1007 token = strsep(&psz_cur, seps);
1008 /* dsp_resourcereqmts dsp_resource_reqmts */
1009 gen_obj->obj_data.node_obj.ndb_props.dsp_resource_reqmts.
1010 cb_struct = (u32) atoi(token);
1011 token = strsep(&psz_cur, seps);
1012
1013 gen_obj->obj_data.node_obj.ndb_props.
1014 dsp_resource_reqmts.static_data_size = atoi(token);
1015 token = strsep(&psz_cur, seps);
1016 gen_obj->obj_data.node_obj.ndb_props.
1017 dsp_resource_reqmts.global_data_size = atoi(token);
1018 token = strsep(&psz_cur, seps);
1019 gen_obj->obj_data.node_obj.ndb_props.
1020 dsp_resource_reqmts.program_mem_size = atoi(token);
1021 token = strsep(&psz_cur, seps);
1022 gen_obj->obj_data.node_obj.ndb_props.
1023 dsp_resource_reqmts.wc_execution_time = atoi(token);
1024 token = strsep(&psz_cur, seps);
1025 gen_obj->obj_data.node_obj.ndb_props.
1026 dsp_resource_reqmts.wc_period = atoi(token);
1027 token = strsep(&psz_cur, seps);
1028
1029 gen_obj->obj_data.node_obj.ndb_props.
1030 dsp_resource_reqmts.wc_deadline = atoi(token);
1031 token = strsep(&psz_cur, seps);
1032
1033 gen_obj->obj_data.node_obj.ndb_props.
1034 dsp_resource_reqmts.avg_exection_time = atoi(token);
1035 token = strsep(&psz_cur, seps);
1036
1037 gen_obj->obj_data.node_obj.ndb_props.
1038 dsp_resource_reqmts.minimum_period = atoi(token);
1039 token = strsep(&psz_cur, seps);
1040
1041 /* s32 prio */
1042 gen_obj->obj_data.node_obj.ndb_props.prio = atoi(token);
1043 token = strsep(&psz_cur, seps);
1044
1045 /* u32 stack_size */
1046 gen_obj->obj_data.node_obj.ndb_props.stack_size = atoi(token);
1047 token = strsep(&psz_cur, seps);
1048
1049 /* u32 sys_stack_size */
1050 gen_obj->obj_data.node_obj.ndb_props.sys_stack_size =
1051 atoi(token);
1052 token = strsep(&psz_cur, seps);
1053
1054 /* u32 stack_seg */
1055 gen_obj->obj_data.node_obj.ndb_props.stack_seg = atoi(token);
1056 token = strsep(&psz_cur, seps);
1057
1058 /* u32 message_depth */
1059 gen_obj->obj_data.node_obj.ndb_props.message_depth =
1060 atoi(token);
1061 token = strsep(&psz_cur, seps);
1062
1063 /* u32 num_input_streams */
1064 gen_obj->obj_data.node_obj.ndb_props.num_input_streams =
1065 atoi(token);
1066 token = strsep(&psz_cur, seps);
1067
1068 /* u32 num_output_streams */
1069 gen_obj->obj_data.node_obj.ndb_props.num_output_streams =
1070 atoi(token);
1071 token = strsep(&psz_cur, seps);
1072
1073 /* u32 timeout */
1074 gen_obj->obj_data.node_obj.ndb_props.timeout = atoi(token);
1075 token = strsep(&psz_cur, seps);
1076
1077 /* char *str_create_phase_fxn */
1078 token_len = strlen(token);
1079 gen_obj->obj_data.node_obj.str_create_phase_fxn =
1080 kzalloc(token_len + 1, GFP_KERNEL);
1081 strncpy(gen_obj->obj_data.node_obj.str_create_phase_fxn,
1082 token, token_len);
1083 gen_obj->obj_data.node_obj.str_create_phase_fxn[token_len] =
1084 '\0';
1085 token = strsep(&psz_cur, seps);
1086
1087 /* char *str_execute_phase_fxn */
1088 token_len = strlen(token);
1089 gen_obj->obj_data.node_obj.str_execute_phase_fxn =
1090 kzalloc(token_len + 1, GFP_KERNEL);
1091 strncpy(gen_obj->obj_data.node_obj.str_execute_phase_fxn,
1092 token, token_len);
1093 gen_obj->obj_data.node_obj.str_execute_phase_fxn[token_len] =
1094 '\0';
1095 token = strsep(&psz_cur, seps);
1096
1097 /* char *str_delete_phase_fxn */
1098 token_len = strlen(token);
1099 gen_obj->obj_data.node_obj.str_delete_phase_fxn =
1100 kzalloc(token_len + 1, GFP_KERNEL);
1101 strncpy(gen_obj->obj_data.node_obj.str_delete_phase_fxn,
1102 token, token_len);
1103 gen_obj->obj_data.node_obj.str_delete_phase_fxn[token_len] =
1104 '\0';
1105 token = strsep(&psz_cur, seps);
1106
1107 /* Segment id for message buffers */
1108 gen_obj->obj_data.node_obj.msg_segid = atoi(token);
1109 token = strsep(&psz_cur, seps);
1110
1111 /* Message notification type */
1112 gen_obj->obj_data.node_obj.msg_notify_type = atoi(token);
1113 token = strsep(&psz_cur, seps);
1114
1115 /* char *str_i_alg_name */
1116 if (token) {
1117 token_len = strlen(token);
1118 gen_obj->obj_data.node_obj.str_i_alg_name =
1119 kzalloc(token_len + 1, GFP_KERNEL);
1120 strncpy(gen_obj->obj_data.node_obj.str_i_alg_name,
1121 token, token_len);
1122 gen_obj->obj_data.node_obj.str_i_alg_name[token_len] =
1123 '\0';
1124 token = strsep(&psz_cur, seps);
1125 }
1126
1127 /* Load type (static, dynamic, or overlay) */
1128 if (token) {
1129 gen_obj->obj_data.node_obj.load_type = atoi(token);
1130 token = strsep(&psz_cur, seps);
1131 }
1132
1133 /* Dynamic load data requirements */
1134 if (token) {
1135 gen_obj->obj_data.node_obj.data_mem_seg_mask =
1136 atoi(token);
1137 token = strsep(&psz_cur, seps);
1138 }
1139
1140 /* Dynamic load code requirements */
1141 if (token) {
1142 gen_obj->obj_data.node_obj.code_mem_seg_mask =
1143 atoi(token);
1144 token = strsep(&psz_cur, seps);
1145 }
1146
1147 /* Extract node profiles into node properties */
1148 if (token) {
1149
1150 gen_obj->obj_data.node_obj.ndb_props.count_profiles =
1151 atoi(token);
1152 for (i = 0;
1153 i <
1154 gen_obj->obj_data.node_obj.
1155 ndb_props.count_profiles; i++) {
1156 token = strsep(&psz_cur, seps);
1157 if (token) {
1158 /* Heap Size for the node */
1159 gen_obj->obj_data.node_obj.
1160 ndb_props.node_profiles[i].
1161 heap_size = atoi(token);
1162 }
1163 }
1164 }
1165 token = strsep(&psz_cur, seps);
1166 if (token) {
1167 gen_obj->obj_data.node_obj.ndb_props.stack_seg_name =
1168 (u32) (token);
1169 }
1170
1171 break;
1172
1173 case DSP_DCDPROCESSORTYPE:
1174 /*
1175 * Parse COFF sect buffer to retrieve individual tokens used
1176 * to fill in object attrs.
1177 */
1178 psz_cur = psz_buf;
1179 token = strsep(&psz_cur, seps);
1180
1181 gen_obj->obj_data.proc_info.cb_struct = atoi(token);
1182 token = strsep(&psz_cur, seps);
1183
1184 gen_obj->obj_data.proc_info.processor_family = atoi(token);
1185 token = strsep(&psz_cur, seps);
1186
1187 gen_obj->obj_data.proc_info.processor_type = atoi(token);
1188 token = strsep(&psz_cur, seps);
1189
1190 gen_obj->obj_data.proc_info.clock_rate = atoi(token);
1191 token = strsep(&psz_cur, seps);
1192
1193 gen_obj->obj_data.proc_info.internal_mem_size = atoi(token);
1194 token = strsep(&psz_cur, seps);
1195
1196 gen_obj->obj_data.proc_info.external_mem_size = atoi(token);
1197 token = strsep(&psz_cur, seps);
1198
1199 gen_obj->obj_data.proc_info.processor_id = atoi(token);
1200 token = strsep(&psz_cur, seps);
1201
1202 gen_obj->obj_data.proc_info.ty_running_rtos = atoi(token);
1203 token = strsep(&psz_cur, seps);
1204
1205 gen_obj->obj_data.proc_info.node_min_priority = atoi(token);
1206 token = strsep(&psz_cur, seps);
1207
1208 gen_obj->obj_data.proc_info.node_max_priority = atoi(token);
1209
1210 #ifdef _DB_TIOMAP
1211 /* Proc object may contain additional(extended) attributes. */
1212 /* attr must match proc.hxx */
1213 for (entry_id = 0; entry_id < 7; entry_id++) {
1214 token = strsep(&psz_cur, seps);
1215 gen_obj->obj_data.ext_proc_obj.ty_tlb[entry_id].
1216 gpp_phys = atoi(token);
1217
1218 token = strsep(&psz_cur, seps);
1219 gen_obj->obj_data.ext_proc_obj.ty_tlb[entry_id].
1220 dsp_virt = atoi(token);
1221 }
1222 #endif
1223
1224 break;
1225
1226 default:
1227 status = -EPERM;
1228 break;
1229 }
1230
1231 return status;
1232 }
1233
1234 /*
1235 * ======== CompressBuffer ========
1236 * Purpose:
1237 * Compress the DSP buffer, if necessary, to conform to PC format.
1238 */
compress_buf(char * psz_buf,u32 ul_buf_size,s32 char_size)1239 static void compress_buf(char *psz_buf, u32 ul_buf_size, s32 char_size)
1240 {
1241 char *p;
1242 char ch;
1243 char *q;
1244
1245 p = psz_buf;
1246 if (p == NULL)
1247 return;
1248
1249 for (q = psz_buf; q < (psz_buf + ul_buf_size);) {
1250 ch = dsp_char2_gpp_char(q, char_size);
1251 if (ch == '\\') {
1252 q += char_size;
1253 ch = dsp_char2_gpp_char(q, char_size);
1254 switch (ch) {
1255 case 't':
1256 *p = '\t';
1257 break;
1258
1259 case 'n':
1260 *p = '\n';
1261 break;
1262
1263 case 'r':
1264 *p = '\r';
1265 break;
1266
1267 case '0':
1268 *p = '\0';
1269 break;
1270
1271 default:
1272 *p = ch;
1273 break;
1274 }
1275 } else {
1276 *p = ch;
1277 }
1278 p++;
1279 q += char_size;
1280 }
1281
1282 /* NULL out remainder of buffer. */
1283 while (p < q)
1284 *p++ = '\0';
1285 }
1286
1287 /*
1288 * ======== dsp_char2_gpp_char ========
1289 * Purpose:
1290 * Convert DSP char to host GPP char in a portable manner
1291 */
dsp_char2_gpp_char(char * word,s32 dsp_char_size)1292 static char dsp_char2_gpp_char(char *word, s32 dsp_char_size)
1293 {
1294 char ch = '\0';
1295 char *ch_src;
1296 s32 i;
1297
1298 for (ch_src = word, i = dsp_char_size; i > 0; i--)
1299 ch |= *ch_src++;
1300
1301 return ch;
1302 }
1303
1304 /*
1305 * ======== get_dep_lib_info ========
1306 */
get_dep_lib_info(struct dcd_manager * hdcd_mgr,struct dsp_uuid * uuid_obj,u16 * num_libs,u16 * num_pers_libs,struct dsp_uuid * dep_lib_uuids,bool * prstnt_dep_libs,enum nldr_phase phase)1307 static int get_dep_lib_info(struct dcd_manager *hdcd_mgr,
1308 struct dsp_uuid *uuid_obj,
1309 u16 *num_libs,
1310 u16 *num_pers_libs,
1311 struct dsp_uuid *dep_lib_uuids,
1312 bool *prstnt_dep_libs,
1313 enum nldr_phase phase)
1314 {
1315 struct dcd_manager *dcd_mgr_obj = hdcd_mgr;
1316 char *psz_coff_buf = NULL;
1317 char *psz_cur;
1318 char *psz_file_name = NULL;
1319 struct cod_libraryobj *lib = NULL;
1320 u32 ul_addr = 0; /* Used by cod_get_section */
1321 u32 ul_len = 0; /* Used by cod_get_section */
1322 u32 dw_data_size = COD_MAXPATHLENGTH;
1323 char seps[] = ", ";
1324 char *token = NULL;
1325 bool get_uuids = (dep_lib_uuids != NULL);
1326 u16 dep_libs = 0;
1327 int status = 0;
1328
1329 /* Initialize to 0 dependent libraries, if only counting number of
1330 * dependent libraries */
1331 if (!get_uuids) {
1332 *num_libs = 0;
1333 *num_pers_libs = 0;
1334 }
1335
1336 /* Allocate a buffer for file name */
1337 psz_file_name = kzalloc(dw_data_size, GFP_KERNEL);
1338 if (psz_file_name == NULL) {
1339 status = -ENOMEM;
1340 } else {
1341 /* Get the name of the library */
1342 status = dcd_get_library_name(hdcd_mgr, uuid_obj, psz_file_name,
1343 &dw_data_size, phase, NULL);
1344 }
1345
1346 /* Open the library */
1347 if (!status) {
1348 status = cod_open(dcd_mgr_obj->cod_mgr, psz_file_name,
1349 COD_NOLOAD, &lib);
1350 }
1351 if (!status) {
1352 /* Get dependent library section information. */
1353 status = cod_get_section(lib, DEPLIBSECT, &ul_addr, &ul_len);
1354
1355 if (status) {
1356 /* Ok, no dependent libraries */
1357 ul_len = 0;
1358 status = 0;
1359 }
1360 }
1361
1362 if (status || !(ul_len > 0))
1363 goto func_cont;
1364
1365 /* Allocate zeroed buffer. */
1366 psz_coff_buf = kzalloc(ul_len + 4, GFP_KERNEL);
1367 if (psz_coff_buf == NULL)
1368 status = -ENOMEM;
1369
1370 /* Read section contents. */
1371 status = cod_read_section(lib, DEPLIBSECT, psz_coff_buf, ul_len);
1372 if (status)
1373 goto func_cont;
1374
1375 /* Compress and format DSP buffer to conform to PC format. */
1376 compress_buf(psz_coff_buf, ul_len, DSPWORDSIZE);
1377
1378 /* Read from buffer */
1379 psz_cur = psz_coff_buf;
1380 while ((token = strsep(&psz_cur, seps)) && *token != '\0') {
1381 if (get_uuids) {
1382 if (dep_libs >= *num_libs) {
1383 /* Gone beyond the limit */
1384 break;
1385 } else {
1386 /* Retrieve UUID string. */
1387 uuid_uuid_from_string(token,
1388 &(dep_lib_uuids
1389 [dep_libs]));
1390 /* Is this library persistent? */
1391 token = strsep(&psz_cur, seps);
1392 prstnt_dep_libs[dep_libs] = atoi(token);
1393 dep_libs++;
1394 }
1395 } else {
1396 /* Advanc to next token */
1397 token = strsep(&psz_cur, seps);
1398 if (atoi(token))
1399 (*num_pers_libs)++;
1400
1401 /* Just counting number of dependent libraries */
1402 (*num_libs)++;
1403 }
1404 }
1405 func_cont:
1406 if (lib)
1407 cod_close(lib);
1408
1409 /* Free previously allocated dynamic buffers. */
1410 kfree(psz_file_name);
1411
1412 kfree(psz_coff_buf);
1413
1414 return status;
1415 }
1416