From nobody Sat Apr 11 18:38:38 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=1775590700; cv=none; d=zohomail.com; s=zohoarc; b=UvPo67rluY5GN47FxmVTUH+Zeuu4xmX43gzNVrHlwcvrAOz+Z4HBlzyGdGLZ5mUONUKQHE1BGyob6iMjSgSUVbExAtn50jvdDc5b4C3xTETn/Hq3Zpny0WkCsK8wvIy9eTOgAOAEnnr3534eZbRnAboWnIogR5giNZLv3M9qhLM= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1775590700; 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=PP7U0ijriQg52XdpvlTp9nrLd0A987FF7rduie3GFx9LiKXOdXcZNLaUYqNXm+Xl5ZtVIMp4Zoo9/2ddmy6gcmm6HB5m0UEd3vte7BKdN0noGTzAoFgD+Jde1yuN//QasDXlFzXdZ40A9fCUPMb/oH8CYO8UiLfu8u91BPIkiFo= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1775590700164476.77613601633277; Tue, 7 Apr 2026 12:38:20 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wABWi-0008C6-HR; Tue, 07 Apr 2026 14:51:57 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wABTn-0003JO-Bd for qemu-devel@nongnu.org; Tue, 07 Apr 2026 14:48:51 -0400 Received: from mail-pg1-x52a.google.com ([2607:f8b0:4864:20::52a]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1wA3fx-0003LP-Of for qemu-devel@nongnu.org; Tue, 07 Apr 2026 06:28:57 -0400 Received: by mail-pg1-x52a.google.com with SMTP id 41be03b00d2f7-c74244dc0b3so2936218a12.2 for ; Tue, 07 Apr 2026 03:28:53 -0700 (PDT) Received: from [172.17.0.5] ([168.126.243.22]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-82cf9b2714dsm21217324b3a.1.2026.04.07.03.28.50 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 07 Apr 2026 03:28:51 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1775557732; x=1776162532; 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=FU8hpNJ1XYQyh284aoZKp593x8Rwzte+8U7Fp0A3ZFYYp3FwqQ77bdF9vvnpGlVqf8 fTui4mq1rCNh3wlnt00+tYDYFD7eOPIO+BQew+aNDzcvx79zOFdAqpo0X+mjD1+e1OSf DaAqHr+zkRfLpnueZDk0upF2jwpZcNSKg9Urvl8acP9/TOlyjGvQ+VT8v3KhfdVfbFFv Xj04AYONgmec4g6gt3x5dAzBlncuRjFElcpll6M+jUD9/muHZjJKnqRWMUAlxvwVkd2G ytxv9mtbkiv6wG17M6FKSjvvM0cVneyvdTDJ26N2nxWcozDjOuSGngfzl/OS9982CH5G flDQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1775557732; x=1776162532; 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=gAbh/FrvlBOBNRdxLwFIv4DmjGcSgiNi8ll0GpOQtl7T4EmzbsXPSrbOc7ZdC/Hlpu +AT7im4cW7BzmvmkSThsT0x37VekqEE/qO6KpgCGBl2iopxSarPub8nNyYbMl/211KD9 eXj/JEQfvfx0PRo6wLe9rOE6CyUdw2LR44y6XrGSohFdAcNY/9wYz1ByJhZlBnEW0sEi YYg65mPLP65g2YIHzjVvSmtZr6yBJfiWicCmG4tKU8xasd3ZsfQcgnC62nHDHjpjymXU q8Ms6Q3mrZhsKQutIwOod2oN8HbbEggBTBHtUnbBfoQtWYiHp198wDQUtek09yl/Inue nNDw== X-Gm-Message-State: AOJu0YzqZzJLzQVzYOHpK7JHm2liq/U91n83m6cwLDgBqkBPd+HrDgfh V7QGGgzIy75rQfF9uieI8ncVGe2oRUfJ4DG5E+tHWPtCAHJ4V0iRkia9CSrmucxgpA8Bqw== X-Gm-Gg: AeBDieuwb1UK1tdagZBKXsjAroxb2402HVBl19SkvmIaXt1ri4HIpP4YNXdbXwpymYZ BJnG3KvVP4kONxc4mMs7Ds1VS2T8yP8fuscbYJp071hk6RaFWGxSnFXgnnoq6OmG0ajl+ps2J9/ BYexutrG5rPR7/ySblGqQzAvvwMshc8KEGfiVO41/pAtedhEduYINKgZBmG5zm7xLeh4I2vnqi2 fXPvRyYE5FjQfUTEopO402MlSG+4FXiXwX9H2IbpyjKxpDN7/WZYSZEbHfa/6pfjI0e+XI6YA3a myu3dsHzGjHFmtTj7NF7gzD2gjepbKRAaf/xBMNQ9+tIMeS3rrTAYbz47uwD55Y8eS12IPfc9fb fi1Mf/tD8N/Y972ANJNtJWcNOT3X74NToVMUjOl4DwwHlOSiC3rVgUK7VhK63BdzQi75x/u78/G 8pkkxizyyA8mMWfoP8QDAJCh8GiEImBenCJ3lRrp7D X-Received: by 2002:a05:6a20:7fa4:b0:366:2447:6778 with SMTP id adf61e73a8af0-39f2f11b01emr18907555637.53.1775557731942; Tue, 07 Apr 2026 03:28:51 -0700 (PDT) From: Jaemyung Lee X-Google-Original-From: Jaemyung Lee Date: Tue, 07 Apr 2026 19:23:39 +0900 Subject: [PATCH v2 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: <20260407-write_booster-v2-1-dd772bb30194@samsung.com> References: <20260407-write_booster-v2-0-dd772bb30194@samsung.com> In-Reply-To: <20260407-write_booster-v2-0-dd772bb30194@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=1775557727; l=12799; i=jaemyung.lee@samsung.com; s=20260402; h=from:subject:message-id; bh=CgN8ljzeml1hAPWOnqVTo/m8W7lnE0WV5YXREroYZ/Q=; b=79FF1PXm0qm+4tIDejVeBDQdgfLnCpBBl54N6d0dXWXXLa/Dyw3hsUWqMtqGEYfkBZmVaOHGY BHsxfTYhmGnACPu+b+pJrXqekI+oh78NB3c9wH69NfbehUUI2QnyAHr 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::52a; envelope-from=ldc.jml@gmail.com; helo=mail-pg1-x52a.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: 1775590701658158500 Apply current UFS 4.1 Specification to QEMU-UFS. QEMU-UFS device emulates operation via UFS 4.0 Specification, but current latest Spec. version is UFS 4.1. So extent internal DESCRIPTOR/FLAG/ATTRIBUTE declaration to follow UFS 4.1 Spec. It does not implement any actual functionallity, but only adds minimum supportability for further implementation. Signed-off-by: Jaemyung Lee --- hw/ufs/ufs.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++++= +--- include/block/ufs.h | 59 ++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 122 insertions(+), 6 deletions(-) diff --git a/hw/ufs/ufs.c b/hw/ufs/ufs.c index cb74cb56bc15ec6fb873097ccb1b6e5694639bd9..b2b70c8b38ebecd8d49ecce2886= 14d55efd90f2e 100644 --- a/hw/ufs/ufs.c +++ b/hw/ufs/ufs.c @@ -9,7 +9,7 @@ */ =20 /** - * Reference Specs: https://www.jedec.org/, 4.0 + * Reference Specs: https://www.jedec.org/, 4.1 * * Usage * ----- @@ -29,8 +29,8 @@ #include "trace.h" #include "ufs.h" =20 -/* The QEMU-UFS device follows spec version 4.0 */ -#define UFS_SPEC_VER 0x0400 +/* The QEMU-UFS device follows spec version 4.1 */ +#define UFS_SPEC_VER 0x0410 #define UFS_MAX_NUTRS 32 #define UFS_MAX_NUTMRS 8 #define UFS_MCQ_QCFGPTR 2 @@ -1000,6 +1000,7 @@ static const int flag_permission[UFS_QUERY_FLAG_IDN_C= OUNT] =3D { [UFS_QUERY_FLAG_IDN_WB_EN] =3D UFS_QUERY_FLAG_READ, [UFS_QUERY_FLAG_IDN_WB_BUFF_FLUSH_EN] =3D UFS_QUERY_FLAG_READ, [UFS_QUERY_FLAG_IDN_WB_BUFF_FLUSH_DURING_HIBERN8] =3D UFS_QUERY_FLAG_R= EAD, + [UFS_QUERY_FLAG_IDN_UNPIN_EN] =3D UFS_QUERY_FLAG_READ, }; =20 static inline QueryRespCode ufs_flag_check_idn_valid(uint8_t idn, int op) @@ -1057,10 +1058,31 @@ static const int attr_permission[UFS_QUERY_ATTR_IDN= _COUNT] =3D { [UFS_QUERY_ATTR_IDN_AVAIL_WB_BUFF_SIZE] =3D UFS_QUERY_ATTR_READ, [UFS_QUERY_ATTR_IDN_WB_BUFF_LIFE_TIME_EST] =3D UFS_QUERY_ATTR_READ, [UFS_QUERY_ATTR_IDN_CURR_WB_BUFF_SIZE] =3D UFS_QUERY_ATTR_READ, + [UFS_QUERY_ATTR_IDN_EXT_IID_EN] =3D UFS_QUERY_ATTR_READ, + [UFS_QUERY_ATTR_IDN_HOST_HINT_CACHE_SIZE] =3D UFS_QUERY_ATTR_READ, /* refresh operation is not supported */ [UFS_QUERY_ATTR_IDN_REFRESH_STATUS] =3D UFS_QUERY_ATTR_READ, [UFS_QUERY_ATTR_IDN_REFRESH_FREQ] =3D UFS_QUERY_ATTR_READ, [UFS_QUERY_ATTR_IDN_REFRESH_UNIT] =3D UFS_QUERY_ATTR_READ, + [UFS_QUERY_ATTR_IDN_TIMESTAMP] =3D UFS_QUERY_ATTR_WRITE, + [UFS_QUERY_ATTR_IDN_DEVICE_LEVEL_EXCEPTION_ID] =3D UFS_QUERY_ATTR_READ, + /* host initiated defragmentation is not supported */ + [UFS_QUERY_ATTR_IDN_DEFRAG_OP] =3D UFS_QUERY_ATTR_READ, + [UFS_QUERY_ATTR_IDN_HID_AVAIL_SIZE] =3D UFS_QUERY_ATTR_READ, + [UFS_QUERY_ATTR_IDN_HID_SIZE] =3D UFS_QUERY_ATTR_READ, + [UFS_QUERY_ATTR_IDN_HID_PROG_RATIO] =3D UFS_QUERY_ATTR_READ, + [UFS_QUERY_ATTR_IDN_HID_STATE] =3D UFS_QUERY_ATTR_READ, + [UFS_QUERY_ATTR_IDN_WB_BUFF_RESIZE_HINT] =3D UFS_QUERY_ATTR_READ, + [UFS_QUERY_ATTR_IDN_WB_BUFF_RESIZE_EN] =3D UFS_QUERY_ATTR_READ, + [UFS_QUERY_ATTR_IDN_WB_BUFF_RESIZE_STATUS] =3D UFS_QUERY_ATTR_READ, + [UFS_QUERY_ATTR_IDN_WB_BUFF_PARTIAL_FLUSH_MODE] =3D UFS_QUERY_ATTR_REA= D, + [UFS_QUERY_ATTR_IDN_MAX_FIFO_WB_PARTIAL_FLUSH_MODE] =3D UFS_QUERY_ATTR= _READ, + [UFS_QUERY_ATTR_IDN_CURR_FIFO_WB_PARTIAL_FLUSH_MODE] =3D UFS_QUERY_ATT= R_READ, + [UFS_QUERY_ATTR_IDN_PINNED_WB_BUFF_CURR_ALLOC_UNITS] =3D UFS_QUERY_ATT= R_READ, + [UFS_QUERY_ATTR_IDN_PINNED_WB_BUFF_AVAIL_PERCENT] =3D UFS_QUERY_ATTR_R= EAD, + [UFS_QUERY_ATTR_IDN_PINNED_WB_CUMM_WRITTEN_SIZE] =3D UFS_QUERY_ATTR_RE= AD, + [UFS_QUERY_ATTR_IDN_PINNED_WB_NUM_ALLOC_UNITS] =3D UFS_QUERY_ATTR_READ, + [UFS_QUERY_ATTR_IDN_NON_PINNED_WB_MIN_NUM_ALLOC_UNITS] =3D UFS_QUERY_A= TTR_READ, }; =20 static inline QueryRespCode ufs_attr_check_idn_valid(uint8_t idn, int op) @@ -1194,12 +1216,50 @@ static uint32_t ufs_read_attr_value(UfsHc *u, uint8= _t idn) return u->attributes.wb_buffer_life_time_est; case UFS_QUERY_ATTR_IDN_CURR_WB_BUFF_SIZE: return be32_to_cpu(u->attributes.current_wb_buffer_size); + case UFS_QUERY_ATTR_IDN_EXT_IID_EN: + return u->attributes.ext_iid_en; + case UFS_QUERY_ATTR_IDN_HOST_HINT_CACHE_SIZE: + return be16_to_cpu(u->attributes.host_hint_cache_size); case UFS_QUERY_ATTR_IDN_REFRESH_STATUS: return u->attributes.refresh_status; case UFS_QUERY_ATTR_IDN_REFRESH_FREQ: return u->attributes.refresh_freq; case UFS_QUERY_ATTR_IDN_REFRESH_UNIT: return u->attributes.refresh_unit; + case UFS_QUERY_ATTR_IDN_DEVICE_LEVEL_EXCEPTION_ID: + return be64_to_cpu(u->attributes.device_level_exception_id); + case UFS_QUERY_ATTR_IDN_DEFRAG_OP: + return u->attributes.defrag_op; + case UFS_QUERY_ATTR_IDN_HID_AVAIL_SIZE: + return be32_to_cpu(u->attributes.hid_avail_size); + case UFS_QUERY_ATTR_IDN_HID_SIZE: + return be32_to_cpu(u->attributes.hid_size); + case UFS_QUERY_ATTR_IDN_HID_PROG_RATIO: + return u->attributes.hid_prog_ratio; + case UFS_QUERY_ATTR_IDN_HID_STATE: + return u->attributes.hid_state; + case UFS_QUERY_ATTR_IDN_WB_BUFF_RESIZE_HINT: + return u->attributes.wb_buffer_resize_hint; + case UFS_QUERY_ATTR_IDN_WB_BUFF_RESIZE_EN: + return u->attributes.wb_buffer_resize_en; + case UFS_QUERY_ATTR_IDN_WB_BUFF_RESIZE_STATUS: + return u->attributes.wb_buffer_resize_status; + case UFS_QUERY_ATTR_IDN_WB_BUFF_PARTIAL_FLUSH_MODE: + return u->attributes.wb_buffer_partial_flush_mode; + case UFS_QUERY_ATTR_IDN_MAX_FIFO_WB_PARTIAL_FLUSH_MODE: + return be32_to_cpu(u->attributes.max_fifo_wb_partial_flush_mode); + case UFS_QUERY_ATTR_IDN_CURR_FIFO_WB_PARTIAL_FLUSH_MODE: + return be32_to_cpu(u->attributes.curr_fifo_wb_partial_flush_mode); + case UFS_QUERY_ATTR_IDN_PINNED_WB_BUFF_CURR_ALLOC_UNITS: + return be32_to_cpu(u->attributes.pinned_wb_buffer_curr_alloc_units= ); + case UFS_QUERY_ATTR_IDN_PINNED_WB_BUFF_AVAIL_PERCENT: + return u->attributes.pinned_wb_buffer_avail_percent; + case UFS_QUERY_ATTR_IDN_PINNED_WB_CUMM_WRITTEN_SIZE: + return be32_to_cpu(u->attributes.pinned_wb_cumm_written_size); + case UFS_QUERY_ATTR_IDN_PINNED_WB_NUM_ALLOC_UNITS: + return be32_to_cpu(u->attributes.pinned_wb_num_alloc_units); + case UFS_QUERY_ATTR_IDN_NON_PINNED_WB_MIN_NUM_ALLOC_UNITS: + return be32_to_cpu(u->attributes.non_pinned_wb_min_num_alloc_units= ); } return 0; } @@ -1237,6 +1297,9 @@ static QueryRespCode ufs_write_attr_value(UfsHc *u, u= int8_t idn, uint32_t value) case UFS_QUERY_ATTR_IDN_PSA_DATA_SIZE: u->attributes.psa_data_size =3D cpu_to_be32(value); break; + case UFS_QUERY_ATTR_IDN_TIMESTAMP: + u->attributes.timestamp =3D cpu_to_be64(value); + break; } return UFS_QUERY_RESULT_SUCCESS; } diff --git a/include/block/ufs.h b/include/block/ufs.h index 04cb24324d7c5585be9df596738183e1924403fb..4dacfb776f947a285d86018add8= 2115f148b7dd9 100644 --- a/include/block/ufs.h +++ b/include/block/ufs.h @@ -294,7 +294,8 @@ typedef struct QEMU_PACKED DeviceDescriptor { uint32_t psa_max_data_size; uint8_t psa_state_timeout; uint8_t product_revision_level; - uint8_t reserved[36]; + uint8_t reserved[34]; + uint16_t extended_wb_support; uint32_t extended_ufs_features_support; uint8_t write_booster_buffer_preserve_user_space_en; uint8_t write_booster_buffer_type; @@ -342,6 +343,8 @@ typedef struct QEMU_PACKED GeometryDescriptor { uint8_t write_booster_buffer_cap_adj_fac; uint8_t supported_write_booster_buffer_user_space_reduction_types; uint8_t supported_write_booster_buffer_types; + uint8_t reserved3[17]; + uint8_t cap_adj_fac_representation; } GeometryDescriptor; =20 #define UFS_GEOMETRY_CAPACITY_SHIFT 9 @@ -437,6 +440,8 @@ typedef struct QEMU_PACKED Flags { uint8_t wb_buffer_flush_en; uint8_t wb_buffer_flush_during_hibernate; uint8_t reserved4[2]; + uint8_t unpin_en; + uint8_t reserved5[235]; } Flags; =20 typedef struct Attributes { @@ -457,6 +462,8 @@ typedef struct Attributes { uint16_t exception_event_status; uint32_t seconds_passed; uint16_t context_conf; + uint8_t obsolete; + uint8_t reserved2[2]; uint8_t device_ffu_status; uint8_t psa_state; uint32_t psa_data_size; @@ -469,10 +476,34 @@ typedef struct Attributes { uint8_t available_wb_buffer_size; uint8_t wb_buffer_life_time_est; uint32_t current_wb_buffer_size; + uint8_t reserved3[10]; + uint8_t ext_iid_en; + uint16_t host_hint_cache_size; uint8_t refresh_status; uint8_t refresh_freq; uint8_t refresh_unit; uint8_t refresh_method; + uint64_t timestamp; + uint8_t reserved4[3]; + uint64_t device_level_exception_id; + uint8_t defrag_op; + uint32_t hid_avail_size; + uint32_t hid_size; + uint8_t hid_prog_ratio; + uint8_t hid_state; + uint8_t reserved5[2]; + uint8_t wb_buffer_resize_hint; + uint8_t wb_buffer_resize_en; + uint8_t wb_buffer_resize_status; + uint8_t wb_buffer_partial_flush_mode; + uint32_t max_fifo_wb_partial_flush_mode; + uint32_t curr_fifo_wb_partial_flush_mode; + uint32_t pinned_wb_buffer_curr_alloc_units; + uint8_t pinned_wb_buffer_avail_percent; + uint32_t pinned_wb_cumm_written_size; + uint32_t pinned_wb_num_alloc_units; + uint32_t non_pinned_wb_min_num_alloc_units; + uint8_t reserved6[184]; } Attributes; =20 #define UFS_TRANSACTION_SPECIFIC_FIELD_SIZE 20 @@ -856,6 +887,7 @@ enum flag_idn { UFS_QUERY_FLAG_IDN_WB_BUFF_FLUSH_DURING_HIBERN8 =3D 0x10, UFS_QUERY_FLAG_IDN_HPB_RESET =3D 0x11, UFS_QUERY_FLAG_IDN_HPB_EN =3D 0x12, + UFS_QUERY_FLAG_IDN_UNPIN_EN =3D 0x13, UFS_QUERY_FLAG_IDN_COUNT, }; =20 @@ -893,9 +925,29 @@ enum attr_idn { UFS_QUERY_ATTR_IDN_AVAIL_WB_BUFF_SIZE =3D 0x1D, UFS_QUERY_ATTR_IDN_WB_BUFF_LIFE_TIME_EST =3D 0x1E, UFS_QUERY_ATTR_IDN_CURR_WB_BUFF_SIZE =3D 0x1F, + UFS_QUERY_ATTR_IDN_EXT_IID_EN =3D 0x2A, + UFS_QUERY_ATTR_IDN_HOST_HINT_CACHE_SIZE =3D 0x2B, UFS_QUERY_ATTR_IDN_REFRESH_STATUS =3D 0x2C, UFS_QUERY_ATTR_IDN_REFRESH_FREQ =3D 0x2D, UFS_QUERY_ATTR_IDN_REFRESH_UNIT =3D 0x2E, + UFS_QUERY_ATTR_IDN_TIMESTAMP =3D 0x30, + UFS_QUERY_ATTR_IDN_DEVICE_LEVEL_EXCEPTION_ID =3D 0x34, + UFS_QUERY_ATTR_IDN_DEFRAG_OP =3D 0x35, + UFS_QUERY_ATTR_IDN_HID_AVAIL_SIZE =3D 0x36, + UFS_QUERY_ATTR_IDN_HID_SIZE =3D 0x37, + UFS_QUERY_ATTR_IDN_HID_PROG_RATIO =3D 0x38, + UFS_QUERY_ATTR_IDN_HID_STATE =3D 0x39, + UFS_QUERY_ATTR_IDN_WB_BUFF_RESIZE_HINT =3D 0x3C, + UFS_QUERY_ATTR_IDN_WB_BUFF_RESIZE_EN =3D 0x3D, + UFS_QUERY_ATTR_IDN_WB_BUFF_RESIZE_STATUS =3D 0x3E, + UFS_QUERY_ATTR_IDN_WB_BUFF_PARTIAL_FLUSH_MODE =3D 0x3F, + UFS_QUERY_ATTR_IDN_MAX_FIFO_WB_PARTIAL_FLUSH_MODE =3D 0x40, + UFS_QUERY_ATTR_IDN_CURR_FIFO_WB_PARTIAL_FLUSH_MODE =3D 0x41, + UFS_QUERY_ATTR_IDN_PINNED_WB_BUFF_CURR_ALLOC_UNITS =3D 0x42, + UFS_QUERY_ATTR_IDN_PINNED_WB_BUFF_AVAIL_PERCENT =3D 0x43, + UFS_QUERY_ATTR_IDN_PINNED_WB_CUMM_WRITTEN_SIZE =3D 0x44, + UFS_QUERY_ATTR_IDN_PINNED_WB_NUM_ALLOC_UNITS =3D 0x45, + UFS_QUERY_ATTR_IDN_NON_PINNED_WB_MIN_NUM_ALLOC_UNITS =3D 0x46, UFS_QUERY_ATTR_IDN_COUNT, }; =20 @@ -1005,6 +1057,7 @@ enum device_desc_param { UFS_DEVICE_DESC_PARAM_PRDCT_REV =3D 0x2A, UFS_DEVICE_DESC_PARAM_HPB_VER =3D 0x40, UFS_DEVICE_DESC_PARAM_HPB_CONTROL =3D 0x42, + UFS_DEVICE_DESC_PARAM_EXT_WB_SUP =3D 0x4D, UFS_DEVICE_DESC_PARAM_EXT_UFS_FEATURE_SUP =3D 0x4F, UFS_DEVICE_DESC_PARAM_WB_PRESRV_USRSPC_EN =3D 0x53, UFS_DEVICE_DESC_PARAM_WB_TYPE =3D 0x54, @@ -1208,14 +1261,14 @@ static inline void _ufs_check_size(void) QEMU_BUILD_BUG_ON(sizeof(UfsMcqCqIntReg) !=3D 12); QEMU_BUILD_BUG_ON(sizeof(UfsMcqOpReg) !=3D 48); QEMU_BUILD_BUG_ON(sizeof(DeviceDescriptor) !=3D 89); - QEMU_BUILD_BUG_ON(sizeof(GeometryDescriptor) !=3D 87); + QEMU_BUILD_BUG_ON(sizeof(GeometryDescriptor) !=3D 105); QEMU_BUILD_BUG_ON(sizeof(UnitDescriptor) !=3D 45); QEMU_BUILD_BUG_ON(sizeof(RpmbUnitDescriptor) !=3D 35); QEMU_BUILD_BUG_ON(sizeof(PowerParametersDescriptor) !=3D 98); QEMU_BUILD_BUG_ON(sizeof(InterconnectDescriptor) !=3D 6); QEMU_BUILD_BUG_ON(sizeof(StringDescriptor) !=3D 254); QEMU_BUILD_BUG_ON(sizeof(DeviceHealthDescriptor) !=3D 45); - QEMU_BUILD_BUG_ON(sizeof(Flags) !=3D 0x13); + QEMU_BUILD_BUG_ON(sizeof(Flags) !=3D 0xFF); QEMU_BUILD_BUG_ON(sizeof(UtpUpiuHeader) !=3D 12); QEMU_BUILD_BUG_ON(sizeof(UtpUpiuQuery) !=3D 276); QEMU_BUILD_BUG_ON(sizeof(UtpUpiuCmd) !=3D 20); --=20 2.48.1 From nobody Sat Apr 11 18:38:38 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=1775590561; cv=none; d=zohomail.com; s=zohoarc; b=BY7SMiA9AOCCrBEZbA9Arq+Y5lDLYnuwVgzG8yjFOVmU4iKyGwv2fwThiivdi+JEtOp9TvUqpxuqo4bgSROm3/xazBNhess8wX5STktXzklaJH6z6TJdVYuVEw1HiirwmWYiz/tZdMg6V5unLZcgVW29DBUUvs2wQWhrvOaD5rA= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1775590561; 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=YmuL7p7Cj6EPfT6TskJfKoJzfg2lliP47OlCm6gFGtQYyDx/D3Ox3Rb7klPQdG7luqwhM4wnVzk7nksUeOziCIjooDOGWxPLFvxL1HgUZ2pR6OULfHNv0gtMbi7X6ubc+iv93HyGKUNBSLGNGVNznuyPS8MaOBK+a4hnjYcyqs8= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1775590561349885.1465053799205; Tue, 7 Apr 2026 12:36:01 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wABWE-00082K-0w; Tue, 07 Apr 2026 14:51:22 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wABTn-0003Pl-CK for qemu-devel@nongnu.org; Tue, 07 Apr 2026 14:48:51 -0400 Received: from mail-pf1-x436.google.com ([2607:f8b0:4864:20::436]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1wA3fz-0003Lr-KL for qemu-devel@nongnu.org; Tue, 07 Apr 2026 06:28:57 -0400 Received: by mail-pf1-x436.google.com with SMTP id d2e1a72fcca58-82ce09b61beso2120261b3a.0 for ; Tue, 07 Apr 2026 03:28:55 -0700 (PDT) Received: from [172.17.0.5] ([168.126.243.22]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-82cf9b2714dsm21217324b3a.1.2026.04.07.03.28.52 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 07 Apr 2026 03:28:53 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1775557734; x=1776162534; 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=fzH68N+DMFMRm88w6Lno1gRVeJlR+xsmiB4L/E7bAt+QWxJoaRgP01sKjf75W2CNYs lYt3v467r2UmjN/e8gYUSzcDyfI4xbcUO6nXnqVedlMON/JopuixTYh1Sr2RCf/e/TSt GA3Z7znpPmxI62eejSjEAZ1mTJw0H76fC9bF/a0VyR0NOMZSRDPnTVSGUBPuG1B1eDba lBskSFqunuB21Q25XgMcdQK7WLcOYnnqPFOMce/aSwr5EnuqAwQ/Bmlm0OLSqHTKtaul NthWDhj86dSPVc0LjcqVVRy6HfyamOvB3WzvfeiEB2ttpsLPAYsMevHcweJo8S7h6avU /KEQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1775557734; x=1776162534; 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=er2HV2TF0SuHDCyQkJ99SkevjM2iaP1KiBAJFXgXyXiyJRtdOZWsgEGFIpMJ6/pEwJ 44v+t43QzwPtkdvtYaxqj2Ocp+AtDk0yrfO4yrGQ1CfcdQD2N7rxn1Y7EnEGLB6ooWGI KNdBo2jXHfHlUj8m5livNG7CEH6VQVxaEOEnkptYnYm2ulhteB/r37y2//XfkASTlL1v v3mr/cyVEMYFJzG6Oj7btBCHSzXLXzhZOd3Mtnl6tiK9wFWlEugwBt3C5K3ZZVwILvOU IYarGeInm2tAzZgUB9PQuicNRpgk6yUY8Ffk4lIzsTJ08m0rcKth0wOJsUXnGiVfhXkf 4tNQ== X-Gm-Message-State: AOJu0Yz6mO4F+MoK3/4wu87PHOlUe3e/1B0dHSF7cy9dpF9uvrkwkps3 rUzAi13CjEAJzRmUYeGa2RtdTg6rf7nJWx+7rbE60S1tCFQQDVBTdlOD5AK8VqXx52Zncg== X-Gm-Gg: AeBDieuHZlByAYt73Wo46nAFhbBkmVXTYfKhmNoFcd6uGyy7PN4+P/dStRGMGWs2agK AhNhC5oyRVWqDt3WIaYdzWua3dbMGxwpBQiT47iLoef9GDZ9QMYsH2HtHVrr4VJaHh5RRzOZwEP cqNhf3TVThzC+ZWSUBtPlcsglEMsyndM8z6VQEOhD9f4/MB6iPg9Hzhd8JRwQBA4ujkOFV7qxHV 51VpUQBC35uTEDduZFidTdpUhmTrUlCcUULHV1Jnq7ZyXsrDaRXYOlhntDtZY8es8a8upyo0ZpZ 0AVRShYxbuhfywR/yoQ7gqyN3Bq9cA/D+wQl6lpMBycqdy3xksS919mnP4WHGwEtbVy02Xf3NeJ 5XmXAjfzPazklYHccY/ObDDLPl9CoEwFZCGvQR/Sxk8dsAboP4oQvuoODPPL/fhUM/tDZa1pDyJ 8wZwwjsmbHYkm88p+L7ed3pGUsTQqvaKMRW2Onih8K X-Received: by 2002:a05:6a00:414b:b0:823:1d05:1660 with SMTP id d2e1a72fcca58-82d0dbd3061mr16177101b3a.52.1775557734043; Tue, 07 Apr 2026 03:28:54 -0700 (PDT) From: Jaemyung Lee X-Google-Original-From: Jaemyung Lee Date: Tue, 07 Apr 2026 19:23:40 +0900 Subject: [PATCH v2 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: <20260407-write_booster-v2-2-dd772bb30194@samsung.com> References: <20260407-write_booster-v2-0-dd772bb30194@samsung.com> In-Reply-To: <20260407-write_booster-v2-0-dd772bb30194@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=1775557727; l=6656; i=jaemyung.lee@samsung.com; s=20260402; h=from:subject:message-id; bh=UwQldvutZu9HqLXksjdiAk3IKzXkRCngBaBlZ026a4E=; b=TCgoBU8s0BrRLtHhIgj2FI6qmMKO1/XHbaQXMC/yFQPj6tGc8e9D66B5Qj44r9A044EHf+CKP GXod/XFeMljAeDpN0imU9BqQz/sQcKeyhV0WNW+/BUhysw769Y2Ua7U 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::436; envelope-from=ldc.jml@gmail.com; helo=mail-pf1-x436.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: 1775590561847154101 Change internal flag handling operation same as attribute's In UFS device, some flag queries directly trigger specific device behaviour like attribute's, not only changes the internal values. So restructure flag query processing functions same as attribute processing, to facilitate linking detailed implementations based on individual flag value changes. Signed-off-by: Jaemyung Lee --- hw/ufs/ufs.c | 152 ++++++++++++++++++++++++++++++++++++++++++++++---------= ---- 1 file changed, 119 insertions(+), 33 deletions(-) diff --git a/hw/ufs/ufs.c b/hw/ufs/ufs.c index b2b70c8b38ebecd8d49ecce288614d55efd90f2e..69f82ab462d135fe6cda479891f= 9d8f26d19be9a 100644 --- a/hw/ufs/ufs.c +++ b/hw/ufs/ufs.c @@ -1021,6 +1021,122 @@ static inline QueryRespCode ufs_flag_check_idn_vali= d(uint8_t idn, int op) return UFS_QUERY_RESULT_SUCCESS; } =20 +static uint32_t ufs_read_flag_value(UfsHc *u, uint8_t idn) +{ + switch (idn) { + case UFS_QUERY_FLAG_IDN_FDEVICEINIT: + return u->flags.device_init; + case UFS_QUERY_FLAG_IDN_PERMANENT_WPE: + return u->flags.permanent_wp_en; + case UFS_QUERY_FLAG_IDN_PWR_ON_WPE: + return u->flags.power_on_wp_en; + case UFS_QUERY_FLAG_IDN_BKOPS_EN: + return u->flags.background_ops_en; + case UFS_QUERY_FLAG_IDN_LIFE_SPAN_MODE_ENABLE: + return u->flags.device_life_span_mode_en; + case UFS_QUERY_FLAG_IDN_PURGE_ENABLE: + return u->flags.purge_enable; + case UFS_QUERY_FLAG_IDN_REFRESH_ENABLE: + return u->flags.refresh_enable; + case UFS_QUERY_FLAG_IDN_FPHYRESOURCEREMOVAL: + return u->flags.phy_resource_removal; + case UFS_QUERY_FLAG_IDN_BUSY_RTC: + return u->flags.busy_rtc; + case UFS_QUERY_FLAG_IDN_PERMANENTLY_DISABLE_FW_UPDATE: + return u->flags.permanently_disable_fw_update; + case UFS_QUERY_FLAG_IDN_WB_EN: + return u->flags.wb_en; + case UFS_QUERY_FLAG_IDN_WB_BUFF_FLUSH_EN: + return u->flags.wb_buffer_flush_en; + case UFS_QUERY_FLAG_IDN_WB_BUFF_FLUSH_DURING_HIBERN8: + return u->flags.wb_buffer_flush_during_hibernate; + case UFS_QUERY_FLAG_IDN_UNPIN_EN: + return u->flags.unpin_en; + default: + g_assert_not_reached(); + return 0; + } +} + +static QueryRespCode ufs_write_flag_value(UfsHc *u, uint8_t idn, uint8_t v= alue) +{ + switch (idn) { + case UFS_QUERY_FLAG_IDN_FDEVICEINIT: + u->flags.device_init =3D 0; + break; + case UFS_QUERY_FLAG_IDN_PERMANENT_WPE: + u->flags.permanent_wp_en =3D value; + break; + case UFS_QUERY_FLAG_IDN_PWR_ON_WPE: + u->flags.power_on_wp_en =3D value; + break; + case UFS_QUERY_FLAG_IDN_BKOPS_EN: + u->flags.background_ops_en =3D value; + break; + case UFS_QUERY_FLAG_IDN_LIFE_SPAN_MODE_ENABLE: + u->flags.device_life_span_mode_en =3D value; + break; + case UFS_QUERY_FLAG_IDN_PURGE_ENABLE: + u->flags.purge_enable =3D value; + break; + case UFS_QUERY_FLAG_IDN_REFRESH_ENABLE: + u->flags.refresh_enable =3D value; + break; + case UFS_QUERY_FLAG_IDN_FPHYRESOURCEREMOVAL: + u->flags.phy_resource_removal =3D value; + break; + case UFS_QUERY_FLAG_IDN_PERMANENTLY_DISABLE_FW_UPDATE: + u->flags.permanently_disable_fw_update =3D value; + break; + case UFS_QUERY_FLAG_IDN_WB_EN: + u->flags.wb_en =3D value; + break; + case UFS_QUERY_FLAG_IDN_WB_BUFF_FLUSH_EN: + u->flags.wb_buffer_flush_en =3D value; + break; + case UFS_QUERY_FLAG_IDN_WB_BUFF_FLUSH_DURING_HIBERN8: + u->flags.wb_buffer_flush_during_hibernate =3D value; + break; + default: + return UFS_QUERY_RESULT_INVALID_VALUE; + } + + return UFS_QUERY_RESULT_SUCCESS; +} + +static QueryRespCode ufs_exec_query_flag(UfsRequest *req, int op) +{ + UfsHc *u =3D req->hc; + uint8_t idn =3D req->req_upiu.qr.idn; + uint8_t value; + QueryRespCode ret; + + ret =3D ufs_flag_check_idn_valid(idn, op); + if (ret) { + return ret; + } + + if (op =3D=3D UFS_QUERY_FLAG_READ) { + value =3D ufs_read_flag_value(u, idn); + ret =3D UFS_QUERY_RESULT_SUCCESS; + } else if (op =3D=3D UFS_QUERY_FLAG_SET) { + value =3D 1; + ret =3D ufs_write_flag_value(u, idn, value); + } else if (op =3D=3D UFS_QUERY_FLAG_CLEAR) { + value =3D 0; + ret =3D ufs_write_flag_value(u, idn, value); + } else if (op =3D=3D UFS_QUERY_FLAG_TOGGLE) { + value =3D !(ufs_read_flag_value(u, idn)); + ret =3D ufs_write_flag_value(u, idn, value); + } else { + trace_ufs_err_query_invalid_opcode(op); + return UFS_QUERY_RESULT_INVALID_OPCODE; + } + + req->rsp_upiu.qr.value =3D cpu_to_be32(value); + return ret; +} + static const int attr_permission[UFS_QUERY_ATTR_IDN_COUNT] =3D { /* booting is not supported */ [UFS_QUERY_ATTR_IDN_BOOT_LU_EN] =3D UFS_QUERY_ATTR_READ, @@ -1103,39 +1219,6 @@ static inline QueryRespCode ufs_attr_check_idn_valid= (uint8_t idn, int op) return UFS_QUERY_RESULT_SUCCESS; } =20 -static QueryRespCode ufs_exec_query_flag(UfsRequest *req, int op) -{ - UfsHc *u =3D req->hc; - uint8_t idn =3D req->req_upiu.qr.idn; - uint32_t value; - QueryRespCode ret; - - ret =3D ufs_flag_check_idn_valid(idn, op); - if (ret) { - return ret; - } - - if (idn =3D=3D UFS_QUERY_FLAG_IDN_FDEVICEINIT) { - value =3D 0; - } else if (op =3D=3D UFS_QUERY_FLAG_READ) { - value =3D *(((uint8_t *)&u->flags) + idn); - } else if (op =3D=3D UFS_QUERY_FLAG_SET) { - value =3D 1; - } else if (op =3D=3D UFS_QUERY_FLAG_CLEAR) { - value =3D 0; - } else if (op =3D=3D UFS_QUERY_FLAG_TOGGLE) { - value =3D *(((uint8_t *)&u->flags) + idn); - value =3D !value; - } else { - trace_ufs_err_query_invalid_opcode(op); - return UFS_QUERY_RESULT_INVALID_OPCODE; - } - - *(((uint8_t *)&u->flags) + idn) =3D value; - req->rsp_upiu.qr.value =3D cpu_to_be32(value); - return UFS_QUERY_RESULT_SUCCESS; -} - static inline uint8_t ufs_read_device_temp(UfsHc *u) { uint8_t feat_sup =3D u->device_desc.ufs_features_support; @@ -1300,6 +1383,9 @@ static QueryRespCode ufs_write_attr_value(UfsHc *u, u= int8_t idn, uint32_t value) case UFS_QUERY_ATTR_IDN_TIMESTAMP: u->attributes.timestamp =3D cpu_to_be64(value); break; + default: + g_assert_not_reached(); + return 0; } return UFS_QUERY_RESULT_SUCCESS; } --=20 2.48.1 From nobody Sat Apr 11 18:38:38 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=1775590415; cv=none; d=zohomail.com; s=zohoarc; b=Ub8zuRNPBTlKWQWuHFd8Whf7V0uEN5w6zpqoIPQ7z3D6Yqk1MdSjw15E8BqIDsJUH+/Cuzlsxq3H2ffCynIwktrUmtAsUqn8ue6CDQWESv8sdC2tOww1ZFJjeKpLIhS5J0QEb/LrjJIBoEEppaYclPbhu3lpo60FmVOd9RoHXfs= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1775590415; 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=LcrKp+d0GU/h7BA8cuQ7nXTTc4Guv25nnJ2LbdVZlfw=; b=EED+v5sh5kgbOw02q6QrObtpMJGLpN87duYaBEsRubhLSuTtSnSMR7MKOZVeBjn8hptS2qcaMWkbALVSWTXCgz5HA9tGybsrnfdJqXd/ECaZPePi4jewOfab1t/t3RIVcaCROH8310k+7GkTRTRePNaY0jyUpswyCyegWpf/4fY= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1775590415423463.66757271440133; Tue, 7 Apr 2026 12:33:35 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wABWC-0007zS-Pg; Tue, 07 Apr 2026 14:51:20 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wABTn-0003wR-5p for qemu-devel@nongnu.org; Tue, 07 Apr 2026 14:48:51 -0400 Received: from mail-pf1-x42c.google.com ([2607:f8b0:4864:20::42c]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1wA3g1-0003MI-RU for qemu-devel@nongnu.org; Tue, 07 Apr 2026 06:29:02 -0400 Received: by mail-pf1-x42c.google.com with SMTP id d2e1a72fcca58-82cf96ca071so2121702b3a.1 for ; Tue, 07 Apr 2026 03:28:57 -0700 (PDT) Received: from [172.17.0.5] ([168.126.243.22]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-82cf9b2714dsm21217324b3a.1.2026.04.07.03.28.54 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 07 Apr 2026 03:28:55 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1775557736; x=1776162536; 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=LcrKp+d0GU/h7BA8cuQ7nXTTc4Guv25nnJ2LbdVZlfw=; b=hDalta1baMRrRIhAzO0WoNCPkF1qLguLNemkCbSH0jSIiLiC5UTBCYdkiu4qu99KiV mTa8N/SFBkMLvkK+p399q/N5JaOHZYFw/0QcYLdba+SPOGrvAS9I4nEpT8cDp12XUGAb k0tWYBSe8u6PCjP7as+D0HTpadJab0A4u6m5WrKyki0sOvflgQNg+B6JyRo8b/ULA50y boXP386WyIYw59JTUgPQz3/vLq5p13Moh/OhjMbrX2yQvTEaENIlyeIgg70xpOPxUZcn cRDzKSy6cZU9i4EzOv7tRGXJ0fkdUFgeuaV+Wdwhfuq2EPzeOPRAxIYRZEnTBbA6/OCK 7MHA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1775557736; x=1776162536; 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=LcrKp+d0GU/h7BA8cuQ7nXTTc4Guv25nnJ2LbdVZlfw=; b=p/TDunIq4YvVecTtKcHrL9Rl7EY4ZeCoxxnvKlVGoG4G0G5ENo4kpqqze1HYYDmBwi eUAh2eGP14KvxJwdLt2Mm5m/N+wY4ABfaDDV/clBCSe2afKKPnnsFb3kusrkOBRqU2SP RiilXQhQXlDG6w9j6gRed1KIvB1S7YOtxy3X+aAOD/vfZJgqsXKqjfG43pRTXyoT9nf6 wBeJQA2KFxcAkrQkL5kF/x3B0WS1j+giDJCtEiaS641KP70pxYdCam+m9QH50wbpuusF hk0qJo0pxSPobWYlibnf+asl6fI/hzfKW2gd+nm60gxsylO+jYKigIVYRvZMKt/RRxz7 UlcA== X-Gm-Message-State: AOJu0YyN0wjlfAV2rVjb1XvVejyTXYw2DfuSeutY4xXELoDGTjLDDfTR FU5TvhvtwZ5BpoJACNzUOfeknSaJuszlQMnOhuYzmSR0vpPVlfL27jB05/6TDwguV7cBMg== X-Gm-Gg: AeBDietO7+8tZ1tj0sqcJJAS4Io+0bw6rl6wqL8F1etQ2foW3P+j+891Zk+gQakG63F JBh7UYWs8oK00uJNeqYAgWiLSy/09eMnZ+8XZaQ/mEAGAeTmNJ3PhTIoyPYfZUFFS4gKdVSvhl7 Bq4PWntkh9kpCssH9Epe+PwElmqcxHg4Cexws8OF8tu0AUwfEFHh5uGnyxutAPivoqphKLlUnTk ENiHm6x+iJyfeIk5yLXvyv31qcZ4auJpv5ddrmo0eZplw9rv5bR/I81o1+N1AbEyrbJ8sdsEg9o 2Ct4S2QV4vRrIQxMgIvfH+goaESrY2pStn8bGssaQaCxzCphiydvmhjwoY5D7NmmsYMT3hk5g62 4sTA1SUSvKOps90AcDxCRk/0yjXMYFFsUyssYisUBTS6pM8TQbs5bc32i3ydezCBy9o9UG3ZtxF I504W8twUjOhh1TQiNbDM6DK7P3D0bmA== X-Received: by 2002:a05:6a00:3d4f:b0:82c:dc9c:e765 with SMTP id d2e1a72fcca58-82d0d749427mr16861865b3a.0.1775557736135; Tue, 07 Apr 2026 03:28:56 -0700 (PDT) From: Jaemyung Lee X-Google-Original-From: Jaemyung Lee Date: Tue, 07 Apr 2026 19:23:41 +0900 Subject: [PATCH v2 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: <20260407-write_booster-v2-3-dd772bb30194@samsung.com> References: <20260407-write_booster-v2-0-dd772bb30194@samsung.com> In-Reply-To: <20260407-write_booster-v2-0-dd772bb30194@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=1775557727; l=3259; i=jaemyung.lee@samsung.com; s=20260402; h=from:subject:message-id; bh=AwIyJDKLRw8lIAaybVo1E6Wec09c09QCMmjVB0P1SBU=; b=iJiCV/zuC0kD1q6dSLyp5oIElM1yrqO+9DgbTCP0Qmxzqcq6acM49YTtNiPFYJE7qYCw61dMk EoejGh0XjfeDVEwGJYZ3t9fu8jEhfnv7RPgIhghRG0HGK1JOZBSnlat 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::42c; envelope-from=ldc.jml@gmail.com; helo=mail-pf1-x42c.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: 1775590416143158500 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 | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++= +++ hw/ufs/ufs.h | 2 ++ 2 files changed, 61 insertions(+) diff --git a/hw/ufs/ufs.c b/hw/ufs/ufs.c index 69f82ab462d135fe6cda479891f9d8f26d19be9a..5102d9bbab640faded69c93be73= cbe319db68646 100644 --- a/hw/ufs/ufs.c +++ b/hw/ufs/ufs.c @@ -1801,6 +1801,59 @@ 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 (!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 (!ufs_mcq_cq_empty(u, qid)) { + 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 +1916,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 +2013,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 +2043,8 @@ static void ufs_exit(PCIDevice *pci_dev) { UfsHc *u =3D UFS(pci_dev); =20 + timer_del(&u->idle_timer); + qemu_free_irq(u->irq); =20 qemu_bh_delete(u->doorbell_bh); diff --git a/hw/ufs/ufs.h b/hw/ufs/ufs.h index 13d964c5ae5ec430a98b2ef71987cb9279e9a317..b5f040302129f4d02732ddd20ef= 82eb33c41922a 100644 --- a/hw/ufs/ufs.h +++ b/hw/ufs/ufs.h @@ -148,6 +148,8 @@ typedef struct UfsHc { UfsCq *cq[UFS_MAX_MCQ_QNUM]; =20 uint8_t temperature; + + QEMUTimer idle_timer; } UfsHc; =20 static inline uint32_t ufs_mcq_sq_tail(UfsHc *u, uint32_t qid) --=20 2.48.1 From nobody Sat Apr 11 18:38:38 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=1775589676; cv=none; d=zohomail.com; s=zohoarc; b=SM5rkqQzJJOW25HrM5P9oC3GobXVUJly1qkUN1Dqof7/eaHANVfZgbbSSSxgh+6fpoKAacR+VOGDD0IeRKZUZGsunkTs5jNftpUVvvbD8zgSSW6nj77CTxNTFGa6YFLz5/gMtgRQwObzVUGuVxBUZrZg+ul76C+gkJUoonazPts= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1775589676; 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=1LF+OEOyk4QHLrmOZ4ySHJ1oxjvYbO7qeGvc/JtrerQ=; b=C4KnPxXYXifYRTurQkjgzenIROLxw3ZIyceSZm1WHWdlRzGhVzQAZ/GUB/Y5I1Kya4u3dSaqsXYEbSXtOO46fIfR0gXfS2KSHdKkC26kAKC66BK8QU3O7XIW7w1dJPJih6ywYx1QUYJabsHxVmf8dD6TkWqRWD5aXxQAb0W3+Co= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1775589676812722.0160601028936; Tue, 7 Apr 2026 12:21:16 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wABWG-000851-2F; Tue, 07 Apr 2026 14:51:24 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wABTm-0004Gt-NF for qemu-devel@nongnu.org; Tue, 07 Apr 2026 14:48:50 -0400 Received: from mail-pf1-x42f.google.com ([2607:f8b0:4864:20::42f]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1wA3g4-0003Mr-3V for qemu-devel@nongnu.org; Tue, 07 Apr 2026 06:29:02 -0400 Received: by mail-pf1-x42f.google.com with SMTP id d2e1a72fcca58-824c9da9928so3860299b3a.3 for ; Tue, 07 Apr 2026 03:28:59 -0700 (PDT) Received: from [172.17.0.5] ([168.126.243.22]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-82cf9b2714dsm21217324b3a.1.2026.04.07.03.28.56 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 07 Apr 2026 03:28:57 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1775557738; x=1776162538; 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=1LF+OEOyk4QHLrmOZ4ySHJ1oxjvYbO7qeGvc/JtrerQ=; b=ouFbhqxQ7EEQfzyxMSxL9eU573ESDcKpsYA9Uso+NsUQ3F+0cX5sK8mhS20OESODD5 /E/LxVehAaDszfypVf4UGzo74Rdni87SCQJXaZE2dWws0XiWOTthUCIh7MzQnYrRSyJa a0FQ8AD3hFG1AhWrz84+PGbxG65vs1pFM4GcclhDFf4dqeAE15fIVvpx+4CDr6YkGS02 HlFHNm3fDeEjCvGPyylc6n57kgViSU0k/JE/F3lrPGz3oyQ5ZKZVULsNd+KR/lB3+Iwt aToGl2O3WxioxayjKKLhOZvc13xLql0azXC715wDgsjQ4H5hBiRnHit1FjSQfmMFXEga siwg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1775557738; x=1776162538; 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=1LF+OEOyk4QHLrmOZ4ySHJ1oxjvYbO7qeGvc/JtrerQ=; b=XRcIKrDIRnugQiw/mODZvZcZYzz4WVju5t0LWfSxW/ewO6zuRSrzyNQ5my49+NneX6 0y1atoSkhxiSBM1fm6TEhO0oHaG9/W0YWSnyg8cQBptQ5eZbQwgvclxoC4aTFRNGvfvF CurNYGtAXLNpniFzHUbThDFsGobNxZdrEO5hbPCWBcRgQ37pnvfqx5HB/oWH44XI9CNm fIhcScuAFUDp9gq2x/jjax6gFEVnxMrwrE3QQkKiZx6EXXwvqIjqzHIJxSF/WVdYUSyt 01AOs3mJSqbHjCBmAUtEZAkZCCiCFBEHYamp27wXMXSp8AsPXvosyXEmhoWUnoaryVwz qoig== X-Gm-Message-State: AOJu0YzQNebbDnoxfsyKzIVrsytwJruXbsgxqsJhWLcchuxHfZHs7f1s IEvWjVbpZaAM65jALsP3XU6Tr1KcRZLGOv/P9fFNcMFlPEC0Vh2GWilvVqt7EugRfxmvdg== X-Gm-Gg: AeBDiet89KBwI80/dQeUWQhpwHTGUFMHFQWzcK3liRFLG3SGfGz/vCCF1ayO5rzeJEk k9dQxt7bfgFFZ09NoTAcdLZwNwfqMRWmeTMiU6IEU6heEvOc0x+xayTOcseKLXiPvPp18i1ykt5 87q3z1VoH67YxdRQ54Qn1ZSuPjpp3xlIT0Wx8bE9H9gqKzmdbpfxLAjH9aDpYEWK0OvsR0pRLS6 S5lfSOKCtZCMDPwmkp8sElH38urVMrroX46l3X7KXCghyP4Hj3iYNRVVEWiHtSy9VuJHuwGGIbF NxyyBRP/o/iYzDZgEaT/xs8s6+qUvNPI8qwQ/E48MwbHHDCFd45m5CZ+LHoZlW28sK+t0rM9LxT Xil+zoVSocPe/NiMauSD5MZ4GHsBeWPLCJjbuoSYZlGw9VJ4CRNC7tXfBAmWwQK4Zew2jaD2cYp 73LADueqy+5PhhRVkS+tAezRHAL6rCSQ== X-Received: by 2002:a05:6a00:3e05:b0:82a:60ad:874 with SMTP id d2e1a72fcca58-82d0da5972fmr15507726b3a.19.1775557738377; Tue, 07 Apr 2026 03:28:58 -0700 (PDT) From: Jaemyung Lee X-Google-Original-From: Jaemyung Lee Date: Tue, 07 Apr 2026 19:23:42 +0900 Subject: [PATCH v2 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: <20260407-write_booster-v2-4-dd772bb30194@samsung.com> References: <20260407-write_booster-v2-0-dd772bb30194@samsung.com> In-Reply-To: <20260407-write_booster-v2-0-dd772bb30194@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=1775557727; l=25754; i=jaemyung.lee@samsung.com; s=20260402; h=from:subject:message-id; bh=H08ksa3f84X0PoRwSgicOjf+OMZih42Lwk6V0+sVl2g=; b=0iHD4aPnhZSZz5z+lOuXTeHr6t4iPHLYcjMAN4QgAMBqKYe2xrVlttLS+W3eWmSCwQR3wM3u1 r/TbD7xTlxBCFZq2yOqaZaZuf3M9jzOzCdaHGbNTORuzZ850l1Zi5Ws 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::42f; envelope-from=ldc.jml@gmail.com; helo=mail-pf1-x42f.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: 1775589678195158500 Add UFS Write Booster implementation which follows UFS 4.1 Spec. Signed-off-by: Jaemyung Lee --- hw/ufs/ufs.c | 425 ++++++++++++++++++++++++++++++++++++++++++++++++= ++-- hw/ufs/ufs.h | 47 ++++++ include/block/ufs.h | 51 +++++++ 3 files changed, 508 insertions(+), 15 deletions(-) diff --git a/hw/ufs/ufs.c b/hw/ufs/ufs.c index 5102d9bbab640faded69c93be73cbe319db68646..cfaff454e8eec84c8d171b68867= 9a11e113fb495 100644 --- a/hw/ufs/ufs.c +++ b/hw/ufs/ufs.c @@ -996,11 +996,15 @@ static const int flag_permission[UFS_QUERY_FLAG_IDN_C= OUNT] =3D { [UFS_QUERY_FLAG_IDN_FPHYRESOURCEREMOVAL] =3D UFS_QUERY_FLAG_READ, [UFS_QUERY_FLAG_IDN_BUSY_RTC] =3D UFS_QUERY_FLAG_READ, [UFS_QUERY_FLAG_IDN_PERMANENTLY_DISABLE_FW_UPDATE] =3D UFS_QUERY_FLAG_= READ, - /* Write Booster is not supported */ - [UFS_QUERY_FLAG_IDN_WB_EN] =3D UFS_QUERY_FLAG_READ, - [UFS_QUERY_FLAG_IDN_WB_BUFF_FLUSH_EN] =3D UFS_QUERY_FLAG_READ, + [UFS_QUERY_FLAG_IDN_WB_EN] =3D UFS_QUERY_FLAG_READ | UFS_QUERY_FLAG_SE= T | + UFS_QUERY_FLAG_CLEAR | UFS_QUERY_FLAG_TOG= GLE, + [UFS_QUERY_FLAG_IDN_WB_BUFF_FLUSH_EN] =3D + UFS_QUERY_FLAG_READ | UFS_QUERY_FLAG_SET | UFS_QUERY_FLAG_CLEAR | + UFS_QUERY_FLAG_TOGGLE, [UFS_QUERY_FLAG_IDN_WB_BUFF_FLUSH_DURING_HIBERN8] =3D UFS_QUERY_FLAG_R= EAD, - [UFS_QUERY_FLAG_IDN_UNPIN_EN] =3D UFS_QUERY_FLAG_READ, + [UFS_QUERY_FLAG_IDN_UNPIN_EN] =3D UFS_QUERY_FLAG_READ | UFS_QUERY_FLAG= _SET | + UFS_QUERY_FLAG_CLEAR | + UFS_QUERY_FLAG_TOGGLE, }; =20 static inline QueryRespCode ufs_flag_check_idn_valid(uint8_t idn, int op) @@ -1097,6 +1101,9 @@ static QueryRespCode ufs_write_flag_value(UfsHc *u, u= int8_t idn, uint8_t value) case UFS_QUERY_FLAG_IDN_WB_BUFF_FLUSH_DURING_HIBERN8: u->flags.wb_buffer_flush_during_hibernate =3D value; break; + case UFS_QUERY_FLAG_IDN_UNPIN_EN: + u->flags.unpin_en =3D value; + break; default: return UFS_QUERY_RESULT_INVALID_VALUE; } @@ -1189,16 +1196,20 @@ static const int attr_permission[UFS_QUERY_ATTR_IDN= _COUNT] =3D { [UFS_QUERY_ATTR_IDN_HID_PROG_RATIO] =3D UFS_QUERY_ATTR_READ, [UFS_QUERY_ATTR_IDN_HID_STATE] =3D UFS_QUERY_ATTR_READ, [UFS_QUERY_ATTR_IDN_WB_BUFF_RESIZE_HINT] =3D UFS_QUERY_ATTR_READ, - [UFS_QUERY_ATTR_IDN_WB_BUFF_RESIZE_EN] =3D UFS_QUERY_ATTR_READ, + [UFS_QUERY_ATTR_IDN_WB_BUFF_RESIZE_EN] =3D UFS_QUERY_ATTR_WRITE, [UFS_QUERY_ATTR_IDN_WB_BUFF_RESIZE_STATUS] =3D UFS_QUERY_ATTR_READ, - [UFS_QUERY_ATTR_IDN_WB_BUFF_PARTIAL_FLUSH_MODE] =3D UFS_QUERY_ATTR_REA= D, - [UFS_QUERY_ATTR_IDN_MAX_FIFO_WB_PARTIAL_FLUSH_MODE] =3D UFS_QUERY_ATTR= _READ, + [UFS_QUERY_ATTR_IDN_WB_BUFF_PARTIAL_FLUSH_MODE] =3D + UFS_QUERY_ATTR_READ | UFS_QUERY_ATTR_WRITE, + [UFS_QUERY_ATTR_IDN_MAX_FIFO_WB_PARTIAL_FLUSH_MODE] =3D + UFS_QUERY_ATTR_READ | UFS_QUERY_ATTR_WRITE, [UFS_QUERY_ATTR_IDN_CURR_FIFO_WB_PARTIAL_FLUSH_MODE] =3D UFS_QUERY_ATT= R_READ, [UFS_QUERY_ATTR_IDN_PINNED_WB_BUFF_CURR_ALLOC_UNITS] =3D UFS_QUERY_ATT= R_READ, [UFS_QUERY_ATTR_IDN_PINNED_WB_BUFF_AVAIL_PERCENT] =3D UFS_QUERY_ATTR_R= EAD, [UFS_QUERY_ATTR_IDN_PINNED_WB_CUMM_WRITTEN_SIZE] =3D UFS_QUERY_ATTR_RE= AD, - [UFS_QUERY_ATTR_IDN_PINNED_WB_NUM_ALLOC_UNITS] =3D UFS_QUERY_ATTR_READ, - [UFS_QUERY_ATTR_IDN_NON_PINNED_WB_MIN_NUM_ALLOC_UNITS] =3D UFS_QUERY_A= TTR_READ, + [UFS_QUERY_ATTR_IDN_PINNED_WB_NUM_ALLOC_UNITS] =3D + UFS_QUERY_ATTR_READ | UFS_QUERY_ATTR_WRITE, + [UFS_QUERY_ATTR_IDN_NON_PINNED_WB_MIN_NUM_ALLOC_UNITS] =3D + UFS_QUERY_ATTR_READ | UFS_QUERY_ATTR_WRITE, }; =20 static inline QueryRespCode ufs_attr_check_idn_valid(uint8_t idn, int op) @@ -1238,6 +1249,27 @@ static inline uint8_t ufs_read_device_temp(UfsHc *u) return 0; } =20 +static inline uint32_t ufs_wb_read_flush_status(UfsHc *u) +{ + if (u->attributes.wb_buffer_flush_status =3D=3D UFS_WB_FLUSH_SUSPENDED= || + u->attributes.wb_buffer_flush_status =3D=3D UFS_WB_FLUSH_COMPLETED= || + u->attributes.wb_buffer_flush_status =3D=3D UFS_WB_FLUSH_FAILED) { + u->attributes.wb_buffer_flush_status =3D UFS_WB_FLUSH_IDLE; + } + + return u->attributes.wb_buffer_flush_status; +} + +static inline uint32_t ufs_wb_read_resize_status(UfsHc *u) +{ + if (u->attributes.wb_buffer_resize_status =3D=3D UFS_WB_RESIZE_COMPLET= ED || + u->attributes.wb_buffer_resize_status =3D=3D UFS_WB_RESIZE_FAILED)= { + u->attributes.wb_buffer_resize_status =3D UFS_WB_RESIZE_IDLE; + } + + return u->attributes.wb_buffer_resize_status; +} + static uint32_t ufs_read_attr_value(UfsHc *u, uint8_t idn) { switch (idn) { @@ -1292,7 +1324,7 @@ static uint32_t ufs_read_attr_value(UfsHc *u, uint8_t= idn) case UFS_QUERY_ATTR_IDN_THROTTLING_STATUS: return u->attributes.throttling_status; case UFS_QUERY_ATTR_IDN_WB_FLUSH_STATUS: - return u->attributes.wb_buffer_flush_status; + return ufs_wb_read_flush_status(u); case UFS_QUERY_ATTR_IDN_AVAIL_WB_BUFF_SIZE: return u->attributes.available_wb_buffer_size; case UFS_QUERY_ATTR_IDN_WB_BUFF_LIFE_TIME_EST: @@ -1323,10 +1355,8 @@ static uint32_t ufs_read_attr_value(UfsHc *u, uint8_= t idn) return u->attributes.hid_state; case UFS_QUERY_ATTR_IDN_WB_BUFF_RESIZE_HINT: return u->attributes.wb_buffer_resize_hint; - case UFS_QUERY_ATTR_IDN_WB_BUFF_RESIZE_EN: - return u->attributes.wb_buffer_resize_en; case UFS_QUERY_ATTR_IDN_WB_BUFF_RESIZE_STATUS: - return u->attributes.wb_buffer_resize_status; + return ufs_wb_read_resize_status(u); case UFS_QUERY_ATTR_IDN_WB_BUFF_PARTIAL_FLUSH_MODE: return u->attributes.wb_buffer_partial_flush_mode; case UFS_QUERY_ATTR_IDN_MAX_FIFO_WB_PARTIAL_FLUSH_MODE: @@ -1347,6 +1377,32 @@ static uint32_t ufs_read_attr_value(UfsHc *u, uint8_= t idn) return 0; } =20 +static void ufs_wb_resize_op(UfsHc *u, uint32_t value) +{ + if (u->attributes.wb_buffer_resize_status =3D=3D UFS_WB_RESIZE_IN_PROG= RESS) { + return; + } + + u->attributes.wb_buffer_resize_en =3D value; + u->attributes.wb_buffer_resize_status =3D UFS_WB_RESIZE_IN_PROGRESS; +} + +static void ufs_wb_pinned_max_size(UfsHc *u, uint32_t value) +{ + UfsWb *wb =3D &u->wb; + + u->attributes.pinned_wb_num_alloc_units =3D cpu_to_be32(value); + wb->pinned_max_bytes =3D ufs_unit_to_byte(u, value); +} + +static void ufs_wb_pinned_min_size(UfsHc *u, uint32_t value) +{ + UfsWb *wb =3D &u->wb; + + u->attributes.non_pinned_wb_min_num_alloc_units =3D cpu_to_be32(value); + wb->pinned_min_bytes =3D ufs_unit_to_byte(u, value); +} + static QueryRespCode ufs_write_attr_value(UfsHc *u, uint8_t idn, uint32_t = value) { switch (idn) { @@ -1383,6 +1439,27 @@ static QueryRespCode ufs_write_attr_value(UfsHc *u, = uint8_t idn, uint32_t value) case UFS_QUERY_ATTR_IDN_TIMESTAMP: u->attributes.timestamp =3D cpu_to_be64(value); break; + case UFS_QUERY_ATTR_IDN_WB_BUFF_RESIZE_EN: + if (value >=3D UFS_WB_RESIZE_OP_MAX) { + return UFS_QUERY_RESULT_INVALID_VALUE; + } + ufs_wb_resize_op(u, value); + break; + case UFS_QUERY_ATTR_IDN_WB_BUFF_PARTIAL_FLUSH_MODE: + if (value >=3D UFS_WB_FLUSH_MODE_MAX) { + return UFS_QUERY_RESULT_INVALID_VALUE; + } + u->attributes.wb_buffer_partial_flush_mode =3D value; + break; + case UFS_QUERY_ATTR_IDN_MAX_FIFO_WB_PARTIAL_FLUSH_MODE: + u->attributes.max_fifo_wb_partial_flush_mode =3D cpu_to_be32(value= ); + break; + case UFS_QUERY_ATTR_IDN_PINNED_WB_NUM_ALLOC_UNITS: + ufs_wb_pinned_max_size(u, value); + break; + case UFS_QUERY_ATTR_IDN_NON_PINNED_WB_MIN_NUM_ALLOC_UNITS: + ufs_wb_pinned_min_size(u, value); + break; default: g_assert_not_reached(); return 0; @@ -1725,6 +1802,98 @@ static void ufs_process_req(void *opaque) } } =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_SHIFT 21 /* 10MB */ +static void ufs_wb_process_write_pinned(UfsHc *u, UfsRequest *req) +{ + UfsWb *wb =3D &u->wb; + uint64_t remain_bytes, remain_data; + uint32_t total_written; + + if (!wb->pinned_curr_bytes) { + return; + } + + if (wb->pinned_used_bytes >=3D wb->pinned_curr_bytes) { + return; + } + + remain_bytes =3D wb->pinned_curr_bytes - wb->pinned_used_bytes; + if (remain_bytes >=3D req->data_len) { + wb->pinned_total_written_bytes +=3D req->data_len; + wb->pinned_used_bytes +=3D req->data_len; + remain_data =3D 0; + + } else { + wb->pinned_total_written_bytes +=3D remain_bytes; + wb->pinned_used_bytes +=3D remain_bytes; + remain_data =3D req->data_len - remain_bytes; + } + + total_written =3D wb->pinned_total_written_bytes >> UFS_WB_TOTAL_WRITT= EN_SHIFT; + u->attributes.pinned_wb_cumm_written_size =3D cpu_to_be32(total_writte= n); + + remain_bytes =3D wb->curr_bytes - wb->used_bytes; + wb->used_bytes +=3D MIN(remain_bytes, remain_data); +} + +static void ufs_wb_process_write_normal(UfsHc *u, UfsRequest *req) +{ + UfsWb *wb =3D &u->wb; + uint64_t curr_bytes, used_bytes, remain_bytes; + + if (!wb->curr_bytes) { + return; + } + + curr_bytes =3D wb->curr_bytes - wb->pinned_curr_bytes; + used_bytes =3D wb->used_bytes - wb->pinned_used_bytes; + + if (used_bytes >=3D curr_bytes) { + return; + } + + remain_bytes =3D curr_bytes - used_bytes; + wb->used_bytes +=3D MIN(remain_bytes, req->data_len); +} + +static void ufs_wb_process_write_req(UfsRequest *req) +{ + 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, req); + + } else { + ufs_wb_process_write_normal(u, req); + } +} + void ufs_complete_req(UfsRequest *req, UfsReqResult req_result) { UfsHc *u =3D req->hc; @@ -1732,6 +1901,7 @@ void ufs_complete_req(UfsRequest *req, UfsReqResult r= eq_result) =20 if (req_result =3D=3D UFS_REQUEST_SUCCESS) { req->utrd.header.dword_2 =3D cpu_to_le32(UFS_OCS_SUCCESS); + ufs_wb_process_write_req(req); } else { req->utrd.header.dword_2 =3D cpu_to_le32(UFS_OCS_INVALID_CMD_TABLE= _ATTR); } @@ -1801,9 +1971,177 @@ static void ufs_sendback_req(void *opaque) ufs_irq_check(u); } =20 +static inline void ufs_wb_update_avail_buffer(UfsHc *u) +{ + UfsWb *wb =3D &u->wb; + uint64_t non_pinned_curr_bytes, non_pinned_used_bytes; + uint32_t units; + + units =3D ufs_byte_to_unit(u, wb->pinned_curr_bytes); + u->attributes.pinned_wb_buffer_curr_alloc_units =3D cpu_to_be32(units); + + if (!wb->pinned_curr_bytes) + u->attributes.pinned_wb_buffer_avail_percent =3D 0; + else + u->attributes.pinned_wb_buffer_avail_percent =3D + (wb->pinned_curr_bytes - wb->pinned_used_bytes) * 10 / + wb->pinned_curr_bytes; + + non_pinned_curr_bytes =3D wb->curr_bytes - wb->pinned_curr_bytes; + non_pinned_used_bytes =3D wb->used_bytes - wb->pinned_used_bytes; + + units =3D ufs_byte_to_unit(u, non_pinned_curr_bytes); + u->attributes.current_wb_buffer_size =3D cpu_to_be32(units); + + if (!non_pinned_curr_bytes) + u->attributes.available_wb_buffer_size =3D 0; + else + u->attributes.available_wb_buffer_size =3D + (non_pinned_curr_bytes - non_pinned_used_bytes) * 10 / + non_pinned_curr_bytes; +} + +static inline bool ufs_wb_is_flush_needed(UfsHc *u, uint64_t *no_flush_byt= es) +{ + UfsWb *wb =3D &u->wb; + uint32_t max_unit; + + switch (u->attributes.wb_buffer_partial_flush_mode) { + case UFS_WB_FLUSH_NONE: + *no_flush_bytes =3D 0; + break; + case UFS_WB_FLUSH_FIFO: + max_unit =3D be32_to_cpu(u->attributes.max_fifo_wb_partial_flush_m= ode); + *no_flush_bytes =3D ufs_unit_to_byte(u, max_unit); + break; + case UFS_WB_FLUSH_PINNED: + *no_flush_bytes =3D (u->flags.unpin_en) ? 0 : wb->pinned_used_byte= s; + break; + default: + g_assert_not_reached(); + break; + } + + return wb->used_bytes > *no_flush_bytes; +} + +#define UFS_WB_FLUSH_BYTES (4096 * 1024) +static void ufs_wb_process_flush(UfsHc *u) +{ + UfsWb *wb =3D &u->wb; + uint64_t flush_bytes, no_flush_bytes; + + switch (u->attributes.wb_buffer_flush_status) { + case UFS_WB_FLUSH_IDLE: + if (u->flags.wb_buffer_flush_en && + ufs_wb_is_flush_needed(u, &no_flush_bytes)) { + u->attributes.wb_buffer_flush_status =3D UFS_WB_FLUSH_IN_PROGR= ESS; + } + + break; + case UFS_WB_FLUSH_IN_PROGRESS: + if (!u->flags.wb_buffer_flush_en) { + u->attributes.wb_buffer_flush_status =3D UFS_WB_FLUSH_FAILED; + + } else if (!ufs_wb_is_flush_needed(u, &no_flush_bytes)) { + u->attributes.wb_buffer_flush_status =3D UFS_WB_FLUSH_COMPLETE= D; + + } else if (wb->pinned_used_bytes && u->flags.unpin_en) { + flush_bytes =3D MIN(wb->pinned_used_bytes, UFS_WB_FLUSH_BYTES); + wb->pinned_used_bytes -=3D flush_bytes; + wb->used_bytes -=3D flush_bytes; + + } else { + flush_bytes =3D MIN(wb->used_bytes - no_flush_bytes, UFS_WB_FL= USH_BYTES); + wb->used_bytes -=3D flush_bytes; + } + + break; + case UFS_WB_FLUSH_COMPLETED: + if (ufs_wb_is_flush_needed(u, &no_flush_bytes)) { + u->attributes.wb_buffer_flush_status =3D + (u->flags.wb_buffer_flush_en) ? UFS_WB_FLUSH_IDLE : + UFS_WB_FLUSH_IN_PROGRESS; + } + } +} + +static void ufs_wb_process_resize(UfsHc *u) +{ + UfsWb *wb =3D &u->wb; + + if (u->attributes.wb_buffer_resize_status !=3D UFS_WB_RESIZE_IN_PROGRE= SS) { + return; + } + + switch (u->attributes.wb_buffer_resize_en) { + case UFS_WB_DECREASE: + if (wb->curr_bytes <=3D wb->min_bytes) { + u->attributes.wb_buffer_resize_status =3D UFS_WB_RESIZE_FAILED; + return; + + } else if (wb->curr_bytes <=3D wb->used_bytes) { + u->attributes.wb_buffer_resize_status =3D UFS_WB_RESIZE_FAILED; + return; + } + + if (wb->curr_bytes - wb->used_bytes >=3D wb->resize_bytes) { + wb->curr_bytes -=3D wb->resize_bytes; + } else { + wb->curr_bytes =3D wb->used_bytes; + } + + if (wb->curr_bytes < wb->min_bytes) { + wb->curr_bytes =3D wb->min_bytes; + } + + break; + case UFS_WB_INCREASE: + if (wb->curr_bytes >=3D wb->max_bytes) { + u->attributes.wb_buffer_resize_status =3D UFS_WB_RESIZE_FAILED; + return; + } + + wb->curr_bytes +=3D wb->resize_bytes; + if (wb->curr_bytes >=3D wb->max_bytes) { + wb->curr_bytes =3D wb->max_bytes; + } + + break; + default: + g_assert_not_reached(); + break; + } + + u->attributes.wb_buffer_resize_status =3D UFS_WB_RESIZE_COMPLETED; +} + +static void ufs_wb_process_pinned(UfsHc *u) +{ + UfsWb *wb =3D &u->wb; + uint64_t avail_bytes; + + avail_bytes =3D wb->curr_bytes - wb->used_bytes + wb->pinned_used_byte= s; + + if ((u->attributes.wb_buffer_partial_flush_mode !=3D UFS_WB_FLUSH_PINN= ED) || + (wb->curr_bytes <=3D wb->pinned_min_bytes)) { + wb->pinned_curr_bytes =3D 0; + wb->pinned_used_bytes =3D 0; + + } else if (avail_bytes <=3D wb->pinned_max_bytes) { + wb->pinned_curr_bytes =3D avail_bytes; + + } else { + wb->pinned_curr_bytes =3D wb->pinned_max_bytes; + } +} + static void ufs_process_idle(UfsHc *u) { - /* Currently do nothing */ + ufs_wb_process_flush(u); + ufs_wb_process_resize(u); + ufs_wb_process_pinned(u); + ufs_wb_update_avail_buffer(u); return; } =20 @@ -1873,6 +2211,10 @@ 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 true; } =20 @@ -1911,11 +2253,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)); @@ -1977,8 +2350,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); @@ -1994,6 +2372,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; @@ -2008,6 +2396,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 @@ -2073,6 +2463,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 18:38:38 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=1775589895; cv=none; d=zohomail.com; s=zohoarc; b=LWXlgSc7aQZ7AI4tgJQ/nkpgB6FJaf6xmWrZ867mBTsryJRKk1jgpAlZBwPemoRPgZF/HWLrgfV4V/eCGR4cJhhE/jigCJeTLbNjf4CNn2Apy0MHCERYXoW+MXWJupCPVHgKcJ5cMJ6jB1qPCJUiSgEqbpB4Fxf1BfcHroUbNUo= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1775589895; 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=Gnbx2oEKr7fkWt+7vYf6974apZzG+Zj+pQb40NZvhJHOEiYURIaUJoZp9u2Kc4Im4qxlSK62PUyo+LbcGcfHh5GXnUIIsObRmErvyaUNqzW9qm8q6ygWglr3HU5LfrXad6YF/itN0tiSQySdaQgymr7RJNfQhg8sZcphCwRGaRI= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 17755898952768.626251121846394; Tue, 7 Apr 2026 12:24:55 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wABW0-0007eT-9Y; Tue, 07 Apr 2026 14:51:08 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wABTm-00042B-MU for qemu-devel@nongnu.org; Tue, 07 Apr 2026 14:48:50 -0400 Received: from mail-pf1-x433.google.com ([2607:f8b0:4864:20::433]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1wA3g6-0003N6-1f for qemu-devel@nongnu.org; Tue, 07 Apr 2026 06:29:04 -0400 Received: by mail-pf1-x433.google.com with SMTP id d2e1a72fcca58-82a893d289bso2073898b3a.0 for ; Tue, 07 Apr 2026 03:29:01 -0700 (PDT) Received: from [172.17.0.5] ([168.126.243.22]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-82cf9b2714dsm21217324b3a.1.2026.04.07.03.28.58 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 07 Apr 2026 03:29:00 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1775557740; x=1776162540; 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=We90ukQizDdZdRoaaIu7fptmS/DBqtib3/iDwCSPwgYD5qv9SuXOWWRXnR2z8KE9Hf C0RX4+WcCYnjpaUDkuylajEmQKw378eHOSwZbq3cwGTie2aHwjk8mah987iOxYj34GQ8 Yg20Of4lxpEVWbVWKZgI34H6KiVdVZFXwl2ZJI4F/WcaaIK2FS4znhU6CGLL1orTMomN a054PoXWqEqjjH66UvhJFInicWqwgjtPBZBJufQOF0vkKajyOUuepo5u5N30yXlgtgEi NFDNHvf54JfIyCyr10mhddtHdYKA94HyWOvnePPKuDV42grLqJgFvoez5mGmcJcFMS/i 8uhg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1775557740; x=1776162540; 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=U/RjHd6IcRHZah1Y1WH8kmGOxfGaq19clpsGqzzpPV1OazmMLLS2w1hFoDIAq9mwfW xLKXW1TcSN3Ix2JljdE901bMZSRUxB4kCBZiKBaXFYrexOvoaM48huIVBjlXkAIMqJg5 i3q7nYFKwO4eeBI+oCPW3NQx43o1QfLOBM1dxMnA/d3Q2lflzBf73xs0ujamVpFR6dRO psReUeHbUDedR6oaOL9O3hc5QbrjJ6BmZdPUoiqix3S9SXkFd0wq616Q9TWIhwmdeia3 12vmyGsWxdySoe2UOEvplo+Pz/7OVEf0ur01jWsjY3ZGfQxeNuFKhQqfsKATeqoHIbJE 4TKg== X-Gm-Message-State: AOJu0YwvleCypKtlZpwNBiud8AIHpWUGOJrp2MbNpip0+qBQPTPh/wuL 86nF6IoTBpONtkgvIydff4LJI/XxT1CwPcgpyirao8sD9wLLW3tzhfbhsDULY1eDLEhkVA== X-Gm-Gg: AeBDietE4R8JA7xReFr1+CzyEEyrfrJFhH4/zn6H96fdKXbZmkYix5C72jlC6rxpMLO OcXfDt7DCTPyhg5lY4seE04RBcTzX0MLOnjIl+ikoSBc3IWKXH/Eyq73b3G0Gqpt17SC0Ios2mz X08AvgeUXJUmKmdlQ7LbodI8t1cgZeImy1rGKBz5oqZairo4mUfDlq8OwlLXw+MYSlYMNQRaFwc kl9RHty5sp2wG90EcWxhopVlJwq7UHZKES2eIzAeopZH0o2pgtyljoB35MXXOLQtj3coy4/Pdxt dSb+OwcaG6BZuOMaVmZI3wrR1Y4hTHzQT5yzjr3VJM3bUBOLd1AUqhGjGWjPdLgO71KkjMayx4y DeHilR28xIoWXk6FwKv9Mfw6zE0pH92DRi+nqEIzQiEAa746xUOyDuFjg8+xFf5LbLs7TeicWeY B+JvuuL4U3aAn6voy4BvImIOTsTngETQ== X-Received: by 2002:a05:6a00:4b50:b0:827:37d5:af4d with SMTP id d2e1a72fcca58-82d0daa016fmr16290396b3a.24.1775557740461; Tue, 07 Apr 2026 03:29:00 -0700 (PDT) From: Jaemyung Lee X-Google-Original-From: Jaemyung Lee Date: Tue, 07 Apr 2026 19:23:43 +0900 Subject: [PATCH v2 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: <20260407-write_booster-v2-5-dd772bb30194@samsung.com> References: <20260407-write_booster-v2-0-dd772bb30194@samsung.com> In-Reply-To: <20260407-write_booster-v2-0-dd772bb30194@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=1775557727; l=8918; i=jaemyung.lee@samsung.com; s=20260402; h=from:subject:message-id; bh=rU67KxRcVLL6ZVBVhiBQ/INRn8llY3KXffQmzbO047E=; b=7SEIR8QGltYS8WYx8pkAQrMxsp3fZlneRgTFIbsxvg710WiCqXH/UmvJTCow1L+ymg8711lvV wmPPDMsZchTBM9U++HD59/gz+4bblPF5MVFkIrPqsG3Kxe9jsrP1Gah 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::433; envelope-from=ldc.jml@gmail.com; helo=mail-pf1-x433.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: 1775589897318158500 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