Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F151925355
D54000.id167343.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
7 KB
Referenced Files
None
Subscribers
None
D54000.id167343.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D54000: ufshci: Support suspend/resume
Attached
Detach File
Event Timeline
Log In to Comment