[PATCH v4 11/21] soc: qcom: Register pstore frontend region with minidump

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

Since qcom_pstore_minidump driver creates platform device for
qualcomm devices, so it knows the physical addresses of the
frontend region now. Let's register the regions with
qcom_minidump driver.

Signed-off-by: Mukesh Ojha <quic_mojha@quicinc.com>
---
drivers/soc/qcom/qcom_pstore_minidump.c | 131 +++++++++++++++++++++++++++++++-
1 file changed, 128 insertions(+), 3 deletions(-)

diff --git a/drivers/soc/qcom/qcom_pstore_minidump.c b/drivers/soc/qcom/qcom_pstore_minidump.c
index b07cd10340df..f17384dd2d72 100644
--- a/drivers/soc/qcom/qcom_pstore_minidump.c
+++ b/drivers/soc/qcom/qcom_pstore_minidump.c
@@ -9,12 +9,120 @@
#include <linux/of_reserved_mem.h>
#include <linux/platform_device.h>
#include <linux/pstore_ram.h>
+#include <soc/qcom/qcom_minidump.h>

struct qcom_ramoops_dd {
struct ramoops_platform_data qcom_ramoops_pdata;
struct platform_device *ramoops_pdev;
+ struct device *dev;
+ struct qcom_minidump_region **dmesg_region;
+ struct qcom_minidump_region *console_region;
+ struct qcom_minidump_region *pmsg_region;
+ struct qcom_minidump_region **ftrace_region;
+ unsigned int max_dump_cnt;
+ unsigned int max_ftrace_cnt;
};

+static int qcom_ramoops_md_region_register(struct device *dev, struct qcom_minidump_region **zone,
+ const char *name, phys_addr_t phys_addr,
+ unsigned long size)
+{
+ struct qcom_minidump_region *md_region;
+ int ret;
+
+ if (!size)
+ return 0;
+
+ md_region = devm_kzalloc(dev, sizeof(*md_region), GFP_KERNEL);
+ if (!md_region)
+ return -ENOMEM;
+
+ strscpy(md_region->name, name, sizeof(md_region->name));
+ md_region->phys_addr = phys_addr;
+ md_region->virt_addr = phys_to_virt(phys_addr);
+ md_region->size = size;
+ *zone = md_region;
+ ret = qcom_minidump_region_register(md_region);
+ if (ret)
+ dev_err(dev, "failed to add %s in minidump: err: %d\n", name, ret);
+
+ return ret;
+}
+
+static int qcom_ramoops_minidump_register(struct qcom_ramoops_dd *qcom_rdd)
+{
+ struct ramoops_platform_data *pdata = &qcom_rdd->qcom_ramoops_pdata;
+ char name[MAX_NAME_LENGTH];
+ size_t zone_sz;
+ phys_addr_t phys_addr;
+ int ret = 0;
+ int i;
+
+ phys_addr = pdata->mem_address;
+ for (i = 0; i < qcom_rdd->max_dump_cnt; i++) {
+ scnprintf(name, sizeof(name), "KDMSG%d", i);
+ ret = qcom_ramoops_md_region_register(qcom_rdd->dev,
+ &qcom_rdd->dmesg_region[i], name, phys_addr,
+ pdata->record_size);
+ if (ret)
+ return ret;
+
+ phys_addr += pdata->record_size;
+ }
+
+ ret = qcom_ramoops_md_region_register(qcom_rdd->dev,
+ &qcom_rdd->console_region, "KCONSOLE", phys_addr,
+ pdata->console_size);
+ if (ret)
+ return ret;
+
+ phys_addr += pdata->console_size;
+
+ ret = qcom_ramoops_md_region_register(qcom_rdd->dev,
+ &qcom_rdd->pmsg_region, "KPMSG", phys_addr,
+ pdata->pmsg_size);
+ if (ret)
+ return ret;
+
+ phys_addr += pdata->pmsg_size;
+
+ zone_sz = pdata->ftrace_size / qcom_rdd->max_ftrace_cnt;
+ for (i = 0; i < qcom_rdd->max_ftrace_cnt; i++) {
+ ret = qcom_ramoops_md_region_register(qcom_rdd->dev,
+ &qcom_rdd->ftrace_region[i], "KFTRACE", phys_addr,
+ zone_sz);
+ if (ret)
+ return ret;
+
+ phys_addr += zone_sz;
+ }
+
+ return ret;
+}
+
+static void qcom_ramoops_minidump_unregister(struct qcom_ramoops_dd *qcom_rdd)
+{
+ struct ramoops_platform_data *pdata;
+ int i;
+
+ pdata = &qcom_rdd->qcom_ramoops_pdata;
+ if (pdata->record_size) {
+ for (i = 0; i < qcom_rdd->max_dump_cnt; i++)
+ qcom_minidump_region_unregister(qcom_rdd->dmesg_region[i]);
+ }
+
+ if (pdata->console_size)
+ qcom_minidump_region_unregister(qcom_rdd->console_region);
+
+ if (pdata->pmsg_size)
+ qcom_minidump_region_unregister(qcom_rdd->pmsg_region);
+
+ if (pdata->ftrace_size) {
+ for (i = 0; i < qcom_rdd->max_ftrace_cnt; i++)
+ qcom_minidump_region_unregister(qcom_rdd->ftrace_region[i]);
+ }
+}
+
static int qcom_ramoops_probe(struct platform_device *pdev)
{
struct device_node *of_node = pdev->dev.of_node;
@@ -22,6 +130,7 @@ static int qcom_ramoops_probe(struct platform_device *pdev)
struct ramoops_platform_data *pdata;
struct reserved_mem *rmem;
struct device_node *node;
+ size_t dump_mem_sz;
long ret;

node = of_parse_phandle(of_node, "memory-region", 0);
@@ -39,27 +148,43 @@ static int qcom_ramoops_probe(struct platform_device *pdev)
if (!qcom_rdd)
return -ENOMEM;

+ qcom_rdd->dev = &pdev->dev;
pdata = &qcom_rdd->qcom_ramoops_pdata;
pdata->mem_size = rmem->size;
pdata->mem_address = rmem->base;
- ramoops_parse_dt(pdev, pdata);
-
+ ret = ramoops_parse_dt(pdev, pdata);
+ if (ret < 0)
+ return ret;
+
+ dump_mem_sz = pdata->mem_size - pdata->console_size - pdata->ftrace_size
+ - pdata->pmsg_size;
+ if (!dump_mem_sz || !pdata->record_size)
+ qcom_rdd->max_dump_cnt = 0;
+ else
+ qcom_rdd->max_dump_cnt = dump_mem_sz / pdata->record_size;
+
+ qcom_rdd->max_ftrace_cnt = (pdata->flags & RAMOOPS_FLAG_FTRACE_PER_CPU)
+ ? nr_cpu_ids
+ : 1;
qcom_rdd->ramoops_pdev = platform_device_register_data(NULL, "ramoops", -1,
pdata, sizeof(*pdata));
if (IS_ERR(qcom_rdd->ramoops_pdev)) {
ret = PTR_ERR(qcom_rdd->ramoops_pdev);
dev_err(&pdev->dev, "could not create platform device: %ld\n", ret);
qcom_rdd->ramoops_pdev = NULL;
+ return ret;
}
+
platform_set_drvdata(pdev, qcom_rdd);

- return ret;
+ return qcom_ramoops_minidump_register(qcom_rdd);
}

static void qcom_ramoops_remove(struct platform_device *pdev)
{
struct qcom_ramoops_dd *qcom_rdd = platform_get_drvdata(pdev);

+ qcom_ramoops_minidump_unregister(qcom_rdd);
platform_device_unregister(qcom_rdd->ramoops_pdev);
qcom_rdd->ramoops_pdev = NULL;
}
--
2.7.4