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

Commit 8d183fc0 authored by qctecmdr Service's avatar qctecmdr Service Committed by Gerrit - the friendly Code Review server
Browse files

Merge "soc: qcom: Create additional ramdump device node for SSR minidump"

parents 3c086986 d7f08923
Loading
Loading
Loading
Loading
+85 −69
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@
#include <soc/qcom/ramdump.h>
#include <soc/qcom/subsystem_restart.h>
#include <soc/qcom/secure_buffer.h>
#include <linux/soc/qcom/smem.h>

#include <linux/uaccess.h>
#include <asm/setup.h>
@@ -59,7 +60,7 @@
#define NUM_OF_ENCRYPTED_KEY	3

static void __iomem *pil_info_base;
static void __iomem *pil_minidump_base;
static struct md_global_toc *g_md_toc;

/**
 * proxy_timeout - Override for proxy vote timeouts
@@ -81,18 +82,6 @@ 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
@@ -147,8 +136,6 @@ 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;
@@ -156,24 +143,27 @@ struct pil_priv {

static int pil_do_minidump(struct pil_desc *desc, void *ramdump_dev)
{
	struct boot_minidump_smem_region __iomem *region_info;
	struct md_ss_region __iomem *region_info;
	struct ramdump_segment *ramdump_segs, *s;
	struct pil_priv *priv = desc->priv;
	void __iomem *subsys_smem_base;
	void __iomem *subsys_segtable_base;
	u64 ss_region_ptr = 0;
	void __iomem *offset;
	int ss_mdump_seg_cnt;
	int ss_valid_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;
	ss_region_ptr = desc->minidump->md_ss_smem_regions_baseptr;
	if (!ramdump_dev)
		return -ENODEV;
	ss_mdump_seg_cnt = desc->minidump->ss_region_count;
	subsys_segtable_base =
		ioremap((unsigned long)ss_region_ptr,
		ss_mdump_seg_cnt * sizeof(struct md_ss_region));
	region_info = (struct md_ss_region __iomem *)subsys_segtable_base;
	if (!region_info)
		return -EINVAL;
	pr_debug("Segments in minidump 0x%x\n", ss_mdump_seg_cnt);
	ramdump_segs = kcalloc(ss_mdump_seg_cnt,
			       sizeof(*ramdump_segs), GFP_KERNEL);
	if (!ramdump_segs)
@@ -184,23 +174,30 @@ static int pil_do_minidump(struct pil_desc *desc, void *ramdump_dev)
			(priv->region_end - priv->region_start));

	s = ramdump_segs;
	ss_valid_seg_cnt = ss_mdump_seg_cnt;
	for (i = 0; i < ss_mdump_seg_cnt; i++) {
		memcpy(&offset, &region_info, sizeof(region_info));
		offset = offset + sizeof(region_info->name) +
				sizeof(region_info->seq_num);
		if (__raw_readl(offset) == MD_REGION_VALID) {
			memcpy(&s->name, &region_info, sizeof(region_info));
		offset = offset + sizeof(region_info->region_name);
			offset = offset + sizeof(region_info->md_valid);
			s->address = __raw_readl(offset);
		offset = offset + sizeof(region_info->region_base_address);
			offset = offset +
				sizeof(region_info->region_base_address);
			s->size = __raw_readl(offset);
			pr_debug("Minidump : Dumping segment %s with address 0x%lx and size 0x%x\n",
				s->name, s->address, (unsigned int)s->size);
		} else
			ss_valid_seg_cnt--;
		s++;
		region_info++;
	}
	ret = do_minidump(ramdump_dev, ramdump_segs, ss_mdump_seg_cnt);
	ret = do_minidump(ramdump_dev, ramdump_segs, ss_valid_seg_cnt);
	kfree(ramdump_segs);
	if (ret)
		pil_err(desc, "%s: Ramdump collection failed for subsys %s rc:%d\n",
		pil_err(desc, "%s: Minidump 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,
@@ -216,16 +213,45 @@ static int pil_do_minidump(struct pil_desc *desc, void *ramdump_dev)
 * Calls the ramdump API with a list of segments generated from the addresses
 * that the descriptor corresponds to.
 */
int pil_do_ramdump(struct pil_desc *desc, void *ramdump_dev)
int pil_do_ramdump(struct pil_desc *desc,
		   void *ramdump_dev, void *minidump_dev)
{
	struct ramdump_segment *ramdump_segs, *s;
	struct pil_priv *priv = desc->priv;
	struct pil_seg *seg;
	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);

	if (desc->minidump) {
		pr_debug("Minidump : md_ss_toc->md_ss_toc_init is 0x%x\n",
			(unsigned int)desc->minidump->md_ss_toc_init);
		pr_debug("Minidump : md_ss_toc->md_ss_enable_status is 0x%x\n",
			(unsigned int)desc->minidump->md_ss_enable_status);
		pr_debug("Minidump : md_ss_toc->encryption_status is 0x%x\n",
			(unsigned int)desc->minidump->encryption_status);
		pr_debug("Minidump : md_ss_toc->ss_region_count is 0x%x\n",
			(unsigned int)desc->minidump->ss_region_count);
		pr_debug("Minidump : md_ss_toc->md_ss_smem_regions_baseptr is 0x%x\n",
			(unsigned int)
			desc->minidump->md_ss_smem_regions_baseptr);
		/**
		 * Collect minidump if SS ToC is valid and segment table
		 * is initialized in memory and encryption status is set.
		 */
		if ((desc->minidump->md_ss_smem_regions_baseptr != 0) &&
			(desc->minidump->md_ss_toc_init == true) &&
			(desc->minidump->md_ss_enable_status ==
				MD_SS_ENABLED)) {
			if (desc->minidump->encryption_status ==
				MD_SS_ENCR_DONE) {
				pr_debug("Dumping Minidump for %s\n",
					desc->name);
				return pil_do_minidump(desc, minidump_dev);
			}
			pr_debug("Minidump aborted for %s\n", desc->name);
			return -EINVAL;
		}
	}
	pr_debug("Continuing with full SSR dump for %s\n", desc->name);
	list_for_each_entry(seg, &priv->segs, list)
		count++;

@@ -1116,7 +1142,8 @@ int pil_desc_init(struct pil_desc *desc)
{
	struct pil_priv *priv;
	void __iomem *addr;
	int ret, ss_imem_offset_mdump;
	void *ss_toc_addr;
	int ret;
	char buf[sizeof(priv->info->name)];
	struct device_node *ofnode = desc->dev->of_node;

@@ -1142,19 +1169,15 @@ int pil_desc_init(struct pil_desc *desc)
		__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);
		&desc->minidump_id))
		pr_err("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;
		if (g_md_toc && g_md_toc->md_toc_init == true) {
			ss_toc_addr = &g_md_toc->md_ss_toc[desc->minidump_id];
			pr_debug("Minidump : ss_toc_addr is %pa and desc->minidump_id is %d\n",
				&ss_toc_addr, desc->minidump_id);
			memcpy(&desc->minidump, &ss_toc_addr,
			       sizeof(ss_toc_addr));
		}
	}

@@ -1243,6 +1266,7 @@ static int __init msm_pil_init(void)
	struct device_node *np;
	struct resource res;
	int i;
	size_t size;

	np = of_find_compatible_node(NULL, NULL, "qcom,msm-imem-pil");
	if (!np) {
@@ -1265,20 +1289,14 @@ 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;
		}
	/* Get Global minidump ToC*/
	g_md_toc = qcom_smem_get(QCOM_SMEM_HOST_ANY, SBL_MINIDUMP_SMEM_ID,
				 &size);
	pr_debug("Minidump: g_md_toc is %pa\n", &g_md_toc);
	if (PTR_ERR(g_md_toc) == -EPROBE_DEFER) {
		pr_err("SMEM is not initialized.\n");
		return -EPROBE_DEFER;
	}
	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);
}
@@ -1289,8 +1307,6 @@ 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);

+8 −31
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
@@ -14,6 +14,7 @@

#include <linux/mailbox_client.h>
#include <linux/mailbox/qmp.h>
#include "minidump_private.h"

struct device;
struct module;
@@ -63,6 +64,8 @@ struct pil_desc {
	bool signal_aop;
	struct mbox_client cl;
	struct mbox_chan *mbox;
	struct md_ss_toc *minidump;
	int minidump_id;
};

/**
@@ -77,34 +80,6 @@ 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
@@ -137,7 +112,8 @@ extern void pil_shutdown(struct pil_desc *desc);
extern void pil_free_memory(struct pil_desc *desc);
extern void pil_desc_release(struct pil_desc *desc);
extern phys_addr_t pil_get_entry_addr(struct pil_desc *desc);
extern int pil_do_ramdump(struct pil_desc *desc, void *ramdump_dev);
extern int pil_do_ramdump(struct pil_desc *desc, void *ramdump_dev,
			  void *minidump_dev);
extern int pil_assign_mem_to_subsys(struct pil_desc *desc, phys_addr_t addr,
						size_t size);
extern int pil_assign_mem_to_linux(struct pil_desc *desc, phys_addr_t addr,
@@ -157,7 +133,8 @@ static inline phys_addr_t pil_get_entry_addr(struct pil_desc *desc)
{
	return 0;
}
static inline int pil_do_ramdump(struct pil_desc *desc, void *ramdump_dev)
static inline int pil_do_ramdump(struct pil_desc *desc,
		void *ramdump_dev, void *minidump_dev)
{
	return 0;
}
+2 −2
Original line number Diff line number Diff line
/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
/* Copyright (c) 2014-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
@@ -864,7 +864,7 @@ static int subsys_ramdump(int enable, const struct subsys_desc *subsys)
	if (!enable)
		return 0;

	return pil_do_ramdump(&d->desc, d->ramdump_dev);
	return pil_do_ramdump(&d->desc, d->ramdump_dev, NULL);
}

static void subsys_free_memory(const struct subsys_desc *subsys)