11c80bd68SAya Levin // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB 21c80bd68SAya Levin /* Copyright (c) 2021, Mellanox Technologies inc. All rights reserved. */ 31c80bd68SAya Levin 41c80bd68SAya Levin #include "en/fs_tt_redirect.h" 51c80bd68SAya Levin #include "fs_core.h" 64e0ecc17SLama Kayal #include "mlx5_core.h" 71c80bd68SAya Levin 81c80bd68SAya Levin enum fs_udp_type { 91c80bd68SAya Levin FS_IPV4_UDP, 101c80bd68SAya Levin FS_IPV6_UDP, 111c80bd68SAya Levin FS_UDP_NUM_TYPES, 121c80bd68SAya Levin }; 131c80bd68SAya Levin 141c80bd68SAya Levin struct mlx5e_fs_udp { 151c80bd68SAya Levin struct mlx5e_flow_table tables[FS_UDP_NUM_TYPES]; 161c80bd68SAya Levin struct mlx5_flow_handle *default_rules[FS_UDP_NUM_TYPES]; 171c80bd68SAya Levin int ref_cnt; 181c80bd68SAya Levin }; 191c80bd68SAya Levin 200f575c20SAya Levin struct mlx5e_fs_any { 210f575c20SAya Levin struct mlx5e_flow_table table; 220f575c20SAya Levin struct mlx5_flow_handle *default_rule; 230f575c20SAya Levin int ref_cnt; 240f575c20SAya Levin }; 250f575c20SAya Levin 261c80bd68SAya Levin static char *fs_udp_type2str(enum fs_udp_type i) 271c80bd68SAya Levin { 281c80bd68SAya Levin switch (i) { 291c80bd68SAya Levin case FS_IPV4_UDP: 301c80bd68SAya Levin return "UDP v4"; 311c80bd68SAya Levin default: /* FS_IPV6_UDP */ 321c80bd68SAya Levin return "UDP v6"; 331c80bd68SAya Levin } 341c80bd68SAya Levin } 351c80bd68SAya Levin 36d443c6f6SMaor Gottlieb static enum mlx5_traffic_types fs_udp2tt(enum fs_udp_type i) 371c80bd68SAya Levin { 381c80bd68SAya Levin switch (i) { 391c80bd68SAya Levin case FS_IPV4_UDP: 40d443c6f6SMaor Gottlieb return MLX5_TT_IPV4_UDP; 411c80bd68SAya Levin default: /* FS_IPV6_UDP */ 42d443c6f6SMaor Gottlieb return MLX5_TT_IPV6_UDP; 431c80bd68SAya Levin } 441c80bd68SAya Levin } 451c80bd68SAya Levin 46d443c6f6SMaor Gottlieb static enum fs_udp_type tt2fs_udp(enum mlx5_traffic_types i) 471c80bd68SAya Levin { 481c80bd68SAya Levin switch (i) { 49d443c6f6SMaor Gottlieb case MLX5_TT_IPV4_UDP: 501c80bd68SAya Levin return FS_IPV4_UDP; 51d443c6f6SMaor Gottlieb case MLX5_TT_IPV6_UDP: 521c80bd68SAya Levin return FS_IPV6_UDP; 531c80bd68SAya Levin default: 541c80bd68SAya Levin return FS_UDP_NUM_TYPES; 551c80bd68SAya Levin } 561c80bd68SAya Levin } 571c80bd68SAya Levin 581c80bd68SAya Levin void mlx5e_fs_tt_redirect_del_rule(struct mlx5_flow_handle *rule) 591c80bd68SAya Levin { 601c80bd68SAya Levin mlx5_del_flow_rules(rule); 611c80bd68SAya Levin } 621c80bd68SAya Levin 631c80bd68SAya Levin static void fs_udp_set_dport_flow(struct mlx5_flow_spec *spec, enum fs_udp_type type, 641c80bd68SAya Levin u16 udp_dport) 651c80bd68SAya Levin { 661c80bd68SAya Levin spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; 671c80bd68SAya Levin MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.ip_protocol); 681c80bd68SAya Levin MLX5_SET(fte_match_param, spec->match_value, outer_headers.ip_protocol, IPPROTO_UDP); 691c80bd68SAya Levin MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.ip_version); 701c80bd68SAya Levin MLX5_SET(fte_match_param, spec->match_value, outer_headers.ip_version, 711c80bd68SAya Levin type == FS_IPV4_UDP ? 4 : 6); 721c80bd68SAya Levin MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.udp_dport); 731c80bd68SAya Levin MLX5_SET(fte_match_param, spec->match_value, outer_headers.udp_dport, udp_dport); 741c80bd68SAya Levin } 751c80bd68SAya Levin 761c80bd68SAya Levin struct mlx5_flow_handle * 774e0ecc17SLama Kayal mlx5e_fs_tt_redirect_udp_add_rule(struct mlx5e_flow_steering *fs, 78d443c6f6SMaor Gottlieb enum mlx5_traffic_types ttc_type, 791c80bd68SAya Levin u32 tir_num, u16 d_port) 801c80bd68SAya Levin { 814e0ecc17SLama Kayal struct mlx5e_fs_udp *fs_udp = mlx5e_fs_get_udp(fs); 821c80bd68SAya Levin enum fs_udp_type type = tt2fs_udp(ttc_type); 831c80bd68SAya Levin struct mlx5_flow_destination dest = {}; 841c80bd68SAya Levin struct mlx5_flow_table *ft = NULL; 851c80bd68SAya Levin MLX5_DECLARE_FLOW_ACT(flow_act); 861c80bd68SAya Levin struct mlx5_flow_handle *rule; 871c80bd68SAya Levin struct mlx5_flow_spec *spec; 881c80bd68SAya Levin int err; 891c80bd68SAya Levin 901c80bd68SAya Levin if (type == FS_UDP_NUM_TYPES) 911c80bd68SAya Levin return ERR_PTR(-EINVAL); 921c80bd68SAya Levin 931c80bd68SAya Levin spec = kvzalloc(sizeof(*spec), GFP_KERNEL); 941c80bd68SAya Levin if (!spec) 951c80bd68SAya Levin return ERR_PTR(-ENOMEM); 961c80bd68SAya Levin 971c80bd68SAya Levin ft = fs_udp->tables[type].t; 981c80bd68SAya Levin 991c80bd68SAya Levin fs_udp_set_dport_flow(spec, type, d_port); 1001c80bd68SAya Levin dest.type = MLX5_FLOW_DESTINATION_TYPE_TIR; 1011c80bd68SAya Levin dest.tir_num = tir_num; 1021c80bd68SAya Levin 1031c80bd68SAya Levin rule = mlx5_add_flow_rules(ft, spec, &flow_act, &dest, 1); 1041c80bd68SAya Levin kvfree(spec); 1051c80bd68SAya Levin 1061c80bd68SAya Levin if (IS_ERR(rule)) { 1071c80bd68SAya Levin err = PTR_ERR(rule); 10893a07599SLama Kayal fs_err(fs, "%s: add %s rule failed, err %d\n", 1091c80bd68SAya Levin __func__, fs_udp_type2str(type), err); 1101c80bd68SAya Levin } 1111c80bd68SAya Levin return rule; 1121c80bd68SAya Levin } 1131c80bd68SAya Levin 1144e0ecc17SLama Kayal static int fs_udp_add_default_rule(struct mlx5e_flow_steering *fs, enum fs_udp_type type) 1151c80bd68SAya Levin { 1164e0ecc17SLama Kayal struct mlx5_ttc_table *ttc = mlx5e_fs_get_ttc(fs, false); 1174e0ecc17SLama Kayal struct mlx5e_fs_udp *fs_udp = mlx5e_fs_get_udp(fs); 1181c80bd68SAya Levin struct mlx5e_flow_table *fs_udp_t; 1191c80bd68SAya Levin struct mlx5_flow_destination dest; 1201c80bd68SAya Levin MLX5_DECLARE_FLOW_ACT(flow_act); 1211c80bd68SAya Levin struct mlx5_flow_handle *rule; 1221c80bd68SAya Levin int err; 1231c80bd68SAya Levin 1241c80bd68SAya Levin fs_udp_t = &fs_udp->tables[type]; 1251c80bd68SAya Levin 126f52f2faeSLama Kayal dest = mlx5_ttc_get_default_dest(ttc, fs_udp2tt(type)); 1271c80bd68SAya Levin rule = mlx5_add_flow_rules(fs_udp_t->t, NULL, &flow_act, &dest, 1); 1281c80bd68SAya Levin if (IS_ERR(rule)) { 1291c80bd68SAya Levin err = PTR_ERR(rule); 13093a07599SLama Kayal fs_err(fs, "%s: add default rule failed, fs type=%d, err %d\n", 1311c80bd68SAya Levin __func__, type, err); 1321c80bd68SAya Levin return err; 1331c80bd68SAya Levin } 1341c80bd68SAya Levin 1351c80bd68SAya Levin fs_udp->default_rules[type] = rule; 1361c80bd68SAya Levin return 0; 1371c80bd68SAya Levin } 1381c80bd68SAya Levin 1391c80bd68SAya Levin #define MLX5E_FS_UDP_NUM_GROUPS (2) 1401c80bd68SAya Levin #define MLX5E_FS_UDP_GROUP1_SIZE (BIT(16)) 1411c80bd68SAya Levin #define MLX5E_FS_UDP_GROUP2_SIZE (BIT(0)) 1421c80bd68SAya Levin #define MLX5E_FS_UDP_TABLE_SIZE (MLX5E_FS_UDP_GROUP1_SIZE +\ 1431c80bd68SAya Levin MLX5E_FS_UDP_GROUP2_SIZE) 1441c80bd68SAya Levin static int fs_udp_create_groups(struct mlx5e_flow_table *ft, enum fs_udp_type type) 1451c80bd68SAya Levin { 1461c80bd68SAya Levin int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in); 1471c80bd68SAya Levin void *outer_headers_c; 1481c80bd68SAya Levin int ix = 0; 1491c80bd68SAya Levin u32 *in; 1501c80bd68SAya Levin int err; 1511c80bd68SAya Levin u8 *mc; 1521c80bd68SAya Levin 1531c80bd68SAya Levin ft->g = kcalloc(MLX5E_FS_UDP_NUM_GROUPS, sizeof(*ft->g), GFP_KERNEL); 1541c80bd68SAya Levin in = kvzalloc(inlen, GFP_KERNEL); 1551c80bd68SAya Levin if (!in || !ft->g) { 1561c80bd68SAya Levin kfree(ft->g); 1571c80bd68SAya Levin kvfree(in); 1581c80bd68SAya Levin return -ENOMEM; 1591c80bd68SAya Levin } 1601c80bd68SAya Levin 1611c80bd68SAya Levin mc = MLX5_ADDR_OF(create_flow_group_in, in, match_criteria); 1621c80bd68SAya Levin outer_headers_c = MLX5_ADDR_OF(fte_match_param, mc, outer_headers); 1631c80bd68SAya Levin MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, outer_headers_c, ip_protocol); 1641c80bd68SAya Levin MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, outer_headers_c, ip_version); 1651c80bd68SAya Levin 1661c80bd68SAya Levin switch (type) { 1671c80bd68SAya Levin case FS_IPV4_UDP: 1681c80bd68SAya Levin case FS_IPV6_UDP: 1691c80bd68SAya Levin MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, outer_headers_c, udp_dport); 1701c80bd68SAya Levin break; 1711c80bd68SAya Levin default: 1721c80bd68SAya Levin err = -EINVAL; 1731c80bd68SAya Levin goto out; 1741c80bd68SAya Levin } 1751c80bd68SAya Levin /* Match on udp protocol, Ipv4/6 and dport */ 1761c80bd68SAya Levin MLX5_SET_CFG(in, match_criteria_enable, MLX5_MATCH_OUTER_HEADERS); 1771c80bd68SAya Levin MLX5_SET_CFG(in, start_flow_index, ix); 1781c80bd68SAya Levin ix += MLX5E_FS_UDP_GROUP1_SIZE; 1791c80bd68SAya Levin MLX5_SET_CFG(in, end_flow_index, ix - 1); 1801c80bd68SAya Levin ft->g[ft->num_groups] = mlx5_create_flow_group(ft->t, in); 1811c80bd68SAya Levin if (IS_ERR(ft->g[ft->num_groups])) 1821c80bd68SAya Levin goto err; 1831c80bd68SAya Levin ft->num_groups++; 1841c80bd68SAya Levin 1851c80bd68SAya Levin /* Default Flow Group */ 1861c80bd68SAya Levin memset(in, 0, inlen); 1871c80bd68SAya Levin MLX5_SET_CFG(in, start_flow_index, ix); 1881c80bd68SAya Levin ix += MLX5E_FS_UDP_GROUP2_SIZE; 1891c80bd68SAya Levin MLX5_SET_CFG(in, end_flow_index, ix - 1); 1901c80bd68SAya Levin ft->g[ft->num_groups] = mlx5_create_flow_group(ft->t, in); 1911c80bd68SAya Levin if (IS_ERR(ft->g[ft->num_groups])) 1921c80bd68SAya Levin goto err; 1931c80bd68SAya Levin ft->num_groups++; 1941c80bd68SAya Levin 1951c80bd68SAya Levin kvfree(in); 1961c80bd68SAya Levin return 0; 1971c80bd68SAya Levin 1981c80bd68SAya Levin err: 1991c80bd68SAya Levin err = PTR_ERR(ft->g[ft->num_groups]); 2001c80bd68SAya Levin ft->g[ft->num_groups] = NULL; 2011c80bd68SAya Levin out: 2021c80bd68SAya Levin kvfree(in); 2031c80bd68SAya Levin 2041c80bd68SAya Levin return err; 2051c80bd68SAya Levin } 2061c80bd68SAya Levin 2074e0ecc17SLama Kayal static int fs_udp_create_table(struct mlx5e_flow_steering *fs, enum fs_udp_type type) 2081c80bd68SAya Levin { 2094e0ecc17SLama Kayal struct mlx5_flow_namespace *ns = mlx5e_fs_get_ns(fs, false); 2104e0ecc17SLama Kayal struct mlx5e_fs_udp *fs_udp = mlx5e_fs_get_udp(fs); 2111c80bd68SAya Levin struct mlx5_flow_table_attr ft_attr = {}; 2124e0ecc17SLama Kayal struct mlx5e_flow_table *ft; 2131c80bd68SAya Levin int err; 2141c80bd68SAya Levin 2154e0ecc17SLama Kayal ft = &fs_udp->tables[type]; 2161c80bd68SAya Levin ft->num_groups = 0; 2171c80bd68SAya Levin 2181c80bd68SAya Levin ft_attr.max_fte = MLX5E_FS_UDP_TABLE_SIZE; 2191c80bd68SAya Levin ft_attr.level = MLX5E_FS_TT_UDP_FT_LEVEL; 2201c80bd68SAya Levin ft_attr.prio = MLX5E_NIC_PRIO; 2211c80bd68SAya Levin 222f52f2faeSLama Kayal ft->t = mlx5_create_flow_table(ns, &ft_attr); 2231c80bd68SAya Levin if (IS_ERR(ft->t)) { 2241c80bd68SAya Levin err = PTR_ERR(ft->t); 2251c80bd68SAya Levin ft->t = NULL; 2261c80bd68SAya Levin return err; 2271c80bd68SAya Levin } 2281c80bd68SAya Levin 2294e0ecc17SLama Kayal mlx5_core_dbg(mlx5e_fs_get_mdev(fs), "Created fs %s table id %u level %u\n", 2301c80bd68SAya Levin fs_udp_type2str(type), ft->t->id, ft->t->level); 2311c80bd68SAya Levin 2321c80bd68SAya Levin err = fs_udp_create_groups(ft, type); 2331c80bd68SAya Levin if (err) 2341c80bd68SAya Levin goto err; 2351c80bd68SAya Levin 2364e0ecc17SLama Kayal err = fs_udp_add_default_rule(fs, type); 2371c80bd68SAya Levin if (err) 2381c80bd68SAya Levin goto err; 2391c80bd68SAya Levin 2401c80bd68SAya Levin return 0; 2411c80bd68SAya Levin 2421c80bd68SAya Levin err: 2431c80bd68SAya Levin mlx5e_destroy_flow_table(ft); 2441c80bd68SAya Levin return err; 2451c80bd68SAya Levin } 2461c80bd68SAya Levin 2471c80bd68SAya Levin static void fs_udp_destroy_table(struct mlx5e_fs_udp *fs_udp, int i) 2481c80bd68SAya Levin { 2491c80bd68SAya Levin if (IS_ERR_OR_NULL(fs_udp->tables[i].t)) 2501c80bd68SAya Levin return; 2511c80bd68SAya Levin 2521c80bd68SAya Levin mlx5_del_flow_rules(fs_udp->default_rules[i]); 2531c80bd68SAya Levin mlx5e_destroy_flow_table(&fs_udp->tables[i]); 2541c80bd68SAya Levin fs_udp->tables[i].t = NULL; 2551c80bd68SAya Levin } 2561c80bd68SAya Levin 2574e0ecc17SLama Kayal static int fs_udp_disable(struct mlx5e_flow_steering *fs) 2581c80bd68SAya Levin { 2594e0ecc17SLama Kayal struct mlx5_ttc_table *ttc = mlx5e_fs_get_ttc(fs, false); 2601c80bd68SAya Levin int err, i; 2611c80bd68SAya Levin 2621c80bd68SAya Levin for (i = 0; i < FS_UDP_NUM_TYPES; i++) { 2631c80bd68SAya Levin /* Modify ttc rules destination to point back to the indir TIRs */ 264f52f2faeSLama Kayal err = mlx5_ttc_fwd_default_dest(ttc, fs_udp2tt(i)); 2651c80bd68SAya Levin if (err) { 26693a07599SLama Kayal fs_err(fs, "%s: modify ttc[%d] default destination failed, err(%d)\n", 2671c80bd68SAya Levin __func__, fs_udp2tt(i), err); 2681c80bd68SAya Levin return err; 2691c80bd68SAya Levin } 2701c80bd68SAya Levin } 2711c80bd68SAya Levin 2721c80bd68SAya Levin return 0; 2731c80bd68SAya Levin } 2741c80bd68SAya Levin 2754e0ecc17SLama Kayal static int fs_udp_enable(struct mlx5e_flow_steering *fs) 2761c80bd68SAya Levin { 2774e0ecc17SLama Kayal struct mlx5_ttc_table *ttc = mlx5e_fs_get_ttc(fs, false); 2784e0ecc17SLama Kayal struct mlx5e_fs_udp *udp = mlx5e_fs_get_udp(fs); 2791c80bd68SAya Levin struct mlx5_flow_destination dest = {}; 2801c80bd68SAya Levin int err, i; 2811c80bd68SAya Levin 2821c80bd68SAya Levin dest.type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE; 2831c80bd68SAya Levin for (i = 0; i < FS_UDP_NUM_TYPES; i++) { 284f52f2faeSLama Kayal dest.ft = udp->tables[i].t; 2851c80bd68SAya Levin 2861c80bd68SAya Levin /* Modify ttc rules destination to point on the accel_fs FTs */ 287f52f2faeSLama Kayal err = mlx5_ttc_fwd_dest(ttc, fs_udp2tt(i), &dest); 2881c80bd68SAya Levin if (err) { 28993a07599SLama Kayal fs_err(fs, "%s: modify ttc[%d] destination to accel failed, err(%d)\n", 2901c80bd68SAya Levin __func__, fs_udp2tt(i), err); 2911c80bd68SAya Levin return err; 2921c80bd68SAya Levin } 2931c80bd68SAya Levin } 2941c80bd68SAya Levin return 0; 2951c80bd68SAya Levin } 2961c80bd68SAya Levin 2974e0ecc17SLama Kayal void mlx5e_fs_tt_redirect_udp_destroy(struct mlx5e_flow_steering *fs) 2981c80bd68SAya Levin { 2994e0ecc17SLama Kayal struct mlx5e_fs_udp *fs_udp = mlx5e_fs_get_udp(fs); 3001c80bd68SAya Levin int i; 3011c80bd68SAya Levin 3021c80bd68SAya Levin if (!fs_udp) 3031c80bd68SAya Levin return; 3041c80bd68SAya Levin 3051c80bd68SAya Levin if (--fs_udp->ref_cnt) 3061c80bd68SAya Levin return; 3071c80bd68SAya Levin 3084e0ecc17SLama Kayal fs_udp_disable(fs); 3091c80bd68SAya Levin 3101c80bd68SAya Levin for (i = 0; i < FS_UDP_NUM_TYPES; i++) 3111c80bd68SAya Levin fs_udp_destroy_table(fs_udp, i); 3121c80bd68SAya Levin 3131c80bd68SAya Levin kfree(fs_udp); 3144e0ecc17SLama Kayal mlx5e_fs_set_udp(fs, NULL); 3151c80bd68SAya Levin } 3161c80bd68SAya Levin 3174e0ecc17SLama Kayal int mlx5e_fs_tt_redirect_udp_create(struct mlx5e_flow_steering *fs) 3181c80bd68SAya Levin { 3194e0ecc17SLama Kayal struct mlx5e_fs_udp *udp = mlx5e_fs_get_udp(fs); 3201c80bd68SAya Levin int i, err; 3211c80bd68SAya Levin 322f52f2faeSLama Kayal if (udp) { 323f52f2faeSLama Kayal udp->ref_cnt++; 3241c80bd68SAya Levin return 0; 3251c80bd68SAya Levin } 3261c80bd68SAya Levin 327f52f2faeSLama Kayal udp = kzalloc(sizeof(*udp), GFP_KERNEL); 328f52f2faeSLama Kayal if (!udp) 3291c80bd68SAya Levin return -ENOMEM; 3304e0ecc17SLama Kayal mlx5e_fs_set_udp(fs, udp); 3311c80bd68SAya Levin 3321c80bd68SAya Levin for (i = 0; i < FS_UDP_NUM_TYPES; i++) { 3334e0ecc17SLama Kayal err = fs_udp_create_table(fs, i); 3341c80bd68SAya Levin if (err) 3351c80bd68SAya Levin goto err_destroy_tables; 3361c80bd68SAya Levin } 3371c80bd68SAya Levin 3384e0ecc17SLama Kayal err = fs_udp_enable(fs); 3391c80bd68SAya Levin if (err) 3401c80bd68SAya Levin goto err_destroy_tables; 3411c80bd68SAya Levin 342f52f2faeSLama Kayal udp->ref_cnt = 1; 3431c80bd68SAya Levin 3441c80bd68SAya Levin return 0; 3451c80bd68SAya Levin 3461c80bd68SAya Levin err_destroy_tables: 3471c80bd68SAya Levin while (--i >= 0) 348f52f2faeSLama Kayal fs_udp_destroy_table(udp, i); 3491c80bd68SAya Levin 350f52f2faeSLama Kayal kfree(udp); 3514e0ecc17SLama Kayal mlx5e_fs_set_udp(fs, NULL); 3521c80bd68SAya Levin return err; 3531c80bd68SAya Levin } 3540f575c20SAya Levin 3550f575c20SAya Levin static void fs_any_set_ethertype_flow(struct mlx5_flow_spec *spec, u16 ether_type) 3560f575c20SAya Levin { 3570f575c20SAya Levin spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; 3580f575c20SAya Levin MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.ethertype); 3590f575c20SAya Levin MLX5_SET(fte_match_param, spec->match_value, outer_headers.ethertype, ether_type); 3600f575c20SAya Levin } 3610f575c20SAya Levin 3620f575c20SAya Levin struct mlx5_flow_handle * 3634e0ecc17SLama Kayal mlx5e_fs_tt_redirect_any_add_rule(struct mlx5e_flow_steering *fs, 3640f575c20SAya Levin u32 tir_num, u16 ether_type) 3650f575c20SAya Levin { 3664e0ecc17SLama Kayal struct mlx5e_fs_any *fs_any = mlx5e_fs_get_any(fs); 3670f575c20SAya Levin struct mlx5_flow_destination dest = {}; 3680f575c20SAya Levin struct mlx5_flow_table *ft = NULL; 3690f575c20SAya Levin MLX5_DECLARE_FLOW_ACT(flow_act); 3700f575c20SAya Levin struct mlx5_flow_handle *rule; 3710f575c20SAya Levin struct mlx5_flow_spec *spec; 3720f575c20SAya Levin int err; 3730f575c20SAya Levin 3740f575c20SAya Levin spec = kvzalloc(sizeof(*spec), GFP_KERNEL); 3750f575c20SAya Levin if (!spec) 3760f575c20SAya Levin return ERR_PTR(-ENOMEM); 3770f575c20SAya Levin 3780f575c20SAya Levin ft = fs_any->table.t; 3790f575c20SAya Levin 3800f575c20SAya Levin fs_any_set_ethertype_flow(spec, ether_type); 3810f575c20SAya Levin dest.type = MLX5_FLOW_DESTINATION_TYPE_TIR; 3820f575c20SAya Levin dest.tir_num = tir_num; 3830f575c20SAya Levin 3840f575c20SAya Levin rule = mlx5_add_flow_rules(ft, spec, &flow_act, &dest, 1); 3850f575c20SAya Levin kvfree(spec); 3860f575c20SAya Levin 3870f575c20SAya Levin if (IS_ERR(rule)) { 3880f575c20SAya Levin err = PTR_ERR(rule); 38993a07599SLama Kayal fs_err(fs, "%s: add ANY rule failed, err %d\n", 3900f575c20SAya Levin __func__, err); 3910f575c20SAya Levin } 3920f575c20SAya Levin return rule; 3930f575c20SAya Levin } 3940f575c20SAya Levin 3954e0ecc17SLama Kayal static int fs_any_add_default_rule(struct mlx5e_flow_steering *fs) 3960f575c20SAya Levin { 3974e0ecc17SLama Kayal struct mlx5_ttc_table *ttc = mlx5e_fs_get_ttc(fs, false); 3984e0ecc17SLama Kayal struct mlx5e_fs_any *fs_any = mlx5e_fs_get_any(fs); 3990f575c20SAya Levin struct mlx5e_flow_table *fs_any_t; 4000f575c20SAya Levin struct mlx5_flow_destination dest; 4010f575c20SAya Levin MLX5_DECLARE_FLOW_ACT(flow_act); 4020f575c20SAya Levin struct mlx5_flow_handle *rule; 4030f575c20SAya Levin int err; 4040f575c20SAya Levin 4050f575c20SAya Levin fs_any_t = &fs_any->table; 406f52f2faeSLama Kayal dest = mlx5_ttc_get_default_dest(ttc, MLX5_TT_ANY); 4070f575c20SAya Levin rule = mlx5_add_flow_rules(fs_any_t->t, NULL, &flow_act, &dest, 1); 4080f575c20SAya Levin if (IS_ERR(rule)) { 4090f575c20SAya Levin err = PTR_ERR(rule); 41093a07599SLama Kayal fs_err(fs, "%s: add default rule failed, fs type=ANY, err %d\n", 4110f575c20SAya Levin __func__, err); 4120f575c20SAya Levin return err; 4130f575c20SAya Levin } 4140f575c20SAya Levin 4150f575c20SAya Levin fs_any->default_rule = rule; 4160f575c20SAya Levin return 0; 4170f575c20SAya Levin } 4180f575c20SAya Levin 4190f575c20SAya Levin #define MLX5E_FS_ANY_NUM_GROUPS (2) 4200f575c20SAya Levin #define MLX5E_FS_ANY_GROUP1_SIZE (BIT(16)) 4210f575c20SAya Levin #define MLX5E_FS_ANY_GROUP2_SIZE (BIT(0)) 4220f575c20SAya Levin #define MLX5E_FS_ANY_TABLE_SIZE (MLX5E_FS_ANY_GROUP1_SIZE +\ 4230f575c20SAya Levin MLX5E_FS_ANY_GROUP2_SIZE) 4240f575c20SAya Levin 4250f575c20SAya Levin static int fs_any_create_groups(struct mlx5e_flow_table *ft) 4260f575c20SAya Levin { 4270f575c20SAya Levin int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in); 4280f575c20SAya Levin void *outer_headers_c; 4290f575c20SAya Levin int ix = 0; 4300f575c20SAya Levin u32 *in; 4310f575c20SAya Levin int err; 4320f575c20SAya Levin u8 *mc; 4330f575c20SAya Levin 4340f575c20SAya Levin ft->g = kcalloc(MLX5E_FS_UDP_NUM_GROUPS, sizeof(*ft->g), GFP_KERNEL); 4350f575c20SAya Levin in = kvzalloc(inlen, GFP_KERNEL); 4360f575c20SAya Levin if (!in || !ft->g) { 4370f575c20SAya Levin kfree(ft->g); 4380f575c20SAya Levin kvfree(in); 4390f575c20SAya Levin return -ENOMEM; 4400f575c20SAya Levin } 4410f575c20SAya Levin 4420f575c20SAya Levin /* Match on ethertype */ 4430f575c20SAya Levin mc = MLX5_ADDR_OF(create_flow_group_in, in, match_criteria); 4440f575c20SAya Levin outer_headers_c = MLX5_ADDR_OF(fte_match_param, mc, outer_headers); 4450f575c20SAya Levin MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, outer_headers_c, ethertype); 4460f575c20SAya Levin MLX5_SET_CFG(in, match_criteria_enable, MLX5_MATCH_OUTER_HEADERS); 4470f575c20SAya Levin MLX5_SET_CFG(in, start_flow_index, ix); 4480f575c20SAya Levin ix += MLX5E_FS_ANY_GROUP1_SIZE; 4490f575c20SAya Levin MLX5_SET_CFG(in, end_flow_index, ix - 1); 4500f575c20SAya Levin ft->g[ft->num_groups] = mlx5_create_flow_group(ft->t, in); 4510f575c20SAya Levin if (IS_ERR(ft->g[ft->num_groups])) 4520f575c20SAya Levin goto err; 4530f575c20SAya Levin ft->num_groups++; 4540f575c20SAya Levin 4550f575c20SAya Levin /* Default Flow Group */ 4560f575c20SAya Levin memset(in, 0, inlen); 4570f575c20SAya Levin MLX5_SET_CFG(in, start_flow_index, ix); 4580f575c20SAya Levin ix += MLX5E_FS_ANY_GROUP2_SIZE; 4590f575c20SAya Levin MLX5_SET_CFG(in, end_flow_index, ix - 1); 4600f575c20SAya Levin ft->g[ft->num_groups] = mlx5_create_flow_group(ft->t, in); 4610f575c20SAya Levin if (IS_ERR(ft->g[ft->num_groups])) 4620f575c20SAya Levin goto err; 4630f575c20SAya Levin ft->num_groups++; 4640f575c20SAya Levin 4650f575c20SAya Levin kvfree(in); 4660f575c20SAya Levin return 0; 4670f575c20SAya Levin 4680f575c20SAya Levin err: 4690f575c20SAya Levin err = PTR_ERR(ft->g[ft->num_groups]); 4700f575c20SAya Levin ft->g[ft->num_groups] = NULL; 4710f575c20SAya Levin kvfree(in); 4720f575c20SAya Levin 4730f575c20SAya Levin return err; 4740f575c20SAya Levin } 4750f575c20SAya Levin 4764e0ecc17SLama Kayal static int fs_any_create_table(struct mlx5e_flow_steering *fs) 4770f575c20SAya Levin { 4784e0ecc17SLama Kayal struct mlx5_flow_namespace *ns = mlx5e_fs_get_ns(fs, false); 4794e0ecc17SLama Kayal struct mlx5e_fs_any *fs_any = mlx5e_fs_get_any(fs); 480f52f2faeSLama Kayal struct mlx5e_flow_table *ft = &fs_any->table; 4810f575c20SAya Levin struct mlx5_flow_table_attr ft_attr = {}; 4820f575c20SAya Levin int err; 4830f575c20SAya Levin 4840f575c20SAya Levin ft->num_groups = 0; 4850f575c20SAya Levin 4860f575c20SAya Levin ft_attr.max_fte = MLX5E_FS_UDP_TABLE_SIZE; 4870f575c20SAya Levin ft_attr.level = MLX5E_FS_TT_ANY_FT_LEVEL; 4880f575c20SAya Levin ft_attr.prio = MLX5E_NIC_PRIO; 4890f575c20SAya Levin 490f52f2faeSLama Kayal ft->t = mlx5_create_flow_table(ns, &ft_attr); 4910f575c20SAya Levin if (IS_ERR(ft->t)) { 4920f575c20SAya Levin err = PTR_ERR(ft->t); 4930f575c20SAya Levin ft->t = NULL; 4940f575c20SAya Levin return err; 4950f575c20SAya Levin } 4960f575c20SAya Levin 4974e0ecc17SLama Kayal mlx5_core_dbg(mlx5e_fs_get_mdev(fs), "Created fs ANY table id %u level %u\n", 4980f575c20SAya Levin ft->t->id, ft->t->level); 4990f575c20SAya Levin 5000f575c20SAya Levin err = fs_any_create_groups(ft); 5010f575c20SAya Levin if (err) 5020f575c20SAya Levin goto err; 5030f575c20SAya Levin 5044e0ecc17SLama Kayal err = fs_any_add_default_rule(fs); 5050f575c20SAya Levin if (err) 5060f575c20SAya Levin goto err; 5070f575c20SAya Levin 5080f575c20SAya Levin return 0; 5090f575c20SAya Levin 5100f575c20SAya Levin err: 5110f575c20SAya Levin mlx5e_destroy_flow_table(ft); 5120f575c20SAya Levin return err; 5130f575c20SAya Levin } 5140f575c20SAya Levin 5154e0ecc17SLama Kayal static int fs_any_disable(struct mlx5e_flow_steering *fs) 5160f575c20SAya Levin { 5174e0ecc17SLama Kayal struct mlx5_ttc_table *ttc = mlx5e_fs_get_ttc(fs, false); 5180f575c20SAya Levin int err; 5190f575c20SAya Levin 5200f575c20SAya Levin /* Modify ttc rules destination to point back to the indir TIRs */ 521f52f2faeSLama Kayal err = mlx5_ttc_fwd_default_dest(ttc, MLX5_TT_ANY); 5220f575c20SAya Levin if (err) { 52393a07599SLama Kayal fs_err(fs, 5240f575c20SAya Levin "%s: modify ttc[%d] default destination failed, err(%d)\n", 525d443c6f6SMaor Gottlieb __func__, MLX5_TT_ANY, err); 5260f575c20SAya Levin return err; 5270f575c20SAya Levin } 5280f575c20SAya Levin return 0; 5290f575c20SAya Levin } 5300f575c20SAya Levin 5314e0ecc17SLama Kayal static int fs_any_enable(struct mlx5e_flow_steering *fs) 5320f575c20SAya Levin { 5334e0ecc17SLama Kayal struct mlx5_ttc_table *ttc = mlx5e_fs_get_ttc(fs, false); 5344e0ecc17SLama Kayal struct mlx5e_fs_any *any = mlx5e_fs_get_any(fs); 5350f575c20SAya Levin struct mlx5_flow_destination dest = {}; 5360f575c20SAya Levin int err; 5370f575c20SAya Levin 5380f575c20SAya Levin dest.type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE; 539f52f2faeSLama Kayal dest.ft = any->table.t; 5400f575c20SAya Levin 5410f575c20SAya Levin /* Modify ttc rules destination to point on the accel_fs FTs */ 542f52f2faeSLama Kayal err = mlx5_ttc_fwd_dest(ttc, MLX5_TT_ANY, &dest); 5430f575c20SAya Levin if (err) { 54493a07599SLama Kayal fs_err(fs, 5450f575c20SAya Levin "%s: modify ttc[%d] destination to accel failed, err(%d)\n", 546d443c6f6SMaor Gottlieb __func__, MLX5_TT_ANY, err); 5470f575c20SAya Levin return err; 5480f575c20SAya Levin } 5490f575c20SAya Levin return 0; 5500f575c20SAya Levin } 5510f575c20SAya Levin 5520f575c20SAya Levin static void fs_any_destroy_table(struct mlx5e_fs_any *fs_any) 5530f575c20SAya Levin { 5540f575c20SAya Levin if (IS_ERR_OR_NULL(fs_any->table.t)) 5550f575c20SAya Levin return; 5560f575c20SAya Levin 5570f575c20SAya Levin mlx5_del_flow_rules(fs_any->default_rule); 5580f575c20SAya Levin mlx5e_destroy_flow_table(&fs_any->table); 5590f575c20SAya Levin fs_any->table.t = NULL; 5600f575c20SAya Levin } 5610f575c20SAya Levin 5624e0ecc17SLama Kayal void mlx5e_fs_tt_redirect_any_destroy(struct mlx5e_flow_steering *fs) 5630f575c20SAya Levin { 5644e0ecc17SLama Kayal struct mlx5e_fs_any *fs_any = mlx5e_fs_get_any(fs); 5650f575c20SAya Levin 5660f575c20SAya Levin if (!fs_any) 5670f575c20SAya Levin return; 5680f575c20SAya Levin 5690f575c20SAya Levin if (--fs_any->ref_cnt) 5700f575c20SAya Levin return; 5710f575c20SAya Levin 5724e0ecc17SLama Kayal fs_any_disable(fs); 5730f575c20SAya Levin 5740f575c20SAya Levin fs_any_destroy_table(fs_any); 5750f575c20SAya Levin 5760f575c20SAya Levin kfree(fs_any); 5774e0ecc17SLama Kayal mlx5e_fs_set_any(fs, NULL); 5780f575c20SAya Levin } 5790f575c20SAya Levin 5804e0ecc17SLama Kayal int mlx5e_fs_tt_redirect_any_create(struct mlx5e_flow_steering *fs) 5810f575c20SAya Levin { 5824e0ecc17SLama Kayal struct mlx5e_fs_any *fs_any = mlx5e_fs_get_any(fs); 5830f575c20SAya Levin int err; 5840f575c20SAya Levin 585f52f2faeSLama Kayal if (fs_any) { 586f52f2faeSLama Kayal fs_any->ref_cnt++; 5870f575c20SAya Levin return 0; 5880f575c20SAya Levin } 5890f575c20SAya Levin 590f52f2faeSLama Kayal fs_any = kzalloc(sizeof(*fs_any), GFP_KERNEL); 591f52f2faeSLama Kayal if (!fs_any) 5920f575c20SAya Levin return -ENOMEM; 5934e0ecc17SLama Kayal mlx5e_fs_set_any(fs, fs_any); 5940f575c20SAya Levin 5954e0ecc17SLama Kayal err = fs_any_create_table(fs); 5960f575c20SAya Levin if (err) 597*3250affdSZhengchao Shao goto err_free_any; 5980f575c20SAya Levin 5994e0ecc17SLama Kayal err = fs_any_enable(fs); 6000f575c20SAya Levin if (err) 6010f575c20SAya Levin goto err_destroy_table; 6020f575c20SAya Levin 603f52f2faeSLama Kayal fs_any->ref_cnt = 1; 6040f575c20SAya Levin 6050f575c20SAya Levin return 0; 6060f575c20SAya Levin 6070f575c20SAya Levin err_destroy_table: 608f52f2faeSLama Kayal fs_any_destroy_table(fs_any); 609*3250affdSZhengchao Shao err_free_any: 6104e0ecc17SLama Kayal mlx5e_fs_set_any(fs, NULL); 611*3250affdSZhengchao Shao kfree(fs_any); 6120f575c20SAya Levin return err; 6130f575c20SAya Levin } 614