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