1 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
2 /* Copyright (c) 2019 Mellanox Technologies. */
4 #include <linux/kernel.h>
9 struct mlx5_core_dev *mdev;
13 struct mutex sync_lock; /* protect GENEVE obj operations */
17 static int mlx5_geneve_tlv_option_create(struct mlx5_core_dev *mdev,
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;
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))
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);
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);
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);
43 err = mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out));
47 obj_id = MLX5_GET(general_obj_out_cmd_hdr, out, obj_id);
51 static void mlx5_geneve_tlv_option_destroy(struct mlx5_core_dev *mdev, u16 obj_id)
53 u32 out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)] = {};
54 u32 in[MLX5_ST_SZ_DW(general_obj_in_cmd_hdr)] = {};
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);
60 mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out));
63 int mlx5_geneve_tlv_option_add(struct mlx5_geneve *geneve, struct geneve_opt *opt)
67 if (IS_ERR_OR_NULL(geneve))
70 mutex_lock(&geneve->sync_lock);
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 */
78 /* TLV options obj allocated, but its params
79 * do not match the new request.
80 * We support only one such object.
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),
91 /* We don't have any TLV options obj allocated */
93 res = mlx5_geneve_tlv_option_create(geneve->mdev,
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);
104 geneve->opt_class = opt->opt_class;
105 geneve->opt_type = opt->type;
106 geneve->obj_id = res;
111 mutex_unlock(&geneve->sync_lock);
115 void mlx5_geneve_tlv_option_del(struct mlx5_geneve *geneve)
117 if (IS_ERR_OR_NULL(geneve))
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.
125 mlx5_geneve_tlv_option_destroy(geneve->mdev, geneve->obj_id);
127 geneve->opt_class = 0;
128 geneve->opt_type = 0;
131 mutex_unlock(&geneve->sync_lock);
134 struct mlx5_geneve *mlx5_geneve_create(struct mlx5_core_dev *mdev)
136 struct mlx5_geneve *geneve =
137 kzalloc(sizeof(*geneve), GFP_KERNEL);
140 return ERR_PTR(-ENOMEM);
142 mutex_init(&geneve->sync_lock);
147 void mlx5_geneve_destroy(struct mlx5_geneve *geneve)
149 if (IS_ERR_OR_NULL(geneve))
152 /* Lockless since we are unloading */
153 if (geneve->refcount)
154 mlx5_geneve_tlv_option_destroy(geneve->mdev, geneve->obj_id);