summaryrefslogtreecommitdiff
path: root/drivers/soc/qcom/peripheral-loader.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/soc/qcom/peripheral-loader.c')
-rw-r--r--drivers/soc/qcom/peripheral-loader.c118
1 files changed, 85 insertions, 33 deletions
diff --git a/drivers/soc/qcom/peripheral-loader.c b/drivers/soc/qcom/peripheral-loader.c
index 6e153500f639..32a457730869 100644
--- a/drivers/soc/qcom/peripheral-loader.c
+++ b/drivers/soc/qcom/peripheral-loader.c
@@ -1,4 +1,4 @@
-/* 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 = readb_relaxed(offset) +
+ ss_mdump_seg_cnt_ss = readb_relaxed(offset_ss) +
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 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_pdr = readb_relaxed(offset_pdr) +
+ NUM_OF_ENCRYPTED_KEY;
+
+ 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_ss++;
+ }
+
+ 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++;
+ region_info_pdr++;
}
- ret = do_minidump(ramdump_dev, ramdump_segs, ss_mdump_seg_cnt);
+
+ 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;
}
}