1// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
2/*
3 * Copyright (c) 2020, Mellanox Technologies inc.  All rights reserved.
4 */
5
6#include <rdma/uverbs_std_types.h>
7#include "rdma_core.h"
8#include "uverbs.h"
9#include "core_priv.h"
10
11static int uverbs_free_qp(struct ib_uobject *uobject,
12			  enum rdma_remove_reason why,
13			  struct uverbs_attr_bundle *attrs)
14{
15	struct ib_qp *qp = uobject->object;
16	struct ib_uqp_object *uqp =
17		container_of(uobject, struct ib_uqp_object, uevent.uobject);
18	int ret;
19
20	/*
21	 * If this is a user triggered destroy then do not allow destruction
22	 * until the user cleans up all the mcast bindings. Unlike in other
23	 * places we forcibly clean up the mcast attachments for !DESTROY
24	 * because the mcast attaches are not ubojects and will not be
25	 * destroyed by anything else during cleanup processing.
26	 */
27	if (why == RDMA_REMOVE_DESTROY) {
28		if (!list_empty(&uqp->mcast_list))
29			return -EBUSY;
30	} else if (qp == qp->real_qp) {
31		ib_uverbs_detach_umcast(qp, uqp);
32	}
33
34	ret = ib_destroy_qp_user(qp, &attrs->driver_udata);
35	if (ret)
36		return ret;
37
38	if (uqp->uxrcd)
39		atomic_dec(&uqp->uxrcd->refcnt);
40
41	ib_uverbs_release_uevent(&uqp->uevent);
42	return 0;
43}
44
45static int check_creation_flags(enum ib_qp_type qp_type,
46				u32 create_flags)
47{
48	create_flags &= ~IB_UVERBS_QP_CREATE_SQ_SIG_ALL;
49
50	if (!create_flags || qp_type == IB_QPT_DRIVER)
51		return 0;
52
53	if (qp_type != IB_QPT_RAW_PACKET && qp_type != IB_QPT_UD)
54		return -EINVAL;
55
56	if ((create_flags & IB_UVERBS_QP_CREATE_SCATTER_FCS ||
57	     create_flags & IB_UVERBS_QP_CREATE_CVLAN_STRIPPING) &&
58	     qp_type != IB_QPT_RAW_PACKET)
59		return -EINVAL;
60
61	return 0;
62}
63
64static void set_caps(struct ib_qp_init_attr *attr,
65		     struct ib_uverbs_qp_cap *cap, bool req)
66{
67	if (req) {
68		attr->cap.max_send_wr = cap->max_send_wr;
69		attr->cap.max_recv_wr = cap->max_recv_wr;
70		attr->cap.max_send_sge = cap->max_send_sge;
71		attr->cap.max_recv_sge = cap->max_recv_sge;
72		attr->cap.max_inline_data = cap->max_inline_data;
73	} else {
74		cap->max_send_wr = attr->cap.max_send_wr;
75		cap->max_recv_wr = attr->cap.max_recv_wr;
76		cap->max_send_sge = attr->cap.max_send_sge;
77		cap->max_recv_sge = attr->cap.max_recv_sge;
78		cap->max_inline_data = attr->cap.max_inline_data;
79	}
80}
81
82static int UVERBS_HANDLER(UVERBS_METHOD_QP_CREATE)(
83	struct uverbs_attr_bundle *attrs)
84{
85	struct ib_uqp_object *obj = container_of(
86		uverbs_attr_get_uobject(attrs, UVERBS_ATTR_CREATE_QP_HANDLE),
87		typeof(*obj), uevent.uobject);
88	struct ib_qp_init_attr attr = {};
89	struct ib_uverbs_qp_cap cap = {};
90	struct ib_rwq_ind_table *rwq_ind_tbl = NULL;
91	struct ib_qp *qp;
92	struct ib_pd *pd = NULL;
93	struct ib_srq *srq = NULL;
94	struct ib_cq *recv_cq = NULL;
95	struct ib_cq *send_cq = NULL;
96	struct ib_xrcd *xrcd = NULL;
97	struct ib_uobject *xrcd_uobj = NULL;
98	struct ib_device *device;
99	u64 user_handle;
100	int ret;
101
102	ret = uverbs_copy_from_or_zero(&cap, attrs,
103			       UVERBS_ATTR_CREATE_QP_CAP);
104	if (!ret)
105		ret = uverbs_copy_from(&user_handle, attrs,
106				       UVERBS_ATTR_CREATE_QP_USER_HANDLE);
107	if (!ret)
108		ret = uverbs_get_const(&attr.qp_type, attrs,
109				       UVERBS_ATTR_CREATE_QP_TYPE);
110	if (ret)
111		return ret;
112
113	switch (attr.qp_type) {
114	case IB_QPT_XRC_TGT:
115		if (uverbs_attr_is_valid(attrs,
116				UVERBS_ATTR_CREATE_QP_RECV_CQ_HANDLE) ||
117		    uverbs_attr_is_valid(attrs,
118				UVERBS_ATTR_CREATE_QP_SEND_CQ_HANDLE) ||
119		    uverbs_attr_is_valid(attrs,
120				UVERBS_ATTR_CREATE_QP_PD_HANDLE) ||
121		    uverbs_attr_is_valid(attrs,
122				UVERBS_ATTR_CREATE_QP_IND_TABLE_HANDLE))
123			return -EINVAL;
124
125		xrcd_uobj = uverbs_attr_get_uobject(attrs,
126					UVERBS_ATTR_CREATE_QP_XRCD_HANDLE);
127		if (IS_ERR(xrcd_uobj))
128			return PTR_ERR(xrcd_uobj);
129
130		xrcd = (struct ib_xrcd *)xrcd_uobj->object;
131		if (!xrcd)
132			return -EINVAL;
133		device = xrcd->device;
134		break;
135	case IB_UVERBS_QPT_RAW_PACKET:
136		if (!capable(CAP_NET_RAW))
137			return -EPERM;
138		fallthrough;
139	case IB_UVERBS_QPT_RC:
140	case IB_UVERBS_QPT_UC:
141	case IB_UVERBS_QPT_UD:
142	case IB_UVERBS_QPT_XRC_INI:
143	case IB_UVERBS_QPT_DRIVER:
144		if (uverbs_attr_is_valid(attrs,
145					 UVERBS_ATTR_CREATE_QP_XRCD_HANDLE) ||
146		   (uverbs_attr_is_valid(attrs,
147					 UVERBS_ATTR_CREATE_QP_SRQ_HANDLE) &&
148			attr.qp_type == IB_QPT_XRC_INI))
149			return -EINVAL;
150
151		pd = uverbs_attr_get_obj(attrs,
152					 UVERBS_ATTR_CREATE_QP_PD_HANDLE);
153		if (IS_ERR(pd))
154			return PTR_ERR(pd);
155
156		rwq_ind_tbl = uverbs_attr_get_obj(attrs,
157			UVERBS_ATTR_CREATE_QP_IND_TABLE_HANDLE);
158		if (!IS_ERR(rwq_ind_tbl)) {
159			if (cap.max_recv_wr || cap.max_recv_sge ||
160			    uverbs_attr_is_valid(attrs,
161				UVERBS_ATTR_CREATE_QP_RECV_CQ_HANDLE) ||
162			    uverbs_attr_is_valid(attrs,
163					UVERBS_ATTR_CREATE_QP_SRQ_HANDLE))
164				return -EINVAL;
165
166			/* send_cq is optional */
167			if (cap.max_send_wr) {
168				send_cq = uverbs_attr_get_obj(attrs,
169					UVERBS_ATTR_CREATE_QP_SEND_CQ_HANDLE);
170				if (IS_ERR(send_cq))
171					return PTR_ERR(send_cq);
172			}
173			attr.rwq_ind_tbl = rwq_ind_tbl;
174		} else {
175			send_cq = uverbs_attr_get_obj(attrs,
176					UVERBS_ATTR_CREATE_QP_SEND_CQ_HANDLE);
177			if (IS_ERR(send_cq))
178				return PTR_ERR(send_cq);
179
180			if (attr.qp_type != IB_QPT_XRC_INI) {
181				recv_cq = uverbs_attr_get_obj(attrs,
182					UVERBS_ATTR_CREATE_QP_RECV_CQ_HANDLE);
183				if (IS_ERR(recv_cq))
184					return PTR_ERR(recv_cq);
185			}
186		}
187
188		device = pd->device;
189		break;
190	default:
191		return -EINVAL;
192	}
193
194	ret = uverbs_get_flags32(&attr.create_flags, attrs,
195			 UVERBS_ATTR_CREATE_QP_FLAGS,
196			 IB_UVERBS_QP_CREATE_BLOCK_MULTICAST_LOOPBACK |
197			 IB_UVERBS_QP_CREATE_SCATTER_FCS |
198			 IB_UVERBS_QP_CREATE_CVLAN_STRIPPING |
199			 IB_UVERBS_QP_CREATE_PCI_WRITE_END_PADDING |
200			 IB_UVERBS_QP_CREATE_SQ_SIG_ALL);
201	if (ret)
202		return ret;
203
204	ret = check_creation_flags(attr.qp_type, attr.create_flags);
205	if (ret)
206		return ret;
207
208	if (uverbs_attr_is_valid(attrs,
209			UVERBS_ATTR_CREATE_QP_SOURCE_QPN)) {
210		ret = uverbs_copy_from(&attr.source_qpn, attrs,
211				       UVERBS_ATTR_CREATE_QP_SOURCE_QPN);
212		if (ret)
213			return ret;
214		attr.create_flags |= IB_QP_CREATE_SOURCE_QPN;
215	}
216
217	srq = uverbs_attr_get_obj(attrs,
218				  UVERBS_ATTR_CREATE_QP_SRQ_HANDLE);
219	if (!IS_ERR(srq)) {
220		if ((srq->srq_type == IB_SRQT_XRC &&
221			attr.qp_type != IB_QPT_XRC_TGT) ||
222		    (srq->srq_type != IB_SRQT_XRC &&
223			attr.qp_type == IB_QPT_XRC_TGT))
224			return -EINVAL;
225		attr.srq = srq;
226	}
227
228	obj->uevent.event_file = ib_uverbs_get_async_event(attrs,
229					UVERBS_ATTR_CREATE_QP_EVENT_FD);
230	INIT_LIST_HEAD(&obj->uevent.event_list);
231	INIT_LIST_HEAD(&obj->mcast_list);
232	obj->uevent.uobject.user_handle = user_handle;
233	attr.event_handler = ib_uverbs_qp_event_handler;
234	attr.send_cq = send_cq;
235	attr.recv_cq = recv_cq;
236	attr.xrcd = xrcd;
237	if (attr.create_flags & IB_UVERBS_QP_CREATE_SQ_SIG_ALL) {
238		/* This creation bit is uverbs one, need to mask before
239		 * calling drivers. It was added to prevent an extra user attr
240		 * only for that when using ioctl.
241		 */
242		attr.create_flags &= ~IB_UVERBS_QP_CREATE_SQ_SIG_ALL;
243		attr.sq_sig_type = IB_SIGNAL_ALL_WR;
244	} else {
245		attr.sq_sig_type = IB_SIGNAL_REQ_WR;
246	}
247
248	set_caps(&attr, &cap, true);
249	mutex_init(&obj->mcast_lock);
250
251	qp = ib_create_qp_user(device, pd, &attr, &attrs->driver_udata, obj,
252			       KBUILD_MODNAME);
253	if (IS_ERR(qp)) {
254		ret = PTR_ERR(qp);
255		goto err_put;
256	}
257	ib_qp_usecnt_inc(qp);
258
259	if (attr.qp_type == IB_QPT_XRC_TGT) {
260		obj->uxrcd = container_of(xrcd_uobj, struct ib_uxrcd_object,
261					  uobject);
262		atomic_inc(&obj->uxrcd->refcnt);
263	}
264
265	obj->uevent.uobject.object = qp;
266	uverbs_finalize_uobj_create(attrs, UVERBS_ATTR_CREATE_QP_HANDLE);
267
268	set_caps(&attr, &cap, false);
269	ret = uverbs_copy_to_struct_or_zero(attrs,
270					UVERBS_ATTR_CREATE_QP_RESP_CAP, &cap,
271					sizeof(cap));
272	if (ret)
273		return ret;
274
275	ret = uverbs_copy_to(attrs, UVERBS_ATTR_CREATE_QP_RESP_QP_NUM,
276			     &qp->qp_num,
277			     sizeof(qp->qp_num));
278
279	return ret;
280err_put:
281	if (obj->uevent.event_file)
282		uverbs_uobject_put(&obj->uevent.event_file->uobj);
283	return ret;
284};
285
286DECLARE_UVERBS_NAMED_METHOD(
287	UVERBS_METHOD_QP_CREATE,
288	UVERBS_ATTR_IDR(UVERBS_ATTR_CREATE_QP_HANDLE,
289			UVERBS_OBJECT_QP,
290			UVERBS_ACCESS_NEW,
291			UA_MANDATORY),
292	UVERBS_ATTR_IDR(UVERBS_ATTR_CREATE_QP_XRCD_HANDLE,
293			UVERBS_OBJECT_XRCD,
294			UVERBS_ACCESS_READ,
295			UA_OPTIONAL),
296	UVERBS_ATTR_IDR(UVERBS_ATTR_CREATE_QP_PD_HANDLE,
297			UVERBS_OBJECT_PD,
298			UVERBS_ACCESS_READ,
299			UA_OPTIONAL),
300	UVERBS_ATTR_IDR(UVERBS_ATTR_CREATE_QP_SRQ_HANDLE,
301			UVERBS_OBJECT_SRQ,
302			UVERBS_ACCESS_READ,
303			UA_OPTIONAL),
304	UVERBS_ATTR_IDR(UVERBS_ATTR_CREATE_QP_SEND_CQ_HANDLE,
305			UVERBS_OBJECT_CQ,
306			UVERBS_ACCESS_READ,
307			UA_OPTIONAL),
308	UVERBS_ATTR_IDR(UVERBS_ATTR_CREATE_QP_RECV_CQ_HANDLE,
309			UVERBS_OBJECT_CQ,
310			UVERBS_ACCESS_READ,
311			UA_OPTIONAL),
312	UVERBS_ATTR_IDR(UVERBS_ATTR_CREATE_QP_IND_TABLE_HANDLE,
313			UVERBS_OBJECT_RWQ_IND_TBL,
314			UVERBS_ACCESS_READ,
315			UA_OPTIONAL),
316	UVERBS_ATTR_PTR_IN(UVERBS_ATTR_CREATE_QP_USER_HANDLE,
317			   UVERBS_ATTR_TYPE(u64),
318			   UA_MANDATORY),
319	UVERBS_ATTR_PTR_IN(UVERBS_ATTR_CREATE_QP_CAP,
320			   UVERBS_ATTR_STRUCT(struct ib_uverbs_qp_cap,
321					      max_inline_data),
322			   UA_MANDATORY),
323	UVERBS_ATTR_CONST_IN(UVERBS_ATTR_CREATE_QP_TYPE,
324			     enum ib_uverbs_qp_type,
325			     UA_MANDATORY),
326	UVERBS_ATTR_FLAGS_IN(UVERBS_ATTR_CREATE_QP_FLAGS,
327			     enum ib_uverbs_qp_create_flags,
328			     UA_OPTIONAL),
329	UVERBS_ATTR_PTR_IN(UVERBS_ATTR_CREATE_QP_SOURCE_QPN,
330			   UVERBS_ATTR_TYPE(u32),
331			   UA_OPTIONAL),
332	UVERBS_ATTR_FD(UVERBS_ATTR_CREATE_QP_EVENT_FD,
333		       UVERBS_OBJECT_ASYNC_EVENT,
334		       UVERBS_ACCESS_READ,
335		       UA_OPTIONAL),
336	UVERBS_ATTR_PTR_OUT(UVERBS_ATTR_CREATE_QP_RESP_CAP,
337			    UVERBS_ATTR_STRUCT(struct ib_uverbs_qp_cap,
338					       max_inline_data),
339			   UA_MANDATORY),
340	UVERBS_ATTR_PTR_OUT(UVERBS_ATTR_CREATE_QP_RESP_QP_NUM,
341			   UVERBS_ATTR_TYPE(u32),
342			   UA_MANDATORY),
343	UVERBS_ATTR_UHW());
344
345static int UVERBS_HANDLER(UVERBS_METHOD_QP_DESTROY)(
346	struct uverbs_attr_bundle *attrs)
347{
348	struct ib_uobject *uobj =
349		uverbs_attr_get_uobject(attrs, UVERBS_ATTR_DESTROY_QP_HANDLE);
350	struct ib_uqp_object *obj =
351		container_of(uobj, struct ib_uqp_object, uevent.uobject);
352	struct ib_uverbs_destroy_qp_resp resp = {
353		.events_reported = obj->uevent.events_reported
354	};
355
356	return uverbs_copy_to(attrs, UVERBS_ATTR_DESTROY_QP_RESP, &resp,
357			      sizeof(resp));
358}
359
360DECLARE_UVERBS_NAMED_METHOD(
361	UVERBS_METHOD_QP_DESTROY,
362	UVERBS_ATTR_IDR(UVERBS_ATTR_DESTROY_QP_HANDLE,
363			UVERBS_OBJECT_QP,
364			UVERBS_ACCESS_DESTROY,
365			UA_MANDATORY),
366	UVERBS_ATTR_PTR_OUT(UVERBS_ATTR_DESTROY_QP_RESP,
367			    UVERBS_ATTR_TYPE(struct ib_uverbs_destroy_qp_resp),
368			    UA_MANDATORY));
369
370DECLARE_UVERBS_NAMED_OBJECT(
371	UVERBS_OBJECT_QP,
372	UVERBS_TYPE_ALLOC_IDR_SZ(sizeof(struct ib_uqp_object), uverbs_free_qp),
373	&UVERBS_METHOD(UVERBS_METHOD_QP_CREATE),
374	&UVERBS_METHOD(UVERBS_METHOD_QP_DESTROY));
375
376const struct uapi_definition uverbs_def_obj_qp[] = {
377	UAPI_DEF_CHAIN_OBJ_TREE_NAMED(UVERBS_OBJECT_QP,
378				      UAPI_DEF_OBJ_NEEDS_FN(destroy_qp)),
379	{}
380};
381