From dcb57ed43d9ec5e16628c337143cd6b387f42778 Mon Sep 17 00:00:00 2001 From: Sarangdhar Joshi Date: Fri, 5 Jan 2018 16:04:20 -0800 Subject: remoteproc: qcom: Register segments for core dump Register MDT segments with the remoteproc core dump functionality in order to include them in a core dump, in case of a recovery of the remote processor. Signed-off-by: Sarangdhar Joshi Signed-off-by: Bjorn Andersson --- drivers/remoteproc/qcom_common.c | 44 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) (limited to 'drivers/remoteproc/qcom_common.c') diff --git a/drivers/remoteproc/qcom_common.c b/drivers/remoteproc/qcom_common.c index 00602499713f..b7d53a9cf21f 100644 --- a/drivers/remoteproc/qcom_common.c +++ b/drivers/remoteproc/qcom_common.c @@ -22,6 +22,7 @@ #include #include #include +#include #include "remoteproc_internal.h" #include "qcom_common.h" @@ -79,6 +80,49 @@ void qcom_remove_glink_subdev(struct rproc *rproc, struct qcom_rproc_glink *glin } EXPORT_SYMBOL_GPL(qcom_remove_glink_subdev); +/** + * qcom_register_dump_segments() - register segments for coredump + * @rproc: remoteproc handle + * @fw: firmware header + * + * Register all segments of the ELF in the remoteproc coredump segment list + * + * Return: 0 on success, negative errno on failure. + */ +int qcom_register_dump_segments(struct rproc *rproc, + const struct firmware *fw) +{ + const struct elf32_phdr *phdrs; + const struct elf32_phdr *phdr; + const struct elf32_hdr *ehdr; + int ret; + int i; + + ehdr = (struct elf32_hdr *)fw->data; + phdrs = (struct elf32_phdr *)(ehdr + 1); + + for (i = 0; i < ehdr->e_phnum; i++) { + phdr = &phdrs[i]; + + if (phdr->p_type != PT_LOAD) + continue; + + if ((phdr->p_flags & QCOM_MDT_TYPE_MASK) == QCOM_MDT_TYPE_HASH) + continue; + + if (!phdr->p_memsz) + continue; + + ret = rproc_coredump_add_segment(rproc, phdr->p_paddr, + phdr->p_memsz); + if (ret) + return ret; + } + + return 0; +} +EXPORT_SYMBOL_GPL(qcom_register_dump_segments); + static int smd_subdev_probe(struct rproc_subdev *subdev) { struct qcom_rproc_subdev *smd = to_smd_subdev(subdev); -- cgit v1.2.3 From 880f5b388252fedb26c70bb80ad1d7c8abbc0607 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Mon, 30 Oct 2017 23:11:14 -0700 Subject: remoteproc: Pass type of shutdown to subdev remove remoteproc instances can be stopped either by invoking shutdown or by an attempt to recover from a crash. For some subdev types it's expected to clean up gracefully during a shutdown, but are unable to do so during a crash - so pass this information to the subdev remove functions. Acked-By: Chris Lew Signed-off-by: Bjorn Andersson --- drivers/remoteproc/qcom_common.c | 6 +++--- drivers/remoteproc/remoteproc_core.c | 18 +++++++++--------- include/linux/remoteproc.h | 7 ++++--- 3 files changed, 16 insertions(+), 15 deletions(-) (limited to 'drivers/remoteproc/qcom_common.c') diff --git a/drivers/remoteproc/qcom_common.c b/drivers/remoteproc/qcom_common.c index b7d53a9cf21f..9e47a147c131 100644 --- a/drivers/remoteproc/qcom_common.c +++ b/drivers/remoteproc/qcom_common.c @@ -42,7 +42,7 @@ static int glink_subdev_probe(struct rproc_subdev *subdev) return PTR_ERR_OR_ZERO(glink->edge); } -static void glink_subdev_remove(struct rproc_subdev *subdev) +static void glink_subdev_remove(struct rproc_subdev *subdev, bool crashed) { struct qcom_rproc_glink *glink = to_glink_subdev(subdev); @@ -132,7 +132,7 @@ static int smd_subdev_probe(struct rproc_subdev *subdev) return PTR_ERR_OR_ZERO(smd->edge); } -static void smd_subdev_remove(struct rproc_subdev *subdev) +static void smd_subdev_remove(struct rproc_subdev *subdev, bool crashed) { struct qcom_rproc_subdev *smd = to_smd_subdev(subdev); @@ -201,7 +201,7 @@ static int ssr_notify_start(struct rproc_subdev *subdev) return 0; } -static void ssr_notify_stop(struct rproc_subdev *subdev) +static void ssr_notify_stop(struct rproc_subdev *subdev, bool crashed) { struct qcom_rproc_ssr *ssr = to_ssr_subdev(subdev); diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c index fd257607a578..6d9c5832ce47 100644 --- a/drivers/remoteproc/remoteproc_core.c +++ b/drivers/remoteproc/remoteproc_core.c @@ -308,7 +308,7 @@ static int rproc_vdev_do_probe(struct rproc_subdev *subdev) return rproc_add_virtio_dev(rvdev, rvdev->id); } -static void rproc_vdev_do_remove(struct rproc_subdev *subdev) +static void rproc_vdev_do_remove(struct rproc_subdev *subdev, bool crashed) { struct rproc_vdev *rvdev = container_of(subdev, struct rproc_vdev, subdev); @@ -789,17 +789,17 @@ static int rproc_probe_subdevices(struct rproc *rproc) unroll_registration: list_for_each_entry_continue_reverse(subdev, &rproc->subdevs, node) - subdev->remove(subdev); + subdev->remove(subdev, true); return ret; } -static void rproc_remove_subdevices(struct rproc *rproc) +static void rproc_remove_subdevices(struct rproc *rproc, bool crashed) { struct rproc_subdev *subdev; list_for_each_entry_reverse(subdev, &rproc->subdevs, node) - subdev->remove(subdev); + subdev->remove(subdev, crashed); } /** @@ -1009,13 +1009,13 @@ static int rproc_trigger_auto_boot(struct rproc *rproc) return ret; } -static int rproc_stop(struct rproc *rproc) +static int rproc_stop(struct rproc *rproc, bool crashed) { struct device *dev = &rproc->dev; int ret; /* remove any subdevices for the remote processor */ - rproc_remove_subdevices(rproc); + rproc_remove_subdevices(rproc, crashed); /* the installed resource table is no longer accessible */ rproc->table_ptr = rproc->cached_table; @@ -1163,7 +1163,7 @@ int rproc_trigger_recovery(struct rproc *rproc) if (ret) return ret; - ret = rproc_stop(rproc); + ret = rproc_stop(rproc, false); if (ret) goto unlock_mutex; @@ -1316,7 +1316,7 @@ void rproc_shutdown(struct rproc *rproc) if (!atomic_dec_and_test(&rproc->power)) goto out; - ret = rproc_stop(rproc); + ret = rproc_stop(rproc, true); if (ret) { atomic_inc(&rproc->power); goto out; @@ -1663,7 +1663,7 @@ EXPORT_SYMBOL(rproc_del); void rproc_add_subdev(struct rproc *rproc, struct rproc_subdev *subdev, int (*probe)(struct rproc_subdev *subdev), - void (*remove)(struct rproc_subdev *subdev)) + void (*remove)(struct rproc_subdev *subdev, bool crashed)) { subdev->probe = probe; subdev->remove = remove; diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h index f16864acedad..d09a9c7af109 100644 --- a/include/linux/remoteproc.h +++ b/include/linux/remoteproc.h @@ -478,13 +478,14 @@ struct rproc { * struct rproc_subdev - subdevice tied to a remoteproc * @node: list node related to the rproc subdevs list * @probe: probe function, called as the rproc is started - * @remove: remove function, called as the rproc is stopped + * @remove: remove function, called as the rproc is being stopped, the @crashed + * parameter indicates if this originates from the a recovery */ struct rproc_subdev { struct list_head node; int (*probe)(struct rproc_subdev *subdev); - void (*remove)(struct rproc_subdev *subdev); + void (*remove)(struct rproc_subdev *subdev, bool crashed); }; /* we currently support only two vrings per rvdev */ @@ -568,7 +569,7 @@ static inline struct rproc *vdev_to_rproc(struct virtio_device *vdev) void rproc_add_subdev(struct rproc *rproc, struct rproc_subdev *subdev, int (*probe)(struct rproc_subdev *subdev), - void (*remove)(struct rproc_subdev *subdev)); + void (*remove)(struct rproc_subdev *subdev, bool graceful)); void rproc_remove_subdev(struct rproc *rproc, struct rproc_subdev *subdev); -- cgit v1.2.3 From 730b2ad8f72898029160a6832141ba954122a0c8 Mon Sep 17 00:00:00 2001 From: Sibi Sankar Date: Tue, 3 Apr 2018 23:45:15 +0530 Subject: remoteproc: fix null pointer dereference on glink only platforms Currently calling list_del on smd subdev remove path results in null pointer dereference on glink only platforms. Fix this by adding safety checks in glink/smd subdev remove paths. Signed-off-by: Sibi Sankar Signed-off-by: Bjorn Andersson --- drivers/remoteproc/qcom_common.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/remoteproc/qcom_common.c') diff --git a/drivers/remoteproc/qcom_common.c b/drivers/remoteproc/qcom_common.c index 9e47a147c131..acfc99f82fb8 100644 --- a/drivers/remoteproc/qcom_common.c +++ b/drivers/remoteproc/qcom_common.c @@ -75,6 +75,9 @@ EXPORT_SYMBOL_GPL(qcom_add_glink_subdev); */ void qcom_remove_glink_subdev(struct rproc *rproc, struct qcom_rproc_glink *glink) { + if (!glink->node) + return; + rproc_remove_subdev(rproc, &glink->subdev); of_node_put(glink->node); } @@ -165,6 +168,9 @@ EXPORT_SYMBOL_GPL(qcom_add_smd_subdev); */ void qcom_remove_smd_subdev(struct rproc *rproc, struct qcom_rproc_subdev *smd) { + if (!smd->node) + return; + rproc_remove_subdev(rproc, &smd->subdev); of_node_put(smd->node); } -- cgit v1.2.3