@@ -389,4 +389,7 @@ extern u32 drv_request_resources(u32 dw_context, u32 *pDevNodeString);
*/
extern u32 drv_release_resources(u32 dw_context, struct drv_object *hdrv_obj);
+#ifdef CONFIG_BRIDGE_RECOVERY
+ void bridge_recover_schedule(void);
+#endif
#endif /* DRV_ */
@@ -52,6 +52,14 @@ config WDT_TIMEOUT
Watchdog timer timeout value, after that time if the watchdog timer
counter is not reset the wdt overflow interrupt will be triggered
+config BRIDGE_RECOVERY
+ bool "DSP Recovery Support"
+ depends on MPU_BRIDGE
+ help
+ In case of DSP fatal error, BRIDGE driver will try to
+ recover itself.
+
+
comment "Bridge Notifications"
depends on MPU_BRIDGE
@@ -381,7 +381,7 @@ u32 wcd_init_complete2(void)
u32 status = DSP_SOK;
struct cfg_devnode *dev_node;
struct dev_object *hdev_obj;
- u32 dev_type;
+ u32 dev_type, tmp;
DBC_REQUIRE(wcd_c_refs > 0);
@@ -396,13 +396,11 @@ u32 wcd_init_complete2(void)
if (DSP_FAILED(dev_get_dev_type(hdev_obj, &dev_type)))
continue;
- if ((dev_type == DSP_UNIT) || (dev_type == IVA_UNIT)) {
- if (DSP_FAILED(proc_auto_start(dev_node, hdev_obj))) {
- status = DSP_EFAIL;
- /* break; */
- }
- }
- } /* End For Loop */
+ if ((dev_type == DSP_UNIT) || (dev_type == IVA_UNIT))
+ if (cfg_get_auto_start(dev_node, &tmp) == DSP_SOK
+ && tmp)
+ proc_auto_start(dev_node, hdev_obj);
+ }
return status;
}
@@ -91,6 +91,15 @@ static s32 shm_size = 0x500000; /* 5 MB */
static u32 phys_mempool_base;
static u32 phys_mempool_size;
static int tc_wordswapon; /* Default value is always false */
+#ifdef CONFIG_BRIDGE_RECOVERY
+#define REC_TIMEOUT 5000 /*recovery timeout in msecs */
+static atomic_t bridge_cref; /* number of bridge open handles */
+static struct workqueue_struct *bridge_rec_queue;
+static struct work_struct bridge_recovery_work;
+static DECLARE_COMPLETION_ONSTACK(bridge_comp);
+static DECLARE_COMPLETION_ONSTACK(bridge_open_comp);
+static bool recover;
+#endif
#ifdef CONFIG_PM
struct omap34_xx_bridge_suspend_data {
@@ -189,6 +198,33 @@ u32 vdd1_dsp_freq[6][4] = {
{0, 430000, 355000, 430000},
};
+#ifdef CONFIG_BRIDGE_RECOVERY
+static void bridge_recover(struct work_struct *work)
+{
+ struct dev_object *dev;
+ struct cfg_devnode *dev_node;
+ if (atomic_read(&bridge_cref)) {
+ INIT_COMPLETION(bridge_comp);
+ while (!wait_for_completion_timeout(&bridge_comp,
+ msecs_to_jiffies(REC_TIMEOUT)))
+ pr_info("%s:%d handle(s) still opened\n",
+ __func__, atomic_read(&bridge_cref));
+ }
+ dev = dev_get_first();
+ dev_get_dev_node(dev, &dev_node);
+ if (!dev_node || DSP_FAILED(proc_auto_start(dev_node, dev)))
+ pr_err("DSP could not be restarted\n");
+ recover = false;
+ complete_all(&bridge_open_comp);
+}
+
+void bridge_recover_schedule(void)
+{
+ INIT_COMPLETION(bridge_open_comp);
+ recover = true;
+ queue_work(bridge_rec_queue, &bridge_recovery_work);
+}
+#endif
#ifdef CONFIG_BRIDGE_DVFS
static int dspbridge_post_scale(struct notifier_block *op, unsigned long level,
void *ptr)
@@ -323,6 +359,12 @@ static int __devinit omap34_xx_bridge_probe(struct platform_device *pdev)
}
}
+#ifdef CONFIG_BRIDGE_RECOVERY
+ bridge_rec_queue = create_workqueue("bridge_rec_queue");
+ INIT_WORK(&bridge_recovery_work, bridge_recover);
+ INIT_COMPLETION(bridge_comp);
+#endif
+
DBC_ASSERT(status == 0);
DBC_ASSERT(DSP_SUCCEEDED(init_status));
@@ -443,6 +485,13 @@ static int bridge_open(struct inode *ip, struct file *filp)
* dload_allocate a new process context and insert it into global
* process context list.
*/
+
+#ifdef CONFIG_BRIDGE_RECOVERY
+ if (recover)
+ if (wait_for_completion_interruptible_timeout(&bridge_open_comp,
+ msecs_to_jiffies(REC_TIMEOUT * 3)) <= 0)
+ return -EBUSY;
+#endif
pr_ctxt = mem_calloc(sizeof(struct process_context), MEM_PAGED);
if (pr_ctxt) {
pr_ctxt->res_state = PROC_RES_ALLOCATED;
@@ -458,6 +507,10 @@ static int bridge_open(struct inode *ip, struct file *filp)
filp->private_data = pr_ctxt;
+#ifdef CONFIG_BRIDGE_RECOVERY
+ if (!status)
+ atomic_inc(&bridge_cref);
+#endif
return status;
}
@@ -484,6 +537,10 @@ static int bridge_release(struct inode *ip, struct file *filp)
filp->private_data = NULL;
err:
+#ifdef CONFIG_BRIDGE_RECOVERY
+ if (!atomic_dec_return(&bridge_cref))
+ complete(&bridge_comp);
+#endif
return status;
}
@@ -496,6 +553,12 @@ static long bridge_ioctl(struct file *filp, unsigned int code,
union Trapped_Args buf_in;
DBC_REQUIRE(filp != NULL);
+#ifdef CONFIG_BRIDGE_RECOVERY
+ if (recover) {
+ status = -EIO;
+ goto err;
+ }
+#endif
#ifdef CONFIG_PM
status = omap34_xxbridge_suspend_lockout(&bridge_suspend_data, filp);
if (status != 0)
@@ -53,6 +53,7 @@
#include <dspbridge/msg.h>
#include <dspbridge/wmdioctl.h>
#include <dspbridge/drv.h>
+#include <dspbridge/reg.h>
/* ----------------------------------- This */
#include <dspbridge/proc.h>
@@ -257,7 +258,6 @@ u32 proc_auto_start(struct cfg_devnode *dev_node_obj,
struct dev_object *hdev_obj)
{
u32 status = DSP_EFAIL;
- u32 dw_auto_start = 0; /* autostart flag */
struct proc_object *pProcObject;
char sz_exec_file[MAXCMDLINELEN];
char *argv[2];
@@ -293,11 +293,6 @@ u32 proc_auto_start(struct cfg_devnode *dev_node_obj,
if (DSP_FAILED(status))
goto func_cont;
- status = cfg_get_auto_start(dev_node_obj, &dw_auto_start);
- if (DSP_FAILED(status) || !dw_auto_start) {
- status = DSP_EFAIL;
- goto func_cont;
- }
/* Get the default executable for this board... */
dev_get_dev_type(hdev_obj, (u32 *) &dev_type);
pProcObject->processor_id = dev_type;
@@ -1024,6 +1019,8 @@ u32 proc_load(void *hprocessor, const s32 argc_index, const char **user_args,
if (DSP_SUCCEEDED((*pProcObject->intf_fxns->pfn_brd_status)
(pProcObject->hwmd_context, &brd_state))) {
pr_info("%s: Processor Loaded %s\n", __func__, pargv0);
+ reg_set_value(DEFEXEC, (u8 *)pargv0,
+ strlen(pargv0) + 1);
DBC_ASSERT(brd_state == BRD_LOADED);
}
}
@@ -287,8 +287,12 @@ void bridge_deh_notify(struct deh_mgr *hdeh_mgr, u32 ulEventMask, u32 dwErrInfo)
}
/* Filter subsequent notifications when an error occurs */
- if (dev_context->dw_brd_state != BRD_ERROR)
+ if (dev_context->dw_brd_state != BRD_ERROR) {
ntfy_notify(deh_mgr_obj->ntfy_obj, ulEventMask);
+#ifdef CONFIG_BRIDGE_RECOVERY
+ bridge_recover_schedule();
+#endif
+ }
/* Set the Board state as ERROR */
dev_context->dw_brd_state = BRD_ERROR;