0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033 #include <rdma/ib_umem.h>
0034 #include <rdma/ib_umem_odp.h>
0035 #include "mlx5_ib.h"
0036 #include <linux/jiffies.h>
0037
0038
0039
0040
0041
0042 void mlx5_ib_populate_pas(struct ib_umem *umem, size_t page_size, __be64 *pas,
0043 u64 access_flags)
0044 {
0045 struct ib_block_iter biter;
0046
0047 rdma_umem_for_each_dma_block (umem, &biter, page_size) {
0048 *pas = cpu_to_be64(rdma_block_iter_dma_address(&biter) |
0049 access_flags);
0050 pas++;
0051 }
0052 }
0053
0054
0055
0056
0057
0058
0059 unsigned long __mlx5_umem_find_best_quantized_pgoff(
0060 struct ib_umem *umem, unsigned long pgsz_bitmap,
0061 unsigned int page_offset_bits, u64 pgoff_bitmask, unsigned int scale,
0062 unsigned int *page_offset_quantized)
0063 {
0064 const u64 page_offset_mask = (1UL << page_offset_bits) - 1;
0065 unsigned long page_size;
0066 u64 page_offset;
0067
0068 page_size = ib_umem_find_best_pgoff(umem, pgsz_bitmap, pgoff_bitmask);
0069 if (!page_size)
0070 return 0;
0071
0072
0073
0074
0075
0076
0077
0078
0079 page_offset = ib_umem_dma_offset(umem, page_size);
0080 while (page_offset & ~(u64)(page_offset_mask * (page_size / scale))) {
0081 page_size /= 2;
0082 page_offset = ib_umem_dma_offset(umem, page_size);
0083 }
0084
0085
0086
0087
0088
0089 if (!(pgsz_bitmap & page_size))
0090 return 0;
0091
0092 *page_offset_quantized =
0093 (unsigned long)page_offset / (page_size / scale);
0094 if (WARN_ON(*page_offset_quantized > page_offset_mask))
0095 return 0;
0096 return page_size;
0097 }
0098
0099 #define WR_ID_BF 0xBF
0100 #define WR_ID_END 0xBAD
0101 #define TEST_WC_NUM_WQES 255
0102 #define TEST_WC_POLLING_MAX_TIME_JIFFIES msecs_to_jiffies(100)
0103 static int post_send_nop(struct mlx5_ib_dev *dev, struct ib_qp *ibqp, u64 wr_id,
0104 bool signaled)
0105 {
0106 struct mlx5_ib_qp *qp = to_mqp(ibqp);
0107 struct mlx5_wqe_ctrl_seg *ctrl;
0108 struct mlx5_bf *bf = &qp->bf;
0109 __be32 mmio_wqe[16] = {};
0110 unsigned long flags;
0111 unsigned int idx;
0112 int i;
0113
0114 if (unlikely(dev->mdev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR))
0115 return -EIO;
0116
0117 spin_lock_irqsave(&qp->sq.lock, flags);
0118
0119 idx = qp->sq.cur_post & (qp->sq.wqe_cnt - 1);
0120 ctrl = mlx5_frag_buf_get_wqe(&qp->sq.fbc, idx);
0121
0122 memset(ctrl, 0, sizeof(struct mlx5_wqe_ctrl_seg));
0123 ctrl->fm_ce_se = signaled ? MLX5_WQE_CTRL_CQ_UPDATE : 0;
0124 ctrl->opmod_idx_opcode =
0125 cpu_to_be32(((u32)(qp->sq.cur_post) << 8) | MLX5_OPCODE_NOP);
0126 ctrl->qpn_ds = cpu_to_be32((sizeof(struct mlx5_wqe_ctrl_seg) / 16) |
0127 (qp->trans_qp.base.mqp.qpn << 8));
0128
0129 qp->sq.wrid[idx] = wr_id;
0130 qp->sq.w_list[idx].opcode = MLX5_OPCODE_NOP;
0131 qp->sq.wqe_head[idx] = qp->sq.head + 1;
0132 qp->sq.cur_post += DIV_ROUND_UP(sizeof(struct mlx5_wqe_ctrl_seg),
0133 MLX5_SEND_WQE_BB);
0134 qp->sq.w_list[idx].next = qp->sq.cur_post;
0135 qp->sq.head++;
0136
0137 memcpy(mmio_wqe, ctrl, sizeof(*ctrl));
0138 ((struct mlx5_wqe_ctrl_seg *)&mmio_wqe)->fm_ce_se |=
0139 MLX5_WQE_CTRL_CQ_UPDATE;
0140
0141
0142
0143
0144 wmb();
0145
0146 qp->db.db[MLX5_SND_DBR] = cpu_to_be32(qp->sq.cur_post);
0147
0148
0149
0150
0151 wmb();
0152 for (i = 0; i < 8; i++)
0153 mlx5_write64(&mmio_wqe[i * 2],
0154 bf->bfreg->map + bf->offset + i * 8);
0155
0156 bf->offset ^= bf->buf_size;
0157
0158 spin_unlock_irqrestore(&qp->sq.lock, flags);
0159
0160 return 0;
0161 }
0162
0163 static int test_wc_poll_cq_result(struct mlx5_ib_dev *dev, struct ib_cq *cq)
0164 {
0165 int ret;
0166 struct ib_wc wc = {};
0167 unsigned long end = jiffies + TEST_WC_POLLING_MAX_TIME_JIFFIES;
0168
0169 do {
0170 ret = ib_poll_cq(cq, 1, &wc);
0171 if (ret < 0 || wc.status)
0172 return ret < 0 ? ret : -EINVAL;
0173 if (ret)
0174 break;
0175 } while (!time_after(jiffies, end));
0176
0177 if (!ret)
0178 return -ETIMEDOUT;
0179
0180 if (wc.wr_id != WR_ID_BF)
0181 ret = 0;
0182
0183 return ret;
0184 }
0185
0186 static int test_wc_do_send(struct mlx5_ib_dev *dev, struct ib_qp *qp)
0187 {
0188 int err, i;
0189
0190 for (i = 0; i < TEST_WC_NUM_WQES; i++) {
0191 err = post_send_nop(dev, qp, WR_ID_BF, false);
0192 if (err)
0193 return err;
0194 }
0195
0196 return post_send_nop(dev, qp, WR_ID_END, true);
0197 }
0198
0199 int mlx5_ib_test_wc(struct mlx5_ib_dev *dev)
0200 {
0201 struct ib_cq_init_attr cq_attr = { .cqe = TEST_WC_NUM_WQES + 1 };
0202 int port_type_cap = MLX5_CAP_GEN(dev->mdev, port_type);
0203 struct ib_qp_init_attr qp_init_attr = {
0204 .cap = { .max_send_wr = TEST_WC_NUM_WQES },
0205 .qp_type = IB_QPT_UD,
0206 .sq_sig_type = IB_SIGNAL_REQ_WR,
0207 .create_flags = MLX5_IB_QP_CREATE_WC_TEST,
0208 };
0209 struct ib_qp_attr qp_attr = { .port_num = 1 };
0210 struct ib_device *ibdev = &dev->ib_dev;
0211 struct ib_qp *qp;
0212 struct ib_cq *cq;
0213 struct ib_pd *pd;
0214 int ret;
0215
0216 if (!MLX5_CAP_GEN(dev->mdev, bf))
0217 return 0;
0218
0219 if (!dev->mdev->roce.roce_en &&
0220 port_type_cap == MLX5_CAP_PORT_TYPE_ETH) {
0221 if (mlx5_core_is_pf(dev->mdev))
0222 dev->wc_support = arch_can_pci_mmap_wc();
0223 return 0;
0224 }
0225
0226 ret = mlx5_alloc_bfreg(dev->mdev, &dev->wc_bfreg, true, false);
0227 if (ret)
0228 goto print_err;
0229
0230 if (!dev->wc_bfreg.wc)
0231 goto out1;
0232
0233 pd = ib_alloc_pd(ibdev, 0);
0234 if (IS_ERR(pd)) {
0235 ret = PTR_ERR(pd);
0236 goto out1;
0237 }
0238
0239 cq = ib_create_cq(ibdev, NULL, NULL, NULL, &cq_attr);
0240 if (IS_ERR(cq)) {
0241 ret = PTR_ERR(cq);
0242 goto out2;
0243 }
0244
0245 qp_init_attr.recv_cq = cq;
0246 qp_init_attr.send_cq = cq;
0247 qp = ib_create_qp(pd, &qp_init_attr);
0248 if (IS_ERR(qp)) {
0249 ret = PTR_ERR(qp);
0250 goto out3;
0251 }
0252
0253 qp_attr.qp_state = IB_QPS_INIT;
0254 ret = ib_modify_qp(qp, &qp_attr,
0255 IB_QP_STATE | IB_QP_PORT | IB_QP_PKEY_INDEX |
0256 IB_QP_QKEY);
0257 if (ret)
0258 goto out4;
0259
0260 qp_attr.qp_state = IB_QPS_RTR;
0261 ret = ib_modify_qp(qp, &qp_attr, IB_QP_STATE);
0262 if (ret)
0263 goto out4;
0264
0265 qp_attr.qp_state = IB_QPS_RTS;
0266 ret = ib_modify_qp(qp, &qp_attr, IB_QP_STATE | IB_QP_SQ_PSN);
0267 if (ret)
0268 goto out4;
0269
0270 ret = test_wc_do_send(dev, qp);
0271 if (ret < 0)
0272 goto out4;
0273
0274 ret = test_wc_poll_cq_result(dev, cq);
0275 if (ret > 0) {
0276 dev->wc_support = true;
0277 ret = 0;
0278 }
0279
0280 out4:
0281 ib_destroy_qp(qp);
0282 out3:
0283 ib_destroy_cq(cq);
0284 out2:
0285 ib_dealloc_pd(pd);
0286 out1:
0287 mlx5_free_bfreg(dev->mdev, &dev->wc_bfreg);
0288 print_err:
0289 if (ret)
0290 mlx5_ib_err(
0291 dev,
0292 "Error %d while trying to test write-combining support\n",
0293 ret);
0294 return ret;
0295 }