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
73extern struct device *bridge;
74
75/*  ----------------------------------- Globals */
76
77/* The proc_object structure. */
78struct 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
101DEFINE_MUTEX(proc_lock);	/* For critical sections */
102
103/*  ----------------------------------- Function Prototypes */
104static int proc_monitor(struct proc_object *proc_obj);
105static s32 get_envp_count(char **envp);
106static char **prepend_envp(char **new_envp, char **envp, s32 envp_elems,
107			   s32 cnew_envp, char *sz_var);
108
109/* remember mapping information */
110static 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
148static 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
159static 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__);
187out:
188	spin_unlock(&pr_ctxt->dmm_map_lock);
189}
190
191static 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
200static 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;
224out:
225	spin_unlock(&pr_ctxt->dmm_map_lock);
226	return map_obj;
227}
228
229static 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
245static 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 */
266int
267proc_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	}
376func_end:
377	return status;
378}
379
380static 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 */
425int 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;
480func_cont:
481	kfree(p_proc_object);
482func_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 */
497int 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 */
545int 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 */
582int 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 */
608static 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
646out:
647	return ret;
648}
649
650static 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
676out:
677	return ret;
678}
679
680/* Cache operation against kernel address instead of users */
681static 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
731kfree_sg:
732	kfree(sg);
733	map_obj->dma_info.sg = NULL;
734out:
735	return ret;
736}
737
738int 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
771no_map:
772	mutex_unlock(&proc_lock);
773err_out:
774
775	return status;
776}
777
778int 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
811no_map:
812	mutex_unlock(&proc_lock);
813err_out:
814	return status;
815}
816
817/*
818 *  ======== proc_flush_memory ========
819 *  Purpose:
820 *     Flush cache
821 */
822int 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 */
835int 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 */
847int 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	}
905func_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 */
915int 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 */
937int 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 */
992int 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 */
1006int 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
1244func_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 */
1266int 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
1335func_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 */
1350int 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	}
1413func_end:
1414	return status;
1415}
1416
1417/*
1418 *  ======== proc_reserve_memory ========
1419 *  Purpose:
1420 *      Reserve a virtually contiguous region of DSP address space.
1421 */
1422int 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
1459func_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 */
1471int 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	}
1522func_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
1533func_end:
1534	return status;
1535}
1536
1537/*
1538 *  ======== proc_stop ========
1539 *  Purpose:
1540 *      Stop a processor running.
1541 */
1542int 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	}
1588func_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 */
1598int 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
1642unmap_failed:
1643	mutex_unlock(&proc_lock);
1644
1645func_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 */
1656int 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
1694func_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 */
1717static 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 */
1748static 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 */
1767static 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 */
1791int 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);
1802func_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 */
1812int 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
1824func_end:
1825	return status;
1826}
1827
1828/*
1829 *  ======== proc_get_processor_id ========
1830 *  Purpose:
1831 *      Retrieves the processor ID.
1832 */
1833int 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