File Index
Files and directories
Sign in
FILE

iosm_ipc_devlink.c

File preview with syntax highlighting.

linux-6.19.14/drivers/net/wwan/iosm/iosm_ipc_devlink.c 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 */
 13static 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 */
 23static 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 */
 36static 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 */
 49static 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 */
 58static enum iosm_flash_comp_type
 59ipc_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 */
 79static 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 */
137static 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 */
149int 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 */
163static 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
189coredump_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 */
195static 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	}
222region_create_fail:
223	return rc;
224}
225
226/* To Destroy devlink regions */
227static 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 */
241struct 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
292chnl_get_fail:
293	ipc_devlink_destroy_region(ipc_devlink);
294region_create_fail:
295	devlink_params_unregister(devlink_ctx, iosm_devlink_params,
296				  ARRAY_SIZE(iosm_devlink_params));
297param_reg_fail:
298	devlink_free(devlink_ctx);
299devlink_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 */
307void 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}
~/ Read-only file preview.