Commit 13bb8429 authored by M Chetan Kumar's avatar M Chetan Kumar Committed by David S. Miller
Browse files

net: wwan: iosm: firmware flashing and coredump collection



This patch brings-in support for M.2 7560 Device firmware flashing &
coredump collection using devlink.
- Driver Registers with Devlink framework.
- Register devlink params callback for configuring device params
  required in flashing or coredump flow.
- Implements devlink ops flash_update callback that programs modem
  firmware.
- Creates region & snapshot required for device coredump log collection.

On early detection of device in boot rom stage. Driver registers with
Devlink framework and establish transport channel for PSI (Primary Signed
Image) injection. Once PSI is injected to device, the device execution
stage details are read to determine whether device is in flash or
exception mode. The collected information is reported to devlink user
space application & based on this informationi, application proceeds with
either modem firmware flashing or coredump collection.

Signed-off-by: default avatarM Chetan Kumar <m.chetan.kumar@linux.intel.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 08c53aee
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -71,6 +71,7 @@ config RPMSG_WWAN_CTRL
config IOSM
	tristate "IOSM Driver for Intel M.2 WWAN Device"
	depends on INTEL_IOMMU
	select NET_DEVLINK
	help
	  This driver enables Intel M.2 WWAN Device communication.

+4 −1
Original line number Diff line number Diff line
@@ -18,6 +18,9 @@ iosm-y = \
	iosm_ipc_protocol.o		\
	iosm_ipc_protocol_ops.o	\
	iosm_ipc_mux.o			\
	iosm_ipc_mux_codec.o
	iosm_ipc_mux_codec.o		\
	iosm_ipc_devlink.o		\
	iosm_ipc_flash.o		\
	iosm_ipc_coredump.o

obj-$(CONFIG_IOSM) := iosm.o
+5 −1
Original line number Diff line number Diff line
@@ -8,7 +8,7 @@
#include "iosm_ipc_chnl_cfg.h"

/* Max. sizes of a downlink buffers */
#define IPC_MEM_MAX_DL_FLASH_BUF_SIZE (16 * 1024)
#define IPC_MEM_MAX_DL_FLASH_BUF_SIZE (64 * 1024)
#define IPC_MEM_MAX_DL_LOOPBACK_SIZE (1 * 1024 * 1024)
#define IPC_MEM_MAX_DL_AT_BUF_SIZE 2048
#define IPC_MEM_MAX_DL_RPC_BUF_SIZE (32 * 1024)
@@ -60,6 +60,10 @@ static struct ipc_chnl_cfg modem_cfg[] = {
	{ IPC_MEM_CTRL_CHL_ID_6, IPC_MEM_PIPE_12, IPC_MEM_PIPE_13,
	  IPC_MEM_MAX_TDS_MBIM, IPC_MEM_MAX_TDS_MBIM,
	  IPC_MEM_MAX_DL_MBIM_BUF_SIZE, WWAN_PORT_MBIM },
	/* Flash Channel/Coredump Channel */
	{ IPC_MEM_CTRL_CHL_ID_7, IPC_MEM_PIPE_0, IPC_MEM_PIPE_1,
	  IPC_MEM_MAX_TDS_FLASH_UL, IPC_MEM_MAX_TDS_FLASH_DL,
	  IPC_MEM_MAX_DL_FLASH_BUF_SIZE, WWAN_PORT_UNKNOWN },
};

int ipc_chnl_cfg_get(struct ipc_chnl_cfg *chnl_cfg, int index)
+1 −0
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ enum ipc_channel_id {
	IPC_MEM_CTRL_CHL_ID_4,
	IPC_MEM_CTRL_CHL_ID_5,
	IPC_MEM_CTRL_CHL_ID_6,
	IPC_MEM_CTRL_CHL_ID_7,
};

/**
+110 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright (C) 2020-2021 Intel Corporation.
 */

#include "iosm_ipc_coredump.h"

/* Collect coredump data from modem */
int ipc_coredump_collect(struct iosm_devlink *devlink, u8 **data, int entry,
			 u32 region_size)
{
	int ret, bytes_to_read, bytes_read = 0, i = 0;
	s32 remaining;
	u8 *data_ptr;

	data_ptr = vmalloc(region_size);
	if (!data_ptr)
		return -ENOMEM;

	remaining = devlink->cd_file_info[entry].actual_size;
	ret = ipc_devlink_send_cmd(devlink, rpsi_cmd_coredump_get, entry);
	if (ret) {
		dev_err(devlink->dev, "Send coredump_get cmd failed");
		goto get_cd_fail;
	}
	while (remaining > 0) {
		bytes_to_read = min(remaining, MAX_DATA_SIZE);
		bytes_read = 0;
		ret = ipc_imem_sys_devlink_read(devlink, data_ptr + i,
						bytes_to_read, &bytes_read);
		if (ret) {
			dev_err(devlink->dev, "CD data read failed");
			goto get_cd_fail;
		}
		remaining -= bytes_read;
		i += bytes_read;
	}

	*data = data_ptr;

	return ret;
get_cd_fail:
	vfree(data_ptr);
	return ret;
}

/* Get coredump list to be collected from modem */
int ipc_coredump_get_list(struct iosm_devlink *devlink, u16 cmd)
{
	u32 byte_read, num_entries, file_size;
	struct iosm_cd_table *cd_table;
	u8 size[MAX_SIZE_LEN], i;
	char *filename;
	int ret = 0;

	cd_table = kzalloc(MAX_CD_LIST_SIZE, GFP_KERNEL);
	if (!cd_table) {
		ret = -ENOMEM;
		goto  cd_init_fail;
	}

	ret = ipc_devlink_send_cmd(devlink, cmd, MAX_CD_LIST_SIZE);
	if (ret) {
		dev_err(devlink->dev, "rpsi_cmd_coredump_start failed");
		goto cd_init_fail;
	}

	ret = ipc_imem_sys_devlink_read(devlink, (u8 *)cd_table,
					MAX_CD_LIST_SIZE, &byte_read);
	if (ret) {
		dev_err(devlink->dev, "Coredump data is invalid");
		goto cd_init_fail;
	}

	if (byte_read != MAX_CD_LIST_SIZE)
		goto cd_init_fail;

	if (cmd == rpsi_cmd_coredump_start) {
		num_entries = le32_to_cpu(cd_table->list.num_entries);
		if (num_entries == 0 || num_entries > IOSM_NOF_CD_REGION) {
			ret = -EINVAL;
			goto cd_init_fail;
		}

		for (i = 0; i < num_entries; i++) {
			file_size = le32_to_cpu(cd_table->list.entry[i].size);
			filename = cd_table->list.entry[i].filename;

			if (file_size > devlink->cd_file_info[i].default_size) {
				ret = -EINVAL;
				goto cd_init_fail;
			}

			devlink->cd_file_info[i].actual_size = file_size;
			dev_dbg(devlink->dev, "file: %s actual size %d",
				filename, file_size);
			devlink_flash_update_status_notify(devlink->devlink_ctx,
							   filename,
							   "FILENAME", 0, 0);
			snprintf(size, sizeof(size), "%d", file_size);
			devlink_flash_update_status_notify(devlink->devlink_ctx,
							   size, "FILE SIZE",
							   0, 0);
		}
	}

cd_init_fail:
	kfree(cd_table);
	return ret;
}
Loading