]> Git Repo - linux.git/blob - drivers/net/wwan/iosm/iosm_ipc_devlink.c
Linux 6.14-rc3
[linux.git] / drivers / net / wwan / iosm / iosm_ipc_devlink.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_chnl_cfg.h"
8 #include "iosm_ipc_coredump.h"
9 #include "iosm_ipc_devlink.h"
10 #include "iosm_ipc_flash.h"
11
12 /* Coredump list */
13 static struct iosm_coredump_file_info list[IOSM_NOF_CD_REGION] = {
14         {"report.json", REPORT_JSON_SIZE,},
15         {"coredump.fcd", COREDUMP_FCD_SIZE,},
16         {"cdd.log", CDD_LOG_SIZE,},
17         {"eeprom.bin", EEPROM_BIN_SIZE,},
18         {"bootcore_trace.bin", BOOTCORE_TRC_BIN_SIZE,},
19         {"bootcore_prev_trace.bin", BOOTCORE_PREV_TRC_BIN_SIZE,},
20 };
21
22 /* Get the param values for the specific param ID's */
23 static int ipc_devlink_get_param(struct devlink *dl, u32 id,
24                                  struct devlink_param_gset_ctx *ctx)
25 {
26         struct iosm_devlink *ipc_devlink = devlink_priv(dl);
27
28         if (id == IOSM_DEVLINK_PARAM_ID_ERASE_FULL_FLASH)
29                 ctx->val.vu8 = ipc_devlink->param.erase_full_flash;
30
31         return 0;
32 }
33
34 /* Set the param values for the specific param ID's */
35 static int ipc_devlink_set_param(struct devlink *dl, u32 id,
36                                  struct devlink_param_gset_ctx *ctx,
37                                  struct netlink_ext_ack *extack)
38 {
39         struct iosm_devlink *ipc_devlink = devlink_priv(dl);
40
41         if (id == IOSM_DEVLINK_PARAM_ID_ERASE_FULL_FLASH)
42                 ipc_devlink->param.erase_full_flash = ctx->val.vu8;
43
44         return 0;
45 }
46
47 /* Devlink param structure array */
48 static const struct devlink_param iosm_devlink_params[] = {
49         DEVLINK_PARAM_DRIVER(IOSM_DEVLINK_PARAM_ID_ERASE_FULL_FLASH,
50                              "erase_full_flash", DEVLINK_PARAM_TYPE_BOOL,
51                              BIT(DEVLINK_PARAM_CMODE_RUNTIME),
52                              ipc_devlink_get_param, ipc_devlink_set_param,
53                              NULL),
54 };
55
56 /* Get devlink flash component type */
57 static enum iosm_flash_comp_type
58 ipc_devlink_get_flash_comp_type(const char comp_str[], u32 len)
59 {
60         enum iosm_flash_comp_type fls_type;
61
62         if (!strncmp("PSI", comp_str, len))
63                 fls_type = FLASH_COMP_TYPE_PSI;
64         else if (!strncmp("EBL", comp_str, len))
65                 fls_type = FLASH_COMP_TYPE_EBL;
66         else if (!strncmp("FLS", comp_str, len))
67                 fls_type = FLASH_COMP_TYPE_FLS;
68         else
69                 fls_type = FLASH_COMP_TYPE_INVAL;
70
71         return fls_type;
72 }
73
74 /* Function triggered on devlink flash command
75  * Flash update function which calls multiple functions based on
76  * component type specified in the flash command
77  */
78 static int ipc_devlink_flash_update(struct devlink *devlink,
79                                     struct devlink_flash_update_params *params,
80                                     struct netlink_ext_ack *extack)
81 {
82         struct iosm_devlink *ipc_devlink = devlink_priv(devlink);
83         enum iosm_flash_comp_type fls_type;
84         struct iosm_devlink_image *header;
85         int rc = -EINVAL;
86         u8 *mdm_rsp;
87
88         header = (struct iosm_devlink_image *)params->fw->data;
89
90         if (!header || params->fw->size <= IOSM_DEVLINK_HDR_SIZE ||
91             (memcmp(header->magic_header, IOSM_DEVLINK_MAGIC_HEADER,
92              IOSM_DEVLINK_MAGIC_HEADER_LEN) != 0))
93                 return -EINVAL;
94
95         mdm_rsp = kzalloc(IOSM_EBL_DW_PACK_SIZE, GFP_KERNEL);
96         if (!mdm_rsp)
97                 return -ENOMEM;
98
99         fls_type = ipc_devlink_get_flash_comp_type(header->image_type,
100                                                    IOSM_DEVLINK_MAX_IMG_LEN);
101
102         switch (fls_type) {
103         case FLASH_COMP_TYPE_PSI:
104                 rc = ipc_flash_boot_psi(ipc_devlink, params->fw);
105                 break;
106         case FLASH_COMP_TYPE_EBL:
107                 rc = ipc_flash_boot_ebl(ipc_devlink, params->fw);
108                 if (rc)
109                         break;
110                 rc = ipc_flash_boot_set_capabilities(ipc_devlink, mdm_rsp);
111                 if (rc)
112                         break;
113                 rc = ipc_flash_read_swid(ipc_devlink, mdm_rsp);
114                 break;
115         case FLASH_COMP_TYPE_FLS:
116                 rc = ipc_flash_send_fls(ipc_devlink, params->fw, mdm_rsp);
117                 break;
118         default:
119                 devlink_flash_update_status_notify(devlink, "Invalid component",
120                                                    NULL, 0, 0);
121                 break;
122         }
123
124         if (!rc)
125                 devlink_flash_update_status_notify(devlink, "Flashing success",
126                                                    header->image_type, 0, 0);
127         else
128                 devlink_flash_update_status_notify(devlink, "Flashing failed",
129                                                    header->image_type, 0, 0);
130
131         kfree(mdm_rsp);
132         return rc;
133 }
134
135 /* Call back function for devlink ops */
136 static const struct devlink_ops devlink_flash_ops = {
137         .flash_update = ipc_devlink_flash_update,
138 };
139
140 /**
141  * ipc_devlink_send_cmd - Send command to Modem
142  * @ipc_devlink: Pointer to struct iosm_devlink
143  * @cmd:         Command to be sent to modem
144  * @entry:       Command entry number
145  *
146  * Returns:      0 on success and failure value on error
147  */
148 int ipc_devlink_send_cmd(struct iosm_devlink *ipc_devlink, u16 cmd, u32 entry)
149 {
150         struct iosm_rpsi_cmd rpsi_cmd;
151
152         rpsi_cmd.param.dword = cpu_to_le32(entry);
153         rpsi_cmd.cmd = cpu_to_le16(cmd);
154         rpsi_cmd.crc = rpsi_cmd.param.word[0] ^ rpsi_cmd.param.word[1] ^
155                        rpsi_cmd.cmd;
156
157         return ipc_imem_sys_devlink_write(ipc_devlink, (u8 *)&rpsi_cmd,
158                                           sizeof(rpsi_cmd));
159 }
160
161 /* Function to create snapshot */
162 static int ipc_devlink_coredump_snapshot(struct devlink *dl,
163                                          const struct devlink_region_ops *ops,
164                                          struct netlink_ext_ack *extack,
165                                          u8 **data)
166 {
167         struct iosm_devlink *ipc_devlink = devlink_priv(dl);
168         struct iosm_coredump_file_info *cd_list = ops->priv;
169         u32 region_size;
170         int rc;
171
172         dev_dbg(ipc_devlink->dev, "Region:%s, ID:%d", ops->name,
173                 cd_list->entry);
174         region_size = cd_list->default_size;
175         rc = ipc_coredump_collect(ipc_devlink, data, cd_list->entry,
176                                   region_size);
177         if (rc) {
178                 dev_err(ipc_devlink->dev, "Fail to create snapshot,err %d", rc);
179                 goto coredump_collect_err;
180         }
181
182         /* Send coredump end cmd indicating end of coredump collection */
183         if (cd_list->entry == (IOSM_NOF_CD_REGION - 1))
184                 ipc_coredump_get_list(ipc_devlink, rpsi_cmd_coredump_end);
185
186         return 0;
187
188 coredump_collect_err:
189         ipc_coredump_get_list(ipc_devlink, rpsi_cmd_coredump_end);
190         return rc;
191 }
192
193 /* To create regions for coredump files */
194 static int ipc_devlink_create_region(struct iosm_devlink *devlink)
195 {
196         struct devlink_region_ops *mdm_coredump;
197         int rc = 0;
198         int i;
199
200         mdm_coredump = devlink->iosm_devlink_mdm_coredump;
201         for (i = 0; i < IOSM_NOF_CD_REGION; i++) {
202                 mdm_coredump[i].name = list[i].filename;
203                 mdm_coredump[i].snapshot = ipc_devlink_coredump_snapshot;
204                 mdm_coredump[i].destructor = vfree;
205                 devlink->cd_regions[i] =
206                         devlink_region_create(devlink->devlink_ctx,
207                                               &mdm_coredump[i], MAX_SNAPSHOTS,
208                                               list[i].default_size);
209
210                 if (IS_ERR(devlink->cd_regions[i])) {
211                         rc = PTR_ERR(devlink->cd_regions[i]);
212                         dev_err(devlink->dev, "Devlink region fail,err %d", rc);
213                         /* Delete previously created regions */
214                         for (i--; i >= 0; i--)
215                                 devlink_region_destroy(devlink->cd_regions[i]);
216                         goto region_create_fail;
217                 }
218                 list[i].entry = i;
219                 mdm_coredump[i].priv = list + i;
220         }
221 region_create_fail:
222         return rc;
223 }
224
225 /* To Destroy devlink regions */
226 static void ipc_devlink_destroy_region(struct iosm_devlink *ipc_devlink)
227 {
228         u8 i;
229
230         for (i = 0; i < IOSM_NOF_CD_REGION; i++)
231                 devlink_region_destroy(ipc_devlink->cd_regions[i]);
232 }
233
234 /**
235  * ipc_devlink_init - Initialize/register devlink to IOSM driver
236  * @ipc_imem:   Pointer to struct iosm_imem
237  *
238  * Returns:     Pointer to iosm_devlink on success and NULL on failure
239  */
240 struct iosm_devlink *ipc_devlink_init(struct iosm_imem *ipc_imem)
241 {
242         struct ipc_chnl_cfg chnl_cfg_flash = { 0 };
243         struct iosm_devlink *ipc_devlink;
244         struct devlink *devlink_ctx;
245         int rc;
246
247         devlink_ctx = devlink_alloc(&devlink_flash_ops,
248                                     sizeof(struct iosm_devlink),
249                                     ipc_imem->dev);
250         if (!devlink_ctx) {
251                 dev_err(ipc_imem->dev, "devlink_alloc failed");
252                 goto devlink_alloc_fail;
253         }
254
255         ipc_devlink = devlink_priv(devlink_ctx);
256         ipc_devlink->devlink_ctx = devlink_ctx;
257         ipc_devlink->pcie = ipc_imem->pcie;
258         ipc_devlink->dev = ipc_imem->dev;
259
260         rc = devlink_params_register(devlink_ctx, iosm_devlink_params,
261                                      ARRAY_SIZE(iosm_devlink_params));
262         if (rc) {
263                 dev_err(ipc_devlink->dev,
264                         "devlink_params_register failed. rc %d", rc);
265                 goto param_reg_fail;
266         }
267
268         ipc_devlink->cd_file_info = list;
269
270         rc = ipc_devlink_create_region(ipc_devlink);
271         if (rc) {
272                 dev_err(ipc_devlink->dev, "Devlink Region create failed, rc %d",
273                         rc);
274                 goto region_create_fail;
275         }
276
277         if (ipc_chnl_cfg_get(&chnl_cfg_flash, IPC_MEM_CTRL_CHL_ID_7) < 0)
278                 goto chnl_get_fail;
279
280         ipc_imem_channel_init(ipc_imem, IPC_CTYPE_CTRL,
281                               chnl_cfg_flash, IRQ_MOD_OFF);
282
283         init_completion(&ipc_devlink->devlink_sio.read_sem);
284         skb_queue_head_init(&ipc_devlink->devlink_sio.rx_list);
285
286         devlink_register(devlink_ctx);
287         dev_dbg(ipc_devlink->dev, "iosm devlink register success");
288
289         return ipc_devlink;
290
291 chnl_get_fail:
292         ipc_devlink_destroy_region(ipc_devlink);
293 region_create_fail:
294         devlink_params_unregister(devlink_ctx, iosm_devlink_params,
295                                   ARRAY_SIZE(iosm_devlink_params));
296 param_reg_fail:
297         devlink_free(devlink_ctx);
298 devlink_alloc_fail:
299         return NULL;
300 }
301
302 /**
303  * ipc_devlink_deinit - To unintialize the devlink from IOSM driver.
304  * @ipc_devlink:        Devlink instance
305  */
306 void ipc_devlink_deinit(struct iosm_devlink *ipc_devlink)
307 {
308         struct devlink *devlink_ctx = ipc_devlink->devlink_ctx;
309
310         devlink_unregister(devlink_ctx);
311         ipc_devlink_destroy_region(ipc_devlink);
312         devlink_params_unregister(devlink_ctx, iosm_devlink_params,
313                                   ARRAY_SIZE(iosm_devlink_params));
314         if (ipc_devlink->devlink_sio.devlink_read_pend) {
315                 complete(&ipc_devlink->devlink_sio.read_sem);
316                 complete(&ipc_devlink->devlink_sio.channel->ul_sem);
317         }
318         if (!ipc_devlink->devlink_sio.devlink_read_pend)
319                 skb_queue_purge(&ipc_devlink->devlink_sio.rx_list);
320
321         ipc_imem_sys_devlink_close(ipc_devlink);
322         devlink_free(devlink_ctx);
323 }
This page took 0.050178 seconds and 4 git commands to generate.