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 */ 12 static 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 */ 22 static 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 */ 34 static 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 */ 46 static 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 */ 55 static enum iosm_flash_comp_type 56 ipc_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 */ 76 static 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 */ 134 static 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 */ 146 int 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 */ 160 static 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 186 coredump_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 */ 192 static 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 } 219 region_create_fail: 220 return rc; 221 } 222 223 /* To Destroy devlink regions */ 224 static 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 */ 238 struct 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 289 chnl_get_fail: 290 ipc_devlink_destroy_region(ipc_devlink); 291 region_create_fail: 292 devlink_params_unregister(devlink_ctx, iosm_devlink_params, 293 ARRAY_SIZE(iosm_devlink_params)); 294 param_reg_fail: 295 devlink_free(devlink_ctx); 296 devlink_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 */ 304 void 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 } 322