Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit abe5dd40 authored by Jitendra Sharma's avatar Jitendra Sharma
Browse files

soc: qcom: pil: Add PDR minidump support



This change add support to collect PD dump along
with minidump on subsystem ssr event.

Change-Id: Icb3c20ee2f37ecc8bdbc91d9ba1ee7f383fa075a
Signed-off-by: default avatarJitendra Sharma <shajit@codeaurora.org>
parent a5cabe93
Loading
Loading
Loading
Loading
+85 −33
Original line number Diff line number Diff line
/* Copyright (c) 2010-2017, The Linux Foundation. All rights reserved.
/* Copyright (c) 2010-2018, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -147,7 +147,8 @@ struct pil_priv {
	phys_addr_t region_end;
	void *region;
	struct pil_image_info __iomem *info;
	struct md_ssr_ss_info __iomem *minidump;
	struct md_ssr_ss_info __iomem *minidump_ss;
	struct md_ssr_ss_info __iomem *minidump_pdr;
	int minidump_id;
	int id;
	int unvoted_flag;
@@ -156,30 +157,54 @@ struct pil_priv {

static int pil_do_minidump(struct pil_desc *desc, void *ramdump_dev)
{
	struct boot_minidump_smem_region __iomem *region_info;
	struct boot_minidump_smem_region __iomem *region_info_ss;
	struct boot_minidump_smem_region __iomem *region_info_pdr;
	struct ramdump_segment *ramdump_segs, *s;
	struct pil_priv *priv = desc->priv;
	void __iomem *subsys_smem_base;
	void __iomem *offset;
	int ss_mdump_seg_cnt;
	void __iomem *subsys_smem_base_pdr;
	void __iomem *subsys_smem_base_ss;
	void __iomem *offset_ss;
	void __iomem *offset_pdr;
	int ss_mdump_seg_cnt_ss = 0, ss_mdump_seg_cnt_pdr = 0, total_segs;
	int ret, i;

	if (!ramdump_dev)
		return -ENODEV;

	memcpy(&offset, &priv->minidump, sizeof(priv->minidump));
	offset = offset + sizeof(priv->minidump->md_ss_smem_regions_baseptr);
	memcpy(&offset_ss, &priv->minidump_ss, sizeof(priv->minidump_ss));
	offset_ss = offset_ss +
		sizeof(priv->minidump_ss->md_ss_smem_regions_baseptr);
	/* There are 3 encryption keys which also need to be dumped */
	ss_mdump_seg_cnt_ss = readb_relaxed(offset_ss) +
				NUM_OF_ENCRYPTED_KEY;

	pr_debug("SMEM base to read minidump ss segments is 0x%x\n",
			__raw_readl(priv->minidump_ss));
	subsys_smem_base_ss = ioremap(__raw_readl(priv->minidump_ss),
			ss_mdump_seg_cnt_ss * sizeof(*region_info_ss));
	region_info_ss =
		(struct boot_minidump_smem_region __iomem *)subsys_smem_base_ss;

	if (priv->minidump_pdr && (__raw_readl(priv->minidump_pdr) != 0)) {
		memcpy(&offset_pdr, &priv->minidump_pdr,
				sizeof(priv->minidump_pdr));
		offset_pdr = offset_pdr +
			sizeof(priv->minidump_pdr->md_ss_smem_regions_baseptr);
		/* There are 3 encryption keys which also need to be dumped */
	ss_mdump_seg_cnt = readb_relaxed(offset) +
		ss_mdump_seg_cnt_pdr = readb_relaxed(offset_pdr) +
					NUM_OF_ENCRYPTED_KEY;

	pr_debug("SMEM base to read minidump segments is 0x%x\n",
			__raw_readl(priv->minidump));
	subsys_smem_base = ioremap(__raw_readl(priv->minidump),
				   ss_mdump_seg_cnt * sizeof(*region_info));
	region_info =
		(struct boot_minidump_smem_region __iomem *)subsys_smem_base;
	ramdump_segs = kcalloc(ss_mdump_seg_cnt,
		pr_debug("SMEM base to read minidump pdr segments is 0x%x\n",
				__raw_readl(priv->minidump_pdr));
		subsys_smem_base_pdr = ioremap(__raw_readl(priv->minidump_pdr),
			ss_mdump_seg_cnt_pdr * sizeof(*region_info_pdr));
		region_info_pdr =
			(struct boot_minidump_smem_region __iomem *)
						subsys_smem_base_pdr;
	}

	total_segs = ss_mdump_seg_cnt_ss + ss_mdump_seg_cnt_pdr;
	ramdump_segs = kcalloc(total_segs,
			       sizeof(*ramdump_segs), GFP_KERNEL);
	if (!ramdump_segs)
		return -ENOMEM;
@@ -189,25 +214,43 @@ static int pil_do_minidump(struct pil_desc *desc, void *ramdump_dev)
			(priv->region_end - priv->region_start));

	s = ramdump_segs;
	for (i = 0; i < ss_mdump_seg_cnt; i++) {
		memcpy(&offset, &region_info, sizeof(region_info));
		memcpy(&s->name, &region_info, sizeof(region_info));
		offset = offset + sizeof(region_info->region_name);
		s->address = __raw_readl(offset);
		offset = offset + sizeof(region_info->region_base_address);
		s->size = __raw_readl(offset);
	for (i = 0; i < ss_mdump_seg_cnt_ss; i++) {
		memcpy(&offset_ss, &region_info_ss, sizeof(region_info_ss));
		memcpy(&s->name, &region_info_ss, sizeof(region_info_ss));
		offset_ss = offset_ss + sizeof(region_info_ss->region_name);
		s->address = __raw_readl(offset_ss);
		offset_ss = offset_ss +
				sizeof(region_info_ss->region_base_address);
		s->size = __raw_readl(offset_ss);
		pr_debug("Dumping segment %s with address %pK and size 0x%x\n",
				s->name, (void *)s->address,
				(unsigned int)s->size);
		s++;
		region_info++;
		region_info_ss++;
	}
	ret = do_minidump(ramdump_dev, ramdump_segs, ss_mdump_seg_cnt);

	for (i = 0; i < ss_mdump_seg_cnt_pdr; i++) {
		memcpy(&offset_pdr, &region_info_pdr, sizeof(region_info_pdr));
		memcpy(&s->name, &region_info_pdr, sizeof(region_info_pdr));
		offset_pdr = offset_pdr + sizeof(region_info_pdr->region_name);
		s->address = __raw_readl(offset_pdr);
		offset_pdr = offset_pdr +
			sizeof(region_info_pdr->region_base_address);
		s->size = __raw_readl(offset_pdr);
		pr_debug("Dumping segment %s with address %pK and size 0x%x\n",
				s->name, (void *)s->address,
				(unsigned int)s->size);
		s++;
		region_info_pdr++;
	}

	ret = do_minidump(ramdump_dev, ramdump_segs, total_segs);
	kfree(ramdump_segs);
	if (ret)
		pil_err(desc, "%s: Ramdump collection failed for subsys %s rc:%d\n",
			__func__, desc->name, ret);
	writeb_relaxed(1, &priv->minidump->md_ss_ssr_cause);
	writeb_relaxed(1, &priv->minidump_ss->md_ss_ssr_cause);
	writeb_relaxed(1, &priv->minidump_pdr->md_ss_ssr_cause);

	if (desc->subsys_vmid > 0)
		ret = pil_assign_mem_to_subsys(desc, priv->region_start,
@@ -232,13 +275,13 @@ int pil_do_ramdump(struct pil_desc *desc,
	struct ramdump_segment *ramdump_segs, *s;
	void __iomem *offset;

	memcpy(&offset, &priv->minidump, sizeof(priv->minidump));
	memcpy(&offset, &priv->minidump_ss, sizeof(priv->minidump_ss));
	/*
	 * Collect minidump if smem base is initialized,
	 * ssr cause is 0. No need to check encryption status
	 */
	if (priv->minidump
	&& (__raw_readl(priv->minidump) != 0)
	if (priv->minidump_ss
	&& (__raw_readl(priv->minidump_ss) != 0)
	&& (readb_relaxed(offset + sizeof(u32) + 2 * sizeof(u8)) == 0)) {
		pr_debug("Dumping Minidump for %s\n", desc->name);
		return pil_do_minidump(desc, minidump_dev);
@@ -1113,7 +1156,7 @@ int pil_desc_init(struct pil_desc *desc)
{
	struct pil_priv *priv;
	void __iomem *addr;
	int ret, ss_imem_offset_mdump;
	int ret, ss_imem_offset_mdump_ss, ss_imem_offset_mdump_pdr;
	char buf[sizeof(priv->info->name)];
	struct device_node *ofnode = desc->dev->of_node;

@@ -1142,16 +1185,25 @@ int pil_desc_init(struct pil_desc *desc)
		&priv->minidump_id))
		pr_debug("minidump-id not found for %s\n", desc->name);
	else {
		ss_imem_offset_mdump =
		ss_imem_offset_mdump_ss =
			sizeof(struct md_ssr_ss_info) * priv->minidump_id;
		ss_imem_offset_mdump_pdr =
			sizeof(struct md_ssr_ss_info) * (priv->minidump_id + 1);
		if (pil_minidump_base) {
			/* Add 0x4 to get start of struct md_ssr_ss_info base
			 * from struct md_ssr_toc for any subsystem,
			 * struct md_ssr_ss_info is actually the pointer
			 * of ToC in smem for any subsystem.
			 */
			addr = pil_minidump_base + ss_imem_offset_mdump + 0x4;
			priv->minidump = (struct md_ssr_ss_info __iomem *)addr;
			addr = pil_minidump_base +
				ss_imem_offset_mdump_ss + 0x4;
			priv->minidump_ss =
				(struct md_ssr_ss_info __iomem *)addr;

			addr = pil_minidump_base +
				ss_imem_offset_mdump_pdr + 0x4;
			priv->minidump_pdr =
				(struct md_ssr_ss_info __iomem *)addr;
		}
	}