[PATCH v4 03/21] soc: qcom: Add qcom_minidump_smem module

Mukesh Ojha
2023-06-28T12:38:05Z

Add qcom_minidump_smem module in a preparation to remove smem
based minidump specific code from driver/remoteproc/qcom_common.c
and provide needed exported API, this abstract minidump specific
data layout from qualcomm's remoteproc driver.

Signed-off-by: Mukesh Ojha <quic_mojha@quicinc.com>
---
drivers/soc/qcom/Kconfig | 8 ++
drivers/soc/qcom/qcom_minidump_smem.c | 147 ++++++++++++++++++++++++++++++++++
include/soc/qcom/qcom_minidump.h | 24 ++++++
3 files changed, 179 insertions(+)
create mode 100644 drivers/soc/qcom/qcom_minidump_smem.c
create mode 100644 include/soc/qcom/qcom_minidump.h

diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
index a491718f8064..982310b5a1cb 100644
--- a/drivers/soc/qcom/Kconfig
+++ b/drivers/soc/qcom/Kconfig
@@ -279,4 +279,12 @@ config QCOM_INLINE_CRYPTO_ENGINE
tristate
select QCOM_SCM

+config QCOM_MINIDUMP_SMEM
+ tristate "QCOM Minidump SMEM (as backend) Support"
+ depends on ARCH_QCOM
+ depends on QCOM_SMEM
+ help
+ Enablement of core minidump feature is controlled from boot firmware
+ side, and this config allow linux to query minidump segments associated
+ with the remote processor and check its validity.
endmenu
diff --git a/drivers/soc/qcom/qcom_minidump_smem.c b/drivers/soc/qcom/qcom_minidump_smem.c
new file mode 100644
index 000000000000..b588833ea26e
--- /dev/null
+++ b/drivers/soc/qcom/qcom_minidump_smem.c
@@ -0,0 +1,147 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/soc/qcom/smem.h>
+#include <soc/qcom/qcom_minidump.h>
+
+#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_ENABLED ('E' << 24 | 'N' << 16 | 'B' << 8 | 'L' << 0)
+
+/**
+ * struct minidump_region - Minidump region
+ * @name : Name of the region to be dumped
+ * @seq_num: : Use to differentiate regions with same name.
+ * @valid : This entry to be dumped (if set to 1)
+ * @address : Physical address of region to be dumped
+ * @size : Size of the region
+ */
+struct minidump_region {
+ char name[MAX_REGION_NAME_LENGTH];
+ __le32 seq_num;
+ __le32 valid;
+ __le64 address;
+ __le64 size;
+};
+
+/**
+ * struct minidump_subsystem - Subsystem's SMEM Table of content
+ * @status : Subsystem toc init status
+ * @enabled : if set to 1, this region would be copied during coredump
+ * @encryption_status: Encryption status for this subsystem
+ * @encryption_required : Decides to encrypt the subsystem regions or not
+ * @region_count : Number of regions added in this subsystem toc
+ * @regions_baseptr : regions base pointer of the subsystem
+ */
+struct minidump_subsystem {
+ __le32 status;
+ __le32 enabled;
+ __le32 encryption_status;
+ __le32 encryption_required;
+ __le32 region_count;
+ __le64 regions_baseptr;
+};
+
+/**
+ * struct minidump_global_toc - Global Table of Content
+ * @status : Global Minidump init status
+ * @md_revision : Minidump revision
+ * @enabled : Minidump enable status
+ * @subsystems : Array of subsystems toc
+ */
+struct minidump_global_toc {
+ __le32 status;
+ __le32 md_revision;
+ __le32 enabled;
+ struct minidump_subsystem subsystems[MAX_NUM_OF_SS];
+};
+
+/**
+ * qcom_ss_md_mapped_base() - For getting subsystem iomapped base segment address
+ * for given minidump index.
+ *
+ * @minidump_id: Subsystem minidump index.
+ * @seg_cnt: Segment count for a given minidump index
+ *
+ * Return: On success, it returns iomapped base segment address, otherwise NULL on error.
+ */
+void *qcom_ss_md_mapped_base(unsigned int minidump_id, int *seg_cnt)
+{
+ struct minidump_global_toc *toc;
+ struct minidump_subsystem *subsystem;
+
+ /*
+ * Get global minidump ToC and check if global table
+ * pointer exists and init is set.
+ */
+ toc = qcom_smem_get(QCOM_SMEM_HOST_ANY, SBL_MINIDUMP_SMEM_ID, NULL);
+ if (IS_ERR(toc) || !toc->status)
+ return NULL;
+
+ /* Get subsystem table of contents using the minidump id */
+ subsystem = &toc->subsystems[minidump_id];
+
+ /**
+ * Collect minidump if SS ToC is valid and segment table
+ * is initialized in memory and encryption status is set.
+ */
+ if (subsystem->regions_baseptr == 0 ||
+ le32_to_cpu(subsystem->status) != 1 ||
+ le32_to_cpu(subsystem->enabled) != MINIDUMP_SS_ENABLED ||
+ le32_to_cpu(subsystem->encryption_status) != MINIDUMP_SS_ENCR_DONE)
+ return NULL;
+
+ *seg_cnt = le32_to_cpu(subsystem->region_count);
+
+ return ioremap((unsigned long)le64_to_cpu(subsystem->regions_baseptr),
+ *seg_cnt * sizeof(struct minidump_region));
+}
+EXPORT_SYMBOL_GPL(qcom_ss_md_mapped_base);
+
+/**
+ * qcom_ss_valid_segment_info() - Checks segment sanity and gets it's details
+ *
+ * @ptr: Segment IO-mapped base address.
+ * @i: Segment index.
+ * @name: Segment name.
+ * @da: Segment physical address.
+ * @size: Segment size.
+ *
+ * Return: It returns 0 on success and 1 if the segment is invalid and negative
+ * value on error.
+ */
+int qcom_ss_valid_segment_info(void *ptr, int i, char **name, dma_addr_t *da, size_t *size)
+{
+ struct minidump_region __iomem *tmp;
+ struct minidump_region region;
+
+ if (!ptr)
+ return -EINVAL;
+
+ tmp = ptr;
+ memcpy_fromio(&region, tmp + i, sizeof(region));
+
+ /* If it is not valid region, skip it */
+ if (le32_to_cpu(region.valid) != MINIDUMP_REGION_VALID)
+ return 1;
+
+ *name = kstrndup(region.name, MAX_REGION_NAME_LENGTH - 1, GFP_KERNEL);
+ if (!*name)
+ return -ENOMEM;
+
+ *da = le64_to_cpu(region.address);
+ *size = le64_to_cpu(region.size);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(qcom_ss_valid_segment_info);
+
+MODULE_DESCRIPTION("Qualcomm Minidump SMEM as backend driver");
+MODULE_LICENSE("GPL");
diff --git a/include/soc/qcom/qcom_minidump.h b/include/soc/qcom/qcom_minidump.h
new file mode 100644
index 000000000000..d7747c27fd45
--- /dev/null
+++ b/include/soc/qcom/qcom_minidump.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#ifndef _QCOM_MINIDUMP_H_
+#define _QCOM_MINIDUMP_H_
+
+#if IS_ENABLED(CONFIG_QCOM_MINIDUMP_SMEM)
+void *qcom_ss_md_mapped_base(unsigned int minidump_id, int *seg_cnt);
+int qcom_ss_valid_segment_info(void *ptr, int i, char **name,
+ dma_addr_t *da, size_t *size);
+#else
+static inline void *qcom_ss_md_mapped_base(unsigned int minidump_id, int *seg_cnt)
+{
+ return NULL;
+}
+static inline int qcom_ss_valid_segment_info(void *ptr, int i, char **name,
+ dma_addr_t *da, size_t *size)
+{
+ return -EINVAL;
+}
+#endif /* CONFIG_QCOM_MINIDUMP_SMEM */
+#endif /* _QCOM_MINIDUMP_H_ */
--
2.7.4