remoteproc: Move coredump functionality to a new file
authorRishabh Bhatnagar <rishabhb@codeaurora.org>
Thu, 16 Jul 2020 22:20:31 +0000 (15:20 -0700)
committerBjorn Andersson <bjorn.andersson@linaro.org>
Tue, 21 Jul 2020 21:00:49 +0000 (14:00 -0700)
Move all coredump functionality to an individual file. This is
being done so that the current functionality can be extended
in future patchsets.

Signed-off-by: Rishabh Bhatnagar <rishabhb@codeaurora.org>
Reviewed-by: Bjorn Andersson <bjorn.andersson@linaro.org>
Reviewed-by: Mathieu Poirier <mathieu.poirier@linaro.org>
Reviewed-by: Sibi Sankar <sibis@codeaurora.org>
Tested-by: Sibi Sankar <sibis@codeaurora.org>
Link: https://lore.kernel.org/r/1594938035-7327-2-git-send-email-rishabhb@codeaurora.org
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
drivers/remoteproc/Makefile
drivers/remoteproc/remoteproc_core.c
drivers/remoteproc/remoteproc_coredump.c [new file with mode: 0644]
drivers/remoteproc/remoteproc_internal.h

index fe398f8..a4c1397 100644 (file)
@@ -5,6 +5,7 @@
 
 obj-$(CONFIG_REMOTEPROC)               += remoteproc.o
 remoteproc-y                           := remoteproc_core.o
+remoteproc-y                           += remoteproc_coredump.o
 remoteproc-y                           += remoteproc_debugfs.o
 remoteproc-y                           += remoteproc_sysfs.o
 remoteproc-y                           += remoteproc_virtio.o
index 6fa9f75..7f0d55f 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/firmware.h>
 #include <linux/string.h>
 #include <linux/debugfs.h>
-#include <linux/devcoredump.h>
 #include <linux/rculist.h>
 #include <linux/remoteproc.h>
 #include <linux/iommu.h>
@@ -40,7 +39,6 @@
 #include <linux/platform_device.h>
 
 #include "remoteproc_internal.h"
-#include "remoteproc_elf_helpers.h"
 
 #define HIGH_BITS_MASK 0xFFFFFFFF00000000ULL
 
@@ -1253,19 +1251,6 @@ static int rproc_alloc_registered_carveouts(struct rproc *rproc)
        return 0;
 }
 
-/**
- * rproc_coredump_cleanup() - clean up dump_segments list
- * @rproc: the remote processor handle
- */
-static void rproc_coredump_cleanup(struct rproc *rproc)
-{
-       struct rproc_dump_segment *entry, *tmp;
-
-       list_for_each_entry_safe(entry, tmp, &rproc->dump_segments, node) {
-               list_del(&entry->node);
-               kfree(entry);
-       }
-}
 
 /**
  * rproc_resource_cleanup() - clean up and free all acquired resources
@@ -1641,182 +1626,6 @@ static int rproc_stop(struct rproc *rproc, bool crashed)
        return 0;
 }
 
-/**
- * rproc_coredump_add_segment() - add segment of device memory to coredump
- * @rproc:     handle of a remote processor
- * @da:                device address
- * @size:      size of segment
- *
- * Add device memory to the list of segments to be included in a coredump for
- * the remoteproc.
- *
- * Return: 0 on success, negative errno on error.
- */
-int rproc_coredump_add_segment(struct rproc *rproc, dma_addr_t da, size_t size)
-{
-       struct rproc_dump_segment *segment;
-
-       segment = kzalloc(sizeof(*segment), GFP_KERNEL);
-       if (!segment)
-               return -ENOMEM;
-
-       segment->da = da;
-       segment->size = size;
-
-       list_add_tail(&segment->node, &rproc->dump_segments);
-
-       return 0;
-}
-EXPORT_SYMBOL(rproc_coredump_add_segment);
-
-/**
- * rproc_coredump_add_custom_segment() - add custom coredump segment
- * @rproc:     handle of a remote processor
- * @da:                device address
- * @size:      size of segment
- * @dumpfn:    custom dump function called for each segment during coredump
- * @priv:      private data
- *
- * Add device memory to the list of segments to be included in the coredump
- * and associate the segment with the given custom dump function and private
- * data.
- *
- * Return: 0 on success, negative errno on error.
- */
-int rproc_coredump_add_custom_segment(struct rproc *rproc,
-                                     dma_addr_t da, size_t size,
-                                     void (*dumpfn)(struct rproc *rproc,
-                                                    struct rproc_dump_segment *segment,
-                                                    void *dest),
-                                     void *priv)
-{
-       struct rproc_dump_segment *segment;
-
-       segment = kzalloc(sizeof(*segment), GFP_KERNEL);
-       if (!segment)
-               return -ENOMEM;
-
-       segment->da = da;
-       segment->size = size;
-       segment->priv = priv;
-       segment->dump = dumpfn;
-
-       list_add_tail(&segment->node, &rproc->dump_segments);
-
-       return 0;
-}
-EXPORT_SYMBOL(rproc_coredump_add_custom_segment);
-
-/**
- * rproc_coredump_set_elf_info() - set coredump elf information
- * @rproc:     handle of a remote processor
- * @class:     elf class for coredump elf file
- * @machine:   elf machine for coredump elf file
- *
- * Set elf information which will be used for coredump elf file.
- *
- * Return: 0 on success, negative errno on error.
- */
-int rproc_coredump_set_elf_info(struct rproc *rproc, u8 class, u16 machine)
-{
-       if (class != ELFCLASS64 && class != ELFCLASS32)
-               return -EINVAL;
-
-       rproc->elf_class = class;
-       rproc->elf_machine = machine;
-
-       return 0;
-}
-EXPORT_SYMBOL(rproc_coredump_set_elf_info);
-
-/**
- * rproc_coredump() - perform coredump
- * @rproc:     rproc handle
- *
- * This function will generate an ELF header for the registered segments
- * and create a devcoredump device associated with rproc.
- */
-static void rproc_coredump(struct rproc *rproc)
-{
-       struct rproc_dump_segment *segment;
-       void *phdr;
-       void *ehdr;
-       size_t data_size;
-       size_t offset;
-       void *data;
-       void *ptr;
-       u8 class = rproc->elf_class;
-       int phnum = 0;
-
-       if (list_empty(&rproc->dump_segments))
-               return;
-
-       if (class == ELFCLASSNONE) {
-               dev_err(&rproc->dev, "Elf class is not set\n");
-               return;
-       }
-
-       data_size = elf_size_of_hdr(class);
-       list_for_each_entry(segment, &rproc->dump_segments, node) {
-               data_size += elf_size_of_phdr(class) + segment->size;
-
-               phnum++;
-       }
-
-       data = vmalloc(data_size);
-       if (!data)
-               return;
-
-       ehdr = data;
-
-       memset(ehdr, 0, elf_size_of_hdr(class));
-       /* e_ident field is common for both elf32 and elf64 */
-       elf_hdr_init_ident(ehdr, class);
-
-       elf_hdr_set_e_type(class, ehdr, ET_CORE);
-       elf_hdr_set_e_machine(class, ehdr, rproc->elf_machine);
-       elf_hdr_set_e_version(class, ehdr, EV_CURRENT);
-       elf_hdr_set_e_entry(class, ehdr, rproc->bootaddr);
-       elf_hdr_set_e_phoff(class, ehdr, elf_size_of_hdr(class));
-       elf_hdr_set_e_ehsize(class, ehdr, elf_size_of_hdr(class));
-       elf_hdr_set_e_phentsize(class, ehdr, elf_size_of_phdr(class));
-       elf_hdr_set_e_phnum(class, ehdr, phnum);
-
-       phdr = data + elf_hdr_get_e_phoff(class, ehdr);
-       offset = elf_hdr_get_e_phoff(class, ehdr);
-       offset += elf_size_of_phdr(class) * elf_hdr_get_e_phnum(class, ehdr);
-
-       list_for_each_entry(segment, &rproc->dump_segments, node) {
-               memset(phdr, 0, elf_size_of_phdr(class));
-               elf_phdr_set_p_type(class, phdr, PT_LOAD);
-               elf_phdr_set_p_offset(class, phdr, offset);
-               elf_phdr_set_p_vaddr(class, phdr, segment->da);
-               elf_phdr_set_p_paddr(class, phdr, segment->da);
-               elf_phdr_set_p_filesz(class, phdr, segment->size);
-               elf_phdr_set_p_memsz(class, phdr, segment->size);
-               elf_phdr_set_p_flags(class, phdr, PF_R | PF_W | PF_X);
-               elf_phdr_set_p_align(class, phdr, 0);
-
-               if (segment->dump) {
-                       segment->dump(rproc, segment, data + offset);
-               } else {
-                       ptr = rproc_da_to_va(rproc, segment->da, segment->size);
-                       if (!ptr) {
-                               dev_err(&rproc->dev,
-                                       "invalid coredump segment (%pad, %zu)\n",
-                                       &segment->da, segment->size);
-                               memset(data + offset, 0xff, segment->size);
-                       } else {
-                               memcpy(data + offset, ptr, segment->size);
-                       }
-               }
-
-               offset += elf_phdr_get_p_filesz(class, phdr);
-               phdr += elf_size_of_phdr(class);
-       }
-
-       dev_coredumpv(&rproc->dev, data, data_size, GFP_KERNEL);
-}
 
 /**
  * rproc_trigger_recovery() - recover a remoteproc
diff --git a/drivers/remoteproc/remoteproc_coredump.c b/drivers/remoteproc/remoteproc_coredump.c
new file mode 100644 (file)
index 0000000..ded0244
--- /dev/null
@@ -0,0 +1,204 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Coredump functionality for Remoteproc framework.
+ *
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ */
+
+#include <linux/devcoredump.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/remoteproc.h>
+#include "remoteproc_internal.h"
+#include "remoteproc_elf_helpers.h"
+
+/**
+ * rproc_coredump_cleanup() - clean up dump_segments list
+ * @rproc: the remote processor handle
+ */
+void rproc_coredump_cleanup(struct rproc *rproc)
+{
+       struct rproc_dump_segment *entry, *tmp;
+
+       list_for_each_entry_safe(entry, tmp, &rproc->dump_segments, node) {
+               list_del(&entry->node);
+               kfree(entry);
+       }
+}
+
+/**
+ * rproc_coredump_add_segment() - add segment of device memory to coredump
+ * @rproc:     handle of a remote processor
+ * @da:                device address
+ * @size:      size of segment
+ *
+ * Add device memory to the list of segments to be included in a coredump for
+ * the remoteproc.
+ *
+ * Return: 0 on success, negative errno on error.
+ */
+int rproc_coredump_add_segment(struct rproc *rproc, dma_addr_t da, size_t size)
+{
+       struct rproc_dump_segment *segment;
+
+       segment = kzalloc(sizeof(*segment), GFP_KERNEL);
+       if (!segment)
+               return -ENOMEM;
+
+       segment->da = da;
+       segment->size = size;
+
+       list_add_tail(&segment->node, &rproc->dump_segments);
+
+       return 0;
+}
+EXPORT_SYMBOL(rproc_coredump_add_segment);
+
+/**
+ * rproc_coredump_add_custom_segment() - add custom coredump segment
+ * @rproc:     handle of a remote processor
+ * @da:                device address
+ * @size:      size of segment
+ * @dumpfn:    custom dump function called for each segment during coredump
+ * @priv:      private data
+ *
+ * Add device memory to the list of segments to be included in the coredump
+ * and associate the segment with the given custom dump function and private
+ * data.
+ *
+ * Return: 0 on success, negative errno on error.
+ */
+int rproc_coredump_add_custom_segment(struct rproc *rproc,
+                                     dma_addr_t da, size_t size,
+                                     void (*dumpfn)(struct rproc *rproc,
+                                                    struct rproc_dump_segment *segment,
+                                                    void *dest),
+                                     void *priv)
+{
+       struct rproc_dump_segment *segment;
+
+       segment = kzalloc(sizeof(*segment), GFP_KERNEL);
+       if (!segment)
+               return -ENOMEM;
+
+       segment->da = da;
+       segment->size = size;
+       segment->priv = priv;
+       segment->dump = dumpfn;
+
+       list_add_tail(&segment->node, &rproc->dump_segments);
+
+       return 0;
+}
+EXPORT_SYMBOL(rproc_coredump_add_custom_segment);
+
+/**
+ * rproc_coredump_set_elf_info() - set coredump elf information
+ * @rproc:     handle of a remote processor
+ * @class:     elf class for coredump elf file
+ * @machine:   elf machine for coredump elf file
+ *
+ * Set elf information which will be used for coredump elf file.
+ *
+ * Return: 0 on success, negative errno on error.
+ */
+int rproc_coredump_set_elf_info(struct rproc *rproc, u8 class, u16 machine)
+{
+       if (class != ELFCLASS64 && class != ELFCLASS32)
+               return -EINVAL;
+
+       rproc->elf_class = class;
+       rproc->elf_machine = machine;
+
+       return 0;
+}
+EXPORT_SYMBOL(rproc_coredump_set_elf_info);
+
+/**
+ * rproc_coredump() - perform coredump
+ * @rproc:     rproc handle
+ *
+ * This function will generate an ELF header for the registered segments
+ * and create a devcoredump device associated with rproc.
+ */
+void rproc_coredump(struct rproc *rproc)
+{
+       struct rproc_dump_segment *segment;
+       void *phdr;
+       void *ehdr;
+       size_t data_size;
+       size_t offset;
+       void *data;
+       void *ptr;
+       u8 class = rproc->elf_class;
+       int phnum = 0;
+
+       if (list_empty(&rproc->dump_segments))
+               return;
+
+       if (class == ELFCLASSNONE) {
+               dev_err(&rproc->dev, "Elf class is not set\n");
+               return;
+       }
+
+       data_size = elf_size_of_hdr(class);
+       list_for_each_entry(segment, &rproc->dump_segments, node) {
+               data_size += elf_size_of_phdr(class) + segment->size;
+
+               phnum++;
+       }
+
+       data = vmalloc(data_size);
+       if (!data)
+               return;
+
+       ehdr = data;
+
+       memset(ehdr, 0, elf_size_of_hdr(class));
+       /* e_ident field is common for both elf32 and elf64 */
+       elf_hdr_init_ident(ehdr, class);
+
+       elf_hdr_set_e_type(class, ehdr, ET_CORE);
+       elf_hdr_set_e_machine(class, ehdr, rproc->elf_machine);
+       elf_hdr_set_e_version(class, ehdr, EV_CURRENT);
+       elf_hdr_set_e_entry(class, ehdr, rproc->bootaddr);
+       elf_hdr_set_e_phoff(class, ehdr, elf_size_of_hdr(class));
+       elf_hdr_set_e_ehsize(class, ehdr, elf_size_of_hdr(class));
+       elf_hdr_set_e_phentsize(class, ehdr, elf_size_of_phdr(class));
+       elf_hdr_set_e_phnum(class, ehdr, phnum);
+
+       phdr = data + elf_hdr_get_e_phoff(class, ehdr);
+       offset = elf_hdr_get_e_phoff(class, ehdr);
+       offset += elf_size_of_phdr(class) * elf_hdr_get_e_phnum(class, ehdr);
+
+       list_for_each_entry(segment, &rproc->dump_segments, node) {
+               memset(phdr, 0, elf_size_of_phdr(class));
+               elf_phdr_set_p_type(class, phdr, PT_LOAD);
+               elf_phdr_set_p_offset(class, phdr, offset);
+               elf_phdr_set_p_vaddr(class, phdr, segment->da);
+               elf_phdr_set_p_paddr(class, phdr, segment->da);
+               elf_phdr_set_p_filesz(class, phdr, segment->size);
+               elf_phdr_set_p_memsz(class, phdr, segment->size);
+               elf_phdr_set_p_flags(class, phdr, PF_R | PF_W | PF_X);
+               elf_phdr_set_p_align(class, phdr, 0);
+
+               if (segment->dump) {
+                       segment->dump(rproc, segment, data + offset);
+               } else {
+                       ptr = rproc_da_to_va(rproc, segment->da, segment->size);
+                       if (!ptr) {
+                               dev_err(&rproc->dev,
+                                       "invalid coredump segment (%pad, %zu)\n",
+                                       &segment->da, segment->size);
+                               memset(data + offset, 0xff, segment->size);
+                       } else {
+                               memcpy(data + offset, ptr, segment->size);
+                       }
+               }
+
+               offset += elf_phdr_get_p_filesz(class, phdr);
+               phdr += elf_size_of_phdr(class);
+       }
+
+       dev_coredumpv(&rproc->dev, data, data_size, GFP_KERNEL);
+}
index fc71086..26fe012 100644 (file)
@@ -47,6 +47,10 @@ extern struct class rproc_class;
 int rproc_init_sysfs(void);
 void rproc_exit_sysfs(void);
 
+/* from remoteproc_coredump.c */
+void rproc_coredump_cleanup(struct rproc *rproc);
+void rproc_coredump(struct rproc *rproc);
+
 void rproc_free_vring(struct rproc_vring *rvring);
 int rproc_alloc_vring(struct rproc_vdev *rvdev, int i);