From: Jaemyung Lee <[email protected]> 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 <[email protected]> Signed-off-by: Jeuk Kim <[email protected]> --- 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 @@ */ /** - * 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" -/* 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_COUNT] = { [UFS_QUERY_FLAG_IDN_WB_EN] = UFS_QUERY_FLAG_READ, [UFS_QUERY_FLAG_IDN_WB_BUFF_FLUSH_EN] = UFS_QUERY_FLAG_READ, [UFS_QUERY_FLAG_IDN_WB_BUFF_FLUSH_DURING_HIBERN8] = UFS_QUERY_FLAG_READ, + [UFS_QUERY_FLAG_IDN_UNPIN_EN] = UFS_QUERY_FLAG_READ, }; 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] = { [UFS_QUERY_ATTR_IDN_AVAIL_WB_BUFF_SIZE] = UFS_QUERY_ATTR_READ, [UFS_QUERY_ATTR_IDN_WB_BUFF_LIFE_TIME_EST] = UFS_QUERY_ATTR_READ, [UFS_QUERY_ATTR_IDN_CURR_WB_BUFF_SIZE] = UFS_QUERY_ATTR_READ, + [UFS_QUERY_ATTR_IDN_EXT_IID_EN] = UFS_QUERY_ATTR_READ, + [UFS_QUERY_ATTR_IDN_HOST_HINT_CACHE_SIZE] = UFS_QUERY_ATTR_READ, /* refresh operation is not supported */ [UFS_QUERY_ATTR_IDN_REFRESH_STATUS] = UFS_QUERY_ATTR_READ, [UFS_QUERY_ATTR_IDN_REFRESH_FREQ] = UFS_QUERY_ATTR_READ, [UFS_QUERY_ATTR_IDN_REFRESH_UNIT] = UFS_QUERY_ATTR_READ, + [UFS_QUERY_ATTR_IDN_TIMESTAMP] = UFS_QUERY_ATTR_WRITE, + [UFS_QUERY_ATTR_IDN_DEVICE_LEVEL_EXCEPTION_ID] = UFS_QUERY_ATTR_READ, + /* host initiated defragmentation is not supported */ + [UFS_QUERY_ATTR_IDN_DEFRAG_OP] = UFS_QUERY_ATTR_READ, + [UFS_QUERY_ATTR_IDN_HID_AVAIL_SIZE] = UFS_QUERY_ATTR_READ, + [UFS_QUERY_ATTR_IDN_HID_SIZE] = UFS_QUERY_ATTR_READ, + [UFS_QUERY_ATTR_IDN_HID_PROG_RATIO] = UFS_QUERY_ATTR_READ, + [UFS_QUERY_ATTR_IDN_HID_STATE] = UFS_QUERY_ATTR_READ, + [UFS_QUERY_ATTR_IDN_WB_BUFF_RESIZE_HINT] = UFS_QUERY_ATTR_READ, + [UFS_QUERY_ATTR_IDN_WB_BUFF_RESIZE_EN] = UFS_QUERY_ATTR_READ, + [UFS_QUERY_ATTR_IDN_WB_BUFF_RESIZE_STATUS] = UFS_QUERY_ATTR_READ, + [UFS_QUERY_ATTR_IDN_WB_BUFF_PARTIAL_FLUSH_MODE] = UFS_QUERY_ATTR_READ, + [UFS_QUERY_ATTR_IDN_MAX_FIFO_WB_PARTIAL_FLUSH_MODE] = UFS_QUERY_ATTR_READ, + [UFS_QUERY_ATTR_IDN_CURR_FIFO_WB_PARTIAL_FLUSH_MODE] = UFS_QUERY_ATTR_READ, + [UFS_QUERY_ATTR_IDN_PINNED_WB_BUFF_CURR_ALLOC_UNITS] = UFS_QUERY_ATTR_READ, + [UFS_QUERY_ATTR_IDN_PINNED_WB_BUFF_AVAIL_PERCENT] = UFS_QUERY_ATTR_READ, + [UFS_QUERY_ATTR_IDN_PINNED_WB_CUMM_WRITTEN_SIZE] = UFS_QUERY_ATTR_READ, + [UFS_QUERY_ATTR_IDN_PINNED_WB_NUM_ALLOC_UNITS] = UFS_QUERY_ATTR_READ, + [UFS_QUERY_ATTR_IDN_NON_PINNED_WB_MIN_NUM_ALLOC_UNITS] = + UFS_QUERY_ATTR_READ, }; 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, uint8_t idn, uint32_t value) case UFS_QUERY_ATTR_IDN_PSA_DATA_SIZE: u->attributes.psa_data_size = cpu_to_be32(value); break; + case UFS_QUERY_ATTR_IDN_TIMESTAMP: + u->attributes.timestamp = 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; #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; 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; #define UFS_TRANSACTION_SPECIFIC_FIELD_SIZE 20 @@ -856,6 +887,7 @@ enum flag_idn { UFS_QUERY_FLAG_IDN_WB_BUFF_FLUSH_DURING_HIBERN8 = 0x10, UFS_QUERY_FLAG_IDN_HPB_RESET = 0x11, UFS_QUERY_FLAG_IDN_HPB_EN = 0x12, + UFS_QUERY_FLAG_IDN_UNPIN_EN = 0x13, UFS_QUERY_FLAG_IDN_COUNT, }; @@ -893,9 +925,29 @@ enum attr_idn { UFS_QUERY_ATTR_IDN_AVAIL_WB_BUFF_SIZE = 0x1D, UFS_QUERY_ATTR_IDN_WB_BUFF_LIFE_TIME_EST = 0x1E, UFS_QUERY_ATTR_IDN_CURR_WB_BUFF_SIZE = 0x1F, + UFS_QUERY_ATTR_IDN_EXT_IID_EN = 0x2A, + UFS_QUERY_ATTR_IDN_HOST_HINT_CACHE_SIZE = 0x2B, UFS_QUERY_ATTR_IDN_REFRESH_STATUS = 0x2C, UFS_QUERY_ATTR_IDN_REFRESH_FREQ = 0x2D, UFS_QUERY_ATTR_IDN_REFRESH_UNIT = 0x2E, + UFS_QUERY_ATTR_IDN_TIMESTAMP = 0x30, + UFS_QUERY_ATTR_IDN_DEVICE_LEVEL_EXCEPTION_ID = 0x34, + UFS_QUERY_ATTR_IDN_DEFRAG_OP = 0x35, + UFS_QUERY_ATTR_IDN_HID_AVAIL_SIZE = 0x36, + UFS_QUERY_ATTR_IDN_HID_SIZE = 0x37, + UFS_QUERY_ATTR_IDN_HID_PROG_RATIO = 0x38, + UFS_QUERY_ATTR_IDN_HID_STATE = 0x39, + UFS_QUERY_ATTR_IDN_WB_BUFF_RESIZE_HINT = 0x3C, + UFS_QUERY_ATTR_IDN_WB_BUFF_RESIZE_EN = 0x3D, + UFS_QUERY_ATTR_IDN_WB_BUFF_RESIZE_STATUS = 0x3E, + UFS_QUERY_ATTR_IDN_WB_BUFF_PARTIAL_FLUSH_MODE = 0x3F, + UFS_QUERY_ATTR_IDN_MAX_FIFO_WB_PARTIAL_FLUSH_MODE = 0x40, + UFS_QUERY_ATTR_IDN_CURR_FIFO_WB_PARTIAL_FLUSH_MODE = 0x41, + UFS_QUERY_ATTR_IDN_PINNED_WB_BUFF_CURR_ALLOC_UNITS = 0x42, + UFS_QUERY_ATTR_IDN_PINNED_WB_BUFF_AVAIL_PERCENT = 0x43, + UFS_QUERY_ATTR_IDN_PINNED_WB_CUMM_WRITTEN_SIZE = 0x44, + UFS_QUERY_ATTR_IDN_PINNED_WB_NUM_ALLOC_UNITS = 0x45, + UFS_QUERY_ATTR_IDN_NON_PINNED_WB_MIN_NUM_ALLOC_UNITS = 0x46, UFS_QUERY_ATTR_IDN_COUNT, }; @@ -1005,6 +1057,7 @@ enum device_desc_param { UFS_DEVICE_DESC_PARAM_PRDCT_REV = 0x2A, UFS_DEVICE_DESC_PARAM_HPB_VER = 0x40, UFS_DEVICE_DESC_PARAM_HPB_CONTROL = 0x42, + UFS_DEVICE_DESC_PARAM_EXT_WB_SUP = 0x4D, UFS_DEVICE_DESC_PARAM_EXT_UFS_FEATURE_SUP = 0x4F, UFS_DEVICE_DESC_PARAM_WB_PRESRV_USRSPC_EN = 0x53, UFS_DEVICE_DESC_PARAM_WB_TYPE = 0x54, @@ -1208,14 +1261,14 @@ static inline void _ufs_check_size(void) QEMU_BUILD_BUG_ON(sizeof(UfsMcqCqIntReg) != 12); QEMU_BUILD_BUG_ON(sizeof(UfsMcqOpReg) != 48); QEMU_BUILD_BUG_ON(sizeof(DeviceDescriptor) != 89); - QEMU_BUILD_BUG_ON(sizeof(GeometryDescriptor) != 87); + QEMU_BUILD_BUG_ON(sizeof(GeometryDescriptor) != 105); QEMU_BUILD_BUG_ON(sizeof(UnitDescriptor) != 45); QEMU_BUILD_BUG_ON(sizeof(RpmbUnitDescriptor) != 35); QEMU_BUILD_BUG_ON(sizeof(PowerParametersDescriptor) != 98); QEMU_BUILD_BUG_ON(sizeof(InterconnectDescriptor) != 6); QEMU_BUILD_BUG_ON(sizeof(StringDescriptor) != 254); QEMU_BUILD_BUG_ON(sizeof(DeviceHealthDescriptor) != 45); - QEMU_BUILD_BUG_ON(sizeof(Flags) != 0x13); + QEMU_BUILD_BUG_ON(sizeof(Flags) != 0xFF); QEMU_BUILD_BUG_ON(sizeof(UtpUpiuHeader) != 12); QEMU_BUILD_BUG_ON(sizeof(UtpUpiuQuery) != 276); QEMU_BUILD_BUG_ON(sizeof(UtpUpiuCmd) != 20); -- 2.43.0
