diff options
author | Alex Elder <elder@linaro.org> | 2022-07-19 13:10:17 -0500 |
---|---|---|
committer | Jakub Kicinski <kuba@kernel.org> | 2022-07-20 21:04:36 -0700 |
commit | 4920065888fa27edf1cb3f2d03c6d1c245e493bf (patch) | |
tree | 2b2efdd30457f30f8f43f527866eb85099a065f4 /drivers | |
parent | b63f507c06e6835aaefe89faee220aefedad0a1d (diff) | |
download | lwn-4920065888fa27edf1cb3f2d03c6d1c245e493bf.tar.gz lwn-4920065888fa27edf1cb3f2d03c6d1c245e493bf.zip |
net: ipa: rearrange transaction initialization
The transaction map is really associated with the transaction pool;
move its definition earlier in the gsi_trans_info structure.
Rearrange initialization in gsi_channel_trans_init() so it
sets the tre_avail value first, then initializes the transaction
pool, and finally allocating the transaction map.
Update comments.
Signed-off-by: Alex Elder <elder@linaro.org>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/ipa/gsi.h | 3 | ||||
-rw-r--r-- | drivers/net/ipa/gsi_trans.c | 60 |
2 files changed, 33 insertions, 30 deletions
diff --git a/drivers/net/ipa/gsi.h b/drivers/net/ipa/gsi.h index 85fb03465713..23de5f67374c 100644 --- a/drivers/net/ipa/gsi.h +++ b/drivers/net/ipa/gsi.h @@ -83,9 +83,10 @@ struct gsi_trans_pool { struct gsi_trans_info { atomic_t tre_avail; /* TREs available for allocation */ struct gsi_trans_pool pool; /* transaction pool */ + struct gsi_trans **map; /* TRE -> transaction map */ + struct gsi_trans_pool sg_pool; /* scatterlist pool */ struct gsi_trans_pool cmd_pool; /* command payload DMA pool */ - struct gsi_trans **map; /* TRE -> transaction map */ spinlock_t spinlock; /* protects updates to the lists */ struct list_head alloc; /* allocated, not committed */ diff --git a/drivers/net/ipa/gsi_trans.c b/drivers/net/ipa/gsi_trans.c index 45572ebb76e9..3f52932e9e41 100644 --- a/drivers/net/ipa/gsi_trans.c +++ b/drivers/net/ipa/gsi_trans.c @@ -709,6 +709,7 @@ void gsi_trans_read_byte_done(struct gsi *gsi, u32 channel_id) int gsi_channel_trans_init(struct gsi *gsi, u32 channel_id) { struct gsi_channel *channel = &gsi->channel[channel_id]; + u32 tre_count = channel->tre_count; struct gsi_trans_info *trans_info; u32 tre_max; int ret; @@ -716,30 +717,40 @@ int gsi_channel_trans_init(struct gsi *gsi, u32 channel_id) /* Ensure the size of a channel element is what's expected */ BUILD_BUG_ON(sizeof(struct gsi_tre) != GSI_RING_ELEMENT_SIZE); - /* The map array is used to determine what transaction is associated - * with a TRE that the hardware reports has completed. We need one - * map entry per TRE. - */ trans_info = &channel->trans_info; - trans_info->map = kcalloc(channel->tre_count, sizeof(*trans_info->map), - GFP_KERNEL); - if (!trans_info->map) - return -ENOMEM; - /* We can't use more TREs than there are available in the ring. - * 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 - * this maximum number. + /* The tre_avail field is what ultimately limits the number of + * outstanding transactions and their resources. A transaction + * allocation succeeds only if the TREs available are sufficient + * for what the transaction might need. */ tre_max = gsi_channel_tre_max(channel->gsi, channel_id); + atomic_set(&trans_info->tre_avail, tre_max); - /* Transactions are allocated one at a time. */ + /* We can't use more TREs than the number available in the ring. + * 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). By allocating a + * power-of-two number of transactions we can use an index + * 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) - goto err_kfree; + return -ENOMEM; + + /* A completion event contains a pointer to the TRE that caused + * the event (which will be the last one used by the transaction). + * Each entry in this map records the transaction associated + * with a corresponding completed TRE. + */ + trans_info->map = kcalloc(tre_count, sizeof(*trans_info->map), + GFP_KERNEL); + if (!trans_info->map) { + ret = -ENOMEM; + goto err_trans_free; + } /* A transaction uses a scatterlist array to represent the data * transfers implemented by the transaction. Each scatterlist @@ -751,16 +762,7 @@ int gsi_channel_trans_init(struct gsi *gsi, u32 channel_id) sizeof(struct scatterlist), tre_max, channel->trans_tre_max); if (ret) - goto err_trans_pool_exit; - - /* Finally, the tre_avail field is what ultimately limits the number - * of outstanding transactions and their resources. A transaction - * allocation succeeds only if the TREs available are sufficient for - * what the transaction might need. Transaction resource pools are - * sized based on the maximum number of outstanding TREs, so there - * will always be resources available if there are TREs available. - */ - atomic_set(&trans_info->tre_avail, tre_max); + goto err_map_free; spin_lock_init(&trans_info->spinlock); INIT_LIST_HEAD(&trans_info->alloc); @@ -771,10 +773,10 @@ int gsi_channel_trans_init(struct gsi *gsi, u32 channel_id) return 0; -err_trans_pool_exit: - gsi_trans_pool_exit(&trans_info->pool); -err_kfree: +err_map_free: kfree(trans_info->map); +err_trans_free: + gsi_trans_pool_exit(&trans_info->pool); dev_err(gsi->dev, "error %d initializing channel %u transactions\n", ret, channel_id); |