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