Convert tx_qp from a single contiguous array allocation to per-queue
individual allocations. Each mana_tx_qp struct is approximately 35KB.
With many queues (e.g., 32/64), the flat array requires a single
contiguous allocation that can fail under memory fragmentation.

Change mana_tx_qp *tx_qp to mana_tx_qp **tx_qp (array of pointers),
allocating each queue's mana_tx_qp individually via kvzalloc. This
reduces each allocation to ~35KB and provides vmalloc fallback,
avoiding allocation failure due to fragmentation.

Signed-off-by: Aditya Garg <[email protected]>
Reviewed-by: Haiyang Zhang <[email protected]>
---
 .../net/ethernet/microsoft/mana/mana_bpf.c    |  2 +-
 drivers/net/ethernet/microsoft/mana/mana_en.c | 49 ++++++++++++-------
 .../ethernet/microsoft/mana/mana_ethtool.c    |  2 +-
 include/net/mana/mana.h                       |  2 +-
 4 files changed, 33 insertions(+), 22 deletions(-)

diff --git a/drivers/net/ethernet/microsoft/mana/mana_bpf.c 
b/drivers/net/ethernet/microsoft/mana/mana_bpf.c
index 7697c9b52ed3..b5e9bb184a1d 100644
--- a/drivers/net/ethernet/microsoft/mana/mana_bpf.c
+++ b/drivers/net/ethernet/microsoft/mana/mana_bpf.c
@@ -68,7 +68,7 @@ int mana_xdp_xmit(struct net_device *ndev, int n, struct 
xdp_frame **frames,
                count++;
        }
 
-       tx_stats = &apc->tx_qp[q_idx].txq.stats;
+       tx_stats = &apc->tx_qp[q_idx]->txq.stats;
 
        u64_stats_update_begin(&tx_stats->syncp);
        tx_stats->xdp_xmit += count;
diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c 
b/drivers/net/ethernet/microsoft/mana/mana_en.c
index a654b3699c4c..8adf72b96145 100644
--- a/drivers/net/ethernet/microsoft/mana/mana_en.c
+++ b/drivers/net/ethernet/microsoft/mana/mana_en.c
@@ -355,9 +355,9 @@ netdev_tx_t mana_start_xmit(struct sk_buff *skb, struct 
net_device *ndev)
        if (skb_cow_head(skb, MANA_HEADROOM))
                goto tx_drop_count;
 
-       txq = &apc->tx_qp[txq_idx].txq;
+       txq = &apc->tx_qp[txq_idx]->txq;
        gdma_sq = txq->gdma_sq;
-       cq = &apc->tx_qp[txq_idx].tx_cq;
+       cq = &apc->tx_qp[txq_idx]->tx_cq;
        tx_stats = &txq->stats;
 
        BUILD_BUG_ON(MAX_TX_WQE_SGL_ENTRIES != MANA_MAX_TX_WQE_SGL_ENTRIES);
@@ -614,7 +614,7 @@ static void mana_get_stats64(struct net_device *ndev,
        }
 
        for (q = 0; q < num_queues; q++) {
-               tx_stats = &apc->tx_qp[q].txq.stats;
+               tx_stats = &apc->tx_qp[q]->txq.stats;
 
                do {
                        start = u64_stats_fetch_begin(&tx_stats->syncp);
@@ -2321,21 +2321,26 @@ static void mana_destroy_txq(struct mana_port_context 
*apc)
                return;
 
        for (i = 0; i < apc->num_queues; i++) {
-               debugfs_remove_recursive(apc->tx_qp[i].mana_tx_debugfs);
-               apc->tx_qp[i].mana_tx_debugfs = NULL;
+               if (!apc->tx_qp[i])
+                       continue;
+
+               debugfs_remove_recursive(apc->tx_qp[i]->mana_tx_debugfs);
+               apc->tx_qp[i]->mana_tx_debugfs = NULL;
 
-               napi = &apc->tx_qp[i].tx_cq.napi;
-               if (apc->tx_qp[i].txq.napi_initialized) {
+               napi = &apc->tx_qp[i]->tx_cq.napi;
+               if (apc->tx_qp[i]->txq.napi_initialized) {
                        napi_synchronize(napi);
                        napi_disable_locked(napi);
                        netif_napi_del_locked(napi);
-                       apc->tx_qp[i].txq.napi_initialized = false;
+                       apc->tx_qp[i]->txq.napi_initialized = false;
                }
-               mana_destroy_wq_obj(apc, GDMA_SQ, apc->tx_qp[i].tx_object);
+               mana_destroy_wq_obj(apc, GDMA_SQ, apc->tx_qp[i]->tx_object);
 
-               mana_deinit_cq(apc, &apc->tx_qp[i].tx_cq);
+               mana_deinit_cq(apc, &apc->tx_qp[i]->tx_cq);
 
-               mana_deinit_txq(apc, &apc->tx_qp[i].txq);
+               mana_deinit_txq(apc, &apc->tx_qp[i]->txq);
+
+               kvfree(apc->tx_qp[i]);
        }
 
        kfree(apc->tx_qp);
@@ -2344,7 +2349,7 @@ static void mana_destroy_txq(struct mana_port_context 
*apc)
 
 static void mana_create_txq_debugfs(struct mana_port_context *apc, int idx)
 {
-       struct mana_tx_qp *tx_qp = &apc->tx_qp[idx];
+       struct mana_tx_qp *tx_qp = apc->tx_qp[idx];
        char qnum[32];
 
        sprintf(qnum, "TX-%d", idx);
@@ -2383,7 +2388,7 @@ static int mana_create_txq(struct mana_port_context *apc,
        int err;
        int i;
 
-       apc->tx_qp = kzalloc_objs(struct mana_tx_qp, apc->num_queues);
+       apc->tx_qp = kzalloc_objs(struct mana_tx_qp *, apc->num_queues);
        if (!apc->tx_qp)
                return -ENOMEM;
 
@@ -2403,10 +2408,16 @@ static int mana_create_txq(struct mana_port_context 
*apc,
        gc = gd->gdma_context;
 
        for (i = 0; i < apc->num_queues; i++) {
-               apc->tx_qp[i].tx_object = INVALID_MANA_HANDLE;
+               apc->tx_qp[i] = kvzalloc_obj(*apc->tx_qp[i]);
+               if (!apc->tx_qp[i]) {
+                       err = -ENOMEM;
+                       goto out;
+               }
+
+               apc->tx_qp[i]->tx_object = INVALID_MANA_HANDLE;
 
                /* Create SQ */
-               txq = &apc->tx_qp[i].txq;
+               txq = &apc->tx_qp[i]->txq;
 
                u64_stats_init(&txq->stats.syncp);
                txq->ndev = net;
@@ -2424,7 +2435,7 @@ static int mana_create_txq(struct mana_port_context *apc,
                        goto out;
 
                /* Create SQ's CQ */
-               cq = &apc->tx_qp[i].tx_cq;
+               cq = &apc->tx_qp[i]->tx_cq;
                cq->type = MANA_CQ_TYPE_TX;
 
                cq->txq = txq;
@@ -2453,7 +2464,7 @@ static int mana_create_txq(struct mana_port_context *apc,
 
                err = mana_create_wq_obj(apc, apc->port_handle, GDMA_SQ,
                                         &wq_spec, &cq_spec,
-                                        &apc->tx_qp[i].tx_object);
+                                        &apc->tx_qp[i]->tx_object);
 
                if (err)
                        goto out;
@@ -3288,7 +3299,7 @@ static int mana_dealloc_queues(struct net_device *ndev)
         */
 
        for (i = 0; i < apc->num_queues; i++) {
-               txq = &apc->tx_qp[i].txq;
+               txq = &apc->tx_qp[i]->txq;
                tsleep = 1000;
                while (atomic_read(&txq->pending_sends) > 0 &&
                       time_before(jiffies, timeout)) {
@@ -3307,7 +3318,7 @@ static int mana_dealloc_queues(struct net_device *ndev)
        }
 
        for (i = 0; i < apc->num_queues; i++) {
-               txq = &apc->tx_qp[i].txq;
+               txq = &apc->tx_qp[i]->txq;
                while ((skb = skb_dequeue(&txq->pending_skbs))) {
                        mana_unmap_skb(skb, apc);
                        dev_kfree_skb_any(skb);
diff --git a/drivers/net/ethernet/microsoft/mana/mana_ethtool.c 
b/drivers/net/ethernet/microsoft/mana/mana_ethtool.c
index 6a4b42fe0944..04350973e19e 100644
--- a/drivers/net/ethernet/microsoft/mana/mana_ethtool.c
+++ b/drivers/net/ethernet/microsoft/mana/mana_ethtool.c
@@ -260,7 +260,7 @@ static void mana_get_ethtool_stats(struct net_device *ndev,
        }
 
        for (q = 0; q < num_queues; q++) {
-               tx_stats = &apc->tx_qp[q].txq.stats;
+               tx_stats = &apc->tx_qp[q]->txq.stats;
 
                do {
                        start = u64_stats_fetch_begin(&tx_stats->syncp);
diff --git a/include/net/mana/mana.h b/include/net/mana/mana.h
index 8f721cd4e4a7..aa90a858c8e3 100644
--- a/include/net/mana/mana.h
+++ b/include/net/mana/mana.h
@@ -507,7 +507,7 @@ struct mana_port_context {
        bool tx_shortform_allowed;
        u16 tx_vp_offset;
 
-       struct mana_tx_qp *tx_qp;
+       struct mana_tx_qp **tx_qp;
 
        /* Indirection Table for RX & TX. The values are queue indexes */
        u32 *indir_table;
-- 
2.43.0


Reply via email to