Loading drivers/platform/msm/ipa/ipa_v3/ipa.c +58 −108 Original line number Diff line number Diff line Loading @@ -1647,39 +1647,40 @@ static void ipa3_destroy_imm(void *user1, int user2) ipahal_destroy_imm_cmd(user1); } static int ipa3_q6_pipe_delay(void) static void ipa3_q6_pipe_delay(bool delay) { int client_idx; int ep_idx; struct ipa_ep_cfg_ctrl ep_ctrl; memset(&ep_ctrl, 0, sizeof(struct ipa_ep_cfg_ctrl)); ep_ctrl.ipa_ep_delay = delay; for (client_idx = 0; client_idx < IPA_CLIENT_MAX; client_idx++) { if (IPA_CLIENT_IS_Q6_PROD(client_idx)) { ep_idx = ipa3_get_ep_mapping(client_idx); if (ep_idx == -1) continue; ep_ctrl.ipa_ep_delay = 1; ipahal_write_reg_n_fields(IPA_ENDP_INIT_CTRL_n, ep_idx, &ep_ctrl); } } return 0; } static int ipa3_q6_avoid_holb(void) static void ipa3_q6_avoid_holb(void) { int ep_idx; int client_idx; struct ipa_ep_cfg_ctrl avoid_holb; struct ipa_ep_cfg_ctrl ep_suspend; struct ipa_ep_cfg_holb ep_holb; memset(&avoid_holb, 0, sizeof(avoid_holb)); memset(&ep_suspend, 0, sizeof(ep_suspend)); memset(&ep_holb, 0, sizeof(ep_holb)); avoid_holb.ipa_ep_suspend = true; ep_suspend.ipa_ep_suspend = true; ep_holb.tmr_val = 0; ep_holb.en = 1; for (client_idx = 0; client_idx < IPA_CLIENT_MAX; client_idx++) { if (IPA_CLIENT_IS_Q6_CONS(client_idx)) { Loading @@ -1693,8 +1694,6 @@ static int ipa3_q6_avoid_holb(void) * they are not valid, therefore, the above function * will fail. */ ep_holb.tmr_val = 0; ep_holb.en = 1; ipahal_write_reg_n_fields( IPA_ENDP_INIT_HOL_BLOCK_TIMER_n, ep_idx, &ep_holb); Loading @@ -1702,11 +1701,11 @@ static int ipa3_q6_avoid_holb(void) IPA_ENDP_INIT_HOL_BLOCK_EN_n, ep_idx, &ep_holb); ipa3_cfg_ep_ctrl(ep_idx, &avoid_holb); ipahal_write_reg_n_fields( IPA_ENDP_INIT_CTRL_n, ep_idx, &ep_suspend); } } return 0; } static u32 ipa3_get_max_flt_rt_cmds(u32 num_pipes) Loading Loading @@ -1785,8 +1784,7 @@ static int ipa3_q6_clean_q6_tables(void) */ cmd.is_read = false; cmd.skip_pipeline_clear = 0; cmd.pipeline_clear_options = IPAHAL_FULL_PIPELINE_CLEAR; cmd.pipeline_clear_options = IPAHAL_HPS_CLEAR; cmd.size = mem.size; cmd.system_addr = mem.phys_base; cmd.local_addr = Loading @@ -1810,8 +1808,7 @@ static int ipa3_q6_clean_q6_tables(void) cmd.is_read = false; cmd.skip_pipeline_clear = false; cmd.pipeline_clear_options = IPAHAL_FULL_PIPELINE_CLEAR; cmd.pipeline_clear_options = IPAHAL_HPS_CLEAR; cmd.size = mem.size; cmd.system_addr = mem.phys_base; cmd.local_addr = Loading Loading @@ -1839,8 +1836,7 @@ static int ipa3_q6_clean_q6_tables(void) */ cmd.is_read = false; cmd.skip_pipeline_clear = false; cmd.pipeline_clear_options = IPAHAL_FULL_PIPELINE_CLEAR; cmd.pipeline_clear_options = IPAHAL_HPS_CLEAR; cmd.size = mem.size; cmd.system_addr = mem.phys_base; cmd.local_addr = Loading @@ -1864,8 +1860,7 @@ static int ipa3_q6_clean_q6_tables(void) cmd.is_read = false; cmd.skip_pipeline_clear = 0; cmd.pipeline_clear_options = IPAHAL_FULL_PIPELINE_CLEAR; cmd.pipeline_clear_options = IPAHAL_HPS_CLEAR; cmd.size = mem.size; cmd.system_addr = mem.phys_base; cmd.local_addr = Loading Loading @@ -1897,7 +1892,7 @@ static int ipa3_q6_clean_q6_tables(void) index++) { cmd.is_read = false; cmd.skip_pipeline_clear = false; cmd.pipeline_clear_options = IPAHAL_FULL_PIPELINE_CLEAR; cmd.pipeline_clear_options = IPAHAL_HPS_CLEAR; cmd.size = mem.size; cmd.system_addr = mem.phys_base; cmd.local_addr = ipa3_ctx->smem_restricted_bytes + Loading @@ -1919,7 +1914,7 @@ static int ipa3_q6_clean_q6_tables(void) cmd.is_read = false; cmd.skip_pipeline_clear = false; cmd.pipeline_clear_options = IPAHAL_FULL_PIPELINE_CLEAR; cmd.pipeline_clear_options = IPAHAL_HPS_CLEAR; cmd.size = mem.size; cmd.system_addr = mem.phys_base; cmd.local_addr = ipa3_ctx->smem_restricted_bytes + Loading @@ -1945,8 +1940,7 @@ static int ipa3_q6_clean_q6_tables(void) index++) { cmd.is_read = false; cmd.skip_pipeline_clear = false; cmd.pipeline_clear_options = IPAHAL_FULL_PIPELINE_CLEAR; cmd.pipeline_clear_options = IPAHAL_HPS_CLEAR; cmd.size = mem.size; cmd.system_addr = mem.phys_base; cmd.local_addr = ipa3_ctx->smem_restricted_bytes + Loading @@ -1968,8 +1962,7 @@ static int ipa3_q6_clean_q6_tables(void) cmd.is_read = false; cmd.skip_pipeline_clear = false; cmd.pipeline_clear_options = IPAHAL_FULL_PIPELINE_CLEAR; cmd.pipeline_clear_options = IPAHAL_HPS_CLEAR; cmd.size = mem.size; cmd.system_addr = mem.phys_base; cmd.local_addr = ipa3_ctx->smem_restricted_bytes + Loading Loading @@ -2008,21 +2001,7 @@ bail_dma: return retval; } static void ipa3_q6_disable_agg_reg( struct ipahal_imm_cmd_register_write *reg_write, int ep_idx) { struct ipahal_reg_valmask valmask; reg_write->skip_pipeline_clear = false; reg_write->pipeline_clear_options = IPAHAL_FULL_PIPELINE_CLEAR; reg_write->offset = ipahal_get_reg_n_ofst(IPA_ENDP_INIT_AGGR_n, ep_idx); ipahal_get_disable_aggr_valmask(&valmask); reg_write->value = valmask.val; reg_write->value_mask = valmask.mask; } static int ipa3_q6_set_ex_path_dis_agg(void) static int ipa3_q6_set_ex_path_to_apps(void) { int ep_idx; int client_idx; Loading Loading @@ -2053,7 +2032,7 @@ static int ipa3_q6_set_ex_path_dis_agg(void) reg_write.skip_pipeline_clear = false; reg_write.pipeline_clear_options = IPAHAL_FULL_PIPELINE_CLEAR; IPAHAL_HPS_CLEAR; reg_write.offset = ipahal_get_reg_ofst(IPA_ENDP_STATUS_n); ipahal_get_status_ep_valmask( Loading @@ -2079,30 +2058,6 @@ static int ipa3_q6_set_ex_path_dis_agg(void) } } /* Disable AGGR on IPA->Q6 pipes */ for (client_idx = 0; client_idx < IPA_CLIENT_MAX; client_idx++) { if (IPA_CLIENT_IS_Q6_CONS(client_idx)) { ipa3_q6_disable_agg_reg(®_write, ipa3_get_ep_mapping(client_idx)); cmd_pyld = ipahal_construct_imm_cmd( IPA_IMM_CMD_REGISTER_WRITE, ®_write, false); if (!cmd_pyld) { IPAERR("fail construct register_write cmd\n"); BUG(); } desc[num_descs].opcode = ipahal_imm_cmd_get_opcode( IPA_IMM_CMD_REGISTER_WRITE); desc[num_descs].type = IPA_IMM_CMD_DESC; desc[num_descs].callback = ipa3_destroy_imm; desc[num_descs].user1 = cmd_pyld; desc[num_descs].pyld = cmd_pyld->data; desc[num_descs].len = cmd_pyld->len; num_descs++; } } /* Will wait 150msecs for IPA tag process completion */ retval = ipa3_tag_process(desc, num_descs, msecs_to_jiffies(CLEANUP_TAG_PROCESS_TIMEOUT)); Loading @@ -2127,70 +2082,65 @@ static int ipa3_q6_set_ex_path_dis_agg(void) * ipa3_q6_cleanup() - A cleanup for all Q6 related configuration * in IPA HW. This is performed in case of SSR. * * Return codes: * 0: success * This is a mandatory procedure, in case one of the steps fails, the * AP needs to restart. */ int ipa3_q6_cleanup(void) void ipa3_q6_cleanup(void) { /* If uC has notified the APPS upon a ZIP engine error, * APPS need to assert (This is a non recoverable error). */ if (ipa3_ctx->uc_ctx.uc_zip_error) BUG(); IPADBG_LOW("ENTER\n"); IPA_ACTIVE_CLIENTS_INC_SPECIAL("Q6"); IPA_ACTIVE_CLIENTS_INC_SIMPLE(); if (ipa3_q6_pipe_delay()) { IPAERR("Failed to delay Q6 pipes\n"); BUG(); } if (ipa3_q6_avoid_holb()) { IPAERR("Failed to set HOLB on Q6 pipes\n"); BUG(); } ipa3_q6_pipe_delay(true); ipa3_q6_avoid_holb(); if (ipa3_q6_clean_q6_tables()) { IPAERR("Failed to clean Q6 tables\n"); BUG(); } if (ipa3_q6_set_ex_path_dis_agg()) { IPAERR("Failed to disable aggregation on Q6 pipes\n"); if (ipa3_q6_set_ex_path_to_apps()) { IPAERR("Failed to redirect exceptions to APPS\n"); BUG(); } /* Remove delay from Q6 PRODs to avoid pending descriptors * on pipe reset procedure */ ipa3_q6_pipe_delay(false); ipa3_ctx->q6_proxy_clk_vote_valid = true; return 0; IPA_ACTIVE_CLIENTS_DEC_SIMPLE(); IPADBG_LOW("Exit with success\n"); } /** * ipa3_q6_pipe_reset() - A cleanup for the Q6 pipes * in IPA HW. This is performed in case of SSR. /* * ipa3_validate_q6_gsi_channel_empty() - Check if GSI channel related to Q6 * producer client is empty. This is used in case of SSR. * * Return codes: * 0: success * This is a mandatory procedure, in case one of the steps fails, the * AP needs to restart. * Q6 GSI channel emptiness is needed to garantee no descriptors with invalid * info are injected into IPA RX from IPA_IF, while modem is restarting. */ int ipa3_q6_pipe_reset(void) void ipa3_validate_q6_gsi_channel_empty(void) { int client_idx; int res; IPADBG_LOW("ENTER\n"); IPA_ACTIVE_CLIENTS_INC_SIMPLE(); if (!ipa3_ctx->uc_ctx.uc_loaded) { IPAERR("uC is not loaded, won't reset Q6 pipes\n"); return 0; IPAERR("uC is not loaded. Skipping\n"); return; } for (client_idx = 0; client_idx < IPA_CLIENT_MAX; client_idx++) if (IPA_CLIENT_IS_Q6_CONS(client_idx) || IPA_CLIENT_IS_Q6_PROD(client_idx)) { res = ipa3_uc_reset_pipe(client_idx); if (res) if (IPA_CLIENT_IS_Q6_PROD(client_idx)) { if (ipa3_uc_is_gsi_channel_empty(client_idx)) { IPAERR("fail to validate Q6 ch emptiness %d\n", client_idx); BUG(); return; } return 0; } IPA_ACTIVE_CLIENTS_DEC_SIMPLE(); IPADBG_LOW("Exit with success\n"); } static inline void ipa3_sram_set_canary(u32 *sram_mmio, int offset) Loading drivers/platform/msm/ipa/ipa_v3/ipa_i.h +29 −17 Original line number Diff line number Diff line Loading @@ -204,6 +204,10 @@ #define IPA_GSI_CHANNEL_STOP_SLEEP_MIN_USEC (1000) #define IPA_GSI_CHANNEL_STOP_SLEEP_MAX_USEC (2000) #define IPA_GSI_CHANNEL_EMPTY_MAX_RETRY 15 #define IPA_GSI_CHANNEL_EMPTY_SLEEP_MIN_USEC (1000) #define IPA_GSI_CHANNEL_EMPTY_SLEEP_MAX_USEC (2000) #define IPA_SLEEP_CLK_RATE_KHZ (32) #define IPA_ACTIVE_CLIENTS_PREP_EP(log_info, client) \ Loading Loading @@ -1081,22 +1085,29 @@ struct ipa3_controller; * enum ipa3_hw_features - Values that represent the features supported in IPA HW * @IPA_HW_FEATURE_COMMON : Feature related to common operation of IPA HW * @IPA_HW_FEATURE_MHI : Feature related to MHI operation in IPA HW * @IPA_HW_FEATURE_POWER_COLLAPSE: Feature related to IPA Power collapse * @IPA_HW_FEATURE_WDI : Feature related to WDI operation in IPA HW * @IPA_HW_FEATURE_ZIP: Feature related to CMP/DCMP operation in IPA HW */ enum ipa3_hw_features { IPA_HW_FEATURE_COMMON = 0x0, IPA_HW_FEATURE_MHI = 0x1, IPA_HW_FEATURE_POWER_COLLAPSE = 0x2, IPA_HW_FEATURE_WDI = 0x3, IPA_HW_FEATURE_ZIP = 0x4, IPA_HW_FEATURE_MAX = IPA_HW_NUM_FEATURES }; /** * enum ipa3_hw_2_cpu_events - Values that represent HW event to be sent to CPU. * @IPA_HW_2_CPU_EVENT_NO_OP : No event present * @IPA_HW_2_CPU_EVENT_ERROR : Event specify a system error is detected by the * device * @IPA_HW_2_CPU_EVENT_LOG_INFO : Event providing logging specific information */ enum ipa3_hw_2_cpu_events { IPA_HW_2_CPU_EVENT_NO_OP = FEATURE_ENUM_VAL(IPA_HW_FEATURE_COMMON, 0), IPA_HW_2_CPU_EVENT_ERROR = FEATURE_ENUM_VAL(IPA_HW_FEATURE_COMMON, 1), IPA_HW_2_CPU_EVENT_LOG_INFO = Loading @@ -1110,7 +1121,8 @@ enum ipa3_hw_2_cpu_events { * @IPA_HW_DMA_ERROR : Unexpected DMA error * @IPA_HW_FATAL_SYSTEM_ERROR : HW has crashed and requires reset. * @IPA_HW_INVALID_OPCODE : Invalid opcode sent * @IPA_HW_ZIP_ENGINE_ERROR : ZIP engine error * @IPA_HW_INVALID_PARAMS : Invalid params for the requested command * @IPA_HW_GSI_CH_NOT_EMPTY_FAILURE : GSI channel emptiness validation failed */ enum ipa3_hw_errors { IPA_HW_ERROR_NONE = Loading @@ -1123,12 +1135,14 @@ enum ipa3_hw_errors { FEATURE_ENUM_VAL(IPA_HW_FEATURE_COMMON, 3), IPA_HW_INVALID_OPCODE = FEATURE_ENUM_VAL(IPA_HW_FEATURE_COMMON, 4), IPA_HW_ZIP_ENGINE_ERROR = IPA_HW_INVALID_PARAMS = FEATURE_ENUM_VAL(IPA_HW_FEATURE_COMMON, 5), IPA_HW_CONS_DISABLE_CMD_GSI_STOP_FAILURE = FEATURE_ENUM_VAL(IPA_HW_FEATURE_COMMON, 6), IPA_HW_PROD_DISABLE_CMD_GSI_STOP_FAILURE = FEATURE_ENUM_VAL(IPA_HW_FEATURE_COMMON, 7) FEATURE_ENUM_VAL(IPA_HW_FEATURE_COMMON, 7), IPA_HW_GSI_CH_NOT_EMPTY_FAILURE = FEATURE_ENUM_VAL(IPA_HW_FEATURE_COMMON, 8) }; /** Loading Loading @@ -1162,14 +1176,13 @@ struct IpaHwSharedMemCommonMapping_t { u32 cmdParams; u32 cmdParams_hi; u8 responseOp; u8 reserved_09; u16 reserved_0B_0A; u8 reserved_0D; u16 reserved_0F_0E; u32 responseParams; u8 eventOp; u8 reserved_11; u16 reserved_13_12; u8 reserved_15; u16 reserved_17_16; u32 eventParams; u32 reserved_1B_18; u32 firstErrorAddress; u8 hwState; u8 warningCounter; Loading Loading @@ -1355,7 +1368,6 @@ union IpaHwMhiDlUlSyncCmdData_t { * @uc_sram_mmio: Pointer to uC mapped memory * @pending_cmd: The last command sent waiting to be ACKed * @uc_status: The last status provided by the uC * @uc_zip_error: uC has notified the APPS upon a ZIP engine error * @uc_error_type: error type from uC error event * @uc_error_timestamp: tag timer sampled after uC crashed */ Loading @@ -1371,7 +1383,6 @@ struct ipa3_uc_ctx { u32 uc_event_top_ofst; u32 pending_cmd; u32 uc_status; bool uc_zip_error; u32 uc_error_type; u32 uc_error_timestamp; }; Loading Loading @@ -2293,8 +2304,8 @@ int ipa3_write_qmapid_wdi_pipe(u32 clnt_hdl, u8 qmap_id); int ipa3_tag_process(struct ipa3_desc *desc, int num_descs, unsigned long timeout); int ipa3_q6_cleanup(void); int ipa3_q6_pipe_reset(void); void ipa3_q6_cleanup(void); void ipa3_validate_q6_gsi_channel_empty(void); int ipa3_init_q6_smem(void); int ipa3_sps_connect_safe(struct sps_pipe *h, struct sps_connect *connect, Loading @@ -2304,6 +2315,7 @@ int ipa3_mhi_handle_ipa_config_req(struct ipa_config_req_msg_v01 *config_req); int ipa3_uc_interface_init(void); int ipa3_uc_reset_pipe(enum ipa_client_type ipa_client); int ipa3_uc_is_gsi_channel_empty(enum ipa_client_type ipa_client); int ipa3_uc_state_check(void); int ipa3_uc_loaded_check(void); void ipa3_uc_load_notify(void); Loading drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.h +3 −1 Original line number Diff line number Diff line /* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. /* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading Loading @@ -34,6 +34,8 @@ pr_debug(DEV_NAME " %s:%d " fmt, __func__, __LINE__, ## args) #define IPAWANERR(fmt, args...) \ pr_err(DEV_NAME " %s:%d " fmt, __func__, __LINE__, ## args) #define IPAWANINFO(fmt, args...) \ pr_info(DEV_NAME " %s:%d " fmt, __func__, __LINE__, ## args) extern struct ipa3_qmi_context *ipa3_qmi_ctx; Loading drivers/platform/msm/ipa/ipa_v3/ipa_uc.c +96 −11 Original line number Diff line number Diff line Loading @@ -13,7 +13,7 @@ #include <linux/delay.h> #define IPA_RAM_UC_SMEM_SIZE 128 #define IPA_HW_INTERFACE_VERSION 0x0111 #define IPA_HW_INTERFACE_VERSION 0x2000 #define IPA_PKT_FLUSH_TO_US 100 #define IPA_UC_POLL_SLEEP_USEC 100 #define IPA_UC_POLL_MAX_RETRY 10000 Loading @@ -40,6 +40,7 @@ * IPA_CPU_2_HW_CMD_CLK_UNGATE : CPU instructs HW to goto Clock Ungated state. * IPA_CPU_2_HW_CMD_MEMCPY : CPU instructs HW to do memcopy using QMB. * IPA_CPU_2_HW_CMD_RESET_PIPE : Command to reset a pipe - SW WA for a HW bug. * IPA_CPU_2_HW_CMD_GSI_CH_EMPTY : Command to check for GSI channel emptiness. */ enum ipa3_cpu_2_hw_commands { IPA_CPU_2_HW_CMD_NO_OP = Loading @@ -62,20 +63,29 @@ enum ipa3_cpu_2_hw_commands { FEATURE_ENUM_VAL(IPA_HW_FEATURE_COMMON, 8), IPA_CPU_2_HW_CMD_REG_WRITE = FEATURE_ENUM_VAL(IPA_HW_FEATURE_COMMON, 9), IPA_CPU_2_HW_CMD_GSI_CH_EMPTY = FEATURE_ENUM_VAL(IPA_HW_FEATURE_COMMON, 10), }; /** * enum ipa3_hw_2_cpu_responses - Values that represent common HW responses * to CPU commands. * @IPA_HW_2_CPU_RESPONSE_NO_OP : No operation response * @IPA_HW_2_CPU_RESPONSE_INIT_COMPLETED : HW shall send this command once * boot sequence is completed and HW is ready to serve commands from CPU * @IPA_HW_2_CPU_RESPONSE_CMD_COMPLETED: Response to CPU commands * @IPA_HW_2_CPU_RESPONSE_DEBUG_GET_INFO : Response to * IPA_CPU_2_HW_CMD_DEBUG_GET_INFO command */ enum ipa3_hw_2_cpu_responses { IPA_HW_2_CPU_RESPONSE_NO_OP = FEATURE_ENUM_VAL(IPA_HW_FEATURE_COMMON, 0), IPA_HW_2_CPU_RESPONSE_INIT_COMPLETED = FEATURE_ENUM_VAL(IPA_HW_FEATURE_COMMON, 1), IPA_HW_2_CPU_RESPONSE_CMD_COMPLETED = FEATURE_ENUM_VAL(IPA_HW_FEATURE_COMMON, 2), IPA_HW_2_CPU_RESPONSE_DEBUG_GET_INFO = FEATURE_ENUM_VAL(IPA_HW_FEATURE_COMMON, 3), }; /** Loading Loading @@ -152,6 +162,23 @@ union IpaHwUpdateFlagsCmdData_t { u32 raw32b; }; /** * union IpaHwChkChEmptyCmdData_t - Structure holding the parameters for * IPA_CPU_2_HW_CMD_GSI_CH_EMPTY command. Parameters are sent as 32b * immediate parameters. * @ee_n : EE owner of the channel * @vir_ch_id : GSI virtual channel ID of the channel to checked of emptiness * @reserved_02_04 : Reserved */ union IpaHwChkChEmptyCmdData_t { struct IpaHwChkChEmptyCmdParams_t { u8 ee_n; u8 vir_ch_id; u16 reserved_02_04; } __packed params; u32 raw32b; } __packed; /** * When resource group 10 limitation mitigation is enabled, uC send * cmd should be able to run in interrupt context, so using spin lock Loading Loading @@ -186,14 +213,26 @@ const char *ipa_hw_error_str(enum ipa3_hw_errors err_type) case IPA_HW_INVALID_DOORBELL_ERROR: str = "IPA_HW_INVALID_DOORBELL_ERROR"; break; case IPA_HW_DMA_ERROR: str = "IPA_HW_DMA_ERROR"; break; case IPA_HW_FATAL_SYSTEM_ERROR: str = "IPA_HW_FATAL_SYSTEM_ERROR"; break; case IPA_HW_INVALID_OPCODE: str = "IPA_HW_INVALID_OPCODE"; break; case IPA_HW_ZIP_ENGINE_ERROR: str = "IPA_HW_ZIP_ENGINE_ERROR"; case IPA_HW_INVALID_PARAMS: str = "IPA_HW_INVALID_PARAMS"; break; case IPA_HW_CONS_DISABLE_CMD_GSI_STOP_FAILURE: str = "IPA_HW_CONS_DISABLE_CMD_GSI_STOP_FAILURE"; break; case IPA_HW_PROD_DISABLE_CMD_GSI_STOP_FAILURE: str = "IPA_HW_PROD_DISABLE_CMD_GSI_STOP_FAILURE"; break; case IPA_HW_GSI_CH_NOT_EMPTY_FAILURE: str = "IPA_HW_GSI_CH_NOT_EMPTY_FAILURE"; break; default: str = "INVALID ipa_hw_errors type"; Loading Loading @@ -324,10 +363,6 @@ static void ipa3_uc_event_handler(enum ipa_irq_type interrupt, ipa_hw_error_str(evt.params.errorType)); ipa3_ctx->uc_ctx.uc_failed = true; ipa3_ctx->uc_ctx.uc_error_type = evt.params.errorType; if (evt.params.errorType == IPA_HW_ZIP_ENGINE_ERROR) { IPAERR("IPA has encountered a ZIP engine error\n"); ipa3_ctx->uc_ctx.uc_zip_error = true; } ipa3_ctx->uc_ctx.uc_error_timestamp = ipahal_read_reg(IPA_TAG_TIMER); BUG(); Loading Loading @@ -466,7 +501,7 @@ static int ipa3_uc_send_cmd_64b_param(u32 cmd_lo, u32 cmd_hi, u32 opcode, unsigned long flags; int retries = 0; send_cmd: send_cmd_lock: IPA3_UC_LOCK(flags); if (ipa3_uc_state_check()) { Loading @@ -474,7 +509,7 @@ send_cmd: IPA3_UC_UNLOCK(flags); return -EBADF; } send_cmd: if (ipa3_ctx->apply_rg10_wa) { if (!polling_mode) IPADBG("Overriding mode to polling mode\n"); Loading Loading @@ -563,6 +598,25 @@ send_cmd: /* sleep for short period to flush IPA */ usleep_range(IPA_GSI_CHANNEL_STOP_SLEEP_MIN_USEC, IPA_GSI_CHANNEL_STOP_SLEEP_MAX_USEC); goto send_cmd_lock; } if (ipa3_ctx->uc_ctx.uc_status == IPA_HW_GSI_CH_NOT_EMPTY_FAILURE) { retries++; if (retries >= IPA_GSI_CHANNEL_EMPTY_MAX_RETRY) { IPAERR("Failed after %d tries\n", retries); IPA3_UC_UNLOCK(flags); return -EFAULT; } if (ipa3_ctx->apply_rg10_wa) udelay( IPA_GSI_CHANNEL_EMPTY_SLEEP_MAX_USEC / 2 + IPA_GSI_CHANNEL_EMPTY_SLEEP_MIN_USEC / 2); else usleep_range( IPA_GSI_CHANNEL_EMPTY_SLEEP_MIN_USEC, IPA_GSI_CHANNEL_EMPTY_SLEEP_MAX_USEC); goto send_cmd; } Loading Loading @@ -784,6 +838,37 @@ int ipa3_uc_reset_pipe(enum ipa_client_type ipa_client) return ret; } int ipa3_uc_is_gsi_channel_empty(enum ipa_client_type ipa_client) { struct ipa_gsi_ep_config *gsi_ep_info; union IpaHwChkChEmptyCmdData_t cmd; int ret; gsi_ep_info = ipa3_get_gsi_ep_info(ipa3_get_ep_mapping(ipa_client)); if (!gsi_ep_info) { IPAERR("Invalid IPA ep index\n"); return 0; } if (ipa3_uc_state_check()) { IPADBG("uC cannot be used to validate ch emptiness clnt=%d\n" , ipa_client); return 0; } cmd.params.ee_n = gsi_ep_info->ee; cmd.params.vir_ch_id = gsi_ep_info->ipa_gsi_chan_num; IPADBG("uC emptiness check for IPA GSI Channel %d\n", gsi_ep_info->ipa_gsi_chan_num); ret = ipa3_uc_send_cmd(cmd.raw32b, IPA_CPU_2_HW_CMD_GSI_CH_EMPTY, 0, false, 10*HZ); return ret; } /** * ipa3_uc_notify_clk_state() - notify to uC of clock enable / disable * @enabled: true if clock are enabled Loading drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c +47 −40 Original line number Diff line number Diff line Loading @@ -2290,9 +2290,12 @@ static int ipa3_ssr_notifier_cb(struct notifier_block *this, unsigned long code, void *data) { if (ipa3_rmnet_ctx.ipa_rmnet_ssr) { if (SUBSYS_BEFORE_SHUTDOWN == code) { pr_info("IPA received MPSS BEFORE_SHUTDOWN\n"); if (!ipa3_rmnet_ctx.ipa_rmnet_ssr) return NOTIFY_DONE; switch (code) { case SUBSYS_BEFORE_SHUTDOWN: IPAWANINFO("IPA received MPSS BEFORE_SHUTDOWN\n"); atomic_set(&rmnet_ipa3_ctx->is_ssr, 1); ipa3_q6_cleanup(); if (IPA_NETDEV()) Loading @@ -2300,37 +2303,41 @@ static int ipa3_ssr_notifier_cb(struct notifier_block *this, ipa3_qmi_stop_workqueues(); ipa3_wan_ioctl_stop_qmi_messages(); ipa_stop_polling_stats(); atomic_set(&rmnet_ipa3_ctx->is_ssr, 1); if (atomic_read(&rmnet_ipa3_ctx->is_initialized)) platform_driver_unregister(&rmnet_ipa_driver); pr_info("IPA BEFORE_SHUTDOWN handling is complete\n"); return NOTIFY_DONE; } if (SUBSYS_AFTER_SHUTDOWN == code) { pr_info("IPA received MPSS AFTER_SHUTDOWN\n"); IPAWANINFO("IPA BEFORE_SHUTDOWN handling is complete\n"); break; case SUBSYS_AFTER_SHUTDOWN: IPAWANINFO("IPA Received MPSS AFTER_SHUTDOWN\n"); if (atomic_read(&rmnet_ipa3_ctx->is_ssr)) ipa3_q6_pipe_reset(); pr_info("IPA AFTER_SHUTDOWN handling is complete\n"); return NOTIFY_DONE; } if (SUBSYS_AFTER_POWERUP == code) { pr_info("IPA received MPSS AFTER_POWERUP\n"); if (!atomic_read(&rmnet_ipa3_ctx->is_initialized) && atomic_read(&rmnet_ipa3_ctx->is_ssr)) platform_driver_register(&rmnet_ipa_driver); pr_info("IPA AFTER_POWERUP handling is complete\n"); return NOTIFY_DONE; } if (SUBSYS_BEFORE_POWERUP == code) { pr_info("IPA received MPSS BEFORE_POWERUP\n"); ipa3_validate_q6_gsi_channel_empty(); IPAWANINFO("IPA AFTER_SHUTDOWN handling is complete\n"); break; case SUBSYS_BEFORE_POWERUP: IPAWANINFO("IPA received MPSS BEFORE_POWERUP\n"); if (atomic_read(&rmnet_ipa3_ctx->is_ssr)) /* clean up cached QMI msg/handlers */ ipa3_qmi_service_exit(); /*hold a proxy vote for the modem*/ ipa3_proxy_clk_vote(); pr_info("IPA BEFORE_POWERUP handling is complete\n"); return NOTIFY_DONE; } IPAWANINFO("IPA BEFORE_POWERUP handling is complete\n"); break; case SUBSYS_AFTER_POWERUP: IPAWANINFO("%s:%d IPA received MPSS AFTER_POWERUP\n", __func__, __LINE__); if (!atomic_read(&rmnet_ipa3_ctx->is_initialized) && atomic_read(&rmnet_ipa3_ctx->is_ssr)) platform_driver_register(&rmnet_ipa_driver); IPAWANINFO("IPA AFTER_POWERUP handling is complete\n"); break; default: IPAWANDBG("Unsupported subsys notification, IPA received: %lu", code); break; } IPAWANDBG("Exit\n"); return NOTIFY_DONE; } Loading Loading
drivers/platform/msm/ipa/ipa_v3/ipa.c +58 −108 Original line number Diff line number Diff line Loading @@ -1647,39 +1647,40 @@ static void ipa3_destroy_imm(void *user1, int user2) ipahal_destroy_imm_cmd(user1); } static int ipa3_q6_pipe_delay(void) static void ipa3_q6_pipe_delay(bool delay) { int client_idx; int ep_idx; struct ipa_ep_cfg_ctrl ep_ctrl; memset(&ep_ctrl, 0, sizeof(struct ipa_ep_cfg_ctrl)); ep_ctrl.ipa_ep_delay = delay; for (client_idx = 0; client_idx < IPA_CLIENT_MAX; client_idx++) { if (IPA_CLIENT_IS_Q6_PROD(client_idx)) { ep_idx = ipa3_get_ep_mapping(client_idx); if (ep_idx == -1) continue; ep_ctrl.ipa_ep_delay = 1; ipahal_write_reg_n_fields(IPA_ENDP_INIT_CTRL_n, ep_idx, &ep_ctrl); } } return 0; } static int ipa3_q6_avoid_holb(void) static void ipa3_q6_avoid_holb(void) { int ep_idx; int client_idx; struct ipa_ep_cfg_ctrl avoid_holb; struct ipa_ep_cfg_ctrl ep_suspend; struct ipa_ep_cfg_holb ep_holb; memset(&avoid_holb, 0, sizeof(avoid_holb)); memset(&ep_suspend, 0, sizeof(ep_suspend)); memset(&ep_holb, 0, sizeof(ep_holb)); avoid_holb.ipa_ep_suspend = true; ep_suspend.ipa_ep_suspend = true; ep_holb.tmr_val = 0; ep_holb.en = 1; for (client_idx = 0; client_idx < IPA_CLIENT_MAX; client_idx++) { if (IPA_CLIENT_IS_Q6_CONS(client_idx)) { Loading @@ -1693,8 +1694,6 @@ static int ipa3_q6_avoid_holb(void) * they are not valid, therefore, the above function * will fail. */ ep_holb.tmr_val = 0; ep_holb.en = 1; ipahal_write_reg_n_fields( IPA_ENDP_INIT_HOL_BLOCK_TIMER_n, ep_idx, &ep_holb); Loading @@ -1702,11 +1701,11 @@ static int ipa3_q6_avoid_holb(void) IPA_ENDP_INIT_HOL_BLOCK_EN_n, ep_idx, &ep_holb); ipa3_cfg_ep_ctrl(ep_idx, &avoid_holb); ipahal_write_reg_n_fields( IPA_ENDP_INIT_CTRL_n, ep_idx, &ep_suspend); } } return 0; } static u32 ipa3_get_max_flt_rt_cmds(u32 num_pipes) Loading Loading @@ -1785,8 +1784,7 @@ static int ipa3_q6_clean_q6_tables(void) */ cmd.is_read = false; cmd.skip_pipeline_clear = 0; cmd.pipeline_clear_options = IPAHAL_FULL_PIPELINE_CLEAR; cmd.pipeline_clear_options = IPAHAL_HPS_CLEAR; cmd.size = mem.size; cmd.system_addr = mem.phys_base; cmd.local_addr = Loading @@ -1810,8 +1808,7 @@ static int ipa3_q6_clean_q6_tables(void) cmd.is_read = false; cmd.skip_pipeline_clear = false; cmd.pipeline_clear_options = IPAHAL_FULL_PIPELINE_CLEAR; cmd.pipeline_clear_options = IPAHAL_HPS_CLEAR; cmd.size = mem.size; cmd.system_addr = mem.phys_base; cmd.local_addr = Loading Loading @@ -1839,8 +1836,7 @@ static int ipa3_q6_clean_q6_tables(void) */ cmd.is_read = false; cmd.skip_pipeline_clear = false; cmd.pipeline_clear_options = IPAHAL_FULL_PIPELINE_CLEAR; cmd.pipeline_clear_options = IPAHAL_HPS_CLEAR; cmd.size = mem.size; cmd.system_addr = mem.phys_base; cmd.local_addr = Loading @@ -1864,8 +1860,7 @@ static int ipa3_q6_clean_q6_tables(void) cmd.is_read = false; cmd.skip_pipeline_clear = 0; cmd.pipeline_clear_options = IPAHAL_FULL_PIPELINE_CLEAR; cmd.pipeline_clear_options = IPAHAL_HPS_CLEAR; cmd.size = mem.size; cmd.system_addr = mem.phys_base; cmd.local_addr = Loading Loading @@ -1897,7 +1892,7 @@ static int ipa3_q6_clean_q6_tables(void) index++) { cmd.is_read = false; cmd.skip_pipeline_clear = false; cmd.pipeline_clear_options = IPAHAL_FULL_PIPELINE_CLEAR; cmd.pipeline_clear_options = IPAHAL_HPS_CLEAR; cmd.size = mem.size; cmd.system_addr = mem.phys_base; cmd.local_addr = ipa3_ctx->smem_restricted_bytes + Loading @@ -1919,7 +1914,7 @@ static int ipa3_q6_clean_q6_tables(void) cmd.is_read = false; cmd.skip_pipeline_clear = false; cmd.pipeline_clear_options = IPAHAL_FULL_PIPELINE_CLEAR; cmd.pipeline_clear_options = IPAHAL_HPS_CLEAR; cmd.size = mem.size; cmd.system_addr = mem.phys_base; cmd.local_addr = ipa3_ctx->smem_restricted_bytes + Loading @@ -1945,8 +1940,7 @@ static int ipa3_q6_clean_q6_tables(void) index++) { cmd.is_read = false; cmd.skip_pipeline_clear = false; cmd.pipeline_clear_options = IPAHAL_FULL_PIPELINE_CLEAR; cmd.pipeline_clear_options = IPAHAL_HPS_CLEAR; cmd.size = mem.size; cmd.system_addr = mem.phys_base; cmd.local_addr = ipa3_ctx->smem_restricted_bytes + Loading @@ -1968,8 +1962,7 @@ static int ipa3_q6_clean_q6_tables(void) cmd.is_read = false; cmd.skip_pipeline_clear = false; cmd.pipeline_clear_options = IPAHAL_FULL_PIPELINE_CLEAR; cmd.pipeline_clear_options = IPAHAL_HPS_CLEAR; cmd.size = mem.size; cmd.system_addr = mem.phys_base; cmd.local_addr = ipa3_ctx->smem_restricted_bytes + Loading Loading @@ -2008,21 +2001,7 @@ bail_dma: return retval; } static void ipa3_q6_disable_agg_reg( struct ipahal_imm_cmd_register_write *reg_write, int ep_idx) { struct ipahal_reg_valmask valmask; reg_write->skip_pipeline_clear = false; reg_write->pipeline_clear_options = IPAHAL_FULL_PIPELINE_CLEAR; reg_write->offset = ipahal_get_reg_n_ofst(IPA_ENDP_INIT_AGGR_n, ep_idx); ipahal_get_disable_aggr_valmask(&valmask); reg_write->value = valmask.val; reg_write->value_mask = valmask.mask; } static int ipa3_q6_set_ex_path_dis_agg(void) static int ipa3_q6_set_ex_path_to_apps(void) { int ep_idx; int client_idx; Loading Loading @@ -2053,7 +2032,7 @@ static int ipa3_q6_set_ex_path_dis_agg(void) reg_write.skip_pipeline_clear = false; reg_write.pipeline_clear_options = IPAHAL_FULL_PIPELINE_CLEAR; IPAHAL_HPS_CLEAR; reg_write.offset = ipahal_get_reg_ofst(IPA_ENDP_STATUS_n); ipahal_get_status_ep_valmask( Loading @@ -2079,30 +2058,6 @@ static int ipa3_q6_set_ex_path_dis_agg(void) } } /* Disable AGGR on IPA->Q6 pipes */ for (client_idx = 0; client_idx < IPA_CLIENT_MAX; client_idx++) { if (IPA_CLIENT_IS_Q6_CONS(client_idx)) { ipa3_q6_disable_agg_reg(®_write, ipa3_get_ep_mapping(client_idx)); cmd_pyld = ipahal_construct_imm_cmd( IPA_IMM_CMD_REGISTER_WRITE, ®_write, false); if (!cmd_pyld) { IPAERR("fail construct register_write cmd\n"); BUG(); } desc[num_descs].opcode = ipahal_imm_cmd_get_opcode( IPA_IMM_CMD_REGISTER_WRITE); desc[num_descs].type = IPA_IMM_CMD_DESC; desc[num_descs].callback = ipa3_destroy_imm; desc[num_descs].user1 = cmd_pyld; desc[num_descs].pyld = cmd_pyld->data; desc[num_descs].len = cmd_pyld->len; num_descs++; } } /* Will wait 150msecs for IPA tag process completion */ retval = ipa3_tag_process(desc, num_descs, msecs_to_jiffies(CLEANUP_TAG_PROCESS_TIMEOUT)); Loading @@ -2127,70 +2082,65 @@ static int ipa3_q6_set_ex_path_dis_agg(void) * ipa3_q6_cleanup() - A cleanup for all Q6 related configuration * in IPA HW. This is performed in case of SSR. * * Return codes: * 0: success * This is a mandatory procedure, in case one of the steps fails, the * AP needs to restart. */ int ipa3_q6_cleanup(void) void ipa3_q6_cleanup(void) { /* If uC has notified the APPS upon a ZIP engine error, * APPS need to assert (This is a non recoverable error). */ if (ipa3_ctx->uc_ctx.uc_zip_error) BUG(); IPADBG_LOW("ENTER\n"); IPA_ACTIVE_CLIENTS_INC_SPECIAL("Q6"); IPA_ACTIVE_CLIENTS_INC_SIMPLE(); if (ipa3_q6_pipe_delay()) { IPAERR("Failed to delay Q6 pipes\n"); BUG(); } if (ipa3_q6_avoid_holb()) { IPAERR("Failed to set HOLB on Q6 pipes\n"); BUG(); } ipa3_q6_pipe_delay(true); ipa3_q6_avoid_holb(); if (ipa3_q6_clean_q6_tables()) { IPAERR("Failed to clean Q6 tables\n"); BUG(); } if (ipa3_q6_set_ex_path_dis_agg()) { IPAERR("Failed to disable aggregation on Q6 pipes\n"); if (ipa3_q6_set_ex_path_to_apps()) { IPAERR("Failed to redirect exceptions to APPS\n"); BUG(); } /* Remove delay from Q6 PRODs to avoid pending descriptors * on pipe reset procedure */ ipa3_q6_pipe_delay(false); ipa3_ctx->q6_proxy_clk_vote_valid = true; return 0; IPA_ACTIVE_CLIENTS_DEC_SIMPLE(); IPADBG_LOW("Exit with success\n"); } /** * ipa3_q6_pipe_reset() - A cleanup for the Q6 pipes * in IPA HW. This is performed in case of SSR. /* * ipa3_validate_q6_gsi_channel_empty() - Check if GSI channel related to Q6 * producer client is empty. This is used in case of SSR. * * Return codes: * 0: success * This is a mandatory procedure, in case one of the steps fails, the * AP needs to restart. * Q6 GSI channel emptiness is needed to garantee no descriptors with invalid * info are injected into IPA RX from IPA_IF, while modem is restarting. */ int ipa3_q6_pipe_reset(void) void ipa3_validate_q6_gsi_channel_empty(void) { int client_idx; int res; IPADBG_LOW("ENTER\n"); IPA_ACTIVE_CLIENTS_INC_SIMPLE(); if (!ipa3_ctx->uc_ctx.uc_loaded) { IPAERR("uC is not loaded, won't reset Q6 pipes\n"); return 0; IPAERR("uC is not loaded. Skipping\n"); return; } for (client_idx = 0; client_idx < IPA_CLIENT_MAX; client_idx++) if (IPA_CLIENT_IS_Q6_CONS(client_idx) || IPA_CLIENT_IS_Q6_PROD(client_idx)) { res = ipa3_uc_reset_pipe(client_idx); if (res) if (IPA_CLIENT_IS_Q6_PROD(client_idx)) { if (ipa3_uc_is_gsi_channel_empty(client_idx)) { IPAERR("fail to validate Q6 ch emptiness %d\n", client_idx); BUG(); return; } return 0; } IPA_ACTIVE_CLIENTS_DEC_SIMPLE(); IPADBG_LOW("Exit with success\n"); } static inline void ipa3_sram_set_canary(u32 *sram_mmio, int offset) Loading
drivers/platform/msm/ipa/ipa_v3/ipa_i.h +29 −17 Original line number Diff line number Diff line Loading @@ -204,6 +204,10 @@ #define IPA_GSI_CHANNEL_STOP_SLEEP_MIN_USEC (1000) #define IPA_GSI_CHANNEL_STOP_SLEEP_MAX_USEC (2000) #define IPA_GSI_CHANNEL_EMPTY_MAX_RETRY 15 #define IPA_GSI_CHANNEL_EMPTY_SLEEP_MIN_USEC (1000) #define IPA_GSI_CHANNEL_EMPTY_SLEEP_MAX_USEC (2000) #define IPA_SLEEP_CLK_RATE_KHZ (32) #define IPA_ACTIVE_CLIENTS_PREP_EP(log_info, client) \ Loading Loading @@ -1081,22 +1085,29 @@ struct ipa3_controller; * enum ipa3_hw_features - Values that represent the features supported in IPA HW * @IPA_HW_FEATURE_COMMON : Feature related to common operation of IPA HW * @IPA_HW_FEATURE_MHI : Feature related to MHI operation in IPA HW * @IPA_HW_FEATURE_POWER_COLLAPSE: Feature related to IPA Power collapse * @IPA_HW_FEATURE_WDI : Feature related to WDI operation in IPA HW * @IPA_HW_FEATURE_ZIP: Feature related to CMP/DCMP operation in IPA HW */ enum ipa3_hw_features { IPA_HW_FEATURE_COMMON = 0x0, IPA_HW_FEATURE_MHI = 0x1, IPA_HW_FEATURE_POWER_COLLAPSE = 0x2, IPA_HW_FEATURE_WDI = 0x3, IPA_HW_FEATURE_ZIP = 0x4, IPA_HW_FEATURE_MAX = IPA_HW_NUM_FEATURES }; /** * enum ipa3_hw_2_cpu_events - Values that represent HW event to be sent to CPU. * @IPA_HW_2_CPU_EVENT_NO_OP : No event present * @IPA_HW_2_CPU_EVENT_ERROR : Event specify a system error is detected by the * device * @IPA_HW_2_CPU_EVENT_LOG_INFO : Event providing logging specific information */ enum ipa3_hw_2_cpu_events { IPA_HW_2_CPU_EVENT_NO_OP = FEATURE_ENUM_VAL(IPA_HW_FEATURE_COMMON, 0), IPA_HW_2_CPU_EVENT_ERROR = FEATURE_ENUM_VAL(IPA_HW_FEATURE_COMMON, 1), IPA_HW_2_CPU_EVENT_LOG_INFO = Loading @@ -1110,7 +1121,8 @@ enum ipa3_hw_2_cpu_events { * @IPA_HW_DMA_ERROR : Unexpected DMA error * @IPA_HW_FATAL_SYSTEM_ERROR : HW has crashed and requires reset. * @IPA_HW_INVALID_OPCODE : Invalid opcode sent * @IPA_HW_ZIP_ENGINE_ERROR : ZIP engine error * @IPA_HW_INVALID_PARAMS : Invalid params for the requested command * @IPA_HW_GSI_CH_NOT_EMPTY_FAILURE : GSI channel emptiness validation failed */ enum ipa3_hw_errors { IPA_HW_ERROR_NONE = Loading @@ -1123,12 +1135,14 @@ enum ipa3_hw_errors { FEATURE_ENUM_VAL(IPA_HW_FEATURE_COMMON, 3), IPA_HW_INVALID_OPCODE = FEATURE_ENUM_VAL(IPA_HW_FEATURE_COMMON, 4), IPA_HW_ZIP_ENGINE_ERROR = IPA_HW_INVALID_PARAMS = FEATURE_ENUM_VAL(IPA_HW_FEATURE_COMMON, 5), IPA_HW_CONS_DISABLE_CMD_GSI_STOP_FAILURE = FEATURE_ENUM_VAL(IPA_HW_FEATURE_COMMON, 6), IPA_HW_PROD_DISABLE_CMD_GSI_STOP_FAILURE = FEATURE_ENUM_VAL(IPA_HW_FEATURE_COMMON, 7) FEATURE_ENUM_VAL(IPA_HW_FEATURE_COMMON, 7), IPA_HW_GSI_CH_NOT_EMPTY_FAILURE = FEATURE_ENUM_VAL(IPA_HW_FEATURE_COMMON, 8) }; /** Loading Loading @@ -1162,14 +1176,13 @@ struct IpaHwSharedMemCommonMapping_t { u32 cmdParams; u32 cmdParams_hi; u8 responseOp; u8 reserved_09; u16 reserved_0B_0A; u8 reserved_0D; u16 reserved_0F_0E; u32 responseParams; u8 eventOp; u8 reserved_11; u16 reserved_13_12; u8 reserved_15; u16 reserved_17_16; u32 eventParams; u32 reserved_1B_18; u32 firstErrorAddress; u8 hwState; u8 warningCounter; Loading Loading @@ -1355,7 +1368,6 @@ union IpaHwMhiDlUlSyncCmdData_t { * @uc_sram_mmio: Pointer to uC mapped memory * @pending_cmd: The last command sent waiting to be ACKed * @uc_status: The last status provided by the uC * @uc_zip_error: uC has notified the APPS upon a ZIP engine error * @uc_error_type: error type from uC error event * @uc_error_timestamp: tag timer sampled after uC crashed */ Loading @@ -1371,7 +1383,6 @@ struct ipa3_uc_ctx { u32 uc_event_top_ofst; u32 pending_cmd; u32 uc_status; bool uc_zip_error; u32 uc_error_type; u32 uc_error_timestamp; }; Loading Loading @@ -2293,8 +2304,8 @@ int ipa3_write_qmapid_wdi_pipe(u32 clnt_hdl, u8 qmap_id); int ipa3_tag_process(struct ipa3_desc *desc, int num_descs, unsigned long timeout); int ipa3_q6_cleanup(void); int ipa3_q6_pipe_reset(void); void ipa3_q6_cleanup(void); void ipa3_validate_q6_gsi_channel_empty(void); int ipa3_init_q6_smem(void); int ipa3_sps_connect_safe(struct sps_pipe *h, struct sps_connect *connect, Loading @@ -2304,6 +2315,7 @@ int ipa3_mhi_handle_ipa_config_req(struct ipa_config_req_msg_v01 *config_req); int ipa3_uc_interface_init(void); int ipa3_uc_reset_pipe(enum ipa_client_type ipa_client); int ipa3_uc_is_gsi_channel_empty(enum ipa_client_type ipa_client); int ipa3_uc_state_check(void); int ipa3_uc_loaded_check(void); void ipa3_uc_load_notify(void); Loading
drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.h +3 −1 Original line number Diff line number Diff line /* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. /* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading Loading @@ -34,6 +34,8 @@ pr_debug(DEV_NAME " %s:%d " fmt, __func__, __LINE__, ## args) #define IPAWANERR(fmt, args...) \ pr_err(DEV_NAME " %s:%d " fmt, __func__, __LINE__, ## args) #define IPAWANINFO(fmt, args...) \ pr_info(DEV_NAME " %s:%d " fmt, __func__, __LINE__, ## args) extern struct ipa3_qmi_context *ipa3_qmi_ctx; Loading
drivers/platform/msm/ipa/ipa_v3/ipa_uc.c +96 −11 Original line number Diff line number Diff line Loading @@ -13,7 +13,7 @@ #include <linux/delay.h> #define IPA_RAM_UC_SMEM_SIZE 128 #define IPA_HW_INTERFACE_VERSION 0x0111 #define IPA_HW_INTERFACE_VERSION 0x2000 #define IPA_PKT_FLUSH_TO_US 100 #define IPA_UC_POLL_SLEEP_USEC 100 #define IPA_UC_POLL_MAX_RETRY 10000 Loading @@ -40,6 +40,7 @@ * IPA_CPU_2_HW_CMD_CLK_UNGATE : CPU instructs HW to goto Clock Ungated state. * IPA_CPU_2_HW_CMD_MEMCPY : CPU instructs HW to do memcopy using QMB. * IPA_CPU_2_HW_CMD_RESET_PIPE : Command to reset a pipe - SW WA for a HW bug. * IPA_CPU_2_HW_CMD_GSI_CH_EMPTY : Command to check for GSI channel emptiness. */ enum ipa3_cpu_2_hw_commands { IPA_CPU_2_HW_CMD_NO_OP = Loading @@ -62,20 +63,29 @@ enum ipa3_cpu_2_hw_commands { FEATURE_ENUM_VAL(IPA_HW_FEATURE_COMMON, 8), IPA_CPU_2_HW_CMD_REG_WRITE = FEATURE_ENUM_VAL(IPA_HW_FEATURE_COMMON, 9), IPA_CPU_2_HW_CMD_GSI_CH_EMPTY = FEATURE_ENUM_VAL(IPA_HW_FEATURE_COMMON, 10), }; /** * enum ipa3_hw_2_cpu_responses - Values that represent common HW responses * to CPU commands. * @IPA_HW_2_CPU_RESPONSE_NO_OP : No operation response * @IPA_HW_2_CPU_RESPONSE_INIT_COMPLETED : HW shall send this command once * boot sequence is completed and HW is ready to serve commands from CPU * @IPA_HW_2_CPU_RESPONSE_CMD_COMPLETED: Response to CPU commands * @IPA_HW_2_CPU_RESPONSE_DEBUG_GET_INFO : Response to * IPA_CPU_2_HW_CMD_DEBUG_GET_INFO command */ enum ipa3_hw_2_cpu_responses { IPA_HW_2_CPU_RESPONSE_NO_OP = FEATURE_ENUM_VAL(IPA_HW_FEATURE_COMMON, 0), IPA_HW_2_CPU_RESPONSE_INIT_COMPLETED = FEATURE_ENUM_VAL(IPA_HW_FEATURE_COMMON, 1), IPA_HW_2_CPU_RESPONSE_CMD_COMPLETED = FEATURE_ENUM_VAL(IPA_HW_FEATURE_COMMON, 2), IPA_HW_2_CPU_RESPONSE_DEBUG_GET_INFO = FEATURE_ENUM_VAL(IPA_HW_FEATURE_COMMON, 3), }; /** Loading Loading @@ -152,6 +162,23 @@ union IpaHwUpdateFlagsCmdData_t { u32 raw32b; }; /** * union IpaHwChkChEmptyCmdData_t - Structure holding the parameters for * IPA_CPU_2_HW_CMD_GSI_CH_EMPTY command. Parameters are sent as 32b * immediate parameters. * @ee_n : EE owner of the channel * @vir_ch_id : GSI virtual channel ID of the channel to checked of emptiness * @reserved_02_04 : Reserved */ union IpaHwChkChEmptyCmdData_t { struct IpaHwChkChEmptyCmdParams_t { u8 ee_n; u8 vir_ch_id; u16 reserved_02_04; } __packed params; u32 raw32b; } __packed; /** * When resource group 10 limitation mitigation is enabled, uC send * cmd should be able to run in interrupt context, so using spin lock Loading Loading @@ -186,14 +213,26 @@ const char *ipa_hw_error_str(enum ipa3_hw_errors err_type) case IPA_HW_INVALID_DOORBELL_ERROR: str = "IPA_HW_INVALID_DOORBELL_ERROR"; break; case IPA_HW_DMA_ERROR: str = "IPA_HW_DMA_ERROR"; break; case IPA_HW_FATAL_SYSTEM_ERROR: str = "IPA_HW_FATAL_SYSTEM_ERROR"; break; case IPA_HW_INVALID_OPCODE: str = "IPA_HW_INVALID_OPCODE"; break; case IPA_HW_ZIP_ENGINE_ERROR: str = "IPA_HW_ZIP_ENGINE_ERROR"; case IPA_HW_INVALID_PARAMS: str = "IPA_HW_INVALID_PARAMS"; break; case IPA_HW_CONS_DISABLE_CMD_GSI_STOP_FAILURE: str = "IPA_HW_CONS_DISABLE_CMD_GSI_STOP_FAILURE"; break; case IPA_HW_PROD_DISABLE_CMD_GSI_STOP_FAILURE: str = "IPA_HW_PROD_DISABLE_CMD_GSI_STOP_FAILURE"; break; case IPA_HW_GSI_CH_NOT_EMPTY_FAILURE: str = "IPA_HW_GSI_CH_NOT_EMPTY_FAILURE"; break; default: str = "INVALID ipa_hw_errors type"; Loading Loading @@ -324,10 +363,6 @@ static void ipa3_uc_event_handler(enum ipa_irq_type interrupt, ipa_hw_error_str(evt.params.errorType)); ipa3_ctx->uc_ctx.uc_failed = true; ipa3_ctx->uc_ctx.uc_error_type = evt.params.errorType; if (evt.params.errorType == IPA_HW_ZIP_ENGINE_ERROR) { IPAERR("IPA has encountered a ZIP engine error\n"); ipa3_ctx->uc_ctx.uc_zip_error = true; } ipa3_ctx->uc_ctx.uc_error_timestamp = ipahal_read_reg(IPA_TAG_TIMER); BUG(); Loading Loading @@ -466,7 +501,7 @@ static int ipa3_uc_send_cmd_64b_param(u32 cmd_lo, u32 cmd_hi, u32 opcode, unsigned long flags; int retries = 0; send_cmd: send_cmd_lock: IPA3_UC_LOCK(flags); if (ipa3_uc_state_check()) { Loading @@ -474,7 +509,7 @@ send_cmd: IPA3_UC_UNLOCK(flags); return -EBADF; } send_cmd: if (ipa3_ctx->apply_rg10_wa) { if (!polling_mode) IPADBG("Overriding mode to polling mode\n"); Loading Loading @@ -563,6 +598,25 @@ send_cmd: /* sleep for short period to flush IPA */ usleep_range(IPA_GSI_CHANNEL_STOP_SLEEP_MIN_USEC, IPA_GSI_CHANNEL_STOP_SLEEP_MAX_USEC); goto send_cmd_lock; } if (ipa3_ctx->uc_ctx.uc_status == IPA_HW_GSI_CH_NOT_EMPTY_FAILURE) { retries++; if (retries >= IPA_GSI_CHANNEL_EMPTY_MAX_RETRY) { IPAERR("Failed after %d tries\n", retries); IPA3_UC_UNLOCK(flags); return -EFAULT; } if (ipa3_ctx->apply_rg10_wa) udelay( IPA_GSI_CHANNEL_EMPTY_SLEEP_MAX_USEC / 2 + IPA_GSI_CHANNEL_EMPTY_SLEEP_MIN_USEC / 2); else usleep_range( IPA_GSI_CHANNEL_EMPTY_SLEEP_MIN_USEC, IPA_GSI_CHANNEL_EMPTY_SLEEP_MAX_USEC); goto send_cmd; } Loading Loading @@ -784,6 +838,37 @@ int ipa3_uc_reset_pipe(enum ipa_client_type ipa_client) return ret; } int ipa3_uc_is_gsi_channel_empty(enum ipa_client_type ipa_client) { struct ipa_gsi_ep_config *gsi_ep_info; union IpaHwChkChEmptyCmdData_t cmd; int ret; gsi_ep_info = ipa3_get_gsi_ep_info(ipa3_get_ep_mapping(ipa_client)); if (!gsi_ep_info) { IPAERR("Invalid IPA ep index\n"); return 0; } if (ipa3_uc_state_check()) { IPADBG("uC cannot be used to validate ch emptiness clnt=%d\n" , ipa_client); return 0; } cmd.params.ee_n = gsi_ep_info->ee; cmd.params.vir_ch_id = gsi_ep_info->ipa_gsi_chan_num; IPADBG("uC emptiness check for IPA GSI Channel %d\n", gsi_ep_info->ipa_gsi_chan_num); ret = ipa3_uc_send_cmd(cmd.raw32b, IPA_CPU_2_HW_CMD_GSI_CH_EMPTY, 0, false, 10*HZ); return ret; } /** * ipa3_uc_notify_clk_state() - notify to uC of clock enable / disable * @enabled: true if clock are enabled Loading
drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c +47 −40 Original line number Diff line number Diff line Loading @@ -2290,9 +2290,12 @@ static int ipa3_ssr_notifier_cb(struct notifier_block *this, unsigned long code, void *data) { if (ipa3_rmnet_ctx.ipa_rmnet_ssr) { if (SUBSYS_BEFORE_SHUTDOWN == code) { pr_info("IPA received MPSS BEFORE_SHUTDOWN\n"); if (!ipa3_rmnet_ctx.ipa_rmnet_ssr) return NOTIFY_DONE; switch (code) { case SUBSYS_BEFORE_SHUTDOWN: IPAWANINFO("IPA received MPSS BEFORE_SHUTDOWN\n"); atomic_set(&rmnet_ipa3_ctx->is_ssr, 1); ipa3_q6_cleanup(); if (IPA_NETDEV()) Loading @@ -2300,37 +2303,41 @@ static int ipa3_ssr_notifier_cb(struct notifier_block *this, ipa3_qmi_stop_workqueues(); ipa3_wan_ioctl_stop_qmi_messages(); ipa_stop_polling_stats(); atomic_set(&rmnet_ipa3_ctx->is_ssr, 1); if (atomic_read(&rmnet_ipa3_ctx->is_initialized)) platform_driver_unregister(&rmnet_ipa_driver); pr_info("IPA BEFORE_SHUTDOWN handling is complete\n"); return NOTIFY_DONE; } if (SUBSYS_AFTER_SHUTDOWN == code) { pr_info("IPA received MPSS AFTER_SHUTDOWN\n"); IPAWANINFO("IPA BEFORE_SHUTDOWN handling is complete\n"); break; case SUBSYS_AFTER_SHUTDOWN: IPAWANINFO("IPA Received MPSS AFTER_SHUTDOWN\n"); if (atomic_read(&rmnet_ipa3_ctx->is_ssr)) ipa3_q6_pipe_reset(); pr_info("IPA AFTER_SHUTDOWN handling is complete\n"); return NOTIFY_DONE; } if (SUBSYS_AFTER_POWERUP == code) { pr_info("IPA received MPSS AFTER_POWERUP\n"); if (!atomic_read(&rmnet_ipa3_ctx->is_initialized) && atomic_read(&rmnet_ipa3_ctx->is_ssr)) platform_driver_register(&rmnet_ipa_driver); pr_info("IPA AFTER_POWERUP handling is complete\n"); return NOTIFY_DONE; } if (SUBSYS_BEFORE_POWERUP == code) { pr_info("IPA received MPSS BEFORE_POWERUP\n"); ipa3_validate_q6_gsi_channel_empty(); IPAWANINFO("IPA AFTER_SHUTDOWN handling is complete\n"); break; case SUBSYS_BEFORE_POWERUP: IPAWANINFO("IPA received MPSS BEFORE_POWERUP\n"); if (atomic_read(&rmnet_ipa3_ctx->is_ssr)) /* clean up cached QMI msg/handlers */ ipa3_qmi_service_exit(); /*hold a proxy vote for the modem*/ ipa3_proxy_clk_vote(); pr_info("IPA BEFORE_POWERUP handling is complete\n"); return NOTIFY_DONE; } IPAWANINFO("IPA BEFORE_POWERUP handling is complete\n"); break; case SUBSYS_AFTER_POWERUP: IPAWANINFO("%s:%d IPA received MPSS AFTER_POWERUP\n", __func__, __LINE__); if (!atomic_read(&rmnet_ipa3_ctx->is_initialized) && atomic_read(&rmnet_ipa3_ctx->is_ssr)) platform_driver_register(&rmnet_ipa_driver); IPAWANINFO("IPA AFTER_POWERUP handling is complete\n"); break; default: IPAWANDBG("Unsupported subsys notification, IPA received: %lu", code); break; } IPAWANDBG("Exit\n"); return NOTIFY_DONE; } Loading