Linux Audio

Check our new training course

Loading...
Note: File does not exist in v5.9.
  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{
 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 */
 35static 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 */
 48static 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 */
 57static enum iosm_flash_comp_type
 58ipc_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 */
 78static 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 */
136static 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 */
148int 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 */
162static 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
188coredump_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 */
194static 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	}
221region_create_fail:
222	return rc;
223}
224
225/* To Destroy devlink regions */
226static 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 */
240struct 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
291chnl_get_fail:
292	ipc_devlink_destroy_region(ipc_devlink);
293region_create_fail:
294	devlink_params_unregister(devlink_ctx, iosm_devlink_params,
295				  ARRAY_SIZE(iosm_devlink_params));
296param_reg_fail:
297	devlink_free(devlink_ctx);
298devlink_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 */
306void 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}