cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

iosm_ipc_devlink.c (9182B)


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