18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright (c) 2013-2015, Mellanox Technologies. All rights reserved. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * This software is available to you under a choice of one of two 58c2ecf20Sopenharmony_ci * licenses. You may choose to be licensed under the terms of the GNU 68c2ecf20Sopenharmony_ci * General Public License (GPL) Version 2, available from the file 78c2ecf20Sopenharmony_ci * COPYING in the main directory of this source tree, or the 88c2ecf20Sopenharmony_ci * OpenIB.org BSD license below: 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or 118c2ecf20Sopenharmony_ci * without modification, are permitted provided that the following 128c2ecf20Sopenharmony_ci * conditions are met: 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * - Redistributions of source code must retain the above 158c2ecf20Sopenharmony_ci * copyright notice, this list of conditions and the following 168c2ecf20Sopenharmony_ci * disclaimer. 178c2ecf20Sopenharmony_ci * 188c2ecf20Sopenharmony_ci * - Redistributions in binary form must reproduce the above 198c2ecf20Sopenharmony_ci * copyright notice, this list of conditions and the following 208c2ecf20Sopenharmony_ci * disclaimer in the documentation and/or other materials 218c2ecf20Sopenharmony_ci * provided with the distribution. 228c2ecf20Sopenharmony_ci * 238c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 248c2ecf20Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 258c2ecf20Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 268c2ecf20Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 278c2ecf20Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 288c2ecf20Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 298c2ecf20Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 308c2ecf20Sopenharmony_ci * SOFTWARE. 318c2ecf20Sopenharmony_ci */ 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci#include <linux/module.h> 348c2ecf20Sopenharmony_ci#include <rdma/ib_umem.h> 358c2ecf20Sopenharmony_ci#include <rdma/ib_umem_odp.h> 368c2ecf20Sopenharmony_ci#include "mlx5_ib.h" 378c2ecf20Sopenharmony_ci#include <linux/jiffies.h> 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci/* @umem: umem object to scan 408c2ecf20Sopenharmony_ci * @addr: ib virtual address requested by the user 418c2ecf20Sopenharmony_ci * @max_page_shift: high limit for page_shift - 0 means no limit 428c2ecf20Sopenharmony_ci * @count: number of PAGE_SIZE pages covered by umem 438c2ecf20Sopenharmony_ci * @shift: page shift for the compound pages found in the region 448c2ecf20Sopenharmony_ci * @ncont: number of compund pages 458c2ecf20Sopenharmony_ci * @order: log2 of the number of compound pages 468c2ecf20Sopenharmony_ci */ 478c2ecf20Sopenharmony_civoid mlx5_ib_cont_pages(struct ib_umem *umem, u64 addr, 488c2ecf20Sopenharmony_ci unsigned long max_page_shift, 498c2ecf20Sopenharmony_ci int *count, int *shift, 508c2ecf20Sopenharmony_ci int *ncont, int *order) 518c2ecf20Sopenharmony_ci{ 528c2ecf20Sopenharmony_ci unsigned long tmp; 538c2ecf20Sopenharmony_ci unsigned long m; 548c2ecf20Sopenharmony_ci u64 base = ~0, p = 0; 558c2ecf20Sopenharmony_ci u64 len, pfn; 568c2ecf20Sopenharmony_ci int i = 0; 578c2ecf20Sopenharmony_ci struct scatterlist *sg; 588c2ecf20Sopenharmony_ci int entry; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci addr = addr >> PAGE_SHIFT; 618c2ecf20Sopenharmony_ci tmp = (unsigned long)addr; 628c2ecf20Sopenharmony_ci m = find_first_bit(&tmp, BITS_PER_LONG); 638c2ecf20Sopenharmony_ci if (max_page_shift) 648c2ecf20Sopenharmony_ci m = min_t(unsigned long, max_page_shift - PAGE_SHIFT, m); 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci for_each_sg(umem->sg_head.sgl, sg, umem->nmap, entry) { 678c2ecf20Sopenharmony_ci len = sg_dma_len(sg) >> PAGE_SHIFT; 688c2ecf20Sopenharmony_ci pfn = sg_dma_address(sg) >> PAGE_SHIFT; 698c2ecf20Sopenharmony_ci if (base + p != pfn) { 708c2ecf20Sopenharmony_ci /* If either the offset or the new 718c2ecf20Sopenharmony_ci * base are unaligned update m 728c2ecf20Sopenharmony_ci */ 738c2ecf20Sopenharmony_ci tmp = (unsigned long)(pfn | p); 748c2ecf20Sopenharmony_ci if (!IS_ALIGNED(tmp, 1 << m)) 758c2ecf20Sopenharmony_ci m = find_first_bit(&tmp, BITS_PER_LONG); 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci base = pfn; 788c2ecf20Sopenharmony_ci p = 0; 798c2ecf20Sopenharmony_ci } 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci p += len; 828c2ecf20Sopenharmony_ci i += len; 838c2ecf20Sopenharmony_ci } 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci if (i) { 868c2ecf20Sopenharmony_ci m = min_t(unsigned long, ilog2(roundup_pow_of_two(i)), m); 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci if (order) 898c2ecf20Sopenharmony_ci *order = ilog2(roundup_pow_of_two(i) >> m); 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci *ncont = DIV_ROUND_UP(i, (1 << m)); 928c2ecf20Sopenharmony_ci } else { 938c2ecf20Sopenharmony_ci m = 0; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci if (order) 968c2ecf20Sopenharmony_ci *order = 0; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci *ncont = 0; 998c2ecf20Sopenharmony_ci } 1008c2ecf20Sopenharmony_ci *shift = PAGE_SHIFT + m; 1018c2ecf20Sopenharmony_ci *count = i; 1028c2ecf20Sopenharmony_ci} 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci/* 1058c2ecf20Sopenharmony_ci * Populate the given array with bus addresses from the umem. 1068c2ecf20Sopenharmony_ci * 1078c2ecf20Sopenharmony_ci * dev - mlx5_ib device 1088c2ecf20Sopenharmony_ci * umem - umem to use to fill the pages 1098c2ecf20Sopenharmony_ci * page_shift - determines the page size used in the resulting array 1108c2ecf20Sopenharmony_ci * offset - offset into the umem to start from, 1118c2ecf20Sopenharmony_ci * only implemented for ODP umems 1128c2ecf20Sopenharmony_ci * num_pages - total number of pages to fill 1138c2ecf20Sopenharmony_ci * pas - bus addresses array to fill 1148c2ecf20Sopenharmony_ci * access_flags - access flags to set on all present pages. 1158c2ecf20Sopenharmony_ci use enum mlx5_ib_mtt_access_flags for this. 1168c2ecf20Sopenharmony_ci */ 1178c2ecf20Sopenharmony_civoid __mlx5_ib_populate_pas(struct mlx5_ib_dev *dev, struct ib_umem *umem, 1188c2ecf20Sopenharmony_ci int page_shift, size_t offset, size_t num_pages, 1198c2ecf20Sopenharmony_ci __be64 *pas, int access_flags) 1208c2ecf20Sopenharmony_ci{ 1218c2ecf20Sopenharmony_ci int shift = page_shift - PAGE_SHIFT; 1228c2ecf20Sopenharmony_ci int mask = (1 << shift) - 1; 1238c2ecf20Sopenharmony_ci int i, k, idx; 1248c2ecf20Sopenharmony_ci u64 cur = 0; 1258c2ecf20Sopenharmony_ci u64 base; 1268c2ecf20Sopenharmony_ci int len; 1278c2ecf20Sopenharmony_ci struct scatterlist *sg; 1288c2ecf20Sopenharmony_ci int entry; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci i = 0; 1318c2ecf20Sopenharmony_ci for_each_sg(umem->sg_head.sgl, sg, umem->nmap, entry) { 1328c2ecf20Sopenharmony_ci len = sg_dma_len(sg) >> PAGE_SHIFT; 1338c2ecf20Sopenharmony_ci base = sg_dma_address(sg); 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci /* Skip elements below offset */ 1368c2ecf20Sopenharmony_ci if (i + len < offset << shift) { 1378c2ecf20Sopenharmony_ci i += len; 1388c2ecf20Sopenharmony_ci continue; 1398c2ecf20Sopenharmony_ci } 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci /* Skip pages below offset */ 1428c2ecf20Sopenharmony_ci if (i < offset << shift) { 1438c2ecf20Sopenharmony_ci k = (offset << shift) - i; 1448c2ecf20Sopenharmony_ci i = offset << shift; 1458c2ecf20Sopenharmony_ci } else { 1468c2ecf20Sopenharmony_ci k = 0; 1478c2ecf20Sopenharmony_ci } 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci for (; k < len; k++) { 1508c2ecf20Sopenharmony_ci if (!(i & mask)) { 1518c2ecf20Sopenharmony_ci cur = base + (k << PAGE_SHIFT); 1528c2ecf20Sopenharmony_ci cur |= access_flags; 1538c2ecf20Sopenharmony_ci idx = (i >> shift) - offset; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci pas[idx] = cpu_to_be64(cur); 1568c2ecf20Sopenharmony_ci mlx5_ib_dbg(dev, "pas[%d] 0x%llx\n", 1578c2ecf20Sopenharmony_ci i >> shift, be64_to_cpu(pas[idx])); 1588c2ecf20Sopenharmony_ci } 1598c2ecf20Sopenharmony_ci i++; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci /* Stop after num_pages reached */ 1628c2ecf20Sopenharmony_ci if (i >> shift >= offset + num_pages) 1638c2ecf20Sopenharmony_ci return; 1648c2ecf20Sopenharmony_ci } 1658c2ecf20Sopenharmony_ci } 1668c2ecf20Sopenharmony_ci} 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_civoid mlx5_ib_populate_pas(struct mlx5_ib_dev *dev, struct ib_umem *umem, 1698c2ecf20Sopenharmony_ci int page_shift, __be64 *pas, int access_flags) 1708c2ecf20Sopenharmony_ci{ 1718c2ecf20Sopenharmony_ci return __mlx5_ib_populate_pas(dev, umem, page_shift, 0, 1728c2ecf20Sopenharmony_ci ib_umem_num_dma_blocks(umem, PAGE_SIZE), 1738c2ecf20Sopenharmony_ci pas, access_flags); 1748c2ecf20Sopenharmony_ci} 1758c2ecf20Sopenharmony_ciint mlx5_ib_get_buf_offset(u64 addr, int page_shift, u32 *offset) 1768c2ecf20Sopenharmony_ci{ 1778c2ecf20Sopenharmony_ci u64 page_size; 1788c2ecf20Sopenharmony_ci u64 page_mask; 1798c2ecf20Sopenharmony_ci u64 off_size; 1808c2ecf20Sopenharmony_ci u64 off_mask; 1818c2ecf20Sopenharmony_ci u64 buf_off; 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci page_size = (u64)1 << page_shift; 1848c2ecf20Sopenharmony_ci page_mask = page_size - 1; 1858c2ecf20Sopenharmony_ci buf_off = addr & page_mask; 1868c2ecf20Sopenharmony_ci off_size = page_size >> 6; 1878c2ecf20Sopenharmony_ci off_mask = off_size - 1; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci if (buf_off & off_mask) 1908c2ecf20Sopenharmony_ci return -EINVAL; 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci *offset = buf_off >> ilog2(off_size); 1938c2ecf20Sopenharmony_ci return 0; 1948c2ecf20Sopenharmony_ci} 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci#define WR_ID_BF 0xBF 1978c2ecf20Sopenharmony_ci#define WR_ID_END 0xBAD 1988c2ecf20Sopenharmony_ci#define TEST_WC_NUM_WQES 255 1998c2ecf20Sopenharmony_ci#define TEST_WC_POLLING_MAX_TIME_JIFFIES msecs_to_jiffies(100) 2008c2ecf20Sopenharmony_cistatic int post_send_nop(struct mlx5_ib_dev *dev, struct ib_qp *ibqp, u64 wr_id, 2018c2ecf20Sopenharmony_ci bool signaled) 2028c2ecf20Sopenharmony_ci{ 2038c2ecf20Sopenharmony_ci struct mlx5_ib_qp *qp = to_mqp(ibqp); 2048c2ecf20Sopenharmony_ci struct mlx5_wqe_ctrl_seg *ctrl; 2058c2ecf20Sopenharmony_ci struct mlx5_bf *bf = &qp->bf; 2068c2ecf20Sopenharmony_ci __be32 mmio_wqe[16] = {}; 2078c2ecf20Sopenharmony_ci unsigned long flags; 2088c2ecf20Sopenharmony_ci unsigned int idx; 2098c2ecf20Sopenharmony_ci int i; 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci if (unlikely(dev->mdev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR)) 2128c2ecf20Sopenharmony_ci return -EIO; 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci spin_lock_irqsave(&qp->sq.lock, flags); 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci idx = qp->sq.cur_post & (qp->sq.wqe_cnt - 1); 2178c2ecf20Sopenharmony_ci ctrl = mlx5_frag_buf_get_wqe(&qp->sq.fbc, idx); 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci memset(ctrl, 0, sizeof(struct mlx5_wqe_ctrl_seg)); 2208c2ecf20Sopenharmony_ci ctrl->fm_ce_se = signaled ? MLX5_WQE_CTRL_CQ_UPDATE : 0; 2218c2ecf20Sopenharmony_ci ctrl->opmod_idx_opcode = 2228c2ecf20Sopenharmony_ci cpu_to_be32(((u32)(qp->sq.cur_post) << 8) | MLX5_OPCODE_NOP); 2238c2ecf20Sopenharmony_ci ctrl->qpn_ds = cpu_to_be32((sizeof(struct mlx5_wqe_ctrl_seg) / 16) | 2248c2ecf20Sopenharmony_ci (qp->trans_qp.base.mqp.qpn << 8)); 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci qp->sq.wrid[idx] = wr_id; 2278c2ecf20Sopenharmony_ci qp->sq.w_list[idx].opcode = MLX5_OPCODE_NOP; 2288c2ecf20Sopenharmony_ci qp->sq.wqe_head[idx] = qp->sq.head + 1; 2298c2ecf20Sopenharmony_ci qp->sq.cur_post += DIV_ROUND_UP(sizeof(struct mlx5_wqe_ctrl_seg), 2308c2ecf20Sopenharmony_ci MLX5_SEND_WQE_BB); 2318c2ecf20Sopenharmony_ci qp->sq.w_list[idx].next = qp->sq.cur_post; 2328c2ecf20Sopenharmony_ci qp->sq.head++; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci memcpy(mmio_wqe, ctrl, sizeof(*ctrl)); 2358c2ecf20Sopenharmony_ci ((struct mlx5_wqe_ctrl_seg *)&mmio_wqe)->fm_ce_se |= 2368c2ecf20Sopenharmony_ci MLX5_WQE_CTRL_CQ_UPDATE; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci /* Make sure that descriptors are written before 2398c2ecf20Sopenharmony_ci * updating doorbell record and ringing the doorbell 2408c2ecf20Sopenharmony_ci */ 2418c2ecf20Sopenharmony_ci wmb(); 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci qp->db.db[MLX5_SND_DBR] = cpu_to_be32(qp->sq.cur_post); 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci /* Make sure doorbell record is visible to the HCA before 2468c2ecf20Sopenharmony_ci * we hit doorbell 2478c2ecf20Sopenharmony_ci */ 2488c2ecf20Sopenharmony_ci wmb(); 2498c2ecf20Sopenharmony_ci for (i = 0; i < 8; i++) 2508c2ecf20Sopenharmony_ci mlx5_write64(&mmio_wqe[i * 2], 2518c2ecf20Sopenharmony_ci bf->bfreg->map + bf->offset + i * 8); 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci bf->offset ^= bf->buf_size; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&qp->sq.lock, flags); 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci return 0; 2588c2ecf20Sopenharmony_ci} 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_cistatic int test_wc_poll_cq_result(struct mlx5_ib_dev *dev, struct ib_cq *cq) 2618c2ecf20Sopenharmony_ci{ 2628c2ecf20Sopenharmony_ci int ret; 2638c2ecf20Sopenharmony_ci struct ib_wc wc = {}; 2648c2ecf20Sopenharmony_ci unsigned long end = jiffies + TEST_WC_POLLING_MAX_TIME_JIFFIES; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci do { 2678c2ecf20Sopenharmony_ci ret = ib_poll_cq(cq, 1, &wc); 2688c2ecf20Sopenharmony_ci if (ret < 0 || wc.status) 2698c2ecf20Sopenharmony_ci return ret < 0 ? ret : -EINVAL; 2708c2ecf20Sopenharmony_ci if (ret) 2718c2ecf20Sopenharmony_ci break; 2728c2ecf20Sopenharmony_ci } while (!time_after(jiffies, end)); 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci if (!ret) 2758c2ecf20Sopenharmony_ci return -ETIMEDOUT; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci if (wc.wr_id != WR_ID_BF) 2788c2ecf20Sopenharmony_ci ret = 0; 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci return ret; 2818c2ecf20Sopenharmony_ci} 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_cistatic int test_wc_do_send(struct mlx5_ib_dev *dev, struct ib_qp *qp) 2848c2ecf20Sopenharmony_ci{ 2858c2ecf20Sopenharmony_ci int err, i; 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci for (i = 0; i < TEST_WC_NUM_WQES; i++) { 2888c2ecf20Sopenharmony_ci err = post_send_nop(dev, qp, WR_ID_BF, false); 2898c2ecf20Sopenharmony_ci if (err) 2908c2ecf20Sopenharmony_ci return err; 2918c2ecf20Sopenharmony_ci } 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci return post_send_nop(dev, qp, WR_ID_END, true); 2948c2ecf20Sopenharmony_ci} 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ciint mlx5_ib_test_wc(struct mlx5_ib_dev *dev) 2978c2ecf20Sopenharmony_ci{ 2988c2ecf20Sopenharmony_ci struct ib_cq_init_attr cq_attr = { .cqe = TEST_WC_NUM_WQES + 1 }; 2998c2ecf20Sopenharmony_ci int port_type_cap = MLX5_CAP_GEN(dev->mdev, port_type); 3008c2ecf20Sopenharmony_ci struct ib_qp_init_attr qp_init_attr = { 3018c2ecf20Sopenharmony_ci .cap = { .max_send_wr = TEST_WC_NUM_WQES }, 3028c2ecf20Sopenharmony_ci .qp_type = IB_QPT_UD, 3038c2ecf20Sopenharmony_ci .sq_sig_type = IB_SIGNAL_REQ_WR, 3048c2ecf20Sopenharmony_ci .create_flags = MLX5_IB_QP_CREATE_WC_TEST, 3058c2ecf20Sopenharmony_ci }; 3068c2ecf20Sopenharmony_ci struct ib_qp_attr qp_attr = { .port_num = 1 }; 3078c2ecf20Sopenharmony_ci struct ib_device *ibdev = &dev->ib_dev; 3088c2ecf20Sopenharmony_ci struct ib_qp *qp; 3098c2ecf20Sopenharmony_ci struct ib_cq *cq; 3108c2ecf20Sopenharmony_ci struct ib_pd *pd; 3118c2ecf20Sopenharmony_ci int ret; 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci if (!MLX5_CAP_GEN(dev->mdev, bf)) 3148c2ecf20Sopenharmony_ci return 0; 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci if (!dev->mdev->roce.roce_en && 3178c2ecf20Sopenharmony_ci port_type_cap == MLX5_CAP_PORT_TYPE_ETH) { 3188c2ecf20Sopenharmony_ci if (mlx5_core_is_pf(dev->mdev)) 3198c2ecf20Sopenharmony_ci dev->wc_support = arch_can_pci_mmap_wc(); 3208c2ecf20Sopenharmony_ci return 0; 3218c2ecf20Sopenharmony_ci } 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci ret = mlx5_alloc_bfreg(dev->mdev, &dev->wc_bfreg, true, false); 3248c2ecf20Sopenharmony_ci if (ret) 3258c2ecf20Sopenharmony_ci goto print_err; 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci if (!dev->wc_bfreg.wc) 3288c2ecf20Sopenharmony_ci goto out1; 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci pd = ib_alloc_pd(ibdev, 0); 3318c2ecf20Sopenharmony_ci if (IS_ERR(pd)) { 3328c2ecf20Sopenharmony_ci ret = PTR_ERR(pd); 3338c2ecf20Sopenharmony_ci goto out1; 3348c2ecf20Sopenharmony_ci } 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci cq = ib_create_cq(ibdev, NULL, NULL, NULL, &cq_attr); 3378c2ecf20Sopenharmony_ci if (IS_ERR(cq)) { 3388c2ecf20Sopenharmony_ci ret = PTR_ERR(cq); 3398c2ecf20Sopenharmony_ci goto out2; 3408c2ecf20Sopenharmony_ci } 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci qp_init_attr.recv_cq = cq; 3438c2ecf20Sopenharmony_ci qp_init_attr.send_cq = cq; 3448c2ecf20Sopenharmony_ci qp = ib_create_qp(pd, &qp_init_attr); 3458c2ecf20Sopenharmony_ci if (IS_ERR(qp)) { 3468c2ecf20Sopenharmony_ci ret = PTR_ERR(qp); 3478c2ecf20Sopenharmony_ci goto out3; 3488c2ecf20Sopenharmony_ci } 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci qp_attr.qp_state = IB_QPS_INIT; 3518c2ecf20Sopenharmony_ci ret = ib_modify_qp(qp, &qp_attr, 3528c2ecf20Sopenharmony_ci IB_QP_STATE | IB_QP_PORT | IB_QP_PKEY_INDEX | 3538c2ecf20Sopenharmony_ci IB_QP_QKEY); 3548c2ecf20Sopenharmony_ci if (ret) 3558c2ecf20Sopenharmony_ci goto out4; 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci qp_attr.qp_state = IB_QPS_RTR; 3588c2ecf20Sopenharmony_ci ret = ib_modify_qp(qp, &qp_attr, IB_QP_STATE); 3598c2ecf20Sopenharmony_ci if (ret) 3608c2ecf20Sopenharmony_ci goto out4; 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci qp_attr.qp_state = IB_QPS_RTS; 3638c2ecf20Sopenharmony_ci ret = ib_modify_qp(qp, &qp_attr, IB_QP_STATE | IB_QP_SQ_PSN); 3648c2ecf20Sopenharmony_ci if (ret) 3658c2ecf20Sopenharmony_ci goto out4; 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci ret = test_wc_do_send(dev, qp); 3688c2ecf20Sopenharmony_ci if (ret < 0) 3698c2ecf20Sopenharmony_ci goto out4; 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci ret = test_wc_poll_cq_result(dev, cq); 3728c2ecf20Sopenharmony_ci if (ret > 0) { 3738c2ecf20Sopenharmony_ci dev->wc_support = true; 3748c2ecf20Sopenharmony_ci ret = 0; 3758c2ecf20Sopenharmony_ci } 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ciout4: 3788c2ecf20Sopenharmony_ci ib_destroy_qp(qp); 3798c2ecf20Sopenharmony_ciout3: 3808c2ecf20Sopenharmony_ci ib_destroy_cq(cq); 3818c2ecf20Sopenharmony_ciout2: 3828c2ecf20Sopenharmony_ci ib_dealloc_pd(pd); 3838c2ecf20Sopenharmony_ciout1: 3848c2ecf20Sopenharmony_ci mlx5_free_bfreg(dev->mdev, &dev->wc_bfreg); 3858c2ecf20Sopenharmony_ciprint_err: 3868c2ecf20Sopenharmony_ci if (ret) 3878c2ecf20Sopenharmony_ci mlx5_ib_err( 3888c2ecf20Sopenharmony_ci dev, 3898c2ecf20Sopenharmony_ci "Error %d while trying to test write-combining support\n", 3908c2ecf20Sopenharmony_ci ret); 3918c2ecf20Sopenharmony_ci return ret; 3928c2ecf20Sopenharmony_ci} 393