*/
if (channel->toward_ipa) {
list = &trans_info->alloc;
+ if (!list_empty(list))
+ goto done;
+ list = &trans_info->committed;
if (!list_empty(list))
goto done;
list = &trans_info->pending;
* first *unfilled* event in the ring (following the last filled one).
*
* Events are sequential within the event ring, and transactions are
- * sequential within the transaction pool.
+ * sequential within the transaction array.
*
* Note that @index always refers to an element *within* the event ring.
*/
spinlock_t spinlock; /* protects updates to the lists */
struct list_head alloc; /* allocated, not committed */
- struct list_head pending; /* committed, awaiting completion */
+ struct list_head committed; /* committed, awaiting doorbell */
+ struct list_head pending; /* pending, awaiting completion */
struct list_head complete; /* completed, awaiting poll */
struct list_head polled; /* returned by gsi_channel_poll_one() */
};
* @gsi: GSI pointer
* @channel_id: Channel whose limit is to be returned
*
- * Return: The maximum number of TREs oustanding on the channel
+ * Return: The maximum number of TREs outstanding on the channel
*/
u32 gsi_channel_tre_max(struct gsi *gsi, u32 channel_id);
struct gsi_trans, links);
}
-/* Move a transaction from the allocated list to the pending list */
+/* Move a transaction from the allocated list to the committed list */
+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;
+
+ spin_lock_bh(&trans_info->spinlock);
+
+ list_move_tail(&trans->links, &trans_info->committed);
+
+ spin_unlock_bh(&trans_info->spinlock);
+}
+
+/* Move transactions from the committed list to the pending list */
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;
+ struct list_head list;
spin_lock_bh(&trans_info->spinlock);
- list_move_tail(&trans->links, &trans_info->pending);
+ /* Move this transaction and all predecessors to the pending list */
+ list_cut_position(&list, &trans_info->committed, &trans->links);
+ list_splice_tail(&list, &trans_info->pending);
spin_unlock_bh(&trans_info->spinlock);
}
if (channel->toward_ipa)
gsi_trans_tx_committed(trans);
- gsi_trans_move_pending(trans);
+ gsi_trans_move_committed(trans);
/* Ring doorbell if requested, or if all TREs are allocated */
if (ring_db || !atomic_read(&channel->trans_info.tre_avail)) {
/* Report what we're handing off to hardware for TX channels */
if (channel->toward_ipa)
gsi_trans_tx_queued(trans);
+ gsi_trans_move_pending(trans);
gsi_channel_doorbell(channel);
}
}
return -ENOMEM;
/* We can't use more TREs than there are available in the ring.
- * This limits the number of transactions that can be oustanding.
+ * This limits the number of transactions that can be outstanding.
* Worst case is one TRE per transaction (but we actually limit
* it to something a little less than that). We allocate resources
* for transactions (including transaction structures) based on
spin_lock_init(&trans_info->spinlock);
INIT_LIST_HEAD(&trans_info->alloc);
+ INIT_LIST_HEAD(&trans_info->committed);
INIT_LIST_HEAD(&trans_info->pending);
INIT_LIST_HEAD(&trans_info->complete);
INIT_LIST_HEAD(&trans_info->polled);