10696d608SHuy Nguyen /* 20696d608SHuy Nguyen * Copyright (c) 2018, Mellanox Technologies. All rights reserved. 30696d608SHuy Nguyen * 40696d608SHuy Nguyen * This software is available to you under a choice of one of two 50696d608SHuy Nguyen * licenses. You may choose to be licensed under the terms of the GNU 60696d608SHuy Nguyen * General Public License (GPL) Version 2, available from the file 70696d608SHuy Nguyen * COPYING in the main directory of this source tree, or the 80696d608SHuy Nguyen * OpenIB.org BSD license below: 90696d608SHuy Nguyen * 100696d608SHuy Nguyen * Redistribution and use in source and binary forms, with or 110696d608SHuy Nguyen * without modification, are permitted provided that the following 120696d608SHuy Nguyen * conditions are met: 130696d608SHuy Nguyen * 140696d608SHuy Nguyen * - Redistributions of source code must retain the above 150696d608SHuy Nguyen * copyright notice, this list of conditions and the following 160696d608SHuy Nguyen * disclaimer. 170696d608SHuy Nguyen * 180696d608SHuy Nguyen * - Redistributions in binary form must reproduce the above 190696d608SHuy Nguyen * copyright notice, this list of conditions and the following 200696d608SHuy Nguyen * disclaimer in the documentation and/or other materials 210696d608SHuy Nguyen * provided with the distribution. 220696d608SHuy Nguyen * 230696d608SHuy Nguyen * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 240696d608SHuy Nguyen * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 250696d608SHuy Nguyen * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 260696d608SHuy Nguyen * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 270696d608SHuy Nguyen * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 280696d608SHuy Nguyen * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 290696d608SHuy Nguyen * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 300696d608SHuy Nguyen * SOFTWARE. 310696d608SHuy Nguyen */ 320696d608SHuy Nguyen #include "port_buffer.h" 330696d608SHuy Nguyen 340696d608SHuy Nguyen int mlx5e_port_query_buffer(struct mlx5e_priv *priv, 350696d608SHuy Nguyen struct mlx5e_port_buffer *port_buffer) 360696d608SHuy Nguyen { 3788b3d5c9SEran Ben Elisha u16 port_buff_cell_sz = priv->dcbx.port_buff_cell_sz; 380696d608SHuy Nguyen struct mlx5_core_dev *mdev = priv->mdev; 390696d608SHuy Nguyen int sz = MLX5_ST_SZ_BYTES(pbmc_reg); 400696d608SHuy Nguyen u32 total_used = 0; 410696d608SHuy Nguyen void *buffer; 420696d608SHuy Nguyen void *out; 430696d608SHuy Nguyen int err; 440696d608SHuy Nguyen int i; 450696d608SHuy Nguyen 460696d608SHuy Nguyen out = kzalloc(sz, GFP_KERNEL); 470696d608SHuy Nguyen if (!out) 480696d608SHuy Nguyen return -ENOMEM; 490696d608SHuy Nguyen 500696d608SHuy Nguyen err = mlx5e_port_query_pbmc(mdev, out); 510696d608SHuy Nguyen if (err) 520696d608SHuy Nguyen goto out; 530696d608SHuy Nguyen 54*81fe2be0SMaher Sanalla for (i = 0; i < MLX5E_MAX_NETWORK_BUFFER; i++) { 550696d608SHuy Nguyen buffer = MLX5_ADDR_OF(pbmc_reg, out, buffer[i]); 560696d608SHuy Nguyen port_buffer->buffer[i].lossy = 570696d608SHuy Nguyen MLX5_GET(bufferx_reg, buffer, lossy); 580696d608SHuy Nguyen port_buffer->buffer[i].epsb = 590696d608SHuy Nguyen MLX5_GET(bufferx_reg, buffer, epsb); 600696d608SHuy Nguyen port_buffer->buffer[i].size = 6188b3d5c9SEran Ben Elisha MLX5_GET(bufferx_reg, buffer, size) * port_buff_cell_sz; 620696d608SHuy Nguyen port_buffer->buffer[i].xon = 6388b3d5c9SEran Ben Elisha MLX5_GET(bufferx_reg, buffer, xon_threshold) * port_buff_cell_sz; 640696d608SHuy Nguyen port_buffer->buffer[i].xoff = 6588b3d5c9SEran Ben Elisha MLX5_GET(bufferx_reg, buffer, xoff_threshold) * port_buff_cell_sz; 660696d608SHuy Nguyen total_used += port_buffer->buffer[i].size; 670696d608SHuy Nguyen 680696d608SHuy Nguyen mlx5e_dbg(HW, priv, "buffer %d: size=%d, xon=%d, xoff=%d, epsb=%d, lossy=%d\n", i, 690696d608SHuy Nguyen port_buffer->buffer[i].size, 700696d608SHuy Nguyen port_buffer->buffer[i].xon, 710696d608SHuy Nguyen port_buffer->buffer[i].xoff, 720696d608SHuy Nguyen port_buffer->buffer[i].epsb, 730696d608SHuy Nguyen port_buffer->buffer[i].lossy); 740696d608SHuy Nguyen } 750696d608SHuy Nguyen 76*81fe2be0SMaher Sanalla port_buffer->internal_buffers_size = 0; 77*81fe2be0SMaher Sanalla for (i = MLX5E_MAX_NETWORK_BUFFER; i < MLX5E_TOTAL_BUFFERS; i++) { 78*81fe2be0SMaher Sanalla buffer = MLX5_ADDR_OF(pbmc_reg, out, buffer[i]); 79*81fe2be0SMaher Sanalla port_buffer->internal_buffers_size += 80*81fe2be0SMaher Sanalla MLX5_GET(bufferx_reg, buffer, size) * port_buff_cell_sz; 81*81fe2be0SMaher Sanalla } 82*81fe2be0SMaher Sanalla 830696d608SHuy Nguyen port_buffer->port_buffer_size = 8488b3d5c9SEran Ben Elisha MLX5_GET(pbmc_reg, out, port_buffer_size) * port_buff_cell_sz; 85*81fe2be0SMaher Sanalla port_buffer->headroom_size = total_used; 86*81fe2be0SMaher Sanalla port_buffer->spare_buffer_size = port_buffer->port_buffer_size - 87*81fe2be0SMaher Sanalla port_buffer->internal_buffers_size - 88*81fe2be0SMaher Sanalla port_buffer->headroom_size; 890696d608SHuy Nguyen 90*81fe2be0SMaher Sanalla mlx5e_dbg(HW, priv, 91*81fe2be0SMaher Sanalla "total buffer size=%u, headroom buffer size=%u, internal buffers size=%u, spare buffer size=%u\n", 92*81fe2be0SMaher Sanalla port_buffer->port_buffer_size, port_buffer->headroom_size, 93*81fe2be0SMaher Sanalla port_buffer->internal_buffers_size, 940696d608SHuy Nguyen port_buffer->spare_buffer_size); 950696d608SHuy Nguyen out: 960696d608SHuy Nguyen kfree(out); 970696d608SHuy Nguyen return err; 980696d608SHuy Nguyen } 990696d608SHuy Nguyen 100a440030dSMaher Sanalla struct mlx5e_buffer_pool { 101a440030dSMaher Sanalla u32 infi_size; 102a440030dSMaher Sanalla u32 size; 103a440030dSMaher Sanalla u32 buff_occupancy; 104a440030dSMaher Sanalla }; 105a440030dSMaher Sanalla 106a440030dSMaher Sanalla static int mlx5e_port_query_pool(struct mlx5_core_dev *mdev, 107a440030dSMaher Sanalla struct mlx5e_buffer_pool *buffer_pool, 108a440030dSMaher Sanalla u32 desc, u8 dir, u8 pool_idx) 109a440030dSMaher Sanalla { 110a440030dSMaher Sanalla u32 out[MLX5_ST_SZ_DW(sbpr_reg)] = {}; 111a440030dSMaher Sanalla int err; 112a440030dSMaher Sanalla 113a440030dSMaher Sanalla err = mlx5e_port_query_sbpr(mdev, desc, dir, pool_idx, out, 114a440030dSMaher Sanalla sizeof(out)); 115a440030dSMaher Sanalla if (err) 116a440030dSMaher Sanalla return err; 117a440030dSMaher Sanalla 118a440030dSMaher Sanalla buffer_pool->size = MLX5_GET(sbpr_reg, out, size); 119a440030dSMaher Sanalla buffer_pool->infi_size = MLX5_GET(sbpr_reg, out, infi_size); 120a440030dSMaher Sanalla buffer_pool->buff_occupancy = MLX5_GET(sbpr_reg, out, buff_occupancy); 121a440030dSMaher Sanalla 122a440030dSMaher Sanalla return err; 123a440030dSMaher Sanalla } 124a440030dSMaher Sanalla 125a440030dSMaher Sanalla enum { 126a440030dSMaher Sanalla MLX5_INGRESS_DIR = 0, 127a440030dSMaher Sanalla MLX5_EGRESS_DIR = 1, 128a440030dSMaher Sanalla }; 129a440030dSMaher Sanalla 130a440030dSMaher Sanalla enum { 131a440030dSMaher Sanalla MLX5_LOSSY_POOL = 0, 132a440030dSMaher Sanalla MLX5_LOSSLESS_POOL = 1, 133a440030dSMaher Sanalla }; 134a440030dSMaher Sanalla 135a440030dSMaher Sanalla /* No limit on usage of shared buffer pool (max_buff=0) */ 136a440030dSMaher Sanalla #define MLX5_SB_POOL_NO_THRESHOLD 0 137a440030dSMaher Sanalla /* Shared buffer pool usage threshold when calculated 138a440030dSMaher Sanalla * dynamically in alpha units. alpha=13 is equivalent to 139a440030dSMaher Sanalla * HW_alpha of [(1/128) * 2 ^ (alpha-1)] = 32, where HW_alpha 140a440030dSMaher Sanalla * equates to the following portion of the shared buffer pool: 141a440030dSMaher Sanalla * [32 / (1 + n * 32)] While *n* is the number of buffers 142a440030dSMaher Sanalla * that are using the shared buffer pool. 143a440030dSMaher Sanalla */ 144a440030dSMaher Sanalla #define MLX5_SB_POOL_THRESHOLD 13 145a440030dSMaher Sanalla 146a440030dSMaher Sanalla /* Shared buffer class management parameters */ 147a440030dSMaher Sanalla struct mlx5_sbcm_params { 148a440030dSMaher Sanalla u8 pool_idx; 149a440030dSMaher Sanalla u8 max_buff; 150a440030dSMaher Sanalla u8 infi_size; 151a440030dSMaher Sanalla }; 152a440030dSMaher Sanalla 153a440030dSMaher Sanalla static const struct mlx5_sbcm_params sbcm_default = { 154a440030dSMaher Sanalla .pool_idx = MLX5_LOSSY_POOL, 155a440030dSMaher Sanalla .max_buff = MLX5_SB_POOL_NO_THRESHOLD, 156a440030dSMaher Sanalla .infi_size = 0, 157a440030dSMaher Sanalla }; 158a440030dSMaher Sanalla 159a440030dSMaher Sanalla static const struct mlx5_sbcm_params sbcm_lossy = { 160a440030dSMaher Sanalla .pool_idx = MLX5_LOSSY_POOL, 161a440030dSMaher Sanalla .max_buff = MLX5_SB_POOL_NO_THRESHOLD, 162a440030dSMaher Sanalla .infi_size = 1, 163a440030dSMaher Sanalla }; 164a440030dSMaher Sanalla 165a440030dSMaher Sanalla static const struct mlx5_sbcm_params sbcm_lossless = { 166a440030dSMaher Sanalla .pool_idx = MLX5_LOSSLESS_POOL, 167a440030dSMaher Sanalla .max_buff = MLX5_SB_POOL_THRESHOLD, 168a440030dSMaher Sanalla .infi_size = 0, 169a440030dSMaher Sanalla }; 170a440030dSMaher Sanalla 171a440030dSMaher Sanalla static const struct mlx5_sbcm_params sbcm_lossless_no_threshold = { 172a440030dSMaher Sanalla .pool_idx = MLX5_LOSSLESS_POOL, 173a440030dSMaher Sanalla .max_buff = MLX5_SB_POOL_NO_THRESHOLD, 174a440030dSMaher Sanalla .infi_size = 1, 175a440030dSMaher Sanalla }; 176a440030dSMaher Sanalla 177a440030dSMaher Sanalla /** 178a440030dSMaher Sanalla * select_sbcm_params() - selects the shared buffer pool configuration 179a440030dSMaher Sanalla * 180a440030dSMaher Sanalla * @buffer: <input> port buffer to retrieve params of 181a440030dSMaher Sanalla * @lossless_buff_count: <input> number of lossless buffers in total 182a440030dSMaher Sanalla * 183a440030dSMaher Sanalla * The selection is based on the following rules: 184a440030dSMaher Sanalla * 1. If buffer size is 0, no shared buffer pool is used. 185a440030dSMaher Sanalla * 2. If buffer is lossy, use lossy shared buffer pool. 186a440030dSMaher Sanalla * 3. If there are more than 1 lossless buffers, use lossless shared buffer pool 187a440030dSMaher Sanalla * with threshold. 188a440030dSMaher Sanalla * 4. If there is only 1 lossless buffer, use lossless shared buffer pool 189a440030dSMaher Sanalla * without threshold. 190a440030dSMaher Sanalla * 191a440030dSMaher Sanalla * @return const struct mlx5_sbcm_params* selected values 192a440030dSMaher Sanalla */ 193a440030dSMaher Sanalla static const struct mlx5_sbcm_params * 194a440030dSMaher Sanalla select_sbcm_params(struct mlx5e_bufferx_reg *buffer, u8 lossless_buff_count) 195a440030dSMaher Sanalla { 196a440030dSMaher Sanalla if (buffer->size == 0) 197a440030dSMaher Sanalla return &sbcm_default; 198a440030dSMaher Sanalla 199a440030dSMaher Sanalla if (buffer->lossy) 200a440030dSMaher Sanalla return &sbcm_lossy; 201a440030dSMaher Sanalla 202a440030dSMaher Sanalla if (lossless_buff_count > 1) 203a440030dSMaher Sanalla return &sbcm_lossless; 204a440030dSMaher Sanalla 205a440030dSMaher Sanalla return &sbcm_lossless_no_threshold; 206a440030dSMaher Sanalla } 207a440030dSMaher Sanalla 208a440030dSMaher Sanalla static int port_update_pool_cfg(struct mlx5_core_dev *mdev, 209a440030dSMaher Sanalla struct mlx5e_port_buffer *port_buffer) 210a440030dSMaher Sanalla { 211a440030dSMaher Sanalla const struct mlx5_sbcm_params *p; 212a440030dSMaher Sanalla u8 lossless_buff_count = 0; 213a440030dSMaher Sanalla int err; 214a440030dSMaher Sanalla int i; 215a440030dSMaher Sanalla 216a440030dSMaher Sanalla if (!MLX5_CAP_GEN(mdev, sbcam_reg)) 217a440030dSMaher Sanalla return 0; 218a440030dSMaher Sanalla 219*81fe2be0SMaher Sanalla for (i = 0; i < MLX5E_MAX_NETWORK_BUFFER; i++) 220a440030dSMaher Sanalla lossless_buff_count += ((port_buffer->buffer[i].size) && 221a440030dSMaher Sanalla (!(port_buffer->buffer[i].lossy))); 222a440030dSMaher Sanalla 223*81fe2be0SMaher Sanalla for (i = 0; i < MLX5E_MAX_NETWORK_BUFFER; i++) { 224a440030dSMaher Sanalla p = select_sbcm_params(&port_buffer->buffer[i], lossless_buff_count); 225a440030dSMaher Sanalla err = mlx5e_port_set_sbcm(mdev, 0, i, 226a440030dSMaher Sanalla MLX5_INGRESS_DIR, 227a440030dSMaher Sanalla p->infi_size, 228a440030dSMaher Sanalla p->max_buff, 229a440030dSMaher Sanalla p->pool_idx); 230a440030dSMaher Sanalla if (err) 231a440030dSMaher Sanalla return err; 232a440030dSMaher Sanalla } 233a440030dSMaher Sanalla 234a440030dSMaher Sanalla return 0; 235a440030dSMaher Sanalla } 236a440030dSMaher Sanalla 237a440030dSMaher Sanalla static int port_update_shared_buffer(struct mlx5_core_dev *mdev, 238a440030dSMaher Sanalla u32 current_headroom_size, 239a440030dSMaher Sanalla u32 new_headroom_size) 240a440030dSMaher Sanalla { 241a440030dSMaher Sanalla struct mlx5e_buffer_pool lossless_ipool; 242a440030dSMaher Sanalla struct mlx5e_buffer_pool lossy_epool; 243a440030dSMaher Sanalla u32 lossless_ipool_size; 244a440030dSMaher Sanalla u32 shared_buffer_size; 245a440030dSMaher Sanalla u32 total_buffer_size; 246a440030dSMaher Sanalla u32 lossy_epool_size; 247a440030dSMaher Sanalla int err; 248a440030dSMaher Sanalla 249a440030dSMaher Sanalla if (!MLX5_CAP_GEN(mdev, sbcam_reg)) 250a440030dSMaher Sanalla return 0; 251a440030dSMaher Sanalla 252a440030dSMaher Sanalla err = mlx5e_port_query_pool(mdev, &lossy_epool, 0, MLX5_EGRESS_DIR, 253a440030dSMaher Sanalla MLX5_LOSSY_POOL); 254a440030dSMaher Sanalla if (err) 255a440030dSMaher Sanalla return err; 256a440030dSMaher Sanalla 257a440030dSMaher Sanalla err = mlx5e_port_query_pool(mdev, &lossless_ipool, 0, MLX5_INGRESS_DIR, 258a440030dSMaher Sanalla MLX5_LOSSLESS_POOL); 259a440030dSMaher Sanalla if (err) 260a440030dSMaher Sanalla return err; 261a440030dSMaher Sanalla 262a440030dSMaher Sanalla total_buffer_size = current_headroom_size + lossy_epool.size + 263a440030dSMaher Sanalla lossless_ipool.size; 264a440030dSMaher Sanalla shared_buffer_size = total_buffer_size - new_headroom_size; 265a440030dSMaher Sanalla 266a440030dSMaher Sanalla if (shared_buffer_size < 4) { 267a440030dSMaher Sanalla pr_err("Requested port buffer is too large, not enough space left for shared buffer\n"); 268a440030dSMaher Sanalla return -EINVAL; 269a440030dSMaher Sanalla } 270a440030dSMaher Sanalla 271a440030dSMaher Sanalla /* Total shared buffer size is split in a ratio of 3:1 between 272a440030dSMaher Sanalla * lossy and lossless pools respectively. 273a440030dSMaher Sanalla */ 274a440030dSMaher Sanalla lossy_epool_size = (shared_buffer_size / 4) * 3; 275a440030dSMaher Sanalla lossless_ipool_size = shared_buffer_size / 4; 276a440030dSMaher Sanalla 277a440030dSMaher Sanalla mlx5e_port_set_sbpr(mdev, 0, MLX5_EGRESS_DIR, MLX5_LOSSY_POOL, 0, 278a440030dSMaher Sanalla lossy_epool_size); 279a440030dSMaher Sanalla mlx5e_port_set_sbpr(mdev, 0, MLX5_INGRESS_DIR, MLX5_LOSSLESS_POOL, 0, 280a440030dSMaher Sanalla lossless_ipool_size); 281a440030dSMaher Sanalla return 0; 282a440030dSMaher Sanalla } 283a440030dSMaher Sanalla 2840696d608SHuy Nguyen static int port_set_buffer(struct mlx5e_priv *priv, 2850696d608SHuy Nguyen struct mlx5e_port_buffer *port_buffer) 2860696d608SHuy Nguyen { 28788b3d5c9SEran Ben Elisha u16 port_buff_cell_sz = priv->dcbx.port_buff_cell_sz; 2880696d608SHuy Nguyen struct mlx5_core_dev *mdev = priv->mdev; 2890696d608SHuy Nguyen int sz = MLX5_ST_SZ_BYTES(pbmc_reg); 290a440030dSMaher Sanalla u32 new_headroom_size = 0; 291a440030dSMaher Sanalla u32 current_headroom_size; 2920696d608SHuy Nguyen void *in; 2930696d608SHuy Nguyen int err; 2940696d608SHuy Nguyen int i; 2950696d608SHuy Nguyen 296a440030dSMaher Sanalla current_headroom_size = port_buffer->headroom_size; 297a440030dSMaher Sanalla 2980696d608SHuy Nguyen in = kzalloc(sz, GFP_KERNEL); 2990696d608SHuy Nguyen if (!in) 3000696d608SHuy Nguyen return -ENOMEM; 3010696d608SHuy Nguyen 3020696d608SHuy Nguyen err = mlx5e_port_query_pbmc(mdev, in); 3030696d608SHuy Nguyen if (err) 3040696d608SHuy Nguyen goto out; 3050696d608SHuy Nguyen 306*81fe2be0SMaher Sanalla for (i = 0; i < MLX5E_MAX_NETWORK_BUFFER; i++) { 30788b3d5c9SEran Ben Elisha void *buffer = MLX5_ADDR_OF(pbmc_reg, in, buffer[i]); 30888b3d5c9SEran Ben Elisha u64 size = port_buffer->buffer[i].size; 30988b3d5c9SEran Ben Elisha u64 xoff = port_buffer->buffer[i].xoff; 31088b3d5c9SEran Ben Elisha u64 xon = port_buffer->buffer[i].xon; 3110696d608SHuy Nguyen 312a440030dSMaher Sanalla new_headroom_size += size; 31388b3d5c9SEran Ben Elisha do_div(size, port_buff_cell_sz); 31488b3d5c9SEran Ben Elisha do_div(xoff, port_buff_cell_sz); 31588b3d5c9SEran Ben Elisha do_div(xon, port_buff_cell_sz); 31688b3d5c9SEran Ben Elisha MLX5_SET(bufferx_reg, buffer, size, size); 31788b3d5c9SEran Ben Elisha MLX5_SET(bufferx_reg, buffer, lossy, port_buffer->buffer[i].lossy); 31888b3d5c9SEran Ben Elisha MLX5_SET(bufferx_reg, buffer, xoff_threshold, xoff); 31988b3d5c9SEran Ben Elisha MLX5_SET(bufferx_reg, buffer, xon_threshold, xon); 3200696d608SHuy Nguyen } 3210696d608SHuy Nguyen 322a440030dSMaher Sanalla new_headroom_size /= port_buff_cell_sz; 323a440030dSMaher Sanalla current_headroom_size /= port_buff_cell_sz; 324a440030dSMaher Sanalla err = port_update_shared_buffer(priv->mdev, current_headroom_size, 325a440030dSMaher Sanalla new_headroom_size); 326a440030dSMaher Sanalla if (err) 327e3e01c1cSMaher Sanalla goto out; 328a440030dSMaher Sanalla 329a440030dSMaher Sanalla err = port_update_pool_cfg(priv->mdev, port_buffer); 330a440030dSMaher Sanalla if (err) 331e3e01c1cSMaher Sanalla goto out; 332a440030dSMaher Sanalla 3330696d608SHuy Nguyen err = mlx5e_port_set_pbmc(mdev, in); 3340696d608SHuy Nguyen out: 3350696d608SHuy Nguyen kfree(in); 3360696d608SHuy Nguyen return err; 3370696d608SHuy Nguyen } 3380696d608SHuy Nguyen 3395ec983e9SHuy Nguyen /* xoff = ((301+2.16 * len [m]) * speed [Gbps] + 2.72 MTU [B]) 3405ec983e9SHuy Nguyen * minimum speed value is 40Gbps 3415ec983e9SHuy Nguyen */ 3420696d608SHuy Nguyen static u32 calculate_xoff(struct mlx5e_priv *priv, unsigned int mtu) 3430696d608SHuy Nguyen { 3440696d608SHuy Nguyen u32 speed; 3450696d608SHuy Nguyen u32 xoff; 3460696d608SHuy Nguyen int err; 3470696d608SHuy Nguyen 3480696d608SHuy Nguyen err = mlx5e_port_linkspeed(priv->mdev, &speed); 3495ec983e9SHuy Nguyen if (err) 3505ec983e9SHuy Nguyen speed = SPEED_40000; 3515ec983e9SHuy Nguyen speed = max_t(u32, speed, SPEED_40000); 3520696d608SHuy Nguyen 3530696d608SHuy Nguyen xoff = (301 + 216 * priv->dcbx.cable_len / 100) * speed / 1000 + 272 * mtu / 100; 3540696d608SHuy Nguyen 3550696d608SHuy Nguyen mlx5e_dbg(HW, priv, "%s: xoff=%d\n", __func__, xoff); 3560696d608SHuy Nguyen return xoff; 3570696d608SHuy Nguyen } 3580696d608SHuy Nguyen 3590696d608SHuy Nguyen static int update_xoff_threshold(struct mlx5e_port_buffer *port_buffer, 36088b3d5c9SEran Ben Elisha u32 xoff, unsigned int max_mtu, u16 port_buff_cell_sz) 3610696d608SHuy Nguyen { 3620696d608SHuy Nguyen int i; 3630696d608SHuy Nguyen 364*81fe2be0SMaher Sanalla for (i = 0; i < MLX5E_MAX_NETWORK_BUFFER; i++) { 3650696d608SHuy Nguyen if (port_buffer->buffer[i].lossy) { 3660696d608SHuy Nguyen port_buffer->buffer[i].xoff = 0; 3670696d608SHuy Nguyen port_buffer->buffer[i].xon = 0; 3680696d608SHuy Nguyen continue; 3690696d608SHuy Nguyen } 3700696d608SHuy Nguyen 3710696d608SHuy Nguyen if (port_buffer->buffer[i].size < 37288b3d5c9SEran Ben Elisha (xoff + max_mtu + port_buff_cell_sz)) { 37373e65516SHuy Nguyen pr_err("buffer_size[%d]=%d is not enough for lossless buffer\n", 37473e65516SHuy Nguyen i, port_buffer->buffer[i].size); 3750696d608SHuy Nguyen return -ENOMEM; 37673e65516SHuy Nguyen } 3770696d608SHuy Nguyen 3780696d608SHuy Nguyen port_buffer->buffer[i].xoff = port_buffer->buffer[i].size - xoff; 379e28408e9SHuy Nguyen port_buffer->buffer[i].xon = 380e28408e9SHuy Nguyen port_buffer->buffer[i].xoff - max_mtu; 3810696d608SHuy Nguyen } 3820696d608SHuy Nguyen 3830696d608SHuy Nguyen return 0; 3840696d608SHuy Nguyen } 3850696d608SHuy Nguyen 3860696d608SHuy Nguyen /** 387d3669ca9SSaeed Mahameed * update_buffer_lossy - Update buffer configuration based on pfc 388a440030dSMaher Sanalla * @mdev: port function core device 389f83f7151SDavid S. Miller * @max_mtu: netdev's max_mtu 390d3669ca9SSaeed Mahameed * @pfc_en: <input> current pfc configuration 391d3669ca9SSaeed Mahameed * @buffer: <input> current prio to buffer mapping 392d3669ca9SSaeed Mahameed * @xoff: <input> xoff value 39388b3d5c9SEran Ben Elisha * @port_buff_cell_sz: <input> port buffer cell_size 394d3669ca9SSaeed Mahameed * @port_buffer: <output> port receive buffer configuration 395d3669ca9SSaeed Mahameed * @change: <output> 3960696d608SHuy Nguyen * 397c199ce4fSGeert Uytterhoeven * Update buffer configuration based on pfc configuration and 398d3669ca9SSaeed Mahameed * priority to buffer mapping. 3990696d608SHuy Nguyen * Buffer's lossy bit is changed to: 400d3669ca9SSaeed Mahameed * lossless if there is at least one PFC enabled priority 401d3669ca9SSaeed Mahameed * mapped to this buffer lossy if all priorities mapped to 402d3669ca9SSaeed Mahameed * this buffer are PFC disabled 4030696d608SHuy Nguyen * 404d3669ca9SSaeed Mahameed * @return: 0 if no error, 405d3669ca9SSaeed Mahameed * sets change to true if buffer configuration was modified. 4060696d608SHuy Nguyen */ 407a440030dSMaher Sanalla static int update_buffer_lossy(struct mlx5_core_dev *mdev, 408a440030dSMaher Sanalla unsigned int max_mtu, 40988b3d5c9SEran Ben Elisha u8 pfc_en, u8 *buffer, u32 xoff, u16 port_buff_cell_sz, 4100696d608SHuy Nguyen struct mlx5e_port_buffer *port_buffer, 4110696d608SHuy Nguyen bool *change) 4120696d608SHuy Nguyen { 4130696d608SHuy Nguyen bool changed = false; 4140696d608SHuy Nguyen u8 lossy_count; 4150696d608SHuy Nguyen u8 prio_count; 4160696d608SHuy Nguyen u8 lossy; 4170696d608SHuy Nguyen int prio; 4180696d608SHuy Nguyen int err; 4190696d608SHuy Nguyen int i; 4200696d608SHuy Nguyen 421*81fe2be0SMaher Sanalla for (i = 0; i < MLX5E_MAX_NETWORK_BUFFER; i++) { 4220696d608SHuy Nguyen prio_count = 0; 4230696d608SHuy Nguyen lossy_count = 0; 4240696d608SHuy Nguyen 4250696d608SHuy Nguyen for (prio = 0; prio < MLX5E_MAX_PRIORITY; prio++) { 4260696d608SHuy Nguyen if (buffer[prio] != i) 4270696d608SHuy Nguyen continue; 4280696d608SHuy Nguyen 4290696d608SHuy Nguyen prio_count++; 4300696d608SHuy Nguyen lossy_count += !(pfc_en & (1 << prio)); 4310696d608SHuy Nguyen } 4320696d608SHuy Nguyen 4330696d608SHuy Nguyen if (lossy_count == prio_count) 4340696d608SHuy Nguyen lossy = 1; 4350696d608SHuy Nguyen else /* lossy_count < prio_count */ 4360696d608SHuy Nguyen lossy = 0; 4370696d608SHuy Nguyen 4380696d608SHuy Nguyen if (lossy != port_buffer->buffer[i].lossy) { 4390696d608SHuy Nguyen port_buffer->buffer[i].lossy = lossy; 4400696d608SHuy Nguyen changed = true; 4410696d608SHuy Nguyen } 4420696d608SHuy Nguyen } 4430696d608SHuy Nguyen 4440696d608SHuy Nguyen if (changed) { 445a440030dSMaher Sanalla err = port_update_pool_cfg(mdev, port_buffer); 446a440030dSMaher Sanalla if (err) 447a440030dSMaher Sanalla return err; 448a440030dSMaher Sanalla 44988b3d5c9SEran Ben Elisha err = update_xoff_threshold(port_buffer, xoff, max_mtu, port_buff_cell_sz); 4500696d608SHuy Nguyen if (err) 4510696d608SHuy Nguyen return err; 4520696d608SHuy Nguyen 4530696d608SHuy Nguyen *change = true; 4540696d608SHuy Nguyen } 4550696d608SHuy Nguyen 4560696d608SHuy Nguyen return 0; 4570696d608SHuy Nguyen } 4580696d608SHuy Nguyen 45973e65516SHuy Nguyen static int fill_pfc_en(struct mlx5_core_dev *mdev, u8 *pfc_en) 46073e65516SHuy Nguyen { 46173e65516SHuy Nguyen u32 g_rx_pause, g_tx_pause; 46273e65516SHuy Nguyen int err; 46373e65516SHuy Nguyen 46473e65516SHuy Nguyen err = mlx5_query_port_pause(mdev, &g_rx_pause, &g_tx_pause); 46573e65516SHuy Nguyen if (err) 46673e65516SHuy Nguyen return err; 46773e65516SHuy Nguyen 46873e65516SHuy Nguyen /* If global pause enabled, set all active buffers to lossless. 46973e65516SHuy Nguyen * Otherwise, check PFC setting. 47073e65516SHuy Nguyen */ 47173e65516SHuy Nguyen if (g_rx_pause || g_tx_pause) 47273e65516SHuy Nguyen *pfc_en = 0xff; 47373e65516SHuy Nguyen else 47473e65516SHuy Nguyen err = mlx5_query_port_pfc(mdev, pfc_en, NULL); 47573e65516SHuy Nguyen 47673e65516SHuy Nguyen return err; 47773e65516SHuy Nguyen } 47873e65516SHuy Nguyen 479e28408e9SHuy Nguyen #define MINIMUM_MAX_MTU 9216 4800696d608SHuy Nguyen int mlx5e_port_manual_buffer_config(struct mlx5e_priv *priv, 4810696d608SHuy Nguyen u32 change, unsigned int mtu, 4820696d608SHuy Nguyen struct ieee_pfc *pfc, 4830696d608SHuy Nguyen u32 *buffer_size, 4840696d608SHuy Nguyen u8 *prio2buffer) 4850696d608SHuy Nguyen { 48688b3d5c9SEran Ben Elisha u16 port_buff_cell_sz = priv->dcbx.port_buff_cell_sz; 4870696d608SHuy Nguyen struct mlx5e_port_buffer port_buffer; 4880696d608SHuy Nguyen u32 xoff = calculate_xoff(priv, mtu); 4890696d608SHuy Nguyen bool update_prio2buffer = false; 4900696d608SHuy Nguyen u8 buffer[MLX5E_MAX_PRIORITY]; 4910696d608SHuy Nguyen bool update_buffer = false; 492e28408e9SHuy Nguyen unsigned int max_mtu; 4930696d608SHuy Nguyen u32 total_used = 0; 4940696d608SHuy Nguyen u8 curr_pfc_en; 4950696d608SHuy Nguyen int err; 4960696d608SHuy Nguyen int i; 4970696d608SHuy Nguyen 4980696d608SHuy Nguyen mlx5e_dbg(HW, priv, "%s: change=%x\n", __func__, change); 499e28408e9SHuy Nguyen max_mtu = max_t(unsigned int, priv->netdev->max_mtu, MINIMUM_MAX_MTU); 5000696d608SHuy Nguyen 5010696d608SHuy Nguyen err = mlx5e_port_query_buffer(priv, &port_buffer); 5020696d608SHuy Nguyen if (err) 5030696d608SHuy Nguyen return err; 5040696d608SHuy Nguyen 5050696d608SHuy Nguyen if (change & MLX5E_PORT_BUFFER_CABLE_LEN) { 5060696d608SHuy Nguyen update_buffer = true; 50788b3d5c9SEran Ben Elisha err = update_xoff_threshold(&port_buffer, xoff, max_mtu, port_buff_cell_sz); 5080696d608SHuy Nguyen if (err) 5090696d608SHuy Nguyen return err; 5100696d608SHuy Nguyen } 5110696d608SHuy Nguyen 5120696d608SHuy Nguyen if (change & MLX5E_PORT_BUFFER_PFC) { 513a440030dSMaher Sanalla mlx5e_dbg(HW, priv, "%s: requested PFC per priority bitmask: 0x%x\n", 514a440030dSMaher Sanalla __func__, pfc->pfc_en); 5150696d608SHuy Nguyen err = mlx5e_port_query_priority2buffer(priv->mdev, buffer); 5160696d608SHuy Nguyen if (err) 5170696d608SHuy Nguyen return err; 5180696d608SHuy Nguyen 519a440030dSMaher Sanalla err = update_buffer_lossy(priv->mdev, max_mtu, pfc->pfc_en, buffer, xoff, 520a440030dSMaher Sanalla port_buff_cell_sz, &port_buffer, 521a440030dSMaher Sanalla &update_buffer); 5220696d608SHuy Nguyen if (err) 5230696d608SHuy Nguyen return err; 5240696d608SHuy Nguyen } 5250696d608SHuy Nguyen 5260696d608SHuy Nguyen if (change & MLX5E_PORT_BUFFER_PRIO2BUFFER) { 5270696d608SHuy Nguyen update_prio2buffer = true; 528*81fe2be0SMaher Sanalla for (i = 0; i < MLX5E_MAX_NETWORK_BUFFER; i++) 529a440030dSMaher Sanalla mlx5e_dbg(HW, priv, "%s: requested to map prio[%d] to buffer %d\n", 530a440030dSMaher Sanalla __func__, i, prio2buffer[i]); 531a440030dSMaher Sanalla 53273e65516SHuy Nguyen err = fill_pfc_en(priv->mdev, &curr_pfc_en); 5330696d608SHuy Nguyen if (err) 5340696d608SHuy Nguyen return err; 5350696d608SHuy Nguyen 536a440030dSMaher Sanalla err = update_buffer_lossy(priv->mdev, max_mtu, curr_pfc_en, prio2buffer, xoff, 537c4d963a5SMark Zhang port_buff_cell_sz, &port_buffer, &update_buffer); 5380696d608SHuy Nguyen if (err) 5390696d608SHuy Nguyen return err; 5400696d608SHuy Nguyen } 5410696d608SHuy Nguyen 5420696d608SHuy Nguyen if (change & MLX5E_PORT_BUFFER_SIZE) { 543*81fe2be0SMaher Sanalla for (i = 0; i < MLX5E_MAX_NETWORK_BUFFER; i++) { 5440696d608SHuy Nguyen mlx5e_dbg(HW, priv, "%s: buffer[%d]=%d\n", __func__, i, buffer_size[i]); 5450696d608SHuy Nguyen if (!port_buffer.buffer[i].lossy && !buffer_size[i]) { 5460696d608SHuy Nguyen mlx5e_dbg(HW, priv, "%s: lossless buffer[%d] size cannot be zero\n", 5470696d608SHuy Nguyen __func__, i); 5480696d608SHuy Nguyen return -EINVAL; 5490696d608SHuy Nguyen } 5500696d608SHuy Nguyen 5510696d608SHuy Nguyen port_buffer.buffer[i].size = buffer_size[i]; 5520696d608SHuy Nguyen total_used += buffer_size[i]; 5530696d608SHuy Nguyen } 5540696d608SHuy Nguyen 5550696d608SHuy Nguyen mlx5e_dbg(HW, priv, "%s: total buffer requested=%d\n", __func__, total_used); 5560696d608SHuy Nguyen 557*81fe2be0SMaher Sanalla if (total_used > port_buffer.headroom_size && 558*81fe2be0SMaher Sanalla (total_used - port_buffer.headroom_size) > 559*81fe2be0SMaher Sanalla port_buffer.spare_buffer_size) 5600696d608SHuy Nguyen return -EINVAL; 5610696d608SHuy Nguyen 5620696d608SHuy Nguyen update_buffer = true; 56388b3d5c9SEran Ben Elisha err = update_xoff_threshold(&port_buffer, xoff, max_mtu, port_buff_cell_sz); 5640696d608SHuy Nguyen if (err) 5650696d608SHuy Nguyen return err; 5660696d608SHuy Nguyen } 5670696d608SHuy Nguyen 5680696d608SHuy Nguyen /* Need to update buffer configuration if xoff value is changed */ 5690696d608SHuy Nguyen if (!update_buffer && xoff != priv->dcbx.xoff) { 5700696d608SHuy Nguyen update_buffer = true; 57188b3d5c9SEran Ben Elisha err = update_xoff_threshold(&port_buffer, xoff, max_mtu, port_buff_cell_sz); 5720696d608SHuy Nguyen if (err) 5730696d608SHuy Nguyen return err; 5740696d608SHuy Nguyen } 5750696d608SHuy Nguyen priv->dcbx.xoff = xoff; 5760696d608SHuy Nguyen 5770696d608SHuy Nguyen /* Apply the settings */ 5780696d608SHuy Nguyen if (update_buffer) { 5790696d608SHuy Nguyen err = port_set_buffer(priv, &port_buffer); 5800696d608SHuy Nguyen if (err) 5810696d608SHuy Nguyen return err; 5820696d608SHuy Nguyen } 5830696d608SHuy Nguyen 5840696d608SHuy Nguyen if (update_prio2buffer) 5850696d608SHuy Nguyen err = mlx5e_port_set_priority2buffer(priv->mdev, prio2buffer); 5860696d608SHuy Nguyen 5870696d608SHuy Nguyen return err; 5880696d608SHuy Nguyen } 589