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);