Loading drivers/soc/qcom/cpuss_dump.c +421 −2 Original line number Diff line number Diff line // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2014-2018, The Linux Foundation. All rights reserved. * Copyright (c) 2014-2019, The Linux Foundation. All rights reserved. */ #include <linux/module.h> Loading @@ -12,6 +12,388 @@ #include <linux/slab.h> #include <soc/qcom/memory_dump.h> #define REG_DUMP_ID 0xEF #define INPUT_DATA_BY_HLOS 0x00C0FFEE #define FORMAT_VERSION_1 0x1 #define CORE_REG_NUM_DEFAULT 0x1 #define MAGIC_INDEX 0 #define FORMAT_VERSION_INDEX 1 #define SYS_REG_INPUT_INDEX 2 #define OUTPUT_DUMP_INDEX 3 #define PERCORE_INDEX 4 #define SYSTEM_REGS_INPUT_INDEX 5 struct cpuss_dump_drvdata { void *dump_vaddr; u32 size; u32 core_reg_num; u32 core_reg_used_num; u32 core_reg_end_index; u32 sys_reg_size; u32 used_memory; struct mutex mutex; }; struct reg_dump_data { uint32_t magic; uint32_t version; uint32_t system_regs_input_index; uint32_t regdump_output_byte_offset; }; /** * update_reg_dump_table - update the register dump table * @core_reg_num: the number of per-core registers * * This function calculates system_regs_input_index and * regdump_output_byte_offset to store into the dump memory. * It also updates members of drvdata by the parameter core_reg_num. * * Returns 0 on success, or -ENOMEM on error of no enough memory. */ static int update_reg_dump_table(struct device *dev, u32 core_reg_num) { int ret = 0; u32 system_regs_input_index = SYSTEM_REGS_INPUT_INDEX + core_reg_num * 2; u32 regdump_output_byte_offset = (system_regs_input_index + 1) * sizeof(uint32_t); struct reg_dump_data *p; struct cpuss_dump_drvdata *drvdata = dev_get_drvdata(dev); mutex_lock(&drvdata->mutex); if (regdump_output_byte_offset >= drvdata->size || regdump_output_byte_offset / sizeof(uint32_t) < system_regs_input_index + 1) { ret = -ENOMEM; goto err; } drvdata->core_reg_num = core_reg_num; drvdata->core_reg_used_num = 0; drvdata->core_reg_end_index = PERCORE_INDEX; drvdata->sys_reg_size = 0; drvdata->used_memory = regdump_output_byte_offset; memset(drvdata->dump_vaddr, 0xDE, drvdata->size); p = (struct reg_dump_data *)drvdata->dump_vaddr; p->magic = INPUT_DATA_BY_HLOS; p->version = FORMAT_VERSION_1; p->system_regs_input_index = system_regs_input_index; p->regdump_output_byte_offset = regdump_output_byte_offset; memset((uint32_t *)drvdata->dump_vaddr + PERCORE_INDEX, 0x0, (system_regs_input_index - PERCORE_INDEX + 1) * sizeof(uint32_t)); err: mutex_unlock(&drvdata->mutex); return ret; } static void init_register_dump(struct device *dev) { update_reg_dump_table(dev, CORE_REG_NUM_DEFAULT); } static ssize_t core_reg_num_show(struct device *dev, struct device_attribute *attr, char *buf) { int ret; struct cpuss_dump_drvdata *drvdata = dev_get_drvdata(dev); mutex_lock(&drvdata->mutex); ret = scnprintf(buf, PAGE_SIZE, "%u\n", drvdata->core_reg_num); mutex_unlock(&drvdata->mutex); return ret; } static ssize_t core_reg_num_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { int ret; unsigned int val; struct cpuss_dump_drvdata *drvdata = dev_get_drvdata(dev); if (kstrtouint(buf, 16, &val)) return -EINVAL; mutex_lock(&drvdata->mutex); if (drvdata->core_reg_used_num || drvdata->sys_reg_size) { dev_err(dev, "Couldn't set core_reg_num, register available in list\n"); ret = -EPERM; goto err; } if (val == drvdata->core_reg_num) { ret = 0; goto err; } mutex_unlock(&drvdata->mutex); ret = update_reg_dump_table(dev, val); if (ret) { dev_err(dev, "Couldn't set core_reg_num, no enough memory\n"); return ret; } return size; err: mutex_unlock(&drvdata->mutex); return ret; } static DEVICE_ATTR_RW(core_reg_num); /** * This function shows configs of per-core and system registers. */ static ssize_t register_config_show(struct device *dev, struct device_attribute *attr, char *buf) { char local_buf[64]; int len = 0, count = 0; int index, system_index_start, index_end; uint32_t register_offset, length_in_bytes; uint32_t length_in_words; uint32_t *p; struct cpuss_dump_drvdata *drvdata = dev_get_drvdata(dev); buf[0] = '\0'; mutex_lock(&drvdata->mutex); p = (uint32_t *)drvdata->dump_vaddr; /* print per-core & system registers */ len = snprintf(local_buf, 64, "per-core registers:\n"); strlcat(buf, local_buf, PAGE_SIZE); count += len; system_index_start = *(p + SYS_REG_INPUT_INDEX); index_end = system_index_start + drvdata->sys_reg_size / sizeof(uint32_t) + 1; for (index = PERCORE_INDEX; index < index_end;) { if (index == system_index_start) { len = snprintf(local_buf, 64, "system registers:\n"); if ((count + len) > PAGE_SIZE) { dev_err(dev, "Couldn't write complete config\n"); break; } strlcat(buf, local_buf, PAGE_SIZE); count += len; } register_offset = *(p + index); if (register_offset == 0) { index++; continue; } if (register_offset & 0x3) { length_in_words = register_offset & 0x3; length_in_bytes = length_in_words << 2; len = snprintf(local_buf, 64, "Index: 0x%x, addr: 0x%x\n", index, register_offset); index++; } else { length_in_bytes = *(p + index + 1); len = snprintf(local_buf, 64, "Index: 0x%x, addr: 0x%x, length: 0x%x\n", index, register_offset, length_in_bytes); index += 2; } if ((count + len) > PAGE_SIZE) { dev_err(dev, "Couldn't write complete config\n"); break; } strlcat(buf, local_buf, PAGE_SIZE); count += len; } mutex_unlock(&drvdata->mutex); return count; } /** * This function sets configs of per-core or system registers. */ static ssize_t register_config_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { int ret; uint32_t register_offset, length_in_bytes, per_core = 0; uint32_t length_in_words; int nval; uint32_t num_cores; u32 extra_memory; u32 used_memory; u32 system_reg_end_index; uint32_t *p; struct cpuss_dump_drvdata *drvdata = dev_get_drvdata(dev); nval = sscanf(buf, "%x %x %u", ®ister_offset, &length_in_bytes, &per_core); if (nval != 2 && nval != 3) return -EINVAL; if (per_core > 1) return -EINVAL; if (register_offset & 0x3) { dev_err(dev, "Invalid address, must be 4 byte aligned\n"); return -EINVAL; } if (length_in_bytes & 0x3) { dev_err(dev, "Invalid length, must be 4 byte aligned\n"); return -EINVAL; } if (length_in_bytes == 0) { dev_err(dev, "Invalid length of 0\n"); return -EINVAL; } mutex_lock(&drvdata->mutex); p = (uint32_t *)drvdata->dump_vaddr; length_in_words = length_in_bytes >> 2; if (per_core) { /* per-core register */ if (drvdata->core_reg_used_num == drvdata->core_reg_num) { dev_err(dev, "Couldn't add per-core config, out of range\n"); ret = -EINVAL; goto err; } num_cores = num_possible_cpus(); extra_memory = length_in_bytes * num_cores; used_memory = drvdata->used_memory + extra_memory; if (extra_memory / num_cores < length_in_bytes || used_memory > drvdata->size || used_memory < drvdata->used_memory) { dev_err(dev, "Couldn't add per-core reg config, no enough memory\n"); ret = -ENOMEM; goto err; } if (length_in_words > 3) { *(p + drvdata->core_reg_end_index) = register_offset; *(p + drvdata->core_reg_end_index + 1) = length_in_bytes; drvdata->core_reg_end_index += 2; } else { *(p + drvdata->core_reg_end_index) = register_offset | length_in_words; drvdata->core_reg_end_index++; } drvdata->core_reg_used_num++; drvdata->used_memory = used_memory; } else { /* system register */ system_reg_end_index = *(p + SYS_REG_INPUT_INDEX) + drvdata->sys_reg_size / sizeof(uint32_t); if (length_in_words > 3) { extra_memory = sizeof(uint32_t) * 2 + length_in_bytes; used_memory = drvdata->used_memory + extra_memory; if (extra_memory < length_in_bytes || used_memory > drvdata->size || used_memory < drvdata->used_memory) { dev_err(dev, "Couldn't add system reg config, no enough memory\n"); ret = -ENOMEM; goto err; } *(p + system_reg_end_index) = register_offset; *(p + system_reg_end_index + 1) = length_in_bytes; system_reg_end_index += 2; drvdata->sys_reg_size += sizeof(uint32_t) * 2; } else { extra_memory = sizeof(uint32_t) + length_in_bytes; used_memory = drvdata->used_memory + extra_memory; if (extra_memory < length_in_bytes || used_memory > drvdata->size || used_memory < drvdata->used_memory) { dev_err(dev, "Couldn't add system reg config, no enough memory\n"); ret = -ENOMEM; goto err; } *(p + system_reg_end_index) = register_offset | length_in_words; system_reg_end_index++; drvdata->sys_reg_size += sizeof(uint32_t); } drvdata->used_memory = used_memory; *(p + system_reg_end_index) = 0x0; *(p + OUTPUT_DUMP_INDEX) = (system_reg_end_index + 1) * sizeof(uint32_t); } ret = size; err: mutex_unlock(&drvdata->mutex); return ret; } static DEVICE_ATTR_RW(register_config); /** * This function resets the register dump table. */ static ssize_t register_reset_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { unsigned int val; if (kstrtouint(buf, 16, &val)) return -EINVAL; if (val != 1) return -EINVAL; init_register_dump(dev); return size; } static DEVICE_ATTR_WO(register_reset); static const struct device_attribute *register_dump_attrs[] = { &dev_attr_core_reg_num, &dev_attr_register_config, &dev_attr_register_reset, NULL, }; static int register_dump_create_files(struct device *dev, const struct device_attribute **attrs) { int ret = 0; int i, j; for (i = 0; attrs[i] != NULL; i++) { ret = device_create_file(dev, attrs[i]); if (ret) { dev_err(dev, "Couldn't create sysfs attribute: %s\n", attrs[i]->attr.name); for (j = 0; j < i; j++) device_remove_file(dev, attrs[j]); break; } } return ret; } static int cpuss_dump_probe(struct platform_device *pdev) { struct device_node *child_node, *dump_node; Loading @@ -22,9 +404,11 @@ static int cpuss_dump_probe(struct platform_device *pdev) struct msm_dump_entry dump_entry; int ret; u32 size, id; struct cpuss_dump_drvdata *drvdata; for_each_available_child_of_node(node, child_node) { dump_node = of_parse_phandle(child_node, "qcom,dump-node", 0); drvdata = NULL; if (!dump_node) { dev_err(&pdev->dev, "Unable to find node for %s\n", Loading Loading @@ -54,13 +438,44 @@ static int cpuss_dump_probe(struct platform_device *pdev) continue; } if (id == REG_DUMP_ID) { drvdata = devm_kzalloc(&pdev->dev, sizeof(struct cpuss_dump_drvdata), GFP_KERNEL); if (!drvdata) { dma_free_coherent(&pdev->dev, size, dump_vaddr, dump_addr); continue; } drvdata->dump_vaddr = dump_vaddr; drvdata->size = size; ret = register_dump_create_files(&pdev->dev, register_dump_attrs); if (ret) { dma_free_coherent(&pdev->dev, size, dump_vaddr, dump_addr); devm_kfree(&pdev->dev, drvdata); continue; } mutex_init(&drvdata->mutex); platform_set_drvdata(pdev, drvdata); init_register_dump(&pdev->dev); } else { memset(dump_vaddr, 0x0, size); } dump_data = devm_kzalloc(&pdev->dev, sizeof(struct msm_dump_data), GFP_KERNEL); if (!dump_data) { dma_free_coherent(&pdev->dev, size, dump_vaddr, dump_addr); if (drvdata) { devm_kfree(&pdev->dev, drvdata); platform_set_drvdata(pdev, NULL); } continue; } Loading @@ -76,6 +491,10 @@ static int cpuss_dump_probe(struct platform_device *pdev) id); dma_free_coherent(&pdev->dev, size, dump_vaddr, dump_addr); if (drvdata) { devm_kfree(&pdev->dev, drvdata); platform_set_drvdata(pdev, NULL); } devm_kfree(&pdev->dev, dump_data); } Loading Loading
drivers/soc/qcom/cpuss_dump.c +421 −2 Original line number Diff line number Diff line // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2014-2018, The Linux Foundation. All rights reserved. * Copyright (c) 2014-2019, The Linux Foundation. All rights reserved. */ #include <linux/module.h> Loading @@ -12,6 +12,388 @@ #include <linux/slab.h> #include <soc/qcom/memory_dump.h> #define REG_DUMP_ID 0xEF #define INPUT_DATA_BY_HLOS 0x00C0FFEE #define FORMAT_VERSION_1 0x1 #define CORE_REG_NUM_DEFAULT 0x1 #define MAGIC_INDEX 0 #define FORMAT_VERSION_INDEX 1 #define SYS_REG_INPUT_INDEX 2 #define OUTPUT_DUMP_INDEX 3 #define PERCORE_INDEX 4 #define SYSTEM_REGS_INPUT_INDEX 5 struct cpuss_dump_drvdata { void *dump_vaddr; u32 size; u32 core_reg_num; u32 core_reg_used_num; u32 core_reg_end_index; u32 sys_reg_size; u32 used_memory; struct mutex mutex; }; struct reg_dump_data { uint32_t magic; uint32_t version; uint32_t system_regs_input_index; uint32_t regdump_output_byte_offset; }; /** * update_reg_dump_table - update the register dump table * @core_reg_num: the number of per-core registers * * This function calculates system_regs_input_index and * regdump_output_byte_offset to store into the dump memory. * It also updates members of drvdata by the parameter core_reg_num. * * Returns 0 on success, or -ENOMEM on error of no enough memory. */ static int update_reg_dump_table(struct device *dev, u32 core_reg_num) { int ret = 0; u32 system_regs_input_index = SYSTEM_REGS_INPUT_INDEX + core_reg_num * 2; u32 regdump_output_byte_offset = (system_regs_input_index + 1) * sizeof(uint32_t); struct reg_dump_data *p; struct cpuss_dump_drvdata *drvdata = dev_get_drvdata(dev); mutex_lock(&drvdata->mutex); if (regdump_output_byte_offset >= drvdata->size || regdump_output_byte_offset / sizeof(uint32_t) < system_regs_input_index + 1) { ret = -ENOMEM; goto err; } drvdata->core_reg_num = core_reg_num; drvdata->core_reg_used_num = 0; drvdata->core_reg_end_index = PERCORE_INDEX; drvdata->sys_reg_size = 0; drvdata->used_memory = regdump_output_byte_offset; memset(drvdata->dump_vaddr, 0xDE, drvdata->size); p = (struct reg_dump_data *)drvdata->dump_vaddr; p->magic = INPUT_DATA_BY_HLOS; p->version = FORMAT_VERSION_1; p->system_regs_input_index = system_regs_input_index; p->regdump_output_byte_offset = regdump_output_byte_offset; memset((uint32_t *)drvdata->dump_vaddr + PERCORE_INDEX, 0x0, (system_regs_input_index - PERCORE_INDEX + 1) * sizeof(uint32_t)); err: mutex_unlock(&drvdata->mutex); return ret; } static void init_register_dump(struct device *dev) { update_reg_dump_table(dev, CORE_REG_NUM_DEFAULT); } static ssize_t core_reg_num_show(struct device *dev, struct device_attribute *attr, char *buf) { int ret; struct cpuss_dump_drvdata *drvdata = dev_get_drvdata(dev); mutex_lock(&drvdata->mutex); ret = scnprintf(buf, PAGE_SIZE, "%u\n", drvdata->core_reg_num); mutex_unlock(&drvdata->mutex); return ret; } static ssize_t core_reg_num_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { int ret; unsigned int val; struct cpuss_dump_drvdata *drvdata = dev_get_drvdata(dev); if (kstrtouint(buf, 16, &val)) return -EINVAL; mutex_lock(&drvdata->mutex); if (drvdata->core_reg_used_num || drvdata->sys_reg_size) { dev_err(dev, "Couldn't set core_reg_num, register available in list\n"); ret = -EPERM; goto err; } if (val == drvdata->core_reg_num) { ret = 0; goto err; } mutex_unlock(&drvdata->mutex); ret = update_reg_dump_table(dev, val); if (ret) { dev_err(dev, "Couldn't set core_reg_num, no enough memory\n"); return ret; } return size; err: mutex_unlock(&drvdata->mutex); return ret; } static DEVICE_ATTR_RW(core_reg_num); /** * This function shows configs of per-core and system registers. */ static ssize_t register_config_show(struct device *dev, struct device_attribute *attr, char *buf) { char local_buf[64]; int len = 0, count = 0; int index, system_index_start, index_end; uint32_t register_offset, length_in_bytes; uint32_t length_in_words; uint32_t *p; struct cpuss_dump_drvdata *drvdata = dev_get_drvdata(dev); buf[0] = '\0'; mutex_lock(&drvdata->mutex); p = (uint32_t *)drvdata->dump_vaddr; /* print per-core & system registers */ len = snprintf(local_buf, 64, "per-core registers:\n"); strlcat(buf, local_buf, PAGE_SIZE); count += len; system_index_start = *(p + SYS_REG_INPUT_INDEX); index_end = system_index_start + drvdata->sys_reg_size / sizeof(uint32_t) + 1; for (index = PERCORE_INDEX; index < index_end;) { if (index == system_index_start) { len = snprintf(local_buf, 64, "system registers:\n"); if ((count + len) > PAGE_SIZE) { dev_err(dev, "Couldn't write complete config\n"); break; } strlcat(buf, local_buf, PAGE_SIZE); count += len; } register_offset = *(p + index); if (register_offset == 0) { index++; continue; } if (register_offset & 0x3) { length_in_words = register_offset & 0x3; length_in_bytes = length_in_words << 2; len = snprintf(local_buf, 64, "Index: 0x%x, addr: 0x%x\n", index, register_offset); index++; } else { length_in_bytes = *(p + index + 1); len = snprintf(local_buf, 64, "Index: 0x%x, addr: 0x%x, length: 0x%x\n", index, register_offset, length_in_bytes); index += 2; } if ((count + len) > PAGE_SIZE) { dev_err(dev, "Couldn't write complete config\n"); break; } strlcat(buf, local_buf, PAGE_SIZE); count += len; } mutex_unlock(&drvdata->mutex); return count; } /** * This function sets configs of per-core or system registers. */ static ssize_t register_config_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { int ret; uint32_t register_offset, length_in_bytes, per_core = 0; uint32_t length_in_words; int nval; uint32_t num_cores; u32 extra_memory; u32 used_memory; u32 system_reg_end_index; uint32_t *p; struct cpuss_dump_drvdata *drvdata = dev_get_drvdata(dev); nval = sscanf(buf, "%x %x %u", ®ister_offset, &length_in_bytes, &per_core); if (nval != 2 && nval != 3) return -EINVAL; if (per_core > 1) return -EINVAL; if (register_offset & 0x3) { dev_err(dev, "Invalid address, must be 4 byte aligned\n"); return -EINVAL; } if (length_in_bytes & 0x3) { dev_err(dev, "Invalid length, must be 4 byte aligned\n"); return -EINVAL; } if (length_in_bytes == 0) { dev_err(dev, "Invalid length of 0\n"); return -EINVAL; } mutex_lock(&drvdata->mutex); p = (uint32_t *)drvdata->dump_vaddr; length_in_words = length_in_bytes >> 2; if (per_core) { /* per-core register */ if (drvdata->core_reg_used_num == drvdata->core_reg_num) { dev_err(dev, "Couldn't add per-core config, out of range\n"); ret = -EINVAL; goto err; } num_cores = num_possible_cpus(); extra_memory = length_in_bytes * num_cores; used_memory = drvdata->used_memory + extra_memory; if (extra_memory / num_cores < length_in_bytes || used_memory > drvdata->size || used_memory < drvdata->used_memory) { dev_err(dev, "Couldn't add per-core reg config, no enough memory\n"); ret = -ENOMEM; goto err; } if (length_in_words > 3) { *(p + drvdata->core_reg_end_index) = register_offset; *(p + drvdata->core_reg_end_index + 1) = length_in_bytes; drvdata->core_reg_end_index += 2; } else { *(p + drvdata->core_reg_end_index) = register_offset | length_in_words; drvdata->core_reg_end_index++; } drvdata->core_reg_used_num++; drvdata->used_memory = used_memory; } else { /* system register */ system_reg_end_index = *(p + SYS_REG_INPUT_INDEX) + drvdata->sys_reg_size / sizeof(uint32_t); if (length_in_words > 3) { extra_memory = sizeof(uint32_t) * 2 + length_in_bytes; used_memory = drvdata->used_memory + extra_memory; if (extra_memory < length_in_bytes || used_memory > drvdata->size || used_memory < drvdata->used_memory) { dev_err(dev, "Couldn't add system reg config, no enough memory\n"); ret = -ENOMEM; goto err; } *(p + system_reg_end_index) = register_offset; *(p + system_reg_end_index + 1) = length_in_bytes; system_reg_end_index += 2; drvdata->sys_reg_size += sizeof(uint32_t) * 2; } else { extra_memory = sizeof(uint32_t) + length_in_bytes; used_memory = drvdata->used_memory + extra_memory; if (extra_memory < length_in_bytes || used_memory > drvdata->size || used_memory < drvdata->used_memory) { dev_err(dev, "Couldn't add system reg config, no enough memory\n"); ret = -ENOMEM; goto err; } *(p + system_reg_end_index) = register_offset | length_in_words; system_reg_end_index++; drvdata->sys_reg_size += sizeof(uint32_t); } drvdata->used_memory = used_memory; *(p + system_reg_end_index) = 0x0; *(p + OUTPUT_DUMP_INDEX) = (system_reg_end_index + 1) * sizeof(uint32_t); } ret = size; err: mutex_unlock(&drvdata->mutex); return ret; } static DEVICE_ATTR_RW(register_config); /** * This function resets the register dump table. */ static ssize_t register_reset_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { unsigned int val; if (kstrtouint(buf, 16, &val)) return -EINVAL; if (val != 1) return -EINVAL; init_register_dump(dev); return size; } static DEVICE_ATTR_WO(register_reset); static const struct device_attribute *register_dump_attrs[] = { &dev_attr_core_reg_num, &dev_attr_register_config, &dev_attr_register_reset, NULL, }; static int register_dump_create_files(struct device *dev, const struct device_attribute **attrs) { int ret = 0; int i, j; for (i = 0; attrs[i] != NULL; i++) { ret = device_create_file(dev, attrs[i]); if (ret) { dev_err(dev, "Couldn't create sysfs attribute: %s\n", attrs[i]->attr.name); for (j = 0; j < i; j++) device_remove_file(dev, attrs[j]); break; } } return ret; } static int cpuss_dump_probe(struct platform_device *pdev) { struct device_node *child_node, *dump_node; Loading @@ -22,9 +404,11 @@ static int cpuss_dump_probe(struct platform_device *pdev) struct msm_dump_entry dump_entry; int ret; u32 size, id; struct cpuss_dump_drvdata *drvdata; for_each_available_child_of_node(node, child_node) { dump_node = of_parse_phandle(child_node, "qcom,dump-node", 0); drvdata = NULL; if (!dump_node) { dev_err(&pdev->dev, "Unable to find node for %s\n", Loading Loading @@ -54,13 +438,44 @@ static int cpuss_dump_probe(struct platform_device *pdev) continue; } if (id == REG_DUMP_ID) { drvdata = devm_kzalloc(&pdev->dev, sizeof(struct cpuss_dump_drvdata), GFP_KERNEL); if (!drvdata) { dma_free_coherent(&pdev->dev, size, dump_vaddr, dump_addr); continue; } drvdata->dump_vaddr = dump_vaddr; drvdata->size = size; ret = register_dump_create_files(&pdev->dev, register_dump_attrs); if (ret) { dma_free_coherent(&pdev->dev, size, dump_vaddr, dump_addr); devm_kfree(&pdev->dev, drvdata); continue; } mutex_init(&drvdata->mutex); platform_set_drvdata(pdev, drvdata); init_register_dump(&pdev->dev); } else { memset(dump_vaddr, 0x0, size); } dump_data = devm_kzalloc(&pdev->dev, sizeof(struct msm_dump_data), GFP_KERNEL); if (!dump_data) { dma_free_coherent(&pdev->dev, size, dump_vaddr, dump_addr); if (drvdata) { devm_kfree(&pdev->dev, drvdata); platform_set_drvdata(pdev, NULL); } continue; } Loading @@ -76,6 +491,10 @@ static int cpuss_dump_probe(struct platform_device *pdev) id); dma_free_coherent(&pdev->dev, size, dump_vaddr, dump_addr); if (drvdata) { devm_kfree(&pdev->dev, drvdata); platform_set_drvdata(pdev, NULL); } devm_kfree(&pdev->dev, dump_data); } Loading