1/* 2 * Copyright (c) 2006, 2007, 2008, 2009 QLogic Corporation. All rights reserved. 3 * Copyright (c) 2005, 2006 PathScale, Inc. All rights reserved. 4 * 5 * This software is available to you under a choice of one of two 6 * licenses. You may choose to be licensed under the terms of the GNU 7 * General Public License (GPL) Version 2, available from the file 8 * COPYING in the main directory of this source tree, or the 9 * OpenIB.org BSD license below: 10 * 11 * Redistribution and use in source and binary forms, with or 12 * without modification, are permitted provided that the following 13 * conditions are met: 14 * 15 * - Redistributions of source code must retain the above 16 * copyright notice, this list of conditions and the following 17 * disclaimer. 18 * 19 * - Redistributions in binary form must reproduce the above 20 * copyright notice, this list of conditions and the following 21 * disclaimer in the documentation and/or other materials 22 * provided with the distribution. 23 * 24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 25 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 26 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 27 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 28 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 29 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 30 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 31 * SOFTWARE. 32 */ 33 34#include <linux/err.h> 35#include <linux/slab.h> 36#include <linux/vmalloc.h> 37 38#include "qib_verbs.h" 39 40/** 41 * qib_post_srq_receive - post a receive on a shared receive queue 42 * @ibsrq: the SRQ to post the receive on 43 * @wr: the list of work requests to post 44 * @bad_wr: A pointer to the first WR to cause a problem is put here 45 * 46 * This may be called from interrupt context. 47 */ 48int qib_post_srq_receive(struct ib_srq *ibsrq, struct ib_recv_wr *wr, 49 struct ib_recv_wr **bad_wr) 50{ 51 struct qib_srq *srq = to_isrq(ibsrq); 52 struct qib_rwq *wq; 53 unsigned long flags; 54 int ret; 55 56 for (; wr; wr = wr->next) { 57 struct qib_rwqe *wqe; 58 u32 next; 59 int i; 60 61 if ((unsigned) wr->num_sge > srq->rq.max_sge) { 62 *bad_wr = wr; 63 ret = -EINVAL; 64 goto bail; 65 } 66 67 spin_lock_irqsave(&srq->rq.lock, flags); 68 wq = srq->rq.wq; 69 next = wq->head + 1; 70 if (next >= srq->rq.size) 71 next = 0; 72 if (next == wq->tail) { 73 spin_unlock_irqrestore(&srq->rq.lock, flags); 74 *bad_wr = wr; 75 ret = -ENOMEM; 76 goto bail; 77 } 78 79 wqe = get_rwqe_ptr(&srq->rq, wq->head); 80 wqe->wr_id = wr->wr_id; 81 wqe->num_sge = wr->num_sge; 82 for (i = 0; i < wr->num_sge; i++) 83 wqe->sg_list[i] = wr->sg_list[i]; 84 /* Make sure queue entry is written before the head index. */ 85 smp_wmb(); 86 wq->head = next; 87 spin_unlock_irqrestore(&srq->rq.lock, flags); 88 } 89 ret = 0; 90 91bail: 92 return ret; 93} 94 95/** 96 * qib_create_srq - create a shared receive queue 97 * @ibpd: the protection domain of the SRQ to create 98 * @srq_init_attr: the attributes of the SRQ 99 * @udata: data from libibverbs when creating a user SRQ 100 */ 101struct ib_srq *qib_create_srq(struct ib_pd *ibpd, 102 struct ib_srq_init_attr *srq_init_attr, 103 struct ib_udata *udata) 104{ 105 struct qib_ibdev *dev = to_idev(ibpd->device); 106 struct qib_srq *srq; 107 u32 sz; 108 struct ib_srq *ret; 109 110 if (srq_init_attr->srq_type != IB_SRQT_BASIC) { 111 ret = ERR_PTR(-ENOSYS); 112 goto done; 113 } 114 115 if (srq_init_attr->attr.max_sge == 0 || 116 srq_init_attr->attr.max_sge > ib_qib_max_srq_sges || 117 srq_init_attr->attr.max_wr == 0 || 118 srq_init_attr->attr.max_wr > ib_qib_max_srq_wrs) { 119 ret = ERR_PTR(-EINVAL); 120 goto done; 121 } 122 123 srq = kmalloc(sizeof(*srq), GFP_KERNEL); 124 if (!srq) { 125 ret = ERR_PTR(-ENOMEM); 126 goto done; 127 } 128 129 /* 130 * Need to use vmalloc() if we want to support large #s of entries. 131 */ 132 srq->rq.size = srq_init_attr->attr.max_wr + 1; 133 srq->rq.max_sge = srq_init_attr->attr.max_sge; 134 sz = sizeof(struct ib_sge) * srq->rq.max_sge + 135 sizeof(struct qib_rwqe); 136 srq->rq.wq = vmalloc_user(sizeof(struct qib_rwq) + srq->rq.size * sz); 137 if (!srq->rq.wq) { 138 ret = ERR_PTR(-ENOMEM); 139 goto bail_srq; 140 } 141 142 /* 143 * Return the address of the RWQ as the offset to mmap. 144 * See qib_mmap() for details. 145 */ 146 if (udata && udata->outlen >= sizeof(__u64)) { 147 int err; 148 u32 s = sizeof(struct qib_rwq) + srq->rq.size * sz; 149 150 srq->ip = 151 qib_create_mmap_info(dev, s, ibpd->uobject->context, 152 srq->rq.wq); 153 if (!srq->ip) { 154 ret = ERR_PTR(-ENOMEM); 155 goto bail_wq; 156 } 157 158 err = ib_copy_to_udata(udata, &srq->ip->offset, 159 sizeof(srq->ip->offset)); 160 if (err) { 161 ret = ERR_PTR(err); 162 goto bail_ip; 163 } 164 } else 165 srq->ip = NULL; 166 167 /* 168 * ib_create_srq() will initialize srq->ibsrq. 169 */ 170 spin_lock_init(&srq->rq.lock); 171 srq->rq.wq->head = 0; 172 srq->rq.wq->tail = 0; 173 srq->limit = srq_init_attr->attr.srq_limit; 174 175 spin_lock(&dev->n_srqs_lock); 176 if (dev->n_srqs_allocated == ib_qib_max_srqs) { 177 spin_unlock(&dev->n_srqs_lock); 178 ret = ERR_PTR(-ENOMEM); 179 goto bail_ip; 180 } 181 182 dev->n_srqs_allocated++; 183 spin_unlock(&dev->n_srqs_lock); 184 185 if (srq->ip) { 186 spin_lock_irq(&dev->pending_lock); 187 list_add(&srq->ip->pending_mmaps, &dev->pending_mmaps); 188 spin_unlock_irq(&dev->pending_lock); 189 } 190 191 ret = &srq->ibsrq; 192 goto done; 193 194bail_ip: 195 kfree(srq->ip); 196bail_wq: 197 vfree(srq->rq.wq); 198bail_srq: 199 kfree(srq); 200done: 201 return ret; 202} 203 204/** 205 * qib_modify_srq - modify a shared receive queue 206 * @ibsrq: the SRQ to modify 207 * @attr: the new attributes of the SRQ 208 * @attr_mask: indicates which attributes to modify 209 * @udata: user data for libibverbs.so 210 */ 211int qib_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr, 212 enum ib_srq_attr_mask attr_mask, 213 struct ib_udata *udata) 214{ 215 struct qib_srq *srq = to_isrq(ibsrq); 216 struct qib_rwq *wq; 217 int ret = 0; 218 219 if (attr_mask & IB_SRQ_MAX_WR) { 220 struct qib_rwq *owq; 221 struct qib_rwqe *p; 222 u32 sz, size, n, head, tail; 223 224 /* Check that the requested sizes are below the limits. */ 225 if ((attr->max_wr > ib_qib_max_srq_wrs) || 226 ((attr_mask & IB_SRQ_LIMIT) ? 227 attr->srq_limit : srq->limit) > attr->max_wr) { 228 ret = -EINVAL; 229 goto bail; 230 } 231 232 sz = sizeof(struct qib_rwqe) + 233 srq->rq.max_sge * sizeof(struct ib_sge); 234 size = attr->max_wr + 1; 235 wq = vmalloc_user(sizeof(struct qib_rwq) + size * sz); 236 if (!wq) { 237 ret = -ENOMEM; 238 goto bail; 239 } 240 241 /* Check that we can write the offset to mmap. */ 242 if (udata && udata->inlen >= sizeof(__u64)) { 243 __u64 offset_addr; 244 __u64 offset = 0; 245 246 ret = ib_copy_from_udata(&offset_addr, udata, 247 sizeof(offset_addr)); 248 if (ret) 249 goto bail_free; 250 udata->outbuf = 251 (void __user *) (unsigned long) offset_addr; 252 ret = ib_copy_to_udata(udata, &offset, 253 sizeof(offset)); 254 if (ret) 255 goto bail_free; 256 } 257 258 spin_lock_irq(&srq->rq.lock); 259 /* 260 * validate head and tail pointer values and compute 261 * the number of remaining WQEs. 262 */ 263 owq = srq->rq.wq; 264 head = owq->head; 265 tail = owq->tail; 266 if (head >= srq->rq.size || tail >= srq->rq.size) { 267 ret = -EINVAL; 268 goto bail_unlock; 269 } 270 n = head; 271 if (n < tail) 272 n += srq->rq.size - tail; 273 else 274 n -= tail; 275 if (size <= n) { 276 ret = -EINVAL; 277 goto bail_unlock; 278 } 279 n = 0; 280 p = wq->wq; 281 while (tail != head) { 282 struct qib_rwqe *wqe; 283 int i; 284 285 wqe = get_rwqe_ptr(&srq->rq, tail); 286 p->wr_id = wqe->wr_id; 287 p->num_sge = wqe->num_sge; 288 for (i = 0; i < wqe->num_sge; i++) 289 p->sg_list[i] = wqe->sg_list[i]; 290 n++; 291 p = (struct qib_rwqe *)((char *) p + sz); 292 if (++tail >= srq->rq.size) 293 tail = 0; 294 } 295 srq->rq.wq = wq; 296 srq->rq.size = size; 297 wq->head = n; 298 wq->tail = 0; 299 if (attr_mask & IB_SRQ_LIMIT) 300 srq->limit = attr->srq_limit; 301 spin_unlock_irq(&srq->rq.lock); 302 303 vfree(owq); 304 305 if (srq->ip) { 306 struct qib_mmap_info *ip = srq->ip; 307 struct qib_ibdev *dev = to_idev(srq->ibsrq.device); 308 u32 s = sizeof(struct qib_rwq) + size * sz; 309 310 qib_update_mmap_info(dev, ip, s, wq); 311 312 /* 313 * Return the offset to mmap. 314 * See qib_mmap() for details. 315 */ 316 if (udata && udata->inlen >= sizeof(__u64)) { 317 ret = ib_copy_to_udata(udata, &ip->offset, 318 sizeof(ip->offset)); 319 if (ret) 320 goto bail; 321 } 322 323 /* 324 * Put user mapping info onto the pending list 325 * unless it already is on the list. 326 */ 327 spin_lock_irq(&dev->pending_lock); 328 if (list_empty(&ip->pending_mmaps)) 329 list_add(&ip->pending_mmaps, 330 &dev->pending_mmaps); 331 spin_unlock_irq(&dev->pending_lock); 332 } 333 } else if (attr_mask & IB_SRQ_LIMIT) { 334 spin_lock_irq(&srq->rq.lock); 335 if (attr->srq_limit >= srq->rq.size) 336 ret = -EINVAL; 337 else 338 srq->limit = attr->srq_limit; 339 spin_unlock_irq(&srq->rq.lock); 340 } 341 goto bail; 342 343bail_unlock: 344 spin_unlock_irq(&srq->rq.lock); 345bail_free: 346 vfree(wq); 347bail: 348 return ret; 349} 350 351int qib_query_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr) 352{ 353 struct qib_srq *srq = to_isrq(ibsrq); 354 355 attr->max_wr = srq->rq.size - 1; 356 attr->max_sge = srq->rq.max_sge; 357 attr->srq_limit = srq->limit; 358 return 0; 359} 360 361/** 362 * qib_destroy_srq - destroy a shared receive queue 363 * @ibsrq: the SRQ to destroy 364 */ 365int qib_destroy_srq(struct ib_srq *ibsrq) 366{ 367 struct qib_srq *srq = to_isrq(ibsrq); 368 struct qib_ibdev *dev = to_idev(ibsrq->device); 369 370 spin_lock(&dev->n_srqs_lock); 371 dev->n_srqs_allocated--; 372 spin_unlock(&dev->n_srqs_lock); 373 if (srq->ip) 374 kref_put(&srq->ip->ref, qib_release_mmap_info); 375 else 376 vfree(srq->rq.wq); 377 kfree(srq); 378 379 return 0; 380} 381