2 * Copyright(c) 2016 Intel Corporation.
4 * This file is provided under a dual BSD/GPLv2 license. When using or
5 * redistributing this file, you may do so under either license.
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of version 2 of the GNU General Public License as
11 * published by the Free Software Foundation.
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
20 * Redistribution and use in source and binary forms, with or without
21 * modification, are permitted provided that the following conditions
24 * - Redistributions of source code must retain the above copyright
25 * notice, this list of conditions and the following disclaimer.
26 * - Redistributions in binary form must reproduce the above copyright
27 * notice, this list of conditions and the following disclaimer in
28 * the documentation and/or other materials provided with the
30 * - Neither the name of Intel Corporation nor the names of its
31 * contributors may be used to endorse or promote products derived
32 * from this software without specific prior written permission.
34 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
35 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
36 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
37 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
38 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
39 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
40 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
41 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
42 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
43 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
44 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
48 #include <linux/err.h>
49 #include <linux/slab.h>
50 #include <linux/vmalloc.h>
56 * rvt_driver_srq_init - init srq resources on a per driver basis
57 * @rdi: rvt dev structure
59 * Do any initialization needed when a driver registers with rdmavt.
61 void rvt_driver_srq_init(struct rvt_dev_info
*rdi
)
63 spin_lock_init(&rdi
->n_srqs_lock
);
64 rdi
->n_srqs_allocated
= 0;
68 * rvt_create_srq - create a shared receive queue
69 * @ibpd: the protection domain of the SRQ to create
70 * @srq_init_attr: the attributes of the SRQ
71 * @udata: data from libibverbs when creating a user SRQ
73 * Return: Allocated srq object
75 struct ib_srq
*rvt_create_srq(struct ib_pd
*ibpd
,
76 struct ib_srq_init_attr
*srq_init_attr
,
77 struct ib_udata
*udata
)
79 struct rvt_dev_info
*dev
= ib_to_rvt(ibpd
->device
);
84 if (srq_init_attr
->srq_type
!= IB_SRQT_BASIC
)
85 return ERR_PTR(-ENOSYS
);
87 if (srq_init_attr
->attr
.max_sge
== 0 ||
88 srq_init_attr
->attr
.max_sge
> dev
->dparms
.props
.max_srq_sge
||
89 srq_init_attr
->attr
.max_wr
== 0 ||
90 srq_init_attr
->attr
.max_wr
> dev
->dparms
.props
.max_srq_wr
)
91 return ERR_PTR(-EINVAL
);
93 srq
= kmalloc(sizeof(*srq
), GFP_KERNEL
);
95 return ERR_PTR(-ENOMEM
);
98 * Need to use vmalloc() if we want to support large #s of entries.
100 srq
->rq
.size
= srq_init_attr
->attr
.max_wr
+ 1;
101 srq
->rq
.max_sge
= srq_init_attr
->attr
.max_sge
;
102 sz
= sizeof(struct ib_sge
) * srq
->rq
.max_sge
+
103 sizeof(struct rvt_rwqe
);
104 srq
->rq
.wq
= vmalloc_user(sizeof(struct rvt_rwq
) + srq
->rq
.size
* sz
);
106 ret
= ERR_PTR(-ENOMEM
);
111 * Return the address of the RWQ as the offset to mmap.
112 * See rvt_mmap() for details.
114 if (udata
&& udata
->outlen
>= sizeof(__u64
)) {
116 u32 s
= sizeof(struct rvt_rwq
) + srq
->rq
.size
* sz
;
119 rvt_create_mmap_info(dev
, s
, ibpd
->uobject
->context
,
122 ret
= ERR_PTR(-ENOMEM
);
126 err
= ib_copy_to_udata(udata
, &srq
->ip
->offset
,
127 sizeof(srq
->ip
->offset
));
137 * ib_create_srq() will initialize srq->ibsrq.
139 spin_lock_init(&srq
->rq
.lock
);
140 srq
->rq
.wq
->head
= 0;
141 srq
->rq
.wq
->tail
= 0;
142 srq
->limit
= srq_init_attr
->attr
.srq_limit
;
144 spin_lock(&dev
->n_srqs_lock
);
145 if (dev
->n_srqs_allocated
== dev
->dparms
.props
.max_srq
) {
146 spin_unlock(&dev
->n_srqs_lock
);
147 ret
= ERR_PTR(-ENOMEM
);
151 dev
->n_srqs_allocated
++;
152 spin_unlock(&dev
->n_srqs_lock
);
155 spin_lock_irq(&dev
->pending_lock
);
156 list_add(&srq
->ip
->pending_mmaps
, &dev
->pending_mmaps
);
157 spin_unlock_irq(&dev
->pending_lock
);
172 * rvt_modify_srq - modify a shared receive queue
173 * @ibsrq: the SRQ to modify
174 * @attr: the new attributes of the SRQ
175 * @attr_mask: indicates which attributes to modify
176 * @udata: user data for libibverbs.so
178 * Return: 0 on success
180 int rvt_modify_srq(struct ib_srq
*ibsrq
, struct ib_srq_attr
*attr
,
181 enum ib_srq_attr_mask attr_mask
,
182 struct ib_udata
*udata
)
184 struct rvt_srq
*srq
= ibsrq_to_rvtsrq(ibsrq
);
185 struct rvt_dev_info
*dev
= ib_to_rvt(ibsrq
->device
);
189 if (attr_mask
& IB_SRQ_MAX_WR
) {
192 u32 sz
, size
, n
, head
, tail
;
194 /* Check that the requested sizes are below the limits. */
195 if ((attr
->max_wr
> dev
->dparms
.props
.max_srq_wr
) ||
196 ((attr_mask
& IB_SRQ_LIMIT
) ?
197 attr
->srq_limit
: srq
->limit
) > attr
->max_wr
)
200 sz
= sizeof(struct rvt_rwqe
) +
201 srq
->rq
.max_sge
* sizeof(struct ib_sge
);
202 size
= attr
->max_wr
+ 1;
203 wq
= vmalloc_user(sizeof(struct rvt_rwq
) + size
* sz
);
207 /* Check that we can write the offset to mmap. */
208 if (udata
&& udata
->inlen
>= sizeof(__u64
)) {
212 ret
= ib_copy_from_udata(&offset_addr
, udata
,
213 sizeof(offset_addr
));
216 udata
->outbuf
= (void __user
*)
217 (unsigned long)offset_addr
;
218 ret
= ib_copy_to_udata(udata
, &offset
,
224 spin_lock_irq(&srq
->rq
.lock
);
226 * validate head and tail pointer values and compute
227 * the number of remaining WQEs.
232 if (head
>= srq
->rq
.size
|| tail
>= srq
->rq
.size
) {
238 n
+= srq
->rq
.size
- tail
;
247 while (tail
!= head
) {
248 struct rvt_rwqe
*wqe
;
251 wqe
= rvt_get_rwqe_ptr(&srq
->rq
, tail
);
252 p
->wr_id
= wqe
->wr_id
;
253 p
->num_sge
= wqe
->num_sge
;
254 for (i
= 0; i
< wqe
->num_sge
; i
++)
255 p
->sg_list
[i
] = wqe
->sg_list
[i
];
257 p
= (struct rvt_rwqe
*)((char *)p
+ sz
);
258 if (++tail
>= srq
->rq
.size
)
265 if (attr_mask
& IB_SRQ_LIMIT
)
266 srq
->limit
= attr
->srq_limit
;
267 spin_unlock_irq(&srq
->rq
.lock
);
272 struct rvt_mmap_info
*ip
= srq
->ip
;
273 struct rvt_dev_info
*dev
= ib_to_rvt(srq
->ibsrq
.device
);
274 u32 s
= sizeof(struct rvt_rwq
) + size
* sz
;
276 rvt_update_mmap_info(dev
, ip
, s
, wq
);
279 * Return the offset to mmap.
280 * See rvt_mmap() for details.
282 if (udata
&& udata
->inlen
>= sizeof(__u64
)) {
283 ret
= ib_copy_to_udata(udata
, &ip
->offset
,
290 * Put user mapping info onto the pending list
291 * unless it already is on the list.
293 spin_lock_irq(&dev
->pending_lock
);
294 if (list_empty(&ip
->pending_mmaps
))
295 list_add(&ip
->pending_mmaps
,
296 &dev
->pending_mmaps
);
297 spin_unlock_irq(&dev
->pending_lock
);
299 } else if (attr_mask
& IB_SRQ_LIMIT
) {
300 spin_lock_irq(&srq
->rq
.lock
);
301 if (attr
->srq_limit
>= srq
->rq
.size
)
304 srq
->limit
= attr
->srq_limit
;
305 spin_unlock_irq(&srq
->rq
.lock
);
310 spin_unlock_irq(&srq
->rq
.lock
);
316 /** rvt_query_srq - query srq data
317 * @ibsrq: srq to query
318 * @attr: return info in attr
322 int rvt_query_srq(struct ib_srq
*ibsrq
, struct ib_srq_attr
*attr
)
324 struct rvt_srq
*srq
= ibsrq_to_rvtsrq(ibsrq
);
326 attr
->max_wr
= srq
->rq
.size
- 1;
327 attr
->max_sge
= srq
->rq
.max_sge
;
328 attr
->srq_limit
= srq
->limit
;
333 * rvt_destroy_srq - destory an srq
334 * @ibsrq: srq object to destroy
338 int rvt_destroy_srq(struct ib_srq
*ibsrq
)
340 struct rvt_srq
*srq
= ibsrq_to_rvtsrq(ibsrq
);
341 struct rvt_dev_info
*dev
= ib_to_rvt(ibsrq
->device
);
343 spin_lock(&dev
->n_srqs_lock
);
344 dev
->n_srqs_allocated
--;
345 spin_unlock(&dev
->n_srqs_lock
);
347 kref_put(&srq
->ip
->ref
, rvt_release_mmap_info
);