Loading arch/arm64/boot/dts/qcom/sdm670.dtsi +1 −0 Original line number Diff line number Diff line Loading @@ -2135,6 +2135,7 @@ qcom,firmware-name = "modem"; qcom,pil-self-auth; qcom,sysmon-id = <0>; qcom,minidump-id = <3>; qcom,ssctl-instance-id = <0x12>; qcom,override-acc; qcom,signal-aop; Loading drivers/soc/qcom/peripheral-loader.c +86 −71 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 Loading Loading @@ -35,6 +35,7 @@ #include <soc/qcom/ramdump.h> #include <soc/qcom/subsystem_restart.h> #include <soc/qcom/secure_buffer.h> #include <soc/qcom/smem.h> #include <linux/uaccess.h> #include <asm/setup.h> Loading @@ -55,10 +56,9 @@ #endif #define PIL_NUM_DESC 10 #define NUM_OF_ENCRYPTED_KEY 3 #define MAX_LEN 96 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 Loading @@ -80,18 +80,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 Loading Loading @@ -146,8 +134,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; Loading @@ -155,24 +141,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) Loading @@ -183,23 +172,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, ®ion_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, ®ion_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, Loading @@ -215,16 +211,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++; Loading Loading @@ -1127,7 +1152,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; Loading @@ -1153,19 +1179,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)); } } Loading Loading @@ -1254,6 +1276,7 @@ static int __init msm_pil_init(void) struct device_node *np; struct resource res; int i; unsigned int size; np = of_find_compatible_node(NULL, NULL, "qcom,msm-imem-pil"); if (!np) { Loading @@ -1276,20 +1299,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 = smem_get_entry(SBL_MINIDUMP_SMEM_ID, &size, 0, SMEM_ANY_HOST_FLAG); 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); } Loading @@ -1300,8 +1317,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); Loading drivers/soc/qcom/peripheral-loader.h +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 Loading @@ -14,6 +14,7 @@ #include <linux/mailbox_client.h> #include <linux/mailbox/qmp.h> #include "minidump_private.h" struct device; struct module; Loading Loading @@ -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; }; /** Loading @@ -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 Loading Loading @@ -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, Loading @@ -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; } Loading drivers/soc/qcom/pil-msa.c +57 −2 Original line number Diff line number Diff line Loading @@ -35,6 +35,7 @@ /* Q6 Register Offsets */ #define QDSP6SS_RST_EVB 0x010 #define QDSP6SS_DBG_CFG 0x018 #define QDSP6SS_NMI_CFG 0x40 /* AXI Halting Registers */ #define MSS_Q6_HALT_BASE 0x180 Loading Loading @@ -366,10 +367,10 @@ int pil_mss_shutdown(struct pil_desc *pil) ret); } pil_mss_assert_resets(drv); pil_mss_restart_reg(drv, true); /* Wait 6 32kHz sleep cycles for reset */ udelay(200); ret = pil_mss_deassert_resets(drv); ret = pil_mss_restart_reg(drv, false); if (drv->is_booted) { pil_mss_disable_clks(drv); Loading Loading @@ -782,6 +783,60 @@ int pil_mss_reset_load_mba(struct pil_desc *pil) return ret; } int pil_mss_debug_reset(struct pil_desc *pil) { struct q6v5_data *drv = container_of(pil, struct q6v5_data, desc); int ret; if (!pil->minidump) return 0; /* * Bring subsystem out of reset and enable required * regulators and clocks. */ ret = pil_mss_enable_clks(drv); if (ret) return ret; if (pil->minidump) { writel_relaxed(0x1, drv->reg_base + QDSP6SS_NMI_CFG); /* Let write complete before proceeding */ mb(); udelay(2); } /* Assert reset to subsystem */ pil_mss_restart_reg(drv, true); /* Wait 6 32kHz sleep cycles for reset */ udelay(200); ret = pil_mss_restart_reg(drv, false); if (ret) goto err_restart; /* Let write complete before proceeding */ mb(); udelay(200); ret = pil_q6v5_reset(pil); /* * Need to Wait for timeout for debug reset sequence to * complete before returning */ pr_debug("Minidump: waiting encryption to complete\n"); msleep(30000); if (pil->minidump) { writel_relaxed(0x2, drv->reg_base + QDSP6SS_NMI_CFG); /* Let write complete before proceeding */ mb(); udelay(200); } if (ret) goto err_restart; return 0; err_restart: pil_mss_disable_clks(drv); if (drv->ahb_clk_vote) clk_disable_unprepare(drv->ahb_clk); return ret; } static int pil_msa_auth_modem_mdt(struct pil_desc *pil, const u8 *metadata, size_t size, phys_addr_t region_start, void *region) Loading drivers/soc/qcom/pil-msa.h +3 −1 Original line number Diff line number Diff line /* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. /* Copyright (c) 2012-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 Loading @@ -22,6 +22,7 @@ struct modem_data { struct subsys_device *subsys; struct subsys_desc subsys_desc; void *ramdump_dev; void *minidump_dev; bool crash_shutdown; u32 pas_id; bool ignore_errors; Loading @@ -46,4 +47,5 @@ int pil_mss_deinit_image(struct pil_desc *pil); int __pil_mss_deinit_image(struct pil_desc *pil, bool err_path); int pil_mss_assert_resets(struct q6v5_data *drv); int pil_mss_deassert_resets(struct q6v5_data *drv); int pil_mss_debug_reset(struct pil_desc *pil); #endif Loading
arch/arm64/boot/dts/qcom/sdm670.dtsi +1 −0 Original line number Diff line number Diff line Loading @@ -2135,6 +2135,7 @@ qcom,firmware-name = "modem"; qcom,pil-self-auth; qcom,sysmon-id = <0>; qcom,minidump-id = <3>; qcom,ssctl-instance-id = <0x12>; qcom,override-acc; qcom,signal-aop; Loading
drivers/soc/qcom/peripheral-loader.c +86 −71 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 Loading Loading @@ -35,6 +35,7 @@ #include <soc/qcom/ramdump.h> #include <soc/qcom/subsystem_restart.h> #include <soc/qcom/secure_buffer.h> #include <soc/qcom/smem.h> #include <linux/uaccess.h> #include <asm/setup.h> Loading @@ -55,10 +56,9 @@ #endif #define PIL_NUM_DESC 10 #define NUM_OF_ENCRYPTED_KEY 3 #define MAX_LEN 96 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 Loading @@ -80,18 +80,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 Loading Loading @@ -146,8 +134,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; Loading @@ -155,24 +141,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) Loading @@ -183,23 +172,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, ®ion_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, ®ion_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, Loading @@ -215,16 +211,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++; Loading Loading @@ -1127,7 +1152,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; Loading @@ -1153,19 +1179,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)); } } Loading Loading @@ -1254,6 +1276,7 @@ static int __init msm_pil_init(void) struct device_node *np; struct resource res; int i; unsigned int size; np = of_find_compatible_node(NULL, NULL, "qcom,msm-imem-pil"); if (!np) { Loading @@ -1276,20 +1299,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 = smem_get_entry(SBL_MINIDUMP_SMEM_ID, &size, 0, SMEM_ANY_HOST_FLAG); 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); } Loading @@ -1300,8 +1317,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); Loading
drivers/soc/qcom/peripheral-loader.h +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 Loading @@ -14,6 +14,7 @@ #include <linux/mailbox_client.h> #include <linux/mailbox/qmp.h> #include "minidump_private.h" struct device; struct module; Loading Loading @@ -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; }; /** Loading @@ -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 Loading Loading @@ -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, Loading @@ -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; } Loading
drivers/soc/qcom/pil-msa.c +57 −2 Original line number Diff line number Diff line Loading @@ -35,6 +35,7 @@ /* Q6 Register Offsets */ #define QDSP6SS_RST_EVB 0x010 #define QDSP6SS_DBG_CFG 0x018 #define QDSP6SS_NMI_CFG 0x40 /* AXI Halting Registers */ #define MSS_Q6_HALT_BASE 0x180 Loading Loading @@ -366,10 +367,10 @@ int pil_mss_shutdown(struct pil_desc *pil) ret); } pil_mss_assert_resets(drv); pil_mss_restart_reg(drv, true); /* Wait 6 32kHz sleep cycles for reset */ udelay(200); ret = pil_mss_deassert_resets(drv); ret = pil_mss_restart_reg(drv, false); if (drv->is_booted) { pil_mss_disable_clks(drv); Loading Loading @@ -782,6 +783,60 @@ int pil_mss_reset_load_mba(struct pil_desc *pil) return ret; } int pil_mss_debug_reset(struct pil_desc *pil) { struct q6v5_data *drv = container_of(pil, struct q6v5_data, desc); int ret; if (!pil->minidump) return 0; /* * Bring subsystem out of reset and enable required * regulators and clocks. */ ret = pil_mss_enable_clks(drv); if (ret) return ret; if (pil->minidump) { writel_relaxed(0x1, drv->reg_base + QDSP6SS_NMI_CFG); /* Let write complete before proceeding */ mb(); udelay(2); } /* Assert reset to subsystem */ pil_mss_restart_reg(drv, true); /* Wait 6 32kHz sleep cycles for reset */ udelay(200); ret = pil_mss_restart_reg(drv, false); if (ret) goto err_restart; /* Let write complete before proceeding */ mb(); udelay(200); ret = pil_q6v5_reset(pil); /* * Need to Wait for timeout for debug reset sequence to * complete before returning */ pr_debug("Minidump: waiting encryption to complete\n"); msleep(30000); if (pil->minidump) { writel_relaxed(0x2, drv->reg_base + QDSP6SS_NMI_CFG); /* Let write complete before proceeding */ mb(); udelay(200); } if (ret) goto err_restart; return 0; err_restart: pil_mss_disable_clks(drv); if (drv->ahb_clk_vote) clk_disable_unprepare(drv->ahb_clk); return ret; } static int pil_msa_auth_modem_mdt(struct pil_desc *pil, const u8 *metadata, size_t size, phys_addr_t region_start, void *region) Loading
drivers/soc/qcom/pil-msa.h +3 −1 Original line number Diff line number Diff line /* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. /* Copyright (c) 2012-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 Loading @@ -22,6 +22,7 @@ struct modem_data { struct subsys_device *subsys; struct subsys_desc subsys_desc; void *ramdump_dev; void *minidump_dev; bool crash_shutdown; u32 pas_id; bool ignore_errors; Loading @@ -46,4 +47,5 @@ int pil_mss_deinit_image(struct pil_desc *pil); int __pil_mss_deinit_image(struct pil_desc *pil, bool err_path); int pil_mss_assert_resets(struct q6v5_data *drv); int pil_mss_deassert_resets(struct q6v5_data *drv); int pil_mss_debug_reset(struct pil_desc *pil); #endif