xref: /freebsd/sys/dev/mlx5/mlx5_core/mlx5_fs_tcp.c (revision 75095cd3)
12c0ade80SHans Petter Selasky /*-
22c0ade80SHans Petter Selasky  * Copyright (c) 2020-2021, Mellanox Technologies, Ltd.
32c0ade80SHans Petter Selasky  *
42c0ade80SHans Petter Selasky  * Redistribution and use in source and binary forms, with or without
52c0ade80SHans Petter Selasky  * modification, are permitted provided that the following conditions
62c0ade80SHans Petter Selasky  * are met:
72c0ade80SHans Petter Selasky  * 1. Redistributions of source code must retain the above copyright
82c0ade80SHans Petter Selasky  *    notice, this list of conditions and the following disclaimer.
92c0ade80SHans Petter Selasky  * 2. Redistributions in binary form must reproduce the above copyright
102c0ade80SHans Petter Selasky  *    notice, this list of conditions and the following disclaimer in the
112c0ade80SHans Petter Selasky  *    documentation and/or other materials provided with the distribution.
122c0ade80SHans Petter Selasky  *
132c0ade80SHans Petter Selasky  * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS `AS IS' AND
142c0ade80SHans Petter Selasky  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
152c0ade80SHans Petter Selasky  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
162c0ade80SHans Petter Selasky  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
172c0ade80SHans Petter Selasky  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
182c0ade80SHans Petter Selasky  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
192c0ade80SHans Petter Selasky  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
202c0ade80SHans Petter Selasky  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
212c0ade80SHans Petter Selasky  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
222c0ade80SHans Petter Selasky  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
232c0ade80SHans Petter Selasky  * SUCH DAMAGE.
242c0ade80SHans Petter Selasky  */
252c0ade80SHans Petter Selasky 
262c0ade80SHans Petter Selasky #include "opt_inet.h"
272c0ade80SHans Petter Selasky #include "opt_inet6.h"
282c0ade80SHans Petter Selasky 
292c0ade80SHans Petter Selasky #include <dev/mlx5/mlx5_en/en.h>
302c0ade80SHans Petter Selasky 
312c0ade80SHans Petter Selasky #include <dev/mlx5/mlx5_core/fs_core.h>
322c0ade80SHans Petter Selasky #include <dev/mlx5/mlx5_core/fs_tcp.h>
332c0ade80SHans Petter Selasky #include <dev/mlx5/device.h>
342c0ade80SHans Petter Selasky 
352c0ade80SHans Petter Selasky #include <sys/domain.h>
362c0ade80SHans Petter Selasky 
372c0ade80SHans Petter Selasky #include <netinet/in_pcb.h>
382c0ade80SHans Petter Selasky 
392c0ade80SHans Petter Selasky #if defined(INET) || defined(INET6)
402c0ade80SHans Petter Selasky static void
412c0ade80SHans Petter Selasky accel_fs_tcp_set_ipv4_flow(struct mlx5_flow_spec *spec, struct inpcb *inp)
422c0ade80SHans Petter Selasky {
432c0ade80SHans Petter Selasky 	MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.ip_protocol);
442c0ade80SHans Petter Selasky 	MLX5_SET(fte_match_param, spec->match_value, outer_headers.ip_protocol, IPPROTO_TCP);
452c0ade80SHans Petter Selasky 	MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.ip_version);
462c0ade80SHans Petter Selasky 	MLX5_SET(fte_match_param, spec->match_value, outer_headers.ip_version, 4);
472c0ade80SHans Petter Selasky 	memcpy(MLX5_ADDR_OF(fte_match_param, spec->match_value,
482c0ade80SHans Petter Selasky 	    outer_headers.src_ipv4_src_ipv6.ipv4_layout.ipv4),
492c0ade80SHans Petter Selasky 	    &inp->inp_faddr, 4);
502c0ade80SHans Petter Selasky 	memcpy(MLX5_ADDR_OF(fte_match_param, spec->match_value,
512c0ade80SHans Petter Selasky 	    outer_headers.dst_ipv4_dst_ipv6.ipv4_layout.ipv4),
522c0ade80SHans Petter Selasky 	    &inp->inp_laddr, 4);
532c0ade80SHans Petter Selasky 	MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria,
542c0ade80SHans Petter Selasky 	    outer_headers.src_ipv4_src_ipv6.ipv4_layout.ipv4);
552c0ade80SHans Petter Selasky 	MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria,
562c0ade80SHans Petter Selasky 	    outer_headers.dst_ipv4_dst_ipv6.ipv4_layout.ipv4);
572c0ade80SHans Petter Selasky }
582c0ade80SHans Petter Selasky #endif
592c0ade80SHans Petter Selasky 
602c0ade80SHans Petter Selasky #ifdef INET6
612c0ade80SHans Petter Selasky static void
622c0ade80SHans Petter Selasky accel_fs_tcp_set_ipv6_flow(struct mlx5_flow_spec *spec, struct inpcb *inp)
632c0ade80SHans Petter Selasky {
642c0ade80SHans Petter Selasky 	MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.ip_protocol);
652c0ade80SHans Petter Selasky 	MLX5_SET(fte_match_param, spec->match_value, outer_headers.ip_protocol, IPPROTO_TCP);
662c0ade80SHans Petter Selasky 	MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.ip_version);
672c0ade80SHans Petter Selasky 	MLX5_SET(fte_match_param, spec->match_value, outer_headers.ip_version, 6);
682c0ade80SHans Petter Selasky 	memcpy(MLX5_ADDR_OF(fte_match_param, spec->match_value,
692c0ade80SHans Petter Selasky 	    outer_headers.src_ipv4_src_ipv6.ipv6_layout.ipv6),
702c0ade80SHans Petter Selasky 	    &inp->in6p_faddr, 16);
712c0ade80SHans Petter Selasky 	memcpy(MLX5_ADDR_OF(fte_match_param, spec->match_value,
722c0ade80SHans Petter Selasky 	    outer_headers.dst_ipv4_dst_ipv6.ipv6_layout.ipv6),
732c0ade80SHans Petter Selasky 	    &inp->in6p_laddr, 16);
742c0ade80SHans Petter Selasky 	memset(MLX5_ADDR_OF(fte_match_param, spec->match_criteria,
752c0ade80SHans Petter Selasky 	    outer_headers.src_ipv4_src_ipv6.ipv6_layout.ipv6),
762c0ade80SHans Petter Selasky 	    0xff, 16);
772c0ade80SHans Petter Selasky 	memset(MLX5_ADDR_OF(fte_match_param, spec->match_criteria,
782c0ade80SHans Petter Selasky 	    outer_headers.dst_ipv4_dst_ipv6.ipv6_layout.ipv6),
792c0ade80SHans Petter Selasky 	    0xff, 16);
802c0ade80SHans Petter Selasky }
812c0ade80SHans Petter Selasky #endif
822c0ade80SHans Petter Selasky 
832c0ade80SHans Petter Selasky void
842c0ade80SHans Petter Selasky mlx5e_accel_fs_del_inpcb(struct mlx5_flow_rule *rule)
852c0ade80SHans Petter Selasky {
862c0ade80SHans Petter Selasky 	mlx5_del_flow_rule(rule);
872c0ade80SHans Petter Selasky }
882c0ade80SHans Petter Selasky 
892c0ade80SHans Petter Selasky struct mlx5_flow_rule *
902c0ade80SHans Petter Selasky mlx5e_accel_fs_add_inpcb(struct mlx5e_priv *priv,
912c0ade80SHans Petter Selasky     struct inpcb *inp, uint32_t tirn, uint32_t flow_tag,
922c0ade80SHans Petter Selasky     uint16_t vlan_id)
932c0ade80SHans Petter Selasky {
942c0ade80SHans Petter Selasky 	struct mlx5_flow_destination dest = {};
952c0ade80SHans Petter Selasky 	struct mlx5e_flow_table *ft = NULL;
9675095cd3SJohn Baldwin #if defined(INET) || defined(INET6)
9775095cd3SJohn Baldwin 	struct mlx5e_accel_fs_tcp *fs_tcp = &priv->fts.accel_tcp;
9875095cd3SJohn Baldwin #endif
992c0ade80SHans Petter Selasky 	struct mlx5_flow_rule *flow;
1002c0ade80SHans Petter Selasky 	struct mlx5_flow_spec *spec;
1012c0ade80SHans Petter Selasky 
1022c0ade80SHans Petter Selasky 	spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
1032c0ade80SHans Petter Selasky 	if (!spec)
1042c0ade80SHans Petter Selasky 		return (ERR_PTR(-ENOMEM));
1052c0ade80SHans Petter Selasky 
1062c0ade80SHans Petter Selasky 	spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS;
1072c0ade80SHans Petter Selasky 
1082c0ade80SHans Petter Selasky 	INP_RLOCK(inp);
1092c0ade80SHans Petter Selasky 	/* Set VLAN ID to match, if any. */
1102c0ade80SHans Petter Selasky 	MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.cvlan_tag);
1112c0ade80SHans Petter Selasky 	MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.first_vid);
1122c0ade80SHans Petter Selasky 	if (vlan_id != MLX5E_ACCEL_FS_ADD_INPCB_NO_VLAN) {
1132c0ade80SHans Petter Selasky 		MLX5_SET_TO_ONES(fte_match_param, spec->match_value, outer_headers.cvlan_tag);
1142c0ade80SHans Petter Selasky 		MLX5_SET(fte_match_param, spec->match_value, outer_headers.first_vid, vlan_id);
1152c0ade80SHans Petter Selasky 	}
1162c0ade80SHans Petter Selasky 
1172c0ade80SHans Petter Selasky 	/* Set TCP port numbers. */
1182c0ade80SHans Petter Selasky 	MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria,
1192c0ade80SHans Petter Selasky 	    outer_headers.tcp_dport);
1202c0ade80SHans Petter Selasky 	MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria,
1212c0ade80SHans Petter Selasky 	    outer_headers.tcp_sport);
1222c0ade80SHans Petter Selasky 	MLX5_SET(fte_match_param, spec->match_value, outer_headers.tcp_dport,
1232c0ade80SHans Petter Selasky 	    ntohs(inp->inp_lport));
1242c0ade80SHans Petter Selasky 	MLX5_SET(fte_match_param, spec->match_value, outer_headers.tcp_sport,
1252c0ade80SHans Petter Selasky 	    ntohs(inp->inp_fport));
1262c0ade80SHans Petter Selasky 
1272c0ade80SHans Petter Selasky 	/* Set IP addresses. */
1282c0ade80SHans Petter Selasky 	switch (INP_SOCKAF(inp->inp_socket)) {
1292c0ade80SHans Petter Selasky #ifdef INET
1302c0ade80SHans Petter Selasky 	case AF_INET:
1312c0ade80SHans Petter Selasky 		accel_fs_tcp_set_ipv4_flow(spec, inp);
1322c0ade80SHans Petter Selasky 		ft = &fs_tcp->tables[MLX5E_ACCEL_FS_IPV4_TCP];
1332c0ade80SHans Petter Selasky 		break;
1342c0ade80SHans Petter Selasky #endif
1352c0ade80SHans Petter Selasky #ifdef INET6
1362c0ade80SHans Petter Selasky 	case AF_INET6:
1372c0ade80SHans Petter Selasky 		if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0 &&
1382c0ade80SHans Petter Selasky 		    IN6_IS_ADDR_V4MAPPED(&inp->in6p_faddr)) {
1392c0ade80SHans Petter Selasky 			accel_fs_tcp_set_ipv4_flow(spec, inp);
1402c0ade80SHans Petter Selasky 			ft = &fs_tcp->tables[MLX5E_ACCEL_FS_IPV4_TCP];
1412c0ade80SHans Petter Selasky 		} else {
1422c0ade80SHans Petter Selasky 			accel_fs_tcp_set_ipv6_flow(spec, inp);
1432c0ade80SHans Petter Selasky 			ft = &fs_tcp->tables[MLX5E_ACCEL_FS_IPV6_TCP];
1442c0ade80SHans Petter Selasky 		}
1452c0ade80SHans Petter Selasky 		break;
1462c0ade80SHans Petter Selasky #endif
1472c0ade80SHans Petter Selasky 	default:
1482c0ade80SHans Petter Selasky 		break;
1492c0ade80SHans Petter Selasky 	}
1502c0ade80SHans Petter Selasky 	INP_RUNLOCK(inp);
1512c0ade80SHans Petter Selasky 
1522c0ade80SHans Petter Selasky 	if (!ft) {
1532c0ade80SHans Petter Selasky 		flow = ERR_PTR(-EINVAL);
1542c0ade80SHans Petter Selasky 		goto out;
1552c0ade80SHans Petter Selasky 	}
1562c0ade80SHans Petter Selasky 
1572c0ade80SHans Petter Selasky 	dest.type = MLX5_FLOW_DESTINATION_TYPE_TIR;
1582c0ade80SHans Petter Selasky 	dest.tir_num = tirn;
1592c0ade80SHans Petter Selasky 
1602c0ade80SHans Petter Selasky 	flow = mlx5_add_flow_rule(ft->t, spec->match_criteria_enable,
1612c0ade80SHans Petter Selasky 	    spec->match_criteria,
1622c0ade80SHans Petter Selasky 	    spec->match_value,
1632c0ade80SHans Petter Selasky 	    MLX5_FLOW_CONTEXT_ACTION_FWD_DEST,
1642c0ade80SHans Petter Selasky 	    flow_tag,
1652c0ade80SHans Petter Selasky 	    &dest);
1662c0ade80SHans Petter Selasky out:
1672c0ade80SHans Petter Selasky 	kvfree(spec);
1682c0ade80SHans Petter Selasky 	return (flow);
1692c0ade80SHans Petter Selasky }
1702c0ade80SHans Petter Selasky 
1712c0ade80SHans Petter Selasky static int
1722c0ade80SHans Petter Selasky accel_fs_tcp_add_default_rule(struct mlx5e_priv *priv, int type)
1732c0ade80SHans Petter Selasky {
1742c0ade80SHans Petter Selasky 	static u32 match_criteria[MLX5_ST_SZ_DW(fte_match_param)];
1752c0ade80SHans Petter Selasky 	static u32 match_value[MLX5_ST_SZ_DW(fte_match_param)];
1762c0ade80SHans Petter Selasky 	struct mlx5_flow_destination dest = {};
1772c0ade80SHans Petter Selasky 	struct mlx5e_accel_fs_tcp *fs_tcp;
1782c0ade80SHans Petter Selasky 	struct mlx5_flow_rule *rule;
1792c0ade80SHans Petter Selasky 
1802c0ade80SHans Petter Selasky 	fs_tcp = &priv->fts.accel_tcp;
1812c0ade80SHans Petter Selasky 
1822c0ade80SHans Petter Selasky 	dest.type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
1832c0ade80SHans Petter Selasky 
1842c0ade80SHans Petter Selasky 	/*
1852c0ade80SHans Petter Selasky 	 * Traffic not matched by flow table rules should be forwarded
1862c0ade80SHans Petter Selasky 	 * to the next flow table in order to not be dropped by the
1872c0ade80SHans Petter Selasky 	 * default action. Refer to the diagram in
1882c0ade80SHans Petter Selasky 	 * mlx5_en_flow_table.c for more information about the order
1892c0ade80SHans Petter Selasky 	 * of flow tables.
1902c0ade80SHans Petter Selasky 	 */
1912c0ade80SHans Petter Selasky 	dest.ft = (type == MLX5E_ACCEL_FS_TCP_NUM_TYPES - 1) ?
1922c0ade80SHans Petter Selasky 	    priv->fts.vlan.t : fs_tcp->tables[type + 1].t;
1932c0ade80SHans Petter Selasky 
1942c0ade80SHans Petter Selasky 	rule = mlx5_add_flow_rule(fs_tcp->tables[type].t, 0, match_criteria, match_value,
1952c0ade80SHans Petter Selasky 	    MLX5_FLOW_CONTEXT_ACTION_FWD_DEST, MLX5_FS_DEFAULT_FLOW_TAG, &dest);
1962c0ade80SHans Petter Selasky 	if (IS_ERR(rule))
1972c0ade80SHans Petter Selasky 		return (PTR_ERR(rule));
1982c0ade80SHans Petter Selasky 
1992c0ade80SHans Petter Selasky 	fs_tcp->default_rules[type] = rule;
2002c0ade80SHans Petter Selasky 	return (0);
2012c0ade80SHans Petter Selasky }
2022c0ade80SHans Petter Selasky 
2032c0ade80SHans Petter Selasky #define	MLX5E_ACCEL_FS_TCP_NUM_GROUPS	(2)
2042c0ade80SHans Petter Selasky #define	MLX5E_ACCEL_FS_TCP_GROUP1_SIZE	(BIT(16) - 1)
2052c0ade80SHans Petter Selasky #define	MLX5E_ACCEL_FS_TCP_GROUP2_SIZE	(BIT(0))
2062c0ade80SHans Petter Selasky #define	MLX5E_ACCEL_FS_TCP_TABLE_SIZE	(MLX5E_ACCEL_FS_TCP_GROUP1_SIZE +\
2072c0ade80SHans Petter Selasky 					 MLX5E_ACCEL_FS_TCP_GROUP2_SIZE)
2082c0ade80SHans Petter Selasky static int
2092c0ade80SHans Petter Selasky accel_fs_tcp_create_groups(struct mlx5e_flow_table *ft, int type)
2102c0ade80SHans Petter Selasky {
2112c0ade80SHans Petter Selasky 	int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
2122c0ade80SHans Petter Selasky 	void *outer_headers_c;
2132c0ade80SHans Petter Selasky 	int ix = 0;
2142c0ade80SHans Petter Selasky 	u32 *in;
2152c0ade80SHans Petter Selasky 	int err;
2162c0ade80SHans Petter Selasky 	u8 *mc;
2172c0ade80SHans Petter Selasky 
2182c0ade80SHans Petter Selasky 	ft->g = kcalloc(MLX5E_ACCEL_FS_TCP_NUM_GROUPS, sizeof(*ft->g), GFP_KERNEL);
2192c0ade80SHans Petter Selasky 	in = kvzalloc(inlen, GFP_KERNEL);
2202c0ade80SHans Petter Selasky 	if (!in || !ft->g) {
2212c0ade80SHans Petter Selasky 		kfree(ft->g);
2222c0ade80SHans Petter Selasky 		kvfree(in);
2232c0ade80SHans Petter Selasky 		return (-ENOMEM);
2242c0ade80SHans Petter Selasky 	}
2252c0ade80SHans Petter Selasky 
2262c0ade80SHans Petter Selasky 	mc = MLX5_ADDR_OF(create_flow_group_in, in, match_criteria);
2272c0ade80SHans Petter Selasky 	outer_headers_c = MLX5_ADDR_OF(fte_match_param, mc, outer_headers);
2282c0ade80SHans Petter Selasky 	MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, outer_headers_c, ip_protocol);
2292c0ade80SHans Petter Selasky 	MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, outer_headers_c, ip_version);
2302c0ade80SHans Petter Selasky 	MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, outer_headers_c, cvlan_tag);
2312c0ade80SHans Petter Selasky 	MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, outer_headers_c, first_vid);
2322c0ade80SHans Petter Selasky 
2332c0ade80SHans Petter Selasky 	switch (type) {
2342c0ade80SHans Petter Selasky 	case MLX5E_ACCEL_FS_IPV4_TCP:
2352c0ade80SHans Petter Selasky 	case MLX5E_ACCEL_FS_IPV6_TCP:
2362c0ade80SHans Petter Selasky 		MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, outer_headers_c, tcp_dport);
2372c0ade80SHans Petter Selasky 		MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, outer_headers_c, tcp_sport);
2382c0ade80SHans Petter Selasky 		break;
2392c0ade80SHans Petter Selasky 	default:
2402c0ade80SHans Petter Selasky 		err = -EINVAL;
2412c0ade80SHans Petter Selasky 		goto out;
2422c0ade80SHans Petter Selasky 	}
2432c0ade80SHans Petter Selasky 
2442c0ade80SHans Petter Selasky 	switch (type) {
2452c0ade80SHans Petter Selasky 	case MLX5E_ACCEL_FS_IPV4_TCP:
2462c0ade80SHans Petter Selasky 		MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, outer_headers_c,
2472c0ade80SHans Petter Selasky 		    src_ipv4_src_ipv6.ipv4_layout.ipv4);
2482c0ade80SHans Petter Selasky 		MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, outer_headers_c,
2492c0ade80SHans Petter Selasky 		    dst_ipv4_dst_ipv6.ipv4_layout.ipv4);
2502c0ade80SHans Petter Selasky 		break;
2512c0ade80SHans Petter Selasky 	case MLX5E_ACCEL_FS_IPV6_TCP:
2522c0ade80SHans Petter Selasky 		memset(MLX5_ADDR_OF(fte_match_set_lyr_2_4, outer_headers_c,
2532c0ade80SHans Petter Selasky 		    src_ipv4_src_ipv6.ipv6_layout.ipv6),
2542c0ade80SHans Petter Selasky 		    0xff, 16);
2552c0ade80SHans Petter Selasky 		memset(MLX5_ADDR_OF(fte_match_set_lyr_2_4, outer_headers_c,
2562c0ade80SHans Petter Selasky 		    dst_ipv4_dst_ipv6.ipv6_layout.ipv6),
2572c0ade80SHans Petter Selasky 		    0xff, 16);
2582c0ade80SHans Petter Selasky 		break;
2592c0ade80SHans Petter Selasky 	default:
2602c0ade80SHans Petter Selasky 		err = -EINVAL;
2612c0ade80SHans Petter Selasky 		goto out;
2622c0ade80SHans Petter Selasky 	}
2632c0ade80SHans Petter Selasky 
2642c0ade80SHans Petter Selasky 	MLX5_SET_CFG(in, match_criteria_enable, MLX5_MATCH_OUTER_HEADERS);
2652c0ade80SHans Petter Selasky 	MLX5_SET_CFG(in, start_flow_index, ix);
2662c0ade80SHans Petter Selasky 	ix += MLX5E_ACCEL_FS_TCP_GROUP1_SIZE;
2672c0ade80SHans Petter Selasky 	MLX5_SET_CFG(in, end_flow_index, ix - 1);
2682c0ade80SHans Petter Selasky 	ft->g[ft->num_groups] = mlx5_create_flow_group(ft->t, in);
2692c0ade80SHans Petter Selasky 	if (IS_ERR(ft->g[ft->num_groups]))
2702c0ade80SHans Petter Selasky 		goto err;
2712c0ade80SHans Petter Selasky 	ft->num_groups++;
2722c0ade80SHans Petter Selasky 
2732c0ade80SHans Petter Selasky 	/* Default Flow Group */
2742c0ade80SHans Petter Selasky 	memset(in, 0, inlen);
2752c0ade80SHans Petter Selasky 	MLX5_SET_CFG(in, start_flow_index, ix);
2762c0ade80SHans Petter Selasky 	ix += MLX5E_ACCEL_FS_TCP_GROUP2_SIZE;
2772c0ade80SHans Petter Selasky 	MLX5_SET_CFG(in, end_flow_index, ix - 1);
2782c0ade80SHans Petter Selasky 	ft->g[ft->num_groups] = mlx5_create_flow_group(ft->t, in);
2792c0ade80SHans Petter Selasky 	if (IS_ERR(ft->g[ft->num_groups]))
2802c0ade80SHans Petter Selasky 		goto err;
2812c0ade80SHans Petter Selasky 	ft->num_groups++;
2822c0ade80SHans Petter Selasky 
2832c0ade80SHans Petter Selasky 	kvfree(in);
2842c0ade80SHans Petter Selasky 	return (0);
2852c0ade80SHans Petter Selasky 
2862c0ade80SHans Petter Selasky err:
2872c0ade80SHans Petter Selasky 	err = PTR_ERR(ft->g[ft->num_groups]);
2882c0ade80SHans Petter Selasky 	ft->g[ft->num_groups] = NULL;
2892c0ade80SHans Petter Selasky out:
2902c0ade80SHans Petter Selasky 	kvfree(in);
2912c0ade80SHans Petter Selasky 
2922c0ade80SHans Petter Selasky 	return (err);
2932c0ade80SHans Petter Selasky }
2942c0ade80SHans Petter Selasky 
2952c0ade80SHans Petter Selasky static void
2962c0ade80SHans Petter Selasky accel_fs_tcp_destroy_groups(struct mlx5e_flow_table *ft)
2972c0ade80SHans Petter Selasky {
2982c0ade80SHans Petter Selasky         int i;
2992c0ade80SHans Petter Selasky 
3002c0ade80SHans Petter Selasky         for (i = ft->num_groups - 1; i >= 0; i--) {
3012c0ade80SHans Petter Selasky                 if (!IS_ERR_OR_NULL(ft->g[i]))
3022c0ade80SHans Petter Selasky                         mlx5_destroy_flow_group(ft->g[i]);
3032c0ade80SHans Petter Selasky                 ft->g[i] = NULL;
3042c0ade80SHans Petter Selasky         }
3052c0ade80SHans Petter Selasky         ft->num_groups = 0;
3062c0ade80SHans Petter Selasky }
3072c0ade80SHans Petter Selasky 
3082c0ade80SHans Petter Selasky static int
3092c0ade80SHans Petter Selasky accel_fs_tcp_create_table(struct mlx5e_priv *priv, int type)
3102c0ade80SHans Petter Selasky {
3112c0ade80SHans Petter Selasky 	struct mlx5e_flow_table *ft = &priv->fts.accel_tcp.tables[type];
3122c0ade80SHans Petter Selasky 	int err;
3132c0ade80SHans Petter Selasky 
3142c0ade80SHans Petter Selasky 	ft->num_groups = 0;
3152c0ade80SHans Petter Selasky 	ft->t = mlx5_create_flow_table(priv->fts.accel_tcp.ns, 0, "tcp",
3162c0ade80SHans Petter Selasky 	    MLX5E_ACCEL_FS_TCP_TABLE_SIZE);
3172c0ade80SHans Petter Selasky 	if (IS_ERR(ft->t)) {
3182c0ade80SHans Petter Selasky 		err = PTR_ERR(ft->t);
3192c0ade80SHans Petter Selasky 		ft->t = NULL;
3202c0ade80SHans Petter Selasky 		return (err);
3212c0ade80SHans Petter Selasky 	}
3222c0ade80SHans Petter Selasky 
3232c0ade80SHans Petter Selasky 	err = accel_fs_tcp_create_groups(ft, type);
3242c0ade80SHans Petter Selasky 	if (err)
3252c0ade80SHans Petter Selasky 		goto err_destroy_flow_table;
3262c0ade80SHans Petter Selasky 
3272c0ade80SHans Petter Selasky 	return (0);
3282c0ade80SHans Petter Selasky 
3292c0ade80SHans Petter Selasky err_destroy_flow_table:
3302c0ade80SHans Petter Selasky 	mlx5_destroy_flow_table(ft->t);
3312c0ade80SHans Petter Selasky 	ft->t = NULL;
3322c0ade80SHans Petter Selasky 	return (err);
3332c0ade80SHans Petter Selasky }
3342c0ade80SHans Petter Selasky 
3352c0ade80SHans Petter Selasky static void
3362c0ade80SHans Petter Selasky accel_fs_tcp_destroy_table(struct mlx5e_priv *priv, int i)
3372c0ade80SHans Petter Selasky {
3382c0ade80SHans Petter Selasky 	struct mlx5e_accel_fs_tcp *fs_tcp;
3392c0ade80SHans Petter Selasky 	struct mlx5e_flow_table *ft;
3402c0ade80SHans Petter Selasky 
3412c0ade80SHans Petter Selasky 	fs_tcp = &priv->fts.accel_tcp;
3422c0ade80SHans Petter Selasky 	ft = fs_tcp->tables + i;
3432c0ade80SHans Petter Selasky 
3442c0ade80SHans Petter Selasky 	mlx5_del_flow_rule(fs_tcp->default_rules[i]);
3452c0ade80SHans Petter Selasky 
3462c0ade80SHans Petter Selasky 	accel_fs_tcp_destroy_groups(ft);
3472c0ade80SHans Petter Selasky 	kfree(ft->g);
3482c0ade80SHans Petter Selasky 	ft->g = NULL;
3492c0ade80SHans Petter Selasky 	mlx5_destroy_flow_table(ft->t);
3502c0ade80SHans Petter Selasky 	ft->t = NULL;
3512c0ade80SHans Petter Selasky }
3522c0ade80SHans Petter Selasky 
3532c0ade80SHans Petter Selasky void
3542c0ade80SHans Petter Selasky mlx5e_accel_fs_tcp_destroy(struct mlx5e_priv *priv)
3552c0ade80SHans Petter Selasky {
3562c0ade80SHans Petter Selasky 	int i;
3572c0ade80SHans Petter Selasky 
3582c0ade80SHans Petter Selasky 	if (!MLX5_CAP_FLOWTABLE_NIC_RX(priv->mdev, ft_field_support.outer_ip_version))
3592c0ade80SHans Petter Selasky 		return;
3602c0ade80SHans Petter Selasky 
3612c0ade80SHans Petter Selasky 	for (i = 0; i < MLX5E_ACCEL_FS_TCP_NUM_TYPES; i++)
3622c0ade80SHans Petter Selasky 		accel_fs_tcp_destroy_table(priv, i);
3632c0ade80SHans Petter Selasky }
3642c0ade80SHans Petter Selasky 
3652c0ade80SHans Petter Selasky int
3662c0ade80SHans Petter Selasky mlx5e_accel_fs_tcp_create(struct mlx5e_priv *priv)
3672c0ade80SHans Petter Selasky {
3682c0ade80SHans Petter Selasky 	int i, err;
3692c0ade80SHans Petter Selasky 
3702c0ade80SHans Petter Selasky 	if (!MLX5_CAP_FLOWTABLE_NIC_RX(priv->mdev, ft_field_support.outer_ip_version))
3712c0ade80SHans Petter Selasky 		return (0);
3722c0ade80SHans Petter Selasky 
3732c0ade80SHans Petter Selasky 	/* Setup namespace pointer. */
3742c0ade80SHans Petter Selasky 	priv->fts.accel_tcp.ns = mlx5_get_flow_namespace(
3752c0ade80SHans Petter Selasky 	    priv->mdev, MLX5_FLOW_NAMESPACE_OFFLOADS);
3762c0ade80SHans Petter Selasky 
3772c0ade80SHans Petter Selasky 	/*
3782c0ade80SHans Petter Selasky 	 * Create flow tables first, because the priority level is
3792c0ade80SHans Petter Selasky 	 * assigned at allocation time.
3802c0ade80SHans Petter Selasky 	 */
3812c0ade80SHans Petter Selasky 	for (i = 0; i != MLX5E_ACCEL_FS_TCP_NUM_TYPES; i++) {
3822c0ade80SHans Petter Selasky 		err = accel_fs_tcp_create_table(priv, i);
3832c0ade80SHans Petter Selasky 		if (err)
3842c0ade80SHans Petter Selasky 			goto err_destroy_tables;
3852c0ade80SHans Petter Selasky 	}
3862c0ade80SHans Petter Selasky 
3872c0ade80SHans Petter Selasky 	/* Create default rules last. */
3882c0ade80SHans Petter Selasky 	for (i = 0; i != MLX5E_ACCEL_FS_TCP_NUM_TYPES; i++) {
3892c0ade80SHans Petter Selasky 		err = accel_fs_tcp_add_default_rule(priv, i);
3902c0ade80SHans Petter Selasky 		if (err)
3912c0ade80SHans Petter Selasky 			goto err_destroy_rules;
3922c0ade80SHans Petter Selasky 	}
3932c0ade80SHans Petter Selasky 	return (0);
3942c0ade80SHans Petter Selasky 
3952c0ade80SHans Petter Selasky err_destroy_rules:
3962c0ade80SHans Petter Selasky 	while (i--)
3972c0ade80SHans Petter Selasky 		mlx5_del_flow_rule(priv->fts.accel_tcp.default_rules[i]);
3982c0ade80SHans Petter Selasky 	i = MLX5E_ACCEL_FS_TCP_NUM_TYPES;
3992c0ade80SHans Petter Selasky 
4002c0ade80SHans Petter Selasky err_destroy_tables:
4012c0ade80SHans Petter Selasky 	while (i--)
4022c0ade80SHans Petter Selasky 		accel_fs_tcp_destroy_table(priv, i);
4032c0ade80SHans Petter Selasky 	return (err);
4042c0ade80SHans Petter Selasky }
405