]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
net/mlx5e: Preserve shared buffer capacity during headroom updates
authorArmen Ratner <armeng@nvidia.com>
Wed, 20 Aug 2025 13:32:09 +0000 (16:32 +0300)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 6 Dec 2025 21:12:37 +0000 (06:12 +0900)
commit 8b0587a885fdb34fd6090a3f8625cb7ac1444826 upstream.

When port buffer headroom changes, port_update_shared_buffer()
recalculates the shared buffer size and splits it in a 3:1 ratio
(lossy:lossless) - Currently, the calculation is:
lossless = shared / 4;
lossy = (shared / 4) * 3;

Meaning, the calculation dropped the remainder of shared % 4 due to
integer division, unintentionally reducing the total shared buffer
by up to three cells on each update. Over time, this could shrink
the buffer below usable size.

Fix it by changing the calculation to:
lossless = shared / 4;
lossy = shared - lossless;

This retains all buffer cells while still approximating the
intended 3:1 split, preventing capacity loss over time.

While at it, perform headroom calculations in units of cells rather than
in bytes for more accurate calculations avoiding extra divisions.

Fixes: a440030d8946 ("net/mlx5e: Update shared buffer along with device buffer changes")
Signed-off-by: Armen Ratner <armeng@nvidia.com>
Signed-off-by: Maher Sanalla <msanalla@nvidia.com>
Reviewed-by: Tariq Toukan <tariqt@nvidia.com>
Signed-off-by: Alexei Lazar <alazar@nvidia.com>
Signed-off-by: Mark Bloch <mbloch@nvidia.com>
Reviewed-by: Przemek Kitszel <przemyslaw.kitszel@intel.com>
Link: https://patch.msgid.link/20250820133209.389065-9-mbloch@nvidia.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/net/ethernet/mellanox/mlx5/core/en/port_buffer.c

index 2ceda8cadd2b8d9527130f4ea96ed091f62b1be7..5fa692b8a3b78ece55c89e1241f934578d78a409 100644 (file)
@@ -272,8 +272,8 @@ static int port_update_shared_buffer(struct mlx5_core_dev *mdev,
        /* Total shared buffer size is split in a ratio of 3:1 between
         * lossy and lossless pools respectively.
         */
-       lossy_epool_size = (shared_buffer_size / 4) * 3;
        lossless_ipool_size = shared_buffer_size / 4;
+       lossy_epool_size    = shared_buffer_size - lossless_ipool_size;
 
        mlx5e_port_set_sbpr(mdev, 0, MLX5_EGRESS_DIR, MLX5_LOSSY_POOL, 0,
                            lossy_epool_size);
@@ -288,14 +288,12 @@ static int port_set_buffer(struct mlx5e_priv *priv,
        u16 port_buff_cell_sz = priv->dcbx.port_buff_cell_sz;
        struct mlx5_core_dev *mdev = priv->mdev;
        int sz = MLX5_ST_SZ_BYTES(pbmc_reg);
-       u32 new_headroom_size = 0;
-       u32 current_headroom_size;
+       u32 current_headroom_cells = 0;
+       u32 new_headroom_cells = 0;
        void *in;
        int err;
        int i;
 
-       current_headroom_size = port_buffer->headroom_size;
-
        in = kzalloc(sz, GFP_KERNEL);
        if (!in)
                return -ENOMEM;
@@ -306,12 +304,14 @@ static int port_set_buffer(struct mlx5e_priv *priv,
 
        for (i = 0; i < MLX5E_MAX_NETWORK_BUFFER; i++) {
                void *buffer = MLX5_ADDR_OF(pbmc_reg, in, buffer[i]);
+               current_headroom_cells += MLX5_GET(bufferx_reg, buffer, size);
+
                u64 size = port_buffer->buffer[i].size;
                u64 xoff = port_buffer->buffer[i].xoff;
                u64 xon = port_buffer->buffer[i].xon;
 
-               new_headroom_size += size;
                do_div(size, port_buff_cell_sz);
+               new_headroom_cells += size;
                do_div(xoff, port_buff_cell_sz);
                do_div(xon, port_buff_cell_sz);
                MLX5_SET(bufferx_reg, buffer, size, size);
@@ -320,10 +320,8 @@ static int port_set_buffer(struct mlx5e_priv *priv,
                MLX5_SET(bufferx_reg, buffer, xon_threshold, xon);
        }
 
-       new_headroom_size /= port_buff_cell_sz;
-       current_headroom_size /= port_buff_cell_sz;
-       err = port_update_shared_buffer(priv->mdev, current_headroom_size,
-                                       new_headroom_size);
+       err = port_update_shared_buffer(priv->mdev, current_headroom_cells,
+                                       new_headroom_cells);
        if (err)
                goto out;