root/drivers/net/ethernet/mellanox/mlx5/core/lib/geneve.c

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

DEFINITIONS

This source file includes following definitions.
  1. mlx5_geneve_tlv_option_create
  2. mlx5_geneve_tlv_option_destroy
  3. mlx5_geneve_tlv_option_add
  4. mlx5_geneve_tlv_option_del
  5. mlx5_geneve_create
  6. mlx5_geneve_destroy

   1 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
   2 /* Copyright (c) 2019 Mellanox Technologies. */
   3 
   4 #include <linux/kernel.h>
   5 #include "mlx5_core.h"
   6 #include "geneve.h"
   7 
   8 struct mlx5_geneve {
   9         struct mlx5_core_dev *mdev;
  10         __be16 opt_class;
  11         u8 opt_type;
  12         u32 obj_id;
  13         struct mutex sync_lock; /* protect GENEVE obj operations */
  14         u32 refcount;
  15 };
  16 
  17 static int mlx5_geneve_tlv_option_create(struct mlx5_core_dev *mdev,
  18                                          __be16 class,
  19                                          u8 type,
  20                                          u8 len)
  21 {
  22         u32 in[MLX5_ST_SZ_DW(create_geneve_tlv_option_in)] = {};
  23         u32 out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)] = {};
  24         u64 general_obj_types;
  25         void *hdr, *opt;
  26         u16 obj_id;
  27         int err;
  28 
  29         general_obj_types = MLX5_CAP_GEN_64(mdev, general_obj_types);
  30         if (!(general_obj_types & MLX5_GENERAL_OBJ_TYPES_CAP_GENEVE_TLV_OPT))
  31                 return -EINVAL;
  32 
  33         hdr = MLX5_ADDR_OF(create_geneve_tlv_option_in, in, hdr);
  34         opt = MLX5_ADDR_OF(create_geneve_tlv_option_in, in, geneve_tlv_opt);
  35 
  36         MLX5_SET(general_obj_in_cmd_hdr, hdr, opcode, MLX5_CMD_OP_CREATE_GENERAL_OBJECT);
  37         MLX5_SET(general_obj_in_cmd_hdr, hdr, obj_type, MLX5_OBJ_TYPE_GENEVE_TLV_OPT);
  38 
  39         MLX5_SET(geneve_tlv_option, opt, option_class, be16_to_cpu(class));
  40         MLX5_SET(geneve_tlv_option, opt, option_type, type);
  41         MLX5_SET(geneve_tlv_option, opt, option_data_length, len);
  42 
  43         err = mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out));
  44         if (err)
  45                 return err;
  46 
  47         obj_id = MLX5_GET(general_obj_out_cmd_hdr, out, obj_id);
  48         return obj_id;
  49 }
  50 
  51 static void mlx5_geneve_tlv_option_destroy(struct mlx5_core_dev *mdev, u16 obj_id)
  52 {
  53         u32 out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)] = {};
  54         u32 in[MLX5_ST_SZ_DW(general_obj_in_cmd_hdr)] = {};
  55 
  56         MLX5_SET(general_obj_in_cmd_hdr, in, opcode, MLX5_CMD_OP_DESTROY_GENERAL_OBJECT);
  57         MLX5_SET(general_obj_in_cmd_hdr, in, obj_type, MLX5_OBJ_TYPE_GENEVE_TLV_OPT);
  58         MLX5_SET(general_obj_in_cmd_hdr, in, obj_id, obj_id);
  59 
  60         mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out));
  61 }
  62 
  63 int mlx5_geneve_tlv_option_add(struct mlx5_geneve *geneve, struct geneve_opt *opt)
  64 {
  65         int res = 0;
  66 
  67         if (IS_ERR_OR_NULL(geneve))
  68                 return -EOPNOTSUPP;
  69 
  70         mutex_lock(&geneve->sync_lock);
  71 
  72         if (geneve->refcount) {
  73                 if (geneve->opt_class == opt->opt_class &&
  74                     geneve->opt_type == opt->type) {
  75                         /* We already have TLV options obj allocated */
  76                         geneve->refcount++;
  77                 } else {
  78                         /* TLV options obj allocated, but its params
  79                          * do not match the new request.
  80                          * We support only one such object.
  81                          */
  82                         mlx5_core_warn(geneve->mdev,
  83                                        "Won't create Geneve TLV opt object with class:type:len = 0x%x:0x%x:%d (another class:type already exists)\n",
  84                                        be16_to_cpu(opt->opt_class),
  85                                        opt->type,
  86                                        opt->length);
  87                         res = -EOPNOTSUPP;
  88                         goto unlock;
  89                 }
  90         } else {
  91                 /* We don't have any TLV options obj allocated */
  92 
  93                 res = mlx5_geneve_tlv_option_create(geneve->mdev,
  94                                                     opt->opt_class,
  95                                                     opt->type,
  96                                                     opt->length);
  97                 if (res < 0) {
  98                         mlx5_core_warn(geneve->mdev,
  99                                        "Failed creating Geneve TLV opt object class:type:len = 0x%x:0x%x:%d (err=%d)\n",
 100                                        be16_to_cpu(opt->opt_class),
 101                                        opt->type, opt->length, res);
 102                         goto unlock;
 103                 }
 104                 geneve->opt_class = opt->opt_class;
 105                 geneve->opt_type = opt->type;
 106                 geneve->obj_id = res;
 107                 geneve->refcount++;
 108         }
 109 
 110 unlock:
 111         mutex_unlock(&geneve->sync_lock);
 112         return res;
 113 }
 114 
 115 void mlx5_geneve_tlv_option_del(struct mlx5_geneve *geneve)
 116 {
 117         if (IS_ERR_OR_NULL(geneve))
 118                 return;
 119 
 120         mutex_lock(&geneve->sync_lock);
 121         if (--geneve->refcount == 0) {
 122                 /* We've just removed the last user of Geneve option.
 123                  * Now delete the object in FW.
 124                  */
 125                 mlx5_geneve_tlv_option_destroy(geneve->mdev, geneve->obj_id);
 126 
 127                 geneve->opt_class = 0;
 128                 geneve->opt_type = 0;
 129                 geneve->obj_id = 0;
 130         }
 131         mutex_unlock(&geneve->sync_lock);
 132 }
 133 
 134 struct mlx5_geneve *mlx5_geneve_create(struct mlx5_core_dev *mdev)
 135 {
 136         struct mlx5_geneve *geneve =
 137                 kzalloc(sizeof(*geneve), GFP_KERNEL);
 138 
 139         if (!geneve)
 140                 return ERR_PTR(-ENOMEM);
 141         geneve->mdev = mdev;
 142         mutex_init(&geneve->sync_lock);
 143 
 144         return geneve;
 145 }
 146 
 147 void mlx5_geneve_destroy(struct mlx5_geneve *geneve)
 148 {
 149         if (IS_ERR_OR_NULL(geneve))
 150                 return;
 151 
 152         /* Lockless since we are unloading */
 153         if (geneve->refcount)
 154                 mlx5_geneve_tlv_option_destroy(geneve->mdev, geneve->obj_id);
 155 
 156         kfree(geneve);
 157 }

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