From nobody Sat Jul 25 21:23:04 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=163.com ARC-Seal: i=1; a=rsa-sha256; t=1783959711; cv=none; d=zohomail.com; s=zohoarc; b=Zd/vpBjxiCHv1bhe+3xgnDG8Or7TZjvcIU9afIe81ZranCAgG4TZMK+Wz0fkmdgX4t7zxBHLKtLMmg82t5PiTwN1inD9PzckvVdYzJHKizUFs0W5zD429VkeeDtM34Gs9PdLlwhEXIVj8r5Z9ssrQpx+w8exK61yBdQyw1FeFpA= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1783959711; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=zOeUvR+KCloUQ9JBTcycPFWmCXukO2RkOFeD1a1nKmQ=; b=LG5pH4BOQvsNL3O7kB1n6aWpqWMo54pPcb/XHLkSQmJacqnr97xkQRhB98ke/1LTZDwuIbbc+mY8ZCvutC87wy4di2OypTm2HAJqLLZDOKGNOTDbjhjGnqkCLzae0h2smc3UQy7/y2VK3G6bisN0nmWzw1uF48q0y5PB1aaM9yU= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 17839597112180.9578260100508942; Mon, 13 Jul 2026 09:21:51 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wjJPM-0006D0-1J; Mon, 13 Jul 2026 12:21:28 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wjJPK-0006CP-FW; Mon, 13 Jul 2026 12:21:26 -0400 Received: from m16.mail.163.com ([220.197.31.3]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wjJPG-0000fM-GM; Mon, 13 Jul 2026 12:21:26 -0400 Received: from dt-VM.localdomain (unknown []) by gzsmtp1 (Coremail) with SMTP id PCgvCgDHn6V0D1Vqlt9mGA--.65356S3; Tue, 14 Jul 2026 00:16:54 +0800 (CST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=163.com; s=s110527; h=From:To:Subject:Date:Message-ID:MIME-Version; bh=zO eUvR+KCloUQ9JBTcycPFWmCXukO2RkOFeD1a1nKmQ=; b=FbODNCjFiWUFBjbBwQ YVF1GH8suvV+oi95WF3apZOkc4ipKeKUIwpwybGFn9bJl2XgFcttPNpwBKKKCIdi wpMIVBLpPrHHTkAuKTrJI+e+1Ptq6vlfDnVRPvdVrjIeGX/0A5FkWRH3z4Gak654 6vXbyMzXJ32koIBd3qinZ9BlI= From: Tao Ding To: qemu-devel@nongnu.org Cc: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , Bin Meng , qemu-block@nongnu.org, Fabiano Rosas , Laurent Vivier , Paolo Bonzini , Tao Ding Subject: [PATCH v6 1/2] hw/sd: sdhci: Fix SDMA boundary bug Date: Tue, 14 Jul 2026 00:16:46 +0800 Message-ID: <20260713161647.20211-2-dingtao0430@163.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260713161647.20211-1-dingtao0430@163.com> References: <20260713161647.20211-1-dingtao0430@163.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-CM-TRANSID: PCgvCgDHn6V0D1Vqlt9mGA--.65356S3 X-Coremail-Antispam: 1Uf129KBjvJXoWxtr13Ar4DZrWrZry7Aw1DKFg_yoWxGFWDpF Zakr4rKrs7Kr1fuF4rJ3W3AF4F9r4xuasrKr43GwnagFZxKFyFvwsFka4UKr10yryxZr12 9rWUJr909a4UA3DanT9S1TB71UUUUU7qnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2 9KBjDUYxBIdaVFxhVjvjDU0xZFpf9x0piOBMtUUUUU= X-Originating-IP: [119.4.20.225] X-CM-SenderInfo: pglqw3tdrqkjqq6rljoofrz/xtbC-hbQD2pVD3ZpQQAA3Z Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=220.197.31.3; envelope-from=dingtao0430@163.com; helo=m16.mail.163.com X-Spam_score_int: -17 X-Spam_score: -1.8 X-Spam_bar: - X-Spam_report: (-1.8 / 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, FREEMAIL_ENVFROM_END_DIGIT=0.25, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, UNPARSEABLE_RELAY=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: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @163.com) X-ZM-MESSAGEID: 1783959713884158500 Content-Type: text/plain; charset="utf-8" During SDMA transfers, the controller raises an interrupt at buffer boundar= ies to request a system address update. The host driver will rewrite the SDHC_S= YSAD register.=20 (according to PartA2_SD_Host_Controller_Simplified_Specification_Ver2.00.pd= f section 2.2.1) However, the current code will ignore write operations to SDHC_SYSAD.=20 To fix this bug, when SDMA encounters a boundary, a state is set to record = it.=20 In this state, SDHC_SYSAD can be written. In other cases, it is still prote= cted by TRANSFERRING_DATA. Meanwhile, a subsection has been added for migration. Suggested-by: Bin Meng Signed-off-by: Tao Ding --- This bug may be encountered when using uboot with SDMA functionality, and c= an be reproduced by following the steps below. Uboot test: 1. Prepare zImage, uboot and rootfs.cpio.gz, make sure uboot config (MM= C_SDHCI_SDMA=3Dy). for more detail, can obtained=20 "https://lore.kernel.org/qemu-devel/20260617155857.7451-1-dingtao04= 30@163.com/T/#mcdf231e6bd762903f8393bf93253cbcb12ececcf" 2. ./qemu-system-aarch64 -M xilinx-zynq-a9 -machine boot-mode=3Dsd -m 1= 024 -display none -serial null -serial stdio -monitor none \ -device loader,file=3Du-boot-dtb.bin,addr=3D0x04000000,cpu-num=3D0 = \ -drive file=3Dzynq-sd.img,format=3Draw,if=3Dsd -D qemu.log After applying the fix, success load sd card: =20 U-Boot 2026.07-rc4-g1e80ee41441c (Jun 15 2026 - 19:05:05 +0800) Model: Xilinx ZC702 board DRAM: ECC disabled 1 GiB Core: 33 devices, 21 uclasses, devicetree: board Flash: 0 Bytes NAND: 0 MiB MMC: mmc@e0100000: 0 Loading Environment from FAT... *** Error - No Valid Environment Area found *** Warning - bad env area, using default environment In: serial@e0001000 Out: serial@e0001000 Err: serial@e0001000 Net: =20 ZYNQ GEM: e000b000, mdio bus e000b000, phyaddr 7, interface rgmii-id Warning: ethernet@e000b000 (eth0) using random MAC address - 4a:63:5a:a4:d3= :6b eth0: ethernet@e000b000 Hit any key to stop autoboot: 0 Zynq> fatload mmc 0 ${kernel_addr_r} zImage 10838528 bytes read in 4316 ms (2.4 MiB/s) Zynq> fatload mmc 0 ${ramdisk_addr_r} rootfs-arm32.cpio.gz 406531 bytes read in 199 ms (1.9 MiB/s) Zynq> setenv ramdisk_size ${filesize} Zynq> fatload mmc 0 ${fdt_addr_r} zynq-zc702.dtb 15754 bytes read in 21 ms (732.4 KiB/s) Zynq> setenv bootargs console=3DttyPS0,115200 earlycon ignore_loglevel rdin= it=3D/init Zynq> bootz ${kernel_addr_r} ${ramdisk_addr_r}:${ramdisk_size} ${fdt_addr_r} Kernel image @ 0x2000000 [ 0x000000 - 0xa56200 ] ## Flattened Device Tree blob at 01f00000 Booting using the fdt blob at 0x1f00000 Working FDT set to 1f00000 Loading Ramdisk to 2ff9c000, end 2ffff403 ... OK Loading Device Tree to 2ff95000, end 2ff9bd89 ... OK Working FDT set to 2ff95000 Starting kernel ... hw/sd/sdhci.c | 25 ++++++++++++++++++++++++- include/hw/sd/sdhci.h | 2 ++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c index c86dfa281f..e614afa346 100644 --- a/hw/sd/sdhci.c +++ b/hw/sd/sdhci.c @@ -307,6 +307,7 @@ static void sdhci_reset(SDHCIState *s) s->data_count =3D 0; s->stopped_state =3D sdhc_not_stopped; s->pending_insert_state =3D false; + s->sdma_boundary_paused =3D false; if (object_dynamic_cast(OBJECT(s), TYPE_FSL_ESDHC_BE) || object_dynamic_cast(OBJECT(s), TYPE_FSL_ESDHC_LE)) { s->norintstsen =3D 0x013f; @@ -414,6 +415,7 @@ static void sdhci_end_transfer(SDHCIState *s) s->norintsts |=3D SDHC_NIS_TRSCMP; } =20 + s->sdma_boundary_paused =3D false; sdhci_update_irq(s); } =20 @@ -681,6 +683,7 @@ static void sdhci_sdma_transfer_multi_blocks(SDHCIState= *s) if (s->blkcnt =3D=3D 0) { sdhci_end_transfer(s); } else { + s->sdma_boundary_paused =3D true; sdhci_update_irq(s); } } @@ -1164,6 +1167,7 @@ static inline void sdhci_reset_write(SDHCIState *s, u= int8_t value) SDHC_DATA_INHIBIT | SDHC_DAT_LINE_ACTIVE); s->blkgap &=3D ~(SDHC_STOP_AT_GAP_REQ | SDHC_CONTINUE_REQ); s->stopped_state =3D sdhc_not_stopped; + s->sdma_boundary_paused =3D false; s->norintsts &=3D ~(SDHC_NIS_WBUFRDY | SDHC_NIS_RBUFRDY | SDHC_NIS_DMA | SDHC_NIS_TRSCMP | SDHC_NIS_BLKGAP); break; @@ -1185,7 +1189,7 @@ sdhci_write(void *opaque, hwaddr offset, uint64_t val= , unsigned size) =20 switch (offset & ~0x3) { case SDHC_SYSAD: - if (!TRANSFERRING_DATA(s->prnsts)) { + if (!TRANSFERRING_DATA(s->prnsts) || s->sdma_boundary_paused) { s->sdmasysad =3D (s->sdmasysad & mask) | value; MASKED_WRITE(s->sdmasysad, mask, value); /* Writing to last byte of sdmasysad might trigger transfer */ @@ -1464,6 +1468,13 @@ static bool sdhci_pending_insert_vmstate_needed(void= *opaque) return s->pending_insert_state; } =20 +static bool sdhci_sdma_boundary_paused_vmstate_needed(void *opaque) +{ + SDHCIState *s =3D opaque; + + return s->sdma_boundary_paused; +} + static const VMStateDescription sdhci_pending_insert_vmstate =3D { .name =3D "sdhci/pending-insert", .version_id =3D 1, @@ -1475,6 +1486,17 @@ static const VMStateDescription sdhci_pending_insert= _vmstate =3D { }, }; =20 +static const VMStateDescription sdhci_sdma_boundary_paused_vmstate =3D { + .name =3D "sdhci/sdma_boundary_paused", + .version_id =3D 1, + .minimum_version_id =3D 1, + .needed =3D sdhci_sdma_boundary_paused_vmstate_needed, + .fields =3D (const VMStateField[]) { + VMSTATE_BOOL(sdma_boundary_paused, SDHCIState), + VMSTATE_END_OF_LIST() + }, +}; + const VMStateDescription sdhci_vmstate =3D { .name =3D "sdhci", .version_id =3D 1, @@ -1512,6 +1534,7 @@ const VMStateDescription sdhci_vmstate =3D { }, .subsections =3D (const VMStateDescription * const []) { &sdhci_pending_insert_vmstate, + &sdhci_sdma_boundary_paused_vmstate, NULL }, }; diff --git a/include/hw/sd/sdhci.h b/include/hw/sd/sdhci.h index a9da6203fc..c485277744 100644 --- a/include/hw/sd/sdhci.h +++ b/include/hw/sd/sdhci.h @@ -103,6 +103,8 @@ struct SDHCIState { * to be protected. Set wp_inverted to invert the signal. */ bool wp_inverted; + /* Indicate that SDMA transfer is paused due to hitting the boundary */ + bool sdma_boundary_paused; }; typedef struct SDHCIState SDHCIState; =20 --=20 2.43.0 From nobody Sat Jul 25 21:23:04 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=163.com ARC-Seal: i=1; a=rsa-sha256; t=1783959712; cv=none; d=zohomail.com; s=zohoarc; b=n6GR7+Cphb7OXjne5l60G0lK6bWCCto9wl68wBbuG4mWEU/orc39K4kY9jC/cuVLPWndyyJW6GNp+L1TAgLOc+s88uq+TzM0I1OHwOqY5GYnUHAyaTQcRpEwt3np6vHaOnk4NoY0QlMPh4Qz3gEM24Wbe2g0ArMr2Us0xctlCD0= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1783959712; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=/ByKZXimCJi4X7EzjbGxNgZhT93ZP7A7Lx8bsxLV0w4=; b=j2I5FE3KUVwNsF1SLd/1gaNhSmnsZsINAbp3L1ghmkSK4cI3A7US8JNJP0fYonGur/DdPsdT4UM8rHDB0Uw/LgUcEr1DBiaZIFtlwyLFov+yw10W7KB+TevT4Jz2+3TlBucQqbbvzeHFFX3rak7r8s9+uIScfTuq46Z1chNSx3s= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 17839597127371023.0321924268181; Mon, 13 Jul 2026 09:21:52 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wjJPP-0006E3-PG; Mon, 13 Jul 2026 12:21:31 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wjJPO-0006Di-K9; Mon, 13 Jul 2026 12:21:30 -0400 Received: from m16.mail.163.com ([220.197.31.2]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wjJPM-0000hP-3x; Mon, 13 Jul 2026 12:21:30 -0400 Received: from dt-VM.localdomain (unknown []) by gzsmtp1 (Coremail) with SMTP id PCgvCgDHn6V0D1Vqlt9mGA--.65356S4; Tue, 14 Jul 2026 00:16:54 +0800 (CST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=163.com; s=s110527; h=From:To:Subject:Date:Message-ID:MIME-Version; bh=/B yKZXimCJi4X7EzjbGxNgZhT93ZP7A7Lx8bsxLV0w4=; b=HhohU5NPtnt7IBii6F dBtlYLomVKOQ8TY9fOy/BaevW5Hj+x9rWHyL4g5U+slkpClv+sTZTf9gOBV9o7pf yLHuGs+ieRh0r79bZe4ZY20gQWESW9jGaO9lnJrdPr6bTvYrXyGpKwnkI7Xugdnj ED+Sek/twiX/krily74yMPPIg= From: Tao Ding To: qemu-devel@nongnu.org Cc: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , Bin Meng , qemu-block@nongnu.org, Fabiano Rosas , Laurent Vivier , Paolo Bonzini , Tao Ding Subject: [PATCH v6 2/2] qtest: add xilinx-zynq SDHCI sdma test Date: Tue, 14 Jul 2026 00:16:47 +0800 Message-ID: <20260713161647.20211-3-dingtao0430@163.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260713161647.20211-1-dingtao0430@163.com> References: <20260713161647.20211-1-dingtao0430@163.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-CM-TRANSID: PCgvCgDHn6V0D1Vqlt9mGA--.65356S4 X-Coremail-Antispam: 1Uf129KBjvJXoW3JFyDWF4rGF4xuF1xXw4UXFb_yoW3XryDpa yj9FyjyrZ0yF18Xrs3G3W5tF1Y9rsxZa4UWFW5urs2kr4kJF9Fvrs7KFyUXrs7JrW8XFyr urs8WF1DGw1xWrJanT9S1TB71UUUUU7qnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2 9KBjDUYxBIdaVFxhVjvjDU0xZFpf9x0pi1E_tUUUUU= X-Originating-IP: [119.4.20.225] X-CM-SenderInfo: pglqw3tdrqkjqq6rljoofrz/xtbC-RbQD2pVD3ZllwAA3A Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=220.197.31.2; envelope-from=dingtao0430@163.com; helo=m16.mail.163.com X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 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, FREEMAIL_ENVFROM_END_DIGIT=0.25, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H2=-0.01, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, UNPARSEABLE_RELAY=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: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @163.com) X-ZM-MESSAGEID: 1783959713911158501 Content-Type: text/plain; charset="utf-8" Add a standalone qtest for the SDHCI controller on the xilinx-zynq-a9 machine. The test covers the SDMA boundary continuation case for a multi-block read. After the controller stops at a boundary, software updates SYSAD to continue the transfer. This verifies the generic SDHCI behavior that previously failed when the continuation SYSAD write was ignored and the transfer stalled. Reviewed-by: Bin Meng Signed-off-by: Tao Ding --- Build: mkdir build cd build ../configure --target-list=3D"arm-softmmu" --disable-slirp --enable-debu= g --disable-werror make -j4 Run: QTEST_QEMU_BINARY=3D./qemu-system-arm \ tests/qtest/xilinx-zynq-sdhci-test Before the fix, the test fails with a BLKCNT assertion: ERROR:../tests/qtest/xilinx-zynq-sdhci-test.c:90:wait_for_block_count:=20 assertion failed (qtest_readw(qts, XILINX_ZYNQ_MMC_BA + SDHC_BLKCNT) =3D= =3D expected): (1 =3D=3D 0) After applying the fix, the test passes: ok 1 /arm/xilinx-zynq-sdhci/sdma/read-boundary-continue tests/qtest/meson.build | 1 + tests/qtest/xilinx-zynq-sdhci-test.c | 178 +++++++++++++++++++++++++++ 2 files changed, 179 insertions(+) create mode 100644 tests/qtest/xilinx-zynq-sdhci-test.c diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build index 2ae720156f..c12a35721d 100644 --- a/tests/qtest/meson.build +++ b/tests/qtest/meson.build @@ -244,6 +244,7 @@ qtests_arm =3D \ config_all_devices.has_key('CONFIG_MUSICPAL') ? ['pflash-cfi02-test'] := []) + \ (config_all_devices.has_key('CONFIG_ASPEED_SOC') ? qtests_aspeed : []) += \ (config_all_devices.has_key('CONFIG_NPCM7XX') ? qtests_npcm7xx : []) + \ + (config_all_devices.has_key('CONFIG_ZYNQ') ? ['xilinx-zynq-sdhci-test'] = : []) + \ (config_all_devices.has_key('CONFIG_GENERIC_LOADER') ? ['hexloader-test'= ] : []) + \ (config_all_devices.has_key('CONFIG_TPM_TIS_I2C') ? ['tpm-tis-i2c-test',= 'tpm-tis-i2c-swtpm-test'] : []) + \ (config_all_devices.has_key('CONFIG_VEXPRESS') ? ['test-arm-mptimer'] : = []) + \ diff --git a/tests/qtest/xilinx-zynq-sdhci-test.c b/tests/qtest/xilinx-zynq= -sdhci-test.c new file mode 100644 index 0000000000..1be9bdabf7 --- /dev/null +++ b/tests/qtest/xilinx-zynq-sdhci-test.c @@ -0,0 +1,178 @@ +/* +* QTests for the Xilinx Zynq SDHCI controller. +* +* Copyright (c) 2026 Tao Ding +* +* SPDX-License-Identifier: GPL-2.0-or-later +*/ + +#include "qemu/osdep.h" +#include "hw/sd/sdhci.h" +#include "hw/sd/sdhci-internal.h" + +#include "libqtest.h" +#include "libqtest-single.h" +#include "libqos/sdhci-cmd.h" + +#define XILINX_ZYNQ_MMC_BA 0xE0100000 +#define XILINX_ZYNQ_BLK_SIZE 512 +#define XILINX_ZYNQ_TEST_IMAGE_SIZE (1 << 20) +#define XILINX_ZYNQ_SDMA_BOUNDARY_ARG 7 +#define XILINX_ZYNQ_SDMA_BOUNDARY_SIZE (512 * 1024) +#define XILINX_ZYNQ_SDMA_BLOCK_COUNT \ + ((XILINX_ZYNQ_SDMA_BOUNDARY_SIZE / XILINX_ZYNQ_BLK_SIZE) + 1) +#define XILINX_ZYNQ_SDMA_TRANSFER_SIZE \ + (XILINX_ZYNQ_SDMA_BLOCK_COUNT * XILINX_ZYNQ_BLK_SIZE) +#define XILINX_ZYNQ_DMA_ADDR 0x00100000 + +#define SDHC_MAKE_BLKSZ(boundary, size) (((boundary) << 12) | (size)) + +static char *sd_path; + +static QTestState *setup_sd_card(void) +{ + QTestState *qts; + uint16_t rca; + + qts =3D qtest_initf( + "-machine xilinx-zynq-a9 " + "-drive if=3Dsd,index=3D0,file=3D%s,format=3Draw,auto-read-only=3D= off", + sd_path); + + qtest_writew(qts, XILINX_ZYNQ_MMC_BA + SDHC_SWRST, SDHC_RESET_ALL); + qtest_writew(qts, XILINX_ZYNQ_MMC_BA + SDHC_CLKCON, + SDHC_CLOCK_SDCLK_EN | SDHC_CLOCK_INT_STABLE | + SDHC_CLOCK_INT_EN); + sdhci_cmd_regs(qts, XILINX_ZYNQ_MMC_BA, 0, 0, 0, 0, SDHC_APP_CMD); + sdhci_cmd_regs(qts, XILINX_ZYNQ_MMC_BA, 0, 0, 0x41200000, 0, + (41 << 8)); + sdhci_cmd_regs(qts, XILINX_ZYNQ_MMC_BA, 0, 0, 0, 0, SDHC_ALL_SEND_CID); + sdhci_cmd_regs(qts, XILINX_ZYNQ_MMC_BA, 0, 0, 0, 0, + SDHC_SEND_RELATIVE_ADDR | SDHC_CMD_RESPONSE); + rca =3D qtest_readl(qts, XILINX_ZYNQ_MMC_BA + SDHC_RSPREG0) >> 16; + sdhci_cmd_regs(qts, XILINX_ZYNQ_MMC_BA, 0, 0, rca << 16, 0, + SDHC_SELECT_DESELECT_CARD); + + return qts; +} + +static void write_pattern_to_image(size_t offset, size_t len) +{ + int fd; + int ret; + uint8_t *buf =3D g_malloc(len); + + for (size_t i =3D 0; i < len; i++) { + buf[i] =3D (i * 13 + 7) & 0xff; + } + + fd =3D open(sd_path, O_WRONLY); + g_assert_cmpint(fd, >=3D, 0); + ret =3D pwrite(fd, buf, len, offset); + close(fd); + g_assert_cmpint(ret, =3D=3D, len); + + g_free(buf); +} + +static void wait_for_block_count(QTestState *qts, uint16_t expected) +{ + int i; + + for (i =3D 0; i < 1000; i++) { + if (qtest_readw(qts, XILINX_ZYNQ_MMC_BA + SDHC_BLKCNT) =3D=3D expe= cted) { + return; + } + g_usleep(100); + } + + g_assert_cmpuint(qtest_readw(qts, XILINX_ZYNQ_MMC_BA + SDHC_BLKCNT), + =3D=3D, expected); +} + +/* + * SDMA stops at each boundary and requires software to update SYSAD + * to continue. The bug this test covers leaves DOING_READ/WRITE asserted, + * so the continuation SYSAD write is ignored and the transfer stalls. + */ +static void test_read_sdma_boundary_continue(void) +{ + QTestState *qts =3D setup_sd_card(); + uint8_t *actual =3D g_malloc0(XILINX_ZYNQ_SDMA_TRANSFER_SIZE); + uint8_t *expected =3D g_malloc(XILINX_ZYNQ_SDMA_TRANSFER_SIZE); + + write_pattern_to_image(0, XILINX_ZYNQ_SDMA_TRANSFER_SIZE); + + for (size_t i =3D 0; i < XILINX_ZYNQ_SDMA_TRANSFER_SIZE; i++) { + expected[i] =3D (i * 13 + 7) & 0xff; + } + + qtest_writel(qts, XILINX_ZYNQ_DMA_ADDR, 0xdeadbeef); + qtest_writel(qts, XILINX_ZYNQ_DMA_ADDR + XILINX_ZYNQ_SDMA_BOUNDARY_SIZ= E, + 0xcafef00d); + + qtest_writel(qts, XILINX_ZYNQ_MMC_BA + SDHC_SYSAD, XILINX_ZYNQ_DMA_ADD= R); + sdhci_cmd_regs(qts, XILINX_ZYNQ_MMC_BA, + SDHC_MAKE_BLKSZ(XILINX_ZYNQ_SDMA_BOUNDARY_ARG, + XILINX_ZYNQ_BLK_SIZE), + XILINX_ZYNQ_SDMA_BLOCK_COUNT, 0, + SDHC_TRNS_DMA | SDHC_TRNS_MULTI | SDHC_TRNS_READ | + SDHC_TRNS_BLK_CNT_EN, + SDHC_READ_MULTIPLE_BLOCK | SDHC_CMD_DATA_PRESENT); + + wait_for_block_count(qts, 1); + + qtest_writew(qts, XILINX_ZYNQ_MMC_BA + SDHC_NORINTSTS, 0xffff); + qtest_writel(qts, XILINX_ZYNQ_MMC_BA + SDHC_SYSAD, + XILINX_ZYNQ_DMA_ADDR + XILINX_ZYNQ_SDMA_BOUNDARY_SIZE); + + wait_for_block_count(qts, 0); + + qtest_memread(qts, XILINX_ZYNQ_DMA_ADDR, actual, + XILINX_ZYNQ_SDMA_TRANSFER_SIZE); + g_assert_cmpmem(actual, XILINX_ZYNQ_SDMA_TRANSFER_SIZE, + expected, XILINX_ZYNQ_SDMA_TRANSFER_SIZE); + + g_free(expected); + g_free(actual); + qtest_quit(qts); +} + +static void drive_destroy(void) +{ + unlink(sd_path); + g_free(sd_path); +} + +static void drive_create(void) +{ + int fd; + int ret; + GError *error =3D NULL; + + fd =3D g_file_open_tmp("xilinx-zynq-sdhci.XXXXXX", &sd_path, &error); + if (fd =3D=3D -1) { + fprintf(stderr, "unable to create sdhci file: %s\n", error->messag= e); + g_error_free(error); + } + g_assert_nonnull(sd_path); + + ret =3D ftruncate(fd, XILINX_ZYNQ_TEST_IMAGE_SIZE); + g_assert_cmpint(ret, =3D=3D, 0); + close(fd); +} + +int main(int argc, char **argv) +{ + int ret; + + drive_create(); + + g_test_init(&argc, &argv, NULL); + qtest_add_func("xilinx-zynq-sdhci/sdma/read-boundary-continue", + test_read_sdma_boundary_continue); + + ret =3D g_test_run(); + drive_destroy(); + return ret; +} --=20 2.43.0