diff options
Diffstat (limited to 'drivers/remoteproc/remoteproc.c')
-rw-r--r-- | drivers/remoteproc/remoteproc.c | 118 |
1 files changed, 93 insertions, 25 deletions
diff --git a/drivers/remoteproc/remoteproc.c b/drivers/remoteproc/remoteproc.c index 4124011..2e9a6e0 100644 --- a/drivers/remoteproc/remoteproc.c +++ b/drivers/remoteproc/remoteproc.c @@ -55,8 +55,8 @@ static ssize_t rproc_format_trace_buf(char __user *userbuf, size_t count, int i, w_pos; /* Assume write_idx is the penultimate byte in the buffer trace*/ - w_idx = (int *)(buf + (size - (sizeof(u32) * 2))); size = size - (sizeof(u32) * 2); + w_idx = (int *)(buf + size); w_pos = *w_idx; if (from_beg) @@ -127,6 +127,10 @@ static const struct file_operations rproc_name_ops = { DEBUGFS_READONLY_FILE(trace0, rproc->trace_buf0, rproc->trace_len0); DEBUGFS_READONLY_FILE(trace1, rproc->trace_buf1, rproc->trace_len1); +DEBUGFS_READONLY_FILE(trace0_last, rproc->last_trace_buf0, + rproc->last_trace_len0); +DEBUGFS_READONLY_FILE(trace1_last, rproc->last_trace_buf1, + rproc->last_trace_len1); #define DEBUGFS_ADD(name) \ debugfs_create_file(#name, 0400, rproc->dbg_dir, \ @@ -194,12 +198,19 @@ rproc_da_to_pa(const struct rproc_mem_entry *maps, u64 da, phys_addr_t *pa) static int rproc_mmu_fault_isr(struct rproc *rproc, u64 da, u32 flags) { dev_err(rproc->dev, "%s\n", __func__); - rproc->state = RPROC_CRASHED; - schedule_work(&rproc->mmufault_work); + schedule_work(&rproc->error_work); return -EIO; } +static int rproc_watchdog_isr(struct rproc *rproc) +{ + dev_err(rproc->dev, "Enter %s\n", __func__); + schedule_work(&rproc->error_work); + + return 0; +} + static int _event_notify(struct rproc *rproc, int type, void *data) { struct blocking_notifier_head *nh; @@ -211,6 +222,12 @@ static int _event_notify(struct rproc *rproc, int type, void *data) init_completion(&rproc->error_comp); rproc->state = RPROC_CRASHED; mutex_unlock(&rproc->lock); + if (rproc->trace_buf0 && rproc->last_trace_buf0) + memcpy(rproc->last_trace_buf0, rproc->trace_buf0, + rproc->last_trace_len0); + if (rproc->trace_buf1 && rproc->last_trace_buf1) + memcpy(rproc->last_trace_buf1, rproc->trace_buf1, + rproc->last_trace_len1); #ifdef CONFIG_REMOTE_PROC_AUTOSUSPEND pm_runtime_dont_use_autosuspend(rproc->dev); #endif @@ -259,6 +276,15 @@ static void rproc_start(struct rproc *rproc, u64 bootaddr) } } + if (rproc->ops->watchdog_init) { + err = rproc->ops->watchdog_init(rproc, rproc_watchdog_isr); + if (err) { + dev_err(dev, "can't configure watchdog timer %d\n", + err); + goto unlock_mutext; + } + } + err = rproc->ops->start(rproc, bootaddr); if (err) { dev_err(dev, "can't start rproc %s: %d\n", rproc->name, err); @@ -393,9 +419,11 @@ static int rproc_handle_resources(struct rproc *rproc, struct fw_resource *rsc, /* store the da for processing at the end */ if (!trace_da0) { rproc->trace_len0 = rsc->len; + rproc->last_trace_len0 = rsc->len; trace_da0 = da; } else { rproc->trace_len1 = rsc->len; + rproc->last_trace_len1 = rsc->len; trace_da1 = da; } break; @@ -446,6 +474,9 @@ static int rproc_handle_resources(struct rproc *rproc, struct fw_resource *rsc, len -= sizeof(*rsc); } + if (ret) + goto error; + /* * post-process trace buffers, as we cannot rely on the order of the * trace section and the carveout sections. @@ -453,33 +484,54 @@ static int rproc_handle_resources(struct rproc *rproc, struct fw_resource *rsc, * trace buffer memory _is_ normal memory, so we cast away the * __iomem to make sparse happy */ - if (!ret && trace_da0) { + if (trace_da0) { ret = rproc_da_to_pa(rproc->memory_maps, trace_da0, &pa); - if (!ret) { - rproc->trace_buf0 = (__force void *) - ioremap_nocache(pa, rproc->trace_len0); - if (rproc->trace_buf0) - DEBUGFS_ADD(trace0); - else { - dev_err(dev, "can't ioremap trace buffer0\n"); - ret = -EIO; + if (ret) + goto error; + rproc->trace_buf0 = (__force void *) + ioremap_nocache(pa, rproc->trace_len0); + if (rproc->trace_buf0) { + DEBUGFS_ADD(trace0); + if (!rproc->last_trace_buf0) { + rproc->last_trace_buf0 = kzalloc(sizeof(u32) * + rproc->last_trace_len0, + GFP_KERNEL); + if (!rproc->last_trace_buf0) { + ret = -ENOMEM; + goto error; + } + DEBUGFS_ADD(trace0_last); } + } else { + dev_err(dev, "can't ioremap trace buffer0\n"); + ret = -EIO; + goto error; } } - if (!ret && trace_da1) { + if (trace_da1) { ret = rproc_da_to_pa(rproc->memory_maps, trace_da1, &pa); - if (!ret) { - rproc->trace_buf1 = (__force void *) - ioremap_nocache(pa, rproc->trace_len1); - if (rproc->trace_buf1) - DEBUGFS_ADD(trace1); - else { - dev_err(dev, "can't ioremap trace buffer1\n"); - ret = -EIO; + if (ret) + goto error; + rproc->trace_buf1 = (__force void *) + ioremap_nocache(pa, rproc->trace_len1); + if (rproc->trace_buf1) { + DEBUGFS_ADD(trace1); + if (!rproc->last_trace_buf1) { + rproc->last_trace_buf1 = kzalloc(sizeof(u32) * + rproc->last_trace_len1, + GFP_KERNEL); + if (!rproc->last_trace_buf1) { + ret = -ENOMEM; + goto error; + } + DEBUGFS_ADD(trace1_last); } + } else { + dev_err(dev, "can't ioremap trace buffer1\n"); + ret = -EIO; } } - +error: return ret; } @@ -638,6 +690,12 @@ static int rproc_loader(struct rproc *rproc) return 0; } +int rproc_errror_notify(struct rproc *rproc) +{ + return _event_notify(rproc, RPROC_ERROR, NULL); +} +EXPORT_SYMBOL_GPL(rproc_errror_notify); + struct rproc *rproc_get(const char *name) { struct rproc *rproc, *ret = NULL; @@ -760,6 +818,14 @@ void rproc_put(struct rproc *rproc) ret); goto out; } + if (rproc->ops->watchdog_exit) { + ret = rproc->ops->watchdog_exit(rproc); + if (ret) { + dev_err(rproc->dev, "error watchdog_exit %d\n", + ret); + goto out; + } + } if (rproc->ops->iommu_exit) { ret = rproc->ops->iommu_exit(rproc); if (ret) { @@ -784,9 +850,9 @@ out: } EXPORT_SYMBOL_GPL(rproc_put); -static void rproc_mmufault_work(struct work_struct *work) +static void rproc_error_work(struct work_struct *work) { - struct rproc *rproc = container_of(work, struct rproc, mmufault_work); + struct rproc *rproc = container_of(work, struct rproc, error_work); dev_dbg(rproc->dev, "Enter %s\n", __func__); _event_notify(rproc, RPROC_ERROR, NULL); @@ -1093,7 +1159,7 @@ int rproc_register(struct device *dev, const char *name, mutex_init(&rproc->pm_lock); #endif mutex_init(&rproc->lock); - INIT_WORK(&rproc->mmufault_work, rproc_mmufault_work); + INIT_WORK(&rproc->error_work, rproc_error_work); BLOCKING_INIT_NOTIFIER_HEAD(&rproc->nb_error); rproc->state = RPROC_OFFLINE; @@ -1160,6 +1226,8 @@ int rproc_unregister(const char *name) pm_qos_remove_request(rproc->qos_request); kfree(rproc->qos_request); + kfree(rproc->last_trace_buf0); + kfree(rproc->last_trace_buf1); kfree(rproc); return 0; |