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 
mlx5dr_domain_is_support_ptrn_arg(struct mlx5dr_domain * dmn)13108ff821SYevgeny Kliteynik bool mlx5dr_domain_is_support_ptrn_arg(struct mlx5dr_domain *dmn)
14108ff821SYevgeny Kliteynik {
15220ae987SYevgeny Kliteynik 	return dmn->info.caps.sw_format_ver >= MLX5_STEERING_FORMAT_CONNECTX_6DX &&
16220ae987SYevgeny Kliteynik 	       dmn->info.caps.support_modify_argument;
17108ff821SYevgeny Kliteynik }
18108ff821SYevgeny Kliteynik 
dr_domain_init_modify_header_resources(struct mlx5dr_domain * dmn)19108ff821SYevgeny Kliteynik static int dr_domain_init_modify_header_resources(struct mlx5dr_domain *dmn)
20108ff821SYevgeny Kliteynik {
21108ff821SYevgeny Kliteynik 	if (!mlx5dr_domain_is_support_ptrn_arg(dmn))
22108ff821SYevgeny Kliteynik 		return 0;
23108ff821SYevgeny Kliteynik 
24108ff821SYevgeny Kliteynik 	dmn->ptrn_mgr = mlx5dr_ptrn_mgr_create(dmn);
25108ff821SYevgeny Kliteynik 	if (!dmn->ptrn_mgr) {
26108ff821SYevgeny Kliteynik 		mlx5dr_err(dmn, "Couldn't create ptrn_mgr\n");
27108ff821SYevgeny Kliteynik 		return -ENOMEM;
28108ff821SYevgeny Kliteynik 	}
29108ff821SYevgeny Kliteynik 
30608d4f17SYevgeny Kliteynik 	/* create argument pool */
31608d4f17SYevgeny Kliteynik 	dmn->arg_mgr = mlx5dr_arg_mgr_create(dmn);
32608d4f17SYevgeny Kliteynik 	if (!dmn->arg_mgr) {
33608d4f17SYevgeny Kliteynik 		mlx5dr_err(dmn, "Couldn't create arg_mgr\n");
34608d4f17SYevgeny Kliteynik 		goto free_modify_header_pattern;
35608d4f17SYevgeny Kliteynik 	}
36608d4f17SYevgeny Kliteynik 
37108ff821SYevgeny Kliteynik 	return 0;
38608d4f17SYevgeny Kliteynik 
39608d4f17SYevgeny Kliteynik free_modify_header_pattern:
40608d4f17SYevgeny Kliteynik 	mlx5dr_ptrn_mgr_destroy(dmn->ptrn_mgr);
41608d4f17SYevgeny Kliteynik 	return -ENOMEM;
42108ff821SYevgeny Kliteynik }
43108ff821SYevgeny Kliteynik 
dr_domain_destroy_modify_header_resources(struct mlx5dr_domain * dmn)44108ff821SYevgeny Kliteynik static void dr_domain_destroy_modify_header_resources(struct mlx5dr_domain *dmn)
45108ff821SYevgeny Kliteynik {
46108ff821SYevgeny Kliteynik 	if (!mlx5dr_domain_is_support_ptrn_arg(dmn))
47108ff821SYevgeny Kliteynik 		return;
48108ff821SYevgeny Kliteynik 
49608d4f17SYevgeny Kliteynik 	mlx5dr_arg_mgr_destroy(dmn->arg_mgr);
50108ff821SYevgeny Kliteynik 	mlx5dr_ptrn_mgr_destroy(dmn->ptrn_mgr);
51108ff821SYevgeny Kliteynik }
52108ff821SYevgeny Kliteynik 
dr_domain_init_csum_recalc_fts(struct mlx5dr_domain * dmn)53c0e90fc2SYevgeny Kliteynik static void dr_domain_init_csum_recalc_fts(struct mlx5dr_domain *dmn)
544ec9e7b0SAlex Vesker {
554ec9e7b0SAlex Vesker 	/* Per vport cached FW FT for checksum recalculation, this
56c0e90fc2SYevgeny Kliteynik 	 * recalculation is needed due to a HW bug in STEv0.
574ec9e7b0SAlex Vesker 	 */
58c0e90fc2SYevgeny Kliteynik 	xa_init(&dmn->csum_fts_xa);
594ec9e7b0SAlex Vesker }
604ec9e7b0SAlex Vesker 
dr_domain_uninit_csum_recalc_fts(struct mlx5dr_domain * dmn)61c0e90fc2SYevgeny Kliteynik static void dr_domain_uninit_csum_recalc_fts(struct mlx5dr_domain *dmn)
624ec9e7b0SAlex Vesker {
63c0e90fc2SYevgeny Kliteynik 	struct mlx5dr_fw_recalc_cs_ft *recalc_cs_ft;
64c0e90fc2SYevgeny Kliteynik 	unsigned long i;
654ec9e7b0SAlex Vesker 
66c0e90fc2SYevgeny Kliteynik 	xa_for_each(&dmn->csum_fts_xa, i, recalc_cs_ft) {
67c0e90fc2SYevgeny Kliteynik 		if (recalc_cs_ft)
68c0e90fc2SYevgeny Kliteynik 			mlx5dr_fw_destroy_recalc_cs_ft(dmn, recalc_cs_ft);
694ec9e7b0SAlex Vesker 	}
704ec9e7b0SAlex Vesker 
71c0e90fc2SYevgeny Kliteynik 	xa_destroy(&dmn->csum_fts_xa);
724ec9e7b0SAlex Vesker }
734ec9e7b0SAlex Vesker 
mlx5dr_domain_get_recalc_cs_ft_addr(struct mlx5dr_domain * dmn,u16 vport_num,u64 * rx_icm_addr)74c0e90fc2SYevgeny Kliteynik int mlx5dr_domain_get_recalc_cs_ft_addr(struct mlx5dr_domain *dmn,
75f9f93bd5SYevgeny Kliteynik 					u16 vport_num,
764ec9e7b0SAlex Vesker 					u64 *rx_icm_addr)
774ec9e7b0SAlex Vesker {
784ec9e7b0SAlex Vesker 	struct mlx5dr_fw_recalc_cs_ft *recalc_cs_ft;
79c0e90fc2SYevgeny Kliteynik 	int ret;
804ec9e7b0SAlex Vesker 
81c0e90fc2SYevgeny Kliteynik 	recalc_cs_ft = xa_load(&dmn->csum_fts_xa, vport_num);
824ec9e7b0SAlex Vesker 	if (!recalc_cs_ft) {
83c0e90fc2SYevgeny Kliteynik 		/* Table hasn't been created yet */
844ec9e7b0SAlex Vesker 		recalc_cs_ft = mlx5dr_fw_create_recalc_cs_ft(dmn, vport_num);
854ec9e7b0SAlex Vesker 		if (!recalc_cs_ft)
864ec9e7b0SAlex Vesker 			return -EINVAL;
874ec9e7b0SAlex Vesker 
88c0e90fc2SYevgeny Kliteynik 		ret = xa_err(xa_store(&dmn->csum_fts_xa, vport_num,
89c0e90fc2SYevgeny Kliteynik 				      recalc_cs_ft, GFP_KERNEL));
90c0e90fc2SYevgeny Kliteynik 		if (ret)
91c0e90fc2SYevgeny Kliteynik 			return ret;
924ec9e7b0SAlex Vesker 	}
934ec9e7b0SAlex Vesker 
944ec9e7b0SAlex Vesker 	*rx_icm_addr = recalc_cs_ft->rx_icm_addr;
954ec9e7b0SAlex Vesker 
964ec9e7b0SAlex Vesker 	return 0;
974ec9e7b0SAlex Vesker }
984ec9e7b0SAlex Vesker 
dr_domain_init_mem_resources(struct mlx5dr_domain * dmn)99183a6706SYevgeny Kliteynik static int dr_domain_init_mem_resources(struct mlx5dr_domain *dmn)
100183a6706SYevgeny Kliteynik {
101183a6706SYevgeny Kliteynik 	int ret;
102183a6706SYevgeny Kliteynik 
103fd785e52SYevgeny Kliteynik 	dmn->chunks_kmem_cache = kmem_cache_create("mlx5_dr_chunks",
104fd785e52SYevgeny Kliteynik 						   sizeof(struct mlx5dr_icm_chunk), 0,
105fd785e52SYevgeny Kliteynik 						   SLAB_HWCACHE_ALIGN, NULL);
106fd785e52SYevgeny Kliteynik 	if (!dmn->chunks_kmem_cache) {
107fd785e52SYevgeny Kliteynik 		mlx5dr_err(dmn, "Couldn't create chunks kmem_cache\n");
108fd785e52SYevgeny Kliteynik 		return -ENOMEM;
109fd785e52SYevgeny Kliteynik 	}
110fd785e52SYevgeny Kliteynik 
111fb628b71SYevgeny Kliteynik 	dmn->htbls_kmem_cache = kmem_cache_create("mlx5_dr_htbls",
112fb628b71SYevgeny Kliteynik 						  sizeof(struct mlx5dr_ste_htbl), 0,
113fb628b71SYevgeny Kliteynik 						  SLAB_HWCACHE_ALIGN, NULL);
114fb628b71SYevgeny Kliteynik 	if (!dmn->htbls_kmem_cache) {
115fb628b71SYevgeny Kliteynik 		mlx5dr_err(dmn, "Couldn't create hash tables kmem_cache\n");
116fb628b71SYevgeny Kliteynik 		ret = -ENOMEM;
117fb628b71SYevgeny Kliteynik 		goto free_chunks_kmem_cache;
118fb628b71SYevgeny Kliteynik 	}
119fb628b71SYevgeny Kliteynik 
120183a6706SYevgeny Kliteynik 	dmn->ste_icm_pool = mlx5dr_icm_pool_create(dmn, DR_ICM_TYPE_STE);
121183a6706SYevgeny Kliteynik 	if (!dmn->ste_icm_pool) {
122183a6706SYevgeny Kliteynik 		mlx5dr_err(dmn, "Couldn't get icm memory\n");
123fd785e52SYevgeny Kliteynik 		ret = -ENOMEM;
124fb628b71SYevgeny Kliteynik 		goto free_htbls_kmem_cache;
125183a6706SYevgeny Kliteynik 	}
126183a6706SYevgeny Kliteynik 
127183a6706SYevgeny Kliteynik 	dmn->action_icm_pool = mlx5dr_icm_pool_create(dmn, DR_ICM_TYPE_MODIFY_ACTION);
128183a6706SYevgeny Kliteynik 	if (!dmn->action_icm_pool) {
129183a6706SYevgeny Kliteynik 		mlx5dr_err(dmn, "Couldn't get action icm memory\n");
130183a6706SYevgeny Kliteynik 		ret = -ENOMEM;
131183a6706SYevgeny Kliteynik 		goto free_ste_icm_pool;
132183a6706SYevgeny Kliteynik 	}
133183a6706SYevgeny Kliteynik 
13417b56073SYevgeny Kliteynik 	ret = mlx5dr_send_info_pool_create(dmn);
13517b56073SYevgeny Kliteynik 	if (ret) {
13617b56073SYevgeny Kliteynik 		mlx5dr_err(dmn, "Couldn't create send info pool\n");
13717b56073SYevgeny Kliteynik 		goto free_action_icm_pool;
13817b56073SYevgeny Kliteynik 	}
13917b56073SYevgeny Kliteynik 
140183a6706SYevgeny Kliteynik 	return 0;
141183a6706SYevgeny Kliteynik 
14217b56073SYevgeny Kliteynik free_action_icm_pool:
14317b56073SYevgeny Kliteynik 	mlx5dr_icm_pool_destroy(dmn->action_icm_pool);
144183a6706SYevgeny Kliteynik free_ste_icm_pool:
145183a6706SYevgeny Kliteynik 	mlx5dr_icm_pool_destroy(dmn->ste_icm_pool);
146fb628b71SYevgeny Kliteynik free_htbls_kmem_cache:
147fb628b71SYevgeny Kliteynik 	kmem_cache_destroy(dmn->htbls_kmem_cache);
148fd785e52SYevgeny Kliteynik free_chunks_kmem_cache:
149fd785e52SYevgeny Kliteynik 	kmem_cache_destroy(dmn->chunks_kmem_cache);
150fd785e52SYevgeny Kliteynik 
151183a6706SYevgeny Kliteynik 	return ret;
152183a6706SYevgeny Kliteynik }
153183a6706SYevgeny Kliteynik 
dr_domain_uninit_mem_resources(struct mlx5dr_domain * dmn)154183a6706SYevgeny Kliteynik static void dr_domain_uninit_mem_resources(struct mlx5dr_domain *dmn)
155183a6706SYevgeny Kliteynik {
15617b56073SYevgeny Kliteynik 	mlx5dr_send_info_pool_destroy(dmn);
157183a6706SYevgeny Kliteynik 	mlx5dr_icm_pool_destroy(dmn->action_icm_pool);
158183a6706SYevgeny Kliteynik 	mlx5dr_icm_pool_destroy(dmn->ste_icm_pool);
159fb628b71SYevgeny Kliteynik 	kmem_cache_destroy(dmn->htbls_kmem_cache);
160fd785e52SYevgeny Kliteynik 	kmem_cache_destroy(dmn->chunks_kmem_cache);
161183a6706SYevgeny Kliteynik }
162183a6706SYevgeny Kliteynik 
dr_domain_init_resources(struct mlx5dr_domain * dmn)1634ec9e7b0SAlex Vesker static int dr_domain_init_resources(struct mlx5dr_domain *dmn)
1644ec9e7b0SAlex Vesker {
1654ec9e7b0SAlex Vesker 	int ret;
1664ec9e7b0SAlex Vesker 
1675212f9c6SYevgeny Kliteynik 	dmn->ste_ctx = mlx5dr_ste_get_ctx(dmn->info.caps.sw_format_ver);
1685212f9c6SYevgeny Kliteynik 	if (!dmn->ste_ctx) {
1695212f9c6SYevgeny Kliteynik 		mlx5dr_err(dmn, "SW Steering on this device is unsupported\n");
1705212f9c6SYevgeny Kliteynik 		return -EOPNOTSUPP;
1715212f9c6SYevgeny Kliteynik 	}
1725212f9c6SYevgeny Kliteynik 
1734ec9e7b0SAlex Vesker 	ret = mlx5_core_alloc_pd(dmn->mdev, &dmn->pdn);
1744ec9e7b0SAlex Vesker 	if (ret) {
175b7d0db55SErez Shitrit 		mlx5dr_err(dmn, "Couldn't allocate PD, ret: %d", ret);
1764ec9e7b0SAlex Vesker 		return ret;
1774ec9e7b0SAlex Vesker 	}
1784ec9e7b0SAlex Vesker 
1794ec9e7b0SAlex Vesker 	dmn->uar = mlx5_get_uars_page(dmn->mdev);
1806b8b4258SMiaoqian Lin 	if (IS_ERR(dmn->uar)) {
1814ec9e7b0SAlex Vesker 		mlx5dr_err(dmn, "Couldn't allocate UAR\n");
1826b8b4258SMiaoqian Lin 		ret = PTR_ERR(dmn->uar);
1834ec9e7b0SAlex Vesker 		goto clean_pd;
1844ec9e7b0SAlex Vesker 	}
1854ec9e7b0SAlex Vesker 
186183a6706SYevgeny Kliteynik 	ret = dr_domain_init_mem_resources(dmn);
187183a6706SYevgeny Kliteynik 	if (ret) {
188183a6706SYevgeny Kliteynik 		mlx5dr_err(dmn, "Couldn't create domain memory resources\n");
1894ec9e7b0SAlex Vesker 		goto clean_uar;
1904ec9e7b0SAlex Vesker 	}
1914ec9e7b0SAlex Vesker 
192108ff821SYevgeny Kliteynik 	ret = dr_domain_init_modify_header_resources(dmn);
193108ff821SYevgeny Kliteynik 	if (ret) {
194108ff821SYevgeny Kliteynik 		mlx5dr_err(dmn, "Couldn't create modify-header-resources\n");
195108ff821SYevgeny Kliteynik 		goto clean_mem_resources;
196108ff821SYevgeny Kliteynik 	}
197108ff821SYevgeny Kliteynik 
1984ec9e7b0SAlex Vesker 	ret = mlx5dr_send_ring_alloc(dmn);
1994ec9e7b0SAlex Vesker 	if (ret) {
20063d67f30SSaeed Mahameed 		mlx5dr_err(dmn, "Couldn't create send-ring\n");
201108ff821SYevgeny Kliteynik 		goto clean_modify_hdr;
2024ec9e7b0SAlex Vesker 	}
2034ec9e7b0SAlex Vesker 
2044ec9e7b0SAlex Vesker 	return 0;
2054ec9e7b0SAlex Vesker 
206108ff821SYevgeny Kliteynik clean_modify_hdr:
207108ff821SYevgeny Kliteynik 	dr_domain_destroy_modify_header_resources(dmn);
208183a6706SYevgeny Kliteynik clean_mem_resources:
209183a6706SYevgeny Kliteynik 	dr_domain_uninit_mem_resources(dmn);
2104ec9e7b0SAlex Vesker clean_uar:
2114ec9e7b0SAlex Vesker 	mlx5_put_uars_page(dmn->mdev, dmn->uar);
2124ec9e7b0SAlex Vesker clean_pd:
2134ec9e7b0SAlex Vesker 	mlx5_core_dealloc_pd(dmn->mdev, dmn->pdn);
2144ec9e7b0SAlex Vesker 
2154ec9e7b0SAlex Vesker 	return ret;
2164ec9e7b0SAlex Vesker }
2174ec9e7b0SAlex Vesker 
dr_domain_uninit_resources(struct mlx5dr_domain * dmn)2184ec9e7b0SAlex Vesker static void dr_domain_uninit_resources(struct mlx5dr_domain *dmn)
2194ec9e7b0SAlex Vesker {
2204ec9e7b0SAlex Vesker 	mlx5dr_send_ring_free(dmn, dmn->send_ring);
221108ff821SYevgeny Kliteynik 	dr_domain_destroy_modify_header_resources(dmn);
222183a6706SYevgeny Kliteynik 	dr_domain_uninit_mem_resources(dmn);
2234ec9e7b0SAlex Vesker 	mlx5_put_uars_page(dmn->mdev, dmn->uar);
2244ec9e7b0SAlex Vesker 	mlx5_core_dealloc_pd(dmn->mdev, dmn->pdn);
2254ec9e7b0SAlex Vesker }
2264ec9e7b0SAlex Vesker 
dr_domain_fill_uplink_caps(struct mlx5dr_domain * dmn,struct mlx5dr_cmd_vport_cap * uplink_vport)22711a45defSYevgeny Kliteynik static void dr_domain_fill_uplink_caps(struct mlx5dr_domain *dmn,
22811a45defSYevgeny Kliteynik 				       struct mlx5dr_cmd_vport_cap *uplink_vport)
22911a45defSYevgeny Kliteynik {
23011a45defSYevgeny Kliteynik 	struct mlx5dr_esw_caps *esw_caps = &dmn->info.caps.esw_caps;
23111a45defSYevgeny Kliteynik 
23211a45defSYevgeny Kliteynik 	uplink_vport->num = MLX5_VPORT_UPLINK;
23311a45defSYevgeny Kliteynik 	uplink_vport->icm_address_rx = esw_caps->uplink_icm_address_rx;
23411a45defSYevgeny Kliteynik 	uplink_vport->icm_address_tx = esw_caps->uplink_icm_address_tx;
23511a45defSYevgeny Kliteynik 	uplink_vport->vport_gvmi = 0;
23611a45defSYevgeny Kliteynik 	uplink_vport->vhca_gvmi = dmn->info.caps.gvmi;
23711a45defSYevgeny Kliteynik }
23811a45defSYevgeny Kliteynik 
dr_domain_query_vport(struct mlx5dr_domain * dmn,u16 vport_number,bool other_vport,struct mlx5dr_cmd_vport_cap * vport_caps)2394ec9e7b0SAlex Vesker static int dr_domain_query_vport(struct mlx5dr_domain *dmn,
240dd4acb2aSYevgeny Kliteynik 				 u16 vport_number,
2419091b821SYevgeny Kliteynik 				 bool other_vport,
242dd4acb2aSYevgeny Kliteynik 				 struct mlx5dr_cmd_vport_cap *vport_caps)
2434ec9e7b0SAlex Vesker {
2444ec9e7b0SAlex Vesker 	int ret;
2454ec9e7b0SAlex Vesker 
2464ec9e7b0SAlex Vesker 	ret = mlx5dr_cmd_query_esw_vport_context(dmn->mdev,
2474ec9e7b0SAlex Vesker 						 other_vport,
2489091b821SYevgeny Kliteynik 						 vport_number,
2494ec9e7b0SAlex Vesker 						 &vport_caps->icm_address_rx,
2504ec9e7b0SAlex Vesker 						 &vport_caps->icm_address_tx);
2514ec9e7b0SAlex Vesker 	if (ret)
2524ec9e7b0SAlex Vesker 		return ret;
2534ec9e7b0SAlex Vesker 
2544ec9e7b0SAlex Vesker 	ret = mlx5dr_cmd_query_gvmi(dmn->mdev,
2554ec9e7b0SAlex Vesker 				    other_vport,
2569091b821SYevgeny Kliteynik 				    vport_number,
2574ec9e7b0SAlex Vesker 				    &vport_caps->vport_gvmi);
2584ec9e7b0SAlex Vesker 	if (ret)
2594ec9e7b0SAlex Vesker 		return ret;
2604ec9e7b0SAlex Vesker 
2614ec9e7b0SAlex Vesker 	vport_caps->num = vport_number;
2624ec9e7b0SAlex Vesker 	vport_caps->vhca_gvmi = dmn->info.caps.gvmi;
2634ec9e7b0SAlex Vesker 
2644ec9e7b0SAlex Vesker 	return 0;
2654ec9e7b0SAlex Vesker }
2664ec9e7b0SAlex Vesker 
dr_domain_query_esw_mgr(struct mlx5dr_domain * dmn)267108ff821SYevgeny Kliteynik static int dr_domain_query_esw_mgr(struct mlx5dr_domain *dmn)
268dd4acb2aSYevgeny Kliteynik {
269624bf42cSYevgeny Kliteynik 	return dr_domain_query_vport(dmn, 0, false,
27011a45defSYevgeny Kliteynik 				     &dmn->info.caps.vports.esw_manager_caps);
271dd4acb2aSYevgeny Kliteynik }
272dd4acb2aSYevgeny Kliteynik 
dr_domain_query_uplink(struct mlx5dr_domain * dmn)2739091b821SYevgeny Kliteynik static void dr_domain_query_uplink(struct mlx5dr_domain *dmn)
2749091b821SYevgeny Kliteynik {
2759091b821SYevgeny Kliteynik 	dr_domain_fill_uplink_caps(dmn, &dmn->info.caps.vports.uplink_caps);
2769091b821SYevgeny Kliteynik }
2779091b821SYevgeny Kliteynik 
27811a45defSYevgeny Kliteynik static struct mlx5dr_cmd_vport_cap *
dr_domain_add_vport_cap(struct mlx5dr_domain * dmn,u16 vport)27911a45defSYevgeny Kliteynik dr_domain_add_vport_cap(struct mlx5dr_domain *dmn, u16 vport)
2804ec9e7b0SAlex Vesker {
28111a45defSYevgeny Kliteynik 	struct mlx5dr_cmd_caps *caps = &dmn->info.caps;
28211a45defSYevgeny Kliteynik 	struct mlx5dr_cmd_vport_cap *vport_caps;
2834ec9e7b0SAlex Vesker 	int ret;
2844ec9e7b0SAlex Vesker 
28511a45defSYevgeny Kliteynik 	vport_caps = kvzalloc(sizeof(*vport_caps), GFP_KERNEL);
28611a45defSYevgeny Kliteynik 	if (!vport_caps)
28711a45defSYevgeny Kliteynik 		return NULL;
288dd4acb2aSYevgeny Kliteynik 
2899091b821SYevgeny Kliteynik 	ret = dr_domain_query_vport(dmn, vport, true, vport_caps);
29011a45defSYevgeny Kliteynik 	if (ret) {
29111a45defSYevgeny Kliteynik 		kvfree(vport_caps);
29211a45defSYevgeny Kliteynik 		return NULL;
2934ec9e7b0SAlex Vesker 	}
2944ec9e7b0SAlex Vesker 
29511a45defSYevgeny Kliteynik 	ret = xa_insert(&caps->vports.vports_caps_xa, vport,
29611a45defSYevgeny Kliteynik 			vport_caps, GFP_KERNEL);
29711a45defSYevgeny Kliteynik 	if (ret) {
29811a45defSYevgeny Kliteynik 		mlx5dr_dbg(dmn, "Couldn't insert new vport into xarray (%d)\n", ret);
29911a45defSYevgeny Kliteynik 		kvfree(vport_caps);
30011a45defSYevgeny Kliteynik 		return ERR_PTR(ret);
30111a45defSYevgeny Kliteynik 	}
30211a45defSYevgeny Kliteynik 
30311a45defSYevgeny Kliteynik 	return vport_caps;
30411a45defSYevgeny Kliteynik }
30511a45defSYevgeny Kliteynik 
dr_domain_is_esw_mgr_vport(struct mlx5dr_domain * dmn,u16 vport)3069091b821SYevgeny Kliteynik static bool dr_domain_is_esw_mgr_vport(struct mlx5dr_domain *dmn, u16 vport)
3079091b821SYevgeny Kliteynik {
3089091b821SYevgeny Kliteynik 	struct mlx5dr_cmd_caps *caps = &dmn->info.caps;
3099091b821SYevgeny Kliteynik 
3109091b821SYevgeny Kliteynik 	return (caps->is_ecpf && vport == MLX5_VPORT_ECPF) ||
3119091b821SYevgeny Kliteynik 	       (!caps->is_ecpf && vport == 0);
3129091b821SYevgeny Kliteynik }
3139091b821SYevgeny Kliteynik 
31411a45defSYevgeny Kliteynik struct mlx5dr_cmd_vport_cap *
mlx5dr_domain_get_vport_cap(struct mlx5dr_domain * dmn,u16 vport)31511a45defSYevgeny Kliteynik mlx5dr_domain_get_vport_cap(struct mlx5dr_domain *dmn, u16 vport)
31611a45defSYevgeny Kliteynik {
31711a45defSYevgeny Kliteynik 	struct mlx5dr_cmd_caps *caps = &dmn->info.caps;
31811a45defSYevgeny Kliteynik 	struct mlx5dr_cmd_vport_cap *vport_caps;
31911a45defSYevgeny Kliteynik 
3209091b821SYevgeny Kliteynik 	if (dr_domain_is_esw_mgr_vport(dmn, vport))
32111a45defSYevgeny Kliteynik 		return &caps->vports.esw_manager_caps;
32211a45defSYevgeny Kliteynik 
3239091b821SYevgeny Kliteynik 	if (vport == MLX5_VPORT_UPLINK)
3249091b821SYevgeny Kliteynik 		return &caps->vports.uplink_caps;
3259091b821SYevgeny Kliteynik 
32611a45defSYevgeny Kliteynik vport_load:
32711a45defSYevgeny Kliteynik 	vport_caps = xa_load(&caps->vports.vports_caps_xa, vport);
32811a45defSYevgeny Kliteynik 	if (vport_caps)
32911a45defSYevgeny Kliteynik 		return vport_caps;
33011a45defSYevgeny Kliteynik 
33111a45defSYevgeny Kliteynik 	vport_caps = dr_domain_add_vport_cap(dmn, vport);
33211a45defSYevgeny Kliteynik 	if (PTR_ERR(vport_caps) == -EBUSY)
33311a45defSYevgeny Kliteynik 		/* caps were already stored by another thread */
33411a45defSYevgeny Kliteynik 		goto vport_load;
33511a45defSYevgeny Kliteynik 
33611a45defSYevgeny Kliteynik 	return vport_caps;
33711a45defSYevgeny Kliteynik }
33811a45defSYevgeny Kliteynik 
dr_domain_clear_vports(struct mlx5dr_domain * dmn)33911a45defSYevgeny Kliteynik static void dr_domain_clear_vports(struct mlx5dr_domain *dmn)
34011a45defSYevgeny Kliteynik {
34111a45defSYevgeny Kliteynik 	struct mlx5dr_cmd_vport_cap *vport_caps;
34211a45defSYevgeny Kliteynik 	unsigned long i;
34311a45defSYevgeny Kliteynik 
34411a45defSYevgeny Kliteynik 	xa_for_each(&dmn->info.caps.vports.vports_caps_xa, i, vport_caps) {
34511a45defSYevgeny Kliteynik 		vport_caps = xa_erase(&dmn->info.caps.vports.vports_caps_xa, i);
34611a45defSYevgeny Kliteynik 		kvfree(vport_caps);
34711a45defSYevgeny Kliteynik 	}
34811a45defSYevgeny Kliteynik }
34911a45defSYevgeny Kliteynik 
dr_domain_query_fdb_caps(struct mlx5_core_dev * mdev,struct mlx5dr_domain * dmn)3504ec9e7b0SAlex Vesker static int dr_domain_query_fdb_caps(struct mlx5_core_dev *mdev,
3514ec9e7b0SAlex Vesker 				    struct mlx5dr_domain *dmn)
3524ec9e7b0SAlex Vesker {
3534ec9e7b0SAlex Vesker 	int ret;
3544ec9e7b0SAlex Vesker 
3554ec9e7b0SAlex Vesker 	if (!dmn->info.caps.eswitch_manager)
3564ec9e7b0SAlex Vesker 		return -EOPNOTSUPP;
3574ec9e7b0SAlex Vesker 
3584ec9e7b0SAlex Vesker 	ret = mlx5dr_cmd_query_esw_caps(mdev, &dmn->info.caps.esw_caps);
3594ec9e7b0SAlex Vesker 	if (ret)
3604ec9e7b0SAlex Vesker 		return ret;
3614ec9e7b0SAlex Vesker 
3624ec9e7b0SAlex Vesker 	dmn->info.caps.fdb_sw_owner = dmn->info.caps.esw_caps.sw_owner;
36364f45c0fSYevgeny Kliteynik 	dmn->info.caps.fdb_sw_owner_v2 = dmn->info.caps.esw_caps.sw_owner_v2;
3644ec9e7b0SAlex Vesker 	dmn->info.caps.esw_rx_drop_address = dmn->info.caps.esw_caps.drop_icm_address_rx;
3654ec9e7b0SAlex Vesker 	dmn->info.caps.esw_tx_drop_address = dmn->info.caps.esw_caps.drop_icm_address_tx;
3664ec9e7b0SAlex Vesker 
36711a45defSYevgeny Kliteynik 	xa_init(&dmn->info.caps.vports.vports_caps_xa);
3684ec9e7b0SAlex Vesker 
36911a45defSYevgeny Kliteynik 	/* Query eswitch manager and uplink vports only. Rest of the
37011a45defSYevgeny Kliteynik 	 * vports (vport 0, VFs and SFs) will be queried dynamically.
37111a45defSYevgeny Kliteynik 	 */
37211a45defSYevgeny Kliteynik 
373108ff821SYevgeny Kliteynik 	ret = dr_domain_query_esw_mgr(dmn);
3744ec9e7b0SAlex Vesker 	if (ret) {
37511a45defSYevgeny Kliteynik 		mlx5dr_err(dmn, "Failed to query eswitch manager vport caps (err: %d)", ret);
37611a45defSYevgeny Kliteynik 		goto free_vports_caps_xa;
3774ec9e7b0SAlex Vesker 	}
3784ec9e7b0SAlex Vesker 
3799091b821SYevgeny Kliteynik 	dr_domain_query_uplink(dmn);
3804ec9e7b0SAlex Vesker 
3814ec9e7b0SAlex Vesker 	return 0;
3824ec9e7b0SAlex Vesker 
38311a45defSYevgeny Kliteynik free_vports_caps_xa:
38411a45defSYevgeny Kliteynik 	xa_destroy(&dmn->info.caps.vports.vports_caps_xa);
38511a45defSYevgeny Kliteynik 
3864ec9e7b0SAlex Vesker 	return ret;
3874ec9e7b0SAlex Vesker }
3884ec9e7b0SAlex Vesker 
dr_domain_caps_init(struct mlx5_core_dev * mdev,struct mlx5dr_domain * dmn)3894ec9e7b0SAlex Vesker static int dr_domain_caps_init(struct mlx5_core_dev *mdev,
3904ec9e7b0SAlex Vesker 			       struct mlx5dr_domain *dmn)
3914ec9e7b0SAlex Vesker {
3924ec9e7b0SAlex Vesker 	struct mlx5dr_cmd_vport_cap *vport_cap;
3934ec9e7b0SAlex Vesker 	int ret;
3944ec9e7b0SAlex Vesker 
3954ec9e7b0SAlex Vesker 	if (MLX5_CAP_GEN(mdev, port_type) != MLX5_CAP_PORT_TYPE_ETH) {
396b7d0db55SErez Shitrit 		mlx5dr_err(dmn, "Failed to allocate domain, bad link type\n");
3974ec9e7b0SAlex Vesker 		return -EOPNOTSUPP;
3984ec9e7b0SAlex Vesker 	}
3994ec9e7b0SAlex Vesker 
4004ec9e7b0SAlex Vesker 	ret = mlx5dr_cmd_query_device(mdev, &dmn->info.caps);
4014ec9e7b0SAlex Vesker 	if (ret)
4024ec9e7b0SAlex Vesker 		return ret;
4034ec9e7b0SAlex Vesker 
4044ec9e7b0SAlex Vesker 	ret = dr_domain_query_fdb_caps(mdev, dmn);
4054ec9e7b0SAlex Vesker 	if (ret)
4064ec9e7b0SAlex Vesker 		return ret;
4074ec9e7b0SAlex Vesker 
4084ec9e7b0SAlex Vesker 	switch (dmn->type) {
4094ec9e7b0SAlex Vesker 	case MLX5DR_DOMAIN_TYPE_NIC_RX:
41064f45c0fSYevgeny Kliteynik 		if (!DR_DOMAIN_SW_STEERING_SUPPORTED(dmn, rx))
4114ec9e7b0SAlex Vesker 			return -ENOTSUPP;
4124ec9e7b0SAlex Vesker 
4134ec9e7b0SAlex Vesker 		dmn->info.supp_sw_steering = true;
41446f2a8aeSYevgeny Kliteynik 		dmn->info.rx.type = DR_DOMAIN_NIC_TYPE_RX;
4154ec9e7b0SAlex Vesker 		dmn->info.rx.default_icm_addr = dmn->info.caps.nic_rx_drop_address;
4164ec9e7b0SAlex Vesker 		dmn->info.rx.drop_icm_addr = dmn->info.caps.nic_rx_drop_address;
4174ec9e7b0SAlex Vesker 		break;
4184ec9e7b0SAlex Vesker 	case MLX5DR_DOMAIN_TYPE_NIC_TX:
41964f45c0fSYevgeny Kliteynik 		if (!DR_DOMAIN_SW_STEERING_SUPPORTED(dmn, tx))
4204ec9e7b0SAlex Vesker 			return -ENOTSUPP;
4214ec9e7b0SAlex Vesker 
4224ec9e7b0SAlex Vesker 		dmn->info.supp_sw_steering = true;
42346f2a8aeSYevgeny Kliteynik 		dmn->info.tx.type = DR_DOMAIN_NIC_TYPE_TX;
4244ec9e7b0SAlex Vesker 		dmn->info.tx.default_icm_addr = dmn->info.caps.nic_tx_allow_address;
4254ec9e7b0SAlex Vesker 		dmn->info.tx.drop_icm_addr = dmn->info.caps.nic_tx_drop_address;
4264ec9e7b0SAlex Vesker 		break;
4274ec9e7b0SAlex Vesker 	case MLX5DR_DOMAIN_TYPE_FDB:
4284ec9e7b0SAlex Vesker 		if (!dmn->info.caps.eswitch_manager)
4294ec9e7b0SAlex Vesker 			return -ENOTSUPP;
4304ec9e7b0SAlex Vesker 
43164f45c0fSYevgeny Kliteynik 		if (!DR_DOMAIN_SW_STEERING_SUPPORTED(dmn, fdb))
4324ec9e7b0SAlex Vesker 			return -ENOTSUPP;
4334ec9e7b0SAlex Vesker 
43446f2a8aeSYevgeny Kliteynik 		dmn->info.rx.type = DR_DOMAIN_NIC_TYPE_RX;
43546f2a8aeSYevgeny Kliteynik 		dmn->info.tx.type = DR_DOMAIN_NIC_TYPE_TX;
43611a45defSYevgeny Kliteynik 		vport_cap = &dmn->info.caps.vports.esw_manager_caps;
4374ec9e7b0SAlex Vesker 
4384ec9e7b0SAlex Vesker 		dmn->info.supp_sw_steering = true;
4394ec9e7b0SAlex Vesker 		dmn->info.tx.default_icm_addr = vport_cap->icm_address_tx;
4404ec9e7b0SAlex Vesker 		dmn->info.rx.default_icm_addr = vport_cap->icm_address_rx;
4414ec9e7b0SAlex Vesker 		dmn->info.rx.drop_icm_addr = dmn->info.caps.esw_rx_drop_address;
4424ec9e7b0SAlex Vesker 		dmn->info.tx.drop_icm_addr = dmn->info.caps.esw_tx_drop_address;
4434ec9e7b0SAlex Vesker 		break;
4444ec9e7b0SAlex Vesker 	default:
445b7d0db55SErez Shitrit 		mlx5dr_err(dmn, "Invalid domain\n");
4464ec9e7b0SAlex Vesker 		ret = -EINVAL;
4474ec9e7b0SAlex Vesker 		break;
4484ec9e7b0SAlex Vesker 	}
4494ec9e7b0SAlex Vesker 
4504ec9e7b0SAlex Vesker 	return ret;
4514ec9e7b0SAlex Vesker }
4524ec9e7b0SAlex Vesker 
dr_domain_caps_uninit(struct mlx5dr_domain * dmn)4534ec9e7b0SAlex Vesker static void dr_domain_caps_uninit(struct mlx5dr_domain *dmn)
4544ec9e7b0SAlex Vesker {
45511a45defSYevgeny Kliteynik 	dr_domain_clear_vports(dmn);
45611a45defSYevgeny Kliteynik 	xa_destroy(&dmn->info.caps.vports.vports_caps_xa);
4574ec9e7b0SAlex Vesker }
4584ec9e7b0SAlex Vesker 
4594ec9e7b0SAlex Vesker struct mlx5dr_domain *
mlx5dr_domain_create(struct mlx5_core_dev * mdev,enum mlx5dr_domain_type type)4604ec9e7b0SAlex Vesker mlx5dr_domain_create(struct mlx5_core_dev *mdev, enum mlx5dr_domain_type type)
4614ec9e7b0SAlex Vesker {
4624ec9e7b0SAlex Vesker 	struct mlx5dr_domain *dmn;
4634ec9e7b0SAlex Vesker 	int ret;
4644ec9e7b0SAlex Vesker 
4654ec9e7b0SAlex Vesker 	if (type > MLX5DR_DOMAIN_TYPE_FDB)
4664ec9e7b0SAlex Vesker 		return NULL;
4674ec9e7b0SAlex Vesker 
4684ec9e7b0SAlex Vesker 	dmn = kzalloc(sizeof(*dmn), GFP_KERNEL);
4694ec9e7b0SAlex Vesker 	if (!dmn)
4704ec9e7b0SAlex Vesker 		return NULL;
4714ec9e7b0SAlex Vesker 
4724ec9e7b0SAlex Vesker 	dmn->mdev = mdev;
4734ec9e7b0SAlex Vesker 	dmn->type = type;
4744ec9e7b0SAlex Vesker 	refcount_set(&dmn->refcount, 1);
475ed03a418SAlex Vesker 	mutex_init(&dmn->info.rx.mutex);
476ed03a418SAlex Vesker 	mutex_init(&dmn->info.tx.mutex);
4771339678fSYevgeny Kliteynik 	xa_init(&dmn->definers_xa);
478*62752c0bSShay Drory 	xa_init(&dmn->peer_dmn_xa);
4794ec9e7b0SAlex Vesker 
4804ec9e7b0SAlex Vesker 	if (dr_domain_caps_init(mdev, dmn)) {
481b7d0db55SErez Shitrit 		mlx5dr_err(dmn, "Failed init domain, no caps\n");
4821339678fSYevgeny Kliteynik 		goto def_xa_destroy;
4834ec9e7b0SAlex Vesker 	}
4844ec9e7b0SAlex Vesker 
4854ec9e7b0SAlex Vesker 	dmn->info.max_log_action_icm_sz = DR_CHUNK_SIZE_4K;
4864ec9e7b0SAlex Vesker 	dmn->info.max_log_sw_icm_sz = min_t(u32, DR_CHUNK_SIZE_1024K,
4874ec9e7b0SAlex Vesker 					    dmn->info.caps.log_icm_size);
488108ff821SYevgeny Kliteynik 	dmn->info.max_log_modify_hdr_pattern_icm_sz =
489108ff821SYevgeny Kliteynik 		min_t(u32, DR_CHUNK_SIZE_4K,
490108ff821SYevgeny Kliteynik 		      dmn->info.caps.log_modify_pattern_icm_size);
4914ec9e7b0SAlex Vesker 
4924ec9e7b0SAlex Vesker 	if (!dmn->info.supp_sw_steering) {
49363d67f30SSaeed Mahameed 		mlx5dr_err(dmn, "SW steering is not supported\n");
4944ec9e7b0SAlex Vesker 		goto uninit_caps;
4954ec9e7b0SAlex Vesker 	}
4964ec9e7b0SAlex Vesker 
4974ec9e7b0SAlex Vesker 	/* Allocate resources */
4984ec9e7b0SAlex Vesker 	ret = dr_domain_init_resources(dmn);
4994ec9e7b0SAlex Vesker 	if (ret) {
50063d67f30SSaeed Mahameed 		mlx5dr_err(dmn, "Failed init domain resources\n");
5014ec9e7b0SAlex Vesker 		goto uninit_caps;
5024ec9e7b0SAlex Vesker 	}
5034ec9e7b0SAlex Vesker 
504c0e90fc2SYevgeny Kliteynik 	dr_domain_init_csum_recalc_fts(dmn);
5059222f0b2SMuhammad Sammar 	mlx5dr_dbg_init_dump(dmn);
5064ec9e7b0SAlex Vesker 	return dmn;
5074ec9e7b0SAlex Vesker 
5084ec9e7b0SAlex Vesker uninit_caps:
5094ec9e7b0SAlex Vesker 	dr_domain_caps_uninit(dmn);
5101339678fSYevgeny Kliteynik def_xa_destroy:
511*62752c0bSShay Drory 	xa_destroy(&dmn->peer_dmn_xa);
5121339678fSYevgeny Kliteynik 	xa_destroy(&dmn->definers_xa);
5134ec9e7b0SAlex Vesker 	kfree(dmn);
5144ec9e7b0SAlex Vesker 	return NULL;
5154ec9e7b0SAlex Vesker }
5164ec9e7b0SAlex Vesker 
5174ec9e7b0SAlex Vesker /* Assure synchronization of the device steering tables with updates made by SW
5184ec9e7b0SAlex Vesker  * insertion.
5194ec9e7b0SAlex Vesker  */
mlx5dr_domain_sync(struct mlx5dr_domain * dmn,u32 flags)5204ec9e7b0SAlex Vesker int mlx5dr_domain_sync(struct mlx5dr_domain *dmn, u32 flags)
5214ec9e7b0SAlex Vesker {
5224ec9e7b0SAlex Vesker 	int ret = 0;
5234ec9e7b0SAlex Vesker 
5244ec9e7b0SAlex Vesker 	if (flags & MLX5DR_DOMAIN_SYNC_FLAGS_SW) {
525ed03a418SAlex Vesker 		mlx5dr_domain_lock(dmn);
5264ec9e7b0SAlex Vesker 		ret = mlx5dr_send_ring_force_drain(dmn);
527ed03a418SAlex Vesker 		mlx5dr_domain_unlock(dmn);
528b7d0db55SErez Shitrit 		if (ret) {
529b7d0db55SErez Shitrit 			mlx5dr_err(dmn, "Force drain failed flags: %d, ret: %d\n",
530b7d0db55SErez Shitrit 				   flags, ret);
5314ec9e7b0SAlex Vesker 			return ret;
5324ec9e7b0SAlex Vesker 		}
533b7d0db55SErez Shitrit 	}
5344ec9e7b0SAlex Vesker 
5354ec9e7b0SAlex Vesker 	if (flags & MLX5DR_DOMAIN_SYNC_FLAGS_HW)
5364ec9e7b0SAlex Vesker 		ret = mlx5dr_cmd_sync_steering(dmn->mdev);
5374ec9e7b0SAlex Vesker 
5384ec9e7b0SAlex Vesker 	return ret;
5394ec9e7b0SAlex Vesker }
5404ec9e7b0SAlex Vesker 
mlx5dr_domain_destroy(struct mlx5dr_domain * dmn)5414ec9e7b0SAlex Vesker int mlx5dr_domain_destroy(struct mlx5dr_domain *dmn)
5424ec9e7b0SAlex Vesker {
543b5412827SYevgeny Kliteynik 	if (WARN_ON_ONCE(refcount_read(&dmn->refcount) > 1))
5444ec9e7b0SAlex Vesker 		return -EBUSY;
5454ec9e7b0SAlex Vesker 
5464ec9e7b0SAlex Vesker 	/* make sure resources are not used by the hardware */
5474ec9e7b0SAlex Vesker 	mlx5dr_cmd_sync_steering(dmn->mdev);
5489222f0b2SMuhammad Sammar 	mlx5dr_dbg_uninit_dump(dmn);
549c0e90fc2SYevgeny Kliteynik 	dr_domain_uninit_csum_recalc_fts(dmn);
5504ec9e7b0SAlex Vesker 	dr_domain_uninit_resources(dmn);
5514ec9e7b0SAlex Vesker 	dr_domain_caps_uninit(dmn);
552*62752c0bSShay Drory 	xa_destroy(&dmn->peer_dmn_xa);
5531339678fSYevgeny Kliteynik 	xa_destroy(&dmn->definers_xa);
554ed03a418SAlex Vesker 	mutex_destroy(&dmn->info.tx.mutex);
555ed03a418SAlex Vesker 	mutex_destroy(&dmn->info.rx.mutex);
5564ec9e7b0SAlex Vesker 	kfree(dmn);
5574ec9e7b0SAlex Vesker 	return 0;
5584ec9e7b0SAlex Vesker }
5594ec9e7b0SAlex Vesker 
mlx5dr_domain_set_peer(struct mlx5dr_domain * dmn,struct mlx5dr_domain * peer_dmn,u16 peer_vhca_id)5604ec9e7b0SAlex Vesker void mlx5dr_domain_set_peer(struct mlx5dr_domain *dmn,
5616d5b7321SShay Drory 			    struct mlx5dr_domain *peer_dmn,
562*62752c0bSShay Drory 			    u16 peer_vhca_id)
5634ec9e7b0SAlex Vesker {
564*62752c0bSShay Drory 	struct mlx5dr_domain *peer;
565*62752c0bSShay Drory 
566ed03a418SAlex Vesker 	mlx5dr_domain_lock(dmn);
5674ec9e7b0SAlex Vesker 
568*62752c0bSShay Drory 	peer = xa_load(&dmn->peer_dmn_xa, peer_vhca_id);
569*62752c0bSShay Drory 	if (peer)
570*62752c0bSShay Drory 		refcount_dec(&peer->refcount);
5714ec9e7b0SAlex Vesker 
572*62752c0bSShay Drory 	WARN_ON(xa_err(xa_store(&dmn->peer_dmn_xa, peer_vhca_id, peer_dmn, GFP_KERNEL)));
5734ec9e7b0SAlex Vesker 
574*62752c0bSShay Drory 	peer = xa_load(&dmn->peer_dmn_xa, peer_vhca_id);
575*62752c0bSShay Drory 	if (peer)
576*62752c0bSShay Drory 		refcount_inc(&peer->refcount);
5774ec9e7b0SAlex Vesker 
578ed03a418SAlex Vesker 	mlx5dr_domain_unlock(dmn);
5794ec9e7b0SAlex Vesker }
580