4 * DSP-BIOS Bridge driver support functions for TI OMAP processors.
6 * This file contains the implementation of the DSP/BIOS Bridge
7 * Configuration Database (DCD).
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
15 * Copyright (C) 2005-2006 Texas Instruments, Inc.
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.
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.
25 #include <linux/types.h>
27 /* ----------------------------------- Host OS */
28 #include <dspbridge/host_os.h>
30 /* ----------------------------------- DSP/BIOS Bridge */
31 #include <dspbridge/dbdefs.h>
33 /* ----------------------------------- Platform Manager */
34 #include <dspbridge/cod.h>
36 /* ----------------------------------- Others */
37 #include <dspbridge/uuidutil.h>
39 /* ----------------------------------- This */
40 #include <dspbridge/dbdcd.h>
42 /* ----------------------------------- Global defines. */
43 #define MAX_INT2CHAR_LENGTH 16 /* Max int2char len of 32 bit int */
45 /* Name of section containing dependent libraries */
46 #define DEPLIBSECT ".dspbridge_deplibs"
48 /* DCD specific structures. */
50 struct cod_manager
*cod_mgr
; /* Handle to COD manager object. */
53 /* Pointer to the registry support key */
54 static struct list_head reg_key_list
;
55 static DEFINE_SPINLOCK(dbdcd_lock
);
57 /* Global reference variables. */
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
,
72 struct dsp_uuid
*dep_lib_uuids
,
73 bool *prstnt_dep_libs
,
74 enum nldr_phase phase
);
77 * ======== dcd_uuid_from_string ========
79 * Converts an ANSI string to a dsp_uuid.
81 * sz_uuid: Pointer to a string that represents a dsp_uuid object.
82 * uuid_obj: Pointer to a dsp_uuid object.
85 * -EINVAL: Coversion failed
87 * uuid_obj & sz_uuid are non-NULL values.
90 * We assume the string representation of a UUID has the following format:
91 * "12345678_1234_1234_1234_123456789abc".
93 static int dcd_uuid_from_string(char *sz_uuid
, struct dsp_uuid
*uuid_obj
)
97 struct dsp_uuid uuid_tmp
;
100 * sscanf implementation cannot deal with hh format modifier
101 * if the converted value doesn't fit in u32. So, convert the
102 * last six bytes to u64 and memcpy what is needed
104 if (sscanf(sz_uuid
, "%8x%c%4hx%c%4hx%c%2hhx%2hhx%c%llx",
105 &uuid_tmp
.data1
, &c
, &uuid_tmp
.data2
, &c
,
106 &uuid_tmp
.data3
, &c
, &uuid_tmp
.data4
,
107 &uuid_tmp
.data5
, &c
, &t
) != 10)
111 memcpy(&uuid_tmp
.data6
[0], ((char *)&t
) + 2, 6);
112 *uuid_obj
= uuid_tmp
;
118 * ======== dcd_auto_register ========
120 * Parses the supplied image and resigsters with DCD.
122 int dcd_auto_register(struct dcd_manager
*hdcd_mgr
,
128 status
= dcd_get_objects(hdcd_mgr
, sz_coff_path
,
129 (dcd_registerfxn
) dcd_register_object
,
130 (void *)sz_coff_path
);
138 * ======== dcd_auto_unregister ========
140 * Parses the supplied DSP image and unresiters from DCD.
142 int dcd_auto_unregister(struct dcd_manager
*hdcd_mgr
,
148 status
= dcd_get_objects(hdcd_mgr
, sz_coff_path
,
149 (dcd_registerfxn
) dcd_register_object
,
158 * ======== dcd_create_manager ========
160 * Creates DCD manager.
162 int dcd_create_manager(char *sz_zl_dll_name
,
163 struct dcd_manager
**dcd_mgr
)
165 struct cod_manager
*cod_mgr
; /* COD manager handle */
166 struct dcd_manager
*dcd_mgr_obj
= NULL
; /* DCD Manager pointer */
169 status
= cod_create(&cod_mgr
, sz_zl_dll_name
);
173 /* Create a DCD object. */
174 dcd_mgr_obj
= kzalloc(sizeof(struct dcd_manager
), GFP_KERNEL
);
175 if (dcd_mgr_obj
!= NULL
) {
176 /* Fill out the object. */
177 dcd_mgr_obj
->cod_mgr
= cod_mgr
;
179 /* Return handle to this DCD interface. */
180 *dcd_mgr
= dcd_mgr_obj
;
185 * If allocation of DcdManager object failed, delete the
196 * ======== dcd_destroy_manager ========
198 * Frees DCD Manager object.
200 int dcd_destroy_manager(struct dcd_manager
*hdcd_mgr
)
202 struct dcd_manager
*dcd_mgr_obj
= hdcd_mgr
;
203 int status
= -EFAULT
;
206 /* Delete the COD manager. */
207 cod_delete(dcd_mgr_obj
->cod_mgr
);
209 /* Deallocate a DCD manager object. */
219 * ======== dcd_enumerate_object ========
221 * Enumerates objects in the DCD.
223 int dcd_enumerate_object(s32 index
, enum dsp_dcdobjtype obj_type
,
224 struct dsp_uuid
*uuid_obj
)
227 char sz_reg_key
[DCD_MAXPATHLENGTH
];
228 char sz_value
[DCD_MAXPATHLENGTH
];
229 struct dsp_uuid dsp_uuid_obj
;
230 char sz_obj_type
[MAX_INT2CHAR_LENGTH
]; /* str. rep. of obj_type. */
232 struct dcd_key_elem
*dcd_key
;
235 if ((index
!= 0) && (enum_refs
== 0)) {
237 * If an enumeration is being performed on an index greater
238 * than zero, then the current enum_refs must have been
239 * incremented to greater than zero.
244 * Pre-determine final key length. It's length of DCD_REGKEY +
245 * "_\0" + length of sz_obj_type string + terminating NULL.
247 dw_key_len
= strlen(DCD_REGKEY
) + 1 + sizeof(sz_obj_type
) + 1;
249 /* Create proper REG key; concatenate DCD_REGKEY with
251 strncpy(sz_reg_key
, DCD_REGKEY
, strlen(DCD_REGKEY
) + 1);
252 if ((strlen(sz_reg_key
) + strlen("_\0")) <
254 strncat(sz_reg_key
, "_\0", 2);
259 /* This snprintf is guaranteed not to exceed max size of an
261 status
= snprintf(sz_obj_type
, MAX_INT2CHAR_LENGTH
, "%d",
268 if ((strlen(sz_reg_key
) + strlen(sz_obj_type
)) <
270 strncat(sz_reg_key
, sz_obj_type
,
271 strlen(sz_obj_type
) + 1);
278 len
= strlen(sz_reg_key
);
279 spin_lock(&dbdcd_lock
);
280 list_for_each_entry(dcd_key
, ®_key_list
, link
) {
281 if (!strncmp(dcd_key
->name
, sz_reg_key
, len
)
283 strncpy(sz_value
, &dcd_key
->name
[len
],
284 strlen(&dcd_key
->name
[len
]) + 1);
288 spin_unlock(&dbdcd_lock
);
290 if (&dcd_key
->link
== ®_key_list
)
295 /* Create UUID value using string retrieved from
297 status
= dcd_uuid_from_string(sz_value
, &dsp_uuid_obj
);
300 *uuid_obj
= dsp_uuid_obj
;
302 /* Increment enum_refs to update reference
306 } else if (status
== -ENODATA
) {
307 /* At the end of enumeration. Reset enum_refs. */
311 * TODO: Revisit, this is not an error case but code
312 * expects non-zero value.
324 * ======== dcd_exit ========
326 * Discontinue usage of the DCD module.
330 struct dcd_key_elem
*rv
, *rv_tmp
;
334 list_for_each_entry_safe(rv
, rv_tmp
, ®_key_list
, link
) {
344 * ======== dcd_get_dep_libs ========
346 int dcd_get_dep_libs(struct dcd_manager
*hdcd_mgr
,
347 struct dsp_uuid
*uuid_obj
,
348 u16 num_libs
, struct dsp_uuid
*dep_lib_uuids
,
349 bool *prstnt_dep_libs
,
350 enum nldr_phase phase
)
355 get_dep_lib_info(hdcd_mgr
, uuid_obj
, &num_libs
, NULL
, dep_lib_uuids
,
356 prstnt_dep_libs
, phase
);
362 * ======== dcd_get_num_dep_libs ========
364 int dcd_get_num_dep_libs(struct dcd_manager
*hdcd_mgr
,
365 struct dsp_uuid
*uuid_obj
,
366 u16
*num_libs
, u16
*num_pers_libs
,
367 enum nldr_phase phase
)
371 status
= get_dep_lib_info(hdcd_mgr
, uuid_obj
, num_libs
, num_pers_libs
,
378 * ======== dcd_get_object_def ========
380 * Retrieves the properties of a node or processor based on the UUID and
383 int dcd_get_object_def(struct dcd_manager
*hdcd_mgr
,
384 struct dsp_uuid
*obj_uuid
,
385 enum dsp_dcdobjtype obj_type
,
386 struct dcd_genericobj
*obj_def
)
388 struct dcd_manager
*dcd_mgr_obj
= hdcd_mgr
; /* ptr to DCD mgr */
389 struct cod_libraryobj
*lib
= NULL
;
392 u32 ul_addr
= 0; /* Used by cod_get_section */
393 u32 ul_len
= 0; /* Used by cod_get_section */
394 u32 dw_buf_size
; /* Used by REG functions */
395 char sz_reg_key
[DCD_MAXPATHLENGTH
];
396 char *sz_uuid
; /*[MAXUUIDLEN]; */
398 struct dcd_key_elem
*dcd_key
= NULL
;
399 char sz_sect_name
[MAXUUIDLEN
+ 2]; /* ".[UUID]\0" */
401 u32 dw_key_len
; /* Len of REG key. */
402 char sz_obj_type
[MAX_INT2CHAR_LENGTH
]; /* str. rep. of obj_type. */
404 sz_uuid
= kzalloc(MAXUUIDLEN
, GFP_KERNEL
);
415 /* Pre-determine final key length. It's length of DCD_REGKEY +
416 * "_\0" + length of sz_obj_type string + terminating NULL */
417 dw_key_len
= strlen(DCD_REGKEY
) + 1 + sizeof(sz_obj_type
) + 1;
419 /* Create proper REG key; concatenate DCD_REGKEY with obj_type. */
420 strncpy(sz_reg_key
, DCD_REGKEY
, strlen(DCD_REGKEY
) + 1);
422 if ((strlen(sz_reg_key
) + strlen("_\0")) < DCD_MAXPATHLENGTH
)
423 strncat(sz_reg_key
, "_\0", 2);
427 status
= snprintf(sz_obj_type
, MAX_INT2CHAR_LENGTH
, "%d", obj_type
);
433 if ((strlen(sz_reg_key
) + strlen(sz_obj_type
)) <
435 strncat(sz_reg_key
, sz_obj_type
,
436 strlen(sz_obj_type
) + 1);
441 /* Create UUID value to set in registry. */
442 snprintf(sz_uuid
, MAXUUIDLEN
, "%pUL", obj_uuid
);
444 if ((strlen(sz_reg_key
) + MAXUUIDLEN
) < DCD_MAXPATHLENGTH
)
445 strncat(sz_reg_key
, sz_uuid
, MAXUUIDLEN
);
449 /* Retrieve paths from the registry based on struct dsp_uuid */
450 dw_buf_size
= DCD_MAXPATHLENGTH
;
453 spin_lock(&dbdcd_lock
);
454 list_for_each_entry(dcd_key
, ®_key_list
, link
) {
455 if (!strncmp(dcd_key
->name
, sz_reg_key
,
456 strlen(sz_reg_key
) + 1))
459 spin_unlock(&dbdcd_lock
);
460 if (&dcd_key
->link
== ®_key_list
) {
467 /* Open COFF file. */
468 status
= cod_open(dcd_mgr_obj
->cod_mgr
, dcd_key
->path
,
475 /* Ensure sz_uuid + 1 is not greater than sizeof sz_sect_name. */
476 len
= strlen(sz_uuid
);
477 if (len
+ 1 > sizeof(sz_sect_name
)) {
482 /* Create section name based on node UUID. A period is
483 * pre-pended to the UUID string to form the section name.
484 * I.e. ".24BC8D90_BB45_11d4_B756_006008BDB66F" */
486 len
-= 4; /* uuid has 4 delimiters '-' */
489 strncpy(sz_sect_name
, ".", 2);
491 char *uuid
= strsep(&tmp
, "-");
495 strncat(sz_sect_name
, uuid
, strlen(uuid
) + 1);
496 } while (len
&& strncat(sz_sect_name
, "_", 2));
498 /* Get section information. */
499 status
= cod_get_section(lib
, sz_sect_name
, &ul_addr
, &ul_len
);
505 /* Allocate zeroed buffer. */
506 psz_coff_buf
= kzalloc(ul_len
+ 4, GFP_KERNEL
);
507 if (psz_coff_buf
== NULL
) {
512 if (strstr(dcd_key
->path
, "iva") == NULL
) {
513 /* Locate section by objectID and read its content. */
515 cod_read_section(lib
, sz_sect_name
, psz_coff_buf
, ul_len
);
518 cod_read_section(lib
, sz_sect_name
, psz_coff_buf
, ul_len
);
519 dev_dbg(bridge
, "%s: Skipped Byte swap for IVA!!\n", __func__
);
522 status
= cod_read_section(lib
, sz_sect_name
, psz_coff_buf
, ul_len
);
525 /* Compress DSP buffer to conform to PC format. */
526 if (strstr(dcd_key
->path
, "iva") == NULL
) {
527 compress_buf(psz_coff_buf
, ul_len
, DSPWORDSIZE
);
529 compress_buf(psz_coff_buf
, ul_len
, 1);
530 dev_dbg(bridge
, "%s: Compressing IVA COFF buffer by 1 "
531 "for IVA!!\n", __func__
);
534 /* Parse the content of the COFF buffer. */
536 get_attrs_from_buf(psz_coff_buf
, ul_len
, obj_type
, obj_def
);
543 /* Free the previously allocated dynamic buffer. */
555 * ======== dcd_get_objects ========
557 int dcd_get_objects(struct dcd_manager
*hdcd_mgr
,
558 char *sz_coff_path
, dcd_registerfxn register_fxn
,
561 struct dcd_manager
*dcd_mgr_obj
= hdcd_mgr
;
565 struct cod_libraryobj
*lib
= NULL
;
566 u32 ul_addr
= 0; /* Used by cod_get_section */
567 u32 ul_len
= 0; /* Used by cod_get_section */
570 struct dsp_uuid dsp_uuid_obj
;
578 /* Open DSP coff file, don't load symbols. */
579 status
= cod_open(dcd_mgr_obj
->cod_mgr
, sz_coff_path
, COD_NOLOAD
, &lib
);
585 /* Get DCD_RESIGER_SECTION section information. */
586 status
= cod_get_section(lib
, DCD_REGISTER_SECTION
, &ul_addr
, &ul_len
);
587 if (status
|| !(ul_len
> 0)) {
592 /* Allocate zeroed buffer. */
593 psz_coff_buf
= kzalloc(ul_len
+ 4, GFP_KERNEL
);
594 if (psz_coff_buf
== NULL
) {
599 if (strstr(sz_coff_path
, "iva") == NULL
) {
600 /* Locate section by objectID and read its content. */
601 status
= cod_read_section(lib
, DCD_REGISTER_SECTION
,
602 psz_coff_buf
, ul_len
);
604 dev_dbg(bridge
, "%s: Skipped Byte swap for IVA!!\n", __func__
);
605 status
= cod_read_section(lib
, DCD_REGISTER_SECTION
,
606 psz_coff_buf
, ul_len
);
610 cod_read_section(lib
, DCD_REGISTER_SECTION
, psz_coff_buf
, ul_len
);
613 /* Compress DSP buffer to conform to PC format. */
614 if (strstr(sz_coff_path
, "iva") == NULL
) {
615 compress_buf(psz_coff_buf
, ul_len
, DSPWORDSIZE
);
617 compress_buf(psz_coff_buf
, ul_len
, 1);
618 dev_dbg(bridge
, "%s: Compress COFF buffer with 1 word "
619 "for IVA!!\n", __func__
);
622 /* Read from buffer and register object in buffer. */
623 psz_cur
= psz_coff_buf
;
624 while ((token
= strsep(&psz_cur
, seps
)) && *token
!= '\0') {
625 /* Retrieve UUID string. */
626 status
= dcd_uuid_from_string(token
, &dsp_uuid_obj
);
629 /* Retrieve object type */
630 token
= strsep(&psz_cur
, seps
);
632 /* Retrieve object type */
633 object_type
= atoi(token
);
636 * Apply register_fxn to the found DCD object.
637 * Possible actions include:
639 * 1) Register found DCD object.
640 * 2) Unregister found DCD object
641 * (when handle == NULL)
642 * 3) Add overlay node.
645 register_fxn(&dsp_uuid_obj
, object_type
,
649 /* if error occurs, break from while loop. */
657 /* Free the previously allocated dynamic buffer. */
668 * ======== dcd_get_library_name ========
670 * Retrieves the library name for the given UUID.
673 int dcd_get_library_name(struct dcd_manager
*hdcd_mgr
,
674 struct dsp_uuid
*uuid_obj
,
677 enum nldr_phase phase
, bool *phase_split
)
679 char sz_reg_key
[DCD_MAXPATHLENGTH
];
680 char sz_uuid
[MAXUUIDLEN
];
681 u32 dw_key_len
; /* Len of REG key. */
682 char sz_obj_type
[MAX_INT2CHAR_LENGTH
]; /* str. rep. of obj_type. */
684 struct dcd_key_elem
*dcd_key
= NULL
;
686 dev_dbg(bridge
, "%s: hdcd_mgr %p, uuid_obj %p, str_lib_name %p,"
687 " buff_size %p\n", __func__
, hdcd_mgr
, uuid_obj
, str_lib_name
,
691 * Pre-determine final key length. It's length of DCD_REGKEY +
692 * "_\0" + length of sz_obj_type string + terminating NULL.
694 dw_key_len
= strlen(DCD_REGKEY
) + 1 + sizeof(sz_obj_type
) + 1;
696 /* Create proper REG key; concatenate DCD_REGKEY with obj_type. */
697 strncpy(sz_reg_key
, DCD_REGKEY
, strlen(DCD_REGKEY
) + 1);
698 if ((strlen(sz_reg_key
) + strlen("_\0")) < DCD_MAXPATHLENGTH
)
699 strncat(sz_reg_key
, "_\0", 2);
705 /* create phase type */
706 sprintf(sz_obj_type
, "%d", DSP_DCDCREATELIBTYPE
);
709 /* execute phase type */
710 sprintf(sz_obj_type
, "%d", DSP_DCDEXECUTELIBTYPE
);
713 /* delete phase type */
714 sprintf(sz_obj_type
, "%d", DSP_DCDDELETELIBTYPE
);
717 /* known to be a dependent library */
718 sprintf(sz_obj_type
, "%d", DSP_DCDLIBRARYTYPE
);
724 if ((strlen(sz_reg_key
) + strlen(sz_obj_type
)) <
726 strncat(sz_reg_key
, sz_obj_type
,
727 strlen(sz_obj_type
) + 1);
731 /* Create UUID value to find match in registry. */
732 snprintf(sz_uuid
, MAXUUIDLEN
, "%pUL", uuid_obj
);
733 if ((strlen(sz_reg_key
) + MAXUUIDLEN
) < DCD_MAXPATHLENGTH
)
734 strncat(sz_reg_key
, sz_uuid
, MAXUUIDLEN
);
739 spin_lock(&dbdcd_lock
);
740 list_for_each_entry(dcd_key
, ®_key_list
, link
) {
741 /* See if the name matches. */
742 if (!strncmp(dcd_key
->name
, sz_reg_key
,
743 strlen(sz_reg_key
) + 1))
746 spin_unlock(&dbdcd_lock
);
749 if (&dcd_key
->link
== ®_key_list
)
752 /* If can't find, phases might be registered as generic LIBRARYTYPE */
753 if (status
&& phase
!= NLDR_NOPHASE
) {
755 *phase_split
= false;
757 strncpy(sz_reg_key
, DCD_REGKEY
, strlen(DCD_REGKEY
) + 1);
758 if ((strlen(sz_reg_key
) + strlen("_\0")) <
760 strncat(sz_reg_key
, "_\0", 2);
764 sprintf(sz_obj_type
, "%d", DSP_DCDLIBRARYTYPE
);
765 if ((strlen(sz_reg_key
) + strlen(sz_obj_type
))
766 < DCD_MAXPATHLENGTH
) {
767 strncat(sz_reg_key
, sz_obj_type
,
768 strlen(sz_obj_type
) + 1);
772 snprintf(sz_uuid
, MAXUUIDLEN
, "%pUL", uuid_obj
);
773 if ((strlen(sz_reg_key
) + MAXUUIDLEN
) < DCD_MAXPATHLENGTH
)
774 strncat(sz_reg_key
, sz_uuid
, MAXUUIDLEN
);
778 spin_lock(&dbdcd_lock
);
779 list_for_each_entry(dcd_key
, ®_key_list
, link
) {
780 /* See if the name matches. */
781 if (!strncmp(dcd_key
->name
, sz_reg_key
,
782 strlen(sz_reg_key
) + 1))
785 spin_unlock(&dbdcd_lock
);
787 status
= (&dcd_key
->link
!= ®_key_list
) ?
792 memcpy(str_lib_name
, dcd_key
->path
, strlen(dcd_key
->path
) + 1);
797 * ======== dcd_init ========
799 * Initialize the DCD module.
806 INIT_LIST_HEAD(®_key_list
);
815 * ======== dcd_register_object ========
817 * Registers a node or a processor with the DCD.
818 * If psz_path_name == NULL, unregister the specified DCD object.
820 int dcd_register_object(struct dsp_uuid
*uuid_obj
,
821 enum dsp_dcdobjtype obj_type
,
825 char sz_reg_key
[DCD_MAXPATHLENGTH
];
826 char sz_uuid
[MAXUUIDLEN
+ 1];
827 u32 dw_path_size
= 0;
828 u32 dw_key_len
; /* Len of REG key. */
829 char sz_obj_type
[MAX_INT2CHAR_LENGTH
]; /* str. rep. of obj_type. */
830 struct dcd_key_elem
*dcd_key
= NULL
;
832 dev_dbg(bridge
, "%s: object UUID %p, obj_type %d, szPathName %s\n",
833 __func__
, uuid_obj
, obj_type
, psz_path_name
);
836 * Pre-determine final key length. It's length of DCD_REGKEY +
837 * "_\0" + length of sz_obj_type string + terminating NULL.
839 dw_key_len
= strlen(DCD_REGKEY
) + 1 + sizeof(sz_obj_type
) + 1;
841 /* Create proper REG key; concatenate DCD_REGKEY with obj_type. */
842 strncpy(sz_reg_key
, DCD_REGKEY
, strlen(DCD_REGKEY
) + 1);
843 if ((strlen(sz_reg_key
) + strlen("_\0")) < DCD_MAXPATHLENGTH
)
844 strncat(sz_reg_key
, "_\0", 2);
850 status
= snprintf(sz_obj_type
, MAX_INT2CHAR_LENGTH
, "%d", obj_type
);
855 if ((strlen(sz_reg_key
) + strlen(sz_obj_type
)) <
857 strncat(sz_reg_key
, sz_obj_type
,
858 strlen(sz_obj_type
) + 1);
862 /* Create UUID value to set in registry. */
863 snprintf(sz_uuid
, MAXUUIDLEN
, "%pUL", uuid_obj
);
864 if ((strlen(sz_reg_key
) + MAXUUIDLEN
) < DCD_MAXPATHLENGTH
)
865 strncat(sz_reg_key
, sz_uuid
, MAXUUIDLEN
);
874 * If psz_path_name != NULL, perform registration, otherwise,
875 * perform unregistration.
879 dw_path_size
= strlen(psz_path_name
) + 1;
880 spin_lock(&dbdcd_lock
);
881 list_for_each_entry(dcd_key
, ®_key_list
, link
) {
882 /* See if the name matches. */
883 if (!strncmp(dcd_key
->name
, sz_reg_key
,
884 strlen(sz_reg_key
) + 1))
887 spin_unlock(&dbdcd_lock
);
888 if (&dcd_key
->link
== ®_key_list
) {
890 * Add new reg value (UUID+obj_type)
891 * with COFF path info
894 dcd_key
= kmalloc(sizeof(struct dcd_key_elem
),
901 dcd_key
->path
= kmalloc(dw_path_size
, GFP_KERNEL
);
903 if (!dcd_key
->path
) {
909 strncpy(dcd_key
->name
, sz_reg_key
,
910 strlen(sz_reg_key
) + 1);
911 strncpy(dcd_key
->path
, psz_path_name
,
913 spin_lock(&dbdcd_lock
);
914 list_add_tail(&dcd_key
->link
, ®_key_list
);
915 spin_unlock(&dbdcd_lock
);
917 /* Make sure the new data is the same. */
918 if (strncmp(dcd_key
->path
, psz_path_name
,
920 /* The caller needs a different data size! */
921 kfree(dcd_key
->path
);
922 dcd_key
->path
= kmalloc(dw_path_size
,
924 if (dcd_key
->path
== NULL
) {
930 /* We have a match! Copy out the data. */
931 memcpy(dcd_key
->path
, psz_path_name
, dw_path_size
);
933 dev_dbg(bridge
, "%s: psz_path_name=%s, dw_path_size=%d\n",
934 __func__
, psz_path_name
, dw_path_size
);
936 /* Deregister an existing object */
937 spin_lock(&dbdcd_lock
);
938 list_for_each_entry(dcd_key
, ®_key_list
, link
) {
939 if (!strncmp(dcd_key
->name
, sz_reg_key
,
940 strlen(sz_reg_key
) + 1)) {
941 list_del(&dcd_key
->link
);
942 kfree(dcd_key
->path
);
947 spin_unlock(&dbdcd_lock
);
948 if (&dcd_key
->link
== ®_key_list
)
954 * Because the node database has been updated through a
955 * successful object registration/de-registration operation,
956 * we need to reset the object enumeration counter to allow
957 * current enumerations to reflect this update in the node
967 * ======== dcd_unregister_object ========
968 * Call DCD_Register object with psz_path_name set to NULL to
969 * perform actual object de-registration.
971 int dcd_unregister_object(struct dsp_uuid
*uuid_obj
,
972 enum dsp_dcdobjtype obj_type
)
977 * When dcd_register_object is called with NULL as pathname,
978 * it indicates an unregister object operation.
980 status
= dcd_register_object(uuid_obj
, obj_type
, NULL
);
986 **********************************************************************
987 * DCD Helper Functions
988 **********************************************************************
992 * ======== atoi ========
994 * This function converts strings in decimal or hex format to integers.
996 static s32
atoi(char *psz_buf
)
1001 while (isspace(*pch
))
1004 if (*pch
== '-' || *pch
== '+') {
1007 } else if (*pch
&& tolower(pch
[strlen(pch
) - 1]) == 'h') {
1011 return simple_strtoul(pch
, NULL
, base
);
1015 * ======== get_attrs_from_buf ========
1017 * Parse the content of a buffer filled with DSP-side data and
1018 * retrieve an object's attributes from it. IMPORTANT: Assume the
1019 * buffer has been converted from DSP format to GPP format.
1021 static int get_attrs_from_buf(char *psz_buf
, u32 ul_buf_size
,
1022 enum dsp_dcdobjtype obj_type
,
1023 struct dcd_genericobj
*gen_obj
)
1036 case DSP_DCDNODETYPE
:
1038 * Parse COFF sect buffer to retrieve individual tokens used
1039 * to fill in object attrs.
1042 token
= strsep(&psz_cur
, seps
);
1045 gen_obj
->obj_data
.node_obj
.ndb_props
.cb_struct
=
1047 token
= strsep(&psz_cur
, seps
);
1049 /* dsp_uuid ui_node_id */
1050 status
= dcd_uuid_from_string(token
,
1051 &gen_obj
->obj_data
.node_obj
.
1052 ndb_props
.ui_node_id
);
1056 token
= strsep(&psz_cur
, seps
);
1059 token_len
= strlen(token
);
1060 if (token_len
> DSP_MAXNAMELEN
- 1)
1061 token_len
= DSP_MAXNAMELEN
- 1;
1063 strncpy(gen_obj
->obj_data
.node_obj
.ndb_props
.ac_name
,
1065 gen_obj
->obj_data
.node_obj
.ndb_props
.ac_name
[token_len
] = '\0';
1066 token
= strsep(&psz_cur
, seps
);
1068 gen_obj
->obj_data
.node_obj
.ndb_props
.ntype
= atoi(token
);
1069 token
= strsep(&psz_cur
, seps
);
1070 /* u32 cache_on_gpp */
1071 gen_obj
->obj_data
.node_obj
.ndb_props
.cache_on_gpp
= atoi(token
);
1072 token
= strsep(&psz_cur
, seps
);
1073 /* dsp_resourcereqmts dsp_resource_reqmts */
1074 gen_obj
->obj_data
.node_obj
.ndb_props
.dsp_resource_reqmts
.
1075 cb_struct
= (u32
) atoi(token
);
1076 token
= strsep(&psz_cur
, seps
);
1078 gen_obj
->obj_data
.node_obj
.ndb_props
.
1079 dsp_resource_reqmts
.static_data_size
= atoi(token
);
1080 token
= strsep(&psz_cur
, seps
);
1081 gen_obj
->obj_data
.node_obj
.ndb_props
.
1082 dsp_resource_reqmts
.global_data_size
= atoi(token
);
1083 token
= strsep(&psz_cur
, seps
);
1084 gen_obj
->obj_data
.node_obj
.ndb_props
.
1085 dsp_resource_reqmts
.program_mem_size
= atoi(token
);
1086 token
= strsep(&psz_cur
, seps
);
1087 gen_obj
->obj_data
.node_obj
.ndb_props
.
1088 dsp_resource_reqmts
.wc_execution_time
= atoi(token
);
1089 token
= strsep(&psz_cur
, seps
);
1090 gen_obj
->obj_data
.node_obj
.ndb_props
.
1091 dsp_resource_reqmts
.wc_period
= atoi(token
);
1092 token
= strsep(&psz_cur
, seps
);
1094 gen_obj
->obj_data
.node_obj
.ndb_props
.
1095 dsp_resource_reqmts
.wc_deadline
= atoi(token
);
1096 token
= strsep(&psz_cur
, seps
);
1098 gen_obj
->obj_data
.node_obj
.ndb_props
.
1099 dsp_resource_reqmts
.avg_exection_time
= atoi(token
);
1100 token
= strsep(&psz_cur
, seps
);
1102 gen_obj
->obj_data
.node_obj
.ndb_props
.
1103 dsp_resource_reqmts
.minimum_period
= atoi(token
);
1104 token
= strsep(&psz_cur
, seps
);
1107 gen_obj
->obj_data
.node_obj
.ndb_props
.prio
= atoi(token
);
1108 token
= strsep(&psz_cur
, seps
);
1110 /* u32 stack_size */
1111 gen_obj
->obj_data
.node_obj
.ndb_props
.stack_size
= atoi(token
);
1112 token
= strsep(&psz_cur
, seps
);
1114 /* u32 sys_stack_size */
1115 gen_obj
->obj_data
.node_obj
.ndb_props
.sys_stack_size
=
1117 token
= strsep(&psz_cur
, seps
);
1120 gen_obj
->obj_data
.node_obj
.ndb_props
.stack_seg
= atoi(token
);
1121 token
= strsep(&psz_cur
, seps
);
1123 /* u32 message_depth */
1124 gen_obj
->obj_data
.node_obj
.ndb_props
.message_depth
=
1126 token
= strsep(&psz_cur
, seps
);
1128 /* u32 num_input_streams */
1129 gen_obj
->obj_data
.node_obj
.ndb_props
.num_input_streams
=
1131 token
= strsep(&psz_cur
, seps
);
1133 /* u32 num_output_streams */
1134 gen_obj
->obj_data
.node_obj
.ndb_props
.num_output_streams
=
1136 token
= strsep(&psz_cur
, seps
);
1139 gen_obj
->obj_data
.node_obj
.ndb_props
.timeout
= atoi(token
);
1140 token
= strsep(&psz_cur
, seps
);
1142 /* char *str_create_phase_fxn */
1143 token_len
= strlen(token
);
1144 gen_obj
->obj_data
.node_obj
.str_create_phase_fxn
=
1145 kzalloc(token_len
+ 1, GFP_KERNEL
);
1146 strncpy(gen_obj
->obj_data
.node_obj
.str_create_phase_fxn
,
1148 gen_obj
->obj_data
.node_obj
.str_create_phase_fxn
[token_len
] =
1150 token
= strsep(&psz_cur
, seps
);
1152 /* char *str_execute_phase_fxn */
1153 token_len
= strlen(token
);
1154 gen_obj
->obj_data
.node_obj
.str_execute_phase_fxn
=
1155 kzalloc(token_len
+ 1, GFP_KERNEL
);
1156 strncpy(gen_obj
->obj_data
.node_obj
.str_execute_phase_fxn
,
1158 gen_obj
->obj_data
.node_obj
.str_execute_phase_fxn
[token_len
] =
1160 token
= strsep(&psz_cur
, seps
);
1162 /* char *str_delete_phase_fxn */
1163 token_len
= strlen(token
);
1164 gen_obj
->obj_data
.node_obj
.str_delete_phase_fxn
=
1165 kzalloc(token_len
+ 1, GFP_KERNEL
);
1166 strncpy(gen_obj
->obj_data
.node_obj
.str_delete_phase_fxn
,
1168 gen_obj
->obj_data
.node_obj
.str_delete_phase_fxn
[token_len
] =
1170 token
= strsep(&psz_cur
, seps
);
1172 /* Segment id for message buffers */
1173 gen_obj
->obj_data
.node_obj
.msg_segid
= atoi(token
);
1174 token
= strsep(&psz_cur
, seps
);
1176 /* Message notification type */
1177 gen_obj
->obj_data
.node_obj
.msg_notify_type
= atoi(token
);
1178 token
= strsep(&psz_cur
, seps
);
1180 /* char *str_i_alg_name */
1182 token_len
= strlen(token
);
1183 gen_obj
->obj_data
.node_obj
.str_i_alg_name
=
1184 kzalloc(token_len
+ 1, GFP_KERNEL
);
1185 strncpy(gen_obj
->obj_data
.node_obj
.str_i_alg_name
,
1187 gen_obj
->obj_data
.node_obj
.str_i_alg_name
[token_len
] =
1189 token
= strsep(&psz_cur
, seps
);
1192 /* Load type (static, dynamic, or overlay) */
1194 gen_obj
->obj_data
.node_obj
.load_type
= atoi(token
);
1195 token
= strsep(&psz_cur
, seps
);
1198 /* Dynamic load data requirements */
1200 gen_obj
->obj_data
.node_obj
.data_mem_seg_mask
=
1202 token
= strsep(&psz_cur
, seps
);
1205 /* Dynamic load code requirements */
1207 gen_obj
->obj_data
.node_obj
.code_mem_seg_mask
=
1209 token
= strsep(&psz_cur
, seps
);
1212 /* Extract node profiles into node properties */
1215 gen_obj
->obj_data
.node_obj
.ndb_props
.count_profiles
=
1219 gen_obj
->obj_data
.node_obj
.
1220 ndb_props
.count_profiles
; i
++) {
1221 token
= strsep(&psz_cur
, seps
);
1223 /* Heap Size for the node */
1224 gen_obj
->obj_data
.node_obj
.
1225 ndb_props
.node_profiles
[i
].
1226 heap_size
= atoi(token
);
1230 token
= strsep(&psz_cur
, seps
);
1232 gen_obj
->obj_data
.node_obj
.ndb_props
.stack_seg_name
=
1238 case DSP_DCDPROCESSORTYPE
:
1240 * Parse COFF sect buffer to retrieve individual tokens used
1241 * to fill in object attrs.
1244 token
= strsep(&psz_cur
, seps
);
1246 gen_obj
->obj_data
.proc_info
.cb_struct
= atoi(token
);
1247 token
= strsep(&psz_cur
, seps
);
1249 gen_obj
->obj_data
.proc_info
.processor_family
= atoi(token
);
1250 token
= strsep(&psz_cur
, seps
);
1252 gen_obj
->obj_data
.proc_info
.processor_type
= atoi(token
);
1253 token
= strsep(&psz_cur
, seps
);
1255 gen_obj
->obj_data
.proc_info
.clock_rate
= atoi(token
);
1256 token
= strsep(&psz_cur
, seps
);
1258 gen_obj
->obj_data
.proc_info
.internal_mem_size
= atoi(token
);
1259 token
= strsep(&psz_cur
, seps
);
1261 gen_obj
->obj_data
.proc_info
.external_mem_size
= atoi(token
);
1262 token
= strsep(&psz_cur
, seps
);
1264 gen_obj
->obj_data
.proc_info
.processor_id
= atoi(token
);
1265 token
= strsep(&psz_cur
, seps
);
1267 gen_obj
->obj_data
.proc_info
.ty_running_rtos
= atoi(token
);
1268 token
= strsep(&psz_cur
, seps
);
1270 gen_obj
->obj_data
.proc_info
.node_min_priority
= atoi(token
);
1271 token
= strsep(&psz_cur
, seps
);
1273 gen_obj
->obj_data
.proc_info
.node_max_priority
= atoi(token
);
1276 /* Proc object may contain additional(extended) attributes. */
1277 /* attr must match proc.hxx */
1278 for (entry_id
= 0; entry_id
< 7; entry_id
++) {
1279 token
= strsep(&psz_cur
, seps
);
1280 gen_obj
->obj_data
.ext_proc_obj
.ty_tlb
[entry_id
].
1281 gpp_phys
= atoi(token
);
1283 token
= strsep(&psz_cur
, seps
);
1284 gen_obj
->obj_data
.ext_proc_obj
.ty_tlb
[entry_id
].
1285 dsp_virt
= atoi(token
);
1300 * ======== CompressBuffer ========
1302 * Compress the DSP buffer, if necessary, to conform to PC format.
1304 static void compress_buf(char *psz_buf
, u32 ul_buf_size
, s32 char_size
)
1314 for (q
= psz_buf
; q
< (psz_buf
+ ul_buf_size
);) {
1315 ch
= dsp_char2_gpp_char(q
, char_size
);
1318 ch
= dsp_char2_gpp_char(q
, char_size
);
1347 /* NULL out remainder of buffer. */
1353 * ======== dsp_char2_gpp_char ========
1355 * Convert DSP char to host GPP char in a portable manner
1357 static char dsp_char2_gpp_char(char *word
, s32 dsp_char_size
)
1363 for (ch_src
= word
, i
= dsp_char_size
; i
> 0; i
--)
1370 * ======== get_dep_lib_info ========
1372 static int get_dep_lib_info(struct dcd_manager
*hdcd_mgr
,
1373 struct dsp_uuid
*uuid_obj
,
1376 struct dsp_uuid
*dep_lib_uuids
,
1377 bool *prstnt_dep_libs
,
1378 enum nldr_phase phase
)
1380 struct dcd_manager
*dcd_mgr_obj
= hdcd_mgr
;
1381 char *psz_coff_buf
= NULL
;
1383 char *psz_file_name
= NULL
;
1384 struct cod_libraryobj
*lib
= NULL
;
1385 u32 ul_addr
= 0; /* Used by cod_get_section */
1386 u32 ul_len
= 0; /* Used by cod_get_section */
1387 u32 dw_data_size
= COD_MAXPATHLENGTH
;
1390 bool get_uuids
= (dep_lib_uuids
!= NULL
);
1394 /* Initialize to 0 dependent libraries, if only counting number of
1395 * dependent libraries */
1401 /* Allocate a buffer for file name */
1402 psz_file_name
= kzalloc(dw_data_size
, GFP_KERNEL
);
1403 if (psz_file_name
== NULL
) {
1406 /* Get the name of the library */
1407 status
= dcd_get_library_name(hdcd_mgr
, uuid_obj
, psz_file_name
,
1408 &dw_data_size
, phase
, NULL
);
1411 /* Open the library */
1413 status
= cod_open(dcd_mgr_obj
->cod_mgr
, psz_file_name
,
1417 /* Get dependent library section information. */
1418 status
= cod_get_section(lib
, DEPLIBSECT
, &ul_addr
, &ul_len
);
1421 /* Ok, no dependent libraries */
1427 if (status
|| !(ul_len
> 0))
1430 /* Allocate zeroed buffer. */
1431 psz_coff_buf
= kzalloc(ul_len
+ 4, GFP_KERNEL
);
1432 if (psz_coff_buf
== NULL
)
1435 /* Read section contents. */
1436 status
= cod_read_section(lib
, DEPLIBSECT
, psz_coff_buf
, ul_len
);
1440 /* Compress and format DSP buffer to conform to PC format. */
1441 compress_buf(psz_coff_buf
, ul_len
, DSPWORDSIZE
);
1443 /* Read from buffer */
1444 psz_cur
= psz_coff_buf
;
1445 while ((token
= strsep(&psz_cur
, seps
)) && *token
!= '\0') {
1447 if (dep_libs
>= *num_libs
) {
1448 /* Gone beyond the limit */
1451 /* Retrieve UUID string. */
1452 status
= dcd_uuid_from_string(token
,
1458 /* Is this library persistent? */
1459 token
= strsep(&psz_cur
, seps
);
1460 prstnt_dep_libs
[dep_libs
] = atoi(token
);
1464 /* Advanc to next token */
1465 token
= strsep(&psz_cur
, seps
);
1469 /* Just counting number of dependent libraries */
1477 /* Free previously allocated dynamic buffers. */
1478 kfree(psz_file_name
);
1480 kfree(psz_coff_buf
);