diff options
Diffstat (limited to 'drivers/infiniband/hw/ipath/ipath_srq.c')
-rw-r--r-- | drivers/infiniband/hw/ipath/ipath_srq.c | 244 |
1 files changed, 153 insertions, 91 deletions
diff --git a/drivers/infiniband/hw/ipath/ipath_srq.c b/drivers/infiniband/hw/ipath/ipath_srq.c index f760434660bd..941e866d9517 100644 --- a/drivers/infiniband/hw/ipath/ipath_srq.c +++ b/drivers/infiniband/hw/ipath/ipath_srq.c | |||
@@ -48,66 +48,39 @@ int ipath_post_srq_receive(struct ib_srq *ibsrq, struct ib_recv_wr *wr, | |||
48 | struct ib_recv_wr **bad_wr) | 48 | struct ib_recv_wr **bad_wr) |
49 | { | 49 | { |
50 | struct ipath_srq *srq = to_isrq(ibsrq); | 50 | struct ipath_srq *srq = to_isrq(ibsrq); |
51 | struct ipath_ibdev *dev = to_idev(ibsrq->device); | 51 | struct ipath_rwq *wq; |
52 | unsigned long flags; | 52 | unsigned long flags; |
53 | int ret; | 53 | int ret; |
54 | 54 | ||
55 | for (; wr; wr = wr->next) { | 55 | for (; wr; wr = wr->next) { |
56 | struct ipath_rwqe *wqe; | 56 | struct ipath_rwqe *wqe; |
57 | u32 next; | 57 | u32 next; |
58 | int i, j; | 58 | int i; |
59 | 59 | ||
60 | if (wr->num_sge > srq->rq.max_sge) { | 60 | if ((unsigned) wr->num_sge > srq->rq.max_sge) { |
61 | *bad_wr = wr; | 61 | *bad_wr = wr; |
62 | ret = -ENOMEM; | 62 | ret = -ENOMEM; |
63 | goto bail; | 63 | goto bail; |
64 | } | 64 | } |
65 | 65 | ||
66 | spin_lock_irqsave(&srq->rq.lock, flags); | 66 | spin_lock_irqsave(&srq->rq.lock, flags); |
67 | next = srq->rq.head + 1; | 67 | wq = srq->rq.wq; |
68 | next = wq->head + 1; | ||
68 | if (next >= srq->rq.size) | 69 | if (next >= srq->rq.size) |
69 | next = 0; | 70 | next = 0; |
70 | if (next == srq->rq.tail) { | 71 | if (next == wq->tail) { |
71 | spin_unlock_irqrestore(&srq->rq.lock, flags); | 72 | spin_unlock_irqrestore(&srq->rq.lock, flags); |
72 | *bad_wr = wr; | 73 | *bad_wr = wr; |
73 | ret = -ENOMEM; | 74 | ret = -ENOMEM; |
74 | goto bail; | 75 | goto bail; |
75 | } | 76 | } |
76 | 77 | ||
77 | wqe = get_rwqe_ptr(&srq->rq, srq->rq.head); | 78 | wqe = get_rwqe_ptr(&srq->rq, wq->head); |
78 | wqe->wr_id = wr->wr_id; | 79 | wqe->wr_id = wr->wr_id; |
79 | wqe->sg_list[0].mr = NULL; | 80 | wqe->num_sge = wr->num_sge; |
80 | wqe->sg_list[0].vaddr = NULL; | 81 | for (i = 0; i < wr->num_sge; i++) |
81 | wqe->sg_list[0].length = 0; | 82 | wqe->sg_list[i] = wr->sg_list[i]; |
82 | wqe->sg_list[0].sge_length = 0; | 83 | wq->head = next; |
83 | wqe->length = 0; | ||
84 | for (i = 0, j = 0; i < wr->num_sge; i++) { | ||
85 | /* Check LKEY */ | ||
86 | if (to_ipd(srq->ibsrq.pd)->user && | ||
87 | wr->sg_list[i].lkey == 0) { | ||
88 | spin_unlock_irqrestore(&srq->rq.lock, | ||
89 | flags); | ||
90 | *bad_wr = wr; | ||
91 | ret = -EINVAL; | ||
92 | goto bail; | ||
93 | } | ||
94 | if (wr->sg_list[i].length == 0) | ||
95 | continue; | ||
96 | if (!ipath_lkey_ok(&dev->lk_table, | ||
97 | &wqe->sg_list[j], | ||
98 | &wr->sg_list[i], | ||
99 | IB_ACCESS_LOCAL_WRITE)) { | ||
100 | spin_unlock_irqrestore(&srq->rq.lock, | ||
101 | flags); | ||
102 | *bad_wr = wr; | ||
103 | ret = -EINVAL; | ||
104 | goto bail; | ||
105 | } | ||
106 | wqe->length += wr->sg_list[i].length; | ||
107 | j++; | ||
108 | } | ||
109 | wqe->num_sge = j; | ||
110 | srq->rq.head = next; | ||
111 | spin_unlock_irqrestore(&srq->rq.lock, flags); | 84 | spin_unlock_irqrestore(&srq->rq.lock, flags); |
112 | } | 85 | } |
113 | ret = 0; | 86 | ret = 0; |
@@ -133,53 +106,95 @@ struct ib_srq *ipath_create_srq(struct ib_pd *ibpd, | |||
133 | 106 | ||
134 | if (dev->n_srqs_allocated == ib_ipath_max_srqs) { | 107 | if (dev->n_srqs_allocated == ib_ipath_max_srqs) { |
135 | ret = ERR_PTR(-ENOMEM); | 108 | ret = ERR_PTR(-ENOMEM); |
136 | goto bail; | 109 | goto done; |
137 | } | 110 | } |
138 | 111 | ||
139 | if (srq_init_attr->attr.max_wr == 0) { | 112 | if (srq_init_attr->attr.max_wr == 0) { |
140 | ret = ERR_PTR(-EINVAL); | 113 | ret = ERR_PTR(-EINVAL); |
141 | goto bail; | 114 | goto done; |
142 | } | 115 | } |
143 | 116 | ||
144 | if ((srq_init_attr->attr.max_sge > ib_ipath_max_srq_sges) || | 117 | if ((srq_init_attr->attr.max_sge > ib_ipath_max_srq_sges) || |
145 | (srq_init_attr->attr.max_wr > ib_ipath_max_srq_wrs)) { | 118 | (srq_init_attr->attr.max_wr > ib_ipath_max_srq_wrs)) { |
146 | ret = ERR_PTR(-EINVAL); | 119 | ret = ERR_PTR(-EINVAL); |
147 | goto bail; | 120 | goto done; |
148 | } | 121 | } |
149 | 122 | ||
150 | srq = kmalloc(sizeof(*srq), GFP_KERNEL); | 123 | srq = kmalloc(sizeof(*srq), GFP_KERNEL); |
151 | if (!srq) { | 124 | if (!srq) { |
152 | ret = ERR_PTR(-ENOMEM); | 125 | ret = ERR_PTR(-ENOMEM); |
153 | goto bail; | 126 | goto done; |
154 | } | 127 | } |
155 | 128 | ||
156 | /* | 129 | /* |
157 | * Need to use vmalloc() if we want to support large #s of entries. | 130 | * Need to use vmalloc() if we want to support large #s of entries. |
158 | */ | 131 | */ |
159 | srq->rq.size = srq_init_attr->attr.max_wr + 1; | 132 | srq->rq.size = srq_init_attr->attr.max_wr + 1; |
160 | sz = sizeof(struct ipath_sge) * srq_init_attr->attr.max_sge + | 133 | srq->rq.max_sge = srq_init_attr->attr.max_sge; |
134 | sz = sizeof(struct ib_sge) * srq->rq.max_sge + | ||
161 | sizeof(struct ipath_rwqe); | 135 | sizeof(struct ipath_rwqe); |
162 | srq->rq.wq = vmalloc(srq->rq.size * sz); | 136 | srq->rq.wq = vmalloc_user(sizeof(struct ipath_rwq) + srq->rq.size * sz); |
163 | if (!srq->rq.wq) { | 137 | if (!srq->rq.wq) { |
164 | kfree(srq); | ||
165 | ret = ERR_PTR(-ENOMEM); | 138 | ret = ERR_PTR(-ENOMEM); |
166 | goto bail; | 139 | goto bail_srq; |
167 | } | 140 | } |
168 | 141 | ||
169 | /* | 142 | /* |
143 | * Return the address of the RWQ as the offset to mmap. | ||
144 | * See ipath_mmap() for details. | ||
145 | */ | ||
146 | if (udata && udata->outlen >= sizeof(__u64)) { | ||
147 | struct ipath_mmap_info *ip; | ||
148 | __u64 offset = (__u64) srq->rq.wq; | ||
149 | int err; | ||
150 | |||
151 | err = ib_copy_to_udata(udata, &offset, sizeof(offset)); | ||
152 | if (err) { | ||
153 | ret = ERR_PTR(err); | ||
154 | goto bail_wq; | ||
155 | } | ||
156 | |||
157 | /* Allocate info for ipath_mmap(). */ | ||
158 | ip = kmalloc(sizeof(*ip), GFP_KERNEL); | ||
159 | if (!ip) { | ||
160 | ret = ERR_PTR(-ENOMEM); | ||
161 | goto bail_wq; | ||
162 | } | ||
163 | srq->ip = ip; | ||
164 | ip->context = ibpd->uobject->context; | ||
165 | ip->obj = srq->rq.wq; | ||
166 | kref_init(&ip->ref); | ||
167 | ip->mmap_cnt = 0; | ||
168 | ip->size = PAGE_ALIGN(sizeof(struct ipath_rwq) + | ||
169 | srq->rq.size * sz); | ||
170 | spin_lock_irq(&dev->pending_lock); | ||
171 | ip->next = dev->pending_mmaps; | ||
172 | dev->pending_mmaps = ip; | ||
173 | spin_unlock_irq(&dev->pending_lock); | ||
174 | } else | ||
175 | srq->ip = NULL; | ||
176 | |||
177 | /* | ||
170 | * ib_create_srq() will initialize srq->ibsrq. | 178 | * ib_create_srq() will initialize srq->ibsrq. |
171 | */ | 179 | */ |
172 | spin_lock_init(&srq->rq.lock); | 180 | spin_lock_init(&srq->rq.lock); |
173 | srq->rq.head = 0; | 181 | srq->rq.wq->head = 0; |
174 | srq->rq.tail = 0; | 182 | srq->rq.wq->tail = 0; |
175 | srq->rq.max_sge = srq_init_attr->attr.max_sge; | 183 | srq->rq.max_sge = srq_init_attr->attr.max_sge; |
176 | srq->limit = srq_init_attr->attr.srq_limit; | 184 | srq->limit = srq_init_attr->attr.srq_limit; |
177 | 185 | ||
186 | dev->n_srqs_allocated++; | ||
187 | |||
178 | ret = &srq->ibsrq; | 188 | ret = &srq->ibsrq; |
189 | goto done; | ||
179 | 190 | ||
180 | dev->n_srqs_allocated++; | 191 | bail_wq: |
192 | vfree(srq->rq.wq); | ||
181 | 193 | ||
182 | bail: | 194 | bail_srq: |
195 | kfree(srq); | ||
196 | |||
197 | done: | ||
183 | return ret; | 198 | return ret; |
184 | } | 199 | } |
185 | 200 | ||
@@ -188,83 +203,130 @@ bail: | |||
188 | * @ibsrq: the SRQ to modify | 203 | * @ibsrq: the SRQ to modify |
189 | * @attr: the new attributes of the SRQ | 204 | * @attr: the new attributes of the SRQ |
190 | * @attr_mask: indicates which attributes to modify | 205 | * @attr_mask: indicates which attributes to modify |
206 | * @udata: user data for ipathverbs.so | ||
191 | */ | 207 | */ |
192 | int ipath_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr, | 208 | int ipath_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr, |
193 | enum ib_srq_attr_mask attr_mask) | 209 | enum ib_srq_attr_mask attr_mask, |
210 | struct ib_udata *udata) | ||
194 | { | 211 | { |
195 | struct ipath_srq *srq = to_isrq(ibsrq); | 212 | struct ipath_srq *srq = to_isrq(ibsrq); |
196 | unsigned long flags; | 213 | int ret = 0; |
197 | int ret; | ||
198 | 214 | ||
199 | if (attr_mask & IB_SRQ_MAX_WR) | 215 | if (attr_mask & IB_SRQ_MAX_WR) { |
200 | if ((attr->max_wr > ib_ipath_max_srq_wrs) || | 216 | struct ipath_rwq *owq; |
201 | (attr->max_sge > srq->rq.max_sge)) { | 217 | struct ipath_rwq *wq; |
202 | ret = -EINVAL; | 218 | struct ipath_rwqe *p; |
203 | goto bail; | 219 | u32 sz, size, n, head, tail; |
204 | } | ||
205 | 220 | ||
206 | if (attr_mask & IB_SRQ_LIMIT) | 221 | /* Check that the requested sizes are below the limits. */ |
207 | if (attr->srq_limit >= srq->rq.size) { | 222 | if ((attr->max_wr > ib_ipath_max_srq_wrs) || |
223 | ((attr_mask & IB_SRQ_LIMIT) ? | ||
224 | attr->srq_limit : srq->limit) > attr->max_wr) { | ||
208 | ret = -EINVAL; | 225 | ret = -EINVAL; |
209 | goto bail; | 226 | goto bail; |
210 | } | 227 | } |
211 | 228 | ||
212 | if (attr_mask & IB_SRQ_MAX_WR) { | ||
213 | struct ipath_rwqe *wq, *p; | ||
214 | u32 sz, size, n; | ||
215 | |||
216 | sz = sizeof(struct ipath_rwqe) + | 229 | sz = sizeof(struct ipath_rwqe) + |
217 | attr->max_sge * sizeof(struct ipath_sge); | 230 | srq->rq.max_sge * sizeof(struct ib_sge); |
218 | size = attr->max_wr + 1; | 231 | size = attr->max_wr + 1; |
219 | wq = vmalloc(size * sz); | 232 | wq = vmalloc_user(sizeof(struct ipath_rwq) + size * sz); |
220 | if (!wq) { | 233 | if (!wq) { |
221 | ret = -ENOMEM; | 234 | ret = -ENOMEM; |
222 | goto bail; | 235 | goto bail; |
223 | } | 236 | } |
224 | 237 | ||
225 | spin_lock_irqsave(&srq->rq.lock, flags); | 238 | /* |
226 | if (srq->rq.head < srq->rq.tail) | 239 | * Return the address of the RWQ as the offset to mmap. |
227 | n = srq->rq.size + srq->rq.head - srq->rq.tail; | 240 | * See ipath_mmap() for details. |
241 | */ | ||
242 | if (udata && udata->inlen >= sizeof(__u64)) { | ||
243 | __u64 offset_addr; | ||
244 | __u64 offset = (__u64) wq; | ||
245 | |||
246 | ret = ib_copy_from_udata(&offset_addr, udata, | ||
247 | sizeof(offset_addr)); | ||
248 | if (ret) { | ||
249 | vfree(wq); | ||
250 | goto bail; | ||
251 | } | ||
252 | udata->outbuf = (void __user *) offset_addr; | ||
253 | ret = ib_copy_to_udata(udata, &offset, | ||
254 | sizeof(offset)); | ||
255 | if (ret) { | ||
256 | vfree(wq); | ||
257 | goto bail; | ||
258 | } | ||
259 | } | ||
260 | |||
261 | spin_lock_irq(&srq->rq.lock); | ||
262 | /* | ||
263 | * validate head pointer value and compute | ||
264 | * the number of remaining WQEs. | ||
265 | */ | ||
266 | owq = srq->rq.wq; | ||
267 | head = owq->head; | ||
268 | if (head >= srq->rq.size) | ||
269 | head = 0; | ||
270 | tail = owq->tail; | ||
271 | if (tail >= srq->rq.size) | ||
272 | tail = 0; | ||
273 | n = head; | ||
274 | if (n < tail) | ||
275 | n += srq->rq.size - tail; | ||
228 | else | 276 | else |
229 | n = srq->rq.head - srq->rq.tail; | 277 | n -= tail; |
230 | if (size <= n || size <= srq->limit) { | 278 | if (size <= n) { |
231 | spin_unlock_irqrestore(&srq->rq.lock, flags); | 279 | spin_unlock_irq(&srq->rq.lock); |
232 | vfree(wq); | 280 | vfree(wq); |
233 | ret = -EINVAL; | 281 | ret = -EINVAL; |
234 | goto bail; | 282 | goto bail; |
235 | } | 283 | } |
236 | n = 0; | 284 | n = 0; |
237 | p = wq; | 285 | p = wq->wq; |
238 | while (srq->rq.tail != srq->rq.head) { | 286 | while (tail != head) { |
239 | struct ipath_rwqe *wqe; | 287 | struct ipath_rwqe *wqe; |
240 | int i; | 288 | int i; |
241 | 289 | ||
242 | wqe = get_rwqe_ptr(&srq->rq, srq->rq.tail); | 290 | wqe = get_rwqe_ptr(&srq->rq, tail); |
243 | p->wr_id = wqe->wr_id; | 291 | p->wr_id = wqe->wr_id; |
244 | p->length = wqe->length; | ||
245 | p->num_sge = wqe->num_sge; | 292 | p->num_sge = wqe->num_sge; |
246 | for (i = 0; i < wqe->num_sge; i++) | 293 | for (i = 0; i < wqe->num_sge; i++) |
247 | p->sg_list[i] = wqe->sg_list[i]; | 294 | p->sg_list[i] = wqe->sg_list[i]; |
248 | n++; | 295 | n++; |
249 | p = (struct ipath_rwqe *)((char *) p + sz); | 296 | p = (struct ipath_rwqe *)((char *) p + sz); |
250 | if (++srq->rq.tail >= srq->rq.size) | 297 | if (++tail >= srq->rq.size) |
251 | srq->rq.tail = 0; | 298 | tail = 0; |
252 | } | 299 | } |
253 | vfree(srq->rq.wq); | ||
254 | srq->rq.wq = wq; | 300 | srq->rq.wq = wq; |
255 | srq->rq.size = size; | 301 | srq->rq.size = size; |
256 | srq->rq.head = n; | 302 | wq->head = n; |
257 | srq->rq.tail = 0; | 303 | wq->tail = 0; |
258 | srq->rq.max_sge = attr->max_sge; | 304 | if (attr_mask & IB_SRQ_LIMIT) |
259 | spin_unlock_irqrestore(&srq->rq.lock, flags); | 305 | srq->limit = attr->srq_limit; |
260 | } | 306 | spin_unlock_irq(&srq->rq.lock); |
261 | 307 | ||
262 | if (attr_mask & IB_SRQ_LIMIT) { | 308 | vfree(owq); |
263 | spin_lock_irqsave(&srq->rq.lock, flags); | 309 | |
264 | srq->limit = attr->srq_limit; | 310 | if (srq->ip) { |
265 | spin_unlock_irqrestore(&srq->rq.lock, flags); | 311 | struct ipath_mmap_info *ip = srq->ip; |
312 | struct ipath_ibdev *dev = to_idev(srq->ibsrq.device); | ||
313 | |||
314 | ip->obj = wq; | ||
315 | ip->size = PAGE_ALIGN(sizeof(struct ipath_rwq) + | ||
316 | size * sz); | ||
317 | spin_lock_irq(&dev->pending_lock); | ||
318 | ip->next = dev->pending_mmaps; | ||
319 | dev->pending_mmaps = ip; | ||
320 | spin_unlock_irq(&dev->pending_lock); | ||
321 | } | ||
322 | } else if (attr_mask & IB_SRQ_LIMIT) { | ||
323 | spin_lock_irq(&srq->rq.lock); | ||
324 | if (attr->srq_limit >= srq->rq.size) | ||
325 | ret = -EINVAL; | ||
326 | else | ||
327 | srq->limit = attr->srq_limit; | ||
328 | spin_unlock_irq(&srq->rq.lock); | ||
266 | } | 329 | } |
267 | ret = 0; | ||
268 | 330 | ||
269 | bail: | 331 | bail: |
270 | return ret; | 332 | return ret; |