4 * DSP-BIOS Bridge driver support functions for TI OMAP processors.
6 * Processor interface at the driver level.
8 * Copyright (C) 2005-2006 Texas Instruments, Inc.
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.
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.
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>
25 /* ----------------------------------- DSP/BIOS Bridge */
26 #include <dspbridge/dbdefs.h>
28 /* ----------------------------------- OS Adaptation Layer */
29 #include <dspbridge/ntfy.h>
30 #include <dspbridge/sync.h>
31 /* ----------------------------------- Bridge Driver */
32 #include <dspbridge/dspdefs.h>
33 #include <dspbridge/dspdeh.h>
34 /* ----------------------------------- Platform Manager */
35 #include <dspbridge/cod.h>
36 #include <dspbridge/dev.h>
37 #include <dspbridge/procpriv.h>
38 #include <dspbridge/dmm.h>
40 /* ----------------------------------- Resource Manager */
41 #include <dspbridge/mgr.h>
42 #include <dspbridge/node.h>
43 #include <dspbridge/nldr.h>
44 #include <dspbridge/rmm.h>
46 /* ----------------------------------- Others */
47 #include <dspbridge/dbdcd.h>
48 #include <dspbridge/msg.h>
49 #include <dspbridge/dspioctl.h>
50 #include <dspbridge/drv.h>
52 /* ----------------------------------- This */
53 #include <dspbridge/proc.h>
54 #include <dspbridge/pwr.h>
56 #include <dspbridge/resourcecleanup.h>
57 /* ----------------------------------- Defines, Data Structures, Typedefs */
58 #define MAXCMDLINELEN 255
59 #define PROC_ENVPROCID "PROC_ID=%d"
60 #define MAXPROCIDLEN (8 + 5)
61 #define PROC_DFLT_TIMEOUT 10000 /* Time out in milliseconds */
62 #define PWR_TIMEOUT 500 /* Sleep/wake timout in msec */
63 #define EXTEND "_EXT_END" /* Extmem end addr in DSP binary */
65 #define DSP_CACHE_LINE 128
67 #define BUFMODE_MASK (3 << 14)
69 /* Buffer modes from DSP perspective */
70 #define RBUF 0x4000 /* Input buffer */
71 #define WBUF 0x8000 /* Output Buffer */
73 extern struct device *bridge;
75 /* ----------------------------------- Globals */
77 /* The proc_object structure. */
79 struct list_head link; /* Link to next proc_object */
80 struct dev_object *dev_obj; /* Device this PROC represents */
81 u32 process; /* Process owning this Processor */
82 struct mgr_object *mgr_obj; /* Manager Object Handle */
83 u32 attach_count; /* Processor attach count */
84 u32 processor_id; /* Processor number */
85 u32 timeout; /* Time out count */
86 enum dsp_procstate proc_state; /* Processor state */
87 u32 unit; /* DDSP unit number */
88 bool is_already_attached; /*
89 * True if the Device below has
92 struct ntfy_object *ntfy_obj; /* Manages notifications */
93 /* Bridge Context Handle */
94 struct bridge_dev_context *bridge_context;
95 /* Function interface to Bridge driver */
96 struct bridge_drv_interface *intf_fxns;
98 struct list_head proc_list;
101 DEFINE_MUTEX(proc_lock); /* For critical sections */
103 /* ----------------------------------- Function Prototypes */
104 static int proc_monitor(struct proc_object *proc_obj);
105 static s32 get_envp_count(char **envp);
106 static char **prepend_envp(char **new_envp, char **envp, s32 envp_elems,
107 s32 cnew_envp, char *sz_var);
109 /* remember mapping information */
110 static struct dmm_map_object *add_mapping_info(struct process_context *pr_ctxt,
111 u32 mpu_addr, u32 dsp_addr, u32 size)
113 struct dmm_map_object *map_obj;
115 u32 num_usr_pgs = size / PG_SIZE4K;
117 pr_debug("%s: adding map info: mpu_addr 0x%x virt 0x%x size 0x%x\n",
121 map_obj = kzalloc(sizeof(struct dmm_map_object), GFP_KERNEL);
125 INIT_LIST_HEAD(&map_obj->link);
127 map_obj->pages = kcalloc(num_usr_pgs, sizeof(struct page *),
129 if (!map_obj->pages) {
134 map_obj->mpu_addr = mpu_addr;
135 map_obj->dsp_addr = dsp_addr;
136 map_obj->size = size;
137 map_obj->num_usr_pgs = num_usr_pgs;
139 spin_lock(&pr_ctxt->dmm_map_lock);
140 list_add(&map_obj->link, &pr_ctxt->dmm_map_list);
141 spin_unlock(&pr_ctxt->dmm_map_lock);
146 static int match_exact_map_obj(struct dmm_map_object *map_obj,
147 u32 dsp_addr, u32 size)
149 if (map_obj->dsp_addr == dsp_addr && map_obj->size != size)
150 pr_err("%s: addr match (0x%x), size don't (0x%x != 0x%x)\n",
151 __func__, dsp_addr, map_obj->size, size);
153 return map_obj->dsp_addr == dsp_addr &&
154 map_obj->size == size;
157 static void remove_mapping_information(struct process_context *pr_ctxt,
158 u32 dsp_addr, u32 size)
160 struct dmm_map_object *map_obj;
162 pr_debug("%s: looking for virt 0x%x size 0x%x\n", __func__,
165 spin_lock(&pr_ctxt->dmm_map_lock);
166 list_for_each_entry(map_obj, &pr_ctxt->dmm_map_list, link) {
167 pr_debug("%s: candidate: mpu_addr 0x%x virt 0x%x size 0x%x\n",
173 if (match_exact_map_obj(map_obj, dsp_addr, size)) {
174 pr_debug("%s: match, deleting map info\n", __func__);
175 list_del(&map_obj->link);
176 kfree(map_obj->dma_info.sg);
177 kfree(map_obj->pages);
181 pr_debug("%s: candidate didn't match\n", __func__);
184 pr_err("%s: failed to find given map info\n", __func__);
186 spin_unlock(&pr_ctxt->dmm_map_lock);
189 static int match_containing_map_obj(struct dmm_map_object *map_obj,
190 u32 mpu_addr, u32 size)
192 u32 map_obj_end = map_obj->mpu_addr + map_obj->size;
194 return mpu_addr >= map_obj->mpu_addr &&
195 mpu_addr + size <= map_obj_end;
198 static struct dmm_map_object *find_containing_mapping(
199 struct process_context *pr_ctxt,
200 u32 mpu_addr, u32 size)
202 struct dmm_map_object *map_obj;
203 pr_debug("%s: looking for mpu_addr 0x%x size 0x%x\n", __func__,
206 spin_lock(&pr_ctxt->dmm_map_lock);
207 list_for_each_entry(map_obj, &pr_ctxt->dmm_map_list, link) {
208 pr_debug("%s: candidate: mpu_addr 0x%x virt 0x%x size 0x%x\n",
213 if (match_containing_map_obj(map_obj, mpu_addr, size)) {
214 pr_debug("%s: match!\n", __func__);
218 pr_debug("%s: no match!\n", __func__);
223 spin_unlock(&pr_ctxt->dmm_map_lock);
227 static int find_first_page_in_cache(struct dmm_map_object *map_obj,
228 unsigned long mpu_addr)
230 u32 mapped_base_page = map_obj->mpu_addr >> PAGE_SHIFT;
231 u32 requested_base_page = mpu_addr >> PAGE_SHIFT;
232 int pg_index = requested_base_page - mapped_base_page;
234 if (pg_index < 0 || pg_index >= map_obj->num_usr_pgs) {
235 pr_err("%s: failed (got %d)\n", __func__, pg_index);
239 pr_debug("%s: first page is %d\n", __func__, pg_index);
243 static inline struct page *get_mapping_page(struct dmm_map_object *map_obj,
246 pr_debug("%s: looking for pg_i %d, num_usr_pgs: %d\n", __func__,
247 pg_i, map_obj->num_usr_pgs);
249 if (pg_i < 0 || pg_i >= map_obj->num_usr_pgs) {
250 pr_err("%s: requested pg_i %d is out of mapped range\n",
255 return map_obj->pages[pg_i];
259 * ======== proc_attach ========
261 * Prepare for communication with a particular DSP processor, and return
262 * a handle to the processor object.
265 proc_attach(u32 processor_id,
266 const struct dsp_processorattrin *attr_in,
267 void **ph_processor, struct process_context *pr_ctxt)
270 struct dev_object *hdev_obj;
271 struct proc_object *p_proc_object = NULL;
272 struct mgr_object *hmgr_obj = NULL;
273 struct drv_object *hdrv_obj = NULL;
274 struct drv_data *drv_datap = dev_get_drvdata(bridge);
277 if (pr_ctxt->processor) {
278 *ph_processor = pr_ctxt->processor;
282 /* Get the Driver and Manager Object Handles */
283 if (!drv_datap || !drv_datap->drv_object || !drv_datap->mgr_object) {
285 pr_err("%s: Failed to get object handles\n", __func__);
287 hdrv_obj = drv_datap->drv_object;
288 hmgr_obj = drv_datap->mgr_object;
292 /* Get the Device Object */
293 status = drv_get_dev_object(processor_id, hdrv_obj, &hdev_obj);
296 status = dev_get_dev_type(hdev_obj, &dev_type);
301 /* If we made it this far, create the Processor object: */
302 p_proc_object = kzalloc(sizeof(struct proc_object), GFP_KERNEL);
303 /* Fill out the Processor Object: */
304 if (p_proc_object == NULL) {
308 p_proc_object->dev_obj = hdev_obj;
309 p_proc_object->mgr_obj = hmgr_obj;
310 p_proc_object->processor_id = dev_type;
311 /* Store TGID instead of process handle */
312 p_proc_object->process = current->tgid;
314 INIT_LIST_HEAD(&p_proc_object->proc_list);
317 p_proc_object->timeout = attr_in->timeout;
319 p_proc_object->timeout = PROC_DFLT_TIMEOUT;
321 status = dev_get_intf_fxns(hdev_obj, &p_proc_object->intf_fxns);
323 status = dev_get_bridge_context(hdev_obj,
324 &p_proc_object->bridge_context);
326 kfree(p_proc_object);
328 kfree(p_proc_object);
333 /* Create the Notification Object */
334 /* This is created with no event mask, no notify mask
335 * and no valid handle to the notification. They all get
336 * filled up when proc_register_notify is called */
337 p_proc_object->ntfy_obj = kmalloc(sizeof(struct ntfy_object),
339 if (p_proc_object->ntfy_obj)
340 ntfy_init(p_proc_object->ntfy_obj);
345 /* Insert the Processor Object into the DEV List.
346 * Return handle to this Processor Object:
347 * Find out if the Device is already attached to a
348 * Processor. If so, return AlreadyAttached status */
349 status = dev_insert_proc_object(p_proc_object->dev_obj,
352 is_already_attached);
354 if (p_proc_object->is_already_attached)
357 if (p_proc_object->ntfy_obj) {
358 ntfy_delete(p_proc_object->ntfy_obj);
359 kfree(p_proc_object->ntfy_obj);
362 kfree(p_proc_object);
365 *ph_processor = (void *)p_proc_object;
366 pr_ctxt->processor = *ph_processor;
367 (void)proc_notify_clients(p_proc_object,
368 DSP_PROCESSORATTACH);
371 /* Don't leak memory if status is failed */
372 kfree(p_proc_object);
378 static int get_exec_file(struct cfg_devnode *dev_node_obj,
379 struct dev_object *hdev_obj,
380 u32 size, char *exec_file)
383 struct drv_data *drv_datap = dev_get_drvdata(bridge);
385 dev_get_dev_type(hdev_obj, (u8 *) &dev_type);
390 if (dev_type == DSP_UNIT) {
391 if (!drv_datap || !drv_datap->base_img)
394 if (strlen(drv_datap->base_img) >= size)
397 strcpy(exec_file, drv_datap->base_img);
406 * ======== proc_auto_start ======== =
408 * A Particular device gets loaded with the default image
409 * if the AutoStart flag is set.
411 * hdev_obj: Handle to the Device
413 * 0: On Successful Loading
414 * -EPERM General Failure
419 int proc_auto_start(struct cfg_devnode *dev_node_obj,
420 struct dev_object *hdev_obj)
423 struct proc_object *p_proc_object;
424 char sz_exec_file[MAXCMDLINELEN];
426 struct mgr_object *hmgr_obj = NULL;
427 struct drv_data *drv_datap = dev_get_drvdata(bridge);
430 /* Create a Dummy PROC Object */
431 if (!drv_datap || !drv_datap->mgr_object) {
433 pr_err("%s: Failed to retrieve the object handle\n", __func__);
436 hmgr_obj = drv_datap->mgr_object;
439 p_proc_object = kzalloc(sizeof(struct proc_object), GFP_KERNEL);
440 if (p_proc_object == NULL) {
444 p_proc_object->dev_obj = hdev_obj;
445 p_proc_object->mgr_obj = hmgr_obj;
446 status = dev_get_intf_fxns(hdev_obj, &p_proc_object->intf_fxns);
448 status = dev_get_bridge_context(hdev_obj,
449 &p_proc_object->bridge_context);
453 /* Stop the Device, put it into standby mode */
454 status = proc_stop(p_proc_object);
459 /* Get the default executable for this board... */
460 dev_get_dev_type(hdev_obj, (u8 *) &dev_type);
461 p_proc_object->processor_id = dev_type;
462 status = get_exec_file(dev_node_obj, hdev_obj, sizeof(sz_exec_file),
465 argv[0] = sz_exec_file;
467 /* ...and try to load it: */
468 status = proc_load(p_proc_object, 1, (const char **)argv, NULL);
470 status = proc_start(p_proc_object);
472 kfree(p_proc_object->last_coff);
473 p_proc_object->last_coff = NULL;
475 kfree(p_proc_object);
481 * ======== proc_ctrl ========
483 * Pass control information to the GPP device driver managing the
486 * This will be an OEM-only function, and not part of the DSP/BIOS Bridge
487 * application developer's API.
488 * Call the bridge_dev_ctrl fxn with the Argument. This is a Synchronous
489 * Operation. arg can be null.
491 int proc_ctrl(void *hprocessor, u32 dw_cmd, struct dsp_cbdata *arg)
494 struct proc_object *p_proc_object = hprocessor;
498 /* intercept PWR deep sleep command */
499 if (dw_cmd == BRDIOCTL_DEEPSLEEP) {
500 timeout = arg->cb_data;
501 status = pwr_sleep_dsp(PWR_DEEPSLEEP, timeout);
503 /* intercept PWR emergency sleep command */
504 else if (dw_cmd == BRDIOCTL_EMERGENCYSLEEP) {
505 timeout = arg->cb_data;
506 status = pwr_sleep_dsp(PWR_EMERGENCYDEEPSLEEP, timeout);
507 } else if (dw_cmd == PWR_DEEPSLEEP) {
508 /* timeout = arg->cb_data; */
509 status = pwr_sleep_dsp(PWR_DEEPSLEEP, timeout);
511 /* intercept PWR wake commands */
512 else if (dw_cmd == BRDIOCTL_WAKEUP) {
513 timeout = arg->cb_data;
514 status = pwr_wake_dsp(timeout);
515 } else if (dw_cmd == PWR_WAKEUP) {
516 /* timeout = arg->cb_data; */
517 status = pwr_wake_dsp(timeout);
519 if (!((*p_proc_object->intf_fxns->dev_cntrl)
520 (p_proc_object->bridge_context, dw_cmd,
534 * ======== proc_detach ========
536 * Destroys the Processor Object. Removes the notification from the Dev
539 int proc_detach(struct process_context *pr_ctxt)
542 struct proc_object *p_proc_object = NULL;
544 p_proc_object = (struct proc_object *)pr_ctxt->processor;
547 /* Notify the Client */
548 ntfy_notify(p_proc_object->ntfy_obj, DSP_PROCESSORDETACH);
549 /* Remove the notification memory */
550 if (p_proc_object->ntfy_obj) {
551 ntfy_delete(p_proc_object->ntfy_obj);
552 kfree(p_proc_object->ntfy_obj);
555 kfree(p_proc_object->last_coff);
556 p_proc_object->last_coff = NULL;
557 /* Remove the Proc from the DEV List */
558 (void)dev_remove_proc_object(p_proc_object->dev_obj,
559 (u32) p_proc_object);
560 /* Free the Processor Object */
561 kfree(p_proc_object);
562 pr_ctxt->processor = NULL;
571 * ======== proc_enum_nodes ========
573 * Enumerate and get configuration information about nodes allocated
574 * on a DSP processor.
576 int proc_enum_nodes(void *hprocessor, void **node_tab,
577 u32 node_tab_size, u32 *pu_num_nodes,
581 struct proc_object *p_proc_object = (struct proc_object *)hprocessor;
582 struct node_mgr *hnode_mgr = NULL;
585 if (!(dev_get_node_manager(p_proc_object->dev_obj,
588 status = node_enum_nodes(hnode_mgr, node_tab,
601 /* Cache operation against kernel address instead of users */
602 static int build_dma_sg(struct dmm_map_object *map_obj, unsigned long start,
603 ssize_t len, int pg_i)
606 unsigned long offset;
609 struct scatterlist *sg = map_obj->dma_info.sg;
612 page = get_mapping_page(map_obj, pg_i);
614 pr_err("%s: no page for %08lx\n", __func__, start);
617 } else if (IS_ERR(page)) {
618 pr_err("%s: err page for %08lx(%lu)\n", __func__, start,
624 offset = start & ~PAGE_MASK;
625 rest = min_t(ssize_t, PAGE_SIZE - offset, len);
627 sg_set_page(&sg[i], page, rest, offset);
634 if (i != map_obj->dma_info.num_pages) {
635 pr_err("%s: bad number of sg iterations\n", __func__);
644 static int memory_regain_ownership(struct dmm_map_object *map_obj,
645 unsigned long start, ssize_t len, enum dma_data_direction dir)
648 unsigned long first_data_page = start >> PAGE_SHIFT;
649 unsigned long last_data_page = ((u32)(start + len - 1) >> PAGE_SHIFT);
650 /* calculating the number of pages this area spans */
651 unsigned long num_pages = last_data_page - first_data_page + 1;
652 struct bridge_dma_map_info *dma_info = &map_obj->dma_info;
657 if (dma_info->dir != dir || dma_info->num_pages != num_pages) {
658 pr_err("%s: dma info doesn't match given params\n", __func__);
662 dma_unmap_sg(bridge, dma_info->sg, num_pages, dma_info->dir);
664 pr_debug("%s: dma_map_sg unmapped\n", __func__);
668 map_obj->dma_info.sg = NULL;
674 /* Cache operation against kernel address instead of users */
675 static int memory_give_ownership(struct dmm_map_object *map_obj,
676 unsigned long start, ssize_t len, enum dma_data_direction dir)
678 int pg_i, ret, sg_num;
679 struct scatterlist *sg;
680 unsigned long first_data_page = start >> PAGE_SHIFT;
681 unsigned long last_data_page = ((u32)(start + len - 1) >> PAGE_SHIFT);
682 /* calculating the number of pages this area spans */
683 unsigned long num_pages = last_data_page - first_data_page + 1;
685 pg_i = find_first_page_in_cache(map_obj, start);
687 pr_err("%s: failed to find first page in cache\n", __func__);
692 sg = kcalloc(num_pages, sizeof(*sg), GFP_KERNEL);
698 sg_init_table(sg, num_pages);
700 /* cleanup a previous sg allocation */
701 /* this may happen if application doesn't signal for e/o DMA */
702 kfree(map_obj->dma_info.sg);
704 map_obj->dma_info.sg = sg;
705 map_obj->dma_info.dir = dir;
706 map_obj->dma_info.num_pages = num_pages;
708 ret = build_dma_sg(map_obj, start, len, pg_i);
712 sg_num = dma_map_sg(bridge, sg, num_pages, dir);
714 pr_err("%s: dma_map_sg failed: %d\n", __func__, sg_num);
719 pr_debug("%s: dma_map_sg mapped %d elements\n", __func__, sg_num);
720 map_obj->dma_info.sg_num = sg_num;
726 map_obj->dma_info.sg = NULL;
731 int proc_begin_dma(void *hprocessor, void *pmpu_addr, u32 ul_size,
732 enum dma_data_direction dir)
734 /* Keep STATUS here for future additions to this function */
736 struct process_context *pr_ctxt = (struct process_context *) hprocessor;
737 struct dmm_map_object *map_obj;
744 pr_debug("%s: addr 0x%x, size 0x%x, type %d\n", __func__,
748 mutex_lock(&proc_lock);
750 /* find requested memory are in cached mapping information */
751 map_obj = find_containing_mapping(pr_ctxt, (u32) pmpu_addr, ul_size);
753 pr_err("%s: find_containing_mapping failed\n", __func__);
758 if (memory_give_ownership(map_obj, (u32) pmpu_addr, ul_size, dir)) {
759 pr_err("%s: InValid address parameters %p %x\n",
760 __func__, pmpu_addr, ul_size);
765 mutex_unlock(&proc_lock);
771 int proc_end_dma(void *hprocessor, void *pmpu_addr, u32 ul_size,
772 enum dma_data_direction dir)
774 /* Keep STATUS here for future additions to this function */
776 struct process_context *pr_ctxt = (struct process_context *) hprocessor;
777 struct dmm_map_object *map_obj;
784 pr_debug("%s: addr 0x%x, size 0x%x, type %d\n", __func__,
788 mutex_lock(&proc_lock);
790 /* find requested memory are in cached mapping information */
791 map_obj = find_containing_mapping(pr_ctxt, (u32) pmpu_addr, ul_size);
793 pr_err("%s: find_containing_mapping failed\n", __func__);
798 if (memory_regain_ownership(map_obj, (u32) pmpu_addr, ul_size, dir)) {
799 pr_err("%s: InValid address parameters %p %x\n",
800 __func__, pmpu_addr, ul_size);
805 mutex_unlock(&proc_lock);
811 * ======== proc_flush_memory ========
815 int proc_flush_memory(void *hprocessor, void *pmpu_addr,
816 u32 ul_size, u32 ul_flags)
818 enum dma_data_direction dir = DMA_BIDIRECTIONAL;
820 return proc_begin_dma(hprocessor, pmpu_addr, ul_size, dir);
824 * ======== proc_invalidate_memory ========
826 * Invalidates the memory specified
828 int proc_invalidate_memory(void *hprocessor, void *pmpu_addr, u32 size)
830 enum dma_data_direction dir = DMA_FROM_DEVICE;
832 return proc_begin_dma(hprocessor, pmpu_addr, size, dir);
836 * ======== proc_get_resource_info ========
838 * Enumerate the resources currently available on a processor.
840 int proc_get_resource_info(void *hprocessor, u32 resource_type,
841 struct dsp_resourceinfo *resource_info,
842 u32 resource_info_size)
845 struct proc_object *p_proc_object = (struct proc_object *)hprocessor;
846 struct node_mgr *hnode_mgr = NULL;
847 struct nldr_object *nldr_obj = NULL;
848 struct rmm_target_obj *rmm = NULL;
849 struct io_mgr *hio_mgr = NULL; /* IO manager handle */
851 if (!p_proc_object) {
855 switch (resource_type) {
856 case DSP_RESOURCE_DYNDARAM:
857 case DSP_RESOURCE_DYNSARAM:
858 case DSP_RESOURCE_DYNEXTERNAL:
859 case DSP_RESOURCE_DYNSRAM:
860 status = dev_get_node_manager(p_proc_object->dev_obj,
867 status = node_get_nldr_obj(hnode_mgr, &nldr_obj);
869 status = nldr_get_rmm_manager(nldr_obj, &rmm);
872 (enum dsp_memtype)resource_type,
873 (struct dsp_memstat *)
874 &(resource_info->result.
882 case DSP_RESOURCE_PROCLOAD:
883 status = dev_get_io_mgr(p_proc_object->dev_obj, &hio_mgr);
886 p_proc_object->intf_fxns->
887 io_get_proc_load(hio_mgr,
888 (struct dsp_procloadstat *)
889 &(resource_info->result.
903 * ======== proc_get_dev_object ========
905 * Return the Dev Object handle for a given Processor.
908 int proc_get_dev_object(void *hprocessor,
909 struct dev_object **device_obj)
912 struct proc_object *p_proc_object = (struct proc_object *)hprocessor;
915 *device_obj = p_proc_object->dev_obj;
926 * ======== proc_get_state ========
928 * Report the state of the specified DSP processor.
930 int proc_get_state(void *hprocessor,
931 struct dsp_processorstate *proc_state_obj,
935 struct proc_object *p_proc_object = (struct proc_object *)hprocessor;
939 /* First, retrieve BRD state information */
940 status = (*p_proc_object->intf_fxns->brd_status)
941 (p_proc_object->bridge_context, &brd_status);
943 switch (brd_status) {
945 proc_state_obj->proc_state = PROC_STOPPED;
947 case BRD_SLEEP_TRANSITION:
948 case BRD_DSP_HIBERNATION:
951 proc_state_obj->proc_state = PROC_RUNNING;
954 proc_state_obj->proc_state = PROC_LOADED;
957 proc_state_obj->proc_state = PROC_ERROR;
960 proc_state_obj->proc_state = 0xFF;
968 dev_dbg(bridge, "%s, results: status: 0x%x proc_state_obj: 0x%x\n",
969 __func__, status, proc_state_obj->proc_state);
974 * ======== proc_get_trace ========
976 * Retrieve the current contents of the trace buffer, located on the
977 * Processor. Predefined symbols for the trace buffer must have been
978 * configured into the DSP executable.
980 * We support using the symbols SYS_PUTCBEG and SYS_PUTCEND to define a
981 * trace buffer, only. Treat it as an undocumented feature.
982 * This call is destructive, meaning the processor is placed in the monitor
983 * state as a result of this function.
985 int proc_get_trace(void *hprocessor, u8 *pbuf, u32 max_size)
993 * ======== proc_load ========
995 * Reset a processor and load a new base program image.
996 * This will be an OEM-only function, and not part of the DSP/BIOS Bridge
997 * application developer's API.
999 int proc_load(void *hprocessor, const s32 argc_index,
1000 const char **user_args, const char **user_envp)
1003 struct proc_object *p_proc_object = (struct proc_object *)hprocessor;
1004 struct io_mgr *hio_mgr; /* IO manager handle */
1005 struct msg_mgr *hmsg_mgr;
1006 struct cod_manager *cod_mgr; /* Code manager handle */
1007 char *pargv0; /* temp argv[0] ptr */
1008 char **new_envp; /* Updated envp[] array. */
1009 char sz_proc_id[MAXPROCIDLEN]; /* Size of "PROC_ID=<n>" */
1010 s32 envp_elems; /* Num elements in envp[]. */
1011 s32 cnew_envp; /* " " in new_envp[] */
1012 s32 nproc_id = 0; /* Anticipate MP version. */
1013 struct dcd_manager *hdcd_handle;
1014 struct dmm_object *dmm_mgr;
1018 struct drv_data *drv_datap = dev_get_drvdata(bridge);
1020 #ifdef OPT_LOAD_TIME_INSTRUMENTATION
1025 #if defined(CONFIG_TIDSPBRIDGE_DVFS) && !defined(CONFIG_CPU_FREQ)
1026 struct dspbridge_platform_data *pdata =
1027 omap_dspbridge_dev->dev.platform_data;
1030 #ifdef OPT_LOAD_TIME_INSTRUMENTATION
1031 do_gettimeofday(&tv1);
1033 if (!p_proc_object) {
1037 dev_get_cod_mgr(p_proc_object->dev_obj, &cod_mgr);
1042 status = proc_stop(hprocessor);
1046 /* Place the board in the monitor state. */
1047 status = proc_monitor(hprocessor);
1051 /* Save ptr to original argv[0]. */
1052 pargv0 = (char *)user_args[0];
1053 /*Prepend "PROC_ID=<nproc_id>"to envp array for target. */
1054 envp_elems = get_envp_count((char **)user_envp);
1055 cnew_envp = (envp_elems ? (envp_elems + 1) : (envp_elems + 2));
1056 new_envp = kzalloc(cnew_envp * sizeof(char **), GFP_KERNEL);
1058 status = snprintf(sz_proc_id, MAXPROCIDLEN, PROC_ENVPROCID,
1061 dev_dbg(bridge, "%s: Proc ID string overflow\n",
1066 prepend_envp(new_envp, (char **)user_envp,
1067 envp_elems, cnew_envp, sz_proc_id);
1068 /* Get the DCD Handle */
1069 status = mgr_get_dcd_handle(p_proc_object->mgr_obj,
1070 (u32 *) &hdcd_handle);
1072 /* Before proceeding with new load,
1073 * check if a previously registered COFF
1075 * If yes, unregister nodes in previously
1076 * registered COFF. If any error occurred,
1077 * set previously registered COFF to NULL. */
1078 if (p_proc_object->last_coff != NULL) {
1080 dcd_auto_unregister(hdcd_handle,
1083 /* Regardless of auto unregister status,
1084 * free previously allocated
1086 kfree(p_proc_object->last_coff);
1087 p_proc_object->last_coff = NULL;
1090 /* On success, do cod_open_base() */
1091 status = cod_open_base(cod_mgr, (char *)user_args[0],
1098 /* Auto-register data base */
1099 /* Get the DCD Handle */
1100 status = mgr_get_dcd_handle(p_proc_object->mgr_obj,
1101 (u32 *) &hdcd_handle);
1103 /* Auto register nodes in specified COFF
1104 * file. If registration did not fail,
1105 * (status = 0 or -EACCES)
1106 * save the name of the COFF file for
1107 * de-registration in the future. */
1109 dcd_auto_register(hdcd_handle,
1110 (char *)user_args[0]);
1111 if (status == -EACCES)
1117 /* Allocate memory for pszLastCoff */
1118 p_proc_object->last_coff =
1119 kzalloc((strlen(user_args[0]) +
1121 /* If memory allocated, save COFF file name */
1122 if (p_proc_object->last_coff) {
1123 strncpy(p_proc_object->last_coff,
1124 (char *)user_args[0],
1125 (strlen((char *)user_args[0]) +
1131 /* Update shared memory address and size */
1133 /* Create the message manager. This must be done
1134 * before calling the IOOnLoaded function. */
1135 dev_get_msg_mgr(p_proc_object->dev_obj, &hmsg_mgr);
1137 status = msg_create(&hmsg_mgr, p_proc_object->dev_obj,
1138 (msg_onexit) node_on_exit);
1139 dev_set_msg_mgr(p_proc_object->dev_obj, hmsg_mgr);
1143 /* Set the Device object's message manager */
1144 status = dev_get_io_mgr(p_proc_object->dev_obj, &hio_mgr);
1146 status = (*p_proc_object->intf_fxns->io_on_loaded)
1152 /* Now, attempt to load an exec: */
1154 /* Boost the OPP level to Maximum level supported by baseport */
1155 #if defined(CONFIG_TIDSPBRIDGE_DVFS) && !defined(CONFIG_CPU_FREQ)
1156 if (pdata->cpu_set_freq)
1157 (*pdata->cpu_set_freq) (pdata->mpu_speed[VDD1_OPP5]);
1159 status = cod_load_base(cod_mgr, argc_index, (char **)user_args,
1161 p_proc_object->dev_obj, NULL);
1163 if (status == -EBADF) {
1164 dev_dbg(bridge, "%s: Failure to Load the EXE\n",
1167 if (status == -ESPIPE) {
1168 pr_err("%s: Couldn't parse the file\n",
1172 /* Requesting the lowest opp supported */
1173 #if defined(CONFIG_TIDSPBRIDGE_DVFS) && !defined(CONFIG_CPU_FREQ)
1174 if (pdata->cpu_set_freq)
1175 (*pdata->cpu_set_freq) (pdata->mpu_speed[VDD1_OPP1]);
1180 /* Update the Processor status to loaded */
1181 status = (*p_proc_object->intf_fxns->brd_set_state)
1182 (p_proc_object->bridge_context, BRD_LOADED);
1184 p_proc_object->proc_state = PROC_LOADED;
1185 if (p_proc_object->ntfy_obj)
1186 proc_notify_clients(p_proc_object,
1187 DSP_PROCESSORSTATECHANGE);
1191 status = proc_get_processor_id(hprocessor, &proc_id);
1192 if (proc_id == DSP_UNIT) {
1193 /* Use all available DSP address space after EXTMEM
1196 status = cod_get_sym_value(cod_mgr, EXTEND,
1199 /* Reset DMM structs and add an initial free chunk */
1202 dev_get_dmm_mgr(p_proc_object->dev_obj,
1205 /* Set dw_ext_end to DMM START u8
1208 (dw_ext_end + 1) * DSPWORDSIZE;
1209 /* DMM memory is from EXT_END */
1210 status = dmm_create_tables(dmm_mgr,
1219 /* Restore the original argv[0] */
1221 user_args[0] = pargv0;
1223 if (!((*p_proc_object->intf_fxns->brd_status)
1224 (p_proc_object->bridge_context, &brd_state))) {
1225 pr_info("%s: Processor Loaded %s\n", __func__, pargv0);
1226 kfree(drv_datap->base_img);
1227 drv_datap->base_img = kstrdup(pargv0, GFP_KERNEL);
1228 if (!drv_datap->base_img)
1235 pr_err("%s: Processor failed to load\n", __func__);
1236 proc_stop(p_proc_object);
1238 #ifdef OPT_LOAD_TIME_INSTRUMENTATION
1239 do_gettimeofday(&tv2);
1240 if (tv2.tv_usec < tv1.tv_usec) {
1241 tv2.tv_usec += 1000000;
1244 dev_dbg(bridge, "%s: time to load %d sec and %d usec\n", __func__,
1245 tv2.tv_sec - tv1.tv_sec, tv2.tv_usec - tv1.tv_usec);
1251 * ======== proc_map ========
1253 * Maps a MPU buffer to DSP address space.
1255 int proc_map(void *hprocessor, void *pmpu_addr, u32 ul_size,
1256 void *req_addr, void **pp_map_addr, u32 ul_map_attr,
1257 struct process_context *pr_ctxt)
1261 struct dmm_object *dmm_mgr;
1264 struct proc_object *p_proc_object = (struct proc_object *)hprocessor;
1265 struct dmm_map_object *map_obj;
1268 #ifdef CONFIG_TIDSPBRIDGE_CACHE_LINE_CHECK
1269 if ((ul_map_attr & BUFMODE_MASK) != RBUF) {
1270 if (!IS_ALIGNED((u32)pmpu_addr, DSP_CACHE_LINE) ||
1271 !IS_ALIGNED(ul_size, DSP_CACHE_LINE)) {
1272 pr_err("%s: not aligned: 0x%x (%d)\n", __func__,
1273 (u32)pmpu_addr, ul_size);
1279 /* Calculate the page-aligned PA, VA and size */
1280 va_align = PG_ALIGN_LOW((u32) req_addr, PG_SIZE4K);
1281 pa_align = PG_ALIGN_LOW((u32) pmpu_addr, PG_SIZE4K);
1282 size_align = PG_ALIGN_HIGH(ul_size + (u32) pmpu_addr - pa_align,
1285 if (!p_proc_object) {
1289 /* Critical section */
1290 mutex_lock(&proc_lock);
1291 dmm_get_handle(p_proc_object, &dmm_mgr);
1293 status = dmm_map_memory(dmm_mgr, va_align, size_align);
1297 /* Add mapping to the page tables. */
1300 /* Mapped address = MSB of VA | LSB of PA */
1301 tmp_addr = (va_align | ((u32) pmpu_addr & (PG_SIZE4K - 1)));
1302 /* mapped memory resource tracking */
1303 map_obj = add_mapping_info(pr_ctxt, pa_align, tmp_addr,
1308 status = (*p_proc_object->intf_fxns->brd_mem_map)
1309 (p_proc_object->bridge_context, pa_align, va_align,
1310 size_align, ul_map_attr, map_obj->pages);
1313 /* Mapped address = MSB of VA | LSB of PA */
1314 *pp_map_addr = (void *) tmp_addr;
1316 remove_mapping_information(pr_ctxt, tmp_addr, size_align);
1317 dmm_un_map_memory(dmm_mgr, va_align, &size_align);
1319 mutex_unlock(&proc_lock);
1325 dev_dbg(bridge, "%s: hprocessor %p, pmpu_addr %p, ul_size %x, "
1326 "req_addr %p, ul_map_attr %x, pp_map_addr %p, va_align %x, "
1327 "pa_align %x, size_align %x status 0x%x\n", __func__,
1328 hprocessor, pmpu_addr, ul_size, req_addr, ul_map_attr,
1329 pp_map_addr, va_align, pa_align, size_align, status);
1335 * ======== proc_register_notify ========
1337 * Register to be notified of specific processor events.
1339 int proc_register_notify(void *hprocessor, u32 event_mask,
1340 u32 notify_type, struct dsp_notification
1344 struct proc_object *p_proc_object = (struct proc_object *)hprocessor;
1345 struct deh_mgr *hdeh_mgr;
1347 /* Check processor handle */
1348 if (!p_proc_object) {
1352 /* Check if event mask is a valid processor related event */
1353 if (event_mask & ~(DSP_PROCESSORSTATECHANGE | DSP_PROCESSORATTACH |
1354 DSP_PROCESSORDETACH | DSP_PROCESSORRESTART |
1355 DSP_MMUFAULT | DSP_SYSERROR | DSP_PWRERROR |
1359 /* Check if notify type is valid */
1360 if (notify_type != DSP_SIGNALEVENT)
1364 /* If event mask is not DSP_SYSERROR, DSP_MMUFAULT,
1365 * or DSP_PWRERROR then register event immediately. */
1367 ~(DSP_SYSERROR | DSP_MMUFAULT | DSP_PWRERROR |
1369 status = ntfy_register(p_proc_object->ntfy_obj,
1370 hnotification, event_mask,
1372 /* Special case alert, special case alert!
1373 * If we're trying to *deregister* (i.e. event_mask
1374 * is 0), a DSP_SYSERROR or DSP_MMUFAULT notification,
1375 * we have to deregister with the DEH manager.
1376 * There's no way to know, based on event_mask which
1377 * manager the notification event was registered with,
1378 * so if we're trying to deregister and ntfy_register
1379 * failed, we'll give the deh manager a shot.
1381 if ((event_mask == 0) && status) {
1383 dev_get_deh_mgr(p_proc_object->dev_obj,
1386 bridge_deh_register_notify(hdeh_mgr,
1392 status = dev_get_deh_mgr(p_proc_object->dev_obj,
1395 bridge_deh_register_notify(hdeh_mgr,
1407 * ======== proc_reserve_memory ========
1409 * Reserve a virtually contiguous region of DSP address space.
1411 int proc_reserve_memory(void *hprocessor, u32 ul_size,
1413 struct process_context *pr_ctxt)
1415 struct dmm_object *dmm_mgr;
1417 struct proc_object *p_proc_object = (struct proc_object *)hprocessor;
1418 struct dmm_rsv_object *rsv_obj;
1420 if (!p_proc_object) {
1425 status = dmm_get_handle(p_proc_object, &dmm_mgr);
1431 status = dmm_reserve_memory(dmm_mgr, ul_size, (u32 *) pp_rsv_addr);
1436 * A successful reserve should be followed by insertion of rsv_obj
1437 * into dmm_rsv_list, so that reserved memory resource tracking
1440 rsv_obj = kmalloc(sizeof(struct dmm_rsv_object), GFP_KERNEL);
1442 rsv_obj->dsp_reserved_addr = (u32) *pp_rsv_addr;
1443 spin_lock(&pr_ctxt->dmm_rsv_lock);
1444 list_add(&rsv_obj->link, &pr_ctxt->dmm_rsv_list);
1445 spin_unlock(&pr_ctxt->dmm_rsv_lock);
1449 dev_dbg(bridge, "%s: hprocessor: 0x%p ul_size: 0x%x pp_rsv_addr: 0x%p "
1450 "status 0x%x\n", __func__, hprocessor,
1451 ul_size, pp_rsv_addr, status);
1456 * ======== proc_start ========
1458 * Start a processor running.
1460 int proc_start(void *hprocessor)
1463 struct proc_object *p_proc_object = (struct proc_object *)hprocessor;
1464 struct cod_manager *cod_mgr; /* Code manager handle */
1465 u32 dw_dsp_addr; /* Loaded code's entry point. */
1468 if (!p_proc_object) {
1472 /* Call the bridge_brd_start */
1473 if (p_proc_object->proc_state != PROC_LOADED) {
1477 status = dev_get_cod_mgr(p_proc_object->dev_obj, &cod_mgr);
1483 status = cod_get_entry(cod_mgr, &dw_dsp_addr);
1487 status = (*p_proc_object->intf_fxns->brd_start)
1488 (p_proc_object->bridge_context, dw_dsp_addr);
1492 /* Call dev_create2 */
1493 status = dev_create2(p_proc_object->dev_obj);
1495 p_proc_object->proc_state = PROC_RUNNING;
1496 /* Deep sleep switces off the peripheral clocks.
1497 * we just put the DSP CPU in idle in the idle loop.
1498 * so there is no need to send a command to DSP */
1500 if (p_proc_object->ntfy_obj) {
1501 proc_notify_clients(p_proc_object,
1502 DSP_PROCESSORSTATECHANGE);
1505 /* Failed to Create Node Manager and DISP Object
1506 * Stop the Processor from running. Put it in STOPPED State */
1507 (void)(*p_proc_object->intf_fxns->
1508 brd_stop) (p_proc_object->bridge_context);
1509 p_proc_object->proc_state = PROC_STOPPED;
1513 if (!((*p_proc_object->intf_fxns->brd_status)
1514 (p_proc_object->bridge_context, &brd_state))) {
1515 pr_info("%s: dsp in running state\n", __func__);
1518 pr_err("%s: Failed to start the dsp\n", __func__);
1519 proc_stop(p_proc_object);
1527 * ======== proc_stop ========
1529 * Stop a processor running.
1531 int proc_stop(void *hprocessor)
1534 struct proc_object *p_proc_object = (struct proc_object *)hprocessor;
1535 struct msg_mgr *hmsg_mgr;
1536 struct node_mgr *hnode_mgr;
1538 u32 node_tab_size = 1;
1540 u32 nodes_allocated = 0;
1542 if (!p_proc_object) {
1546 /* check if there are any running nodes */
1547 status = dev_get_node_manager(p_proc_object->dev_obj, &hnode_mgr);
1548 if (!status && hnode_mgr) {
1549 status = node_enum_nodes(hnode_mgr, &hnode, node_tab_size,
1550 &num_nodes, &nodes_allocated);
1551 if ((status == -EINVAL) || (nodes_allocated > 0)) {
1552 pr_err("%s: Can't stop device, active nodes = %d\n",
1553 __func__, nodes_allocated);
1557 /* Call the bridge_brd_stop */
1558 /* It is OK to stop a device that does n't have nodes OR not started */
1560 (*p_proc_object->intf_fxns->
1561 brd_stop) (p_proc_object->bridge_context);
1563 dev_dbg(bridge, "%s: processor in standby mode\n", __func__);
1564 p_proc_object->proc_state = PROC_STOPPED;
1565 /* Destroy the Node Manager, msg_ctrl Manager */
1566 if (!(dev_destroy2(p_proc_object->dev_obj))) {
1567 /* Destroy the msg_ctrl by calling msg_delete */
1568 dev_get_msg_mgr(p_proc_object->dev_obj, &hmsg_mgr);
1570 msg_delete(hmsg_mgr);
1571 dev_set_msg_mgr(p_proc_object->dev_obj, NULL);
1575 pr_err("%s: Failed to stop the processor\n", __func__);
1583 * ======== proc_un_map ========
1585 * Removes a MPU buffer mapping from the DSP address space.
1587 int proc_un_map(void *hprocessor, void *map_addr,
1588 struct process_context *pr_ctxt)
1591 struct proc_object *p_proc_object = (struct proc_object *)hprocessor;
1592 struct dmm_object *dmm_mgr;
1596 va_align = PG_ALIGN_LOW((u32) map_addr, PG_SIZE4K);
1597 if (!p_proc_object) {
1602 status = dmm_get_handle(hprocessor, &dmm_mgr);
1608 /* Critical section */
1609 mutex_lock(&proc_lock);
1611 * Update DMM structures. Get the size to unmap.
1612 * This function returns error if the VA is not mapped
1614 status = dmm_un_map_memory(dmm_mgr, (u32) va_align, &size_align);
1615 /* Remove mapping from the page tables. */
1617 status = (*p_proc_object->intf_fxns->brd_mem_un_map)
1618 (p_proc_object->bridge_context, va_align, size_align);
1625 * A successful unmap should be followed by removal of map_obj
1626 * from dmm_map_list, so that mapped memory resource tracking
1629 remove_mapping_information(pr_ctxt, (u32) map_addr, size_align);
1632 mutex_unlock(&proc_lock);
1635 dev_dbg(bridge, "%s: hprocessor: 0x%p map_addr: 0x%p status: 0x%x\n",
1636 __func__, hprocessor, map_addr, status);
1641 * ======== proc_un_reserve_memory ========
1643 * Frees a previously reserved region of DSP address space.
1645 int proc_un_reserve_memory(void *hprocessor, void *prsv_addr,
1646 struct process_context *pr_ctxt)
1648 struct dmm_object *dmm_mgr;
1650 struct proc_object *p_proc_object = (struct proc_object *)hprocessor;
1651 struct dmm_rsv_object *rsv_obj;
1653 if (!p_proc_object) {
1658 status = dmm_get_handle(p_proc_object, &dmm_mgr);
1664 status = dmm_un_reserve_memory(dmm_mgr, (u32) prsv_addr);
1669 * A successful unreserve should be followed by removal of rsv_obj
1670 * from dmm_rsv_list, so that reserved memory resource tracking
1673 spin_lock(&pr_ctxt->dmm_rsv_lock);
1674 list_for_each_entry(rsv_obj, &pr_ctxt->dmm_rsv_list, link) {
1675 if (rsv_obj->dsp_reserved_addr == (u32) prsv_addr) {
1676 list_del(&rsv_obj->link);
1681 spin_unlock(&pr_ctxt->dmm_rsv_lock);
1684 dev_dbg(bridge, "%s: hprocessor: 0x%p prsv_addr: 0x%p status: 0x%x\n",
1685 __func__, hprocessor, prsv_addr, status);
1690 * ======== = proc_monitor ======== ==
1692 * Place the Processor in Monitor State. This is an internal
1693 * function and a requirement before Processor is loaded.
1694 * This does a bridge_brd_stop, dev_destroy2 and bridge_brd_monitor.
1695 * In dev_destroy2 we delete the node manager.
1697 * p_proc_object: Pointer to Processor Object
1699 * 0: Processor placed in monitor mode.
1700 * !0: Failed to place processor in monitor mode.
1702 * Valid Processor Handle
1704 * Success: ProcObject state is PROC_IDLE
1706 static int proc_monitor(struct proc_object *proc_obj)
1708 int status = -EPERM;
1709 struct msg_mgr *hmsg_mgr;
1711 /* This is needed only when Device is loaded when it is
1712 * already 'ACTIVE' */
1713 /* Destroy the Node Manager, msg_ctrl Manager */
1714 if (!dev_destroy2(proc_obj->dev_obj)) {
1715 /* Destroy the msg_ctrl by calling msg_delete */
1716 dev_get_msg_mgr(proc_obj->dev_obj, &hmsg_mgr);
1718 msg_delete(hmsg_mgr);
1719 dev_set_msg_mgr(proc_obj->dev_obj, NULL);
1722 /* Place the Board in the Monitor State */
1723 if (!((*proc_obj->intf_fxns->brd_monitor)
1724 (proc_obj->bridge_context))) {
1732 * ======== get_envp_count ========
1734 * Return the number of elements in the envp array, including the
1735 * terminating NULL element.
1737 static s32 get_envp_count(char **envp)
1744 ret += 1; /* Include the terminating NULL in the count. */
1751 * ======== prepend_envp ========
1753 * Prepend an environment variable=value pair to the new envp array, and
1754 * copy in the existing var=value pairs in the old envp array.
1756 static char **prepend_envp(char **new_envp, char **envp, s32 envp_elems,
1757 s32 cnew_envp, char *sz_var)
1759 char **pp_envp = new_envp;
1761 /* Prepend new environ var=value string */
1762 *new_envp++ = sz_var;
1764 /* Copy user's environment into our own. */
1765 while (envp_elems--)
1766 *new_envp++ = *envp++;
1768 /* Ensure NULL terminates the new environment strings array. */
1769 if (envp_elems == 0)
1776 * ======== proc_notify_clients ========
1778 * Notify the processor the events.
1780 int proc_notify_clients(void *proc, u32 events)
1783 struct proc_object *p_proc_object = (struct proc_object *)proc;
1785 if (!p_proc_object) {
1790 ntfy_notify(p_proc_object->ntfy_obj, events);
1796 * ======== proc_notify_all_clients ========
1798 * Notify the processor the events. This includes notifying all clients
1799 * attached to a particulat DSP.
1801 int proc_notify_all_clients(void *proc, u32 events)
1804 struct proc_object *p_proc_object = (struct proc_object *)proc;
1806 if (!p_proc_object) {
1811 dev_notify_clients(p_proc_object->dev_obj, events);
1818 * ======== proc_get_processor_id ========
1820 * Retrieves the processor ID.
1822 int proc_get_processor_id(void *proc, u32 *proc_id)
1825 struct proc_object *p_proc_object = (struct proc_object *)proc;
1828 *proc_id = p_proc_object->processor_id;