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

Commit 59544880 authored by Avaneesh Kumar Dwivedi's avatar Avaneesh Kumar Dwivedi Committed by Isaac J. Manjarres
Browse files

soc: qcom: Add SSR minidump provision for subsystem ramdump



Minidump is concise and bare minimum dump to enable technology
teams to debug most of subsystem issues. This change adds required
driver code changes to provide support of subsystem minidump.

Increase PIL timeout to give MBA more time for encryption
and decryption for modem segments.

Change-Id: I1d04a9306ce507bc610777bc476197f26c1e18ac
Signed-off-by: default avatarAvaneesh Kumar Dwivedi <akdwived@codeaurora.org>
[isaacm@codeaurora.org: Resolve trivial merge conflicts]
Signed-off-by: default avatarIsaac J. Manjarres <isaacm@codeaurora.org>
parent 7fae8e75
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -73,6 +73,11 @@ USB Diag Cookies:
Memory region used to store USB PID and serial numbers to be used by
bootloader in download mode.

SSR Minidump Offset
-------------------
-Compatible: "qcom,msm-imem-minidump"
-reg: start address and size of ssr imem region

Required properties:
-compatible: "qcom,msm-imem-diag-dload"
-reg: start address and size of USB Diag download mode region in imem
@@ -121,4 +126,9 @@ Example:
			compatible = "qcom,msm-imem-emergency_download_mode";
			reg = <0xfe0 12>;
		};

		ss_mdump@b88 {
			compatible = "qcom,msm-imem-minidump";
			reg = <0xb88 28>;
		};
	};
+108 −1
Original line number Diff line number Diff line
@@ -56,7 +56,10 @@

#define PIL_NUM_DESC		10
#define MAX_LEN 96
#define NUM_OF_ENCRYPTED_KEY	3

static void __iomem *pil_info_base;
static void __iomem *pil_minidump_base;

/**
 * proxy_timeout - Override for proxy vote timeouts
@@ -78,6 +81,18 @@ struct pil_mdt {
	struct elf32_phdr phdr[];
};

/**
 * struct boot_minidump_smem_region - Representation of SMEM TOC
 * @region_name: Name of modem segment to be dumped
 * @region_base_address: Where segment start from
 * @region_size: Size of segment to be dumped
 */
struct boot_minidump_smem_region {
	char region_name[16];
	u64 region_base_address;
	u64 region_size;
};

/**
 * struct pil_seg - memory map representing one segment
 * @next: points to next seg mentor NULL if last segment
@@ -132,11 +147,67 @@ struct pil_priv {
	phys_addr_t region_end;
	void *region;
	struct pil_image_info __iomem *info;
	struct md_ssr_ss_info __iomem *minidump;
	int minidump_id;
	int id;
	int unvoted_flag;
	size_t region_size;
};

static int pil_do_minidump(struct pil_desc *desc, void *ramdump_dev)
{
	struct boot_minidump_smem_region __iomem *region_info;
	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;
	int ret, i;

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

	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,
			       sizeof(*ramdump_segs), GFP_KERNEL);
	if (!ramdump_segs)
		return -ENOMEM;

	if (desc->subsys_vmid > 0)
		ret = pil_assign_mem_to_linux(desc, priv->region_start,
			(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);
		s++;
		region_info++;
	}
	ret = do_minidump(ramdump_dev, ramdump_segs, ss_mdump_seg_cnt);
	kfree(ramdump_segs);
	if (ret)
		pil_err(desc, "%s: Ramdump collection failed for subsys %s rc:%d\n",
			__func__, desc->name, ret);
	writel_relaxed(0, &priv->minidump->md_ss_smem_regions_baseptr);
	writeb_relaxed(1, &priv->minidump->md_ss_ssr_cause);

	if (desc->subsys_vmid > 0)
		ret = pil_assign_mem_to_subsys(desc, priv->region_start,
			(priv->region_end - priv->region_start));
	return ret;
}

/**
 * pil_do_ramdump() - Ramdump an image
 * @desc: descriptor from pil_desc_init()
@@ -152,6 +223,9 @@ int pil_do_ramdump(struct pil_desc *desc, void *ramdump_dev)
	int count = 0, ret;
	struct ramdump_segment *ramdump_segs, *s;

	if (priv->minidump && (__raw_readl(priv->minidump) > 0))
		return pil_do_minidump(desc, ramdump_dev);

	list_for_each_entry(seg, &priv->segs, list)
		count++;

@@ -1041,9 +1115,10 @@ bool is_timeout_disabled(void)
int pil_desc_init(struct pil_desc *desc)
{
	struct pil_priv *priv;
	int ret;
	void __iomem *addr;
	int ret, ss_imem_offset_mdump;
	char buf[sizeof(priv->info->name)];
	struct device_node *ofnode = desc->dev->of_node;

	if (WARN(desc->ops->proxy_unvote && !desc->ops->proxy_vote,
				"Invalid proxy voting. Ignoring\n"))
@@ -1066,6 +1141,22 @@ int pil_desc_init(struct pil_desc *desc)
		strlcpy(buf, desc->name, sizeof(buf));
		__iowrite32_copy(priv->info->name, buf, sizeof(buf) / 4);
	}
	if (of_property_read_u32(ofnode, "qcom,minidump-id",
		&priv->minidump_id))
		pr_debug("minidump-id not found for %s\n", desc->name);
	else {
		ss_imem_offset_mdump =
			sizeof(struct md_ssr_ss_info) * priv->minidump_id;
		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;
		}
	}

	ret = pil_parse_devicetree(desc);
	if (ret)
@@ -1174,6 +1265,20 @@ static int __init msm_pil_init(void)
	for (i = 0; i < resource_size(&res)/sizeof(u32); i++)
		writel_relaxed(0, pil_info_base + (i * sizeof(u32)));

	np = of_find_compatible_node(NULL, NULL, "qcom,msm-imem-minidump");
	if (!np) {
		pr_warn("pil: failed to find qcom,msm-imem-minidump node\n");
		goto out;
	} else {
		pil_minidump_base = of_iomap(np, 0);
		if (!pil_minidump_base) {
			pr_err("unable to map pil minidump imem offset\n");
			goto out;
		}
	}
	for (i = 0; i < sizeof(struct md_ssr_toc)/sizeof(u32); i++)
		writel_relaxed(0, pil_minidump_base + (i * sizeof(u32)));
	writel_relaxed(1, pil_minidump_base);
out:
	return register_pm_notifier(&pil_pm_notifier);
}
@@ -1184,6 +1289,8 @@ static void __exit msm_pil_exit(void)
	unregister_pm_notifier(&pil_pm_notifier);
	if (pil_info_base)
		iounmap(pil_info_base);
	if (pil_minidump_base)
		iounmap(pil_minidump_base);
}
module_exit(msm_pil_exit);

+28 −0
Original line number Diff line number Diff line
@@ -77,6 +77,34 @@ struct pil_image_info {
	__le32 size;
} __attribute__((__packed__));

#define MAX_NUM_OF_SS 3

/**
 * struct md_ssr_ss_info - Info in imem about smem ToC
 * @md_ss_smem_regions_baseptr: Start physical address of SMEM TOC
 * @md_ss_num_of_regions: number of segments that need to be dumped
 * @md_ss_encryption_status: status of encryption of segments
 * @md_ss_ssr_cause: ssr cause enum
 */
struct md_ssr_ss_info {
	u32 md_ss_smem_regions_baseptr;
	u8 md_ss_num_of_regions;
	u8 md_ss_encryption_status;
	u8 md_ss_ssr_cause;
	u8 reserved;
};

/**
 * struct md_ssr_toc - Wrapper of struct md_ssr_ss_info
 * @md_ssr_toc_init: flag to indicate to MSS SW about imem init done
 * @md_ssr_ss: Instance of struct md_ssr_ss_info for a subsystem
 */
struct md_ssr_toc /* Shared IMEM ToC struct */
{
	u32 md_ssr_toc_init;
	struct md_ssr_ss_info	md_ssr_ss[MAX_NUM_OF_SS];
};

/**
 * struct pil_reset_ops - PIL operations
 * @init_image: prepare an image for authentication
+2 −0
Original line number Diff line number Diff line
@@ -29,6 +29,8 @@ extern int do_ramdump(void *handle, struct ramdump_segment *segments,
		int nsegments);
extern int do_elf_ramdump(void *handle, struct ramdump_segment *segments,
		int nsegments);
extern int do_minidump(void *handle, struct ramdump_segment *segments,
		       int nsegments);

#else
static inline void *create_ramdump_device(const char *dev_name,