0001
0002
0003
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
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
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
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
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
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
0073
0074
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
0134 static const struct devlink_ops devlink_flash_ops = {
0135 .flash_update = ipc_devlink_flash_update,
0136 };
0137
0138
0139
0140
0141
0142
0143
0144
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
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
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
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
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
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
0234
0235
0236
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
0302
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 }