xref: /openbmc/linux/drivers/infiniband/core/verbs.c (revision d9f272c5)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  * Copyright (c) 2004 Mellanox Technologies Ltd.  All rights reserved.
31da177e4SLinus Torvalds  * Copyright (c) 2004 Infinicon Corporation.  All rights reserved.
41da177e4SLinus Torvalds  * Copyright (c) 2004 Intel Corporation.  All rights reserved.
51da177e4SLinus Torvalds  * Copyright (c) 2004 Topspin Corporation.  All rights reserved.
61da177e4SLinus Torvalds  * Copyright (c) 2004 Voltaire Corporation.  All rights reserved.
72a1d9b7fSRoland Dreier  * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
833b9b3eeSRoland Dreier  * Copyright (c) 2005, 2006 Cisco Systems.  All rights reserved.
91da177e4SLinus Torvalds  *
101da177e4SLinus Torvalds  * This software is available to you under a choice of one of two
111da177e4SLinus Torvalds  * licenses.  You may choose to be licensed under the terms of the GNU
121da177e4SLinus Torvalds  * General Public License (GPL) Version 2, available from the file
131da177e4SLinus Torvalds  * COPYING in the main directory of this source tree, or the
141da177e4SLinus Torvalds  * OpenIB.org BSD license below:
151da177e4SLinus Torvalds  *
161da177e4SLinus Torvalds  *     Redistribution and use in source and binary forms, with or
171da177e4SLinus Torvalds  *     without modification, are permitted provided that the following
181da177e4SLinus Torvalds  *     conditions are met:
191da177e4SLinus Torvalds  *
201da177e4SLinus Torvalds  *      - Redistributions of source code must retain the above
211da177e4SLinus Torvalds  *        copyright notice, this list of conditions and the following
221da177e4SLinus Torvalds  *        disclaimer.
231da177e4SLinus Torvalds  *
241da177e4SLinus Torvalds  *      - Redistributions in binary form must reproduce the above
251da177e4SLinus Torvalds  *        copyright notice, this list of conditions and the following
261da177e4SLinus Torvalds  *        disclaimer in the documentation and/or other materials
271da177e4SLinus Torvalds  *        provided with the distribution.
281da177e4SLinus Torvalds  *
291da177e4SLinus Torvalds  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
301da177e4SLinus Torvalds  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
311da177e4SLinus Torvalds  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
321da177e4SLinus Torvalds  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
331da177e4SLinus Torvalds  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
341da177e4SLinus Torvalds  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
351da177e4SLinus Torvalds  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
361da177e4SLinus Torvalds  * SOFTWARE.
371da177e4SLinus Torvalds  */
381da177e4SLinus Torvalds 
391da177e4SLinus Torvalds #include <linux/errno.h>
401da177e4SLinus Torvalds #include <linux/err.h>
41b108d976SPaul Gortmaker #include <linux/export.h>
428c65b4a6STim Schmielau #include <linux/string.h>
430e0ec7e0SSean Hefty #include <linux/slab.h>
441da177e4SLinus Torvalds 
45a4d61e84SRoland Dreier #include <rdma/ib_verbs.h>
46a4d61e84SRoland Dreier #include <rdma/ib_cache.h>
47dd5f03beSMatan Barak #include <rdma/ib_addr.h>
481da177e4SLinus Torvalds 
49ed4c54e5SOr Gerlitz #include "core_priv.h"
501da177e4SLinus Torvalds 
512b1b5b60SSagi Grimberg static const char * const ib_events[] = {
522b1b5b60SSagi Grimberg 	[IB_EVENT_CQ_ERR]		= "CQ error",
532b1b5b60SSagi Grimberg 	[IB_EVENT_QP_FATAL]		= "QP fatal error",
542b1b5b60SSagi Grimberg 	[IB_EVENT_QP_REQ_ERR]		= "QP request error",
552b1b5b60SSagi Grimberg 	[IB_EVENT_QP_ACCESS_ERR]	= "QP access error",
562b1b5b60SSagi Grimberg 	[IB_EVENT_COMM_EST]		= "communication established",
572b1b5b60SSagi Grimberg 	[IB_EVENT_SQ_DRAINED]		= "send queue drained",
582b1b5b60SSagi Grimberg 	[IB_EVENT_PATH_MIG]		= "path migration successful",
592b1b5b60SSagi Grimberg 	[IB_EVENT_PATH_MIG_ERR]		= "path migration error",
602b1b5b60SSagi Grimberg 	[IB_EVENT_DEVICE_FATAL]		= "device fatal error",
612b1b5b60SSagi Grimberg 	[IB_EVENT_PORT_ACTIVE]		= "port active",
622b1b5b60SSagi Grimberg 	[IB_EVENT_PORT_ERR]		= "port error",
632b1b5b60SSagi Grimberg 	[IB_EVENT_LID_CHANGE]		= "LID change",
642b1b5b60SSagi Grimberg 	[IB_EVENT_PKEY_CHANGE]		= "P_key change",
652b1b5b60SSagi Grimberg 	[IB_EVENT_SM_CHANGE]		= "SM change",
662b1b5b60SSagi Grimberg 	[IB_EVENT_SRQ_ERR]		= "SRQ error",
672b1b5b60SSagi Grimberg 	[IB_EVENT_SRQ_LIMIT_REACHED]	= "SRQ limit reached",
682b1b5b60SSagi Grimberg 	[IB_EVENT_QP_LAST_WQE_REACHED]	= "last WQE reached",
692b1b5b60SSagi Grimberg 	[IB_EVENT_CLIENT_REREGISTER]	= "client reregister",
702b1b5b60SSagi Grimberg 	[IB_EVENT_GID_CHANGE]		= "GID changed",
712b1b5b60SSagi Grimberg };
722b1b5b60SSagi Grimberg 
732b1b5b60SSagi Grimberg const char *ib_event_msg(enum ib_event_type event)
742b1b5b60SSagi Grimberg {
752b1b5b60SSagi Grimberg 	size_t index = event;
762b1b5b60SSagi Grimberg 
772b1b5b60SSagi Grimberg 	return (index < ARRAY_SIZE(ib_events) && ib_events[index]) ?
782b1b5b60SSagi Grimberg 			ib_events[index] : "unrecognized event";
792b1b5b60SSagi Grimberg }
802b1b5b60SSagi Grimberg EXPORT_SYMBOL(ib_event_msg);
812b1b5b60SSagi Grimberg 
822b1b5b60SSagi Grimberg static const char * const wc_statuses[] = {
832b1b5b60SSagi Grimberg 	[IB_WC_SUCCESS]			= "success",
842b1b5b60SSagi Grimberg 	[IB_WC_LOC_LEN_ERR]		= "local length error",
852b1b5b60SSagi Grimberg 	[IB_WC_LOC_QP_OP_ERR]		= "local QP operation error",
862b1b5b60SSagi Grimberg 	[IB_WC_LOC_EEC_OP_ERR]		= "local EE context operation error",
872b1b5b60SSagi Grimberg 	[IB_WC_LOC_PROT_ERR]		= "local protection error",
882b1b5b60SSagi Grimberg 	[IB_WC_WR_FLUSH_ERR]		= "WR flushed",
892b1b5b60SSagi Grimberg 	[IB_WC_MW_BIND_ERR]		= "memory management operation error",
902b1b5b60SSagi Grimberg 	[IB_WC_BAD_RESP_ERR]		= "bad response error",
912b1b5b60SSagi Grimberg 	[IB_WC_LOC_ACCESS_ERR]		= "local access error",
922b1b5b60SSagi Grimberg 	[IB_WC_REM_INV_REQ_ERR]		= "invalid request error",
932b1b5b60SSagi Grimberg 	[IB_WC_REM_ACCESS_ERR]		= "remote access error",
942b1b5b60SSagi Grimberg 	[IB_WC_REM_OP_ERR]		= "remote operation error",
952b1b5b60SSagi Grimberg 	[IB_WC_RETRY_EXC_ERR]		= "transport retry counter exceeded",
962b1b5b60SSagi Grimberg 	[IB_WC_RNR_RETRY_EXC_ERR]	= "RNR retry counter exceeded",
972b1b5b60SSagi Grimberg 	[IB_WC_LOC_RDD_VIOL_ERR]	= "local RDD violation error",
982b1b5b60SSagi Grimberg 	[IB_WC_REM_INV_RD_REQ_ERR]	= "remote invalid RD request",
992b1b5b60SSagi Grimberg 	[IB_WC_REM_ABORT_ERR]		= "operation aborted",
1002b1b5b60SSagi Grimberg 	[IB_WC_INV_EECN_ERR]		= "invalid EE context number",
1012b1b5b60SSagi Grimberg 	[IB_WC_INV_EEC_STATE_ERR]	= "invalid EE context state",
1022b1b5b60SSagi Grimberg 	[IB_WC_FATAL_ERR]		= "fatal error",
1032b1b5b60SSagi Grimberg 	[IB_WC_RESP_TIMEOUT_ERR]	= "response timeout error",
1042b1b5b60SSagi Grimberg 	[IB_WC_GENERAL_ERR]		= "general error",
1052b1b5b60SSagi Grimberg };
1062b1b5b60SSagi Grimberg 
1072b1b5b60SSagi Grimberg const char *ib_wc_status_msg(enum ib_wc_status status)
1082b1b5b60SSagi Grimberg {
1092b1b5b60SSagi Grimberg 	size_t index = status;
1102b1b5b60SSagi Grimberg 
1112b1b5b60SSagi Grimberg 	return (index < ARRAY_SIZE(wc_statuses) && wc_statuses[index]) ?
1122b1b5b60SSagi Grimberg 			wc_statuses[index] : "unrecognized status";
1132b1b5b60SSagi Grimberg }
1142b1b5b60SSagi Grimberg EXPORT_SYMBOL(ib_wc_status_msg);
1152b1b5b60SSagi Grimberg 
1168385fd84SRoland Dreier __attribute_const__ int ib_rate_to_mult(enum ib_rate rate)
117bf6a9e31SJack Morgenstein {
118bf6a9e31SJack Morgenstein 	switch (rate) {
119bf6a9e31SJack Morgenstein 	case IB_RATE_2_5_GBPS: return  1;
120bf6a9e31SJack Morgenstein 	case IB_RATE_5_GBPS:   return  2;
121bf6a9e31SJack Morgenstein 	case IB_RATE_10_GBPS:  return  4;
122bf6a9e31SJack Morgenstein 	case IB_RATE_20_GBPS:  return  8;
123bf6a9e31SJack Morgenstein 	case IB_RATE_30_GBPS:  return 12;
124bf6a9e31SJack Morgenstein 	case IB_RATE_40_GBPS:  return 16;
125bf6a9e31SJack Morgenstein 	case IB_RATE_60_GBPS:  return 24;
126bf6a9e31SJack Morgenstein 	case IB_RATE_80_GBPS:  return 32;
127bf6a9e31SJack Morgenstein 	case IB_RATE_120_GBPS: return 48;
128bf6a9e31SJack Morgenstein 	default:	       return -1;
129bf6a9e31SJack Morgenstein 	}
130bf6a9e31SJack Morgenstein }
131bf6a9e31SJack Morgenstein EXPORT_SYMBOL(ib_rate_to_mult);
132bf6a9e31SJack Morgenstein 
1338385fd84SRoland Dreier __attribute_const__ enum ib_rate mult_to_ib_rate(int mult)
134bf6a9e31SJack Morgenstein {
135bf6a9e31SJack Morgenstein 	switch (mult) {
136bf6a9e31SJack Morgenstein 	case 1:  return IB_RATE_2_5_GBPS;
137bf6a9e31SJack Morgenstein 	case 2:  return IB_RATE_5_GBPS;
138bf6a9e31SJack Morgenstein 	case 4:  return IB_RATE_10_GBPS;
139bf6a9e31SJack Morgenstein 	case 8:  return IB_RATE_20_GBPS;
140bf6a9e31SJack Morgenstein 	case 12: return IB_RATE_30_GBPS;
141bf6a9e31SJack Morgenstein 	case 16: return IB_RATE_40_GBPS;
142bf6a9e31SJack Morgenstein 	case 24: return IB_RATE_60_GBPS;
143bf6a9e31SJack Morgenstein 	case 32: return IB_RATE_80_GBPS;
144bf6a9e31SJack Morgenstein 	case 48: return IB_RATE_120_GBPS;
145bf6a9e31SJack Morgenstein 	default: return IB_RATE_PORT_CURRENT;
146bf6a9e31SJack Morgenstein 	}
147bf6a9e31SJack Morgenstein }
148bf6a9e31SJack Morgenstein EXPORT_SYMBOL(mult_to_ib_rate);
149bf6a9e31SJack Morgenstein 
1508385fd84SRoland Dreier __attribute_const__ int ib_rate_to_mbps(enum ib_rate rate)
15171eeba16SMarcel Apfelbaum {
15271eeba16SMarcel Apfelbaum 	switch (rate) {
15371eeba16SMarcel Apfelbaum 	case IB_RATE_2_5_GBPS: return 2500;
15471eeba16SMarcel Apfelbaum 	case IB_RATE_5_GBPS:   return 5000;
15571eeba16SMarcel Apfelbaum 	case IB_RATE_10_GBPS:  return 10000;
15671eeba16SMarcel Apfelbaum 	case IB_RATE_20_GBPS:  return 20000;
15771eeba16SMarcel Apfelbaum 	case IB_RATE_30_GBPS:  return 30000;
15871eeba16SMarcel Apfelbaum 	case IB_RATE_40_GBPS:  return 40000;
15971eeba16SMarcel Apfelbaum 	case IB_RATE_60_GBPS:  return 60000;
16071eeba16SMarcel Apfelbaum 	case IB_RATE_80_GBPS:  return 80000;
16171eeba16SMarcel Apfelbaum 	case IB_RATE_120_GBPS: return 120000;
16271eeba16SMarcel Apfelbaum 	case IB_RATE_14_GBPS:  return 14062;
16371eeba16SMarcel Apfelbaum 	case IB_RATE_56_GBPS:  return 56250;
16471eeba16SMarcel Apfelbaum 	case IB_RATE_112_GBPS: return 112500;
16571eeba16SMarcel Apfelbaum 	case IB_RATE_168_GBPS: return 168750;
16671eeba16SMarcel Apfelbaum 	case IB_RATE_25_GBPS:  return 25781;
16771eeba16SMarcel Apfelbaum 	case IB_RATE_100_GBPS: return 103125;
16871eeba16SMarcel Apfelbaum 	case IB_RATE_200_GBPS: return 206250;
16971eeba16SMarcel Apfelbaum 	case IB_RATE_300_GBPS: return 309375;
17071eeba16SMarcel Apfelbaum 	default:	       return -1;
17171eeba16SMarcel Apfelbaum 	}
17271eeba16SMarcel Apfelbaum }
17371eeba16SMarcel Apfelbaum EXPORT_SYMBOL(ib_rate_to_mbps);
17471eeba16SMarcel Apfelbaum 
1758385fd84SRoland Dreier __attribute_const__ enum rdma_transport_type
17607ebafbaSTom Tucker rdma_node_get_transport(enum rdma_node_type node_type)
17707ebafbaSTom Tucker {
17807ebafbaSTom Tucker 	switch (node_type) {
17907ebafbaSTom Tucker 	case RDMA_NODE_IB_CA:
18007ebafbaSTom Tucker 	case RDMA_NODE_IB_SWITCH:
18107ebafbaSTom Tucker 	case RDMA_NODE_IB_ROUTER:
18207ebafbaSTom Tucker 		return RDMA_TRANSPORT_IB;
18307ebafbaSTom Tucker 	case RDMA_NODE_RNIC:
18407ebafbaSTom Tucker 		return RDMA_TRANSPORT_IWARP;
185180771a3SUpinder Malhi \(umalhi\) 	case RDMA_NODE_USNIC:
1865db5765eSUpinder Malhi 		return RDMA_TRANSPORT_USNIC;
1875db5765eSUpinder Malhi 	case RDMA_NODE_USNIC_UDP:
188248567f7SUpinder Malhi 		return RDMA_TRANSPORT_USNIC_UDP;
18907ebafbaSTom Tucker 	default:
19007ebafbaSTom Tucker 		BUG();
19107ebafbaSTom Tucker 		return 0;
19207ebafbaSTom Tucker 	}
19307ebafbaSTom Tucker }
19407ebafbaSTom Tucker EXPORT_SYMBOL(rdma_node_get_transport);
19507ebafbaSTom Tucker 
196a3f5adafSEli Cohen enum rdma_link_layer rdma_port_get_link_layer(struct ib_device *device, u8 port_num)
197a3f5adafSEli Cohen {
198a3f5adafSEli Cohen 	if (device->get_link_layer)
199a3f5adafSEli Cohen 		return device->get_link_layer(device, port_num);
200a3f5adafSEli Cohen 
201a3f5adafSEli Cohen 	switch (rdma_node_get_transport(device->node_type)) {
202a3f5adafSEli Cohen 	case RDMA_TRANSPORT_IB:
203a3f5adafSEli Cohen 		return IB_LINK_LAYER_INFINIBAND;
204a3f5adafSEli Cohen 	case RDMA_TRANSPORT_IWARP:
205180771a3SUpinder Malhi \(umalhi\) 	case RDMA_TRANSPORT_USNIC:
206248567f7SUpinder Malhi 	case RDMA_TRANSPORT_USNIC_UDP:
207a3f5adafSEli Cohen 		return IB_LINK_LAYER_ETHERNET;
208a3f5adafSEli Cohen 	default:
209a3f5adafSEli Cohen 		return IB_LINK_LAYER_UNSPECIFIED;
210a3f5adafSEli Cohen 	}
211a3f5adafSEli Cohen }
212a3f5adafSEli Cohen EXPORT_SYMBOL(rdma_port_get_link_layer);
213a3f5adafSEli Cohen 
2141da177e4SLinus Torvalds /* Protection domains */
2151da177e4SLinus Torvalds 
2161da177e4SLinus Torvalds struct ib_pd *ib_alloc_pd(struct ib_device *device)
2171da177e4SLinus Torvalds {
2181da177e4SLinus Torvalds 	struct ib_pd *pd;
2191da177e4SLinus Torvalds 
220b5e81bf5SRoland Dreier 	pd = device->alloc_pd(device, NULL, NULL);
2211da177e4SLinus Torvalds 
2221da177e4SLinus Torvalds 	if (!IS_ERR(pd)) {
2231da177e4SLinus Torvalds 		pd->device  = device;
224b5e81bf5SRoland Dreier 		pd->uobject = NULL;
2251da177e4SLinus Torvalds 		atomic_set(&pd->usecnt, 0);
2261da177e4SLinus Torvalds 	}
2271da177e4SLinus Torvalds 
2281da177e4SLinus Torvalds 	return pd;
2291da177e4SLinus Torvalds }
2301da177e4SLinus Torvalds EXPORT_SYMBOL(ib_alloc_pd);
2311da177e4SLinus Torvalds 
2321da177e4SLinus Torvalds int ib_dealloc_pd(struct ib_pd *pd)
2331da177e4SLinus Torvalds {
2341da177e4SLinus Torvalds 	if (atomic_read(&pd->usecnt))
2351da177e4SLinus Torvalds 		return -EBUSY;
2361da177e4SLinus Torvalds 
2371da177e4SLinus Torvalds 	return pd->device->dealloc_pd(pd);
2381da177e4SLinus Torvalds }
2391da177e4SLinus Torvalds EXPORT_SYMBOL(ib_dealloc_pd);
2401da177e4SLinus Torvalds 
2411da177e4SLinus Torvalds /* Address handles */
2421da177e4SLinus Torvalds 
2431da177e4SLinus Torvalds struct ib_ah *ib_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr)
2441da177e4SLinus Torvalds {
2451da177e4SLinus Torvalds 	struct ib_ah *ah;
2461da177e4SLinus Torvalds 
2471da177e4SLinus Torvalds 	ah = pd->device->create_ah(pd, ah_attr);
2481da177e4SLinus Torvalds 
2491da177e4SLinus Torvalds 	if (!IS_ERR(ah)) {
2501da177e4SLinus Torvalds 		ah->device  = pd->device;
2511da177e4SLinus Torvalds 		ah->pd      = pd;
252b5e81bf5SRoland Dreier 		ah->uobject = NULL;
2531da177e4SLinus Torvalds 		atomic_inc(&pd->usecnt);
2541da177e4SLinus Torvalds 	}
2551da177e4SLinus Torvalds 
2561da177e4SLinus Torvalds 	return ah;
2571da177e4SLinus Torvalds }
2581da177e4SLinus Torvalds EXPORT_SYMBOL(ib_create_ah);
2591da177e4SLinus Torvalds 
26073cdaaeeSIra Weiny int ib_init_ah_from_wc(struct ib_device *device, u8 port_num,
26173cdaaeeSIra Weiny 		       const struct ib_wc *wc, const struct ib_grh *grh,
26273cdaaeeSIra Weiny 		       struct ib_ah_attr *ah_attr)
263513789edSHal Rosenstock {
264513789edSHal Rosenstock 	u32 flow_class;
265513789edSHal Rosenstock 	u16 gid_index;
266513789edSHal Rosenstock 	int ret;
267513789edSHal Rosenstock 
2684e00d694SSean Hefty 	memset(ah_attr, 0, sizeof *ah_attr);
269227128fcSMichael Wang 	if (rdma_cap_eth_ah(device, port_num)) {
270dd5f03beSMatan Barak 		if (!(wc->wc_flags & IB_WC_GRH))
271dd5f03beSMatan Barak 			return -EPROTOTYPE;
272dd5f03beSMatan Barak 
273dd5f03beSMatan Barak 		if (wc->wc_flags & IB_WC_WITH_SMAC &&
274dd5f03beSMatan Barak 		    wc->wc_flags & IB_WC_WITH_VLAN) {
275dd5f03beSMatan Barak 			memcpy(ah_attr->dmac, wc->smac, ETH_ALEN);
276dd5f03beSMatan Barak 			ah_attr->vlan_id = wc->vlan_id;
277dd5f03beSMatan Barak 		} else {
278dd5f03beSMatan Barak 			ret = rdma_addr_find_dmac_by_grh(&grh->dgid, &grh->sgid,
279dd5f03beSMatan Barak 					ah_attr->dmac, &ah_attr->vlan_id);
280dd5f03beSMatan Barak 			if (ret)
281dd5f03beSMatan Barak 				return ret;
282dd5f03beSMatan Barak 		}
283dd5f03beSMatan Barak 	} else {
284dd5f03beSMatan Barak 		ah_attr->vlan_id = 0xffff;
285dd5f03beSMatan Barak 	}
286dd5f03beSMatan Barak 
2874e00d694SSean Hefty 	ah_attr->dlid = wc->slid;
2884e00d694SSean Hefty 	ah_attr->sl = wc->sl;
2894e00d694SSean Hefty 	ah_attr->src_path_bits = wc->dlid_path_bits;
2904e00d694SSean Hefty 	ah_attr->port_num = port_num;
291513789edSHal Rosenstock 
292513789edSHal Rosenstock 	if (wc->wc_flags & IB_WC_GRH) {
2934e00d694SSean Hefty 		ah_attr->ah_flags = IB_AH_GRH;
2944e00d694SSean Hefty 		ah_attr->grh.dgid = grh->sgid;
295513789edSHal Rosenstock 
2964e00d694SSean Hefty 		ret = ib_find_cached_gid(device, &grh->dgid, &port_num,
297513789edSHal Rosenstock 					 &gid_index);
298513789edSHal Rosenstock 		if (ret)
2994e00d694SSean Hefty 			return ret;
300513789edSHal Rosenstock 
3014e00d694SSean Hefty 		ah_attr->grh.sgid_index = (u8) gid_index;
302497677abSHal Rosenstock 		flow_class = be32_to_cpu(grh->version_tclass_flow);
3034e00d694SSean Hefty 		ah_attr->grh.flow_label = flow_class & 0xFFFFF;
30447645d8dSSean Hefty 		ah_attr->grh.hop_limit = 0xFF;
3054e00d694SSean Hefty 		ah_attr->grh.traffic_class = (flow_class >> 20) & 0xFF;
306513789edSHal Rosenstock 	}
3074e00d694SSean Hefty 	return 0;
3084e00d694SSean Hefty }
3094e00d694SSean Hefty EXPORT_SYMBOL(ib_init_ah_from_wc);
3104e00d694SSean Hefty 
31173cdaaeeSIra Weiny struct ib_ah *ib_create_ah_from_wc(struct ib_pd *pd, const struct ib_wc *wc,
31273cdaaeeSIra Weiny 				   const struct ib_grh *grh, u8 port_num)
3134e00d694SSean Hefty {
3144e00d694SSean Hefty 	struct ib_ah_attr ah_attr;
3154e00d694SSean Hefty 	int ret;
3164e00d694SSean Hefty 
3174e00d694SSean Hefty 	ret = ib_init_ah_from_wc(pd->device, port_num, wc, grh, &ah_attr);
3184e00d694SSean Hefty 	if (ret)
3194e00d694SSean Hefty 		return ERR_PTR(ret);
320513789edSHal Rosenstock 
321513789edSHal Rosenstock 	return ib_create_ah(pd, &ah_attr);
322513789edSHal Rosenstock }
323513789edSHal Rosenstock EXPORT_SYMBOL(ib_create_ah_from_wc);
324513789edSHal Rosenstock 
3251da177e4SLinus Torvalds int ib_modify_ah(struct ib_ah *ah, struct ib_ah_attr *ah_attr)
3261da177e4SLinus Torvalds {
3271da177e4SLinus Torvalds 	return ah->device->modify_ah ?
3281da177e4SLinus Torvalds 		ah->device->modify_ah(ah, ah_attr) :
3291da177e4SLinus Torvalds 		-ENOSYS;
3301da177e4SLinus Torvalds }
3311da177e4SLinus Torvalds EXPORT_SYMBOL(ib_modify_ah);
3321da177e4SLinus Torvalds 
3331da177e4SLinus Torvalds int ib_query_ah(struct ib_ah *ah, struct ib_ah_attr *ah_attr)
3341da177e4SLinus Torvalds {
3351da177e4SLinus Torvalds 	return ah->device->query_ah ?
3361da177e4SLinus Torvalds 		ah->device->query_ah(ah, ah_attr) :
3371da177e4SLinus Torvalds 		-ENOSYS;
3381da177e4SLinus Torvalds }
3391da177e4SLinus Torvalds EXPORT_SYMBOL(ib_query_ah);
3401da177e4SLinus Torvalds 
3411da177e4SLinus Torvalds int ib_destroy_ah(struct ib_ah *ah)
3421da177e4SLinus Torvalds {
3431da177e4SLinus Torvalds 	struct ib_pd *pd;
3441da177e4SLinus Torvalds 	int ret;
3451da177e4SLinus Torvalds 
3461da177e4SLinus Torvalds 	pd = ah->pd;
3471da177e4SLinus Torvalds 	ret = ah->device->destroy_ah(ah);
3481da177e4SLinus Torvalds 	if (!ret)
3491da177e4SLinus Torvalds 		atomic_dec(&pd->usecnt);
3501da177e4SLinus Torvalds 
3511da177e4SLinus Torvalds 	return ret;
3521da177e4SLinus Torvalds }
3531da177e4SLinus Torvalds EXPORT_SYMBOL(ib_destroy_ah);
3541da177e4SLinus Torvalds 
355d41fcc67SRoland Dreier /* Shared receive queues */
356d41fcc67SRoland Dreier 
357d41fcc67SRoland Dreier struct ib_srq *ib_create_srq(struct ib_pd *pd,
358d41fcc67SRoland Dreier 			     struct ib_srq_init_attr *srq_init_attr)
359d41fcc67SRoland Dreier {
360d41fcc67SRoland Dreier 	struct ib_srq *srq;
361d41fcc67SRoland Dreier 
362d41fcc67SRoland Dreier 	if (!pd->device->create_srq)
363d41fcc67SRoland Dreier 		return ERR_PTR(-ENOSYS);
364d41fcc67SRoland Dreier 
365d41fcc67SRoland Dreier 	srq = pd->device->create_srq(pd, srq_init_attr, NULL);
366d41fcc67SRoland Dreier 
367d41fcc67SRoland Dreier 	if (!IS_ERR(srq)) {
368d41fcc67SRoland Dreier 		srq->device    	   = pd->device;
369d41fcc67SRoland Dreier 		srq->pd        	   = pd;
370d41fcc67SRoland Dreier 		srq->uobject       = NULL;
371d41fcc67SRoland Dreier 		srq->event_handler = srq_init_attr->event_handler;
372d41fcc67SRoland Dreier 		srq->srq_context   = srq_init_attr->srq_context;
37396104edaSSean Hefty 		srq->srq_type      = srq_init_attr->srq_type;
374418d5130SSean Hefty 		if (srq->srq_type == IB_SRQT_XRC) {
375418d5130SSean Hefty 			srq->ext.xrc.xrcd = srq_init_attr->ext.xrc.xrcd;
376418d5130SSean Hefty 			srq->ext.xrc.cq   = srq_init_attr->ext.xrc.cq;
377418d5130SSean Hefty 			atomic_inc(&srq->ext.xrc.xrcd->usecnt);
378418d5130SSean Hefty 			atomic_inc(&srq->ext.xrc.cq->usecnt);
379418d5130SSean Hefty 		}
380d41fcc67SRoland Dreier 		atomic_inc(&pd->usecnt);
381d41fcc67SRoland Dreier 		atomic_set(&srq->usecnt, 0);
382d41fcc67SRoland Dreier 	}
383d41fcc67SRoland Dreier 
384d41fcc67SRoland Dreier 	return srq;
385d41fcc67SRoland Dreier }
386d41fcc67SRoland Dreier EXPORT_SYMBOL(ib_create_srq);
387d41fcc67SRoland Dreier 
388d41fcc67SRoland Dreier int ib_modify_srq(struct ib_srq *srq,
389d41fcc67SRoland Dreier 		  struct ib_srq_attr *srq_attr,
390d41fcc67SRoland Dreier 		  enum ib_srq_attr_mask srq_attr_mask)
391d41fcc67SRoland Dreier {
3927ce5eacbSDotan Barak 	return srq->device->modify_srq ?
3937ce5eacbSDotan Barak 		srq->device->modify_srq(srq, srq_attr, srq_attr_mask, NULL) :
3947ce5eacbSDotan Barak 		-ENOSYS;
395d41fcc67SRoland Dreier }
396d41fcc67SRoland Dreier EXPORT_SYMBOL(ib_modify_srq);
397d41fcc67SRoland Dreier 
398d41fcc67SRoland Dreier int ib_query_srq(struct ib_srq *srq,
399d41fcc67SRoland Dreier 		 struct ib_srq_attr *srq_attr)
400d41fcc67SRoland Dreier {
401d41fcc67SRoland Dreier 	return srq->device->query_srq ?
402d41fcc67SRoland Dreier 		srq->device->query_srq(srq, srq_attr) : -ENOSYS;
403d41fcc67SRoland Dreier }
404d41fcc67SRoland Dreier EXPORT_SYMBOL(ib_query_srq);
405d41fcc67SRoland Dreier 
406d41fcc67SRoland Dreier int ib_destroy_srq(struct ib_srq *srq)
407d41fcc67SRoland Dreier {
408d41fcc67SRoland Dreier 	struct ib_pd *pd;
409418d5130SSean Hefty 	enum ib_srq_type srq_type;
410418d5130SSean Hefty 	struct ib_xrcd *uninitialized_var(xrcd);
411418d5130SSean Hefty 	struct ib_cq *uninitialized_var(cq);
412d41fcc67SRoland Dreier 	int ret;
413d41fcc67SRoland Dreier 
414d41fcc67SRoland Dreier 	if (atomic_read(&srq->usecnt))
415d41fcc67SRoland Dreier 		return -EBUSY;
416d41fcc67SRoland Dreier 
417d41fcc67SRoland Dreier 	pd = srq->pd;
418418d5130SSean Hefty 	srq_type = srq->srq_type;
419418d5130SSean Hefty 	if (srq_type == IB_SRQT_XRC) {
420418d5130SSean Hefty 		xrcd = srq->ext.xrc.xrcd;
421418d5130SSean Hefty 		cq = srq->ext.xrc.cq;
422418d5130SSean Hefty 	}
423d41fcc67SRoland Dreier 
424d41fcc67SRoland Dreier 	ret = srq->device->destroy_srq(srq);
425418d5130SSean Hefty 	if (!ret) {
426d41fcc67SRoland Dreier 		atomic_dec(&pd->usecnt);
427418d5130SSean Hefty 		if (srq_type == IB_SRQT_XRC) {
428418d5130SSean Hefty 			atomic_dec(&xrcd->usecnt);
429418d5130SSean Hefty 			atomic_dec(&cq->usecnt);
430418d5130SSean Hefty 		}
431418d5130SSean Hefty 	}
432d41fcc67SRoland Dreier 
433d41fcc67SRoland Dreier 	return ret;
434d41fcc67SRoland Dreier }
435d41fcc67SRoland Dreier EXPORT_SYMBOL(ib_destroy_srq);
436d41fcc67SRoland Dreier 
4371da177e4SLinus Torvalds /* Queue pairs */
4381da177e4SLinus Torvalds 
4390e0ec7e0SSean Hefty static void __ib_shared_qp_event_handler(struct ib_event *event, void *context)
4400e0ec7e0SSean Hefty {
4410e0ec7e0SSean Hefty 	struct ib_qp *qp = context;
44273c40c61SYishai Hadas 	unsigned long flags;
4430e0ec7e0SSean Hefty 
44473c40c61SYishai Hadas 	spin_lock_irqsave(&qp->device->event_handler_lock, flags);
4450e0ec7e0SSean Hefty 	list_for_each_entry(event->element.qp, &qp->open_list, open_list)
446eec9e29fSShlomo Pongratz 		if (event->element.qp->event_handler)
4470e0ec7e0SSean Hefty 			event->element.qp->event_handler(event, event->element.qp->qp_context);
44873c40c61SYishai Hadas 	spin_unlock_irqrestore(&qp->device->event_handler_lock, flags);
4490e0ec7e0SSean Hefty }
4500e0ec7e0SSean Hefty 
451d3d72d90SSean Hefty static void __ib_insert_xrcd_qp(struct ib_xrcd *xrcd, struct ib_qp *qp)
452d3d72d90SSean Hefty {
453d3d72d90SSean Hefty 	mutex_lock(&xrcd->tgt_qp_mutex);
454d3d72d90SSean Hefty 	list_add(&qp->xrcd_list, &xrcd->tgt_qp_list);
455d3d72d90SSean Hefty 	mutex_unlock(&xrcd->tgt_qp_mutex);
456d3d72d90SSean Hefty }
457d3d72d90SSean Hefty 
4580e0ec7e0SSean Hefty static struct ib_qp *__ib_open_qp(struct ib_qp *real_qp,
4590e0ec7e0SSean Hefty 				  void (*event_handler)(struct ib_event *, void *),
4600e0ec7e0SSean Hefty 				  void *qp_context)
461d3d72d90SSean Hefty {
4620e0ec7e0SSean Hefty 	struct ib_qp *qp;
4630e0ec7e0SSean Hefty 	unsigned long flags;
4640e0ec7e0SSean Hefty 
4650e0ec7e0SSean Hefty 	qp = kzalloc(sizeof *qp, GFP_KERNEL);
4660e0ec7e0SSean Hefty 	if (!qp)
4670e0ec7e0SSean Hefty 		return ERR_PTR(-ENOMEM);
4680e0ec7e0SSean Hefty 
4690e0ec7e0SSean Hefty 	qp->real_qp = real_qp;
4700e0ec7e0SSean Hefty 	atomic_inc(&real_qp->usecnt);
4710e0ec7e0SSean Hefty 	qp->device = real_qp->device;
4720e0ec7e0SSean Hefty 	qp->event_handler = event_handler;
4730e0ec7e0SSean Hefty 	qp->qp_context = qp_context;
4740e0ec7e0SSean Hefty 	qp->qp_num = real_qp->qp_num;
4750e0ec7e0SSean Hefty 	qp->qp_type = real_qp->qp_type;
4760e0ec7e0SSean Hefty 
4770e0ec7e0SSean Hefty 	spin_lock_irqsave(&real_qp->device->event_handler_lock, flags);
4780e0ec7e0SSean Hefty 	list_add(&qp->open_list, &real_qp->open_list);
4790e0ec7e0SSean Hefty 	spin_unlock_irqrestore(&real_qp->device->event_handler_lock, flags);
4800e0ec7e0SSean Hefty 
4810e0ec7e0SSean Hefty 	return qp;
482d3d72d90SSean Hefty }
483d3d72d90SSean Hefty 
4840e0ec7e0SSean Hefty struct ib_qp *ib_open_qp(struct ib_xrcd *xrcd,
4850e0ec7e0SSean Hefty 			 struct ib_qp_open_attr *qp_open_attr)
4860e0ec7e0SSean Hefty {
4870e0ec7e0SSean Hefty 	struct ib_qp *qp, *real_qp;
4880e0ec7e0SSean Hefty 
4890e0ec7e0SSean Hefty 	if (qp_open_attr->qp_type != IB_QPT_XRC_TGT)
4900e0ec7e0SSean Hefty 		return ERR_PTR(-EINVAL);
4910e0ec7e0SSean Hefty 
4920e0ec7e0SSean Hefty 	qp = ERR_PTR(-EINVAL);
4930e0ec7e0SSean Hefty 	mutex_lock(&xrcd->tgt_qp_mutex);
4940e0ec7e0SSean Hefty 	list_for_each_entry(real_qp, &xrcd->tgt_qp_list, xrcd_list) {
4950e0ec7e0SSean Hefty 		if (real_qp->qp_num == qp_open_attr->qp_num) {
4960e0ec7e0SSean Hefty 			qp = __ib_open_qp(real_qp, qp_open_attr->event_handler,
4970e0ec7e0SSean Hefty 					  qp_open_attr->qp_context);
4980e0ec7e0SSean Hefty 			break;
4990e0ec7e0SSean Hefty 		}
5000e0ec7e0SSean Hefty 	}
5010e0ec7e0SSean Hefty 	mutex_unlock(&xrcd->tgt_qp_mutex);
5020e0ec7e0SSean Hefty 	return qp;
5030e0ec7e0SSean Hefty }
5040e0ec7e0SSean Hefty EXPORT_SYMBOL(ib_open_qp);
5050e0ec7e0SSean Hefty 
5061da177e4SLinus Torvalds struct ib_qp *ib_create_qp(struct ib_pd *pd,
5071da177e4SLinus Torvalds 			   struct ib_qp_init_attr *qp_init_attr)
5081da177e4SLinus Torvalds {
5090e0ec7e0SSean Hefty 	struct ib_qp *qp, *real_qp;
510b42b63cfSSean Hefty 	struct ib_device *device;
5111da177e4SLinus Torvalds 
512b42b63cfSSean Hefty 	device = pd ? pd->device : qp_init_attr->xrcd->device;
513b42b63cfSSean Hefty 	qp = device->create_qp(pd, qp_init_attr, NULL);
5141da177e4SLinus Torvalds 
5151da177e4SLinus Torvalds 	if (!IS_ERR(qp)) {
516b42b63cfSSean Hefty 		qp->device     = device;
5170e0ec7e0SSean Hefty 		qp->real_qp    = qp;
518b5e81bf5SRoland Dreier 		qp->uobject    = NULL;
5190e0ec7e0SSean Hefty 		qp->qp_type    = qp_init_attr->qp_type;
520b42b63cfSSean Hefty 
521e47e321aSBernd Schubert 		atomic_set(&qp->usecnt, 0);
522b42b63cfSSean Hefty 		if (qp_init_attr->qp_type == IB_QPT_XRC_TGT) {
5230e0ec7e0SSean Hefty 			qp->event_handler = __ib_shared_qp_event_handler;
5240e0ec7e0SSean Hefty 			qp->qp_context = qp;
525b42b63cfSSean Hefty 			qp->pd = NULL;
526b42b63cfSSean Hefty 			qp->send_cq = qp->recv_cq = NULL;
527b42b63cfSSean Hefty 			qp->srq = NULL;
528b42b63cfSSean Hefty 			qp->xrcd = qp_init_attr->xrcd;
529b42b63cfSSean Hefty 			atomic_inc(&qp_init_attr->xrcd->usecnt);
5300e0ec7e0SSean Hefty 			INIT_LIST_HEAD(&qp->open_list);
5310e0ec7e0SSean Hefty 
5320e0ec7e0SSean Hefty 			real_qp = qp;
5330e0ec7e0SSean Hefty 			qp = __ib_open_qp(real_qp, qp_init_attr->event_handler,
5340e0ec7e0SSean Hefty 					  qp_init_attr->qp_context);
5350e0ec7e0SSean Hefty 			if (!IS_ERR(qp))
5360e0ec7e0SSean Hefty 				__ib_insert_xrcd_qp(qp_init_attr->xrcd, real_qp);
5370e0ec7e0SSean Hefty 			else
5380e0ec7e0SSean Hefty 				real_qp->device->destroy_qp(real_qp);
539b42b63cfSSean Hefty 		} else {
5401da177e4SLinus Torvalds 			qp->event_handler = qp_init_attr->event_handler;
5411da177e4SLinus Torvalds 			qp->qp_context = qp_init_attr->qp_context;
542b42b63cfSSean Hefty 			if (qp_init_attr->qp_type == IB_QPT_XRC_INI) {
543b42b63cfSSean Hefty 				qp->recv_cq = NULL;
544b42b63cfSSean Hefty 				qp->srq = NULL;
545b42b63cfSSean Hefty 			} else {
546b42b63cfSSean Hefty 				qp->recv_cq = qp_init_attr->recv_cq;
547b42b63cfSSean Hefty 				atomic_inc(&qp_init_attr->recv_cq->usecnt);
548b42b63cfSSean Hefty 				qp->srq = qp_init_attr->srq;
549b42b63cfSSean Hefty 				if (qp->srq)
550b42b63cfSSean Hefty 					atomic_inc(&qp_init_attr->srq->usecnt);
551b42b63cfSSean Hefty 			}
552b42b63cfSSean Hefty 
5531da177e4SLinus Torvalds 			qp->pd	    = pd;
5541da177e4SLinus Torvalds 			qp->send_cq = qp_init_attr->send_cq;
555b42b63cfSSean Hefty 			qp->xrcd    = NULL;
556b42b63cfSSean Hefty 
5571da177e4SLinus Torvalds 			atomic_inc(&pd->usecnt);
5581da177e4SLinus Torvalds 			atomic_inc(&qp_init_attr->send_cq->usecnt);
559b42b63cfSSean Hefty 		}
5601da177e4SLinus Torvalds 	}
5611da177e4SLinus Torvalds 
5621da177e4SLinus Torvalds 	return qp;
5631da177e4SLinus Torvalds }
5641da177e4SLinus Torvalds EXPORT_SYMBOL(ib_create_qp);
5651da177e4SLinus Torvalds 
5668a51866fSRoland Dreier static const struct {
5678a51866fSRoland Dreier 	int			valid;
568b42b63cfSSean Hefty 	enum ib_qp_attr_mask	req_param[IB_QPT_MAX];
569dd5f03beSMatan Barak 	enum ib_qp_attr_mask	req_param_add_eth[IB_QPT_MAX];
570b42b63cfSSean Hefty 	enum ib_qp_attr_mask	opt_param[IB_QPT_MAX];
571dd5f03beSMatan Barak 	enum ib_qp_attr_mask	opt_param_add_eth[IB_QPT_MAX];
5728a51866fSRoland Dreier } qp_state_table[IB_QPS_ERR + 1][IB_QPS_ERR + 1] = {
5738a51866fSRoland Dreier 	[IB_QPS_RESET] = {
5748a51866fSRoland Dreier 		[IB_QPS_RESET] = { .valid = 1 },
5758a51866fSRoland Dreier 		[IB_QPS_INIT]  = {
5768a51866fSRoland Dreier 			.valid = 1,
5778a51866fSRoland Dreier 			.req_param = {
5788a51866fSRoland Dreier 				[IB_QPT_UD]  = (IB_QP_PKEY_INDEX		|
5798a51866fSRoland Dreier 						IB_QP_PORT			|
5808a51866fSRoland Dreier 						IB_QP_QKEY),
581c938a616SOr Gerlitz 				[IB_QPT_RAW_PACKET] = IB_QP_PORT,
5828a51866fSRoland Dreier 				[IB_QPT_UC]  = (IB_QP_PKEY_INDEX		|
5838a51866fSRoland Dreier 						IB_QP_PORT			|
5848a51866fSRoland Dreier 						IB_QP_ACCESS_FLAGS),
5858a51866fSRoland Dreier 				[IB_QPT_RC]  = (IB_QP_PKEY_INDEX		|
5868a51866fSRoland Dreier 						IB_QP_PORT			|
5878a51866fSRoland Dreier 						IB_QP_ACCESS_FLAGS),
588b42b63cfSSean Hefty 				[IB_QPT_XRC_INI] = (IB_QP_PKEY_INDEX		|
589b42b63cfSSean Hefty 						IB_QP_PORT			|
590b42b63cfSSean Hefty 						IB_QP_ACCESS_FLAGS),
591b42b63cfSSean Hefty 				[IB_QPT_XRC_TGT] = (IB_QP_PKEY_INDEX		|
592b42b63cfSSean Hefty 						IB_QP_PORT			|
593b42b63cfSSean Hefty 						IB_QP_ACCESS_FLAGS),
5948a51866fSRoland Dreier 				[IB_QPT_SMI] = (IB_QP_PKEY_INDEX		|
5958a51866fSRoland Dreier 						IB_QP_QKEY),
5968a51866fSRoland Dreier 				[IB_QPT_GSI] = (IB_QP_PKEY_INDEX		|
5978a51866fSRoland Dreier 						IB_QP_QKEY),
5988a51866fSRoland Dreier 			}
5998a51866fSRoland Dreier 		},
6008a51866fSRoland Dreier 	},
6018a51866fSRoland Dreier 	[IB_QPS_INIT]  = {
6028a51866fSRoland Dreier 		[IB_QPS_RESET] = { .valid = 1 },
6038a51866fSRoland Dreier 		[IB_QPS_ERR] =   { .valid = 1 },
6048a51866fSRoland Dreier 		[IB_QPS_INIT]  = {
6058a51866fSRoland Dreier 			.valid = 1,
6068a51866fSRoland Dreier 			.opt_param = {
6078a51866fSRoland Dreier 				[IB_QPT_UD]  = (IB_QP_PKEY_INDEX		|
6088a51866fSRoland Dreier 						IB_QP_PORT			|
6098a51866fSRoland Dreier 						IB_QP_QKEY),
6108a51866fSRoland Dreier 				[IB_QPT_UC]  = (IB_QP_PKEY_INDEX		|
6118a51866fSRoland Dreier 						IB_QP_PORT			|
6128a51866fSRoland Dreier 						IB_QP_ACCESS_FLAGS),
6138a51866fSRoland Dreier 				[IB_QPT_RC]  = (IB_QP_PKEY_INDEX		|
6148a51866fSRoland Dreier 						IB_QP_PORT			|
6158a51866fSRoland Dreier 						IB_QP_ACCESS_FLAGS),
616b42b63cfSSean Hefty 				[IB_QPT_XRC_INI] = (IB_QP_PKEY_INDEX		|
617b42b63cfSSean Hefty 						IB_QP_PORT			|
618b42b63cfSSean Hefty 						IB_QP_ACCESS_FLAGS),
619b42b63cfSSean Hefty 				[IB_QPT_XRC_TGT] = (IB_QP_PKEY_INDEX		|
620b42b63cfSSean Hefty 						IB_QP_PORT			|
621b42b63cfSSean Hefty 						IB_QP_ACCESS_FLAGS),
6228a51866fSRoland Dreier 				[IB_QPT_SMI] = (IB_QP_PKEY_INDEX		|
6238a51866fSRoland Dreier 						IB_QP_QKEY),
6248a51866fSRoland Dreier 				[IB_QPT_GSI] = (IB_QP_PKEY_INDEX		|
6258a51866fSRoland Dreier 						IB_QP_QKEY),
6268a51866fSRoland Dreier 			}
6278a51866fSRoland Dreier 		},
6288a51866fSRoland Dreier 		[IB_QPS_RTR]   = {
6298a51866fSRoland Dreier 			.valid = 1,
6308a51866fSRoland Dreier 			.req_param = {
6318a51866fSRoland Dreier 				[IB_QPT_UC]  = (IB_QP_AV			|
6328a51866fSRoland Dreier 						IB_QP_PATH_MTU			|
6338a51866fSRoland Dreier 						IB_QP_DEST_QPN			|
6348a51866fSRoland Dreier 						IB_QP_RQ_PSN),
6358a51866fSRoland Dreier 				[IB_QPT_RC]  = (IB_QP_AV			|
6368a51866fSRoland Dreier 						IB_QP_PATH_MTU			|
6378a51866fSRoland Dreier 						IB_QP_DEST_QPN			|
6388a51866fSRoland Dreier 						IB_QP_RQ_PSN			|
6398a51866fSRoland Dreier 						IB_QP_MAX_DEST_RD_ATOMIC	|
6408a51866fSRoland Dreier 						IB_QP_MIN_RNR_TIMER),
641b42b63cfSSean Hefty 				[IB_QPT_XRC_INI] = (IB_QP_AV			|
642b42b63cfSSean Hefty 						IB_QP_PATH_MTU			|
643b42b63cfSSean Hefty 						IB_QP_DEST_QPN			|
644b42b63cfSSean Hefty 						IB_QP_RQ_PSN),
645b42b63cfSSean Hefty 				[IB_QPT_XRC_TGT] = (IB_QP_AV			|
646b42b63cfSSean Hefty 						IB_QP_PATH_MTU			|
647b42b63cfSSean Hefty 						IB_QP_DEST_QPN			|
648b42b63cfSSean Hefty 						IB_QP_RQ_PSN			|
649b42b63cfSSean Hefty 						IB_QP_MAX_DEST_RD_ATOMIC	|
650b42b63cfSSean Hefty 						IB_QP_MIN_RNR_TIMER),
6518a51866fSRoland Dreier 			},
652dd5f03beSMatan Barak 			.req_param_add_eth = {
653dd5f03beSMatan Barak 				[IB_QPT_RC]  = (IB_QP_SMAC),
654dd5f03beSMatan Barak 				[IB_QPT_UC]  = (IB_QP_SMAC),
655dd5f03beSMatan Barak 				[IB_QPT_XRC_INI]  = (IB_QP_SMAC),
656dd5f03beSMatan Barak 				[IB_QPT_XRC_TGT]  = (IB_QP_SMAC)
657dd5f03beSMatan Barak 			},
6588a51866fSRoland Dreier 			.opt_param = {
6598a51866fSRoland Dreier 				 [IB_QPT_UD]  = (IB_QP_PKEY_INDEX		|
6608a51866fSRoland Dreier 						 IB_QP_QKEY),
6618a51866fSRoland Dreier 				 [IB_QPT_UC]  = (IB_QP_ALT_PATH			|
6628a51866fSRoland Dreier 						 IB_QP_ACCESS_FLAGS		|
6638a51866fSRoland Dreier 						 IB_QP_PKEY_INDEX),
6648a51866fSRoland Dreier 				 [IB_QPT_RC]  = (IB_QP_ALT_PATH			|
6658a51866fSRoland Dreier 						 IB_QP_ACCESS_FLAGS		|
6668a51866fSRoland Dreier 						 IB_QP_PKEY_INDEX),
667b42b63cfSSean Hefty 				 [IB_QPT_XRC_INI] = (IB_QP_ALT_PATH		|
668b42b63cfSSean Hefty 						 IB_QP_ACCESS_FLAGS		|
669b42b63cfSSean Hefty 						 IB_QP_PKEY_INDEX),
670b42b63cfSSean Hefty 				 [IB_QPT_XRC_TGT] = (IB_QP_ALT_PATH		|
671b42b63cfSSean Hefty 						 IB_QP_ACCESS_FLAGS		|
672b42b63cfSSean Hefty 						 IB_QP_PKEY_INDEX),
6738a51866fSRoland Dreier 				 [IB_QPT_SMI] = (IB_QP_PKEY_INDEX		|
6748a51866fSRoland Dreier 						 IB_QP_QKEY),
6758a51866fSRoland Dreier 				 [IB_QPT_GSI] = (IB_QP_PKEY_INDEX		|
6768a51866fSRoland Dreier 						 IB_QP_QKEY),
677dd5f03beSMatan Barak 			 },
678dd5f03beSMatan Barak 			.opt_param_add_eth = {
679dd5f03beSMatan Barak 				[IB_QPT_RC]  = (IB_QP_ALT_SMAC			|
680dd5f03beSMatan Barak 						IB_QP_VID			|
681dd5f03beSMatan Barak 						IB_QP_ALT_VID),
682dd5f03beSMatan Barak 				[IB_QPT_UC]  = (IB_QP_ALT_SMAC			|
683dd5f03beSMatan Barak 						IB_QP_VID			|
684dd5f03beSMatan Barak 						IB_QP_ALT_VID),
685dd5f03beSMatan Barak 				[IB_QPT_XRC_INI]  = (IB_QP_ALT_SMAC			|
686dd5f03beSMatan Barak 						IB_QP_VID			|
687dd5f03beSMatan Barak 						IB_QP_ALT_VID),
688dd5f03beSMatan Barak 				[IB_QPT_XRC_TGT]  = (IB_QP_ALT_SMAC			|
689dd5f03beSMatan Barak 						IB_QP_VID			|
690dd5f03beSMatan Barak 						IB_QP_ALT_VID)
6918a51866fSRoland Dreier 			}
6928a51866fSRoland Dreier 		}
6938a51866fSRoland Dreier 	},
6948a51866fSRoland Dreier 	[IB_QPS_RTR]   = {
6958a51866fSRoland Dreier 		[IB_QPS_RESET] = { .valid = 1 },
6968a51866fSRoland Dreier 		[IB_QPS_ERR] =   { .valid = 1 },
6978a51866fSRoland Dreier 		[IB_QPS_RTS]   = {
6988a51866fSRoland Dreier 			.valid = 1,
6998a51866fSRoland Dreier 			.req_param = {
7008a51866fSRoland Dreier 				[IB_QPT_UD]  = IB_QP_SQ_PSN,
7018a51866fSRoland Dreier 				[IB_QPT_UC]  = IB_QP_SQ_PSN,
7028a51866fSRoland Dreier 				[IB_QPT_RC]  = (IB_QP_TIMEOUT			|
7038a51866fSRoland Dreier 						IB_QP_RETRY_CNT			|
7048a51866fSRoland Dreier 						IB_QP_RNR_RETRY			|
7058a51866fSRoland Dreier 						IB_QP_SQ_PSN			|
7068a51866fSRoland Dreier 						IB_QP_MAX_QP_RD_ATOMIC),
707b42b63cfSSean Hefty 				[IB_QPT_XRC_INI] = (IB_QP_TIMEOUT		|
708b42b63cfSSean Hefty 						IB_QP_RETRY_CNT			|
709b42b63cfSSean Hefty 						IB_QP_RNR_RETRY			|
710b42b63cfSSean Hefty 						IB_QP_SQ_PSN			|
711b42b63cfSSean Hefty 						IB_QP_MAX_QP_RD_ATOMIC),
712b42b63cfSSean Hefty 				[IB_QPT_XRC_TGT] = (IB_QP_TIMEOUT		|
713b42b63cfSSean Hefty 						IB_QP_SQ_PSN),
7148a51866fSRoland Dreier 				[IB_QPT_SMI] = IB_QP_SQ_PSN,
7158a51866fSRoland Dreier 				[IB_QPT_GSI] = IB_QP_SQ_PSN,
7168a51866fSRoland Dreier 			},
7178a51866fSRoland Dreier 			.opt_param = {
7188a51866fSRoland Dreier 				 [IB_QPT_UD]  = (IB_QP_CUR_STATE		|
7198a51866fSRoland Dreier 						 IB_QP_QKEY),
7208a51866fSRoland Dreier 				 [IB_QPT_UC]  = (IB_QP_CUR_STATE		|
7218a51866fSRoland Dreier 						 IB_QP_ALT_PATH			|
7228a51866fSRoland Dreier 						 IB_QP_ACCESS_FLAGS		|
7238a51866fSRoland Dreier 						 IB_QP_PATH_MIG_STATE),
7248a51866fSRoland Dreier 				 [IB_QPT_RC]  = (IB_QP_CUR_STATE		|
7258a51866fSRoland Dreier 						 IB_QP_ALT_PATH			|
7268a51866fSRoland Dreier 						 IB_QP_ACCESS_FLAGS		|
7278a51866fSRoland Dreier 						 IB_QP_MIN_RNR_TIMER		|
7288a51866fSRoland Dreier 						 IB_QP_PATH_MIG_STATE),
729b42b63cfSSean Hefty 				 [IB_QPT_XRC_INI] = (IB_QP_CUR_STATE		|
730b42b63cfSSean Hefty 						 IB_QP_ALT_PATH			|
731b42b63cfSSean Hefty 						 IB_QP_ACCESS_FLAGS		|
732b42b63cfSSean Hefty 						 IB_QP_PATH_MIG_STATE),
733b42b63cfSSean Hefty 				 [IB_QPT_XRC_TGT] = (IB_QP_CUR_STATE		|
734b42b63cfSSean Hefty 						 IB_QP_ALT_PATH			|
735b42b63cfSSean Hefty 						 IB_QP_ACCESS_FLAGS		|
736b42b63cfSSean Hefty 						 IB_QP_MIN_RNR_TIMER		|
737b42b63cfSSean Hefty 						 IB_QP_PATH_MIG_STATE),
7388a51866fSRoland Dreier 				 [IB_QPT_SMI] = (IB_QP_CUR_STATE		|
7398a51866fSRoland Dreier 						 IB_QP_QKEY),
7408a51866fSRoland Dreier 				 [IB_QPT_GSI] = (IB_QP_CUR_STATE		|
7418a51866fSRoland Dreier 						 IB_QP_QKEY),
7428a51866fSRoland Dreier 			 }
7438a51866fSRoland Dreier 		}
7448a51866fSRoland Dreier 	},
7458a51866fSRoland Dreier 	[IB_QPS_RTS]   = {
7468a51866fSRoland Dreier 		[IB_QPS_RESET] = { .valid = 1 },
7478a51866fSRoland Dreier 		[IB_QPS_ERR] =   { .valid = 1 },
7488a51866fSRoland Dreier 		[IB_QPS_RTS]   = {
7498a51866fSRoland Dreier 			.valid = 1,
7508a51866fSRoland Dreier 			.opt_param = {
7518a51866fSRoland Dreier 				[IB_QPT_UD]  = (IB_QP_CUR_STATE			|
7528a51866fSRoland Dreier 						IB_QP_QKEY),
7534546d31dSDotan Barak 				[IB_QPT_UC]  = (IB_QP_CUR_STATE			|
7544546d31dSDotan Barak 						IB_QP_ACCESS_FLAGS		|
7558a51866fSRoland Dreier 						IB_QP_ALT_PATH			|
7568a51866fSRoland Dreier 						IB_QP_PATH_MIG_STATE),
7574546d31dSDotan Barak 				[IB_QPT_RC]  = (IB_QP_CUR_STATE			|
7584546d31dSDotan Barak 						IB_QP_ACCESS_FLAGS		|
7598a51866fSRoland Dreier 						IB_QP_ALT_PATH			|
7608a51866fSRoland Dreier 						IB_QP_PATH_MIG_STATE		|
7618a51866fSRoland Dreier 						IB_QP_MIN_RNR_TIMER),
762b42b63cfSSean Hefty 				[IB_QPT_XRC_INI] = (IB_QP_CUR_STATE		|
763b42b63cfSSean Hefty 						IB_QP_ACCESS_FLAGS		|
764b42b63cfSSean Hefty 						IB_QP_ALT_PATH			|
765b42b63cfSSean Hefty 						IB_QP_PATH_MIG_STATE),
766b42b63cfSSean Hefty 				[IB_QPT_XRC_TGT] = (IB_QP_CUR_STATE		|
767b42b63cfSSean Hefty 						IB_QP_ACCESS_FLAGS		|
768b42b63cfSSean Hefty 						IB_QP_ALT_PATH			|
769b42b63cfSSean Hefty 						IB_QP_PATH_MIG_STATE		|
770b42b63cfSSean Hefty 						IB_QP_MIN_RNR_TIMER),
7718a51866fSRoland Dreier 				[IB_QPT_SMI] = (IB_QP_CUR_STATE			|
7728a51866fSRoland Dreier 						IB_QP_QKEY),
7738a51866fSRoland Dreier 				[IB_QPT_GSI] = (IB_QP_CUR_STATE			|
7748a51866fSRoland Dreier 						IB_QP_QKEY),
7758a51866fSRoland Dreier 			}
7768a51866fSRoland Dreier 		},
7778a51866fSRoland Dreier 		[IB_QPS_SQD]   = {
7788a51866fSRoland Dreier 			.valid = 1,
7798a51866fSRoland Dreier 			.opt_param = {
7808a51866fSRoland Dreier 				[IB_QPT_UD]  = IB_QP_EN_SQD_ASYNC_NOTIFY,
7818a51866fSRoland Dreier 				[IB_QPT_UC]  = IB_QP_EN_SQD_ASYNC_NOTIFY,
7828a51866fSRoland Dreier 				[IB_QPT_RC]  = IB_QP_EN_SQD_ASYNC_NOTIFY,
783b42b63cfSSean Hefty 				[IB_QPT_XRC_INI] = IB_QP_EN_SQD_ASYNC_NOTIFY,
784b42b63cfSSean Hefty 				[IB_QPT_XRC_TGT] = IB_QP_EN_SQD_ASYNC_NOTIFY, /* ??? */
7858a51866fSRoland Dreier 				[IB_QPT_SMI] = IB_QP_EN_SQD_ASYNC_NOTIFY,
7868a51866fSRoland Dreier 				[IB_QPT_GSI] = IB_QP_EN_SQD_ASYNC_NOTIFY
7878a51866fSRoland Dreier 			}
7888a51866fSRoland Dreier 		},
7898a51866fSRoland Dreier 	},
7908a51866fSRoland Dreier 	[IB_QPS_SQD]   = {
7918a51866fSRoland Dreier 		[IB_QPS_RESET] = { .valid = 1 },
7928a51866fSRoland Dreier 		[IB_QPS_ERR] =   { .valid = 1 },
7938a51866fSRoland Dreier 		[IB_QPS_RTS]   = {
7948a51866fSRoland Dreier 			.valid = 1,
7958a51866fSRoland Dreier 			.opt_param = {
7968a51866fSRoland Dreier 				[IB_QPT_UD]  = (IB_QP_CUR_STATE			|
7978a51866fSRoland Dreier 						IB_QP_QKEY),
7988a51866fSRoland Dreier 				[IB_QPT_UC]  = (IB_QP_CUR_STATE			|
7998a51866fSRoland Dreier 						IB_QP_ALT_PATH			|
8008a51866fSRoland Dreier 						IB_QP_ACCESS_FLAGS		|
8018a51866fSRoland Dreier 						IB_QP_PATH_MIG_STATE),
8028a51866fSRoland Dreier 				[IB_QPT_RC]  = (IB_QP_CUR_STATE			|
8038a51866fSRoland Dreier 						IB_QP_ALT_PATH			|
8048a51866fSRoland Dreier 						IB_QP_ACCESS_FLAGS		|
8058a51866fSRoland Dreier 						IB_QP_MIN_RNR_TIMER		|
8068a51866fSRoland Dreier 						IB_QP_PATH_MIG_STATE),
807b42b63cfSSean Hefty 				[IB_QPT_XRC_INI] = (IB_QP_CUR_STATE		|
808b42b63cfSSean Hefty 						IB_QP_ALT_PATH			|
809b42b63cfSSean Hefty 						IB_QP_ACCESS_FLAGS		|
810b42b63cfSSean Hefty 						IB_QP_PATH_MIG_STATE),
811b42b63cfSSean Hefty 				[IB_QPT_XRC_TGT] = (IB_QP_CUR_STATE		|
812b42b63cfSSean Hefty 						IB_QP_ALT_PATH			|
813b42b63cfSSean Hefty 						IB_QP_ACCESS_FLAGS		|
814b42b63cfSSean Hefty 						IB_QP_MIN_RNR_TIMER		|
815b42b63cfSSean Hefty 						IB_QP_PATH_MIG_STATE),
8168a51866fSRoland Dreier 				[IB_QPT_SMI] = (IB_QP_CUR_STATE			|
8178a51866fSRoland Dreier 						IB_QP_QKEY),
8188a51866fSRoland Dreier 				[IB_QPT_GSI] = (IB_QP_CUR_STATE			|
8198a51866fSRoland Dreier 						IB_QP_QKEY),
8208a51866fSRoland Dreier 			}
8218a51866fSRoland Dreier 		},
8228a51866fSRoland Dreier 		[IB_QPS_SQD]   = {
8238a51866fSRoland Dreier 			.valid = 1,
8248a51866fSRoland Dreier 			.opt_param = {
8258a51866fSRoland Dreier 				[IB_QPT_UD]  = (IB_QP_PKEY_INDEX		|
8268a51866fSRoland Dreier 						IB_QP_QKEY),
8278a51866fSRoland Dreier 				[IB_QPT_UC]  = (IB_QP_AV			|
8288a51866fSRoland Dreier 						IB_QP_ALT_PATH			|
8298a51866fSRoland Dreier 						IB_QP_ACCESS_FLAGS		|
8308a51866fSRoland Dreier 						IB_QP_PKEY_INDEX		|
8318a51866fSRoland Dreier 						IB_QP_PATH_MIG_STATE),
8328a51866fSRoland Dreier 				[IB_QPT_RC]  = (IB_QP_PORT			|
8338a51866fSRoland Dreier 						IB_QP_AV			|
8348a51866fSRoland Dreier 						IB_QP_TIMEOUT			|
8358a51866fSRoland Dreier 						IB_QP_RETRY_CNT			|
8368a51866fSRoland Dreier 						IB_QP_RNR_RETRY			|
8378a51866fSRoland Dreier 						IB_QP_MAX_QP_RD_ATOMIC		|
8388a51866fSRoland Dreier 						IB_QP_MAX_DEST_RD_ATOMIC	|
8398a51866fSRoland Dreier 						IB_QP_ALT_PATH			|
8408a51866fSRoland Dreier 						IB_QP_ACCESS_FLAGS		|
8418a51866fSRoland Dreier 						IB_QP_PKEY_INDEX		|
8428a51866fSRoland Dreier 						IB_QP_MIN_RNR_TIMER		|
8438a51866fSRoland Dreier 						IB_QP_PATH_MIG_STATE),
844b42b63cfSSean Hefty 				[IB_QPT_XRC_INI] = (IB_QP_PORT			|
845b42b63cfSSean Hefty 						IB_QP_AV			|
846b42b63cfSSean Hefty 						IB_QP_TIMEOUT			|
847b42b63cfSSean Hefty 						IB_QP_RETRY_CNT			|
848b42b63cfSSean Hefty 						IB_QP_RNR_RETRY			|
849b42b63cfSSean Hefty 						IB_QP_MAX_QP_RD_ATOMIC		|
850b42b63cfSSean Hefty 						IB_QP_ALT_PATH			|
851b42b63cfSSean Hefty 						IB_QP_ACCESS_FLAGS		|
852b42b63cfSSean Hefty 						IB_QP_PKEY_INDEX		|
853b42b63cfSSean Hefty 						IB_QP_PATH_MIG_STATE),
854b42b63cfSSean Hefty 				[IB_QPT_XRC_TGT] = (IB_QP_PORT			|
855b42b63cfSSean Hefty 						IB_QP_AV			|
856b42b63cfSSean Hefty 						IB_QP_TIMEOUT			|
857b42b63cfSSean Hefty 						IB_QP_MAX_DEST_RD_ATOMIC	|
858b42b63cfSSean Hefty 						IB_QP_ALT_PATH			|
859b42b63cfSSean Hefty 						IB_QP_ACCESS_FLAGS		|
860b42b63cfSSean Hefty 						IB_QP_PKEY_INDEX		|
861b42b63cfSSean Hefty 						IB_QP_MIN_RNR_TIMER		|
862b42b63cfSSean Hefty 						IB_QP_PATH_MIG_STATE),
8638a51866fSRoland Dreier 				[IB_QPT_SMI] = (IB_QP_PKEY_INDEX		|
8648a51866fSRoland Dreier 						IB_QP_QKEY),
8658a51866fSRoland Dreier 				[IB_QPT_GSI] = (IB_QP_PKEY_INDEX		|
8668a51866fSRoland Dreier 						IB_QP_QKEY),
8678a51866fSRoland Dreier 			}
8688a51866fSRoland Dreier 		}
8698a51866fSRoland Dreier 	},
8708a51866fSRoland Dreier 	[IB_QPS_SQE]   = {
8718a51866fSRoland Dreier 		[IB_QPS_RESET] = { .valid = 1 },
8728a51866fSRoland Dreier 		[IB_QPS_ERR] =   { .valid = 1 },
8738a51866fSRoland Dreier 		[IB_QPS_RTS]   = {
8748a51866fSRoland Dreier 			.valid = 1,
8758a51866fSRoland Dreier 			.opt_param = {
8768a51866fSRoland Dreier 				[IB_QPT_UD]  = (IB_QP_CUR_STATE			|
8778a51866fSRoland Dreier 						IB_QP_QKEY),
8788a51866fSRoland Dreier 				[IB_QPT_UC]  = (IB_QP_CUR_STATE			|
8798a51866fSRoland Dreier 						IB_QP_ACCESS_FLAGS),
8808a51866fSRoland Dreier 				[IB_QPT_SMI] = (IB_QP_CUR_STATE			|
8818a51866fSRoland Dreier 						IB_QP_QKEY),
8828a51866fSRoland Dreier 				[IB_QPT_GSI] = (IB_QP_CUR_STATE			|
8838a51866fSRoland Dreier 						IB_QP_QKEY),
8848a51866fSRoland Dreier 			}
8858a51866fSRoland Dreier 		}
8868a51866fSRoland Dreier 	},
8878a51866fSRoland Dreier 	[IB_QPS_ERR] = {
8888a51866fSRoland Dreier 		[IB_QPS_RESET] = { .valid = 1 },
8898a51866fSRoland Dreier 		[IB_QPS_ERR] =   { .valid = 1 }
8908a51866fSRoland Dreier 	}
8918a51866fSRoland Dreier };
8928a51866fSRoland Dreier 
8938a51866fSRoland Dreier int ib_modify_qp_is_ok(enum ib_qp_state cur_state, enum ib_qp_state next_state,
894dd5f03beSMatan Barak 		       enum ib_qp_type type, enum ib_qp_attr_mask mask,
895dd5f03beSMatan Barak 		       enum rdma_link_layer ll)
8968a51866fSRoland Dreier {
8978a51866fSRoland Dreier 	enum ib_qp_attr_mask req_param, opt_param;
8988a51866fSRoland Dreier 
8998a51866fSRoland Dreier 	if (cur_state  < 0 || cur_state  > IB_QPS_ERR ||
9008a51866fSRoland Dreier 	    next_state < 0 || next_state > IB_QPS_ERR)
9018a51866fSRoland Dreier 		return 0;
9028a51866fSRoland Dreier 
9038a51866fSRoland Dreier 	if (mask & IB_QP_CUR_STATE  &&
9048a51866fSRoland Dreier 	    cur_state != IB_QPS_RTR && cur_state != IB_QPS_RTS &&
9058a51866fSRoland Dreier 	    cur_state != IB_QPS_SQD && cur_state != IB_QPS_SQE)
9068a51866fSRoland Dreier 		return 0;
9078a51866fSRoland Dreier 
9088a51866fSRoland Dreier 	if (!qp_state_table[cur_state][next_state].valid)
9098a51866fSRoland Dreier 		return 0;
9108a51866fSRoland Dreier 
9118a51866fSRoland Dreier 	req_param = qp_state_table[cur_state][next_state].req_param[type];
9128a51866fSRoland Dreier 	opt_param = qp_state_table[cur_state][next_state].opt_param[type];
9138a51866fSRoland Dreier 
914dd5f03beSMatan Barak 	if (ll == IB_LINK_LAYER_ETHERNET) {
915dd5f03beSMatan Barak 		req_param |= qp_state_table[cur_state][next_state].
916dd5f03beSMatan Barak 			req_param_add_eth[type];
917dd5f03beSMatan Barak 		opt_param |= qp_state_table[cur_state][next_state].
918dd5f03beSMatan Barak 			opt_param_add_eth[type];
919dd5f03beSMatan Barak 	}
920dd5f03beSMatan Barak 
9218a51866fSRoland Dreier 	if ((mask & req_param) != req_param)
9228a51866fSRoland Dreier 		return 0;
9238a51866fSRoland Dreier 
9248a51866fSRoland Dreier 	if (mask & ~(req_param | opt_param | IB_QP_STATE))
9258a51866fSRoland Dreier 		return 0;
9268a51866fSRoland Dreier 
9278a51866fSRoland Dreier 	return 1;
9288a51866fSRoland Dreier }
9298a51866fSRoland Dreier EXPORT_SYMBOL(ib_modify_qp_is_ok);
9308a51866fSRoland Dreier 
931ed4c54e5SOr Gerlitz int ib_resolve_eth_l2_attrs(struct ib_qp *qp,
932ed4c54e5SOr Gerlitz 			    struct ib_qp_attr *qp_attr, int *qp_attr_mask)
933ed4c54e5SOr Gerlitz {
934ed4c54e5SOr Gerlitz 	int           ret = 0;
935ed4c54e5SOr Gerlitz 	union ib_gid  sgid;
936ed4c54e5SOr Gerlitz 
937ed4c54e5SOr Gerlitz 	if ((*qp_attr_mask & IB_QP_AV)  &&
938227128fcSMichael Wang 	    (rdma_cap_eth_ah(qp->device, qp_attr->ah_attr.port_num))) {
939ed4c54e5SOr Gerlitz 		ret = ib_query_gid(qp->device, qp_attr->ah_attr.port_num,
940ed4c54e5SOr Gerlitz 				   qp_attr->ah_attr.grh.sgid_index, &sgid);
941ed4c54e5SOr Gerlitz 		if (ret)
942ed4c54e5SOr Gerlitz 			goto out;
943ed4c54e5SOr Gerlitz 		if (rdma_link_local_addr((struct in6_addr *)qp_attr->ah_attr.grh.dgid.raw)) {
944ed4c54e5SOr Gerlitz 			rdma_get_ll_mac((struct in6_addr *)qp_attr->ah_attr.grh.dgid.raw, qp_attr->ah_attr.dmac);
945ed4c54e5SOr Gerlitz 			rdma_get_ll_mac((struct in6_addr *)sgid.raw, qp_attr->smac);
946c1bd6cdeSMoni Shoua 			if (!(*qp_attr_mask & IB_QP_VID))
947ed4c54e5SOr Gerlitz 				qp_attr->vlan_id = rdma_get_vlan_id(&sgid);
948ed4c54e5SOr Gerlitz 		} else {
949ed4c54e5SOr Gerlitz 			ret = rdma_addr_find_dmac_by_grh(&sgid, &qp_attr->ah_attr.grh.dgid,
950ed4c54e5SOr Gerlitz 					qp_attr->ah_attr.dmac, &qp_attr->vlan_id);
951ed4c54e5SOr Gerlitz 			if (ret)
952ed4c54e5SOr Gerlitz 				goto out;
953ed4c54e5SOr Gerlitz 			ret = rdma_addr_find_smac_by_sgid(&sgid, qp_attr->smac, NULL);
954ed4c54e5SOr Gerlitz 			if (ret)
955ed4c54e5SOr Gerlitz 				goto out;
956ed4c54e5SOr Gerlitz 		}
957ed4c54e5SOr Gerlitz 		*qp_attr_mask |= IB_QP_SMAC;
958ed4c54e5SOr Gerlitz 		if (qp_attr->vlan_id < 0xFFFF)
959ed4c54e5SOr Gerlitz 			*qp_attr_mask |= IB_QP_VID;
960ed4c54e5SOr Gerlitz 	}
961ed4c54e5SOr Gerlitz out:
962ed4c54e5SOr Gerlitz 	return ret;
963ed4c54e5SOr Gerlitz }
964ed4c54e5SOr Gerlitz EXPORT_SYMBOL(ib_resolve_eth_l2_attrs);
965ed4c54e5SOr Gerlitz 
966ed4c54e5SOr Gerlitz 
9671da177e4SLinus Torvalds int ib_modify_qp(struct ib_qp *qp,
9681da177e4SLinus Torvalds 		 struct ib_qp_attr *qp_attr,
9691da177e4SLinus Torvalds 		 int qp_attr_mask)
9701da177e4SLinus Torvalds {
971ed4c54e5SOr Gerlitz 	int ret;
972ed4c54e5SOr Gerlitz 
973ed4c54e5SOr Gerlitz 	ret = ib_resolve_eth_l2_attrs(qp, qp_attr, &qp_attr_mask);
974ed4c54e5SOr Gerlitz 	if (ret)
975ed4c54e5SOr Gerlitz 		return ret;
976ed4c54e5SOr Gerlitz 
9770e0ec7e0SSean Hefty 	return qp->device->modify_qp(qp->real_qp, qp_attr, qp_attr_mask, NULL);
9781da177e4SLinus Torvalds }
9791da177e4SLinus Torvalds EXPORT_SYMBOL(ib_modify_qp);
9801da177e4SLinus Torvalds 
9811da177e4SLinus Torvalds int ib_query_qp(struct ib_qp *qp,
9821da177e4SLinus Torvalds 		struct ib_qp_attr *qp_attr,
9831da177e4SLinus Torvalds 		int qp_attr_mask,
9841da177e4SLinus Torvalds 		struct ib_qp_init_attr *qp_init_attr)
9851da177e4SLinus Torvalds {
9861da177e4SLinus Torvalds 	return qp->device->query_qp ?
9870e0ec7e0SSean Hefty 		qp->device->query_qp(qp->real_qp, qp_attr, qp_attr_mask, qp_init_attr) :
9881da177e4SLinus Torvalds 		-ENOSYS;
9891da177e4SLinus Torvalds }
9901da177e4SLinus Torvalds EXPORT_SYMBOL(ib_query_qp);
9911da177e4SLinus Torvalds 
9920e0ec7e0SSean Hefty int ib_close_qp(struct ib_qp *qp)
9930e0ec7e0SSean Hefty {
9940e0ec7e0SSean Hefty 	struct ib_qp *real_qp;
9950e0ec7e0SSean Hefty 	unsigned long flags;
9960e0ec7e0SSean Hefty 
9970e0ec7e0SSean Hefty 	real_qp = qp->real_qp;
9980e0ec7e0SSean Hefty 	if (real_qp == qp)
9990e0ec7e0SSean Hefty 		return -EINVAL;
10000e0ec7e0SSean Hefty 
10010e0ec7e0SSean Hefty 	spin_lock_irqsave(&real_qp->device->event_handler_lock, flags);
10020e0ec7e0SSean Hefty 	list_del(&qp->open_list);
10030e0ec7e0SSean Hefty 	spin_unlock_irqrestore(&real_qp->device->event_handler_lock, flags);
10040e0ec7e0SSean Hefty 
10050e0ec7e0SSean Hefty 	atomic_dec(&real_qp->usecnt);
10060e0ec7e0SSean Hefty 	kfree(qp);
10070e0ec7e0SSean Hefty 
10080e0ec7e0SSean Hefty 	return 0;
10090e0ec7e0SSean Hefty }
10100e0ec7e0SSean Hefty EXPORT_SYMBOL(ib_close_qp);
10110e0ec7e0SSean Hefty 
10120e0ec7e0SSean Hefty static int __ib_destroy_shared_qp(struct ib_qp *qp)
10130e0ec7e0SSean Hefty {
10140e0ec7e0SSean Hefty 	struct ib_xrcd *xrcd;
10150e0ec7e0SSean Hefty 	struct ib_qp *real_qp;
10160e0ec7e0SSean Hefty 	int ret;
10170e0ec7e0SSean Hefty 
10180e0ec7e0SSean Hefty 	real_qp = qp->real_qp;
10190e0ec7e0SSean Hefty 	xrcd = real_qp->xrcd;
10200e0ec7e0SSean Hefty 
10210e0ec7e0SSean Hefty 	mutex_lock(&xrcd->tgt_qp_mutex);
10220e0ec7e0SSean Hefty 	ib_close_qp(qp);
10230e0ec7e0SSean Hefty 	if (atomic_read(&real_qp->usecnt) == 0)
10240e0ec7e0SSean Hefty 		list_del(&real_qp->xrcd_list);
10250e0ec7e0SSean Hefty 	else
10260e0ec7e0SSean Hefty 		real_qp = NULL;
10270e0ec7e0SSean Hefty 	mutex_unlock(&xrcd->tgt_qp_mutex);
10280e0ec7e0SSean Hefty 
10290e0ec7e0SSean Hefty 	if (real_qp) {
10300e0ec7e0SSean Hefty 		ret = ib_destroy_qp(real_qp);
10310e0ec7e0SSean Hefty 		if (!ret)
10320e0ec7e0SSean Hefty 			atomic_dec(&xrcd->usecnt);
10330e0ec7e0SSean Hefty 		else
10340e0ec7e0SSean Hefty 			__ib_insert_xrcd_qp(xrcd, real_qp);
10350e0ec7e0SSean Hefty 	}
10360e0ec7e0SSean Hefty 
10370e0ec7e0SSean Hefty 	return 0;
10380e0ec7e0SSean Hefty }
10390e0ec7e0SSean Hefty 
10401da177e4SLinus Torvalds int ib_destroy_qp(struct ib_qp *qp)
10411da177e4SLinus Torvalds {
10421da177e4SLinus Torvalds 	struct ib_pd *pd;
10431da177e4SLinus Torvalds 	struct ib_cq *scq, *rcq;
10441da177e4SLinus Torvalds 	struct ib_srq *srq;
10451da177e4SLinus Torvalds 	int ret;
10461da177e4SLinus Torvalds 
10470e0ec7e0SSean Hefty 	if (atomic_read(&qp->usecnt))
10480e0ec7e0SSean Hefty 		return -EBUSY;
10490e0ec7e0SSean Hefty 
10500e0ec7e0SSean Hefty 	if (qp->real_qp != qp)
10510e0ec7e0SSean Hefty 		return __ib_destroy_shared_qp(qp);
10520e0ec7e0SSean Hefty 
10531da177e4SLinus Torvalds 	pd   = qp->pd;
10541da177e4SLinus Torvalds 	scq  = qp->send_cq;
10551da177e4SLinus Torvalds 	rcq  = qp->recv_cq;
10561da177e4SLinus Torvalds 	srq  = qp->srq;
10571da177e4SLinus Torvalds 
10581da177e4SLinus Torvalds 	ret = qp->device->destroy_qp(qp);
10591da177e4SLinus Torvalds 	if (!ret) {
1060b42b63cfSSean Hefty 		if (pd)
10611da177e4SLinus Torvalds 			atomic_dec(&pd->usecnt);
1062b42b63cfSSean Hefty 		if (scq)
10631da177e4SLinus Torvalds 			atomic_dec(&scq->usecnt);
1064b42b63cfSSean Hefty 		if (rcq)
10651da177e4SLinus Torvalds 			atomic_dec(&rcq->usecnt);
10661da177e4SLinus Torvalds 		if (srq)
10671da177e4SLinus Torvalds 			atomic_dec(&srq->usecnt);
10681da177e4SLinus Torvalds 	}
10691da177e4SLinus Torvalds 
10701da177e4SLinus Torvalds 	return ret;
10711da177e4SLinus Torvalds }
10721da177e4SLinus Torvalds EXPORT_SYMBOL(ib_destroy_qp);
10731da177e4SLinus Torvalds 
10741da177e4SLinus Torvalds /* Completion queues */
10751da177e4SLinus Torvalds 
10761da177e4SLinus Torvalds struct ib_cq *ib_create_cq(struct ib_device *device,
10771da177e4SLinus Torvalds 			   ib_comp_handler comp_handler,
10781da177e4SLinus Torvalds 			   void (*event_handler)(struct ib_event *, void *),
10798e37210bSMatan Barak 			   void *cq_context,
10808e37210bSMatan Barak 			   const struct ib_cq_init_attr *cq_attr)
10811da177e4SLinus Torvalds {
10821da177e4SLinus Torvalds 	struct ib_cq *cq;
10831da177e4SLinus Torvalds 
10848e37210bSMatan Barak 	cq = device->create_cq(device, cq_attr, NULL, NULL);
10851da177e4SLinus Torvalds 
10861da177e4SLinus Torvalds 	if (!IS_ERR(cq)) {
10871da177e4SLinus Torvalds 		cq->device        = device;
1088b5e81bf5SRoland Dreier 		cq->uobject       = NULL;
10891da177e4SLinus Torvalds 		cq->comp_handler  = comp_handler;
10901da177e4SLinus Torvalds 		cq->event_handler = event_handler;
10911da177e4SLinus Torvalds 		cq->cq_context    = cq_context;
10921da177e4SLinus Torvalds 		atomic_set(&cq->usecnt, 0);
10931da177e4SLinus Torvalds 	}
10941da177e4SLinus Torvalds 
10951da177e4SLinus Torvalds 	return cq;
10961da177e4SLinus Torvalds }
10971da177e4SLinus Torvalds EXPORT_SYMBOL(ib_create_cq);
10981da177e4SLinus Torvalds 
10992dd57162SEli Cohen int ib_modify_cq(struct ib_cq *cq, u16 cq_count, u16 cq_period)
11002dd57162SEli Cohen {
11012dd57162SEli Cohen 	return cq->device->modify_cq ?
11022dd57162SEli Cohen 		cq->device->modify_cq(cq, cq_count, cq_period) : -ENOSYS;
11032dd57162SEli Cohen }
11042dd57162SEli Cohen EXPORT_SYMBOL(ib_modify_cq);
11052dd57162SEli Cohen 
11061da177e4SLinus Torvalds int ib_destroy_cq(struct ib_cq *cq)
11071da177e4SLinus Torvalds {
11081da177e4SLinus Torvalds 	if (atomic_read(&cq->usecnt))
11091da177e4SLinus Torvalds 		return -EBUSY;
11101da177e4SLinus Torvalds 
11111da177e4SLinus Torvalds 	return cq->device->destroy_cq(cq);
11121da177e4SLinus Torvalds }
11131da177e4SLinus Torvalds EXPORT_SYMBOL(ib_destroy_cq);
11141da177e4SLinus Torvalds 
1115a74cd4afSRoland Dreier int ib_resize_cq(struct ib_cq *cq, int cqe)
11161da177e4SLinus Torvalds {
111740de2e54SRoland Dreier 	return cq->device->resize_cq ?
111833b9b3eeSRoland Dreier 		cq->device->resize_cq(cq, cqe, NULL) : -ENOSYS;
11191da177e4SLinus Torvalds }
11201da177e4SLinus Torvalds EXPORT_SYMBOL(ib_resize_cq);
11211da177e4SLinus Torvalds 
11221da177e4SLinus Torvalds /* Memory regions */
11231da177e4SLinus Torvalds 
11241da177e4SLinus Torvalds struct ib_mr *ib_get_dma_mr(struct ib_pd *pd, int mr_access_flags)
11251da177e4SLinus Torvalds {
11261da177e4SLinus Torvalds 	struct ib_mr *mr;
11271c636f80SEli Cohen 	int err;
11281c636f80SEli Cohen 
11291c636f80SEli Cohen 	err = ib_check_mr_access(mr_access_flags);
11301c636f80SEli Cohen 	if (err)
11311c636f80SEli Cohen 		return ERR_PTR(err);
11321da177e4SLinus Torvalds 
11331da177e4SLinus Torvalds 	mr = pd->device->get_dma_mr(pd, mr_access_flags);
11341da177e4SLinus Torvalds 
11351da177e4SLinus Torvalds 	if (!IS_ERR(mr)) {
11361da177e4SLinus Torvalds 		mr->device  = pd->device;
11371da177e4SLinus Torvalds 		mr->pd      = pd;
1138b5e81bf5SRoland Dreier 		mr->uobject = NULL;
11391da177e4SLinus Torvalds 		atomic_inc(&pd->usecnt);
11401da177e4SLinus Torvalds 		atomic_set(&mr->usecnt, 0);
11411da177e4SLinus Torvalds 	}
11421da177e4SLinus Torvalds 
11431da177e4SLinus Torvalds 	return mr;
11441da177e4SLinus Torvalds }
11451da177e4SLinus Torvalds EXPORT_SYMBOL(ib_get_dma_mr);
11461da177e4SLinus Torvalds 
11471da177e4SLinus Torvalds struct ib_mr *ib_reg_phys_mr(struct ib_pd *pd,
11481da177e4SLinus Torvalds 			     struct ib_phys_buf *phys_buf_array,
11491da177e4SLinus Torvalds 			     int num_phys_buf,
11501da177e4SLinus Torvalds 			     int mr_access_flags,
11511da177e4SLinus Torvalds 			     u64 *iova_start)
11521da177e4SLinus Torvalds {
11531da177e4SLinus Torvalds 	struct ib_mr *mr;
11541c636f80SEli Cohen 	int err;
11551c636f80SEli Cohen 
11561c636f80SEli Cohen 	err = ib_check_mr_access(mr_access_flags);
11571c636f80SEli Cohen 	if (err)
11581c636f80SEli Cohen 		return ERR_PTR(err);
11591da177e4SLinus Torvalds 
11607ce5eacbSDotan Barak 	if (!pd->device->reg_phys_mr)
11617ce5eacbSDotan Barak 		return ERR_PTR(-ENOSYS);
11627ce5eacbSDotan Barak 
11631da177e4SLinus Torvalds 	mr = pd->device->reg_phys_mr(pd, phys_buf_array, num_phys_buf,
11641da177e4SLinus Torvalds 				     mr_access_flags, iova_start);
11651da177e4SLinus Torvalds 
11661da177e4SLinus Torvalds 	if (!IS_ERR(mr)) {
11671da177e4SLinus Torvalds 		mr->device  = pd->device;
11681da177e4SLinus Torvalds 		mr->pd      = pd;
1169b5e81bf5SRoland Dreier 		mr->uobject = NULL;
11701da177e4SLinus Torvalds 		atomic_inc(&pd->usecnt);
11711da177e4SLinus Torvalds 		atomic_set(&mr->usecnt, 0);
11721da177e4SLinus Torvalds 	}
11731da177e4SLinus Torvalds 
11741da177e4SLinus Torvalds 	return mr;
11751da177e4SLinus Torvalds }
11761da177e4SLinus Torvalds EXPORT_SYMBOL(ib_reg_phys_mr);
11771da177e4SLinus Torvalds 
11781da177e4SLinus Torvalds int ib_rereg_phys_mr(struct ib_mr *mr,
11791da177e4SLinus Torvalds 		     int mr_rereg_mask,
11801da177e4SLinus Torvalds 		     struct ib_pd *pd,
11811da177e4SLinus Torvalds 		     struct ib_phys_buf *phys_buf_array,
11821da177e4SLinus Torvalds 		     int num_phys_buf,
11831da177e4SLinus Torvalds 		     int mr_access_flags,
11841da177e4SLinus Torvalds 		     u64 *iova_start)
11851da177e4SLinus Torvalds {
11861da177e4SLinus Torvalds 	struct ib_pd *old_pd;
11871da177e4SLinus Torvalds 	int ret;
11881da177e4SLinus Torvalds 
11891c636f80SEli Cohen 	ret = ib_check_mr_access(mr_access_flags);
11901c636f80SEli Cohen 	if (ret)
11911c636f80SEli Cohen 		return ret;
11921c636f80SEli Cohen 
11931da177e4SLinus Torvalds 	if (!mr->device->rereg_phys_mr)
11941da177e4SLinus Torvalds 		return -ENOSYS;
11951da177e4SLinus Torvalds 
11961da177e4SLinus Torvalds 	if (atomic_read(&mr->usecnt))
11971da177e4SLinus Torvalds 		return -EBUSY;
11981da177e4SLinus Torvalds 
11991da177e4SLinus Torvalds 	old_pd = mr->pd;
12001da177e4SLinus Torvalds 
12011da177e4SLinus Torvalds 	ret = mr->device->rereg_phys_mr(mr, mr_rereg_mask, pd,
12021da177e4SLinus Torvalds 					phys_buf_array, num_phys_buf,
12031da177e4SLinus Torvalds 					mr_access_flags, iova_start);
12041da177e4SLinus Torvalds 
12051da177e4SLinus Torvalds 	if (!ret && (mr_rereg_mask & IB_MR_REREG_PD)) {
12061da177e4SLinus Torvalds 		atomic_dec(&old_pd->usecnt);
12071da177e4SLinus Torvalds 		atomic_inc(&pd->usecnt);
12081da177e4SLinus Torvalds 	}
12091da177e4SLinus Torvalds 
12101da177e4SLinus Torvalds 	return ret;
12111da177e4SLinus Torvalds }
12121da177e4SLinus Torvalds EXPORT_SYMBOL(ib_rereg_phys_mr);
12131da177e4SLinus Torvalds 
12141da177e4SLinus Torvalds int ib_query_mr(struct ib_mr *mr, struct ib_mr_attr *mr_attr)
12151da177e4SLinus Torvalds {
12161da177e4SLinus Torvalds 	return mr->device->query_mr ?
12171da177e4SLinus Torvalds 		mr->device->query_mr(mr, mr_attr) : -ENOSYS;
12181da177e4SLinus Torvalds }
12191da177e4SLinus Torvalds EXPORT_SYMBOL(ib_query_mr);
12201da177e4SLinus Torvalds 
12211da177e4SLinus Torvalds int ib_dereg_mr(struct ib_mr *mr)
12221da177e4SLinus Torvalds {
12231da177e4SLinus Torvalds 	struct ib_pd *pd;
12241da177e4SLinus Torvalds 	int ret;
12251da177e4SLinus Torvalds 
12261da177e4SLinus Torvalds 	if (atomic_read(&mr->usecnt))
12271da177e4SLinus Torvalds 		return -EBUSY;
12281da177e4SLinus Torvalds 
12291da177e4SLinus Torvalds 	pd = mr->pd;
12301da177e4SLinus Torvalds 	ret = mr->device->dereg_mr(mr);
12311da177e4SLinus Torvalds 	if (!ret)
12321da177e4SLinus Torvalds 		atomic_dec(&pd->usecnt);
12331da177e4SLinus Torvalds 
12341da177e4SLinus Torvalds 	return ret;
12351da177e4SLinus Torvalds }
12361da177e4SLinus Torvalds EXPORT_SYMBOL(ib_dereg_mr);
12371da177e4SLinus Torvalds 
12389bee178bSSagi Grimberg /**
12399bee178bSSagi Grimberg  * ib_alloc_mr() - Allocates a memory region
12409bee178bSSagi Grimberg  * @pd:            protection domain associated with the region
12419bee178bSSagi Grimberg  * @mr_type:       memory region type
12429bee178bSSagi Grimberg  * @max_num_sg:    maximum sg entries available for registration.
12439bee178bSSagi Grimberg  *
12449bee178bSSagi Grimberg  * Notes:
12459bee178bSSagi Grimberg  * Memory registeration page/sg lists must not exceed max_num_sg.
12469bee178bSSagi Grimberg  * For mr_type IB_MR_TYPE_MEM_REG, the total length cannot exceed
12479bee178bSSagi Grimberg  * max_num_sg * used_page_size.
12489bee178bSSagi Grimberg  *
12499bee178bSSagi Grimberg  */
12509bee178bSSagi Grimberg struct ib_mr *ib_alloc_mr(struct ib_pd *pd,
12519bee178bSSagi Grimberg 			  enum ib_mr_type mr_type,
12529bee178bSSagi Grimberg 			  u32 max_num_sg)
125317cd3a2dSSagi Grimberg {
125417cd3a2dSSagi Grimberg 	struct ib_mr *mr;
125517cd3a2dSSagi Grimberg 
1256d9f272c5SSagi Grimberg 	if (!pd->device->alloc_mr)
125717cd3a2dSSagi Grimberg 		return ERR_PTR(-ENOSYS);
125817cd3a2dSSagi Grimberg 
1259d9f272c5SSagi Grimberg 	mr = pd->device->alloc_mr(pd, mr_type, max_num_sg);
126017cd3a2dSSagi Grimberg 	if (!IS_ERR(mr)) {
126117cd3a2dSSagi Grimberg 		mr->device  = pd->device;
126217cd3a2dSSagi Grimberg 		mr->pd      = pd;
126317cd3a2dSSagi Grimberg 		mr->uobject = NULL;
126417cd3a2dSSagi Grimberg 		atomic_inc(&pd->usecnt);
126517cd3a2dSSagi Grimberg 		atomic_set(&mr->usecnt, 0);
126617cd3a2dSSagi Grimberg 	}
126717cd3a2dSSagi Grimberg 
126817cd3a2dSSagi Grimberg 	return mr;
126917cd3a2dSSagi Grimberg }
12709bee178bSSagi Grimberg EXPORT_SYMBOL(ib_alloc_mr);
127117cd3a2dSSagi Grimberg 
127200f7ec36SSteve Wise struct ib_fast_reg_page_list *ib_alloc_fast_reg_page_list(struct ib_device *device,
127300f7ec36SSteve Wise 							  int max_page_list_len)
127400f7ec36SSteve Wise {
127500f7ec36SSteve Wise 	struct ib_fast_reg_page_list *page_list;
127600f7ec36SSteve Wise 
127700f7ec36SSteve Wise 	if (!device->alloc_fast_reg_page_list)
127800f7ec36SSteve Wise 		return ERR_PTR(-ENOSYS);
127900f7ec36SSteve Wise 
128000f7ec36SSteve Wise 	page_list = device->alloc_fast_reg_page_list(device, max_page_list_len);
128100f7ec36SSteve Wise 
128200f7ec36SSteve Wise 	if (!IS_ERR(page_list)) {
128300f7ec36SSteve Wise 		page_list->device = device;
128400f7ec36SSteve Wise 		page_list->max_page_list_len = max_page_list_len;
128500f7ec36SSteve Wise 	}
128600f7ec36SSteve Wise 
128700f7ec36SSteve Wise 	return page_list;
128800f7ec36SSteve Wise }
128900f7ec36SSteve Wise EXPORT_SYMBOL(ib_alloc_fast_reg_page_list);
129000f7ec36SSteve Wise 
129100f7ec36SSteve Wise void ib_free_fast_reg_page_list(struct ib_fast_reg_page_list *page_list)
129200f7ec36SSteve Wise {
129300f7ec36SSteve Wise 	page_list->device->free_fast_reg_page_list(page_list);
129400f7ec36SSteve Wise }
129500f7ec36SSteve Wise EXPORT_SYMBOL(ib_free_fast_reg_page_list);
129600f7ec36SSteve Wise 
12971da177e4SLinus Torvalds /* Memory windows */
12981da177e4SLinus Torvalds 
12997083e42eSShani Michaeli struct ib_mw *ib_alloc_mw(struct ib_pd *pd, enum ib_mw_type type)
13001da177e4SLinus Torvalds {
13011da177e4SLinus Torvalds 	struct ib_mw *mw;
13021da177e4SLinus Torvalds 
13031da177e4SLinus Torvalds 	if (!pd->device->alloc_mw)
13041da177e4SLinus Torvalds 		return ERR_PTR(-ENOSYS);
13051da177e4SLinus Torvalds 
13067083e42eSShani Michaeli 	mw = pd->device->alloc_mw(pd, type);
13071da177e4SLinus Torvalds 	if (!IS_ERR(mw)) {
13081da177e4SLinus Torvalds 		mw->device  = pd->device;
13091da177e4SLinus Torvalds 		mw->pd      = pd;
1310b5e81bf5SRoland Dreier 		mw->uobject = NULL;
13117083e42eSShani Michaeli 		mw->type    = type;
13121da177e4SLinus Torvalds 		atomic_inc(&pd->usecnt);
13131da177e4SLinus Torvalds 	}
13141da177e4SLinus Torvalds 
13151da177e4SLinus Torvalds 	return mw;
13161da177e4SLinus Torvalds }
13171da177e4SLinus Torvalds EXPORT_SYMBOL(ib_alloc_mw);
13181da177e4SLinus Torvalds 
13191da177e4SLinus Torvalds int ib_dealloc_mw(struct ib_mw *mw)
13201da177e4SLinus Torvalds {
13211da177e4SLinus Torvalds 	struct ib_pd *pd;
13221da177e4SLinus Torvalds 	int ret;
13231da177e4SLinus Torvalds 
13241da177e4SLinus Torvalds 	pd = mw->pd;
13251da177e4SLinus Torvalds 	ret = mw->device->dealloc_mw(mw);
13261da177e4SLinus Torvalds 	if (!ret)
13271da177e4SLinus Torvalds 		atomic_dec(&pd->usecnt);
13281da177e4SLinus Torvalds 
13291da177e4SLinus Torvalds 	return ret;
13301da177e4SLinus Torvalds }
13311da177e4SLinus Torvalds EXPORT_SYMBOL(ib_dealloc_mw);
13321da177e4SLinus Torvalds 
13331da177e4SLinus Torvalds /* "Fast" memory regions */
13341da177e4SLinus Torvalds 
13351da177e4SLinus Torvalds struct ib_fmr *ib_alloc_fmr(struct ib_pd *pd,
13361da177e4SLinus Torvalds 			    int mr_access_flags,
13371da177e4SLinus Torvalds 			    struct ib_fmr_attr *fmr_attr)
13381da177e4SLinus Torvalds {
13391da177e4SLinus Torvalds 	struct ib_fmr *fmr;
13401da177e4SLinus Torvalds 
13411da177e4SLinus Torvalds 	if (!pd->device->alloc_fmr)
13421da177e4SLinus Torvalds 		return ERR_PTR(-ENOSYS);
13431da177e4SLinus Torvalds 
13441da177e4SLinus Torvalds 	fmr = pd->device->alloc_fmr(pd, mr_access_flags, fmr_attr);
13451da177e4SLinus Torvalds 	if (!IS_ERR(fmr)) {
13461da177e4SLinus Torvalds 		fmr->device = pd->device;
13471da177e4SLinus Torvalds 		fmr->pd     = pd;
13481da177e4SLinus Torvalds 		atomic_inc(&pd->usecnt);
13491da177e4SLinus Torvalds 	}
13501da177e4SLinus Torvalds 
13511da177e4SLinus Torvalds 	return fmr;
13521da177e4SLinus Torvalds }
13531da177e4SLinus Torvalds EXPORT_SYMBOL(ib_alloc_fmr);
13541da177e4SLinus Torvalds 
13551da177e4SLinus Torvalds int ib_unmap_fmr(struct list_head *fmr_list)
13561da177e4SLinus Torvalds {
13571da177e4SLinus Torvalds 	struct ib_fmr *fmr;
13581da177e4SLinus Torvalds 
13591da177e4SLinus Torvalds 	if (list_empty(fmr_list))
13601da177e4SLinus Torvalds 		return 0;
13611da177e4SLinus Torvalds 
13621da177e4SLinus Torvalds 	fmr = list_entry(fmr_list->next, struct ib_fmr, list);
13631da177e4SLinus Torvalds 	return fmr->device->unmap_fmr(fmr_list);
13641da177e4SLinus Torvalds }
13651da177e4SLinus Torvalds EXPORT_SYMBOL(ib_unmap_fmr);
13661da177e4SLinus Torvalds 
13671da177e4SLinus Torvalds int ib_dealloc_fmr(struct ib_fmr *fmr)
13681da177e4SLinus Torvalds {
13691da177e4SLinus Torvalds 	struct ib_pd *pd;
13701da177e4SLinus Torvalds 	int ret;
13711da177e4SLinus Torvalds 
13721da177e4SLinus Torvalds 	pd = fmr->pd;
13731da177e4SLinus Torvalds 	ret = fmr->device->dealloc_fmr(fmr);
13741da177e4SLinus Torvalds 	if (!ret)
13751da177e4SLinus Torvalds 		atomic_dec(&pd->usecnt);
13761da177e4SLinus Torvalds 
13771da177e4SLinus Torvalds 	return ret;
13781da177e4SLinus Torvalds }
13791da177e4SLinus Torvalds EXPORT_SYMBOL(ib_dealloc_fmr);
13801da177e4SLinus Torvalds 
13811da177e4SLinus Torvalds /* Multicast groups */
13821da177e4SLinus Torvalds 
13831da177e4SLinus Torvalds int ib_attach_mcast(struct ib_qp *qp, union ib_gid *gid, u16 lid)
13841da177e4SLinus Torvalds {
1385c3bccbfbSOr Gerlitz 	int ret;
1386c3bccbfbSOr Gerlitz 
13870c33aeedSJack Morgenstein 	if (!qp->device->attach_mcast)
13880c33aeedSJack Morgenstein 		return -ENOSYS;
13890c33aeedSJack Morgenstein 	if (gid->raw[0] != 0xff || qp->qp_type != IB_QPT_UD)
13900c33aeedSJack Morgenstein 		return -EINVAL;
13910c33aeedSJack Morgenstein 
1392c3bccbfbSOr Gerlitz 	ret = qp->device->attach_mcast(qp, gid, lid);
1393c3bccbfbSOr Gerlitz 	if (!ret)
1394c3bccbfbSOr Gerlitz 		atomic_inc(&qp->usecnt);
1395c3bccbfbSOr Gerlitz 	return ret;
13961da177e4SLinus Torvalds }
13971da177e4SLinus Torvalds EXPORT_SYMBOL(ib_attach_mcast);
13981da177e4SLinus Torvalds 
13991da177e4SLinus Torvalds int ib_detach_mcast(struct ib_qp *qp, union ib_gid *gid, u16 lid)
14001da177e4SLinus Torvalds {
1401c3bccbfbSOr Gerlitz 	int ret;
1402c3bccbfbSOr Gerlitz 
14030c33aeedSJack Morgenstein 	if (!qp->device->detach_mcast)
14040c33aeedSJack Morgenstein 		return -ENOSYS;
14050c33aeedSJack Morgenstein 	if (gid->raw[0] != 0xff || qp->qp_type != IB_QPT_UD)
14060c33aeedSJack Morgenstein 		return -EINVAL;
14070c33aeedSJack Morgenstein 
1408c3bccbfbSOr Gerlitz 	ret = qp->device->detach_mcast(qp, gid, lid);
1409c3bccbfbSOr Gerlitz 	if (!ret)
1410c3bccbfbSOr Gerlitz 		atomic_dec(&qp->usecnt);
1411c3bccbfbSOr Gerlitz 	return ret;
14121da177e4SLinus Torvalds }
14131da177e4SLinus Torvalds EXPORT_SYMBOL(ib_detach_mcast);
141459991f94SSean Hefty 
141559991f94SSean Hefty struct ib_xrcd *ib_alloc_xrcd(struct ib_device *device)
141659991f94SSean Hefty {
141759991f94SSean Hefty 	struct ib_xrcd *xrcd;
141859991f94SSean Hefty 
141959991f94SSean Hefty 	if (!device->alloc_xrcd)
142059991f94SSean Hefty 		return ERR_PTR(-ENOSYS);
142159991f94SSean Hefty 
142259991f94SSean Hefty 	xrcd = device->alloc_xrcd(device, NULL, NULL);
142359991f94SSean Hefty 	if (!IS_ERR(xrcd)) {
142459991f94SSean Hefty 		xrcd->device = device;
142553d0bd1eSSean Hefty 		xrcd->inode = NULL;
142659991f94SSean Hefty 		atomic_set(&xrcd->usecnt, 0);
1427d3d72d90SSean Hefty 		mutex_init(&xrcd->tgt_qp_mutex);
1428d3d72d90SSean Hefty 		INIT_LIST_HEAD(&xrcd->tgt_qp_list);
142959991f94SSean Hefty 	}
143059991f94SSean Hefty 
143159991f94SSean Hefty 	return xrcd;
143259991f94SSean Hefty }
143359991f94SSean Hefty EXPORT_SYMBOL(ib_alloc_xrcd);
143459991f94SSean Hefty 
143559991f94SSean Hefty int ib_dealloc_xrcd(struct ib_xrcd *xrcd)
143659991f94SSean Hefty {
1437d3d72d90SSean Hefty 	struct ib_qp *qp;
1438d3d72d90SSean Hefty 	int ret;
1439d3d72d90SSean Hefty 
144059991f94SSean Hefty 	if (atomic_read(&xrcd->usecnt))
144159991f94SSean Hefty 		return -EBUSY;
144259991f94SSean Hefty 
1443d3d72d90SSean Hefty 	while (!list_empty(&xrcd->tgt_qp_list)) {
1444d3d72d90SSean Hefty 		qp = list_entry(xrcd->tgt_qp_list.next, struct ib_qp, xrcd_list);
1445d3d72d90SSean Hefty 		ret = ib_destroy_qp(qp);
1446d3d72d90SSean Hefty 		if (ret)
1447d3d72d90SSean Hefty 			return ret;
1448d3d72d90SSean Hefty 	}
1449d3d72d90SSean Hefty 
145059991f94SSean Hefty 	return xrcd->device->dealloc_xrcd(xrcd);
145159991f94SSean Hefty }
145259991f94SSean Hefty EXPORT_SYMBOL(ib_dealloc_xrcd);
1453319a441dSHadar Hen Zion 
1454319a441dSHadar Hen Zion struct ib_flow *ib_create_flow(struct ib_qp *qp,
1455319a441dSHadar Hen Zion 			       struct ib_flow_attr *flow_attr,
1456319a441dSHadar Hen Zion 			       int domain)
1457319a441dSHadar Hen Zion {
1458319a441dSHadar Hen Zion 	struct ib_flow *flow_id;
1459319a441dSHadar Hen Zion 	if (!qp->device->create_flow)
1460319a441dSHadar Hen Zion 		return ERR_PTR(-ENOSYS);
1461319a441dSHadar Hen Zion 
1462319a441dSHadar Hen Zion 	flow_id = qp->device->create_flow(qp, flow_attr, domain);
1463319a441dSHadar Hen Zion 	if (!IS_ERR(flow_id))
1464319a441dSHadar Hen Zion 		atomic_inc(&qp->usecnt);
1465319a441dSHadar Hen Zion 	return flow_id;
1466319a441dSHadar Hen Zion }
1467319a441dSHadar Hen Zion EXPORT_SYMBOL(ib_create_flow);
1468319a441dSHadar Hen Zion 
1469319a441dSHadar Hen Zion int ib_destroy_flow(struct ib_flow *flow_id)
1470319a441dSHadar Hen Zion {
1471319a441dSHadar Hen Zion 	int err;
1472319a441dSHadar Hen Zion 	struct ib_qp *qp = flow_id->qp;
1473319a441dSHadar Hen Zion 
1474319a441dSHadar Hen Zion 	err = qp->device->destroy_flow(flow_id);
1475319a441dSHadar Hen Zion 	if (!err)
1476319a441dSHadar Hen Zion 		atomic_dec(&qp->usecnt);
1477319a441dSHadar Hen Zion 	return err;
1478319a441dSHadar Hen Zion }
1479319a441dSHadar Hen Zion EXPORT_SYMBOL(ib_destroy_flow);
14801b01d335SSagi Grimberg 
14811b01d335SSagi Grimberg int ib_check_mr_status(struct ib_mr *mr, u32 check_mask,
14821b01d335SSagi Grimberg 		       struct ib_mr_status *mr_status)
14831b01d335SSagi Grimberg {
14841b01d335SSagi Grimberg 	return mr->device->check_mr_status ?
14851b01d335SSagi Grimberg 		mr->device->check_mr_status(mr, check_mask, mr_status) : -ENOSYS;
14861b01d335SSagi Grimberg }
14871b01d335SSagi Grimberg EXPORT_SYMBOL(ib_check_mr_status);
1488