]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - drivers/staging/tidspbridge/rmgr/proc.c
staging: tidspbridge: protect dmm_map properly
[karo-tx-linux.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         mutex_lock(&proc_lock);
785
786         /* find requested memory are in cached mapping information */
787         map_obj = find_containing_mapping(pr_ctxt, (u32) pmpu_addr, ul_size);
788         if (!map_obj) {
789                 pr_err("%s: find_containing_mapping failed\n", __func__);
790                 status = -EFAULT;
791                 goto no_map;
792         }
793
794         if (memory_give_ownership(map_obj, (u32) pmpu_addr, ul_size, dir)) {
795                 pr_err("%s: InValid address parameters %p %x\n",
796                                __func__, pmpu_addr, ul_size);
797                 status = -EFAULT;
798         }
799
800 no_map:
801         mutex_unlock(&proc_lock);
802 err_out:
803
804         return status;
805 }
806
807 int proc_end_dma(void *hprocessor, void *pmpu_addr, u32 ul_size,
808                         enum dma_data_direction dir)
809 {
810         /* Keep STATUS here for future additions to this function */
811         int status = 0;
812         struct process_context *pr_ctxt = (struct process_context *) hprocessor;
813         struct dmm_map_object *map_obj;
814
815         DBC_REQUIRE(refs > 0);
816
817         if (!pr_ctxt) {
818                 status = -EFAULT;
819                 goto err_out;
820         }
821
822         pr_debug("%s: addr 0x%x, size 0x%x, type %d\n", __func__,
823                                                         (u32)pmpu_addr,
824                                                         ul_size, dir);
825
826         mutex_lock(&proc_lock);
827
828         /* find requested memory are in cached mapping information */
829         map_obj = find_containing_mapping(pr_ctxt, (u32) pmpu_addr, ul_size);
830         if (!map_obj) {
831                 pr_err("%s: find_containing_mapping failed\n", __func__);
832                 status = -EFAULT;
833                 goto no_map;
834         }
835
836         if (memory_regain_ownership(map_obj, (u32) pmpu_addr, ul_size, dir)) {
837                 pr_err("%s: InValid address parameters %p %x\n",
838                        __func__, pmpu_addr, ul_size);
839                 status = -EFAULT;
840         }
841
842 no_map:
843         mutex_unlock(&proc_lock);
844 err_out:
845         return status;
846 }
847
848 /*
849  *  ======== proc_flush_memory ========
850  *  Purpose:
851  *     Flush cache
852  */
853 int proc_flush_memory(void *hprocessor, void *pmpu_addr,
854                              u32 ul_size, u32 ul_flags)
855 {
856         enum dma_data_direction dir = DMA_BIDIRECTIONAL;
857
858         return proc_begin_dma(hprocessor, pmpu_addr, ul_size, dir);
859 }
860
861 /*
862  *  ======== proc_invalidate_memory ========
863  *  Purpose:
864  *     Invalidates the memory specified
865  */
866 int proc_invalidate_memory(void *hprocessor, void *pmpu_addr, u32 size)
867 {
868         enum dma_data_direction dir = DMA_FROM_DEVICE;
869
870         return proc_begin_dma(hprocessor, pmpu_addr, size, dir);
871 }
872
873 /*
874  *  ======== proc_get_resource_info ========
875  *  Purpose:
876  *      Enumerate the resources currently available on a processor.
877  */
878 int proc_get_resource_info(void *hprocessor, u32 resource_type,
879                                   struct dsp_resourceinfo *resource_info,
880                                   u32 resource_info_size)
881 {
882         int status = -EPERM;
883         struct proc_object *p_proc_object = (struct proc_object *)hprocessor;
884         struct node_mgr *hnode_mgr = NULL;
885         struct nldr_object *nldr_obj = NULL;
886         struct rmm_target_obj *rmm = NULL;
887         struct io_mgr *hio_mgr = NULL;  /* IO manager handle */
888
889         DBC_REQUIRE(refs > 0);
890         DBC_REQUIRE(resource_info != NULL);
891         DBC_REQUIRE(resource_info_size >= sizeof(struct dsp_resourceinfo));
892
893         if (!p_proc_object) {
894                 status = -EFAULT;
895                 goto func_end;
896         }
897         switch (resource_type) {
898         case DSP_RESOURCE_DYNDARAM:
899         case DSP_RESOURCE_DYNSARAM:
900         case DSP_RESOURCE_DYNEXTERNAL:
901         case DSP_RESOURCE_DYNSRAM:
902                 status = dev_get_node_manager(p_proc_object->hdev_obj,
903                                               &hnode_mgr);
904                 if (!hnode_mgr) {
905                         status = -EFAULT;
906                         goto func_end;
907                 }
908
909                 status = node_get_nldr_obj(hnode_mgr, &nldr_obj);
910                 if (!status) {
911                         status = nldr_get_rmm_manager(nldr_obj, &rmm);
912                         if (rmm) {
913                                 if (!rmm_stat(rmm,
914                                               (enum dsp_memtype)resource_type,
915                                               (struct dsp_memstat *)
916                                               &(resource_info->result.
917                                                 mem_stat)))
918                                         status = -EINVAL;
919                         } else {
920                                 status = -EFAULT;
921                         }
922                 }
923                 break;
924         case DSP_RESOURCE_PROCLOAD:
925                 status = dev_get_io_mgr(p_proc_object->hdev_obj, &hio_mgr);
926                 if (hio_mgr)
927                         status =
928                             p_proc_object->intf_fxns->
929                             pfn_io_get_proc_load(hio_mgr,
930                                                  (struct dsp_procloadstat *)
931                                                  &(resource_info->result.
932                                                    proc_load_stat));
933                 else
934                         status = -EFAULT;
935                 break;
936         default:
937                 status = -EPERM;
938                 break;
939         }
940 func_end:
941         return status;
942 }
943
944 /*
945  *  ======== proc_exit ========
946  *  Purpose:
947  *      Decrement reference count, and free resources when reference count is
948  *      0.
949  */
950 void proc_exit(void)
951 {
952         DBC_REQUIRE(refs > 0);
953
954         refs--;
955
956         DBC_ENSURE(refs >= 0);
957 }
958
959 /*
960  *  ======== proc_get_dev_object ========
961  *  Purpose:
962  *      Return the Dev Object handle for a given Processor.
963  *
964  */
965 int proc_get_dev_object(void *hprocessor,
966                                struct dev_object **device_obj)
967 {
968         int status = -EPERM;
969         struct proc_object *p_proc_object = (struct proc_object *)hprocessor;
970
971         DBC_REQUIRE(refs > 0);
972         DBC_REQUIRE(device_obj != NULL);
973
974         if (p_proc_object) {
975                 *device_obj = p_proc_object->hdev_obj;
976                 status = 0;
977         } else {
978                 *device_obj = NULL;
979                 status = -EFAULT;
980         }
981
982         DBC_ENSURE((!status && *device_obj != NULL) ||
983                    (status && *device_obj == NULL));
984
985         return status;
986 }
987
988 /*
989  *  ======== proc_get_state ========
990  *  Purpose:
991  *      Report the state of the specified DSP processor.
992  */
993 int proc_get_state(void *hprocessor,
994                           struct dsp_processorstate *proc_state_obj,
995                           u32 state_info_size)
996 {
997         int status = 0;
998         struct proc_object *p_proc_object = (struct proc_object *)hprocessor;
999         int brd_status;
1000
1001         DBC_REQUIRE(refs > 0);
1002         DBC_REQUIRE(proc_state_obj != NULL);
1003         DBC_REQUIRE(state_info_size >= sizeof(struct dsp_processorstate));
1004
1005         if (p_proc_object) {
1006                 /* First, retrieve BRD state information */
1007                 status = (*p_proc_object->intf_fxns->pfn_brd_status)
1008                     (p_proc_object->hbridge_context, &brd_status);
1009                 if (!status) {
1010                         switch (brd_status) {
1011                         case BRD_STOPPED:
1012                                 proc_state_obj->proc_state = PROC_STOPPED;
1013                                 break;
1014                         case BRD_SLEEP_TRANSITION:
1015                         case BRD_DSP_HIBERNATION:
1016                                 /* Fall through */
1017                         case BRD_RUNNING:
1018                                 proc_state_obj->proc_state = PROC_RUNNING;
1019                                 break;
1020                         case BRD_LOADED:
1021                                 proc_state_obj->proc_state = PROC_LOADED;
1022                                 break;
1023                         case BRD_ERROR:
1024                                 proc_state_obj->proc_state = PROC_ERROR;
1025                                 break;
1026                         default:
1027                                 proc_state_obj->proc_state = 0xFF;
1028                                 status = -EPERM;
1029                                 break;
1030                         }
1031                 }
1032         } else {
1033                 status = -EFAULT;
1034         }
1035         dev_dbg(bridge, "%s, results: status: 0x%x proc_state_obj: 0x%x\n",
1036                 __func__, status, proc_state_obj->proc_state);
1037         return status;
1038 }
1039
1040 /*
1041  *  ======== proc_get_trace ========
1042  *  Purpose:
1043  *      Retrieve the current contents of the trace buffer, located on the
1044  *      Processor.  Predefined symbols for the trace buffer must have been
1045  *      configured into the DSP executable.
1046  *  Details:
1047  *      We support using the symbols SYS_PUTCBEG and SYS_PUTCEND to define a
1048  *      trace buffer, only.  Treat it as an undocumented feature.
1049  *      This call is destructive, meaning the processor is placed in the monitor
1050  *      state as a result of this function.
1051  */
1052 int proc_get_trace(void *hprocessor, u8 * pbuf, u32 max_size)
1053 {
1054         int status;
1055         status = -ENOSYS;
1056         return status;
1057 }
1058
1059 /*
1060  *  ======== proc_init ========
1061  *  Purpose:
1062  *      Initialize PROC's private state, keeping a reference count on each call
1063  */
1064 bool proc_init(void)
1065 {
1066         bool ret = true;
1067
1068         DBC_REQUIRE(refs >= 0);
1069
1070         if (ret)
1071                 refs++;
1072
1073         DBC_ENSURE((ret && (refs > 0)) || (!ret && (refs >= 0)));
1074
1075         return ret;
1076 }
1077
1078 /*
1079  *  ======== proc_load ========
1080  *  Purpose:
1081  *      Reset a processor and load a new base program image.
1082  *      This will be an OEM-only function, and not part of the DSP/BIOS Bridge
1083  *      application developer's API.
1084  */
1085 int proc_load(void *hprocessor, const s32 argc_index,
1086                      const char **user_args, const char **user_envp)
1087 {
1088         int status = 0;
1089         struct proc_object *p_proc_object = (struct proc_object *)hprocessor;
1090         struct io_mgr *hio_mgr; /* IO manager handle */
1091         struct msg_mgr *hmsg_mgr;
1092         struct cod_manager *cod_mgr;    /* Code manager handle */
1093         char *pargv0;           /* temp argv[0] ptr */
1094         char **new_envp;        /* Updated envp[] array. */
1095         char sz_proc_id[MAXPROCIDLEN];  /* Size of "PROC_ID=<n>" */
1096         s32 envp_elems;         /* Num elements in envp[]. */
1097         s32 cnew_envp;          /* "  " in new_envp[] */
1098         s32 nproc_id = 0;       /* Anticipate MP version. */
1099         struct dcd_manager *hdcd_handle;
1100         struct dmm_object *dmm_mgr;
1101         u32 dw_ext_end;
1102         u32 proc_id;
1103         int brd_state;
1104         struct drv_data *drv_datap = dev_get_drvdata(bridge);
1105
1106 #ifdef OPT_LOAD_TIME_INSTRUMENTATION
1107         struct timeval tv1;
1108         struct timeval tv2;
1109 #endif
1110
1111 #if defined(CONFIG_TIDSPBRIDGE_DVFS) && !defined(CONFIG_CPU_FREQ)
1112         struct dspbridge_platform_data *pdata =
1113             omap_dspbridge_dev->dev.platform_data;
1114 #endif
1115
1116         DBC_REQUIRE(refs > 0);
1117         DBC_REQUIRE(argc_index > 0);
1118         DBC_REQUIRE(user_args != NULL);
1119
1120 #ifdef OPT_LOAD_TIME_INSTRUMENTATION
1121         do_gettimeofday(&tv1);
1122 #endif
1123         if (!p_proc_object) {
1124                 status = -EFAULT;
1125                 goto func_end;
1126         }
1127         dev_get_cod_mgr(p_proc_object->hdev_obj, &cod_mgr);
1128         if (!cod_mgr) {
1129                 status = -EPERM;
1130                 goto func_end;
1131         }
1132         status = proc_stop(hprocessor);
1133         if (status)
1134                 goto func_end;
1135
1136         /* Place the board in the monitor state. */
1137         status = proc_monitor(hprocessor);
1138         if (status)
1139                 goto func_end;
1140
1141         /* Save ptr to  original argv[0]. */
1142         pargv0 = (char *)user_args[0];
1143         /*Prepend "PROC_ID=<nproc_id>"to envp array for target. */
1144         envp_elems = get_envp_count((char **)user_envp);
1145         cnew_envp = (envp_elems ? (envp_elems + 1) : (envp_elems + 2));
1146         new_envp = kzalloc(cnew_envp * sizeof(char **), GFP_KERNEL);
1147         if (new_envp) {
1148                 status = snprintf(sz_proc_id, MAXPROCIDLEN, PROC_ENVPROCID,
1149                                   nproc_id);
1150                 if (status == -1) {
1151                         dev_dbg(bridge, "%s: Proc ID string overflow\n",
1152                                 __func__);
1153                         status = -EPERM;
1154                 } else {
1155                         new_envp =
1156                             prepend_envp(new_envp, (char **)user_envp,
1157                                          envp_elems, cnew_envp, sz_proc_id);
1158                         /* Get the DCD Handle */
1159                         status = mgr_get_dcd_handle(p_proc_object->hmgr_obj,
1160                                                     (u32 *) &hdcd_handle);
1161                         if (!status) {
1162                                 /*  Before proceeding with new load,
1163                                  *  check if a previously registered COFF
1164                                  *  exists.
1165                                  *  If yes, unregister nodes in previously
1166                                  *  registered COFF.  If any error occurred,
1167                                  *  set previously registered COFF to NULL. */
1168                                 if (p_proc_object->psz_last_coff != NULL) {
1169                                         status =
1170                                             dcd_auto_unregister(hdcd_handle,
1171                                                                 p_proc_object->
1172                                                                 psz_last_coff);
1173                                         /* Regardless of auto unregister status,
1174                                          *  free previously allocated
1175                                          *  memory. */
1176                                         kfree(p_proc_object->psz_last_coff);
1177                                         p_proc_object->psz_last_coff = NULL;
1178                                 }
1179                         }
1180                         /* On success, do cod_open_base() */
1181                         status = cod_open_base(cod_mgr, (char *)user_args[0],
1182                                                COD_SYMB);
1183                 }
1184         } else {
1185                 status = -ENOMEM;
1186         }
1187         if (!status) {
1188                 /* Auto-register data base */
1189                 /* Get the DCD Handle */
1190                 status = mgr_get_dcd_handle(p_proc_object->hmgr_obj,
1191                                             (u32 *) &hdcd_handle);
1192                 if (!status) {
1193                         /*  Auto register nodes in specified COFF
1194                          *  file.  If registration did not fail,
1195                          *  (status = 0 or -EACCES)
1196                          *  save the name of the COFF file for
1197                          *  de-registration in the future. */
1198                         status =
1199                             dcd_auto_register(hdcd_handle,
1200                                               (char *)user_args[0]);
1201                         if (status == -EACCES)
1202                                 status = 0;
1203
1204                         if (status) {
1205                                 status = -EPERM;
1206                         } else {
1207                                 DBC_ASSERT(p_proc_object->psz_last_coff ==
1208                                            NULL);
1209                                 /* Allocate memory for pszLastCoff */
1210                                 p_proc_object->psz_last_coff =
1211                                                 kzalloc((strlen(user_args[0]) +
1212                                                 1), GFP_KERNEL);
1213                                 /* If memory allocated, save COFF file name */
1214                                 if (p_proc_object->psz_last_coff) {
1215                                         strncpy(p_proc_object->psz_last_coff,
1216                                                 (char *)user_args[0],
1217                                                 (strlen((char *)user_args[0]) +
1218                                                  1));
1219                                 }
1220                         }
1221                 }
1222         }
1223         /* Update shared memory address and size */
1224         if (!status) {
1225                 /*  Create the message manager. This must be done
1226                  *  before calling the IOOnLoaded function. */
1227                 dev_get_msg_mgr(p_proc_object->hdev_obj, &hmsg_mgr);
1228                 if (!hmsg_mgr) {
1229                         status = msg_create(&hmsg_mgr, p_proc_object->hdev_obj,
1230                                             (msg_onexit) node_on_exit);
1231                         DBC_ASSERT(!status);
1232                         dev_set_msg_mgr(p_proc_object->hdev_obj, hmsg_mgr);
1233                 }
1234         }
1235         if (!status) {
1236                 /* Set the Device object's message manager */
1237                 status = dev_get_io_mgr(p_proc_object->hdev_obj, &hio_mgr);
1238                 if (hio_mgr)
1239                         status = (*p_proc_object->intf_fxns->pfn_io_on_loaded)
1240                                                                 (hio_mgr);
1241                 else
1242                         status = -EFAULT;
1243         }
1244         if (!status) {
1245                 /* Now, attempt to load an exec: */
1246
1247                 /* Boost the OPP level to Maximum level supported by baseport */
1248 #if defined(CONFIG_TIDSPBRIDGE_DVFS) && !defined(CONFIG_CPU_FREQ)
1249                 if (pdata->cpu_set_freq)
1250                         (*pdata->cpu_set_freq) (pdata->mpu_speed[VDD1_OPP5]);
1251 #endif
1252                 status = cod_load_base(cod_mgr, argc_index, (char **)user_args,
1253                                        dev_brd_write_fxn,
1254                                        p_proc_object->hdev_obj, NULL);
1255                 if (status) {
1256                         if (status == -EBADF) {
1257                                 dev_dbg(bridge, "%s: Failure to Load the EXE\n",
1258                                         __func__);
1259                         }
1260                         if (status == -ESPIPE) {
1261                                 pr_err("%s: Couldn't parse the file\n",
1262                                        __func__);
1263                         }
1264                 }
1265                 /* Requesting the lowest opp supported */
1266 #if defined(CONFIG_TIDSPBRIDGE_DVFS) && !defined(CONFIG_CPU_FREQ)
1267                 if (pdata->cpu_set_freq)
1268                         (*pdata->cpu_set_freq) (pdata->mpu_speed[VDD1_OPP1]);
1269 #endif
1270
1271         }
1272         if (!status) {
1273                 /* Update the Processor status to loaded */
1274                 status = (*p_proc_object->intf_fxns->pfn_brd_set_state)
1275                     (p_proc_object->hbridge_context, BRD_LOADED);
1276                 if (!status) {
1277                         p_proc_object->proc_state = PROC_LOADED;
1278                         if (p_proc_object->ntfy_obj)
1279                                 proc_notify_clients(p_proc_object,
1280                                                     DSP_PROCESSORSTATECHANGE);
1281                 }
1282         }
1283         if (!status) {
1284                 status = proc_get_processor_id(hprocessor, &proc_id);
1285                 if (proc_id == DSP_UNIT) {
1286                         /* Use all available DSP address space after EXTMEM
1287                          * for DMM */
1288                         if (!status)
1289                                 status = cod_get_sym_value(cod_mgr, EXTEND,
1290                                                            &dw_ext_end);
1291
1292                         /* Reset DMM structs and add an initial free chunk */
1293                         if (!status) {
1294                                 status =
1295                                     dev_get_dmm_mgr(p_proc_object->hdev_obj,
1296                                                     &dmm_mgr);
1297                                 if (dmm_mgr) {
1298                                         /* Set dw_ext_end to DMM START u8
1299                                          * address */
1300                                         dw_ext_end =
1301                                             (dw_ext_end + 1) * DSPWORDSIZE;
1302                                         /* DMM memory is from EXT_END */
1303                                         status = dmm_create_tables(dmm_mgr,
1304                                                                    dw_ext_end,
1305                                                                    DMMPOOLSIZE);
1306                                 } else {
1307                                         status = -EFAULT;
1308                                 }
1309                         }
1310                 }
1311         }
1312         /* Restore the original argv[0] */
1313         kfree(new_envp);
1314         user_args[0] = pargv0;
1315         if (!status) {
1316                 if (!((*p_proc_object->intf_fxns->pfn_brd_status)
1317                                 (p_proc_object->hbridge_context, &brd_state))) {
1318                         pr_info("%s: Processor Loaded %s\n", __func__, pargv0);
1319                         kfree(drv_datap->base_img);
1320                         drv_datap->base_img = kmalloc(strlen(pargv0) + 1,
1321                                                                 GFP_KERNEL);
1322                         if (drv_datap->base_img)
1323                                 strncpy(drv_datap->base_img, pargv0,
1324                                                         strlen(pargv0) + 1);
1325                         else
1326                                 status = -ENOMEM;
1327                         DBC_ASSERT(brd_state == BRD_LOADED);
1328                 }
1329         }
1330
1331 func_end:
1332         if (status) {
1333                 pr_err("%s: Processor failed to load\n", __func__);
1334                 proc_stop(p_proc_object);
1335         }
1336         DBC_ENSURE((!status
1337                     && p_proc_object->proc_state == PROC_LOADED)
1338                    || status);
1339 #ifdef OPT_LOAD_TIME_INSTRUMENTATION
1340         do_gettimeofday(&tv2);
1341         if (tv2.tv_usec < tv1.tv_usec) {
1342                 tv2.tv_usec += 1000000;
1343                 tv2.tv_sec--;
1344         }
1345         dev_dbg(bridge, "%s: time to load %d sec and %d usec\n", __func__,
1346                 tv2.tv_sec - tv1.tv_sec, tv2.tv_usec - tv1.tv_usec);
1347 #endif
1348         return status;
1349 }
1350
1351 /*
1352  *  ======== proc_map ========
1353  *  Purpose:
1354  *      Maps a MPU buffer to DSP address space.
1355  */
1356 int proc_map(void *hprocessor, void *pmpu_addr, u32 ul_size,
1357                     void *req_addr, void **pp_map_addr, u32 ul_map_attr,
1358                     struct process_context *pr_ctxt)
1359 {
1360         u32 va_align;
1361         u32 pa_align;
1362         struct dmm_object *dmm_mgr;
1363         u32 size_align;
1364         int status = 0;
1365         struct proc_object *p_proc_object = (struct proc_object *)hprocessor;
1366         struct dmm_map_object *map_obj;
1367         u32 tmp_addr = 0;
1368
1369 #ifdef CONFIG_TIDSPBRIDGE_CACHE_LINE_CHECK
1370         if ((ul_map_attr & BUFMODE_MASK) != RBUF) {
1371                 if (!IS_ALIGNED((u32)pmpu_addr, DSP_CACHE_LINE) ||
1372                     !IS_ALIGNED(ul_size, DSP_CACHE_LINE)) {
1373                         pr_err("%s: not aligned: 0x%x (%d)\n", __func__,
1374                                                 (u32)pmpu_addr, ul_size);
1375                         return -EFAULT;
1376                 }
1377         }
1378 #endif
1379
1380         /* Calculate the page-aligned PA, VA and size */
1381         va_align = PG_ALIGN_LOW((u32) req_addr, PG_SIZE4K);
1382         pa_align = PG_ALIGN_LOW((u32) pmpu_addr, PG_SIZE4K);
1383         size_align = PG_ALIGN_HIGH(ul_size + (u32) pmpu_addr - pa_align,
1384                                    PG_SIZE4K);
1385
1386         if (!p_proc_object) {
1387                 status = -EFAULT;
1388                 goto func_end;
1389         }
1390         /* Critical section */
1391         mutex_lock(&proc_lock);
1392         dmm_get_handle(p_proc_object, &dmm_mgr);
1393         if (dmm_mgr)
1394                 status = dmm_map_memory(dmm_mgr, va_align, size_align);
1395         else
1396                 status = -EFAULT;
1397
1398         /* Add mapping to the page tables. */
1399         if (!status) {
1400
1401                 /* Mapped address = MSB of VA | LSB of PA */
1402                 tmp_addr = (va_align | ((u32) pmpu_addr & (PG_SIZE4K - 1)));
1403                 /* mapped memory resource tracking */
1404                 map_obj = add_mapping_info(pr_ctxt, pa_align, tmp_addr,
1405                                                 size_align);
1406                 if (!map_obj)
1407                         status = -ENOMEM;
1408                 else
1409                         status = (*p_proc_object->intf_fxns->pfn_brd_mem_map)
1410                             (p_proc_object->hbridge_context, pa_align, va_align,
1411                              size_align, ul_map_attr, map_obj->pages);
1412         }
1413         if (!status) {
1414                 /* Mapped address = MSB of VA | LSB of PA */
1415                 *pp_map_addr = (void *) tmp_addr;
1416         } else {
1417                 remove_mapping_information(pr_ctxt, tmp_addr, size_align);
1418                 dmm_un_map_memory(dmm_mgr, va_align, &size_align);
1419         }
1420         mutex_unlock(&proc_lock);
1421
1422         if (status)
1423                 goto func_end;
1424
1425 func_end:
1426         dev_dbg(bridge, "%s: hprocessor %p, pmpu_addr %p, ul_size %x, "
1427                 "req_addr %p, ul_map_attr %x, pp_map_addr %p, va_align %x, "
1428                 "pa_align %x, size_align %x status 0x%x\n", __func__,
1429                 hprocessor, pmpu_addr, ul_size, req_addr, ul_map_attr,
1430                 pp_map_addr, va_align, pa_align, size_align, status);
1431
1432         return status;
1433 }
1434
1435 /*
1436  *  ======== proc_register_notify ========
1437  *  Purpose:
1438  *      Register to be notified of specific processor events.
1439  */
1440 int proc_register_notify(void *hprocessor, u32 event_mask,
1441                                 u32 notify_type, struct dsp_notification
1442                                 * hnotification)
1443 {
1444         int status = 0;
1445         struct proc_object *p_proc_object = (struct proc_object *)hprocessor;
1446         struct deh_mgr *hdeh_mgr;
1447
1448         DBC_REQUIRE(hnotification != NULL);
1449         DBC_REQUIRE(refs > 0);
1450
1451         /* Check processor handle */
1452         if (!p_proc_object) {
1453                 status = -EFAULT;
1454                 goto func_end;
1455         }
1456         /* Check if event mask is a valid processor related event */
1457         if (event_mask & ~(DSP_PROCESSORSTATECHANGE | DSP_PROCESSORATTACH |
1458                         DSP_PROCESSORDETACH | DSP_PROCESSORRESTART |
1459                         DSP_MMUFAULT | DSP_SYSERROR | DSP_PWRERROR |
1460                         DSP_WDTOVERFLOW))
1461                 status = -EINVAL;
1462
1463         /* Check if notify type is valid */
1464         if (notify_type != DSP_SIGNALEVENT)
1465                 status = -EINVAL;
1466
1467         if (!status) {
1468                 /* If event mask is not DSP_SYSERROR, DSP_MMUFAULT,
1469                  * or DSP_PWRERROR then register event immediately. */
1470                 if (event_mask &
1471                     ~(DSP_SYSERROR | DSP_MMUFAULT | DSP_PWRERROR |
1472                                 DSP_WDTOVERFLOW)) {
1473                         status = ntfy_register(p_proc_object->ntfy_obj,
1474                                                hnotification, event_mask,
1475                                                notify_type);
1476                         /* Special case alert, special case alert!
1477                          * If we're trying to *deregister* (i.e. event_mask
1478                          * is 0), a DSP_SYSERROR or DSP_MMUFAULT notification,
1479                          * we have to deregister with the DEH manager.
1480                          * There's no way to know, based on event_mask which
1481                          * manager the notification event was registered with,
1482                          * so if we're trying to deregister and ntfy_register
1483                          * failed, we'll give the deh manager a shot.
1484                          */
1485                         if ((event_mask == 0) && status) {
1486                                 status =
1487                                     dev_get_deh_mgr(p_proc_object->hdev_obj,
1488                                                     &hdeh_mgr);
1489                                 status =
1490                                         bridge_deh_register_notify(hdeh_mgr,
1491                                                         event_mask,
1492                                                         notify_type,
1493                                                         hnotification);
1494                         }
1495                 } else {
1496                         status = dev_get_deh_mgr(p_proc_object->hdev_obj,
1497                                                  &hdeh_mgr);
1498                         status =
1499                             bridge_deh_register_notify(hdeh_mgr,
1500                                             event_mask,
1501                                             notify_type,
1502                                             hnotification);
1503
1504                 }
1505         }
1506 func_end:
1507         return status;
1508 }
1509
1510 /*
1511  *  ======== proc_reserve_memory ========
1512  *  Purpose:
1513  *      Reserve a virtually contiguous region of DSP address space.
1514  */
1515 int proc_reserve_memory(void *hprocessor, u32 ul_size,
1516                                void **pp_rsv_addr,
1517                                struct process_context *pr_ctxt)
1518 {
1519         struct dmm_object *dmm_mgr;
1520         int status = 0;
1521         struct proc_object *p_proc_object = (struct proc_object *)hprocessor;
1522         struct dmm_rsv_object *rsv_obj;
1523
1524         if (!p_proc_object) {
1525                 status = -EFAULT;
1526                 goto func_end;
1527         }
1528
1529         status = dmm_get_handle(p_proc_object, &dmm_mgr);
1530         if (!dmm_mgr) {
1531                 status = -EFAULT;
1532                 goto func_end;
1533         }
1534
1535         status = dmm_reserve_memory(dmm_mgr, ul_size, (u32 *) pp_rsv_addr);
1536         if (status != 0)
1537                 goto func_end;
1538
1539         /*
1540          * A successful reserve should be followed by insertion of rsv_obj
1541          * into dmm_rsv_list, so that reserved memory resource tracking
1542          * remains uptodate
1543          */
1544         rsv_obj = kmalloc(sizeof(struct dmm_rsv_object), GFP_KERNEL);
1545         if (rsv_obj) {
1546                 rsv_obj->dsp_reserved_addr = (u32) *pp_rsv_addr;
1547                 spin_lock(&pr_ctxt->dmm_rsv_lock);
1548                 list_add(&rsv_obj->link, &pr_ctxt->dmm_rsv_list);
1549                 spin_unlock(&pr_ctxt->dmm_rsv_lock);
1550         }
1551
1552 func_end:
1553         dev_dbg(bridge, "%s: hprocessor: 0x%p ul_size: 0x%x pp_rsv_addr: 0x%p "
1554                 "status 0x%x\n", __func__, hprocessor,
1555                 ul_size, pp_rsv_addr, status);
1556         return status;
1557 }
1558
1559 /*
1560  *  ======== proc_start ========
1561  *  Purpose:
1562  *      Start a processor running.
1563  */
1564 int proc_start(void *hprocessor)
1565 {
1566         int status = 0;
1567         struct proc_object *p_proc_object = (struct proc_object *)hprocessor;
1568         struct cod_manager *cod_mgr;    /* Code manager handle */
1569         u32 dw_dsp_addr;        /* Loaded code's entry point. */
1570         int brd_state;
1571
1572         DBC_REQUIRE(refs > 0);
1573         if (!p_proc_object) {
1574                 status = -EFAULT;
1575                 goto func_end;
1576         }
1577         /* Call the bridge_brd_start */
1578         if (p_proc_object->proc_state != PROC_LOADED) {
1579                 status = -EBADR;
1580                 goto func_end;
1581         }
1582         status = dev_get_cod_mgr(p_proc_object->hdev_obj, &cod_mgr);
1583         if (!cod_mgr) {
1584                 status = -EFAULT;
1585                 goto func_cont;
1586         }
1587
1588         status = cod_get_entry(cod_mgr, &dw_dsp_addr);
1589         if (status)
1590                 goto func_cont;
1591
1592         status = (*p_proc_object->intf_fxns->pfn_brd_start)
1593             (p_proc_object->hbridge_context, dw_dsp_addr);
1594         if (status)
1595                 goto func_cont;
1596
1597         /* Call dev_create2 */
1598         status = dev_create2(p_proc_object->hdev_obj);
1599         if (!status) {
1600                 p_proc_object->proc_state = PROC_RUNNING;
1601                 /* Deep sleep switces off the peripheral clocks.
1602                  * we just put the DSP CPU in idle in the idle loop.
1603                  * so there is no need to send a command to DSP */
1604
1605                 if (p_proc_object->ntfy_obj) {
1606                         proc_notify_clients(p_proc_object,
1607                                             DSP_PROCESSORSTATECHANGE);
1608                 }
1609         } else {
1610                 /* Failed to Create Node Manager and DISP Object
1611                  * Stop the Processor from running. Put it in STOPPED State */
1612                 (void)(*p_proc_object->intf_fxns->
1613                        pfn_brd_stop) (p_proc_object->hbridge_context);
1614                 p_proc_object->proc_state = PROC_STOPPED;
1615         }
1616 func_cont:
1617         if (!status) {
1618                 if (!((*p_proc_object->intf_fxns->pfn_brd_status)
1619                                 (p_proc_object->hbridge_context, &brd_state))) {
1620                         pr_info("%s: dsp in running state\n", __func__);
1621                         DBC_ASSERT(brd_state != BRD_HIBERNATION);
1622                 }
1623         } else {
1624                 pr_err("%s: Failed to start the dsp\n", __func__);
1625                 proc_stop(p_proc_object);
1626         }
1627
1628 func_end:
1629         DBC_ENSURE((!status && p_proc_object->proc_state ==
1630                     PROC_RUNNING) || status);
1631         return status;
1632 }
1633
1634 /*
1635  *  ======== proc_stop ========
1636  *  Purpose:
1637  *      Stop a processor running.
1638  */
1639 int proc_stop(void *hprocessor)
1640 {
1641         int status = 0;
1642         struct proc_object *p_proc_object = (struct proc_object *)hprocessor;
1643         struct msg_mgr *hmsg_mgr;
1644         struct node_mgr *hnode_mgr;
1645         void *hnode;
1646         u32 node_tab_size = 1;
1647         u32 num_nodes = 0;
1648         u32 nodes_allocated = 0;
1649         int brd_state;
1650
1651         DBC_REQUIRE(refs > 0);
1652         if (!p_proc_object) {
1653                 status = -EFAULT;
1654                 goto func_end;
1655         }
1656         /* check if there are any running nodes */
1657         status = dev_get_node_manager(p_proc_object->hdev_obj, &hnode_mgr);
1658         if (!status && hnode_mgr) {
1659                 status = node_enum_nodes(hnode_mgr, &hnode, node_tab_size,
1660                                          &num_nodes, &nodes_allocated);
1661                 if ((status == -EINVAL) || (nodes_allocated > 0)) {
1662                         pr_err("%s: Can't stop device, active nodes = %d \n",
1663                                __func__, nodes_allocated);
1664                         return -EBADR;
1665                 }
1666         }
1667         /* Call the bridge_brd_stop */
1668         /* It is OK to stop a device that does n't have nodes OR not started */
1669         status =
1670             (*p_proc_object->intf_fxns->
1671              pfn_brd_stop) (p_proc_object->hbridge_context);
1672         if (!status) {
1673                 dev_dbg(bridge, "%s: processor in standby mode\n", __func__);
1674                 p_proc_object->proc_state = PROC_STOPPED;
1675                 /* Destory the Node Manager, msg_ctrl Manager */
1676                 if (!(dev_destroy2(p_proc_object->hdev_obj))) {
1677                         /* Destroy the msg_ctrl by calling msg_delete */
1678                         dev_get_msg_mgr(p_proc_object->hdev_obj, &hmsg_mgr);
1679                         if (hmsg_mgr) {
1680                                 msg_delete(hmsg_mgr);
1681                                 dev_set_msg_mgr(p_proc_object->hdev_obj, NULL);
1682                         }
1683                         if (!((*p_proc_object->
1684                               intf_fxns->pfn_brd_status) (p_proc_object->
1685                                                           hbridge_context,
1686                                                           &brd_state)))
1687                                 DBC_ASSERT(brd_state == BRD_STOPPED);
1688                 }
1689         } else {
1690                 pr_err("%s: Failed to stop the processor\n", __func__);
1691         }
1692 func_end:
1693
1694         return status;
1695 }
1696
1697 /*
1698  *  ======== proc_un_map ========
1699  *  Purpose:
1700  *      Removes a MPU buffer mapping from the DSP address space.
1701  */
1702 int proc_un_map(void *hprocessor, void *map_addr,
1703                        struct process_context *pr_ctxt)
1704 {
1705         int status = 0;
1706         struct proc_object *p_proc_object = (struct proc_object *)hprocessor;
1707         struct dmm_object *dmm_mgr;
1708         u32 va_align;
1709         u32 size_align;
1710
1711         va_align = PG_ALIGN_LOW((u32) map_addr, PG_SIZE4K);
1712         if (!p_proc_object) {
1713                 status = -EFAULT;
1714                 goto func_end;
1715         }
1716
1717         status = dmm_get_handle(hprocessor, &dmm_mgr);
1718         if (!dmm_mgr) {
1719                 status = -EFAULT;
1720                 goto func_end;
1721         }
1722
1723         /* Critical section */
1724         mutex_lock(&proc_lock);
1725         /*
1726          * Update DMM structures. Get the size to unmap.
1727          * This function returns error if the VA is not mapped
1728          */
1729         status = dmm_un_map_memory(dmm_mgr, (u32) va_align, &size_align);
1730         /* Remove mapping from the page tables. */
1731         if (!status) {
1732                 status = (*p_proc_object->intf_fxns->pfn_brd_mem_un_map)
1733                     (p_proc_object->hbridge_context, va_align, size_align);
1734         }
1735
1736         if (status)
1737                 goto unmap_failed;
1738
1739         /*
1740          * A successful unmap should be followed by removal of map_obj
1741          * from dmm_map_list, so that mapped memory resource tracking
1742          * remains uptodate
1743          */
1744         remove_mapping_information(pr_ctxt, (u32) map_addr, size_align);
1745
1746 unmap_failed:
1747         mutex_unlock(&proc_lock);
1748
1749 func_end:
1750         dev_dbg(bridge, "%s: hprocessor: 0x%p map_addr: 0x%p status: 0x%x\n",
1751                 __func__, hprocessor, map_addr, status);
1752         return status;
1753 }
1754
1755 /*
1756  *  ======== proc_un_reserve_memory ========
1757  *  Purpose:
1758  *      Frees a previously reserved region of DSP address space.
1759  */
1760 int proc_un_reserve_memory(void *hprocessor, void *prsv_addr,
1761                                   struct process_context *pr_ctxt)
1762 {
1763         struct dmm_object *dmm_mgr;
1764         int status = 0;
1765         struct proc_object *p_proc_object = (struct proc_object *)hprocessor;
1766         struct dmm_rsv_object *rsv_obj;
1767
1768         if (!p_proc_object) {
1769                 status = -EFAULT;
1770                 goto func_end;
1771         }
1772
1773         status = dmm_get_handle(p_proc_object, &dmm_mgr);
1774         if (!dmm_mgr) {
1775                 status = -EFAULT;
1776                 goto func_end;
1777         }
1778
1779         status = dmm_un_reserve_memory(dmm_mgr, (u32) prsv_addr);
1780         if (status != 0)
1781                 goto func_end;
1782
1783         /*
1784          * A successful unreserve should be followed by removal of rsv_obj
1785          * from dmm_rsv_list, so that reserved memory resource tracking
1786          * remains uptodate
1787          */
1788         spin_lock(&pr_ctxt->dmm_rsv_lock);
1789         list_for_each_entry(rsv_obj, &pr_ctxt->dmm_rsv_list, link) {
1790                 if (rsv_obj->dsp_reserved_addr == (u32) prsv_addr) {
1791                         list_del(&rsv_obj->link);
1792                         kfree(rsv_obj);
1793                         break;
1794                 }
1795         }
1796         spin_unlock(&pr_ctxt->dmm_rsv_lock);
1797
1798 func_end:
1799         dev_dbg(bridge, "%s: hprocessor: 0x%p prsv_addr: 0x%p status: 0x%x\n",
1800                 __func__, hprocessor, prsv_addr, status);
1801         return status;
1802 }
1803
1804 /*
1805  *  ======== = proc_monitor ======== ==
1806  *  Purpose:
1807  *      Place the Processor in Monitor State. This is an internal
1808  *      function and a requirement before Processor is loaded.
1809  *      This does a bridge_brd_stop, dev_destroy2 and bridge_brd_monitor.
1810  *      In dev_destroy2 we delete the node manager.
1811  *  Parameters:
1812  *      p_proc_object:    Pointer to Processor Object
1813  *  Returns:
1814  *      0:      Processor placed in monitor mode.
1815  *      !0:       Failed to place processor in monitor mode.
1816  *  Requires:
1817  *      Valid Processor Handle
1818  *  Ensures:
1819  *      Success:        ProcObject state is PROC_IDLE
1820  */
1821 static int proc_monitor(struct proc_object *proc_obj)
1822 {
1823         int status = -EPERM;
1824         struct msg_mgr *hmsg_mgr;
1825         int brd_state;
1826
1827         DBC_REQUIRE(refs > 0);
1828         DBC_REQUIRE(proc_obj);
1829
1830         /* This is needed only when Device is loaded when it is
1831          * already 'ACTIVE' */
1832         /* Destory the Node Manager, msg_ctrl Manager */
1833         if (!dev_destroy2(proc_obj->hdev_obj)) {
1834                 /* Destroy the msg_ctrl by calling msg_delete */
1835                 dev_get_msg_mgr(proc_obj->hdev_obj, &hmsg_mgr);
1836                 if (hmsg_mgr) {
1837                         msg_delete(hmsg_mgr);
1838                         dev_set_msg_mgr(proc_obj->hdev_obj, NULL);
1839                 }
1840         }
1841         /* Place the Board in the Monitor State */
1842         if (!((*proc_obj->intf_fxns->pfn_brd_monitor)
1843                           (proc_obj->hbridge_context))) {
1844                 status = 0;
1845                 if (!((*proc_obj->intf_fxns->pfn_brd_status)
1846                                   (proc_obj->hbridge_context, &brd_state)))
1847                         DBC_ASSERT(brd_state == BRD_IDLE);
1848         }
1849
1850         DBC_ENSURE((!status && brd_state == BRD_IDLE) ||
1851                    status);
1852         return status;
1853 }
1854
1855 /*
1856  *  ======== get_envp_count ========
1857  *  Purpose:
1858  *      Return the number of elements in the envp array, including the
1859  *      terminating NULL element.
1860  */
1861 static s32 get_envp_count(char **envp)
1862 {
1863         s32 ret = 0;
1864         if (envp) {
1865                 while (*envp++)
1866                         ret++;
1867
1868                 ret += 1;       /* Include the terminating NULL in the count. */
1869         }
1870
1871         return ret;
1872 }
1873
1874 /*
1875  *  ======== prepend_envp ========
1876  *  Purpose:
1877  *      Prepend an environment variable=value pair to the new envp array, and
1878  *      copy in the existing var=value pairs in the old envp array.
1879  */
1880 static char **prepend_envp(char **new_envp, char **envp, s32 envp_elems,
1881                            s32 cnew_envp, char *sz_var)
1882 {
1883         char **pp_envp = new_envp;
1884
1885         DBC_REQUIRE(new_envp);
1886
1887         /* Prepend new environ var=value string */
1888         *new_envp++ = sz_var;
1889
1890         /* Copy user's environment into our own. */
1891         while (envp_elems--)
1892                 *new_envp++ = *envp++;
1893
1894         /* Ensure NULL terminates the new environment strings array. */
1895         if (envp_elems == 0)
1896                 *new_envp = NULL;
1897
1898         return pp_envp;
1899 }
1900
1901 /*
1902  *  ======== proc_notify_clients ========
1903  *  Purpose:
1904  *      Notify the processor the events.
1905  */
1906 int proc_notify_clients(void *proc, u32 events)
1907 {
1908         int status = 0;
1909         struct proc_object *p_proc_object = (struct proc_object *)proc;
1910
1911         DBC_REQUIRE(p_proc_object);
1912         DBC_REQUIRE(is_valid_proc_event(events));
1913         DBC_REQUIRE(refs > 0);
1914         if (!p_proc_object) {
1915                 status = -EFAULT;
1916                 goto func_end;
1917         }
1918
1919         ntfy_notify(p_proc_object->ntfy_obj, events);
1920 func_end:
1921         return status;
1922 }
1923
1924 /*
1925  *  ======== proc_notify_all_clients ========
1926  *  Purpose:
1927  *      Notify the processor the events. This includes notifying all clients
1928  *      attached to a particulat DSP.
1929  */
1930 int proc_notify_all_clients(void *proc, u32 events)
1931 {
1932         int status = 0;
1933         struct proc_object *p_proc_object = (struct proc_object *)proc;
1934
1935         DBC_REQUIRE(is_valid_proc_event(events));
1936         DBC_REQUIRE(refs > 0);
1937
1938         if (!p_proc_object) {
1939                 status = -EFAULT;
1940                 goto func_end;
1941         }
1942
1943         dev_notify_clients(p_proc_object->hdev_obj, events);
1944
1945 func_end:
1946         return status;
1947 }
1948
1949 /*
1950  *  ======== proc_get_processor_id ========
1951  *  Purpose:
1952  *      Retrieves the processor ID.
1953  */
1954 int proc_get_processor_id(void *proc, u32 * proc_id)
1955 {
1956         int status = 0;
1957         struct proc_object *p_proc_object = (struct proc_object *)proc;
1958
1959         if (p_proc_object)
1960                 *proc_id = p_proc_object->processor_id;
1961         else
1962                 status = -EFAULT;
1963
1964         return status;
1965 }