--- v1
+++ v2
@@ -1,53 +1,74 @@
-No completion interrupts will occur while an endpoint is suspended,
-or when a channel has been stopped for suspend. So there's no need
-to disable the interrupt during suspend and re-enable it when
-resuming.
+Transactions to send data for a network device can be allocated at
+any time up until the point the TX queue is stopped. It is possible
+for ipa_start_xmit() to be called in one context just before a
+the transmit queue is stopped in another.
-We'll enable the interrupt when we first start the channel, and
-disable it again only when it's "really" stopped.
+Update gsi_channel_trans_last() so that for TX channels the
+allocated and pending transaction lists are checked--in addition
+to the completed and polled lists--to determine the "last"
+transaction. This means any transaction that has been allocated
+before the TX queue is stopped will be allowed to complete before
+we conclude the channel is quiesced.
+
+Rework the function a bit to use a list pointer and gotos.
Signed-off-by: Alex Elder <elder@linaro.org>
---
- drivers/net/ipa/gsi.c | 18 ++----------------
- 1 file changed, 2 insertions(+), 16 deletions(-)
+ drivers/net/ipa/gsi.c | 34 +++++++++++++++++++++++++---------
+ 1 file changed, 25 insertions(+), 9 deletions(-)
diff --git a/drivers/net/ipa/gsi.c b/drivers/net/ipa/gsi.c
-index 70647e8450845..74d1dd04ad6e9 100644
+index 03498182ad024..8b64cbe4737a4 100644
--- a/drivers/net/ipa/gsi.c
+++ b/drivers/net/ipa/gsi.c
-@@ -959,30 +959,16 @@ void gsi_channel_reset(struct gsi *gsi, u32 channel_id, bool doorbell)
- int gsi_channel_suspend(struct gsi *gsi, u32 channel_id, bool stop)
- {
- struct gsi_channel *channel = &gsi->channel[channel_id];
-- int ret;
-
-- /* No completions when suspended; disable interrupt if successful */
-- ret = __gsi_channel_stop(channel, stop);
-- if (!ret)
-- gsi_irq_ieob_disable_one(gsi, channel->evt_ring_id);
--
-- return ret;
-+ return __gsi_channel_stop(channel, stop);
+@@ -725,22 +725,38 @@ static void gsi_evt_ring_program(struct gsi *gsi, u32 evt_ring_id)
+ gsi_evt_ring_doorbell(gsi, evt_ring_id, 0);
}
- /* Resume a suspended channel (starting will be requested if STOPPED) */
- int gsi_channel_resume(struct gsi *gsi, u32 channel_id, bool start)
+-/* Return the last (most recent) transaction completed on a channel. */
++/* Find the transaction whose completion indicates a channel is quiesced */
+ static struct gsi_trans *gsi_channel_trans_last(struct gsi_channel *channel)
{
- struct gsi_channel *channel = &gsi->channel[channel_id];
-- int ret;
+ struct gsi_trans_info *trans_info = &channel->trans_info;
++ const struct list_head *list;
+ struct gsi_trans *trans;
-- /* Re-enable the completion interrupt */
-- gsi_irq_ieob_enable_one(gsi, channel->evt_ring_id);
--
-- ret = __gsi_channel_start(channel, start);
-- if (ret)
-- gsi_irq_ieob_disable_one(gsi, channel->evt_ring_id);
--
-- return ret;
-+ return __gsi_channel_start(channel, start);
- }
+ spin_lock_bh(&trans_info->spinlock);
- /**
+- if (!list_empty(&trans_info->complete))
+- trans = list_last_entry(&trans_info->complete,
+- struct gsi_trans, links);
+- else if (!list_empty(&trans_info->polled))
+- trans = list_last_entry(&trans_info->polled,
+- struct gsi_trans, links);
+- else
+- trans = NULL;
++ /* There is a small chance a TX transaction got allocated just
++ * before we disabled transmits, so check for that.
++ */
++ if (channel->toward_ipa) {
++ list = &trans_info->alloc;
++ if (!list_empty(list))
++ goto done;
++ list = &trans_info->pending;
++ if (!list_empty(list))
++ goto done;
++ }
++
++ /* Otherwise (TX or RX) we want to wait for anything that
++ * has completed, or has been polled but not released yet.
++ */
++ list = &trans_info->complete;
++ if (!list_empty(list))
++ goto done;
++ list = &trans_info->polled;
++ if (list_empty(list))
++ list = NULL;
++done:
++ trans = list ? list_last_entry(list, struct gsi_trans, links) : NULL;
+
+ /* Caller will wait for this, so take a reference */
+ if (trans)
--
2.27.0