488 lines · c
1/*2 * Copyright (c) 2018 Chelsio, Inc. All rights reserved.3 *4 * This software is available to you under a choice of one of two5 * licenses. You may choose to be licensed under the terms of the GNU6 * General Public License (GPL) Version 2, available from the file7 * COPYING in the main directory of this source tree, or the8 * OpenIB.org BSD license below:9 *10 * Redistribution and use in source and binary forms, with or11 * without modification, are permitted provided that the following12 * conditions are met:13 *14 * - Redistributions of source code must retain the above15 * copyright notice, this list of conditions and the following16 * disclaimer.17 *18 * - Redistributions in binary form must reproduce the above19 * copyright notice, this list of conditions and the following20 * disclaimer in the documentation and/or other materials21 * provided with the distribution.22 *23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,24 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF25 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND26 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS27 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN28 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN29 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE30 * SOFTWARE.31 */32 33#include <rdma/rdma_cm.h>34 35#include "iw_cxgb4.h"36#include <rdma/restrack.h>37#include <uapi/rdma/rdma_netlink.h>38 39static int fill_sq(struct sk_buff *msg, struct t4_wq *wq)40{41 /* WQ+SQ */42 if (rdma_nl_put_driver_u32(msg, "sqid", wq->sq.qid))43 goto err;44 if (rdma_nl_put_driver_u32(msg, "flushed", wq->flushed))45 goto err;46 if (rdma_nl_put_driver_u32(msg, "memsize", wq->sq.memsize))47 goto err;48 if (rdma_nl_put_driver_u32(msg, "cidx", wq->sq.cidx))49 goto err;50 if (rdma_nl_put_driver_u32(msg, "pidx", wq->sq.pidx))51 goto err;52 if (rdma_nl_put_driver_u32(msg, "wq_pidx", wq->sq.wq_pidx))53 goto err;54 if (rdma_nl_put_driver_u32(msg, "flush_cidx", wq->sq.flush_cidx))55 goto err;56 if (rdma_nl_put_driver_u32(msg, "in_use", wq->sq.in_use))57 goto err;58 if (rdma_nl_put_driver_u32(msg, "size", wq->sq.size))59 goto err;60 if (rdma_nl_put_driver_u32_hex(msg, "flags", wq->sq.flags))61 goto err;62 return 0;63err:64 return -EMSGSIZE;65}66 67static int fill_rq(struct sk_buff *msg, struct t4_wq *wq)68{69 /* RQ */70 if (rdma_nl_put_driver_u32(msg, "rqid", wq->rq.qid))71 goto err;72 if (rdma_nl_put_driver_u32(msg, "memsize", wq->rq.memsize))73 goto err;74 if (rdma_nl_put_driver_u32(msg, "cidx", wq->rq.cidx))75 goto err;76 if (rdma_nl_put_driver_u32(msg, "pidx", wq->rq.pidx))77 goto err;78 if (rdma_nl_put_driver_u32(msg, "wq_pidx", wq->rq.wq_pidx))79 goto err;80 if (rdma_nl_put_driver_u32(msg, "msn", wq->rq.msn))81 goto err;82 if (rdma_nl_put_driver_u32_hex(msg, "rqt_hwaddr", wq->rq.rqt_hwaddr))83 goto err;84 if (rdma_nl_put_driver_u32(msg, "rqt_size", wq->rq.rqt_size))85 goto err;86 if (rdma_nl_put_driver_u32(msg, "in_use", wq->rq.in_use))87 goto err;88 if (rdma_nl_put_driver_u32(msg, "size", wq->rq.size))89 goto err;90 return 0;91err:92 return -EMSGSIZE;93}94 95static int fill_swsqe(struct sk_buff *msg, struct t4_sq *sq, u16 idx,96 struct t4_swsqe *sqe)97{98 if (rdma_nl_put_driver_u32(msg, "idx", idx))99 goto err;100 if (rdma_nl_put_driver_u32(msg, "opcode", sqe->opcode))101 goto err;102 if (rdma_nl_put_driver_u32(msg, "complete", sqe->complete))103 goto err;104 if (sqe->complete &&105 rdma_nl_put_driver_u32(msg, "cqe_status", CQE_STATUS(&sqe->cqe)))106 goto err;107 if (rdma_nl_put_driver_u32(msg, "signaled", sqe->signaled))108 goto err;109 if (rdma_nl_put_driver_u32(msg, "flushed", sqe->flushed))110 goto err;111 return 0;112err:113 return -EMSGSIZE;114}115 116/*117 * Dump the first and last pending sqes.118 */119static int fill_swsqes(struct sk_buff *msg, struct t4_sq *sq,120 u16 first_idx, struct t4_swsqe *first_sqe,121 u16 last_idx, struct t4_swsqe *last_sqe)122{123 if (!first_sqe)124 goto out;125 if (fill_swsqe(msg, sq, first_idx, first_sqe))126 goto err;127 if (!last_sqe)128 goto out;129 if (fill_swsqe(msg, sq, last_idx, last_sqe))130 goto err;131out:132 return 0;133err:134 return -EMSGSIZE;135}136 137int c4iw_fill_res_qp_entry(struct sk_buff *msg, struct ib_qp *ibqp)138{139 struct t4_swsqe *fsp = NULL, *lsp = NULL;140 struct c4iw_qp *qhp = to_c4iw_qp(ibqp);141 u16 first_sq_idx = 0, last_sq_idx = 0;142 struct t4_swsqe first_sqe, last_sqe;143 struct nlattr *table_attr;144 struct t4_wq wq;145 146 /* User qp state is not available, so don't dump user qps */147 if (qhp->ucontext)148 return 0;149 150 table_attr = nla_nest_start_noflag(msg, RDMA_NLDEV_ATTR_DRIVER);151 if (!table_attr)152 goto err;153 154 /* Get a consistent snapshot */155 spin_lock_irq(&qhp->lock);156 wq = qhp->wq;157 158 /* If there are any pending sqes, copy the first and last */159 if (wq.sq.cidx != wq.sq.pidx) {160 first_sq_idx = wq.sq.cidx;161 first_sqe = qhp->wq.sq.sw_sq[first_sq_idx];162 fsp = &first_sqe;163 last_sq_idx = wq.sq.pidx;164 if (last_sq_idx-- == 0)165 last_sq_idx = wq.sq.size - 1;166 if (last_sq_idx != first_sq_idx) {167 last_sqe = qhp->wq.sq.sw_sq[last_sq_idx];168 lsp = &last_sqe;169 }170 }171 spin_unlock_irq(&qhp->lock);172 173 if (fill_sq(msg, &wq))174 goto err_cancel_table;175 176 if (fill_swsqes(msg, &wq.sq, first_sq_idx, fsp, last_sq_idx, lsp))177 goto err_cancel_table;178 179 if (fill_rq(msg, &wq))180 goto err_cancel_table;181 182 nla_nest_end(msg, table_attr);183 return 0;184 185err_cancel_table:186 nla_nest_cancel(msg, table_attr);187err:188 return -EMSGSIZE;189}190 191union union_ep {192 struct c4iw_listen_ep lep;193 struct c4iw_ep ep;194};195 196int c4iw_fill_res_cm_id_entry(struct sk_buff *msg,197 struct rdma_cm_id *cm_id)198{199 struct nlattr *table_attr;200 struct c4iw_ep_common *epcp;201 struct c4iw_listen_ep *listen_ep = NULL;202 struct c4iw_ep *ep = NULL;203 struct iw_cm_id *iw_cm_id;204 union union_ep *uep;205 206 iw_cm_id = rdma_iw_cm_id(cm_id);207 if (!iw_cm_id)208 return 0;209 epcp = (struct c4iw_ep_common *)iw_cm_id->provider_data;210 if (!epcp)211 return 0;212 uep = kzalloc(sizeof(*uep), GFP_KERNEL);213 if (!uep)214 return 0;215 216 table_attr = nla_nest_start_noflag(msg, RDMA_NLDEV_ATTR_DRIVER);217 if (!table_attr)218 goto err_free_uep;219 220 /* Get a consistent snapshot */221 mutex_lock(&epcp->mutex);222 if (epcp->state == LISTEN) {223 uep->lep = *(struct c4iw_listen_ep *)epcp;224 mutex_unlock(&epcp->mutex);225 listen_ep = &uep->lep;226 epcp = &listen_ep->com;227 } else {228 uep->ep = *(struct c4iw_ep *)epcp;229 mutex_unlock(&epcp->mutex);230 ep = &uep->ep;231 epcp = &ep->com;232 }233 234 if (rdma_nl_put_driver_u32(msg, "state", epcp->state))235 goto err_cancel_table;236 if (rdma_nl_put_driver_u64_hex(msg, "flags", epcp->flags))237 goto err_cancel_table;238 if (rdma_nl_put_driver_u64_hex(msg, "history", epcp->history))239 goto err_cancel_table;240 241 if (listen_ep) {242 if (rdma_nl_put_driver_u32(msg, "stid", listen_ep->stid))243 goto err_cancel_table;244 if (rdma_nl_put_driver_u32(msg, "backlog", listen_ep->backlog))245 goto err_cancel_table;246 } else {247 if (rdma_nl_put_driver_u32(msg, "hwtid", ep->hwtid))248 goto err_cancel_table;249 if (rdma_nl_put_driver_u32(msg, "ord", ep->ord))250 goto err_cancel_table;251 if (rdma_nl_put_driver_u32(msg, "ird", ep->ird))252 goto err_cancel_table;253 if (rdma_nl_put_driver_u32(msg, "emss", ep->emss))254 goto err_cancel_table;255 256 if (!ep->parent_ep && rdma_nl_put_driver_u32(msg, "atid",257 ep->atid))258 goto err_cancel_table;259 }260 nla_nest_end(msg, table_attr);261 kfree(uep);262 return 0;263 264err_cancel_table:265 nla_nest_cancel(msg, table_attr);266err_free_uep:267 kfree(uep);268 return -EMSGSIZE;269}270 271static int fill_cq(struct sk_buff *msg, struct t4_cq *cq)272{273 if (rdma_nl_put_driver_u32(msg, "cqid", cq->cqid))274 goto err;275 if (rdma_nl_put_driver_u32(msg, "memsize", cq->memsize))276 goto err;277 if (rdma_nl_put_driver_u32(msg, "size", cq->size))278 goto err;279 if (rdma_nl_put_driver_u32(msg, "cidx", cq->cidx))280 goto err;281 if (rdma_nl_put_driver_u32(msg, "cidx_inc", cq->cidx_inc))282 goto err;283 if (rdma_nl_put_driver_u32(msg, "sw_cidx", cq->sw_cidx))284 goto err;285 if (rdma_nl_put_driver_u32(msg, "sw_pidx", cq->sw_pidx))286 goto err;287 if (rdma_nl_put_driver_u32(msg, "sw_in_use", cq->sw_in_use))288 goto err;289 if (rdma_nl_put_driver_u32(msg, "vector", cq->vector))290 goto err;291 if (rdma_nl_put_driver_u32(msg, "gen", cq->gen))292 goto err;293 if (rdma_nl_put_driver_u32(msg, "error", cq->error))294 goto err;295 if (rdma_nl_put_driver_u64_hex(msg, "bits_type_ts",296 be64_to_cpu(cq->bits_type_ts)))297 goto err;298 if (rdma_nl_put_driver_u64_hex(msg, "flags", cq->flags))299 goto err;300 301 return 0;302 303err:304 return -EMSGSIZE;305}306 307static int fill_cqe(struct sk_buff *msg, struct t4_cqe *cqe, u16 idx,308 const char *qstr)309{310 if (rdma_nl_put_driver_u32(msg, qstr, idx))311 goto err;312 if (rdma_nl_put_driver_u32_hex(msg, "header",313 be32_to_cpu(cqe->header)))314 goto err;315 if (rdma_nl_put_driver_u32(msg, "len", be32_to_cpu(cqe->len)))316 goto err;317 if (rdma_nl_put_driver_u32_hex(msg, "wrid_hi",318 be32_to_cpu(cqe->u.gen.wrid_hi)))319 goto err;320 if (rdma_nl_put_driver_u32_hex(msg, "wrid_low",321 be32_to_cpu(cqe->u.gen.wrid_low)))322 goto err;323 if (rdma_nl_put_driver_u64_hex(msg, "bits_type_ts",324 be64_to_cpu(cqe->bits_type_ts)))325 goto err;326 327 return 0;328 329err:330 return -EMSGSIZE;331}332 333static int fill_hwcqes(struct sk_buff *msg, struct t4_cq *cq,334 struct t4_cqe *cqes)335{336 u16 idx;337 338 idx = (cq->cidx > 0) ? cq->cidx - 1 : cq->size - 1;339 if (fill_cqe(msg, cqes, idx, "hwcq_idx"))340 goto err;341 idx = cq->cidx;342 if (fill_cqe(msg, cqes + 1, idx, "hwcq_idx"))343 goto err;344 345 return 0;346err:347 return -EMSGSIZE;348}349 350static int fill_swcqes(struct sk_buff *msg, struct t4_cq *cq,351 struct t4_cqe *cqes)352{353 u16 idx;354 355 if (!cq->sw_in_use)356 return 0;357 358 idx = cq->sw_cidx;359 if (fill_cqe(msg, cqes, idx, "swcq_idx"))360 goto err;361 if (cq->sw_in_use == 1)362 goto out;363 idx = (cq->sw_pidx > 0) ? cq->sw_pidx - 1 : cq->size - 1;364 if (fill_cqe(msg, cqes + 1, idx, "swcq_idx"))365 goto err;366out:367 return 0;368err:369 return -EMSGSIZE;370}371 372int c4iw_fill_res_cq_entry(struct sk_buff *msg, struct ib_cq *ibcq)373{374 struct c4iw_cq *chp = to_c4iw_cq(ibcq);375 struct nlattr *table_attr;376 struct t4_cqe hwcqes[2];377 struct t4_cqe swcqes[2];378 struct t4_cq cq;379 u16 idx;380 381 /* User cq state is not available, so don't dump user cqs */382 if (ibcq->uobject)383 return 0;384 385 table_attr = nla_nest_start_noflag(msg, RDMA_NLDEV_ATTR_DRIVER);386 if (!table_attr)387 goto err;388 389 /* Get a consistent snapshot */390 spin_lock_irq(&chp->lock);391 392 /* t4_cq struct */393 cq = chp->cq;394 395 /* get 2 hw cqes: cidx-1, and cidx */396 idx = (cq.cidx > 0) ? cq.cidx - 1 : cq.size - 1;397 hwcqes[0] = chp->cq.queue[idx];398 399 idx = cq.cidx;400 hwcqes[1] = chp->cq.queue[idx];401 402 /* get first and last sw cqes */403 if (cq.sw_in_use) {404 swcqes[0] = chp->cq.sw_queue[cq.sw_cidx];405 if (cq.sw_in_use > 1) {406 idx = (cq.sw_pidx > 0) ? cq.sw_pidx - 1 : cq.size - 1;407 swcqes[1] = chp->cq.sw_queue[idx];408 }409 }410 411 spin_unlock_irq(&chp->lock);412 413 if (fill_cq(msg, &cq))414 goto err_cancel_table;415 416 if (fill_swcqes(msg, &cq, swcqes))417 goto err_cancel_table;418 419 if (fill_hwcqes(msg, &cq, hwcqes))420 goto err_cancel_table;421 422 nla_nest_end(msg, table_attr);423 return 0;424 425err_cancel_table:426 nla_nest_cancel(msg, table_attr);427err:428 return -EMSGSIZE;429}430 431int c4iw_fill_res_mr_entry(struct sk_buff *msg, struct ib_mr *ibmr)432{433 struct c4iw_mr *mhp = to_c4iw_mr(ibmr);434 struct c4iw_dev *dev = mhp->rhp;435 u32 stag = mhp->attr.stag;436 struct nlattr *table_attr;437 struct fw_ri_tpte tpte;438 int ret;439 440 if (!stag)441 return 0;442 443 table_attr = nla_nest_start_noflag(msg, RDMA_NLDEV_ATTR_DRIVER);444 if (!table_attr)445 goto err;446 447 ret = cxgb4_read_tpte(dev->rdev.lldi.ports[0], stag, (__be32 *)&tpte);448 if (ret) {449 dev_err(&dev->rdev.lldi.pdev->dev,450 "%s cxgb4_read_tpte err %d\n", __func__, ret);451 return 0;452 }453 454 if (rdma_nl_put_driver_u32_hex(msg, "idx", stag >> 8))455 goto err_cancel_table;456 if (rdma_nl_put_driver_u32(msg, "valid",457 FW_RI_TPTE_VALID_G(ntohl(tpte.valid_to_pdid))))458 goto err_cancel_table;459 if (rdma_nl_put_driver_u32_hex(msg, "key", stag & 0xff))460 goto err_cancel_table;461 if (rdma_nl_put_driver_u32(msg, "state",462 FW_RI_TPTE_STAGSTATE_G(ntohl(tpte.valid_to_pdid))))463 goto err_cancel_table;464 if (rdma_nl_put_driver_u32(msg, "pdid",465 FW_RI_TPTE_PDID_G(ntohl(tpte.valid_to_pdid))))466 goto err_cancel_table;467 if (rdma_nl_put_driver_u32_hex(msg, "perm",468 FW_RI_TPTE_PERM_G(ntohl(tpte.locread_to_qpid))))469 goto err_cancel_table;470 if (rdma_nl_put_driver_u32(msg, "ps",471 FW_RI_TPTE_PS_G(ntohl(tpte.locread_to_qpid))))472 goto err_cancel_table;473 if (rdma_nl_put_driver_u64(msg, "len",474 ((u64)ntohl(tpte.len_hi) << 32) | ntohl(tpte.len_lo)))475 goto err_cancel_table;476 if (rdma_nl_put_driver_u32_hex(msg, "pbl_addr",477 FW_RI_TPTE_PBLADDR_G(ntohl(tpte.nosnoop_pbladdr))))478 goto err_cancel_table;479 480 nla_nest_end(msg, table_attr);481 return 0;482 483err_cancel_table:484 nla_nest_cancel(msg, table_attr);485err:486 return -EMSGSIZE;487}488