From nobody Sat Apr 18 20:20:59 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=quarantine dis=none) header.from=avm.de ARC-Seal: i=1; a=rsa-sha256; t=1776419871; cv=none; d=zohomail.com; s=zohoarc; b=CVxcwEC2tLS4vj3OR2+0iewo/DnJGTLUcco1aTbxyNuyUgKphaPAe2HIEEZ4tQYGZdlrDMDARxaniNnhISLlkqUgU/464hlbnAoTZhRX6mfpUgnaszcFcX7vRmPtbZHjohfqDA9RlkQcMAXd9pAj/Wv7qmsmdAgez55wlkGvwm0= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1776419871; h=Content-Type: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=Rfs6SlfchO1eiqboHp94S4uD/7T1GVKj9ELXSHGcaDY=; b=jC1S0bN8tSl5TZAoxUaa8MiJeb/zDzYB1Sa2XMdXWW7dpRB4i21ye0uxGD1x5Tw3xGbP4euVF8izFDKTzWObeTQkUXGWqZEl/xwLAQYolgEBdmXxSUsASBjLvQvUjqumfTereGrg64eY40QOZM+T4b3FxnPBWSveL+WbtchKBO8= 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=quarantine dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1776419871031291.30868098894234; Fri, 17 Apr 2026 02:57:51 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wDfxJ-00038H-4N; Fri, 17 Apr 2026 05:57:46 -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 1wDfx9-0002jT-Di; Fri, 17 Apr 2026 05:57:35 -0400 Received: from mail.avm.de ([212.42.244.119]) by eggs.gnu.org with esmtps (TLS1.2:DHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wDfx5-0002zP-Ia; Fri, 17 Apr 2026 05:57:33 -0400 Received: from [172.16.0.1] (helo=mail.avm.de) by mail.avm.de with ESMTP (eXpurgate 4.55.2) (envelope-from ) id 69e20404-1e6c-7f0000032729-7f000001c504-1 for ; Fri, 17 Apr 2026 11:57:24 +0200 Received: from mail-notes.avm.de (mail-notes.avm.de [172.16.0.1]) by mail.avm.de (Postfix) with ESMTP; Fri, 17 Apr 2026 11:57:24 +0200 (CEST) Received: from [127.0.1.1] ([172.17.89.139]) by mail-notes.avm.de (HCL Domino Release 14.0FP4) with ESMTP id 2026041711572442-2974 ; Fri, 17 Apr 2026 11:57:24 +0200 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=avm.de; s=mail; t=1776419845; bh=SwBm8aaTR5UUQij4KU+WjH8fTCf9makjG0ZretA3JBo=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=QwA1n7zjK7ZHpeg314pX0qEd1vD4c8r5G+Id5QAATf0knC85GOBQXMBVWXgc0xbV5 IXLfMPryFXV3TCujcl+fe/5nVGfPptznPMfp/zPCdbAh2Iomm99w5tLWOEYq4rFDYc iEtDeX2oviaUD8AY27bjBzUe6SzNDYfiXvSavMmQ= From: Christian Speich Date: Fri, 17 Apr 2026 11:51:34 +0200 Subject: [PATCH v4 1/7] hw/sd: Switch read/write primitive to buf+len MIME-Version: 1.0 Message-Id: <20260417-sdcard-performance-b4-v4-1-119e66be10c2@avm.de> References: <20260417-sdcard-performance-b4-v4-0-119e66be10c2@avm.de> In-Reply-To: <20260417-sdcard-performance-b4-v4-0-119e66be10c2@avm.de> To: qemu-devel@nongnu.org Cc: =?utf-8?q?Philippe_Mathieu-Daud=C3=A9?= , Bin Meng , qemu-block@nongnu.org, Marcel Apfelbaum , Yanan Wang , Zhao Liu , Christian Speich X-Mailer: b4 0.14.2 X-MIMETrack: Itemize by SMTP Server on ANIS1/AVM(Release 14.0FP4|March 10, 2025) at 17.04.2026 11:57:24, Serialize by Router on ANIS1/AVM(Release 14.0FP4|March 10, 2025) at 17.04.2026 11:57:24, Serialize complete at 17.04.2026 11:57:24 X-TNEFEvaluated: 1 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" X-purgate-ID: 149429::1776419845-30F16233-6BA837FA/0/0 X-purgate-type: clean X-purgate-size: 10846 X-purgate-Ad: Categorized by eleven eXpurgate (R) https://www.eleven.de X-purgate: This mail is considered clean (visit https://www.eleven.de for further information) X-purgate: clean 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=212.42.244.119; envelope-from=c.speich@avm.de; helo=mail.avm.de X-Spam_score_int: -48 X-Spam_score: -4.9 X-Spam_bar: ---- X-Spam_report: (-4.9 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.54, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_MED=-2.3, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=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: 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 @avm.de) X-ZM-MESSAGEID: 1776419876286158500 Currently, read/writes are broken down into individual bytes which result in many function calls. This is quite bad for performance and since both the layer below and above work with larger buffers, it should be corrected. This patch is the first that switches the corresponding interface over to use a buf+len instead of a single byte. However, for most cases the implementation still only reads one byte and is then called again with the remaining buffer. Optimizations taking advantage of this new interface are to follow in the next commits. Signed-off-by: Christian Speich Reviewed-by: Philippe Mathieu-Daud=C3=A9 --- hw/sd/core.c | 26 ++++++++++++++--------- hw/sd/sd.c | 62 +++++++++++++++++++++++++++++++++++---------------= ---- include/hw/sd/sd.h | 22 +++++++++++++------ 3 files changed, 71 insertions(+), 39 deletions(-) diff --git a/hw/sd/core.c b/hw/sd/core.c index 3568a81e809fe107cfd0b5cc33b8b5761b11ce04..594c5e011ba30940a33799f9032= c92494ee0ca19 100644 --- a/hw/sd/core.c +++ b/hw/sd/core.c @@ -113,21 +113,24 @@ void sdbus_write_byte(SDBus *sdbus, uint8_t value) if (card) { SDCardClass *sc =3D SDMMC_COMMON_GET_CLASS(card); =20 - sc->write_byte(card, value); + sc->write_data(card, &value, 1); } } =20 void sdbus_write_data(SDBus *sdbus, const void *buf, size_t length) { SDState *card =3D get_card(sdbus); - const uint8_t *data =3D buf; =20 if (card) { SDCardClass *sc =3D SDMMC_COMMON_GET_CLASS(card); =20 - for (size_t i =3D 0; i < length; i++) { - trace_sdbus_write(sdbus_name(sdbus), data[i]); - sc->write_byte(card, data[i]); + while (length > 0) { + size_t written =3D sc->write_data(card, buf, length); + + g_assert(written >=3D 1); + + buf +=3D written; + length -=3D written; } } } @@ -140,7 +143,7 @@ uint8_t sdbus_read_byte(SDBus *sdbus) if (card) { SDCardClass *sc =3D SDMMC_COMMON_GET_CLASS(card); =20 - value =3D sc->read_byte(card); + sc->read_data(card, &value, 1); } trace_sdbus_read(sdbus_name(sdbus), value); =20 @@ -150,14 +153,17 @@ uint8_t sdbus_read_byte(SDBus *sdbus) void sdbus_read_data(SDBus *sdbus, void *buf, size_t length) { SDState *card =3D get_card(sdbus); - uint8_t *data =3D buf; =20 if (card) { SDCardClass *sc =3D SDMMC_COMMON_GET_CLASS(card); =20 - for (size_t i =3D 0; i < length; i++) { - data[i] =3D sc->read_byte(card); - trace_sdbus_read(sdbus_name(sdbus), data[i]); + while (length > 0) { + size_t read =3D sc->read_data(card, buf, length); + + g_assert(read >=3D 1); + + buf +=3D read; + length -=3D read; } } } diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 37f6e0702b0bce85915ef727ba1ec05f02f9c32c..135113add29b5ee3cb11d9d5353= 55eba8f6cb3f7 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -2638,30 +2638,37 @@ static bool sd_generic_read_byte(SDState *sd, uint8= _t *value) return false; } =20 -static void sd_write_byte(SDState *sd, uint8_t value) +static size_t sd_write_data(SDState *sd, const void *buf, size_t length) { unsigned int partition_access; int i; + const uint8_t *value =3D buf; =20 if (!sd->blk || !blk_is_inserted(sd->blk)) { - return; + return length; } =20 if (sd->state !=3D sd_receivingdata_state) { qemu_log_mask(LOG_GUEST_ERROR, "%s: not in Receiving-Data state\n", __func__); - return; + return length; } =20 if (sd->card_status & (ADDRESS_ERROR | WP_VIOLATION)) - return; + return length; + + /* + * Only read one byte at a time. We will be called again with the + * remaining. + */ + length =3D 1; =20 trace_sdcard_write_data(sd->proto->name, sd->last_cmd_name, - sd->current_cmd, sd->data_offset, value); + sd->current_cmd, sd->data_offset, value[0]); switch (sd->current_cmd) { case 24: /* CMD24: WRITE_SINGLE_BLOCK */ - if (sd_generic_write_byte(sd, value)) { + if (sd_generic_write_byte(sd, value[0])) { /* TODO: Check CRC before committing */ sd->state =3D sd_programming_state; sd_blk_write(sd, sd->data_start, sd->data_offset); @@ -2686,7 +2693,7 @@ static void sd_write_byte(SDState *sd, uint8_t value) } } } - sd->data[sd->data_offset++] =3D value; + sd->data[sd->data_offset++] =3D value[0]; if (sd->data_offset >=3D sd->blk_len) { /* TODO: Check CRC before committing */ sd->state =3D sd_programming_state; @@ -2716,7 +2723,7 @@ static void sd_write_byte(SDState *sd, uint8_t value) break; =20 case 26: /* CMD26: PROGRAM_CID */ - if (sd_generic_write_byte(sd, value)) { + if (sd_generic_write_byte(sd, value[0])) { /* TODO: Check CRC before committing */ sd->state =3D sd_programming_state; for (i =3D 0; i < sizeof(sd->cid); i ++) @@ -2734,7 +2741,7 @@ static void sd_write_byte(SDState *sd, uint8_t value) break; =20 case 27: /* CMD27: PROGRAM_CSD */ - if (sd_generic_write_byte(sd, value)) { + if (sd_generic_write_byte(sd, value[0])) { /* TODO: Check CRC before committing */ sd->state =3D sd_programming_state; for (i =3D 0; i < sizeof(sd->csd); i ++) @@ -2757,7 +2764,7 @@ static void sd_write_byte(SDState *sd, uint8_t value) break; =20 case 42: /* CMD42: LOCK_UNLOCK */ - if (sd_generic_write_byte(sd, value)) { + if (sd_generic_write_byte(sd, value[0])) { /* TODO: Check CRC before committing */ sd->state =3D sd_programming_state; sd_lock_command(sd); @@ -2767,36 +2774,47 @@ static void sd_write_byte(SDState *sd, uint8_t valu= e) break; =20 case 56: /* CMD56: GEN_CMD */ - sd_generic_write_byte(sd, value); + sd_generic_write_byte(sd, value[0]); break; =20 default: g_assert_not_reached(); } + + return length; } =20 -static uint8_t sd_read_byte(SDState *sd) +static size_t sd_read_data(SDState *sd, void *buf, size_t length) { /* TODO: Append CRCs */ const uint8_t dummy_byte =3D 0x00; unsigned int partition_access; - uint8_t ret; uint32_t io_len; + uint8_t *value =3D buf; =20 if (!sd->blk || !blk_is_inserted(sd->blk)) { - return dummy_byte; + memset(buf, dummy_byte, length); + return length; } =20 if (sd->state !=3D sd_sendingdata_state) { qemu_log_mask(LOG_GUEST_ERROR, "%s: not in Sending-Data state\n", __func__); - return dummy_byte; + memset(buf, dummy_byte, length); + return length; } =20 if (sd->card_status & (ADDRESS_ERROR | WP_VIOLATION)) { - return dummy_byte; + memset(buf, dummy_byte, length); + return length; } =20 + /* + * We will only read one byte at a time. We will be called again with = the + * remaining buffer. + */ + length =3D 1; + io_len =3D sd_blk_len(sd); =20 trace_sdcard_read_data(sd->proto->name, @@ -2814,7 +2832,7 @@ static uint8_t sd_read_byte(SDState *sd) case 30: /* CMD30: SEND_WRITE_PROT */ case 51: /* ACMD51: SEND_SCR */ case 56: /* CMD56: GEN_CMD */ - sd_generic_read_byte(sd, &ret); + sd_generic_read_byte(sd, value); break; =20 case 18: /* CMD18: READ_MULTIPLE_BLOCK */ @@ -2831,7 +2849,7 @@ static uint8_t sd_read_byte(SDState *sd) sd_blk_read(sd, sd->data_start, io_len); } } - ret =3D sd->data[sd->data_offset ++]; + *value =3D sd->data[sd->data_offset++]; =20 if (sd->data_offset >=3D io_len) { sd->data_start +=3D io_len; @@ -2850,10 +2868,10 @@ static uint8_t sd_read_byte(SDState *sd) default: qemu_log_mask(LOG_GUEST_ERROR, "%s: DAT read illegal for command %= s\n", __func__, sd->last_cmd_name); - return dummy_byte; + *value =3D dummy_byte; } =20 - return ret; + return length; } =20 static bool sd_receive_ready(SDState *sd) @@ -3173,8 +3191,8 @@ static void sdmmc_common_class_init(ObjectClass *klas= s, const void *data) sc->get_dat_lines =3D sd_get_dat_lines; sc->get_cmd_line =3D sd_get_cmd_line; sc->do_command =3D sd_do_command; - sc->write_byte =3D sd_write_byte; - sc->read_byte =3D sd_read_byte; + sc->write_data =3D sd_write_data; + sc->read_data =3D sd_read_data; sc->receive_ready =3D sd_receive_ready; sc->data_ready =3D sd_data_ready; sc->get_inserted =3D sd_get_inserted; diff --git a/include/hw/sd/sd.h b/include/hw/sd/sd.h index d12f24955a5ba3c1ba9ab851d75992e830c00608..2162fb584020110bcdaa7a92c2a= 05b6cfc041d2f 100644 --- a/include/hw/sd/sd.h +++ b/include/hw/sd/sd.h @@ -107,22 +107,30 @@ struct SDCardClass { size_t (*do_command)(SDState *sd, SDRequest *req, uint8_t *resp, size_t respsz); /** - * Write a byte to a SD card. + * Write data to a SD card. * @sd: card - * @value: byte to write + * @value: data to write + * @len: length of data * - * Write a byte on the data lines of a SD card. + * Write data on the data lines of a SD card. May write not all data, = in + * which case it should be called again. At least one byte must be con= sumed. + * + * Return: number of bytes actually written. >=3D 1 */ - void (*write_byte)(SDState *sd, uint8_t value); + size_t (*write_data)(SDState *sd, const void *buf, size_t len); /** * Read a byte from a SD card. * @sd: card + * @buf: buffer to receive the data + * @len: size of data to read * - * Read a byte from the data lines of a SD card. + * Read data from the data lines of a SD card. This may not read all + * requested data, in this case it should be called again with the rem= aining + * buffer. At least one byte must be read. * - * Return: byte value read + * Return: number of bytes actually read. >=3D 1 */ - uint8_t (*read_byte)(SDState *sd); + size_t (*read_data)(SDState *sd, void* buf, size_t len); bool (*receive_ready)(SDState *sd); bool (*data_ready)(SDState *sd); void (*set_voltage)(SDState *sd, uint16_t millivolts); --=20 2.43.0 From nobody Sat Apr 18 20:20:59 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=quarantine dis=none) header.from=avm.de ARC-Seal: i=1; a=rsa-sha256; t=1776419884; cv=none; d=zohomail.com; s=zohoarc; b=MpVKOQiDcj3CMNkZHUu2mwSePAP9rAmnq0+aSUNa9P1TGrEG4EKTn89Vahu99bvYyRMcLxQJn693PlWBoH5ztzuTJVB7U0QEdWWz9VeRUbph7UWBNf8lQzJzZ6p4jcRKKgkyZQ3TgAi0kyyeE9AM6QI2JhXF6ww5JvmpyWxfd3A= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1776419884; h=Content-Type: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=WVtXsCNpp8BULbIUqxP/bzRqd3ch9d6x0Am2nxTaaBs=; b=k+phAsttLJPMgYY3BGm9BnLNYOD0kJl37PeX5isCil3Zod//3l4XFRFGqMztS3xXqv2CQXIKG1h2dj4Mpn7y8aswIcGH9r1vNyJWmEuDvu81jIAj9Weplm+HOsAvwOYCqjeynCz1pYWxe3PbZJNHJzWLzULIS2U9P0zMdRwB6+4= 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=quarantine dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1776419884343171.6268886394422; Fri, 17 Apr 2026 02:58:04 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wDfxO-0003Ek-Ct; Fri, 17 Apr 2026 05:57:50 -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 1wDfx9-0002jW-I8; Fri, 17 Apr 2026 05:57:35 -0400 Received: from mail.avm.de ([212.42.244.119]) by eggs.gnu.org with esmtps (TLS1.2:DHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wDfx5-000302-HO; Fri, 17 Apr 2026 05:57:35 -0400 Received: from [172.16.0.1] (helo=mail.avm.de) by mail.avm.de with ESMTP (eXpurgate 4.55.2) (envelope-from ) id 69e20405-1e6c-7f0000032729-7f000001c518-1 for ; Fri, 17 Apr 2026 11:57:25 +0200 Received: from mail-notes.avm.de (mail-notes.avm.de [172.16.0.1]) by mail.avm.de (Postfix) with ESMTP; Fri, 17 Apr 2026 11:57:25 +0200 (CEST) Received: from [127.0.1.1] ([172.17.89.139]) by mail-notes.avm.de (HCL Domino Release 14.0FP4) with ESMTP id 2026041711572443-2975 ; Fri, 17 Apr 2026 11:57:24 +0200 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=avm.de; s=mail; t=1776419845; bh=hEncSpiJ83XFws/L5Xd2Q4V9lgBRfDDWRPUG5zSMWVU=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=E28HWfUHpE7UwXsF/9AJCkDWBgBQMTs2CFrv+Y79SGIPEBnx1twKaG+80LpmPQcCG VKRtrAz5GGEp6yvdveMg7qdAvej/86a8GBoWYkcIwJOo6Ixgj5xETcy0Oiy6ExlpQ8 3xG4GXoft2Fa1WD1V8sFtMbWSMQCealMpA6DaKvA= From: Christian Speich Date: Fri, 17 Apr 2026 11:51:35 +0200 Subject: [PATCH v4 2/7] hw/sd/sd: Allow multi-byte read/write for generic paths MIME-Version: 1.0 Message-Id: <20260417-sdcard-performance-b4-v4-2-119e66be10c2@avm.de> References: <20260417-sdcard-performance-b4-v4-0-119e66be10c2@avm.de> In-Reply-To: <20260417-sdcard-performance-b4-v4-0-119e66be10c2@avm.de> To: qemu-devel@nongnu.org Cc: =?utf-8?q?Philippe_Mathieu-Daud=C3=A9?= , Bin Meng , qemu-block@nongnu.org, Marcel Apfelbaum , Yanan Wang , Zhao Liu , Christian Speich X-Mailer: b4 0.14.2 X-MIMETrack: Itemize by SMTP Server on ANIS1/AVM(Release 14.0FP4|March 10, 2025) at 17.04.2026 11:57:24, Serialize by Router on ANIS1/AVM(Release 14.0FP4|March 10, 2025) at 17.04.2026 11:57:24, Serialize complete at 17.04.2026 11:57:24 X-TNEFEvaluated: 1 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" X-purgate-ID: 149429::1776419845-38707233-2F1C2574/0/0 X-purgate-type: clean X-purgate-size: 7064 X-purgate-Ad: Categorized by eleven eXpurgate (R) https://www.eleven.de X-purgate: This mail is considered clean (visit https://www.eleven.de for further information) X-purgate: clean 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=212.42.244.119; envelope-from=c.speich@avm.de; helo=mail.avm.de X-Spam_score_int: -48 X-Spam_score: -4.9 X-Spam_bar: ---- X-Spam_report: (-4.9 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.54, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_MED=-2.3, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=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: 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 @avm.de) X-ZM-MESSAGEID: 1776419885285158500 Paths that use sd_generic_write/read_data can now write/read multiple bytes with one call. Signed-off-by: Christian Speich Reviewed-by: Philippe Mathieu-Daud=C3=A9 --- hw/sd/sd.c | 62 +++++++++++++++++++++++++++++++++++-----------------------= ---- 1 file changed, 35 insertions(+), 27 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 135113add29b5ee3cb11d9d535355eba8f6cb3f7..2c81776df316feda75f97e15cc9= bbd1538f1a21c 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -1609,7 +1609,7 @@ static sd_rsp_type_t sd_cmd_optional(SDState *sd, SDR= equest req) return sd_illegal; } =20 -/* Configure fields for following sd_generic_write_byte() calls */ +/* Configure fields for following sd_generic_write_data() calls */ static sd_rsp_type_t sd_cmd_to_receivingdata(SDState *sd, SDRequest req, uint64_t start, size_t size) { @@ -1624,7 +1624,7 @@ static sd_rsp_type_t sd_cmd_to_receivingdata(SDState = *sd, SDRequest req, return sd_r1; } =20 -/* Configure fields for following sd_generic_read_byte() calls */ +/* Configure fields for following sd_generic_read_data() calls */ static sd_rsp_type_t sd_cmd_to_sendingdata(SDState *sd, SDRequest req, uint64_t start, const void *data, size_t size) @@ -2614,11 +2614,15 @@ send_response: } =20 /* Return true if buffer is consumed. Configured by sd_cmd_to_receivingdat= a() */ -static bool sd_generic_write_byte(SDState *sd, uint8_t value) +static bool sd_generic_write_data(SDState *sd, const void *buf, size_t *le= n) { - sd->data[sd->data_offset] =3D value; + size_t to_write =3D MIN(sd->data_size - sd->data_offset, *len); =20 - if (++sd->data_offset >=3D sd->data_size) { + memcpy(sd->data, buf, to_write); + sd->data_offset +=3D to_write; + *len =3D to_write; + + if (sd->data_offset >=3D sd->data_size) { sd->state =3D sd_transfer_state; return true; } @@ -2626,11 +2630,15 @@ static bool sd_generic_write_byte(SDState *sd, uint= 8_t value) } =20 /* Return true when buffer is consumed. Configured by sd_cmd_to_sendingdat= a() */ -static bool sd_generic_read_byte(SDState *sd, uint8_t *value) +static bool sd_generic_read_data(SDState *sd, void *buf, size_t *len) { - *value =3D sd->data[sd->data_offset]; + size_t to_read =3D MIN(sd->data_size - sd->data_offset, *len); + + memcpy(buf, sd->data, to_read); + sd->data_offset +=3D to_read; + *len =3D to_read; =20 - if (++sd->data_offset >=3D sd->data_size) { + if (sd->data_offset >=3D sd->data_size) { sd->state =3D sd_transfer_state; return true; } @@ -2657,18 +2665,12 @@ static size_t sd_write_data(SDState *sd, const void= *buf, size_t length) if (sd->card_status & (ADDRESS_ERROR | WP_VIOLATION)) return length; =20 - /* - * Only read one byte at a time. We will be called again with the - * remaining. - */ - length =3D 1; - trace_sdcard_write_data(sd->proto->name, sd->last_cmd_name, sd->current_cmd, sd->data_offset, value[0]); switch (sd->current_cmd) { case 24: /* CMD24: WRITE_SINGLE_BLOCK */ - if (sd_generic_write_byte(sd, value[0])) { + if (sd_generic_write_data(sd, buf, &length)) { /* TODO: Check CRC before committing */ sd->state =3D sd_programming_state; sd_blk_write(sd, sd->data_start, sd->data_offset); @@ -2680,6 +2682,12 @@ static size_t sd_write_data(SDState *sd, const void = *buf, size_t length) break; =20 case 25: /* CMD25: WRITE_MULTIPLE_BLOCK */ + /* + * Only read one byte at a time. We will be called again with the + * remaining. + */ + length =3D 1; + if (sd->data_offset =3D=3D 0) { /* Start of the block - let's check the address is valid */ if (!address_in_range(sd, "WRITE_MULTIPLE_BLOCK", @@ -2723,7 +2731,7 @@ static size_t sd_write_data(SDState *sd, const void *= buf, size_t length) break; =20 case 26: /* CMD26: PROGRAM_CID */ - if (sd_generic_write_byte(sd, value[0])) { + if (sd_generic_write_data(sd, buf, &length)) { /* TODO: Check CRC before committing */ sd->state =3D sd_programming_state; for (i =3D 0; i < sizeof(sd->cid); i ++) @@ -2741,7 +2749,7 @@ static size_t sd_write_data(SDState *sd, const void *= buf, size_t length) break; =20 case 27: /* CMD27: PROGRAM_CSD */ - if (sd_generic_write_byte(sd, value[0])) { + if (sd_generic_write_data(sd, buf, &length)) { /* TODO: Check CRC before committing */ sd->state =3D sd_programming_state; for (i =3D 0; i < sizeof(sd->csd); i ++) @@ -2764,7 +2772,7 @@ static size_t sd_write_data(SDState *sd, const void *= buf, size_t length) break; =20 case 42: /* CMD42: LOCK_UNLOCK */ - if (sd_generic_write_byte(sd, value[0])) { + if (sd_generic_write_data(sd, buf, &length)) { /* TODO: Check CRC before committing */ sd->state =3D sd_programming_state; sd_lock_command(sd); @@ -2774,7 +2782,7 @@ static size_t sd_write_data(SDState *sd, const void *= buf, size_t length) break; =20 case 56: /* CMD56: GEN_CMD */ - sd_generic_write_byte(sd, value[0]); + sd_generic_write_data(sd, buf, &length); break; =20 default: @@ -2809,12 +2817,6 @@ static size_t sd_read_data(SDState *sd, void *buf, s= ize_t length) return length; } =20 - /* - * We will only read one byte at a time. We will be called again with = the - * remaining buffer. - */ - length =3D 1; - io_len =3D sd_blk_len(sd); =20 trace_sdcard_read_data(sd->proto->name, @@ -2832,10 +2834,16 @@ static size_t sd_read_data(SDState *sd, void *buf, = size_t length) case 30: /* CMD30: SEND_WRITE_PROT */ case 51: /* ACMD51: SEND_SCR */ case 56: /* CMD56: GEN_CMD */ - sd_generic_read_byte(sd, value); + sd_generic_read_data(sd, buf, &length); break; =20 case 18: /* CMD18: READ_MULTIPLE_BLOCK */ + /* + * We will only read one byte at a time. We will be called again w= ith + * the remaining buffer. + */ + length =3D 1; + if (sd->data_offset =3D=3D 0) { if (!address_in_range(sd, "READ_MULTIPLE_BLOCK", sd->data_start, io_len)) { @@ -2868,7 +2876,7 @@ static size_t sd_read_data(SDState *sd, void *buf, si= ze_t length) default: qemu_log_mask(LOG_GUEST_ERROR, "%s: DAT read illegal for command %= s\n", __func__, sd->last_cmd_name); - *value =3D dummy_byte; + memset(buf, dummy_byte, length); } =20 return length; --=20 2.43.0 From nobody Sat Apr 18 20:20:59 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=quarantine dis=none) header.from=avm.de ARC-Seal: i=1; a=rsa-sha256; t=1776419944; cv=none; d=zohomail.com; s=zohoarc; b=bRp75GfxwZHAhFVfliMzaay113NjYqDGIhgr+r1BqYaXuDxKPeTCy2eYt47FzAPCOIWz+cWzwrAdLe0D2EwrL2AmOvwPc3TAVgX2p92Qi5jbz7DzTeBIpiVufwkhGLgw99bboIRgrUJZgLiAHVe36oqcUe3BXL/Yr4nPKuTkjyk= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1776419944; h=Content-Type: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=7V6O9fHtuPkYhGGZAG9yXHt8GoTwFECAUft6m4/G3R4=; b=HVKmpBlZe2s+EDQLIWEC8iHkof/GN7tnpcy2L1iIdnwOcZ0LfqkxdsR1YDCReuIzc1hBlDRqodDHn2pQQpI7a5dzCFFwnsm7gV2SWHIShxuJyuFLmFq7oUbItLnGvpa8JpFWUFendeZbUMFNJFHzmAJcpwhf9CNeitjx+jLrLFk= 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=quarantine dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1776419944243876.5421048443438; Fri, 17 Apr 2026 02:59:04 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wDfxH-00031t-4P; Fri, 17 Apr 2026 05:57:43 -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 1wDfx9-0002jp-Uj; Fri, 17 Apr 2026 05:57:35 -0400 Received: from mail.avm.de ([212.42.244.119]) by eggs.gnu.org with esmtps (TLS1.2:DHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wDfx5-00030T-HO; Fri, 17 Apr 2026 05:57:35 -0400 Received: from [172.16.0.1] (helo=mail.avm.de) by mail.avm.de with ESMTP (eXpurgate 4.55.2) (envelope-from ) id 69e20405-1e6c-7f0000032729-7f000001c51e-1 for ; Fri, 17 Apr 2026 11:57:25 +0200 Received: from mail-notes.avm.de (mail-notes.avm.de [172.16.0.1]) by mail.avm.de (Postfix) with ESMTP; Fri, 17 Apr 2026 11:57:25 +0200 (CEST) Received: from [127.0.1.1] ([172.17.89.139]) by mail-notes.avm.de (HCL Domino Release 14.0FP4) with ESMTP id 2026041711572443-2976 ; Fri, 17 Apr 2026 11:57:24 +0200 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=avm.de; s=mail; t=1776419845; bh=QoyvxQROiGbE6vAvJxaG+85jruxRTacuSs9YktkmEG0=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=OPKm0GxdEpwO+n7aXHamI33uktNSIId8uheR7V3/x/MCVl1IjvdFq85n1S1ChZs/c gBk5D1rjOAVORQGUdDDXoXEfUwPZvU066FU9OYQ91F2ZWPaCwGI42O13y7GfQ6mIo0 V2TwgMroMnWGDsXUXuy5qsEZOIL3LL0uZ7tcUino= From: Christian Speich Date: Fri, 17 Apr 2026 11:51:36 +0200 Subject: [PATCH v4 3/7] hw/sd/sd: Use multi-byte/block writes for block path MIME-Version: 1.0 Message-Id: <20260417-sdcard-performance-b4-v4-3-119e66be10c2@avm.de> References: <20260417-sdcard-performance-b4-v4-0-119e66be10c2@avm.de> In-Reply-To: <20260417-sdcard-performance-b4-v4-0-119e66be10c2@avm.de> To: qemu-devel@nongnu.org Cc: =?utf-8?q?Philippe_Mathieu-Daud=C3=A9?= , Bin Meng , qemu-block@nongnu.org, Marcel Apfelbaum , Yanan Wang , Zhao Liu , Christian Speich X-Mailer: b4 0.14.2 X-MIMETrack: Itemize by SMTP Server on ANIS1/AVM(Release 14.0FP4|March 10, 2025) at 17.04.2026 11:57:24, Serialize by Router on ANIS1/AVM(Release 14.0FP4|March 10, 2025) at 17.04.2026 11:57:25, Serialize complete at 17.04.2026 11:57:25 X-TNEFEvaluated: 1 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" X-purgate-ID: 149429::1776419845-4BF2C233-2AF0D54D/0/0 X-purgate-type: clean X-purgate-size: 12969 X-purgate-Ad: Categorized by eleven eXpurgate (R) https://www.eleven.de X-purgate: This mail is considered clean (visit https://www.eleven.de for further information) X-purgate: clean 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=212.42.244.119; envelope-from=c.speich@avm.de; helo=mail.avm.de X-Spam_score_int: -48 X-Spam_score: -4.9 X-Spam_bar: ---- X-Spam_report: (-4.9 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.54, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_MED=-2.3, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=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: 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 @avm.de) X-ZM-MESSAGEID: 1776419946224154100 When writing/reading blocks via WRITE/READ_MULTIPLE_BLOCK we try to directly pass this request down to the block layer. This can only be done for properly sized and aligned accesses, other access still use a bounce buffer but still benefit from copying as much data in one memcpy as possible. RPMB is limited to the slow path using a bounce buffer. Signed-off-by: Christian Speich --- hw/sd/sd.c | 228 ++++++++++++++++++++++++++++++++++++++++++++++-----------= ---- 1 file changed, 172 insertions(+), 56 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 2c81776df316feda75f97e15cc9bbd1538f1a21c..b27fed2e563e5971dd32787498e= b8abed9ffe9be 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -1112,24 +1112,36 @@ static const VMStateDescription sd_vmstate =3D { }, }; =20 -static void sd_blk_read(SDState *sd, uint64_t addr, uint32_t len) +static void sd_blk_read(SDState *sd, void* buf, uint64_t addr, + uint32_t len) { trace_sdcard_read_block(addr, len); addr +=3D sd_part_offset(sd); - if (!sd->blk || blk_pread(sd->blk, addr, len, sd->data, 0) < 0) { + if (!sd->blk || blk_pread(sd->blk, addr, len, buf, 0) < 0) { fprintf(stderr, "sd_blk_read: read error on host side\n"); } } =20 -static void sd_blk_write(SDState *sd, uint64_t addr, uint32_t len) +static void sd_blk_read_bounce_buffer(SDState *sd, uint64_t addr, uint32_t= len) +{ + sd_blk_read(sd, sd->data, addr, len); +} + +static void sd_blk_write(SDState *sd, const void *buf, uint64_t addr, + uint32_t len) { trace_sdcard_write_block(addr, len); addr +=3D sd_part_offset(sd); - if (!sd->blk || blk_pwrite(sd->blk, addr, len, sd->data, 0) < 0) { + if (!sd->blk || blk_pwrite(sd->blk, addr, len, buf, 0) < 0) { fprintf(stderr, "sd_blk_write: write error on host side\n"); } } =20 +static void sd_blk_write_bounce_buffer(SDState *sd, uint64_t addr, uint32_= t len) +{ + sd_blk_write(sd, sd->data, addr, len); +} + static bool rpmb_calc_hmac(SDState *sd, const RPMBDataFrame *frame, unsigned int num_blocks, uint8_t *mac) { @@ -1363,7 +1375,7 @@ static void sd_erase(SDState *sd) continue; } } - sd_blk_write(sd, erase_addr, erase_len); + sd_blk_write_bounce_buffer(sd, erase_addr, erase_len); } } =20 @@ -1984,7 +1996,7 @@ static sd_rsp_type_t sd_cmd_READ_SINGLE_BLOCK(SDState= *sd, SDRequest req) return sd_r1; } =20 - sd_blk_read(sd, addr, sd->blk_len); + sd_blk_read_bounce_buffer(sd, addr, sd->blk_len); return sd_cmd_to_sendingdata(sd, req, addr, NULL, sd->blk_len); } =20 @@ -2673,7 +2685,7 @@ static size_t sd_write_data(SDState *sd, const void *= buf, size_t length) if (sd_generic_write_data(sd, buf, &length)) { /* TODO: Check CRC before committing */ sd->state =3D sd_programming_state; - sd_blk_write(sd, sd->data_start, sd->data_offset); + sd_blk_write_bounce_buffer(sd, sd->data_start, sd->data_offset= ); sd->blk_written ++; sd->csd[14] |=3D 0x40; /* Bzzzzzzztt .... Operation complete. */ @@ -2682,44 +2694,85 @@ static size_t sd_write_data(SDState *sd, const void= *buf, size_t length) break; =20 case 25: /* CMD25: WRITE_MULTIPLE_BLOCK */ - /* - * Only read one byte at a time. We will be called again with the - * remaining. - */ - length =3D 1; - - if (sd->data_offset =3D=3D 0) { - /* Start of the block - let's check the address is valid */ - if (!address_in_range(sd, "WRITE_MULTIPLE_BLOCK", - sd->data_start, sd->blk_len)) { - break; + if (!address_in_range(sd, "WRITE_MULTIPLE_BLOCK", + sd->data_start + sd->data_offset, length)) { + /* Limit writing data to our device size */ + length =3D sd->size - sd->data_start - sd->data_offset; + + /* We've read past the end, return a dummy write. */ + if (length =3D=3D 0) { + return 1; } - if (sd->size <=3D SDSC_MAX_CAPACITY) { - if (sd_wp_addr(sd, sd->data_start)) { + } + + if (sd->size <=3D SDSC_MAX_CAPACITY) { + uint64_t start =3D sd->data_start + sd->data_offset; + + /* + * Check if any covered address violates WP. If so, limit our = write + * up to the allowed address. + */ + for (uint64_t addr =3D start; addr < start + length; + addr =3D ROUND_UP(addr + 1, WPGROUP_SIZE)) { + if (sd_wp_addr(sd, addr)) { sd->card_status |=3D WP_VIOLATION; + + length =3D addr - start - 1; break; } } } - sd->data[sd->data_offset++] =3D value[0]; - if (sd->data_offset >=3D sd->blk_len) { - /* TODO: Check CRC before committing */ - sd->state =3D sd_programming_state; - partition_access =3D sd->ext_csd[EXT_CSD_PART_CONFIG] - & EXT_CSD_PART_CONFIG_ACC_MASK; - if (partition_access =3D=3D EXT_CSD_PART_CONFIG_ACC_RPMB) { - emmc_rpmb_blk_write(sd, sd->data_start, sd->data_offset); - } else { - sd_blk_write(sd, sd->data_start, sd->data_offset); + + partition_access =3D sd->ext_csd[EXT_CSD_PART_CONFIG] + & EXT_CSD_PART_CONFIG_ACC_MASK; + + /* Partial write or RPMB (single block only for now) */ + if (sd->data_offset > 0 + || partition_access =3D=3D EXT_CSD_PART_CONFIG_ACC_RPMB) { + length =3D MIN(sd->blk_len - sd->data_offset, length); + + memcpy(sd->data + sd->data_offset, buf, length); + sd->data_offset +=3D length; + + if (sd->data_offset >=3D sd->blk_len) { + sd->state =3D sd_programming_state; + if (partition_access =3D=3D EXT_CSD_PART_CONFIG_ACC_RPMB) { + emmc_rpmb_blk_write(sd, sd->data_start, sd->data_offse= t); + } else { + sd_blk_write_bounce_buffer(sd, sd->data_start, + sd->data_offset); + } + sd->blk_written++; + sd->data_start +=3D sd->blk_len; + sd->data_offset =3D 0; + sd->csd[14] |=3D 0x40; + + /* Bzzzzzzztt .... Operation complete. */ + if (sd->multi_blk_cnt !=3D 0) { + if (--sd->multi_blk_cnt =3D=3D 0) { + /* Stop! */ + sd->state =3D sd_transfer_state; + break; + } + } + + sd->state =3D sd_receivingdata_state; } - sd->blk_written++; - sd->data_start +=3D sd->blk_len; - sd->data_offset =3D 0; + } + /* Try to write multiple of block sizes */ + else if (length >=3D sd->blk_len) { + length =3D QEMU_ALIGN_DOWN(length, sd->blk_len); + + sd->state =3D sd_programming_state; + sd_blk_write(sd, buf, sd->data_start, length); + sd->blk_written +=3D length / sd->blk_len; + sd->data_start +=3D length; sd->csd[14] |=3D 0x40; =20 - /* Bzzzzzzztt .... Operation complete. */ if (sd->multi_blk_cnt !=3D 0) { - if (--sd->multi_blk_cnt =3D=3D 0) { + sd->multi_blk_cnt -=3D length / sd->blk_len; + + if (sd->multi_blk_cnt =3D=3D 0) { /* Stop! */ sd->state =3D sd_transfer_state; break; @@ -2728,6 +2781,12 @@ static size_t sd_write_data(SDState *sd, const void = *buf, size_t length) =20 sd->state =3D sd_receivingdata_state; } + /* Partial write */ + else if (length > 0) { + memcpy(sd->data, buf, length); + sd->data_offset =3D length; + } + break; =20 case 26: /* CMD26: PROGRAM_CID */ @@ -2798,7 +2857,6 @@ static size_t sd_read_data(SDState *sd, void *buf, si= ze_t length) const uint8_t dummy_byte =3D 0x00; unsigned int partition_access; uint32_t io_len; - uint8_t *value =3D buf; =20 if (!sd->blk || !blk_is_inserted(sd->blk)) { memset(buf, dummy_byte, length); @@ -2838,36 +2896,94 @@ static size_t sd_read_data(SDState *sd, void *buf, = size_t length) break; =20 case 18: /* CMD18: READ_MULTIPLE_BLOCK */ + if (!address_in_range(sd, "READ_MULTIPLE_BLOCK", + sd->data_start + sd->data_offset, length)) { + /* Limit reading data to our device size */ + length =3D sd->size - sd->data_start - sd->data_offset; + + /* We read past the end, return a dummy read. */ + if (length =3D=3D 0) { + memset(buf, dummy_byte, 1); + return 1; + } + } + + partition_access =3D sd->ext_csd[EXT_CSD_PART_CONFIG] + & EXT_CSD_PART_CONFIG_ACC_MASK; + + /* We have a partially read block. */ + if (sd->data_offset > 0) { + length =3D MIN(sd->data_size - sd->data_offset, length); + + memcpy(buf, sd->data + sd->data_offset, length); + + sd->data_offset +=3D length; + + /* Partial read is complete, clear state. */ + if (sd->data_offset >=3D sd->data_size) { + sd->data_start +=3D io_len; + sd->data_size =3D 0; + sd->data_offset =3D 0; + + if (sd->multi_blk_cnt !=3D 0) { + if (--sd->multi_blk_cnt =3D=3D 0) { + sd->state =3D sd_transfer_state; + } + } + } + } /* - * We will only read one byte at a time. We will be called again w= ith - * the remaining buffer. + * Try to read multiples of the block size directly bypassing the = local + * bounce buffer. + * Not for RPMB. */ - length =3D 1; + else if (length >=3D io_len + && partition_access !=3D EXT_CSD_PART_CONFIG_ACC_RPMB) { + length =3D QEMU_ALIGN_DOWN(length, io_len); =20 - if (sd->data_offset =3D=3D 0) { - if (!address_in_range(sd, "READ_MULTIPLE_BLOCK", - sd->data_start, io_len)) { - return dummy_byte; + /* For limited reads, only read the requested block count. */ + if (sd->multi_blk_cnt !=3D 0) { + length =3D MIN(length, sd->multi_blk_cnt * io_len); } - partition_access =3D sd->ext_csd[EXT_CSD_PART_CONFIG] - & EXT_CSD_PART_CONFIG_ACC_MASK; + + sd_blk_read(sd, buf, sd->data_start, length); + + sd->data_start +=3D length; + + if (sd->multi_blk_cnt !=3D 0) { + sd->multi_blk_cnt -=3D length / io_len; + + if (sd->multi_blk_cnt =3D=3D 0) { + sd->state =3D sd_transfer_state; + } + } + } + /* Read partial at the end or sinlge-block RPMB */ + else if (length > 0) { + length =3D MIN(length, io_len); + + /* Fill the buffer */ if (partition_access =3D=3D EXT_CSD_PART_CONFIG_ACC_RPMB) { emmc_rpmb_blk_read(sd, sd->data_start, io_len); } else { - sd_blk_read(sd, sd->data_start, io_len); + sd_blk_read_bounce_buffer(sd, sd->data_start, io_len); } - } - *value =3D sd->data[sd->data_offset++]; =20 - if (sd->data_offset >=3D io_len) { - sd->data_start +=3D io_len; - sd->data_offset =3D 0; + memcpy(buf, sd->data, length); =20 - if (sd->multi_blk_cnt !=3D 0) { - if (--sd->multi_blk_cnt =3D=3D 0) { - /* Stop! */ - sd->state =3D sd_transfer_state; - break; + sd->data_size =3D io_len; + sd->data_offset =3D length; + + if (sd->data_offset >=3D io_len) { + sd->data_start +=3D io_len; + sd->data_offset =3D 0; + + if (sd->multi_blk_cnt !=3D 0) { + if (--sd->multi_blk_cnt =3D=3D 0) { + /* Stop! */ + sd->state =3D sd_transfer_state; + break; + } } } } --=20 2.43.0 From nobody Sat Apr 18 20:20:59 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=quarantine dis=none) header.from=avm.de ARC-Seal: i=1; a=rsa-sha256; t=1776419949; cv=none; d=zohomail.com; s=zohoarc; b=VlO6S2/vpdBVXeLiSmZcArmVqTmb18KhstQJZR13Zh2zOHLPWyTIzV7Kttatx+73DuLptoCU33ZGHGDu4SGbMiLM8ZaL26xy2IlKQOrRnTIbC/F8bVAXt12+2YWs0tpl7haooWnlD1NbFCur7DS8q6Udbsf1q/piF9UAmyUoHz4= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1776419949; h=Content-Type: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=ARDQXecSkIWKM2jW8b1XQhbvDhHeLHKbx6hiMjGlpD8=; b=Bma/9QjlL5AfJfH4jEsK8y2zW6+Ll817rcG8YY0SJzY+ZmkRmgDDPFzKxfuSCqD/GB9NeBY8Y5Lt780J2v+fY2cLrtN1uit/jtqdUZik+QVDcXx/rRv6VzVckQDGJAmpSI2pOvZMyXpk/jr+9D/ZtaDhLB/jYYEowHtAGRIM/7Q= 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=quarantine dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1776419948994374.5060021759773; Fri, 17 Apr 2026 02:59:08 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wDfxF-0002zn-Tr; Fri, 17 Apr 2026 05:57:42 -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 1wDfxB-0002pw-Qu; Fri, 17 Apr 2026 05:57:37 -0400 Received: from mail.avm.de ([2001:bf0:244:244::119]) by eggs.gnu.org with esmtps (TLS1.2:DHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wDfx9-000387-Gb; Fri, 17 Apr 2026 05:57:37 -0400 Received: from [172.16.0.1] (helo=mail.avm.de) by mail.avm.de with ESMTP (eXpurgate 4.55.2) (envelope-from ) id 69e20406-1e6c-7f0000032729-7f000001b2e8-1 for ; Fri, 17 Apr 2026 11:57:26 +0200 Received: from mail-notes.avm.de (mail-notes.avm.de [172.16.0.1]) by mail.avm.de (Postfix) with ESMTP; Fri, 17 Apr 2026 11:57:26 +0200 (CEST) Received: from [127.0.1.1] ([172.17.89.139]) by mail-notes.avm.de (HCL Domino Release 14.0FP4) with ESMTP id 2026041711572444-2977 ; Fri, 17 Apr 2026 11:57:24 +0200 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=avm.de; s=mail; t=1776419846; bh=q4twjt2E4pRsujRgtku8JrJOS12+2byH1d3KqcJv0Gs=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=nPXTiVnF2AK6Ttv8AoR1MwnTHSiIYhlXGM4JBKlgYBxOmn0oGotNRrHG1okQcR40x m/naXhu8wUZXHOYyF0JYwIqIhnYV+wvLE2RBQ1t6+UnVU2sD4/cgxOmIPmwh7TaC2h BK6oQd+SVbLHO7iHzXoUqvNNioNqPlSEsZz64PS4= From: Christian Speich Date: Fri, 17 Apr 2026 11:51:37 +0200 Subject: [PATCH v4 4/7] hw/sd/sdhci: Don't use bounce buffer for ADMA MIME-Version: 1.0 Message-Id: <20260417-sdcard-performance-b4-v4-4-119e66be10c2@avm.de> References: <20260417-sdcard-performance-b4-v4-0-119e66be10c2@avm.de> In-Reply-To: <20260417-sdcard-performance-b4-v4-0-119e66be10c2@avm.de> To: qemu-devel@nongnu.org Cc: =?utf-8?q?Philippe_Mathieu-Daud=C3=A9?= , Bin Meng , qemu-block@nongnu.org, Marcel Apfelbaum , Yanan Wang , Zhao Liu , Christian Speich X-Mailer: b4 0.14.2 X-MIMETrack: Itemize by SMTP Server on ANIS1/AVM(Release 14.0FP4|March 10, 2025) at 17.04.2026 11:57:24, Serialize by Router on ANIS1/AVM(Release 14.0FP4|March 10, 2025) at 17.04.2026 11:57:26, Serialize complete at 17.04.2026 11:57:26 X-TNEFEvaluated: 1 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" X-purgate-ID: 149429::1776419846-34F1E373-3203CE97/0/0 X-purgate-type: clean X-purgate-size: 6515 X-purgate-Ad: Categorized by eleven eXpurgate (R) https://www.eleven.de X-purgate: This mail is considered clean (visit https://www.eleven.de for further information) X-purgate: clean 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=2001:bf0:244:244::119; envelope-from=c.speich@avm.de; helo=mail.avm.de X-Spam_score_int: -25 X-Spam_score: -2.6 X-Spam_bar: -- X-Spam_report: (-2.6 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.54, 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: 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 @avm.de) X-ZM-MESSAGEID: 1776419952313154100 Currently, ADMA will temporarily store data into a local bounce buffer when transferring it. This will produce unneeded copies of the data and limit us to the bounce buffer size for each step. This patch now maps the requested DMA address and passes this buffer directly to sdbus_{read,write}_data. This allows to pass much larger buffers down to increase the performance. sdbus_{read,write}_data is already able to handle arbitrary length and alignments, so we do not need to ensure this. Signed-off-by: Christian Speich Reviewed-by: Philippe Mathieu-Daud=C3=A9 --- hw/sd/sdhci.c | 102 +++++++++++++++++++++++++++++++-----------------------= ---- 1 file changed, 55 insertions(+), 47 deletions(-) diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c index c86dfa281f4b0218bf6dda7a38d46abfc9638450..6e07711478cb6ca046a7d371a82= e2c682ebbda00 100644 --- a/hw/sd/sdhci.c +++ b/hw/sd/sdhci.c @@ -775,7 +775,7 @@ static void get_adma_description(SDHCIState *s, ADMADes= cr *dscr) =20 static void sdhci_do_adma(SDHCIState *s) { - unsigned int begin, length; + unsigned int length; const uint16_t block_size =3D s->blksize & BLOCK_SIZE_MASK; const MemTxAttrs attrs =3D { .memory =3D true }; ADMADescr dscr =3D {}; @@ -817,66 +817,74 @@ static void sdhci_do_adma(SDHCIState *s) if (s->trnmod & SDHC_TRNS_READ) { s->prnsts |=3D SDHC_DOING_READ; while (length) { - if (s->data_count =3D=3D 0) { - sdbus_read_data(&s->sdbus, s->fifo_buffer, block_s= ize); - } - begin =3D s->data_count; - if ((length + begin) < block_size) { - s->data_count =3D length + begin; - length =3D 0; - } else { - s->data_count =3D block_size; - length -=3D block_size - begin; - } - res =3D dma_memory_write(s->dma_as, dscr.addr, - &s->fifo_buffer[begin], - s->data_count - begin, - attrs); - if (res !=3D MEMTX_OK) { + dma_addr_t dma_len =3D length; + + void *buf =3D dma_memory_map(s->dma_as, dscr.addr, &dm= a_len, + DMA_DIRECTION_FROM_DEVICE, + attrs); + + if (buf =3D=3D NULL) { + res =3D MEMTX_ERROR; break; + } else { + res =3D MEMTX_OK; } - dscr.addr +=3D s->data_count - begin; - if (s->data_count =3D=3D block_size) { - s->data_count =3D 0; - if (s->trnmod & SDHC_TRNS_BLK_CNT_EN) { - s->blkcnt--; - if (s->blkcnt =3D=3D 0) { - break; - } + + sdbus_read_data(&s->sdbus, buf, dma_len); + length -=3D dma_len; + dscr.addr +=3D dma_len; + + dma_memory_unmap(s->dma_as, buf, dma_len, + DMA_DIRECTION_FROM_DEVICE, dma_len); + + if (s->trnmod & SDHC_TRNS_BLK_CNT_EN) { + size_t transfered =3D s->data_count + dma_len; + + s->blkcnt -=3D transfered / block_size; + s->data_count =3D transfered % block_size; + + if (s->blkcnt =3D=3D 0) { + s->data_count =3D 0; + break; } } } } else { s->prnsts |=3D SDHC_DOING_WRITE; while (length) { - begin =3D s->data_count; - if ((length + begin) < block_size) { - s->data_count =3D length + begin; - length =3D 0; - } else { - s->data_count =3D block_size; - length -=3D block_size - begin; - } - res =3D dma_memory_read(s->dma_as, dscr.addr, - &s->fifo_buffer[begin], - s->data_count - begin, - attrs); - if (res !=3D MEMTX_OK) { + dma_addr_t dma_len =3D length; + + void *buf =3D dma_memory_map(s->dma_as, dscr.addr, &dm= a_len, + DMA_DIRECTION_TO_DEVICE, at= trs); + + if (buf =3D=3D NULL) { + res =3D MEMTX_ERROR; break; + } else { + res =3D MEMTX_OK; } - dscr.addr +=3D s->data_count - begin; - if (s->data_count =3D=3D block_size) { - sdbus_write_data(&s->sdbus, s->fifo_buffer, block_= size); - s->data_count =3D 0; - if (s->trnmod & SDHC_TRNS_BLK_CNT_EN) { - s->blkcnt--; - if (s->blkcnt =3D=3D 0) { - break; - } + + sdbus_write_data(&s->sdbus, buf, dma_len); + length -=3D dma_len; + dscr.addr +=3D dma_len; + + dma_memory_unmap(s->dma_as, buf, dma_len, + DMA_DIRECTION_TO_DEVICE, dma_len); + + if (s->trnmod & SDHC_TRNS_BLK_CNT_EN) { + size_t transfered =3D s->data_count + dma_len; + + s->blkcnt -=3D transfered / block_size; + s->data_count =3D transfered % block_size; + + if (s->blkcnt =3D=3D 0) { + s->data_count =3D 0; + break; } } } } + if (res !=3D MEMTX_OK) { s->data_count =3D 0; if (s->errintstsen & SDHC_EISEN_ADMAERR) { --=20 2.43.0 From nobody Sat Apr 18 20:20:59 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=quarantine dis=none) header.from=avm.de ARC-Seal: i=1; a=rsa-sha256; t=1776419926; cv=none; d=zohomail.com; s=zohoarc; b=k4RXWk0Uuo/aNF96uNWgqOF1clYu/KxBDpwOJFa9bdFRsX+wf1GYvCSVOrEgM+RXEspw7hYE78RiFc6ey+/y+VYrsFrQByli1WWfFXeg/DuyufwJEcsZTp9081gjIcQ1wlJIlWew/ex7r/0dkOBKM81CdPP3cI51Il8Ey/qdBZo= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1776419926; h=Content-Type: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=S8WjG+j8l6vjfEvidGEV9uwvnbh2PS8Xq3jG8PgHz3A=; b=mdldZV+K3V5XgzXe0tnL/IrlrIWnxZBs7F9lT3PuT8D+XC/SdbPCn3TZZRqgeVsXUYoKwl6R3+UaWv62LjpGfWwDVhSHr+EQu8dKQeU2il4NfcaJbLR7r/Ww5pt+6HltJ1Pg4uVh/7e9QHq50ggi4hfIua36arr0Pvl/j1Qp4X4= 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=quarantine dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1776419926383349.9151682564923; Fri, 17 Apr 2026 02:58:46 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wDfxF-0002yV-LV; Fri, 17 Apr 2026 05:57:41 -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 1wDfx9-0002jV-GU; Fri, 17 Apr 2026 05:57:35 -0400 Received: from mail.avm.de ([212.42.244.119]) by eggs.gnu.org with esmtps (TLS1.2:DHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wDfx5-00030z-Ib; Fri, 17 Apr 2026 05:57:35 -0400 Received: from [172.16.0.1] (helo=mail.avm.de) by mail.avm.de with ESMTP (eXpurgate 4.55.2) (envelope-from ) id 69e20405-1e6c-7f0000032729-7f000001c526-1 for ; Fri, 17 Apr 2026 11:57:25 +0200 Received: from mail-notes.avm.de (mail-notes.avm.de [172.16.0.1]) by mail.avm.de (Postfix) with ESMTP; Fri, 17 Apr 2026 11:57:25 +0200 (CEST) Received: from [127.0.1.1] ([172.17.89.139]) by mail-notes.avm.de (HCL Domino Release 14.0FP4) with ESMTP id 2026041711572445-2978 ; Fri, 17 Apr 2026 11:57:24 +0200 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=avm.de; s=mail; t=1776419845; bh=+0mmvb50jR9kZ68HQ7CQk2Labu3feNtqqLeBytUExT4=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=Wm5S1lahyJKP7HKLqYguJ7D6Zz6CAGwNNWjCkBRcWjyxGud4t5IXB82DvtUsRS5Kj iUxeSLj1w8nS+vZZ0320iuke8swQhf40hnsNudCks79TaBpRvk8TZ8ACEF+AEHzQMq zcNT75yN50mxfEf12/qe2cZ3YvKtrIzRX63gs/0U= From: Christian Speich Date: Fri, 17 Apr 2026 11:51:38 +0200 Subject: [PATCH v4 5/7] hw/sd/sdcard: Add erase-blocks-as-zero option. MIME-Version: 1.0 Message-Id: <20260417-sdcard-performance-b4-v4-5-119e66be10c2@avm.de> References: <20260417-sdcard-performance-b4-v4-0-119e66be10c2@avm.de> In-Reply-To: <20260417-sdcard-performance-b4-v4-0-119e66be10c2@avm.de> To: qemu-devel@nongnu.org Cc: =?utf-8?q?Philippe_Mathieu-Daud=C3=A9?= , Bin Meng , qemu-block@nongnu.org, Marcel Apfelbaum , Yanan Wang , Zhao Liu , Christian Speich X-Mailer: b4 0.14.2 X-MIMETrack: Itemize by SMTP Server on ANIS1/AVM(Release 14.0FP4|March 10, 2025) at 17.04.2026 11:57:24, Serialize by Router on ANIS1/AVM(Release 14.0FP4|March 10, 2025) at 17.04.2026 11:57:25, Serialize complete at 17.04.2026 11:57:25 X-TNEFEvaluated: 1 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" X-purgate-ID: 149429::1776419845-22F7A373-09464F27/0/0 X-purgate-type: clean X-purgate-size: 3423 X-purgate-Ad: Categorized by eleven eXpurgate (R) https://www.eleven.de X-purgate: This mail is considered clean (visit https://www.eleven.de for further information) X-purgate: clean 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=212.42.244.119; envelope-from=c.speich@avm.de; helo=mail.avm.de X-Spam_score_int: -48 X-Spam_score: -4.9 X-Spam_bar: ---- X-Spam_report: (-4.9 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.54, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_MED=-2.3, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=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: 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 @avm.de) X-ZM-MESSAGEID: 1776419927768158500 Currently, erased blocks are filled with 0xFF. However SCR Bit 55 (DATA_STAT_AFTER_ERASE) indicates that an erase produces zeros. One of them is wrong. This patch does two things. First it fixes the reporting of DATA_STAT_AFTER_ERASE in SCR to correctly reflect the content of erased blocks. We also increase the Product Revision (REV in CID) to indicate to the guest that DATA_STAT_AFTER_ERASE is now reliable. Secondly, we introduce a erase-blocks-as-zero option, which allows the user to choose if erased blocks should contain 0xFF or 0x00. The default is still 0xFF to remain compatible with current users. Signed-off-by: Christian Speich Reviewed-by: Philippe Mathieu-Daud=C3=A9 --- hw/core/machine.c | 5 +++++ hw/sd/sd.c | 15 +++++++++++++-- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/hw/core/machine.c b/hw/core/machine.c index 0aa77a57e956693208d77fea6af5853ed4904234..54e4c05c96e3cf35ab2e702ee81= fba36457cadd7 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -38,6 +38,11 @@ #include "hw/acpi/generic_event_device.h" #include "qemu/audio.h" =20 +GlobalProperty hw_compat_11_0[] =3D { + { "sdmmc-common", "erase-blocks-as-zero", "false" }, +}; +const size_t hw_compat_11_0_len =3D G_N_ELEMENTS(hw_compat_11_0); + GlobalProperty hw_compat_10_2[] =3D { { "scsi-block", "migrate-pr", "off" }, { "isa-cirrus-vga", "global-vmstate", "true" }, diff --git a/hw/sd/sd.c b/hw/sd/sd.c index b27fed2e563e5971dd32787498eb8abed9ffe9be..0f997ed8cc80e38645101cb8f47= c86f1c30d5a25 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -162,6 +162,7 @@ struct SDState { /* Static properties */ =20 uint8_t spec_version; + bool erase_blocks_as_zero; uint64_t boot_part_size; uint64_t rpmb_part_size; BlockBackend *blk; @@ -439,6 +440,9 @@ static void sd_set_scr(SDState *sd) sd->scr[0] |=3D 2; /* Spec Version 2.00 or Version 3.0X */ sd->scr[1] =3D (2 << 4) /* SDSC Card (Security Version 1.01) */ | 0b0101; /* 1-bit or 4-bit width bus modes */ + if (!sd->erase_blocks_as_zero) { + sd->scr[1] |=3D (1 << 7); /* DATA_STAT_AFTER_ERASE: Erase produces= 0xFF */ + } sd->scr[2] =3D 0x00; /* Extended Security is not supported. */ if (sd->spec_version >=3D SD_PHY_SPECv3_01_VERS) { sd->scr[2] |=3D 1 << 7; /* Spec Version 3.0X */ @@ -456,7 +460,7 @@ static void sd_set_scr(SDState *sd) #define MID 0xaa #define OID "XY" #define PNM "QEMU!" -#define PRV 0x01 +#define PRV 0x02 #define MDT_YR 2006 #define MDT_MON 2 =20 @@ -1363,7 +1367,12 @@ static void sd_erase(SDState *sd) sd->erase_end =3D INVALID_ADDRESS; sd->csd[14] |=3D 0x40; =20 - memset(sd->data, 0xff, erase_len); + if (sd->erase_blocks_as_zero) { + memset(sd->data, 0x0, erase_len); + } else { + memset(sd->data, 0xFF, erase_len); + } + for (erase_addr =3D erase_start; erase_addr <=3D erase_end; erase_addr +=3D erase_len) { if (sdsc) { @@ -3287,6 +3296,8 @@ static void emmc_realize(DeviceState *dev, Error **er= rp) =20 static const Property sdmmc_common_properties[] =3D { DEFINE_PROP_DRIVE("drive", SDState, blk), + DEFINE_PROP_BOOL("erase-blocks-as-zero", SDState, erase_blocks_as_zero, + true), }; =20 static const Property sd_properties[] =3D { --=20 2.43.0 From nobody Sat Apr 18 20:20:59 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=quarantine dis=none) header.from=avm.de ARC-Seal: i=1; a=rsa-sha256; t=1776419899; cv=none; d=zohomail.com; s=zohoarc; b=dlo+hDwHjOoxsFfC5HDfZj83UdjfV4oKjQmCG0A8bCmVBDWjEgxLK98R2EJAAohkl9wVgEUz2JjYwBm/PltBLTeBGCwTRWWgbV89Gzlqi3Ip9OiQAarcZoDZcs/zKqtwLk4xm2mTCqP/99JXIv4mpkHoltLuymMDvEFsjYn2Jco= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1776419899; h=Content-Type: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=qVrx1MF6ZDYeLdfVpt48Hnz6CzyFkNIDUnn9T2GjS5U=; b=ZY+Q95TBk7Gk+4DaLKXzZ4qVH1eouFdna0BpP+72J7o7zn5MI1w8+itsqnc1DAmFLqIZukG3rfcKf3GTYBYOiVzufEbo7tj6NSYlhQAOc5uiqHAMeN8GCzolLoGqbSJkc8a2bFNdU5JUzWYRrbqncWKrBF9kZ59w0f7Ge26cI5s= 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=quarantine dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1776419899123139.47053298626656; Fri, 17 Apr 2026 02:58:19 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wDfxf-0003Ku-Fg; Fri, 17 Apr 2026 05:58:09 -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 1wDfxB-0002pp-OO; Fri, 17 Apr 2026 05:57:37 -0400 Received: from mail.avm.de ([2001:bf0:244:244::119]) by eggs.gnu.org with esmtps (TLS1.2:DHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wDfx9-000389-GR; Fri, 17 Apr 2026 05:57:36 -0400 Received: from [172.16.0.1] (helo=mail.avm.de) by mail.avm.de with ESMTP (eXpurgate 4.55.2) (envelope-from ) id 69e20406-1e6c-7f0000032729-7f000001b2c4-1 for ; Fri, 17 Apr 2026 11:57:26 +0200 Received: from mail-notes.avm.de (mail-notes.avm.de [172.16.0.1]) by mail.avm.de (Postfix) with ESMTP; Fri, 17 Apr 2026 11:57:26 +0200 (CEST) Received: from [127.0.1.1] ([172.17.89.139]) by mail-notes.avm.de (HCL Domino Release 14.0FP4) with ESMTP id 2026041711572445-2979 ; Fri, 17 Apr 2026 11:57:24 +0200 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=avm.de; s=mail; t=1776419846; bh=5SYH+A8NyAGbb6vSKm8RhEoSuVLKy93+R7omElZI8D4=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=ZK9i54fox3XJjwgzlj4oZZGMT+xviuIjKa+l5O2HvQKizvFaHch20mI7QrWVrhR7G XkISUDdCmBiW5aQYukofDLW5d5bDLo6CdBz0ziQDpBt5zdHrQrhKqSLoPkHIIqdZfQ ooHJafZY5mXIDPjh+dBlIRsOKJRQ6aNcYzQ+yBrk= From: Christian Speich Date: Fri, 17 Apr 2026 11:51:39 +0200 Subject: [PATCH v4 6/7] hw/sd/sdcard: Optimize erase blocks as zero. MIME-Version: 1.0 Message-Id: <20260417-sdcard-performance-b4-v4-6-119e66be10c2@avm.de> References: <20260417-sdcard-performance-b4-v4-0-119e66be10c2@avm.de> In-Reply-To: <20260417-sdcard-performance-b4-v4-0-119e66be10c2@avm.de> To: qemu-devel@nongnu.org Cc: =?utf-8?q?Philippe_Mathieu-Daud=C3=A9?= , Bin Meng , qemu-block@nongnu.org, Marcel Apfelbaum , Yanan Wang , Zhao Liu , Christian Speich X-Mailer: b4 0.14.2 X-MIMETrack: Itemize by SMTP Server on ANIS1/AVM(Release 14.0FP4|March 10, 2025) at 17.04.2026 11:57:24, Serialize by Router on ANIS1/AVM(Release 14.0FP4|March 10, 2025) at 17.04.2026 11:57:26, Serialize complete at 17.04.2026 11:57:26 X-TNEFEvaluated: 1 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" X-purgate-ID: 149429::1776419846-50F26373-590759AA/0/0 X-purgate-type: clean X-purgate-size: 3267 X-purgate-Ad: Categorized by eleven eXpurgate (R) https://www.eleven.de X-purgate: This mail is considered clean (visit https://www.eleven.de for further information) X-purgate: clean 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=2001:bf0:244:244::119; envelope-from=c.speich@avm.de; helo=mail.avm.de X-Spam_score_int: -25 X-Spam_score: -2.6 X-Spam_bar: -- X-Spam_report: (-2.6 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.54, 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: 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 @avm.de) X-ZM-MESSAGEID: 1776419902401154100 When erasing blocks as zero, we can use optimized block functions to achieve this. These allow us to request a large rage to be zeroed, possible optimizing this operation and freeing disk space for sparsesly stored images. This only is possible when erase-blocks-as-zero=3Dtrue is used and can provide a significant performance boost. The case where 0xFF is used during erase is as slow as before. Signed-off-by: Christian Speich --- hw/sd/sd.c | 43 +++++++++++++++++++++++++++++++++---------- 1 file changed, 33 insertions(+), 10 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 0f997ed8cc80e38645101cb8f47c86f1c30d5a25..d1ff9badb39b699ce734a533cce= bfab894958d2d 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -1331,6 +1331,26 @@ exit: trace_sdcard_rpmb_write_block(req, lduw_be_p(&sd->rpmb.result.result)); } =20 +/* Requires sd->buf to be filled with 0xFF */ +static void sd_erase_ff(SDState *sd, uint64_t addr, size_t len) +{ + int erase_len =3D 1 << HWBLOCK_SHIFT; + uint64_t erase_addr; + + for (erase_addr =3D addr; erase_addr < addr + len; erase_addr +=3D era= se_len) { + sd_blk_write_bounce_buffer(sd, erase_addr, erase_len); + } +} + +static void sd_blk_erase(SDState *sd, uint64_t addr, size_t len) +{ + if (sd->erase_blocks_as_zero) { + blk_pwrite_zeroes(sd->blk, addr + sd_part_offset(sd), len, 0); + } else { + sd_erase_ff(sd, addr, len); + } +} + static void sd_erase(SDState *sd) { uint64_t erase_start =3D sd->erase_start; @@ -1338,7 +1358,6 @@ static void sd_erase(SDState *sd) bool sdsc =3D true; uint64_t wpnum; uint64_t erase_addr; - int erase_len =3D 1 << HWBLOCK_SHIFT; =20 trace_sdcard_erase(sd->erase_start, sd->erase_end); if (sd->erase_start =3D=3D INVALID_ADDRESS @@ -1367,24 +1386,28 @@ static void sd_erase(SDState *sd) sd->erase_end =3D INVALID_ADDRESS; sd->csd[14] |=3D 0x40; =20 - if (sd->erase_blocks_as_zero) { - memset(sd->data, 0x0, erase_len); - } else { - memset(sd->data, 0xFF, erase_len); + if (!sd->erase_blocks_as_zero) { + memset(sd->data, 0xFF, 1 << HWBLOCK_SHIFT); } =20 - for (erase_addr =3D erase_start; erase_addr <=3D erase_end; - erase_addr +=3D erase_len) { - if (sdsc) { - /* Only SDSC cards support write protect groups */ + /* Only SDSC cards support write protect groups */ + if (sdsc) { + for (erase_addr =3D erase_start; erase_addr <=3D erase_end; + erase_addr =3D ROUND_UP(erase_addr + 1, WPGROUP_SIZE)) { + uint64_t wp_group_end =3D ROUND_UP(erase_addr + 1, WPGROUP_SIZ= E) - 1; + size_t erase_len =3D MIN(erase_end, wp_group_end) - erase_addr; + wpnum =3D sd_addr_to_wpnum(erase_addr); assert(wpnum < sd->wp_group_bits); if (test_bit(wpnum, sd->wp_group_bmap)) { sd->card_status |=3D WP_ERASE_SKIP; continue; } + + sd_blk_erase(sd, erase_addr, erase_len); } - sd_blk_write_bounce_buffer(sd, erase_addr, erase_len); + } else { + sd_blk_erase(sd, erase_start, erase_end - erase_start); } } =20 --=20 2.43.0 From nobody Sat Apr 18 20:20:59 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=quarantine dis=none) header.from=avm.de ARC-Seal: i=1; a=rsa-sha256; t=1776419930; cv=none; d=zohomail.com; s=zohoarc; b=lfYflQEYDNudh6HLvaolTs5c7a1i8ITS8UCMb1LPS3DnhDfRTE1NKTrzQSSVO3OCuMOQKS18vlwt8Xy8C3QCgWrMsYUfHsjJR73ZCFkUeissHqPB4HwYmG/Fg6+UQ/J6Pen0cbDmsABgD7h+dkhWz5JsfpfGtwxrO6oP/pk0NfQ= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1776419930; h=Content-Type: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=e4EJ+gtuxNmrHsVYbF8AH2azDQiEUAlyYGd1h1zBAPI=; b=M6832pwFQt5sTJ48VOPzYGXdxGyaDxeelXJQM0L6NQYrSJYyWScBuAXo20KnDLznnMwfaMHAoFwvQMFB3OtT1FNMCwbthNz36FyoqcKTzIW+CSQoUiT5oQt9JPefl3wVjH7/l/zUVKbsghiuI8zOffSnX7A+G4TQahLGDu9lxas= 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=quarantine dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1776419930985433.34991129346986; Fri, 17 Apr 2026 02:58:50 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wDfxo-0003ca-QR; Fri, 17 Apr 2026 05:58:16 -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 1wDfxC-0002qB-1D; Fri, 17 Apr 2026 05:57:38 -0400 Received: from mail.avm.de ([2001:bf0:244:244::119]) by eggs.gnu.org with esmtps (TLS1.2:DHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wDfx9-000385-Fu; Fri, 17 Apr 2026 05:57:37 -0400 Received: from [172.16.0.1] (helo=mail.avm.de) by mail.avm.de with ESMTP (eXpurgate 4.55.2) (envelope-from ) id 69e20406-1e6c-7f0000032729-7f000001b2d8-1 for ; Fri, 17 Apr 2026 11:57:26 +0200 Received: from mail-notes.avm.de (mail-notes.avm.de [172.16.0.1]) by mail.avm.de (Postfix) with ESMTP; Fri, 17 Apr 2026 11:57:26 +0200 (CEST) Received: from [127.0.1.1] ([172.17.89.139]) by mail-notes.avm.de (HCL Domino Release 14.0FP4) with ESMTP id 2026041711572446-2980 ; Fri, 17 Apr 2026 11:57:24 +0200 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=avm.de; s=mail; t=1776419846; bh=SRP0r66lkPbAsXef7wraN73YdZHRb8aL7UMn1EI5U3Q=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=R98l8PsuL/yWR09LLVXQ6ScreJePL0C6Aj7xtTdXrjSQJIZmvLwu13Ep/steuNdP8 N5TQw3Uhe+DD++DaHZ711S8QK5gA7qHeq3yzCLFjYw7U6CU4Vlqsqb+vIxbRUDir+Y gDEMMW+uYtcHsg7NMC+PjM1xEueP2RkmydvBiuMA= From: Christian Speich Date: Fri, 17 Apr 2026 11:51:40 +0200 Subject: [PATCH v4 7/7] hw/sd: Update trace events for buf+len data MIME-Version: 1.0 Message-Id: <20260417-sdcard-performance-b4-v4-7-119e66be10c2@avm.de> References: <20260417-sdcard-performance-b4-v4-0-119e66be10c2@avm.de> In-Reply-To: <20260417-sdcard-performance-b4-v4-0-119e66be10c2@avm.de> To: qemu-devel@nongnu.org Cc: =?utf-8?q?Philippe_Mathieu-Daud=C3=A9?= , Bin Meng , qemu-block@nongnu.org, Marcel Apfelbaum , Yanan Wang , Zhao Liu , Christian Speich X-Mailer: b4 0.14.2 X-MIMETrack: Itemize by SMTP Server on ANIS1/AVM(Release 14.0FP4|March 10, 2025) at 17.04.2026 11:57:24, Serialize by Router on ANIS1/AVM(Release 14.0FP4|March 10, 2025) at 17.04.2026 11:57:26, Serialize complete at 17.04.2026 11:57:26 X-TNEFEvaluated: 1 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" X-purgate-ID: 149429::1776419846-48727373-546759EF/0/0 X-purgate-type: clean X-purgate-size: 6295 X-purgate-Ad: Categorized by eleven eXpurgate (R) https://www.eleven.de X-purgate: This mail is considered clean (visit https://www.eleven.de for further information) X-purgate: clean 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=2001:bf0:244:244::119; envelope-from=c.speich@avm.de; helo=mail.avm.de X-Spam_score_int: -25 X-Spam_score: -2.6 X-Spam_bar: -- X-Spam_report: (-2.6 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.54, 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: 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 @avm.de) X-ZM-MESSAGEID: 1776419934629158500 After switching sdbuf and sdcard over to use buf+len instead of single byte operation, the trace events need to be updated. This patch updates sdbus_{read,write} and sdcard_write_data to output the buffer that is worked on. sdcard_read_data is left unchanged, as it did not print the read byte before anyways. Signed-off-by: Christian Speich Reviewed-by: Philippe Mathieu-Daud=C3=A9 --- hw/sd/core.c | 27 +++++++++++++++++++++++++-- hw/sd/sd.c | 19 +++++++++++++++---- hw/sd/trace-events | 6 +++--- 3 files changed, 43 insertions(+), 9 deletions(-) diff --git a/hw/sd/core.c b/hw/sd/core.c index 594c5e011ba30940a33799f9032c92494ee0ca19..eaa186fbfca3cdf000c200c3a84= 4aac373ba7fec 100644 --- a/hw/sd/core.c +++ b/hw/sd/core.c @@ -24,6 +24,7 @@ #include "hw/sd/sd.h" #include "qemu/module.h" #include "qapi/error.h" +#include "qemu/cutils.h" #include "sdmmc-internal.h" #include "trace.h" =20 @@ -43,6 +44,26 @@ static SDState *get_card(SDBus *sdbus) return SDMMC_COMMON(kid->child); } =20 +static void sdbus_write_dump(const char *bus_name, const void *buf, size_t= len) +{ + g_autoptr(GString) str =3D NULL; + + if (trace_event_get_state_backends(TRACE_SDBUS_WRITE)) { + str =3D qemu_hexdump_line(NULL, buf, len, 8, 0); + trace_sdbus_write(bus_name, str->str); + } +} + +static void sdbus_read_dump(const char *bus_name, const void *buf, size_t = len) +{ + g_autoptr(GString) str =3D NULL; + + if (trace_event_get_state_backends(TRACE_SDBUS_READ)) { + str =3D qemu_hexdump_line(NULL, buf, len, 8, 0); + trace_sdbus_read(bus_name, str->str); + } +} + uint8_t sdbus_get_dat_lines(SDBus *sdbus) { SDState *slave =3D get_card(sdbus); @@ -109,7 +130,7 @@ void sdbus_write_byte(SDBus *sdbus, uint8_t value) { SDState *card =3D get_card(sdbus); =20 - trace_sdbus_write(sdbus_name(sdbus), value); + sdbus_write_dump(sdbus_name(sdbus), &value, 1); if (card) { SDCardClass *sc =3D SDMMC_COMMON_GET_CLASS(card); =20 @@ -121,6 +142,7 @@ void sdbus_write_data(SDBus *sdbus, const void *buf, si= ze_t length) { SDState *card =3D get_card(sdbus); =20 + sdbus_write_dump(sdbus_name(sdbus), buf, length); if (card) { SDCardClass *sc =3D SDMMC_COMMON_GET_CLASS(card); =20 @@ -145,7 +167,7 @@ uint8_t sdbus_read_byte(SDBus *sdbus) =20 sc->read_data(card, &value, 1); } - trace_sdbus_read(sdbus_name(sdbus), value); + sdbus_read_dump(sdbus_name(sdbus), &value, 1); =20 return value; } @@ -166,6 +188,7 @@ void sdbus_read_data(SDBus *sdbus, void *buf, size_t le= ngth) length -=3D read; } } + sdbus_read_dump(sdbus_name(sdbus), buf, length); } =20 bool sdbus_receive_ready(SDBus *sdbus) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index d1ff9badb39b699ce734a533ccebfab894958d2d..13039187fcda2444d1b4aa173ab= 64c601bc71924 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -2690,11 +2690,22 @@ static bool sd_generic_read_data(SDState *sd, void = *buf, size_t *len) return false; } =20 +static void sdcard_write_data_dump(const char *proto, const char *cmd_desc, + uint8_t cmd, uint32_t offset, + const void *buf, size_t len) +{ + g_autoptr(GString) str =3D NULL; + + if (trace_event_get_state_backends(TRACE_SDCARD_WRITE_DATA)) { + str =3D qemu_hexdump_line(NULL, buf, len, 8, 0); + trace_sdcard_write_data(proto, cmd_desc, cmd, offset, str->str); + } +} + static size_t sd_write_data(SDState *sd, const void *buf, size_t length) { unsigned int partition_access; int i; - const uint8_t *value =3D buf; =20 if (!sd->blk || !blk_is_inserted(sd->blk)) { return length; @@ -2709,9 +2720,9 @@ static size_t sd_write_data(SDState *sd, const void *= buf, size_t length) if (sd->card_status & (ADDRESS_ERROR | WP_VIOLATION)) return length; =20 - trace_sdcard_write_data(sd->proto->name, - sd->last_cmd_name, - sd->current_cmd, sd->data_offset, value[0]); + sdcard_write_data_dump(sd->proto->name, + sd->last_cmd_name, + sd->current_cmd, sd->data_offset, buf, length); switch (sd->current_cmd) { case 24: /* CMD24: WRITE_SINGLE_BLOCK */ if (sd_generic_write_data(sd, buf, &length)) { diff --git a/hw/sd/trace-events b/hw/sd/trace-events index 4ec52d2a81995ddf8d4ebef9dcc79224c90a2982..c6811f3a08e018fc45ec4f259b5= 895998b86bd77 100644 --- a/hw/sd/trace-events +++ b/hw/sd/trace-events @@ -15,8 +15,8 @@ bcm2835_sdhost_update_irq(uint32_t irq) "IRQ bits 0x%x" =20 # core.c sdbus_command(const char *bus_name, uint8_t cmd, uint32_t arg) "@%s CMD%02= d arg 0x%08x" -sdbus_read(const char *bus_name, uint8_t value) "@%s value 0x%02x" -sdbus_write(const char *bus_name, uint8_t value) "@%s value 0x%02x" +sdbus_read(const char *bus_name, const char *hexdump) "@%s data %s" +sdbus_write(const char *bus_name, const char *hexdump) "@%s data %s" sdbus_set_voltage(const char *bus_name, uint16_t millivolts) "@%s %u (mV)" sdbus_get_dat_lines(const char *bus_name, uint8_t dat_lines) "@%s dat_line= s: %u" sdbus_get_cmd_line(const char *bus_name, bool cmd_line) "@%s cmd_line: %u" @@ -54,7 +54,7 @@ sdcard_unlock(void) "" sdcard_req_addr(uint32_t req_arg, uint64_t addr) "req 0x%" PRIx32 " addr 0= x%" PRIx64 sdcard_read_block(uint64_t addr, uint32_t len) "addr 0x%" PRIx64 " size 0x= %x" sdcard_write_block(uint64_t addr, uint32_t len) "addr 0x%" PRIx64 " size 0= x%x" -sdcard_write_data(const char *proto, const char *cmd_desc, uint8_t cmd, ui= nt32_t offset, uint8_t value) "%s %20s/ CMD%02d ofs %"PRIu32" value 0x%02x" +sdcard_write_data(const char *proto, const char *cmd_desc, uint8_t cmd, ui= nt32_t offset, const char *hexdump) "%s %20s/ CMD%02d ofs %"PRIu32" data %s" sdcard_read_data(const char *proto, const char *cmd_desc, uint8_t cmd, uin= t32_t offset, uint64_t size, uint32_t blklen) "%s %20s/ CMD%02d ofs %"PRIu3= 2" size %"PRIu64" blklen %" PRIu32 sdcard_set_voltage(uint16_t millivolts) "%u mV" sdcard_ext_csd_update(unsigned index, uint8_t oval, uint8_t nval) "index %= u: 0x%02x -> 0x%02x" --=20 2.43.0