msm: ipa3: Add SSR support for IPA3.1

Add SubSystem Restart APPS support for IPA3.1

CRs-Fixed: 991549
Change-Id: I98dbc4cef7c08fa7452a6912e4f98270c72dc6d2
Signed-off-by: Nadine Toledano <nadinet@codeaurora.org>
Signed-off-by: Ghanim Fodi <gfodi@codeaurora.org>
This commit is contained in:
Ghanim Fodi 2016-03-20 18:23:12 +02:00 committed by Jeevan Shriram
parent 2113925929
commit 35d39fbf1c
5 changed files with 233 additions and 177 deletions

View file

@ -1647,39 +1647,40 @@ static void ipa3_destroy_imm(void *user1, int user2)
ipahal_destroy_imm_cmd(user1); ipahal_destroy_imm_cmd(user1);
} }
static int ipa3_q6_pipe_delay(void) static void ipa3_q6_pipe_delay(bool delay)
{ {
int client_idx; int client_idx;
int ep_idx; int ep_idx;
struct ipa_ep_cfg_ctrl ep_ctrl; struct ipa_ep_cfg_ctrl ep_ctrl;
memset(&ep_ctrl, 0, sizeof(struct ipa_ep_cfg_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++) { for (client_idx = 0; client_idx < IPA_CLIENT_MAX; client_idx++) {
if (IPA_CLIENT_IS_Q6_PROD(client_idx)) { if (IPA_CLIENT_IS_Q6_PROD(client_idx)) {
ep_idx = ipa3_get_ep_mapping(client_idx); ep_idx = ipa3_get_ep_mapping(client_idx);
if (ep_idx == -1) if (ep_idx == -1)
continue; continue;
ep_ctrl.ipa_ep_delay = 1;
ipahal_write_reg_n_fields(IPA_ENDP_INIT_CTRL_n, ipahal_write_reg_n_fields(IPA_ENDP_INIT_CTRL_n,
ep_idx, &ep_ctrl); ep_idx, &ep_ctrl);
} }
} }
return 0;
} }
static int ipa3_q6_avoid_holb(void) static void ipa3_q6_avoid_holb(void)
{ {
int ep_idx; int ep_idx;
int client_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; 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)); 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++) { for (client_idx = 0; client_idx < IPA_CLIENT_MAX; client_idx++) {
if (IPA_CLIENT_IS_Q6_CONS(client_idx)) { if (IPA_CLIENT_IS_Q6_CONS(client_idx)) {
@ -1693,8 +1694,6 @@ static int ipa3_q6_avoid_holb(void)
* they are not valid, therefore, the above function * they are not valid, therefore, the above function
* will fail. * will fail.
*/ */
ep_holb.tmr_val = 0;
ep_holb.en = 1;
ipahal_write_reg_n_fields( ipahal_write_reg_n_fields(
IPA_ENDP_INIT_HOL_BLOCK_TIMER_n, IPA_ENDP_INIT_HOL_BLOCK_TIMER_n,
ep_idx, &ep_holb); ep_idx, &ep_holb);
@ -1702,11 +1701,11 @@ static int ipa3_q6_avoid_holb(void)
IPA_ENDP_INIT_HOL_BLOCK_EN_n, IPA_ENDP_INIT_HOL_BLOCK_EN_n,
ep_idx, &ep_holb); 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) static u32 ipa3_get_max_flt_rt_cmds(u32 num_pipes)
@ -1785,8 +1784,7 @@ static int ipa3_q6_clean_q6_tables(void)
*/ */
cmd.is_read = false; cmd.is_read = false;
cmd.skip_pipeline_clear = 0; cmd.skip_pipeline_clear = 0;
cmd.pipeline_clear_options = cmd.pipeline_clear_options = IPAHAL_HPS_CLEAR;
IPAHAL_FULL_PIPELINE_CLEAR;
cmd.size = mem.size; cmd.size = mem.size;
cmd.system_addr = mem.phys_base; cmd.system_addr = mem.phys_base;
cmd.local_addr = cmd.local_addr =
@ -1810,8 +1808,7 @@ static int ipa3_q6_clean_q6_tables(void)
cmd.is_read = false; cmd.is_read = false;
cmd.skip_pipeline_clear = false; cmd.skip_pipeline_clear = false;
cmd.pipeline_clear_options = cmd.pipeline_clear_options = IPAHAL_HPS_CLEAR;
IPAHAL_FULL_PIPELINE_CLEAR;
cmd.size = mem.size; cmd.size = mem.size;
cmd.system_addr = mem.phys_base; cmd.system_addr = mem.phys_base;
cmd.local_addr = cmd.local_addr =
@ -1839,8 +1836,7 @@ static int ipa3_q6_clean_q6_tables(void)
*/ */
cmd.is_read = false; cmd.is_read = false;
cmd.skip_pipeline_clear = false; cmd.skip_pipeline_clear = false;
cmd.pipeline_clear_options = cmd.pipeline_clear_options = IPAHAL_HPS_CLEAR;
IPAHAL_FULL_PIPELINE_CLEAR;
cmd.size = mem.size; cmd.size = mem.size;
cmd.system_addr = mem.phys_base; cmd.system_addr = mem.phys_base;
cmd.local_addr = cmd.local_addr =
@ -1864,8 +1860,7 @@ static int ipa3_q6_clean_q6_tables(void)
cmd.is_read = false; cmd.is_read = false;
cmd.skip_pipeline_clear = 0; cmd.skip_pipeline_clear = 0;
cmd.pipeline_clear_options = cmd.pipeline_clear_options = IPAHAL_HPS_CLEAR;
IPAHAL_FULL_PIPELINE_CLEAR;
cmd.size = mem.size; cmd.size = mem.size;
cmd.system_addr = mem.phys_base; cmd.system_addr = mem.phys_base;
cmd.local_addr = cmd.local_addr =
@ -1897,7 +1892,7 @@ static int ipa3_q6_clean_q6_tables(void)
index++) { index++) {
cmd.is_read = false; cmd.is_read = false;
cmd.skip_pipeline_clear = 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.size = mem.size;
cmd.system_addr = mem.phys_base; cmd.system_addr = mem.phys_base;
cmd.local_addr = ipa3_ctx->smem_restricted_bytes + cmd.local_addr = ipa3_ctx->smem_restricted_bytes +
@ -1919,7 +1914,7 @@ static int ipa3_q6_clean_q6_tables(void)
cmd.is_read = false; cmd.is_read = false;
cmd.skip_pipeline_clear = 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.size = mem.size;
cmd.system_addr = mem.phys_base; cmd.system_addr = mem.phys_base;
cmd.local_addr = ipa3_ctx->smem_restricted_bytes + cmd.local_addr = ipa3_ctx->smem_restricted_bytes +
@ -1945,8 +1940,7 @@ static int ipa3_q6_clean_q6_tables(void)
index++) { index++) {
cmd.is_read = false; cmd.is_read = false;
cmd.skip_pipeline_clear = false; cmd.skip_pipeline_clear = false;
cmd.pipeline_clear_options = cmd.pipeline_clear_options = IPAHAL_HPS_CLEAR;
IPAHAL_FULL_PIPELINE_CLEAR;
cmd.size = mem.size; cmd.size = mem.size;
cmd.system_addr = mem.phys_base; cmd.system_addr = mem.phys_base;
cmd.local_addr = ipa3_ctx->smem_restricted_bytes + cmd.local_addr = ipa3_ctx->smem_restricted_bytes +
@ -1968,8 +1962,7 @@ static int ipa3_q6_clean_q6_tables(void)
cmd.is_read = false; cmd.is_read = false;
cmd.skip_pipeline_clear = false; cmd.skip_pipeline_clear = false;
cmd.pipeline_clear_options = cmd.pipeline_clear_options = IPAHAL_HPS_CLEAR;
IPAHAL_FULL_PIPELINE_CLEAR;
cmd.size = mem.size; cmd.size = mem.size;
cmd.system_addr = mem.phys_base; cmd.system_addr = mem.phys_base;
cmd.local_addr = ipa3_ctx->smem_restricted_bytes + cmd.local_addr = ipa3_ctx->smem_restricted_bytes +
@ -2008,21 +2001,7 @@ bail_dma:
return retval; return retval;
} }
static void ipa3_q6_disable_agg_reg( static int ipa3_q6_set_ex_path_to_apps(void)
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)
{ {
int ep_idx; int ep_idx;
int client_idx; int client_idx;
@ -2053,7 +2032,7 @@ static int ipa3_q6_set_ex_path_dis_agg(void)
reg_write.skip_pipeline_clear = false; reg_write.skip_pipeline_clear = false;
reg_write.pipeline_clear_options = reg_write.pipeline_clear_options =
IPAHAL_FULL_PIPELINE_CLEAR; IPAHAL_HPS_CLEAR;
reg_write.offset = reg_write.offset =
ipahal_get_reg_ofst(IPA_ENDP_STATUS_n); ipahal_get_reg_ofst(IPA_ENDP_STATUS_n);
ipahal_get_status_ep_valmask( ipahal_get_status_ep_valmask(
@ -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(&reg_write,
ipa3_get_ep_mapping(client_idx));
cmd_pyld = ipahal_construct_imm_cmd(
IPA_IMM_CMD_REGISTER_WRITE, &reg_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 */ /* Will wait 150msecs for IPA tag process completion */
retval = ipa3_tag_process(desc, num_descs, retval = ipa3_tag_process(desc, num_descs,
msecs_to_jiffies(CLEANUP_TAG_PROCESS_TIMEOUT)); msecs_to_jiffies(CLEANUP_TAG_PROCESS_TIMEOUT));
@ -2127,70 +2082,65 @@ static int ipa3_q6_set_ex_path_dis_agg(void)
* ipa3_q6_cleanup() - A cleanup for all Q6 related configuration * ipa3_q6_cleanup() - A cleanup for all Q6 related configuration
* in IPA HW. This is performed in case of SSR. * 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 * This is a mandatory procedure, in case one of the steps fails, the
* AP needs to restart. * 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, IPADBG_LOW("ENTER\n");
* APPS need to assert (This is a non recoverable error).
*/
if (ipa3_ctx->uc_ctx.uc_zip_error)
BUG();
IPA_ACTIVE_CLIENTS_INC_SPECIAL("Q6"); IPA_ACTIVE_CLIENTS_INC_SIMPLE();
if (ipa3_q6_pipe_delay()) { ipa3_q6_pipe_delay(true);
IPAERR("Failed to delay Q6 pipes\n"); ipa3_q6_avoid_holb();
BUG();
}
if (ipa3_q6_avoid_holb()) {
IPAERR("Failed to set HOLB on Q6 pipes\n");
BUG();
}
if (ipa3_q6_clean_q6_tables()) { if (ipa3_q6_clean_q6_tables()) {
IPAERR("Failed to clean Q6 tables\n"); IPAERR("Failed to clean Q6 tables\n");
BUG(); BUG();
} }
if (ipa3_q6_set_ex_path_dis_agg()) { if (ipa3_q6_set_ex_path_to_apps()) {
IPAERR("Failed to disable aggregation on Q6 pipes\n"); IPAERR("Failed to redirect exceptions to APPS\n");
BUG(); 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; IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
IPADBG_LOW("Exit with success\n");
return 0;
} }
/** /*
* ipa3_q6_pipe_reset() - A cleanup for the Q6 pipes * ipa3_validate_q6_gsi_channel_empty() - Check if GSI channel related to Q6
* in IPA HW. This is performed in case of SSR. * producer client is empty. This is used in case of SSR.
* *
* Return codes: * Q6 GSI channel emptiness is needed to garantee no descriptors with invalid
* 0: success * info are injected into IPA RX from IPA_IF, while modem is restarting.
* This is a mandatory procedure, in case one of the steps fails, the */
* AP needs to restart. void ipa3_validate_q6_gsi_channel_empty(void)
*/
int ipa3_q6_pipe_reset(void)
{ {
int client_idx; int client_idx;
int res;
IPADBG_LOW("ENTER\n");
IPA_ACTIVE_CLIENTS_INC_SIMPLE();
if (!ipa3_ctx->uc_ctx.uc_loaded) { if (!ipa3_ctx->uc_ctx.uc_loaded) {
IPAERR("uC is not loaded, won't reset Q6 pipes\n"); IPAERR("uC is not loaded. Skipping\n");
return 0; return;
} }
for (client_idx = 0; client_idx < IPA_CLIENT_MAX; client_idx++) for (client_idx = 0; client_idx < IPA_CLIENT_MAX; client_idx++)
if (IPA_CLIENT_IS_Q6_CONS(client_idx) || if (IPA_CLIENT_IS_Q6_PROD(client_idx)) {
IPA_CLIENT_IS_Q6_PROD(client_idx)) { if (ipa3_uc_is_gsi_channel_empty(client_idx)) {
res = ipa3_uc_reset_pipe(client_idx); IPAERR("fail to validate Q6 ch emptiness %d\n",
if (res) client_idx);
BUG(); 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) static inline void ipa3_sram_set_canary(u32 *sram_mmio, int offset)

View file

@ -204,6 +204,10 @@
#define IPA_GSI_CHANNEL_STOP_SLEEP_MIN_USEC (1000) #define IPA_GSI_CHANNEL_STOP_SLEEP_MIN_USEC (1000)
#define IPA_GSI_CHANNEL_STOP_SLEEP_MAX_USEC (2000) #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_SLEEP_CLK_RATE_KHZ (32)
#define IPA_ACTIVE_CLIENTS_PREP_EP(log_info, client) \ #define IPA_ACTIVE_CLIENTS_PREP_EP(log_info, client) \
@ -1081,22 +1085,29 @@ struct ipa3_controller;
* enum ipa3_hw_features - Values that represent the features supported in IPA HW * 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_COMMON : Feature related to common operation of IPA HW
* @IPA_HW_FEATURE_MHI : Feature related to MHI operation in 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_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 { enum ipa3_hw_features {
IPA_HW_FEATURE_COMMON = 0x0, IPA_HW_FEATURE_COMMON = 0x0,
IPA_HW_FEATURE_MHI = 0x1, IPA_HW_FEATURE_MHI = 0x1,
IPA_HW_FEATURE_WDI = 0x3, IPA_HW_FEATURE_POWER_COLLAPSE = 0x2,
IPA_HW_FEATURE_MAX = IPA_HW_NUM_FEATURES 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. * 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 * @IPA_HW_2_CPU_EVENT_ERROR : Event specify a system error is detected by the
* device * device
* @IPA_HW_2_CPU_EVENT_LOG_INFO : Event providing logging specific information * @IPA_HW_2_CPU_EVENT_LOG_INFO : Event providing logging specific information
*/ */
enum ipa3_hw_2_cpu_events { 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 = IPA_HW_2_CPU_EVENT_ERROR =
FEATURE_ENUM_VAL(IPA_HW_FEATURE_COMMON, 1), FEATURE_ENUM_VAL(IPA_HW_FEATURE_COMMON, 1),
IPA_HW_2_CPU_EVENT_LOG_INFO = IPA_HW_2_CPU_EVENT_LOG_INFO =
@ -1110,7 +1121,8 @@ enum ipa3_hw_2_cpu_events {
* @IPA_HW_DMA_ERROR : Unexpected DMA error * @IPA_HW_DMA_ERROR : Unexpected DMA error
* @IPA_HW_FATAL_SYSTEM_ERROR : HW has crashed and requires reset. * @IPA_HW_FATAL_SYSTEM_ERROR : HW has crashed and requires reset.
* @IPA_HW_INVALID_OPCODE : Invalid opcode sent * @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 { enum ipa3_hw_errors {
IPA_HW_ERROR_NONE = IPA_HW_ERROR_NONE =
@ -1123,12 +1135,14 @@ enum ipa3_hw_errors {
FEATURE_ENUM_VAL(IPA_HW_FEATURE_COMMON, 3), FEATURE_ENUM_VAL(IPA_HW_FEATURE_COMMON, 3),
IPA_HW_INVALID_OPCODE = IPA_HW_INVALID_OPCODE =
FEATURE_ENUM_VAL(IPA_HW_FEATURE_COMMON, 4), 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), FEATURE_ENUM_VAL(IPA_HW_FEATURE_COMMON, 5),
IPA_HW_CONS_DISABLE_CMD_GSI_STOP_FAILURE = IPA_HW_CONS_DISABLE_CMD_GSI_STOP_FAILURE =
FEATURE_ENUM_VAL(IPA_HW_FEATURE_COMMON, 6), FEATURE_ENUM_VAL(IPA_HW_FEATURE_COMMON, 6),
IPA_HW_PROD_DISABLE_CMD_GSI_STOP_FAILURE = 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)
}; };
/** /**
@ -1162,14 +1176,13 @@ struct IpaHwSharedMemCommonMapping_t {
u32 cmdParams; u32 cmdParams;
u32 cmdParams_hi; u32 cmdParams_hi;
u8 responseOp; u8 responseOp;
u8 reserved_09; u8 reserved_0D;
u16 reserved_0B_0A; u16 reserved_0F_0E;
u32 responseParams; u32 responseParams;
u8 eventOp; u8 eventOp;
u8 reserved_11; u8 reserved_15;
u16 reserved_13_12; u16 reserved_17_16;
u32 eventParams; u32 eventParams;
u32 reserved_1B_18;
u32 firstErrorAddress; u32 firstErrorAddress;
u8 hwState; u8 hwState;
u8 warningCounter; u8 warningCounter;
@ -1355,7 +1368,6 @@ union IpaHwMhiDlUlSyncCmdData_t {
* @uc_sram_mmio: Pointer to uC mapped memory * @uc_sram_mmio: Pointer to uC mapped memory
* @pending_cmd: The last command sent waiting to be ACKed * @pending_cmd: The last command sent waiting to be ACKed
* @uc_status: The last status provided by the uC * @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_type: error type from uC error event
* @uc_error_timestamp: tag timer sampled after uC crashed * @uc_error_timestamp: tag timer sampled after uC crashed
*/ */
@ -1371,7 +1383,6 @@ struct ipa3_uc_ctx {
u32 uc_event_top_ofst; u32 uc_event_top_ofst;
u32 pending_cmd; u32 pending_cmd;
u32 uc_status; u32 uc_status;
bool uc_zip_error;
u32 uc_error_type; u32 uc_error_type;
u32 uc_error_timestamp; u32 uc_error_timestamp;
}; };
@ -2307,8 +2318,8 @@ int ipa3_write_qmapid_wdi_pipe(u32 clnt_hdl, u8 qmap_id);
int ipa3_tag_process(struct ipa3_desc *desc, int num_descs, int ipa3_tag_process(struct ipa3_desc *desc, int num_descs,
unsigned long timeout); unsigned long timeout);
int ipa3_q6_cleanup(void); void ipa3_q6_cleanup(void);
int ipa3_q6_pipe_reset(void); void ipa3_validate_q6_gsi_channel_empty(void);
int ipa3_init_q6_smem(void); int ipa3_init_q6_smem(void);
int ipa3_sps_connect_safe(struct sps_pipe *h, struct sps_connect *connect, int ipa3_sps_connect_safe(struct sps_pipe *h, struct sps_connect *connect,
@ -2318,6 +2329,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_interface_init(void);
int ipa3_uc_reset_pipe(enum ipa_client_type ipa_client); 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_state_check(void);
int ipa3_uc_loaded_check(void); int ipa3_uc_loaded_check(void);
void ipa3_uc_load_notify(void); void ipa3_uc_load_notify(void);

View file

@ -1,4 +1,4 @@
/* 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 * 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 * it under the terms of the GNU General Public License version 2 and
@ -34,6 +34,8 @@
pr_debug(DEV_NAME " %s:%d " fmt, __func__, __LINE__, ## args) pr_debug(DEV_NAME " %s:%d " fmt, __func__, __LINE__, ## args)
#define IPAWANERR(fmt, args...) \ #define IPAWANERR(fmt, args...) \
pr_err(DEV_NAME " %s:%d " fmt, __func__, __LINE__, ## 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; extern struct ipa3_qmi_context *ipa3_qmi_ctx;

View file

@ -13,7 +13,7 @@
#include <linux/delay.h> #include <linux/delay.h>
#define IPA_RAM_UC_SMEM_SIZE 128 #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_PKT_FLUSH_TO_US 100
#define IPA_UC_POLL_SLEEP_USEC 100 #define IPA_UC_POLL_SLEEP_USEC 100
#define IPA_UC_POLL_MAX_RETRY 10000 #define IPA_UC_POLL_MAX_RETRY 10000
@ -40,6 +40,7 @@
* IPA_CPU_2_HW_CMD_CLK_UNGATE : CPU instructs HW to goto Clock Ungated state. * 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_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_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 { enum ipa3_cpu_2_hw_commands {
IPA_CPU_2_HW_CMD_NO_OP = IPA_CPU_2_HW_CMD_NO_OP =
@ -62,20 +63,29 @@ enum ipa3_cpu_2_hw_commands {
FEATURE_ENUM_VAL(IPA_HW_FEATURE_COMMON, 8), FEATURE_ENUM_VAL(IPA_HW_FEATURE_COMMON, 8),
IPA_CPU_2_HW_CMD_REG_WRITE = IPA_CPU_2_HW_CMD_REG_WRITE =
FEATURE_ENUM_VAL(IPA_HW_FEATURE_COMMON, 9), 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 * enum ipa3_hw_2_cpu_responses - Values that represent common HW responses
* to CPU commands. * 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 * @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 * 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_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 { 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 = IPA_HW_2_CPU_RESPONSE_INIT_COMPLETED =
FEATURE_ENUM_VAL(IPA_HW_FEATURE_COMMON, 1), FEATURE_ENUM_VAL(IPA_HW_FEATURE_COMMON, 1),
IPA_HW_2_CPU_RESPONSE_CMD_COMPLETED = IPA_HW_2_CPU_RESPONSE_CMD_COMPLETED =
FEATURE_ENUM_VAL(IPA_HW_FEATURE_COMMON, 2), FEATURE_ENUM_VAL(IPA_HW_FEATURE_COMMON, 2),
IPA_HW_2_CPU_RESPONSE_DEBUG_GET_INFO =
FEATURE_ENUM_VAL(IPA_HW_FEATURE_COMMON, 3),
}; };
/** /**
@ -152,6 +162,23 @@ union IpaHwUpdateFlagsCmdData_t {
u32 raw32b; 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 * When resource group 10 limitation mitigation is enabled, uC send
* cmd should be able to run in interrupt context, so using spin lock * cmd should be able to run in interrupt context, so using spin lock
@ -186,14 +213,26 @@ const char *ipa_hw_error_str(enum ipa3_hw_errors err_type)
case IPA_HW_INVALID_DOORBELL_ERROR: case IPA_HW_INVALID_DOORBELL_ERROR:
str = "IPA_HW_INVALID_DOORBELL_ERROR"; str = "IPA_HW_INVALID_DOORBELL_ERROR";
break; break;
case IPA_HW_DMA_ERROR:
str = "IPA_HW_DMA_ERROR";
break;
case IPA_HW_FATAL_SYSTEM_ERROR: case IPA_HW_FATAL_SYSTEM_ERROR:
str = "IPA_HW_FATAL_SYSTEM_ERROR"; str = "IPA_HW_FATAL_SYSTEM_ERROR";
break; break;
case IPA_HW_INVALID_OPCODE: case IPA_HW_INVALID_OPCODE:
str = "IPA_HW_INVALID_OPCODE"; str = "IPA_HW_INVALID_OPCODE";
break; break;
case IPA_HW_ZIP_ENGINE_ERROR: case IPA_HW_INVALID_PARAMS:
str = "IPA_HW_ZIP_ENGINE_ERROR"; 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; break;
default: default:
str = "INVALID ipa_hw_errors type"; str = "INVALID ipa_hw_errors type";
@ -324,10 +363,6 @@ static void ipa3_uc_event_handler(enum ipa_irq_type interrupt,
ipa_hw_error_str(evt.params.errorType)); ipa_hw_error_str(evt.params.errorType));
ipa3_ctx->uc_ctx.uc_failed = true; ipa3_ctx->uc_ctx.uc_failed = true;
ipa3_ctx->uc_ctx.uc_error_type = evt.params.errorType; 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 = ipa3_ctx->uc_ctx.uc_error_timestamp =
ipahal_read_reg(IPA_TAG_TIMER); ipahal_read_reg(IPA_TAG_TIMER);
BUG(); BUG();
@ -466,7 +501,7 @@ static int ipa3_uc_send_cmd_64b_param(u32 cmd_lo, u32 cmd_hi, u32 opcode,
unsigned long flags; unsigned long flags;
int retries = 0; int retries = 0;
send_cmd: send_cmd_lock:
IPA3_UC_LOCK(flags); IPA3_UC_LOCK(flags);
if (ipa3_uc_state_check()) { if (ipa3_uc_state_check()) {
@ -474,7 +509,7 @@ send_cmd:
IPA3_UC_UNLOCK(flags); IPA3_UC_UNLOCK(flags);
return -EBADF; return -EBADF;
} }
send_cmd:
if (ipa3_ctx->apply_rg10_wa) { if (ipa3_ctx->apply_rg10_wa) {
if (!polling_mode) if (!polling_mode)
IPADBG("Overriding mode to polling mode\n"); IPADBG("Overriding mode to polling mode\n");
@ -563,6 +598,25 @@ send_cmd:
/* sleep for short period to flush IPA */ /* sleep for short period to flush IPA */
usleep_range(IPA_GSI_CHANNEL_STOP_SLEEP_MIN_USEC, usleep_range(IPA_GSI_CHANNEL_STOP_SLEEP_MIN_USEC,
IPA_GSI_CHANNEL_STOP_SLEEP_MAX_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; goto send_cmd;
} }
@ -784,6 +838,37 @@ int ipa3_uc_reset_pipe(enum ipa_client_type ipa_client)
return ret; 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 * ipa3_uc_notify_clk_state() - notify to uC of clock enable / disable
* @enabled: true if clock are enabled * @enabled: true if clock are enabled

View file

@ -2290,47 +2290,54 @@ static int ipa3_ssr_notifier_cb(struct notifier_block *this,
unsigned long code, unsigned long code,
void *data) void *data)
{ {
if (ipa3_rmnet_ctx.ipa_rmnet_ssr) { if (!ipa3_rmnet_ctx.ipa_rmnet_ssr)
if (SUBSYS_BEFORE_SHUTDOWN == code) { return NOTIFY_DONE;
pr_info("IPA received MPSS BEFORE_SHUTDOWN\n");
atomic_set(&rmnet_ipa3_ctx->is_ssr, 1); switch (code) {
ipa3_q6_cleanup(); case SUBSYS_BEFORE_SHUTDOWN:
if (IPA_NETDEV()) IPAWANINFO("IPA received MPSS BEFORE_SHUTDOWN\n");
netif_stop_queue(IPA_NETDEV()); atomic_set(&rmnet_ipa3_ctx->is_ssr, 1);
ipa3_qmi_stop_workqueues(); ipa3_q6_cleanup();
ipa3_wan_ioctl_stop_qmi_messages(); if (IPA_NETDEV())
ipa_stop_polling_stats(); netif_stop_queue(IPA_NETDEV());
atomic_set(&rmnet_ipa3_ctx->is_ssr, 1); ipa3_qmi_stop_workqueues();
if (atomic_read(&rmnet_ipa3_ctx->is_initialized)) ipa3_wan_ioctl_stop_qmi_messages();
platform_driver_unregister(&rmnet_ipa_driver); ipa_stop_polling_stats();
pr_info("IPA BEFORE_SHUTDOWN handling is complete\n"); if (atomic_read(&rmnet_ipa3_ctx->is_initialized))
return NOTIFY_DONE; platform_driver_unregister(&rmnet_ipa_driver);
} IPAWANINFO("IPA BEFORE_SHUTDOWN handling is complete\n");
if (SUBSYS_AFTER_SHUTDOWN == code) { break;
pr_info("IPA received MPSS AFTER_SHUTDOWN\n"); case SUBSYS_AFTER_SHUTDOWN:
if (atomic_read(&rmnet_ipa3_ctx->is_ssr)) IPAWANINFO("IPA Received MPSS AFTER_SHUTDOWN\n");
ipa3_q6_pipe_reset(); if (atomic_read(&rmnet_ipa3_ctx->is_ssr))
pr_info("IPA AFTER_SHUTDOWN handling is complete\n"); ipa3_validate_q6_gsi_channel_empty();
return NOTIFY_DONE; IPAWANINFO("IPA AFTER_SHUTDOWN handling is complete\n");
} break;
if (SUBSYS_AFTER_POWERUP == code) { case SUBSYS_BEFORE_POWERUP:
pr_info("IPA received MPSS AFTER_POWERUP\n"); IPAWANINFO("IPA received MPSS BEFORE_POWERUP\n");
if (!atomic_read(&rmnet_ipa3_ctx->is_initialized) if (atomic_read(&rmnet_ipa3_ctx->is_ssr))
&& atomic_read(&rmnet_ipa3_ctx->is_ssr)) /* clean up cached QMI msg/handlers */
platform_driver_register(&rmnet_ipa_driver); ipa3_qmi_service_exit();
pr_info("IPA AFTER_POWERUP handling is complete\n"); /*hold a proxy vote for the modem*/
return NOTIFY_DONE; ipa3_proxy_clk_vote();
} IPAWANINFO("IPA BEFORE_POWERUP handling is complete\n");
if (SUBSYS_BEFORE_POWERUP == code) { break;
pr_info("IPA received MPSS BEFORE_POWERUP\n"); case SUBSYS_AFTER_POWERUP:
if (atomic_read(&rmnet_ipa3_ctx->is_ssr)) IPAWANINFO("%s:%d IPA received MPSS AFTER_POWERUP\n",
/* clean up cached QMI msg/handlers */ __func__, __LINE__);
ipa3_qmi_service_exit(); if (!atomic_read(&rmnet_ipa3_ctx->is_initialized) &&
ipa3_proxy_clk_vote(); atomic_read(&rmnet_ipa3_ctx->is_ssr))
pr_info("IPA BEFORE_POWERUP handling is complete\n"); platform_driver_register(&rmnet_ipa_driver);
return NOTIFY_DONE;
} 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; return NOTIFY_DONE;
} }