msm: ipa4: Enhanced flow control changes

Adding changes to support enhanced flow control.

Change-Id: Id656319703a27f5073c6fd129fb4202a37b49aad
Signed-off-by: Ashok Vuyyuru <avuyyuru@codeaurora.org>
This commit is contained in:
Ashok Vuyyuru 2020-03-27 02:31:37 +05:30
parent 3da31ea0a2
commit f20c9b46d4
10 changed files with 346 additions and 28 deletions

View File

@ -1367,6 +1367,10 @@ int gsi_register_device(struct gsi_per_props *props, unsigned long *dev_hdl)
gsi_writel(0, gsi_ctx->base +
GSI_EE_n_ERROR_LOG_OFFS(gsi_ctx->per.ee));
/* Reset to zero scratch_1 register*/
gsi_writel(0, gsi_ctx->base +
GSI_EE_n_CNTXT_SCRATCH_1_OFFS(gsi_ctx->per.ee));
if (running_emulation) {
/*
* Set up the emulator's interrupt controller...
@ -4713,6 +4717,165 @@ free_lock:
}
EXPORT_SYMBOL(gsi_enable_flow_control_ee);
int gsi_flow_control_ee(unsigned int chan_idx, unsigned int ee,
bool enable, bool prmy_scnd_fc, int *code)
{
enum gsi_generic_ee_cmd_opcode op = enable ?
GSI_GEN_EE_CMD_ENABLE_FLOW_CHANNEL :
GSI_GEN_EE_CMD_DISABLE_FLOW_CHANNEL;
uint32_t val;
int res;
if (!gsi_ctx) {
pr_err("%s:%d gsi context not allocated\n", __func__, __LINE__);
return -GSI_STATUS_NODEV;
}
if (chan_idx >= gsi_ctx->max_ch || !code) {
GSIERR("bad params chan_idx=%d\n", chan_idx);
return -GSI_STATUS_INVALID_PARAMS;
}
mutex_lock(&gsi_ctx->mlock);
__gsi_config_glob_irq(gsi_ctx->per.ee,
GSI_EE_n_CNTXT_GLOB_IRQ_EN_GP_INT1_BMSK, ~0);
reinit_completion(&gsi_ctx->gen_ee_cmd_compl);
/* invalidate the response */
gsi_ctx->scratch.word0.val = gsi_readl(gsi_ctx->base +
GSI_EE_n_CNTXT_SCRATCH_0_OFFS(gsi_ctx->per.ee));
gsi_ctx->scratch.word0.s.generic_ee_cmd_return_code = 0;
gsi_writel(gsi_ctx->scratch.word0.val, gsi_ctx->base +
GSI_EE_n_CNTXT_SCRATCH_0_OFFS(gsi_ctx->per.ee));
gsi_ctx->gen_ee_cmd_dbg.flow_ctrl_channel++;
val = (((op << GSI_EE_n_GSI_EE_GENERIC_CMD_OPCODE_SHFT) &
GSI_EE_n_GSI_EE_GENERIC_CMD_OPCODE_BMSK) |
((chan_idx << GSI_EE_n_GSI_EE_GENERIC_CMD_VIRT_CHAN_IDX_SHFT) &
GSI_EE_n_GSI_EE_GENERIC_CMD_VIRT_CHAN_IDX_BMSK) |
((ee << GSI_EE_n_GSI_EE_GENERIC_CMD_EE_SHFT) &
GSI_EE_n_GSI_EE_GENERIC_CMD_EE_BMSK) |
((prmy_scnd_fc << GSI_EE_n_GSI_EE_GENERIC_CMD_PARAM_SHFT) &
GSI_EE_n_GSI_EE_GENERIC_CMD_PARAM_BMSK));
gsi_writel(val, gsi_ctx->base +
GSI_EE_n_GSI_EE_GENERIC_CMD_OFFS(gsi_ctx->per.ee));
res = wait_for_completion_timeout(&gsi_ctx->gen_ee_cmd_compl,
msecs_to_jiffies(GSI_CMD_TIMEOUT));
if (res == 0) {
GSIERR("chan_idx=%u ee=%u timed out\n", chan_idx, ee);
res = -GSI_STATUS_TIMED_OUT;
GSI_ASSERT();
goto free_lock;
}
gsi_ctx->scratch.word0.val = gsi_readl(gsi_ctx->base +
GSI_EE_n_CNTXT_SCRATCH_0_OFFS(gsi_ctx->per.ee));
if (gsi_ctx->scratch.word0.s.generic_ee_cmd_return_code ==
GSI_GEN_EE_CMD_RETURN_CODE_CHANNEL_NOT_RUNNING) {
GSIDBG("chan_idx=%u ee=%u not in correct state\n",
chan_idx, ee);
*code = GSI_GEN_EE_CMD_RETURN_CODE_CHANNEL_NOT_RUNNING;
res = -GSI_STATUS_RES_ALLOC_FAILURE;
goto free_lock;
} else if (gsi_ctx->scratch.word0.s.generic_ee_cmd_return_code ==
GSI_GEN_EE_CMD_RETURN_CODE_INCORRECT_CHANNEL_TYPE ||
gsi_ctx->scratch.word0.s.generic_ee_cmd_return_code ==
GSI_GEN_EE_CMD_RETURN_CODE_INCORRECT_CHANNEL_INDEX){
GSIERR("chan_idx=%u ee=%u not in correct state\n",
chan_idx, ee);
GSI_ASSERT();
}
if (gsi_ctx->scratch.word0.s.generic_ee_cmd_return_code == 0) {
GSIERR("No response received\n");
res = -GSI_STATUS_ERROR;
goto free_lock;
}
*code = gsi_ctx->scratch.word0.s.generic_ee_cmd_return_code;
res = GSI_STATUS_SUCCESS;
free_lock:
__gsi_config_glob_irq(gsi_ctx->per.ee,
GSI_EE_n_CNTXT_GLOB_IRQ_EN_GP_INT1_BMSK, 0);
mutex_unlock(&gsi_ctx->mlock);
return res;
}
EXPORT_SYMBOL(gsi_flow_control_ee);
int gsi_query_flow_control_state_ee(unsigned int chan_idx, unsigned int ee,
bool prmy_scnd_fc, int *code)
{
enum gsi_generic_ee_cmd_opcode op = GSI_GEN_EE_CMD_QUERY_FLOW_CHANNEL;
uint32_t val;
int res;
if (!gsi_ctx) {
pr_err("%s:%d gsi context not allocated\n", __func__, __LINE__);
return -GSI_STATUS_NODEV;
}
if (chan_idx >= gsi_ctx->max_ch || !code) {
GSIERR("bad params chan_idx=%d\n", chan_idx);
return -GSI_STATUS_INVALID_PARAMS;
}
mutex_lock(&gsi_ctx->mlock);
__gsi_config_glob_irq(gsi_ctx->per.ee,
GSI_EE_n_CNTXT_GLOB_IRQ_EN_GP_INT1_BMSK, ~0);
reinit_completion(&gsi_ctx->gen_ee_cmd_compl);
/* invalidate the response */
gsi_ctx->scratch.word0.val = gsi_readl(gsi_ctx->base +
GSI_EE_n_CNTXT_SCRATCH_0_OFFS(gsi_ctx->per.ee));
gsi_ctx->scratch.word0.s.generic_ee_cmd_return_code = 0;
gsi_writel(gsi_ctx->scratch.word0.val, gsi_ctx->base +
GSI_EE_n_CNTXT_SCRATCH_0_OFFS(gsi_ctx->per.ee));
gsi_ctx->gen_ee_cmd_dbg.flow_ctrl_channel++;
val = (((op << GSI_EE_n_GSI_EE_GENERIC_CMD_OPCODE_SHFT) &
GSI_EE_n_GSI_EE_GENERIC_CMD_OPCODE_BMSK) |
((chan_idx << GSI_EE_n_GSI_EE_GENERIC_CMD_VIRT_CHAN_IDX_SHFT) &
GSI_EE_n_GSI_EE_GENERIC_CMD_VIRT_CHAN_IDX_BMSK) |
((ee << GSI_EE_n_GSI_EE_GENERIC_CMD_EE_SHFT) &
GSI_EE_n_GSI_EE_GENERIC_CMD_EE_BMSK) |
((prmy_scnd_fc << GSI_EE_n_GSI_EE_GENERIC_CMD_PARAM_SHFT) &
GSI_EE_n_GSI_EE_GENERIC_CMD_PARAM_BMSK));
gsi_writel(val, gsi_ctx->base +
GSI_EE_n_GSI_EE_GENERIC_CMD_OFFS(gsi_ctx->per.ee));
res = wait_for_completion_timeout(&gsi_ctx->gen_ee_cmd_compl,
msecs_to_jiffies(GSI_CMD_TIMEOUT));
if (res == 0) {
GSIERR("chan_idx=%u ee=%u timed out\n", chan_idx, ee);
res = -GSI_STATUS_TIMED_OUT;
goto free_lock;
}
gsi_ctx->scratch.word0.val = gsi_readl(gsi_ctx->base +
GSI_EE_n_CNTXT_SCRATCH_0_OFFS(gsi_ctx->per.ee));
*code = gsi_ctx->scratch.word0.s.generic_ee_cmd_return_val;
if (prmy_scnd_fc)
res = (gsi_ctx->scratch.word0.s.generic_ee_cmd_return_val ==
GSI_GEN_EE_CMD_RETURN_VAL_FLOW_CONTROL_SECONDARY)?
GSI_STATUS_SUCCESS:-GSI_STATUS_ERROR;
else
res = (gsi_ctx->scratch.word0.s.generic_ee_cmd_return_val ==
GSI_GEN_EE_CMD_RETURN_VAL_FLOW_CONTROL_PRIMARY)?
GSI_STATUS_SUCCESS:-GSI_STATUS_ERROR;
free_lock:
__gsi_config_glob_irq(gsi_ctx->per.ee,
GSI_EE_n_CNTXT_GLOB_IRQ_EN_GP_INT1_BMSK, 0);
mutex_unlock(&gsi_ctx->mlock);
return res;
}
EXPORT_SYMBOL(gsi_query_flow_control_state_ee);
int gsi_map_virtual_ch_to_per_ep(u32 ee, u32 chan_num, u32 per_ep_index)
{
if (!gsi_ctx) {

View File

@ -1228,7 +1228,9 @@ struct gsi_ee_scratch {
uint32_t inter_ee_cmd_return_code:3;
uint32_t resvd1:2;
uint32_t generic_ee_cmd_return_code:3;
uint32_t resvd2:7;
uint32_t resvd2:2;
uint32_t generic_ee_cmd_return_val:3;
uint32_t resvd4:2;
uint32_t max_usb_pkt_size:1;
uint32_t resvd3:8;
uint32_t mhi_base_chan_idx:8;
@ -1397,6 +1399,7 @@ enum gsi_generic_ee_cmd_opcode {
GSI_GEN_EE_CMD_ALLOC_CHANNEL = 0x2,
GSI_GEN_EE_CMD_ENABLE_FLOW_CHANNEL = 0x3,
GSI_GEN_EE_CMD_DISABLE_FLOW_CHANNEL = 0x4,
GSI_GEN_EE_CMD_QUERY_FLOW_CHANNEL = 0x5,
};
enum gsi_generic_ee_cmd_return_code {
@ -1409,6 +1412,11 @@ enum gsi_generic_ee_cmd_return_code {
GSI_GEN_EE_CMD_RETURN_CODE_OUT_OF_RESOURCES = 0x7,
};
enum gsi_generic_ee_cmd_query_retun_val {
GSI_GEN_EE_CMD_RETURN_VAL_FLOW_CONTROL_PRIMARY = 0,
GSI_GEN_EE_CMD_RETURN_VAL_FLOW_CONTROL_SECONDARY = 1,
GSI_GEN_EE_CMD_RETURN_VAL_FLOW_CONTROL_PENDING = 2,
};
extern struct gsi_ctx *gsi_ctx;
/**
@ -2119,7 +2127,10 @@ int gsi_alloc_channel_ee(unsigned int chan_idx, unsigned int ee, int *code);
*/
int gsi_enable_flow_control_ee(unsigned int chan_idx, unsigned int ee,
int *code);
int gsi_flow_control_ee(unsigned int chan_idx, unsigned int ee,
bool enable, bool prmy_scnd_fc, int *code);
int gsi_query_flow_control_state_ee(unsigned int chan_idx, unsigned int ee,
bool prmy_scnd_fc, int *code);
/*
* Here is a typical sequence of calls
*

View File

@ -749,6 +749,8 @@
#define GSI_EE_n_GSI_EE_GENERIC_CMD_VIRT_CHAN_IDX_SHFT 0x5
#define GSI_EE_n_GSI_EE_GENERIC_CMD_EE_BMSK 0x3c00
#define GSI_EE_n_GSI_EE_GENERIC_CMD_EE_SHFT 0xa
#define GSI_EE_n_GSI_EE_GENERIC_CMD_PARAM_BMSK 0xff000000
#define GSI_EE_n_GSI_EE_GENERIC_CMD_PARAM_SHFT 0x18
#define GSI_V1_0_EE_n_GSI_HW_PARAM_OFFS(n) \
(GSI_GSI_REG_BASE_OFFS + 0x0001f040 + 0x4000 * (n))
@ -1178,6 +1180,11 @@
#define GSI_EE_n_CNTXT_SCRATCH_0_SCRATCH_BMSK 0xffffffff
#define GSI_EE_n_CNTXT_SCRATCH_0_SCRATCH_SHFT 0x0
#define GSI_EE_n_CNTXT_SCRATCH_1_OFFS(n) \
(GSI_GSI_REG_BASE_OFFS + 0x00012404 + 0x4000 * (n))
#define GSI_EE_n_CNTXT_SCRATCH_1_SCRATCH_BMSK 0xffffffff
#define GSI_EE_n_CNTXT_SCRATCH_1_SCRATCH_SHFT 0x0
#define GSI_INTER_EE_n_SRC_GSI_CH_IRQ_OFFS(n) \
(GSI_GSI_REG_BASE_OFFS + 0x0000c018 + 0x1000 * (n))
#define GSI_INTER_EE_n_SRC_GSI_CH_IRQ_GSI_CH_BIT_MAP_BMSK 0xffffffff

View File

@ -3312,6 +3312,40 @@ static void ipa3_destroy_imm(void *user1, int user2)
ipahal_destroy_imm_cmd(user1);
}
static void ipa3_q6_pipe_flow_control(bool delay)
{
int ep_idx;
int client_idx;
int code = 0, result;
const struct ipa_gsi_ep_config *gsi_ep_cfg;
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;
gsi_ep_cfg = ipa3_get_gsi_ep_info(client_idx);
if (!gsi_ep_cfg) {
IPAERR("failed to get GSI config\n");
ipa_assert();
return;
}
IPADBG("pipe setting V2 flow control\n");
/* Configurig primary flow control on Q6 pipes*/
result = gsi_flow_control_ee(
gsi_ep_cfg->ipa_gsi_chan_num,
gsi_ep_cfg->ee, delay, false, &code);
if (result == GSI_STATUS_SUCCESS) {
IPADBG("sussess gsi ch %d with code %d\n",
gsi_ep_cfg->ipa_gsi_chan_num, code);
} else {
IPADBG("failed gsi ch %d code %d\n",
gsi_ep_cfg->ipa_gsi_chan_num, code);
}
}
}
}
static void ipa3_q6_pipe_delay(bool delay)
{
int client_idx;
@ -3987,8 +4021,12 @@ void ipa3_q6_pre_shutdown_cleanup(void)
IPA_ACTIVE_CLIENTS_INC_SIMPLE();
ipa3_update_ssr_state(true);
if (!ipa3_ctx->ipa_endp_delay_wa)
if (ipa3_ctx->ipa_endp_delay_wa_v2)
ipa3_q6_pipe_flow_control(true);
else if (!ipa3_ctx->ipa_endp_delay_wa)
ipa3_q6_pipe_delay(true);
ipa3_q6_avoid_holb();
if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0) {
prod = true;
@ -4016,7 +4054,11 @@ void ipa3_q6_pre_shutdown_cleanup(void)
/* Remove delay from Q6 PRODs to avoid pending descriptors
* on pipe reset procedure
*/
if (!ipa3_ctx->ipa_endp_delay_wa) {
if (ipa3_ctx->ipa_endp_delay_wa_v2) {
ipa3_q6_pipe_flow_control(false);
ipa3_set_reset_client_prod_pipe_delay(true,
IPA_CLIENT_USB_PROD);
} else if (!ipa3_ctx->ipa_endp_delay_wa) {
ipa3_q6_pipe_delay(false);
ipa3_set_reset_client_prod_pipe_delay(true,
IPA_CLIENT_USB_PROD);
@ -7103,6 +7145,7 @@ static int ipa3_pre_init(const struct ipa3_plat_drv_res *resource_p,
ipa3_ctx->do_testbus_collection_on_crash = false;
}
ipa3_ctx->ipa_endp_delay_wa = resource_p->ipa_endp_delay_wa;
ipa3_ctx->ipa_endp_delay_wa_v2 = resource_p->ipa_endp_delay_wa_v2;
WARN(ipa3_ctx->ipa3_hw_mode != IPA_HW_MODE_NORMAL,
"Non NORMAL IPA HW mode, is this emulation platform ?");
@ -7850,6 +7893,7 @@ static int get_ipa_dts_configuration(struct platform_device *pdev,
ipa_drv_res->ipa_config_is_auto = false;
ipa_drv_res->manual_fw_load = false;
ipa_drv_res->max_num_smmu_cb = IPA_SMMU_CB_MAX;
ipa_drv_res->ipa_endp_delay_wa_v2 = false;
/* Get IPA HW Version */
result = of_property_read_u32(pdev->dev.of_node, "qcom,ipa-hw-ver",
@ -7942,6 +7986,14 @@ static int get_ipa_dts_configuration(struct platform_device *pdev,
ipa_drv_res->ipa_endp_delay_wa
? "True" : "False");
ipa_drv_res->ipa_endp_delay_wa_v2 =
of_property_read_bool(pdev->dev.of_node,
"qcom,ipa-endp-delay-wa-v2");
IPADBG(": endppoint delay wa v2 = %s\n",
ipa_drv_res->ipa_endp_delay_wa_v2
? "True" : "False");
ipa_drv_res->ipa_wdi3_over_gsi =
of_property_read_bool(pdev->dev.of_node,
"qcom,ipa-wdi3-over-gsi");

View File

@ -1176,6 +1176,29 @@ static int ipa3_xdci_stop_gsi_ch_brute_force(u32 clnt_hdl,
}
}
int ipa3_remove_secondary_flow_ctrl(int gsi_chan_hdl)
{
int code = 0;
int result;
result = gsi_query_flow_control_state_ee(gsi_chan_hdl, 0, 1, &code);
if (result == GSI_STATUS_SUCCESS) {
code = 0;
result = gsi_flow_control_ee(gsi_chan_hdl, 0, false, true,
&code);
if (result == GSI_STATUS_SUCCESS) {
IPADBG("flow control sussess ch %d code %d\n",
gsi_chan_hdl, code);
} else {
IPADBG("failed to flow control ch %d code %d\n",
gsi_chan_hdl, code);
}
} else {
IPADBG("failed to query flow control mode ch %d code %d\n",
gsi_chan_hdl, code);
}
return result;
}
/* Clocks should be voted for before invoking this function */
static int ipa3_stop_ul_chan_with_data_drain(u32 qmi_req_id,
u32 source_pipe_bitmask, bool should_force_clear, u32 clnt_hdl,
@ -1261,10 +1284,15 @@ static int ipa3_stop_ul_chan_with_data_drain(u32 qmi_req_id,
IPAERR(
"failed to force clear %d, remove delay from SCND reg\n"
, result);
ep_ctrl_scnd.endp_delay = false;
ipahal_write_reg_n_fields(
IPA_ENDP_INIT_CTRL_SCND_n, clnt_hdl,
&ep_ctrl_scnd);
if (ipa3_ctx->ipa_endp_delay_wa_v2) {
ipa3_remove_secondary_flow_ctrl(
ep->gsi_chan_hdl);
} else {
ep_ctrl_scnd.endp_delay = false;
ipahal_write_reg_n_fields(
IPA_ENDP_INIT_CTRL_SCND_n, clnt_hdl,
&ep_ctrl_scnd);
}
}
}
/* with force clear, wait for emptiness */

View File

@ -2144,6 +2144,7 @@ struct ipa3_context {
bool manual_fw_load;
u32 num_smmu_cb_probed;
u32 max_num_smmu_cb;
bool ipa_endp_delay_wa_v2;
};
struct ipa3_plat_drv_res {
@ -2212,6 +2213,7 @@ struct ipa3_plat_drv_res {
bool manual_fw_load;
bool ipa_config_is_auto;
u32 max_num_smmu_cb;
bool ipa_endp_delay_wa_v2;
};
/**
@ -2904,6 +2906,7 @@ void ipa3_skb_recycle(struct sk_buff *skb);
void ipa3_install_dflt_flt_rules(u32 ipa_ep_idx);
void ipa3_delete_dflt_flt_rules(u32 ipa_ep_idx);
int ipa3_remove_secondary_flow_ctrl(int gsi_chan_hdl);
int ipa3_enable_data_path(u32 clnt_hdl);
int ipa3_disable_data_path(u32 clnt_hdl);
int ipa3_disable_gsi_data_path(u32 clnt_hdl);

View File

@ -1402,12 +1402,6 @@ int ipa3_connect_gsi_wdi_pipe(struct ipa_wdi_in_params *in,
ep->skip_ep_cfg = in->sys.skip_ep_cfg;
ep->client_notify = in->sys.notify;
ep->priv = in->sys.priv;
if (IPA_CLIENT_IS_PROD(in->sys.client)) {
memset(&ep_cfg_ctrl, 0, sizeof(struct ipa_ep_cfg_ctrl));
ep_cfg_ctrl.ipa_ep_delay = true;
ipa3_cfg_ep_ctrl(ipa_ep_idx, &ep_cfg_ctrl);
}
if (IPA_CLIENT_IS_CONS(in->sys.client)) {
in->sys.ipa_ep_cfg.aggr.aggr_en = IPA_ENABLE_AGGR;
in->sys.ipa_ep_cfg.aggr.aggr = IPA_GENERIC;
@ -1444,6 +1438,13 @@ int ipa3_connect_gsi_wdi_pipe(struct ipa_wdi_in_params *in,
&ep->gsi_chan_hdl, ep->gsi_evt_ring_hdl);
if (result)
goto fail_alloc_channel;
if (IPA_CLIENT_IS_PROD(in->sys.client)) {
memset(&ep_cfg_ctrl, 0, sizeof(struct ipa_ep_cfg_ctrl));
ep_cfg_ctrl.ipa_ep_delay = true;
ipa3_cfg_ep_ctrl(ipa_ep_idx, &ep_cfg_ctrl);
}
ep->gsi_mem_info.chan_ring_len = gsi_channel_props.ring_len;
ep->gsi_mem_info.chan_ring_base_addr = gsi_channel_props.ring_base_addr;
ep->gsi_mem_info.chan_ring_base_vaddr =
@ -2657,10 +2658,15 @@ int ipa3_suspend_gsi_wdi_pipe(u32 clnt_hdl)
*/
IPAERR("failed to force clear %d\n", res);
IPAERR("remove delay from SCND reg\n");
ep_ctrl_scnd.endp_delay = false;
ipahal_write_reg_n_fields(
IPA_ENDP_INIT_CTRL_SCND_n, clnt_hdl,
&ep_ctrl_scnd);
if (ipa3_ctx->ipa_endp_delay_wa_v2) {
ipa3_remove_secondary_flow_ctrl(
ep->gsi_chan_hdl);
} else {
ep_ctrl_scnd.endp_delay = false;
ipahal_write_reg_n_fields(
IPA_ENDP_INIT_CTRL_SCND_n,
clnt_hdl, &ep_ctrl_scnd);
}
} else {
disable_force_clear = true;
}
@ -2785,10 +2791,15 @@ int ipa3_suspend_wdi_pipe(u32 clnt_hdl)
*/
IPAERR("failed to force clear %d\n", result);
IPAERR("remove delay from SCND reg\n");
ep_ctrl_scnd.endp_delay = false;
ipahal_write_reg_n_fields(
if (ipa3_ctx->ipa_endp_delay_wa_v2) {
ipa3_remove_secondary_flow_ctrl(
ep->gsi_chan_hdl);
} else {
ep_ctrl_scnd.endp_delay = false;
ipahal_write_reg_n_fields(
IPA_ENDP_INIT_CTRL_SCND_n, clnt_hdl,
&ep_ctrl_scnd);
}
} else {
disable_force_clear = true;
}

View File

@ -5792,6 +5792,10 @@ int ipa3_cfg_ep_hdr_ext(u32 clnt_hdl,
*/
int ipa3_cfg_ep_ctrl(u32 clnt_hdl, const struct ipa_ep_cfg_ctrl *ep_ctrl)
{
int code = 0, result;
struct ipa3_ep_context *ep;
bool primary_secondry;
if (clnt_hdl >= ipa3_ctx->ipa_num_pipes || ep_ctrl == NULL) {
IPAERR("bad parm, clnt_hdl = %d\n", clnt_hdl);
return -EINVAL;
@ -5812,6 +5816,33 @@ int ipa3_cfg_ep_ctrl(u32 clnt_hdl, const struct ipa_ep_cfg_ctrl *ep_ctrl)
clnt_hdl,
ep_ctrl->ipa_ep_suspend,
ep_ctrl->ipa_ep_delay);
ep = &ipa3_ctx->ep[clnt_hdl];
if (ipa3_ctx->ipa_endp_delay_wa_v2 &&
IPA_CLIENT_IS_PROD(ep->client)) {
IPADBG("Configuring flow control for pipe = %d\n", clnt_hdl);
/* Configure enhanced flow control instead of delay
* Q6 controlled AP pipes(USB PROD and MHI_PROD) configuring the
* secondary flow control.
* AP controlled pipe configuring primary flow control.
*/
if (ep->client == IPA_CLIENT_USB_PROD ||
ep->client == IPA_CLIENT_MHI_PROD)
primary_secondry = true;
else
primary_secondry = false;
result = gsi_flow_control_ee(ep->gsi_chan_hdl, 0,
ep_ctrl->ipa_ep_delay, primary_secondry, &code);
if (result == GSI_STATUS_SUCCESS) {
IPADBG("flow control sussess gsi ch %d with code %d\n",
ep->gsi_chan_hdl, code);
} else {
IPADBG("failed to flow control gsi ch %d code %d\n",
ep->gsi_chan_hdl, code);
}
return 0;
}
ipahal_write_reg_n_fields(IPA_ENDP_INIT_CTRL_n, clnt_hdl, ep_ctrl);

View File

@ -974,10 +974,16 @@ int ipa3_disable_wdi3_pipes(int ipa_ep_idx_tx, int ipa_ep_idx_rx)
*/
IPAERR("failed to force clear %d\n", result);
IPAERR("remove delay from SCND reg\n");
ep_ctrl_scnd.endp_delay = false;
ipahal_write_reg_n_fields(
IPA_ENDP_INIT_CTRL_SCND_n, ipa_ep_idx_rx,
&ep_ctrl_scnd);
if (ipa3_ctx->ipa_endp_delay_wa_v2) {
ipa3_remove_secondary_flow_ctrl(
ep->gsi_chan_hdl);
} else {
ep_ctrl_scnd.endp_delay = false;
ipahal_write_reg_n_fields(
IPA_ENDP_INIT_CTRL_SCND_n,
ipa_ep_idx_rx,
&ep_ctrl_scnd);
}
} else {
disable_force_clear = true;
}

View File

@ -1820,10 +1820,16 @@ int ipa3_disable_wigig_pipe_i(enum ipa_client_type client)
*/
IPAERR("failed to force clear %d\n", res);
IPAERR("remove delay from SCND reg\n");
ep_ctrl_scnd.endp_delay = false;
ipahal_write_reg_n_fields(
IPA_ENDP_INIT_CTRL_SCND_n, ipa_ep_idx,
&ep_ctrl_scnd);
if (ipa3_ctx->ipa_endp_delay_wa_v2) {
ipa3_remove_secondary_flow_ctrl(
ep->gsi_chan_hdl);
} else {
ep_ctrl_scnd.endp_delay = false;
ipahal_write_reg_n_fields(
IPA_ENDP_INIT_CTRL_SCND_n,
ipa_ep_idx,
&ep_ctrl_scnd);
}
} else {
disable_force_clear = true;
}