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 
fs_udp_type2str(enum fs_udp_type i)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 
fs_udp2tt(enum fs_udp_type i)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 
tt2fs_udp(enum mlx5_traffic_types i)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 
mlx5e_fs_tt_redirect_del_rule(struct mlx5_flow_handle * rule)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 
fs_udp_set_dport_flow(struct mlx5_flow_spec * spec,enum fs_udp_type type,u16 udp_dport)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 *
mlx5e_fs_tt_redirect_udp_add_rule(struct mlx5e_flow_steering * fs,enum mlx5_traffic_types ttc_type,u32 tir_num,u16 d_port)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 
fs_udp_add_default_rule(struct mlx5e_flow_steering * fs,enum fs_udp_type type)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)
fs_udp_create_groups(struct mlx5e_flow_table * ft,enum fs_udp_type type)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);
1572f4d6328SDinghao Liu 		ft->g = NULL;
1581c80bd68SAya Levin 		kvfree(in);
1591c80bd68SAya Levin 		return -ENOMEM;
1601c80bd68SAya Levin 	}
1611c80bd68SAya Levin 
1621c80bd68SAya Levin 	mc = MLX5_ADDR_OF(create_flow_group_in, in, match_criteria);
1631c80bd68SAya Levin 	outer_headers_c = MLX5_ADDR_OF(fte_match_param, mc, outer_headers);
1641c80bd68SAya Levin 	MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, outer_headers_c, ip_protocol);
1651c80bd68SAya Levin 	MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, outer_headers_c, ip_version);
1661c80bd68SAya Levin 
1671c80bd68SAya Levin 	switch (type) {
1681c80bd68SAya Levin 	case FS_IPV4_UDP:
1691c80bd68SAya Levin 	case FS_IPV6_UDP:
1701c80bd68SAya Levin 		MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, outer_headers_c, udp_dport);
1711c80bd68SAya Levin 		break;
1721c80bd68SAya Levin 	default:
1731c80bd68SAya Levin 		err = -EINVAL;
1741c80bd68SAya Levin 		goto out;
1751c80bd68SAya Levin 	}
1761c80bd68SAya Levin 	/* Match on udp protocol, Ipv4/6 and dport */
1771c80bd68SAya Levin 	MLX5_SET_CFG(in, match_criteria_enable, MLX5_MATCH_OUTER_HEADERS);
1781c80bd68SAya Levin 	MLX5_SET_CFG(in, start_flow_index, ix);
1791c80bd68SAya Levin 	ix += MLX5E_FS_UDP_GROUP1_SIZE;
1801c80bd68SAya Levin 	MLX5_SET_CFG(in, end_flow_index, ix - 1);
1811c80bd68SAya Levin 	ft->g[ft->num_groups] = mlx5_create_flow_group(ft->t, in);
1821c80bd68SAya Levin 	if (IS_ERR(ft->g[ft->num_groups]))
1831c80bd68SAya Levin 		goto err;
1841c80bd68SAya Levin 	ft->num_groups++;
1851c80bd68SAya Levin 
1861c80bd68SAya Levin 	/* Default Flow Group */
1871c80bd68SAya Levin 	memset(in, 0, inlen);
1881c80bd68SAya Levin 	MLX5_SET_CFG(in, start_flow_index, ix);
1891c80bd68SAya Levin 	ix += MLX5E_FS_UDP_GROUP2_SIZE;
1901c80bd68SAya Levin 	MLX5_SET_CFG(in, end_flow_index, ix - 1);
1911c80bd68SAya Levin 	ft->g[ft->num_groups] = mlx5_create_flow_group(ft->t, in);
1921c80bd68SAya Levin 	if (IS_ERR(ft->g[ft->num_groups]))
1931c80bd68SAya Levin 		goto err;
1941c80bd68SAya Levin 	ft->num_groups++;
1951c80bd68SAya Levin 
1961c80bd68SAya Levin 	kvfree(in);
1971c80bd68SAya Levin 	return 0;
1981c80bd68SAya Levin 
1991c80bd68SAya Levin err:
2001c80bd68SAya Levin 	err = PTR_ERR(ft->g[ft->num_groups]);
2011c80bd68SAya Levin 	ft->g[ft->num_groups] = NULL;
2021c80bd68SAya Levin out:
2031c80bd68SAya Levin 	kvfree(in);
2041c80bd68SAya Levin 
2051c80bd68SAya Levin 	return err;
2061c80bd68SAya Levin }
2071c80bd68SAya Levin 
fs_udp_create_table(struct mlx5e_flow_steering * fs,enum fs_udp_type type)2084e0ecc17SLama Kayal static int fs_udp_create_table(struct mlx5e_flow_steering *fs, enum fs_udp_type type)
2091c80bd68SAya Levin {
2104e0ecc17SLama Kayal 	struct mlx5_flow_namespace *ns = mlx5e_fs_get_ns(fs, false);
2114e0ecc17SLama Kayal 	struct mlx5e_fs_udp *fs_udp = mlx5e_fs_get_udp(fs);
2121c80bd68SAya Levin 	struct mlx5_flow_table_attr ft_attr = {};
2134e0ecc17SLama Kayal 	struct mlx5e_flow_table *ft;
2141c80bd68SAya Levin 	int err;
2151c80bd68SAya Levin 
2164e0ecc17SLama Kayal 	ft = &fs_udp->tables[type];
2171c80bd68SAya Levin 	ft->num_groups = 0;
2181c80bd68SAya Levin 
2191c80bd68SAya Levin 	ft_attr.max_fte = MLX5E_FS_UDP_TABLE_SIZE;
2201c80bd68SAya Levin 	ft_attr.level = MLX5E_FS_TT_UDP_FT_LEVEL;
2211c80bd68SAya Levin 	ft_attr.prio = MLX5E_NIC_PRIO;
2221c80bd68SAya Levin 
223f52f2faeSLama Kayal 	ft->t = mlx5_create_flow_table(ns, &ft_attr);
2241c80bd68SAya Levin 	if (IS_ERR(ft->t)) {
2251c80bd68SAya Levin 		err = PTR_ERR(ft->t);
2261c80bd68SAya Levin 		ft->t = NULL;
2271c80bd68SAya Levin 		return err;
2281c80bd68SAya Levin 	}
2291c80bd68SAya Levin 
2304e0ecc17SLama Kayal 	mlx5_core_dbg(mlx5e_fs_get_mdev(fs), "Created fs %s table id %u level %u\n",
2311c80bd68SAya Levin 		      fs_udp_type2str(type), ft->t->id, ft->t->level);
2321c80bd68SAya Levin 
2331c80bd68SAya Levin 	err = fs_udp_create_groups(ft, type);
2341c80bd68SAya Levin 	if (err)
2351c80bd68SAya Levin 		goto err;
2361c80bd68SAya Levin 
2374e0ecc17SLama Kayal 	err = fs_udp_add_default_rule(fs, type);
2381c80bd68SAya Levin 	if (err)
2391c80bd68SAya Levin 		goto err;
2401c80bd68SAya Levin 
2411c80bd68SAya Levin 	return 0;
2421c80bd68SAya Levin 
2431c80bd68SAya Levin err:
2441c80bd68SAya Levin 	mlx5e_destroy_flow_table(ft);
2451c80bd68SAya Levin 	return err;
2461c80bd68SAya Levin }
2471c80bd68SAya Levin 
fs_udp_destroy_table(struct mlx5e_fs_udp * fs_udp,int i)2481c80bd68SAya Levin static void fs_udp_destroy_table(struct mlx5e_fs_udp *fs_udp, int i)
2491c80bd68SAya Levin {
2501c80bd68SAya Levin 	if (IS_ERR_OR_NULL(fs_udp->tables[i].t))
2511c80bd68SAya Levin 		return;
2521c80bd68SAya Levin 
2531c80bd68SAya Levin 	mlx5_del_flow_rules(fs_udp->default_rules[i]);
2541c80bd68SAya Levin 	mlx5e_destroy_flow_table(&fs_udp->tables[i]);
2551c80bd68SAya Levin 	fs_udp->tables[i].t = NULL;
2561c80bd68SAya Levin }
2571c80bd68SAya Levin 
fs_udp_disable(struct mlx5e_flow_steering * fs)2584e0ecc17SLama Kayal static int fs_udp_disable(struct mlx5e_flow_steering *fs)
2591c80bd68SAya Levin {
2604e0ecc17SLama Kayal 	struct mlx5_ttc_table *ttc = mlx5e_fs_get_ttc(fs, false);
2611c80bd68SAya Levin 	int err, i;
2621c80bd68SAya Levin 
2631c80bd68SAya Levin 	for (i = 0; i < FS_UDP_NUM_TYPES; i++) {
2641c80bd68SAya Levin 		/* Modify ttc rules destination to point back to the indir TIRs */
265f52f2faeSLama Kayal 		err = mlx5_ttc_fwd_default_dest(ttc, fs_udp2tt(i));
2661c80bd68SAya Levin 		if (err) {
26793a07599SLama Kayal 			fs_err(fs, "%s: modify ttc[%d] default destination failed, err(%d)\n",
2681c80bd68SAya Levin 			       __func__, fs_udp2tt(i), err);
2691c80bd68SAya Levin 			return err;
2701c80bd68SAya Levin 		}
2711c80bd68SAya Levin 	}
2721c80bd68SAya Levin 
2731c80bd68SAya Levin 	return 0;
2741c80bd68SAya Levin }
2751c80bd68SAya Levin 
fs_udp_enable(struct mlx5e_flow_steering * fs)2764e0ecc17SLama Kayal static int fs_udp_enable(struct mlx5e_flow_steering *fs)
2771c80bd68SAya Levin {
2784e0ecc17SLama Kayal 	struct mlx5_ttc_table *ttc = mlx5e_fs_get_ttc(fs, false);
2794e0ecc17SLama Kayal 	struct mlx5e_fs_udp *udp = mlx5e_fs_get_udp(fs);
2801c80bd68SAya Levin 	struct mlx5_flow_destination dest = {};
2811c80bd68SAya Levin 	int err, i;
2821c80bd68SAya Levin 
2831c80bd68SAya Levin 	dest.type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
2841c80bd68SAya Levin 	for (i = 0; i < FS_UDP_NUM_TYPES; i++) {
285f52f2faeSLama Kayal 		dest.ft = udp->tables[i].t;
2861c80bd68SAya Levin 
2871c80bd68SAya Levin 		/* Modify ttc rules destination to point on the accel_fs FTs */
288f52f2faeSLama Kayal 		err = mlx5_ttc_fwd_dest(ttc, fs_udp2tt(i), &dest);
2891c80bd68SAya Levin 		if (err) {
29093a07599SLama Kayal 			fs_err(fs, "%s: modify ttc[%d] destination to accel failed, err(%d)\n",
2911c80bd68SAya Levin 			       __func__, fs_udp2tt(i), err);
2921c80bd68SAya Levin 			return err;
2931c80bd68SAya Levin 		}
2941c80bd68SAya Levin 	}
2951c80bd68SAya Levin 	return 0;
2961c80bd68SAya Levin }
2971c80bd68SAya Levin 
mlx5e_fs_tt_redirect_udp_destroy(struct mlx5e_flow_steering * fs)2984e0ecc17SLama Kayal void mlx5e_fs_tt_redirect_udp_destroy(struct mlx5e_flow_steering *fs)
2991c80bd68SAya Levin {
3004e0ecc17SLama Kayal 	struct mlx5e_fs_udp *fs_udp = mlx5e_fs_get_udp(fs);
3011c80bd68SAya Levin 	int i;
3021c80bd68SAya Levin 
3031c80bd68SAya Levin 	if (!fs_udp)
3041c80bd68SAya Levin 		return;
3051c80bd68SAya Levin 
3061c80bd68SAya Levin 	if (--fs_udp->ref_cnt)
3071c80bd68SAya Levin 		return;
3081c80bd68SAya Levin 
3094e0ecc17SLama Kayal 	fs_udp_disable(fs);
3101c80bd68SAya Levin 
3111c80bd68SAya Levin 	for (i = 0; i < FS_UDP_NUM_TYPES; i++)
3121c80bd68SAya Levin 		fs_udp_destroy_table(fs_udp, i);
3131c80bd68SAya Levin 
3141c80bd68SAya Levin 	kfree(fs_udp);
3154e0ecc17SLama Kayal 	mlx5e_fs_set_udp(fs, NULL);
3161c80bd68SAya Levin }
3171c80bd68SAya Levin 
mlx5e_fs_tt_redirect_udp_create(struct mlx5e_flow_steering * fs)3184e0ecc17SLama Kayal int mlx5e_fs_tt_redirect_udp_create(struct mlx5e_flow_steering *fs)
3191c80bd68SAya Levin {
3204e0ecc17SLama Kayal 	struct mlx5e_fs_udp *udp = mlx5e_fs_get_udp(fs);
3211c80bd68SAya Levin 	int i, err;
3221c80bd68SAya Levin 
323f52f2faeSLama Kayal 	if (udp) {
324f52f2faeSLama Kayal 		udp->ref_cnt++;
3251c80bd68SAya Levin 		return 0;
3261c80bd68SAya Levin 	}
3271c80bd68SAya Levin 
328f52f2faeSLama Kayal 	udp = kzalloc(sizeof(*udp), GFP_KERNEL);
329f52f2faeSLama Kayal 	if (!udp)
3301c80bd68SAya Levin 		return -ENOMEM;
3314e0ecc17SLama Kayal 	mlx5e_fs_set_udp(fs, udp);
3321c80bd68SAya Levin 
3331c80bd68SAya Levin 	for (i = 0; i < FS_UDP_NUM_TYPES; i++) {
3344e0ecc17SLama Kayal 		err = fs_udp_create_table(fs, i);
3351c80bd68SAya Levin 		if (err)
3361c80bd68SAya Levin 			goto err_destroy_tables;
3371c80bd68SAya Levin 	}
3381c80bd68SAya Levin 
3394e0ecc17SLama Kayal 	err = fs_udp_enable(fs);
3401c80bd68SAya Levin 	if (err)
3411c80bd68SAya Levin 		goto err_destroy_tables;
3421c80bd68SAya Levin 
343f52f2faeSLama Kayal 	udp->ref_cnt = 1;
3441c80bd68SAya Levin 
3451c80bd68SAya Levin 	return 0;
3461c80bd68SAya Levin 
3471c80bd68SAya Levin err_destroy_tables:
3481c80bd68SAya Levin 	while (--i >= 0)
349f52f2faeSLama Kayal 		fs_udp_destroy_table(udp, i);
3501c80bd68SAya Levin 
351f52f2faeSLama Kayal 	kfree(udp);
3524e0ecc17SLama Kayal 	mlx5e_fs_set_udp(fs, NULL);
3531c80bd68SAya Levin 	return err;
3541c80bd68SAya Levin }
3550f575c20SAya Levin 
fs_any_set_ethertype_flow(struct mlx5_flow_spec * spec,u16 ether_type)3560f575c20SAya Levin static void fs_any_set_ethertype_flow(struct mlx5_flow_spec *spec, u16 ether_type)
3570f575c20SAya Levin {
3580f575c20SAya Levin 	spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS;
3590f575c20SAya Levin 	MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.ethertype);
3600f575c20SAya Levin 	MLX5_SET(fte_match_param, spec->match_value, outer_headers.ethertype, ether_type);
3610f575c20SAya Levin }
3620f575c20SAya Levin 
3630f575c20SAya Levin struct mlx5_flow_handle *
mlx5e_fs_tt_redirect_any_add_rule(struct mlx5e_flow_steering * fs,u32 tir_num,u16 ether_type)3644e0ecc17SLama Kayal mlx5e_fs_tt_redirect_any_add_rule(struct mlx5e_flow_steering *fs,
3650f575c20SAya Levin 				  u32 tir_num, u16 ether_type)
3660f575c20SAya Levin {
3674e0ecc17SLama Kayal 	struct mlx5e_fs_any *fs_any = mlx5e_fs_get_any(fs);
3680f575c20SAya Levin 	struct mlx5_flow_destination dest = {};
3690f575c20SAya Levin 	struct mlx5_flow_table *ft = NULL;
3700f575c20SAya Levin 	MLX5_DECLARE_FLOW_ACT(flow_act);
3710f575c20SAya Levin 	struct mlx5_flow_handle *rule;
3720f575c20SAya Levin 	struct mlx5_flow_spec *spec;
3730f575c20SAya Levin 	int err;
3740f575c20SAya Levin 
3750f575c20SAya Levin 	spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
3760f575c20SAya Levin 	if (!spec)
3770f575c20SAya Levin 		return ERR_PTR(-ENOMEM);
3780f575c20SAya Levin 
3790f575c20SAya Levin 	ft = fs_any->table.t;
3800f575c20SAya Levin 
3810f575c20SAya Levin 	fs_any_set_ethertype_flow(spec, ether_type);
3820f575c20SAya Levin 	dest.type = MLX5_FLOW_DESTINATION_TYPE_TIR;
3830f575c20SAya Levin 	dest.tir_num = tir_num;
3840f575c20SAya Levin 
3850f575c20SAya Levin 	rule = mlx5_add_flow_rules(ft, spec, &flow_act, &dest, 1);
3860f575c20SAya Levin 	kvfree(spec);
3870f575c20SAya Levin 
3880f575c20SAya Levin 	if (IS_ERR(rule)) {
3890f575c20SAya Levin 		err = PTR_ERR(rule);
39093a07599SLama Kayal 		fs_err(fs, "%s: add ANY rule failed, err %d\n",
3910f575c20SAya Levin 		       __func__, err);
3920f575c20SAya Levin 	}
3930f575c20SAya Levin 	return rule;
3940f575c20SAya Levin }
3950f575c20SAya Levin 
fs_any_add_default_rule(struct mlx5e_flow_steering * fs)3964e0ecc17SLama Kayal static int fs_any_add_default_rule(struct mlx5e_flow_steering *fs)
3970f575c20SAya Levin {
3984e0ecc17SLama Kayal 	struct mlx5_ttc_table *ttc = mlx5e_fs_get_ttc(fs, false);
3994e0ecc17SLama Kayal 	struct mlx5e_fs_any *fs_any = mlx5e_fs_get_any(fs);
4000f575c20SAya Levin 	struct mlx5e_flow_table *fs_any_t;
4010f575c20SAya Levin 	struct mlx5_flow_destination dest;
4020f575c20SAya Levin 	MLX5_DECLARE_FLOW_ACT(flow_act);
4030f575c20SAya Levin 	struct mlx5_flow_handle *rule;
4040f575c20SAya Levin 	int err;
4050f575c20SAya Levin 
4060f575c20SAya Levin 	fs_any_t = &fs_any->table;
407f52f2faeSLama Kayal 	dest = mlx5_ttc_get_default_dest(ttc, MLX5_TT_ANY);
4080f575c20SAya Levin 	rule = mlx5_add_flow_rules(fs_any_t->t, NULL, &flow_act, &dest, 1);
4090f575c20SAya Levin 	if (IS_ERR(rule)) {
4100f575c20SAya Levin 		err = PTR_ERR(rule);
41193a07599SLama Kayal 		fs_err(fs, "%s: add default rule failed, fs type=ANY, err %d\n",
4120f575c20SAya Levin 		       __func__, err);
4130f575c20SAya Levin 		return err;
4140f575c20SAya Levin 	}
4150f575c20SAya Levin 
4160f575c20SAya Levin 	fs_any->default_rule = rule;
4170f575c20SAya Levin 	return 0;
4180f575c20SAya Levin }
4190f575c20SAya Levin 
4200f575c20SAya Levin #define MLX5E_FS_ANY_NUM_GROUPS	(2)
4210f575c20SAya Levin #define MLX5E_FS_ANY_GROUP1_SIZE	(BIT(16))
4220f575c20SAya Levin #define MLX5E_FS_ANY_GROUP2_SIZE	(BIT(0))
4230f575c20SAya Levin #define MLX5E_FS_ANY_TABLE_SIZE		(MLX5E_FS_ANY_GROUP1_SIZE +\
4240f575c20SAya Levin 					 MLX5E_FS_ANY_GROUP2_SIZE)
4250f575c20SAya Levin 
fs_any_create_groups(struct mlx5e_flow_table * ft)4260f575c20SAya Levin static int fs_any_create_groups(struct mlx5e_flow_table *ft)
4270f575c20SAya Levin {
4280f575c20SAya Levin 	int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
4290f575c20SAya Levin 	void *outer_headers_c;
4300f575c20SAya Levin 	int ix = 0;
4310f575c20SAya Levin 	u32 *in;
4320f575c20SAya Levin 	int err;
4330f575c20SAya Levin 	u8 *mc;
4340f575c20SAya Levin 
4350f575c20SAya Levin 	ft->g = kcalloc(MLX5E_FS_UDP_NUM_GROUPS, sizeof(*ft->g), GFP_KERNEL);
4360f575c20SAya Levin 	in = kvzalloc(inlen, GFP_KERNEL);
4370f575c20SAya Levin 	if  (!in || !ft->g) {
4380f575c20SAya Levin 		kfree(ft->g);
439*2897c981SDinghao Liu 		ft->g = NULL;
4400f575c20SAya Levin 		kvfree(in);
4410f575c20SAya Levin 		return -ENOMEM;
4420f575c20SAya Levin 	}
4430f575c20SAya Levin 
4440f575c20SAya Levin 	/* Match on ethertype */
4450f575c20SAya Levin 	mc = MLX5_ADDR_OF(create_flow_group_in, in, match_criteria);
4460f575c20SAya Levin 	outer_headers_c = MLX5_ADDR_OF(fte_match_param, mc, outer_headers);
4470f575c20SAya Levin 	MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, outer_headers_c, ethertype);
4480f575c20SAya Levin 	MLX5_SET_CFG(in, match_criteria_enable, MLX5_MATCH_OUTER_HEADERS);
4490f575c20SAya Levin 	MLX5_SET_CFG(in, start_flow_index, ix);
4500f575c20SAya Levin 	ix += MLX5E_FS_ANY_GROUP1_SIZE;
4510f575c20SAya Levin 	MLX5_SET_CFG(in, end_flow_index, ix - 1);
4520f575c20SAya Levin 	ft->g[ft->num_groups] = mlx5_create_flow_group(ft->t, in);
4530f575c20SAya Levin 	if (IS_ERR(ft->g[ft->num_groups]))
4540f575c20SAya Levin 		goto err;
4550f575c20SAya Levin 	ft->num_groups++;
4560f575c20SAya Levin 
4570f575c20SAya Levin 	/* Default Flow Group */
4580f575c20SAya Levin 	memset(in, 0, inlen);
4590f575c20SAya Levin 	MLX5_SET_CFG(in, start_flow_index, ix);
4600f575c20SAya Levin 	ix += MLX5E_FS_ANY_GROUP2_SIZE;
4610f575c20SAya Levin 	MLX5_SET_CFG(in, end_flow_index, ix - 1);
4620f575c20SAya Levin 	ft->g[ft->num_groups] = mlx5_create_flow_group(ft->t, in);
4630f575c20SAya Levin 	if (IS_ERR(ft->g[ft->num_groups]))
4640f575c20SAya Levin 		goto err;
4650f575c20SAya Levin 	ft->num_groups++;
4660f575c20SAya Levin 
4670f575c20SAya Levin 	kvfree(in);
4680f575c20SAya Levin 	return 0;
4690f575c20SAya Levin 
4700f575c20SAya Levin err:
4710f575c20SAya Levin 	err = PTR_ERR(ft->g[ft->num_groups]);
4720f575c20SAya Levin 	ft->g[ft->num_groups] = NULL;
4730f575c20SAya Levin 	kvfree(in);
4740f575c20SAya Levin 
4750f575c20SAya Levin 	return err;
4760f575c20SAya Levin }
4770f575c20SAya Levin 
fs_any_create_table(struct mlx5e_flow_steering * fs)4784e0ecc17SLama Kayal static int fs_any_create_table(struct mlx5e_flow_steering *fs)
4790f575c20SAya Levin {
4804e0ecc17SLama Kayal 	struct mlx5_flow_namespace *ns = mlx5e_fs_get_ns(fs, false);
4814e0ecc17SLama Kayal 	struct mlx5e_fs_any *fs_any = mlx5e_fs_get_any(fs);
482f52f2faeSLama Kayal 	struct mlx5e_flow_table *ft = &fs_any->table;
4830f575c20SAya Levin 	struct mlx5_flow_table_attr ft_attr = {};
4840f575c20SAya Levin 	int err;
4850f575c20SAya Levin 
4860f575c20SAya Levin 	ft->num_groups = 0;
4870f575c20SAya Levin 
4880f575c20SAya Levin 	ft_attr.max_fte = MLX5E_FS_UDP_TABLE_SIZE;
4890f575c20SAya Levin 	ft_attr.level = MLX5E_FS_TT_ANY_FT_LEVEL;
4900f575c20SAya Levin 	ft_attr.prio = MLX5E_NIC_PRIO;
4910f575c20SAya Levin 
492f52f2faeSLama Kayal 	ft->t = mlx5_create_flow_table(ns, &ft_attr);
4930f575c20SAya Levin 	if (IS_ERR(ft->t)) {
4940f575c20SAya Levin 		err = PTR_ERR(ft->t);
4950f575c20SAya Levin 		ft->t = NULL;
4960f575c20SAya Levin 		return err;
4970f575c20SAya Levin 	}
4980f575c20SAya Levin 
4994e0ecc17SLama Kayal 	mlx5_core_dbg(mlx5e_fs_get_mdev(fs), "Created fs ANY table id %u level %u\n",
5000f575c20SAya Levin 		      ft->t->id, ft->t->level);
5010f575c20SAya Levin 
5020f575c20SAya Levin 	err = fs_any_create_groups(ft);
5030f575c20SAya Levin 	if (err)
5040f575c20SAya Levin 		goto err;
5050f575c20SAya Levin 
5064e0ecc17SLama Kayal 	err = fs_any_add_default_rule(fs);
5070f575c20SAya Levin 	if (err)
5080f575c20SAya Levin 		goto err;
5090f575c20SAya Levin 
5100f575c20SAya Levin 	return 0;
5110f575c20SAya Levin 
5120f575c20SAya Levin err:
5130f575c20SAya Levin 	mlx5e_destroy_flow_table(ft);
5140f575c20SAya Levin 	return err;
5150f575c20SAya Levin }
5160f575c20SAya Levin 
fs_any_disable(struct mlx5e_flow_steering * fs)5174e0ecc17SLama Kayal static int fs_any_disable(struct mlx5e_flow_steering *fs)
5180f575c20SAya Levin {
5194e0ecc17SLama Kayal 	struct mlx5_ttc_table *ttc = mlx5e_fs_get_ttc(fs, false);
5200f575c20SAya Levin 	int err;
5210f575c20SAya Levin 
5220f575c20SAya Levin 	/* Modify ttc rules destination to point back to the indir TIRs */
523f52f2faeSLama Kayal 	err = mlx5_ttc_fwd_default_dest(ttc, MLX5_TT_ANY);
5240f575c20SAya Levin 	if (err) {
52593a07599SLama Kayal 		fs_err(fs,
5260f575c20SAya Levin 		       "%s: modify ttc[%d] default destination failed, err(%d)\n",
527d443c6f6SMaor Gottlieb 		       __func__, MLX5_TT_ANY, err);
5280f575c20SAya Levin 		return err;
5290f575c20SAya Levin 	}
5300f575c20SAya Levin 	return 0;
5310f575c20SAya Levin }
5320f575c20SAya Levin 
fs_any_enable(struct mlx5e_flow_steering * fs)5334e0ecc17SLama Kayal static int fs_any_enable(struct mlx5e_flow_steering *fs)
5340f575c20SAya Levin {
5354e0ecc17SLama Kayal 	struct mlx5_ttc_table *ttc = mlx5e_fs_get_ttc(fs, false);
5364e0ecc17SLama Kayal 	struct mlx5e_fs_any *any = mlx5e_fs_get_any(fs);
5370f575c20SAya Levin 	struct mlx5_flow_destination dest = {};
5380f575c20SAya Levin 	int err;
5390f575c20SAya Levin 
5400f575c20SAya Levin 	dest.type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
541f52f2faeSLama Kayal 	dest.ft = any->table.t;
5420f575c20SAya Levin 
5430f575c20SAya Levin 	/* Modify ttc rules destination to point on the accel_fs FTs */
544f52f2faeSLama Kayal 	err = mlx5_ttc_fwd_dest(ttc, MLX5_TT_ANY, &dest);
5450f575c20SAya Levin 	if (err) {
54693a07599SLama Kayal 		fs_err(fs,
5470f575c20SAya Levin 		       "%s: modify ttc[%d] destination to accel failed, err(%d)\n",
548d443c6f6SMaor Gottlieb 		       __func__, MLX5_TT_ANY, err);
5490f575c20SAya Levin 		return err;
5500f575c20SAya Levin 	}
5510f575c20SAya Levin 	return 0;
5520f575c20SAya Levin }
5530f575c20SAya Levin 
fs_any_destroy_table(struct mlx5e_fs_any * fs_any)5540f575c20SAya Levin static void fs_any_destroy_table(struct mlx5e_fs_any *fs_any)
5550f575c20SAya Levin {
5560f575c20SAya Levin 	if (IS_ERR_OR_NULL(fs_any->table.t))
5570f575c20SAya Levin 		return;
5580f575c20SAya Levin 
5590f575c20SAya Levin 	mlx5_del_flow_rules(fs_any->default_rule);
5600f575c20SAya Levin 	mlx5e_destroy_flow_table(&fs_any->table);
5610f575c20SAya Levin 	fs_any->table.t = NULL;
5620f575c20SAya Levin }
5630f575c20SAya Levin 
mlx5e_fs_tt_redirect_any_destroy(struct mlx5e_flow_steering * fs)5644e0ecc17SLama Kayal void mlx5e_fs_tt_redirect_any_destroy(struct mlx5e_flow_steering *fs)
5650f575c20SAya Levin {
5664e0ecc17SLama Kayal 	struct mlx5e_fs_any *fs_any = mlx5e_fs_get_any(fs);
5670f575c20SAya Levin 
5680f575c20SAya Levin 	if (!fs_any)
5690f575c20SAya Levin 		return;
5700f575c20SAya Levin 
5710f575c20SAya Levin 	if (--fs_any->ref_cnt)
5720f575c20SAya Levin 		return;
5730f575c20SAya Levin 
5744e0ecc17SLama Kayal 	fs_any_disable(fs);
5750f575c20SAya Levin 
5760f575c20SAya Levin 	fs_any_destroy_table(fs_any);
5770f575c20SAya Levin 
5780f575c20SAya Levin 	kfree(fs_any);
5794e0ecc17SLama Kayal 	mlx5e_fs_set_any(fs, NULL);
5800f575c20SAya Levin }
5810f575c20SAya Levin 
mlx5e_fs_tt_redirect_any_create(struct mlx5e_flow_steering * fs)5824e0ecc17SLama Kayal int mlx5e_fs_tt_redirect_any_create(struct mlx5e_flow_steering *fs)
5830f575c20SAya Levin {
5844e0ecc17SLama Kayal 	struct mlx5e_fs_any *fs_any = mlx5e_fs_get_any(fs);
5850f575c20SAya Levin 	int err;
5860f575c20SAya Levin 
587f52f2faeSLama Kayal 	if (fs_any) {
588f52f2faeSLama Kayal 		fs_any->ref_cnt++;
5890f575c20SAya Levin 		return 0;
5900f575c20SAya Levin 	}
5910f575c20SAya Levin 
592f52f2faeSLama Kayal 	fs_any = kzalloc(sizeof(*fs_any), GFP_KERNEL);
593f52f2faeSLama Kayal 	if (!fs_any)
5940f575c20SAya Levin 		return -ENOMEM;
5954e0ecc17SLama Kayal 	mlx5e_fs_set_any(fs, fs_any);
5960f575c20SAya Levin 
5974e0ecc17SLama Kayal 	err = fs_any_create_table(fs);
5980f575c20SAya Levin 	if (err)
5993250affdSZhengchao Shao 		goto err_free_any;
6000f575c20SAya Levin 
6014e0ecc17SLama Kayal 	err = fs_any_enable(fs);
6020f575c20SAya Levin 	if (err)
6030f575c20SAya Levin 		goto err_destroy_table;
6040f575c20SAya Levin 
605f52f2faeSLama Kayal 	fs_any->ref_cnt = 1;
6060f575c20SAya Levin 
6070f575c20SAya Levin 	return 0;
6080f575c20SAya Levin 
6090f575c20SAya Levin err_destroy_table:
610f52f2faeSLama Kayal 	fs_any_destroy_table(fs_any);
6113250affdSZhengchao Shao err_free_any:
6124e0ecc17SLama Kayal 	mlx5e_fs_set_any(fs, NULL);
6133250affdSZhengchao Shao 	kfree(fs_any);
6140f575c20SAya Levin 	return err;
6150f575c20SAya Levin }
616