1193323Sed// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB 2193323Sed/* Copyright (c) 2020, Mellanox Technologies inc. All rights reserved. */ 3193323Sed 4193323Sed#include <mlx5_core.h> 5193323Sed#include "en_accel/fs_tcp.h" 6193323Sed#include "fs_core.h" 7193323Sed 8193323Sedenum accel_fs_tcp_type { 9193323Sed ACCEL_FS_IPV4_TCP, 10193323Sed ACCEL_FS_IPV6_TCP, 11193323Sed ACCEL_FS_TCP_NUM_TYPES, 12193323Sed}; 13193323Sed 14193323Sedstruct mlx5e_accel_fs_tcp { 15193323Sed struct mlx5e_flow_table tables[ACCEL_FS_TCP_NUM_TYPES]; 16193323Sed struct mlx5_flow_handle *default_rules[ACCEL_FS_TCP_NUM_TYPES]; 17193323Sed}; 18198090Srdivacky 19193323Sedstatic enum mlx5_traffic_types fs_accel2tt(enum accel_fs_tcp_type i) 20206083Srdivacky{ 21206083Srdivacky switch (i) { 22206083Srdivacky case ACCEL_FS_IPV4_TCP: 23193323Sed return MLX5_TT_IPV4_TCP; 24193323Sed default: /* ACCEL_FS_IPV6_TCP */ 25198090Srdivacky return MLX5_TT_IPV6_TCP; 26206083Srdivacky } 27198090Srdivacky} 28193323Sed 29193323Sedstatic void accel_fs_tcp_set_ipv4_flow(struct mlx5_flow_spec *spec, struct sock *sk) 30193323Sed{ 31193323Sed MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.ip_protocol); 32193323Sed MLX5_SET(fte_match_param, spec->match_value, outer_headers.ip_protocol, IPPROTO_TCP); 33198090Srdivacky MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.ip_version); 34193323Sed MLX5_SET(fte_match_param, spec->match_value, outer_headers.ip_version, 4); 35193323Sed memcpy(MLX5_ADDR_OF(fte_match_param, spec->match_value, 36193323Sed outer_headers.src_ipv4_src_ipv6.ipv4_layout.ipv4), 37193323Sed &inet_sk(sk)->inet_daddr, 4); 38193323Sed memcpy(MLX5_ADDR_OF(fte_match_param, spec->match_value, 39193323Sed outer_headers.dst_ipv4_dst_ipv6.ipv4_layout.ipv4), 40193323Sed &inet_sk(sk)->inet_rcv_saddr, 4); 41193323Sed MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, 42193323Sed outer_headers.src_ipv4_src_ipv6.ipv4_layout.ipv4); 43193323Sed MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, 44193323Sed outer_headers.dst_ipv4_dst_ipv6.ipv4_layout.ipv4); 45193323Sed} 46193323Sed 47193323Sed#if IS_ENABLED(CONFIG_IPV6) 48193323Sedstatic void accel_fs_tcp_set_ipv6_flow(struct mlx5_flow_spec *spec, struct sock *sk) 49193323Sed{ 50193323Sed MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.ip_protocol); 51193323Sed MLX5_SET(fte_match_param, spec->match_value, outer_headers.ip_protocol, IPPROTO_TCP); 52193323Sed MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.ip_version); 53193323Sed MLX5_SET(fte_match_param, spec->match_value, outer_headers.ip_version, 6); 54193323Sed memcpy(MLX5_ADDR_OF(fte_match_param, spec->match_value, 55193323Sed outer_headers.src_ipv4_src_ipv6.ipv6_layout.ipv6), 56193323Sed &sk->sk_v6_daddr, 16); 57193323Sed memcpy(MLX5_ADDR_OF(fte_match_param, spec->match_value, 58193323Sed outer_headers.dst_ipv4_dst_ipv6.ipv6_layout.ipv6), 59193323Sed &inet6_sk(sk)->saddr, 16); 60193323Sed memset(MLX5_ADDR_OF(fte_match_param, spec->match_criteria, 61202878Srdivacky outer_headers.src_ipv4_src_ipv6.ipv6_layout.ipv6), 62202878Srdivacky 0xff, 16); 63202878Srdivacky memset(MLX5_ADDR_OF(fte_match_param, spec->match_criteria, 64193323Sed outer_headers.dst_ipv4_dst_ipv6.ipv6_layout.ipv6), 65193323Sed 0xff, 16); 66198090Srdivacky} 67193323Sed#endif 68193323Sed 69193323Sedvoid mlx5e_accel_fs_del_sk(struct mlx5_flow_handle *rule) 70193323Sed{ 71193323Sed mlx5_del_flow_rules(rule); 72193323Sed} 73193323Sed 74193323Sedstruct mlx5_flow_handle *mlx5e_accel_fs_add_sk(struct mlx5e_flow_steering *fs, 75198090Srdivacky struct sock *sk, u32 tirn, 76198090Srdivacky uint32_t flow_tag) 77193323Sed{ 78193323Sed struct mlx5e_accel_fs_tcp *fs_tcp = mlx5e_fs_get_accel_tcp(fs); 79193323Sed struct mlx5_flow_destination dest = {}; 80193323Sed struct mlx5e_flow_table *ft = NULL; 81193323Sed MLX5_DECLARE_FLOW_ACT(flow_act); 82198090Srdivacky struct mlx5_flow_handle *flow; 83198090Srdivacky struct mlx5_flow_spec *spec; 84198090Srdivacky 85198090Srdivacky spec = kvzalloc(sizeof(*spec), GFP_KERNEL); 86198090Srdivacky if (!spec) 87198090Srdivacky return ERR_PTR(-ENOMEM); 88193323Sed 89193323Sed spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; 90198090Srdivacky 91198090Srdivacky switch (sk->sk_family) { 92198090Srdivacky case AF_INET: 93198090Srdivacky accel_fs_tcp_set_ipv4_flow(spec, sk); 94198090Srdivacky ft = &fs_tcp->tables[ACCEL_FS_IPV4_TCP]; 95198090Srdivacky fs_dbg(fs, "%s flow is %pI4:%d -> %pI4:%d\n", __func__, 96198090Srdivacky &inet_sk(sk)->inet_rcv_saddr, 97202878Srdivacky inet_sk(sk)->inet_sport, 98202878Srdivacky &inet_sk(sk)->inet_daddr, 99202878Srdivacky inet_sk(sk)->inet_dport); 100202878Srdivacky break; 101198090Srdivacky#if IS_ENABLED(CONFIG_IPV6) 102198090Srdivacky case AF_INET6: 103198090Srdivacky if (!ipv6_only_sock(sk) && 104198090Srdivacky ipv6_addr_type(&sk->sk_v6_daddr) == IPV6_ADDR_MAPPED) { 105198090Srdivacky accel_fs_tcp_set_ipv4_flow(spec, sk); 106206083Srdivacky ft = &fs_tcp->tables[ACCEL_FS_IPV4_TCP]; 107206083Srdivacky } else { 108206083Srdivacky accel_fs_tcp_set_ipv6_flow(spec, sk); 109206083Srdivacky ft = &fs_tcp->tables[ACCEL_FS_IPV6_TCP]; 110198090Srdivacky } 111198090Srdivacky break; 112198090Srdivacky#endif 113198090Srdivacky default: 114198090Srdivacky break; 115198090Srdivacky } 116198090Srdivacky 117198090Srdivacky if (!ft) { 118198090Srdivacky flow = ERR_PTR(-EINVAL); 119198090Srdivacky goto out; 120198090Srdivacky } 121198090Srdivacky 122202878Srdivacky MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, 123202878Srdivacky outer_headers.tcp_dport); 124202878Srdivacky MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, 125202878Srdivacky outer_headers.tcp_sport); 126198090Srdivacky MLX5_SET(fte_match_param, spec->match_value, outer_headers.tcp_dport, 127198090Srdivacky ntohs(inet_sk(sk)->inet_sport)); 128198090Srdivacky MLX5_SET(fte_match_param, spec->match_value, outer_headers.tcp_sport, 129198090Srdivacky ntohs(inet_sk(sk)->inet_dport)); 130206083Srdivacky 131198090Srdivacky dest.type = MLX5_FLOW_DESTINATION_TYPE_TIR; 132198090Srdivacky dest.tir_num = tirn; 133198090Srdivacky if (flow_tag != MLX5_FS_DEFAULT_FLOW_TAG) { 134198090Srdivacky spec->flow_context.flow_tag = flow_tag; 135198090Srdivacky spec->flow_context.flags = FLOW_CONTEXT_HAS_TAG; 136198090Srdivacky } 137198090Srdivacky 138201360Srdivacky flow = mlx5_add_flow_rules(ft->t, spec, &flow_act, &dest, 1); 139198090Srdivacky 140198090Srdivacky if (IS_ERR(flow)) 141198090Srdivacky fs_err(fs, "mlx5_add_flow_rules() failed, flow is %ld\n", PTR_ERR(flow)); 142198090Srdivacky 143193323Sedout: 144193323Sed kvfree(spec); 145198090Srdivacky return flow; 146198090Srdivacky} 147198090Srdivacky 148198090Srdivackystatic int accel_fs_tcp_add_default_rule(struct mlx5e_flow_steering *fs, 149198090Srdivacky enum accel_fs_tcp_type type) 150198090Srdivacky{ 151198090Srdivacky struct mlx5e_accel_fs_tcp *fs_tcp = mlx5e_fs_get_accel_tcp(fs); 152198090Srdivacky struct mlx5_ttc_table *ttc = mlx5e_fs_get_ttc(fs, false); 153198090Srdivacky struct mlx5e_flow_table *accel_fs_t; 154198090Srdivacky struct mlx5_flow_destination dest; 155201360Srdivacky MLX5_DECLARE_FLOW_ACT(flow_act); 156198090Srdivacky struct mlx5_flow_handle *rule; 157198090Srdivacky int err = 0; 158198090Srdivacky 159198090Srdivacky accel_fs_t = &fs_tcp->tables[type]; 160198090Srdivacky 161198090Srdivacky dest = mlx5_ttc_get_default_dest(ttc, fs_accel2tt(type)); 162198090Srdivacky rule = mlx5_add_flow_rules(accel_fs_t->t, NULL, &flow_act, &dest, 1); 163198090Srdivacky if (IS_ERR(rule)) { 164198090Srdivacky err = PTR_ERR(rule); 165198090Srdivacky fs_err(fs, "%s: add default rule failed, accel_fs type=%d, err %d\n", 166198090Srdivacky __func__, type, err); 167198090Srdivacky return err; 168198090Srdivacky } 169198090Srdivacky 170198090Srdivacky fs_tcp->default_rules[type] = rule; 171198090Srdivacky return 0; 172198090Srdivacky} 173198090Srdivacky 174198090Srdivacky#define MLX5E_ACCEL_FS_TCP_NUM_GROUPS (2) 175198090Srdivacky#define MLX5E_ACCEL_FS_TCP_GROUP1_SIZE (BIT(16) - 1) 176198090Srdivacky#define MLX5E_ACCEL_FS_TCP_GROUP2_SIZE (BIT(0)) 177198090Srdivacky#define MLX5E_ACCEL_FS_TCP_TABLE_SIZE (MLX5E_ACCEL_FS_TCP_GROUP1_SIZE +\ 178198090Srdivacky MLX5E_ACCEL_FS_TCP_GROUP2_SIZE) 179198090Srdivackystatic int accel_fs_tcp_create_groups(struct mlx5e_flow_table *ft, 180198090Srdivacky enum accel_fs_tcp_type type) 181198090Srdivacky{ 182198090Srdivacky int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in); 183198090Srdivacky void *outer_headers_c; 184198090Srdivacky int ix = 0; 185198090Srdivacky u32 *in; 186198090Srdivacky int err; 187198090Srdivacky u8 *mc; 188198090Srdivacky 189198090Srdivacky ft->g = kcalloc(MLX5E_ACCEL_FS_TCP_NUM_GROUPS, sizeof(*ft->g), GFP_KERNEL); 190198090Srdivacky in = kvzalloc(inlen, GFP_KERNEL); 191198090Srdivacky if (!in || !ft->g) { 192198090Srdivacky kfree(ft->g); 193198090Srdivacky ft->g = NULL; 194198090Srdivacky kvfree(in); 195198090Srdivacky return -ENOMEM; 196198090Srdivacky } 197198090Srdivacky 198198090Srdivacky mc = MLX5_ADDR_OF(create_flow_group_in, in, match_criteria); 199198090Srdivacky outer_headers_c = MLX5_ADDR_OF(fte_match_param, mc, outer_headers); 200198090Srdivacky MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, outer_headers_c, ip_protocol); 201198090Srdivacky MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, outer_headers_c, ip_version); 202198090Srdivacky 203198090Srdivacky switch (type) { 204198090Srdivacky case ACCEL_FS_IPV4_TCP: 205198090Srdivacky case ACCEL_FS_IPV6_TCP: 206198090Srdivacky MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, outer_headers_c, tcp_dport); 207198090Srdivacky MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, outer_headers_c, tcp_sport); 208198090Srdivacky break; 209198090Srdivacky default: 210198090Srdivacky err = -EINVAL; 211198090Srdivacky goto out; 212198090Srdivacky } 213198090Srdivacky 214198090Srdivacky switch (type) { 215198090Srdivacky case ACCEL_FS_IPV4_TCP: 216198090Srdivacky MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, outer_headers_c, 217198090Srdivacky src_ipv4_src_ipv6.ipv4_layout.ipv4); 218198090Srdivacky MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, outer_headers_c, 219198090Srdivacky dst_ipv4_dst_ipv6.ipv4_layout.ipv4); 220198090Srdivacky break; 221198090Srdivacky case ACCEL_FS_IPV6_TCP: 222198090Srdivacky memset(MLX5_ADDR_OF(fte_match_set_lyr_2_4, outer_headers_c, 223198090Srdivacky src_ipv4_src_ipv6.ipv6_layout.ipv6), 224198090Srdivacky 0xff, 16); 225198090Srdivacky memset(MLX5_ADDR_OF(fte_match_set_lyr_2_4, outer_headers_c, 226198090Srdivacky dst_ipv4_dst_ipv6.ipv6_layout.ipv6), 227198090Srdivacky 0xff, 16); 228198090Srdivacky break; 229198090Srdivacky default: 230198090Srdivacky err = -EINVAL; 231198090Srdivacky goto out; 232198090Srdivacky } 233198090Srdivacky 234198090Srdivacky MLX5_SET_CFG(in, match_criteria_enable, MLX5_MATCH_OUTER_HEADERS); 235198090Srdivacky MLX5_SET_CFG(in, start_flow_index, ix); 236198090Srdivacky ix += MLX5E_ACCEL_FS_TCP_GROUP1_SIZE; 237198090Srdivacky MLX5_SET_CFG(in, end_flow_index, ix - 1); 238198090Srdivacky ft->g[ft->num_groups] = mlx5_create_flow_group(ft->t, in); 239198090Srdivacky if (IS_ERR(ft->g[ft->num_groups])) 240198090Srdivacky goto err; 241198090Srdivacky ft->num_groups++; 242198090Srdivacky 243198090Srdivacky /* Default Flow Group */ 244198090Srdivacky memset(in, 0, inlen); 245198090Srdivacky MLX5_SET_CFG(in, start_flow_index, ix); 246198090Srdivacky ix += MLX5E_ACCEL_FS_TCP_GROUP2_SIZE; 247198090Srdivacky MLX5_SET_CFG(in, end_flow_index, ix - 1); 248198090Srdivacky ft->g[ft->num_groups] = mlx5_create_flow_group(ft->t, in); 249198090Srdivacky if (IS_ERR(ft->g[ft->num_groups])) 250198090Srdivacky goto err; 251198090Srdivacky ft->num_groups++; 252198090Srdivacky 253198090Srdivacky kvfree(in); 254198090Srdivacky return 0; 255198090Srdivacky 256198090Srdivackyerr: 257198090Srdivacky err = PTR_ERR(ft->g[ft->num_groups]); 258198090Srdivacky ft->g[ft->num_groups] = NULL; 259198090Srdivackyout: 260198090Srdivacky kvfree(in); 261198090Srdivacky 262198090Srdivacky return err; 263198090Srdivacky} 264198090Srdivacky 265198090Srdivackystatic int accel_fs_tcp_create_table(struct mlx5e_flow_steering *fs, enum accel_fs_tcp_type type) 266198090Srdivacky{ 267198090Srdivacky struct mlx5e_accel_fs_tcp *accel_tcp = mlx5e_fs_get_accel_tcp(fs); 268198090Srdivacky struct mlx5_flow_namespace *ns = mlx5e_fs_get_ns(fs, false); 269198090Srdivacky struct mlx5e_flow_table *ft = &accel_tcp->tables[type]; 270198090Srdivacky struct mlx5_flow_table_attr ft_attr = {}; 271198090Srdivacky int err; 272198090Srdivacky 273198090Srdivacky ft->num_groups = 0; 274198090Srdivacky 275198090Srdivacky ft_attr.max_fte = MLX5E_ACCEL_FS_TCP_TABLE_SIZE; 276198090Srdivacky ft_attr.level = MLX5E_ACCEL_FS_TCP_FT_LEVEL; 277198090Srdivacky ft_attr.prio = MLX5E_NIC_PRIO; 278198090Srdivacky 279198090Srdivacky ft->t = mlx5_create_flow_table(ns, &ft_attr); 280198090Srdivacky if (IS_ERR(ft->t)) { 281198090Srdivacky err = PTR_ERR(ft->t); 282198090Srdivacky ft->t = NULL; 283198090Srdivacky return err; 284198090Srdivacky } 285198090Srdivacky 286198090Srdivacky fs_dbg(fs, "Created fs accel table id %u level %u\n", 287198090Srdivacky ft->t->id, ft->t->level); 288198090Srdivacky 289201360Srdivacky err = accel_fs_tcp_create_groups(ft, type); 290198090Srdivacky if (err) 291198090Srdivacky goto err; 292198090Srdivacky 293201360Srdivacky err = accel_fs_tcp_add_default_rule(fs, type); 294198090Srdivacky if (err) 295198090Srdivacky goto err; 296198090Srdivacky 297198090Srdivacky return 0; 298193323Sederr: 299193323Sed mlx5e_destroy_flow_table(ft); 300193323Sed return err; 301193323Sed} 302193323Sed 303193323Sedstatic int accel_fs_tcp_disable(struct mlx5e_flow_steering *fs) 304198090Srdivacky{ 305198090Srdivacky struct mlx5_ttc_table *ttc = mlx5e_fs_get_ttc(fs, false); 306198090Srdivacky int err, i; 307198090Srdivacky 308198090Srdivacky for (i = 0; i < ACCEL_FS_TCP_NUM_TYPES; i++) { 309198090Srdivacky /* Modify ttc rules destination to point back to the indir TIRs */ 310198090Srdivacky err = mlx5_ttc_fwd_default_dest(ttc, fs_accel2tt(i)); 311198090Srdivacky if (err) { 312198090Srdivacky fs_err(fs, 313198090Srdivacky "%s: modify ttc[%d] default destination failed, err(%d)\n", 314198090Srdivacky __func__, fs_accel2tt(i), err); 315198090Srdivacky return err; 316198090Srdivacky } 317198090Srdivacky } 318198090Srdivacky 319198090Srdivacky return 0; 320198090Srdivacky} 321198090Srdivacky 322198090Srdivackystatic int accel_fs_tcp_enable(struct mlx5e_flow_steering *fs) 323198090Srdivacky{ 324198090Srdivacky struct mlx5e_accel_fs_tcp *accel_tcp = mlx5e_fs_get_accel_tcp(fs); 325198090Srdivacky struct mlx5_ttc_table *ttc = mlx5e_fs_get_ttc(fs, false); 326198090Srdivacky struct mlx5_flow_destination dest = {}; 327198090Srdivacky int err, i; 328193323Sed 329198090Srdivacky dest.type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE; 330198090Srdivacky for (i = 0; i < ACCEL_FS_TCP_NUM_TYPES; i++) { 331198090Srdivacky dest.ft = accel_tcp->tables[i].t; 332198090Srdivacky 333198090Srdivacky /* Modify ttc rules destination to point on the accel_fs FTs */ 334198090Srdivacky err = mlx5_ttc_fwd_dest(ttc, fs_accel2tt(i), &dest); 335198090Srdivacky if (err) { 336198090Srdivacky fs_err(fs, "%s: modify ttc[%d] destination to accel failed, err(%d)\n", 337198090Srdivacky __func__, fs_accel2tt(i), err); 338198090Srdivacky return err; 339198090Srdivacky } 340198090Srdivacky } 341198090Srdivacky return 0; 342198090Srdivacky} 343193323Sed 344193323Sedstatic void accel_fs_tcp_destroy_table(struct mlx5e_flow_steering *fs, int i) 345193323Sed{ 346193323Sed struct mlx5e_accel_fs_tcp *fs_tcp = mlx5e_fs_get_accel_tcp(fs); 347198090Srdivacky 348198090Srdivacky if (IS_ERR_OR_NULL(fs_tcp->tables[i].t)) 349193323Sed return; 350193323Sed 351193323Sed mlx5_del_flow_rules(fs_tcp->default_rules[i]); 352193323Sed mlx5e_destroy_flow_table(&fs_tcp->tables[i]); 353193323Sed fs_tcp->tables[i].t = NULL; 354193323Sed} 355193323Sed 356193323Sedvoid mlx5e_accel_fs_tcp_destroy(struct mlx5e_flow_steering *fs) 357193323Sed{ 358193323Sed struct mlx5e_accel_fs_tcp *accel_tcp = mlx5e_fs_get_accel_tcp(fs); 359198090Srdivacky int i; 360198090Srdivacky 361198090Srdivacky if (!accel_tcp) 362198090Srdivacky return; 363198090Srdivacky 364193323Sed accel_fs_tcp_disable(fs); 365193323Sed 366193323Sed for (i = 0; i < ACCEL_FS_TCP_NUM_TYPES; i++) 367193323Sed accel_fs_tcp_destroy_table(fs, i); 368193323Sed 369193323Sed kfree(accel_tcp); 370193323Sed mlx5e_fs_set_accel_tcp(fs, NULL); 371193323Sed} 372202878Srdivacky 373202878Srdivackyint mlx5e_accel_fs_tcp_create(struct mlx5e_flow_steering *fs) 374202878Srdivacky{ 375202878Srdivacky struct mlx5e_accel_fs_tcp *accel_tcp; 376202878Srdivacky int i, err; 377193323Sed 378202878Srdivacky if (!MLX5_CAP_FLOWTABLE_NIC_RX(mlx5e_fs_get_mdev(fs), ft_field_support.outer_ip_version)) 379193323Sed return -EOPNOTSUPP; 380193323Sed 381193323Sed accel_tcp = kzalloc(sizeof(*accel_tcp), GFP_KERNEL); 382193323Sed if (!accel_tcp) 383193323Sed return -ENOMEM; 384193323Sed mlx5e_fs_set_accel_tcp(fs, accel_tcp); 385193323Sed 386193323Sed for (i = 0; i < ACCEL_FS_TCP_NUM_TYPES; i++) { 387202878Srdivacky err = accel_fs_tcp_create_table(fs, i); 388202878Srdivacky if (err) 389202878Srdivacky goto err_destroy_tables; 390202878Srdivacky } 391202878Srdivacky 392193323Sed err = accel_fs_tcp_enable(fs); 393202878Srdivacky if (err) 394193323Sed goto err_destroy_tables; 395193323Sed 396193323Sed return 0; 397193323Sed 398193323Sederr_destroy_tables: 399193323Sed while (--i >= 0) 400193323Sed accel_fs_tcp_destroy_table(fs, i); 401193323Sed kfree(accel_tcp); 402193323Sed mlx5e_fs_set_accel_tcp(fs, NULL); 403193323Sed return err; 404193323Sed} 405193323Sed