xref: /freebsd/sys/dev/mlx5/mlx5_core/mlx5_rl.c (revision 95ee2897)
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 
26ee9d634bSKonstantin Belousov #include "opt_rss.h"
27ee9d634bSKonstantin Belousov #include "opt_ratelimit.h"
28ee9d634bSKonstantin Belousov 
2938535d6cSHans Petter Selasky #include <linux/kernel.h>
3038535d6cSHans Petter Selasky #include <linux/module.h>
3138535d6cSHans Petter Selasky #include <dev/mlx5/driver.h>
3212c56d7dSHans Petter Selasky #include <dev/mlx5/mlx5_core/mlx5_core.h>
3338535d6cSHans Petter Selasky 
3438535d6cSHans Petter Selasky #ifdef RATELIMIT
3538535d6cSHans Petter Selasky 
3638535d6cSHans Petter Selasky /* Finds an entry where we can register the given rate
3738535d6cSHans Petter Selasky  * If the rate already exists, return the entry where it is registered,
3838535d6cSHans Petter Selasky  * otherwise return the first available entry.
3938535d6cSHans Petter Selasky  * If the table is full, return NULL
4038535d6cSHans Petter Selasky  */
find_rl_entry(struct mlx5_rl_table * table,u32 rate,u16 burst)4138535d6cSHans Petter Selasky static struct mlx5_rl_entry *find_rl_entry(struct mlx5_rl_table *table,
4238535d6cSHans Petter Selasky 					   u32 rate, u16 burst)
4338535d6cSHans Petter Selasky {
4438535d6cSHans Petter Selasky 	struct mlx5_rl_entry *ret_entry = NULL;
4538535d6cSHans Petter Selasky 	struct mlx5_rl_entry *entry;
4638535d6cSHans Petter Selasky 	u16 i;
4738535d6cSHans Petter Selasky 
4838535d6cSHans Petter Selasky 	for (i = 0; i < table->max_size; i++) {
4938535d6cSHans Petter Selasky 		entry = table->rl_entry + i;
5038535d6cSHans Petter Selasky 		if (entry->rate == rate && entry->burst == burst)
5138535d6cSHans Petter Selasky 			return entry;
5238535d6cSHans Petter Selasky 		if (ret_entry == NULL && entry->rate == 0)
5338535d6cSHans Petter Selasky 			ret_entry = entry;
5438535d6cSHans Petter Selasky 	}
5538535d6cSHans Petter Selasky 
5638535d6cSHans Petter Selasky 	return ret_entry;
5738535d6cSHans Petter Selasky }
5838535d6cSHans Petter Selasky 
mlx5_set_rate_limit_cmd(struct mlx5_core_dev * dev,u32 rate,u32 burst,u16 index)5938535d6cSHans Petter Selasky static int mlx5_set_rate_limit_cmd(struct mlx5_core_dev *dev,
6038535d6cSHans Petter Selasky 				   u32 rate, u32 burst, u16 index)
6138535d6cSHans Petter Selasky {
62bf43f981SHans Petter Selasky 	u32 in[MLX5_ST_SZ_DW(set_rate_limit_in)] = {};
63bf43f981SHans Petter Selasky 	u32 out[MLX5_ST_SZ_DW(set_rate_limit_out)] = {};
6438535d6cSHans Petter Selasky 
65bf43f981SHans Petter Selasky 	MLX5_SET(set_rate_limit_in, in, opcode, MLX5_CMD_OP_SET_RATE_LIMIT);
6638535d6cSHans Petter Selasky 	MLX5_SET(set_rate_limit_in, in, rate_limit_index, index);
6738535d6cSHans Petter Selasky 	MLX5_SET(set_rate_limit_in, in, rate_limit, rate);
6838535d6cSHans Petter Selasky 	MLX5_SET(set_rate_limit_in, in, burst_upper_bound, burst);
69bf43f981SHans Petter Selasky 	MLX5_SET(set_rate_limit_in, in, typical_packet_size, 0 /* use MTU */);
7038535d6cSHans Petter Selasky 
7138535d6cSHans Petter Selasky 	return mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
7238535d6cSHans Petter Selasky }
7338535d6cSHans Petter Selasky 
mlx5e_query_rate_limit_cmd(struct mlx5_core_dev * dev,u16 index,u32 * scq_handle)74266c81aaSHans Petter Selasky int mlx5e_query_rate_limit_cmd(struct mlx5_core_dev *dev,
75266c81aaSHans Petter Selasky 				   u16 index, u32 *scq_handle)
76266c81aaSHans Petter Selasky {
77266c81aaSHans Petter Selasky 	int err;
78266c81aaSHans Petter Selasky 	u32 in[MLX5_ST_SZ_DW(query_pp_rate_limit_in)] = {};
79266c81aaSHans Petter Selasky 	u32 out[MLX5_ST_SZ_DW(query_pp_rate_limit_out)] = {};
80266c81aaSHans Petter Selasky 
81266c81aaSHans Petter Selasky 	MLX5_SET(query_pp_rate_limit_in, in, opcode, MLX5_CMD_OP_QUERY_RATE_LIMIT);
82266c81aaSHans Petter Selasky 	MLX5_SET(query_pp_rate_limit_in, in, rate_limit_index, index);
83266c81aaSHans Petter Selasky 
84266c81aaSHans Petter Selasky 	err = mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
85266c81aaSHans Petter Selasky 	if (err)
86266c81aaSHans Petter Selasky 		return err;
87266c81aaSHans Petter Selasky 
88266c81aaSHans Petter Selasky 	*scq_handle = MLX5_GET(query_pp_rate_limit_out, out, pp_context.qos_handle);
89266c81aaSHans Petter Selasky 
90266c81aaSHans Petter Selasky 	return 0;
91266c81aaSHans Petter Selasky }
92266c81aaSHans Petter Selasky 
mlx5_rl_is_in_range(const struct mlx5_core_dev * dev,u32 rate,u32 burst)9338535d6cSHans Petter Selasky bool mlx5_rl_is_in_range(const struct mlx5_core_dev *dev, u32 rate, u32 burst)
9438535d6cSHans Petter Selasky {
9538535d6cSHans Petter Selasky 	const struct mlx5_rl_table *table = &dev->priv.rl_table;
9638535d6cSHans Petter Selasky 
9738535d6cSHans Petter Selasky 	return (rate <= table->max_rate && rate >= table->min_rate &&
9838535d6cSHans Petter Selasky 		burst <= 65535);
9938535d6cSHans Petter Selasky }
10038535d6cSHans Petter Selasky EXPORT_SYMBOL(mlx5_rl_is_in_range);
10138535d6cSHans Petter Selasky 
mlx5_rl_add_rate(struct mlx5_core_dev * dev,u32 rate,u32 burst,u16 * index)10238535d6cSHans Petter Selasky int mlx5_rl_add_rate(struct mlx5_core_dev *dev, u32 rate, u32 burst, u16 *index)
10338535d6cSHans Petter Selasky {
10438535d6cSHans Petter Selasky 	struct mlx5_rl_table *table = &dev->priv.rl_table;
10538535d6cSHans Petter Selasky 	struct mlx5_rl_entry *entry;
10638535d6cSHans Petter Selasky 	int err = 0;
10738535d6cSHans Petter Selasky 
10838535d6cSHans Petter Selasky 	mutex_lock(&table->rl_lock);
10938535d6cSHans Petter Selasky 
11038535d6cSHans Petter Selasky 	if (!rate || !mlx5_rl_is_in_range(dev, rate, burst)) {
11138535d6cSHans Petter Selasky 		mlx5_core_err(dev, "Invalid rate: %u, should be %u to %u\n",
11238535d6cSHans Petter Selasky 			      rate, table->min_rate, table->max_rate);
11338535d6cSHans Petter Selasky 		err = -ERANGE;
11438535d6cSHans Petter Selasky 		goto out;
11538535d6cSHans Petter Selasky 	}
11638535d6cSHans Petter Selasky 
11738535d6cSHans Petter Selasky 	entry = find_rl_entry(table, rate, burst);
11838535d6cSHans Petter Selasky 	if (!entry) {
11938535d6cSHans Petter Selasky 		mlx5_core_err(dev, "Max number of %u rates reached\n",
12038535d6cSHans Petter Selasky 			      table->max_size);
12138535d6cSHans Petter Selasky 		err = -ENOSPC;
12238535d6cSHans Petter Selasky 		goto out;
12338535d6cSHans Petter Selasky 	}
12438535d6cSHans Petter Selasky 	if (entry->refcount == 0xFFFFFFFFU) {
12538535d6cSHans Petter Selasky 		/* out of refcounts */
12638535d6cSHans Petter Selasky 		err = -ENOMEM;
12738535d6cSHans Petter Selasky 		goto out;
12838535d6cSHans Petter Selasky 	} else if (entry->refcount != 0) {
12938535d6cSHans Petter Selasky 		/* rate already configured */
13038535d6cSHans Petter Selasky 		entry->refcount++;
13138535d6cSHans Petter Selasky 	} else {
13238535d6cSHans Petter Selasky 		/* new rate limit */
13338535d6cSHans Petter Selasky 		err = mlx5_set_rate_limit_cmd(dev, rate, burst, entry->index);
13438535d6cSHans Petter Selasky 		if (err) {
13538535d6cSHans Petter Selasky 			mlx5_core_err(dev, "Failed configuring rate: %u (%d)\n",
13638535d6cSHans Petter Selasky 				      rate, err);
13738535d6cSHans Petter Selasky 			goto out;
13838535d6cSHans Petter Selasky 		}
13938535d6cSHans Petter Selasky 		entry->rate = rate;
14038535d6cSHans Petter Selasky 		entry->burst = burst;
14138535d6cSHans Petter Selasky 		entry->refcount = 1;
142266c81aaSHans Petter Selasky 
143266c81aaSHans Petter Selasky 		if (MLX5_CAP_QOS(dev, qos_remap_pp)) {
144266c81aaSHans Petter Selasky 			err = mlx5e_query_rate_limit_cmd(dev, entry->index, &entry->qos_handle);
145266c81aaSHans Petter Selasky 			if (err) {
146266c81aaSHans Petter Selasky 				mlx5_core_err(dev, "Failed retrieving schedule queue handle for"
147266c81aaSHans Petter Selasky 				    "SQ remap: rate: %u error:(%d)\n", rate, err);
148266c81aaSHans Petter Selasky 				entry->qos_handle = MLX5_INVALID_QUEUE_HANDLE;
149266c81aaSHans Petter Selasky 			}
150266c81aaSHans Petter Selasky 		} else
151266c81aaSHans Petter Selasky 			entry->qos_handle = MLX5_INVALID_QUEUE_HANDLE;
15238535d6cSHans Petter Selasky 	}
15338535d6cSHans Petter Selasky 	*index = entry->index;
15438535d6cSHans Petter Selasky 
15538535d6cSHans Petter Selasky out:
15638535d6cSHans Petter Selasky 	mutex_unlock(&table->rl_lock);
15738535d6cSHans Petter Selasky 	return err;
15838535d6cSHans Petter Selasky }
15938535d6cSHans Petter Selasky EXPORT_SYMBOL(mlx5_rl_add_rate);
16038535d6cSHans Petter Selasky 
mlx5_rl_remove_rate(struct mlx5_core_dev * dev,u32 rate,u32 burst)16138535d6cSHans Petter Selasky void mlx5_rl_remove_rate(struct mlx5_core_dev *dev, u32 rate, u32 burst)
16238535d6cSHans Petter Selasky {
16338535d6cSHans Petter Selasky 	struct mlx5_rl_table *table = &dev->priv.rl_table;
16438535d6cSHans Petter Selasky 	struct mlx5_rl_entry *entry = NULL;
16538535d6cSHans Petter Selasky 
16638535d6cSHans Petter Selasky 	/* 0 is a reserved value for unlimited rate */
16738535d6cSHans Petter Selasky 	if (rate == 0)
16838535d6cSHans Petter Selasky 		return;
16938535d6cSHans Petter Selasky 
17038535d6cSHans Petter Selasky 	mutex_lock(&table->rl_lock);
17138535d6cSHans Petter Selasky 	entry = find_rl_entry(table, rate, burst);
17238535d6cSHans Petter Selasky 	if (!entry || !entry->refcount) {
17338535d6cSHans Petter Selasky 		mlx5_core_warn(dev, "Rate %u is not configured\n", rate);
17438535d6cSHans Petter Selasky 		goto out;
17538535d6cSHans Petter Selasky 	}
17638535d6cSHans Petter Selasky 
17738535d6cSHans Petter Selasky 	entry->refcount--;
17838535d6cSHans Petter Selasky 	if (!entry->refcount) {
17938535d6cSHans Petter Selasky 		/* need to remove rate */
18038535d6cSHans Petter Selasky 		mlx5_set_rate_limit_cmd(dev, 0, 0, entry->index);
18138535d6cSHans Petter Selasky 		entry->rate = 0;
18238535d6cSHans Petter Selasky 		entry->burst = 0;
18338535d6cSHans Petter Selasky 	}
18438535d6cSHans Petter Selasky 
18538535d6cSHans Petter Selasky out:
18638535d6cSHans Petter Selasky 	mutex_unlock(&table->rl_lock);
18738535d6cSHans Petter Selasky }
18838535d6cSHans Petter Selasky EXPORT_SYMBOL(mlx5_rl_remove_rate);
18938535d6cSHans Petter Selasky 
mlx5_init_rl_table(struct mlx5_core_dev * dev)19038535d6cSHans Petter Selasky int mlx5_init_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 	mutex_init(&table->rl_lock);
19638535d6cSHans Petter Selasky 	if (!MLX5_CAP_GEN(dev, qos) || !MLX5_CAP_QOS(dev, packet_pacing)) {
19738535d6cSHans Petter Selasky 		table->max_size = 0;
19838535d6cSHans Petter Selasky 		return 0;
19938535d6cSHans Petter Selasky 	}
20038535d6cSHans Petter Selasky 
20138535d6cSHans Petter Selasky 	/* First entry is reserved for unlimited rate */
20238535d6cSHans Petter Selasky 	table->max_size = MLX5_CAP_QOS(dev, packet_pacing_rate_table_size) - 1;
20338535d6cSHans Petter Selasky 	table->max_rate = MLX5_CAP_QOS(dev, packet_pacing_max_rate);
20438535d6cSHans Petter Selasky 	table->min_rate = MLX5_CAP_QOS(dev, packet_pacing_min_rate);
20538535d6cSHans Petter Selasky 
20638535d6cSHans Petter Selasky 	table->rl_entry = kcalloc(table->max_size, sizeof(struct mlx5_rl_entry),
20738535d6cSHans Petter Selasky 				  GFP_KERNEL);
20838535d6cSHans Petter Selasky 	if (!table->rl_entry)
20938535d6cSHans Petter Selasky 		return -ENOMEM;
21038535d6cSHans Petter Selasky 
21138535d6cSHans Petter Selasky 	/* The index represents the index in HW rate limit table
21238535d6cSHans Petter Selasky 	 * Index 0 is reserved for unlimited rate
21338535d6cSHans Petter Selasky 	 */
21438535d6cSHans Petter Selasky 	for (i = 0; i < table->max_size; i++)
21538535d6cSHans Petter Selasky 		table->rl_entry[i].index = i + 1;
21638535d6cSHans Petter Selasky 
21738535d6cSHans Petter Selasky 	return 0;
21838535d6cSHans Petter Selasky }
21938535d6cSHans Petter Selasky 
mlx5_cleanup_rl_table(struct mlx5_core_dev * dev)22038535d6cSHans Petter Selasky void mlx5_cleanup_rl_table(struct mlx5_core_dev *dev)
22138535d6cSHans Petter Selasky {
22238535d6cSHans Petter Selasky 	struct mlx5_rl_table *table = &dev->priv.rl_table;
22338535d6cSHans Petter Selasky 	int i;
22438535d6cSHans Petter Selasky 
22538535d6cSHans Petter Selasky 	/* Clear all configured rates */
22638535d6cSHans Petter Selasky 	for (i = 0; i < table->max_size; i++)
22738535d6cSHans Petter Selasky 		if (table->rl_entry[i].rate)
22838535d6cSHans Petter Selasky 			mlx5_set_rate_limit_cmd(dev, 0, 0,
22938535d6cSHans Petter Selasky 						table->rl_entry[i].index);
23038535d6cSHans Petter Selasky 
23138535d6cSHans Petter Selasky 	kfree(dev->priv.rl_table.rl_entry);
23238535d6cSHans Petter Selasky }
23338535d6cSHans Petter Selasky 
23438535d6cSHans Petter Selasky #endif
235