@samitouri / QOSamiQemu / commits / f4958cb6e9

hw/ufs: Apply UFS 4.1 Specification

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 <jaemyung.lee@samsung.com> Signed-off-by: Jeuk Kim <jeuk20.kim@samsung.com>

Jaemyung Lee committed May 14, 2026 at 17:10 UTC f4958cb6e9187c182d75d5524594d23b97e3d13c
2 files changed +123 -6
hw/ufs/ufs.c
+67 -3
@@ -9,7 +9,7 @@
9 */
10
11 /**
12 - * Reference Specs: https://www.jedec.org/, 4.0
12 + * Reference Specs: https://www.jedec.org/, 4.1
13 *
14 * Usage
15 * -----
@@ -29,8 +29,8 @@
29 #include "trace.h"
30 #include "ufs.h"
31
32 -/* The QEMU-UFS device follows spec version 4.0 */
33 -#define UFS_SPEC_VER 0x0400
32 +/* The QEMU-UFS device follows spec version 4.1 */
33 +#define UFS_SPEC_VER 0x0410
34 #define UFS_MAX_NUTRS 32
35 #define UFS_MAX_NUTMRS 8
36 #define UFS_MCQ_QCFGPTR 2
@@ -1068,6 +1068,7 @@ static const int flag_permission[UFS_QUERY_FLAG_IDN_COUNT] = {
1068 [UFS_QUERY_FLAG_IDN_WB_EN] = UFS_QUERY_FLAG_READ,
1069 [UFS_QUERY_FLAG_IDN_WB_BUFF_FLUSH_EN] = UFS_QUERY_FLAG_READ,
1070 [UFS_QUERY_FLAG_IDN_WB_BUFF_FLUSH_DURING_HIBERN8] = UFS_QUERY_FLAG_READ,
1071 + [UFS_QUERY_FLAG_IDN_UNPIN_EN] = UFS_QUERY_FLAG_READ,
1072 };
1073
1074 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] = {
1126 [UFS_QUERY_ATTR_IDN_AVAIL_WB_BUFF_SIZE] = UFS_QUERY_ATTR_READ,
1127 [UFS_QUERY_ATTR_IDN_WB_BUFF_LIFE_TIME_EST] = UFS_QUERY_ATTR_READ,
1128 [UFS_QUERY_ATTR_IDN_CURR_WB_BUFF_SIZE] = UFS_QUERY_ATTR_READ,
1129 + [UFS_QUERY_ATTR_IDN_EXT_IID_EN] = UFS_QUERY_ATTR_READ,
1130 + [UFS_QUERY_ATTR_IDN_HOST_HINT_CACHE_SIZE] = UFS_QUERY_ATTR_READ,
1131 /* refresh operation is not supported */
1132 [UFS_QUERY_ATTR_IDN_REFRESH_STATUS] = UFS_QUERY_ATTR_READ,
1133 [UFS_QUERY_ATTR_IDN_REFRESH_FREQ] = UFS_QUERY_ATTR_READ,
1134 [UFS_QUERY_ATTR_IDN_REFRESH_UNIT] = UFS_QUERY_ATTR_READ,
1135 + [UFS_QUERY_ATTR_IDN_TIMESTAMP] = UFS_QUERY_ATTR_WRITE,
1136 + [UFS_QUERY_ATTR_IDN_DEVICE_LEVEL_EXCEPTION_ID] = UFS_QUERY_ATTR_READ,
1137 + /* host initiated defragmentation is not supported */
1138 + [UFS_QUERY_ATTR_IDN_DEFRAG_OP] = UFS_QUERY_ATTR_READ,
1139 + [UFS_QUERY_ATTR_IDN_HID_AVAIL_SIZE] = UFS_QUERY_ATTR_READ,
1140 + [UFS_QUERY_ATTR_IDN_HID_SIZE] = UFS_QUERY_ATTR_READ,
1141 + [UFS_QUERY_ATTR_IDN_HID_PROG_RATIO] = UFS_QUERY_ATTR_READ,
1142 + [UFS_QUERY_ATTR_IDN_HID_STATE] = UFS_QUERY_ATTR_READ,
1143 + [UFS_QUERY_ATTR_IDN_WB_BUFF_RESIZE_HINT] = UFS_QUERY_ATTR_READ,
1144 + [UFS_QUERY_ATTR_IDN_WB_BUFF_RESIZE_EN] = UFS_QUERY_ATTR_READ,
1145 + [UFS_QUERY_ATTR_IDN_WB_BUFF_RESIZE_STATUS] = UFS_QUERY_ATTR_READ,
1146 + [UFS_QUERY_ATTR_IDN_WB_BUFF_PARTIAL_FLUSH_MODE] = UFS_QUERY_ATTR_READ,
1147 + [UFS_QUERY_ATTR_IDN_MAX_FIFO_WB_PARTIAL_FLUSH_MODE] = UFS_QUERY_ATTR_READ,
1148 + [UFS_QUERY_ATTR_IDN_CURR_FIFO_WB_PARTIAL_FLUSH_MODE] = UFS_QUERY_ATTR_READ,
1149 + [UFS_QUERY_ATTR_IDN_PINNED_WB_BUFF_CURR_ALLOC_UNITS] = UFS_QUERY_ATTR_READ,
1150 + [UFS_QUERY_ATTR_IDN_PINNED_WB_BUFF_AVAIL_PERCENT] = UFS_QUERY_ATTR_READ,
1151 + [UFS_QUERY_ATTR_IDN_PINNED_WB_CUMM_WRITTEN_SIZE] = UFS_QUERY_ATTR_READ,
1152 + [UFS_QUERY_ATTR_IDN_PINNED_WB_NUM_ALLOC_UNITS] = UFS_QUERY_ATTR_READ,
1153 + [UFS_QUERY_ATTR_IDN_NON_PINNED_WB_MIN_NUM_ALLOC_UNITS] =
1154 + UFS_QUERY_ATTR_READ,
1155 };
1156
1157 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)
1285 return u->attributes.wb_buffer_life_time_est;
1286 case UFS_QUERY_ATTR_IDN_CURR_WB_BUFF_SIZE:
1287 return be32_to_cpu(u->attributes.current_wb_buffer_size);
1288 + case UFS_QUERY_ATTR_IDN_EXT_IID_EN:
1289 + return u->attributes.ext_iid_en;
1290 + case UFS_QUERY_ATTR_IDN_HOST_HINT_CACHE_SIZE:
1291 + return be16_to_cpu(u->attributes.host_hint_cache_size);
1292 case UFS_QUERY_ATTR_IDN_REFRESH_STATUS:
1293 return u->attributes.refresh_status;
1294 case UFS_QUERY_ATTR_IDN_REFRESH_FREQ:
1295 return u->attributes.refresh_freq;
1296 case UFS_QUERY_ATTR_IDN_REFRESH_UNIT:
1297 return u->attributes.refresh_unit;
1298 + case UFS_QUERY_ATTR_IDN_DEVICE_LEVEL_EXCEPTION_ID:
1299 + return be64_to_cpu(u->attributes.device_level_exception_id);
1300 + case UFS_QUERY_ATTR_IDN_DEFRAG_OP:
1301 + return u->attributes.defrag_op;
1302 + case UFS_QUERY_ATTR_IDN_HID_AVAIL_SIZE:
1303 + return be32_to_cpu(u->attributes.hid_avail_size);
1304 + case UFS_QUERY_ATTR_IDN_HID_SIZE:
1305 + return be32_to_cpu(u->attributes.hid_size);
1306 + case UFS_QUERY_ATTR_IDN_HID_PROG_RATIO:
1307 + return u->attributes.hid_prog_ratio;
1308 + case UFS_QUERY_ATTR_IDN_HID_STATE:
1309 + return u->attributes.hid_state;
1310 + case UFS_QUERY_ATTR_IDN_WB_BUFF_RESIZE_HINT:
1311 + return u->attributes.wb_buffer_resize_hint;
1312 + case UFS_QUERY_ATTR_IDN_WB_BUFF_RESIZE_EN:
1313 + return u->attributes.wb_buffer_resize_en;
1314 + case UFS_QUERY_ATTR_IDN_WB_BUFF_RESIZE_STATUS:
1315 + return u->attributes.wb_buffer_resize_status;
1316 + case UFS_QUERY_ATTR_IDN_WB_BUFF_PARTIAL_FLUSH_MODE:
1317 + return u->attributes.wb_buffer_partial_flush_mode;
1318 + case UFS_QUERY_ATTR_IDN_MAX_FIFO_WB_PARTIAL_FLUSH_MODE:
1319 + return be32_to_cpu(u->attributes.max_fifo_wb_partial_flush_mode);
1320 + case UFS_QUERY_ATTR_IDN_CURR_FIFO_WB_PARTIAL_FLUSH_MODE:
1321 + return be32_to_cpu(u->attributes.curr_fifo_wb_partial_flush_mode);
1322 + case UFS_QUERY_ATTR_IDN_PINNED_WB_BUFF_CURR_ALLOC_UNITS:
1323 + return be32_to_cpu(u->attributes.pinned_wb_buffer_curr_alloc_units);
1324 + case UFS_QUERY_ATTR_IDN_PINNED_WB_BUFF_AVAIL_PERCENT:
1325 + return u->attributes.pinned_wb_buffer_avail_percent;
1326 + case UFS_QUERY_ATTR_IDN_PINNED_WB_CUMM_WRITTEN_SIZE:
1327 + return be32_to_cpu(u->attributes.pinned_wb_cumm_written_size);
1328 + case UFS_QUERY_ATTR_IDN_PINNED_WB_NUM_ALLOC_UNITS:
1329 + return be32_to_cpu(u->attributes.pinned_wb_num_alloc_units);
1330 + case UFS_QUERY_ATTR_IDN_NON_PINNED_WB_MIN_NUM_ALLOC_UNITS:
1331 + return be32_to_cpu(u->attributes.non_pinned_wb_min_num_alloc_units);
1332 }
1333 return 0;
1334 }
@@ -1305,6 +1366,9 @@ static QueryRespCode ufs_write_attr_value(UfsHc *u, uint8_t idn, uint32_t value)
1366 case UFS_QUERY_ATTR_IDN_PSA_DATA_SIZE:
1367 u->attributes.psa_data_size = cpu_to_be32(value);
1368 break;
1369 + case UFS_QUERY_ATTR_IDN_TIMESTAMP:
1370 + u->attributes.timestamp = cpu_to_be64(value);
1371 + break;
1372 }
1373 return UFS_QUERY_RESULT_SUCCESS;
1374 }
include/block/ufs.h
+56 -3
@@ -294,7 +294,8 @@ typedef struct QEMU_PACKED DeviceDescriptor {
294 uint32_t psa_max_data_size;
295 uint8_t psa_state_timeout;
296 uint8_t product_revision_level;
297 - uint8_t reserved[36];
297 + uint8_t reserved[34];
298 + uint16_t extended_wb_support;
299 uint32_t extended_ufs_features_support;
300 uint8_t write_booster_buffer_preserve_user_space_en;
301 uint8_t write_booster_buffer_type;
@@ -342,6 +343,8 @@ typedef struct QEMU_PACKED GeometryDescriptor {
343 uint8_t write_booster_buffer_cap_adj_fac;
344 uint8_t supported_write_booster_buffer_user_space_reduction_types;
345 uint8_t supported_write_booster_buffer_types;
346 + uint8_t reserved3[17];
347 + uint8_t cap_adj_fac_representation;
348 } GeometryDescriptor;
349
350 #define UFS_GEOMETRY_CAPACITY_SHIFT 9
@@ -437,6 +440,8 @@ typedef struct QEMU_PACKED Flags {
440 uint8_t wb_buffer_flush_en;
441 uint8_t wb_buffer_flush_during_hibernate;
442 uint8_t reserved4[2];
443 + uint8_t unpin_en;
444 + uint8_t reserved5[235];
445 } Flags;
446
447 typedef struct Attributes {
@@ -457,6 +462,8 @@ typedef struct Attributes {
462 uint16_t exception_event_status;
463 uint32_t seconds_passed;
464 uint16_t context_conf;
465 + uint8_t obsolete;
466 + uint8_t reserved2[2];
467 uint8_t device_ffu_status;
468 uint8_t psa_state;
469 uint32_t psa_data_size;
@@ -469,10 +476,34 @@ typedef struct Attributes {
476 uint8_t available_wb_buffer_size;
477 uint8_t wb_buffer_life_time_est;
478 uint32_t current_wb_buffer_size;
479 + uint8_t reserved3[10];
480 + uint8_t ext_iid_en;
481 + uint16_t host_hint_cache_size;
482 uint8_t refresh_status;
483 uint8_t refresh_freq;
484 uint8_t refresh_unit;
485 uint8_t refresh_method;
486 + uint64_t timestamp;
487 + uint8_t reserved4[3];
488 + uint64_t device_level_exception_id;
489 + uint8_t defrag_op;
490 + uint32_t hid_avail_size;
491 + uint32_t hid_size;
492 + uint8_t hid_prog_ratio;
493 + uint8_t hid_state;
494 + uint8_t reserved5[2];
495 + uint8_t wb_buffer_resize_hint;
496 + uint8_t wb_buffer_resize_en;
497 + uint8_t wb_buffer_resize_status;
498 + uint8_t wb_buffer_partial_flush_mode;
499 + uint32_t max_fifo_wb_partial_flush_mode;
500 + uint32_t curr_fifo_wb_partial_flush_mode;
501 + uint32_t pinned_wb_buffer_curr_alloc_units;
502 + uint8_t pinned_wb_buffer_avail_percent;
503 + uint32_t pinned_wb_cumm_written_size;
504 + uint32_t pinned_wb_num_alloc_units;
505 + uint32_t non_pinned_wb_min_num_alloc_units;
506 + uint8_t reserved6[184];
507 } Attributes;
508
509 #define UFS_TRANSACTION_SPECIFIC_FIELD_SIZE 20
@@ -856,6 +887,7 @@ enum flag_idn {
887 UFS_QUERY_FLAG_IDN_WB_BUFF_FLUSH_DURING_HIBERN8 = 0x10,
888 UFS_QUERY_FLAG_IDN_HPB_RESET = 0x11,
889 UFS_QUERY_FLAG_IDN_HPB_EN = 0x12,
890 + UFS_QUERY_FLAG_IDN_UNPIN_EN = 0x13,
891 UFS_QUERY_FLAG_IDN_COUNT,
892 };
893
@@ -893,9 +925,29 @@ enum attr_idn {
925 UFS_QUERY_ATTR_IDN_AVAIL_WB_BUFF_SIZE = 0x1D,
926 UFS_QUERY_ATTR_IDN_WB_BUFF_LIFE_TIME_EST = 0x1E,
927 UFS_QUERY_ATTR_IDN_CURR_WB_BUFF_SIZE = 0x1F,
928 + UFS_QUERY_ATTR_IDN_EXT_IID_EN = 0x2A,
929 + UFS_QUERY_ATTR_IDN_HOST_HINT_CACHE_SIZE = 0x2B,
930 UFS_QUERY_ATTR_IDN_REFRESH_STATUS = 0x2C,
931 UFS_QUERY_ATTR_IDN_REFRESH_FREQ = 0x2D,
932 UFS_QUERY_ATTR_IDN_REFRESH_UNIT = 0x2E,
933 + UFS_QUERY_ATTR_IDN_TIMESTAMP = 0x30,
934 + UFS_QUERY_ATTR_IDN_DEVICE_LEVEL_EXCEPTION_ID = 0x34,
935 + UFS_QUERY_ATTR_IDN_DEFRAG_OP = 0x35,
936 + UFS_QUERY_ATTR_IDN_HID_AVAIL_SIZE = 0x36,
937 + UFS_QUERY_ATTR_IDN_HID_SIZE = 0x37,
938 + UFS_QUERY_ATTR_IDN_HID_PROG_RATIO = 0x38,
939 + UFS_QUERY_ATTR_IDN_HID_STATE = 0x39,
940 + UFS_QUERY_ATTR_IDN_WB_BUFF_RESIZE_HINT = 0x3C,
941 + UFS_QUERY_ATTR_IDN_WB_BUFF_RESIZE_EN = 0x3D,
942 + UFS_QUERY_ATTR_IDN_WB_BUFF_RESIZE_STATUS = 0x3E,
943 + UFS_QUERY_ATTR_IDN_WB_BUFF_PARTIAL_FLUSH_MODE = 0x3F,
944 + UFS_QUERY_ATTR_IDN_MAX_FIFO_WB_PARTIAL_FLUSH_MODE = 0x40,
945 + UFS_QUERY_ATTR_IDN_CURR_FIFO_WB_PARTIAL_FLUSH_MODE = 0x41,
946 + UFS_QUERY_ATTR_IDN_PINNED_WB_BUFF_CURR_ALLOC_UNITS = 0x42,
947 + UFS_QUERY_ATTR_IDN_PINNED_WB_BUFF_AVAIL_PERCENT = 0x43,
948 + UFS_QUERY_ATTR_IDN_PINNED_WB_CUMM_WRITTEN_SIZE = 0x44,
949 + UFS_QUERY_ATTR_IDN_PINNED_WB_NUM_ALLOC_UNITS = 0x45,
950 + UFS_QUERY_ATTR_IDN_NON_PINNED_WB_MIN_NUM_ALLOC_UNITS = 0x46,
951 UFS_QUERY_ATTR_IDN_COUNT,
952 };
953
@@ -1005,6 +1057,7 @@ enum device_desc_param {
1057 UFS_DEVICE_DESC_PARAM_PRDCT_REV = 0x2A,
1058 UFS_DEVICE_DESC_PARAM_HPB_VER = 0x40,
1059 UFS_DEVICE_DESC_PARAM_HPB_CONTROL = 0x42,
1060 + UFS_DEVICE_DESC_PARAM_EXT_WB_SUP = 0x4D,
1061 UFS_DEVICE_DESC_PARAM_EXT_UFS_FEATURE_SUP = 0x4F,
1062 UFS_DEVICE_DESC_PARAM_WB_PRESRV_USRSPC_EN = 0x53,
1063 UFS_DEVICE_DESC_PARAM_WB_TYPE = 0x54,
@@ -1208,14 +1261,14 @@ static inline void _ufs_check_size(void)
1261 QEMU_BUILD_BUG_ON(sizeof(UfsMcqCqIntReg) != 12);
1262 QEMU_BUILD_BUG_ON(sizeof(UfsMcqOpReg) != 48);
1263 QEMU_BUILD_BUG_ON(sizeof(DeviceDescriptor) != 89);
1211 - QEMU_BUILD_BUG_ON(sizeof(GeometryDescriptor) != 87);
1264 + QEMU_BUILD_BUG_ON(sizeof(GeometryDescriptor) != 105);
1265 QEMU_BUILD_BUG_ON(sizeof(UnitDescriptor) != 45);
1266 QEMU_BUILD_BUG_ON(sizeof(RpmbUnitDescriptor) != 35);
1267 QEMU_BUILD_BUG_ON(sizeof(PowerParametersDescriptor) != 98);
1268 QEMU_BUILD_BUG_ON(sizeof(InterconnectDescriptor) != 6);
1269 QEMU_BUILD_BUG_ON(sizeof(StringDescriptor) != 254);
1270 QEMU_BUILD_BUG_ON(sizeof(DeviceHealthDescriptor) != 45);
1218 - QEMU_BUILD_BUG_ON(sizeof(Flags) != 0x13);
1271 + QEMU_BUILD_BUG_ON(sizeof(Flags) != 0xFF);
1272 QEMU_BUILD_BUG_ON(sizeof(UtpUpiuHeader) != 12);
1273 QEMU_BUILD_BUG_ON(sizeof(UtpUpiuQuery) != 276);
1274 QEMU_BUILD_BUG_ON(sizeof(UtpUpiuCmd) != 20);