Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mlx5: Add driver for Mellanox Connect-IB adapters

The driver is comprised of two kernel modules: mlx5_ib and mlx5_core.
This partitioning resembles what we have for mlx4, except that mlx5_ib
is the pci device driver and not mlx5_core.

mlx5_core is essentially a library that provides general functionality
that is intended to be used by other Mellanox devices that will be
introduced in the future. mlx5_ib has a similar role as any hardware
device under drivers/infiniband/hw.

Signed-off-by: Eli Cohen <eli@mellanox.com>
Signed-off-by: Jack Morgenstein <jackm@dev.mellanox.co.il>
Signed-off-by: Or Gerlitz <ogerlitz@mellanox.com>

[ Merge in coccinelle fixes from Fengguang Wu <fengguang.wu@intel.com>.
- Roland ]

Signed-off-by: Roland Dreier <roland@purestorage.com>

authored by

Eli Cohen and committed by
Roland Dreier
e126ba97 0134f16b

+15779
+22
MAINTAINERS
··· 5365 5365 S: Odd Fixes 5366 5366 F: drivers/media/radio/radio-miropcm20* 5367 5367 5368 + Mellanox MLX5 core VPI driver 5369 + M: Eli Cohen <eli@mellanox.com> 5370 + L: netdev@vger.kernel.org 5371 + L: linux-rdma@vger.kernel.org 5372 + W: http://www.mellanox.com 5373 + Q: http://patchwork.ozlabs.org/project/netdev/list/ 5374 + Q: http://patchwork.kernel.org/project/linux-rdma/list/ 5375 + T: git://openfabrics.org/~eli/connect-ib.git 5376 + S: Supported 5377 + F: drivers/net/ethernet/mellanox/mlx5/core/ 5378 + F: include/linux/mlx5/ 5379 + 5380 + Mellanox MLX5 IB driver 5381 + M: Eli Cohen <eli@mellanox.com> 5382 + L: linux-rdma@vger.kernel.org 5383 + W: http://www.mellanox.com 5384 + Q: http://patchwork.kernel.org/project/linux-rdma/list/ 5385 + T: git://openfabrics.org/~eli/connect-ib.git 5386 + S: Supported 5387 + F: include/linux/mlx5/ 5388 + F: drivers/infiniband/hw/mlx5/ 5389 + 5368 5390 MODULE SUPPORT 5369 5391 M: Rusty Russell <rusty@rustcorp.com.au> 5370 5392 S: Maintained
+1
drivers/infiniband/Kconfig
··· 50 50 source "drivers/infiniband/hw/cxgb3/Kconfig" 51 51 source "drivers/infiniband/hw/cxgb4/Kconfig" 52 52 source "drivers/infiniband/hw/mlx4/Kconfig" 53 + source "drivers/infiniband/hw/mlx5/Kconfig" 53 54 source "drivers/infiniband/hw/nes/Kconfig" 54 55 source "drivers/infiniband/hw/ocrdma/Kconfig" 55 56
+1
drivers/infiniband/Makefile
··· 7 7 obj-$(CONFIG_INFINIBAND_CXGB3) += hw/cxgb3/ 8 8 obj-$(CONFIG_INFINIBAND_CXGB4) += hw/cxgb4/ 9 9 obj-$(CONFIG_MLX4_INFINIBAND) += hw/mlx4/ 10 + obj-$(CONFIG_MLX5_INFINIBAND) += hw/mlx5/ 10 11 obj-$(CONFIG_INFINIBAND_NES) += hw/nes/ 11 12 obj-$(CONFIG_INFINIBAND_OCRDMA) += hw/ocrdma/ 12 13 obj-$(CONFIG_INFINIBAND_IPOIB) += ulp/ipoib/
+10
drivers/infiniband/hw/mlx5/Kconfig
··· 1 + config MLX5_INFINIBAND 2 + tristate "Mellanox Connect-IB HCA support" 3 + depends on NETDEVICES && ETHERNET && PCI && X86 4 + select NET_VENDOR_MELLANOX 5 + select MLX5_CORE 6 + ---help--- 7 + This driver provides low-level InfiniBand support for 8 + Mellanox Connect-IB PCI Express host channel adapters (HCAs). 9 + This is required to use InfiniBand protocols such as 10 + IP-over-IB or SRP with these devices.
+3
drivers/infiniband/hw/mlx5/Makefile
··· 1 + obj-$(CONFIG_MLX5_INFINIBAND) += mlx5_ib.o 2 + 3 + mlx5_ib-y := main.o cq.o doorbell.o qp.o mem.o srq.o mr.o ah.o mad.o
+92
drivers/infiniband/hw/mlx5/ah.c
··· 1 + /* 2 + * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved. 3 + * 4 + * This software is available to you under a choice of one of two 5 + * licenses. You may choose to be licensed under the terms of the GNU 6 + * General Public License (GPL) Version 2, available from the file 7 + * COPYING in the main directory of this source tree, or the 8 + * OpenIB.org BSD license below: 9 + * 10 + * Redistribution and use in source and binary forms, with or 11 + * without modification, are permitted provided that the following 12 + * conditions are met: 13 + * 14 + * - Redistributions of source code must retain the above 15 + * copyright notice, this list of conditions and the following 16 + * disclaimer. 17 + * 18 + * - Redistributions in binary form must reproduce the above 19 + * copyright notice, this list of conditions and the following 20 + * disclaimer in the documentation and/or other materials 21 + * 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 OF 25 + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26 + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 27 + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 28 + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29 + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30 + * SOFTWARE. 31 + */ 32 + 33 + #include "mlx5_ib.h" 34 + 35 + struct ib_ah *create_ib_ah(struct ib_ah_attr *ah_attr, 36 + struct mlx5_ib_ah *ah) 37 + { 38 + if (ah_attr->ah_flags & IB_AH_GRH) { 39 + memcpy(ah->av.rgid, &ah_attr->grh.dgid, 16); 40 + ah->av.grh_gid_fl = cpu_to_be32(ah_attr->grh.flow_label | 41 + (1 << 30) | 42 + ah_attr->grh.sgid_index << 20); 43 + ah->av.hop_limit = ah_attr->grh.hop_limit; 44 + ah->av.tclass = ah_attr->grh.traffic_class; 45 + } 46 + 47 + ah->av.rlid = cpu_to_be16(ah_attr->dlid); 48 + ah->av.fl_mlid = ah_attr->src_path_bits & 0x7f; 49 + ah->av.stat_rate_sl = (ah_attr->static_rate << 4) | (ah_attr->sl & 0xf); 50 + 51 + return &ah->ibah; 52 + } 53 + 54 + struct ib_ah *mlx5_ib_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr) 55 + { 56 + struct mlx5_ib_ah *ah; 57 + 58 + ah = kzalloc(sizeof(*ah), GFP_ATOMIC); 59 + if (!ah) 60 + return ERR_PTR(-ENOMEM); 61 + 62 + return create_ib_ah(ah_attr, ah); /* never fails */ 63 + } 64 + 65 + int mlx5_ib_query_ah(struct ib_ah *ibah, struct ib_ah_attr *ah_attr) 66 + { 67 + struct mlx5_ib_ah *ah = to_mah(ibah); 68 + u32 tmp; 69 + 70 + memset(ah_attr, 0, sizeof(*ah_attr)); 71 + 72 + tmp = be32_to_cpu(ah->av.grh_gid_fl); 73 + if (tmp & (1 << 30)) { 74 + ah_attr->ah_flags = IB_AH_GRH; 75 + ah_attr->grh.sgid_index = (tmp >> 20) & 0xff; 76 + ah_attr->grh.flow_label = tmp & 0xfffff; 77 + memcpy(&ah_attr->grh.dgid, ah->av.rgid, 16); 78 + ah_attr->grh.hop_limit = ah->av.hop_limit; 79 + ah_attr->grh.traffic_class = ah->av.tclass; 80 + } 81 + ah_attr->dlid = be16_to_cpu(ah->av.rlid); 82 + ah_attr->static_rate = ah->av.stat_rate_sl >> 4; 83 + ah_attr->sl = ah->av.stat_rate_sl & 0xf; 84 + 85 + return 0; 86 + } 87 + 88 + int mlx5_ib_destroy_ah(struct ib_ah *ah) 89 + { 90 + kfree(to_mah(ah)); 91 + return 0; 92 + }
+843
drivers/infiniband/hw/mlx5/cq.c
··· 1 + /* 2 + * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved. 3 + * 4 + * This software is available to you under a choice of one of two 5 + * licenses. You may choose to be licensed under the terms of the GNU 6 + * General Public License (GPL) Version 2, available from the file 7 + * COPYING in the main directory of this source tree, or the 8 + * OpenIB.org BSD license below: 9 + * 10 + * Redistribution and use in source and binary forms, with or 11 + * without modification, are permitted provided that the following 12 + * conditions are met: 13 + * 14 + * - Redistributions of source code must retain the above 15 + * copyright notice, this list of conditions and the following 16 + * disclaimer. 17 + * 18 + * - Redistributions in binary form must reproduce the above 19 + * copyright notice, this list of conditions and the following 20 + * disclaimer in the documentation and/or other materials 21 + * 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 OF 25 + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26 + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 27 + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 28 + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29 + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30 + * SOFTWARE. 31 + */ 32 + 33 + #include <linux/kref.h> 34 + #include <rdma/ib_umem.h> 35 + #include "mlx5_ib.h" 36 + #include "user.h" 37 + 38 + static void mlx5_ib_cq_comp(struct mlx5_core_cq *cq) 39 + { 40 + struct ib_cq *ibcq = &to_mibcq(cq)->ibcq; 41 + 42 + ibcq->comp_handler(ibcq, ibcq->cq_context); 43 + } 44 + 45 + static void mlx5_ib_cq_event(struct mlx5_core_cq *mcq, enum mlx5_event type) 46 + { 47 + struct mlx5_ib_cq *cq = container_of(mcq, struct mlx5_ib_cq, mcq); 48 + struct mlx5_ib_dev *dev = to_mdev(cq->ibcq.device); 49 + struct ib_cq *ibcq = &cq->ibcq; 50 + struct ib_event event; 51 + 52 + if (type != MLX5_EVENT_TYPE_CQ_ERROR) { 53 + mlx5_ib_warn(dev, "Unexpected event type %d on CQ %06x\n", 54 + type, mcq->cqn); 55 + return; 56 + } 57 + 58 + if (ibcq->event_handler) { 59 + event.device = &dev->ib_dev; 60 + event.event = IB_EVENT_CQ_ERR; 61 + event.element.cq = ibcq; 62 + ibcq->event_handler(&event, ibcq->cq_context); 63 + } 64 + } 65 + 66 + static void *get_cqe_from_buf(struct mlx5_ib_cq_buf *buf, int n, int size) 67 + { 68 + return mlx5_buf_offset(&buf->buf, n * size); 69 + } 70 + 71 + static void *get_cqe(struct mlx5_ib_cq *cq, int n) 72 + { 73 + return get_cqe_from_buf(&cq->buf, n, cq->mcq.cqe_sz); 74 + } 75 + 76 + static void *get_sw_cqe(struct mlx5_ib_cq *cq, int n) 77 + { 78 + void *cqe = get_cqe(cq, n & cq->ibcq.cqe); 79 + struct mlx5_cqe64 *cqe64; 80 + 81 + cqe64 = (cq->mcq.cqe_sz == 64) ? cqe : cqe + 64; 82 + return ((cqe64->op_own & MLX5_CQE_OWNER_MASK) ^ 83 + !!(n & (cq->ibcq.cqe + 1))) ? NULL : cqe; 84 + } 85 + 86 + static void *next_cqe_sw(struct mlx5_ib_cq *cq) 87 + { 88 + return get_sw_cqe(cq, cq->mcq.cons_index); 89 + } 90 + 91 + static enum ib_wc_opcode get_umr_comp(struct mlx5_ib_wq *wq, int idx) 92 + { 93 + switch (wq->wr_data[idx]) { 94 + case MLX5_IB_WR_UMR: 95 + return 0; 96 + 97 + case IB_WR_LOCAL_INV: 98 + return IB_WC_LOCAL_INV; 99 + 100 + case IB_WR_FAST_REG_MR: 101 + return IB_WC_FAST_REG_MR; 102 + 103 + default: 104 + pr_warn("unknown completion status\n"); 105 + return 0; 106 + } 107 + } 108 + 109 + static void handle_good_req(struct ib_wc *wc, struct mlx5_cqe64 *cqe, 110 + struct mlx5_ib_wq *wq, int idx) 111 + { 112 + wc->wc_flags = 0; 113 + switch (be32_to_cpu(cqe->sop_drop_qpn) >> 24) { 114 + case MLX5_OPCODE_RDMA_WRITE_IMM: 115 + wc->wc_flags |= IB_WC_WITH_IMM; 116 + case MLX5_OPCODE_RDMA_WRITE: 117 + wc->opcode = IB_WC_RDMA_WRITE; 118 + break; 119 + case MLX5_OPCODE_SEND_IMM: 120 + wc->wc_flags |= IB_WC_WITH_IMM; 121 + case MLX5_OPCODE_SEND: 122 + case MLX5_OPCODE_SEND_INVAL: 123 + wc->opcode = IB_WC_SEND; 124 + break; 125 + case MLX5_OPCODE_RDMA_READ: 126 + wc->opcode = IB_WC_RDMA_READ; 127 + wc->byte_len = be32_to_cpu(cqe->byte_cnt); 128 + break; 129 + case MLX5_OPCODE_ATOMIC_CS: 130 + wc->opcode = IB_WC_COMP_SWAP; 131 + wc->byte_len = 8; 132 + break; 133 + case MLX5_OPCODE_ATOMIC_FA: 134 + wc->opcode = IB_WC_FETCH_ADD; 135 + wc->byte_len = 8; 136 + break; 137 + case MLX5_OPCODE_ATOMIC_MASKED_CS: 138 + wc->opcode = IB_WC_MASKED_COMP_SWAP; 139 + wc->byte_len = 8; 140 + break; 141 + case MLX5_OPCODE_ATOMIC_MASKED_FA: 142 + wc->opcode = IB_WC_MASKED_FETCH_ADD; 143 + wc->byte_len = 8; 144 + break; 145 + case MLX5_OPCODE_BIND_MW: 146 + wc->opcode = IB_WC_BIND_MW; 147 + break; 148 + case MLX5_OPCODE_UMR: 149 + wc->opcode = get_umr_comp(wq, idx); 150 + break; 151 + } 152 + } 153 + 154 + enum { 155 + MLX5_GRH_IN_BUFFER = 1, 156 + MLX5_GRH_IN_CQE = 2, 157 + }; 158 + 159 + static void handle_responder(struct ib_wc *wc, struct mlx5_cqe64 *cqe, 160 + struct mlx5_ib_qp *qp) 161 + { 162 + struct mlx5_ib_dev *dev = to_mdev(qp->ibqp.device); 163 + struct mlx5_ib_srq *srq; 164 + struct mlx5_ib_wq *wq; 165 + u16 wqe_ctr; 166 + u8 g; 167 + 168 + if (qp->ibqp.srq || qp->ibqp.xrcd) { 169 + struct mlx5_core_srq *msrq = NULL; 170 + 171 + if (qp->ibqp.xrcd) { 172 + msrq = mlx5_core_get_srq(&dev->mdev, 173 + be32_to_cpu(cqe->srqn)); 174 + srq = to_mibsrq(msrq); 175 + } else { 176 + srq = to_msrq(qp->ibqp.srq); 177 + } 178 + if (srq) { 179 + wqe_ctr = be16_to_cpu(cqe->wqe_counter); 180 + wc->wr_id = srq->wrid[wqe_ctr]; 181 + mlx5_ib_free_srq_wqe(srq, wqe_ctr); 182 + if (msrq && atomic_dec_and_test(&msrq->refcount)) 183 + complete(&msrq->free); 184 + } 185 + } else { 186 + wq = &qp->rq; 187 + wc->wr_id = wq->wrid[wq->tail & (wq->wqe_cnt - 1)]; 188 + ++wq->tail; 189 + } 190 + wc->byte_len = be32_to_cpu(cqe->byte_cnt); 191 + 192 + switch (cqe->op_own >> 4) { 193 + case MLX5_CQE_RESP_WR_IMM: 194 + wc->opcode = IB_WC_RECV_RDMA_WITH_IMM; 195 + wc->wc_flags = IB_WC_WITH_IMM; 196 + wc->ex.imm_data = cqe->imm_inval_pkey; 197 + break; 198 + case MLX5_CQE_RESP_SEND: 199 + wc->opcode = IB_WC_RECV; 200 + wc->wc_flags = 0; 201 + break; 202 + case MLX5_CQE_RESP_SEND_IMM: 203 + wc->opcode = IB_WC_RECV; 204 + wc->wc_flags = IB_WC_WITH_IMM; 205 + wc->ex.imm_data = cqe->imm_inval_pkey; 206 + break; 207 + case MLX5_CQE_RESP_SEND_INV: 208 + wc->opcode = IB_WC_RECV; 209 + wc->wc_flags = IB_WC_WITH_INVALIDATE; 210 + wc->ex.invalidate_rkey = be32_to_cpu(cqe->imm_inval_pkey); 211 + break; 212 + } 213 + wc->slid = be16_to_cpu(cqe->slid); 214 + wc->sl = (be32_to_cpu(cqe->flags_rqpn) >> 24) & 0xf; 215 + wc->src_qp = be32_to_cpu(cqe->flags_rqpn) & 0xffffff; 216 + wc->dlid_path_bits = cqe->ml_path; 217 + g = (be32_to_cpu(cqe->flags_rqpn) >> 28) & 3; 218 + wc->wc_flags |= g ? IB_WC_GRH : 0; 219 + wc->pkey_index = be32_to_cpu(cqe->imm_inval_pkey) & 0xffff; 220 + } 221 + 222 + static void dump_cqe(struct mlx5_ib_dev *dev, struct mlx5_err_cqe *cqe) 223 + { 224 + __be32 *p = (__be32 *)cqe; 225 + int i; 226 + 227 + mlx5_ib_warn(dev, "dump error cqe\n"); 228 + for (i = 0; i < sizeof(*cqe) / 16; i++, p += 4) 229 + pr_info("%08x %08x %08x %08x\n", be32_to_cpu(p[0]), 230 + be32_to_cpu(p[1]), be32_to_cpu(p[2]), 231 + be32_to_cpu(p[3])); 232 + } 233 + 234 + static void mlx5_handle_error_cqe(struct mlx5_ib_dev *dev, 235 + struct mlx5_err_cqe *cqe, 236 + struct ib_wc *wc) 237 + { 238 + int dump = 1; 239 + 240 + switch (cqe->syndrome) { 241 + case MLX5_CQE_SYNDROME_LOCAL_LENGTH_ERR: 242 + wc->status = IB_WC_LOC_LEN_ERR; 243 + break; 244 + case MLX5_CQE_SYNDROME_LOCAL_QP_OP_ERR: 245 + wc->status = IB_WC_LOC_QP_OP_ERR; 246 + break; 247 + case MLX5_CQE_SYNDROME_LOCAL_PROT_ERR: 248 + wc->status = IB_WC_LOC_PROT_ERR; 249 + break; 250 + case MLX5_CQE_SYNDROME_WR_FLUSH_ERR: 251 + dump = 0; 252 + wc->status = IB_WC_WR_FLUSH_ERR; 253 + break; 254 + case MLX5_CQE_SYNDROME_MW_BIND_ERR: 255 + wc->status = IB_WC_MW_BIND_ERR; 256 + break; 257 + case MLX5_CQE_SYNDROME_BAD_RESP_ERR: 258 + wc->status = IB_WC_BAD_RESP_ERR; 259 + break; 260 + case MLX5_CQE_SYNDROME_LOCAL_ACCESS_ERR: 261 + wc->status = IB_WC_LOC_ACCESS_ERR; 262 + break; 263 + case MLX5_CQE_SYNDROME_REMOTE_INVAL_REQ_ERR: 264 + wc->status = IB_WC_REM_INV_REQ_ERR; 265 + break; 266 + case MLX5_CQE_SYNDROME_REMOTE_ACCESS_ERR: 267 + wc->status = IB_WC_REM_ACCESS_ERR; 268 + break; 269 + case MLX5_CQE_SYNDROME_REMOTE_OP_ERR: 270 + wc->status = IB_WC_REM_OP_ERR; 271 + break; 272 + case MLX5_CQE_SYNDROME_TRANSPORT_RETRY_EXC_ERR: 273 + wc->status = IB_WC_RETRY_EXC_ERR; 274 + dump = 0; 275 + break; 276 + case MLX5_CQE_SYNDROME_RNR_RETRY_EXC_ERR: 277 + wc->status = IB_WC_RNR_RETRY_EXC_ERR; 278 + dump = 0; 279 + break; 280 + case MLX5_CQE_SYNDROME_REMOTE_ABORTED_ERR: 281 + wc->status = IB_WC_REM_ABORT_ERR; 282 + break; 283 + default: 284 + wc->status = IB_WC_GENERAL_ERR; 285 + break; 286 + } 287 + 288 + wc->vendor_err = cqe->vendor_err_synd; 289 + if (dump) 290 + dump_cqe(dev, cqe); 291 + } 292 + 293 + static int is_atomic_response(struct mlx5_ib_qp *qp, uint16_t idx) 294 + { 295 + /* TBD: waiting decision 296 + */ 297 + return 0; 298 + } 299 + 300 + static void *mlx5_get_atomic_laddr(struct mlx5_ib_qp *qp, uint16_t idx) 301 + { 302 + struct mlx5_wqe_data_seg *dpseg; 303 + void *addr; 304 + 305 + dpseg = mlx5_get_send_wqe(qp, idx) + sizeof(struct mlx5_wqe_ctrl_seg) + 306 + sizeof(struct mlx5_wqe_raddr_seg) + 307 + sizeof(struct mlx5_wqe_atomic_seg); 308 + addr = (void *)(unsigned long)be64_to_cpu(dpseg->addr); 309 + return addr; 310 + } 311 + 312 + static void handle_atomic(struct mlx5_ib_qp *qp, struct mlx5_cqe64 *cqe64, 313 + uint16_t idx) 314 + { 315 + void *addr; 316 + int byte_count; 317 + int i; 318 + 319 + if (!is_atomic_response(qp, idx)) 320 + return; 321 + 322 + byte_count = be32_to_cpu(cqe64->byte_cnt); 323 + addr = mlx5_get_atomic_laddr(qp, idx); 324 + 325 + if (byte_count == 4) { 326 + *(uint32_t *)addr = be32_to_cpu(*((__be32 *)addr)); 327 + } else { 328 + for (i = 0; i < byte_count; i += 8) { 329 + *(uint64_t *)addr = be64_to_cpu(*((__be64 *)addr)); 330 + addr += 8; 331 + } 332 + } 333 + 334 + return; 335 + } 336 + 337 + static void handle_atomics(struct mlx5_ib_qp *qp, struct mlx5_cqe64 *cqe64, 338 + u16 tail, u16 head) 339 + { 340 + int idx; 341 + 342 + do { 343 + idx = tail & (qp->sq.wqe_cnt - 1); 344 + handle_atomic(qp, cqe64, idx); 345 + if (idx == head) 346 + break; 347 + 348 + tail = qp->sq.w_list[idx].next; 349 + } while (1); 350 + tail = qp->sq.w_list[idx].next; 351 + qp->sq.last_poll = tail; 352 + } 353 + 354 + static int mlx5_poll_one(struct mlx5_ib_cq *cq, 355 + struct mlx5_ib_qp **cur_qp, 356 + struct ib_wc *wc) 357 + { 358 + struct mlx5_ib_dev *dev = to_mdev(cq->ibcq.device); 359 + struct mlx5_err_cqe *err_cqe; 360 + struct mlx5_cqe64 *cqe64; 361 + struct mlx5_core_qp *mqp; 362 + struct mlx5_ib_wq *wq; 363 + uint8_t opcode; 364 + uint32_t qpn; 365 + u16 wqe_ctr; 366 + void *cqe; 367 + int idx; 368 + 369 + cqe = next_cqe_sw(cq); 370 + if (!cqe) 371 + return -EAGAIN; 372 + 373 + cqe64 = (cq->mcq.cqe_sz == 64) ? cqe : cqe + 64; 374 + 375 + ++cq->mcq.cons_index; 376 + 377 + /* Make sure we read CQ entry contents after we've checked the 378 + * ownership bit. 379 + */ 380 + rmb(); 381 + 382 + /* TBD: resize CQ */ 383 + 384 + qpn = ntohl(cqe64->sop_drop_qpn) & 0xffffff; 385 + if (!*cur_qp || (qpn != (*cur_qp)->ibqp.qp_num)) { 386 + /* We do not have to take the QP table lock here, 387 + * because CQs will be locked while QPs are removed 388 + * from the table. 389 + */ 390 + mqp = __mlx5_qp_lookup(&dev->mdev, qpn); 391 + if (unlikely(!mqp)) { 392 + mlx5_ib_warn(dev, "CQE@CQ %06x for unknown QPN %6x\n", 393 + cq->mcq.cqn, qpn); 394 + return -EINVAL; 395 + } 396 + 397 + *cur_qp = to_mibqp(mqp); 398 + } 399 + 400 + wc->qp = &(*cur_qp)->ibqp; 401 + opcode = cqe64->op_own >> 4; 402 + switch (opcode) { 403 + case MLX5_CQE_REQ: 404 + wq = &(*cur_qp)->sq; 405 + wqe_ctr = be16_to_cpu(cqe64->wqe_counter); 406 + idx = wqe_ctr & (wq->wqe_cnt - 1); 407 + handle_good_req(wc, cqe64, wq, idx); 408 + handle_atomics(*cur_qp, cqe64, wq->last_poll, idx); 409 + wc->wr_id = wq->wrid[idx]; 410 + wq->tail = wq->wqe_head[idx] + 1; 411 + wc->status = IB_WC_SUCCESS; 412 + break; 413 + case MLX5_CQE_RESP_WR_IMM: 414 + case MLX5_CQE_RESP_SEND: 415 + case MLX5_CQE_RESP_SEND_IMM: 416 + case MLX5_CQE_RESP_SEND_INV: 417 + handle_responder(wc, cqe64, *cur_qp); 418 + wc->status = IB_WC_SUCCESS; 419 + break; 420 + case MLX5_CQE_RESIZE_CQ: 421 + break; 422 + case MLX5_CQE_REQ_ERR: 423 + case MLX5_CQE_RESP_ERR: 424 + err_cqe = (struct mlx5_err_cqe *)cqe64; 425 + mlx5_handle_error_cqe(dev, err_cqe, wc); 426 + mlx5_ib_dbg(dev, "%s error cqe on cqn 0x%x:\n", 427 + opcode == MLX5_CQE_REQ_ERR ? 428 + "Requestor" : "Responder", cq->mcq.cqn); 429 + mlx5_ib_dbg(dev, "syndrome 0x%x, vendor syndrome 0x%x\n", 430 + err_cqe->syndrome, err_cqe->vendor_err_synd); 431 + if (opcode == MLX5_CQE_REQ_ERR) { 432 + wq = &(*cur_qp)->sq; 433 + wqe_ctr = be16_to_cpu(cqe64->wqe_counter); 434 + idx = wqe_ctr & (wq->wqe_cnt - 1); 435 + wc->wr_id = wq->wrid[idx]; 436 + wq->tail = wq->wqe_head[idx] + 1; 437 + } else { 438 + struct mlx5_ib_srq *srq; 439 + 440 + if ((*cur_qp)->ibqp.srq) { 441 + srq = to_msrq((*cur_qp)->ibqp.srq); 442 + wqe_ctr = be16_to_cpu(cqe64->wqe_counter); 443 + wc->wr_id = srq->wrid[wqe_ctr]; 444 + mlx5_ib_free_srq_wqe(srq, wqe_ctr); 445 + } else { 446 + wq = &(*cur_qp)->rq; 447 + wc->wr_id = wq->wrid[wq->tail & (wq->wqe_cnt - 1)]; 448 + ++wq->tail; 449 + } 450 + } 451 + break; 452 + } 453 + 454 + return 0; 455 + } 456 + 457 + int mlx5_ib_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc) 458 + { 459 + struct mlx5_ib_cq *cq = to_mcq(ibcq); 460 + struct mlx5_ib_qp *cur_qp = NULL; 461 + unsigned long flags; 462 + int npolled; 463 + int err = 0; 464 + 465 + spin_lock_irqsave(&cq->lock, flags); 466 + 467 + for (npolled = 0; npolled < num_entries; npolled++) { 468 + err = mlx5_poll_one(cq, &cur_qp, wc + npolled); 469 + if (err) 470 + break; 471 + } 472 + 473 + if (npolled) 474 + mlx5_cq_set_ci(&cq->mcq); 475 + 476 + spin_unlock_irqrestore(&cq->lock, flags); 477 + 478 + if (err == 0 || err == -EAGAIN) 479 + return npolled; 480 + else 481 + return err; 482 + } 483 + 484 + int mlx5_ib_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags flags) 485 + { 486 + mlx5_cq_arm(&to_mcq(ibcq)->mcq, 487 + (flags & IB_CQ_SOLICITED_MASK) == IB_CQ_SOLICITED ? 488 + MLX5_CQ_DB_REQ_NOT_SOL : MLX5_CQ_DB_REQ_NOT, 489 + to_mdev(ibcq->device)->mdev.priv.uuari.uars[0].map, 490 + MLX5_GET_DOORBELL_LOCK(&to_mdev(ibcq->device)->mdev.priv.cq_uar_lock)); 491 + 492 + return 0; 493 + } 494 + 495 + static int alloc_cq_buf(struct mlx5_ib_dev *dev, struct mlx5_ib_cq_buf *buf, 496 + int nent, int cqe_size) 497 + { 498 + int err; 499 + 500 + err = mlx5_buf_alloc(&dev->mdev, nent * cqe_size, 501 + PAGE_SIZE * 2, &buf->buf); 502 + if (err) 503 + return err; 504 + 505 + buf->cqe_size = cqe_size; 506 + 507 + return 0; 508 + } 509 + 510 + static void free_cq_buf(struct mlx5_ib_dev *dev, struct mlx5_ib_cq_buf *buf) 511 + { 512 + mlx5_buf_free(&dev->mdev, &buf->buf); 513 + } 514 + 515 + static int create_cq_user(struct mlx5_ib_dev *dev, struct ib_udata *udata, 516 + struct ib_ucontext *context, struct mlx5_ib_cq *cq, 517 + int entries, struct mlx5_create_cq_mbox_in **cqb, 518 + int *cqe_size, int *index, int *inlen) 519 + { 520 + struct mlx5_ib_create_cq ucmd; 521 + int page_shift; 522 + int npages; 523 + int ncont; 524 + int err; 525 + 526 + if (ib_copy_from_udata(&ucmd, udata, sizeof(ucmd))) 527 + return -EFAULT; 528 + 529 + if (ucmd.cqe_size != 64 && ucmd.cqe_size != 128) 530 + return -EINVAL; 531 + 532 + *cqe_size = ucmd.cqe_size; 533 + 534 + cq->buf.umem = ib_umem_get(context, ucmd.buf_addr, 535 + entries * ucmd.cqe_size, 536 + IB_ACCESS_LOCAL_WRITE, 1); 537 + if (IS_ERR(cq->buf.umem)) { 538 + err = PTR_ERR(cq->buf.umem); 539 + return err; 540 + } 541 + 542 + err = mlx5_ib_db_map_user(to_mucontext(context), ucmd.db_addr, 543 + &cq->db); 544 + if (err) 545 + goto err_umem; 546 + 547 + mlx5_ib_cont_pages(cq->buf.umem, ucmd.buf_addr, &npages, &page_shift, 548 + &ncont, NULL); 549 + mlx5_ib_dbg(dev, "addr 0x%llx, size %u, npages %d, page_shift %d, ncont %d\n", 550 + ucmd.buf_addr, entries * ucmd.cqe_size, npages, page_shift, ncont); 551 + 552 + *inlen = sizeof(**cqb) + sizeof(*(*cqb)->pas) * ncont; 553 + *cqb = mlx5_vzalloc(*inlen); 554 + if (!*cqb) { 555 + err = -ENOMEM; 556 + goto err_db; 557 + } 558 + mlx5_ib_populate_pas(dev, cq->buf.umem, page_shift, (*cqb)->pas, 0); 559 + (*cqb)->ctx.log_pg_sz = page_shift - PAGE_SHIFT; 560 + 561 + *index = to_mucontext(context)->uuari.uars[0].index; 562 + 563 + return 0; 564 + 565 + err_db: 566 + mlx5_ib_db_unmap_user(to_mucontext(context), &cq->db); 567 + 568 + err_umem: 569 + ib_umem_release(cq->buf.umem); 570 + return err; 571 + } 572 + 573 + static void destroy_cq_user(struct mlx5_ib_cq *cq, struct ib_ucontext *context) 574 + { 575 + mlx5_ib_db_unmap_user(to_mucontext(context), &cq->db); 576 + ib_umem_release(cq->buf.umem); 577 + } 578 + 579 + static void init_cq_buf(struct mlx5_ib_cq *cq, int nent) 580 + { 581 + int i; 582 + void *cqe; 583 + struct mlx5_cqe64 *cqe64; 584 + 585 + for (i = 0; i < nent; i++) { 586 + cqe = get_cqe(cq, i); 587 + cqe64 = (cq->buf.cqe_size == 64) ? cqe : cqe + 64; 588 + cqe64->op_own = 0xf1; 589 + } 590 + } 591 + 592 + static int create_cq_kernel(struct mlx5_ib_dev *dev, struct mlx5_ib_cq *cq, 593 + int entries, int cqe_size, 594 + struct mlx5_create_cq_mbox_in **cqb, 595 + int *index, int *inlen) 596 + { 597 + int err; 598 + 599 + err = mlx5_db_alloc(&dev->mdev, &cq->db); 600 + if (err) 601 + return err; 602 + 603 + cq->mcq.set_ci_db = cq->db.db; 604 + cq->mcq.arm_db = cq->db.db + 1; 605 + *cq->mcq.set_ci_db = 0; 606 + *cq->mcq.arm_db = 0; 607 + cq->mcq.cqe_sz = cqe_size; 608 + 609 + err = alloc_cq_buf(dev, &cq->buf, entries, cqe_size); 610 + if (err) 611 + goto err_db; 612 + 613 + init_cq_buf(cq, entries); 614 + 615 + *inlen = sizeof(**cqb) + sizeof(*(*cqb)->pas) * cq->buf.buf.npages; 616 + *cqb = mlx5_vzalloc(*inlen); 617 + if (!*cqb) { 618 + err = -ENOMEM; 619 + goto err_buf; 620 + } 621 + mlx5_fill_page_array(&cq->buf.buf, (*cqb)->pas); 622 + 623 + (*cqb)->ctx.log_pg_sz = cq->buf.buf.page_shift - PAGE_SHIFT; 624 + *index = dev->mdev.priv.uuari.uars[0].index; 625 + 626 + return 0; 627 + 628 + err_buf: 629 + free_cq_buf(dev, &cq->buf); 630 + 631 + err_db: 632 + mlx5_db_free(&dev->mdev, &cq->db); 633 + return err; 634 + } 635 + 636 + static void destroy_cq_kernel(struct mlx5_ib_dev *dev, struct mlx5_ib_cq *cq) 637 + { 638 + free_cq_buf(dev, &cq->buf); 639 + mlx5_db_free(&dev->mdev, &cq->db); 640 + } 641 + 642 + struct ib_cq *mlx5_ib_create_cq(struct ib_device *ibdev, int entries, 643 + int vector, struct ib_ucontext *context, 644 + struct ib_udata *udata) 645 + { 646 + struct mlx5_create_cq_mbox_in *cqb = NULL; 647 + struct mlx5_ib_dev *dev = to_mdev(ibdev); 648 + struct mlx5_ib_cq *cq; 649 + int uninitialized_var(index); 650 + int uninitialized_var(inlen); 651 + int cqe_size; 652 + int irqn; 653 + int eqn; 654 + int err; 655 + 656 + entries = roundup_pow_of_two(entries + 1); 657 + if (entries < 1 || entries > dev->mdev.caps.max_cqes) 658 + return ERR_PTR(-EINVAL); 659 + 660 + cq = kzalloc(sizeof(*cq), GFP_KERNEL); 661 + if (!cq) 662 + return ERR_PTR(-ENOMEM); 663 + 664 + cq->ibcq.cqe = entries - 1; 665 + mutex_init(&cq->resize_mutex); 666 + spin_lock_init(&cq->lock); 667 + cq->resize_buf = NULL; 668 + cq->resize_umem = NULL; 669 + 670 + if (context) { 671 + err = create_cq_user(dev, udata, context, cq, entries, 672 + &cqb, &cqe_size, &index, &inlen); 673 + if (err) 674 + goto err_create; 675 + } else { 676 + /* for now choose 64 bytes till we have a proper interface */ 677 + cqe_size = 64; 678 + err = create_cq_kernel(dev, cq, entries, cqe_size, &cqb, 679 + &index, &inlen); 680 + if (err) 681 + goto err_create; 682 + } 683 + 684 + cq->cqe_size = cqe_size; 685 + cqb->ctx.cqe_sz_flags = cqe_sz_to_mlx_sz(cqe_size) << 5; 686 + cqb->ctx.log_sz_usr_page = cpu_to_be32((ilog2(entries) << 24) | index); 687 + err = mlx5_vector2eqn(dev, vector, &eqn, &irqn); 688 + if (err) 689 + goto err_cqb; 690 + 691 + cqb->ctx.c_eqn = cpu_to_be16(eqn); 692 + cqb->ctx.db_record_addr = cpu_to_be64(cq->db.dma); 693 + 694 + err = mlx5_core_create_cq(&dev->mdev, &cq->mcq, cqb, inlen); 695 + if (err) 696 + goto err_cqb; 697 + 698 + mlx5_ib_dbg(dev, "cqn 0x%x\n", cq->mcq.cqn); 699 + cq->mcq.irqn = irqn; 700 + cq->mcq.comp = mlx5_ib_cq_comp; 701 + cq->mcq.event = mlx5_ib_cq_event; 702 + 703 + if (context) 704 + if (ib_copy_to_udata(udata, &cq->mcq.cqn, sizeof(__u32))) { 705 + err = -EFAULT; 706 + goto err_cmd; 707 + } 708 + 709 + 710 + mlx5_vfree(cqb); 711 + return &cq->ibcq; 712 + 713 + err_cmd: 714 + mlx5_core_destroy_cq(&dev->mdev, &cq->mcq); 715 + 716 + err_cqb: 717 + mlx5_vfree(cqb); 718 + if (context) 719 + destroy_cq_user(cq, context); 720 + else 721 + destroy_cq_kernel(dev, cq); 722 + 723 + err_create: 724 + kfree(cq); 725 + 726 + return ERR_PTR(err); 727 + } 728 + 729 + 730 + int mlx5_ib_destroy_cq(struct ib_cq *cq) 731 + { 732 + struct mlx5_ib_dev *dev = to_mdev(cq->device); 733 + struct mlx5_ib_cq *mcq = to_mcq(cq); 734 + struct ib_ucontext *context = NULL; 735 + 736 + if (cq->uobject) 737 + context = cq->uobject->context; 738 + 739 + mlx5_core_destroy_cq(&dev->mdev, &mcq->mcq); 740 + if (context) 741 + destroy_cq_user(mcq, context); 742 + else 743 + destroy_cq_kernel(dev, mcq); 744 + 745 + kfree(mcq); 746 + 747 + return 0; 748 + } 749 + 750 + static int is_equal_rsn(struct mlx5_cqe64 *cqe64, struct mlx5_ib_srq *srq, 751 + u32 rsn) 752 + { 753 + u32 lrsn; 754 + 755 + if (srq) 756 + lrsn = be32_to_cpu(cqe64->srqn) & 0xffffff; 757 + else 758 + lrsn = be32_to_cpu(cqe64->sop_drop_qpn) & 0xffffff; 759 + 760 + return rsn == lrsn; 761 + } 762 + 763 + void __mlx5_ib_cq_clean(struct mlx5_ib_cq *cq, u32 rsn, struct mlx5_ib_srq *srq) 764 + { 765 + struct mlx5_cqe64 *cqe64, *dest64; 766 + void *cqe, *dest; 767 + u32 prod_index; 768 + int nfreed = 0; 769 + u8 owner_bit; 770 + 771 + if (!cq) 772 + return; 773 + 774 + /* First we need to find the current producer index, so we 775 + * know where to start cleaning from. It doesn't matter if HW 776 + * adds new entries after this loop -- the QP we're worried 777 + * about is already in RESET, so the new entries won't come 778 + * from our QP and therefore don't need to be checked. 779 + */ 780 + for (prod_index = cq->mcq.cons_index; get_sw_cqe(cq, prod_index); prod_index++) 781 + if (prod_index == cq->mcq.cons_index + cq->ibcq.cqe) 782 + break; 783 + 784 + /* Now sweep backwards through the CQ, removing CQ entries 785 + * that match our QP by copying older entries on top of them. 786 + */ 787 + while ((int) --prod_index - (int) cq->mcq.cons_index >= 0) { 788 + cqe = get_cqe(cq, prod_index & cq->ibcq.cqe); 789 + cqe64 = (cq->mcq.cqe_sz == 64) ? cqe : cqe + 64; 790 + if (is_equal_rsn(cqe64, srq, rsn)) { 791 + if (srq) 792 + mlx5_ib_free_srq_wqe(srq, be16_to_cpu(cqe64->wqe_counter)); 793 + ++nfreed; 794 + } else if (nfreed) { 795 + dest = get_cqe(cq, (prod_index + nfreed) & cq->ibcq.cqe); 796 + dest64 = (cq->mcq.cqe_sz == 64) ? dest : dest + 64; 797 + owner_bit = dest64->op_own & MLX5_CQE_OWNER_MASK; 798 + memcpy(dest, cqe, cq->mcq.cqe_sz); 799 + dest64->op_own = owner_bit | 800 + (dest64->op_own & ~MLX5_CQE_OWNER_MASK); 801 + } 802 + } 803 + 804 + if (nfreed) { 805 + cq->mcq.cons_index += nfreed; 806 + /* Make sure update of buffer contents is done before 807 + * updating consumer index. 808 + */ 809 + wmb(); 810 + mlx5_cq_set_ci(&cq->mcq); 811 + } 812 + } 813 + 814 + void mlx5_ib_cq_clean(struct mlx5_ib_cq *cq, u32 qpn, struct mlx5_ib_srq *srq) 815 + { 816 + if (!cq) 817 + return; 818 + 819 + spin_lock_irq(&cq->lock); 820 + __mlx5_ib_cq_clean(cq, qpn, srq); 821 + spin_unlock_irq(&cq->lock); 822 + } 823 + 824 + int mlx5_ib_modify_cq(struct ib_cq *cq, u16 cq_count, u16 cq_period) 825 + { 826 + return -ENOSYS; 827 + } 828 + 829 + int mlx5_ib_resize_cq(struct ib_cq *ibcq, int entries, struct ib_udata *udata) 830 + { 831 + return -ENOSYS; 832 + } 833 + 834 + int mlx5_ib_get_cqe_size(struct mlx5_ib_dev *dev, struct ib_cq *ibcq) 835 + { 836 + struct mlx5_ib_cq *cq; 837 + 838 + if (!ibcq) 839 + return 128; 840 + 841 + cq = to_mcq(ibcq); 842 + return cq->cqe_size; 843 + }
+100
drivers/infiniband/hw/mlx5/doorbell.c
··· 1 + /* 2 + * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved. 3 + * 4 + * This software is available to you under a choice of one of two 5 + * licenses. You may choose to be licensed under the terms of the GNU 6 + * General Public License (GPL) Version 2, available from the file 7 + * COPYING in the main directory of this source tree, or the 8 + * OpenIB.org BSD license below: 9 + * 10 + * Redistribution and use in source and binary forms, with or 11 + * without modification, are permitted provided that the following 12 + * conditions are met: 13 + * 14 + * - Redistributions of source code must retain the above 15 + * copyright notice, this list of conditions and the following 16 + * disclaimer. 17 + * 18 + * - Redistributions in binary form must reproduce the above 19 + * copyright notice, this list of conditions and the following 20 + * disclaimer in the documentation and/or other materials 21 + * 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 OF 25 + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26 + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 27 + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 28 + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29 + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30 + * SOFTWARE. 31 + */ 32 + 33 + #include <linux/kref.h> 34 + #include <linux/slab.h> 35 + #include <rdma/ib_umem.h> 36 + 37 + #include "mlx5_ib.h" 38 + 39 + struct mlx5_ib_user_db_page { 40 + struct list_head list; 41 + struct ib_umem *umem; 42 + unsigned long user_virt; 43 + int refcnt; 44 + }; 45 + 46 + int mlx5_ib_db_map_user(struct mlx5_ib_ucontext *context, unsigned long virt, 47 + struct mlx5_db *db) 48 + { 49 + struct mlx5_ib_user_db_page *page; 50 + struct ib_umem_chunk *chunk; 51 + int err = 0; 52 + 53 + mutex_lock(&context->db_page_mutex); 54 + 55 + list_for_each_entry(page, &context->db_page_list, list) 56 + if (page->user_virt == (virt & PAGE_MASK)) 57 + goto found; 58 + 59 + page = kmalloc(sizeof(*page), GFP_KERNEL); 60 + if (!page) { 61 + err = -ENOMEM; 62 + goto out; 63 + } 64 + 65 + page->user_virt = (virt & PAGE_MASK); 66 + page->refcnt = 0; 67 + page->umem = ib_umem_get(&context->ibucontext, virt & PAGE_MASK, 68 + PAGE_SIZE, 0, 0); 69 + if (IS_ERR(page->umem)) { 70 + err = PTR_ERR(page->umem); 71 + kfree(page); 72 + goto out; 73 + } 74 + 75 + list_add(&page->list, &context->db_page_list); 76 + 77 + found: 78 + chunk = list_entry(page->umem->chunk_list.next, struct ib_umem_chunk, list); 79 + db->dma = sg_dma_address(chunk->page_list) + (virt & ~PAGE_MASK); 80 + db->u.user_page = page; 81 + ++page->refcnt; 82 + 83 + out: 84 + mutex_unlock(&context->db_page_mutex); 85 + 86 + return err; 87 + } 88 + 89 + void mlx5_ib_db_unmap_user(struct mlx5_ib_ucontext *context, struct mlx5_db *db) 90 + { 91 + mutex_lock(&context->db_page_mutex); 92 + 93 + if (!--db->u.user_page->refcnt) { 94 + list_del(&db->u.user_page->list); 95 + ib_umem_release(db->u.user_page->umem); 96 + kfree(db->u.user_page); 97 + } 98 + 99 + mutex_unlock(&context->db_page_mutex); 100 + }
+139
drivers/infiniband/hw/mlx5/mad.c
··· 1 + /* 2 + * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved. 3 + * 4 + * This software is available to you under a choice of one of two 5 + * licenses. You may choose to be licensed under the terms of the GNU 6 + * General Public License (GPL) Version 2, available from the file 7 + * COPYING in the main directory of this source tree, or the 8 + * OpenIB.org BSD license below: 9 + * 10 + * Redistribution and use in source and binary forms, with or 11 + * without modification, are permitted provided that the following 12 + * conditions are met: 13 + * 14 + * - Redistributions of source code must retain the above 15 + * copyright notice, this list of conditions and the following 16 + * disclaimer. 17 + * 18 + * - Redistributions in binary form must reproduce the above 19 + * copyright notice, this list of conditions and the following 20 + * disclaimer in the documentation and/or other materials 21 + * 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 OF 25 + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26 + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 27 + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 28 + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29 + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30 + * SOFTWARE. 31 + */ 32 + 33 + #include <linux/mlx5/cmd.h> 34 + #include <rdma/ib_mad.h> 35 + #include <rdma/ib_smi.h> 36 + #include "mlx5_ib.h" 37 + 38 + enum { 39 + MLX5_IB_VENDOR_CLASS1 = 0x9, 40 + MLX5_IB_VENDOR_CLASS2 = 0xa 41 + }; 42 + 43 + int mlx5_MAD_IFC(struct mlx5_ib_dev *dev, int ignore_mkey, int ignore_bkey, 44 + int port, struct ib_wc *in_wc, struct ib_grh *in_grh, 45 + void *in_mad, void *response_mad) 46 + { 47 + u8 op_modifier = 0; 48 + 49 + /* Key check traps can't be generated unless we have in_wc to 50 + * tell us where to send the trap. 51 + */ 52 + if (ignore_mkey || !in_wc) 53 + op_modifier |= 0x1; 54 + if (ignore_bkey || !in_wc) 55 + op_modifier |= 0x2; 56 + 57 + return mlx5_core_mad_ifc(&dev->mdev, in_mad, response_mad, op_modifier, port); 58 + } 59 + 60 + int mlx5_ib_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num, 61 + struct ib_wc *in_wc, struct ib_grh *in_grh, 62 + struct ib_mad *in_mad, struct ib_mad *out_mad) 63 + { 64 + u16 slid; 65 + int err; 66 + 67 + slid = in_wc ? in_wc->slid : be16_to_cpu(IB_LID_PERMISSIVE); 68 + 69 + if (in_mad->mad_hdr.method == IB_MGMT_METHOD_TRAP && slid == 0) 70 + return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_CONSUMED; 71 + 72 + if (in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED || 73 + in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) { 74 + if (in_mad->mad_hdr.method != IB_MGMT_METHOD_GET && 75 + in_mad->mad_hdr.method != IB_MGMT_METHOD_SET && 76 + in_mad->mad_hdr.method != IB_MGMT_METHOD_TRAP_REPRESS) 77 + return IB_MAD_RESULT_SUCCESS; 78 + 79 + /* Don't process SMInfo queries -- the SMA can't handle them. 80 + */ 81 + if (in_mad->mad_hdr.attr_id == IB_SMP_ATTR_SM_INFO) 82 + return IB_MAD_RESULT_SUCCESS; 83 + } else if (in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_PERF_MGMT || 84 + in_mad->mad_hdr.mgmt_class == MLX5_IB_VENDOR_CLASS1 || 85 + in_mad->mad_hdr.mgmt_class == MLX5_IB_VENDOR_CLASS2 || 86 + in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_CONG_MGMT) { 87 + if (in_mad->mad_hdr.method != IB_MGMT_METHOD_GET && 88 + in_mad->mad_hdr.method != IB_MGMT_METHOD_SET) 89 + return IB_MAD_RESULT_SUCCESS; 90 + } else { 91 + return IB_MAD_RESULT_SUCCESS; 92 + } 93 + 94 + err = mlx5_MAD_IFC(to_mdev(ibdev), 95 + mad_flags & IB_MAD_IGNORE_MKEY, 96 + mad_flags & IB_MAD_IGNORE_BKEY, 97 + port_num, in_wc, in_grh, in_mad, out_mad); 98 + if (err) 99 + return IB_MAD_RESULT_FAILURE; 100 + 101 + /* set return bit in status of directed route responses */ 102 + if (in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) 103 + out_mad->mad_hdr.status |= cpu_to_be16(1 << 15); 104 + 105 + if (in_mad->mad_hdr.method == IB_MGMT_METHOD_TRAP_REPRESS) 106 + /* no response for trap repress */ 107 + return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_CONSUMED; 108 + 109 + return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_REPLY; 110 + } 111 + 112 + int mlx5_query_ext_port_caps(struct mlx5_ib_dev *dev, u8 port) 113 + { 114 + struct ib_smp *in_mad = NULL; 115 + struct ib_smp *out_mad = NULL; 116 + int err = -ENOMEM; 117 + u16 packet_error; 118 + 119 + in_mad = kzalloc(sizeof(*in_mad), GFP_KERNEL); 120 + out_mad = kmalloc(sizeof(*out_mad), GFP_KERNEL); 121 + if (!in_mad || !out_mad) 122 + goto out; 123 + 124 + init_query_mad(in_mad); 125 + in_mad->attr_id = MLX5_ATTR_EXTENDED_PORT_INFO; 126 + in_mad->attr_mod = cpu_to_be32(port); 127 + 128 + err = mlx5_MAD_IFC(dev, 1, 1, 1, NULL, NULL, in_mad, out_mad); 129 + 130 + packet_error = be16_to_cpu(out_mad->status); 131 + 132 + dev->mdev.caps.ext_port_cap[port - 1] = (!err && !packet_error) ? 133 + MLX_EXT_PORT_CAP_FLAG_EXTENDED_PORT_INFO : 0; 134 + 135 + out: 136 + kfree(in_mad); 137 + kfree(out_mad); 138 + return err; 139 + }
+1504
drivers/infiniband/hw/mlx5/main.c
··· 1 + /* 2 + * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved. 3 + * 4 + * This software is available to you under a choice of one of two 5 + * licenses. You may choose to be licensed under the terms of the GNU 6 + * General Public License (GPL) Version 2, available from the file 7 + * COPYING in the main directory of this source tree, or the 8 + * OpenIB.org BSD license below: 9 + * 10 + * Redistribution and use in source and binary forms, with or 11 + * without modification, are permitted provided that the following 12 + * conditions are met: 13 + * 14 + * - Redistributions of source code must retain the above 15 + * copyright notice, this list of conditions and the following 16 + * disclaimer. 17 + * 18 + * - Redistributions in binary form must reproduce the above 19 + * copyright notice, this list of conditions and the following 20 + * disclaimer in the documentation and/or other materials 21 + * 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 OF 25 + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26 + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 27 + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 28 + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29 + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30 + * SOFTWARE. 31 + */ 32 + 33 + #include <asm-generic/kmap_types.h> 34 + #include <linux/module.h> 35 + #include <linux/init.h> 36 + #include <linux/errno.h> 37 + #include <linux/pci.h> 38 + #include <linux/dma-mapping.h> 39 + #include <linux/slab.h> 40 + #include <linux/io-mapping.h> 41 + #include <linux/sched.h> 42 + #include <rdma/ib_user_verbs.h> 43 + #include <rdma/ib_smi.h> 44 + #include <rdma/ib_umem.h> 45 + #include "user.h" 46 + #include "mlx5_ib.h" 47 + 48 + #define DRIVER_NAME "mlx5_ib" 49 + #define DRIVER_VERSION "1.0" 50 + #define DRIVER_RELDATE "June 2013" 51 + 52 + MODULE_AUTHOR("Eli Cohen <eli@mellanox.com>"); 53 + MODULE_DESCRIPTION("Mellanox Connect-IB HCA IB driver"); 54 + MODULE_LICENSE("Dual BSD/GPL"); 55 + MODULE_VERSION(DRIVER_VERSION); 56 + 57 + static int prof_sel = 2; 58 + module_param_named(prof_sel, prof_sel, int, 0444); 59 + MODULE_PARM_DESC(prof_sel, "profile selector. Valid range 0 - 2"); 60 + 61 + static char mlx5_version[] = 62 + DRIVER_NAME ": Mellanox Connect-IB Infiniband driver v" 63 + DRIVER_VERSION " (" DRIVER_RELDATE ")\n"; 64 + 65 + struct mlx5_profile profile[] = { 66 + [0] = { 67 + .mask = 0, 68 + }, 69 + [1] = { 70 + .mask = MLX5_PROF_MASK_QP_SIZE, 71 + .log_max_qp = 12, 72 + }, 73 + [2] = { 74 + .mask = MLX5_PROF_MASK_QP_SIZE | 75 + MLX5_PROF_MASK_MR_CACHE, 76 + .log_max_qp = 17, 77 + .mr_cache[0] = { 78 + .size = 500, 79 + .limit = 250 80 + }, 81 + .mr_cache[1] = { 82 + .size = 500, 83 + .limit = 250 84 + }, 85 + .mr_cache[2] = { 86 + .size = 500, 87 + .limit = 250 88 + }, 89 + .mr_cache[3] = { 90 + .size = 500, 91 + .limit = 250 92 + }, 93 + .mr_cache[4] = { 94 + .size = 500, 95 + .limit = 250 96 + }, 97 + .mr_cache[5] = { 98 + .size = 500, 99 + .limit = 250 100 + }, 101 + .mr_cache[6] = { 102 + .size = 500, 103 + .limit = 250 104 + }, 105 + .mr_cache[7] = { 106 + .size = 500, 107 + .limit = 250 108 + }, 109 + .mr_cache[8] = { 110 + .size = 500, 111 + .limit = 250 112 + }, 113 + .mr_cache[9] = { 114 + .size = 500, 115 + .limit = 250 116 + }, 117 + .mr_cache[10] = { 118 + .size = 500, 119 + .limit = 250 120 + }, 121 + .mr_cache[11] = { 122 + .size = 500, 123 + .limit = 250 124 + }, 125 + .mr_cache[12] = { 126 + .size = 64, 127 + .limit = 32 128 + }, 129 + .mr_cache[13] = { 130 + .size = 32, 131 + .limit = 16 132 + }, 133 + .mr_cache[14] = { 134 + .size = 16, 135 + .limit = 8 136 + }, 137 + .mr_cache[15] = { 138 + .size = 8, 139 + .limit = 4 140 + }, 141 + }, 142 + }; 143 + 144 + int mlx5_vector2eqn(struct mlx5_ib_dev *dev, int vector, int *eqn, int *irqn) 145 + { 146 + struct mlx5_eq_table *table = &dev->mdev.priv.eq_table; 147 + struct mlx5_eq *eq, *n; 148 + int err = -ENOENT; 149 + 150 + spin_lock(&table->lock); 151 + list_for_each_entry_safe(eq, n, &dev->eqs_list, list) { 152 + if (eq->index == vector) { 153 + *eqn = eq->eqn; 154 + *irqn = eq->irqn; 155 + err = 0; 156 + break; 157 + } 158 + } 159 + spin_unlock(&table->lock); 160 + 161 + return err; 162 + } 163 + 164 + static int alloc_comp_eqs(struct mlx5_ib_dev *dev) 165 + { 166 + struct mlx5_eq_table *table = &dev->mdev.priv.eq_table; 167 + struct mlx5_eq *eq, *n; 168 + int ncomp_vec; 169 + int nent; 170 + int err; 171 + int i; 172 + 173 + INIT_LIST_HEAD(&dev->eqs_list); 174 + ncomp_vec = table->num_comp_vectors; 175 + nent = MLX5_COMP_EQ_SIZE; 176 + for (i = 0; i < ncomp_vec; i++) { 177 + eq = kzalloc(sizeof(*eq), GFP_KERNEL); 178 + if (!eq) { 179 + err = -ENOMEM; 180 + goto clean; 181 + } 182 + 183 + snprintf(eq->name, MLX5_MAX_EQ_NAME, "mlx5_comp%d", i); 184 + err = mlx5_create_map_eq(&dev->mdev, eq, 185 + i + MLX5_EQ_VEC_COMP_BASE, nent, 0, 186 + eq->name, 187 + &dev->mdev.priv.uuari.uars[0]); 188 + if (err) { 189 + kfree(eq); 190 + goto clean; 191 + } 192 + mlx5_ib_dbg(dev, "allocated completion EQN %d\n", eq->eqn); 193 + eq->index = i; 194 + spin_lock(&table->lock); 195 + list_add_tail(&eq->list, &dev->eqs_list); 196 + spin_unlock(&table->lock); 197 + } 198 + 199 + dev->num_comp_vectors = ncomp_vec; 200 + return 0; 201 + 202 + clean: 203 + spin_lock(&table->lock); 204 + list_for_each_entry_safe(eq, n, &dev->eqs_list, list) { 205 + list_del(&eq->list); 206 + spin_unlock(&table->lock); 207 + if (mlx5_destroy_unmap_eq(&dev->mdev, eq)) 208 + mlx5_ib_warn(dev, "failed to destroy EQ 0x%x\n", eq->eqn); 209 + kfree(eq); 210 + spin_lock(&table->lock); 211 + } 212 + spin_unlock(&table->lock); 213 + return err; 214 + } 215 + 216 + static void free_comp_eqs(struct mlx5_ib_dev *dev) 217 + { 218 + struct mlx5_eq_table *table = &dev->mdev.priv.eq_table; 219 + struct mlx5_eq *eq, *n; 220 + 221 + spin_lock(&table->lock); 222 + list_for_each_entry_safe(eq, n, &dev->eqs_list, list) { 223 + list_del(&eq->list); 224 + spin_unlock(&table->lock); 225 + if (mlx5_destroy_unmap_eq(&dev->mdev, eq)) 226 + mlx5_ib_warn(dev, "failed to destroy EQ 0x%x\n", eq->eqn); 227 + kfree(eq); 228 + spin_lock(&table->lock); 229 + } 230 + spin_unlock(&table->lock); 231 + } 232 + 233 + static int mlx5_ib_query_device(struct ib_device *ibdev, 234 + struct ib_device_attr *props) 235 + { 236 + struct mlx5_ib_dev *dev = to_mdev(ibdev); 237 + struct ib_smp *in_mad = NULL; 238 + struct ib_smp *out_mad = NULL; 239 + int err = -ENOMEM; 240 + int max_rq_sg; 241 + int max_sq_sg; 242 + u64 flags; 243 + 244 + in_mad = kzalloc(sizeof(*in_mad), GFP_KERNEL); 245 + out_mad = kmalloc(sizeof(*out_mad), GFP_KERNEL); 246 + if (!in_mad || !out_mad) 247 + goto out; 248 + 249 + init_query_mad(in_mad); 250 + in_mad->attr_id = IB_SMP_ATTR_NODE_INFO; 251 + 252 + err = mlx5_MAD_IFC(to_mdev(ibdev), 1, 1, 1, NULL, NULL, in_mad, out_mad); 253 + if (err) 254 + goto out; 255 + 256 + memset(props, 0, sizeof(*props)); 257 + 258 + props->fw_ver = ((u64)fw_rev_maj(&dev->mdev) << 32) | 259 + (fw_rev_min(&dev->mdev) << 16) | 260 + fw_rev_sub(&dev->mdev); 261 + props->device_cap_flags = IB_DEVICE_CHANGE_PHY_PORT | 262 + IB_DEVICE_PORT_ACTIVE_EVENT | 263 + IB_DEVICE_SYS_IMAGE_GUID | 264 + IB_DEVICE_RC_RNR_NAK_GEN | 265 + IB_DEVICE_BLOCK_MULTICAST_LOOPBACK; 266 + flags = dev->mdev.caps.flags; 267 + if (flags & MLX5_DEV_CAP_FLAG_BAD_PKEY_CNTR) 268 + props->device_cap_flags |= IB_DEVICE_BAD_PKEY_CNTR; 269 + if (flags & MLX5_DEV_CAP_FLAG_BAD_QKEY_CNTR) 270 + props->device_cap_flags |= IB_DEVICE_BAD_QKEY_CNTR; 271 + if (flags & MLX5_DEV_CAP_FLAG_APM) 272 + props->device_cap_flags |= IB_DEVICE_AUTO_PATH_MIG; 273 + props->device_cap_flags |= IB_DEVICE_LOCAL_DMA_LKEY; 274 + if (flags & MLX5_DEV_CAP_FLAG_XRC) 275 + props->device_cap_flags |= IB_DEVICE_XRC; 276 + props->device_cap_flags |= IB_DEVICE_MEM_MGT_EXTENSIONS; 277 + 278 + props->vendor_id = be32_to_cpup((__be32 *)(out_mad->data + 36)) & 279 + 0xffffff; 280 + props->vendor_part_id = be16_to_cpup((__be16 *)(out_mad->data + 30)); 281 + props->hw_ver = be32_to_cpup((__be32 *)(out_mad->data + 32)); 282 + memcpy(&props->sys_image_guid, out_mad->data + 4, 8); 283 + 284 + props->max_mr_size = ~0ull; 285 + props->page_size_cap = dev->mdev.caps.min_page_sz; 286 + props->max_qp = 1 << dev->mdev.caps.log_max_qp; 287 + props->max_qp_wr = dev->mdev.caps.max_wqes; 288 + max_rq_sg = dev->mdev.caps.max_rq_desc_sz / sizeof(struct mlx5_wqe_data_seg); 289 + max_sq_sg = (dev->mdev.caps.max_sq_desc_sz - sizeof(struct mlx5_wqe_ctrl_seg)) / 290 + sizeof(struct mlx5_wqe_data_seg); 291 + props->max_sge = min(max_rq_sg, max_sq_sg); 292 + props->max_cq = 1 << dev->mdev.caps.log_max_cq; 293 + props->max_cqe = dev->mdev.caps.max_cqes - 1; 294 + props->max_mr = 1 << dev->mdev.caps.log_max_mkey; 295 + props->max_pd = 1 << dev->mdev.caps.log_max_pd; 296 + props->max_qp_rd_atom = dev->mdev.caps.max_ra_req_qp; 297 + props->max_qp_init_rd_atom = dev->mdev.caps.max_ra_res_qp; 298 + props->max_res_rd_atom = props->max_qp_rd_atom * props->max_qp; 299 + props->max_srq = 1 << dev->mdev.caps.log_max_srq; 300 + props->max_srq_wr = dev->mdev.caps.max_srq_wqes - 1; 301 + props->max_srq_sge = max_rq_sg - 1; 302 + props->max_fast_reg_page_list_len = (unsigned int)-1; 303 + props->local_ca_ack_delay = dev->mdev.caps.local_ca_ack_delay; 304 + props->atomic_cap = dev->mdev.caps.flags & MLX5_DEV_CAP_FLAG_ATOMIC ? 305 + IB_ATOMIC_HCA : IB_ATOMIC_NONE; 306 + props->masked_atomic_cap = IB_ATOMIC_HCA; 307 + props->max_pkeys = be16_to_cpup((__be16 *)(out_mad->data + 28)); 308 + props->max_mcast_grp = 1 << dev->mdev.caps.log_max_mcg; 309 + props->max_mcast_qp_attach = dev->mdev.caps.max_qp_mcg; 310 + props->max_total_mcast_qp_attach = props->max_mcast_qp_attach * 311 + props->max_mcast_grp; 312 + props->max_map_per_fmr = INT_MAX; /* no limit in ConnectIB */ 313 + 314 + out: 315 + kfree(in_mad); 316 + kfree(out_mad); 317 + 318 + return err; 319 + } 320 + 321 + int mlx5_ib_query_port(struct ib_device *ibdev, u8 port, 322 + struct ib_port_attr *props) 323 + { 324 + struct mlx5_ib_dev *dev = to_mdev(ibdev); 325 + struct ib_smp *in_mad = NULL; 326 + struct ib_smp *out_mad = NULL; 327 + int ext_active_speed; 328 + int err = -ENOMEM; 329 + 330 + if (port < 1 || port > dev->mdev.caps.num_ports) { 331 + mlx5_ib_warn(dev, "invalid port number %d\n", port); 332 + return -EINVAL; 333 + } 334 + 335 + in_mad = kzalloc(sizeof(*in_mad), GFP_KERNEL); 336 + out_mad = kmalloc(sizeof(*out_mad), GFP_KERNEL); 337 + if (!in_mad || !out_mad) 338 + goto out; 339 + 340 + memset(props, 0, sizeof(*props)); 341 + 342 + init_query_mad(in_mad); 343 + in_mad->attr_id = IB_SMP_ATTR_PORT_INFO; 344 + in_mad->attr_mod = cpu_to_be32(port); 345 + 346 + err = mlx5_MAD_IFC(dev, 1, 1, port, NULL, NULL, in_mad, out_mad); 347 + if (err) { 348 + mlx5_ib_warn(dev, "err %d\n", err); 349 + goto out; 350 + } 351 + 352 + 353 + props->lid = be16_to_cpup((__be16 *)(out_mad->data + 16)); 354 + props->lmc = out_mad->data[34] & 0x7; 355 + props->sm_lid = be16_to_cpup((__be16 *)(out_mad->data + 18)); 356 + props->sm_sl = out_mad->data[36] & 0xf; 357 + props->state = out_mad->data[32] & 0xf; 358 + props->phys_state = out_mad->data[33] >> 4; 359 + props->port_cap_flags = be32_to_cpup((__be32 *)(out_mad->data + 20)); 360 + props->gid_tbl_len = out_mad->data[50]; 361 + props->max_msg_sz = 1 << to_mdev(ibdev)->mdev.caps.log_max_msg; 362 + props->pkey_tbl_len = to_mdev(ibdev)->mdev.caps.port[port - 1].pkey_table_len; 363 + props->bad_pkey_cntr = be16_to_cpup((__be16 *)(out_mad->data + 46)); 364 + props->qkey_viol_cntr = be16_to_cpup((__be16 *)(out_mad->data + 48)); 365 + props->active_width = out_mad->data[31] & 0xf; 366 + props->active_speed = out_mad->data[35] >> 4; 367 + props->max_mtu = out_mad->data[41] & 0xf; 368 + props->active_mtu = out_mad->data[36] >> 4; 369 + props->subnet_timeout = out_mad->data[51] & 0x1f; 370 + props->max_vl_num = out_mad->data[37] >> 4; 371 + props->init_type_reply = out_mad->data[41] >> 4; 372 + 373 + /* Check if extended speeds (EDR/FDR/...) are supported */ 374 + if (props->port_cap_flags & IB_PORT_EXTENDED_SPEEDS_SUP) { 375 + ext_active_speed = out_mad->data[62] >> 4; 376 + 377 + switch (ext_active_speed) { 378 + case 1: 379 + props->active_speed = 16; /* FDR */ 380 + break; 381 + case 2: 382 + props->active_speed = 32; /* EDR */ 383 + break; 384 + } 385 + } 386 + 387 + /* If reported active speed is QDR, check if is FDR-10 */ 388 + if (props->active_speed == 4) { 389 + if (dev->mdev.caps.ext_port_cap[port - 1] & 390 + MLX_EXT_PORT_CAP_FLAG_EXTENDED_PORT_INFO) { 391 + init_query_mad(in_mad); 392 + in_mad->attr_id = MLX5_ATTR_EXTENDED_PORT_INFO; 393 + in_mad->attr_mod = cpu_to_be32(port); 394 + 395 + err = mlx5_MAD_IFC(dev, 1, 1, port, 396 + NULL, NULL, in_mad, out_mad); 397 + if (err) 398 + goto out; 399 + 400 + /* Checking LinkSpeedActive for FDR-10 */ 401 + if (out_mad->data[15] & 0x1) 402 + props->active_speed = 8; 403 + } 404 + } 405 + 406 + out: 407 + kfree(in_mad); 408 + kfree(out_mad); 409 + 410 + return err; 411 + } 412 + 413 + static int mlx5_ib_query_gid(struct ib_device *ibdev, u8 port, int index, 414 + union ib_gid *gid) 415 + { 416 + struct ib_smp *in_mad = NULL; 417 + struct ib_smp *out_mad = NULL; 418 + int err = -ENOMEM; 419 + 420 + in_mad = kzalloc(sizeof(*in_mad), GFP_KERNEL); 421 + out_mad = kmalloc(sizeof(*out_mad), GFP_KERNEL); 422 + if (!in_mad || !out_mad) 423 + goto out; 424 + 425 + init_query_mad(in_mad); 426 + in_mad->attr_id = IB_SMP_ATTR_PORT_INFO; 427 + in_mad->attr_mod = cpu_to_be32(port); 428 + 429 + err = mlx5_MAD_IFC(to_mdev(ibdev), 1, 1, port, NULL, NULL, in_mad, out_mad); 430 + if (err) 431 + goto out; 432 + 433 + memcpy(gid->raw, out_mad->data + 8, 8); 434 + 435 + init_query_mad(in_mad); 436 + in_mad->attr_id = IB_SMP_ATTR_GUID_INFO; 437 + in_mad->attr_mod = cpu_to_be32(index / 8); 438 + 439 + err = mlx5_MAD_IFC(to_mdev(ibdev), 1, 1, port, NULL, NULL, in_mad, out_mad); 440 + if (err) 441 + goto out; 442 + 443 + memcpy(gid->raw + 8, out_mad->data + (index % 8) * 8, 8); 444 + 445 + out: 446 + kfree(in_mad); 447 + kfree(out_mad); 448 + return err; 449 + } 450 + 451 + static int mlx5_ib_query_pkey(struct ib_device *ibdev, u8 port, u16 index, 452 + u16 *pkey) 453 + { 454 + struct ib_smp *in_mad = NULL; 455 + struct ib_smp *out_mad = NULL; 456 + int err = -ENOMEM; 457 + 458 + in_mad = kzalloc(sizeof(*in_mad), GFP_KERNEL); 459 + out_mad = kmalloc(sizeof(*out_mad), GFP_KERNEL); 460 + if (!in_mad || !out_mad) 461 + goto out; 462 + 463 + init_query_mad(in_mad); 464 + in_mad->attr_id = IB_SMP_ATTR_PKEY_TABLE; 465 + in_mad->attr_mod = cpu_to_be32(index / 32); 466 + 467 + err = mlx5_MAD_IFC(to_mdev(ibdev), 1, 1, port, NULL, NULL, in_mad, out_mad); 468 + if (err) 469 + goto out; 470 + 471 + *pkey = be16_to_cpu(((__be16 *)out_mad->data)[index % 32]); 472 + 473 + out: 474 + kfree(in_mad); 475 + kfree(out_mad); 476 + return err; 477 + } 478 + 479 + struct mlx5_reg_node_desc { 480 + u8 desc[64]; 481 + }; 482 + 483 + static int mlx5_ib_modify_device(struct ib_device *ibdev, int mask, 484 + struct ib_device_modify *props) 485 + { 486 + struct mlx5_ib_dev *dev = to_mdev(ibdev); 487 + struct mlx5_reg_node_desc in; 488 + struct mlx5_reg_node_desc out; 489 + int err; 490 + 491 + if (mask & ~IB_DEVICE_MODIFY_NODE_DESC) 492 + return -EOPNOTSUPP; 493 + 494 + if (!(mask & IB_DEVICE_MODIFY_NODE_DESC)) 495 + return 0; 496 + 497 + /* 498 + * If possible, pass node desc to FW, so it can generate 499 + * a 144 trap. If cmd fails, just ignore. 500 + */ 501 + memcpy(&in, props->node_desc, 64); 502 + err = mlx5_core_access_reg(&dev->mdev, &in, sizeof(in), &out, 503 + sizeof(out), MLX5_REG_NODE_DESC, 0, 1); 504 + if (err) 505 + return err; 506 + 507 + memcpy(ibdev->node_desc, props->node_desc, 64); 508 + 509 + return err; 510 + } 511 + 512 + static int mlx5_ib_modify_port(struct ib_device *ibdev, u8 port, int mask, 513 + struct ib_port_modify *props) 514 + { 515 + struct mlx5_ib_dev *dev = to_mdev(ibdev); 516 + struct ib_port_attr attr; 517 + u32 tmp; 518 + int err; 519 + 520 + mutex_lock(&dev->cap_mask_mutex); 521 + 522 + err = mlx5_ib_query_port(ibdev, port, &attr); 523 + if (err) 524 + goto out; 525 + 526 + tmp = (attr.port_cap_flags | props->set_port_cap_mask) & 527 + ~props->clr_port_cap_mask; 528 + 529 + err = mlx5_set_port_caps(&dev->mdev, port, tmp); 530 + 531 + out: 532 + mutex_unlock(&dev->cap_mask_mutex); 533 + return err; 534 + } 535 + 536 + static struct ib_ucontext *mlx5_ib_alloc_ucontext(struct ib_device *ibdev, 537 + struct ib_udata *udata) 538 + { 539 + struct mlx5_ib_dev *dev = to_mdev(ibdev); 540 + struct mlx5_ib_alloc_ucontext_req req; 541 + struct mlx5_ib_alloc_ucontext_resp resp; 542 + struct mlx5_ib_ucontext *context; 543 + struct mlx5_uuar_info *uuari; 544 + struct mlx5_uar *uars; 545 + int num_uars; 546 + int uuarn; 547 + int err; 548 + int i; 549 + 550 + if (!dev->ib_active) 551 + return ERR_PTR(-EAGAIN); 552 + 553 + err = ib_copy_from_udata(&req, udata, sizeof(req)); 554 + if (err) 555 + return ERR_PTR(err); 556 + 557 + if (req.total_num_uuars > MLX5_MAX_UUARS) 558 + return ERR_PTR(-ENOMEM); 559 + 560 + if (req.total_num_uuars == 0) 561 + return ERR_PTR(-EINVAL); 562 + 563 + req.total_num_uuars = ALIGN(req.total_num_uuars, MLX5_BF_REGS_PER_PAGE); 564 + if (req.num_low_latency_uuars > req.total_num_uuars - 1) 565 + return ERR_PTR(-EINVAL); 566 + 567 + num_uars = req.total_num_uuars / MLX5_BF_REGS_PER_PAGE; 568 + resp.qp_tab_size = 1 << dev->mdev.caps.log_max_qp; 569 + resp.bf_reg_size = dev->mdev.caps.bf_reg_size; 570 + resp.cache_line_size = L1_CACHE_BYTES; 571 + resp.max_sq_desc_sz = dev->mdev.caps.max_sq_desc_sz; 572 + resp.max_rq_desc_sz = dev->mdev.caps.max_rq_desc_sz; 573 + resp.max_send_wqebb = dev->mdev.caps.max_wqes; 574 + resp.max_recv_wr = dev->mdev.caps.max_wqes; 575 + resp.max_srq_recv_wr = dev->mdev.caps.max_srq_wqes; 576 + 577 + context = kzalloc(sizeof(*context), GFP_KERNEL); 578 + if (!context) 579 + return ERR_PTR(-ENOMEM); 580 + 581 + uuari = &context->uuari; 582 + mutex_init(&uuari->lock); 583 + uars = kcalloc(num_uars, sizeof(*uars), GFP_KERNEL); 584 + if (!uars) { 585 + err = -ENOMEM; 586 + goto out_ctx; 587 + } 588 + 589 + uuari->bitmap = kcalloc(BITS_TO_LONGS(req.total_num_uuars), 590 + sizeof(*uuari->bitmap), 591 + GFP_KERNEL); 592 + if (!uuari->bitmap) { 593 + err = -ENOMEM; 594 + goto out_uar_ctx; 595 + } 596 + /* 597 + * clear all fast path uuars 598 + */ 599 + for (i = 0; i < req.total_num_uuars; i++) { 600 + uuarn = i & 3; 601 + if (uuarn == 2 || uuarn == 3) 602 + set_bit(i, uuari->bitmap); 603 + } 604 + 605 + uuari->count = kcalloc(req.total_num_uuars, sizeof(*uuari->count), GFP_KERNEL); 606 + if (!uuari->count) { 607 + err = -ENOMEM; 608 + goto out_bitmap; 609 + } 610 + 611 + for (i = 0; i < num_uars; i++) { 612 + err = mlx5_cmd_alloc_uar(&dev->mdev, &uars[i].index); 613 + if (err) 614 + goto out_count; 615 + } 616 + 617 + INIT_LIST_HEAD(&context->db_page_list); 618 + mutex_init(&context->db_page_mutex); 619 + 620 + resp.tot_uuars = req.total_num_uuars; 621 + resp.num_ports = dev->mdev.caps.num_ports; 622 + err = ib_copy_to_udata(udata, &resp, sizeof(resp)); 623 + if (err) 624 + goto out_uars; 625 + 626 + uuari->num_low_latency_uuars = req.num_low_latency_uuars; 627 + uuari->uars = uars; 628 + uuari->num_uars = num_uars; 629 + return &context->ibucontext; 630 + 631 + out_uars: 632 + for (i--; i >= 0; i--) 633 + mlx5_cmd_free_uar(&dev->mdev, uars[i].index); 634 + out_count: 635 + kfree(uuari->count); 636 + 637 + out_bitmap: 638 + kfree(uuari->bitmap); 639 + 640 + out_uar_ctx: 641 + kfree(uars); 642 + 643 + out_ctx: 644 + kfree(context); 645 + return ERR_PTR(err); 646 + } 647 + 648 + static int mlx5_ib_dealloc_ucontext(struct ib_ucontext *ibcontext) 649 + { 650 + struct mlx5_ib_ucontext *context = to_mucontext(ibcontext); 651 + struct mlx5_ib_dev *dev = to_mdev(ibcontext->device); 652 + struct mlx5_uuar_info *uuari = &context->uuari; 653 + int i; 654 + 655 + for (i = 0; i < uuari->num_uars; i++) { 656 + if (mlx5_cmd_free_uar(&dev->mdev, uuari->uars[i].index)) 657 + mlx5_ib_warn(dev, "failed to free UAR 0x%x\n", uuari->uars[i].index); 658 + } 659 + 660 + kfree(uuari->count); 661 + kfree(uuari->bitmap); 662 + kfree(uuari->uars); 663 + kfree(context); 664 + 665 + return 0; 666 + } 667 + 668 + static phys_addr_t uar_index2pfn(struct mlx5_ib_dev *dev, int index) 669 + { 670 + return (pci_resource_start(dev->mdev.pdev, 0) >> PAGE_SHIFT) + index; 671 + } 672 + 673 + static int get_command(unsigned long offset) 674 + { 675 + return (offset >> MLX5_IB_MMAP_CMD_SHIFT) & MLX5_IB_MMAP_CMD_MASK; 676 + } 677 + 678 + static int get_arg(unsigned long offset) 679 + { 680 + return offset & ((1 << MLX5_IB_MMAP_CMD_SHIFT) - 1); 681 + } 682 + 683 + static int get_index(unsigned long offset) 684 + { 685 + return get_arg(offset); 686 + } 687 + 688 + static int mlx5_ib_mmap(struct ib_ucontext *ibcontext, struct vm_area_struct *vma) 689 + { 690 + struct mlx5_ib_ucontext *context = to_mucontext(ibcontext); 691 + struct mlx5_ib_dev *dev = to_mdev(ibcontext->device); 692 + struct mlx5_uuar_info *uuari = &context->uuari; 693 + unsigned long command; 694 + unsigned long idx; 695 + phys_addr_t pfn; 696 + 697 + command = get_command(vma->vm_pgoff); 698 + switch (command) { 699 + case MLX5_IB_MMAP_REGULAR_PAGE: 700 + if (vma->vm_end - vma->vm_start != PAGE_SIZE) 701 + return -EINVAL; 702 + 703 + idx = get_index(vma->vm_pgoff); 704 + pfn = uar_index2pfn(dev, uuari->uars[idx].index); 705 + mlx5_ib_dbg(dev, "uar idx 0x%lx, pfn 0x%llx\n", idx, 706 + (unsigned long long)pfn); 707 + 708 + if (idx >= uuari->num_uars) 709 + return -EINVAL; 710 + 711 + vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); 712 + if (io_remap_pfn_range(vma, vma->vm_start, pfn, 713 + PAGE_SIZE, vma->vm_page_prot)) 714 + return -EAGAIN; 715 + 716 + mlx5_ib_dbg(dev, "mapped WC at 0x%lx, PA 0x%llx\n", 717 + vma->vm_start, 718 + (unsigned long long)pfn << PAGE_SHIFT); 719 + break; 720 + 721 + case MLX5_IB_MMAP_GET_CONTIGUOUS_PAGES: 722 + return -ENOSYS; 723 + 724 + default: 725 + return -EINVAL; 726 + } 727 + 728 + return 0; 729 + } 730 + 731 + static int alloc_pa_mkey(struct mlx5_ib_dev *dev, u32 *key, u32 pdn) 732 + { 733 + struct mlx5_create_mkey_mbox_in *in; 734 + struct mlx5_mkey_seg *seg; 735 + struct mlx5_core_mr mr; 736 + int err; 737 + 738 + in = kzalloc(sizeof(*in), GFP_KERNEL); 739 + if (!in) 740 + return -ENOMEM; 741 + 742 + seg = &in->seg; 743 + seg->flags = MLX5_PERM_LOCAL_READ | MLX5_ACCESS_MODE_PA; 744 + seg->flags_pd = cpu_to_be32(pdn | MLX5_MKEY_LEN64); 745 + seg->qpn_mkey7_0 = cpu_to_be32(0xffffff << 8); 746 + seg->start_addr = 0; 747 + 748 + err = mlx5_core_create_mkey(&dev->mdev, &mr, in, sizeof(*in)); 749 + if (err) { 750 + mlx5_ib_warn(dev, "failed to create mkey, %d\n", err); 751 + goto err_in; 752 + } 753 + 754 + kfree(in); 755 + *key = mr.key; 756 + 757 + return 0; 758 + 759 + err_in: 760 + kfree(in); 761 + 762 + return err; 763 + } 764 + 765 + static void free_pa_mkey(struct mlx5_ib_dev *dev, u32 key) 766 + { 767 + struct mlx5_core_mr mr; 768 + int err; 769 + 770 + memset(&mr, 0, sizeof(mr)); 771 + mr.key = key; 772 + err = mlx5_core_destroy_mkey(&dev->mdev, &mr); 773 + if (err) 774 + mlx5_ib_warn(dev, "failed to destroy mkey 0x%x\n", key); 775 + } 776 + 777 + static struct ib_pd *mlx5_ib_alloc_pd(struct ib_device *ibdev, 778 + struct ib_ucontext *context, 779 + struct ib_udata *udata) 780 + { 781 + struct mlx5_ib_alloc_pd_resp resp; 782 + struct mlx5_ib_pd *pd; 783 + int err; 784 + 785 + pd = kmalloc(sizeof(*pd), GFP_KERNEL); 786 + if (!pd) 787 + return ERR_PTR(-ENOMEM); 788 + 789 + err = mlx5_core_alloc_pd(&to_mdev(ibdev)->mdev, &pd->pdn); 790 + if (err) { 791 + kfree(pd); 792 + return ERR_PTR(err); 793 + } 794 + 795 + if (context) { 796 + resp.pdn = pd->pdn; 797 + if (ib_copy_to_udata(udata, &resp, sizeof(resp))) { 798 + mlx5_core_dealloc_pd(&to_mdev(ibdev)->mdev, pd->pdn); 799 + kfree(pd); 800 + return ERR_PTR(-EFAULT); 801 + } 802 + } else { 803 + err = alloc_pa_mkey(to_mdev(ibdev), &pd->pa_lkey, pd->pdn); 804 + if (err) { 805 + mlx5_core_dealloc_pd(&to_mdev(ibdev)->mdev, pd->pdn); 806 + kfree(pd); 807 + return ERR_PTR(err); 808 + } 809 + } 810 + 811 + return &pd->ibpd; 812 + } 813 + 814 + static int mlx5_ib_dealloc_pd(struct ib_pd *pd) 815 + { 816 + struct mlx5_ib_dev *mdev = to_mdev(pd->device); 817 + struct mlx5_ib_pd *mpd = to_mpd(pd); 818 + 819 + if (!pd->uobject) 820 + free_pa_mkey(mdev, mpd->pa_lkey); 821 + 822 + mlx5_core_dealloc_pd(&mdev->mdev, mpd->pdn); 823 + kfree(mpd); 824 + 825 + return 0; 826 + } 827 + 828 + static int mlx5_ib_mcg_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) 829 + { 830 + struct mlx5_ib_dev *dev = to_mdev(ibqp->device); 831 + int err; 832 + 833 + err = mlx5_core_attach_mcg(&dev->mdev, gid, ibqp->qp_num); 834 + if (err) 835 + mlx5_ib_warn(dev, "failed attaching QPN 0x%x, MGID %pI6\n", 836 + ibqp->qp_num, gid->raw); 837 + 838 + return err; 839 + } 840 + 841 + static int mlx5_ib_mcg_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) 842 + { 843 + struct mlx5_ib_dev *dev = to_mdev(ibqp->device); 844 + int err; 845 + 846 + err = mlx5_core_detach_mcg(&dev->mdev, gid, ibqp->qp_num); 847 + if (err) 848 + mlx5_ib_warn(dev, "failed detaching QPN 0x%x, MGID %pI6\n", 849 + ibqp->qp_num, gid->raw); 850 + 851 + return err; 852 + } 853 + 854 + static int init_node_data(struct mlx5_ib_dev *dev) 855 + { 856 + struct ib_smp *in_mad = NULL; 857 + struct ib_smp *out_mad = NULL; 858 + int err = -ENOMEM; 859 + 860 + in_mad = kzalloc(sizeof(*in_mad), GFP_KERNEL); 861 + out_mad = kmalloc(sizeof(*out_mad), GFP_KERNEL); 862 + if (!in_mad || !out_mad) 863 + goto out; 864 + 865 + init_query_mad(in_mad); 866 + in_mad->attr_id = IB_SMP_ATTR_NODE_DESC; 867 + 868 + err = mlx5_MAD_IFC(dev, 1, 1, 1, NULL, NULL, in_mad, out_mad); 869 + if (err) 870 + goto out; 871 + 872 + memcpy(dev->ib_dev.node_desc, out_mad->data, 64); 873 + 874 + in_mad->attr_id = IB_SMP_ATTR_NODE_INFO; 875 + 876 + err = mlx5_MAD_IFC(dev, 1, 1, 1, NULL, NULL, in_mad, out_mad); 877 + if (err) 878 + goto out; 879 + 880 + dev->mdev.rev_id = be32_to_cpup((__be32 *)(out_mad->data + 32)); 881 + memcpy(&dev->ib_dev.node_guid, out_mad->data + 12, 8); 882 + 883 + out: 884 + kfree(in_mad); 885 + kfree(out_mad); 886 + return err; 887 + } 888 + 889 + static ssize_t show_fw_pages(struct device *device, struct device_attribute *attr, 890 + char *buf) 891 + { 892 + struct mlx5_ib_dev *dev = 893 + container_of(device, struct mlx5_ib_dev, ib_dev.dev); 894 + 895 + return sprintf(buf, "%d\n", dev->mdev.priv.fw_pages); 896 + } 897 + 898 + static ssize_t show_reg_pages(struct device *device, 899 + struct device_attribute *attr, char *buf) 900 + { 901 + struct mlx5_ib_dev *dev = 902 + container_of(device, struct mlx5_ib_dev, ib_dev.dev); 903 + 904 + return sprintf(buf, "%d\n", dev->mdev.priv.reg_pages); 905 + } 906 + 907 + static ssize_t show_hca(struct device *device, struct device_attribute *attr, 908 + char *buf) 909 + { 910 + struct mlx5_ib_dev *dev = 911 + container_of(device, struct mlx5_ib_dev, ib_dev.dev); 912 + return sprintf(buf, "MT%d\n", dev->mdev.pdev->device); 913 + } 914 + 915 + static ssize_t show_fw_ver(struct device *device, struct device_attribute *attr, 916 + char *buf) 917 + { 918 + struct mlx5_ib_dev *dev = 919 + container_of(device, struct mlx5_ib_dev, ib_dev.dev); 920 + return sprintf(buf, "%d.%d.%d\n", fw_rev_maj(&dev->mdev), 921 + fw_rev_min(&dev->mdev), fw_rev_sub(&dev->mdev)); 922 + } 923 + 924 + static ssize_t show_rev(struct device *device, struct device_attribute *attr, 925 + char *buf) 926 + { 927 + struct mlx5_ib_dev *dev = 928 + container_of(device, struct mlx5_ib_dev, ib_dev.dev); 929 + return sprintf(buf, "%x\n", dev->mdev.rev_id); 930 + } 931 + 932 + static ssize_t show_board(struct device *device, struct device_attribute *attr, 933 + char *buf) 934 + { 935 + struct mlx5_ib_dev *dev = 936 + container_of(device, struct mlx5_ib_dev, ib_dev.dev); 937 + return sprintf(buf, "%.*s\n", MLX5_BOARD_ID_LEN, 938 + dev->mdev.board_id); 939 + } 940 + 941 + static DEVICE_ATTR(hw_rev, S_IRUGO, show_rev, NULL); 942 + static DEVICE_ATTR(fw_ver, S_IRUGO, show_fw_ver, NULL); 943 + static DEVICE_ATTR(hca_type, S_IRUGO, show_hca, NULL); 944 + static DEVICE_ATTR(board_id, S_IRUGO, show_board, NULL); 945 + static DEVICE_ATTR(fw_pages, S_IRUGO, show_fw_pages, NULL); 946 + static DEVICE_ATTR(reg_pages, S_IRUGO, show_reg_pages, NULL); 947 + 948 + static struct device_attribute *mlx5_class_attributes[] = { 949 + &dev_attr_hw_rev, 950 + &dev_attr_fw_ver, 951 + &dev_attr_hca_type, 952 + &dev_attr_board_id, 953 + &dev_attr_fw_pages, 954 + &dev_attr_reg_pages, 955 + }; 956 + 957 + static void mlx5_ib_event(struct mlx5_core_dev *dev, enum mlx5_dev_event event, 958 + void *data) 959 + { 960 + struct mlx5_ib_dev *ibdev = container_of(dev, struct mlx5_ib_dev, mdev); 961 + struct ib_event ibev; 962 + u8 port = 0; 963 + 964 + switch (event) { 965 + case MLX5_DEV_EVENT_SYS_ERROR: 966 + ibdev->ib_active = false; 967 + ibev.event = IB_EVENT_DEVICE_FATAL; 968 + break; 969 + 970 + case MLX5_DEV_EVENT_PORT_UP: 971 + ibev.event = IB_EVENT_PORT_ACTIVE; 972 + port = *(u8 *)data; 973 + break; 974 + 975 + case MLX5_DEV_EVENT_PORT_DOWN: 976 + ibev.event = IB_EVENT_PORT_ERR; 977 + port = *(u8 *)data; 978 + break; 979 + 980 + case MLX5_DEV_EVENT_PORT_INITIALIZED: 981 + /* not used by ULPs */ 982 + return; 983 + 984 + case MLX5_DEV_EVENT_LID_CHANGE: 985 + ibev.event = IB_EVENT_LID_CHANGE; 986 + port = *(u8 *)data; 987 + break; 988 + 989 + case MLX5_DEV_EVENT_PKEY_CHANGE: 990 + ibev.event = IB_EVENT_PKEY_CHANGE; 991 + port = *(u8 *)data; 992 + break; 993 + 994 + case MLX5_DEV_EVENT_GUID_CHANGE: 995 + ibev.event = IB_EVENT_GID_CHANGE; 996 + port = *(u8 *)data; 997 + break; 998 + 999 + case MLX5_DEV_EVENT_CLIENT_REREG: 1000 + ibev.event = IB_EVENT_CLIENT_REREGISTER; 1001 + port = *(u8 *)data; 1002 + break; 1003 + } 1004 + 1005 + ibev.device = &ibdev->ib_dev; 1006 + ibev.element.port_num = port; 1007 + 1008 + if (ibdev->ib_active) 1009 + ib_dispatch_event(&ibev); 1010 + } 1011 + 1012 + static void get_ext_port_caps(struct mlx5_ib_dev *dev) 1013 + { 1014 + int port; 1015 + 1016 + for (port = 1; port <= dev->mdev.caps.num_ports; port++) 1017 + mlx5_query_ext_port_caps(dev, port); 1018 + } 1019 + 1020 + static int get_port_caps(struct mlx5_ib_dev *dev) 1021 + { 1022 + struct ib_device_attr *dprops = NULL; 1023 + struct ib_port_attr *pprops = NULL; 1024 + int err = 0; 1025 + int port; 1026 + 1027 + pprops = kmalloc(sizeof(*pprops), GFP_KERNEL); 1028 + if (!pprops) 1029 + goto out; 1030 + 1031 + dprops = kmalloc(sizeof(*dprops), GFP_KERNEL); 1032 + if (!dprops) 1033 + goto out; 1034 + 1035 + err = mlx5_ib_query_device(&dev->ib_dev, dprops); 1036 + if (err) { 1037 + mlx5_ib_warn(dev, "query_device failed %d\n", err); 1038 + goto out; 1039 + } 1040 + 1041 + for (port = 1; port <= dev->mdev.caps.num_ports; port++) { 1042 + err = mlx5_ib_query_port(&dev->ib_dev, port, pprops); 1043 + if (err) { 1044 + mlx5_ib_warn(dev, "query_port %d failed %d\n", port, err); 1045 + break; 1046 + } 1047 + dev->mdev.caps.port[port - 1].pkey_table_len = dprops->max_pkeys; 1048 + dev->mdev.caps.port[port - 1].gid_table_len = pprops->gid_tbl_len; 1049 + mlx5_ib_dbg(dev, "pkey_table_len %d, gid_table_len %d\n", 1050 + dprops->max_pkeys, pprops->gid_tbl_len); 1051 + } 1052 + 1053 + out: 1054 + kfree(pprops); 1055 + kfree(dprops); 1056 + 1057 + return err; 1058 + } 1059 + 1060 + static void destroy_umrc_res(struct mlx5_ib_dev *dev) 1061 + { 1062 + int err; 1063 + 1064 + err = mlx5_mr_cache_cleanup(dev); 1065 + if (err) 1066 + mlx5_ib_warn(dev, "mr cache cleanup failed\n"); 1067 + 1068 + mlx5_ib_destroy_qp(dev->umrc.qp); 1069 + ib_destroy_cq(dev->umrc.cq); 1070 + ib_dereg_mr(dev->umrc.mr); 1071 + ib_dealloc_pd(dev->umrc.pd); 1072 + } 1073 + 1074 + enum { 1075 + MAX_UMR_WR = 128, 1076 + }; 1077 + 1078 + static int create_umr_res(struct mlx5_ib_dev *dev) 1079 + { 1080 + struct ib_qp_init_attr *init_attr = NULL; 1081 + struct ib_qp_attr *attr = NULL; 1082 + struct ib_pd *pd; 1083 + struct ib_cq *cq; 1084 + struct ib_qp *qp; 1085 + struct ib_mr *mr; 1086 + int ret; 1087 + 1088 + attr = kzalloc(sizeof(*attr), GFP_KERNEL); 1089 + init_attr = kzalloc(sizeof(*init_attr), GFP_KERNEL); 1090 + if (!attr || !init_attr) { 1091 + ret = -ENOMEM; 1092 + goto error_0; 1093 + } 1094 + 1095 + pd = ib_alloc_pd(&dev->ib_dev); 1096 + if (IS_ERR(pd)) { 1097 + mlx5_ib_dbg(dev, "Couldn't create PD for sync UMR QP\n"); 1098 + ret = PTR_ERR(pd); 1099 + goto error_0; 1100 + } 1101 + 1102 + mr = ib_get_dma_mr(pd, IB_ACCESS_LOCAL_WRITE); 1103 + if (IS_ERR(mr)) { 1104 + mlx5_ib_dbg(dev, "Couldn't create DMA MR for sync UMR QP\n"); 1105 + ret = PTR_ERR(mr); 1106 + goto error_1; 1107 + } 1108 + 1109 + cq = ib_create_cq(&dev->ib_dev, mlx5_umr_cq_handler, NULL, NULL, 128, 1110 + 0); 1111 + if (IS_ERR(cq)) { 1112 + mlx5_ib_dbg(dev, "Couldn't create CQ for sync UMR QP\n"); 1113 + ret = PTR_ERR(cq); 1114 + goto error_2; 1115 + } 1116 + ib_req_notify_cq(cq, IB_CQ_NEXT_COMP); 1117 + 1118 + init_attr->send_cq = cq; 1119 + init_attr->recv_cq = cq; 1120 + init_attr->sq_sig_type = IB_SIGNAL_ALL_WR; 1121 + init_attr->cap.max_send_wr = MAX_UMR_WR; 1122 + init_attr->cap.max_send_sge = 1; 1123 + init_attr->qp_type = MLX5_IB_QPT_REG_UMR; 1124 + init_attr->port_num = 1; 1125 + qp = mlx5_ib_create_qp(pd, init_attr, NULL); 1126 + if (IS_ERR(qp)) { 1127 + mlx5_ib_dbg(dev, "Couldn't create sync UMR QP\n"); 1128 + ret = PTR_ERR(qp); 1129 + goto error_3; 1130 + } 1131 + qp->device = &dev->ib_dev; 1132 + qp->real_qp = qp; 1133 + qp->uobject = NULL; 1134 + qp->qp_type = MLX5_IB_QPT_REG_UMR; 1135 + 1136 + attr->qp_state = IB_QPS_INIT; 1137 + attr->port_num = 1; 1138 + ret = mlx5_ib_modify_qp(qp, attr, IB_QP_STATE | IB_QP_PKEY_INDEX | 1139 + IB_QP_PORT, NULL); 1140 + if (ret) { 1141 + mlx5_ib_dbg(dev, "Couldn't modify UMR QP\n"); 1142 + goto error_4; 1143 + } 1144 + 1145 + memset(attr, 0, sizeof(*attr)); 1146 + attr->qp_state = IB_QPS_RTR; 1147 + attr->path_mtu = IB_MTU_256; 1148 + 1149 + ret = mlx5_ib_modify_qp(qp, attr, IB_QP_STATE, NULL); 1150 + if (ret) { 1151 + mlx5_ib_dbg(dev, "Couldn't modify umr QP to rtr\n"); 1152 + goto error_4; 1153 + } 1154 + 1155 + memset(attr, 0, sizeof(*attr)); 1156 + attr->qp_state = IB_QPS_RTS; 1157 + ret = mlx5_ib_modify_qp(qp, attr, IB_QP_STATE, NULL); 1158 + if (ret) { 1159 + mlx5_ib_dbg(dev, "Couldn't modify umr QP to rts\n"); 1160 + goto error_4; 1161 + } 1162 + 1163 + dev->umrc.qp = qp; 1164 + dev->umrc.cq = cq; 1165 + dev->umrc.mr = mr; 1166 + dev->umrc.pd = pd; 1167 + 1168 + sema_init(&dev->umrc.sem, MAX_UMR_WR); 1169 + ret = mlx5_mr_cache_init(dev); 1170 + if (ret) { 1171 + mlx5_ib_warn(dev, "mr cache init failed %d\n", ret); 1172 + goto error_4; 1173 + } 1174 + 1175 + kfree(attr); 1176 + kfree(init_attr); 1177 + 1178 + return 0; 1179 + 1180 + error_4: 1181 + mlx5_ib_destroy_qp(qp); 1182 + 1183 + error_3: 1184 + ib_destroy_cq(cq); 1185 + 1186 + error_2: 1187 + ib_dereg_mr(mr); 1188 + 1189 + error_1: 1190 + ib_dealloc_pd(pd); 1191 + 1192 + error_0: 1193 + kfree(attr); 1194 + kfree(init_attr); 1195 + return ret; 1196 + } 1197 + 1198 + static int create_dev_resources(struct mlx5_ib_resources *devr) 1199 + { 1200 + struct ib_srq_init_attr attr; 1201 + struct mlx5_ib_dev *dev; 1202 + int ret = 0; 1203 + 1204 + dev = container_of(devr, struct mlx5_ib_dev, devr); 1205 + 1206 + devr->p0 = mlx5_ib_alloc_pd(&dev->ib_dev, NULL, NULL); 1207 + if (IS_ERR(devr->p0)) { 1208 + ret = PTR_ERR(devr->p0); 1209 + goto error0; 1210 + } 1211 + devr->p0->device = &dev->ib_dev; 1212 + devr->p0->uobject = NULL; 1213 + atomic_set(&devr->p0->usecnt, 0); 1214 + 1215 + devr->c0 = mlx5_ib_create_cq(&dev->ib_dev, 1, 0, NULL, NULL); 1216 + if (IS_ERR(devr->c0)) { 1217 + ret = PTR_ERR(devr->c0); 1218 + goto error1; 1219 + } 1220 + devr->c0->device = &dev->ib_dev; 1221 + devr->c0->uobject = NULL; 1222 + devr->c0->comp_handler = NULL; 1223 + devr->c0->event_handler = NULL; 1224 + devr->c0->cq_context = NULL; 1225 + atomic_set(&devr->c0->usecnt, 0); 1226 + 1227 + devr->x0 = mlx5_ib_alloc_xrcd(&dev->ib_dev, NULL, NULL); 1228 + if (IS_ERR(devr->x0)) { 1229 + ret = PTR_ERR(devr->x0); 1230 + goto error2; 1231 + } 1232 + devr->x0->device = &dev->ib_dev; 1233 + devr->x0->inode = NULL; 1234 + atomic_set(&devr->x0->usecnt, 0); 1235 + mutex_init(&devr->x0->tgt_qp_mutex); 1236 + INIT_LIST_HEAD(&devr->x0->tgt_qp_list); 1237 + 1238 + devr->x1 = mlx5_ib_alloc_xrcd(&dev->ib_dev, NULL, NULL); 1239 + if (IS_ERR(devr->x1)) { 1240 + ret = PTR_ERR(devr->x1); 1241 + goto error3; 1242 + } 1243 + devr->x1->device = &dev->ib_dev; 1244 + devr->x1->inode = NULL; 1245 + atomic_set(&devr->x1->usecnt, 0); 1246 + mutex_init(&devr->x1->tgt_qp_mutex); 1247 + INIT_LIST_HEAD(&devr->x1->tgt_qp_list); 1248 + 1249 + memset(&attr, 0, sizeof(attr)); 1250 + attr.attr.max_sge = 1; 1251 + attr.attr.max_wr = 1; 1252 + attr.srq_type = IB_SRQT_XRC; 1253 + attr.ext.xrc.cq = devr->c0; 1254 + attr.ext.xrc.xrcd = devr->x0; 1255 + 1256 + devr->s0 = mlx5_ib_create_srq(devr->p0, &attr, NULL); 1257 + if (IS_ERR(devr->s0)) { 1258 + ret = PTR_ERR(devr->s0); 1259 + goto error4; 1260 + } 1261 + devr->s0->device = &dev->ib_dev; 1262 + devr->s0->pd = devr->p0; 1263 + devr->s0->uobject = NULL; 1264 + devr->s0->event_handler = NULL; 1265 + devr->s0->srq_context = NULL; 1266 + devr->s0->srq_type = IB_SRQT_XRC; 1267 + devr->s0->ext.xrc.xrcd = devr->x0; 1268 + devr->s0->ext.xrc.cq = devr->c0; 1269 + atomic_inc(&devr->s0->ext.xrc.xrcd->usecnt); 1270 + atomic_inc(&devr->s0->ext.xrc.cq->usecnt); 1271 + atomic_inc(&devr->p0->usecnt); 1272 + atomic_set(&devr->s0->usecnt, 0); 1273 + 1274 + return 0; 1275 + 1276 + error4: 1277 + mlx5_ib_dealloc_xrcd(devr->x1); 1278 + error3: 1279 + mlx5_ib_dealloc_xrcd(devr->x0); 1280 + error2: 1281 + mlx5_ib_destroy_cq(devr->c0); 1282 + error1: 1283 + mlx5_ib_dealloc_pd(devr->p0); 1284 + error0: 1285 + return ret; 1286 + } 1287 + 1288 + static void destroy_dev_resources(struct mlx5_ib_resources *devr) 1289 + { 1290 + mlx5_ib_destroy_srq(devr->s0); 1291 + mlx5_ib_dealloc_xrcd(devr->x0); 1292 + mlx5_ib_dealloc_xrcd(devr->x1); 1293 + mlx5_ib_destroy_cq(devr->c0); 1294 + mlx5_ib_dealloc_pd(devr->p0); 1295 + } 1296 + 1297 + static int init_one(struct pci_dev *pdev, 1298 + const struct pci_device_id *id) 1299 + { 1300 + struct mlx5_core_dev *mdev; 1301 + struct mlx5_ib_dev *dev; 1302 + int err; 1303 + int i; 1304 + 1305 + printk_once(KERN_INFO "%s", mlx5_version); 1306 + 1307 + dev = (struct mlx5_ib_dev *)ib_alloc_device(sizeof(*dev)); 1308 + if (!dev) 1309 + return -ENOMEM; 1310 + 1311 + mdev = &dev->mdev; 1312 + mdev->event = mlx5_ib_event; 1313 + if (prof_sel >= ARRAY_SIZE(profile)) { 1314 + pr_warn("selected pofile out of range, selceting default\n"); 1315 + prof_sel = 0; 1316 + } 1317 + mdev->profile = &profile[prof_sel]; 1318 + err = mlx5_dev_init(mdev, pdev); 1319 + if (err) 1320 + goto err_free; 1321 + 1322 + err = get_port_caps(dev); 1323 + if (err) 1324 + goto err_cleanup; 1325 + 1326 + get_ext_port_caps(dev); 1327 + 1328 + err = alloc_comp_eqs(dev); 1329 + if (err) 1330 + goto err_cleanup; 1331 + 1332 + MLX5_INIT_DOORBELL_LOCK(&dev->uar_lock); 1333 + 1334 + strlcpy(dev->ib_dev.name, "mlx5_%d", IB_DEVICE_NAME_MAX); 1335 + dev->ib_dev.owner = THIS_MODULE; 1336 + dev->ib_dev.node_type = RDMA_NODE_IB_CA; 1337 + dev->ib_dev.local_dma_lkey = mdev->caps.reserved_lkey; 1338 + dev->num_ports = mdev->caps.num_ports; 1339 + dev->ib_dev.phys_port_cnt = dev->num_ports; 1340 + dev->ib_dev.num_comp_vectors = dev->num_comp_vectors; 1341 + dev->ib_dev.dma_device = &mdev->pdev->dev; 1342 + 1343 + dev->ib_dev.uverbs_abi_ver = MLX5_IB_UVERBS_ABI_VERSION; 1344 + dev->ib_dev.uverbs_cmd_mask = 1345 + (1ull << IB_USER_VERBS_CMD_GET_CONTEXT) | 1346 + (1ull << IB_USER_VERBS_CMD_QUERY_DEVICE) | 1347 + (1ull << IB_USER_VERBS_CMD_QUERY_PORT) | 1348 + (1ull << IB_USER_VERBS_CMD_ALLOC_PD) | 1349 + (1ull << IB_USER_VERBS_CMD_DEALLOC_PD) | 1350 + (1ull << IB_USER_VERBS_CMD_REG_MR) | 1351 + (1ull << IB_USER_VERBS_CMD_DEREG_MR) | 1352 + (1ull << IB_USER_VERBS_CMD_CREATE_COMP_CHANNEL) | 1353 + (1ull << IB_USER_VERBS_CMD_CREATE_CQ) | 1354 + (1ull << IB_USER_VERBS_CMD_RESIZE_CQ) | 1355 + (1ull << IB_USER_VERBS_CMD_DESTROY_CQ) | 1356 + (1ull << IB_USER_VERBS_CMD_CREATE_QP) | 1357 + (1ull << IB_USER_VERBS_CMD_MODIFY_QP) | 1358 + (1ull << IB_USER_VERBS_CMD_QUERY_QP) | 1359 + (1ull << IB_USER_VERBS_CMD_DESTROY_QP) | 1360 + (1ull << IB_USER_VERBS_CMD_ATTACH_MCAST) | 1361 + (1ull << IB_USER_VERBS_CMD_DETACH_MCAST) | 1362 + (1ull << IB_USER_VERBS_CMD_CREATE_SRQ) | 1363 + (1ull << IB_USER_VERBS_CMD_MODIFY_SRQ) | 1364 + (1ull << IB_USER_VERBS_CMD_QUERY_SRQ) | 1365 + (1ull << IB_USER_VERBS_CMD_DESTROY_SRQ) | 1366 + (1ull << IB_USER_VERBS_CMD_CREATE_XSRQ) | 1367 + (1ull << IB_USER_VERBS_CMD_OPEN_QP); 1368 + 1369 + dev->ib_dev.query_device = mlx5_ib_query_device; 1370 + dev->ib_dev.query_port = mlx5_ib_query_port; 1371 + dev->ib_dev.query_gid = mlx5_ib_query_gid; 1372 + dev->ib_dev.query_pkey = mlx5_ib_query_pkey; 1373 + dev->ib_dev.modify_device = mlx5_ib_modify_device; 1374 + dev->ib_dev.modify_port = mlx5_ib_modify_port; 1375 + dev->ib_dev.alloc_ucontext = mlx5_ib_alloc_ucontext; 1376 + dev->ib_dev.dealloc_ucontext = mlx5_ib_dealloc_ucontext; 1377 + dev->ib_dev.mmap = mlx5_ib_mmap; 1378 + dev->ib_dev.alloc_pd = mlx5_ib_alloc_pd; 1379 + dev->ib_dev.dealloc_pd = mlx5_ib_dealloc_pd; 1380 + dev->ib_dev.create_ah = mlx5_ib_create_ah; 1381 + dev->ib_dev.query_ah = mlx5_ib_query_ah; 1382 + dev->ib_dev.destroy_ah = mlx5_ib_destroy_ah; 1383 + dev->ib_dev.create_srq = mlx5_ib_create_srq; 1384 + dev->ib_dev.modify_srq = mlx5_ib_modify_srq; 1385 + dev->ib_dev.query_srq = mlx5_ib_query_srq; 1386 + dev->ib_dev.destroy_srq = mlx5_ib_destroy_srq; 1387 + dev->ib_dev.post_srq_recv = mlx5_ib_post_srq_recv; 1388 + dev->ib_dev.create_qp = mlx5_ib_create_qp; 1389 + dev->ib_dev.modify_qp = mlx5_ib_modify_qp; 1390 + dev->ib_dev.query_qp = mlx5_ib_query_qp; 1391 + dev->ib_dev.destroy_qp = mlx5_ib_destroy_qp; 1392 + dev->ib_dev.post_send = mlx5_ib_post_send; 1393 + dev->ib_dev.post_recv = mlx5_ib_post_recv; 1394 + dev->ib_dev.create_cq = mlx5_ib_create_cq; 1395 + dev->ib_dev.modify_cq = mlx5_ib_modify_cq; 1396 + dev->ib_dev.resize_cq = mlx5_ib_resize_cq; 1397 + dev->ib_dev.destroy_cq = mlx5_ib_destroy_cq; 1398 + dev->ib_dev.poll_cq = mlx5_ib_poll_cq; 1399 + dev->ib_dev.req_notify_cq = mlx5_ib_arm_cq; 1400 + dev->ib_dev.get_dma_mr = mlx5_ib_get_dma_mr; 1401 + dev->ib_dev.reg_user_mr = mlx5_ib_reg_user_mr; 1402 + dev->ib_dev.dereg_mr = mlx5_ib_dereg_mr; 1403 + dev->ib_dev.attach_mcast = mlx5_ib_mcg_attach; 1404 + dev->ib_dev.detach_mcast = mlx5_ib_mcg_detach; 1405 + dev->ib_dev.process_mad = mlx5_ib_process_mad; 1406 + dev->ib_dev.alloc_fast_reg_mr = mlx5_ib_alloc_fast_reg_mr; 1407 + dev->ib_dev.alloc_fast_reg_page_list = mlx5_ib_alloc_fast_reg_page_list; 1408 + dev->ib_dev.free_fast_reg_page_list = mlx5_ib_free_fast_reg_page_list; 1409 + 1410 + if (mdev->caps.flags & MLX5_DEV_CAP_FLAG_XRC) { 1411 + dev->ib_dev.alloc_xrcd = mlx5_ib_alloc_xrcd; 1412 + dev->ib_dev.dealloc_xrcd = mlx5_ib_dealloc_xrcd; 1413 + dev->ib_dev.uverbs_cmd_mask |= 1414 + (1ull << IB_USER_VERBS_CMD_OPEN_XRCD) | 1415 + (1ull << IB_USER_VERBS_CMD_CLOSE_XRCD); 1416 + } 1417 + 1418 + err = init_node_data(dev); 1419 + if (err) 1420 + goto err_eqs; 1421 + 1422 + mutex_init(&dev->cap_mask_mutex); 1423 + spin_lock_init(&dev->mr_lock); 1424 + 1425 + err = create_dev_resources(&dev->devr); 1426 + if (err) 1427 + goto err_eqs; 1428 + 1429 + if (ib_register_device(&dev->ib_dev, NULL)) 1430 + goto err_rsrc; 1431 + 1432 + err = create_umr_res(dev); 1433 + if (err) 1434 + goto err_dev; 1435 + 1436 + for (i = 0; i < ARRAY_SIZE(mlx5_class_attributes); i++) { 1437 + if (device_create_file(&dev->ib_dev.dev, 1438 + mlx5_class_attributes[i])) 1439 + goto err_umrc; 1440 + } 1441 + 1442 + dev->ib_active = true; 1443 + 1444 + return 0; 1445 + 1446 + err_umrc: 1447 + destroy_umrc_res(dev); 1448 + 1449 + err_dev: 1450 + ib_unregister_device(&dev->ib_dev); 1451 + 1452 + err_rsrc: 1453 + destroy_dev_resources(&dev->devr); 1454 + 1455 + err_eqs: 1456 + free_comp_eqs(dev); 1457 + 1458 + err_cleanup: 1459 + mlx5_dev_cleanup(mdev); 1460 + 1461 + err_free: 1462 + ib_dealloc_device((struct ib_device *)dev); 1463 + 1464 + return err; 1465 + } 1466 + 1467 + static void remove_one(struct pci_dev *pdev) 1468 + { 1469 + struct mlx5_ib_dev *dev = mlx5_pci2ibdev(pdev); 1470 + 1471 + destroy_umrc_res(dev); 1472 + ib_unregister_device(&dev->ib_dev); 1473 + destroy_dev_resources(&dev->devr); 1474 + free_comp_eqs(dev); 1475 + mlx5_dev_cleanup(&dev->mdev); 1476 + ib_dealloc_device(&dev->ib_dev); 1477 + } 1478 + 1479 + static DEFINE_PCI_DEVICE_TABLE(mlx5_ib_pci_table) = { 1480 + { PCI_VDEVICE(MELLANOX, 4113) }, /* MT4113 Connect-IB */ 1481 + { 0, } 1482 + }; 1483 + 1484 + MODULE_DEVICE_TABLE(pci, mlx5_ib_pci_table); 1485 + 1486 + static struct pci_driver mlx5_ib_driver = { 1487 + .name = DRIVER_NAME, 1488 + .id_table = mlx5_ib_pci_table, 1489 + .probe = init_one, 1490 + .remove = remove_one 1491 + }; 1492 + 1493 + static int __init mlx5_ib_init(void) 1494 + { 1495 + return pci_register_driver(&mlx5_ib_driver); 1496 + } 1497 + 1498 + static void __exit mlx5_ib_cleanup(void) 1499 + { 1500 + pci_unregister_driver(&mlx5_ib_driver); 1501 + } 1502 + 1503 + module_init(mlx5_ib_init); 1504 + module_exit(mlx5_ib_cleanup);
+162
drivers/infiniband/hw/mlx5/mem.c
··· 1 + /* 2 + * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved. 3 + * 4 + * This software is available to you under a choice of one of two 5 + * licenses. You may choose to be licensed under the terms of the GNU 6 + * General Public License (GPL) Version 2, available from the file 7 + * COPYING in the main directory of this source tree, or the 8 + * OpenIB.org BSD license below: 9 + * 10 + * Redistribution and use in source and binary forms, with or 11 + * without modification, are permitted provided that the following 12 + * conditions are met: 13 + * 14 + * - Redistributions of source code must retain the above 15 + * copyright notice, this list of conditions and the following 16 + * disclaimer. 17 + * 18 + * - Redistributions in binary form must reproduce the above 19 + * copyright notice, this list of conditions and the following 20 + * disclaimer in the documentation and/or other materials 21 + * 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 OF 25 + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26 + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 27 + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 28 + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29 + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30 + * SOFTWARE. 31 + */ 32 + 33 + #include <linux/module.h> 34 + #include <rdma/ib_umem.h> 35 + #include "mlx5_ib.h" 36 + 37 + /* @umem: umem object to scan 38 + * @addr: ib virtual address requested by the user 39 + * @count: number of PAGE_SIZE pages covered by umem 40 + * @shift: page shift for the compound pages found in the region 41 + * @ncont: number of compund pages 42 + * @order: log2 of the number of compound pages 43 + */ 44 + void mlx5_ib_cont_pages(struct ib_umem *umem, u64 addr, int *count, int *shift, 45 + int *ncont, int *order) 46 + { 47 + struct ib_umem_chunk *chunk; 48 + unsigned long tmp; 49 + unsigned long m; 50 + int i, j, k; 51 + u64 base = 0; 52 + int p = 0; 53 + int skip; 54 + int mask; 55 + u64 len; 56 + u64 pfn; 57 + 58 + addr = addr >> PAGE_SHIFT; 59 + tmp = (unsigned long)addr; 60 + m = find_first_bit(&tmp, sizeof(tmp)); 61 + skip = 1 << m; 62 + mask = skip - 1; 63 + i = 0; 64 + list_for_each_entry(chunk, &umem->chunk_list, list) 65 + for (j = 0; j < chunk->nmap; j++) { 66 + len = sg_dma_len(&chunk->page_list[j]) >> PAGE_SHIFT; 67 + pfn = sg_dma_address(&chunk->page_list[j]) >> PAGE_SHIFT; 68 + for (k = 0; k < len; k++) { 69 + if (!(i & mask)) { 70 + tmp = (unsigned long)pfn; 71 + m = min(m, find_first_bit(&tmp, sizeof(tmp))); 72 + skip = 1 << m; 73 + mask = skip - 1; 74 + base = pfn; 75 + p = 0; 76 + } else { 77 + if (base + p != pfn) { 78 + tmp = (unsigned long)p; 79 + m = find_first_bit(&tmp, sizeof(tmp)); 80 + skip = 1 << m; 81 + mask = skip - 1; 82 + base = pfn; 83 + p = 0; 84 + } 85 + } 86 + p++; 87 + i++; 88 + } 89 + } 90 + 91 + if (i) { 92 + m = min_t(unsigned long, ilog2(roundup_pow_of_two(i)), m); 93 + 94 + if (order) 95 + *order = ilog2(roundup_pow_of_two(i) >> m); 96 + 97 + *ncont = DIV_ROUND_UP(i, (1 << m)); 98 + } else { 99 + m = 0; 100 + 101 + if (order) 102 + *order = 0; 103 + 104 + *ncont = 0; 105 + } 106 + *shift = PAGE_SHIFT + m; 107 + *count = i; 108 + } 109 + 110 + void mlx5_ib_populate_pas(struct mlx5_ib_dev *dev, struct ib_umem *umem, 111 + int page_shift, __be64 *pas, int umr) 112 + { 113 + int shift = page_shift - PAGE_SHIFT; 114 + int mask = (1 << shift) - 1; 115 + struct ib_umem_chunk *chunk; 116 + int i, j, k; 117 + u64 cur = 0; 118 + u64 base; 119 + int len; 120 + 121 + i = 0; 122 + list_for_each_entry(chunk, &umem->chunk_list, list) 123 + for (j = 0; j < chunk->nmap; j++) { 124 + len = sg_dma_len(&chunk->page_list[j]) >> PAGE_SHIFT; 125 + base = sg_dma_address(&chunk->page_list[j]); 126 + for (k = 0; k < len; k++) { 127 + if (!(i & mask)) { 128 + cur = base + (k << PAGE_SHIFT); 129 + if (umr) 130 + cur |= 3; 131 + 132 + pas[i >> shift] = cpu_to_be64(cur); 133 + mlx5_ib_dbg(dev, "pas[%d] 0x%llx\n", 134 + i >> shift, be64_to_cpu(pas[i >> shift])); 135 + } else 136 + mlx5_ib_dbg(dev, "=====> 0x%llx\n", 137 + base + (k << PAGE_SHIFT)); 138 + i++; 139 + } 140 + } 141 + } 142 + 143 + int mlx5_ib_get_buf_offset(u64 addr, int page_shift, u32 *offset) 144 + { 145 + u64 page_size; 146 + u64 page_mask; 147 + u64 off_size; 148 + u64 off_mask; 149 + u64 buf_off; 150 + 151 + page_size = 1 << page_shift; 152 + page_mask = page_size - 1; 153 + buf_off = addr & page_mask; 154 + off_size = page_size >> 6; 155 + off_mask = off_size - 1; 156 + 157 + if (buf_off & off_mask) 158 + return -EINVAL; 159 + 160 + *offset = buf_off >> ilog2(off_size); 161 + return 0; 162 + }
+545
drivers/infiniband/hw/mlx5/mlx5_ib.h
··· 1 + /* 2 + * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved. 3 + * 4 + * This software is available to you under a choice of one of two 5 + * licenses. You may choose to be licensed under the terms of the GNU 6 + * General Public License (GPL) Version 2, available from the file 7 + * COPYING in the main directory of this source tree, or the 8 + * OpenIB.org BSD license below: 9 + * 10 + * Redistribution and use in source and binary forms, with or 11 + * without modification, are permitted provided that the following 12 + * conditions are met: 13 + * 14 + * - Redistributions of source code must retain the above 15 + * copyright notice, this list of conditions and the following 16 + * disclaimer. 17 + * 18 + * - Redistributions in binary form must reproduce the above 19 + * copyright notice, this list of conditions and the following 20 + * disclaimer in the documentation and/or other materials 21 + * 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 OF 25 + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26 + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 27 + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 28 + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29 + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30 + * SOFTWARE. 31 + */ 32 + 33 + #ifndef MLX5_IB_H 34 + #define MLX5_IB_H 35 + 36 + #include <linux/kernel.h> 37 + #include <linux/sched.h> 38 + #include <rdma/ib_verbs.h> 39 + #include <rdma/ib_smi.h> 40 + #include <linux/mlx5/driver.h> 41 + #include <linux/mlx5/cq.h> 42 + #include <linux/mlx5/qp.h> 43 + #include <linux/mlx5/srq.h> 44 + #include <linux/types.h> 45 + 46 + #define mlx5_ib_dbg(dev, format, arg...) \ 47 + pr_debug("%s:%s:%d:(pid %d): " format, (dev)->ib_dev.name, __func__, \ 48 + __LINE__, current->pid, ##arg) 49 + 50 + #define mlx5_ib_err(dev, format, arg...) \ 51 + pr_err("%s:%s:%d:(pid %d): " format, (dev)->ib_dev.name, __func__, \ 52 + __LINE__, current->pid, ##arg) 53 + 54 + #define mlx5_ib_warn(dev, format, arg...) \ 55 + pr_warn("%s:%s:%d:(pid %d): " format, (dev)->ib_dev.name, __func__, \ 56 + __LINE__, current->pid, ##arg) 57 + 58 + enum { 59 + MLX5_IB_MMAP_CMD_SHIFT = 8, 60 + MLX5_IB_MMAP_CMD_MASK = 0xff, 61 + }; 62 + 63 + enum mlx5_ib_mmap_cmd { 64 + MLX5_IB_MMAP_REGULAR_PAGE = 0, 65 + MLX5_IB_MMAP_GET_CONTIGUOUS_PAGES = 1, /* always last */ 66 + }; 67 + 68 + enum { 69 + MLX5_RES_SCAT_DATA32_CQE = 0x1, 70 + MLX5_RES_SCAT_DATA64_CQE = 0x2, 71 + MLX5_REQ_SCAT_DATA32_CQE = 0x11, 72 + MLX5_REQ_SCAT_DATA64_CQE = 0x22, 73 + }; 74 + 75 + enum mlx5_ib_latency_class { 76 + MLX5_IB_LATENCY_CLASS_LOW, 77 + MLX5_IB_LATENCY_CLASS_MEDIUM, 78 + MLX5_IB_LATENCY_CLASS_HIGH, 79 + MLX5_IB_LATENCY_CLASS_FAST_PATH 80 + }; 81 + 82 + enum mlx5_ib_mad_ifc_flags { 83 + MLX5_MAD_IFC_IGNORE_MKEY = 1, 84 + MLX5_MAD_IFC_IGNORE_BKEY = 2, 85 + MLX5_MAD_IFC_NET_VIEW = 4, 86 + }; 87 + 88 + struct mlx5_ib_ucontext { 89 + struct ib_ucontext ibucontext; 90 + struct list_head db_page_list; 91 + 92 + /* protect doorbell record alloc/free 93 + */ 94 + struct mutex db_page_mutex; 95 + struct mlx5_uuar_info uuari; 96 + }; 97 + 98 + static inline struct mlx5_ib_ucontext *to_mucontext(struct ib_ucontext *ibucontext) 99 + { 100 + return container_of(ibucontext, struct mlx5_ib_ucontext, ibucontext); 101 + } 102 + 103 + struct mlx5_ib_pd { 104 + struct ib_pd ibpd; 105 + u32 pdn; 106 + u32 pa_lkey; 107 + }; 108 + 109 + /* Use macros here so that don't have to duplicate 110 + * enum ib_send_flags and enum ib_qp_type for low-level driver 111 + */ 112 + 113 + #define MLX5_IB_SEND_UMR_UNREG IB_SEND_RESERVED_START 114 + #define MLX5_IB_QPT_REG_UMR IB_QPT_RESERVED1 115 + #define MLX5_IB_WR_UMR IB_WR_RESERVED1 116 + 117 + struct wr_list { 118 + u16 opcode; 119 + u16 next; 120 + }; 121 + 122 + struct mlx5_ib_wq { 123 + u64 *wrid; 124 + u32 *wr_data; 125 + struct wr_list *w_list; 126 + unsigned *wqe_head; 127 + u16 unsig_count; 128 + 129 + /* serialize post to the work queue 130 + */ 131 + spinlock_t lock; 132 + int wqe_cnt; 133 + int max_post; 134 + int max_gs; 135 + int offset; 136 + int wqe_shift; 137 + unsigned head; 138 + unsigned tail; 139 + u16 cur_post; 140 + u16 last_poll; 141 + void *qend; 142 + }; 143 + 144 + enum { 145 + MLX5_QP_USER, 146 + MLX5_QP_KERNEL, 147 + MLX5_QP_EMPTY 148 + }; 149 + 150 + struct mlx5_ib_qp { 151 + struct ib_qp ibqp; 152 + struct mlx5_core_qp mqp; 153 + struct mlx5_buf buf; 154 + 155 + struct mlx5_db db; 156 + struct mlx5_ib_wq rq; 157 + 158 + u32 doorbell_qpn; 159 + u8 sq_signal_bits; 160 + u8 fm_cache; 161 + int sq_max_wqes_per_wr; 162 + int sq_spare_wqes; 163 + struct mlx5_ib_wq sq; 164 + 165 + struct ib_umem *umem; 166 + int buf_size; 167 + 168 + /* serialize qp state modifications 169 + */ 170 + struct mutex mutex; 171 + u16 xrcdn; 172 + u32 flags; 173 + u8 port; 174 + u8 alt_port; 175 + u8 atomic_rd_en; 176 + u8 resp_depth; 177 + u8 state; 178 + int mlx_type; 179 + int wq_sig; 180 + int scat_cqe; 181 + int max_inline_data; 182 + struct mlx5_bf *bf; 183 + int has_rq; 184 + 185 + /* only for user space QPs. For kernel 186 + * we have it from the bf object 187 + */ 188 + int uuarn; 189 + 190 + int create_type; 191 + u32 pa_lkey; 192 + }; 193 + 194 + struct mlx5_ib_cq_buf { 195 + struct mlx5_buf buf; 196 + struct ib_umem *umem; 197 + int cqe_size; 198 + }; 199 + 200 + enum mlx5_ib_qp_flags { 201 + MLX5_IB_QP_BLOCK_MULTICAST_LOOPBACK = 1 << 0, 202 + MLX5_IB_QP_SIGNATURE_HANDLING = 1 << 1, 203 + }; 204 + 205 + struct mlx5_shared_mr_info { 206 + int mr_id; 207 + struct ib_umem *umem; 208 + }; 209 + 210 + struct mlx5_ib_cq { 211 + struct ib_cq ibcq; 212 + struct mlx5_core_cq mcq; 213 + struct mlx5_ib_cq_buf buf; 214 + struct mlx5_db db; 215 + 216 + /* serialize access to the CQ 217 + */ 218 + spinlock_t lock; 219 + 220 + /* protect resize cq 221 + */ 222 + struct mutex resize_mutex; 223 + struct mlx5_ib_cq_resize *resize_buf; 224 + struct ib_umem *resize_umem; 225 + int cqe_size; 226 + }; 227 + 228 + struct mlx5_ib_srq { 229 + struct ib_srq ibsrq; 230 + struct mlx5_core_srq msrq; 231 + struct mlx5_buf buf; 232 + struct mlx5_db db; 233 + u64 *wrid; 234 + /* protect SRQ hanlding 235 + */ 236 + spinlock_t lock; 237 + int head; 238 + int tail; 239 + u16 wqe_ctr; 240 + struct ib_umem *umem; 241 + /* serialize arming a SRQ 242 + */ 243 + struct mutex mutex; 244 + int wq_sig; 245 + }; 246 + 247 + struct mlx5_ib_xrcd { 248 + struct ib_xrcd ibxrcd; 249 + u32 xrcdn; 250 + }; 251 + 252 + struct mlx5_ib_mr { 253 + struct ib_mr ibmr; 254 + struct mlx5_core_mr mmr; 255 + struct ib_umem *umem; 256 + struct mlx5_shared_mr_info *smr_info; 257 + struct list_head list; 258 + int order; 259 + int umred; 260 + __be64 *pas; 261 + dma_addr_t dma; 262 + int npages; 263 + struct completion done; 264 + enum ib_wc_status status; 265 + }; 266 + 267 + struct mlx5_ib_fast_reg_page_list { 268 + struct ib_fast_reg_page_list ibfrpl; 269 + __be64 *mapped_page_list; 270 + dma_addr_t map; 271 + }; 272 + 273 + struct umr_common { 274 + struct ib_pd *pd; 275 + struct ib_cq *cq; 276 + struct ib_qp *qp; 277 + struct ib_mr *mr; 278 + /* control access to UMR QP 279 + */ 280 + struct semaphore sem; 281 + }; 282 + 283 + enum { 284 + MLX5_FMR_INVALID, 285 + MLX5_FMR_VALID, 286 + MLX5_FMR_BUSY, 287 + }; 288 + 289 + struct mlx5_ib_fmr { 290 + struct ib_fmr ibfmr; 291 + struct mlx5_core_mr mr; 292 + int access_flags; 293 + int state; 294 + /* protect fmr state 295 + */ 296 + spinlock_t lock; 297 + u64 wrid; 298 + struct ib_send_wr wr[2]; 299 + u8 page_shift; 300 + struct ib_fast_reg_page_list page_list; 301 + }; 302 + 303 + struct mlx5_cache_ent { 304 + struct list_head head; 305 + /* sync access to the cahce entry 306 + */ 307 + spinlock_t lock; 308 + 309 + 310 + struct dentry *dir; 311 + char name[4]; 312 + u32 order; 313 + u32 size; 314 + u32 cur; 315 + u32 miss; 316 + u32 limit; 317 + 318 + struct dentry *fsize; 319 + struct dentry *fcur; 320 + struct dentry *fmiss; 321 + struct dentry *flimit; 322 + 323 + struct mlx5_ib_dev *dev; 324 + struct work_struct work; 325 + struct delayed_work dwork; 326 + }; 327 + 328 + struct mlx5_mr_cache { 329 + struct workqueue_struct *wq; 330 + struct mlx5_cache_ent ent[MAX_MR_CACHE_ENTRIES]; 331 + int stopped; 332 + struct dentry *root; 333 + unsigned long last_add; 334 + }; 335 + 336 + struct mlx5_ib_resources { 337 + struct ib_cq *c0; 338 + struct ib_xrcd *x0; 339 + struct ib_xrcd *x1; 340 + struct ib_pd *p0; 341 + struct ib_srq *s0; 342 + }; 343 + 344 + struct mlx5_ib_dev { 345 + struct ib_device ib_dev; 346 + struct mlx5_core_dev mdev; 347 + MLX5_DECLARE_DOORBELL_LOCK(uar_lock); 348 + struct list_head eqs_list; 349 + int num_ports; 350 + int num_comp_vectors; 351 + /* serialize update of capability mask 352 + */ 353 + struct mutex cap_mask_mutex; 354 + bool ib_active; 355 + struct umr_common umrc; 356 + /* sync used page count stats 357 + */ 358 + spinlock_t mr_lock; 359 + struct mlx5_ib_resources devr; 360 + struct mlx5_mr_cache cache; 361 + }; 362 + 363 + static inline struct mlx5_ib_cq *to_mibcq(struct mlx5_core_cq *mcq) 364 + { 365 + return container_of(mcq, struct mlx5_ib_cq, mcq); 366 + } 367 + 368 + static inline struct mlx5_ib_xrcd *to_mxrcd(struct ib_xrcd *ibxrcd) 369 + { 370 + return container_of(ibxrcd, struct mlx5_ib_xrcd, ibxrcd); 371 + } 372 + 373 + static inline struct mlx5_ib_dev *to_mdev(struct ib_device *ibdev) 374 + { 375 + return container_of(ibdev, struct mlx5_ib_dev, ib_dev); 376 + } 377 + 378 + static inline struct mlx5_ib_fmr *to_mfmr(struct ib_fmr *ibfmr) 379 + { 380 + return container_of(ibfmr, struct mlx5_ib_fmr, ibfmr); 381 + } 382 + 383 + static inline struct mlx5_ib_cq *to_mcq(struct ib_cq *ibcq) 384 + { 385 + return container_of(ibcq, struct mlx5_ib_cq, ibcq); 386 + } 387 + 388 + static inline struct mlx5_ib_qp *to_mibqp(struct mlx5_core_qp *mqp) 389 + { 390 + return container_of(mqp, struct mlx5_ib_qp, mqp); 391 + } 392 + 393 + static inline struct mlx5_ib_pd *to_mpd(struct ib_pd *ibpd) 394 + { 395 + return container_of(ibpd, struct mlx5_ib_pd, ibpd); 396 + } 397 + 398 + static inline struct mlx5_ib_srq *to_msrq(struct ib_srq *ibsrq) 399 + { 400 + return container_of(ibsrq, struct mlx5_ib_srq, ibsrq); 401 + } 402 + 403 + static inline struct mlx5_ib_qp *to_mqp(struct ib_qp *ibqp) 404 + { 405 + return container_of(ibqp, struct mlx5_ib_qp, ibqp); 406 + } 407 + 408 + static inline struct mlx5_ib_srq *to_mibsrq(struct mlx5_core_srq *msrq) 409 + { 410 + return container_of(msrq, struct mlx5_ib_srq, msrq); 411 + } 412 + 413 + static inline struct mlx5_ib_mr *to_mmr(struct ib_mr *ibmr) 414 + { 415 + return container_of(ibmr, struct mlx5_ib_mr, ibmr); 416 + } 417 + 418 + static inline struct mlx5_ib_fast_reg_page_list *to_mfrpl(struct ib_fast_reg_page_list *ibfrpl) 419 + { 420 + return container_of(ibfrpl, struct mlx5_ib_fast_reg_page_list, ibfrpl); 421 + } 422 + 423 + struct mlx5_ib_ah { 424 + struct ib_ah ibah; 425 + struct mlx5_av av; 426 + }; 427 + 428 + static inline struct mlx5_ib_ah *to_mah(struct ib_ah *ibah) 429 + { 430 + return container_of(ibah, struct mlx5_ib_ah, ibah); 431 + } 432 + 433 + static inline struct mlx5_ib_dev *mlx5_core2ibdev(struct mlx5_core_dev *dev) 434 + { 435 + return container_of(dev, struct mlx5_ib_dev, mdev); 436 + } 437 + 438 + static inline struct mlx5_ib_dev *mlx5_pci2ibdev(struct pci_dev *pdev) 439 + { 440 + return mlx5_core2ibdev(pci2mlx5_core_dev(pdev)); 441 + } 442 + 443 + int mlx5_ib_db_map_user(struct mlx5_ib_ucontext *context, unsigned long virt, 444 + struct mlx5_db *db); 445 + void mlx5_ib_db_unmap_user(struct mlx5_ib_ucontext *context, struct mlx5_db *db); 446 + void __mlx5_ib_cq_clean(struct mlx5_ib_cq *cq, u32 qpn, struct mlx5_ib_srq *srq); 447 + void mlx5_ib_cq_clean(struct mlx5_ib_cq *cq, u32 qpn, struct mlx5_ib_srq *srq); 448 + void mlx5_ib_free_srq_wqe(struct mlx5_ib_srq *srq, int wqe_index); 449 + int mlx5_MAD_IFC(struct mlx5_ib_dev *dev, int ignore_mkey, int ignore_bkey, 450 + int port, struct ib_wc *in_wc, struct ib_grh *in_grh, 451 + void *in_mad, void *response_mad); 452 + struct ib_ah *create_ib_ah(struct ib_ah_attr *ah_attr, 453 + struct mlx5_ib_ah *ah); 454 + struct ib_ah *mlx5_ib_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr); 455 + int mlx5_ib_query_ah(struct ib_ah *ibah, struct ib_ah_attr *ah_attr); 456 + int mlx5_ib_destroy_ah(struct ib_ah *ah); 457 + struct ib_srq *mlx5_ib_create_srq(struct ib_pd *pd, 458 + struct ib_srq_init_attr *init_attr, 459 + struct ib_udata *udata); 460 + int mlx5_ib_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr, 461 + enum ib_srq_attr_mask attr_mask, struct ib_udata *udata); 462 + int mlx5_ib_query_srq(struct ib_srq *ibsrq, struct ib_srq_attr *srq_attr); 463 + int mlx5_ib_destroy_srq(struct ib_srq *srq); 464 + int mlx5_ib_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr, 465 + struct ib_recv_wr **bad_wr); 466 + struct ib_qp *mlx5_ib_create_qp(struct ib_pd *pd, 467 + struct ib_qp_init_attr *init_attr, 468 + struct ib_udata *udata); 469 + int mlx5_ib_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, 470 + int attr_mask, struct ib_udata *udata); 471 + int mlx5_ib_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr, int qp_attr_mask, 472 + struct ib_qp_init_attr *qp_init_attr); 473 + int mlx5_ib_destroy_qp(struct ib_qp *qp); 474 + int mlx5_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, 475 + struct ib_send_wr **bad_wr); 476 + int mlx5_ib_post_recv(struct ib_qp *ibqp, struct ib_recv_wr *wr, 477 + struct ib_recv_wr **bad_wr); 478 + void *mlx5_get_send_wqe(struct mlx5_ib_qp *qp, int n); 479 + struct ib_cq *mlx5_ib_create_cq(struct ib_device *ibdev, int entries, 480 + int vector, struct ib_ucontext *context, 481 + struct ib_udata *udata); 482 + int mlx5_ib_destroy_cq(struct ib_cq *cq); 483 + int mlx5_ib_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc); 484 + int mlx5_ib_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags flags); 485 + int mlx5_ib_modify_cq(struct ib_cq *cq, u16 cq_count, u16 cq_period); 486 + int mlx5_ib_resize_cq(struct ib_cq *ibcq, int entries, struct ib_udata *udata); 487 + struct ib_mr *mlx5_ib_get_dma_mr(struct ib_pd *pd, int acc); 488 + struct ib_mr *mlx5_ib_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, 489 + u64 virt_addr, int access_flags, 490 + struct ib_udata *udata); 491 + int mlx5_ib_dereg_mr(struct ib_mr *ibmr); 492 + struct ib_mr *mlx5_ib_alloc_fast_reg_mr(struct ib_pd *pd, 493 + int max_page_list_len); 494 + struct ib_fast_reg_page_list *mlx5_ib_alloc_fast_reg_page_list(struct ib_device *ibdev, 495 + int page_list_len); 496 + void mlx5_ib_free_fast_reg_page_list(struct ib_fast_reg_page_list *page_list); 497 + struct ib_fmr *mlx5_ib_fmr_alloc(struct ib_pd *pd, int acc, 498 + struct ib_fmr_attr *fmr_attr); 499 + int mlx5_ib_map_phys_fmr(struct ib_fmr *ibfmr, u64 *page_list, 500 + int npages, u64 iova); 501 + int mlx5_ib_unmap_fmr(struct list_head *fmr_list); 502 + int mlx5_ib_fmr_dealloc(struct ib_fmr *ibfmr); 503 + int mlx5_ib_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num, 504 + struct ib_wc *in_wc, struct ib_grh *in_grh, 505 + struct ib_mad *in_mad, struct ib_mad *out_mad); 506 + struct ib_xrcd *mlx5_ib_alloc_xrcd(struct ib_device *ibdev, 507 + struct ib_ucontext *context, 508 + struct ib_udata *udata); 509 + int mlx5_ib_dealloc_xrcd(struct ib_xrcd *xrcd); 510 + int mlx5_vector2eqn(struct mlx5_ib_dev *dev, int vector, int *eqn, int *irqn); 511 + int mlx5_ib_get_buf_offset(u64 addr, int page_shift, u32 *offset); 512 + int mlx5_query_ext_port_caps(struct mlx5_ib_dev *dev, u8 port); 513 + int mlx5_ib_query_port(struct ib_device *ibdev, u8 port, 514 + struct ib_port_attr *props); 515 + int mlx5_ib_init_fmr(struct mlx5_ib_dev *dev); 516 + void mlx5_ib_cleanup_fmr(struct mlx5_ib_dev *dev); 517 + void mlx5_ib_cont_pages(struct ib_umem *umem, u64 addr, int *count, int *shift, 518 + int *ncont, int *order); 519 + void mlx5_ib_populate_pas(struct mlx5_ib_dev *dev, struct ib_umem *umem, 520 + int page_shift, __be64 *pas, int umr); 521 + void mlx5_ib_copy_pas(u64 *old, u64 *new, int step, int num); 522 + int mlx5_ib_get_cqe_size(struct mlx5_ib_dev *dev, struct ib_cq *ibcq); 523 + int mlx5_mr_cache_init(struct mlx5_ib_dev *dev); 524 + int mlx5_mr_cache_cleanup(struct mlx5_ib_dev *dev); 525 + int mlx5_mr_ib_cont_pages(struct ib_umem *umem, u64 addr, int *count, int *shift); 526 + void mlx5_umr_cq_handler(struct ib_cq *cq, void *cq_context); 527 + 528 + static inline void init_query_mad(struct ib_smp *mad) 529 + { 530 + mad->base_version = 1; 531 + mad->mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED; 532 + mad->class_version = 1; 533 + mad->method = IB_MGMT_METHOD_GET; 534 + } 535 + 536 + static inline u8 convert_access(int acc) 537 + { 538 + return (acc & IB_ACCESS_REMOTE_ATOMIC ? MLX5_PERM_ATOMIC : 0) | 539 + (acc & IB_ACCESS_REMOTE_WRITE ? MLX5_PERM_REMOTE_WRITE : 0) | 540 + (acc & IB_ACCESS_REMOTE_READ ? MLX5_PERM_REMOTE_READ : 0) | 541 + (acc & IB_ACCESS_LOCAL_WRITE ? MLX5_PERM_LOCAL_WRITE : 0) | 542 + MLX5_PERM_LOCAL_READ; 543 + } 544 + 545 + #endif /* MLX5_IB_H */
+1007
drivers/infiniband/hw/mlx5/mr.c
··· 1 + /* 2 + * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved. 3 + * 4 + * This software is available to you under a choice of one of two 5 + * licenses. You may choose to be licensed under the terms of the GNU 6 + * General Public License (GPL) Version 2, available from the file 7 + * COPYING in the main directory of this source tree, or the 8 + * OpenIB.org BSD license below: 9 + * 10 + * Redistribution and use in source and binary forms, with or 11 + * without modification, are permitted provided that the following 12 + * conditions are met: 13 + * 14 + * - Redistributions of source code must retain the above 15 + * copyright notice, this list of conditions and the following 16 + * disclaimer. 17 + * 18 + * - Redistributions in binary form must reproduce the above 19 + * copyright notice, this list of conditions and the following 20 + * disclaimer in the documentation and/or other materials 21 + * 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 OF 25 + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26 + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 27 + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 28 + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29 + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30 + * SOFTWARE. 31 + */ 32 + 33 + 34 + #include <linux/kref.h> 35 + #include <linux/random.h> 36 + #include <linux/debugfs.h> 37 + #include <linux/export.h> 38 + #include <rdma/ib_umem.h> 39 + #include "mlx5_ib.h" 40 + 41 + enum { 42 + DEF_CACHE_SIZE = 10, 43 + }; 44 + 45 + static __be64 *mr_align(__be64 *ptr, int align) 46 + { 47 + unsigned long mask = align - 1; 48 + 49 + return (__be64 *)(((unsigned long)ptr + mask) & ~mask); 50 + } 51 + 52 + static int order2idx(struct mlx5_ib_dev *dev, int order) 53 + { 54 + struct mlx5_mr_cache *cache = &dev->cache; 55 + 56 + if (order < cache->ent[0].order) 57 + return 0; 58 + else 59 + return order - cache->ent[0].order; 60 + } 61 + 62 + static int add_keys(struct mlx5_ib_dev *dev, int c, int num) 63 + { 64 + struct device *ddev = dev->ib_dev.dma_device; 65 + struct mlx5_mr_cache *cache = &dev->cache; 66 + struct mlx5_cache_ent *ent = &cache->ent[c]; 67 + struct mlx5_create_mkey_mbox_in *in; 68 + struct mlx5_ib_mr *mr; 69 + int npages = 1 << ent->order; 70 + int size = sizeof(u64) * npages; 71 + int err = 0; 72 + int i; 73 + 74 + in = kzalloc(sizeof(*in), GFP_KERNEL); 75 + if (!in) 76 + return -ENOMEM; 77 + 78 + for (i = 0; i < num; i++) { 79 + mr = kzalloc(sizeof(*mr), GFP_KERNEL); 80 + if (!mr) { 81 + err = -ENOMEM; 82 + goto out; 83 + } 84 + mr->order = ent->order; 85 + mr->umred = 1; 86 + mr->pas = kmalloc(size + 0x3f, GFP_KERNEL); 87 + if (!mr->pas) { 88 + kfree(mr); 89 + err = -ENOMEM; 90 + goto out; 91 + } 92 + mr->dma = dma_map_single(ddev, mr_align(mr->pas, 0x40), size, 93 + DMA_TO_DEVICE); 94 + if (dma_mapping_error(ddev, mr->dma)) { 95 + kfree(mr->pas); 96 + kfree(mr); 97 + err = -ENOMEM; 98 + goto out; 99 + } 100 + 101 + in->seg.status = 1 << 6; 102 + in->seg.xlt_oct_size = cpu_to_be32((npages + 1) / 2); 103 + in->seg.qpn_mkey7_0 = cpu_to_be32(0xffffff << 8); 104 + in->seg.flags = MLX5_ACCESS_MODE_MTT | MLX5_PERM_UMR_EN; 105 + in->seg.log2_page_size = 12; 106 + 107 + err = mlx5_core_create_mkey(&dev->mdev, &mr->mmr, in, 108 + sizeof(*in)); 109 + if (err) { 110 + mlx5_ib_warn(dev, "create mkey failed %d\n", err); 111 + dma_unmap_single(ddev, mr->dma, size, DMA_TO_DEVICE); 112 + kfree(mr->pas); 113 + kfree(mr); 114 + goto out; 115 + } 116 + cache->last_add = jiffies; 117 + 118 + spin_lock(&ent->lock); 119 + list_add_tail(&mr->list, &ent->head); 120 + ent->cur++; 121 + ent->size++; 122 + spin_unlock(&ent->lock); 123 + } 124 + 125 + out: 126 + kfree(in); 127 + return err; 128 + } 129 + 130 + static void remove_keys(struct mlx5_ib_dev *dev, int c, int num) 131 + { 132 + struct device *ddev = dev->ib_dev.dma_device; 133 + struct mlx5_mr_cache *cache = &dev->cache; 134 + struct mlx5_cache_ent *ent = &cache->ent[c]; 135 + struct mlx5_ib_mr *mr; 136 + int size; 137 + int err; 138 + int i; 139 + 140 + for (i = 0; i < num; i++) { 141 + spin_lock(&ent->lock); 142 + if (list_empty(&ent->head)) { 143 + spin_unlock(&ent->lock); 144 + return; 145 + } 146 + mr = list_first_entry(&ent->head, struct mlx5_ib_mr, list); 147 + list_del(&mr->list); 148 + ent->cur--; 149 + ent->size--; 150 + spin_unlock(&ent->lock); 151 + err = mlx5_core_destroy_mkey(&dev->mdev, &mr->mmr); 152 + if (err) { 153 + mlx5_ib_warn(dev, "failed destroy mkey\n"); 154 + } else { 155 + size = ALIGN(sizeof(u64) * (1 << mr->order), 0x40); 156 + dma_unmap_single(ddev, mr->dma, size, DMA_TO_DEVICE); 157 + kfree(mr->pas); 158 + kfree(mr); 159 + } 160 + } 161 + } 162 + 163 + static ssize_t size_write(struct file *filp, const char __user *buf, 164 + size_t count, loff_t *pos) 165 + { 166 + struct mlx5_cache_ent *ent = filp->private_data; 167 + struct mlx5_ib_dev *dev = ent->dev; 168 + char lbuf[20]; 169 + u32 var; 170 + int err; 171 + int c; 172 + 173 + if (copy_from_user(lbuf, buf, sizeof(lbuf))) 174 + return -EPERM; 175 + 176 + c = order2idx(dev, ent->order); 177 + lbuf[sizeof(lbuf) - 1] = 0; 178 + 179 + if (sscanf(lbuf, "%u", &var) != 1) 180 + return -EINVAL; 181 + 182 + if (var < ent->limit) 183 + return -EINVAL; 184 + 185 + if (var > ent->size) { 186 + err = add_keys(dev, c, var - ent->size); 187 + if (err) 188 + return err; 189 + } else if (var < ent->size) { 190 + remove_keys(dev, c, ent->size - var); 191 + } 192 + 193 + return count; 194 + } 195 + 196 + static ssize_t size_read(struct file *filp, char __user *buf, size_t count, 197 + loff_t *pos) 198 + { 199 + struct mlx5_cache_ent *ent = filp->private_data; 200 + char lbuf[20]; 201 + int err; 202 + 203 + if (*pos) 204 + return 0; 205 + 206 + err = snprintf(lbuf, sizeof(lbuf), "%d\n", ent->size); 207 + if (err < 0) 208 + return err; 209 + 210 + if (copy_to_user(buf, lbuf, err)) 211 + return -EPERM; 212 + 213 + *pos += err; 214 + 215 + return err; 216 + } 217 + 218 + static const struct file_operations size_fops = { 219 + .owner = THIS_MODULE, 220 + .open = simple_open, 221 + .write = size_write, 222 + .read = size_read, 223 + }; 224 + 225 + static ssize_t limit_write(struct file *filp, const char __user *buf, 226 + size_t count, loff_t *pos) 227 + { 228 + struct mlx5_cache_ent *ent = filp->private_data; 229 + struct mlx5_ib_dev *dev = ent->dev; 230 + char lbuf[20]; 231 + u32 var; 232 + int err; 233 + int c; 234 + 235 + if (copy_from_user(lbuf, buf, sizeof(lbuf))) 236 + return -EPERM; 237 + 238 + c = order2idx(dev, ent->order); 239 + lbuf[sizeof(lbuf) - 1] = 0; 240 + 241 + if (sscanf(lbuf, "%u", &var) != 1) 242 + return -EINVAL; 243 + 244 + if (var > ent->size) 245 + return -EINVAL; 246 + 247 + ent->limit = var; 248 + 249 + if (ent->cur < ent->limit) { 250 + err = add_keys(dev, c, 2 * ent->limit - ent->cur); 251 + if (err) 252 + return err; 253 + } 254 + 255 + return count; 256 + } 257 + 258 + static ssize_t limit_read(struct file *filp, char __user *buf, size_t count, 259 + loff_t *pos) 260 + { 261 + struct mlx5_cache_ent *ent = filp->private_data; 262 + char lbuf[20]; 263 + int err; 264 + 265 + if (*pos) 266 + return 0; 267 + 268 + err = snprintf(lbuf, sizeof(lbuf), "%d\n", ent->limit); 269 + if (err < 0) 270 + return err; 271 + 272 + if (copy_to_user(buf, lbuf, err)) 273 + return -EPERM; 274 + 275 + *pos += err; 276 + 277 + return err; 278 + } 279 + 280 + static const struct file_operations limit_fops = { 281 + .owner = THIS_MODULE, 282 + .open = simple_open, 283 + .write = limit_write, 284 + .read = limit_read, 285 + }; 286 + 287 + static int someone_adding(struct mlx5_mr_cache *cache) 288 + { 289 + int i; 290 + 291 + for (i = 0; i < MAX_MR_CACHE_ENTRIES; i++) { 292 + if (cache->ent[i].cur < cache->ent[i].limit) 293 + return 1; 294 + } 295 + 296 + return 0; 297 + } 298 + 299 + static void __cache_work_func(struct mlx5_cache_ent *ent) 300 + { 301 + struct mlx5_ib_dev *dev = ent->dev; 302 + struct mlx5_mr_cache *cache = &dev->cache; 303 + int i = order2idx(dev, ent->order); 304 + 305 + if (cache->stopped) 306 + return; 307 + 308 + ent = &dev->cache.ent[i]; 309 + if (ent->cur < 2 * ent->limit) { 310 + add_keys(dev, i, 1); 311 + if (ent->cur < 2 * ent->limit) 312 + queue_work(cache->wq, &ent->work); 313 + } else if (ent->cur > 2 * ent->limit) { 314 + if (!someone_adding(cache) && 315 + time_after(jiffies, cache->last_add + 60 * HZ)) { 316 + remove_keys(dev, i, 1); 317 + if (ent->cur > ent->limit) 318 + queue_work(cache->wq, &ent->work); 319 + } else { 320 + queue_delayed_work(cache->wq, &ent->dwork, 60 * HZ); 321 + } 322 + } 323 + } 324 + 325 + static void delayed_cache_work_func(struct work_struct *work) 326 + { 327 + struct mlx5_cache_ent *ent; 328 + 329 + ent = container_of(work, struct mlx5_cache_ent, dwork.work); 330 + __cache_work_func(ent); 331 + } 332 + 333 + static void cache_work_func(struct work_struct *work) 334 + { 335 + struct mlx5_cache_ent *ent; 336 + 337 + ent = container_of(work, struct mlx5_cache_ent, work); 338 + __cache_work_func(ent); 339 + } 340 + 341 + static struct mlx5_ib_mr *alloc_cached_mr(struct mlx5_ib_dev *dev, int order) 342 + { 343 + struct mlx5_mr_cache *cache = &dev->cache; 344 + struct mlx5_ib_mr *mr = NULL; 345 + struct mlx5_cache_ent *ent; 346 + int c; 347 + int i; 348 + 349 + c = order2idx(dev, order); 350 + if (c < 0 || c >= MAX_MR_CACHE_ENTRIES) { 351 + mlx5_ib_warn(dev, "order %d, cache index %d\n", order, c); 352 + return NULL; 353 + } 354 + 355 + for (i = c; i < MAX_MR_CACHE_ENTRIES; i++) { 356 + ent = &cache->ent[i]; 357 + 358 + mlx5_ib_dbg(dev, "order %d, cache index %d\n", ent->order, i); 359 + 360 + spin_lock(&ent->lock); 361 + if (!list_empty(&ent->head)) { 362 + mr = list_first_entry(&ent->head, struct mlx5_ib_mr, 363 + list); 364 + list_del(&mr->list); 365 + ent->cur--; 366 + spin_unlock(&ent->lock); 367 + if (ent->cur < ent->limit) 368 + queue_work(cache->wq, &ent->work); 369 + break; 370 + } 371 + spin_unlock(&ent->lock); 372 + 373 + queue_work(cache->wq, &ent->work); 374 + 375 + if (mr) 376 + break; 377 + } 378 + 379 + if (!mr) 380 + cache->ent[c].miss++; 381 + 382 + return mr; 383 + } 384 + 385 + static void free_cached_mr(struct mlx5_ib_dev *dev, struct mlx5_ib_mr *mr) 386 + { 387 + struct mlx5_mr_cache *cache = &dev->cache; 388 + struct mlx5_cache_ent *ent; 389 + int shrink = 0; 390 + int c; 391 + 392 + c = order2idx(dev, mr->order); 393 + if (c < 0 || c >= MAX_MR_CACHE_ENTRIES) { 394 + mlx5_ib_warn(dev, "order %d, cache index %d\n", mr->order, c); 395 + return; 396 + } 397 + ent = &cache->ent[c]; 398 + spin_lock(&ent->lock); 399 + list_add_tail(&mr->list, &ent->head); 400 + ent->cur++; 401 + if (ent->cur > 2 * ent->limit) 402 + shrink = 1; 403 + spin_unlock(&ent->lock); 404 + 405 + if (shrink) 406 + queue_work(cache->wq, &ent->work); 407 + } 408 + 409 + static void clean_keys(struct mlx5_ib_dev *dev, int c) 410 + { 411 + struct device *ddev = dev->ib_dev.dma_device; 412 + struct mlx5_mr_cache *cache = &dev->cache; 413 + struct mlx5_cache_ent *ent = &cache->ent[c]; 414 + struct mlx5_ib_mr *mr; 415 + int size; 416 + int err; 417 + 418 + while (1) { 419 + spin_lock(&ent->lock); 420 + if (list_empty(&ent->head)) { 421 + spin_unlock(&ent->lock); 422 + return; 423 + } 424 + mr = list_first_entry(&ent->head, struct mlx5_ib_mr, list); 425 + list_del(&mr->list); 426 + ent->cur--; 427 + ent->size--; 428 + spin_unlock(&ent->lock); 429 + err = mlx5_core_destroy_mkey(&dev->mdev, &mr->mmr); 430 + if (err) { 431 + mlx5_ib_warn(dev, "failed destroy mkey\n"); 432 + } else { 433 + size = ALIGN(sizeof(u64) * (1 << mr->order), 0x40); 434 + dma_unmap_single(ddev, mr->dma, size, DMA_TO_DEVICE); 435 + kfree(mr->pas); 436 + kfree(mr); 437 + } 438 + } 439 + } 440 + 441 + static int mlx5_mr_cache_debugfs_init(struct mlx5_ib_dev *dev) 442 + { 443 + struct mlx5_mr_cache *cache = &dev->cache; 444 + struct mlx5_cache_ent *ent; 445 + int i; 446 + 447 + if (!mlx5_debugfs_root) 448 + return 0; 449 + 450 + cache->root = debugfs_create_dir("mr_cache", dev->mdev.priv.dbg_root); 451 + if (!cache->root) 452 + return -ENOMEM; 453 + 454 + for (i = 0; i < MAX_MR_CACHE_ENTRIES; i++) { 455 + ent = &cache->ent[i]; 456 + sprintf(ent->name, "%d", ent->order); 457 + ent->dir = debugfs_create_dir(ent->name, cache->root); 458 + if (!ent->dir) 459 + return -ENOMEM; 460 + 461 + ent->fsize = debugfs_create_file("size", 0600, ent->dir, ent, 462 + &size_fops); 463 + if (!ent->fsize) 464 + return -ENOMEM; 465 + 466 + ent->flimit = debugfs_create_file("limit", 0600, ent->dir, ent, 467 + &limit_fops); 468 + if (!ent->flimit) 469 + return -ENOMEM; 470 + 471 + ent->fcur = debugfs_create_u32("cur", 0400, ent->dir, 472 + &ent->cur); 473 + if (!ent->fcur) 474 + return -ENOMEM; 475 + 476 + ent->fmiss = debugfs_create_u32("miss", 0600, ent->dir, 477 + &ent->miss); 478 + if (!ent->fmiss) 479 + return -ENOMEM; 480 + } 481 + 482 + return 0; 483 + } 484 + 485 + static void mlx5_mr_cache_debugfs_cleanup(struct mlx5_ib_dev *dev) 486 + { 487 + if (!mlx5_debugfs_root) 488 + return; 489 + 490 + debugfs_remove_recursive(dev->cache.root); 491 + } 492 + 493 + int mlx5_mr_cache_init(struct mlx5_ib_dev *dev) 494 + { 495 + struct mlx5_mr_cache *cache = &dev->cache; 496 + struct mlx5_cache_ent *ent; 497 + int limit; 498 + int size; 499 + int err; 500 + int i; 501 + 502 + cache->wq = create_singlethread_workqueue("mkey_cache"); 503 + if (!cache->wq) { 504 + mlx5_ib_warn(dev, "failed to create work queue\n"); 505 + return -ENOMEM; 506 + } 507 + 508 + for (i = 0; i < MAX_MR_CACHE_ENTRIES; i++) { 509 + INIT_LIST_HEAD(&cache->ent[i].head); 510 + spin_lock_init(&cache->ent[i].lock); 511 + 512 + ent = &cache->ent[i]; 513 + INIT_LIST_HEAD(&ent->head); 514 + spin_lock_init(&ent->lock); 515 + ent->order = i + 2; 516 + ent->dev = dev; 517 + 518 + if (dev->mdev.profile->mask & MLX5_PROF_MASK_MR_CACHE) { 519 + size = dev->mdev.profile->mr_cache[i].size; 520 + limit = dev->mdev.profile->mr_cache[i].limit; 521 + } else { 522 + size = DEF_CACHE_SIZE; 523 + limit = 0; 524 + } 525 + INIT_WORK(&ent->work, cache_work_func); 526 + INIT_DELAYED_WORK(&ent->dwork, delayed_cache_work_func); 527 + ent->limit = limit; 528 + queue_work(cache->wq, &ent->work); 529 + } 530 + 531 + err = mlx5_mr_cache_debugfs_init(dev); 532 + if (err) 533 + mlx5_ib_warn(dev, "cache debugfs failure\n"); 534 + 535 + return 0; 536 + } 537 + 538 + int mlx5_mr_cache_cleanup(struct mlx5_ib_dev *dev) 539 + { 540 + int i; 541 + 542 + dev->cache.stopped = 1; 543 + destroy_workqueue(dev->cache.wq); 544 + 545 + mlx5_mr_cache_debugfs_cleanup(dev); 546 + 547 + for (i = 0; i < MAX_MR_CACHE_ENTRIES; i++) 548 + clean_keys(dev, i); 549 + 550 + return 0; 551 + } 552 + 553 + struct ib_mr *mlx5_ib_get_dma_mr(struct ib_pd *pd, int acc) 554 + { 555 + struct mlx5_ib_dev *dev = to_mdev(pd->device); 556 + struct mlx5_core_dev *mdev = &dev->mdev; 557 + struct mlx5_create_mkey_mbox_in *in; 558 + struct mlx5_mkey_seg *seg; 559 + struct mlx5_ib_mr *mr; 560 + int err; 561 + 562 + mr = kzalloc(sizeof(*mr), GFP_KERNEL); 563 + if (!mr) 564 + return ERR_PTR(-ENOMEM); 565 + 566 + in = kzalloc(sizeof(*in), GFP_KERNEL); 567 + if (!in) { 568 + err = -ENOMEM; 569 + goto err_free; 570 + } 571 + 572 + seg = &in->seg; 573 + seg->flags = convert_access(acc) | MLX5_ACCESS_MODE_PA; 574 + seg->flags_pd = cpu_to_be32(to_mpd(pd)->pdn | MLX5_MKEY_LEN64); 575 + seg->qpn_mkey7_0 = cpu_to_be32(0xffffff << 8); 576 + seg->start_addr = 0; 577 + 578 + err = mlx5_core_create_mkey(mdev, &mr->mmr, in, sizeof(*in)); 579 + if (err) 580 + goto err_in; 581 + 582 + kfree(in); 583 + mr->ibmr.lkey = mr->mmr.key; 584 + mr->ibmr.rkey = mr->mmr.key; 585 + mr->umem = NULL; 586 + 587 + return &mr->ibmr; 588 + 589 + err_in: 590 + kfree(in); 591 + 592 + err_free: 593 + kfree(mr); 594 + 595 + return ERR_PTR(err); 596 + } 597 + 598 + static int get_octo_len(u64 addr, u64 len, int page_size) 599 + { 600 + u64 offset; 601 + int npages; 602 + 603 + offset = addr & (page_size - 1); 604 + npages = ALIGN(len + offset, page_size) >> ilog2(page_size); 605 + return (npages + 1) / 2; 606 + } 607 + 608 + static int use_umr(int order) 609 + { 610 + return order <= 17; 611 + } 612 + 613 + static void prep_umr_reg_wqe(struct ib_pd *pd, struct ib_send_wr *wr, 614 + struct ib_sge *sg, u64 dma, int n, u32 key, 615 + int page_shift, u64 virt_addr, u64 len, 616 + int access_flags) 617 + { 618 + struct mlx5_ib_dev *dev = to_mdev(pd->device); 619 + struct ib_mr *mr = dev->umrc.mr; 620 + 621 + sg->addr = dma; 622 + sg->length = ALIGN(sizeof(u64) * n, 64); 623 + sg->lkey = mr->lkey; 624 + 625 + wr->next = NULL; 626 + wr->send_flags = 0; 627 + wr->sg_list = sg; 628 + if (n) 629 + wr->num_sge = 1; 630 + else 631 + wr->num_sge = 0; 632 + 633 + wr->opcode = MLX5_IB_WR_UMR; 634 + wr->wr.fast_reg.page_list_len = n; 635 + wr->wr.fast_reg.page_shift = page_shift; 636 + wr->wr.fast_reg.rkey = key; 637 + wr->wr.fast_reg.iova_start = virt_addr; 638 + wr->wr.fast_reg.length = len; 639 + wr->wr.fast_reg.access_flags = access_flags; 640 + wr->wr.fast_reg.page_list = (struct ib_fast_reg_page_list *)pd; 641 + } 642 + 643 + static void prep_umr_unreg_wqe(struct mlx5_ib_dev *dev, 644 + struct ib_send_wr *wr, u32 key) 645 + { 646 + wr->send_flags = MLX5_IB_SEND_UMR_UNREG; 647 + wr->opcode = MLX5_IB_WR_UMR; 648 + wr->wr.fast_reg.rkey = key; 649 + } 650 + 651 + void mlx5_umr_cq_handler(struct ib_cq *cq, void *cq_context) 652 + { 653 + struct mlx5_ib_mr *mr; 654 + struct ib_wc wc; 655 + int err; 656 + 657 + while (1) { 658 + err = ib_poll_cq(cq, 1, &wc); 659 + if (err < 0) { 660 + pr_warn("poll cq error %d\n", err); 661 + return; 662 + } 663 + if (err == 0) 664 + break; 665 + 666 + mr = (struct mlx5_ib_mr *)(unsigned long)wc.wr_id; 667 + mr->status = wc.status; 668 + complete(&mr->done); 669 + } 670 + ib_req_notify_cq(cq, IB_CQ_NEXT_COMP); 671 + } 672 + 673 + static struct mlx5_ib_mr *reg_umr(struct ib_pd *pd, struct ib_umem *umem, 674 + u64 virt_addr, u64 len, int npages, 675 + int page_shift, int order, int access_flags) 676 + { 677 + struct mlx5_ib_dev *dev = to_mdev(pd->device); 678 + struct umr_common *umrc = &dev->umrc; 679 + struct ib_send_wr wr, *bad; 680 + struct mlx5_ib_mr *mr; 681 + struct ib_sge sg; 682 + int err; 683 + int i; 684 + 685 + for (i = 0; i < 10; i++) { 686 + mr = alloc_cached_mr(dev, order); 687 + if (mr) 688 + break; 689 + 690 + err = add_keys(dev, order2idx(dev, order), 1); 691 + if (err) { 692 + mlx5_ib_warn(dev, "add_keys failed\n"); 693 + break; 694 + } 695 + } 696 + 697 + if (!mr) 698 + return ERR_PTR(-EAGAIN); 699 + 700 + mlx5_ib_populate_pas(dev, umem, page_shift, mr_align(mr->pas, 0x40), 1); 701 + 702 + memset(&wr, 0, sizeof(wr)); 703 + wr.wr_id = (u64)(unsigned long)mr; 704 + prep_umr_reg_wqe(pd, &wr, &sg, mr->dma, npages, mr->mmr.key, page_shift, virt_addr, len, access_flags); 705 + 706 + /* We serialize polls so one process does not kidnap another's 707 + * completion. This is not a problem since wr is completed in 708 + * around 1 usec 709 + */ 710 + down(&umrc->sem); 711 + init_completion(&mr->done); 712 + err = ib_post_send(umrc->qp, &wr, &bad); 713 + if (err) { 714 + mlx5_ib_warn(dev, "post send failed, err %d\n", err); 715 + up(&umrc->sem); 716 + goto error; 717 + } 718 + wait_for_completion(&mr->done); 719 + up(&umrc->sem); 720 + 721 + if (mr->status != IB_WC_SUCCESS) { 722 + mlx5_ib_warn(dev, "reg umr failed\n"); 723 + err = -EFAULT; 724 + goto error; 725 + } 726 + 727 + return mr; 728 + 729 + error: 730 + free_cached_mr(dev, mr); 731 + return ERR_PTR(err); 732 + } 733 + 734 + static struct mlx5_ib_mr *reg_create(struct ib_pd *pd, u64 virt_addr, 735 + u64 length, struct ib_umem *umem, 736 + int npages, int page_shift, 737 + int access_flags) 738 + { 739 + struct mlx5_ib_dev *dev = to_mdev(pd->device); 740 + struct mlx5_create_mkey_mbox_in *in; 741 + struct mlx5_ib_mr *mr; 742 + int inlen; 743 + int err; 744 + 745 + mr = kzalloc(sizeof(*mr), GFP_KERNEL); 746 + if (!mr) 747 + return ERR_PTR(-ENOMEM); 748 + 749 + inlen = sizeof(*in) + sizeof(*in->pas) * ((npages + 1) / 2) * 2; 750 + in = mlx5_vzalloc(inlen); 751 + if (!in) { 752 + err = -ENOMEM; 753 + goto err_1; 754 + } 755 + mlx5_ib_populate_pas(dev, umem, page_shift, in->pas, 0); 756 + 757 + in->seg.flags = convert_access(access_flags) | 758 + MLX5_ACCESS_MODE_MTT; 759 + in->seg.flags_pd = cpu_to_be32(to_mpd(pd)->pdn); 760 + in->seg.start_addr = cpu_to_be64(virt_addr); 761 + in->seg.len = cpu_to_be64(length); 762 + in->seg.bsfs_octo_size = 0; 763 + in->seg.xlt_oct_size = cpu_to_be32(get_octo_len(virt_addr, length, 1 << page_shift)); 764 + in->seg.log2_page_size = page_shift; 765 + in->seg.qpn_mkey7_0 = cpu_to_be32(0xffffff << 8); 766 + in->xlat_oct_act_size = cpu_to_be32(get_octo_len(virt_addr, length, 1 << page_shift)); 767 + err = mlx5_core_create_mkey(&dev->mdev, &mr->mmr, in, inlen); 768 + if (err) { 769 + mlx5_ib_warn(dev, "create mkey failed\n"); 770 + goto err_2; 771 + } 772 + mr->umem = umem; 773 + mlx5_vfree(in); 774 + 775 + mlx5_ib_dbg(dev, "mkey = 0x%x\n", mr->mmr.key); 776 + 777 + return mr; 778 + 779 + err_2: 780 + mlx5_vfree(in); 781 + 782 + err_1: 783 + kfree(mr); 784 + 785 + return ERR_PTR(err); 786 + } 787 + 788 + struct ib_mr *mlx5_ib_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, 789 + u64 virt_addr, int access_flags, 790 + struct ib_udata *udata) 791 + { 792 + struct mlx5_ib_dev *dev = to_mdev(pd->device); 793 + struct mlx5_ib_mr *mr = NULL; 794 + struct ib_umem *umem; 795 + int page_shift; 796 + int npages; 797 + int ncont; 798 + int order; 799 + int err; 800 + 801 + mlx5_ib_dbg(dev, "start 0x%llx, virt_addr 0x%llx, length 0x%llx\n", 802 + start, virt_addr, length); 803 + umem = ib_umem_get(pd->uobject->context, start, length, access_flags, 804 + 0); 805 + if (IS_ERR(umem)) { 806 + mlx5_ib_dbg(dev, "umem get failed\n"); 807 + return (void *)umem; 808 + } 809 + 810 + mlx5_ib_cont_pages(umem, start, &npages, &page_shift, &ncont, &order); 811 + if (!npages) { 812 + mlx5_ib_warn(dev, "avoid zero region\n"); 813 + err = -EINVAL; 814 + goto error; 815 + } 816 + 817 + mlx5_ib_dbg(dev, "npages %d, ncont %d, order %d, page_shift %d\n", 818 + npages, ncont, order, page_shift); 819 + 820 + if (use_umr(order)) { 821 + mr = reg_umr(pd, umem, virt_addr, length, ncont, page_shift, 822 + order, access_flags); 823 + if (PTR_ERR(mr) == -EAGAIN) { 824 + mlx5_ib_dbg(dev, "cache empty for order %d", order); 825 + mr = NULL; 826 + } 827 + } 828 + 829 + if (!mr) 830 + mr = reg_create(pd, virt_addr, length, umem, ncont, page_shift, 831 + access_flags); 832 + 833 + if (IS_ERR(mr)) { 834 + err = PTR_ERR(mr); 835 + goto error; 836 + } 837 + 838 + mlx5_ib_dbg(dev, "mkey 0x%x\n", mr->mmr.key); 839 + 840 + mr->umem = umem; 841 + mr->npages = npages; 842 + spin_lock(&dev->mr_lock); 843 + dev->mdev.priv.reg_pages += npages; 844 + spin_unlock(&dev->mr_lock); 845 + mr->ibmr.lkey = mr->mmr.key; 846 + mr->ibmr.rkey = mr->mmr.key; 847 + 848 + return &mr->ibmr; 849 + 850 + error: 851 + ib_umem_release(umem); 852 + return ERR_PTR(err); 853 + } 854 + 855 + static int unreg_umr(struct mlx5_ib_dev *dev, struct mlx5_ib_mr *mr) 856 + { 857 + struct umr_common *umrc = &dev->umrc; 858 + struct ib_send_wr wr, *bad; 859 + int err; 860 + 861 + memset(&wr, 0, sizeof(wr)); 862 + wr.wr_id = (u64)(unsigned long)mr; 863 + prep_umr_unreg_wqe(dev, &wr, mr->mmr.key); 864 + 865 + down(&umrc->sem); 866 + init_completion(&mr->done); 867 + err = ib_post_send(umrc->qp, &wr, &bad); 868 + if (err) { 869 + up(&umrc->sem); 870 + mlx5_ib_dbg(dev, "err %d\n", err); 871 + goto error; 872 + } 873 + wait_for_completion(&mr->done); 874 + up(&umrc->sem); 875 + if (mr->status != IB_WC_SUCCESS) { 876 + mlx5_ib_warn(dev, "unreg umr failed\n"); 877 + err = -EFAULT; 878 + goto error; 879 + } 880 + return 0; 881 + 882 + error: 883 + return err; 884 + } 885 + 886 + int mlx5_ib_dereg_mr(struct ib_mr *ibmr) 887 + { 888 + struct mlx5_ib_dev *dev = to_mdev(ibmr->device); 889 + struct mlx5_ib_mr *mr = to_mmr(ibmr); 890 + struct ib_umem *umem = mr->umem; 891 + int npages = mr->npages; 892 + int umred = mr->umred; 893 + int err; 894 + 895 + if (!umred) { 896 + err = mlx5_core_destroy_mkey(&dev->mdev, &mr->mmr); 897 + if (err) { 898 + mlx5_ib_warn(dev, "failed to destroy mkey 0x%x (%d)\n", 899 + mr->mmr.key, err); 900 + return err; 901 + } 902 + } else { 903 + err = unreg_umr(dev, mr); 904 + if (err) { 905 + mlx5_ib_warn(dev, "failed unregister\n"); 906 + return err; 907 + } 908 + free_cached_mr(dev, mr); 909 + } 910 + 911 + if (umem) { 912 + ib_umem_release(umem); 913 + spin_lock(&dev->mr_lock); 914 + dev->mdev.priv.reg_pages -= npages; 915 + spin_unlock(&dev->mr_lock); 916 + } 917 + 918 + if (!umred) 919 + kfree(mr); 920 + 921 + return 0; 922 + } 923 + 924 + struct ib_mr *mlx5_ib_alloc_fast_reg_mr(struct ib_pd *pd, 925 + int max_page_list_len) 926 + { 927 + struct mlx5_ib_dev *dev = to_mdev(pd->device); 928 + struct mlx5_create_mkey_mbox_in *in; 929 + struct mlx5_ib_mr *mr; 930 + int err; 931 + 932 + mr = kzalloc(sizeof(*mr), GFP_KERNEL); 933 + if (!mr) 934 + return ERR_PTR(-ENOMEM); 935 + 936 + in = kzalloc(sizeof(*in), GFP_KERNEL); 937 + if (!in) { 938 + err = -ENOMEM; 939 + goto err_free; 940 + } 941 + 942 + in->seg.status = 1 << 6; /* free */ 943 + in->seg.xlt_oct_size = cpu_to_be32((max_page_list_len + 1) / 2); 944 + in->seg.qpn_mkey7_0 = cpu_to_be32(0xffffff << 8); 945 + in->seg.flags = MLX5_PERM_UMR_EN | MLX5_ACCESS_MODE_MTT; 946 + in->seg.flags_pd = cpu_to_be32(to_mpd(pd)->pdn); 947 + /* 948 + * TBD not needed - issue 197292 */ 949 + in->seg.log2_page_size = PAGE_SHIFT; 950 + 951 + err = mlx5_core_create_mkey(&dev->mdev, &mr->mmr, in, sizeof(*in)); 952 + kfree(in); 953 + if (err) 954 + goto err_free; 955 + 956 + mr->ibmr.lkey = mr->mmr.key; 957 + mr->ibmr.rkey = mr->mmr.key; 958 + mr->umem = NULL; 959 + 960 + return &mr->ibmr; 961 + 962 + err_free: 963 + kfree(mr); 964 + return ERR_PTR(err); 965 + } 966 + 967 + struct ib_fast_reg_page_list *mlx5_ib_alloc_fast_reg_page_list(struct ib_device *ibdev, 968 + int page_list_len) 969 + { 970 + struct mlx5_ib_fast_reg_page_list *mfrpl; 971 + int size = page_list_len * sizeof(u64); 972 + 973 + mfrpl = kmalloc(sizeof(*mfrpl), GFP_KERNEL); 974 + if (!mfrpl) 975 + return ERR_PTR(-ENOMEM); 976 + 977 + mfrpl->ibfrpl.page_list = kmalloc(size, GFP_KERNEL); 978 + if (!mfrpl->ibfrpl.page_list) 979 + goto err_free; 980 + 981 + mfrpl->mapped_page_list = dma_alloc_coherent(ibdev->dma_device, 982 + size, &mfrpl->map, 983 + GFP_KERNEL); 984 + if (!mfrpl->mapped_page_list) 985 + goto err_free; 986 + 987 + WARN_ON(mfrpl->map & 0x3f); 988 + 989 + return &mfrpl->ibfrpl; 990 + 991 + err_free: 992 + kfree(mfrpl->ibfrpl.page_list); 993 + kfree(mfrpl); 994 + return ERR_PTR(-ENOMEM); 995 + } 996 + 997 + void mlx5_ib_free_fast_reg_page_list(struct ib_fast_reg_page_list *page_list) 998 + { 999 + struct mlx5_ib_fast_reg_page_list *mfrpl = to_mfrpl(page_list); 1000 + struct mlx5_ib_dev *dev = to_mdev(page_list->device); 1001 + int size = page_list->max_page_list_len * sizeof(u64); 1002 + 1003 + dma_free_coherent(&dev->mdev.pdev->dev, size, mfrpl->mapped_page_list, 1004 + mfrpl->map); 1005 + kfree(mfrpl->ibfrpl.page_list); 1006 + kfree(mfrpl); 1007 + }
+2524
drivers/infiniband/hw/mlx5/qp.c
··· 1 + /* 2 + * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved. 3 + * 4 + * This software is available to you under a choice of one of two 5 + * licenses. You may choose to be licensed under the terms of the GNU 6 + * General Public License (GPL) Version 2, available from the file 7 + * COPYING in the main directory of this source tree, or the 8 + * OpenIB.org BSD license below: 9 + * 10 + * Redistribution and use in source and binary forms, with or 11 + * without modification, are permitted provided that the following 12 + * conditions are met: 13 + * 14 + * - Redistributions of source code must retain the above 15 + * copyright notice, this list of conditions and the following 16 + * disclaimer. 17 + * 18 + * - Redistributions in binary form must reproduce the above 19 + * copyright notice, this list of conditions and the following 20 + * disclaimer in the documentation and/or other materials 21 + * 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 OF 25 + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26 + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 27 + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 28 + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29 + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30 + * SOFTWARE. 31 + */ 32 + 33 + #include <linux/module.h> 34 + #include <rdma/ib_umem.h> 35 + #include "mlx5_ib.h" 36 + #include "user.h" 37 + 38 + /* not supported currently */ 39 + static int wq_signature; 40 + 41 + enum { 42 + MLX5_IB_ACK_REQ_FREQ = 8, 43 + }; 44 + 45 + enum { 46 + MLX5_IB_DEFAULT_SCHED_QUEUE = 0x83, 47 + MLX5_IB_DEFAULT_QP0_SCHED_QUEUE = 0x3f, 48 + MLX5_IB_LINK_TYPE_IB = 0, 49 + MLX5_IB_LINK_TYPE_ETH = 1 50 + }; 51 + 52 + enum { 53 + MLX5_IB_SQ_STRIDE = 6, 54 + MLX5_IB_CACHE_LINE_SIZE = 64, 55 + }; 56 + 57 + static const u32 mlx5_ib_opcode[] = { 58 + [IB_WR_SEND] = MLX5_OPCODE_SEND, 59 + [IB_WR_SEND_WITH_IMM] = MLX5_OPCODE_SEND_IMM, 60 + [IB_WR_RDMA_WRITE] = MLX5_OPCODE_RDMA_WRITE, 61 + [IB_WR_RDMA_WRITE_WITH_IMM] = MLX5_OPCODE_RDMA_WRITE_IMM, 62 + [IB_WR_RDMA_READ] = MLX5_OPCODE_RDMA_READ, 63 + [IB_WR_ATOMIC_CMP_AND_SWP] = MLX5_OPCODE_ATOMIC_CS, 64 + [IB_WR_ATOMIC_FETCH_AND_ADD] = MLX5_OPCODE_ATOMIC_FA, 65 + [IB_WR_SEND_WITH_INV] = MLX5_OPCODE_SEND_INVAL, 66 + [IB_WR_LOCAL_INV] = MLX5_OPCODE_UMR, 67 + [IB_WR_FAST_REG_MR] = MLX5_OPCODE_UMR, 68 + [IB_WR_MASKED_ATOMIC_CMP_AND_SWP] = MLX5_OPCODE_ATOMIC_MASKED_CS, 69 + [IB_WR_MASKED_ATOMIC_FETCH_AND_ADD] = MLX5_OPCODE_ATOMIC_MASKED_FA, 70 + [MLX5_IB_WR_UMR] = MLX5_OPCODE_UMR, 71 + }; 72 + 73 + struct umr_wr { 74 + u64 virt_addr; 75 + struct ib_pd *pd; 76 + unsigned int page_shift; 77 + unsigned int npages; 78 + u32 length; 79 + int access_flags; 80 + u32 mkey; 81 + }; 82 + 83 + static int is_qp0(enum ib_qp_type qp_type) 84 + { 85 + return qp_type == IB_QPT_SMI; 86 + } 87 + 88 + static int is_qp1(enum ib_qp_type qp_type) 89 + { 90 + return qp_type == IB_QPT_GSI; 91 + } 92 + 93 + static int is_sqp(enum ib_qp_type qp_type) 94 + { 95 + return is_qp0(qp_type) || is_qp1(qp_type); 96 + } 97 + 98 + static void *get_wqe(struct mlx5_ib_qp *qp, int offset) 99 + { 100 + return mlx5_buf_offset(&qp->buf, offset); 101 + } 102 + 103 + static void *get_recv_wqe(struct mlx5_ib_qp *qp, int n) 104 + { 105 + return get_wqe(qp, qp->rq.offset + (n << qp->rq.wqe_shift)); 106 + } 107 + 108 + void *mlx5_get_send_wqe(struct mlx5_ib_qp *qp, int n) 109 + { 110 + return get_wqe(qp, qp->sq.offset + (n << MLX5_IB_SQ_STRIDE)); 111 + } 112 + 113 + static void mlx5_ib_qp_event(struct mlx5_core_qp *qp, int type) 114 + { 115 + struct ib_qp *ibqp = &to_mibqp(qp)->ibqp; 116 + struct ib_event event; 117 + 118 + if (type == MLX5_EVENT_TYPE_PATH_MIG) 119 + to_mibqp(qp)->port = to_mibqp(qp)->alt_port; 120 + 121 + if (ibqp->event_handler) { 122 + event.device = ibqp->device; 123 + event.element.qp = ibqp; 124 + switch (type) { 125 + case MLX5_EVENT_TYPE_PATH_MIG: 126 + event.event = IB_EVENT_PATH_MIG; 127 + break; 128 + case MLX5_EVENT_TYPE_COMM_EST: 129 + event.event = IB_EVENT_COMM_EST; 130 + break; 131 + case MLX5_EVENT_TYPE_SQ_DRAINED: 132 + event.event = IB_EVENT_SQ_DRAINED; 133 + break; 134 + case MLX5_EVENT_TYPE_SRQ_LAST_WQE: 135 + event.event = IB_EVENT_QP_LAST_WQE_REACHED; 136 + break; 137 + case MLX5_EVENT_TYPE_WQ_CATAS_ERROR: 138 + event.event = IB_EVENT_QP_FATAL; 139 + break; 140 + case MLX5_EVENT_TYPE_PATH_MIG_FAILED: 141 + event.event = IB_EVENT_PATH_MIG_ERR; 142 + break; 143 + case MLX5_EVENT_TYPE_WQ_INVAL_REQ_ERROR: 144 + event.event = IB_EVENT_QP_REQ_ERR; 145 + break; 146 + case MLX5_EVENT_TYPE_WQ_ACCESS_ERROR: 147 + event.event = IB_EVENT_QP_ACCESS_ERR; 148 + break; 149 + default: 150 + pr_warn("mlx5_ib: Unexpected event type %d on QP %06x\n", type, qp->qpn); 151 + return; 152 + } 153 + 154 + ibqp->event_handler(&event, ibqp->qp_context); 155 + } 156 + } 157 + 158 + static int set_rq_size(struct mlx5_ib_dev *dev, struct ib_qp_cap *cap, 159 + int has_rq, struct mlx5_ib_qp *qp, struct mlx5_ib_create_qp *ucmd) 160 + { 161 + int wqe_size; 162 + int wq_size; 163 + 164 + /* Sanity check RQ size before proceeding */ 165 + if (cap->max_recv_wr > dev->mdev.caps.max_wqes) 166 + return -EINVAL; 167 + 168 + if (!has_rq) { 169 + qp->rq.max_gs = 0; 170 + qp->rq.wqe_cnt = 0; 171 + qp->rq.wqe_shift = 0; 172 + } else { 173 + if (ucmd) { 174 + qp->rq.wqe_cnt = ucmd->rq_wqe_count; 175 + qp->rq.wqe_shift = ucmd->rq_wqe_shift; 176 + qp->rq.max_gs = (1 << qp->rq.wqe_shift) / sizeof(struct mlx5_wqe_data_seg) - qp->wq_sig; 177 + qp->rq.max_post = qp->rq.wqe_cnt; 178 + } else { 179 + wqe_size = qp->wq_sig ? sizeof(struct mlx5_wqe_signature_seg) : 0; 180 + wqe_size += cap->max_recv_sge * sizeof(struct mlx5_wqe_data_seg); 181 + wqe_size = roundup_pow_of_two(wqe_size); 182 + wq_size = roundup_pow_of_two(cap->max_recv_wr) * wqe_size; 183 + wq_size = max_t(int, wq_size, MLX5_SEND_WQE_BB); 184 + qp->rq.wqe_cnt = wq_size / wqe_size; 185 + if (wqe_size > dev->mdev.caps.max_rq_desc_sz) { 186 + mlx5_ib_dbg(dev, "wqe_size %d, max %d\n", 187 + wqe_size, 188 + dev->mdev.caps.max_rq_desc_sz); 189 + return -EINVAL; 190 + } 191 + qp->rq.wqe_shift = ilog2(wqe_size); 192 + qp->rq.max_gs = (1 << qp->rq.wqe_shift) / sizeof(struct mlx5_wqe_data_seg) - qp->wq_sig; 193 + qp->rq.max_post = qp->rq.wqe_cnt; 194 + } 195 + } 196 + 197 + return 0; 198 + } 199 + 200 + static int sq_overhead(enum ib_qp_type qp_type) 201 + { 202 + int size; 203 + 204 + switch (qp_type) { 205 + case IB_QPT_XRC_INI: 206 + size = sizeof(struct mlx5_wqe_xrc_seg); 207 + /* fall through */ 208 + case IB_QPT_RC: 209 + size += sizeof(struct mlx5_wqe_ctrl_seg) + 210 + sizeof(struct mlx5_wqe_atomic_seg) + 211 + sizeof(struct mlx5_wqe_raddr_seg); 212 + break; 213 + 214 + case IB_QPT_UC: 215 + size = sizeof(struct mlx5_wqe_ctrl_seg) + 216 + sizeof(struct mlx5_wqe_raddr_seg); 217 + break; 218 + 219 + case IB_QPT_UD: 220 + case IB_QPT_SMI: 221 + case IB_QPT_GSI: 222 + size = sizeof(struct mlx5_wqe_ctrl_seg) + 223 + sizeof(struct mlx5_wqe_datagram_seg); 224 + break; 225 + 226 + case MLX5_IB_QPT_REG_UMR: 227 + size = sizeof(struct mlx5_wqe_ctrl_seg) + 228 + sizeof(struct mlx5_wqe_umr_ctrl_seg) + 229 + sizeof(struct mlx5_mkey_seg); 230 + break; 231 + 232 + default: 233 + return -EINVAL; 234 + } 235 + 236 + return size; 237 + } 238 + 239 + static int calc_send_wqe(struct ib_qp_init_attr *attr) 240 + { 241 + int inl_size = 0; 242 + int size; 243 + 244 + size = sq_overhead(attr->qp_type); 245 + if (size < 0) 246 + return size; 247 + 248 + if (attr->cap.max_inline_data) { 249 + inl_size = size + sizeof(struct mlx5_wqe_inline_seg) + 250 + attr->cap.max_inline_data; 251 + } 252 + 253 + size += attr->cap.max_send_sge * sizeof(struct mlx5_wqe_data_seg); 254 + 255 + return ALIGN(max_t(int, inl_size, size), MLX5_SEND_WQE_BB); 256 + } 257 + 258 + static int calc_sq_size(struct mlx5_ib_dev *dev, struct ib_qp_init_attr *attr, 259 + struct mlx5_ib_qp *qp) 260 + { 261 + int wqe_size; 262 + int wq_size; 263 + 264 + if (!attr->cap.max_send_wr) 265 + return 0; 266 + 267 + wqe_size = calc_send_wqe(attr); 268 + mlx5_ib_dbg(dev, "wqe_size %d\n", wqe_size); 269 + if (wqe_size < 0) 270 + return wqe_size; 271 + 272 + if (wqe_size > dev->mdev.caps.max_sq_desc_sz) { 273 + mlx5_ib_dbg(dev, "\n"); 274 + return -EINVAL; 275 + } 276 + 277 + qp->max_inline_data = wqe_size - sq_overhead(attr->qp_type) - 278 + sizeof(struct mlx5_wqe_inline_seg); 279 + attr->cap.max_inline_data = qp->max_inline_data; 280 + 281 + wq_size = roundup_pow_of_two(attr->cap.max_send_wr * wqe_size); 282 + qp->sq.wqe_cnt = wq_size / MLX5_SEND_WQE_BB; 283 + qp->sq.wqe_shift = ilog2(MLX5_SEND_WQE_BB); 284 + qp->sq.max_gs = attr->cap.max_send_sge; 285 + qp->sq.max_post = 1 << ilog2(wq_size / wqe_size); 286 + 287 + return wq_size; 288 + } 289 + 290 + static int set_user_buf_size(struct mlx5_ib_dev *dev, 291 + struct mlx5_ib_qp *qp, 292 + struct mlx5_ib_create_qp *ucmd) 293 + { 294 + int desc_sz = 1 << qp->sq.wqe_shift; 295 + 296 + if (desc_sz > dev->mdev.caps.max_sq_desc_sz) { 297 + mlx5_ib_warn(dev, "desc_sz %d, max_sq_desc_sz %d\n", 298 + desc_sz, dev->mdev.caps.max_sq_desc_sz); 299 + return -EINVAL; 300 + } 301 + 302 + if (ucmd->sq_wqe_count && ((1 << ilog2(ucmd->sq_wqe_count)) != ucmd->sq_wqe_count)) { 303 + mlx5_ib_warn(dev, "sq_wqe_count %d, sq_wqe_count %d\n", 304 + ucmd->sq_wqe_count, ucmd->sq_wqe_count); 305 + return -EINVAL; 306 + } 307 + 308 + qp->sq.wqe_cnt = ucmd->sq_wqe_count; 309 + 310 + if (qp->sq.wqe_cnt > dev->mdev.caps.max_wqes) { 311 + mlx5_ib_warn(dev, "wqe_cnt %d, max_wqes %d\n", 312 + qp->sq.wqe_cnt, dev->mdev.caps.max_wqes); 313 + return -EINVAL; 314 + } 315 + 316 + qp->buf_size = (qp->rq.wqe_cnt << qp->rq.wqe_shift) + 317 + (qp->sq.wqe_cnt << 6); 318 + 319 + return 0; 320 + } 321 + 322 + static int qp_has_rq(struct ib_qp_init_attr *attr) 323 + { 324 + if (attr->qp_type == IB_QPT_XRC_INI || 325 + attr->qp_type == IB_QPT_XRC_TGT || attr->srq || 326 + attr->qp_type == MLX5_IB_QPT_REG_UMR || 327 + !attr->cap.max_recv_wr) 328 + return 0; 329 + 330 + return 1; 331 + } 332 + 333 + static int alloc_high_class_uuar(struct mlx5_uuar_info *uuari) 334 + { 335 + int nuuars = uuari->num_uars * MLX5_BF_REGS_PER_PAGE; 336 + int start_uuar; 337 + int i; 338 + 339 + start_uuar = nuuars - uuari->num_low_latency_uuars; 340 + for (i = start_uuar; i < nuuars; i++) { 341 + if (!test_bit(i, uuari->bitmap)) { 342 + set_bit(i, uuari->bitmap); 343 + uuari->count[i]++; 344 + return i; 345 + } 346 + } 347 + 348 + return -ENOMEM; 349 + } 350 + 351 + static int alloc_med_class_uuar(struct mlx5_uuar_info *uuari) 352 + { 353 + int nuuars = uuari->num_uars * MLX5_BF_REGS_PER_PAGE; 354 + int minidx = 1; 355 + int uuarn; 356 + int end; 357 + int i; 358 + 359 + end = nuuars - uuari->num_low_latency_uuars; 360 + 361 + for (i = 1; i < end; i++) { 362 + uuarn = i & 3; 363 + if (uuarn == 2 || uuarn == 3) 364 + continue; 365 + 366 + if (uuari->count[i] < uuari->count[minidx]) 367 + minidx = i; 368 + } 369 + 370 + uuari->count[minidx]++; 371 + return minidx; 372 + } 373 + 374 + static int alloc_uuar(struct mlx5_uuar_info *uuari, 375 + enum mlx5_ib_latency_class lat) 376 + { 377 + int uuarn = -EINVAL; 378 + 379 + mutex_lock(&uuari->lock); 380 + switch (lat) { 381 + case MLX5_IB_LATENCY_CLASS_LOW: 382 + uuarn = 0; 383 + uuari->count[uuarn]++; 384 + break; 385 + 386 + case MLX5_IB_LATENCY_CLASS_MEDIUM: 387 + uuarn = alloc_med_class_uuar(uuari); 388 + break; 389 + 390 + case MLX5_IB_LATENCY_CLASS_HIGH: 391 + uuarn = alloc_high_class_uuar(uuari); 392 + break; 393 + 394 + case MLX5_IB_LATENCY_CLASS_FAST_PATH: 395 + uuarn = 2; 396 + break; 397 + } 398 + mutex_unlock(&uuari->lock); 399 + 400 + return uuarn; 401 + } 402 + 403 + static void free_med_class_uuar(struct mlx5_uuar_info *uuari, int uuarn) 404 + { 405 + clear_bit(uuarn, uuari->bitmap); 406 + --uuari->count[uuarn]; 407 + } 408 + 409 + static void free_high_class_uuar(struct mlx5_uuar_info *uuari, int uuarn) 410 + { 411 + clear_bit(uuarn, uuari->bitmap); 412 + --uuari->count[uuarn]; 413 + } 414 + 415 + static void free_uuar(struct mlx5_uuar_info *uuari, int uuarn) 416 + { 417 + int nuuars = uuari->num_uars * MLX5_BF_REGS_PER_PAGE; 418 + int high_uuar = nuuars - uuari->num_low_latency_uuars; 419 + 420 + mutex_lock(&uuari->lock); 421 + if (uuarn == 0) { 422 + --uuari->count[uuarn]; 423 + goto out; 424 + } 425 + 426 + if (uuarn < high_uuar) { 427 + free_med_class_uuar(uuari, uuarn); 428 + goto out; 429 + } 430 + 431 + free_high_class_uuar(uuari, uuarn); 432 + 433 + out: 434 + mutex_unlock(&uuari->lock); 435 + } 436 + 437 + static enum mlx5_qp_state to_mlx5_state(enum ib_qp_state state) 438 + { 439 + switch (state) { 440 + case IB_QPS_RESET: return MLX5_QP_STATE_RST; 441 + case IB_QPS_INIT: return MLX5_QP_STATE_INIT; 442 + case IB_QPS_RTR: return MLX5_QP_STATE_RTR; 443 + case IB_QPS_RTS: return MLX5_QP_STATE_RTS; 444 + case IB_QPS_SQD: return MLX5_QP_STATE_SQD; 445 + case IB_QPS_SQE: return MLX5_QP_STATE_SQER; 446 + case IB_QPS_ERR: return MLX5_QP_STATE_ERR; 447 + default: return -1; 448 + } 449 + } 450 + 451 + static int to_mlx5_st(enum ib_qp_type type) 452 + { 453 + switch (type) { 454 + case IB_QPT_RC: return MLX5_QP_ST_RC; 455 + case IB_QPT_UC: return MLX5_QP_ST_UC; 456 + case IB_QPT_UD: return MLX5_QP_ST_UD; 457 + case MLX5_IB_QPT_REG_UMR: return MLX5_QP_ST_REG_UMR; 458 + case IB_QPT_XRC_INI: 459 + case IB_QPT_XRC_TGT: return MLX5_QP_ST_XRC; 460 + case IB_QPT_SMI: return MLX5_QP_ST_QP0; 461 + case IB_QPT_GSI: return MLX5_QP_ST_QP1; 462 + case IB_QPT_RAW_IPV6: return MLX5_QP_ST_RAW_IPV6; 463 + case IB_QPT_RAW_ETHERTYPE: return MLX5_QP_ST_RAW_ETHERTYPE; 464 + case IB_QPT_RAW_PACKET: 465 + case IB_QPT_MAX: 466 + default: return -EINVAL; 467 + } 468 + } 469 + 470 + static int uuarn_to_uar_index(struct mlx5_uuar_info *uuari, int uuarn) 471 + { 472 + return uuari->uars[uuarn / MLX5_BF_REGS_PER_PAGE].index; 473 + } 474 + 475 + static int create_user_qp(struct mlx5_ib_dev *dev, struct ib_pd *pd, 476 + struct mlx5_ib_qp *qp, struct ib_udata *udata, 477 + struct mlx5_create_qp_mbox_in **in, 478 + struct mlx5_ib_create_qp_resp *resp, int *inlen) 479 + { 480 + struct mlx5_ib_ucontext *context; 481 + struct mlx5_ib_create_qp ucmd; 482 + int page_shift; 483 + int uar_index; 484 + int npages; 485 + u32 offset; 486 + int uuarn; 487 + int ncont; 488 + int err; 489 + 490 + err = ib_copy_from_udata(&ucmd, udata, sizeof(ucmd)); 491 + if (err) { 492 + mlx5_ib_dbg(dev, "copy failed\n"); 493 + return err; 494 + } 495 + 496 + context = to_mucontext(pd->uobject->context); 497 + /* 498 + * TBD: should come from the verbs when we have the API 499 + */ 500 + uuarn = alloc_uuar(&context->uuari, MLX5_IB_LATENCY_CLASS_HIGH); 501 + if (uuarn < 0) { 502 + mlx5_ib_dbg(dev, "failed to allocate low latency UUAR\n"); 503 + mlx5_ib_dbg(dev, "reverting to high latency\n"); 504 + uuarn = alloc_uuar(&context->uuari, MLX5_IB_LATENCY_CLASS_LOW); 505 + if (uuarn < 0) { 506 + mlx5_ib_dbg(dev, "uuar allocation failed\n"); 507 + return uuarn; 508 + } 509 + } 510 + 511 + uar_index = uuarn_to_uar_index(&context->uuari, uuarn); 512 + mlx5_ib_dbg(dev, "uuarn 0x%x, uar_index 0x%x\n", uuarn, uar_index); 513 + 514 + err = set_user_buf_size(dev, qp, &ucmd); 515 + if (err) 516 + goto err_uuar; 517 + 518 + qp->umem = ib_umem_get(pd->uobject->context, ucmd.buf_addr, 519 + qp->buf_size, 0, 0); 520 + if (IS_ERR(qp->umem)) { 521 + mlx5_ib_dbg(dev, "umem_get failed\n"); 522 + err = PTR_ERR(qp->umem); 523 + goto err_uuar; 524 + } 525 + 526 + mlx5_ib_cont_pages(qp->umem, ucmd.buf_addr, &npages, &page_shift, 527 + &ncont, NULL); 528 + err = mlx5_ib_get_buf_offset(ucmd.buf_addr, page_shift, &offset); 529 + if (err) { 530 + mlx5_ib_warn(dev, "bad offset\n"); 531 + goto err_umem; 532 + } 533 + mlx5_ib_dbg(dev, "addr 0x%llx, size %d, npages %d, page_shift %d, ncont %d, offset %d\n", 534 + ucmd.buf_addr, qp->buf_size, npages, page_shift, ncont, offset); 535 + 536 + *inlen = sizeof(**in) + sizeof(*(*in)->pas) * ncont; 537 + *in = mlx5_vzalloc(*inlen); 538 + if (!*in) { 539 + err = -ENOMEM; 540 + goto err_umem; 541 + } 542 + mlx5_ib_populate_pas(dev, qp->umem, page_shift, (*in)->pas, 0); 543 + (*in)->ctx.log_pg_sz_remote_qpn = 544 + cpu_to_be32((page_shift - PAGE_SHIFT) << 24); 545 + (*in)->ctx.params2 = cpu_to_be32(offset << 6); 546 + 547 + (*in)->ctx.qp_counter_set_usr_page = cpu_to_be32(uar_index); 548 + resp->uuar_index = uuarn; 549 + qp->uuarn = uuarn; 550 + 551 + err = mlx5_ib_db_map_user(context, ucmd.db_addr, &qp->db); 552 + if (err) { 553 + mlx5_ib_dbg(dev, "map failed\n"); 554 + goto err_free; 555 + } 556 + 557 + err = ib_copy_to_udata(udata, resp, sizeof(*resp)); 558 + if (err) { 559 + mlx5_ib_dbg(dev, "copy failed\n"); 560 + goto err_unmap; 561 + } 562 + qp->create_type = MLX5_QP_USER; 563 + 564 + return 0; 565 + 566 + err_unmap: 567 + mlx5_ib_db_unmap_user(context, &qp->db); 568 + 569 + err_free: 570 + mlx5_vfree(*in); 571 + 572 + err_umem: 573 + ib_umem_release(qp->umem); 574 + 575 + err_uuar: 576 + free_uuar(&context->uuari, uuarn); 577 + return err; 578 + } 579 + 580 + static void destroy_qp_user(struct ib_pd *pd, struct mlx5_ib_qp *qp) 581 + { 582 + struct mlx5_ib_ucontext *context; 583 + 584 + context = to_mucontext(pd->uobject->context); 585 + mlx5_ib_db_unmap_user(context, &qp->db); 586 + ib_umem_release(qp->umem); 587 + free_uuar(&context->uuari, qp->uuarn); 588 + } 589 + 590 + static int create_kernel_qp(struct mlx5_ib_dev *dev, 591 + struct ib_qp_init_attr *init_attr, 592 + struct mlx5_ib_qp *qp, 593 + struct mlx5_create_qp_mbox_in **in, int *inlen) 594 + { 595 + enum mlx5_ib_latency_class lc = MLX5_IB_LATENCY_CLASS_LOW; 596 + struct mlx5_uuar_info *uuari; 597 + int uar_index; 598 + int uuarn; 599 + int err; 600 + 601 + uuari = &dev->mdev.priv.uuari; 602 + if (init_attr->create_flags & IB_QP_CREATE_BLOCK_MULTICAST_LOOPBACK) 603 + qp->flags |= MLX5_IB_QP_BLOCK_MULTICAST_LOOPBACK; 604 + 605 + if (init_attr->qp_type == MLX5_IB_QPT_REG_UMR) 606 + lc = MLX5_IB_LATENCY_CLASS_FAST_PATH; 607 + 608 + uuarn = alloc_uuar(uuari, lc); 609 + if (uuarn < 0) { 610 + mlx5_ib_dbg(dev, "\n"); 611 + return -ENOMEM; 612 + } 613 + 614 + qp->bf = &uuari->bfs[uuarn]; 615 + uar_index = qp->bf->uar->index; 616 + 617 + err = calc_sq_size(dev, init_attr, qp); 618 + if (err < 0) { 619 + mlx5_ib_dbg(dev, "err %d\n", err); 620 + goto err_uuar; 621 + } 622 + 623 + qp->rq.offset = 0; 624 + qp->sq.offset = qp->rq.wqe_cnt << qp->rq.wqe_shift; 625 + qp->buf_size = err + (qp->rq.wqe_cnt << qp->rq.wqe_shift); 626 + 627 + err = mlx5_buf_alloc(&dev->mdev, qp->buf_size, PAGE_SIZE * 2, &qp->buf); 628 + if (err) { 629 + mlx5_ib_dbg(dev, "err %d\n", err); 630 + goto err_uuar; 631 + } 632 + 633 + qp->sq.qend = mlx5_get_send_wqe(qp, qp->sq.wqe_cnt); 634 + *inlen = sizeof(**in) + sizeof(*(*in)->pas) * qp->buf.npages; 635 + *in = mlx5_vzalloc(*inlen); 636 + if (!*in) { 637 + err = -ENOMEM; 638 + goto err_buf; 639 + } 640 + (*in)->ctx.qp_counter_set_usr_page = cpu_to_be32(uar_index); 641 + (*in)->ctx.log_pg_sz_remote_qpn = cpu_to_be32((qp->buf.page_shift - PAGE_SHIFT) << 24); 642 + /* Set "fast registration enabled" for all kernel QPs */ 643 + (*in)->ctx.params1 |= cpu_to_be32(1 << 11); 644 + (*in)->ctx.sq_crq_size |= cpu_to_be16(1 << 4); 645 + 646 + mlx5_fill_page_array(&qp->buf, (*in)->pas); 647 + 648 + err = mlx5_db_alloc(&dev->mdev, &qp->db); 649 + if (err) { 650 + mlx5_ib_dbg(dev, "err %d\n", err); 651 + goto err_free; 652 + } 653 + 654 + qp->db.db[0] = 0; 655 + qp->db.db[1] = 0; 656 + 657 + qp->sq.wrid = kmalloc(qp->sq.wqe_cnt * sizeof(*qp->sq.wrid), GFP_KERNEL); 658 + qp->sq.wr_data = kmalloc(qp->sq.wqe_cnt * sizeof(*qp->sq.wr_data), GFP_KERNEL); 659 + qp->rq.wrid = kmalloc(qp->rq.wqe_cnt * sizeof(*qp->rq.wrid), GFP_KERNEL); 660 + qp->sq.w_list = kmalloc(qp->sq.wqe_cnt * sizeof(*qp->sq.w_list), GFP_KERNEL); 661 + qp->sq.wqe_head = kmalloc(qp->sq.wqe_cnt * sizeof(*qp->sq.wqe_head), GFP_KERNEL); 662 + 663 + if (!qp->sq.wrid || !qp->sq.wr_data || !qp->rq.wrid || 664 + !qp->sq.w_list || !qp->sq.wqe_head) { 665 + err = -ENOMEM; 666 + goto err_wrid; 667 + } 668 + qp->create_type = MLX5_QP_KERNEL; 669 + 670 + return 0; 671 + 672 + err_wrid: 673 + mlx5_db_free(&dev->mdev, &qp->db); 674 + kfree(qp->sq.wqe_head); 675 + kfree(qp->sq.w_list); 676 + kfree(qp->sq.wrid); 677 + kfree(qp->sq.wr_data); 678 + kfree(qp->rq.wrid); 679 + 680 + err_free: 681 + mlx5_vfree(*in); 682 + 683 + err_buf: 684 + mlx5_buf_free(&dev->mdev, &qp->buf); 685 + 686 + err_uuar: 687 + free_uuar(&dev->mdev.priv.uuari, uuarn); 688 + return err; 689 + } 690 + 691 + static void destroy_qp_kernel(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp) 692 + { 693 + mlx5_db_free(&dev->mdev, &qp->db); 694 + kfree(qp->sq.wqe_head); 695 + kfree(qp->sq.w_list); 696 + kfree(qp->sq.wrid); 697 + kfree(qp->sq.wr_data); 698 + kfree(qp->rq.wrid); 699 + mlx5_buf_free(&dev->mdev, &qp->buf); 700 + free_uuar(&dev->mdev.priv.uuari, qp->bf->uuarn); 701 + } 702 + 703 + static __be32 get_rx_type(struct mlx5_ib_qp *qp, struct ib_qp_init_attr *attr) 704 + { 705 + if (attr->srq || (attr->qp_type == IB_QPT_XRC_TGT) || 706 + (attr->qp_type == IB_QPT_XRC_INI)) 707 + return cpu_to_be32(MLX5_SRQ_RQ); 708 + else if (!qp->has_rq) 709 + return cpu_to_be32(MLX5_ZERO_LEN_RQ); 710 + else 711 + return cpu_to_be32(MLX5_NON_ZERO_RQ); 712 + } 713 + 714 + static int is_connected(enum ib_qp_type qp_type) 715 + { 716 + if (qp_type == IB_QPT_RC || qp_type == IB_QPT_UC) 717 + return 1; 718 + 719 + return 0; 720 + } 721 + 722 + static int create_qp_common(struct mlx5_ib_dev *dev, struct ib_pd *pd, 723 + struct ib_qp_init_attr *init_attr, 724 + struct ib_udata *udata, struct mlx5_ib_qp *qp) 725 + { 726 + struct mlx5_ib_resources *devr = &dev->devr; 727 + struct mlx5_ib_create_qp_resp resp; 728 + struct mlx5_create_qp_mbox_in *in; 729 + struct mlx5_ib_create_qp ucmd; 730 + int inlen = sizeof(*in); 731 + int err; 732 + 733 + mutex_init(&qp->mutex); 734 + spin_lock_init(&qp->sq.lock); 735 + spin_lock_init(&qp->rq.lock); 736 + 737 + if (init_attr->sq_sig_type == IB_SIGNAL_ALL_WR) 738 + qp->sq_signal_bits = MLX5_WQE_CTRL_CQ_UPDATE; 739 + 740 + if (pd && pd->uobject) { 741 + if (ib_copy_from_udata(&ucmd, udata, sizeof(ucmd))) { 742 + mlx5_ib_dbg(dev, "copy failed\n"); 743 + return -EFAULT; 744 + } 745 + 746 + qp->wq_sig = !!(ucmd.flags & MLX5_QP_FLAG_SIGNATURE); 747 + qp->scat_cqe = !!(ucmd.flags & MLX5_QP_FLAG_SCATTER_CQE); 748 + } else { 749 + qp->wq_sig = !!wq_signature; 750 + } 751 + 752 + qp->has_rq = qp_has_rq(init_attr); 753 + err = set_rq_size(dev, &init_attr->cap, qp->has_rq, 754 + qp, (pd && pd->uobject) ? &ucmd : NULL); 755 + if (err) { 756 + mlx5_ib_dbg(dev, "err %d\n", err); 757 + return err; 758 + } 759 + 760 + if (pd) { 761 + if (pd->uobject) { 762 + mlx5_ib_dbg(dev, "requested sq_wqe_count (%d)\n", ucmd.sq_wqe_count); 763 + if (ucmd.rq_wqe_shift != qp->rq.wqe_shift || 764 + ucmd.rq_wqe_count != qp->rq.wqe_cnt) { 765 + mlx5_ib_dbg(dev, "invalid rq params\n"); 766 + return -EINVAL; 767 + } 768 + if (ucmd.sq_wqe_count > dev->mdev.caps.max_wqes) { 769 + mlx5_ib_dbg(dev, "requested sq_wqe_count (%d) > max allowed (%d)\n", 770 + ucmd.sq_wqe_count, dev->mdev.caps.max_wqes); 771 + return -EINVAL; 772 + } 773 + err = create_user_qp(dev, pd, qp, udata, &in, &resp, &inlen); 774 + if (err) 775 + mlx5_ib_dbg(dev, "err %d\n", err); 776 + } else { 777 + err = create_kernel_qp(dev, init_attr, qp, &in, &inlen); 778 + if (err) 779 + mlx5_ib_dbg(dev, "err %d\n", err); 780 + else 781 + qp->pa_lkey = to_mpd(pd)->pa_lkey; 782 + } 783 + 784 + if (err) 785 + return err; 786 + } else { 787 + in = mlx5_vzalloc(sizeof(*in)); 788 + if (!in) 789 + return -ENOMEM; 790 + 791 + qp->create_type = MLX5_QP_EMPTY; 792 + } 793 + 794 + if (is_sqp(init_attr->qp_type)) 795 + qp->port = init_attr->port_num; 796 + 797 + in->ctx.flags = cpu_to_be32(to_mlx5_st(init_attr->qp_type) << 16 | 798 + MLX5_QP_PM_MIGRATED << 11); 799 + 800 + if (init_attr->qp_type != MLX5_IB_QPT_REG_UMR) 801 + in->ctx.flags_pd = cpu_to_be32(to_mpd(pd ? pd : devr->p0)->pdn); 802 + else 803 + in->ctx.flags_pd = cpu_to_be32(MLX5_QP_LAT_SENSITIVE); 804 + 805 + if (qp->wq_sig) 806 + in->ctx.flags_pd |= cpu_to_be32(MLX5_QP_ENABLE_SIG); 807 + 808 + if (qp->scat_cqe && is_connected(init_attr->qp_type)) { 809 + int rcqe_sz; 810 + int scqe_sz; 811 + 812 + rcqe_sz = mlx5_ib_get_cqe_size(dev, init_attr->recv_cq); 813 + scqe_sz = mlx5_ib_get_cqe_size(dev, init_attr->send_cq); 814 + 815 + if (rcqe_sz == 128) 816 + in->ctx.cs_res = MLX5_RES_SCAT_DATA64_CQE; 817 + else 818 + in->ctx.cs_res = MLX5_RES_SCAT_DATA32_CQE; 819 + 820 + if (init_attr->sq_sig_type == IB_SIGNAL_ALL_WR) { 821 + if (scqe_sz == 128) 822 + in->ctx.cs_req = MLX5_REQ_SCAT_DATA64_CQE; 823 + else 824 + in->ctx.cs_req = MLX5_REQ_SCAT_DATA32_CQE; 825 + } 826 + } 827 + 828 + if (qp->rq.wqe_cnt) { 829 + in->ctx.rq_size_stride = (qp->rq.wqe_shift - 4); 830 + in->ctx.rq_size_stride |= ilog2(qp->rq.wqe_cnt) << 3; 831 + } 832 + 833 + in->ctx.rq_type_srqn = get_rx_type(qp, init_attr); 834 + 835 + if (qp->sq.wqe_cnt) 836 + in->ctx.sq_crq_size |= cpu_to_be16(ilog2(qp->sq.wqe_cnt) << 11); 837 + else 838 + in->ctx.sq_crq_size |= cpu_to_be16(0x8000); 839 + 840 + /* Set default resources */ 841 + switch (init_attr->qp_type) { 842 + case IB_QPT_XRC_TGT: 843 + in->ctx.cqn_recv = cpu_to_be32(to_mcq(devr->c0)->mcq.cqn); 844 + in->ctx.cqn_send = cpu_to_be32(to_mcq(devr->c0)->mcq.cqn); 845 + in->ctx.rq_type_srqn |= cpu_to_be32(to_msrq(devr->s0)->msrq.srqn); 846 + in->ctx.xrcd = cpu_to_be32(to_mxrcd(init_attr->xrcd)->xrcdn); 847 + break; 848 + case IB_QPT_XRC_INI: 849 + in->ctx.cqn_recv = cpu_to_be32(to_mcq(devr->c0)->mcq.cqn); 850 + in->ctx.xrcd = cpu_to_be32(to_mxrcd(devr->x1)->xrcdn); 851 + in->ctx.rq_type_srqn |= cpu_to_be32(to_msrq(devr->s0)->msrq.srqn); 852 + break; 853 + default: 854 + if (init_attr->srq) { 855 + in->ctx.xrcd = cpu_to_be32(to_mxrcd(devr->x0)->xrcdn); 856 + in->ctx.rq_type_srqn |= cpu_to_be32(to_msrq(init_attr->srq)->msrq.srqn); 857 + } else { 858 + in->ctx.xrcd = cpu_to_be32(to_mxrcd(devr->x1)->xrcdn); 859 + in->ctx.rq_type_srqn |= cpu_to_be32(to_msrq(devr->s0)->msrq.srqn); 860 + } 861 + } 862 + 863 + if (init_attr->send_cq) 864 + in->ctx.cqn_send = cpu_to_be32(to_mcq(init_attr->send_cq)->mcq.cqn); 865 + 866 + if (init_attr->recv_cq) 867 + in->ctx.cqn_recv = cpu_to_be32(to_mcq(init_attr->recv_cq)->mcq.cqn); 868 + 869 + in->ctx.db_rec_addr = cpu_to_be64(qp->db.dma); 870 + 871 + err = mlx5_core_create_qp(&dev->mdev, &qp->mqp, in, inlen); 872 + if (err) { 873 + mlx5_ib_dbg(dev, "create qp failed\n"); 874 + goto err_create; 875 + } 876 + 877 + mlx5_vfree(in); 878 + /* Hardware wants QPN written in big-endian order (after 879 + * shifting) for send doorbell. Precompute this value to save 880 + * a little bit when posting sends. 881 + */ 882 + qp->doorbell_qpn = swab32(qp->mqp.qpn << 8); 883 + 884 + qp->mqp.event = mlx5_ib_qp_event; 885 + 886 + return 0; 887 + 888 + err_create: 889 + if (qp->create_type == MLX5_QP_USER) 890 + destroy_qp_user(pd, qp); 891 + else if (qp->create_type == MLX5_QP_KERNEL) 892 + destroy_qp_kernel(dev, qp); 893 + 894 + mlx5_vfree(in); 895 + return err; 896 + } 897 + 898 + static void mlx5_ib_lock_cqs(struct mlx5_ib_cq *send_cq, struct mlx5_ib_cq *recv_cq) 899 + __acquires(&send_cq->lock) __acquires(&recv_cq->lock) 900 + { 901 + if (send_cq) { 902 + if (recv_cq) { 903 + if (send_cq->mcq.cqn < recv_cq->mcq.cqn) { 904 + spin_lock_irq(&send_cq->lock); 905 + spin_lock_nested(&recv_cq->lock, 906 + SINGLE_DEPTH_NESTING); 907 + } else if (send_cq->mcq.cqn == recv_cq->mcq.cqn) { 908 + spin_lock_irq(&send_cq->lock); 909 + __acquire(&recv_cq->lock); 910 + } else { 911 + spin_lock_irq(&recv_cq->lock); 912 + spin_lock_nested(&send_cq->lock, 913 + SINGLE_DEPTH_NESTING); 914 + } 915 + } else { 916 + spin_lock_irq(&send_cq->lock); 917 + } 918 + } else if (recv_cq) { 919 + spin_lock_irq(&recv_cq->lock); 920 + } 921 + } 922 + 923 + static void mlx5_ib_unlock_cqs(struct mlx5_ib_cq *send_cq, struct mlx5_ib_cq *recv_cq) 924 + __releases(&send_cq->lock) __releases(&recv_cq->lock) 925 + { 926 + if (send_cq) { 927 + if (recv_cq) { 928 + if (send_cq->mcq.cqn < recv_cq->mcq.cqn) { 929 + spin_unlock(&recv_cq->lock); 930 + spin_unlock_irq(&send_cq->lock); 931 + } else if (send_cq->mcq.cqn == recv_cq->mcq.cqn) { 932 + __release(&recv_cq->lock); 933 + spin_unlock_irq(&send_cq->lock); 934 + } else { 935 + spin_unlock(&send_cq->lock); 936 + spin_unlock_irq(&recv_cq->lock); 937 + } 938 + } else { 939 + spin_unlock_irq(&send_cq->lock); 940 + } 941 + } else if (recv_cq) { 942 + spin_unlock_irq(&recv_cq->lock); 943 + } 944 + } 945 + 946 + static struct mlx5_ib_pd *get_pd(struct mlx5_ib_qp *qp) 947 + { 948 + return to_mpd(qp->ibqp.pd); 949 + } 950 + 951 + static void get_cqs(struct mlx5_ib_qp *qp, 952 + struct mlx5_ib_cq **send_cq, struct mlx5_ib_cq **recv_cq) 953 + { 954 + switch (qp->ibqp.qp_type) { 955 + case IB_QPT_XRC_TGT: 956 + *send_cq = NULL; 957 + *recv_cq = NULL; 958 + break; 959 + case MLX5_IB_QPT_REG_UMR: 960 + case IB_QPT_XRC_INI: 961 + *send_cq = to_mcq(qp->ibqp.send_cq); 962 + *recv_cq = NULL; 963 + break; 964 + 965 + case IB_QPT_SMI: 966 + case IB_QPT_GSI: 967 + case IB_QPT_RC: 968 + case IB_QPT_UC: 969 + case IB_QPT_UD: 970 + case IB_QPT_RAW_IPV6: 971 + case IB_QPT_RAW_ETHERTYPE: 972 + *send_cq = to_mcq(qp->ibqp.send_cq); 973 + *recv_cq = to_mcq(qp->ibqp.recv_cq); 974 + break; 975 + 976 + case IB_QPT_RAW_PACKET: 977 + case IB_QPT_MAX: 978 + default: 979 + *send_cq = NULL; 980 + *recv_cq = NULL; 981 + break; 982 + } 983 + } 984 + 985 + static void destroy_qp_common(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp) 986 + { 987 + struct mlx5_ib_cq *send_cq, *recv_cq; 988 + struct mlx5_modify_qp_mbox_in *in; 989 + int err; 990 + 991 + in = kzalloc(sizeof(*in), GFP_KERNEL); 992 + if (!in) 993 + return; 994 + if (qp->state != IB_QPS_RESET) 995 + if (mlx5_core_qp_modify(&dev->mdev, to_mlx5_state(qp->state), 996 + MLX5_QP_STATE_RST, in, sizeof(*in), &qp->mqp)) 997 + mlx5_ib_warn(dev, "mlx5_ib: modify QP %06x to RESET failed\n", 998 + qp->mqp.qpn); 999 + 1000 + get_cqs(qp, &send_cq, &recv_cq); 1001 + 1002 + if (qp->create_type == MLX5_QP_KERNEL) { 1003 + mlx5_ib_lock_cqs(send_cq, recv_cq); 1004 + __mlx5_ib_cq_clean(recv_cq, qp->mqp.qpn, 1005 + qp->ibqp.srq ? to_msrq(qp->ibqp.srq) : NULL); 1006 + if (send_cq != recv_cq) 1007 + __mlx5_ib_cq_clean(send_cq, qp->mqp.qpn, NULL); 1008 + mlx5_ib_unlock_cqs(send_cq, recv_cq); 1009 + } 1010 + 1011 + err = mlx5_core_destroy_qp(&dev->mdev, &qp->mqp); 1012 + if (err) 1013 + mlx5_ib_warn(dev, "failed to destroy QP 0x%x\n", qp->mqp.qpn); 1014 + kfree(in); 1015 + 1016 + 1017 + if (qp->create_type == MLX5_QP_KERNEL) 1018 + destroy_qp_kernel(dev, qp); 1019 + else if (qp->create_type == MLX5_QP_USER) 1020 + destroy_qp_user(&get_pd(qp)->ibpd, qp); 1021 + } 1022 + 1023 + static const char *ib_qp_type_str(enum ib_qp_type type) 1024 + { 1025 + switch (type) { 1026 + case IB_QPT_SMI: 1027 + return "IB_QPT_SMI"; 1028 + case IB_QPT_GSI: 1029 + return "IB_QPT_GSI"; 1030 + case IB_QPT_RC: 1031 + return "IB_QPT_RC"; 1032 + case IB_QPT_UC: 1033 + return "IB_QPT_UC"; 1034 + case IB_QPT_UD: 1035 + return "IB_QPT_UD"; 1036 + case IB_QPT_RAW_IPV6: 1037 + return "IB_QPT_RAW_IPV6"; 1038 + case IB_QPT_RAW_ETHERTYPE: 1039 + return "IB_QPT_RAW_ETHERTYPE"; 1040 + case IB_QPT_XRC_INI: 1041 + return "IB_QPT_XRC_INI"; 1042 + case IB_QPT_XRC_TGT: 1043 + return "IB_QPT_XRC_TGT"; 1044 + case IB_QPT_RAW_PACKET: 1045 + return "IB_QPT_RAW_PACKET"; 1046 + case MLX5_IB_QPT_REG_UMR: 1047 + return "MLX5_IB_QPT_REG_UMR"; 1048 + case IB_QPT_MAX: 1049 + default: 1050 + return "Invalid QP type"; 1051 + } 1052 + } 1053 + 1054 + struct ib_qp *mlx5_ib_create_qp(struct ib_pd *pd, 1055 + struct ib_qp_init_attr *init_attr, 1056 + struct ib_udata *udata) 1057 + { 1058 + struct mlx5_ib_dev *dev; 1059 + struct mlx5_ib_qp *qp; 1060 + u16 xrcdn = 0; 1061 + int err; 1062 + 1063 + if (pd) { 1064 + dev = to_mdev(pd->device); 1065 + } else { 1066 + /* being cautious here */ 1067 + if (init_attr->qp_type != IB_QPT_XRC_TGT && 1068 + init_attr->qp_type != MLX5_IB_QPT_REG_UMR) { 1069 + pr_warn("%s: no PD for transport %s\n", __func__, 1070 + ib_qp_type_str(init_attr->qp_type)); 1071 + return ERR_PTR(-EINVAL); 1072 + } 1073 + dev = to_mdev(to_mxrcd(init_attr->xrcd)->ibxrcd.device); 1074 + } 1075 + 1076 + switch (init_attr->qp_type) { 1077 + case IB_QPT_XRC_TGT: 1078 + case IB_QPT_XRC_INI: 1079 + if (!(dev->mdev.caps.flags & MLX5_DEV_CAP_FLAG_XRC)) { 1080 + mlx5_ib_dbg(dev, "XRC not supported\n"); 1081 + return ERR_PTR(-ENOSYS); 1082 + } 1083 + init_attr->recv_cq = NULL; 1084 + if (init_attr->qp_type == IB_QPT_XRC_TGT) { 1085 + xrcdn = to_mxrcd(init_attr->xrcd)->xrcdn; 1086 + init_attr->send_cq = NULL; 1087 + } 1088 + 1089 + /* fall through */ 1090 + case IB_QPT_RC: 1091 + case IB_QPT_UC: 1092 + case IB_QPT_UD: 1093 + case IB_QPT_SMI: 1094 + case IB_QPT_GSI: 1095 + case MLX5_IB_QPT_REG_UMR: 1096 + qp = kzalloc(sizeof(*qp), GFP_KERNEL); 1097 + if (!qp) 1098 + return ERR_PTR(-ENOMEM); 1099 + 1100 + err = create_qp_common(dev, pd, init_attr, udata, qp); 1101 + if (err) { 1102 + mlx5_ib_dbg(dev, "create_qp_common failed\n"); 1103 + kfree(qp); 1104 + return ERR_PTR(err); 1105 + } 1106 + 1107 + if (is_qp0(init_attr->qp_type)) 1108 + qp->ibqp.qp_num = 0; 1109 + else if (is_qp1(init_attr->qp_type)) 1110 + qp->ibqp.qp_num = 1; 1111 + else 1112 + qp->ibqp.qp_num = qp->mqp.qpn; 1113 + 1114 + mlx5_ib_dbg(dev, "ib qpnum 0x%x, mlx qpn 0x%x, rcqn 0x%x, scqn 0x%x\n", 1115 + qp->ibqp.qp_num, qp->mqp.qpn, to_mcq(init_attr->recv_cq)->mcq.cqn, 1116 + to_mcq(init_attr->send_cq)->mcq.cqn); 1117 + 1118 + qp->xrcdn = xrcdn; 1119 + 1120 + break; 1121 + 1122 + case IB_QPT_RAW_IPV6: 1123 + case IB_QPT_RAW_ETHERTYPE: 1124 + case IB_QPT_RAW_PACKET: 1125 + case IB_QPT_MAX: 1126 + default: 1127 + mlx5_ib_dbg(dev, "unsupported qp type %d\n", 1128 + init_attr->qp_type); 1129 + /* Don't support raw QPs */ 1130 + return ERR_PTR(-EINVAL); 1131 + } 1132 + 1133 + return &qp->ibqp; 1134 + } 1135 + 1136 + int mlx5_ib_destroy_qp(struct ib_qp *qp) 1137 + { 1138 + struct mlx5_ib_dev *dev = to_mdev(qp->device); 1139 + struct mlx5_ib_qp *mqp = to_mqp(qp); 1140 + 1141 + destroy_qp_common(dev, mqp); 1142 + 1143 + kfree(mqp); 1144 + 1145 + return 0; 1146 + } 1147 + 1148 + static __be32 to_mlx5_access_flags(struct mlx5_ib_qp *qp, const struct ib_qp_attr *attr, 1149 + int attr_mask) 1150 + { 1151 + u32 hw_access_flags = 0; 1152 + u8 dest_rd_atomic; 1153 + u32 access_flags; 1154 + 1155 + if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC) 1156 + dest_rd_atomic = attr->max_dest_rd_atomic; 1157 + else 1158 + dest_rd_atomic = qp->resp_depth; 1159 + 1160 + if (attr_mask & IB_QP_ACCESS_FLAGS) 1161 + access_flags = attr->qp_access_flags; 1162 + else 1163 + access_flags = qp->atomic_rd_en; 1164 + 1165 + if (!dest_rd_atomic) 1166 + access_flags &= IB_ACCESS_REMOTE_WRITE; 1167 + 1168 + if (access_flags & IB_ACCESS_REMOTE_READ) 1169 + hw_access_flags |= MLX5_QP_BIT_RRE; 1170 + if (access_flags & IB_ACCESS_REMOTE_ATOMIC) 1171 + hw_access_flags |= (MLX5_QP_BIT_RAE | MLX5_ATOMIC_MODE_CX); 1172 + if (access_flags & IB_ACCESS_REMOTE_WRITE) 1173 + hw_access_flags |= MLX5_QP_BIT_RWE; 1174 + 1175 + return cpu_to_be32(hw_access_flags); 1176 + } 1177 + 1178 + enum { 1179 + MLX5_PATH_FLAG_FL = 1 << 0, 1180 + MLX5_PATH_FLAG_FREE_AR = 1 << 1, 1181 + MLX5_PATH_FLAG_COUNTER = 1 << 2, 1182 + }; 1183 + 1184 + static int ib_rate_to_mlx5(struct mlx5_ib_dev *dev, u8 rate) 1185 + { 1186 + if (rate == IB_RATE_PORT_CURRENT) { 1187 + return 0; 1188 + } else if (rate < IB_RATE_2_5_GBPS || rate > IB_RATE_300_GBPS) { 1189 + return -EINVAL; 1190 + } else { 1191 + while (rate != IB_RATE_2_5_GBPS && 1192 + !(1 << (rate + MLX5_STAT_RATE_OFFSET) & 1193 + dev->mdev.caps.stat_rate_support)) 1194 + --rate; 1195 + } 1196 + 1197 + return rate + MLX5_STAT_RATE_OFFSET; 1198 + } 1199 + 1200 + static int mlx5_set_path(struct mlx5_ib_dev *dev, const struct ib_ah_attr *ah, 1201 + struct mlx5_qp_path *path, u8 port, int attr_mask, 1202 + u32 path_flags, const struct ib_qp_attr *attr) 1203 + { 1204 + int err; 1205 + 1206 + path->fl = (path_flags & MLX5_PATH_FLAG_FL) ? 0x80 : 0; 1207 + path->free_ar = (path_flags & MLX5_PATH_FLAG_FREE_AR) ? 0x80 : 0; 1208 + 1209 + if (attr_mask & IB_QP_PKEY_INDEX) 1210 + path->pkey_index = attr->pkey_index; 1211 + 1212 + path->grh_mlid = ah->src_path_bits & 0x7f; 1213 + path->rlid = cpu_to_be16(ah->dlid); 1214 + 1215 + if (ah->ah_flags & IB_AH_GRH) { 1216 + path->grh_mlid |= 1 << 7; 1217 + path->mgid_index = ah->grh.sgid_index; 1218 + path->hop_limit = ah->grh.hop_limit; 1219 + path->tclass_flowlabel = 1220 + cpu_to_be32((ah->grh.traffic_class << 20) | 1221 + (ah->grh.flow_label)); 1222 + memcpy(path->rgid, ah->grh.dgid.raw, 16); 1223 + } 1224 + 1225 + err = ib_rate_to_mlx5(dev, ah->static_rate); 1226 + if (err < 0) 1227 + return err; 1228 + path->static_rate = err; 1229 + path->port = port; 1230 + 1231 + if (ah->ah_flags & IB_AH_GRH) { 1232 + if (ah->grh.sgid_index >= dev->mdev.caps.port[port - 1].gid_table_len) { 1233 + pr_err(KERN_ERR "sgid_index (%u) too large. max is %d\n", 1234 + ah->grh.sgid_index, dev->mdev.caps.port[port - 1].gid_table_len); 1235 + return -EINVAL; 1236 + } 1237 + 1238 + path->grh_mlid |= 1 << 7; 1239 + path->mgid_index = ah->grh.sgid_index; 1240 + path->hop_limit = ah->grh.hop_limit; 1241 + path->tclass_flowlabel = 1242 + cpu_to_be32((ah->grh.traffic_class << 20) | 1243 + (ah->grh.flow_label)); 1244 + memcpy(path->rgid, ah->grh.dgid.raw, 16); 1245 + } 1246 + 1247 + if (attr_mask & IB_QP_TIMEOUT) 1248 + path->ackto_lt = attr->timeout << 3; 1249 + 1250 + path->sl = ah->sl & 0xf; 1251 + 1252 + return 0; 1253 + } 1254 + 1255 + static enum mlx5_qp_optpar opt_mask[MLX5_QP_NUM_STATE][MLX5_QP_NUM_STATE][MLX5_QP_ST_MAX] = { 1256 + [MLX5_QP_STATE_INIT] = { 1257 + [MLX5_QP_STATE_INIT] = { 1258 + [MLX5_QP_ST_RC] = MLX5_QP_OPTPAR_RRE | 1259 + MLX5_QP_OPTPAR_RAE | 1260 + MLX5_QP_OPTPAR_RWE | 1261 + MLX5_QP_OPTPAR_PKEY_INDEX | 1262 + MLX5_QP_OPTPAR_PRI_PORT, 1263 + [MLX5_QP_ST_UC] = MLX5_QP_OPTPAR_RWE | 1264 + MLX5_QP_OPTPAR_PKEY_INDEX | 1265 + MLX5_QP_OPTPAR_PRI_PORT, 1266 + [MLX5_QP_ST_UD] = MLX5_QP_OPTPAR_PKEY_INDEX | 1267 + MLX5_QP_OPTPAR_Q_KEY | 1268 + MLX5_QP_OPTPAR_PRI_PORT, 1269 + }, 1270 + [MLX5_QP_STATE_RTR] = { 1271 + [MLX5_QP_ST_RC] = MLX5_QP_OPTPAR_ALT_ADDR_PATH | 1272 + MLX5_QP_OPTPAR_RRE | 1273 + MLX5_QP_OPTPAR_RAE | 1274 + MLX5_QP_OPTPAR_RWE | 1275 + MLX5_QP_OPTPAR_PKEY_INDEX, 1276 + [MLX5_QP_ST_UC] = MLX5_QP_OPTPAR_ALT_ADDR_PATH | 1277 + MLX5_QP_OPTPAR_RWE | 1278 + MLX5_QP_OPTPAR_PKEY_INDEX, 1279 + [MLX5_QP_ST_UD] = MLX5_QP_OPTPAR_PKEY_INDEX | 1280 + MLX5_QP_OPTPAR_Q_KEY, 1281 + [MLX5_QP_ST_MLX] = MLX5_QP_OPTPAR_PKEY_INDEX | 1282 + MLX5_QP_OPTPAR_Q_KEY, 1283 + }, 1284 + }, 1285 + [MLX5_QP_STATE_RTR] = { 1286 + [MLX5_QP_STATE_RTS] = { 1287 + [MLX5_QP_ST_RC] = MLX5_QP_OPTPAR_ALT_ADDR_PATH | 1288 + MLX5_QP_OPTPAR_RRE | 1289 + MLX5_QP_OPTPAR_RAE | 1290 + MLX5_QP_OPTPAR_RWE | 1291 + MLX5_QP_OPTPAR_PM_STATE | 1292 + MLX5_QP_OPTPAR_RNR_TIMEOUT, 1293 + [MLX5_QP_ST_UC] = MLX5_QP_OPTPAR_ALT_ADDR_PATH | 1294 + MLX5_QP_OPTPAR_RWE | 1295 + MLX5_QP_OPTPAR_PM_STATE, 1296 + [MLX5_QP_ST_UD] = MLX5_QP_OPTPAR_Q_KEY, 1297 + }, 1298 + }, 1299 + [MLX5_QP_STATE_RTS] = { 1300 + [MLX5_QP_STATE_RTS] = { 1301 + [MLX5_QP_ST_RC] = MLX5_QP_OPTPAR_RRE | 1302 + MLX5_QP_OPTPAR_RAE | 1303 + MLX5_QP_OPTPAR_RWE | 1304 + MLX5_QP_OPTPAR_RNR_TIMEOUT | 1305 + MLX5_QP_OPTPAR_PM_STATE, 1306 + [MLX5_QP_ST_UC] = MLX5_QP_OPTPAR_RWE | 1307 + MLX5_QP_OPTPAR_PM_STATE, 1308 + [MLX5_QP_ST_UD] = MLX5_QP_OPTPAR_Q_KEY | 1309 + MLX5_QP_OPTPAR_SRQN | 1310 + MLX5_QP_OPTPAR_CQN_RCV, 1311 + }, 1312 + }, 1313 + [MLX5_QP_STATE_SQER] = { 1314 + [MLX5_QP_STATE_RTS] = { 1315 + [MLX5_QP_ST_UD] = MLX5_QP_OPTPAR_Q_KEY, 1316 + [MLX5_QP_ST_MLX] = MLX5_QP_OPTPAR_Q_KEY, 1317 + }, 1318 + }, 1319 + }; 1320 + 1321 + static int ib_nr_to_mlx5_nr(int ib_mask) 1322 + { 1323 + switch (ib_mask) { 1324 + case IB_QP_STATE: 1325 + return 0; 1326 + case IB_QP_CUR_STATE: 1327 + return 0; 1328 + case IB_QP_EN_SQD_ASYNC_NOTIFY: 1329 + return 0; 1330 + case IB_QP_ACCESS_FLAGS: 1331 + return MLX5_QP_OPTPAR_RWE | MLX5_QP_OPTPAR_RRE | 1332 + MLX5_QP_OPTPAR_RAE; 1333 + case IB_QP_PKEY_INDEX: 1334 + return MLX5_QP_OPTPAR_PKEY_INDEX; 1335 + case IB_QP_PORT: 1336 + return MLX5_QP_OPTPAR_PRI_PORT; 1337 + case IB_QP_QKEY: 1338 + return MLX5_QP_OPTPAR_Q_KEY; 1339 + case IB_QP_AV: 1340 + return MLX5_QP_OPTPAR_PRIMARY_ADDR_PATH | 1341 + MLX5_QP_OPTPAR_PRI_PORT; 1342 + case IB_QP_PATH_MTU: 1343 + return 0; 1344 + case IB_QP_TIMEOUT: 1345 + return MLX5_QP_OPTPAR_ACK_TIMEOUT; 1346 + case IB_QP_RETRY_CNT: 1347 + return MLX5_QP_OPTPAR_RETRY_COUNT; 1348 + case IB_QP_RNR_RETRY: 1349 + return MLX5_QP_OPTPAR_RNR_RETRY; 1350 + case IB_QP_RQ_PSN: 1351 + return 0; 1352 + case IB_QP_MAX_QP_RD_ATOMIC: 1353 + return MLX5_QP_OPTPAR_SRA_MAX; 1354 + case IB_QP_ALT_PATH: 1355 + return MLX5_QP_OPTPAR_ALT_ADDR_PATH; 1356 + case IB_QP_MIN_RNR_TIMER: 1357 + return MLX5_QP_OPTPAR_RNR_TIMEOUT; 1358 + case IB_QP_SQ_PSN: 1359 + return 0; 1360 + case IB_QP_MAX_DEST_RD_ATOMIC: 1361 + return MLX5_QP_OPTPAR_RRA_MAX | MLX5_QP_OPTPAR_RWE | 1362 + MLX5_QP_OPTPAR_RRE | MLX5_QP_OPTPAR_RAE; 1363 + case IB_QP_PATH_MIG_STATE: 1364 + return MLX5_QP_OPTPAR_PM_STATE; 1365 + case IB_QP_CAP: 1366 + return 0; 1367 + case IB_QP_DEST_QPN: 1368 + return 0; 1369 + } 1370 + return 0; 1371 + } 1372 + 1373 + static int ib_mask_to_mlx5_opt(int ib_mask) 1374 + { 1375 + int result = 0; 1376 + int i; 1377 + 1378 + for (i = 0; i < 8 * sizeof(int); i++) { 1379 + if ((1 << i) & ib_mask) 1380 + result |= ib_nr_to_mlx5_nr(1 << i); 1381 + } 1382 + 1383 + return result; 1384 + } 1385 + 1386 + static int __mlx5_ib_modify_qp(struct ib_qp *ibqp, 1387 + const struct ib_qp_attr *attr, int attr_mask, 1388 + enum ib_qp_state cur_state, enum ib_qp_state new_state) 1389 + { 1390 + struct mlx5_ib_dev *dev = to_mdev(ibqp->device); 1391 + struct mlx5_ib_qp *qp = to_mqp(ibqp); 1392 + struct mlx5_ib_cq *send_cq, *recv_cq; 1393 + struct mlx5_qp_context *context; 1394 + struct mlx5_modify_qp_mbox_in *in; 1395 + struct mlx5_ib_pd *pd; 1396 + enum mlx5_qp_state mlx5_cur, mlx5_new; 1397 + enum mlx5_qp_optpar optpar; 1398 + int sqd_event; 1399 + int mlx5_st; 1400 + int err; 1401 + 1402 + in = kzalloc(sizeof(*in), GFP_KERNEL); 1403 + if (!in) 1404 + return -ENOMEM; 1405 + 1406 + context = &in->ctx; 1407 + err = to_mlx5_st(ibqp->qp_type); 1408 + if (err < 0) 1409 + goto out; 1410 + 1411 + context->flags = cpu_to_be32(err << 16); 1412 + 1413 + if (!(attr_mask & IB_QP_PATH_MIG_STATE)) { 1414 + context->flags |= cpu_to_be32(MLX5_QP_PM_MIGRATED << 11); 1415 + } else { 1416 + switch (attr->path_mig_state) { 1417 + case IB_MIG_MIGRATED: 1418 + context->flags |= cpu_to_be32(MLX5_QP_PM_MIGRATED << 11); 1419 + break; 1420 + case IB_MIG_REARM: 1421 + context->flags |= cpu_to_be32(MLX5_QP_PM_REARM << 11); 1422 + break; 1423 + case IB_MIG_ARMED: 1424 + context->flags |= cpu_to_be32(MLX5_QP_PM_ARMED << 11); 1425 + break; 1426 + } 1427 + } 1428 + 1429 + if (ibqp->qp_type == IB_QPT_GSI || ibqp->qp_type == IB_QPT_SMI) { 1430 + context->mtu_msgmax = (IB_MTU_256 << 5) | 8; 1431 + } else if (ibqp->qp_type == IB_QPT_UD || 1432 + ibqp->qp_type == MLX5_IB_QPT_REG_UMR) { 1433 + context->mtu_msgmax = (IB_MTU_4096 << 5) | 12; 1434 + } else if (attr_mask & IB_QP_PATH_MTU) { 1435 + if (attr->path_mtu < IB_MTU_256 || 1436 + attr->path_mtu > IB_MTU_4096) { 1437 + mlx5_ib_warn(dev, "invalid mtu %d\n", attr->path_mtu); 1438 + err = -EINVAL; 1439 + goto out; 1440 + } 1441 + context->mtu_msgmax = (attr->path_mtu << 5) | dev->mdev.caps.log_max_msg; 1442 + } 1443 + 1444 + if (attr_mask & IB_QP_DEST_QPN) 1445 + context->log_pg_sz_remote_qpn = cpu_to_be32(attr->dest_qp_num); 1446 + 1447 + if (attr_mask & IB_QP_PKEY_INDEX) 1448 + context->pri_path.pkey_index = attr->pkey_index; 1449 + 1450 + /* todo implement counter_index functionality */ 1451 + 1452 + if (is_sqp(ibqp->qp_type)) 1453 + context->pri_path.port = qp->port; 1454 + 1455 + if (attr_mask & IB_QP_PORT) 1456 + context->pri_path.port = attr->port_num; 1457 + 1458 + if (attr_mask & IB_QP_AV) { 1459 + err = mlx5_set_path(dev, &attr->ah_attr, &context->pri_path, 1460 + attr_mask & IB_QP_PORT ? attr->port_num : qp->port, 1461 + attr_mask, 0, attr); 1462 + if (err) 1463 + goto out; 1464 + } 1465 + 1466 + if (attr_mask & IB_QP_TIMEOUT) 1467 + context->pri_path.ackto_lt |= attr->timeout << 3; 1468 + 1469 + if (attr_mask & IB_QP_ALT_PATH) { 1470 + err = mlx5_set_path(dev, &attr->alt_ah_attr, &context->alt_path, 1471 + attr->alt_port_num, attr_mask, 0, attr); 1472 + if (err) 1473 + goto out; 1474 + } 1475 + 1476 + pd = get_pd(qp); 1477 + get_cqs(qp, &send_cq, &recv_cq); 1478 + 1479 + context->flags_pd = cpu_to_be32(pd ? pd->pdn : to_mpd(dev->devr.p0)->pdn); 1480 + context->cqn_send = send_cq ? cpu_to_be32(send_cq->mcq.cqn) : 0; 1481 + context->cqn_recv = recv_cq ? cpu_to_be32(recv_cq->mcq.cqn) : 0; 1482 + context->params1 = cpu_to_be32(MLX5_IB_ACK_REQ_FREQ << 28); 1483 + 1484 + if (attr_mask & IB_QP_RNR_RETRY) 1485 + context->params1 |= cpu_to_be32(attr->rnr_retry << 13); 1486 + 1487 + if (attr_mask & IB_QP_RETRY_CNT) 1488 + context->params1 |= cpu_to_be32(attr->retry_cnt << 16); 1489 + 1490 + if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC) { 1491 + if (attr->max_rd_atomic) 1492 + context->params1 |= 1493 + cpu_to_be32(fls(attr->max_rd_atomic - 1) << 21); 1494 + } 1495 + 1496 + if (attr_mask & IB_QP_SQ_PSN) 1497 + context->next_send_psn = cpu_to_be32(attr->sq_psn); 1498 + 1499 + if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC) { 1500 + if (attr->max_dest_rd_atomic) 1501 + context->params2 |= 1502 + cpu_to_be32(fls(attr->max_dest_rd_atomic - 1) << 21); 1503 + } 1504 + 1505 + if (attr_mask & (IB_QP_ACCESS_FLAGS | IB_QP_MAX_DEST_RD_ATOMIC)) 1506 + context->params2 |= to_mlx5_access_flags(qp, attr, attr_mask); 1507 + 1508 + if (attr_mask & IB_QP_MIN_RNR_TIMER) 1509 + context->rnr_nextrecvpsn |= cpu_to_be32(attr->min_rnr_timer << 24); 1510 + 1511 + if (attr_mask & IB_QP_RQ_PSN) 1512 + context->rnr_nextrecvpsn |= cpu_to_be32(attr->rq_psn); 1513 + 1514 + if (attr_mask & IB_QP_QKEY) 1515 + context->qkey = cpu_to_be32(attr->qkey); 1516 + 1517 + if (qp->rq.wqe_cnt && cur_state == IB_QPS_RESET && new_state == IB_QPS_INIT) 1518 + context->db_rec_addr = cpu_to_be64(qp->db.dma); 1519 + 1520 + if (cur_state == IB_QPS_RTS && new_state == IB_QPS_SQD && 1521 + attr_mask & IB_QP_EN_SQD_ASYNC_NOTIFY && attr->en_sqd_async_notify) 1522 + sqd_event = 1; 1523 + else 1524 + sqd_event = 0; 1525 + 1526 + if (!ibqp->uobject && cur_state == IB_QPS_RESET && new_state == IB_QPS_INIT) 1527 + context->sq_crq_size |= cpu_to_be16(1 << 4); 1528 + 1529 + 1530 + mlx5_cur = to_mlx5_state(cur_state); 1531 + mlx5_new = to_mlx5_state(new_state); 1532 + mlx5_st = to_mlx5_st(ibqp->qp_type); 1533 + if (mlx5_cur < 0 || mlx5_new < 0 || mlx5_st < 0) 1534 + goto out; 1535 + 1536 + optpar = ib_mask_to_mlx5_opt(attr_mask); 1537 + optpar &= opt_mask[mlx5_cur][mlx5_new][mlx5_st]; 1538 + in->optparam = cpu_to_be32(optpar); 1539 + err = mlx5_core_qp_modify(&dev->mdev, to_mlx5_state(cur_state), 1540 + to_mlx5_state(new_state), in, sqd_event, 1541 + &qp->mqp); 1542 + if (err) 1543 + goto out; 1544 + 1545 + qp->state = new_state; 1546 + 1547 + if (attr_mask & IB_QP_ACCESS_FLAGS) 1548 + qp->atomic_rd_en = attr->qp_access_flags; 1549 + if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC) 1550 + qp->resp_depth = attr->max_dest_rd_atomic; 1551 + if (attr_mask & IB_QP_PORT) 1552 + qp->port = attr->port_num; 1553 + if (attr_mask & IB_QP_ALT_PATH) 1554 + qp->alt_port = attr->alt_port_num; 1555 + 1556 + /* 1557 + * If we moved a kernel QP to RESET, clean up all old CQ 1558 + * entries and reinitialize the QP. 1559 + */ 1560 + if (new_state == IB_QPS_RESET && !ibqp->uobject) { 1561 + mlx5_ib_cq_clean(recv_cq, qp->mqp.qpn, 1562 + ibqp->srq ? to_msrq(ibqp->srq) : NULL); 1563 + if (send_cq != recv_cq) 1564 + mlx5_ib_cq_clean(send_cq, qp->mqp.qpn, NULL); 1565 + 1566 + qp->rq.head = 0; 1567 + qp->rq.tail = 0; 1568 + qp->sq.head = 0; 1569 + qp->sq.tail = 0; 1570 + qp->sq.cur_post = 0; 1571 + qp->sq.last_poll = 0; 1572 + qp->db.db[MLX5_RCV_DBR] = 0; 1573 + qp->db.db[MLX5_SND_DBR] = 0; 1574 + } 1575 + 1576 + out: 1577 + kfree(in); 1578 + return err; 1579 + } 1580 + 1581 + int mlx5_ib_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, 1582 + int attr_mask, struct ib_udata *udata) 1583 + { 1584 + struct mlx5_ib_dev *dev = to_mdev(ibqp->device); 1585 + struct mlx5_ib_qp *qp = to_mqp(ibqp); 1586 + enum ib_qp_state cur_state, new_state; 1587 + int err = -EINVAL; 1588 + int port; 1589 + 1590 + mutex_lock(&qp->mutex); 1591 + 1592 + cur_state = attr_mask & IB_QP_CUR_STATE ? attr->cur_qp_state : qp->state; 1593 + new_state = attr_mask & IB_QP_STATE ? attr->qp_state : cur_state; 1594 + 1595 + if (ibqp->qp_type != MLX5_IB_QPT_REG_UMR && 1596 + !ib_modify_qp_is_ok(cur_state, new_state, ibqp->qp_type, attr_mask)) 1597 + goto out; 1598 + 1599 + if ((attr_mask & IB_QP_PORT) && 1600 + (attr->port_num == 0 || attr->port_num > dev->mdev.caps.num_ports)) 1601 + goto out; 1602 + 1603 + if (attr_mask & IB_QP_PKEY_INDEX) { 1604 + port = attr_mask & IB_QP_PORT ? attr->port_num : qp->port; 1605 + if (attr->pkey_index >= dev->mdev.caps.port[port - 1].pkey_table_len) 1606 + goto out; 1607 + } 1608 + 1609 + if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC && 1610 + attr->max_rd_atomic > dev->mdev.caps.max_ra_res_qp) 1611 + goto out; 1612 + 1613 + if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC && 1614 + attr->max_dest_rd_atomic > dev->mdev.caps.max_ra_req_qp) 1615 + goto out; 1616 + 1617 + if (cur_state == new_state && cur_state == IB_QPS_RESET) { 1618 + err = 0; 1619 + goto out; 1620 + } 1621 + 1622 + err = __mlx5_ib_modify_qp(ibqp, attr, attr_mask, cur_state, new_state); 1623 + 1624 + out: 1625 + mutex_unlock(&qp->mutex); 1626 + return err; 1627 + } 1628 + 1629 + static int mlx5_wq_overflow(struct mlx5_ib_wq *wq, int nreq, struct ib_cq *ib_cq) 1630 + { 1631 + struct mlx5_ib_cq *cq; 1632 + unsigned cur; 1633 + 1634 + cur = wq->head - wq->tail; 1635 + if (likely(cur + nreq < wq->max_post)) 1636 + return 0; 1637 + 1638 + cq = to_mcq(ib_cq); 1639 + spin_lock(&cq->lock); 1640 + cur = wq->head - wq->tail; 1641 + spin_unlock(&cq->lock); 1642 + 1643 + return cur + nreq >= wq->max_post; 1644 + } 1645 + 1646 + static __always_inline void set_raddr_seg(struct mlx5_wqe_raddr_seg *rseg, 1647 + u64 remote_addr, u32 rkey) 1648 + { 1649 + rseg->raddr = cpu_to_be64(remote_addr); 1650 + rseg->rkey = cpu_to_be32(rkey); 1651 + rseg->reserved = 0; 1652 + } 1653 + 1654 + static void set_atomic_seg(struct mlx5_wqe_atomic_seg *aseg, struct ib_send_wr *wr) 1655 + { 1656 + if (wr->opcode == IB_WR_ATOMIC_CMP_AND_SWP) { 1657 + aseg->swap_add = cpu_to_be64(wr->wr.atomic.swap); 1658 + aseg->compare = cpu_to_be64(wr->wr.atomic.compare_add); 1659 + } else if (wr->opcode == IB_WR_MASKED_ATOMIC_FETCH_AND_ADD) { 1660 + aseg->swap_add = cpu_to_be64(wr->wr.atomic.compare_add); 1661 + aseg->compare = cpu_to_be64(wr->wr.atomic.compare_add_mask); 1662 + } else { 1663 + aseg->swap_add = cpu_to_be64(wr->wr.atomic.compare_add); 1664 + aseg->compare = 0; 1665 + } 1666 + } 1667 + 1668 + static void set_masked_atomic_seg(struct mlx5_wqe_masked_atomic_seg *aseg, 1669 + struct ib_send_wr *wr) 1670 + { 1671 + aseg->swap_add = cpu_to_be64(wr->wr.atomic.swap); 1672 + aseg->swap_add_mask = cpu_to_be64(wr->wr.atomic.swap_mask); 1673 + aseg->compare = cpu_to_be64(wr->wr.atomic.compare_add); 1674 + aseg->compare_mask = cpu_to_be64(wr->wr.atomic.compare_add_mask); 1675 + } 1676 + 1677 + static void set_datagram_seg(struct mlx5_wqe_datagram_seg *dseg, 1678 + struct ib_send_wr *wr) 1679 + { 1680 + memcpy(&dseg->av, &to_mah(wr->wr.ud.ah)->av, sizeof(struct mlx5_av)); 1681 + dseg->av.dqp_dct = cpu_to_be32(wr->wr.ud.remote_qpn | MLX5_EXTENDED_UD_AV); 1682 + dseg->av.key.qkey.qkey = cpu_to_be32(wr->wr.ud.remote_qkey); 1683 + } 1684 + 1685 + static void set_data_ptr_seg(struct mlx5_wqe_data_seg *dseg, struct ib_sge *sg) 1686 + { 1687 + dseg->byte_count = cpu_to_be32(sg->length); 1688 + dseg->lkey = cpu_to_be32(sg->lkey); 1689 + dseg->addr = cpu_to_be64(sg->addr); 1690 + } 1691 + 1692 + static __be16 get_klm_octo(int npages) 1693 + { 1694 + return cpu_to_be16(ALIGN(npages, 8) / 2); 1695 + } 1696 + 1697 + static __be64 frwr_mkey_mask(void) 1698 + { 1699 + u64 result; 1700 + 1701 + result = MLX5_MKEY_MASK_LEN | 1702 + MLX5_MKEY_MASK_PAGE_SIZE | 1703 + MLX5_MKEY_MASK_START_ADDR | 1704 + MLX5_MKEY_MASK_EN_RINVAL | 1705 + MLX5_MKEY_MASK_KEY | 1706 + MLX5_MKEY_MASK_LR | 1707 + MLX5_MKEY_MASK_LW | 1708 + MLX5_MKEY_MASK_RR | 1709 + MLX5_MKEY_MASK_RW | 1710 + MLX5_MKEY_MASK_A | 1711 + MLX5_MKEY_MASK_SMALL_FENCE | 1712 + MLX5_MKEY_MASK_FREE; 1713 + 1714 + return cpu_to_be64(result); 1715 + } 1716 + 1717 + static void set_frwr_umr_segment(struct mlx5_wqe_umr_ctrl_seg *umr, 1718 + struct ib_send_wr *wr, int li) 1719 + { 1720 + memset(umr, 0, sizeof(*umr)); 1721 + 1722 + if (li) { 1723 + umr->mkey_mask = cpu_to_be64(MLX5_MKEY_MASK_FREE); 1724 + umr->flags = 1 << 7; 1725 + return; 1726 + } 1727 + 1728 + umr->flags = (1 << 5); /* fail if not free */ 1729 + umr->klm_octowords = get_klm_octo(wr->wr.fast_reg.page_list_len); 1730 + umr->mkey_mask = frwr_mkey_mask(); 1731 + } 1732 + 1733 + static void set_reg_umr_segment(struct mlx5_wqe_umr_ctrl_seg *umr, 1734 + struct ib_send_wr *wr) 1735 + { 1736 + struct umr_wr *umrwr = (struct umr_wr *)&wr->wr.fast_reg; 1737 + u64 mask; 1738 + 1739 + memset(umr, 0, sizeof(*umr)); 1740 + 1741 + if (!(wr->send_flags & MLX5_IB_SEND_UMR_UNREG)) { 1742 + umr->flags = 1 << 5; /* fail if not free */ 1743 + umr->klm_octowords = get_klm_octo(umrwr->npages); 1744 + mask = MLX5_MKEY_MASK_LEN | 1745 + MLX5_MKEY_MASK_PAGE_SIZE | 1746 + MLX5_MKEY_MASK_START_ADDR | 1747 + MLX5_MKEY_MASK_PD | 1748 + MLX5_MKEY_MASK_LR | 1749 + MLX5_MKEY_MASK_LW | 1750 + MLX5_MKEY_MASK_RR | 1751 + MLX5_MKEY_MASK_RW | 1752 + MLX5_MKEY_MASK_A | 1753 + MLX5_MKEY_MASK_FREE; 1754 + umr->mkey_mask = cpu_to_be64(mask); 1755 + } else { 1756 + umr->flags = 2 << 5; /* fail if free */ 1757 + mask = MLX5_MKEY_MASK_FREE; 1758 + umr->mkey_mask = cpu_to_be64(mask); 1759 + } 1760 + 1761 + if (!wr->num_sge) 1762 + umr->flags |= (1 << 7); /* inline */ 1763 + } 1764 + 1765 + static u8 get_umr_flags(int acc) 1766 + { 1767 + return (acc & IB_ACCESS_REMOTE_ATOMIC ? MLX5_PERM_ATOMIC : 0) | 1768 + (acc & IB_ACCESS_REMOTE_WRITE ? MLX5_PERM_REMOTE_WRITE : 0) | 1769 + (acc & IB_ACCESS_REMOTE_READ ? MLX5_PERM_REMOTE_READ : 0) | 1770 + (acc & IB_ACCESS_LOCAL_WRITE ? MLX5_PERM_LOCAL_WRITE : 0) | 1771 + MLX5_PERM_LOCAL_READ | MLX5_PERM_UMR_EN | MLX5_ACCESS_MODE_MTT; 1772 + } 1773 + 1774 + static void set_mkey_segment(struct mlx5_mkey_seg *seg, struct ib_send_wr *wr, 1775 + int li, int *writ) 1776 + { 1777 + memset(seg, 0, sizeof(*seg)); 1778 + if (li) { 1779 + seg->status = 1 << 6; 1780 + return; 1781 + } 1782 + 1783 + seg->flags = get_umr_flags(wr->wr.fast_reg.access_flags); 1784 + *writ = seg->flags & (MLX5_PERM_LOCAL_WRITE | IB_ACCESS_REMOTE_WRITE); 1785 + seg->qpn_mkey7_0 = cpu_to_be32((wr->wr.fast_reg.rkey & 0xff) | 0xffffff00); 1786 + seg->flags_pd = cpu_to_be32(MLX5_MKEY_REMOTE_INVAL); 1787 + seg->start_addr = cpu_to_be64(wr->wr.fast_reg.iova_start); 1788 + seg->len = cpu_to_be64(wr->wr.fast_reg.length); 1789 + seg->xlt_oct_size = cpu_to_be32((wr->wr.fast_reg.page_list_len + 1) / 2); 1790 + seg->log2_page_size = wr->wr.fast_reg.page_shift; 1791 + } 1792 + 1793 + static void set_reg_mkey_segment(struct mlx5_mkey_seg *seg, struct ib_send_wr *wr) 1794 + { 1795 + memset(seg, 0, sizeof(*seg)); 1796 + if (wr->send_flags & MLX5_IB_SEND_UMR_UNREG) { 1797 + seg->status = 1 << 6; 1798 + return; 1799 + } 1800 + 1801 + seg->flags = convert_access(wr->wr.fast_reg.access_flags); 1802 + seg->flags_pd = cpu_to_be32(to_mpd((struct ib_pd *)wr->wr.fast_reg.page_list)->pdn); 1803 + seg->start_addr = cpu_to_be64(wr->wr.fast_reg.iova_start); 1804 + seg->len = cpu_to_be64(wr->wr.fast_reg.length); 1805 + seg->log2_page_size = wr->wr.fast_reg.page_shift; 1806 + seg->qpn_mkey7_0 = cpu_to_be32(0xffffff << 8); 1807 + } 1808 + 1809 + static void set_frwr_pages(struct mlx5_wqe_data_seg *dseg, 1810 + struct ib_send_wr *wr, 1811 + struct mlx5_core_dev *mdev, 1812 + struct mlx5_ib_pd *pd, 1813 + int writ) 1814 + { 1815 + struct mlx5_ib_fast_reg_page_list *mfrpl = to_mfrpl(wr->wr.fast_reg.page_list); 1816 + u64 *page_list = wr->wr.fast_reg.page_list->page_list; 1817 + u64 perm = MLX5_EN_RD | (writ ? MLX5_EN_WR : 0); 1818 + int i; 1819 + 1820 + for (i = 0; i < wr->wr.fast_reg.page_list_len; i++) 1821 + mfrpl->mapped_page_list[i] = cpu_to_be64(page_list[i] | perm); 1822 + dseg->addr = cpu_to_be64(mfrpl->map); 1823 + dseg->byte_count = cpu_to_be32(ALIGN(sizeof(u64) * wr->wr.fast_reg.page_list_len, 64)); 1824 + dseg->lkey = cpu_to_be32(pd->pa_lkey); 1825 + } 1826 + 1827 + static __be32 send_ieth(struct ib_send_wr *wr) 1828 + { 1829 + switch (wr->opcode) { 1830 + case IB_WR_SEND_WITH_IMM: 1831 + case IB_WR_RDMA_WRITE_WITH_IMM: 1832 + return wr->ex.imm_data; 1833 + 1834 + case IB_WR_SEND_WITH_INV: 1835 + return cpu_to_be32(wr->ex.invalidate_rkey); 1836 + 1837 + default: 1838 + return 0; 1839 + } 1840 + } 1841 + 1842 + static u8 calc_sig(void *wqe, int size) 1843 + { 1844 + u8 *p = wqe; 1845 + u8 res = 0; 1846 + int i; 1847 + 1848 + for (i = 0; i < size; i++) 1849 + res ^= p[i]; 1850 + 1851 + return ~res; 1852 + } 1853 + 1854 + static u8 wq_sig(void *wqe) 1855 + { 1856 + return calc_sig(wqe, (*((u8 *)wqe + 8) & 0x3f) << 4); 1857 + } 1858 + 1859 + static int set_data_inl_seg(struct mlx5_ib_qp *qp, struct ib_send_wr *wr, 1860 + void *wqe, int *sz) 1861 + { 1862 + struct mlx5_wqe_inline_seg *seg; 1863 + void *qend = qp->sq.qend; 1864 + void *addr; 1865 + int inl = 0; 1866 + int copy; 1867 + int len; 1868 + int i; 1869 + 1870 + seg = wqe; 1871 + wqe += sizeof(*seg); 1872 + for (i = 0; i < wr->num_sge; i++) { 1873 + addr = (void *)(unsigned long)(wr->sg_list[i].addr); 1874 + len = wr->sg_list[i].length; 1875 + inl += len; 1876 + 1877 + if (unlikely(inl > qp->max_inline_data)) 1878 + return -ENOMEM; 1879 + 1880 + if (unlikely(wqe + len > qend)) { 1881 + copy = qend - wqe; 1882 + memcpy(wqe, addr, copy); 1883 + addr += copy; 1884 + len -= copy; 1885 + wqe = mlx5_get_send_wqe(qp, 0); 1886 + } 1887 + memcpy(wqe, addr, len); 1888 + wqe += len; 1889 + } 1890 + 1891 + seg->byte_count = cpu_to_be32(inl | MLX5_INLINE_SEG); 1892 + 1893 + *sz = ALIGN(inl + sizeof(seg->byte_count), 16) / 16; 1894 + 1895 + return 0; 1896 + } 1897 + 1898 + static int set_frwr_li_wr(void **seg, struct ib_send_wr *wr, int *size, 1899 + struct mlx5_core_dev *mdev, struct mlx5_ib_pd *pd, struct mlx5_ib_qp *qp) 1900 + { 1901 + int writ = 0; 1902 + int li; 1903 + 1904 + li = wr->opcode == IB_WR_LOCAL_INV ? 1 : 0; 1905 + if (unlikely(wr->send_flags & IB_SEND_INLINE)) 1906 + return -EINVAL; 1907 + 1908 + set_frwr_umr_segment(*seg, wr, li); 1909 + *seg += sizeof(struct mlx5_wqe_umr_ctrl_seg); 1910 + *size += sizeof(struct mlx5_wqe_umr_ctrl_seg) / 16; 1911 + if (unlikely((*seg == qp->sq.qend))) 1912 + *seg = mlx5_get_send_wqe(qp, 0); 1913 + set_mkey_segment(*seg, wr, li, &writ); 1914 + *seg += sizeof(struct mlx5_mkey_seg); 1915 + *size += sizeof(struct mlx5_mkey_seg) / 16; 1916 + if (unlikely((*seg == qp->sq.qend))) 1917 + *seg = mlx5_get_send_wqe(qp, 0); 1918 + if (!li) { 1919 + set_frwr_pages(*seg, wr, mdev, pd, writ); 1920 + *seg += sizeof(struct mlx5_wqe_data_seg); 1921 + *size += (sizeof(struct mlx5_wqe_data_seg) / 16); 1922 + } 1923 + return 0; 1924 + } 1925 + 1926 + static void dump_wqe(struct mlx5_ib_qp *qp, int idx, int size_16) 1927 + { 1928 + __be32 *p = NULL; 1929 + int tidx = idx; 1930 + int i, j; 1931 + 1932 + pr_debug("dump wqe at %p\n", mlx5_get_send_wqe(qp, tidx)); 1933 + for (i = 0, j = 0; i < size_16 * 4; i += 4, j += 4) { 1934 + if ((i & 0xf) == 0) { 1935 + void *buf = mlx5_get_send_wqe(qp, tidx); 1936 + tidx = (tidx + 1) & (qp->sq.wqe_cnt - 1); 1937 + p = buf; 1938 + j = 0; 1939 + } 1940 + pr_debug("%08x %08x %08x %08x\n", be32_to_cpu(p[j]), 1941 + be32_to_cpu(p[j + 1]), be32_to_cpu(p[j + 2]), 1942 + be32_to_cpu(p[j + 3])); 1943 + } 1944 + } 1945 + 1946 + static void mlx5_bf_copy(u64 __iomem *dst, u64 *src, 1947 + unsigned bytecnt, struct mlx5_ib_qp *qp) 1948 + { 1949 + while (bytecnt > 0) { 1950 + __iowrite64_copy(dst++, src++, 8); 1951 + __iowrite64_copy(dst++, src++, 8); 1952 + __iowrite64_copy(dst++, src++, 8); 1953 + __iowrite64_copy(dst++, src++, 8); 1954 + __iowrite64_copy(dst++, src++, 8); 1955 + __iowrite64_copy(dst++, src++, 8); 1956 + __iowrite64_copy(dst++, src++, 8); 1957 + __iowrite64_copy(dst++, src++, 8); 1958 + bytecnt -= 64; 1959 + if (unlikely(src == qp->sq.qend)) 1960 + src = mlx5_get_send_wqe(qp, 0); 1961 + } 1962 + } 1963 + 1964 + static u8 get_fence(u8 fence, struct ib_send_wr *wr) 1965 + { 1966 + if (unlikely(wr->opcode == IB_WR_LOCAL_INV && 1967 + wr->send_flags & IB_SEND_FENCE)) 1968 + return MLX5_FENCE_MODE_STRONG_ORDERING; 1969 + 1970 + if (unlikely(fence)) { 1971 + if (wr->send_flags & IB_SEND_FENCE) 1972 + return MLX5_FENCE_MODE_SMALL_AND_FENCE; 1973 + else 1974 + return fence; 1975 + 1976 + } else { 1977 + return 0; 1978 + } 1979 + } 1980 + 1981 + int mlx5_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, 1982 + struct ib_send_wr **bad_wr) 1983 + { 1984 + struct mlx5_wqe_ctrl_seg *ctrl = NULL; /* compiler warning */ 1985 + struct mlx5_ib_dev *dev = to_mdev(ibqp->device); 1986 + struct mlx5_core_dev *mdev = &dev->mdev; 1987 + struct mlx5_ib_qp *qp = to_mqp(ibqp); 1988 + struct mlx5_wqe_data_seg *dpseg; 1989 + struct mlx5_wqe_xrc_seg *xrc; 1990 + struct mlx5_bf *bf = qp->bf; 1991 + int uninitialized_var(size); 1992 + void *qend = qp->sq.qend; 1993 + unsigned long flags; 1994 + u32 mlx5_opcode; 1995 + unsigned idx; 1996 + int err = 0; 1997 + int inl = 0; 1998 + int num_sge; 1999 + void *seg; 2000 + int nreq; 2001 + int i; 2002 + u8 next_fence = 0; 2003 + u8 opmod = 0; 2004 + u8 fence; 2005 + 2006 + spin_lock_irqsave(&qp->sq.lock, flags); 2007 + 2008 + for (nreq = 0; wr; nreq++, wr = wr->next) { 2009 + if (unlikely(wr->opcode >= sizeof(mlx5_ib_opcode) / sizeof(mlx5_ib_opcode[0]))) { 2010 + mlx5_ib_warn(dev, "\n"); 2011 + err = -EINVAL; 2012 + *bad_wr = wr; 2013 + goto out; 2014 + } 2015 + 2016 + if (unlikely(mlx5_wq_overflow(&qp->sq, nreq, qp->ibqp.send_cq))) { 2017 + mlx5_ib_warn(dev, "\n"); 2018 + err = -ENOMEM; 2019 + *bad_wr = wr; 2020 + goto out; 2021 + } 2022 + 2023 + fence = qp->fm_cache; 2024 + num_sge = wr->num_sge; 2025 + if (unlikely(num_sge > qp->sq.max_gs)) { 2026 + mlx5_ib_warn(dev, "\n"); 2027 + err = -ENOMEM; 2028 + *bad_wr = wr; 2029 + goto out; 2030 + } 2031 + 2032 + idx = qp->sq.cur_post & (qp->sq.wqe_cnt - 1); 2033 + seg = mlx5_get_send_wqe(qp, idx); 2034 + ctrl = seg; 2035 + *(uint32_t *)(seg + 8) = 0; 2036 + ctrl->imm = send_ieth(wr); 2037 + ctrl->fm_ce_se = qp->sq_signal_bits | 2038 + (wr->send_flags & IB_SEND_SIGNALED ? 2039 + MLX5_WQE_CTRL_CQ_UPDATE : 0) | 2040 + (wr->send_flags & IB_SEND_SOLICITED ? 2041 + MLX5_WQE_CTRL_SOLICITED : 0); 2042 + 2043 + seg += sizeof(*ctrl); 2044 + size = sizeof(*ctrl) / 16; 2045 + 2046 + switch (ibqp->qp_type) { 2047 + case IB_QPT_XRC_INI: 2048 + xrc = seg; 2049 + xrc->xrc_srqn = htonl(wr->xrc_remote_srq_num); 2050 + seg += sizeof(*xrc); 2051 + size += sizeof(*xrc) / 16; 2052 + /* fall through */ 2053 + case IB_QPT_RC: 2054 + switch (wr->opcode) { 2055 + case IB_WR_RDMA_READ: 2056 + case IB_WR_RDMA_WRITE: 2057 + case IB_WR_RDMA_WRITE_WITH_IMM: 2058 + set_raddr_seg(seg, wr->wr.rdma.remote_addr, 2059 + wr->wr.rdma.rkey); 2060 + seg += sizeof(struct mlx5_wqe_raddr_seg); 2061 + size += sizeof(struct mlx5_wqe_raddr_seg) / 16; 2062 + break; 2063 + 2064 + case IB_WR_ATOMIC_CMP_AND_SWP: 2065 + case IB_WR_ATOMIC_FETCH_AND_ADD: 2066 + set_raddr_seg(seg, wr->wr.atomic.remote_addr, 2067 + wr->wr.atomic.rkey); 2068 + seg += sizeof(struct mlx5_wqe_raddr_seg); 2069 + 2070 + set_atomic_seg(seg, wr); 2071 + seg += sizeof(struct mlx5_wqe_atomic_seg); 2072 + 2073 + size += (sizeof(struct mlx5_wqe_raddr_seg) + 2074 + sizeof(struct mlx5_wqe_atomic_seg)) / 16; 2075 + break; 2076 + 2077 + case IB_WR_MASKED_ATOMIC_CMP_AND_SWP: 2078 + set_raddr_seg(seg, wr->wr.atomic.remote_addr, 2079 + wr->wr.atomic.rkey); 2080 + seg += sizeof(struct mlx5_wqe_raddr_seg); 2081 + 2082 + set_masked_atomic_seg(seg, wr); 2083 + seg += sizeof(struct mlx5_wqe_masked_atomic_seg); 2084 + 2085 + size += (sizeof(struct mlx5_wqe_raddr_seg) + 2086 + sizeof(struct mlx5_wqe_masked_atomic_seg)) / 16; 2087 + break; 2088 + 2089 + case IB_WR_LOCAL_INV: 2090 + next_fence = MLX5_FENCE_MODE_INITIATOR_SMALL; 2091 + qp->sq.wr_data[idx] = IB_WR_LOCAL_INV; 2092 + ctrl->imm = cpu_to_be32(wr->ex.invalidate_rkey); 2093 + err = set_frwr_li_wr(&seg, wr, &size, mdev, to_mpd(ibqp->pd), qp); 2094 + if (err) { 2095 + mlx5_ib_warn(dev, "\n"); 2096 + *bad_wr = wr; 2097 + goto out; 2098 + } 2099 + num_sge = 0; 2100 + break; 2101 + 2102 + case IB_WR_FAST_REG_MR: 2103 + next_fence = MLX5_FENCE_MODE_INITIATOR_SMALL; 2104 + qp->sq.wr_data[idx] = IB_WR_FAST_REG_MR; 2105 + ctrl->imm = cpu_to_be32(wr->wr.fast_reg.rkey); 2106 + err = set_frwr_li_wr(&seg, wr, &size, mdev, to_mpd(ibqp->pd), qp); 2107 + if (err) { 2108 + mlx5_ib_warn(dev, "\n"); 2109 + *bad_wr = wr; 2110 + goto out; 2111 + } 2112 + num_sge = 0; 2113 + break; 2114 + 2115 + default: 2116 + break; 2117 + } 2118 + break; 2119 + 2120 + case IB_QPT_UC: 2121 + switch (wr->opcode) { 2122 + case IB_WR_RDMA_WRITE: 2123 + case IB_WR_RDMA_WRITE_WITH_IMM: 2124 + set_raddr_seg(seg, wr->wr.rdma.remote_addr, 2125 + wr->wr.rdma.rkey); 2126 + seg += sizeof(struct mlx5_wqe_raddr_seg); 2127 + size += sizeof(struct mlx5_wqe_raddr_seg) / 16; 2128 + break; 2129 + 2130 + default: 2131 + break; 2132 + } 2133 + break; 2134 + 2135 + case IB_QPT_UD: 2136 + case IB_QPT_SMI: 2137 + case IB_QPT_GSI: 2138 + set_datagram_seg(seg, wr); 2139 + seg += sizeof(struct mlx5_wqe_datagram_seg); 2140 + size += sizeof(struct mlx5_wqe_datagram_seg) / 16; 2141 + if (unlikely((seg == qend))) 2142 + seg = mlx5_get_send_wqe(qp, 0); 2143 + break; 2144 + 2145 + case MLX5_IB_QPT_REG_UMR: 2146 + if (wr->opcode != MLX5_IB_WR_UMR) { 2147 + err = -EINVAL; 2148 + mlx5_ib_warn(dev, "bad opcode\n"); 2149 + goto out; 2150 + } 2151 + qp->sq.wr_data[idx] = MLX5_IB_WR_UMR; 2152 + ctrl->imm = cpu_to_be32(wr->wr.fast_reg.rkey); 2153 + set_reg_umr_segment(seg, wr); 2154 + seg += sizeof(struct mlx5_wqe_umr_ctrl_seg); 2155 + size += sizeof(struct mlx5_wqe_umr_ctrl_seg) / 16; 2156 + if (unlikely((seg == qend))) 2157 + seg = mlx5_get_send_wqe(qp, 0); 2158 + set_reg_mkey_segment(seg, wr); 2159 + seg += sizeof(struct mlx5_mkey_seg); 2160 + size += sizeof(struct mlx5_mkey_seg) / 16; 2161 + if (unlikely((seg == qend))) 2162 + seg = mlx5_get_send_wqe(qp, 0); 2163 + break; 2164 + 2165 + default: 2166 + break; 2167 + } 2168 + 2169 + if (wr->send_flags & IB_SEND_INLINE && num_sge) { 2170 + int uninitialized_var(sz); 2171 + 2172 + err = set_data_inl_seg(qp, wr, seg, &sz); 2173 + if (unlikely(err)) { 2174 + mlx5_ib_warn(dev, "\n"); 2175 + *bad_wr = wr; 2176 + goto out; 2177 + } 2178 + inl = 1; 2179 + size += sz; 2180 + } else { 2181 + dpseg = seg; 2182 + for (i = 0; i < num_sge; i++) { 2183 + if (unlikely(dpseg == qend)) { 2184 + seg = mlx5_get_send_wqe(qp, 0); 2185 + dpseg = seg; 2186 + } 2187 + if (likely(wr->sg_list[i].length)) { 2188 + set_data_ptr_seg(dpseg, wr->sg_list + i); 2189 + size += sizeof(struct mlx5_wqe_data_seg) / 16; 2190 + dpseg++; 2191 + } 2192 + } 2193 + } 2194 + 2195 + mlx5_opcode = mlx5_ib_opcode[wr->opcode]; 2196 + ctrl->opmod_idx_opcode = cpu_to_be32(((u32)(qp->sq.cur_post) << 8) | 2197 + mlx5_opcode | 2198 + ((u32)opmod << 24)); 2199 + ctrl->qpn_ds = cpu_to_be32(size | (qp->mqp.qpn << 8)); 2200 + ctrl->fm_ce_se |= get_fence(fence, wr); 2201 + qp->fm_cache = next_fence; 2202 + if (unlikely(qp->wq_sig)) 2203 + ctrl->signature = wq_sig(ctrl); 2204 + 2205 + qp->sq.wrid[idx] = wr->wr_id; 2206 + qp->sq.w_list[idx].opcode = mlx5_opcode; 2207 + qp->sq.wqe_head[idx] = qp->sq.head + nreq; 2208 + qp->sq.cur_post += DIV_ROUND_UP(size * 16, MLX5_SEND_WQE_BB); 2209 + qp->sq.w_list[idx].next = qp->sq.cur_post; 2210 + 2211 + if (0) 2212 + dump_wqe(qp, idx, size); 2213 + } 2214 + 2215 + out: 2216 + if (likely(nreq)) { 2217 + qp->sq.head += nreq; 2218 + 2219 + /* Make sure that descriptors are written before 2220 + * updating doorbell record and ringing the doorbell 2221 + */ 2222 + wmb(); 2223 + 2224 + qp->db.db[MLX5_SND_DBR] = cpu_to_be32(qp->sq.cur_post); 2225 + 2226 + if (bf->need_lock) 2227 + spin_lock(&bf->lock); 2228 + 2229 + /* TBD enable WC */ 2230 + if (0 && nreq == 1 && bf->uuarn && inl && size > 1 && size <= bf->buf_size / 16) { 2231 + mlx5_bf_copy(bf->reg + bf->offset, (u64 *)ctrl, ALIGN(size * 16, 64), qp); 2232 + /* wc_wmb(); */ 2233 + } else { 2234 + mlx5_write64((__be32 *)ctrl, bf->regreg + bf->offset, 2235 + MLX5_GET_DOORBELL_LOCK(&bf->lock32)); 2236 + /* Make sure doorbells don't leak out of SQ spinlock 2237 + * and reach the HCA out of order. 2238 + */ 2239 + mmiowb(); 2240 + } 2241 + bf->offset ^= bf->buf_size; 2242 + if (bf->need_lock) 2243 + spin_unlock(&bf->lock); 2244 + } 2245 + 2246 + spin_unlock_irqrestore(&qp->sq.lock, flags); 2247 + 2248 + return err; 2249 + } 2250 + 2251 + static void set_sig_seg(struct mlx5_rwqe_sig *sig, int size) 2252 + { 2253 + sig->signature = calc_sig(sig, size); 2254 + } 2255 + 2256 + int mlx5_ib_post_recv(struct ib_qp *ibqp, struct ib_recv_wr *wr, 2257 + struct ib_recv_wr **bad_wr) 2258 + { 2259 + struct mlx5_ib_qp *qp = to_mqp(ibqp); 2260 + struct mlx5_wqe_data_seg *scat; 2261 + struct mlx5_rwqe_sig *sig; 2262 + unsigned long flags; 2263 + int err = 0; 2264 + int nreq; 2265 + int ind; 2266 + int i; 2267 + 2268 + spin_lock_irqsave(&qp->rq.lock, flags); 2269 + 2270 + ind = qp->rq.head & (qp->rq.wqe_cnt - 1); 2271 + 2272 + for (nreq = 0; wr; nreq++, wr = wr->next) { 2273 + if (mlx5_wq_overflow(&qp->rq, nreq, qp->ibqp.recv_cq)) { 2274 + err = -ENOMEM; 2275 + *bad_wr = wr; 2276 + goto out; 2277 + } 2278 + 2279 + if (unlikely(wr->num_sge > qp->rq.max_gs)) { 2280 + err = -EINVAL; 2281 + *bad_wr = wr; 2282 + goto out; 2283 + } 2284 + 2285 + scat = get_recv_wqe(qp, ind); 2286 + if (qp->wq_sig) 2287 + scat++; 2288 + 2289 + for (i = 0; i < wr->num_sge; i++) 2290 + set_data_ptr_seg(scat + i, wr->sg_list + i); 2291 + 2292 + if (i < qp->rq.max_gs) { 2293 + scat[i].byte_count = 0; 2294 + scat[i].lkey = cpu_to_be32(MLX5_INVALID_LKEY); 2295 + scat[i].addr = 0; 2296 + } 2297 + 2298 + if (qp->wq_sig) { 2299 + sig = (struct mlx5_rwqe_sig *)scat; 2300 + set_sig_seg(sig, (qp->rq.max_gs + 1) << 2); 2301 + } 2302 + 2303 + qp->rq.wrid[ind] = wr->wr_id; 2304 + 2305 + ind = (ind + 1) & (qp->rq.wqe_cnt - 1); 2306 + } 2307 + 2308 + out: 2309 + if (likely(nreq)) { 2310 + qp->rq.head += nreq; 2311 + 2312 + /* Make sure that descriptors are written before 2313 + * doorbell record. 2314 + */ 2315 + wmb(); 2316 + 2317 + *qp->db.db = cpu_to_be32(qp->rq.head & 0xffff); 2318 + } 2319 + 2320 + spin_unlock_irqrestore(&qp->rq.lock, flags); 2321 + 2322 + return err; 2323 + } 2324 + 2325 + static inline enum ib_qp_state to_ib_qp_state(enum mlx5_qp_state mlx5_state) 2326 + { 2327 + switch (mlx5_state) { 2328 + case MLX5_QP_STATE_RST: return IB_QPS_RESET; 2329 + case MLX5_QP_STATE_INIT: return IB_QPS_INIT; 2330 + case MLX5_QP_STATE_RTR: return IB_QPS_RTR; 2331 + case MLX5_QP_STATE_RTS: return IB_QPS_RTS; 2332 + case MLX5_QP_STATE_SQ_DRAINING: 2333 + case MLX5_QP_STATE_SQD: return IB_QPS_SQD; 2334 + case MLX5_QP_STATE_SQER: return IB_QPS_SQE; 2335 + case MLX5_QP_STATE_ERR: return IB_QPS_ERR; 2336 + default: return -1; 2337 + } 2338 + } 2339 + 2340 + static inline enum ib_mig_state to_ib_mig_state(int mlx5_mig_state) 2341 + { 2342 + switch (mlx5_mig_state) { 2343 + case MLX5_QP_PM_ARMED: return IB_MIG_ARMED; 2344 + case MLX5_QP_PM_REARM: return IB_MIG_REARM; 2345 + case MLX5_QP_PM_MIGRATED: return IB_MIG_MIGRATED; 2346 + default: return -1; 2347 + } 2348 + } 2349 + 2350 + static int to_ib_qp_access_flags(int mlx5_flags) 2351 + { 2352 + int ib_flags = 0; 2353 + 2354 + if (mlx5_flags & MLX5_QP_BIT_RRE) 2355 + ib_flags |= IB_ACCESS_REMOTE_READ; 2356 + if (mlx5_flags & MLX5_QP_BIT_RWE) 2357 + ib_flags |= IB_ACCESS_REMOTE_WRITE; 2358 + if (mlx5_flags & MLX5_QP_BIT_RAE) 2359 + ib_flags |= IB_ACCESS_REMOTE_ATOMIC; 2360 + 2361 + return ib_flags; 2362 + } 2363 + 2364 + static void to_ib_ah_attr(struct mlx5_ib_dev *ibdev, struct ib_ah_attr *ib_ah_attr, 2365 + struct mlx5_qp_path *path) 2366 + { 2367 + struct mlx5_core_dev *dev = &ibdev->mdev; 2368 + 2369 + memset(ib_ah_attr, 0, sizeof(*ib_ah_attr)); 2370 + ib_ah_attr->port_num = path->port; 2371 + 2372 + if (ib_ah_attr->port_num == 0 || ib_ah_attr->port_num > dev->caps.num_ports) 2373 + return; 2374 + 2375 + ib_ah_attr->sl = path->sl & 0xf; 2376 + 2377 + ib_ah_attr->dlid = be16_to_cpu(path->rlid); 2378 + ib_ah_attr->src_path_bits = path->grh_mlid & 0x7f; 2379 + ib_ah_attr->static_rate = path->static_rate ? path->static_rate - 5 : 0; 2380 + ib_ah_attr->ah_flags = (path->grh_mlid & (1 << 7)) ? IB_AH_GRH : 0; 2381 + if (ib_ah_attr->ah_flags) { 2382 + ib_ah_attr->grh.sgid_index = path->mgid_index; 2383 + ib_ah_attr->grh.hop_limit = path->hop_limit; 2384 + ib_ah_attr->grh.traffic_class = 2385 + (be32_to_cpu(path->tclass_flowlabel) >> 20) & 0xff; 2386 + ib_ah_attr->grh.flow_label = 2387 + be32_to_cpu(path->tclass_flowlabel) & 0xfffff; 2388 + memcpy(ib_ah_attr->grh.dgid.raw, 2389 + path->rgid, sizeof(ib_ah_attr->grh.dgid.raw)); 2390 + } 2391 + } 2392 + 2393 + int mlx5_ib_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr, int qp_attr_mask, 2394 + struct ib_qp_init_attr *qp_init_attr) 2395 + { 2396 + struct mlx5_ib_dev *dev = to_mdev(ibqp->device); 2397 + struct mlx5_ib_qp *qp = to_mqp(ibqp); 2398 + struct mlx5_query_qp_mbox_out *outb; 2399 + struct mlx5_qp_context *context; 2400 + int mlx5_state; 2401 + int err = 0; 2402 + 2403 + mutex_lock(&qp->mutex); 2404 + outb = kzalloc(sizeof(*outb), GFP_KERNEL); 2405 + if (!outb) { 2406 + err = -ENOMEM; 2407 + goto out; 2408 + } 2409 + context = &outb->ctx; 2410 + err = mlx5_core_qp_query(&dev->mdev, &qp->mqp, outb, sizeof(*outb)); 2411 + if (err) 2412 + goto out_free; 2413 + 2414 + mlx5_state = be32_to_cpu(context->flags) >> 28; 2415 + 2416 + qp->state = to_ib_qp_state(mlx5_state); 2417 + qp_attr->qp_state = qp->state; 2418 + qp_attr->path_mtu = context->mtu_msgmax >> 5; 2419 + qp_attr->path_mig_state = 2420 + to_ib_mig_state((be32_to_cpu(context->flags) >> 11) & 0x3); 2421 + qp_attr->qkey = be32_to_cpu(context->qkey); 2422 + qp_attr->rq_psn = be32_to_cpu(context->rnr_nextrecvpsn) & 0xffffff; 2423 + qp_attr->sq_psn = be32_to_cpu(context->next_send_psn) & 0xffffff; 2424 + qp_attr->dest_qp_num = be32_to_cpu(context->log_pg_sz_remote_qpn) & 0xffffff; 2425 + qp_attr->qp_access_flags = 2426 + to_ib_qp_access_flags(be32_to_cpu(context->params2)); 2427 + 2428 + if (qp->ibqp.qp_type == IB_QPT_RC || qp->ibqp.qp_type == IB_QPT_UC) { 2429 + to_ib_ah_attr(dev, &qp_attr->ah_attr, &context->pri_path); 2430 + to_ib_ah_attr(dev, &qp_attr->alt_ah_attr, &context->alt_path); 2431 + qp_attr->alt_pkey_index = context->alt_path.pkey_index & 0x7f; 2432 + qp_attr->alt_port_num = qp_attr->alt_ah_attr.port_num; 2433 + } 2434 + 2435 + qp_attr->pkey_index = context->pri_path.pkey_index & 0x7f; 2436 + qp_attr->port_num = context->pri_path.port; 2437 + 2438 + /* qp_attr->en_sqd_async_notify is only applicable in modify qp */ 2439 + qp_attr->sq_draining = mlx5_state == MLX5_QP_STATE_SQ_DRAINING; 2440 + 2441 + qp_attr->max_rd_atomic = 1 << ((be32_to_cpu(context->params1) >> 21) & 0x7); 2442 + 2443 + qp_attr->max_dest_rd_atomic = 2444 + 1 << ((be32_to_cpu(context->params2) >> 21) & 0x7); 2445 + qp_attr->min_rnr_timer = 2446 + (be32_to_cpu(context->rnr_nextrecvpsn) >> 24) & 0x1f; 2447 + qp_attr->timeout = context->pri_path.ackto_lt >> 3; 2448 + qp_attr->retry_cnt = (be32_to_cpu(context->params1) >> 16) & 0x7; 2449 + qp_attr->rnr_retry = (be32_to_cpu(context->params1) >> 13) & 0x7; 2450 + qp_attr->alt_timeout = context->alt_path.ackto_lt >> 3; 2451 + qp_attr->cur_qp_state = qp_attr->qp_state; 2452 + qp_attr->cap.max_recv_wr = qp->rq.wqe_cnt; 2453 + qp_attr->cap.max_recv_sge = qp->rq.max_gs; 2454 + 2455 + if (!ibqp->uobject) { 2456 + qp_attr->cap.max_send_wr = qp->sq.wqe_cnt; 2457 + qp_attr->cap.max_send_sge = qp->sq.max_gs; 2458 + } else { 2459 + qp_attr->cap.max_send_wr = 0; 2460 + qp_attr->cap.max_send_sge = 0; 2461 + } 2462 + 2463 + /* We don't support inline sends for kernel QPs (yet), and we 2464 + * don't know what userspace's value should be. 2465 + */ 2466 + qp_attr->cap.max_inline_data = 0; 2467 + 2468 + qp_init_attr->cap = qp_attr->cap; 2469 + 2470 + qp_init_attr->create_flags = 0; 2471 + if (qp->flags & MLX5_IB_QP_BLOCK_MULTICAST_LOOPBACK) 2472 + qp_init_attr->create_flags |= IB_QP_CREATE_BLOCK_MULTICAST_LOOPBACK; 2473 + 2474 + qp_init_attr->sq_sig_type = qp->sq_signal_bits & MLX5_WQE_CTRL_CQ_UPDATE ? 2475 + IB_SIGNAL_ALL_WR : IB_SIGNAL_REQ_WR; 2476 + 2477 + out_free: 2478 + kfree(outb); 2479 + 2480 + out: 2481 + mutex_unlock(&qp->mutex); 2482 + return err; 2483 + } 2484 + 2485 + struct ib_xrcd *mlx5_ib_alloc_xrcd(struct ib_device *ibdev, 2486 + struct ib_ucontext *context, 2487 + struct ib_udata *udata) 2488 + { 2489 + struct mlx5_ib_dev *dev = to_mdev(ibdev); 2490 + struct mlx5_ib_xrcd *xrcd; 2491 + int err; 2492 + 2493 + if (!(dev->mdev.caps.flags & MLX5_DEV_CAP_FLAG_XRC)) 2494 + return ERR_PTR(-ENOSYS); 2495 + 2496 + xrcd = kmalloc(sizeof(*xrcd), GFP_KERNEL); 2497 + if (!xrcd) 2498 + return ERR_PTR(-ENOMEM); 2499 + 2500 + err = mlx5_core_xrcd_alloc(&dev->mdev, &xrcd->xrcdn); 2501 + if (err) { 2502 + kfree(xrcd); 2503 + return ERR_PTR(-ENOMEM); 2504 + } 2505 + 2506 + return &xrcd->ibxrcd; 2507 + } 2508 + 2509 + int mlx5_ib_dealloc_xrcd(struct ib_xrcd *xrcd) 2510 + { 2511 + struct mlx5_ib_dev *dev = to_mdev(xrcd->device); 2512 + u32 xrcdn = to_mxrcd(xrcd)->xrcdn; 2513 + int err; 2514 + 2515 + err = mlx5_core_xrcd_dealloc(&dev->mdev, xrcdn); 2516 + if (err) { 2517 + mlx5_ib_warn(dev, "failed to dealloc xrcdn 0x%x\n", xrcdn); 2518 + return err; 2519 + } 2520 + 2521 + kfree(xrcd); 2522 + 2523 + return 0; 2524 + }
+473
drivers/infiniband/hw/mlx5/srq.c
··· 1 + /* 2 + * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved. 3 + * 4 + * This software is available to you under a choice of one of two 5 + * licenses. You may choose to be licensed under the terms of the GNU 6 + * General Public License (GPL) Version 2, available from the file 7 + * COPYING in the main directory of this source tree, or the 8 + * OpenIB.org BSD license below: 9 + * 10 + * Redistribution and use in source and binary forms, with or 11 + * without modification, are permitted provided that the following 12 + * conditions are met: 13 + * 14 + * - Redistributions of source code must retain the above 15 + * copyright notice, this list of conditions and the following 16 + * disclaimer. 17 + * 18 + * - Redistributions in binary form must reproduce the above 19 + * copyright notice, this list of conditions and the following 20 + * disclaimer in the documentation and/or other materials 21 + * 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 OF 25 + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26 + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 27 + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 28 + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29 + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30 + * SOFTWARE. 31 + */ 32 + 33 + #include <linux/module.h> 34 + #include <linux/mlx5/qp.h> 35 + #include <linux/mlx5/srq.h> 36 + #include <linux/slab.h> 37 + #include <rdma/ib_umem.h> 38 + 39 + #include "mlx5_ib.h" 40 + #include "user.h" 41 + 42 + /* not supported currently */ 43 + static int srq_signature; 44 + 45 + static void *get_wqe(struct mlx5_ib_srq *srq, int n) 46 + { 47 + return mlx5_buf_offset(&srq->buf, n << srq->msrq.wqe_shift); 48 + } 49 + 50 + static void mlx5_ib_srq_event(struct mlx5_core_srq *srq, enum mlx5_event type) 51 + { 52 + struct ib_event event; 53 + struct ib_srq *ibsrq = &to_mibsrq(srq)->ibsrq; 54 + 55 + if (ibsrq->event_handler) { 56 + event.device = ibsrq->device; 57 + event.element.srq = ibsrq; 58 + switch (type) { 59 + case MLX5_EVENT_TYPE_SRQ_RQ_LIMIT: 60 + event.event = IB_EVENT_SRQ_LIMIT_REACHED; 61 + break; 62 + case MLX5_EVENT_TYPE_SRQ_CATAS_ERROR: 63 + event.event = IB_EVENT_SRQ_ERR; 64 + break; 65 + default: 66 + pr_warn("mlx5_ib: Unexpected event type %d on SRQ %06x\n", 67 + type, srq->srqn); 68 + return; 69 + } 70 + 71 + ibsrq->event_handler(&event, ibsrq->srq_context); 72 + } 73 + } 74 + 75 + static int create_srq_user(struct ib_pd *pd, struct mlx5_ib_srq *srq, 76 + struct mlx5_create_srq_mbox_in **in, 77 + struct ib_udata *udata, int buf_size, int *inlen) 78 + { 79 + struct mlx5_ib_dev *dev = to_mdev(pd->device); 80 + struct mlx5_ib_create_srq ucmd; 81 + int err; 82 + int npages; 83 + int page_shift; 84 + int ncont; 85 + u32 offset; 86 + 87 + if (ib_copy_from_udata(&ucmd, udata, sizeof(ucmd))) { 88 + mlx5_ib_dbg(dev, "failed copy udata\n"); 89 + return -EFAULT; 90 + } 91 + srq->wq_sig = !!(ucmd.flags & MLX5_SRQ_FLAG_SIGNATURE); 92 + 93 + srq->umem = ib_umem_get(pd->uobject->context, ucmd.buf_addr, buf_size, 94 + 0, 0); 95 + if (IS_ERR(srq->umem)) { 96 + mlx5_ib_dbg(dev, "failed umem get, size %d\n", buf_size); 97 + err = PTR_ERR(srq->umem); 98 + return err; 99 + } 100 + 101 + mlx5_ib_cont_pages(srq->umem, ucmd.buf_addr, &npages, 102 + &page_shift, &ncont, NULL); 103 + err = mlx5_ib_get_buf_offset(ucmd.buf_addr, page_shift, 104 + &offset); 105 + if (err) { 106 + mlx5_ib_warn(dev, "bad offset\n"); 107 + goto err_umem; 108 + } 109 + 110 + *inlen = sizeof(**in) + sizeof(*(*in)->pas) * ncont; 111 + *in = mlx5_vzalloc(*inlen); 112 + if (!(*in)) { 113 + err = -ENOMEM; 114 + goto err_umem; 115 + } 116 + 117 + mlx5_ib_populate_pas(dev, srq->umem, page_shift, (*in)->pas, 0); 118 + 119 + err = mlx5_ib_db_map_user(to_mucontext(pd->uobject->context), 120 + ucmd.db_addr, &srq->db); 121 + if (err) { 122 + mlx5_ib_dbg(dev, "map doorbell failed\n"); 123 + goto err_in; 124 + } 125 + 126 + (*in)->ctx.log_pg_sz = page_shift - PAGE_SHIFT; 127 + (*in)->ctx.pgoff_cqn = cpu_to_be32(offset << 26); 128 + 129 + return 0; 130 + 131 + err_in: 132 + mlx5_vfree(*in); 133 + 134 + err_umem: 135 + ib_umem_release(srq->umem); 136 + 137 + return err; 138 + } 139 + 140 + static int create_srq_kernel(struct mlx5_ib_dev *dev, struct mlx5_ib_srq *srq, 141 + struct mlx5_create_srq_mbox_in **in, int buf_size, 142 + int *inlen) 143 + { 144 + int err; 145 + int i; 146 + struct mlx5_wqe_srq_next_seg *next; 147 + int page_shift; 148 + int npages; 149 + 150 + err = mlx5_db_alloc(&dev->mdev, &srq->db); 151 + if (err) { 152 + mlx5_ib_warn(dev, "alloc dbell rec failed\n"); 153 + return err; 154 + } 155 + 156 + *srq->db.db = 0; 157 + 158 + if (mlx5_buf_alloc(&dev->mdev, buf_size, PAGE_SIZE * 2, &srq->buf)) { 159 + mlx5_ib_dbg(dev, "buf alloc failed\n"); 160 + err = -ENOMEM; 161 + goto err_db; 162 + } 163 + page_shift = srq->buf.page_shift; 164 + 165 + srq->head = 0; 166 + srq->tail = srq->msrq.max - 1; 167 + srq->wqe_ctr = 0; 168 + 169 + for (i = 0; i < srq->msrq.max; i++) { 170 + next = get_wqe(srq, i); 171 + next->next_wqe_index = 172 + cpu_to_be16((i + 1) & (srq->msrq.max - 1)); 173 + } 174 + 175 + npages = DIV_ROUND_UP(srq->buf.npages, 1 << (page_shift - PAGE_SHIFT)); 176 + mlx5_ib_dbg(dev, "buf_size %d, page_shift %d, npages %d, calc npages %d\n", 177 + buf_size, page_shift, srq->buf.npages, npages); 178 + *inlen = sizeof(**in) + sizeof(*(*in)->pas) * npages; 179 + *in = mlx5_vzalloc(*inlen); 180 + if (!*in) { 181 + err = -ENOMEM; 182 + goto err_buf; 183 + } 184 + mlx5_fill_page_array(&srq->buf, (*in)->pas); 185 + 186 + srq->wrid = kmalloc(srq->msrq.max * sizeof(u64), GFP_KERNEL); 187 + if (!srq->wrid) { 188 + mlx5_ib_dbg(dev, "kmalloc failed %lu\n", 189 + (unsigned long)(srq->msrq.max * sizeof(u64))); 190 + err = -ENOMEM; 191 + goto err_in; 192 + } 193 + srq->wq_sig = !!srq_signature; 194 + 195 + (*in)->ctx.log_pg_sz = page_shift - PAGE_SHIFT; 196 + 197 + return 0; 198 + 199 + err_in: 200 + mlx5_vfree(*in); 201 + 202 + err_buf: 203 + mlx5_buf_free(&dev->mdev, &srq->buf); 204 + 205 + err_db: 206 + mlx5_db_free(&dev->mdev, &srq->db); 207 + return err; 208 + } 209 + 210 + static void destroy_srq_user(struct ib_pd *pd, struct mlx5_ib_srq *srq) 211 + { 212 + mlx5_ib_db_unmap_user(to_mucontext(pd->uobject->context), &srq->db); 213 + ib_umem_release(srq->umem); 214 + } 215 + 216 + 217 + static void destroy_srq_kernel(struct mlx5_ib_dev *dev, struct mlx5_ib_srq *srq) 218 + { 219 + kfree(srq->wrid); 220 + mlx5_buf_free(&dev->mdev, &srq->buf); 221 + mlx5_db_free(&dev->mdev, &srq->db); 222 + } 223 + 224 + struct ib_srq *mlx5_ib_create_srq(struct ib_pd *pd, 225 + struct ib_srq_init_attr *init_attr, 226 + struct ib_udata *udata) 227 + { 228 + struct mlx5_ib_dev *dev = to_mdev(pd->device); 229 + struct mlx5_ib_srq *srq; 230 + int desc_size; 231 + int buf_size; 232 + int err; 233 + struct mlx5_create_srq_mbox_in *uninitialized_var(in); 234 + int uninitialized_var(inlen); 235 + int is_xrc; 236 + u32 flgs, xrcdn; 237 + 238 + /* Sanity check SRQ size before proceeding */ 239 + if (init_attr->attr.max_wr >= dev->mdev.caps.max_srq_wqes) { 240 + mlx5_ib_dbg(dev, "max_wr %d, cap %d\n", 241 + init_attr->attr.max_wr, 242 + dev->mdev.caps.max_srq_wqes); 243 + return ERR_PTR(-EINVAL); 244 + } 245 + 246 + srq = kmalloc(sizeof(*srq), GFP_KERNEL); 247 + if (!srq) 248 + return ERR_PTR(-ENOMEM); 249 + 250 + mutex_init(&srq->mutex); 251 + spin_lock_init(&srq->lock); 252 + srq->msrq.max = roundup_pow_of_two(init_attr->attr.max_wr + 1); 253 + srq->msrq.max_gs = init_attr->attr.max_sge; 254 + 255 + desc_size = sizeof(struct mlx5_wqe_srq_next_seg) + 256 + srq->msrq.max_gs * sizeof(struct mlx5_wqe_data_seg); 257 + desc_size = roundup_pow_of_two(desc_size); 258 + desc_size = max_t(int, 32, desc_size); 259 + srq->msrq.max_avail_gather = (desc_size - sizeof(struct mlx5_wqe_srq_next_seg)) / 260 + sizeof(struct mlx5_wqe_data_seg); 261 + srq->msrq.wqe_shift = ilog2(desc_size); 262 + buf_size = srq->msrq.max * desc_size; 263 + mlx5_ib_dbg(dev, "desc_size 0x%x, req wr 0x%x, srq size 0x%x, max_gs 0x%x, max_avail_gather 0x%x\n", 264 + desc_size, init_attr->attr.max_wr, srq->msrq.max, srq->msrq.max_gs, 265 + srq->msrq.max_avail_gather); 266 + 267 + if (pd->uobject) 268 + err = create_srq_user(pd, srq, &in, udata, buf_size, &inlen); 269 + else 270 + err = create_srq_kernel(dev, srq, &in, buf_size, &inlen); 271 + 272 + if (err) { 273 + mlx5_ib_warn(dev, "create srq %s failed, err %d\n", 274 + pd->uobject ? "user" : "kernel", err); 275 + goto err_srq; 276 + } 277 + 278 + is_xrc = (init_attr->srq_type == IB_SRQT_XRC); 279 + in->ctx.state_log_sz = ilog2(srq->msrq.max); 280 + flgs = ((srq->msrq.wqe_shift - 4) | (is_xrc << 5) | (srq->wq_sig << 7)) << 24; 281 + xrcdn = 0; 282 + if (is_xrc) { 283 + xrcdn = to_mxrcd(init_attr->ext.xrc.xrcd)->xrcdn; 284 + in->ctx.pgoff_cqn |= cpu_to_be32(to_mcq(init_attr->ext.xrc.cq)->mcq.cqn); 285 + } else if (init_attr->srq_type == IB_SRQT_BASIC) { 286 + xrcdn = to_mxrcd(dev->devr.x0)->xrcdn; 287 + in->ctx.pgoff_cqn |= cpu_to_be32(to_mcq(dev->devr.c0)->mcq.cqn); 288 + } 289 + 290 + in->ctx.flags_xrcd = cpu_to_be32((flgs & 0xFF000000) | (xrcdn & 0xFFFFFF)); 291 + 292 + in->ctx.pd = cpu_to_be32(to_mpd(pd)->pdn); 293 + in->ctx.db_record = cpu_to_be64(srq->db.dma); 294 + err = mlx5_core_create_srq(&dev->mdev, &srq->msrq, in, inlen); 295 + mlx5_vfree(in); 296 + if (err) { 297 + mlx5_ib_dbg(dev, "create SRQ failed, err %d\n", err); 298 + goto err_srq; 299 + } 300 + 301 + mlx5_ib_dbg(dev, "create SRQ with srqn 0x%x\n", srq->msrq.srqn); 302 + 303 + srq->msrq.event = mlx5_ib_srq_event; 304 + srq->ibsrq.ext.xrc.srq_num = srq->msrq.srqn; 305 + 306 + if (pd->uobject) 307 + if (ib_copy_to_udata(udata, &srq->msrq.srqn, sizeof(__u32))) { 308 + mlx5_ib_dbg(dev, "copy to user failed\n"); 309 + err = -EFAULT; 310 + goto err_core; 311 + } 312 + 313 + init_attr->attr.max_wr = srq->msrq.max - 1; 314 + 315 + return &srq->ibsrq; 316 + 317 + err_core: 318 + mlx5_core_destroy_srq(&dev->mdev, &srq->msrq); 319 + if (pd->uobject) 320 + destroy_srq_user(pd, srq); 321 + else 322 + destroy_srq_kernel(dev, srq); 323 + 324 + err_srq: 325 + kfree(srq); 326 + 327 + return ERR_PTR(err); 328 + } 329 + 330 + int mlx5_ib_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr, 331 + enum ib_srq_attr_mask attr_mask, struct ib_udata *udata) 332 + { 333 + struct mlx5_ib_dev *dev = to_mdev(ibsrq->device); 334 + struct mlx5_ib_srq *srq = to_msrq(ibsrq); 335 + int ret; 336 + 337 + /* We don't support resizing SRQs yet */ 338 + if (attr_mask & IB_SRQ_MAX_WR) 339 + return -EINVAL; 340 + 341 + if (attr_mask & IB_SRQ_LIMIT) { 342 + if (attr->srq_limit >= srq->msrq.max) 343 + return -EINVAL; 344 + 345 + mutex_lock(&srq->mutex); 346 + ret = mlx5_core_arm_srq(&dev->mdev, &srq->msrq, attr->srq_limit, 1); 347 + mutex_unlock(&srq->mutex); 348 + 349 + if (ret) 350 + return ret; 351 + } 352 + 353 + return 0; 354 + } 355 + 356 + int mlx5_ib_query_srq(struct ib_srq *ibsrq, struct ib_srq_attr *srq_attr) 357 + { 358 + struct mlx5_ib_dev *dev = to_mdev(ibsrq->device); 359 + struct mlx5_ib_srq *srq = to_msrq(ibsrq); 360 + int ret; 361 + struct mlx5_query_srq_mbox_out *out; 362 + 363 + out = kzalloc(sizeof(*out), GFP_KERNEL); 364 + if (!out) 365 + return -ENOMEM; 366 + 367 + ret = mlx5_core_query_srq(&dev->mdev, &srq->msrq, out); 368 + if (ret) 369 + goto out_box; 370 + 371 + srq_attr->srq_limit = be16_to_cpu(out->ctx.lwm); 372 + srq_attr->max_wr = srq->msrq.max - 1; 373 + srq_attr->max_sge = srq->msrq.max_gs; 374 + 375 + out_box: 376 + kfree(out); 377 + return ret; 378 + } 379 + 380 + int mlx5_ib_destroy_srq(struct ib_srq *srq) 381 + { 382 + struct mlx5_ib_dev *dev = to_mdev(srq->device); 383 + struct mlx5_ib_srq *msrq = to_msrq(srq); 384 + 385 + mlx5_core_destroy_srq(&dev->mdev, &msrq->msrq); 386 + 387 + if (srq->uobject) { 388 + mlx5_ib_db_unmap_user(to_mucontext(srq->uobject->context), &msrq->db); 389 + ib_umem_release(msrq->umem); 390 + } else { 391 + kfree(msrq->wrid); 392 + mlx5_buf_free(&dev->mdev, &msrq->buf); 393 + mlx5_db_free(&dev->mdev, &msrq->db); 394 + } 395 + 396 + kfree(srq); 397 + return 0; 398 + } 399 + 400 + void mlx5_ib_free_srq_wqe(struct mlx5_ib_srq *srq, int wqe_index) 401 + { 402 + struct mlx5_wqe_srq_next_seg *next; 403 + 404 + /* always called with interrupts disabled. */ 405 + spin_lock(&srq->lock); 406 + 407 + next = get_wqe(srq, srq->tail); 408 + next->next_wqe_index = cpu_to_be16(wqe_index); 409 + srq->tail = wqe_index; 410 + 411 + spin_unlock(&srq->lock); 412 + } 413 + 414 + int mlx5_ib_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr, 415 + struct ib_recv_wr **bad_wr) 416 + { 417 + struct mlx5_ib_srq *srq = to_msrq(ibsrq); 418 + struct mlx5_wqe_srq_next_seg *next; 419 + struct mlx5_wqe_data_seg *scat; 420 + unsigned long flags; 421 + int err = 0; 422 + int nreq; 423 + int i; 424 + 425 + spin_lock_irqsave(&srq->lock, flags); 426 + 427 + for (nreq = 0; wr; nreq++, wr = wr->next) { 428 + if (unlikely(wr->num_sge > srq->msrq.max_gs)) { 429 + err = -EINVAL; 430 + *bad_wr = wr; 431 + break; 432 + } 433 + 434 + if (unlikely(srq->head == srq->tail)) { 435 + err = -ENOMEM; 436 + *bad_wr = wr; 437 + break; 438 + } 439 + 440 + srq->wrid[srq->head] = wr->wr_id; 441 + 442 + next = get_wqe(srq, srq->head); 443 + srq->head = be16_to_cpu(next->next_wqe_index); 444 + scat = (struct mlx5_wqe_data_seg *)(next + 1); 445 + 446 + for (i = 0; i < wr->num_sge; i++) { 447 + scat[i].byte_count = cpu_to_be32(wr->sg_list[i].length); 448 + scat[i].lkey = cpu_to_be32(wr->sg_list[i].lkey); 449 + scat[i].addr = cpu_to_be64(wr->sg_list[i].addr); 450 + } 451 + 452 + if (i < srq->msrq.max_avail_gather) { 453 + scat[i].byte_count = 0; 454 + scat[i].lkey = cpu_to_be32(MLX5_INVALID_LKEY); 455 + scat[i].addr = 0; 456 + } 457 + } 458 + 459 + if (likely(nreq)) { 460 + srq->wqe_ctr += nreq; 461 + 462 + /* Make sure that descriptors are written before 463 + * doorbell record. 464 + */ 465 + wmb(); 466 + 467 + *srq->db.db = cpu_to_be32(srq->wqe_ctr); 468 + } 469 + 470 + spin_unlock_irqrestore(&srq->lock, flags); 471 + 472 + return err; 473 + }
+121
drivers/infiniband/hw/mlx5/user.h
··· 1 + /* 2 + * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved. 3 + * 4 + * This software is available to you under a choice of one of two 5 + * licenses. You may choose to be licensed under the terms of the GNU 6 + * General Public License (GPL) Version 2, available from the file 7 + * COPYING in the main directory of this source tree, or the 8 + * OpenIB.org BSD license below: 9 + * 10 + * Redistribution and use in source and binary forms, with or 11 + * without modification, are permitted provided that the following 12 + * conditions are met: 13 + * 14 + * - Redistributions of source code must retain the above 15 + * copyright notice, this list of conditions and the following 16 + * disclaimer. 17 + * 18 + * - Redistributions in binary form must reproduce the above 19 + * copyright notice, this list of conditions and the following 20 + * disclaimer in the documentation and/or other materials 21 + * 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 OF 25 + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26 + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 27 + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 28 + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29 + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30 + * SOFTWARE. 31 + */ 32 + 33 + #ifndef MLX5_IB_USER_H 34 + #define MLX5_IB_USER_H 35 + 36 + #include <linux/types.h> 37 + 38 + enum { 39 + MLX5_QP_FLAG_SIGNATURE = 1 << 0, 40 + MLX5_QP_FLAG_SCATTER_CQE = 1 << 1, 41 + }; 42 + 43 + enum { 44 + MLX5_SRQ_FLAG_SIGNATURE = 1 << 0, 45 + }; 46 + 47 + 48 + /* Increment this value if any changes that break userspace ABI 49 + * compatibility are made. 50 + */ 51 + #define MLX5_IB_UVERBS_ABI_VERSION 1 52 + 53 + /* Make sure that all structs defined in this file remain laid out so 54 + * that they pack the same way on 32-bit and 64-bit architectures (to 55 + * avoid incompatibility between 32-bit userspace and 64-bit kernels). 56 + * In particular do not use pointer types -- pass pointers in __u64 57 + * instead. 58 + */ 59 + 60 + struct mlx5_ib_alloc_ucontext_req { 61 + __u32 total_num_uuars; 62 + __u32 num_low_latency_uuars; 63 + }; 64 + 65 + struct mlx5_ib_alloc_ucontext_resp { 66 + __u32 qp_tab_size; 67 + __u32 bf_reg_size; 68 + __u32 tot_uuars; 69 + __u32 cache_line_size; 70 + __u16 max_sq_desc_sz; 71 + __u16 max_rq_desc_sz; 72 + __u32 max_send_wqebb; 73 + __u32 max_recv_wr; 74 + __u32 max_srq_recv_wr; 75 + __u16 num_ports; 76 + __u16 reserved; 77 + }; 78 + 79 + struct mlx5_ib_alloc_pd_resp { 80 + __u32 pdn; 81 + }; 82 + 83 + struct mlx5_ib_create_cq { 84 + __u64 buf_addr; 85 + __u64 db_addr; 86 + __u32 cqe_size; 87 + }; 88 + 89 + struct mlx5_ib_create_cq_resp { 90 + __u32 cqn; 91 + __u32 reserved; 92 + }; 93 + 94 + struct mlx5_ib_resize_cq { 95 + __u64 buf_addr; 96 + }; 97 + 98 + struct mlx5_ib_create_srq { 99 + __u64 buf_addr; 100 + __u64 db_addr; 101 + __u32 flags; 102 + }; 103 + 104 + struct mlx5_ib_create_srq_resp { 105 + __u32 srqn; 106 + __u32 reserved; 107 + }; 108 + 109 + struct mlx5_ib_create_qp { 110 + __u64 buf_addr; 111 + __u64 db_addr; 112 + __u32 sq_wqe_count; 113 + __u32 rq_wqe_count; 114 + __u32 rq_wqe_shift; 115 + __u32 flags; 116 + }; 117 + 118 + struct mlx5_ib_create_qp_resp { 119 + __u32 uuar_index; 120 + }; 121 + #endif /* MLX5_IB_USER_H */
+1
drivers/net/ethernet/mellanox/Kconfig
··· 19 19 if NET_VENDOR_MELLANOX 20 20 21 21 source "drivers/net/ethernet/mellanox/mlx4/Kconfig" 22 + source "drivers/net/ethernet/mellanox/mlx5/core/Kconfig" 22 23 23 24 endif # NET_VENDOR_MELLANOX
+1
drivers/net/ethernet/mellanox/Makefile
··· 3 3 # 4 4 5 5 obj-$(CONFIG_MLX4_CORE) += mlx4/ 6 + obj-$(CONFIG_MLX5_CORE) += mlx5/core/
+18
drivers/net/ethernet/mellanox/mlx5/core/Kconfig
··· 1 + # 2 + # Mellanox driver configuration 3 + # 4 + 5 + config MLX5_CORE 6 + tristate 7 + depends on PCI && X86 8 + default n 9 + 10 + config MLX5_DEBUG 11 + bool "Verbose debugging output" if (MLX5_CORE && EXPERT) 12 + depends on MLX5_CORE 13 + default y 14 + ---help--- 15 + This option causes debugging code to be compiled into the 16 + mlx5_core driver. The output can be turned on via the 17 + debug_mask module parameter (which can also be set after 18 + the driver is loaded through sysfs).
+5
drivers/net/ethernet/mellanox/mlx5/core/Makefile
··· 1 + obj-$(CONFIG_MLX5_CORE) += mlx5_core.o 2 + 3 + mlx5_core-y := main.o cmd.o debugfs.o fw.o eq.o uar.o pagealloc.o \ 4 + health.o mcg.o cq.o srq.o alloc.o qp.o port.o mr.o pd.o \ 5 + mad.o
+238
drivers/net/ethernet/mellanox/mlx5/core/alloc.c
··· 1 + /* 2 + * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved. 3 + * 4 + * This software is available to you under a choice of one of two 5 + * licenses. You may choose to be licensed under the terms of the GNU 6 + * General Public License (GPL) Version 2, available from the file 7 + * COPYING in the main directory of this source tree, or the 8 + * OpenIB.org BSD license below: 9 + * 10 + * Redistribution and use in source and binary forms, with or 11 + * without modification, are permitted provided that the following 12 + * conditions are met: 13 + * 14 + * - Redistributions of source code must retain the above 15 + * copyright notice, this list of conditions and the following 16 + * disclaimer. 17 + * 18 + * - Redistributions in binary form must reproduce the above 19 + * copyright notice, this list of conditions and the following 20 + * disclaimer in the documentation and/or other materials 21 + * 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 OF 25 + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26 + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 27 + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 28 + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29 + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30 + * SOFTWARE. 31 + */ 32 + 33 + #include <linux/errno.h> 34 + #include <linux/slab.h> 35 + #include <linux/mm.h> 36 + #include <linux/export.h> 37 + #include <linux/bitmap.h> 38 + #include <linux/dma-mapping.h> 39 + #include <linux/vmalloc.h> 40 + #include <linux/mlx5/driver.h> 41 + 42 + #include "mlx5_core.h" 43 + 44 + /* Handling for queue buffers -- we allocate a bunch of memory and 45 + * register it in a memory region at HCA virtual address 0. If the 46 + * requested size is > max_direct, we split the allocation into 47 + * multiple pages, so we don't require too much contiguous memory. 48 + */ 49 + 50 + int mlx5_buf_alloc(struct mlx5_core_dev *dev, int size, int max_direct, 51 + struct mlx5_buf *buf) 52 + { 53 + dma_addr_t t; 54 + 55 + buf->size = size; 56 + if (size <= max_direct) { 57 + buf->nbufs = 1; 58 + buf->npages = 1; 59 + buf->page_shift = get_order(size) + PAGE_SHIFT; 60 + buf->direct.buf = dma_zalloc_coherent(&dev->pdev->dev, 61 + size, &t, GFP_KERNEL); 62 + if (!buf->direct.buf) 63 + return -ENOMEM; 64 + 65 + buf->direct.map = t; 66 + 67 + while (t & ((1 << buf->page_shift) - 1)) { 68 + --buf->page_shift; 69 + buf->npages *= 2; 70 + } 71 + } else { 72 + int i; 73 + 74 + buf->direct.buf = NULL; 75 + buf->nbufs = (size + PAGE_SIZE - 1) / PAGE_SIZE; 76 + buf->npages = buf->nbufs; 77 + buf->page_shift = PAGE_SHIFT; 78 + buf->page_list = kcalloc(buf->nbufs, sizeof(*buf->page_list), 79 + GFP_KERNEL); 80 + if (!buf->page_list) 81 + return -ENOMEM; 82 + 83 + for (i = 0; i < buf->nbufs; i++) { 84 + buf->page_list[i].buf = 85 + dma_zalloc_coherent(&dev->pdev->dev, PAGE_SIZE, 86 + &t, GFP_KERNEL); 87 + if (!buf->page_list[i].buf) 88 + goto err_free; 89 + 90 + buf->page_list[i].map = t; 91 + } 92 + 93 + if (BITS_PER_LONG == 64) { 94 + struct page **pages; 95 + pages = kmalloc(sizeof(*pages) * buf->nbufs, GFP_KERNEL); 96 + if (!pages) 97 + goto err_free; 98 + for (i = 0; i < buf->nbufs; i++) 99 + pages[i] = virt_to_page(buf->page_list[i].buf); 100 + buf->direct.buf = vmap(pages, buf->nbufs, VM_MAP, PAGE_KERNEL); 101 + kfree(pages); 102 + if (!buf->direct.buf) 103 + goto err_free; 104 + } 105 + } 106 + 107 + return 0; 108 + 109 + err_free: 110 + mlx5_buf_free(dev, buf); 111 + 112 + return -ENOMEM; 113 + } 114 + EXPORT_SYMBOL_GPL(mlx5_buf_alloc); 115 + 116 + void mlx5_buf_free(struct mlx5_core_dev *dev, struct mlx5_buf *buf) 117 + { 118 + int i; 119 + 120 + if (buf->nbufs == 1) 121 + dma_free_coherent(&dev->pdev->dev, buf->size, buf->direct.buf, 122 + buf->direct.map); 123 + else { 124 + if (BITS_PER_LONG == 64 && buf->direct.buf) 125 + vunmap(buf->direct.buf); 126 + 127 + for (i = 0; i < buf->nbufs; i++) 128 + if (buf->page_list[i].buf) 129 + dma_free_coherent(&dev->pdev->dev, PAGE_SIZE, 130 + buf->page_list[i].buf, 131 + buf->page_list[i].map); 132 + kfree(buf->page_list); 133 + } 134 + } 135 + EXPORT_SYMBOL_GPL(mlx5_buf_free); 136 + 137 + static struct mlx5_db_pgdir *mlx5_alloc_db_pgdir(struct device *dma_device) 138 + { 139 + struct mlx5_db_pgdir *pgdir; 140 + 141 + pgdir = kzalloc(sizeof(*pgdir), GFP_KERNEL); 142 + if (!pgdir) 143 + return NULL; 144 + 145 + bitmap_fill(pgdir->bitmap, MLX5_DB_PER_PAGE); 146 + pgdir->db_page = dma_alloc_coherent(dma_device, PAGE_SIZE, 147 + &pgdir->db_dma, GFP_KERNEL); 148 + if (!pgdir->db_page) { 149 + kfree(pgdir); 150 + return NULL; 151 + } 152 + 153 + return pgdir; 154 + } 155 + 156 + static int mlx5_alloc_db_from_pgdir(struct mlx5_db_pgdir *pgdir, 157 + struct mlx5_db *db) 158 + { 159 + int offset; 160 + int i; 161 + 162 + i = find_first_bit(pgdir->bitmap, MLX5_DB_PER_PAGE); 163 + if (i >= MLX5_DB_PER_PAGE) 164 + return -ENOMEM; 165 + 166 + __clear_bit(i, pgdir->bitmap); 167 + 168 + db->u.pgdir = pgdir; 169 + db->index = i; 170 + offset = db->index * L1_CACHE_BYTES; 171 + db->db = pgdir->db_page + offset / sizeof(*pgdir->db_page); 172 + db->dma = pgdir->db_dma + offset; 173 + 174 + return 0; 175 + } 176 + 177 + int mlx5_db_alloc(struct mlx5_core_dev *dev, struct mlx5_db *db) 178 + { 179 + struct mlx5_db_pgdir *pgdir; 180 + int ret = 0; 181 + 182 + mutex_lock(&dev->priv.pgdir_mutex); 183 + 184 + list_for_each_entry(pgdir, &dev->priv.pgdir_list, list) 185 + if (!mlx5_alloc_db_from_pgdir(pgdir, db)) 186 + goto out; 187 + 188 + pgdir = mlx5_alloc_db_pgdir(&(dev->pdev->dev)); 189 + if (!pgdir) { 190 + ret = -ENOMEM; 191 + goto out; 192 + } 193 + 194 + list_add(&pgdir->list, &dev->priv.pgdir_list); 195 + 196 + /* This should never fail -- we just allocated an empty page: */ 197 + WARN_ON(mlx5_alloc_db_from_pgdir(pgdir, db)); 198 + 199 + out: 200 + mutex_unlock(&dev->priv.pgdir_mutex); 201 + 202 + return ret; 203 + } 204 + EXPORT_SYMBOL_GPL(mlx5_db_alloc); 205 + 206 + void mlx5_db_free(struct mlx5_core_dev *dev, struct mlx5_db *db) 207 + { 208 + mutex_lock(&dev->priv.pgdir_mutex); 209 + 210 + __set_bit(db->index, db->u.pgdir->bitmap); 211 + 212 + if (bitmap_full(db->u.pgdir->bitmap, MLX5_DB_PER_PAGE)) { 213 + dma_free_coherent(&(dev->pdev->dev), PAGE_SIZE, 214 + db->u.pgdir->db_page, db->u.pgdir->db_dma); 215 + list_del(&db->u.pgdir->list); 216 + kfree(db->u.pgdir); 217 + } 218 + 219 + mutex_unlock(&dev->priv.pgdir_mutex); 220 + } 221 + EXPORT_SYMBOL_GPL(mlx5_db_free); 222 + 223 + 224 + void mlx5_fill_page_array(struct mlx5_buf *buf, __be64 *pas) 225 + { 226 + u64 addr; 227 + int i; 228 + 229 + for (i = 0; i < buf->npages; i++) { 230 + if (buf->nbufs == 1) 231 + addr = buf->direct.map + (i << buf->page_shift); 232 + else 233 + addr = buf->page_list[i].map; 234 + 235 + pas[i] = cpu_to_be64(addr); 236 + } 237 + } 238 + EXPORT_SYMBOL_GPL(mlx5_fill_page_array);
+1515
drivers/net/ethernet/mellanox/mlx5/core/cmd.c
··· 1 + /* 2 + * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved. 3 + * 4 + * This software is available to you under a choice of one of two 5 + * licenses. You may choose to be licensed under the terms of the GNU 6 + * General Public License (GPL) Version 2, available from the file 7 + * COPYING in the main directory of this source tree, or the 8 + * OpenIB.org BSD license below: 9 + * 10 + * Redistribution and use in source and binary forms, with or 11 + * without modification, are permitted provided that the following 12 + * conditions are met: 13 + * 14 + * - Redistributions of source code must retain the above 15 + * copyright notice, this list of conditions and the following 16 + * disclaimer. 17 + * 18 + * - Redistributions in binary form must reproduce the above 19 + * copyright notice, this list of conditions and the following 20 + * disclaimer in the documentation and/or other materials 21 + * 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 OF 25 + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26 + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 27 + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 28 + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29 + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30 + * SOFTWARE. 31 + */ 32 + 33 + #include <asm-generic/kmap_types.h> 34 + #include <linux/module.h> 35 + #include <linux/init.h> 36 + #include <linux/errno.h> 37 + #include <linux/pci.h> 38 + #include <linux/dma-mapping.h> 39 + #include <linux/slab.h> 40 + #include <linux/delay.h> 41 + #include <linux/random.h> 42 + #include <linux/io-mapping.h> 43 + #include <linux/mlx5/driver.h> 44 + #include <linux/debugfs.h> 45 + 46 + #include "mlx5_core.h" 47 + 48 + enum { 49 + CMD_IF_REV = 3, 50 + }; 51 + 52 + enum { 53 + CMD_MODE_POLLING, 54 + CMD_MODE_EVENTS 55 + }; 56 + 57 + enum { 58 + NUM_LONG_LISTS = 2, 59 + NUM_MED_LISTS = 64, 60 + LONG_LIST_SIZE = (2ULL * 1024 * 1024 * 1024 / PAGE_SIZE) * 8 + 16 + 61 + MLX5_CMD_DATA_BLOCK_SIZE, 62 + MED_LIST_SIZE = 16 + MLX5_CMD_DATA_BLOCK_SIZE, 63 + }; 64 + 65 + enum { 66 + MLX5_CMD_DELIVERY_STAT_OK = 0x0, 67 + MLX5_CMD_DELIVERY_STAT_SIGNAT_ERR = 0x1, 68 + MLX5_CMD_DELIVERY_STAT_TOK_ERR = 0x2, 69 + MLX5_CMD_DELIVERY_STAT_BAD_BLK_NUM_ERR = 0x3, 70 + MLX5_CMD_DELIVERY_STAT_OUT_PTR_ALIGN_ERR = 0x4, 71 + MLX5_CMD_DELIVERY_STAT_IN_PTR_ALIGN_ERR = 0x5, 72 + MLX5_CMD_DELIVERY_STAT_FW_ERR = 0x6, 73 + MLX5_CMD_DELIVERY_STAT_IN_LENGTH_ERR = 0x7, 74 + MLX5_CMD_DELIVERY_STAT_OUT_LENGTH_ERR = 0x8, 75 + MLX5_CMD_DELIVERY_STAT_RES_FLD_NOT_CLR_ERR = 0x9, 76 + MLX5_CMD_DELIVERY_STAT_CMD_DESCR_ERR = 0x10, 77 + }; 78 + 79 + enum { 80 + MLX5_CMD_STAT_OK = 0x0, 81 + MLX5_CMD_STAT_INT_ERR = 0x1, 82 + MLX5_CMD_STAT_BAD_OP_ERR = 0x2, 83 + MLX5_CMD_STAT_BAD_PARAM_ERR = 0x3, 84 + MLX5_CMD_STAT_BAD_SYS_STATE_ERR = 0x4, 85 + MLX5_CMD_STAT_BAD_RES_ERR = 0x5, 86 + MLX5_CMD_STAT_RES_BUSY = 0x6, 87 + MLX5_CMD_STAT_LIM_ERR = 0x8, 88 + MLX5_CMD_STAT_BAD_RES_STATE_ERR = 0x9, 89 + MLX5_CMD_STAT_IX_ERR = 0xa, 90 + MLX5_CMD_STAT_NO_RES_ERR = 0xf, 91 + MLX5_CMD_STAT_BAD_INP_LEN_ERR = 0x50, 92 + MLX5_CMD_STAT_BAD_OUTP_LEN_ERR = 0x51, 93 + MLX5_CMD_STAT_BAD_QP_STATE_ERR = 0x10, 94 + MLX5_CMD_STAT_BAD_PKT_ERR = 0x30, 95 + MLX5_CMD_STAT_BAD_SIZE_OUTS_CQES_ERR = 0x40, 96 + }; 97 + 98 + static struct mlx5_cmd_work_ent *alloc_cmd(struct mlx5_cmd *cmd, 99 + struct mlx5_cmd_msg *in, 100 + struct mlx5_cmd_msg *out, 101 + mlx5_cmd_cbk_t cbk, 102 + void *context, int page_queue) 103 + { 104 + gfp_t alloc_flags = cbk ? GFP_ATOMIC : GFP_KERNEL; 105 + struct mlx5_cmd_work_ent *ent; 106 + 107 + ent = kzalloc(sizeof(*ent), alloc_flags); 108 + if (!ent) 109 + return ERR_PTR(-ENOMEM); 110 + 111 + ent->in = in; 112 + ent->out = out; 113 + ent->callback = cbk; 114 + ent->context = context; 115 + ent->cmd = cmd; 116 + ent->page_queue = page_queue; 117 + 118 + return ent; 119 + } 120 + 121 + static u8 alloc_token(struct mlx5_cmd *cmd) 122 + { 123 + u8 token; 124 + 125 + spin_lock(&cmd->token_lock); 126 + token = cmd->token++ % 255 + 1; 127 + spin_unlock(&cmd->token_lock); 128 + 129 + return token; 130 + } 131 + 132 + static int alloc_ent(struct mlx5_cmd *cmd) 133 + { 134 + unsigned long flags; 135 + int ret; 136 + 137 + spin_lock_irqsave(&cmd->alloc_lock, flags); 138 + ret = find_first_bit(&cmd->bitmask, cmd->max_reg_cmds); 139 + if (ret < cmd->max_reg_cmds) 140 + clear_bit(ret, &cmd->bitmask); 141 + spin_unlock_irqrestore(&cmd->alloc_lock, flags); 142 + 143 + return ret < cmd->max_reg_cmds ? ret : -ENOMEM; 144 + } 145 + 146 + static void free_ent(struct mlx5_cmd *cmd, int idx) 147 + { 148 + unsigned long flags; 149 + 150 + spin_lock_irqsave(&cmd->alloc_lock, flags); 151 + set_bit(idx, &cmd->bitmask); 152 + spin_unlock_irqrestore(&cmd->alloc_lock, flags); 153 + } 154 + 155 + static struct mlx5_cmd_layout *get_inst(struct mlx5_cmd *cmd, int idx) 156 + { 157 + return cmd->cmd_buf + (idx << cmd->log_stride); 158 + } 159 + 160 + static u8 xor8_buf(void *buf, int len) 161 + { 162 + u8 *ptr = buf; 163 + u8 sum = 0; 164 + int i; 165 + 166 + for (i = 0; i < len; i++) 167 + sum ^= ptr[i]; 168 + 169 + return sum; 170 + } 171 + 172 + static int verify_block_sig(struct mlx5_cmd_prot_block *block) 173 + { 174 + if (xor8_buf(block->rsvd0, sizeof(*block) - sizeof(block->data) - 1) != 0xff) 175 + return -EINVAL; 176 + 177 + if (xor8_buf(block, sizeof(*block)) != 0xff) 178 + return -EINVAL; 179 + 180 + return 0; 181 + } 182 + 183 + static void calc_block_sig(struct mlx5_cmd_prot_block *block, u8 token) 184 + { 185 + block->token = token; 186 + block->ctrl_sig = ~xor8_buf(block->rsvd0, sizeof(*block) - sizeof(block->data) - 2); 187 + block->sig = ~xor8_buf(block, sizeof(*block) - 1); 188 + } 189 + 190 + static void calc_chain_sig(struct mlx5_cmd_msg *msg, u8 token) 191 + { 192 + struct mlx5_cmd_mailbox *next = msg->next; 193 + 194 + while (next) { 195 + calc_block_sig(next->buf, token); 196 + next = next->next; 197 + } 198 + } 199 + 200 + static void set_signature(struct mlx5_cmd_work_ent *ent) 201 + { 202 + ent->lay->sig = ~xor8_buf(ent->lay, sizeof(*ent->lay)); 203 + calc_chain_sig(ent->in, ent->token); 204 + calc_chain_sig(ent->out, ent->token); 205 + } 206 + 207 + static void poll_timeout(struct mlx5_cmd_work_ent *ent) 208 + { 209 + unsigned long poll_end = jiffies + msecs_to_jiffies(MLX5_CMD_TIMEOUT_MSEC + 1000); 210 + u8 own; 211 + 212 + do { 213 + own = ent->lay->status_own; 214 + if (!(own & CMD_OWNER_HW)) { 215 + ent->ret = 0; 216 + return; 217 + } 218 + usleep_range(5000, 10000); 219 + } while (time_before(jiffies, poll_end)); 220 + 221 + ent->ret = -ETIMEDOUT; 222 + } 223 + 224 + static void free_cmd(struct mlx5_cmd_work_ent *ent) 225 + { 226 + kfree(ent); 227 + } 228 + 229 + 230 + static int verify_signature(struct mlx5_cmd_work_ent *ent) 231 + { 232 + struct mlx5_cmd_mailbox *next = ent->out->next; 233 + int err; 234 + u8 sig; 235 + 236 + sig = xor8_buf(ent->lay, sizeof(*ent->lay)); 237 + if (sig != 0xff) 238 + return -EINVAL; 239 + 240 + while (next) { 241 + err = verify_block_sig(next->buf); 242 + if (err) 243 + return err; 244 + 245 + next = next->next; 246 + } 247 + 248 + return 0; 249 + } 250 + 251 + static void dump_buf(void *buf, int size, int data_only, int offset) 252 + { 253 + __be32 *p = buf; 254 + int i; 255 + 256 + for (i = 0; i < size; i += 16) { 257 + pr_debug("%03x: %08x %08x %08x %08x\n", offset, be32_to_cpu(p[0]), 258 + be32_to_cpu(p[1]), be32_to_cpu(p[2]), 259 + be32_to_cpu(p[3])); 260 + p += 4; 261 + offset += 16; 262 + } 263 + if (!data_only) 264 + pr_debug("\n"); 265 + } 266 + 267 + const char *mlx5_command_str(int command) 268 + { 269 + switch (command) { 270 + case MLX5_CMD_OP_QUERY_HCA_CAP: 271 + return "QUERY_HCA_CAP"; 272 + 273 + case MLX5_CMD_OP_SET_HCA_CAP: 274 + return "SET_HCA_CAP"; 275 + 276 + case MLX5_CMD_OP_QUERY_ADAPTER: 277 + return "QUERY_ADAPTER"; 278 + 279 + case MLX5_CMD_OP_INIT_HCA: 280 + return "INIT_HCA"; 281 + 282 + case MLX5_CMD_OP_TEARDOWN_HCA: 283 + return "TEARDOWN_HCA"; 284 + 285 + case MLX5_CMD_OP_QUERY_PAGES: 286 + return "QUERY_PAGES"; 287 + 288 + case MLX5_CMD_OP_MANAGE_PAGES: 289 + return "MANAGE_PAGES"; 290 + 291 + case MLX5_CMD_OP_CREATE_MKEY: 292 + return "CREATE_MKEY"; 293 + 294 + case MLX5_CMD_OP_QUERY_MKEY: 295 + return "QUERY_MKEY"; 296 + 297 + case MLX5_CMD_OP_DESTROY_MKEY: 298 + return "DESTROY_MKEY"; 299 + 300 + case MLX5_CMD_OP_QUERY_SPECIAL_CONTEXTS: 301 + return "QUERY_SPECIAL_CONTEXTS"; 302 + 303 + case MLX5_CMD_OP_CREATE_EQ: 304 + return "CREATE_EQ"; 305 + 306 + case MLX5_CMD_OP_DESTROY_EQ: 307 + return "DESTROY_EQ"; 308 + 309 + case MLX5_CMD_OP_QUERY_EQ: 310 + return "QUERY_EQ"; 311 + 312 + case MLX5_CMD_OP_CREATE_CQ: 313 + return "CREATE_CQ"; 314 + 315 + case MLX5_CMD_OP_DESTROY_CQ: 316 + return "DESTROY_CQ"; 317 + 318 + case MLX5_CMD_OP_QUERY_CQ: 319 + return "QUERY_CQ"; 320 + 321 + case MLX5_CMD_OP_MODIFY_CQ: 322 + return "MODIFY_CQ"; 323 + 324 + case MLX5_CMD_OP_CREATE_QP: 325 + return "CREATE_QP"; 326 + 327 + case MLX5_CMD_OP_DESTROY_QP: 328 + return "DESTROY_QP"; 329 + 330 + case MLX5_CMD_OP_RST2INIT_QP: 331 + return "RST2INIT_QP"; 332 + 333 + case MLX5_CMD_OP_INIT2RTR_QP: 334 + return "INIT2RTR_QP"; 335 + 336 + case MLX5_CMD_OP_RTR2RTS_QP: 337 + return "RTR2RTS_QP"; 338 + 339 + case MLX5_CMD_OP_RTS2RTS_QP: 340 + return "RTS2RTS_QP"; 341 + 342 + case MLX5_CMD_OP_SQERR2RTS_QP: 343 + return "SQERR2RTS_QP"; 344 + 345 + case MLX5_CMD_OP_2ERR_QP: 346 + return "2ERR_QP"; 347 + 348 + case MLX5_CMD_OP_RTS2SQD_QP: 349 + return "RTS2SQD_QP"; 350 + 351 + case MLX5_CMD_OP_SQD2RTS_QP: 352 + return "SQD2RTS_QP"; 353 + 354 + case MLX5_CMD_OP_2RST_QP: 355 + return "2RST_QP"; 356 + 357 + case MLX5_CMD_OP_QUERY_QP: 358 + return "QUERY_QP"; 359 + 360 + case MLX5_CMD_OP_CONF_SQP: 361 + return "CONF_SQP"; 362 + 363 + case MLX5_CMD_OP_MAD_IFC: 364 + return "MAD_IFC"; 365 + 366 + case MLX5_CMD_OP_INIT2INIT_QP: 367 + return "INIT2INIT_QP"; 368 + 369 + case MLX5_CMD_OP_SUSPEND_QP: 370 + return "SUSPEND_QP"; 371 + 372 + case MLX5_CMD_OP_UNSUSPEND_QP: 373 + return "UNSUSPEND_QP"; 374 + 375 + case MLX5_CMD_OP_SQD2SQD_QP: 376 + return "SQD2SQD_QP"; 377 + 378 + case MLX5_CMD_OP_ALLOC_QP_COUNTER_SET: 379 + return "ALLOC_QP_COUNTER_SET"; 380 + 381 + case MLX5_CMD_OP_DEALLOC_QP_COUNTER_SET: 382 + return "DEALLOC_QP_COUNTER_SET"; 383 + 384 + case MLX5_CMD_OP_QUERY_QP_COUNTER_SET: 385 + return "QUERY_QP_COUNTER_SET"; 386 + 387 + case MLX5_CMD_OP_CREATE_PSV: 388 + return "CREATE_PSV"; 389 + 390 + case MLX5_CMD_OP_DESTROY_PSV: 391 + return "DESTROY_PSV"; 392 + 393 + case MLX5_CMD_OP_QUERY_PSV: 394 + return "QUERY_PSV"; 395 + 396 + case MLX5_CMD_OP_QUERY_SIG_RULE_TABLE: 397 + return "QUERY_SIG_RULE_TABLE"; 398 + 399 + case MLX5_CMD_OP_QUERY_BLOCK_SIZE_TABLE: 400 + return "QUERY_BLOCK_SIZE_TABLE"; 401 + 402 + case MLX5_CMD_OP_CREATE_SRQ: 403 + return "CREATE_SRQ"; 404 + 405 + case MLX5_CMD_OP_DESTROY_SRQ: 406 + return "DESTROY_SRQ"; 407 + 408 + case MLX5_CMD_OP_QUERY_SRQ: 409 + return "QUERY_SRQ"; 410 + 411 + case MLX5_CMD_OP_ARM_RQ: 412 + return "ARM_RQ"; 413 + 414 + case MLX5_CMD_OP_RESIZE_SRQ: 415 + return "RESIZE_SRQ"; 416 + 417 + case MLX5_CMD_OP_ALLOC_PD: 418 + return "ALLOC_PD"; 419 + 420 + case MLX5_CMD_OP_DEALLOC_PD: 421 + return "DEALLOC_PD"; 422 + 423 + case MLX5_CMD_OP_ALLOC_UAR: 424 + return "ALLOC_UAR"; 425 + 426 + case MLX5_CMD_OP_DEALLOC_UAR: 427 + return "DEALLOC_UAR"; 428 + 429 + case MLX5_CMD_OP_ATTACH_TO_MCG: 430 + return "ATTACH_TO_MCG"; 431 + 432 + case MLX5_CMD_OP_DETACH_FROM_MCG: 433 + return "DETACH_FROM_MCG"; 434 + 435 + case MLX5_CMD_OP_ALLOC_XRCD: 436 + return "ALLOC_XRCD"; 437 + 438 + case MLX5_CMD_OP_DEALLOC_XRCD: 439 + return "DEALLOC_XRCD"; 440 + 441 + case MLX5_CMD_OP_ACCESS_REG: 442 + return "MLX5_CMD_OP_ACCESS_REG"; 443 + 444 + default: return "unknown command opcode"; 445 + } 446 + } 447 + 448 + static void dump_command(struct mlx5_core_dev *dev, 449 + struct mlx5_cmd_work_ent *ent, int input) 450 + { 451 + u16 op = be16_to_cpu(((struct mlx5_inbox_hdr *)(ent->lay->in))->opcode); 452 + struct mlx5_cmd_msg *msg = input ? ent->in : ent->out; 453 + struct mlx5_cmd_mailbox *next = msg->next; 454 + int data_only; 455 + int offset = 0; 456 + int dump_len; 457 + 458 + data_only = !!(mlx5_core_debug_mask & (1 << MLX5_CMD_DATA)); 459 + 460 + if (data_only) 461 + mlx5_core_dbg_mask(dev, 1 << MLX5_CMD_DATA, 462 + "dump command data %s(0x%x) %s\n", 463 + mlx5_command_str(op), op, 464 + input ? "INPUT" : "OUTPUT"); 465 + else 466 + mlx5_core_dbg(dev, "dump command %s(0x%x) %s\n", 467 + mlx5_command_str(op), op, 468 + input ? "INPUT" : "OUTPUT"); 469 + 470 + if (data_only) { 471 + if (input) { 472 + dump_buf(ent->lay->in, sizeof(ent->lay->in), 1, offset); 473 + offset += sizeof(ent->lay->in); 474 + } else { 475 + dump_buf(ent->lay->out, sizeof(ent->lay->out), 1, offset); 476 + offset += sizeof(ent->lay->out); 477 + } 478 + } else { 479 + dump_buf(ent->lay, sizeof(*ent->lay), 0, offset); 480 + offset += sizeof(*ent->lay); 481 + } 482 + 483 + while (next && offset < msg->len) { 484 + if (data_only) { 485 + dump_len = min_t(int, MLX5_CMD_DATA_BLOCK_SIZE, msg->len - offset); 486 + dump_buf(next->buf, dump_len, 1, offset); 487 + offset += MLX5_CMD_DATA_BLOCK_SIZE; 488 + } else { 489 + mlx5_core_dbg(dev, "command block:\n"); 490 + dump_buf(next->buf, sizeof(struct mlx5_cmd_prot_block), 0, offset); 491 + offset += sizeof(struct mlx5_cmd_prot_block); 492 + } 493 + next = next->next; 494 + } 495 + 496 + if (data_only) 497 + pr_debug("\n"); 498 + } 499 + 500 + static void cmd_work_handler(struct work_struct *work) 501 + { 502 + struct mlx5_cmd_work_ent *ent = container_of(work, struct mlx5_cmd_work_ent, work); 503 + struct mlx5_cmd *cmd = ent->cmd; 504 + struct mlx5_core_dev *dev = container_of(cmd, struct mlx5_core_dev, cmd); 505 + struct mlx5_cmd_layout *lay; 506 + struct semaphore *sem; 507 + 508 + sem = ent->page_queue ? &cmd->pages_sem : &cmd->sem; 509 + down(sem); 510 + if (!ent->page_queue) { 511 + ent->idx = alloc_ent(cmd); 512 + if (ent->idx < 0) { 513 + mlx5_core_err(dev, "failed to allocate command entry\n"); 514 + up(sem); 515 + return; 516 + } 517 + } else { 518 + ent->idx = cmd->max_reg_cmds; 519 + } 520 + 521 + ent->token = alloc_token(cmd); 522 + cmd->ent_arr[ent->idx] = ent; 523 + lay = get_inst(cmd, ent->idx); 524 + ent->lay = lay; 525 + memset(lay, 0, sizeof(*lay)); 526 + memcpy(lay->in, ent->in->first.data, sizeof(lay->in)); 527 + if (ent->in->next) 528 + lay->in_ptr = cpu_to_be64(ent->in->next->dma); 529 + lay->inlen = cpu_to_be32(ent->in->len); 530 + if (ent->out->next) 531 + lay->out_ptr = cpu_to_be64(ent->out->next->dma); 532 + lay->outlen = cpu_to_be32(ent->out->len); 533 + lay->type = MLX5_PCI_CMD_XPORT; 534 + lay->token = ent->token; 535 + lay->status_own = CMD_OWNER_HW; 536 + if (!cmd->checksum_disabled) 537 + set_signature(ent); 538 + dump_command(dev, ent, 1); 539 + ktime_get_ts(&ent->ts1); 540 + 541 + /* ring doorbell after the descriptor is valid */ 542 + wmb(); 543 + iowrite32be(1 << ent->idx, &dev->iseg->cmd_dbell); 544 + mlx5_core_dbg(dev, "write 0x%x to command doorbell\n", 1 << ent->idx); 545 + mmiowb(); 546 + if (cmd->mode == CMD_MODE_POLLING) { 547 + poll_timeout(ent); 548 + /* make sure we read the descriptor after ownership is SW */ 549 + rmb(); 550 + mlx5_cmd_comp_handler(dev, 1UL << ent->idx); 551 + } 552 + } 553 + 554 + static const char *deliv_status_to_str(u8 status) 555 + { 556 + switch (status) { 557 + case MLX5_CMD_DELIVERY_STAT_OK: 558 + return "no errors"; 559 + case MLX5_CMD_DELIVERY_STAT_SIGNAT_ERR: 560 + return "signature error"; 561 + case MLX5_CMD_DELIVERY_STAT_TOK_ERR: 562 + return "token error"; 563 + case MLX5_CMD_DELIVERY_STAT_BAD_BLK_NUM_ERR: 564 + return "bad block number"; 565 + case MLX5_CMD_DELIVERY_STAT_OUT_PTR_ALIGN_ERR: 566 + return "output pointer not aligned to block size"; 567 + case MLX5_CMD_DELIVERY_STAT_IN_PTR_ALIGN_ERR: 568 + return "input pointer not aligned to block size"; 569 + case MLX5_CMD_DELIVERY_STAT_FW_ERR: 570 + return "firmware internal error"; 571 + case MLX5_CMD_DELIVERY_STAT_IN_LENGTH_ERR: 572 + return "command input length error"; 573 + case MLX5_CMD_DELIVERY_STAT_OUT_LENGTH_ERR: 574 + return "command ouput length error"; 575 + case MLX5_CMD_DELIVERY_STAT_RES_FLD_NOT_CLR_ERR: 576 + return "reserved fields not cleared"; 577 + case MLX5_CMD_DELIVERY_STAT_CMD_DESCR_ERR: 578 + return "bad command descriptor type"; 579 + default: 580 + return "unknown status code"; 581 + } 582 + } 583 + 584 + static u16 msg_to_opcode(struct mlx5_cmd_msg *in) 585 + { 586 + struct mlx5_inbox_hdr *hdr = (struct mlx5_inbox_hdr *)(in->first.data); 587 + 588 + return be16_to_cpu(hdr->opcode); 589 + } 590 + 591 + static int wait_func(struct mlx5_core_dev *dev, struct mlx5_cmd_work_ent *ent) 592 + { 593 + unsigned long timeout = msecs_to_jiffies(MLX5_CMD_TIMEOUT_MSEC); 594 + struct mlx5_cmd *cmd = &dev->cmd; 595 + int err; 596 + 597 + if (cmd->mode == CMD_MODE_POLLING) { 598 + wait_for_completion(&ent->done); 599 + err = ent->ret; 600 + } else { 601 + if (!wait_for_completion_timeout(&ent->done, timeout)) 602 + err = -ETIMEDOUT; 603 + else 604 + err = 0; 605 + } 606 + if (err == -ETIMEDOUT) { 607 + mlx5_core_warn(dev, "%s(0x%x) timeout. Will cause a leak of a command resource\n", 608 + mlx5_command_str(msg_to_opcode(ent->in)), 609 + msg_to_opcode(ent->in)); 610 + } 611 + mlx5_core_dbg(dev, "err %d, delivery status %s(%d)\n", err, 612 + deliv_status_to_str(ent->status), ent->status); 613 + 614 + return err; 615 + } 616 + 617 + /* Notes: 618 + * 1. Callback functions may not sleep 619 + * 2. page queue commands do not support asynchrous completion 620 + */ 621 + static int mlx5_cmd_invoke(struct mlx5_core_dev *dev, struct mlx5_cmd_msg *in, 622 + struct mlx5_cmd_msg *out, mlx5_cmd_cbk_t callback, 623 + void *context, int page_queue, u8 *status) 624 + { 625 + struct mlx5_cmd *cmd = &dev->cmd; 626 + struct mlx5_cmd_work_ent *ent; 627 + ktime_t t1, t2, delta; 628 + struct mlx5_cmd_stats *stats; 629 + int err = 0; 630 + s64 ds; 631 + u16 op; 632 + 633 + if (callback && page_queue) 634 + return -EINVAL; 635 + 636 + ent = alloc_cmd(cmd, in, out, callback, context, page_queue); 637 + if (IS_ERR(ent)) 638 + return PTR_ERR(ent); 639 + 640 + if (!callback) 641 + init_completion(&ent->done); 642 + 643 + INIT_WORK(&ent->work, cmd_work_handler); 644 + if (page_queue) { 645 + cmd_work_handler(&ent->work); 646 + } else if (!queue_work(cmd->wq, &ent->work)) { 647 + mlx5_core_warn(dev, "failed to queue work\n"); 648 + err = -ENOMEM; 649 + goto out_free; 650 + } 651 + 652 + if (!callback) { 653 + err = wait_func(dev, ent); 654 + if (err == -ETIMEDOUT) 655 + goto out; 656 + 657 + t1 = timespec_to_ktime(ent->ts1); 658 + t2 = timespec_to_ktime(ent->ts2); 659 + delta = ktime_sub(t2, t1); 660 + ds = ktime_to_ns(delta); 661 + op = be16_to_cpu(((struct mlx5_inbox_hdr *)in->first.data)->opcode); 662 + if (op < ARRAY_SIZE(cmd->stats)) { 663 + stats = &cmd->stats[op]; 664 + spin_lock(&stats->lock); 665 + stats->sum += ds; 666 + ++stats->n; 667 + spin_unlock(&stats->lock); 668 + } 669 + mlx5_core_dbg_mask(dev, 1 << MLX5_CMD_TIME, 670 + "fw exec time for %s is %lld nsec\n", 671 + mlx5_command_str(op), ds); 672 + *status = ent->status; 673 + free_cmd(ent); 674 + } 675 + 676 + return err; 677 + 678 + out_free: 679 + free_cmd(ent); 680 + out: 681 + return err; 682 + } 683 + 684 + static ssize_t dbg_write(struct file *filp, const char __user *buf, 685 + size_t count, loff_t *pos) 686 + { 687 + struct mlx5_core_dev *dev = filp->private_data; 688 + struct mlx5_cmd_debug *dbg = &dev->cmd.dbg; 689 + char lbuf[3]; 690 + int err; 691 + 692 + if (!dbg->in_msg || !dbg->out_msg) 693 + return -ENOMEM; 694 + 695 + if (copy_from_user(lbuf, buf, sizeof(lbuf))) 696 + return -EPERM; 697 + 698 + lbuf[sizeof(lbuf) - 1] = 0; 699 + 700 + if (strcmp(lbuf, "go")) 701 + return -EINVAL; 702 + 703 + err = mlx5_cmd_exec(dev, dbg->in_msg, dbg->inlen, dbg->out_msg, dbg->outlen); 704 + 705 + return err ? err : count; 706 + } 707 + 708 + 709 + static const struct file_operations fops = { 710 + .owner = THIS_MODULE, 711 + .open = simple_open, 712 + .write = dbg_write, 713 + }; 714 + 715 + static int mlx5_copy_to_msg(struct mlx5_cmd_msg *to, void *from, int size) 716 + { 717 + struct mlx5_cmd_prot_block *block; 718 + struct mlx5_cmd_mailbox *next; 719 + int copy; 720 + 721 + if (!to || !from) 722 + return -ENOMEM; 723 + 724 + copy = min_t(int, size, sizeof(to->first.data)); 725 + memcpy(to->first.data, from, copy); 726 + size -= copy; 727 + from += copy; 728 + 729 + next = to->next; 730 + while (size) { 731 + if (!next) { 732 + /* this is a BUG */ 733 + return -ENOMEM; 734 + } 735 + 736 + copy = min_t(int, size, MLX5_CMD_DATA_BLOCK_SIZE); 737 + block = next->buf; 738 + memcpy(block->data, from, copy); 739 + from += copy; 740 + size -= copy; 741 + next = next->next; 742 + } 743 + 744 + return 0; 745 + } 746 + 747 + static int mlx5_copy_from_msg(void *to, struct mlx5_cmd_msg *from, int size) 748 + { 749 + struct mlx5_cmd_prot_block *block; 750 + struct mlx5_cmd_mailbox *next; 751 + int copy; 752 + 753 + if (!to || !from) 754 + return -ENOMEM; 755 + 756 + copy = min_t(int, size, sizeof(from->first.data)); 757 + memcpy(to, from->first.data, copy); 758 + size -= copy; 759 + to += copy; 760 + 761 + next = from->next; 762 + while (size) { 763 + if (!next) { 764 + /* this is a BUG */ 765 + return -ENOMEM; 766 + } 767 + 768 + copy = min_t(int, size, MLX5_CMD_DATA_BLOCK_SIZE); 769 + block = next->buf; 770 + if (xor8_buf(block, sizeof(*block)) != 0xff) 771 + return -EINVAL; 772 + 773 + memcpy(to, block->data, copy); 774 + to += copy; 775 + size -= copy; 776 + next = next->next; 777 + } 778 + 779 + return 0; 780 + } 781 + 782 + static struct mlx5_cmd_mailbox *alloc_cmd_box(struct mlx5_core_dev *dev, 783 + gfp_t flags) 784 + { 785 + struct mlx5_cmd_mailbox *mailbox; 786 + 787 + mailbox = kmalloc(sizeof(*mailbox), flags); 788 + if (!mailbox) 789 + return ERR_PTR(-ENOMEM); 790 + 791 + mailbox->buf = pci_pool_alloc(dev->cmd.pool, flags, 792 + &mailbox->dma); 793 + if (!mailbox->buf) { 794 + mlx5_core_dbg(dev, "failed allocation\n"); 795 + kfree(mailbox); 796 + return ERR_PTR(-ENOMEM); 797 + } 798 + memset(mailbox->buf, 0, sizeof(struct mlx5_cmd_prot_block)); 799 + mailbox->next = NULL; 800 + 801 + return mailbox; 802 + } 803 + 804 + static void free_cmd_box(struct mlx5_core_dev *dev, 805 + struct mlx5_cmd_mailbox *mailbox) 806 + { 807 + pci_pool_free(dev->cmd.pool, mailbox->buf, mailbox->dma); 808 + kfree(mailbox); 809 + } 810 + 811 + static struct mlx5_cmd_msg *mlx5_alloc_cmd_msg(struct mlx5_core_dev *dev, 812 + gfp_t flags, int size) 813 + { 814 + struct mlx5_cmd_mailbox *tmp, *head = NULL; 815 + struct mlx5_cmd_prot_block *block; 816 + struct mlx5_cmd_msg *msg; 817 + int blen; 818 + int err; 819 + int n; 820 + int i; 821 + 822 + msg = kzalloc(sizeof(*msg), GFP_KERNEL); 823 + if (!msg) 824 + return ERR_PTR(-ENOMEM); 825 + 826 + blen = size - min_t(int, sizeof(msg->first.data), size); 827 + n = (blen + MLX5_CMD_DATA_BLOCK_SIZE - 1) / MLX5_CMD_DATA_BLOCK_SIZE; 828 + 829 + for (i = 0; i < n; i++) { 830 + tmp = alloc_cmd_box(dev, flags); 831 + if (IS_ERR(tmp)) { 832 + mlx5_core_warn(dev, "failed allocating block\n"); 833 + err = PTR_ERR(tmp); 834 + goto err_alloc; 835 + } 836 + 837 + block = tmp->buf; 838 + tmp->next = head; 839 + block->next = cpu_to_be64(tmp->next ? tmp->next->dma : 0); 840 + block->block_num = cpu_to_be32(n - i - 1); 841 + head = tmp; 842 + } 843 + msg->next = head; 844 + msg->len = size; 845 + return msg; 846 + 847 + err_alloc: 848 + while (head) { 849 + tmp = head->next; 850 + free_cmd_box(dev, head); 851 + head = tmp; 852 + } 853 + kfree(msg); 854 + 855 + return ERR_PTR(err); 856 + } 857 + 858 + static void mlx5_free_cmd_msg(struct mlx5_core_dev *dev, 859 + struct mlx5_cmd_msg *msg) 860 + { 861 + struct mlx5_cmd_mailbox *head = msg->next; 862 + struct mlx5_cmd_mailbox *next; 863 + 864 + while (head) { 865 + next = head->next; 866 + free_cmd_box(dev, head); 867 + head = next; 868 + } 869 + kfree(msg); 870 + } 871 + 872 + static ssize_t data_write(struct file *filp, const char __user *buf, 873 + size_t count, loff_t *pos) 874 + { 875 + struct mlx5_core_dev *dev = filp->private_data; 876 + struct mlx5_cmd_debug *dbg = &dev->cmd.dbg; 877 + void *ptr; 878 + int err; 879 + 880 + if (*pos != 0) 881 + return -EINVAL; 882 + 883 + kfree(dbg->in_msg); 884 + dbg->in_msg = NULL; 885 + dbg->inlen = 0; 886 + 887 + ptr = kzalloc(count, GFP_KERNEL); 888 + if (!ptr) 889 + return -ENOMEM; 890 + 891 + if (copy_from_user(ptr, buf, count)) { 892 + err = -EPERM; 893 + goto out; 894 + } 895 + dbg->in_msg = ptr; 896 + dbg->inlen = count; 897 + 898 + *pos = count; 899 + 900 + return count; 901 + 902 + out: 903 + kfree(ptr); 904 + return err; 905 + } 906 + 907 + static ssize_t data_read(struct file *filp, char __user *buf, size_t count, 908 + loff_t *pos) 909 + { 910 + struct mlx5_core_dev *dev = filp->private_data; 911 + struct mlx5_cmd_debug *dbg = &dev->cmd.dbg; 912 + int copy; 913 + 914 + if (*pos) 915 + return 0; 916 + 917 + if (!dbg->out_msg) 918 + return -ENOMEM; 919 + 920 + copy = min_t(int, count, dbg->outlen); 921 + if (copy_to_user(buf, dbg->out_msg, copy)) 922 + return -EPERM; 923 + 924 + *pos += copy; 925 + 926 + return copy; 927 + } 928 + 929 + static const struct file_operations dfops = { 930 + .owner = THIS_MODULE, 931 + .open = simple_open, 932 + .write = data_write, 933 + .read = data_read, 934 + }; 935 + 936 + static ssize_t outlen_read(struct file *filp, char __user *buf, size_t count, 937 + loff_t *pos) 938 + { 939 + struct mlx5_core_dev *dev = filp->private_data; 940 + struct mlx5_cmd_debug *dbg = &dev->cmd.dbg; 941 + char outlen[8]; 942 + int err; 943 + 944 + if (*pos) 945 + return 0; 946 + 947 + err = snprintf(outlen, sizeof(outlen), "%d", dbg->outlen); 948 + if (err < 0) 949 + return err; 950 + 951 + if (copy_to_user(buf, &outlen, err)) 952 + return -EPERM; 953 + 954 + *pos += err; 955 + 956 + return err; 957 + } 958 + 959 + static ssize_t outlen_write(struct file *filp, const char __user *buf, 960 + size_t count, loff_t *pos) 961 + { 962 + struct mlx5_core_dev *dev = filp->private_data; 963 + struct mlx5_cmd_debug *dbg = &dev->cmd.dbg; 964 + char outlen_str[8]; 965 + int outlen; 966 + void *ptr; 967 + int err; 968 + 969 + if (*pos != 0 || count > 6) 970 + return -EINVAL; 971 + 972 + kfree(dbg->out_msg); 973 + dbg->out_msg = NULL; 974 + dbg->outlen = 0; 975 + 976 + if (copy_from_user(outlen_str, buf, count)) 977 + return -EPERM; 978 + 979 + outlen_str[7] = 0; 980 + 981 + err = sscanf(outlen_str, "%d", &outlen); 982 + if (err < 0) 983 + return err; 984 + 985 + ptr = kzalloc(outlen, GFP_KERNEL); 986 + if (!ptr) 987 + return -ENOMEM; 988 + 989 + dbg->out_msg = ptr; 990 + dbg->outlen = outlen; 991 + 992 + *pos = count; 993 + 994 + return count; 995 + } 996 + 997 + static const struct file_operations olfops = { 998 + .owner = THIS_MODULE, 999 + .open = simple_open, 1000 + .write = outlen_write, 1001 + .read = outlen_read, 1002 + }; 1003 + 1004 + static void set_wqname(struct mlx5_core_dev *dev) 1005 + { 1006 + struct mlx5_cmd *cmd = &dev->cmd; 1007 + 1008 + snprintf(cmd->wq_name, sizeof(cmd->wq_name), "mlx5_cmd_%s", 1009 + dev_name(&dev->pdev->dev)); 1010 + } 1011 + 1012 + static void clean_debug_files(struct mlx5_core_dev *dev) 1013 + { 1014 + struct mlx5_cmd_debug *dbg = &dev->cmd.dbg; 1015 + 1016 + if (!mlx5_debugfs_root) 1017 + return; 1018 + 1019 + mlx5_cmdif_debugfs_cleanup(dev); 1020 + debugfs_remove_recursive(dbg->dbg_root); 1021 + } 1022 + 1023 + static int create_debugfs_files(struct mlx5_core_dev *dev) 1024 + { 1025 + struct mlx5_cmd_debug *dbg = &dev->cmd.dbg; 1026 + int err = -ENOMEM; 1027 + 1028 + if (!mlx5_debugfs_root) 1029 + return 0; 1030 + 1031 + dbg->dbg_root = debugfs_create_dir("cmd", dev->priv.dbg_root); 1032 + if (!dbg->dbg_root) 1033 + return err; 1034 + 1035 + dbg->dbg_in = debugfs_create_file("in", 0400, dbg->dbg_root, 1036 + dev, &dfops); 1037 + if (!dbg->dbg_in) 1038 + goto err_dbg; 1039 + 1040 + dbg->dbg_out = debugfs_create_file("out", 0200, dbg->dbg_root, 1041 + dev, &dfops); 1042 + if (!dbg->dbg_out) 1043 + goto err_dbg; 1044 + 1045 + dbg->dbg_outlen = debugfs_create_file("out_len", 0600, dbg->dbg_root, 1046 + dev, &olfops); 1047 + if (!dbg->dbg_outlen) 1048 + goto err_dbg; 1049 + 1050 + dbg->dbg_status = debugfs_create_u8("status", 0600, dbg->dbg_root, 1051 + &dbg->status); 1052 + if (!dbg->dbg_status) 1053 + goto err_dbg; 1054 + 1055 + dbg->dbg_run = debugfs_create_file("run", 0200, dbg->dbg_root, dev, &fops); 1056 + if (!dbg->dbg_run) 1057 + goto err_dbg; 1058 + 1059 + mlx5_cmdif_debugfs_init(dev); 1060 + 1061 + return 0; 1062 + 1063 + err_dbg: 1064 + clean_debug_files(dev); 1065 + return err; 1066 + } 1067 + 1068 + void mlx5_cmd_use_events(struct mlx5_core_dev *dev) 1069 + { 1070 + struct mlx5_cmd *cmd = &dev->cmd; 1071 + int i; 1072 + 1073 + for (i = 0; i < cmd->max_reg_cmds; i++) 1074 + down(&cmd->sem); 1075 + 1076 + down(&cmd->pages_sem); 1077 + 1078 + flush_workqueue(cmd->wq); 1079 + 1080 + cmd->mode = CMD_MODE_EVENTS; 1081 + 1082 + up(&cmd->pages_sem); 1083 + for (i = 0; i < cmd->max_reg_cmds; i++) 1084 + up(&cmd->sem); 1085 + } 1086 + 1087 + void mlx5_cmd_use_polling(struct mlx5_core_dev *dev) 1088 + { 1089 + struct mlx5_cmd *cmd = &dev->cmd; 1090 + int i; 1091 + 1092 + for (i = 0; i < cmd->max_reg_cmds; i++) 1093 + down(&cmd->sem); 1094 + 1095 + down(&cmd->pages_sem); 1096 + 1097 + flush_workqueue(cmd->wq); 1098 + cmd->mode = CMD_MODE_POLLING; 1099 + 1100 + up(&cmd->pages_sem); 1101 + for (i = 0; i < cmd->max_reg_cmds; i++) 1102 + up(&cmd->sem); 1103 + } 1104 + 1105 + void mlx5_cmd_comp_handler(struct mlx5_core_dev *dev, unsigned long vector) 1106 + { 1107 + struct mlx5_cmd *cmd = &dev->cmd; 1108 + struct mlx5_cmd_work_ent *ent; 1109 + mlx5_cmd_cbk_t callback; 1110 + void *context; 1111 + int err; 1112 + int i; 1113 + 1114 + for (i = 0; i < (1 << cmd->log_sz); i++) { 1115 + if (test_bit(i, &vector)) { 1116 + ent = cmd->ent_arr[i]; 1117 + ktime_get_ts(&ent->ts2); 1118 + memcpy(ent->out->first.data, ent->lay->out, sizeof(ent->lay->out)); 1119 + dump_command(dev, ent, 0); 1120 + if (!ent->ret) { 1121 + if (!cmd->checksum_disabled) 1122 + ent->ret = verify_signature(ent); 1123 + else 1124 + ent->ret = 0; 1125 + ent->status = ent->lay->status_own >> 1; 1126 + mlx5_core_dbg(dev, "command completed. ret 0x%x, delivery status %s(0x%x)\n", 1127 + ent->ret, deliv_status_to_str(ent->status), ent->status); 1128 + } 1129 + free_ent(cmd, ent->idx); 1130 + if (ent->callback) { 1131 + callback = ent->callback; 1132 + context = ent->context; 1133 + err = ent->ret; 1134 + free_cmd(ent); 1135 + callback(err, context); 1136 + } else { 1137 + complete(&ent->done); 1138 + } 1139 + if (ent->page_queue) 1140 + up(&cmd->pages_sem); 1141 + else 1142 + up(&cmd->sem); 1143 + } 1144 + } 1145 + } 1146 + EXPORT_SYMBOL(mlx5_cmd_comp_handler); 1147 + 1148 + static int status_to_err(u8 status) 1149 + { 1150 + return status ? -1 : 0; /* TBD more meaningful codes */ 1151 + } 1152 + 1153 + static struct mlx5_cmd_msg *alloc_msg(struct mlx5_core_dev *dev, int in_size) 1154 + { 1155 + struct mlx5_cmd_msg *msg = ERR_PTR(-ENOMEM); 1156 + struct mlx5_cmd *cmd = &dev->cmd; 1157 + struct cache_ent *ent = NULL; 1158 + 1159 + if (in_size > MED_LIST_SIZE && in_size <= LONG_LIST_SIZE) 1160 + ent = &cmd->cache.large; 1161 + else if (in_size > 16 && in_size <= MED_LIST_SIZE) 1162 + ent = &cmd->cache.med; 1163 + 1164 + if (ent) { 1165 + spin_lock(&ent->lock); 1166 + if (!list_empty(&ent->head)) { 1167 + msg = list_entry(ent->head.next, typeof(*msg), list); 1168 + /* For cached lists, we must explicitly state what is 1169 + * the real size 1170 + */ 1171 + msg->len = in_size; 1172 + list_del(&msg->list); 1173 + } 1174 + spin_unlock(&ent->lock); 1175 + } 1176 + 1177 + if (IS_ERR(msg)) 1178 + msg = mlx5_alloc_cmd_msg(dev, GFP_KERNEL, in_size); 1179 + 1180 + return msg; 1181 + } 1182 + 1183 + static void free_msg(struct mlx5_core_dev *dev, struct mlx5_cmd_msg *msg) 1184 + { 1185 + if (msg->cache) { 1186 + spin_lock(&msg->cache->lock); 1187 + list_add_tail(&msg->list, &msg->cache->head); 1188 + spin_unlock(&msg->cache->lock); 1189 + } else { 1190 + mlx5_free_cmd_msg(dev, msg); 1191 + } 1192 + } 1193 + 1194 + static int is_manage_pages(struct mlx5_inbox_hdr *in) 1195 + { 1196 + return be16_to_cpu(in->opcode) == MLX5_CMD_OP_MANAGE_PAGES; 1197 + } 1198 + 1199 + int mlx5_cmd_exec(struct mlx5_core_dev *dev, void *in, int in_size, void *out, 1200 + int out_size) 1201 + { 1202 + struct mlx5_cmd_msg *inb; 1203 + struct mlx5_cmd_msg *outb; 1204 + int pages_queue; 1205 + int err; 1206 + u8 status = 0; 1207 + 1208 + pages_queue = is_manage_pages(in); 1209 + 1210 + inb = alloc_msg(dev, in_size); 1211 + if (IS_ERR(inb)) { 1212 + err = PTR_ERR(inb); 1213 + return err; 1214 + } 1215 + 1216 + err = mlx5_copy_to_msg(inb, in, in_size); 1217 + if (err) { 1218 + mlx5_core_warn(dev, "err %d\n", err); 1219 + goto out_in; 1220 + } 1221 + 1222 + outb = mlx5_alloc_cmd_msg(dev, GFP_KERNEL, out_size); 1223 + if (IS_ERR(outb)) { 1224 + err = PTR_ERR(outb); 1225 + goto out_in; 1226 + } 1227 + 1228 + err = mlx5_cmd_invoke(dev, inb, outb, NULL, NULL, pages_queue, &status); 1229 + if (err) 1230 + goto out_out; 1231 + 1232 + mlx5_core_dbg(dev, "err %d, status %d\n", err, status); 1233 + if (status) { 1234 + err = status_to_err(status); 1235 + goto out_out; 1236 + } 1237 + 1238 + err = mlx5_copy_from_msg(out, outb, out_size); 1239 + 1240 + out_out: 1241 + mlx5_free_cmd_msg(dev, outb); 1242 + 1243 + out_in: 1244 + free_msg(dev, inb); 1245 + return err; 1246 + } 1247 + EXPORT_SYMBOL(mlx5_cmd_exec); 1248 + 1249 + static void destroy_msg_cache(struct mlx5_core_dev *dev) 1250 + { 1251 + struct mlx5_cmd *cmd = &dev->cmd; 1252 + struct mlx5_cmd_msg *msg; 1253 + struct mlx5_cmd_msg *n; 1254 + 1255 + list_for_each_entry_safe(msg, n, &cmd->cache.large.head, list) { 1256 + list_del(&msg->list); 1257 + mlx5_free_cmd_msg(dev, msg); 1258 + } 1259 + 1260 + list_for_each_entry_safe(msg, n, &cmd->cache.med.head, list) { 1261 + list_del(&msg->list); 1262 + mlx5_free_cmd_msg(dev, msg); 1263 + } 1264 + } 1265 + 1266 + static int create_msg_cache(struct mlx5_core_dev *dev) 1267 + { 1268 + struct mlx5_cmd *cmd = &dev->cmd; 1269 + struct mlx5_cmd_msg *msg; 1270 + int err; 1271 + int i; 1272 + 1273 + spin_lock_init(&cmd->cache.large.lock); 1274 + INIT_LIST_HEAD(&cmd->cache.large.head); 1275 + spin_lock_init(&cmd->cache.med.lock); 1276 + INIT_LIST_HEAD(&cmd->cache.med.head); 1277 + 1278 + for (i = 0; i < NUM_LONG_LISTS; i++) { 1279 + msg = mlx5_alloc_cmd_msg(dev, GFP_KERNEL, LONG_LIST_SIZE); 1280 + if (IS_ERR(msg)) { 1281 + err = PTR_ERR(msg); 1282 + goto ex_err; 1283 + } 1284 + msg->cache = &cmd->cache.large; 1285 + list_add_tail(&msg->list, &cmd->cache.large.head); 1286 + } 1287 + 1288 + for (i = 0; i < NUM_MED_LISTS; i++) { 1289 + msg = mlx5_alloc_cmd_msg(dev, GFP_KERNEL, MED_LIST_SIZE); 1290 + if (IS_ERR(msg)) { 1291 + err = PTR_ERR(msg); 1292 + goto ex_err; 1293 + } 1294 + msg->cache = &cmd->cache.med; 1295 + list_add_tail(&msg->list, &cmd->cache.med.head); 1296 + } 1297 + 1298 + return 0; 1299 + 1300 + ex_err: 1301 + destroy_msg_cache(dev); 1302 + return err; 1303 + } 1304 + 1305 + int mlx5_cmd_init(struct mlx5_core_dev *dev) 1306 + { 1307 + int size = sizeof(struct mlx5_cmd_prot_block); 1308 + int align = roundup_pow_of_two(size); 1309 + struct mlx5_cmd *cmd = &dev->cmd; 1310 + u32 cmd_h, cmd_l; 1311 + u16 cmd_if_rev; 1312 + int err; 1313 + int i; 1314 + 1315 + cmd_if_rev = cmdif_rev(dev); 1316 + if (cmd_if_rev != CMD_IF_REV) { 1317 + dev_err(&dev->pdev->dev, 1318 + "Driver cmdif rev(%d) differs from firmware's(%d)\n", 1319 + CMD_IF_REV, cmd_if_rev); 1320 + return -EINVAL; 1321 + } 1322 + 1323 + cmd->pool = pci_pool_create("mlx5_cmd", dev->pdev, size, align, 0); 1324 + if (!cmd->pool) 1325 + return -ENOMEM; 1326 + 1327 + cmd->cmd_buf = (void *)__get_free_pages(GFP_ATOMIC, 0); 1328 + if (!cmd->cmd_buf) { 1329 + err = -ENOMEM; 1330 + goto err_free_pool; 1331 + } 1332 + cmd->dma = dma_map_single(&dev->pdev->dev, cmd->cmd_buf, PAGE_SIZE, 1333 + DMA_BIDIRECTIONAL); 1334 + if (dma_mapping_error(&dev->pdev->dev, cmd->dma)) { 1335 + err = -ENOMEM; 1336 + goto err_free; 1337 + } 1338 + 1339 + cmd_l = ioread32be(&dev->iseg->cmdq_addr_l_sz) & 0xff; 1340 + cmd->log_sz = cmd_l >> 4 & 0xf; 1341 + cmd->log_stride = cmd_l & 0xf; 1342 + if (1 << cmd->log_sz > MLX5_MAX_COMMANDS) { 1343 + dev_err(&dev->pdev->dev, "firmware reports too many outstanding commands %d\n", 1344 + 1 << cmd->log_sz); 1345 + err = -EINVAL; 1346 + goto err_map; 1347 + } 1348 + 1349 + if (cmd->log_sz + cmd->log_stride > PAGE_SHIFT) { 1350 + dev_err(&dev->pdev->dev, "command queue size overflow\n"); 1351 + err = -EINVAL; 1352 + goto err_map; 1353 + } 1354 + 1355 + cmd->max_reg_cmds = (1 << cmd->log_sz) - 1; 1356 + cmd->bitmask = (1 << cmd->max_reg_cmds) - 1; 1357 + 1358 + cmd->cmdif_rev = ioread32be(&dev->iseg->cmdif_rev_fw_sub) >> 16; 1359 + if (cmd->cmdif_rev > CMD_IF_REV) { 1360 + dev_err(&dev->pdev->dev, "driver does not support command interface version. driver %d, firmware %d\n", 1361 + CMD_IF_REV, cmd->cmdif_rev); 1362 + err = -ENOTSUPP; 1363 + goto err_map; 1364 + } 1365 + 1366 + spin_lock_init(&cmd->alloc_lock); 1367 + spin_lock_init(&cmd->token_lock); 1368 + for (i = 0; i < ARRAY_SIZE(cmd->stats); i++) 1369 + spin_lock_init(&cmd->stats[i].lock); 1370 + 1371 + sema_init(&cmd->sem, cmd->max_reg_cmds); 1372 + sema_init(&cmd->pages_sem, 1); 1373 + 1374 + cmd_h = (u32)((u64)(cmd->dma) >> 32); 1375 + cmd_l = (u32)(cmd->dma); 1376 + if (cmd_l & 0xfff) { 1377 + dev_err(&dev->pdev->dev, "invalid command queue address\n"); 1378 + err = -ENOMEM; 1379 + goto err_map; 1380 + } 1381 + 1382 + iowrite32be(cmd_h, &dev->iseg->cmdq_addr_h); 1383 + iowrite32be(cmd_l, &dev->iseg->cmdq_addr_l_sz); 1384 + 1385 + /* Make sure firmware sees the complete address before we proceed */ 1386 + wmb(); 1387 + 1388 + mlx5_core_dbg(dev, "descriptor at dma 0x%llx\n", (unsigned long long)(cmd->dma)); 1389 + 1390 + cmd->mode = CMD_MODE_POLLING; 1391 + 1392 + err = create_msg_cache(dev); 1393 + if (err) { 1394 + dev_err(&dev->pdev->dev, "failed to create command cache\n"); 1395 + goto err_map; 1396 + } 1397 + 1398 + set_wqname(dev); 1399 + cmd->wq = create_singlethread_workqueue(cmd->wq_name); 1400 + if (!cmd->wq) { 1401 + dev_err(&dev->pdev->dev, "failed to create command workqueue\n"); 1402 + err = -ENOMEM; 1403 + goto err_cache; 1404 + } 1405 + 1406 + err = create_debugfs_files(dev); 1407 + if (err) { 1408 + err = -ENOMEM; 1409 + goto err_wq; 1410 + } 1411 + 1412 + return 0; 1413 + 1414 + err_wq: 1415 + destroy_workqueue(cmd->wq); 1416 + 1417 + err_cache: 1418 + destroy_msg_cache(dev); 1419 + 1420 + err_map: 1421 + dma_unmap_single(&dev->pdev->dev, cmd->dma, PAGE_SIZE, 1422 + DMA_BIDIRECTIONAL); 1423 + err_free: 1424 + free_pages((unsigned long)cmd->cmd_buf, 0); 1425 + 1426 + err_free_pool: 1427 + pci_pool_destroy(cmd->pool); 1428 + 1429 + return err; 1430 + } 1431 + EXPORT_SYMBOL(mlx5_cmd_init); 1432 + 1433 + void mlx5_cmd_cleanup(struct mlx5_core_dev *dev) 1434 + { 1435 + struct mlx5_cmd *cmd = &dev->cmd; 1436 + 1437 + clean_debug_files(dev); 1438 + destroy_workqueue(cmd->wq); 1439 + destroy_msg_cache(dev); 1440 + dma_unmap_single(&dev->pdev->dev, cmd->dma, PAGE_SIZE, 1441 + DMA_BIDIRECTIONAL); 1442 + free_pages((unsigned long)cmd->cmd_buf, 0); 1443 + pci_pool_destroy(cmd->pool); 1444 + } 1445 + EXPORT_SYMBOL(mlx5_cmd_cleanup); 1446 + 1447 + static const char *cmd_status_str(u8 status) 1448 + { 1449 + switch (status) { 1450 + case MLX5_CMD_STAT_OK: 1451 + return "OK"; 1452 + case MLX5_CMD_STAT_INT_ERR: 1453 + return "internal error"; 1454 + case MLX5_CMD_STAT_BAD_OP_ERR: 1455 + return "bad operation"; 1456 + case MLX5_CMD_STAT_BAD_PARAM_ERR: 1457 + return "bad parameter"; 1458 + case MLX5_CMD_STAT_BAD_SYS_STATE_ERR: 1459 + return "bad system state"; 1460 + case MLX5_CMD_STAT_BAD_RES_ERR: 1461 + return "bad resource"; 1462 + case MLX5_CMD_STAT_RES_BUSY: 1463 + return "resource busy"; 1464 + case MLX5_CMD_STAT_LIM_ERR: 1465 + return "limits exceeded"; 1466 + case MLX5_CMD_STAT_BAD_RES_STATE_ERR: 1467 + return "bad resource state"; 1468 + case MLX5_CMD_STAT_IX_ERR: 1469 + return "bad index"; 1470 + case MLX5_CMD_STAT_NO_RES_ERR: 1471 + return "no resources"; 1472 + case MLX5_CMD_STAT_BAD_INP_LEN_ERR: 1473 + return "bad input length"; 1474 + case MLX5_CMD_STAT_BAD_OUTP_LEN_ERR: 1475 + return "bad output length"; 1476 + case MLX5_CMD_STAT_BAD_QP_STATE_ERR: 1477 + return "bad QP state"; 1478 + case MLX5_CMD_STAT_BAD_PKT_ERR: 1479 + return "bad packet (discarded)"; 1480 + case MLX5_CMD_STAT_BAD_SIZE_OUTS_CQES_ERR: 1481 + return "bad size too many outstanding CQEs"; 1482 + default: 1483 + return "unknown status"; 1484 + } 1485 + } 1486 + 1487 + int mlx5_cmd_status_to_err(struct mlx5_outbox_hdr *hdr) 1488 + { 1489 + if (!hdr->status) 1490 + return 0; 1491 + 1492 + pr_warn("command failed, status %s(0x%x), syndrome 0x%x\n", 1493 + cmd_status_str(hdr->status), hdr->status, 1494 + be32_to_cpu(hdr->syndrome)); 1495 + 1496 + switch (hdr->status) { 1497 + case MLX5_CMD_STAT_OK: return 0; 1498 + case MLX5_CMD_STAT_INT_ERR: return -EIO; 1499 + case MLX5_CMD_STAT_BAD_OP_ERR: return -EINVAL; 1500 + case MLX5_CMD_STAT_BAD_PARAM_ERR: return -EINVAL; 1501 + case MLX5_CMD_STAT_BAD_SYS_STATE_ERR: return -EIO; 1502 + case MLX5_CMD_STAT_BAD_RES_ERR: return -EINVAL; 1503 + case MLX5_CMD_STAT_RES_BUSY: return -EBUSY; 1504 + case MLX5_CMD_STAT_LIM_ERR: return -EINVAL; 1505 + case MLX5_CMD_STAT_BAD_RES_STATE_ERR: return -EINVAL; 1506 + case MLX5_CMD_STAT_IX_ERR: return -EINVAL; 1507 + case MLX5_CMD_STAT_NO_RES_ERR: return -EAGAIN; 1508 + case MLX5_CMD_STAT_BAD_INP_LEN_ERR: return -EIO; 1509 + case MLX5_CMD_STAT_BAD_OUTP_LEN_ERR: return -EIO; 1510 + case MLX5_CMD_STAT_BAD_QP_STATE_ERR: return -EINVAL; 1511 + case MLX5_CMD_STAT_BAD_PKT_ERR: return -EINVAL; 1512 + case MLX5_CMD_STAT_BAD_SIZE_OUTS_CQES_ERR: return -EINVAL; 1513 + default: return -EIO; 1514 + } 1515 + }
+224
drivers/net/ethernet/mellanox/mlx5/core/cq.c
··· 1 + /* 2 + * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved. 3 + * 4 + * This software is available to you under a choice of one of two 5 + * licenses. You may choose to be licensed under the terms of the GNU 6 + * General Public License (GPL) Version 2, available from the file 7 + * COPYING in the main directory of this source tree, or the 8 + * OpenIB.org BSD license below: 9 + * 10 + * Redistribution and use in source and binary forms, with or 11 + * without modification, are permitted provided that the following 12 + * conditions are met: 13 + * 14 + * - Redistributions of source code must retain the above 15 + * copyright notice, this list of conditions and the following 16 + * disclaimer. 17 + * 18 + * - Redistributions in binary form must reproduce the above 19 + * copyright notice, this list of conditions and the following 20 + * disclaimer in the documentation and/or other materials 21 + * 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 OF 25 + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26 + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 27 + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 28 + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29 + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30 + * SOFTWARE. 31 + */ 32 + 33 + #include <linux/kernel.h> 34 + #include <linux/module.h> 35 + #include <linux/hardirq.h> 36 + #include <linux/mlx5/driver.h> 37 + #include <linux/mlx5/cmd.h> 38 + #include <rdma/ib_verbs.h> 39 + #include <linux/mlx5/cq.h> 40 + #include "mlx5_core.h" 41 + 42 + void mlx5_cq_completion(struct mlx5_core_dev *dev, u32 cqn) 43 + { 44 + struct mlx5_core_cq *cq; 45 + struct mlx5_cq_table *table = &dev->priv.cq_table; 46 + 47 + spin_lock(&table->lock); 48 + cq = radix_tree_lookup(&table->tree, cqn); 49 + if (likely(cq)) 50 + atomic_inc(&cq->refcount); 51 + spin_unlock(&table->lock); 52 + 53 + if (!cq) { 54 + mlx5_core_warn(dev, "Completion event for bogus CQ 0x%x\n", cqn); 55 + return; 56 + } 57 + 58 + ++cq->arm_sn; 59 + 60 + cq->comp(cq); 61 + 62 + if (atomic_dec_and_test(&cq->refcount)) 63 + complete(&cq->free); 64 + } 65 + 66 + void mlx5_cq_event(struct mlx5_core_dev *dev, u32 cqn, int event_type) 67 + { 68 + struct mlx5_cq_table *table = &dev->priv.cq_table; 69 + struct mlx5_core_cq *cq; 70 + 71 + spin_lock(&table->lock); 72 + 73 + cq = radix_tree_lookup(&table->tree, cqn); 74 + if (cq) 75 + atomic_inc(&cq->refcount); 76 + 77 + spin_unlock(&table->lock); 78 + 79 + if (!cq) { 80 + mlx5_core_warn(dev, "Async event for bogus CQ 0x%x\n", cqn); 81 + return; 82 + } 83 + 84 + cq->event(cq, event_type); 85 + 86 + if (atomic_dec_and_test(&cq->refcount)) 87 + complete(&cq->free); 88 + } 89 + 90 + 91 + int mlx5_core_create_cq(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq, 92 + struct mlx5_create_cq_mbox_in *in, int inlen) 93 + { 94 + int err; 95 + struct mlx5_cq_table *table = &dev->priv.cq_table; 96 + struct mlx5_create_cq_mbox_out out; 97 + struct mlx5_destroy_cq_mbox_in din; 98 + struct mlx5_destroy_cq_mbox_out dout; 99 + 100 + in->hdr.opcode = cpu_to_be16(MLX5_CMD_OP_CREATE_CQ); 101 + memset(&out, 0, sizeof(out)); 102 + err = mlx5_cmd_exec(dev, in, inlen, &out, sizeof(out)); 103 + if (err) 104 + return err; 105 + 106 + if (out.hdr.status) 107 + return mlx5_cmd_status_to_err(&out.hdr); 108 + 109 + cq->cqn = be32_to_cpu(out.cqn) & 0xffffff; 110 + cq->cons_index = 0; 111 + cq->arm_sn = 0; 112 + atomic_set(&cq->refcount, 1); 113 + init_completion(&cq->free); 114 + 115 + spin_lock_irq(&table->lock); 116 + err = radix_tree_insert(&table->tree, cq->cqn, cq); 117 + spin_unlock_irq(&table->lock); 118 + if (err) 119 + goto err_cmd; 120 + 121 + cq->pid = current->pid; 122 + err = mlx5_debug_cq_add(dev, cq); 123 + if (err) 124 + mlx5_core_dbg(dev, "failed adding CP 0x%x to debug file system\n", 125 + cq->cqn); 126 + 127 + return 0; 128 + 129 + err_cmd: 130 + memset(&din, 0, sizeof(din)); 131 + memset(&dout, 0, sizeof(dout)); 132 + din.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_DESTROY_CQ); 133 + mlx5_cmd_exec(dev, &din, sizeof(din), &dout, sizeof(dout)); 134 + return err; 135 + } 136 + EXPORT_SYMBOL(mlx5_core_create_cq); 137 + 138 + int mlx5_core_destroy_cq(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq) 139 + { 140 + struct mlx5_cq_table *table = &dev->priv.cq_table; 141 + struct mlx5_destroy_cq_mbox_in in; 142 + struct mlx5_destroy_cq_mbox_out out; 143 + struct mlx5_core_cq *tmp; 144 + int err; 145 + 146 + spin_lock_irq(&table->lock); 147 + tmp = radix_tree_delete(&table->tree, cq->cqn); 148 + spin_unlock_irq(&table->lock); 149 + if (!tmp) { 150 + mlx5_core_warn(dev, "cq 0x%x not found in tree\n", cq->cqn); 151 + return -EINVAL; 152 + } 153 + if (tmp != cq) { 154 + mlx5_core_warn(dev, "corruption on srqn 0x%x\n", cq->cqn); 155 + return -EINVAL; 156 + } 157 + 158 + memset(&in, 0, sizeof(in)); 159 + memset(&out, 0, sizeof(out)); 160 + in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_DESTROY_CQ); 161 + in.cqn = cpu_to_be32(cq->cqn); 162 + err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out)); 163 + if (err) 164 + return err; 165 + 166 + if (out.hdr.status) 167 + return mlx5_cmd_status_to_err(&out.hdr); 168 + 169 + synchronize_irq(cq->irqn); 170 + 171 + mlx5_debug_cq_remove(dev, cq); 172 + if (atomic_dec_and_test(&cq->refcount)) 173 + complete(&cq->free); 174 + wait_for_completion(&cq->free); 175 + 176 + return 0; 177 + } 178 + EXPORT_SYMBOL(mlx5_core_destroy_cq); 179 + 180 + int mlx5_core_query_cq(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq, 181 + struct mlx5_query_cq_mbox_out *out) 182 + { 183 + struct mlx5_query_cq_mbox_in in; 184 + int err; 185 + 186 + memset(&in, 0, sizeof(in)); 187 + memset(out, 0, sizeof(*out)); 188 + 189 + in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_QUERY_CQ); 190 + in.cqn = cpu_to_be32(cq->cqn); 191 + err = mlx5_cmd_exec(dev, &in, sizeof(in), out, sizeof(*out)); 192 + if (err) 193 + return err; 194 + 195 + if (out->hdr.status) 196 + return mlx5_cmd_status_to_err(&out->hdr); 197 + 198 + return err; 199 + } 200 + EXPORT_SYMBOL(mlx5_core_query_cq); 201 + 202 + 203 + int mlx5_core_modify_cq(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq, 204 + int type, struct mlx5_cq_modify_params *params) 205 + { 206 + return -ENOSYS; 207 + } 208 + 209 + int mlx5_init_cq_table(struct mlx5_core_dev *dev) 210 + { 211 + struct mlx5_cq_table *table = &dev->priv.cq_table; 212 + int err; 213 + 214 + spin_lock_init(&table->lock); 215 + INIT_RADIX_TREE(&table->tree, GFP_ATOMIC); 216 + err = mlx5_cq_debugfs_init(dev); 217 + 218 + return err; 219 + } 220 + 221 + void mlx5_cleanup_cq_table(struct mlx5_core_dev *dev) 222 + { 223 + mlx5_cq_debugfs_cleanup(dev); 224 + }
+587
drivers/net/ethernet/mellanox/mlx5/core/debugfs.c
··· 1 + /* 2 + * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved. 3 + * 4 + * This software is available to you under a choice of one of two 5 + * licenses. You may choose to be licensed under the terms of the GNU 6 + * General Public License (GPL) Version 2, available from the file 7 + * COPYING in the main directory of this source tree, or the 8 + * OpenIB.org BSD license below: 9 + * 10 + * Redistribution and use in source and binary forms, with or 11 + * without modification, are permitted provided that the following 12 + * conditions are met: 13 + * 14 + * - Redistributions of source code must retain the above 15 + * copyright notice, this list of conditions and the following 16 + * disclaimer. 17 + * 18 + * - Redistributions in binary form must reproduce the above 19 + * copyright notice, this list of conditions and the following 20 + * disclaimer in the documentation and/or other materials 21 + * 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 OF 25 + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26 + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 27 + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 28 + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29 + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30 + * SOFTWARE. 31 + */ 32 + 33 + #include <linux/module.h> 34 + #include <linux/debugfs.h> 35 + #include <linux/mlx5/qp.h> 36 + #include <linux/mlx5/cq.h> 37 + #include <linux/mlx5/driver.h> 38 + #include "mlx5_core.h" 39 + 40 + enum { 41 + QP_PID, 42 + QP_STATE, 43 + QP_XPORT, 44 + QP_MTU, 45 + QP_N_RECV, 46 + QP_RECV_SZ, 47 + QP_N_SEND, 48 + QP_LOG_PG_SZ, 49 + QP_RQPN, 50 + }; 51 + 52 + static char *qp_fields[] = { 53 + [QP_PID] = "pid", 54 + [QP_STATE] = "state", 55 + [QP_XPORT] = "transport", 56 + [QP_MTU] = "mtu", 57 + [QP_N_RECV] = "num_recv", 58 + [QP_RECV_SZ] = "rcv_wqe_sz", 59 + [QP_N_SEND] = "num_send", 60 + [QP_LOG_PG_SZ] = "log2_page_sz", 61 + [QP_RQPN] = "remote_qpn", 62 + }; 63 + 64 + enum { 65 + EQ_NUM_EQES, 66 + EQ_INTR, 67 + EQ_LOG_PG_SZ, 68 + }; 69 + 70 + static char *eq_fields[] = { 71 + [EQ_NUM_EQES] = "num_eqes", 72 + [EQ_INTR] = "intr", 73 + [EQ_LOG_PG_SZ] = "log_page_size", 74 + }; 75 + 76 + enum { 77 + CQ_PID, 78 + CQ_NUM_CQES, 79 + CQ_LOG_PG_SZ, 80 + }; 81 + 82 + static char *cq_fields[] = { 83 + [CQ_PID] = "pid", 84 + [CQ_NUM_CQES] = "num_cqes", 85 + [CQ_LOG_PG_SZ] = "log_page_size", 86 + }; 87 + 88 + struct dentry *mlx5_debugfs_root; 89 + EXPORT_SYMBOL(mlx5_debugfs_root); 90 + 91 + void mlx5_register_debugfs(void) 92 + { 93 + mlx5_debugfs_root = debugfs_create_dir("mlx5", NULL); 94 + if (IS_ERR_OR_NULL(mlx5_debugfs_root)) 95 + mlx5_debugfs_root = NULL; 96 + } 97 + 98 + void mlx5_unregister_debugfs(void) 99 + { 100 + debugfs_remove(mlx5_debugfs_root); 101 + } 102 + 103 + int mlx5_qp_debugfs_init(struct mlx5_core_dev *dev) 104 + { 105 + if (!mlx5_debugfs_root) 106 + return 0; 107 + 108 + atomic_set(&dev->num_qps, 0); 109 + 110 + dev->priv.qp_debugfs = debugfs_create_dir("QPs", dev->priv.dbg_root); 111 + if (!dev->priv.qp_debugfs) 112 + return -ENOMEM; 113 + 114 + return 0; 115 + } 116 + 117 + void mlx5_qp_debugfs_cleanup(struct mlx5_core_dev *dev) 118 + { 119 + if (!mlx5_debugfs_root) 120 + return; 121 + 122 + debugfs_remove_recursive(dev->priv.qp_debugfs); 123 + } 124 + 125 + int mlx5_eq_debugfs_init(struct mlx5_core_dev *dev) 126 + { 127 + if (!mlx5_debugfs_root) 128 + return 0; 129 + 130 + dev->priv.eq_debugfs = debugfs_create_dir("EQs", dev->priv.dbg_root); 131 + if (!dev->priv.eq_debugfs) 132 + return -ENOMEM; 133 + 134 + return 0; 135 + } 136 + 137 + void mlx5_eq_debugfs_cleanup(struct mlx5_core_dev *dev) 138 + { 139 + if (!mlx5_debugfs_root) 140 + return; 141 + 142 + debugfs_remove_recursive(dev->priv.eq_debugfs); 143 + } 144 + 145 + static ssize_t average_read(struct file *filp, char __user *buf, size_t count, 146 + loff_t *pos) 147 + { 148 + struct mlx5_cmd_stats *stats; 149 + u64 field = 0; 150 + int ret; 151 + int err; 152 + char tbuf[22]; 153 + 154 + if (*pos) 155 + return 0; 156 + 157 + stats = filp->private_data; 158 + spin_lock(&stats->lock); 159 + if (stats->n) 160 + field = stats->sum / stats->n; 161 + spin_unlock(&stats->lock); 162 + ret = snprintf(tbuf, sizeof(tbuf), "%llu\n", field); 163 + if (ret > 0) { 164 + err = copy_to_user(buf, tbuf, ret); 165 + if (err) 166 + return err; 167 + } 168 + 169 + *pos += ret; 170 + return ret; 171 + } 172 + 173 + 174 + static ssize_t average_write(struct file *filp, const char __user *buf, 175 + size_t count, loff_t *pos) 176 + { 177 + struct mlx5_cmd_stats *stats; 178 + 179 + stats = filp->private_data; 180 + spin_lock(&stats->lock); 181 + stats->sum = 0; 182 + stats->n = 0; 183 + spin_unlock(&stats->lock); 184 + 185 + *pos += count; 186 + 187 + return count; 188 + } 189 + 190 + static const struct file_operations stats_fops = { 191 + .owner = THIS_MODULE, 192 + .open = simple_open, 193 + .read = average_read, 194 + .write = average_write, 195 + }; 196 + 197 + int mlx5_cmdif_debugfs_init(struct mlx5_core_dev *dev) 198 + { 199 + struct mlx5_cmd_stats *stats; 200 + struct dentry **cmd; 201 + const char *namep; 202 + int err; 203 + int i; 204 + 205 + if (!mlx5_debugfs_root) 206 + return 0; 207 + 208 + cmd = &dev->priv.cmdif_debugfs; 209 + *cmd = debugfs_create_dir("commands", dev->priv.dbg_root); 210 + if (!*cmd) 211 + return -ENOMEM; 212 + 213 + for (i = 0; i < ARRAY_SIZE(dev->cmd.stats); i++) { 214 + stats = &dev->cmd.stats[i]; 215 + namep = mlx5_command_str(i); 216 + if (strcmp(namep, "unknown command opcode")) { 217 + stats->root = debugfs_create_dir(namep, *cmd); 218 + if (!stats->root) { 219 + mlx5_core_warn(dev, "failed adding command %d\n", 220 + i); 221 + err = -ENOMEM; 222 + goto out; 223 + } 224 + 225 + stats->avg = debugfs_create_file("average", 0400, 226 + stats->root, stats, 227 + &stats_fops); 228 + if (!stats->avg) { 229 + mlx5_core_warn(dev, "failed creating debugfs file\n"); 230 + err = -ENOMEM; 231 + goto out; 232 + } 233 + 234 + stats->count = debugfs_create_u64("n", 0400, 235 + stats->root, 236 + &stats->n); 237 + if (!stats->count) { 238 + mlx5_core_warn(dev, "failed creating debugfs file\n"); 239 + err = -ENOMEM; 240 + goto out; 241 + } 242 + } 243 + } 244 + 245 + return 0; 246 + out: 247 + debugfs_remove_recursive(dev->priv.cmdif_debugfs); 248 + return err; 249 + } 250 + 251 + void mlx5_cmdif_debugfs_cleanup(struct mlx5_core_dev *dev) 252 + { 253 + if (!mlx5_debugfs_root) 254 + return; 255 + 256 + debugfs_remove_recursive(dev->priv.cmdif_debugfs); 257 + } 258 + 259 + int mlx5_cq_debugfs_init(struct mlx5_core_dev *dev) 260 + { 261 + if (!mlx5_debugfs_root) 262 + return 0; 263 + 264 + dev->priv.cq_debugfs = debugfs_create_dir("CQs", dev->priv.dbg_root); 265 + if (!dev->priv.cq_debugfs) 266 + return -ENOMEM; 267 + 268 + return 0; 269 + } 270 + 271 + void mlx5_cq_debugfs_cleanup(struct mlx5_core_dev *dev) 272 + { 273 + if (!mlx5_debugfs_root) 274 + return; 275 + 276 + debugfs_remove_recursive(dev->priv.cq_debugfs); 277 + } 278 + 279 + static u64 qp_read_field(struct mlx5_core_dev *dev, struct mlx5_core_qp *qp, 280 + int index) 281 + { 282 + struct mlx5_query_qp_mbox_out *out; 283 + struct mlx5_qp_context *ctx; 284 + u64 param = 0; 285 + int err; 286 + int no_sq; 287 + 288 + out = kzalloc(sizeof(*out), GFP_KERNEL); 289 + if (!out) 290 + return param; 291 + 292 + err = mlx5_core_qp_query(dev, qp, out, sizeof(*out)); 293 + if (err) { 294 + mlx5_core_warn(dev, "failed to query qp\n"); 295 + goto out; 296 + } 297 + 298 + ctx = &out->ctx; 299 + switch (index) { 300 + case QP_PID: 301 + param = qp->pid; 302 + break; 303 + case QP_STATE: 304 + param = be32_to_cpu(ctx->flags) >> 28; 305 + break; 306 + case QP_XPORT: 307 + param = (be32_to_cpu(ctx->flags) >> 16) & 0xff; 308 + break; 309 + case QP_MTU: 310 + param = ctx->mtu_msgmax >> 5; 311 + break; 312 + case QP_N_RECV: 313 + param = 1 << ((ctx->rq_size_stride >> 3) & 0xf); 314 + break; 315 + case QP_RECV_SZ: 316 + param = 1 << ((ctx->rq_size_stride & 7) + 4); 317 + break; 318 + case QP_N_SEND: 319 + no_sq = be16_to_cpu(ctx->sq_crq_size) >> 15; 320 + if (!no_sq) 321 + param = 1 << (be16_to_cpu(ctx->sq_crq_size) >> 11); 322 + else 323 + param = 0; 324 + break; 325 + case QP_LOG_PG_SZ: 326 + param = ((cpu_to_be32(ctx->log_pg_sz_remote_qpn) >> 24) & 0x1f); 327 + param += 12; 328 + break; 329 + case QP_RQPN: 330 + param = cpu_to_be32(ctx->log_pg_sz_remote_qpn) & 0xffffff; 331 + break; 332 + } 333 + 334 + out: 335 + kfree(out); 336 + return param; 337 + } 338 + 339 + static u64 eq_read_field(struct mlx5_core_dev *dev, struct mlx5_eq *eq, 340 + int index) 341 + { 342 + struct mlx5_query_eq_mbox_out *out; 343 + struct mlx5_eq_context *ctx; 344 + u64 param = 0; 345 + int err; 346 + 347 + out = kzalloc(sizeof(*out), GFP_KERNEL); 348 + if (!out) 349 + return param; 350 + 351 + ctx = &out->ctx; 352 + 353 + err = mlx5_core_eq_query(dev, eq, out, sizeof(*out)); 354 + if (err) { 355 + mlx5_core_warn(dev, "failed to query eq\n"); 356 + goto out; 357 + } 358 + 359 + switch (index) { 360 + case EQ_NUM_EQES: 361 + param = 1 << ((be32_to_cpu(ctx->log_sz_usr_page) >> 24) & 0x1f); 362 + break; 363 + case EQ_INTR: 364 + param = ctx->intr; 365 + break; 366 + case EQ_LOG_PG_SZ: 367 + param = (ctx->log_page_size & 0x1f) + 12; 368 + break; 369 + } 370 + 371 + out: 372 + kfree(out); 373 + return param; 374 + } 375 + 376 + static u64 cq_read_field(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq, 377 + int index) 378 + { 379 + struct mlx5_query_cq_mbox_out *out; 380 + struct mlx5_cq_context *ctx; 381 + u64 param = 0; 382 + int err; 383 + 384 + out = kzalloc(sizeof(*out), GFP_KERNEL); 385 + if (!out) 386 + return param; 387 + 388 + ctx = &out->ctx; 389 + 390 + err = mlx5_core_query_cq(dev, cq, out); 391 + if (err) { 392 + mlx5_core_warn(dev, "failed to query cq\n"); 393 + goto out; 394 + } 395 + 396 + switch (index) { 397 + case CQ_PID: 398 + param = cq->pid; 399 + break; 400 + case CQ_NUM_CQES: 401 + param = 1 << ((be32_to_cpu(ctx->log_sz_usr_page) >> 24) & 0x1f); 402 + break; 403 + case CQ_LOG_PG_SZ: 404 + param = (ctx->log_pg_sz & 0x1f) + 12; 405 + break; 406 + } 407 + 408 + out: 409 + kfree(out); 410 + return param; 411 + } 412 + 413 + static ssize_t dbg_read(struct file *filp, char __user *buf, size_t count, 414 + loff_t *pos) 415 + { 416 + struct mlx5_field_desc *desc; 417 + struct mlx5_rsc_debug *d; 418 + char tbuf[18]; 419 + u64 field; 420 + int ret; 421 + int err; 422 + 423 + if (*pos) 424 + return 0; 425 + 426 + desc = filp->private_data; 427 + d = (void *)(desc - desc->i) - sizeof(*d); 428 + switch (d->type) { 429 + case MLX5_DBG_RSC_QP: 430 + field = qp_read_field(d->dev, d->object, desc->i); 431 + break; 432 + 433 + case MLX5_DBG_RSC_EQ: 434 + field = eq_read_field(d->dev, d->object, desc->i); 435 + break; 436 + 437 + case MLX5_DBG_RSC_CQ: 438 + field = cq_read_field(d->dev, d->object, desc->i); 439 + break; 440 + 441 + default: 442 + mlx5_core_warn(d->dev, "invalid resource type %d\n", d->type); 443 + return -EINVAL; 444 + } 445 + 446 + ret = snprintf(tbuf, sizeof(tbuf), "0x%llx\n", field); 447 + if (ret > 0) { 448 + err = copy_to_user(buf, tbuf, ret); 449 + if (err) 450 + return err; 451 + } 452 + 453 + *pos += ret; 454 + return ret; 455 + } 456 + 457 + static const struct file_operations fops = { 458 + .owner = THIS_MODULE, 459 + .open = simple_open, 460 + .read = dbg_read, 461 + }; 462 + 463 + static int add_res_tree(struct mlx5_core_dev *dev, enum dbg_rsc_type type, 464 + struct dentry *root, struct mlx5_rsc_debug **dbg, 465 + int rsn, char **field, int nfile, void *data) 466 + { 467 + struct mlx5_rsc_debug *d; 468 + char resn[32]; 469 + int err; 470 + int i; 471 + 472 + d = kzalloc(sizeof(*d) + nfile * sizeof(d->fields[0]), GFP_KERNEL); 473 + if (!d) 474 + return -ENOMEM; 475 + 476 + d->dev = dev; 477 + d->object = data; 478 + d->type = type; 479 + sprintf(resn, "0x%x", rsn); 480 + d->root = debugfs_create_dir(resn, root); 481 + if (!d->root) { 482 + err = -ENOMEM; 483 + goto out_free; 484 + } 485 + 486 + for (i = 0; i < nfile; i++) { 487 + d->fields[i].i = i; 488 + d->fields[i].dent = debugfs_create_file(field[i], 0400, 489 + d->root, &d->fields[i], 490 + &fops); 491 + if (!d->fields[i].dent) { 492 + err = -ENOMEM; 493 + goto out_rem; 494 + } 495 + } 496 + *dbg = d; 497 + 498 + return 0; 499 + out_rem: 500 + debugfs_remove_recursive(d->root); 501 + 502 + out_free: 503 + kfree(d); 504 + return err; 505 + } 506 + 507 + static void rem_res_tree(struct mlx5_rsc_debug *d) 508 + { 509 + debugfs_remove_recursive(d->root); 510 + kfree(d); 511 + } 512 + 513 + int mlx5_debug_qp_add(struct mlx5_core_dev *dev, struct mlx5_core_qp *qp) 514 + { 515 + int err; 516 + 517 + if (!mlx5_debugfs_root) 518 + return 0; 519 + 520 + err = add_res_tree(dev, MLX5_DBG_RSC_QP, dev->priv.qp_debugfs, 521 + &qp->dbg, qp->qpn, qp_fields, 522 + ARRAY_SIZE(qp_fields), qp); 523 + if (err) 524 + qp->dbg = NULL; 525 + 526 + return err; 527 + } 528 + 529 + void mlx5_debug_qp_remove(struct mlx5_core_dev *dev, struct mlx5_core_qp *qp) 530 + { 531 + if (!mlx5_debugfs_root) 532 + return; 533 + 534 + if (qp->dbg) 535 + rem_res_tree(qp->dbg); 536 + } 537 + 538 + 539 + int mlx5_debug_eq_add(struct mlx5_core_dev *dev, struct mlx5_eq *eq) 540 + { 541 + int err; 542 + 543 + if (!mlx5_debugfs_root) 544 + return 0; 545 + 546 + err = add_res_tree(dev, MLX5_DBG_RSC_EQ, dev->priv.eq_debugfs, 547 + &eq->dbg, eq->eqn, eq_fields, 548 + ARRAY_SIZE(eq_fields), eq); 549 + if (err) 550 + eq->dbg = NULL; 551 + 552 + return err; 553 + } 554 + 555 + void mlx5_debug_eq_remove(struct mlx5_core_dev *dev, struct mlx5_eq *eq) 556 + { 557 + if (!mlx5_debugfs_root) 558 + return; 559 + 560 + if (eq->dbg) 561 + rem_res_tree(eq->dbg); 562 + } 563 + 564 + int mlx5_debug_cq_add(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq) 565 + { 566 + int err; 567 + 568 + if (!mlx5_debugfs_root) 569 + return 0; 570 + 571 + err = add_res_tree(dev, MLX5_DBG_RSC_CQ, dev->priv.cq_debugfs, 572 + &cq->dbg, cq->cqn, cq_fields, 573 + ARRAY_SIZE(cq_fields), cq); 574 + if (err) 575 + cq->dbg = NULL; 576 + 577 + return err; 578 + } 579 + 580 + void mlx5_debug_cq_remove(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq) 581 + { 582 + if (!mlx5_debugfs_root) 583 + return; 584 + 585 + if (cq->dbg) 586 + rem_res_tree(cq->dbg); 587 + }
+521
drivers/net/ethernet/mellanox/mlx5/core/eq.c
··· 1 + /* 2 + * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved. 3 + * 4 + * This software is available to you under a choice of one of two 5 + * licenses. You may choose to be licensed under the terms of the GNU 6 + * General Public License (GPL) Version 2, available from the file 7 + * COPYING in the main directory of this source tree, or the 8 + * OpenIB.org BSD license below: 9 + * 10 + * Redistribution and use in source and binary forms, with or 11 + * without modification, are permitted provided that the following 12 + * conditions are met: 13 + * 14 + * - Redistributions of source code must retain the above 15 + * copyright notice, this list of conditions and the following 16 + * disclaimer. 17 + * 18 + * - Redistributions in binary form must reproduce the above 19 + * copyright notice, this list of conditions and the following 20 + * disclaimer in the documentation and/or other materials 21 + * 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 OF 25 + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26 + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 27 + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 28 + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29 + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30 + * SOFTWARE. 31 + */ 32 + 33 + #include <linux/interrupt.h> 34 + #include <linux/module.h> 35 + #include <linux/mlx5/driver.h> 36 + #include <linux/mlx5/cmd.h> 37 + #include "mlx5_core.h" 38 + 39 + enum { 40 + MLX5_EQE_SIZE = sizeof(struct mlx5_eqe), 41 + MLX5_EQE_OWNER_INIT_VAL = 0x1, 42 + }; 43 + 44 + enum { 45 + MLX5_EQ_STATE_ARMED = 0x9, 46 + MLX5_EQ_STATE_FIRED = 0xa, 47 + MLX5_EQ_STATE_ALWAYS_ARMED = 0xb, 48 + }; 49 + 50 + enum { 51 + MLX5_NUM_SPARE_EQE = 0x80, 52 + MLX5_NUM_ASYNC_EQE = 0x100, 53 + MLX5_NUM_CMD_EQE = 32, 54 + }; 55 + 56 + enum { 57 + MLX5_EQ_DOORBEL_OFFSET = 0x40, 58 + }; 59 + 60 + #define MLX5_ASYNC_EVENT_MASK ((1ull << MLX5_EVENT_TYPE_PATH_MIG) | \ 61 + (1ull << MLX5_EVENT_TYPE_COMM_EST) | \ 62 + (1ull << MLX5_EVENT_TYPE_SQ_DRAINED) | \ 63 + (1ull << MLX5_EVENT_TYPE_CQ_ERROR) | \ 64 + (1ull << MLX5_EVENT_TYPE_WQ_CATAS_ERROR) | \ 65 + (1ull << MLX5_EVENT_TYPE_PATH_MIG_FAILED) | \ 66 + (1ull << MLX5_EVENT_TYPE_WQ_INVAL_REQ_ERROR) | \ 67 + (1ull << MLX5_EVENT_TYPE_WQ_ACCESS_ERROR) | \ 68 + (1ull << MLX5_EVENT_TYPE_PORT_CHANGE) | \ 69 + (1ull << MLX5_EVENT_TYPE_SRQ_CATAS_ERROR) | \ 70 + (1ull << MLX5_EVENT_TYPE_SRQ_LAST_WQE) | \ 71 + (1ull << MLX5_EVENT_TYPE_SRQ_RQ_LIMIT)) 72 + 73 + struct map_eq_in { 74 + u64 mask; 75 + u32 reserved; 76 + u32 unmap_eqn; 77 + }; 78 + 79 + struct cre_des_eq { 80 + u8 reserved[15]; 81 + u8 eqn; 82 + }; 83 + 84 + static int mlx5_cmd_destroy_eq(struct mlx5_core_dev *dev, u8 eqn) 85 + { 86 + struct mlx5_destroy_eq_mbox_in in; 87 + struct mlx5_destroy_eq_mbox_out out; 88 + int err; 89 + 90 + memset(&in, 0, sizeof(in)); 91 + memset(&out, 0, sizeof(out)); 92 + in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_DESTROY_EQ); 93 + in.eqn = eqn; 94 + err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out)); 95 + if (!err) 96 + goto ex; 97 + 98 + if (out.hdr.status) 99 + err = mlx5_cmd_status_to_err(&out.hdr); 100 + 101 + ex: 102 + return err; 103 + } 104 + 105 + static struct mlx5_eqe *get_eqe(struct mlx5_eq *eq, u32 entry) 106 + { 107 + return mlx5_buf_offset(&eq->buf, entry * MLX5_EQE_SIZE); 108 + } 109 + 110 + static struct mlx5_eqe *next_eqe_sw(struct mlx5_eq *eq) 111 + { 112 + struct mlx5_eqe *eqe = get_eqe(eq, eq->cons_index & (eq->nent - 1)); 113 + 114 + return ((eqe->owner & 1) ^ !!(eq->cons_index & eq->nent)) ? NULL : eqe; 115 + } 116 + 117 + static const char *eqe_type_str(u8 type) 118 + { 119 + switch (type) { 120 + case MLX5_EVENT_TYPE_COMP: 121 + return "MLX5_EVENT_TYPE_COMP"; 122 + case MLX5_EVENT_TYPE_PATH_MIG: 123 + return "MLX5_EVENT_TYPE_PATH_MIG"; 124 + case MLX5_EVENT_TYPE_COMM_EST: 125 + return "MLX5_EVENT_TYPE_COMM_EST"; 126 + case MLX5_EVENT_TYPE_SQ_DRAINED: 127 + return "MLX5_EVENT_TYPE_SQ_DRAINED"; 128 + case MLX5_EVENT_TYPE_SRQ_LAST_WQE: 129 + return "MLX5_EVENT_TYPE_SRQ_LAST_WQE"; 130 + case MLX5_EVENT_TYPE_SRQ_RQ_LIMIT: 131 + return "MLX5_EVENT_TYPE_SRQ_RQ_LIMIT"; 132 + case MLX5_EVENT_TYPE_CQ_ERROR: 133 + return "MLX5_EVENT_TYPE_CQ_ERROR"; 134 + case MLX5_EVENT_TYPE_WQ_CATAS_ERROR: 135 + return "MLX5_EVENT_TYPE_WQ_CATAS_ERROR"; 136 + case MLX5_EVENT_TYPE_PATH_MIG_FAILED: 137 + return "MLX5_EVENT_TYPE_PATH_MIG_FAILED"; 138 + case MLX5_EVENT_TYPE_WQ_INVAL_REQ_ERROR: 139 + return "MLX5_EVENT_TYPE_WQ_INVAL_REQ_ERROR"; 140 + case MLX5_EVENT_TYPE_WQ_ACCESS_ERROR: 141 + return "MLX5_EVENT_TYPE_WQ_ACCESS_ERROR"; 142 + case MLX5_EVENT_TYPE_SRQ_CATAS_ERROR: 143 + return "MLX5_EVENT_TYPE_SRQ_CATAS_ERROR"; 144 + case MLX5_EVENT_TYPE_INTERNAL_ERROR: 145 + return "MLX5_EVENT_TYPE_INTERNAL_ERROR"; 146 + case MLX5_EVENT_TYPE_PORT_CHANGE: 147 + return "MLX5_EVENT_TYPE_PORT_CHANGE"; 148 + case MLX5_EVENT_TYPE_GPIO_EVENT: 149 + return "MLX5_EVENT_TYPE_GPIO_EVENT"; 150 + case MLX5_EVENT_TYPE_REMOTE_CONFIG: 151 + return "MLX5_EVENT_TYPE_REMOTE_CONFIG"; 152 + case MLX5_EVENT_TYPE_DB_BF_CONGESTION: 153 + return "MLX5_EVENT_TYPE_DB_BF_CONGESTION"; 154 + case MLX5_EVENT_TYPE_STALL_EVENT: 155 + return "MLX5_EVENT_TYPE_STALL_EVENT"; 156 + case MLX5_EVENT_TYPE_CMD: 157 + return "MLX5_EVENT_TYPE_CMD"; 158 + case MLX5_EVENT_TYPE_PAGE_REQUEST: 159 + return "MLX5_EVENT_TYPE_PAGE_REQUEST"; 160 + default: 161 + return "Unrecognized event"; 162 + } 163 + } 164 + 165 + static enum mlx5_dev_event port_subtype_event(u8 subtype) 166 + { 167 + switch (subtype) { 168 + case MLX5_PORT_CHANGE_SUBTYPE_DOWN: 169 + return MLX5_DEV_EVENT_PORT_DOWN; 170 + case MLX5_PORT_CHANGE_SUBTYPE_ACTIVE: 171 + return MLX5_DEV_EVENT_PORT_UP; 172 + case MLX5_PORT_CHANGE_SUBTYPE_INITIALIZED: 173 + return MLX5_DEV_EVENT_PORT_INITIALIZED; 174 + case MLX5_PORT_CHANGE_SUBTYPE_LID: 175 + return MLX5_DEV_EVENT_LID_CHANGE; 176 + case MLX5_PORT_CHANGE_SUBTYPE_PKEY: 177 + return MLX5_DEV_EVENT_PKEY_CHANGE; 178 + case MLX5_PORT_CHANGE_SUBTYPE_GUID: 179 + return MLX5_DEV_EVENT_GUID_CHANGE; 180 + case MLX5_PORT_CHANGE_SUBTYPE_CLIENT_REREG: 181 + return MLX5_DEV_EVENT_CLIENT_REREG; 182 + } 183 + return -1; 184 + } 185 + 186 + static void eq_update_ci(struct mlx5_eq *eq, int arm) 187 + { 188 + __be32 __iomem *addr = eq->doorbell + (arm ? 0 : 2); 189 + u32 val = (eq->cons_index & 0xffffff) | (eq->eqn << 24); 190 + __raw_writel((__force u32) cpu_to_be32(val), addr); 191 + /* We still want ordering, just not swabbing, so add a barrier */ 192 + mb(); 193 + } 194 + 195 + static int mlx5_eq_int(struct mlx5_core_dev *dev, struct mlx5_eq *eq) 196 + { 197 + struct mlx5_eqe *eqe; 198 + int eqes_found = 0; 199 + int set_ci = 0; 200 + u32 cqn; 201 + u32 srqn; 202 + u8 port; 203 + 204 + while ((eqe = next_eqe_sw(eq))) { 205 + /* 206 + * Make sure we read EQ entry contents after we've 207 + * checked the ownership bit. 208 + */ 209 + rmb(); 210 + 211 + mlx5_core_dbg(eq->dev, "eqn %d, eqe type %s\n", eq->eqn, eqe_type_str(eqe->type)); 212 + switch (eqe->type) { 213 + case MLX5_EVENT_TYPE_COMP: 214 + cqn = be32_to_cpu(eqe->data.comp.cqn) & 0xffffff; 215 + mlx5_cq_completion(dev, cqn); 216 + break; 217 + 218 + case MLX5_EVENT_TYPE_PATH_MIG: 219 + case MLX5_EVENT_TYPE_COMM_EST: 220 + case MLX5_EVENT_TYPE_SQ_DRAINED: 221 + case MLX5_EVENT_TYPE_SRQ_LAST_WQE: 222 + case MLX5_EVENT_TYPE_WQ_CATAS_ERROR: 223 + case MLX5_EVENT_TYPE_PATH_MIG_FAILED: 224 + case MLX5_EVENT_TYPE_WQ_INVAL_REQ_ERROR: 225 + case MLX5_EVENT_TYPE_WQ_ACCESS_ERROR: 226 + mlx5_core_dbg(dev, "event %s(%d) arrived\n", 227 + eqe_type_str(eqe->type), eqe->type); 228 + mlx5_qp_event(dev, be32_to_cpu(eqe->data.qp_srq.qp_srq_n) & 0xffffff, 229 + eqe->type); 230 + break; 231 + 232 + case MLX5_EVENT_TYPE_SRQ_RQ_LIMIT: 233 + case MLX5_EVENT_TYPE_SRQ_CATAS_ERROR: 234 + srqn = be32_to_cpu(eqe->data.qp_srq.qp_srq_n) & 0xffffff; 235 + mlx5_core_dbg(dev, "SRQ event %s(%d): srqn 0x%x\n", 236 + eqe_type_str(eqe->type), eqe->type, srqn); 237 + mlx5_srq_event(dev, srqn, eqe->type); 238 + break; 239 + 240 + case MLX5_EVENT_TYPE_CMD: 241 + mlx5_cmd_comp_handler(dev, be32_to_cpu(eqe->data.cmd.vector)); 242 + break; 243 + 244 + case MLX5_EVENT_TYPE_PORT_CHANGE: 245 + port = (eqe->data.port.port >> 4) & 0xf; 246 + switch (eqe->sub_type) { 247 + case MLX5_PORT_CHANGE_SUBTYPE_DOWN: 248 + case MLX5_PORT_CHANGE_SUBTYPE_ACTIVE: 249 + case MLX5_PORT_CHANGE_SUBTYPE_LID: 250 + case MLX5_PORT_CHANGE_SUBTYPE_PKEY: 251 + case MLX5_PORT_CHANGE_SUBTYPE_GUID: 252 + case MLX5_PORT_CHANGE_SUBTYPE_CLIENT_REREG: 253 + case MLX5_PORT_CHANGE_SUBTYPE_INITIALIZED: 254 + dev->event(dev, port_subtype_event(eqe->sub_type), &port); 255 + break; 256 + default: 257 + mlx5_core_warn(dev, "Port event with unrecognized subtype: port %d, sub_type %d\n", 258 + port, eqe->sub_type); 259 + } 260 + break; 261 + case MLX5_EVENT_TYPE_CQ_ERROR: 262 + cqn = be32_to_cpu(eqe->data.cq_err.cqn) & 0xffffff; 263 + mlx5_core_warn(dev, "CQ error on CQN 0x%x, syndrom 0x%x\n", 264 + cqn, eqe->data.cq_err.syndrome); 265 + mlx5_cq_event(dev, cqn, eqe->type); 266 + break; 267 + 268 + case MLX5_EVENT_TYPE_PAGE_REQUEST: 269 + { 270 + u16 func_id = be16_to_cpu(eqe->data.req_pages.func_id); 271 + s16 npages = be16_to_cpu(eqe->data.req_pages.num_pages); 272 + 273 + mlx5_core_dbg(dev, "page request for func 0x%x, napges %d\n", func_id, npages); 274 + mlx5_core_req_pages_handler(dev, func_id, npages); 275 + } 276 + break; 277 + 278 + 279 + default: 280 + mlx5_core_warn(dev, "Unhandled event 0x%x on EQ 0x%x\n", eqe->type, eq->eqn); 281 + break; 282 + } 283 + 284 + ++eq->cons_index; 285 + eqes_found = 1; 286 + ++set_ci; 287 + 288 + /* The HCA will think the queue has overflowed if we 289 + * don't tell it we've been processing events. We 290 + * create our EQs with MLX5_NUM_SPARE_EQE extra 291 + * entries, so we must update our consumer index at 292 + * least that often. 293 + */ 294 + if (unlikely(set_ci >= MLX5_NUM_SPARE_EQE)) { 295 + eq_update_ci(eq, 0); 296 + set_ci = 0; 297 + } 298 + } 299 + 300 + eq_update_ci(eq, 1); 301 + 302 + return eqes_found; 303 + } 304 + 305 + static irqreturn_t mlx5_msix_handler(int irq, void *eq_ptr) 306 + { 307 + struct mlx5_eq *eq = eq_ptr; 308 + struct mlx5_core_dev *dev = eq->dev; 309 + 310 + mlx5_eq_int(dev, eq); 311 + 312 + /* MSI-X vectors always belong to us */ 313 + return IRQ_HANDLED; 314 + } 315 + 316 + static void init_eq_buf(struct mlx5_eq *eq) 317 + { 318 + struct mlx5_eqe *eqe; 319 + int i; 320 + 321 + for (i = 0; i < eq->nent; i++) { 322 + eqe = get_eqe(eq, i); 323 + eqe->owner = MLX5_EQE_OWNER_INIT_VAL; 324 + } 325 + } 326 + 327 + int mlx5_create_map_eq(struct mlx5_core_dev *dev, struct mlx5_eq *eq, u8 vecidx, 328 + int nent, u64 mask, const char *name, struct mlx5_uar *uar) 329 + { 330 + struct mlx5_eq_table *table = &dev->priv.eq_table; 331 + struct mlx5_create_eq_mbox_in *in; 332 + struct mlx5_create_eq_mbox_out out; 333 + int err; 334 + int inlen; 335 + 336 + eq->nent = roundup_pow_of_two(nent + MLX5_NUM_SPARE_EQE); 337 + err = mlx5_buf_alloc(dev, eq->nent * MLX5_EQE_SIZE, 2 * PAGE_SIZE, 338 + &eq->buf); 339 + if (err) 340 + return err; 341 + 342 + init_eq_buf(eq); 343 + 344 + inlen = sizeof(*in) + sizeof(in->pas[0]) * eq->buf.npages; 345 + in = mlx5_vzalloc(inlen); 346 + if (!in) { 347 + err = -ENOMEM; 348 + goto err_buf; 349 + } 350 + memset(&out, 0, sizeof(out)); 351 + 352 + mlx5_fill_page_array(&eq->buf, in->pas); 353 + 354 + in->hdr.opcode = cpu_to_be16(MLX5_CMD_OP_CREATE_EQ); 355 + in->ctx.log_sz_usr_page = cpu_to_be32(ilog2(eq->nent) << 24 | uar->index); 356 + in->ctx.intr = vecidx; 357 + in->ctx.log_page_size = PAGE_SHIFT - 12; 358 + in->events_mask = cpu_to_be64(mask); 359 + 360 + err = mlx5_cmd_exec(dev, in, inlen, &out, sizeof(out)); 361 + if (err) 362 + goto err_in; 363 + 364 + if (out.hdr.status) { 365 + err = mlx5_cmd_status_to_err(&out.hdr); 366 + goto err_in; 367 + } 368 + 369 + eq->eqn = out.eq_number; 370 + err = request_irq(table->msix_arr[vecidx].vector, mlx5_msix_handler, 0, 371 + name, eq); 372 + if (err) 373 + goto err_eq; 374 + 375 + eq->irqn = vecidx; 376 + eq->dev = dev; 377 + eq->doorbell = uar->map + MLX5_EQ_DOORBEL_OFFSET; 378 + 379 + err = mlx5_debug_eq_add(dev, eq); 380 + if (err) 381 + goto err_irq; 382 + 383 + /* EQs are created in ARMED state 384 + */ 385 + eq_update_ci(eq, 1); 386 + 387 + mlx5_vfree(in); 388 + return 0; 389 + 390 + err_irq: 391 + free_irq(table->msix_arr[vecidx].vector, eq); 392 + 393 + err_eq: 394 + mlx5_cmd_destroy_eq(dev, eq->eqn); 395 + 396 + err_in: 397 + mlx5_vfree(in); 398 + 399 + err_buf: 400 + mlx5_buf_free(dev, &eq->buf); 401 + return err; 402 + } 403 + EXPORT_SYMBOL_GPL(mlx5_create_map_eq); 404 + 405 + int mlx5_destroy_unmap_eq(struct mlx5_core_dev *dev, struct mlx5_eq *eq) 406 + { 407 + struct mlx5_eq_table *table = &dev->priv.eq_table; 408 + int err; 409 + 410 + mlx5_debug_eq_remove(dev, eq); 411 + free_irq(table->msix_arr[eq->irqn].vector, eq); 412 + err = mlx5_cmd_destroy_eq(dev, eq->eqn); 413 + if (err) 414 + mlx5_core_warn(dev, "failed to destroy a previously created eq: eqn %d\n", 415 + eq->eqn); 416 + mlx5_buf_free(dev, &eq->buf); 417 + 418 + return err; 419 + } 420 + EXPORT_SYMBOL_GPL(mlx5_destroy_unmap_eq); 421 + 422 + int mlx5_eq_init(struct mlx5_core_dev *dev) 423 + { 424 + int err; 425 + 426 + spin_lock_init(&dev->priv.eq_table.lock); 427 + 428 + err = mlx5_eq_debugfs_init(dev); 429 + 430 + return err; 431 + } 432 + 433 + 434 + void mlx5_eq_cleanup(struct mlx5_core_dev *dev) 435 + { 436 + mlx5_eq_debugfs_cleanup(dev); 437 + } 438 + 439 + int mlx5_start_eqs(struct mlx5_core_dev *dev) 440 + { 441 + struct mlx5_eq_table *table = &dev->priv.eq_table; 442 + int err; 443 + 444 + err = mlx5_create_map_eq(dev, &table->cmd_eq, MLX5_EQ_VEC_CMD, 445 + MLX5_NUM_CMD_EQE, 1ull << MLX5_EVENT_TYPE_CMD, 446 + "mlx5_cmd_eq", &dev->priv.uuari.uars[0]); 447 + if (err) { 448 + mlx5_core_warn(dev, "failed to create cmd EQ %d\n", err); 449 + return err; 450 + } 451 + 452 + mlx5_cmd_use_events(dev); 453 + 454 + err = mlx5_create_map_eq(dev, &table->async_eq, MLX5_EQ_VEC_ASYNC, 455 + MLX5_NUM_ASYNC_EQE, MLX5_ASYNC_EVENT_MASK, 456 + "mlx5_async_eq", &dev->priv.uuari.uars[0]); 457 + if (err) { 458 + mlx5_core_warn(dev, "failed to create async EQ %d\n", err); 459 + goto err1; 460 + } 461 + 462 + err = mlx5_create_map_eq(dev, &table->pages_eq, 463 + MLX5_EQ_VEC_PAGES, 464 + dev->caps.max_vf + 1, 465 + 1 << MLX5_EVENT_TYPE_PAGE_REQUEST, "mlx5_pages_eq", 466 + &dev->priv.uuari.uars[0]); 467 + if (err) { 468 + mlx5_core_warn(dev, "failed to create pages EQ %d\n", err); 469 + goto err2; 470 + } 471 + 472 + return err; 473 + 474 + err2: 475 + mlx5_destroy_unmap_eq(dev, &table->async_eq); 476 + 477 + err1: 478 + mlx5_cmd_use_polling(dev); 479 + mlx5_destroy_unmap_eq(dev, &table->cmd_eq); 480 + return err; 481 + } 482 + 483 + int mlx5_stop_eqs(struct mlx5_core_dev *dev) 484 + { 485 + struct mlx5_eq_table *table = &dev->priv.eq_table; 486 + int err; 487 + 488 + err = mlx5_destroy_unmap_eq(dev, &table->pages_eq); 489 + if (err) 490 + return err; 491 + 492 + mlx5_destroy_unmap_eq(dev, &table->async_eq); 493 + mlx5_cmd_use_polling(dev); 494 + 495 + err = mlx5_destroy_unmap_eq(dev, &table->cmd_eq); 496 + if (err) 497 + mlx5_cmd_use_events(dev); 498 + 499 + return err; 500 + } 501 + 502 + int mlx5_core_eq_query(struct mlx5_core_dev *dev, struct mlx5_eq *eq, 503 + struct mlx5_query_eq_mbox_out *out, int outlen) 504 + { 505 + struct mlx5_query_eq_mbox_in in; 506 + int err; 507 + 508 + memset(&in, 0, sizeof(in)); 509 + memset(out, 0, outlen); 510 + in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_QUERY_EQ); 511 + in.eqn = eq->eqn; 512 + err = mlx5_cmd_exec(dev, &in, sizeof(in), out, outlen); 513 + if (err) 514 + return err; 515 + 516 + if (out->hdr.status) 517 + err = mlx5_cmd_status_to_err(&out->hdr); 518 + 519 + return err; 520 + } 521 + EXPORT_SYMBOL_GPL(mlx5_core_eq_query);
+185
drivers/net/ethernet/mellanox/mlx5/core/fw.c
··· 1 + /* 2 + * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved. 3 + * 4 + * This software is available to you under a choice of one of two 5 + * licenses. You may choose to be licensed under the terms of the GNU 6 + * General Public License (GPL) Version 2, available from the file 7 + * COPYING in the main directory of this source tree, or the 8 + * OpenIB.org BSD license below: 9 + * 10 + * Redistribution and use in source and binary forms, with or 11 + * without modification, are permitted provided that the following 12 + * conditions are met: 13 + * 14 + * - Redistributions of source code must retain the above 15 + * copyright notice, this list of conditions and the following 16 + * disclaimer. 17 + * 18 + * - Redistributions in binary form must reproduce the above 19 + * copyright notice, this list of conditions and the following 20 + * disclaimer in the documentation and/or other materials 21 + * 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 OF 25 + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26 + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 27 + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 28 + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29 + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30 + * SOFTWARE. 31 + */ 32 + 33 + #include <linux/mlx5/driver.h> 34 + #include <linux/mlx5/cmd.h> 35 + #include <linux/module.h> 36 + #include "mlx5_core.h" 37 + 38 + int mlx5_cmd_query_adapter(struct mlx5_core_dev *dev) 39 + { 40 + struct mlx5_cmd_query_adapter_mbox_out *out; 41 + struct mlx5_cmd_query_adapter_mbox_in in; 42 + int err; 43 + 44 + out = kzalloc(sizeof(*out), GFP_KERNEL); 45 + if (!out) 46 + return -ENOMEM; 47 + 48 + memset(&in, 0, sizeof(in)); 49 + in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_QUERY_ADAPTER); 50 + err = mlx5_cmd_exec(dev, &in, sizeof(in), out, sizeof(*out)); 51 + if (err) 52 + goto out_out; 53 + 54 + if (out->hdr.status) { 55 + err = mlx5_cmd_status_to_err(&out->hdr); 56 + goto out_out; 57 + } 58 + 59 + memcpy(dev->board_id, out->vsd_psid, sizeof(out->vsd_psid)); 60 + 61 + out_out: 62 + kfree(out); 63 + 64 + return err; 65 + } 66 + 67 + int mlx5_cmd_query_hca_cap(struct mlx5_core_dev *dev, 68 + struct mlx5_caps *caps) 69 + { 70 + struct mlx5_cmd_query_hca_cap_mbox_out *out; 71 + struct mlx5_cmd_query_hca_cap_mbox_in in; 72 + struct mlx5_query_special_ctxs_mbox_out ctx_out; 73 + struct mlx5_query_special_ctxs_mbox_in ctx_in; 74 + int err; 75 + u16 t16; 76 + 77 + out = kzalloc(sizeof(*out), GFP_KERNEL); 78 + if (!out) 79 + return -ENOMEM; 80 + 81 + memset(&in, 0, sizeof(in)); 82 + in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_QUERY_HCA_CAP); 83 + in.hdr.opmod = cpu_to_be16(0x1); 84 + err = mlx5_cmd_exec(dev, &in, sizeof(in), out, sizeof(*out)); 85 + if (err) 86 + goto out_out; 87 + 88 + if (out->hdr.status) { 89 + err = mlx5_cmd_status_to_err(&out->hdr); 90 + goto out_out; 91 + } 92 + 93 + 94 + caps->log_max_eq = out->hca_cap.log_max_eq & 0xf; 95 + caps->max_cqes = 1 << out->hca_cap.log_max_cq_sz; 96 + caps->max_wqes = 1 << out->hca_cap.log_max_qp_sz; 97 + caps->max_sq_desc_sz = be16_to_cpu(out->hca_cap.max_desc_sz_sq); 98 + caps->max_rq_desc_sz = be16_to_cpu(out->hca_cap.max_desc_sz_rq); 99 + caps->flags = be64_to_cpu(out->hca_cap.flags); 100 + caps->stat_rate_support = be16_to_cpu(out->hca_cap.stat_rate_support); 101 + caps->log_max_msg = out->hca_cap.log_max_msg & 0x1f; 102 + caps->num_ports = out->hca_cap.num_ports & 0xf; 103 + caps->log_max_cq = out->hca_cap.log_max_cq & 0x1f; 104 + if (caps->num_ports > MLX5_MAX_PORTS) { 105 + mlx5_core_err(dev, "device has %d ports while the driver supports max %d ports\n", 106 + caps->num_ports, MLX5_MAX_PORTS); 107 + err = -EINVAL; 108 + goto out_out; 109 + } 110 + caps->log_max_qp = out->hca_cap.log_max_qp & 0x1f; 111 + caps->log_max_mkey = out->hca_cap.log_max_mkey & 0x3f; 112 + caps->log_max_pd = out->hca_cap.log_max_pd & 0x1f; 113 + caps->log_max_srq = out->hca_cap.log_max_srqs & 0x1f; 114 + caps->local_ca_ack_delay = out->hca_cap.local_ca_ack_delay & 0x1f; 115 + caps->log_max_mcg = out->hca_cap.log_max_mcg; 116 + caps->max_qp_mcg = be16_to_cpu(out->hca_cap.max_qp_mcg); 117 + caps->max_ra_res_qp = 1 << (out->hca_cap.log_max_ra_res_qp & 0x3f); 118 + caps->max_ra_req_qp = 1 << (out->hca_cap.log_max_ra_req_qp & 0x3f); 119 + caps->max_srq_wqes = 1 << out->hca_cap.log_max_srq_sz; 120 + t16 = be16_to_cpu(out->hca_cap.bf_log_bf_reg_size); 121 + if (t16 & 0x8000) { 122 + caps->bf_reg_size = 1 << (t16 & 0x1f); 123 + caps->bf_regs_per_page = MLX5_BF_REGS_PER_PAGE; 124 + } else { 125 + caps->bf_reg_size = 0; 126 + caps->bf_regs_per_page = 0; 127 + } 128 + caps->min_page_sz = ~(u32)((1 << out->hca_cap.log_pg_sz) - 1); 129 + 130 + memset(&ctx_in, 0, sizeof(ctx_in)); 131 + memset(&ctx_out, 0, sizeof(ctx_out)); 132 + ctx_in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_QUERY_SPECIAL_CONTEXTS); 133 + err = mlx5_cmd_exec(dev, &ctx_in, sizeof(ctx_in), 134 + &ctx_out, sizeof(ctx_out)); 135 + if (err) 136 + goto out_out; 137 + 138 + if (ctx_out.hdr.status) 139 + err = mlx5_cmd_status_to_err(&ctx_out.hdr); 140 + 141 + caps->reserved_lkey = be32_to_cpu(ctx_out.reserved_lkey); 142 + 143 + out_out: 144 + kfree(out); 145 + 146 + return err; 147 + } 148 + 149 + int mlx5_cmd_init_hca(struct mlx5_core_dev *dev) 150 + { 151 + struct mlx5_cmd_init_hca_mbox_in in; 152 + struct mlx5_cmd_init_hca_mbox_out out; 153 + int err; 154 + 155 + memset(&in, 0, sizeof(in)); 156 + memset(&out, 0, sizeof(out)); 157 + in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_INIT_HCA); 158 + err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out)); 159 + if (err) 160 + return err; 161 + 162 + if (out.hdr.status) 163 + err = mlx5_cmd_status_to_err(&out.hdr); 164 + 165 + return err; 166 + } 167 + 168 + int mlx5_cmd_teardown_hca(struct mlx5_core_dev *dev) 169 + { 170 + struct mlx5_cmd_teardown_hca_mbox_in in; 171 + struct mlx5_cmd_teardown_hca_mbox_out out; 172 + int err; 173 + 174 + memset(&in, 0, sizeof(in)); 175 + memset(&out, 0, sizeof(out)); 176 + in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_TEARDOWN_HCA); 177 + err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out)); 178 + if (err) 179 + return err; 180 + 181 + if (out.hdr.status) 182 + err = mlx5_cmd_status_to_err(&out.hdr); 183 + 184 + return err; 185 + }
+217
drivers/net/ethernet/mellanox/mlx5/core/health.c
··· 1 + /* 2 + * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved. 3 + * 4 + * This software is available to you under a choice of one of two 5 + * licenses. You may choose to be licensed under the terms of the GNU 6 + * General Public License (GPL) Version 2, available from the file 7 + * COPYING in the main directory of this source tree, or the 8 + * OpenIB.org BSD license below: 9 + * 10 + * Redistribution and use in source and binary forms, with or 11 + * without modification, are permitted provided that the following 12 + * conditions are met: 13 + * 14 + * - Redistributions of source code must retain the above 15 + * copyright notice, this list of conditions and the following 16 + * disclaimer. 17 + * 18 + * - Redistributions in binary form must reproduce the above 19 + * copyright notice, this list of conditions and the following 20 + * disclaimer in the documentation and/or other materials 21 + * 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 OF 25 + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26 + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 27 + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 28 + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29 + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30 + * SOFTWARE. 31 + */ 32 + 33 + #include <linux/kernel.h> 34 + #include <linux/module.h> 35 + #include <linux/random.h> 36 + #include <linux/vmalloc.h> 37 + #include <linux/mlx5/driver.h> 38 + #include <linux/mlx5/cmd.h> 39 + #include "mlx5_core.h" 40 + 41 + enum { 42 + MLX5_HEALTH_POLL_INTERVAL = 2 * HZ, 43 + MAX_MISSES = 3, 44 + }; 45 + 46 + enum { 47 + MLX5_HEALTH_SYNDR_FW_ERR = 0x1, 48 + MLX5_HEALTH_SYNDR_IRISC_ERR = 0x7, 49 + MLX5_HEALTH_SYNDR_CRC_ERR = 0x9, 50 + MLX5_HEALTH_SYNDR_FETCH_PCI_ERR = 0xa, 51 + MLX5_HEALTH_SYNDR_HW_FTL_ERR = 0xb, 52 + MLX5_HEALTH_SYNDR_ASYNC_EQ_OVERRUN_ERR = 0xc, 53 + MLX5_HEALTH_SYNDR_EQ_ERR = 0xd, 54 + MLX5_HEALTH_SYNDR_FFSER_ERR = 0xf, 55 + }; 56 + 57 + static DEFINE_SPINLOCK(health_lock); 58 + 59 + static LIST_HEAD(health_list); 60 + static struct work_struct health_work; 61 + 62 + static health_handler_t reg_handler; 63 + int mlx5_register_health_report_handler(health_handler_t handler) 64 + { 65 + spin_lock_irq(&health_lock); 66 + if (reg_handler) { 67 + spin_unlock_irq(&health_lock); 68 + return -EEXIST; 69 + } 70 + reg_handler = handler; 71 + spin_unlock_irq(&health_lock); 72 + 73 + return 0; 74 + } 75 + EXPORT_SYMBOL(mlx5_register_health_report_handler); 76 + 77 + void mlx5_unregister_health_report_handler(void) 78 + { 79 + spin_lock_irq(&health_lock); 80 + reg_handler = NULL; 81 + spin_unlock_irq(&health_lock); 82 + } 83 + EXPORT_SYMBOL(mlx5_unregister_health_report_handler); 84 + 85 + static void health_care(struct work_struct *work) 86 + { 87 + struct mlx5_core_health *health, *n; 88 + struct mlx5_core_dev *dev; 89 + struct mlx5_priv *priv; 90 + LIST_HEAD(tlist); 91 + 92 + spin_lock_irq(&health_lock); 93 + list_splice_init(&health_list, &tlist); 94 + 95 + spin_unlock_irq(&health_lock); 96 + 97 + list_for_each_entry_safe(health, n, &tlist, list) { 98 + priv = container_of(health, struct mlx5_priv, health); 99 + dev = container_of(priv, struct mlx5_core_dev, priv); 100 + mlx5_core_warn(dev, "handling bad device here\n"); 101 + spin_lock_irq(&health_lock); 102 + if (reg_handler) 103 + reg_handler(dev->pdev, health->health, 104 + sizeof(health->health)); 105 + 106 + list_del_init(&health->list); 107 + spin_unlock_irq(&health_lock); 108 + } 109 + } 110 + 111 + static const char *hsynd_str(u8 synd) 112 + { 113 + switch (synd) { 114 + case MLX5_HEALTH_SYNDR_FW_ERR: 115 + return "firmware internal error"; 116 + case MLX5_HEALTH_SYNDR_IRISC_ERR: 117 + return "irisc not responding"; 118 + case MLX5_HEALTH_SYNDR_CRC_ERR: 119 + return "firmware CRC error"; 120 + case MLX5_HEALTH_SYNDR_FETCH_PCI_ERR: 121 + return "ICM fetch PCI error"; 122 + case MLX5_HEALTH_SYNDR_HW_FTL_ERR: 123 + return "HW fatal error\n"; 124 + case MLX5_HEALTH_SYNDR_ASYNC_EQ_OVERRUN_ERR: 125 + return "async EQ buffer overrun"; 126 + case MLX5_HEALTH_SYNDR_EQ_ERR: 127 + return "EQ error"; 128 + case MLX5_HEALTH_SYNDR_FFSER_ERR: 129 + return "FFSER error"; 130 + default: 131 + return "unrecognized error"; 132 + } 133 + } 134 + 135 + static void print_health_info(struct mlx5_core_dev *dev) 136 + { 137 + struct mlx5_core_health *health = &dev->priv.health; 138 + struct health_buffer __iomem *h = health->health; 139 + int i; 140 + 141 + for (i = 0; i < ARRAY_SIZE(h->assert_var); i++) 142 + pr_info("assert_var[%d] 0x%08x\n", i, be32_to_cpu(h->assert_var[i])); 143 + 144 + pr_info("assert_exit_ptr 0x%08x\n", be32_to_cpu(h->assert_exit_ptr)); 145 + pr_info("assert_callra 0x%08x\n", be32_to_cpu(h->assert_callra)); 146 + pr_info("fw_ver 0x%08x\n", be32_to_cpu(h->fw_ver)); 147 + pr_info("hw_id 0x%08x\n", be32_to_cpu(h->hw_id)); 148 + pr_info("irisc_index %d\n", h->irisc_index); 149 + pr_info("synd 0x%x: %s\n", h->synd, hsynd_str(h->synd)); 150 + pr_info("ext_sync 0x%04x\n", be16_to_cpu(h->ext_sync)); 151 + } 152 + 153 + static void poll_health(unsigned long data) 154 + { 155 + struct mlx5_core_dev *dev = (struct mlx5_core_dev *)data; 156 + struct mlx5_core_health *health = &dev->priv.health; 157 + unsigned long next; 158 + u32 count; 159 + 160 + count = ioread32be(health->health_counter); 161 + if (count == health->prev) 162 + ++health->miss_counter; 163 + else 164 + health->miss_counter = 0; 165 + 166 + health->prev = count; 167 + if (health->miss_counter == MAX_MISSES) { 168 + mlx5_core_err(dev, "device's health compromised\n"); 169 + print_health_info(dev); 170 + spin_lock_irq(&health_lock); 171 + list_add_tail(&health->list, &health_list); 172 + spin_unlock_irq(&health_lock); 173 + 174 + queue_work(mlx5_core_wq, &health_work); 175 + } else { 176 + get_random_bytes(&next, sizeof(next)); 177 + next %= HZ; 178 + next += jiffies + MLX5_HEALTH_POLL_INTERVAL; 179 + mod_timer(&health->timer, next); 180 + } 181 + } 182 + 183 + void mlx5_start_health_poll(struct mlx5_core_dev *dev) 184 + { 185 + struct mlx5_core_health *health = &dev->priv.health; 186 + 187 + INIT_LIST_HEAD(&health->list); 188 + init_timer(&health->timer); 189 + health->health = &dev->iseg->health; 190 + health->health_counter = &dev->iseg->health_counter; 191 + 192 + health->timer.data = (unsigned long)dev; 193 + health->timer.function = poll_health; 194 + health->timer.expires = round_jiffies(jiffies + MLX5_HEALTH_POLL_INTERVAL); 195 + add_timer(&health->timer); 196 + } 197 + 198 + void mlx5_stop_health_poll(struct mlx5_core_dev *dev) 199 + { 200 + struct mlx5_core_health *health = &dev->priv.health; 201 + 202 + del_timer_sync(&health->timer); 203 + 204 + spin_lock_irq(&health_lock); 205 + if (!list_empty(&health->list)) 206 + list_del_init(&health->list); 207 + spin_unlock_irq(&health_lock); 208 + } 209 + 210 + void mlx5_health_cleanup(void) 211 + { 212 + } 213 + 214 + void __init mlx5_health_init(void) 215 + { 216 + INIT_WORK(&health_work, health_care); 217 + }
+78
drivers/net/ethernet/mellanox/mlx5/core/mad.c
··· 1 + /* 2 + * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved. 3 + * 4 + * This software is available to you under a choice of one of two 5 + * licenses. You may choose to be licensed under the terms of the GNU 6 + * General Public License (GPL) Version 2, available from the file 7 + * COPYING in the main directory of this source tree, or the 8 + * OpenIB.org BSD license below: 9 + * 10 + * Redistribution and use in source and binary forms, with or 11 + * without modification, are permitted provided that the following 12 + * conditions are met: 13 + * 14 + * - Redistributions of source code must retain the above 15 + * copyright notice, this list of conditions and the following 16 + * disclaimer. 17 + * 18 + * - Redistributions in binary form must reproduce the above 19 + * copyright notice, this list of conditions and the following 20 + * disclaimer in the documentation and/or other materials 21 + * 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 OF 25 + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26 + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 27 + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 28 + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29 + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30 + * SOFTWARE. 31 + */ 32 + 33 + #include <linux/kernel.h> 34 + #include <linux/module.h> 35 + #include <linux/mlx5/driver.h> 36 + #include <linux/mlx5/cmd.h> 37 + #include "mlx5_core.h" 38 + 39 + int mlx5_core_mad_ifc(struct mlx5_core_dev *dev, void *inb, void *outb, 40 + u16 opmod, int port) 41 + { 42 + struct mlx5_mad_ifc_mbox_in *in = NULL; 43 + struct mlx5_mad_ifc_mbox_out *out = NULL; 44 + int err; 45 + 46 + in = kzalloc(sizeof(*in), GFP_KERNEL); 47 + if (!in) 48 + return -ENOMEM; 49 + 50 + out = kzalloc(sizeof(*out), GFP_KERNEL); 51 + if (!out) { 52 + err = -ENOMEM; 53 + goto out; 54 + } 55 + 56 + in->hdr.opcode = cpu_to_be16(MLX5_CMD_OP_MAD_IFC); 57 + in->hdr.opmod = cpu_to_be16(opmod); 58 + in->port = port; 59 + 60 + memcpy(in->data, inb, sizeof(in->data)); 61 + 62 + err = mlx5_cmd_exec(dev, in, sizeof(*in), out, sizeof(*out)); 63 + if (err) 64 + goto out; 65 + 66 + if (out->hdr.status) { 67 + err = mlx5_cmd_status_to_err(&out->hdr); 68 + goto out; 69 + } 70 + 71 + memcpy(outb, out->data, sizeof(out->data)); 72 + 73 + out: 74 + kfree(out); 75 + kfree(in); 76 + return err; 77 + } 78 + EXPORT_SYMBOL_GPL(mlx5_core_mad_ifc);
+475
drivers/net/ethernet/mellanox/mlx5/core/main.c
··· 1 + /* 2 + * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved. 3 + * 4 + * This software is available to you under a choice of one of two 5 + * licenses. You may choose to be licensed under the terms of the GNU 6 + * General Public License (GPL) Version 2, available from the file 7 + * COPYING in the main directory of this source tree, or the 8 + * OpenIB.org BSD license below: 9 + * 10 + * Redistribution and use in source and binary forms, with or 11 + * without modification, are permitted provided that the following 12 + * conditions are met: 13 + * 14 + * - Redistributions of source code must retain the above 15 + * copyright notice, this list of conditions and the following 16 + * disclaimer. 17 + * 18 + * - Redistributions in binary form must reproduce the above 19 + * copyright notice, this list of conditions and the following 20 + * disclaimer in the documentation and/or other materials 21 + * 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 OF 25 + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26 + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 27 + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 28 + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29 + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30 + * SOFTWARE. 31 + */ 32 + 33 + #include <asm-generic/kmap_types.h> 34 + #include <linux/module.h> 35 + #include <linux/init.h> 36 + #include <linux/errno.h> 37 + #include <linux/pci.h> 38 + #include <linux/dma-mapping.h> 39 + #include <linux/slab.h> 40 + #include <linux/io-mapping.h> 41 + #include <linux/mlx5/driver.h> 42 + #include <linux/mlx5/cq.h> 43 + #include <linux/mlx5/qp.h> 44 + #include <linux/mlx5/srq.h> 45 + #include <linux/debugfs.h> 46 + #include "mlx5_core.h" 47 + 48 + #define DRIVER_NAME "mlx5_core" 49 + #define DRIVER_VERSION "1.0" 50 + #define DRIVER_RELDATE "June 2013" 51 + 52 + MODULE_AUTHOR("Eli Cohen <eli@mellanox.com>"); 53 + MODULE_DESCRIPTION("Mellanox ConnectX-IB HCA core library"); 54 + MODULE_LICENSE("Dual BSD/GPL"); 55 + MODULE_VERSION(DRIVER_VERSION); 56 + 57 + int mlx5_core_debug_mask; 58 + module_param_named(debug_mask, mlx5_core_debug_mask, int, 0644); 59 + MODULE_PARM_DESC(debug_mask, "debug mask: 1 = dump cmd data, 2 = dump cmd exec time, 3 = both. Default=0"); 60 + 61 + struct workqueue_struct *mlx5_core_wq; 62 + 63 + static int set_dma_caps(struct pci_dev *pdev) 64 + { 65 + int err; 66 + 67 + err = pci_set_dma_mask(pdev, DMA_BIT_MASK(64)); 68 + if (err) { 69 + dev_warn(&pdev->dev, "Warning: couldn't set 64-bit PCI DMA mask.\n"); 70 + err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); 71 + if (err) { 72 + dev_err(&pdev->dev, "Can't set PCI DMA mask, aborting.\n"); 73 + return err; 74 + } 75 + } 76 + 77 + err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)); 78 + if (err) { 79 + dev_warn(&pdev->dev, 80 + "Warning: couldn't set 64-bit consistent PCI DMA mask.\n"); 81 + err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); 82 + if (err) { 83 + dev_err(&pdev->dev, 84 + "Can't set consistent PCI DMA mask, aborting.\n"); 85 + return err; 86 + } 87 + } 88 + 89 + dma_set_max_seg_size(&pdev->dev, 2u * 1024 * 1024 * 1024); 90 + return err; 91 + } 92 + 93 + static int request_bar(struct pci_dev *pdev) 94 + { 95 + int err = 0; 96 + 97 + if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) { 98 + dev_err(&pdev->dev, "Missing registers BAR, aborting.\n"); 99 + return -ENODEV; 100 + } 101 + 102 + err = pci_request_regions(pdev, DRIVER_NAME); 103 + if (err) 104 + dev_err(&pdev->dev, "Couldn't get PCI resources, aborting\n"); 105 + 106 + return err; 107 + } 108 + 109 + static void release_bar(struct pci_dev *pdev) 110 + { 111 + pci_release_regions(pdev); 112 + } 113 + 114 + static int mlx5_enable_msix(struct mlx5_core_dev *dev) 115 + { 116 + struct mlx5_eq_table *table = &dev->priv.eq_table; 117 + int num_eqs = 1 << dev->caps.log_max_eq; 118 + int nvec; 119 + int err; 120 + int i; 121 + 122 + nvec = dev->caps.num_ports * num_online_cpus() + MLX5_EQ_VEC_COMP_BASE; 123 + nvec = min_t(int, nvec, num_eqs); 124 + if (nvec <= MLX5_EQ_VEC_COMP_BASE) 125 + return -ENOMEM; 126 + 127 + table->msix_arr = kzalloc(nvec * sizeof(*table->msix_arr), GFP_KERNEL); 128 + if (!table->msix_arr) 129 + return -ENOMEM; 130 + 131 + for (i = 0; i < nvec; i++) 132 + table->msix_arr[i].entry = i; 133 + 134 + retry: 135 + table->num_comp_vectors = nvec - MLX5_EQ_VEC_COMP_BASE; 136 + err = pci_enable_msix(dev->pdev, table->msix_arr, nvec); 137 + if (err <= 0) { 138 + return err; 139 + } else if (err > 2) { 140 + nvec = err; 141 + goto retry; 142 + } 143 + 144 + mlx5_core_dbg(dev, "received %d MSI vectors out of %d requested\n", err, nvec); 145 + 146 + return 0; 147 + } 148 + 149 + static void mlx5_disable_msix(struct mlx5_core_dev *dev) 150 + { 151 + struct mlx5_eq_table *table = &dev->priv.eq_table; 152 + 153 + pci_disable_msix(dev->pdev); 154 + kfree(table->msix_arr); 155 + } 156 + 157 + struct mlx5_reg_host_endianess { 158 + u8 he; 159 + u8 rsvd[15]; 160 + }; 161 + 162 + static int handle_hca_cap(struct mlx5_core_dev *dev) 163 + { 164 + struct mlx5_cmd_query_hca_cap_mbox_out *query_out = NULL; 165 + struct mlx5_cmd_set_hca_cap_mbox_in *set_ctx = NULL; 166 + struct mlx5_cmd_query_hca_cap_mbox_in query_ctx; 167 + struct mlx5_cmd_set_hca_cap_mbox_out set_out; 168 + struct mlx5_profile *prof = dev->profile; 169 + u64 flags; 170 + int csum = 1; 171 + int err; 172 + 173 + memset(&query_ctx, 0, sizeof(query_ctx)); 174 + query_out = kzalloc(sizeof(*query_out), GFP_KERNEL); 175 + if (!query_out) 176 + return -ENOMEM; 177 + 178 + set_ctx = kzalloc(sizeof(*set_ctx), GFP_KERNEL); 179 + if (!set_ctx) { 180 + err = -ENOMEM; 181 + goto query_ex; 182 + } 183 + 184 + query_ctx.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_QUERY_HCA_CAP); 185 + query_ctx.hdr.opmod = cpu_to_be16(0x1); 186 + err = mlx5_cmd_exec(dev, &query_ctx, sizeof(query_ctx), 187 + query_out, sizeof(*query_out)); 188 + if (err) 189 + goto query_ex; 190 + 191 + err = mlx5_cmd_status_to_err(&query_out->hdr); 192 + if (err) { 193 + mlx5_core_warn(dev, "query hca cap failed, %d\n", err); 194 + goto query_ex; 195 + } 196 + 197 + memcpy(&set_ctx->hca_cap, &query_out->hca_cap, 198 + sizeof(set_ctx->hca_cap)); 199 + 200 + if (prof->mask & MLX5_PROF_MASK_CMDIF_CSUM) { 201 + csum = !!prof->cmdif_csum; 202 + flags = be64_to_cpu(set_ctx->hca_cap.flags); 203 + if (csum) 204 + flags |= MLX5_DEV_CAP_FLAG_CMDIF_CSUM; 205 + else 206 + flags &= ~MLX5_DEV_CAP_FLAG_CMDIF_CSUM; 207 + 208 + set_ctx->hca_cap.flags = cpu_to_be64(flags); 209 + } 210 + 211 + if (dev->profile->mask & MLX5_PROF_MASK_QP_SIZE) 212 + set_ctx->hca_cap.log_max_qp = dev->profile->log_max_qp; 213 + 214 + memset(&set_out, 0, sizeof(set_out)); 215 + set_ctx->hca_cap.uar_page_sz = cpu_to_be16(PAGE_SHIFT - 12); 216 + set_ctx->hdr.opcode = cpu_to_be16(MLX5_CMD_OP_SET_HCA_CAP); 217 + err = mlx5_cmd_exec(dev, set_ctx, sizeof(*set_ctx), 218 + &set_out, sizeof(set_out)); 219 + if (err) { 220 + mlx5_core_warn(dev, "set hca cap failed, %d\n", err); 221 + goto query_ex; 222 + } 223 + 224 + err = mlx5_cmd_status_to_err(&set_out.hdr); 225 + if (err) 226 + goto query_ex; 227 + 228 + if (!csum) 229 + dev->cmd.checksum_disabled = 1; 230 + 231 + query_ex: 232 + kfree(query_out); 233 + kfree(set_ctx); 234 + 235 + return err; 236 + } 237 + 238 + static int set_hca_ctrl(struct mlx5_core_dev *dev) 239 + { 240 + struct mlx5_reg_host_endianess he_in; 241 + struct mlx5_reg_host_endianess he_out; 242 + int err; 243 + 244 + memset(&he_in, 0, sizeof(he_in)); 245 + he_in.he = MLX5_SET_HOST_ENDIANNESS; 246 + err = mlx5_core_access_reg(dev, &he_in, sizeof(he_in), 247 + &he_out, sizeof(he_out), 248 + MLX5_REG_HOST_ENDIANNESS, 0, 1); 249 + return err; 250 + } 251 + 252 + int mlx5_dev_init(struct mlx5_core_dev *dev, struct pci_dev *pdev) 253 + { 254 + struct mlx5_priv *priv = &dev->priv; 255 + int err; 256 + 257 + dev->pdev = pdev; 258 + pci_set_drvdata(dev->pdev, dev); 259 + strncpy(priv->name, dev_name(&pdev->dev), MLX5_MAX_NAME_LEN); 260 + priv->name[MLX5_MAX_NAME_LEN - 1] = 0; 261 + 262 + mutex_init(&priv->pgdir_mutex); 263 + INIT_LIST_HEAD(&priv->pgdir_list); 264 + spin_lock_init(&priv->mkey_lock); 265 + 266 + priv->dbg_root = debugfs_create_dir(dev_name(&pdev->dev), mlx5_debugfs_root); 267 + if (!priv->dbg_root) 268 + return -ENOMEM; 269 + 270 + err = pci_enable_device(pdev); 271 + if (err) { 272 + dev_err(&pdev->dev, "Cannot enable PCI device, aborting.\n"); 273 + goto err_dbg; 274 + } 275 + 276 + err = request_bar(pdev); 277 + if (err) { 278 + dev_err(&pdev->dev, "error requesting BARs, aborting.\n"); 279 + goto err_disable; 280 + } 281 + 282 + pci_set_master(pdev); 283 + 284 + err = set_dma_caps(pdev); 285 + if (err) { 286 + dev_err(&pdev->dev, "Failed setting DMA capabilities mask, aborting\n"); 287 + goto err_clr_master; 288 + } 289 + 290 + dev->iseg_base = pci_resource_start(dev->pdev, 0); 291 + dev->iseg = ioremap(dev->iseg_base, sizeof(*dev->iseg)); 292 + if (!dev->iseg) { 293 + err = -ENOMEM; 294 + dev_err(&pdev->dev, "Failed mapping initialization segment, aborting\n"); 295 + goto err_clr_master; 296 + } 297 + dev_info(&pdev->dev, "firmware version: %d.%d.%d\n", fw_rev_maj(dev), 298 + fw_rev_min(dev), fw_rev_sub(dev)); 299 + 300 + err = mlx5_cmd_init(dev); 301 + if (err) { 302 + dev_err(&pdev->dev, "Failed initializing command interface, aborting\n"); 303 + goto err_unmap; 304 + } 305 + 306 + mlx5_pagealloc_init(dev); 307 + err = set_hca_ctrl(dev); 308 + if (err) { 309 + dev_err(&pdev->dev, "set_hca_ctrl failed\n"); 310 + goto err_pagealloc_cleanup; 311 + } 312 + 313 + err = handle_hca_cap(dev); 314 + if (err) { 315 + dev_err(&pdev->dev, "handle_hca_cap failed\n"); 316 + goto err_pagealloc_cleanup; 317 + } 318 + 319 + err = mlx5_satisfy_startup_pages(dev); 320 + if (err) { 321 + dev_err(&pdev->dev, "failed to allocate startup pages\n"); 322 + goto err_pagealloc_cleanup; 323 + } 324 + 325 + err = mlx5_pagealloc_start(dev); 326 + if (err) { 327 + dev_err(&pdev->dev, "mlx5_pagealloc_start failed\n"); 328 + goto err_reclaim_pages; 329 + } 330 + 331 + err = mlx5_cmd_init_hca(dev); 332 + if (err) { 333 + dev_err(&pdev->dev, "init hca failed\n"); 334 + goto err_pagealloc_stop; 335 + } 336 + 337 + mlx5_start_health_poll(dev); 338 + 339 + err = mlx5_cmd_query_hca_cap(dev, &dev->caps); 340 + if (err) { 341 + dev_err(&pdev->dev, "query hca failed\n"); 342 + goto err_stop_poll; 343 + } 344 + 345 + err = mlx5_cmd_query_adapter(dev); 346 + if (err) { 347 + dev_err(&pdev->dev, "query adapter failed\n"); 348 + goto err_stop_poll; 349 + } 350 + 351 + err = mlx5_enable_msix(dev); 352 + if (err) { 353 + dev_err(&pdev->dev, "enable msix failed\n"); 354 + goto err_stop_poll; 355 + } 356 + 357 + err = mlx5_eq_init(dev); 358 + if (err) { 359 + dev_err(&pdev->dev, "failed to initialize eq\n"); 360 + goto disable_msix; 361 + } 362 + 363 + err = mlx5_alloc_uuars(dev, &priv->uuari); 364 + if (err) { 365 + dev_err(&pdev->dev, "Failed allocating uar, aborting\n"); 366 + goto err_eq_cleanup; 367 + } 368 + 369 + err = mlx5_start_eqs(dev); 370 + if (err) { 371 + dev_err(&pdev->dev, "Failed to start pages and async EQs\n"); 372 + goto err_free_uar; 373 + } 374 + 375 + MLX5_INIT_DOORBELL_LOCK(&priv->cq_uar_lock); 376 + 377 + mlx5_init_cq_table(dev); 378 + mlx5_init_qp_table(dev); 379 + mlx5_init_srq_table(dev); 380 + 381 + return 0; 382 + 383 + err_free_uar: 384 + mlx5_free_uuars(dev, &priv->uuari); 385 + 386 + err_eq_cleanup: 387 + mlx5_eq_cleanup(dev); 388 + 389 + disable_msix: 390 + mlx5_disable_msix(dev); 391 + 392 + err_stop_poll: 393 + mlx5_stop_health_poll(dev); 394 + mlx5_cmd_teardown_hca(dev); 395 + 396 + err_pagealloc_stop: 397 + mlx5_pagealloc_stop(dev); 398 + 399 + err_reclaim_pages: 400 + mlx5_reclaim_startup_pages(dev); 401 + 402 + err_pagealloc_cleanup: 403 + mlx5_pagealloc_cleanup(dev); 404 + mlx5_cmd_cleanup(dev); 405 + 406 + err_unmap: 407 + iounmap(dev->iseg); 408 + 409 + err_clr_master: 410 + pci_clear_master(dev->pdev); 411 + release_bar(dev->pdev); 412 + 413 + err_disable: 414 + pci_disable_device(dev->pdev); 415 + 416 + err_dbg: 417 + debugfs_remove(priv->dbg_root); 418 + return err; 419 + } 420 + EXPORT_SYMBOL(mlx5_dev_init); 421 + 422 + void mlx5_dev_cleanup(struct mlx5_core_dev *dev) 423 + { 424 + struct mlx5_priv *priv = &dev->priv; 425 + 426 + mlx5_cleanup_srq_table(dev); 427 + mlx5_cleanup_qp_table(dev); 428 + mlx5_cleanup_cq_table(dev); 429 + mlx5_stop_eqs(dev); 430 + mlx5_free_uuars(dev, &priv->uuari); 431 + mlx5_eq_cleanup(dev); 432 + mlx5_disable_msix(dev); 433 + mlx5_stop_health_poll(dev); 434 + mlx5_cmd_teardown_hca(dev); 435 + mlx5_pagealloc_stop(dev); 436 + mlx5_reclaim_startup_pages(dev); 437 + mlx5_pagealloc_cleanup(dev); 438 + mlx5_cmd_cleanup(dev); 439 + iounmap(dev->iseg); 440 + pci_clear_master(dev->pdev); 441 + release_bar(dev->pdev); 442 + pci_disable_device(dev->pdev); 443 + debugfs_remove(priv->dbg_root); 444 + } 445 + EXPORT_SYMBOL(mlx5_dev_cleanup); 446 + 447 + static int __init init(void) 448 + { 449 + int err; 450 + 451 + mlx5_register_debugfs(); 452 + mlx5_core_wq = create_singlethread_workqueue("mlx5_core_wq"); 453 + if (!mlx5_core_wq) { 454 + err = -ENOMEM; 455 + goto err_debug; 456 + } 457 + mlx5_health_init(); 458 + 459 + return 0; 460 + 461 + mlx5_health_cleanup(); 462 + err_debug: 463 + mlx5_unregister_debugfs(); 464 + return err; 465 + } 466 + 467 + static void __exit cleanup(void) 468 + { 469 + mlx5_health_cleanup(); 470 + destroy_workqueue(mlx5_core_wq); 471 + mlx5_unregister_debugfs(); 472 + } 473 + 474 + module_init(init); 475 + module_exit(cleanup);
+106
drivers/net/ethernet/mellanox/mlx5/core/mcg.c
··· 1 + /* 2 + * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved. 3 + * 4 + * This software is available to you under a choice of one of two 5 + * licenses. You may choose to be licensed under the terms of the GNU 6 + * General Public License (GPL) Version 2, available from the file 7 + * COPYING in the main directory of this source tree, or the 8 + * OpenIB.org BSD license below: 9 + * 10 + * Redistribution and use in source and binary forms, with or 11 + * without modification, are permitted provided that the following 12 + * conditions are met: 13 + * 14 + * - Redistributions of source code must retain the above 15 + * copyright notice, this list of conditions and the following 16 + * disclaimer. 17 + * 18 + * - Redistributions in binary form must reproduce the above 19 + * copyright notice, this list of conditions and the following 20 + * disclaimer in the documentation and/or other materials 21 + * 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 OF 25 + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26 + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 27 + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 28 + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29 + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30 + * SOFTWARE. 31 + */ 32 + 33 + #include <linux/kernel.h> 34 + #include <linux/module.h> 35 + #include <linux/mlx5/driver.h> 36 + #include <linux/mlx5/cmd.h> 37 + #include <rdma/ib_verbs.h> 38 + #include "mlx5_core.h" 39 + 40 + struct mlx5_attach_mcg_mbox_in { 41 + struct mlx5_inbox_hdr hdr; 42 + __be32 qpn; 43 + __be32 rsvd; 44 + u8 gid[16]; 45 + }; 46 + 47 + struct mlx5_attach_mcg_mbox_out { 48 + struct mlx5_outbox_hdr hdr; 49 + u8 rsvf[8]; 50 + }; 51 + 52 + struct mlx5_detach_mcg_mbox_in { 53 + struct mlx5_inbox_hdr hdr; 54 + __be32 qpn; 55 + __be32 rsvd; 56 + u8 gid[16]; 57 + }; 58 + 59 + struct mlx5_detach_mcg_mbox_out { 60 + struct mlx5_outbox_hdr hdr; 61 + u8 rsvf[8]; 62 + }; 63 + 64 + int mlx5_core_attach_mcg(struct mlx5_core_dev *dev, union ib_gid *mgid, u32 qpn) 65 + { 66 + struct mlx5_attach_mcg_mbox_in in; 67 + struct mlx5_attach_mcg_mbox_out out; 68 + int err; 69 + 70 + memset(&in, 0, sizeof(in)); 71 + memset(&out, 0, sizeof(out)); 72 + in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_ATTACH_TO_MCG); 73 + memcpy(in.gid, mgid, sizeof(*mgid)); 74 + in.qpn = cpu_to_be32(qpn); 75 + err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out)); 76 + if (err) 77 + return err; 78 + 79 + if (out.hdr.status) 80 + err = mlx5_cmd_status_to_err(&out.hdr); 81 + 82 + return err; 83 + } 84 + EXPORT_SYMBOL(mlx5_core_attach_mcg); 85 + 86 + int mlx5_core_detach_mcg(struct mlx5_core_dev *dev, union ib_gid *mgid, u32 qpn) 87 + { 88 + struct mlx5_detach_mcg_mbox_in in; 89 + struct mlx5_detach_mcg_mbox_out out; 90 + int err; 91 + 92 + memset(&in, 0, sizeof(in)); 93 + memset(&out, 0, sizeof(out)); 94 + in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_DETACH_FROM_MCG); 95 + memcpy(in.gid, mgid, sizeof(*mgid)); 96 + in.qpn = cpu_to_be32(qpn); 97 + err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out)); 98 + if (err) 99 + return err; 100 + 101 + if (out.hdr.status) 102 + err = mlx5_cmd_status_to_err(&out.hdr); 103 + 104 + return err; 105 + } 106 + EXPORT_SYMBOL(mlx5_core_detach_mcg);
+73
drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h
··· 1 + /* 2 + * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved. 3 + * 4 + * This software is available to you under a choice of one of two 5 + * licenses. You may choose to be licensed under the terms of the GNU 6 + * General Public License (GPL) Version 2, available from the file 7 + * COPYING in the main directory of this source tree, or the 8 + * OpenIB.org BSD license below: 9 + * 10 + * Redistribution and use in source and binary forms, with or 11 + * without modification, are permitted provided that the following 12 + * conditions are met: 13 + * 14 + * - Redistributions of source code must retain the above 15 + * copyright notice, this list of conditions and the following 16 + * disclaimer. 17 + * 18 + * - Redistributions in binary form must reproduce the above 19 + * copyright notice, this list of conditions and the following 20 + * disclaimer in the documentation and/or other materials 21 + * 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 OF 25 + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26 + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 27 + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 28 + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29 + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30 + * SOFTWARE. 31 + */ 32 + 33 + #ifndef __MLX5_CORE_H__ 34 + #define __MLX5_CORE_H__ 35 + 36 + #include <linux/types.h> 37 + #include <linux/kernel.h> 38 + #include <linux/sched.h> 39 + 40 + extern int mlx5_core_debug_mask; 41 + 42 + #define mlx5_core_dbg(dev, format, arg...) \ 43 + pr_debug("%s:%s:%d:(pid %d): " format, (dev)->priv.name, __func__, __LINE__, \ 44 + current->pid, ##arg) 45 + 46 + #define mlx5_core_dbg_mask(dev, mask, format, arg...) \ 47 + do { \ 48 + if ((mask) & mlx5_core_debug_mask) \ 49 + pr_debug("%s:%s:%d:(pid %d): " format, (dev)->priv.name, \ 50 + __func__, __LINE__, current->pid, ##arg); \ 51 + } while (0) 52 + 53 + #define mlx5_core_err(dev, format, arg...) \ 54 + pr_err("%s:%s:%d:(pid %d): " format, (dev)->priv.name, __func__, __LINE__, \ 55 + current->pid, ##arg) 56 + 57 + #define mlx5_core_warn(dev, format, arg...) \ 58 + pr_warn("%s:%s:%d:(pid %d): " format, (dev)->priv.name, __func__, __LINE__, \ 59 + current->pid, ##arg) 60 + 61 + enum { 62 + MLX5_CMD_DATA, /* print command payload only */ 63 + MLX5_CMD_TIME, /* print command execution time */ 64 + }; 65 + 66 + 67 + int mlx5_cmd_query_hca_cap(struct mlx5_core_dev *dev, 68 + struct mlx5_caps *caps); 69 + int mlx5_cmd_query_adapter(struct mlx5_core_dev *dev); 70 + int mlx5_cmd_init_hca(struct mlx5_core_dev *dev); 71 + int mlx5_cmd_teardown_hca(struct mlx5_core_dev *dev); 72 + 73 + #endif /* __MLX5_CORE_H__ */
+136
drivers/net/ethernet/mellanox/mlx5/core/mr.c
··· 1 + /* 2 + * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved. 3 + * 4 + * This software is available to you under a choice of one of two 5 + * licenses. You may choose to be licensed under the terms of the GNU 6 + * General Public License (GPL) Version 2, available from the file 7 + * COPYING in the main directory of this source tree, or the 8 + * OpenIB.org BSD license below: 9 + * 10 + * Redistribution and use in source and binary forms, with or 11 + * without modification, are permitted provided that the following 12 + * conditions are met: 13 + * 14 + * - Redistributions of source code must retain the above 15 + * copyright notice, this list of conditions and the following 16 + * disclaimer. 17 + * 18 + * - Redistributions in binary form must reproduce the above 19 + * copyright notice, this list of conditions and the following 20 + * disclaimer in the documentation and/or other materials 21 + * 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 OF 25 + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26 + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 27 + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 28 + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29 + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30 + * SOFTWARE. 31 + */ 32 + 33 + #include <linux/kernel.h> 34 + #include <linux/module.h> 35 + #include <linux/mlx5/driver.h> 36 + #include <linux/mlx5/cmd.h> 37 + #include "mlx5_core.h" 38 + 39 + int mlx5_core_create_mkey(struct mlx5_core_dev *dev, struct mlx5_core_mr *mr, 40 + struct mlx5_create_mkey_mbox_in *in, int inlen) 41 + { 42 + struct mlx5_create_mkey_mbox_out out; 43 + int err; 44 + u8 key; 45 + 46 + memset(&out, 0, sizeof(out)); 47 + spin_lock(&dev->priv.mkey_lock); 48 + key = dev->priv.mkey_key++; 49 + spin_unlock(&dev->priv.mkey_lock); 50 + in->seg.qpn_mkey7_0 |= cpu_to_be32(key); 51 + in->hdr.opcode = cpu_to_be16(MLX5_CMD_OP_CREATE_MKEY); 52 + err = mlx5_cmd_exec(dev, in, inlen, &out, sizeof(out)); 53 + if (err) { 54 + mlx5_core_dbg(dev, "cmd exec faile %d\n", err); 55 + return err; 56 + } 57 + 58 + if (out.hdr.status) { 59 + mlx5_core_dbg(dev, "status %d\n", out.hdr.status); 60 + return mlx5_cmd_status_to_err(&out.hdr); 61 + } 62 + 63 + mr->key = mlx5_idx_to_mkey(be32_to_cpu(out.mkey) & 0xffffff) | key; 64 + mlx5_core_dbg(dev, "out 0x%x, key 0x%x, mkey 0x%x\n", be32_to_cpu(out.mkey), key, mr->key); 65 + 66 + return err; 67 + } 68 + EXPORT_SYMBOL(mlx5_core_create_mkey); 69 + 70 + int mlx5_core_destroy_mkey(struct mlx5_core_dev *dev, struct mlx5_core_mr *mr) 71 + { 72 + struct mlx5_destroy_mkey_mbox_in in; 73 + struct mlx5_destroy_mkey_mbox_out out; 74 + int err; 75 + 76 + memset(&in, 0, sizeof(in)); 77 + memset(&out, 0, sizeof(out)); 78 + 79 + in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_DESTROY_MKEY); 80 + in.mkey = cpu_to_be32(mlx5_mkey_to_idx(mr->key)); 81 + err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out)); 82 + if (err) 83 + return err; 84 + 85 + if (out.hdr.status) 86 + return mlx5_cmd_status_to_err(&out.hdr); 87 + 88 + return err; 89 + } 90 + EXPORT_SYMBOL(mlx5_core_destroy_mkey); 91 + 92 + int mlx5_core_query_mkey(struct mlx5_core_dev *dev, struct mlx5_core_mr *mr, 93 + struct mlx5_query_mkey_mbox_out *out, int outlen) 94 + { 95 + struct mlx5_destroy_mkey_mbox_in in; 96 + int err; 97 + 98 + memset(&in, 0, sizeof(in)); 99 + memset(out, 0, outlen); 100 + 101 + in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_QUERY_MKEY); 102 + in.mkey = cpu_to_be32(mlx5_mkey_to_idx(mr->key)); 103 + err = mlx5_cmd_exec(dev, &in, sizeof(in), out, outlen); 104 + if (err) 105 + return err; 106 + 107 + if (out->hdr.status) 108 + return mlx5_cmd_status_to_err(&out->hdr); 109 + 110 + return err; 111 + } 112 + EXPORT_SYMBOL(mlx5_core_query_mkey); 113 + 114 + int mlx5_core_dump_fill_mkey(struct mlx5_core_dev *dev, struct mlx5_core_mr *mr, 115 + u32 *mkey) 116 + { 117 + struct mlx5_query_special_ctxs_mbox_in in; 118 + struct mlx5_query_special_ctxs_mbox_out out; 119 + int err; 120 + 121 + memset(&in, 0, sizeof(in)); 122 + memset(&out, 0, sizeof(out)); 123 + 124 + in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_QUERY_SPECIAL_CONTEXTS); 125 + err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out)); 126 + if (err) 127 + return err; 128 + 129 + if (out.hdr.status) 130 + return mlx5_cmd_status_to_err(&out.hdr); 131 + 132 + *mkey = be32_to_cpu(out.dump_fill_mkey); 133 + 134 + return err; 135 + } 136 + EXPORT_SYMBOL(mlx5_core_dump_fill_mkey);
+435
drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c
··· 1 + /* 2 + * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved. 3 + * 4 + * This software is available to you under a choice of one of two 5 + * licenses. You may choose to be licensed under the terms of the GNU 6 + * General Public License (GPL) Version 2, available from the file 7 + * COPYING in the main directory of this source tree, or the 8 + * OpenIB.org BSD license below: 9 + * 10 + * Redistribution and use in source and binary forms, with or 11 + * without modification, are permitted provided that the following 12 + * conditions are met: 13 + * 14 + * - Redistributions of source code must retain the above 15 + * copyright notice, this list of conditions and the following 16 + * disclaimer. 17 + * 18 + * - Redistributions in binary form must reproduce the above 19 + * copyright notice, this list of conditions and the following 20 + * disclaimer in the documentation and/or other materials 21 + * 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 OF 25 + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26 + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 27 + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 28 + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29 + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30 + * SOFTWARE. 31 + */ 32 + 33 + #include <asm-generic/kmap_types.h> 34 + #include <linux/kernel.h> 35 + #include <linux/module.h> 36 + #include <linux/mlx5/driver.h> 37 + #include <linux/mlx5/cmd.h> 38 + #include "mlx5_core.h" 39 + 40 + enum { 41 + MLX5_PAGES_CANT_GIVE = 0, 42 + MLX5_PAGES_GIVE = 1, 43 + MLX5_PAGES_TAKE = 2 44 + }; 45 + 46 + struct mlx5_pages_req { 47 + struct mlx5_core_dev *dev; 48 + u32 func_id; 49 + s16 npages; 50 + struct work_struct work; 51 + }; 52 + 53 + struct fw_page { 54 + struct rb_node rb_node; 55 + u64 addr; 56 + struct page *page; 57 + u16 func_id; 58 + }; 59 + 60 + struct mlx5_query_pages_inbox { 61 + struct mlx5_inbox_hdr hdr; 62 + u8 rsvd[8]; 63 + }; 64 + 65 + struct mlx5_query_pages_outbox { 66 + struct mlx5_outbox_hdr hdr; 67 + u8 reserved[2]; 68 + __be16 func_id; 69 + __be16 init_pages; 70 + __be16 num_pages; 71 + }; 72 + 73 + struct mlx5_manage_pages_inbox { 74 + struct mlx5_inbox_hdr hdr; 75 + __be16 rsvd0; 76 + __be16 func_id; 77 + __be16 rsvd1; 78 + __be16 num_entries; 79 + u8 rsvd2[16]; 80 + __be64 pas[0]; 81 + }; 82 + 83 + struct mlx5_manage_pages_outbox { 84 + struct mlx5_outbox_hdr hdr; 85 + u8 rsvd0[2]; 86 + __be16 num_entries; 87 + u8 rsvd1[20]; 88 + __be64 pas[0]; 89 + }; 90 + 91 + static int insert_page(struct mlx5_core_dev *dev, u64 addr, struct page *page, u16 func_id) 92 + { 93 + struct rb_root *root = &dev->priv.page_root; 94 + struct rb_node **new = &root->rb_node; 95 + struct rb_node *parent = NULL; 96 + struct fw_page *nfp; 97 + struct fw_page *tfp; 98 + 99 + while (*new) { 100 + parent = *new; 101 + tfp = rb_entry(parent, struct fw_page, rb_node); 102 + if (tfp->addr < addr) 103 + new = &parent->rb_left; 104 + else if (tfp->addr > addr) 105 + new = &parent->rb_right; 106 + else 107 + return -EEXIST; 108 + } 109 + 110 + nfp = kmalloc(sizeof(*nfp), GFP_KERNEL); 111 + if (!nfp) 112 + return -ENOMEM; 113 + 114 + nfp->addr = addr; 115 + nfp->page = page; 116 + nfp->func_id = func_id; 117 + 118 + rb_link_node(&nfp->rb_node, parent, new); 119 + rb_insert_color(&nfp->rb_node, root); 120 + 121 + return 0; 122 + } 123 + 124 + static struct page *remove_page(struct mlx5_core_dev *dev, u64 addr) 125 + { 126 + struct rb_root *root = &dev->priv.page_root; 127 + struct rb_node *tmp = root->rb_node; 128 + struct page *result = NULL; 129 + struct fw_page *tfp; 130 + 131 + while (tmp) { 132 + tfp = rb_entry(tmp, struct fw_page, rb_node); 133 + if (tfp->addr < addr) { 134 + tmp = tmp->rb_left; 135 + } else if (tfp->addr > addr) { 136 + tmp = tmp->rb_right; 137 + } else { 138 + rb_erase(&tfp->rb_node, root); 139 + result = tfp->page; 140 + kfree(tfp); 141 + break; 142 + } 143 + } 144 + 145 + return result; 146 + } 147 + 148 + static int mlx5_cmd_query_pages(struct mlx5_core_dev *dev, u16 *func_id, 149 + s16 *pages, s16 *init_pages) 150 + { 151 + struct mlx5_query_pages_inbox in; 152 + struct mlx5_query_pages_outbox out; 153 + int err; 154 + 155 + memset(&in, 0, sizeof(in)); 156 + memset(&out, 0, sizeof(out)); 157 + in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_QUERY_PAGES); 158 + err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out)); 159 + if (err) 160 + return err; 161 + 162 + if (out.hdr.status) 163 + return mlx5_cmd_status_to_err(&out.hdr); 164 + 165 + if (pages) 166 + *pages = be16_to_cpu(out.num_pages); 167 + if (init_pages) 168 + *init_pages = be16_to_cpu(out.init_pages); 169 + *func_id = be16_to_cpu(out.func_id); 170 + 171 + return err; 172 + } 173 + 174 + static int give_pages(struct mlx5_core_dev *dev, u16 func_id, int npages, 175 + int notify_fail) 176 + { 177 + struct mlx5_manage_pages_inbox *in; 178 + struct mlx5_manage_pages_outbox out; 179 + struct page *page; 180 + int inlen; 181 + u64 addr; 182 + int err; 183 + int i; 184 + 185 + inlen = sizeof(*in) + npages * sizeof(in->pas[0]); 186 + in = mlx5_vzalloc(inlen); 187 + if (!in) { 188 + mlx5_core_warn(dev, "vzalloc failed %d\n", inlen); 189 + return -ENOMEM; 190 + } 191 + memset(&out, 0, sizeof(out)); 192 + 193 + for (i = 0; i < npages; i++) { 194 + page = alloc_page(GFP_HIGHUSER); 195 + if (!page) { 196 + err = -ENOMEM; 197 + mlx5_core_warn(dev, "failed to allocate page\n"); 198 + goto out_alloc; 199 + } 200 + addr = dma_map_page(&dev->pdev->dev, page, 0, 201 + PAGE_SIZE, DMA_BIDIRECTIONAL); 202 + if (dma_mapping_error(&dev->pdev->dev, addr)) { 203 + mlx5_core_warn(dev, "failed dma mapping page\n"); 204 + __free_page(page); 205 + err = -ENOMEM; 206 + goto out_alloc; 207 + } 208 + err = insert_page(dev, addr, page, func_id); 209 + if (err) { 210 + mlx5_core_err(dev, "failed to track allocated page\n"); 211 + dma_unmap_page(&dev->pdev->dev, addr, PAGE_SIZE, DMA_BIDIRECTIONAL); 212 + __free_page(page); 213 + err = -ENOMEM; 214 + goto out_alloc; 215 + } 216 + in->pas[i] = cpu_to_be64(addr); 217 + } 218 + 219 + in->hdr.opcode = cpu_to_be16(MLX5_CMD_OP_MANAGE_PAGES); 220 + in->hdr.opmod = cpu_to_be16(MLX5_PAGES_GIVE); 221 + in->func_id = cpu_to_be16(func_id); 222 + in->num_entries = cpu_to_be16(npages); 223 + err = mlx5_cmd_exec(dev, in, inlen, &out, sizeof(out)); 224 + mlx5_core_dbg(dev, "err %d\n", err); 225 + if (err) { 226 + mlx5_core_warn(dev, "func_id 0x%x, npages %d, err %d\n", func_id, npages, err); 227 + goto out_alloc; 228 + } 229 + dev->priv.fw_pages += npages; 230 + 231 + if (out.hdr.status) { 232 + err = mlx5_cmd_status_to_err(&out.hdr); 233 + if (err) { 234 + mlx5_core_warn(dev, "func_id 0x%x, npages %d, status %d\n", func_id, npages, out.hdr.status); 235 + goto out_alloc; 236 + } 237 + } 238 + 239 + mlx5_core_dbg(dev, "err %d\n", err); 240 + 241 + goto out_free; 242 + 243 + out_alloc: 244 + if (notify_fail) { 245 + memset(in, 0, inlen); 246 + memset(&out, 0, sizeof(out)); 247 + in->hdr.opcode = cpu_to_be16(MLX5_CMD_OP_MANAGE_PAGES); 248 + in->hdr.opmod = cpu_to_be16(MLX5_PAGES_CANT_GIVE); 249 + if (mlx5_cmd_exec(dev, in, sizeof(*in), &out, sizeof(out))) 250 + mlx5_core_warn(dev, "\n"); 251 + } 252 + for (i--; i >= 0; i--) { 253 + addr = be64_to_cpu(in->pas[i]); 254 + page = remove_page(dev, addr); 255 + if (!page) { 256 + mlx5_core_err(dev, "BUG: can't remove page at addr 0x%llx\n", 257 + addr); 258 + continue; 259 + } 260 + dma_unmap_page(&dev->pdev->dev, addr, PAGE_SIZE, DMA_BIDIRECTIONAL); 261 + __free_page(page); 262 + } 263 + 264 + out_free: 265 + mlx5_vfree(in); 266 + return err; 267 + } 268 + 269 + static int reclaim_pages(struct mlx5_core_dev *dev, u32 func_id, int npages, 270 + int *nclaimed) 271 + { 272 + struct mlx5_manage_pages_inbox in; 273 + struct mlx5_manage_pages_outbox *out; 274 + struct page *page; 275 + int num_claimed; 276 + int outlen; 277 + u64 addr; 278 + int err; 279 + int i; 280 + 281 + memset(&in, 0, sizeof(in)); 282 + outlen = sizeof(*out) + npages * sizeof(out->pas[0]); 283 + out = mlx5_vzalloc(outlen); 284 + if (!out) 285 + return -ENOMEM; 286 + 287 + in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_MANAGE_PAGES); 288 + in.hdr.opmod = cpu_to_be16(MLX5_PAGES_TAKE); 289 + in.func_id = cpu_to_be16(func_id); 290 + in.num_entries = cpu_to_be16(npages); 291 + mlx5_core_dbg(dev, "npages %d, outlen %d\n", npages, outlen); 292 + err = mlx5_cmd_exec(dev, &in, sizeof(in), out, outlen); 293 + if (err) { 294 + mlx5_core_err(dev, "failed recliaming pages\n"); 295 + goto out_free; 296 + } 297 + dev->priv.fw_pages -= npages; 298 + 299 + if (out->hdr.status) { 300 + err = mlx5_cmd_status_to_err(&out->hdr); 301 + goto out_free; 302 + } 303 + 304 + num_claimed = be16_to_cpu(out->num_entries); 305 + if (nclaimed) 306 + *nclaimed = num_claimed; 307 + 308 + for (i = 0; i < num_claimed; i++) { 309 + addr = be64_to_cpu(out->pas[i]); 310 + page = remove_page(dev, addr); 311 + if (!page) { 312 + mlx5_core_warn(dev, "FW reported unknown DMA address 0x%llx\n", addr); 313 + } else { 314 + dma_unmap_page(&dev->pdev->dev, addr, PAGE_SIZE, DMA_BIDIRECTIONAL); 315 + __free_page(page); 316 + } 317 + } 318 + 319 + out_free: 320 + mlx5_vfree(out); 321 + return err; 322 + } 323 + 324 + static void pages_work_handler(struct work_struct *work) 325 + { 326 + struct mlx5_pages_req *req = container_of(work, struct mlx5_pages_req, work); 327 + struct mlx5_core_dev *dev = req->dev; 328 + int err = 0; 329 + 330 + if (req->npages < 0) 331 + err = reclaim_pages(dev, req->func_id, -1 * req->npages, NULL); 332 + else if (req->npages > 0) 333 + err = give_pages(dev, req->func_id, req->npages, 1); 334 + 335 + if (err) 336 + mlx5_core_warn(dev, "%s fail %d\n", req->npages < 0 ? 337 + "reclaim" : "give", err); 338 + 339 + kfree(req); 340 + } 341 + 342 + void mlx5_core_req_pages_handler(struct mlx5_core_dev *dev, u16 func_id, 343 + s16 npages) 344 + { 345 + struct mlx5_pages_req *req; 346 + 347 + req = kzalloc(sizeof(*req), GFP_ATOMIC); 348 + if (!req) { 349 + mlx5_core_warn(dev, "failed to allocate pages request\n"); 350 + return; 351 + } 352 + 353 + req->dev = dev; 354 + req->func_id = func_id; 355 + req->npages = npages; 356 + INIT_WORK(&req->work, pages_work_handler); 357 + queue_work(dev->priv.pg_wq, &req->work); 358 + } 359 + 360 + int mlx5_satisfy_startup_pages(struct mlx5_core_dev *dev) 361 + { 362 + s16 uninitialized_var(init_pages); 363 + u16 uninitialized_var(func_id); 364 + int err; 365 + 366 + err = mlx5_cmd_query_pages(dev, &func_id, NULL, &init_pages); 367 + if (err) 368 + return err; 369 + 370 + mlx5_core_dbg(dev, "requested %d init pages for func_id 0x%x\n", init_pages, func_id); 371 + 372 + return give_pages(dev, func_id, init_pages, 0); 373 + } 374 + 375 + static int optimal_reclaimed_pages(void) 376 + { 377 + struct mlx5_cmd_prot_block *block; 378 + struct mlx5_cmd_layout *lay; 379 + int ret; 380 + 381 + ret = (sizeof(lay->in) + sizeof(block->data) - 382 + sizeof(struct mlx5_manage_pages_outbox)) / 8; 383 + 384 + return ret; 385 + } 386 + 387 + int mlx5_reclaim_startup_pages(struct mlx5_core_dev *dev) 388 + { 389 + unsigned long end = jiffies + msecs_to_jiffies(5000); 390 + struct fw_page *fwp; 391 + struct rb_node *p; 392 + int err; 393 + 394 + do { 395 + p = rb_first(&dev->priv.page_root); 396 + if (p) { 397 + fwp = rb_entry(p, struct fw_page, rb_node); 398 + err = reclaim_pages(dev, fwp->func_id, optimal_reclaimed_pages(), NULL); 399 + if (err) { 400 + mlx5_core_warn(dev, "failed reclaiming pages (%d)\n", err); 401 + return err; 402 + } 403 + } 404 + if (time_after(jiffies, end)) { 405 + mlx5_core_warn(dev, "FW did not return all pages. giving up...\n"); 406 + break; 407 + } 408 + } while (p); 409 + 410 + return 0; 411 + } 412 + 413 + void mlx5_pagealloc_init(struct mlx5_core_dev *dev) 414 + { 415 + dev->priv.page_root = RB_ROOT; 416 + } 417 + 418 + void mlx5_pagealloc_cleanup(struct mlx5_core_dev *dev) 419 + { 420 + /* nothing */ 421 + } 422 + 423 + int mlx5_pagealloc_start(struct mlx5_core_dev *dev) 424 + { 425 + dev->priv.pg_wq = create_singlethread_workqueue("mlx5_page_allocator"); 426 + if (!dev->priv.pg_wq) 427 + return -ENOMEM; 428 + 429 + return 0; 430 + } 431 + 432 + void mlx5_pagealloc_stop(struct mlx5_core_dev *dev) 433 + { 434 + destroy_workqueue(dev->priv.pg_wq); 435 + }
+101
drivers/net/ethernet/mellanox/mlx5/core/pd.c
··· 1 + /* 2 + * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved. 3 + * 4 + * This software is available to you under a choice of one of two 5 + * licenses. You may choose to be licensed under the terms of the GNU 6 + * General Public License (GPL) Version 2, available from the file 7 + * COPYING in the main directory of this source tree, or the 8 + * OpenIB.org BSD license below: 9 + * 10 + * Redistribution and use in source and binary forms, with or 11 + * without modification, are permitted provided that the following 12 + * conditions are met: 13 + * 14 + * - Redistributions of source code must retain the above 15 + * copyright notice, this list of conditions and the following 16 + * disclaimer. 17 + * 18 + * - Redistributions in binary form must reproduce the above 19 + * copyright notice, this list of conditions and the following 20 + * disclaimer in the documentation and/or other materials 21 + * 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 OF 25 + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26 + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 27 + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 28 + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29 + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30 + * SOFTWARE. 31 + */ 32 + 33 + #include <linux/kernel.h> 34 + #include <linux/module.h> 35 + #include <linux/mlx5/driver.h> 36 + #include <linux/mlx5/cmd.h> 37 + #include "mlx5_core.h" 38 + 39 + struct mlx5_alloc_pd_mbox_in { 40 + struct mlx5_inbox_hdr hdr; 41 + u8 rsvd[8]; 42 + }; 43 + 44 + struct mlx5_alloc_pd_mbox_out { 45 + struct mlx5_outbox_hdr hdr; 46 + __be32 pdn; 47 + u8 rsvd[4]; 48 + }; 49 + 50 + struct mlx5_dealloc_pd_mbox_in { 51 + struct mlx5_inbox_hdr hdr; 52 + __be32 pdn; 53 + u8 rsvd[4]; 54 + }; 55 + 56 + struct mlx5_dealloc_pd_mbox_out { 57 + struct mlx5_outbox_hdr hdr; 58 + u8 rsvd[8]; 59 + }; 60 + 61 + int mlx5_core_alloc_pd(struct mlx5_core_dev *dev, u32 *pdn) 62 + { 63 + struct mlx5_alloc_pd_mbox_in in; 64 + struct mlx5_alloc_pd_mbox_out out; 65 + int err; 66 + 67 + memset(&in, 0, sizeof(in)); 68 + memset(&out, 0, sizeof(out)); 69 + in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_ALLOC_PD); 70 + err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out)); 71 + if (err) 72 + return err; 73 + 74 + if (out.hdr.status) 75 + return mlx5_cmd_status_to_err(&out.hdr); 76 + 77 + *pdn = be32_to_cpu(out.pdn) & 0xffffff; 78 + return err; 79 + } 80 + EXPORT_SYMBOL(mlx5_core_alloc_pd); 81 + 82 + int mlx5_core_dealloc_pd(struct mlx5_core_dev *dev, u32 pdn) 83 + { 84 + struct mlx5_dealloc_pd_mbox_in in; 85 + struct mlx5_dealloc_pd_mbox_out out; 86 + int err; 87 + 88 + memset(&in, 0, sizeof(in)); 89 + memset(&out, 0, sizeof(out)); 90 + in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_DEALLOC_PD); 91 + in.pdn = cpu_to_be32(pdn); 92 + err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out)); 93 + if (err) 94 + return err; 95 + 96 + if (out.hdr.status) 97 + return mlx5_cmd_status_to_err(&out.hdr); 98 + 99 + return err; 100 + } 101 + EXPORT_SYMBOL(mlx5_core_dealloc_pd);
+104
drivers/net/ethernet/mellanox/mlx5/core/port.c
··· 1 + /* 2 + * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved. 3 + * 4 + * This software is available to you under a choice of one of two 5 + * licenses. You may choose to be licensed under the terms of the GNU 6 + * General Public License (GPL) Version 2, available from the file 7 + * COPYING in the main directory of this source tree, or the 8 + * OpenIB.org BSD license below: 9 + * 10 + * Redistribution and use in source and binary forms, with or 11 + * without modification, are permitted provided that the following 12 + * conditions are met: 13 + * 14 + * - Redistributions of source code must retain the above 15 + * copyright notice, this list of conditions and the following 16 + * disclaimer. 17 + * 18 + * - Redistributions in binary form must reproduce the above 19 + * copyright notice, this list of conditions and the following 20 + * disclaimer in the documentation and/or other materials 21 + * 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 OF 25 + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26 + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 27 + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 28 + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29 + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30 + * SOFTWARE. 31 + */ 32 + 33 + #include <linux/module.h> 34 + #include <linux/mlx5/driver.h> 35 + #include <linux/mlx5/cmd.h> 36 + #include "mlx5_core.h" 37 + 38 + int mlx5_core_access_reg(struct mlx5_core_dev *dev, void *data_in, 39 + int size_in, void *data_out, int size_out, 40 + u16 reg_num, int arg, int write) 41 + { 42 + struct mlx5_access_reg_mbox_in *in = NULL; 43 + struct mlx5_access_reg_mbox_out *out = NULL; 44 + int err = -ENOMEM; 45 + 46 + in = mlx5_vzalloc(sizeof(*in) + size_in); 47 + if (!in) 48 + return -ENOMEM; 49 + 50 + out = mlx5_vzalloc(sizeof(*out) + size_out); 51 + if (!out) 52 + goto ex1; 53 + 54 + memcpy(in->data, data_in, size_in); 55 + in->hdr.opcode = cpu_to_be16(MLX5_CMD_OP_ACCESS_REG); 56 + in->hdr.opmod = cpu_to_be16(!write); 57 + in->arg = cpu_to_be32(arg); 58 + in->register_id = cpu_to_be16(reg_num); 59 + err = mlx5_cmd_exec(dev, in, sizeof(*in) + size_in, out, 60 + sizeof(out) + size_out); 61 + if (err) 62 + goto ex2; 63 + 64 + if (out->hdr.status) 65 + err = mlx5_cmd_status_to_err(&out->hdr); 66 + 67 + if (!err) 68 + memcpy(data_out, out->data, size_out); 69 + 70 + ex2: 71 + mlx5_vfree(out); 72 + ex1: 73 + mlx5_vfree(in); 74 + return err; 75 + } 76 + EXPORT_SYMBOL_GPL(mlx5_core_access_reg); 77 + 78 + 79 + struct mlx5_reg_pcap { 80 + u8 rsvd0; 81 + u8 port_num; 82 + u8 rsvd1[2]; 83 + __be32 caps_127_96; 84 + __be32 caps_95_64; 85 + __be32 caps_63_32; 86 + __be32 caps_31_0; 87 + }; 88 + 89 + int mlx5_set_port_caps(struct mlx5_core_dev *dev, int port_num, u32 caps) 90 + { 91 + struct mlx5_reg_pcap in; 92 + struct mlx5_reg_pcap out; 93 + int err; 94 + 95 + memset(&in, 0, sizeof(in)); 96 + in.caps_127_96 = cpu_to_be32(caps); 97 + in.port_num = port_num; 98 + 99 + err = mlx5_core_access_reg(dev, &in, sizeof(in), &out, 100 + sizeof(out), MLX5_REG_PCAP, 0, 1); 101 + 102 + return err; 103 + } 104 + EXPORT_SYMBOL_GPL(mlx5_set_port_caps);
+301
drivers/net/ethernet/mellanox/mlx5/core/qp.c
··· 1 + /* 2 + * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved. 3 + * 4 + * This software is available to you under a choice of one of two 5 + * licenses. You may choose to be licensed under the terms of the GNU 6 + * General Public License (GPL) Version 2, available from the file 7 + * COPYING in the main directory of this source tree, or the 8 + * OpenIB.org BSD license below: 9 + * 10 + * Redistribution and use in source and binary forms, with or 11 + * without modification, are permitted provided that the following 12 + * conditions are met: 13 + * 14 + * - Redistributions of source code must retain the above 15 + * copyright notice, this list of conditions and the following 16 + * disclaimer. 17 + * 18 + * - Redistributions in binary form must reproduce the above 19 + * copyright notice, this list of conditions and the following 20 + * disclaimer in the documentation and/or other materials 21 + * 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 OF 25 + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26 + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 27 + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 28 + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29 + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30 + * SOFTWARE. 31 + */ 32 + 33 + 34 + #include <linux/gfp.h> 35 + #include <linux/export.h> 36 + #include <linux/mlx5/cmd.h> 37 + #include <linux/mlx5/qp.h> 38 + #include <linux/mlx5/driver.h> 39 + 40 + #include "mlx5_core.h" 41 + 42 + void mlx5_qp_event(struct mlx5_core_dev *dev, u32 qpn, int event_type) 43 + { 44 + struct mlx5_qp_table *table = &dev->priv.qp_table; 45 + struct mlx5_core_qp *qp; 46 + 47 + spin_lock(&table->lock); 48 + 49 + qp = radix_tree_lookup(&table->tree, qpn); 50 + if (qp) 51 + atomic_inc(&qp->refcount); 52 + 53 + spin_unlock(&table->lock); 54 + 55 + if (!qp) { 56 + mlx5_core_warn(dev, "Async event for bogus QP 0x%x\n", qpn); 57 + return; 58 + } 59 + 60 + qp->event(qp, event_type); 61 + 62 + if (atomic_dec_and_test(&qp->refcount)) 63 + complete(&qp->free); 64 + } 65 + 66 + int mlx5_core_create_qp(struct mlx5_core_dev *dev, 67 + struct mlx5_core_qp *qp, 68 + struct mlx5_create_qp_mbox_in *in, 69 + int inlen) 70 + { 71 + struct mlx5_qp_table *table = &dev->priv.qp_table; 72 + struct mlx5_create_qp_mbox_out out; 73 + struct mlx5_destroy_qp_mbox_in din; 74 + struct mlx5_destroy_qp_mbox_out dout; 75 + int err; 76 + 77 + memset(&dout, 0, sizeof(dout)); 78 + in->hdr.opcode = cpu_to_be16(MLX5_CMD_OP_CREATE_QP); 79 + 80 + err = mlx5_cmd_exec(dev, in, inlen, &out, sizeof(out)); 81 + if (err) { 82 + mlx5_core_warn(dev, "ret %d", err); 83 + return err; 84 + } 85 + 86 + if (out.hdr.status) { 87 + pr_warn("current num of QPs 0x%x\n", atomic_read(&dev->num_qps)); 88 + return mlx5_cmd_status_to_err(&out.hdr); 89 + } 90 + 91 + qp->qpn = be32_to_cpu(out.qpn) & 0xffffff; 92 + mlx5_core_dbg(dev, "qpn = 0x%x\n", qp->qpn); 93 + 94 + spin_lock_irq(&table->lock); 95 + err = radix_tree_insert(&table->tree, qp->qpn, qp); 96 + spin_unlock_irq(&table->lock); 97 + if (err) { 98 + mlx5_core_warn(dev, "err %d", err); 99 + goto err_cmd; 100 + } 101 + 102 + err = mlx5_debug_qp_add(dev, qp); 103 + if (err) 104 + mlx5_core_dbg(dev, "failed adding QP 0x%x to debug file system\n", 105 + qp->qpn); 106 + 107 + qp->pid = current->pid; 108 + atomic_set(&qp->refcount, 1); 109 + atomic_inc(&dev->num_qps); 110 + init_completion(&qp->free); 111 + 112 + return 0; 113 + 114 + err_cmd: 115 + memset(&din, 0, sizeof(din)); 116 + memset(&dout, 0, sizeof(dout)); 117 + din.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_DESTROY_QP); 118 + din.qpn = cpu_to_be32(qp->qpn); 119 + mlx5_cmd_exec(dev, &din, sizeof(din), &out, sizeof(dout)); 120 + 121 + return err; 122 + } 123 + EXPORT_SYMBOL_GPL(mlx5_core_create_qp); 124 + 125 + int mlx5_core_destroy_qp(struct mlx5_core_dev *dev, 126 + struct mlx5_core_qp *qp) 127 + { 128 + struct mlx5_destroy_qp_mbox_in in; 129 + struct mlx5_destroy_qp_mbox_out out; 130 + struct mlx5_qp_table *table = &dev->priv.qp_table; 131 + unsigned long flags; 132 + int err; 133 + 134 + mlx5_debug_qp_remove(dev, qp); 135 + 136 + spin_lock_irqsave(&table->lock, flags); 137 + radix_tree_delete(&table->tree, qp->qpn); 138 + spin_unlock_irqrestore(&table->lock, flags); 139 + 140 + if (atomic_dec_and_test(&qp->refcount)) 141 + complete(&qp->free); 142 + wait_for_completion(&qp->free); 143 + 144 + memset(&in, 0, sizeof(in)); 145 + memset(&out, 0, sizeof(out)); 146 + in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_DESTROY_QP); 147 + in.qpn = cpu_to_be32(qp->qpn); 148 + err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out)); 149 + if (err) 150 + return err; 151 + 152 + if (out.hdr.status) 153 + return mlx5_cmd_status_to_err(&out.hdr); 154 + 155 + atomic_dec(&dev->num_qps); 156 + return 0; 157 + } 158 + EXPORT_SYMBOL_GPL(mlx5_core_destroy_qp); 159 + 160 + int mlx5_core_qp_modify(struct mlx5_core_dev *dev, enum mlx5_qp_state cur_state, 161 + enum mlx5_qp_state new_state, 162 + struct mlx5_modify_qp_mbox_in *in, int sqd_event, 163 + struct mlx5_core_qp *qp) 164 + { 165 + static const u16 optab[MLX5_QP_NUM_STATE][MLX5_QP_NUM_STATE] = { 166 + [MLX5_QP_STATE_RST] = { 167 + [MLX5_QP_STATE_RST] = MLX5_CMD_OP_2RST_QP, 168 + [MLX5_QP_STATE_ERR] = MLX5_CMD_OP_2ERR_QP, 169 + [MLX5_QP_STATE_INIT] = MLX5_CMD_OP_RST2INIT_QP, 170 + }, 171 + [MLX5_QP_STATE_INIT] = { 172 + [MLX5_QP_STATE_RST] = MLX5_CMD_OP_2RST_QP, 173 + [MLX5_QP_STATE_ERR] = MLX5_CMD_OP_2ERR_QP, 174 + [MLX5_QP_STATE_INIT] = MLX5_CMD_OP_INIT2INIT_QP, 175 + [MLX5_QP_STATE_RTR] = MLX5_CMD_OP_INIT2RTR_QP, 176 + }, 177 + [MLX5_QP_STATE_RTR] = { 178 + [MLX5_QP_STATE_RST] = MLX5_CMD_OP_2RST_QP, 179 + [MLX5_QP_STATE_ERR] = MLX5_CMD_OP_2ERR_QP, 180 + [MLX5_QP_STATE_RTS] = MLX5_CMD_OP_RTR2RTS_QP, 181 + }, 182 + [MLX5_QP_STATE_RTS] = { 183 + [MLX5_QP_STATE_RST] = MLX5_CMD_OP_2RST_QP, 184 + [MLX5_QP_STATE_ERR] = MLX5_CMD_OP_2ERR_QP, 185 + [MLX5_QP_STATE_RTS] = MLX5_CMD_OP_RTS2RTS_QP, 186 + [MLX5_QP_STATE_SQD] = MLX5_CMD_OP_RTS2SQD_QP, 187 + }, 188 + [MLX5_QP_STATE_SQD] = { 189 + [MLX5_QP_STATE_RST] = MLX5_CMD_OP_2RST_QP, 190 + [MLX5_QP_STATE_ERR] = MLX5_CMD_OP_2ERR_QP, 191 + [MLX5_QP_STATE_RTS] = MLX5_CMD_OP_SQD2RTS_QP, 192 + [MLX5_QP_STATE_SQD] = MLX5_CMD_OP_SQD2SQD_QP, 193 + }, 194 + [MLX5_QP_STATE_SQER] = { 195 + [MLX5_QP_STATE_RST] = MLX5_CMD_OP_2RST_QP, 196 + [MLX5_QP_STATE_ERR] = MLX5_CMD_OP_2ERR_QP, 197 + [MLX5_QP_STATE_RTS] = MLX5_CMD_OP_SQERR2RTS_QP, 198 + }, 199 + [MLX5_QP_STATE_ERR] = { 200 + [MLX5_QP_STATE_RST] = MLX5_CMD_OP_2RST_QP, 201 + [MLX5_QP_STATE_ERR] = MLX5_CMD_OP_2ERR_QP, 202 + } 203 + }; 204 + 205 + struct mlx5_modify_qp_mbox_out out; 206 + int err = 0; 207 + u16 op; 208 + 209 + if (cur_state >= MLX5_QP_NUM_STATE || new_state >= MLX5_QP_NUM_STATE || 210 + !optab[cur_state][new_state]) 211 + return -EINVAL; 212 + 213 + memset(&out, 0, sizeof(out)); 214 + op = optab[cur_state][new_state]; 215 + in->hdr.opcode = cpu_to_be16(op); 216 + in->qpn = cpu_to_be32(qp->qpn); 217 + err = mlx5_cmd_exec(dev, in, sizeof(*in), &out, sizeof(out)); 218 + if (err) 219 + return err; 220 + 221 + return mlx5_cmd_status_to_err(&out.hdr); 222 + } 223 + EXPORT_SYMBOL_GPL(mlx5_core_qp_modify); 224 + 225 + void mlx5_init_qp_table(struct mlx5_core_dev *dev) 226 + { 227 + struct mlx5_qp_table *table = &dev->priv.qp_table; 228 + 229 + spin_lock_init(&table->lock); 230 + INIT_RADIX_TREE(&table->tree, GFP_ATOMIC); 231 + mlx5_qp_debugfs_init(dev); 232 + } 233 + 234 + void mlx5_cleanup_qp_table(struct mlx5_core_dev *dev) 235 + { 236 + mlx5_qp_debugfs_cleanup(dev); 237 + } 238 + 239 + int mlx5_core_qp_query(struct mlx5_core_dev *dev, struct mlx5_core_qp *qp, 240 + struct mlx5_query_qp_mbox_out *out, int outlen) 241 + { 242 + struct mlx5_query_qp_mbox_in in; 243 + int err; 244 + 245 + memset(&in, 0, sizeof(in)); 246 + memset(out, 0, outlen); 247 + in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_QUERY_QP); 248 + in.qpn = cpu_to_be32(qp->qpn); 249 + err = mlx5_cmd_exec(dev, &in, sizeof(in), out, outlen); 250 + if (err) 251 + return err; 252 + 253 + if (out->hdr.status) 254 + return mlx5_cmd_status_to_err(&out->hdr); 255 + 256 + return err; 257 + } 258 + EXPORT_SYMBOL_GPL(mlx5_core_qp_query); 259 + 260 + int mlx5_core_xrcd_alloc(struct mlx5_core_dev *dev, u32 *xrcdn) 261 + { 262 + struct mlx5_alloc_xrcd_mbox_in in; 263 + struct mlx5_alloc_xrcd_mbox_out out; 264 + int err; 265 + 266 + memset(&in, 0, sizeof(in)); 267 + memset(&out, 0, sizeof(out)); 268 + in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_ALLOC_XRCD); 269 + err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out)); 270 + if (err) 271 + return err; 272 + 273 + if (out.hdr.status) 274 + err = mlx5_cmd_status_to_err(&out.hdr); 275 + else 276 + *xrcdn = be32_to_cpu(out.xrcdn); 277 + 278 + return err; 279 + } 280 + EXPORT_SYMBOL_GPL(mlx5_core_xrcd_alloc); 281 + 282 + int mlx5_core_xrcd_dealloc(struct mlx5_core_dev *dev, u32 xrcdn) 283 + { 284 + struct mlx5_dealloc_xrcd_mbox_in in; 285 + struct mlx5_dealloc_xrcd_mbox_out out; 286 + int err; 287 + 288 + memset(&in, 0, sizeof(in)); 289 + memset(&out, 0, sizeof(out)); 290 + in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_DEALLOC_XRCD); 291 + in.xrcdn = cpu_to_be32(xrcdn); 292 + err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out)); 293 + if (err) 294 + return err; 295 + 296 + if (out.hdr.status) 297 + err = mlx5_cmd_status_to_err(&out.hdr); 298 + 299 + return err; 300 + } 301 + EXPORT_SYMBOL_GPL(mlx5_core_xrcd_dealloc);
+223
drivers/net/ethernet/mellanox/mlx5/core/srq.c
··· 1 + /* 2 + * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved. 3 + * 4 + * This software is available to you under a choice of one of two 5 + * licenses. You may choose to be licensed under the terms of the GNU 6 + * General Public License (GPL) Version 2, available from the file 7 + * COPYING in the main directory of this source tree, or the 8 + * OpenIB.org BSD license below: 9 + * 10 + * Redistribution and use in source and binary forms, with or 11 + * without modification, are permitted provided that the following 12 + * conditions are met: 13 + * 14 + * - Redistributions of source code must retain the above 15 + * copyright notice, this list of conditions and the following 16 + * disclaimer. 17 + * 18 + * - Redistributions in binary form must reproduce the above 19 + * copyright notice, this list of conditions and the following 20 + * disclaimer in the documentation and/or other materials 21 + * 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 OF 25 + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26 + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 27 + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 28 + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29 + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30 + * SOFTWARE. 31 + */ 32 + 33 + #include <linux/kernel.h> 34 + #include <linux/module.h> 35 + #include <linux/mlx5/driver.h> 36 + #include <linux/mlx5/cmd.h> 37 + #include <linux/mlx5/srq.h> 38 + #include <rdma/ib_verbs.h> 39 + #include "mlx5_core.h" 40 + 41 + void mlx5_srq_event(struct mlx5_core_dev *dev, u32 srqn, int event_type) 42 + { 43 + struct mlx5_srq_table *table = &dev->priv.srq_table; 44 + struct mlx5_core_srq *srq; 45 + 46 + spin_lock(&table->lock); 47 + 48 + srq = radix_tree_lookup(&table->tree, srqn); 49 + if (srq) 50 + atomic_inc(&srq->refcount); 51 + 52 + spin_unlock(&table->lock); 53 + 54 + if (!srq) { 55 + mlx5_core_warn(dev, "Async event for bogus SRQ 0x%08x\n", srqn); 56 + return; 57 + } 58 + 59 + srq->event(srq, event_type); 60 + 61 + if (atomic_dec_and_test(&srq->refcount)) 62 + complete(&srq->free); 63 + } 64 + 65 + struct mlx5_core_srq *mlx5_core_get_srq(struct mlx5_core_dev *dev, u32 srqn) 66 + { 67 + struct mlx5_srq_table *table = &dev->priv.srq_table; 68 + struct mlx5_core_srq *srq; 69 + 70 + spin_lock(&table->lock); 71 + 72 + srq = radix_tree_lookup(&table->tree, srqn); 73 + if (srq) 74 + atomic_inc(&srq->refcount); 75 + 76 + spin_unlock(&table->lock); 77 + 78 + return srq; 79 + } 80 + EXPORT_SYMBOL(mlx5_core_get_srq); 81 + 82 + int mlx5_core_create_srq(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq, 83 + struct mlx5_create_srq_mbox_in *in, int inlen) 84 + { 85 + struct mlx5_create_srq_mbox_out out; 86 + struct mlx5_srq_table *table = &dev->priv.srq_table; 87 + struct mlx5_destroy_srq_mbox_in din; 88 + struct mlx5_destroy_srq_mbox_out dout; 89 + int err; 90 + 91 + memset(&out, 0, sizeof(out)); 92 + in->hdr.opcode = cpu_to_be16(MLX5_CMD_OP_CREATE_SRQ); 93 + err = mlx5_cmd_exec(dev, in, inlen, &out, sizeof(out)); 94 + if (err) 95 + return err; 96 + 97 + if (out.hdr.status) 98 + return mlx5_cmd_status_to_err(&out.hdr); 99 + 100 + srq->srqn = be32_to_cpu(out.srqn) & 0xffffff; 101 + 102 + atomic_set(&srq->refcount, 1); 103 + init_completion(&srq->free); 104 + 105 + spin_lock_irq(&table->lock); 106 + err = radix_tree_insert(&table->tree, srq->srqn, srq); 107 + spin_unlock_irq(&table->lock); 108 + if (err) { 109 + mlx5_core_warn(dev, "err %d, srqn 0x%x\n", err, srq->srqn); 110 + goto err_cmd; 111 + } 112 + 113 + return 0; 114 + 115 + err_cmd: 116 + memset(&din, 0, sizeof(din)); 117 + memset(&dout, 0, sizeof(dout)); 118 + din.srqn = cpu_to_be32(srq->srqn); 119 + din.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_DESTROY_SRQ); 120 + mlx5_cmd_exec(dev, &din, sizeof(din), &dout, sizeof(dout)); 121 + return err; 122 + } 123 + EXPORT_SYMBOL(mlx5_core_create_srq); 124 + 125 + int mlx5_core_destroy_srq(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq) 126 + { 127 + struct mlx5_destroy_srq_mbox_in in; 128 + struct mlx5_destroy_srq_mbox_out out; 129 + struct mlx5_srq_table *table = &dev->priv.srq_table; 130 + struct mlx5_core_srq *tmp; 131 + int err; 132 + 133 + spin_lock_irq(&table->lock); 134 + tmp = radix_tree_delete(&table->tree, srq->srqn); 135 + spin_unlock_irq(&table->lock); 136 + if (!tmp) { 137 + mlx5_core_warn(dev, "srq 0x%x not found in tree\n", srq->srqn); 138 + return -EINVAL; 139 + } 140 + if (tmp != srq) { 141 + mlx5_core_warn(dev, "corruption on srqn 0x%x\n", srq->srqn); 142 + return -EINVAL; 143 + } 144 + 145 + memset(&in, 0, sizeof(in)); 146 + memset(&out, 0, sizeof(out)); 147 + in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_DESTROY_SRQ); 148 + in.srqn = cpu_to_be32(srq->srqn); 149 + err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out)); 150 + if (err) 151 + return err; 152 + 153 + if (out.hdr.status) 154 + return mlx5_cmd_status_to_err(&out.hdr); 155 + 156 + if (atomic_dec_and_test(&srq->refcount)) 157 + complete(&srq->free); 158 + wait_for_completion(&srq->free); 159 + 160 + return 0; 161 + } 162 + EXPORT_SYMBOL(mlx5_core_destroy_srq); 163 + 164 + int mlx5_core_query_srq(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq, 165 + struct mlx5_query_srq_mbox_out *out) 166 + { 167 + struct mlx5_query_srq_mbox_in in; 168 + int err; 169 + 170 + memset(&in, 0, sizeof(in)); 171 + memset(out, 0, sizeof(*out)); 172 + 173 + in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_QUERY_SRQ); 174 + in.srqn = cpu_to_be32(srq->srqn); 175 + err = mlx5_cmd_exec(dev, &in, sizeof(in), out, sizeof(*out)); 176 + if (err) 177 + return err; 178 + 179 + if (out->hdr.status) 180 + return mlx5_cmd_status_to_err(&out->hdr); 181 + 182 + return err; 183 + } 184 + EXPORT_SYMBOL(mlx5_core_query_srq); 185 + 186 + int mlx5_core_arm_srq(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq, 187 + u16 lwm, int is_srq) 188 + { 189 + struct mlx5_arm_srq_mbox_in in; 190 + struct mlx5_arm_srq_mbox_out out; 191 + int err; 192 + 193 + memset(&in, 0, sizeof(in)); 194 + memset(&out, 0, sizeof(out)); 195 + 196 + in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_ARM_RQ); 197 + in.hdr.opmod = cpu_to_be16(!!is_srq); 198 + in.srqn = cpu_to_be32(srq->srqn); 199 + in.lwm = cpu_to_be16(lwm); 200 + 201 + err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out)); 202 + if (err) 203 + return err; 204 + 205 + if (out.hdr.status) 206 + return mlx5_cmd_status_to_err(&out.hdr); 207 + 208 + return err; 209 + } 210 + EXPORT_SYMBOL(mlx5_core_arm_srq); 211 + 212 + void mlx5_init_srq_table(struct mlx5_core_dev *dev) 213 + { 214 + struct mlx5_srq_table *table = &dev->priv.srq_table; 215 + 216 + spin_lock_init(&table->lock); 217 + INIT_RADIX_TREE(&table->tree, GFP_ATOMIC); 218 + } 219 + 220 + void mlx5_cleanup_srq_table(struct mlx5_core_dev *dev) 221 + { 222 + /* nothing */ 223 + }
+223
drivers/net/ethernet/mellanox/mlx5/core/uar.c
··· 1 + /* 2 + * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved. 3 + * 4 + * This software is available to you under a choice of one of two 5 + * licenses. You may choose to be licensed under the terms of the GNU 6 + * General Public License (GPL) Version 2, available from the file 7 + * COPYING in the main directory of this source tree, or the 8 + * OpenIB.org BSD license below: 9 + * 10 + * Redistribution and use in source and binary forms, with or 11 + * without modification, are permitted provided that the following 12 + * conditions are met: 13 + * 14 + * - Redistributions of source code must retain the above 15 + * copyright notice, this list of conditions and the following 16 + * disclaimer. 17 + * 18 + * - Redistributions in binary form must reproduce the above 19 + * copyright notice, this list of conditions and the following 20 + * disclaimer in the documentation and/or other materials 21 + * 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 OF 25 + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26 + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 27 + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 28 + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29 + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30 + * SOFTWARE. 31 + */ 32 + 33 + #include <linux/kernel.h> 34 + #include <linux/module.h> 35 + #include <linux/mlx5/driver.h> 36 + #include <linux/mlx5/cmd.h> 37 + #include "mlx5_core.h" 38 + 39 + enum { 40 + NUM_DRIVER_UARS = 4, 41 + NUM_LOW_LAT_UUARS = 4, 42 + }; 43 + 44 + 45 + struct mlx5_alloc_uar_mbox_in { 46 + struct mlx5_inbox_hdr hdr; 47 + u8 rsvd[8]; 48 + }; 49 + 50 + struct mlx5_alloc_uar_mbox_out { 51 + struct mlx5_outbox_hdr hdr; 52 + __be32 uarn; 53 + u8 rsvd[4]; 54 + }; 55 + 56 + struct mlx5_free_uar_mbox_in { 57 + struct mlx5_inbox_hdr hdr; 58 + __be32 uarn; 59 + u8 rsvd[4]; 60 + }; 61 + 62 + struct mlx5_free_uar_mbox_out { 63 + struct mlx5_outbox_hdr hdr; 64 + u8 rsvd[8]; 65 + }; 66 + 67 + int mlx5_cmd_alloc_uar(struct mlx5_core_dev *dev, u32 *uarn) 68 + { 69 + struct mlx5_alloc_uar_mbox_in in; 70 + struct mlx5_alloc_uar_mbox_out out; 71 + int err; 72 + 73 + memset(&in, 0, sizeof(in)); 74 + memset(&out, 0, sizeof(out)); 75 + in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_ALLOC_UAR); 76 + err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out)); 77 + if (err) 78 + goto ex; 79 + 80 + if (out.hdr.status) { 81 + err = mlx5_cmd_status_to_err(&out.hdr); 82 + goto ex; 83 + } 84 + 85 + *uarn = be32_to_cpu(out.uarn) & 0xffffff; 86 + 87 + ex: 88 + return err; 89 + } 90 + EXPORT_SYMBOL(mlx5_cmd_alloc_uar); 91 + 92 + int mlx5_cmd_free_uar(struct mlx5_core_dev *dev, u32 uarn) 93 + { 94 + struct mlx5_free_uar_mbox_in in; 95 + struct mlx5_free_uar_mbox_out out; 96 + int err; 97 + 98 + memset(&in, 0, sizeof(in)); 99 + in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_DEALLOC_UAR); 100 + in.uarn = cpu_to_be32(uarn); 101 + err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out)); 102 + if (err) 103 + goto ex; 104 + 105 + if (out.hdr.status) 106 + err = mlx5_cmd_status_to_err(&out.hdr); 107 + 108 + ex: 109 + return err; 110 + } 111 + EXPORT_SYMBOL(mlx5_cmd_free_uar); 112 + 113 + static int need_uuar_lock(int uuarn) 114 + { 115 + int tot_uuars = NUM_DRIVER_UARS * MLX5_BF_REGS_PER_PAGE; 116 + 117 + if (uuarn == 0 || tot_uuars - NUM_LOW_LAT_UUARS) 118 + return 0; 119 + 120 + return 1; 121 + } 122 + 123 + int mlx5_alloc_uuars(struct mlx5_core_dev *dev, struct mlx5_uuar_info *uuari) 124 + { 125 + int tot_uuars = NUM_DRIVER_UARS * MLX5_BF_REGS_PER_PAGE; 126 + struct mlx5_bf *bf; 127 + phys_addr_t addr; 128 + int err; 129 + int i; 130 + 131 + uuari->num_uars = NUM_DRIVER_UARS; 132 + uuari->num_low_latency_uuars = NUM_LOW_LAT_UUARS; 133 + 134 + mutex_init(&uuari->lock); 135 + uuari->uars = kcalloc(uuari->num_uars, sizeof(*uuari->uars), GFP_KERNEL); 136 + if (!uuari->uars) 137 + return -ENOMEM; 138 + 139 + uuari->bfs = kcalloc(tot_uuars, sizeof(*uuari->bfs), GFP_KERNEL); 140 + if (!uuari->bfs) { 141 + err = -ENOMEM; 142 + goto out_uars; 143 + } 144 + 145 + uuari->bitmap = kcalloc(BITS_TO_LONGS(tot_uuars), sizeof(*uuari->bitmap), 146 + GFP_KERNEL); 147 + if (!uuari->bitmap) { 148 + err = -ENOMEM; 149 + goto out_bfs; 150 + } 151 + 152 + uuari->count = kcalloc(tot_uuars, sizeof(*uuari->count), GFP_KERNEL); 153 + if (!uuari->count) { 154 + err = -ENOMEM; 155 + goto out_bitmap; 156 + } 157 + 158 + for (i = 0; i < uuari->num_uars; i++) { 159 + err = mlx5_cmd_alloc_uar(dev, &uuari->uars[i].index); 160 + if (err) 161 + goto out_count; 162 + 163 + addr = dev->iseg_base + ((phys_addr_t)(uuari->uars[i].index) << PAGE_SHIFT); 164 + uuari->uars[i].map = ioremap(addr, PAGE_SIZE); 165 + if (!uuari->uars[i].map) { 166 + mlx5_cmd_free_uar(dev, uuari->uars[i].index); 167 + goto out_count; 168 + } 169 + mlx5_core_dbg(dev, "allocated uar index 0x%x, mmaped at %p\n", 170 + uuari->uars[i].index, uuari->uars[i].map); 171 + } 172 + 173 + for (i = 0; i < tot_uuars; i++) { 174 + bf = &uuari->bfs[i]; 175 + 176 + bf->buf_size = dev->caps.bf_reg_size / 2; 177 + bf->uar = &uuari->uars[i / MLX5_BF_REGS_PER_PAGE]; 178 + bf->regreg = uuari->uars[i / MLX5_BF_REGS_PER_PAGE].map; 179 + bf->reg = NULL; /* Add WC support */ 180 + bf->offset = (i % MLX5_BF_REGS_PER_PAGE) * dev->caps.bf_reg_size + 181 + MLX5_BF_OFFSET; 182 + bf->need_lock = need_uuar_lock(i); 183 + spin_lock_init(&bf->lock); 184 + spin_lock_init(&bf->lock32); 185 + bf->uuarn = i; 186 + } 187 + 188 + return 0; 189 + 190 + out_count: 191 + for (i--; i >= 0; i--) { 192 + iounmap(uuari->uars[i].map); 193 + mlx5_cmd_free_uar(dev, uuari->uars[i].index); 194 + } 195 + kfree(uuari->count); 196 + 197 + out_bitmap: 198 + kfree(uuari->bitmap); 199 + 200 + out_bfs: 201 + kfree(uuari->bfs); 202 + 203 + out_uars: 204 + kfree(uuari->uars); 205 + return err; 206 + } 207 + 208 + int mlx5_free_uuars(struct mlx5_core_dev *dev, struct mlx5_uuar_info *uuari) 209 + { 210 + int i = uuari->num_uars; 211 + 212 + for (i--; i >= 0; i--) { 213 + iounmap(uuari->uars[i].map); 214 + mlx5_cmd_free_uar(dev, uuari->uars[i].index); 215 + } 216 + 217 + kfree(uuari->count); 218 + kfree(uuari->bitmap); 219 + kfree(uuari->bfs); 220 + kfree(uuari->uars); 221 + 222 + return 0; 223 + }
+51
include/linux/mlx5/cmd.h
··· 1 + /* 2 + * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved. 3 + * 4 + * This software is available to you under a choice of one of two 5 + * licenses. You may choose to be licensed under the terms of the GNU 6 + * General Public License (GPL) Version 2, available from the file 7 + * COPYING in the main directory of this source tree, or the 8 + * OpenIB.org BSD license below: 9 + * 10 + * Redistribution and use in source and binary forms, with or 11 + * without modification, are permitted provided that the following 12 + * conditions are met: 13 + * 14 + * - Redistributions of source code must retain the above 15 + * copyright notice, this list of conditions and the following 16 + * disclaimer. 17 + * 18 + * - Redistributions in binary form must reproduce the above 19 + * copyright notice, this list of conditions and the following 20 + * disclaimer in the documentation and/or other materials 21 + * 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 OF 25 + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26 + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 27 + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 28 + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29 + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30 + * SOFTWARE. 31 + */ 32 + 33 + #ifndef MLX5_CMD_H 34 + #define MLX5_CMD_H 35 + 36 + #include <linux/types.h> 37 + 38 + struct manage_pages_layout { 39 + u64 ptr; 40 + u32 reserved; 41 + u16 num_entries; 42 + u16 func_id; 43 + }; 44 + 45 + 46 + struct mlx5_cmd_alloc_uar_imm_out { 47 + u32 rsvd[3]; 48 + u32 uarn; 49 + }; 50 + 51 + #endif /* MLX5_CMD_H */
+165
include/linux/mlx5/cq.h
··· 1 + /* 2 + * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved. 3 + * 4 + * This software is available to you under a choice of one of two 5 + * licenses. You may choose to be licensed under the terms of the GNU 6 + * General Public License (GPL) Version 2, available from the file 7 + * COPYING in the main directory of this source tree, or the 8 + * OpenIB.org BSD license below: 9 + * 10 + * Redistribution and use in source and binary forms, with or 11 + * without modification, are permitted provided that the following 12 + * conditions are met: 13 + * 14 + * - Redistributions of source code must retain the above 15 + * copyright notice, this list of conditions and the following 16 + * disclaimer. 17 + * 18 + * - Redistributions in binary form must reproduce the above 19 + * copyright notice, this list of conditions and the following 20 + * disclaimer in the documentation and/or other materials 21 + * 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 OF 25 + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26 + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 27 + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 28 + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29 + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30 + * SOFTWARE. 31 + */ 32 + 33 + #ifndef MLX5_CORE_CQ_H 34 + #define MLX5_CORE_CQ_H 35 + 36 + #include <rdma/ib_verbs.h> 37 + #include <linux/mlx5/driver.h> 38 + 39 + 40 + struct mlx5_core_cq { 41 + u32 cqn; 42 + int cqe_sz; 43 + __be32 *set_ci_db; 44 + __be32 *arm_db; 45 + atomic_t refcount; 46 + struct completion free; 47 + unsigned vector; 48 + int irqn; 49 + void (*comp) (struct mlx5_core_cq *); 50 + void (*event) (struct mlx5_core_cq *, enum mlx5_event); 51 + struct mlx5_uar *uar; 52 + u32 cons_index; 53 + unsigned arm_sn; 54 + struct mlx5_rsc_debug *dbg; 55 + int pid; 56 + }; 57 + 58 + 59 + enum { 60 + MLX5_CQE_SYNDROME_LOCAL_LENGTH_ERR = 0x01, 61 + MLX5_CQE_SYNDROME_LOCAL_QP_OP_ERR = 0x02, 62 + MLX5_CQE_SYNDROME_LOCAL_PROT_ERR = 0x04, 63 + MLX5_CQE_SYNDROME_WR_FLUSH_ERR = 0x05, 64 + MLX5_CQE_SYNDROME_MW_BIND_ERR = 0x06, 65 + MLX5_CQE_SYNDROME_BAD_RESP_ERR = 0x10, 66 + MLX5_CQE_SYNDROME_LOCAL_ACCESS_ERR = 0x11, 67 + MLX5_CQE_SYNDROME_REMOTE_INVAL_REQ_ERR = 0x12, 68 + MLX5_CQE_SYNDROME_REMOTE_ACCESS_ERR = 0x13, 69 + MLX5_CQE_SYNDROME_REMOTE_OP_ERR = 0x14, 70 + MLX5_CQE_SYNDROME_TRANSPORT_RETRY_EXC_ERR = 0x15, 71 + MLX5_CQE_SYNDROME_RNR_RETRY_EXC_ERR = 0x16, 72 + MLX5_CQE_SYNDROME_REMOTE_ABORTED_ERR = 0x22, 73 + }; 74 + 75 + enum { 76 + MLX5_CQE_OWNER_MASK = 1, 77 + MLX5_CQE_REQ = 0, 78 + MLX5_CQE_RESP_WR_IMM = 1, 79 + MLX5_CQE_RESP_SEND = 2, 80 + MLX5_CQE_RESP_SEND_IMM = 3, 81 + MLX5_CQE_RESP_SEND_INV = 4, 82 + MLX5_CQE_RESIZE_CQ = 0xff, /* TBD */ 83 + MLX5_CQE_REQ_ERR = 13, 84 + MLX5_CQE_RESP_ERR = 14, 85 + }; 86 + 87 + enum { 88 + MLX5_CQ_MODIFY_RESEIZE = 0, 89 + MLX5_CQ_MODIFY_MODER = 1, 90 + MLX5_CQ_MODIFY_MAPPING = 2, 91 + }; 92 + 93 + struct mlx5_cq_modify_params { 94 + int type; 95 + union { 96 + struct { 97 + u32 page_offset; 98 + u8 log_cq_size; 99 + } resize; 100 + 101 + struct { 102 + } moder; 103 + 104 + struct { 105 + } mapping; 106 + } params; 107 + }; 108 + 109 + enum { 110 + CQE_SIZE_64 = 0, 111 + CQE_SIZE_128 = 1, 112 + }; 113 + 114 + static inline int cqe_sz_to_mlx_sz(u8 size) 115 + { 116 + return size == 64 ? CQE_SIZE_64 : CQE_SIZE_128; 117 + } 118 + 119 + static inline void mlx5_cq_set_ci(struct mlx5_core_cq *cq) 120 + { 121 + *cq->set_ci_db = cpu_to_be32(cq->cons_index & 0xffffff); 122 + } 123 + 124 + enum { 125 + MLX5_CQ_DB_REQ_NOT_SOL = 1 << 24, 126 + MLX5_CQ_DB_REQ_NOT = 0 << 24 127 + }; 128 + 129 + static inline void mlx5_cq_arm(struct mlx5_core_cq *cq, u32 cmd, 130 + void __iomem *uar_page, 131 + spinlock_t *doorbell_lock) 132 + { 133 + __be32 doorbell[2]; 134 + u32 sn; 135 + u32 ci; 136 + 137 + sn = cq->arm_sn & 3; 138 + ci = cq->cons_index & 0xffffff; 139 + 140 + *cq->arm_db = cpu_to_be32(sn << 28 | cmd | ci); 141 + 142 + /* Make sure that the doorbell record in host memory is 143 + * written before ringing the doorbell via PCI MMIO. 144 + */ 145 + wmb(); 146 + 147 + doorbell[0] = cpu_to_be32(sn << 28 | cmd | ci); 148 + doorbell[1] = cpu_to_be32(cq->cqn); 149 + 150 + mlx5_write64(doorbell, uar_page + MLX5_CQ_DOORBELL, doorbell_lock); 151 + } 152 + 153 + int mlx5_init_cq_table(struct mlx5_core_dev *dev); 154 + void mlx5_cleanup_cq_table(struct mlx5_core_dev *dev); 155 + int mlx5_core_create_cq(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq, 156 + struct mlx5_create_cq_mbox_in *in, int inlen); 157 + int mlx5_core_destroy_cq(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq); 158 + int mlx5_core_query_cq(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq, 159 + struct mlx5_query_cq_mbox_out *out); 160 + int mlx5_core_modify_cq(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq, 161 + int type, struct mlx5_cq_modify_params *params); 162 + int mlx5_debug_cq_add(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq); 163 + void mlx5_debug_cq_remove(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq); 164 + 165 + #endif /* MLX5_CORE_CQ_H */
+893
include/linux/mlx5/device.h
··· 1 + /* 2 + * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved. 3 + * 4 + * This software is available to you under a choice of one of two 5 + * licenses. You may choose to be licensed under the terms of the GNU 6 + * General Public License (GPL) Version 2, available from the file 7 + * COPYING in the main directory of this source tree, or the 8 + * OpenIB.org BSD license below: 9 + * 10 + * Redistribution and use in source and binary forms, with or 11 + * without modification, are permitted provided that the following 12 + * conditions are met: 13 + * 14 + * - Redistributions of source code must retain the above 15 + * copyright notice, this list of conditions and the following 16 + * disclaimer. 17 + * 18 + * - Redistributions in binary form must reproduce the above 19 + * copyright notice, this list of conditions and the following 20 + * disclaimer in the documentation and/or other materials 21 + * 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 OF 25 + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26 + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 27 + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 28 + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29 + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30 + * SOFTWARE. 31 + */ 32 + 33 + #ifndef MLX5_DEVICE_H 34 + #define MLX5_DEVICE_H 35 + 36 + #include <linux/types.h> 37 + #include <rdma/ib_verbs.h> 38 + 39 + #if defined(__LITTLE_ENDIAN) 40 + #define MLX5_SET_HOST_ENDIANNESS 0 41 + #elif defined(__BIG_ENDIAN) 42 + #define MLX5_SET_HOST_ENDIANNESS 0x80 43 + #else 44 + #error Host endianness not defined 45 + #endif 46 + 47 + enum { 48 + MLX5_MAX_COMMANDS = 32, 49 + MLX5_CMD_DATA_BLOCK_SIZE = 512, 50 + MLX5_PCI_CMD_XPORT = 7, 51 + }; 52 + 53 + enum { 54 + MLX5_EXTENDED_UD_AV = 0x80000000, 55 + }; 56 + 57 + enum { 58 + MLX5_CQ_STATE_ARMED = 9, 59 + MLX5_CQ_STATE_ALWAYS_ARMED = 0xb, 60 + MLX5_CQ_STATE_FIRED = 0xa, 61 + }; 62 + 63 + enum { 64 + MLX5_STAT_RATE_OFFSET = 5, 65 + }; 66 + 67 + enum { 68 + MLX5_INLINE_SEG = 0x80000000, 69 + }; 70 + 71 + enum { 72 + MLX5_PERM_LOCAL_READ = 1 << 2, 73 + MLX5_PERM_LOCAL_WRITE = 1 << 3, 74 + MLX5_PERM_REMOTE_READ = 1 << 4, 75 + MLX5_PERM_REMOTE_WRITE = 1 << 5, 76 + MLX5_PERM_ATOMIC = 1 << 6, 77 + MLX5_PERM_UMR_EN = 1 << 7, 78 + }; 79 + 80 + enum { 81 + MLX5_PCIE_CTRL_SMALL_FENCE = 1 << 0, 82 + MLX5_PCIE_CTRL_RELAXED_ORDERING = 1 << 2, 83 + MLX5_PCIE_CTRL_NO_SNOOP = 1 << 3, 84 + MLX5_PCIE_CTRL_TLP_PROCE_EN = 1 << 6, 85 + MLX5_PCIE_CTRL_TPH_MASK = 3 << 4, 86 + }; 87 + 88 + enum { 89 + MLX5_ACCESS_MODE_PA = 0, 90 + MLX5_ACCESS_MODE_MTT = 1, 91 + MLX5_ACCESS_MODE_KLM = 2 92 + }; 93 + 94 + enum { 95 + MLX5_MKEY_REMOTE_INVAL = 1 << 24, 96 + MLX5_MKEY_FLAG_SYNC_UMR = 1 << 29, 97 + MLX5_MKEY_BSF_EN = 1 << 30, 98 + MLX5_MKEY_LEN64 = 1 << 31, 99 + }; 100 + 101 + enum { 102 + MLX5_EN_RD = (u64)1, 103 + MLX5_EN_WR = (u64)2 104 + }; 105 + 106 + enum { 107 + MLX5_BF_REGS_PER_PAGE = 4, 108 + MLX5_MAX_UAR_PAGES = 1 << 8, 109 + MLX5_MAX_UUARS = MLX5_MAX_UAR_PAGES * MLX5_BF_REGS_PER_PAGE, 110 + }; 111 + 112 + enum { 113 + MLX5_MKEY_MASK_LEN = 1ull << 0, 114 + MLX5_MKEY_MASK_PAGE_SIZE = 1ull << 1, 115 + MLX5_MKEY_MASK_START_ADDR = 1ull << 6, 116 + MLX5_MKEY_MASK_PD = 1ull << 7, 117 + MLX5_MKEY_MASK_EN_RINVAL = 1ull << 8, 118 + MLX5_MKEY_MASK_BSF_EN = 1ull << 12, 119 + MLX5_MKEY_MASK_KEY = 1ull << 13, 120 + MLX5_MKEY_MASK_QPN = 1ull << 14, 121 + MLX5_MKEY_MASK_LR = 1ull << 17, 122 + MLX5_MKEY_MASK_LW = 1ull << 18, 123 + MLX5_MKEY_MASK_RR = 1ull << 19, 124 + MLX5_MKEY_MASK_RW = 1ull << 20, 125 + MLX5_MKEY_MASK_A = 1ull << 21, 126 + MLX5_MKEY_MASK_SMALL_FENCE = 1ull << 23, 127 + MLX5_MKEY_MASK_FREE = 1ull << 29, 128 + }; 129 + 130 + enum mlx5_event { 131 + MLX5_EVENT_TYPE_COMP = 0x0, 132 + 133 + MLX5_EVENT_TYPE_PATH_MIG = 0x01, 134 + MLX5_EVENT_TYPE_COMM_EST = 0x02, 135 + MLX5_EVENT_TYPE_SQ_DRAINED = 0x03, 136 + MLX5_EVENT_TYPE_SRQ_LAST_WQE = 0x13, 137 + MLX5_EVENT_TYPE_SRQ_RQ_LIMIT = 0x14, 138 + 139 + MLX5_EVENT_TYPE_CQ_ERROR = 0x04, 140 + MLX5_EVENT_TYPE_WQ_CATAS_ERROR = 0x05, 141 + MLX5_EVENT_TYPE_PATH_MIG_FAILED = 0x07, 142 + MLX5_EVENT_TYPE_WQ_INVAL_REQ_ERROR = 0x10, 143 + MLX5_EVENT_TYPE_WQ_ACCESS_ERROR = 0x11, 144 + MLX5_EVENT_TYPE_SRQ_CATAS_ERROR = 0x12, 145 + 146 + MLX5_EVENT_TYPE_INTERNAL_ERROR = 0x08, 147 + MLX5_EVENT_TYPE_PORT_CHANGE = 0x09, 148 + MLX5_EVENT_TYPE_GPIO_EVENT = 0x15, 149 + MLX5_EVENT_TYPE_REMOTE_CONFIG = 0x19, 150 + 151 + MLX5_EVENT_TYPE_DB_BF_CONGESTION = 0x1a, 152 + MLX5_EVENT_TYPE_STALL_EVENT = 0x1b, 153 + 154 + MLX5_EVENT_TYPE_CMD = 0x0a, 155 + MLX5_EVENT_TYPE_PAGE_REQUEST = 0xb, 156 + }; 157 + 158 + enum { 159 + MLX5_PORT_CHANGE_SUBTYPE_DOWN = 1, 160 + MLX5_PORT_CHANGE_SUBTYPE_ACTIVE = 4, 161 + MLX5_PORT_CHANGE_SUBTYPE_INITIALIZED = 5, 162 + MLX5_PORT_CHANGE_SUBTYPE_LID = 6, 163 + MLX5_PORT_CHANGE_SUBTYPE_PKEY = 7, 164 + MLX5_PORT_CHANGE_SUBTYPE_GUID = 8, 165 + MLX5_PORT_CHANGE_SUBTYPE_CLIENT_REREG = 9, 166 + }; 167 + 168 + enum { 169 + MLX5_DEV_CAP_FLAG_RC = 1LL << 0, 170 + MLX5_DEV_CAP_FLAG_UC = 1LL << 1, 171 + MLX5_DEV_CAP_FLAG_UD = 1LL << 2, 172 + MLX5_DEV_CAP_FLAG_XRC = 1LL << 3, 173 + MLX5_DEV_CAP_FLAG_SRQ = 1LL << 6, 174 + MLX5_DEV_CAP_FLAG_BAD_PKEY_CNTR = 1LL << 8, 175 + MLX5_DEV_CAP_FLAG_BAD_QKEY_CNTR = 1LL << 9, 176 + MLX5_DEV_CAP_FLAG_APM = 1LL << 17, 177 + MLX5_DEV_CAP_FLAG_ATOMIC = 1LL << 18, 178 + MLX5_DEV_CAP_FLAG_ON_DMND_PG = 1LL << 24, 179 + MLX5_DEV_CAP_FLAG_RESIZE_SRQ = 1LL << 32, 180 + MLX5_DEV_CAP_FLAG_REMOTE_FENCE = 1LL << 38, 181 + MLX5_DEV_CAP_FLAG_TLP_HINTS = 1LL << 39, 182 + MLX5_DEV_CAP_FLAG_SIG_HAND_OVER = 1LL << 40, 183 + MLX5_DEV_CAP_FLAG_DCT = 1LL << 41, 184 + MLX5_DEV_CAP_FLAG_CMDIF_CSUM = 1LL << 46, 185 + }; 186 + 187 + enum { 188 + MLX5_OPCODE_NOP = 0x00, 189 + MLX5_OPCODE_SEND_INVAL = 0x01, 190 + MLX5_OPCODE_RDMA_WRITE = 0x08, 191 + MLX5_OPCODE_RDMA_WRITE_IMM = 0x09, 192 + MLX5_OPCODE_SEND = 0x0a, 193 + MLX5_OPCODE_SEND_IMM = 0x0b, 194 + MLX5_OPCODE_RDMA_READ = 0x10, 195 + MLX5_OPCODE_ATOMIC_CS = 0x11, 196 + MLX5_OPCODE_ATOMIC_FA = 0x12, 197 + MLX5_OPCODE_ATOMIC_MASKED_CS = 0x14, 198 + MLX5_OPCODE_ATOMIC_MASKED_FA = 0x15, 199 + MLX5_OPCODE_BIND_MW = 0x18, 200 + MLX5_OPCODE_CONFIG_CMD = 0x1f, 201 + 202 + MLX5_RECV_OPCODE_RDMA_WRITE_IMM = 0x00, 203 + MLX5_RECV_OPCODE_SEND = 0x01, 204 + MLX5_RECV_OPCODE_SEND_IMM = 0x02, 205 + MLX5_RECV_OPCODE_SEND_INVAL = 0x03, 206 + 207 + MLX5_CQE_OPCODE_ERROR = 0x1e, 208 + MLX5_CQE_OPCODE_RESIZE = 0x16, 209 + 210 + MLX5_OPCODE_SET_PSV = 0x20, 211 + MLX5_OPCODE_GET_PSV = 0x21, 212 + MLX5_OPCODE_CHECK_PSV = 0x22, 213 + MLX5_OPCODE_RGET_PSV = 0x26, 214 + MLX5_OPCODE_RCHECK_PSV = 0x27, 215 + 216 + MLX5_OPCODE_UMR = 0x25, 217 + 218 + }; 219 + 220 + enum { 221 + MLX5_SET_PORT_RESET_QKEY = 0, 222 + MLX5_SET_PORT_GUID0 = 16, 223 + MLX5_SET_PORT_NODE_GUID = 17, 224 + MLX5_SET_PORT_SYS_GUID = 18, 225 + MLX5_SET_PORT_GID_TABLE = 19, 226 + MLX5_SET_PORT_PKEY_TABLE = 20, 227 + }; 228 + 229 + enum { 230 + MLX5_MAX_PAGE_SHIFT = 31 231 + }; 232 + 233 + struct mlx5_inbox_hdr { 234 + __be16 opcode; 235 + u8 rsvd[4]; 236 + __be16 opmod; 237 + }; 238 + 239 + struct mlx5_outbox_hdr { 240 + u8 status; 241 + u8 rsvd[3]; 242 + __be32 syndrome; 243 + }; 244 + 245 + struct mlx5_cmd_query_adapter_mbox_in { 246 + struct mlx5_inbox_hdr hdr; 247 + u8 rsvd[8]; 248 + }; 249 + 250 + struct mlx5_cmd_query_adapter_mbox_out { 251 + struct mlx5_outbox_hdr hdr; 252 + u8 rsvd0[24]; 253 + u8 intapin; 254 + u8 rsvd1[13]; 255 + __be16 vsd_vendor_id; 256 + u8 vsd[208]; 257 + u8 vsd_psid[16]; 258 + }; 259 + 260 + struct mlx5_hca_cap { 261 + u8 rsvd1[16]; 262 + u8 log_max_srq_sz; 263 + u8 log_max_qp_sz; 264 + u8 rsvd2; 265 + u8 log_max_qp; 266 + u8 log_max_strq_sz; 267 + u8 log_max_srqs; 268 + u8 rsvd4[2]; 269 + u8 rsvd5; 270 + u8 log_max_cq_sz; 271 + u8 rsvd6; 272 + u8 log_max_cq; 273 + u8 log_max_eq_sz; 274 + u8 log_max_mkey; 275 + u8 rsvd7; 276 + u8 log_max_eq; 277 + u8 max_indirection; 278 + u8 log_max_mrw_sz; 279 + u8 log_max_bsf_list_sz; 280 + u8 log_max_klm_list_sz; 281 + u8 rsvd_8_0; 282 + u8 log_max_ra_req_dc; 283 + u8 rsvd_8_1; 284 + u8 log_max_ra_res_dc; 285 + u8 rsvd9; 286 + u8 log_max_ra_req_qp; 287 + u8 rsvd10; 288 + u8 log_max_ra_res_qp; 289 + u8 rsvd11[4]; 290 + __be16 max_qp_count; 291 + __be16 rsvd12; 292 + u8 rsvd13; 293 + u8 local_ca_ack_delay; 294 + u8 rsvd14; 295 + u8 num_ports; 296 + u8 log_max_msg; 297 + u8 rsvd15[3]; 298 + __be16 stat_rate_support; 299 + u8 rsvd16[2]; 300 + __be64 flags; 301 + u8 rsvd17; 302 + u8 uar_sz; 303 + u8 rsvd18; 304 + u8 log_pg_sz; 305 + __be16 bf_log_bf_reg_size; 306 + u8 rsvd19[4]; 307 + __be16 max_desc_sz_sq; 308 + u8 rsvd20[2]; 309 + __be16 max_desc_sz_rq; 310 + u8 rsvd21[2]; 311 + __be16 max_desc_sz_sq_dc; 312 + u8 rsvd22[4]; 313 + __be16 max_qp_mcg; 314 + u8 rsvd23; 315 + u8 log_max_mcg; 316 + u8 rsvd24; 317 + u8 log_max_pd; 318 + u8 rsvd25; 319 + u8 log_max_xrcd; 320 + u8 rsvd26[40]; 321 + __be32 uar_page_sz; 322 + u8 rsvd27[28]; 323 + u8 log_msx_atomic_size_qp; 324 + u8 rsvd28[2]; 325 + u8 log_msx_atomic_size_dc; 326 + u8 rsvd29[76]; 327 + }; 328 + 329 + 330 + struct mlx5_cmd_query_hca_cap_mbox_in { 331 + struct mlx5_inbox_hdr hdr; 332 + u8 rsvd[8]; 333 + }; 334 + 335 + 336 + struct mlx5_cmd_query_hca_cap_mbox_out { 337 + struct mlx5_outbox_hdr hdr; 338 + u8 rsvd0[8]; 339 + struct mlx5_hca_cap hca_cap; 340 + }; 341 + 342 + 343 + struct mlx5_cmd_set_hca_cap_mbox_in { 344 + struct mlx5_inbox_hdr hdr; 345 + u8 rsvd[8]; 346 + struct mlx5_hca_cap hca_cap; 347 + }; 348 + 349 + 350 + struct mlx5_cmd_set_hca_cap_mbox_out { 351 + struct mlx5_outbox_hdr hdr; 352 + u8 rsvd0[8]; 353 + }; 354 + 355 + 356 + struct mlx5_cmd_init_hca_mbox_in { 357 + struct mlx5_inbox_hdr hdr; 358 + u8 rsvd0[2]; 359 + __be16 profile; 360 + u8 rsvd1[4]; 361 + }; 362 + 363 + struct mlx5_cmd_init_hca_mbox_out { 364 + struct mlx5_outbox_hdr hdr; 365 + u8 rsvd[8]; 366 + }; 367 + 368 + struct mlx5_cmd_teardown_hca_mbox_in { 369 + struct mlx5_inbox_hdr hdr; 370 + u8 rsvd0[2]; 371 + __be16 profile; 372 + u8 rsvd1[4]; 373 + }; 374 + 375 + struct mlx5_cmd_teardown_hca_mbox_out { 376 + struct mlx5_outbox_hdr hdr; 377 + u8 rsvd[8]; 378 + }; 379 + 380 + struct mlx5_cmd_layout { 381 + u8 type; 382 + u8 rsvd0[3]; 383 + __be32 inlen; 384 + __be64 in_ptr; 385 + __be32 in[4]; 386 + __be32 out[4]; 387 + __be64 out_ptr; 388 + __be32 outlen; 389 + u8 token; 390 + u8 sig; 391 + u8 rsvd1; 392 + u8 status_own; 393 + }; 394 + 395 + 396 + struct health_buffer { 397 + __be32 assert_var[5]; 398 + __be32 rsvd0[3]; 399 + __be32 assert_exit_ptr; 400 + __be32 assert_callra; 401 + __be32 rsvd1[2]; 402 + __be32 fw_ver; 403 + __be32 hw_id; 404 + __be32 rsvd2; 405 + u8 irisc_index; 406 + u8 synd; 407 + __be16 ext_sync; 408 + }; 409 + 410 + struct mlx5_init_seg { 411 + __be32 fw_rev; 412 + __be32 cmdif_rev_fw_sub; 413 + __be32 rsvd0[2]; 414 + __be32 cmdq_addr_h; 415 + __be32 cmdq_addr_l_sz; 416 + __be32 cmd_dbell; 417 + __be32 rsvd1[121]; 418 + struct health_buffer health; 419 + __be32 rsvd2[884]; 420 + __be32 health_counter; 421 + __be32 rsvd3[1023]; 422 + __be64 ieee1588_clk; 423 + __be32 ieee1588_clk_type; 424 + __be32 clr_intx; 425 + }; 426 + 427 + struct mlx5_eqe_comp { 428 + __be32 reserved[6]; 429 + __be32 cqn; 430 + }; 431 + 432 + struct mlx5_eqe_qp_srq { 433 + __be32 reserved[6]; 434 + __be32 qp_srq_n; 435 + }; 436 + 437 + struct mlx5_eqe_cq_err { 438 + __be32 cqn; 439 + u8 reserved1[7]; 440 + u8 syndrome; 441 + }; 442 + 443 + struct mlx5_eqe_dropped_packet { 444 + }; 445 + 446 + struct mlx5_eqe_port_state { 447 + u8 reserved0[8]; 448 + u8 port; 449 + }; 450 + 451 + struct mlx5_eqe_gpio { 452 + __be32 reserved0[2]; 453 + __be64 gpio_event; 454 + }; 455 + 456 + struct mlx5_eqe_congestion { 457 + u8 type; 458 + u8 rsvd0; 459 + u8 congestion_level; 460 + }; 461 + 462 + struct mlx5_eqe_stall_vl { 463 + u8 rsvd0[3]; 464 + u8 port_vl; 465 + }; 466 + 467 + struct mlx5_eqe_cmd { 468 + __be32 vector; 469 + __be32 rsvd[6]; 470 + }; 471 + 472 + struct mlx5_eqe_page_req { 473 + u8 rsvd0[2]; 474 + __be16 func_id; 475 + u8 rsvd1[2]; 476 + __be16 num_pages; 477 + __be32 rsvd2[5]; 478 + }; 479 + 480 + union ev_data { 481 + __be32 raw[7]; 482 + struct mlx5_eqe_cmd cmd; 483 + struct mlx5_eqe_comp comp; 484 + struct mlx5_eqe_qp_srq qp_srq; 485 + struct mlx5_eqe_cq_err cq_err; 486 + struct mlx5_eqe_dropped_packet dp; 487 + struct mlx5_eqe_port_state port; 488 + struct mlx5_eqe_gpio gpio; 489 + struct mlx5_eqe_congestion cong; 490 + struct mlx5_eqe_stall_vl stall_vl; 491 + struct mlx5_eqe_page_req req_pages; 492 + } __packed; 493 + 494 + struct mlx5_eqe { 495 + u8 rsvd0; 496 + u8 type; 497 + u8 rsvd1; 498 + u8 sub_type; 499 + __be32 rsvd2[7]; 500 + union ev_data data; 501 + __be16 rsvd3; 502 + u8 signature; 503 + u8 owner; 504 + } __packed; 505 + 506 + struct mlx5_cmd_prot_block { 507 + u8 data[MLX5_CMD_DATA_BLOCK_SIZE]; 508 + u8 rsvd0[48]; 509 + __be64 next; 510 + __be32 block_num; 511 + u8 rsvd1; 512 + u8 token; 513 + u8 ctrl_sig; 514 + u8 sig; 515 + }; 516 + 517 + struct mlx5_err_cqe { 518 + u8 rsvd0[32]; 519 + __be32 srqn; 520 + u8 rsvd1[18]; 521 + u8 vendor_err_synd; 522 + u8 syndrome; 523 + __be32 s_wqe_opcode_qpn; 524 + __be16 wqe_counter; 525 + u8 signature; 526 + u8 op_own; 527 + }; 528 + 529 + struct mlx5_cqe64 { 530 + u8 rsvd0[17]; 531 + u8 ml_path; 532 + u8 rsvd20[4]; 533 + __be16 slid; 534 + __be32 flags_rqpn; 535 + u8 rsvd28[4]; 536 + __be32 srqn; 537 + __be32 imm_inval_pkey; 538 + u8 rsvd40[4]; 539 + __be32 byte_cnt; 540 + __be64 timestamp; 541 + __be32 sop_drop_qpn; 542 + __be16 wqe_counter; 543 + u8 signature; 544 + u8 op_own; 545 + }; 546 + 547 + struct mlx5_wqe_srq_next_seg { 548 + u8 rsvd0[2]; 549 + __be16 next_wqe_index; 550 + u8 signature; 551 + u8 rsvd1[11]; 552 + }; 553 + 554 + union mlx5_ext_cqe { 555 + struct ib_grh grh; 556 + u8 inl[64]; 557 + }; 558 + 559 + struct mlx5_cqe128 { 560 + union mlx5_ext_cqe inl_grh; 561 + struct mlx5_cqe64 cqe64; 562 + }; 563 + 564 + struct mlx5_srq_ctx { 565 + u8 state_log_sz; 566 + u8 rsvd0[3]; 567 + __be32 flags_xrcd; 568 + __be32 pgoff_cqn; 569 + u8 rsvd1[4]; 570 + u8 log_pg_sz; 571 + u8 rsvd2[7]; 572 + __be32 pd; 573 + __be16 lwm; 574 + __be16 wqe_cnt; 575 + u8 rsvd3[8]; 576 + __be64 db_record; 577 + }; 578 + 579 + struct mlx5_create_srq_mbox_in { 580 + struct mlx5_inbox_hdr hdr; 581 + __be32 input_srqn; 582 + u8 rsvd0[4]; 583 + struct mlx5_srq_ctx ctx; 584 + u8 rsvd1[208]; 585 + __be64 pas[0]; 586 + }; 587 + 588 + struct mlx5_create_srq_mbox_out { 589 + struct mlx5_outbox_hdr hdr; 590 + __be32 srqn; 591 + u8 rsvd[4]; 592 + }; 593 + 594 + struct mlx5_destroy_srq_mbox_in { 595 + struct mlx5_inbox_hdr hdr; 596 + __be32 srqn; 597 + u8 rsvd[4]; 598 + }; 599 + 600 + struct mlx5_destroy_srq_mbox_out { 601 + struct mlx5_outbox_hdr hdr; 602 + u8 rsvd[8]; 603 + }; 604 + 605 + struct mlx5_query_srq_mbox_in { 606 + struct mlx5_inbox_hdr hdr; 607 + __be32 srqn; 608 + u8 rsvd0[4]; 609 + }; 610 + 611 + struct mlx5_query_srq_mbox_out { 612 + struct mlx5_outbox_hdr hdr; 613 + u8 rsvd0[8]; 614 + struct mlx5_srq_ctx ctx; 615 + u8 rsvd1[32]; 616 + __be64 pas[0]; 617 + }; 618 + 619 + struct mlx5_arm_srq_mbox_in { 620 + struct mlx5_inbox_hdr hdr; 621 + __be32 srqn; 622 + __be16 rsvd; 623 + __be16 lwm; 624 + }; 625 + 626 + struct mlx5_arm_srq_mbox_out { 627 + struct mlx5_outbox_hdr hdr; 628 + u8 rsvd[8]; 629 + }; 630 + 631 + struct mlx5_cq_context { 632 + u8 status; 633 + u8 cqe_sz_flags; 634 + u8 st; 635 + u8 rsvd3; 636 + u8 rsvd4[6]; 637 + __be16 page_offset; 638 + __be32 log_sz_usr_page; 639 + __be16 cq_period; 640 + __be16 cq_max_count; 641 + __be16 rsvd20; 642 + __be16 c_eqn; 643 + u8 log_pg_sz; 644 + u8 rsvd25[7]; 645 + __be32 last_notified_index; 646 + __be32 solicit_producer_index; 647 + __be32 consumer_counter; 648 + __be32 producer_counter; 649 + u8 rsvd48[8]; 650 + __be64 db_record_addr; 651 + }; 652 + 653 + struct mlx5_create_cq_mbox_in { 654 + struct mlx5_inbox_hdr hdr; 655 + __be32 input_cqn; 656 + u8 rsvdx[4]; 657 + struct mlx5_cq_context ctx; 658 + u8 rsvd6[192]; 659 + __be64 pas[0]; 660 + }; 661 + 662 + struct mlx5_create_cq_mbox_out { 663 + struct mlx5_outbox_hdr hdr; 664 + __be32 cqn; 665 + u8 rsvd0[4]; 666 + }; 667 + 668 + struct mlx5_destroy_cq_mbox_in { 669 + struct mlx5_inbox_hdr hdr; 670 + __be32 cqn; 671 + u8 rsvd0[4]; 672 + }; 673 + 674 + struct mlx5_destroy_cq_mbox_out { 675 + struct mlx5_outbox_hdr hdr; 676 + u8 rsvd0[8]; 677 + }; 678 + 679 + struct mlx5_query_cq_mbox_in { 680 + struct mlx5_inbox_hdr hdr; 681 + __be32 cqn; 682 + u8 rsvd0[4]; 683 + }; 684 + 685 + struct mlx5_query_cq_mbox_out { 686 + struct mlx5_outbox_hdr hdr; 687 + u8 rsvd0[8]; 688 + struct mlx5_cq_context ctx; 689 + u8 rsvd6[16]; 690 + __be64 pas[0]; 691 + }; 692 + 693 + struct mlx5_eq_context { 694 + u8 status; 695 + u8 ec_oi; 696 + u8 st; 697 + u8 rsvd2[7]; 698 + __be16 page_pffset; 699 + __be32 log_sz_usr_page; 700 + u8 rsvd3[7]; 701 + u8 intr; 702 + u8 log_page_size; 703 + u8 rsvd4[15]; 704 + __be32 consumer_counter; 705 + __be32 produser_counter; 706 + u8 rsvd5[16]; 707 + }; 708 + 709 + struct mlx5_create_eq_mbox_in { 710 + struct mlx5_inbox_hdr hdr; 711 + u8 rsvd0[3]; 712 + u8 input_eqn; 713 + u8 rsvd1[4]; 714 + struct mlx5_eq_context ctx; 715 + u8 rsvd2[8]; 716 + __be64 events_mask; 717 + u8 rsvd3[176]; 718 + __be64 pas[0]; 719 + }; 720 + 721 + struct mlx5_create_eq_mbox_out { 722 + struct mlx5_outbox_hdr hdr; 723 + u8 rsvd0[3]; 724 + u8 eq_number; 725 + u8 rsvd1[4]; 726 + }; 727 + 728 + struct mlx5_destroy_eq_mbox_in { 729 + struct mlx5_inbox_hdr hdr; 730 + u8 rsvd0[3]; 731 + u8 eqn; 732 + u8 rsvd1[4]; 733 + }; 734 + 735 + struct mlx5_destroy_eq_mbox_out { 736 + struct mlx5_outbox_hdr hdr; 737 + u8 rsvd[8]; 738 + }; 739 + 740 + struct mlx5_map_eq_mbox_in { 741 + struct mlx5_inbox_hdr hdr; 742 + __be64 mask; 743 + u8 mu; 744 + u8 rsvd0[2]; 745 + u8 eqn; 746 + u8 rsvd1[24]; 747 + }; 748 + 749 + struct mlx5_map_eq_mbox_out { 750 + struct mlx5_outbox_hdr hdr; 751 + u8 rsvd[8]; 752 + }; 753 + 754 + struct mlx5_query_eq_mbox_in { 755 + struct mlx5_inbox_hdr hdr; 756 + u8 rsvd0[3]; 757 + u8 eqn; 758 + u8 rsvd1[4]; 759 + }; 760 + 761 + struct mlx5_query_eq_mbox_out { 762 + struct mlx5_outbox_hdr hdr; 763 + u8 rsvd[8]; 764 + struct mlx5_eq_context ctx; 765 + }; 766 + 767 + struct mlx5_mkey_seg { 768 + /* This is a two bit field occupying bits 31-30. 769 + * bit 31 is always 0, 770 + * bit 30 is zero for regular MRs and 1 (e.g free) for UMRs that do not have tanslation 771 + */ 772 + u8 status; 773 + u8 pcie_control; 774 + u8 flags; 775 + u8 version; 776 + __be32 qpn_mkey7_0; 777 + u8 rsvd1[4]; 778 + __be32 flags_pd; 779 + __be64 start_addr; 780 + __be64 len; 781 + __be32 bsfs_octo_size; 782 + u8 rsvd2[16]; 783 + __be32 xlt_oct_size; 784 + u8 rsvd3[3]; 785 + u8 log2_page_size; 786 + u8 rsvd4[4]; 787 + }; 788 + 789 + struct mlx5_query_special_ctxs_mbox_in { 790 + struct mlx5_inbox_hdr hdr; 791 + u8 rsvd[8]; 792 + }; 793 + 794 + struct mlx5_query_special_ctxs_mbox_out { 795 + struct mlx5_outbox_hdr hdr; 796 + __be32 dump_fill_mkey; 797 + __be32 reserved_lkey; 798 + }; 799 + 800 + struct mlx5_create_mkey_mbox_in { 801 + struct mlx5_inbox_hdr hdr; 802 + __be32 input_mkey_index; 803 + u8 rsvd0[4]; 804 + struct mlx5_mkey_seg seg; 805 + u8 rsvd1[16]; 806 + __be32 xlat_oct_act_size; 807 + __be32 bsf_coto_act_size; 808 + u8 rsvd2[168]; 809 + __be64 pas[0]; 810 + }; 811 + 812 + struct mlx5_create_mkey_mbox_out { 813 + struct mlx5_outbox_hdr hdr; 814 + __be32 mkey; 815 + u8 rsvd[4]; 816 + }; 817 + 818 + struct mlx5_destroy_mkey_mbox_in { 819 + struct mlx5_inbox_hdr hdr; 820 + __be32 mkey; 821 + u8 rsvd[4]; 822 + }; 823 + 824 + struct mlx5_destroy_mkey_mbox_out { 825 + struct mlx5_outbox_hdr hdr; 826 + u8 rsvd[8]; 827 + }; 828 + 829 + struct mlx5_query_mkey_mbox_in { 830 + struct mlx5_inbox_hdr hdr; 831 + __be32 mkey; 832 + }; 833 + 834 + struct mlx5_query_mkey_mbox_out { 835 + struct mlx5_outbox_hdr hdr; 836 + __be64 pas[0]; 837 + }; 838 + 839 + struct mlx5_modify_mkey_mbox_in { 840 + struct mlx5_inbox_hdr hdr; 841 + __be32 mkey; 842 + __be64 pas[0]; 843 + }; 844 + 845 + struct mlx5_modify_mkey_mbox_out { 846 + struct mlx5_outbox_hdr hdr; 847 + }; 848 + 849 + struct mlx5_dump_mkey_mbox_in { 850 + struct mlx5_inbox_hdr hdr; 851 + }; 852 + 853 + struct mlx5_dump_mkey_mbox_out { 854 + struct mlx5_outbox_hdr hdr; 855 + __be32 mkey; 856 + }; 857 + 858 + struct mlx5_mad_ifc_mbox_in { 859 + struct mlx5_inbox_hdr hdr; 860 + __be16 remote_lid; 861 + u8 rsvd0; 862 + u8 port; 863 + u8 rsvd1[4]; 864 + u8 data[256]; 865 + }; 866 + 867 + struct mlx5_mad_ifc_mbox_out { 868 + struct mlx5_outbox_hdr hdr; 869 + u8 rsvd[8]; 870 + u8 data[256]; 871 + }; 872 + 873 + struct mlx5_access_reg_mbox_in { 874 + struct mlx5_inbox_hdr hdr; 875 + u8 rsvd0[2]; 876 + __be16 register_id; 877 + __be32 arg; 878 + __be32 data[0]; 879 + }; 880 + 881 + struct mlx5_access_reg_mbox_out { 882 + struct mlx5_outbox_hdr hdr; 883 + u8 rsvd[8]; 884 + __be32 data[0]; 885 + }; 886 + 887 + #define MLX5_ATTR_EXTENDED_PORT_INFO cpu_to_be16(0xff90) 888 + 889 + enum { 890 + MLX_EXT_PORT_CAP_FLAG_EXTENDED_PORT_INFO = 1 << 0 891 + }; 892 + 893 + #endif /* MLX5_DEVICE_H */
+79
include/linux/mlx5/doorbell.h
··· 1 + /* 2 + * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved. 3 + * 4 + * This software is available to you under a choice of one of two 5 + * licenses. You may choose to be licensed under the terms of the GNU 6 + * General Public License (GPL) Version 2, available from the file 7 + * COPYING in the main directory of this source tree, or the 8 + * OpenIB.org BSD license below: 9 + * 10 + * Redistribution and use in source and binary forms, with or 11 + * without modification, are permitted provided that the following 12 + * conditions are met: 13 + * 14 + * - Redistributions of source code must retain the above 15 + * copyright notice, this list of conditions and the following 16 + * disclaimer. 17 + * 18 + * - Redistributions in binary form must reproduce the above 19 + * copyright notice, this list of conditions and the following 20 + * disclaimer in the documentation and/or other materials 21 + * 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 OF 25 + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26 + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 27 + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 28 + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29 + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30 + * SOFTWARE. 31 + */ 32 + 33 + #ifndef MLX5_DOORBELL_H 34 + #define MLX5_DOORBELL_H 35 + 36 + #define MLX5_BF_OFFSET 0x800 37 + #define MLX5_CQ_DOORBELL 0x20 38 + 39 + #if BITS_PER_LONG == 64 40 + /* Assume that we can just write a 64-bit doorbell atomically. s390 41 + * actually doesn't have writeq() but S/390 systems don't even have 42 + * PCI so we won't worry about it. 43 + */ 44 + 45 + #define MLX5_DECLARE_DOORBELL_LOCK(name) 46 + #define MLX5_INIT_DOORBELL_LOCK(ptr) do { } while (0) 47 + #define MLX5_GET_DOORBELL_LOCK(ptr) (NULL) 48 + 49 + static inline void mlx5_write64(__be32 val[2], void __iomem *dest, 50 + spinlock_t *doorbell_lock) 51 + { 52 + __raw_writeq(*(u64 *)val, dest); 53 + } 54 + 55 + #else 56 + 57 + /* Just fall back to a spinlock to protect the doorbell if 58 + * BITS_PER_LONG is 32 -- there's no portable way to do atomic 64-bit 59 + * MMIO writes. 60 + */ 61 + 62 + #define MLX5_DECLARE_DOORBELL_LOCK(name) spinlock_t name; 63 + #define MLX5_INIT_DOORBELL_LOCK(ptr) spin_lock_init(ptr) 64 + #define MLX5_GET_DOORBELL_LOCK(ptr) (ptr) 65 + 66 + static inline void mlx5_write64(__be32 val[2], void __iomem *dest, 67 + spinlock_t *doorbell_lock) 68 + { 69 + unsigned long flags; 70 + 71 + spin_lock_irqsave(doorbell_lock, flags); 72 + __raw_writel((__force u32) val[0], dest); 73 + __raw_writel((__force u32) val[1], dest + 4); 74 + spin_unlock_irqrestore(doorbell_lock, flags); 75 + } 76 + 77 + #endif 78 + 79 + #endif /* MLX5_DOORBELL_H */
+769
include/linux/mlx5/driver.h
··· 1 + /* 2 + * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved. 3 + * 4 + * This software is available to you under a choice of one of two 5 + * licenses. You may choose to be licensed under the terms of the GNU 6 + * General Public License (GPL) Version 2, available from the file 7 + * COPYING in the main directory of this source tree, or the 8 + * OpenIB.org BSD license below: 9 + * 10 + * Redistribution and use in source and binary forms, with or 11 + * without modification, are permitted provided that the following 12 + * conditions are met: 13 + * 14 + * - Redistributions of source code must retain the above 15 + * copyright notice, this list of conditions and the following 16 + * disclaimer. 17 + * 18 + * - Redistributions in binary form must reproduce the above 19 + * copyright notice, this list of conditions and the following 20 + * disclaimer in the documentation and/or other materials 21 + * 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 OF 25 + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26 + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 27 + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 28 + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29 + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30 + * SOFTWARE. 31 + */ 32 + 33 + #ifndef MLX5_DRIVER_H 34 + #define MLX5_DRIVER_H 35 + 36 + #include <linux/kernel.h> 37 + #include <linux/completion.h> 38 + #include <linux/pci.h> 39 + #include <linux/spinlock_types.h> 40 + #include <linux/semaphore.h> 41 + #include <linux/vmalloc.h> 42 + #include <linux/radix-tree.h> 43 + #include <linux/mlx5/device.h> 44 + #include <linux/mlx5/doorbell.h> 45 + 46 + enum { 47 + MLX5_BOARD_ID_LEN = 64, 48 + MLX5_MAX_NAME_LEN = 16, 49 + }; 50 + 51 + enum { 52 + /* one minute for the sake of bringup. Generally, commands must always 53 + * complete and we may need to increase this timeout value 54 + */ 55 + MLX5_CMD_TIMEOUT_MSEC = 7200 * 1000, 56 + MLX5_CMD_WQ_MAX_NAME = 32, 57 + }; 58 + 59 + enum { 60 + CMD_OWNER_SW = 0x0, 61 + CMD_OWNER_HW = 0x1, 62 + CMD_STATUS_SUCCESS = 0, 63 + }; 64 + 65 + enum mlx5_sqp_t { 66 + MLX5_SQP_SMI = 0, 67 + MLX5_SQP_GSI = 1, 68 + MLX5_SQP_IEEE_1588 = 2, 69 + MLX5_SQP_SNIFFER = 3, 70 + MLX5_SQP_SYNC_UMR = 4, 71 + }; 72 + 73 + enum { 74 + MLX5_MAX_PORTS = 2, 75 + }; 76 + 77 + enum { 78 + MLX5_EQ_VEC_PAGES = 0, 79 + MLX5_EQ_VEC_CMD = 1, 80 + MLX5_EQ_VEC_ASYNC = 2, 81 + MLX5_EQ_VEC_COMP_BASE, 82 + }; 83 + 84 + enum { 85 + MLX5_MAX_EQ_NAME = 20 86 + }; 87 + 88 + enum { 89 + MLX5_ATOMIC_MODE_IB_COMP = 1 << 16, 90 + MLX5_ATOMIC_MODE_CX = 2 << 16, 91 + MLX5_ATOMIC_MODE_8B = 3 << 16, 92 + MLX5_ATOMIC_MODE_16B = 4 << 16, 93 + MLX5_ATOMIC_MODE_32B = 5 << 16, 94 + MLX5_ATOMIC_MODE_64B = 6 << 16, 95 + MLX5_ATOMIC_MODE_128B = 7 << 16, 96 + MLX5_ATOMIC_MODE_256B = 8 << 16, 97 + }; 98 + 99 + enum { 100 + MLX5_CMD_OP_QUERY_HCA_CAP = 0x100, 101 + MLX5_CMD_OP_QUERY_ADAPTER = 0x101, 102 + MLX5_CMD_OP_INIT_HCA = 0x102, 103 + MLX5_CMD_OP_TEARDOWN_HCA = 0x103, 104 + MLX5_CMD_OP_QUERY_PAGES = 0x107, 105 + MLX5_CMD_OP_MANAGE_PAGES = 0x108, 106 + MLX5_CMD_OP_SET_HCA_CAP = 0x109, 107 + 108 + MLX5_CMD_OP_CREATE_MKEY = 0x200, 109 + MLX5_CMD_OP_QUERY_MKEY = 0x201, 110 + MLX5_CMD_OP_DESTROY_MKEY = 0x202, 111 + MLX5_CMD_OP_QUERY_SPECIAL_CONTEXTS = 0x203, 112 + 113 + MLX5_CMD_OP_CREATE_EQ = 0x301, 114 + MLX5_CMD_OP_DESTROY_EQ = 0x302, 115 + MLX5_CMD_OP_QUERY_EQ = 0x303, 116 + 117 + MLX5_CMD_OP_CREATE_CQ = 0x400, 118 + MLX5_CMD_OP_DESTROY_CQ = 0x401, 119 + MLX5_CMD_OP_QUERY_CQ = 0x402, 120 + MLX5_CMD_OP_MODIFY_CQ = 0x403, 121 + 122 + MLX5_CMD_OP_CREATE_QP = 0x500, 123 + MLX5_CMD_OP_DESTROY_QP = 0x501, 124 + MLX5_CMD_OP_RST2INIT_QP = 0x502, 125 + MLX5_CMD_OP_INIT2RTR_QP = 0x503, 126 + MLX5_CMD_OP_RTR2RTS_QP = 0x504, 127 + MLX5_CMD_OP_RTS2RTS_QP = 0x505, 128 + MLX5_CMD_OP_SQERR2RTS_QP = 0x506, 129 + MLX5_CMD_OP_2ERR_QP = 0x507, 130 + MLX5_CMD_OP_RTS2SQD_QP = 0x508, 131 + MLX5_CMD_OP_SQD2RTS_QP = 0x509, 132 + MLX5_CMD_OP_2RST_QP = 0x50a, 133 + MLX5_CMD_OP_QUERY_QP = 0x50b, 134 + MLX5_CMD_OP_CONF_SQP = 0x50c, 135 + MLX5_CMD_OP_MAD_IFC = 0x50d, 136 + MLX5_CMD_OP_INIT2INIT_QP = 0x50e, 137 + MLX5_CMD_OP_SUSPEND_QP = 0x50f, 138 + MLX5_CMD_OP_UNSUSPEND_QP = 0x510, 139 + MLX5_CMD_OP_SQD2SQD_QP = 0x511, 140 + MLX5_CMD_OP_ALLOC_QP_COUNTER_SET = 0x512, 141 + MLX5_CMD_OP_DEALLOC_QP_COUNTER_SET = 0x513, 142 + MLX5_CMD_OP_QUERY_QP_COUNTER_SET = 0x514, 143 + 144 + MLX5_CMD_OP_CREATE_PSV = 0x600, 145 + MLX5_CMD_OP_DESTROY_PSV = 0x601, 146 + MLX5_CMD_OP_QUERY_PSV = 0x602, 147 + MLX5_CMD_OP_QUERY_SIG_RULE_TABLE = 0x603, 148 + MLX5_CMD_OP_QUERY_BLOCK_SIZE_TABLE = 0x604, 149 + 150 + MLX5_CMD_OP_CREATE_SRQ = 0x700, 151 + MLX5_CMD_OP_DESTROY_SRQ = 0x701, 152 + MLX5_CMD_OP_QUERY_SRQ = 0x702, 153 + MLX5_CMD_OP_ARM_RQ = 0x703, 154 + MLX5_CMD_OP_RESIZE_SRQ = 0x704, 155 + 156 + MLX5_CMD_OP_ALLOC_PD = 0x800, 157 + MLX5_CMD_OP_DEALLOC_PD = 0x801, 158 + MLX5_CMD_OP_ALLOC_UAR = 0x802, 159 + MLX5_CMD_OP_DEALLOC_UAR = 0x803, 160 + 161 + MLX5_CMD_OP_ATTACH_TO_MCG = 0x806, 162 + MLX5_CMD_OP_DETACH_FROM_MCG = 0x807, 163 + 164 + 165 + MLX5_CMD_OP_ALLOC_XRCD = 0x80e, 166 + MLX5_CMD_OP_DEALLOC_XRCD = 0x80f, 167 + 168 + MLX5_CMD_OP_ACCESS_REG = 0x805, 169 + MLX5_CMD_OP_MAX = 0x810, 170 + }; 171 + 172 + enum { 173 + MLX5_REG_PCAP = 0x5001, 174 + MLX5_REG_PMTU = 0x5003, 175 + MLX5_REG_PTYS = 0x5004, 176 + MLX5_REG_PAOS = 0x5006, 177 + MLX5_REG_PMAOS = 0x5012, 178 + MLX5_REG_PUDE = 0x5009, 179 + MLX5_REG_PMPE = 0x5010, 180 + MLX5_REG_PELC = 0x500e, 181 + MLX5_REG_PMLP = 0, /* TBD */ 182 + MLX5_REG_NODE_DESC = 0x6001, 183 + MLX5_REG_HOST_ENDIANNESS = 0x7004, 184 + }; 185 + 186 + enum dbg_rsc_type { 187 + MLX5_DBG_RSC_QP, 188 + MLX5_DBG_RSC_EQ, 189 + MLX5_DBG_RSC_CQ, 190 + }; 191 + 192 + struct mlx5_field_desc { 193 + struct dentry *dent; 194 + int i; 195 + }; 196 + 197 + struct mlx5_rsc_debug { 198 + struct mlx5_core_dev *dev; 199 + void *object; 200 + enum dbg_rsc_type type; 201 + struct dentry *root; 202 + struct mlx5_field_desc fields[0]; 203 + }; 204 + 205 + enum mlx5_dev_event { 206 + MLX5_DEV_EVENT_SYS_ERROR, 207 + MLX5_DEV_EVENT_PORT_UP, 208 + MLX5_DEV_EVENT_PORT_DOWN, 209 + MLX5_DEV_EVENT_PORT_INITIALIZED, 210 + MLX5_DEV_EVENT_LID_CHANGE, 211 + MLX5_DEV_EVENT_PKEY_CHANGE, 212 + MLX5_DEV_EVENT_GUID_CHANGE, 213 + MLX5_DEV_EVENT_CLIENT_REREG, 214 + }; 215 + 216 + struct mlx5_uuar_info { 217 + struct mlx5_uar *uars; 218 + int num_uars; 219 + int num_low_latency_uuars; 220 + unsigned long *bitmap; 221 + unsigned int *count; 222 + struct mlx5_bf *bfs; 223 + 224 + /* 225 + * protect uuar allocation data structs 226 + */ 227 + struct mutex lock; 228 + }; 229 + 230 + struct mlx5_bf { 231 + void __iomem *reg; 232 + void __iomem *regreg; 233 + int buf_size; 234 + struct mlx5_uar *uar; 235 + unsigned long offset; 236 + int need_lock; 237 + /* protect blue flame buffer selection when needed 238 + */ 239 + spinlock_t lock; 240 + 241 + /* serialize 64 bit writes when done as two 32 bit accesses 242 + */ 243 + spinlock_t lock32; 244 + int uuarn; 245 + }; 246 + 247 + struct mlx5_cmd_first { 248 + __be32 data[4]; 249 + }; 250 + 251 + struct mlx5_cmd_msg { 252 + struct list_head list; 253 + struct cache_ent *cache; 254 + u32 len; 255 + struct mlx5_cmd_first first; 256 + struct mlx5_cmd_mailbox *next; 257 + }; 258 + 259 + struct mlx5_cmd_debug { 260 + struct dentry *dbg_root; 261 + struct dentry *dbg_in; 262 + struct dentry *dbg_out; 263 + struct dentry *dbg_outlen; 264 + struct dentry *dbg_status; 265 + struct dentry *dbg_run; 266 + void *in_msg; 267 + void *out_msg; 268 + u8 status; 269 + u16 inlen; 270 + u16 outlen; 271 + }; 272 + 273 + struct cache_ent { 274 + /* protect block chain allocations 275 + */ 276 + spinlock_t lock; 277 + struct list_head head; 278 + }; 279 + 280 + struct cmd_msg_cache { 281 + struct cache_ent large; 282 + struct cache_ent med; 283 + 284 + }; 285 + 286 + struct mlx5_cmd_stats { 287 + u64 sum; 288 + u64 n; 289 + struct dentry *root; 290 + struct dentry *avg; 291 + struct dentry *count; 292 + /* protect command average calculations */ 293 + spinlock_t lock; 294 + }; 295 + 296 + struct mlx5_cmd { 297 + void *cmd_buf; 298 + dma_addr_t dma; 299 + u16 cmdif_rev; 300 + u8 log_sz; 301 + u8 log_stride; 302 + int max_reg_cmds; 303 + int events; 304 + u32 __iomem *vector; 305 + 306 + /* protect command queue allocations 307 + */ 308 + spinlock_t alloc_lock; 309 + 310 + /* protect token allocations 311 + */ 312 + spinlock_t token_lock; 313 + u8 token; 314 + unsigned long bitmask; 315 + char wq_name[MLX5_CMD_WQ_MAX_NAME]; 316 + struct workqueue_struct *wq; 317 + struct semaphore sem; 318 + struct semaphore pages_sem; 319 + int mode; 320 + struct mlx5_cmd_work_ent *ent_arr[MLX5_MAX_COMMANDS]; 321 + struct pci_pool *pool; 322 + struct mlx5_cmd_debug dbg; 323 + struct cmd_msg_cache cache; 324 + int checksum_disabled; 325 + struct mlx5_cmd_stats stats[MLX5_CMD_OP_MAX]; 326 + }; 327 + 328 + struct mlx5_port_caps { 329 + int gid_table_len; 330 + int pkey_table_len; 331 + }; 332 + 333 + struct mlx5_caps { 334 + u8 log_max_eq; 335 + u8 log_max_cq; 336 + u8 log_max_qp; 337 + u8 log_max_mkey; 338 + u8 log_max_pd; 339 + u8 log_max_srq; 340 + u32 max_cqes; 341 + int max_wqes; 342 + int max_sq_desc_sz; 343 + int max_rq_desc_sz; 344 + u64 flags; 345 + u16 stat_rate_support; 346 + int log_max_msg; 347 + int num_ports; 348 + int max_ra_res_qp; 349 + int max_ra_req_qp; 350 + int max_srq_wqes; 351 + int bf_reg_size; 352 + int bf_regs_per_page; 353 + struct mlx5_port_caps port[MLX5_MAX_PORTS]; 354 + u8 ext_port_cap[MLX5_MAX_PORTS]; 355 + int max_vf; 356 + u32 reserved_lkey; 357 + u8 local_ca_ack_delay; 358 + u8 log_max_mcg; 359 + u16 max_qp_mcg; 360 + int min_page_sz; 361 + }; 362 + 363 + struct mlx5_cmd_mailbox { 364 + void *buf; 365 + dma_addr_t dma; 366 + struct mlx5_cmd_mailbox *next; 367 + }; 368 + 369 + struct mlx5_buf_list { 370 + void *buf; 371 + dma_addr_t map; 372 + }; 373 + 374 + struct mlx5_buf { 375 + struct mlx5_buf_list direct; 376 + struct mlx5_buf_list *page_list; 377 + int nbufs; 378 + int npages; 379 + int page_shift; 380 + int size; 381 + }; 382 + 383 + struct mlx5_eq { 384 + struct mlx5_core_dev *dev; 385 + __be32 __iomem *doorbell; 386 + u32 cons_index; 387 + struct mlx5_buf buf; 388 + int size; 389 + u8 irqn; 390 + u8 eqn; 391 + int nent; 392 + u64 mask; 393 + char name[MLX5_MAX_EQ_NAME]; 394 + struct list_head list; 395 + int index; 396 + struct mlx5_rsc_debug *dbg; 397 + }; 398 + 399 + 400 + struct mlx5_core_mr { 401 + u64 iova; 402 + u64 size; 403 + u32 key; 404 + u32 pd; 405 + u32 access; 406 + }; 407 + 408 + struct mlx5_core_srq { 409 + u32 srqn; 410 + int max; 411 + int max_gs; 412 + int max_avail_gather; 413 + int wqe_shift; 414 + void (*event) (struct mlx5_core_srq *, enum mlx5_event); 415 + 416 + atomic_t refcount; 417 + struct completion free; 418 + }; 419 + 420 + struct mlx5_eq_table { 421 + void __iomem *update_ci; 422 + void __iomem *update_arm_ci; 423 + struct list_head *comp_eq_head; 424 + struct mlx5_eq pages_eq; 425 + struct mlx5_eq async_eq; 426 + struct mlx5_eq cmd_eq; 427 + struct msix_entry *msix_arr; 428 + int num_comp_vectors; 429 + /* protect EQs list 430 + */ 431 + spinlock_t lock; 432 + }; 433 + 434 + struct mlx5_uar { 435 + u32 index; 436 + struct list_head bf_list; 437 + unsigned free_bf_bmap; 438 + void __iomem *wc_map; 439 + void __iomem *map; 440 + }; 441 + 442 + 443 + struct mlx5_core_health { 444 + struct health_buffer __iomem *health; 445 + __be32 __iomem *health_counter; 446 + struct timer_list timer; 447 + struct list_head list; 448 + u32 prev; 449 + int miss_counter; 450 + }; 451 + 452 + struct mlx5_cq_table { 453 + /* protect radix tree 454 + */ 455 + spinlock_t lock; 456 + struct radix_tree_root tree; 457 + }; 458 + 459 + struct mlx5_qp_table { 460 + /* protect radix tree 461 + */ 462 + spinlock_t lock; 463 + struct radix_tree_root tree; 464 + }; 465 + 466 + struct mlx5_srq_table { 467 + /* protect radix tree 468 + */ 469 + spinlock_t lock; 470 + struct radix_tree_root tree; 471 + }; 472 + 473 + struct mlx5_priv { 474 + char name[MLX5_MAX_NAME_LEN]; 475 + struct mlx5_eq_table eq_table; 476 + struct mlx5_uuar_info uuari; 477 + MLX5_DECLARE_DOORBELL_LOCK(cq_uar_lock); 478 + 479 + /* pages stuff */ 480 + struct workqueue_struct *pg_wq; 481 + struct rb_root page_root; 482 + int fw_pages; 483 + int reg_pages; 484 + 485 + struct mlx5_core_health health; 486 + 487 + struct mlx5_srq_table srq_table; 488 + 489 + /* start: qp staff */ 490 + struct mlx5_qp_table qp_table; 491 + struct dentry *qp_debugfs; 492 + struct dentry *eq_debugfs; 493 + struct dentry *cq_debugfs; 494 + struct dentry *cmdif_debugfs; 495 + /* end: qp staff */ 496 + 497 + /* start: cq staff */ 498 + struct mlx5_cq_table cq_table; 499 + /* end: cq staff */ 500 + 501 + /* start: alloc staff */ 502 + struct mutex pgdir_mutex; 503 + struct list_head pgdir_list; 504 + /* end: alloc staff */ 505 + struct dentry *dbg_root; 506 + 507 + /* protect mkey key part */ 508 + spinlock_t mkey_lock; 509 + u8 mkey_key; 510 + }; 511 + 512 + struct mlx5_core_dev { 513 + struct pci_dev *pdev; 514 + u8 rev_id; 515 + char board_id[MLX5_BOARD_ID_LEN]; 516 + struct mlx5_cmd cmd; 517 + struct mlx5_caps caps; 518 + phys_addr_t iseg_base; 519 + struct mlx5_init_seg __iomem *iseg; 520 + void (*event) (struct mlx5_core_dev *dev, 521 + enum mlx5_dev_event event, 522 + void *data); 523 + struct mlx5_priv priv; 524 + struct mlx5_profile *profile; 525 + atomic_t num_qps; 526 + }; 527 + 528 + struct mlx5_db { 529 + __be32 *db; 530 + union { 531 + struct mlx5_db_pgdir *pgdir; 532 + struct mlx5_ib_user_db_page *user_page; 533 + } u; 534 + dma_addr_t dma; 535 + int index; 536 + }; 537 + 538 + enum { 539 + MLX5_DB_PER_PAGE = PAGE_SIZE / L1_CACHE_BYTES, 540 + }; 541 + 542 + enum { 543 + MLX5_COMP_EQ_SIZE = 1024, 544 + }; 545 + 546 + struct mlx5_db_pgdir { 547 + struct list_head list; 548 + DECLARE_BITMAP(bitmap, MLX5_DB_PER_PAGE); 549 + __be32 *db_page; 550 + dma_addr_t db_dma; 551 + }; 552 + 553 + typedef void (*mlx5_cmd_cbk_t)(int status, void *context); 554 + 555 + struct mlx5_cmd_work_ent { 556 + struct mlx5_cmd_msg *in; 557 + struct mlx5_cmd_msg *out; 558 + mlx5_cmd_cbk_t callback; 559 + void *context; 560 + int idx; 561 + struct completion done; 562 + struct mlx5_cmd *cmd; 563 + struct work_struct work; 564 + struct mlx5_cmd_layout *lay; 565 + int ret; 566 + int page_queue; 567 + u8 status; 568 + u8 token; 569 + struct timespec ts1; 570 + struct timespec ts2; 571 + }; 572 + 573 + struct mlx5_pas { 574 + u64 pa; 575 + u8 log_sz; 576 + }; 577 + 578 + static inline void *mlx5_buf_offset(struct mlx5_buf *buf, int offset) 579 + { 580 + if (likely(BITS_PER_LONG == 64 || buf->nbufs == 1)) 581 + return buf->direct.buf + offset; 582 + else 583 + return buf->page_list[offset >> PAGE_SHIFT].buf + 584 + (offset & (PAGE_SIZE - 1)); 585 + } 586 + 587 + extern struct workqueue_struct *mlx5_core_wq; 588 + 589 + #define STRUCT_FIELD(header, field) \ 590 + .struct_offset_bytes = offsetof(struct ib_unpacked_ ## header, field), \ 591 + .struct_size_bytes = sizeof((struct ib_unpacked_ ## header *)0)->field 592 + 593 + struct ib_field { 594 + size_t struct_offset_bytes; 595 + size_t struct_size_bytes; 596 + int offset_bits; 597 + int size_bits; 598 + }; 599 + 600 + static inline struct mlx5_core_dev *pci2mlx5_core_dev(struct pci_dev *pdev) 601 + { 602 + return pci_get_drvdata(pdev); 603 + } 604 + 605 + extern struct dentry *mlx5_debugfs_root; 606 + 607 + static inline u16 fw_rev_maj(struct mlx5_core_dev *dev) 608 + { 609 + return ioread32be(&dev->iseg->fw_rev) & 0xffff; 610 + } 611 + 612 + static inline u16 fw_rev_min(struct mlx5_core_dev *dev) 613 + { 614 + return ioread32be(&dev->iseg->fw_rev) >> 16; 615 + } 616 + 617 + static inline u16 fw_rev_sub(struct mlx5_core_dev *dev) 618 + { 619 + return ioread32be(&dev->iseg->cmdif_rev_fw_sub) & 0xffff; 620 + } 621 + 622 + static inline u16 cmdif_rev(struct mlx5_core_dev *dev) 623 + { 624 + return ioread32be(&dev->iseg->cmdif_rev_fw_sub) >> 16; 625 + } 626 + 627 + static inline void *mlx5_vzalloc(unsigned long size) 628 + { 629 + void *rtn; 630 + 631 + rtn = kzalloc(size, GFP_KERNEL | __GFP_NOWARN); 632 + if (!rtn) 633 + rtn = vzalloc(size); 634 + return rtn; 635 + } 636 + 637 + static inline void mlx5_vfree(const void *addr) 638 + { 639 + if (addr && is_vmalloc_addr(addr)) 640 + vfree(addr); 641 + else 642 + kfree(addr); 643 + } 644 + 645 + int mlx5_dev_init(struct mlx5_core_dev *dev, struct pci_dev *pdev); 646 + void mlx5_dev_cleanup(struct mlx5_core_dev *dev); 647 + int mlx5_cmd_init(struct mlx5_core_dev *dev); 648 + void mlx5_cmd_cleanup(struct mlx5_core_dev *dev); 649 + void mlx5_cmd_use_events(struct mlx5_core_dev *dev); 650 + void mlx5_cmd_use_polling(struct mlx5_core_dev *dev); 651 + int mlx5_cmd_status_to_err(struct mlx5_outbox_hdr *hdr); 652 + int mlx5_cmd_exec(struct mlx5_core_dev *dev, void *in, int in_size, void *out, 653 + int out_size); 654 + int mlx5_cmd_alloc_uar(struct mlx5_core_dev *dev, u32 *uarn); 655 + int mlx5_cmd_free_uar(struct mlx5_core_dev *dev, u32 uarn); 656 + int mlx5_alloc_uuars(struct mlx5_core_dev *dev, struct mlx5_uuar_info *uuari); 657 + int mlx5_free_uuars(struct mlx5_core_dev *dev, struct mlx5_uuar_info *uuari); 658 + void mlx5_health_cleanup(void); 659 + void __init mlx5_health_init(void); 660 + void mlx5_start_health_poll(struct mlx5_core_dev *dev); 661 + void mlx5_stop_health_poll(struct mlx5_core_dev *dev); 662 + int mlx5_buf_alloc(struct mlx5_core_dev *dev, int size, int max_direct, 663 + struct mlx5_buf *buf); 664 + void mlx5_buf_free(struct mlx5_core_dev *dev, struct mlx5_buf *buf); 665 + struct mlx5_cmd_mailbox *mlx5_alloc_cmd_mailbox_chain(struct mlx5_core_dev *dev, 666 + gfp_t flags, int npages); 667 + void mlx5_free_cmd_mailbox_chain(struct mlx5_core_dev *dev, 668 + struct mlx5_cmd_mailbox *head); 669 + int mlx5_core_create_srq(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq, 670 + struct mlx5_create_srq_mbox_in *in, int inlen); 671 + int mlx5_core_destroy_srq(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq); 672 + int mlx5_core_query_srq(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq, 673 + struct mlx5_query_srq_mbox_out *out); 674 + int mlx5_core_arm_srq(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq, 675 + u16 lwm, int is_srq); 676 + int mlx5_core_create_mkey(struct mlx5_core_dev *dev, struct mlx5_core_mr *mr, 677 + struct mlx5_create_mkey_mbox_in *in, int inlen); 678 + int mlx5_core_destroy_mkey(struct mlx5_core_dev *dev, struct mlx5_core_mr *mr); 679 + int mlx5_core_query_mkey(struct mlx5_core_dev *dev, struct mlx5_core_mr *mr, 680 + struct mlx5_query_mkey_mbox_out *out, int outlen); 681 + int mlx5_core_dump_fill_mkey(struct mlx5_core_dev *dev, struct mlx5_core_mr *mr, 682 + u32 *mkey); 683 + int mlx5_core_alloc_pd(struct mlx5_core_dev *dev, u32 *pdn); 684 + int mlx5_core_dealloc_pd(struct mlx5_core_dev *dev, u32 pdn); 685 + int mlx5_core_mad_ifc(struct mlx5_core_dev *dev, void *inb, void *outb, 686 + u16 opmod, int port); 687 + void mlx5_pagealloc_init(struct mlx5_core_dev *dev); 688 + void mlx5_pagealloc_cleanup(struct mlx5_core_dev *dev); 689 + int mlx5_pagealloc_start(struct mlx5_core_dev *dev); 690 + void mlx5_pagealloc_stop(struct mlx5_core_dev *dev); 691 + void mlx5_core_req_pages_handler(struct mlx5_core_dev *dev, u16 func_id, 692 + s16 npages); 693 + int mlx5_satisfy_startup_pages(struct mlx5_core_dev *dev); 694 + int mlx5_reclaim_startup_pages(struct mlx5_core_dev *dev); 695 + void mlx5_register_debugfs(void); 696 + void mlx5_unregister_debugfs(void); 697 + int mlx5_eq_init(struct mlx5_core_dev *dev); 698 + void mlx5_eq_cleanup(struct mlx5_core_dev *dev); 699 + void mlx5_fill_page_array(struct mlx5_buf *buf, __be64 *pas); 700 + void mlx5_cq_completion(struct mlx5_core_dev *dev, u32 cqn); 701 + void mlx5_qp_event(struct mlx5_core_dev *dev, u32 qpn, int event_type); 702 + void mlx5_srq_event(struct mlx5_core_dev *dev, u32 srqn, int event_type); 703 + struct mlx5_core_srq *mlx5_core_get_srq(struct mlx5_core_dev *dev, u32 srqn); 704 + void mlx5_cmd_comp_handler(struct mlx5_core_dev *dev, unsigned long vector); 705 + void mlx5_cq_event(struct mlx5_core_dev *dev, u32 cqn, int event_type); 706 + int mlx5_create_map_eq(struct mlx5_core_dev *dev, struct mlx5_eq *eq, u8 vecidx, 707 + int nent, u64 mask, const char *name, struct mlx5_uar *uar); 708 + int mlx5_destroy_unmap_eq(struct mlx5_core_dev *dev, struct mlx5_eq *eq); 709 + int mlx5_start_eqs(struct mlx5_core_dev *dev); 710 + int mlx5_stop_eqs(struct mlx5_core_dev *dev); 711 + int mlx5_core_attach_mcg(struct mlx5_core_dev *dev, union ib_gid *mgid, u32 qpn); 712 + int mlx5_core_detach_mcg(struct mlx5_core_dev *dev, union ib_gid *mgid, u32 qpn); 713 + 714 + int mlx5_qp_debugfs_init(struct mlx5_core_dev *dev); 715 + void mlx5_qp_debugfs_cleanup(struct mlx5_core_dev *dev); 716 + int mlx5_core_access_reg(struct mlx5_core_dev *dev, void *data_in, 717 + int size_in, void *data_out, int size_out, 718 + u16 reg_num, int arg, int write); 719 + int mlx5_set_port_caps(struct mlx5_core_dev *dev, int port_num, u32 caps); 720 + 721 + int mlx5_debug_eq_add(struct mlx5_core_dev *dev, struct mlx5_eq *eq); 722 + void mlx5_debug_eq_remove(struct mlx5_core_dev *dev, struct mlx5_eq *eq); 723 + int mlx5_core_eq_query(struct mlx5_core_dev *dev, struct mlx5_eq *eq, 724 + struct mlx5_query_eq_mbox_out *out, int outlen); 725 + int mlx5_eq_debugfs_init(struct mlx5_core_dev *dev); 726 + void mlx5_eq_debugfs_cleanup(struct mlx5_core_dev *dev); 727 + int mlx5_cq_debugfs_init(struct mlx5_core_dev *dev); 728 + void mlx5_cq_debugfs_cleanup(struct mlx5_core_dev *dev); 729 + int mlx5_db_alloc(struct mlx5_core_dev *dev, struct mlx5_db *db); 730 + void mlx5_db_free(struct mlx5_core_dev *dev, struct mlx5_db *db); 731 + 732 + typedef void (*health_handler_t)(struct pci_dev *pdev, void *buf, int size); 733 + int mlx5_register_health_report_handler(health_handler_t handler); 734 + void mlx5_unregister_health_report_handler(void); 735 + const char *mlx5_command_str(int command); 736 + int mlx5_cmdif_debugfs_init(struct mlx5_core_dev *dev); 737 + void mlx5_cmdif_debugfs_cleanup(struct mlx5_core_dev *dev); 738 + 739 + static inline u32 mlx5_mkey_to_idx(u32 mkey) 740 + { 741 + return mkey >> 8; 742 + } 743 + 744 + static inline u32 mlx5_idx_to_mkey(u32 mkey_idx) 745 + { 746 + return mkey_idx << 8; 747 + } 748 + 749 + enum { 750 + MLX5_PROF_MASK_QP_SIZE = (u64)1 << 0, 751 + MLX5_PROF_MASK_CMDIF_CSUM = (u64)1 << 1, 752 + MLX5_PROF_MASK_MR_CACHE = (u64)1 << 2, 753 + }; 754 + 755 + enum { 756 + MAX_MR_CACHE_ENTRIES = 16, 757 + }; 758 + 759 + struct mlx5_profile { 760 + u64 mask; 761 + u32 log_max_qp; 762 + int cmdif_csum; 763 + struct { 764 + int size; 765 + int limit; 766 + } mr_cache[MAX_MR_CACHE_ENTRIES]; 767 + }; 768 + 769 + #endif /* MLX5_DRIVER_H */
+467
include/linux/mlx5/qp.h
··· 1 + /* 2 + * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved. 3 + * 4 + * This software is available to you under a choice of one of two 5 + * licenses. You may choose to be licensed under the terms of the GNU 6 + * General Public License (GPL) Version 2, available from the file 7 + * COPYING in the main directory of this source tree, or the 8 + * OpenIB.org BSD license below: 9 + * 10 + * Redistribution and use in source and binary forms, with or 11 + * without modification, are permitted provided that the following 12 + * conditions are met: 13 + * 14 + * - Redistributions of source code must retain the above 15 + * copyright notice, this list of conditions and the following 16 + * disclaimer. 17 + * 18 + * - Redistributions in binary form must reproduce the above 19 + * copyright notice, this list of conditions and the following 20 + * disclaimer in the documentation and/or other materials 21 + * 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 OF 25 + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26 + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 27 + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 28 + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29 + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30 + * SOFTWARE. 31 + */ 32 + 33 + #ifndef MLX5_QP_H 34 + #define MLX5_QP_H 35 + 36 + #include <linux/mlx5/device.h> 37 + #include <linux/mlx5/driver.h> 38 + 39 + #define MLX5_INVALID_LKEY 0x100 40 + 41 + enum mlx5_qp_optpar { 42 + MLX5_QP_OPTPAR_ALT_ADDR_PATH = 1 << 0, 43 + MLX5_QP_OPTPAR_RRE = 1 << 1, 44 + MLX5_QP_OPTPAR_RAE = 1 << 2, 45 + MLX5_QP_OPTPAR_RWE = 1 << 3, 46 + MLX5_QP_OPTPAR_PKEY_INDEX = 1 << 4, 47 + MLX5_QP_OPTPAR_Q_KEY = 1 << 5, 48 + MLX5_QP_OPTPAR_RNR_TIMEOUT = 1 << 6, 49 + MLX5_QP_OPTPAR_PRIMARY_ADDR_PATH = 1 << 7, 50 + MLX5_QP_OPTPAR_SRA_MAX = 1 << 8, 51 + MLX5_QP_OPTPAR_RRA_MAX = 1 << 9, 52 + MLX5_QP_OPTPAR_PM_STATE = 1 << 10, 53 + MLX5_QP_OPTPAR_RETRY_COUNT = 1 << 12, 54 + MLX5_QP_OPTPAR_RNR_RETRY = 1 << 13, 55 + MLX5_QP_OPTPAR_ACK_TIMEOUT = 1 << 14, 56 + MLX5_QP_OPTPAR_PRI_PORT = 1 << 16, 57 + MLX5_QP_OPTPAR_SRQN = 1 << 18, 58 + MLX5_QP_OPTPAR_CQN_RCV = 1 << 19, 59 + MLX5_QP_OPTPAR_DC_HS = 1 << 20, 60 + MLX5_QP_OPTPAR_DC_KEY = 1 << 21, 61 + }; 62 + 63 + enum mlx5_qp_state { 64 + MLX5_QP_STATE_RST = 0, 65 + MLX5_QP_STATE_INIT = 1, 66 + MLX5_QP_STATE_RTR = 2, 67 + MLX5_QP_STATE_RTS = 3, 68 + MLX5_QP_STATE_SQER = 4, 69 + MLX5_QP_STATE_SQD = 5, 70 + MLX5_QP_STATE_ERR = 6, 71 + MLX5_QP_STATE_SQ_DRAINING = 7, 72 + MLX5_QP_STATE_SUSPENDED = 9, 73 + MLX5_QP_NUM_STATE 74 + }; 75 + 76 + enum { 77 + MLX5_QP_ST_RC = 0x0, 78 + MLX5_QP_ST_UC = 0x1, 79 + MLX5_QP_ST_UD = 0x2, 80 + MLX5_QP_ST_XRC = 0x3, 81 + MLX5_QP_ST_MLX = 0x4, 82 + MLX5_QP_ST_DCI = 0x5, 83 + MLX5_QP_ST_DCT = 0x6, 84 + MLX5_QP_ST_QP0 = 0x7, 85 + MLX5_QP_ST_QP1 = 0x8, 86 + MLX5_QP_ST_RAW_ETHERTYPE = 0x9, 87 + MLX5_QP_ST_RAW_IPV6 = 0xa, 88 + MLX5_QP_ST_SNIFFER = 0xb, 89 + MLX5_QP_ST_SYNC_UMR = 0xe, 90 + MLX5_QP_ST_PTP_1588 = 0xd, 91 + MLX5_QP_ST_REG_UMR = 0xc, 92 + MLX5_QP_ST_MAX 93 + }; 94 + 95 + enum { 96 + MLX5_QP_PM_MIGRATED = 0x3, 97 + MLX5_QP_PM_ARMED = 0x0, 98 + MLX5_QP_PM_REARM = 0x1 99 + }; 100 + 101 + enum { 102 + MLX5_NON_ZERO_RQ = 0 << 24, 103 + MLX5_SRQ_RQ = 1 << 24, 104 + MLX5_CRQ_RQ = 2 << 24, 105 + MLX5_ZERO_LEN_RQ = 3 << 24 106 + }; 107 + 108 + enum { 109 + /* params1 */ 110 + MLX5_QP_BIT_SRE = 1 << 15, 111 + MLX5_QP_BIT_SWE = 1 << 14, 112 + MLX5_QP_BIT_SAE = 1 << 13, 113 + /* params2 */ 114 + MLX5_QP_BIT_RRE = 1 << 15, 115 + MLX5_QP_BIT_RWE = 1 << 14, 116 + MLX5_QP_BIT_RAE = 1 << 13, 117 + MLX5_QP_BIT_RIC = 1 << 4, 118 + }; 119 + 120 + enum { 121 + MLX5_WQE_CTRL_CQ_UPDATE = 2 << 2, 122 + MLX5_WQE_CTRL_SOLICITED = 1 << 1, 123 + }; 124 + 125 + enum { 126 + MLX5_SEND_WQE_BB = 64, 127 + }; 128 + 129 + enum { 130 + MLX5_WQE_FMR_PERM_LOCAL_READ = 1 << 27, 131 + MLX5_WQE_FMR_PERM_LOCAL_WRITE = 1 << 28, 132 + MLX5_WQE_FMR_PERM_REMOTE_READ = 1 << 29, 133 + MLX5_WQE_FMR_PERM_REMOTE_WRITE = 1 << 30, 134 + MLX5_WQE_FMR_PERM_ATOMIC = 1 << 31 135 + }; 136 + 137 + enum { 138 + MLX5_FENCE_MODE_NONE = 0 << 5, 139 + MLX5_FENCE_MODE_INITIATOR_SMALL = 1 << 5, 140 + MLX5_FENCE_MODE_STRONG_ORDERING = 3 << 5, 141 + MLX5_FENCE_MODE_SMALL_AND_FENCE = 4 << 5, 142 + }; 143 + 144 + enum { 145 + MLX5_QP_LAT_SENSITIVE = 1 << 28, 146 + MLX5_QP_ENABLE_SIG = 1 << 31, 147 + }; 148 + 149 + enum { 150 + MLX5_RCV_DBR = 0, 151 + MLX5_SND_DBR = 1, 152 + }; 153 + 154 + struct mlx5_wqe_fmr_seg { 155 + __be32 flags; 156 + __be32 mem_key; 157 + __be64 buf_list; 158 + __be64 start_addr; 159 + __be64 reg_len; 160 + __be32 offset; 161 + __be32 page_size; 162 + u32 reserved[2]; 163 + }; 164 + 165 + struct mlx5_wqe_ctrl_seg { 166 + __be32 opmod_idx_opcode; 167 + __be32 qpn_ds; 168 + u8 signature; 169 + u8 rsvd[2]; 170 + u8 fm_ce_se; 171 + __be32 imm; 172 + }; 173 + 174 + struct mlx5_wqe_xrc_seg { 175 + __be32 xrc_srqn; 176 + u8 rsvd[12]; 177 + }; 178 + 179 + struct mlx5_wqe_masked_atomic_seg { 180 + __be64 swap_add; 181 + __be64 compare; 182 + __be64 swap_add_mask; 183 + __be64 compare_mask; 184 + }; 185 + 186 + struct mlx5_av { 187 + union { 188 + struct { 189 + __be32 qkey; 190 + __be32 reserved; 191 + } qkey; 192 + __be64 dc_key; 193 + } key; 194 + __be32 dqp_dct; 195 + u8 stat_rate_sl; 196 + u8 fl_mlid; 197 + __be16 rlid; 198 + u8 reserved0[10]; 199 + u8 tclass; 200 + u8 hop_limit; 201 + __be32 grh_gid_fl; 202 + u8 rgid[16]; 203 + }; 204 + 205 + struct mlx5_wqe_datagram_seg { 206 + struct mlx5_av av; 207 + }; 208 + 209 + struct mlx5_wqe_raddr_seg { 210 + __be64 raddr; 211 + __be32 rkey; 212 + u32 reserved; 213 + }; 214 + 215 + struct mlx5_wqe_atomic_seg { 216 + __be64 swap_add; 217 + __be64 compare; 218 + }; 219 + 220 + struct mlx5_wqe_data_seg { 221 + __be32 byte_count; 222 + __be32 lkey; 223 + __be64 addr; 224 + }; 225 + 226 + struct mlx5_wqe_umr_ctrl_seg { 227 + u8 flags; 228 + u8 rsvd0[3]; 229 + __be16 klm_octowords; 230 + __be16 bsf_octowords; 231 + __be64 mkey_mask; 232 + u8 rsvd1[32]; 233 + }; 234 + 235 + struct mlx5_seg_set_psv { 236 + __be32 psv_num; 237 + __be16 syndrome; 238 + __be16 status; 239 + __be32 transient_sig; 240 + __be32 ref_tag; 241 + }; 242 + 243 + struct mlx5_seg_get_psv { 244 + u8 rsvd[19]; 245 + u8 num_psv; 246 + __be32 l_key; 247 + __be64 va; 248 + __be32 psv_index[4]; 249 + }; 250 + 251 + struct mlx5_seg_check_psv { 252 + u8 rsvd0[2]; 253 + __be16 err_coalescing_op; 254 + u8 rsvd1[2]; 255 + __be16 xport_err_op; 256 + u8 rsvd2[2]; 257 + __be16 xport_err_mask; 258 + u8 rsvd3[7]; 259 + u8 num_psv; 260 + __be32 l_key; 261 + __be64 va; 262 + __be32 psv_index[4]; 263 + }; 264 + 265 + struct mlx5_rwqe_sig { 266 + u8 rsvd0[4]; 267 + u8 signature; 268 + u8 rsvd1[11]; 269 + }; 270 + 271 + struct mlx5_wqe_signature_seg { 272 + u8 rsvd0[4]; 273 + u8 signature; 274 + u8 rsvd1[11]; 275 + }; 276 + 277 + struct mlx5_wqe_inline_seg { 278 + __be32 byte_count; 279 + }; 280 + 281 + struct mlx5_core_qp { 282 + void (*event) (struct mlx5_core_qp *, int); 283 + int qpn; 284 + atomic_t refcount; 285 + struct completion free; 286 + struct mlx5_rsc_debug *dbg; 287 + int pid; 288 + }; 289 + 290 + struct mlx5_qp_path { 291 + u8 fl; 292 + u8 rsvd3; 293 + u8 free_ar; 294 + u8 pkey_index; 295 + u8 rsvd0; 296 + u8 grh_mlid; 297 + __be16 rlid; 298 + u8 ackto_lt; 299 + u8 mgid_index; 300 + u8 static_rate; 301 + u8 hop_limit; 302 + __be32 tclass_flowlabel; 303 + u8 rgid[16]; 304 + u8 rsvd1[4]; 305 + u8 sl; 306 + u8 port; 307 + u8 rsvd2[6]; 308 + }; 309 + 310 + struct mlx5_qp_context { 311 + __be32 flags; 312 + __be32 flags_pd; 313 + u8 mtu_msgmax; 314 + u8 rq_size_stride; 315 + __be16 sq_crq_size; 316 + __be32 qp_counter_set_usr_page; 317 + __be32 wire_qpn; 318 + __be32 log_pg_sz_remote_qpn; 319 + struct mlx5_qp_path pri_path; 320 + struct mlx5_qp_path alt_path; 321 + __be32 params1; 322 + u8 reserved2[4]; 323 + __be32 next_send_psn; 324 + __be32 cqn_send; 325 + u8 reserved3[8]; 326 + __be32 last_acked_psn; 327 + __be32 ssn; 328 + __be32 params2; 329 + __be32 rnr_nextrecvpsn; 330 + __be32 xrcd; 331 + __be32 cqn_recv; 332 + __be64 db_rec_addr; 333 + __be32 qkey; 334 + __be32 rq_type_srqn; 335 + __be32 rmsn; 336 + __be16 hw_sq_wqe_counter; 337 + __be16 sw_sq_wqe_counter; 338 + __be16 hw_rcyclic_byte_counter; 339 + __be16 hw_rq_counter; 340 + __be16 sw_rcyclic_byte_counter; 341 + __be16 sw_rq_counter; 342 + u8 rsvd0[5]; 343 + u8 cgs; 344 + u8 cs_req; 345 + u8 cs_res; 346 + __be64 dc_access_key; 347 + u8 rsvd1[24]; 348 + }; 349 + 350 + struct mlx5_create_qp_mbox_in { 351 + struct mlx5_inbox_hdr hdr; 352 + __be32 input_qpn; 353 + u8 rsvd0[4]; 354 + __be32 opt_param_mask; 355 + u8 rsvd1[4]; 356 + struct mlx5_qp_context ctx; 357 + u8 rsvd3[16]; 358 + __be64 pas[0]; 359 + }; 360 + 361 + struct mlx5_create_qp_mbox_out { 362 + struct mlx5_outbox_hdr hdr; 363 + __be32 qpn; 364 + u8 rsvd0[4]; 365 + }; 366 + 367 + struct mlx5_destroy_qp_mbox_in { 368 + struct mlx5_inbox_hdr hdr; 369 + __be32 qpn; 370 + u8 rsvd0[4]; 371 + }; 372 + 373 + struct mlx5_destroy_qp_mbox_out { 374 + struct mlx5_outbox_hdr hdr; 375 + u8 rsvd0[8]; 376 + }; 377 + 378 + struct mlx5_modify_qp_mbox_in { 379 + struct mlx5_inbox_hdr hdr; 380 + __be32 qpn; 381 + u8 rsvd1[4]; 382 + __be32 optparam; 383 + u8 rsvd0[4]; 384 + struct mlx5_qp_context ctx; 385 + }; 386 + 387 + struct mlx5_modify_qp_mbox_out { 388 + struct mlx5_outbox_hdr hdr; 389 + u8 rsvd0[8]; 390 + }; 391 + 392 + struct mlx5_query_qp_mbox_in { 393 + struct mlx5_inbox_hdr hdr; 394 + __be32 qpn; 395 + u8 rsvd[4]; 396 + }; 397 + 398 + struct mlx5_query_qp_mbox_out { 399 + struct mlx5_outbox_hdr hdr; 400 + u8 rsvd1[8]; 401 + __be32 optparam; 402 + u8 rsvd0[4]; 403 + struct mlx5_qp_context ctx; 404 + u8 rsvd2[16]; 405 + __be64 pas[0]; 406 + }; 407 + 408 + struct mlx5_conf_sqp_mbox_in { 409 + struct mlx5_inbox_hdr hdr; 410 + __be32 qpn; 411 + u8 rsvd[3]; 412 + u8 type; 413 + }; 414 + 415 + struct mlx5_conf_sqp_mbox_out { 416 + struct mlx5_outbox_hdr hdr; 417 + u8 rsvd[8]; 418 + }; 419 + 420 + struct mlx5_alloc_xrcd_mbox_in { 421 + struct mlx5_inbox_hdr hdr; 422 + u8 rsvd[8]; 423 + }; 424 + 425 + struct mlx5_alloc_xrcd_mbox_out { 426 + struct mlx5_outbox_hdr hdr; 427 + __be32 xrcdn; 428 + u8 rsvd[4]; 429 + }; 430 + 431 + struct mlx5_dealloc_xrcd_mbox_in { 432 + struct mlx5_inbox_hdr hdr; 433 + __be32 xrcdn; 434 + u8 rsvd[4]; 435 + }; 436 + 437 + struct mlx5_dealloc_xrcd_mbox_out { 438 + struct mlx5_outbox_hdr hdr; 439 + u8 rsvd[8]; 440 + }; 441 + 442 + static inline struct mlx5_core_qp *__mlx5_qp_lookup(struct mlx5_core_dev *dev, u32 qpn) 443 + { 444 + return radix_tree_lookup(&dev->priv.qp_table.tree, qpn); 445 + } 446 + 447 + int mlx5_core_create_qp(struct mlx5_core_dev *dev, 448 + struct mlx5_core_qp *qp, 449 + struct mlx5_create_qp_mbox_in *in, 450 + int inlen); 451 + int mlx5_core_qp_modify(struct mlx5_core_dev *dev, enum mlx5_qp_state cur_state, 452 + enum mlx5_qp_state new_state, 453 + struct mlx5_modify_qp_mbox_in *in, int sqd_event, 454 + struct mlx5_core_qp *qp); 455 + int mlx5_core_destroy_qp(struct mlx5_core_dev *dev, 456 + struct mlx5_core_qp *qp); 457 + int mlx5_core_qp_query(struct mlx5_core_dev *dev, struct mlx5_core_qp *qp, 458 + struct mlx5_query_qp_mbox_out *out, int outlen); 459 + 460 + int mlx5_core_xrcd_alloc(struct mlx5_core_dev *dev, u32 *xrcdn); 461 + int mlx5_core_xrcd_dealloc(struct mlx5_core_dev *dev, u32 xrcdn); 462 + void mlx5_init_qp_table(struct mlx5_core_dev *dev); 463 + void mlx5_cleanup_qp_table(struct mlx5_core_dev *dev); 464 + int mlx5_debug_qp_add(struct mlx5_core_dev *dev, struct mlx5_core_qp *qp); 465 + void mlx5_debug_qp_remove(struct mlx5_core_dev *dev, struct mlx5_core_qp *qp); 466 + 467 + #endif /* MLX5_QP_H */
+41
include/linux/mlx5/srq.h
··· 1 + /* 2 + * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved. 3 + * 4 + * This software is available to you under a choice of one of two 5 + * licenses. You may choose to be licensed under the terms of the GNU 6 + * General Public License (GPL) Version 2, available from the file 7 + * COPYING in the main directory of this source tree, or the 8 + * OpenIB.org BSD license below: 9 + * 10 + * Redistribution and use in source and binary forms, with or 11 + * without modification, are permitted provided that the following 12 + * conditions are met: 13 + * 14 + * - Redistributions of source code must retain the above 15 + * copyright notice, this list of conditions and the following 16 + * disclaimer. 17 + * 18 + * - Redistributions in binary form must reproduce the above 19 + * copyright notice, this list of conditions and the following 20 + * disclaimer in the documentation and/or other materials 21 + * 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 OF 25 + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26 + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 27 + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 28 + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29 + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30 + * SOFTWARE. 31 + */ 32 + 33 + #ifndef MLX5_SRQ_H 34 + #define MLX5_SRQ_H 35 + 36 + #include <linux/mlx5/driver.h> 37 + 38 + void mlx5_init_srq_table(struct mlx5_core_dev *dev); 39 + void mlx5_cleanup_srq_table(struct mlx5_core_dev *dev); 40 + 41 + #endif /* MLX5_SRQ_H */