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