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