From nobody Sat Apr 11 18:37:57 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=gmail.com ARC-Seal: i=1; a=rsa-sha256; t=1775137991; cv=none; d=zohomail.com; s=zohoarc; b=KWF7EsuoirtzTUlGAuEEk+uE9HlZN7xOZf9xTRNuzVOU3cXHLgRap8blSiPdhaFJPu6cQwe5pdGV5pwqcTwyXaJsRzJEqJigJEy7kOSEKS411wCjVTgF3sRz4JWRZSKl/MhsEy4HoFE9Alt76193i7EbDTxkn8w33/vS66hwm4w= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1775137991; 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=nEvvbdwpOxSnYp5j1qxcKcTTJ9o9BYKzkXwsXDSeBbU=; b=dC5d6w7SnudElXntIqhrnzZCCJuSXM8/R5mo3OBm9ZS+1iPxHUTW5z8RUhfZUIb+EmoDd81rEc4C5e7NZKpOx09Qz3g8p9gwXHb1QDTzPClWWYgDMelAqIbKddntpYImbdCGFn20cZvNX61+YYWNiFJQllnuwkVPpTxgWCuJVbg= 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 lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 17751379912721018.4736188059536; Thu, 2 Apr 2026 06:53:11 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1w8ITK-0003Qx-Np; Thu, 02 Apr 2026 09:52:42 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1w8Eap-00018j-DD for qemu-devel@nongnu.org; Thu, 02 Apr 2026 05:44:04 -0400 Received: from mail-pf1-x42b.google.com ([2607:f8b0:4864:20::42b]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1w8Eam-0005MT-3i for qemu-devel@nongnu.org; Thu, 02 Apr 2026 05:44:03 -0400 Received: by mail-pf1-x42b.google.com with SMTP id d2e1a72fcca58-82418b0178cso326302b3a.1 for ; Thu, 02 Apr 2026 02:43:59 -0700 (PDT) Received: from [172.17.0.5] ([168.126.243.22]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-82cf9c6ad8asm2668477b3a.40.2026.04.02.02.43.55 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 02 Apr 2026 02:43:57 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1775123038; x=1775727838; darn=nongnu.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=nEvvbdwpOxSnYp5j1qxcKcTTJ9o9BYKzkXwsXDSeBbU=; b=LvLVp9M2J6eTRRC57BNTaPS6nleg/H9y+5t8GyzAGV3g0Ty9/LFDyExff595RnGGco f4eJoACwPlU/SOCxvInBnCzz5ly/vcNvtR8WveIg1s3+EHkCx2hnXD/UgmKDiTXcVUWB CX3JUAU7xuus2NUlKecHXkHVZ3X1AAHQFB9w0tuXFF1JJCsGMWFEam8QppH6vTSoqRN5 6nInU4dZ/6mzxoaEtvx6xSIYYV8vlrk0BvXtgviFra/QuJBMH2jOJsDOeOelS5/VhP/d xKTg4LlnJUuJMPV/mC7GiRajvnOB5I3PnTmR0nt9dOqEI7uF3yL8ynSGVjdjE3565g+H bNkg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1775123038; x=1775727838; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-gg:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to; bh=nEvvbdwpOxSnYp5j1qxcKcTTJ9o9BYKzkXwsXDSeBbU=; b=Q3HeIVPWMBfvUG1wVQUkv/e85ailTZDmI/qkyeXj+F0a3SlL8gbreRj+Bgm74BtL1C Xazjkg1okEgsOqGJ8bgUfvhWbEiuE3/Y7Yt5Bf4XsEDtFy6unB0anrSlHunA1pGiNuIZ SiTRniuTeYzz7cSDqeQ6iq0Vd0Dw6UBSHJP/HM/QodxxKskJazg+eI0RfP68sn+WMaIF hueZBTkAC0cQkYTxjbDrf7XABYUffQVfvEdIQQSVj877DXLICbARAZKbTqT32amtqL73 GIv3d3ZwcqihbS8ewnXrfyBtkA2+dfTutqeSFLJDEZNJL6h6Ct46Jb4EdhN8/hBAKPZM VQYw== X-Gm-Message-State: AOJu0YzUN5v8WqwMr28a0KnHUvw8FvJcJEsXA2Sq6TOXhlb9mOkvwM7Y 8TuFaEh4V5XHubGVzIq9lzB+4cd9MCIsJejYpl8kXxIc8u6bvIRsggXi X-Gm-Gg: ATEYQzx08/uw7C2zgfyGF7nnKYMrJxmeVv3XLwelbC0U4DR8EmCeJG7CHP4LYV3A2vE 58g07l923PNjOfbA7ckhPxuLYvJEXSsz3jz0FlMam6YcKYJ9yXIn63lQIhQMVEDIIOA7KcpKTR0 YDin4+BBZO/7njrcSBwFcXZFqp4k2Q0HbDTfwzvpRa+jsZJ3fsQ4L0/NdbCcM9MGHnApilcPXVw 4RKHHeYUP2ZjV+elFn67zfZfGKEbiecaiqmLW5SxwKs1R+Sd3c22IT0LebJ+Qc225R5gJATg5xw bOfBX7nkdRjWRI4wRIVlLnAPVMGyXR5xpbVreeK1ieLb1Jy+CSDYEgBfyaziI4cFGgDmrLMssjJ 2PJJRAGiIFCYlUI8iExVpl5/7EaxMG59wGCOThpQOGHbk3pIzaxqUzdqO+vQlvt1hueZDSktt0a kJIswiDxugryo9zKTefIPhmKA8HRjuIQ== X-Received: by 2002:a05:6a00:4995:b0:82c:eb46:aeac with SMTP id d2e1a72fcca58-82ceb46b1a4mr4359219b3a.50.1775123038130; Thu, 02 Apr 2026 02:43:58 -0700 (PDT) From: Jaemyung Lee X-Google-Original-From: Jaemyung Lee Date: Thu, 02 Apr 2026 18:43:45 +0900 Subject: [PATCH 1/5] hw/ufs: Apply UFS 4.1 Specification MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260402-write_booster-v1-1-e4fed1df6c7e@samsung.com> References: <20260402-write_booster-v1-0-e4fed1df6c7e@samsung.com> In-Reply-To: <20260402-write_booster-v1-0-e4fed1df6c7e@samsung.com> To: qemu-devel@nongnu.org Cc: Jeuk Kim , Kevin Wolf , Hanna Reitz , qemu-block@nongnu.org, Fabiano Rosas , Laurent Vivier , Paolo Bonzini , Jaemyung Lee X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1775123032; l=12799; i=jaemyung.lee@samsung.com; s=20260402; h=from:subject:message-id; bh=CgN8ljzeml1hAPWOnqVTo/m8W7lnE0WV5YXREroYZ/Q=; b=ZL/4EMy9fMjRkrz5gmAaQrxtB8iV9Nr6afksRwyc2kYYNOgQc7IaNoGwML78u3WqK7Erm2/lh 0BdxS7ZTXYnDQtUcGrjrMf24ShOz0zoMXwSHS/zfV/+XjqtF6b4fgC4 X-Developer-Key: i=jaemyung.lee@samsung.com; a=ed25519; pk=bZPd7A/kteUO62FfUM6IrI1LuBPe5QrcqfvsitM1ZjE= 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=2607:f8b0:4864:20::42b; envelope-from=ldc.jml@gmail.com; helo=mail-pf1-x42b.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-Mailman-Approved-At: Thu, 02 Apr 2026 09:51:38 -0400 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 @gmail.com) X-ZM-MESSAGEID: 1775137993006158500 Apply current UFS 4.1 Specification to QEMU-UFS. QEMU-UFS device emulates operation via UFS 4.0 Specification, but current latest Spec. version is UFS 4.1. So extent internal DESCRIPTOR/FLAG/ATTRIBUTE declaration to follow UFS 4.1 Spec. It does not implement any actual functionallity, but only adds minimum supportability for further implementation. Signed-off-by: Jaemyung Lee --- hw/ufs/ufs.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++++= +--- include/block/ufs.h | 59 ++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 122 insertions(+), 6 deletions(-) diff --git a/hw/ufs/ufs.c b/hw/ufs/ufs.c index cb74cb56bc15ec6fb873097ccb1b6e5694639bd9..b2b70c8b38ebecd8d49ecce2886= 14d55efd90f2e 100644 --- a/hw/ufs/ufs.c +++ b/hw/ufs/ufs.c @@ -9,7 +9,7 @@ */ =20 /** - * Reference Specs: https://www.jedec.org/, 4.0 + * Reference Specs: https://www.jedec.org/, 4.1 * * Usage * ----- @@ -29,8 +29,8 @@ #include "trace.h" #include "ufs.h" =20 -/* The QEMU-UFS device follows spec version 4.0 */ -#define UFS_SPEC_VER 0x0400 +/* The QEMU-UFS device follows spec version 4.1 */ +#define UFS_SPEC_VER 0x0410 #define UFS_MAX_NUTRS 32 #define UFS_MAX_NUTMRS 8 #define UFS_MCQ_QCFGPTR 2 @@ -1000,6 +1000,7 @@ static const int flag_permission[UFS_QUERY_FLAG_IDN_C= OUNT] =3D { [UFS_QUERY_FLAG_IDN_WB_EN] =3D UFS_QUERY_FLAG_READ, [UFS_QUERY_FLAG_IDN_WB_BUFF_FLUSH_EN] =3D UFS_QUERY_FLAG_READ, [UFS_QUERY_FLAG_IDN_WB_BUFF_FLUSH_DURING_HIBERN8] =3D UFS_QUERY_FLAG_R= EAD, + [UFS_QUERY_FLAG_IDN_UNPIN_EN] =3D UFS_QUERY_FLAG_READ, }; =20 static inline QueryRespCode ufs_flag_check_idn_valid(uint8_t idn, int op) @@ -1057,10 +1058,31 @@ static const int attr_permission[UFS_QUERY_ATTR_IDN= _COUNT] =3D { [UFS_QUERY_ATTR_IDN_AVAIL_WB_BUFF_SIZE] =3D UFS_QUERY_ATTR_READ, [UFS_QUERY_ATTR_IDN_WB_BUFF_LIFE_TIME_EST] =3D UFS_QUERY_ATTR_READ, [UFS_QUERY_ATTR_IDN_CURR_WB_BUFF_SIZE] =3D UFS_QUERY_ATTR_READ, + [UFS_QUERY_ATTR_IDN_EXT_IID_EN] =3D UFS_QUERY_ATTR_READ, + [UFS_QUERY_ATTR_IDN_HOST_HINT_CACHE_SIZE] =3D UFS_QUERY_ATTR_READ, /* refresh operation is not supported */ [UFS_QUERY_ATTR_IDN_REFRESH_STATUS] =3D UFS_QUERY_ATTR_READ, [UFS_QUERY_ATTR_IDN_REFRESH_FREQ] =3D UFS_QUERY_ATTR_READ, [UFS_QUERY_ATTR_IDN_REFRESH_UNIT] =3D UFS_QUERY_ATTR_READ, + [UFS_QUERY_ATTR_IDN_TIMESTAMP] =3D UFS_QUERY_ATTR_WRITE, + [UFS_QUERY_ATTR_IDN_DEVICE_LEVEL_EXCEPTION_ID] =3D UFS_QUERY_ATTR_READ, + /* host initiated defragmentation is not supported */ + [UFS_QUERY_ATTR_IDN_DEFRAG_OP] =3D UFS_QUERY_ATTR_READ, + [UFS_QUERY_ATTR_IDN_HID_AVAIL_SIZE] =3D UFS_QUERY_ATTR_READ, + [UFS_QUERY_ATTR_IDN_HID_SIZE] =3D UFS_QUERY_ATTR_READ, + [UFS_QUERY_ATTR_IDN_HID_PROG_RATIO] =3D UFS_QUERY_ATTR_READ, + [UFS_QUERY_ATTR_IDN_HID_STATE] =3D UFS_QUERY_ATTR_READ, + [UFS_QUERY_ATTR_IDN_WB_BUFF_RESIZE_HINT] =3D UFS_QUERY_ATTR_READ, + [UFS_QUERY_ATTR_IDN_WB_BUFF_RESIZE_EN] =3D UFS_QUERY_ATTR_READ, + [UFS_QUERY_ATTR_IDN_WB_BUFF_RESIZE_STATUS] =3D UFS_QUERY_ATTR_READ, + [UFS_QUERY_ATTR_IDN_WB_BUFF_PARTIAL_FLUSH_MODE] =3D UFS_QUERY_ATTR_REA= D, + [UFS_QUERY_ATTR_IDN_MAX_FIFO_WB_PARTIAL_FLUSH_MODE] =3D UFS_QUERY_ATTR= _READ, + [UFS_QUERY_ATTR_IDN_CURR_FIFO_WB_PARTIAL_FLUSH_MODE] =3D UFS_QUERY_ATT= R_READ, + [UFS_QUERY_ATTR_IDN_PINNED_WB_BUFF_CURR_ALLOC_UNITS] =3D UFS_QUERY_ATT= R_READ, + [UFS_QUERY_ATTR_IDN_PINNED_WB_BUFF_AVAIL_PERCENT] =3D UFS_QUERY_ATTR_R= EAD, + [UFS_QUERY_ATTR_IDN_PINNED_WB_CUMM_WRITTEN_SIZE] =3D UFS_QUERY_ATTR_RE= AD, + [UFS_QUERY_ATTR_IDN_PINNED_WB_NUM_ALLOC_UNITS] =3D UFS_QUERY_ATTR_READ, + [UFS_QUERY_ATTR_IDN_NON_PINNED_WB_MIN_NUM_ALLOC_UNITS] =3D UFS_QUERY_A= TTR_READ, }; =20 static inline QueryRespCode ufs_attr_check_idn_valid(uint8_t idn, int op) @@ -1194,12 +1216,50 @@ static uint32_t ufs_read_attr_value(UfsHc *u, uint8= _t idn) return u->attributes.wb_buffer_life_time_est; case UFS_QUERY_ATTR_IDN_CURR_WB_BUFF_SIZE: return be32_to_cpu(u->attributes.current_wb_buffer_size); + case UFS_QUERY_ATTR_IDN_EXT_IID_EN: + return u->attributes.ext_iid_en; + case UFS_QUERY_ATTR_IDN_HOST_HINT_CACHE_SIZE: + return be16_to_cpu(u->attributes.host_hint_cache_size); case UFS_QUERY_ATTR_IDN_REFRESH_STATUS: return u->attributes.refresh_status; case UFS_QUERY_ATTR_IDN_REFRESH_FREQ: return u->attributes.refresh_freq; case UFS_QUERY_ATTR_IDN_REFRESH_UNIT: return u->attributes.refresh_unit; + case UFS_QUERY_ATTR_IDN_DEVICE_LEVEL_EXCEPTION_ID: + return be64_to_cpu(u->attributes.device_level_exception_id); + case UFS_QUERY_ATTR_IDN_DEFRAG_OP: + return u->attributes.defrag_op; + case UFS_QUERY_ATTR_IDN_HID_AVAIL_SIZE: + return be32_to_cpu(u->attributes.hid_avail_size); + case UFS_QUERY_ATTR_IDN_HID_SIZE: + return be32_to_cpu(u->attributes.hid_size); + case UFS_QUERY_ATTR_IDN_HID_PROG_RATIO: + return u->attributes.hid_prog_ratio; + case UFS_QUERY_ATTR_IDN_HID_STATE: + return u->attributes.hid_state; + case UFS_QUERY_ATTR_IDN_WB_BUFF_RESIZE_HINT: + return u->attributes.wb_buffer_resize_hint; + case UFS_QUERY_ATTR_IDN_WB_BUFF_RESIZE_EN: + return u->attributes.wb_buffer_resize_en; + case UFS_QUERY_ATTR_IDN_WB_BUFF_RESIZE_STATUS: + return u->attributes.wb_buffer_resize_status; + case UFS_QUERY_ATTR_IDN_WB_BUFF_PARTIAL_FLUSH_MODE: + return u->attributes.wb_buffer_partial_flush_mode; + case UFS_QUERY_ATTR_IDN_MAX_FIFO_WB_PARTIAL_FLUSH_MODE: + return be32_to_cpu(u->attributes.max_fifo_wb_partial_flush_mode); + case UFS_QUERY_ATTR_IDN_CURR_FIFO_WB_PARTIAL_FLUSH_MODE: + return be32_to_cpu(u->attributes.curr_fifo_wb_partial_flush_mode); + case UFS_QUERY_ATTR_IDN_PINNED_WB_BUFF_CURR_ALLOC_UNITS: + return be32_to_cpu(u->attributes.pinned_wb_buffer_curr_alloc_units= ); + case UFS_QUERY_ATTR_IDN_PINNED_WB_BUFF_AVAIL_PERCENT: + return u->attributes.pinned_wb_buffer_avail_percent; + case UFS_QUERY_ATTR_IDN_PINNED_WB_CUMM_WRITTEN_SIZE: + return be32_to_cpu(u->attributes.pinned_wb_cumm_written_size); + case UFS_QUERY_ATTR_IDN_PINNED_WB_NUM_ALLOC_UNITS: + return be32_to_cpu(u->attributes.pinned_wb_num_alloc_units); + case UFS_QUERY_ATTR_IDN_NON_PINNED_WB_MIN_NUM_ALLOC_UNITS: + return be32_to_cpu(u->attributes.non_pinned_wb_min_num_alloc_units= ); } return 0; } @@ -1237,6 +1297,9 @@ static QueryRespCode ufs_write_attr_value(UfsHc *u, u= int8_t idn, uint32_t value) case UFS_QUERY_ATTR_IDN_PSA_DATA_SIZE: u->attributes.psa_data_size =3D cpu_to_be32(value); break; + case UFS_QUERY_ATTR_IDN_TIMESTAMP: + u->attributes.timestamp =3D cpu_to_be64(value); + break; } return UFS_QUERY_RESULT_SUCCESS; } diff --git a/include/block/ufs.h b/include/block/ufs.h index 04cb24324d7c5585be9df596738183e1924403fb..4dacfb776f947a285d86018add8= 2115f148b7dd9 100644 --- a/include/block/ufs.h +++ b/include/block/ufs.h @@ -294,7 +294,8 @@ typedef struct QEMU_PACKED DeviceDescriptor { uint32_t psa_max_data_size; uint8_t psa_state_timeout; uint8_t product_revision_level; - uint8_t reserved[36]; + uint8_t reserved[34]; + uint16_t extended_wb_support; uint32_t extended_ufs_features_support; uint8_t write_booster_buffer_preserve_user_space_en; uint8_t write_booster_buffer_type; @@ -342,6 +343,8 @@ typedef struct QEMU_PACKED GeometryDescriptor { uint8_t write_booster_buffer_cap_adj_fac; uint8_t supported_write_booster_buffer_user_space_reduction_types; uint8_t supported_write_booster_buffer_types; + uint8_t reserved3[17]; + uint8_t cap_adj_fac_representation; } GeometryDescriptor; =20 #define UFS_GEOMETRY_CAPACITY_SHIFT 9 @@ -437,6 +440,8 @@ typedef struct QEMU_PACKED Flags { uint8_t wb_buffer_flush_en; uint8_t wb_buffer_flush_during_hibernate; uint8_t reserved4[2]; + uint8_t unpin_en; + uint8_t reserved5[235]; } Flags; =20 typedef struct Attributes { @@ -457,6 +462,8 @@ typedef struct Attributes { uint16_t exception_event_status; uint32_t seconds_passed; uint16_t context_conf; + uint8_t obsolete; + uint8_t reserved2[2]; uint8_t device_ffu_status; uint8_t psa_state; uint32_t psa_data_size; @@ -469,10 +476,34 @@ typedef struct Attributes { uint8_t available_wb_buffer_size; uint8_t wb_buffer_life_time_est; uint32_t current_wb_buffer_size; + uint8_t reserved3[10]; + uint8_t ext_iid_en; + uint16_t host_hint_cache_size; uint8_t refresh_status; uint8_t refresh_freq; uint8_t refresh_unit; uint8_t refresh_method; + uint64_t timestamp; + uint8_t reserved4[3]; + uint64_t device_level_exception_id; + uint8_t defrag_op; + uint32_t hid_avail_size; + uint32_t hid_size; + uint8_t hid_prog_ratio; + uint8_t hid_state; + uint8_t reserved5[2]; + uint8_t wb_buffer_resize_hint; + uint8_t wb_buffer_resize_en; + uint8_t wb_buffer_resize_status; + uint8_t wb_buffer_partial_flush_mode; + uint32_t max_fifo_wb_partial_flush_mode; + uint32_t curr_fifo_wb_partial_flush_mode; + uint32_t pinned_wb_buffer_curr_alloc_units; + uint8_t pinned_wb_buffer_avail_percent; + uint32_t pinned_wb_cumm_written_size; + uint32_t pinned_wb_num_alloc_units; + uint32_t non_pinned_wb_min_num_alloc_units; + uint8_t reserved6[184]; } Attributes; =20 #define UFS_TRANSACTION_SPECIFIC_FIELD_SIZE 20 @@ -856,6 +887,7 @@ enum flag_idn { UFS_QUERY_FLAG_IDN_WB_BUFF_FLUSH_DURING_HIBERN8 =3D 0x10, UFS_QUERY_FLAG_IDN_HPB_RESET =3D 0x11, UFS_QUERY_FLAG_IDN_HPB_EN =3D 0x12, + UFS_QUERY_FLAG_IDN_UNPIN_EN =3D 0x13, UFS_QUERY_FLAG_IDN_COUNT, }; =20 @@ -893,9 +925,29 @@ enum attr_idn { UFS_QUERY_ATTR_IDN_AVAIL_WB_BUFF_SIZE =3D 0x1D, UFS_QUERY_ATTR_IDN_WB_BUFF_LIFE_TIME_EST =3D 0x1E, UFS_QUERY_ATTR_IDN_CURR_WB_BUFF_SIZE =3D 0x1F, + UFS_QUERY_ATTR_IDN_EXT_IID_EN =3D 0x2A, + UFS_QUERY_ATTR_IDN_HOST_HINT_CACHE_SIZE =3D 0x2B, UFS_QUERY_ATTR_IDN_REFRESH_STATUS =3D 0x2C, UFS_QUERY_ATTR_IDN_REFRESH_FREQ =3D 0x2D, UFS_QUERY_ATTR_IDN_REFRESH_UNIT =3D 0x2E, + UFS_QUERY_ATTR_IDN_TIMESTAMP =3D 0x30, + UFS_QUERY_ATTR_IDN_DEVICE_LEVEL_EXCEPTION_ID =3D 0x34, + UFS_QUERY_ATTR_IDN_DEFRAG_OP =3D 0x35, + UFS_QUERY_ATTR_IDN_HID_AVAIL_SIZE =3D 0x36, + UFS_QUERY_ATTR_IDN_HID_SIZE =3D 0x37, + UFS_QUERY_ATTR_IDN_HID_PROG_RATIO =3D 0x38, + UFS_QUERY_ATTR_IDN_HID_STATE =3D 0x39, + UFS_QUERY_ATTR_IDN_WB_BUFF_RESIZE_HINT =3D 0x3C, + UFS_QUERY_ATTR_IDN_WB_BUFF_RESIZE_EN =3D 0x3D, + UFS_QUERY_ATTR_IDN_WB_BUFF_RESIZE_STATUS =3D 0x3E, + UFS_QUERY_ATTR_IDN_WB_BUFF_PARTIAL_FLUSH_MODE =3D 0x3F, + UFS_QUERY_ATTR_IDN_MAX_FIFO_WB_PARTIAL_FLUSH_MODE =3D 0x40, + UFS_QUERY_ATTR_IDN_CURR_FIFO_WB_PARTIAL_FLUSH_MODE =3D 0x41, + UFS_QUERY_ATTR_IDN_PINNED_WB_BUFF_CURR_ALLOC_UNITS =3D 0x42, + UFS_QUERY_ATTR_IDN_PINNED_WB_BUFF_AVAIL_PERCENT =3D 0x43, + UFS_QUERY_ATTR_IDN_PINNED_WB_CUMM_WRITTEN_SIZE =3D 0x44, + UFS_QUERY_ATTR_IDN_PINNED_WB_NUM_ALLOC_UNITS =3D 0x45, + UFS_QUERY_ATTR_IDN_NON_PINNED_WB_MIN_NUM_ALLOC_UNITS =3D 0x46, UFS_QUERY_ATTR_IDN_COUNT, }; =20 @@ -1005,6 +1057,7 @@ enum device_desc_param { UFS_DEVICE_DESC_PARAM_PRDCT_REV =3D 0x2A, UFS_DEVICE_DESC_PARAM_HPB_VER =3D 0x40, UFS_DEVICE_DESC_PARAM_HPB_CONTROL =3D 0x42, + UFS_DEVICE_DESC_PARAM_EXT_WB_SUP =3D 0x4D, UFS_DEVICE_DESC_PARAM_EXT_UFS_FEATURE_SUP =3D 0x4F, UFS_DEVICE_DESC_PARAM_WB_PRESRV_USRSPC_EN =3D 0x53, UFS_DEVICE_DESC_PARAM_WB_TYPE =3D 0x54, @@ -1208,14 +1261,14 @@ static inline void _ufs_check_size(void) QEMU_BUILD_BUG_ON(sizeof(UfsMcqCqIntReg) !=3D 12); QEMU_BUILD_BUG_ON(sizeof(UfsMcqOpReg) !=3D 48); QEMU_BUILD_BUG_ON(sizeof(DeviceDescriptor) !=3D 89); - QEMU_BUILD_BUG_ON(sizeof(GeometryDescriptor) !=3D 87); + QEMU_BUILD_BUG_ON(sizeof(GeometryDescriptor) !=3D 105); QEMU_BUILD_BUG_ON(sizeof(UnitDescriptor) !=3D 45); QEMU_BUILD_BUG_ON(sizeof(RpmbUnitDescriptor) !=3D 35); QEMU_BUILD_BUG_ON(sizeof(PowerParametersDescriptor) !=3D 98); QEMU_BUILD_BUG_ON(sizeof(InterconnectDescriptor) !=3D 6); QEMU_BUILD_BUG_ON(sizeof(StringDescriptor) !=3D 254); QEMU_BUILD_BUG_ON(sizeof(DeviceHealthDescriptor) !=3D 45); - QEMU_BUILD_BUG_ON(sizeof(Flags) !=3D 0x13); + QEMU_BUILD_BUG_ON(sizeof(Flags) !=3D 0xFF); QEMU_BUILD_BUG_ON(sizeof(UtpUpiuHeader) !=3D 12); QEMU_BUILD_BUG_ON(sizeof(UtpUpiuQuery) !=3D 276); QEMU_BUILD_BUG_ON(sizeof(UtpUpiuCmd) !=3D 20); --=20 2.48.1 From nobody Sat Apr 11 18:37:57 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=gmail.com ARC-Seal: i=1; a=rsa-sha256; t=1775137992; cv=none; d=zohomail.com; s=zohoarc; b=CUiosd+6Z8bjIiK5NyXIU620CdZwP6B+GEm9I+iQ8KRd4rMeDzNoV6bKzdMUAwyhnW0xLa1yUUBWvKtH2wlGRFxvaXYrXbYIyTZMbhusU+Var4fqG/TFYVNJMo4veRGja2rY03CKqXoS6ls2GbhbFLQnNc/DWgkYpYQm0n9bj0o= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1775137992; 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=wp610CTuY5BtVJCvmliEvcgHSUgtMv4PTZfRqvUtBfw=; b=ZLl1piblZR2SaSThvx9yFvGKNy9pWQFV0FfKKFrtWIoPAOsYyMgW2v/zhy5FNU7jtHEyoJIT2vEXmxGQqNVbhA/Tf+WOYS+gCJWUqiYiL3+SCj0P1xSCM/wkcP58O1GXQzYT5w/5H0BPv7qS9sxnLFEz9zlD9t8BWm9IkxxbWNU= 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 lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1775137992079443.13072202122953; Thu, 2 Apr 2026 06:53:12 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1w8ISZ-00038u-Od; Thu, 02 Apr 2026 09:51:48 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1w8Eaq-00019K-Vy for qemu-devel@nongnu.org; Thu, 02 Apr 2026 05:44:06 -0400 Received: from mail-pf1-x42a.google.com ([2607:f8b0:4864:20::42a]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1w8Eao-0005N1-6c for qemu-devel@nongnu.org; Thu, 02 Apr 2026 05:44:04 -0400 Received: by mail-pf1-x42a.google.com with SMTP id d2e1a72fcca58-8296dabef74so679591b3a.1 for ; Thu, 02 Apr 2026 02:44:01 -0700 (PDT) Received: from [172.17.0.5] ([168.126.243.22]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-82cf9c6ad8asm2668477b3a.40.2026.04.02.02.43.58 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 02 Apr 2026 02:44:00 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1775123041; x=1775727841; darn=nongnu.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=wp610CTuY5BtVJCvmliEvcgHSUgtMv4PTZfRqvUtBfw=; b=glYwg7GGgpR9PL2EHrBVAOw4dg2DY3J/UBGjPbZJKgZsazVS2aJyDq0SJIgSGbOWrt hAxgFpoo/QGYpHerKjhPQTX4XYVRlS5qi9HTxinlo0T3ig/06NZzm8/TgaUgXB8+05Y5 g/aJbL9h6mE/EasSdB8tdCvBVAXpza1fp2NX2UXWMoTvdOGTDlj4cgxhNgU3eOcmYKAx qZI7XLdQku8AptuSMGckohENIJq24cA/mPUO4eDLpF+QZLi/vCd7jOmOorfaFGrFPbKS xREz4aWSkamWwU+TEFzkxFiVhBT8PbXlAgahfrMkxU10ilSXFpcQLB4sqy9SO19D1PVF oCzQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1775123041; x=1775727841; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-gg:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to; bh=wp610CTuY5BtVJCvmliEvcgHSUgtMv4PTZfRqvUtBfw=; b=XNiyRrbM+TbT12vPsYoJwXvZPumqAoz5PRwHhDUIiesBC+qUh8C23meiVtb3Ex1n79 UD0xt9Hkq6miFQ/f3zvs3KXYSHD+p2SN0f+IFyjvAa63J8ccG6/zLMY105Lbw7xqv3TN sHrdhgMBuelv7B3iR+7H0PkJeFpBmnfrnTLj/vg6wBB9Ggng7EZwMwFhfn4eIXpMn2bN Hc5RATRrxVAq4HlOv3twqHciHXyXH4gOTx5iRfd2YVUzBOsgpLjlrAj7ISfxpjNw+Xoe n4XbsYVUIe2uzULoZlqiCUOTSvU3uTZ6HeowdqVT6VVNJtqODrsCsMa1co8rj29XJM2e 9rmA== X-Gm-Message-State: AOJu0YzksRWBKyMdN7vs63jWPkHdGOBlCsZCPZDZOfQ3/pCThpyQMWJE aQ6+ECfSRNt28lxrImVRBvMjaYq8oyuNWPiBymJOqssvUJ5xdpk9t6yO X-Gm-Gg: ATEYQzyO/hH3OYjpVKNAS7drX3AupzPXsYjg/4hNmW1CK9QIxKfRlknqS3cFDku28JR TUdp8e5eQybfnuxxWfE74oxAOrJtv0n80k3mUfBJRzKoqFDw5NMycUw5lNyjOjJjsPNhuSBmKM4 YM8DyiO6QOxLwRyKtblhSDzjfxthSOiKYmsH/LtTpouefEQ1pjwg5LMYq7/GbrefRrwC7B4zzdM KJNYcSacV+vfSrK27A/cKqs8Ki90DQ60KI+91azZx6ISdrSgri72ABS2BGcXdlIhvn2cH4qU0Px qGey4k4gtDEvc0cONHE5xuKG29tijo2Jtt9P3ZjrhRY/57H8p0VPBv9h5gaQvbrp3faJOF4pUUw KAvCIjfwDU52+kaSaMPe0tIhiJw71HlQ3lUM/Cblt8oy/25/jN2h4lrsKu48ctQYJPNy0AaB2ka EiKVd2YqcJMstezj/DwHLqtmn9Kg1Jfhf+TbOGw1cZ X-Received: by 2002:a05:6a00:8008:b0:824:93e4:2ddf with SMTP id d2e1a72fcca58-82cfb86f42bmr2864829b3a.13.1775123040848; Thu, 02 Apr 2026 02:44:00 -0700 (PDT) From: Jaemyung Lee X-Google-Original-From: Jaemyung Lee Date: Thu, 02 Apr 2026 18:43:46 +0900 Subject: [PATCH 2/5] hw/ufs: Modify flag handling operation MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260402-write_booster-v1-2-e4fed1df6c7e@samsung.com> References: <20260402-write_booster-v1-0-e4fed1df6c7e@samsung.com> In-Reply-To: <20260402-write_booster-v1-0-e4fed1df6c7e@samsung.com> To: qemu-devel@nongnu.org Cc: Jeuk Kim , Kevin Wolf , Hanna Reitz , qemu-block@nongnu.org, Fabiano Rosas , Laurent Vivier , Paolo Bonzini , Jaemyung Lee X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1775123032; l=6656; i=jaemyung.lee@samsung.com; s=20260402; h=from:subject:message-id; bh=UwQldvutZu9HqLXksjdiAk3IKzXkRCngBaBlZ026a4E=; b=0bN/XtTRtEN1LXvZZnTKvHZfSmKcAqHBEIgpqvBbnYlsT4sbZ/FwEf87VA6/nQwPEl+uhuPei MKNP25e1+6XCdXigof5fotvoYDPTpbJSB1Li//DTOaRpvzoyQrvGftd X-Developer-Key: i=jaemyung.lee@samsung.com; a=ed25519; pk=bZPd7A/kteUO62FfUM6IrI1LuBPe5QrcqfvsitM1ZjE= 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=2607:f8b0:4864:20::42a; envelope-from=ldc.jml@gmail.com; helo=mail-pf1-x42a.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-Mailman-Approved-At: Thu, 02 Apr 2026 09:51:38 -0400 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 @gmail.com) X-ZM-MESSAGEID: 1775137994610154100 Change internal flag handling operation same as attribute's In UFS device, some flag queries directly trigger specific device behaviour like attribute's, not only changes the internal values. So restructure flag query processing functions same as attribute processing, to facilitate linking detailed implementations based on individual flag value changes. Signed-off-by: Jaemyung Lee --- hw/ufs/ufs.c | 152 ++++++++++++++++++++++++++++++++++++++++++++++---------= ---- 1 file changed, 119 insertions(+), 33 deletions(-) diff --git a/hw/ufs/ufs.c b/hw/ufs/ufs.c index b2b70c8b38ebecd8d49ecce288614d55efd90f2e..69f82ab462d135fe6cda479891f= 9d8f26d19be9a 100644 --- a/hw/ufs/ufs.c +++ b/hw/ufs/ufs.c @@ -1021,6 +1021,122 @@ static inline QueryRespCode ufs_flag_check_idn_vali= d(uint8_t idn, int op) return UFS_QUERY_RESULT_SUCCESS; } =20 +static uint32_t ufs_read_flag_value(UfsHc *u, uint8_t idn) +{ + switch (idn) { + case UFS_QUERY_FLAG_IDN_FDEVICEINIT: + return u->flags.device_init; + case UFS_QUERY_FLAG_IDN_PERMANENT_WPE: + return u->flags.permanent_wp_en; + case UFS_QUERY_FLAG_IDN_PWR_ON_WPE: + return u->flags.power_on_wp_en; + case UFS_QUERY_FLAG_IDN_BKOPS_EN: + return u->flags.background_ops_en; + case UFS_QUERY_FLAG_IDN_LIFE_SPAN_MODE_ENABLE: + return u->flags.device_life_span_mode_en; + case UFS_QUERY_FLAG_IDN_PURGE_ENABLE: + return u->flags.purge_enable; + case UFS_QUERY_FLAG_IDN_REFRESH_ENABLE: + return u->flags.refresh_enable; + case UFS_QUERY_FLAG_IDN_FPHYRESOURCEREMOVAL: + return u->flags.phy_resource_removal; + case UFS_QUERY_FLAG_IDN_BUSY_RTC: + return u->flags.busy_rtc; + case UFS_QUERY_FLAG_IDN_PERMANENTLY_DISABLE_FW_UPDATE: + return u->flags.permanently_disable_fw_update; + case UFS_QUERY_FLAG_IDN_WB_EN: + return u->flags.wb_en; + case UFS_QUERY_FLAG_IDN_WB_BUFF_FLUSH_EN: + return u->flags.wb_buffer_flush_en; + case UFS_QUERY_FLAG_IDN_WB_BUFF_FLUSH_DURING_HIBERN8: + return u->flags.wb_buffer_flush_during_hibernate; + case UFS_QUERY_FLAG_IDN_UNPIN_EN: + return u->flags.unpin_en; + default: + g_assert_not_reached(); + return 0; + } +} + +static QueryRespCode ufs_write_flag_value(UfsHc *u, uint8_t idn, uint8_t v= alue) +{ + switch (idn) { + case UFS_QUERY_FLAG_IDN_FDEVICEINIT: + u->flags.device_init =3D 0; + break; + case UFS_QUERY_FLAG_IDN_PERMANENT_WPE: + u->flags.permanent_wp_en =3D value; + break; + case UFS_QUERY_FLAG_IDN_PWR_ON_WPE: + u->flags.power_on_wp_en =3D value; + break; + case UFS_QUERY_FLAG_IDN_BKOPS_EN: + u->flags.background_ops_en =3D value; + break; + case UFS_QUERY_FLAG_IDN_LIFE_SPAN_MODE_ENABLE: + u->flags.device_life_span_mode_en =3D value; + break; + case UFS_QUERY_FLAG_IDN_PURGE_ENABLE: + u->flags.purge_enable =3D value; + break; + case UFS_QUERY_FLAG_IDN_REFRESH_ENABLE: + u->flags.refresh_enable =3D value; + break; + case UFS_QUERY_FLAG_IDN_FPHYRESOURCEREMOVAL: + u->flags.phy_resource_removal =3D value; + break; + case UFS_QUERY_FLAG_IDN_PERMANENTLY_DISABLE_FW_UPDATE: + u->flags.permanently_disable_fw_update =3D value; + break; + case UFS_QUERY_FLAG_IDN_WB_EN: + u->flags.wb_en =3D value; + break; + case UFS_QUERY_FLAG_IDN_WB_BUFF_FLUSH_EN: + u->flags.wb_buffer_flush_en =3D value; + break; + case UFS_QUERY_FLAG_IDN_WB_BUFF_FLUSH_DURING_HIBERN8: + u->flags.wb_buffer_flush_during_hibernate =3D value; + break; + default: + return UFS_QUERY_RESULT_INVALID_VALUE; + } + + return UFS_QUERY_RESULT_SUCCESS; +} + +static QueryRespCode ufs_exec_query_flag(UfsRequest *req, int op) +{ + UfsHc *u =3D req->hc; + uint8_t idn =3D req->req_upiu.qr.idn; + uint8_t value; + QueryRespCode ret; + + ret =3D ufs_flag_check_idn_valid(idn, op); + if (ret) { + return ret; + } + + if (op =3D=3D UFS_QUERY_FLAG_READ) { + value =3D ufs_read_flag_value(u, idn); + ret =3D UFS_QUERY_RESULT_SUCCESS; + } else if (op =3D=3D UFS_QUERY_FLAG_SET) { + value =3D 1; + ret =3D ufs_write_flag_value(u, idn, value); + } else if (op =3D=3D UFS_QUERY_FLAG_CLEAR) { + value =3D 0; + ret =3D ufs_write_flag_value(u, idn, value); + } else if (op =3D=3D UFS_QUERY_FLAG_TOGGLE) { + value =3D !(ufs_read_flag_value(u, idn)); + ret =3D ufs_write_flag_value(u, idn, value); + } else { + trace_ufs_err_query_invalid_opcode(op); + return UFS_QUERY_RESULT_INVALID_OPCODE; + } + + req->rsp_upiu.qr.value =3D cpu_to_be32(value); + return ret; +} + static const int attr_permission[UFS_QUERY_ATTR_IDN_COUNT] =3D { /* booting is not supported */ [UFS_QUERY_ATTR_IDN_BOOT_LU_EN] =3D UFS_QUERY_ATTR_READ, @@ -1103,39 +1219,6 @@ static inline QueryRespCode ufs_attr_check_idn_valid= (uint8_t idn, int op) return UFS_QUERY_RESULT_SUCCESS; } =20 -static QueryRespCode ufs_exec_query_flag(UfsRequest *req, int op) -{ - UfsHc *u =3D req->hc; - uint8_t idn =3D req->req_upiu.qr.idn; - uint32_t value; - QueryRespCode ret; - - ret =3D ufs_flag_check_idn_valid(idn, op); - if (ret) { - return ret; - } - - if (idn =3D=3D UFS_QUERY_FLAG_IDN_FDEVICEINIT) { - value =3D 0; - } else if (op =3D=3D UFS_QUERY_FLAG_READ) { - value =3D *(((uint8_t *)&u->flags) + idn); - } else if (op =3D=3D UFS_QUERY_FLAG_SET) { - value =3D 1; - } else if (op =3D=3D UFS_QUERY_FLAG_CLEAR) { - value =3D 0; - } else if (op =3D=3D UFS_QUERY_FLAG_TOGGLE) { - value =3D *(((uint8_t *)&u->flags) + idn); - value =3D !value; - } else { - trace_ufs_err_query_invalid_opcode(op); - return UFS_QUERY_RESULT_INVALID_OPCODE; - } - - *(((uint8_t *)&u->flags) + idn) =3D value; - req->rsp_upiu.qr.value =3D cpu_to_be32(value); - return UFS_QUERY_RESULT_SUCCESS; -} - static inline uint8_t ufs_read_device_temp(UfsHc *u) { uint8_t feat_sup =3D u->device_desc.ufs_features_support; @@ -1300,6 +1383,9 @@ static QueryRespCode ufs_write_attr_value(UfsHc *u, u= int8_t idn, uint32_t value) case UFS_QUERY_ATTR_IDN_TIMESTAMP: u->attributes.timestamp =3D cpu_to_be64(value); break; + default: + g_assert_not_reached(); + return 0; } return UFS_QUERY_RESULT_SUCCESS; } --=20 2.48.1 From nobody Sat Apr 11 18:37:57 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=gmail.com ARC-Seal: i=1; a=rsa-sha256; t=1775138050; cv=none; d=zohomail.com; s=zohoarc; b=HikFVDvn3bzIkwKjcnQPZCsrnZVOIhT4RoUjbitmMuY+LAgsHsm28X/GXdZhmJ96Vv3tGQq1ticSBBTDoL97YQcijlSYS8kHGcZcx087L/xRbD+z8lzJIfDIjpPZDK8SO0vTWKNYINuq325+9aw+7RQewDoSQPX/02oAvZHMGxE= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1775138050; 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=CksdsVsNY6Vvge/pF7DyPU97nKOJ2uT4c+sk2AA7088=; b=lYNaNpKxrrCZ66hK5g+mVdtHjDX9Xit1p+sYQIm0f72ayssfkMNowqKAZn53+OvDo+1f0nKGi9pJtIh9v2IWQWr0fmAXog6gs1ZWzEgF/F4RXRuukhXLBLFkF4RAS5nKON7DDDSaGpy/0Xd8zkCTn+YOJNf5qIcxD5WXJuZMo4k= 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 lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 177513805007051.655099769011144; Thu, 2 Apr 2026 06:54:10 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1w8ISr-0003I7-KN; Thu, 02 Apr 2026 09:52:06 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1w8Eav-0001D9-Ul for qemu-devel@nongnu.org; Thu, 02 Apr 2026 05:44:10 -0400 Received: from mail-pf1-x42e.google.com ([2607:f8b0:4864:20::42e]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1w8Ear-0005Ng-CL for qemu-devel@nongnu.org; Thu, 02 Apr 2026 05:44:09 -0400 Received: by mail-pf1-x42e.google.com with SMTP id d2e1a72fcca58-827270d50d4so635116b3a.3 for ; Thu, 02 Apr 2026 02:44:04 -0700 (PDT) Received: from [172.17.0.5] ([168.126.243.22]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-82cf9c6ad8asm2668477b3a.40.2026.04.02.02.44.01 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 02 Apr 2026 02:44:03 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1775123044; x=1775727844; darn=nongnu.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=CksdsVsNY6Vvge/pF7DyPU97nKOJ2uT4c+sk2AA7088=; b=UURZvFtRPNPUtad4RPbn7E/qNtpGehLzSSuUtRPc2Dd1uP55FnxTFDzh4uszo0y019 LMKY2wM21GA7f0hYbCV1KqeKJ+zQfn5QjOWsKQVlrC0TAMBN01t1PRckx/zOb2QCbUvg IGelurMNCmzjnRT98/FhhI/zlIl1UA9zIj/AmXjsUthoOdvK4W/d8Kez25504d10cByx UgSQg/KfVsKXxbFhalvZn8OJEnvOQPr6qit/7KMSJY5DKi27yQOgvHn9echBqujhmzHW KVcpC8YiQXe7WRXC9ii1E4zrP+6L0IpyICfAwIc40HmJTxCmySdVa5wf46ZVGZ0VDAFG Jghw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1775123044; x=1775727844; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-gg:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to; bh=CksdsVsNY6Vvge/pF7DyPU97nKOJ2uT4c+sk2AA7088=; b=awsWH/IAbg8AtubKU3aUlJIeJh61KNNaHfZ9A/oWAkUaQCB0Z37WvfJTRa8w93RpLU vF1uwL1k/GXDrdC6vGPR3T4oYDtZaAAlaU6TeB/qO4IMGd6SFNXhqK6Io2tgBuFDgk6i cNdKWo8M0kPI0yAV5vTOB4sngrJ9qSfsIyJlcdB5vj5w1mEM2KP8rJeGBiihcNUiiHTY 41IinK1F+Noyksdz0qVcvoecnvBl3Vv6xKdah+XZm5ZKDc/BVWgArh89puqb+KiKZVvl uqGDShTClQw/xwr99uKHxQrwAtGeuoxdOTgMQhaGYdBZgatLamFVoyQQLXaAIZ7xDYqh s8fA== X-Gm-Message-State: AOJu0Yzm8ODos5wwnElzrGrKvLk/LtgmXaGUs0hgJFA28JKZtHTvSaMX sP8rim7pCGJqx/7ASAsLOo6fa6YNXoi/Bvc2MdLiD43+GZ5axNRKCCq3 X-Gm-Gg: ATEYQzy7TDbZt4+qzQr0pMrVq0++GA61PNNV0Rt4izTF56qiqwc1H54aOMj9UXBEnG8 78bDZb8GM6XY6xKSOqdDSoN2Aurv3g0yxrdcnK1fyGU0TYplPHekUH+txdl4bxoi9aBk2B0/hBO UDziBhiNPmRJzEdPrMfb2recRvlBufp7jlkFnB8ocfYsgJy26W5OjDJcpJMvElexfR/ISOceike jVDOgEbTEGBdpGBoKCx0P6Qlv8N8ZIBxf6s3E2nBsDTWpMht069QaLp271N/f8AYBPHZUk03rpN A/8J4Xf32ggWFJhSkNTy+Sk72btMwSErcvv3jb5F1mohg78abTCXQrsO1hqclguNlsqSYgVSD4H F4Gp9obCGlJGMuFV6sXBdkycy5R4WLh7Kj6tHML2z2ODj+Cmb7zCd7bs73ovBRMz24SDslwxKR2 frMiR7hlR5AHHUFz8Ebfz5uyxMWuvD5w== X-Received: by 2002:a05:6a00:2406:b0:829:7d31:dd9a with SMTP id d2e1a72fcca58-82ce8ae3016mr7540021b3a.51.1775123043783; Thu, 02 Apr 2026 02:44:03 -0700 (PDT) From: Jaemyung Lee X-Google-Original-From: Jaemyung Lee Date: Thu, 02 Apr 2026 18:43:47 +0900 Subject: [PATCH 3/5] hw/ufs: Add idle operation MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260402-write_booster-v1-3-e4fed1df6c7e@samsung.com> References: <20260402-write_booster-v1-0-e4fed1df6c7e@samsung.com> In-Reply-To: <20260402-write_booster-v1-0-e4fed1df6c7e@samsung.com> To: qemu-devel@nongnu.org Cc: Jeuk Kim , Kevin Wolf , Hanna Reitz , qemu-block@nongnu.org, Fabiano Rosas , Laurent Vivier , Paolo Bonzini , Jaemyung Lee X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1775123032; l=2916; i=jaemyung.lee@samsung.com; s=20260402; h=from:subject:message-id; bh=/YX9M0/8utB10RyJw1Al6+6NhTczJLb9C2D6zloxtfQ=; b=MaUmkDUTMfV4ai3EE2sxjNQfLI2ZCCsmJroS/6g1hn3HdGK2LwFbFpi/I1WQw2yb0Ls9Hg10i Ew5K1qMNhKZDA+DkZtf+Opz1zH/oJUPe2lcKWZuM68U1yA36n5BV+WU X-Developer-Key: i=jaemyung.lee@samsung.com; a=ed25519; pk=bZPd7A/kteUO62FfUM6IrI1LuBPe5QrcqfvsitM1ZjE= 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=2607:f8b0:4864:20::42e; envelope-from=ldc.jml@gmail.com; helo=mail-pf1-x42e.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-Mailman-Approved-At: Thu, 02 Apr 2026 09:51:40 -0400 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 @gmail.com) X-ZM-MESSAGEID: 1775138051306158500 When no I/O occurs, the UFS Device performs various internal operations. To emulate this, adds a timer that periodically checks the current I/O status of the device and call the ufs_process_idle() function when idle. Signed-off-by: Jaemyung Lee --- hw/ufs/ufs.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++ hw/ufs/ufs.h | 2 ++ 2 files changed, 49 insertions(+) diff --git a/hw/ufs/ufs.c b/hw/ufs/ufs.c index 69f82ab462d135fe6cda479891f9d8f26d19be9a..111ce3c3a0b03a1ead722f48b79= 9e3ed0c403cce 100644 --- a/hw/ufs/ufs.c +++ b/hw/ufs/ufs.c @@ -1801,6 +1801,47 @@ static void ufs_sendback_req(void *opaque) ufs_irq_check(u); } =20 +static void ufs_process_idle(UfsHc *u) +{ + /* Currently do nothing */ + return; +} + +static inline bool ufs_check_idle(UfsHc *u) +{ + return !u->reg.utrldbr; +} + +static inline bool ufs_mcq_check_idle(UfsHc *u) +{ + for (int i =3D 0; i < ARRAY_SIZE(u->sq); i++) { + if (!ufs_mcq_sq_empty(u, i)) { + return false; + } + } + + for (int i =3D 0; i < ARRAY_SIZE(u->cq); i++) { + if (!ufs_mcq_cq_empty(u, i)) { + return false; + } + } + + return true; +} + +#define UFS_IDLE_TIMER_TICK 100 /* 0.1s */ +static void ufs_idle_timer_cb(void *opaque) +{ + UfsHc *u =3D opaque; + int64_t now =3D qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL_RT); + + if (ufs_check_idle(u) && ufs_mcq_check_idle(u)) { + ufs_process_idle(u); + } + + timer_mod(&u->idle_timer, now + UFS_IDLE_TIMER_TICK); +} + static bool ufs_check_constraints(UfsHc *u, Error **errp) { if (u->params.nutrs > UFS_MAX_NUTRS) { @@ -1863,6 +1904,7 @@ static void ufs_init_hc(UfsHc *u) uint32_t cap =3D 0; uint32_t mcqconfig =3D 0; uint32_t mcqcap =3D 0; + int64_t now =3D qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL_RT); =20 u->reg_size =3D pow2ceil(ufs_reg_size(u)); =20 @@ -1959,6 +2001,9 @@ static void ufs_init_hc(UfsHc *u) * dynamically */ u->temperature =3D UFS_TEMPERATURE; + + timer_init_ms(&u->idle_timer, QEMU_CLOCK_VIRTUAL_RT, ufs_idle_timer_cb= , u); + timer_mod(&u->idle_timer, now + UFS_IDLE_TIMER_TICK); } =20 static void ufs_realize(PCIDevice *pci_dev, Error **errp) @@ -1986,6 +2031,8 @@ static void ufs_exit(PCIDevice *pci_dev) { UfsHc *u =3D UFS(pci_dev); =20 + timer_del(&u->idle_timer); + qemu_free_irq(u->irq); =20 qemu_bh_delete(u->doorbell_bh); diff --git a/hw/ufs/ufs.h b/hw/ufs/ufs.h index 13d964c5ae5ec430a98b2ef71987cb9279e9a317..b5f040302129f4d02732ddd20ef= 82eb33c41922a 100644 --- a/hw/ufs/ufs.h +++ b/hw/ufs/ufs.h @@ -148,6 +148,8 @@ typedef struct UfsHc { UfsCq *cq[UFS_MAX_MCQ_QNUM]; =20 uint8_t temperature; + + QEMUTimer idle_timer; } UfsHc; =20 static inline uint32_t ufs_mcq_sq_tail(UfsHc *u, uint32_t qid) --=20 2.48.1 From nobody Sat Apr 11 18:37:57 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=gmail.com ARC-Seal: i=1; a=rsa-sha256; t=1775137968; cv=none; d=zohomail.com; s=zohoarc; b=WinQk5F/3+XND/qovHdsNYi7k+wCHK3/NMDsf2SfxUPBkPK5vNe0F2iVD8tJLXhwYZbkTyL9cQKFMO09RZ9R/lAfiC+AkX8BSkkvT4TmI8jt97UOSWTXezZk413OCNCtTS0MNeZ3qdX/gtkQrsVuUVkoRPkgIZuD2E4K/C1jGwQ= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1775137968; 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=Bfb8YXGRc71OupZ3vGGVhFCM1RFW8zaN1q08/2Gx108=; b=GD5axh3At2OTevT9PVk8JTIi0WS/tcGt7CTFYg39L3PPqCe/k2V2gtdI/1sFYh6r0sFJ7wd4YaBmHsh7kv+eZe4zoIhKSm1/lV0e9TttWNCaZ8Qt127fxZNobk0NNFlFFgNDBDTNYnztmZunwdIJP/SjL3I/mhqTRF0N4FTPP+Y= 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 lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1775137968893965.7129445618306; Thu, 2 Apr 2026 06:52:48 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1w8ISn-0003GB-Eh; Thu, 02 Apr 2026 09:52:03 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1w8Eay-0001Dx-Jt for qemu-devel@nongnu.org; Thu, 02 Apr 2026 05:44:14 -0400 Received: from mail-pf1-x429.google.com ([2607:f8b0:4864:20::429]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1w8Eau-0005OO-8A for qemu-devel@nongnu.org; Thu, 02 Apr 2026 05:44:11 -0400 Received: by mail-pf1-x429.google.com with SMTP id d2e1a72fcca58-82cf83bf375so294921b3a.0 for ; Thu, 02 Apr 2026 02:44:07 -0700 (PDT) Received: from [172.17.0.5] ([168.126.243.22]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-82cf9c6ad8asm2668477b3a.40.2026.04.02.02.44.04 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 02 Apr 2026 02:44:06 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1775123047; x=1775727847; darn=nongnu.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=Bfb8YXGRc71OupZ3vGGVhFCM1RFW8zaN1q08/2Gx108=; b=nQqfzBnJnnBw6nk5za1aovPUvhKDodaVRWEv6iPKO0hWHm5ixKqV7pHsbwZNRXWRUy yO4jcKuz2cF41n6KhwYw7tMkJ2JrkItobPytEHmku0mF0fms6BAv4rSmmGp2sbmoIDYt iLmkSyKQxuMHIIkbxYqaxcwqCEvCcAxmKCmuoisc17G9O9hWSeYMgaQABPpVOzGWfsYj 7Q8LyRptIlveZp68sgkiUgCyeXVhT5arM4ULt3VeTlpMY2Olj3yD6bJejBI3pYzAu19S 8f9FD8KS3Dj692UAVUU36HVxuWnB2hw8rOHMmflCnOZX1LC85fLSmfVR1J8TRQvbATqe DIoA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1775123047; x=1775727847; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-gg:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to; bh=Bfb8YXGRc71OupZ3vGGVhFCM1RFW8zaN1q08/2Gx108=; b=owpFpUDLcaeXVEQNljklLmUZfaFZnCTi25bgB3ac6WvBvH1okdzjH1uSUfC6Bmbr+5 6m/F2r40YRrLSOPdOyI5XJFR3vW/IdPBbjmFG4pY1F+M7SzDVSPlvQB3uxxgaIoP9hqC ee75uqP4HkcnxMtPbvZuCPFp5NkB985AMSeD5NzUlY08EzdQtNdBkhGKaUpsAO+bjASk 929Av8dnbPecnu+Hd2F9QDJ31iz659h2fw2MYkNDK2TafWJO3fV/TFZg/oK2HGNwtQDc VJS/YjZvJ+8CMqxCQ+dbzQrSzKPoqEJpQVGVHil196XOfoZ4fkBy3VRY7NV02QZw6R2t 8rJQ== X-Gm-Message-State: AOJu0YzclvUW9R2Je1s+TqHeT2Y62Go40VYT5rVCBQ9tAqiJAI6V2EoN 7RbZYVX/SKaWz7dCBqLnibFnlMZWGlAIIMGqOVKaf3G631K1yVQEbGJ9 X-Gm-Gg: ATEYQzwiAsYYOw9JFYkADAepJ5h7FBiWf+Z2NV+o+wUnxbrmX1VCex5m3PEQMN5I5B1 w1aK7qORGLtAZ26+ScWq6evT3X8mvkViXJDP8VzkeoFMGJvrbnJSUODNlDomAR1fIkCGxmmMN5A fXBPh0KHh+JBqiRzCDnHjsRVaCydQlmw0k1cMI18dBoKXxPYCaic6aokhlxpZoRxkqWj+Eq7Cvq fi8ceNsOYG52MhB/cN0gSjkhNW9CO12TsU+p3qR/b48mPxGg82rO1D40g2CPgHUvoQVppnYPYs7 L+gDiN39Fqus0xefSF0/Abd0k8QoR79SInAkCtgG1c3l1T9X46PD+gutLW3RAvGgYC9ktDtuNJ5 iA5G5d5wEDNoJP8fl+u8aKG74bWq52i6czPMuphycT2L7N1ZUReAppG1jibo07YDmHMuCX4M20r ZpzNfmzOuWEu88CI4zaAb1O+24ZV+WF8DiTXwNDBSF X-Received: by 2002:a05:6a00:448d:b0:82c:70a8:faec with SMTP id d2e1a72fcca58-82ce8960f03mr7774704b3a.21.1775123046654; Thu, 02 Apr 2026 02:44:06 -0700 (PDT) From: Jaemyung Lee X-Google-Original-From: Jaemyung Lee Date: Thu, 02 Apr 2026 18:43:48 +0900 Subject: [PATCH 4/5] hw/ufs: Add UFS Write Booster Support MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260402-write_booster-v1-4-e4fed1df6c7e@samsung.com> References: <20260402-write_booster-v1-0-e4fed1df6c7e@samsung.com> In-Reply-To: <20260402-write_booster-v1-0-e4fed1df6c7e@samsung.com> To: qemu-devel@nongnu.org Cc: Jeuk Kim , Kevin Wolf , Hanna Reitz , qemu-block@nongnu.org, Fabiano Rosas , Laurent Vivier , Paolo Bonzini , Jaemyung Lee X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1775123032; l=25227; i=jaemyung.lee@samsung.com; s=20260402; h=from:subject:message-id; bh=+yxVF3yyPUOckIo8ni1rA7x2VicWb/OlpmcBy20wq50=; b=zujFV2ZcMzP+2vtX+eS1R+xZaWAFm1SQac8+pI4HPa4z/vhxhfoHvG25DL9Ou6Nx+Smjsu+nz jBfEyHHicTpAITm5DR4d/MOT0CoHjEckaBUugmDEx+mDsCniodHacKM X-Developer-Key: i=jaemyung.lee@samsung.com; a=ed25519; pk=bZPd7A/kteUO62FfUM6IrI1LuBPe5QrcqfvsitM1ZjE= 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=2607:f8b0:4864:20::429; envelope-from=ldc.jml@gmail.com; helo=mail-pf1-x429.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-Mailman-Approved-At: Thu, 02 Apr 2026 09:51:39 -0400 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 @gmail.com) X-ZM-MESSAGEID: 1775137970277154100 Add UFS Write Booster implementation which follows UFS 4.1 Spec. Signed-off-by: Jaemyung Lee --- hw/ufs/lu.c | 85 ++++++++++++++ hw/ufs/ufs.c | 328 ++++++++++++++++++++++++++++++++++++++++++++++++= +--- hw/ufs/ufs.h | 39 +++++++ include/block/ufs.h | 51 ++++++++ 4 files changed, 488 insertions(+), 15 deletions(-) diff --git a/hw/ufs/lu.c b/hw/ufs/lu.c index 3f3c9589cee57ae3e77e2f486476d5fcec204d80..7c25c15169f76f22059c3ae03df= c1f21b0e41e8d 100644 --- a/hw/ufs/lu.c +++ b/hw/ufs/lu.c @@ -247,6 +247,89 @@ static UfsReqResult ufs_emulate_scsi_cmd(UfsLu *lu, Uf= sRequest *req) return UFS_REQUEST_SUCCESS; } =20 +#define UFS_GROUP_NUMBER_MASK 0x1F +#define UFS_WB_GROUP_NUMBER_PINNED 0x18 /* 11000b */ +static bool ufs_wb_check_write_pinned(UfsHc *u, UfsRequest *req) +{ + uint8_t group_number =3D req->req_upiu.sc.cdb[6] & UFS_GROUP_NUMBER_MA= SK; + + if (u->attributes.wb_buffer_partial_flush_mode !=3D UFS_WB_FLUSH_PINNE= D) { + return false; + } + + return (group_number =3D=3D UFS_WB_GROUP_NUMBER_PINNED); +} + +#define UFS_WB_TOTAL_WRITTEN_SHIFT 21 /* 10MB */ +static void ufs_wb_process_write_pinned(UfsHc *u, UfsRequest *req) +{ + UfsWb *wb =3D &u->wb; + uint64_t remain_bytes, remain_data; + uint32_t total_written; + + if (!wb->pinned_curr_bytes) { + return; + } + + if (wb->pinned_used_bytes >=3D wb->pinned_curr_bytes) { + return; + } + + remain_bytes =3D wb->pinned_curr_bytes - wb->pinned_used_bytes; + if (remain_bytes >=3D req->data_len) { + wb->pinned_total_written_bytes +=3D req->data_len; + wb->pinned_used_bytes +=3D req->data_len; + remain_data =3D 0; + + } else { + wb->pinned_total_written_bytes +=3D remain_bytes; + wb->pinned_used_bytes +=3D remain_bytes; + remain_data =3D req->data_len - remain_bytes; + } + + total_written =3D wb->pinned_total_written_bytes >> UFS_WB_TOTAL_WRITT= EN_SHIFT; + u->attributes.pinned_wb_cumm_written_size =3D cpu_to_be32(total_writte= n); + + remain_bytes =3D wb->curr_bytes - wb->used_bytes; + wb->used_bytes +=3D MIN(remain_bytes, remain_data); +} + +static void ufs_wb_process_write_normal(UfsHc *u, UfsRequest *req) +{ + UfsWb *wb =3D &u->wb; + uint64_t curr_bytes, used_bytes, remain_bytes; + + if (!wb->curr_bytes) { + return; + } + + curr_bytes =3D wb->curr_bytes - wb->pinned_curr_bytes; + used_bytes =3D wb->used_bytes - wb->pinned_used_bytes; + + if (used_bytes >=3D curr_bytes) { + return; + } + + remain_bytes =3D curr_bytes - used_bytes; + wb->used_bytes +=3D MIN(remain_bytes, req->data_len); +} + +static void ufs_wb_process_write_cmd(UfsRequest *req) +{ + uint8_t command =3D req->req_upiu.sc.cdb[0]; + UfsHc *u =3D req->hc; + + if (command !=3D WRITE_10 || !u->flags.wb_en) { + return; + } + + if (ufs_wb_check_write_pinned(u, req)) { + ufs_wb_process_write_pinned(u, req); + } else { + ufs_wb_process_write_normal(u, req); + } +} + static UfsReqResult ufs_process_scsi_cmd(UfsLu *lu, UfsRequest *req) { uint8_t task_tag =3D req->req_upiu.header.task_tag; @@ -261,6 +344,8 @@ static UfsReqResult ufs_process_scsi_cmd(UfsLu *lu, Ufs= Request *req) return ufs_emulate_scsi_cmd(lu, req); } =20 + ufs_wb_process_write_cmd(req); + SCSIRequest *scsi_req =3D scsi_req_new(lu->scsi_dev, task_tag, lu->lun, req->req_upiu.sc.cdb, UFS_CDB_SIZE, req); diff --git a/hw/ufs/ufs.c b/hw/ufs/ufs.c index 111ce3c3a0b03a1ead722f48b799e3ed0c403cce..3c58760663d2752c3478d83a067= 5b879c7f5c6f2 100644 --- a/hw/ufs/ufs.c +++ b/hw/ufs/ufs.c @@ -996,11 +996,15 @@ static const int flag_permission[UFS_QUERY_FLAG_IDN_C= OUNT] =3D { [UFS_QUERY_FLAG_IDN_FPHYRESOURCEREMOVAL] =3D UFS_QUERY_FLAG_READ, [UFS_QUERY_FLAG_IDN_BUSY_RTC] =3D UFS_QUERY_FLAG_READ, [UFS_QUERY_FLAG_IDN_PERMANENTLY_DISABLE_FW_UPDATE] =3D UFS_QUERY_FLAG_= READ, - /* Write Booster is not supported */ - [UFS_QUERY_FLAG_IDN_WB_EN] =3D UFS_QUERY_FLAG_READ, - [UFS_QUERY_FLAG_IDN_WB_BUFF_FLUSH_EN] =3D UFS_QUERY_FLAG_READ, + [UFS_QUERY_FLAG_IDN_WB_EN] =3D UFS_QUERY_FLAG_READ | UFS_QUERY_FLAG_SE= T | + UFS_QUERY_FLAG_CLEAR | UFS_QUERY_FLAG_TOG= GLE, + [UFS_QUERY_FLAG_IDN_WB_BUFF_FLUSH_EN] =3D + UFS_QUERY_FLAG_READ | UFS_QUERY_FLAG_SET | UFS_QUERY_FLAG_CLEAR | + UFS_QUERY_FLAG_TOGGLE, [UFS_QUERY_FLAG_IDN_WB_BUFF_FLUSH_DURING_HIBERN8] =3D UFS_QUERY_FLAG_R= EAD, - [UFS_QUERY_FLAG_IDN_UNPIN_EN] =3D UFS_QUERY_FLAG_READ, + [UFS_QUERY_FLAG_IDN_UNPIN_EN] =3D UFS_QUERY_FLAG_READ | UFS_QUERY_FLAG= _SET | + UFS_QUERY_FLAG_CLEAR | + UFS_QUERY_FLAG_TOGGLE, }; =20 static inline QueryRespCode ufs_flag_check_idn_valid(uint8_t idn, int op) @@ -1097,6 +1101,9 @@ static QueryRespCode ufs_write_flag_value(UfsHc *u, u= int8_t idn, uint8_t value) case UFS_QUERY_FLAG_IDN_WB_BUFF_FLUSH_DURING_HIBERN8: u->flags.wb_buffer_flush_during_hibernate =3D value; break; + case UFS_QUERY_FLAG_IDN_UNPIN_EN: + u->flags.unpin_en =3D value; + break; default: return UFS_QUERY_RESULT_INVALID_VALUE; } @@ -1189,16 +1196,20 @@ static const int attr_permission[UFS_QUERY_ATTR_IDN= _COUNT] =3D { [UFS_QUERY_ATTR_IDN_HID_PROG_RATIO] =3D UFS_QUERY_ATTR_READ, [UFS_QUERY_ATTR_IDN_HID_STATE] =3D UFS_QUERY_ATTR_READ, [UFS_QUERY_ATTR_IDN_WB_BUFF_RESIZE_HINT] =3D UFS_QUERY_ATTR_READ, - [UFS_QUERY_ATTR_IDN_WB_BUFF_RESIZE_EN] =3D UFS_QUERY_ATTR_READ, + [UFS_QUERY_ATTR_IDN_WB_BUFF_RESIZE_EN] =3D UFS_QUERY_ATTR_WRITE, [UFS_QUERY_ATTR_IDN_WB_BUFF_RESIZE_STATUS] =3D UFS_QUERY_ATTR_READ, - [UFS_QUERY_ATTR_IDN_WB_BUFF_PARTIAL_FLUSH_MODE] =3D UFS_QUERY_ATTR_REA= D, - [UFS_QUERY_ATTR_IDN_MAX_FIFO_WB_PARTIAL_FLUSH_MODE] =3D UFS_QUERY_ATTR= _READ, + [UFS_QUERY_ATTR_IDN_WB_BUFF_PARTIAL_FLUSH_MODE] =3D + UFS_QUERY_ATTR_READ | UFS_QUERY_ATTR_WRITE, + [UFS_QUERY_ATTR_IDN_MAX_FIFO_WB_PARTIAL_FLUSH_MODE] =3D + UFS_QUERY_ATTR_READ | UFS_QUERY_ATTR_WRITE, [UFS_QUERY_ATTR_IDN_CURR_FIFO_WB_PARTIAL_FLUSH_MODE] =3D UFS_QUERY_ATT= R_READ, [UFS_QUERY_ATTR_IDN_PINNED_WB_BUFF_CURR_ALLOC_UNITS] =3D UFS_QUERY_ATT= R_READ, [UFS_QUERY_ATTR_IDN_PINNED_WB_BUFF_AVAIL_PERCENT] =3D UFS_QUERY_ATTR_R= EAD, [UFS_QUERY_ATTR_IDN_PINNED_WB_CUMM_WRITTEN_SIZE] =3D UFS_QUERY_ATTR_RE= AD, - [UFS_QUERY_ATTR_IDN_PINNED_WB_NUM_ALLOC_UNITS] =3D UFS_QUERY_ATTR_READ, - [UFS_QUERY_ATTR_IDN_NON_PINNED_WB_MIN_NUM_ALLOC_UNITS] =3D UFS_QUERY_A= TTR_READ, + [UFS_QUERY_ATTR_IDN_PINNED_WB_NUM_ALLOC_UNITS] =3D + UFS_QUERY_ATTR_READ | UFS_QUERY_ATTR_WRITE, + [UFS_QUERY_ATTR_IDN_NON_PINNED_WB_MIN_NUM_ALLOC_UNITS] =3D + UFS_QUERY_ATTR_READ | UFS_QUERY_ATTR_WRITE, }; =20 static inline QueryRespCode ufs_attr_check_idn_valid(uint8_t idn, int op) @@ -1238,6 +1249,27 @@ static inline uint8_t ufs_read_device_temp(UfsHc *u) return 0; } =20 +static inline uint32_t ufs_wb_read_flush_status(UfsHc *u) +{ + if (u->attributes.wb_buffer_flush_status =3D=3D UFS_WB_FLUSH_SUSPENDED= || + u->attributes.wb_buffer_flush_status =3D=3D UFS_WB_FLUSH_COMPLETED= || + u->attributes.wb_buffer_flush_status =3D=3D UFS_WB_FLUSH_FAILED) { + u->attributes.wb_buffer_flush_status =3D UFS_WB_FLUSH_IDLE; + } + + return u->attributes.wb_buffer_flush_status; +} + +static inline uint32_t ufs_wb_read_resize_status(UfsHc *u) +{ + if (u->attributes.wb_buffer_resize_status =3D=3D UFS_WB_RESIZE_COMPLET= ED || + u->attributes.wb_buffer_resize_status =3D=3D UFS_WB_RESIZE_FAILED)= { + u->attributes.wb_buffer_resize_status =3D UFS_WB_RESIZE_IDLE; + } + + return u->attributes.wb_buffer_resize_status; +} + static uint32_t ufs_read_attr_value(UfsHc *u, uint8_t idn) { switch (idn) { @@ -1292,7 +1324,7 @@ static uint32_t ufs_read_attr_value(UfsHc *u, uint8_t= idn) case UFS_QUERY_ATTR_IDN_THROTTLING_STATUS: return u->attributes.throttling_status; case UFS_QUERY_ATTR_IDN_WB_FLUSH_STATUS: - return u->attributes.wb_buffer_flush_status; + return ufs_wb_read_flush_status(u); case UFS_QUERY_ATTR_IDN_AVAIL_WB_BUFF_SIZE: return u->attributes.available_wb_buffer_size; case UFS_QUERY_ATTR_IDN_WB_BUFF_LIFE_TIME_EST: @@ -1323,10 +1355,8 @@ static uint32_t ufs_read_attr_value(UfsHc *u, uint8_= t idn) return u->attributes.hid_state; case UFS_QUERY_ATTR_IDN_WB_BUFF_RESIZE_HINT: return u->attributes.wb_buffer_resize_hint; - case UFS_QUERY_ATTR_IDN_WB_BUFF_RESIZE_EN: - return u->attributes.wb_buffer_resize_en; case UFS_QUERY_ATTR_IDN_WB_BUFF_RESIZE_STATUS: - return u->attributes.wb_buffer_resize_status; + return ufs_wb_read_resize_status(u); case UFS_QUERY_ATTR_IDN_WB_BUFF_PARTIAL_FLUSH_MODE: return u->attributes.wb_buffer_partial_flush_mode; case UFS_QUERY_ATTR_IDN_MAX_FIFO_WB_PARTIAL_FLUSH_MODE: @@ -1347,6 +1377,32 @@ static uint32_t ufs_read_attr_value(UfsHc *u, uint8_= t idn) return 0; } =20 +static void ufs_wb_resize_op(UfsHc *u, uint32_t value) +{ + if (u->attributes.wb_buffer_resize_status =3D=3D UFS_WB_RESIZE_IN_PROG= RESS) { + return; + } + + u->attributes.wb_buffer_resize_en =3D value; + u->attributes.wb_buffer_resize_status =3D UFS_WB_RESIZE_IN_PROGRESS; +} + +static void ufs_wb_pinned_max_size(UfsHc *u, uint32_t value) +{ + UfsWb *wb =3D &u->wb; + + u->attributes.pinned_wb_num_alloc_units =3D cpu_to_be32(value); + wb->pinned_max_bytes =3D ufs_unit_to_byte(u, value); +} + +static void ufs_wb_pinned_min_size(UfsHc *u, uint32_t value) +{ + UfsWb *wb =3D &u->wb; + + u->attributes.non_pinned_wb_min_num_alloc_units =3D cpu_to_be32(value); + wb->pinned_min_bytes =3D ufs_unit_to_byte(u, value); +} + static QueryRespCode ufs_write_attr_value(UfsHc *u, uint8_t idn, uint32_t = value) { switch (idn) { @@ -1383,6 +1439,27 @@ static QueryRespCode ufs_write_attr_value(UfsHc *u, = uint8_t idn, uint32_t value) case UFS_QUERY_ATTR_IDN_TIMESTAMP: u->attributes.timestamp =3D cpu_to_be64(value); break; + case UFS_QUERY_ATTR_IDN_WB_BUFF_RESIZE_EN: + if (value >=3D UFS_WB_RESIZE_OP_MAX) { + return UFS_QUERY_RESULT_INVALID_VALUE; + } + ufs_wb_resize_op(u, value); + break; + case UFS_QUERY_ATTR_IDN_WB_BUFF_PARTIAL_FLUSH_MODE: + if (value >=3D UFS_WB_FLUSH_MODE_MAX) { + return UFS_QUERY_RESULT_INVALID_VALUE; + } + u->attributes.wb_buffer_partial_flush_mode =3D value; + break; + case UFS_QUERY_ATTR_IDN_MAX_FIFO_WB_PARTIAL_FLUSH_MODE: + u->attributes.max_fifo_wb_partial_flush_mode =3D cpu_to_be32(value= ); + break; + case UFS_QUERY_ATTR_IDN_PINNED_WB_NUM_ALLOC_UNITS: + ufs_wb_pinned_max_size(u, value); + break; + case UFS_QUERY_ATTR_IDN_NON_PINNED_WB_MIN_NUM_ALLOC_UNITS: + ufs_wb_pinned_min_size(u, value); + break; default: g_assert_not_reached(); return 0; @@ -1801,9 +1878,177 @@ static void ufs_sendback_req(void *opaque) ufs_irq_check(u); } =20 +static inline void ufs_wb_update_avail_buffer(UfsHc *u) +{ + UfsWb *wb =3D &u->wb; + uint64_t non_pinned_curr_bytes, non_pinned_used_bytes; + uint32_t units; + + units =3D ufs_byte_to_unit(u, wb->pinned_curr_bytes); + u->attributes.pinned_wb_buffer_curr_alloc_units =3D cpu_to_be32(units); + + if (!wb->pinned_curr_bytes) + u->attributes.pinned_wb_buffer_avail_percent =3D 0; + else + u->attributes.pinned_wb_buffer_avail_percent =3D + (wb->pinned_curr_bytes - wb->pinned_used_bytes) * 10 / + wb->pinned_curr_bytes; + + non_pinned_curr_bytes =3D wb->curr_bytes - wb->pinned_curr_bytes; + non_pinned_used_bytes =3D wb->used_bytes - wb->pinned_used_bytes; + + units =3D ufs_byte_to_unit(u, non_pinned_curr_bytes); + u->attributes.current_wb_buffer_size =3D cpu_to_be32(units); + + if (!non_pinned_curr_bytes) + u->attributes.available_wb_buffer_size =3D 0; + else + u->attributes.available_wb_buffer_size =3D + (non_pinned_curr_bytes - non_pinned_used_bytes) * 10 / + non_pinned_curr_bytes; +} + +static inline bool ufs_wb_is_flush_needed(UfsHc *u, uint64_t *no_flush_byt= es) +{ + UfsWb *wb =3D &u->wb; + uint32_t max_unit; + + switch (u->attributes.wb_buffer_partial_flush_mode) { + case UFS_WB_FLUSH_NONE: + *no_flush_bytes =3D 0; + break; + case UFS_WB_FLUSH_FIFO: + max_unit =3D be32_to_cpu(u->attributes.max_fifo_wb_partial_flush_m= ode); + *no_flush_bytes =3D ufs_unit_to_byte(u, max_unit); + break; + case UFS_WB_FLUSH_PINNED: + *no_flush_bytes =3D (u->flags.unpin_en) ? 0 : wb->pinned_used_byte= s; + break; + default: + g_assert_not_reached(); + break; + } + + return wb->used_bytes > *no_flush_bytes; +} + +#define UFS_WB_FLUSH_BYTES (4096 * 1024) +static void ufs_wb_process_flush(UfsHc *u) +{ + UfsWb *wb =3D &u->wb; + uint64_t flush_bytes, no_flush_bytes; + + switch (u->attributes.wb_buffer_flush_status) { + case UFS_WB_FLUSH_IDLE: + if (u->flags.wb_buffer_flush_en && + ufs_wb_is_flush_needed(u, &no_flush_bytes)) { + u->attributes.wb_buffer_flush_status =3D UFS_WB_FLUSH_IN_PROGR= ESS; + } + + break; + case UFS_WB_FLUSH_IN_PROGRESS: + if (!u->flags.wb_buffer_flush_en) { + u->attributes.wb_buffer_flush_status =3D UFS_WB_FLUSH_FAILED; + + } else if (!ufs_wb_is_flush_needed(u, &no_flush_bytes)) { + u->attributes.wb_buffer_flush_status =3D UFS_WB_FLUSH_COMPLETE= D; + + } else if (wb->pinned_used_bytes && u->flags.unpin_en) { + flush_bytes =3D MIN(wb->pinned_used_bytes, UFS_WB_FLUSH_BYTES); + wb->pinned_used_bytes -=3D flush_bytes; + wb->used_bytes -=3D flush_bytes; + + } else { + flush_bytes =3D MIN(wb->used_bytes - no_flush_bytes, UFS_WB_FL= USH_BYTES); + wb->used_bytes -=3D flush_bytes; + } + + break; + case UFS_WB_FLUSH_COMPLETED: + if (ufs_wb_is_flush_needed(u, &no_flush_bytes)) { + u->attributes.wb_buffer_flush_status =3D + (u->flags.wb_buffer_flush_en) ? UFS_WB_FLUSH_IDLE : + UFS_WB_FLUSH_IN_PROGRESS; + } + } +} + +static void ufs_wb_process_resize(UfsHc *u) +{ + UfsWb *wb =3D &u->wb; + + if (u->attributes.wb_buffer_resize_status !=3D UFS_WB_RESIZE_IN_PROGRE= SS) { + return; + } + + switch (u->attributes.wb_buffer_resize_en) { + case UFS_WB_DECREASE: + if (wb->curr_bytes <=3D wb->min_bytes) { + u->attributes.wb_buffer_resize_status =3D UFS_WB_RESIZE_FAILED; + return; + + } else if (wb->curr_bytes <=3D wb->used_bytes) { + u->attributes.wb_buffer_resize_status =3D UFS_WB_RESIZE_FAILED; + return; + } + + if (wb->curr_bytes - wb->used_bytes >=3D wb->resize_bytes) { + wb->curr_bytes -=3D wb->resize_bytes; + } else { + wb->curr_bytes =3D wb->used_bytes; + } + + if (wb->curr_bytes < wb->min_bytes) { + wb->curr_bytes =3D wb->min_bytes; + } + + break; + case UFS_WB_INCREASE: + if (wb->curr_bytes >=3D wb->max_bytes) { + u->attributes.wb_buffer_resize_status =3D UFS_WB_RESIZE_FAILED; + return; + } + + wb->curr_bytes +=3D wb->resize_bytes; + if (wb->curr_bytes >=3D wb->max_bytes) { + wb->curr_bytes =3D wb->max_bytes; + } + + break; + default: + g_assert_not_reached(); + break; + } + + u->attributes.wb_buffer_resize_status =3D UFS_WB_RESIZE_COMPLETED; +} + +static void ufs_wb_process_pinned(UfsHc *u) +{ + UfsWb *wb =3D &u->wb; + uint64_t avail_bytes; + + avail_bytes =3D wb->curr_bytes - wb->used_bytes + wb->pinned_used_byte= s; + + if ((u->attributes.wb_buffer_partial_flush_mode !=3D UFS_WB_FLUSH_PINN= ED) || + (wb->curr_bytes <=3D wb->pinned_min_bytes)) { + wb->pinned_curr_bytes =3D 0; + wb->pinned_used_bytes =3D 0; + + } else if (avail_bytes <=3D wb->pinned_max_bytes) { + wb->pinned_curr_bytes =3D avail_bytes; + + } else { + wb->pinned_curr_bytes =3D wb->pinned_max_bytes; + } +} + static void ufs_process_idle(UfsHc *u) { - /* Currently do nothing */ + ufs_wb_process_flush(u); + ufs_wb_process_resize(u); + ufs_wb_process_pinned(u); + ufs_wb_update_avail_buffer(u); return; } =20 @@ -1899,11 +2144,42 @@ static void ufs_init_state(UfsHc *u) } } =20 +static void ufs_wb_init(UfsHc *u) +{ + UfsWb *wb =3D &u->wb; + + wb->max_bytes =3D ufs_unit_to_byte(u, u->params.wb_max_size); + wb->min_bytes =3D ufs_unit_to_byte(u, u->params.wb_min_size); + + wb->curr_bytes =3D wb->max_bytes; + wb->used_bytes =3D 0; + wb->resize_bytes =3D (wb->max_bytes - wb->min_bytes) / 10; + + u->attributes.wb_buffer_flush_status =3D UFS_WB_FLUSH_IDLE; + u->attributes.available_wb_buffer_size =3D 0xA; + u->attributes.wb_buffer_life_time_est =3D 0x1; + u->attributes.current_wb_buffer_size =3D cpu_to_be32(u->params.wb_max_= size); + + u->attributes.wb_buffer_resize_hint =3D UFS_WB_HINT_KEEP; + u->attributes.wb_buffer_resize_status =3D UFS_WB_RESIZE_IDLE; + + u->attributes.wb_buffer_partial_flush_mode =3D UFS_WB_FLUSH_NONE; + + wb->pinned_curr_bytes =3D 0; + wb->pinned_used_bytes =3D 0; + wb->pinned_min_bytes =3D 0; + wb->pinned_total_written_bytes =3D 0; +} + static void ufs_init_hc(UfsHc *u) { uint32_t cap =3D 0; uint32_t mcqconfig =3D 0; uint32_t mcqcap =3D 0; + uint32_t ext_wb_sup =3D WB_RESIZE | WB_FIFO | WB_PINNED; + uint32_t ext_ufs_feat_sup =3D UFS_DEV_WB_SUPPORT | + UFS_DEV_HIGH_TEMP_NOTIF | + UFS_DEV_LOW_TEMP_NOTIF; int64_t now =3D qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL_RT); =20 u->reg_size =3D pow2ceil(ufs_reg_size(u)); @@ -1965,8 +2241,13 @@ static void ufs_init_hc(UfsHc *u) UFS_DEV_LOW_TEMP_NOTIF; u->device_desc.queue_depth =3D u->params.nutrs; u->device_desc.product_revision_level =3D 0x04; + u->device_desc.extended_wb_support |=3D cpu_to_be16(ext_wb_sup); u->device_desc.extended_ufs_features_support =3D - cpu_to_be32(UFS_DEV_HIGH_TEMP_NOTIF | UFS_DEV_LOW_TEMP_NOTIF); + cpu_to_be32((ext_ufs_feat_sup)); + u->device_desc.write_booster_buffer_preserve_user_space_en =3D 0x01; + u->device_desc.write_booster_buffer_type =3D 0x01; + u->device_desc.num_shared_write_booster_buffer_alloc_units =3D + cpu_to_be32(0x400); /* 4GB */ =20 memset(&u->geometry_desc, 0, sizeof(GeometryDescriptor)); u->geometry_desc.length =3D sizeof(GeometryDescriptor); @@ -1982,6 +2263,16 @@ static void ufs_init_hc(UfsHc *u) 0x0; /* out-of-order data transfer is not supported */ u->geometry_desc.max_context_id_number =3D 0x5; u->geometry_desc.supported_memory_types =3D cpu_to_be16(0x8001); + u->geometry_desc.write_booster_buffer_max_n_alloc_units =3D + cpu_to_be32(u->params.wb_max_size); + u->geometry_desc.device_max_write_booster_l_us =3D + u->params.wb_max_lus; + u->geometry_desc.write_booster_buffer_cap_adj_fac =3D + u->params.wb_cap_adj_fac; + u->geometry_desc.supported_write_booster_buffer_user_space_reduction_t= ypes =3D + u->params.wb_reduction; + u->geometry_desc.supported_write_booster_buffer_types =3D + 0x1; /* lu-dedicated buffer type is not supported */ =20 memset(&u->attributes, 0, sizeof(u->attributes)); u->attributes.max_data_in_size =3D 0x08; @@ -1996,6 +2287,8 @@ static void ufs_init_hc(UfsHc *u) memset(&u->flags, 0, sizeof(u->flags)); u->flags.permanently_disable_fw_update =3D 1; =20 + ufs_wb_init(u); + /* * The temperature value is fixed to UFS_TEMPERATURE and does not chan= ge * dynamically @@ -2061,6 +2354,11 @@ static const Property ufs_props[] =3D { DEFINE_PROP_UINT8("nutmrs", UfsHc, params.nutmrs, 8), DEFINE_PROP_BOOL("mcq", UfsHc, params.mcq, false), DEFINE_PROP_UINT8("mcq-maxq", UfsHc, params.mcq_maxq, 2), + DEFINE_PROP_UINT32("wb-max-size", UfsHc, params.wb_max_size, 0x400), + DEFINE_PROP_UINT32("wb-min-size", UfsHc, params.wb_min_size, 0x100), + DEFINE_PROP_UINT8("wb-max-lus", UfsHc, params.wb_max_lus, 1), + DEFINE_PROP_UINT8("wb-cap-adj-fac", UfsHc, params.wb_cap_adj_fac, 3), + DEFINE_PROP_UINT8("wb-reduction", UfsHc, params.wb_reduction, 1), }; =20 static const VMStateDescription ufs_vmstate =3D { diff --git a/hw/ufs/ufs.h b/hw/ufs/ufs.h index b5f040302129f4d02732ddd20ef82eb33c41922a..f27c30d202195636726e6920d14= c3ee9c03494be 100644 --- a/hw/ufs/ufs.h +++ b/hw/ufs/ufs.h @@ -91,6 +91,11 @@ typedef struct UfsParams { bool mcq; /* Multiple Command Queue support */ uint8_t mcq_qcfgptr; /* MCQ Queue Configuration Pointer in MCQCAP */ uint8_t mcq_maxq; /* MCQ Maximum number of Queues */ + uint32_t wb_max_size; /* WB Maximum allocation units */ + uint32_t wb_min_size; /* WB Minimum allocation units */ + uint8_t wb_max_lus; /* WB Maximum number of LUs */ + uint8_t wb_cap_adj_fac; /* WB Capacity Adjustment Factor */ + uint8_t wb_reduction; /* WB User Space Reduction */ } UfsParams; =20 /* @@ -118,6 +123,24 @@ typedef struct UfsCq { QTAILQ_HEAD(, UfsRequest) req_list; } UfsCq; =20 +/* + * Extended features + */ +typedef struct UfsWb { + struct UfsHc *u; + uint64_t max_bytes; + uint64_t min_bytes; + uint64_t curr_bytes; + uint64_t used_bytes; + uint64_t resize_bytes; + + uint64_t pinned_max_bytes; + uint64_t pinned_min_bytes; + uint64_t pinned_curr_bytes; + uint64_t pinned_used_bytes; + uint64_t pinned_total_written_bytes; +} UfsWb; + typedef struct UfsHc { PCIDevice parent_obj; UfsBus bus; @@ -147,6 +170,9 @@ typedef struct UfsHc { UfsSq *sq[UFS_MAX_MCQ_QNUM]; UfsCq *cq[UFS_MAX_MCQ_QNUM]; =20 + /* Extended features */ + UfsWb wb; + uint8_t temperature; =20 QEMUTimer idle_timer; @@ -211,6 +237,19 @@ static inline bool ufs_mcq_cq_full(UfsHc *u, uint32_t = qid) return tail =3D=3D ufs_mcq_cq_head(u, qid); } =20 +static inline uint64_t ufs_unit_to_byte(UfsHc *u, uint32_t unit) +{ + return unit * u->geometry_desc.allocation_unit_size * + be32_to_cpu(u->geometry_desc.segment_size) * BDRV_SECTOR_SIZE; +} + +static inline uint32_t ufs_byte_to_unit(UfsHc *u, uint64_t byte) +{ + return byte / BDRV_SECTOR_SIZE / + be32_to_cpu(u->geometry_desc.segment_size) / + u->geometry_desc.allocation_unit_size; +} + #define TYPE_UFS "ufs" #define UFS(obj) OBJECT_CHECK(UfsHc, (obj), TYPE_UFS) =20 diff --git a/include/block/ufs.h b/include/block/ufs.h index 4dacfb776f947a285d86018add82115f148b7dd9..aa0dde805826d0b06ab80fb7403= 4192ba06c2045 100644 --- a/include/block/ufs.h +++ b/include/block/ufs.h @@ -1126,11 +1126,24 @@ enum health_desc_param { UFS_HEALTH_DESC_PARAM_LIFE_TIME_EST_B =3D 0x4, }; =20 +/* Possible values for bUFSFeaturesSupport */ enum { UFS_DEV_HIGH_TEMP_NOTIF =3D BIT(4), UFS_DEV_LOW_TEMP_NOTIF =3D BIT(5), }; =20 +/* Possible values for dExtendedWriteBoosterSupport */ +enum { + WB_RESIZE =3D BIT(0), + WB_FIFO =3D BIT(1), + WB_PINNED =3D BIT(2), +}; + +/* Possible values for dExtendedUFSFeaturesSupport */ +enum { + UFS_DEV_WB_SUPPORT =3D BIT(8), +}; + /* WriteBooster buffer mode */ enum { UFS_WB_BUF_MODE_LU_DEDICATED =3D 0x0, @@ -1207,6 +1220,44 @@ enum ufs_dev_pwr_mode { UFS_DEEPSLEEP_PWR_MODE =3D 4, }; =20 +/* UFS Write Booster */ +enum ufs_wb_flush_status { + UFS_WB_FLUSH_IDLE =3D 0, + UFS_WB_FLUSH_IN_PROGRESS =3D 1, + UFS_WB_FLUSH_SUSPENDED =3D 2, + UFS_WB_FLUSH_COMPLETED =3D 3, + UFS_WB_FLUSH_FAILED =3D 4, + UFS_WB_FLUSH_STATUS_MAX, +}; + +enum ufs_wb_flush_mode { + UFS_WB_FLUSH_NONE =3D 0, + UFS_WB_FLUSH_FIFO =3D 1, + UFS_WB_FLUSH_PINNED =3D 2, + UFS_WB_FLUSH_MODE_MAX, +}; + +enum ufs_wb_resize_hint { + UFS_WB_HINT_KEEP =3D 0, + UFS_WB_HINT_DECREASE =3D 1, + UFS_WB_HINT_ENCREASE =3D 2, + UFS_WB_RESIZE_HINT_MAX, +}; + +enum ufs_wb_resize_op { + UFS_WB_DECREASE =3D 0, + UFS_WB_INCREASE =3D 1, + UFS_WB_RESIZE_OP_MAX, +}; + +enum ufs_wb_resize_status { + UFS_WB_RESIZE_IDLE =3D 0, + UFS_WB_RESIZE_IN_PROGRESS =3D 1, + UFS_WB_RESIZE_COMPLETED =3D 2, + UFS_WB_RESIZE_FAILED =3D 3, + UFS_WB_RESIZE_STATUS_MAX, +}; + /* * struct UtpCmdRsp - Response UPIU structure * @residual_transfer_count: Residual transfer count DW-3 --=20 2.48.1 From nobody Sat Apr 11 18:37:57 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=gmail.com ARC-Seal: i=1; a=rsa-sha256; t=1775137991; cv=none; d=zohomail.com; s=zohoarc; b=cI7UWWZ2CRwsStagqFR0A9fFtjw98HVoYgnHUElANfAn5PevpmmEWJO5ZMqL+OVAskGkdzKB0Y5/8kawYspETlXfr49FgW6Mh5IPp8bmSbYF89GtAP0Q6SwE3BKk31iqm+zSrx6JM+6eTtI/obuZQS4UC6y99FJn8KQElEc4pBY= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1775137991; 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=UvnDam+RI7xNOArU3spJiI07Kx70RBnYFEvTvltBdIM=; b=QpST7AI3LvmHT+mYz1gm3zjYpjJv5q5JIm86GfDWI7HKrOXeMaR7aDvlnjqTPXGrkzku+WT9toL1jThmgpKuwkHGOoQKESj1SoHZQDkm34C1SHU+XM5paJSySSt4T6Ku50tl4v+iMLQTG31L4dV5bMsMUJgrr1wTeQeqoQHpQew= 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 lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1775137991130825.1177976278547; Thu, 2 Apr 2026 06:53:11 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1w8ISc-0003Ae-Ef; Thu, 02 Apr 2026 09:51:51 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1w8Eay-0001E1-QF for qemu-devel@nongnu.org; Thu, 02 Apr 2026 05:44:14 -0400 Received: from mail-pf1-x435.google.com ([2607:f8b0:4864:20::435]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1w8Eaw-0005Os-QN for qemu-devel@nongnu.org; Thu, 02 Apr 2026 05:44:12 -0400 Received: by mail-pf1-x435.google.com with SMTP id d2e1a72fcca58-82cebbdab08so502067b3a.2 for ; Thu, 02 Apr 2026 02:44:10 -0700 (PDT) Received: from [172.17.0.5] ([168.126.243.22]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-82cf9c6ad8asm2668477b3a.40.2026.04.02.02.44.06 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 02 Apr 2026 02:44:08 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1775123049; x=1775727849; darn=nongnu.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=UvnDam+RI7xNOArU3spJiI07Kx70RBnYFEvTvltBdIM=; b=g/gGyBMd6BlXR9KEAB6PQAWXm5pK3a8T7cv7At3bK699/lYUql/I5sJHYAJO9OlAof c/UhfvklLL7+DTIhSDxr8py/HQzaOCF8hsjHnbUu+ePN516qD/zlQ5KQZuUEZ2RfAHHF 2JX8rn0NkcvQ8Angyy740IK9Ke3ymdPtDr/YhpOs1VB2RyVq//WqMEEN9RFj/fEOWPgq ZFbpNTsNyd6VrghaTrD5RJd5tm5AT9DrdinU1SbGBTamUfxHiPJDzQ3+09SyqpzYjExh MC9eYgj/ioNf0pXgnooFQ/Znqiu+ipXVIDd5W2tfgdg1d5LGk5oyyIg/aoiN2wX3e00Q iVpA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1775123049; x=1775727849; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-gg:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to; bh=UvnDam+RI7xNOArU3spJiI07Kx70RBnYFEvTvltBdIM=; b=Wk0JwGWILBu/F2GknH1accaXFVS13VrQSxUBJwo85qNrgbTD2FkdFPQp1VCsyBcg5r uqsOxDGNDHhX+UGjIX0Czck8a0yS4bfOH0xIDU6vIWXx72n1UN/RuXSlSjthJeoTfR1p WgquZlV1u3Dx0Y72JXQ8jqrv/LMmIJ22PWZi5FeBgRNPhUtUoy7FHmp6EMu6zJLcOgpk aJz9Gwmx2Q+zLe14BCr3R72AmD+/fdXLaKkzIobqWh+PHbVoHzfSaYGQCRJ3kuMB0AK8 KpnxmH6CWtCBikXhTTwyPSIo+uR2OxByyVZUcSMeCRDUZmvWoH6p+T4b0YvaJAI3ZVKz Jp5Q== X-Gm-Message-State: AOJu0YzKQwTjDtS+emTgkuLa9IoJniDywIrzkL9pQ4Cil0p0vNZ0mXU7 wcyyKW04U1tk2Eq8zoOOJkKzke86K3GM8S6/VcVxWMKSdsUCCFZsbw8m X-Gm-Gg: ATEYQzzBNgZbuuMzEId6OFGztQUPoszKJnuLuX661NlGxeQQaIV3sgRzGthtlrqO/Gs +7yhDU5+crbR6HIZt8SiW7wGQtc+GTp/ljoYNoOo3d40rtAqn/mhwV20m/M2SnILhaY6UQhu7RJ tG9iHnAvMwSaVuTSHsAdUqWAqFfjsbYiL+LQCTzXl6O1g2EC0THngG5iIic3go5CobTd6Q+AQhm 4X4luyCYK6fL+1N21oTQipffE6w0RGViOfPG0xGepQp1SnHnaHgTAy60b36tXRz8I8NsKloq0s8 aRRFrMv5EsR5wBnXtiV8y2QlBAySz8zU+8QYuH5hyflvfpdiStsPuk6yQAh9fg6fsk18s8BQNJP zIkgXrXaY8ok3CwUoCyqPhzkmOyBRbUymdDZ2FdlykqXxnOapM39C3GR1tDYpw6foBZiDCO/tkG a9Zib9/R5Q9Co41gr8oKEsm0L9LDVJBA== X-Received: by 2002:a05:6a00:4c1a:b0:82c:e0d7:2691 with SMTP id d2e1a72fcca58-82ce898242bmr7214886b3a.24.1775123049421; Thu, 02 Apr 2026 02:44:09 -0700 (PDT) From: Jaemyung Lee X-Google-Original-From: Jaemyung Lee Date: Thu, 02 Apr 2026 18:43:49 +0900 Subject: [PATCH 5/5] tests/qtest: Add UFS Write Booster QTest MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260402-write_booster-v1-5-e4fed1df6c7e@samsung.com> References: <20260402-write_booster-v1-0-e4fed1df6c7e@samsung.com> In-Reply-To: <20260402-write_booster-v1-0-e4fed1df6c7e@samsung.com> To: qemu-devel@nongnu.org Cc: Jeuk Kim , Kevin Wolf , Hanna Reitz , qemu-block@nongnu.org, Fabiano Rosas , Laurent Vivier , Paolo Bonzini , Jaemyung Lee X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1775123032; l=8918; i=jaemyung.lee@samsung.com; s=20260402; h=from:subject:message-id; bh=rU67KxRcVLL6ZVBVhiBQ/INRn8llY3KXffQmzbO047E=; b=UpeoBpik1U1BPwlC3nNSNzfUx57G1BZnIkwy3hN/PaWb4UQMiJf0t89iCXCRZI8lk6uc6UJnv 3WZnPd9eGPMCDfpYLn5Eo1lzJA3e+aJRngfq25KIxPh/4sXciJxxA0j X-Developer-Key: i=jaemyung.lee@samsung.com; a=ed25519; pk=bZPd7A/kteUO62FfUM6IrI1LuBPe5QrcqfvsitM1ZjE= 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=2607:f8b0:4864:20::435; envelope-from=ldc.jml@gmail.com; helo=mail-pf1-x435.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-Mailman-Approved-At: Thu, 02 Apr 2026 09:51:40 -0400 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 @gmail.com) X-ZM-MESSAGEID: 1775137992585154100 It adds 'wb-init' and 'wb-read-write' TCs into tests/qtest/ufs-test.c. 'wb-init' tests that the WB support is properly initialized with UFS device and 'wb-read-write' tests that WB can be enabled and WRITE I/O can be handled/buffered as a WB command. Signed-off-by: Jaemyung Lee --- tests/qtest/ufs-test.c | 176 +++++++++++++++++++++++++++++++++++++++++++++= ++++ 1 file changed, 176 insertions(+) diff --git a/tests/qtest/ufs-test.c b/tests/qtest/ufs-test.c index 7f999441552a105987aaaf8e2b976f4a05f953ed..253fea27a5e52619f433d150755= 00a566eddeccc 100644 --- a/tests/qtest/ufs-test.c +++ b/tests/qtest/ufs-test.c @@ -1182,6 +1182,173 @@ static void ufstest_query_desc_request(void *obj, v= oid *data, ufs_exit(ufs, alloc); } =20 +static void ufstest_wb_init(void *obj, void *data, QGuestAllocator *alloc) +{ + QUfs *ufs =3D obj; + enum UtpOcsCodes ocs; + UtpUpiuRsp rsp_upiu; + uint8_t *desc; + uint32_t value; + + ufs_init(ufs, alloc); + + /* Read Device Descriptor */ + ocs =3D ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, + UFS_UPIU_QUERY_OPCODE_READ_DESC, + UFS_QUERY_DESC_IDN_DEVICE, 0, 0, 0, &rsp_upiu); + g_assert_cmpuint(ocs, =3D=3D, UFS_OCS_SUCCESS); + g_assert_cmpuint(rsp_upiu.header.response, =3D=3D, UFS_COMMAND_RESULT_= SUCCESS); + g_assert_cmpuint(rsp_upiu.qr.opcode, =3D=3D, UFS_UPIU_QUERY_OPCODE_REA= D_DESC); + g_assert_cmpuint(rsp_upiu.qr.idn, =3D=3D, UFS_QUERY_DESC_IDN_DEVICE); + g_assert_cmpuint(rsp_upiu.qr.data[0], =3D=3D, sizeof(DeviceDescriptor)= ); + g_assert_cmpuint(rsp_upiu.qr.data[1], =3D=3D, UFS_QUERY_DESC_IDN_DEVIC= E); + + /* Check Write Booster Supportability */ + desc =3D rsp_upiu.qr.data; + + value =3D *(uint16_t *)(desc + UFS_DEVICE_DESC_PARAM_EXT_WB_SUP); + value =3D be16_to_cpu(value); + g_assert_cmpuint(value, =3D=3D, WB_RESIZE | WB_FIFO | WB_PINNED); + + value =3D *(uint32_t *)(desc + UFS_DEVICE_DESC_PARAM_EXT_UFS_FEATURE_S= UP); + value =3D be32_to_cpu(value); + g_assert_cmpuint(value & UFS_DEV_WB_SUPPORT, =3D=3D, UFS_DEV_WB_SUPPOR= T); + + /* Read Geometry Descriptor */ + ocs =3D ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, + UFS_UPIU_QUERY_OPCODE_READ_DESC, + UFS_QUERY_DESC_IDN_GEOMETRY, 0, 0, 0, &rsp_upiu); + g_assert_cmpuint(ocs, =3D=3D, UFS_OCS_SUCCESS); + g_assert_cmpuint(rsp_upiu.header.response, =3D=3D, UFS_COMMAND_RESULT_= SUCCESS); + g_assert_cmpuint(rsp_upiu.qr.data[0], =3D=3D, sizeof(GeometryDescripto= r)); + g_assert_cmpuint(rsp_upiu.qr.data[1], =3D=3D, UFS_QUERY_DESC_IDN_GEOME= TRY); + + /* Check Write Booster Configuration */ + desc =3D rsp_upiu.qr.data; + + value =3D *(uint32_t *)(desc + UFS_GEOMETRY_DESC_PARAM_WB_MAX_ALLOC_UN= ITS); + value =3D be32_to_cpu(value); + g_assert_cmpuint(value, =3D=3D, 1024); + + value =3D desc[UFS_GEOMETRY_DESC_PARAM_WB_MAX_WB_LUNS]; + g_assert_cmpuint(value, =3D=3D, 1); + + value =3D desc[UFS_GEOMETRY_DESC_PARAM_WB_BUFF_CAP_ADJ]; + g_assert_cmpuint(value, =3D=3D, 3); + + value =3D desc[UFS_GEOMETRY_DESC_PARAM_WB_SUP_RED_TYPE]; + g_assert_cmpuint(value, =3D=3D, 1); + + value =3D desc[UFS_GEOMETRY_DESC_PARAM_WB_SUP_WB_TYPE]; + g_assert_cmpuint(value, =3D=3D, 1); + + ufs_exit(ufs, alloc); +} + +static void ufstest_wb_read_write(void *obj, void *data, QGuestAllocator *= alloc) +{ + QUfs *ufs =3D obj; + uint8_t read_buf[4096] =3D { 0 }; + uint8_t write_buf[4096] =3D { 0 }; + const uint8_t read_capacity_cdb[UFS_CDB_SIZE] =3D { + /* allocation length 4096 */ + SERVICE_ACTION_IN_16, + SAI_READ_CAPACITY_16, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x10, + 0x00, + 0x00, + 0x00 + }; + const uint8_t request_sense_cdb[UFS_CDB_SIZE] =3D { + REQUEST_SENSE, + }; + const uint8_t write_cdb[UFS_CDB_SIZE] =3D { + /* WRITE(10) to LBA 0, transfer length 1 */ + WRITE_10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00 + }; + uint32_t block_size; + enum UtpOcsCodes ocs; + UtpUpiuRsp rsp_upiu; + const int test_lun =3D 1; + uint64_t end_time; + + ufs_init(ufs, alloc); + + /* Clear Unit Attention */ + ocs =3D ufs_send_scsi_command(ufs, test_lun, request_sense_cdb, NULL, = 0, + read_buf, sizeof(read_buf), &rsp_upiu); + g_assert_cmpuint(ocs, =3D=3D, UFS_OCS_SUCCESS); + g_assert_cmpuint(rsp_upiu.header.scsi_status, =3D=3D, CHECK_CONDITION); + + /* Read capacity */ + ocs =3D ufs_send_scsi_command(ufs, test_lun, read_capacity_cdb, NULL, = 0, + read_buf, sizeof(read_buf), &rsp_upiu); + g_assert_cmpuint(ocs, =3D=3D, UFS_OCS_SUCCESS); + g_assert_cmpuint(rsp_upiu.header.scsi_status, =3D=3D, + UFS_COMMAND_RESULT_SUCCESS); + block_size =3D ldl_be_p(&read_buf[8]); + g_assert_cmpuint(block_size, =3D=3D, 4096); + + /* Check available buffer size */ + ocs =3D ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, + UFS_UPIU_QUERY_OPCODE_READ_ATTR, + UFS_QUERY_ATTR_IDN_AVAIL_WB_BUFF_SIZE, 0, 0, 0, &= rsp_upiu); + g_assert_cmpuint(ocs, =3D=3D, UFS_OCS_SUCCESS); + g_assert_cmpuint(rsp_upiu.header.response, =3D=3D, UFS_COMMAND_RESULT_= SUCCESS); + g_assert_cmpuint(rsp_upiu.qr.opcode, =3D=3D, UFS_UPIU_QUERY_OPCODE_REA= D_ATTR); + g_assert_cmpuint(rsp_upiu.qr.idn, =3D=3D, UFS_QUERY_ATTR_IDN_AVAIL_WB_= BUFF_SIZE); + g_assert_cmpuint(rsp_upiu.qr.value, =3D=3D, cpu_to_be32(0xA)); + + /* Enable WB */ + ocs =3D ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST, + UFS_UPIU_QUERY_OPCODE_SET_FLAG, + UFS_QUERY_FLAG_IDN_WB_EN, 0, 0, 0, + &rsp_upiu); + g_assert_cmpuint(ocs, =3D=3D, UFS_OCS_SUCCESS); + g_assert_cmpuint(rsp_upiu.header.response, =3D=3D, UFS_COMMAND_RESULT_= SUCCESS); + g_assert_cmpuint(rsp_upiu.qr.value, =3D=3D, be32_to_cpu(1)); + + /* Write data */ + for (int i =3D 0; i < 256; i++) { + memset(write_buf, 0xab, block_size); + ocs =3D ufs_send_scsi_command(ufs, test_lun, write_cdb, write_buf, + block_size, NULL, 0, &rsp_upiu); + g_assert_cmpuint(ocs, =3D=3D, UFS_OCS_SUCCESS); + g_assert_cmpuint(rsp_upiu.header.scsi_status, =3D=3D, + UFS_COMMAND_RESULT_SUCCESS); + } + + end_time =3D g_get_monotonic_time() + TIMEOUT_SECONDS * G_TIME_SPAN_SE= COND; + do { + qtest_clock_step(ufs->dev.bus->qts, 100); + + /* Check available buffer size */ + ocs =3D ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQU= EST, + UFS_UPIU_QUERY_OPCODE_READ_ATTR, + UFS_QUERY_ATTR_IDN_AVAIL_WB_BUFF_SIZE, 0, 0, = 0, + &rsp_upiu); + g_assert_cmpuint(ocs, =3D=3D, UFS_OCS_SUCCESS); + g_assert_cmpuint(rsp_upiu.header.response, =3D=3D, UFS_COMMAND_RES= ULT_SUCCESS); + g_assert_cmpuint(rsp_upiu.qr.opcode, =3D=3D, UFS_UPIU_QUERY_OPCODE= _READ_ATTR); + g_assert_cmpuint(rsp_upiu.qr.idn, =3D=3D, UFS_QUERY_ATTR_IDN_AVAIL= _WB_BUFF_SIZE); + } while (rsp_upiu.qr.value =3D=3D cpu_to_be32(0xA) && g_get_monotonic_= time() < end_time); + + /* Check available buffer size */ + g_assert_cmpuint(rsp_upiu.qr.value, =3D=3D, cpu_to_be32(0x9)); + + ufs_exit(ufs, alloc); +} + static void drive_destroy(void *path) { unlink(path); @@ -1234,6 +1401,13 @@ static void ufs_register_nodes(void) .edge.extra_device_opts =3D "mcq=3Dtrue,mcq-maxq=3D1" }; =20 + QOSGraphTestOptions wb_test_opts =3D { .before =3D ufs_blk_test_setup, + .edge.extra_device_opts =3D + "mcq=3Dfalse,nutrs=3D32,nutmr= s=3D8," + "wb-max-size=3D1024,wb-min-si= ze=3D256," + "wb-max-lus=3D1,wb-cap-adj-fa= c=3D3," + "wb-reduction=3D1" }; + add_qpci_address(&edge_opts, &(QPCIAddress){ .devfn =3D QPCI_DEVFN(4, = 0) }); =20 qos_node_create_driver("ufs", ufs_create); @@ -1262,6 +1436,8 @@ static void ufs_register_nodes(void) &io_test_opts); qos_add_test("query-desciptor", "ufs", ufstest_query_desc_request, &io_test_opts); + qos_add_test("wb-init", "ufs", ufstest_wb_init, &wb_test_opts); + qos_add_test("wb-read-write", "ufs", ufstest_wb_read_write, &wb_test_o= pts); } =20 libqos_init(ufs_register_nodes); --=20 2.48.1