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 
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;
13cc2295cdSYevgeny Kliteynik 	int ret;
14cc2295cdSYevgeny Kliteynik 
15cc2295cdSYevgeny Kliteynik 	if (!list_empty(&nic_tbl->nic_matcher_list))
16cc2295cdSYevgeny Kliteynik 		last_nic_matcher = list_last_entry(&nic_tbl->nic_matcher_list,
17cc2295cdSYevgeny Kliteynik 						   struct mlx5dr_matcher_rx_tx,
18cc2295cdSYevgeny Kliteynik 						   list_node);
19cc2295cdSYevgeny Kliteynik 
20cc2295cdSYevgeny Kliteynik 	if (last_nic_matcher)
21cc2295cdSYevgeny Kliteynik 		last_htbl = last_nic_matcher->e_anchor;
22cc2295cdSYevgeny Kliteynik 	else
23cc2295cdSYevgeny Kliteynik 		last_htbl = nic_tbl->s_anchor;
24cc2295cdSYevgeny Kliteynik 
25cc2295cdSYevgeny Kliteynik 	if (action)
26cc2295cdSYevgeny Kliteynik 		nic_tbl->default_icm_addr =
27cc2295cdSYevgeny Kliteynik 			nic_tbl->nic_dmn->type == DR_DOMAIN_NIC_TYPE_RX ?
28cc2295cdSYevgeny Kliteynik 				action->dest_tbl->tbl->rx.s_anchor->chunk->icm_addr :
29cc2295cdSYevgeny Kliteynik 				action->dest_tbl->tbl->tx.s_anchor->chunk->icm_addr;
30cc2295cdSYevgeny Kliteynik 	else
31cc2295cdSYevgeny Kliteynik 		nic_tbl->default_icm_addr = nic_tbl->nic_dmn->default_icm_addr;
32cc2295cdSYevgeny Kliteynik 
33cc2295cdSYevgeny Kliteynik 	info.type = CONNECT_MISS;
34cc2295cdSYevgeny Kliteynik 	info.miss_icm_addr = nic_tbl->default_icm_addr;
35cc2295cdSYevgeny Kliteynik 
36cc2295cdSYevgeny Kliteynik 	ret = mlx5dr_ste_htbl_init_and_postsend(dmn, nic_tbl->nic_dmn,
37cc2295cdSYevgeny Kliteynik 						last_htbl, &info, true);
38cc2295cdSYevgeny Kliteynik 	if (ret)
39cc2295cdSYevgeny Kliteynik 		mlx5dr_dbg(dmn, "Failed to set NIC RX/TX miss action, ret %d\n", ret);
40cc2295cdSYevgeny Kliteynik 
41cc2295cdSYevgeny Kliteynik 	return ret;
42cc2295cdSYevgeny Kliteynik }
43cc2295cdSYevgeny Kliteynik 
447838e172SAlex Vesker int mlx5dr_table_set_miss_action(struct mlx5dr_table *tbl,
457838e172SAlex Vesker 				 struct mlx5dr_action *action)
467838e172SAlex Vesker {
477838e172SAlex Vesker 	int ret;
487838e172SAlex Vesker 
497838e172SAlex Vesker 	if (action && action->action_type != DR_ACTION_TYP_FT)
507838e172SAlex Vesker 		return -EOPNOTSUPP;
517838e172SAlex Vesker 
52ed03a418SAlex Vesker 	mlx5dr_domain_lock(tbl->dmn);
537838e172SAlex Vesker 
547838e172SAlex Vesker 	if (tbl->dmn->type == MLX5DR_DOMAIN_TYPE_NIC_RX ||
557838e172SAlex Vesker 	    tbl->dmn->type == MLX5DR_DOMAIN_TYPE_FDB) {
56cc2295cdSYevgeny Kliteynik 		ret = dr_table_set_miss_action_nic(tbl->dmn, &tbl->rx, action);
57cc2295cdSYevgeny Kliteynik 		if (ret)
587838e172SAlex Vesker 			goto out;
597838e172SAlex Vesker 	}
607838e172SAlex Vesker 
617838e172SAlex Vesker 	if (tbl->dmn->type == MLX5DR_DOMAIN_TYPE_NIC_TX ||
627838e172SAlex Vesker 	    tbl->dmn->type == MLX5DR_DOMAIN_TYPE_FDB) {
63cc2295cdSYevgeny Kliteynik 		ret = dr_table_set_miss_action_nic(tbl->dmn, &tbl->tx, action);
64cc2295cdSYevgeny Kliteynik 		if (ret)
657838e172SAlex Vesker 			goto out;
667838e172SAlex Vesker 	}
677838e172SAlex Vesker 
687838e172SAlex Vesker 	/* Release old action */
697838e172SAlex Vesker 	if (tbl->miss_action)
707838e172SAlex Vesker 		refcount_dec(&tbl->miss_action->refcount);
717838e172SAlex Vesker 
727838e172SAlex Vesker 	/* Set new miss action */
737838e172SAlex Vesker 	tbl->miss_action = action;
747838e172SAlex Vesker 	if (tbl->miss_action)
757838e172SAlex Vesker 		refcount_inc(&action->refcount);
767838e172SAlex Vesker 
777838e172SAlex Vesker out:
78ed03a418SAlex Vesker 	mlx5dr_domain_unlock(tbl->dmn);
797838e172SAlex Vesker 	return ret;
807838e172SAlex Vesker }
817838e172SAlex Vesker 
827838e172SAlex Vesker static void dr_table_uninit_nic(struct mlx5dr_table_rx_tx *nic_tbl)
837838e172SAlex Vesker {
847838e172SAlex Vesker 	mlx5dr_htbl_put(nic_tbl->s_anchor);
857838e172SAlex Vesker }
867838e172SAlex Vesker 
877838e172SAlex Vesker static void dr_table_uninit_fdb(struct mlx5dr_table *tbl)
887838e172SAlex Vesker {
897838e172SAlex Vesker 	dr_table_uninit_nic(&tbl->rx);
907838e172SAlex Vesker 	dr_table_uninit_nic(&tbl->tx);
917838e172SAlex Vesker }
927838e172SAlex Vesker 
937838e172SAlex Vesker static void dr_table_uninit(struct mlx5dr_table *tbl)
947838e172SAlex Vesker {
95ed03a418SAlex Vesker 	mlx5dr_domain_lock(tbl->dmn);
967838e172SAlex Vesker 
977838e172SAlex Vesker 	switch (tbl->dmn->type) {
987838e172SAlex Vesker 	case MLX5DR_DOMAIN_TYPE_NIC_RX:
997838e172SAlex Vesker 		dr_table_uninit_nic(&tbl->rx);
1007838e172SAlex Vesker 		break;
1017838e172SAlex Vesker 	case MLX5DR_DOMAIN_TYPE_NIC_TX:
1027838e172SAlex Vesker 		dr_table_uninit_nic(&tbl->tx);
1037838e172SAlex Vesker 		break;
1047838e172SAlex Vesker 	case MLX5DR_DOMAIN_TYPE_FDB:
1057838e172SAlex Vesker 		dr_table_uninit_fdb(tbl);
1067838e172SAlex Vesker 		break;
1077838e172SAlex Vesker 	default:
1087838e172SAlex Vesker 		WARN_ON(true);
1097838e172SAlex Vesker 		break;
1107838e172SAlex Vesker 	}
1117838e172SAlex Vesker 
112ed03a418SAlex Vesker 	mlx5dr_domain_unlock(tbl->dmn);
1137838e172SAlex Vesker }
1147838e172SAlex Vesker 
1157838e172SAlex Vesker static int dr_table_init_nic(struct mlx5dr_domain *dmn,
1167838e172SAlex Vesker 			     struct mlx5dr_table_rx_tx *nic_tbl)
1177838e172SAlex Vesker {
1187838e172SAlex Vesker 	struct mlx5dr_domain_rx_tx *nic_dmn = nic_tbl->nic_dmn;
1197838e172SAlex Vesker 	struct mlx5dr_htbl_connect_info info;
1207838e172SAlex Vesker 	int ret;
1217838e172SAlex Vesker 
122cc2295cdSYevgeny Kliteynik 	INIT_LIST_HEAD(&nic_tbl->nic_matcher_list);
123cc2295cdSYevgeny Kliteynik 
1247838e172SAlex Vesker 	nic_tbl->default_icm_addr = nic_dmn->default_icm_addr;
1257838e172SAlex Vesker 
1267838e172SAlex Vesker 	nic_tbl->s_anchor = mlx5dr_ste_htbl_alloc(dmn->ste_icm_pool,
1277838e172SAlex Vesker 						  DR_CHUNK_SIZE_1,
1287838e172SAlex Vesker 						  MLX5DR_STE_LU_TYPE_DONT_CARE,
1297838e172SAlex Vesker 						  0);
130b7d0db55SErez Shitrit 	if (!nic_tbl->s_anchor) {
131b7d0db55SErez Shitrit 		mlx5dr_err(dmn, "Failed allocating htbl\n");
1327838e172SAlex Vesker 		return -ENOMEM;
133b7d0db55SErez Shitrit 	}
1347838e172SAlex Vesker 
1357838e172SAlex Vesker 	info.type = CONNECT_MISS;
1367838e172SAlex Vesker 	info.miss_icm_addr = nic_dmn->default_icm_addr;
1377838e172SAlex Vesker 	ret = mlx5dr_ste_htbl_init_and_postsend(dmn, nic_dmn,
1387838e172SAlex Vesker 						nic_tbl->s_anchor,
1397838e172SAlex Vesker 						&info, true);
140b7d0db55SErez Shitrit 	if (ret) {
141b7d0db55SErez Shitrit 		mlx5dr_err(dmn, "Failed int and send htbl\n");
1427838e172SAlex Vesker 		goto free_s_anchor;
143b7d0db55SErez Shitrit 	}
1447838e172SAlex Vesker 
1457838e172SAlex Vesker 	mlx5dr_htbl_get(nic_tbl->s_anchor);
1467838e172SAlex Vesker 
1477838e172SAlex Vesker 	return 0;
1487838e172SAlex Vesker 
1497838e172SAlex Vesker free_s_anchor:
1507838e172SAlex Vesker 	mlx5dr_ste_htbl_free(nic_tbl->s_anchor);
1517838e172SAlex Vesker 	return ret;
1527838e172SAlex Vesker }
1537838e172SAlex Vesker 
1547838e172SAlex Vesker static int dr_table_init_fdb(struct mlx5dr_table *tbl)
1557838e172SAlex Vesker {
1567838e172SAlex Vesker 	int ret;
1577838e172SAlex Vesker 
1587838e172SAlex Vesker 	ret = dr_table_init_nic(tbl->dmn, &tbl->rx);
1597838e172SAlex Vesker 	if (ret)
1607838e172SAlex Vesker 		return ret;
1617838e172SAlex Vesker 
1627838e172SAlex Vesker 	ret = dr_table_init_nic(tbl->dmn, &tbl->tx);
1637838e172SAlex Vesker 	if (ret)
1647838e172SAlex Vesker 		goto destroy_rx;
1657838e172SAlex Vesker 
1667838e172SAlex Vesker 	return 0;
1677838e172SAlex Vesker 
1687838e172SAlex Vesker destroy_rx:
1697838e172SAlex Vesker 	dr_table_uninit_nic(&tbl->rx);
1707838e172SAlex Vesker 	return ret;
1717838e172SAlex Vesker }
1727838e172SAlex Vesker 
1737838e172SAlex Vesker static int dr_table_init(struct mlx5dr_table *tbl)
1747838e172SAlex Vesker {
1757838e172SAlex Vesker 	int ret = 0;
1767838e172SAlex Vesker 
1777838e172SAlex Vesker 	INIT_LIST_HEAD(&tbl->matcher_list);
1787838e172SAlex Vesker 
179ed03a418SAlex Vesker 	mlx5dr_domain_lock(tbl->dmn);
1807838e172SAlex Vesker 
1817838e172SAlex Vesker 	switch (tbl->dmn->type) {
1827838e172SAlex Vesker 	case MLX5DR_DOMAIN_TYPE_NIC_RX:
1837838e172SAlex Vesker 		tbl->table_type = MLX5_FLOW_TABLE_TYPE_NIC_RX;
1847838e172SAlex Vesker 		tbl->rx.nic_dmn = &tbl->dmn->info.rx;
1857838e172SAlex Vesker 		ret = dr_table_init_nic(tbl->dmn, &tbl->rx);
1867838e172SAlex Vesker 		break;
1877838e172SAlex Vesker 	case MLX5DR_DOMAIN_TYPE_NIC_TX:
1887838e172SAlex Vesker 		tbl->table_type = MLX5_FLOW_TABLE_TYPE_NIC_TX;
1897838e172SAlex Vesker 		tbl->tx.nic_dmn = &tbl->dmn->info.tx;
1907838e172SAlex Vesker 		ret = dr_table_init_nic(tbl->dmn, &tbl->tx);
1917838e172SAlex Vesker 		break;
1927838e172SAlex Vesker 	case MLX5DR_DOMAIN_TYPE_FDB:
1937838e172SAlex Vesker 		tbl->table_type = MLX5_FLOW_TABLE_TYPE_FDB;
1947838e172SAlex Vesker 		tbl->rx.nic_dmn = &tbl->dmn->info.rx;
1957838e172SAlex Vesker 		tbl->tx.nic_dmn = &tbl->dmn->info.tx;
1967838e172SAlex Vesker 		ret = dr_table_init_fdb(tbl);
1977838e172SAlex Vesker 		break;
1987838e172SAlex Vesker 	default:
1997838e172SAlex Vesker 		WARN_ON(true);
2007838e172SAlex Vesker 		break;
2017838e172SAlex Vesker 	}
2027838e172SAlex Vesker 
203ed03a418SAlex Vesker 	mlx5dr_domain_unlock(tbl->dmn);
2047838e172SAlex Vesker 
2057838e172SAlex Vesker 	return ret;
2067838e172SAlex Vesker }
2077838e172SAlex Vesker 
2087838e172SAlex Vesker static int dr_table_destroy_sw_owned_tbl(struct mlx5dr_table *tbl)
2097838e172SAlex Vesker {
2107838e172SAlex Vesker 	return mlx5dr_cmd_destroy_flow_table(tbl->dmn->mdev,
2117838e172SAlex Vesker 					     tbl->table_id,
2127838e172SAlex Vesker 					     tbl->table_type);
2137838e172SAlex Vesker }
2147838e172SAlex Vesker 
2157838e172SAlex Vesker static int dr_table_create_sw_owned_tbl(struct mlx5dr_table *tbl)
2167838e172SAlex Vesker {
217988fd6b3SErez Shitrit 	bool en_encap = !!(tbl->flags & MLX5_FLOW_TABLE_TUNNEL_EN_REFORMAT);
218988fd6b3SErez Shitrit 	bool en_decap = !!(tbl->flags & MLX5_FLOW_TABLE_TUNNEL_EN_DECAP);
219cc78dbd7SAlex Vesker 	struct mlx5dr_cmd_create_flow_table_attr ft_attr = {};
2207838e172SAlex Vesker 	u64 icm_addr_rx = 0;
2217838e172SAlex Vesker 	u64 icm_addr_tx = 0;
2227838e172SAlex Vesker 	int ret;
2237838e172SAlex Vesker 
2247838e172SAlex Vesker 	if (tbl->rx.s_anchor)
2257838e172SAlex Vesker 		icm_addr_rx = tbl->rx.s_anchor->chunk->icm_addr;
2267838e172SAlex Vesker 
2277838e172SAlex Vesker 	if (tbl->tx.s_anchor)
2287838e172SAlex Vesker 		icm_addr_tx = tbl->tx.s_anchor->chunk->icm_addr;
2297838e172SAlex Vesker 
230cc78dbd7SAlex Vesker 	ft_attr.table_type = tbl->table_type;
231cc78dbd7SAlex Vesker 	ft_attr.icm_addr_rx = icm_addr_rx;
232cc78dbd7SAlex Vesker 	ft_attr.icm_addr_tx = icm_addr_tx;
233cc78dbd7SAlex Vesker 	ft_attr.level = tbl->dmn->info.caps.max_ft_level - 1;
234cc78dbd7SAlex Vesker 	ft_attr.sw_owner = true;
235988fd6b3SErez Shitrit 	ft_attr.decap_en = en_decap;
236988fd6b3SErez Shitrit 	ft_attr.reformat_en = en_encap;
237cc78dbd7SAlex Vesker 
238cc78dbd7SAlex Vesker 	ret = mlx5dr_cmd_create_flow_table(tbl->dmn->mdev, &ft_attr,
239cc78dbd7SAlex Vesker 					   NULL, &tbl->table_id);
2407838e172SAlex Vesker 
2417838e172SAlex Vesker 	return ret;
2427838e172SAlex Vesker }
2437838e172SAlex Vesker 
244988fd6b3SErez Shitrit struct mlx5dr_table *mlx5dr_table_create(struct mlx5dr_domain *dmn, u32 level, u32 flags)
2457838e172SAlex Vesker {
2467838e172SAlex Vesker 	struct mlx5dr_table *tbl;
2477838e172SAlex Vesker 	int ret;
2487838e172SAlex Vesker 
2497838e172SAlex Vesker 	refcount_inc(&dmn->refcount);
2507838e172SAlex Vesker 
2517838e172SAlex Vesker 	tbl = kzalloc(sizeof(*tbl), GFP_KERNEL);
2527838e172SAlex Vesker 	if (!tbl)
2537838e172SAlex Vesker 		goto dec_ref;
2547838e172SAlex Vesker 
2557838e172SAlex Vesker 	tbl->dmn = dmn;
2567838e172SAlex Vesker 	tbl->level = level;
257988fd6b3SErez Shitrit 	tbl->flags = flags;
2587838e172SAlex Vesker 	refcount_set(&tbl->refcount, 1);
2597838e172SAlex Vesker 
2607838e172SAlex Vesker 	ret = dr_table_init(tbl);
2617838e172SAlex Vesker 	if (ret)
2627838e172SAlex Vesker 		goto free_tbl;
2637838e172SAlex Vesker 
2647838e172SAlex Vesker 	ret = dr_table_create_sw_owned_tbl(tbl);
2657838e172SAlex Vesker 	if (ret)
2667838e172SAlex Vesker 		goto uninit_tbl;
2677838e172SAlex Vesker 
2689222f0b2SMuhammad Sammar 	INIT_LIST_HEAD(&tbl->dbg_node);
2699222f0b2SMuhammad Sammar 	mlx5dr_dbg_tbl_add(tbl);
2707838e172SAlex Vesker 	return tbl;
2717838e172SAlex Vesker 
2727838e172SAlex Vesker uninit_tbl:
2737838e172SAlex Vesker 	dr_table_uninit(tbl);
2747838e172SAlex Vesker free_tbl:
2757838e172SAlex Vesker 	kfree(tbl);
2767838e172SAlex Vesker dec_ref:
2777838e172SAlex Vesker 	refcount_dec(&dmn->refcount);
2787838e172SAlex Vesker 	return NULL;
2797838e172SAlex Vesker }
2807838e172SAlex Vesker 
2817838e172SAlex Vesker int mlx5dr_table_destroy(struct mlx5dr_table *tbl)
2827838e172SAlex Vesker {
2837838e172SAlex Vesker 	int ret;
2847838e172SAlex Vesker 
285b5412827SYevgeny Kliteynik 	if (WARN_ON_ONCE(refcount_read(&tbl->refcount) > 1))
2867838e172SAlex Vesker 		return -EBUSY;
2877838e172SAlex Vesker 
2889222f0b2SMuhammad Sammar 	mlx5dr_dbg_tbl_del(tbl);
2897838e172SAlex Vesker 	ret = dr_table_destroy_sw_owned_tbl(tbl);
2907838e172SAlex Vesker 	if (ret)
2917838e172SAlex Vesker 		return ret;
2927838e172SAlex Vesker 
2937838e172SAlex Vesker 	dr_table_uninit(tbl);
2947838e172SAlex Vesker 
2957838e172SAlex Vesker 	if (tbl->miss_action)
2967838e172SAlex Vesker 		refcount_dec(&tbl->miss_action->refcount);
2977838e172SAlex Vesker 
2987838e172SAlex Vesker 	refcount_dec(&tbl->dmn->refcount);
2997838e172SAlex Vesker 	kfree(tbl);
3007838e172SAlex Vesker 
3017838e172SAlex Vesker 	return ret;
3027838e172SAlex Vesker }
3037838e172SAlex Vesker 
3047838e172SAlex Vesker u32 mlx5dr_table_get_id(struct mlx5dr_table *tbl)
3057838e172SAlex Vesker {
3067838e172SAlex Vesker 	return tbl->table_id;
3077838e172SAlex Vesker }
308*34ea969dSPaul Blakey 
309*34ea969dSPaul Blakey struct mlx5dr_table *mlx5dr_table_get_from_fs_ft(struct mlx5_flow_table *ft)
310*34ea969dSPaul Blakey {
311*34ea969dSPaul Blakey 	return ft->fs_dr_table.dr_table;
312*34ea969dSPaul Blakey }
313