summaryrefslogtreecommitdiff
path: root/drivers/staging/tidspbridge/rmgr/proc.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/tidspbridge/rmgr/proc.c')
-rw-r--r--drivers/staging/tidspbridge/rmgr/proc.c1833
1 files changed, 0 insertions, 1833 deletions
diff --git a/drivers/staging/tidspbridge/rmgr/proc.c b/drivers/staging/tidspbridge/rmgr/proc.c
deleted file mode 100644
index cd5235a4f77c..000000000000
--- a/drivers/staging/tidspbridge/rmgr/proc.c
+++ /dev/null
@@ -1,1833 +0,0 @@
-/*
- * proc.c
- *
- * DSP-BIOS Bridge driver support functions for TI OMAP processors.
- *
- * Processor interface at the driver level.
- *
- * Copyright (C) 2005-2006 Texas Instruments, Inc.
- *
- * This package is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
- */
-
-#include <linux/types.h>
-/* ------------------------------------ Host OS */
-#include <linux/dma-mapping.h>
-#include <linux/scatterlist.h>
-#include <dspbridge/host_os.h>
-
-/* ----------------------------------- DSP/BIOS Bridge */
-#include <dspbridge/dbdefs.h>
-
-/* ----------------------------------- OS Adaptation Layer */
-#include <dspbridge/ntfy.h>
-#include <dspbridge/sync.h>
-/* ----------------------------------- Bridge Driver */
-#include <dspbridge/dspdefs.h>
-#include <dspbridge/dspdeh.h>
-/* ----------------------------------- Platform Manager */
-#include <dspbridge/cod.h>
-#include <dspbridge/dev.h>
-#include <dspbridge/procpriv.h>
-#include <dspbridge/dmm.h>
-
-/* ----------------------------------- Resource Manager */
-#include <dspbridge/mgr.h>
-#include <dspbridge/node.h>
-#include <dspbridge/nldr.h>
-#include <dspbridge/rmm.h>
-
-/* ----------------------------------- Others */
-#include <dspbridge/dbdcd.h>
-#include <dspbridge/msg.h>
-#include <dspbridge/dspioctl.h>
-#include <dspbridge/drv.h>
-
-/* ----------------------------------- This */
-#include <dspbridge/proc.h>
-#include <dspbridge/pwr.h>
-
-#include <dspbridge/resourcecleanup.h>
-/* ----------------------------------- Defines, Data Structures, Typedefs */
-#define MAXCMDLINELEN 255
-#define PROC_ENVPROCID "PROC_ID=%d"
-#define MAXPROCIDLEN (8 + 5)
-#define PROC_DFLT_TIMEOUT 10000 /* Time out in milliseconds */
-#define PWR_TIMEOUT 500 /* Sleep/wake timout in msec */
-#define EXTEND "_EXT_END" /* Extmem end addr in DSP binary */
-
-#define DSP_CACHE_LINE 128
-
-#define BUFMODE_MASK (3 << 14)
-
-/* Buffer modes from DSP perspective */
-#define RBUF 0x4000 /* Input buffer */
-#define WBUF 0x8000 /* Output Buffer */
-
-extern struct device *bridge;
-
-/* ----------------------------------- Globals */
-
-/* The proc_object structure. */
-struct proc_object {
- struct list_head link; /* Link to next proc_object */
- struct dev_object *dev_obj; /* Device this PROC represents */
- u32 process; /* Process owning this Processor */
- struct mgr_object *mgr_obj; /* Manager Object Handle */
- u32 attach_count; /* Processor attach count */
- u32 processor_id; /* Processor number */
- u32 timeout; /* Time out count */
- enum dsp_procstate proc_state; /* Processor state */
- u32 unit; /* DDSP unit number */
- bool is_already_attached; /*
- * True if the Device below has
- * GPP Client attached
- */
- struct ntfy_object *ntfy_obj; /* Manages notifications */
- /* Bridge Context Handle */
- struct bridge_dev_context *bridge_context;
- /* Function interface to Bridge driver */
- struct bridge_drv_interface *intf_fxns;
- char *last_coff;
- struct list_head proc_list;
-};
-
-DEFINE_MUTEX(proc_lock); /* For critical sections */
-
-/* ----------------------------------- Function Prototypes */
-static int proc_monitor(struct proc_object *proc_obj);
-static s32 get_envp_count(char **envp);
-static char **prepend_envp(char **new_envp, char **envp, s32 envp_elems,
- s32 cnew_envp, char *sz_var);
-
-/* remember mapping information */
-static struct dmm_map_object *add_mapping_info(struct process_context *pr_ctxt,
- u32 mpu_addr, u32 dsp_addr, u32 size)
-{
- struct dmm_map_object *map_obj;
-
- u32 num_usr_pgs = size / PG_SIZE4K;
-
- pr_debug("%s: adding map info: mpu_addr 0x%x virt 0x%x size 0x%x\n",
- __func__, mpu_addr,
- dsp_addr, size);
-
- map_obj = kzalloc(sizeof(struct dmm_map_object), GFP_KERNEL);
- if (!map_obj)
- return NULL;
-
- INIT_LIST_HEAD(&map_obj->link);
-
- map_obj->pages = kcalloc(num_usr_pgs, sizeof(struct page *),
- GFP_KERNEL);
- if (!map_obj->pages) {
- kfree(map_obj);
- return NULL;
- }
-
- map_obj->mpu_addr = mpu_addr;
- map_obj->dsp_addr = dsp_addr;
- map_obj->size = size;
- map_obj->num_usr_pgs = num_usr_pgs;
-
- spin_lock(&pr_ctxt->dmm_map_lock);
- list_add(&map_obj->link, &pr_ctxt->dmm_map_list);
- spin_unlock(&pr_ctxt->dmm_map_lock);
-
- return map_obj;
-}
-
-static int match_exact_map_obj(struct dmm_map_object *map_obj,
- u32 dsp_addr, u32 size)
-{
- if (map_obj->dsp_addr == dsp_addr && map_obj->size != size)
- pr_err("%s: addr match (0x%x), size don't (0x%x != 0x%x)\n",
- __func__, dsp_addr, map_obj->size, size);
-
- return map_obj->dsp_addr == dsp_addr &&
- map_obj->size == size;
-}
-
-static void remove_mapping_information(struct process_context *pr_ctxt,
- u32 dsp_addr, u32 size)
-{
- struct dmm_map_object *map_obj;
-
- pr_debug("%s: looking for virt 0x%x size 0x%x\n", __func__,
- dsp_addr, size);
-
- spin_lock(&pr_ctxt->dmm_map_lock);
- list_for_each_entry(map_obj, &pr_ctxt->dmm_map_list, link) {
- pr_debug("%s: candidate: mpu_addr 0x%x virt 0x%x size 0x%x\n",
- __func__,
- map_obj->mpu_addr,
- map_obj->dsp_addr,
- map_obj->size);
-
- if (match_exact_map_obj(map_obj, dsp_addr, size)) {
- pr_debug("%s: match, deleting map info\n", __func__);
- list_del(&map_obj->link);
- kfree(map_obj->dma_info.sg);
- kfree(map_obj->pages);
- kfree(map_obj);
- goto out;
- }
- pr_debug("%s: candidate didn't match\n", __func__);
- }
-
- pr_err("%s: failed to find given map info\n", __func__);
-out:
- spin_unlock(&pr_ctxt->dmm_map_lock);
-}
-
-static int match_containing_map_obj(struct dmm_map_object *map_obj,
- u32 mpu_addr, u32 size)
-{
- u32 map_obj_end = map_obj->mpu_addr + map_obj->size;
-
- return mpu_addr >= map_obj->mpu_addr &&
- mpu_addr + size <= map_obj_end;
-}
-
-static struct dmm_map_object *find_containing_mapping(
- struct process_context *pr_ctxt,
- u32 mpu_addr, u32 size)
-{
- struct dmm_map_object *map_obj;
- pr_debug("%s: looking for mpu_addr 0x%x size 0x%x\n", __func__,
- mpu_addr, size);
-
- spin_lock(&pr_ctxt->dmm_map_lock);
- list_for_each_entry(map_obj, &pr_ctxt->dmm_map_list, link) {
- pr_debug("%s: candidate: mpu_addr 0x%x virt 0x%x size 0x%x\n",
- __func__,
- map_obj->mpu_addr,
- map_obj->dsp_addr,
- map_obj->size);
- if (match_containing_map_obj(map_obj, mpu_addr, size)) {
- pr_debug("%s: match!\n", __func__);
- goto out;
- }
-
- pr_debug("%s: no match!\n", __func__);
- }
-
- map_obj = NULL;
-out:
- spin_unlock(&pr_ctxt->dmm_map_lock);
- return map_obj;
-}
-
-static int find_first_page_in_cache(struct dmm_map_object *map_obj,
- unsigned long mpu_addr)
-{
- u32 mapped_base_page = map_obj->mpu_addr >> PAGE_SHIFT;
- u32 requested_base_page = mpu_addr >> PAGE_SHIFT;
- int pg_index = requested_base_page - mapped_base_page;
-
- if (pg_index < 0 || pg_index >= map_obj->num_usr_pgs) {
- pr_err("%s: failed (got %d)\n", __func__, pg_index);
- return -1;
- }
-
- pr_debug("%s: first page is %d\n", __func__, pg_index);
- return pg_index;
-}
-
-static inline struct page *get_mapping_page(struct dmm_map_object *map_obj,
- int pg_i)
-{
- pr_debug("%s: looking for pg_i %d, num_usr_pgs: %d\n", __func__,
- pg_i, map_obj->num_usr_pgs);
-
- if (pg_i < 0 || pg_i >= map_obj->num_usr_pgs) {
- pr_err("%s: requested pg_i %d is out of mapped range\n",
- __func__, pg_i);
- return NULL;
- }
-
- return map_obj->pages[pg_i];
-}
-
-/*
- * ======== proc_attach ========
- * Purpose:
- * Prepare for communication with a particular DSP processor, and return
- * a handle to the processor object.
- */
-int
-proc_attach(u32 processor_id,
- const struct dsp_processorattrin *attr_in,
- void **ph_processor, struct process_context *pr_ctxt)
-{
- int status = 0;
- struct dev_object *hdev_obj;
- struct proc_object *p_proc_object = NULL;
- struct mgr_object *hmgr_obj = NULL;
- struct drv_object *hdrv_obj = NULL;
- struct drv_data *drv_datap = dev_get_drvdata(bridge);
- u8 dev_type;
-
- if (pr_ctxt->processor) {
- *ph_processor = pr_ctxt->processor;
- return status;
- }
-
- /* Get the Driver and Manager Object Handles */
- if (!drv_datap || !drv_datap->drv_object || !drv_datap->mgr_object) {
- status = -ENODATA;
- pr_err("%s: Failed to get object handles\n", __func__);
- } else {
- hdrv_obj = drv_datap->drv_object;
- hmgr_obj = drv_datap->mgr_object;
- }
-
- if (!status) {
- /* Get the Device Object */
- status = drv_get_dev_object(processor_id, hdrv_obj, &hdev_obj);
- }
- if (!status)
- status = dev_get_dev_type(hdev_obj, &dev_type);
-
- if (status)
- goto func_end;
-
- /* If we made it this far, create the Processor object: */
- p_proc_object = kzalloc(sizeof(struct proc_object), GFP_KERNEL);
- /* Fill out the Processor Object: */
- if (p_proc_object == NULL) {
- status = -ENOMEM;
- goto func_end;
- }
- p_proc_object->dev_obj = hdev_obj;
- p_proc_object->mgr_obj = hmgr_obj;
- p_proc_object->processor_id = dev_type;
- /* Store TGID instead of process handle */
- p_proc_object->process = current->tgid;
-
- INIT_LIST_HEAD(&p_proc_object->proc_list);
-
- if (attr_in)
- p_proc_object->timeout = attr_in->timeout;
- else
- p_proc_object->timeout = PROC_DFLT_TIMEOUT;
-
- status = dev_get_intf_fxns(hdev_obj, &p_proc_object->intf_fxns);
- if (!status) {
- status = dev_get_bridge_context(hdev_obj,
- &p_proc_object->bridge_context);
- if (status)
- kfree(p_proc_object);
- } else
- kfree(p_proc_object);
-
- if (status)
- goto func_end;
-
- /* Create the Notification Object */
- /* This is created with no event mask, no notify mask
- * and no valid handle to the notification. They all get
- * filled up when proc_register_notify is called */
- p_proc_object->ntfy_obj = kmalloc(sizeof(struct ntfy_object),
- GFP_KERNEL);
- if (p_proc_object->ntfy_obj)
- ntfy_init(p_proc_object->ntfy_obj);
- else
- status = -ENOMEM;
-
- if (!status) {
- /* Insert the Processor Object into the DEV List.
- * Return handle to this Processor Object:
- * Find out if the Device is already attached to a
- * Processor. If so, return AlreadyAttached status */
- status = dev_insert_proc_object(p_proc_object->dev_obj,
- (u32) p_proc_object,
- &p_proc_object->
- is_already_attached);
- if (!status) {
- if (p_proc_object->is_already_attached)
- status = 0;
- } else {
- if (p_proc_object->ntfy_obj) {
- ntfy_delete(p_proc_object->ntfy_obj);
- kfree(p_proc_object->ntfy_obj);
- }
-
- kfree(p_proc_object);
- }
- if (!status) {
- *ph_processor = (void *)p_proc_object;
- pr_ctxt->processor = *ph_processor;
- (void)proc_notify_clients(p_proc_object,
- DSP_PROCESSORATTACH);
- }
- } else {
- /* Don't leak memory if status is failed */
- kfree(p_proc_object);
- }
-func_end:
- return status;
-}
-
-static int get_exec_file(struct cfg_devnode *dev_node_obj,
- struct dev_object *hdev_obj,
- u32 size, char *exec_file)
-{
- u8 dev_type;
- struct drv_data *drv_datap = dev_get_drvdata(bridge);
-
- dev_get_dev_type(hdev_obj, (u8 *) &dev_type);
-
- if (!exec_file)
- return -EFAULT;
-
- if (dev_type == DSP_UNIT) {
- if (!drv_datap || !drv_datap->base_img)
- return -EFAULT;
-
- if (strlen(drv_datap->base_img) >= size)
- return -EINVAL;
-
- strcpy(exec_file, drv_datap->base_img);
- } else {
- return -ENOENT;
- }
-
- return 0;
-}
-
-/*
- * ======== proc_auto_start ======== =
- * Purpose:
- * A Particular device gets loaded with the default image
- * if the AutoStart flag is set.
- * Parameters:
- * hdev_obj: Handle to the Device
- * Returns:
- * 0: On Successful Loading
- * -EPERM General Failure
- * Requires:
- * hdev_obj != NULL
- * Ensures:
- */
-int proc_auto_start(struct cfg_devnode *dev_node_obj,
- struct dev_object *hdev_obj)
-{
- int status = -EPERM;
- struct proc_object *p_proc_object;
- char sz_exec_file[MAXCMDLINELEN];
- char *argv[2];
- struct mgr_object *hmgr_obj = NULL;
- struct drv_data *drv_datap = dev_get_drvdata(bridge);
- u8 dev_type;
-
- /* Create a Dummy PROC Object */
- if (!drv_datap || !drv_datap->mgr_object) {
- status = -ENODATA;
- pr_err("%s: Failed to retrieve the object handle\n", __func__);
- goto func_end;
- } else {
- hmgr_obj = drv_datap->mgr_object;
- }
-
- p_proc_object = kzalloc(sizeof(struct proc_object), GFP_KERNEL);
- if (p_proc_object == NULL) {
- status = -ENOMEM;
- goto func_end;
- }
- p_proc_object->dev_obj = hdev_obj;
- p_proc_object->mgr_obj = hmgr_obj;
- status = dev_get_intf_fxns(hdev_obj, &p_proc_object->intf_fxns);
- if (!status)
- status = dev_get_bridge_context(hdev_obj,
- &p_proc_object->bridge_context);
- if (status)
- goto func_cont;
-
- /* Stop the Device, put it into standby mode */
- status = proc_stop(p_proc_object);
-
- if (status)
- goto func_cont;
-
- /* Get the default executable for this board... */
- dev_get_dev_type(hdev_obj, (u8 *) &dev_type);
- p_proc_object->processor_id = dev_type;
- status = get_exec_file(dev_node_obj, hdev_obj, sizeof(sz_exec_file),
- sz_exec_file);
- if (!status) {
- argv[0] = sz_exec_file;
- argv[1] = NULL;
- /* ...and try to load it: */
- status = proc_load(p_proc_object, 1, (const char **)argv, NULL);
- if (!status)
- status = proc_start(p_proc_object);
- }
- kfree(p_proc_object->last_coff);
- p_proc_object->last_coff = NULL;
-func_cont:
- kfree(p_proc_object);
-func_end:
- return status;
-}
-
-/*
- * ======== proc_ctrl ========
- * Purpose:
- * Pass control information to the GPP device driver managing the
- * DSP processor.
- *
- * This will be an OEM-only function, and not part of the DSP/BIOS Bridge
- * application developer's API.
- * Call the bridge_dev_ctrl fxn with the Argument. This is a Synchronous
- * Operation. arg can be null.
- */
-int proc_ctrl(void *hprocessor, u32 dw_cmd, struct dsp_cbdata *arg)
-{
- int status = 0;
- struct proc_object *p_proc_object = hprocessor;
- u32 timeout = 0;
-
- if (p_proc_object) {
- /* intercept PWR deep sleep command */
- if (dw_cmd == BRDIOCTL_DEEPSLEEP) {
- timeout = arg->cb_data;
- status = pwr_sleep_dsp(PWR_DEEPSLEEP, timeout);
- }
- /* intercept PWR emergency sleep command */
- else if (dw_cmd == BRDIOCTL_EMERGENCYSLEEP) {
- timeout = arg->cb_data;
- status = pwr_sleep_dsp(PWR_EMERGENCYDEEPSLEEP, timeout);
- } else if (dw_cmd == PWR_DEEPSLEEP) {
- /* timeout = arg->cb_data; */
- status = pwr_sleep_dsp(PWR_DEEPSLEEP, timeout);
- }
- /* intercept PWR wake commands */
- else if (dw_cmd == BRDIOCTL_WAKEUP) {
- timeout = arg->cb_data;
- status = pwr_wake_dsp(timeout);
- } else if (dw_cmd == PWR_WAKEUP) {
- /* timeout = arg->cb_data; */
- status = pwr_wake_dsp(timeout);
- } else
- if (!((*p_proc_object->intf_fxns->dev_cntrl)
- (p_proc_object->bridge_context, dw_cmd,
- arg))) {
- status = 0;
- } else {
- status = -EPERM;
- }
- } else {
- status = -EFAULT;
- }
-
- return status;
-}
-
-/*
- * ======== proc_detach ========
- * Purpose:
- * Destroys the Processor Object. Removes the notification from the Dev
- * List.
- */
-int proc_detach(struct process_context *pr_ctxt)
-{
- int status = 0;
- struct proc_object *p_proc_object = NULL;
-
- p_proc_object = (struct proc_object *)pr_ctxt->processor;
-
- if (p_proc_object) {
- /* Notify the Client */
- ntfy_notify(p_proc_object->ntfy_obj, DSP_PROCESSORDETACH);
- /* Remove the notification memory */
- if (p_proc_object->ntfy_obj) {
- ntfy_delete(p_proc_object->ntfy_obj);
- kfree(p_proc_object->ntfy_obj);
- }
-
- kfree(p_proc_object->last_coff);
- p_proc_object->last_coff = NULL;
- /* Remove the Proc from the DEV List */
- (void)dev_remove_proc_object(p_proc_object->dev_obj,
- (u32) p_proc_object);
- /* Free the Processor Object */
- kfree(p_proc_object);
- pr_ctxt->processor = NULL;
- } else {
- status = -EFAULT;
- }
-
- return status;
-}
-
-/*
- * ======== proc_enum_nodes ========
- * Purpose:
- * Enumerate and get configuration information about nodes allocated
- * on a DSP processor.
- */
-int proc_enum_nodes(void *hprocessor, void **node_tab,
- u32 node_tab_size, u32 *pu_num_nodes,
- u32 *pu_allocated)
-{
- int status = -EPERM;
- struct proc_object *p_proc_object = (struct proc_object *)hprocessor;
- struct node_mgr *hnode_mgr = NULL;
-
- if (p_proc_object) {
- if (!(dev_get_node_manager(p_proc_object->dev_obj,
- &hnode_mgr))) {
- if (hnode_mgr) {
- status = node_enum_nodes(hnode_mgr, node_tab,
- node_tab_size,
- pu_num_nodes,
- pu_allocated);
- }
- }
- } else {
- status = -EFAULT;
- }
-
- return status;
-}
-
-/* Cache operation against kernel address instead of users */
-static int build_dma_sg(struct dmm_map_object *map_obj, unsigned long start,
- ssize_t len, int pg_i)
-{
- struct page *page;
- unsigned long offset;
- ssize_t rest;
- int ret = 0, i = 0;
- struct scatterlist *sg = map_obj->dma_info.sg;
-
- while (len) {
- page = get_mapping_page(map_obj, pg_i);
- if (!page) {
- pr_err("%s: no page for %08lx\n", __func__, start);
- ret = -EINVAL;
- goto out;
- } else if (IS_ERR(page)) {
- pr_err("%s: err page for %08lx(%lu)\n", __func__, start,
- PTR_ERR(page));
- ret = PTR_ERR(page);
- goto out;
- }
-
- offset = start & ~PAGE_MASK;
- rest = min_t(ssize_t, PAGE_SIZE - offset, len);
-
- sg_set_page(&sg[i], page, rest, offset);
-
- len -= rest;
- start += rest;
- pg_i++, i++;
- }
-
- if (i != map_obj->dma_info.num_pages) {
- pr_err("%s: bad number of sg iterations\n", __func__);
- ret = -EFAULT;
- goto out;
- }
-
-out:
- return ret;
-}
-
-static int memory_regain_ownership(struct dmm_map_object *map_obj,
- unsigned long start, ssize_t len, enum dma_data_direction dir)
-{
- int ret = 0;
- unsigned long first_data_page = start >> PAGE_SHIFT;
- unsigned long last_data_page = ((u32)(start + len - 1) >> PAGE_SHIFT);
- /* calculating the number of pages this area spans */
- unsigned long num_pages = last_data_page - first_data_page + 1;
- struct bridge_dma_map_info *dma_info = &map_obj->dma_info;
-
- if (!dma_info->sg)
- goto out;
-
- if (dma_info->dir != dir || dma_info->num_pages != num_pages) {
- pr_err("%s: dma info doesn't match given params\n", __func__);
- return -EINVAL;
- }
-
- dma_unmap_sg(bridge, dma_info->sg, num_pages, dma_info->dir);
-
- pr_debug("%s: dma_map_sg unmapped\n", __func__);
-
- kfree(dma_info->sg);
-
- map_obj->dma_info.sg = NULL;
-
-out:
- return ret;
-}
-
-/* Cache operation against kernel address instead of users */
-static int memory_give_ownership(struct dmm_map_object *map_obj,
- unsigned long start, ssize_t len, enum dma_data_direction dir)
-{
- int pg_i, ret, sg_num;
- struct scatterlist *sg;
- unsigned long first_data_page = start >> PAGE_SHIFT;
- unsigned long last_data_page = ((u32)(start + len - 1) >> PAGE_SHIFT);
- /* calculating the number of pages this area spans */
- unsigned long num_pages = last_data_page - first_data_page + 1;
-
- pg_i = find_first_page_in_cache(map_obj, start);
- if (pg_i < 0) {
- pr_err("%s: failed to find first page in cache\n", __func__);
- ret = -EINVAL;
- goto out;
- }
-
- sg = kcalloc(num_pages, sizeof(*sg), GFP_KERNEL);
- if (!sg) {
- ret = -ENOMEM;
- goto out;
- }
-
- sg_init_table(sg, num_pages);
-
- /* cleanup a previous sg allocation */
- /* this may happen if application doesn't signal for e/o DMA */
- kfree(map_obj->dma_info.sg);
-
- map_obj->dma_info.sg = sg;
- map_obj->dma_info.dir = dir;
- map_obj->dma_info.num_pages = num_pages;
-
- ret = build_dma_sg(map_obj, start, len, pg_i);
- if (ret)
- goto kfree_sg;
-
- sg_num = dma_map_sg(bridge, sg, num_pages, dir);
- if (sg_num < 1) {
- pr_err("%s: dma_map_sg failed: %d\n", __func__, sg_num);
- ret = -EFAULT;
- goto kfree_sg;
- }
-
- pr_debug("%s: dma_map_sg mapped %d elements\n", __func__, sg_num);
- map_obj->dma_info.sg_num = sg_num;
-
- return 0;
-
-kfree_sg:
- kfree(sg);
- map_obj->dma_info.sg = NULL;
-out:
- return ret;
-}
-
-int proc_begin_dma(void *hprocessor, void *pmpu_addr, u32 ul_size,
- enum dma_data_direction dir)
-{
- /* Keep STATUS here for future additions to this function */
- int status = 0;
- struct process_context *pr_ctxt = (struct process_context *) hprocessor;
- struct dmm_map_object *map_obj;
-
- if (!pr_ctxt) {
- status = -EFAULT;
- goto err_out;
- }
-
- pr_debug("%s: addr 0x%x, size 0x%x, type %d\n", __func__,
- (u32)pmpu_addr,
- ul_size, dir);
-
- mutex_lock(&proc_lock);
-
- /* find requested memory are in cached mapping information */
- map_obj = find_containing_mapping(pr_ctxt, (u32) pmpu_addr, ul_size);
- if (!map_obj) {
- pr_err("%s: find_containing_mapping failed\n", __func__);
- status = -EFAULT;
- goto no_map;
- }
-
- if (memory_give_ownership(map_obj, (u32) pmpu_addr, ul_size, dir)) {
- pr_err("%s: InValid address parameters %p %x\n",
- __func__, pmpu_addr, ul_size);
- status = -EFAULT;
- }
-
-no_map:
- mutex_unlock(&proc_lock);
-err_out:
-
- return status;
-}
-
-int proc_end_dma(void *hprocessor, void *pmpu_addr, u32 ul_size,
- enum dma_data_direction dir)
-{
- /* Keep STATUS here for future additions to this function */
- int status = 0;
- struct process_context *pr_ctxt = (struct process_context *) hprocessor;
- struct dmm_map_object *map_obj;
-
- if (!pr_ctxt) {
- status = -EFAULT;
- goto err_out;
- }
-
- pr_debug("%s: addr 0x%x, size 0x%x, type %d\n", __func__,
- (u32)pmpu_addr,
- ul_size, dir);
-
- mutex_lock(&proc_lock);
-
- /* find requested memory are in cached mapping information */
- map_obj = find_containing_mapping(pr_ctxt, (u32) pmpu_addr, ul_size);
- if (!map_obj) {
- pr_err("%s: find_containing_mapping failed\n", __func__);
- status = -EFAULT;
- goto no_map;
- }
-
- if (memory_regain_ownership(map_obj, (u32) pmpu_addr, ul_size, dir)) {
- pr_err("%s: InValid address parameters %p %x\n",
- __func__, pmpu_addr, ul_size);
- status = -EFAULT;
- }
-
-no_map:
- mutex_unlock(&proc_lock);
-err_out:
- return status;
-}
-
-/*
- * ======== proc_flush_memory ========
- * Purpose:
- * Flush cache
- */
-int proc_flush_memory(void *hprocessor, void *pmpu_addr,
- u32 ul_size, u32 ul_flags)
-{
- enum dma_data_direction dir = DMA_BIDIRECTIONAL;
-
- return proc_begin_dma(hprocessor, pmpu_addr, ul_size, dir);
-}
-
-/*
- * ======== proc_invalidate_memory ========
- * Purpose:
- * Invalidates the memory specified
- */
-int proc_invalidate_memory(void *hprocessor, void *pmpu_addr, u32 size)
-{
- enum dma_data_direction dir = DMA_FROM_DEVICE;
-
- return proc_begin_dma(hprocessor, pmpu_addr, size, dir);
-}
-
-/*
- * ======== proc_get_resource_info ========
- * Purpose:
- * Enumerate the resources currently available on a processor.
- */
-int proc_get_resource_info(void *hprocessor, u32 resource_type,
- struct dsp_resourceinfo *resource_info,
- u32 resource_info_size)
-{
- int status = -EPERM;
- struct proc_object *p_proc_object = (struct proc_object *)hprocessor;
- struct node_mgr *hnode_mgr = NULL;
- struct nldr_object *nldr_obj = NULL;
- struct rmm_target_obj *rmm = NULL;
- struct io_mgr *hio_mgr = NULL; /* IO manager handle */
-
- if (!p_proc_object) {
- status = -EFAULT;
- goto func_end;
- }
- switch (resource_type) {
- case DSP_RESOURCE_DYNDARAM:
- case DSP_RESOURCE_DYNSARAM:
- case DSP_RESOURCE_DYNEXTERNAL:
- case DSP_RESOURCE_DYNSRAM:
- status = dev_get_node_manager(p_proc_object->dev_obj,
- &hnode_mgr);
- if (!hnode_mgr) {
- status = -EFAULT;
- goto func_end;
- }
-
- status = node_get_nldr_obj(hnode_mgr, &nldr_obj);
- if (!status) {
- status = nldr_get_rmm_manager(nldr_obj, &rmm);
- if (rmm) {
- if (!rmm_stat(rmm,
- (enum dsp_memtype)resource_type,
- (struct dsp_memstat *)
- &(resource_info->result.
- mem_stat)))
- status = -EINVAL;
- } else {
- status = -EFAULT;
- }
- }
- break;
- case DSP_RESOURCE_PROCLOAD:
- status = dev_get_io_mgr(p_proc_object->dev_obj, &hio_mgr);
- if (hio_mgr)
- status =
- p_proc_object->intf_fxns->
- io_get_proc_load(hio_mgr,
- (struct dsp_procloadstat *)
- &(resource_info->result.
- proc_load_stat));
- else
- status = -EFAULT;
- break;
- default:
- status = -EPERM;
- break;
- }
-func_end:
- return status;
-}
-
-/*
- * ======== proc_get_dev_object ========
- * Purpose:
- * Return the Dev Object handle for a given Processor.
- *
- */
-int proc_get_dev_object(void *hprocessor,
- struct dev_object **device_obj)
-{
- int status = -EPERM;
- struct proc_object *p_proc_object = (struct proc_object *)hprocessor;
-
- if (p_proc_object) {
- *device_obj = p_proc_object->dev_obj;
- status = 0;
- } else {
- *device_obj = NULL;
- status = -EFAULT;
- }
-
- return status;
-}
-
-/*
- * ======== proc_get_state ========
- * Purpose:
- * Report the state of the specified DSP processor.
- */
-int proc_get_state(void *hprocessor,
- struct dsp_processorstate *proc_state_obj,
- u32 state_info_size)
-{
- int status = 0;
- struct proc_object *p_proc_object = (struct proc_object *)hprocessor;
- int brd_status;
-
- if (p_proc_object) {
- /* First, retrieve BRD state information */
- status = (*p_proc_object->intf_fxns->brd_status)
- (p_proc_object->bridge_context, &brd_status);
- if (!status) {
- switch (brd_status) {
- case BRD_STOPPED:
- proc_state_obj->proc_state = PROC_STOPPED;
- break;
- case BRD_SLEEP_TRANSITION:
- case BRD_DSP_HIBERNATION:
- /* Fall through */
- case BRD_RUNNING:
- proc_state_obj->proc_state = PROC_RUNNING;
- break;
- case BRD_LOADED:
- proc_state_obj->proc_state = PROC_LOADED;
- break;
- case BRD_ERROR:
- proc_state_obj->proc_state = PROC_ERROR;
- break;
- default:
- proc_state_obj->proc_state = 0xFF;
- status = -EPERM;
- break;
- }
- }
- } else {
- status = -EFAULT;
- }
- dev_dbg(bridge, "%s, results: status: 0x%x proc_state_obj: 0x%x\n",
- __func__, status, proc_state_obj->proc_state);
- return status;
-}
-
-/*
- * ======== proc_get_trace ========
- * Purpose:
- * Retrieve the current contents of the trace buffer, located on the
- * Processor. Predefined symbols for the trace buffer must have been
- * configured into the DSP executable.
- * Details:
- * We support using the symbols SYS_PUTCBEG and SYS_PUTCEND to define a
- * trace buffer, only. Treat it as an undocumented feature.
- * This call is destructive, meaning the processor is placed in the monitor
- * state as a result of this function.
- */
-int proc_get_trace(void *hprocessor, u8 *pbuf, u32 max_size)
-{
- int status;
- status = -ENOSYS;
- return status;
-}
-
-/*
- * ======== proc_load ========
- * Purpose:
- * Reset a processor and load a new base program image.
- * This will be an OEM-only function, and not part of the DSP/BIOS Bridge
- * application developer's API.
- */
-int proc_load(void *hprocessor, const s32 argc_index,
- const char **user_args, const char **user_envp)
-{
- int status = 0;
- struct proc_object *p_proc_object = (struct proc_object *)hprocessor;
- struct io_mgr *hio_mgr; /* IO manager handle */
- struct msg_mgr *hmsg_mgr;
- struct cod_manager *cod_mgr; /* Code manager handle */
- char *pargv0; /* temp argv[0] ptr */
- char **new_envp; /* Updated envp[] array. */
- char sz_proc_id[MAXPROCIDLEN]; /* Size of "PROC_ID=<n>" */
- s32 envp_elems; /* Num elements in envp[]. */
- s32 cnew_envp; /* " " in new_envp[] */
- s32 nproc_id = 0; /* Anticipate MP version. */
- struct dcd_manager *hdcd_handle;
- struct dmm_object *dmm_mgr;
- u32 dw_ext_end;
- u32 proc_id;
- int brd_state;
- struct drv_data *drv_datap = dev_get_drvdata(bridge);
-
-#ifdef OPT_LOAD_TIME_INSTRUMENTATION
- struct timeval tv1;
- struct timeval tv2;
-#endif
-
-#if defined(CONFIG_TIDSPBRIDGE_DVFS) && !defined(CONFIG_CPU_FREQ)
- struct dspbridge_platform_data *pdata =
- omap_dspbridge_dev->dev.platform_data;
-#endif
-
-#ifdef OPT_LOAD_TIME_INSTRUMENTATION
- do_gettimeofday(&tv1);
-#endif
- if (!p_proc_object) {
- status = -EFAULT;
- goto func_end;
- }
- dev_get_cod_mgr(p_proc_object->dev_obj, &cod_mgr);
- if (!cod_mgr) {
- status = -EPERM;
- goto func_end;
- }
- status = proc_stop(hprocessor);
- if (status)
- goto func_end;
-
- /* Place the board in the monitor state. */
- status = proc_monitor(hprocessor);
- if (status)
- goto func_end;
-
- /* Save ptr to original argv[0]. */
- pargv0 = (char *)user_args[0];
- /*Prepend "PROC_ID=<nproc_id>"to envp array for target. */
- envp_elems = get_envp_count((char **)user_envp);
- cnew_envp = (envp_elems ? (envp_elems + 1) : (envp_elems + 2));
- new_envp = kzalloc(cnew_envp * sizeof(char **), GFP_KERNEL);
- if (new_envp) {
- status = snprintf(sz_proc_id, MAXPROCIDLEN, PROC_ENVPROCID,
- nproc_id);
- if (status == -1) {
- dev_dbg(bridge, "%s: Proc ID string overflow\n",
- __func__);
- status = -EPERM;
- } else {
- new_envp =
- prepend_envp(new_envp, (char **)user_envp,
- envp_elems, cnew_envp, sz_proc_id);
- /* Get the DCD Handle */
- status = mgr_get_dcd_handle(p_proc_object->mgr_obj,
- (u32 *) &hdcd_handle);
- if (!status) {
- /* Before proceeding with new load,
- * check if a previously registered COFF
- * exists.
- * If yes, unregister nodes in previously
- * registered COFF. If any error occurred,
- * set previously registered COFF to NULL. */
- if (p_proc_object->last_coff != NULL) {
- status =
- dcd_auto_unregister(hdcd_handle,
- p_proc_object->
- last_coff);
- /* Regardless of auto unregister status,
- * free previously allocated
- * memory. */
- kfree(p_proc_object->last_coff);
- p_proc_object->last_coff = NULL;
- }
- }
- /* On success, do cod_open_base() */
- status = cod_open_base(cod_mgr, (char *)user_args[0],
- COD_SYMB);
- }
- } else {
- status = -ENOMEM;
- }
- if (!status) {
- /* Auto-register data base */
- /* Get the DCD Handle */
- status = mgr_get_dcd_handle(p_proc_object->mgr_obj,
- (u32 *) &hdcd_handle);
- if (!status) {
- /* Auto register nodes in specified COFF
- * file. If registration did not fail,
- * (status = 0 or -EACCES)
- * save the name of the COFF file for
- * de-registration in the future. */
- status =
- dcd_auto_register(hdcd_handle,
- (char *)user_args[0]);
- if (status == -EACCES)
- status = 0;
-
- if (status) {
- status = -EPERM;
- } else {
- /* Allocate memory for pszLastCoff */
- p_proc_object->last_coff =
- kzalloc((strlen(user_args[0]) +
- 1), GFP_KERNEL);
- /* If memory allocated, save COFF file name */
- if (p_proc_object->last_coff) {
- strncpy(p_proc_object->last_coff,
- (char *)user_args[0],
- (strlen((char *)user_args[0]) +
- 1));
- }
- }
- }
- }
- /* Update shared memory address and size */
- if (!status) {
- /* Create the message manager. This must be done
- * before calling the IOOnLoaded function. */
- dev_get_msg_mgr(p_proc_object->dev_obj, &hmsg_mgr);
- if (!hmsg_mgr) {
- status = msg_create(&hmsg_mgr, p_proc_object->dev_obj,
- (msg_onexit) node_on_exit);
- dev_set_msg_mgr(p_proc_object->dev_obj, hmsg_mgr);
- }
- }
- if (!status) {
- /* Set the Device object's message manager */
- status = dev_get_io_mgr(p_proc_object->dev_obj, &hio_mgr);
- if (hio_mgr)
- status = (*p_proc_object->intf_fxns->io_on_loaded)
- (hio_mgr);
- else
- status = -EFAULT;
- }
- if (!status) {
- /* Now, attempt to load an exec: */
-
- /* Boost the OPP level to Maximum level supported by baseport */
-#if defined(CONFIG_TIDSPBRIDGE_DVFS) && !defined(CONFIG_CPU_FREQ)
- if (pdata->cpu_set_freq)
- (*pdata->cpu_set_freq) (pdata->mpu_speed[VDD1_OPP5]);
-#endif
- status = cod_load_base(cod_mgr, argc_index, (char **)user_args,
- dev_brd_write_fxn,
- p_proc_object->dev_obj, NULL);
- if (status) {
- if (status == -EBADF) {
- dev_dbg(bridge, "%s: Failure to Load the EXE\n",
- __func__);
- }
- if (status == -ESPIPE) {
- pr_err("%s: Couldn't parse the file\n",
- __func__);
- }
- }
- /* Requesting the lowest opp supported */
-#if defined(CONFIG_TIDSPBRIDGE_DVFS) && !defined(CONFIG_CPU_FREQ)
- if (pdata->cpu_set_freq)
- (*pdata->cpu_set_freq) (pdata->mpu_speed[VDD1_OPP1]);
-#endif
-
- }
- if (!status) {
- /* Update the Processor status to loaded */
- status = (*p_proc_object->intf_fxns->brd_set_state)
- (p_proc_object->bridge_context, BRD_LOADED);
- if (!status) {
- p_proc_object->proc_state = PROC_LOADED;
- if (p_proc_object->ntfy_obj)
- proc_notify_clients(p_proc_object,
- DSP_PROCESSORSTATECHANGE);
- }
- }
- if (!status) {
- status = proc_get_processor_id(hprocessor, &proc_id);
- if (proc_id == DSP_UNIT) {
- /* Use all available DSP address space after EXTMEM
- * for DMM */
- if (!status)
- status = cod_get_sym_value(cod_mgr, EXTEND,
- &dw_ext_end);
-
- /* Reset DMM structs and add an initial free chunk */
- if (!status) {
- status =
- dev_get_dmm_mgr(p_proc_object->dev_obj,
- &dmm_mgr);
- if (dmm_mgr) {
- /* Set dw_ext_end to DMM START u8
- * address */
- dw_ext_end =
- (dw_ext_end + 1) * DSPWORDSIZE;
- /* DMM memory is from EXT_END */
- status = dmm_create_tables(dmm_mgr,
- dw_ext_end,
- DMMPOOLSIZE);
- } else {
- status = -EFAULT;
- }
- }
- }
- }
- /* Restore the original argv[0] */
- kfree(new_envp);
- user_args[0] = pargv0;
- if (!status) {
- if (!((*p_proc_object->intf_fxns->brd_status)
- (p_proc_object->bridge_context, &brd_state))) {
- pr_info("%s: Processor Loaded %s\n", __func__, pargv0);
- kfree(drv_datap->base_img);
- drv_datap->base_img = kstrdup(pargv0, GFP_KERNEL);
- if (!drv_datap->base_img)
- status = -ENOMEM;
- }
- }
-
-func_end:
- if (status) {
- pr_err("%s: Processor failed to load\n", __func__);
- proc_stop(p_proc_object);
- }
-#ifdef OPT_LOAD_TIME_INSTRUMENTATION
- do_gettimeofday(&tv2);
- if (tv2.tv_usec < tv1.tv_usec) {
- tv2.tv_usec += 1000000;
- tv2.tv_sec--;
- }
- dev_dbg(bridge, "%s: time to load %d sec and %d usec\n", __func__,
- tv2.tv_sec - tv1.tv_sec, tv2.tv_usec - tv1.tv_usec);
-#endif
- return status;
-}
-
-/*
- * ======== proc_map ========
- * Purpose:
- * Maps a MPU buffer to DSP address space.
- */
-int proc_map(void *hprocessor, void *pmpu_addr, u32 ul_size,
- void *req_addr, void **pp_map_addr, u32 ul_map_attr,
- struct process_context *pr_ctxt)
-{
- u32 va_align;
- u32 pa_align;
- struct dmm_object *dmm_mgr;
- u32 size_align;
- int status = 0;
- struct proc_object *p_proc_object = (struct proc_object *)hprocessor;
- struct dmm_map_object *map_obj;
- u32 tmp_addr = 0;
-
-#ifdef CONFIG_TIDSPBRIDGE_CACHE_LINE_CHECK
- if ((ul_map_attr & BUFMODE_MASK) != RBUF) {
- if (!IS_ALIGNED((u32)pmpu_addr, DSP_CACHE_LINE) ||
- !IS_ALIGNED(ul_size, DSP_CACHE_LINE)) {
- pr_err("%s: not aligned: 0x%x (%d)\n", __func__,
- (u32)pmpu_addr, ul_size);
- return -EFAULT;
- }
- }
-#endif
-
- /* Calculate the page-aligned PA, VA and size */
- va_align = PG_ALIGN_LOW((u32) req_addr, PG_SIZE4K);
- pa_align = PG_ALIGN_LOW((u32) pmpu_addr, PG_SIZE4K);
- size_align = PG_ALIGN_HIGH(ul_size + (u32) pmpu_addr - pa_align,
- PG_SIZE4K);
-
- if (!p_proc_object) {
- status = -EFAULT;
- goto func_end;
- }
- /* Critical section */
- mutex_lock(&proc_lock);
- dmm_get_handle(p_proc_object, &dmm_mgr);
- if (dmm_mgr)
- status = dmm_map_memory(dmm_mgr, va_align, size_align);
- else
- status = -EFAULT;
-
- /* Add mapping to the page tables. */
- if (!status) {
-
- /* Mapped address = MSB of VA | LSB of PA */
- tmp_addr = (va_align | ((u32) pmpu_addr & (PG_SIZE4K - 1)));
- /* mapped memory resource tracking */
- map_obj = add_mapping_info(pr_ctxt, pa_align, tmp_addr,
- size_align);
- if (!map_obj)
- status = -ENOMEM;
- else
- status = (*p_proc_object->intf_fxns->brd_mem_map)
- (p_proc_object->bridge_context, pa_align, va_align,
- size_align, ul_map_attr, map_obj->pages);
- }
- if (!status) {
- /* Mapped address = MSB of VA | LSB of PA */
- *pp_map_addr = (void *) tmp_addr;
- } else {
- remove_mapping_information(pr_ctxt, tmp_addr, size_align);
- dmm_un_map_memory(dmm_mgr, va_align, &size_align);
- }
- mutex_unlock(&proc_lock);
-
- if (status)
- goto func_end;
-
-func_end:
- dev_dbg(bridge, "%s: hprocessor %p, pmpu_addr %p, ul_size %x, "
- "req_addr %p, ul_map_attr %x, pp_map_addr %p, va_align %x, "
- "pa_align %x, size_align %x status 0x%x\n", __func__,
- hprocessor, pmpu_addr, ul_size, req_addr, ul_map_attr,
- pp_map_addr, va_align, pa_align, size_align, status);
-
- return status;
-}
-
-/*
- * ======== proc_register_notify ========
- * Purpose:
- * Register to be notified of specific processor events.
- */
-int proc_register_notify(void *hprocessor, u32 event_mask,
- u32 notify_type, struct dsp_notification
- *hnotification)
-{
- int status = 0;
- struct proc_object *p_proc_object = (struct proc_object *)hprocessor;
- struct deh_mgr *hdeh_mgr;
-
- /* Check processor handle */
- if (!p_proc_object) {
- status = -EFAULT;
- goto func_end;
- }
- /* Check if event mask is a valid processor related event */
- if (event_mask & ~(DSP_PROCESSORSTATECHANGE | DSP_PROCESSORATTACH |
- DSP_PROCESSORDETACH | DSP_PROCESSORRESTART |
- DSP_MMUFAULT | DSP_SYSERROR | DSP_PWRERROR |
- DSP_WDTOVERFLOW))
- status = -EINVAL;
-
- /* Check if notify type is valid */
- if (notify_type != DSP_SIGNALEVENT)
- status = -EINVAL;
-
- if (!status) {
- /* If event mask is not DSP_SYSERROR, DSP_MMUFAULT,
- * or DSP_PWRERROR then register event immediately. */
- if (event_mask &
- ~(DSP_SYSERROR | DSP_MMUFAULT | DSP_PWRERROR |
- DSP_WDTOVERFLOW)) {
- status = ntfy_register(p_proc_object->ntfy_obj,
- hnotification, event_mask,
- notify_type);
- /* Special case alert, special case alert!
- * If we're trying to *deregister* (i.e. event_mask
- * is 0), a DSP_SYSERROR or DSP_MMUFAULT notification,
- * we have to deregister with the DEH manager.
- * There's no way to know, based on event_mask which
- * manager the notification event was registered with,
- * so if we're trying to deregister and ntfy_register
- * failed, we'll give the deh manager a shot.
- */
- if ((event_mask == 0) && status) {
- status =
- dev_get_deh_mgr(p_proc_object->dev_obj,
- &hdeh_mgr);
- status =
- bridge_deh_register_notify(hdeh_mgr,
- event_mask,
- notify_type,
- hnotification);
- }
- } else {
- status = dev_get_deh_mgr(p_proc_object->dev_obj,
- &hdeh_mgr);
- status =
- bridge_deh_register_notify(hdeh_mgr,
- event_mask,
- notify_type,
- hnotification);
-
- }
- }
-func_end:
- return status;
-}
-
-/*
- * ======== proc_reserve_memory ========
- * Purpose:
- * Reserve a virtually contiguous region of DSP address space.
- */
-int proc_reserve_memory(void *hprocessor, u32 ul_size,
- void **pp_rsv_addr,
- struct process_context *pr_ctxt)
-{
- struct dmm_object *dmm_mgr;
- int status = 0;
- struct proc_object *p_proc_object = (struct proc_object *)hprocessor;
- struct dmm_rsv_object *rsv_obj;
-
- if (!p_proc_object) {
- status = -EFAULT;
- goto func_end;
- }
-
- status = dmm_get_handle(p_proc_object, &dmm_mgr);
- if (!dmm_mgr) {
- status = -EFAULT;
- goto func_end;
- }
-
- status = dmm_reserve_memory(dmm_mgr, ul_size, (u32 *) pp_rsv_addr);
- if (status != 0)
- goto func_end;
-
- /*
- * A successful reserve should be followed by insertion of rsv_obj
- * into dmm_rsv_list, so that reserved memory resource tracking
- * remains uptodate
- */
- rsv_obj = kmalloc(sizeof(struct dmm_rsv_object), GFP_KERNEL);
- if (rsv_obj) {
- rsv_obj->dsp_reserved_addr = (u32) *pp_rsv_addr;
- spin_lock(&pr_ctxt->dmm_rsv_lock);
- list_add(&rsv_obj->link, &pr_ctxt->dmm_rsv_list);
- spin_unlock(&pr_ctxt->dmm_rsv_lock);
- }
-
-func_end:
- dev_dbg(bridge, "%s: hprocessor: 0x%p ul_size: 0x%x pp_rsv_addr: 0x%p "
- "status 0x%x\n", __func__, hprocessor,
- ul_size, pp_rsv_addr, status);
- return status;
-}
-
-/*
- * ======== proc_start ========
- * Purpose:
- * Start a processor running.
- */
-int proc_start(void *hprocessor)
-{
- int status = 0;
- struct proc_object *p_proc_object = (struct proc_object *)hprocessor;
- struct cod_manager *cod_mgr; /* Code manager handle */
- u32 dw_dsp_addr; /* Loaded code's entry point. */
- int brd_state;
-
- if (!p_proc_object) {
- status = -EFAULT;
- goto func_end;
- }
- /* Call the bridge_brd_start */
- if (p_proc_object->proc_state != PROC_LOADED) {
- status = -EBADR;
- goto func_end;
- }
- status = dev_get_cod_mgr(p_proc_object->dev_obj, &cod_mgr);
- if (!cod_mgr) {
- status = -EFAULT;
- goto func_cont;
- }
-
- status = cod_get_entry(cod_mgr, &dw_dsp_addr);
- if (status)
- goto func_cont;
-
- status = (*p_proc_object->intf_fxns->brd_start)
- (p_proc_object->bridge_context, dw_dsp_addr);
- if (status)
- goto func_cont;
-
- /* Call dev_create2 */
- status = dev_create2(p_proc_object->dev_obj);
- if (!status) {
- p_proc_object->proc_state = PROC_RUNNING;
- /* Deep sleep switces off the peripheral clocks.
- * we just put the DSP CPU in idle in the idle loop.
- * so there is no need to send a command to DSP */
-
- if (p_proc_object->ntfy_obj) {
- proc_notify_clients(p_proc_object,
- DSP_PROCESSORSTATECHANGE);
- }
- } else {
- /* Failed to Create Node Manager and DISP Object
- * Stop the Processor from running. Put it in STOPPED State */
- (void)(*p_proc_object->intf_fxns->
- brd_stop) (p_proc_object->bridge_context);
- p_proc_object->proc_state = PROC_STOPPED;
- }
-func_cont:
- if (!status) {
- if (!((*p_proc_object->intf_fxns->brd_status)
- (p_proc_object->bridge_context, &brd_state))) {
- pr_info("%s: dsp in running state\n", __func__);
- }
- } else {
- pr_err("%s: Failed to start the dsp\n", __func__);
- proc_stop(p_proc_object);
- }
-
-func_end:
- return status;
-}
-
-/*
- * ======== proc_stop ========
- * Purpose:
- * Stop a processor running.
- */
-int proc_stop(void *hprocessor)
-{
- int status = 0;
- struct proc_object *p_proc_object = (struct proc_object *)hprocessor;
- struct msg_mgr *hmsg_mgr;
- struct node_mgr *hnode_mgr;
- void *hnode;
- u32 node_tab_size = 1;
- u32 num_nodes = 0;
- u32 nodes_allocated = 0;
-
- if (!p_proc_object) {
- status = -EFAULT;
- goto func_end;
- }
- /* check if there are any running nodes */
- status = dev_get_node_manager(p_proc_object->dev_obj, &hnode_mgr);
- if (!status && hnode_mgr) {
- status = node_enum_nodes(hnode_mgr, &hnode, node_tab_size,
- &num_nodes, &nodes_allocated);
- if ((status == -EINVAL) || (nodes_allocated > 0)) {
- pr_err("%s: Can't stop device, active nodes = %d\n",
- __func__, nodes_allocated);
- return -EBADR;
- }
- }
- /* Call the bridge_brd_stop */
- /* It is OK to stop a device that does n't have nodes OR not started */
- status =
- (*p_proc_object->intf_fxns->
- brd_stop) (p_proc_object->bridge_context);
- if (!status) {
- dev_dbg(bridge, "%s: processor in standby mode\n", __func__);
- p_proc_object->proc_state = PROC_STOPPED;
- /* Destroy the Node Manager, msg_ctrl Manager */
- if (!(dev_destroy2(p_proc_object->dev_obj))) {
- /* Destroy the msg_ctrl by calling msg_delete */
- dev_get_msg_mgr(p_proc_object->dev_obj, &hmsg_mgr);
- if (hmsg_mgr) {
- msg_delete(hmsg_mgr);
- dev_set_msg_mgr(p_proc_object->dev_obj, NULL);
- }
- }
- } else {
- pr_err("%s: Failed to stop the processor\n", __func__);
- }
-func_end:
-
- return status;
-}
-
-/*
- * ======== proc_un_map ========
- * Purpose:
- * Removes a MPU buffer mapping from the DSP address space.
- */
-int proc_un_map(void *hprocessor, void *map_addr,
- struct process_context *pr_ctxt)
-{
- int status = 0;
- struct proc_object *p_proc_object = (struct proc_object *)hprocessor;
- struct dmm_object *dmm_mgr;
- u32 va_align;
- u32 size_align;
-
- va_align = PG_ALIGN_LOW((u32) map_addr, PG_SIZE4K);
- if (!p_proc_object) {
- status = -EFAULT;
- goto func_end;
- }
-
- status = dmm_get_handle(hprocessor, &dmm_mgr);
- if (!dmm_mgr) {
- status = -EFAULT;
- goto func_end;
- }
-
- /* Critical section */
- mutex_lock(&proc_lock);
- /*
- * Update DMM structures. Get the size to unmap.
- * This function returns error if the VA is not mapped
- */
- status = dmm_un_map_memory(dmm_mgr, (u32) va_align, &size_align);
- /* Remove mapping from the page tables. */
- if (!status) {
- status = (*p_proc_object->intf_fxns->brd_mem_un_map)
- (p_proc_object->bridge_context, va_align, size_align);
- }
-
- if (status)
- goto unmap_failed;
-
- /*
- * A successful unmap should be followed by removal of map_obj
- * from dmm_map_list, so that mapped memory resource tracking
- * remains uptodate
- */
- remove_mapping_information(pr_ctxt, (u32) map_addr, size_align);
-
-unmap_failed:
- mutex_unlock(&proc_lock);
-
-func_end:
- dev_dbg(bridge, "%s: hprocessor: 0x%p map_addr: 0x%p status: 0x%x\n",
- __func__, hprocessor, map_addr, status);
- return status;
-}
-
-/*
- * ======== proc_un_reserve_memory ========
- * Purpose:
- * Frees a previously reserved region of DSP address space.
- */
-int proc_un_reserve_memory(void *hprocessor, void *prsv_addr,
- struct process_context *pr_ctxt)
-{
- struct dmm_object *dmm_mgr;
- int status = 0;
- struct proc_object *p_proc_object = (struct proc_object *)hprocessor;
- struct dmm_rsv_object *rsv_obj;
-
- if (!p_proc_object) {
- status = -EFAULT;
- goto func_end;
- }
-
- status = dmm_get_handle(p_proc_object, &dmm_mgr);
- if (!dmm_mgr) {
- status = -EFAULT;
- goto func_end;
- }
-
- status = dmm_un_reserve_memory(dmm_mgr, (u32) prsv_addr);
- if (status != 0)
- goto func_end;
-
- /*
- * A successful unreserve should be followed by removal of rsv_obj
- * from dmm_rsv_list, so that reserved memory resource tracking
- * remains uptodate
- */
- spin_lock(&pr_ctxt->dmm_rsv_lock);
- list_for_each_entry(rsv_obj, &pr_ctxt->dmm_rsv_list, link) {
- if (rsv_obj->dsp_reserved_addr == (u32) prsv_addr) {
- list_del(&rsv_obj->link);
- kfree(rsv_obj);
- break;
- }
- }
- spin_unlock(&pr_ctxt->dmm_rsv_lock);
-
-func_end:
- dev_dbg(bridge, "%s: hprocessor: 0x%p prsv_addr: 0x%p status: 0x%x\n",
- __func__, hprocessor, prsv_addr, status);
- return status;
-}
-
-/*
- * ======== = proc_monitor ======== ==
- * Purpose:
- * Place the Processor in Monitor State. This is an internal
- * function and a requirement before Processor is loaded.
- * This does a bridge_brd_stop, dev_destroy2 and bridge_brd_monitor.
- * In dev_destroy2 we delete the node manager.
- * Parameters:
- * p_proc_object: Pointer to Processor Object
- * Returns:
- * 0: Processor placed in monitor mode.
- * !0: Failed to place processor in monitor mode.
- * Requires:
- * Valid Processor Handle
- * Ensures:
- * Success: ProcObject state is PROC_IDLE
- */
-static int proc_monitor(struct proc_object *proc_obj)
-{
- int status = -EPERM;
- struct msg_mgr *hmsg_mgr;
-
- /* This is needed only when Device is loaded when it is
- * already 'ACTIVE' */
- /* Destroy the Node Manager, msg_ctrl Manager */
- if (!dev_destroy2(proc_obj->dev_obj)) {
- /* Destroy the msg_ctrl by calling msg_delete */
- dev_get_msg_mgr(proc_obj->dev_obj, &hmsg_mgr);
- if (hmsg_mgr) {
- msg_delete(hmsg_mgr);
- dev_set_msg_mgr(proc_obj->dev_obj, NULL);
- }
- }
- /* Place the Board in the Monitor State */
- if (!((*proc_obj->intf_fxns->brd_monitor)
- (proc_obj->bridge_context))) {
- status = 0;
- }
-
- return status;
-}
-
-/*
- * ======== get_envp_count ========
- * Purpose:
- * Return the number of elements in the envp array, including the
- * terminating NULL element.
- */
-static s32 get_envp_count(char **envp)
-{
- s32 ret = 0;
- if (envp) {
- while (*envp++)
- ret++;
-
- ret += 1; /* Include the terminating NULL in the count. */
- }
-
- return ret;
-}
-
-/*
- * ======== prepend_envp ========
- * Purpose:
- * Prepend an environment variable=value pair to the new envp array, and
- * copy in the existing var=value pairs in the old envp array.
- */
-static char **prepend_envp(char **new_envp, char **envp, s32 envp_elems,
- s32 cnew_envp, char *sz_var)
-{
- char **pp_envp = new_envp;
-
- /* Prepend new environ var=value string */
- *new_envp++ = sz_var;
-
- /* Copy user's environment into our own. */
- while (envp_elems--)
- *new_envp++ = *envp++;
-
- /* Ensure NULL terminates the new environment strings array. */
- if (envp_elems == 0)
- *new_envp = NULL;
-
- return pp_envp;
-}
-
-/*
- * ======== proc_notify_clients ========
- * Purpose:
- * Notify the processor the events.
- */
-int proc_notify_clients(void *proc, u32 events)
-{
- int status = 0;
- struct proc_object *p_proc_object = (struct proc_object *)proc;
-
- if (!p_proc_object) {
- status = -EFAULT;
- goto func_end;
- }
-
- ntfy_notify(p_proc_object->ntfy_obj, events);
-func_end:
- return status;
-}
-
-/*
- * ======== proc_notify_all_clients ========
- * Purpose:
- * Notify the processor the events. This includes notifying all clients
- * attached to a particulat DSP.
- */
-int proc_notify_all_clients(void *proc, u32 events)
-{
- int status = 0;
- struct proc_object *p_proc_object = (struct proc_object *)proc;
-
- if (!p_proc_object) {
- status = -EFAULT;
- goto func_end;
- }
-
- dev_notify_clients(p_proc_object->dev_obj, events);
-
-func_end:
- return status;
-}
-
-/*
- * ======== proc_get_processor_id ========
- * Purpose:
- * Retrieves the processor ID.
- */
-int proc_get_processor_id(void *proc, u32 *proc_id)
-{
- int status = 0;
- struct proc_object *p_proc_object = (struct proc_object *)proc;
-
- if (p_proc_object)
- *proc_id = p_proc_object->processor_id;
- else
- status = -EFAULT;
-
- return status;
-}