FILE
mpfs.c
File preview with syntax highlighting.
linux-6.19.14/drivers/net/ethernet/mellanox/mlx5/core/lib/mpfs.c
1/* 2 * Copyright (c) 2017, Mellanox Technologies. All rights reserved. 3 * 4 * This software is available to you under a choice of one of two 5 * licenses. You may choose to be licensed under the terms of the GNU 6 * General Public License (GPL) Version 2, available from the file 7 * COPYING in the main directory of this source tree, or the 8 * OpenIB.org BSD license below: 9 * 10 * Redistribution and use in source and binary forms, with or 11 * without modification, are permitted provided that the following 12 * conditions are met: 13 * 14 * - Redistributions of source code must retain the above 15 * copyright notice, this list of conditions and the following 16 * disclaimer. 17 * 18 * - Redistributions in binary form must reproduce the above 19 * copyright notice, this list of conditions and the following 20 * disclaimer in the documentation and/or other materials 21 * provided with the distribution. 22 * 23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 24 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 25 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 27 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 28 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30 * SOFTWARE. 31 */ 32 33#include <linux/etherdevice.h> 34#include <linux/mlx5/driver.h> 35#include <linux/mlx5/mlx5_ifc.h> 36#include <linux/mlx5/mpfs.h> 37#include <linux/mlx5/eswitch.h> 38#include "mlx5_core.h" 39#include "lib/mpfs.h" 40 41/* HW L2 Table (MPFS) management */ 42static int set_l2table_entry_cmd(struct mlx5_core_dev *dev, u32 index, u8 *mac) 43{ 44 u32 in[MLX5_ST_SZ_DW(set_l2_table_entry_in)] = {}; 45 u8 *in_mac_addr; 46 47 MLX5_SET(set_l2_table_entry_in, in, opcode, MLX5_CMD_OP_SET_L2_TABLE_ENTRY); 48 MLX5_SET(set_l2_table_entry_in, in, table_index, index); 49 50 in_mac_addr = MLX5_ADDR_OF(set_l2_table_entry_in, in, mac_address); 51 ether_addr_copy(&in_mac_addr[2], mac); 52 53 return mlx5_cmd_exec_in(dev, set_l2_table_entry, in); 54} 55 56static int del_l2table_entry_cmd(struct mlx5_core_dev *dev, u32 index) 57{ 58 u32 in[MLX5_ST_SZ_DW(delete_l2_table_entry_in)] = {}; 59 60 MLX5_SET(delete_l2_table_entry_in, in, opcode, MLX5_CMD_OP_DELETE_L2_TABLE_ENTRY); 61 MLX5_SET(delete_l2_table_entry_in, in, table_index, index); 62 return mlx5_cmd_exec_in(dev, delete_l2_table_entry, in); 63} 64 65/* UC L2 table hash node */ 66struct l2table_node { 67 struct l2addr_node node; 68 int index; /* index in HW l2 table */ 69 int ref_count; 70}; 71 72struct mlx5_mpfs { 73 struct hlist_head hash[MLX5_L2_ADDR_HASH_SIZE]; 74 struct mutex lock; /* Synchronize l2 table access */ 75 bool enabled; 76 u32 size; 77 unsigned long *bitmap; 78}; 79 80static int alloc_l2table_index(struct mlx5_mpfs *l2table, u32 *ix) 81{ 82 int err = 0; 83 84 *ix = find_first_zero_bit(l2table->bitmap, l2table->size); 85 if (*ix >= l2table->size) 86 err = -ENOSPC; 87 else 88 __set_bit(*ix, l2table->bitmap); 89 90 return err; 91} 92 93static void free_l2table_index(struct mlx5_mpfs *l2table, u32 ix) 94{ 95 __clear_bit(ix, l2table->bitmap); 96} 97 98int mlx5_mpfs_init(struct mlx5_core_dev *dev) 99{ 100 int l2table_size = 1 << MLX5_CAP_GEN(dev, log_max_l2_table); 101 struct mlx5_mpfs *mpfs; 102 103 if (!MLX5_ESWITCH_MANAGER(dev) || l2table_size == 1) 104 return 0; 105 106 mpfs = kzalloc(sizeof(*mpfs), GFP_KERNEL); 107 if (!mpfs) 108 return -ENOMEM; 109 110 mutex_init(&mpfs->lock); 111 mpfs->size = l2table_size; 112 mpfs->bitmap = bitmap_zalloc(l2table_size, GFP_KERNEL); 113 if (!mpfs->bitmap) { 114 kfree(mpfs); 115 return -ENOMEM; 116 } 117 118 mpfs->enabled = true; 119 120 dev->priv.mpfs = mpfs; 121 return 0; 122} 123 124void mlx5_mpfs_cleanup(struct mlx5_core_dev *dev) 125{ 126 struct mlx5_mpfs *mpfs = dev->priv.mpfs; 127 128 if (!mpfs) 129 return; 130 131 WARN_ON(!hlist_empty(mpfs->hash)); 132 bitmap_free(mpfs->bitmap); 133 kfree(mpfs); 134} 135 136int mlx5_mpfs_add_mac(struct mlx5_core_dev *dev, u8 *mac) 137{ 138 struct mlx5_mpfs *mpfs = dev->priv.mpfs; 139 struct l2table_node *l2addr; 140 int err = 0; 141 int index; 142 143 if (!mpfs) 144 return 0; 145 146 mutex_lock(&mpfs->lock); 147 148 l2addr = l2addr_hash_find(mpfs->hash, mac, struct l2table_node); 149 if (l2addr) { 150 l2addr->ref_count++; 151 goto out; 152 } 153 154 l2addr = l2addr_hash_add(mpfs->hash, mac, struct l2table_node, GFP_KERNEL); 155 if (!l2addr) { 156 err = -ENOMEM; 157 goto out; 158 } 159 160 index = -1; 161 162 if (mpfs->enabled) { 163 err = alloc_l2table_index(mpfs, &index); 164 if (err) 165 goto hash_del; 166 err = set_l2table_entry_cmd(dev, index, mac); 167 if (err) 168 goto free_l2table_index; 169 mlx5_core_dbg(dev, "MPFS entry %pM, set @index (%d)\n", 170 l2addr->node.addr, index); 171 } 172 173 l2addr->index = index; 174 l2addr->ref_count = 1; 175 176 mlx5_core_dbg(dev, "MPFS mac added %pM, index (%d)\n", mac, index); 177 goto out; 178free_l2table_index: 179 free_l2table_index(mpfs, index); 180hash_del: 181 l2addr_hash_del(l2addr); 182out: 183 mutex_unlock(&mpfs->lock); 184 return err; 185} 186EXPORT_SYMBOL(mlx5_mpfs_add_mac); 187 188int mlx5_mpfs_del_mac(struct mlx5_core_dev *dev, u8 *mac) 189{ 190 struct mlx5_mpfs *mpfs = dev->priv.mpfs; 191 struct l2table_node *l2addr; 192 int err = 0; 193 int index; 194 195 if (!mpfs) 196 return 0; 197 198 mutex_lock(&mpfs->lock); 199 200 l2addr = l2addr_hash_find(mpfs->hash, mac, struct l2table_node); 201 if (!l2addr) { 202 err = -ENOENT; 203 goto unlock; 204 } 205 206 if (--l2addr->ref_count > 0) 207 goto unlock; 208 209 index = l2addr->index; 210 if (index >= 0) { 211 del_l2table_entry_cmd(dev, index); 212 free_l2table_index(mpfs, index); 213 mlx5_core_dbg(dev, "MPFS entry %pM, deleted @index (%d)\n", 214 mac, index); 215 } 216 l2addr_hash_del(l2addr); 217 mlx5_core_dbg(dev, "MPFS mac deleted %pM, index (%d)\n", mac, index); 218unlock: 219 mutex_unlock(&mpfs->lock); 220 return err; 221} 222EXPORT_SYMBOL(mlx5_mpfs_del_mac); 223 224int mlx5_mpfs_enable(struct mlx5_core_dev *dev) 225{ 226 struct mlx5_mpfs *mpfs = dev->priv.mpfs; 227 struct l2table_node *l2addr; 228 struct hlist_node *n; 229 int err = 0, i; 230 231 if (!mpfs) 232 return -ENODEV; 233 234 mutex_lock(&mpfs->lock); 235 if (mpfs->enabled) 236 goto out; 237 mpfs->enabled = true; 238 mlx5_core_dbg(dev, "MPFS enabling mpfs\n"); 239 240 mlx5_mpfs_foreach(l2addr, n, mpfs, i) { 241 u32 index; 242 243 err = alloc_l2table_index(mpfs, &index); 244 if (err) { 245 mlx5_core_err(dev, "Failed to allocated MPFS index for %pM, err(%d)\n", 246 l2addr->node.addr, err); 247 goto out; 248 } 249 250 err = set_l2table_entry_cmd(dev, index, l2addr->node.addr); 251 if (err) { 252 mlx5_core_err(dev, "Failed to set MPFS l2table entry for %pM index=%d, err(%d)\n", 253 l2addr->node.addr, index, err); 254 free_l2table_index(mpfs, index); 255 goto out; 256 } 257 258 l2addr->index = index; 259 mlx5_core_dbg(dev, "MPFS entry %pM, set @index (%d)\n", 260 l2addr->node.addr, l2addr->index); 261 } 262out: 263 mutex_unlock(&mpfs->lock); 264 return err; 265} 266 267void mlx5_mpfs_disable(struct mlx5_core_dev *dev) 268{ 269 struct mlx5_mpfs *mpfs = dev->priv.mpfs; 270 struct l2table_node *l2addr; 271 struct hlist_node *n; 272 int i; 273 274 if (!mpfs) 275 return; 276 277 mutex_lock(&mpfs->lock); 278 if (!mpfs->enabled) 279 goto unlock; 280 mlx5_mpfs_foreach(l2addr, n, mpfs, i) { 281 if (l2addr->index < 0) 282 continue; 283 del_l2table_entry_cmd(dev, l2addr->index); 284 free_l2table_index(mpfs, l2addr->index); 285 mlx5_core_dbg(dev, "MPFS entry %pM, deleted @index (%d)\n", 286 l2addr->node.addr, l2addr->index); 287 l2addr->index = -1; 288 } 289 mpfs->enabled = false; 290 mlx5_core_dbg(dev, "MPFS disabled\n"); 291unlock: 292 mutex_unlock(&mpfs->lock); 293}
~/
Read-only file preview.