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