geneve.c (4249B)
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}