From nobody Mon Feb 9 01:47:19 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; 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=nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1770211459; cv=none; d=zohomail.com; s=zohoarc; b=KIE9uSbjdFBBDOo16vG1oIKijSU44iskbKWMO7kvsZdaaYZAUAy1tMBqhhyyyLwj0KSG3FEGw6t1gbxtfOWZy+HS1UcSaoHrbC4qot/rhmlEmi7ayAA/W9V5XgqRwELVEjxNC3Sjia0/dSAd+8MiyPLAZtkgHig7YfWIeovz5Ps= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1770211459; 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:Reply-To:Reply-To:References:Sender:Subject:Subject:To:To:Message-Id; bh=e01gb+A41n+7/msZcgCy5vahzD5cOFHiH/LYpgOdweg=; b=DFow5WSO0XX4Q2FT3NxfFeBQnLJzAmTUN6SuuiytNqtokKi3FbU6i5UiXMg3HiDWxxf0ne4NGP56lyR+J/zyW5FbTdJh3Cz9dzrLJlWI0k90YYE2QOLQJOUxHXRB9diPAr4nMFQfVxCDGe16hof8szogMSBi1JYrhVC3SmM/e5A= ARC-Authentication-Results: i=1; mx.zohomail.com; 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 lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1770211459450116.9906527314754; Wed, 4 Feb 2026 05:24:19 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1vncqM-0003Kt-5t; Wed, 04 Feb 2026 08:22:54 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1vncqI-0003Ib-Um; Wed, 04 Feb 2026 08:22:50 -0500 Received: from mail.avm.de ([2001:bf0:244:244::120]) by eggs.gnu.org with esmtps (TLS1.2:DHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1vncqE-000311-Js; Wed, 04 Feb 2026 08:22:49 -0500 Received: from [172.16.0.1] (helo=mail.avm.de) by mail.avm.de with ESMTP (eXpurgate 4.55.0) (envelope-from ) id 6983481f-cb91-7f0000032729-7f000001d8ec-1 for ; Wed, 04 Feb 2026 14:22:39 +0100 Received: from mail-notes.avm.de (mail-notes.avm.de [172.16.0.1]) by mail.avm.de (Postfix) with ESMTP; Wed, 4 Feb 2026 14:22:39 +0100 (CET) Received: from [127.0.1.1] ([172.17.89.139]) by mail-notes.avm.de (HCL Domino Release 14.0FP4) with ESMTP id 2026020414223965-15149 ; Wed, 4 Feb 2026 14:22:39 +0100 Date: Wed, 04 Feb 2026 14:22:26 +0100 Subject: [PATCH v3 2/6] hw/sd/sd: Allow multi-byte read/write for generic paths MIME-Version: 1.0 Message-Id: <20260204-sdcard-performance-b4-v3-2-dc1cf172ee57@avm.de> References: <20260204-sdcard-performance-b4-v3-0-dc1cf172ee57@avm.de> In-Reply-To: <20260204-sdcard-performance-b4-v3-0-dc1cf172ee57@avm.de> To: qemu-devel@nongnu.org Cc: =?utf-8?q?Philippe_Mathieu-Daud=C3=A9?= , Bin Meng , qemu-block@nongnu.org, Christian Speich X-Mailer: b4 0.14.2 X-MIMETrack: Itemize by SMTP Server on ANIS1/AVM(Release 14.0FP4|March 10, 2025) at 04.02.2026 14:22:39, Serialize by Router on ANIS1/AVM(Release 14.0FP4|March 10, 2025) at 04.02.2026 14:22:39, Serialize complete at 04.02.2026 14:22:39 X-TNEFEvaluated: 1 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" X-purgate-ID: 149429::1770211359-C964C71A-CF93AFD6/0/0 X-purgate-type: clean X-purgate-size: 7006 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=lists.gnu.org; Received-SPF: pass client-ip=2001:bf0:244:244::120; envelope-from=c.speich@avm.de; helo=mail.avm.de 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, 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: , Reply-to: Christian Speich From: Christian Speich via qemu development Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZM-MESSAGEID: 1770211460975154100 Paths that use sd_generic_write/read_data can now write/read multiple bytes with one call. Signed-off-by: Christian Speich --- 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