File Index
Files and directories
Sign in
FILE

geneve.c

File preview with syntax highlighting.

linux-6.19.14/drivers/net/ethernet/mellanox/mlx5/core/lib/geneve.c C
  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		res = 0;
109	}
110
111unlock:
112	mutex_unlock(&geneve->sync_lock);
113	return res;
114}
115
116void mlx5_geneve_tlv_option_del(struct mlx5_geneve *geneve)
117{
118	if (IS_ERR_OR_NULL(geneve))
119		return;
120
121	mutex_lock(&geneve->sync_lock);
122	if (--geneve->refcount == 0) {
123		/* We've just removed the last user of Geneve option.
124		 * Now delete the object in FW.
125		 */
126		mlx5_geneve_tlv_option_destroy(geneve->mdev, geneve->obj_id);
127
128		geneve->opt_class = 0;
129		geneve->opt_type = 0;
130		geneve->obj_id = 0;
131	}
132	mutex_unlock(&geneve->sync_lock);
133}
134
135struct mlx5_geneve *mlx5_geneve_create(struct mlx5_core_dev *mdev)
136{
137	struct mlx5_geneve *geneve =
138		kzalloc(sizeof(*geneve), GFP_KERNEL);
139
140	if (!geneve)
141		return ERR_PTR(-ENOMEM);
142	geneve->mdev = mdev;
143	mutex_init(&geneve->sync_lock);
144
145	return geneve;
146}
147
148void mlx5_geneve_destroy(struct mlx5_geneve *geneve)
149{
150	if (IS_ERR_OR_NULL(geneve))
151		return;
152
153	/* Lockless since we are unloading */
154	if (geneve->refcount)
155		mlx5_geneve_tlv_option_destroy(geneve->mdev, geneve->obj_id);
156
157	kfree(geneve);
158}
~/ Read-only file preview.