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