17838e172SAlex Vesker // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
27838e172SAlex Vesker /* Copyright (c) 2019 Mellanox Technologies. */
37838e172SAlex Vesker 
47838e172SAlex Vesker #include "dr_types.h"
57838e172SAlex Vesker 
dr_table_set_miss_action_nic(struct mlx5dr_domain * dmn,struct mlx5dr_table_rx_tx * nic_tbl,struct mlx5dr_action * action)6cc2295cdSYevgeny Kliteynik static int dr_table_set_miss_action_nic(struct mlx5dr_domain *dmn,
7cc2295cdSYevgeny Kliteynik 					struct mlx5dr_table_rx_tx *nic_tbl,
8cc2295cdSYevgeny Kliteynik 					struct mlx5dr_action *action)
9cc2295cdSYevgeny Kliteynik {
10cc2295cdSYevgeny Kliteynik 	struct mlx5dr_matcher_rx_tx *last_nic_matcher = NULL;
11cc2295cdSYevgeny Kliteynik 	struct mlx5dr_htbl_connect_info info;
12cc2295cdSYevgeny Kliteynik 	struct mlx5dr_ste_htbl *last_htbl;
135c4f9b6eSRongwei Liu 	struct mlx5dr_icm_chunk *chunk;
14cc2295cdSYevgeny Kliteynik 	int ret;
15cc2295cdSYevgeny Kliteynik 
16cc2295cdSYevgeny Kliteynik 	if (!list_empty(&nic_tbl->nic_matcher_list))
17cc2295cdSYevgeny Kliteynik 		last_nic_matcher = list_last_entry(&nic_tbl->nic_matcher_list,
18cc2295cdSYevgeny Kliteynik 						   struct mlx5dr_matcher_rx_tx,
19cc2295cdSYevgeny Kliteynik 						   list_node);
20cc2295cdSYevgeny Kliteynik 
21cc2295cdSYevgeny Kliteynik 	if (last_nic_matcher)
22cc2295cdSYevgeny Kliteynik 		last_htbl = last_nic_matcher->e_anchor;
23cc2295cdSYevgeny Kliteynik 	else
24cc2295cdSYevgeny Kliteynik 		last_htbl = nic_tbl->s_anchor;
25cc2295cdSYevgeny Kliteynik 
265c4f9b6eSRongwei Liu 	if (action) {
275c4f9b6eSRongwei Liu 		chunk = nic_tbl->nic_dmn->type == DR_DOMAIN_NIC_TYPE_RX ?
285c4f9b6eSRongwei Liu 			action->dest_tbl->tbl->rx.s_anchor->chunk :
295c4f9b6eSRongwei Liu 			action->dest_tbl->tbl->tx.s_anchor->chunk;
305c4f9b6eSRongwei Liu 		nic_tbl->default_icm_addr = mlx5dr_icm_pool_get_chunk_icm_addr(chunk);
315c4f9b6eSRongwei Liu 	} else {
32cc2295cdSYevgeny Kliteynik 		nic_tbl->default_icm_addr = nic_tbl->nic_dmn->default_icm_addr;
335c4f9b6eSRongwei Liu 	}
34cc2295cdSYevgeny Kliteynik 
35cc2295cdSYevgeny Kliteynik 	info.type = CONNECT_MISS;
36cc2295cdSYevgeny Kliteynik 	info.miss_icm_addr = nic_tbl->default_icm_addr;
37cc2295cdSYevgeny Kliteynik 
38cc2295cdSYevgeny Kliteynik 	ret = mlx5dr_ste_htbl_init_and_postsend(dmn, nic_tbl->nic_dmn,
39cc2295cdSYevgeny Kliteynik 						last_htbl, &info, true);
40cc2295cdSYevgeny Kliteynik 	if (ret)
41cc2295cdSYevgeny Kliteynik 		mlx5dr_dbg(dmn, "Failed to set NIC RX/TX miss action, ret %d\n", ret);
42cc2295cdSYevgeny Kliteynik 
43cc2295cdSYevgeny Kliteynik 	return ret;
44cc2295cdSYevgeny Kliteynik }
45cc2295cdSYevgeny Kliteynik 
mlx5dr_table_set_miss_action(struct mlx5dr_table * tbl,struct mlx5dr_action * action)467838e172SAlex Vesker int mlx5dr_table_set_miss_action(struct mlx5dr_table *tbl,
477838e172SAlex Vesker 				 struct mlx5dr_action *action)
487838e172SAlex Vesker {
49*52f7cf70SYueHaibing 	int ret = -EOPNOTSUPP;
507838e172SAlex Vesker 
517838e172SAlex Vesker 	if (action && action->action_type != DR_ACTION_TYP_FT)
527838e172SAlex Vesker 		return -EOPNOTSUPP;
537838e172SAlex Vesker 
54ed03a418SAlex Vesker 	mlx5dr_domain_lock(tbl->dmn);
557838e172SAlex Vesker 
567838e172SAlex Vesker 	if (tbl->dmn->type == MLX5DR_DOMAIN_TYPE_NIC_RX ||
577838e172SAlex Vesker 	    tbl->dmn->type == MLX5DR_DOMAIN_TYPE_FDB) {
58cc2295cdSYevgeny Kliteynik 		ret = dr_table_set_miss_action_nic(tbl->dmn, &tbl->rx, action);
59cc2295cdSYevgeny Kliteynik 		if (ret)
607838e172SAlex Vesker 			goto out;
617838e172SAlex Vesker 	}
627838e172SAlex Vesker 
637838e172SAlex Vesker 	if (tbl->dmn->type == MLX5DR_DOMAIN_TYPE_NIC_TX ||
647838e172SAlex Vesker 	    tbl->dmn->type == MLX5DR_DOMAIN_TYPE_FDB) {
65cc2295cdSYevgeny Kliteynik 		ret = dr_table_set_miss_action_nic(tbl->dmn, &tbl->tx, action);
66cc2295cdSYevgeny Kliteynik 		if (ret)
677838e172SAlex Vesker 			goto out;
687838e172SAlex Vesker 	}
697838e172SAlex Vesker 
70*52f7cf70SYueHaibing 	if (ret)
71*52f7cf70SYueHaibing 		goto out;
72*52f7cf70SYueHaibing 
737838e172SAlex Vesker 	/* Release old action */
747838e172SAlex Vesker 	if (tbl->miss_action)
757838e172SAlex Vesker 		refcount_dec(&tbl->miss_action->refcount);
767838e172SAlex Vesker 
777838e172SAlex Vesker 	/* Set new miss action */
787838e172SAlex Vesker 	tbl->miss_action = action;
797838e172SAlex Vesker 	if (tbl->miss_action)
807838e172SAlex Vesker 		refcount_inc(&action->refcount);
817838e172SAlex Vesker 
827838e172SAlex Vesker out:
83ed03a418SAlex Vesker 	mlx5dr_domain_unlock(tbl->dmn);
847838e172SAlex Vesker 	return ret;
857838e172SAlex Vesker }
867838e172SAlex Vesker 
dr_table_uninit_nic(struct mlx5dr_table_rx_tx * nic_tbl)877838e172SAlex Vesker static void dr_table_uninit_nic(struct mlx5dr_table_rx_tx *nic_tbl)
887838e172SAlex Vesker {
897838e172SAlex Vesker 	mlx5dr_htbl_put(nic_tbl->s_anchor);
907838e172SAlex Vesker }
917838e172SAlex Vesker 
dr_table_uninit_fdb(struct mlx5dr_table * tbl)927838e172SAlex Vesker static void dr_table_uninit_fdb(struct mlx5dr_table *tbl)
937838e172SAlex Vesker {
947838e172SAlex Vesker 	dr_table_uninit_nic(&tbl->rx);
957838e172SAlex Vesker 	dr_table_uninit_nic(&tbl->tx);
967838e172SAlex Vesker }
977838e172SAlex Vesker 
dr_table_uninit(struct mlx5dr_table * tbl)987838e172SAlex Vesker static void dr_table_uninit(struct mlx5dr_table *tbl)
997838e172SAlex Vesker {
100ed03a418SAlex Vesker 	mlx5dr_domain_lock(tbl->dmn);
1017838e172SAlex Vesker 
1027838e172SAlex Vesker 	switch (tbl->dmn->type) {
1037838e172SAlex Vesker 	case MLX5DR_DOMAIN_TYPE_NIC_RX:
1047838e172SAlex Vesker 		dr_table_uninit_nic(&tbl->rx);
1057838e172SAlex Vesker 		break;
1067838e172SAlex Vesker 	case MLX5DR_DOMAIN_TYPE_NIC_TX:
1077838e172SAlex Vesker 		dr_table_uninit_nic(&tbl->tx);
1087838e172SAlex Vesker 		break;
1097838e172SAlex Vesker 	case MLX5DR_DOMAIN_TYPE_FDB:
1107838e172SAlex Vesker 		dr_table_uninit_fdb(tbl);
1117838e172SAlex Vesker 		break;
1127838e172SAlex Vesker 	default:
1137838e172SAlex Vesker 		WARN_ON(true);
1147838e172SAlex Vesker 		break;
1157838e172SAlex Vesker 	}
1167838e172SAlex Vesker 
117ed03a418SAlex Vesker 	mlx5dr_domain_unlock(tbl->dmn);
1187838e172SAlex Vesker }
1197838e172SAlex Vesker 
dr_table_init_nic(struct mlx5dr_domain * dmn,struct mlx5dr_table_rx_tx * nic_tbl)1207838e172SAlex Vesker static int dr_table_init_nic(struct mlx5dr_domain *dmn,
1217838e172SAlex Vesker 			     struct mlx5dr_table_rx_tx *nic_tbl)
1227838e172SAlex Vesker {
1237838e172SAlex Vesker 	struct mlx5dr_domain_rx_tx *nic_dmn = nic_tbl->nic_dmn;
1247838e172SAlex Vesker 	struct mlx5dr_htbl_connect_info info;
1257838e172SAlex Vesker 	int ret;
1267838e172SAlex Vesker 
127cc2295cdSYevgeny Kliteynik 	INIT_LIST_HEAD(&nic_tbl->nic_matcher_list);
128cc2295cdSYevgeny Kliteynik 
1297838e172SAlex Vesker 	nic_tbl->default_icm_addr = nic_dmn->default_icm_addr;
1307838e172SAlex Vesker 
1317838e172SAlex Vesker 	nic_tbl->s_anchor = mlx5dr_ste_htbl_alloc(dmn->ste_icm_pool,
1327838e172SAlex Vesker 						  DR_CHUNK_SIZE_1,
1337838e172SAlex Vesker 						  MLX5DR_STE_LU_TYPE_DONT_CARE,
1347838e172SAlex Vesker 						  0);
135b7d0db55SErez Shitrit 	if (!nic_tbl->s_anchor) {
136b7d0db55SErez Shitrit 		mlx5dr_err(dmn, "Failed allocating htbl\n");
1377838e172SAlex Vesker 		return -ENOMEM;
138b7d0db55SErez Shitrit 	}
1397838e172SAlex Vesker 
1407838e172SAlex Vesker 	info.type = CONNECT_MISS;
1417838e172SAlex Vesker 	info.miss_icm_addr = nic_dmn->default_icm_addr;
1427838e172SAlex Vesker 	ret = mlx5dr_ste_htbl_init_and_postsend(dmn, nic_dmn,
1437838e172SAlex Vesker 						nic_tbl->s_anchor,
1447838e172SAlex Vesker 						&info, true);
145b7d0db55SErez Shitrit 	if (ret) {
146b7d0db55SErez Shitrit 		mlx5dr_err(dmn, "Failed int and send htbl\n");
1477838e172SAlex Vesker 		goto free_s_anchor;
148b7d0db55SErez Shitrit 	}
1497838e172SAlex Vesker 
1507838e172SAlex Vesker 	mlx5dr_htbl_get(nic_tbl->s_anchor);
1517838e172SAlex Vesker 
1527838e172SAlex Vesker 	return 0;
1537838e172SAlex Vesker 
1547838e172SAlex Vesker free_s_anchor:
1557838e172SAlex Vesker 	mlx5dr_ste_htbl_free(nic_tbl->s_anchor);
1567838e172SAlex Vesker 	return ret;
1577838e172SAlex Vesker }
1587838e172SAlex Vesker 
dr_table_init_fdb(struct mlx5dr_table * tbl)1597838e172SAlex Vesker static int dr_table_init_fdb(struct mlx5dr_table *tbl)
1607838e172SAlex Vesker {
1617838e172SAlex Vesker 	int ret;
1627838e172SAlex Vesker 
1637838e172SAlex Vesker 	ret = dr_table_init_nic(tbl->dmn, &tbl->rx);
1647838e172SAlex Vesker 	if (ret)
1657838e172SAlex Vesker 		return ret;
1667838e172SAlex Vesker 
1677838e172SAlex Vesker 	ret = dr_table_init_nic(tbl->dmn, &tbl->tx);
1687838e172SAlex Vesker 	if (ret)
1697838e172SAlex Vesker 		goto destroy_rx;
1707838e172SAlex Vesker 
1717838e172SAlex Vesker 	return 0;
1727838e172SAlex Vesker 
1737838e172SAlex Vesker destroy_rx:
1747838e172SAlex Vesker 	dr_table_uninit_nic(&tbl->rx);
1757838e172SAlex Vesker 	return ret;
1767838e172SAlex Vesker }
1777838e172SAlex Vesker 
dr_table_init(struct mlx5dr_table * tbl)1787838e172SAlex Vesker static int dr_table_init(struct mlx5dr_table *tbl)
1797838e172SAlex Vesker {
1807838e172SAlex Vesker 	int ret = 0;
1817838e172SAlex Vesker 
1827838e172SAlex Vesker 	INIT_LIST_HEAD(&tbl->matcher_list);
1837838e172SAlex Vesker 
184ed03a418SAlex Vesker 	mlx5dr_domain_lock(tbl->dmn);
1857838e172SAlex Vesker 
1867838e172SAlex Vesker 	switch (tbl->dmn->type) {
1877838e172SAlex Vesker 	case MLX5DR_DOMAIN_TYPE_NIC_RX:
1887838e172SAlex Vesker 		tbl->table_type = MLX5_FLOW_TABLE_TYPE_NIC_RX;
1897838e172SAlex Vesker 		tbl->rx.nic_dmn = &tbl->dmn->info.rx;
1907838e172SAlex Vesker 		ret = dr_table_init_nic(tbl->dmn, &tbl->rx);
1917838e172SAlex Vesker 		break;
1927838e172SAlex Vesker 	case MLX5DR_DOMAIN_TYPE_NIC_TX:
1937838e172SAlex Vesker 		tbl->table_type = MLX5_FLOW_TABLE_TYPE_NIC_TX;
1947838e172SAlex Vesker 		tbl->tx.nic_dmn = &tbl->dmn->info.tx;
1957838e172SAlex Vesker 		ret = dr_table_init_nic(tbl->dmn, &tbl->tx);
1967838e172SAlex Vesker 		break;
1977838e172SAlex Vesker 	case MLX5DR_DOMAIN_TYPE_FDB:
1987838e172SAlex Vesker 		tbl->table_type = MLX5_FLOW_TABLE_TYPE_FDB;
1997838e172SAlex Vesker 		tbl->rx.nic_dmn = &tbl->dmn->info.rx;
2007838e172SAlex Vesker 		tbl->tx.nic_dmn = &tbl->dmn->info.tx;
2017838e172SAlex Vesker 		ret = dr_table_init_fdb(tbl);
2027838e172SAlex Vesker 		break;
2037838e172SAlex Vesker 	default:
2047838e172SAlex Vesker 		WARN_ON(true);
2057838e172SAlex Vesker 		break;
2067838e172SAlex Vesker 	}
2077838e172SAlex Vesker 
208ed03a418SAlex Vesker 	mlx5dr_domain_unlock(tbl->dmn);
2097838e172SAlex Vesker 
2107838e172SAlex Vesker 	return ret;
2117838e172SAlex Vesker }
2127838e172SAlex Vesker 
dr_table_destroy_sw_owned_tbl(struct mlx5dr_table * tbl)2137838e172SAlex Vesker static int dr_table_destroy_sw_owned_tbl(struct mlx5dr_table *tbl)
2147838e172SAlex Vesker {
2157838e172SAlex Vesker 	return mlx5dr_cmd_destroy_flow_table(tbl->dmn->mdev,
2167838e172SAlex Vesker 					     tbl->table_id,
2177838e172SAlex Vesker 					     tbl->table_type);
2187838e172SAlex Vesker }
2197838e172SAlex Vesker 
dr_table_create_sw_owned_tbl(struct mlx5dr_table * tbl,u16 uid)220b0bb369eSMark Bloch static int dr_table_create_sw_owned_tbl(struct mlx5dr_table *tbl, u16 uid)
2217838e172SAlex Vesker {
222988fd6b3SErez Shitrit 	bool en_encap = !!(tbl->flags & MLX5_FLOW_TABLE_TUNNEL_EN_REFORMAT);
223988fd6b3SErez Shitrit 	bool en_decap = !!(tbl->flags & MLX5_FLOW_TABLE_TUNNEL_EN_DECAP);
224cc78dbd7SAlex Vesker 	struct mlx5dr_cmd_create_flow_table_attr ft_attr = {};
2257838e172SAlex Vesker 	u64 icm_addr_rx = 0;
2267838e172SAlex Vesker 	u64 icm_addr_tx = 0;
2277838e172SAlex Vesker 	int ret;
2287838e172SAlex Vesker 
2297838e172SAlex Vesker 	if (tbl->rx.s_anchor)
2305c4f9b6eSRongwei Liu 		icm_addr_rx = mlx5dr_icm_pool_get_chunk_icm_addr(tbl->rx.s_anchor->chunk);
2317838e172SAlex Vesker 
2327838e172SAlex Vesker 	if (tbl->tx.s_anchor)
2335c4f9b6eSRongwei Liu 		icm_addr_tx = mlx5dr_icm_pool_get_chunk_icm_addr(tbl->tx.s_anchor->chunk);
2347838e172SAlex Vesker 
235cc78dbd7SAlex Vesker 	ft_attr.table_type = tbl->table_type;
236cc78dbd7SAlex Vesker 	ft_attr.icm_addr_rx = icm_addr_rx;
237cc78dbd7SAlex Vesker 	ft_attr.icm_addr_tx = icm_addr_tx;
238cc78dbd7SAlex Vesker 	ft_attr.level = tbl->dmn->info.caps.max_ft_level - 1;
239cc78dbd7SAlex Vesker 	ft_attr.sw_owner = true;
240988fd6b3SErez Shitrit 	ft_attr.decap_en = en_decap;
241988fd6b3SErez Shitrit 	ft_attr.reformat_en = en_encap;
242b0bb369eSMark Bloch 	ft_attr.uid = uid;
243cc78dbd7SAlex Vesker 
244cc78dbd7SAlex Vesker 	ret = mlx5dr_cmd_create_flow_table(tbl->dmn->mdev, &ft_attr,
245cc78dbd7SAlex Vesker 					   NULL, &tbl->table_id);
2467838e172SAlex Vesker 
2477838e172SAlex Vesker 	return ret;
2487838e172SAlex Vesker }
2497838e172SAlex Vesker 
mlx5dr_table_create(struct mlx5dr_domain * dmn,u32 level,u32 flags,u16 uid)250b0bb369eSMark Bloch struct mlx5dr_table *mlx5dr_table_create(struct mlx5dr_domain *dmn, u32 level,
251b0bb369eSMark Bloch 					 u32 flags, u16 uid)
2527838e172SAlex Vesker {
2537838e172SAlex Vesker 	struct mlx5dr_table *tbl;
2547838e172SAlex Vesker 	int ret;
2557838e172SAlex Vesker 
2567838e172SAlex Vesker 	refcount_inc(&dmn->refcount);
2577838e172SAlex Vesker 
2587838e172SAlex Vesker 	tbl = kzalloc(sizeof(*tbl), GFP_KERNEL);
2597838e172SAlex Vesker 	if (!tbl)
2607838e172SAlex Vesker 		goto dec_ref;
2617838e172SAlex Vesker 
2627838e172SAlex Vesker 	tbl->dmn = dmn;
2637838e172SAlex Vesker 	tbl->level = level;
264988fd6b3SErez Shitrit 	tbl->flags = flags;
2657838e172SAlex Vesker 	refcount_set(&tbl->refcount, 1);
2667838e172SAlex Vesker 
2677838e172SAlex Vesker 	ret = dr_table_init(tbl);
2687838e172SAlex Vesker 	if (ret)
2697838e172SAlex Vesker 		goto free_tbl;
2707838e172SAlex Vesker 
271b0bb369eSMark Bloch 	ret = dr_table_create_sw_owned_tbl(tbl, uid);
2727838e172SAlex Vesker 	if (ret)
2737838e172SAlex Vesker 		goto uninit_tbl;
2747838e172SAlex Vesker 
2759222f0b2SMuhammad Sammar 	INIT_LIST_HEAD(&tbl->dbg_node);
2769222f0b2SMuhammad Sammar 	mlx5dr_dbg_tbl_add(tbl);
2777838e172SAlex Vesker 	return tbl;
2787838e172SAlex Vesker 
2797838e172SAlex Vesker uninit_tbl:
2807838e172SAlex Vesker 	dr_table_uninit(tbl);
2817838e172SAlex Vesker free_tbl:
2827838e172SAlex Vesker 	kfree(tbl);
2837838e172SAlex Vesker dec_ref:
2847838e172SAlex Vesker 	refcount_dec(&dmn->refcount);
2857838e172SAlex Vesker 	return NULL;
2867838e172SAlex Vesker }
2877838e172SAlex Vesker 
mlx5dr_table_destroy(struct mlx5dr_table * tbl)2887838e172SAlex Vesker int mlx5dr_table_destroy(struct mlx5dr_table *tbl)
2897838e172SAlex Vesker {
2907838e172SAlex Vesker 	int ret;
2917838e172SAlex Vesker 
292b5412827SYevgeny Kliteynik 	if (WARN_ON_ONCE(refcount_read(&tbl->refcount) > 1))
2937838e172SAlex Vesker 		return -EBUSY;
2947838e172SAlex Vesker 
2959222f0b2SMuhammad Sammar 	mlx5dr_dbg_tbl_del(tbl);
2967838e172SAlex Vesker 	ret = dr_table_destroy_sw_owned_tbl(tbl);
2977838e172SAlex Vesker 	if (ret)
2987838e172SAlex Vesker 		mlx5dr_err(tbl->dmn, "Failed to destroy sw owned table\n");
2997838e172SAlex Vesker 
3007838e172SAlex Vesker 	dr_table_uninit(tbl);
3017838e172SAlex Vesker 
3027838e172SAlex Vesker 	if (tbl->miss_action)
3037838e172SAlex Vesker 		refcount_dec(&tbl->miss_action->refcount);
3047838e172SAlex Vesker 
3057838e172SAlex Vesker 	refcount_dec(&tbl->dmn->refcount);
3067838e172SAlex Vesker 	kfree(tbl);
3077838e172SAlex Vesker 
3087838e172SAlex Vesker 	return ret;
3097838e172SAlex Vesker }
3107838e172SAlex Vesker 
mlx5dr_table_get_id(struct mlx5dr_table * tbl)3117838e172SAlex Vesker u32 mlx5dr_table_get_id(struct mlx5dr_table *tbl)
3127838e172SAlex Vesker {
3137838e172SAlex Vesker 	return tbl->table_id;
3147838e172SAlex Vesker }
31534ea969dSPaul Blakey 
mlx5dr_table_get_from_fs_ft(struct mlx5_flow_table * ft)31634ea969dSPaul Blakey struct mlx5dr_table *mlx5dr_table_get_from_fs_ft(struct mlx5_flow_table *ft)
31734ea969dSPaul Blakey {
31834ea969dSPaul Blakey 	return ft->fs_dr_table.dr_table;
31934ea969dSPaul Blakey }
320