File Index
Files and directories
Sign in
FILE

mpfs.c

File preview with syntax highlighting.

linux-6.19.14/drivers/net/ethernet/mellanox/mlx5/core/lib/mpfs.c 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.