linux/drivers/net/ethernet/mellanox/mlx5/core/lib/geneve.c
<<
>>
Prefs
   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
   8struct 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
  17static 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
  51static 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
  63int 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
 110unlock:
 111        mutex_unlock(&geneve->sync_lock);
 112        return res;
 113}
 114
 115void 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
 134struct 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
 147void 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}
 158