summaryrefslogtreecommitdiff
path: root/drivers/net/wwan/iosm/iosm_ipc_flash.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wwan/iosm/iosm_ipc_flash.c')
-rw-r--r--drivers/net/wwan/iosm/iosm_ipc_flash.c562
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;
-}