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  */
18 int 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 
52 get_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  */
64 int 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 
123 cd_init_fail:
124 	kfree(cd_table);
125 	return ret;
126 }
127