root/drivers/net/ethernet/mellanox/mlx5/core/rl.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. mlx5_create_scheduling_element_cmd
  2. mlx5_modify_scheduling_element_cmd
  3. mlx5_destroy_scheduling_element_cmd
  4. find_rl_entry
  5. mlx5_set_pp_rate_limit_cmd
  6. mlx5_rl_is_in_range
  7. mlx5_rl_are_equal
  8. mlx5_rl_add_rate
  9. mlx5_rl_remove_rate
  10. mlx5_init_rl_table
  11. mlx5_cleanup_rl_table

   1 /*
   2  * Copyright (c) 2013-2016, 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/kernel.h>
  34 #include <linux/module.h>
  35 #include <linux/mlx5/driver.h>
  36 #include <linux/mlx5/cmd.h>
  37 #include "mlx5_core.h"
  38 
  39 /* Scheduling element fw management */
  40 int mlx5_create_scheduling_element_cmd(struct mlx5_core_dev *dev, u8 hierarchy,
  41                                        void *ctx, u32 *element_id)
  42 {
  43         u32 in[MLX5_ST_SZ_DW(create_scheduling_element_in)]  = {0};
  44         u32 out[MLX5_ST_SZ_DW(create_scheduling_element_in)] = {0};
  45         void *schedc;
  46         int err;
  47 
  48         schedc = MLX5_ADDR_OF(create_scheduling_element_in, in,
  49                               scheduling_context);
  50         MLX5_SET(create_scheduling_element_in, in, opcode,
  51                  MLX5_CMD_OP_CREATE_SCHEDULING_ELEMENT);
  52         MLX5_SET(create_scheduling_element_in, in, scheduling_hierarchy,
  53                  hierarchy);
  54         memcpy(schedc, ctx, MLX5_ST_SZ_BYTES(scheduling_context));
  55 
  56         err = mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
  57         if (err)
  58                 return err;
  59 
  60         *element_id = MLX5_GET(create_scheduling_element_out, out,
  61                                scheduling_element_id);
  62         return 0;
  63 }
  64 
  65 int mlx5_modify_scheduling_element_cmd(struct mlx5_core_dev *dev, u8 hierarchy,
  66                                        void *ctx, u32 element_id,
  67                                        u32 modify_bitmask)
  68 {
  69         u32 in[MLX5_ST_SZ_DW(modify_scheduling_element_in)]  = {0};
  70         u32 out[MLX5_ST_SZ_DW(modify_scheduling_element_in)] = {0};
  71         void *schedc;
  72 
  73         schedc = MLX5_ADDR_OF(modify_scheduling_element_in, in,
  74                               scheduling_context);
  75         MLX5_SET(modify_scheduling_element_in, in, opcode,
  76                  MLX5_CMD_OP_MODIFY_SCHEDULING_ELEMENT);
  77         MLX5_SET(modify_scheduling_element_in, in, scheduling_element_id,
  78                  element_id);
  79         MLX5_SET(modify_scheduling_element_in, in, modify_bitmask,
  80                  modify_bitmask);
  81         MLX5_SET(modify_scheduling_element_in, in, scheduling_hierarchy,
  82                  hierarchy);
  83         memcpy(schedc, ctx, MLX5_ST_SZ_BYTES(scheduling_context));
  84 
  85         return mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
  86 }
  87 
  88 int mlx5_destroy_scheduling_element_cmd(struct mlx5_core_dev *dev, u8 hierarchy,
  89                                         u32 element_id)
  90 {
  91         u32 in[MLX5_ST_SZ_DW(destroy_scheduling_element_in)]  = {0};
  92         u32 out[MLX5_ST_SZ_DW(destroy_scheduling_element_in)] = {0};
  93 
  94         MLX5_SET(destroy_scheduling_element_in, in, opcode,
  95                  MLX5_CMD_OP_DESTROY_SCHEDULING_ELEMENT);
  96         MLX5_SET(destroy_scheduling_element_in, in, scheduling_element_id,
  97                  element_id);
  98         MLX5_SET(destroy_scheduling_element_in, in, scheduling_hierarchy,
  99                  hierarchy);
 100 
 101         return mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
 102 }
 103 
 104 /* Finds an entry where we can register the given rate
 105  * If the rate already exists, return the entry where it is registered,
 106  * otherwise return the first available entry.
 107  * If the table is full, return NULL
 108  */
 109 static struct mlx5_rl_entry *find_rl_entry(struct mlx5_rl_table *table,
 110                                            struct mlx5_rate_limit *rl)
 111 {
 112         struct mlx5_rl_entry *ret_entry = NULL;
 113         bool empty_found = false;
 114         int i;
 115 
 116         for (i = 0; i < table->max_size; i++) {
 117                 if (mlx5_rl_are_equal(&table->rl_entry[i].rl, rl))
 118                         return &table->rl_entry[i];
 119                 if (!empty_found && !table->rl_entry[i].rl.rate) {
 120                         empty_found = true;
 121                         ret_entry = &table->rl_entry[i];
 122                 }
 123         }
 124 
 125         return ret_entry;
 126 }
 127 
 128 static int mlx5_set_pp_rate_limit_cmd(struct mlx5_core_dev *dev,
 129                                       u16 index,
 130                                       struct mlx5_rate_limit *rl)
 131 {
 132         u32 in[MLX5_ST_SZ_DW(set_pp_rate_limit_in)]   = {0};
 133         u32 out[MLX5_ST_SZ_DW(set_pp_rate_limit_out)] = {0};
 134 
 135         MLX5_SET(set_pp_rate_limit_in, in, opcode,
 136                  MLX5_CMD_OP_SET_PP_RATE_LIMIT);
 137         MLX5_SET(set_pp_rate_limit_in, in, rate_limit_index, index);
 138         MLX5_SET(set_pp_rate_limit_in, in, rate_limit, rl->rate);
 139         MLX5_SET(set_pp_rate_limit_in, in, burst_upper_bound, rl->max_burst_sz);
 140         MLX5_SET(set_pp_rate_limit_in, in, typical_packet_size, rl->typical_pkt_sz);
 141         return mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
 142 }
 143 
 144 bool mlx5_rl_is_in_range(struct mlx5_core_dev *dev, u32 rate)
 145 {
 146         struct mlx5_rl_table *table = &dev->priv.rl_table;
 147 
 148         return (rate <= table->max_rate && rate >= table->min_rate);
 149 }
 150 EXPORT_SYMBOL(mlx5_rl_is_in_range);
 151 
 152 bool mlx5_rl_are_equal(struct mlx5_rate_limit *rl_0,
 153                        struct mlx5_rate_limit *rl_1)
 154 {
 155         return ((rl_0->rate == rl_1->rate) &&
 156                 (rl_0->max_burst_sz == rl_1->max_burst_sz) &&
 157                 (rl_0->typical_pkt_sz == rl_1->typical_pkt_sz));
 158 }
 159 EXPORT_SYMBOL(mlx5_rl_are_equal);
 160 
 161 int mlx5_rl_add_rate(struct mlx5_core_dev *dev, u16 *index,
 162                      struct mlx5_rate_limit *rl)
 163 {
 164         struct mlx5_rl_table *table = &dev->priv.rl_table;
 165         struct mlx5_rl_entry *entry;
 166         int err = 0;
 167 
 168         mutex_lock(&table->rl_lock);
 169 
 170         if (!rl->rate || !mlx5_rl_is_in_range(dev, rl->rate)) {
 171                 mlx5_core_err(dev, "Invalid rate: %u, should be %u to %u\n",
 172                               rl->rate, table->min_rate, table->max_rate);
 173                 err = -EINVAL;
 174                 goto out;
 175         }
 176 
 177         entry = find_rl_entry(table, rl);
 178         if (!entry) {
 179                 mlx5_core_err(dev, "Max number of %u rates reached\n",
 180                               table->max_size);
 181                 err = -ENOSPC;
 182                 goto out;
 183         }
 184         if (entry->refcount) {
 185                 /* rate already configured */
 186                 entry->refcount++;
 187         } else {
 188                 /* new rate limit */
 189                 err = mlx5_set_pp_rate_limit_cmd(dev, entry->index, rl);
 190                 if (err) {
 191                         mlx5_core_err(dev, "Failed configuring rate limit(err %d): rate %u, max_burst_sz %u, typical_pkt_sz %u\n",
 192                                       err, rl->rate, rl->max_burst_sz,
 193                                       rl->typical_pkt_sz);
 194                         goto out;
 195                 }
 196                 entry->rl = *rl;
 197                 entry->refcount = 1;
 198         }
 199         *index = entry->index;
 200 
 201 out:
 202         mutex_unlock(&table->rl_lock);
 203         return err;
 204 }
 205 EXPORT_SYMBOL(mlx5_rl_add_rate);
 206 
 207 void mlx5_rl_remove_rate(struct mlx5_core_dev *dev, struct mlx5_rate_limit *rl)
 208 {
 209         struct mlx5_rl_table *table = &dev->priv.rl_table;
 210         struct mlx5_rl_entry *entry = NULL;
 211         struct mlx5_rate_limit reset_rl = {0};
 212 
 213         /* 0 is a reserved value for unlimited rate */
 214         if (rl->rate == 0)
 215                 return;
 216 
 217         mutex_lock(&table->rl_lock);
 218         entry = find_rl_entry(table, rl);
 219         if (!entry || !entry->refcount) {
 220                 mlx5_core_warn(dev, "Rate %u, max_burst_sz %u typical_pkt_sz %u are not configured\n",
 221                                rl->rate, rl->max_burst_sz, rl->typical_pkt_sz);
 222                 goto out;
 223         }
 224 
 225         entry->refcount--;
 226         if (!entry->refcount) {
 227                 /* need to remove rate */
 228                 mlx5_set_pp_rate_limit_cmd(dev, entry->index, &reset_rl);
 229                 entry->rl = reset_rl;
 230         }
 231 
 232 out:
 233         mutex_unlock(&table->rl_lock);
 234 }
 235 EXPORT_SYMBOL(mlx5_rl_remove_rate);
 236 
 237 int mlx5_init_rl_table(struct mlx5_core_dev *dev)
 238 {
 239         struct mlx5_rl_table *table = &dev->priv.rl_table;
 240         int i;
 241 
 242         mutex_init(&table->rl_lock);
 243         if (!MLX5_CAP_GEN(dev, qos) || !MLX5_CAP_QOS(dev, packet_pacing)) {
 244                 table->max_size = 0;
 245                 return 0;
 246         }
 247 
 248         /* First entry is reserved for unlimited rate */
 249         table->max_size = MLX5_CAP_QOS(dev, packet_pacing_rate_table_size) - 1;
 250         table->max_rate = MLX5_CAP_QOS(dev, packet_pacing_max_rate);
 251         table->min_rate = MLX5_CAP_QOS(dev, packet_pacing_min_rate);
 252 
 253         table->rl_entry = kcalloc(table->max_size, sizeof(struct mlx5_rl_entry),
 254                                   GFP_KERNEL);
 255         if (!table->rl_entry)
 256                 return -ENOMEM;
 257 
 258         /* The index represents the index in HW rate limit table
 259          * Index 0 is reserved for unlimited rate
 260          */
 261         for (i = 0; i < table->max_size; i++)
 262                 table->rl_entry[i].index = i + 1;
 263 
 264         /* Index 0 is reserved */
 265         mlx5_core_info(dev, "Rate limit: %u rates are supported, range: %uMbps to %uMbps\n",
 266                        table->max_size,
 267                        table->min_rate >> 10,
 268                        table->max_rate >> 10);
 269 
 270         return 0;
 271 }
 272 
 273 void mlx5_cleanup_rl_table(struct mlx5_core_dev *dev)
 274 {
 275         struct mlx5_rl_table *table = &dev->priv.rl_table;
 276         struct mlx5_rate_limit rl = {0};
 277         int i;
 278 
 279         /* Clear all configured rates */
 280         for (i = 0; i < table->max_size; i++)
 281                 if (table->rl_entry[i].rl.rate)
 282                         mlx5_set_pp_rate_limit_cmd(dev, table->rl_entry[i].index,
 283                                                    &rl);
 284 
 285         kfree(dev->priv.rl_table.rl_entry);
 286 }

/* [<][>][^][v][top][bottom][index][help] */