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