The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/mlx5/mlx5_en/mlx5_en_port_buffer.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 2018-2019 Mellanox Technologies. All rights reserved.
    3  *
    4  * Redistribution and use in source and binary forms, with or without
    5  * modification, are permitted provided that the following conditions
    6  * are met:
    7  * 1. Redistributions of source code must retain the above copyright
    8  *    notice, this list of conditions and the following disclaimer.
    9  * 2. Redistributions in binary form must reproduce the above copyright
   10  *    notice, this list of conditions and the following disclaimer in the
   11  *    documentation and/or other materials provided with the distribution.
   12  *
   13  * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS `AS IS' AND
   14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   16  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
   17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   19  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   20  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   23  * SUCH DAMAGE.
   24  *
   25  * $FreeBSD$
   26  */
   27 
   28 #include "opt_rss.h"
   29 #include "opt_ratelimit.h"
   30 
   31 #include <dev/mlx5/mlx5_en/port_buffer.h>
   32 
   33 #define MLX5E_MAX_PORT_MTU  9216
   34 
   35 int mlx5e_port_query_buffer(struct mlx5e_priv *priv,
   36                             struct mlx5e_port_buffer *port_buffer)
   37 {
   38         struct mlx5_core_dev *mdev = priv->mdev;
   39         int sz = MLX5_ST_SZ_BYTES(pbmc_reg);
   40         u32 total_used = 0;
   41         void *buffer;
   42         void *out;
   43         int err;
   44         int i;
   45 
   46         out = kzalloc(sz, GFP_KERNEL);
   47         if (!out)
   48                 return -ENOMEM;
   49 
   50         err = mlx5e_port_query_pbmc(mdev, out);
   51         if (err)
   52                 goto out;
   53 
   54         for (i = 0; i < MLX5E_MAX_BUFFER; i++) {
   55                 buffer = MLX5_ADDR_OF(pbmc_reg, out, buffer[i]);
   56                 port_buffer->buffer[i].lossy =
   57                         MLX5_GET(bufferx_reg, buffer, lossy);
   58                 port_buffer->buffer[i].epsb =
   59                         MLX5_GET(bufferx_reg, buffer, epsb);
   60                 port_buffer->buffer[i].size =
   61                         MLX5_GET(bufferx_reg, buffer, size) << MLX5E_BUFFER_CELL_SHIFT;
   62                 port_buffer->buffer[i].xon =
   63                         MLX5_GET(bufferx_reg, buffer, xon_threshold) << MLX5E_BUFFER_CELL_SHIFT;
   64                 port_buffer->buffer[i].xoff =
   65                         MLX5_GET(bufferx_reg, buffer, xoff_threshold) << MLX5E_BUFFER_CELL_SHIFT;
   66                 total_used += port_buffer->buffer[i].size;
   67 
   68                 mlx5e_dbg(HW, priv, "buffer %d: size=%d, xon=%d, xoff=%d, epsb=%d, lossy=%d\n", i,
   69                           port_buffer->buffer[i].size,
   70                           port_buffer->buffer[i].xon,
   71                           port_buffer->buffer[i].xoff,
   72                           port_buffer->buffer[i].epsb,
   73                           port_buffer->buffer[i].lossy);
   74         }
   75 
   76         port_buffer->port_buffer_size =
   77                 MLX5_GET(pbmc_reg, out, port_buffer_size) << MLX5E_BUFFER_CELL_SHIFT;
   78         port_buffer->spare_buffer_size =
   79                 port_buffer->port_buffer_size - total_used;
   80 
   81         mlx5e_dbg(HW, priv, "total buffer size=%d, spare buffer size=%d\n",
   82                   port_buffer->port_buffer_size,
   83                   port_buffer->spare_buffer_size);
   84 out:
   85         kfree(out);
   86         return err;
   87 }
   88 
   89 static int port_set_buffer(struct mlx5e_priv *priv,
   90                            struct mlx5e_port_buffer *port_buffer)
   91 {
   92         struct mlx5_core_dev *mdev = priv->mdev;
   93         int sz = MLX5_ST_SZ_BYTES(pbmc_reg);
   94         void *buffer;
   95         void *in;
   96         int err;
   97         int i;
   98 
   99         in = kzalloc(sz, GFP_KERNEL);
  100         if (!in)
  101                 return -ENOMEM;
  102 
  103         err = mlx5e_port_query_pbmc(mdev, in);
  104         if (err)
  105                 goto out;
  106 
  107         for (i = 0; i < MLX5E_MAX_BUFFER; i++) {
  108                 buffer = MLX5_ADDR_OF(pbmc_reg, in, buffer[i]);
  109 
  110                 MLX5_SET(bufferx_reg, buffer, size,
  111                          port_buffer->buffer[i].size >> MLX5E_BUFFER_CELL_SHIFT);
  112                 MLX5_SET(bufferx_reg, buffer, lossy,
  113                          port_buffer->buffer[i].lossy);
  114                 MLX5_SET(bufferx_reg, buffer, xoff_threshold,
  115                          port_buffer->buffer[i].xoff >> MLX5E_BUFFER_CELL_SHIFT);
  116                 MLX5_SET(bufferx_reg, buffer, xon_threshold,
  117                          port_buffer->buffer[i].xon >> MLX5E_BUFFER_CELL_SHIFT);
  118         }
  119 
  120         err = mlx5e_port_set_pbmc(mdev, in);
  121 out:
  122         kfree(in);
  123         return err;
  124 }
  125 
  126 /* xoff = ((301+2.16 * len [m]) * speed [Gbps] + 2.72 MTU [B]) */
  127 static u32 calculate_xoff(struct mlx5e_priv *priv, unsigned int mtu)
  128 {
  129         u32 speed;
  130         u32 xoff;
  131         int err;
  132 
  133         err = mlx5e_port_linkspeed(priv->mdev, &speed);
  134         if (err) {
  135                 mlx5_core_warn(priv->mdev, "cannot get port speed\n");
  136                 speed = SPEED_40000;
  137         }
  138         speed = max_t(u32, speed, SPEED_40000);
  139         xoff = (301 + 216 * priv->dcbx.cable_len / 100) * speed / 1000 + 272 * mtu / 100;
  140 
  141         mlx5e_dbg(HW, priv, "%s: xoff=%d\n", __func__, xoff);
  142         return xoff;
  143 }
  144 
  145 static int update_xoff_threshold(struct mlx5e_priv *priv,
  146     struct mlx5e_port_buffer *port_buffer, u32 xoff)
  147 {
  148         int i;
  149 
  150         for (i = 0; i < MLX5E_MAX_BUFFER; i++) {
  151                 if (port_buffer->buffer[i].lossy) {
  152                         port_buffer->buffer[i].xoff = 0;
  153                         port_buffer->buffer[i].xon  = 0;
  154                         continue;
  155                 }
  156 
  157                 if (port_buffer->buffer[i].size <
  158                     (xoff + MLX5E_MAX_PORT_MTU + (1 << MLX5E_BUFFER_CELL_SHIFT))) {
  159                         mlx5_en_info(priv->ifp,
  160         "non-lossy buffer %d size %d less than xoff threshold %d\n",
  161                             i, port_buffer->buffer[i].size,
  162                             xoff + MLX5E_MAX_PORT_MTU +
  163                             (1 << MLX5E_BUFFER_CELL_SHIFT));
  164                         return -ENOMEM;
  165                 }
  166 
  167                 port_buffer->buffer[i].xoff = port_buffer->buffer[i].size - xoff;
  168                 port_buffer->buffer[i].xon  = 
  169                         port_buffer->buffer[i].xoff - MLX5E_MAX_PORT_MTU;
  170         }
  171 
  172         return 0;
  173 }
  174 
  175 /**
  176  * update_buffer_lossy()
  177  *   mtu: device's MTU
  178  *   pfc_en: <input> current pfc configuration
  179  *   buffer: <input> current prio to buffer mapping
  180  *   xoff:   <input> xoff value
  181  *   port_buffer: <output> port receive buffer configuration
  182  *   change: <output>
  183  *
  184  *   Update buffer configuration based on pfc configuration and priority
  185  *   to buffer mapping.
  186  *   Buffer's lossy bit is changed to:
  187  *     lossless if there is at least one PFC enabled priority mapped to this buffer
  188  *     lossy if all priorities mapped to this buffer are PFC disabled
  189  *
  190  *   Return:
  191  *     Return 0 if no error.
  192  *     Set change to true if buffer configuration is modified.
  193  */
  194 static int update_buffer_lossy(struct mlx5e_priv *priv, unsigned int mtu,
  195                                u8 pfc_en, u8 *buffer, u32 xoff,
  196                                struct mlx5e_port_buffer *port_buffer,
  197                                bool *change)
  198 {
  199         bool changed = false;
  200         u8 lossy_count;
  201         u8 prio_count;
  202         u8 lossy;
  203         int prio;
  204         int err;
  205         int i;
  206 
  207         for (i = 0; i < MLX5E_MAX_BUFFER; i++) {
  208                 prio_count = 0;
  209                 lossy_count = 0;
  210 
  211                 for (prio = 0; prio < MLX5E_MAX_PRIORITY; prio++) {
  212                         if (buffer[prio] != i)
  213                                 continue;
  214 
  215                         prio_count++;
  216                         lossy_count += !(pfc_en & (1 << prio));
  217                 }
  218 
  219                 if (lossy_count == prio_count)
  220                         lossy = 1;
  221                 else /* lossy_count < prio_count */
  222                         lossy = 0;
  223 
  224                 if (lossy != port_buffer->buffer[i].lossy) {
  225                         port_buffer->buffer[i].lossy = lossy;
  226                         changed = true;
  227                 }
  228         }
  229 
  230         if (changed) {
  231                 err = update_xoff_threshold(priv, port_buffer, xoff);
  232                 if (err)
  233                         return err;
  234 
  235                 *change = true;
  236         }
  237 
  238         return 0;
  239 }
  240 
  241 int mlx5e_port_manual_buffer_config(struct mlx5e_priv *priv,
  242                                     u32 change, unsigned int mtu,
  243                                     struct ieee_pfc *pfc,
  244                                     u32 *buffer_size,
  245                                     u8 *prio2buffer)
  246 {
  247         struct mlx5e_port_buffer port_buffer;
  248         u32 xoff = calculate_xoff(priv, mtu);
  249         bool update_prio2buffer = false;
  250         u8 buffer[MLX5E_MAX_PRIORITY];
  251         bool update_buffer = false;
  252         u32 total_used = 0;
  253         u8 curr_pfc_en;
  254         int err;
  255         int i;
  256 
  257         mlx5e_dbg(HW, priv, "%s: change=%x\n", __func__, change);
  258 
  259         err = mlx5e_port_query_buffer(priv, &port_buffer);
  260         if (err)
  261                 return err;
  262 
  263         if (change & MLX5E_PORT_BUFFER_CABLE_LEN) {
  264                 update_buffer = true;
  265                 err = update_xoff_threshold(priv, &port_buffer, xoff);
  266                 if (err)
  267                         return err;
  268         }
  269 
  270         if (change & MLX5E_PORT_BUFFER_PFC) {
  271                 err = mlx5e_port_query_priority2buffer(priv->mdev, buffer);
  272                 if (err)
  273                         return err;
  274 
  275                 priv->sw_is_port_buf_owner = true;
  276                 err = update_buffer_lossy(priv, mtu, pfc->pfc_en, buffer, xoff,
  277                                           &port_buffer, &update_buffer);
  278                 if (err)
  279                         return err;
  280         }
  281 
  282         if (change & MLX5E_PORT_BUFFER_PRIO2BUFFER) {
  283                 update_prio2buffer = true;
  284                 err = mlx5_query_port_pfc(priv->mdev, &curr_pfc_en, NULL);
  285                 if (err)
  286                         return err;
  287 
  288                 err = update_buffer_lossy(priv, mtu, curr_pfc_en, prio2buffer, xoff,
  289                                           &port_buffer, &update_buffer);
  290                 if (err)
  291                         return err;
  292         }
  293 
  294         if (change & MLX5E_PORT_BUFFER_SIZE) {
  295                 for (i = 0; i < MLX5E_MAX_BUFFER; i++) {
  296                         mlx5e_dbg(HW, priv, "%s: buffer[%d]=%d\n", __func__, i, buffer_size[i]);
  297                         if (!port_buffer.buffer[i].lossy && !buffer_size[i]) {
  298                                 mlx5e_dbg(HW, priv, "%s: lossless buffer[%d] size cannot be zero\n",
  299                                           __func__, i);
  300                                 return -EINVAL;
  301                         }
  302 
  303                         port_buffer.buffer[i].size = buffer_size[i];
  304                         total_used += buffer_size[i];
  305                 }
  306 
  307                 mlx5e_dbg(HW, priv, "%s: total buffer requested=%d\n", __func__, total_used);
  308 
  309                 if (total_used > port_buffer.port_buffer_size)
  310                         return -EINVAL;
  311 
  312                 update_buffer = true;
  313                 err = update_xoff_threshold(priv, &port_buffer, xoff);
  314                 if (err)
  315                         return err;
  316         }
  317 
  318         /* Need to update buffer configuration if xoff value is changed */
  319         if (!update_buffer && xoff != priv->dcbx.xoff) {
  320                 update_buffer = true;
  321                 err = update_xoff_threshold(priv, &port_buffer, xoff);
  322                 if (err)
  323                         return err;
  324         }
  325         priv->dcbx.xoff = xoff;
  326 
  327         /* Apply the settings */
  328         if (update_buffer) {
  329                 priv->sw_is_port_buf_owner = true;
  330                 err = port_set_buffer(priv, &port_buffer);
  331                 if (err)
  332                         return err;
  333         }
  334 
  335         if (update_prio2buffer) {
  336                 priv->sw_is_port_buf_owner = true;
  337                 err = mlx5e_port_set_priority2buffer(priv->mdev, prio2buffer);
  338         }
  339 
  340         return err;
  341 }

Cache object: 3e4ea905e5e13e0799e1bc9c3feb05c3


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.