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