net: ipa: rearrange transaction initialization
authorAlex Elder <elder@linaro.org>
Tue, 19 Jul 2022 18:10:17 +0000 (13:10 -0500)
committerJakub Kicinski <kuba@kernel.org>
Thu, 21 Jul 2022 04:04:36 +0000 (21:04 -0700)
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>
drivers/net/ipa/gsi.h
drivers/net/ipa/gsi_trans.c

index 85fb03465713fb7ba13a9b5f47c3b59bdfc449ba..23de5f67374cf2daed9ad135d7c41a931d3fc7ec 100644 (file)
@@ -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 */
index 45572ebb76e955218bb10879f4f5b498d428d83e..3f52932e9e413a3d68a836a3252e4b37e7b82ed2 100644 (file)
@@ -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);