From: Mukesh Ojha <mukesh.ojha@oss.qualcomm.com>
To: Jonathan Corbet <corbet@lwn.net>,
Shuah Khan <skhan@linuxfoundation.org>,
Eugen Hristev <eugen.hristev@linaro.org>,
Arnd Bergmann <arnd@arndb.de>, Dennis Zhou <dennis@kernel.org>,
Tejun Heo <tj@kernel.org>, Christoph Lameter <cl@gentwo.org>,
Andrew Morton <akpm@linux-foundation.org>,
Thomas Gleixner <tglx@kernel.org>,
Peter Zijlstra <peterz@infradead.org>,
Anna-Maria Behnsen <anna-maria@linutronix.de>,
Frederic Weisbecker <frederic@kernel.org>,
Ingo Molnar <mingo@redhat.com>,
Juri Lelli <juri.lelli@redhat.com>,
Vincent Guittot <vincent.guittot@linaro.org>,
Dietmar Eggemann <dietmar.eggemann@arm.com>,
Steven Rostedt <rostedt@goodmis.org>,
Ben Segall <bsegall@google.com>, Mel Gorman <mgorman@suse.de>,
Valentin Schneider <vschneid@redhat.com>,
David Hildenbrand <david@kernel.org>,
Lorenzo Stoakes <ljs@kernel.org>,
"Liam R. Howlett" <Liam.Howlett@oracle.com>,
Vlastimil Babka <vbabka@kernel.org>,
Mike Rapoport <rppt@kernel.org>,
Suren Baghdasaryan <surenb@google.com>,
Michal Hocko <mhocko@suse.com>, Kees Cook <kees@kernel.org>,
Brendan Jackman <jackmanb@google.com>,
Johannes Weiner <hannes@cmpxchg.org>, Zi Yan <ziy@nvidia.com>,
Chris Li <chrisl@kernel.org>, Kairui Song <kasong@tencent.com>,
Kemeng Shi <shikemeng@huaweicloud.com>,
Nhat Pham <nphamcs@gmail.com>, Baoquan He <bhe@redhat.com>,
Barry Song <baohua@kernel.org>,
Youngjun Park <youngjun.park@lge.com>,
Petr Mladek <pmladek@suse.com>,
John Ogness <john.ogness@linutronix.de>,
Sergey Senozhatsky <senozhatsky@chromium.org>,
Bjorn Andersson <andersson@kernel.org>,
Mathieu Poirier <mathieu.poirier@linaro.org>,
Konrad Dybcio <konradybcio@kernel.org>,
Mukesh Ojha <mukesh.ojha@oss.qualcomm.com>,
Rob Herring <robh@kernel.org>,
Krzysztof Kozlowski <krzk+dt@kernel.org>,
Conor Dooley <conor+dt@kernel.org>,
Saravana Kannan <saravanak@kernel.org>
Cc: workflows@vger.kernel.org, linux-doc@vger.kernel.org,
linux-kernel@vger.kernel.org, linux-arch@vger.kernel.org,
linux-mm@kvack.org, linux-arm-msm@vger.kernel.org,
linux-remoteproc@vger.kernel.org, devicetree@vger.kernel.org
Subject: [PATCH v2 22/25] soc: qcom: Add minidump backend driver
Date: Wed, 11 Mar 2026 01:46:06 +0530 [thread overview]
Message-ID: <20260311-minidump-v2-v2-22-f91cedc6f99e@oss.qualcomm.com> (raw)
In-Reply-To: <20260311-minidump-v2-v2-0-f91cedc6f99e@oss.qualcomm.com>
From: Eugen Hristev <eugen.hristev@linaro.org>
Qualcomm Minidump is a backend driver that manages the minidump shared
memory table on Qualcomm platforms. It uses the meminspect table that
it parses in order to obtain inspection entries from the kernel and
convert them into regions. Regions are afterwards being registered into
the shared memory's Minidump table of contents. Further, Qualcomm boot
firmware can read the table of contents and dump the memory accordingly,
as per the firmware requirements.
Signed-off-by: Eugen Hristev <eugen.hristev@linaro.org>
Signed-off-by: Mukesh Ojha <mukesh.ojha@oss.qualcomm.com>
---
drivers/soc/qcom/Kconfig | 13 ++
drivers/soc/qcom/Makefile | 1 +
drivers/soc/qcom/minidump.c | 272 ++++++++++++++++++++++++++++++++++++++
include/linux/soc/qcom/minidump.h | 4 +
4 files changed, 290 insertions(+)
diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
index 2caadbbcf830..be768537528e 100644
--- a/drivers/soc/qcom/Kconfig
+++ b/drivers/soc/qcom/Kconfig
@@ -180,6 +180,19 @@ config QCOM_SMEM
The driver provides an interface to items in a heap shared among all
processors in a Qualcomm platform.
+config QCOM_MINIDUMP
+ tristate "Qualcomm Minidump memory inspection driver"
+ depends on ARCH_QCOM || COMPILE_TEST
+ depends on QCOM_SMEM
+ help
+ Say y here to enable the Qualcomm Minidump memory inspection driver.
+ This driver uses memory inspection mechanism to register minidump
+ regions with the Qualcomm firmware, into the shared memory.
+ The registered regions are being linked into the minidump table
+ of contents.
+ Further on, the firmware will be able to read the table of contents
+ and extract the memory regions on case-by-case basis.
+
config QCOM_SMD_RPM
tristate "Qualcomm Resource Power Manager (RPM) over SMD"
depends on ARCH_QCOM || COMPILE_TEST
diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile
index b7f1d2a57367..3e5a2cacccd4 100644
--- a/drivers/soc/qcom/Makefile
+++ b/drivers/soc/qcom/Makefile
@@ -25,6 +25,7 @@ qcom_rpmh-y += rpmh.o
obj-$(CONFIG_QCOM_SMD_RPM) += rpm-proc.o smd-rpm.o
obj-$(CONFIG_QCOM_SMEM) += smem.o
obj-$(CONFIG_QCOM_SMEM_STATE) += smem_state.o
+obj-$(CONFIG_QCOM_MINIDUMP) += minidump.o
CFLAGS_smp2p.o := -I$(src)
obj-$(CONFIG_QCOM_SMP2P) += smp2p.o
obj-$(CONFIG_QCOM_SMSM) += smsm.o
diff --git a/drivers/soc/qcom/minidump.c b/drivers/soc/qcom/minidump.c
new file mode 100644
index 000000000000..8d2e5047b5d9
--- /dev/null
+++ b/drivers/soc/qcom/minidump.c
@@ -0,0 +1,272 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Qualcomm Minidump kernel inspect driver
+ * Copyright (C) 2016,2024-2025 Linaro Ltd
+ * Copyright (C) 2015 Sony Mobile Communications Inc
+ * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+ */
+
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/notifier.h>
+#include <linux/sizes.h>
+#include <linux/slab.h>
+#include <linux/soc/qcom/smem.h>
+#include <linux/soc/qcom/minidump.h>
+#include <linux/meminspect.h>
+
+/**
+ * struct minidump - Minidump driver data information
+ *
+ * @dev: Minidump device struct.
+ * @toc: Minidump table of contents subsystem.
+ * @regions: Minidump regions array.
+ * @nb: Notifier block to register to meminspect.
+ */
+struct minidump {
+ struct device *dev;
+ struct minidump_subsystem *toc;
+ struct minidump_region *regions;
+ struct notifier_block nb;
+};
+
+static const char * const meminspect_id_to_md_string[] = {
+ "",
+ "ELF",
+ "vmcoreinfo",
+ "config",
+ "totalram",
+ "cpu_possible",
+ "cpu_present",
+ "cpu_online",
+ "cpu_active",
+ "mem_section",
+ "jiffies",
+ "linux_banner",
+ "nr_threads",
+ "nr_irqs",
+ "tainted_mask",
+ "taint_flags",
+ "node_states",
+ "__per_cpu_offset",
+ "nr_swapfiles",
+ "init_uts_ns",
+ "printk_rb_static",
+ "printk_rb_dynamic",
+ "prb",
+ "prb_descs",
+ "prb_infos",
+ "prb_data",
+ "high_memory",
+ "init_mm",
+ "init_mm_pgd",
+};
+
+/**
+ * qcom_md_table_init() - Initialize the minidump table
+ * @md: minidump data
+ * @mdss_toc: minidump subsystem table of contents
+ *
+ * Return: On success, it returns 0 and negative error value on failure.
+ */
+static int qcom_md_table_init(struct minidump *md,
+ struct minidump_subsystem *mdss_toc)
+{
+ md->toc = mdss_toc;
+ md->regions = devm_kcalloc(md->dev, MAX_NUM_REGIONS,
+ sizeof(*md->regions), GFP_KERNEL);
+ if (!md->regions)
+ return -ENOMEM;
+
+ md->toc->regions_baseptr = cpu_to_le64(virt_to_phys(md->regions));
+ md->toc->enabled = cpu_to_le32(MINIDUMP_SS_ENABLED);
+ md->toc->status = cpu_to_le32(1);
+ md->toc->region_count = cpu_to_le32(0);
+
+ /* Tell bootloader not to encrypt the regions of this subsystem */
+ md->toc->encryption_status = cpu_to_le32(MINIDUMP_SS_ENCR_DONE);
+ md->toc->encryption_required = cpu_to_le32(MINIDUMP_SS_ENCR_NOTREQ);
+
+ return 0;
+}
+
+/**
+ * qcom_md_get_region_index() - Lookup minidump region by id
+ * @md: minidump data
+ * @id: minidump region id
+ *
+ * Return: On success, it returns the internal region index, on failure,
+ * returns negative error value
+ */
+static int qcom_md_get_region_index(struct minidump *md, int id)
+{
+ unsigned int count = le32_to_cpu(md->toc->region_count);
+ unsigned int i;
+
+ for (i = 0; i < count; i++)
+ if (md->regions[i].seq_num == id)
+ return i;
+
+ return -ENOENT;
+}
+
+/**
+ * register_md_region() - Register a new minidump region
+ * @priv: private data
+ * @e: pointer to inspect entry
+ *
+ * Return: None
+ */
+static void __maybe_unused register_md_region(void *priv,
+ const struct inspect_entry *e)
+{
+ unsigned int num_region, region_cnt;
+ const char *name = "unknown";
+ struct minidump_region *mdr;
+ struct minidump *md = priv;
+
+ if (!(e->va || e->pa) || !e->size) {
+ dev_dbg(md->dev, "invalid region requested\n");
+ return;
+ }
+
+ if (e->id < ARRAY_SIZE(meminspect_id_to_md_string))
+ name = meminspect_id_to_md_string[e->id];
+
+ if (qcom_md_get_region_index(md, e->id) >= 0) {
+ dev_dbg(md->dev, "%s:%d region is already registered\n",
+ name, e->id);
+ return;
+ }
+
+ /* Check if there is a room for a new entry */
+ num_region = le32_to_cpu(md->toc->region_count);
+ if (num_region >= MAX_NUM_REGIONS) {
+ dev_dbg(md->dev, "maximum region limit %u reached\n",
+ num_region);
+ return;
+ }
+
+ region_cnt = le32_to_cpu(md->toc->region_count);
+ mdr = &md->regions[region_cnt];
+ scnprintf(mdr->name, MAX_REGION_NAME_LENGTH, "K%.8s", name);
+ mdr->seq_num = e->id;
+ if (e->pa)
+ mdr->address = cpu_to_le64(e->pa);
+ else if (e->va)
+ mdr->address = cpu_to_le64(__pa(e->va));
+ mdr->size = cpu_to_le64(ALIGN(e->size, 4));
+ mdr->valid = cpu_to_le32(MINIDUMP_REGION_VALID);
+ region_cnt++;
+ md->toc->region_count = cpu_to_le32(region_cnt);
+
+ dev_dbg(md->dev, "%s:%d region registered %llx:%llx\n",
+ mdr->name, mdr->seq_num, mdr->address, mdr->size);
+}
+
+/**
+ * unregister_md_region() - Unregister a previously registered minidump region
+ * @priv: private data
+ * @e: pointer to inspect entry
+ *
+ * Return: None
+ */
+static void __maybe_unused unregister_md_region(void *priv,
+ const struct inspect_entry *e)
+{
+ struct minidump_region *mdr;
+ struct minidump *md = priv;
+ unsigned int region_cnt;
+ unsigned int idx;
+
+ idx = qcom_md_get_region_index(md, e->id);
+ if (idx < 0) {
+ dev_dbg(md->dev, "%d region is not present\n", e->id);
+ return;
+ }
+
+ mdr = &md->regions[0];
+ region_cnt = le32_to_cpu(md->toc->region_count);
+
+ /*
+ * Left shift one position all the regions located after the
+ * region being removed, in order to fill the gap.
+ * Then, zero out the last region at the end.
+ */
+ memmove(&mdr[idx], &mdr[idx + 1], (region_cnt - idx - 1) * sizeof(*mdr));
+ memset(&mdr[region_cnt - 1], 0, sizeof(*mdr));
+ region_cnt--;
+ md->toc->region_count = cpu_to_le32(region_cnt);
+}
+
+static int qcom_md_notifier_cb(struct notifier_block *nb,
+ unsigned long code, void *entry)
+{
+ struct minidump *md = container_of(nb, struct minidump, nb);
+
+ if (code == MEMINSPECT_NOTIFIER_ADD)
+ register_md_region(md, entry);
+ else if (code == MEMINSPECT_NOTIFIER_REMOVE)
+ unregister_md_region(md, entry);
+
+ return 0;
+}
+
+static int qcom_md_probe(struct platform_device *pdev)
+{
+ struct minidump_global_toc *mdgtoc;
+ struct device *dev = &pdev->dev;
+ struct minidump *md;
+ size_t size;
+ int ret;
+
+ md = devm_kzalloc(dev, sizeof(*md), GFP_KERNEL);
+ if (!md)
+ return -ENOMEM;
+ platform_set_drvdata(pdev, md);
+
+ md->dev = dev;
+ md->nb.notifier_call = qcom_md_notifier_cb;
+
+ mdgtoc = qcom_smem_get(QCOM_SMEM_HOST_ANY, SBL_MINIDUMP_SMEM_ID, &size);
+ if (IS_ERR(mdgtoc)) {
+ ret = PTR_ERR(mdgtoc);
+ dev_err_probe(dev, ret, "Couldn't find minidump smem item\n");
+ }
+
+ if (size < sizeof(*mdgtoc) || !mdgtoc->status)
+ dev_err_probe(dev, -EINVAL, "minidump table not ready\n");
+
+ ret = qcom_md_table_init(md, &mdgtoc->subsystems[MINIDUMP_SUBSYSTEM_APSS]);
+ if (ret)
+ dev_err_probe(dev, ret, "Could not initialize table\n");
+
+ meminspect_notifier_register(&md->nb);
+
+ meminspect_lock_traverse(md, register_md_region);
+ return 0;
+}
+
+static void qcom_md_remove(struct platform_device *pdev)
+{
+ struct minidump *md = platform_get_drvdata(pdev);
+
+ meminspect_notifier_unregister(&md->nb);
+ meminspect_lock_traverse(md, unregister_md_region);
+}
+
+static struct platform_driver qcom_md_driver = {
+ .probe = qcom_md_probe,
+ .remove = qcom_md_remove,
+ .driver = {
+ .name = "qcom-minidump",
+ },
+};
+
+module_platform_driver(qcom_md_driver);
+
+MODULE_AUTHOR("Eugen Hristev <eugen.hristev@linaro.org>");
+MODULE_AUTHOR("Mukesh Ojha <mukesh.ojha@oss.qualcomm.com>");
+MODULE_DESCRIPTION("Qualcomm minidump inspect driver");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/soc/qcom/minidump.h b/include/linux/soc/qcom/minidump.h
index 25247a6216e2..f90b61feb550 100644
--- a/include/linux/soc/qcom/minidump.h
+++ b/include/linux/soc/qcom/minidump.h
@@ -10,12 +10,16 @@
#ifndef __QCOM_MINIDUMP_H__
#define __QCOM_MINIDUMP_H__
+#define MINIDUMP_SUBSYSTEM_APSS 0
#define MAX_NUM_OF_SS 10
#define MAX_REGION_NAME_LENGTH 16
#define SBL_MINIDUMP_SMEM_ID 602
#define MINIDUMP_REGION_VALID ('V' << 24 | 'A' << 16 | 'L' << 8 | 'I' << 0)
#define MINIDUMP_SS_ENCR_DONE ('D' << 24 | 'O' << 16 | 'N' << 8 | 'E' << 0)
+#define MINIDUMP_SS_ENCR_NOTREQ (0 << 24 | 0 << 16 | 'N' << 8 | 'R' << 0)
#define MINIDUMP_SS_ENABLED ('E' << 24 | 'N' << 16 | 'B' << 8 | 'L' << 0)
+#define MAX_NUM_REGIONS 201
+
/**
* struct minidump_region - Minidump region
--
2.50.1
next prev parent reply other threads:[~2026-03-10 20:21 UTC|newest]
Thread overview: 39+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-03-10 20:15 [PATCH v2 00/25] Introduce meminspect Mukesh Ojha
2026-03-10 20:15 ` [PATCH v2 01/25] kernel: " Mukesh Ojha
2026-03-12 4:33 ` Randy Dunlap
2026-03-12 4:46 ` Randy Dunlap
2026-03-16 8:31 ` Mukesh Ojha
2026-03-10 20:15 ` [PATCH v2 02/25] init/version: Annotate static information into meminspect Mukesh Ojha
2026-03-10 20:15 ` [PATCH v2 03/25] mm/percpu: " Mukesh Ojha
2026-03-10 20:15 ` [PATCH v2 04/25] cpu: " Mukesh Ojha
2026-03-10 20:15 ` [PATCH v2 05/25] genirq/irqdesc: " Mukesh Ojha
2026-03-10 20:15 ` [PATCH v2 06/25] timers: " Mukesh Ojha
2026-03-10 20:15 ` [PATCH v2 07/25] kernel/fork: " Mukesh Ojha
2026-03-10 20:15 ` [PATCH v2 08/25] mm/page_alloc: " Mukesh Ojha
2026-03-10 20:15 ` [PATCH v2 09/25] mm/show_mem: " Mukesh Ojha
2026-03-10 20:15 ` [PATCH v2 10/25] mm/swapfile: " Mukesh Ojha
2026-03-10 20:15 ` [PATCH v2 11/25] kernel/vmcore_info: Register dynamic " Mukesh Ojha
2026-03-10 20:15 ` [PATCH v2 12/25] kernel/configs: " Mukesh Ojha
2026-03-10 20:15 ` [PATCH v2 13/25] mm/init-mm: Annotate static " Mukesh Ojha
2026-03-10 20:15 ` [PATCH v2 14/25] panic: " Mukesh Ojha
2026-03-10 20:15 ` [PATCH v2 15/25] kallsyms: " Mukesh Ojha
2026-03-10 20:16 ` [PATCH v2 16/25] mm/mm_init: " Mukesh Ojha
2026-03-10 20:16 ` [PATCH v2 17/25] sched/core: Annotate runqueues " Mukesh Ojha
2026-03-10 20:16 ` [PATCH v2 18/25] mm/numa: Register node data information " Mukesh Ojha
2026-03-10 20:16 ` [PATCH v2 19/25] mm/sparse: Register " Mukesh Ojha
2026-03-10 20:16 ` [PATCH v2 20/25] printk: " Mukesh Ojha
2026-03-16 9:39 ` John Ogness
2026-03-16 10:24 ` Eugen Hristev
2026-03-10 20:16 ` [PATCH v2 21/25] remoteproc: qcom: Move minidump data structures into its own header Mukesh Ojha
2026-03-10 20:16 ` Mukesh Ojha [this message]
2026-03-10 20:16 ` [PATCH v2 23/25] soc: qcom: smem: Add minidump platform device Mukesh Ojha
2026-03-10 20:16 ` [PATCH v2 24/25] dt-bindings: reserved-memory: Add Google Kinfo Pixel reserved memory Mukesh Ojha
2026-03-11 9:05 ` Krzysztof Kozlowski
2026-03-16 11:12 ` Mukesh Ojha
2026-03-10 20:16 ` [PATCH v2 25/25] meminspect: Add debug kinfo compatible driver Mukesh Ojha
2026-03-11 9:09 ` Krzysztof Kozlowski
2026-03-11 22:07 ` Randy Dunlap
2026-03-16 2:24 ` [PATCH v2 00/25] Introduce meminspect Bjorn Andersson
2026-03-16 18:16 ` Mukesh Ojha
2026-03-19 2:55 ` Bjorn Andersson
2026-03-19 7:33 ` Eugen Hristev
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260311-minidump-v2-v2-22-f91cedc6f99e@oss.qualcomm.com \
--to=mukesh.ojha@oss.qualcomm.com \
--cc=Liam.Howlett@oracle.com \
--cc=akpm@linux-foundation.org \
--cc=andersson@kernel.org \
--cc=anna-maria@linutronix.de \
--cc=arnd@arndb.de \
--cc=baohua@kernel.org \
--cc=bhe@redhat.com \
--cc=bsegall@google.com \
--cc=chrisl@kernel.org \
--cc=cl@gentwo.org \
--cc=conor+dt@kernel.org \
--cc=corbet@lwn.net \
--cc=david@kernel.org \
--cc=dennis@kernel.org \
--cc=devicetree@vger.kernel.org \
--cc=dietmar.eggemann@arm.com \
--cc=eugen.hristev@linaro.org \
--cc=frederic@kernel.org \
--cc=hannes@cmpxchg.org \
--cc=jackmanb@google.com \
--cc=john.ogness@linutronix.de \
--cc=juri.lelli@redhat.com \
--cc=kasong@tencent.com \
--cc=kees@kernel.org \
--cc=konradybcio@kernel.org \
--cc=krzk+dt@kernel.org \
--cc=linux-arch@vger.kernel.org \
--cc=linux-arm-msm@vger.kernel.org \
--cc=linux-doc@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=linux-remoteproc@vger.kernel.org \
--cc=ljs@kernel.org \
--cc=mathieu.poirier@linaro.org \
--cc=mgorman@suse.de \
--cc=mhocko@suse.com \
--cc=mingo@redhat.com \
--cc=nphamcs@gmail.com \
--cc=peterz@infradead.org \
--cc=pmladek@suse.com \
--cc=robh@kernel.org \
--cc=rostedt@goodmis.org \
--cc=rppt@kernel.org \
--cc=saravanak@kernel.org \
--cc=senozhatsky@chromium.org \
--cc=shikemeng@huaweicloud.com \
--cc=skhan@linuxfoundation.org \
--cc=surenb@google.com \
--cc=tglx@kernel.org \
--cc=tj@kernel.org \
--cc=vbabka@kernel.org \
--cc=vincent.guittot@linaro.org \
--cc=vschneid@redhat.com \
--cc=workflows@vger.kernel.org \
--cc=youngjun.park@lge.com \
--cc=ziy@nvidia.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox