1 /*-
2 * SPDX-License-Identifier: GPL-2.0 or Linux-OpenIB
3 *
4 * Copyright (C) 2019 - 2026 Intel Corporation
5 *
6 * This software is available to you under a choice of one of two
7 * licenses. You may choose to be licensed under the terms of the GNU
8 * General Public License (GPL) Version 2, available from the file
9 * COPYING in the main directory of this source tree, or the
10 * OpenFabrics.org BSD license below:
11 *
12 * Redistribution and use in source and binary forms, with or
13 * without modification, are permitted provided that the following
14 * conditions are met:
15 *
16 * - Redistributions of source code must retain the above
17 * copyright notice, this list of conditions and the following
18 * disclaimer.
19 *
20 * - Redistributions in binary form must reproduce the above
21 * copyright notice, this list of conditions and the following
22 * disclaimer in the documentation and/or other materials
23 * provided with the distribution.
24 *
25 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
29 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
30 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
31 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
32 * SOFTWARE.
33 */
34
35 #include <config.h>
36 #include <stdlib.h>
37 #include <stdio.h>
38 #include <string.h>
39 #include <unistd.h>
40 #include <signal.h>
41 #include <errno.h>
42 #include <sys/param.h>
43 #include <sys/mman.h>
44 #include <netinet/in.h>
45 #include <sys/stat.h>
46 #include <fcntl.h>
47 #include <stdbool.h>
48 #include <infiniband/opcode.h>
49
50 #include "irdma_umain.h"
51 #include "abi.h"
52
53 static inline void
print_fw_ver(uint64_t fw_ver,char * str,size_t len)54 print_fw_ver(uint64_t fw_ver, char *str, size_t len)
55 {
56 uint16_t major, minor;
57
58 major = fw_ver >> 32 & 0xffff;
59 minor = fw_ver & 0xffff;
60
61 snprintf(str, len, "%d.%d", major, minor);
62 }
63
64 /**
65 * irdma_uquery_device_ex - query device attributes including extended properties
66 * @context: user context for the device
67 * @input: extensible input struct for ibv_query_device_ex verb
68 * @attr: extended device attribute struct
69 * @attr_size: size of extended device attribute struct
70 **/
71 int
irdma_uquery_device_ex(struct ibv_context * context,const struct ibv_query_device_ex_input * input,struct ibv_device_attr_ex * attr,size_t attr_size)72 irdma_uquery_device_ex(struct ibv_context *context,
73 const struct ibv_query_device_ex_input *input,
74 struct ibv_device_attr_ex *attr, size_t attr_size)
75 {
76 struct irdma_query_device_ex cmd = {};
77 struct irdma_query_device_ex_resp resp = {};
78 uint64_t fw_ver;
79 int ret;
80
81 ret = ibv_cmd_query_device_ex(context, input, attr, attr_size, &fw_ver,
82 &cmd.ibv_cmd, sizeof(cmd.ibv_cmd), sizeof(cmd),
83 &resp.ibv_resp, sizeof(resp.ibv_resp), sizeof(resp));
84 if (ret)
85 return ret;
86
87 print_fw_ver(fw_ver, attr->orig_attr.fw_ver, sizeof(attr->orig_attr.fw_ver));
88
89 return 0;
90 }
91
92 /**
93 * irdma_uquery_device - call driver to query device for max resources
94 * @context: user context for the device
95 * @attr: where to save all the mx resources from the driver
96 **/
97 int
irdma_uquery_device(struct ibv_context * context,struct ibv_device_attr * attr)98 irdma_uquery_device(struct ibv_context *context, struct ibv_device_attr *attr)
99 {
100 struct ibv_query_device cmd;
101 uint64_t fw_ver;
102 int ret;
103
104 ret = ibv_cmd_query_device(context, attr, &fw_ver, &cmd, sizeof(cmd));
105 if (ret)
106 return ret;
107
108 print_fw_ver(fw_ver, attr->fw_ver, sizeof(attr->fw_ver));
109
110 return 0;
111 }
112
113 /**
114 * irdma_uquery_port - get port attributes (msg size, lnk, mtu...)
115 * @context: user context of the device
116 * @port: port for the attributes
117 * @attr: to return port attributes
118 **/
119 int
irdma_uquery_port(struct ibv_context * context,uint8_t port,struct ibv_port_attr * attr)120 irdma_uquery_port(struct ibv_context *context, uint8_t port,
121 struct ibv_port_attr *attr)
122 {
123 struct ibv_query_port cmd;
124
125 return ibv_cmd_query_port(context, port, attr, &cmd, sizeof(cmd));
126 }
127
128 /**
129 * irdma_ualloc_pd - allocates protection domain and return pd ptr
130 * @context: user context of the device
131 **/
132 struct ibv_pd *
irdma_ualloc_pd(struct ibv_context * context)133 irdma_ualloc_pd(struct ibv_context *context)
134 {
135 struct ibv_alloc_pd cmd;
136 struct irdma_ualloc_pd_resp resp = {};
137 struct irdma_upd *iwupd;
138 int err;
139
140 iwupd = calloc(1, sizeof(*iwupd));
141 if (!iwupd)
142 return NULL;
143
144 err = ibv_cmd_alloc_pd(context, &iwupd->ibv_pd, &cmd, sizeof(cmd),
145 &resp.ibv_resp, sizeof(resp));
146 if (err)
147 goto err_free;
148
149 iwupd->pd_id = resp.pd_id;
150
151 return &iwupd->ibv_pd;
152
153 err_free:
154 free(iwupd);
155
156 errno = err;
157 return NULL;
158 }
159
160 /**
161 * irdma_ufree_pd - free pd resources
162 * @pd: pd to free resources
163 */
164 int
irdma_ufree_pd(struct ibv_pd * pd)165 irdma_ufree_pd(struct ibv_pd *pd)
166 {
167 struct irdma_upd *iwupd;
168 int ret;
169
170 iwupd = container_of(pd, struct irdma_upd, ibv_pd);
171 ret = ibv_cmd_dealloc_pd(pd);
172 if (ret)
173 return ret;
174
175 free(iwupd);
176
177 return 0;
178 }
179
180 /**
181 * irdma_ureg_mr - register user memory region
182 * @pd: pd for the mr
183 * @addr: user address of the memory region
184 * @length: length of the memory
185 * @hca_va: hca_va
186 * @access: access allowed on this mr
187 */
188 struct ibv_mr *
irdma_ureg_mr(struct ibv_pd * pd,void * addr,size_t length,int access)189 irdma_ureg_mr(struct ibv_pd *pd, void *addr, size_t length,
190 int access)
191 {
192 struct verbs_mr *vmr;
193 struct irdma_ureg_mr cmd = {};
194 struct ibv_reg_mr_resp resp;
195 int err;
196
197 vmr = malloc(sizeof(*vmr));
198 if (!vmr)
199 return NULL;
200
201 cmd.reg_type = IRDMA_MEMREG_TYPE_MEM;
202 err = ibv_cmd_reg_mr(pd, addr, length,
203 (uintptr_t)addr, access, &vmr->ibv_mr, &cmd.ibv_cmd,
204 sizeof(cmd), &resp, sizeof(resp));
205 if (err) {
206 free(vmr);
207 errno = err;
208 return NULL;
209 }
210
211 return &vmr->ibv_mr;
212 }
213
214 /*
215 * irdma_urereg_mr - re-register memory region @vmr: mr that was allocated @flags: bit mask to indicate which of the
216 * attr's of MR modified @pd: pd of the mr @addr: user address of the memory region @length: length of the memory
217 * @access: access allowed on this mr
218 */
219 int
irdma_urereg_mr(struct verbs_mr * vmr,int flags,struct ibv_pd * pd,void * addr,size_t length,int access)220 irdma_urereg_mr(struct verbs_mr *vmr, int flags, struct ibv_pd *pd,
221 void *addr, size_t length, int access)
222 {
223 struct irdma_urereg_mr cmd = {};
224 struct ibv_rereg_mr_resp resp = {};
225
226 cmd.reg_type = IRDMA_MEMREG_TYPE_MEM;
227 return ibv_cmd_rereg_mr(&vmr->ibv_mr, flags, addr, length, (uintptr_t)addr,
228 access, pd, &cmd.ibv_cmd, sizeof(cmd), &resp,
229 sizeof(resp));
230 }
231
232 /**
233 * irdma_udereg_mr - re-register memory region
234 * @mr: mr that was allocated
235 */
236 int
irdma_udereg_mr(struct ibv_mr * mr)237 irdma_udereg_mr(struct ibv_mr *mr)
238 {
239 struct verbs_mr *vmr;
240 int ret;
241
242 vmr = container_of(mr, struct verbs_mr, ibv_mr);
243
244 ret = ibv_cmd_dereg_mr(mr);
245 if (ret)
246 return ret;
247
248 return 0;
249 }
250
251 /**
252 * irdma_ualloc_mw - allocate memory window
253 * @pd: protection domain
254 * @type: memory window type
255 */
256 struct ibv_mw *
irdma_ualloc_mw(struct ibv_pd * pd,enum ibv_mw_type type)257 irdma_ualloc_mw(struct ibv_pd *pd, enum ibv_mw_type type)
258 {
259 struct ibv_mw *mw;
260 struct ibv_alloc_mw cmd;
261 struct ibv_alloc_mw_resp resp = {};
262 int err;
263
264 mw = calloc(1, sizeof(*mw));
265 if (!mw)
266 return NULL;
267
268 err = ibv_cmd_alloc_mw(pd, type, mw, &cmd, sizeof(cmd), &resp,
269 sizeof(resp));
270 if (err) {
271 printf("%s: Failed to alloc memory window\n",
272 __func__);
273 free(mw);
274 errno = err;
275 return NULL;
276 }
277
278 return mw;
279 }
280
281 /**
282 * irdma_ubind_mw - bind a memory window
283 * @qp: qp to post WR
284 * @mw: memory window to bind
285 * @mw_bind: bind info
286 */
287 int
irdma_ubind_mw(struct ibv_qp * qp,struct ibv_mw * mw,struct ibv_mw_bind * mw_bind)288 irdma_ubind_mw(struct ibv_qp *qp, struct ibv_mw *mw,
289 struct ibv_mw_bind *mw_bind)
290 {
291 struct ibv_mw_bind_info *bind_info = &mw_bind->bind_info;
292 struct verbs_mr *vmr;
293
294 struct ibv_send_wr wr = {};
295 struct ibv_send_wr *bad_wr;
296 int err;
297
298 if (!bind_info->mr && (bind_info->addr || bind_info->length))
299 return EINVAL;
300
301 if (bind_info->mr) {
302 vmr = verbs_get_mr(bind_info->mr);
303 if (vmr->mr_type != IBV_MR_TYPE_MR)
304 return ENOTSUP;
305
306 if (vmr->access & IBV_ACCESS_ZERO_BASED)
307 return EINVAL;
308
309 if (mw->pd != bind_info->mr->pd)
310 return EPERM;
311 }
312
313 wr.opcode = IBV_WR_BIND_MW;
314 wr.bind_mw.bind_info = mw_bind->bind_info;
315 wr.bind_mw.mw = mw;
316 wr.bind_mw.rkey = ibv_inc_rkey(mw->rkey);
317
318 wr.wr_id = mw_bind->wr_id;
319 wr.send_flags = mw_bind->send_flags;
320
321 err = irdma_upost_send(qp, &wr, &bad_wr);
322 if (!err)
323 mw->rkey = wr.bind_mw.rkey;
324
325 return err;
326 }
327
328 /**
329 * irdma_udealloc_mw - deallocate memory window
330 * @mw: memory window to dealloc
331 */
332 int
irdma_udealloc_mw(struct ibv_mw * mw)333 irdma_udealloc_mw(struct ibv_mw *mw)
334 {
335 int ret;
336 struct ibv_dealloc_mw cmd;
337
338 ret = ibv_cmd_dealloc_mw(mw, &cmd, sizeof(cmd));
339 if (ret)
340 return ret;
341 free(mw);
342
343 return 0;
344 }
345
346 static void *
irdma_calloc_hw_buf_sz(size_t size,size_t alignment)347 irdma_calloc_hw_buf_sz(size_t size, size_t alignment)
348 {
349 void *buf;
350
351 buf = memalign(alignment, size);
352
353 if (!buf)
354 return NULL;
355 if (ibv_dontfork_range(buf, size)) {
356 free(buf);
357 return NULL;
358 }
359 memset(buf, 0, size);
360
361 return buf;
362 }
363
364 static void *
irdma_calloc_hw_buf(size_t size)365 irdma_calloc_hw_buf(size_t size)
366 {
367 return irdma_calloc_hw_buf_sz(size, IRDMA_HW_PAGE_SIZE);
368 }
369
370 static void
irdma_free_hw_buf(void * buf,size_t size)371 irdma_free_hw_buf(void *buf, size_t size)
372 {
373 ibv_dofork_range(buf, size);
374 free(buf);
375 }
376
377 /**
378 * get_cq_size - returns actual cqe needed by HW
379 * @ncqe: minimum cqes requested by application
380 * @hw_rev: HW generation
381 * @cqe_64byte_ena: enable 64byte cqe
382 */
383 static inline int
get_cq_size(int ncqe,u8 hw_rev)384 get_cq_size(int ncqe, u8 hw_rev)
385 {
386
387 ncqe += 2;
388
389 /* Completions with immediate require 1 extra entry */
390 if (hw_rev > IRDMA_GEN_1)
391 ncqe *= 2;
392 if (ncqe & 1)
393 ncqe += 1; /* cq size must be an even number */
394
395 if (ncqe < IRDMA_U_MINCQ_SIZE)
396 ncqe = IRDMA_U_MINCQ_SIZE;
397
398 return ncqe;
399 }
400
get_cq_total_bytes(u32 cq_size)401 static inline size_t get_cq_total_bytes(u32 cq_size) {
402 return roundup(cq_size * sizeof(struct irdma_cqe), IRDMA_HW_PAGE_SIZE);
403 }
404
405 /**
406 * ucreate_cq - irdma util function to create a CQ
407 * @context: ibv context
408 * @attr_ex: CQ init attributes
409 * @ext_cq: flag to create an extendable or normal CQ
410 */
411 static struct ibv_cq_ex *
ucreate_cq(struct ibv_context * context,struct ibv_cq_init_attr_ex * attr_ex,bool ext_cq)412 ucreate_cq(struct ibv_context *context,
413 struct ibv_cq_init_attr_ex *attr_ex,
414 bool ext_cq)
415 {
416 struct irdma_cq_uk_init_info info = {};
417 struct irdma_ureg_mr reg_mr_cmd = {};
418 struct irdma_ucreate_cq_ex cmd = {};
419 struct irdma_ucreate_cq_ex_resp resp = {};
420 struct ibv_reg_mr_resp reg_mr_resp = {};
421 struct irdma_ureg_mr reg_mr_shadow_cmd = {};
422 struct ibv_reg_mr_resp reg_mr_shadow_resp = {};
423 struct irdma_uk_attrs *uk_attrs;
424 struct irdma_uvcontext *iwvctx;
425 struct irdma_ucq *iwucq;
426 size_t total_size;
427 u32 cq_pages;
428 int ret, ncqe;
429 u8 hw_rev;
430
431 iwvctx = container_of(context, struct irdma_uvcontext, ibv_ctx);
432 uk_attrs = &iwvctx->uk_attrs;
433 hw_rev = uk_attrs->hw_rev;
434
435 if (ext_cq) {
436 u32 supported_flags = IRDMA_STANDARD_WC_FLAGS_EX;
437
438 if (hw_rev == IRDMA_GEN_1 || attr_ex->wc_flags & ~supported_flags) {
439 errno = EOPNOTSUPP;
440 return NULL;
441 }
442 }
443
444 if (attr_ex->cqe < uk_attrs->min_hw_cq_size || attr_ex->cqe > uk_attrs->max_hw_cq_size - 1) {
445 errno = EINVAL;
446 return NULL;
447 }
448
449 /* save the cqe requested by application */
450 ncqe = attr_ex->cqe;
451
452 iwucq = calloc(1, sizeof(*iwucq));
453 if (!iwucq)
454 return NULL;
455
456 ret = pthread_spin_init(&iwucq->lock, PTHREAD_PROCESS_PRIVATE);
457 if (ret) {
458 free(iwucq);
459 errno = ret;
460 return NULL;
461 }
462
463 info.cq_size = get_cq_size(attr_ex->cqe, hw_rev);
464 total_size = get_cq_total_bytes(info.cq_size);
465 iwucq->comp_vector = attr_ex->comp_vector;
466 LIST_INIT(&iwucq->resize_list);
467 cq_pages = total_size >> IRDMA_HW_PAGE_SHIFT;
468
469 if (!(uk_attrs->feature_flags & IRDMA_FEATURE_CQ_RESIZE))
470 total_size = (cq_pages << IRDMA_HW_PAGE_SHIFT) + IRDMA_DB_SHADOW_AREA_SIZE;
471
472 iwucq->buf_size = total_size;
473 info.cq_base = irdma_calloc_hw_buf(total_size);
474 if (!info.cq_base) {
475 ret = ENOMEM;
476 goto err_cq_base;
477 }
478
479 reg_mr_cmd.reg_type = IRDMA_MEMREG_TYPE_CQ;
480 reg_mr_cmd.cq_pages = cq_pages;
481
482 ret = ibv_cmd_reg_mr(&iwvctx->iwupd->ibv_pd, info.cq_base,
483 total_size, (uintptr_t)info.cq_base,
484 IBV_ACCESS_LOCAL_WRITE, &iwucq->vmr.ibv_mr,
485 ®_mr_cmd.ibv_cmd, sizeof(reg_mr_cmd),
486 ®_mr_resp, sizeof(reg_mr_resp));
487 if (ret)
488 goto err_dereg_mr;
489
490 iwucq->vmr.ibv_mr.pd = &iwvctx->iwupd->ibv_pd;
491
492 if (uk_attrs->feature_flags & IRDMA_FEATURE_CQ_RESIZE) {
493 info.shadow_area = irdma_calloc_hw_buf(IRDMA_DB_SHADOW_AREA_SIZE);
494 if (!info.shadow_area) {
495 ret = ENOMEM;
496 goto err_alloc_shadow;
497 }
498
499 reg_mr_shadow_cmd.reg_type = IRDMA_MEMREG_TYPE_CQ;
500 reg_mr_shadow_cmd.cq_pages = 1;
501
502 ret = ibv_cmd_reg_mr(&iwvctx->iwupd->ibv_pd, info.shadow_area,
503 IRDMA_DB_SHADOW_AREA_SIZE, (uintptr_t)info.shadow_area,
504 IBV_ACCESS_LOCAL_WRITE, &iwucq->vmr_shadow_area.ibv_mr,
505 ®_mr_shadow_cmd.ibv_cmd, sizeof(reg_mr_shadow_cmd),
506 ®_mr_shadow_resp, sizeof(reg_mr_shadow_resp));
507 if (ret) {
508 irdma_free_hw_buf(info.shadow_area, IRDMA_DB_SHADOW_AREA_SIZE);
509 goto err_alloc_shadow;
510 }
511
512 iwucq->vmr_shadow_area.ibv_mr.pd = &iwvctx->iwupd->ibv_pd;
513
514 } else {
515 info.shadow_area = (__le64 *) ((u8 *)info.cq_base + (cq_pages << IRDMA_HW_PAGE_SHIFT));
516 }
517
518 attr_ex->cqe = info.cq_size;
519 cmd.user_cq_buf = (__u64) ((uintptr_t)info.cq_base);
520 cmd.user_shadow_area = (__u64) ((uintptr_t)info.shadow_area);
521
522 ret = ibv_cmd_create_cq_ex(context, attr_ex, &iwucq->verbs_cq.cq_ex,
523 &cmd.ibv_cmd, sizeof(cmd.ibv_cmd), sizeof(cmd), &resp.ibv_resp,
524 sizeof(resp.ibv_resp), sizeof(resp));
525 attr_ex->cqe = ncqe;
526 if (ret)
527 goto err_create_cq;
528
529 if (ext_cq)
530 irdma_ibvcq_ex_fill_priv_funcs(iwucq, attr_ex);
531 info.cq_id = resp.cq_id;
532 /* Do not report the CQE's reserved for immediate and burned by HW */
533 iwucq->verbs_cq.cq.cqe = ncqe;
534 info.cqe_alloc_db = (u32 *)((u8 *)iwvctx->db + IRDMA_DB_CQ_OFFSET);
535 irdma_uk_cq_init(&iwucq->cq, &info);
536 return &iwucq->verbs_cq.cq_ex;
537
538 err_create_cq:
539 if (iwucq->vmr_shadow_area.ibv_mr.handle) {
540 ibv_cmd_dereg_mr(&iwucq->vmr_shadow_area.ibv_mr);
541 irdma_free_hw_buf(info.shadow_area, IRDMA_DB_SHADOW_AREA_SIZE);
542 }
543 err_alloc_shadow:
544 ibv_cmd_dereg_mr(&iwucq->vmr.ibv_mr);
545 err_dereg_mr:
546 irdma_free_hw_buf(info.cq_base, total_size);
547 err_cq_base:
548 printf("%s: failed to initialize CQ\n", __func__);
549 pthread_spin_destroy(&iwucq->lock);
550
551 free(iwucq);
552
553 errno = ret;
554 return NULL;
555 }
556
557 struct ibv_cq *
irdma_ucreate_cq(struct ibv_context * context,int cqe,struct ibv_comp_channel * channel,int comp_vector)558 irdma_ucreate_cq(struct ibv_context *context, int cqe,
559 struct ibv_comp_channel *channel,
560 int comp_vector)
561 {
562 struct ibv_cq_init_attr_ex attr_ex = {
563 .cqe = cqe,
564 .channel = channel,
565 .comp_vector = comp_vector,
566 };
567 struct ibv_cq_ex *ibvcq_ex;
568
569 ibvcq_ex = ucreate_cq(context, &attr_ex, false);
570
571 return ibvcq_ex ? ibv_cq_ex_to_cq(ibvcq_ex) : NULL;
572 }
573
574 struct ibv_cq_ex *
irdma_ucreate_cq_ex(struct ibv_context * context,struct ibv_cq_init_attr_ex * attr_ex)575 irdma_ucreate_cq_ex(struct ibv_context *context,
576 struct ibv_cq_init_attr_ex *attr_ex)
577 {
578 return ucreate_cq(context, attr_ex, true);
579 }
580
581 /**
582 * irdma_free_cq_buf - free memory for cq buffer
583 * @cq_buf: cq buf to free
584 */
585 static void
irdma_free_cq_buf(struct irdma_cq_buf * cq_buf)586 irdma_free_cq_buf(struct irdma_cq_buf *cq_buf)
587 {
588 ibv_cmd_dereg_mr(&cq_buf->vmr.ibv_mr);
589 irdma_free_hw_buf(cq_buf->cq.cq_base, get_cq_total_bytes(cq_buf->cq.cq_size));
590 free(cq_buf);
591 }
592
593 /**
594 * irdma_process_resize_list - process the cq list to remove buffers
595 * @iwucq: cq which owns the list
596 * @lcqe_buf: cq buf where the last cqe is found
597 */
598 static int
irdma_process_resize_list(struct irdma_ucq * iwucq,struct irdma_cq_buf * lcqe_buf)599 irdma_process_resize_list(struct irdma_ucq *iwucq,
600 struct irdma_cq_buf *lcqe_buf)
601 {
602 struct irdma_cq_buf *cq_buf, *next;
603 int cq_cnt = 0;
604
605 LIST_FOREACH_SAFE(cq_buf, &iwucq->resize_list, list, next) {
606 if (cq_buf == lcqe_buf)
607 return cq_cnt;
608
609 LIST_REMOVE(cq_buf, list);
610 irdma_free_cq_buf(cq_buf);
611 cq_cnt++;
612 }
613
614 return cq_cnt;
615 }
616
617 /**
618 * irdma_udestroy_cq - destroys cq
619 * @cq: ptr to cq to be destroyed
620 */
621 int
irdma_udestroy_cq(struct ibv_cq * cq)622 irdma_udestroy_cq(struct ibv_cq *cq)
623 {
624 struct irdma_uk_attrs *uk_attrs;
625 struct irdma_uvcontext *iwvctx;
626 struct irdma_ucq *iwucq;
627 int ret;
628
629 iwucq = container_of(cq, struct irdma_ucq, verbs_cq.cq);
630 iwvctx = container_of(cq->context, struct irdma_uvcontext, ibv_ctx);
631 uk_attrs = &iwvctx->uk_attrs;
632 ret = ibv_cmd_destroy_cq(cq);
633 if (ret)
634 return ret;
635 ibv_cmd_dereg_mr(&iwucq->vmr.ibv_mr);
636 irdma_free_hw_buf(iwucq->cq.cq_base, iwucq->buf_size);
637
638 if (uk_attrs->feature_flags & IRDMA_FEATURE_CQ_RESIZE) {
639 ibv_cmd_dereg_mr(&iwucq->vmr_shadow_area.ibv_mr);
640 irdma_free_hw_buf(iwucq->cq.shadow_area, IRDMA_DB_SHADOW_AREA_SIZE);
641 }
642
643 irdma_process_resize_list(iwucq, NULL);
644
645 ret = pthread_spin_destroy(&iwucq->lock);
646 if (ret)
647 return ret;
648
649 free(iwucq);
650 return 0;
651 }
652
653 static enum ibv_wc_status
irdma_flush_err_to_ib_wc_status(enum irdma_flush_opcode opcode)654 irdma_flush_err_to_ib_wc_status(enum irdma_flush_opcode opcode)
655 {
656 switch (opcode) {
657 case FLUSH_PROT_ERR:
658 return IBV_WC_LOC_PROT_ERR;
659 case FLUSH_REM_ACCESS_ERR:
660 return IBV_WC_REM_ACCESS_ERR;
661 case FLUSH_LOC_QP_OP_ERR:
662 return IBV_WC_LOC_QP_OP_ERR;
663 case FLUSH_REM_OP_ERR:
664 return IBV_WC_REM_OP_ERR;
665 case FLUSH_LOC_LEN_ERR:
666 return IBV_WC_LOC_LEN_ERR;
667 case FLUSH_GENERAL_ERR:
668 return IBV_WC_WR_FLUSH_ERR;
669 case FLUSH_MW_BIND_ERR:
670 return IBV_WC_MW_BIND_ERR;
671 case FLUSH_REM_INV_REQ_ERR:
672 return IBV_WC_REM_INV_REQ_ERR;
673 case FLUSH_RETRY_EXC_ERR:
674 return IBV_WC_RETRY_EXC_ERR;
675 case FLUSH_FATAL_ERR:
676 default:
677 return IBV_WC_FATAL_ERR;
678 }
679 }
680
681 static inline void
set_ib_wc_op_sq(struct irdma_cq_poll_info * cur_cqe,struct ibv_wc * entry)682 set_ib_wc_op_sq(struct irdma_cq_poll_info *cur_cqe, struct ibv_wc *entry)
683 {
684 switch (cur_cqe->op_type) {
685 case IRDMA_OP_TYPE_RDMA_WRITE:
686 case IRDMA_OP_TYPE_RDMA_WRITE_SOL:
687 entry->opcode = IBV_WC_RDMA_WRITE;
688 break;
689 case IRDMA_OP_TYPE_RDMA_READ:
690 entry->opcode = IBV_WC_RDMA_READ;
691 break;
692 case IRDMA_OP_TYPE_SEND_SOL:
693 case IRDMA_OP_TYPE_SEND_SOL_INV:
694 case IRDMA_OP_TYPE_SEND_INV:
695 case IRDMA_OP_TYPE_SEND:
696 entry->opcode = IBV_WC_SEND;
697 break;
698 case IRDMA_OP_TYPE_BIND_MW:
699 entry->opcode = IBV_WC_BIND_MW;
700 break;
701 case IRDMA_OP_TYPE_INV_STAG:
702 entry->opcode = IBV_WC_LOCAL_INV;
703 break;
704 default:
705 entry->status = IBV_WC_GENERAL_ERR;
706 printf("%s: Invalid opcode = %d in CQE\n",
707 __func__, cur_cqe->op_type);
708 }
709 }
710
711 static inline void
set_ib_wc_op_rq(struct irdma_cq_poll_info * cur_cqe,struct ibv_wc * entry,bool send_imm_support)712 set_ib_wc_op_rq(struct irdma_cq_poll_info *cur_cqe,
713 struct ibv_wc *entry, bool send_imm_support)
714 {
715 if (!send_imm_support) {
716 entry->opcode = cur_cqe->imm_valid ? IBV_WC_RECV_RDMA_WITH_IMM :
717 IBV_WC_RECV;
718 return;
719 }
720 switch (cur_cqe->op_type) {
721 case IBV_OPCODE_RDMA_WRITE_ONLY_WITH_IMMEDIATE:
722 case IBV_OPCODE_RDMA_WRITE_LAST_WITH_IMMEDIATE:
723 entry->opcode = IBV_WC_RECV_RDMA_WITH_IMM;
724 break;
725 default:
726 entry->opcode = IBV_WC_RECV;
727 }
728 }
729
730 /**
731 * irdma_process_cqe_ext - process current cqe for extended CQ
732 * @cur_cqe - current cqe info
733 */
734 static void
irdma_process_cqe_ext(struct irdma_cq_poll_info * cur_cqe)735 irdma_process_cqe_ext(struct irdma_cq_poll_info *cur_cqe)
736 {
737 struct irdma_ucq *iwucq = container_of(cur_cqe, struct irdma_ucq, cur_cqe);
738 struct ibv_cq_ex *ibvcq_ex = &iwucq->verbs_cq.cq_ex;
739
740 ibvcq_ex->wr_id = cur_cqe->wr_id;
741 if (cur_cqe->error)
742 ibvcq_ex->status = (cur_cqe->comp_status == IRDMA_COMPL_STATUS_FLUSHED) ?
743 irdma_flush_err_to_ib_wc_status(cur_cqe->minor_err) : IBV_WC_GENERAL_ERR;
744 else
745 ibvcq_ex->status = IBV_WC_SUCCESS;
746 }
747
748 /**
749 * irdma_process_cqe - process current cqe info
750 * @entry - ibv_wc object to fill in for non-extended CQ
751 * @cur_cqe - current cqe info
752 */
753 static void
irdma_process_cqe(struct ibv_wc * entry,struct irdma_cq_poll_info * cur_cqe)754 irdma_process_cqe(struct ibv_wc *entry, struct irdma_cq_poll_info *cur_cqe)
755 {
756 struct irdma_qp_uk *qp;
757 struct ibv_qp *ib_qp;
758
759 entry->wc_flags = 0;
760 entry->wr_id = cur_cqe->wr_id;
761 entry->qp_num = cur_cqe->qp_id;
762 qp = cur_cqe->qp_handle;
763 ib_qp = qp->back_qp;
764
765 if (cur_cqe->error) {
766 entry->status = (cur_cqe->comp_status == IRDMA_COMPL_STATUS_FLUSHED) ?
767 irdma_flush_err_to_ib_wc_status(cur_cqe->minor_err) : IBV_WC_GENERAL_ERR;
768 entry->vendor_err = cur_cqe->major_err << 16 |
769 cur_cqe->minor_err;
770 } else {
771 entry->status = IBV_WC_SUCCESS;
772 }
773
774 if (cur_cqe->imm_valid) {
775 entry->imm_data = htonl(cur_cqe->imm_data);
776 entry->wc_flags |= IBV_WC_WITH_IMM;
777 }
778
779 if (cur_cqe->q_type == IRDMA_CQE_QTYPE_SQ) {
780 set_ib_wc_op_sq(cur_cqe, entry);
781 } else {
782 set_ib_wc_op_rq(cur_cqe, entry,
783 qp->qp_caps & IRDMA_SEND_WITH_IMM ?
784 true : false);
785 if (ib_qp->qp_type != IBV_QPT_UD &&
786 cur_cqe->stag_invalid_set) {
787 entry->invalidated_rkey = cur_cqe->inv_stag;
788 entry->wc_flags |= IBV_WC_WITH_INV;
789 }
790 }
791
792 if (ib_qp->qp_type == IBV_QPT_UD) {
793 entry->src_qp = cur_cqe->ud_src_qpn;
794 #define IRDMA_PKT_TYPE_ROCE_V2_IPV4 1
795 #define IRDMA_PKT_TYPE_ROCE_V2_IPV6 2
796 entry->sl = cur_cqe->ipv4 ? IRDMA_PKT_TYPE_ROCE_V2_IPV4 :
797 IRDMA_PKT_TYPE_ROCE_V2_IPV6;
798 entry->wc_flags |= IBV_WC_GRH;
799 } else {
800 entry->src_qp = cur_cqe->qp_id;
801 }
802 entry->byte_len = cur_cqe->bytes_xfered;
803 }
804
805 /**
806 * irdma_poll_one - poll one entry of the CQ
807 * @ukcq: ukcq to poll
808 * @cur_cqe: current CQE info to be filled in
809 * @entry: ibv_wc object to be filled for non-extended CQ or NULL for extended CQ
810 *
811 * Returns the internal irdma device error code or 0 on success
812 */
813 static int
irdma_poll_one(struct irdma_cq_uk * ukcq,struct irdma_cq_poll_info * cur_cqe,struct ibv_wc * entry)814 irdma_poll_one(struct irdma_cq_uk *ukcq, struct irdma_cq_poll_info *cur_cqe,
815 struct ibv_wc *entry)
816 {
817 int ret = irdma_uk_cq_poll_cmpl(ukcq, cur_cqe);
818
819 if (ret)
820 return ret;
821
822 if (!entry)
823 irdma_process_cqe_ext(cur_cqe);
824 else
825 irdma_process_cqe(entry, cur_cqe);
826
827 return 0;
828 }
829
830 /**
831 * __irdma_upoll_cq - irdma util function to poll device CQ
832 * @iwucq: irdma cq to poll
833 * @num_entries: max cq entries to poll
834 * @entry: pointer to array of ibv_wc objects to be filled in for each completion or NULL if ext CQ
835 *
836 * Returns non-negative value equal to the number of completions
837 * found. On failure, EINVAL
838 */
839 static int
__irdma_upoll_cq(struct irdma_ucq * iwucq,int num_entries,struct ibv_wc * entry)840 __irdma_upoll_cq(struct irdma_ucq *iwucq, int num_entries,
841 struct ibv_wc *entry)
842 {
843 struct irdma_cq_buf *cq_buf, *next;
844 struct irdma_cq_buf *last_buf = NULL;
845 struct irdma_cq_poll_info *cur_cqe = &iwucq->cur_cqe;
846 bool cq_new_cqe = false;
847 int resized_bufs = 0;
848 int npolled = 0;
849 int ret;
850
851 /* go through the list of previously resized CQ buffers */
852 LIST_FOREACH_SAFE(cq_buf, &iwucq->resize_list, list, next) {
853 while (npolled < num_entries) {
854 ret = irdma_poll_one(&cq_buf->cq, cur_cqe,
855 entry ? entry + npolled : NULL);
856 if (!ret) {
857 ++npolled;
858 cq_new_cqe = true;
859 continue;
860 }
861 if (ret == ENOENT)
862 break;
863 /* QP using the CQ is destroyed. Skip reporting this CQE */
864 if (ret == EFAULT) {
865 cq_new_cqe = true;
866 continue;
867 }
868 goto error;
869 }
870
871 /* save the resized CQ buffer which received the last cqe */
872 if (cq_new_cqe)
873 last_buf = cq_buf;
874 cq_new_cqe = false;
875 }
876
877 /* check the current CQ for new cqes */
878 while (npolled < num_entries) {
879 ret = irdma_poll_one(&iwucq->cq, cur_cqe,
880 entry ? entry + npolled : NULL);
881 if (!ret) {
882 ++npolled;
883 cq_new_cqe = true;
884 continue;
885 }
886 if (ret == ENOENT)
887 break;
888 /* QP using the CQ is destroyed. Skip reporting this CQE */
889 if (ret == EFAULT) {
890 cq_new_cqe = true;
891 continue;
892 }
893 goto error;
894 }
895
896 if (cq_new_cqe)
897 /* all previous CQ resizes are complete */
898 resized_bufs = irdma_process_resize_list(iwucq, NULL);
899 else if (last_buf)
900 /* only CQ resizes up to the last_buf are complete */
901 resized_bufs = irdma_process_resize_list(iwucq, last_buf);
902 if (resized_bufs)
903 /* report to the HW the number of complete CQ resizes */
904 irdma_uk_cq_set_resized_cnt(&iwucq->cq, resized_bufs);
905
906 return npolled;
907
908 error:
909 printf("%s: Error polling CQ, irdma_err: %d\n", __func__, ret);
910
911 return EINVAL;
912 }
913
914 /**
915 * irdma_upoll_cq - verb API callback to poll device CQ
916 * @cq: ibv_cq to poll
917 * @num_entries: max cq entries to poll
918 * @entry: pointer to array of ibv_wc objects to be filled in for each completion
919 *
920 * Returns non-negative value equal to the number of completions
921 * found and a negative error code on failure
922 */
923 int
irdma_upoll_cq(struct ibv_cq * cq,int num_entries,struct ibv_wc * entry)924 irdma_upoll_cq(struct ibv_cq *cq, int num_entries, struct ibv_wc *entry)
925 {
926 struct irdma_ucq *iwucq;
927 int ret;
928
929 iwucq = container_of(cq, struct irdma_ucq, verbs_cq.cq);
930 ret = pthread_spin_lock(&iwucq->lock);
931 if (ret)
932 return -ret;
933
934 ret = __irdma_upoll_cq(iwucq, num_entries, entry);
935
936 pthread_spin_unlock(&iwucq->lock);
937
938 return ret;
939 }
940
941 /**
942 * irdma_start_poll - verb_ex API callback to poll batch of WC's
943 * @ibvcq_ex: ibv extended CQ
944 * @attr: attributes (not used)
945 *
946 * Start polling batch of work completions. Return 0 on success, ENONENT when
947 * no completions are available on CQ. And an error code on errors
948 */
949 static int
irdma_start_poll(struct ibv_cq_ex * ibvcq_ex,struct ibv_poll_cq_attr * attr)950 irdma_start_poll(struct ibv_cq_ex *ibvcq_ex, struct ibv_poll_cq_attr *attr)
951 {
952 struct irdma_ucq *iwucq;
953 int ret;
954
955 iwucq = container_of(ibvcq_ex, struct irdma_ucq, verbs_cq.cq_ex);
956 ret = pthread_spin_lock(&iwucq->lock);
957 if (ret)
958 return ret;
959
960 ret = __irdma_upoll_cq(iwucq, 1, NULL);
961 if (ret == 1)
962 return 0;
963
964 /* No Completions on CQ */
965 if (!ret)
966 ret = ENOENT;
967
968 pthread_spin_unlock(&iwucq->lock);
969
970 return ret;
971 }
972
973 /**
974 * irdma_next_poll - verb_ex API callback to get next WC
975 * @ibvcq_ex: ibv extended CQ
976 *
977 * Return 0 on success, ENONENT when no completions are available on CQ.
978 * And an error code on errors
979 */
980 static int
irdma_next_poll(struct ibv_cq_ex * ibvcq_ex)981 irdma_next_poll(struct ibv_cq_ex *ibvcq_ex)
982 {
983 struct irdma_ucq *iwucq;
984 int ret;
985
986 iwucq = container_of(ibvcq_ex, struct irdma_ucq, verbs_cq.cq_ex);
987 ret = __irdma_upoll_cq(iwucq, 1, NULL);
988 if (ret == 1)
989 return 0;
990
991 /* No Completions on CQ */
992 if (!ret)
993 ret = ENOENT;
994
995 return ret;
996 }
997
998 /**
999 * irdma_end_poll - verb_ex API callback to end polling of WC's
1000 * @ibvcq_ex: ibv extended CQ
1001 */
1002 static void
irdma_end_poll(struct ibv_cq_ex * ibvcq_ex)1003 irdma_end_poll(struct ibv_cq_ex *ibvcq_ex)
1004 {
1005 struct irdma_ucq *iwucq = container_of(ibvcq_ex, struct irdma_ucq,
1006 verbs_cq.cq_ex);
1007
1008 pthread_spin_unlock(&iwucq->lock);
1009 }
1010
1011 static enum ibv_wc_opcode
irdma_wc_read_opcode(struct ibv_cq_ex * ibvcq_ex)1012 irdma_wc_read_opcode(struct ibv_cq_ex *ibvcq_ex)
1013 {
1014 struct irdma_ucq *iwucq = container_of(ibvcq_ex, struct irdma_ucq,
1015 verbs_cq.cq_ex);
1016
1017 switch (iwucq->cur_cqe.op_type) {
1018 case IRDMA_OP_TYPE_RDMA_WRITE:
1019 case IRDMA_OP_TYPE_RDMA_WRITE_SOL:
1020 return IBV_WC_RDMA_WRITE;
1021 case IRDMA_OP_TYPE_RDMA_READ:
1022 return IBV_WC_RDMA_READ;
1023 case IRDMA_OP_TYPE_SEND_SOL:
1024 case IRDMA_OP_TYPE_SEND_SOL_INV:
1025 case IRDMA_OP_TYPE_SEND_INV:
1026 case IRDMA_OP_TYPE_SEND:
1027 return IBV_WC_SEND;
1028 case IRDMA_OP_TYPE_BIND_MW:
1029 return IBV_WC_BIND_MW;
1030 case IRDMA_OP_TYPE_REC:
1031 return IBV_WC_RECV;
1032 case IRDMA_OP_TYPE_REC_IMM:
1033 return IBV_WC_RECV_RDMA_WITH_IMM;
1034 case IRDMA_OP_TYPE_INV_STAG:
1035 return IBV_WC_LOCAL_INV;
1036 }
1037
1038 printf("%s: Invalid opcode = %d in CQE\n", __func__,
1039 iwucq->cur_cqe.op_type);
1040
1041 return 0;
1042 }
1043
irdma_wc_read_vendor_err(struct ibv_cq_ex * ibvcq_ex)1044 static uint32_t irdma_wc_read_vendor_err(struct ibv_cq_ex *ibvcq_ex){
1045 struct irdma_cq_poll_info *cur_cqe;
1046 struct irdma_ucq *iwucq;
1047
1048 iwucq = container_of(ibvcq_ex, struct irdma_ucq, verbs_cq.cq_ex);
1049 cur_cqe = &iwucq->cur_cqe;
1050
1051 return cur_cqe->error ? cur_cqe->major_err << 16 | cur_cqe->minor_err : 0;
1052 }
1053
1054 static int
irdma_wc_read_wc_flags(struct ibv_cq_ex * ibvcq_ex)1055 irdma_wc_read_wc_flags(struct ibv_cq_ex *ibvcq_ex)
1056 {
1057 struct irdma_cq_poll_info *cur_cqe;
1058 struct irdma_ucq *iwucq;
1059 struct irdma_qp_uk *qp;
1060 struct ibv_qp *ib_qp;
1061 int wc_flags = 0;
1062
1063 iwucq = container_of(ibvcq_ex, struct irdma_ucq, verbs_cq.cq_ex);
1064 cur_cqe = &iwucq->cur_cqe;
1065 qp = cur_cqe->qp_handle;
1066 ib_qp = qp->back_qp;
1067
1068 if (cur_cqe->imm_valid)
1069 wc_flags |= IBV_WC_WITH_IMM;
1070
1071 if (ib_qp->qp_type == IBV_QPT_UD) {
1072 wc_flags |= IBV_WC_GRH;
1073 } else {
1074 if (cur_cqe->stag_invalid_set) {
1075 switch (cur_cqe->op_type) {
1076 case IRDMA_OP_TYPE_REC:
1077 wc_flags |= IBV_WC_WITH_INV;
1078 break;
1079 case IRDMA_OP_TYPE_REC_IMM:
1080 wc_flags |= IBV_WC_WITH_INV;
1081 break;
1082 }
1083 }
1084 }
1085
1086 return wc_flags;
1087 }
1088
irdma_wc_read_byte_len(struct ibv_cq_ex * ibvcq_ex)1089 static uint32_t irdma_wc_read_byte_len(struct ibv_cq_ex *ibvcq_ex){
1090 struct irdma_ucq *iwucq = container_of(ibvcq_ex, struct irdma_ucq,
1091 verbs_cq.cq_ex);
1092
1093 return iwucq->cur_cqe.bytes_xfered;
1094 }
1095
irdma_wc_read_imm_data(struct ibv_cq_ex * ibvcq_ex)1096 static __be32 irdma_wc_read_imm_data(struct ibv_cq_ex *ibvcq_ex){
1097 struct irdma_cq_poll_info *cur_cqe;
1098 struct irdma_ucq *iwucq;
1099
1100 iwucq = container_of(ibvcq_ex, struct irdma_ucq, verbs_cq.cq_ex);
1101 cur_cqe = &iwucq->cur_cqe;
1102
1103 return cur_cqe->imm_valid ? htonl(cur_cqe->imm_data) : 0;
1104 }
1105
irdma_wc_read_qp_num(struct ibv_cq_ex * ibvcq_ex)1106 static uint32_t irdma_wc_read_qp_num(struct ibv_cq_ex *ibvcq_ex){
1107 struct irdma_ucq *iwucq = container_of(ibvcq_ex, struct irdma_ucq,
1108 verbs_cq.cq_ex);
1109
1110 return iwucq->cur_cqe.qp_id;
1111 }
1112
irdma_wc_read_src_qp(struct ibv_cq_ex * ibvcq_ex)1113 static uint32_t irdma_wc_read_src_qp(struct ibv_cq_ex *ibvcq_ex){
1114 struct irdma_cq_poll_info *cur_cqe;
1115 struct irdma_ucq *iwucq;
1116 struct irdma_qp_uk *qp;
1117 struct ibv_qp *ib_qp;
1118
1119 iwucq = container_of(ibvcq_ex, struct irdma_ucq, verbs_cq.cq_ex);
1120 cur_cqe = &iwucq->cur_cqe;
1121 qp = cur_cqe->qp_handle;
1122 ib_qp = qp->back_qp;
1123
1124 return ib_qp->qp_type == IBV_QPT_UD ? cur_cqe->ud_src_qpn : cur_cqe->qp_id;
1125 }
1126
irdma_wc_read_sl(struct ibv_cq_ex * ibvcq_ex)1127 static uint8_t irdma_wc_read_sl(struct ibv_cq_ex *ibvcq_ex){
1128 return 0;
1129 }
1130
1131 void
irdma_ibvcq_ex_fill_priv_funcs(struct irdma_ucq * iwucq,struct ibv_cq_init_attr_ex * attr_ex)1132 irdma_ibvcq_ex_fill_priv_funcs(struct irdma_ucq *iwucq,
1133 struct ibv_cq_init_attr_ex *attr_ex)
1134 {
1135 struct ibv_cq_ex *ibvcq_ex = &iwucq->verbs_cq.cq_ex;
1136
1137 ibvcq_ex->start_poll = irdma_start_poll;
1138 ibvcq_ex->end_poll = irdma_end_poll;
1139 ibvcq_ex->next_poll = irdma_next_poll;
1140
1141 ibvcq_ex->read_opcode = irdma_wc_read_opcode;
1142 ibvcq_ex->read_vendor_err = irdma_wc_read_vendor_err;
1143 ibvcq_ex->read_wc_flags = irdma_wc_read_wc_flags;
1144
1145 if (attr_ex->wc_flags & IBV_WC_EX_WITH_BYTE_LEN)
1146 ibvcq_ex->read_byte_len = irdma_wc_read_byte_len;
1147 if (attr_ex->wc_flags & IBV_WC_EX_WITH_IMM)
1148 ibvcq_ex->read_imm_data = irdma_wc_read_imm_data;
1149 if (attr_ex->wc_flags & IBV_WC_EX_WITH_QP_NUM)
1150 ibvcq_ex->read_qp_num = irdma_wc_read_qp_num;
1151 if (attr_ex->wc_flags & IBV_WC_EX_WITH_SRC_QP)
1152 ibvcq_ex->read_src_qp = irdma_wc_read_src_qp;
1153 if (attr_ex->wc_flags & IBV_WC_EX_WITH_SL)
1154 ibvcq_ex->read_sl = irdma_wc_read_sl;
1155 }
1156
1157 /**
1158 * irdma_arm_cq - arm of cq
1159 * @iwucq: cq to which arm
1160 * @cq_notify: notification params
1161 */
1162 static void
irdma_arm_cq(struct irdma_ucq * iwucq,enum irdma_cmpl_notify cq_notify)1163 irdma_arm_cq(struct irdma_ucq *iwucq,
1164 enum irdma_cmpl_notify cq_notify)
1165 {
1166 iwucq->is_armed = true;
1167 iwucq->arm_sol = true;
1168 iwucq->skip_arm = false;
1169 iwucq->skip_sol = true;
1170 irdma_uk_cq_request_notification(&iwucq->cq, cq_notify);
1171 }
1172
1173 /**
1174 * irdma_uarm_cq - callback for arm of cq
1175 * @cq: cq to arm
1176 * @solicited: to get notify params
1177 */
1178 int
irdma_uarm_cq(struct ibv_cq * cq,int solicited)1179 irdma_uarm_cq(struct ibv_cq *cq, int solicited)
1180 {
1181 struct irdma_ucq *iwucq;
1182 enum irdma_cmpl_notify cq_notify = IRDMA_CQ_COMPL_EVENT;
1183 int ret;
1184
1185 iwucq = container_of(cq, struct irdma_ucq, verbs_cq.cq);
1186 if (solicited)
1187 cq_notify = IRDMA_CQ_COMPL_SOLICITED;
1188
1189 ret = pthread_spin_lock(&iwucq->lock);
1190 if (ret)
1191 return ret;
1192
1193 if (iwucq->is_armed) {
1194 if (iwucq->arm_sol && !solicited) {
1195 irdma_arm_cq(iwucq, cq_notify);
1196 } else {
1197 iwucq->skip_arm = true;
1198 iwucq->skip_sol = solicited ? true : false;
1199 }
1200 } else {
1201 irdma_arm_cq(iwucq, cq_notify);
1202 }
1203
1204 pthread_spin_unlock(&iwucq->lock);
1205
1206 return 0;
1207 }
1208
1209 /**
1210 * irdma_cq_event - cq to do completion event
1211 * @cq: cq to arm
1212 */
1213 void
irdma_cq_event(struct ibv_cq * cq)1214 irdma_cq_event(struct ibv_cq *cq)
1215 {
1216 struct irdma_ucq *iwucq;
1217
1218 iwucq = container_of(cq, struct irdma_ucq, verbs_cq.cq);
1219 if (pthread_spin_lock(&iwucq->lock))
1220 return;
1221
1222 if (iwucq->skip_arm)
1223 irdma_arm_cq(iwucq, IRDMA_CQ_COMPL_EVENT);
1224 else
1225 iwucq->is_armed = false;
1226
1227 pthread_spin_unlock(&iwucq->lock);
1228 }
1229
1230 void *
irdma_mmap(int fd,off_t offset)1231 irdma_mmap(int fd, off_t offset)
1232 {
1233 void *map;
1234
1235 map = mmap(NULL, IRDMA_HW_PAGE_SIZE, PROT_WRITE | PROT_READ, MAP_SHARED,
1236 fd, offset);
1237 if (map == MAP_FAILED)
1238 return map;
1239
1240 if (ibv_dontfork_range(map, IRDMA_HW_PAGE_SIZE)) {
1241 munmap(map, IRDMA_HW_PAGE_SIZE);
1242 return MAP_FAILED;
1243 }
1244
1245 return map;
1246 }
1247
1248 void
irdma_munmap(void * map)1249 irdma_munmap(void *map)
1250 {
1251 ibv_dofork_range(map, IRDMA_HW_PAGE_SIZE);
1252 munmap(map, IRDMA_HW_PAGE_SIZE);
1253 }
1254
1255 /**
1256 * irdma_destroy_vmapped_qp - destroy resources for qp
1257 * @iwuqp: qp struct for resources
1258 */
1259 static int
irdma_destroy_vmapped_qp(struct irdma_uqp * iwuqp)1260 irdma_destroy_vmapped_qp(struct irdma_uqp *iwuqp)
1261 {
1262 int ret;
1263
1264 ret = ibv_cmd_destroy_qp(&iwuqp->ibv_qp);
1265 if (ret)
1266 return ret;
1267
1268 if (iwuqp->qp.push_db)
1269 irdma_munmap(iwuqp->qp.push_db_map);
1270 if (iwuqp->qp.push_wqe)
1271 irdma_munmap(iwuqp->qp.push_wqe_map);
1272
1273 ibv_cmd_dereg_mr(&iwuqp->vmr.ibv_mr);
1274
1275 return 0;
1276 }
1277
1278 /**
1279 * irdma_vmapped_qp - create resources for qp
1280 * @iwuqp: qp struct for resources
1281 * @pd: pd for the qp
1282 * @attr: attributes of qp passed
1283 * @resp: response back from create qp
1284 * @info: uk info for initializing user level qp
1285 * @abi_ver: abi version of the create qp command
1286 */
1287 static int
irdma_vmapped_qp(struct irdma_uqp * iwuqp,struct ibv_pd * pd,struct ibv_qp_init_attr * attr,struct irdma_qp_uk_init_info * info,bool legacy_mode)1288 irdma_vmapped_qp(struct irdma_uqp *iwuqp, struct ibv_pd *pd,
1289 struct ibv_qp_init_attr *attr,
1290 struct irdma_qp_uk_init_info *info,
1291 bool legacy_mode)
1292 {
1293 struct irdma_ucreate_qp cmd = {};
1294 size_t sqsize, rqsize, totalqpsize;
1295 struct irdma_ucreate_qp_resp resp = {};
1296 struct irdma_ureg_mr reg_mr_cmd = {};
1297 struct ibv_reg_mr_resp reg_mr_resp = {};
1298 struct irdma_uvcontext *iwvctx;
1299 int ret;
1300 long os_pgsz = IRDMA_HW_PAGE_SIZE;
1301
1302 sqsize = roundup(info->sq_depth * IRDMA_QP_WQE_MIN_SIZE, IRDMA_HW_PAGE_SIZE);
1303 rqsize = roundup(info->rq_depth * IRDMA_QP_WQE_MIN_SIZE, IRDMA_HW_PAGE_SIZE);
1304 totalqpsize = rqsize + sqsize + IRDMA_DB_SHADOW_AREA_SIZE;
1305
1306 iwvctx = container_of(pd->context, struct irdma_uvcontext, ibv_ctx);
1307 /* adjust alignment for iwarp */
1308 if (iwvctx->ibv_ctx.device->transport_type ==
1309 IBV_TRANSPORT_IWARP) {
1310 long pgsz = sysconf(_SC_PAGESIZE);
1311
1312 if (pgsz > 0)
1313 os_pgsz = pgsz;
1314 }
1315 info->sq = irdma_calloc_hw_buf_sz(totalqpsize, os_pgsz);
1316 if (!info->sq)
1317 return ENOMEM;
1318
1319 iwuqp->buf_size = totalqpsize;
1320 info->rq = &info->sq[sqsize / IRDMA_QP_WQE_MIN_SIZE];
1321 info->shadow_area = info->rq[rqsize / IRDMA_QP_WQE_MIN_SIZE].elem;
1322
1323 reg_mr_cmd.reg_type = IRDMA_MEMREG_TYPE_QP;
1324 reg_mr_cmd.sq_pages = sqsize >> IRDMA_HW_PAGE_SHIFT;
1325 reg_mr_cmd.rq_pages = rqsize >> IRDMA_HW_PAGE_SHIFT;
1326
1327 ret = ibv_cmd_reg_mr(pd, info->sq, totalqpsize,
1328 (uintptr_t)info->sq, IBV_ACCESS_LOCAL_WRITE,
1329 &iwuqp->vmr.ibv_mr, ®_mr_cmd.ibv_cmd,
1330 sizeof(reg_mr_cmd), ®_mr_resp,
1331 sizeof(reg_mr_resp));
1332 if (ret)
1333 goto err_dereg_mr;
1334
1335 cmd.user_wqe_bufs = (__u64) ((uintptr_t)info->sq);
1336 cmd.user_compl_ctx = (__u64) (uintptr_t)&iwuqp->qp;
1337 cmd.comp_mask |= IRDMA_CREATE_QP_USE_START_WQE_IDX;
1338
1339 ret = ibv_cmd_create_qp(pd, &iwuqp->ibv_qp, attr, &cmd.ibv_cmd,
1340 sizeof(cmd), &resp.ibv_resp,
1341 sizeof(struct irdma_ucreate_qp_resp));
1342 if (ret)
1343 goto err_qp;
1344
1345 info->sq_size = resp.actual_sq_size;
1346 info->rq_size = resp.actual_rq_size;
1347 info->first_sq_wq = legacy_mode ? 1 : resp.lsmm;
1348 if (resp.comp_mask & IRDMA_CREATE_QP_USE_START_WQE_IDX)
1349 info->start_wqe_idx = resp.start_wqe_idx;
1350 info->qp_caps = resp.qp_caps;
1351 info->qp_id = resp.qp_id;
1352 iwuqp->irdma_drv_opt = resp.irdma_drv_opt;
1353 iwuqp->ibv_qp.qp_num = resp.qp_id;
1354
1355 iwuqp->send_cq = container_of(attr->send_cq, struct irdma_ucq,
1356 verbs_cq.cq);
1357 iwuqp->recv_cq = container_of(attr->recv_cq, struct irdma_ucq,
1358 verbs_cq.cq);
1359 iwuqp->send_cq->uqp = iwuqp;
1360 iwuqp->recv_cq->uqp = iwuqp;
1361
1362 return 0;
1363 err_qp:
1364 ibv_cmd_dereg_mr(&iwuqp->vmr.ibv_mr);
1365 err_dereg_mr:
1366 printf("%s: failed to create QP, status %d\n", __func__, ret);
1367 irdma_free_hw_buf(info->sq, iwuqp->buf_size);
1368 return ret;
1369 }
1370
1371 /**
1372 * irdma_ucreate_qp - create qp on user app
1373 * @pd: pd for the qp
1374 * @attr: attributes of the qp to be created (sizes, sge, cq)
1375 */
1376 struct ibv_qp *
irdma_ucreate_qp(struct ibv_pd * pd,struct ibv_qp_init_attr * attr)1377 irdma_ucreate_qp(struct ibv_pd *pd,
1378 struct ibv_qp_init_attr *attr)
1379 {
1380 struct irdma_qp_uk_init_info info = {};
1381 struct irdma_uk_attrs *uk_attrs;
1382 struct irdma_uvcontext *iwvctx;
1383 struct irdma_uqp *iwuqp;
1384 int status;
1385
1386 if (attr->qp_type != IBV_QPT_RC && attr->qp_type != IBV_QPT_UD) {
1387 printf("%s: failed to create QP, unsupported QP type: 0x%x\n",
1388 __func__, attr->qp_type);
1389 errno = EOPNOTSUPP;
1390 return NULL;
1391 }
1392
1393 iwvctx = container_of(pd->context, struct irdma_uvcontext, ibv_ctx);
1394 uk_attrs = &iwvctx->uk_attrs;
1395
1396 if (attr->cap.max_send_sge > uk_attrs->max_hw_wq_frags ||
1397 attr->cap.max_recv_sge > uk_attrs->max_hw_wq_frags ||
1398 attr->cap.max_send_wr > uk_attrs->max_hw_wq_quanta ||
1399 attr->cap.max_recv_wr > uk_attrs->max_hw_rq_quanta ||
1400 attr->cap.max_inline_data > uk_attrs->max_hw_inline) {
1401 errno = EINVAL;
1402 return NULL;
1403 }
1404
1405 info.uk_attrs = uk_attrs;
1406 info.sq_size = attr->cap.max_send_wr;
1407 info.rq_size = attr->cap.max_recv_wr;
1408 info.max_sq_frag_cnt = attr->cap.max_send_sge;
1409 info.max_rq_frag_cnt = attr->cap.max_recv_sge;
1410 info.max_inline_data = attr->cap.max_inline_data;
1411 info.abi_ver = iwvctx->abi_ver;
1412
1413 status = irdma_uk_calc_depth_shift_sq(&info, &info.sq_depth, &info.sq_shift);
1414 if (status) {
1415 printf("%s: invalid SQ attributes, max_send_wr=%d max_send_sge=%d max_inline=%d\n",
1416 __func__, attr->cap.max_send_wr, attr->cap.max_send_sge,
1417 attr->cap.max_inline_data);
1418 errno = status;
1419 return NULL;
1420 }
1421
1422 status = irdma_uk_calc_depth_shift_rq(&info, &info.rq_depth, &info.rq_shift);
1423 if (status) {
1424 printf("%s: invalid RQ attributes, recv_wr=%d recv_sge=%d\n",
1425 __func__, attr->cap.max_recv_wr, attr->cap.max_recv_sge);
1426 errno = status;
1427 return NULL;
1428 }
1429
1430 iwuqp = memalign(1024, sizeof(*iwuqp));
1431 if (!iwuqp)
1432 return NULL;
1433
1434 memset(iwuqp, 0, sizeof(*iwuqp));
1435
1436 status = pthread_spin_init(&iwuqp->lock, PTHREAD_PROCESS_PRIVATE);
1437 if (status)
1438 goto err_free_qp;
1439
1440 info.sq_size = info.sq_depth >> info.sq_shift;
1441 info.rq_size = info.rq_depth >> info.rq_shift;
1442 /**
1443 * Maintain backward compatibility with older ABI which pass sq
1444 * and rq depth (in quanta) in cap.max_send_wr a cap.max_recv_wr
1445 */
1446 if (!iwvctx->use_raw_attrs) {
1447 attr->cap.max_send_wr = info.sq_size;
1448 attr->cap.max_recv_wr = info.rq_size;
1449 }
1450
1451 info.wqe_alloc_db = (u32 *)iwvctx->db;
1452 info.legacy_mode = iwvctx->legacy_mode;
1453 info.sq_wrtrk_array = calloc(info.sq_depth, sizeof(*info.sq_wrtrk_array));
1454 if (!info.sq_wrtrk_array) {
1455 status = errno; /* preserve errno */
1456 goto err_destroy_lock;
1457 }
1458
1459 info.rq_wrid_array = calloc(info.rq_depth, sizeof(*info.rq_wrid_array));
1460 if (!info.rq_wrid_array) {
1461 status = errno; /* preserve errno */
1462 goto err_free_sq_wrtrk;
1463 }
1464
1465 iwuqp->sq_sig_all = attr->sq_sig_all;
1466 iwuqp->qp_type = attr->qp_type;
1467 status = irdma_vmapped_qp(iwuqp, pd, attr, &info, iwvctx->legacy_mode);
1468 if (status)
1469 goto err_free_rq_wrid;
1470
1471 iwuqp->qp.back_qp = iwuqp;
1472 iwuqp->qp.lock = &iwuqp->lock;
1473
1474 status = irdma_uk_qp_init(&iwuqp->qp, &info);
1475 if (status)
1476 goto err_free_vmap_qp;
1477
1478 attr->cap.max_send_wr = (info.sq_depth - IRDMA_SQ_RSVD) >> info.sq_shift;
1479 attr->cap.max_recv_wr = (info.rq_depth - IRDMA_RQ_RSVD) >> info.rq_shift;
1480
1481 return &iwuqp->ibv_qp;
1482
1483 err_free_vmap_qp:
1484 irdma_destroy_vmapped_qp(iwuqp);
1485 irdma_free_hw_buf(info.sq, iwuqp->buf_size);
1486 err_free_rq_wrid:
1487 free(info.rq_wrid_array);
1488 err_free_sq_wrtrk:
1489 free(info.sq_wrtrk_array);
1490 err_destroy_lock:
1491 pthread_spin_destroy(&iwuqp->lock);
1492 err_free_qp:
1493 printf("%s: failed to create QP\n", __func__);
1494 free(iwuqp);
1495
1496 errno = status;
1497 return NULL;
1498 }
1499
1500 /**
1501 * irdma_uquery_qp - query qp for some attribute
1502 * @qp: qp for the attributes query
1503 * @attr: to return the attributes
1504 * @attr_mask: mask of what is query for
1505 * @init_attr: initial attributes during create_qp
1506 */
1507 int
irdma_uquery_qp(struct ibv_qp * qp,struct ibv_qp_attr * attr,int attr_mask,struct ibv_qp_init_attr * init_attr)1508 irdma_uquery_qp(struct ibv_qp *qp, struct ibv_qp_attr *attr, int attr_mask,
1509 struct ibv_qp_init_attr *init_attr)
1510 {
1511 struct ibv_query_qp cmd;
1512
1513 return ibv_cmd_query_qp(qp, attr, attr_mask, init_attr, &cmd,
1514 sizeof(cmd));
1515 }
1516
1517 /**
1518 * irdma_umodify_qp - send qp modify to driver
1519 * @qp: qp to modify
1520 * @attr: attribute to modify
1521 * @attr_mask: mask of the attribute
1522 */
1523 int
irdma_umodify_qp(struct ibv_qp * qp,struct ibv_qp_attr * attr,int attr_mask)1524 irdma_umodify_qp(struct ibv_qp *qp, struct ibv_qp_attr *attr, int attr_mask)
1525 {
1526 struct irdma_umodify_qp_resp resp = {};
1527 struct ibv_modify_qp cmd = {};
1528 struct irdma_modify_qp_cmd cmd_ex = {};
1529 struct irdma_uvcontext *iwvctx;
1530 struct irdma_uqp *iwuqp;
1531
1532 iwuqp = container_of(qp, struct irdma_uqp, ibv_qp);
1533 iwvctx = container_of(qp->context, struct irdma_uvcontext, ibv_ctx);
1534
1535 if (iwuqp->qp.qp_caps & IRDMA_PUSH_MODE && attr_mask & IBV_QP_STATE &&
1536 iwvctx->uk_attrs.hw_rev > IRDMA_GEN_1) {
1537 u64 offset;
1538 int ret;
1539
1540 ret = ibv_cmd_modify_qp_ex(qp, attr, attr_mask, &cmd_ex.ibv_cmd,
1541 sizeof(cmd_ex.ibv_cmd),
1542 sizeof(cmd_ex), &resp.ibv_resp,
1543 sizeof(resp.ibv_resp),
1544 sizeof(resp));
1545 if (!ret)
1546 iwuqp->qp.rd_fence_rate = resp.rd_fence_rate;
1547 if (ret || !resp.push_valid)
1548 return ret;
1549
1550 if (iwuqp->qp.push_wqe)
1551 return ret;
1552
1553 offset = resp.push_wqe_mmap_key;
1554 iwuqp->qp.push_wqe_map = irdma_mmap(qp->context->cmd_fd, offset);
1555 if (iwuqp->qp.push_wqe_map == MAP_FAILED)
1556 return ret;
1557
1558 offset = resp.push_db_mmap_key;
1559 iwuqp->qp.push_db_map = irdma_mmap(qp->context->cmd_fd, offset);
1560 if (iwuqp->qp.push_db_map == MAP_FAILED) {
1561 irdma_munmap(iwuqp->qp.push_wqe_map);
1562 printf("failed to map push page, errno %d\n", errno);
1563 return ret;
1564 }
1565 iwuqp->qp.push_wqe = iwuqp->qp.push_wqe_map + resp.push_offset;
1566 iwuqp->qp.push_db = iwuqp->qp.push_db_map + resp.push_offset;
1567
1568 return ret;
1569 } else {
1570 return ibv_cmd_modify_qp(qp, attr, attr_mask, &cmd, sizeof(cmd));
1571 }
1572 }
1573
1574 static void
irdma_issue_flush(struct ibv_qp * qp,bool sq_flush,bool rq_flush)1575 irdma_issue_flush(struct ibv_qp *qp, bool sq_flush, bool rq_flush)
1576 {
1577 struct irdma_umodify_qp_resp resp = {};
1578 struct irdma_modify_qp_cmd cmd_ex = {};
1579 struct ibv_qp_attr attr = {};
1580
1581 attr.qp_state = IBV_QPS_ERR;
1582 cmd_ex.sq_flush = sq_flush;
1583 cmd_ex.rq_flush = rq_flush;
1584
1585 ibv_cmd_modify_qp_ex(qp, &attr, IBV_QP_STATE,
1586 &cmd_ex.ibv_cmd,
1587 sizeof(cmd_ex.ibv_cmd),
1588 sizeof(cmd_ex), &resp.ibv_resp,
1589 sizeof(resp.ibv_resp),
1590 sizeof(resp));
1591 }
1592
1593 /**
1594 * irdma_clean_cqes - clean cq entries for qp
1595 * @qp: qp for which completions are cleaned
1596 * @iwcq: cq to be cleaned
1597 */
1598 static void
irdma_clean_cqes(struct irdma_qp_uk * qp,struct irdma_ucq * iwucq)1599 irdma_clean_cqes(struct irdma_qp_uk *qp, struct irdma_ucq *iwucq)
1600 {
1601 struct irdma_cq_uk *ukcq = &iwucq->cq;
1602 int ret;
1603
1604 ret = pthread_spin_lock(&iwucq->lock);
1605 if (ret)
1606 return;
1607
1608 irdma_uk_clean_cq(qp, ukcq);
1609 pthread_spin_unlock(&iwucq->lock);
1610 }
1611
1612 /**
1613 * irdma_udestroy_qp - destroy qp
1614 * @qp: qp to destroy
1615 */
1616 int
irdma_udestroy_qp(struct ibv_qp * qp)1617 irdma_udestroy_qp(struct ibv_qp *qp)
1618 {
1619 struct irdma_uqp *iwuqp;
1620 int ret;
1621
1622 iwuqp = container_of(qp, struct irdma_uqp, ibv_qp);
1623 ret = pthread_spin_destroy(&iwuqp->lock);
1624 if (ret)
1625 goto err;
1626
1627 ret = irdma_destroy_vmapped_qp(iwuqp);
1628 if (ret)
1629 goto err;
1630
1631 /* Clean any pending completions from the cq(s) */
1632 if (iwuqp->send_cq)
1633 irdma_clean_cqes(&iwuqp->qp, iwuqp->send_cq);
1634
1635 if (iwuqp->recv_cq && iwuqp->recv_cq != iwuqp->send_cq)
1636 irdma_clean_cqes(&iwuqp->qp, iwuqp->recv_cq);
1637
1638 if (iwuqp->qp.sq_wrtrk_array)
1639 free(iwuqp->qp.sq_wrtrk_array);
1640 if (iwuqp->qp.rq_wrid_array)
1641 free(iwuqp->qp.rq_wrid_array);
1642
1643 irdma_free_hw_buf(iwuqp->qp.sq_base, iwuqp->buf_size);
1644 free(iwuqp);
1645 return 0;
1646
1647 err:
1648 printf("%s: failed to destroy QP, status %d\n",
1649 __func__, ret);
1650 return ret;
1651 }
1652
1653 /**
1654 * calc_type2_mw_stag - calculate type 2 MW stag
1655 * @rkey: desired rkey of the MW
1656 * @mw_rkey: type2 memory window rkey
1657 *
1658 * compute type2 memory window stag by taking lower 8 bits
1659 * of the desired rkey and leaving 24 bits if mw->rkey unchanged
1660 */
calc_type2_mw_stag(u32 rkey,u32 mw_rkey)1661 static inline u32 calc_type2_mw_stag(u32 rkey, u32 mw_rkey) {
1662 const u32 mask = 0xff;
1663
1664 return (rkey & mask) | (mw_rkey & ~mask);
1665 }
1666
1667 /**
1668 * irdma_post_send - post send wr for user application
1669 * @ib_qp: qp to post wr
1670 * @ib_wr: work request ptr
1671 * @bad_wr: return of bad wr if err
1672 */
1673 int
irdma_upost_send(struct ibv_qp * ib_qp,struct ibv_send_wr * ib_wr,struct ibv_send_wr ** bad_wr)1674 irdma_upost_send(struct ibv_qp *ib_qp, struct ibv_send_wr *ib_wr,
1675 struct ibv_send_wr **bad_wr)
1676 {
1677 struct irdma_post_sq_info info;
1678 struct irdma_uvcontext *iwvctx;
1679 struct irdma_uk_attrs *uk_attrs;
1680 struct irdma_uqp *iwuqp;
1681 bool reflush = false;
1682 int err = 0;
1683
1684 iwuqp = container_of(ib_qp, struct irdma_uqp, ibv_qp);
1685 iwvctx = container_of(ib_qp->context, struct irdma_uvcontext, ibv_ctx);
1686 uk_attrs = &iwvctx->uk_attrs;
1687
1688 err = pthread_spin_lock(&iwuqp->lock);
1689 if (err)
1690 return err;
1691
1692 if (!IRDMA_RING_MORE_WORK(iwuqp->qp.sq_ring) &&
1693 ib_qp->state == IBV_QPS_ERR)
1694 reflush = true;
1695
1696 while (ib_wr) {
1697 memset(&info, 0, sizeof(info));
1698 info.wr_id = (u64)(ib_wr->wr_id);
1699 if ((ib_wr->send_flags & IBV_SEND_SIGNALED) ||
1700 iwuqp->sq_sig_all)
1701 info.signaled = true;
1702 if (ib_wr->send_flags & IBV_SEND_FENCE)
1703 info.read_fence = true;
1704
1705 switch (ib_wr->opcode) {
1706 case IBV_WR_SEND_WITH_IMM:
1707 if (iwuqp->qp.qp_caps & IRDMA_SEND_WITH_IMM) {
1708 info.imm_data_valid = true;
1709 info.imm_data = ntohl(ib_wr->imm_data);
1710 } else {
1711 err = EINVAL;
1712 break;
1713 }
1714 /* fallthrough */
1715 case IBV_WR_SEND:
1716 case IBV_WR_SEND_WITH_INV:
1717 if (ib_wr->opcode == IBV_WR_SEND ||
1718 ib_wr->opcode == IBV_WR_SEND_WITH_IMM) {
1719 if (ib_wr->send_flags & IBV_SEND_SOLICITED)
1720 info.op_type = IRDMA_OP_TYPE_SEND_SOL;
1721 else
1722 info.op_type = IRDMA_OP_TYPE_SEND;
1723 } else {
1724 if (ib_wr->send_flags & IBV_SEND_SOLICITED)
1725 info.op_type = IRDMA_OP_TYPE_SEND_SOL_INV;
1726 else
1727 info.op_type = IRDMA_OP_TYPE_SEND_INV;
1728 info.stag_to_inv = ib_wr->imm_data;
1729 }
1730 info.op.send.num_sges = ib_wr->num_sge;
1731 info.op.send.sg_list = (struct ibv_sge *)ib_wr->sg_list;
1732 if (ib_qp->qp_type == IBV_QPT_UD) {
1733 struct irdma_uah *ah = container_of(ib_wr->wr.ud.ah,
1734 struct irdma_uah, ibv_ah);
1735
1736 info.op.send.ah_id = ah->ah_id;
1737 info.op.send.qkey = ib_wr->wr.ud.remote_qkey;
1738 info.op.send.dest_qp = ib_wr->wr.ud.remote_qpn;
1739 }
1740
1741 if (ib_wr->send_flags & IBV_SEND_INLINE)
1742 err = irdma_uk_inline_send(&iwuqp->qp, &info, false);
1743 else
1744 err = irdma_uk_send(&iwuqp->qp, &info, false);
1745 break;
1746 case IBV_WR_RDMA_WRITE_WITH_IMM:
1747 if (iwuqp->qp.qp_caps & IRDMA_WRITE_WITH_IMM) {
1748 info.imm_data_valid = true;
1749 info.imm_data = ntohl(ib_wr->imm_data);
1750 } else {
1751 err = EINVAL;
1752 break;
1753 }
1754 /* fallthrough */
1755 case IBV_WR_RDMA_WRITE:
1756 if (ib_wr->send_flags & IBV_SEND_SOLICITED)
1757 info.op_type = IRDMA_OP_TYPE_RDMA_WRITE_SOL;
1758 else
1759 info.op_type = IRDMA_OP_TYPE_RDMA_WRITE;
1760
1761 info.op.rdma_write.num_lo_sges = ib_wr->num_sge;
1762 info.op.rdma_write.lo_sg_list = ib_wr->sg_list;
1763 info.op.rdma_write.rem_addr.addr = ib_wr->wr.rdma.remote_addr;
1764 info.op.rdma_write.rem_addr.lkey = ib_wr->wr.rdma.rkey;
1765 if (ib_wr->send_flags & IBV_SEND_INLINE)
1766 err = irdma_uk_inline_rdma_write(&iwuqp->qp, &info, false);
1767 else
1768 err = irdma_uk_rdma_write(&iwuqp->qp, &info, false);
1769 break;
1770 case IBV_WR_RDMA_READ:
1771 if (ib_wr->num_sge > uk_attrs->max_hw_read_sges) {
1772 err = EINVAL;
1773 break;
1774 }
1775 info.op_type = IRDMA_OP_TYPE_RDMA_READ;
1776 info.op.rdma_read.rem_addr.addr = ib_wr->wr.rdma.remote_addr;
1777 info.op.rdma_read.rem_addr.lkey = ib_wr->wr.rdma.rkey;
1778
1779 info.op.rdma_read.lo_sg_list = ib_wr->sg_list;
1780 info.op.rdma_read.num_lo_sges = ib_wr->num_sge;
1781 err = irdma_uk_rdma_read(&iwuqp->qp, &info, false, false);
1782 break;
1783 case IBV_WR_BIND_MW:
1784 if (ib_qp->qp_type != IBV_QPT_RC ||
1785 (ib_wr->bind_mw.mw->type == IBV_MW_TYPE_1 &&
1786 ib_wr->bind_mw.bind_info.mw_access_flags &
1787 IBV_ACCESS_ZERO_BASED)) {
1788 err = EINVAL;
1789 break;
1790 }
1791 info.op_type = IRDMA_OP_TYPE_BIND_MW;
1792 info.op.bind_window.mr_stag = ib_wr->bind_mw.bind_info.mr->rkey;
1793 if (ib_wr->bind_mw.mw->type == IBV_MW_TYPE_1) {
1794 info.op.bind_window.mem_window_type_1 = true;
1795 info.op.bind_window.mw_stag = ib_wr->bind_mw.rkey;
1796 } else {
1797 struct verbs_mr *vmr = verbs_get_mr(ib_wr->bind_mw.bind_info.mr);
1798
1799 if (vmr->access & IBV_ACCESS_ZERO_BASED) {
1800 err = EINVAL;
1801 break;
1802 }
1803 info.op.bind_window.mw_stag =
1804 calc_type2_mw_stag(ib_wr->bind_mw.rkey, ib_wr->bind_mw.mw->rkey);
1805 ib_wr->bind_mw.mw->rkey = info.op.bind_window.mw_stag;
1806 }
1807
1808 if (ib_wr->bind_mw.bind_info.mw_access_flags & IBV_ACCESS_ZERO_BASED)
1809 info.op.bind_window.addressing_type = IRDMA_ADDR_TYPE_ZERO_BASED;
1810 else
1811 info.op.bind_window.addressing_type = IRDMA_ADDR_TYPE_VA_BASED;
1812
1813 info.op.bind_window.va = (void *)(uintptr_t)ib_wr->bind_mw.bind_info.addr;
1814 info.op.bind_window.bind_len = ib_wr->bind_mw.bind_info.length;
1815 info.op.bind_window.ena_reads =
1816 (ib_wr->bind_mw.bind_info.mw_access_flags & IBV_ACCESS_REMOTE_READ) ? 1 : 0;
1817 info.op.bind_window.ena_writes =
1818 (ib_wr->bind_mw.bind_info.mw_access_flags & IBV_ACCESS_REMOTE_WRITE) ? 1 : 0;
1819
1820 err = irdma_uk_mw_bind(&iwuqp->qp, &info, false);
1821 break;
1822 case IBV_WR_LOCAL_INV:
1823 info.op_type = IRDMA_OP_TYPE_INV_STAG;
1824 info.op.inv_local_stag.target_stag = ib_wr->imm_data;
1825 err = irdma_uk_stag_local_invalidate(&iwuqp->qp, &info, true);
1826 break;
1827 default:
1828 /* error */
1829 err = EINVAL;
1830 printf("%s: post work request failed, invalid opcode: 0x%x\n",
1831 __func__, ib_wr->opcode);
1832 break;
1833 }
1834 if (err)
1835 break;
1836
1837 ib_wr = ib_wr->next;
1838 }
1839
1840 if (err)
1841 *bad_wr = ib_wr;
1842
1843 irdma_uk_qp_post_wr(&iwuqp->qp);
1844 if (reflush)
1845 irdma_issue_flush(ib_qp, 1, 0);
1846
1847 pthread_spin_unlock(&iwuqp->lock);
1848
1849 return err;
1850 }
1851
1852 /**
1853 * irdma_post_recv - post receive wr for user application
1854 * @ib_wr: work request for receive
1855 * @bad_wr: bad wr caused an error
1856 */
1857 int
irdma_upost_recv(struct ibv_qp * ib_qp,struct ibv_recv_wr * ib_wr,struct ibv_recv_wr ** bad_wr)1858 irdma_upost_recv(struct ibv_qp *ib_qp, struct ibv_recv_wr *ib_wr,
1859 struct ibv_recv_wr **bad_wr)
1860 {
1861 struct irdma_post_rq_info post_recv = {};
1862 struct irdma_uqp *iwuqp;
1863 bool reflush = false;
1864 int err;
1865
1866 iwuqp = container_of(ib_qp, struct irdma_uqp, ibv_qp);
1867 err = pthread_spin_lock(&iwuqp->lock);
1868 if (err)
1869 return err;
1870
1871 if (!IRDMA_RING_MORE_WORK(iwuqp->qp.rq_ring) &&
1872 ib_qp->state == IBV_QPS_ERR)
1873 reflush = true;
1874
1875 while (ib_wr) {
1876 if (ib_wr->num_sge > iwuqp->qp.max_rq_frag_cnt) {
1877 *bad_wr = ib_wr;
1878 err = EINVAL;
1879 goto error;
1880 }
1881 post_recv.num_sges = ib_wr->num_sge;
1882 post_recv.wr_id = ib_wr->wr_id;
1883 post_recv.sg_list = ib_wr->sg_list;
1884 err = irdma_uk_post_receive(&iwuqp->qp, &post_recv);
1885 if (err) {
1886 *bad_wr = ib_wr;
1887 goto error;
1888 }
1889
1890 if (reflush)
1891 irdma_issue_flush(ib_qp, 0, 1);
1892
1893 ib_wr = ib_wr->next;
1894 }
1895 error:
1896 pthread_spin_unlock(&iwuqp->lock);
1897
1898 return err;
1899 }
1900
1901 /**
1902 * irdma_ucreate_ah - create address handle associated with a pd
1903 * @ibpd: pd for the address handle
1904 * @attr: attributes of address handle
1905 */
1906 struct ibv_ah *
irdma_ucreate_ah(struct ibv_pd * ibpd,struct ibv_ah_attr * attr)1907 irdma_ucreate_ah(struct ibv_pd *ibpd, struct ibv_ah_attr *attr)
1908 {
1909 struct irdma_uah *ah;
1910 union ibv_gid sgid;
1911 struct irdma_ucreate_ah_resp resp = {};
1912 int err;
1913
1914 if (ibv_query_gid(ibpd->context, attr->port_num, attr->grh.sgid_index,
1915 &sgid)) {
1916 fprintf(stderr, "irdma: Error from ibv_query_gid.\n");
1917 errno = ENOENT;
1918 return NULL;
1919 }
1920
1921 ah = calloc(1, sizeof(*ah));
1922 if (!ah)
1923 return NULL;
1924
1925 err = ibv_cmd_create_ah(ibpd, &ah->ibv_ah, attr, &resp.ibv_resp,
1926 sizeof(resp));
1927 if (err) {
1928 free(ah);
1929 errno = err;
1930 return NULL;
1931 }
1932
1933 ah->ah_id = resp.ah_id;
1934
1935 return &ah->ibv_ah;
1936 }
1937
1938 /**
1939 * irdma_udestroy_ah - destroy the address handle
1940 * @ibah: address handle
1941 */
1942 int
irdma_udestroy_ah(struct ibv_ah * ibah)1943 irdma_udestroy_ah(struct ibv_ah *ibah)
1944 {
1945 struct irdma_uah *ah;
1946 int ret;
1947
1948 ah = container_of(ibah, struct irdma_uah, ibv_ah);
1949
1950 ret = ibv_cmd_destroy_ah(ibah);
1951 if (ret)
1952 return ret;
1953
1954 free(ah);
1955
1956 return 0;
1957 }
1958
1959 /**
1960 * irdma_uattach_mcast - Attach qp to multicast group implemented
1961 * @qp: The queue pair
1962 * @gid:The Global ID for multicast group
1963 * @lid: The Local ID
1964 */
1965 int
irdma_uattach_mcast(struct ibv_qp * qp,const union ibv_gid * gid,uint16_t lid)1966 irdma_uattach_mcast(struct ibv_qp *qp, const union ibv_gid *gid,
1967 uint16_t lid)
1968 {
1969 return ibv_cmd_attach_mcast(qp, gid, lid);
1970 }
1971
1972 /**
1973 * irdma_udetach_mcast - Detach qp from multicast group
1974 * @qp: The queue pair
1975 * @gid:The Global ID for multicast group
1976 * @lid: The Local ID
1977 */
1978 int
irdma_udetach_mcast(struct ibv_qp * qp,const union ibv_gid * gid,uint16_t lid)1979 irdma_udetach_mcast(struct ibv_qp *qp, const union ibv_gid *gid,
1980 uint16_t lid)
1981 {
1982 return ibv_cmd_detach_mcast(qp, gid, lid);
1983 }
1984
1985 /**
1986 * irdma_uresize_cq - resizes a cq
1987 * @cq: cq to resize
1988 * @cqe: the number of cqes of the new cq
1989 */
1990 int
irdma_uresize_cq(struct ibv_cq * cq,int cqe)1991 irdma_uresize_cq(struct ibv_cq *cq, int cqe)
1992 {
1993 struct irdma_uvcontext *iwvctx;
1994 struct irdma_uk_attrs *uk_attrs;
1995 struct irdma_uresize_cq cmd = {};
1996 struct ibv_resize_cq_resp resp = {};
1997 struct irdma_ureg_mr reg_mr_cmd = {};
1998 struct ibv_reg_mr_resp reg_mr_resp = {};
1999 struct irdma_cq_buf *cq_buf = NULL;
2000 struct irdma_cqe *cq_base = NULL;
2001 struct verbs_mr new_mr = {};
2002 struct irdma_ucq *iwucq;
2003 size_t cq_size;
2004 u32 cq_pages;
2005 int cqe_needed;
2006 int ret = 0;
2007
2008 iwucq = container_of(cq, struct irdma_ucq, verbs_cq.cq);
2009 iwvctx = container_of(cq->context, struct irdma_uvcontext, ibv_ctx);
2010 uk_attrs = &iwvctx->uk_attrs;
2011
2012 if (!(uk_attrs->feature_flags & IRDMA_FEATURE_CQ_RESIZE))
2013 return EOPNOTSUPP;
2014
2015 if (cqe < uk_attrs->min_hw_cq_size || cqe > uk_attrs->max_hw_cq_size - 1)
2016 return EINVAL;
2017
2018 cqe_needed = get_cq_size(cqe, uk_attrs->hw_rev);
2019 if (cqe_needed == iwucq->cq.cq_size)
2020 return 0;
2021
2022 cq_size = get_cq_total_bytes(cqe_needed);
2023 cq_pages = cq_size >> IRDMA_HW_PAGE_SHIFT;
2024 cq_base = irdma_calloc_hw_buf(cq_size);
2025 if (!cq_base)
2026 return ENOMEM;
2027
2028 cq_buf = malloc(sizeof(*cq_buf));
2029 if (!cq_buf) {
2030 ret = ENOMEM;
2031 goto err_buf;
2032 }
2033
2034 new_mr.ibv_mr.pd = iwucq->vmr.ibv_mr.pd;
2035 reg_mr_cmd.reg_type = IRDMA_MEMREG_TYPE_CQ;
2036 reg_mr_cmd.cq_pages = cq_pages;
2037
2038 ret = ibv_cmd_reg_mr(new_mr.ibv_mr.pd, cq_base, cq_size,
2039 (uintptr_t)cq_base, IBV_ACCESS_LOCAL_WRITE,
2040 &new_mr.ibv_mr, ®_mr_cmd.ibv_cmd, sizeof(reg_mr_cmd),
2041 ®_mr_resp, sizeof(reg_mr_resp));
2042 if (ret)
2043 goto err_dereg_mr;
2044
2045 ret = pthread_spin_lock(&iwucq->lock);
2046 if (ret)
2047 goto err_lock;
2048
2049 cmd.user_cq_buffer = (__u64) ((uintptr_t)cq_base);
2050 ret = ibv_cmd_resize_cq(&iwucq->verbs_cq.cq, cqe_needed, &cmd.ibv_cmd,
2051 sizeof(cmd), &resp, sizeof(resp));
2052 if (ret)
2053 goto err_resize;
2054
2055 memcpy(&cq_buf->cq, &iwucq->cq, sizeof(cq_buf->cq));
2056 cq_buf->vmr = iwucq->vmr;
2057 iwucq->vmr = new_mr;
2058 irdma_uk_cq_resize(&iwucq->cq, cq_base, cqe_needed);
2059 iwucq->verbs_cq.cq.cqe = cqe;
2060 LIST_INSERT_HEAD(&iwucq->resize_list, cq_buf, list);
2061
2062 pthread_spin_unlock(&iwucq->lock);
2063
2064 return ret;
2065
2066 err_resize:
2067 pthread_spin_unlock(&iwucq->lock);
2068 err_lock:
2069 ibv_cmd_dereg_mr(&new_mr.ibv_mr);
2070 err_dereg_mr:
2071 free(cq_buf);
2072 err_buf:
2073 fprintf(stderr, "failed to resize CQ cq_id=%d ret=%d\n", iwucq->cq.cq_id, ret);
2074 irdma_free_hw_buf(cq_base, cq_size);
2075 return ret;
2076 }
2077