1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright (c) 2022 NVIDIA Corporation & Affiliates 3 */ 4 5 #include "mlx5dr_internal.h" 6 7 static void mlx5dr_table_init_next_ft_attr(struct mlx5dr_table *tbl, 8 struct mlx5dr_cmd_ft_create_attr *ft_attr) 9 { 10 ft_attr->type = tbl->fw_ft_type; 11 if (tbl->type == MLX5DR_TABLE_TYPE_FDB) 12 ft_attr->level = tbl->ctx->caps->fdb_ft.max_level - 1; 13 else 14 ft_attr->level = tbl->ctx->caps->nic_ft.max_level - 1; 15 ft_attr->rtc_valid = true; 16 } 17 18 /* Call this under ctx->ctrl_lock */ 19 static int 20 mlx5dr_table_up_default_fdb_miss_tbl(struct mlx5dr_table *tbl) 21 { 22 struct mlx5dr_cmd_ft_create_attr ft_attr = {0}; 23 struct mlx5dr_cmd_forward_tbl *default_miss; 24 struct mlx5dr_context *ctx = tbl->ctx; 25 uint8_t tbl_type = tbl->type; 26 uint32_t vport; 27 28 if (tbl->type != MLX5DR_TABLE_TYPE_FDB) 29 return 0; 30 31 if (ctx->common_res[tbl_type].default_miss) { 32 ctx->common_res[tbl_type].default_miss->refcount++; 33 return 0; 34 } 35 36 ft_attr.type = tbl->fw_ft_type; 37 ft_attr.level = tbl->ctx->caps->fdb_ft.max_level; /* The last level */ 38 ft_attr.rtc_valid = false; 39 40 assert(ctx->caps->eswitch_manager); 41 vport = ctx->caps->eswitch_manager_vport_number; 42 43 default_miss = mlx5dr_cmd_miss_ft_create(ctx->ibv_ctx, &ft_attr, vport); 44 if (!default_miss) { 45 DR_LOG(ERR, "Failed to default miss table type: 0x%x", tbl_type); 46 return rte_errno; 47 } 48 49 ctx->common_res[tbl_type].default_miss = default_miss; 50 ctx->common_res[tbl_type].default_miss->refcount++; 51 return 0; 52 } 53 54 /* Called under pthread_spin_lock(&ctx->ctrl_lock) */ 55 static void mlx5dr_table_down_default_fdb_miss_tbl(struct mlx5dr_table *tbl) 56 { 57 struct mlx5dr_cmd_forward_tbl *default_miss; 58 struct mlx5dr_context *ctx = tbl->ctx; 59 uint8_t tbl_type = tbl->type; 60 61 if (tbl->type != MLX5DR_TABLE_TYPE_FDB) 62 return; 63 64 default_miss = ctx->common_res[tbl_type].default_miss; 65 if (--default_miss->refcount) 66 return; 67 68 mlx5dr_cmd_miss_ft_destroy(default_miss); 69 70 simple_free(default_miss); 71 ctx->common_res[tbl_type].default_miss = NULL; 72 } 73 74 static int 75 mlx5dr_table_connect_to_default_miss_tbl(struct mlx5dr_table *tbl, 76 struct mlx5dr_devx_obj *ft) 77 { 78 struct mlx5dr_cmd_ft_modify_attr ft_attr = {0}; 79 int ret; 80 81 assert(tbl->type == MLX5DR_TABLE_TYPE_FDB); 82 83 mlx5dr_cmd_set_attr_connect_miss_tbl(tbl->ctx, 84 tbl->fw_ft_type, 85 tbl->type, 86 &ft_attr); 87 88 /* Connect to next */ 89 ret = mlx5dr_cmd_flow_table_modify(ft, &ft_attr); 90 if (ret) { 91 DR_LOG(ERR, "Failed to connect FT to default FDB FT"); 92 return errno; 93 } 94 95 return 0; 96 } 97 98 struct mlx5dr_devx_obj * 99 mlx5dr_table_create_default_ft(struct mlx5dr_table *tbl) 100 { 101 struct mlx5dr_cmd_ft_create_attr ft_attr = {0}; 102 struct mlx5dr_devx_obj *ft_obj; 103 int ret; 104 105 mlx5dr_table_init_next_ft_attr(tbl, &ft_attr); 106 107 ft_obj = mlx5dr_cmd_flow_table_create(tbl->ctx->ibv_ctx, &ft_attr); 108 if (ft_obj && tbl->type == MLX5DR_TABLE_TYPE_FDB) { 109 /* Take/create ref over the default miss */ 110 ret = mlx5dr_table_up_default_fdb_miss_tbl(tbl); 111 if (ret) { 112 DR_LOG(ERR, "Failed to get default fdb miss"); 113 goto free_ft_obj; 114 } 115 ret = mlx5dr_table_connect_to_default_miss_tbl(tbl, ft_obj); 116 if (ret) { 117 DR_LOG(ERR, "Failed connecting to default miss tbl"); 118 goto down_miss_tbl; 119 } 120 } 121 122 return ft_obj; 123 124 down_miss_tbl: 125 mlx5dr_table_down_default_fdb_miss_tbl(tbl); 126 free_ft_obj: 127 mlx5dr_cmd_destroy_obj(ft_obj); 128 return NULL; 129 } 130 131 void mlx5dr_table_destroy_default_ft(struct mlx5dr_table *tbl, 132 struct mlx5dr_devx_obj *ft_obj) 133 { 134 mlx5dr_cmd_destroy_obj(ft_obj); 135 mlx5dr_table_down_default_fdb_miss_tbl(tbl); 136 } 137 138 static int mlx5dr_table_init(struct mlx5dr_table *tbl) 139 { 140 struct mlx5dr_context *ctx = tbl->ctx; 141 int ret; 142 143 if (mlx5dr_table_is_root(tbl)) 144 return 0; 145 146 if (!(tbl->ctx->flags & MLX5DR_CONTEXT_FLAG_HWS_SUPPORT)) { 147 DR_LOG(ERR, "HWS not supported, cannot create mlx5dr_table"); 148 rte_errno = EOPNOTSUPP; 149 return rte_errno; 150 } 151 152 switch (tbl->type) { 153 case MLX5DR_TABLE_TYPE_NIC_RX: 154 tbl->fw_ft_type = FS_FT_NIC_RX; 155 break; 156 case MLX5DR_TABLE_TYPE_NIC_TX: 157 tbl->fw_ft_type = FS_FT_NIC_TX; 158 break; 159 case MLX5DR_TABLE_TYPE_FDB: 160 tbl->fw_ft_type = FS_FT_FDB; 161 break; 162 default: 163 assert(0); 164 break; 165 } 166 167 pthread_spin_lock(&ctx->ctrl_lock); 168 tbl->ft = mlx5dr_table_create_default_ft(tbl); 169 if (!tbl->ft) { 170 DR_LOG(ERR, "Failed to create flow table devx object"); 171 pthread_spin_unlock(&ctx->ctrl_lock); 172 return rte_errno; 173 } 174 175 ret = mlx5dr_action_get_default_stc(ctx, tbl->type); 176 if (ret) 177 goto tbl_destroy; 178 pthread_spin_unlock(&ctx->ctrl_lock); 179 180 return 0; 181 182 tbl_destroy: 183 mlx5dr_table_destroy_default_ft(tbl, tbl->ft); 184 pthread_spin_unlock(&ctx->ctrl_lock); 185 return rte_errno; 186 } 187 188 static void mlx5dr_table_uninit(struct mlx5dr_table *tbl) 189 { 190 if (mlx5dr_table_is_root(tbl)) 191 return; 192 pthread_spin_lock(&tbl->ctx->ctrl_lock); 193 mlx5dr_action_put_default_stc(tbl->ctx, tbl->type); 194 mlx5dr_table_destroy_default_ft(tbl, tbl->ft); 195 pthread_spin_unlock(&tbl->ctx->ctrl_lock); 196 } 197 198 struct mlx5dr_table *mlx5dr_table_create(struct mlx5dr_context *ctx, 199 struct mlx5dr_table_attr *attr) 200 { 201 struct mlx5dr_table *tbl; 202 int ret; 203 204 if (attr->type > MLX5DR_TABLE_TYPE_FDB) { 205 DR_LOG(ERR, "Invalid table type %d", attr->type); 206 return NULL; 207 } 208 209 tbl = simple_malloc(sizeof(*tbl)); 210 if (!tbl) { 211 rte_errno = ENOMEM; 212 return NULL; 213 } 214 215 tbl->ctx = ctx; 216 tbl->type = attr->type; 217 tbl->level = attr->level; 218 LIST_INIT(&tbl->head); 219 220 ret = mlx5dr_table_init(tbl); 221 if (ret) { 222 DR_LOG(ERR, "Failed to initialise table"); 223 goto free_tbl; 224 } 225 226 pthread_spin_lock(&ctx->ctrl_lock); 227 LIST_INSERT_HEAD(&ctx->head, tbl, next); 228 pthread_spin_unlock(&ctx->ctrl_lock); 229 230 return tbl; 231 232 free_tbl: 233 simple_free(tbl); 234 return NULL; 235 } 236 237 int mlx5dr_table_destroy(struct mlx5dr_table *tbl) 238 { 239 struct mlx5dr_context *ctx = tbl->ctx; 240 241 pthread_spin_lock(&ctx->ctrl_lock); 242 LIST_REMOVE(tbl, next); 243 pthread_spin_unlock(&ctx->ctrl_lock); 244 mlx5dr_table_uninit(tbl); 245 simple_free(tbl); 246 247 return 0; 248 } 249