linux/drivers/net/ethernet/mellanox/mlx5/core/lib/port_tun.c
<<
>>
Prefs
   1/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */
   2/* Copyright (c) 2019 Mellanox Technologies. */
   3
   4#include <linux/module.h>
   5#include <linux/mlx5/driver.h>
   6#include <linux/mlx5/port.h>
   7#include "mlx5_core.h"
   8#include "lib/port_tun.h"
   9
  10struct mlx5_port_tun_entropy_flags {
  11        bool force_supported, force_enabled;
  12        bool calc_supported, calc_enabled;
  13        bool gre_calc_supported, gre_calc_enabled;
  14};
  15
  16static void mlx5_query_port_tun_entropy(struct mlx5_core_dev *mdev,
  17                                        struct mlx5_port_tun_entropy_flags *entropy_flags)
  18{
  19        u32 out[MLX5_ST_SZ_DW(pcmr_reg)];
  20        /* Default values for FW which do not support MLX5_REG_PCMR */
  21        entropy_flags->force_supported = false;
  22        entropy_flags->calc_supported = false;
  23        entropy_flags->gre_calc_supported = false;
  24        entropy_flags->force_enabled = false;
  25        entropy_flags->calc_enabled = true;
  26        entropy_flags->gre_calc_enabled = true;
  27
  28        if (!MLX5_CAP_GEN(mdev, ports_check))
  29                return;
  30
  31        if (mlx5_query_ports_check(mdev, out, sizeof(out)))
  32                return;
  33
  34        entropy_flags->force_supported = !!(MLX5_GET(pcmr_reg, out, entropy_force_cap));
  35        entropy_flags->calc_supported = !!(MLX5_GET(pcmr_reg, out, entropy_calc_cap));
  36        entropy_flags->gre_calc_supported = !!(MLX5_GET(pcmr_reg, out, entropy_gre_calc_cap));
  37        entropy_flags->force_enabled = !!(MLX5_GET(pcmr_reg, out, entropy_force));
  38        entropy_flags->calc_enabled = !!(MLX5_GET(pcmr_reg, out, entropy_calc));
  39        entropy_flags->gre_calc_enabled = !!(MLX5_GET(pcmr_reg, out, entropy_gre_calc));
  40}
  41
  42static int mlx5_set_port_tun_entropy_calc(struct mlx5_core_dev *mdev, u8 enable,
  43                                          u8 force)
  44{
  45        u32 in[MLX5_ST_SZ_DW(pcmr_reg)] = {0};
  46        int err;
  47
  48        err = mlx5_query_ports_check(mdev, in, sizeof(in));
  49        if (err)
  50                return err;
  51        MLX5_SET(pcmr_reg, in, local_port, 1);
  52        MLX5_SET(pcmr_reg, in, entropy_force, force);
  53        MLX5_SET(pcmr_reg, in, entropy_calc, enable);
  54        return mlx5_set_ports_check(mdev, in, sizeof(in));
  55}
  56
  57static int mlx5_set_port_gre_tun_entropy_calc(struct mlx5_core_dev *mdev,
  58                                              u8 enable, u8 force)
  59{
  60        u32 in[MLX5_ST_SZ_DW(pcmr_reg)] = {0};
  61        int err;
  62
  63        err = mlx5_query_ports_check(mdev, in, sizeof(in));
  64        if (err)
  65                return err;
  66        MLX5_SET(pcmr_reg, in, local_port, 1);
  67        MLX5_SET(pcmr_reg, in, entropy_force, force);
  68        MLX5_SET(pcmr_reg, in, entropy_gre_calc, enable);
  69        return mlx5_set_ports_check(mdev, in, sizeof(in));
  70}
  71
  72void mlx5_init_port_tun_entropy(struct mlx5_tun_entropy *tun_entropy,
  73                                struct mlx5_core_dev *mdev)
  74{
  75        struct mlx5_port_tun_entropy_flags entropy_flags;
  76
  77        tun_entropy->mdev = mdev;
  78        mutex_init(&tun_entropy->lock);
  79        mlx5_query_port_tun_entropy(mdev, &entropy_flags);
  80        tun_entropy->num_enabling_entries = 0;
  81        tun_entropy->num_disabling_entries = 0;
  82        tun_entropy->enabled = entropy_flags.calc_supported ?
  83                               entropy_flags.calc_enabled : true;
  84}
  85
  86static int mlx5_set_entropy(struct mlx5_tun_entropy *tun_entropy,
  87                            int reformat_type, bool enable)
  88{
  89        struct mlx5_port_tun_entropy_flags entropy_flags;
  90        int err;
  91
  92        mlx5_query_port_tun_entropy(tun_entropy->mdev, &entropy_flags);
  93        /* Tunnel entropy calculation may be controlled either on port basis
  94         * for all tunneling protocols or specifically for GRE protocol.
  95         * Prioritize GRE protocol control (if capable) over global port
  96         * configuration.
  97         */
  98        if (entropy_flags.gre_calc_supported &&
  99            reformat_type == MLX5_REFORMAT_TYPE_L2_TO_NVGRE) {
 100                if (!entropy_flags.force_supported)
 101                        return 0;
 102                err = mlx5_set_port_gre_tun_entropy_calc(tun_entropy->mdev,
 103                                                         enable, !enable);
 104                if (err)
 105                        return err;
 106        } else if (entropy_flags.calc_supported) {
 107                /* Other applications may change the global FW entropy
 108                 * calculations settings. Check that the current entropy value
 109                 * is the negative of the updated value.
 110                 */
 111                if (entropy_flags.force_enabled &&
 112                    enable == entropy_flags.calc_enabled) {
 113                        mlx5_core_warn(tun_entropy->mdev,
 114                                       "Unexpected entropy calc setting - expected %d",
 115                                       !entropy_flags.calc_enabled);
 116                        return -EOPNOTSUPP;
 117                }
 118                /* GRE requires disabling entropy calculation. if there are
 119                 * enabling entries (i.e VXLAN) we cannot turn it off for them,
 120                 * thus fail.
 121                 */
 122                if (tun_entropy->num_enabling_entries)
 123                        return -EOPNOTSUPP;
 124                err = mlx5_set_port_tun_entropy_calc(tun_entropy->mdev, enable,
 125                                                     entropy_flags.force_supported);
 126                if (err)
 127                        return err;
 128                tun_entropy->enabled = enable;
 129                /* if we turn on the entropy we don't need to force it anymore */
 130                if (entropy_flags.force_supported && enable) {
 131                        err = mlx5_set_port_tun_entropy_calc(tun_entropy->mdev, 1, 0);
 132                        if (err)
 133                                return err;
 134                }
 135        }
 136
 137        return 0;
 138}
 139
 140/* the function manages the refcount for enabling/disabling tunnel types.
 141 * the return value indicates if the inc is successful or not, depending on
 142 * entropy capabilities and configuration.
 143 */
 144int mlx5_tun_entropy_refcount_inc(struct mlx5_tun_entropy *tun_entropy,
 145                                  int reformat_type)
 146{
 147        int err = -EOPNOTSUPP;
 148
 149        mutex_lock(&tun_entropy->lock);
 150        if ((reformat_type == MLX5_REFORMAT_TYPE_L2_TO_VXLAN ||
 151             reformat_type == MLX5_REFORMAT_TYPE_L2_TO_L3_TUNNEL) &&
 152            tun_entropy->enabled) {
 153                /* in case entropy calculation is enabled for all tunneling
 154                 * types, it is ok for VXLAN, so approve.
 155                 * otherwise keep the error default.
 156                 */
 157                tun_entropy->num_enabling_entries++;
 158                err = 0;
 159        } else if (reformat_type == MLX5_REFORMAT_TYPE_L2_TO_NVGRE) {
 160                /* turn off the entropy only for the first GRE rule.
 161                 * for the next rules the entropy was already disabled
 162                 * successfully.
 163                 */
 164                if (tun_entropy->num_disabling_entries == 0)
 165                        err = mlx5_set_entropy(tun_entropy, reformat_type, 0);
 166                else
 167                        err = 0;
 168                if (!err)
 169                        tun_entropy->num_disabling_entries++;
 170        }
 171        mutex_unlock(&tun_entropy->lock);
 172
 173        return err;
 174}
 175
 176void mlx5_tun_entropy_refcount_dec(struct mlx5_tun_entropy *tun_entropy,
 177                                   int reformat_type)
 178{
 179        mutex_lock(&tun_entropy->lock);
 180        if (reformat_type == MLX5_REFORMAT_TYPE_L2_TO_VXLAN)
 181                tun_entropy->num_enabling_entries--;
 182        else if (reformat_type == MLX5_REFORMAT_TYPE_L2_TO_NVGRE &&
 183                 --tun_entropy->num_disabling_entries == 0)
 184                mlx5_set_entropy(tun_entropy, reformat_type, 1);
 185        mutex_unlock(&tun_entropy->lock);
 186}
 187
 188