diff options
Diffstat (limited to 'drivers/net/ipa/gsi_trans.c')
-rw-r--r-- | drivers/net/ipa/gsi_trans.c | 46 |
1 files changed, 28 insertions, 18 deletions
diff --git a/drivers/net/ipa/gsi_trans.c b/drivers/net/ipa/gsi_trans.c index 72da795908fe..5e3b4f673d9f 100644 --- a/drivers/net/ipa/gsi_trans.c +++ b/drivers/net/ipa/gsi_trans.c @@ -246,23 +246,15 @@ static void gsi_trans_move_committed(struct gsi_trans *trans) { struct gsi_channel *channel = &trans->gsi->channel[trans->channel_id]; struct gsi_trans_info *trans_info = &channel->trans_info; - u16 trans_index; spin_lock_bh(&trans_info->spinlock); list_move_tail(&trans->links, &trans_info->committed); - trans = list_first_entry(&trans_info->committed, - struct gsi_trans, links); - spin_unlock_bh(&trans_info->spinlock); /* This allocated transaction is now committed */ trans_info->allocated_id++; - - WARN_ON(trans_info->committed_id == trans_info->allocated_id); - trans_index = trans_info->committed_id % channel->tre_count; - WARN_ON(trans != &trans_info->trans[trans_index]); } /* Move transactions from the committed list to the pending list */ @@ -280,8 +272,8 @@ static void gsi_trans_move_pending(struct gsi_trans *trans) list_cut_position(&list, &trans_info->committed, &trans->links); list_splice_tail(&list, &trans_info->pending); - trans = list_first_entry_or_null(&trans_info->committed, - struct gsi_trans, links); + trans = list_first_entry(&trans_info->pending, + struct gsi_trans, links); spin_unlock_bh(&trans_info->spinlock); @@ -289,13 +281,9 @@ static void gsi_trans_move_pending(struct gsi_trans *trans) delta = trans_index - trans_info->committed_id + 1; trans_info->committed_id += delta % channel->tre_count; - if (trans) { - trans_index = trans_info->committed_id % channel->tre_count; - WARN_ON(trans != &trans_info->trans[trans_index]); - } else { - WARN_ON(trans_info->committed_id != - trans_info->allocated_id); - } + WARN_ON(trans_info->pending_id == trans_info->committed_id); + trans_index = trans_info->pending_id % channel->tre_count; + WARN_ON(trans != &trans_info->trans[trans_index]); } /* Move a transaction and all of its predecessors from the pending list @@ -305,7 +293,9 @@ void gsi_trans_move_complete(struct gsi_trans *trans) { struct gsi_channel *channel = &trans->gsi->channel[trans->channel_id]; struct gsi_trans_info *trans_info = &channel->trans_info; + u16 trans_index = trans - trans_info->trans; struct list_head list; + u16 delta; spin_lock_bh(&trans_info->spinlock); @@ -313,7 +303,23 @@ void gsi_trans_move_complete(struct gsi_trans *trans) list_cut_position(&list, &trans_info->pending, &trans->links); list_splice_tail(&list, &trans_info->complete); + trans = list_first_entry_or_null(&trans_info->pending, + struct gsi_trans, links); + spin_unlock_bh(&trans_info->spinlock); + + /* These pending transactions are now completed */ + delta = trans_index - trans_info->pending_id + 1; + delta %= channel->tre_count; + trans_info->pending_id += delta; + + if (trans) { + trans_index = trans_info->pending_id % channel->tre_count; + WARN_ON(trans != &trans_info->trans[trans_index]); + } else { + WARN_ON(trans_info->pending_id != + trans_info->committed_id); + } } /* Move a transaction from the completed list to the polled list */ @@ -436,10 +442,13 @@ void gsi_trans_free(struct gsi_trans *trans) if (!last) return; - /* Unused transactions are allocated but never committed or pending */ + /* Unused transactions are allocated but never committed, pending, + * or completed. + */ if (!trans->used_count) { trans_info->allocated_id++; trans_info->committed_id++; + trans_info->pending_id++; } else { ipa_gsi_trans_release(trans); } @@ -780,6 +789,7 @@ int gsi_channel_trans_init(struct gsi *gsi, u32 channel_id) trans_info->free_id = 0; /* all modulo channel->tre_count */ trans_info->allocated_id = 0; trans_info->committed_id = 0; + trans_info->pending_id = 0; /* A completion event contains a pointer to the TRE that caused * the event (which will be the last one used by the transaction). |