diff options
-rw-r--r-- | arch/arm/mach-omap2/iommu2.c | 3 | ||||
-rw-r--r-- | arch/arm/mach-omap2/remoteproc.c | 6 | ||||
-rw-r--r-- | arch/arm/plat-omap/include/plat/iommu2.h | 1 | ||||
-rw-r--r-- | arch/arm/plat-omap/omap_rpmsg.c | 2 | ||||
-rw-r--r-- | drivers/remoteproc/Kconfig | 7 | ||||
-rw-r--r-- | drivers/remoteproc/omap_remoteproc.c | 59 | ||||
-rw-r--r-- | drivers/remoteproc/remoteproc.c | 118 | ||||
-rw-r--r-- | drivers/rpmsg/rpmsg_omx.c | 2 | ||||
-rw-r--r-- | include/linux/remoteproc.h | 7 |
9 files changed, 176 insertions, 29 deletions
diff --git a/arch/arm/mach-omap2/iommu2.c b/arch/arm/mach-omap2/iommu2.c index de06f56..faa7646 100644 --- a/arch/arm/mach-omap2/iommu2.c +++ b/arch/arm/mach-omap2/iommu2.c @@ -130,6 +130,9 @@ static int omap2_iommu_enable(struct iommu *obj) __iommu_set_twl(obj, true); + if (cpu_is_omap44xx()) + iommu_write_reg(obj, 0x1, MMU_GP_REG); + return 0; } diff --git a/arch/arm/mach-omap2/remoteproc.c b/arch/arm/mach-omap2/remoteproc.c index 5d6ccdd..43d49eb 100644 --- a/arch/arm/mach-omap2/remoteproc.c +++ b/arch/arm/mach-omap2/remoteproc.c @@ -34,6 +34,10 @@ static struct omap_rproc_timers_info ipu_timers[] = { { .id = 3 }, { .id = 4 }, +#ifdef CONFIG_REMOTEPROC_WATCHDOG + { .id = 9 }, + { .id = 11 }, +#endif }; static struct omap_rproc_pdata omap4_rproc_data[] = { @@ -55,7 +59,7 @@ static struct omap_rproc_pdata omap4_rproc_data[] = { .timers_cnt = ARRAY_SIZE(ipu_timers), .idle_addr = OMAP4430_CM_M3_M3_CLKCTRL, .idle_mask = OMAP4430_STBYST_MASK, - .suspend_addr = 0xb7ff02d8, + .suspend_addr = 0xb43f02d8, .suspend_mask = ~0, .sus_timeout = 5000, .sus_mbox_name = "mailbox-1", diff --git a/arch/arm/plat-omap/include/plat/iommu2.h b/arch/arm/plat-omap/include/plat/iommu2.h index 10ad05f..45b2e36 100644 --- a/arch/arm/plat-omap/include/plat/iommu2.h +++ b/arch/arm/plat-omap/include/plat/iommu2.h @@ -36,6 +36,7 @@ #define MMU_READ_CAM 0x68 #define MMU_READ_RAM 0x6c #define MMU_EMU_FAULT_AD 0x70 +#define MMU_GP_REG 0x88 #define MMU_REG_SIZE 256 diff --git a/arch/arm/plat-omap/omap_rpmsg.c b/arch/arm/plat-omap/omap_rpmsg.c index c4d1342..7de18ff 100644 --- a/arch/arm/plat-omap/omap_rpmsg.c +++ b/arch/arm/plat-omap/omap_rpmsg.c @@ -168,7 +168,7 @@ static int omap_rpmsg_mbox_callback(struct notifier_block *this, switch (msg) { case RP_MBOX_CRASH: pr_err("%s has just crashed !\n", rpdev->rproc_name); - /* todo: smarter error handling here */ + rproc_errror_notify(rpdev->rproc); break; case RP_MBOX_ECHO_REPLY: pr_info("received echo reply from %s !\n", rpdev->rproc_name); diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig index 069c8fd..5a6ba3a 100644 --- a/drivers/remoteproc/Kconfig +++ b/drivers/remoteproc/Kconfig @@ -41,3 +41,10 @@ config OMAP_RPRES help Say Y here if you want to use OMAP remote processor resources frame work. + +config REMOTEPROC_WATCHDOG + bool "OMAP remoteproc watchdog timer" + depends on REMOTE_PROC + default y + help + Say y to enable watchdog timer for remote cores diff --git a/drivers/remoteproc/omap_remoteproc.c b/drivers/remoteproc/omap_remoteproc.c index c464c1d..2d2bcb6 100644 --- a/drivers/remoteproc/omap_remoteproc.c +++ b/drivers/remoteproc/omap_remoteproc.c @@ -39,6 +39,7 @@ struct omap_rproc_priv { struct iommu *iommu; int (*iommu_cb)(struct rproc *, u64, u32); + int (*wdt_cb)(struct rproc *); #ifdef CONFIG_REMOTE_PROC_AUTOSUSPEND struct omap_mbox *mbox; void __iomem *idle; @@ -321,7 +322,51 @@ static void _destroy_pm_flags(struct rproc *rproc) } } #endif +#ifdef CONFIG_REMOTEPROC_WATCHDOG +static int omap_rproc_watchdog_init(struct rproc *rproc, + int (*callback)(struct rproc *rproc)) +{ + struct omap_rproc_priv *rpp = rproc->priv; + + rpp->wdt_cb = callback; + return 0; +} + +static int omap_rproc_watchdog_exit(struct rproc *rproc) +{ + struct omap_rproc_priv *rpp = rproc->priv; + + rpp->wdt_cb = NULL; + return 0; +} + +static irqreturn_t omap_rproc_watchdog_isr(int irq, void *p) +{ + struct rproc *rproc = p; + struct omap_rproc_pdata *pdata = rproc->dev->platform_data; + struct omap_rproc_timers_info *timers = pdata->timers; + struct omap_dm_timer *timer = NULL; + struct omap_rproc_priv *rpp = rproc->priv; + int i; + + for (i = 0; i < pdata->timers_cnt; i++) { + if (irq == omap_dm_timer_get_irq(timers[i].odt)) { + timer = timers[i].odt; + break; + } + } + + if (!timer) + return IRQ_NONE; + omap_dm_timer_write_status(timer, OMAP_TIMER_INT_OVERFLOW); + + if (rpp->wdt_cb) + rpp->wdt_cb(rproc); + + return IRQ_HANDLED; +} +#endif static inline int omap_rproc_start(struct rproc *rproc, u64 bootaddr) { struct device *dev = rproc->dev; @@ -339,6 +384,16 @@ static inline int omap_rproc_start(struct rproc *rproc, u64 bootaddr) goto out; } omap_dm_timer_set_source(timers[i].odt, OMAP_TIMER_SRC_SYS_CLK); +#ifdef CONFIG_REMOTEPROC_WATCHDOG + /* GPT 9 and 11 are using as WDT */ + if (timers[i].id == 9 || timers[i].id == 11) { + ret = request_irq(omap_dm_timer_get_irq(timers[i].odt), + omap_rproc_watchdog_isr, IRQF_DISABLED, + "rproc-wdt", rproc); + /* Clean counter, remoteproc proc will set the value */ + omap_dm_timer_set_load(timers[i].odt, 0, 0); + } +#endif } ret = omap_device_enable(pdev); @@ -413,6 +468,10 @@ static struct rproc_ops omap_rproc_ops = { .set_lat = omap_rproc_set_lat, .set_bw = omap_rproc_set_l3_bw, .scale = omap_rproc_scale, +#ifdef CONFIG_REMOTEPROC_WATCHDOG + .watchdog_init = omap_rproc_watchdog_init, + .watchdog_exit = omap_rproc_watchdog_exit, +#endif }; static int omap_rproc_probe(struct platform_device *pdev) 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; diff --git a/drivers/rpmsg/rpmsg_omx.c b/drivers/rpmsg/rpmsg_omx.c index b3a8b7e..bd417c4 100644 --- a/drivers/rpmsg/rpmsg_omx.c +++ b/drivers/rpmsg/rpmsg_omx.c @@ -111,7 +111,7 @@ static LIST_HEAD(rpmsg_omx_services_list); */ #define TILER_START 0x60000000 #define TILER_END 0x80000000 -#define ION_1D_START 0xBDF00000 +#define ION_1D_START 0xBA300000 #define ION_1D_END 0xBFD00000 #define ION_1D_VA 0x88000000 static u32 _rpmsg_pa_to_da(u32 pa) diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h index 7b9c549..8076cff 100644 --- a/include/linux/remoteproc.h +++ b/include/linux/remoteproc.h @@ -153,6 +153,8 @@ struct rproc_ops { int (*set_lat)(struct rproc *rproc, long v); int (*set_bw)(struct rproc *rproc, long v); int (*scale)(struct rproc *rproc, long v); + int (*watchdog_init)(struct rproc *, int (*)(struct rproc *)); + int (*watchdog_exit)(struct rproc *); }; /* @@ -244,9 +246,11 @@ struct rproc { struct mutex lock; struct dentry *dbg_dir; char *trace_buf0, *trace_buf1; + char *last_trace_buf0, *last_trace_buf1; int trace_len0, trace_len1; + int last_trace_len0, last_trace_len1; struct completion firmware_loading_complete; - struct work_struct mmufault_work; + struct work_struct error_work; struct blocking_notifier_head nb_error; struct completion error_comp; #ifdef CONFIG_REMOTE_PROC_AUTOSUSPEND @@ -277,5 +281,6 @@ extern const struct dev_pm_ops rproc_gen_pm_ops; #define GENERIC_RPROC_PM_OPS NULL #endif int rproc_set_constraints(struct rproc *, enum rproc_constraint type, long v); +int rproc_errror_notify(struct rproc *rproc); #endif /* REMOTEPROC_H */ |