Qualcomm Minidump is a 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
and into the table of contents.
Further, the 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>
---
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(+)
create mode 100644 drivers/soc/qcom/minidump.c
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..67ebbf09c171
--- /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 <quic_mojha@quicinc.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.43.0
Hi Eugen,
kernel test robot noticed the following build warnings:
[auto build test WARNING on rppt-memblock/fixes]
[also build test WARNING on linus/master v6.18-rc6]
[cannot apply to akpm-mm/mm-everything rppt-memblock/for-next next-20251121]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Eugen-Hristev/kernel-Introduce-meminspect/20251119-235912
base: https://git.kernel.org/pub/scm/linux/kernel/git/rppt/memblock.git fixes
patch link: https://lore.kernel.org/r/20251119154427.1033475-24-eugen.hristev%40linaro.org
patch subject: [PATCH 23/26] soc: qcom: Add minidump driver
config: nios2-randconfig-r123-20251122 (https://download.01.org/0day-ci/archive/20251122/202511221521.2OINSDPK-lkp@intel.com/config)
compiler: nios2-linux-gcc (GCC) 11.5.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251122/202511221521.2OINSDPK-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202511221521.2OINSDPK-lkp@intel.com/
sparse warnings: (new ones prefixed by >>)
>> drivers/soc/qcom/minidump.c:108:35: sparse: sparse: restricted __le32 degrades to integer
>> drivers/soc/qcom/minidump.c:154:22: sparse: sparse: incorrect type in assignment (different base types) @@ expected restricted __le32 [usertype] seq_num @@ got unsigned int enum meminspect_uid const id @@
drivers/soc/qcom/minidump.c:154:22: sparse: expected restricted __le32 [usertype] seq_num
drivers/soc/qcom/minidump.c:154:22: sparse: got unsigned int enum meminspect_uid const id
>> drivers/soc/qcom/minidump.c:184:19: sparse: sparse: unsigned value that used to be signed checked against zero?
drivers/soc/qcom/minidump.c:183:39: sparse: signed value source
vim +108 drivers/soc/qcom/minidump.c
93
94 /**
95 * qcom_md_get_region_index() - Lookup minidump region by id
96 * @md: minidump data
97 * @id: minidump region id
98 *
99 * Return: On success, it returns the internal region index, on failure,
100 * returns negative error value
101 */
102 static int qcom_md_get_region_index(struct minidump *md, int id)
103 {
104 unsigned int count = le32_to_cpu(md->toc->region_count);
105 unsigned int i;
106
107 for (i = 0; i < count; i++)
> 108 if (md->regions[i].seq_num == id)
109 return i;
110
111 return -ENOENT;
112 }
113
114 /**
115 * register_md_region() - Register a new minidump region
116 * @priv: private data
117 * @e: pointer to inspect entry
118 *
119 * Return: None
120 */
121 static void __maybe_unused register_md_region(void *priv,
122 const struct inspect_entry *e)
123 {
124 unsigned int num_region, region_cnt;
125 const char *name = "unknown";
126 struct minidump_region *mdr;
127 struct minidump *md = priv;
128
129 if (!(e->va || e->pa) || !e->size) {
130 dev_dbg(md->dev, "invalid region requested\n");
131 return;
132 }
133
134 if (e->id < ARRAY_SIZE(meminspect_id_to_md_string))
135 name = meminspect_id_to_md_string[e->id];
136
137 if (qcom_md_get_region_index(md, e->id) >= 0) {
138 dev_dbg(md->dev, "%s:%d region is already registered\n",
139 name, e->id);
140 return;
141 }
142
143 /* Check if there is a room for a new entry */
144 num_region = le32_to_cpu(md->toc->region_count);
145 if (num_region >= MAX_NUM_REGIONS) {
146 dev_dbg(md->dev, "maximum region limit %u reached\n",
147 num_region);
148 return;
149 }
150
151 region_cnt = le32_to_cpu(md->toc->region_count);
152 mdr = &md->regions[region_cnt];
153 scnprintf(mdr->name, MAX_REGION_NAME_LENGTH, "K%.8s", name);
> 154 mdr->seq_num = e->id;
155 if (e->pa)
156 mdr->address = cpu_to_le64(e->pa);
157 else if (e->va)
158 mdr->address = cpu_to_le64(__pa(e->va));
159 mdr->size = cpu_to_le64(ALIGN(e->size, 4));
160 mdr->valid = cpu_to_le32(MINIDUMP_REGION_VALID);
161 region_cnt++;
162 md->toc->region_count = cpu_to_le32(region_cnt);
163
164 dev_dbg(md->dev, "%s:%d region registered %llx:%llx\n",
165 mdr->name, mdr->seq_num, mdr->address, mdr->size);
166 }
167
168 /**
169 * unregister_md_region() - Unregister a previously registered minidump region
170 * @priv: private data
171 * @e: pointer to inspect entry
172 *
173 * Return: None
174 */
175 static void __maybe_unused unregister_md_region(void *priv,
176 const struct inspect_entry *e)
177 {
178 struct minidump_region *mdr;
179 struct minidump *md = priv;
180 unsigned int region_cnt;
181 unsigned int idx;
182
183 idx = qcom_md_get_region_index(md, e->id);
> 184 if (idx < 0) {
185 dev_dbg(md->dev, "%d region is not present\n", e->id);
186 return;
187 }
188
189 mdr = &md->regions[0];
190 region_cnt = le32_to_cpu(md->toc->region_count);
191
192 /*
193 * Left shift one position all the regions located after the
194 * region being removed, in order to fill the gap.
195 * Then, zero out the last region at the end.
196 */
197 memmove(&mdr[idx], &mdr[idx + 1], (region_cnt - idx - 1) * sizeof(*mdr));
198 memset(&mdr[region_cnt - 1], 0, sizeof(*mdr));
199 region_cnt--;
200 md->toc->region_count = cpu_to_le32(region_cnt);
201 }
202
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
Hi Eugen,
kernel test robot noticed the following build warnings:
[auto build test WARNING on rppt-memblock/fixes]
[also build test WARNING on linus/master v6.18-rc6]
[cannot apply to akpm-mm/mm-everything rppt-memblock/for-next next-20251121]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Eugen-Hristev/kernel-Introduce-meminspect/20251119-235912
base: https://git.kernel.org/pub/scm/linux/kernel/git/rppt/memblock.git fixes
patch link: https://lore.kernel.org/r/20251119154427.1033475-24-eugen.hristev%40linaro.org
patch subject: [PATCH 23/26] soc: qcom: Add minidump driver
config: nios2-randconfig-r123-20251122 (https://download.01.org/0day-ci/archive/20251122/202511221252.PPEXScZ2-lkp@intel.com/config)
compiler: nios2-linux-gcc (GCC) 11.5.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251122/202511221252.PPEXScZ2-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202511221252.PPEXScZ2-lkp@intel.com/
sparse warnings: (new ones prefixed by >>)
>> drivers/soc/qcom/minidump.c:108:35: sparse: sparse: restricted __le32 degrades to integer
>> drivers/soc/qcom/minidump.c:154:22: sparse: sparse: incorrect type in assignment (different base types) @@ expected restricted __le32 [usertype] seq_num @@ got unsigned int enum meminspect_uid const id @@
drivers/soc/qcom/minidump.c:154:22: sparse: expected restricted __le32 [usertype] seq_num
drivers/soc/qcom/minidump.c:154:22: sparse: got unsigned int enum meminspect_uid const id
>> drivers/soc/qcom/minidump.c:184:19: sparse: sparse: unsigned value that used to be signed checked against zero?
drivers/soc/qcom/minidump.c:183:39: sparse: signed value source
vim +108 drivers/soc/qcom/minidump.c
93
94 /**
95 * qcom_md_get_region_index() - Lookup minidump region by id
96 * @md: minidump data
97 * @id: minidump region id
98 *
99 * Return: On success, it returns the internal region index, on failure,
100 * returns negative error value
101 */
102 static int qcom_md_get_region_index(struct minidump *md, int id)
103 {
104 unsigned int count = le32_to_cpu(md->toc->region_count);
105 unsigned int i;
106
107 for (i = 0; i < count; i++)
> 108 if (md->regions[i].seq_num == id)
109 return i;
110
111 return -ENOENT;
112 }
113
114 /**
115 * register_md_region() - Register a new minidump region
116 * @priv: private data
117 * @e: pointer to inspect entry
118 *
119 * Return: None
120 */
121 static void __maybe_unused register_md_region(void *priv,
122 const struct inspect_entry *e)
123 {
124 unsigned int num_region, region_cnt;
125 const char *name = "unknown";
126 struct minidump_region *mdr;
127 struct minidump *md = priv;
128
129 if (!(e->va || e->pa) || !e->size) {
130 dev_dbg(md->dev, "invalid region requested\n");
131 return;
132 }
133
134 if (e->id < ARRAY_SIZE(meminspect_id_to_md_string))
135 name = meminspect_id_to_md_string[e->id];
136
137 if (qcom_md_get_region_index(md, e->id) >= 0) {
138 dev_dbg(md->dev, "%s:%d region is already registered\n",
139 name, e->id);
140 return;
141 }
142
143 /* Check if there is a room for a new entry */
144 num_region = le32_to_cpu(md->toc->region_count);
145 if (num_region >= MAX_NUM_REGIONS) {
146 dev_dbg(md->dev, "maximum region limit %u reached\n",
147 num_region);
148 return;
149 }
150
151 region_cnt = le32_to_cpu(md->toc->region_count);
152 mdr = &md->regions[region_cnt];
153 scnprintf(mdr->name, MAX_REGION_NAME_LENGTH, "K%.8s", name);
> 154 mdr->seq_num = e->id;
155 if (e->pa)
156 mdr->address = cpu_to_le64(e->pa);
157 else if (e->va)
158 mdr->address = cpu_to_le64(__pa(e->va));
159 mdr->size = cpu_to_le64(ALIGN(e->size, 4));
160 mdr->valid = cpu_to_le32(MINIDUMP_REGION_VALID);
161 region_cnt++;
162 md->toc->region_count = cpu_to_le32(region_cnt);
163
164 dev_dbg(md->dev, "%s:%d region registered %llx:%llx\n",
165 mdr->name, mdr->seq_num, mdr->address, mdr->size);
166 }
167
168 /**
169 * unregister_md_region() - Unregister a previously registered minidump region
170 * @priv: private data
171 * @e: pointer to inspect entry
172 *
173 * Return: None
174 */
175 static void __maybe_unused unregister_md_region(void *priv,
176 const struct inspect_entry *e)
177 {
178 struct minidump_region *mdr;
179 struct minidump *md = priv;
180 unsigned int region_cnt;
181 unsigned int idx;
182
183 idx = qcom_md_get_region_index(md, e->id);
> 184 if (idx < 0) {
185 dev_dbg(md->dev, "%d region is not present\n", e->id);
186 return;
187 }
188
189 mdr = &md->regions[0];
190 region_cnt = le32_to_cpu(md->toc->region_count);
191
192 /*
193 * Left shift one position all the regions located after the
194 * region being removed, in order to fill the gap.
195 * Then, zero out the last region at the end.
196 */
197 memmove(&mdr[idx], &mdr[idx + 1], (region_cnt - idx - 1) * sizeof(*mdr));
198 memset(&mdr[region_cnt - 1], 0, sizeof(*mdr));
199 region_cnt--;
200 md->toc->region_count = cpu_to_le32(region_cnt);
201 }
202
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
© 2016 - 2025 Red Hat, Inc.