diff mbox series

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

Message ID 1687955688-20809-12-git-send-email-quic_mojha@quicinc.com
State New
Headers show
Series [v4,01/21] docs: qcom: Add qualcomm minidump guide | expand

Commit Message

Mukesh Ojha June 28, 2023, 12:34 p.m. UTC
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(-)

Comments

Pavan Kondeti June 30, 2023, 4:55 a.m. UTC | #1
On Wed, Jun 28, 2023 at 06:04:38PM +0530, Mukesh Ojha wrote:
> +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;
> +}

This may be the least of your worries, but plan to fix the error
handling in this function. The probe expects this function to self clean
when returning error.

Thanks,
Pavan
Andy Shevchenko June 30, 2023, 9:25 a.m. UTC | #2
On Fri, Jun 30, 2023 at 7:55 AM Pavan Kondeti <quic_pkondeti@quicinc.com> wrote:
> On Wed, Jun 28, 2023 at 06:04:38PM +0530, Mukesh Ojha wrote:

...

> > +             scnprintf(name, sizeof(name), "KDMSG%d", i);

Also a side note: here you use the 'c' variant of sprintf(),why bother
with it if you don't even check the returned value?
diff mbox series

Patch

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;
 }