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 28ee9d634bSKonstantin Belousov #include "opt_rss.h" 29ee9d634bSKonstantin Belousov #include "opt_ratelimit.h" 30ee9d634bSKonstantin Belousov 3138535d6cSHans Petter Selasky #include <linux/kernel.h> 3238535d6cSHans Petter Selasky #include <linux/module.h> 3338535d6cSHans Petter Selasky #include <dev/mlx5/driver.h> 3412c56d7dSHans Petter Selasky #include <dev/mlx5/mlx5_core/mlx5_core.h> 3538535d6cSHans Petter Selasky 3638535d6cSHans Petter Selasky #ifdef RATELIMIT 3738535d6cSHans Petter Selasky 3838535d6cSHans Petter Selasky /* Finds an entry where we can register the given rate 3938535d6cSHans Petter Selasky * If the rate already exists, return the entry where it is registered, 4038535d6cSHans Petter Selasky * otherwise return the first available entry. 4138535d6cSHans Petter Selasky * If the table is full, return NULL 4238535d6cSHans Petter Selasky */ 4338535d6cSHans Petter Selasky static struct mlx5_rl_entry *find_rl_entry(struct mlx5_rl_table *table, 4438535d6cSHans Petter Selasky u32 rate, u16 burst) 4538535d6cSHans Petter Selasky { 4638535d6cSHans Petter Selasky struct mlx5_rl_entry *ret_entry = NULL; 4738535d6cSHans Petter Selasky struct mlx5_rl_entry *entry; 4838535d6cSHans Petter Selasky u16 i; 4938535d6cSHans Petter Selasky 5038535d6cSHans Petter Selasky for (i = 0; i < table->max_size; i++) { 5138535d6cSHans Petter Selasky entry = table->rl_entry + i; 5238535d6cSHans Petter Selasky if (entry->rate == rate && entry->burst == burst) 5338535d6cSHans Petter Selasky return entry; 5438535d6cSHans Petter Selasky if (ret_entry == NULL && entry->rate == 0) 5538535d6cSHans Petter Selasky ret_entry = entry; 5638535d6cSHans Petter Selasky } 5738535d6cSHans Petter Selasky 5838535d6cSHans Petter Selasky return ret_entry; 5938535d6cSHans Petter Selasky } 6038535d6cSHans Petter Selasky 6138535d6cSHans Petter Selasky static int mlx5_set_rate_limit_cmd(struct mlx5_core_dev *dev, 6238535d6cSHans Petter Selasky u32 rate, u32 burst, u16 index) 6338535d6cSHans Petter Selasky { 64bf43f981SHans Petter Selasky u32 in[MLX5_ST_SZ_DW(set_rate_limit_in)] = {}; 65bf43f981SHans Petter Selasky u32 out[MLX5_ST_SZ_DW(set_rate_limit_out)] = {}; 6638535d6cSHans Petter Selasky 67bf43f981SHans Petter Selasky MLX5_SET(set_rate_limit_in, in, opcode, MLX5_CMD_OP_SET_RATE_LIMIT); 6838535d6cSHans Petter Selasky MLX5_SET(set_rate_limit_in, in, rate_limit_index, index); 6938535d6cSHans Petter Selasky MLX5_SET(set_rate_limit_in, in, rate_limit, rate); 7038535d6cSHans Petter Selasky MLX5_SET(set_rate_limit_in, in, burst_upper_bound, burst); 71bf43f981SHans Petter Selasky MLX5_SET(set_rate_limit_in, in, typical_packet_size, 0 /* use MTU */); 7238535d6cSHans Petter Selasky 7338535d6cSHans Petter Selasky return mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out)); 7438535d6cSHans Petter Selasky } 7538535d6cSHans Petter Selasky 7638535d6cSHans Petter Selasky bool mlx5_rl_is_in_range(const struct mlx5_core_dev *dev, u32 rate, u32 burst) 7738535d6cSHans Petter Selasky { 7838535d6cSHans Petter Selasky const struct mlx5_rl_table *table = &dev->priv.rl_table; 7938535d6cSHans Petter Selasky 8038535d6cSHans Petter Selasky return (rate <= table->max_rate && rate >= table->min_rate && 8138535d6cSHans Petter Selasky burst <= 65535); 8238535d6cSHans Petter Selasky } 8338535d6cSHans Petter Selasky EXPORT_SYMBOL(mlx5_rl_is_in_range); 8438535d6cSHans Petter Selasky 8538535d6cSHans Petter Selasky int mlx5_rl_add_rate(struct mlx5_core_dev *dev, u32 rate, u32 burst, u16 *index) 8638535d6cSHans Petter Selasky { 8738535d6cSHans Petter Selasky struct mlx5_rl_table *table = &dev->priv.rl_table; 8838535d6cSHans Petter Selasky struct mlx5_rl_entry *entry; 8938535d6cSHans Petter Selasky int err = 0; 9038535d6cSHans Petter Selasky 9138535d6cSHans Petter Selasky mutex_lock(&table->rl_lock); 9238535d6cSHans Petter Selasky 9338535d6cSHans Petter Selasky if (!rate || !mlx5_rl_is_in_range(dev, rate, burst)) { 9438535d6cSHans Petter Selasky mlx5_core_err(dev, "Invalid rate: %u, should be %u to %u\n", 9538535d6cSHans Petter Selasky rate, table->min_rate, table->max_rate); 9638535d6cSHans Petter Selasky err = -ERANGE; 9738535d6cSHans Petter Selasky goto out; 9838535d6cSHans Petter Selasky } 9938535d6cSHans Petter Selasky 10038535d6cSHans Petter Selasky entry = find_rl_entry(table, rate, burst); 10138535d6cSHans Petter Selasky if (!entry) { 10238535d6cSHans Petter Selasky mlx5_core_err(dev, "Max number of %u rates reached\n", 10338535d6cSHans Petter Selasky table->max_size); 10438535d6cSHans Petter Selasky err = -ENOSPC; 10538535d6cSHans Petter Selasky goto out; 10638535d6cSHans Petter Selasky } 10738535d6cSHans Petter Selasky if (entry->refcount == 0xFFFFFFFFU) { 10838535d6cSHans Petter Selasky /* out of refcounts */ 10938535d6cSHans Petter Selasky err = -ENOMEM; 11038535d6cSHans Petter Selasky goto out; 11138535d6cSHans Petter Selasky } else if (entry->refcount != 0) { 11238535d6cSHans Petter Selasky /* rate already configured */ 11338535d6cSHans Petter Selasky entry->refcount++; 11438535d6cSHans Petter Selasky } else { 11538535d6cSHans Petter Selasky /* new rate limit */ 11638535d6cSHans Petter Selasky err = mlx5_set_rate_limit_cmd(dev, rate, burst, entry->index); 11738535d6cSHans Petter Selasky if (err) { 11838535d6cSHans Petter Selasky mlx5_core_err(dev, "Failed configuring rate: %u (%d)\n", 11938535d6cSHans Petter Selasky rate, err); 12038535d6cSHans Petter Selasky goto out; 12138535d6cSHans Petter Selasky } 12238535d6cSHans Petter Selasky entry->rate = rate; 12338535d6cSHans Petter Selasky entry->burst = burst; 12438535d6cSHans Petter Selasky entry->refcount = 1; 12538535d6cSHans Petter Selasky } 12638535d6cSHans Petter Selasky *index = entry->index; 12738535d6cSHans Petter Selasky 12838535d6cSHans Petter Selasky out: 12938535d6cSHans Petter Selasky mutex_unlock(&table->rl_lock); 13038535d6cSHans Petter Selasky return err; 13138535d6cSHans Petter Selasky } 13238535d6cSHans Petter Selasky EXPORT_SYMBOL(mlx5_rl_add_rate); 13338535d6cSHans Petter Selasky 13438535d6cSHans Petter Selasky void mlx5_rl_remove_rate(struct mlx5_core_dev *dev, u32 rate, u32 burst) 13538535d6cSHans Petter Selasky { 13638535d6cSHans Petter Selasky struct mlx5_rl_table *table = &dev->priv.rl_table; 13738535d6cSHans Petter Selasky struct mlx5_rl_entry *entry = NULL; 13838535d6cSHans Petter Selasky 13938535d6cSHans Petter Selasky /* 0 is a reserved value for unlimited rate */ 14038535d6cSHans Petter Selasky if (rate == 0) 14138535d6cSHans Petter Selasky return; 14238535d6cSHans Petter Selasky 14338535d6cSHans Petter Selasky mutex_lock(&table->rl_lock); 14438535d6cSHans Petter Selasky entry = find_rl_entry(table, rate, burst); 14538535d6cSHans Petter Selasky if (!entry || !entry->refcount) { 14638535d6cSHans Petter Selasky mlx5_core_warn(dev, "Rate %u is not configured\n", rate); 14738535d6cSHans Petter Selasky goto out; 14838535d6cSHans Petter Selasky } 14938535d6cSHans Petter Selasky 15038535d6cSHans Petter Selasky entry->refcount--; 15138535d6cSHans Petter Selasky if (!entry->refcount) { 15238535d6cSHans Petter Selasky /* need to remove rate */ 15338535d6cSHans Petter Selasky mlx5_set_rate_limit_cmd(dev, 0, 0, entry->index); 15438535d6cSHans Petter Selasky entry->rate = 0; 15538535d6cSHans Petter Selasky entry->burst = 0; 15638535d6cSHans Petter Selasky } 15738535d6cSHans Petter Selasky 15838535d6cSHans Petter Selasky out: 15938535d6cSHans Petter Selasky mutex_unlock(&table->rl_lock); 16038535d6cSHans Petter Selasky } 16138535d6cSHans Petter Selasky EXPORT_SYMBOL(mlx5_rl_remove_rate); 16238535d6cSHans Petter Selasky 16338535d6cSHans Petter Selasky int mlx5_init_rl_table(struct mlx5_core_dev *dev) 16438535d6cSHans Petter Selasky { 16538535d6cSHans Petter Selasky struct mlx5_rl_table *table = &dev->priv.rl_table; 16638535d6cSHans Petter Selasky int i; 16738535d6cSHans Petter Selasky 16838535d6cSHans Petter Selasky mutex_init(&table->rl_lock); 16938535d6cSHans Petter Selasky if (!MLX5_CAP_GEN(dev, qos) || !MLX5_CAP_QOS(dev, packet_pacing)) { 17038535d6cSHans Petter Selasky table->max_size = 0; 17138535d6cSHans Petter Selasky return 0; 17238535d6cSHans Petter Selasky } 17338535d6cSHans Petter Selasky 17438535d6cSHans Petter Selasky /* First entry is reserved for unlimited rate */ 17538535d6cSHans Petter Selasky table->max_size = MLX5_CAP_QOS(dev, packet_pacing_rate_table_size) - 1; 17638535d6cSHans Petter Selasky table->max_rate = MLX5_CAP_QOS(dev, packet_pacing_max_rate); 17738535d6cSHans Petter Selasky table->min_rate = MLX5_CAP_QOS(dev, packet_pacing_min_rate); 17838535d6cSHans Petter Selasky 17938535d6cSHans Petter Selasky table->rl_entry = kcalloc(table->max_size, sizeof(struct mlx5_rl_entry), 18038535d6cSHans Petter Selasky GFP_KERNEL); 18138535d6cSHans Petter Selasky if (!table->rl_entry) 18238535d6cSHans Petter Selasky return -ENOMEM; 18338535d6cSHans Petter Selasky 18438535d6cSHans Petter Selasky /* The index represents the index in HW rate limit table 18538535d6cSHans Petter Selasky * Index 0 is reserved for unlimited rate 18638535d6cSHans Petter Selasky */ 18738535d6cSHans Petter Selasky for (i = 0; i < table->max_size; i++) 18838535d6cSHans Petter Selasky table->rl_entry[i].index = i + 1; 18938535d6cSHans Petter Selasky 19038535d6cSHans Petter Selasky return 0; 19138535d6cSHans Petter Selasky } 19238535d6cSHans Petter Selasky 19338535d6cSHans Petter Selasky void mlx5_cleanup_rl_table(struct mlx5_core_dev *dev) 19438535d6cSHans Petter Selasky { 19538535d6cSHans Petter Selasky struct mlx5_rl_table *table = &dev->priv.rl_table; 19638535d6cSHans Petter Selasky int i; 19738535d6cSHans Petter Selasky 19838535d6cSHans Petter Selasky /* Clear all configured rates */ 19938535d6cSHans Petter Selasky for (i = 0; i < table->max_size; i++) 20038535d6cSHans Petter Selasky if (table->rl_entry[i].rate) 20138535d6cSHans Petter Selasky mlx5_set_rate_limit_cmd(dev, 0, 0, 20238535d6cSHans Petter Selasky table->rl_entry[i].index); 20338535d6cSHans Petter Selasky 20438535d6cSHans Petter Selasky kfree(dev->priv.rl_table.rl_entry); 20538535d6cSHans Petter Selasky } 20638535d6cSHans Petter Selasky 20738535d6cSHans Petter Selasky #endif 208