The channel stop and suspend paths both call __gsi_channel_stop(), which quiesces channel activity, disables NAPI, and (on other than SDM845) stops the channel. Similarly, the start and resume paths share __gsi_channel_start(), which starts the channel and re-enables NAPI again.
Disabling NAPI should be done when stopping a channel, but this should *not* be done when suspending. It's not necessary in the suspend path anyway, because the stopped channel (or suspended endpoint on SDM845) will not cause interrupts to schedule NAPI, and gsi_channel_trans_quiesce() won't return until there are no more transactions to process in the NAPI polling loop. Instead, enable NAPI in gsi_channel_start(), when the completion interrupt is first enabled. Disable it again in gsi_channel_stop(), when finally disabling the interrupt. Add a call to napi_synchronize() to __gsi_channel_stop(), to ensure NAPI polling is done before moving on. Signed-off-by: Alex Elder <el...@linaro.org> --- drivers/net/ipa/gsi.c | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/drivers/net/ipa/gsi.c b/drivers/net/ipa/gsi.c index 217ca21bfe043..afc5c9ede01af 100644 --- a/drivers/net/ipa/gsi.c +++ b/drivers/net/ipa/gsi.c @@ -876,15 +876,15 @@ static int __gsi_channel_start(struct gsi_channel *channel, bool start) struct gsi *gsi = channel->gsi; int ret; + if (!start) + return 0; + mutex_lock(&gsi->mutex); - ret = start ? gsi_channel_start_command(channel) : 0; + ret = gsi_channel_start_command(channel); mutex_unlock(&gsi->mutex); - if (!ret) - napi_enable(&channel->napi); - return ret; } @@ -894,12 +894,16 @@ int gsi_channel_start(struct gsi *gsi, u32 channel_id) struct gsi_channel *channel = &gsi->channel[channel_id]; int ret; - /* Enable the completion interrupt */ + /* Enable NAPI and the completion interrupt */ + napi_enable(&channel->napi); gsi_irq_ieob_enable_one(gsi, channel->evt_ring_id); ret = __gsi_channel_start(channel, true); - if (ret) - gsi_irq_ieob_disable_one(gsi, channel->evt_ring_id); + if (!ret) + return 0; + + gsi_irq_ieob_disable_one(gsi, channel->evt_ring_id); + napi_disable(&channel->napi); return ret; } @@ -928,13 +932,13 @@ static int __gsi_channel_stop(struct gsi_channel *channel, bool stop) { int ret; + /* Wait for any underway transactions to complete before stopping. */ gsi_channel_trans_quiesce(channel); - napi_disable(&channel->napi); ret = stop ? gsi_channel_stop_retry(channel) : 0; - - if (ret) - napi_enable(&channel->napi); + /* Finally, ensure NAPI polling has finished. */ + if (!ret) + napi_synchronize(&channel->napi); return ret; } @@ -947,10 +951,13 @@ int gsi_channel_stop(struct gsi *gsi, u32 channel_id) /* Only disable the completion interrupt if stop is successful */ ret = __gsi_channel_stop(channel, true); - if (!ret) - gsi_irq_ieob_disable_one(gsi, channel->evt_ring_id); + if (ret) + return ret; - return ret; + gsi_irq_ieob_disable_one(gsi, channel->evt_ring_id); + napi_disable(&channel->napi); + + return 0; } /* Reset and reconfigure a channel, (possibly) enabling the doorbell engine */ -- 2.27.0