162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Copyright (c) 2004 Mellanox Technologies Ltd. All rights reserved. 362306a36Sopenharmony_ci * Copyright (c) 2004 Infinicon Corporation. All rights reserved. 462306a36Sopenharmony_ci * Copyright (c) 2004 Intel Corporation. All rights reserved. 562306a36Sopenharmony_ci * Copyright (c) 2004 Topspin Corporation. All rights reserved. 662306a36Sopenharmony_ci * Copyright (c) 2004 Voltaire Corporation. All rights reserved. 762306a36Sopenharmony_ci * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. 862306a36Sopenharmony_ci * Copyright (c) 2005, 2006 Cisco Systems. All rights reserved. 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * This software is available to you under a choice of one of two 1162306a36Sopenharmony_ci * licenses. You may choose to be licensed under the terms of the GNU 1262306a36Sopenharmony_ci * General Public License (GPL) Version 2, available from the file 1362306a36Sopenharmony_ci * COPYING in the main directory of this source tree, or the 1462306a36Sopenharmony_ci * OpenIB.org BSD license below: 1562306a36Sopenharmony_ci * 1662306a36Sopenharmony_ci * Redistribution and use in source and binary forms, with or 1762306a36Sopenharmony_ci * without modification, are permitted provided that the following 1862306a36Sopenharmony_ci * conditions are met: 1962306a36Sopenharmony_ci * 2062306a36Sopenharmony_ci * - Redistributions of source code must retain the above 2162306a36Sopenharmony_ci * copyright notice, this list of conditions and the following 2262306a36Sopenharmony_ci * disclaimer. 2362306a36Sopenharmony_ci * 2462306a36Sopenharmony_ci * - Redistributions in binary form must reproduce the above 2562306a36Sopenharmony_ci * copyright notice, this list of conditions and the following 2662306a36Sopenharmony_ci * disclaimer in the documentation and/or other materials 2762306a36Sopenharmony_ci * provided with the distribution. 2862306a36Sopenharmony_ci * 2962306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 3062306a36Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 3162306a36Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 3262306a36Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 3362306a36Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 3462306a36Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 3562306a36Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 3662306a36Sopenharmony_ci * SOFTWARE. 3762306a36Sopenharmony_ci */ 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci#include <linux/errno.h> 4062306a36Sopenharmony_ci#include <linux/err.h> 4162306a36Sopenharmony_ci#include <linux/export.h> 4262306a36Sopenharmony_ci#include <linux/string.h> 4362306a36Sopenharmony_ci#include <linux/slab.h> 4462306a36Sopenharmony_ci#include <linux/in.h> 4562306a36Sopenharmony_ci#include <linux/in6.h> 4662306a36Sopenharmony_ci#include <net/addrconf.h> 4762306a36Sopenharmony_ci#include <linux/security.h> 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci#include <rdma/ib_verbs.h> 5062306a36Sopenharmony_ci#include <rdma/ib_cache.h> 5162306a36Sopenharmony_ci#include <rdma/ib_addr.h> 5262306a36Sopenharmony_ci#include <rdma/rw.h> 5362306a36Sopenharmony_ci#include <rdma/lag.h> 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci#include "core_priv.h" 5662306a36Sopenharmony_ci#include <trace/events/rdma_core.h> 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_cistatic int ib_resolve_eth_dmac(struct ib_device *device, 5962306a36Sopenharmony_ci struct rdma_ah_attr *ah_attr); 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_cistatic const char * const ib_events[] = { 6262306a36Sopenharmony_ci [IB_EVENT_CQ_ERR] = "CQ error", 6362306a36Sopenharmony_ci [IB_EVENT_QP_FATAL] = "QP fatal error", 6462306a36Sopenharmony_ci [IB_EVENT_QP_REQ_ERR] = "QP request error", 6562306a36Sopenharmony_ci [IB_EVENT_QP_ACCESS_ERR] = "QP access error", 6662306a36Sopenharmony_ci [IB_EVENT_COMM_EST] = "communication established", 6762306a36Sopenharmony_ci [IB_EVENT_SQ_DRAINED] = "send queue drained", 6862306a36Sopenharmony_ci [IB_EVENT_PATH_MIG] = "path migration successful", 6962306a36Sopenharmony_ci [IB_EVENT_PATH_MIG_ERR] = "path migration error", 7062306a36Sopenharmony_ci [IB_EVENT_DEVICE_FATAL] = "device fatal error", 7162306a36Sopenharmony_ci [IB_EVENT_PORT_ACTIVE] = "port active", 7262306a36Sopenharmony_ci [IB_EVENT_PORT_ERR] = "port error", 7362306a36Sopenharmony_ci [IB_EVENT_LID_CHANGE] = "LID change", 7462306a36Sopenharmony_ci [IB_EVENT_PKEY_CHANGE] = "P_key change", 7562306a36Sopenharmony_ci [IB_EVENT_SM_CHANGE] = "SM change", 7662306a36Sopenharmony_ci [IB_EVENT_SRQ_ERR] = "SRQ error", 7762306a36Sopenharmony_ci [IB_EVENT_SRQ_LIMIT_REACHED] = "SRQ limit reached", 7862306a36Sopenharmony_ci [IB_EVENT_QP_LAST_WQE_REACHED] = "last WQE reached", 7962306a36Sopenharmony_ci [IB_EVENT_CLIENT_REREGISTER] = "client reregister", 8062306a36Sopenharmony_ci [IB_EVENT_GID_CHANGE] = "GID changed", 8162306a36Sopenharmony_ci}; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ciconst char *__attribute_const__ ib_event_msg(enum ib_event_type event) 8462306a36Sopenharmony_ci{ 8562306a36Sopenharmony_ci size_t index = event; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci return (index < ARRAY_SIZE(ib_events) && ib_events[index]) ? 8862306a36Sopenharmony_ci ib_events[index] : "unrecognized event"; 8962306a36Sopenharmony_ci} 9062306a36Sopenharmony_ciEXPORT_SYMBOL(ib_event_msg); 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_cistatic const char * const wc_statuses[] = { 9362306a36Sopenharmony_ci [IB_WC_SUCCESS] = "success", 9462306a36Sopenharmony_ci [IB_WC_LOC_LEN_ERR] = "local length error", 9562306a36Sopenharmony_ci [IB_WC_LOC_QP_OP_ERR] = "local QP operation error", 9662306a36Sopenharmony_ci [IB_WC_LOC_EEC_OP_ERR] = "local EE context operation error", 9762306a36Sopenharmony_ci [IB_WC_LOC_PROT_ERR] = "local protection error", 9862306a36Sopenharmony_ci [IB_WC_WR_FLUSH_ERR] = "WR flushed", 9962306a36Sopenharmony_ci [IB_WC_MW_BIND_ERR] = "memory bind operation error", 10062306a36Sopenharmony_ci [IB_WC_BAD_RESP_ERR] = "bad response error", 10162306a36Sopenharmony_ci [IB_WC_LOC_ACCESS_ERR] = "local access error", 10262306a36Sopenharmony_ci [IB_WC_REM_INV_REQ_ERR] = "remote invalid request error", 10362306a36Sopenharmony_ci [IB_WC_REM_ACCESS_ERR] = "remote access error", 10462306a36Sopenharmony_ci [IB_WC_REM_OP_ERR] = "remote operation error", 10562306a36Sopenharmony_ci [IB_WC_RETRY_EXC_ERR] = "transport retry counter exceeded", 10662306a36Sopenharmony_ci [IB_WC_RNR_RETRY_EXC_ERR] = "RNR retry counter exceeded", 10762306a36Sopenharmony_ci [IB_WC_LOC_RDD_VIOL_ERR] = "local RDD violation error", 10862306a36Sopenharmony_ci [IB_WC_REM_INV_RD_REQ_ERR] = "remote invalid RD request", 10962306a36Sopenharmony_ci [IB_WC_REM_ABORT_ERR] = "operation aborted", 11062306a36Sopenharmony_ci [IB_WC_INV_EECN_ERR] = "invalid EE context number", 11162306a36Sopenharmony_ci [IB_WC_INV_EEC_STATE_ERR] = "invalid EE context state", 11262306a36Sopenharmony_ci [IB_WC_FATAL_ERR] = "fatal error", 11362306a36Sopenharmony_ci [IB_WC_RESP_TIMEOUT_ERR] = "response timeout error", 11462306a36Sopenharmony_ci [IB_WC_GENERAL_ERR] = "general error", 11562306a36Sopenharmony_ci}; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ciconst char *__attribute_const__ ib_wc_status_msg(enum ib_wc_status status) 11862306a36Sopenharmony_ci{ 11962306a36Sopenharmony_ci size_t index = status; 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci return (index < ARRAY_SIZE(wc_statuses) && wc_statuses[index]) ? 12262306a36Sopenharmony_ci wc_statuses[index] : "unrecognized status"; 12362306a36Sopenharmony_ci} 12462306a36Sopenharmony_ciEXPORT_SYMBOL(ib_wc_status_msg); 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci__attribute_const__ int ib_rate_to_mult(enum ib_rate rate) 12762306a36Sopenharmony_ci{ 12862306a36Sopenharmony_ci switch (rate) { 12962306a36Sopenharmony_ci case IB_RATE_2_5_GBPS: return 1; 13062306a36Sopenharmony_ci case IB_RATE_5_GBPS: return 2; 13162306a36Sopenharmony_ci case IB_RATE_10_GBPS: return 4; 13262306a36Sopenharmony_ci case IB_RATE_20_GBPS: return 8; 13362306a36Sopenharmony_ci case IB_RATE_30_GBPS: return 12; 13462306a36Sopenharmony_ci case IB_RATE_40_GBPS: return 16; 13562306a36Sopenharmony_ci case IB_RATE_60_GBPS: return 24; 13662306a36Sopenharmony_ci case IB_RATE_80_GBPS: return 32; 13762306a36Sopenharmony_ci case IB_RATE_120_GBPS: return 48; 13862306a36Sopenharmony_ci case IB_RATE_14_GBPS: return 6; 13962306a36Sopenharmony_ci case IB_RATE_56_GBPS: return 22; 14062306a36Sopenharmony_ci case IB_RATE_112_GBPS: return 45; 14162306a36Sopenharmony_ci case IB_RATE_168_GBPS: return 67; 14262306a36Sopenharmony_ci case IB_RATE_25_GBPS: return 10; 14362306a36Sopenharmony_ci case IB_RATE_100_GBPS: return 40; 14462306a36Sopenharmony_ci case IB_RATE_200_GBPS: return 80; 14562306a36Sopenharmony_ci case IB_RATE_300_GBPS: return 120; 14662306a36Sopenharmony_ci case IB_RATE_28_GBPS: return 11; 14762306a36Sopenharmony_ci case IB_RATE_50_GBPS: return 20; 14862306a36Sopenharmony_ci case IB_RATE_400_GBPS: return 160; 14962306a36Sopenharmony_ci case IB_RATE_600_GBPS: return 240; 15062306a36Sopenharmony_ci default: return -1; 15162306a36Sopenharmony_ci } 15262306a36Sopenharmony_ci} 15362306a36Sopenharmony_ciEXPORT_SYMBOL(ib_rate_to_mult); 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci__attribute_const__ enum ib_rate mult_to_ib_rate(int mult) 15662306a36Sopenharmony_ci{ 15762306a36Sopenharmony_ci switch (mult) { 15862306a36Sopenharmony_ci case 1: return IB_RATE_2_5_GBPS; 15962306a36Sopenharmony_ci case 2: return IB_RATE_5_GBPS; 16062306a36Sopenharmony_ci case 4: return IB_RATE_10_GBPS; 16162306a36Sopenharmony_ci case 8: return IB_RATE_20_GBPS; 16262306a36Sopenharmony_ci case 12: return IB_RATE_30_GBPS; 16362306a36Sopenharmony_ci case 16: return IB_RATE_40_GBPS; 16462306a36Sopenharmony_ci case 24: return IB_RATE_60_GBPS; 16562306a36Sopenharmony_ci case 32: return IB_RATE_80_GBPS; 16662306a36Sopenharmony_ci case 48: return IB_RATE_120_GBPS; 16762306a36Sopenharmony_ci case 6: return IB_RATE_14_GBPS; 16862306a36Sopenharmony_ci case 22: return IB_RATE_56_GBPS; 16962306a36Sopenharmony_ci case 45: return IB_RATE_112_GBPS; 17062306a36Sopenharmony_ci case 67: return IB_RATE_168_GBPS; 17162306a36Sopenharmony_ci case 10: return IB_RATE_25_GBPS; 17262306a36Sopenharmony_ci case 40: return IB_RATE_100_GBPS; 17362306a36Sopenharmony_ci case 80: return IB_RATE_200_GBPS; 17462306a36Sopenharmony_ci case 120: return IB_RATE_300_GBPS; 17562306a36Sopenharmony_ci case 11: return IB_RATE_28_GBPS; 17662306a36Sopenharmony_ci case 20: return IB_RATE_50_GBPS; 17762306a36Sopenharmony_ci case 160: return IB_RATE_400_GBPS; 17862306a36Sopenharmony_ci case 240: return IB_RATE_600_GBPS; 17962306a36Sopenharmony_ci default: return IB_RATE_PORT_CURRENT; 18062306a36Sopenharmony_ci } 18162306a36Sopenharmony_ci} 18262306a36Sopenharmony_ciEXPORT_SYMBOL(mult_to_ib_rate); 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci__attribute_const__ int ib_rate_to_mbps(enum ib_rate rate) 18562306a36Sopenharmony_ci{ 18662306a36Sopenharmony_ci switch (rate) { 18762306a36Sopenharmony_ci case IB_RATE_2_5_GBPS: return 2500; 18862306a36Sopenharmony_ci case IB_RATE_5_GBPS: return 5000; 18962306a36Sopenharmony_ci case IB_RATE_10_GBPS: return 10000; 19062306a36Sopenharmony_ci case IB_RATE_20_GBPS: return 20000; 19162306a36Sopenharmony_ci case IB_RATE_30_GBPS: return 30000; 19262306a36Sopenharmony_ci case IB_RATE_40_GBPS: return 40000; 19362306a36Sopenharmony_ci case IB_RATE_60_GBPS: return 60000; 19462306a36Sopenharmony_ci case IB_RATE_80_GBPS: return 80000; 19562306a36Sopenharmony_ci case IB_RATE_120_GBPS: return 120000; 19662306a36Sopenharmony_ci case IB_RATE_14_GBPS: return 14062; 19762306a36Sopenharmony_ci case IB_RATE_56_GBPS: return 56250; 19862306a36Sopenharmony_ci case IB_RATE_112_GBPS: return 112500; 19962306a36Sopenharmony_ci case IB_RATE_168_GBPS: return 168750; 20062306a36Sopenharmony_ci case IB_RATE_25_GBPS: return 25781; 20162306a36Sopenharmony_ci case IB_RATE_100_GBPS: return 103125; 20262306a36Sopenharmony_ci case IB_RATE_200_GBPS: return 206250; 20362306a36Sopenharmony_ci case IB_RATE_300_GBPS: return 309375; 20462306a36Sopenharmony_ci case IB_RATE_28_GBPS: return 28125; 20562306a36Sopenharmony_ci case IB_RATE_50_GBPS: return 53125; 20662306a36Sopenharmony_ci case IB_RATE_400_GBPS: return 425000; 20762306a36Sopenharmony_ci case IB_RATE_600_GBPS: return 637500; 20862306a36Sopenharmony_ci default: return -1; 20962306a36Sopenharmony_ci } 21062306a36Sopenharmony_ci} 21162306a36Sopenharmony_ciEXPORT_SYMBOL(ib_rate_to_mbps); 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci__attribute_const__ enum rdma_transport_type 21462306a36Sopenharmony_cirdma_node_get_transport(unsigned int node_type) 21562306a36Sopenharmony_ci{ 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci if (node_type == RDMA_NODE_USNIC) 21862306a36Sopenharmony_ci return RDMA_TRANSPORT_USNIC; 21962306a36Sopenharmony_ci if (node_type == RDMA_NODE_USNIC_UDP) 22062306a36Sopenharmony_ci return RDMA_TRANSPORT_USNIC_UDP; 22162306a36Sopenharmony_ci if (node_type == RDMA_NODE_RNIC) 22262306a36Sopenharmony_ci return RDMA_TRANSPORT_IWARP; 22362306a36Sopenharmony_ci if (node_type == RDMA_NODE_UNSPECIFIED) 22462306a36Sopenharmony_ci return RDMA_TRANSPORT_UNSPECIFIED; 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci return RDMA_TRANSPORT_IB; 22762306a36Sopenharmony_ci} 22862306a36Sopenharmony_ciEXPORT_SYMBOL(rdma_node_get_transport); 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_cienum rdma_link_layer rdma_port_get_link_layer(struct ib_device *device, 23162306a36Sopenharmony_ci u32 port_num) 23262306a36Sopenharmony_ci{ 23362306a36Sopenharmony_ci enum rdma_transport_type lt; 23462306a36Sopenharmony_ci if (device->ops.get_link_layer) 23562306a36Sopenharmony_ci return device->ops.get_link_layer(device, port_num); 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci lt = rdma_node_get_transport(device->node_type); 23862306a36Sopenharmony_ci if (lt == RDMA_TRANSPORT_IB) 23962306a36Sopenharmony_ci return IB_LINK_LAYER_INFINIBAND; 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci return IB_LINK_LAYER_ETHERNET; 24262306a36Sopenharmony_ci} 24362306a36Sopenharmony_ciEXPORT_SYMBOL(rdma_port_get_link_layer); 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci/* Protection domains */ 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci/** 24862306a36Sopenharmony_ci * __ib_alloc_pd - Allocates an unused protection domain. 24962306a36Sopenharmony_ci * @device: The device on which to allocate the protection domain. 25062306a36Sopenharmony_ci * @flags: protection domain flags 25162306a36Sopenharmony_ci * @caller: caller's build-time module name 25262306a36Sopenharmony_ci * 25362306a36Sopenharmony_ci * A protection domain object provides an association between QPs, shared 25462306a36Sopenharmony_ci * receive queues, address handles, memory regions, and memory windows. 25562306a36Sopenharmony_ci * 25662306a36Sopenharmony_ci * Every PD has a local_dma_lkey which can be used as the lkey value for local 25762306a36Sopenharmony_ci * memory operations. 25862306a36Sopenharmony_ci */ 25962306a36Sopenharmony_cistruct ib_pd *__ib_alloc_pd(struct ib_device *device, unsigned int flags, 26062306a36Sopenharmony_ci const char *caller) 26162306a36Sopenharmony_ci{ 26262306a36Sopenharmony_ci struct ib_pd *pd; 26362306a36Sopenharmony_ci int mr_access_flags = 0; 26462306a36Sopenharmony_ci int ret; 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci pd = rdma_zalloc_drv_obj(device, ib_pd); 26762306a36Sopenharmony_ci if (!pd) 26862306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci pd->device = device; 27162306a36Sopenharmony_ci pd->flags = flags; 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci rdma_restrack_new(&pd->res, RDMA_RESTRACK_PD); 27462306a36Sopenharmony_ci rdma_restrack_set_name(&pd->res, caller); 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci ret = device->ops.alloc_pd(pd, NULL); 27762306a36Sopenharmony_ci if (ret) { 27862306a36Sopenharmony_ci rdma_restrack_put(&pd->res); 27962306a36Sopenharmony_ci kfree(pd); 28062306a36Sopenharmony_ci return ERR_PTR(ret); 28162306a36Sopenharmony_ci } 28262306a36Sopenharmony_ci rdma_restrack_add(&pd->res); 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci if (device->attrs.kernel_cap_flags & IBK_LOCAL_DMA_LKEY) 28562306a36Sopenharmony_ci pd->local_dma_lkey = device->local_dma_lkey; 28662306a36Sopenharmony_ci else 28762306a36Sopenharmony_ci mr_access_flags |= IB_ACCESS_LOCAL_WRITE; 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci if (flags & IB_PD_UNSAFE_GLOBAL_RKEY) { 29062306a36Sopenharmony_ci pr_warn("%s: enabling unsafe global rkey\n", caller); 29162306a36Sopenharmony_ci mr_access_flags |= IB_ACCESS_REMOTE_READ | IB_ACCESS_REMOTE_WRITE; 29262306a36Sopenharmony_ci } 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci if (mr_access_flags) { 29562306a36Sopenharmony_ci struct ib_mr *mr; 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci mr = pd->device->ops.get_dma_mr(pd, mr_access_flags); 29862306a36Sopenharmony_ci if (IS_ERR(mr)) { 29962306a36Sopenharmony_ci ib_dealloc_pd(pd); 30062306a36Sopenharmony_ci return ERR_CAST(mr); 30162306a36Sopenharmony_ci } 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci mr->device = pd->device; 30462306a36Sopenharmony_ci mr->pd = pd; 30562306a36Sopenharmony_ci mr->type = IB_MR_TYPE_DMA; 30662306a36Sopenharmony_ci mr->uobject = NULL; 30762306a36Sopenharmony_ci mr->need_inval = false; 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci pd->__internal_mr = mr; 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci if (!(device->attrs.kernel_cap_flags & IBK_LOCAL_DMA_LKEY)) 31262306a36Sopenharmony_ci pd->local_dma_lkey = pd->__internal_mr->lkey; 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci if (flags & IB_PD_UNSAFE_GLOBAL_RKEY) 31562306a36Sopenharmony_ci pd->unsafe_global_rkey = pd->__internal_mr->rkey; 31662306a36Sopenharmony_ci } 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci return pd; 31962306a36Sopenharmony_ci} 32062306a36Sopenharmony_ciEXPORT_SYMBOL(__ib_alloc_pd); 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci/** 32362306a36Sopenharmony_ci * ib_dealloc_pd_user - Deallocates a protection domain. 32462306a36Sopenharmony_ci * @pd: The protection domain to deallocate. 32562306a36Sopenharmony_ci * @udata: Valid user data or NULL for kernel object 32662306a36Sopenharmony_ci * 32762306a36Sopenharmony_ci * It is an error to call this function while any resources in the pd still 32862306a36Sopenharmony_ci * exist. The caller is responsible to synchronously destroy them and 32962306a36Sopenharmony_ci * guarantee no new allocations will happen. 33062306a36Sopenharmony_ci */ 33162306a36Sopenharmony_ciint ib_dealloc_pd_user(struct ib_pd *pd, struct ib_udata *udata) 33262306a36Sopenharmony_ci{ 33362306a36Sopenharmony_ci int ret; 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci if (pd->__internal_mr) { 33662306a36Sopenharmony_ci ret = pd->device->ops.dereg_mr(pd->__internal_mr, NULL); 33762306a36Sopenharmony_ci WARN_ON(ret); 33862306a36Sopenharmony_ci pd->__internal_mr = NULL; 33962306a36Sopenharmony_ci } 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci ret = pd->device->ops.dealloc_pd(pd, udata); 34262306a36Sopenharmony_ci if (ret) 34362306a36Sopenharmony_ci return ret; 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci rdma_restrack_del(&pd->res); 34662306a36Sopenharmony_ci kfree(pd); 34762306a36Sopenharmony_ci return ret; 34862306a36Sopenharmony_ci} 34962306a36Sopenharmony_ciEXPORT_SYMBOL(ib_dealloc_pd_user); 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci/* Address handles */ 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci/** 35462306a36Sopenharmony_ci * rdma_copy_ah_attr - Copy rdma ah attribute from source to destination. 35562306a36Sopenharmony_ci * @dest: Pointer to destination ah_attr. Contents of the destination 35662306a36Sopenharmony_ci * pointer is assumed to be invalid and attribute are overwritten. 35762306a36Sopenharmony_ci * @src: Pointer to source ah_attr. 35862306a36Sopenharmony_ci */ 35962306a36Sopenharmony_civoid rdma_copy_ah_attr(struct rdma_ah_attr *dest, 36062306a36Sopenharmony_ci const struct rdma_ah_attr *src) 36162306a36Sopenharmony_ci{ 36262306a36Sopenharmony_ci *dest = *src; 36362306a36Sopenharmony_ci if (dest->grh.sgid_attr) 36462306a36Sopenharmony_ci rdma_hold_gid_attr(dest->grh.sgid_attr); 36562306a36Sopenharmony_ci} 36662306a36Sopenharmony_ciEXPORT_SYMBOL(rdma_copy_ah_attr); 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci/** 36962306a36Sopenharmony_ci * rdma_replace_ah_attr - Replace valid ah_attr with new new one. 37062306a36Sopenharmony_ci * @old: Pointer to existing ah_attr which needs to be replaced. 37162306a36Sopenharmony_ci * old is assumed to be valid or zero'd 37262306a36Sopenharmony_ci * @new: Pointer to the new ah_attr. 37362306a36Sopenharmony_ci * 37462306a36Sopenharmony_ci * rdma_replace_ah_attr() first releases any reference in the old ah_attr if 37562306a36Sopenharmony_ci * old the ah_attr is valid; after that it copies the new attribute and holds 37662306a36Sopenharmony_ci * the reference to the replaced ah_attr. 37762306a36Sopenharmony_ci */ 37862306a36Sopenharmony_civoid rdma_replace_ah_attr(struct rdma_ah_attr *old, 37962306a36Sopenharmony_ci const struct rdma_ah_attr *new) 38062306a36Sopenharmony_ci{ 38162306a36Sopenharmony_ci rdma_destroy_ah_attr(old); 38262306a36Sopenharmony_ci *old = *new; 38362306a36Sopenharmony_ci if (old->grh.sgid_attr) 38462306a36Sopenharmony_ci rdma_hold_gid_attr(old->grh.sgid_attr); 38562306a36Sopenharmony_ci} 38662306a36Sopenharmony_ciEXPORT_SYMBOL(rdma_replace_ah_attr); 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci/** 38962306a36Sopenharmony_ci * rdma_move_ah_attr - Move ah_attr pointed by source to destination. 39062306a36Sopenharmony_ci * @dest: Pointer to destination ah_attr to copy to. 39162306a36Sopenharmony_ci * dest is assumed to be valid or zero'd 39262306a36Sopenharmony_ci * @src: Pointer to the new ah_attr. 39362306a36Sopenharmony_ci * 39462306a36Sopenharmony_ci * rdma_move_ah_attr() first releases any reference in the destination ah_attr 39562306a36Sopenharmony_ci * if it is valid. This also transfers ownership of internal references from 39662306a36Sopenharmony_ci * src to dest, making src invalid in the process. No new reference of the src 39762306a36Sopenharmony_ci * ah_attr is taken. 39862306a36Sopenharmony_ci */ 39962306a36Sopenharmony_civoid rdma_move_ah_attr(struct rdma_ah_attr *dest, struct rdma_ah_attr *src) 40062306a36Sopenharmony_ci{ 40162306a36Sopenharmony_ci rdma_destroy_ah_attr(dest); 40262306a36Sopenharmony_ci *dest = *src; 40362306a36Sopenharmony_ci src->grh.sgid_attr = NULL; 40462306a36Sopenharmony_ci} 40562306a36Sopenharmony_ciEXPORT_SYMBOL(rdma_move_ah_attr); 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci/* 40862306a36Sopenharmony_ci * Validate that the rdma_ah_attr is valid for the device before passing it 40962306a36Sopenharmony_ci * off to the driver. 41062306a36Sopenharmony_ci */ 41162306a36Sopenharmony_cistatic int rdma_check_ah_attr(struct ib_device *device, 41262306a36Sopenharmony_ci struct rdma_ah_attr *ah_attr) 41362306a36Sopenharmony_ci{ 41462306a36Sopenharmony_ci if (!rdma_is_port_valid(device, ah_attr->port_num)) 41562306a36Sopenharmony_ci return -EINVAL; 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci if ((rdma_is_grh_required(device, ah_attr->port_num) || 41862306a36Sopenharmony_ci ah_attr->type == RDMA_AH_ATTR_TYPE_ROCE) && 41962306a36Sopenharmony_ci !(ah_attr->ah_flags & IB_AH_GRH)) 42062306a36Sopenharmony_ci return -EINVAL; 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci if (ah_attr->grh.sgid_attr) { 42362306a36Sopenharmony_ci /* 42462306a36Sopenharmony_ci * Make sure the passed sgid_attr is consistent with the 42562306a36Sopenharmony_ci * parameters 42662306a36Sopenharmony_ci */ 42762306a36Sopenharmony_ci if (ah_attr->grh.sgid_attr->index != ah_attr->grh.sgid_index || 42862306a36Sopenharmony_ci ah_attr->grh.sgid_attr->port_num != ah_attr->port_num) 42962306a36Sopenharmony_ci return -EINVAL; 43062306a36Sopenharmony_ci } 43162306a36Sopenharmony_ci return 0; 43262306a36Sopenharmony_ci} 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci/* 43562306a36Sopenharmony_ci * If the ah requires a GRH then ensure that sgid_attr pointer is filled in. 43662306a36Sopenharmony_ci * On success the caller is responsible to call rdma_unfill_sgid_attr(). 43762306a36Sopenharmony_ci */ 43862306a36Sopenharmony_cistatic int rdma_fill_sgid_attr(struct ib_device *device, 43962306a36Sopenharmony_ci struct rdma_ah_attr *ah_attr, 44062306a36Sopenharmony_ci const struct ib_gid_attr **old_sgid_attr) 44162306a36Sopenharmony_ci{ 44262306a36Sopenharmony_ci const struct ib_gid_attr *sgid_attr; 44362306a36Sopenharmony_ci struct ib_global_route *grh; 44462306a36Sopenharmony_ci int ret; 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci *old_sgid_attr = ah_attr->grh.sgid_attr; 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci ret = rdma_check_ah_attr(device, ah_attr); 44962306a36Sopenharmony_ci if (ret) 45062306a36Sopenharmony_ci return ret; 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci if (!(ah_attr->ah_flags & IB_AH_GRH)) 45362306a36Sopenharmony_ci return 0; 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci grh = rdma_ah_retrieve_grh(ah_attr); 45662306a36Sopenharmony_ci if (grh->sgid_attr) 45762306a36Sopenharmony_ci return 0; 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci sgid_attr = 46062306a36Sopenharmony_ci rdma_get_gid_attr(device, ah_attr->port_num, grh->sgid_index); 46162306a36Sopenharmony_ci if (IS_ERR(sgid_attr)) 46262306a36Sopenharmony_ci return PTR_ERR(sgid_attr); 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci /* Move ownerhip of the kref into the ah_attr */ 46562306a36Sopenharmony_ci grh->sgid_attr = sgid_attr; 46662306a36Sopenharmony_ci return 0; 46762306a36Sopenharmony_ci} 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_cistatic void rdma_unfill_sgid_attr(struct rdma_ah_attr *ah_attr, 47062306a36Sopenharmony_ci const struct ib_gid_attr *old_sgid_attr) 47162306a36Sopenharmony_ci{ 47262306a36Sopenharmony_ci /* 47362306a36Sopenharmony_ci * Fill didn't change anything, the caller retains ownership of 47462306a36Sopenharmony_ci * whatever it passed 47562306a36Sopenharmony_ci */ 47662306a36Sopenharmony_ci if (ah_attr->grh.sgid_attr == old_sgid_attr) 47762306a36Sopenharmony_ci return; 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci /* 48062306a36Sopenharmony_ci * Otherwise, we need to undo what rdma_fill_sgid_attr so the caller 48162306a36Sopenharmony_ci * doesn't see any change in the rdma_ah_attr. If we get here 48262306a36Sopenharmony_ci * old_sgid_attr is NULL. 48362306a36Sopenharmony_ci */ 48462306a36Sopenharmony_ci rdma_destroy_ah_attr(ah_attr); 48562306a36Sopenharmony_ci} 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_cistatic const struct ib_gid_attr * 48862306a36Sopenharmony_cirdma_update_sgid_attr(struct rdma_ah_attr *ah_attr, 48962306a36Sopenharmony_ci const struct ib_gid_attr *old_attr) 49062306a36Sopenharmony_ci{ 49162306a36Sopenharmony_ci if (old_attr) 49262306a36Sopenharmony_ci rdma_put_gid_attr(old_attr); 49362306a36Sopenharmony_ci if (ah_attr->ah_flags & IB_AH_GRH) { 49462306a36Sopenharmony_ci rdma_hold_gid_attr(ah_attr->grh.sgid_attr); 49562306a36Sopenharmony_ci return ah_attr->grh.sgid_attr; 49662306a36Sopenharmony_ci } 49762306a36Sopenharmony_ci return NULL; 49862306a36Sopenharmony_ci} 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_cistatic struct ib_ah *_rdma_create_ah(struct ib_pd *pd, 50162306a36Sopenharmony_ci struct rdma_ah_attr *ah_attr, 50262306a36Sopenharmony_ci u32 flags, 50362306a36Sopenharmony_ci struct ib_udata *udata, 50462306a36Sopenharmony_ci struct net_device *xmit_slave) 50562306a36Sopenharmony_ci{ 50662306a36Sopenharmony_ci struct rdma_ah_init_attr init_attr = {}; 50762306a36Sopenharmony_ci struct ib_device *device = pd->device; 50862306a36Sopenharmony_ci struct ib_ah *ah; 50962306a36Sopenharmony_ci int ret; 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci might_sleep_if(flags & RDMA_CREATE_AH_SLEEPABLE); 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci if (!udata && !device->ops.create_ah) 51462306a36Sopenharmony_ci return ERR_PTR(-EOPNOTSUPP); 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci ah = rdma_zalloc_drv_obj_gfp( 51762306a36Sopenharmony_ci device, ib_ah, 51862306a36Sopenharmony_ci (flags & RDMA_CREATE_AH_SLEEPABLE) ? GFP_KERNEL : GFP_ATOMIC); 51962306a36Sopenharmony_ci if (!ah) 52062306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci ah->device = device; 52362306a36Sopenharmony_ci ah->pd = pd; 52462306a36Sopenharmony_ci ah->type = ah_attr->type; 52562306a36Sopenharmony_ci ah->sgid_attr = rdma_update_sgid_attr(ah_attr, NULL); 52662306a36Sopenharmony_ci init_attr.ah_attr = ah_attr; 52762306a36Sopenharmony_ci init_attr.flags = flags; 52862306a36Sopenharmony_ci init_attr.xmit_slave = xmit_slave; 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci if (udata) 53162306a36Sopenharmony_ci ret = device->ops.create_user_ah(ah, &init_attr, udata); 53262306a36Sopenharmony_ci else 53362306a36Sopenharmony_ci ret = device->ops.create_ah(ah, &init_attr, NULL); 53462306a36Sopenharmony_ci if (ret) { 53562306a36Sopenharmony_ci if (ah->sgid_attr) 53662306a36Sopenharmony_ci rdma_put_gid_attr(ah->sgid_attr); 53762306a36Sopenharmony_ci kfree(ah); 53862306a36Sopenharmony_ci return ERR_PTR(ret); 53962306a36Sopenharmony_ci } 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci atomic_inc(&pd->usecnt); 54262306a36Sopenharmony_ci return ah; 54362306a36Sopenharmony_ci} 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci/** 54662306a36Sopenharmony_ci * rdma_create_ah - Creates an address handle for the 54762306a36Sopenharmony_ci * given address vector. 54862306a36Sopenharmony_ci * @pd: The protection domain associated with the address handle. 54962306a36Sopenharmony_ci * @ah_attr: The attributes of the address vector. 55062306a36Sopenharmony_ci * @flags: Create address handle flags (see enum rdma_create_ah_flags). 55162306a36Sopenharmony_ci * 55262306a36Sopenharmony_ci * It returns 0 on success and returns appropriate error code on error. 55362306a36Sopenharmony_ci * The address handle is used to reference a local or global destination 55462306a36Sopenharmony_ci * in all UD QP post sends. 55562306a36Sopenharmony_ci */ 55662306a36Sopenharmony_cistruct ib_ah *rdma_create_ah(struct ib_pd *pd, struct rdma_ah_attr *ah_attr, 55762306a36Sopenharmony_ci u32 flags) 55862306a36Sopenharmony_ci{ 55962306a36Sopenharmony_ci const struct ib_gid_attr *old_sgid_attr; 56062306a36Sopenharmony_ci struct net_device *slave; 56162306a36Sopenharmony_ci struct ib_ah *ah; 56262306a36Sopenharmony_ci int ret; 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci ret = rdma_fill_sgid_attr(pd->device, ah_attr, &old_sgid_attr); 56562306a36Sopenharmony_ci if (ret) 56662306a36Sopenharmony_ci return ERR_PTR(ret); 56762306a36Sopenharmony_ci slave = rdma_lag_get_ah_roce_slave(pd->device, ah_attr, 56862306a36Sopenharmony_ci (flags & RDMA_CREATE_AH_SLEEPABLE) ? 56962306a36Sopenharmony_ci GFP_KERNEL : GFP_ATOMIC); 57062306a36Sopenharmony_ci if (IS_ERR(slave)) { 57162306a36Sopenharmony_ci rdma_unfill_sgid_attr(ah_attr, old_sgid_attr); 57262306a36Sopenharmony_ci return (void *)slave; 57362306a36Sopenharmony_ci } 57462306a36Sopenharmony_ci ah = _rdma_create_ah(pd, ah_attr, flags, NULL, slave); 57562306a36Sopenharmony_ci rdma_lag_put_ah_roce_slave(slave); 57662306a36Sopenharmony_ci rdma_unfill_sgid_attr(ah_attr, old_sgid_attr); 57762306a36Sopenharmony_ci return ah; 57862306a36Sopenharmony_ci} 57962306a36Sopenharmony_ciEXPORT_SYMBOL(rdma_create_ah); 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci/** 58262306a36Sopenharmony_ci * rdma_create_user_ah - Creates an address handle for the 58362306a36Sopenharmony_ci * given address vector. 58462306a36Sopenharmony_ci * It resolves destination mac address for ah attribute of RoCE type. 58562306a36Sopenharmony_ci * @pd: The protection domain associated with the address handle. 58662306a36Sopenharmony_ci * @ah_attr: The attributes of the address vector. 58762306a36Sopenharmony_ci * @udata: pointer to user's input output buffer information need by 58862306a36Sopenharmony_ci * provider driver. 58962306a36Sopenharmony_ci * 59062306a36Sopenharmony_ci * It returns 0 on success and returns appropriate error code on error. 59162306a36Sopenharmony_ci * The address handle is used to reference a local or global destination 59262306a36Sopenharmony_ci * in all UD QP post sends. 59362306a36Sopenharmony_ci */ 59462306a36Sopenharmony_cistruct ib_ah *rdma_create_user_ah(struct ib_pd *pd, 59562306a36Sopenharmony_ci struct rdma_ah_attr *ah_attr, 59662306a36Sopenharmony_ci struct ib_udata *udata) 59762306a36Sopenharmony_ci{ 59862306a36Sopenharmony_ci const struct ib_gid_attr *old_sgid_attr; 59962306a36Sopenharmony_ci struct ib_ah *ah; 60062306a36Sopenharmony_ci int err; 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci err = rdma_fill_sgid_attr(pd->device, ah_attr, &old_sgid_attr); 60362306a36Sopenharmony_ci if (err) 60462306a36Sopenharmony_ci return ERR_PTR(err); 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci if (ah_attr->type == RDMA_AH_ATTR_TYPE_ROCE) { 60762306a36Sopenharmony_ci err = ib_resolve_eth_dmac(pd->device, ah_attr); 60862306a36Sopenharmony_ci if (err) { 60962306a36Sopenharmony_ci ah = ERR_PTR(err); 61062306a36Sopenharmony_ci goto out; 61162306a36Sopenharmony_ci } 61262306a36Sopenharmony_ci } 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci ah = _rdma_create_ah(pd, ah_attr, RDMA_CREATE_AH_SLEEPABLE, 61562306a36Sopenharmony_ci udata, NULL); 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ciout: 61862306a36Sopenharmony_ci rdma_unfill_sgid_attr(ah_attr, old_sgid_attr); 61962306a36Sopenharmony_ci return ah; 62062306a36Sopenharmony_ci} 62162306a36Sopenharmony_ciEXPORT_SYMBOL(rdma_create_user_ah); 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ciint ib_get_rdma_header_version(const union rdma_network_hdr *hdr) 62462306a36Sopenharmony_ci{ 62562306a36Sopenharmony_ci const struct iphdr *ip4h = (struct iphdr *)&hdr->roce4grh; 62662306a36Sopenharmony_ci struct iphdr ip4h_checked; 62762306a36Sopenharmony_ci const struct ipv6hdr *ip6h = (struct ipv6hdr *)&hdr->ibgrh; 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci /* If it's IPv6, the version must be 6, otherwise, the first 63062306a36Sopenharmony_ci * 20 bytes (before the IPv4 header) are garbled. 63162306a36Sopenharmony_ci */ 63262306a36Sopenharmony_ci if (ip6h->version != 6) 63362306a36Sopenharmony_ci return (ip4h->version == 4) ? 4 : 0; 63462306a36Sopenharmony_ci /* version may be 6 or 4 because the first 20 bytes could be garbled */ 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci /* RoCE v2 requires no options, thus header length 63762306a36Sopenharmony_ci * must be 5 words 63862306a36Sopenharmony_ci */ 63962306a36Sopenharmony_ci if (ip4h->ihl != 5) 64062306a36Sopenharmony_ci return 6; 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci /* Verify checksum. 64362306a36Sopenharmony_ci * We can't write on scattered buffers so we need to copy to 64462306a36Sopenharmony_ci * temp buffer. 64562306a36Sopenharmony_ci */ 64662306a36Sopenharmony_ci memcpy(&ip4h_checked, ip4h, sizeof(ip4h_checked)); 64762306a36Sopenharmony_ci ip4h_checked.check = 0; 64862306a36Sopenharmony_ci ip4h_checked.check = ip_fast_csum((u8 *)&ip4h_checked, 5); 64962306a36Sopenharmony_ci /* if IPv4 header checksum is OK, believe it */ 65062306a36Sopenharmony_ci if (ip4h->check == ip4h_checked.check) 65162306a36Sopenharmony_ci return 4; 65262306a36Sopenharmony_ci return 6; 65362306a36Sopenharmony_ci} 65462306a36Sopenharmony_ciEXPORT_SYMBOL(ib_get_rdma_header_version); 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_cistatic enum rdma_network_type ib_get_net_type_by_grh(struct ib_device *device, 65762306a36Sopenharmony_ci u32 port_num, 65862306a36Sopenharmony_ci const struct ib_grh *grh) 65962306a36Sopenharmony_ci{ 66062306a36Sopenharmony_ci int grh_version; 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci if (rdma_protocol_ib(device, port_num)) 66362306a36Sopenharmony_ci return RDMA_NETWORK_IB; 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci grh_version = ib_get_rdma_header_version((union rdma_network_hdr *)grh); 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci if (grh_version == 4) 66862306a36Sopenharmony_ci return RDMA_NETWORK_IPV4; 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci if (grh->next_hdr == IPPROTO_UDP) 67162306a36Sopenharmony_ci return RDMA_NETWORK_IPV6; 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci return RDMA_NETWORK_ROCE_V1; 67462306a36Sopenharmony_ci} 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_cistruct find_gid_index_context { 67762306a36Sopenharmony_ci u16 vlan_id; 67862306a36Sopenharmony_ci enum ib_gid_type gid_type; 67962306a36Sopenharmony_ci}; 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_cistatic bool find_gid_index(const union ib_gid *gid, 68262306a36Sopenharmony_ci const struct ib_gid_attr *gid_attr, 68362306a36Sopenharmony_ci void *context) 68462306a36Sopenharmony_ci{ 68562306a36Sopenharmony_ci struct find_gid_index_context *ctx = context; 68662306a36Sopenharmony_ci u16 vlan_id = 0xffff; 68762306a36Sopenharmony_ci int ret; 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci if (ctx->gid_type != gid_attr->gid_type) 69062306a36Sopenharmony_ci return false; 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci ret = rdma_read_gid_l2_fields(gid_attr, &vlan_id, NULL); 69362306a36Sopenharmony_ci if (ret) 69462306a36Sopenharmony_ci return false; 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci return ctx->vlan_id == vlan_id; 69762306a36Sopenharmony_ci} 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_cistatic const struct ib_gid_attr * 70062306a36Sopenharmony_ciget_sgid_attr_from_eth(struct ib_device *device, u32 port_num, 70162306a36Sopenharmony_ci u16 vlan_id, const union ib_gid *sgid, 70262306a36Sopenharmony_ci enum ib_gid_type gid_type) 70362306a36Sopenharmony_ci{ 70462306a36Sopenharmony_ci struct find_gid_index_context context = {.vlan_id = vlan_id, 70562306a36Sopenharmony_ci .gid_type = gid_type}; 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_ci return rdma_find_gid_by_filter(device, sgid, port_num, find_gid_index, 70862306a36Sopenharmony_ci &context); 70962306a36Sopenharmony_ci} 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ciint ib_get_gids_from_rdma_hdr(const union rdma_network_hdr *hdr, 71262306a36Sopenharmony_ci enum rdma_network_type net_type, 71362306a36Sopenharmony_ci union ib_gid *sgid, union ib_gid *dgid) 71462306a36Sopenharmony_ci{ 71562306a36Sopenharmony_ci struct sockaddr_in src_in; 71662306a36Sopenharmony_ci struct sockaddr_in dst_in; 71762306a36Sopenharmony_ci __be32 src_saddr, dst_saddr; 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ci if (!sgid || !dgid) 72062306a36Sopenharmony_ci return -EINVAL; 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci if (net_type == RDMA_NETWORK_IPV4) { 72362306a36Sopenharmony_ci memcpy(&src_in.sin_addr.s_addr, 72462306a36Sopenharmony_ci &hdr->roce4grh.saddr, 4); 72562306a36Sopenharmony_ci memcpy(&dst_in.sin_addr.s_addr, 72662306a36Sopenharmony_ci &hdr->roce4grh.daddr, 4); 72762306a36Sopenharmony_ci src_saddr = src_in.sin_addr.s_addr; 72862306a36Sopenharmony_ci dst_saddr = dst_in.sin_addr.s_addr; 72962306a36Sopenharmony_ci ipv6_addr_set_v4mapped(src_saddr, 73062306a36Sopenharmony_ci (struct in6_addr *)sgid); 73162306a36Sopenharmony_ci ipv6_addr_set_v4mapped(dst_saddr, 73262306a36Sopenharmony_ci (struct in6_addr *)dgid); 73362306a36Sopenharmony_ci return 0; 73462306a36Sopenharmony_ci } else if (net_type == RDMA_NETWORK_IPV6 || 73562306a36Sopenharmony_ci net_type == RDMA_NETWORK_IB || RDMA_NETWORK_ROCE_V1) { 73662306a36Sopenharmony_ci *dgid = hdr->ibgrh.dgid; 73762306a36Sopenharmony_ci *sgid = hdr->ibgrh.sgid; 73862306a36Sopenharmony_ci return 0; 73962306a36Sopenharmony_ci } else { 74062306a36Sopenharmony_ci return -EINVAL; 74162306a36Sopenharmony_ci } 74262306a36Sopenharmony_ci} 74362306a36Sopenharmony_ciEXPORT_SYMBOL(ib_get_gids_from_rdma_hdr); 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_ci/* Resolve destination mac address and hop limit for unicast destination 74662306a36Sopenharmony_ci * GID entry, considering the source GID entry as well. 74762306a36Sopenharmony_ci * ah_attribute must have have valid port_num, sgid_index. 74862306a36Sopenharmony_ci */ 74962306a36Sopenharmony_cistatic int ib_resolve_unicast_gid_dmac(struct ib_device *device, 75062306a36Sopenharmony_ci struct rdma_ah_attr *ah_attr) 75162306a36Sopenharmony_ci{ 75262306a36Sopenharmony_ci struct ib_global_route *grh = rdma_ah_retrieve_grh(ah_attr); 75362306a36Sopenharmony_ci const struct ib_gid_attr *sgid_attr = grh->sgid_attr; 75462306a36Sopenharmony_ci int hop_limit = 0xff; 75562306a36Sopenharmony_ci int ret = 0; 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_ci /* If destination is link local and source GID is RoCEv1, 75862306a36Sopenharmony_ci * IP stack is not used. 75962306a36Sopenharmony_ci */ 76062306a36Sopenharmony_ci if (rdma_link_local_addr((struct in6_addr *)grh->dgid.raw) && 76162306a36Sopenharmony_ci sgid_attr->gid_type == IB_GID_TYPE_ROCE) { 76262306a36Sopenharmony_ci rdma_get_ll_mac((struct in6_addr *)grh->dgid.raw, 76362306a36Sopenharmony_ci ah_attr->roce.dmac); 76462306a36Sopenharmony_ci return ret; 76562306a36Sopenharmony_ci } 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_ci ret = rdma_addr_find_l2_eth_by_grh(&sgid_attr->gid, &grh->dgid, 76862306a36Sopenharmony_ci ah_attr->roce.dmac, 76962306a36Sopenharmony_ci sgid_attr, &hop_limit); 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci grh->hop_limit = hop_limit; 77262306a36Sopenharmony_ci return ret; 77362306a36Sopenharmony_ci} 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_ci/* 77662306a36Sopenharmony_ci * This function initializes address handle attributes from the incoming packet. 77762306a36Sopenharmony_ci * Incoming packet has dgid of the receiver node on which this code is 77862306a36Sopenharmony_ci * getting executed and, sgid contains the GID of the sender. 77962306a36Sopenharmony_ci * 78062306a36Sopenharmony_ci * When resolving mac address of destination, the arrived dgid is used 78162306a36Sopenharmony_ci * as sgid and, sgid is used as dgid because sgid contains destinations 78262306a36Sopenharmony_ci * GID whom to respond to. 78362306a36Sopenharmony_ci * 78462306a36Sopenharmony_ci * On success the caller is responsible to call rdma_destroy_ah_attr on the 78562306a36Sopenharmony_ci * attr. 78662306a36Sopenharmony_ci */ 78762306a36Sopenharmony_ciint ib_init_ah_attr_from_wc(struct ib_device *device, u32 port_num, 78862306a36Sopenharmony_ci const struct ib_wc *wc, const struct ib_grh *grh, 78962306a36Sopenharmony_ci struct rdma_ah_attr *ah_attr) 79062306a36Sopenharmony_ci{ 79162306a36Sopenharmony_ci u32 flow_class; 79262306a36Sopenharmony_ci int ret; 79362306a36Sopenharmony_ci enum rdma_network_type net_type = RDMA_NETWORK_IB; 79462306a36Sopenharmony_ci enum ib_gid_type gid_type = IB_GID_TYPE_IB; 79562306a36Sopenharmony_ci const struct ib_gid_attr *sgid_attr; 79662306a36Sopenharmony_ci int hoplimit = 0xff; 79762306a36Sopenharmony_ci union ib_gid dgid; 79862306a36Sopenharmony_ci union ib_gid sgid; 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_ci might_sleep(); 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_ci memset(ah_attr, 0, sizeof *ah_attr); 80362306a36Sopenharmony_ci ah_attr->type = rdma_ah_find_type(device, port_num); 80462306a36Sopenharmony_ci if (rdma_cap_eth_ah(device, port_num)) { 80562306a36Sopenharmony_ci if (wc->wc_flags & IB_WC_WITH_NETWORK_HDR_TYPE) 80662306a36Sopenharmony_ci net_type = wc->network_hdr_type; 80762306a36Sopenharmony_ci else 80862306a36Sopenharmony_ci net_type = ib_get_net_type_by_grh(device, port_num, grh); 80962306a36Sopenharmony_ci gid_type = ib_network_to_gid_type(net_type); 81062306a36Sopenharmony_ci } 81162306a36Sopenharmony_ci ret = ib_get_gids_from_rdma_hdr((union rdma_network_hdr *)grh, net_type, 81262306a36Sopenharmony_ci &sgid, &dgid); 81362306a36Sopenharmony_ci if (ret) 81462306a36Sopenharmony_ci return ret; 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_ci rdma_ah_set_sl(ah_attr, wc->sl); 81762306a36Sopenharmony_ci rdma_ah_set_port_num(ah_attr, port_num); 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_ci if (rdma_protocol_roce(device, port_num)) { 82062306a36Sopenharmony_ci u16 vlan_id = wc->wc_flags & IB_WC_WITH_VLAN ? 82162306a36Sopenharmony_ci wc->vlan_id : 0xffff; 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_ci if (!(wc->wc_flags & IB_WC_GRH)) 82462306a36Sopenharmony_ci return -EPROTOTYPE; 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci sgid_attr = get_sgid_attr_from_eth(device, port_num, 82762306a36Sopenharmony_ci vlan_id, &dgid, 82862306a36Sopenharmony_ci gid_type); 82962306a36Sopenharmony_ci if (IS_ERR(sgid_attr)) 83062306a36Sopenharmony_ci return PTR_ERR(sgid_attr); 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_ci flow_class = be32_to_cpu(grh->version_tclass_flow); 83362306a36Sopenharmony_ci rdma_move_grh_sgid_attr(ah_attr, 83462306a36Sopenharmony_ci &sgid, 83562306a36Sopenharmony_ci flow_class & 0xFFFFF, 83662306a36Sopenharmony_ci hoplimit, 83762306a36Sopenharmony_ci (flow_class >> 20) & 0xFF, 83862306a36Sopenharmony_ci sgid_attr); 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci ret = ib_resolve_unicast_gid_dmac(device, ah_attr); 84162306a36Sopenharmony_ci if (ret) 84262306a36Sopenharmony_ci rdma_destroy_ah_attr(ah_attr); 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_ci return ret; 84562306a36Sopenharmony_ci } else { 84662306a36Sopenharmony_ci rdma_ah_set_dlid(ah_attr, wc->slid); 84762306a36Sopenharmony_ci rdma_ah_set_path_bits(ah_attr, wc->dlid_path_bits); 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_ci if ((wc->wc_flags & IB_WC_GRH) == 0) 85062306a36Sopenharmony_ci return 0; 85162306a36Sopenharmony_ci 85262306a36Sopenharmony_ci if (dgid.global.interface_id != 85362306a36Sopenharmony_ci cpu_to_be64(IB_SA_WELL_KNOWN_GUID)) { 85462306a36Sopenharmony_ci sgid_attr = rdma_find_gid_by_port( 85562306a36Sopenharmony_ci device, &dgid, IB_GID_TYPE_IB, port_num, NULL); 85662306a36Sopenharmony_ci } else 85762306a36Sopenharmony_ci sgid_attr = rdma_get_gid_attr(device, port_num, 0); 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_ci if (IS_ERR(sgid_attr)) 86062306a36Sopenharmony_ci return PTR_ERR(sgid_attr); 86162306a36Sopenharmony_ci flow_class = be32_to_cpu(grh->version_tclass_flow); 86262306a36Sopenharmony_ci rdma_move_grh_sgid_attr(ah_attr, 86362306a36Sopenharmony_ci &sgid, 86462306a36Sopenharmony_ci flow_class & 0xFFFFF, 86562306a36Sopenharmony_ci hoplimit, 86662306a36Sopenharmony_ci (flow_class >> 20) & 0xFF, 86762306a36Sopenharmony_ci sgid_attr); 86862306a36Sopenharmony_ci 86962306a36Sopenharmony_ci return 0; 87062306a36Sopenharmony_ci } 87162306a36Sopenharmony_ci} 87262306a36Sopenharmony_ciEXPORT_SYMBOL(ib_init_ah_attr_from_wc); 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_ci/** 87562306a36Sopenharmony_ci * rdma_move_grh_sgid_attr - Sets the sgid attribute of GRH, taking ownership 87662306a36Sopenharmony_ci * of the reference 87762306a36Sopenharmony_ci * 87862306a36Sopenharmony_ci * @attr: Pointer to AH attribute structure 87962306a36Sopenharmony_ci * @dgid: Destination GID 88062306a36Sopenharmony_ci * @flow_label: Flow label 88162306a36Sopenharmony_ci * @hop_limit: Hop limit 88262306a36Sopenharmony_ci * @traffic_class: traffic class 88362306a36Sopenharmony_ci * @sgid_attr: Pointer to SGID attribute 88462306a36Sopenharmony_ci * 88562306a36Sopenharmony_ci * This takes ownership of the sgid_attr reference. The caller must ensure 88662306a36Sopenharmony_ci * rdma_destroy_ah_attr() is called before destroying the rdma_ah_attr after 88762306a36Sopenharmony_ci * calling this function. 88862306a36Sopenharmony_ci */ 88962306a36Sopenharmony_civoid rdma_move_grh_sgid_attr(struct rdma_ah_attr *attr, union ib_gid *dgid, 89062306a36Sopenharmony_ci u32 flow_label, u8 hop_limit, u8 traffic_class, 89162306a36Sopenharmony_ci const struct ib_gid_attr *sgid_attr) 89262306a36Sopenharmony_ci{ 89362306a36Sopenharmony_ci rdma_ah_set_grh(attr, dgid, flow_label, sgid_attr->index, hop_limit, 89462306a36Sopenharmony_ci traffic_class); 89562306a36Sopenharmony_ci attr->grh.sgid_attr = sgid_attr; 89662306a36Sopenharmony_ci} 89762306a36Sopenharmony_ciEXPORT_SYMBOL(rdma_move_grh_sgid_attr); 89862306a36Sopenharmony_ci 89962306a36Sopenharmony_ci/** 90062306a36Sopenharmony_ci * rdma_destroy_ah_attr - Release reference to SGID attribute of 90162306a36Sopenharmony_ci * ah attribute. 90262306a36Sopenharmony_ci * @ah_attr: Pointer to ah attribute 90362306a36Sopenharmony_ci * 90462306a36Sopenharmony_ci * Release reference to the SGID attribute of the ah attribute if it is 90562306a36Sopenharmony_ci * non NULL. It is safe to call this multiple times, and safe to call it on 90662306a36Sopenharmony_ci * a zero initialized ah_attr. 90762306a36Sopenharmony_ci */ 90862306a36Sopenharmony_civoid rdma_destroy_ah_attr(struct rdma_ah_attr *ah_attr) 90962306a36Sopenharmony_ci{ 91062306a36Sopenharmony_ci if (ah_attr->grh.sgid_attr) { 91162306a36Sopenharmony_ci rdma_put_gid_attr(ah_attr->grh.sgid_attr); 91262306a36Sopenharmony_ci ah_attr->grh.sgid_attr = NULL; 91362306a36Sopenharmony_ci } 91462306a36Sopenharmony_ci} 91562306a36Sopenharmony_ciEXPORT_SYMBOL(rdma_destroy_ah_attr); 91662306a36Sopenharmony_ci 91762306a36Sopenharmony_cistruct ib_ah *ib_create_ah_from_wc(struct ib_pd *pd, const struct ib_wc *wc, 91862306a36Sopenharmony_ci const struct ib_grh *grh, u32 port_num) 91962306a36Sopenharmony_ci{ 92062306a36Sopenharmony_ci struct rdma_ah_attr ah_attr; 92162306a36Sopenharmony_ci struct ib_ah *ah; 92262306a36Sopenharmony_ci int ret; 92362306a36Sopenharmony_ci 92462306a36Sopenharmony_ci ret = ib_init_ah_attr_from_wc(pd->device, port_num, wc, grh, &ah_attr); 92562306a36Sopenharmony_ci if (ret) 92662306a36Sopenharmony_ci return ERR_PTR(ret); 92762306a36Sopenharmony_ci 92862306a36Sopenharmony_ci ah = rdma_create_ah(pd, &ah_attr, RDMA_CREATE_AH_SLEEPABLE); 92962306a36Sopenharmony_ci 93062306a36Sopenharmony_ci rdma_destroy_ah_attr(&ah_attr); 93162306a36Sopenharmony_ci return ah; 93262306a36Sopenharmony_ci} 93362306a36Sopenharmony_ciEXPORT_SYMBOL(ib_create_ah_from_wc); 93462306a36Sopenharmony_ci 93562306a36Sopenharmony_ciint rdma_modify_ah(struct ib_ah *ah, struct rdma_ah_attr *ah_attr) 93662306a36Sopenharmony_ci{ 93762306a36Sopenharmony_ci const struct ib_gid_attr *old_sgid_attr; 93862306a36Sopenharmony_ci int ret; 93962306a36Sopenharmony_ci 94062306a36Sopenharmony_ci if (ah->type != ah_attr->type) 94162306a36Sopenharmony_ci return -EINVAL; 94262306a36Sopenharmony_ci 94362306a36Sopenharmony_ci ret = rdma_fill_sgid_attr(ah->device, ah_attr, &old_sgid_attr); 94462306a36Sopenharmony_ci if (ret) 94562306a36Sopenharmony_ci return ret; 94662306a36Sopenharmony_ci 94762306a36Sopenharmony_ci ret = ah->device->ops.modify_ah ? 94862306a36Sopenharmony_ci ah->device->ops.modify_ah(ah, ah_attr) : 94962306a36Sopenharmony_ci -EOPNOTSUPP; 95062306a36Sopenharmony_ci 95162306a36Sopenharmony_ci ah->sgid_attr = rdma_update_sgid_attr(ah_attr, ah->sgid_attr); 95262306a36Sopenharmony_ci rdma_unfill_sgid_attr(ah_attr, old_sgid_attr); 95362306a36Sopenharmony_ci return ret; 95462306a36Sopenharmony_ci} 95562306a36Sopenharmony_ciEXPORT_SYMBOL(rdma_modify_ah); 95662306a36Sopenharmony_ci 95762306a36Sopenharmony_ciint rdma_query_ah(struct ib_ah *ah, struct rdma_ah_attr *ah_attr) 95862306a36Sopenharmony_ci{ 95962306a36Sopenharmony_ci ah_attr->grh.sgid_attr = NULL; 96062306a36Sopenharmony_ci 96162306a36Sopenharmony_ci return ah->device->ops.query_ah ? 96262306a36Sopenharmony_ci ah->device->ops.query_ah(ah, ah_attr) : 96362306a36Sopenharmony_ci -EOPNOTSUPP; 96462306a36Sopenharmony_ci} 96562306a36Sopenharmony_ciEXPORT_SYMBOL(rdma_query_ah); 96662306a36Sopenharmony_ci 96762306a36Sopenharmony_ciint rdma_destroy_ah_user(struct ib_ah *ah, u32 flags, struct ib_udata *udata) 96862306a36Sopenharmony_ci{ 96962306a36Sopenharmony_ci const struct ib_gid_attr *sgid_attr = ah->sgid_attr; 97062306a36Sopenharmony_ci struct ib_pd *pd; 97162306a36Sopenharmony_ci int ret; 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_ci might_sleep_if(flags & RDMA_DESTROY_AH_SLEEPABLE); 97462306a36Sopenharmony_ci 97562306a36Sopenharmony_ci pd = ah->pd; 97662306a36Sopenharmony_ci 97762306a36Sopenharmony_ci ret = ah->device->ops.destroy_ah(ah, flags); 97862306a36Sopenharmony_ci if (ret) 97962306a36Sopenharmony_ci return ret; 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_ci atomic_dec(&pd->usecnt); 98262306a36Sopenharmony_ci if (sgid_attr) 98362306a36Sopenharmony_ci rdma_put_gid_attr(sgid_attr); 98462306a36Sopenharmony_ci 98562306a36Sopenharmony_ci kfree(ah); 98662306a36Sopenharmony_ci return ret; 98762306a36Sopenharmony_ci} 98862306a36Sopenharmony_ciEXPORT_SYMBOL(rdma_destroy_ah_user); 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_ci/* Shared receive queues */ 99162306a36Sopenharmony_ci 99262306a36Sopenharmony_ci/** 99362306a36Sopenharmony_ci * ib_create_srq_user - Creates a SRQ associated with the specified protection 99462306a36Sopenharmony_ci * domain. 99562306a36Sopenharmony_ci * @pd: The protection domain associated with the SRQ. 99662306a36Sopenharmony_ci * @srq_init_attr: A list of initial attributes required to create the 99762306a36Sopenharmony_ci * SRQ. If SRQ creation succeeds, then the attributes are updated to 99862306a36Sopenharmony_ci * the actual capabilities of the created SRQ. 99962306a36Sopenharmony_ci * @uobject: uobject pointer if this is not a kernel SRQ 100062306a36Sopenharmony_ci * @udata: udata pointer if this is not a kernel SRQ 100162306a36Sopenharmony_ci * 100262306a36Sopenharmony_ci * srq_attr->max_wr and srq_attr->max_sge are read the determine the 100362306a36Sopenharmony_ci * requested size of the SRQ, and set to the actual values allocated 100462306a36Sopenharmony_ci * on return. If ib_create_srq() succeeds, then max_wr and max_sge 100562306a36Sopenharmony_ci * will always be at least as large as the requested values. 100662306a36Sopenharmony_ci */ 100762306a36Sopenharmony_cistruct ib_srq *ib_create_srq_user(struct ib_pd *pd, 100862306a36Sopenharmony_ci struct ib_srq_init_attr *srq_init_attr, 100962306a36Sopenharmony_ci struct ib_usrq_object *uobject, 101062306a36Sopenharmony_ci struct ib_udata *udata) 101162306a36Sopenharmony_ci{ 101262306a36Sopenharmony_ci struct ib_srq *srq; 101362306a36Sopenharmony_ci int ret; 101462306a36Sopenharmony_ci 101562306a36Sopenharmony_ci srq = rdma_zalloc_drv_obj(pd->device, ib_srq); 101662306a36Sopenharmony_ci if (!srq) 101762306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 101862306a36Sopenharmony_ci 101962306a36Sopenharmony_ci srq->device = pd->device; 102062306a36Sopenharmony_ci srq->pd = pd; 102162306a36Sopenharmony_ci srq->event_handler = srq_init_attr->event_handler; 102262306a36Sopenharmony_ci srq->srq_context = srq_init_attr->srq_context; 102362306a36Sopenharmony_ci srq->srq_type = srq_init_attr->srq_type; 102462306a36Sopenharmony_ci srq->uobject = uobject; 102562306a36Sopenharmony_ci 102662306a36Sopenharmony_ci if (ib_srq_has_cq(srq->srq_type)) { 102762306a36Sopenharmony_ci srq->ext.cq = srq_init_attr->ext.cq; 102862306a36Sopenharmony_ci atomic_inc(&srq->ext.cq->usecnt); 102962306a36Sopenharmony_ci } 103062306a36Sopenharmony_ci if (srq->srq_type == IB_SRQT_XRC) { 103162306a36Sopenharmony_ci srq->ext.xrc.xrcd = srq_init_attr->ext.xrc.xrcd; 103262306a36Sopenharmony_ci if (srq->ext.xrc.xrcd) 103362306a36Sopenharmony_ci atomic_inc(&srq->ext.xrc.xrcd->usecnt); 103462306a36Sopenharmony_ci } 103562306a36Sopenharmony_ci atomic_inc(&pd->usecnt); 103662306a36Sopenharmony_ci 103762306a36Sopenharmony_ci rdma_restrack_new(&srq->res, RDMA_RESTRACK_SRQ); 103862306a36Sopenharmony_ci rdma_restrack_parent_name(&srq->res, &pd->res); 103962306a36Sopenharmony_ci 104062306a36Sopenharmony_ci ret = pd->device->ops.create_srq(srq, srq_init_attr, udata); 104162306a36Sopenharmony_ci if (ret) { 104262306a36Sopenharmony_ci rdma_restrack_put(&srq->res); 104362306a36Sopenharmony_ci atomic_dec(&pd->usecnt); 104462306a36Sopenharmony_ci if (srq->srq_type == IB_SRQT_XRC && srq->ext.xrc.xrcd) 104562306a36Sopenharmony_ci atomic_dec(&srq->ext.xrc.xrcd->usecnt); 104662306a36Sopenharmony_ci if (ib_srq_has_cq(srq->srq_type)) 104762306a36Sopenharmony_ci atomic_dec(&srq->ext.cq->usecnt); 104862306a36Sopenharmony_ci kfree(srq); 104962306a36Sopenharmony_ci return ERR_PTR(ret); 105062306a36Sopenharmony_ci } 105162306a36Sopenharmony_ci 105262306a36Sopenharmony_ci rdma_restrack_add(&srq->res); 105362306a36Sopenharmony_ci 105462306a36Sopenharmony_ci return srq; 105562306a36Sopenharmony_ci} 105662306a36Sopenharmony_ciEXPORT_SYMBOL(ib_create_srq_user); 105762306a36Sopenharmony_ci 105862306a36Sopenharmony_ciint ib_modify_srq(struct ib_srq *srq, 105962306a36Sopenharmony_ci struct ib_srq_attr *srq_attr, 106062306a36Sopenharmony_ci enum ib_srq_attr_mask srq_attr_mask) 106162306a36Sopenharmony_ci{ 106262306a36Sopenharmony_ci return srq->device->ops.modify_srq ? 106362306a36Sopenharmony_ci srq->device->ops.modify_srq(srq, srq_attr, srq_attr_mask, 106462306a36Sopenharmony_ci NULL) : -EOPNOTSUPP; 106562306a36Sopenharmony_ci} 106662306a36Sopenharmony_ciEXPORT_SYMBOL(ib_modify_srq); 106762306a36Sopenharmony_ci 106862306a36Sopenharmony_ciint ib_query_srq(struct ib_srq *srq, 106962306a36Sopenharmony_ci struct ib_srq_attr *srq_attr) 107062306a36Sopenharmony_ci{ 107162306a36Sopenharmony_ci return srq->device->ops.query_srq ? 107262306a36Sopenharmony_ci srq->device->ops.query_srq(srq, srq_attr) : -EOPNOTSUPP; 107362306a36Sopenharmony_ci} 107462306a36Sopenharmony_ciEXPORT_SYMBOL(ib_query_srq); 107562306a36Sopenharmony_ci 107662306a36Sopenharmony_ciint ib_destroy_srq_user(struct ib_srq *srq, struct ib_udata *udata) 107762306a36Sopenharmony_ci{ 107862306a36Sopenharmony_ci int ret; 107962306a36Sopenharmony_ci 108062306a36Sopenharmony_ci if (atomic_read(&srq->usecnt)) 108162306a36Sopenharmony_ci return -EBUSY; 108262306a36Sopenharmony_ci 108362306a36Sopenharmony_ci ret = srq->device->ops.destroy_srq(srq, udata); 108462306a36Sopenharmony_ci if (ret) 108562306a36Sopenharmony_ci return ret; 108662306a36Sopenharmony_ci 108762306a36Sopenharmony_ci atomic_dec(&srq->pd->usecnt); 108862306a36Sopenharmony_ci if (srq->srq_type == IB_SRQT_XRC && srq->ext.xrc.xrcd) 108962306a36Sopenharmony_ci atomic_dec(&srq->ext.xrc.xrcd->usecnt); 109062306a36Sopenharmony_ci if (ib_srq_has_cq(srq->srq_type)) 109162306a36Sopenharmony_ci atomic_dec(&srq->ext.cq->usecnt); 109262306a36Sopenharmony_ci rdma_restrack_del(&srq->res); 109362306a36Sopenharmony_ci kfree(srq); 109462306a36Sopenharmony_ci 109562306a36Sopenharmony_ci return ret; 109662306a36Sopenharmony_ci} 109762306a36Sopenharmony_ciEXPORT_SYMBOL(ib_destroy_srq_user); 109862306a36Sopenharmony_ci 109962306a36Sopenharmony_ci/* Queue pairs */ 110062306a36Sopenharmony_ci 110162306a36Sopenharmony_cistatic void __ib_shared_qp_event_handler(struct ib_event *event, void *context) 110262306a36Sopenharmony_ci{ 110362306a36Sopenharmony_ci struct ib_qp *qp = context; 110462306a36Sopenharmony_ci unsigned long flags; 110562306a36Sopenharmony_ci 110662306a36Sopenharmony_ci spin_lock_irqsave(&qp->device->qp_open_list_lock, flags); 110762306a36Sopenharmony_ci list_for_each_entry(event->element.qp, &qp->open_list, open_list) 110862306a36Sopenharmony_ci if (event->element.qp->event_handler) 110962306a36Sopenharmony_ci event->element.qp->event_handler(event, event->element.qp->qp_context); 111062306a36Sopenharmony_ci spin_unlock_irqrestore(&qp->device->qp_open_list_lock, flags); 111162306a36Sopenharmony_ci} 111262306a36Sopenharmony_ci 111362306a36Sopenharmony_cistatic struct ib_qp *__ib_open_qp(struct ib_qp *real_qp, 111462306a36Sopenharmony_ci void (*event_handler)(struct ib_event *, void *), 111562306a36Sopenharmony_ci void *qp_context) 111662306a36Sopenharmony_ci{ 111762306a36Sopenharmony_ci struct ib_qp *qp; 111862306a36Sopenharmony_ci unsigned long flags; 111962306a36Sopenharmony_ci int err; 112062306a36Sopenharmony_ci 112162306a36Sopenharmony_ci qp = kzalloc(sizeof *qp, GFP_KERNEL); 112262306a36Sopenharmony_ci if (!qp) 112362306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 112462306a36Sopenharmony_ci 112562306a36Sopenharmony_ci qp->real_qp = real_qp; 112662306a36Sopenharmony_ci err = ib_open_shared_qp_security(qp, real_qp->device); 112762306a36Sopenharmony_ci if (err) { 112862306a36Sopenharmony_ci kfree(qp); 112962306a36Sopenharmony_ci return ERR_PTR(err); 113062306a36Sopenharmony_ci } 113162306a36Sopenharmony_ci 113262306a36Sopenharmony_ci qp->real_qp = real_qp; 113362306a36Sopenharmony_ci atomic_inc(&real_qp->usecnt); 113462306a36Sopenharmony_ci qp->device = real_qp->device; 113562306a36Sopenharmony_ci qp->event_handler = event_handler; 113662306a36Sopenharmony_ci qp->qp_context = qp_context; 113762306a36Sopenharmony_ci qp->qp_num = real_qp->qp_num; 113862306a36Sopenharmony_ci qp->qp_type = real_qp->qp_type; 113962306a36Sopenharmony_ci 114062306a36Sopenharmony_ci spin_lock_irqsave(&real_qp->device->qp_open_list_lock, flags); 114162306a36Sopenharmony_ci list_add(&qp->open_list, &real_qp->open_list); 114262306a36Sopenharmony_ci spin_unlock_irqrestore(&real_qp->device->qp_open_list_lock, flags); 114362306a36Sopenharmony_ci 114462306a36Sopenharmony_ci return qp; 114562306a36Sopenharmony_ci} 114662306a36Sopenharmony_ci 114762306a36Sopenharmony_cistruct ib_qp *ib_open_qp(struct ib_xrcd *xrcd, 114862306a36Sopenharmony_ci struct ib_qp_open_attr *qp_open_attr) 114962306a36Sopenharmony_ci{ 115062306a36Sopenharmony_ci struct ib_qp *qp, *real_qp; 115162306a36Sopenharmony_ci 115262306a36Sopenharmony_ci if (qp_open_attr->qp_type != IB_QPT_XRC_TGT) 115362306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 115462306a36Sopenharmony_ci 115562306a36Sopenharmony_ci down_read(&xrcd->tgt_qps_rwsem); 115662306a36Sopenharmony_ci real_qp = xa_load(&xrcd->tgt_qps, qp_open_attr->qp_num); 115762306a36Sopenharmony_ci if (!real_qp) { 115862306a36Sopenharmony_ci up_read(&xrcd->tgt_qps_rwsem); 115962306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 116062306a36Sopenharmony_ci } 116162306a36Sopenharmony_ci qp = __ib_open_qp(real_qp, qp_open_attr->event_handler, 116262306a36Sopenharmony_ci qp_open_attr->qp_context); 116362306a36Sopenharmony_ci up_read(&xrcd->tgt_qps_rwsem); 116462306a36Sopenharmony_ci return qp; 116562306a36Sopenharmony_ci} 116662306a36Sopenharmony_ciEXPORT_SYMBOL(ib_open_qp); 116762306a36Sopenharmony_ci 116862306a36Sopenharmony_cistatic struct ib_qp *create_xrc_qp_user(struct ib_qp *qp, 116962306a36Sopenharmony_ci struct ib_qp_init_attr *qp_init_attr) 117062306a36Sopenharmony_ci{ 117162306a36Sopenharmony_ci struct ib_qp *real_qp = qp; 117262306a36Sopenharmony_ci int err; 117362306a36Sopenharmony_ci 117462306a36Sopenharmony_ci qp->event_handler = __ib_shared_qp_event_handler; 117562306a36Sopenharmony_ci qp->qp_context = qp; 117662306a36Sopenharmony_ci qp->pd = NULL; 117762306a36Sopenharmony_ci qp->send_cq = qp->recv_cq = NULL; 117862306a36Sopenharmony_ci qp->srq = NULL; 117962306a36Sopenharmony_ci qp->xrcd = qp_init_attr->xrcd; 118062306a36Sopenharmony_ci atomic_inc(&qp_init_attr->xrcd->usecnt); 118162306a36Sopenharmony_ci INIT_LIST_HEAD(&qp->open_list); 118262306a36Sopenharmony_ci 118362306a36Sopenharmony_ci qp = __ib_open_qp(real_qp, qp_init_attr->event_handler, 118462306a36Sopenharmony_ci qp_init_attr->qp_context); 118562306a36Sopenharmony_ci if (IS_ERR(qp)) 118662306a36Sopenharmony_ci return qp; 118762306a36Sopenharmony_ci 118862306a36Sopenharmony_ci err = xa_err(xa_store(&qp_init_attr->xrcd->tgt_qps, real_qp->qp_num, 118962306a36Sopenharmony_ci real_qp, GFP_KERNEL)); 119062306a36Sopenharmony_ci if (err) { 119162306a36Sopenharmony_ci ib_close_qp(qp); 119262306a36Sopenharmony_ci return ERR_PTR(err); 119362306a36Sopenharmony_ci } 119462306a36Sopenharmony_ci return qp; 119562306a36Sopenharmony_ci} 119662306a36Sopenharmony_ci 119762306a36Sopenharmony_cistatic struct ib_qp *create_qp(struct ib_device *dev, struct ib_pd *pd, 119862306a36Sopenharmony_ci struct ib_qp_init_attr *attr, 119962306a36Sopenharmony_ci struct ib_udata *udata, 120062306a36Sopenharmony_ci struct ib_uqp_object *uobj, const char *caller) 120162306a36Sopenharmony_ci{ 120262306a36Sopenharmony_ci struct ib_udata dummy = {}; 120362306a36Sopenharmony_ci struct ib_qp *qp; 120462306a36Sopenharmony_ci int ret; 120562306a36Sopenharmony_ci 120662306a36Sopenharmony_ci if (!dev->ops.create_qp) 120762306a36Sopenharmony_ci return ERR_PTR(-EOPNOTSUPP); 120862306a36Sopenharmony_ci 120962306a36Sopenharmony_ci qp = rdma_zalloc_drv_obj_numa(dev, ib_qp); 121062306a36Sopenharmony_ci if (!qp) 121162306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 121262306a36Sopenharmony_ci 121362306a36Sopenharmony_ci qp->device = dev; 121462306a36Sopenharmony_ci qp->pd = pd; 121562306a36Sopenharmony_ci qp->uobject = uobj; 121662306a36Sopenharmony_ci qp->real_qp = qp; 121762306a36Sopenharmony_ci 121862306a36Sopenharmony_ci qp->qp_type = attr->qp_type; 121962306a36Sopenharmony_ci qp->rwq_ind_tbl = attr->rwq_ind_tbl; 122062306a36Sopenharmony_ci qp->srq = attr->srq; 122162306a36Sopenharmony_ci qp->event_handler = attr->event_handler; 122262306a36Sopenharmony_ci qp->port = attr->port_num; 122362306a36Sopenharmony_ci qp->qp_context = attr->qp_context; 122462306a36Sopenharmony_ci 122562306a36Sopenharmony_ci spin_lock_init(&qp->mr_lock); 122662306a36Sopenharmony_ci INIT_LIST_HEAD(&qp->rdma_mrs); 122762306a36Sopenharmony_ci INIT_LIST_HEAD(&qp->sig_mrs); 122862306a36Sopenharmony_ci 122962306a36Sopenharmony_ci qp->send_cq = attr->send_cq; 123062306a36Sopenharmony_ci qp->recv_cq = attr->recv_cq; 123162306a36Sopenharmony_ci 123262306a36Sopenharmony_ci rdma_restrack_new(&qp->res, RDMA_RESTRACK_QP); 123362306a36Sopenharmony_ci WARN_ONCE(!udata && !caller, "Missing kernel QP owner"); 123462306a36Sopenharmony_ci rdma_restrack_set_name(&qp->res, udata ? NULL : caller); 123562306a36Sopenharmony_ci ret = dev->ops.create_qp(qp, attr, udata); 123662306a36Sopenharmony_ci if (ret) 123762306a36Sopenharmony_ci goto err_create; 123862306a36Sopenharmony_ci 123962306a36Sopenharmony_ci /* 124062306a36Sopenharmony_ci * TODO: The mlx4 internally overwrites send_cq and recv_cq. 124162306a36Sopenharmony_ci * Unfortunately, it is not an easy task to fix that driver. 124262306a36Sopenharmony_ci */ 124362306a36Sopenharmony_ci qp->send_cq = attr->send_cq; 124462306a36Sopenharmony_ci qp->recv_cq = attr->recv_cq; 124562306a36Sopenharmony_ci 124662306a36Sopenharmony_ci ret = ib_create_qp_security(qp, dev); 124762306a36Sopenharmony_ci if (ret) 124862306a36Sopenharmony_ci goto err_security; 124962306a36Sopenharmony_ci 125062306a36Sopenharmony_ci rdma_restrack_add(&qp->res); 125162306a36Sopenharmony_ci return qp; 125262306a36Sopenharmony_ci 125362306a36Sopenharmony_cierr_security: 125462306a36Sopenharmony_ci qp->device->ops.destroy_qp(qp, udata ? &dummy : NULL); 125562306a36Sopenharmony_cierr_create: 125662306a36Sopenharmony_ci rdma_restrack_put(&qp->res); 125762306a36Sopenharmony_ci kfree(qp); 125862306a36Sopenharmony_ci return ERR_PTR(ret); 125962306a36Sopenharmony_ci 126062306a36Sopenharmony_ci} 126162306a36Sopenharmony_ci 126262306a36Sopenharmony_ci/** 126362306a36Sopenharmony_ci * ib_create_qp_user - Creates a QP associated with the specified protection 126462306a36Sopenharmony_ci * domain. 126562306a36Sopenharmony_ci * @dev: IB device 126662306a36Sopenharmony_ci * @pd: The protection domain associated with the QP. 126762306a36Sopenharmony_ci * @attr: A list of initial attributes required to create the 126862306a36Sopenharmony_ci * QP. If QP creation succeeds, then the attributes are updated to 126962306a36Sopenharmony_ci * the actual capabilities of the created QP. 127062306a36Sopenharmony_ci * @udata: User data 127162306a36Sopenharmony_ci * @uobj: uverbs obect 127262306a36Sopenharmony_ci * @caller: caller's build-time module name 127362306a36Sopenharmony_ci */ 127462306a36Sopenharmony_cistruct ib_qp *ib_create_qp_user(struct ib_device *dev, struct ib_pd *pd, 127562306a36Sopenharmony_ci struct ib_qp_init_attr *attr, 127662306a36Sopenharmony_ci struct ib_udata *udata, 127762306a36Sopenharmony_ci struct ib_uqp_object *uobj, const char *caller) 127862306a36Sopenharmony_ci{ 127962306a36Sopenharmony_ci struct ib_qp *qp, *xrc_qp; 128062306a36Sopenharmony_ci 128162306a36Sopenharmony_ci if (attr->qp_type == IB_QPT_XRC_TGT) 128262306a36Sopenharmony_ci qp = create_qp(dev, pd, attr, NULL, NULL, caller); 128362306a36Sopenharmony_ci else 128462306a36Sopenharmony_ci qp = create_qp(dev, pd, attr, udata, uobj, NULL); 128562306a36Sopenharmony_ci if (attr->qp_type != IB_QPT_XRC_TGT || IS_ERR(qp)) 128662306a36Sopenharmony_ci return qp; 128762306a36Sopenharmony_ci 128862306a36Sopenharmony_ci xrc_qp = create_xrc_qp_user(qp, attr); 128962306a36Sopenharmony_ci if (IS_ERR(xrc_qp)) { 129062306a36Sopenharmony_ci ib_destroy_qp(qp); 129162306a36Sopenharmony_ci return xrc_qp; 129262306a36Sopenharmony_ci } 129362306a36Sopenharmony_ci 129462306a36Sopenharmony_ci xrc_qp->uobject = uobj; 129562306a36Sopenharmony_ci return xrc_qp; 129662306a36Sopenharmony_ci} 129762306a36Sopenharmony_ciEXPORT_SYMBOL(ib_create_qp_user); 129862306a36Sopenharmony_ci 129962306a36Sopenharmony_civoid ib_qp_usecnt_inc(struct ib_qp *qp) 130062306a36Sopenharmony_ci{ 130162306a36Sopenharmony_ci if (qp->pd) 130262306a36Sopenharmony_ci atomic_inc(&qp->pd->usecnt); 130362306a36Sopenharmony_ci if (qp->send_cq) 130462306a36Sopenharmony_ci atomic_inc(&qp->send_cq->usecnt); 130562306a36Sopenharmony_ci if (qp->recv_cq) 130662306a36Sopenharmony_ci atomic_inc(&qp->recv_cq->usecnt); 130762306a36Sopenharmony_ci if (qp->srq) 130862306a36Sopenharmony_ci atomic_inc(&qp->srq->usecnt); 130962306a36Sopenharmony_ci if (qp->rwq_ind_tbl) 131062306a36Sopenharmony_ci atomic_inc(&qp->rwq_ind_tbl->usecnt); 131162306a36Sopenharmony_ci} 131262306a36Sopenharmony_ciEXPORT_SYMBOL(ib_qp_usecnt_inc); 131362306a36Sopenharmony_ci 131462306a36Sopenharmony_civoid ib_qp_usecnt_dec(struct ib_qp *qp) 131562306a36Sopenharmony_ci{ 131662306a36Sopenharmony_ci if (qp->rwq_ind_tbl) 131762306a36Sopenharmony_ci atomic_dec(&qp->rwq_ind_tbl->usecnt); 131862306a36Sopenharmony_ci if (qp->srq) 131962306a36Sopenharmony_ci atomic_dec(&qp->srq->usecnt); 132062306a36Sopenharmony_ci if (qp->recv_cq) 132162306a36Sopenharmony_ci atomic_dec(&qp->recv_cq->usecnt); 132262306a36Sopenharmony_ci if (qp->send_cq) 132362306a36Sopenharmony_ci atomic_dec(&qp->send_cq->usecnt); 132462306a36Sopenharmony_ci if (qp->pd) 132562306a36Sopenharmony_ci atomic_dec(&qp->pd->usecnt); 132662306a36Sopenharmony_ci} 132762306a36Sopenharmony_ciEXPORT_SYMBOL(ib_qp_usecnt_dec); 132862306a36Sopenharmony_ci 132962306a36Sopenharmony_cistruct ib_qp *ib_create_qp_kernel(struct ib_pd *pd, 133062306a36Sopenharmony_ci struct ib_qp_init_attr *qp_init_attr, 133162306a36Sopenharmony_ci const char *caller) 133262306a36Sopenharmony_ci{ 133362306a36Sopenharmony_ci struct ib_device *device = pd->device; 133462306a36Sopenharmony_ci struct ib_qp *qp; 133562306a36Sopenharmony_ci int ret; 133662306a36Sopenharmony_ci 133762306a36Sopenharmony_ci /* 133862306a36Sopenharmony_ci * If the callers is using the RDMA API calculate the resources 133962306a36Sopenharmony_ci * needed for the RDMA READ/WRITE operations. 134062306a36Sopenharmony_ci * 134162306a36Sopenharmony_ci * Note that these callers need to pass in a port number. 134262306a36Sopenharmony_ci */ 134362306a36Sopenharmony_ci if (qp_init_attr->cap.max_rdma_ctxs) 134462306a36Sopenharmony_ci rdma_rw_init_qp(device, qp_init_attr); 134562306a36Sopenharmony_ci 134662306a36Sopenharmony_ci qp = create_qp(device, pd, qp_init_attr, NULL, NULL, caller); 134762306a36Sopenharmony_ci if (IS_ERR(qp)) 134862306a36Sopenharmony_ci return qp; 134962306a36Sopenharmony_ci 135062306a36Sopenharmony_ci ib_qp_usecnt_inc(qp); 135162306a36Sopenharmony_ci 135262306a36Sopenharmony_ci if (qp_init_attr->cap.max_rdma_ctxs) { 135362306a36Sopenharmony_ci ret = rdma_rw_init_mrs(qp, qp_init_attr); 135462306a36Sopenharmony_ci if (ret) 135562306a36Sopenharmony_ci goto err; 135662306a36Sopenharmony_ci } 135762306a36Sopenharmony_ci 135862306a36Sopenharmony_ci /* 135962306a36Sopenharmony_ci * Note: all hw drivers guarantee that max_send_sge is lower than 136062306a36Sopenharmony_ci * the device RDMA WRITE SGE limit but not all hw drivers ensure that 136162306a36Sopenharmony_ci * max_send_sge <= max_sge_rd. 136262306a36Sopenharmony_ci */ 136362306a36Sopenharmony_ci qp->max_write_sge = qp_init_attr->cap.max_send_sge; 136462306a36Sopenharmony_ci qp->max_read_sge = min_t(u32, qp_init_attr->cap.max_send_sge, 136562306a36Sopenharmony_ci device->attrs.max_sge_rd); 136662306a36Sopenharmony_ci if (qp_init_attr->create_flags & IB_QP_CREATE_INTEGRITY_EN) 136762306a36Sopenharmony_ci qp->integrity_en = true; 136862306a36Sopenharmony_ci 136962306a36Sopenharmony_ci return qp; 137062306a36Sopenharmony_ci 137162306a36Sopenharmony_cierr: 137262306a36Sopenharmony_ci ib_destroy_qp(qp); 137362306a36Sopenharmony_ci return ERR_PTR(ret); 137462306a36Sopenharmony_ci 137562306a36Sopenharmony_ci} 137662306a36Sopenharmony_ciEXPORT_SYMBOL(ib_create_qp_kernel); 137762306a36Sopenharmony_ci 137862306a36Sopenharmony_cistatic const struct { 137962306a36Sopenharmony_ci int valid; 138062306a36Sopenharmony_ci enum ib_qp_attr_mask req_param[IB_QPT_MAX]; 138162306a36Sopenharmony_ci enum ib_qp_attr_mask opt_param[IB_QPT_MAX]; 138262306a36Sopenharmony_ci} qp_state_table[IB_QPS_ERR + 1][IB_QPS_ERR + 1] = { 138362306a36Sopenharmony_ci [IB_QPS_RESET] = { 138462306a36Sopenharmony_ci [IB_QPS_RESET] = { .valid = 1 }, 138562306a36Sopenharmony_ci [IB_QPS_INIT] = { 138662306a36Sopenharmony_ci .valid = 1, 138762306a36Sopenharmony_ci .req_param = { 138862306a36Sopenharmony_ci [IB_QPT_UD] = (IB_QP_PKEY_INDEX | 138962306a36Sopenharmony_ci IB_QP_PORT | 139062306a36Sopenharmony_ci IB_QP_QKEY), 139162306a36Sopenharmony_ci [IB_QPT_RAW_PACKET] = IB_QP_PORT, 139262306a36Sopenharmony_ci [IB_QPT_UC] = (IB_QP_PKEY_INDEX | 139362306a36Sopenharmony_ci IB_QP_PORT | 139462306a36Sopenharmony_ci IB_QP_ACCESS_FLAGS), 139562306a36Sopenharmony_ci [IB_QPT_RC] = (IB_QP_PKEY_INDEX | 139662306a36Sopenharmony_ci IB_QP_PORT | 139762306a36Sopenharmony_ci IB_QP_ACCESS_FLAGS), 139862306a36Sopenharmony_ci [IB_QPT_XRC_INI] = (IB_QP_PKEY_INDEX | 139962306a36Sopenharmony_ci IB_QP_PORT | 140062306a36Sopenharmony_ci IB_QP_ACCESS_FLAGS), 140162306a36Sopenharmony_ci [IB_QPT_XRC_TGT] = (IB_QP_PKEY_INDEX | 140262306a36Sopenharmony_ci IB_QP_PORT | 140362306a36Sopenharmony_ci IB_QP_ACCESS_FLAGS), 140462306a36Sopenharmony_ci [IB_QPT_SMI] = (IB_QP_PKEY_INDEX | 140562306a36Sopenharmony_ci IB_QP_QKEY), 140662306a36Sopenharmony_ci [IB_QPT_GSI] = (IB_QP_PKEY_INDEX | 140762306a36Sopenharmony_ci IB_QP_QKEY), 140862306a36Sopenharmony_ci } 140962306a36Sopenharmony_ci }, 141062306a36Sopenharmony_ci }, 141162306a36Sopenharmony_ci [IB_QPS_INIT] = { 141262306a36Sopenharmony_ci [IB_QPS_RESET] = { .valid = 1 }, 141362306a36Sopenharmony_ci [IB_QPS_ERR] = { .valid = 1 }, 141462306a36Sopenharmony_ci [IB_QPS_INIT] = { 141562306a36Sopenharmony_ci .valid = 1, 141662306a36Sopenharmony_ci .opt_param = { 141762306a36Sopenharmony_ci [IB_QPT_UD] = (IB_QP_PKEY_INDEX | 141862306a36Sopenharmony_ci IB_QP_PORT | 141962306a36Sopenharmony_ci IB_QP_QKEY), 142062306a36Sopenharmony_ci [IB_QPT_UC] = (IB_QP_PKEY_INDEX | 142162306a36Sopenharmony_ci IB_QP_PORT | 142262306a36Sopenharmony_ci IB_QP_ACCESS_FLAGS), 142362306a36Sopenharmony_ci [IB_QPT_RC] = (IB_QP_PKEY_INDEX | 142462306a36Sopenharmony_ci IB_QP_PORT | 142562306a36Sopenharmony_ci IB_QP_ACCESS_FLAGS), 142662306a36Sopenharmony_ci [IB_QPT_XRC_INI] = (IB_QP_PKEY_INDEX | 142762306a36Sopenharmony_ci IB_QP_PORT | 142862306a36Sopenharmony_ci IB_QP_ACCESS_FLAGS), 142962306a36Sopenharmony_ci [IB_QPT_XRC_TGT] = (IB_QP_PKEY_INDEX | 143062306a36Sopenharmony_ci IB_QP_PORT | 143162306a36Sopenharmony_ci IB_QP_ACCESS_FLAGS), 143262306a36Sopenharmony_ci [IB_QPT_SMI] = (IB_QP_PKEY_INDEX | 143362306a36Sopenharmony_ci IB_QP_QKEY), 143462306a36Sopenharmony_ci [IB_QPT_GSI] = (IB_QP_PKEY_INDEX | 143562306a36Sopenharmony_ci IB_QP_QKEY), 143662306a36Sopenharmony_ci } 143762306a36Sopenharmony_ci }, 143862306a36Sopenharmony_ci [IB_QPS_RTR] = { 143962306a36Sopenharmony_ci .valid = 1, 144062306a36Sopenharmony_ci .req_param = { 144162306a36Sopenharmony_ci [IB_QPT_UC] = (IB_QP_AV | 144262306a36Sopenharmony_ci IB_QP_PATH_MTU | 144362306a36Sopenharmony_ci IB_QP_DEST_QPN | 144462306a36Sopenharmony_ci IB_QP_RQ_PSN), 144562306a36Sopenharmony_ci [IB_QPT_RC] = (IB_QP_AV | 144662306a36Sopenharmony_ci IB_QP_PATH_MTU | 144762306a36Sopenharmony_ci IB_QP_DEST_QPN | 144862306a36Sopenharmony_ci IB_QP_RQ_PSN | 144962306a36Sopenharmony_ci IB_QP_MAX_DEST_RD_ATOMIC | 145062306a36Sopenharmony_ci IB_QP_MIN_RNR_TIMER), 145162306a36Sopenharmony_ci [IB_QPT_XRC_INI] = (IB_QP_AV | 145262306a36Sopenharmony_ci IB_QP_PATH_MTU | 145362306a36Sopenharmony_ci IB_QP_DEST_QPN | 145462306a36Sopenharmony_ci IB_QP_RQ_PSN), 145562306a36Sopenharmony_ci [IB_QPT_XRC_TGT] = (IB_QP_AV | 145662306a36Sopenharmony_ci IB_QP_PATH_MTU | 145762306a36Sopenharmony_ci IB_QP_DEST_QPN | 145862306a36Sopenharmony_ci IB_QP_RQ_PSN | 145962306a36Sopenharmony_ci IB_QP_MAX_DEST_RD_ATOMIC | 146062306a36Sopenharmony_ci IB_QP_MIN_RNR_TIMER), 146162306a36Sopenharmony_ci }, 146262306a36Sopenharmony_ci .opt_param = { 146362306a36Sopenharmony_ci [IB_QPT_UD] = (IB_QP_PKEY_INDEX | 146462306a36Sopenharmony_ci IB_QP_QKEY), 146562306a36Sopenharmony_ci [IB_QPT_UC] = (IB_QP_ALT_PATH | 146662306a36Sopenharmony_ci IB_QP_ACCESS_FLAGS | 146762306a36Sopenharmony_ci IB_QP_PKEY_INDEX), 146862306a36Sopenharmony_ci [IB_QPT_RC] = (IB_QP_ALT_PATH | 146962306a36Sopenharmony_ci IB_QP_ACCESS_FLAGS | 147062306a36Sopenharmony_ci IB_QP_PKEY_INDEX), 147162306a36Sopenharmony_ci [IB_QPT_XRC_INI] = (IB_QP_ALT_PATH | 147262306a36Sopenharmony_ci IB_QP_ACCESS_FLAGS | 147362306a36Sopenharmony_ci IB_QP_PKEY_INDEX), 147462306a36Sopenharmony_ci [IB_QPT_XRC_TGT] = (IB_QP_ALT_PATH | 147562306a36Sopenharmony_ci IB_QP_ACCESS_FLAGS | 147662306a36Sopenharmony_ci IB_QP_PKEY_INDEX), 147762306a36Sopenharmony_ci [IB_QPT_SMI] = (IB_QP_PKEY_INDEX | 147862306a36Sopenharmony_ci IB_QP_QKEY), 147962306a36Sopenharmony_ci [IB_QPT_GSI] = (IB_QP_PKEY_INDEX | 148062306a36Sopenharmony_ci IB_QP_QKEY), 148162306a36Sopenharmony_ci }, 148262306a36Sopenharmony_ci }, 148362306a36Sopenharmony_ci }, 148462306a36Sopenharmony_ci [IB_QPS_RTR] = { 148562306a36Sopenharmony_ci [IB_QPS_RESET] = { .valid = 1 }, 148662306a36Sopenharmony_ci [IB_QPS_ERR] = { .valid = 1 }, 148762306a36Sopenharmony_ci [IB_QPS_RTS] = { 148862306a36Sopenharmony_ci .valid = 1, 148962306a36Sopenharmony_ci .req_param = { 149062306a36Sopenharmony_ci [IB_QPT_UD] = IB_QP_SQ_PSN, 149162306a36Sopenharmony_ci [IB_QPT_UC] = IB_QP_SQ_PSN, 149262306a36Sopenharmony_ci [IB_QPT_RC] = (IB_QP_TIMEOUT | 149362306a36Sopenharmony_ci IB_QP_RETRY_CNT | 149462306a36Sopenharmony_ci IB_QP_RNR_RETRY | 149562306a36Sopenharmony_ci IB_QP_SQ_PSN | 149662306a36Sopenharmony_ci IB_QP_MAX_QP_RD_ATOMIC), 149762306a36Sopenharmony_ci [IB_QPT_XRC_INI] = (IB_QP_TIMEOUT | 149862306a36Sopenharmony_ci IB_QP_RETRY_CNT | 149962306a36Sopenharmony_ci IB_QP_RNR_RETRY | 150062306a36Sopenharmony_ci IB_QP_SQ_PSN | 150162306a36Sopenharmony_ci IB_QP_MAX_QP_RD_ATOMIC), 150262306a36Sopenharmony_ci [IB_QPT_XRC_TGT] = (IB_QP_TIMEOUT | 150362306a36Sopenharmony_ci IB_QP_SQ_PSN), 150462306a36Sopenharmony_ci [IB_QPT_SMI] = IB_QP_SQ_PSN, 150562306a36Sopenharmony_ci [IB_QPT_GSI] = IB_QP_SQ_PSN, 150662306a36Sopenharmony_ci }, 150762306a36Sopenharmony_ci .opt_param = { 150862306a36Sopenharmony_ci [IB_QPT_UD] = (IB_QP_CUR_STATE | 150962306a36Sopenharmony_ci IB_QP_QKEY), 151062306a36Sopenharmony_ci [IB_QPT_UC] = (IB_QP_CUR_STATE | 151162306a36Sopenharmony_ci IB_QP_ALT_PATH | 151262306a36Sopenharmony_ci IB_QP_ACCESS_FLAGS | 151362306a36Sopenharmony_ci IB_QP_PATH_MIG_STATE), 151462306a36Sopenharmony_ci [IB_QPT_RC] = (IB_QP_CUR_STATE | 151562306a36Sopenharmony_ci IB_QP_ALT_PATH | 151662306a36Sopenharmony_ci IB_QP_ACCESS_FLAGS | 151762306a36Sopenharmony_ci IB_QP_MIN_RNR_TIMER | 151862306a36Sopenharmony_ci IB_QP_PATH_MIG_STATE), 151962306a36Sopenharmony_ci [IB_QPT_XRC_INI] = (IB_QP_CUR_STATE | 152062306a36Sopenharmony_ci IB_QP_ALT_PATH | 152162306a36Sopenharmony_ci IB_QP_ACCESS_FLAGS | 152262306a36Sopenharmony_ci IB_QP_PATH_MIG_STATE), 152362306a36Sopenharmony_ci [IB_QPT_XRC_TGT] = (IB_QP_CUR_STATE | 152462306a36Sopenharmony_ci IB_QP_ALT_PATH | 152562306a36Sopenharmony_ci IB_QP_ACCESS_FLAGS | 152662306a36Sopenharmony_ci IB_QP_MIN_RNR_TIMER | 152762306a36Sopenharmony_ci IB_QP_PATH_MIG_STATE), 152862306a36Sopenharmony_ci [IB_QPT_SMI] = (IB_QP_CUR_STATE | 152962306a36Sopenharmony_ci IB_QP_QKEY), 153062306a36Sopenharmony_ci [IB_QPT_GSI] = (IB_QP_CUR_STATE | 153162306a36Sopenharmony_ci IB_QP_QKEY), 153262306a36Sopenharmony_ci [IB_QPT_RAW_PACKET] = IB_QP_RATE_LIMIT, 153362306a36Sopenharmony_ci } 153462306a36Sopenharmony_ci } 153562306a36Sopenharmony_ci }, 153662306a36Sopenharmony_ci [IB_QPS_RTS] = { 153762306a36Sopenharmony_ci [IB_QPS_RESET] = { .valid = 1 }, 153862306a36Sopenharmony_ci [IB_QPS_ERR] = { .valid = 1 }, 153962306a36Sopenharmony_ci [IB_QPS_RTS] = { 154062306a36Sopenharmony_ci .valid = 1, 154162306a36Sopenharmony_ci .opt_param = { 154262306a36Sopenharmony_ci [IB_QPT_UD] = (IB_QP_CUR_STATE | 154362306a36Sopenharmony_ci IB_QP_QKEY), 154462306a36Sopenharmony_ci [IB_QPT_UC] = (IB_QP_CUR_STATE | 154562306a36Sopenharmony_ci IB_QP_ACCESS_FLAGS | 154662306a36Sopenharmony_ci IB_QP_ALT_PATH | 154762306a36Sopenharmony_ci IB_QP_PATH_MIG_STATE), 154862306a36Sopenharmony_ci [IB_QPT_RC] = (IB_QP_CUR_STATE | 154962306a36Sopenharmony_ci IB_QP_ACCESS_FLAGS | 155062306a36Sopenharmony_ci IB_QP_ALT_PATH | 155162306a36Sopenharmony_ci IB_QP_PATH_MIG_STATE | 155262306a36Sopenharmony_ci IB_QP_MIN_RNR_TIMER), 155362306a36Sopenharmony_ci [IB_QPT_XRC_INI] = (IB_QP_CUR_STATE | 155462306a36Sopenharmony_ci IB_QP_ACCESS_FLAGS | 155562306a36Sopenharmony_ci IB_QP_ALT_PATH | 155662306a36Sopenharmony_ci IB_QP_PATH_MIG_STATE), 155762306a36Sopenharmony_ci [IB_QPT_XRC_TGT] = (IB_QP_CUR_STATE | 155862306a36Sopenharmony_ci IB_QP_ACCESS_FLAGS | 155962306a36Sopenharmony_ci IB_QP_ALT_PATH | 156062306a36Sopenharmony_ci IB_QP_PATH_MIG_STATE | 156162306a36Sopenharmony_ci IB_QP_MIN_RNR_TIMER), 156262306a36Sopenharmony_ci [IB_QPT_SMI] = (IB_QP_CUR_STATE | 156362306a36Sopenharmony_ci IB_QP_QKEY), 156462306a36Sopenharmony_ci [IB_QPT_GSI] = (IB_QP_CUR_STATE | 156562306a36Sopenharmony_ci IB_QP_QKEY), 156662306a36Sopenharmony_ci [IB_QPT_RAW_PACKET] = IB_QP_RATE_LIMIT, 156762306a36Sopenharmony_ci } 156862306a36Sopenharmony_ci }, 156962306a36Sopenharmony_ci [IB_QPS_SQD] = { 157062306a36Sopenharmony_ci .valid = 1, 157162306a36Sopenharmony_ci .opt_param = { 157262306a36Sopenharmony_ci [IB_QPT_UD] = IB_QP_EN_SQD_ASYNC_NOTIFY, 157362306a36Sopenharmony_ci [IB_QPT_UC] = IB_QP_EN_SQD_ASYNC_NOTIFY, 157462306a36Sopenharmony_ci [IB_QPT_RC] = IB_QP_EN_SQD_ASYNC_NOTIFY, 157562306a36Sopenharmony_ci [IB_QPT_XRC_INI] = IB_QP_EN_SQD_ASYNC_NOTIFY, 157662306a36Sopenharmony_ci [IB_QPT_XRC_TGT] = IB_QP_EN_SQD_ASYNC_NOTIFY, /* ??? */ 157762306a36Sopenharmony_ci [IB_QPT_SMI] = IB_QP_EN_SQD_ASYNC_NOTIFY, 157862306a36Sopenharmony_ci [IB_QPT_GSI] = IB_QP_EN_SQD_ASYNC_NOTIFY 157962306a36Sopenharmony_ci } 158062306a36Sopenharmony_ci }, 158162306a36Sopenharmony_ci }, 158262306a36Sopenharmony_ci [IB_QPS_SQD] = { 158362306a36Sopenharmony_ci [IB_QPS_RESET] = { .valid = 1 }, 158462306a36Sopenharmony_ci [IB_QPS_ERR] = { .valid = 1 }, 158562306a36Sopenharmony_ci [IB_QPS_RTS] = { 158662306a36Sopenharmony_ci .valid = 1, 158762306a36Sopenharmony_ci .opt_param = { 158862306a36Sopenharmony_ci [IB_QPT_UD] = (IB_QP_CUR_STATE | 158962306a36Sopenharmony_ci IB_QP_QKEY), 159062306a36Sopenharmony_ci [IB_QPT_UC] = (IB_QP_CUR_STATE | 159162306a36Sopenharmony_ci IB_QP_ALT_PATH | 159262306a36Sopenharmony_ci IB_QP_ACCESS_FLAGS | 159362306a36Sopenharmony_ci IB_QP_PATH_MIG_STATE), 159462306a36Sopenharmony_ci [IB_QPT_RC] = (IB_QP_CUR_STATE | 159562306a36Sopenharmony_ci IB_QP_ALT_PATH | 159662306a36Sopenharmony_ci IB_QP_ACCESS_FLAGS | 159762306a36Sopenharmony_ci IB_QP_MIN_RNR_TIMER | 159862306a36Sopenharmony_ci IB_QP_PATH_MIG_STATE), 159962306a36Sopenharmony_ci [IB_QPT_XRC_INI] = (IB_QP_CUR_STATE | 160062306a36Sopenharmony_ci IB_QP_ALT_PATH | 160162306a36Sopenharmony_ci IB_QP_ACCESS_FLAGS | 160262306a36Sopenharmony_ci IB_QP_PATH_MIG_STATE), 160362306a36Sopenharmony_ci [IB_QPT_XRC_TGT] = (IB_QP_CUR_STATE | 160462306a36Sopenharmony_ci IB_QP_ALT_PATH | 160562306a36Sopenharmony_ci IB_QP_ACCESS_FLAGS | 160662306a36Sopenharmony_ci IB_QP_MIN_RNR_TIMER | 160762306a36Sopenharmony_ci IB_QP_PATH_MIG_STATE), 160862306a36Sopenharmony_ci [IB_QPT_SMI] = (IB_QP_CUR_STATE | 160962306a36Sopenharmony_ci IB_QP_QKEY), 161062306a36Sopenharmony_ci [IB_QPT_GSI] = (IB_QP_CUR_STATE | 161162306a36Sopenharmony_ci IB_QP_QKEY), 161262306a36Sopenharmony_ci } 161362306a36Sopenharmony_ci }, 161462306a36Sopenharmony_ci [IB_QPS_SQD] = { 161562306a36Sopenharmony_ci .valid = 1, 161662306a36Sopenharmony_ci .opt_param = { 161762306a36Sopenharmony_ci [IB_QPT_UD] = (IB_QP_PKEY_INDEX | 161862306a36Sopenharmony_ci IB_QP_QKEY), 161962306a36Sopenharmony_ci [IB_QPT_UC] = (IB_QP_AV | 162062306a36Sopenharmony_ci IB_QP_ALT_PATH | 162162306a36Sopenharmony_ci IB_QP_ACCESS_FLAGS | 162262306a36Sopenharmony_ci IB_QP_PKEY_INDEX | 162362306a36Sopenharmony_ci IB_QP_PATH_MIG_STATE), 162462306a36Sopenharmony_ci [IB_QPT_RC] = (IB_QP_PORT | 162562306a36Sopenharmony_ci IB_QP_AV | 162662306a36Sopenharmony_ci IB_QP_TIMEOUT | 162762306a36Sopenharmony_ci IB_QP_RETRY_CNT | 162862306a36Sopenharmony_ci IB_QP_RNR_RETRY | 162962306a36Sopenharmony_ci IB_QP_MAX_QP_RD_ATOMIC | 163062306a36Sopenharmony_ci IB_QP_MAX_DEST_RD_ATOMIC | 163162306a36Sopenharmony_ci IB_QP_ALT_PATH | 163262306a36Sopenharmony_ci IB_QP_ACCESS_FLAGS | 163362306a36Sopenharmony_ci IB_QP_PKEY_INDEX | 163462306a36Sopenharmony_ci IB_QP_MIN_RNR_TIMER | 163562306a36Sopenharmony_ci IB_QP_PATH_MIG_STATE), 163662306a36Sopenharmony_ci [IB_QPT_XRC_INI] = (IB_QP_PORT | 163762306a36Sopenharmony_ci IB_QP_AV | 163862306a36Sopenharmony_ci IB_QP_TIMEOUT | 163962306a36Sopenharmony_ci IB_QP_RETRY_CNT | 164062306a36Sopenharmony_ci IB_QP_RNR_RETRY | 164162306a36Sopenharmony_ci IB_QP_MAX_QP_RD_ATOMIC | 164262306a36Sopenharmony_ci IB_QP_ALT_PATH | 164362306a36Sopenharmony_ci IB_QP_ACCESS_FLAGS | 164462306a36Sopenharmony_ci IB_QP_PKEY_INDEX | 164562306a36Sopenharmony_ci IB_QP_PATH_MIG_STATE), 164662306a36Sopenharmony_ci [IB_QPT_XRC_TGT] = (IB_QP_PORT | 164762306a36Sopenharmony_ci IB_QP_AV | 164862306a36Sopenharmony_ci IB_QP_TIMEOUT | 164962306a36Sopenharmony_ci IB_QP_MAX_DEST_RD_ATOMIC | 165062306a36Sopenharmony_ci IB_QP_ALT_PATH | 165162306a36Sopenharmony_ci IB_QP_ACCESS_FLAGS | 165262306a36Sopenharmony_ci IB_QP_PKEY_INDEX | 165362306a36Sopenharmony_ci IB_QP_MIN_RNR_TIMER | 165462306a36Sopenharmony_ci IB_QP_PATH_MIG_STATE), 165562306a36Sopenharmony_ci [IB_QPT_SMI] = (IB_QP_PKEY_INDEX | 165662306a36Sopenharmony_ci IB_QP_QKEY), 165762306a36Sopenharmony_ci [IB_QPT_GSI] = (IB_QP_PKEY_INDEX | 165862306a36Sopenharmony_ci IB_QP_QKEY), 165962306a36Sopenharmony_ci } 166062306a36Sopenharmony_ci } 166162306a36Sopenharmony_ci }, 166262306a36Sopenharmony_ci [IB_QPS_SQE] = { 166362306a36Sopenharmony_ci [IB_QPS_RESET] = { .valid = 1 }, 166462306a36Sopenharmony_ci [IB_QPS_ERR] = { .valid = 1 }, 166562306a36Sopenharmony_ci [IB_QPS_RTS] = { 166662306a36Sopenharmony_ci .valid = 1, 166762306a36Sopenharmony_ci .opt_param = { 166862306a36Sopenharmony_ci [IB_QPT_UD] = (IB_QP_CUR_STATE | 166962306a36Sopenharmony_ci IB_QP_QKEY), 167062306a36Sopenharmony_ci [IB_QPT_UC] = (IB_QP_CUR_STATE | 167162306a36Sopenharmony_ci IB_QP_ACCESS_FLAGS), 167262306a36Sopenharmony_ci [IB_QPT_SMI] = (IB_QP_CUR_STATE | 167362306a36Sopenharmony_ci IB_QP_QKEY), 167462306a36Sopenharmony_ci [IB_QPT_GSI] = (IB_QP_CUR_STATE | 167562306a36Sopenharmony_ci IB_QP_QKEY), 167662306a36Sopenharmony_ci } 167762306a36Sopenharmony_ci } 167862306a36Sopenharmony_ci }, 167962306a36Sopenharmony_ci [IB_QPS_ERR] = { 168062306a36Sopenharmony_ci [IB_QPS_RESET] = { .valid = 1 }, 168162306a36Sopenharmony_ci [IB_QPS_ERR] = { .valid = 1 } 168262306a36Sopenharmony_ci } 168362306a36Sopenharmony_ci}; 168462306a36Sopenharmony_ci 168562306a36Sopenharmony_cibool ib_modify_qp_is_ok(enum ib_qp_state cur_state, enum ib_qp_state next_state, 168662306a36Sopenharmony_ci enum ib_qp_type type, enum ib_qp_attr_mask mask) 168762306a36Sopenharmony_ci{ 168862306a36Sopenharmony_ci enum ib_qp_attr_mask req_param, opt_param; 168962306a36Sopenharmony_ci 169062306a36Sopenharmony_ci if (mask & IB_QP_CUR_STATE && 169162306a36Sopenharmony_ci cur_state != IB_QPS_RTR && cur_state != IB_QPS_RTS && 169262306a36Sopenharmony_ci cur_state != IB_QPS_SQD && cur_state != IB_QPS_SQE) 169362306a36Sopenharmony_ci return false; 169462306a36Sopenharmony_ci 169562306a36Sopenharmony_ci if (!qp_state_table[cur_state][next_state].valid) 169662306a36Sopenharmony_ci return false; 169762306a36Sopenharmony_ci 169862306a36Sopenharmony_ci req_param = qp_state_table[cur_state][next_state].req_param[type]; 169962306a36Sopenharmony_ci opt_param = qp_state_table[cur_state][next_state].opt_param[type]; 170062306a36Sopenharmony_ci 170162306a36Sopenharmony_ci if ((mask & req_param) != req_param) 170262306a36Sopenharmony_ci return false; 170362306a36Sopenharmony_ci 170462306a36Sopenharmony_ci if (mask & ~(req_param | opt_param | IB_QP_STATE)) 170562306a36Sopenharmony_ci return false; 170662306a36Sopenharmony_ci 170762306a36Sopenharmony_ci return true; 170862306a36Sopenharmony_ci} 170962306a36Sopenharmony_ciEXPORT_SYMBOL(ib_modify_qp_is_ok); 171062306a36Sopenharmony_ci 171162306a36Sopenharmony_ci/** 171262306a36Sopenharmony_ci * ib_resolve_eth_dmac - Resolve destination mac address 171362306a36Sopenharmony_ci * @device: Device to consider 171462306a36Sopenharmony_ci * @ah_attr: address handle attribute which describes the 171562306a36Sopenharmony_ci * source and destination parameters 171662306a36Sopenharmony_ci * ib_resolve_eth_dmac() resolves destination mac address and L3 hop limit It 171762306a36Sopenharmony_ci * returns 0 on success or appropriate error code. It initializes the 171862306a36Sopenharmony_ci * necessary ah_attr fields when call is successful. 171962306a36Sopenharmony_ci */ 172062306a36Sopenharmony_cistatic int ib_resolve_eth_dmac(struct ib_device *device, 172162306a36Sopenharmony_ci struct rdma_ah_attr *ah_attr) 172262306a36Sopenharmony_ci{ 172362306a36Sopenharmony_ci int ret = 0; 172462306a36Sopenharmony_ci 172562306a36Sopenharmony_ci if (rdma_is_multicast_addr((struct in6_addr *)ah_attr->grh.dgid.raw)) { 172662306a36Sopenharmony_ci if (ipv6_addr_v4mapped((struct in6_addr *)ah_attr->grh.dgid.raw)) { 172762306a36Sopenharmony_ci __be32 addr = 0; 172862306a36Sopenharmony_ci 172962306a36Sopenharmony_ci memcpy(&addr, ah_attr->grh.dgid.raw + 12, 4); 173062306a36Sopenharmony_ci ip_eth_mc_map(addr, (char *)ah_attr->roce.dmac); 173162306a36Sopenharmony_ci } else { 173262306a36Sopenharmony_ci ipv6_eth_mc_map((struct in6_addr *)ah_attr->grh.dgid.raw, 173362306a36Sopenharmony_ci (char *)ah_attr->roce.dmac); 173462306a36Sopenharmony_ci } 173562306a36Sopenharmony_ci } else { 173662306a36Sopenharmony_ci ret = ib_resolve_unicast_gid_dmac(device, ah_attr); 173762306a36Sopenharmony_ci } 173862306a36Sopenharmony_ci return ret; 173962306a36Sopenharmony_ci} 174062306a36Sopenharmony_ci 174162306a36Sopenharmony_cistatic bool is_qp_type_connected(const struct ib_qp *qp) 174262306a36Sopenharmony_ci{ 174362306a36Sopenharmony_ci return (qp->qp_type == IB_QPT_UC || 174462306a36Sopenharmony_ci qp->qp_type == IB_QPT_RC || 174562306a36Sopenharmony_ci qp->qp_type == IB_QPT_XRC_INI || 174662306a36Sopenharmony_ci qp->qp_type == IB_QPT_XRC_TGT); 174762306a36Sopenharmony_ci} 174862306a36Sopenharmony_ci 174962306a36Sopenharmony_ci/* 175062306a36Sopenharmony_ci * IB core internal function to perform QP attributes modification. 175162306a36Sopenharmony_ci */ 175262306a36Sopenharmony_cistatic int _ib_modify_qp(struct ib_qp *qp, struct ib_qp_attr *attr, 175362306a36Sopenharmony_ci int attr_mask, struct ib_udata *udata) 175462306a36Sopenharmony_ci{ 175562306a36Sopenharmony_ci u32 port = attr_mask & IB_QP_PORT ? attr->port_num : qp->port; 175662306a36Sopenharmony_ci const struct ib_gid_attr *old_sgid_attr_av; 175762306a36Sopenharmony_ci const struct ib_gid_attr *old_sgid_attr_alt_av; 175862306a36Sopenharmony_ci int ret; 175962306a36Sopenharmony_ci 176062306a36Sopenharmony_ci attr->xmit_slave = NULL; 176162306a36Sopenharmony_ci if (attr_mask & IB_QP_AV) { 176262306a36Sopenharmony_ci ret = rdma_fill_sgid_attr(qp->device, &attr->ah_attr, 176362306a36Sopenharmony_ci &old_sgid_attr_av); 176462306a36Sopenharmony_ci if (ret) 176562306a36Sopenharmony_ci return ret; 176662306a36Sopenharmony_ci 176762306a36Sopenharmony_ci if (attr->ah_attr.type == RDMA_AH_ATTR_TYPE_ROCE && 176862306a36Sopenharmony_ci is_qp_type_connected(qp)) { 176962306a36Sopenharmony_ci struct net_device *slave; 177062306a36Sopenharmony_ci 177162306a36Sopenharmony_ci /* 177262306a36Sopenharmony_ci * If the user provided the qp_attr then we have to 177362306a36Sopenharmony_ci * resolve it. Kerne users have to provide already 177462306a36Sopenharmony_ci * resolved rdma_ah_attr's. 177562306a36Sopenharmony_ci */ 177662306a36Sopenharmony_ci if (udata) { 177762306a36Sopenharmony_ci ret = ib_resolve_eth_dmac(qp->device, 177862306a36Sopenharmony_ci &attr->ah_attr); 177962306a36Sopenharmony_ci if (ret) 178062306a36Sopenharmony_ci goto out_av; 178162306a36Sopenharmony_ci } 178262306a36Sopenharmony_ci slave = rdma_lag_get_ah_roce_slave(qp->device, 178362306a36Sopenharmony_ci &attr->ah_attr, 178462306a36Sopenharmony_ci GFP_KERNEL); 178562306a36Sopenharmony_ci if (IS_ERR(slave)) { 178662306a36Sopenharmony_ci ret = PTR_ERR(slave); 178762306a36Sopenharmony_ci goto out_av; 178862306a36Sopenharmony_ci } 178962306a36Sopenharmony_ci attr->xmit_slave = slave; 179062306a36Sopenharmony_ci } 179162306a36Sopenharmony_ci } 179262306a36Sopenharmony_ci if (attr_mask & IB_QP_ALT_PATH) { 179362306a36Sopenharmony_ci /* 179462306a36Sopenharmony_ci * FIXME: This does not track the migration state, so if the 179562306a36Sopenharmony_ci * user loads a new alternate path after the HW has migrated 179662306a36Sopenharmony_ci * from primary->alternate we will keep the wrong 179762306a36Sopenharmony_ci * references. This is OK for IB because the reference 179862306a36Sopenharmony_ci * counting does not serve any functional purpose. 179962306a36Sopenharmony_ci */ 180062306a36Sopenharmony_ci ret = rdma_fill_sgid_attr(qp->device, &attr->alt_ah_attr, 180162306a36Sopenharmony_ci &old_sgid_attr_alt_av); 180262306a36Sopenharmony_ci if (ret) 180362306a36Sopenharmony_ci goto out_av; 180462306a36Sopenharmony_ci 180562306a36Sopenharmony_ci /* 180662306a36Sopenharmony_ci * Today the core code can only handle alternate paths and APM 180762306a36Sopenharmony_ci * for IB. Ban them in roce mode. 180862306a36Sopenharmony_ci */ 180962306a36Sopenharmony_ci if (!(rdma_protocol_ib(qp->device, 181062306a36Sopenharmony_ci attr->alt_ah_attr.port_num) && 181162306a36Sopenharmony_ci rdma_protocol_ib(qp->device, port))) { 181262306a36Sopenharmony_ci ret = -EINVAL; 181362306a36Sopenharmony_ci goto out; 181462306a36Sopenharmony_ci } 181562306a36Sopenharmony_ci } 181662306a36Sopenharmony_ci 181762306a36Sopenharmony_ci if (rdma_ib_or_roce(qp->device, port)) { 181862306a36Sopenharmony_ci if (attr_mask & IB_QP_RQ_PSN && attr->rq_psn & ~0xffffff) { 181962306a36Sopenharmony_ci dev_warn(&qp->device->dev, 182062306a36Sopenharmony_ci "%s rq_psn overflow, masking to 24 bits\n", 182162306a36Sopenharmony_ci __func__); 182262306a36Sopenharmony_ci attr->rq_psn &= 0xffffff; 182362306a36Sopenharmony_ci } 182462306a36Sopenharmony_ci 182562306a36Sopenharmony_ci if (attr_mask & IB_QP_SQ_PSN && attr->sq_psn & ~0xffffff) { 182662306a36Sopenharmony_ci dev_warn(&qp->device->dev, 182762306a36Sopenharmony_ci " %s sq_psn overflow, masking to 24 bits\n", 182862306a36Sopenharmony_ci __func__); 182962306a36Sopenharmony_ci attr->sq_psn &= 0xffffff; 183062306a36Sopenharmony_ci } 183162306a36Sopenharmony_ci } 183262306a36Sopenharmony_ci 183362306a36Sopenharmony_ci /* 183462306a36Sopenharmony_ci * Bind this qp to a counter automatically based on the rdma counter 183562306a36Sopenharmony_ci * rules. This only set in RST2INIT with port specified 183662306a36Sopenharmony_ci */ 183762306a36Sopenharmony_ci if (!qp->counter && (attr_mask & IB_QP_PORT) && 183862306a36Sopenharmony_ci ((attr_mask & IB_QP_STATE) && attr->qp_state == IB_QPS_INIT)) 183962306a36Sopenharmony_ci rdma_counter_bind_qp_auto(qp, attr->port_num); 184062306a36Sopenharmony_ci 184162306a36Sopenharmony_ci ret = ib_security_modify_qp(qp, attr, attr_mask, udata); 184262306a36Sopenharmony_ci if (ret) 184362306a36Sopenharmony_ci goto out; 184462306a36Sopenharmony_ci 184562306a36Sopenharmony_ci if (attr_mask & IB_QP_PORT) 184662306a36Sopenharmony_ci qp->port = attr->port_num; 184762306a36Sopenharmony_ci if (attr_mask & IB_QP_AV) 184862306a36Sopenharmony_ci qp->av_sgid_attr = 184962306a36Sopenharmony_ci rdma_update_sgid_attr(&attr->ah_attr, qp->av_sgid_attr); 185062306a36Sopenharmony_ci if (attr_mask & IB_QP_ALT_PATH) 185162306a36Sopenharmony_ci qp->alt_path_sgid_attr = rdma_update_sgid_attr( 185262306a36Sopenharmony_ci &attr->alt_ah_attr, qp->alt_path_sgid_attr); 185362306a36Sopenharmony_ci 185462306a36Sopenharmony_ciout: 185562306a36Sopenharmony_ci if (attr_mask & IB_QP_ALT_PATH) 185662306a36Sopenharmony_ci rdma_unfill_sgid_attr(&attr->alt_ah_attr, old_sgid_attr_alt_av); 185762306a36Sopenharmony_ciout_av: 185862306a36Sopenharmony_ci if (attr_mask & IB_QP_AV) { 185962306a36Sopenharmony_ci rdma_lag_put_ah_roce_slave(attr->xmit_slave); 186062306a36Sopenharmony_ci rdma_unfill_sgid_attr(&attr->ah_attr, old_sgid_attr_av); 186162306a36Sopenharmony_ci } 186262306a36Sopenharmony_ci return ret; 186362306a36Sopenharmony_ci} 186462306a36Sopenharmony_ci 186562306a36Sopenharmony_ci/** 186662306a36Sopenharmony_ci * ib_modify_qp_with_udata - Modifies the attributes for the specified QP. 186762306a36Sopenharmony_ci * @ib_qp: The QP to modify. 186862306a36Sopenharmony_ci * @attr: On input, specifies the QP attributes to modify. On output, 186962306a36Sopenharmony_ci * the current values of selected QP attributes are returned. 187062306a36Sopenharmony_ci * @attr_mask: A bit-mask used to specify which attributes of the QP 187162306a36Sopenharmony_ci * are being modified. 187262306a36Sopenharmony_ci * @udata: pointer to user's input output buffer information 187362306a36Sopenharmony_ci * are being modified. 187462306a36Sopenharmony_ci * It returns 0 on success and returns appropriate error code on error. 187562306a36Sopenharmony_ci */ 187662306a36Sopenharmony_ciint ib_modify_qp_with_udata(struct ib_qp *ib_qp, struct ib_qp_attr *attr, 187762306a36Sopenharmony_ci int attr_mask, struct ib_udata *udata) 187862306a36Sopenharmony_ci{ 187962306a36Sopenharmony_ci return _ib_modify_qp(ib_qp->real_qp, attr, attr_mask, udata); 188062306a36Sopenharmony_ci} 188162306a36Sopenharmony_ciEXPORT_SYMBOL(ib_modify_qp_with_udata); 188262306a36Sopenharmony_ci 188362306a36Sopenharmony_cistatic void ib_get_width_and_speed(u32 netdev_speed, u32 lanes, 188462306a36Sopenharmony_ci u16 *speed, u8 *width) 188562306a36Sopenharmony_ci{ 188662306a36Sopenharmony_ci if (!lanes) { 188762306a36Sopenharmony_ci if (netdev_speed <= SPEED_1000) { 188862306a36Sopenharmony_ci *width = IB_WIDTH_1X; 188962306a36Sopenharmony_ci *speed = IB_SPEED_SDR; 189062306a36Sopenharmony_ci } else if (netdev_speed <= SPEED_10000) { 189162306a36Sopenharmony_ci *width = IB_WIDTH_1X; 189262306a36Sopenharmony_ci *speed = IB_SPEED_FDR10; 189362306a36Sopenharmony_ci } else if (netdev_speed <= SPEED_20000) { 189462306a36Sopenharmony_ci *width = IB_WIDTH_4X; 189562306a36Sopenharmony_ci *speed = IB_SPEED_DDR; 189662306a36Sopenharmony_ci } else if (netdev_speed <= SPEED_25000) { 189762306a36Sopenharmony_ci *width = IB_WIDTH_1X; 189862306a36Sopenharmony_ci *speed = IB_SPEED_EDR; 189962306a36Sopenharmony_ci } else if (netdev_speed <= SPEED_40000) { 190062306a36Sopenharmony_ci *width = IB_WIDTH_4X; 190162306a36Sopenharmony_ci *speed = IB_SPEED_FDR10; 190262306a36Sopenharmony_ci } else if (netdev_speed <= SPEED_50000) { 190362306a36Sopenharmony_ci *width = IB_WIDTH_2X; 190462306a36Sopenharmony_ci *speed = IB_SPEED_EDR; 190562306a36Sopenharmony_ci } else if (netdev_speed <= SPEED_100000) { 190662306a36Sopenharmony_ci *width = IB_WIDTH_4X; 190762306a36Sopenharmony_ci *speed = IB_SPEED_EDR; 190862306a36Sopenharmony_ci } else if (netdev_speed <= SPEED_200000) { 190962306a36Sopenharmony_ci *width = IB_WIDTH_4X; 191062306a36Sopenharmony_ci *speed = IB_SPEED_HDR; 191162306a36Sopenharmony_ci } else { 191262306a36Sopenharmony_ci *width = IB_WIDTH_4X; 191362306a36Sopenharmony_ci *speed = IB_SPEED_NDR; 191462306a36Sopenharmony_ci } 191562306a36Sopenharmony_ci 191662306a36Sopenharmony_ci return; 191762306a36Sopenharmony_ci } 191862306a36Sopenharmony_ci 191962306a36Sopenharmony_ci switch (lanes) { 192062306a36Sopenharmony_ci case 1: 192162306a36Sopenharmony_ci *width = IB_WIDTH_1X; 192262306a36Sopenharmony_ci break; 192362306a36Sopenharmony_ci case 2: 192462306a36Sopenharmony_ci *width = IB_WIDTH_2X; 192562306a36Sopenharmony_ci break; 192662306a36Sopenharmony_ci case 4: 192762306a36Sopenharmony_ci *width = IB_WIDTH_4X; 192862306a36Sopenharmony_ci break; 192962306a36Sopenharmony_ci case 8: 193062306a36Sopenharmony_ci *width = IB_WIDTH_8X; 193162306a36Sopenharmony_ci break; 193262306a36Sopenharmony_ci case 12: 193362306a36Sopenharmony_ci *width = IB_WIDTH_12X; 193462306a36Sopenharmony_ci break; 193562306a36Sopenharmony_ci default: 193662306a36Sopenharmony_ci *width = IB_WIDTH_1X; 193762306a36Sopenharmony_ci } 193862306a36Sopenharmony_ci 193962306a36Sopenharmony_ci switch (netdev_speed / lanes) { 194062306a36Sopenharmony_ci case SPEED_2500: 194162306a36Sopenharmony_ci *speed = IB_SPEED_SDR; 194262306a36Sopenharmony_ci break; 194362306a36Sopenharmony_ci case SPEED_5000: 194462306a36Sopenharmony_ci *speed = IB_SPEED_DDR; 194562306a36Sopenharmony_ci break; 194662306a36Sopenharmony_ci case SPEED_10000: 194762306a36Sopenharmony_ci *speed = IB_SPEED_FDR10; 194862306a36Sopenharmony_ci break; 194962306a36Sopenharmony_ci case SPEED_14000: 195062306a36Sopenharmony_ci *speed = IB_SPEED_FDR; 195162306a36Sopenharmony_ci break; 195262306a36Sopenharmony_ci case SPEED_25000: 195362306a36Sopenharmony_ci *speed = IB_SPEED_EDR; 195462306a36Sopenharmony_ci break; 195562306a36Sopenharmony_ci case SPEED_50000: 195662306a36Sopenharmony_ci *speed = IB_SPEED_HDR; 195762306a36Sopenharmony_ci break; 195862306a36Sopenharmony_ci case SPEED_100000: 195962306a36Sopenharmony_ci *speed = IB_SPEED_NDR; 196062306a36Sopenharmony_ci break; 196162306a36Sopenharmony_ci default: 196262306a36Sopenharmony_ci *speed = IB_SPEED_SDR; 196362306a36Sopenharmony_ci } 196462306a36Sopenharmony_ci} 196562306a36Sopenharmony_ci 196662306a36Sopenharmony_ciint ib_get_eth_speed(struct ib_device *dev, u32 port_num, u16 *speed, u8 *width) 196762306a36Sopenharmony_ci{ 196862306a36Sopenharmony_ci int rc; 196962306a36Sopenharmony_ci u32 netdev_speed; 197062306a36Sopenharmony_ci struct net_device *netdev; 197162306a36Sopenharmony_ci struct ethtool_link_ksettings lksettings = {}; 197262306a36Sopenharmony_ci 197362306a36Sopenharmony_ci if (rdma_port_get_link_layer(dev, port_num) != IB_LINK_LAYER_ETHERNET) 197462306a36Sopenharmony_ci return -EINVAL; 197562306a36Sopenharmony_ci 197662306a36Sopenharmony_ci netdev = ib_device_get_netdev(dev, port_num); 197762306a36Sopenharmony_ci if (!netdev) 197862306a36Sopenharmony_ci return -ENODEV; 197962306a36Sopenharmony_ci 198062306a36Sopenharmony_ci rtnl_lock(); 198162306a36Sopenharmony_ci rc = __ethtool_get_link_ksettings(netdev, &lksettings); 198262306a36Sopenharmony_ci rtnl_unlock(); 198362306a36Sopenharmony_ci 198462306a36Sopenharmony_ci dev_put(netdev); 198562306a36Sopenharmony_ci 198662306a36Sopenharmony_ci if (!rc && lksettings.base.speed != (u32)SPEED_UNKNOWN) { 198762306a36Sopenharmony_ci netdev_speed = lksettings.base.speed; 198862306a36Sopenharmony_ci } else { 198962306a36Sopenharmony_ci netdev_speed = SPEED_1000; 199062306a36Sopenharmony_ci if (rc) 199162306a36Sopenharmony_ci pr_warn("%s speed is unknown, defaulting to %u\n", 199262306a36Sopenharmony_ci netdev->name, netdev_speed); 199362306a36Sopenharmony_ci } 199462306a36Sopenharmony_ci 199562306a36Sopenharmony_ci ib_get_width_and_speed(netdev_speed, lksettings.lanes, 199662306a36Sopenharmony_ci speed, width); 199762306a36Sopenharmony_ci 199862306a36Sopenharmony_ci return 0; 199962306a36Sopenharmony_ci} 200062306a36Sopenharmony_ciEXPORT_SYMBOL(ib_get_eth_speed); 200162306a36Sopenharmony_ci 200262306a36Sopenharmony_ciint ib_modify_qp(struct ib_qp *qp, 200362306a36Sopenharmony_ci struct ib_qp_attr *qp_attr, 200462306a36Sopenharmony_ci int qp_attr_mask) 200562306a36Sopenharmony_ci{ 200662306a36Sopenharmony_ci return _ib_modify_qp(qp->real_qp, qp_attr, qp_attr_mask, NULL); 200762306a36Sopenharmony_ci} 200862306a36Sopenharmony_ciEXPORT_SYMBOL(ib_modify_qp); 200962306a36Sopenharmony_ci 201062306a36Sopenharmony_ciint ib_query_qp(struct ib_qp *qp, 201162306a36Sopenharmony_ci struct ib_qp_attr *qp_attr, 201262306a36Sopenharmony_ci int qp_attr_mask, 201362306a36Sopenharmony_ci struct ib_qp_init_attr *qp_init_attr) 201462306a36Sopenharmony_ci{ 201562306a36Sopenharmony_ci qp_attr->ah_attr.grh.sgid_attr = NULL; 201662306a36Sopenharmony_ci qp_attr->alt_ah_attr.grh.sgid_attr = NULL; 201762306a36Sopenharmony_ci 201862306a36Sopenharmony_ci return qp->device->ops.query_qp ? 201962306a36Sopenharmony_ci qp->device->ops.query_qp(qp->real_qp, qp_attr, qp_attr_mask, 202062306a36Sopenharmony_ci qp_init_attr) : -EOPNOTSUPP; 202162306a36Sopenharmony_ci} 202262306a36Sopenharmony_ciEXPORT_SYMBOL(ib_query_qp); 202362306a36Sopenharmony_ci 202462306a36Sopenharmony_ciint ib_close_qp(struct ib_qp *qp) 202562306a36Sopenharmony_ci{ 202662306a36Sopenharmony_ci struct ib_qp *real_qp; 202762306a36Sopenharmony_ci unsigned long flags; 202862306a36Sopenharmony_ci 202962306a36Sopenharmony_ci real_qp = qp->real_qp; 203062306a36Sopenharmony_ci if (real_qp == qp) 203162306a36Sopenharmony_ci return -EINVAL; 203262306a36Sopenharmony_ci 203362306a36Sopenharmony_ci spin_lock_irqsave(&real_qp->device->qp_open_list_lock, flags); 203462306a36Sopenharmony_ci list_del(&qp->open_list); 203562306a36Sopenharmony_ci spin_unlock_irqrestore(&real_qp->device->qp_open_list_lock, flags); 203662306a36Sopenharmony_ci 203762306a36Sopenharmony_ci atomic_dec(&real_qp->usecnt); 203862306a36Sopenharmony_ci if (qp->qp_sec) 203962306a36Sopenharmony_ci ib_close_shared_qp_security(qp->qp_sec); 204062306a36Sopenharmony_ci kfree(qp); 204162306a36Sopenharmony_ci 204262306a36Sopenharmony_ci return 0; 204362306a36Sopenharmony_ci} 204462306a36Sopenharmony_ciEXPORT_SYMBOL(ib_close_qp); 204562306a36Sopenharmony_ci 204662306a36Sopenharmony_cistatic int __ib_destroy_shared_qp(struct ib_qp *qp) 204762306a36Sopenharmony_ci{ 204862306a36Sopenharmony_ci struct ib_xrcd *xrcd; 204962306a36Sopenharmony_ci struct ib_qp *real_qp; 205062306a36Sopenharmony_ci int ret; 205162306a36Sopenharmony_ci 205262306a36Sopenharmony_ci real_qp = qp->real_qp; 205362306a36Sopenharmony_ci xrcd = real_qp->xrcd; 205462306a36Sopenharmony_ci down_write(&xrcd->tgt_qps_rwsem); 205562306a36Sopenharmony_ci ib_close_qp(qp); 205662306a36Sopenharmony_ci if (atomic_read(&real_qp->usecnt) == 0) 205762306a36Sopenharmony_ci xa_erase(&xrcd->tgt_qps, real_qp->qp_num); 205862306a36Sopenharmony_ci else 205962306a36Sopenharmony_ci real_qp = NULL; 206062306a36Sopenharmony_ci up_write(&xrcd->tgt_qps_rwsem); 206162306a36Sopenharmony_ci 206262306a36Sopenharmony_ci if (real_qp) { 206362306a36Sopenharmony_ci ret = ib_destroy_qp(real_qp); 206462306a36Sopenharmony_ci if (!ret) 206562306a36Sopenharmony_ci atomic_dec(&xrcd->usecnt); 206662306a36Sopenharmony_ci } 206762306a36Sopenharmony_ci 206862306a36Sopenharmony_ci return 0; 206962306a36Sopenharmony_ci} 207062306a36Sopenharmony_ci 207162306a36Sopenharmony_ciint ib_destroy_qp_user(struct ib_qp *qp, struct ib_udata *udata) 207262306a36Sopenharmony_ci{ 207362306a36Sopenharmony_ci const struct ib_gid_attr *alt_path_sgid_attr = qp->alt_path_sgid_attr; 207462306a36Sopenharmony_ci const struct ib_gid_attr *av_sgid_attr = qp->av_sgid_attr; 207562306a36Sopenharmony_ci struct ib_qp_security *sec; 207662306a36Sopenharmony_ci int ret; 207762306a36Sopenharmony_ci 207862306a36Sopenharmony_ci WARN_ON_ONCE(qp->mrs_used > 0); 207962306a36Sopenharmony_ci 208062306a36Sopenharmony_ci if (atomic_read(&qp->usecnt)) 208162306a36Sopenharmony_ci return -EBUSY; 208262306a36Sopenharmony_ci 208362306a36Sopenharmony_ci if (qp->real_qp != qp) 208462306a36Sopenharmony_ci return __ib_destroy_shared_qp(qp); 208562306a36Sopenharmony_ci 208662306a36Sopenharmony_ci sec = qp->qp_sec; 208762306a36Sopenharmony_ci if (sec) 208862306a36Sopenharmony_ci ib_destroy_qp_security_begin(sec); 208962306a36Sopenharmony_ci 209062306a36Sopenharmony_ci if (!qp->uobject) 209162306a36Sopenharmony_ci rdma_rw_cleanup_mrs(qp); 209262306a36Sopenharmony_ci 209362306a36Sopenharmony_ci rdma_counter_unbind_qp(qp, true); 209462306a36Sopenharmony_ci ret = qp->device->ops.destroy_qp(qp, udata); 209562306a36Sopenharmony_ci if (ret) { 209662306a36Sopenharmony_ci if (sec) 209762306a36Sopenharmony_ci ib_destroy_qp_security_abort(sec); 209862306a36Sopenharmony_ci return ret; 209962306a36Sopenharmony_ci } 210062306a36Sopenharmony_ci 210162306a36Sopenharmony_ci if (alt_path_sgid_attr) 210262306a36Sopenharmony_ci rdma_put_gid_attr(alt_path_sgid_attr); 210362306a36Sopenharmony_ci if (av_sgid_attr) 210462306a36Sopenharmony_ci rdma_put_gid_attr(av_sgid_attr); 210562306a36Sopenharmony_ci 210662306a36Sopenharmony_ci ib_qp_usecnt_dec(qp); 210762306a36Sopenharmony_ci if (sec) 210862306a36Sopenharmony_ci ib_destroy_qp_security_end(sec); 210962306a36Sopenharmony_ci 211062306a36Sopenharmony_ci rdma_restrack_del(&qp->res); 211162306a36Sopenharmony_ci kfree(qp); 211262306a36Sopenharmony_ci return ret; 211362306a36Sopenharmony_ci} 211462306a36Sopenharmony_ciEXPORT_SYMBOL(ib_destroy_qp_user); 211562306a36Sopenharmony_ci 211662306a36Sopenharmony_ci/* Completion queues */ 211762306a36Sopenharmony_ci 211862306a36Sopenharmony_cistruct ib_cq *__ib_create_cq(struct ib_device *device, 211962306a36Sopenharmony_ci ib_comp_handler comp_handler, 212062306a36Sopenharmony_ci void (*event_handler)(struct ib_event *, void *), 212162306a36Sopenharmony_ci void *cq_context, 212262306a36Sopenharmony_ci const struct ib_cq_init_attr *cq_attr, 212362306a36Sopenharmony_ci const char *caller) 212462306a36Sopenharmony_ci{ 212562306a36Sopenharmony_ci struct ib_cq *cq; 212662306a36Sopenharmony_ci int ret; 212762306a36Sopenharmony_ci 212862306a36Sopenharmony_ci cq = rdma_zalloc_drv_obj(device, ib_cq); 212962306a36Sopenharmony_ci if (!cq) 213062306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 213162306a36Sopenharmony_ci 213262306a36Sopenharmony_ci cq->device = device; 213362306a36Sopenharmony_ci cq->uobject = NULL; 213462306a36Sopenharmony_ci cq->comp_handler = comp_handler; 213562306a36Sopenharmony_ci cq->event_handler = event_handler; 213662306a36Sopenharmony_ci cq->cq_context = cq_context; 213762306a36Sopenharmony_ci atomic_set(&cq->usecnt, 0); 213862306a36Sopenharmony_ci 213962306a36Sopenharmony_ci rdma_restrack_new(&cq->res, RDMA_RESTRACK_CQ); 214062306a36Sopenharmony_ci rdma_restrack_set_name(&cq->res, caller); 214162306a36Sopenharmony_ci 214262306a36Sopenharmony_ci ret = device->ops.create_cq(cq, cq_attr, NULL); 214362306a36Sopenharmony_ci if (ret) { 214462306a36Sopenharmony_ci rdma_restrack_put(&cq->res); 214562306a36Sopenharmony_ci kfree(cq); 214662306a36Sopenharmony_ci return ERR_PTR(ret); 214762306a36Sopenharmony_ci } 214862306a36Sopenharmony_ci 214962306a36Sopenharmony_ci rdma_restrack_add(&cq->res); 215062306a36Sopenharmony_ci return cq; 215162306a36Sopenharmony_ci} 215262306a36Sopenharmony_ciEXPORT_SYMBOL(__ib_create_cq); 215362306a36Sopenharmony_ci 215462306a36Sopenharmony_ciint rdma_set_cq_moderation(struct ib_cq *cq, u16 cq_count, u16 cq_period) 215562306a36Sopenharmony_ci{ 215662306a36Sopenharmony_ci if (cq->shared) 215762306a36Sopenharmony_ci return -EOPNOTSUPP; 215862306a36Sopenharmony_ci 215962306a36Sopenharmony_ci return cq->device->ops.modify_cq ? 216062306a36Sopenharmony_ci cq->device->ops.modify_cq(cq, cq_count, 216162306a36Sopenharmony_ci cq_period) : -EOPNOTSUPP; 216262306a36Sopenharmony_ci} 216362306a36Sopenharmony_ciEXPORT_SYMBOL(rdma_set_cq_moderation); 216462306a36Sopenharmony_ci 216562306a36Sopenharmony_ciint ib_destroy_cq_user(struct ib_cq *cq, struct ib_udata *udata) 216662306a36Sopenharmony_ci{ 216762306a36Sopenharmony_ci int ret; 216862306a36Sopenharmony_ci 216962306a36Sopenharmony_ci if (WARN_ON_ONCE(cq->shared)) 217062306a36Sopenharmony_ci return -EOPNOTSUPP; 217162306a36Sopenharmony_ci 217262306a36Sopenharmony_ci if (atomic_read(&cq->usecnt)) 217362306a36Sopenharmony_ci return -EBUSY; 217462306a36Sopenharmony_ci 217562306a36Sopenharmony_ci ret = cq->device->ops.destroy_cq(cq, udata); 217662306a36Sopenharmony_ci if (ret) 217762306a36Sopenharmony_ci return ret; 217862306a36Sopenharmony_ci 217962306a36Sopenharmony_ci rdma_restrack_del(&cq->res); 218062306a36Sopenharmony_ci kfree(cq); 218162306a36Sopenharmony_ci return ret; 218262306a36Sopenharmony_ci} 218362306a36Sopenharmony_ciEXPORT_SYMBOL(ib_destroy_cq_user); 218462306a36Sopenharmony_ci 218562306a36Sopenharmony_ciint ib_resize_cq(struct ib_cq *cq, int cqe) 218662306a36Sopenharmony_ci{ 218762306a36Sopenharmony_ci if (cq->shared) 218862306a36Sopenharmony_ci return -EOPNOTSUPP; 218962306a36Sopenharmony_ci 219062306a36Sopenharmony_ci return cq->device->ops.resize_cq ? 219162306a36Sopenharmony_ci cq->device->ops.resize_cq(cq, cqe, NULL) : -EOPNOTSUPP; 219262306a36Sopenharmony_ci} 219362306a36Sopenharmony_ciEXPORT_SYMBOL(ib_resize_cq); 219462306a36Sopenharmony_ci 219562306a36Sopenharmony_ci/* Memory regions */ 219662306a36Sopenharmony_ci 219762306a36Sopenharmony_cistruct ib_mr *ib_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, 219862306a36Sopenharmony_ci u64 virt_addr, int access_flags) 219962306a36Sopenharmony_ci{ 220062306a36Sopenharmony_ci struct ib_mr *mr; 220162306a36Sopenharmony_ci 220262306a36Sopenharmony_ci if (access_flags & IB_ACCESS_ON_DEMAND) { 220362306a36Sopenharmony_ci if (!(pd->device->attrs.kernel_cap_flags & 220462306a36Sopenharmony_ci IBK_ON_DEMAND_PAGING)) { 220562306a36Sopenharmony_ci pr_debug("ODP support not available\n"); 220662306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 220762306a36Sopenharmony_ci } 220862306a36Sopenharmony_ci } 220962306a36Sopenharmony_ci 221062306a36Sopenharmony_ci mr = pd->device->ops.reg_user_mr(pd, start, length, virt_addr, 221162306a36Sopenharmony_ci access_flags, NULL); 221262306a36Sopenharmony_ci 221362306a36Sopenharmony_ci if (IS_ERR(mr)) 221462306a36Sopenharmony_ci return mr; 221562306a36Sopenharmony_ci 221662306a36Sopenharmony_ci mr->device = pd->device; 221762306a36Sopenharmony_ci mr->type = IB_MR_TYPE_USER; 221862306a36Sopenharmony_ci mr->pd = pd; 221962306a36Sopenharmony_ci mr->dm = NULL; 222062306a36Sopenharmony_ci atomic_inc(&pd->usecnt); 222162306a36Sopenharmony_ci mr->iova = virt_addr; 222262306a36Sopenharmony_ci mr->length = length; 222362306a36Sopenharmony_ci 222462306a36Sopenharmony_ci rdma_restrack_new(&mr->res, RDMA_RESTRACK_MR); 222562306a36Sopenharmony_ci rdma_restrack_parent_name(&mr->res, &pd->res); 222662306a36Sopenharmony_ci rdma_restrack_add(&mr->res); 222762306a36Sopenharmony_ci 222862306a36Sopenharmony_ci return mr; 222962306a36Sopenharmony_ci} 223062306a36Sopenharmony_ciEXPORT_SYMBOL(ib_reg_user_mr); 223162306a36Sopenharmony_ci 223262306a36Sopenharmony_ciint ib_advise_mr(struct ib_pd *pd, enum ib_uverbs_advise_mr_advice advice, 223362306a36Sopenharmony_ci u32 flags, struct ib_sge *sg_list, u32 num_sge) 223462306a36Sopenharmony_ci{ 223562306a36Sopenharmony_ci if (!pd->device->ops.advise_mr) 223662306a36Sopenharmony_ci return -EOPNOTSUPP; 223762306a36Sopenharmony_ci 223862306a36Sopenharmony_ci if (!num_sge) 223962306a36Sopenharmony_ci return 0; 224062306a36Sopenharmony_ci 224162306a36Sopenharmony_ci return pd->device->ops.advise_mr(pd, advice, flags, sg_list, num_sge, 224262306a36Sopenharmony_ci NULL); 224362306a36Sopenharmony_ci} 224462306a36Sopenharmony_ciEXPORT_SYMBOL(ib_advise_mr); 224562306a36Sopenharmony_ci 224662306a36Sopenharmony_ciint ib_dereg_mr_user(struct ib_mr *mr, struct ib_udata *udata) 224762306a36Sopenharmony_ci{ 224862306a36Sopenharmony_ci struct ib_pd *pd = mr->pd; 224962306a36Sopenharmony_ci struct ib_dm *dm = mr->dm; 225062306a36Sopenharmony_ci struct ib_sig_attrs *sig_attrs = mr->sig_attrs; 225162306a36Sopenharmony_ci int ret; 225262306a36Sopenharmony_ci 225362306a36Sopenharmony_ci trace_mr_dereg(mr); 225462306a36Sopenharmony_ci rdma_restrack_del(&mr->res); 225562306a36Sopenharmony_ci ret = mr->device->ops.dereg_mr(mr, udata); 225662306a36Sopenharmony_ci if (!ret) { 225762306a36Sopenharmony_ci atomic_dec(&pd->usecnt); 225862306a36Sopenharmony_ci if (dm) 225962306a36Sopenharmony_ci atomic_dec(&dm->usecnt); 226062306a36Sopenharmony_ci kfree(sig_attrs); 226162306a36Sopenharmony_ci } 226262306a36Sopenharmony_ci 226362306a36Sopenharmony_ci return ret; 226462306a36Sopenharmony_ci} 226562306a36Sopenharmony_ciEXPORT_SYMBOL(ib_dereg_mr_user); 226662306a36Sopenharmony_ci 226762306a36Sopenharmony_ci/** 226862306a36Sopenharmony_ci * ib_alloc_mr() - Allocates a memory region 226962306a36Sopenharmony_ci * @pd: protection domain associated with the region 227062306a36Sopenharmony_ci * @mr_type: memory region type 227162306a36Sopenharmony_ci * @max_num_sg: maximum sg entries available for registration. 227262306a36Sopenharmony_ci * 227362306a36Sopenharmony_ci * Notes: 227462306a36Sopenharmony_ci * Memory registeration page/sg lists must not exceed max_num_sg. 227562306a36Sopenharmony_ci * For mr_type IB_MR_TYPE_MEM_REG, the total length cannot exceed 227662306a36Sopenharmony_ci * max_num_sg * used_page_size. 227762306a36Sopenharmony_ci * 227862306a36Sopenharmony_ci */ 227962306a36Sopenharmony_cistruct ib_mr *ib_alloc_mr(struct ib_pd *pd, enum ib_mr_type mr_type, 228062306a36Sopenharmony_ci u32 max_num_sg) 228162306a36Sopenharmony_ci{ 228262306a36Sopenharmony_ci struct ib_mr *mr; 228362306a36Sopenharmony_ci 228462306a36Sopenharmony_ci if (!pd->device->ops.alloc_mr) { 228562306a36Sopenharmony_ci mr = ERR_PTR(-EOPNOTSUPP); 228662306a36Sopenharmony_ci goto out; 228762306a36Sopenharmony_ci } 228862306a36Sopenharmony_ci 228962306a36Sopenharmony_ci if (mr_type == IB_MR_TYPE_INTEGRITY) { 229062306a36Sopenharmony_ci WARN_ON_ONCE(1); 229162306a36Sopenharmony_ci mr = ERR_PTR(-EINVAL); 229262306a36Sopenharmony_ci goto out; 229362306a36Sopenharmony_ci } 229462306a36Sopenharmony_ci 229562306a36Sopenharmony_ci mr = pd->device->ops.alloc_mr(pd, mr_type, max_num_sg); 229662306a36Sopenharmony_ci if (IS_ERR(mr)) 229762306a36Sopenharmony_ci goto out; 229862306a36Sopenharmony_ci 229962306a36Sopenharmony_ci mr->device = pd->device; 230062306a36Sopenharmony_ci mr->pd = pd; 230162306a36Sopenharmony_ci mr->dm = NULL; 230262306a36Sopenharmony_ci mr->uobject = NULL; 230362306a36Sopenharmony_ci atomic_inc(&pd->usecnt); 230462306a36Sopenharmony_ci mr->need_inval = false; 230562306a36Sopenharmony_ci mr->type = mr_type; 230662306a36Sopenharmony_ci mr->sig_attrs = NULL; 230762306a36Sopenharmony_ci 230862306a36Sopenharmony_ci rdma_restrack_new(&mr->res, RDMA_RESTRACK_MR); 230962306a36Sopenharmony_ci rdma_restrack_parent_name(&mr->res, &pd->res); 231062306a36Sopenharmony_ci rdma_restrack_add(&mr->res); 231162306a36Sopenharmony_ciout: 231262306a36Sopenharmony_ci trace_mr_alloc(pd, mr_type, max_num_sg, mr); 231362306a36Sopenharmony_ci return mr; 231462306a36Sopenharmony_ci} 231562306a36Sopenharmony_ciEXPORT_SYMBOL(ib_alloc_mr); 231662306a36Sopenharmony_ci 231762306a36Sopenharmony_ci/** 231862306a36Sopenharmony_ci * ib_alloc_mr_integrity() - Allocates an integrity memory region 231962306a36Sopenharmony_ci * @pd: protection domain associated with the region 232062306a36Sopenharmony_ci * @max_num_data_sg: maximum data sg entries available for registration 232162306a36Sopenharmony_ci * @max_num_meta_sg: maximum metadata sg entries available for 232262306a36Sopenharmony_ci * registration 232362306a36Sopenharmony_ci * 232462306a36Sopenharmony_ci * Notes: 232562306a36Sopenharmony_ci * Memory registration page/sg lists must not exceed max_num_sg, 232662306a36Sopenharmony_ci * also the integrity page/sg lists must not exceed max_num_meta_sg. 232762306a36Sopenharmony_ci * 232862306a36Sopenharmony_ci */ 232962306a36Sopenharmony_cistruct ib_mr *ib_alloc_mr_integrity(struct ib_pd *pd, 233062306a36Sopenharmony_ci u32 max_num_data_sg, 233162306a36Sopenharmony_ci u32 max_num_meta_sg) 233262306a36Sopenharmony_ci{ 233362306a36Sopenharmony_ci struct ib_mr *mr; 233462306a36Sopenharmony_ci struct ib_sig_attrs *sig_attrs; 233562306a36Sopenharmony_ci 233662306a36Sopenharmony_ci if (!pd->device->ops.alloc_mr_integrity || 233762306a36Sopenharmony_ci !pd->device->ops.map_mr_sg_pi) { 233862306a36Sopenharmony_ci mr = ERR_PTR(-EOPNOTSUPP); 233962306a36Sopenharmony_ci goto out; 234062306a36Sopenharmony_ci } 234162306a36Sopenharmony_ci 234262306a36Sopenharmony_ci if (!max_num_meta_sg) { 234362306a36Sopenharmony_ci mr = ERR_PTR(-EINVAL); 234462306a36Sopenharmony_ci goto out; 234562306a36Sopenharmony_ci } 234662306a36Sopenharmony_ci 234762306a36Sopenharmony_ci sig_attrs = kzalloc(sizeof(struct ib_sig_attrs), GFP_KERNEL); 234862306a36Sopenharmony_ci if (!sig_attrs) { 234962306a36Sopenharmony_ci mr = ERR_PTR(-ENOMEM); 235062306a36Sopenharmony_ci goto out; 235162306a36Sopenharmony_ci } 235262306a36Sopenharmony_ci 235362306a36Sopenharmony_ci mr = pd->device->ops.alloc_mr_integrity(pd, max_num_data_sg, 235462306a36Sopenharmony_ci max_num_meta_sg); 235562306a36Sopenharmony_ci if (IS_ERR(mr)) { 235662306a36Sopenharmony_ci kfree(sig_attrs); 235762306a36Sopenharmony_ci goto out; 235862306a36Sopenharmony_ci } 235962306a36Sopenharmony_ci 236062306a36Sopenharmony_ci mr->device = pd->device; 236162306a36Sopenharmony_ci mr->pd = pd; 236262306a36Sopenharmony_ci mr->dm = NULL; 236362306a36Sopenharmony_ci mr->uobject = NULL; 236462306a36Sopenharmony_ci atomic_inc(&pd->usecnt); 236562306a36Sopenharmony_ci mr->need_inval = false; 236662306a36Sopenharmony_ci mr->type = IB_MR_TYPE_INTEGRITY; 236762306a36Sopenharmony_ci mr->sig_attrs = sig_attrs; 236862306a36Sopenharmony_ci 236962306a36Sopenharmony_ci rdma_restrack_new(&mr->res, RDMA_RESTRACK_MR); 237062306a36Sopenharmony_ci rdma_restrack_parent_name(&mr->res, &pd->res); 237162306a36Sopenharmony_ci rdma_restrack_add(&mr->res); 237262306a36Sopenharmony_ciout: 237362306a36Sopenharmony_ci trace_mr_integ_alloc(pd, max_num_data_sg, max_num_meta_sg, mr); 237462306a36Sopenharmony_ci return mr; 237562306a36Sopenharmony_ci} 237662306a36Sopenharmony_ciEXPORT_SYMBOL(ib_alloc_mr_integrity); 237762306a36Sopenharmony_ci 237862306a36Sopenharmony_ci/* Multicast groups */ 237962306a36Sopenharmony_ci 238062306a36Sopenharmony_cistatic bool is_valid_mcast_lid(struct ib_qp *qp, u16 lid) 238162306a36Sopenharmony_ci{ 238262306a36Sopenharmony_ci struct ib_qp_init_attr init_attr = {}; 238362306a36Sopenharmony_ci struct ib_qp_attr attr = {}; 238462306a36Sopenharmony_ci int num_eth_ports = 0; 238562306a36Sopenharmony_ci unsigned int port; 238662306a36Sopenharmony_ci 238762306a36Sopenharmony_ci /* If QP state >= init, it is assigned to a port and we can check this 238862306a36Sopenharmony_ci * port only. 238962306a36Sopenharmony_ci */ 239062306a36Sopenharmony_ci if (!ib_query_qp(qp, &attr, IB_QP_STATE | IB_QP_PORT, &init_attr)) { 239162306a36Sopenharmony_ci if (attr.qp_state >= IB_QPS_INIT) { 239262306a36Sopenharmony_ci if (rdma_port_get_link_layer(qp->device, attr.port_num) != 239362306a36Sopenharmony_ci IB_LINK_LAYER_INFINIBAND) 239462306a36Sopenharmony_ci return true; 239562306a36Sopenharmony_ci goto lid_check; 239662306a36Sopenharmony_ci } 239762306a36Sopenharmony_ci } 239862306a36Sopenharmony_ci 239962306a36Sopenharmony_ci /* Can't get a quick answer, iterate over all ports */ 240062306a36Sopenharmony_ci rdma_for_each_port(qp->device, port) 240162306a36Sopenharmony_ci if (rdma_port_get_link_layer(qp->device, port) != 240262306a36Sopenharmony_ci IB_LINK_LAYER_INFINIBAND) 240362306a36Sopenharmony_ci num_eth_ports++; 240462306a36Sopenharmony_ci 240562306a36Sopenharmony_ci /* If we have at lease one Ethernet port, RoCE annex declares that 240662306a36Sopenharmony_ci * multicast LID should be ignored. We can't tell at this step if the 240762306a36Sopenharmony_ci * QP belongs to an IB or Ethernet port. 240862306a36Sopenharmony_ci */ 240962306a36Sopenharmony_ci if (num_eth_ports) 241062306a36Sopenharmony_ci return true; 241162306a36Sopenharmony_ci 241262306a36Sopenharmony_ci /* If all the ports are IB, we can check according to IB spec. */ 241362306a36Sopenharmony_cilid_check: 241462306a36Sopenharmony_ci return !(lid < be16_to_cpu(IB_MULTICAST_LID_BASE) || 241562306a36Sopenharmony_ci lid == be16_to_cpu(IB_LID_PERMISSIVE)); 241662306a36Sopenharmony_ci} 241762306a36Sopenharmony_ci 241862306a36Sopenharmony_ciint ib_attach_mcast(struct ib_qp *qp, union ib_gid *gid, u16 lid) 241962306a36Sopenharmony_ci{ 242062306a36Sopenharmony_ci int ret; 242162306a36Sopenharmony_ci 242262306a36Sopenharmony_ci if (!qp->device->ops.attach_mcast) 242362306a36Sopenharmony_ci return -EOPNOTSUPP; 242462306a36Sopenharmony_ci 242562306a36Sopenharmony_ci if (!rdma_is_multicast_addr((struct in6_addr *)gid->raw) || 242662306a36Sopenharmony_ci qp->qp_type != IB_QPT_UD || !is_valid_mcast_lid(qp, lid)) 242762306a36Sopenharmony_ci return -EINVAL; 242862306a36Sopenharmony_ci 242962306a36Sopenharmony_ci ret = qp->device->ops.attach_mcast(qp, gid, lid); 243062306a36Sopenharmony_ci if (!ret) 243162306a36Sopenharmony_ci atomic_inc(&qp->usecnt); 243262306a36Sopenharmony_ci return ret; 243362306a36Sopenharmony_ci} 243462306a36Sopenharmony_ciEXPORT_SYMBOL(ib_attach_mcast); 243562306a36Sopenharmony_ci 243662306a36Sopenharmony_ciint ib_detach_mcast(struct ib_qp *qp, union ib_gid *gid, u16 lid) 243762306a36Sopenharmony_ci{ 243862306a36Sopenharmony_ci int ret; 243962306a36Sopenharmony_ci 244062306a36Sopenharmony_ci if (!qp->device->ops.detach_mcast) 244162306a36Sopenharmony_ci return -EOPNOTSUPP; 244262306a36Sopenharmony_ci 244362306a36Sopenharmony_ci if (!rdma_is_multicast_addr((struct in6_addr *)gid->raw) || 244462306a36Sopenharmony_ci qp->qp_type != IB_QPT_UD || !is_valid_mcast_lid(qp, lid)) 244562306a36Sopenharmony_ci return -EINVAL; 244662306a36Sopenharmony_ci 244762306a36Sopenharmony_ci ret = qp->device->ops.detach_mcast(qp, gid, lid); 244862306a36Sopenharmony_ci if (!ret) 244962306a36Sopenharmony_ci atomic_dec(&qp->usecnt); 245062306a36Sopenharmony_ci return ret; 245162306a36Sopenharmony_ci} 245262306a36Sopenharmony_ciEXPORT_SYMBOL(ib_detach_mcast); 245362306a36Sopenharmony_ci 245462306a36Sopenharmony_ci/** 245562306a36Sopenharmony_ci * ib_alloc_xrcd_user - Allocates an XRC domain. 245662306a36Sopenharmony_ci * @device: The device on which to allocate the XRC domain. 245762306a36Sopenharmony_ci * @inode: inode to connect XRCD 245862306a36Sopenharmony_ci * @udata: Valid user data or NULL for kernel object 245962306a36Sopenharmony_ci */ 246062306a36Sopenharmony_cistruct ib_xrcd *ib_alloc_xrcd_user(struct ib_device *device, 246162306a36Sopenharmony_ci struct inode *inode, struct ib_udata *udata) 246262306a36Sopenharmony_ci{ 246362306a36Sopenharmony_ci struct ib_xrcd *xrcd; 246462306a36Sopenharmony_ci int ret; 246562306a36Sopenharmony_ci 246662306a36Sopenharmony_ci if (!device->ops.alloc_xrcd) 246762306a36Sopenharmony_ci return ERR_PTR(-EOPNOTSUPP); 246862306a36Sopenharmony_ci 246962306a36Sopenharmony_ci xrcd = rdma_zalloc_drv_obj(device, ib_xrcd); 247062306a36Sopenharmony_ci if (!xrcd) 247162306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 247262306a36Sopenharmony_ci 247362306a36Sopenharmony_ci xrcd->device = device; 247462306a36Sopenharmony_ci xrcd->inode = inode; 247562306a36Sopenharmony_ci atomic_set(&xrcd->usecnt, 0); 247662306a36Sopenharmony_ci init_rwsem(&xrcd->tgt_qps_rwsem); 247762306a36Sopenharmony_ci xa_init(&xrcd->tgt_qps); 247862306a36Sopenharmony_ci 247962306a36Sopenharmony_ci ret = device->ops.alloc_xrcd(xrcd, udata); 248062306a36Sopenharmony_ci if (ret) 248162306a36Sopenharmony_ci goto err; 248262306a36Sopenharmony_ci return xrcd; 248362306a36Sopenharmony_cierr: 248462306a36Sopenharmony_ci kfree(xrcd); 248562306a36Sopenharmony_ci return ERR_PTR(ret); 248662306a36Sopenharmony_ci} 248762306a36Sopenharmony_ciEXPORT_SYMBOL(ib_alloc_xrcd_user); 248862306a36Sopenharmony_ci 248962306a36Sopenharmony_ci/** 249062306a36Sopenharmony_ci * ib_dealloc_xrcd_user - Deallocates an XRC domain. 249162306a36Sopenharmony_ci * @xrcd: The XRC domain to deallocate. 249262306a36Sopenharmony_ci * @udata: Valid user data or NULL for kernel object 249362306a36Sopenharmony_ci */ 249462306a36Sopenharmony_ciint ib_dealloc_xrcd_user(struct ib_xrcd *xrcd, struct ib_udata *udata) 249562306a36Sopenharmony_ci{ 249662306a36Sopenharmony_ci int ret; 249762306a36Sopenharmony_ci 249862306a36Sopenharmony_ci if (atomic_read(&xrcd->usecnt)) 249962306a36Sopenharmony_ci return -EBUSY; 250062306a36Sopenharmony_ci 250162306a36Sopenharmony_ci WARN_ON(!xa_empty(&xrcd->tgt_qps)); 250262306a36Sopenharmony_ci ret = xrcd->device->ops.dealloc_xrcd(xrcd, udata); 250362306a36Sopenharmony_ci if (ret) 250462306a36Sopenharmony_ci return ret; 250562306a36Sopenharmony_ci kfree(xrcd); 250662306a36Sopenharmony_ci return ret; 250762306a36Sopenharmony_ci} 250862306a36Sopenharmony_ciEXPORT_SYMBOL(ib_dealloc_xrcd_user); 250962306a36Sopenharmony_ci 251062306a36Sopenharmony_ci/** 251162306a36Sopenharmony_ci * ib_create_wq - Creates a WQ associated with the specified protection 251262306a36Sopenharmony_ci * domain. 251362306a36Sopenharmony_ci * @pd: The protection domain associated with the WQ. 251462306a36Sopenharmony_ci * @wq_attr: A list of initial attributes required to create the 251562306a36Sopenharmony_ci * WQ. If WQ creation succeeds, then the attributes are updated to 251662306a36Sopenharmony_ci * the actual capabilities of the created WQ. 251762306a36Sopenharmony_ci * 251862306a36Sopenharmony_ci * wq_attr->max_wr and wq_attr->max_sge determine 251962306a36Sopenharmony_ci * the requested size of the WQ, and set to the actual values allocated 252062306a36Sopenharmony_ci * on return. 252162306a36Sopenharmony_ci * If ib_create_wq() succeeds, then max_wr and max_sge will always be 252262306a36Sopenharmony_ci * at least as large as the requested values. 252362306a36Sopenharmony_ci */ 252462306a36Sopenharmony_cistruct ib_wq *ib_create_wq(struct ib_pd *pd, 252562306a36Sopenharmony_ci struct ib_wq_init_attr *wq_attr) 252662306a36Sopenharmony_ci{ 252762306a36Sopenharmony_ci struct ib_wq *wq; 252862306a36Sopenharmony_ci 252962306a36Sopenharmony_ci if (!pd->device->ops.create_wq) 253062306a36Sopenharmony_ci return ERR_PTR(-EOPNOTSUPP); 253162306a36Sopenharmony_ci 253262306a36Sopenharmony_ci wq = pd->device->ops.create_wq(pd, wq_attr, NULL); 253362306a36Sopenharmony_ci if (!IS_ERR(wq)) { 253462306a36Sopenharmony_ci wq->event_handler = wq_attr->event_handler; 253562306a36Sopenharmony_ci wq->wq_context = wq_attr->wq_context; 253662306a36Sopenharmony_ci wq->wq_type = wq_attr->wq_type; 253762306a36Sopenharmony_ci wq->cq = wq_attr->cq; 253862306a36Sopenharmony_ci wq->device = pd->device; 253962306a36Sopenharmony_ci wq->pd = pd; 254062306a36Sopenharmony_ci wq->uobject = NULL; 254162306a36Sopenharmony_ci atomic_inc(&pd->usecnt); 254262306a36Sopenharmony_ci atomic_inc(&wq_attr->cq->usecnt); 254362306a36Sopenharmony_ci atomic_set(&wq->usecnt, 0); 254462306a36Sopenharmony_ci } 254562306a36Sopenharmony_ci return wq; 254662306a36Sopenharmony_ci} 254762306a36Sopenharmony_ciEXPORT_SYMBOL(ib_create_wq); 254862306a36Sopenharmony_ci 254962306a36Sopenharmony_ci/** 255062306a36Sopenharmony_ci * ib_destroy_wq_user - Destroys the specified user WQ. 255162306a36Sopenharmony_ci * @wq: The WQ to destroy. 255262306a36Sopenharmony_ci * @udata: Valid user data 255362306a36Sopenharmony_ci */ 255462306a36Sopenharmony_ciint ib_destroy_wq_user(struct ib_wq *wq, struct ib_udata *udata) 255562306a36Sopenharmony_ci{ 255662306a36Sopenharmony_ci struct ib_cq *cq = wq->cq; 255762306a36Sopenharmony_ci struct ib_pd *pd = wq->pd; 255862306a36Sopenharmony_ci int ret; 255962306a36Sopenharmony_ci 256062306a36Sopenharmony_ci if (atomic_read(&wq->usecnt)) 256162306a36Sopenharmony_ci return -EBUSY; 256262306a36Sopenharmony_ci 256362306a36Sopenharmony_ci ret = wq->device->ops.destroy_wq(wq, udata); 256462306a36Sopenharmony_ci if (ret) 256562306a36Sopenharmony_ci return ret; 256662306a36Sopenharmony_ci 256762306a36Sopenharmony_ci atomic_dec(&pd->usecnt); 256862306a36Sopenharmony_ci atomic_dec(&cq->usecnt); 256962306a36Sopenharmony_ci return ret; 257062306a36Sopenharmony_ci} 257162306a36Sopenharmony_ciEXPORT_SYMBOL(ib_destroy_wq_user); 257262306a36Sopenharmony_ci 257362306a36Sopenharmony_ciint ib_check_mr_status(struct ib_mr *mr, u32 check_mask, 257462306a36Sopenharmony_ci struct ib_mr_status *mr_status) 257562306a36Sopenharmony_ci{ 257662306a36Sopenharmony_ci if (!mr->device->ops.check_mr_status) 257762306a36Sopenharmony_ci return -EOPNOTSUPP; 257862306a36Sopenharmony_ci 257962306a36Sopenharmony_ci return mr->device->ops.check_mr_status(mr, check_mask, mr_status); 258062306a36Sopenharmony_ci} 258162306a36Sopenharmony_ciEXPORT_SYMBOL(ib_check_mr_status); 258262306a36Sopenharmony_ci 258362306a36Sopenharmony_ciint ib_set_vf_link_state(struct ib_device *device, int vf, u32 port, 258462306a36Sopenharmony_ci int state) 258562306a36Sopenharmony_ci{ 258662306a36Sopenharmony_ci if (!device->ops.set_vf_link_state) 258762306a36Sopenharmony_ci return -EOPNOTSUPP; 258862306a36Sopenharmony_ci 258962306a36Sopenharmony_ci return device->ops.set_vf_link_state(device, vf, port, state); 259062306a36Sopenharmony_ci} 259162306a36Sopenharmony_ciEXPORT_SYMBOL(ib_set_vf_link_state); 259262306a36Sopenharmony_ci 259362306a36Sopenharmony_ciint ib_get_vf_config(struct ib_device *device, int vf, u32 port, 259462306a36Sopenharmony_ci struct ifla_vf_info *info) 259562306a36Sopenharmony_ci{ 259662306a36Sopenharmony_ci if (!device->ops.get_vf_config) 259762306a36Sopenharmony_ci return -EOPNOTSUPP; 259862306a36Sopenharmony_ci 259962306a36Sopenharmony_ci return device->ops.get_vf_config(device, vf, port, info); 260062306a36Sopenharmony_ci} 260162306a36Sopenharmony_ciEXPORT_SYMBOL(ib_get_vf_config); 260262306a36Sopenharmony_ci 260362306a36Sopenharmony_ciint ib_get_vf_stats(struct ib_device *device, int vf, u32 port, 260462306a36Sopenharmony_ci struct ifla_vf_stats *stats) 260562306a36Sopenharmony_ci{ 260662306a36Sopenharmony_ci if (!device->ops.get_vf_stats) 260762306a36Sopenharmony_ci return -EOPNOTSUPP; 260862306a36Sopenharmony_ci 260962306a36Sopenharmony_ci return device->ops.get_vf_stats(device, vf, port, stats); 261062306a36Sopenharmony_ci} 261162306a36Sopenharmony_ciEXPORT_SYMBOL(ib_get_vf_stats); 261262306a36Sopenharmony_ci 261362306a36Sopenharmony_ciint ib_set_vf_guid(struct ib_device *device, int vf, u32 port, u64 guid, 261462306a36Sopenharmony_ci int type) 261562306a36Sopenharmony_ci{ 261662306a36Sopenharmony_ci if (!device->ops.set_vf_guid) 261762306a36Sopenharmony_ci return -EOPNOTSUPP; 261862306a36Sopenharmony_ci 261962306a36Sopenharmony_ci return device->ops.set_vf_guid(device, vf, port, guid, type); 262062306a36Sopenharmony_ci} 262162306a36Sopenharmony_ciEXPORT_SYMBOL(ib_set_vf_guid); 262262306a36Sopenharmony_ci 262362306a36Sopenharmony_ciint ib_get_vf_guid(struct ib_device *device, int vf, u32 port, 262462306a36Sopenharmony_ci struct ifla_vf_guid *node_guid, 262562306a36Sopenharmony_ci struct ifla_vf_guid *port_guid) 262662306a36Sopenharmony_ci{ 262762306a36Sopenharmony_ci if (!device->ops.get_vf_guid) 262862306a36Sopenharmony_ci return -EOPNOTSUPP; 262962306a36Sopenharmony_ci 263062306a36Sopenharmony_ci return device->ops.get_vf_guid(device, vf, port, node_guid, port_guid); 263162306a36Sopenharmony_ci} 263262306a36Sopenharmony_ciEXPORT_SYMBOL(ib_get_vf_guid); 263362306a36Sopenharmony_ci/** 263462306a36Sopenharmony_ci * ib_map_mr_sg_pi() - Map the dma mapped SG lists for PI (protection 263562306a36Sopenharmony_ci * information) and set an appropriate memory region for registration. 263662306a36Sopenharmony_ci * @mr: memory region 263762306a36Sopenharmony_ci * @data_sg: dma mapped scatterlist for data 263862306a36Sopenharmony_ci * @data_sg_nents: number of entries in data_sg 263962306a36Sopenharmony_ci * @data_sg_offset: offset in bytes into data_sg 264062306a36Sopenharmony_ci * @meta_sg: dma mapped scatterlist for metadata 264162306a36Sopenharmony_ci * @meta_sg_nents: number of entries in meta_sg 264262306a36Sopenharmony_ci * @meta_sg_offset: offset in bytes into meta_sg 264362306a36Sopenharmony_ci * @page_size: page vector desired page size 264462306a36Sopenharmony_ci * 264562306a36Sopenharmony_ci * Constraints: 264662306a36Sopenharmony_ci * - The MR must be allocated with type IB_MR_TYPE_INTEGRITY. 264762306a36Sopenharmony_ci * 264862306a36Sopenharmony_ci * Return: 0 on success. 264962306a36Sopenharmony_ci * 265062306a36Sopenharmony_ci * After this completes successfully, the memory region 265162306a36Sopenharmony_ci * is ready for registration. 265262306a36Sopenharmony_ci */ 265362306a36Sopenharmony_ciint ib_map_mr_sg_pi(struct ib_mr *mr, struct scatterlist *data_sg, 265462306a36Sopenharmony_ci int data_sg_nents, unsigned int *data_sg_offset, 265562306a36Sopenharmony_ci struct scatterlist *meta_sg, int meta_sg_nents, 265662306a36Sopenharmony_ci unsigned int *meta_sg_offset, unsigned int page_size) 265762306a36Sopenharmony_ci{ 265862306a36Sopenharmony_ci if (unlikely(!mr->device->ops.map_mr_sg_pi || 265962306a36Sopenharmony_ci WARN_ON_ONCE(mr->type != IB_MR_TYPE_INTEGRITY))) 266062306a36Sopenharmony_ci return -EOPNOTSUPP; 266162306a36Sopenharmony_ci 266262306a36Sopenharmony_ci mr->page_size = page_size; 266362306a36Sopenharmony_ci 266462306a36Sopenharmony_ci return mr->device->ops.map_mr_sg_pi(mr, data_sg, data_sg_nents, 266562306a36Sopenharmony_ci data_sg_offset, meta_sg, 266662306a36Sopenharmony_ci meta_sg_nents, meta_sg_offset); 266762306a36Sopenharmony_ci} 266862306a36Sopenharmony_ciEXPORT_SYMBOL(ib_map_mr_sg_pi); 266962306a36Sopenharmony_ci 267062306a36Sopenharmony_ci/** 267162306a36Sopenharmony_ci * ib_map_mr_sg() - Map the largest prefix of a dma mapped SG list 267262306a36Sopenharmony_ci * and set it the memory region. 267362306a36Sopenharmony_ci * @mr: memory region 267462306a36Sopenharmony_ci * @sg: dma mapped scatterlist 267562306a36Sopenharmony_ci * @sg_nents: number of entries in sg 267662306a36Sopenharmony_ci * @sg_offset: offset in bytes into sg 267762306a36Sopenharmony_ci * @page_size: page vector desired page size 267862306a36Sopenharmony_ci * 267962306a36Sopenharmony_ci * Constraints: 268062306a36Sopenharmony_ci * 268162306a36Sopenharmony_ci * - The first sg element is allowed to have an offset. 268262306a36Sopenharmony_ci * - Each sg element must either be aligned to page_size or virtually 268362306a36Sopenharmony_ci * contiguous to the previous element. In case an sg element has a 268462306a36Sopenharmony_ci * non-contiguous offset, the mapping prefix will not include it. 268562306a36Sopenharmony_ci * - The last sg element is allowed to have length less than page_size. 268662306a36Sopenharmony_ci * - If sg_nents total byte length exceeds the mr max_num_sge * page_size 268762306a36Sopenharmony_ci * then only max_num_sg entries will be mapped. 268862306a36Sopenharmony_ci * - If the MR was allocated with type IB_MR_TYPE_SG_GAPS, none of these 268962306a36Sopenharmony_ci * constraints holds and the page_size argument is ignored. 269062306a36Sopenharmony_ci * 269162306a36Sopenharmony_ci * Returns the number of sg elements that were mapped to the memory region. 269262306a36Sopenharmony_ci * 269362306a36Sopenharmony_ci * After this completes successfully, the memory region 269462306a36Sopenharmony_ci * is ready for registration. 269562306a36Sopenharmony_ci */ 269662306a36Sopenharmony_ciint ib_map_mr_sg(struct ib_mr *mr, struct scatterlist *sg, int sg_nents, 269762306a36Sopenharmony_ci unsigned int *sg_offset, unsigned int page_size) 269862306a36Sopenharmony_ci{ 269962306a36Sopenharmony_ci if (unlikely(!mr->device->ops.map_mr_sg)) 270062306a36Sopenharmony_ci return -EOPNOTSUPP; 270162306a36Sopenharmony_ci 270262306a36Sopenharmony_ci mr->page_size = page_size; 270362306a36Sopenharmony_ci 270462306a36Sopenharmony_ci return mr->device->ops.map_mr_sg(mr, sg, sg_nents, sg_offset); 270562306a36Sopenharmony_ci} 270662306a36Sopenharmony_ciEXPORT_SYMBOL(ib_map_mr_sg); 270762306a36Sopenharmony_ci 270862306a36Sopenharmony_ci/** 270962306a36Sopenharmony_ci * ib_sg_to_pages() - Convert the largest prefix of a sg list 271062306a36Sopenharmony_ci * to a page vector 271162306a36Sopenharmony_ci * @mr: memory region 271262306a36Sopenharmony_ci * @sgl: dma mapped scatterlist 271362306a36Sopenharmony_ci * @sg_nents: number of entries in sg 271462306a36Sopenharmony_ci * @sg_offset_p: ==== ======================================================= 271562306a36Sopenharmony_ci * IN start offset in bytes into sg 271662306a36Sopenharmony_ci * OUT offset in bytes for element n of the sg of the first 271762306a36Sopenharmony_ci * byte that has not been processed where n is the return 271862306a36Sopenharmony_ci * value of this function. 271962306a36Sopenharmony_ci * ==== ======================================================= 272062306a36Sopenharmony_ci * @set_page: driver page assignment function pointer 272162306a36Sopenharmony_ci * 272262306a36Sopenharmony_ci * Core service helper for drivers to convert the largest 272362306a36Sopenharmony_ci * prefix of given sg list to a page vector. The sg list 272462306a36Sopenharmony_ci * prefix converted is the prefix that meet the requirements 272562306a36Sopenharmony_ci * of ib_map_mr_sg. 272662306a36Sopenharmony_ci * 272762306a36Sopenharmony_ci * Returns the number of sg elements that were assigned to 272862306a36Sopenharmony_ci * a page vector. 272962306a36Sopenharmony_ci */ 273062306a36Sopenharmony_ciint ib_sg_to_pages(struct ib_mr *mr, struct scatterlist *sgl, int sg_nents, 273162306a36Sopenharmony_ci unsigned int *sg_offset_p, int (*set_page)(struct ib_mr *, u64)) 273262306a36Sopenharmony_ci{ 273362306a36Sopenharmony_ci struct scatterlist *sg; 273462306a36Sopenharmony_ci u64 last_end_dma_addr = 0; 273562306a36Sopenharmony_ci unsigned int sg_offset = sg_offset_p ? *sg_offset_p : 0; 273662306a36Sopenharmony_ci unsigned int last_page_off = 0; 273762306a36Sopenharmony_ci u64 page_mask = ~((u64)mr->page_size - 1); 273862306a36Sopenharmony_ci int i, ret; 273962306a36Sopenharmony_ci 274062306a36Sopenharmony_ci if (unlikely(sg_nents <= 0 || sg_offset > sg_dma_len(&sgl[0]))) 274162306a36Sopenharmony_ci return -EINVAL; 274262306a36Sopenharmony_ci 274362306a36Sopenharmony_ci mr->iova = sg_dma_address(&sgl[0]) + sg_offset; 274462306a36Sopenharmony_ci mr->length = 0; 274562306a36Sopenharmony_ci 274662306a36Sopenharmony_ci for_each_sg(sgl, sg, sg_nents, i) { 274762306a36Sopenharmony_ci u64 dma_addr = sg_dma_address(sg) + sg_offset; 274862306a36Sopenharmony_ci u64 prev_addr = dma_addr; 274962306a36Sopenharmony_ci unsigned int dma_len = sg_dma_len(sg) - sg_offset; 275062306a36Sopenharmony_ci u64 end_dma_addr = dma_addr + dma_len; 275162306a36Sopenharmony_ci u64 page_addr = dma_addr & page_mask; 275262306a36Sopenharmony_ci 275362306a36Sopenharmony_ci /* 275462306a36Sopenharmony_ci * For the second and later elements, check whether either the 275562306a36Sopenharmony_ci * end of element i-1 or the start of element i is not aligned 275662306a36Sopenharmony_ci * on a page boundary. 275762306a36Sopenharmony_ci */ 275862306a36Sopenharmony_ci if (i && (last_page_off != 0 || page_addr != dma_addr)) { 275962306a36Sopenharmony_ci /* Stop mapping if there is a gap. */ 276062306a36Sopenharmony_ci if (last_end_dma_addr != dma_addr) 276162306a36Sopenharmony_ci break; 276262306a36Sopenharmony_ci 276362306a36Sopenharmony_ci /* 276462306a36Sopenharmony_ci * Coalesce this element with the last. If it is small 276562306a36Sopenharmony_ci * enough just update mr->length. Otherwise start 276662306a36Sopenharmony_ci * mapping from the next page. 276762306a36Sopenharmony_ci */ 276862306a36Sopenharmony_ci goto next_page; 276962306a36Sopenharmony_ci } 277062306a36Sopenharmony_ci 277162306a36Sopenharmony_ci do { 277262306a36Sopenharmony_ci ret = set_page(mr, page_addr); 277362306a36Sopenharmony_ci if (unlikely(ret < 0)) { 277462306a36Sopenharmony_ci sg_offset = prev_addr - sg_dma_address(sg); 277562306a36Sopenharmony_ci mr->length += prev_addr - dma_addr; 277662306a36Sopenharmony_ci if (sg_offset_p) 277762306a36Sopenharmony_ci *sg_offset_p = sg_offset; 277862306a36Sopenharmony_ci return i || sg_offset ? i : ret; 277962306a36Sopenharmony_ci } 278062306a36Sopenharmony_ci prev_addr = page_addr; 278162306a36Sopenharmony_cinext_page: 278262306a36Sopenharmony_ci page_addr += mr->page_size; 278362306a36Sopenharmony_ci } while (page_addr < end_dma_addr); 278462306a36Sopenharmony_ci 278562306a36Sopenharmony_ci mr->length += dma_len; 278662306a36Sopenharmony_ci last_end_dma_addr = end_dma_addr; 278762306a36Sopenharmony_ci last_page_off = end_dma_addr & ~page_mask; 278862306a36Sopenharmony_ci 278962306a36Sopenharmony_ci sg_offset = 0; 279062306a36Sopenharmony_ci } 279162306a36Sopenharmony_ci 279262306a36Sopenharmony_ci if (sg_offset_p) 279362306a36Sopenharmony_ci *sg_offset_p = 0; 279462306a36Sopenharmony_ci return i; 279562306a36Sopenharmony_ci} 279662306a36Sopenharmony_ciEXPORT_SYMBOL(ib_sg_to_pages); 279762306a36Sopenharmony_ci 279862306a36Sopenharmony_cistruct ib_drain_cqe { 279962306a36Sopenharmony_ci struct ib_cqe cqe; 280062306a36Sopenharmony_ci struct completion done; 280162306a36Sopenharmony_ci}; 280262306a36Sopenharmony_ci 280362306a36Sopenharmony_cistatic void ib_drain_qp_done(struct ib_cq *cq, struct ib_wc *wc) 280462306a36Sopenharmony_ci{ 280562306a36Sopenharmony_ci struct ib_drain_cqe *cqe = container_of(wc->wr_cqe, struct ib_drain_cqe, 280662306a36Sopenharmony_ci cqe); 280762306a36Sopenharmony_ci 280862306a36Sopenharmony_ci complete(&cqe->done); 280962306a36Sopenharmony_ci} 281062306a36Sopenharmony_ci 281162306a36Sopenharmony_ci/* 281262306a36Sopenharmony_ci * Post a WR and block until its completion is reaped for the SQ. 281362306a36Sopenharmony_ci */ 281462306a36Sopenharmony_cistatic void __ib_drain_sq(struct ib_qp *qp) 281562306a36Sopenharmony_ci{ 281662306a36Sopenharmony_ci struct ib_cq *cq = qp->send_cq; 281762306a36Sopenharmony_ci struct ib_qp_attr attr = { .qp_state = IB_QPS_ERR }; 281862306a36Sopenharmony_ci struct ib_drain_cqe sdrain; 281962306a36Sopenharmony_ci struct ib_rdma_wr swr = { 282062306a36Sopenharmony_ci .wr = { 282162306a36Sopenharmony_ci .next = NULL, 282262306a36Sopenharmony_ci { .wr_cqe = &sdrain.cqe, }, 282362306a36Sopenharmony_ci .opcode = IB_WR_RDMA_WRITE, 282462306a36Sopenharmony_ci }, 282562306a36Sopenharmony_ci }; 282662306a36Sopenharmony_ci int ret; 282762306a36Sopenharmony_ci 282862306a36Sopenharmony_ci ret = ib_modify_qp(qp, &attr, IB_QP_STATE); 282962306a36Sopenharmony_ci if (ret) { 283062306a36Sopenharmony_ci WARN_ONCE(ret, "failed to drain send queue: %d\n", ret); 283162306a36Sopenharmony_ci return; 283262306a36Sopenharmony_ci } 283362306a36Sopenharmony_ci 283462306a36Sopenharmony_ci sdrain.cqe.done = ib_drain_qp_done; 283562306a36Sopenharmony_ci init_completion(&sdrain.done); 283662306a36Sopenharmony_ci 283762306a36Sopenharmony_ci ret = ib_post_send(qp, &swr.wr, NULL); 283862306a36Sopenharmony_ci if (ret) { 283962306a36Sopenharmony_ci WARN_ONCE(ret, "failed to drain send queue: %d\n", ret); 284062306a36Sopenharmony_ci return; 284162306a36Sopenharmony_ci } 284262306a36Sopenharmony_ci 284362306a36Sopenharmony_ci if (cq->poll_ctx == IB_POLL_DIRECT) 284462306a36Sopenharmony_ci while (wait_for_completion_timeout(&sdrain.done, HZ / 10) <= 0) 284562306a36Sopenharmony_ci ib_process_cq_direct(cq, -1); 284662306a36Sopenharmony_ci else 284762306a36Sopenharmony_ci wait_for_completion(&sdrain.done); 284862306a36Sopenharmony_ci} 284962306a36Sopenharmony_ci 285062306a36Sopenharmony_ci/* 285162306a36Sopenharmony_ci * Post a WR and block until its completion is reaped for the RQ. 285262306a36Sopenharmony_ci */ 285362306a36Sopenharmony_cistatic void __ib_drain_rq(struct ib_qp *qp) 285462306a36Sopenharmony_ci{ 285562306a36Sopenharmony_ci struct ib_cq *cq = qp->recv_cq; 285662306a36Sopenharmony_ci struct ib_qp_attr attr = { .qp_state = IB_QPS_ERR }; 285762306a36Sopenharmony_ci struct ib_drain_cqe rdrain; 285862306a36Sopenharmony_ci struct ib_recv_wr rwr = {}; 285962306a36Sopenharmony_ci int ret; 286062306a36Sopenharmony_ci 286162306a36Sopenharmony_ci ret = ib_modify_qp(qp, &attr, IB_QP_STATE); 286262306a36Sopenharmony_ci if (ret) { 286362306a36Sopenharmony_ci WARN_ONCE(ret, "failed to drain recv queue: %d\n", ret); 286462306a36Sopenharmony_ci return; 286562306a36Sopenharmony_ci } 286662306a36Sopenharmony_ci 286762306a36Sopenharmony_ci rwr.wr_cqe = &rdrain.cqe; 286862306a36Sopenharmony_ci rdrain.cqe.done = ib_drain_qp_done; 286962306a36Sopenharmony_ci init_completion(&rdrain.done); 287062306a36Sopenharmony_ci 287162306a36Sopenharmony_ci ret = ib_post_recv(qp, &rwr, NULL); 287262306a36Sopenharmony_ci if (ret) { 287362306a36Sopenharmony_ci WARN_ONCE(ret, "failed to drain recv queue: %d\n", ret); 287462306a36Sopenharmony_ci return; 287562306a36Sopenharmony_ci } 287662306a36Sopenharmony_ci 287762306a36Sopenharmony_ci if (cq->poll_ctx == IB_POLL_DIRECT) 287862306a36Sopenharmony_ci while (wait_for_completion_timeout(&rdrain.done, HZ / 10) <= 0) 287962306a36Sopenharmony_ci ib_process_cq_direct(cq, -1); 288062306a36Sopenharmony_ci else 288162306a36Sopenharmony_ci wait_for_completion(&rdrain.done); 288262306a36Sopenharmony_ci} 288362306a36Sopenharmony_ci 288462306a36Sopenharmony_ci/** 288562306a36Sopenharmony_ci * ib_drain_sq() - Block until all SQ CQEs have been consumed by the 288662306a36Sopenharmony_ci * application. 288762306a36Sopenharmony_ci * @qp: queue pair to drain 288862306a36Sopenharmony_ci * 288962306a36Sopenharmony_ci * If the device has a provider-specific drain function, then 289062306a36Sopenharmony_ci * call that. Otherwise call the generic drain function 289162306a36Sopenharmony_ci * __ib_drain_sq(). 289262306a36Sopenharmony_ci * 289362306a36Sopenharmony_ci * The caller must: 289462306a36Sopenharmony_ci * 289562306a36Sopenharmony_ci * ensure there is room in the CQ and SQ for the drain work request and 289662306a36Sopenharmony_ci * completion. 289762306a36Sopenharmony_ci * 289862306a36Sopenharmony_ci * allocate the CQ using ib_alloc_cq(). 289962306a36Sopenharmony_ci * 290062306a36Sopenharmony_ci * ensure that there are no other contexts that are posting WRs concurrently. 290162306a36Sopenharmony_ci * Otherwise the drain is not guaranteed. 290262306a36Sopenharmony_ci */ 290362306a36Sopenharmony_civoid ib_drain_sq(struct ib_qp *qp) 290462306a36Sopenharmony_ci{ 290562306a36Sopenharmony_ci if (qp->device->ops.drain_sq) 290662306a36Sopenharmony_ci qp->device->ops.drain_sq(qp); 290762306a36Sopenharmony_ci else 290862306a36Sopenharmony_ci __ib_drain_sq(qp); 290962306a36Sopenharmony_ci trace_cq_drain_complete(qp->send_cq); 291062306a36Sopenharmony_ci} 291162306a36Sopenharmony_ciEXPORT_SYMBOL(ib_drain_sq); 291262306a36Sopenharmony_ci 291362306a36Sopenharmony_ci/** 291462306a36Sopenharmony_ci * ib_drain_rq() - Block until all RQ CQEs have been consumed by the 291562306a36Sopenharmony_ci * application. 291662306a36Sopenharmony_ci * @qp: queue pair to drain 291762306a36Sopenharmony_ci * 291862306a36Sopenharmony_ci * If the device has a provider-specific drain function, then 291962306a36Sopenharmony_ci * call that. Otherwise call the generic drain function 292062306a36Sopenharmony_ci * __ib_drain_rq(). 292162306a36Sopenharmony_ci * 292262306a36Sopenharmony_ci * The caller must: 292362306a36Sopenharmony_ci * 292462306a36Sopenharmony_ci * ensure there is room in the CQ and RQ for the drain work request and 292562306a36Sopenharmony_ci * completion. 292662306a36Sopenharmony_ci * 292762306a36Sopenharmony_ci * allocate the CQ using ib_alloc_cq(). 292862306a36Sopenharmony_ci * 292962306a36Sopenharmony_ci * ensure that there are no other contexts that are posting WRs concurrently. 293062306a36Sopenharmony_ci * Otherwise the drain is not guaranteed. 293162306a36Sopenharmony_ci */ 293262306a36Sopenharmony_civoid ib_drain_rq(struct ib_qp *qp) 293362306a36Sopenharmony_ci{ 293462306a36Sopenharmony_ci if (qp->device->ops.drain_rq) 293562306a36Sopenharmony_ci qp->device->ops.drain_rq(qp); 293662306a36Sopenharmony_ci else 293762306a36Sopenharmony_ci __ib_drain_rq(qp); 293862306a36Sopenharmony_ci trace_cq_drain_complete(qp->recv_cq); 293962306a36Sopenharmony_ci} 294062306a36Sopenharmony_ciEXPORT_SYMBOL(ib_drain_rq); 294162306a36Sopenharmony_ci 294262306a36Sopenharmony_ci/** 294362306a36Sopenharmony_ci * ib_drain_qp() - Block until all CQEs have been consumed by the 294462306a36Sopenharmony_ci * application on both the RQ and SQ. 294562306a36Sopenharmony_ci * @qp: queue pair to drain 294662306a36Sopenharmony_ci * 294762306a36Sopenharmony_ci * The caller must: 294862306a36Sopenharmony_ci * 294962306a36Sopenharmony_ci * ensure there is room in the CQ(s), SQ, and RQ for drain work requests 295062306a36Sopenharmony_ci * and completions. 295162306a36Sopenharmony_ci * 295262306a36Sopenharmony_ci * allocate the CQs using ib_alloc_cq(). 295362306a36Sopenharmony_ci * 295462306a36Sopenharmony_ci * ensure that there are no other contexts that are posting WRs concurrently. 295562306a36Sopenharmony_ci * Otherwise the drain is not guaranteed. 295662306a36Sopenharmony_ci */ 295762306a36Sopenharmony_civoid ib_drain_qp(struct ib_qp *qp) 295862306a36Sopenharmony_ci{ 295962306a36Sopenharmony_ci ib_drain_sq(qp); 296062306a36Sopenharmony_ci if (!qp->srq) 296162306a36Sopenharmony_ci ib_drain_rq(qp); 296262306a36Sopenharmony_ci} 296362306a36Sopenharmony_ciEXPORT_SYMBOL(ib_drain_qp); 296462306a36Sopenharmony_ci 296562306a36Sopenharmony_cistruct net_device *rdma_alloc_netdev(struct ib_device *device, u32 port_num, 296662306a36Sopenharmony_ci enum rdma_netdev_t type, const char *name, 296762306a36Sopenharmony_ci unsigned char name_assign_type, 296862306a36Sopenharmony_ci void (*setup)(struct net_device *)) 296962306a36Sopenharmony_ci{ 297062306a36Sopenharmony_ci struct rdma_netdev_alloc_params params; 297162306a36Sopenharmony_ci struct net_device *netdev; 297262306a36Sopenharmony_ci int rc; 297362306a36Sopenharmony_ci 297462306a36Sopenharmony_ci if (!device->ops.rdma_netdev_get_params) 297562306a36Sopenharmony_ci return ERR_PTR(-EOPNOTSUPP); 297662306a36Sopenharmony_ci 297762306a36Sopenharmony_ci rc = device->ops.rdma_netdev_get_params(device, port_num, type, 297862306a36Sopenharmony_ci ¶ms); 297962306a36Sopenharmony_ci if (rc) 298062306a36Sopenharmony_ci return ERR_PTR(rc); 298162306a36Sopenharmony_ci 298262306a36Sopenharmony_ci netdev = alloc_netdev_mqs(params.sizeof_priv, name, name_assign_type, 298362306a36Sopenharmony_ci setup, params.txqs, params.rxqs); 298462306a36Sopenharmony_ci if (!netdev) 298562306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 298662306a36Sopenharmony_ci 298762306a36Sopenharmony_ci return netdev; 298862306a36Sopenharmony_ci} 298962306a36Sopenharmony_ciEXPORT_SYMBOL(rdma_alloc_netdev); 299062306a36Sopenharmony_ci 299162306a36Sopenharmony_ciint rdma_init_netdev(struct ib_device *device, u32 port_num, 299262306a36Sopenharmony_ci enum rdma_netdev_t type, const char *name, 299362306a36Sopenharmony_ci unsigned char name_assign_type, 299462306a36Sopenharmony_ci void (*setup)(struct net_device *), 299562306a36Sopenharmony_ci struct net_device *netdev) 299662306a36Sopenharmony_ci{ 299762306a36Sopenharmony_ci struct rdma_netdev_alloc_params params; 299862306a36Sopenharmony_ci int rc; 299962306a36Sopenharmony_ci 300062306a36Sopenharmony_ci if (!device->ops.rdma_netdev_get_params) 300162306a36Sopenharmony_ci return -EOPNOTSUPP; 300262306a36Sopenharmony_ci 300362306a36Sopenharmony_ci rc = device->ops.rdma_netdev_get_params(device, port_num, type, 300462306a36Sopenharmony_ci ¶ms); 300562306a36Sopenharmony_ci if (rc) 300662306a36Sopenharmony_ci return rc; 300762306a36Sopenharmony_ci 300862306a36Sopenharmony_ci return params.initialize_rdma_netdev(device, port_num, 300962306a36Sopenharmony_ci netdev, params.param); 301062306a36Sopenharmony_ci} 301162306a36Sopenharmony_ciEXPORT_SYMBOL(rdma_init_netdev); 301262306a36Sopenharmony_ci 301362306a36Sopenharmony_civoid __rdma_block_iter_start(struct ib_block_iter *biter, 301462306a36Sopenharmony_ci struct scatterlist *sglist, unsigned int nents, 301562306a36Sopenharmony_ci unsigned long pgsz) 301662306a36Sopenharmony_ci{ 301762306a36Sopenharmony_ci memset(biter, 0, sizeof(struct ib_block_iter)); 301862306a36Sopenharmony_ci biter->__sg = sglist; 301962306a36Sopenharmony_ci biter->__sg_nents = nents; 302062306a36Sopenharmony_ci 302162306a36Sopenharmony_ci /* Driver provides best block size to use */ 302262306a36Sopenharmony_ci biter->__pg_bit = __fls(pgsz); 302362306a36Sopenharmony_ci} 302462306a36Sopenharmony_ciEXPORT_SYMBOL(__rdma_block_iter_start); 302562306a36Sopenharmony_ci 302662306a36Sopenharmony_cibool __rdma_block_iter_next(struct ib_block_iter *biter) 302762306a36Sopenharmony_ci{ 302862306a36Sopenharmony_ci unsigned int block_offset; 302962306a36Sopenharmony_ci unsigned int sg_delta; 303062306a36Sopenharmony_ci 303162306a36Sopenharmony_ci if (!biter->__sg_nents || !biter->__sg) 303262306a36Sopenharmony_ci return false; 303362306a36Sopenharmony_ci 303462306a36Sopenharmony_ci biter->__dma_addr = sg_dma_address(biter->__sg) + biter->__sg_advance; 303562306a36Sopenharmony_ci block_offset = biter->__dma_addr & (BIT_ULL(biter->__pg_bit) - 1); 303662306a36Sopenharmony_ci sg_delta = BIT_ULL(biter->__pg_bit) - block_offset; 303762306a36Sopenharmony_ci 303862306a36Sopenharmony_ci if (sg_dma_len(biter->__sg) - biter->__sg_advance > sg_delta) { 303962306a36Sopenharmony_ci biter->__sg_advance += sg_delta; 304062306a36Sopenharmony_ci } else { 304162306a36Sopenharmony_ci biter->__sg_advance = 0; 304262306a36Sopenharmony_ci biter->__sg = sg_next(biter->__sg); 304362306a36Sopenharmony_ci biter->__sg_nents--; 304462306a36Sopenharmony_ci } 304562306a36Sopenharmony_ci 304662306a36Sopenharmony_ci return true; 304762306a36Sopenharmony_ci} 304862306a36Sopenharmony_ciEXPORT_SYMBOL(__rdma_block_iter_next); 304962306a36Sopenharmony_ci 305062306a36Sopenharmony_ci/** 305162306a36Sopenharmony_ci * rdma_alloc_hw_stats_struct - Helper function to allocate dynamic struct 305262306a36Sopenharmony_ci * for the drivers. 305362306a36Sopenharmony_ci * @descs: array of static descriptors 305462306a36Sopenharmony_ci * @num_counters: number of elements in array 305562306a36Sopenharmony_ci * @lifespan: milliseconds between updates 305662306a36Sopenharmony_ci */ 305762306a36Sopenharmony_cistruct rdma_hw_stats *rdma_alloc_hw_stats_struct( 305862306a36Sopenharmony_ci const struct rdma_stat_desc *descs, int num_counters, 305962306a36Sopenharmony_ci unsigned long lifespan) 306062306a36Sopenharmony_ci{ 306162306a36Sopenharmony_ci struct rdma_hw_stats *stats; 306262306a36Sopenharmony_ci 306362306a36Sopenharmony_ci stats = kzalloc(struct_size(stats, value, num_counters), GFP_KERNEL); 306462306a36Sopenharmony_ci if (!stats) 306562306a36Sopenharmony_ci return NULL; 306662306a36Sopenharmony_ci 306762306a36Sopenharmony_ci stats->is_disabled = kcalloc(BITS_TO_LONGS(num_counters), 306862306a36Sopenharmony_ci sizeof(*stats->is_disabled), GFP_KERNEL); 306962306a36Sopenharmony_ci if (!stats->is_disabled) 307062306a36Sopenharmony_ci goto err; 307162306a36Sopenharmony_ci 307262306a36Sopenharmony_ci stats->descs = descs; 307362306a36Sopenharmony_ci stats->num_counters = num_counters; 307462306a36Sopenharmony_ci stats->lifespan = msecs_to_jiffies(lifespan); 307562306a36Sopenharmony_ci mutex_init(&stats->lock); 307662306a36Sopenharmony_ci 307762306a36Sopenharmony_ci return stats; 307862306a36Sopenharmony_ci 307962306a36Sopenharmony_cierr: 308062306a36Sopenharmony_ci kfree(stats); 308162306a36Sopenharmony_ci return NULL; 308262306a36Sopenharmony_ci} 308362306a36Sopenharmony_ciEXPORT_SYMBOL(rdma_alloc_hw_stats_struct); 308462306a36Sopenharmony_ci 308562306a36Sopenharmony_ci/** 308662306a36Sopenharmony_ci * rdma_free_hw_stats_struct - Helper function to release rdma_hw_stats 308762306a36Sopenharmony_ci * @stats: statistics to release 308862306a36Sopenharmony_ci */ 308962306a36Sopenharmony_civoid rdma_free_hw_stats_struct(struct rdma_hw_stats *stats) 309062306a36Sopenharmony_ci{ 309162306a36Sopenharmony_ci if (!stats) 309262306a36Sopenharmony_ci return; 309362306a36Sopenharmony_ci 309462306a36Sopenharmony_ci kfree(stats->is_disabled); 309562306a36Sopenharmony_ci kfree(stats); 309662306a36Sopenharmony_ci} 309762306a36Sopenharmony_ciEXPORT_SYMBOL(rdma_free_hw_stats_struct); 3098