| // SPDX-License-Identifier: GPL-2.0-only |
| /* |
| * Copyright (C) 2020-2021 Intel Corporation. |
| */ |
| #include <linux/vmalloc.h> |
| |
| #include "iosm_ipc_coredump.h" |
| |
| /** |
| * ipc_coredump_collect - To collect coredump |
| * @devlink: Pointer to devlink instance. |
| * @data: Pointer to snapshot |
| * @entry: ID of requested snapshot |
| * @region_size: Region size |
| * |
| * Returns: 0 on success, error on failure |
| */ |
| int ipc_coredump_collect(struct iosm_devlink *devlink, u8 **data, int entry, |
| u32 region_size) |
| { |
| int ret, bytes_to_read, bytes_read = 0, i = 0; |
| s32 remaining; |
| u8 *data_ptr; |
| |
| data_ptr = vmalloc(region_size); |
| if (!data_ptr) |
| return -ENOMEM; |
| |
| remaining = devlink->cd_file_info[entry].actual_size; |
| ret = ipc_devlink_send_cmd(devlink, rpsi_cmd_coredump_get, entry); |
| if (ret) { |
| dev_err(devlink->dev, "Send coredump_get cmd failed"); |
| goto get_cd_fail; |
| } |
| while (remaining > 0) { |
| bytes_to_read = min(remaining, MAX_DATA_SIZE); |
| bytes_read = 0; |
| ret = ipc_imem_sys_devlink_read(devlink, data_ptr + i, |
| bytes_to_read, &bytes_read); |
| if (ret) { |
| dev_err(devlink->dev, "CD data read failed"); |
| goto get_cd_fail; |
| } |
| remaining -= bytes_read; |
| i += bytes_read; |
| } |
| |
| *data = data_ptr; |
| |
| return 0; |
| |
| get_cd_fail: |
| vfree(data_ptr); |
| return ret; |
| } |
| |
| /** |
| * ipc_coredump_get_list - Get coredump list from modem |
| * @devlink: Pointer to devlink instance. |
| * @cmd: RPSI command to be sent |
| * |
| * Returns: 0 on success, error on failure |
| */ |
| int ipc_coredump_get_list(struct iosm_devlink *devlink, u16 cmd) |
| { |
| u32 byte_read, num_entries, file_size; |
| struct iosm_cd_table *cd_table; |
| u8 size[MAX_SIZE_LEN], i; |
| char *filename; |
| int ret; |
| |
| cd_table = kzalloc(MAX_CD_LIST_SIZE, GFP_KERNEL); |
| if (!cd_table) { |
| ret = -ENOMEM; |
| goto cd_init_fail; |
| } |
| |
| ret = ipc_devlink_send_cmd(devlink, cmd, MAX_CD_LIST_SIZE); |
| if (ret) { |
| dev_err(devlink->dev, "rpsi_cmd_coredump_start failed"); |
| goto cd_init_fail; |
| } |
| |
| ret = ipc_imem_sys_devlink_read(devlink, (u8 *)cd_table, |
| MAX_CD_LIST_SIZE, &byte_read); |
| if (ret) { |
| dev_err(devlink->dev, "Coredump data is invalid"); |
| goto cd_init_fail; |
| } |
| |
| if (byte_read != MAX_CD_LIST_SIZE) |
| goto cd_init_fail; |
| |
| if (cmd == rpsi_cmd_coredump_start) { |
| num_entries = le32_to_cpu(cd_table->list.num_entries); |
| if (num_entries == 0 || num_entries > IOSM_NOF_CD_REGION) { |
| ret = -EINVAL; |
| goto cd_init_fail; |
| } |
| |
| for (i = 0; i < num_entries; i++) { |
| file_size = le32_to_cpu(cd_table->list.entry[i].size); |
| filename = cd_table->list.entry[i].filename; |
| |
| if (file_size > devlink->cd_file_info[i].default_size) { |
| ret = -EINVAL; |
| goto cd_init_fail; |
| } |
| |
| devlink->cd_file_info[i].actual_size = file_size; |
| dev_dbg(devlink->dev, "file: %s actual size %d", |
| filename, file_size); |
| devlink_flash_update_status_notify(devlink->devlink_ctx, |
| filename, |
| "FILENAME", 0, 0); |
| snprintf(size, sizeof(size), "%d", file_size); |
| devlink_flash_update_status_notify(devlink->devlink_ctx, |
| size, "FILE SIZE", |
| 0, 0); |
| } |
| } |
| |
| cd_init_fail: |
| kfree(cd_table); |
| return ret; |
| } |