| # SPDX-License-Identifier: (GPL-2.0 OR Linux-OpenIB) | |
| # Copyright (c) 2021 Nvidia, Inc. All rights reserved. See COPYING file | |
| from pyverbs.providers.mlx5.mlx5dv import Wqe, WqeDataSeg, WqeCtrlSeg | |
| from pyverbs.pyverbs_error import PyverbsError | |
| from pyverbs.providers.mlx5.mlx5_enums import mlx5dv_qp_create_send_ops_flags, MLX5_WQE_CTRL_CQ_UPDATE, MLX5_OPCODE_SEND | |
| from tests.mlx5_base import Mlx5RDMATestCase, Mlx5RcResources | |
| from pyverbs.qp import QPCap | |
| from pyverbs.wr import SGE | |
| from pyverbs.libibverbs_enums import ibv_qp_create_send_ops_flags, ibv_send_flags, ibv_wc_opcode | |
| import tests.utils as u | |
| class Mlx5RawWqeResources(Mlx5RcResources): | |
| def create_send_ops_flags(self): | |
| self.dv_send_ops_flags = mlx5dv_qp_create_send_ops_flags.MLX5DV_QP_EX_WITH_RAW_WQE | |
| self.send_ops_flags = ibv_qp_create_send_ops_flags.IBV_QP_EX_WITH_SEND | |
| def create_qp_cap(self): | |
| """ | |
| Create QPCap such that work queue elements will wrap around the send | |
| work queue, this happens due to the iteration count being higher | |
| than the max_send_wr. | |
| :return: | |
| """ | |
| return QPCap(max_send_wr=1, max_recv_wr=4, max_recv_sge=2, max_send_sge=2) | |
| class RawWqeTest(Mlx5RDMATestCase): | |
| def setUp(self): | |
| super().setUp() | |
| self.iters = 10 | |
| self.server = None | |
| self.client = None | |
| def prepare_send_elements(self): | |
| mr = self.client.mr | |
| sge_count = 2 | |
| unit_size = mr.length / 2 | |
| data_segs = [WqeDataSeg(unit_size, mr.lkey, mr.buf + i * unit_size) for | |
| i in range(sge_count)] | |
| ctrl_seg = WqeCtrlSeg() | |
| ctrl_seg.fm_ce_se = MLX5_WQE_CTRL_CQ_UPDATE | |
| segment_num = 1 + len(data_segs) | |
| ctrl_seg.opmod_idx_opcode = MLX5_OPCODE_SEND | |
| ctrl_seg.qpn_ds = segment_num | int(self.client.qp.qp_num) << 8 | |
| self.raw_send_wqe = Wqe([ctrl_seg] + data_segs) | |
| self.regular_send_sge = SGE(mr.buf, mr.length, mr.lkey) | |
| def mixed_traffic(self): | |
| s_recv_wr = u.get_recv_wr(self.server) | |
| u.post_recv(self.server, s_recv_wr) | |
| self.prepare_send_elements() | |
| for i in range(self.iters): | |
| self.client.qp.wr_start() | |
| if i % 2: | |
| self.client.mr.write('c' * self.client.mr.length, self.client.mr.length) | |
| self.client.qp.wr_flags = ibv_send_flags.IBV_SEND_SIGNALED | |
| self.client.qp.wr_send() | |
| self.client.qp.wr_set_sge(self.regular_send_sge) | |
| else: | |
| self.client.mr.write('s' * self.client.mr.length, self.client.mr.length) | |
| self.client.qp.wr_raw_wqe(self.raw_send_wqe) | |
| self.client.qp.wr_complete() | |
| u.poll_cq_ex(self.client.cq) | |
| u.poll_cq_ex(self.server.cq) | |
| u.post_recv(self.server, s_recv_wr) | |
| expected_opcode = ibv_wc_opcode.IBV_WC_SEND if i % 2 else ibv_wc_opcode.IBV_WC_DRIVER2 | |
| if self.client.cq.read_opcode() != expected_opcode: | |
| raise PyverbsError('Opcode validation failed: expected ' | |
| f'{expected_opcode}, received {self.client.cq.read_opcode()}') | |
| act_buffer = self.server.mr.read(self.server.mr.length, 0) | |
| u.validate(act_buffer, i % 2, self.server.mr.length) | |
| def test_mixed_raw_wqe_traffic(self): | |
| """ | |
| Runs traffic with a mix of SEND opcode regular WQEs and SEND opcode RAW | |
| WQEs. | |
| """ | |
| self.create_players(Mlx5RawWqeResources) | |
| self.mixed_traffic() |