aboutsummaryrefslogtreecommitdiff
path: root/hw/ufs
diff options
context:
space:
mode:
Diffstat (limited to 'hw/ufs')
-rw-r--r--hw/ufs/lu.c9
-rw-r--r--hw/ufs/ufs.c98
-rw-r--r--hw/ufs/ufs.h2
3 files changed, 94 insertions, 15 deletions
diff --git a/hw/ufs/lu.c b/hw/ufs/lu.c
index 81bfff9..2d8ffd7 100644
--- a/hw/ufs/lu.c
+++ b/hw/ufs/lu.c
@@ -14,7 +14,7 @@
#include "qemu/memalign.h"
#include "hw/scsi/scsi.h"
#include "scsi/constants.h"
-#include "sysemu/block-backend.h"
+#include "system/block-backend.h"
#include "qemu/cutils.h"
#include "trace.h"
#include "ufs.h"
@@ -194,7 +194,7 @@ static int ufs_emulate_wlun_inquiry(UfsRequest *req, uint8_t *outbuf,
static UfsReqResult ufs_emulate_scsi_cmd(UfsLu *lu, UfsRequest *req)
{
uint8_t lun = lu->lun;
- uint8_t outbuf[4096];
+ QEMU_UNINITIALIZED uint8_t outbuf[4096];
uint8_t sense_buf[UFS_SENSE_SIZE];
uint8_t scsi_status;
int len = 0;
@@ -274,10 +274,9 @@ static UfsReqResult ufs_process_scsi_cmd(UfsLu *lu, UfsRequest *req)
return UFS_REQUEST_NO_COMPLETE;
}
-static Property ufs_lu_props[] = {
+static const Property ufs_lu_props[] = {
DEFINE_PROP_DRIVE("drive", UfsLu, conf.blk),
DEFINE_PROP_UINT8("lun", UfsLu, lun, 0),
- DEFINE_PROP_END_OF_LIST(),
};
static bool ufs_add_lu(UfsHc *u, UfsLu *lu, Error **errp)
@@ -420,7 +419,7 @@ static void ufs_lu_unrealize(DeviceState *dev)
}
}
-static void ufs_lu_class_init(ObjectClass *oc, void *data)
+static void ufs_lu_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
diff --git a/hw/ufs/ufs.c b/hw/ufs/ufs.c
index 79f786e..0577747 100644
--- a/hw/ufs/ufs.c
+++ b/hw/ufs/ufs.c
@@ -25,6 +25,7 @@
#include "qapi/error.h"
#include "migration/vmstate.h"
#include "scsi/constants.h"
+#include "hw/irq.h"
#include "trace.h"
#include "ufs.h"
@@ -34,6 +35,11 @@
#define UFS_MAX_NUTMRS 8
#define UFS_MCQ_QCFGPTR 2
+/* Each value represents the temperature in celsius as (value - 80) */
+#define UFS_TEMPERATURE 120
+#define UFS_TOO_HIGH_TEMP_BOUNDARY 160
+#define UFS_TOO_LOW_TEMP_BOUNDARY 60
+
static void ufs_exec_req(UfsRequest *req);
static void ufs_clear_req(UfsRequest *req);
@@ -838,6 +844,42 @@ static const MemoryRegionOps ufs_mmio_ops = {
},
};
+static void ufs_update_ee_status(UfsHc *u)
+{
+ uint16_t ee_status = be16_to_cpu(u->attributes.exception_event_status);
+ uint8_t high_temp_thresh = u->attributes.device_too_high_temp_boundary;
+ uint8_t low_temp_thresh = u->attributes.device_too_low_temp_boundary;
+
+ if (u->temperature >= high_temp_thresh) {
+ ee_status |= MASK_EE_TOO_HIGH_TEMP;
+ } else {
+ ee_status &= ~MASK_EE_TOO_HIGH_TEMP;
+ }
+
+ if (u->temperature <= low_temp_thresh) {
+ ee_status |= MASK_EE_TOO_LOW_TEMP;
+ } else {
+ ee_status &= ~MASK_EE_TOO_LOW_TEMP;
+ }
+
+ u->attributes.exception_event_status = cpu_to_be16(ee_status);
+}
+
+static bool ufs_check_exception_event_alert(UfsHc *u, uint8_t trans_type)
+{
+ uint16_t ee_control = be16_to_cpu(u->attributes.exception_event_control);
+ uint16_t ee_status;
+
+ if (trans_type != UFS_UPIU_TRANSACTION_RESPONSE) {
+ return false;
+ }
+
+ ufs_update_ee_status(u);
+
+ ee_status = be16_to_cpu(u->attributes.exception_event_status);
+
+ return ee_control & ee_status;
+}
void ufs_build_upiu_header(UfsRequest *req, uint8_t trans_type, uint8_t flags,
uint8_t response, uint8_t scsi_status,
@@ -848,6 +890,8 @@ void ufs_build_upiu_header(UfsRequest *req, uint8_t trans_type, uint8_t flags,
req->rsp_upiu.header.flags = flags;
req->rsp_upiu.header.response = response;
req->rsp_upiu.header.scsi_status = scsi_status;
+ req->rsp_upiu.header.device_inf =
+ ufs_check_exception_event_alert(req->hc, trans_type);
req->rsp_upiu.header.data_segment_length = cpu_to_be16(data_segment_length);
}
@@ -1042,6 +1086,25 @@ static QueryRespCode ufs_exec_query_flag(UfsRequest *req, int op)
return UFS_QUERY_RESULT_SUCCESS;
}
+static inline uint8_t ufs_read_device_temp(UfsHc *u)
+{
+ uint8_t feat_sup = u->device_desc.ufs_features_support;
+ bool high_temp_sup, low_temp_sup, high_temp_en, low_temp_en;
+ uint16_t ee_control = be16_to_cpu(u->attributes.exception_event_control);
+
+ high_temp_sup = feat_sup & UFS_DEV_HIGH_TEMP_NOTIF;
+ low_temp_sup = feat_sup & UFS_DEV_LOW_TEMP_NOTIF;
+ high_temp_en = ee_control & MASK_EE_TOO_HIGH_TEMP;
+ low_temp_en = ee_control & MASK_EE_TOO_LOW_TEMP;
+
+ if ((high_temp_sup && high_temp_en) ||
+ (low_temp_sup && low_temp_en)) {
+ return u->temperature;
+ }
+
+ return 0;
+}
+
static uint32_t ufs_read_attr_value(UfsHc *u, uint8_t idn)
{
switch (idn) {
@@ -1072,6 +1135,7 @@ static uint32_t ufs_read_attr_value(UfsHc *u, uint8_t idn)
case UFS_QUERY_ATTR_IDN_EE_CONTROL:
return be16_to_cpu(u->attributes.exception_event_control);
case UFS_QUERY_ATTR_IDN_EE_STATUS:
+ ufs_update_ee_status(u);
return be16_to_cpu(u->attributes.exception_event_status);
case UFS_QUERY_ATTR_IDN_SECONDS_PASSED:
return be32_to_cpu(u->attributes.seconds_passed);
@@ -1086,7 +1150,8 @@ static uint32_t ufs_read_attr_value(UfsHc *u, uint8_t idn)
case UFS_QUERY_ATTR_IDN_REF_CLK_GATING_WAIT_TIME:
return u->attributes.ref_clk_gating_wait_time;
case UFS_QUERY_ATTR_IDN_CASE_ROUGH_TEMP:
- return u->attributes.device_case_rough_temperaure;
+ u->attributes.device_case_rough_temperature = ufs_read_device_temp(u);
+ return u->attributes.device_case_rough_temperature;
case UFS_QUERY_ATTR_IDN_HIGH_TEMP_BOUND:
return u->attributes.device_too_high_temp_boundary;
case UFS_QUERY_ATTR_IDN_LOW_TEMP_BOUND:
@@ -1164,7 +1229,7 @@ static QueryRespCode ufs_exec_query_attr(UfsRequest *req, int op)
value = ufs_read_attr_value(u, idn);
ret = UFS_QUERY_RESULT_SUCCESS;
} else {
- value = req->req_upiu.qr.value;
+ value = be32_to_cpu(req->req_upiu.qr.value);
ret = ufs_write_attr_value(u, idn, value);
}
req->rsp_upiu.qr.value = cpu_to_be32(value);
@@ -1635,7 +1700,7 @@ static void ufs_init_hc(UfsHc *u)
cap = FIELD_DP32(cap, CAP, OODDS, 0);
cap = FIELD_DP32(cap, CAP, UICDMETMS, 0);
cap = FIELD_DP32(cap, CAP, CS, 0);
- cap = FIELD_DP32(cap, CAP, LSDBS, 1);
+ cap = FIELD_DP32(cap, CAP, LSDBS, 0);
cap = FIELD_DP32(cap, CAP, MCQS, u->params.mcq);
u->reg.cap = cap;
@@ -1677,15 +1742,19 @@ static void ufs_init_hc(UfsHc *u)
u->device_desc.ud_0_base_offset = 0x16;
u->device_desc.ud_config_p_length = 0x1A;
u->device_desc.device_rtt_cap = 0x02;
+ u->device_desc.ufs_features_support = UFS_DEV_HIGH_TEMP_NOTIF |
+ UFS_DEV_LOW_TEMP_NOTIF;
u->device_desc.queue_depth = u->params.nutrs;
u->device_desc.product_revision_level = 0x04;
+ u->device_desc.extended_ufs_features_support =
+ cpu_to_be32(UFS_DEV_HIGH_TEMP_NOTIF | UFS_DEV_LOW_TEMP_NOTIF);
memset(&u->geometry_desc, 0, sizeof(GeometryDescriptor));
u->geometry_desc.length = sizeof(GeometryDescriptor);
u->geometry_desc.descriptor_idn = UFS_QUERY_DESC_IDN_GEOMETRY;
u->geometry_desc.max_number_lu = (UFS_MAX_LUS == 32) ? 0x1 : 0x0;
- u->geometry_desc.segment_size = cpu_to_be32(0x2000); /* 4KB */
- u->geometry_desc.allocation_unit_size = 0x1; /* 4KB */
+ u->geometry_desc.segment_size = cpu_to_be32(0x2000); /* 4MB: 8192 * 512B */
+ u->geometry_desc.allocation_unit_size = 0x1; /* 4MB: 1 segment */
u->geometry_desc.min_addr_block_size = 0x8; /* 4KB */
u->geometry_desc.max_in_buffer_size = 0x8;
u->geometry_desc.max_out_buffer_size = 0x8;
@@ -1702,9 +1771,17 @@ static void ufs_init_hc(UfsHc *u)
/* configure descriptor is not supported */
u->attributes.config_descr_lock = 0x01;
u->attributes.max_num_of_rtt = 0x02;
+ u->attributes.device_too_high_temp_boundary = UFS_TOO_HIGH_TEMP_BOUNDARY;
+ u->attributes.device_too_low_temp_boundary = UFS_TOO_LOW_TEMP_BOUNDARY;
memset(&u->flags, 0, sizeof(u->flags));
u->flags.permanently_disable_fw_update = 1;
+
+ /*
+ * The temperature value is fixed to UFS_TEMPERATURE and does not change
+ * dynamically
+ */
+ u->temperature = UFS_TEMPERATURE;
}
static void ufs_realize(PCIDevice *pci_dev, Error **errp)
@@ -1732,6 +1809,8 @@ static void ufs_exit(PCIDevice *pci_dev)
{
UfsHc *u = UFS(pci_dev);
+ qemu_free_irq(u->irq);
+
qemu_bh_delete(u->doorbell_bh);
qemu_bh_delete(u->complete_bh);
@@ -1752,13 +1831,12 @@ static void ufs_exit(PCIDevice *pci_dev)
}
}
-static Property ufs_props[] = {
+static const Property ufs_props[] = {
DEFINE_PROP_STRING("serial", UfsHc, params.serial),
DEFINE_PROP_UINT8("nutrs", UfsHc, params.nutrs, 32),
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_END_OF_LIST(),
};
static const VMStateDescription ufs_vmstate = {
@@ -1766,7 +1844,7 @@ static const VMStateDescription ufs_vmstate = {
.unmigratable = 1,
};
-static void ufs_class_init(ObjectClass *oc, void *data)
+static void ufs_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
PCIDeviceClass *pc = PCI_DEVICE_CLASS(oc);
@@ -1802,7 +1880,7 @@ static char *ufs_bus_get_dev_path(DeviceState *dev)
return qdev_get_dev_path(bus->parent);
}
-static void ufs_bus_class_init(ObjectClass *class, void *data)
+static void ufs_bus_class_init(ObjectClass *class, const void *data)
{
BusClass *bc = BUS_CLASS(class);
bc->get_dev_path = ufs_bus_get_dev_path;
@@ -1814,7 +1892,7 @@ static const TypeInfo ufs_info = {
.parent = TYPE_PCI_DEVICE,
.class_init = ufs_class_init,
.instance_size = sizeof(UfsHc),
- .interfaces = (InterfaceInfo[]){ { INTERFACE_PCIE_DEVICE }, {} },
+ .interfaces = (const InterfaceInfo[]){ { INTERFACE_PCIE_DEVICE }, {} },
};
static const TypeInfo ufs_bus_info = {
diff --git a/hw/ufs/ufs.h b/hw/ufs/ufs.h
index 4bcc41f..3799d97 100644
--- a/hw/ufs/ufs.h
+++ b/hw/ufs/ufs.h
@@ -146,6 +146,8 @@ typedef struct UfsHc {
/* MCQ properties */
UfsSq *sq[UFS_MAX_MCQ_QNUM];
UfsCq *cq[UFS_MAX_MCQ_QNUM];
+
+ uint8_t temperature;
} UfsHc;
static inline uint32_t ufs_mcq_sq_tail(UfsHc *u, uint32_t qid)