1 /*
2  * proc.c
3  *
4  * DSP-BIOS Bridge driver support functions for TI OMAP processors.
5  *
6  * Processor interface at the driver level.
7  *
8  * Copyright (C) 2005-2006 Texas Instruments, Inc.
9  *
10  * This package is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License version 2 as
12  * published by the Free Software Foundation.
13  *
14  * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
15  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
16  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
17  */
18 
19 #include <linux/types.h>
20 /* ------------------------------------ Host OS */
21 #include <linux/dma-mapping.h>
22 #include <linux/scatterlist.h>
23 #include <dspbridge/host_os.h>
24 
25 /*  ----------------------------------- DSP/BIOS Bridge */
26 #include <dspbridge/dbdefs.h>
27 
28 /*  ----------------------------------- OS Adaptation Layer */
29 #include <dspbridge/ntfy.h>
30 #include <dspbridge/sync.h>
31 /*  ----------------------------------- Bridge Driver */
32 #include <dspbridge/dspdefs.h>
33 #include <dspbridge/dspdeh.h>
34 /*  ----------------------------------- Platform Manager */
35 #include <dspbridge/cod.h>
36 #include <dspbridge/dev.h>
37 #include <dspbridge/procpriv.h>
38 #include <dspbridge/dmm.h>
39 
40 /*  ----------------------------------- Resource Manager */
41 #include <dspbridge/mgr.h>
42 #include <dspbridge/node.h>
43 #include <dspbridge/nldr.h>
44 #include <dspbridge/rmm.h>
45 
46 /*  ----------------------------------- Others */
47 #include <dspbridge/dbdcd.h>
48 #include <dspbridge/msg.h>
49 #include <dspbridge/dspioctl.h>
50 #include <dspbridge/drv.h>
51 
52 /*  ----------------------------------- This */
53 #include <dspbridge/proc.h>
54 #include <dspbridge/pwr.h>
55 
56 #include <dspbridge/resourcecleanup.h>
57 /*  ----------------------------------- Defines, Data Structures, Typedefs */
58 #define MAXCMDLINELEN       255
59 #define PROC_ENVPROCID      "PROC_ID=%d"
60 #define MAXPROCIDLEN	(8 + 5)
61 #define PROC_DFLT_TIMEOUT   10000	/* Time out in milliseconds */
62 #define PWR_TIMEOUT	 500	/* Sleep/wake timout in msec */
63 #define EXTEND	      "_EXT_END"	/* Extmem end addr in DSP binary */
64 
65 #define DSP_CACHE_LINE 128
66 
67 #define BUFMODE_MASK	(3 << 14)
68 
69 /* Buffer modes from DSP perspective */
70 #define RBUF		0x4000		/* Input buffer */
71 #define WBUF		0x8000		/* Output Buffer */
72 
73 extern struct device *bridge;
74 
75 /*  ----------------------------------- Globals */
76 
77 /* The proc_object structure. */
78 struct proc_object {
79 	struct list_head link;	/* Link to next proc_object */
80 	struct dev_object *dev_obj;	/* Device this PROC represents */
81 	u32 process;		/* Process owning this Processor */
82 	struct mgr_object *mgr_obj;	/* Manager Object Handle */
83 	u32 attach_count;	/* Processor attach count */
84 	u32 processor_id;	/* Processor number */
85 	u32 timeout;		/* Time out count */
86 	enum dsp_procstate proc_state;	/* Processor state */
87 	u32 unit;		/* DDSP unit number */
88 	bool is_already_attached;	/*
89 					 * True if the Device below has
90 					 * GPP Client attached
91 					 */
92 	struct ntfy_object *ntfy_obj;	/* Manages  notifications */
93 	/* Bridge Context Handle */
94 	struct bridge_dev_context *bridge_context;
95 	/* Function interface to Bridge driver */
96 	struct bridge_drv_interface *intf_fxns;
97 	char *last_coff;
98 	struct list_head proc_list;
99 };
100 
101 DEFINE_MUTEX(proc_lock);	/* For critical sections */
102 
103 /*  ----------------------------------- Function Prototypes */
104 static int proc_monitor(struct proc_object *proc_obj);
105 static s32 get_envp_count(char **envp);
106 static char **prepend_envp(char **new_envp, char **envp, s32 envp_elems,
107 			   s32 cnew_envp, char *sz_var);
108 
109 /* remember mapping information */
add_mapping_info(struct process_context * pr_ctxt,u32 mpu_addr,u32 dsp_addr,u32 size)110 static struct dmm_map_object *add_mapping_info(struct process_context *pr_ctxt,
111 				u32 mpu_addr, u32 dsp_addr, u32 size)
112 {
113 	struct dmm_map_object *map_obj;
114 
115 	u32 num_usr_pgs = size / PG_SIZE4K;
116 
117 	pr_debug("%s: adding map info: mpu_addr 0x%x virt 0x%x size 0x%x\n",
118 						__func__, mpu_addr,
119 						dsp_addr, size);
120 
121 	map_obj = kzalloc(sizeof(struct dmm_map_object), GFP_KERNEL);
122 	if (!map_obj) {
123 		pr_err("%s: kzalloc failed\n", __func__);
124 		return NULL;
125 	}
126 	INIT_LIST_HEAD(&map_obj->link);
127 
128 	map_obj->pages = kcalloc(num_usr_pgs, sizeof(struct page *),
129 							GFP_KERNEL);
130 	if (!map_obj->pages) {
131 		pr_err("%s: kzalloc failed\n", __func__);
132 		kfree(map_obj);
133 		return NULL;
134 	}
135 
136 	map_obj->mpu_addr = mpu_addr;
137 	map_obj->dsp_addr = dsp_addr;
138 	map_obj->size = size;
139 	map_obj->num_usr_pgs = num_usr_pgs;
140 
141 	spin_lock(&pr_ctxt->dmm_map_lock);
142 	list_add(&map_obj->link, &pr_ctxt->dmm_map_list);
143 	spin_unlock(&pr_ctxt->dmm_map_lock);
144 
145 	return map_obj;
146 }
147 
match_exact_map_obj(struct dmm_map_object * map_obj,u32 dsp_addr,u32 size)148 static int match_exact_map_obj(struct dmm_map_object *map_obj,
149 					u32 dsp_addr, u32 size)
150 {
151 	if (map_obj->dsp_addr == dsp_addr && map_obj->size != size)
152 		pr_err("%s: addr match (0x%x), size don't (0x%x != 0x%x)\n",
153 				__func__, dsp_addr, map_obj->size, size);
154 
155 	return map_obj->dsp_addr == dsp_addr &&
156 		map_obj->size == size;
157 }
158 
remove_mapping_information(struct process_context * pr_ctxt,u32 dsp_addr,u32 size)159 static void remove_mapping_information(struct process_context *pr_ctxt,
160 						u32 dsp_addr, u32 size)
161 {
162 	struct dmm_map_object *map_obj;
163 
164 	pr_debug("%s: looking for virt 0x%x size 0x%x\n", __func__,
165 							dsp_addr, size);
166 
167 	spin_lock(&pr_ctxt->dmm_map_lock);
168 	list_for_each_entry(map_obj, &pr_ctxt->dmm_map_list, link) {
169 		pr_debug("%s: candidate: mpu_addr 0x%x virt 0x%x size 0x%x\n",
170 							__func__,
171 							map_obj->mpu_addr,
172 							map_obj->dsp_addr,
173 							map_obj->size);
174 
175 		if (match_exact_map_obj(map_obj, dsp_addr, size)) {
176 			pr_debug("%s: match, deleting map info\n", __func__);
177 			list_del(&map_obj->link);
178 			kfree(map_obj->dma_info.sg);
179 			kfree(map_obj->pages);
180 			kfree(map_obj);
181 			goto out;
182 		}
183 		pr_debug("%s: candidate didn't match\n", __func__);
184 	}
185 
186 	pr_err("%s: failed to find given map info\n", __func__);
187 out:
188 	spin_unlock(&pr_ctxt->dmm_map_lock);
189 }
190 
match_containing_map_obj(struct dmm_map_object * map_obj,u32 mpu_addr,u32 size)191 static int match_containing_map_obj(struct dmm_map_object *map_obj,
192 					u32 mpu_addr, u32 size)
193 {
194 	u32 map_obj_end = map_obj->mpu_addr + map_obj->size;
195 
196 	return mpu_addr >= map_obj->mpu_addr &&
197 		mpu_addr + size <= map_obj_end;
198 }
199 
find_containing_mapping(struct process_context * pr_ctxt,u32 mpu_addr,u32 size)200 static struct dmm_map_object *find_containing_mapping(
201 				struct process_context *pr_ctxt,
202 				u32 mpu_addr, u32 size)
203 {
204 	struct dmm_map_object *map_obj;
205 	pr_debug("%s: looking for mpu_addr 0x%x size 0x%x\n", __func__,
206 						mpu_addr, size);
207 
208 	spin_lock(&pr_ctxt->dmm_map_lock);
209 	list_for_each_entry(map_obj, &pr_ctxt->dmm_map_list, link) {
210 		pr_debug("%s: candidate: mpu_addr 0x%x virt 0x%x size 0x%x\n",
211 						__func__,
212 						map_obj->mpu_addr,
213 						map_obj->dsp_addr,
214 						map_obj->size);
215 		if (match_containing_map_obj(map_obj, mpu_addr, size)) {
216 			pr_debug("%s: match!\n", __func__);
217 			goto out;
218 		}
219 
220 		pr_debug("%s: no match!\n", __func__);
221 	}
222 
223 	map_obj = NULL;
224 out:
225 	spin_unlock(&pr_ctxt->dmm_map_lock);
226 	return map_obj;
227 }
228 
find_first_page_in_cache(struct dmm_map_object * map_obj,unsigned long mpu_addr)229 static int find_first_page_in_cache(struct dmm_map_object *map_obj,
230 					unsigned long mpu_addr)
231 {
232 	u32 mapped_base_page = map_obj->mpu_addr >> PAGE_SHIFT;
233 	u32 requested_base_page = mpu_addr >> PAGE_SHIFT;
234 	int pg_index = requested_base_page - mapped_base_page;
235 
236 	if (pg_index < 0 || pg_index >= map_obj->num_usr_pgs) {
237 		pr_err("%s: failed (got %d)\n", __func__, pg_index);
238 		return -1;
239 	}
240 
241 	pr_debug("%s: first page is %d\n", __func__, pg_index);
242 	return pg_index;
243 }
244 
get_mapping_page(struct dmm_map_object * map_obj,int pg_i)245 static inline struct page *get_mapping_page(struct dmm_map_object *map_obj,
246 								int pg_i)
247 {
248 	pr_debug("%s: looking for pg_i %d, num_usr_pgs: %d\n", __func__,
249 					pg_i, map_obj->num_usr_pgs);
250 
251 	if (pg_i < 0 || pg_i >= map_obj->num_usr_pgs) {
252 		pr_err("%s: requested pg_i %d is out of mapped range\n",
253 				__func__, pg_i);
254 		return NULL;
255 	}
256 
257 	return map_obj->pages[pg_i];
258 }
259 
260 /*
261  *  ======== proc_attach ========
262  *  Purpose:
263  *      Prepare for communication with a particular DSP processor, and return
264  *      a handle to the processor object.
265  */
266 int
proc_attach(u32 processor_id,const struct dsp_processorattrin * attr_in,void ** ph_processor,struct process_context * pr_ctxt)267 proc_attach(u32 processor_id,
268 	    const struct dsp_processorattrin *attr_in,
269 	    void **ph_processor, struct process_context *pr_ctxt)
270 {
271 	int status = 0;
272 	struct dev_object *hdev_obj;
273 	struct proc_object *p_proc_object = NULL;
274 	struct mgr_object *hmgr_obj = NULL;
275 	struct drv_object *hdrv_obj = NULL;
276 	struct drv_data *drv_datap = dev_get_drvdata(bridge);
277 	u8 dev_type;
278 
279 	if (pr_ctxt->processor) {
280 		*ph_processor = pr_ctxt->processor;
281 		return status;
282 	}
283 
284 	/* Get the Driver and Manager Object Handles */
285 	if (!drv_datap || !drv_datap->drv_object || !drv_datap->mgr_object) {
286 		status = -ENODATA;
287 		pr_err("%s: Failed to get object handles\n", __func__);
288 	} else {
289 		hdrv_obj = drv_datap->drv_object;
290 		hmgr_obj = drv_datap->mgr_object;
291 	}
292 
293 	if (!status) {
294 		/* Get the Device Object */
295 		status = drv_get_dev_object(processor_id, hdrv_obj, &hdev_obj);
296 	}
297 	if (!status)
298 		status = dev_get_dev_type(hdev_obj, &dev_type);
299 
300 	if (status)
301 		goto func_end;
302 
303 	/* If we made it this far, create the Proceesor object: */
304 	p_proc_object = kzalloc(sizeof(struct proc_object), GFP_KERNEL);
305 	/* Fill out the Processor Object: */
306 	if (p_proc_object == NULL) {
307 		status = -ENOMEM;
308 		goto func_end;
309 	}
310 	p_proc_object->dev_obj = hdev_obj;
311 	p_proc_object->mgr_obj = hmgr_obj;
312 	p_proc_object->processor_id = dev_type;
313 	/* Store TGID instead of process handle */
314 	p_proc_object->process = current->tgid;
315 
316 	INIT_LIST_HEAD(&p_proc_object->proc_list);
317 
318 	if (attr_in)
319 		p_proc_object->timeout = attr_in->timeout;
320 	else
321 		p_proc_object->timeout = PROC_DFLT_TIMEOUT;
322 
323 	status = dev_get_intf_fxns(hdev_obj, &p_proc_object->intf_fxns);
324 	if (!status) {
325 		status = dev_get_bridge_context(hdev_obj,
326 					     &p_proc_object->bridge_context);
327 		if (status)
328 			kfree(p_proc_object);
329 	} else
330 		kfree(p_proc_object);
331 
332 	if (status)
333 		goto func_end;
334 
335 	/* Create the Notification Object */
336 	/* This is created with no event mask, no notify mask
337 	 * and no valid handle to the notification. They all get
338 	 * filled up when proc_register_notify is called */
339 	p_proc_object->ntfy_obj = kmalloc(sizeof(struct ntfy_object),
340 							GFP_KERNEL);
341 	if (p_proc_object->ntfy_obj)
342 		ntfy_init(p_proc_object->ntfy_obj);
343 	else
344 		status = -ENOMEM;
345 
346 	if (!status) {
347 		/* Insert the Processor Object into the DEV List.
348 		 * Return handle to this Processor Object:
349 		 * Find out if the Device is already attached to a
350 		 * Processor. If so, return AlreadyAttached status */
351 		status = dev_insert_proc_object(p_proc_object->dev_obj,
352 						(u32) p_proc_object,
353 						&p_proc_object->
354 						is_already_attached);
355 		if (!status) {
356 			if (p_proc_object->is_already_attached)
357 				status = 0;
358 		} else {
359 			if (p_proc_object->ntfy_obj) {
360 				ntfy_delete(p_proc_object->ntfy_obj);
361 				kfree(p_proc_object->ntfy_obj);
362 			}
363 
364 			kfree(p_proc_object);
365 		}
366 		if (!status) {
367 			*ph_processor = (void *)p_proc_object;
368 			pr_ctxt->processor = *ph_processor;
369 			(void)proc_notify_clients(p_proc_object,
370 						  DSP_PROCESSORATTACH);
371 		}
372 	} else {
373 		/* Don't leak memory if status is failed */
374 		kfree(p_proc_object);
375 	}
376 func_end:
377 	return status;
378 }
379 
get_exec_file(struct cfg_devnode * dev_node_obj,struct dev_object * hdev_obj,u32 size,char * exec_file)380 static int get_exec_file(struct cfg_devnode *dev_node_obj,
381 				struct dev_object *hdev_obj,
382 				u32 size, char *exec_file)
383 {
384 	u8 dev_type;
385 	s32 len;
386 	struct drv_data *drv_datap = dev_get_drvdata(bridge);
387 
388 	dev_get_dev_type(hdev_obj, (u8 *) &dev_type);
389 
390 	if (!exec_file)
391 		return -EFAULT;
392 
393 	if (dev_type == DSP_UNIT) {
394 		if (!drv_datap || !drv_datap->base_img)
395 			return -EFAULT;
396 
397 		if (strlen(drv_datap->base_img) > size)
398 			return -EINVAL;
399 
400 		strcpy(exec_file, drv_datap->base_img);
401 	} else if (dev_type == IVA_UNIT && iva_img) {
402 		len = strlen(iva_img);
403 		strncpy(exec_file, iva_img, len + 1);
404 	} else {
405 		return -ENOENT;
406 	}
407 
408 	return 0;
409 }
410 
411 /*
412  *  ======== proc_auto_start ======== =
413  *  Purpose:
414  *      A Particular device gets loaded with the default image
415  *      if the AutoStart flag is set.
416  *  Parameters:
417  *      hdev_obj:     Handle to the Device
418  *  Returns:
419  *      0:   On Successful Loading
420  *      -EPERM  General Failure
421  *  Requires:
422  *      hdev_obj != NULL
423  *  Ensures:
424  */
proc_auto_start(struct cfg_devnode * dev_node_obj,struct dev_object * hdev_obj)425 int proc_auto_start(struct cfg_devnode *dev_node_obj,
426 			   struct dev_object *hdev_obj)
427 {
428 	int status = -EPERM;
429 	struct proc_object *p_proc_object;
430 	char sz_exec_file[MAXCMDLINELEN];
431 	char *argv[2];
432 	struct mgr_object *hmgr_obj = NULL;
433 	struct drv_data *drv_datap = dev_get_drvdata(bridge);
434 	u8 dev_type;
435 
436 	/* Create a Dummy PROC Object */
437 	if (!drv_datap || !drv_datap->mgr_object) {
438 		status = -ENODATA;
439 		pr_err("%s: Failed to retrieve the object handle\n", __func__);
440 		goto func_end;
441 	} else {
442 		hmgr_obj = drv_datap->mgr_object;
443 	}
444 
445 	p_proc_object = kzalloc(sizeof(struct proc_object), GFP_KERNEL);
446 	if (p_proc_object == NULL) {
447 		status = -ENOMEM;
448 		goto func_end;
449 	}
450 	p_proc_object->dev_obj = hdev_obj;
451 	p_proc_object->mgr_obj = hmgr_obj;
452 	status = dev_get_intf_fxns(hdev_obj, &p_proc_object->intf_fxns);
453 	if (!status)
454 		status = dev_get_bridge_context(hdev_obj,
455 					     &p_proc_object->bridge_context);
456 	if (status)
457 		goto func_cont;
458 
459 	/* Stop the Device, put it into standby mode */
460 	status = proc_stop(p_proc_object);
461 
462 	if (status)
463 		goto func_cont;
464 
465 	/* Get the default executable for this board... */
466 	dev_get_dev_type(hdev_obj, (u8 *) &dev_type);
467 	p_proc_object->processor_id = dev_type;
468 	status = get_exec_file(dev_node_obj, hdev_obj, sizeof(sz_exec_file),
469 			       sz_exec_file);
470 	if (!status) {
471 		argv[0] = sz_exec_file;
472 		argv[1] = NULL;
473 		/* ...and try to load it: */
474 		status = proc_load(p_proc_object, 1, (const char **)argv, NULL);
475 		if (!status)
476 			status = proc_start(p_proc_object);
477 	}
478 	kfree(p_proc_object->last_coff);
479 	p_proc_object->last_coff = NULL;
480 func_cont:
481 	kfree(p_proc_object);
482 func_end:
483 	return status;
484 }
485 
486 /*
487  *  ======== proc_ctrl ========
488  *  Purpose:
489  *      Pass control information to the GPP device driver managing the
490  *      DSP processor.
491  *
492  *      This will be an OEM-only function, and not part of the DSP/BIOS Bridge
493  *      application developer's API.
494  *      Call the bridge_dev_ctrl fxn with the Argument. This is a Synchronous
495  *      Operation. arg can be null.
496  */
proc_ctrl(void * hprocessor,u32 dw_cmd,struct dsp_cbdata * arg)497 int proc_ctrl(void *hprocessor, u32 dw_cmd, struct dsp_cbdata * arg)
498 {
499 	int status = 0;
500 	struct proc_object *p_proc_object = hprocessor;
501 	u32 timeout = 0;
502 
503 	if (p_proc_object) {
504 		/* intercept PWR deep sleep command */
505 		if (dw_cmd == BRDIOCTL_DEEPSLEEP) {
506 			timeout = arg->cb_data;
507 			status = pwr_sleep_dsp(PWR_DEEPSLEEP, timeout);
508 		}
509 		/* intercept PWR emergency sleep command */
510 		else if (dw_cmd == BRDIOCTL_EMERGENCYSLEEP) {
511 			timeout = arg->cb_data;
512 			status = pwr_sleep_dsp(PWR_EMERGENCYDEEPSLEEP, timeout);
513 		} else if (dw_cmd == PWR_DEEPSLEEP) {
514 			/* timeout = arg->cb_data; */
515 			status = pwr_sleep_dsp(PWR_DEEPSLEEP, timeout);
516 		}
517 		/* intercept PWR wake commands */
518 		else if (dw_cmd == BRDIOCTL_WAKEUP) {
519 			timeout = arg->cb_data;
520 			status = pwr_wake_dsp(timeout);
521 		} else if (dw_cmd == PWR_WAKEUP) {
522 			/* timeout = arg->cb_data; */
523 			status = pwr_wake_dsp(timeout);
524 		} else
525 		    if (!((*p_proc_object->intf_fxns->dev_cntrl)
526 				      (p_proc_object->bridge_context, dw_cmd,
527 				       arg))) {
528 			status = 0;
529 		} else {
530 			status = -EPERM;
531 		}
532 	} else {
533 		status = -EFAULT;
534 	}
535 
536 	return status;
537 }
538 
539 /*
540  *  ======== proc_detach ========
541  *  Purpose:
542  *      Destroys the  Processor Object. Removes the notification from the Dev
543  *      List.
544  */
proc_detach(struct process_context * pr_ctxt)545 int proc_detach(struct process_context *pr_ctxt)
546 {
547 	int status = 0;
548 	struct proc_object *p_proc_object = NULL;
549 
550 	p_proc_object = (struct proc_object *)pr_ctxt->processor;
551 
552 	if (p_proc_object) {
553 		/* Notify the Client */
554 		ntfy_notify(p_proc_object->ntfy_obj, DSP_PROCESSORDETACH);
555 		/* Remove the notification memory */
556 		if (p_proc_object->ntfy_obj) {
557 			ntfy_delete(p_proc_object->ntfy_obj);
558 			kfree(p_proc_object->ntfy_obj);
559 		}
560 
561 		kfree(p_proc_object->last_coff);
562 		p_proc_object->last_coff = NULL;
563 		/* Remove the Proc from the DEV List */
564 		(void)dev_remove_proc_object(p_proc_object->dev_obj,
565 					     (u32) p_proc_object);
566 		/* Free the Processor Object */
567 		kfree(p_proc_object);
568 		pr_ctxt->processor = NULL;
569 	} else {
570 		status = -EFAULT;
571 	}
572 
573 	return status;
574 }
575 
576 /*
577  *  ======== proc_enum_nodes ========
578  *  Purpose:
579  *      Enumerate and get configuration information about nodes allocated
580  *      on a DSP processor.
581  */
proc_enum_nodes(void * hprocessor,void ** node_tab,u32 node_tab_size,u32 * pu_num_nodes,u32 * pu_allocated)582 int proc_enum_nodes(void *hprocessor, void **node_tab,
583 			   u32 node_tab_size, u32 *pu_num_nodes,
584 			   u32 *pu_allocated)
585 {
586 	int status = -EPERM;
587 	struct proc_object *p_proc_object = (struct proc_object *)hprocessor;
588 	struct node_mgr *hnode_mgr = NULL;
589 
590 	if (p_proc_object) {
591 		if (!(dev_get_node_manager(p_proc_object->dev_obj,
592 						       &hnode_mgr))) {
593 			if (hnode_mgr) {
594 				status = node_enum_nodes(hnode_mgr, node_tab,
595 							 node_tab_size,
596 							 pu_num_nodes,
597 							 pu_allocated);
598 			}
599 		}
600 	} else {
601 		status = -EFAULT;
602 	}
603 
604 	return status;
605 }
606 
607 /* Cache operation against kernel address instead of users */
build_dma_sg(struct dmm_map_object * map_obj,unsigned long start,ssize_t len,int pg_i)608 static int build_dma_sg(struct dmm_map_object *map_obj, unsigned long start,
609 						ssize_t len, int pg_i)
610 {
611 	struct page *page;
612 	unsigned long offset;
613 	ssize_t rest;
614 	int ret = 0, i = 0;
615 	struct scatterlist *sg = map_obj->dma_info.sg;
616 
617 	while (len) {
618 		page = get_mapping_page(map_obj, pg_i);
619 		if (!page) {
620 			pr_err("%s: no page for %08lx\n", __func__, start);
621 			ret = -EINVAL;
622 			goto out;
623 		} else if (IS_ERR(page)) {
624 			pr_err("%s: err page for %08lx(%lu)\n", __func__, start,
625 			       PTR_ERR(page));
626 			ret = PTR_ERR(page);
627 			goto out;
628 		}
629 
630 		offset = start & ~PAGE_MASK;
631 		rest = min_t(ssize_t, PAGE_SIZE - offset, len);
632 
633 		sg_set_page(&sg[i], page, rest, offset);
634 
635 		len -= rest;
636 		start += rest;
637 		pg_i++, i++;
638 	}
639 
640 	if (i != map_obj->dma_info.num_pages) {
641 		pr_err("%s: bad number of sg iterations\n", __func__);
642 		ret = -EFAULT;
643 		goto out;
644 	}
645 
646 out:
647 	return ret;
648 }
649 
memory_regain_ownership(struct dmm_map_object * map_obj,unsigned long start,ssize_t len,enum dma_data_direction dir)650 static int memory_regain_ownership(struct dmm_map_object *map_obj,
651 		unsigned long start, ssize_t len, enum dma_data_direction dir)
652 {
653 	int ret = 0;
654 	unsigned long first_data_page = start >> PAGE_SHIFT;
655 	unsigned long last_data_page = ((u32)(start + len - 1) >> PAGE_SHIFT);
656 	/* calculating the number of pages this area spans */
657 	unsigned long num_pages = last_data_page - first_data_page + 1;
658 	struct bridge_dma_map_info *dma_info = &map_obj->dma_info;
659 
660 	if (!dma_info->sg)
661 		goto out;
662 
663 	if (dma_info->dir != dir || dma_info->num_pages != num_pages) {
664 		pr_err("%s: dma info doesn't match given params\n", __func__);
665 		return -EINVAL;
666 	}
667 
668 	dma_unmap_sg(bridge, dma_info->sg, num_pages, dma_info->dir);
669 
670 	pr_debug("%s: dma_map_sg unmapped\n", __func__);
671 
672 	kfree(dma_info->sg);
673 
674 	map_obj->dma_info.sg = NULL;
675 
676 out:
677 	return ret;
678 }
679 
680 /* Cache operation against kernel address instead of users */
memory_give_ownership(struct dmm_map_object * map_obj,unsigned long start,ssize_t len,enum dma_data_direction dir)681 static int memory_give_ownership(struct dmm_map_object *map_obj,
682 		unsigned long start, ssize_t len, enum dma_data_direction dir)
683 {
684 	int pg_i, ret, sg_num;
685 	struct scatterlist *sg;
686 	unsigned long first_data_page = start >> PAGE_SHIFT;
687 	unsigned long last_data_page = ((u32)(start + len - 1) >> PAGE_SHIFT);
688 	/* calculating the number of pages this area spans */
689 	unsigned long num_pages = last_data_page - first_data_page + 1;
690 
691 	pg_i = find_first_page_in_cache(map_obj, start);
692 	if (pg_i < 0) {
693 		pr_err("%s: failed to find first page in cache\n", __func__);
694 		ret = -EINVAL;
695 		goto out;
696 	}
697 
698 	sg = kcalloc(num_pages, sizeof(*sg), GFP_KERNEL);
699 	if (!sg) {
700 		pr_err("%s: kcalloc failed\n", __func__);
701 		ret = -ENOMEM;
702 		goto out;
703 	}
704 
705 	sg_init_table(sg, num_pages);
706 
707 	/* cleanup a previous sg allocation */
708 	/* this may happen if application doesn't signal for e/o DMA */
709 	kfree(map_obj->dma_info.sg);
710 
711 	map_obj->dma_info.sg = sg;
712 	map_obj->dma_info.dir = dir;
713 	map_obj->dma_info.num_pages = num_pages;
714 
715 	ret = build_dma_sg(map_obj, start, len, pg_i);
716 	if (ret)
717 		goto kfree_sg;
718 
719 	sg_num = dma_map_sg(bridge, sg, num_pages, dir);
720 	if (sg_num < 1) {
721 		pr_err("%s: dma_map_sg failed: %d\n", __func__, sg_num);
722 		ret = -EFAULT;
723 		goto kfree_sg;
724 	}
725 
726 	pr_debug("%s: dma_map_sg mapped %d elements\n", __func__, sg_num);
727 	map_obj->dma_info.sg_num = sg_num;
728 
729 	return 0;
730 
731 kfree_sg:
732 	kfree(sg);
733 	map_obj->dma_info.sg = NULL;
734 out:
735 	return ret;
736 }
737 
proc_begin_dma(void * hprocessor,void * pmpu_addr,u32 ul_size,enum dma_data_direction dir)738 int proc_begin_dma(void *hprocessor, void *pmpu_addr, u32 ul_size,
739 				enum dma_data_direction dir)
740 {
741 	/* Keep STATUS here for future additions to this function */
742 	int status = 0;
743 	struct process_context *pr_ctxt = (struct process_context *) hprocessor;
744 	struct dmm_map_object *map_obj;
745 
746 	if (!pr_ctxt) {
747 		status = -EFAULT;
748 		goto err_out;
749 	}
750 
751 	pr_debug("%s: addr 0x%x, size 0x%x, type %d\n", __func__,
752 							(u32)pmpu_addr,
753 							ul_size, dir);
754 
755 	mutex_lock(&proc_lock);
756 
757 	/* find requested memory are in cached mapping information */
758 	map_obj = find_containing_mapping(pr_ctxt, (u32) pmpu_addr, ul_size);
759 	if (!map_obj) {
760 		pr_err("%s: find_containing_mapping failed\n", __func__);
761 		status = -EFAULT;
762 		goto no_map;
763 	}
764 
765 	if (memory_give_ownership(map_obj, (u32) pmpu_addr, ul_size, dir)) {
766 		pr_err("%s: InValid address parameters %p %x\n",
767 			       __func__, pmpu_addr, ul_size);
768 		status = -EFAULT;
769 	}
770 
771 no_map:
772 	mutex_unlock(&proc_lock);
773 err_out:
774 
775 	return status;
776 }
777 
proc_end_dma(void * hprocessor,void * pmpu_addr,u32 ul_size,enum dma_data_direction dir)778 int proc_end_dma(void *hprocessor, void *pmpu_addr, u32 ul_size,
779 			enum dma_data_direction dir)
780 {
781 	/* Keep STATUS here for future additions to this function */
782 	int status = 0;
783 	struct process_context *pr_ctxt = (struct process_context *) hprocessor;
784 	struct dmm_map_object *map_obj;
785 
786 	if (!pr_ctxt) {
787 		status = -EFAULT;
788 		goto err_out;
789 	}
790 
791 	pr_debug("%s: addr 0x%x, size 0x%x, type %d\n", __func__,
792 							(u32)pmpu_addr,
793 							ul_size, dir);
794 
795 	mutex_lock(&proc_lock);
796 
797 	/* find requested memory are in cached mapping information */
798 	map_obj = find_containing_mapping(pr_ctxt, (u32) pmpu_addr, ul_size);
799 	if (!map_obj) {
800 		pr_err("%s: find_containing_mapping failed\n", __func__);
801 		status = -EFAULT;
802 		goto no_map;
803 	}
804 
805 	if (memory_regain_ownership(map_obj, (u32) pmpu_addr, ul_size, dir)) {
806 		pr_err("%s: InValid address parameters %p %x\n",
807 		       __func__, pmpu_addr, ul_size);
808 		status = -EFAULT;
809 	}
810 
811 no_map:
812 	mutex_unlock(&proc_lock);
813 err_out:
814 	return status;
815 }
816 
817 /*
818  *  ======== proc_flush_memory ========
819  *  Purpose:
820  *     Flush cache
821  */
proc_flush_memory(void * hprocessor,void * pmpu_addr,u32 ul_size,u32 ul_flags)822 int proc_flush_memory(void *hprocessor, void *pmpu_addr,
823 			     u32 ul_size, u32 ul_flags)
824 {
825 	enum dma_data_direction dir = DMA_BIDIRECTIONAL;
826 
827 	return proc_begin_dma(hprocessor, pmpu_addr, ul_size, dir);
828 }
829 
830 /*
831  *  ======== proc_invalidate_memory ========
832  *  Purpose:
833  *     Invalidates the memory specified
834  */
proc_invalidate_memory(void * hprocessor,void * pmpu_addr,u32 size)835 int proc_invalidate_memory(void *hprocessor, void *pmpu_addr, u32 size)
836 {
837 	enum dma_data_direction dir = DMA_FROM_DEVICE;
838 
839 	return proc_begin_dma(hprocessor, pmpu_addr, size, dir);
840 }
841 
842 /*
843  *  ======== proc_get_resource_info ========
844  *  Purpose:
845  *      Enumerate the resources currently available on a processor.
846  */
proc_get_resource_info(void * hprocessor,u32 resource_type,struct dsp_resourceinfo * resource_info,u32 resource_info_size)847 int proc_get_resource_info(void *hprocessor, u32 resource_type,
848 				  struct dsp_resourceinfo *resource_info,
849 				  u32 resource_info_size)
850 {
851 	int status = -EPERM;
852 	struct proc_object *p_proc_object = (struct proc_object *)hprocessor;
853 	struct node_mgr *hnode_mgr = NULL;
854 	struct nldr_object *nldr_obj = NULL;
855 	struct rmm_target_obj *rmm = NULL;
856 	struct io_mgr *hio_mgr = NULL;	/* IO manager handle */
857 
858 	if (!p_proc_object) {
859 		status = -EFAULT;
860 		goto func_end;
861 	}
862 	switch (resource_type) {
863 	case DSP_RESOURCE_DYNDARAM:
864 	case DSP_RESOURCE_DYNSARAM:
865 	case DSP_RESOURCE_DYNEXTERNAL:
866 	case DSP_RESOURCE_DYNSRAM:
867 		status = dev_get_node_manager(p_proc_object->dev_obj,
868 					      &hnode_mgr);
869 		if (!hnode_mgr) {
870 			status = -EFAULT;
871 			goto func_end;
872 		}
873 
874 		status = node_get_nldr_obj(hnode_mgr, &nldr_obj);
875 		if (!status) {
876 			status = nldr_get_rmm_manager(nldr_obj, &rmm);
877 			if (rmm) {
878 				if (!rmm_stat(rmm,
879 					      (enum dsp_memtype)resource_type,
880 					      (struct dsp_memstat *)
881 					      &(resource_info->result.
882 						mem_stat)))
883 					status = -EINVAL;
884 			} else {
885 				status = -EFAULT;
886 			}
887 		}
888 		break;
889 	case DSP_RESOURCE_PROCLOAD:
890 		status = dev_get_io_mgr(p_proc_object->dev_obj, &hio_mgr);
891 		if (hio_mgr)
892 			status =
893 			    p_proc_object->intf_fxns->
894 			    io_get_proc_load(hio_mgr,
895 						 (struct dsp_procloadstat *)
896 						 &(resource_info->result.
897 						   proc_load_stat));
898 		else
899 			status = -EFAULT;
900 		break;
901 	default:
902 		status = -EPERM;
903 		break;
904 	}
905 func_end:
906 	return status;
907 }
908 
909 /*
910  *  ======== proc_get_dev_object ========
911  *  Purpose:
912  *      Return the Dev Object handle for a given Processor.
913  *
914  */
proc_get_dev_object(void * hprocessor,struct dev_object ** device_obj)915 int proc_get_dev_object(void *hprocessor,
916 			       struct dev_object **device_obj)
917 {
918 	int status = -EPERM;
919 	struct proc_object *p_proc_object = (struct proc_object *)hprocessor;
920 
921 	if (p_proc_object) {
922 		*device_obj = p_proc_object->dev_obj;
923 		status = 0;
924 	} else {
925 		*device_obj = NULL;
926 		status = -EFAULT;
927 	}
928 
929 	return status;
930 }
931 
932 /*
933  *  ======== proc_get_state ========
934  *  Purpose:
935  *      Report the state of the specified DSP processor.
936  */
proc_get_state(void * hprocessor,struct dsp_processorstate * proc_state_obj,u32 state_info_size)937 int proc_get_state(void *hprocessor,
938 			  struct dsp_processorstate *proc_state_obj,
939 			  u32 state_info_size)
940 {
941 	int status = 0;
942 	struct proc_object *p_proc_object = (struct proc_object *)hprocessor;
943 	int brd_status;
944 
945 	if (p_proc_object) {
946 		/* First, retrieve BRD state information */
947 		status = (*p_proc_object->intf_fxns->brd_status)
948 		    (p_proc_object->bridge_context, &brd_status);
949 		if (!status) {
950 			switch (brd_status) {
951 			case BRD_STOPPED:
952 				proc_state_obj->proc_state = PROC_STOPPED;
953 				break;
954 			case BRD_SLEEP_TRANSITION:
955 			case BRD_DSP_HIBERNATION:
956 				/* Fall through */
957 			case BRD_RUNNING:
958 				proc_state_obj->proc_state = PROC_RUNNING;
959 				break;
960 			case BRD_LOADED:
961 				proc_state_obj->proc_state = PROC_LOADED;
962 				break;
963 			case BRD_ERROR:
964 				proc_state_obj->proc_state = PROC_ERROR;
965 				break;
966 			default:
967 				proc_state_obj->proc_state = 0xFF;
968 				status = -EPERM;
969 				break;
970 			}
971 		}
972 	} else {
973 		status = -EFAULT;
974 	}
975 	dev_dbg(bridge, "%s, results: status: 0x%x proc_state_obj: 0x%x\n",
976 		__func__, status, proc_state_obj->proc_state);
977 	return status;
978 }
979 
980 /*
981  *  ======== proc_get_trace ========
982  *  Purpose:
983  *      Retrieve the current contents of the trace buffer, located on the
984  *      Processor.  Predefined symbols for the trace buffer must have been
985  *      configured into the DSP executable.
986  *  Details:
987  *      We support using the symbols SYS_PUTCBEG and SYS_PUTCEND to define a
988  *      trace buffer, only.  Treat it as an undocumented feature.
989  *      This call is destructive, meaning the processor is placed in the monitor
990  *      state as a result of this function.
991  */
proc_get_trace(void * hprocessor,u8 * pbuf,u32 max_size)992 int proc_get_trace(void *hprocessor, u8 * pbuf, u32 max_size)
993 {
994 	int status;
995 	status = -ENOSYS;
996 	return status;
997 }
998 
999 /*
1000  *  ======== proc_load ========
1001  *  Purpose:
1002  *      Reset a processor and load a new base program image.
1003  *      This will be an OEM-only function, and not part of the DSP/BIOS Bridge
1004  *      application developer's API.
1005  */
proc_load(void * hprocessor,const s32 argc_index,const char ** user_args,const char ** user_envp)1006 int proc_load(void *hprocessor, const s32 argc_index,
1007 		     const char **user_args, const char **user_envp)
1008 {
1009 	int status = 0;
1010 	struct proc_object *p_proc_object = (struct proc_object *)hprocessor;
1011 	struct io_mgr *hio_mgr;	/* IO manager handle */
1012 	struct msg_mgr *hmsg_mgr;
1013 	struct cod_manager *cod_mgr;	/* Code manager handle */
1014 	char *pargv0;		/* temp argv[0] ptr */
1015 	char **new_envp;	/* Updated envp[] array. */
1016 	char sz_proc_id[MAXPROCIDLEN];	/* Size of "PROC_ID=<n>" */
1017 	s32 envp_elems;		/* Num elements in envp[]. */
1018 	s32 cnew_envp;		/* "  " in new_envp[] */
1019 	s32 nproc_id = 0;	/* Anticipate MP version. */
1020 	struct dcd_manager *hdcd_handle;
1021 	struct dmm_object *dmm_mgr;
1022 	u32 dw_ext_end;
1023 	u32 proc_id;
1024 	int brd_state;
1025 	struct drv_data *drv_datap = dev_get_drvdata(bridge);
1026 
1027 #ifdef OPT_LOAD_TIME_INSTRUMENTATION
1028 	struct timeval tv1;
1029 	struct timeval tv2;
1030 #endif
1031 
1032 #if defined(CONFIG_TIDSPBRIDGE_DVFS) && !defined(CONFIG_CPU_FREQ)
1033 	struct dspbridge_platform_data *pdata =
1034 	    omap_dspbridge_dev->dev.platform_data;
1035 #endif
1036 
1037 #ifdef OPT_LOAD_TIME_INSTRUMENTATION
1038 	do_gettimeofday(&tv1);
1039 #endif
1040 	if (!p_proc_object) {
1041 		status = -EFAULT;
1042 		goto func_end;
1043 	}
1044 	dev_get_cod_mgr(p_proc_object->dev_obj, &cod_mgr);
1045 	if (!cod_mgr) {
1046 		status = -EPERM;
1047 		goto func_end;
1048 	}
1049 	status = proc_stop(hprocessor);
1050 	if (status)
1051 		goto func_end;
1052 
1053 	/* Place the board in the monitor state. */
1054 	status = proc_monitor(hprocessor);
1055 	if (status)
1056 		goto func_end;
1057 
1058 	/* Save ptr to  original argv[0]. */
1059 	pargv0 = (char *)user_args[0];
1060 	/*Prepend "PROC_ID=<nproc_id>"to envp array for target. */
1061 	envp_elems = get_envp_count((char **)user_envp);
1062 	cnew_envp = (envp_elems ? (envp_elems + 1) : (envp_elems + 2));
1063 	new_envp = kzalloc(cnew_envp * sizeof(char **), GFP_KERNEL);
1064 	if (new_envp) {
1065 		status = snprintf(sz_proc_id, MAXPROCIDLEN, PROC_ENVPROCID,
1066 				  nproc_id);
1067 		if (status == -1) {
1068 			dev_dbg(bridge, "%s: Proc ID string overflow\n",
1069 				__func__);
1070 			status = -EPERM;
1071 		} else {
1072 			new_envp =
1073 			    prepend_envp(new_envp, (char **)user_envp,
1074 					 envp_elems, cnew_envp, sz_proc_id);
1075 			/* Get the DCD Handle */
1076 			status = mgr_get_dcd_handle(p_proc_object->mgr_obj,
1077 						    (u32 *) &hdcd_handle);
1078 			if (!status) {
1079 				/*  Before proceeding with new load,
1080 				 *  check if a previously registered COFF
1081 				 *  exists.
1082 				 *  If yes, unregister nodes in previously
1083 				 *  registered COFF.  If any error occurred,
1084 				 *  set previously registered COFF to NULL. */
1085 				if (p_proc_object->last_coff != NULL) {
1086 					status =
1087 					    dcd_auto_unregister(hdcd_handle,
1088 								p_proc_object->
1089 								last_coff);
1090 					/* Regardless of auto unregister status,
1091 					 *  free previously allocated
1092 					 *  memory. */
1093 					kfree(p_proc_object->last_coff);
1094 					p_proc_object->last_coff = NULL;
1095 				}
1096 			}
1097 			/* On success, do cod_open_base() */
1098 			status = cod_open_base(cod_mgr, (char *)user_args[0],
1099 					       COD_SYMB);
1100 		}
1101 	} else {
1102 		status = -ENOMEM;
1103 	}
1104 	if (!status) {
1105 		/* Auto-register data base */
1106 		/* Get the DCD Handle */
1107 		status = mgr_get_dcd_handle(p_proc_object->mgr_obj,
1108 					    (u32 *) &hdcd_handle);
1109 		if (!status) {
1110 			/*  Auto register nodes in specified COFF
1111 			 *  file.  If registration did not fail,
1112 			 *  (status = 0 or -EACCES)
1113 			 *  save the name of the COFF file for
1114 			 *  de-registration in the future. */
1115 			status =
1116 			    dcd_auto_register(hdcd_handle,
1117 					      (char *)user_args[0]);
1118 			if (status == -EACCES)
1119 				status = 0;
1120 
1121 			if (status) {
1122 				status = -EPERM;
1123 			} else {
1124 				/* Allocate memory for pszLastCoff */
1125 				p_proc_object->last_coff =
1126 						kzalloc((strlen(user_args[0]) +
1127 						1), GFP_KERNEL);
1128 				/* If memory allocated, save COFF file name */
1129 				if (p_proc_object->last_coff) {
1130 					strncpy(p_proc_object->last_coff,
1131 						(char *)user_args[0],
1132 						(strlen((char *)user_args[0]) +
1133 						 1));
1134 				}
1135 			}
1136 		}
1137 	}
1138 	/* Update shared memory address and size */
1139 	if (!status) {
1140 		/*  Create the message manager. This must be done
1141 		 *  before calling the IOOnLoaded function. */
1142 		dev_get_msg_mgr(p_proc_object->dev_obj, &hmsg_mgr);
1143 		if (!hmsg_mgr) {
1144 			status = msg_create(&hmsg_mgr, p_proc_object->dev_obj,
1145 					    (msg_onexit) node_on_exit);
1146 			dev_set_msg_mgr(p_proc_object->dev_obj, hmsg_mgr);
1147 		}
1148 	}
1149 	if (!status) {
1150 		/* Set the Device object's message manager */
1151 		status = dev_get_io_mgr(p_proc_object->dev_obj, &hio_mgr);
1152 		if (hio_mgr)
1153 			status = (*p_proc_object->intf_fxns->io_on_loaded)
1154 								(hio_mgr);
1155 		else
1156 			status = -EFAULT;
1157 	}
1158 	if (!status) {
1159 		/* Now, attempt to load an exec: */
1160 
1161 		/* Boost the OPP level to Maximum level supported by baseport */
1162 #if defined(CONFIG_TIDSPBRIDGE_DVFS) && !defined(CONFIG_CPU_FREQ)
1163 		if (pdata->cpu_set_freq)
1164 			(*pdata->cpu_set_freq) (pdata->mpu_speed[VDD1_OPP5]);
1165 #endif
1166 		status = cod_load_base(cod_mgr, argc_index, (char **)user_args,
1167 				       dev_brd_write_fxn,
1168 				       p_proc_object->dev_obj, NULL);
1169 		if (status) {
1170 			if (status == -EBADF) {
1171 				dev_dbg(bridge, "%s: Failure to Load the EXE\n",
1172 					__func__);
1173 			}
1174 			if (status == -ESPIPE) {
1175 				pr_err("%s: Couldn't parse the file\n",
1176 				       __func__);
1177 			}
1178 		}
1179 		/* Requesting the lowest opp supported */
1180 #if defined(CONFIG_TIDSPBRIDGE_DVFS) && !defined(CONFIG_CPU_FREQ)
1181 		if (pdata->cpu_set_freq)
1182 			(*pdata->cpu_set_freq) (pdata->mpu_speed[VDD1_OPP1]);
1183 #endif
1184 
1185 	}
1186 	if (!status) {
1187 		/* Update the Processor status to loaded */
1188 		status = (*p_proc_object->intf_fxns->brd_set_state)
1189 		    (p_proc_object->bridge_context, BRD_LOADED);
1190 		if (!status) {
1191 			p_proc_object->proc_state = PROC_LOADED;
1192 			if (p_proc_object->ntfy_obj)
1193 				proc_notify_clients(p_proc_object,
1194 						    DSP_PROCESSORSTATECHANGE);
1195 		}
1196 	}
1197 	if (!status) {
1198 		status = proc_get_processor_id(hprocessor, &proc_id);
1199 		if (proc_id == DSP_UNIT) {
1200 			/* Use all available DSP address space after EXTMEM
1201 			 * for DMM */
1202 			if (!status)
1203 				status = cod_get_sym_value(cod_mgr, EXTEND,
1204 							   &dw_ext_end);
1205 
1206 			/* Reset DMM structs and add an initial free chunk */
1207 			if (!status) {
1208 				status =
1209 				    dev_get_dmm_mgr(p_proc_object->dev_obj,
1210 						    &dmm_mgr);
1211 				if (dmm_mgr) {
1212 					/* Set dw_ext_end to DMM START u8
1213 					 * address */
1214 					dw_ext_end =
1215 					    (dw_ext_end + 1) * DSPWORDSIZE;
1216 					/* DMM memory is from EXT_END */
1217 					status = dmm_create_tables(dmm_mgr,
1218 								   dw_ext_end,
1219 								   DMMPOOLSIZE);
1220 				} else {
1221 					status = -EFAULT;
1222 				}
1223 			}
1224 		}
1225 	}
1226 	/* Restore the original argv[0] */
1227 	kfree(new_envp);
1228 	user_args[0] = pargv0;
1229 	if (!status) {
1230 		if (!((*p_proc_object->intf_fxns->brd_status)
1231 				(p_proc_object->bridge_context, &brd_state))) {
1232 			pr_info("%s: Processor Loaded %s\n", __func__, pargv0);
1233 			kfree(drv_datap->base_img);
1234 			drv_datap->base_img = kmalloc(strlen(pargv0) + 1,
1235 								GFP_KERNEL);
1236 			if (drv_datap->base_img)
1237 				strncpy(drv_datap->base_img, pargv0,
1238 							strlen(pargv0) + 1);
1239 			else
1240 				status = -ENOMEM;
1241 		}
1242 	}
1243 
1244 func_end:
1245 	if (status) {
1246 		pr_err("%s: Processor failed to load\n", __func__);
1247 		proc_stop(p_proc_object);
1248 	}
1249 #ifdef OPT_LOAD_TIME_INSTRUMENTATION
1250 	do_gettimeofday(&tv2);
1251 	if (tv2.tv_usec < tv1.tv_usec) {
1252 		tv2.tv_usec += 1000000;
1253 		tv2.tv_sec--;
1254 	}
1255 	dev_dbg(bridge, "%s: time to load %d sec and %d usec\n", __func__,
1256 		tv2.tv_sec - tv1.tv_sec, tv2.tv_usec - tv1.tv_usec);
1257 #endif
1258 	return status;
1259 }
1260 
1261 /*
1262  *  ======== proc_map ========
1263  *  Purpose:
1264  *      Maps a MPU buffer to DSP address space.
1265  */
proc_map(void * hprocessor,void * pmpu_addr,u32 ul_size,void * req_addr,void ** pp_map_addr,u32 ul_map_attr,struct process_context * pr_ctxt)1266 int proc_map(void *hprocessor, void *pmpu_addr, u32 ul_size,
1267 		    void *req_addr, void **pp_map_addr, u32 ul_map_attr,
1268 		    struct process_context *pr_ctxt)
1269 {
1270 	u32 va_align;
1271 	u32 pa_align;
1272 	struct dmm_object *dmm_mgr;
1273 	u32 size_align;
1274 	int status = 0;
1275 	struct proc_object *p_proc_object = (struct proc_object *)hprocessor;
1276 	struct dmm_map_object *map_obj;
1277 	u32 tmp_addr = 0;
1278 
1279 #ifdef CONFIG_TIDSPBRIDGE_CACHE_LINE_CHECK
1280 	if ((ul_map_attr & BUFMODE_MASK) != RBUF) {
1281 		if (!IS_ALIGNED((u32)pmpu_addr, DSP_CACHE_LINE) ||
1282 		    !IS_ALIGNED(ul_size, DSP_CACHE_LINE)) {
1283 			pr_err("%s: not aligned: 0x%x (%d)\n", __func__,
1284 						(u32)pmpu_addr, ul_size);
1285 			return -EFAULT;
1286 		}
1287 	}
1288 #endif
1289 
1290 	/* Calculate the page-aligned PA, VA and size */
1291 	va_align = PG_ALIGN_LOW((u32) req_addr, PG_SIZE4K);
1292 	pa_align = PG_ALIGN_LOW((u32) pmpu_addr, PG_SIZE4K);
1293 	size_align = PG_ALIGN_HIGH(ul_size + (u32) pmpu_addr - pa_align,
1294 				   PG_SIZE4K);
1295 
1296 	if (!p_proc_object) {
1297 		status = -EFAULT;
1298 		goto func_end;
1299 	}
1300 	/* Critical section */
1301 	mutex_lock(&proc_lock);
1302 	dmm_get_handle(p_proc_object, &dmm_mgr);
1303 	if (dmm_mgr)
1304 		status = dmm_map_memory(dmm_mgr, va_align, size_align);
1305 	else
1306 		status = -EFAULT;
1307 
1308 	/* Add mapping to the page tables. */
1309 	if (!status) {
1310 
1311 		/* Mapped address = MSB of VA | LSB of PA */
1312 		tmp_addr = (va_align | ((u32) pmpu_addr & (PG_SIZE4K - 1)));
1313 		/* mapped memory resource tracking */
1314 		map_obj = add_mapping_info(pr_ctxt, pa_align, tmp_addr,
1315 						size_align);
1316 		if (!map_obj)
1317 			status = -ENOMEM;
1318 		else
1319 			status = (*p_proc_object->intf_fxns->brd_mem_map)
1320 			    (p_proc_object->bridge_context, pa_align, va_align,
1321 			     size_align, ul_map_attr, map_obj->pages);
1322 	}
1323 	if (!status) {
1324 		/* Mapped address = MSB of VA | LSB of PA */
1325 		*pp_map_addr = (void *) tmp_addr;
1326 	} else {
1327 		remove_mapping_information(pr_ctxt, tmp_addr, size_align);
1328 		dmm_un_map_memory(dmm_mgr, va_align, &size_align);
1329 	}
1330 	mutex_unlock(&proc_lock);
1331 
1332 	if (status)
1333 		goto func_end;
1334 
1335 func_end:
1336 	dev_dbg(bridge, "%s: hprocessor %p, pmpu_addr %p, ul_size %x, "
1337 		"req_addr %p, ul_map_attr %x, pp_map_addr %p, va_align %x, "
1338 		"pa_align %x, size_align %x status 0x%x\n", __func__,
1339 		hprocessor, pmpu_addr, ul_size, req_addr, ul_map_attr,
1340 		pp_map_addr, va_align, pa_align, size_align, status);
1341 
1342 	return status;
1343 }
1344 
1345 /*
1346  *  ======== proc_register_notify ========
1347  *  Purpose:
1348  *      Register to be notified of specific processor events.
1349  */
proc_register_notify(void * hprocessor,u32 event_mask,u32 notify_type,struct dsp_notification * hnotification)1350 int proc_register_notify(void *hprocessor, u32 event_mask,
1351 				u32 notify_type, struct dsp_notification
1352 				* hnotification)
1353 {
1354 	int status = 0;
1355 	struct proc_object *p_proc_object = (struct proc_object *)hprocessor;
1356 	struct deh_mgr *hdeh_mgr;
1357 
1358 	/* Check processor handle */
1359 	if (!p_proc_object) {
1360 		status = -EFAULT;
1361 		goto func_end;
1362 	}
1363 	/* Check if event mask is a valid processor related event */
1364 	if (event_mask & ~(DSP_PROCESSORSTATECHANGE | DSP_PROCESSORATTACH |
1365 			DSP_PROCESSORDETACH | DSP_PROCESSORRESTART |
1366 			DSP_MMUFAULT | DSP_SYSERROR | DSP_PWRERROR |
1367 			DSP_WDTOVERFLOW))
1368 		status = -EINVAL;
1369 
1370 	/* Check if notify type is valid */
1371 	if (notify_type != DSP_SIGNALEVENT)
1372 		status = -EINVAL;
1373 
1374 	if (!status) {
1375 		/* If event mask is not DSP_SYSERROR, DSP_MMUFAULT,
1376 		 * or DSP_PWRERROR then register event immediately. */
1377 		if (event_mask &
1378 		    ~(DSP_SYSERROR | DSP_MMUFAULT | DSP_PWRERROR |
1379 				DSP_WDTOVERFLOW)) {
1380 			status = ntfy_register(p_proc_object->ntfy_obj,
1381 					       hnotification, event_mask,
1382 					       notify_type);
1383 			/* Special case alert, special case alert!
1384 			 * If we're trying to *deregister* (i.e. event_mask
1385 			 * is 0), a DSP_SYSERROR or DSP_MMUFAULT notification,
1386 			 * we have to deregister with the DEH manager.
1387 			 * There's no way to know, based on event_mask which
1388 			 * manager the notification event was registered with,
1389 			 * so if we're trying to deregister and ntfy_register
1390 			 * failed, we'll give the deh manager a shot.
1391 			 */
1392 			if ((event_mask == 0) && status) {
1393 				status =
1394 				    dev_get_deh_mgr(p_proc_object->dev_obj,
1395 						    &hdeh_mgr);
1396 				status =
1397 					bridge_deh_register_notify(hdeh_mgr,
1398 							event_mask,
1399 							notify_type,
1400 							hnotification);
1401 			}
1402 		} else {
1403 			status = dev_get_deh_mgr(p_proc_object->dev_obj,
1404 						 &hdeh_mgr);
1405 			status =
1406 			    bridge_deh_register_notify(hdeh_mgr,
1407 					    event_mask,
1408 					    notify_type,
1409 					    hnotification);
1410 
1411 		}
1412 	}
1413 func_end:
1414 	return status;
1415 }
1416 
1417 /*
1418  *  ======== proc_reserve_memory ========
1419  *  Purpose:
1420  *      Reserve a virtually contiguous region of DSP address space.
1421  */
proc_reserve_memory(void * hprocessor,u32 ul_size,void ** pp_rsv_addr,struct process_context * pr_ctxt)1422 int proc_reserve_memory(void *hprocessor, u32 ul_size,
1423 			       void **pp_rsv_addr,
1424 			       struct process_context *pr_ctxt)
1425 {
1426 	struct dmm_object *dmm_mgr;
1427 	int status = 0;
1428 	struct proc_object *p_proc_object = (struct proc_object *)hprocessor;
1429 	struct dmm_rsv_object *rsv_obj;
1430 
1431 	if (!p_proc_object) {
1432 		status = -EFAULT;
1433 		goto func_end;
1434 	}
1435 
1436 	status = dmm_get_handle(p_proc_object, &dmm_mgr);
1437 	if (!dmm_mgr) {
1438 		status = -EFAULT;
1439 		goto func_end;
1440 	}
1441 
1442 	status = dmm_reserve_memory(dmm_mgr, ul_size, (u32 *) pp_rsv_addr);
1443 	if (status != 0)
1444 		goto func_end;
1445 
1446 	/*
1447 	 * A successful reserve should be followed by insertion of rsv_obj
1448 	 * into dmm_rsv_list, so that reserved memory resource tracking
1449 	 * remains uptodate
1450 	 */
1451 	rsv_obj = kmalloc(sizeof(struct dmm_rsv_object), GFP_KERNEL);
1452 	if (rsv_obj) {
1453 		rsv_obj->dsp_reserved_addr = (u32) *pp_rsv_addr;
1454 		spin_lock(&pr_ctxt->dmm_rsv_lock);
1455 		list_add(&rsv_obj->link, &pr_ctxt->dmm_rsv_list);
1456 		spin_unlock(&pr_ctxt->dmm_rsv_lock);
1457 	}
1458 
1459 func_end:
1460 	dev_dbg(bridge, "%s: hprocessor: 0x%p ul_size: 0x%x pp_rsv_addr: 0x%p "
1461 		"status 0x%x\n", __func__, hprocessor,
1462 		ul_size, pp_rsv_addr, status);
1463 	return status;
1464 }
1465 
1466 /*
1467  *  ======== proc_start ========
1468  *  Purpose:
1469  *      Start a processor running.
1470  */
proc_start(void * hprocessor)1471 int proc_start(void *hprocessor)
1472 {
1473 	int status = 0;
1474 	struct proc_object *p_proc_object = (struct proc_object *)hprocessor;
1475 	struct cod_manager *cod_mgr;	/* Code manager handle */
1476 	u32 dw_dsp_addr;	/* Loaded code's entry point. */
1477 	int brd_state;
1478 
1479 	if (!p_proc_object) {
1480 		status = -EFAULT;
1481 		goto func_end;
1482 	}
1483 	/* Call the bridge_brd_start */
1484 	if (p_proc_object->proc_state != PROC_LOADED) {
1485 		status = -EBADR;
1486 		goto func_end;
1487 	}
1488 	status = dev_get_cod_mgr(p_proc_object->dev_obj, &cod_mgr);
1489 	if (!cod_mgr) {
1490 		status = -EFAULT;
1491 		goto func_cont;
1492 	}
1493 
1494 	status = cod_get_entry(cod_mgr, &dw_dsp_addr);
1495 	if (status)
1496 		goto func_cont;
1497 
1498 	status = (*p_proc_object->intf_fxns->brd_start)
1499 	    (p_proc_object->bridge_context, dw_dsp_addr);
1500 	if (status)
1501 		goto func_cont;
1502 
1503 	/* Call dev_create2 */
1504 	status = dev_create2(p_proc_object->dev_obj);
1505 	if (!status) {
1506 		p_proc_object->proc_state = PROC_RUNNING;
1507 		/* Deep sleep switces off the peripheral clocks.
1508 		 * we just put the DSP CPU in idle in the idle loop.
1509 		 * so there is no need to send a command to DSP */
1510 
1511 		if (p_proc_object->ntfy_obj) {
1512 			proc_notify_clients(p_proc_object,
1513 					    DSP_PROCESSORSTATECHANGE);
1514 		}
1515 	} else {
1516 		/* Failed to Create Node Manager and DISP Object
1517 		 * Stop the Processor from running. Put it in STOPPED State */
1518 		(void)(*p_proc_object->intf_fxns->
1519 		       brd_stop) (p_proc_object->bridge_context);
1520 		p_proc_object->proc_state = PROC_STOPPED;
1521 	}
1522 func_cont:
1523 	if (!status) {
1524 		if (!((*p_proc_object->intf_fxns->brd_status)
1525 				(p_proc_object->bridge_context, &brd_state))) {
1526 			pr_info("%s: dsp in running state\n", __func__);
1527 		}
1528 	} else {
1529 		pr_err("%s: Failed to start the dsp\n", __func__);
1530 		proc_stop(p_proc_object);
1531 	}
1532 
1533 func_end:
1534 	return status;
1535 }
1536 
1537 /*
1538  *  ======== proc_stop ========
1539  *  Purpose:
1540  *      Stop a processor running.
1541  */
proc_stop(void * hprocessor)1542 int proc_stop(void *hprocessor)
1543 {
1544 	int status = 0;
1545 	struct proc_object *p_proc_object = (struct proc_object *)hprocessor;
1546 	struct msg_mgr *hmsg_mgr;
1547 	struct node_mgr *hnode_mgr;
1548 	void *hnode;
1549 	u32 node_tab_size = 1;
1550 	u32 num_nodes = 0;
1551 	u32 nodes_allocated = 0;
1552 
1553 	if (!p_proc_object) {
1554 		status = -EFAULT;
1555 		goto func_end;
1556 	}
1557 	/* check if there are any running nodes */
1558 	status = dev_get_node_manager(p_proc_object->dev_obj, &hnode_mgr);
1559 	if (!status && hnode_mgr) {
1560 		status = node_enum_nodes(hnode_mgr, &hnode, node_tab_size,
1561 					 &num_nodes, &nodes_allocated);
1562 		if ((status == -EINVAL) || (nodes_allocated > 0)) {
1563 			pr_err("%s: Can't stop device, active nodes = %d \n",
1564 			       __func__, nodes_allocated);
1565 			return -EBADR;
1566 		}
1567 	}
1568 	/* Call the bridge_brd_stop */
1569 	/* It is OK to stop a device that does n't have nodes OR not started */
1570 	status =
1571 	    (*p_proc_object->intf_fxns->
1572 	     brd_stop) (p_proc_object->bridge_context);
1573 	if (!status) {
1574 		dev_dbg(bridge, "%s: processor in standby mode\n", __func__);
1575 		p_proc_object->proc_state = PROC_STOPPED;
1576 		/* Destroy the Node Manager, msg_ctrl Manager */
1577 		if (!(dev_destroy2(p_proc_object->dev_obj))) {
1578 			/* Destroy the msg_ctrl by calling msg_delete */
1579 			dev_get_msg_mgr(p_proc_object->dev_obj, &hmsg_mgr);
1580 			if (hmsg_mgr) {
1581 				msg_delete(hmsg_mgr);
1582 				dev_set_msg_mgr(p_proc_object->dev_obj, NULL);
1583 			}
1584 		}
1585 	} else {
1586 		pr_err("%s: Failed to stop the processor\n", __func__);
1587 	}
1588 func_end:
1589 
1590 	return status;
1591 }
1592 
1593 /*
1594  *  ======== proc_un_map ========
1595  *  Purpose:
1596  *      Removes a MPU buffer mapping from the DSP address space.
1597  */
proc_un_map(void * hprocessor,void * map_addr,struct process_context * pr_ctxt)1598 int proc_un_map(void *hprocessor, void *map_addr,
1599 		       struct process_context *pr_ctxt)
1600 {
1601 	int status = 0;
1602 	struct proc_object *p_proc_object = (struct proc_object *)hprocessor;
1603 	struct dmm_object *dmm_mgr;
1604 	u32 va_align;
1605 	u32 size_align;
1606 
1607 	va_align = PG_ALIGN_LOW((u32) map_addr, PG_SIZE4K);
1608 	if (!p_proc_object) {
1609 		status = -EFAULT;
1610 		goto func_end;
1611 	}
1612 
1613 	status = dmm_get_handle(hprocessor, &dmm_mgr);
1614 	if (!dmm_mgr) {
1615 		status = -EFAULT;
1616 		goto func_end;
1617 	}
1618 
1619 	/* Critical section */
1620 	mutex_lock(&proc_lock);
1621 	/*
1622 	 * Update DMM structures. Get the size to unmap.
1623 	 * This function returns error if the VA is not mapped
1624 	 */
1625 	status = dmm_un_map_memory(dmm_mgr, (u32) va_align, &size_align);
1626 	/* Remove mapping from the page tables. */
1627 	if (!status) {
1628 		status = (*p_proc_object->intf_fxns->brd_mem_un_map)
1629 		    (p_proc_object->bridge_context, va_align, size_align);
1630 	}
1631 
1632 	if (status)
1633 		goto unmap_failed;
1634 
1635 	/*
1636 	 * A successful unmap should be followed by removal of map_obj
1637 	 * from dmm_map_list, so that mapped memory resource tracking
1638 	 * remains uptodate
1639 	 */
1640 	remove_mapping_information(pr_ctxt, (u32) map_addr, size_align);
1641 
1642 unmap_failed:
1643 	mutex_unlock(&proc_lock);
1644 
1645 func_end:
1646 	dev_dbg(bridge, "%s: hprocessor: 0x%p map_addr: 0x%p status: 0x%x\n",
1647 		__func__, hprocessor, map_addr, status);
1648 	return status;
1649 }
1650 
1651 /*
1652  *  ======== proc_un_reserve_memory ========
1653  *  Purpose:
1654  *      Frees a previously reserved region of DSP address space.
1655  */
proc_un_reserve_memory(void * hprocessor,void * prsv_addr,struct process_context * pr_ctxt)1656 int proc_un_reserve_memory(void *hprocessor, void *prsv_addr,
1657 				  struct process_context *pr_ctxt)
1658 {
1659 	struct dmm_object *dmm_mgr;
1660 	int status = 0;
1661 	struct proc_object *p_proc_object = (struct proc_object *)hprocessor;
1662 	struct dmm_rsv_object *rsv_obj;
1663 
1664 	if (!p_proc_object) {
1665 		status = -EFAULT;
1666 		goto func_end;
1667 	}
1668 
1669 	status = dmm_get_handle(p_proc_object, &dmm_mgr);
1670 	if (!dmm_mgr) {
1671 		status = -EFAULT;
1672 		goto func_end;
1673 	}
1674 
1675 	status = dmm_un_reserve_memory(dmm_mgr, (u32) prsv_addr);
1676 	if (status != 0)
1677 		goto func_end;
1678 
1679 	/*
1680 	 * A successful unreserve should be followed by removal of rsv_obj
1681 	 * from dmm_rsv_list, so that reserved memory resource tracking
1682 	 * remains uptodate
1683 	 */
1684 	spin_lock(&pr_ctxt->dmm_rsv_lock);
1685 	list_for_each_entry(rsv_obj, &pr_ctxt->dmm_rsv_list, link) {
1686 		if (rsv_obj->dsp_reserved_addr == (u32) prsv_addr) {
1687 			list_del(&rsv_obj->link);
1688 			kfree(rsv_obj);
1689 			break;
1690 		}
1691 	}
1692 	spin_unlock(&pr_ctxt->dmm_rsv_lock);
1693 
1694 func_end:
1695 	dev_dbg(bridge, "%s: hprocessor: 0x%p prsv_addr: 0x%p status: 0x%x\n",
1696 		__func__, hprocessor, prsv_addr, status);
1697 	return status;
1698 }
1699 
1700 /*
1701  *  ======== = proc_monitor ======== ==
1702  *  Purpose:
1703  *      Place the Processor in Monitor State. This is an internal
1704  *      function and a requirement before Processor is loaded.
1705  *      This does a bridge_brd_stop, dev_destroy2 and bridge_brd_monitor.
1706  *      In dev_destroy2 we delete the node manager.
1707  *  Parameters:
1708  *      p_proc_object:    Pointer to Processor Object
1709  *  Returns:
1710  *      0:	Processor placed in monitor mode.
1711  *      !0:       Failed to place processor in monitor mode.
1712  *  Requires:
1713  *      Valid Processor Handle
1714  *  Ensures:
1715  *      Success:	ProcObject state is PROC_IDLE
1716  */
proc_monitor(struct proc_object * proc_obj)1717 static int proc_monitor(struct proc_object *proc_obj)
1718 {
1719 	int status = -EPERM;
1720 	struct msg_mgr *hmsg_mgr;
1721 
1722 	/* This is needed only when Device is loaded when it is
1723 	 * already 'ACTIVE' */
1724 	/* Destroy the Node Manager, msg_ctrl Manager */
1725 	if (!dev_destroy2(proc_obj->dev_obj)) {
1726 		/* Destroy the msg_ctrl by calling msg_delete */
1727 		dev_get_msg_mgr(proc_obj->dev_obj, &hmsg_mgr);
1728 		if (hmsg_mgr) {
1729 			msg_delete(hmsg_mgr);
1730 			dev_set_msg_mgr(proc_obj->dev_obj, NULL);
1731 		}
1732 	}
1733 	/* Place the Board in the Monitor State */
1734 	if (!((*proc_obj->intf_fxns->brd_monitor)
1735 			  (proc_obj->bridge_context))) {
1736 		status = 0;
1737 	}
1738 
1739 	return status;
1740 }
1741 
1742 /*
1743  *  ======== get_envp_count ========
1744  *  Purpose:
1745  *      Return the number of elements in the envp array, including the
1746  *      terminating NULL element.
1747  */
get_envp_count(char ** envp)1748 static s32 get_envp_count(char **envp)
1749 {
1750 	s32 ret = 0;
1751 	if (envp) {
1752 		while (*envp++)
1753 			ret++;
1754 
1755 		ret += 1;	/* Include the terminating NULL in the count. */
1756 	}
1757 
1758 	return ret;
1759 }
1760 
1761 /*
1762  *  ======== prepend_envp ========
1763  *  Purpose:
1764  *      Prepend an environment variable=value pair to the new envp array, and
1765  *      copy in the existing var=value pairs in the old envp array.
1766  */
prepend_envp(char ** new_envp,char ** envp,s32 envp_elems,s32 cnew_envp,char * sz_var)1767 static char **prepend_envp(char **new_envp, char **envp, s32 envp_elems,
1768 			   s32 cnew_envp, char *sz_var)
1769 {
1770 	char **pp_envp = new_envp;
1771 
1772 	/* Prepend new environ var=value string */
1773 	*new_envp++ = sz_var;
1774 
1775 	/* Copy user's environment into our own. */
1776 	while (envp_elems--)
1777 		*new_envp++ = *envp++;
1778 
1779 	/* Ensure NULL terminates the new environment strings array. */
1780 	if (envp_elems == 0)
1781 		*new_envp = NULL;
1782 
1783 	return pp_envp;
1784 }
1785 
1786 /*
1787  *  ======== proc_notify_clients ========
1788  *  Purpose:
1789  *      Notify the processor the events.
1790  */
proc_notify_clients(void * proc,u32 events)1791 int proc_notify_clients(void *proc, u32 events)
1792 {
1793 	int status = 0;
1794 	struct proc_object *p_proc_object = (struct proc_object *)proc;
1795 
1796 	if (!p_proc_object) {
1797 		status = -EFAULT;
1798 		goto func_end;
1799 	}
1800 
1801 	ntfy_notify(p_proc_object->ntfy_obj, events);
1802 func_end:
1803 	return status;
1804 }
1805 
1806 /*
1807  *  ======== proc_notify_all_clients ========
1808  *  Purpose:
1809  *      Notify the processor the events. This includes notifying all clients
1810  *      attached to a particulat DSP.
1811  */
proc_notify_all_clients(void * proc,u32 events)1812 int proc_notify_all_clients(void *proc, u32 events)
1813 {
1814 	int status = 0;
1815 	struct proc_object *p_proc_object = (struct proc_object *)proc;
1816 
1817 	if (!p_proc_object) {
1818 		status = -EFAULT;
1819 		goto func_end;
1820 	}
1821 
1822 	dev_notify_clients(p_proc_object->dev_obj, events);
1823 
1824 func_end:
1825 	return status;
1826 }
1827 
1828 /*
1829  *  ======== proc_get_processor_id ========
1830  *  Purpose:
1831  *      Retrieves the processor ID.
1832  */
proc_get_processor_id(void * proc,u32 * proc_id)1833 int proc_get_processor_id(void *proc, u32 * proc_id)
1834 {
1835 	int status = 0;
1836 	struct proc_object *p_proc_object = (struct proc_object *)proc;
1837 
1838 	if (p_proc_object)
1839 		*proc_id = p_proc_object->processor_id;
1840 	else
1841 		status = -EFAULT;
1842 
1843 	return status;
1844 }
1845