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