0001
0002
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;
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
0076 geneve->refcount++;
0077 } else {
0078
0079
0080
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
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
0123
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
0153 if (geneve->refcount)
0154 mlx5_geneve_tlv_option_destroy(geneve->mdev, geneve->obj_id);
0155
0156 kfree(geneve);
0157 }