1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * Copyright (C) 2020-2021 Intel Corporation.
4 */
5#include <linux/vmalloc.h>
6
7#include "iosm_ipc_coredump.h"
8
9/**
10 * ipc_coredump_collect - To collect coredump
11 * @devlink:            Pointer to devlink instance.
12 * @data:               Pointer to snapshot
13 * @entry:              ID of requested snapshot
14 * @region_size:        Region size
15 *
16 * Returns: 0 on success, error on failure
17 */
18int ipc_coredump_collect(struct iosm_devlink *devlink, u8 **data, int entry,
19			 u32 region_size)
20{
21	int ret, bytes_to_read, bytes_read = 0, i = 0;
22	s32 remaining;
23	u8 *data_ptr;
24
25	data_ptr = vmalloc(region_size);
26	if (!data_ptr)
27		return -ENOMEM;
28
29	remaining = devlink->cd_file_info[entry].actual_size;
30	ret = ipc_devlink_send_cmd(devlink, rpsi_cmd_coredump_get, entry);
31	if (ret) {
32		dev_err(devlink->dev, "Send coredump_get cmd failed");
33		goto get_cd_fail;
34	}
35	while (remaining > 0) {
36		bytes_to_read = min(remaining, MAX_DATA_SIZE);
37		bytes_read = 0;
38		ret = ipc_imem_sys_devlink_read(devlink, data_ptr + i,
39						bytes_to_read, &bytes_read);
40		if (ret) {
41			dev_err(devlink->dev, "CD data read failed");
42			goto get_cd_fail;
43		}
44		remaining -= bytes_read;
45		i += bytes_read;
46	}
47
48	*data = data_ptr;
49
50	return 0;
51
52get_cd_fail:
53	vfree(data_ptr);
54	return ret;
55}
56
57/**
58 * ipc_coredump_get_list - Get coredump list from modem
59 * @devlink:         Pointer to devlink instance.
60 * @cmd:             RPSI command to be sent
61 *
62 * Returns: 0 on success, error on failure
63 */
64int ipc_coredump_get_list(struct iosm_devlink *devlink, u16 cmd)
65{
66	u32 byte_read, num_entries, file_size;
67	struct iosm_cd_table *cd_table;
68	u8 size[MAX_SIZE_LEN], i;
69	char *filename;
70	int ret;
71
72	cd_table = kzalloc(MAX_CD_LIST_SIZE, GFP_KERNEL);
73	if (!cd_table) {
74		ret = -ENOMEM;
75		goto  cd_init_fail;
76	}
77
78	ret = ipc_devlink_send_cmd(devlink, cmd, MAX_CD_LIST_SIZE);
79	if (ret) {
80		dev_err(devlink->dev, "rpsi_cmd_coredump_start failed");
81		goto cd_init_fail;
82	}
83
84	ret = ipc_imem_sys_devlink_read(devlink, (u8 *)cd_table,
85					MAX_CD_LIST_SIZE, &byte_read);
86	if (ret) {
87		dev_err(devlink->dev, "Coredump data is invalid");
88		goto cd_init_fail;
89	}
90
91	if (byte_read != MAX_CD_LIST_SIZE)
92		goto cd_init_fail;
93
94	if (cmd == rpsi_cmd_coredump_start) {
95		num_entries = le32_to_cpu(cd_table->list.num_entries);
96		if (num_entries == 0 || num_entries > IOSM_NOF_CD_REGION) {
97			ret = -EINVAL;
98			goto cd_init_fail;
99		}
100
101		for (i = 0; i < num_entries; i++) {
102			file_size = le32_to_cpu(cd_table->list.entry[i].size);
103			filename = cd_table->list.entry[i].filename;
104
105			if (file_size > devlink->cd_file_info[i].default_size) {
106				ret = -EINVAL;
107				goto cd_init_fail;
108			}
109
110			devlink->cd_file_info[i].actual_size = file_size;
111			dev_dbg(devlink->dev, "file: %s actual size %d",
112				filename, file_size);
113			devlink_flash_update_status_notify(devlink->devlink_ctx,
114							   filename,
115							   "FILENAME", 0, 0);
116			snprintf(size, sizeof(size), "%d", file_size);
117			devlink_flash_update_status_notify(devlink->devlink_ctx,
118							   size, "FILE SIZE",
119							   0, 0);
120		}
121	}
122
123cd_init_fail:
124	kfree(cd_table);
125	return ret;
126}
127