Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
0002 /* Copyright (c) 2019 Mellanox Technologies. */
0003 
0004 #include <linux/kernel.h>
0005 #include "mlx5_core.h"
0006 #include "geneve.h"
0007 
0008 struct mlx5_geneve {
0009     struct mlx5_core_dev *mdev;
0010     __be16 opt_class;
0011     u8 opt_type;
0012     u32 obj_id;
0013     struct mutex sync_lock; /* protect GENEVE obj operations */
0014     u32 refcount;
0015 };
0016 
0017 static int mlx5_geneve_tlv_option_create(struct mlx5_core_dev *mdev,
0018                      __be16 class,
0019                      u8 type,
0020                      u8 len)
0021 {
0022     u32 in[MLX5_ST_SZ_DW(create_geneve_tlv_option_in)] = {};
0023     u32 out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)] = {};
0024     u64 general_obj_types;
0025     void *hdr, *opt;
0026     u16 obj_id;
0027     int err;
0028 
0029     general_obj_types = MLX5_CAP_GEN_64(mdev, general_obj_types);
0030     if (!(general_obj_types & MLX5_GENERAL_OBJ_TYPES_CAP_GENEVE_TLV_OPT))
0031         return -EINVAL;
0032 
0033     hdr = MLX5_ADDR_OF(create_geneve_tlv_option_in, in, hdr);
0034     opt = MLX5_ADDR_OF(create_geneve_tlv_option_in, in, geneve_tlv_opt);
0035 
0036     MLX5_SET(general_obj_in_cmd_hdr, hdr, opcode, MLX5_CMD_OP_CREATE_GENERAL_OBJECT);
0037     MLX5_SET(general_obj_in_cmd_hdr, hdr, obj_type, MLX5_OBJ_TYPE_GENEVE_TLV_OPT);
0038 
0039     MLX5_SET(geneve_tlv_option, opt, option_class, be16_to_cpu(class));
0040     MLX5_SET(geneve_tlv_option, opt, option_type, type);
0041     MLX5_SET(geneve_tlv_option, opt, option_data_length, len);
0042 
0043     err = mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out));
0044     if (err)
0045         return err;
0046 
0047     obj_id = MLX5_GET(general_obj_out_cmd_hdr, out, obj_id);
0048     return obj_id;
0049 }
0050 
0051 static void mlx5_geneve_tlv_option_destroy(struct mlx5_core_dev *mdev, u16 obj_id)
0052 {
0053     u32 out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)] = {};
0054     u32 in[MLX5_ST_SZ_DW(general_obj_in_cmd_hdr)] = {};
0055 
0056     MLX5_SET(general_obj_in_cmd_hdr, in, opcode, MLX5_CMD_OP_DESTROY_GENERAL_OBJECT);
0057     MLX5_SET(general_obj_in_cmd_hdr, in, obj_type, MLX5_OBJ_TYPE_GENEVE_TLV_OPT);
0058     MLX5_SET(general_obj_in_cmd_hdr, in, obj_id, obj_id);
0059 
0060     mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out));
0061 }
0062 
0063 int mlx5_geneve_tlv_option_add(struct mlx5_geneve *geneve, struct geneve_opt *opt)
0064 {
0065     int res = 0;
0066 
0067     if (IS_ERR_OR_NULL(geneve))
0068         return -EOPNOTSUPP;
0069 
0070     mutex_lock(&geneve->sync_lock);
0071 
0072     if (geneve->refcount) {
0073         if (geneve->opt_class == opt->opt_class &&
0074             geneve->opt_type == opt->type) {
0075             /* We already have TLV options obj allocated */
0076             geneve->refcount++;
0077         } else {
0078             /* TLV options obj allocated, but its params
0079              * do not match the new request.
0080              * We support only one such object.
0081              */
0082             mlx5_core_warn(geneve->mdev,
0083                        "Won't create Geneve TLV opt object with class:type:len = 0x%x:0x%x:%d (another class:type already exists)\n",
0084                        be16_to_cpu(opt->opt_class),
0085                        opt->type,
0086                        opt->length);
0087             res = -EOPNOTSUPP;
0088             goto unlock;
0089         }
0090     } else {
0091         /* We don't have any TLV options obj allocated */
0092 
0093         res = mlx5_geneve_tlv_option_create(geneve->mdev,
0094                             opt->opt_class,
0095                             opt->type,
0096                             opt->length);
0097         if (res < 0) {
0098             mlx5_core_warn(geneve->mdev,
0099                        "Failed creating Geneve TLV opt object class:type:len = 0x%x:0x%x:%d (err=%d)\n",
0100                        be16_to_cpu(opt->opt_class),
0101                        opt->type, opt->length, res);
0102             goto unlock;
0103         }
0104         geneve->opt_class = opt->opt_class;
0105         geneve->opt_type = opt->type;
0106         geneve->obj_id = res;
0107         geneve->refcount++;
0108     }
0109 
0110 unlock:
0111     mutex_unlock(&geneve->sync_lock);
0112     return res;
0113 }
0114 
0115 void mlx5_geneve_tlv_option_del(struct mlx5_geneve *geneve)
0116 {
0117     if (IS_ERR_OR_NULL(geneve))
0118         return;
0119 
0120     mutex_lock(&geneve->sync_lock);
0121     if (--geneve->refcount == 0) {
0122         /* We've just removed the last user of Geneve option.
0123          * Now delete the object in FW.
0124          */
0125         mlx5_geneve_tlv_option_destroy(geneve->mdev, geneve->obj_id);
0126 
0127         geneve->opt_class = 0;
0128         geneve->opt_type = 0;
0129         geneve->obj_id = 0;
0130     }
0131     mutex_unlock(&geneve->sync_lock);
0132 }
0133 
0134 struct mlx5_geneve *mlx5_geneve_create(struct mlx5_core_dev *mdev)
0135 {
0136     struct mlx5_geneve *geneve =
0137         kzalloc(sizeof(*geneve), GFP_KERNEL);
0138 
0139     if (!geneve)
0140         return ERR_PTR(-ENOMEM);
0141     geneve->mdev = mdev;
0142     mutex_init(&geneve->sync_lock);
0143 
0144     return geneve;
0145 }
0146 
0147 void mlx5_geneve_destroy(struct mlx5_geneve *geneve)
0148 {
0149     if (IS_ERR_OR_NULL(geneve))
0150         return;
0151 
0152     /* Lockless since we are unloading */
0153     if (geneve->refcount)
0154         mlx5_geneve_tlv_option_destroy(geneve->mdev, geneve->obj_id);
0155 
0156     kfree(geneve);
0157 }