Always use transaction IDs when finding the "last" transaction to await when quiescing a channel. This basically extends what was done in the previous patch to all other transaction state IDs. As a result we are no longer updating any transaction lists inside gsi_channel_trans_last(), so there's no need to take the spinlock. Signed-off-by: Alex Elder <elder@xxxxxxxxxx> --- drivers/net/ipa/gsi.c | 42 +++++++++++++++++++++++++++--------------- 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/drivers/net/ipa/gsi.c b/drivers/net/ipa/gsi.c index 135e51980d793..0983a11409f2d 100644 --- a/drivers/net/ipa/gsi.c +++ b/drivers/net/ipa/gsi.c @@ -714,8 +714,6 @@ static struct gsi_trans *gsi_channel_trans_last(struct gsi_channel *channel) u16 trans_index; u16 trans_id; - spin_lock_bh(&trans_info->spinlock); - /* There is a small chance a TX transaction got allocated just * before we disabled transmits, so check for that. */ @@ -728,32 +726,46 @@ static struct gsi_trans *gsi_channel_trans_last(struct gsi_channel *channel) goto done; } - trans = list_last_entry_or_null(&trans_info->committed, - struct gsi_trans, links); - if (trans) + /* Last committed transaction precedes the first allocated */ + if (trans_info->committed_id != trans_info->allocated_id) { + trans_id = trans_info->allocated_id - 1; + trans_index = trans_id % channel->tre_count; + trans = &trans_info->trans[trans_index]; goto done; - trans = list_last_entry_or_null(&trans_info->pending, - struct gsi_trans, links); - if (trans) + } + + /* Last pending transaction precedes the first committed */ + if (trans_info->pending_id != trans_info->committed_id) { + trans_id = trans_info->committed_id - 1; + trans_index = trans_id % channel->tre_count; + trans = &trans_info->trans[trans_index]; goto done; + } } /* Otherwise (TX or RX) we want to wait for anything that * has completed, or has been polled but not released yet. + * + * The last pending transaction precedes the first committed. */ - trans = list_last_entry_or_null(&trans_info->complete, - struct gsi_trans, links); - if (trans) + if (trans_info->completed_id != trans_info->pending_id) { + trans_id = trans_info->pending_id - 1; + trans_index = trans_id % channel->tre_count; + trans = &trans_info->trans[trans_index]; goto done; - trans = list_last_entry_or_null(&trans_info->polled, - struct gsi_trans, links); + } + if (trans_info->polled_id != trans_info->completed_id) { + trans_id = trans_info->completed_id - 1; + trans_index = trans_id % channel->tre_count; + trans = &trans_info->trans[trans_index]; + } else { + trans = NULL; + } done: /* Caller will wait for this, so take a reference */ if (trans) refcount_inc(&trans->refcount); - spin_unlock_bh(&trans_info->spinlock); - return trans; } -- 2.34.1