Merge "msm: ipa3: Fix to race condition in updating current polling state"

This commit is contained in:
qctecmdr 2019-11-12 06:37:39 -08:00 • committed by Gerrit - the friendly Code Review server
commit 4c92e30fe3
2 changed files with 92 additions and 36 deletions

View file

@ -769,6 +769,26 @@ static int ipa3_handle_rx_core(struct ipa3_sys_context *sys, bool process_all,
return cnt;
}
/**
* __ipa3_update_curr_poll_state -> update current polling for default wan and
* coalescing pipe.
* In RSC/RSB enabled cases using common event ring, so both the pipe
* polling state should be in sync.
*/
void __ipa3_update_curr_poll_state(enum ipa_client_type client, int state)
{
int ep_idx = IPA_EP_NOT_ALLOCATED;
if (client == IPA_CLIENT_APPS_WAN_COAL_CONS)
ep_idx = ipa3_get_ep_mapping(IPA_CLIENT_APPS_WAN_CONS);
if (client == IPA_CLIENT_APPS_WAN_CONS)
ep_idx = ipa3_get_ep_mapping(IPA_CLIENT_APPS_WAN_COAL_CONS);
if (ep_idx != IPA_EP_NOT_ALLOCATED && ipa3_ctx->ep[ep_idx].sys)
atomic_set(&ipa3_ctx->ep[ep_idx].sys->curr_polling_state,
state);
}
/**
* ipa3_rx_switch_to_intr_mode() - Operate the Rx data path in interrupt mode
*/
@ -777,6 +797,8 @@ static int ipa3_rx_switch_to_intr_mode(struct ipa3_sys_context *sys)
int ret;
atomic_set(&sys->curr_polling_state, 0);
__ipa3_update_curr_poll_state(sys->ep->client, 0);
ipa3_dec_release_wakelock();
ret = gsi_config_channel_mode(sys->ep->gsi_chan_hdl,
GSI_CHAN_MODE_CALLBACK);
@ -785,8 +807,10 @@ static int ipa3_rx_switch_to_intr_mode(struct ipa3_sys_context *sys)
if (ret == -GSI_STATUS_PENDING_IRQ) {
ipa3_inc_acquire_wakelock();
atomic_set(&sys->curr_polling_state, 1);
__ipa3_update_curr_poll_state(sys->ep->client, 1);
} else {
IPAERR("Failed to switch to intr mode.\n");
IPAERR("Failed to switch to intr mode %d ch_id %d\n",
sys->curr_polling_state, sys->ep->gsi_chan_hdl);
}
}
@ -4290,6 +4314,8 @@ void __ipa_gsi_irq_rx_scedule_poll(struct ipa3_sys_context *sys)
bool clk_off;
atomic_set(&sys->curr_polling_state, 1);
__ipa3_update_curr_poll_state(sys->ep->client, 1);
ipa3_inc_acquire_wakelock();
/*

View file

@ -7988,7 +7988,7 @@ int ipa3_stop_gsi_channel(u32 clnt_hdl)
static int _ipa_suspend_resume_pipe(enum ipa_client_type client, bool suspend)
{
int ipa_ep_idx;
int ipa_ep_idx, coal_ep_idx;
struct ipa3_ep_context *ep;
int res;
@ -8007,16 +8007,16 @@ static int _ipa_suspend_resume_pipe(enum ipa_client_type client, bool suspend)
if (!ep->valid)
return 0;
coal_ep_idx = ipa3_get_ep_mapping(IPA_CLIENT_APPS_WAN_COAL_CONS);
IPADBG("%s pipe %d\n", suspend ? "suspend" : "unsuspend", ipa_ep_idx);
/*
* move the channel to callback mode.
* This needs to happen before starting the channel to make
* sure we don't loose any interrupt
* Configure the callback mode only one time after starting the channel
* otherwise observing IEOB interrupt received before configure callmode
* second time. It was leading race condition in updating current
* polling state.
*/
if (!suspend && !atomic_read(&ep->sys->curr_polling_state) &&
!IPA_CLIENT_IS_APPS_PROD(client))
gsi_config_channel_mode(ep->gsi_chan_hdl,
GSI_CHAN_MODE_CALLBACK);
if (suspend) {
res = __ipa3_stop_gsi_channel(ipa_ep_idx);
@ -8033,7 +8033,17 @@ static int _ipa_suspend_resume_pipe(enum ipa_client_type client, bool suspend)
}
/* Apps prod pipes use common event ring so cannot configure mode*/
if (IPA_CLIENT_IS_APPS_PROD(client))
/*
* Skipping to configure mode for default wan pipe,
* as both pipes using commong event ring. if both pipes
* configure same event ring observing race condition in
* updating current polling state.
*/
if (IPA_CLIENT_IS_APPS_PROD(client) ||
(client == IPA_CLIENT_APPS_WAN_CONS &&
coal_ep_idx != IPA_EP_NOT_ALLOCATED))
return 0;
if (suspend) {
@ -8089,18 +8099,29 @@ void ipa3_force_close_coal(void)
int ipa3_suspend_apps_pipes(bool suspend)
{
int res;
enum ipa_client_type client;
if (suspend)
ipa3_force_close_coal();
for (client = 0; client < IPA_CLIENT_MAX; client++) {
if (IPA_CLIENT_IS_APPS_CONS(client)) {
res = _ipa_suspend_resume_pipe(client, suspend);
if (res)
goto undo_cons;
}
}
/* As per HPG first need start/stop coalescing channel
* then default one. Coalescing client number was greater then
* default one so starting the last client.
*/
res = _ipa_suspend_resume_pipe(IPA_CLIENT_APPS_WAN_COAL_CONS, suspend);
if (res == -EAGAIN)
goto undo_coal_cons;
res = _ipa_suspend_resume_pipe(IPA_CLIENT_APPS_WAN_CONS, suspend);
if (res == -EAGAIN)
goto undo_wan_cons;
res = _ipa_suspend_resume_pipe(IPA_CLIENT_APPS_LAN_CONS, suspend);
if (res == -EAGAIN)
goto undo_lan_cons;
res = _ipa_suspend_resume_pipe(IPA_CLIENT_ODL_DPL_CONS, suspend);
if (res == -EAGAIN)
goto undo_odl_cons;
if (suspend) {
struct ipahal_reg_tx_wrapper tx;
@ -8116,7 +8137,7 @@ int ipa3_suspend_apps_pipes(bool suspend)
IPADBG("COAL frame is open 0x%x\n",
tx.coal_slave_open_frame);
res = -EAGAIN;
goto undo_cons;
goto undo_odl_cons;
}
usleep_range(IPA_TAG_SLEEP_MIN_USEC, IPA_TAG_SLEEP_MAX_USEC);
@ -8125,28 +8146,37 @@ int ipa3_suspend_apps_pipes(bool suspend)
ipa3_ctx->ee);
if (res) {
IPADBG("suspend irq is pending 0x%x\n", res);
goto undo_cons;
goto undo_odl_cons;
}
}
do_prod:
for (client = 0; client < IPA_CLIENT_MAX; client++) {
if (IPA_CLIENT_IS_APPS_PROD(client)) {
res = _ipa_suspend_resume_pipe(client, suspend);
if (res)
goto undo_prod;
}
}
res = _ipa_suspend_resume_pipe(IPA_CLIENT_APPS_LAN_PROD, suspend);
if (res == -EAGAIN)
goto undo_lan_prod;
res = _ipa_suspend_resume_pipe(IPA_CLIENT_APPS_WAN_PROD, suspend);
if (res == -EAGAIN)
goto undo_wan_prod;
return 0;
undo_prod:
for (; client <= IPA_CLIENT_MAX && client >= 0; client--)
if (IPA_CLIENT_IS_APPS_PROD(client))
_ipa_suspend_resume_pipe(client, !suspend);
client = IPA_CLIENT_MAX;
undo_cons:
for (; client <= IPA_CLIENT_MAX && client >= 0; client--)
if (IPA_CLIENT_IS_APPS_CONS(client))
_ipa_suspend_resume_pipe(client, !suspend);
undo_wan_prod:
_ipa_suspend_resume_pipe(IPA_CLIENT_APPS_WAN_PROD, !suspend);
undo_lan_prod:
_ipa_suspend_resume_pipe(IPA_CLIENT_APPS_LAN_PROD, !suspend);
undo_odl_cons:
_ipa_suspend_resume_pipe(IPA_CLIENT_ODL_DPL_CONS, !suspend);
undo_lan_cons:
_ipa_suspend_resume_pipe(IPA_CLIENT_APPS_LAN_CONS, !suspend);
undo_wan_cons:
_ipa_suspend_resume_pipe(IPA_CLIENT_APPS_WAN_COAL_CONS, !suspend);
_ipa_suspend_resume_pipe(IPA_CLIENT_APPS_WAN_CONS, !suspend);
return res;
undo_coal_cons:
_ipa_suspend_resume_pipe(IPA_CLIENT_APPS_WAN_COAL_CONS, !suspend);
return res;
}