diff options
Diffstat (limited to 'drivers/net/ipa/gsi_trans.c')
-rw-r--r-- | drivers/net/ipa/gsi_trans.c | 45 |
1 files changed, 28 insertions, 17 deletions
diff --git a/drivers/net/ipa/gsi_trans.c b/drivers/net/ipa/gsi_trans.c index d84400e13487..72da795908fe 100644 --- a/drivers/net/ipa/gsi_trans.c +++ b/drivers/net/ipa/gsi_trans.c @@ -252,20 +252,17 @@ static void gsi_trans_move_committed(struct gsi_trans *trans) list_move_tail(&trans->links, &trans_info->committed); - trans = list_first_entry_or_null(&trans_info->alloc, - struct gsi_trans, links); + 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++; - if (trans) { - trans_index = trans_info->allocated_id % channel->tre_count; - WARN_ON(trans != &trans_info->trans[trans_index]); - } else { - WARN_ON(trans_info->allocated_id != trans_info->free_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 */ @@ -273,7 +270,9 @@ static void gsi_trans_move_pending(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[0]; struct list_head list; + u16 delta; spin_lock_bh(&trans_info->spinlock); @@ -281,7 +280,22 @@ 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); + spin_unlock_bh(&trans_info->spinlock); + + /* These committed transactions are now pending */ + 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); + } } /* Move a transaction and all of its predecessors from the pending list @@ -392,14 +406,8 @@ struct gsi_trans *gsi_channel_trans_alloc(struct gsi *gsi, u32 channel_id, list_add_tail(&trans->links, &trans_info->alloc); - trans = list_first_entry(&trans_info->alloc, struct gsi_trans, links); - spin_unlock_bh(&trans_info->spinlock); - WARN_ON(trans_info->allocated_id == trans_info->free_id); - trans_index = trans_info->allocated_id % channel->tre_count; - WARN_ON(trans != &trans_info->trans[trans_index]); - return trans; } @@ -428,11 +436,13 @@ void gsi_trans_free(struct gsi_trans *trans) if (!last) return; - /* Unused transactions are allocated but never committed */ - if (!trans->used_count) + /* Unused transactions are allocated but never committed or pending */ + if (!trans->used_count) { trans_info->allocated_id++; - else + trans_info->committed_id++; + } else { ipa_gsi_trans_release(trans); + } /* Releasing the reserved TREs implicitly frees the sgl[] and * (if present) info[] arrays, plus the transaction itself. @@ -769,6 +779,7 @@ int gsi_channel_trans_init(struct gsi *gsi, u32 channel_id) return -ENOMEM; trans_info->free_id = 0; /* all modulo channel->tre_count */ trans_info->allocated_id = 0; + trans_info->committed_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). |