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