From patchwork Thu Apr 25 02:21:04 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hao Xiang X-Patchwork-Id: 13642786 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id EF949C4345F for ; Thu, 25 Apr 2024 02:23:41 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1rzokr-0000SP-KW; Wed, 24 Apr 2024 22:22:33 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1rzokp-0000S0-RV for qemu-devel@nongnu.org; Wed, 24 Apr 2024 22:22:31 -0400 Received: from out-171.mta1.migadu.com ([95.215.58.171]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1rzokn-0004q2-9n for qemu-devel@nongnu.org; Wed, 24 Apr 2024 22:22:31 -0400 X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1714011745; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=lr14qF8cTKwF4Hevf4OoGD2r0msdSRvcgGtDvrTeAv0=; b=qRaCfkD7MzbM0yGmJeGF6Gb05dSJfCFip2TTvZHVqQTKsKDNI+b3aHLw3ycTZn5zeg8As8 nGv7iPdWEontI6xq9RZKhO1eG6EpCpTUth7noray4B+fd+3C3y04jGl/pajsTmRCjhkp1z +K2qDDWlj1SceccaE6Uhikzc2I0yQ5M= From: Hao Xiang To: marcandre.lureau@redhat.com, peterx@redhat.com, farosas@suse.de, armbru@redhat.com, lvivier@redhat.com, qemu-devel@nongnu.org Cc: Hao Xiang Subject: [PATCH v4 01/14] meson: Introduce new instruction set enqcmd to the build system. Date: Thu, 25 Apr 2024 02:21:04 +0000 Message-Id: <20240425022117.4035031-2-hao.xiang@linux.dev> In-Reply-To: <20240425022117.4035031-1-hao.xiang@linux.dev> References: <20240425022117.4035031-1-hao.xiang@linux.dev> MIME-Version: 1.0 X-Migadu-Flow: FLOW_OUT Received-SPF: pass client-ip=95.215.58.171; envelope-from=hao.xiang@linux.dev; helo=out-171.mta1.migadu.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Enable instruction set enqcmd in build. Signed-off-by: Hao Xiang --- meson.build | 14 ++++++++++++++ meson_options.txt | 2 ++ scripts/meson-buildoptions.sh | 3 +++ 3 files changed, 19 insertions(+) diff --git a/meson.build b/meson.build index 95cee7046e..9e008ddc34 100644 --- a/meson.build +++ b/meson.build @@ -2824,6 +2824,20 @@ config_host_data.set('CONFIG_AVX512BW_OPT', get_option('avx512bw') \ int main(int argc, char *argv[]) { return bar(argv[0]); } '''), error_message: 'AVX512BW not available').allowed()) +config_host_data.set('CONFIG_DSA_OPT', get_option('enqcmd') \ + .require(have_cpuid_h, error_message: 'cpuid.h not available, cannot enable ENQCMD') \ + .require(cc.links(''' + #include + #include + #include + static int __attribute__((target("enqcmd"))) bar(void *a) { + uint64_t dst[8] = { 0 }; + uint64_t src[8] = { 0 }; + return _enqcmd(dst, src); + } + int main(int argc, char *argv[]) { return bar(argv[argc - 1]); } + '''), error_message: 'ENQCMD not available').allowed()) + # For both AArch64 and AArch32, detect if builtins are available. config_host_data.set('CONFIG_ARM_AES_BUILTIN', cc.compiles(''' #include diff --git a/meson_options.txt b/meson_options.txt index b5c0bad9e7..63c1bf815b 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -121,6 +121,8 @@ option('avx512f', type: 'feature', value: 'disabled', description: 'AVX512F optimizations') option('avx512bw', type: 'feature', value: 'auto', description: 'AVX512BW optimizations') +option('enqcmd', type: 'feature', value: 'disabled', + description: 'MENQCMD optimizations') option('keyring', type: 'feature', value: 'auto', description: 'Linux keyring support') option('libkeyutils', type: 'feature', value: 'auto', diff --git a/scripts/meson-buildoptions.sh b/scripts/meson-buildoptions.sh index 5ace33f167..2cdfc84455 100644 --- a/scripts/meson-buildoptions.sh +++ b/scripts/meson-buildoptions.sh @@ -93,6 +93,7 @@ meson_options_help() { printf "%s\n" ' avx2 AVX2 optimizations' printf "%s\n" ' avx512bw AVX512BW optimizations' printf "%s\n" ' avx512f AVX512F optimizations' + printf "%s\n" ' enqcmd ENQCMD optimizations' printf "%s\n" ' blkio libblkio block device driver' printf "%s\n" ' bochs bochs image format support' printf "%s\n" ' bpf eBPF support' @@ -239,6 +240,8 @@ _meson_option_parse() { --disable-avx512bw) printf "%s" -Davx512bw=disabled ;; --enable-avx512f) printf "%s" -Davx512f=enabled ;; --disable-avx512f) printf "%s" -Davx512f=disabled ;; + --enable-enqcmd) printf "%s" -Denqcmd=enabled ;; + --disable-enqcmd) printf "%s" -Denqcmd=disabled ;; --enable-gcov) printf "%s" -Db_coverage=true ;; --disable-gcov) printf "%s" -Db_coverage=false ;; --enable-lto) printf "%s" -Db_lto=true ;; From patchwork Thu Apr 25 02:21:05 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hao Xiang X-Patchwork-Id: 13642782 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 5B36DC10F15 for ; Thu, 25 Apr 2024 02:23:17 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1rzokt-0000TA-JM; Wed, 24 Apr 2024 22:22:35 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1rzokr-0000Sa-Lf for qemu-devel@nongnu.org; Wed, 24 Apr 2024 22:22:33 -0400 Received: from out-188.mta1.migadu.com ([2001:41d0:203:375::bc]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1rzokn-0004qD-Ab for qemu-devel@nongnu.org; Wed, 24 Apr 2024 22:22:33 -0400 X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1714011747; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=kjdVWecrwwPDQpy9+vetY0jaSQPOxwH/bMy/SbjAqvk=; b=Z8AJbAtg3CYBc5IL4HlxzguoZnLc7gnnRS1J4bnTDq346KvL4Tr40M0jiyiVmTJQsJzbB/ uH7jT4GCflRk6gskgm7x3+Qv6K98WcrtoHe7lmbXcwLkpN5ZpxKojMQyaYLJ7Wo5WI3Ywv bCAXPTdmSHtiPB11SPNHcKNtXHU3Hp8= From: Hao Xiang To: marcandre.lureau@redhat.com, peterx@redhat.com, farosas@suse.de, armbru@redhat.com, lvivier@redhat.com, qemu-devel@nongnu.org Cc: Hao Xiang Subject: [PATCH v4 02/14] util/dsa: Add dependency idxd. Date: Thu, 25 Apr 2024 02:21:05 +0000 Message-Id: <20240425022117.4035031-3-hao.xiang@linux.dev> In-Reply-To: <20240425022117.4035031-1-hao.xiang@linux.dev> References: <20240425022117.4035031-1-hao.xiang@linux.dev> MIME-Version: 1.0 X-Migadu-Flow: FLOW_OUT Received-SPF: pass client-ip=2001:41d0:203:375::bc; envelope-from=hao.xiang@linux.dev; helo=out-188.mta1.migadu.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Idxd is the device driver for DSA (Intel Data Streaming Accelerator). The driver is fully functioning since Linux kernel 5.19. This change adds the driver's header file used for userspace development. Signed-off-by: Hao Xiang --- linux-headers/linux/idxd.h | 356 +++++++++++++++++++++++++++++++++++++ 1 file changed, 356 insertions(+) create mode 100644 linux-headers/linux/idxd.h diff --git a/linux-headers/linux/idxd.h b/linux-headers/linux/idxd.h new file mode 100644 index 0000000000..1d553bedbd --- /dev/null +++ b/linux-headers/linux/idxd.h @@ -0,0 +1,356 @@ +/* SPDX-License-Identifier: LGPL-2.1 WITH Linux-syscall-note */ +/* Copyright(c) 2019 Intel Corporation. All rights rsvd. */ +#ifndef _USR_IDXD_H_ +#define _USR_IDXD_H_ + +#ifdef __KERNEL__ +#include +#else +#include +#endif + +/* Driver command error status */ +enum idxd_scmd_stat { + IDXD_SCMD_DEV_ENABLED = 0x80000010, + IDXD_SCMD_DEV_NOT_ENABLED = 0x80000020, + IDXD_SCMD_WQ_ENABLED = 0x80000021, + IDXD_SCMD_DEV_DMA_ERR = 0x80020000, + IDXD_SCMD_WQ_NO_GRP = 0x80030000, + IDXD_SCMD_WQ_NO_NAME = 0x80040000, + IDXD_SCMD_WQ_NO_SVM = 0x80050000, + IDXD_SCMD_WQ_NO_THRESH = 0x80060000, + IDXD_SCMD_WQ_PORTAL_ERR = 0x80070000, + IDXD_SCMD_WQ_RES_ALLOC_ERR = 0x80080000, + IDXD_SCMD_PERCPU_ERR = 0x80090000, + IDXD_SCMD_DMA_CHAN_ERR = 0x800a0000, + IDXD_SCMD_CDEV_ERR = 0x800b0000, + IDXD_SCMD_WQ_NO_SWQ_SUPPORT = 0x800c0000, + IDXD_SCMD_WQ_NONE_CONFIGURED = 0x800d0000, + IDXD_SCMD_WQ_NO_SIZE = 0x800e0000, + IDXD_SCMD_WQ_NO_PRIV = 0x800f0000, + IDXD_SCMD_WQ_IRQ_ERR = 0x80100000, + IDXD_SCMD_WQ_USER_NO_IOMMU = 0x80110000, +}; + +#define IDXD_SCMD_SOFTERR_MASK 0x80000000 +#define IDXD_SCMD_SOFTERR_SHIFT 16 + +/* Descriptor flags */ +#define IDXD_OP_FLAG_FENCE 0x0001 +#define IDXD_OP_FLAG_BOF 0x0002 +#define IDXD_OP_FLAG_CRAV 0x0004 +#define IDXD_OP_FLAG_RCR 0x0008 +#define IDXD_OP_FLAG_RCI 0x0010 +#define IDXD_OP_FLAG_CRSTS 0x0020 +#define IDXD_OP_FLAG_CR 0x0080 +#define IDXD_OP_FLAG_CC 0x0100 +#define IDXD_OP_FLAG_ADDR1_TCS 0x0200 +#define IDXD_OP_FLAG_ADDR2_TCS 0x0400 +#define IDXD_OP_FLAG_ADDR3_TCS 0x0800 +#define IDXD_OP_FLAG_CR_TCS 0x1000 +#define IDXD_OP_FLAG_STORD 0x2000 +#define IDXD_OP_FLAG_DRDBK 0x4000 +#define IDXD_OP_FLAG_DSTS 0x8000 + +/* IAX */ +#define IDXD_OP_FLAG_RD_SRC2_AECS 0x010000 +#define IDXD_OP_FLAG_RD_SRC2_2ND 0x020000 +#define IDXD_OP_FLAG_WR_SRC2_AECS_COMP 0x040000 +#define IDXD_OP_FLAG_WR_SRC2_AECS_OVFL 0x080000 +#define IDXD_OP_FLAG_SRC2_STS 0x100000 +#define IDXD_OP_FLAG_CRC_RFC3720 0x200000 + +/* Opcode */ +enum dsa_opcode { + DSA_OPCODE_NOOP = 0, + DSA_OPCODE_BATCH, + DSA_OPCODE_DRAIN, + DSA_OPCODE_MEMMOVE, + DSA_OPCODE_MEMFILL, + DSA_OPCODE_COMPARE, + DSA_OPCODE_COMPVAL, + DSA_OPCODE_CR_DELTA, + DSA_OPCODE_AP_DELTA, + DSA_OPCODE_DUALCAST, + DSA_OPCODE_CRCGEN = 0x10, + DSA_OPCODE_COPY_CRC, + DSA_OPCODE_DIF_CHECK, + DSA_OPCODE_DIF_INS, + DSA_OPCODE_DIF_STRP, + DSA_OPCODE_DIF_UPDT, + DSA_OPCODE_CFLUSH = 0x20, +}; + +enum iax_opcode { + IAX_OPCODE_NOOP = 0, + IAX_OPCODE_DRAIN = 2, + IAX_OPCODE_MEMMOVE, + IAX_OPCODE_DECOMPRESS = 0x42, + IAX_OPCODE_COMPRESS, + IAX_OPCODE_CRC64, + IAX_OPCODE_ZERO_DECOMP_32 = 0x48, + IAX_OPCODE_ZERO_DECOMP_16, + IAX_OPCODE_ZERO_COMP_32 = 0x4c, + IAX_OPCODE_ZERO_COMP_16, + IAX_OPCODE_SCAN = 0x50, + IAX_OPCODE_SET_MEMBER, + IAX_OPCODE_EXTRACT, + IAX_OPCODE_SELECT, + IAX_OPCODE_RLE_BURST, + IAX_OPCODE_FIND_UNIQUE, + IAX_OPCODE_EXPAND, +}; + +/* Completion record status */ +enum dsa_completion_status { + DSA_COMP_NONE = 0, + DSA_COMP_SUCCESS, + DSA_COMP_SUCCESS_PRED, + DSA_COMP_PAGE_FAULT_NOBOF, + DSA_COMP_PAGE_FAULT_IR, + DSA_COMP_BATCH_FAIL, + DSA_COMP_BATCH_PAGE_FAULT, + DSA_COMP_DR_OFFSET_NOINC, + DSA_COMP_DR_OFFSET_ERANGE, + DSA_COMP_DIF_ERR, + DSA_COMP_BAD_OPCODE = 0x10, + DSA_COMP_INVALID_FLAGS, + DSA_COMP_NOZERO_RESERVE, + DSA_COMP_XFER_ERANGE, + DSA_COMP_DESC_CNT_ERANGE, + DSA_COMP_DR_ERANGE, + DSA_COMP_OVERLAP_BUFFERS, + DSA_COMP_DCAST_ERR, + DSA_COMP_DESCLIST_ALIGN, + DSA_COMP_INT_HANDLE_INVAL, + DSA_COMP_CRA_XLAT, + DSA_COMP_CRA_ALIGN, + DSA_COMP_ADDR_ALIGN, + DSA_COMP_PRIV_BAD, + DSA_COMP_TRAFFIC_CLASS_CONF, + DSA_COMP_PFAULT_RDBA, + DSA_COMP_HW_ERR1, + DSA_COMP_HW_ERR_DRB, + DSA_COMP_TRANSLATION_FAIL, +}; + +enum iax_completion_status { + IAX_COMP_NONE = 0, + IAX_COMP_SUCCESS, + IAX_COMP_PAGE_FAULT_IR = 0x04, + IAX_COMP_ANALYTICS_ERROR = 0x0a, + IAX_COMP_OUTBUF_OVERFLOW, + IAX_COMP_BAD_OPCODE = 0x10, + IAX_COMP_INVALID_FLAGS, + IAX_COMP_NOZERO_RESERVE, + IAX_COMP_INVALID_SIZE, + IAX_COMP_OVERLAP_BUFFERS = 0x16, + IAX_COMP_INT_HANDLE_INVAL = 0x19, + IAX_COMP_CRA_XLAT, + IAX_COMP_CRA_ALIGN, + IAX_COMP_ADDR_ALIGN, + IAX_COMP_PRIV_BAD, + IAX_COMP_TRAFFIC_CLASS_CONF, + IAX_COMP_PFAULT_RDBA, + IAX_COMP_HW_ERR1, + IAX_COMP_HW_ERR_DRB, + IAX_COMP_TRANSLATION_FAIL, + IAX_COMP_PRS_TIMEOUT, + IAX_COMP_WATCHDOG, + IAX_COMP_INVALID_COMP_FLAG = 0x30, + IAX_COMP_INVALID_FILTER_FLAG, + IAX_COMP_INVALID_INPUT_SIZE, + IAX_COMP_INVALID_NUM_ELEMS, + IAX_COMP_INVALID_SRC1_WIDTH, + IAX_COMP_INVALID_INVERT_OUT, +}; + +#define DSA_COMP_STATUS_MASK 0x7f +#define DSA_COMP_STATUS_WRITE 0x80 + +struct dsa_hw_desc { + uint32_t pasid:20; + uint32_t rsvd:11; + uint32_t priv:1; + uint32_t flags:24; + uint32_t opcode:8; + uint64_t completion_addr; + union { + uint64_t src_addr; + uint64_t rdback_addr; + uint64_t pattern; + uint64_t desc_list_addr; + }; + union { + uint64_t dst_addr; + uint64_t rdback_addr2; + uint64_t src2_addr; + uint64_t comp_pattern; + }; + union { + uint32_t xfer_size; + uint32_t desc_count; + }; + uint16_t int_handle; + uint16_t rsvd1; + union { + uint8_t expected_res; + /* create delta record */ + struct { + uint64_t delta_addr; + uint32_t max_delta_size; + uint32_t delt_rsvd; + uint8_t expected_res_mask; + }; + uint32_t delta_rec_size; + uint64_t dest2; + /* CRC */ + struct { + uint32_t crc_seed; + uint32_t crc_rsvd; + uint64_t seed_addr; + }; + /* DIF check or strip */ + struct { + uint8_t src_dif_flags; + uint8_t dif_chk_res; + uint8_t dif_chk_flags; + uint8_t dif_chk_res2[5]; + uint32_t chk_ref_tag_seed; + uint16_t chk_app_tag_mask; + uint16_t chk_app_tag_seed; + }; + /* DIF insert */ + struct { + uint8_t dif_ins_res; + uint8_t dest_dif_flag; + uint8_t dif_ins_flags; + uint8_t dif_ins_res2[13]; + uint32_t ins_ref_tag_seed; + uint16_t ins_app_tag_mask; + uint16_t ins_app_tag_seed; + }; + /* DIF update */ + struct { + uint8_t src_upd_flags; + uint8_t upd_dest_flags; + uint8_t dif_upd_flags; + uint8_t dif_upd_res[5]; + uint32_t src_ref_tag_seed; + uint16_t src_app_tag_mask; + uint16_t src_app_tag_seed; + uint32_t dest_ref_tag_seed; + uint16_t dest_app_tag_mask; + uint16_t dest_app_tag_seed; + }; + + uint8_t op_specific[24]; + }; +} __attribute__((packed)); + +struct iax_hw_desc { + uint32_t pasid:20; + uint32_t rsvd:11; + uint32_t priv:1; + uint32_t flags:24; + uint32_t opcode:8; + uint64_t completion_addr; + uint64_t src1_addr; + uint64_t dst_addr; + uint32_t src1_size; + uint16_t int_handle; + union { + uint16_t compr_flags; + uint16_t decompr_flags; + }; + uint64_t src2_addr; + uint32_t max_dst_size; + uint32_t src2_size; + uint32_t filter_flags; + uint32_t num_inputs; +} __attribute__((packed)); + +struct dsa_raw_desc { + uint64_t field[8]; +} __attribute__((packed)); + +/* + * The status field will be modified by hardware, therefore it should be + * volatile and prevent the compiler from optimize the read. + */ +struct dsa_completion_record { + volatile uint8_t status; + union { + uint8_t result; + uint8_t dif_status; + }; + uint16_t rsvd; + uint32_t bytes_completed; + uint64_t fault_addr; + union { + /* common record */ + struct { + uint32_t invalid_flags:24; + uint32_t rsvd2:8; + }; + + uint32_t delta_rec_size; + uint64_t crc_val; + + /* DIF check & strip */ + struct { + uint32_t dif_chk_ref_tag; + uint16_t dif_chk_app_tag_mask; + uint16_t dif_chk_app_tag; + }; + + /* DIF insert */ + struct { + uint64_t dif_ins_res; + uint32_t dif_ins_ref_tag; + uint16_t dif_ins_app_tag_mask; + uint16_t dif_ins_app_tag; + }; + + /* DIF update */ + struct { + uint32_t dif_upd_src_ref_tag; + uint16_t dif_upd_src_app_tag_mask; + uint16_t dif_upd_src_app_tag; + uint32_t dif_upd_dest_ref_tag; + uint16_t dif_upd_dest_app_tag_mask; + uint16_t dif_upd_dest_app_tag; + }; + + uint8_t op_specific[16]; + }; +} __attribute__((packed)); + +struct dsa_raw_completion_record { + uint64_t field[4]; +} __attribute__((packed)); + +struct iax_completion_record { + volatile uint8_t status; + uint8_t error_code; + uint16_t rsvd; + uint32_t bytes_completed; + uint64_t fault_addr; + uint32_t invalid_flags; + uint32_t rsvd2; + uint32_t output_size; + uint8_t output_bits; + uint8_t rsvd3; + uint16_t xor_csum; + uint32_t crc; + uint32_t min; + uint32_t max; + uint32_t sum; + uint64_t rsvd4[2]; +} __attribute__((packed)); + +struct iax_raw_completion_record { + uint64_t field[8]; +} __attribute__((packed)); + +#endif From patchwork Thu Apr 25 02:21:06 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hao Xiang X-Patchwork-Id: 13642791 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 875E7C10F15 for ; Thu, 25 Apr 2024 02:24:54 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1rzokw-0000Tj-VN; Wed, 24 Apr 2024 22:22:38 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1rzokt-0000T1-0D for qemu-devel@nongnu.org; Wed, 24 Apr 2024 22:22:35 -0400 Received: from out-189.mta1.migadu.com ([2001:41d0:203:375::bd]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1rzokq-0004rm-Hz for qemu-devel@nongnu.org; Wed, 24 Apr 2024 22:22:34 -0400 X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1714011749; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=NAbh7BYnj26RaAM2u77UOr3YjU1pxmHehljVAEbJqZw=; b=m7Z/FjumLtnmFqg/xRYOYNe1qZwJ1MwS5pF0I1q4OJJaRaZxqGve7EtbQuv9HBG1MEbQ+I XcPbGyZ5Ofso4SaUw7yzcEEO6QDT9/jyfsyXKQZauXoUjg0tCUeziFyk5Fa4ZfnEi6sbSR shRril6IEt4ajJb8oamJv6k0V2Plrsk= From: Hao Xiang To: marcandre.lureau@redhat.com, peterx@redhat.com, farosas@suse.de, armbru@redhat.com, lvivier@redhat.com, qemu-devel@nongnu.org Cc: Hao Xiang , Bryan Zhang Subject: [PATCH v4 03/14] util/dsa: Implement DSA device start and stop logic. Date: Thu, 25 Apr 2024 02:21:06 +0000 Message-Id: <20240425022117.4035031-4-hao.xiang@linux.dev> In-Reply-To: <20240425022117.4035031-1-hao.xiang@linux.dev> References: <20240425022117.4035031-1-hao.xiang@linux.dev> MIME-Version: 1.0 X-Migadu-Flow: FLOW_OUT Received-SPF: pass client-ip=2001:41d0:203:375::bd; envelope-from=hao.xiang@linux.dev; helo=out-189.mta1.migadu.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org * DSA device open and close. * DSA group contains multiple DSA devices. * DSA group configure/start/stop/clean. Signed-off-by: Hao Xiang Signed-off-by: Bryan Zhang --- include/qemu/dsa.h | 72 +++++++++++ util/dsa.c | 316 +++++++++++++++++++++++++++++++++++++++++++++ util/meson.build | 1 + 3 files changed, 389 insertions(+) create mode 100644 include/qemu/dsa.h create mode 100644 util/dsa.c diff --git a/include/qemu/dsa.h b/include/qemu/dsa.h new file mode 100644 index 0000000000..f15c05ee85 --- /dev/null +++ b/include/qemu/dsa.h @@ -0,0 +1,72 @@ +#ifndef QEMU_DSA_H +#define QEMU_DSA_H + +#include "qemu/error-report.h" +#include "qemu/thread.h" +#include "qemu/queue.h" + +#ifdef CONFIG_DSA_OPT + +#pragma GCC push_options +#pragma GCC target("enqcmd") + +#include +#include "x86intrin.h" + +/** + * @brief Initializes DSA devices. + * + * @param dsa_parameter A list of DSA device path from migration parameter. + * + * @return int Zero if successful, otherwise non zero. + */ +int dsa_init(const char *dsa_parameter); + +/** + * @brief Start logic to enable using DSA. + */ +void dsa_start(void); + +/** + * @brief Stop the device group and the completion thread. + */ +void dsa_stop(void); + +/** + * @brief Clean up system resources created for DSA offloading. + */ +void dsa_cleanup(void); + +/** + * @brief Check if DSA is running. + * + * @return True if DSA is running, otherwise false. + */ +bool dsa_is_running(void); + +#else + +static inline bool dsa_is_running(void) +{ + return false; +} + +static inline int dsa_init(const char *dsa_parameter) +{ + if (dsa_parameter != NULL && strlen(dsa_parameter) != 0) { + error_report("DSA not supported."); + return -1; + } + + return 0; +} + +static inline void dsa_start(void) {} + +static inline void dsa_stop(void) {} + +static inline void dsa_cleanup(void) {} + +#endif + +#endif diff --git a/util/dsa.c b/util/dsa.c new file mode 100644 index 0000000000..05bbf8e31a --- /dev/null +++ b/util/dsa.c @@ -0,0 +1,316 @@ +/* + * Use Intel Data Streaming Accelerator to offload certain background + * operations. + * + * Copyright (c) 2023 Hao Xiang + * Bryan Zhang + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "qemu/osdep.h" +#include "qemu/queue.h" +#include "qemu/memalign.h" +#include "qemu/lockable.h" +#include "qemu/cutils.h" +#include "qemu/dsa.h" +#include "qemu/bswap.h" +#include "qemu/error-report.h" +#include "qemu/rcu.h" + +#ifdef CONFIG_DSA_OPT + +#pragma GCC push_options +#pragma GCC target("enqcmd") + +#include +#include "x86intrin.h" + +#define DSA_WQ_SIZE 4096 +#define MAX_DSA_DEVICES 16 + +typedef QSIMPLEQ_HEAD(dsa_task_queue, dsa_batch_task) dsa_task_queue; + +struct dsa_device { + void *work_queue; +}; + +struct dsa_device_group { + struct dsa_device *dsa_devices; + int num_dsa_devices; + /* The index of the next DSA device to be used. */ + uint32_t device_allocator_index; + bool running; + QemuMutex task_queue_lock; + QemuCond task_queue_cond; + dsa_task_queue task_queue; +}; + +uint64_t max_retry_count; +static struct dsa_device_group dsa_group; + + +/** + * @brief This function opens a DSA device's work queue and + * maps the DSA device memory into the current process. + * + * @param dsa_wq_path A pointer to the DSA device work queue's file path. + * @return A pointer to the mapped memory, or MAP_FAILED on failure. + */ +static void * +map_dsa_device(const char *dsa_wq_path) +{ + void *dsa_device; + int fd; + + fd = open(dsa_wq_path, O_RDWR); + if (fd < 0) { + error_report("Open %s failed with errno = %d.", + dsa_wq_path, errno); + return MAP_FAILED; + } + dsa_device = mmap(NULL, DSA_WQ_SIZE, PROT_WRITE, + MAP_SHARED | MAP_POPULATE, fd, 0); + close(fd); + if (dsa_device == MAP_FAILED) { + error_report("mmap failed with errno = %d.", errno); + return MAP_FAILED; + } + return dsa_device; +} + +/** + * @brief Initializes a DSA device structure. + * + * @param instance A pointer to the DSA device. + * @param work_queue A pointer to the DSA work queue. + */ +static void +dsa_device_init(struct dsa_device *instance, + void *dsa_work_queue) +{ + instance->work_queue = dsa_work_queue; +} + +/** + * @brief Cleans up a DSA device structure. + * + * @param instance A pointer to the DSA device to cleanup. + */ +static void +dsa_device_cleanup(struct dsa_device *instance) +{ + if (instance->work_queue != MAP_FAILED) { + munmap(instance->work_queue, DSA_WQ_SIZE); + } +} + +/** + * @brief Initializes a DSA device group. + * + * @param group A pointer to the DSA device group. + * @param dsa_parameter A list of DSA device path from are separated by space + * character migration parameter. Multiple DSA device path. + * + * @return Zero if successful, non-zero otherwise. + */ +static int +dsa_device_group_init(struct dsa_device_group *group, + const char *dsa_parameter) +{ + if (dsa_parameter == NULL || strlen(dsa_parameter) == 0) { + return 0; + } + + int ret = 0; + char *local_dsa_parameter = g_strdup(dsa_parameter); + const char *dsa_path[MAX_DSA_DEVICES]; + int num_dsa_devices = 0; + char delim[2] = " "; + + char *current_dsa_path = strtok(local_dsa_parameter, delim); + + while (current_dsa_path != NULL) { + dsa_path[num_dsa_devices++] = current_dsa_path; + if (num_dsa_devices == MAX_DSA_DEVICES) { + break; + } + current_dsa_path = strtok(NULL, delim); + } + + group->dsa_devices = + g_new0(struct dsa_device, num_dsa_devices); + group->num_dsa_devices = num_dsa_devices; + group->device_allocator_index = 0; + + group->running = false; + qemu_mutex_init(&group->task_queue_lock); + qemu_cond_init(&group->task_queue_cond); + QSIMPLEQ_INIT(&group->task_queue); + + void *dsa_wq = MAP_FAILED; + for (int i = 0; i < num_dsa_devices; i++) { + dsa_wq = map_dsa_device(dsa_path[i]); + if (dsa_wq == MAP_FAILED) { + error_report("map_dsa_device failed MAP_FAILED."); + ret = -1; + goto exit; + } + dsa_device_init(&dsa_group.dsa_devices[i], dsa_wq); + } + +exit: + g_free(local_dsa_parameter); + return ret; +} + +/** + * @brief Starts a DSA device group. + * + * @param group A pointer to the DSA device group. + */ +static void +dsa_device_group_start(struct dsa_device_group *group) +{ + group->running = true; +} + +/** + * @brief Stops a DSA device group. + * + * @param group A pointer to the DSA device group. + */ +__attribute__((unused)) +static void +dsa_device_group_stop(struct dsa_device_group *group) +{ + group->running = false; +} + +/** + * @brief Cleans up a DSA device group. + * + * @param group A pointer to the DSA device group. + */ +static void +dsa_device_group_cleanup(struct dsa_device_group *group) +{ + if (!group->dsa_devices) { + return; + } + for (int i = 0; i < group->num_dsa_devices; i++) { + dsa_device_cleanup(&group->dsa_devices[i]); + } + g_free(group->dsa_devices); + group->dsa_devices = NULL; + + qemu_mutex_destroy(&group->task_queue_lock); + qemu_cond_destroy(&group->task_queue_cond); +} + +/** + * @brief Returns the next available DSA device in the group. + * + * @param group A pointer to the DSA device group. + * + * @return struct dsa_device* A pointer to the next available DSA device + * in the group. + */ +__attribute__((unused)) +static struct dsa_device * +dsa_device_group_get_next_device(struct dsa_device_group *group) +{ + if (group->num_dsa_devices == 0) { + return NULL; + } + uint32_t current = qatomic_fetch_inc(&group->device_allocator_index); + current %= group->num_dsa_devices; + return &group->dsa_devices[current]; +} + +/** + * @brief Check if DSA is running. + * + * @return True if DSA is running, otherwise false. + */ +bool dsa_is_running(void) +{ + return false; +} + +static void +dsa_globals_init(void) +{ + max_retry_count = UINT64_MAX; +} + +/** + * @brief Initializes DSA devices. + * + * @param dsa_parameter A list of DSA device path from migration parameter. + * + * @return int Zero if successful, otherwise non zero. + */ +int dsa_init(const char *dsa_parameter) +{ + dsa_globals_init(); + + return dsa_device_group_init(&dsa_group, dsa_parameter); +} + +/** + * @brief Start logic to enable using DSA. + * + */ +void dsa_start(void) +{ + if (dsa_group.num_dsa_devices == 0) { + return; + } + if (dsa_group.running) { + return; + } + dsa_device_group_start(&dsa_group); +} + +/** + * @brief Stop the device group and the completion thread. + * + */ +void dsa_stop(void) +{ + struct dsa_device_group *group = &dsa_group; + + if (!group->running) { + return; + } +} + +/** + * @brief Clean up system resources created for DSA offloading. + * + */ +void dsa_cleanup(void) +{ + dsa_stop(); + dsa_device_group_cleanup(&dsa_group); +} + +#endif + diff --git a/util/meson.build b/util/meson.build index 2ad57b10ba..144c6812e5 100644 --- a/util/meson.build +++ b/util/meson.build @@ -88,6 +88,7 @@ if have_block or have_ga endif if have_block util_ss.add(files('aio-wait.c')) + util_ss.add(files('dsa.c')) util_ss.add(files('buffer.c')) util_ss.add(files('bufferiszero.c')) util_ss.add(files('hbitmap.c')) From patchwork Thu Apr 25 02:21:07 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hao Xiang X-Patchwork-Id: 13642796 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 52EF1C19F4F for ; Thu, 25 Apr 2024 02:25:56 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1rzokx-0000Uj-Tt; Wed, 24 Apr 2024 22:22:39 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1rzoku-0000TQ-Bn for qemu-devel@nongnu.org; Wed, 24 Apr 2024 22:22:36 -0400 Received: from out-189.mta1.migadu.com ([95.215.58.189]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1rzoks-00051I-FL for qemu-devel@nongnu.org; Wed, 24 Apr 2024 22:22:36 -0400 X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1714011752; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=nlIyorlshT2KtpOtlnobLBBslJn63zcO14fOuSzWnq4=; b=FKoet1pLYSogT2dOq268S0y+aWTFC8gcp0VQQ3avSg+iMg6pMELQy2e48ufTT6JGCNP4PE e/LThCb3nVt4Ks3WcFr/171ztBIuqnDqxL0/v6Pq0esgxcUWpoGa/qF1Im8+AfJ/oWL75E Z/Ml+2CNDxInfZu5DIgB37+Xrc/HHjE= From: Hao Xiang To: marcandre.lureau@redhat.com, peterx@redhat.com, farosas@suse.de, armbru@redhat.com, lvivier@redhat.com, qemu-devel@nongnu.org Cc: Hao Xiang Subject: [PATCH v4 04/14] util/dsa: Implement DSA task enqueue and dequeue. Date: Thu, 25 Apr 2024 02:21:07 +0000 Message-Id: <20240425022117.4035031-5-hao.xiang@linux.dev> In-Reply-To: <20240425022117.4035031-1-hao.xiang@linux.dev> References: <20240425022117.4035031-1-hao.xiang@linux.dev> MIME-Version: 1.0 X-Migadu-Flow: FLOW_OUT Received-SPF: pass client-ip=95.215.58.189; envelope-from=hao.xiang@linux.dev; helo=out-189.mta1.migadu.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_MSPIKE_H2=-0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org * Use a safe thread queue for DSA task enqueue/dequeue. * Implement DSA task submission. * Implement DSA batch task submission. Signed-off-by: Hao Xiang --- include/qemu/dsa.h | 28 +++++++ util/dsa.c | 201 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 229 insertions(+) diff --git a/include/qemu/dsa.h b/include/qemu/dsa.h index f15c05ee85..37cae8d9d2 100644 --- a/include/qemu/dsa.h +++ b/include/qemu/dsa.h @@ -13,6 +13,34 @@ #include #include "x86intrin.h" +typedef enum DsaTaskType { + DSA_TASK = 0, + DSA_BATCH_TASK +} DsaTaskType; + +typedef enum DsaTaskStatus { + DSA_TASK_READY = 0, + DSA_TASK_PROCESSING, + DSA_TASK_COMPLETION +} DsaTaskStatus; + +typedef void (*dsa_completion_fn)(void *); + +typedef struct dsa_batch_task { + struct dsa_hw_desc batch_descriptor; + struct dsa_hw_desc *descriptors; + struct dsa_completion_record batch_completion __attribute__((aligned(32))); + struct dsa_completion_record *completions; + struct dsa_device_group *group; + struct dsa_device *device; + dsa_completion_fn completion_callback; + QemuSemaphore sem_task_complete; + DsaTaskType task_type; + DsaTaskStatus status; + int batch_size; + QSIMPLEQ_ENTRY(dsa_batch_task) entry; +} dsa_batch_task; + /** * @brief Initializes DSA devices. * diff --git a/util/dsa.c b/util/dsa.c index 05bbf8e31a..75739a1af6 100644 --- a/util/dsa.c +++ b/util/dsa.c @@ -244,6 +244,205 @@ dsa_device_group_get_next_device(struct dsa_device_group *group) return &group->dsa_devices[current]; } +/** + * @brief Empties out the DSA task queue. + * + * @param group A pointer to the DSA device group. + */ +static void +dsa_empty_task_queue(struct dsa_device_group *group) +{ + qemu_mutex_lock(&group->task_queue_lock); + dsa_task_queue *task_queue = &group->task_queue; + while (!QSIMPLEQ_EMPTY(task_queue)) { + QSIMPLEQ_REMOVE_HEAD(task_queue, entry); + } + qemu_mutex_unlock(&group->task_queue_lock); +} + +/** + * @brief Adds a task to the DSA task queue. + * + * @param group A pointer to the DSA device group. + * @param context A pointer to the DSA task to enqueue. + * + * @return int Zero if successful, otherwise a proper error code. + */ +static int +dsa_task_enqueue(struct dsa_device_group *group, + struct dsa_batch_task *task) +{ + dsa_task_queue *task_queue = &group->task_queue; + QemuMutex *task_queue_lock = &group->task_queue_lock; + QemuCond *task_queue_cond = &group->task_queue_cond; + + bool notify = false; + + qemu_mutex_lock(task_queue_lock); + + if (!group->running) { + error_report("DSA: Tried to queue task to stopped device queue."); + qemu_mutex_unlock(task_queue_lock); + return -1; + } + + /* The queue is empty. This enqueue operation is a 0->1 transition. */ + if (QSIMPLEQ_EMPTY(task_queue)) { + notify = true; + } + + QSIMPLEQ_INSERT_TAIL(task_queue, task, entry); + + /* We need to notify the waiter for 0->1 transitions. */ + if (notify) { + qemu_cond_signal(task_queue_cond); + } + + qemu_mutex_unlock(task_queue_lock); + + return 0; +} + +/** + * @brief Takes a DSA task out of the task queue. + * + * @param group A pointer to the DSA device group. + * @return dsa_batch_task* The DSA task being dequeued. + */ +__attribute__((unused)) +static struct dsa_batch_task * +dsa_task_dequeue(struct dsa_device_group *group) +{ + struct dsa_batch_task *task = NULL; + dsa_task_queue *task_queue = &group->task_queue; + QemuMutex *task_queue_lock = &group->task_queue_lock; + QemuCond *task_queue_cond = &group->task_queue_cond; + + qemu_mutex_lock(task_queue_lock); + + while (true) { + if (!group->running) { + goto exit; + } + task = QSIMPLEQ_FIRST(task_queue); + if (task != NULL) { + break; + } + qemu_cond_wait(task_queue_cond, task_queue_lock); + } + + QSIMPLEQ_REMOVE_HEAD(task_queue, entry); + +exit: + qemu_mutex_unlock(task_queue_lock); + return task; +} + +/** + * @brief Submits a DSA work item to the device work queue. + * + * @param wq A pointer to the DSA work queue's device memory. + * @param descriptor A pointer to the DSA work item descriptor. + * + * @return Zero if successful, non-zero otherwise. + */ +static int +submit_wi_int(void *wq, struct dsa_hw_desc *descriptor) +{ + uint64_t retry = 0; + + _mm_sfence(); + + while (true) { + if (_enqcmd(wq, descriptor) == 0) { + break; + } + retry++; + if (retry > max_retry_count) { + error_report("Submit work retry %lu times.", retry); + return -1; + } + } + + return 0; +} + +/** + * @brief Synchronously submits a DSA work item to the + * device work queue. + * + * @param wq A pointer to the DSA worjk queue's device memory. + * @param descriptor A pointer to the DSA work item descriptor. + * + * @return int Zero if successful, non-zero otherwise. + */ +__attribute__((unused)) +static int +submit_wi(void *wq, struct dsa_hw_desc *descriptor) +{ + return submit_wi_int(wq, descriptor); +} + +/** + * @brief Asynchronously submits a DSA work item to the + * device work queue. + * + * @param task A pointer to the buffer zero task. + * + * @return int Zero if successful, non-zero otherwise. + */ +__attribute__((unused)) +static int +submit_wi_async(struct dsa_batch_task *task) +{ + struct dsa_device_group *device_group = task->group; + struct dsa_device *device_instance = task->device; + int ret; + + assert(task->task_type == DSA_TASK); + + task->status = DSA_TASK_PROCESSING; + + ret = submit_wi_int(device_instance->work_queue, + &task->descriptors[0]); + if (ret != 0) { + return ret; + } + + return dsa_task_enqueue(device_group, task); +} + +/** + * @brief Asynchronously submits a DSA batch work item to the + * device work queue. + * + * @param dsa_batch_task A pointer to the batch buffer zero task. + * + * @return int Zero if successful, non-zero otherwise. + */ +__attribute__((unused)) +static int +submit_batch_wi_async(struct dsa_batch_task *batch_task) +{ + struct dsa_device_group *device_group = batch_task->group; + struct dsa_device *device_instance = batch_task->device; + int ret; + + assert(batch_task->task_type == DSA_BATCH_TASK); + assert(batch_task->batch_descriptor.desc_count <= batch_task->batch_size); + assert(batch_task->status == DSA_TASK_READY); + + batch_task->status = DSA_TASK_PROCESSING; + + ret = submit_wi_int(device_instance->work_queue, + &batch_task->batch_descriptor); + if (ret != 0) { + return ret; + } + + return dsa_task_enqueue(device_group, batch_task); +} + /** * @brief Check if DSA is running. * @@ -300,6 +499,8 @@ void dsa_stop(void) if (!group->running) { return; } + + dsa_empty_task_queue(group); } /** From patchwork Thu Apr 25 02:21:08 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hao Xiang X-Patchwork-Id: 13642787 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 1B979C10F15 for ; Thu, 25 Apr 2024 02:23:43 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1rzol0-0000W1-LL; Wed, 24 Apr 2024 22:22:42 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1rzokw-0000Tk-Vh for qemu-devel@nongnu.org; Wed, 24 Apr 2024 22:22:38 -0400 Received: from out-173.mta1.migadu.com ([2001:41d0:203:375::ad]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1rzoku-00054g-9n for qemu-devel@nongnu.org; Wed, 24 Apr 2024 22:22:38 -0400 X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1714011754; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=VNJkfGyi2rtj7X7uudx4KFAw0gzv12DqnHcWYmGz0MA=; b=NGx2I39l8uAUMKGB8OxQOCrx7ur06QI5C0ZruaX2B9pqQ655ukd4Vaik7Yr8LMp0m6mTr8 z9qnACHKOYnGOofJL9be/QGweMpjvUZboDNWvuxiELYX5uMdQXpLvt0qCMKN+sJO0z+JqE B1KV/RvkhXghMmIfpCxusDLrYXZvzJs= From: Hao Xiang To: marcandre.lureau@redhat.com, peterx@redhat.com, farosas@suse.de, armbru@redhat.com, lvivier@redhat.com, qemu-devel@nongnu.org Cc: Hao Xiang Subject: [PATCH v4 05/14] util/dsa: Implement DSA task asynchronous completion thread model. Date: Thu, 25 Apr 2024 02:21:08 +0000 Message-Id: <20240425022117.4035031-6-hao.xiang@linux.dev> In-Reply-To: <20240425022117.4035031-1-hao.xiang@linux.dev> References: <20240425022117.4035031-1-hao.xiang@linux.dev> MIME-Version: 1.0 X-Migadu-Flow: FLOW_OUT Received-SPF: pass client-ip=2001:41d0:203:375::ad; envelope-from=hao.xiang@linux.dev; helo=out-173.mta1.migadu.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org * Create a dedicated thread for DSA task completion. * DSA completion thread runs a loop and poll for completed tasks. * Start and stop DSA completion thread during DSA device start stop. User space application can directly submit task to Intel DSA accelerator by writing to DSA's device memory (mapped in user space). Once a task is submitted, the device starts processing it and write the completion status back to the task. A user space application can poll the task's completion status to check for completion. This change uses a dedicated thread to perform DSA task completion checking. Signed-off-by: Hao Xiang --- include/qemu/dsa.h | 1 + util/dsa.c | 274 ++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 274 insertions(+), 1 deletion(-) diff --git a/include/qemu/dsa.h b/include/qemu/dsa.h index 37cae8d9d2..2513192a2b 100644 --- a/include/qemu/dsa.h +++ b/include/qemu/dsa.h @@ -38,6 +38,7 @@ typedef struct dsa_batch_task { DsaTaskType task_type; DsaTaskStatus status; int batch_size; + bool *results; QSIMPLEQ_ENTRY(dsa_batch_task) entry; } dsa_batch_task; diff --git a/util/dsa.c b/util/dsa.c index 75739a1af6..003c4f47d9 100644 --- a/util/dsa.c +++ b/util/dsa.c @@ -44,6 +44,7 @@ #define DSA_WQ_SIZE 4096 #define MAX_DSA_DEVICES 16 +#define DSA_COMPLETION_THREAD "dsa_completion" typedef QSIMPLEQ_HEAD(dsa_task_queue, dsa_batch_task) dsa_task_queue; @@ -62,8 +63,18 @@ struct dsa_device_group { dsa_task_queue task_queue; }; +struct dsa_completion_thread { + bool stopping; + bool running; + QemuThread thread; + int thread_id; + QemuSemaphore sem_init_done; + struct dsa_device_group *group; +}; + uint64_t max_retry_count; static struct dsa_device_group dsa_group; +static struct dsa_completion_thread completion_thread; /** @@ -443,6 +454,265 @@ submit_batch_wi_async(struct dsa_batch_task *batch_task) return dsa_task_enqueue(device_group, batch_task); } +/** + * @brief Poll for the DSA work item completion. + * + * @param completion A pointer to the DSA work item completion record. + * @param opcode The DSA opcode. + * + * @return Zero if successful, non-zero otherwise. + */ +static int +poll_completion(struct dsa_completion_record *completion, + enum dsa_opcode opcode) +{ + uint8_t status; + uint64_t retry = 0; + + while (true) { + /* The DSA operation completes successfully or fails. */ + status = completion->status; + if (status == DSA_COMP_SUCCESS || + status == DSA_COMP_PAGE_FAULT_NOBOF || + status == DSA_COMP_BATCH_PAGE_FAULT || + status == DSA_COMP_BATCH_FAIL) { + break; + } else if (status != DSA_COMP_NONE) { + error_report("DSA opcode %d failed with status = %d.", + opcode, status); + return 1; + } + retry++; + if (retry > max_retry_count) { + error_report("DSA wait for completion retry %lu times.", retry); + return 1; + } + _mm_pause(); + } + + return 0; +} + +/** + * @brief Complete a single DSA task in the batch task. + * + * @param task A pointer to the batch task structure. + * + * @return Zero if successful, otherwise non-zero. + */ +static int +poll_task_completion(struct dsa_batch_task *task) +{ + assert(task->task_type == DSA_TASK); + + struct dsa_completion_record *completion = &task->completions[0]; + uint8_t status; + int ret; + + ret = poll_completion(completion, task->descriptors[0].opcode); + if (ret != 0) { + goto exit; + } + + status = completion->status; + if (status == DSA_COMP_SUCCESS) { + task->results[0] = (completion->result == 0); + goto exit; + } + + assert(status == DSA_COMP_PAGE_FAULT_NOBOF); + +exit: + return ret; +} + +/** + * @brief Poll a batch task status until it completes. If DSA task doesn't + * complete properly, use CPU to complete the task. + * + * @param batch_task A pointer to the DSA batch task. + * + * @return Zero if successful, otherwise non-zero. + */ +static int +poll_batch_task_completion(struct dsa_batch_task *batch_task) +{ + struct dsa_completion_record *batch_completion = + &batch_task->batch_completion; + struct dsa_completion_record *completion; + uint8_t batch_status; + uint8_t status; + bool *results = batch_task->results; + uint32_t count = batch_task->batch_descriptor.desc_count; + int ret; + + ret = poll_completion(batch_completion, + batch_task->batch_descriptor.opcode); + if (ret != 0) { + goto exit; + } + + batch_status = batch_completion->status; + + if (batch_status == DSA_COMP_SUCCESS) { + if (batch_completion->bytes_completed == count) { + /* + * Let's skip checking for each descriptors' completion status + * if the batch descriptor says all succedded. + */ + for (int i = 0; i < count; i++) { + assert(batch_task->completions[i].status == DSA_COMP_SUCCESS); + results[i] = (batch_task->completions[i].result == 0); + } + goto exit; + } + } else { + assert(batch_status == DSA_COMP_BATCH_FAIL || + batch_status == DSA_COMP_BATCH_PAGE_FAULT); + } + + for (int i = 0; i < count; i++) { + + completion = &batch_task->completions[i]; + status = completion->status; + + if (status == DSA_COMP_SUCCESS) { + results[i] = (completion->result == 0); + continue; + } + + assert(status == DSA_COMP_PAGE_FAULT_NOBOF); + + if (status != DSA_COMP_PAGE_FAULT_NOBOF) { + error_report("Unexpected DSA completion status = %u.", status); + ret = 1; + goto exit; + } + } + +exit: + return ret; +} + +/** + * @brief Handles an asynchronous DSA batch task completion. + * + * @param task A pointer to the batch buffer zero task structure. + */ +static void +dsa_batch_task_complete(struct dsa_batch_task *batch_task) +{ + batch_task->status = DSA_TASK_COMPLETION; + batch_task->completion_callback(batch_task); +} + +/** + * @brief The function entry point called by a dedicated DSA + * work item completion thread. + * + * @param opaque A pointer to the thread context. + * + * @return void* Not used. + */ +static void * +dsa_completion_loop(void *opaque) +{ + struct dsa_completion_thread *thread_context = + (struct dsa_completion_thread *)opaque; + struct dsa_batch_task *batch_task; + struct dsa_device_group *group = thread_context->group; + int ret; + + rcu_register_thread(); + + thread_context->thread_id = qemu_get_thread_id(); + qemu_sem_post(&thread_context->sem_init_done); + + while (thread_context->running) { + batch_task = dsa_task_dequeue(group); + assert(batch_task != NULL || !group->running); + if (!group->running) { + assert(!thread_context->running); + break; + } + if (batch_task->task_type == DSA_TASK) { + ret = poll_task_completion(batch_task); + } else { + assert(batch_task->task_type == DSA_BATCH_TASK); + ret = poll_batch_task_completion(batch_task); + } + + if (ret != 0) { + goto exit; + } + + dsa_batch_task_complete(batch_task); + } + +exit: + if (ret != 0) { + error_report("DSA completion thread exited due to internal error."); + } + rcu_unregister_thread(); + return NULL; +} + +/** + * @brief Initializes a DSA completion thread. + * + * @param completion_thread A pointer to the completion thread context. + * @param group A pointer to the DSA device group. + */ +static void +dsa_completion_thread_init( + struct dsa_completion_thread *completion_thread, + struct dsa_device_group *group) +{ + completion_thread->stopping = false; + completion_thread->running = true; + completion_thread->thread_id = -1; + qemu_sem_init(&completion_thread->sem_init_done, 0); + completion_thread->group = group; + + qemu_thread_create(&completion_thread->thread, + DSA_COMPLETION_THREAD, + dsa_completion_loop, + completion_thread, + QEMU_THREAD_JOINABLE); + + /* Wait for initialization to complete */ + qemu_sem_wait(&completion_thread->sem_init_done); +} + +/** + * @brief Stops the completion thread (and implicitly, the device group). + * + * @param opaque A pointer to the completion thread. + */ +static void dsa_completion_thread_stop(void *opaque) +{ + struct dsa_completion_thread *thread_context = + (struct dsa_completion_thread *)opaque; + + struct dsa_device_group *group = thread_context->group; + + qemu_mutex_lock(&group->task_queue_lock); + + thread_context->stopping = true; + thread_context->running = false; + + /* Prevent the compiler from setting group->running first. */ + barrier(); + dsa_device_group_stop(group); + + qemu_cond_signal(&group->task_queue_cond); + qemu_mutex_unlock(&group->task_queue_lock); + + qemu_thread_join(&thread_context->thread); + + qemu_sem_destroy(&thread_context->sem_init_done); +} + /** * @brief Check if DSA is running. * @@ -450,7 +720,7 @@ submit_batch_wi_async(struct dsa_batch_task *batch_task) */ bool dsa_is_running(void) { - return false; + return completion_thread.running; } static void @@ -486,6 +756,7 @@ void dsa_start(void) return; } dsa_device_group_start(&dsa_group); + dsa_completion_thread_init(&completion_thread, &dsa_group); } /** @@ -500,6 +771,7 @@ void dsa_stop(void) return; } + dsa_completion_thread_stop(&completion_thread); dsa_empty_task_queue(group); } From patchwork Thu Apr 25 02:21:09 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hao Xiang X-Patchwork-Id: 13642784 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 589AEC4345F for ; Thu, 25 Apr 2024 02:23:17 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1rzol4-0000XL-Bg; Wed, 24 Apr 2024 22:22:46 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1rzokz-0000W4-TZ for qemu-devel@nongnu.org; Wed, 24 Apr 2024 22:22:42 -0400 Received: from out-182.mta1.migadu.com ([2001:41d0:203:375::b6]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1rzokx-00058U-BM for qemu-devel@nongnu.org; Wed, 24 Apr 2024 22:22:41 -0400 X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1714011757; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=vCK0OaAzn2uiGL4qe3G1NlR2NavXKytCE3U+haCGbzE=; b=DSp9ta4bOcDDmjxiLijpgb9lvc6kITQke3RhLpkMRlT/uxLyoups1Nn9UASqvjWpMKG1eE AwxNcym3+uI1kZxRp6HJeLQOLiB7E3UFSuzp/jo52p/X6t7aP+iWSr63U5w+ctMaRB7iKd Yj6G2zKGR+SIpEBJu7/wi++PEuYeC/g= From: Hao Xiang To: marcandre.lureau@redhat.com, peterx@redhat.com, farosas@suse.de, armbru@redhat.com, lvivier@redhat.com, qemu-devel@nongnu.org Cc: Hao Xiang , Bryan Zhang Subject: [PATCH v4 06/14] util/dsa: Implement zero page checking in DSA task. Date: Thu, 25 Apr 2024 02:21:09 +0000 Message-Id: <20240425022117.4035031-7-hao.xiang@linux.dev> In-Reply-To: <20240425022117.4035031-1-hao.xiang@linux.dev> References: <20240425022117.4035031-1-hao.xiang@linux.dev> MIME-Version: 1.0 X-Migadu-Flow: FLOW_OUT Received-SPF: pass client-ip=2001:41d0:203:375::b6; envelope-from=hao.xiang@linux.dev; helo=out-182.mta1.migadu.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Create DSA task with operation code DSA_OPCODE_COMPVAL. Here we create two types of DSA tasks, a single DSA task and a batch DSA task. Batch DSA task reduces task submission overhead and hence should be the default option. However, due to the way DSA hardware works, a DSA batch task must contain at least two individual tasks. There are times we need to submit a single task and hence a single DSA task submission is also required. Signed-off-by: Hao Xiang Signed-off-by: Bryan Zhang --- include/qemu/dsa.h | 18 ++++ util/dsa.c | 247 +++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 244 insertions(+), 21 deletions(-) diff --git a/include/qemu/dsa.h b/include/qemu/dsa.h index 2513192a2b..645e6fc367 100644 --- a/include/qemu/dsa.h +++ b/include/qemu/dsa.h @@ -73,6 +73,24 @@ void dsa_cleanup(void); */ bool dsa_is_running(void); +/** + * @brief Initializes a buffer zero batch task. + * + * @param task A pointer to the batch task to initialize. + * @param results A pointer to an array of zero page checking results. + * @param batch_size The number of DSA tasks in the batch. + */ +void +buffer_zero_batch_task_init(struct dsa_batch_task *task, + bool *results, int batch_size); + +/** + * @brief Performs the proper cleanup on a DSA batch task. + * + * @param task A pointer to the batch task to cleanup. + */ +void buffer_zero_batch_task_destroy(struct dsa_batch_task *task); + #else static inline bool dsa_is_running(void) diff --git a/util/dsa.c b/util/dsa.c index 003c4f47d9..9db4cfcf1d 100644 --- a/util/dsa.c +++ b/util/dsa.c @@ -76,6 +76,7 @@ uint64_t max_retry_count; static struct dsa_device_group dsa_group; static struct dsa_completion_thread completion_thread; +static void buffer_zero_dsa_completion(void *context); /** * @brief This function opens a DSA device's work queue and @@ -207,7 +208,6 @@ dsa_device_group_start(struct dsa_device_group *group) * * @param group A pointer to the DSA device group. */ -__attribute__((unused)) static void dsa_device_group_stop(struct dsa_device_group *group) { @@ -243,7 +243,6 @@ dsa_device_group_cleanup(struct dsa_device_group *group) * @return struct dsa_device* A pointer to the next available DSA device * in the group. */ -__attribute__((unused)) static struct dsa_device * dsa_device_group_get_next_device(struct dsa_device_group *group) { @@ -320,7 +319,6 @@ dsa_task_enqueue(struct dsa_device_group *group, * @param group A pointer to the DSA device group. * @return dsa_batch_task* The DSA task being dequeued. */ -__attribute__((unused)) static struct dsa_batch_task * dsa_task_dequeue(struct dsa_device_group *group) { @@ -378,22 +376,6 @@ submit_wi_int(void *wq, struct dsa_hw_desc *descriptor) return 0; } -/** - * @brief Synchronously submits a DSA work item to the - * device work queue. - * - * @param wq A pointer to the DSA worjk queue's device memory. - * @param descriptor A pointer to the DSA work item descriptor. - * - * @return int Zero if successful, non-zero otherwise. - */ -__attribute__((unused)) -static int -submit_wi(void *wq, struct dsa_hw_desc *descriptor) -{ - return submit_wi_int(wq, descriptor); -} - /** * @brief Asynchronously submits a DSA work item to the * device work queue. @@ -402,7 +384,6 @@ submit_wi(void *wq, struct dsa_hw_desc *descriptor) * * @return int Zero if successful, non-zero otherwise. */ -__attribute__((unused)) static int submit_wi_async(struct dsa_batch_task *task) { @@ -431,7 +412,6 @@ submit_wi_async(struct dsa_batch_task *task) * * @return int Zero if successful, non-zero otherwise. */ -__attribute__((unused)) static int submit_batch_wi_async(struct dsa_batch_task *batch_task) { @@ -713,6 +693,231 @@ static void dsa_completion_thread_stop(void *opaque) qemu_sem_destroy(&thread_context->sem_init_done); } +/** + * @brief Initializes a buffer zero comparison DSA task. + * + * @param descriptor A pointer to the DSA task descriptor. + * @param completion A pointer to the DSA task completion record. + */ +static void +buffer_zero_task_init_int(struct dsa_hw_desc *descriptor, + struct dsa_completion_record *completion) +{ + descriptor->opcode = DSA_OPCODE_COMPVAL; + descriptor->flags = IDXD_OP_FLAG_RCR | IDXD_OP_FLAG_CRAV; + descriptor->comp_pattern = (uint64_t)0; + descriptor->completion_addr = (uint64_t)completion; +} + +/** + * @brief Initializes a buffer zero batch task. + * + * @param task A pointer to the batch task to initialize. + * @param results A pointer to an array of zero page checking results. + * @param batch_size The number of DSA tasks in the batch. + */ +void +buffer_zero_batch_task_init(struct dsa_batch_task *task, + bool *results, int batch_size) +{ + int descriptors_size = sizeof(*task->descriptors) * batch_size; + memset(task, 0, sizeof(*task)); + + task->descriptors = + (struct dsa_hw_desc *)qemu_memalign(64, descriptors_size); + memset(task->descriptors, 0, descriptors_size); + task->completions = (struct dsa_completion_record *)qemu_memalign( + 32, sizeof(*task->completions) * batch_size); + task->results = results; + task->batch_size = batch_size; + + task->batch_completion.status = DSA_COMP_NONE; + task->batch_descriptor.completion_addr = (uint64_t)&task->batch_completion; + /* TODO: Ensure that we never send a batch with count <= 1 */ + task->batch_descriptor.desc_count = 0; + task->batch_descriptor.opcode = DSA_OPCODE_BATCH; + task->batch_descriptor.flags = IDXD_OP_FLAG_RCR | IDXD_OP_FLAG_CRAV; + task->batch_descriptor.desc_list_addr = (uintptr_t)task->descriptors; + task->status = DSA_TASK_READY; + task->group = &dsa_group; + task->device = dsa_device_group_get_next_device(&dsa_group); + + for (int i = 0; i < task->batch_size; i++) { + buffer_zero_task_init_int(&task->descriptors[i], + &task->completions[i]); + } + + qemu_sem_init(&task->sem_task_complete, 0); + task->completion_callback = buffer_zero_dsa_completion; +} + +/** + * @brief Performs the proper cleanup on a DSA batch task. + * + * @param task A pointer to the batch task to cleanup. + */ +void +buffer_zero_batch_task_destroy(struct dsa_batch_task *task) +{ + qemu_vfree(task->descriptors); + qemu_vfree(task->completions); + task->results = NULL; + + qemu_sem_destroy(&task->sem_task_complete); +} + +/** + * @brief Resets a buffer zero comparison DSA batch task. + * + * @param task A pointer to the batch task. + * @param count The number of DSA tasks this batch task will contain. + */ +static void +buffer_zero_batch_task_reset(struct dsa_batch_task *task, size_t count) +{ + task->batch_completion.status = DSA_COMP_NONE; + task->batch_descriptor.desc_count = count; + task->task_type = DSA_BATCH_TASK; + task->status = DSA_TASK_READY; +} + +/** + * @brief Sets a buffer zero comparison DSA task. + * + * @param descriptor A pointer to the DSA task descriptor. + * @param buf A pointer to the memory buffer. + * @param len The length of the buffer. + */ +static void +buffer_zero_task_set_int(struct dsa_hw_desc *descriptor, + const void *buf, + size_t len) +{ + struct dsa_completion_record *completion = + (struct dsa_completion_record *)descriptor->completion_addr; + + descriptor->xfer_size = len; + descriptor->src_addr = (uintptr_t)buf; + completion->status = 0; + completion->result = 0; +} + +/** + * @brief Resets a buffer zero comparison DSA batch task. + * + * @param task A pointer to the DSA batch task. + */ +static void +buffer_zero_task_reset(struct dsa_batch_task *task) +{ + task->completions[0].status = DSA_COMP_NONE; + task->task_type = DSA_TASK; + task->status = DSA_TASK_READY; +} + +/** + * @brief Sets a buffer zero comparison DSA task. + * + * @param task A pointer to the DSA task. + * @param buf A pointer to the memory buffer. + * @param len The buffer length. + */ +static void +buffer_zero_task_set(struct dsa_batch_task *task, + const void *buf, + size_t len) +{ + buffer_zero_task_reset(task); + buffer_zero_task_set_int(&task->descriptors[0], buf, len); +} + +/** + * @brief Sets a buffer zero comparison batch task. + * + * @param batch_task A pointer to the batch task. + * @param buf An array of memory buffers. + * @param count The number of buffers in the array. + * @param len The length of the buffers. + */ +static void +buffer_zero_batch_task_set(struct dsa_batch_task *batch_task, + const void **buf, size_t count, size_t len) +{ + assert(count > 0); + assert(count <= batch_task->batch_size); + + buffer_zero_batch_task_reset(batch_task, count); + for (int i = 0; i < count; i++) { + buffer_zero_task_set_int(&batch_task->descriptors[i], buf[i], len); + } +} + +/** + * @brief Asychronously perform a buffer zero DSA operation. + * + * @param task A pointer to the batch task structure. + * @param buf A pointer to the memory buffer. + * @param len The length of the memory buffer. + * + * @return int Zero if successful, otherwise an appropriate error code. + */ +__attribute__((unused)) +static int +buffer_zero_dsa_async(struct dsa_batch_task *task, + const void *buf, size_t len) +{ + buffer_zero_task_set(task, buf, len); + + return submit_wi_async(task); +} + +/** + * @brief Sends a memory comparison batch task to a DSA device and wait + * for completion. + * + * @param batch_task The batch task to be submitted to DSA device. + * @param buf An array of memory buffers to check for zero. + * @param count The number of buffers. + * @param len The buffer length. + */ +__attribute__((unused)) +static int +buffer_zero_dsa_batch_async(struct dsa_batch_task *batch_task, + const void **buf, size_t count, size_t len) +{ + assert(count <= batch_task->batch_size); + buffer_zero_batch_task_set(batch_task, buf, count, len); + + return submit_batch_wi_async(batch_task); +} + +/** + * @brief The completion callback function for buffer zero + * comparison DSA task completion. + * + * @param context A pointer to the callback context. + */ +static void +buffer_zero_dsa_completion(void *context) +{ + assert(context != NULL); + + struct dsa_batch_task *task = (struct dsa_batch_task *)context; + qemu_sem_post(&task->sem_task_complete); +} + +/** + * @brief Wait for the asynchronous DSA task to complete. + * + * @param batch_task A pointer to the buffer zero comparison batch task. + */ +__attribute__((unused)) +static void +buffer_zero_dsa_wait(struct dsa_batch_task *batch_task) +{ + qemu_sem_wait(&batch_task->sem_task_complete); +} + /** * @brief Check if DSA is running. * From patchwork Thu Apr 25 02:21:10 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hao Xiang X-Patchwork-Id: 13642788 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 33507C10F15 for ; Thu, 25 Apr 2024 02:24:33 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1rzol5-0000Xe-4R; Wed, 24 Apr 2024 22:22:47 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1rzol0-0000WX-LW for qemu-devel@nongnu.org; Wed, 24 Apr 2024 22:22:42 -0400 Received: from out-181.mta1.migadu.com ([95.215.58.181]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1rzoky-0005AI-GN for qemu-devel@nongnu.org; Wed, 24 Apr 2024 22:22:42 -0400 X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1714011759; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=EGc89WKM0cHq+3UC0v4DbA0/xNOJoDXKucErcy0uuiY=; b=N6xoF3F73kIv8H/hfvV+egYoZEo1tfaV8qqLMD+9H6mCii5OPPwfx8xxJO6Eyw9LXvZhAp ZYuGHT3ldLI1KPWPTJFG8DjpBTDfGSXTJvz9xzCfBjwbvSbNthSgOcWgUCB64W5fYLnCvI EL+aDTysNY2Qy71hSNoHAMJc7ZX6D0Y= From: Hao Xiang To: marcandre.lureau@redhat.com, peterx@redhat.com, farosas@suse.de, armbru@redhat.com, lvivier@redhat.com, qemu-devel@nongnu.org Cc: Hao Xiang , Bryan Zhang Subject: [PATCH v4 07/14] util/dsa: Implement DSA task asynchronous submission and wait for completion. Date: Thu, 25 Apr 2024 02:21:10 +0000 Message-Id: <20240425022117.4035031-8-hao.xiang@linux.dev> In-Reply-To: <20240425022117.4035031-1-hao.xiang@linux.dev> References: <20240425022117.4035031-1-hao.xiang@linux.dev> MIME-Version: 1.0 X-Migadu-Flow: FLOW_OUT Received-SPF: pass client-ip=95.215.58.181; envelope-from=hao.xiang@linux.dev; helo=out-181.mta1.migadu.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org * Add a DSA task completion callback. * DSA completion thread will call the tasks's completion callback on every task/batch task completion. * DSA submission path to wait for completion. * Implement CPU fallback if DSA is not able to complete the task. Signed-off-by: Hao Xiang Signed-off-by: Bryan Zhang --- include/qemu/dsa.h | 14 +++++ util/dsa.c | 147 ++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 158 insertions(+), 3 deletions(-) diff --git a/include/qemu/dsa.h b/include/qemu/dsa.h index 645e6fc367..e002652879 100644 --- a/include/qemu/dsa.h +++ b/include/qemu/dsa.h @@ -91,6 +91,20 @@ buffer_zero_batch_task_init(struct dsa_batch_task *task, */ void buffer_zero_batch_task_destroy(struct dsa_batch_task *task); +/** + * @brief Performs buffer zero comparison on a DSA batch task asynchronously. + * + * @param batch_task A pointer to the batch task. + * @param buf An array of memory buffers. + * @param count The number of buffers in the array. + * @param len The buffer length. + * + * @return Zero if successful, otherwise non-zero. + */ +int +buffer_is_zero_dsa_batch_async(struct dsa_batch_task *batch_task, + const void **buf, size_t count, size_t len); + #else static inline bool dsa_is_running(void) diff --git a/util/dsa.c b/util/dsa.c index 9db4cfcf1d..5a2bf33651 100644 --- a/util/dsa.c +++ b/util/dsa.c @@ -473,6 +473,57 @@ poll_completion(struct dsa_completion_record *completion, return 0; } +/** + * @brief Helper function to use CPU to complete a single + * zero page checking task. + * + * @param completion A pointer to a DSA task completion record. + * @param descriptor A pointer to a DSA task descriptor. + * @param result A pointer to the result of a zero page checking. + */ +static void +task_cpu_fallback_int(struct dsa_completion_record *completion, + struct dsa_hw_desc *descriptor, bool *result) +{ + const uint8_t *buf; + size_t len; + + if (completion->status == DSA_COMP_SUCCESS) { + return; + } + + /* + * DSA was able to partially complete the operation. Check the + * result. If we already know this is not a zero page, we can + * return now. + */ + if (completion->bytes_completed != 0 && completion->result != 0) { + *result = false; + return; + } + + /* Let's fallback to use CPU to complete it. */ + buf = (const uint8_t *)descriptor->src_addr; + len = descriptor->xfer_size; + *result = buffer_is_zero(buf + completion->bytes_completed, + len - completion->bytes_completed); +} + +/** + * @brief Use CPU to complete a single zero page checking task. + * + * @param task A pointer to the task. + */ +static void +task_cpu_fallback(struct dsa_batch_task *task) +{ + assert(task->task_type == DSA_TASK); + + task_cpu_fallback_int(&task->completions[0], + &task->descriptors[0], + &task->results[0]); +} + /** * @brief Complete a single DSA task in the batch task. * @@ -574,6 +625,47 @@ exit: return ret; } +/** + * @brief Use CPU to complete the zero page checking batch task. + * + * @param batch_task A pointer to the batch task. + */ +static void +batch_task_cpu_fallback(struct dsa_batch_task *batch_task) +{ + assert(batch_task->task_type == DSA_BATCH_TASK); + + struct dsa_completion_record *batch_completion = + &batch_task->batch_completion; + struct dsa_completion_record *completion; + uint8_t status; + bool *results = batch_task->results; + uint32_t count = batch_task->batch_descriptor.desc_count; + + /* DSA is able to complete the entire batch task. */ + if (batch_completion->status == DSA_COMP_SUCCESS) { + assert(count == batch_completion->bytes_completed); + return; + } + + /* + * DSA encounters some error and is not able to complete + * the entire batch task. Use CPU fallback. + */ + for (int i = 0; i < count; i++) { + + completion = &batch_task->completions[i]; + status = completion->status; + + assert(status == DSA_COMP_SUCCESS || + status == DSA_COMP_PAGE_FAULT_NOBOF); + + task_cpu_fallback_int(completion, + &batch_task->descriptors[i], + &results[i]); + } +} + /** * @brief Handles an asynchronous DSA batch task completion. * @@ -861,7 +953,6 @@ buffer_zero_batch_task_set(struct dsa_batch_task *batch_task, * * @return int Zero if successful, otherwise an appropriate error code. */ -__attribute__((unused)) static int buffer_zero_dsa_async(struct dsa_batch_task *task, const void *buf, size_t len) @@ -880,7 +971,6 @@ buffer_zero_dsa_async(struct dsa_batch_task *task, * @param count The number of buffers. * @param len The buffer length. */ -__attribute__((unused)) static int buffer_zero_dsa_batch_async(struct dsa_batch_task *batch_task, const void **buf, size_t count, size_t len) @@ -911,13 +1001,29 @@ buffer_zero_dsa_completion(void *context) * * @param batch_task A pointer to the buffer zero comparison batch task. */ -__attribute__((unused)) static void buffer_zero_dsa_wait(struct dsa_batch_task *batch_task) { qemu_sem_wait(&batch_task->sem_task_complete); } +/** + * @brief Use CPU to complete the zero page checking task if DSA + * is not able to complete it. + * + * @param batch_task A pointer to the batch task. + */ +static void +buffer_zero_cpu_fallback(struct dsa_batch_task *batch_task) +{ + if (batch_task->task_type == DSA_TASK) { + task_cpu_fallback(batch_task); + } else { + assert(batch_task->task_type == DSA_BATCH_TASK); + batch_task_cpu_fallback(batch_task); + } +} + /** * @brief Check if DSA is running. * @@ -990,5 +1096,40 @@ void dsa_cleanup(void) dsa_device_group_cleanup(&dsa_group); } +/** + * @brief Performs buffer zero comparison on a DSA batch task asynchronously. + * + * @param batch_task A pointer to the batch task. + * @param buf An array of memory buffers. + * @param count The number of buffers in the array. + * @param len The buffer length. + * + * @return Zero if successful, otherwise non-zero. + */ +int +buffer_is_zero_dsa_batch_async(struct dsa_batch_task *batch_task, + const void **buf, size_t count, size_t len) +{ + if (count <= 0 || count > batch_task->batch_size) { + return -1; + } + + assert(batch_task != NULL); + assert(len != 0); + assert(buf != NULL); + + if (count == 1) { + /* DSA doesn't take batch operation with only 1 task. */ + buffer_zero_dsa_async(batch_task, buf[0], len); + } else { + buffer_zero_dsa_batch_async(batch_task, buf, count, len); + } + + buffer_zero_dsa_wait(batch_task); + buffer_zero_cpu_fallback(batch_task); + + return 0; +} + #endif From patchwork Thu Apr 25 02:21:11 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hao Xiang X-Patchwork-Id: 13642795 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 2FFB6C10F15 for ; Thu, 25 Apr 2024 02:25:54 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1rzol5-0000Xy-Oc; Wed, 24 Apr 2024 22:22:47 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1rzol3-0000X9-5g for qemu-devel@nongnu.org; Wed, 24 Apr 2024 22:22:45 -0400 Received: from out-173.mta1.migadu.com ([95.215.58.173]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1rzol1-0005IL-An for qemu-devel@nongnu.org; Wed, 24 Apr 2024 22:22:44 -0400 X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1714011762; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=QzuSJ1zKYkpx7ByvuyAxfu5NoEWY50aKxHnWj75q2gE=; b=IOsynXx6S5B89y3R2OsL6G69El2xPkzR4+iWqeJ3Z4HKiGZ4LZIxM2aGa3nIfsKLuMZSOK 6PknMF91LaNpo6f4ugRtGCMHLjVFMXjpP1SknXWFYDaJ3fCGFc+BgsEuywkm9AsSuvos8d Evco26giDoklEmzP/Bdi2U3obVlbL4Y= From: Hao Xiang To: marcandre.lureau@redhat.com, peterx@redhat.com, farosas@suse.de, armbru@redhat.com, lvivier@redhat.com, qemu-devel@nongnu.org Cc: Hao Xiang Subject: [PATCH v4 08/14] migration/multifd: Add new migration option for multifd DSA offloading. Date: Thu, 25 Apr 2024 02:21:11 +0000 Message-Id: <20240425022117.4035031-9-hao.xiang@linux.dev> In-Reply-To: <20240425022117.4035031-1-hao.xiang@linux.dev> References: <20240425022117.4035031-1-hao.xiang@linux.dev> MIME-Version: 1.0 X-Migadu-Flow: FLOW_OUT Received-SPF: pass client-ip=95.215.58.173; envelope-from=hao.xiang@linux.dev; helo=out-173.mta1.migadu.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_MSPIKE_H2=-0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Intel DSA offloading is an optional feature that turns on if proper hardware and software stack is available. To turn on DSA offloading in multifd live migration: multifd-dsa-accel="[dsa_dev_path1] [dsa_dev_path2] ... [dsa_dev_pathX]" This feature is turned off by default. Signed-off-by: Hao Xiang --- migration/migration-hmp-cmds.c | 8 ++++++++ migration/options.c | 30 ++++++++++++++++++++++++++++++ migration/options.h | 1 + qapi/migration.json | 26 +++++++++++++++++++++++--- 4 files changed, 62 insertions(+), 3 deletions(-) diff --git a/migration/migration-hmp-cmds.c b/migration/migration-hmp-cmds.c index 7e96ae6ffd..7e9bb278c9 100644 --- a/migration/migration-hmp-cmds.c +++ b/migration/migration-hmp-cmds.c @@ -358,6 +358,9 @@ void hmp_info_migrate_parameters(Monitor *mon, const QDict *qdict) monitor_printf(mon, "%s: '%s'\n", MigrationParameter_str(MIGRATION_PARAMETER_TLS_AUTHZ), params->tls_authz); + monitor_printf(mon, "%s: '%s'\n", + MigrationParameter_str(MIGRATION_PARAMETER_MULTIFD_DSA_ACCEL), + params->multifd_dsa_accel); if (params->has_block_bitmap_mapping) { const BitmapMigrationNodeAliasList *bmnal; @@ -622,6 +625,11 @@ void hmp_migrate_set_parameter(Monitor *mon, const QDict *qdict) p->has_block_incremental = true; visit_type_bool(v, param, &p->block_incremental, &err); break; + case MIGRATION_PARAMETER_MULTIFD_DSA_ACCEL: + p->multifd_dsa_accel = g_new0(StrOrNull, 1); + p->multifd_dsa_accel->type = QTYPE_QSTRING; + visit_type_str(v, param, &p->multifd_dsa_accel->u.s, &err); + break; case MIGRATION_PARAMETER_MULTIFD_CHANNELS: p->has_multifd_channels = true; visit_type_uint8(v, param, &p->multifd_channels, &err); diff --git a/migration/options.c b/migration/options.c index 239f5ecfb4..dc8642df81 100644 --- a/migration/options.c +++ b/migration/options.c @@ -182,6 +182,8 @@ Property migration_properties[] = { DEFINE_PROP_ZERO_PAGE_DETECTION("zero-page-detection", MigrationState, parameters.zero_page_detection, ZERO_PAGE_DETECTION_MULTIFD), + DEFINE_PROP_STRING("multifd-dsa-accel", MigrationState, + parameters.multifd_dsa_accel), /* Migration capabilities */ DEFINE_PROP_MIG_CAP("x-xbzrle", MIGRATION_CAPABILITY_XBZRLE), @@ -920,6 +922,13 @@ const char *migrate_tls_creds(void) return s->parameters.tls_creds; } +const char *migrate_multifd_dsa_accel(void) +{ + MigrationState *s = migrate_get_current(); + + return s->parameters.multifd_dsa_accel; +} + const char *migrate_tls_hostname(void) { MigrationState *s = migrate_get_current(); @@ -1060,6 +1069,8 @@ MigrationParameters *qmp_query_migrate_parameters(Error **errp) params->mode = s->parameters.mode; params->has_zero_page_detection = true; params->zero_page_detection = s->parameters.zero_page_detection; + params->multifd_dsa_accel = g_strdup(s->parameters.multifd_dsa_accel ? + s->parameters.multifd_dsa_accel : ""); return params; } @@ -1068,6 +1079,7 @@ void migrate_params_init(MigrationParameters *params) { params->tls_hostname = g_strdup(""); params->tls_creds = g_strdup(""); + params->multifd_dsa_accel = g_strdup(""); /* Set has_* up only for parameter checks */ params->has_compress_level = true; @@ -1416,6 +1428,11 @@ static void migrate_params_test_apply(MigrateSetParameters *params, if (params->has_zero_page_detection) { dest->zero_page_detection = params->zero_page_detection; } + + if (params->multifd_dsa_accel) { + assert(params->multifd_dsa_accel->type == QTYPE_QSTRING); + dest->multifd_dsa_accel = params->multifd_dsa_accel->u.s; + } } static void migrate_params_apply(MigrateSetParameters *params, Error **errp) @@ -1570,6 +1587,13 @@ static void migrate_params_apply(MigrateSetParameters *params, Error **errp) if (params->has_zero_page_detection) { s->parameters.zero_page_detection = params->zero_page_detection; } + + if (params->multifd_dsa_accel) { + g_free(s->parameters.multifd_dsa_accel); + assert(params->multifd_dsa_accel->type == QTYPE_QSTRING); + s->parameters.multifd_dsa_accel = + g_strdup(params->multifd_dsa_accel->u.s); + } } void qmp_migrate_set_parameters(MigrateSetParameters *params, Error **errp) @@ -1595,6 +1619,12 @@ void qmp_migrate_set_parameters(MigrateSetParameters *params, Error **errp) params->tls_authz->type = QTYPE_QSTRING; params->tls_authz->u.s = strdup(""); } + if (params->multifd_dsa_accel + && params->multifd_dsa_accel->type == QTYPE_QNULL) { + qobject_unref(params->multifd_dsa_accel->u.n); + params->multifd_dsa_accel->type = QTYPE_QSTRING; + params->multifd_dsa_accel->u.s = strdup(""); + } migrate_params_test_apply(params, &tmp); diff --git a/migration/options.h b/migration/options.h index ab8199e207..1cb3393be9 100644 --- a/migration/options.h +++ b/migration/options.h @@ -91,6 +91,7 @@ const char *migrate_tls_creds(void); const char *migrate_tls_hostname(void); uint64_t migrate_xbzrle_cache_size(void); ZeroPageDetection migrate_zero_page_detection(void); +const char *migrate_multifd_dsa_accel(void); /* parameters setters */ diff --git a/qapi/migration.json b/qapi/migration.json index 8c65b90328..934fa8839e 100644 --- a/qapi/migration.json +++ b/qapi/migration.json @@ -914,6 +914,12 @@ # See description in @ZeroPageDetection. Default is 'multifd'. # (since 9.0) # +# @multifd-dsa-accel: If enabled, use DSA accelerator offloading for +# certain memory operations. Enable DSA accelerator offloading by +# setting this string to a list of DSA device path separated by space +# characters. Setting this string to an empty string means disabling +# DSA accelerator offloading. Defaults to an empty string. (since 9.2) +# # Features: # # @deprecated: Member @block-incremental is deprecated. Use @@ -937,7 +943,7 @@ 'cpu-throttle-initial', 'cpu-throttle-increment', 'cpu-throttle-tailslow', 'tls-creds', 'tls-hostname', 'tls-authz', 'max-bandwidth', - 'avail-switchover-bandwidth', 'downtime-limit', + 'avail-switchover-bandwidth', 'downtime-limit', 'multifd-dsa-accel', { 'name': 'x-checkpoint-delay', 'features': [ 'unstable' ] }, { 'name': 'block-incremental', 'features': [ 'deprecated' ] }, 'multifd-channels', @@ -1122,6 +1128,12 @@ # See description in @ZeroPageDetection. Default is 'multifd'. # (since 9.0) # +# @multifd-dsa-accel: If enabled, use DSA accelerator offloading for +# certain memory operations. Enable DSA accelerator offloading by +# setting this string to a list of DSA device path separated by space +# characters. Setting this string to an empty string means disabling +# DSA accelerator offloading. Defaults to an empty string. (since 9.2) +# # Features: # # @deprecated: Member @block-incremental is deprecated. Use @@ -1176,7 +1188,8 @@ 'features': [ 'unstable' ] }, '*vcpu-dirty-limit': 'uint64', '*mode': 'MigMode', - '*zero-page-detection': 'ZeroPageDetection'} } + '*zero-page-detection': 'ZeroPageDetection', + '*multifd-dsa-accel': 'StrOrNull'} } ## # @migrate-set-parameters: @@ -1354,6 +1367,12 @@ # See description in @ZeroPageDetection. Default is 'multifd'. # (since 9.0) # +# @multifd-dsa-accel: If enabled, use DSA accelerator offloading for +# certain memory operations. Enable DSA accelerator offloading by +# setting this string to a list of DSA device path separated by space +# characters. Setting this string to an empty string means disabling +# DSA accelerator offloading. Defaults to an empty string. (since 9.2) +# # Features: # # @deprecated: Member @block-incremental is deprecated. Use @@ -1405,7 +1424,8 @@ 'features': [ 'unstable' ] }, '*vcpu-dirty-limit': 'uint64', '*mode': 'MigMode', - '*zero-page-detection': 'ZeroPageDetection'} } + '*zero-page-detection': 'ZeroPageDetection', + '*multifd-dsa-accel': 'str'} } ## # @query-migrate-parameters: From patchwork Thu Apr 25 02:21:12 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hao Xiang X-Patchwork-Id: 13642794 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 1D0C3C4345F for ; Thu, 25 Apr 2024 02:25:54 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1rzol7-0000YY-51; Wed, 24 Apr 2024 22:22:49 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1rzol4-0000Xa-TH for qemu-devel@nongnu.org; Wed, 24 Apr 2024 22:22:46 -0400 Received: from out-189.mta1.migadu.com ([2001:41d0:203:375::bd]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1rzol2-0005KM-US for qemu-devel@nongnu.org; Wed, 24 Apr 2024 22:22:46 -0400 X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1714011763; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=R1cSokO6PX4qtftK34R3zY5rMpYUEQVNbC4cHnwkamg=; b=W4/UE0wbteecEfMP7+aaBYgNyLpuxSSyTMe4HdOWjqRxhuI4eJFfDYxx8U3rmrmcaEcTp2 bLa3A4iysTG5RFdN78q9sya2lPiCfjvgHbHVdj2q1mnDcwWPXbmJuXiTMCXWQMRVGFE4fi dZA/7WBGpjeT/kPUgegXEw357wKuIRc= From: Hao Xiang To: marcandre.lureau@redhat.com, peterx@redhat.com, farosas@suse.de, armbru@redhat.com, lvivier@redhat.com, qemu-devel@nongnu.org Cc: Hao Xiang Subject: [PATCH v4 09/14] migration/multifd: Prepare to introduce DSA acceleration on the multifd path. Date: Thu, 25 Apr 2024 02:21:12 +0000 Message-Id: <20240425022117.4035031-10-hao.xiang@linux.dev> In-Reply-To: <20240425022117.4035031-1-hao.xiang@linux.dev> References: <20240425022117.4035031-1-hao.xiang@linux.dev> MIME-Version: 1.0 X-Migadu-Flow: FLOW_OUT Received-SPF: pass client-ip=2001:41d0:203:375::bd; envelope-from=hao.xiang@linux.dev; helo=out-189.mta1.migadu.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org 1. Refactor multifd_send_thread function. 2. Introduce the batch task structure in MultiFDSendParams. Signed-off-by: Hao Xiang --- include/qemu/dsa.h | 51 +++++++++++++++++++++++++++++++++++++++++++-- migration/multifd.c | 5 +++++ migration/multifd.h | 2 ++ util/dsa.c | 51 ++++++++++++++++++++++++++++++++++++++------- 4 files changed, 99 insertions(+), 10 deletions(-) diff --git a/include/qemu/dsa.h b/include/qemu/dsa.h index e002652879..0c36e93016 100644 --- a/include/qemu/dsa.h +++ b/include/qemu/dsa.h @@ -2,6 +2,7 @@ #define QEMU_DSA_H #include "qemu/error-report.h" +#include "exec/cpu-common.h" #include "qemu/thread.h" #include "qemu/queue.h" @@ -42,6 +43,21 @@ typedef struct dsa_batch_task { QSIMPLEQ_ENTRY(dsa_batch_task) entry; } dsa_batch_task; +#endif + +struct batch_task { +#ifdef CONFIG_DSA_OPT + /* Address of each pages in pages */ + ram_addr_t *addr; + /* Zero page checking results */ + bool *results; + /* Batch task DSA specific implementation */ + struct dsa_batch_task *dsa_batch; +#endif +}; + +#ifdef CONFIG_DSA_OPT + /** * @brief Initializes DSA devices. * @@ -74,7 +90,7 @@ void dsa_cleanup(void); bool dsa_is_running(void); /** - * @brief Initializes a buffer zero batch task. + * @brief Initializes a buffer zero DSA batch task. * * @param task A pointer to the batch task to initialize. * @param results A pointer to an array of zero page checking results. @@ -102,9 +118,26 @@ void buffer_zero_batch_task_destroy(struct dsa_batch_task *task); * @return Zero if successful, otherwise non-zero. */ int -buffer_is_zero_dsa_batch_async(struct dsa_batch_task *batch_task, +buffer_is_zero_dsa_batch_async(struct batch_task *batch_task, const void **buf, size_t count, size_t len); +/** + * @brief Initializes a general buffer zero batch task. + * + * @param batch_size The number of zero page checking tasks in the batch. + * @return A pointer to the general batch task initialized. + */ +struct batch_task * +batch_task_init(int batch_size); + +/** + * @brief Destroys a general buffer zero batch task. + * + * @param task A pointer to the general batch task to destroy. + */ +void +batch_task_destroy(struct batch_task *task); + #else static inline bool dsa_is_running(void) @@ -128,6 +161,20 @@ static inline void dsa_stop(void) {} static inline void dsa_cleanup(void) {} +static inline int +buffer_is_zero_dsa_batch_async(struct batch_task *batch_task, + const void **buf, size_t count, size_t len) +{ + exit(1); +} + +static inline struct batch_task *batch_task_init(int batch_size) +{ + return NULL; +} + +static inline void batch_task_destroy(struct batch_task *task) {} + #endif #endif diff --git a/migration/multifd.c b/migration/multifd.c index f317bff077..cfd3a92f6c 100644 --- a/migration/multifd.c +++ b/migration/multifd.c @@ -13,6 +13,8 @@ #include "qemu/osdep.h" #include "qemu/cutils.h" #include "qemu/rcu.h" +#include "qemu/dsa.h" +#include "qemu/memalign.h" #include "exec/target_page.h" #include "sysemu/sysemu.h" #include "exec/ramblock.h" @@ -780,6 +782,8 @@ static bool multifd_send_cleanup_channel(MultiFDSendParams *p, Error **errp) p->name = NULL; multifd_pages_clear(p->pages); p->pages = NULL; + batch_task_destroy(p->batch_task); + p->batch_task = NULL; p->packet_len = 0; g_free(p->packet); p->packet = NULL; @@ -1172,6 +1176,7 @@ bool multifd_send_setup(void) qemu_sem_init(&p->sem_sync, 0); p->id = i; p->pages = multifd_pages_init(page_count); + p->batch_task = batch_task_init(page_count); if (use_packets) { p->packet_len = sizeof(MultiFDPacket_t) diff --git a/migration/multifd.h b/migration/multifd.h index c9d9b09239..16e27db5e9 100644 --- a/migration/multifd.h +++ b/migration/multifd.h @@ -135,6 +135,8 @@ typedef struct { * pending_job != 0 -> multifd_channel can use it. */ MultiFDPages_t *pages; + /* Zero page checking batch task */ + struct batch_task *batch_task; /* thread local variables. No locking required */ diff --git a/util/dsa.c b/util/dsa.c index 5a2bf33651..4f695e58af 100644 --- a/util/dsa.c +++ b/util/dsa.c @@ -802,7 +802,7 @@ buffer_zero_task_init_int(struct dsa_hw_desc *descriptor, } /** - * @brief Initializes a buffer zero batch task. + * @brief Initializes a buffer zero DSA batch task. * * @param task A pointer to the batch task to initialize. * @param results A pointer to an array of zero page checking results. @@ -1107,29 +1107,64 @@ void dsa_cleanup(void) * @return Zero if successful, otherwise non-zero. */ int -buffer_is_zero_dsa_batch_async(struct dsa_batch_task *batch_task, +buffer_is_zero_dsa_batch_async(struct batch_task *batch_task, const void **buf, size_t count, size_t len) { - if (count <= 0 || count > batch_task->batch_size) { + struct dsa_batch_task *dsa_batch = batch_task->dsa_batch; + + if (count <= 0 || count > dsa_batch->batch_size) { return -1; } - assert(batch_task != NULL); + assert(dsa_batch != NULL); assert(len != 0); assert(buf != NULL); if (count == 1) { /* DSA doesn't take batch operation with only 1 task. */ - buffer_zero_dsa_async(batch_task, buf[0], len); + buffer_zero_dsa_async(dsa_batch, buf[0], len); } else { - buffer_zero_dsa_batch_async(batch_task, buf, count, len); + buffer_zero_dsa_batch_async(dsa_batch, buf, count, len); } - buffer_zero_dsa_wait(batch_task); - buffer_zero_cpu_fallback(batch_task); + buffer_zero_dsa_wait(dsa_batch); + buffer_zero_cpu_fallback(dsa_batch); return 0; } +/** + * @brief Initializes a general buffer zero batch task. + * + * @param batch_size The number of zero page checking tasks in the batch. + * @return A pointer to the general batch task initialized. + */ +struct batch_task * +batch_task_init(int batch_size) +{ + struct batch_task *task = g_malloc0(sizeof(struct batch_task)); + task->addr = g_new0(ram_addr_t, batch_size); + task->results = g_new0(bool, batch_size); + task->dsa_batch = qemu_memalign(64, sizeof(struct dsa_batch_task)); + buffer_zero_batch_task_init(task->dsa_batch, task->results, batch_size); + + return task; +} + +/** + * @brief Destroys a general buffer zero batch task. + * + * @param task A pointer to the general batch task to destroy. + */ +void +batch_task_destroy(struct batch_task *task) +{ + g_free(task->addr); + g_free(task->results); + buffer_zero_batch_task_destroy(task->dsa_batch); + qemu_vfree(task->dsa_batch); + g_free(task); +} + #endif From patchwork Thu Apr 25 02:21:13 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hao Xiang X-Patchwork-Id: 13642785 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id EAA66C4345F for ; Thu, 25 Apr 2024 02:23:32 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1rzol9-0000Yq-Qg; Wed, 24 Apr 2024 22:22:51 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1rzol8-0000Yf-4l for qemu-devel@nongnu.org; Wed, 24 Apr 2024 22:22:50 -0400 Received: from out-172.mta1.migadu.com ([2001:41d0:203:375::ac]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1rzol5-0005Oc-Tq for qemu-devel@nongnu.org; Wed, 24 Apr 2024 22:22:49 -0400 X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1714011766; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=TyXscLmfoHanQlIuNZkg8+4DhXkI75Cog5suPvjmYdI=; b=F2zyZnilK80+knG+VXmNz8VTZVfz+39KbG1lLD25J8BJKm6sxtlYattU1fMw7YJSU/vBKU /BltPXWZjULEwmOhXYRPwXcKCjB0zGQufQwS/KmXi8Xxx6/CPzA6iMPcxXEuzJuIuS7USD 02FnLbUFfz/v/cUuhOfoGCgRpoHthUc= From: Hao Xiang To: marcandre.lureau@redhat.com, peterx@redhat.com, farosas@suse.de, armbru@redhat.com, lvivier@redhat.com, qemu-devel@nongnu.org Cc: Hao Xiang Subject: [PATCH v4 10/14] migration/multifd: Enable DSA offloading in multifd sender path. Date: Thu, 25 Apr 2024 02:21:13 +0000 Message-Id: <20240425022117.4035031-11-hao.xiang@linux.dev> In-Reply-To: <20240425022117.4035031-1-hao.xiang@linux.dev> References: <20240425022117.4035031-1-hao.xiang@linux.dev> MIME-Version: 1.0 X-Migadu-Flow: FLOW_OUT Received-SPF: pass client-ip=2001:41d0:203:375::ac; envelope-from=hao.xiang@linux.dev; helo=out-172.mta1.migadu.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Multifd sender path gets an array of pages queued by the migration thread. It performs zero page checking on every page in the array. The pages are classfied as either a zero page or a normal page. This change uses Intel DSA to offload the zero page checking from CPU to the DSA accelerator. The sender thread submits a batch of pages to DSA hardware and waits for the DSA completion thread to signal for work completion. Signed-off-by: Hao Xiang --- migration/multifd-zero-page.c | 99 +++++++++++++++++++++++++++++++++-- migration/multifd.c | 27 +++++++++- migration/multifd.h | 1 + 3 files changed, 120 insertions(+), 7 deletions(-) diff --git a/migration/multifd-zero-page.c b/migration/multifd-zero-page.c index e1b8370f88..4f426289e4 100644 --- a/migration/multifd-zero-page.c +++ b/migration/multifd-zero-page.c @@ -37,25 +37,83 @@ static void swap_page_offset(ram_addr_t *pages_offset, int a, int b) } /** - * multifd_send_zero_page_detect: Perform zero page detection on all pages. + * zero_page_detect_cpu: Perform zero page detection using CPU. * * Sorts normal pages before zero pages in p->pages->offset and updates * p->pages->normal_num. * * @param p A pointer to the send params. */ -void multifd_send_zero_page_detect(MultiFDSendParams *p) +static void zero_page_detect_cpu(MultiFDSendParams *p) { MultiFDPages_t *pages = p->pages; RAMBlock *rb = pages->block; int i = 0; int j = pages->num - 1; - if (!multifd_zero_page_enabled()) { - pages->normal_num = pages->num; + /* + * Sort the page offset array by moving all normal pages to + * the left and all zero pages to the right of the array. + */ + while (i <= j) { + uint64_t offset = pages->offset[i]; + + if (!buffer_is_zero(rb->host + offset, p->page_size)) { + i++; + continue; + } + + swap_page_offset(pages->offset, i, j); + ram_release_page(rb->idstr, offset); + j--; + } + + pages->normal_num = i; +} + + +#ifdef CONFIG_DSA_OPT + +static void swap_result(bool *results, int a, int b) +{ + bool temp; + + if (a == b) { return; } + temp = results[a]; + results[a] = results[b]; + results[b] = temp; +} + +/** + * zero_page_detect_dsa: Perform zero page detection using + * Intel Data Streaming Accelerator (DSA). + * + * Sorts normal pages before zero pages in p->pages->offset and updates + * p->pages->normal_num. + * + * @param p A pointer to the send params. + */ +static void zero_page_detect_dsa(MultiFDSendParams *p) +{ + MultiFDPages_t *pages = p->pages; + RAMBlock *rb = pages->block; + bool *results = p->batch_task->results; + + for (int i = 0; i < p->pages->num; i++) { + p->batch_task->addr[i] = (ram_addr_t)(rb->host + p->pages->offset[i]); + } + + buffer_is_zero_dsa_batch_async(p->batch_task, + (const void **)p->batch_task->addr, + p->pages->num, + p->page_size); + + int i = 0; + int j = pages->num - 1; + /* * Sort the page offset array by moving all normal pages to * the left and all zero pages to the right of the array. @@ -63,11 +121,12 @@ void multifd_send_zero_page_detect(MultiFDSendParams *p) while (i <= j) { uint64_t offset = pages->offset[i]; - if (!buffer_is_zero(rb->host + offset, p->page_size)) { + if (!results[i]) { i++; continue; } + swap_result(results, i, j); swap_page_offset(pages->offset, i, j); ram_release_page(rb->idstr, offset); j--; @@ -76,6 +135,15 @@ void multifd_send_zero_page_detect(MultiFDSendParams *p) pages->normal_num = i; } +#else + +static void zero_page_detect_dsa(MultiFDSendParams *p) +{ + exit(1); +} + +#endif + void multifd_recv_zero_page_process(MultiFDRecvParams *p) { for (int i = 0; i < p->zero_num; i++) { @@ -87,3 +155,24 @@ void multifd_recv_zero_page_process(MultiFDRecvParams *p) } } } + +/** + * multifd_send_zero_page_detect: Perform zero page detection on all pages. + * + * @param p A pointer to the send params. + */ +void multifd_send_zero_page_detect(MultiFDSendParams *p) +{ + MultiFDPages_t *pages = p->pages; + + if (!multifd_zero_page_enabled()) { + pages->normal_num = pages->num; + return; + } + + if (dsa_is_running()) { + zero_page_detect_dsa(p); + } else { + zero_page_detect_cpu(p); + } +} diff --git a/migration/multifd.c b/migration/multifd.c index cfd3a92f6c..7316643d0a 100644 --- a/migration/multifd.c +++ b/migration/multifd.c @@ -818,6 +818,8 @@ void multifd_send_shutdown(void) multifd_send_terminate_threads(); + dsa_cleanup(); + for (i = 0; i < migrate_multifd_channels(); i++) { MultiFDSendParams *p = &multifd_send_state->params[i]; Error *local_err = NULL; @@ -1155,11 +1157,20 @@ bool multifd_send_setup(void) uint32_t page_count = MULTIFD_PACKET_SIZE / qemu_target_page_size(); bool use_packets = multifd_use_packets(); uint8_t i; + const char *dsa_parameter = migrate_multifd_dsa_accel(); if (!migrate_multifd()) { return true; } + if (dsa_init(dsa_parameter)) { + error_setg(&local_err, "multifd: Sender failed to initialize DSA."); + error_report_err(local_err); + return false; + } + + dsa_start(); + thread_count = migrate_multifd_channels(); multifd_send_state = g_malloc0(sizeof(*multifd_send_state)); multifd_send_state->params = g_new0(MultiFDSendParams, thread_count); @@ -1393,6 +1404,7 @@ void multifd_recv_cleanup(void) qemu_thread_join(&p->thread); } } + dsa_cleanup(); for (i = 0; i < migrate_multifd_channels(); i++) { multifd_recv_cleanup_channel(&multifd_recv_state->params[i]); } @@ -1568,6 +1580,9 @@ int multifd_recv_setup(Error **errp) uint32_t page_count = MULTIFD_PACKET_SIZE / qemu_target_page_size(); bool use_packets = multifd_use_packets(); uint8_t i; + const char *dsa_parameter = migrate_multifd_dsa_accel(); + int ret; + Error *local_err = NULL; /* * Return successfully if multiFD recv state is already initialised @@ -1577,6 +1592,15 @@ int multifd_recv_setup(Error **errp) return 0; } + ret = dsa_init(dsa_parameter); + if (ret != 0) { + error_setg(&local_err, "multifd: Receiver failed to initialize DSA."); + error_propagate(errp, local_err); + return ret; + } + + dsa_start(); + thread_count = migrate_multifd_channels(); multifd_recv_state = g_malloc0(sizeof(*multifd_recv_state)); multifd_recv_state->params = g_new0(MultiFDRecvParams, thread_count); @@ -1616,13 +1640,12 @@ int multifd_recv_setup(Error **errp) for (i = 0; i < thread_count; i++) { MultiFDRecvParams *p = &multifd_recv_state->params[i]; - int ret; - ret = multifd_recv_state->ops->recv_setup(p, errp); if (ret) { return ret; } } + return 0; } diff --git a/migration/multifd.h b/migration/multifd.h index 16e27db5e9..b3717fae24 100644 --- a/migration/multifd.h +++ b/migration/multifd.h @@ -14,6 +14,7 @@ #define QEMU_MIGRATION_MULTIFD_H #include "ram.h" +#include "qemu/dsa.h" typedef struct MultiFDRecvData MultiFDRecvData; From patchwork Thu Apr 25 02:21:14 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hao Xiang X-Patchwork-Id: 13642783 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 61BD5C41513 for ; Thu, 25 Apr 2024 02:23:17 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1rzolD-0000a5-K9; Wed, 24 Apr 2024 22:22:55 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1rzolB-0000ZF-A8 for qemu-devel@nongnu.org; Wed, 24 Apr 2024 22:22:53 -0400 Received: from out-174.mta1.migadu.com ([2001:41d0:203:375::ae]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1rzol8-0005Vs-VY for qemu-devel@nongnu.org; Wed, 24 Apr 2024 22:22:53 -0400 X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1714011769; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=N/RsfKs4JwATvFtMGxilZWLtkW2M6AtYnhYyV482uxM=; b=CRkVyU0b/z5LlKmh/GFAvpbK0jyX+FER3HbF606lVUATIMws6I5GUqj1PCg64LwDGAfH3s 6tYEFoqetYMyzvp0JT/ltXD1Ae6CwOSqsQgp3BWVt6s0/nC5G1pfUB1vJJWyKo2W7F5Wpu VuAvBDFrLVHx/+zoPf41udxRvVjtW1E= From: Hao Xiang To: marcandre.lureau@redhat.com, peterx@redhat.com, farosas@suse.de, armbru@redhat.com, lvivier@redhat.com, qemu-devel@nongnu.org Cc: Hao Xiang Subject: [PATCH v4 11/14] migration/multifd: Add migration option set packet size. Date: Thu, 25 Apr 2024 02:21:14 +0000 Message-Id: <20240425022117.4035031-12-hao.xiang@linux.dev> In-Reply-To: <20240425022117.4035031-1-hao.xiang@linux.dev> References: <20240425022117.4035031-1-hao.xiang@linux.dev> MIME-Version: 1.0 X-Migadu-Flow: FLOW_OUT Received-SPF: pass client-ip=2001:41d0:203:375::ae; envelope-from=hao.xiang@linux.dev; helo=out-174.mta1.migadu.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org The current multifd packet size is 128 * 4kb. This change adds an option to set the packet size. Both sender and receiver needs to set the same packet size for things to work. Signed-off-by: Hao Xiang --- migration/options.c | 36 ++++++++++++++++++++++++++++++++++++ migration/options.h | 1 + qapi/migration.json | 21 ++++++++++++++++++--- 3 files changed, 55 insertions(+), 3 deletions(-) diff --git a/migration/options.c b/migration/options.c index dc8642df81..a9deb079eb 100644 --- a/migration/options.c +++ b/migration/options.c @@ -79,6 +79,12 @@ #define DEFAULT_MIGRATE_ANNOUNCE_ROUNDS 5 #define DEFAULT_MIGRATE_ANNOUNCE_STEP 100 +/* + * Parameter for multifd packet size. + */ +#define DEFAULT_MIGRATE_MULTIFD_PACKET_SIZE (128 * 4 * 1024) +#define MAX_MIGRATE_MULTIFD_PACKET_SIZE (1023 * 4 * 1024) + #define DEFINE_PROP_MIG_CAP(name, x) \ DEFINE_PROP_BOOL(name, MigrationState, capabilities[x], false) @@ -184,6 +190,9 @@ Property migration_properties[] = { ZERO_PAGE_DETECTION_MULTIFD), DEFINE_PROP_STRING("multifd-dsa-accel", MigrationState, parameters.multifd_dsa_accel), + DEFINE_PROP_SIZE("multifd-packet-size", MigrationState, + parameters.multifd_packet_size, + DEFAULT_MIGRATE_MULTIFD_PACKET_SIZE), /* Migration capabilities */ DEFINE_PROP_MIG_CAP("x-xbzrle", MIGRATION_CAPABILITY_XBZRLE), @@ -879,6 +888,13 @@ int migrate_multifd_channels(void) return s->parameters.multifd_channels; } +uint64_t migrate_multifd_packet_size(void) +{ + MigrationState *s = migrate_get_current(); + + return s->parameters.multifd_packet_size; +} + MultiFDCompression migrate_multifd_compression(void) { MigrationState *s = migrate_get_current(); @@ -1031,6 +1047,8 @@ MigrationParameters *qmp_query_migrate_parameters(Error **errp) params->x_checkpoint_delay = s->parameters.x_checkpoint_delay; params->has_block_incremental = true; params->block_incremental = s->parameters.block_incremental; + params->has_multifd_packet_size = true; + params->multifd_packet_size = s->parameters.multifd_packet_size; params->has_multifd_channels = true; params->multifd_channels = s->parameters.multifd_channels; params->has_multifd_compression = true; @@ -1094,6 +1112,7 @@ void migrate_params_init(MigrationParameters *params) params->has_downtime_limit = true; params->has_x_checkpoint_delay = true; params->has_block_incremental = true; + params->has_multifd_packet_size = true; params->has_multifd_channels = true; params->has_multifd_compression = true; params->has_multifd_zlib_level = true; @@ -1195,6 +1214,17 @@ bool migrate_params_check(MigrationParameters *params, Error **errp) /* x_checkpoint_delay is now always positive */ + if (params->has_multifd_packet_size && + ((params->multifd_packet_size < DEFAULT_MIGRATE_MULTIFD_PACKET_SIZE) || + (params->multifd_packet_size > MAX_MIGRATE_MULTIFD_PACKET_SIZE) || + (params->multifd_packet_size % qemu_target_page_size() != 0))) { + error_setg(errp, QERR_INVALID_PARAMETER_VALUE, + "multifd_packet_size", + "a value between 524288 and 4190208, " + "must be a multiple of guest VM's page size."); + return false; + } + if (params->has_multifd_channels && (params->multifd_channels < 1)) { error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "multifd_channels", @@ -1374,6 +1404,9 @@ static void migrate_params_test_apply(MigrateSetParameters *params, if (params->has_block_incremental) { dest->block_incremental = params->block_incremental; } + if (params->has_multifd_packet_size) { + dest->multifd_packet_size = params->multifd_packet_size; + } if (params->has_multifd_channels) { dest->multifd_channels = params->multifd_channels; } @@ -1524,6 +1557,9 @@ static void migrate_params_apply(MigrateSetParameters *params, Error **errp) " use blockdev-mirror with NBD instead"); s->parameters.block_incremental = params->block_incremental; } + if (params->has_multifd_packet_size) { + s->parameters.multifd_packet_size = params->multifd_packet_size; + } if (params->has_multifd_channels) { s->parameters.multifd_channels = params->multifd_channels; } diff --git a/migration/options.h b/migration/options.h index 1cb3393be9..23995e6608 100644 --- a/migration/options.h +++ b/migration/options.h @@ -92,6 +92,7 @@ const char *migrate_tls_hostname(void); uint64_t migrate_xbzrle_cache_size(void); ZeroPageDetection migrate_zero_page_detection(void); const char *migrate_multifd_dsa_accel(void); +uint64_t migrate_multifd_packet_size(void); /* parameters setters */ diff --git a/qapi/migration.json b/qapi/migration.json index 934fa8839e..39d609c394 100644 --- a/qapi/migration.json +++ b/qapi/migration.json @@ -920,6 +920,10 @@ # characters. Setting this string to an empty string means disabling # DSA accelerator offloading. Defaults to an empty string. (since 9.2) # +# @multifd-packet-size: Packet size in bytes used to migrate data. +# The value needs to be a multiple of guest VM's page size. +# The default value is 524288 and max value is 4190208. (Since 9.2) +# # Features: # # @deprecated: Member @block-incremental is deprecated. Use @@ -954,7 +958,8 @@ { 'name': 'x-vcpu-dirty-limit-period', 'features': ['unstable'] }, 'vcpu-dirty-limit', 'mode', - 'zero-page-detection'] } + 'zero-page-detection', + 'multifd-packet-size'] } ## # @MigrateSetParameters: @@ -1134,6 +1139,10 @@ # characters. Setting this string to an empty string means disabling # DSA accelerator offloading. Defaults to an empty string. (since 9.2) # +# @multifd-packet-size: Packet size in bytes used to migrate data. +# The value needs to be a multiple of guest VM's page size. +# The default value is 524288 and max value is 4190208. (Since 9.2) +# # Features: # # @deprecated: Member @block-incremental is deprecated. Use @@ -1189,7 +1198,8 @@ '*vcpu-dirty-limit': 'uint64', '*mode': 'MigMode', '*zero-page-detection': 'ZeroPageDetection', - '*multifd-dsa-accel': 'StrOrNull'} } + '*multifd-dsa-accel': 'StrOrNull', + '*multifd-packet-size' : 'uint64'} } ## # @migrate-set-parameters: @@ -1373,6 +1383,10 @@ # characters. Setting this string to an empty string means disabling # DSA accelerator offloading. Defaults to an empty string. (since 9.2) # +# @multifd-packet-size: Packet size in bytes used to migrate data. +# The value needs to be a multiple of guest VM's page size. +# The default value is 524288 and max value is 4190208. (Since 9.2) +# # Features: # # @deprecated: Member @block-incremental is deprecated. Use @@ -1425,7 +1439,8 @@ '*vcpu-dirty-limit': 'uint64', '*mode': 'MigMode', '*zero-page-detection': 'ZeroPageDetection', - '*multifd-dsa-accel': 'str'} } + '*multifd-dsa-accel': 'str', + '*multifd-packet-size': 'uint64'} } ## # @query-migrate-parameters: From patchwork Thu Apr 25 02:21:15 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hao Xiang X-Patchwork-Id: 13642789 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 8E308C4345F for ; Thu, 25 Apr 2024 02:24:40 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1rzolE-0000aQ-OG; Wed, 24 Apr 2024 22:22:56 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1rzolC-0000Zh-QC for qemu-devel@nongnu.org; Wed, 24 Apr 2024 22:22:54 -0400 Received: from out-171.mta1.migadu.com ([95.215.58.171]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1rzolA-0005W8-OJ for qemu-devel@nongnu.org; Wed, 24 Apr 2024 22:22:54 -0400 X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1714011771; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=xSyTylQQ31rsJQfAL2357Ree+ThKdOMHtL686KJImlE=; b=e+EIoVTx/vOJ1z4Tucuzr1PPLLqlaXPz0kHyzPTxmF7DouyhzUmeGNmTz9TOPNlNonM5D0 bepfM8Y1KzEFwuSqOrQ/7mzDNOzSuPsIhPmGeChE2y+9WLs/n5HNxnknxZpv8s5F5w+Pfv lShAIawzrO+UgIhXgxpNq1pavU0RulA= From: Hao Xiang To: marcandre.lureau@redhat.com, peterx@redhat.com, farosas@suse.de, armbru@redhat.com, lvivier@redhat.com, qemu-devel@nongnu.org Cc: Hao Xiang Subject: [PATCH v4 12/14] migration/multifd: Enable set packet size migration option. Date: Thu, 25 Apr 2024 02:21:15 +0000 Message-Id: <20240425022117.4035031-13-hao.xiang@linux.dev> In-Reply-To: <20240425022117.4035031-1-hao.xiang@linux.dev> References: <20240425022117.4035031-1-hao.xiang@linux.dev> MIME-Version: 1.0 X-Migadu-Flow: FLOW_OUT Received-SPF: pass client-ip=95.215.58.171; envelope-from=hao.xiang@linux.dev; helo=out-171.mta1.migadu.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org During live migration, if the latency between sender and receiver is high and bandwidth is also high (a long and fat pipe), using a bigger packet size can help reduce migration total time. In addition, Intel DSA offloading performs better with a large batch task. Providing an option to set the packet size is useful for performance tuning. Set the option: migrate_set_parameter multifd-packet-size 4190208 Signed-off-by: Hao Xiang --- migration/migration-hmp-cmds.c | 7 +++++++ migration/multifd-zlib.c | 6 ++++-- migration/multifd-zstd.c | 6 ++++-- migration/multifd.c | 6 ++++-- migration/multifd.h | 3 --- 5 files changed, 19 insertions(+), 9 deletions(-) diff --git a/migration/migration-hmp-cmds.c b/migration/migration-hmp-cmds.c index 7e9bb278c9..053ad0283a 100644 --- a/migration/migration-hmp-cmds.c +++ b/migration/migration-hmp-cmds.c @@ -338,6 +338,9 @@ void hmp_info_migrate_parameters(Monitor *mon, const QDict *qdict) monitor_printf(mon, "%s: %s\n", MigrationParameter_str(MIGRATION_PARAMETER_BLOCK_INCREMENTAL), params->block_incremental ? "on" : "off"); + monitor_printf(mon, "%s: %" PRIu64 "\n", + MigrationParameter_str(MIGRATION_PARAMETER_MULTIFD_PACKET_SIZE), + params->multifd_packet_size); monitor_printf(mon, "%s: %u\n", MigrationParameter_str(MIGRATION_PARAMETER_MULTIFD_CHANNELS), params->multifd_channels); @@ -630,6 +633,10 @@ void hmp_migrate_set_parameter(Monitor *mon, const QDict *qdict) p->multifd_dsa_accel->type = QTYPE_QSTRING; visit_type_str(v, param, &p->multifd_dsa_accel->u.s, &err); break; + case MIGRATION_PARAMETER_MULTIFD_PACKET_SIZE: + p->has_multifd_packet_size = true; + visit_type_size(v, param, &p->multifd_packet_size, &err); + break; case MIGRATION_PARAMETER_MULTIFD_CHANNELS: p->has_multifd_channels = true; visit_type_uint8(v, param, &p->multifd_channels, &err); diff --git a/migration/multifd-zlib.c b/migration/multifd-zlib.c index 737a9645d2..2880d35841 100644 --- a/migration/multifd-zlib.c +++ b/migration/multifd-zlib.c @@ -49,6 +49,7 @@ static int zlib_send_setup(MultiFDSendParams *p, Error **errp) struct zlib_data *z = g_new0(struct zlib_data, 1); z_stream *zs = &z->zs; const char *err_msg; + uint64_t multifd_packet_size = migrate_multifd_packet_size(); zs->zalloc = Z_NULL; zs->zfree = Z_NULL; @@ -58,7 +59,7 @@ static int zlib_send_setup(MultiFDSendParams *p, Error **errp) goto err_free_z; } /* This is the maximum size of the compressed buffer */ - z->zbuff_len = compressBound(MULTIFD_PACKET_SIZE); + z->zbuff_len = compressBound(multifd_packet_size); z->zbuff = g_try_malloc(z->zbuff_len); if (!z->zbuff) { err_msg = "out of memory for zbuff"; @@ -193,6 +194,7 @@ out: */ static int zlib_recv_setup(MultiFDRecvParams *p, Error **errp) { + uint64_t multifd_packet_size = migrate_multifd_packet_size(); struct zlib_data *z = g_new0(struct zlib_data, 1); z_stream *zs = &z->zs; @@ -207,7 +209,7 @@ static int zlib_recv_setup(MultiFDRecvParams *p, Error **errp) return -1; } /* To be safe, we reserve twice the size of the packet */ - z->zbuff_len = MULTIFD_PACKET_SIZE * 2; + z->zbuff_len = multifd_packet_size * 2; z->zbuff = g_try_malloc(z->zbuff_len); if (!z->zbuff) { inflateEnd(zs); diff --git a/migration/multifd-zstd.c b/migration/multifd-zstd.c index 256858df0a..edc738afbb 100644 --- a/migration/multifd-zstd.c +++ b/migration/multifd-zstd.c @@ -49,6 +49,7 @@ struct zstd_data { */ static int zstd_send_setup(MultiFDSendParams *p, Error **errp) { + uint64_t multifd_packet_size = migrate_multifd_packet_size(); struct zstd_data *z = g_new0(struct zstd_data, 1); int res; @@ -69,7 +70,7 @@ static int zstd_send_setup(MultiFDSendParams *p, Error **errp) return -1; } /* This is the maximum size of the compressed buffer */ - z->zbuff_len = ZSTD_compressBound(MULTIFD_PACKET_SIZE); + z->zbuff_len = ZSTD_compressBound(multifd_packet_size); z->zbuff = g_try_malloc(z->zbuff_len); if (!z->zbuff) { ZSTD_freeCStream(z->zcs); @@ -182,6 +183,7 @@ out: */ static int zstd_recv_setup(MultiFDRecvParams *p, Error **errp) { + uint64_t multifd_packet_size = migrate_multifd_packet_size(); struct zstd_data *z = g_new0(struct zstd_data, 1); int ret; @@ -203,7 +205,7 @@ static int zstd_recv_setup(MultiFDRecvParams *p, Error **errp) } /* To be safe, we reserve twice the size of the packet */ - z->zbuff_len = MULTIFD_PACKET_SIZE * 2; + z->zbuff_len = multifd_packet_size * 2; z->zbuff = g_try_malloc(z->zbuff_len); if (!z->zbuff) { ZSTD_freeDStream(z->zds); diff --git a/migration/multifd.c b/migration/multifd.c index 7316643d0a..2796646087 100644 --- a/migration/multifd.c +++ b/migration/multifd.c @@ -1154,7 +1154,8 @@ bool multifd_send_setup(void) MigrationState *s = migrate_get_current(); Error *local_err = NULL; int thread_count, ret = 0; - uint32_t page_count = MULTIFD_PACKET_SIZE / qemu_target_page_size(); + uint32_t page_count = + migrate_multifd_packet_size() / qemu_target_page_size(); bool use_packets = multifd_use_packets(); uint8_t i; const char *dsa_parameter = migrate_multifd_dsa_accel(); @@ -1577,7 +1578,8 @@ static void *multifd_recv_thread(void *opaque) int multifd_recv_setup(Error **errp) { int thread_count; - uint32_t page_count = MULTIFD_PACKET_SIZE / qemu_target_page_size(); + uint32_t page_count = + migrate_multifd_packet_size() / qemu_target_page_size(); bool use_packets = multifd_use_packets(); uint8_t i; const char *dsa_parameter = migrate_multifd_dsa_accel(); diff --git a/migration/multifd.h b/migration/multifd.h index b3717fae24..97d4095b6a 100644 --- a/migration/multifd.h +++ b/migration/multifd.h @@ -42,9 +42,6 @@ MultiFDRecvData *multifd_get_recv_data(void); #define MULTIFD_FLAG_ZLIB (1 << 1) #define MULTIFD_FLAG_ZSTD (2 << 1) -/* This value needs to be a multiple of qemu_target_page_size() */ -#define MULTIFD_PACKET_SIZE (512 * 1024) - typedef struct { uint32_t magic; uint32_t version; From patchwork Thu Apr 25 02:21:16 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hao Xiang X-Patchwork-Id: 13642790 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id AFB11C4345F for ; Thu, 25 Apr 2024 02:24:53 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1rzolI-0000b1-Oo; Wed, 24 Apr 2024 22:23:02 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1rzolF-0000aV-DM for qemu-devel@nongnu.org; Wed, 24 Apr 2024 22:22:57 -0400 Received: from out-181.mta1.migadu.com ([95.215.58.181]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1rzolC-0005fm-Nu for qemu-devel@nongnu.org; Wed, 24 Apr 2024 22:22:57 -0400 X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1714011773; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=0crJNuoW+nW3d0lLEukaZUR839qcrFK+o9JwkG0Mflg=; b=H84vlzX4x67rGXD6UaZWaGYvvHJqklyIf1Eov+2GgWitImODoNFhHfnqG7NWyBiuoJZYqr DGYBnIQ4P1fLuMJw3yxtWKkaIKCEwQGR/FQ+FOfjF7HsEyjnFTKeiYAt5Qh3Msdp0fpCas bgJK4OJCs9U4uWg1HQbCipgqvGxg6uk= From: Hao Xiang To: marcandre.lureau@redhat.com, peterx@redhat.com, farosas@suse.de, armbru@redhat.com, lvivier@redhat.com, qemu-devel@nongnu.org Cc: Hao Xiang , Bryan Zhang Subject: [PATCH v4 13/14] util/dsa: Add unit test coverage for Intel DSA task submission and completion. Date: Thu, 25 Apr 2024 02:21:16 +0000 Message-Id: <20240425022117.4035031-14-hao.xiang@linux.dev> In-Reply-To: <20240425022117.4035031-1-hao.xiang@linux.dev> References: <20240425022117.4035031-1-hao.xiang@linux.dev> MIME-Version: 1.0 X-Migadu-Flow: FLOW_OUT Received-SPF: pass client-ip=95.215.58.181; envelope-from=hao.xiang@linux.dev; helo=out-181.mta1.migadu.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org * Test DSA start and stop path. * Test DSA configure and cleanup path. * Test DSA task submission and completion path. Signed-off-by: Bryan Zhang Signed-off-by: Hao Xiang --- tests/unit/meson.build | 6 + tests/unit/test-dsa.c | 499 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 505 insertions(+) create mode 100644 tests/unit/test-dsa.c diff --git a/tests/unit/meson.build b/tests/unit/meson.build index 26c109c968..1d4d48898b 100644 --- a/tests/unit/meson.build +++ b/tests/unit/meson.build @@ -49,6 +49,12 @@ tests = { 'test-interval-tree': [], } +if config_host_data.get('CONFIG_DSA_OPT') + tests += { + 'test-dsa': [], + } +endif + if have_system or have_tools tests += { 'test-qmp-event': [testqapi], diff --git a/tests/unit/test-dsa.c b/tests/unit/test-dsa.c new file mode 100644 index 0000000000..0f2092767d --- /dev/null +++ b/tests/unit/test-dsa.c @@ -0,0 +1,499 @@ +/* + * Test DSA functions. + * + * Copyright (c) 2023 Hao Xiang + * Copyright (c) 2023 Bryan Zhang + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ +#include "qemu/osdep.h" +#include "qemu/host-utils.h" + +#include "qemu/cutils.h" +#include "qemu/memalign.h" +#include "qemu/dsa.h" + +/* + * TODO Communicate that DSA must be configured to support this batch size. + * TODO Alternatively, poke the DSA device to figure out batch size. + */ +#define batch_size 128 +#define page_size 4096 + +#define oversized_batch_size (batch_size + 1) +#define num_devices 2 +#define max_buffer_size (64 * 1024) + +/* TODO Make these not-hardcoded. */ +static const char *path1 = "/dev/dsa/wq4.0"; +static const char *path2 = "/dev/dsa/wq4.0 /dev/dsa/wq4.1"; + +static struct batch_task *task; + +/* A helper for running a single task and checking for correctness. */ +static void do_single_task(void) +{ + task = batch_task_init(batch_size); + char buf[page_size]; + char *ptr = buf; + + buffer_is_zero_dsa_batch_async(task, + (const void **)&ptr, + 1, + page_size); + g_assert(task->results[0] == buffer_is_zero(buf, page_size)); + + batch_task_destroy(task); +} + +static void test_single_zero(void) +{ + g_assert(!dsa_init(path1)); + dsa_start(); + + task = batch_task_init(batch_size); + + char buf[page_size]; + char *ptr = buf; + + memset(buf, 0x0, page_size); + buffer_is_zero_dsa_batch_async(task, + (const void **)&ptr, + 1, page_size); + g_assert(task->results[0]); + + batch_task_destroy(task); + + dsa_cleanup(); +} + +static void test_single_zero_async(void) +{ + test_single_zero(); +} + +static void test_single_nonzero(void) +{ + g_assert(!dsa_init(path1)); + dsa_start(); + + task = batch_task_init(batch_size); + + char buf[page_size]; + char *ptr = buf; + + memset(buf, 0x1, page_size); + buffer_is_zero_dsa_batch_async(task, + (const void **)&ptr, + 1, page_size); + g_assert(!task->results[0]); + + batch_task_destroy(task); + + dsa_cleanup(); +} + +static void test_single_nonzero_async(void) +{ + test_single_nonzero(); +} + +/* count == 0 should return quickly without calling into DSA. */ +static void test_zero_count_async(void) +{ + char buf[page_size]; + buffer_is_zero_dsa_batch_async(task, + (const void **)&buf, + 0, + page_size); +} + +static void test_null_task_async(void) +{ + if (g_test_subprocess()) { + g_assert(!dsa_init(path1)); + + char buf[page_size * batch_size]; + char *addrs[batch_size]; + for (int i = 0; i < batch_size; i++) { + addrs[i] = buf + (page_size * i); + } + + buffer_is_zero_dsa_batch_async(NULL, (const void **)addrs, + batch_size, + page_size); + } else { + g_test_trap_subprocess(NULL, 0, 0); + g_test_trap_assert_failed(); + } +} + +static void test_oversized_batch(void) +{ + g_assert(!dsa_init(path1)); + dsa_start(); + + task = batch_task_init(batch_size); + + char buf[page_size * oversized_batch_size]; + char *addrs[batch_size]; + for (int i = 0; i < oversized_batch_size; i++) { + addrs[i] = buf + (page_size * i); + } + + int ret = buffer_is_zero_dsa_batch_async(task, + (const void **)addrs, + oversized_batch_size, + page_size); + g_assert(ret != 0); + + batch_task_destroy(task); + + dsa_cleanup(); +} + +static void test_oversized_batch_async(void) +{ + test_oversized_batch(); +} + +static void test_zero_len_async(void) +{ + if (g_test_subprocess()) { + g_assert(!dsa_init(path1)); + + task = batch_task_init(batch_size); + + char buf[page_size]; + + buffer_is_zero_dsa_batch_async(task, + (const void **)&buf, + 1, + 0); + + batch_task_destroy(task); + } else { + g_test_trap_subprocess(NULL, 0, 0); + g_test_trap_assert_failed(); + } +} + +static void test_null_buf_async(void) +{ + if (g_test_subprocess()) { + g_assert(!dsa_init(path1)); + + task = batch_task_init(batch_size); + + buffer_is_zero_dsa_batch_async(task, NULL, 1, page_size); + + batch_task_destroy(task); + } else { + g_test_trap_subprocess(NULL, 0, 0); + g_test_trap_assert_failed(); + } +} + +static void test_batch(void) +{ + g_assert(!dsa_init(path1)); + dsa_start(); + + task = batch_task_init(batch_size); + + char buf[page_size * batch_size]; + char *addrs[batch_size]; + for (int i = 0; i < batch_size; i++) { + addrs[i] = buf + (page_size * i); + } + + /* + * Using whatever is on the stack is somewhat random. + * Manually set some pages to zero and some to nonzero. + */ + memset(buf + 0, 0, page_size * 10); + memset(buf + (10 * page_size), 0xff, page_size * 10); + + buffer_is_zero_dsa_batch_async(task, + (const void **)addrs, + batch_size, + page_size); + + bool is_zero; + for (int i = 0; i < batch_size; i++) { + is_zero = buffer_is_zero((const void *)&buf[page_size * i], page_size); + g_assert(task->results[i] == is_zero); + } + + batch_task_destroy(task); + + dsa_cleanup(); +} + +static void test_batch_async(void) +{ + test_batch(); +} + +static void test_page_fault(void) +{ + g_assert(!dsa_init(path1)); + dsa_start(); + + char *buf[2]; + int prot = PROT_READ | PROT_WRITE; + int flags = MAP_SHARED | MAP_ANON; + buf[0] = (char *)mmap(NULL, page_size * batch_size, prot, flags, -1, 0); + assert(buf[0] != MAP_FAILED); + buf[1] = (char *)malloc(page_size * batch_size); + assert(buf[1] != NULL); + + for (int j = 0; j < 2; j++) { + task = batch_task_init(batch_size); + + char *addrs[batch_size]; + for (int i = 0; i < batch_size; i++) { + addrs[i] = buf[j] + (page_size * i); + } + + buffer_is_zero_dsa_batch_async(task, + (const void **)addrs, + batch_size, + page_size); + + bool is_zero; + for (int i = 0; i < batch_size; i++) { + is_zero = buffer_is_zero((const void *)&buf[j][page_size * i], + page_size); + g_assert(task->results[i] == is_zero); + } + batch_task_destroy(task); + } + + assert(!munmap(buf[0], page_size * batch_size)); + free(buf[1]); + dsa_cleanup(); +} + +static void test_various_buffer_sizes(void) +{ + g_assert(!dsa_init(path1)); + dsa_start(); + + char *buf = malloc(max_buffer_size * batch_size); + char *addrs[batch_size]; + + for (int len = 16; len <= max_buffer_size; len *= 2) { + task = batch_task_init(batch_size); + + for (int i = 0; i < batch_size; i++) { + addrs[i] = buf + (len * i); + } + + buffer_is_zero_dsa_batch_async(task, + (const void **)addrs, + batch_size, + len); + + bool is_zero; + for (int j = 0; j < batch_size; j++) { + is_zero = buffer_is_zero((const void *)&buf[len * j], len); + g_assert(task->results[j] == is_zero); + } + + batch_task_destroy(task); + } + + free(buf); + + dsa_cleanup(); +} + +static void test_various_buffer_sizes_async(void) +{ + test_various_buffer_sizes(); +} + +static void test_double_start_stop(void) +{ + g_assert(!dsa_init(path1)); + /* Double start */ + dsa_start(); + dsa_start(); + g_assert(dsa_is_running()); + do_single_task(); + + /* Double stop */ + dsa_stop(); + g_assert(!dsa_is_running()); + dsa_stop(); + g_assert(!dsa_is_running()); + + /* Restart */ + dsa_start(); + g_assert(dsa_is_running()); + do_single_task(); + dsa_cleanup(); +} + +static void test_is_running(void) +{ + g_assert(!dsa_init(path1)); + + g_assert(!dsa_is_running()); + dsa_start(); + g_assert(dsa_is_running()); + dsa_stop(); + g_assert(!dsa_is_running()); + dsa_cleanup(); +} + +static void test_multiple_engines(void) +{ + g_assert(!dsa_init(path2)); + dsa_start(); + + struct batch_task *tasks[num_devices]; + char bufs[num_devices][page_size * batch_size]; + char *addrs[num_devices][batch_size]; + + /* + * This is a somewhat implementation-specific way + * of testing that the tasks have unique engines + * assigned to them. + */ + tasks[0] = batch_task_init(batch_size); + tasks[1] = batch_task_init(batch_size); + g_assert(tasks[0]->dsa_batch->device != tasks[1]->dsa_batch->device); + + for (int i = 0; i < num_devices; i++) { + for (int j = 0; j < batch_size; j++) { + addrs[i][j] = bufs[i] + (page_size * j); + } + + buffer_is_zero_dsa_batch_async(tasks[i], + (const void **)addrs[i], + batch_size, page_size); + + bool is_zero; + for (int j = 0; j < batch_size; j++) { + is_zero = buffer_is_zero((const void *)&bufs[i][page_size * j], + page_size); + g_assert(tasks[i]->results[j] == is_zero); + } + } + + batch_task_destroy(tasks[0]); + batch_task_destroy(tasks[1]); + + dsa_cleanup(); +} + +static void test_configure_dsa_twice(void) +{ + g_assert(!dsa_init(path2)); + g_assert(!dsa_init(path2)); + dsa_start(); + do_single_task(); + dsa_cleanup(); +} + +static void test_configure_dsa_bad_path(void) +{ + const char *bad_path = "/not/a/real/path"; + g_assert(dsa_init(bad_path)); +} + +static void test_cleanup_before_configure(void) +{ + dsa_cleanup(); + g_assert(!dsa_init(path2)); +} + +static void test_configure_dsa_num_devices(void) +{ + g_assert(!dsa_init(path1)); + dsa_start(); + + do_single_task(); + dsa_stop(); + dsa_cleanup(); +} + +static void test_cleanup_twice(void) +{ + g_assert(!dsa_init(path2)); + dsa_cleanup(); + dsa_cleanup(); + + g_assert(!dsa_init(path2)); + dsa_start(); + do_single_task(); + dsa_cleanup(); +} + +static int check_test_setup(void) +{ + const char *path[2] = {path1, path2}; + for (int i = 0; i < sizeof(path) / sizeof(char *); i++) { + if (dsa_init(path[i])) { + return -1; + } + dsa_cleanup(); + } + return 0; +} + +int main(int argc, char **argv) +{ + g_test_init(&argc, &argv, NULL); + + if (check_test_setup() != 0) { + /* + * This test requires extra setup. The current + * setup is not correct. Just skip this test + * for now. + */ + exit(0); + } + + if (num_devices > 1) { + g_test_add_func("/dsa/multiple_engines", test_multiple_engines); + } + + g_test_add_func("/dsa/async/batch", test_batch_async); + g_test_add_func("/dsa/async/various_buffer_sizes", + test_various_buffer_sizes_async); + g_test_add_func("/dsa/async/null_buf", test_null_buf_async); + g_test_add_func("/dsa/async/zero_len", test_zero_len_async); + g_test_add_func("/dsa/async/oversized_batch", test_oversized_batch_async); + g_test_add_func("/dsa/async/zero_count", test_zero_count_async); + g_test_add_func("/dsa/async/single_zero", test_single_zero_async); + g_test_add_func("/dsa/async/single_nonzero", test_single_nonzero_async); + g_test_add_func("/dsa/async/null_task", test_null_task_async); + g_test_add_func("/dsa/async/page_fault", test_page_fault); + + g_test_add_func("/dsa/double_start_stop", test_double_start_stop); + g_test_add_func("/dsa/is_running", test_is_running); + + g_test_add_func("/dsa/configure_dsa_twice", test_configure_dsa_twice); + g_test_add_func("/dsa/configure_dsa_bad_path", test_configure_dsa_bad_path); + g_test_add_func("/dsa/cleanup_before_configure", + test_cleanup_before_configure); + g_test_add_func("/dsa/configure_dsa_num_devices", + test_configure_dsa_num_devices); + g_test_add_func("/dsa/cleanup_twice", test_cleanup_twice); + + return g_test_run(); +} From patchwork Thu Apr 25 02:21:17 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hao Xiang X-Patchwork-Id: 13642792 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id A7B2EC41513 for ; Thu, 25 Apr 2024 02:24:54 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1rzolN-0000cd-7C; Wed, 24 Apr 2024 22:23:06 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1rzolH-0000b2-2N for qemu-devel@nongnu.org; Wed, 24 Apr 2024 22:23:00 -0400 Received: from out-185.mta1.migadu.com ([2001:41d0:203:375::b9]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1rzolE-0005jO-Ut for qemu-devel@nongnu.org; Wed, 24 Apr 2024 22:22:58 -0400 X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1714011775; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=3FdkH12BWUl2uudWmCYj+yzXHq6/TJHWfPBfYdJebJE=; b=YuYBeH5Bp768uVYCDf0u1rbKanNZlYE6CdPpIqKh7F6YBfI61UTLNas8EsFgu4POFGCQbn F9Y7gHrLPxbDbUJ4V2qG/SIAaD97fCR51vxIuAIWjMqRuL519rMs0JFyQGyT+SrOtMlJHu eXYxN9QeA0FNjqknR/HyGG1d8qI0eUM= From: Hao Xiang To: marcandre.lureau@redhat.com, peterx@redhat.com, farosas@suse.de, armbru@redhat.com, lvivier@redhat.com, qemu-devel@nongnu.org Cc: Hao Xiang , Bryan Zhang Subject: [PATCH v4 14/14] migration/multifd: Add integration tests for multifd with Intel DSA offloading. Date: Thu, 25 Apr 2024 02:21:17 +0000 Message-Id: <20240425022117.4035031-15-hao.xiang@linux.dev> In-Reply-To: <20240425022117.4035031-1-hao.xiang@linux.dev> References: <20240425022117.4035031-1-hao.xiang@linux.dev> MIME-Version: 1.0 X-Migadu-Flow: FLOW_OUT Received-SPF: pass client-ip=2001:41d0:203:375::b9; envelope-from=hao.xiang@linux.dev; helo=out-185.mta1.migadu.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org * Add test case to start and complete multifd live migration with DSA offloading enabled. * Add test case to start and cancel multifd live migration with DSA offloading enabled. Signed-off-by: Bryan Zhang Signed-off-by: Hao Xiang --- tests/qtest/migration-test.c | 77 +++++++++++++++++++++++++++++++++++- 1 file changed, 76 insertions(+), 1 deletion(-) diff --git a/tests/qtest/migration-test.c b/tests/qtest/migration-test.c index 5d6d8cd634..354c5f26f8 100644 --- a/tests/qtest/migration-test.c +++ b/tests/qtest/migration-test.c @@ -616,6 +616,12 @@ typedef struct { bool suspend_me; } MigrateStart; +/* + * It requires separate steps to configure and enable DSA device. + * This test assumes that the configuration is done already. + */ +static const char *dsa_dev_path = "/dev/dsa/wq4.0"; + /* * A hook that runs after the src and dst QEMUs have been * created, but before the migration is started. This can @@ -3025,7 +3031,7 @@ static void test_multifd_tcp_tls_x509_reject_anon_client(void) * * And see that it works */ -static void test_multifd_tcp_cancel(void) +static void test_multifd_tcp_cancel_common(bool use_dsa) { MigrateStart args = { .hide_stderr = true, @@ -3045,6 +3051,10 @@ static void test_multifd_tcp_cancel(void) migrate_set_capability(from, "multifd", true); migrate_set_capability(to, "multifd", true); + if (use_dsa) { + migrate_set_parameter_str(from, "multifd-dsa-accel", dsa_dev_path); + } + /* Start incoming migration from the 1st socket */ migrate_incoming_qmp(to, "tcp:127.0.0.1:0", "{}"); @@ -3094,6 +3104,48 @@ static void test_multifd_tcp_cancel(void) test_migrate_end(from, to2, true); } +/* + * This test does: + * source target + * migrate_incoming + * migrate + * migrate_cancel + * launch another target + * migrate + * + * And see that it works + */ +static void test_multifd_tcp_cancel(void) +{ + test_multifd_tcp_cancel_common(false); +} + +#ifdef CONFIG_DSA_OPT + +static void *test_migrate_precopy_tcp_multifd_start_dsa(QTestState *from, + QTestState *to) +{ + migrate_set_parameter_str(from, "multifd-dsa-accel", dsa_dev_path); + return test_migrate_precopy_tcp_multifd_start_common(from, to, "none"); +} + +static void test_multifd_tcp_zero_page_dsa(void) +{ + MigrateCommon args = { + .listen_uri = "defer", + .start_hook = test_migrate_precopy_tcp_multifd_start_dsa, + }; + + test_precopy_common(&args); +} + +static void test_multifd_tcp_cancel_dsa(void) +{ + test_multifd_tcp_cancel_common(true); +} + +#endif + static void calc_dirty_rate(QTestState *who, uint64_t calc_time) { qtest_qmp_assert_success(who, @@ -3518,6 +3570,19 @@ static bool kvm_dirty_ring_supported(void) #endif } +#ifdef CONFIG_DSA_OPT +static int test_dsa_setup(void) +{ + int fd; + fd = open(dsa_dev_path, O_RDWR); + if (fd < 0) { + return -1; + } + close(fd); + return 0; +} +#endif + int main(int argc, char **argv) { bool has_kvm, has_tcg; @@ -3752,6 +3817,16 @@ int main(int argc, char **argv) test_multifd_tcp_zero_page_legacy); migration_test_add("/migration/multifd/tcp/plain/zero-page/none", test_multifd_tcp_no_zero_page); + +#ifdef CONFIG_DSA_OPT + if (g_str_equal(arch, "x86_64") && test_dsa_setup() == 0) { + migration_test_add("/migration/multifd/tcp/plain/zero-page/dsa", + test_multifd_tcp_zero_page_dsa); + migration_test_add("/migration/multifd/tcp/plain/cancel/dsa", + test_multifd_tcp_cancel_dsa); + } +#endif + migration_test_add("/migration/multifd/tcp/plain/cancel", test_multifd_tcp_cancel); migration_test_add("/migration/multifd/tcp/plain/zlib",