14ec9e7b0SAlex Vesker // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
24ec9e7b0SAlex Vesker /* Copyright (c) 2019 Mellanox Technologies. */
34ec9e7b0SAlex Vesker 
44ec9e7b0SAlex Vesker #include <linux/mlx5/eswitch.h>
56b8b4258SMiaoqian Lin #include <linux/err.h>
64ec9e7b0SAlex Vesker #include "dr_types.h"
74ec9e7b0SAlex Vesker 
864f45c0fSYevgeny Kliteynik #define DR_DOMAIN_SW_STEERING_SUPPORTED(dmn, dmn_type)	\
964f45c0fSYevgeny Kliteynik 	((dmn)->info.caps.dmn_type##_sw_owner ||	\
1064f45c0fSYevgeny Kliteynik 	 ((dmn)->info.caps.dmn_type##_sw_owner_v2 &&	\
116862c787SYevgeny Kliteynik 	  (dmn)->info.caps.sw_format_ver <= MLX5_STEERING_FORMAT_CONNECTX_7))
1264f45c0fSYevgeny Kliteynik 
13*108ff821SYevgeny Kliteynik bool mlx5dr_domain_is_support_ptrn_arg(struct mlx5dr_domain *dmn)
14*108ff821SYevgeny Kliteynik {
15*108ff821SYevgeny Kliteynik 	return false;
16*108ff821SYevgeny Kliteynik }
17*108ff821SYevgeny Kliteynik 
18*108ff821SYevgeny Kliteynik static int dr_domain_init_modify_header_resources(struct mlx5dr_domain *dmn)
19*108ff821SYevgeny Kliteynik {
20*108ff821SYevgeny Kliteynik 	if (!mlx5dr_domain_is_support_ptrn_arg(dmn))
21*108ff821SYevgeny Kliteynik 		return 0;
22*108ff821SYevgeny Kliteynik 
23*108ff821SYevgeny Kliteynik 	dmn->ptrn_mgr = mlx5dr_ptrn_mgr_create(dmn);
24*108ff821SYevgeny Kliteynik 	if (!dmn->ptrn_mgr) {
25*108ff821SYevgeny Kliteynik 		mlx5dr_err(dmn, "Couldn't create ptrn_mgr\n");
26*108ff821SYevgeny Kliteynik 		return -ENOMEM;
27*108ff821SYevgeny Kliteynik 	}
28*108ff821SYevgeny Kliteynik 
29*108ff821SYevgeny Kliteynik 	return 0;
30*108ff821SYevgeny Kliteynik }
31*108ff821SYevgeny Kliteynik 
32*108ff821SYevgeny Kliteynik static void dr_domain_destroy_modify_header_resources(struct mlx5dr_domain *dmn)
33*108ff821SYevgeny Kliteynik {
34*108ff821SYevgeny Kliteynik 	if (!mlx5dr_domain_is_support_ptrn_arg(dmn))
35*108ff821SYevgeny Kliteynik 		return;
36*108ff821SYevgeny Kliteynik 
37*108ff821SYevgeny Kliteynik 	mlx5dr_ptrn_mgr_destroy(dmn->ptrn_mgr);
38*108ff821SYevgeny Kliteynik }
39*108ff821SYevgeny Kliteynik 
40c0e90fc2SYevgeny Kliteynik static void dr_domain_init_csum_recalc_fts(struct mlx5dr_domain *dmn)
414ec9e7b0SAlex Vesker {
424ec9e7b0SAlex Vesker 	/* Per vport cached FW FT for checksum recalculation, this
43c0e90fc2SYevgeny Kliteynik 	 * recalculation is needed due to a HW bug in STEv0.
444ec9e7b0SAlex Vesker 	 */
45c0e90fc2SYevgeny Kliteynik 	xa_init(&dmn->csum_fts_xa);
464ec9e7b0SAlex Vesker }
474ec9e7b0SAlex Vesker 
48c0e90fc2SYevgeny Kliteynik static void dr_domain_uninit_csum_recalc_fts(struct mlx5dr_domain *dmn)
494ec9e7b0SAlex Vesker {
50c0e90fc2SYevgeny Kliteynik 	struct mlx5dr_fw_recalc_cs_ft *recalc_cs_ft;
51c0e90fc2SYevgeny Kliteynik 	unsigned long i;
524ec9e7b0SAlex Vesker 
53c0e90fc2SYevgeny Kliteynik 	xa_for_each(&dmn->csum_fts_xa, i, recalc_cs_ft) {
54c0e90fc2SYevgeny Kliteynik 		if (recalc_cs_ft)
55c0e90fc2SYevgeny Kliteynik 			mlx5dr_fw_destroy_recalc_cs_ft(dmn, recalc_cs_ft);
564ec9e7b0SAlex Vesker 	}
574ec9e7b0SAlex Vesker 
58c0e90fc2SYevgeny Kliteynik 	xa_destroy(&dmn->csum_fts_xa);
594ec9e7b0SAlex Vesker }
604ec9e7b0SAlex Vesker 
61c0e90fc2SYevgeny Kliteynik int mlx5dr_domain_get_recalc_cs_ft_addr(struct mlx5dr_domain *dmn,
62f9f93bd5SYevgeny Kliteynik 					u16 vport_num,
634ec9e7b0SAlex Vesker 					u64 *rx_icm_addr)
644ec9e7b0SAlex Vesker {
654ec9e7b0SAlex Vesker 	struct mlx5dr_fw_recalc_cs_ft *recalc_cs_ft;
66c0e90fc2SYevgeny Kliteynik 	int ret;
674ec9e7b0SAlex Vesker 
68c0e90fc2SYevgeny Kliteynik 	recalc_cs_ft = xa_load(&dmn->csum_fts_xa, vport_num);
694ec9e7b0SAlex Vesker 	if (!recalc_cs_ft) {
70c0e90fc2SYevgeny Kliteynik 		/* Table hasn't been created yet */
714ec9e7b0SAlex Vesker 		recalc_cs_ft = mlx5dr_fw_create_recalc_cs_ft(dmn, vport_num);
724ec9e7b0SAlex Vesker 		if (!recalc_cs_ft)
734ec9e7b0SAlex Vesker 			return -EINVAL;
744ec9e7b0SAlex Vesker 
75c0e90fc2SYevgeny Kliteynik 		ret = xa_err(xa_store(&dmn->csum_fts_xa, vport_num,
76c0e90fc2SYevgeny Kliteynik 				      recalc_cs_ft, GFP_KERNEL));
77c0e90fc2SYevgeny Kliteynik 		if (ret)
78c0e90fc2SYevgeny Kliteynik 			return ret;
794ec9e7b0SAlex Vesker 	}
804ec9e7b0SAlex Vesker 
814ec9e7b0SAlex Vesker 	*rx_icm_addr = recalc_cs_ft->rx_icm_addr;
824ec9e7b0SAlex Vesker 
834ec9e7b0SAlex Vesker 	return 0;
844ec9e7b0SAlex Vesker }
854ec9e7b0SAlex Vesker 
86183a6706SYevgeny Kliteynik static int dr_domain_init_mem_resources(struct mlx5dr_domain *dmn)
87183a6706SYevgeny Kliteynik {
88183a6706SYevgeny Kliteynik 	int ret;
89183a6706SYevgeny Kliteynik 
90fd785e52SYevgeny Kliteynik 	dmn->chunks_kmem_cache = kmem_cache_create("mlx5_dr_chunks",
91fd785e52SYevgeny Kliteynik 						   sizeof(struct mlx5dr_icm_chunk), 0,
92fd785e52SYevgeny Kliteynik 						   SLAB_HWCACHE_ALIGN, NULL);
93fd785e52SYevgeny Kliteynik 	if (!dmn->chunks_kmem_cache) {
94fd785e52SYevgeny Kliteynik 		mlx5dr_err(dmn, "Couldn't create chunks kmem_cache\n");
95fd785e52SYevgeny Kliteynik 		return -ENOMEM;
96fd785e52SYevgeny Kliteynik 	}
97fd785e52SYevgeny Kliteynik 
98fb628b71SYevgeny Kliteynik 	dmn->htbls_kmem_cache = kmem_cache_create("mlx5_dr_htbls",
99fb628b71SYevgeny Kliteynik 						  sizeof(struct mlx5dr_ste_htbl), 0,
100fb628b71SYevgeny Kliteynik 						  SLAB_HWCACHE_ALIGN, NULL);
101fb628b71SYevgeny Kliteynik 	if (!dmn->htbls_kmem_cache) {
102fb628b71SYevgeny Kliteynik 		mlx5dr_err(dmn, "Couldn't create hash tables kmem_cache\n");
103fb628b71SYevgeny Kliteynik 		ret = -ENOMEM;
104fb628b71SYevgeny Kliteynik 		goto free_chunks_kmem_cache;
105fb628b71SYevgeny Kliteynik 	}
106fb628b71SYevgeny Kliteynik 
107183a6706SYevgeny Kliteynik 	dmn->ste_icm_pool = mlx5dr_icm_pool_create(dmn, DR_ICM_TYPE_STE);
108183a6706SYevgeny Kliteynik 	if (!dmn->ste_icm_pool) {
109183a6706SYevgeny Kliteynik 		mlx5dr_err(dmn, "Couldn't get icm memory\n");
110fd785e52SYevgeny Kliteynik 		ret = -ENOMEM;
111fb628b71SYevgeny Kliteynik 		goto free_htbls_kmem_cache;
112183a6706SYevgeny Kliteynik 	}
113183a6706SYevgeny Kliteynik 
114183a6706SYevgeny Kliteynik 	dmn->action_icm_pool = mlx5dr_icm_pool_create(dmn, DR_ICM_TYPE_MODIFY_ACTION);
115183a6706SYevgeny Kliteynik 	if (!dmn->action_icm_pool) {
116183a6706SYevgeny Kliteynik 		mlx5dr_err(dmn, "Couldn't get action icm memory\n");
117183a6706SYevgeny Kliteynik 		ret = -ENOMEM;
118183a6706SYevgeny Kliteynik 		goto free_ste_icm_pool;
119183a6706SYevgeny Kliteynik 	}
120183a6706SYevgeny Kliteynik 
12117b56073SYevgeny Kliteynik 	ret = mlx5dr_send_info_pool_create(dmn);
12217b56073SYevgeny Kliteynik 	if (ret) {
12317b56073SYevgeny Kliteynik 		mlx5dr_err(dmn, "Couldn't create send info pool\n");
12417b56073SYevgeny Kliteynik 		goto free_action_icm_pool;
12517b56073SYevgeny Kliteynik 	}
12617b56073SYevgeny Kliteynik 
127183a6706SYevgeny Kliteynik 	return 0;
128183a6706SYevgeny Kliteynik 
12917b56073SYevgeny Kliteynik free_action_icm_pool:
13017b56073SYevgeny Kliteynik 	mlx5dr_icm_pool_destroy(dmn->action_icm_pool);
131183a6706SYevgeny Kliteynik free_ste_icm_pool:
132183a6706SYevgeny Kliteynik 	mlx5dr_icm_pool_destroy(dmn->ste_icm_pool);
133fb628b71SYevgeny Kliteynik free_htbls_kmem_cache:
134fb628b71SYevgeny Kliteynik 	kmem_cache_destroy(dmn->htbls_kmem_cache);
135fd785e52SYevgeny Kliteynik free_chunks_kmem_cache:
136fd785e52SYevgeny Kliteynik 	kmem_cache_destroy(dmn->chunks_kmem_cache);
137fd785e52SYevgeny Kliteynik 
138183a6706SYevgeny Kliteynik 	return ret;
139183a6706SYevgeny Kliteynik }
140183a6706SYevgeny Kliteynik 
141183a6706SYevgeny Kliteynik static void dr_domain_uninit_mem_resources(struct mlx5dr_domain *dmn)
142183a6706SYevgeny Kliteynik {
14317b56073SYevgeny Kliteynik 	mlx5dr_send_info_pool_destroy(dmn);
144183a6706SYevgeny Kliteynik 	mlx5dr_icm_pool_destroy(dmn->action_icm_pool);
145183a6706SYevgeny Kliteynik 	mlx5dr_icm_pool_destroy(dmn->ste_icm_pool);
146fb628b71SYevgeny Kliteynik 	kmem_cache_destroy(dmn->htbls_kmem_cache);
147fd785e52SYevgeny Kliteynik 	kmem_cache_destroy(dmn->chunks_kmem_cache);
148183a6706SYevgeny Kliteynik }
149183a6706SYevgeny Kliteynik 
1504ec9e7b0SAlex Vesker static int dr_domain_init_resources(struct mlx5dr_domain *dmn)
1514ec9e7b0SAlex Vesker {
1524ec9e7b0SAlex Vesker 	int ret;
1534ec9e7b0SAlex Vesker 
1545212f9c6SYevgeny Kliteynik 	dmn->ste_ctx = mlx5dr_ste_get_ctx(dmn->info.caps.sw_format_ver);
1555212f9c6SYevgeny Kliteynik 	if (!dmn->ste_ctx) {
1565212f9c6SYevgeny Kliteynik 		mlx5dr_err(dmn, "SW Steering on this device is unsupported\n");
1575212f9c6SYevgeny Kliteynik 		return -EOPNOTSUPP;
1585212f9c6SYevgeny Kliteynik 	}
1595212f9c6SYevgeny Kliteynik 
1604ec9e7b0SAlex Vesker 	ret = mlx5_core_alloc_pd(dmn->mdev, &dmn->pdn);
1614ec9e7b0SAlex Vesker 	if (ret) {
162b7d0db55SErez Shitrit 		mlx5dr_err(dmn, "Couldn't allocate PD, ret: %d", ret);
1634ec9e7b0SAlex Vesker 		return ret;
1644ec9e7b0SAlex Vesker 	}
1654ec9e7b0SAlex Vesker 
1664ec9e7b0SAlex Vesker 	dmn->uar = mlx5_get_uars_page(dmn->mdev);
1676b8b4258SMiaoqian Lin 	if (IS_ERR(dmn->uar)) {
1684ec9e7b0SAlex Vesker 		mlx5dr_err(dmn, "Couldn't allocate UAR\n");
1696b8b4258SMiaoqian Lin 		ret = PTR_ERR(dmn->uar);
1704ec9e7b0SAlex Vesker 		goto clean_pd;
1714ec9e7b0SAlex Vesker 	}
1724ec9e7b0SAlex Vesker 
173183a6706SYevgeny Kliteynik 	ret = dr_domain_init_mem_resources(dmn);
174183a6706SYevgeny Kliteynik 	if (ret) {
175183a6706SYevgeny Kliteynik 		mlx5dr_err(dmn, "Couldn't create domain memory resources\n");
1764ec9e7b0SAlex Vesker 		goto clean_uar;
1774ec9e7b0SAlex Vesker 	}
1784ec9e7b0SAlex Vesker 
179*108ff821SYevgeny Kliteynik 	ret = dr_domain_init_modify_header_resources(dmn);
180*108ff821SYevgeny Kliteynik 	if (ret) {
181*108ff821SYevgeny Kliteynik 		mlx5dr_err(dmn, "Couldn't create modify-header-resources\n");
182*108ff821SYevgeny Kliteynik 		goto clean_mem_resources;
183*108ff821SYevgeny Kliteynik 	}
184*108ff821SYevgeny Kliteynik 
1854ec9e7b0SAlex Vesker 	ret = mlx5dr_send_ring_alloc(dmn);
1864ec9e7b0SAlex Vesker 	if (ret) {
18763d67f30SSaeed Mahameed 		mlx5dr_err(dmn, "Couldn't create send-ring\n");
188*108ff821SYevgeny Kliteynik 		goto clean_modify_hdr;
1894ec9e7b0SAlex Vesker 	}
1904ec9e7b0SAlex Vesker 
1914ec9e7b0SAlex Vesker 	return 0;
1924ec9e7b0SAlex Vesker 
193*108ff821SYevgeny Kliteynik clean_modify_hdr:
194*108ff821SYevgeny Kliteynik 	dr_domain_destroy_modify_header_resources(dmn);
195183a6706SYevgeny Kliteynik clean_mem_resources:
196183a6706SYevgeny Kliteynik 	dr_domain_uninit_mem_resources(dmn);
1974ec9e7b0SAlex Vesker clean_uar:
1984ec9e7b0SAlex Vesker 	mlx5_put_uars_page(dmn->mdev, dmn->uar);
1994ec9e7b0SAlex Vesker clean_pd:
2004ec9e7b0SAlex Vesker 	mlx5_core_dealloc_pd(dmn->mdev, dmn->pdn);
2014ec9e7b0SAlex Vesker 
2024ec9e7b0SAlex Vesker 	return ret;
2034ec9e7b0SAlex Vesker }
2044ec9e7b0SAlex Vesker 
2054ec9e7b0SAlex Vesker static void dr_domain_uninit_resources(struct mlx5dr_domain *dmn)
2064ec9e7b0SAlex Vesker {
2074ec9e7b0SAlex Vesker 	mlx5dr_send_ring_free(dmn, dmn->send_ring);
208*108ff821SYevgeny Kliteynik 	dr_domain_destroy_modify_header_resources(dmn);
209183a6706SYevgeny Kliteynik 	dr_domain_uninit_mem_resources(dmn);
2104ec9e7b0SAlex Vesker 	mlx5_put_uars_page(dmn->mdev, dmn->uar);
2114ec9e7b0SAlex Vesker 	mlx5_core_dealloc_pd(dmn->mdev, dmn->pdn);
2124ec9e7b0SAlex Vesker }
2134ec9e7b0SAlex Vesker 
21411a45defSYevgeny Kliteynik static void dr_domain_fill_uplink_caps(struct mlx5dr_domain *dmn,
21511a45defSYevgeny Kliteynik 				       struct mlx5dr_cmd_vport_cap *uplink_vport)
21611a45defSYevgeny Kliteynik {
21711a45defSYevgeny Kliteynik 	struct mlx5dr_esw_caps *esw_caps = &dmn->info.caps.esw_caps;
21811a45defSYevgeny Kliteynik 
21911a45defSYevgeny Kliteynik 	uplink_vport->num = MLX5_VPORT_UPLINK;
22011a45defSYevgeny Kliteynik 	uplink_vport->icm_address_rx = esw_caps->uplink_icm_address_rx;
22111a45defSYevgeny Kliteynik 	uplink_vport->icm_address_tx = esw_caps->uplink_icm_address_tx;
22211a45defSYevgeny Kliteynik 	uplink_vport->vport_gvmi = 0;
22311a45defSYevgeny Kliteynik 	uplink_vport->vhca_gvmi = dmn->info.caps.gvmi;
22411a45defSYevgeny Kliteynik }
22511a45defSYevgeny Kliteynik 
2264ec9e7b0SAlex Vesker static int dr_domain_query_vport(struct mlx5dr_domain *dmn,
227dd4acb2aSYevgeny Kliteynik 				 u16 vport_number,
2289091b821SYevgeny Kliteynik 				 bool other_vport,
229dd4acb2aSYevgeny Kliteynik 				 struct mlx5dr_cmd_vport_cap *vport_caps)
2304ec9e7b0SAlex Vesker {
2314ec9e7b0SAlex Vesker 	int ret;
2324ec9e7b0SAlex Vesker 
2334ec9e7b0SAlex Vesker 	ret = mlx5dr_cmd_query_esw_vport_context(dmn->mdev,
2344ec9e7b0SAlex Vesker 						 other_vport,
2359091b821SYevgeny Kliteynik 						 vport_number,
2364ec9e7b0SAlex Vesker 						 &vport_caps->icm_address_rx,
2374ec9e7b0SAlex Vesker 						 &vport_caps->icm_address_tx);
2384ec9e7b0SAlex Vesker 	if (ret)
2394ec9e7b0SAlex Vesker 		return ret;
2404ec9e7b0SAlex Vesker 
2414ec9e7b0SAlex Vesker 	ret = mlx5dr_cmd_query_gvmi(dmn->mdev,
2424ec9e7b0SAlex Vesker 				    other_vport,
2439091b821SYevgeny Kliteynik 				    vport_number,
2444ec9e7b0SAlex Vesker 				    &vport_caps->vport_gvmi);
2454ec9e7b0SAlex Vesker 	if (ret)
2464ec9e7b0SAlex Vesker 		return ret;
2474ec9e7b0SAlex Vesker 
2484ec9e7b0SAlex Vesker 	vport_caps->num = vport_number;
2494ec9e7b0SAlex Vesker 	vport_caps->vhca_gvmi = dmn->info.caps.gvmi;
2504ec9e7b0SAlex Vesker 
2514ec9e7b0SAlex Vesker 	return 0;
2524ec9e7b0SAlex Vesker }
2534ec9e7b0SAlex Vesker 
254*108ff821SYevgeny Kliteynik static int dr_domain_query_esw_mgr(struct mlx5dr_domain *dmn)
255dd4acb2aSYevgeny Kliteynik {
256624bf42cSYevgeny Kliteynik 	return dr_domain_query_vport(dmn, 0, false,
25711a45defSYevgeny Kliteynik 				     &dmn->info.caps.vports.esw_manager_caps);
258dd4acb2aSYevgeny Kliteynik }
259dd4acb2aSYevgeny Kliteynik 
2609091b821SYevgeny Kliteynik static void dr_domain_query_uplink(struct mlx5dr_domain *dmn)
2619091b821SYevgeny Kliteynik {
2629091b821SYevgeny Kliteynik 	dr_domain_fill_uplink_caps(dmn, &dmn->info.caps.vports.uplink_caps);
2639091b821SYevgeny Kliteynik }
2649091b821SYevgeny Kliteynik 
26511a45defSYevgeny Kliteynik static struct mlx5dr_cmd_vport_cap *
26611a45defSYevgeny Kliteynik dr_domain_add_vport_cap(struct mlx5dr_domain *dmn, u16 vport)
2674ec9e7b0SAlex Vesker {
26811a45defSYevgeny Kliteynik 	struct mlx5dr_cmd_caps *caps = &dmn->info.caps;
26911a45defSYevgeny Kliteynik 	struct mlx5dr_cmd_vport_cap *vport_caps;
2704ec9e7b0SAlex Vesker 	int ret;
2714ec9e7b0SAlex Vesker 
27211a45defSYevgeny Kliteynik 	vport_caps = kvzalloc(sizeof(*vport_caps), GFP_KERNEL);
27311a45defSYevgeny Kliteynik 	if (!vport_caps)
27411a45defSYevgeny Kliteynik 		return NULL;
275dd4acb2aSYevgeny Kliteynik 
2769091b821SYevgeny Kliteynik 	ret = dr_domain_query_vport(dmn, vport, true, vport_caps);
27711a45defSYevgeny Kliteynik 	if (ret) {
27811a45defSYevgeny Kliteynik 		kvfree(vport_caps);
27911a45defSYevgeny Kliteynik 		return NULL;
2804ec9e7b0SAlex Vesker 	}
2814ec9e7b0SAlex Vesker 
28211a45defSYevgeny Kliteynik 	ret = xa_insert(&caps->vports.vports_caps_xa, vport,
28311a45defSYevgeny Kliteynik 			vport_caps, GFP_KERNEL);
28411a45defSYevgeny Kliteynik 	if (ret) {
28511a45defSYevgeny Kliteynik 		mlx5dr_dbg(dmn, "Couldn't insert new vport into xarray (%d)\n", ret);
28611a45defSYevgeny Kliteynik 		kvfree(vport_caps);
28711a45defSYevgeny Kliteynik 		return ERR_PTR(ret);
28811a45defSYevgeny Kliteynik 	}
28911a45defSYevgeny Kliteynik 
29011a45defSYevgeny Kliteynik 	return vport_caps;
29111a45defSYevgeny Kliteynik }
29211a45defSYevgeny Kliteynik 
2939091b821SYevgeny Kliteynik static bool dr_domain_is_esw_mgr_vport(struct mlx5dr_domain *dmn, u16 vport)
2949091b821SYevgeny Kliteynik {
2959091b821SYevgeny Kliteynik 	struct mlx5dr_cmd_caps *caps = &dmn->info.caps;
2969091b821SYevgeny Kliteynik 
2979091b821SYevgeny Kliteynik 	return (caps->is_ecpf && vport == MLX5_VPORT_ECPF) ||
2989091b821SYevgeny Kliteynik 	       (!caps->is_ecpf && vport == 0);
2999091b821SYevgeny Kliteynik }
3009091b821SYevgeny Kliteynik 
30111a45defSYevgeny Kliteynik struct mlx5dr_cmd_vport_cap *
30211a45defSYevgeny Kliteynik mlx5dr_domain_get_vport_cap(struct mlx5dr_domain *dmn, u16 vport)
30311a45defSYevgeny Kliteynik {
30411a45defSYevgeny Kliteynik 	struct mlx5dr_cmd_caps *caps = &dmn->info.caps;
30511a45defSYevgeny Kliteynik 	struct mlx5dr_cmd_vport_cap *vport_caps;
30611a45defSYevgeny Kliteynik 
3079091b821SYevgeny Kliteynik 	if (dr_domain_is_esw_mgr_vport(dmn, vport))
30811a45defSYevgeny Kliteynik 		return &caps->vports.esw_manager_caps;
30911a45defSYevgeny Kliteynik 
3109091b821SYevgeny Kliteynik 	if (vport == MLX5_VPORT_UPLINK)
3119091b821SYevgeny Kliteynik 		return &caps->vports.uplink_caps;
3129091b821SYevgeny Kliteynik 
31311a45defSYevgeny Kliteynik vport_load:
31411a45defSYevgeny Kliteynik 	vport_caps = xa_load(&caps->vports.vports_caps_xa, vport);
31511a45defSYevgeny Kliteynik 	if (vport_caps)
31611a45defSYevgeny Kliteynik 		return vport_caps;
31711a45defSYevgeny Kliteynik 
31811a45defSYevgeny Kliteynik 	vport_caps = dr_domain_add_vport_cap(dmn, vport);
31911a45defSYevgeny Kliteynik 	if (PTR_ERR(vport_caps) == -EBUSY)
32011a45defSYevgeny Kliteynik 		/* caps were already stored by another thread */
32111a45defSYevgeny Kliteynik 		goto vport_load;
32211a45defSYevgeny Kliteynik 
32311a45defSYevgeny Kliteynik 	return vport_caps;
32411a45defSYevgeny Kliteynik }
32511a45defSYevgeny Kliteynik 
32611a45defSYevgeny Kliteynik static void dr_domain_clear_vports(struct mlx5dr_domain *dmn)
32711a45defSYevgeny Kliteynik {
32811a45defSYevgeny Kliteynik 	struct mlx5dr_cmd_vport_cap *vport_caps;
32911a45defSYevgeny Kliteynik 	unsigned long i;
33011a45defSYevgeny Kliteynik 
33111a45defSYevgeny Kliteynik 	xa_for_each(&dmn->info.caps.vports.vports_caps_xa, i, vport_caps) {
33211a45defSYevgeny Kliteynik 		vport_caps = xa_erase(&dmn->info.caps.vports.vports_caps_xa, i);
33311a45defSYevgeny Kliteynik 		kvfree(vport_caps);
33411a45defSYevgeny Kliteynik 	}
33511a45defSYevgeny Kliteynik }
33611a45defSYevgeny Kliteynik 
3374ec9e7b0SAlex Vesker static int dr_domain_query_fdb_caps(struct mlx5_core_dev *mdev,
3384ec9e7b0SAlex Vesker 				    struct mlx5dr_domain *dmn)
3394ec9e7b0SAlex Vesker {
3404ec9e7b0SAlex Vesker 	int ret;
3414ec9e7b0SAlex Vesker 
3424ec9e7b0SAlex Vesker 	if (!dmn->info.caps.eswitch_manager)
3434ec9e7b0SAlex Vesker 		return -EOPNOTSUPP;
3444ec9e7b0SAlex Vesker 
3454ec9e7b0SAlex Vesker 	ret = mlx5dr_cmd_query_esw_caps(mdev, &dmn->info.caps.esw_caps);
3464ec9e7b0SAlex Vesker 	if (ret)
3474ec9e7b0SAlex Vesker 		return ret;
3484ec9e7b0SAlex Vesker 
3494ec9e7b0SAlex Vesker 	dmn->info.caps.fdb_sw_owner = dmn->info.caps.esw_caps.sw_owner;
35064f45c0fSYevgeny Kliteynik 	dmn->info.caps.fdb_sw_owner_v2 = dmn->info.caps.esw_caps.sw_owner_v2;
3514ec9e7b0SAlex Vesker 	dmn->info.caps.esw_rx_drop_address = dmn->info.caps.esw_caps.drop_icm_address_rx;
3524ec9e7b0SAlex Vesker 	dmn->info.caps.esw_tx_drop_address = dmn->info.caps.esw_caps.drop_icm_address_tx;
3534ec9e7b0SAlex Vesker 
35411a45defSYevgeny Kliteynik 	xa_init(&dmn->info.caps.vports.vports_caps_xa);
3554ec9e7b0SAlex Vesker 
35611a45defSYevgeny Kliteynik 	/* Query eswitch manager and uplink vports only. Rest of the
35711a45defSYevgeny Kliteynik 	 * vports (vport 0, VFs and SFs) will be queried dynamically.
35811a45defSYevgeny Kliteynik 	 */
35911a45defSYevgeny Kliteynik 
360*108ff821SYevgeny Kliteynik 	ret = dr_domain_query_esw_mgr(dmn);
3614ec9e7b0SAlex Vesker 	if (ret) {
36211a45defSYevgeny Kliteynik 		mlx5dr_err(dmn, "Failed to query eswitch manager vport caps (err: %d)", ret);
36311a45defSYevgeny Kliteynik 		goto free_vports_caps_xa;
3644ec9e7b0SAlex Vesker 	}
3654ec9e7b0SAlex Vesker 
3669091b821SYevgeny Kliteynik 	dr_domain_query_uplink(dmn);
3674ec9e7b0SAlex Vesker 
3684ec9e7b0SAlex Vesker 	return 0;
3694ec9e7b0SAlex Vesker 
37011a45defSYevgeny Kliteynik free_vports_caps_xa:
37111a45defSYevgeny Kliteynik 	xa_destroy(&dmn->info.caps.vports.vports_caps_xa);
37211a45defSYevgeny Kliteynik 
3734ec9e7b0SAlex Vesker 	return ret;
3744ec9e7b0SAlex Vesker }
3754ec9e7b0SAlex Vesker 
3764ec9e7b0SAlex Vesker static int dr_domain_caps_init(struct mlx5_core_dev *mdev,
3774ec9e7b0SAlex Vesker 			       struct mlx5dr_domain *dmn)
3784ec9e7b0SAlex Vesker {
3794ec9e7b0SAlex Vesker 	struct mlx5dr_cmd_vport_cap *vport_cap;
3804ec9e7b0SAlex Vesker 	int ret;
3814ec9e7b0SAlex Vesker 
3824ec9e7b0SAlex Vesker 	if (MLX5_CAP_GEN(mdev, port_type) != MLX5_CAP_PORT_TYPE_ETH) {
383b7d0db55SErez Shitrit 		mlx5dr_err(dmn, "Failed to allocate domain, bad link type\n");
3844ec9e7b0SAlex Vesker 		return -EOPNOTSUPP;
3854ec9e7b0SAlex Vesker 	}
3864ec9e7b0SAlex Vesker 
3874ec9e7b0SAlex Vesker 	ret = mlx5dr_cmd_query_device(mdev, &dmn->info.caps);
3884ec9e7b0SAlex Vesker 	if (ret)
3894ec9e7b0SAlex Vesker 		return ret;
3904ec9e7b0SAlex Vesker 
3914ec9e7b0SAlex Vesker 	ret = dr_domain_query_fdb_caps(mdev, dmn);
3924ec9e7b0SAlex Vesker 	if (ret)
3934ec9e7b0SAlex Vesker 		return ret;
3944ec9e7b0SAlex Vesker 
3954ec9e7b0SAlex Vesker 	switch (dmn->type) {
3964ec9e7b0SAlex Vesker 	case MLX5DR_DOMAIN_TYPE_NIC_RX:
39764f45c0fSYevgeny Kliteynik 		if (!DR_DOMAIN_SW_STEERING_SUPPORTED(dmn, rx))
3984ec9e7b0SAlex Vesker 			return -ENOTSUPP;
3994ec9e7b0SAlex Vesker 
4004ec9e7b0SAlex Vesker 		dmn->info.supp_sw_steering = true;
40146f2a8aeSYevgeny Kliteynik 		dmn->info.rx.type = DR_DOMAIN_NIC_TYPE_RX;
4024ec9e7b0SAlex Vesker 		dmn->info.rx.default_icm_addr = dmn->info.caps.nic_rx_drop_address;
4034ec9e7b0SAlex Vesker 		dmn->info.rx.drop_icm_addr = dmn->info.caps.nic_rx_drop_address;
4044ec9e7b0SAlex Vesker 		break;
4054ec9e7b0SAlex Vesker 	case MLX5DR_DOMAIN_TYPE_NIC_TX:
40664f45c0fSYevgeny Kliteynik 		if (!DR_DOMAIN_SW_STEERING_SUPPORTED(dmn, tx))
4074ec9e7b0SAlex Vesker 			return -ENOTSUPP;
4084ec9e7b0SAlex Vesker 
4094ec9e7b0SAlex Vesker 		dmn->info.supp_sw_steering = true;
41046f2a8aeSYevgeny Kliteynik 		dmn->info.tx.type = DR_DOMAIN_NIC_TYPE_TX;
4114ec9e7b0SAlex Vesker 		dmn->info.tx.default_icm_addr = dmn->info.caps.nic_tx_allow_address;
4124ec9e7b0SAlex Vesker 		dmn->info.tx.drop_icm_addr = dmn->info.caps.nic_tx_drop_address;
4134ec9e7b0SAlex Vesker 		break;
4144ec9e7b0SAlex Vesker 	case MLX5DR_DOMAIN_TYPE_FDB:
4154ec9e7b0SAlex Vesker 		if (!dmn->info.caps.eswitch_manager)
4164ec9e7b0SAlex Vesker 			return -ENOTSUPP;
4174ec9e7b0SAlex Vesker 
41864f45c0fSYevgeny Kliteynik 		if (!DR_DOMAIN_SW_STEERING_SUPPORTED(dmn, fdb))
4194ec9e7b0SAlex Vesker 			return -ENOTSUPP;
4204ec9e7b0SAlex Vesker 
42146f2a8aeSYevgeny Kliteynik 		dmn->info.rx.type = DR_DOMAIN_NIC_TYPE_RX;
42246f2a8aeSYevgeny Kliteynik 		dmn->info.tx.type = DR_DOMAIN_NIC_TYPE_TX;
42311a45defSYevgeny Kliteynik 		vport_cap = &dmn->info.caps.vports.esw_manager_caps;
4244ec9e7b0SAlex Vesker 
4254ec9e7b0SAlex Vesker 		dmn->info.supp_sw_steering = true;
4264ec9e7b0SAlex Vesker 		dmn->info.tx.default_icm_addr = vport_cap->icm_address_tx;
4274ec9e7b0SAlex Vesker 		dmn->info.rx.default_icm_addr = vport_cap->icm_address_rx;
4284ec9e7b0SAlex Vesker 		dmn->info.rx.drop_icm_addr = dmn->info.caps.esw_rx_drop_address;
4294ec9e7b0SAlex Vesker 		dmn->info.tx.drop_icm_addr = dmn->info.caps.esw_tx_drop_address;
4304ec9e7b0SAlex Vesker 		break;
4314ec9e7b0SAlex Vesker 	default:
432b7d0db55SErez Shitrit 		mlx5dr_err(dmn, "Invalid domain\n");
4334ec9e7b0SAlex Vesker 		ret = -EINVAL;
4344ec9e7b0SAlex Vesker 		break;
4354ec9e7b0SAlex Vesker 	}
4364ec9e7b0SAlex Vesker 
4374ec9e7b0SAlex Vesker 	return ret;
4384ec9e7b0SAlex Vesker }
4394ec9e7b0SAlex Vesker 
4404ec9e7b0SAlex Vesker static void dr_domain_caps_uninit(struct mlx5dr_domain *dmn)
4414ec9e7b0SAlex Vesker {
44211a45defSYevgeny Kliteynik 	dr_domain_clear_vports(dmn);
44311a45defSYevgeny Kliteynik 	xa_destroy(&dmn->info.caps.vports.vports_caps_xa);
4444ec9e7b0SAlex Vesker }
4454ec9e7b0SAlex Vesker 
4464ec9e7b0SAlex Vesker struct mlx5dr_domain *
4474ec9e7b0SAlex Vesker mlx5dr_domain_create(struct mlx5_core_dev *mdev, enum mlx5dr_domain_type type)
4484ec9e7b0SAlex Vesker {
4494ec9e7b0SAlex Vesker 	struct mlx5dr_domain *dmn;
4504ec9e7b0SAlex Vesker 	int ret;
4514ec9e7b0SAlex Vesker 
4524ec9e7b0SAlex Vesker 	if (type > MLX5DR_DOMAIN_TYPE_FDB)
4534ec9e7b0SAlex Vesker 		return NULL;
4544ec9e7b0SAlex Vesker 
4554ec9e7b0SAlex Vesker 	dmn = kzalloc(sizeof(*dmn), GFP_KERNEL);
4564ec9e7b0SAlex Vesker 	if (!dmn)
4574ec9e7b0SAlex Vesker 		return NULL;
4584ec9e7b0SAlex Vesker 
4594ec9e7b0SAlex Vesker 	dmn->mdev = mdev;
4604ec9e7b0SAlex Vesker 	dmn->type = type;
4614ec9e7b0SAlex Vesker 	refcount_set(&dmn->refcount, 1);
462ed03a418SAlex Vesker 	mutex_init(&dmn->info.rx.mutex);
463ed03a418SAlex Vesker 	mutex_init(&dmn->info.tx.mutex);
4641339678fSYevgeny Kliteynik 	xa_init(&dmn->definers_xa);
4654ec9e7b0SAlex Vesker 
4664ec9e7b0SAlex Vesker 	if (dr_domain_caps_init(mdev, dmn)) {
467b7d0db55SErez Shitrit 		mlx5dr_err(dmn, "Failed init domain, no caps\n");
4681339678fSYevgeny Kliteynik 		goto def_xa_destroy;
4694ec9e7b0SAlex Vesker 	}
4704ec9e7b0SAlex Vesker 
4714ec9e7b0SAlex Vesker 	dmn->info.max_log_action_icm_sz = DR_CHUNK_SIZE_4K;
4724ec9e7b0SAlex Vesker 	dmn->info.max_log_sw_icm_sz = min_t(u32, DR_CHUNK_SIZE_1024K,
4734ec9e7b0SAlex Vesker 					    dmn->info.caps.log_icm_size);
474*108ff821SYevgeny Kliteynik 	dmn->info.max_log_modify_hdr_pattern_icm_sz =
475*108ff821SYevgeny Kliteynik 		min_t(u32, DR_CHUNK_SIZE_4K,
476*108ff821SYevgeny Kliteynik 		      dmn->info.caps.log_modify_pattern_icm_size);
4774ec9e7b0SAlex Vesker 
4784ec9e7b0SAlex Vesker 	if (!dmn->info.supp_sw_steering) {
47963d67f30SSaeed Mahameed 		mlx5dr_err(dmn, "SW steering is not supported\n");
4804ec9e7b0SAlex Vesker 		goto uninit_caps;
4814ec9e7b0SAlex Vesker 	}
4824ec9e7b0SAlex Vesker 
4834ec9e7b0SAlex Vesker 	/* Allocate resources */
4844ec9e7b0SAlex Vesker 	ret = dr_domain_init_resources(dmn);
4854ec9e7b0SAlex Vesker 	if (ret) {
48663d67f30SSaeed Mahameed 		mlx5dr_err(dmn, "Failed init domain resources\n");
4874ec9e7b0SAlex Vesker 		goto uninit_caps;
4884ec9e7b0SAlex Vesker 	}
4894ec9e7b0SAlex Vesker 
490c0e90fc2SYevgeny Kliteynik 	dr_domain_init_csum_recalc_fts(dmn);
4919222f0b2SMuhammad Sammar 	mlx5dr_dbg_init_dump(dmn);
4924ec9e7b0SAlex Vesker 	return dmn;
4934ec9e7b0SAlex Vesker 
4944ec9e7b0SAlex Vesker uninit_caps:
4954ec9e7b0SAlex Vesker 	dr_domain_caps_uninit(dmn);
4961339678fSYevgeny Kliteynik def_xa_destroy:
4971339678fSYevgeny Kliteynik 	xa_destroy(&dmn->definers_xa);
4984ec9e7b0SAlex Vesker 	kfree(dmn);
4994ec9e7b0SAlex Vesker 	return NULL;
5004ec9e7b0SAlex Vesker }
5014ec9e7b0SAlex Vesker 
5024ec9e7b0SAlex Vesker /* Assure synchronization of the device steering tables with updates made by SW
5034ec9e7b0SAlex Vesker  * insertion.
5044ec9e7b0SAlex Vesker  */
5054ec9e7b0SAlex Vesker int mlx5dr_domain_sync(struct mlx5dr_domain *dmn, u32 flags)
5064ec9e7b0SAlex Vesker {
5074ec9e7b0SAlex Vesker 	int ret = 0;
5084ec9e7b0SAlex Vesker 
5094ec9e7b0SAlex Vesker 	if (flags & MLX5DR_DOMAIN_SYNC_FLAGS_SW) {
510ed03a418SAlex Vesker 		mlx5dr_domain_lock(dmn);
5114ec9e7b0SAlex Vesker 		ret = mlx5dr_send_ring_force_drain(dmn);
512ed03a418SAlex Vesker 		mlx5dr_domain_unlock(dmn);
513b7d0db55SErez Shitrit 		if (ret) {
514b7d0db55SErez Shitrit 			mlx5dr_err(dmn, "Force drain failed flags: %d, ret: %d\n",
515b7d0db55SErez Shitrit 				   flags, ret);
5164ec9e7b0SAlex Vesker 			return ret;
5174ec9e7b0SAlex Vesker 		}
518b7d0db55SErez Shitrit 	}
5194ec9e7b0SAlex Vesker 
5204ec9e7b0SAlex Vesker 	if (flags & MLX5DR_DOMAIN_SYNC_FLAGS_HW)
5214ec9e7b0SAlex Vesker 		ret = mlx5dr_cmd_sync_steering(dmn->mdev);
5224ec9e7b0SAlex Vesker 
5234ec9e7b0SAlex Vesker 	return ret;
5244ec9e7b0SAlex Vesker }
5254ec9e7b0SAlex Vesker 
5264ec9e7b0SAlex Vesker int mlx5dr_domain_destroy(struct mlx5dr_domain *dmn)
5274ec9e7b0SAlex Vesker {
528b5412827SYevgeny Kliteynik 	if (WARN_ON_ONCE(refcount_read(&dmn->refcount) > 1))
5294ec9e7b0SAlex Vesker 		return -EBUSY;
5304ec9e7b0SAlex Vesker 
5314ec9e7b0SAlex Vesker 	/* make sure resources are not used by the hardware */
5324ec9e7b0SAlex Vesker 	mlx5dr_cmd_sync_steering(dmn->mdev);
5339222f0b2SMuhammad Sammar 	mlx5dr_dbg_uninit_dump(dmn);
534c0e90fc2SYevgeny Kliteynik 	dr_domain_uninit_csum_recalc_fts(dmn);
5354ec9e7b0SAlex Vesker 	dr_domain_uninit_resources(dmn);
5364ec9e7b0SAlex Vesker 	dr_domain_caps_uninit(dmn);
5371339678fSYevgeny Kliteynik 	xa_destroy(&dmn->definers_xa);
538ed03a418SAlex Vesker 	mutex_destroy(&dmn->info.tx.mutex);
539ed03a418SAlex Vesker 	mutex_destroy(&dmn->info.rx.mutex);
5404ec9e7b0SAlex Vesker 	kfree(dmn);
5414ec9e7b0SAlex Vesker 	return 0;
5424ec9e7b0SAlex Vesker }
5434ec9e7b0SAlex Vesker 
5444ec9e7b0SAlex Vesker void mlx5dr_domain_set_peer(struct mlx5dr_domain *dmn,
5454ec9e7b0SAlex Vesker 			    struct mlx5dr_domain *peer_dmn)
5464ec9e7b0SAlex Vesker {
547ed03a418SAlex Vesker 	mlx5dr_domain_lock(dmn);
5484ec9e7b0SAlex Vesker 
5494ec9e7b0SAlex Vesker 	if (dmn->peer_dmn)
5504ec9e7b0SAlex Vesker 		refcount_dec(&dmn->peer_dmn->refcount);
5514ec9e7b0SAlex Vesker 
5524ec9e7b0SAlex Vesker 	dmn->peer_dmn = peer_dmn;
5534ec9e7b0SAlex Vesker 
5544ec9e7b0SAlex Vesker 	if (dmn->peer_dmn)
5554ec9e7b0SAlex Vesker 		refcount_inc(&dmn->peer_dmn->refcount);
5564ec9e7b0SAlex Vesker 
557ed03a418SAlex Vesker 	mlx5dr_domain_unlock(dmn);
5584ec9e7b0SAlex Vesker }
559