From nobody Sat May 30 18:34:28 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=1779264024; cv=none; d=zohomail.com; s=zohoarc; b=ZFNljECxf66UohhEIPz6QVRwY4O9FNgxKiozvGwvk9hVu4TAvnwH4C7+r3yLwFOX2FeESYh7VOf6ofk90+Ouwq0vWcvjyT5T6xUiIV5DcpMGygFVPA4CaQ+rR/eCE1J31xOh5AI8GQn0ycvIc6m0Ik6WqiN/wZtalt96DmyAthc= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1779264024; h=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=n3WZnE0eDbhnSVeNXWk5c+JKL5ligHJETZ0o7+l76M8=; b=dzAdwbVgIf4EhFkAA3Fe+SPSOyfXC5ZMqlEQSUdRx7cAC/lrPtTiP7866SmRCrcyWGpqDpx4jSlu82IsJZgO1nMRqiaSmQFegRPoV9fK618XY1YFGWLVSF3k+owj8mSb4K3GJ/B0H0LlV5tg5NhA7VLkGp6BLDjF/yEXOgm29y8= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1779264023997273.6350351894149; Wed, 20 May 2026 01:00:23 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wPbqN-0003T0-V9; Wed, 20 May 2026 03:59:55 -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 1wPbqL-0003SU-Fo for qemu-devel@nongnu.org; Wed, 20 May 2026 03:59:53 -0400 Received: from mail-pg1-x529.google.com ([2607:f8b0:4864:20::529]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1wPbqJ-00043j-0j for qemu-devel@nongnu.org; Wed, 20 May 2026 03:59:53 -0400 Received: by mail-pg1-x529.google.com with SMTP id 41be03b00d2f7-c736261ee8dso2049320a12.1 for ; Wed, 20 May 2026 00:59:50 -0700 (PDT) Received: from jeuk-MS-7D42.. ([211.226.54.223]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-2bd5c05ffbesm216608435ad.27.2026.05.20.00.59.46 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 20 May 2026 00:59:48 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1779263989; x=1779868789; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=n3WZnE0eDbhnSVeNXWk5c+JKL5ligHJETZ0o7+l76M8=; b=PN9lN0DovbdYsA301WHvHJHJ5u+RzAswH3lCPmZAqB3kKLQLEsEKvsY4qw5xhUCm33 lYJo1YicpfRX0Y4q3nXSES1Jybu9BROKaS3XvlOU/NAXLJi/hXbtMHCwhxz5s1jDiV5J qWVEgTq19FtoqtoyFPY+LSmzr2wqgtu/lMFEwN4GHlai0NuL3EmD5uByczeJ35fKVrru GiC6RL0Z5JF8dq+dntAMZqqppt4+cagTLYT//0v4iF0DX4Tp8yEw487NgEtImZ2JS0+W xZD43blf7d7lvaEPVIuF2jdGu8jt7307BqNFKXLi8KoHUyv7seoWMhBxHIRkXgsfGYy4 OH0g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1779263989; x=1779868789; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=n3WZnE0eDbhnSVeNXWk5c+JKL5ligHJETZ0o7+l76M8=; b=XHlt6KqjqPzUFdsgPwe5Z8TlWLrFKs3Ynox54nWuyfgcrS3rAmN3ZRZJOmUqZMvw/K AGdbs+G3WvNbyEWMF8t9KydidSKUsDm5vElAw6wJgUuX8TukOMkrOT3em2jYRXD+s4dz ZoTGZIWIVgCVEzZtL3fbtICNdOfh4m+E23t2LNh9/VNFdCwH7wUDgIDPLwmt0NnTt0UJ sKvCo/FOwF/yrwpQGGAJHjBpaylC093rvkq/bIQkq2j+oI3gS2dQe/CoA8SL6drTAk+5 gBxlGngp3W2ogF8X8bbrUGsK4PasUv00zl1WcUT2vxEiqQ80J6Ah5rM+FWbeuCPuEYxd 9Y/Q== X-Gm-Message-State: AOJu0Yy+PI1fx51gmwHbNG9zR3bijuUfHpi/t6I/WiMPQdjXUpcjyNB/ kuCsgUGqGVUxPO9mW+CPQBYdb634YkY/rDsEHuTwIb4ZvZSX3wOrTzzno7q+5A== X-Gm-Gg: Acq92OE3dkTlzWvrD7yY9dEpMmkE4eVEe2+wo19yp7BgHekY7ecT/lR0u9rKClP785a uNnipTl/MidV9j/r083D2JLMh0Cw196u9JTE11SaPeXniSdeHgnJr32Xw4hzYpAIDDARX3XUstF NFxhlkciYMLXWeVomiQgYddYHcG8x4oc8JHrDW/dVxJlfOnU4QujyWEdzIj6ZvFVHKCbMSHGQEa Z42OzC0Sl+8o6fVguZGbF9nY7nBUTwGJ2dlEPF63lwPMDzdY76NSzTk/VkTAfK6jAMjLsJpL2Uy LcE0Oitzq69HUxoYztSUgCHKQMRLvlXaxRO68hMWDJp0zUap5X0EnCAhY/6b9+hdjYcBD3dMV7u 5021I8fWroLRwryBnlyKGh7Pt/HtpRdl0EF/35G5D1VNKSKpRHbDYReiAYgJVmabWa5+mNPUhdm XRoNxmXA8KjrOyA0kucwR2DDOSmKe2xRZRdbiJh3s= X-Received: by 2002:a17:902:c403:b0:2bd:8dbd:17e6 with SMTP id d9443c01a7336-2bd8dbd19c6mr229704585ad.35.1779263989250; Wed, 20 May 2026 00:59:49 -0700 (PDT) From: Jeuk Kim To: qemu-devel@nongnu.org, stefanha@redhat.com Cc: kwolf@redhat.com, hreitz@redhat.com, farosas@suse.de, lvivier@redhat.com, pbonzini@redhat.com, qemu-block@nongnu.org, jeuk20.kim@samsung.com, j-young.choi@samsung.com, jaemyung.lee@samsung.com, Jaemyung Lee Subject: [PULL 1/5] hw/ufs: Apply UFS 4.1 Specification Date: Wed, 20 May 2026 16:59:27 +0900 Message-ID: X-Mailer: git-send-email 2.43.0 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=2607:f8b0:4864:20::529; envelope-from=jeuk20.kim@gmail.com; helo=mail-pg1-x529.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: 1779264027651154100 Content-Type: text/plain; charset="utf-8" From: Jaemyung Lee 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 Signed-off-by: Jeuk Kim --- hw/ufs/ufs.c | 70 +++++++++++++++++++++++++++++++++++++++++++-- include/block/ufs.h | 59 ++++++++++++++++++++++++++++++++++++-- 2 files changed, 123 insertions(+), 6 deletions(-) diff --git a/hw/ufs/ufs.c b/hw/ufs/ufs.c index 6548f0f637..a3f2a3be18 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 @@ -1068,6 +1068,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) @@ -1125,10 +1126,32 @@ 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_ATTR_READ, }; =20 static inline QueryRespCode ufs_attr_check_idn_valid(uint8_t idn, int op) @@ -1262,12 +1285,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; } @@ -1305,6 +1366,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 04cb24324d..4dacfb776f 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.43.0 From nobody Sat May 30 18:34:28 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=1779264047; cv=none; d=zohomail.com; s=zohoarc; b=UrI1dq8bGYYUOpNtu2iVr4wvQJwB8WqCQsjucjYT0axX1WDsfpufozadf8X/mVmbxmzKzeEvVFcDAUjBXbG/7sskYBGDHwu0v/IkR0P8RJDYI82NJQL4rW6bewsWWA41jxQWLR9o8Ae4f6q0A8Yf03O4DpyUNh/NcaNLtDpXHjY= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1779264047; h=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=IxzZDu5BKm346SHqX6kslm5xBxSbr8zBKiC+4HDaSlU=; b=SUI+H4FbHJVphbYmh8we8IxGdP8hYQXWGLmZ1td2U86gFiTrNR7BaE3dvI22AKa9I5VJCIv1qqHK249VlLm/lHIR5kZhqbbfLSgSz9GEA6XF+lMrmUfIGg3K3bKVvugdozHMn0qCLITkn/AAZ95XRiHCuAVcLVqDcf4QRbuCfRc= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1779264047709211.57446987028175; Wed, 20 May 2026 01:00:47 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wPbqq-0003UR-AX; Wed, 20 May 2026 04:00: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 1wPbqN-0003Sq-NL for qemu-devel@nongnu.org; Wed, 20 May 2026 03:59:55 -0400 Received: from mail-pl1-x632.google.com ([2607:f8b0:4864:20::632]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1wPbqL-00047I-PT for qemu-devel@nongnu.org; Wed, 20 May 2026 03:59:55 -0400 Received: by mail-pl1-x632.google.com with SMTP id d9443c01a7336-2ba856db1c0so32984255ad.3 for ; Wed, 20 May 2026 00:59:53 -0700 (PDT) Received: from jeuk-MS-7D42.. ([211.226.54.223]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-2bd5c05ffbesm216608435ad.27.2026.05.20.00.59.49 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 20 May 2026 00:59:51 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1779263992; x=1779868792; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=IxzZDu5BKm346SHqX6kslm5xBxSbr8zBKiC+4HDaSlU=; b=jnOK+DKu8Lifr0atebU2QAsynJNThWp1l3upHL3kHe4DoGOD72C7OcNjRGLnA5oTP8 1mt1iUjvREL21DcuUIryZL6okkO5Y+lInjEBgRBsEYuz8Rx9eMEqAu0HxleIwog3s6XA eKJle3Kc0Jfiw8vYbPhgGIORaJgrH7CSbbOBJT6rRWyjm6ZQb/o8znlkTcDHSXtXANjS i0Pkin7Zk42p0Hm5Z773f1s8O11YPTPaVMskCEYHr+v4riodtpLX7BjQPCJ4rUWiMCvG sAFAc+rMy54bnR5igBNalWsSZaWRHa+TMH1xvJofsVDpGQPgGuMXLMLDsCGI8o08jfi5 6E3w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1779263992; x=1779868792; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=IxzZDu5BKm346SHqX6kslm5xBxSbr8zBKiC+4HDaSlU=; b=DHDtiDuJJoN1s+s/rU5I3cU+ixmPdsmYOZPjwqpksLeRFD7A5JEupDrEAFG6MtaOmb E9ZovZ2W1CzXplu9KWb3JptxlR2KYR7ZKnUm1tEuviLv1xK5DcgCRbxRVGe9sACLY22c YeUkKdumB4rKnHBvCpSBP15pitOWZbAC2P4X1oJ+AdPkasoF9CML+dYWyZ5KJiC4u6O4 jE6tE2L3827F0i052+xHfMn6ZJbs8VBVnmldDIvXY54NPTvWcUWF6SalRNdocYYAkops HHgXk1DW6E2/gjJlDUElr1GvcCLhU6Tii0Wnu6G4HmXoBdjkfe7VoxJwgGx32n+5SmKB tBXQ== X-Gm-Message-State: AOJu0YzNYBPiu1dqz4ldh14V38Mard6bKBxT4Fzz5s5Y89Fvxgc9oSTc MCCtxfw/EVYc5oeAGQtkCaDOt0u4EC9cu/vdRHa2mWzM5hIEHOiar7FDM+c2tQ== X-Gm-Gg: Acq92OG8JL9Gd497JsQysfBuFCytaJoVE7JwodQ3dP0Xz65ZD3+9TEKQCfArcs1SE1w A6asTyhtOQzVsLcFul6zCcJqQbzWCp2hZl85K0sgj006kDOPiGNbjJ+SRy4VikkLEoLcbXA8h50 jZU5cSgHH34JqisQqjL/hkcjS04ZFtXKlUJ15Cv15NNMq8TgjmIku27AFsYCB/xBLVinLu5DkIT ddUMQ+k5sZOlS2WSOD2FQ0zMsvrNLBZCqet3mJEaciXOeRFIuQbNv6lAuWNpsByFt2Wv+V/zLCx PqDj5r9Yn3h+VNFePOfQOXt9/7yFi4qeTrK6Vl4SHz6ULdNtrjYQIZJgDfrEdzJpT4Ryjmr2qHy VtrHhGRfgJzrocfBHUe4yL7VHrJK62BAF7947He3G0tlYLuvJ0XYwtTkVlDbvKfL1NrxMBYo6v2 LvOR9grHLHAILa34jTHVY7x26vV1A8 X-Received: by 2002:a17:903:32ce:b0:2b0:6a22:5165 with SMTP id d9443c01a7336-2bd7e77a968mr235897775ad.7.1779263991821; Wed, 20 May 2026 00:59:51 -0700 (PDT) From: Jeuk Kim To: qemu-devel@nongnu.org, stefanha@redhat.com Cc: kwolf@redhat.com, hreitz@redhat.com, farosas@suse.de, lvivier@redhat.com, pbonzini@redhat.com, qemu-block@nongnu.org, jeuk20.kim@samsung.com, j-young.choi@samsung.com, jaemyung.lee@samsung.com, Jaemyung Lee Subject: [PULL 2/5] hw/ufs: Modify flag handling operation Date: Wed, 20 May 2026 16:59:28 +0900 Message-ID: X-Mailer: git-send-email 2.43.0 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=2607:f8b0:4864:20::632; envelope-from=jeuk20.kim@gmail.com; helo=mail-pl1-x632.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=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: 1779264049923154100 Content-Type: text/plain; charset="utf-8" From: Jaemyung Lee 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 Signed-off-by: Jeuk Kim --- hw/ufs/ufs.c | 152 ++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 119 insertions(+), 33 deletions(-) diff --git a/hw/ufs/ufs.c b/hw/ufs/ufs.c index a3f2a3be18..2cf838d20f 100644 --- a/hw/ufs/ufs.c +++ b/hw/ufs/ufs.c @@ -1089,6 +1089,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, @@ -1172,39 +1288,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; @@ -1369,6 +1452,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.43.0 From nobody Sat May 30 18:34:28 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=1779264083; cv=none; d=zohomail.com; s=zohoarc; b=gQiSM+ECKlNR314GacJnkZyw7+HZ1I4QvZbwNVRVM7RAiLg5lxNCD/+ArVhfT5iLtLmIL5d5V251amU7LHBRPPqQCRCkp7fSdDoemDbGzpfUBx8AkeWXi98zb7RIzXLznnteYVpAZEHmuE1CCcaORgqdnZvy31DVtcvI5igMXqI= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1779264083; h=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=jqta58yhpZd9aYHLNbyGE5K22GTl6WBvggYweOfKiPI=; b=jRsY2FPTBWh3Zdg6KQhngDGLCC5kyrxyLCA48Pjv7dM0eCg2tpqfstq7GLBKZDcPV8NrbME8P40eeKxeXdvMHxgJpdNG27tZ6qzWKwEzRxOAL/dNVdl8ruPMLUENM7F6pXhvH4tqcUm5rNwmddQW4I7qnxkyxL170X1DvM/k52A= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1779264083234772.918893164057; Wed, 20 May 2026 01:01:23 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wPbrC-0003tG-L2; Wed, 20 May 2026 04:00: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 1wPbqR-0003US-8d for qemu-devel@nongnu.org; Wed, 20 May 2026 04:00:08 -0400 Received: from mail-pl1-x62a.google.com ([2607:f8b0:4864:20::62a]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1wPbqO-00047u-I7 for qemu-devel@nongnu.org; Wed, 20 May 2026 03:59:58 -0400 Received: by mail-pl1-x62a.google.com with SMTP id d9443c01a7336-2bcd3ac3307so25417875ad.0 for ; Wed, 20 May 2026 00:59:56 -0700 (PDT) Received: from jeuk-MS-7D42.. ([211.226.54.223]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-2bd5c05ffbesm216608435ad.27.2026.05.20.00.59.52 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 20 May 2026 00:59:54 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1779263994; x=1779868794; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=jqta58yhpZd9aYHLNbyGE5K22GTl6WBvggYweOfKiPI=; b=QnLon9Kvo0JTu19anuCZ8JrlaxUYgcooyAU/YFC5vmxUsE4+nmRusr5S0zwCZLBLul qLKYwhVNEI3SBM2lHl4JwocmTaL+JcObwnipor93zJDu6yt5lc3mvxZUKam2ALq0qOO/ USHdyQQh2P4gDK7cH6yVR1nfNd/xCdeSzgAo/9U4rDGK0KPkOMgvnksCvPMmMNGrtD8n JMFiLkzDxLF9W13Wg216WcvIpdw0iLe6Xn1KlGbOmpIlQL8WD8S16PGcqNRYA8AOzCR2 RTN/5NY3PCcuK4duN8odHJYn/uWPz/u8kiuFCfccZ4M9yJw0m3M1In/hMx6r9/ROMfxX 4mKQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1779263994; x=1779868794; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=jqta58yhpZd9aYHLNbyGE5K22GTl6WBvggYweOfKiPI=; b=gUvdm9lDNCczG1cpx/Zhtd/XE2uazFqUrS52IxO61DrQJ6WT4UFw+DLmXuTB/KeAjH 6tINc5v0Pm3yOxHBhaX6gQ1OP4dlhy03QVsnZWfeEjCDMRH0TuEMUf0OKVyjfbyhBHWh NS7OfAUIE+2KE53OMxeNb7wCISI/DaypkZXnp7cWQqP199KcZo9FsuRnu3Q/pyoThqpi yWRnZ/Is62hZxWC0KCRQxTQqvQWG0HeVBiQl4O9RyPPUNOCDr0lxubrM9fMgdgKifnXR ucAa2JWZtxCtudVoG0dlMPdoVGIbbHRFOaavmqxFbeXYn0hXdsvXLIP9qPMAD0seDB13 GMOw== X-Gm-Message-State: AOJu0YxaUonL4La73aokAGihZF4YGEP06BeAIqna65zQx3fv61Ez91vu C7/9aUnEfypRwOclPmZ3FYECg/T86hdbDlmckidi6jyoa0zw3mv2PtD9vLcJlg== X-Gm-Gg: Acq92OHIM3JE+r/JCQXFxVVbC9YpNIDLXZqSIiFR8IKCyaDqwzBXECx48ypNyUDcs6W YNLwR6HNH2CpYTsUwg8M1phV8W8M1AyKO7IYsJ49tOMGNXKsHwtNkcTsidc+2Xh9GSaQ67h8G86 +KUMe7YQ37AikEgXs92iZBwwhvfZDymhvepDnW5rfvmgOljXsNcENiSsv/rM0ezdze65jjMrmVh O5JZCUfFsri9Qr/gFodlunh65u/fCUSopMTKCrUBddvVe09HI9roJbg1ixf46HEXAE8DeeFSl04 uxP3zKS9y4dahivzlVMaGMJqgoNukbGiYW6oyfttAkSkBAfbBuDlJi8yAFLrHkjUFH938RcPT4L iQkXNqeWn3QBfHS78PfRq7521jZvZqf6tn7AUYIqfVNhyoL7DrYDwC/tzamsZ5XDbZtPw6m7XNg yfI+aDA16xfJQs5YvKJx+2Um2Nwwts2j+2fFSR85s= X-Received: by 2002:a17:903:94e:b0:2b9:f59e:aca5 with SMTP id d9443c01a7336-2bd7e9e7777mr241599135ad.39.1779263994463; Wed, 20 May 2026 00:59:54 -0700 (PDT) From: Jeuk Kim To: qemu-devel@nongnu.org, stefanha@redhat.com Cc: kwolf@redhat.com, hreitz@redhat.com, farosas@suse.de, lvivier@redhat.com, pbonzini@redhat.com, qemu-block@nongnu.org, jeuk20.kim@samsung.com, j-young.choi@samsung.com, jaemyung.lee@samsung.com, Jaemyung Lee Subject: [PULL 3/5] hw/ufs: Add idle operation Date: Wed, 20 May 2026 16:59:29 +0900 Message-ID: <9b43508b10469f6cd5dad3223d1cdcf2b448d5c9.1779263628.git.jeuk20.kim@samsung.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=2607:f8b0:4864:20::62a; envelope-from=jeuk20.kim@gmail.com; helo=mail-pl1-x62a.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: 1779264086461154100 Content-Type: text/plain; charset="utf-8" From: Jaemyung Lee 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 Signed-off-by: Jeuk Kim --- hw/ufs/ufs.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++++ hw/ufs/ufs.h | 2 ++ 2 files changed, 73 insertions(+) diff --git a/hw/ufs/ufs.c b/hw/ufs/ufs.c index 2cf838d20f..237b410668 100644 --- a/hw/ufs/ufs.c +++ b/hw/ufs/ufs.c @@ -1870,6 +1870,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) { @@ -1932,6 +1997,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 @@ -2028,6 +2094,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) @@ -2055,6 +2124,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 9e800cafac..64144b556a 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.43.0 From nobody Sat May 30 18:34:28 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=1779264120; cv=none; d=zohomail.com; s=zohoarc; b=JlKoU2zDlDkXc6frdTt5BNLD9wPQSJMwvMdtniXmn0ogI/DqgYJ8vcFadG1d/KHT2lswRlLZmUxjd0rYysiBbUuVsEgvWtDRpjguArd9e1Am3dfMXId5Uubo57Kr3eU4sNS5REJIYGSag8EoQF+0aAH1O0dKytn2Sugx2DQJD1Y= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1779264120; h=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=keXF5Y5f8VicSkJdCNSw0VaXFvzzvmv1oU3yOpECxHg=; b=j/2QWZBmFQTG8G7Q3wZSp9yifEgT2EFaTX9Ifwi7lyJPRLXNsm6JqVwvLj6MIHVOd2cGqrflcfH13S3ykVvf6+JFkhRH8bZH07finrPYZwDMG/uouShO14LfjFc2oMbGPizBgDoMGCyHmZmLQCDvQQlSv5BbfzlROpFbcFABhZg= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1779264120715237.5653655903061; Wed, 20 May 2026 01:02:00 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wPbrB-0003qS-FC; Wed, 20 May 2026 04:00:45 -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 1wPbqi-0003et-8e for qemu-devel@nongnu.org; Wed, 20 May 2026 04:00:22 -0400 Received: from mail-pl1-x62d.google.com ([2607:f8b0:4864:20::62d]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1wPbqT-00049d-08 for qemu-devel@nongnu.org; Wed, 20 May 2026 04:00:08 -0400 Received: by mail-pl1-x62d.google.com with SMTP id d9443c01a7336-2ba1e9d3687so29765915ad.3 for ; Wed, 20 May 2026 00:59:58 -0700 (PDT) Received: from jeuk-MS-7D42.. ([211.226.54.223]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-2bd5c05ffbesm216608435ad.27.2026.05.20.00.59.54 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 20 May 2026 00:59:56 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1779263997; x=1779868797; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=keXF5Y5f8VicSkJdCNSw0VaXFvzzvmv1oU3yOpECxHg=; b=qQrJoywcbonx2wiuCBSIyAWITPkf9nUEgmDbcAtEVXewfyMvSUJGYNEnS3mQf3Wdxs ici/JsFscIpPXgpZADlejyPBTtHpr9Ji7boUAGF4MfnEhMm8IWHW6CTBFkToVUfcQBL8 kZ3NMEfK6l1LgbOVjgjssObCzH4FQ0EyMuM3W4OHm6GtrsAxoeMXG6D1vyoGWgaRwj1m JgksKWluSmAKwJHmpjh6cNXi8adkLrXPJ0kVm7bw3X10QkI2YbP7o8zjlwNBc8jnJyZK mqvuFvDnVy/1/vaiuPxr1AKslJ2rs34IHIYqYkOUv340thP9sz8L3CswnjrlT/1FQC+i +4WQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1779263997; x=1779868797; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=keXF5Y5f8VicSkJdCNSw0VaXFvzzvmv1oU3yOpECxHg=; b=XD4wnlehbBUB5r9jAf7m2JBB9VQGx+NIdaWGc33UAx/+RjeWw7Z6ic+yYc9LEQKXjk R44B2KhQCTX4NEkgFaj6K5wgmhMO/iq3TKqr/jByUY9Ti2YD+/wMCAIu7yHuQAmG2WZS R3P4FbqkHkW5BOm8oPt7Y1cE8EmWwjnrFKJ/9F9AzX9YuebiRNB0N5J8/WoVmgYH7fr4 RzQXhr6rtsykdHHZirL3nxc4ELgFyyfjXrUsqhVvK7hB2fjIPAtjqBZ60RFhfkx6Vfev RcdT4gs3zDD/1MkbX4Ec0h9uFjLoL01W1fj9iyTLfw2hKgMfL0vw5mKl1I+jGYvP5PN7 7S5A== X-Gm-Message-State: AOJu0YwNjWdRW0re70gIDZQk6aVBywoSf77b7cdY2wq+WGykIyN8T4Pv psCUo0G71yzPiemy3FUXHdlj0PWwgrNIPxvXkvZMPDVZlWs7CheXE/yLB/7zHg== X-Gm-Gg: Acq92OGHm+yWuvm9W2EYD+tVh/a2i9C3g2/+iKVmU2SY+amFyl2ZXE4ZKYOuUr/L5sK cdz1Bbjsh51NO3B/0PKznsDF8WiEXmdcYPgw/0ij6COqDTHWAM7vQPP4cv63cI7m6Rc8pHzSRed DkG6bVV3XpKykjNd9/y9krxsaTArQ32app1iHTcWf9QpMRp5Z0C/4W/HFjy6PifoshzXmcJHMNr Gd7ZLHXNjtv+W/MVCdPdRc7c5+/X/eoem62kJSh2BKEvyUN/XsPNSlhrdKUmuf9aySFyji51+qO eMtmcoZy3tQnfyfnRU6jCCMqQntWIsPWe+QcP37xSQuOgMKadL7cj+qCAvwam/5olRDFsCNOZ4O EWLpjJcCYs3fQyOJfiB57gOvMca+kwb7lnSq0NTowAVMYweo+6VT7PqSpF8lH8wE3ZgCEXTcsFy jhrOXIkPoYdWkGHYrHoAl2LuWpy3DH X-Received: by 2002:a17:902:ea01:b0:2bd:d7b5:83ed with SMTP id d9443c01a7336-2bdd7b5879cmr138691545ad.39.1779263997174; Wed, 20 May 2026 00:59:57 -0700 (PDT) From: Jeuk Kim To: qemu-devel@nongnu.org, stefanha@redhat.com Cc: kwolf@redhat.com, hreitz@redhat.com, farosas@suse.de, lvivier@redhat.com, pbonzini@redhat.com, qemu-block@nongnu.org, jeuk20.kim@samsung.com, j-young.choi@samsung.com, jaemyung.lee@samsung.com, Jaemyung Lee Subject: [PULL 4/5] hw/ufs: Add UFS Write Booster Support Date: Wed, 20 May 2026 16:59:30 +0900 Message-ID: X-Mailer: git-send-email 2.43.0 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=2607:f8b0:4864:20::62d; envelope-from=jeuk20.kim@gmail.com; helo=mail-pl1-x62d.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: 1779264123000154101 Content-Type: text/plain; charset="utf-8" From: Jaemyung Lee Add UFS Write Booster implementation which follows UFS 4.1 Spec. Signed-off-by: Jaemyung Lee Signed-off-by: Jeuk Kim --- hw/ufs/lu.c | 102 +++++++++- hw/ufs/ufs.c | 444 ++++++++++++++++++++++++++++++++++++++++++-- hw/ufs/ufs.h | 47 +++++ include/block/ufs.h | 55 ++++++ 4 files changed, 628 insertions(+), 20 deletions(-) diff --git a/hw/ufs/lu.c b/hw/ufs/lu.c index 709d6adcf6..f13fc6e342 100644 --- a/hw/ufs/lu.c +++ b/hw/ufs/lu.c @@ -58,13 +58,113 @@ static void ufs_build_scsi_response_upiu(UfsRequest *r= eq, uint8_t *sense, status, data_segment_length); } =20 +#define UFS_GROUP_NUMBER_MASK 0x1F +#define UFS_WB_GROUP_NUMBER_DEFAULT 0x00 /* 00000b */ +#define UFS_WB_GROUP_NUMBER_PINNED 0x18 /* 11000b */ +static bool ufs_wb_check_write_pinned(UfsHc *u, UfsRequest *req) +{ + uint8_t cmd =3D req->req_upiu.sc.cdb[0]; + uint8_t group_number =3D UFS_WB_GROUP_NUMBER_DEFAULT; + + if (u->attributes.wb_buffer_partial_flush_mode !=3D UFS_WB_FLUSH_PINNE= D) { + return false; + } + + if (cmd =3D=3D WRITE_16) { + group_number =3D req->req_upiu.sc.cdb[14] & UFS_GROUP_NUMBER_MASK; + + } else if (cmd =3D=3D WRITE_10) { + group_number =3D req->req_upiu.sc.cdb[6] & UFS_GROUP_NUMBER_MASK; + } + + return (group_number =3D=3D UFS_WB_GROUP_NUMBER_PINNED); +} + +static void ufs_wb_process_write_normal(UfsHc *u, uint32_t transfered_len) +{ + UfsWb *wb =3D &u->wb; + uint64_t curr_bytes, used_bytes, remain_bytes; + + if (!wb->curr_bytes) { + return; + } + + curr_bytes =3D wb->curr_bytes - wb->pinned_curr_bytes; + used_bytes =3D wb->used_bytes - wb->pinned_used_bytes; + + if (used_bytes >=3D curr_bytes) { + return; + } + + remain_bytes =3D curr_bytes - used_bytes; + wb->used_bytes +=3D MIN(remain_bytes, transfered_len); +} + +#define UFS_WB_TOTAL_WRITTEN_DIV (10 * 1024 * 1024) /* 10MiB */ +static void ufs_wb_process_write_pinned(UfsHc *u, uint32_t transfered_len) +{ + UfsWb *wb =3D &u->wb; + uint64_t remain_bytes, remain_data; + uint32_t total_written; + + if (!wb->pinned_curr_bytes) { + ufs_wb_process_write_normal(u, transfered_len); + return; + } + + if (wb->pinned_used_bytes >=3D wb->pinned_curr_bytes) { + ufs_wb_process_write_normal(u, transfered_len); + return; + } + + remain_bytes =3D wb->pinned_curr_bytes - wb->pinned_used_bytes; + if (remain_bytes >=3D transfered_len) { + wb->pinned_total_written_bytes +=3D transfered_len; + wb->pinned_used_bytes +=3D transfered_len; + wb->used_bytes +=3D transfered_len; + remain_data =3D 0; + + } else { + wb->pinned_total_written_bytes +=3D remain_bytes; + wb->pinned_used_bytes +=3D remain_bytes; + wb->used_bytes +=3D remain_bytes; + remain_data =3D transfered_len - remain_bytes; + } + + total_written =3D wb->pinned_total_written_bytes / UFS_WB_TOTAL_WRITTE= N_DIV; + u->attributes.pinned_wb_cumm_written_size =3D cpu_to_be32(total_writte= n); + + ufs_wb_process_write_normal(u, remain_data); +} + +static void ufs_wb_process_write_req(UfsRequest *req, uint32_t transfered_= len) +{ + UfsHc *u =3D req->hc; + + if (!u->flags.wb_en || !ufs_is_write_req(req)) { + return; + } + + if (ufs_wb_check_write_pinned(u, req)) { + ufs_wb_process_write_pinned(u, transfered_len); + } else { + ufs_wb_process_write_normal(u, transfered_len); + } + + ufs_wb_update_avail_buffer(u); +} + static void ufs_scsi_command_complete(SCSIRequest *scsi_req, size_t resid) { UfsRequest *req =3D scsi_req->hba_private; int16_t status =3D scsi_req->status; - uint32_t transfered_len =3D scsi_req->cmd.xfer - resid; =20 + /* WB accounting should only happen for successful commands */ + if (status =3D=3D GOOD) { + ufs_wb_process_write_req(req, transfered_len); + } + ufs_build_scsi_response_upiu(req, scsi_req->sense, scsi_req->sense_len, transfered_len, status); =20 diff --git a/hw/ufs/ufs.c b/hw/ufs/ufs.c index 237b410668..6780d73174 100644 --- a/hw/ufs/ufs.c +++ b/hw/ufs/ufs.c @@ -375,7 +375,12 @@ static void ufs_process_uiccmd(UfsHc *u, uint32_t val) u->reg.hcs =3D FIELD_DP32(u->reg.hcs, HCS, UTMRLRDY, 1); u->reg.ucmdarg2 =3D UFS_UIC_CMD_RESULT_SUCCESS; break; - /* TODO: Revisit it when Power Management is implemented */ + /* + * TODO: Revisit after PM implementation + * Power Management is not supported in current QEMU-UFS, + * So Write Booster's Flush during Hibern8 operation is also remained + * as not considered. + */ case UFS_UIC_CMD_DME_HIBER_ENTER: u->reg.is =3D FIELD_DP32(u->reg.is, IS, UHES, 1); u->reg.hcs =3D FIELD_DP32(u->reg.hcs, HCS, UPMCRS, UFS_PWR_LOCAL); @@ -940,6 +945,32 @@ static const MemoryRegionOps ufs_mmio_ops =3D { }, }; =20 +static void ufs_wb_update_ee_status(UfsHc *u, uint16_t *ee_status) +{ + UfsWb *wb =3D &u->wb; + uint64_t curr_bytes =3D wb->curr_bytes - wb->pinned_curr_bytes; + uint64_t used_bytes =3D wb->used_bytes - wb->pinned_used_bytes; + + if (curr_bytes !=3D 0 && used_bytes >=3D curr_bytes) { + *ee_status |=3D MASK_EE_WB_FLUSH_NEEDED; + } else { + *ee_status &=3D ~MASK_EE_WB_FLUSH_NEEDED; + } + + if (u->attributes.wb_buffer_resize_hint !=3D UFS_WB_HINT_KEEP) { + *ee_status |=3D MASK_EE_WB_RESIZE_HINT; + } else { + *ee_status &=3D ~MASK_EE_WB_RESIZE_HINT; + } + + if (wb->pinned_used_bytes !=3D 0 && + wb->pinned_used_bytes >=3D wb->pinned_curr_bytes) { + *ee_status |=3D MASK_EE_PINNED_WB_FULL; + } else { + *ee_status &=3D ~MASK_EE_PINNED_WB_FULL; + } +} + static void ufs_update_ee_status(UfsHc *u) { uint16_t ee_status =3D be16_to_cpu(u->attributes.exception_event_statu= s); @@ -958,6 +989,8 @@ static void ufs_update_ee_status(UfsHc *u) ee_status &=3D ~MASK_EE_TOO_LOW_TEMP; } =20 + ufs_wb_update_ee_status(u, &ee_status); + u->attributes.exception_event_status =3D cpu_to_be16(ee_status); } =20 @@ -1064,11 +1097,16 @@ static const int flag_permission[UFS_QUERY_FLAG_IDN= _COUNT] =3D { [UFS_QUERY_FLAG_IDN_FPHYRESOURCEREMOVAL] =3D UFS_QUERY_FLAG_READ, [UFS_QUERY_FLAG_IDN_BUSY_RTC] =3D UFS_QUERY_FLAG_READ, [UFS_QUERY_FLAG_IDN_PERMANENTLY_DISABLE_FW_UPDATE] =3D UFS_QUERY_FLAG_= READ, - /* Write Booster is not supported */ - [UFS_QUERY_FLAG_IDN_WB_EN] =3D UFS_QUERY_FLAG_READ, - [UFS_QUERY_FLAG_IDN_WB_BUFF_FLUSH_EN] =3D UFS_QUERY_FLAG_READ, + [UFS_QUERY_FLAG_IDN_WB_EN] =3D UFS_QUERY_FLAG_READ | UFS_QUERY_FLAG_SE= T | + UFS_QUERY_FLAG_CLEAR | UFS_QUERY_FLAG_TOG= GLE, + [UFS_QUERY_FLAG_IDN_WB_BUFF_FLUSH_EN] =3D + UFS_QUERY_FLAG_READ | UFS_QUERY_FLAG_SET | UFS_QUERY_FLAG_CLEAR | + UFS_QUERY_FLAG_TOGGLE, + /* TODO: Revisit after PM implementation */ [UFS_QUERY_FLAG_IDN_WB_BUFF_FLUSH_DURING_HIBERN8] =3D UFS_QUERY_FLAG_R= EAD, - [UFS_QUERY_FLAG_IDN_UNPIN_EN] =3D UFS_QUERY_FLAG_READ, + [UFS_QUERY_FLAG_IDN_UNPIN_EN] =3D UFS_QUERY_FLAG_READ | UFS_QUERY_FLAG= _SET | + UFS_QUERY_FLAG_CLEAR | + UFS_QUERY_FLAG_TOGGLE, }; =20 static inline QueryRespCode ufs_flag_check_idn_valid(uint8_t idn, int op) @@ -1162,8 +1200,8 @@ static QueryRespCode ufs_write_flag_value(UfsHc *u, u= int8_t idn, uint8_t value) case UFS_QUERY_FLAG_IDN_WB_BUFF_FLUSH_EN: u->flags.wb_buffer_flush_en =3D value; break; - case UFS_QUERY_FLAG_IDN_WB_BUFF_FLUSH_DURING_HIBERN8: - u->flags.wb_buffer_flush_during_hibernate =3D value; + case UFS_QUERY_FLAG_IDN_UNPIN_EN: + u->flags.unpin_en =3D value; break; default: return UFS_QUERY_RESULT_INVALID_VALUE; @@ -1257,17 +1295,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_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_READ | UFS_QUERY_ATTR_WRITE, }; =20 static inline QueryRespCode ufs_attr_check_idn_valid(uint8_t idn, int op) @@ -1307,6 +1348,29 @@ 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_C= OMPLETED || + value =3D=3D UFS_WB_FLUSH_FAILED) { + u->attributes.wb_buffer_flush_status =3D UFS_WB_FLUSH_IDLE; + } + + return value; +} + +static inline uint32_t ufs_wb_read_resize_status(UfsHc *u) +{ + uint32_t value =3D u->attributes.wb_buffer_resize_status; + + if (value =3D=3D UFS_WB_RESIZE_COMPLETED || value =3D=3D UFS_WB_RESIZE= _FAILED) { + u->attributes.wb_buffer_resize_status =3D UFS_WB_RESIZE_IDLE; + } + + return value; +} + static uint32_t ufs_read_attr_value(UfsHc *u, uint8_t idn) { switch (idn) { @@ -1361,7 +1425,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: @@ -1392,10 +1456,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: @@ -1416,6 +1478,132 @@ static uint32_t ufs_read_attr_value(UfsHc *u, uint8= _t idn) return 0; } =20 +static void ufs_wb_resize_op(UfsHc *u, uint32_t value) +{ + if (u->attributes.wb_buffer_resize_status =3D=3D UFS_WB_RESIZE_IN_PROG= RESS) { + return; + } + + if (value =3D=3D UFS_WB_IDLE) { + return; + } + + u->attributes.wb_buffer_resize_en =3D value; + u->attributes.wb_buffer_resize_status =3D UFS_WB_RESIZE_IN_PROGRESS; + u->attributes.wb_buffer_resize_hint =3D UFS_WB_HINT_KEEP; +} + +void ufs_wb_update_avail_buffer(UfsHc *u) +{ + UfsWb *wb =3D &u->wb; + uint64_t non_pinned_curr_bytes, non_pinned_used_bytes; + uint32_t units; + + units =3D ufs_byte_to_unit(u, wb->fifo_curr_bytes); + u->attributes.curr_fifo_wb_partial_flush_mode =3D cpu_to_be32(units); + + units =3D ufs_byte_to_unit(u, wb->pinned_curr_bytes); + u->attributes.pinned_wb_buffer_curr_alloc_units =3D cpu_to_be32(units); + + if (wb->pinned_curr_bytes <=3D wb->pinned_used_bytes) + u->attributes.pinned_wb_buffer_avail_percent =3D 0; + else + u->attributes.pinned_wb_buffer_avail_percent =3D + (wb->pinned_curr_bytes - wb->pinned_used_bytes) * 10 / + wb->pinned_curr_bytes; + + non_pinned_curr_bytes =3D wb->curr_bytes - wb->pinned_curr_bytes; + non_pinned_used_bytes =3D wb->used_bytes - wb->pinned_used_bytes; + + units =3D ufs_byte_to_unit(u, non_pinned_curr_bytes); + u->attributes.current_wb_buffer_size =3D cpu_to_be32(units); + + if (!non_pinned_curr_bytes) + u->attributes.available_wb_buffer_size =3D 0; + else + u->attributes.available_wb_buffer_size =3D + (non_pinned_curr_bytes - non_pinned_used_bytes) * 10 / + non_pinned_curr_bytes; + + assert(wb->curr_bytes >=3D wb->pinned_curr_bytes); + assert(wb->used_bytes >=3D wb->pinned_used_bytes); +} + +static void ufs_wb_sync_buffer_size(UfsHc *u) +{ + UfsWb *wb =3D &u->wb; + uint64_t avail_bytes; + + wb->fifo_curr_bytes =3D MIN(wb->curr_bytes, wb->fifo_max_bytes); + avail_bytes =3D wb->curr_bytes - wb->used_bytes + wb->pinned_used_byte= s; + + if ((u->attributes.wb_buffer_partial_flush_mode !=3D UFS_WB_FLUSH_PINN= ED) || + (wb->curr_bytes <=3D wb->non_pinned_min_bytes)) { + wb->pinned_curr_bytes =3D 0; + wb->pinned_used_bytes =3D 0; + + } else if (avail_bytes <=3D wb->pinned_max_bytes) { + wb->pinned_curr_bytes =3D avail_bytes; + wb->pinned_used_bytes =3D + MIN(wb->pinned_curr_bytes, wb->pinned_used_bytes); + + } else { + wb->pinned_curr_bytes =3D wb->pinned_max_bytes; + wb->pinned_used_bytes =3D + MIN(wb->pinned_curr_bytes, wb->pinned_used_bytes); + } + + ufs_wb_update_avail_buffer(u); +} + +static bool ufs_wb_max_fifo(UfsHc *u, uint32_t value) +{ + UfsWb *wb =3D &u->wb; + uint64_t fifo_max_bytes =3D ufs_unit_to_byte(u, value); + + if (fifo_max_bytes > wb->max_bytes) { + return false; + } + + u->attributes.max_fifo_wb_partial_flush_mode =3D cpu_to_be32(value); + wb->fifo_max_bytes =3D fifo_max_bytes; + ufs_wb_sync_buffer_size(u); + + return true; +} + +static bool ufs_wb_pinned_max_size(UfsHc *u, uint32_t value) +{ + UfsWb *wb =3D &u->wb; + uint64_t pinned_max_bytes =3D ufs_unit_to_byte(u, value); + + if (wb->max_bytes < wb->non_pinned_min_bytes + pinned_max_bytes) { + return false; + } + + u->attributes.pinned_wb_num_alloc_units =3D cpu_to_be32(value); + wb->pinned_max_bytes =3D pinned_max_bytes; + ufs_wb_sync_buffer_size(u); + + return true; +} + +static bool ufs_wb_pinned_min_size(UfsHc *u, uint32_t value) +{ + UfsWb *wb =3D &u->wb; + uint64_t non_pinned_min_bytes =3D ufs_unit_to_byte(u, value); + + if (wb->max_bytes < non_pinned_min_bytes + wb->pinned_max_bytes) { + return false; + } + + u->attributes.non_pinned_wb_min_num_alloc_units =3D cpu_to_be32(value); + wb->non_pinned_min_bytes =3D non_pinned_min_bytes; + ufs_wb_sync_buffer_size(u); + + return true; +} + static QueryRespCode ufs_write_attr_value(UfsHc *u, uint8_t idn, uint32_t = value) { switch (idn) { @@ -1452,6 +1640,34 @@ static QueryRespCode ufs_write_attr_value(UfsHc *u, = uint8_t idn, uint32_t value) case UFS_QUERY_ATTR_IDN_TIMESTAMP: u->attributes.timestamp =3D cpu_to_be64(value); break; + case UFS_QUERY_ATTR_IDN_WB_BUFF_RESIZE_EN: + if (value >=3D UFS_WB_RESIZE_OP_MAX) { + return UFS_QUERY_RESULT_INVALID_VALUE; + } + ufs_wb_resize_op(u, value); + break; + case UFS_QUERY_ATTR_IDN_WB_BUFF_PARTIAL_FLUSH_MODE: + if (value >=3D UFS_WB_FLUSH_MODE_MAX) { + return UFS_QUERY_RESULT_INVALID_VALUE; + } + u->attributes.wb_buffer_partial_flush_mode =3D value; + ufs_wb_sync_buffer_size(u); + break; + case UFS_QUERY_ATTR_IDN_MAX_FIFO_WB_PARTIAL_FLUSH_MODE: + if (!ufs_wb_max_fifo(u, value)) { + return UFS_QUERY_RESULT_INVALID_VALUE; + } + break; + case UFS_QUERY_ATTR_IDN_PINNED_WB_NUM_ALLOC_UNITS: + if (!ufs_wb_pinned_max_size(u, value)) { + return UFS_QUERY_RESULT_INVALID_VALUE; + } + break; + case UFS_QUERY_ATTR_IDN_NON_PINNED_WB_MIN_NUM_ALLOC_UNITS: + if (!ufs_wb_pinned_min_size(u, value)) { + return UFS_QUERY_RESULT_INVALID_VALUE; + } + break; default: g_assert_not_reached(); return 0; @@ -1870,10 +2086,136 @@ static void ufs_sendback_req(void *opaque) ufs_irq_check(u); } =20 +static inline uint64_t ufs_wb_total_flush_bytes(UfsHc *u) +{ + UfsWb *wb =3D &u->wb; + uint64_t no_flush_bytes; + + switch (u->attributes.wb_buffer_partial_flush_mode) { + case UFS_WB_FLUSH_NONE: + no_flush_bytes =3D 0; + break; + case UFS_WB_FLUSH_FIFO: + no_flush_bytes =3D wb->fifo_curr_bytes; + break; + case UFS_WB_FLUSH_PINNED: + no_flush_bytes =3D (u->flags.unpin_en) ? 0 : wb->pinned_used_bytes; + break; + default: + g_assert_not_reached(); + break; + } + + if (wb->used_bytes < no_flush_bytes) { + return 0; + } + + return wb->used_bytes - no_flush_bytes; +} + +#define UFS_WB_FLUSH_BYTES (4096 * 1024) +static void ufs_wb_process_flush(UfsHc *u) +{ + UfsWb *wb =3D &u->wb; + uint64_t flush_bytes, total_flush_bytes; + + switch (u->attributes.wb_buffer_flush_status) { + case UFS_WB_FLUSH_IDLE: + case UFS_WB_FLUSH_SUSPENDED: + if (!u->flags.wb_buffer_flush_en || !ufs_wb_total_flush_bytes(u)) { + break; + } + + u->attributes.wb_buffer_flush_status =3D UFS_WB_FLUSH_IN_PROGRESS; + /* fallthrough */ + case UFS_WB_FLUSH_IN_PROGRESS: + if (!u->flags.wb_buffer_flush_en) { + u->attributes.wb_buffer_flush_status =3D UFS_WB_FLUSH_SUSPENDE= D; + break; + } + + total_flush_bytes =3D ufs_wb_total_flush_bytes(u); + if (!total_flush_bytes) { + u->attributes.wb_buffer_flush_status =3D UFS_WB_FLUSH_COMPLETE= D; + break; + } + + /* Flush Pinned first */ + if (wb->pinned_used_bytes && u->flags.unpin_en) { + flush_bytes =3D MIN(wb->pinned_used_bytes, UFS_WB_FLUSH_BYTES); + wb->pinned_used_bytes -=3D flush_bytes; + wb->used_bytes -=3D flush_bytes; + } else { + flush_bytes =3D MIN(total_flush_bytes, UFS_WB_FLUSH_BYTES); + wb->used_bytes -=3D flush_bytes; + } + + u->attributes.wb_buffer_flush_status =3D UFS_WB_FLUSH_COMPLETED; + /* fallthrough */ + case UFS_WB_FLUSH_COMPLETED: + if (ufs_wb_total_flush_bytes(u)) { + u->attributes.wb_buffer_flush_status =3D + (u->flags.wb_buffer_flush_en) ? UFS_WB_FLUSH_IN_PROGRESS : + UFS_WB_FLUSH_IDLE; + } + } +} + +static void ufs_wb_process_resize(UfsHc *u) +{ + UfsWb *wb =3D &u->wb; + + if (u->attributes.wb_buffer_resize_status !=3D UFS_WB_RESIZE_IN_PROGRE= SS) { + return; + } + + switch (u->attributes.wb_buffer_resize_en) { + case UFS_WB_IDLE: + /* Do nothing. Complete resize directly. */ + break; + case UFS_WB_DECREASE: + if (wb->curr_bytes <=3D wb->min_bytes || + wb->curr_bytes <=3D wb->used_bytes) { + u->attributes.wb_buffer_resize_status =3D UFS_WB_RESIZE_FAILED; + return; + } + + if (wb->curr_bytes - wb->used_bytes >=3D wb->resize_bytes) { + wb->curr_bytes -=3D wb->resize_bytes; + } else { + wb->curr_bytes =3D wb->used_bytes; + } + + if (wb->curr_bytes < wb->min_bytes) { + wb->curr_bytes =3D wb->min_bytes; + } + + break; + case UFS_WB_INCREASE: + if (wb->curr_bytes >=3D wb->max_bytes) { + u->attributes.wb_buffer_resize_status =3D UFS_WB_RESIZE_FAILED; + return; + } + + wb->curr_bytes +=3D wb->resize_bytes; + if (wb->curr_bytes >=3D wb->max_bytes) { + wb->curr_bytes =3D wb->max_bytes; + } + + break; + default: + g_assert_not_reached(); + break; + } + + u->attributes.wb_buffer_resize_status =3D UFS_WB_RESIZE_COMPLETED; +} + static void ufs_process_idle(UfsHc *u) { - /* Currently do nothing */ - return; + ufs_wb_process_flush(u); + ufs_wb_process_resize(u); + ufs_wb_sync_buffer_size(u); } =20 static inline bool ufs_check_idle(UfsHc *u) @@ -1954,6 +2296,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 @@ -1992,11 +2339,53 @@ static void ufs_init_state(UfsHc *u) } } =20 +static void ufs_wb_init(UfsHc *u) +{ + UfsWb *wb =3D &u->wb; + uint32_t max_units =3D u->params.wb_max_size; + uint32_t min_units =3D u->params.wb_min_size; + + wb->max_bytes =3D ufs_unit_to_byte(u, max_units); + wb->min_bytes =3D ufs_unit_to_byte(u, min_units); + + wb->curr_bytes =3D wb->max_bytes; + wb->used_bytes =3D 0; + wb->resize_bytes =3D (wb->max_bytes - wb->min_bytes) / 10; + + u->attributes.wb_buffer_flush_status =3D UFS_WB_FLUSH_IDLE; + u->attributes.available_wb_buffer_size =3D 0xA; + u->attributes.wb_buffer_life_time_est =3D 0x1; + u->attributes.current_wb_buffer_size =3D cpu_to_be32(max_units); + + u->attributes.wb_buffer_resize_hint =3D UFS_WB_HINT_KEEP; + u->attributes.wb_buffer_resize_status =3D UFS_WB_RESIZE_IDLE; + + u->attributes.wb_buffer_partial_flush_mode =3D UFS_WB_FLUSH_NONE; + + u->attributes.max_fifo_wb_partial_flush_mode =3D cpu_to_be32(max_units= ); + u->attributes.curr_fifo_wb_partial_flush_mode =3D cpu_to_be32(max_unit= s); + + wb->fifo_max_bytes =3D ufs_unit_to_byte(u, max_units); + wb->fifo_curr_bytes =3D ufs_unit_to_byte(u, max_units); + + u->attributes.pinned_wb_num_alloc_units =3D cpu_to_be32(max_units); + u->attributes.non_pinned_wb_min_num_alloc_units =3D 0; + + wb->pinned_curr_bytes =3D 0; + wb->pinned_used_bytes =3D 0; + wb->pinned_max_bytes =3D ufs_unit_to_byte(u, max_units); + wb->non_pinned_min_bytes =3D 0; + wb->pinned_total_written_bytes =3D 0; +} + static void ufs_init_hc(UfsHc *u) { uint32_t cap =3D 0; uint32_t mcqconfig =3D 0; uint32_t mcqcap =3D 0; + uint32_t ext_wb_sup =3D WB_RESIZE | WB_FIFO | WB_PINNED; + uint32_t ext_ufs_feat_sup =3D + UFS_DEV_WB_SUPPORT | UFS_DEV_HIGH_TEMP_NOTIF | UFS_DEV_LOW_TEMP_NO= TIF; int64_t now =3D qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL_RT); =20 u->reg_size =3D pow2ceil(ufs_reg_size(u)); @@ -2058,8 +2447,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); @@ -2075,6 +2469,14 @@ static void ufs_init_hc(UfsHc *u) 0x0; /* out-of-order data transfer is not supported */ u->geometry_desc.max_context_id_number =3D 0x5; u->geometry_desc.supported_memory_types =3D cpu_to_be16(0x8001); + u->geometry_desc.write_booster_buffer_max_n_alloc_units =3D + cpu_to_be32(u->params.wb_max_size); + u->geometry_desc.device_max_write_booster_l_us =3D 0x1; + u->geometry_desc.write_booster_buffer_cap_adj_fac =3D 0x3; + u->geometry_desc.supported_write_booster_buffer_user_space_reduction_t= ypes =3D + 0x1; + u->geometry_desc.supported_write_booster_buffer_types =3D + 0x1; /* lu-dedicated buffer type is not supported */ =20 memset(&u->attributes, 0, sizeof(u->attributes)); u->attributes.max_data_in_size =3D 0x08; @@ -2089,6 +2491,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 @@ -2156,6 +2560,8 @@ static const Property ufs_props[] =3D { DEFINE_PROP_UINT8("nutmrs", UfsHc, params.nutmrs, 8), DEFINE_PROP_BOOL("mcq", UfsHc, params.mcq, false), DEFINE_PROP_UINT8("mcq-maxq", UfsHc, params.mcq_maxq, 2), + DEFINE_PROP_UINT32("wb-max-size", UfsHc, params.wb_max_size, 0x400), + DEFINE_PROP_UINT32("wb-min-size", UfsHc, params.wb_min_size, 0x100), }; =20 static const VMStateDescription ufs_vmstate =3D { diff --git a/hw/ufs/ufs.h b/hw/ufs/ufs.h index 64144b556a..8743501810 100644 --- a/hw/ufs/ufs.h +++ b/hw/ufs/ufs.h @@ -91,6 +91,8 @@ typedef struct UfsParams { bool mcq; /* Multiple Command Queue support */ uint8_t mcq_qcfgptr; /* MCQ Queue Configuration Pointer in MCQCAP */ uint8_t mcq_maxq; /* MCQ Maximum number of Queues */ + uint32_t wb_max_size; /* WB Maximum allocation units */ + uint32_t wb_min_size; /* WB Minimum allocation units */ } UfsParams; =20 /* @@ -118,6 +120,26 @@ typedef struct UfsCq { QTAILQ_HEAD(, UfsRequest) req_list; } UfsCq; =20 +/* + * Extended features + */ +typedef struct UfsWb { + uint64_t max_bytes; + uint64_t min_bytes; + uint64_t curr_bytes; + uint64_t used_bytes; + uint64_t resize_bytes; + + uint64_t fifo_max_bytes; + uint64_t fifo_curr_bytes; + + uint64_t pinned_max_bytes; + uint64_t non_pinned_min_bytes; + uint64_t pinned_curr_bytes; + uint64_t pinned_used_bytes; + uint64_t pinned_total_written_bytes; +} UfsWb; + typedef struct UfsHc { PCIDevice parent_obj; UfsBus bus; @@ -147,6 +169,9 @@ typedef struct UfsHc { UfsSq *sq[UFS_MAX_MCQ_QNUM]; UfsCq *cq[UFS_MAX_MCQ_QNUM]; =20 + /* Extended features */ + UfsWb wb; + uint8_t temperature; =20 QEMUTimer idle_timer; @@ -218,6 +243,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 @@ -250,5 +296,6 @@ void ufs_build_upiu_header(UfsRequest *req, uint8_t tra= ns_type, uint8_t flags, uint16_t data_segment_length); void ufs_build_query_response(UfsRequest *req); void ufs_complete_req(UfsRequest *req, UfsReqResult req_result); +void ufs_wb_update_avail_buffer(UfsHc *u); void ufs_init_wlu(UfsLu *wlu, uint8_t wlun); #endif /* HW_UFS_UFS_H */ diff --git a/include/block/ufs.h b/include/block/ufs.h index 4dacfb776f..0f7cc9c21b 100644 --- a/include/block/ufs.h +++ b/include/block/ufs.h @@ -1126,11 +1126,24 @@ enum health_desc_param { UFS_HEALTH_DESC_PARAM_LIFE_TIME_EST_B =3D 0x4, }; =20 +/* Possible values for bUFSFeaturesSupport */ enum { UFS_DEV_HIGH_TEMP_NOTIF =3D BIT(4), UFS_DEV_LOW_TEMP_NOTIF =3D BIT(5), }; =20 +/* Possible values for dExtendedWriteBoosterSupport */ +enum { + WB_RESIZE =3D BIT(0), + WB_FIFO =3D BIT(1), + WB_PINNED =3D BIT(2), +}; + +/* Possible values for dExtendedUFSFeaturesSupport */ +enum { + UFS_DEV_WB_SUPPORT =3D BIT(8), +}; + /* WriteBooster buffer mode */ enum { UFS_WB_BUF_MODE_LU_DEDICATED =3D 0x0, @@ -1153,6 +1166,9 @@ enum ufs_lu_wp_type { enum { MASK_EE_TOO_HIGH_TEMP =3D BIT(3), MASK_EE_TOO_LOW_TEMP =3D BIT(4), + MASK_EE_WB_FLUSH_NEEDED =3D BIT(5), + MASK_EE_WB_RESIZE_HINT =3D BIT(8), + MASK_EE_PINNED_WB_FULL =3D BIT(10), }; =20 /* UTP QUERY Transaction Specific Fields OpCode */ @@ -1207,6 +1223,45 @@ enum ufs_dev_pwr_mode { UFS_DEEPSLEEP_PWR_MODE =3D 4, }; =20 +/* UFS Write Booster */ +enum ufs_wb_flush_status { + UFS_WB_FLUSH_IDLE =3D 0, + UFS_WB_FLUSH_IN_PROGRESS =3D 1, + UFS_WB_FLUSH_SUSPENDED =3D 2, + UFS_WB_FLUSH_COMPLETED =3D 3, + UFS_WB_FLUSH_FAILED =3D 4, + UFS_WB_FLUSH_STATUS_MAX, +}; + +enum ufs_wb_flush_mode { + UFS_WB_FLUSH_NONE =3D 0, + UFS_WB_FLUSH_FIFO =3D 1, + UFS_WB_FLUSH_PINNED =3D 2, + UFS_WB_FLUSH_MODE_MAX, +}; + +enum ufs_wb_resize_hint { + UFS_WB_HINT_KEEP =3D 0, + UFS_WB_HINT_DECREASE =3D 1, + UFS_WB_HINT_INCREASE =3D 2, + UFS_WB_RESIZE_HINT_MAX, +}; + +enum ufs_wb_resize_op { + UFS_WB_IDLE =3D 0, + UFS_WB_DECREASE =3D 1, + UFS_WB_INCREASE =3D 2, + UFS_WB_RESIZE_OP_MAX, +}; + +enum ufs_wb_resize_status { + UFS_WB_RESIZE_IDLE =3D 0, + UFS_WB_RESIZE_IN_PROGRESS =3D 1, + UFS_WB_RESIZE_COMPLETED =3D 2, + UFS_WB_RESIZE_FAILED =3D 3, + UFS_WB_RESIZE_STATUS_MAX, +}; + /* * struct UtpCmdRsp - Response UPIU structure * @residual_transfer_count: Residual transfer count DW-3 --=20 2.43.0 From nobody Sat May 30 18:34:28 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=1779264088; cv=none; d=zohomail.com; s=zohoarc; b=ltUEUBmttpEBiTqgg8Fv147WRGzSC5BqREAFkhuxVReaZWtRwE9UWnp+yji6OoHjdybWVMNjbjvIv32XB+gbLI5mQkBVCRoq4P7FYT4lwo0mzxzGn0X3g/w5shvPU/oSs1AGlZoH3nJ0k6P7sKeve7vIQMRcJxg83NGq9VC0K7A= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1779264088; h=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=Q171zmzoZtyUjP/bzaCh8JzygW2pCZmah2r5hRqpdIM=; b=Nj9nUhlVY2nJsPD0n0XjaziIIMeHjmuEPXaa6Kr2Ty39kL4m17rOGzst64fIc55uToSF6McCyY9orhu2GREUNYVt0kyDU1lIIU9wH1JgjAxLlZnz7wQbZy9DlWLcgTPOcA5syUk4noqeoFnMsFVrcBfsIehmZxVxKYBNahSLYzM= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1779264088685491.64183814573016; Wed, 20 May 2026 01:01:28 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wPbrC-0003sh-En; Wed, 20 May 2026 04:00: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 1wPbqj-0003f5-5A for qemu-devel@nongnu.org; Wed, 20 May 2026 04:00:30 -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 1wPbqY-0004AM-TL for qemu-devel@nongnu.org; Wed, 20 May 2026 04:00:10 -0400 Received: by mail-pg1-x52a.google.com with SMTP id 41be03b00d2f7-c827313dac0so2444266a12.1 for ; Wed, 20 May 2026 01:00:01 -0700 (PDT) Received: from jeuk-MS-7D42.. ([211.226.54.223]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-2bd5c05ffbesm216608435ad.27.2026.05.20.00.59.57 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 20 May 2026 00:59:59 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1779264000; x=1779868800; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=Q171zmzoZtyUjP/bzaCh8JzygW2pCZmah2r5hRqpdIM=; b=F21tMMub6vD6bXeNGlt026U57nBi6bjHE6tddh4z+T4GQGMIDvFw33EoOBdbWtUsJ3 EOomwtX29yFYlUstD6WSgqLUjY4JrncYr290HruUqHK6JJkZyN7dM7fwnyVaDNrY0e9V J3tCsLRaj3SHu0oJbgBtN0p0FeAYTXRHOpLBrmXrFG3YRHvKRQIt2qVpQQ3no4SsAkZn 3w9MO4EDCLySd4909LEgvItIQvq3t69TY5fzqBdeDD5zEiQHCptesRyz/GxL9/fGBKJk 60oRFqRRIhlDwFFQiJE5MvrmEWdsujMn7WyXy9tLsZ/AdR1ZtyKWpL97LmcJa4H5NH9e xN7Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1779264000; x=1779868800; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=Q171zmzoZtyUjP/bzaCh8JzygW2pCZmah2r5hRqpdIM=; b=sSbm34xpJltLwCWzOSwxf2zNSRPGf1fL3voQIGYPla8P8ZNocPFd0jgbIQGiPljE7Q Oq0s9HjqNR7BH7BJfAOWe3lCbO2FCV0TRQqMNDICgVVHtoSRqSL0pu7zr0TWJ0IFQIQo 2vyHb47ZyxZc7O5/LbcsXyCZrnaTfXtAIj2SBSZDxGeai66B3FmMMI3CkXmensAqTm1a Z62tXSBuUPupeHmFKqQnYmKiOVt2K9PDhSgowQwWNW2TDIikaMdkTBCjMmi+XXXg0ova iQwXxzfEGqdZSz5QvJIv748+cERT73P6gERbJHzUubTrS3lqt3cjyBaFvYcn8SZi39hZ R87g== X-Gm-Message-State: AOJu0Yx6M80+lmBoRInx4iqXmTeVNmpqzDQo1sZW6+ziq9ewVe91MzLp Z7Y7PY/eJOGr8tH7rovGEq5MkyimkENMSZq/dudEj+NJnHBD6PaMXK6NkOez4Q== X-Gm-Gg: Acq92OGg/rKDt+MOWBgyZPgYkGmq/qhNziEu66BdJ7M8mZ9lT5DJ2NtA1IrD5wQg6Ar yFyEHy2ObgBfXTY+tTMHcLIamvx4kwY2omnpfg7M5y/QH3gzLvIm5A1DYU+MXlnuIf3mQ8E/XQ9 EwLXhy8RNUfI44xsFdFE0p93s7pWsnT8tUkR3ryhb56mwXNv1xiljHJ5iGXUrxbXuzofqDCJdBg 5ua96awhd8eixHNSN4V4hncgaz+ADNGY+MuAzuBJ1z2wPuhiRggdpA8HYsy3WsscQnSAAUEYFyc nEYYDvmESnTeZvnJ6f/p6RGnPR08Zq5KhwW9A8Fe90V3XWOyppSpptJbjeFNaGXYAsvSfDLEQSw 94ii6CMPitMzyn+mTeppqevNfkuLoyOInzxq2RGjTmTLLZuchGslDNT9qxWEqzeGIgtA4lGz4oc X67PUygRMgg9PoUkZOrwi6oChK+MBF X-Received: by 2002:a17:902:d509:b0:2b4:5bf8:a7e1 with SMTP id d9443c01a7336-2bd7e8288acmr207100325ad.6.1779263999848; Wed, 20 May 2026 00:59:59 -0700 (PDT) From: Jeuk Kim To: qemu-devel@nongnu.org, stefanha@redhat.com Cc: kwolf@redhat.com, hreitz@redhat.com, farosas@suse.de, lvivier@redhat.com, pbonzini@redhat.com, qemu-block@nongnu.org, jeuk20.kim@samsung.com, j-young.choi@samsung.com, jaemyung.lee@samsung.com, Jaemyung Lee Subject: [PULL 5/5] tests/qtest: Add UFS Write Booster QTest Date: Wed, 20 May 2026 16:59:31 +0900 Message-ID: X-Mailer: git-send-email 2.43.0 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=2607:f8b0:4864:20::52a; envelope-from=jeuk20.kim@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=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: 1779264089443158500 Content-Type: text/plain; charset="utf-8" From: Jaemyung Lee 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 Signed-off-by: Jeuk Kim --- tests/qtest/ufs-test.c | 177 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 177 insertions(+) diff --git a/tests/qtest/ufs-test.c b/tests/qtest/ufs-test.c index 7f99944155..f677896db0 100644 --- a/tests/qtest/ufs-test.c +++ b/tests/qtest/ufs-test.c @@ -1182,6 +1182,175 @@ static void ufstest_query_desc_request(void *obj, v= oid *data, ufs_exit(ufs, alloc); } =20 +static void ufstest_wb_init(void *obj, void *data, QGuestAllocator *alloc) +{ + QUfs *ufs =3D obj; + enum UtpOcsCodes ocs; + UtpUpiuRsp rsp_upiu; + uint8_t *desc; + uint32_t value; + + ufs_init(ufs, alloc); + + /* Read Device Descriptor */ + ocs =3D ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, + UFS_UPIU_QUERY_OPCODE_READ_DESC, + UFS_QUERY_DESC_IDN_DEVICE, 0, 0, 0, &rsp_upiu); + g_assert_cmpuint(ocs, =3D=3D, UFS_OCS_SUCCESS); + g_assert_cmpuint(rsp_upiu.header.response, =3D=3D, UFS_COMMAND_RESULT_= SUCCESS); + g_assert_cmpuint(rsp_upiu.qr.opcode, =3D=3D, UFS_UPIU_QUERY_OPCODE_REA= D_DESC); + g_assert_cmpuint(rsp_upiu.qr.idn, =3D=3D, UFS_QUERY_DESC_IDN_DEVICE); + g_assert_cmpuint(rsp_upiu.qr.data[0], =3D=3D, sizeof(DeviceDescriptor)= ); + g_assert_cmpuint(rsp_upiu.qr.data[1], =3D=3D, UFS_QUERY_DESC_IDN_DEVIC= E); + + /* Check Write Booster Supportability */ + desc =3D rsp_upiu.qr.data; + + value =3D lduw_be_p(desc + UFS_DEVICE_DESC_PARAM_EXT_WB_SUP); + g_assert_cmpuint(value, =3D=3D, WB_RESIZE | WB_FIFO | WB_PINNED); + + value =3D ldl_be_p(desc + UFS_DEVICE_DESC_PARAM_EXT_UFS_FEATURE_SUP); + g_assert_cmpuint(value & UFS_DEV_WB_SUPPORT, =3D=3D, UFS_DEV_WB_SUPPOR= T); + + /* Read Geometry Descriptor */ + ocs =3D ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, + UFS_UPIU_QUERY_OPCODE_READ_DESC, + UFS_QUERY_DESC_IDN_GEOMETRY, 0, 0, 0, &rsp_upiu); + g_assert_cmpuint(ocs, =3D=3D, UFS_OCS_SUCCESS); + g_assert_cmpuint(rsp_upiu.header.response, =3D=3D, UFS_COMMAND_RESULT_= SUCCESS); + g_assert_cmpuint(rsp_upiu.qr.data[0], =3D=3D, sizeof(GeometryDescripto= r)); + g_assert_cmpuint(rsp_upiu.qr.data[1], =3D=3D, UFS_QUERY_DESC_IDN_GEOME= TRY); + + /* Check Write Booster Configuration */ + desc =3D rsp_upiu.qr.data; + + value =3D ldl_be_p(desc + UFS_GEOMETRY_DESC_PARAM_WB_MAX_ALLOC_UNITS); + g_assert_cmpuint(value, =3D=3D, 1024); + + value =3D desc[UFS_GEOMETRY_DESC_PARAM_WB_MAX_WB_LUNS]; + g_assert_cmpuint(value, =3D=3D, 1); + + value =3D desc[UFS_GEOMETRY_DESC_PARAM_WB_BUFF_CAP_ADJ]; + g_assert_cmpuint(value, =3D=3D, 3); + + value =3D desc[UFS_GEOMETRY_DESC_PARAM_WB_SUP_RED_TYPE]; + g_assert_cmpuint(value, =3D=3D, 1); + + value =3D desc[UFS_GEOMETRY_DESC_PARAM_WB_SUP_WB_TYPE]; + g_assert_cmpuint(value, =3D=3D, 1); + + ufs_exit(ufs, alloc); +} + +static void ufstest_wb_read_write(void *obj, void *data, QGuestAllocator *= alloc) +{ + QUfs *ufs =3D obj; + uint8_t read_buf[4096] =3D { 0 }; + uint8_t write_buf[4096] =3D { 0 }; + const uint8_t read_capacity_cdb[UFS_CDB_SIZE] =3D { + /* allocation length 4096 */ + SERVICE_ACTION_IN_16, + SAI_READ_CAPACITY_16, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x10, + 0x00, + 0x00, + 0x00 + }; + const uint8_t request_sense_cdb[UFS_CDB_SIZE] =3D { + REQUEST_SENSE, + }; + const uint8_t write_cdb[UFS_CDB_SIZE] =3D { + /* WRITE(10) to LBA 0, transfer length 1 */ + WRITE_10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00 + }; + uint32_t block_size; + enum UtpOcsCodes ocs; + UtpUpiuRsp rsp_upiu; + const int test_lun =3D 1; + uint64_t end_time; + + ufs_init(ufs, alloc); + + /* Clear Unit Attention */ + ocs =3D ufs_send_scsi_command(ufs, test_lun, request_sense_cdb, NULL, = 0, + read_buf, sizeof(read_buf), &rsp_upiu); + g_assert_cmpuint(ocs, =3D=3D, UFS_OCS_SUCCESS); + g_assert_cmpuint(rsp_upiu.header.scsi_status, =3D=3D, CHECK_CONDITION); + + /* Read capacity */ + ocs =3D ufs_send_scsi_command(ufs, test_lun, read_capacity_cdb, NULL, = 0, + read_buf, sizeof(read_buf), &rsp_upiu); + g_assert_cmpuint(ocs, =3D=3D, UFS_OCS_SUCCESS); + g_assert_cmpuint(rsp_upiu.header.scsi_status, =3D=3D, + UFS_COMMAND_RESULT_SUCCESS); + block_size =3D ldl_be_p(&read_buf[8]); + g_assert_cmpuint(block_size, =3D=3D, 4096); + + /* Check available buffer size */ + ocs =3D ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, + UFS_UPIU_QUERY_OPCODE_READ_ATTR, + UFS_QUERY_ATTR_IDN_AVAIL_WB_BUFF_SIZE, 0, 0, 0, + &rsp_upiu); + g_assert_cmpuint(ocs, =3D=3D, UFS_OCS_SUCCESS); + g_assert_cmpuint(rsp_upiu.header.response, =3D=3D, UFS_COMMAND_RESULT_= SUCCESS); + g_assert_cmpuint(rsp_upiu.qr.opcode, =3D=3D, UFS_UPIU_QUERY_OPCODE_REA= D_ATTR); + g_assert_cmpuint(rsp_upiu.qr.idn, =3D=3D, + UFS_QUERY_ATTR_IDN_AVAIL_WB_BUFF_SIZE); + g_assert_cmpuint(rsp_upiu.qr.value, =3D=3D, cpu_to_be32(0xA)); + + /* Enable WB */ + ocs =3D ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST, + UFS_UPIU_QUERY_OPCODE_SET_FLAG, + UFS_QUERY_FLAG_IDN_WB_EN, 0, 0, 0, &rsp_upiu); + g_assert_cmpuint(ocs, =3D=3D, UFS_OCS_SUCCESS); + g_assert_cmpuint(rsp_upiu.header.response, =3D=3D, UFS_COMMAND_RESULT_= SUCCESS); + g_assert_cmpuint(rsp_upiu.qr.value, =3D=3D, be32_to_cpu(1)); + + /* Write data */ + for (int i =3D 0; i < 256; i++) { + memset(write_buf, 0xab, block_size); + ocs =3D ufs_send_scsi_command(ufs, test_lun, write_cdb, write_buf, + block_size, NULL, 0, &rsp_upiu); + g_assert_cmpuint(ocs, =3D=3D, UFS_OCS_SUCCESS); + g_assert_cmpuint(rsp_upiu.header.scsi_status, =3D=3D, + UFS_COMMAND_RESULT_SUCCESS); + } + + end_time =3D g_get_monotonic_time() + TIMEOUT_SECONDS * G_TIME_SPAN_SE= COND; + do { + qtest_clock_step(ufs->dev.bus->qts, 100); + + /* Check available buffer size */ + ocs =3D ufs_send_query(ufs, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQU= EST, + UFS_UPIU_QUERY_OPCODE_READ_ATTR, + UFS_QUERY_ATTR_IDN_AVAIL_WB_BUFF_SIZE, 0, 0, = 0, + &rsp_upiu); + g_assert_cmpuint(ocs, =3D=3D, UFS_OCS_SUCCESS); + g_assert_cmpuint(rsp_upiu.header.response, =3D=3D, + UFS_COMMAND_RESULT_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 +1403,12 @@ static void ufs_register_nodes(void) .edge.extra_device_opts =3D "mcq=3Dtrue,mcq-maxq=3D1" }; =20 + QOSGraphTestOptions wb_test_opts =3D { .before =3D ufs_blk_test_setup, + .edge.extra_device_opts =3D + "mcq=3Dfalse,nutrs=3D32,nutmr= s=3D8," + "wb-max-size=3D1024," + "wb-min-size=3D256" }; + add_qpci_address(&edge_opts, &(QPCIAddress){ .devfn =3D QPCI_DEVFN(4, = 0) }); =20 qos_node_create_driver("ufs", ufs_create); @@ -1262,6 +1437,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.43.0