Page MenuHomeFreeBSD

D54000.id167343.diff
No OneTemporary

D54000.id167343.diff

diff --git a/sys/dev/ufshci/ufshci.c b/sys/dev/ufshci/ufshci.c
--- a/sys/dev/ufshci/ufshci.c
+++ b/sys/dev/ufshci/ufshci.c
@@ -8,12 +8,16 @@
#include <sys/param.h>
#include <sys/bus.h>
#include <sys/conf.h>
+#include <sys/eventhandler.h>
#include <sys/module.h>
#include "ufshci_private.h"
MALLOC_DEFINE(M_UFSHCI, "ufshci", "ufshci(4) memory allocations");
+static void ufshci_suspend_handler(void *priv, enum power_stype);
+static void ufshci_resume_handler(void *priv, enum power_stype);
+
int
ufshci_attach(device_t dev)
{
@@ -32,9 +36,74 @@
if (config_intrhook_establish(&ctrlr->config_hook) != 0)
return (ENOMEM);
+ /* Register suspend/resume event handlers */
+ if (ctrlr->ufs_dev.power_mode_supported) {
+ ctrlr->suspend_eh = EVENTHANDLER_REGISTER(power_suspend,
+ ufshci_suspend_handler, ctrlr, EVENTHANDLER_PRI_LAST);
+ if (ctrlr->suspend_eh == NULL) {
+ ufshci_printf(ctrlr,
+ "Failed to register suspend event handler\n");
+ return (0);
+ }
+ ctrlr->resume_eh = EVENTHANDLER_REGISTER(power_resume,
+ ufshci_resume_handler, ctrlr, EVENTHANDLER_PRI_LAST);
+ if (ctrlr->resume_eh == NULL) {
+ ufshci_printf(ctrlr,
+ "Failed to register resume event handler\n");
+ EVENTHANDLER_DEREGISTER(power_suspend,
+ ctrlr->suspend_eh);
+ }
+ }
+
return (0);
}
+static void
+ufshci_suspend_handler(void *priv, enum power_stype stype)
+{
+ struct ufshci_controller *ctrlr;
+
+ ctrlr = priv;
+ if (!ctrlr->ufs_dev.power_mode_supported)
+ return;
+
+ /* TODO: Need to flush the request queue */
+
+ if (ctrlr->ufs_device_wlun_periph) {
+ ctrlr->ufs_dev.power_mode = power_map[stype].dev_pwr;
+ if (ufshci_sim_send_ssu(ctrlr, /*start*/ false,
+ power_map[stype].ssu_pc, /*immed*/ false)) {
+ ufshci_printf(ctrlr,
+ "Failed to send SSU in suspend handler\n");
+ return;
+ }
+ }
+
+ /* TODO: Change the link state to Hibernate if necessary. */
+}
+
+static void
+ufshci_resume_handler(void *priv, enum power_stype stype)
+{
+ struct ufshci_controller *ctrlr;
+
+ ctrlr = priv;
+ if (!ctrlr->ufs_dev.power_mode_supported)
+ return;
+
+ /* TODO: Change the link state to Active if necessary. */
+
+ if (ctrlr->ufs_device_wlun_periph) {
+ ctrlr->ufs_dev.power_mode = power_map[stype].dev_pwr;
+ if (ufshci_sim_send_ssu(ctrlr, /*start*/ false,
+ power_map[stype].ssu_pc, /*immed*/ false)) {
+ ufshci_printf(ctrlr,
+ "Failed to send SSU in resume handler\n");
+ return;
+ }
+ }
+}
+
int
ufshci_detach(device_t dev)
{
@@ -44,6 +113,9 @@
ufshci_ctrlr_destruct(ctrlr, dev);
+ EVENTHANDLER_DEREGISTER(power_suspend, ctrlr->suspend_eh);
+ EVENTHANDLER_DEREGISTER(power_resume, ctrlr->resume_eh);
+
return (0);
}
diff --git a/sys/dev/ufshci/ufshci_dev.c b/sys/dev/ufshci/ufshci_dev.c
--- a/sys/dev/ufshci/ufshci_dev.c
+++ b/sys/dev/ufshci/ufshci_dev.c
@@ -469,6 +469,8 @@
}
ctrlr->ufs_dev.power_mode_supported = true;
+ ctrlr->ufs_dev.power_mode = UFSHCI_DEV_PWR_ACTIVE;
+
return (0);
}
@@ -786,3 +788,20 @@
ufshci_dev_disable_write_booster(ctrlr);
return (error);
}
+
+int
+ufshci_dev_get_current_power_mode(struct ufshci_controller *ctrlr,
+ uint8_t *power_mode)
+{
+ uint64_t value;
+ int err;
+
+ err = ufshci_dev_read_attribute(ctrlr, UFSHCI_ATTR_B_CURRENT_POWER_MODE,
+ /*index*/ 0, /*selector*/ 0, &value);
+ if (err)
+ return (err);
+
+ *power_mode = (uint8_t)value;
+
+ return (0);
+}
diff --git a/sys/dev/ufshci/ufshci_private.h b/sys/dev/ufshci/ufshci_private.h
--- a/sys/dev/ufshci/ufshci_private.h
+++ b/sys/dev/ufshci/ufshci_private.h
@@ -26,12 +26,14 @@
#include <sys/memdesc.h>
#include <sys/module.h>
#include <sys/mutex.h>
+#include <sys/power.h>
#include <sys/rman.h>
#include <sys/taskqueue.h>
#include <machine/bus.h>
#include <cam/cam.h>
+#include <cam/scsi/scsi_all.h>
#include "ufshci.h"
@@ -233,6 +235,30 @@
bus_dmamap_t ucdmem_map;
};
+enum ufshci_dev_pwr {
+ UFSHCI_DEV_PWR_ACTIVE = 0,
+ UFSHCI_DEV_PWR_SLEEP,
+ UFSHCI_DEV_PWR_POWERDOWN,
+ UFSHCI_DEV_PWR_DEEPSLEEP,
+ UFSHCI_DEV_PWR_COUNT,
+};
+
+struct ufshci_power_entry {
+ enum ufshci_dev_pwr dev_pwr;
+ uint8_t ssu_pc; /* SSU Power Condition */
+};
+
+/* SSU Power Condition 0x40 is defined in the UFS specification */
+static const struct ufshci_power_entry power_map[POWER_STYPE_COUNT] = {
+ [POWER_STYPE_AWAKE] = { UFSHCI_DEV_PWR_ACTIVE, SSS_PC_ACTIVE },
+ [POWER_STYPE_STANDBY] = { UFSHCI_DEV_PWR_SLEEP, SSS_PC_IDLE },
+ [POWER_STYPE_SUSPEND_TO_MEM] = { UFSHCI_DEV_PWR_POWERDOWN,
+ SSS_PC_STANDBY },
+ [POWER_STYPE_SUSPEND_TO_IDLE] = { UFSHCI_DEV_PWR_SLEEP, SSS_PC_IDLE },
+ [POWER_STYPE_HIBERNATE] = { UFSHCI_DEV_PWR_DEEPSLEEP, 0x40 },
+ [POWER_STYPE_POWEROFF] = { UFSHCI_DEV_PWR_POWERDOWN, SSS_PC_STANDBY },
+};
+
struct ufshci_device {
uint32_t max_lun_count;
@@ -252,6 +278,7 @@
/* Power mode */
bool power_mode_supported;
+ enum ufshci_dev_pwr power_mode;
};
/*
@@ -293,6 +320,9 @@
int resource_id;
struct resource *resource;
+ eventhandler_tag suspend_eh;
+ eventhandler_tag resume_eh;
+
/* Currently, there is no UFSHCI that supports MSI, MSI-X. */
int msi_count;
@@ -386,7 +416,7 @@
struct cam_periph *ufshci_sim_find_periph(struct ufshci_controller *ctrlr,
uint8_t wlun);
int ufshci_sim_send_ssu(struct ufshci_controller *ctrlr, bool start,
- int pwr_cond, bool immed);
+ uint8_t pwr_cond, bool immed);
/* Controller */
int ufshci_ctrlr_construct(struct ufshci_controller *ctrlr, device_t dev);
@@ -415,6 +445,8 @@
int ufshci_dev_init_ufs_power_mode(struct ufshci_controller *ctrlr);
int ufshci_dev_get_descriptor(struct ufshci_controller *ctrlr);
int ufshci_dev_config_write_booster(struct ufshci_controller *ctrlr);
+int ufshci_dev_get_current_power_mode(struct ufshci_controller *ctrlr,
+ uint8_t *power_mode);
/* Controller Command */
void ufshci_ctrlr_cmd_send_task_mgmt_request(struct ufshci_controller *ctrlr,
diff --git a/sys/dev/ufshci/ufshci_req_queue.c b/sys/dev/ufshci/ufshci_req_queue.c
--- a/sys/dev/ufshci/ufshci_req_queue.c
+++ b/sys/dev/ufshci/ufshci_req_queue.c
@@ -147,7 +147,8 @@
/* Check response UPIU header */
if (response->header.response != UFSHCI_RESPONSE_CODE_TARGET_SUCCESS) {
ufshci_printf(req_queue->ctrlr,
- "Invalid response code = 0x%x\n",
+ "Function(0x%x) Invalid response code = 0x%x\n",
+ response->header.ext_iid_or_function,
response->header.response);
is_error = true;
}
diff --git a/sys/dev/ufshci/ufshci_sim.c b/sys/dev/ufshci/ufshci_sim.c
--- a/sys/dev/ufshci/ufshci_sim.c
+++ b/sys/dev/ufshci/ufshci_sim.c
@@ -46,6 +46,11 @@
ccb->ccb_h.status &= ~CAM_SIM_QUEUED;
if (error) {
+ printf("ufshci: SCSI command completion error, Status(0x%x)"
+ " Key(0x%x), ASC(0x%x), ASCQ(0x%x)\n",
+ cpl->response_upiu.cmd_response_upiu.header
+ .ext_iid_or_status,
+ sense_data[2], sense_data[12], sense_data[13]);
ccb->ccb_h.status = CAM_REQ_CMP_ERR;
xpt_done(ccb);
} else {
@@ -455,7 +460,7 @@
/* This function is called during suspend/resume. */
int
ufshci_sim_send_ssu(struct ufshci_controller *ctrlr, bool start,
- int power_condition, bool immed)
+ uint8_t power_condition, bool immed)
{
struct cam_periph *periph = ctrlr->ufs_device_wlun_periph;
union ccb *ccb;
diff --git a/sys/dev/ufshci/ufshci_sysctl.c b/sys/dev/ufshci/ufshci_sysctl.c
--- a/sys/dev/ufshci/ufshci_sysctl.c
+++ b/sys/dev/ufshci/ufshci_sysctl.c
@@ -201,6 +201,9 @@
CTLFLAG_RD, &dev->power_mode_supported, 0,
"Device power mode support");
+ SYSCTL_ADD_UINT(ctrlr_ctx, ctrlr_list, OID_AUTO, "power_mode",
+ CTLFLAG_RD, &dev->power_mode, 0, "Current device power mode");
+
SYSCTL_ADD_PROC(ctrlr_ctx, ctrlr_list, OID_AUTO, "timeout_period",
CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_MPSAFE, &ctrlr->timeout_period,
0, ufshci_sysctl_timeout_period, "IU",

File Metadata

Mime Type
text/plain
Expires
Sun, Apr 12, 1:48 PM (4 h, 7 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
31295468
Default Alt Text
D54000.id167343.diff (7 KB)

Event Timeline