diff --git a/drivers/soc/qcom/peripheral-loader.c b/drivers/soc/qcom/peripheral-loader.c index ef72cdd3f540..50883e418c9f 100644 --- a/drivers/soc/qcom/peripheral-loader.c +++ b/drivers/soc/qcom/peripheral-loader.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2010-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2010-2020, The Linux Foundation. All rights reserved. */ #include @@ -237,6 +237,22 @@ static void unmap_aux_minidump_regions(struct aux_minidump_info *aux_mdump, } } +/** + * unmap_minidump_segments() - unmap the individual segments that were mapped + * @rd_segs: The array of ramdump segments + * @num_valid_segs: The number of valid segments from rd_segs + * + * The function unmaps the valid regions for the segments that were mapped. + */ +static void unmap_minidump_segments(struct ramdump_segment *rd_segs, + int num_valid_segs) +{ + while (num_valid_segs--) { + iounmap(rd_segs->v_address); + rd_segs++; + } +} + /** * prepare_minidump_segments() - Fills in the necessary information for the * ramdump driver to dump a region of memory, described by a segment. @@ -271,6 +287,12 @@ static unsigned int prepare_minidump_segments(struct ramdump_segment *rd_segs, offset = offset + sizeof(region_info->region_base_address); rd_segs->size = __raw_readl(offset); + + rd_segs->v_address = ioremap_wc(rd_segs->address, + rd_segs->size); + if (!rd_segs->v_address) + return -ENOMEM; + pr_debug("Minidump : Dumping segment %s with address 0x%lx and size 0x%x\n", rd_segs->name, rd_segs->address, (unsigned int)rd_segs->size); @@ -301,14 +323,14 @@ static unsigned int prepare_minidump_segments(struct ramdump_segment *rd_segs, * describe the regions that should be dumped by the ramdump driver for a set * of auxiliary minidump IDs. */ -static void prepare_aux_minidump_segments(struct ramdump_segment *rd_segs, +static int prepare_aux_minidump_segments(struct ramdump_segment *rd_segs, struct aux_minidump_info *aux_mdump, int *ss_valid_seg_cnt, int num_aux_md_ids) { unsigned int i; struct ramdump_segment *s = rd_segs; - unsigned int next_offset = 0; + int next_offset = 0; for (i = 0; i < num_aux_md_ids; i++) { s = &rd_segs[next_offset]; @@ -316,7 +338,11 @@ static void prepare_aux_minidump_segments(struct ramdump_segment *rd_segs, aux_mdump[i].region_info_aux, aux_mdump[i].seg_cnt, ss_valid_seg_cnt); + if (next_offset < 0) + return next_offset; } + + return 0; } static int pil_do_minidump(struct pil_desc *desc, void *ramdump_dev) @@ -329,7 +355,7 @@ static int pil_do_minidump(struct pil_desc *desc, void *ramdump_dev) int ss_valid_seg_cnt; int ret; struct aux_minidump_info *aux_minidump_data = NULL; - unsigned int next_offset; + int next_offset; if (!ramdump_dev) return -ENODEV; @@ -372,12 +398,17 @@ static int pil_do_minidump(struct pil_desc *desc, void *ramdump_dev) next_offset = prepare_minidump_segments(ramdump_segs, region_info_ss, ss_mdump_seg_cnt_ss, &ss_valid_seg_cnt); + if (next_offset < 0) + goto seg_mapping_fail; - if (desc->num_aux_minidump_ids > 0) - prepare_aux_minidump_segments(&ramdump_segs[next_offset], + if (desc->num_aux_minidump_ids > 0) { + ret = prepare_aux_minidump_segments(&ramdump_segs[next_offset], aux_minidump_data, &ss_valid_seg_cnt, desc->num_aux_minidump_ids); + if (ret < 0) + goto seg_mapping_fail; + } ret = do_minidump(ramdump_dev, ramdump_segs, ss_valid_seg_cnt); if (ret) @@ -388,6 +419,8 @@ static int pil_do_minidump(struct pil_desc *desc, void *ramdump_dev) ret = pil_assign_mem_to_subsys(desc, priv->region_start, (priv->region_end - priv->region_start)); +seg_mapping_fail: + unmap_minidump_segments(ramdump_segs, ss_valid_seg_cnt); kfree(ramdump_segs); mapping_fail: unmap_aux_minidump_regions(aux_minidump_data, diff --git a/drivers/soc/qcom/ramdump.c b/drivers/soc/qcom/ramdump.c index 2731c7828576..01efce451f2b 100644 --- a/drivers/soc/qcom/ramdump.c +++ b/drivers/soc/qcom/ramdump.c @@ -140,7 +140,7 @@ static unsigned long offset_translate(loff_t user_offset, *data_left); if (rd_dev->segments[i].v_address) - *vaddr = rd_dev->segments[i].v_address + user_offset; + *vaddr = (void *) rd_dev->segments[i].v_address + user_offset; return rd_dev->segments[i].address + user_offset; } diff --git a/include/soc/qcom/ramdump.h b/include/soc/qcom/ramdump.h index ae03e9f091e3..99b3c445f013 100644 --- a/include/soc/qcom/ramdump.h +++ b/include/soc/qcom/ramdump.h @@ -15,7 +15,7 @@ struct device; struct ramdump_segment { char *name; unsigned long address; - void *v_address; + volatile void __iomem *v_address; unsigned long size; };