Commit 12382d11 authored by Alex Elder's avatar Alex Elder Committed by David S. Miller
Browse files

net: ipa: use an array for transactions



Transactions are always allocated one at a time.  The maximum number
of them we could ever need occurs if each TRE is assigned to a
transaction.  So a channel requires no more transactions than the
number of TREs in its transfer ring.  That number is known to be a
power-of-2 less than 65536.

The transaction pool abstraction is used for other things, but for
transactions we can use a simple array of transaction structures,
and use a free index to indicate which entry in the array is the
next one free for allocation.

By having the number of elements in the array be a power-of-2, we
can use an ever-incrementing 16-bit free index, and use it modulo
the array size.  Distinguish a "trans_id" (whose value can exceed
the number of entries in the transaction array) from a "trans_index"
(which is less than the number of entries).

Signed-off-by: default avatarAlex Elder <elder@linaro.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent a01105f1
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -82,7 +82,9 @@ struct gsi_trans_pool {

struct gsi_trans_info {
	atomic_t tre_avail;		/* TREs available for allocation */
	struct gsi_trans_pool pool;	/* transaction pool */

	u16 free_id;			/* first free trans in array */
	struct gsi_trans *trans;	/* transaction array */
	struct gsi_trans **map;		/* TRE -> transaction map */

	struct gsi_trans_pool sg_pool;	/* scatterlist pool */
+17 −12
Original line number Diff line number Diff line
@@ -343,20 +343,22 @@ struct gsi_trans *gsi_channel_trans_alloc(struct gsi *gsi, u32 channel_id,
	struct gsi_channel *channel = &gsi->channel[channel_id];
	struct gsi_trans_info *trans_info;
	struct gsi_trans *trans;
	u16 trans_index;

	if (WARN_ON(tre_count > channel->trans_tre_max))
		return NULL;

	trans_info = &channel->trans_info;

	/* We reserve the TREs now, but consume them at commit time.
	 * If there aren't enough available, we're done.
	 */
	/* If we can't reserve the TREs for the transaction, we're done */
	if (!gsi_trans_tre_reserve(trans_info, tre_count))
		return NULL;

	/* Allocate and initialize non-zero fields in the transaction */
	trans = gsi_trans_pool_alloc(&trans_info->pool, 1);
	trans_index = trans_info->free_id % channel->tre_count;
	trans = &trans_info->trans[trans_index];
	memset(trans, 0, sizeof(*trans));

	/* Initialize non-zero fields in the transaction */
	trans->gsi = gsi;
	trans->channel_id = channel_id;
	trans->rsvd_count = tre_count;
@@ -367,6 +369,10 @@ struct gsi_trans *gsi_channel_trans_alloc(struct gsi *gsi, u32 channel_id,
	sg_init_marker(trans->sgl, tre_count);

	trans->direction = direction;
	refcount_set(&trans->refcount, 1);

	/* This free transaction will now be allocated */
	trans_info->free_id++;

	spin_lock_bh(&trans_info->spinlock);

@@ -374,8 +380,6 @@ struct gsi_trans *gsi_channel_trans_alloc(struct gsi *gsi, u32 channel_id,

	spin_unlock_bh(&trans_info->spinlock);

	refcount_set(&trans->refcount, 1);

	return trans;
}

@@ -736,10 +740,11 @@ int gsi_channel_trans_init(struct gsi *gsi, u32 channel_id)
	 * modulo that number to determine the next one that's free.
	 * Transactions are allocated one at a time.
	 */
	ret = gsi_trans_pool_init(&trans_info->pool, sizeof(struct gsi_trans),
				  tre_max, 1);
	if (ret)
	trans_info->trans = kcalloc(tre_count, sizeof(*trans_info->trans),
				    GFP_KERNEL);
	if (!trans_info->trans)
		return -ENOMEM;
	trans_info->free_id = 0;	/* modulo channel->tre_count */

	/* A completion event contains a pointer to the TRE that caused
	 * the event (which will be the last one used by the transaction).
@@ -777,7 +782,7 @@ int gsi_channel_trans_init(struct gsi *gsi, u32 channel_id)
err_map_free:
	kfree(trans_info->map);
err_trans_free:
	gsi_trans_pool_exit(&trans_info->pool);
	kfree(trans_info->trans);

	dev_err(gsi->dev, "error %d initializing channel %u transactions\n",
		ret, channel_id);
@@ -791,6 +796,6 @@ void gsi_channel_trans_exit(struct gsi_channel *channel)
	struct gsi_trans_info *trans_info = &channel->trans_info;

	gsi_trans_pool_exit(&trans_info->sg_pool);
	gsi_trans_pool_exit(&trans_info->pool);
	kfree(trans_info->trans);
	kfree(trans_info->map);
}