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
10static int uverbs_free_srq(struct ib_uobject *uobject,
11		    enum rdma_remove_reason why,
12		    struct uverbs_attr_bundle *attrs)
13{
14	struct ib_srq *srq = uobject->object;
15	struct ib_uevent_object *uevent =
16		container_of(uobject, struct ib_uevent_object, uobject);
17	enum ib_srq_type srq_type = srq->srq_type;
18	int ret;
19
20	ret = ib_destroy_srq_user(srq, &attrs->driver_udata);
21	if (ret)
22		return ret;
23
24	if (srq_type == IB_SRQT_XRC) {
25		struct ib_usrq_object *us =
26			container_of(uobject, struct ib_usrq_object,
27				     uevent.uobject);
28
29		atomic_dec(&us->uxrcd->refcnt);
30	}
31
32	ib_uverbs_release_uevent(uevent);
33	return 0;
34}
35
36static int UVERBS_HANDLER(UVERBS_METHOD_SRQ_CREATE)(
37	struct uverbs_attr_bundle *attrs)
38{
39	struct ib_usrq_object *obj = container_of(
40		uverbs_attr_get_uobject(attrs, UVERBS_ATTR_CREATE_SRQ_HANDLE),
41		typeof(*obj), uevent.uobject);
42	struct ib_pd *pd =
43		uverbs_attr_get_obj(attrs, UVERBS_ATTR_CREATE_SRQ_PD_HANDLE);
44	struct ib_srq_init_attr attr = {};
45	struct ib_uobject *xrcd_uobj;
46	struct ib_srq *srq;
47	u64 user_handle;
48	int ret;
49
50	ret = uverbs_copy_from(&attr.attr.max_sge, attrs,
51			       UVERBS_ATTR_CREATE_SRQ_MAX_SGE);
52	if (!ret)
53		ret = uverbs_copy_from(&attr.attr.max_wr, attrs,
54				       UVERBS_ATTR_CREATE_SRQ_MAX_WR);
55	if (!ret)
56		ret = uverbs_copy_from(&attr.attr.srq_limit, attrs,
57				       UVERBS_ATTR_CREATE_SRQ_LIMIT);
58	if (!ret)
59		ret = uverbs_copy_from(&user_handle, attrs,
60				       UVERBS_ATTR_CREATE_SRQ_USER_HANDLE);
61	if (!ret)
62		ret = uverbs_get_const(&attr.srq_type, attrs,
63				       UVERBS_ATTR_CREATE_SRQ_TYPE);
64	if (ret)
65		return ret;
66
67	if (ib_srq_has_cq(attr.srq_type)) {
68		attr.ext.cq = uverbs_attr_get_obj(attrs,
69					UVERBS_ATTR_CREATE_SRQ_CQ_HANDLE);
70		if (IS_ERR(attr.ext.cq))
71			return PTR_ERR(attr.ext.cq);
72	}
73
74	switch (attr.srq_type) {
75	case IB_UVERBS_SRQT_XRC:
76		xrcd_uobj = uverbs_attr_get_uobject(attrs,
77					UVERBS_ATTR_CREATE_SRQ_XRCD_HANDLE);
78		if (IS_ERR(xrcd_uobj))
79			return PTR_ERR(xrcd_uobj);
80
81		attr.ext.xrc.xrcd = (struct ib_xrcd *)xrcd_uobj->object;
82		if (!attr.ext.xrc.xrcd)
83			return -EINVAL;
84		obj->uxrcd = container_of(xrcd_uobj, struct ib_uxrcd_object,
85					  uobject);
86		atomic_inc(&obj->uxrcd->refcnt);
87		break;
88	case IB_UVERBS_SRQT_TM:
89		ret = uverbs_copy_from(&attr.ext.tag_matching.max_num_tags,
90				       attrs,
91				       UVERBS_ATTR_CREATE_SRQ_MAX_NUM_TAGS);
92		if (ret)
93			return ret;
94		break;
95	case IB_UVERBS_SRQT_BASIC:
96		break;
97	default:
98		return -EINVAL;
99	}
100
101	obj->uevent.event_file = ib_uverbs_get_async_event(attrs,
102					UVERBS_ATTR_CREATE_SRQ_EVENT_FD);
103	INIT_LIST_HEAD(&obj->uevent.event_list);
104	attr.event_handler = ib_uverbs_srq_event_handler;
105	obj->uevent.uobject.user_handle = user_handle;
106
107	srq = ib_create_srq_user(pd, &attr, obj, &attrs->driver_udata);
108	if (IS_ERR(srq)) {
109		ret = PTR_ERR(srq);
110		goto err;
111	}
112
113	obj->uevent.uobject.object = srq;
114	uverbs_finalize_uobj_create(attrs, UVERBS_ATTR_CREATE_SRQ_HANDLE);
115
116	ret = uverbs_copy_to(attrs, UVERBS_ATTR_CREATE_SRQ_RESP_MAX_WR,
117			     &attr.attr.max_wr,
118			     sizeof(attr.attr.max_wr));
119	if (ret)
120		return ret;
121
122	ret = uverbs_copy_to(attrs, UVERBS_ATTR_CREATE_SRQ_RESP_MAX_SGE,
123			     &attr.attr.max_sge,
124			     sizeof(attr.attr.max_sge));
125	if (ret)
126		return ret;
127
128	if (attr.srq_type == IB_SRQT_XRC) {
129		ret = uverbs_copy_to(attrs,
130				     UVERBS_ATTR_CREATE_SRQ_RESP_SRQ_NUM,
131				     &srq->ext.xrc.srq_num,
132				     sizeof(srq->ext.xrc.srq_num));
133		if (ret)
134			return ret;
135	}
136
137	return 0;
138err:
139	if (obj->uevent.event_file)
140		uverbs_uobject_put(&obj->uevent.event_file->uobj);
141	if (attr.srq_type == IB_SRQT_XRC)
142		atomic_dec(&obj->uxrcd->refcnt);
143	return ret;
144};
145
146DECLARE_UVERBS_NAMED_METHOD(
147	UVERBS_METHOD_SRQ_CREATE,
148	UVERBS_ATTR_IDR(UVERBS_ATTR_CREATE_SRQ_HANDLE,
149			UVERBS_OBJECT_SRQ,
150			UVERBS_ACCESS_NEW,
151			UA_MANDATORY),
152	UVERBS_ATTR_IDR(UVERBS_ATTR_CREATE_SRQ_PD_HANDLE,
153			UVERBS_OBJECT_PD,
154			UVERBS_ACCESS_READ,
155			UA_MANDATORY),
156	UVERBS_ATTR_CONST_IN(UVERBS_ATTR_CREATE_SRQ_TYPE,
157			     enum ib_uverbs_srq_type,
158			     UA_MANDATORY),
159	UVERBS_ATTR_PTR_IN(UVERBS_ATTR_CREATE_SRQ_USER_HANDLE,
160			   UVERBS_ATTR_TYPE(u64),
161			   UA_MANDATORY),
162	UVERBS_ATTR_PTR_IN(UVERBS_ATTR_CREATE_SRQ_MAX_WR,
163			   UVERBS_ATTR_TYPE(u32),
164			   UA_MANDATORY),
165	UVERBS_ATTR_PTR_IN(UVERBS_ATTR_CREATE_SRQ_MAX_SGE,
166			   UVERBS_ATTR_TYPE(u32),
167			   UA_MANDATORY),
168	UVERBS_ATTR_PTR_IN(UVERBS_ATTR_CREATE_SRQ_LIMIT,
169			   UVERBS_ATTR_TYPE(u32),
170			   UA_MANDATORY),
171	UVERBS_ATTR_IDR(UVERBS_ATTR_CREATE_SRQ_XRCD_HANDLE,
172			UVERBS_OBJECT_XRCD,
173			UVERBS_ACCESS_READ,
174			UA_OPTIONAL),
175	UVERBS_ATTR_IDR(UVERBS_ATTR_CREATE_SRQ_CQ_HANDLE,
176			UVERBS_OBJECT_CQ,
177			UVERBS_ACCESS_READ,
178			UA_OPTIONAL),
179	UVERBS_ATTR_PTR_IN(UVERBS_ATTR_CREATE_SRQ_MAX_NUM_TAGS,
180			   UVERBS_ATTR_TYPE(u32),
181			   UA_OPTIONAL),
182	UVERBS_ATTR_FD(UVERBS_ATTR_CREATE_SRQ_EVENT_FD,
183		       UVERBS_OBJECT_ASYNC_EVENT,
184		       UVERBS_ACCESS_READ,
185		       UA_OPTIONAL),
186	UVERBS_ATTR_PTR_OUT(UVERBS_ATTR_CREATE_SRQ_RESP_MAX_WR,
187			    UVERBS_ATTR_TYPE(u32),
188			    UA_MANDATORY),
189	UVERBS_ATTR_PTR_OUT(UVERBS_ATTR_CREATE_SRQ_RESP_MAX_SGE,
190			    UVERBS_ATTR_TYPE(u32),
191			    UA_MANDATORY),
192	UVERBS_ATTR_PTR_OUT(UVERBS_ATTR_CREATE_SRQ_RESP_SRQ_NUM,
193			   UVERBS_ATTR_TYPE(u32),
194			   UA_OPTIONAL),
195	UVERBS_ATTR_UHW());
196
197static int UVERBS_HANDLER(UVERBS_METHOD_SRQ_DESTROY)(
198	struct uverbs_attr_bundle *attrs)
199{
200	struct ib_uobject *uobj =
201		uverbs_attr_get_uobject(attrs, UVERBS_ATTR_DESTROY_SRQ_HANDLE);
202	struct ib_usrq_object *obj =
203		container_of(uobj, struct ib_usrq_object, uevent.uobject);
204	struct ib_uverbs_destroy_srq_resp resp = {
205		.events_reported = obj->uevent.events_reported
206	};
207
208	return uverbs_copy_to(attrs, UVERBS_ATTR_DESTROY_SRQ_RESP, &resp,
209			      sizeof(resp));
210}
211
212DECLARE_UVERBS_NAMED_METHOD(
213	UVERBS_METHOD_SRQ_DESTROY,
214	UVERBS_ATTR_IDR(UVERBS_ATTR_DESTROY_SRQ_HANDLE,
215			UVERBS_OBJECT_SRQ,
216			UVERBS_ACCESS_DESTROY,
217			UA_MANDATORY),
218	UVERBS_ATTR_PTR_OUT(UVERBS_ATTR_DESTROY_SRQ_RESP,
219			    UVERBS_ATTR_TYPE(struct ib_uverbs_destroy_srq_resp),
220			    UA_MANDATORY));
221
222DECLARE_UVERBS_NAMED_OBJECT(
223	UVERBS_OBJECT_SRQ,
224	UVERBS_TYPE_ALLOC_IDR_SZ(sizeof(struct ib_usrq_object),
225				 uverbs_free_srq),
226	&UVERBS_METHOD(UVERBS_METHOD_SRQ_CREATE),
227	&UVERBS_METHOD(UVERBS_METHOD_SRQ_DESTROY)
228);
229
230const struct uapi_definition uverbs_def_obj_srq[] = {
231	UAPI_DEF_CHAIN_OBJ_TREE_NAMED(UVERBS_OBJECT_SRQ,
232				      UAPI_DEF_OBJ_NEEDS_FN(destroy_srq)),
233	{}
234};
235