1 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB 2 /* 3 * Copyright (c) 2016 Mellanox Technologies Ltd. All rights reserved. 4 * Copyright (c) 2015 System Fabric Works, Inc. All rights reserved. 5 */ 6 7 #include <linux/vmalloc.h> 8 #include "rxe.h" 9 #include "rxe_queue.h" 10 11 int rxe_srq_chk_init(struct rxe_dev *rxe, struct ib_srq_init_attr *init) 12 { 13 struct ib_srq_attr *attr = &init->attr; 14 15 if (attr->max_wr > rxe->attr.max_srq_wr) { 16 rxe_dbg_dev(rxe, "max_wr(%d) > max_srq_wr(%d)\n", 17 attr->max_wr, rxe->attr.max_srq_wr); 18 goto err1; 19 } 20 21 if (attr->max_wr <= 0) { 22 rxe_dbg_dev(rxe, "max_wr(%d) <= 0\n", attr->max_wr); 23 goto err1; 24 } 25 26 if (attr->max_wr < RXE_MIN_SRQ_WR) 27 attr->max_wr = RXE_MIN_SRQ_WR; 28 29 if (attr->max_sge > rxe->attr.max_srq_sge) { 30 rxe_dbg_dev(rxe, "max_sge(%d) > max_srq_sge(%d)\n", 31 attr->max_sge, rxe->attr.max_srq_sge); 32 goto err1; 33 } 34 35 if (attr->max_sge < RXE_MIN_SRQ_SGE) 36 attr->max_sge = RXE_MIN_SRQ_SGE; 37 38 return 0; 39 40 err1: 41 return -EINVAL; 42 } 43 44 int rxe_srq_from_init(struct rxe_dev *rxe, struct rxe_srq *srq, 45 struct ib_srq_init_attr *init, struct ib_udata *udata, 46 struct rxe_create_srq_resp __user *uresp) 47 { 48 struct rxe_queue *q; 49 int wqe_size; 50 int err; 51 52 srq->ibsrq.event_handler = init->event_handler; 53 srq->ibsrq.srq_context = init->srq_context; 54 srq->limit = init->attr.srq_limit; 55 srq->srq_num = srq->elem.index; 56 srq->rq.max_wr = init->attr.max_wr; 57 srq->rq.max_sge = init->attr.max_sge; 58 59 wqe_size = sizeof(struct rxe_recv_wqe) + 60 srq->rq.max_sge*sizeof(struct ib_sge); 61 62 spin_lock_init(&srq->rq.producer_lock); 63 spin_lock_init(&srq->rq.consumer_lock); 64 65 q = rxe_queue_init(rxe, &srq->rq.max_wr, wqe_size, 66 QUEUE_TYPE_FROM_CLIENT); 67 if (!q) { 68 rxe_dbg_srq(srq, "Unable to allocate queue\n"); 69 err = -ENOMEM; 70 goto err_out; 71 } 72 73 err = do_mmap_info(rxe, uresp ? &uresp->mi : NULL, udata, q->buf, 74 q->buf_size, &q->ip); 75 if (err) { 76 rxe_dbg_srq(srq, "Unable to init mmap info for caller\n"); 77 goto err_free; 78 } 79 80 srq->rq.queue = q; 81 init->attr.max_wr = srq->rq.max_wr; 82 83 if (uresp) { 84 if (copy_to_user(&uresp->srq_num, &srq->srq_num, 85 sizeof(uresp->srq_num))) { 86 rxe_queue_cleanup(q); 87 return -EFAULT; 88 } 89 } 90 91 return 0; 92 93 err_free: 94 vfree(q->buf); 95 kfree(q); 96 err_out: 97 return err; 98 } 99 100 int rxe_srq_chk_attr(struct rxe_dev *rxe, struct rxe_srq *srq, 101 struct ib_srq_attr *attr, enum ib_srq_attr_mask mask) 102 { 103 if (srq->error) { 104 rxe_dbg_srq(srq, "in error state\n"); 105 goto err1; 106 } 107 108 if (mask & IB_SRQ_MAX_WR) { 109 if (attr->max_wr > rxe->attr.max_srq_wr) { 110 rxe_dbg_srq(srq, "max_wr(%d) > max_srq_wr(%d)\n", 111 attr->max_wr, rxe->attr.max_srq_wr); 112 goto err1; 113 } 114 115 if (attr->max_wr <= 0) { 116 rxe_dbg_srq(srq, "max_wr(%d) <= 0\n", attr->max_wr); 117 goto err1; 118 } 119 120 if (srq->limit && (attr->max_wr < srq->limit)) { 121 rxe_dbg_srq(srq, "max_wr (%d) < srq->limit (%d)\n", 122 attr->max_wr, srq->limit); 123 goto err1; 124 } 125 126 if (attr->max_wr < RXE_MIN_SRQ_WR) 127 attr->max_wr = RXE_MIN_SRQ_WR; 128 } 129 130 if (mask & IB_SRQ_LIMIT) { 131 if (attr->srq_limit > rxe->attr.max_srq_wr) { 132 rxe_dbg_srq(srq, "srq_limit(%d) > max_srq_wr(%d)\n", 133 attr->srq_limit, rxe->attr.max_srq_wr); 134 goto err1; 135 } 136 137 if (attr->srq_limit > srq->rq.queue->buf->index_mask) { 138 rxe_dbg_srq(srq, "srq_limit (%d) > cur limit(%d)\n", 139 attr->srq_limit, 140 srq->rq.queue->buf->index_mask); 141 goto err1; 142 } 143 } 144 145 return 0; 146 147 err1: 148 return -EINVAL; 149 } 150 151 int rxe_srq_from_attr(struct rxe_dev *rxe, struct rxe_srq *srq, 152 struct ib_srq_attr *attr, enum ib_srq_attr_mask mask, 153 struct rxe_modify_srq_cmd *ucmd, struct ib_udata *udata) 154 { 155 struct rxe_queue *q = srq->rq.queue; 156 struct mminfo __user *mi = NULL; 157 int wqe_size; 158 int err; 159 160 if (mask & IB_SRQ_MAX_WR) { 161 /* 162 * This is completely screwed up, the response is supposed to 163 * be in the outbuf not like this. 164 */ 165 mi = u64_to_user_ptr(ucmd->mmap_info_addr); 166 167 wqe_size = sizeof(struct rxe_recv_wqe) + 168 srq->rq.max_sge*sizeof(struct ib_sge); 169 170 err = rxe_queue_resize(q, &attr->max_wr, wqe_size, 171 udata, mi, &srq->rq.producer_lock, 172 &srq->rq.consumer_lock); 173 if (err) 174 goto err_free; 175 176 srq->rq.max_wr = attr->max_wr; 177 } 178 179 if (mask & IB_SRQ_LIMIT) 180 srq->limit = attr->srq_limit; 181 182 return 0; 183 184 err_free: 185 rxe_queue_cleanup(q); 186 srq->rq.queue = NULL; 187 return err; 188 } 189 190 void rxe_srq_cleanup(struct rxe_pool_elem *elem) 191 { 192 struct rxe_srq *srq = container_of(elem, typeof(*srq), elem); 193 194 if (srq->pd) 195 rxe_put(srq->pd); 196 197 if (srq->rq.queue) 198 rxe_queue_cleanup(srq->rq.queue); 199 } 200