GNU Linux-libre 6.8.9-gnu
[releases.git] / drivers / net / wwan / iosm / iosm_ipc_coredump.c
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 }