From nobody Sat May 30 18:35:59 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=gmail.com ARC-Seal: i=1; a=rsa-sha256; t=1778746358; cv=none; d=zohomail.com; s=zohoarc; b=hjMErNB0cp9xFGjmlgalDH61sRRX6H7PABLAGw568rkvIZ9hz0rYa4IoFBQ67pm37r9Gc5hSuhbn4CvcQNiI4d7xOHVdWHQPwM+EgKal3C7EpJ/WmKpNWnyAfYTY7COwhuVVP4ieqrH2EsDdnfQ/yTh13+zVXGW/L81lrdqapws= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1778746358; 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=CHQ7bUQ2xItk/fCKPpzud/D/Mj4MHPfcnYTyuCHqq1PiOZj4MhmBIJoBdVah9POSy/MEuGlPEiReTV2DPo8OIgKx5uRKkfkH2LFVA4aZXmSSvVapvjx7DSwvftkUDQzGCetWvfc7Yme7SmsfRSHYxeTKiF8YuktNMi+x8oJgQig= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1778746358385255.02112002013007; Thu, 14 May 2026 01:12:38 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wNRAK-0004et-05; Thu, 14 May 2026 04:11:32 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wNRA3-0004bD-QM for qemu-devel@nongnu.org; Thu, 14 May 2026 04:11:17 -0400 Received: from mail-pg1-x535.google.com ([2607:f8b0:4864:20::535]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1wNR9x-0001bo-HQ for qemu-devel@nongnu.org; Thu, 14 May 2026 04:11:13 -0400 Received: by mail-pg1-x535.google.com with SMTP id 41be03b00d2f7-c80203b9d7bso3202810a12.0 for ; Thu, 14 May 2026 01:11:08 -0700 (PDT) Received: from [172.17.0.5] ([168.126.243.22]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-2bd5c2631basm14480165ad.34.2026.05.14.01.11.04 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 14 May 2026 01:11:06 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1778746267; x=1779351067; 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=VUvffboPeNMtM7pD7ZnrRVCAbOSB0HC3chIeVxfc4LzKN9JifrHALMFo9TKZN402X/ mY8XJzRAgCUOHz/LYZbqtgR3I4B+9e1CzXGpPN6APZmGRPzUorFqy12iM9chgXMOMmiZ RNbripeImwMYpAySe+IlmHbTQnf4PkIVCTPhlk45fY4L/wpRStdVlF0KPNUmdKquUrg5 PfMpshCh+pO8NHIj794h4T+j/zydHC0VpzHirq1C5lrRJNxj4WAssLUIBfmnP4JbuQ2w w/YK6Hsiv10kW3NBleUkoujxT0E+RpRd43jMValsMOOZ1K8ILcng9/1oZ4J0U9xJlcQl 3joA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1778746267; x=1779351067; 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=XIMJpnVPea2wS4PCjxPe00b9hDEyi3hWPg4XRwJvwzst5TkgkagAQjUE6dvAKW5Wci EVJG9xBofploPQV0cyaB2witYUjdQNkk5lOs2mYAZTuNiu7/EcTbkezxFfiGRy7hfmzZ UYEbLDp2FR7K17wHHkqHBfujbkKoQ2ae1/UucndkVAblKxkxkRSroiLCsPRCZqD/Vr3b ZF1fgC097mfJN0YEFR2NnCw60aEJLjdEg4piqdqKAFSyBRQOMlsN7eutJbDzcD9iEDNl BHdZ9/CwaifRW9DGjaFSos3MhkJR0cr/5nco+P7bWS7GtN4T1DGlBaMq6bqEn8WjV9Vv Hs7A== X-Gm-Message-State: AOJu0YwlykY4HReTeztALNpiz/2A+cKSQIQbC7NuDEBEi2v0xpVNQD8G BuPdOxA2DX++COINVMU+fmFz2NSm83p1KQwG3TXsx5j5Xaf6K0DfzOBi X-Gm-Gg: Acq92OHmDIWTAk0ArwAVXybjyOwX27jhnfTZMeMXmG9XJI3bHW/B+gOsJImioM0Qob+ 3LxdBB+xHfqJrr0z0fbaoJ/mWA3FKozNoI1mkX7BDNDtfGP6KyXaM0vud8wAWWtK0hAZi2W7O9m m9eBgdotgu7i63BVWGSU++PAu919/nVDFK+zRtp8FX+qyv/XCGD5IVJvLYAIoCtf8iojOjpI5Pp QVkl0uJtB7ALthh6hVBHbEUgUEFYIIElMklMGUiZk1iEQMgD6EMyjgeq5BTKlcoAO0EbjdOyYnU OCvbvyHnUKMh6TrVywnxxoQPWjbdcohGbHvneZdPPpeJoKYk2bfQ9Zg7ACnEJEAyZyi75MIDt19 oLnjeT18yHzzatrByHkdR79GzJ839hJESRoNQj5LHqRmkDBBhvmQSxapzuhZiUtyEHNRUKNBb+e pM8akpEyPdC4chVTBOiyf3Gw0iyspRLg== X-Received: by 2002:a17:903:228f:b0:2b0:70c8:ccea with SMTP id d9443c01a7336-2bd27157864mr76819425ad.13.1778746266888; Thu, 14 May 2026 01:11:06 -0700 (PDT) From: Jaemyung Lee X-Google-Original-From: Jaemyung Lee Date: Thu, 14 May 2026 17:10:44 +0900 Subject: [PATCH v7 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: <20260514-write_booster-v7-1-c3ae3452980f@samsung.com> References: <20260514-write_booster-v7-0-c3ae3452980f@samsung.com> In-Reply-To: <20260514-write_booster-v7-0-c3ae3452980f@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=1778746262; l=12799; i=jaemyung.lee@samsung.com; s=20260402; h=from:subject:message-id; bh=CgN8ljzeml1hAPWOnqVTo/m8W7lnE0WV5YXREroYZ/Q=; b=wDmTZzqZtD+vnnPrWZO4V+TmR2AfDGPouS2WO3WjNzREMe73+X5skfQEVHvVSa279eYsGbebT K1B7LzUPD53DV/Pp0fn6hNYQssVNyxdtQa4Q5vBuWZpnFOGi3XdR8gu 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=lists1p.gnu.org; Received-SPF: pass client-ip=2607:f8b0:4864:20::535; envelope-from=ldc.jml@gmail.com; helo=mail-pg1-x535.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=unavailable autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @gmail.com) X-ZM-MESSAGEID: 1778746359742158500 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 Reviewed-by: Jeuk Kim --- 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 May 30 18:35:59 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=gmail.com ARC-Seal: i=1; a=rsa-sha256; t=1778746327; cv=none; d=zohomail.com; s=zohoarc; b=HrmBk/bgcz7QN9ulZgBR1e6nP1TNn8Jozn9wBOxnb0tGEB5hD/DHtKPJOyCg/E6DmBNK+24EMlzELUI2QMcCATHVPmhQq/mI29YGmCqY1F9NTDxR8UBxkRBfRKQRjAFtzUaAzNsYxP/R9lguHomQqjA0tVChBkYMbS4zgXd+snE= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1778746327; 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=O1tMWV/JKzKy0GhPYq0t3EOOuW6uGUlyVifTANo7XPPPFliVPyyAZyRq0lwk0NBvVoqCkMmfGhs33k5dWGrTeZxg0tqYUYELm1p7aWPtcl3kU1Gz0NDz8FwXdNyQKGySPwQysa6897Hwms1AGRdkgVMLZfZ2aLj/UgDO8xgWaBw= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1778746327298209.54688347429942; Thu, 14 May 2026 01:12:07 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wNRAF-0004ds-Uj; Thu, 14 May 2026 04:11:27 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wNRA3-0004bB-Q5 for qemu-devel@nongnu.org; Thu, 14 May 2026 04:11:17 -0400 Received: from mail-pl1-x632.google.com ([2607:f8b0:4864:20::632]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1wNR9z-0001cE-OB for qemu-devel@nongnu.org; Thu, 14 May 2026 04:11:15 -0400 Received: by mail-pl1-x632.google.com with SMTP id d9443c01a7336-2b788a98557so58087925ad.2 for ; Thu, 14 May 2026 01:11:10 -0700 (PDT) Received: from [172.17.0.5] ([168.126.243.22]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-2bd5c2631basm14480165ad.34.2026.05.14.01.11.07 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 14 May 2026 01:11:08 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1778746269; x=1779351069; 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=ETukIjuVPauMCE75mkCTkYN9OinCmyhUSwQhkCzBss712pPa6J+uGVu5hpXUQrLRii YzDCY51DnuyQ7WknssGY4FG422KNgLE7L2+IlCVHSJiKgOeOmZTeyI4uWC9NnJ4k4vvN Pm6h1JPmfajJO0f5tkQz06fNUgGBkig3SYy49YZpzfrZ0Y6CyKPdB+84xM65l5k7r9TH hNDV/W5RUS1q35dswi1odcLdR0n+/AzyUzYjY0sus2oL2ML+e3QY1uIB6dkzdNVJYPIG almz7rDfW0+JtqiOn+/AIdc0UoOxscFXm2SOY+KfSLiWj/B/JtECjjM566HpefB9OgMt xh4g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1778746269; x=1779351069; 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=hwUwbT7YMVtBiNe+E8Rr1os1ZEhI51oz+LKvFFCOobOzGF16nX8vSKhX/YiGBHa8xy Kq35KZ6PlXLict19dpj1KiELSvnMH1P7021YmpE8HFPWzNQBl8f3kPRGDtYMQQJHTJQ4 NQmyO0WBdBQPQac2PkzyA9jZkCfLP3OwAh2wk2LbGLN7Ej6+qsFFgAyBNiw3iBM0Ai0k we2zhhHg+EKvRU89JjcDG4hMqyx0pY8UVVguLCxooWaXFqsZEvp5FnPO8aqxp826R5Sm /4UMrXYJEkxkJ8xyZ2SbqrOsT/5lbYy08xJAAV+pO/ojKal65VA3cNQ/MsQ7OJoE6Xx0 03ug== X-Gm-Message-State: AOJu0Yzz6PcjMZOl7insZA7U/Ll8tCjSmGwhhO3jIoC+gUq+BKcdNrjg tSnEUEzQDflN1WCQ/OAGIGEwVpFOjrCO+7o281MgpHekg1k6JubY1/xm X-Gm-Gg: Acq92OFTZle6ZUs1vjKPcmAoaNVuEHxIC89GoEGVXZfJK3j+mFnoX91aSAOh9kMGe5M 5r0i4Cixi5kXDvIL2fra5RVk+biXcRXthF2EXgy4KkIGZQgLM/vlTOwb6DufECdGfvmcVdh5nPC wpuN+wGi+xOlXJurxQlF8YPu6WF24TrWhQp863a39aXQbMiYwWI0oQr4LcHCp0UBGd3h2FnDdGm Efd92JIZsZ9P9SOo6yhx6PeXlN2V0I3H/mD/vlZ1AfomEzdmE5WbBGJmEkbRnaumltCQ9qF4Psd 0+F5uIXQ8pVGNWMk/9TySKC7AWwT14ENyxvyRM9kMOGg6XlIRuZ3zluW2FojSIQjsY9jWu9xRiL 37N9X42KGsm9wC/AvM+HYT07fstZOb533MPj6i5QPBos8hsJIXeadrDoyl8J9e/Ho4VbkfXcTDd r2pU6n9hIF/h64lSnKuX5A14+tgnkjxQ== X-Received: by 2002:a17:903:4514:b0:2b9:ec37:2977 with SMTP id d9443c01a7336-2bd275c6df7mr50400735ad.38.1778746268947; Thu, 14 May 2026 01:11:08 -0700 (PDT) From: Jaemyung Lee X-Google-Original-From: Jaemyung Lee Date: Thu, 14 May 2026 17:10:45 +0900 Subject: [PATCH v7 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: <20260514-write_booster-v7-2-c3ae3452980f@samsung.com> References: <20260514-write_booster-v7-0-c3ae3452980f@samsung.com> In-Reply-To: <20260514-write_booster-v7-0-c3ae3452980f@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=1778746262; l=6656; i=jaemyung.lee@samsung.com; s=20260402; h=from:subject:message-id; bh=UwQldvutZu9HqLXksjdiAk3IKzXkRCngBaBlZ026a4E=; b=AnhaQp2/PhH9GU/ydKRfgxenEr0M+0qBJrMuyOUBC1xE/KRVUQbZdNZHPq9cO8eUJRUgK1vm6 CO3RJ+7WFZXCY6MDOYJM+uYzp96NMmPwYhhBKcc9pixUei2p6Zkq+ab 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=lists1p.gnu.org; Received-SPF: pass client-ip=2607:f8b0:4864:20::632; envelope-from=ldc.jml@gmail.com; helo=mail-pl1-x632.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-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: 1778746329343158500 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 Reviewed-by: Jeuk Kim --- 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 May 30 18:35:59 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=gmail.com ARC-Seal: i=1; a=rsa-sha256; t=1778746342; cv=none; d=zohomail.com; s=zohoarc; b=awA4pWUail+pW7fOMAQpZoYX3z1mYLcydNY4zq4AGgbsX1rRM/iHcGrTZagG7QUEVJEQG4zV/XE6Lgj7yFQqfv5BpieKOLnaP973GXmNKI4TH+4AGYg6anuTgtRY4qv93NQBCJtV4fXLe62/Soi7ZBu0Uc5OTmgqy6Kkl2Sq+9U= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1778746342; 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=s7rduMfdSHBv6Dm+D3nhuA8gVs+ENlu+IzPYpxEzuEI=; b=B0S18k4m0YW51n4P/atJhAehd8Vb9+wAh+p+hOprHisOzKlc40g/q2wu1Al78wErPCAi7BlBRpzBxUrOLENuI0l32y8HrdFTsmHRbnU+KOdkjIbTg11QeXdyyhl6ym8Y37t97997e9WPJn/fQq/wXGPAbiTJrABspl7BRvYcDEE= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1778746342282603.4331319771748; Thu, 14 May 2026 01:12:22 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wNRAE-0004dZ-0Z; Thu, 14 May 2026 04:11:26 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wNRA3-0004bC-QF for qemu-devel@nongnu.org; Thu, 14 May 2026 04:11:17 -0400 Received: from mail-pl1-x62e.google.com ([2607:f8b0:4864:20::62e]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1wNRA1-0001cg-0r for qemu-devel@nongnu.org; Thu, 14 May 2026 04:11:15 -0400 Received: by mail-pl1-x62e.google.com with SMTP id d9443c01a7336-2b941cd869cso48838235ad.1 for ; Thu, 14 May 2026 01:11:12 -0700 (PDT) Received: from [172.17.0.5] ([168.126.243.22]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-2bd5c2631basm14480165ad.34.2026.05.14.01.11.09 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 14 May 2026 01:11:10 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1778746271; x=1779351071; 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=s7rduMfdSHBv6Dm+D3nhuA8gVs+ENlu+IzPYpxEzuEI=; b=g65n5aGgeHW6mAfEKoFeqyfoEqxNSk+X/4qXsY9aRDv8EP8eQ7JMmXusyL6SsCQsi3 Z8vsHxI0Xm6aOSBs/KJk8JisA9sc6ft+huo3sQ0ISS0IqTG3o4y3pUOK9IJ5CcK05uIZ xUbCjMF2+2cWYJi2FI24t2IqhPe2sJ6Orz/CyaT9eMlcbDCdHADPhSb4jGj5KE5AXZh8 R64tq5QhH+rzAvADScR07pSIiAvTh4defUjLtVEh3H7iaGblTy0iVeOJnnibEIMUsadg 7ee3yADRIM3HfufoOHv+JxXz/8pqik8PRzjBZH/PytrBYxy6dSdDVnnR9Cx4YzBM5Ps7 sZ9A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1778746271; x=1779351071; 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=s7rduMfdSHBv6Dm+D3nhuA8gVs+ENlu+IzPYpxEzuEI=; b=f9BC2KCnjZiKEq4XaVj/Y/1+cmh4yx0+oQnO0KE0R1GdK5frrU9V0t/um5CnGZkwet SnazQ6tZbJXsWinzeJ6uYwBF2nTNnr8LV3m/FU8RAlFAOPqf5kNO4NqBEdHxqqeTtIZJ BBZDc7kQoHEO58pf/N22shqtGv73S4NYbm+6jnh0R5xUBhy/2EwmwIezIIXvOGqt/02h QV1wLEhORN84Z3LEvIdXmXUppn0OJTvuXP+rYglU5+ACzMtUTQWf9UQOUFQAvFvxflE0 ceyw3L1BBe+1YJRcwbmo38qWYe57jneC+vauY7a5qeVCMOeXl1u7tAH/SZYQQnnmMeC1 RXuA== X-Gm-Message-State: AOJu0YzJL708eaA75DqpI4O8z1D2+73gwzTxOPP+PDz4X4pe4NKE/n8H i5F9q+VvsvkqyeNxs51UXmHsO6CNelTgVyVilY2o6j0bkSf4WEDZxIBz X-Gm-Gg: Acq92OGc5dUShnTuqly0oETsMLf5JMOiOR3CSOZj1FW08aRPU/vqGSWwisJYfmExZqS g3h80MmEOWSxsiLLGb7v0fWW757CZdjMiYzLFfouzKICyvZ7AC5/P8ljE1XhlCWnNpA9/HH+BKR rExv3TKsfvAe1I9kbzC6CfFif1pSLCKqwbnld4WZh1e2GhABBJ8X6Ha67yDtfKOmz98ZFedBQn1 0NxoB0SohXcQ6SdcL3eGDgSEY15Of7BS43aqCaMF6ZpwJfkWp9br6loE+U51FQagh5go+9cDVKl SqwJJB5i9hHrV6iBcsRR+WfTghyH6BOQZIZM6M5Hosv47xa5RtTCFs5mcsl2u4bbvmT4SoEnxiC ey0Z/sFDKGIwVsOg/0ctB9VejX4UmAwxP5JHQE0RF2Y7QlLjrAPQaNJ0YSdzWe9wajezEYV2WlK KHfHQfuf6hjBhZee/daorrdmvefhCUxA== X-Received: by 2002:a17:903:2b0e:b0:2b4:696b:7bb7 with SMTP id d9443c01a7336-2bd2f601102mr63795185ad.15.1778746271036; Thu, 14 May 2026 01:11:11 -0700 (PDT) From: Jaemyung Lee X-Google-Original-From: Jaemyung Lee Date: Thu, 14 May 2026 17:10:46 +0900 Subject: [PATCH v7 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: <20260514-write_booster-v7-3-c3ae3452980f@samsung.com> References: <20260514-write_booster-v7-0-c3ae3452980f@samsung.com> In-Reply-To: <20260514-write_booster-v7-0-c3ae3452980f@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=1778746262; l=3493; i=jaemyung.lee@samsung.com; s=20260402; h=from:subject:message-id; bh=U1I7iR9KAXBx24tNL1R8hKu0trzHrSPwvB+dS7OpoRs=; b=d0pa4iOIVhRUJClM4W3bMXe2hveXxz7dY69rUHsa8iSGi+9BmbLBxs1yK9iZ+j21bb8IFZbKh 1V3qquUxQ3/Di5Tcv4NcEtAJwY2bX0Fa5Ile4JmEauzTdqpk68LRzdA 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=lists1p.gnu.org; Received-SPF: pass client-ip=2607:f8b0:4864:20::62e; envelope-from=ldc.jml@gmail.com; helo=mail-pl1-x62e.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-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: 1778746343497158500 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 Reviewed-by: Jeuk Kim --- hw/ufs/ufs.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++= ++++ hw/ufs/ufs.h | 2 ++ 2 files changed, 73 insertions(+) diff --git a/hw/ufs/ufs.c b/hw/ufs/ufs.c index 69f82ab462d135fe6cda479891f9d8f26d19be9a..c504a0d7e3fb89eb5558cfd9c41= 0cda9396bc3b4 100644 --- a/hw/ufs/ufs.c +++ b/hw/ufs/ufs.c @@ -1801,6 +1801,71 @@ 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) +{ + if (!u->params.mcq) { + return true; + } + + for (int qid =3D 0; qid < ARRAY_SIZE(u->sq); qid++) { + if (!u->sq[qid]) { + continue; + } + + if (!ufs_mcq_sq_empty(u, qid)) { + return false; + } + + /* internal ongoing MCQ request check */ + UfsSq *sq =3D u->sq[qid]; + for (int i =3D 0; i < sq->size; i++) { + if (sq->req[i].state !=3D UFS_REQUEST_IDLE) { + return false; + } + } + } + + for (int qid =3D 0; qid < ARRAY_SIZE(u->cq); qid++) { + if (!u->cq[qid]) { + continue; + } + + if (!ufs_mcq_cq_empty(u, qid)) { + return false; + } + + if (!QTAILQ_EMPTY(&u->cq[qid]->req_list)) { + 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 +1928,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 +2025,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 +2055,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 May 30 18:35:59 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=gmail.com ARC-Seal: i=1; a=rsa-sha256; t=1778746364; cv=none; d=zohomail.com; s=zohoarc; b=Vzpp7AYfSt0zYKDQvSg39K14mkr8gYXWV5kmUF1Mel9xLauVxfb79Gc9GI+2u8G1iMWFjJRCP+DyA1kXvIYzo4afP1gfUwtk49xHEQpzSFdzwLSykJ1eZR1A6KgYeZk5WJMJW8HPpwlPJMhPwLEYnthbmg4hiPR7RWU+PkvW6h4= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1778746364; 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=Sz9zFadj0eryy1N/x2Rp41/1bN8n6orxsfMSg68s36k=; b=T/tL64nB5HdjSYWTE1hak36B8U3kkuBczgJQKrw+oH0ipwrWXOQNc8ukL6ivdjvWhwaZTqqDrwMOxJqtl9o8seElw7NOROzeKGToTaqsdO3PplOlfTqyc8BfN5TB5ZWa97sP7/ooOY9FWAYmJe7iOVYqddDFrOn3779hXjCm7cs= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1778746364531250.79461073608888; Thu, 14 May 2026 01:12:44 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wNRAK-0004fy-Fm; Thu, 14 May 2026 04:11:32 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wNRA7-0004cD-Av for qemu-devel@nongnu.org; Thu, 14 May 2026 04:11:21 -0400 Received: from mail-pl1-x62e.google.com ([2607:f8b0:4864:20::62e]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1wNRA3-0001d2-NP for qemu-devel@nongnu.org; Thu, 14 May 2026 04:11:18 -0400 Received: by mail-pl1-x62e.google.com with SMTP id d9443c01a7336-2ba1e9d3687so50761065ad.3 for ; Thu, 14 May 2026 01:11:14 -0700 (PDT) Received: from [172.17.0.5] ([168.126.243.22]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-2bd5c2631basm14480165ad.34.2026.05.14.01.11.11 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 14 May 2026 01:11:12 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1778746274; x=1779351074; 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=Sz9zFadj0eryy1N/x2Rp41/1bN8n6orxsfMSg68s36k=; b=dXq9SO4DphHhucqZT7GzPHbWhRxgzLup4ctdcs9GTFvQmwFUOonBYRfVwzOQEUxofj GznImhZSVpkbQCF38wPiemLR8Eem4DPTh1ryp6VUJgD253JYlMzZIFy5BmlNNBU934oo fv7XsakoDJ7xIh3Hwef/Ywep5W+ProoAk4OVzToaTM2sTpOPrpGl6CAahf7f9PZBbKr/ tTBWQtS/T3xbPIEkTNMuYmjE4Hi7znoYMwei/5H23RvYXfoE0LTVmXQzcAU1Xz8puQeV QYVbtaEAH5czyROXpgoGc9pysEmmqGxu6u6Duyudkzyus+dlvy3KestO3RgJqBSq63HU 54jw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1778746274; x=1779351074; 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=Sz9zFadj0eryy1N/x2Rp41/1bN8n6orxsfMSg68s36k=; b=sLofKh9WYj3SrniprAc3dNFLDwe7uDZXaXqAA0i/utSKs8UBVt/NEa2Bg41p7VotGu 2y3ZBoZJAv6C0SarC0vOMNj8xV5HkH0z5blbflru46pDJPcHWzx0aw3UPG8uzG1o2Xww msT0tgGoDDc48V61r98uBawjmXkoIVl9dBcHkG9YxkTAf6L3PIvxxOrMrkJbgIB5/a9g FZ+yxrgJyEHWfZJsmoHEJZvYKbBYcULNs0U1oa+4j3VIaxw3DVYCqi1j7MABwGZlrOgB QhMAMO+tSLB8WxFYTQWo7W5Bo810oHWDu6aAYRjCmhWLgQpOoIHfP6IXqhyTw+JCspdK gVfA== X-Gm-Message-State: AOJu0YxIubYMic1M+6ITPx5hkiJzbR0gH3tmOYcqIe6ILgMwPbsYUIvt BRyghCzz/N9s/xq2FOfxZkAeiKCFh5NXrLDeb07giCooN7QjZXZdUmzV X-Gm-Gg: Acq92OFm7dg//YIGz9y3aAq7YXRhCGn9Th0YmGzXi8NE2tUpujTGhgH6JBe/LpOsR/f fp/OvtcrljhrGsLlL9Ak9nlaZ+xGS6bprpkn+RqAZj8kgt35xE3TgaYbIB9SPGafcGHZZJQBVvU EdCioqFENEkec2ZHDyjBLnMnTGDwaPvrniJxoB8X0owJS7KBfYqaNtPShaMheENUUbX1OwtExGS UHJKwYKsjMbCtyjU1rYug2Erfaw+YlfxEFyygtBU4vFpmME3BNXJnq4lgijdblhbW1qEHlvtu0t XUOsvK9MMBmPRqLSUCs9LpwuKVjYxsdUDSRW8gp+wfM0s14EhMkt331rRH2eYsuT3iP/k8on/oA 0+sOz064JLCvk28nf/itF07Ues6qCzVsaQduehDCegCk5lkcJkzH9nmfTu7EazWby3hGwmI6Snq p6oUUMzFrlu4PTMuuNKkckTPKmP+3a8A== X-Received: by 2002:a17:902:d486:b0:2b9:87e0:1f80 with SMTP id d9443c01a7336-2bd30210d53mr69678485ad.24.1778746273318; Thu, 14 May 2026 01:11:13 -0700 (PDT) From: Jaemyung Lee X-Google-Original-From: Jaemyung Lee Date: Thu, 14 May 2026 17:10:47 +0900 Subject: [PATCH v7 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: <20260514-write_booster-v7-4-c3ae3452980f@samsung.com> References: <20260514-write_booster-v7-0-c3ae3452980f@samsung.com> In-Reply-To: <20260514-write_booster-v7-0-c3ae3452980f@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=1778746262; l=31293; i=jaemyung.lee@samsung.com; s=20260402; h=from:subject:message-id; bh=fADtbB20gBW3+kSqBvzGtRoIc5kmaPhtiYA+5a9N5ms=; b=anVjcThHzU+FVv0HOgVPlrzRZ+w+Aj94Aky/ywQH0YhafNiDbyCE70yQpUelvbfvwooh3kKgU E/KjWCSDKBID0oa0M84DMs3BWT7mPb+pdMDfBGSi5Dw9WZ4peXeNQim 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=lists1p.gnu.org; Received-SPF: pass client-ip=2607:f8b0:4864:20::62e; envelope-from=ldc.jml@gmail.com; helo=mail-pl1-x62e.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-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: 1778746365618158500 Add UFS Write Booster implementation which follows UFS 4.1 Spec. Signed-off-by: Jaemyung Lee Reviewed-by: Jeuk Kim --- hw/ufs/lu.c | 102 +++++++++++- hw/ufs/ufs.c | 448 ++++++++++++++++++++++++++++++++++++++++++++++++= +--- hw/ufs/ufs.h | 47 ++++++ include/block/ufs.h | 55 +++++++ 4 files changed, 632 insertions(+), 20 deletions(-) diff --git a/hw/ufs/lu.c b/hw/ufs/lu.c index 3f3c9589cee57ae3e77e2f486476d5fcec204d80..b33587cc85a1ae64e9b82fffed2= 6bef8530e87e8 100644 --- a/hw/ufs/lu.c +++ b/hw/ufs/lu.c @@ -58,13 +58,113 @@ static void ufs_build_scsi_response_upiu(UfsRequest *r= eq, uint8_t *sense, status, data_segment_length); } =20 +#define UFS_GROUP_NUMBER_MASK 0x1F +#define UFS_WB_GROUP_NUMBER_DEFAULT 0x00 /* 00000b */ +#define UFS_WB_GROUP_NUMBER_PINNED 0x18 /* 11000b */ +static bool ufs_wb_check_write_pinned(UfsHc *u, UfsRequest *req) +{ + uint8_t cmd =3D req->req_upiu.sc.cdb[0]; + uint8_t group_number =3D UFS_WB_GROUP_NUMBER_DEFAULT; + + if (u->attributes.wb_buffer_partial_flush_mode !=3D UFS_WB_FLUSH_PINNE= D) { + return false; + } + + if (cmd =3D=3D WRITE_16) { + group_number =3D req->req_upiu.sc.cdb[14] & UFS_GROUP_NUMBER_MASK; + + } else if (cmd =3D=3D WRITE_10) { + group_number =3D req->req_upiu.sc.cdb[6] & UFS_GROUP_NUMBER_MASK; + } + + return (group_number =3D=3D UFS_WB_GROUP_NUMBER_PINNED); +} + +static void ufs_wb_process_write_normal(UfsHc *u, uint32_t transfered_len) +{ + 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, transfered_len); +} + +#define UFS_WB_TOTAL_WRITTEN_DIV (10 * 1024 * 1024) /* 10MiB */ +static void ufs_wb_process_write_pinned(UfsHc *u, uint32_t transfered_len) +{ + UfsWb *wb =3D &u->wb; + uint64_t remain_bytes, remain_data; + uint32_t total_written; + + if (!wb->pinned_curr_bytes) { + ufs_wb_process_write_normal(u, transfered_len); + return; + } + + if (wb->pinned_used_bytes >=3D wb->pinned_curr_bytes) { + ufs_wb_process_write_normal(u, transfered_len); + return; + } + + remain_bytes =3D wb->pinned_curr_bytes - wb->pinned_used_bytes; + if (remain_bytes >=3D transfered_len) { + wb->pinned_total_written_bytes +=3D transfered_len; + wb->pinned_used_bytes +=3D transfered_len; + wb->used_bytes +=3D transfered_len; + remain_data =3D 0; + + } else { + wb->pinned_total_written_bytes +=3D remain_bytes; + wb->pinned_used_bytes +=3D remain_bytes; + wb->used_bytes +=3D remain_bytes; + remain_data =3D transfered_len - remain_bytes; + } + + total_written =3D wb->pinned_total_written_bytes / UFS_WB_TOTAL_WRITTE= N_DIV; + u->attributes.pinned_wb_cumm_written_size =3D cpu_to_be32(total_writte= n); + + ufs_wb_process_write_normal(u, remain_data); +} + +static void ufs_wb_process_write_req(UfsRequest *req, uint32_t transfered_= len) +{ + UfsHc *u =3D req->hc; + + if (!u->flags.wb_en || !ufs_is_write_req(req)) { + return; + } + + if (ufs_wb_check_write_pinned(u, req)) { + ufs_wb_process_write_pinned(u, transfered_len); + } else { + ufs_wb_process_write_normal(u, transfered_len); + } + + ufs_wb_update_avail_buffer(u); +} + static void ufs_scsi_command_complete(SCSIRequest *scsi_req, size_t resid) { UfsRequest *req =3D scsi_req->hba_private; int16_t status =3D scsi_req->status; - uint32_t transfered_len =3D scsi_req->cmd.xfer - resid; =20 + /* WB accounting should only happen for successful commands */ + if (status =3D=3D GOOD) { + ufs_wb_process_write_req(req, transfered_len); + } + ufs_build_scsi_response_upiu(req, scsi_req->sense, scsi_req->sense_len, transfered_len, status); =20 diff --git a/hw/ufs/ufs.c b/hw/ufs/ufs.c index c504a0d7e3fb89eb5558cfd9c410cda9396bc3b4..98ff612d9a4df3abb659458e732= 56e906c968317 100644 --- a/hw/ufs/ufs.c +++ b/hw/ufs/ufs.c @@ -375,7 +375,12 @@ static void ufs_process_uiccmd(UfsHc *u, uint32_t val) u->reg.hcs =3D FIELD_DP32(u->reg.hcs, HCS, UTMRLRDY, 1); u->reg.ucmdarg2 =3D UFS_UIC_CMD_RESULT_SUCCESS; break; - /* TODO: Revisit it when Power Management is implemented */ + /* + * TODO: Revisit after PM implementation + * Power Management is not supported in current QEMU-UFS, + * So Write Booster's Flush during Hibern8 operation is also remained + * as not considered. + */ case UFS_UIC_CMD_DME_HIBER_ENTER: u->reg.is =3D FIELD_DP32(u->reg.is, IS, UHES, 1); u->reg.hcs =3D FIELD_DP32(u->reg.hcs, HCS, UPMCRS, UFS_PWR_LOCAL); @@ -872,6 +877,32 @@ static const MemoryRegionOps ufs_mmio_ops =3D { }, }; =20 +static void ufs_wb_update_ee_status(UfsHc *u, uint16_t *ee_status) +{ + UfsWb *wb =3D &u->wb; + uint64_t curr_bytes =3D wb->curr_bytes - wb->pinned_curr_bytes; + uint64_t used_bytes =3D wb->used_bytes - wb->pinned_used_bytes; + + if (curr_bytes !=3D 0 && used_bytes >=3D curr_bytes) { + *ee_status |=3D MASK_EE_WB_FLUSH_NEEDED; + } else { + *ee_status &=3D ~MASK_EE_WB_FLUSH_NEEDED; + } + + if (u->attributes.wb_buffer_resize_hint !=3D UFS_WB_HINT_KEEP) { + *ee_status |=3D MASK_EE_WB_RESIZE_HINT; + } else { + *ee_status &=3D ~MASK_EE_WB_RESIZE_HINT; + } + + if (wb->pinned_used_bytes !=3D 0 && + wb->pinned_used_bytes >=3D wb->pinned_curr_bytes) { + *ee_status |=3D MASK_EE_PINNED_WB_FULL; + } else { + *ee_status &=3D ~MASK_EE_PINNED_WB_FULL; + } +} + static void ufs_update_ee_status(UfsHc *u) { uint16_t ee_status =3D be16_to_cpu(u->attributes.exception_event_statu= s); @@ -890,6 +921,8 @@ static void ufs_update_ee_status(UfsHc *u) ee_status &=3D ~MASK_EE_TOO_LOW_TEMP; } =20 + ufs_wb_update_ee_status(u, &ee_status); + u->attributes.exception_event_status =3D cpu_to_be16(ee_status); } =20 @@ -996,11 +1029,16 @@ static const int flag_permission[UFS_QUERY_FLAG_IDN_= COUNT] =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, + /* TODO: Revisit after PM implementation */ [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) @@ -1094,8 +1132,8 @@ static QueryRespCode ufs_write_flag_value(UfsHc *u, u= int8_t idn, uint8_t value) 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; + case UFS_QUERY_FLAG_IDN_UNPIN_EN: + u->flags.unpin_en =3D value; break; default: return UFS_QUERY_RESULT_INVALID_VALUE; @@ -1189,16 +1227,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 +1280,31 @@ static inline uint8_t ufs_read_device_temp(UfsHc *u) return 0; } =20 +static inline uint32_t ufs_wb_read_flush_status(UfsHc *u) +{ + uint32_t value =3D u->attributes.wb_buffer_flush_status; + + if (value =3D=3D UFS_WB_FLUSH_SUSPENDED || + value =3D=3D UFS_WB_FLUSH_COMPLETED || + value =3D=3D UFS_WB_FLUSH_FAILED) { + u->attributes.wb_buffer_flush_status =3D UFS_WB_FLUSH_IDLE; + } + + return value; +} + +static inline uint32_t ufs_wb_read_resize_status(UfsHc *u) +{ + uint32_t value =3D u->attributes.wb_buffer_resize_status; + + if (value =3D=3D UFS_WB_RESIZE_COMPLETED || + value =3D=3D UFS_WB_RESIZE_FAILED) { + u->attributes.wb_buffer_resize_status =3D UFS_WB_RESIZE_IDLE; + } + + return value; +} + static uint32_t ufs_read_attr_value(UfsHc *u, uint8_t idn) { switch (idn) { @@ -1292,7 +1359,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 +1390,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 +1412,132 @@ 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; + } + + if (value =3D=3D UFS_WB_IDLE) { + return; + } + + u->attributes.wb_buffer_resize_en =3D value; + u->attributes.wb_buffer_resize_status =3D UFS_WB_RESIZE_IN_PROGRESS; + u->attributes.wb_buffer_resize_hint =3D UFS_WB_HINT_KEEP; +} + +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->fifo_curr_bytes); + u->attributes.curr_fifo_wb_partial_flush_mode =3D cpu_to_be32(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 <=3D wb->pinned_used_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; + + assert(wb->curr_bytes >=3D wb->pinned_curr_bytes); + assert(wb->used_bytes >=3D wb->pinned_used_bytes); +} + +static void ufs_wb_sync_buffer_size(UfsHc *u) +{ + UfsWb *wb =3D &u->wb; + uint64_t avail_bytes; + + wb->fifo_curr_bytes =3D MIN(wb->curr_bytes, wb->fifo_max_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->non_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; + wb->pinned_used_bytes =3D MIN(wb->pinned_curr_bytes, + wb->pinned_used_bytes); + + } else { + wb->pinned_curr_bytes =3D wb->pinned_max_bytes; + wb->pinned_used_bytes =3D MIN(wb->pinned_curr_bytes, + wb->pinned_used_bytes); + } + + ufs_wb_update_avail_buffer(u); +} + +static bool ufs_wb_max_fifo(UfsHc *u, uint32_t value) +{ + UfsWb *wb =3D &u->wb; + uint64_t fifo_max_bytes =3D ufs_unit_to_byte(u, value); + + if (fifo_max_bytes > wb->max_bytes) { + return false; + } + + u->attributes.max_fifo_wb_partial_flush_mode =3D cpu_to_be32(value); + wb->fifo_max_bytes =3D fifo_max_bytes; + ufs_wb_sync_buffer_size(u); + + return true; +} + +static bool ufs_wb_pinned_max_size(UfsHc *u, uint32_t value) +{ + UfsWb *wb =3D &u->wb; + uint64_t pinned_max_bytes =3D ufs_unit_to_byte(u, value); + + if (wb->max_bytes < wb->non_pinned_min_bytes + pinned_max_bytes) { + return false; + } + + u->attributes.pinned_wb_num_alloc_units =3D cpu_to_be32(value); + wb->pinned_max_bytes =3D pinned_max_bytes; + ufs_wb_sync_buffer_size(u); + + return true; +} + +static bool ufs_wb_pinned_min_size(UfsHc *u, uint32_t value) +{ + UfsWb *wb =3D &u->wb; + uint64_t non_pinned_min_bytes =3D ufs_unit_to_byte(u, value); + + if (wb->max_bytes < non_pinned_min_bytes + wb->pinned_max_bytes) { + return false; + } + + u->attributes.non_pinned_wb_min_num_alloc_units =3D cpu_to_be32(value); + wb->non_pinned_min_bytes =3D non_pinned_min_bytes; + ufs_wb_sync_buffer_size(u); + + return true; +} + static QueryRespCode ufs_write_attr_value(UfsHc *u, uint8_t idn, uint32_t = value) { switch (idn) { @@ -1383,6 +1574,34 @@ 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; + ufs_wb_sync_buffer_size(u); + break; + case UFS_QUERY_ATTR_IDN_MAX_FIFO_WB_PARTIAL_FLUSH_MODE: + if (!ufs_wb_max_fifo(u, value)) { + return UFS_QUERY_RESULT_INVALID_VALUE; + } + break; + case UFS_QUERY_ATTR_IDN_PINNED_WB_NUM_ALLOC_UNITS: + if (!ufs_wb_pinned_max_size(u, value)) { + return UFS_QUERY_RESULT_INVALID_VALUE; + } + break; + case UFS_QUERY_ATTR_IDN_NON_PINNED_WB_MIN_NUM_ALLOC_UNITS: + if (!ufs_wb_pinned_min_size(u, value)) { + return UFS_QUERY_RESULT_INVALID_VALUE; + } + break; default: g_assert_not_reached(); return 0; @@ -1801,10 +2020,136 @@ static void ufs_sendback_req(void *opaque) ufs_irq_check(u); } =20 +static inline uint64_t ufs_wb_total_flush_bytes(UfsHc *u) +{ + UfsWb *wb =3D &u->wb; + uint64_t no_flush_bytes; + + switch (u->attributes.wb_buffer_partial_flush_mode) { + case UFS_WB_FLUSH_NONE: + no_flush_bytes =3D 0; + break; + case UFS_WB_FLUSH_FIFO: + no_flush_bytes =3D wb->fifo_curr_bytes; + break; + case UFS_WB_FLUSH_PINNED: + no_flush_bytes =3D (u->flags.unpin_en) ? 0 : wb->pinned_used_bytes; + break; + default: + g_assert_not_reached(); + break; + } + + if (wb->used_bytes < no_flush_bytes) { + return 0; + } + + 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, total_flush_bytes; + + switch (u->attributes.wb_buffer_flush_status) { + case UFS_WB_FLUSH_IDLE: + case UFS_WB_FLUSH_SUSPENDED: + if (!u->flags.wb_buffer_flush_en || !ufs_wb_total_flush_bytes(u)) { + break; + } + + u->attributes.wb_buffer_flush_status =3D UFS_WB_FLUSH_IN_PROGRESS; + /* fallthrough */ + case UFS_WB_FLUSH_IN_PROGRESS: + if (!u->flags.wb_buffer_flush_en) { + u->attributes.wb_buffer_flush_status =3D UFS_WB_FLUSH_SUSPENDE= D; + break; + } + + total_flush_bytes =3D ufs_wb_total_flush_bytes(u); + if (!total_flush_bytes) { + u->attributes.wb_buffer_flush_status =3D UFS_WB_FLUSH_COMPLETE= D; + break; + } + + /* Flush Pinned first */ + 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(total_flush_bytes, UFS_WB_FLUSH_BYTES); + wb->used_bytes -=3D flush_bytes; + } + + u->attributes.wb_buffer_flush_status =3D UFS_WB_FLUSH_COMPLETED; + /* fallthrough */ + case UFS_WB_FLUSH_COMPLETED: + if (ufs_wb_total_flush_bytes(u)) { + u->attributes.wb_buffer_flush_status =3D + (u->flags.wb_buffer_flush_en) ? UFS_WB_FLUSH_IN_PROGRESS : + UFS_WB_FLUSH_IDLE; + } + } +} + +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_IDLE: + /* Do nothing. Complete resize directly. */ + break; + case UFS_WB_DECREASE: + if (wb->curr_bytes <=3D wb->min_bytes || + 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_process_idle(UfsHc *u) { - /* Currently do nothing */ - return; + ufs_wb_process_flush(u); + ufs_wb_process_resize(u); + ufs_wb_sync_buffer_size(u); } =20 static inline bool ufs_check_idle(UfsHc *u) @@ -1885,6 +2230,11 @@ static bool ufs_check_constraints(UfsHc *u, Error **= errp) return false; } =20 + if (u->params.wb_min_size > u->params.wb_max_size) { + error_setg(errp, "wb-min-size must be less than or equal wb-max-si= ze"); + return false; + } + return true; } =20 @@ -1923,11 +2273,54 @@ static void ufs_init_state(UfsHc *u) } } =20 +static void ufs_wb_init(UfsHc *u) +{ + UfsWb *wb =3D &u->wb; + uint32_t max_units =3D u->params.wb_max_size; + uint32_t min_units =3D u->params.wb_min_size; + + wb->max_bytes =3D ufs_unit_to_byte(u, max_units); + wb->min_bytes =3D ufs_unit_to_byte(u, min_units); + + 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(max_units); + + 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; + + u->attributes.max_fifo_wb_partial_flush_mode =3D cpu_to_be32(max_units= ); + u->attributes.curr_fifo_wb_partial_flush_mode =3D cpu_to_be32(max_unit= s); + + wb->fifo_max_bytes =3D ufs_unit_to_byte(u, max_units); + wb->fifo_curr_bytes =3D ufs_unit_to_byte(u, max_units); + + u->attributes.pinned_wb_num_alloc_units =3D cpu_to_be32(max_units); + u->attributes.non_pinned_wb_min_num_alloc_units =3D 0; + + wb->pinned_curr_bytes =3D 0; + wb->pinned_used_bytes =3D 0; + wb->pinned_max_bytes =3D ufs_unit_to_byte(u, max_units); + wb->non_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)); @@ -1989,8 +2382,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(u->params.wb_max_size); =20 memset(&u->geometry_desc, 0, sizeof(GeometryDescriptor)); u->geometry_desc.length =3D sizeof(GeometryDescriptor); @@ -2006,6 +2404,14 @@ 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 0x1; + u->geometry_desc.write_booster_buffer_cap_adj_fac =3D 0x3; + u->geometry_desc.supported_write_booster_buffer_user_space_reduction_t= ypes =3D + 0x1; + 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; @@ -2020,6 +2426,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 @@ -2085,6 +2493,8 @@ 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), }; =20 static const VMStateDescription ufs_vmstate =3D { diff --git a/hw/ufs/ufs.h b/hw/ufs/ufs.h index b5f040302129f4d02732ddd20ef82eb33c41922a..6ae8e235b145f7596ba24a9d27a= 4ab4a4f90d8de 100644 --- a/hw/ufs/ufs.h +++ b/hw/ufs/ufs.h @@ -91,6 +91,8 @@ 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 */ } UfsParams; =20 /* @@ -118,6 +120,26 @@ typedef struct UfsCq { QTAILQ_HEAD(, UfsRequest) req_list; } UfsCq; =20 +/* + * Extended features + */ +typedef struct UfsWb { + uint64_t max_bytes; + uint64_t min_bytes; + uint64_t curr_bytes; + uint64_t used_bytes; + uint64_t resize_bytes; + + uint64_t fifo_max_bytes; + uint64_t fifo_curr_bytes; + + uint64_t pinned_max_bytes; + uint64_t non_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 +169,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 +236,27 @@ 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 (uint64_t)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; +} + +static inline bool ufs_is_write_req(UfsRequest *req) +{ + uint8_t cmd =3D req->req_upiu.sc.cdb[0]; + + /* UFS 4.1 Specifiaction doesn't support WRITE_12 */ + return (cmd =3D=3D WRITE_6) || (cmd =3D=3D WRITE_10) || (cmd =3D=3D WR= ITE_16); +} + #define TYPE_UFS "ufs" #define UFS(obj) OBJECT_CHECK(UfsHc, (obj), TYPE_UFS) =20 @@ -243,5 +289,6 @@ void ufs_build_upiu_header(UfsRequest *req, uint8_t tra= ns_type, uint8_t flags, uint16_t data_segment_length); void ufs_build_query_response(UfsRequest *req); void ufs_complete_req(UfsRequest *req, UfsReqResult req_result); +void ufs_wb_update_avail_buffer(UfsHc *u); void ufs_init_wlu(UfsLu *wlu, uint8_t wlun); #endif /* HW_UFS_UFS_H */ diff --git a/include/block/ufs.h b/include/block/ufs.h index 4dacfb776f947a285d86018add82115f148b7dd9..0f7cc9c21b8c5e9f31b1256ee47= 68aff700968fc 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, @@ -1153,6 +1166,9 @@ enum ufs_lu_wp_type { enum { MASK_EE_TOO_HIGH_TEMP =3D BIT(3), MASK_EE_TOO_LOW_TEMP =3D BIT(4), + MASK_EE_WB_FLUSH_NEEDED =3D BIT(5), + MASK_EE_WB_RESIZE_HINT =3D BIT(8), + MASK_EE_PINNED_WB_FULL =3D BIT(10), }; =20 /* UTP QUERY Transaction Specific Fields OpCode */ @@ -1207,6 +1223,45 @@ 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_INCREASE =3D 2, + UFS_WB_RESIZE_HINT_MAX, +}; + +enum ufs_wb_resize_op { + UFS_WB_IDLE =3D 0, + UFS_WB_DECREASE =3D 1, + UFS_WB_INCREASE =3D 2, + 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 May 30 18:35:59 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=gmail.com ARC-Seal: i=1; a=rsa-sha256; t=1778746358; cv=none; d=zohomail.com; s=zohoarc; b=Wz09TRgq/JtQLEg+PcIsO3r03HhmjggphKOZ7s/WdN18Ln6xXkVsd9/lHpGkdBCgrZ3XVCOdZY0f+mWndFKv/UK/sg9N0x6A2FoUSU8gwLSajg1wU8xwCPghrBp+J3mi8H4K744VUcadZEkzEcTBd/8Eh9q86dEozxOQ/pilTWQ= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1778746358; 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=MQ+5ywA3ydfBVc0Y2SIXe1ysRDC1KubdnKS/us59kO4=; b=Cz2SVz0hIjpZRkXoOp5PvaCy4nuLJFwMQDNiAI+1r13UrQwASktVL38stxbPx4ASUzfX1D5Yjrjw+8IHPSSoS3cd7aYfDjYdQ3y3uOQNwKkpSJOnPGoslONmVhZKLraCAlpfQfwdLCTHj+SSqnnp5/Y2q/IA7Be5vVHNFSbStqA= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1778746358725756.3915017186255; Thu, 14 May 2026 01:12:38 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wNRAK-0004fj-DK; Thu, 14 May 2026 04:11:32 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wNRA6-0004c8-Vp for qemu-devel@nongnu.org; Thu, 14 May 2026 04:11:21 -0400 Received: from mail-pl1-x635.google.com ([2607:f8b0:4864:20::635]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1wNRA4-0001dq-Vr for qemu-devel@nongnu.org; Thu, 14 May 2026 04:11:18 -0400 Received: by mail-pl1-x635.google.com with SMTP id d9443c01a7336-2bd2c147abaso12208465ad.3 for ; Thu, 14 May 2026 01:11:16 -0700 (PDT) Received: from [172.17.0.5] ([168.126.243.22]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-2bd5c2631basm14480165ad.34.2026.05.14.01.11.13 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 14 May 2026 01:11:14 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1778746275; x=1779351075; 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=MQ+5ywA3ydfBVc0Y2SIXe1ysRDC1KubdnKS/us59kO4=; b=BbfzvFama7deOjubR1gO5O6Vp7f1FzQlqfPnQijXGrH2F6s12JzEFbhGpgXEzSYjvZ gWB0TYnt6bB+/+xwgiZlnx+jb/nKtzNk0oFrIpi9mtb6SsxdZxRApEDz+KOCIBKmw15Y rGto4zlKo8+x+zz3upoqWg/NTiLjqOPib0eXCcct+n1caAHEa8vnkB/jfkSjei9okkA0 L1ayaFFyPjPtG2yMkqoHxNUT413M/k9OByk+jWj/Nd4QfKCSKhT4JmjKp9IzgtN6UgmT ufVEJEKp/fQjhauSvhK+gPTde+IayPSuefyKzPGOvMxfATvvrTHY4KUkdxLkbprdSqv1 qLOA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1778746275; x=1779351075; 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=MQ+5ywA3ydfBVc0Y2SIXe1ysRDC1KubdnKS/us59kO4=; b=KY1YmvnluNPWUagBwdq884X8sxgOmZtkXXjUyTfvXWLsN8TFeY4o7A+gEfD7/d+eAY SCDA1wKg1mhTOc5sIghV7O6RCk41OS07/yC4IL8yqBqA8tZna6XwSyTykNP1FTH/Sq1q cEbjxU7TjE5of8gTjqaY8dlFqk5FSp9IIbJtG3cGT7HJDSe/dmxLXhC/lYzdj2KpXCrB dRXgSODdvW3FNXa9crXvNESZlpiFWFMwwny8kLsu7+BtXgsexBkoWrXAnsmOc0Vg8zW3 qizpMbgVkSqvNiX0goVUQrDVVEsOwgtIjRR4cz+eJEqBsOZyRO4+8PC1fK2jjkq7qctz x1cA== X-Gm-Message-State: AOJu0Yw4qnuBc7RA+i1kYpT/j+nenNM/cFTFPObaZDopT5BfHSJ7+mqG pqzk9n8m1ZIUtMfvN8RTMmOgqy2qZ9+9vafnX6OeIjTCL6fm0McwIYPX X-Gm-Gg: Acq92OEmuYdfgbCl3NWM0JRGS0FBniVH+TxSJ6UGty/6nj20SzQ62mg52sGz3/UfO4r IK6mTBO79twGf0rWBQp269Z+v3fWzWlWJ+gwdPjXtUxk/8ISUek0RjBxfE8dmZRoJQNMlnFmVau 1qxIe972+gV+BfobW6j6sdGwn5iCKPz70CNThYvhTM2Bs5ymufCYmWRAbDADRWq7TYNoeIR7+PI 1jLGqiZvM9j41kZpSQ0qorLPJaBEOM8HTwr8aOGvArm8xXYMGIXJ5ABnyRmncdEl8ywiGV9kSyo cQAR1GLQ6kBSEPCl570ZcqVZjB5T3ReQswMeW3vdY43BjxFNL54c9DJyjERrBoo75a+U0j/BsNr qEOctZkmSVni/nmhegpWidy3EsUUwQixsodsRS4l6vFUFkxf8qnn8Ugwr9Y4gdbpB3V6L8FNIvD E92DAoAao4OSjgolCEzw5MwhrGfOHSQg== X-Received: by 2002:a17:902:ceca:b0:2bd:2de3:5181 with SMTP id d9443c01a7336-2bd2de353e8mr65173175ad.9.1778746275334; Thu, 14 May 2026 01:11:15 -0700 (PDT) From: Jaemyung Lee X-Google-Original-From: Jaemyung Lee Date: Thu, 14 May 2026 17:10:48 +0900 Subject: [PATCH v7 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: <20260514-write_booster-v7-5-c3ae3452980f@samsung.com> References: <20260514-write_booster-v7-0-c3ae3452980f@samsung.com> In-Reply-To: <20260514-write_booster-v7-0-c3ae3452980f@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=1778746262; l=8707; i=jaemyung.lee@samsung.com; s=20260402; h=from:subject:message-id; bh=VF/oNvi7a6+2ChQ1c7V146kArgtcUgd94DaSD1duQAw=; b=z2zEWSas4vxuk76WJwPAtvnFNIz/QNB/ucyBVQElOlNbEWd/CV+/4krOiVC/O5BxzFhmiAFCV w4PXHqzAnKiASQIySfcedgmVaAfj2S8W5bZyBJwoMCCVdWkP6sNYwLy 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=lists1p.gnu.org; Received-SPF: pass client-ip=2607:f8b0:4864:20::635; envelope-from=ldc.jml@gmail.com; helo=mail-pl1-x635.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-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: 1778746359504158500 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 Reviewed-by: Jeuk Kim --- tests/qtest/ufs-test.c | 172 +++++++++++++++++++++++++++++++++++++++++++++= ++++ 1 file changed, 172 insertions(+) diff --git a/tests/qtest/ufs-test.c b/tests/qtest/ufs-test.c index 7f999441552a105987aaaf8e2b976f4a05f953ed..c33cb58c14e94f7b44a454bce34= ad35ecace5634 100644 --- a/tests/qtest/ufs-test.c +++ b/tests/qtest/ufs-test.c @@ -1182,6 +1182,170 @@ 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 lduw_be_p(desc + UFS_DEVICE_DESC_PARAM_EXT_WB_SUP); + g_assert_cmpuint(value, =3D=3D, WB_RESIZE | WB_FIFO | WB_PINNED); + + value =3D ldl_be_p(desc + UFS_DEVICE_DESC_PARAM_EXT_UFS_FEATURE_SUP); + 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 ldl_be_p(desc + UFS_GEOMETRY_DESC_PARAM_WB_MAX_ALLOC_UNITS); + 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 +1398,12 @@ 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-size=3D256" }; + add_qpci_address(&edge_opts, &(QPCIAddress){ .devfn =3D QPCI_DEVFN(4, = 0) }); =20 qos_node_create_driver("ufs", ufs_create); @@ -1262,6 +1432,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