From nobody Sat Apr 11 17:09:03 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=1775800682; cv=none; d=zohomail.com; s=zohoarc; b=hetuZpDRi4y11/rrXOd4lUyg6q4cY+Ex745vi8iVOv5+e8Auedetop721Iw1vYxBe92jmvzYHbXGBJxcvac6j5p3n0IDCsO7Yd38x9WnHXgSm4XEPjokakA6Sadfhbx/V1/1C7RvnAHbJQSzMzt6719bvKDtg1jIrVeV6YHISfs= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1775800682; 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=lg1IVoT1JmHmC7SBaLWiU8PeNlx8orzgtvJ/6bMd5Zc7+MMda7EVkboFE/jeD1oKJ9IhoPaWIXnSGqtMGgr8wT3XA0habyaDtAGCM4INwXJGG7LmsiUkDXP3eIt/A+dD7Rr2Ai2TyNRk4gO/wySAjpV2naXxPeB0IZ3dJ1dcVzs= 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 (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1775800682591208.55315125662582; Thu, 9 Apr 2026 22:58:02 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wB4s3-0004q1-JG; Fri, 10 Apr 2026 01:57:35 -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 1wB4s2-0004pT-3z for qemu-devel@nongnu.org; Fri, 10 Apr 2026 01:57:34 -0400 Received: from mail-pg1-x532.google.com ([2607:f8b0:4864:20::532]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1wB4rz-0007x4-PL for qemu-devel@nongnu.org; Fri, 10 Apr 2026 01:57:33 -0400 Received: by mail-pg1-x532.google.com with SMTP id 41be03b00d2f7-c76b9efc299so765938a12.0 for ; Thu, 09 Apr 2026 22:57:31 -0700 (PDT) Received: from [172.17.0.5] ([168.126.243.22]) by smtp.gmail.com with ESMTPSA id 41be03b00d2f7-c79218fc8d9sm1225965a12.12.2026.04.09.22.57.27 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 09 Apr 2026 22:57:29 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1775800650; x=1776405450; 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=gJfoNWtLYI1l+dhNeTzkYGNFjhPvGoghdmOnbqZwW/jzLsrcJVncviC2pgWUMB4LSK EHSkbMTZ9pyFzsVMEEZGk1mp7nf/KnH5B6VwpK6OpEqhTOKx/dTZpOss7aGuFDsxzDFb Q8krR6bpImKj16kwToXIFo8ggQelBSlaBbFeBEliTTAIB8nkZfcBeX4cFrslIK5Bjr0Q 4bCY+HiNZRyDkCcRy8Fl2skJ9STvV36tZLJF5MiCAVnMjHP3wfs88n+fnCXK+024r5h1 tTve/ab3j9YCMP9VqStcYxWs6TR2bnqzkJJC/uoGx+ZMQKmIPQoTEQmOki9kHr6QuBDQ 11cQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1775800650; x=1776405450; 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=Qsq0WVjmCP2jzTuVfpQTfRIWJ528PnILSqSWmxuGc31Q7zK4waHqI7O3nNRvSh09VF sH+Wi0W19U9Y9lTxeGcbERxTe3oDlQB6KBJYxJLab6dEOO2ZRfy/kFUmczbRQaodlSGo ZWXkRPR1/QMAwmcDMdkD4e4iVJXEtLmoNHfZY2yVWIuW1x0anHCn+KWNCjNg7uDZTP7u nZDhoukYKDesic9C517OWMlQ8d3txrA8qso7excQron8O+fLsihoTyQHUcI8l8jyZ5oC zi8QIReypOBmm3ysr0S8oDug1pBFDfpoQFJrAgj2WmGm1OMzYhwhRa8+UU/noxo+g3dm l5WQ== X-Gm-Message-State: AOJu0YwveiK5QpiB+CGd5S8ti8K52QdMpuYea6Q60qTwo9GFEwcIdiP4 SZbqsNna2V0D6yZ+RfcMu43H+nM5O+MK38i80s/8cOtvyiVruuWiu8oMYAaQMrybG8w= X-Gm-Gg: AeBDievahg52yDG2l2GLta8jARhYVrxGLXzodPbyHkfYDkKd9+ZScIIRr+sprmT1hqy 5gyUSmsYNSQ4uBE8EViILBcL9nQFYSKSTUXaRbwvFnvMA6tCx//c0PFucoE3TW0n3ZlVGdpJMFQ uI1QNElDJyfPAn6JA955YPOG6Kh2P3ni5KHHULPNprjBFcwe0VgVlrmkDS6aWkPWfb8jABXMnOu TrxssGniAwyn4ztg3oforTF9YuFOAj+cFXqmwBHQGGYYMksKoXDM+91CMG6p5vDOXQROhvHttsl GuRLxNcFUKF+6OK9I2I2YYu4D0lQyIqRFGn6ylHm8X3OAKueA9BTcUt+1ENj03eA0x5tOANvdA2 RbSSHQoNZKtsU4ILGJHV26vKrqvYVqRVRhHOGhDqWkCPcw/K/Zhkf8CucWfFq6ZkRluQH3RBdI3 1dtEFYHLlk4XyYxyMN/TEbsR0ubtHgYw== X-Received: by 2002:a05:6a20:938f:b0:39b:f8d1:a603 with SMTP id adf61e73a8af0-39fe3d17fbbmr2155471637.22.1775800650180; Thu, 09 Apr 2026 22:57:30 -0700 (PDT) From: Jaemyung Lee X-Google-Original-From: Jaemyung Lee Date: Fri, 10 Apr 2026 14:57:14 +0900 Subject: [PATCH v5 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: <20260410-write_booster-v5-1-d44e1a0e191c@samsung.com> References: <20260410-write_booster-v5-0-d44e1a0e191c@samsung.com> In-Reply-To: <20260410-write_booster-v5-0-d44e1a0e191c@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=1775800645; l=12799; i=jaemyung.lee@samsung.com; s=20260402; h=from:subject:message-id; bh=CgN8ljzeml1hAPWOnqVTo/m8W7lnE0WV5YXREroYZ/Q=; b=529NF8ziGwReTLjoHuoRJ8Nn/LqkRPBrjJFyju3Ss/BerpTGj6D8GviwlpNPT8O/LbhuZNKl1 mG9ujRC5xX0B5zSeiB+qDs0XX9kkxeNKomjZFhUt6kuqfb7LZPwuKPc 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::532; envelope-from=ldc.jml@gmail.com; helo=mail-pg1-x532.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: 1775800684472158500 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 17:09:03 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=1775800686; cv=none; d=zohomail.com; s=zohoarc; b=nn1v4R739tD5nkpy063WsXgT8CCKhhaKlecHma3OS7Jz9+3WMZ4JTvOrlsjFH3n58YrJ0gBNxUU/2oTs2O13oPImdW+bXEaMiGy7gA0oLj7NQrK3HOjlcTV7E/8kdNG+iu3oCOEMOwt21kXvXem5piv1pmIYKwHrBp/WlDTRoEo= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1775800686; 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=d4t7ELMIQaYZB1J0G+Hv87XMId1AYagc0fJOdj/yAOvi4m4s5B6oiqsYpjH+XVb/Aef+IvNUKyx8XPSHtdMuoNrVRONH8pBHDBvIlvuDTGJesLSNHTdWpGDa2/3wNumiMGua5LgDosIsxBgTbKGJkDDR0afJqqpjTS87Nj9AW0Q= 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 (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1775800686367632.6024158790797; Thu, 9 Apr 2026 22:58:06 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wB4s5-0004qb-7s; Fri, 10 Apr 2026 01:57:37 -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 1wB4s4-0004q3-1Q for qemu-devel@nongnu.org; Fri, 10 Apr 2026 01:57:36 -0400 Received: from mail-pj1-x1036.google.com ([2607:f8b0:4864:20::1036]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1wB4s2-0007xZ-92 for qemu-devel@nongnu.org; Fri, 10 Apr 2026 01:57:35 -0400 Received: by mail-pj1-x1036.google.com with SMTP id 98e67ed59e1d1-35d965648a2so1529394a91.0 for ; Thu, 09 Apr 2026 22:57:33 -0700 (PDT) Received: from [172.17.0.5] ([168.126.243.22]) by smtp.gmail.com with ESMTPSA id 41be03b00d2f7-c79218fc8d9sm1225965a12.12.2026.04.09.22.57.30 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 09 Apr 2026 22:57:32 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1775800653; x=1776405453; 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=T7EmLdBH4LA+o6pHMRJtTArEblpOd9Wx+SZpVsQ7ej1uYqykPN9kBB6ns6nvEMAjL/ nkoYukFbqyMCOrUkHUTsczSn2E/sri72uiaZaxOI2mA0l9exV017k+szwf8xj5S954Hc QvSd6iYNTuQYxuMJTPzRmUJ9ESwF8Mz0b2/6beUHupkOaf8iyuLUz0LpvWWjmZ6xdulE 1gUwEAGdMFogOH/q//E6K8QxqbsXCcp5BYJaDMEsWJzMJh/dF1S0SfKnrHJRgjPaIXnD BcmMwaJRVuA7sR3oZp6oy3mrGbuM6eQDV2uEE06PdV3y2jUkVrwJGtSBN8Kepja3OtrI Z0Tg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1775800653; x=1776405453; 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=BSKVrgojQ8/Y/oHpwgUn0C2U5EHMN5E5/Cml5bCJdfpmFEwwFv1udUTXkzAuIF0piH UEmcGnmd0ctHlwPLgnPMITrU4DkTPZ46cBUR/bCkoGNn7ZGG2YdeO8oEd5zdMM6o4dUg Gled5A8da0vjWcaKd4eKA2nNH61kQlAX6vNG0Ma2fnWb8kFK2ibz+UatKFndCDBicXPi qzdN2bwj8dTvVF6DTe1YM3JQU5lgCeJdt6QyoMIcVoAWnttKtb0AC/RApYPBhSCAg0oJ q0b48gsKJjtdK/fNR3IQPPR+feLM3Bt0dOZW1+NYPCdhISWQvAtDZCngBHEEVrRvNV8K yaxA== X-Gm-Message-State: AOJu0YxtLuYOdOSQUlbSW4QWycGzUfiRJy8OdMkRM4Y5cG6RGza8dXrp G8RcNLoi8E4XABn57i4BMfjXoQMfLvTZDyZ/GEAN/eKZ64TFYTPVgX8h X-Gm-Gg: AeBDietfLVFXNZnwG8sZ8Qs5q/e9SfuncVJf8S3MHUdwOeAbLm/hGav+FxmMzOkVQRx eFK3nWVJvoCukS6to40kddbZF4fGyUu4atD6WZQVC8UKX5Jkgsd/TvIaBJnqDbblZ704mTSx6ll m7TaDPUus3T0Fttg+9ci8OH7E0aZZgkHQ1Y2nz3V2gE5W6+F2DL/hvpAINNiTpQAr3kuAI8yh6k DCLu07qssQVTKMRzLmBbNhn/l2N4QieRtyq2nIJMkPgfUhibgbz6wGTVGUJhYvhdhesq+9C6o80 YjPIb+k8sbODkC0ALd5k0r+DS0VA0CnEW3w7313aEv4qkHe+FxYgGPEuLTCuyuFNz6A2YaLRVR9 V2tqrGsDt+swXkyAtJQRrdsXbSEUTppkoD+dD5JzxPUo9gZe/4T+J9eti5NDucvTqVVYQQmsHH7 ILkqg42AqCBvB2hkpE6GQDqV86IbvbNQ== X-Received: by 2002:a17:90b:2e49:b0:35d:935f:2ff with SMTP id 98e67ed59e1d1-35e427a423amr1961898a91.2.1775800652817; Thu, 09 Apr 2026 22:57:32 -0700 (PDT) From: Jaemyung Lee X-Google-Original-From: Jaemyung Lee Date: Fri, 10 Apr 2026 14:57:15 +0900 Subject: [PATCH v5 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: <20260410-write_booster-v5-2-d44e1a0e191c@samsung.com> References: <20260410-write_booster-v5-0-d44e1a0e191c@samsung.com> In-Reply-To: <20260410-write_booster-v5-0-d44e1a0e191c@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=1775800645; l=6656; i=jaemyung.lee@samsung.com; s=20260402; h=from:subject:message-id; bh=UwQldvutZu9HqLXksjdiAk3IKzXkRCngBaBlZ026a4E=; b=hinVNtXg2/Ua3scU5pktlj5elhjNbUtuAJNfvHR5hBSj451AIPP3Q88pGpTeT8MgqphC4F99g 8wuyvw9zK6DCPLOPCpKjzLcDYRKLCyhGhtw8RtH94I0G9lSNDp4mRU1 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::1036; envelope-from=ldc.jml@gmail.com; helo=mail-pj1-x1036.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: 1775800687877154100 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 17:09:03 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=1775800715; cv=none; d=zohomail.com; s=zohoarc; b=G2qartNX0xnqLtTqoTRP/u+F25NSTCdv2wlIciNdDzhiEVqEhSMmml7pAdQWMUlqLCSFd+PaLlD5H0DQ5PR7M6bpxjPaqJ08S50Ulpv7u2SUmUV7Sh8L9p/yFdyiqOUvfmgH6+fTXjgMqPF2MZ1poBfF87G5/UZntanbDHFyHlM= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1775800715; 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=JaciWTqVmWxxBGzy8Jhiuqc1VjI18qtcQYS1SFVvjvteZc3OKCcXGpuwFOjT6NKW1/j7TU64jzQV26ypSJYXdBjpquNKlMemyBahQAabySkLK+bb2w4ZdoEnXN3p6HISCgWCLBlv+lHiULbIlSqsBbc1OIbCnCsWTnoWu6bpyD0= 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 (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1775800715635924.2942333025596; Thu, 9 Apr 2026 22:58:35 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wB4s7-0004rk-MC; Fri, 10 Apr 2026 01:57:39 -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 1wB4s6-0004r5-9y for qemu-devel@nongnu.org; Fri, 10 Apr 2026 01:57:38 -0400 Received: from mail-pg1-x52b.google.com ([2607:f8b0:4864:20::52b]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1wB4s4-0007yJ-Qw for qemu-devel@nongnu.org; Fri, 10 Apr 2026 01:57:38 -0400 Received: by mail-pg1-x52b.google.com with SMTP id 41be03b00d2f7-c736261ee8dso686710a12.1 for ; Thu, 09 Apr 2026 22:57:36 -0700 (PDT) Received: from [172.17.0.5] ([168.126.243.22]) by smtp.gmail.com with ESMTPSA id 41be03b00d2f7-c79218fc8d9sm1225965a12.12.2026.04.09.22.57.33 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 09 Apr 2026 22:57:35 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1775800655; x=1776405455; 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=nVwzyxZlQvwRIVA+kgibucTsoo9px2EivKfE8/IcKP4EHjcswWyVjRzYvyzviU0X7d GqTDlhHVBokOCCPOiLwS644uYowWyCC+AkeeEPpI9Kh3+NX0IjNn05cgNJ08ldcrNnjP +fDuO5RYid/hqrfSD+Ey3C1uuQiEsYqOMWWXNUnVjGUtrpDCHFpHVyetbmpx9i5eeQri Y++d8zgwADlFrfy8vnx/tOVliJ2UsMDjnumi3ZBb/EqUQuWkZy3XKjeCGfFk+KJgqRq9 uupNJgOaAIbnWYWx1/WcE5DE7Qu5K0aGFmv9Oim81Fn6c2xE/Pq+lFpVoaqIYQ2EfJU8 8Kdw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1775800655; x=1776405455; 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=Coc5BvSEYZB4waKr30OzAOw1ObAI+BEtY8TikOny0tVQCSDah5vDq5L2nV4FZ2SgML nH3BWdtVUGijmjw3Q1xwwcCuzq2b5kE7ly1DR0gKelj3Ps3xqi8nMNbiZS52pw6MKU/t NJyLOIKqzj5K41SbiLYA4e5KWS7vWm6D3ORoybeqEqZeSFKU4iVlwyxUhNnN311CTEiR 5c8U+khOG8m3CCwXqMmfESEFuBgywUp436Xa0YCDN9P0tJzSv+vPX4sQoNtAuMotGCf6 WfE1aENT4f/RhwLIRR9EymeLytNwfqiR4kODRdxNPBecBTGfLCZ9T3C8hcbtrKRpEToj C1vQ== X-Gm-Message-State: AOJu0YxCu6lwC0Wf7xwOJz5VATMyiDNAEFDBh+HFkzMd2upoZkO4V/PO cgPNfJ+vwTkyWIRV6oGkV01i0tCMPkMwxdWITvdex50xPM0XcQcVfSZr X-Gm-Gg: AeBDiesn2doynK3oZCWyhAFTIF5p75yGy9WeVnEKtZU4N2WLSmd1poJbmNe/BSzpb+7 NKLmMA4EDP24+Ql2fVua1VKhMVTrvdGZh7aswvMk4UAI1fA1pBB63P2DX3qTVZDwqQ0MiCUHmB7 MHVdfHtaytEheV/PBHGlDyzQAL5tETnZCt27daodvhn2UvjPoVuuxGzorYEKtkWcof5mH1SRfb2 VCLPqCUAlRN+SUIMPK5F1hBxftwHL92u6OcPVmyMLDtbQ/KRRoNcO/VXuRU0b7/0dN/DgLURq+3 Kxtk56giw4V7NvkOj4FIsh34PpB8h4DcTw9DSBqW7O62mgYA7ZIWZWBW1l9yHe9XwflWvI91utG w72wAODRV7SgxOmQMjdw4/nOpqUZ2oHgq3mUZkCGM+Yeqeb5d9LZLrPaytkI1YRtXLCAtwY/GfB FvPMHCxWgQcia8xCQ8Ik/j1iCT2dfRTQ== X-Received: by 2002:a05:6a20:729b:b0:39c:4c23:a175 with SMTP id adf61e73a8af0-39fe40026a7mr2115115637.45.1775800655436; Thu, 09 Apr 2026 22:57:35 -0700 (PDT) From: Jaemyung Lee X-Google-Original-From: Jaemyung Lee Date: Fri, 10 Apr 2026 14:57:16 +0900 Subject: [PATCH v5 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: <20260410-write_booster-v5-3-d44e1a0e191c@samsung.com> References: <20260410-write_booster-v5-0-d44e1a0e191c@samsung.com> In-Reply-To: <20260410-write_booster-v5-0-d44e1a0e191c@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=1775800645; l=3493; i=jaemyung.lee@samsung.com; s=20260402; h=from:subject:message-id; bh=U1I7iR9KAXBx24tNL1R8hKu0trzHrSPwvB+dS7OpoRs=; b=W8jthARYna/2LYMfh5ouMy3fTqaKr56qNjQpI3MDkq1KG6PHSxqLrTCuE0fmO3kCcnNe1/YO4 0oMMu/eNkKyAHrd4Zr8acIECW6J0C+VXIx1CHVPc9fI1kssWX7ULzxr 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::52b; envelope-from=ldc.jml@gmail.com; helo=mail-pg1-x52b.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: 1775800716253158500 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 | 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 Apr 11 17:09:03 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=1775800714; cv=none; d=zohomail.com; s=zohoarc; b=F93pckRaQAmqjL74ymXShnT9UIq2Pym1q2GpZjaJ8zMVAvVUA7l8JCR/5IP/peb1s6mLTuD7cCgBz6vTq+fpzwOgLGLMxe2j8xtF4VlHGEcTTyW9mYDA/vIFFA/ipW8aMwu8tHams5XoFI2l0ubXj/Go9mV/OoTj/+gh6cjHJts= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1775800714; 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=/jnwcGWe0CEMIdSZ9yYs8I1gaoqoOOd3VKWz0yFN/qM=; b=iIRXC8KhD1Gt9ap6WpQYEn6RYlijNO8Bi1CT/MjbuY5/Ma9jMsHSmjHmpEwF4pfa9ODPVcx+4hO4B2f1iFQMy273JNTu5flDtxKf7WNRqgbRVOPEYT+tOlsbAuGABiCF80UrP5HS9pvBvrftk2qC6gscNLc5cZuY6a6ylGYAyw8= 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 (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1775800714414902.9719351854625; Thu, 9 Apr 2026 22:58:34 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wB4sC-0004t0-1o; Fri, 10 Apr 2026 01:57:44 -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 1wB4sA-0004sA-GJ for qemu-devel@nongnu.org; Fri, 10 Apr 2026 01:57:42 -0400 Received: from mail-pg1-x531.google.com ([2607:f8b0:4864:20::531]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1wB4s7-0007yy-JM for qemu-devel@nongnu.org; Fri, 10 Apr 2026 01:57:42 -0400 Received: by mail-pg1-x531.google.com with SMTP id 41be03b00d2f7-c766a95a72dso1141512a12.1 for ; Thu, 09 Apr 2026 22:57:39 -0700 (PDT) Received: from [172.17.0.5] ([168.126.243.22]) by smtp.gmail.com with ESMTPSA id 41be03b00d2f7-c79218fc8d9sm1225965a12.12.2026.04.09.22.57.35 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 09 Apr 2026 22:57:37 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1775800658; x=1776405458; 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=/jnwcGWe0CEMIdSZ9yYs8I1gaoqoOOd3VKWz0yFN/qM=; b=XEqK1bhdr7/gXV11wUkK7pZlvuZ5eXY/SvLOkQaA93OVlM9FeK+8E1tc8wFsD0HgRv GGn8RW/tdjjTR3datPU2enRhcdbNLJ8Kf20lKNxt0LLEsh5/bef4BrN2xFRFBcti2gEp jViDLuIlmXJ2UnKJdq9YgaRG8pCWuUo2/y8nJjfFWv+Cg5AbF/JtnB9QCemJkjFVfZNc QRX0Zin/5Jf3vZkyWLTUj3blXSDSLPDetIu0gaSHpJ/5Q22B7+UkSBekvCpx8cLmpPFN bFPzLQWPnWOQ69hjVfNwf1E48Kn3qoF40zQBy9KhXHyuJuNI0jFMaplD/t10fVdt4jNz 69Vw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1775800658; x=1776405458; 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=/jnwcGWe0CEMIdSZ9yYs8I1gaoqoOOd3VKWz0yFN/qM=; b=l7l6uew0k55QWVuIlP/0kLSCfhSIlxsXWc2JYZb3/Qpu1psyhsR0fIaTD7zSaf3iYP 3e3J/Rc7I/PpP10khKNm+I6E/50B3yk4E3WVPF41IMwZYLG+VOb4FG4crVDvwG/Jkx3x 2CwivwpztTW3rJXpxBhsnJd/js6HtcagFRrlGRxBZJa+dfvfXS9lXgBOeAozWMgeVC9s 9F/E/VcEAzQYtP78ZIQJo7+0a784EcgG2/S/34j78lhRWsn1tCD6Zq5IaQ8YLERJ8Elb M4uculXbxn74sveGx4q4UhBPpT5D9SdKc1uPzIXz0JiO2LBzjJo7M1XKglmWdZAvbiFy IoRg== X-Gm-Message-State: AOJu0YyGvNWcL6VMMSDxM8EXbrR+fVLc8FhIc8F+pxJThLyURLTuDwYM jeTWQU+Zq9w3tUI+/AHATGhhDgAStkfAtpCBTOaptcdgN5ncGZ/KjymL X-Gm-Gg: AeBDietVMHbEAJ4fGqRgPYbio+RlOtQNYz21QWHJ/yKcNxcv5D39d9dy4AZFf1yEK6Q kB/ds9s21a7l/wvbjqQ97cGDDk4X0iZgYhfRNmhxvPw+CI5OJqz47alP6fFsOXMLNgHfXwiAAVj nIBvst85THwF7aGMLg0UIXcxrWVNeNqFbmGRc0IklYY115+bMilqdblkDoqaYkGJ9I1lTr8eGwd SWV1TYH0XHdX7SNO8WQkqlwEcQ6DysSFZ6a7kD/+PA+RAgATRoBYD2xEUOKJYXG/dIm1cYvG2Cg OHmqES8ntjoS4GLJNUVLwaH8YwhHMOKM5cenRScAeIpyGijhT02KrEK0iI2rO15COJv+K2zIzLy o5z3pLShQlEEP4Io0fy1zq8WhoJE9vWhl38y62UtvER2I5wtfbUDcdwQ/RTKvqXvmCsaGc62bWH 0oH9aE6y3SBbJJPYKATjMXGC4aNuXR3Q== X-Received: by 2002:a05:6a20:1592:b0:398:a1ca:7a22 with SMTP id adf61e73a8af0-39fe40d2beemr2332379637.54.1775800658255; Thu, 09 Apr 2026 22:57:38 -0700 (PDT) From: Jaemyung Lee X-Google-Original-From: Jaemyung Lee Date: Fri, 10 Apr 2026 14:57:17 +0900 Subject: [PATCH v5 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: <20260410-write_booster-v5-4-d44e1a0e191c@samsung.com> References: <20260410-write_booster-v5-0-d44e1a0e191c@samsung.com> In-Reply-To: <20260410-write_booster-v5-0-d44e1a0e191c@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=1775800645; l=26154; i=jaemyung.lee@samsung.com; s=20260402; h=from:subject:message-id; bh=bWjBlkztsvNX/EqLRnY2XYsPXz/4kWT4lCyOXhj6kYg=; b=Mg8xfzh4s3TT2Pppl5pj/b9V+8S1yEBtNN2+SxOkpPqa7lm4qIQL2ZBn3ZJ/BSpn+/dY9mKiG QwhtMuVeMIEBY2qFdt4e5dT7q/vvwm9Lhj931aQbu4lQgPYvAtmzu7c 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::531; envelope-from=ldc.jml@gmail.com; helo=mail-pg1-x531.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: 1775800716272158500 Add UFS Write Booster implementation which follows UFS 4.1 Spec. Signed-off-by: Jaemyung Lee --- hw/ufs/lu.c | 97 ++++++++++++++- hw/ufs/ufs.c | 337 ++++++++++++++++++++++++++++++++++++++++++++++++= +--- hw/ufs/ufs.h | 47 ++++++++ include/block/ufs.h | 51 ++++++++ 4 files changed, 516 insertions(+), 16 deletions(-) diff --git a/hw/ufs/lu.c b/hw/ufs/lu.c index 3f3c9589cee57ae3e77e2f486476d5fcec204d80..b4ec91d6b806c100b0ae96c67e3= a3404694517ed 100644 --- a/hw/ufs/lu.c +++ b/hw/ufs/lu.c @@ -58,13 +58,108 @@ 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); +} + +#define UFS_WB_TOTAL_WRITTEN_DIV (1000 * 1000) /* 10MB */ +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) { + 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 transfered_len) { + wb->pinned_total_written_bytes +=3D transfered_len; + wb->pinned_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; + 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); + + 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, 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); +} + +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); + } +} + 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..78bd3e4a0536350400cfb7a4f14= e93c790e7a9d3 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,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_flush_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 +1328,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 +1359,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 +1381,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 +1443,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 +1882,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_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_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 @@ -1885,6 +2134,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 +2177,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)); @@ -1989,8 +2274,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 +2296,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; @@ -2020,6 +2320,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 +2387,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..42a20245128a765afc256034213= 5ced81dcc684c 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,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 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 17:09:03 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=1775800719; cv=none; d=zohomail.com; s=zohoarc; b=i/8NJgvPB8XEg7UONfolrVy7Nnisqida5jL4UfHnuEkwWNtf0Vs8LcJI5hOg6MfkR17SCK271rhx2yDmBBdq1laCVwS25o3J16vTPMgIa5C18G1Kbx7ghRnuIi98EkVgpliUi0WH2MB06ZwTO44VAFpeYKRDCQeH3e9/ekDINB0= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1775800719; 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=Bz1U/f25iAnmatonMx8HV2z+Q4NlqQY3IbAKNzV5iSACRz2L0OpT/X7I8ETCVnpgh41SflWeBF6UEMuRaiws6/OTuXn8CNL1sv7cGiqDaakSG7+IeS3qGJnl1QEs3o7Ppb7EWi8OhgZyzEcvTpVJp5/8I+yXJ0WQj2hjCsqYzjU= 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 (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1775800719499593.9170286286922; Thu, 9 Apr 2026 22:58:39 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wB4sE-0004vt-2y; Fri, 10 Apr 2026 01:57:46 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wB4sC-0004t2-7d for qemu-devel@nongnu.org; Fri, 10 Apr 2026 01:57:44 -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 1wB4sA-0007zM-Cz for qemu-devel@nongnu.org; Fri, 10 Apr 2026 01:57:44 -0400 Received: by mail-pg1-x535.google.com with SMTP id 41be03b00d2f7-c70fb6aa323so671296a12.3 for ; Thu, 09 Apr 2026 22:57:42 -0700 (PDT) Received: from [172.17.0.5] ([168.126.243.22]) by smtp.gmail.com with ESMTPSA id 41be03b00d2f7-c79218fc8d9sm1225965a12.12.2026.04.09.22.57.38 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 09 Apr 2026 22:57:40 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1775800661; x=1776405461; 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=odOEuxPSULQeUrqIBSKO9zOBgyfXoUy9cnR2a349r0DzstylLTDjM+/tB85SZ1y9/b l6e+Drht6NZhYfT9X2o8SpcaAH0F9yXpmLynNNJGa7KNsrUWxn/Ohm2gxofRAAxYLiKC OyUrKAOIWz1c/8I3aQxxNu9lY8NtW/mtk6qTf/dCqfwzPvU83dAr+8v9iKrzWVkcO7GN rW0l9Q3RMTd6aCZ7YwkdjRbaruRhEFLyAsfHhmGRovk1BY8YcArCf/zQ771netcpIk1A S8T5X+0/QjrCStm/e7U+euSFzmN2xX92xyuNpNf4RHJ23FlHWCX05ad68WQOVxvAcfkR ZZJg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1775800661; x=1776405461; 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=Qzy2TfeBApd86/3XWrv7IEDU8+7eonJMCZngXRQIBi1/q57dbNHJ9AOmbzvotp5D4y lmtCJIFQta9SnE1SmSbL0YbnDebqzjLhHbZjacN2A9x8nscXVte4BSAocaur49b0eKw7 iVpUPwkUomodE6UtwH53wokD8pSmFpY2spsHKF4qMsIgRYj20DsQZ47KXQU6BXUx6wE/ puVA+Y1VuyeW3qYrOctlTh6aGDJe23BhFa1Ec+wopxVHMd+HaL0KsynQBhg0GtQOY2HR Wm0aWullz2IDpeKWp06aa4Xf5acWrg7pkpmU0RGVWWfd+8hbZwTxelhqD2xjJfh5JIrM vmMA== X-Gm-Message-State: AOJu0YxiTBcQ++2wz4pjcWXGddyCipsbLV/XGjEnoeDHhifUoGZQgBwX WV8d9F4xVIML+Ql9JEFvaPRlN62Waza6YLNN1DeBKq5awsCk6Bry6oQC X-Gm-Gg: AeBDievaHMMIyuKbqg6rsK80vskrPwPHI6sCLQ3+tPvOxH68YJmuoCKgoGeA51Nqn0T tmxvOim2i31jr3NYS8SriAaw/og4mm0kF2eq7Ik7O8TCVkOjrxMqwRnTEBhU8B1WUbSCwtcq/Dy vP5SSRzD/w2Z1m0BE5vWVYVzgyxE6IkIZY3hGqFZkFnWJ0jeIbdql8N2ETEqBDUDV/GOux0veoe R3n2aTvtBFOiK23Tm+43OsvbOxZWbHfun95b6bxbcIC8aXKwAs1xlDttp9Jg3NRPJUqHHBNpUPp ESlL2RB9D9pJo/YXISMq/I6kDPSBDU3bGeYcmTyMlR4vRwtCIU+inqpzgLxrWmhciqN0vYWWnlg hrmwY5FkhwefcE9cZGjMa/M0MouS+u5grwBYVh79YjP9ZBF0sFP3abRob/76/Ejnzs1y4ElOxvn q3NQvWTXPPD1Yj2gzo1K1gfq+Oh/2T0DSVPvdjTL3g X-Received: by 2002:a05:6a20:6a1d:b0:39f:a8fb:3354 with SMTP id adf61e73a8af0-39fe3cf233fmr2319155637.17.1775800660823; Thu, 09 Apr 2026 22:57:40 -0700 (PDT) From: Jaemyung Lee X-Google-Original-From: Jaemyung Lee Date: Fri, 10 Apr 2026 14:57:18 +0900 Subject: [PATCH v5 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: <20260410-write_booster-v5-5-d44e1a0e191c@samsung.com> References: <20260410-write_booster-v5-0-d44e1a0e191c@samsung.com> In-Reply-To: <20260410-write_booster-v5-0-d44e1a0e191c@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=1775800645; l=8918; i=jaemyung.lee@samsung.com; s=20260402; h=from:subject:message-id; bh=rU67KxRcVLL6ZVBVhiBQ/INRn8llY3KXffQmzbO047E=; b=9aBa1DA8BEB/wBsYy+k3c3Bh5gJpLqOCExbaDWns0ydiSQAT4zknTw3J0R5LIH1lumD5kFBAg vG0L80gPwyVAlDvp+poDJy9rVT3+uylJ8BRUYBTJnEaIMFpflPBuWUH 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::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: 1775800720135158500 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