Skip to content

Commit 4dcd183

Browse files
mchetankumardavem330
authored andcommitted
net: wwan: iosm: devlink registration
Register with devlink framework and implment callbacks required for fw flashing and coredump collection. Signed-off-by: M Chetan Kumar <m.chetan.kumar@linux.intel.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent d44fd86 commit 4dcd183

File tree

2 files changed

+570
-0
lines changed

2 files changed

+570
-0
lines changed
Lines changed: 363 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,363 @@
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+
int rc = 0;
27+
28+
switch (id) {
29+
case IOSM_DEVLINK_PARAM_ID_ERASE_FULL_FLASH:
30+
ctx->val.vu8 = ipc_devlink->param.erase_full_flash;
31+
break;
32+
33+
case IOSM_DEVLINK_PARAM_ID_DOWNLOAD_REGION:
34+
ctx->val.vu8 = ipc_devlink->param.download_region;
35+
break;
36+
37+
case IOSM_DEVLINK_PARAM_ID_ADDRESS:
38+
ctx->val.vu32 = ipc_devlink->param.address;
39+
break;
40+
41+
case IOSM_DEVLINK_PARAM_ID_REGION_COUNT:
42+
ctx->val.vu8 = ipc_devlink->param.region_count;
43+
break;
44+
45+
default:
46+
rc = -EOPNOTSUPP;
47+
break;
48+
}
49+
50+
return rc;
51+
}
52+
53+
/* Set the param values for the specific param ID's */
54+
static int ipc_devlink_set_param(struct devlink *dl, u32 id,
55+
struct devlink_param_gset_ctx *ctx)
56+
{
57+
struct iosm_devlink *ipc_devlink = devlink_priv(dl);
58+
int rc = 0;
59+
60+
switch (id) {
61+
case IOSM_DEVLINK_PARAM_ID_ERASE_FULL_FLASH:
62+
ipc_devlink->param.erase_full_flash = ctx->val.vu8;
63+
break;
64+
65+
case IOSM_DEVLINK_PARAM_ID_DOWNLOAD_REGION:
66+
ipc_devlink->param.download_region = ctx->val.vu8;
67+
break;
68+
69+
case IOSM_DEVLINK_PARAM_ID_ADDRESS:
70+
ipc_devlink->param.address = ctx->val.vu32;
71+
break;
72+
73+
case IOSM_DEVLINK_PARAM_ID_REGION_COUNT:
74+
ipc_devlink->param.region_count = ctx->val.vu8;
75+
break;
76+
77+
default:
78+
rc = -EOPNOTSUPP;
79+
break;
80+
}
81+
82+
return rc;
83+
}
84+
85+
/* Devlink param structure array */
86+
static const struct devlink_param iosm_devlink_params[] = {
87+
DEVLINK_PARAM_DRIVER(IOSM_DEVLINK_PARAM_ID_ERASE_FULL_FLASH,
88+
"erase_full_flash", DEVLINK_PARAM_TYPE_BOOL,
89+
BIT(DEVLINK_PARAM_CMODE_RUNTIME),
90+
ipc_devlink_get_param, ipc_devlink_set_param,
91+
NULL),
92+
DEVLINK_PARAM_DRIVER(IOSM_DEVLINK_PARAM_ID_DOWNLOAD_REGION,
93+
"download_region", DEVLINK_PARAM_TYPE_BOOL,
94+
BIT(DEVLINK_PARAM_CMODE_RUNTIME),
95+
ipc_devlink_get_param, ipc_devlink_set_param,
96+
NULL),
97+
DEVLINK_PARAM_DRIVER(IOSM_DEVLINK_PARAM_ID_ADDRESS,
98+
"address", DEVLINK_PARAM_TYPE_U32,
99+
BIT(DEVLINK_PARAM_CMODE_RUNTIME),
100+
ipc_devlink_get_param, ipc_devlink_set_param,
101+
NULL),
102+
DEVLINK_PARAM_DRIVER(IOSM_DEVLINK_PARAM_ID_REGION_COUNT,
103+
"region_count", DEVLINK_PARAM_TYPE_U8,
104+
BIT(DEVLINK_PARAM_CMODE_RUNTIME),
105+
ipc_devlink_get_param, ipc_devlink_set_param,
106+
NULL),
107+
};
108+
109+
/* Get devlink flash component type */
110+
static enum iosm_flash_comp_type
111+
ipc_devlink_get_flash_comp_type(const char comp_str[], u32 len)
112+
{
113+
enum iosm_flash_comp_type fls_type;
114+
115+
if (!strncmp("PSI", comp_str, len))
116+
fls_type = FLASH_COMP_TYPE_PSI;
117+
else if (!strncmp("EBL", comp_str, len))
118+
fls_type = FLASH_COMP_TYPE_EBL;
119+
else if (!strncmp("FLS", comp_str, len))
120+
fls_type = FLASH_COMP_TYPE_FLS;
121+
else
122+
fls_type = FLASH_COMP_TYPE_INVAL;
123+
124+
return fls_type;
125+
}
126+
127+
/* Function triggered on devlink flash command
128+
* Flash update function which calls multiple functions based on
129+
* component type specified in the flash command
130+
*/
131+
static int ipc_devlink_flash_update(struct devlink *devlink,
132+
struct devlink_flash_update_params *params,
133+
struct netlink_ext_ack *extack)
134+
{
135+
struct iosm_devlink *ipc_devlink = devlink_priv(devlink);
136+
enum iosm_flash_comp_type fls_type;
137+
u32 rc = -EINVAL;
138+
u8 *mdm_rsp;
139+
140+
if (!params->component)
141+
return rc;
142+
143+
mdm_rsp = kzalloc(IOSM_EBL_DW_PACK_SIZE, GFP_KERNEL);
144+
if (!mdm_rsp)
145+
return -ENOMEM;
146+
147+
fls_type = ipc_devlink_get_flash_comp_type(params->component,
148+
strlen(params->component));
149+
150+
switch (fls_type) {
151+
case FLASH_COMP_TYPE_PSI:
152+
rc = ipc_flash_boot_psi(ipc_devlink, params->fw);
153+
break;
154+
case FLASH_COMP_TYPE_EBL:
155+
rc = ipc_flash_boot_ebl(ipc_devlink, params->fw);
156+
if (!rc)
157+
rc = ipc_flash_boot_set_capabilities(ipc_devlink,
158+
mdm_rsp);
159+
if (!rc)
160+
rc = ipc_flash_read_swid(ipc_devlink, mdm_rsp);
161+
break;
162+
case FLASH_COMP_TYPE_FLS:
163+
rc = ipc_flash_send_fls(ipc_devlink, params->fw, mdm_rsp);
164+
break;
165+
default:
166+
devlink_flash_update_status_notify(devlink, "Invalid component",
167+
params->component, 0, 0);
168+
break;
169+
}
170+
171+
if (!rc)
172+
devlink_flash_update_status_notify(devlink, "Flashing success",
173+
params->component, 0, 0);
174+
else
175+
devlink_flash_update_status_notify(devlink, "Flashing failed",
176+
params->component, 0, 0);
177+
178+
kfree(mdm_rsp);
179+
return rc;
180+
}
181+
182+
/* Call back function for devlink ops */
183+
static const struct devlink_ops devlink_flash_ops = {
184+
.supported_flash_update_params = DEVLINK_SUPPORT_FLASH_UPDATE_COMPONENT,
185+
.flash_update = ipc_devlink_flash_update,
186+
};
187+
188+
/* Send command to modem to collect data */
189+
int ipc_devlink_send_cmd(struct iosm_devlink *ipc_devlink, u16 cmd, u32 entry)
190+
{
191+
struct iosm_rpsi_cmd rpsi_cmd;
192+
193+
rpsi_cmd.param.dword = cpu_to_le32(entry);
194+
rpsi_cmd.cmd = cpu_to_le16(cmd);
195+
rpsi_cmd.crc = rpsi_cmd.param.word[0] ^ rpsi_cmd.param.word[1] ^
196+
rpsi_cmd.cmd;
197+
198+
return ipc_imem_sys_devlink_write(ipc_devlink, (u8 *)&rpsi_cmd,
199+
sizeof(rpsi_cmd));
200+
}
201+
202+
static int ipc_devlink_coredump_snapshot(struct devlink *dl,
203+
const struct devlink_region_ops *ops,
204+
struct netlink_ext_ack *extack,
205+
u8 **data)
206+
{
207+
struct iosm_devlink *ipc_devlink = devlink_priv(dl);
208+
struct iosm_coredump_file_info *cd_list = ops->priv;
209+
u32 region_size;
210+
int rc;
211+
212+
dev_dbg(ipc_devlink->dev, "Region:%s, ID:%d", ops->name,
213+
cd_list->entry);
214+
region_size = cd_list->default_size;
215+
rc = ipc_coredump_collect(ipc_devlink, data, cd_list->entry,
216+
region_size);
217+
if (rc) {
218+
dev_err(ipc_devlink->dev, "Fail to create snapshot,err %d", rc);
219+
goto coredump_collect_err;
220+
}
221+
222+
/* Send coredump end cmd indicating end of coredump collection */
223+
if (cd_list->entry == (IOSM_NOF_CD_REGION - 1))
224+
ipc_coredump_get_list(ipc_devlink, rpsi_cmd_coredump_end);
225+
226+
return rc;
227+
coredump_collect_err:
228+
ipc_coredump_get_list(ipc_devlink, rpsi_cmd_coredump_end);
229+
return rc;
230+
}
231+
232+
/* To create regions for coredump files */
233+
static int ipc_devlink_create_region(struct iosm_devlink *devlink)
234+
{
235+
struct devlink_region_ops *mdm_coredump;
236+
int rc = 0;
237+
int i;
238+
239+
mdm_coredump = devlink->iosm_devlink_mdm_coredump;
240+
for (i = 0; i < IOSM_NOF_CD_REGION; i++) {
241+
mdm_coredump[i].name = list[i].filename;
242+
mdm_coredump[i].snapshot = ipc_devlink_coredump_snapshot;
243+
mdm_coredump[i].destructor = vfree;
244+
devlink->cd_regions[i] =
245+
devlink_region_create(devlink->devlink_ctx,
246+
&mdm_coredump[i], MAX_SNAPSHOTS,
247+
list[i].default_size);
248+
249+
if (IS_ERR(devlink->cd_regions[i])) {
250+
rc = PTR_ERR(devlink->cd_regions[i]);
251+
dev_err(devlink->dev, "Devlink region fail,err %d", rc);
252+
/* Delete previously created regions */
253+
for ( ; i >= 0; i--)
254+
devlink_region_destroy(devlink->cd_regions[i]);
255+
goto region_create_fail;
256+
}
257+
list[i].entry = i;
258+
mdm_coredump[i].priv = list + i;
259+
}
260+
region_create_fail:
261+
return rc;
262+
}
263+
264+
/* To Destroy devlink regions */
265+
static void ipc_devlink_destroy_region(struct iosm_devlink *ipc_devlink)
266+
{
267+
u8 i;
268+
269+
for (i = 0; i < IOSM_NOF_CD_REGION; i++)
270+
devlink_region_destroy(ipc_devlink->cd_regions[i]);
271+
}
272+
273+
/* Handle registration to devlink framework */
274+
struct iosm_devlink *ipc_devlink_init(struct iosm_imem *ipc_imem)
275+
{
276+
struct ipc_chnl_cfg chnl_cfg_flash = { 0 };
277+
struct iosm_devlink *ipc_devlink;
278+
struct devlink *devlink_ctx;
279+
int rc;
280+
281+
devlink_ctx = devlink_alloc(&devlink_flash_ops,
282+
sizeof(struct iosm_devlink),
283+
ipc_imem->dev);
284+
if (!devlink_ctx) {
285+
dev_err(ipc_imem->dev, "devlink_alloc failed");
286+
goto devlink_alloc_fail;
287+
}
288+
289+
ipc_devlink = devlink_priv(devlink_ctx);
290+
ipc_devlink->devlink_ctx = devlink_ctx;
291+
ipc_devlink->pcie = ipc_imem->pcie;
292+
ipc_devlink->dev = ipc_imem->dev;
293+
rc = devlink_register(devlink_ctx);
294+
if (rc) {
295+
dev_err(ipc_devlink->dev, "devlink_register failed rc %d", rc);
296+
goto free_dl;
297+
}
298+
299+
rc = devlink_params_register(devlink_ctx, iosm_devlink_params,
300+
ARRAY_SIZE(iosm_devlink_params));
301+
if (rc) {
302+
dev_err(ipc_devlink->dev,
303+
"devlink_params_register failed. rc %d", rc);
304+
goto param_reg_fail;
305+
}
306+
307+
devlink_params_publish(devlink_ctx);
308+
ipc_devlink->cd_file_info = list;
309+
310+
rc = ipc_devlink_create_region(ipc_devlink);
311+
if (rc) {
312+
dev_err(ipc_devlink->dev, "Devlink Region create failed, rc %d",
313+
rc);
314+
goto region_create_fail;
315+
}
316+
317+
if (ipc_chnl_cfg_get(&chnl_cfg_flash, IPC_MEM_CTRL_CHL_ID_7) < 0)
318+
goto chnl_get_fail;
319+
320+
ipc_imem_channel_init(ipc_imem, IPC_CTYPE_CTRL,
321+
chnl_cfg_flash, IRQ_MOD_OFF);
322+
323+
init_completion(&ipc_devlink->devlink_sio.read_sem);
324+
skb_queue_head_init(&ipc_devlink->devlink_sio.rx_list);
325+
326+
dev_dbg(ipc_devlink->dev, "iosm devlink register success");
327+
328+
return ipc_devlink;
329+
330+
chnl_get_fail:
331+
ipc_devlink_destroy_region(ipc_devlink);
332+
region_create_fail:
333+
devlink_params_unpublish(devlink_ctx);
334+
devlink_params_unregister(devlink_ctx, iosm_devlink_params,
335+
ARRAY_SIZE(iosm_devlink_params));
336+
param_reg_fail:
337+
devlink_unregister(devlink_ctx);
338+
free_dl:
339+
devlink_free(devlink_ctx);
340+
devlink_alloc_fail:
341+
return NULL;
342+
}
343+
344+
/* Handle unregistration of devlink */
345+
void ipc_devlink_deinit(struct iosm_devlink *ipc_devlink)
346+
{
347+
struct devlink *devlink_ctx = ipc_devlink->devlink_ctx;
348+
349+
ipc_devlink_destroy_region(ipc_devlink);
350+
devlink_params_unpublish(devlink_ctx);
351+
devlink_params_unregister(devlink_ctx, iosm_devlink_params,
352+
ARRAY_SIZE(iosm_devlink_params));
353+
if (ipc_devlink->devlink_sio.devlink_read_pend) {
354+
complete(&ipc_devlink->devlink_sio.read_sem);
355+
complete(&ipc_devlink->devlink_sio.channel->ul_sem);
356+
}
357+
if (!ipc_devlink->devlink_sio.devlink_read_pend)
358+
skb_queue_purge(&ipc_devlink->devlink_sio.rx_list);
359+
360+
ipc_imem_sys_devlink_close(ipc_devlink);
361+
devlink_unregister(devlink_ctx);
362+
devlink_free(devlink_ctx);
363+
}

0 commit comments

Comments
 (0)