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						&params);
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						&params);
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