diff options
Diffstat (limited to 'drivers/net/wwan/iosm/iosm_ipc_flash.c')
-rw-r--r-- | drivers/net/wwan/iosm/iosm_ipc_flash.c | 562 |
1 files changed, 0 insertions, 562 deletions
diff --git a/drivers/net/wwan/iosm/iosm_ipc_flash.c b/drivers/net/wwan/iosm/iosm_ipc_flash.c deleted file mode 100644 index a43aafc70168..000000000000 --- a/drivers/net/wwan/iosm/iosm_ipc_flash.c +++ /dev/null @@ -1,562 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) 2020-2021 Intel Corporation. - */ - -#include "iosm_ipc_coredump.h" -#include "iosm_ipc_devlink.h" -#include "iosm_ipc_flash.h" - -/* This function will pack the data to be sent to the modem using the - * payload, payload length and pack id - */ -static int ipc_flash_proc_format_ebl_pack(struct iosm_flash_data *flash_req, - u32 pack_length, u16 pack_id, - u8 *payload, u32 payload_length) -{ - u16 checksum = pack_id; - u32 i; - - if (payload_length + IOSM_EBL_HEAD_SIZE > pack_length) - return -EINVAL; - - flash_req->pack_id = cpu_to_le16(pack_id); - flash_req->msg_length = cpu_to_le32(payload_length); - checksum += (payload_length >> IOSM_EBL_PAYL_SHIFT) + - (payload_length & IOSM_EBL_CKSM); - - for (i = 0; i < payload_length; i++) - checksum += payload[i]; - - flash_req->checksum = cpu_to_le16(checksum); - - return 0; -} - -/* validate the response received from modem and - * check the type of errors received - */ -static int ipc_flash_proc_check_ebl_rsp(void *hdr_rsp, void *payload_rsp) -{ - struct iosm_ebl_error *err_info = payload_rsp; - u16 *rsp_code = hdr_rsp; - int res = 0; - u32 i; - - if (*rsp_code == IOSM_EBL_RSP_BUFF) { - for (i = 0; i < IOSM_MAX_ERRORS; i++) { - if (!err_info->error[i].error_code) { - pr_err("EBL: error_class = %d, error_code = %d", - err_info->error[i].error_class, - err_info->error[i].error_code); - } - } - res = -EINVAL; - } - - return res; -} - -/* Send data to the modem */ -static int ipc_flash_send_data(struct iosm_devlink *ipc_devlink, u32 size, - u16 pack_id, u8 *payload, u32 payload_length) -{ - struct iosm_flash_data flash_req; - int ret; - - ret = ipc_flash_proc_format_ebl_pack(&flash_req, size, - pack_id, payload, payload_length); - if (ret) { - dev_err(ipc_devlink->dev, "EBL2 pack failed for pack_id:%d", - pack_id); - goto ipc_free_payload; - } - - ret = ipc_imem_sys_devlink_write(ipc_devlink, (u8 *)&flash_req, - IOSM_EBL_HEAD_SIZE); - if (ret) { - dev_err(ipc_devlink->dev, "EBL Header write failed for Id:%x", - pack_id); - goto ipc_free_payload; - } - - ret = ipc_imem_sys_devlink_write(ipc_devlink, payload, payload_length); - if (ret) { - dev_err(ipc_devlink->dev, "EBL Payload write failed for Id:%x", - pack_id); - } - -ipc_free_payload: - return ret; -} - -/* Allocate flash channel and read LER data from modem */ -int ipc_flash_link_establish(struct iosm_imem *ipc_imem) -{ - u8 ler_data[IOSM_LER_RSP_SIZE]; - u32 bytes_read; - - /* Allocate channel for flashing/cd collection */ - ipc_imem->ipc_devlink->devlink_sio.channel = - ipc_imem_sys_devlink_open(ipc_imem); - - if (!ipc_imem->ipc_devlink->devlink_sio.channel) - goto chl_open_fail; - - if (ipc_imem_sys_devlink_read(ipc_imem->ipc_devlink, ler_data, - IOSM_LER_RSP_SIZE, &bytes_read)) - goto devlink_read_fail; - - if (bytes_read != IOSM_LER_RSP_SIZE) - goto devlink_read_fail; - return 0; - -devlink_read_fail: - ipc_imem_sys_devlink_close(ipc_imem->ipc_devlink); -chl_open_fail: - return -EIO; -} - -/* Receive data from the modem */ -static int ipc_flash_receive_data(struct iosm_devlink *ipc_devlink, u32 size, - u8 *mdm_rsp) -{ - u8 mdm_rsp_hdr[IOSM_EBL_HEAD_SIZE]; - u32 bytes_read; - int ret; - - ret = ipc_imem_sys_devlink_read(ipc_devlink, mdm_rsp_hdr, - IOSM_EBL_HEAD_SIZE, &bytes_read); - if (ret) { - dev_err(ipc_devlink->dev, "EBL rsp to read %d bytes failed", - IOSM_EBL_HEAD_SIZE); - goto ipc_flash_recv_err; - } - - if (bytes_read != IOSM_EBL_HEAD_SIZE) { - ret = -EINVAL; - goto ipc_flash_recv_err; - } - - ret = ipc_imem_sys_devlink_read(ipc_devlink, mdm_rsp, size, - &bytes_read); - if (ret) { - dev_err(ipc_devlink->dev, "EBL rsp to read %d bytes failed", - size); - goto ipc_flash_recv_err; - } - - if (bytes_read != size) { - ret = -EINVAL; - goto ipc_flash_recv_err; - } - - ret = ipc_flash_proc_check_ebl_rsp(mdm_rsp_hdr + 2, mdm_rsp); - -ipc_flash_recv_err: - return ret; -} - -/* Function to send command to modem and receive response */ -static int ipc_flash_send_receive(struct iosm_devlink *ipc_devlink, u16 pack_id, - u8 *payload, u32 payload_length, u8 *mdm_rsp) -{ - size_t frame_len = IOSM_EBL_DW_PACK_SIZE; - int ret; - - if (pack_id == FLASH_SET_PROT_CONF) - frame_len = IOSM_EBL_W_PACK_SIZE; - - ret = ipc_flash_send_data(ipc_devlink, frame_len, pack_id, payload, - payload_length); - if (ret) - goto ipc_flash_send_rcv; - - ret = ipc_flash_receive_data(ipc_devlink, - frame_len - IOSM_EBL_HEAD_SIZE, mdm_rsp); - -ipc_flash_send_rcv: - return ret; -} - -/* Set the capabilities for the EBL */ -int ipc_flash_boot_set_capabilities(struct iosm_devlink *ipc_devlink, - u8 *mdm_rsp) -{ - int ret; - - ipc_devlink->ebl_ctx.ebl_sw_info_version = - ipc_devlink->ebl_ctx.m_ebl_resp[EBL_RSP_SW_INFO_VER]; - ipc_devlink->ebl_ctx.m_ebl_resp[EBL_SKIP_ERASE] = IOSM_CAP_NOT_ENHANCED; - ipc_devlink->ebl_ctx.m_ebl_resp[EBL_SKIP_CRC] = IOSM_CAP_NOT_ENHANCED; - - if (ipc_devlink->ebl_ctx.m_ebl_resp[EBL_CAPS_FLAG] & - IOSM_CAP_USE_EXT_CAP) { - if (ipc_devlink->param.erase_full_flash) - ipc_devlink->ebl_ctx.m_ebl_resp[EBL_OOS_CONFIG] &= - ~((u8)IOSM_EXT_CAP_ERASE_ALL); - else - ipc_devlink->ebl_ctx.m_ebl_resp[EBL_OOS_CONFIG] &= - ~((u8)IOSM_EXT_CAP_COMMIT_ALL); - ipc_devlink->ebl_ctx.m_ebl_resp[EBL_EXT_CAPS_HANDLED] = - IOSM_CAP_USE_EXT_CAP; - } - - /* Write back the EBL capability to modem - * Request Set Protcnf command - */ - ret = ipc_flash_send_receive(ipc_devlink, FLASH_SET_PROT_CONF, - ipc_devlink->ebl_ctx.m_ebl_resp, - IOSM_EBL_RSP_SIZE, mdm_rsp); - return ret; -} - -/* Read the SWID type and SWID value from the EBL */ -int ipc_flash_read_swid(struct iosm_devlink *ipc_devlink, u8 *mdm_rsp) -{ - struct iosm_flash_msg_control cmd_msg; - struct iosm_swid_table *swid; - char ebl_swid[IOSM_SWID_STR]; - int ret; - - if (ipc_devlink->ebl_ctx.ebl_sw_info_version != - IOSM_EXT_CAP_SWID_OOS_PACK) - return -EINVAL; - - cmd_msg.action = cpu_to_le32(FLASH_OOSC_ACTION_READ); - cmd_msg.type = cpu_to_le32(FLASH_OOSC_TYPE_SWID_TABLE); - cmd_msg.length = cpu_to_le32(IOSM_MSG_LEN_ARG); - cmd_msg.arguments = cpu_to_le32(IOSM_MSG_LEN_ARG); - - ret = ipc_flash_send_receive(ipc_devlink, FLASH_OOS_CONTROL, - (u8 *)&cmd_msg, IOSM_MDM_SEND_16, mdm_rsp); - if (ret) - goto ipc_swid_err; - - cmd_msg.action = cpu_to_le32(*((u32 *)mdm_rsp)); - - ret = ipc_flash_send_receive(ipc_devlink, FLASH_OOS_DATA_READ, - (u8 *)&cmd_msg, IOSM_MDM_SEND_4, mdm_rsp); - if (ret) - goto ipc_swid_err; - - swid = (struct iosm_swid_table *)mdm_rsp; - dev_dbg(ipc_devlink->dev, "SWID %x RF_ENGINE_ID %x", swid->sw_id_val, - swid->rf_engine_id_val); - - snprintf(ebl_swid, sizeof(ebl_swid), "SWID: %x, RF_ENGINE_ID: %x", - swid->sw_id_val, swid->rf_engine_id_val); - - devlink_flash_update_status_notify(ipc_devlink->devlink_ctx, ebl_swid, - NULL, 0, 0); -ipc_swid_err: - return ret; -} - -/* Function to check if full erase or conditional erase was successful */ -static int ipc_flash_erase_check(struct iosm_devlink *ipc_devlink, u8 *mdm_rsp) -{ - int ret, count = 0; - u16 mdm_rsp_data; - - /* Request Flash Erase Check */ - do { - mdm_rsp_data = IOSM_MDM_SEND_DATA; - ret = ipc_flash_send_receive(ipc_devlink, FLASH_ERASE_CHECK, - (u8 *)&mdm_rsp_data, - IOSM_MDM_SEND_2, mdm_rsp); - if (ret) - goto ipc_erase_chk_err; - - mdm_rsp_data = *((u16 *)mdm_rsp); - if (mdm_rsp_data > IOSM_MDM_ERASE_RSP) { - dev_err(ipc_devlink->dev, - "Flash Erase Check resp wrong 0x%04X", - mdm_rsp_data); - ret = -EINVAL; - goto ipc_erase_chk_err; - } - count++; - msleep(IOSM_FLASH_ERASE_CHECK_INTERVAL); - } while ((mdm_rsp_data != IOSM_MDM_ERASE_RSP) && - (count < (IOSM_FLASH_ERASE_CHECK_TIMEOUT / - IOSM_FLASH_ERASE_CHECK_INTERVAL))); - - if (mdm_rsp_data != IOSM_MDM_ERASE_RSP) { - dev_err(ipc_devlink->dev, "Modem erase check timeout failure!"); - ret = -ETIMEDOUT; - } - -ipc_erase_chk_err: - return ret; -} - -/* Full erase function which will erase the nand flash through EBL command */ -static int ipc_flash_full_erase(struct iosm_devlink *ipc_devlink, u8 *mdm_rsp) -{ - u32 erase_address = IOSM_ERASE_START_ADDR; - struct iosm_flash_msg_control cmd_msg; - u32 erase_length = IOSM_ERASE_LEN; - int ret; - - dev_dbg(ipc_devlink->dev, "Erase full nand flash"); - cmd_msg.action = cpu_to_le32(FLASH_OOSC_ACTION_ERASE); - cmd_msg.type = cpu_to_le32(FLASH_OOSC_TYPE_ALL_FLASH); - cmd_msg.length = cpu_to_le32(erase_length); - cmd_msg.arguments = cpu_to_le32(erase_address); - - ret = ipc_flash_send_receive(ipc_devlink, FLASH_OOS_CONTROL, - (unsigned char *)&cmd_msg, - IOSM_MDM_SEND_16, mdm_rsp); - if (ret) - goto ipc_flash_erase_err; - - ipc_devlink->param.erase_full_flash_done = IOSM_SET_FLAG; - ret = ipc_flash_erase_check(ipc_devlink, mdm_rsp); - -ipc_flash_erase_err: - return ret; -} - -/* Logic for flashing all the Loadmaps available for individual fls file */ -static int ipc_flash_download_region(struct iosm_devlink *ipc_devlink, - const struct firmware *fw, u8 *mdm_rsp) -{ - __le32 reg_info[2]; /* 0th position region address, 1st position size */ - char *file_ptr; - u32 rest_len; - u32 raw_len; - int ret; - - file_ptr = (char *)fw->data; - reg_info[0] = cpu_to_le32(ipc_devlink->param.address); - - if (!ipc_devlink->param.erase_full_flash_done) { - reg_info[1] = cpu_to_le32(ipc_devlink->param.address + - fw->size - 2); - ret = ipc_flash_send_receive(ipc_devlink, FLASH_ERASE_START, - (u8 *)reg_info, IOSM_MDM_SEND_8, - mdm_rsp); - if (ret) - goto dl_region_fail; - - ret = ipc_flash_erase_check(ipc_devlink, mdm_rsp); - if (ret) - goto dl_region_fail; - } - - /* Request Flash Set Address */ - ret = ipc_flash_send_receive(ipc_devlink, FLASH_SET_ADDRESS, - (u8 *)reg_info, IOSM_MDM_SEND_4, mdm_rsp); - if (ret) - goto dl_region_fail; - - rest_len = fw->size; - - /* Request Flash Write Raw Image */ - ret = ipc_flash_send_data(ipc_devlink, IOSM_EBL_DW_PACK_SIZE, - FLASH_WRITE_IMAGE_RAW, (u8 *)&rest_len, - IOSM_MDM_SEND_4); - if (ret) - goto dl_region_fail; - - do { - raw_len = (rest_len > IOSM_FLS_BUF_SIZE) ? IOSM_FLS_BUF_SIZE : - rest_len; - ret = ipc_imem_sys_devlink_write(ipc_devlink, file_ptr, - raw_len); - if (ret) { - dev_err(ipc_devlink->dev, "Image write failed"); - goto dl_region_fail; - } - file_ptr += raw_len; - rest_len -= raw_len; - } while (rest_len); - - ret = ipc_flash_receive_data(ipc_devlink, IOSM_EBL_DW_PAYL_SIZE, - mdm_rsp); - -dl_region_fail: - return ret; -} - -/* Flash the individual fls files */ -int ipc_flash_send_fls(struct iosm_devlink *ipc_devlink, - const struct firmware *fw, u8 *mdm_rsp) -{ - u16 flash_cmd; - int ret; - - if (ipc_devlink->param.erase_full_flash) { - ipc_devlink->param.erase_full_flash = false; - ret = ipc_flash_full_erase(ipc_devlink, mdm_rsp); - if (ret) - goto ipc_flash_err; - } - - /* Request Sec Start */ - if (!ipc_devlink->param.download_region) { - ret = ipc_flash_send_receive(ipc_devlink, FLASH_SEC_START, - (u8 *)fw->data, fw->size, mdm_rsp); - if (ret) - goto ipc_flash_err; - } else { - /* Download regions */ - ipc_devlink->param.region_count -= IOSM_SET_FLAG; - ret = ipc_flash_download_region(ipc_devlink, fw, mdm_rsp); - if (ret) - goto ipc_flash_err; - - if (!ipc_devlink->param.region_count) { - /* Request Sec End */ - flash_cmd = IOSM_MDM_SEND_DATA; - ret = ipc_flash_send_receive(ipc_devlink, FLASH_SEC_END, - (u8 *)&flash_cmd, - IOSM_MDM_SEND_2, mdm_rsp); - } - } - -ipc_flash_err: - return ret; -} - -/* Inject RPSI */ -int ipc_flash_boot_psi(struct iosm_devlink *ipc_devlink, - const struct firmware *fw) -{ - u8 psi_ack_byte[IOSM_PSI_ACK], read_data[2]; - u32 bytes_read; - u8 *psi_code; - int ret; - - dev_dbg(ipc_devlink->dev, "Boot transfer PSI"); - psi_code = kzalloc(fw->size, GFP_KERNEL); - if (!psi_code) - return -ENOMEM; - - memcpy(psi_code, fw->data, fw->size); - ret = ipc_imem_sys_devlink_write(ipc_devlink, psi_code, fw->size); - if (ret) { - dev_err(ipc_devlink->dev, "RPSI Image write failed"); - goto ipc_flash_psi_free; - } - - ret = ipc_imem_sys_devlink_read(ipc_devlink, read_data, - IOSM_LER_ACK_SIZE, &bytes_read); - if (ret) { - dev_err(ipc_devlink->dev, "ipc_devlink_sio_read ACK failed"); - goto ipc_flash_psi_free; - } - - if (bytes_read != IOSM_LER_ACK_SIZE) { - ret = -EINVAL; - goto ipc_flash_psi_free; - } - - snprintf(psi_ack_byte, sizeof(psi_ack_byte), "%x%x", read_data[0], - read_data[1]); - devlink_flash_update_status_notify(ipc_devlink->devlink_ctx, - psi_ack_byte, "PSI ACK", 0, 0); - - if (read_data[0] == 0x00 && read_data[1] == 0xCD) { - dev_dbg(ipc_devlink->dev, "Coredump detected"); - ret = ipc_coredump_get_list(ipc_devlink, - rpsi_cmd_coredump_start); - if (ret) - dev_err(ipc_devlink->dev, "Failed to get cd list"); - } - -ipc_flash_psi_free: - kfree(psi_code); - return ret; -} - -/* Inject EBL */ -int ipc_flash_boot_ebl(struct iosm_devlink *ipc_devlink, - const struct firmware *fw) -{ - u32 ebl_size = fw->size; - u8 read_data[2]; - u32 bytes_read; - int ret; - - if (ipc_mmio_get_exec_stage(ipc_devlink->pcie->imem->mmio) != - IPC_MEM_EXEC_STAGE_PSI) { - devlink_flash_update_status_notify(ipc_devlink->devlink_ctx, - "Invalid execution stage", - NULL, 0, 0); - return -EINVAL; - } - - dev_dbg(ipc_devlink->dev, "Boot transfer EBL"); - ret = ipc_devlink_send_cmd(ipc_devlink, rpsi_cmd_code_ebl, - IOSM_RPSI_LOAD_SIZE); - if (ret) { - dev_err(ipc_devlink->dev, "Sending rpsi_cmd_code_ebl failed"); - goto ipc_flash_ebl_err; - } - - ret = ipc_imem_sys_devlink_read(ipc_devlink, read_data, IOSM_READ_SIZE, - &bytes_read); - if (ret) { - dev_err(ipc_devlink->dev, "rpsi_cmd_code_ebl read failed"); - goto ipc_flash_ebl_err; - } - - if (bytes_read != IOSM_READ_SIZE) { - ret = -EINVAL; - goto ipc_flash_ebl_err; - } - - ret = ipc_imem_sys_devlink_write(ipc_devlink, (u8 *)&ebl_size, - sizeof(ebl_size)); - if (ret) { - dev_err(ipc_devlink->dev, "EBL length write failed"); - goto ipc_flash_ebl_err; - } - - ret = ipc_imem_sys_devlink_read(ipc_devlink, read_data, IOSM_READ_SIZE, - &bytes_read); - if (ret) { - dev_err(ipc_devlink->dev, "EBL read failed"); - goto ipc_flash_ebl_err; - } - - if (bytes_read != IOSM_READ_SIZE) { - ret = -EINVAL; - goto ipc_flash_ebl_err; - } - - ret = ipc_imem_sys_devlink_write(ipc_devlink, (unsigned char *)fw->data, - fw->size); - if (ret) { - dev_err(ipc_devlink->dev, "EBL data transfer failed"); - goto ipc_flash_ebl_err; - } - - ret = ipc_imem_sys_devlink_read(ipc_devlink, read_data, IOSM_READ_SIZE, - &bytes_read); - if (ret) { - dev_err(ipc_devlink->dev, "EBL read failed"); - goto ipc_flash_ebl_err; - } - - if (bytes_read != IOSM_READ_SIZE) { - ret = -EINVAL; - goto ipc_flash_ebl_err; - } - - ret = ipc_imem_sys_devlink_read(ipc_devlink, - ipc_devlink->ebl_ctx.m_ebl_resp, - IOSM_EBL_RSP_SIZE, &bytes_read); - if (ret) { - dev_err(ipc_devlink->dev, "EBL response read failed"); - goto ipc_flash_ebl_err; - } - - if (bytes_read != IOSM_EBL_RSP_SIZE) - ret = -EINVAL; - -ipc_flash_ebl_err: - return ret; -} |