xref: /freebsd/sys/dev/mlx5/mlx5_core/mlx5_rl.c (revision bf43f981)
138535d6cSHans Petter Selasky /*-
238535d6cSHans Petter Selasky  * Copyright (c) 2013-2017, Mellanox Technologies, Ltd.  All rights reserved.
338535d6cSHans Petter Selasky  *
438535d6cSHans Petter Selasky  * Redistribution and use in source and binary forms, with or without
538535d6cSHans Petter Selasky  * modification, are permitted provided that the following conditions
638535d6cSHans Petter Selasky  * are met:
738535d6cSHans Petter Selasky  * 1. Redistributions of source code must retain the above copyright
838535d6cSHans Petter Selasky  *    notice, this list of conditions and the following disclaimer.
938535d6cSHans Petter Selasky  * 2. Redistributions in binary form must reproduce the above copyright
1038535d6cSHans Petter Selasky  *    notice, this list of conditions and the following disclaimer in the
1138535d6cSHans Petter Selasky  *    documentation and/or other materials provided with the distribution.
1238535d6cSHans Petter Selasky  *
1338535d6cSHans Petter Selasky  * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS `AS IS' AND
1438535d6cSHans Petter Selasky  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1538535d6cSHans Petter Selasky  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1638535d6cSHans Petter Selasky  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
1738535d6cSHans Petter Selasky  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1838535d6cSHans Petter Selasky  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
1938535d6cSHans Petter Selasky  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2038535d6cSHans Petter Selasky  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2138535d6cSHans Petter Selasky  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2238535d6cSHans Petter Selasky  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2338535d6cSHans Petter Selasky  * SUCH DAMAGE.
2438535d6cSHans Petter Selasky  *
2538535d6cSHans Petter Selasky  * $FreeBSD$
2638535d6cSHans Petter Selasky  */
2738535d6cSHans Petter Selasky 
2838535d6cSHans Petter Selasky #include <linux/kernel.h>
2938535d6cSHans Petter Selasky #include <linux/module.h>
3038535d6cSHans Petter Selasky #include <dev/mlx5/driver.h>
3138535d6cSHans Petter Selasky #include "mlx5_core.h"
3238535d6cSHans Petter Selasky 
3338535d6cSHans Petter Selasky #ifdef RATELIMIT
3438535d6cSHans Petter Selasky 
3538535d6cSHans Petter Selasky /* Finds an entry where we can register the given rate
3638535d6cSHans Petter Selasky  * If the rate already exists, return the entry where it is registered,
3738535d6cSHans Petter Selasky  * otherwise return the first available entry.
3838535d6cSHans Petter Selasky  * If the table is full, return NULL
3938535d6cSHans Petter Selasky  */
4038535d6cSHans Petter Selasky static struct mlx5_rl_entry *find_rl_entry(struct mlx5_rl_table *table,
4138535d6cSHans Petter Selasky 					   u32 rate, u16 burst)
4238535d6cSHans Petter Selasky {
4338535d6cSHans Petter Selasky 	struct mlx5_rl_entry *ret_entry = NULL;
4438535d6cSHans Petter Selasky 	struct mlx5_rl_entry *entry;
4538535d6cSHans Petter Selasky 	u16 i;
4638535d6cSHans Petter Selasky 
4738535d6cSHans Petter Selasky 	for (i = 0; i < table->max_size; i++) {
4838535d6cSHans Petter Selasky 		entry = table->rl_entry + i;
4938535d6cSHans Petter Selasky 		if (entry->rate == rate && entry->burst == burst)
5038535d6cSHans Petter Selasky 			return entry;
5138535d6cSHans Petter Selasky 		if (ret_entry == NULL && entry->rate == 0)
5238535d6cSHans Petter Selasky 			ret_entry = entry;
5338535d6cSHans Petter Selasky 	}
5438535d6cSHans Petter Selasky 
5538535d6cSHans Petter Selasky 	return ret_entry;
5638535d6cSHans Petter Selasky }
5738535d6cSHans Petter Selasky 
5838535d6cSHans Petter Selasky static int mlx5_set_rate_limit_cmd(struct mlx5_core_dev *dev,
5938535d6cSHans Petter Selasky 				   u32 rate, u32 burst, u16 index)
6038535d6cSHans Petter Selasky {
61bf43f981SHans Petter Selasky 	u32 in[MLX5_ST_SZ_DW(set_rate_limit_in)] = {};
62bf43f981SHans Petter Selasky 	u32 out[MLX5_ST_SZ_DW(set_rate_limit_out)] = {};
6338535d6cSHans Petter Selasky 
64bf43f981SHans Petter Selasky 	MLX5_SET(set_rate_limit_in, in, opcode, MLX5_CMD_OP_SET_RATE_LIMIT);
6538535d6cSHans Petter Selasky 	MLX5_SET(set_rate_limit_in, in, rate_limit_index, index);
6638535d6cSHans Petter Selasky 	MLX5_SET(set_rate_limit_in, in, rate_limit, rate);
6738535d6cSHans Petter Selasky 	MLX5_SET(set_rate_limit_in, in, burst_upper_bound, burst);
68bf43f981SHans Petter Selasky 	MLX5_SET(set_rate_limit_in, in, typical_packet_size, 0 /* use MTU */);
6938535d6cSHans Petter Selasky 
7038535d6cSHans Petter Selasky 	return mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
7138535d6cSHans Petter Selasky }
7238535d6cSHans Petter Selasky 
7338535d6cSHans Petter Selasky bool mlx5_rl_is_in_range(const struct mlx5_core_dev *dev, u32 rate, u32 burst)
7438535d6cSHans Petter Selasky {
7538535d6cSHans Petter Selasky 	const struct mlx5_rl_table *table = &dev->priv.rl_table;
7638535d6cSHans Petter Selasky 
7738535d6cSHans Petter Selasky 	return (rate <= table->max_rate && rate >= table->min_rate &&
7838535d6cSHans Petter Selasky 		burst <= 65535);
7938535d6cSHans Petter Selasky }
8038535d6cSHans Petter Selasky EXPORT_SYMBOL(mlx5_rl_is_in_range);
8138535d6cSHans Petter Selasky 
8238535d6cSHans Petter Selasky int mlx5_rl_add_rate(struct mlx5_core_dev *dev, u32 rate, u32 burst, u16 *index)
8338535d6cSHans Petter Selasky {
8438535d6cSHans Petter Selasky 	struct mlx5_rl_table *table = &dev->priv.rl_table;
8538535d6cSHans Petter Selasky 	struct mlx5_rl_entry *entry;
8638535d6cSHans Petter Selasky 	int err = 0;
8738535d6cSHans Petter Selasky 
8838535d6cSHans Petter Selasky 	mutex_lock(&table->rl_lock);
8938535d6cSHans Petter Selasky 
9038535d6cSHans Petter Selasky 	if (!rate || !mlx5_rl_is_in_range(dev, rate, burst)) {
9138535d6cSHans Petter Selasky 		mlx5_core_err(dev, "Invalid rate: %u, should be %u to %u\n",
9238535d6cSHans Petter Selasky 			      rate, table->min_rate, table->max_rate);
9338535d6cSHans Petter Selasky 		err = -ERANGE;
9438535d6cSHans Petter Selasky 		goto out;
9538535d6cSHans Petter Selasky 	}
9638535d6cSHans Petter Selasky 
9738535d6cSHans Petter Selasky 	entry = find_rl_entry(table, rate, burst);
9838535d6cSHans Petter Selasky 	if (!entry) {
9938535d6cSHans Petter Selasky 		mlx5_core_err(dev, "Max number of %u rates reached\n",
10038535d6cSHans Petter Selasky 			      table->max_size);
10138535d6cSHans Petter Selasky 		err = -ENOSPC;
10238535d6cSHans Petter Selasky 		goto out;
10338535d6cSHans Petter Selasky 	}
10438535d6cSHans Petter Selasky 	if (entry->refcount == 0xFFFFFFFFU) {
10538535d6cSHans Petter Selasky 		/* out of refcounts */
10638535d6cSHans Petter Selasky 		err = -ENOMEM;
10738535d6cSHans Petter Selasky 		goto out;
10838535d6cSHans Petter Selasky 	} else if (entry->refcount != 0) {
10938535d6cSHans Petter Selasky 		/* rate already configured */
11038535d6cSHans Petter Selasky 		entry->refcount++;
11138535d6cSHans Petter Selasky 	} else {
11238535d6cSHans Petter Selasky 		/* new rate limit */
11338535d6cSHans Petter Selasky 		err = mlx5_set_rate_limit_cmd(dev, rate, burst, entry->index);
11438535d6cSHans Petter Selasky 		if (err) {
11538535d6cSHans Petter Selasky 			mlx5_core_err(dev, "Failed configuring rate: %u (%d)\n",
11638535d6cSHans Petter Selasky 				      rate, err);
11738535d6cSHans Petter Selasky 			goto out;
11838535d6cSHans Petter Selasky 		}
11938535d6cSHans Petter Selasky 		entry->rate = rate;
12038535d6cSHans Petter Selasky 		entry->burst = burst;
12138535d6cSHans Petter Selasky 		entry->refcount = 1;
12238535d6cSHans Petter Selasky 	}
12338535d6cSHans Petter Selasky 	*index = entry->index;
12438535d6cSHans Petter Selasky 
12538535d6cSHans Petter Selasky out:
12638535d6cSHans Petter Selasky 	mutex_unlock(&table->rl_lock);
12738535d6cSHans Petter Selasky 	return err;
12838535d6cSHans Petter Selasky }
12938535d6cSHans Petter Selasky EXPORT_SYMBOL(mlx5_rl_add_rate);
13038535d6cSHans Petter Selasky 
13138535d6cSHans Petter Selasky void mlx5_rl_remove_rate(struct mlx5_core_dev *dev, u32 rate, u32 burst)
13238535d6cSHans Petter Selasky {
13338535d6cSHans Petter Selasky 	struct mlx5_rl_table *table = &dev->priv.rl_table;
13438535d6cSHans Petter Selasky 	struct mlx5_rl_entry *entry = NULL;
13538535d6cSHans Petter Selasky 
13638535d6cSHans Petter Selasky 	/* 0 is a reserved value for unlimited rate */
13738535d6cSHans Petter Selasky 	if (rate == 0)
13838535d6cSHans Petter Selasky 		return;
13938535d6cSHans Petter Selasky 
14038535d6cSHans Petter Selasky 	mutex_lock(&table->rl_lock);
14138535d6cSHans Petter Selasky 	entry = find_rl_entry(table, rate, burst);
14238535d6cSHans Petter Selasky 	if (!entry || !entry->refcount) {
14338535d6cSHans Petter Selasky 		mlx5_core_warn(dev, "Rate %u is not configured\n", rate);
14438535d6cSHans Petter Selasky 		goto out;
14538535d6cSHans Petter Selasky 	}
14638535d6cSHans Petter Selasky 
14738535d6cSHans Petter Selasky 	entry->refcount--;
14838535d6cSHans Petter Selasky 	if (!entry->refcount) {
14938535d6cSHans Petter Selasky 		/* need to remove rate */
15038535d6cSHans Petter Selasky 		mlx5_set_rate_limit_cmd(dev, 0, 0, entry->index);
15138535d6cSHans Petter Selasky 		entry->rate = 0;
15238535d6cSHans Petter Selasky 		entry->burst = 0;
15338535d6cSHans Petter Selasky 	}
15438535d6cSHans Petter Selasky 
15538535d6cSHans Petter Selasky out:
15638535d6cSHans Petter Selasky 	mutex_unlock(&table->rl_lock);
15738535d6cSHans Petter Selasky }
15838535d6cSHans Petter Selasky EXPORT_SYMBOL(mlx5_rl_remove_rate);
15938535d6cSHans Petter Selasky 
16038535d6cSHans Petter Selasky int mlx5_init_rl_table(struct mlx5_core_dev *dev)
16138535d6cSHans Petter Selasky {
16238535d6cSHans Petter Selasky 	struct mlx5_rl_table *table = &dev->priv.rl_table;
16338535d6cSHans Petter Selasky 	int i;
16438535d6cSHans Petter Selasky 
16538535d6cSHans Petter Selasky 	mutex_init(&table->rl_lock);
16638535d6cSHans Petter Selasky 	if (!MLX5_CAP_GEN(dev, qos) || !MLX5_CAP_QOS(dev, packet_pacing)) {
16738535d6cSHans Petter Selasky 		table->max_size = 0;
16838535d6cSHans Petter Selasky 		return 0;
16938535d6cSHans Petter Selasky 	}
17038535d6cSHans Petter Selasky 
17138535d6cSHans Petter Selasky 	/* First entry is reserved for unlimited rate */
17238535d6cSHans Petter Selasky 	table->max_size = MLX5_CAP_QOS(dev, packet_pacing_rate_table_size) - 1;
17338535d6cSHans Petter Selasky 	table->max_rate = MLX5_CAP_QOS(dev, packet_pacing_max_rate);
17438535d6cSHans Petter Selasky 	table->min_rate = MLX5_CAP_QOS(dev, packet_pacing_min_rate);
17538535d6cSHans Petter Selasky 
17638535d6cSHans Petter Selasky 	table->rl_entry = kcalloc(table->max_size, sizeof(struct mlx5_rl_entry),
17738535d6cSHans Petter Selasky 				  GFP_KERNEL);
17838535d6cSHans Petter Selasky 	if (!table->rl_entry)
17938535d6cSHans Petter Selasky 		return -ENOMEM;
18038535d6cSHans Petter Selasky 
18138535d6cSHans Petter Selasky 	/* The index represents the index in HW rate limit table
18238535d6cSHans Petter Selasky 	 * Index 0 is reserved for unlimited rate
18338535d6cSHans Petter Selasky 	 */
18438535d6cSHans Petter Selasky 	for (i = 0; i < table->max_size; i++)
18538535d6cSHans Petter Selasky 		table->rl_entry[i].index = i + 1;
18638535d6cSHans Petter Selasky 
18738535d6cSHans Petter Selasky 	return 0;
18838535d6cSHans Petter Selasky }
18938535d6cSHans Petter Selasky 
19038535d6cSHans Petter Selasky void mlx5_cleanup_rl_table(struct mlx5_core_dev *dev)
19138535d6cSHans Petter Selasky {
19238535d6cSHans Petter Selasky 	struct mlx5_rl_table *table = &dev->priv.rl_table;
19338535d6cSHans Petter Selasky 	int i;
19438535d6cSHans Petter Selasky 
19538535d6cSHans Petter Selasky 	/* Clear all configured rates */
19638535d6cSHans Petter Selasky 	for (i = 0; i < table->max_size; i++)
19738535d6cSHans Petter Selasky 		if (table->rl_entry[i].rate)
19838535d6cSHans Petter Selasky 			mlx5_set_rate_limit_cmd(dev, 0, 0,
19938535d6cSHans Petter Selasky 						table->rl_entry[i].index);
20038535d6cSHans Petter Selasky 
20138535d6cSHans Petter Selasky 	kfree(dev->priv.rl_table.rl_entry);
20238535d6cSHans Petter Selasky }
20338535d6cSHans Petter Selasky 
20438535d6cSHans Petter Selasky #endif
205