Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (C) 2020-2021 Intel Corporation.
0004  */
0005 
0006 #include "iosm_ipc_chnl_cfg.h"
0007 #include "iosm_ipc_coredump.h"
0008 #include "iosm_ipc_devlink.h"
0009 #include "iosm_ipc_flash.h"
0010 
0011 /* Coredump list */
0012 static struct iosm_coredump_file_info list[IOSM_NOF_CD_REGION] = {
0013     {"report.json", REPORT_JSON_SIZE,},
0014     {"coredump.fcd", COREDUMP_FCD_SIZE,},
0015     {"cdd.log", CDD_LOG_SIZE,},
0016     {"eeprom.bin", EEPROM_BIN_SIZE,},
0017     {"bootcore_trace.bin", BOOTCORE_TRC_BIN_SIZE,},
0018     {"bootcore_prev_trace.bin", BOOTCORE_PREV_TRC_BIN_SIZE,},
0019 };
0020 
0021 /* Get the param values for the specific param ID's */
0022 static int ipc_devlink_get_param(struct devlink *dl, u32 id,
0023                  struct devlink_param_gset_ctx *ctx)
0024 {
0025     struct iosm_devlink *ipc_devlink = devlink_priv(dl);
0026 
0027     if (id == IOSM_DEVLINK_PARAM_ID_ERASE_FULL_FLASH)
0028         ctx->val.vu8 = ipc_devlink->param.erase_full_flash;
0029 
0030     return 0;
0031 }
0032 
0033 /* Set the param values for the specific param ID's */
0034 static int ipc_devlink_set_param(struct devlink *dl, u32 id,
0035                  struct devlink_param_gset_ctx *ctx)
0036 {
0037     struct iosm_devlink *ipc_devlink = devlink_priv(dl);
0038 
0039     if (id == IOSM_DEVLINK_PARAM_ID_ERASE_FULL_FLASH)
0040         ipc_devlink->param.erase_full_flash = ctx->val.vu8;
0041 
0042     return 0;
0043 }
0044 
0045 /* Devlink param structure array */
0046 static const struct devlink_param iosm_devlink_params[] = {
0047     DEVLINK_PARAM_DRIVER(IOSM_DEVLINK_PARAM_ID_ERASE_FULL_FLASH,
0048                  "erase_full_flash", DEVLINK_PARAM_TYPE_BOOL,
0049                  BIT(DEVLINK_PARAM_CMODE_RUNTIME),
0050                  ipc_devlink_get_param, ipc_devlink_set_param,
0051                  NULL),
0052 };
0053 
0054 /* Get devlink flash component type */
0055 static enum iosm_flash_comp_type
0056 ipc_devlink_get_flash_comp_type(const char comp_str[], u32 len)
0057 {
0058     enum iosm_flash_comp_type fls_type;
0059 
0060     if (!strncmp("PSI", comp_str, len))
0061         fls_type = FLASH_COMP_TYPE_PSI;
0062     else if (!strncmp("EBL", comp_str, len))
0063         fls_type = FLASH_COMP_TYPE_EBL;
0064     else if (!strncmp("FLS", comp_str, len))
0065         fls_type = FLASH_COMP_TYPE_FLS;
0066     else
0067         fls_type = FLASH_COMP_TYPE_INVAL;
0068 
0069     return fls_type;
0070 }
0071 
0072 /* Function triggered on devlink flash command
0073  * Flash update function which calls multiple functions based on
0074  * component type specified in the flash command
0075  */
0076 static int ipc_devlink_flash_update(struct devlink *devlink,
0077                     struct devlink_flash_update_params *params,
0078                     struct netlink_ext_ack *extack)
0079 {
0080     struct iosm_devlink *ipc_devlink = devlink_priv(devlink);
0081     enum iosm_flash_comp_type fls_type;
0082     struct iosm_devlink_image *header;
0083     int rc = -EINVAL;
0084     u8 *mdm_rsp;
0085 
0086     header = (struct iosm_devlink_image *)params->fw->data;
0087 
0088     if (!header || params->fw->size <= IOSM_DEVLINK_HDR_SIZE ||
0089         (memcmp(header->magic_header, IOSM_DEVLINK_MAGIC_HEADER,
0090          IOSM_DEVLINK_MAGIC_HEADER_LEN) != 0))
0091         return -EINVAL;
0092 
0093     mdm_rsp = kzalloc(IOSM_EBL_DW_PACK_SIZE, GFP_KERNEL);
0094     if (!mdm_rsp)
0095         return -ENOMEM;
0096 
0097     fls_type = ipc_devlink_get_flash_comp_type(header->image_type,
0098                            IOSM_DEVLINK_MAX_IMG_LEN);
0099 
0100     switch (fls_type) {
0101     case FLASH_COMP_TYPE_PSI:
0102         rc = ipc_flash_boot_psi(ipc_devlink, params->fw);
0103         break;
0104     case FLASH_COMP_TYPE_EBL:
0105         rc = ipc_flash_boot_ebl(ipc_devlink, params->fw);
0106         if (rc)
0107             break;
0108         rc = ipc_flash_boot_set_capabilities(ipc_devlink, mdm_rsp);
0109         if (rc)
0110             break;
0111         rc = ipc_flash_read_swid(ipc_devlink, mdm_rsp);
0112         break;
0113     case FLASH_COMP_TYPE_FLS:
0114         rc = ipc_flash_send_fls(ipc_devlink, params->fw, mdm_rsp);
0115         break;
0116     default:
0117         devlink_flash_update_status_notify(devlink, "Invalid component",
0118                            NULL, 0, 0);
0119         break;
0120     }
0121 
0122     if (!rc)
0123         devlink_flash_update_status_notify(devlink, "Flashing success",
0124                            header->image_type, 0, 0);
0125     else
0126         devlink_flash_update_status_notify(devlink, "Flashing failed",
0127                            header->image_type, 0, 0);
0128 
0129     kfree(mdm_rsp);
0130     return rc;
0131 }
0132 
0133 /* Call back function for devlink ops */
0134 static const struct devlink_ops devlink_flash_ops = {
0135     .flash_update = ipc_devlink_flash_update,
0136 };
0137 
0138 /**
0139  * ipc_devlink_send_cmd - Send command to Modem
0140  * @ipc_devlink: Pointer to struct iosm_devlink
0141  * @cmd:         Command to be sent to modem
0142  * @entry:       Command entry number
0143  *
0144  * Returns:      0 on success and failure value on error
0145  */
0146 int ipc_devlink_send_cmd(struct iosm_devlink *ipc_devlink, u16 cmd, u32 entry)
0147 {
0148     struct iosm_rpsi_cmd rpsi_cmd;
0149 
0150     rpsi_cmd.param.dword = cpu_to_le32(entry);
0151     rpsi_cmd.cmd = cpu_to_le16(cmd);
0152     rpsi_cmd.crc = rpsi_cmd.param.word[0] ^ rpsi_cmd.param.word[1] ^
0153                rpsi_cmd.cmd;
0154 
0155     return ipc_imem_sys_devlink_write(ipc_devlink, (u8 *)&rpsi_cmd,
0156                       sizeof(rpsi_cmd));
0157 }
0158 
0159 /* Function to create snapshot */
0160 static int ipc_devlink_coredump_snapshot(struct devlink *dl,
0161                      const struct devlink_region_ops *ops,
0162                      struct netlink_ext_ack *extack,
0163                      u8 **data)
0164 {
0165     struct iosm_devlink *ipc_devlink = devlink_priv(dl);
0166     struct iosm_coredump_file_info *cd_list = ops->priv;
0167     u32 region_size;
0168     int rc;
0169 
0170     dev_dbg(ipc_devlink->dev, "Region:%s, ID:%d", ops->name,
0171         cd_list->entry);
0172     region_size = cd_list->default_size;
0173     rc = ipc_coredump_collect(ipc_devlink, data, cd_list->entry,
0174                   region_size);
0175     if (rc) {
0176         dev_err(ipc_devlink->dev, "Fail to create snapshot,err %d", rc);
0177         goto coredump_collect_err;
0178     }
0179 
0180     /* Send coredump end cmd indicating end of coredump collection */
0181     if (cd_list->entry == (IOSM_NOF_CD_REGION - 1))
0182         ipc_coredump_get_list(ipc_devlink, rpsi_cmd_coredump_end);
0183 
0184     return 0;
0185 
0186 coredump_collect_err:
0187     ipc_coredump_get_list(ipc_devlink, rpsi_cmd_coredump_end);
0188     return rc;
0189 }
0190 
0191 /* To create regions for coredump files */
0192 static int ipc_devlink_create_region(struct iosm_devlink *devlink)
0193 {
0194     struct devlink_region_ops *mdm_coredump;
0195     int rc = 0;
0196     int i;
0197 
0198     mdm_coredump = devlink->iosm_devlink_mdm_coredump;
0199     for (i = 0; i < IOSM_NOF_CD_REGION; i++) {
0200         mdm_coredump[i].name = list[i].filename;
0201         mdm_coredump[i].snapshot = ipc_devlink_coredump_snapshot;
0202         mdm_coredump[i].destructor = vfree;
0203         devlink->cd_regions[i] =
0204             devlink_region_create(devlink->devlink_ctx,
0205                           &mdm_coredump[i], MAX_SNAPSHOTS,
0206                           list[i].default_size);
0207 
0208         if (IS_ERR(devlink->cd_regions[i])) {
0209             rc = PTR_ERR(devlink->cd_regions[i]);
0210             dev_err(devlink->dev, "Devlink region fail,err %d", rc);
0211             /* Delete previously created regions */
0212             for ( ; i >= 0; i--)
0213                 devlink_region_destroy(devlink->cd_regions[i]);
0214             goto region_create_fail;
0215         }
0216         list[i].entry = i;
0217         mdm_coredump[i].priv = list + i;
0218     }
0219 region_create_fail:
0220     return rc;
0221 }
0222 
0223 /* To Destroy devlink regions */
0224 static void ipc_devlink_destroy_region(struct iosm_devlink *ipc_devlink)
0225 {
0226     u8 i;
0227 
0228     for (i = 0; i < IOSM_NOF_CD_REGION; i++)
0229         devlink_region_destroy(ipc_devlink->cd_regions[i]);
0230 }
0231 
0232 /**
0233  * ipc_devlink_init - Initialize/register devlink to IOSM driver
0234  * @ipc_imem:   Pointer to struct iosm_imem
0235  *
0236  * Returns:     Pointer to iosm_devlink on success and NULL on failure
0237  */
0238 struct iosm_devlink *ipc_devlink_init(struct iosm_imem *ipc_imem)
0239 {
0240     struct ipc_chnl_cfg chnl_cfg_flash = { 0 };
0241     struct iosm_devlink *ipc_devlink;
0242     struct devlink *devlink_ctx;
0243     int rc;
0244 
0245     devlink_ctx = devlink_alloc(&devlink_flash_ops,
0246                     sizeof(struct iosm_devlink),
0247                     ipc_imem->dev);
0248     if (!devlink_ctx) {
0249         dev_err(ipc_imem->dev, "devlink_alloc failed");
0250         goto devlink_alloc_fail;
0251     }
0252 
0253     ipc_devlink = devlink_priv(devlink_ctx);
0254     ipc_devlink->devlink_ctx = devlink_ctx;
0255     ipc_devlink->pcie = ipc_imem->pcie;
0256     ipc_devlink->dev = ipc_imem->dev;
0257 
0258     rc = devlink_params_register(devlink_ctx, iosm_devlink_params,
0259                      ARRAY_SIZE(iosm_devlink_params));
0260     if (rc) {
0261         dev_err(ipc_devlink->dev,
0262             "devlink_params_register failed. rc %d", rc);
0263         goto param_reg_fail;
0264     }
0265 
0266     ipc_devlink->cd_file_info = list;
0267 
0268     rc = ipc_devlink_create_region(ipc_devlink);
0269     if (rc) {
0270         dev_err(ipc_devlink->dev, "Devlink Region create failed, rc %d",
0271             rc);
0272         goto region_create_fail;
0273     }
0274 
0275     if (ipc_chnl_cfg_get(&chnl_cfg_flash, IPC_MEM_CTRL_CHL_ID_7) < 0)
0276         goto chnl_get_fail;
0277 
0278     ipc_imem_channel_init(ipc_imem, IPC_CTYPE_CTRL,
0279                   chnl_cfg_flash, IRQ_MOD_OFF);
0280 
0281     init_completion(&ipc_devlink->devlink_sio.read_sem);
0282     skb_queue_head_init(&ipc_devlink->devlink_sio.rx_list);
0283 
0284     devlink_register(devlink_ctx);
0285     dev_dbg(ipc_devlink->dev, "iosm devlink register success");
0286 
0287     return ipc_devlink;
0288 
0289 chnl_get_fail:
0290     ipc_devlink_destroy_region(ipc_devlink);
0291 region_create_fail:
0292     devlink_params_unregister(devlink_ctx, iosm_devlink_params,
0293                   ARRAY_SIZE(iosm_devlink_params));
0294 param_reg_fail:
0295     devlink_free(devlink_ctx);
0296 devlink_alloc_fail:
0297     return NULL;
0298 }
0299 
0300 /**
0301  * ipc_devlink_deinit - To unintialize the devlink from IOSM driver.
0302  * @ipc_devlink:        Devlink instance
0303  */
0304 void ipc_devlink_deinit(struct iosm_devlink *ipc_devlink)
0305 {
0306     struct devlink *devlink_ctx = ipc_devlink->devlink_ctx;
0307 
0308     devlink_unregister(devlink_ctx);
0309     ipc_devlink_destroy_region(ipc_devlink);
0310     devlink_params_unregister(devlink_ctx, iosm_devlink_params,
0311                   ARRAY_SIZE(iosm_devlink_params));
0312     if (ipc_devlink->devlink_sio.devlink_read_pend) {
0313         complete(&ipc_devlink->devlink_sio.read_sem);
0314         complete(&ipc_devlink->devlink_sio.channel->ul_sem);
0315     }
0316     if (!ipc_devlink->devlink_sio.devlink_read_pend)
0317         skb_queue_purge(&ipc_devlink->devlink_sio.rx_list);
0318 
0319     ipc_imem_sys_devlink_close(ipc_devlink);
0320     devlink_free(devlink_ctx);
0321 }