Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F157331818
D54002.id167413.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
D54002.id167413.diff
View Options
diff --git a/sys/dev/ufshci/ufshci_ctrlr.c b/sys/dev/ufshci/ufshci_ctrlr.c
--- a/sys/dev/ufshci/ufshci_ctrlr.c
+++ b/sys/dev/ufshci/ufshci_ctrlr.c
@@ -610,3 +610,53 @@
ufshci_printf(ctrlr, "========================================\n");
}
+
+int
+ufshci_ctrlr_suspend(struct ufshci_controller *ctrlr, enum power_stype stype)
+{
+ int error;
+
+ if (!ctrlr->ufs_dev.power_mode_supported)
+ return (0);
+
+ /* TODO: Need to flush the request queue */
+
+ if (ctrlr->ufs_device_wlun_periph) {
+ ctrlr->ufs_dev.power_mode = power_map[stype].dev_pwr;
+ error = ufshci_sim_send_ssu(ctrlr, /*start*/ false,
+ power_map[stype].ssu_pc, /*immed*/ false);
+ if (error) {
+ ufshci_printf(ctrlr,
+ "Failed to send SSU in suspend handler\n");
+ return (error);
+ }
+ }
+
+ /* TODO: Change the link state to Hibernate if necessary. */
+
+ return (0);
+}
+
+int
+ufshci_ctrlr_resume(struct ufshci_controller *ctrlr, enum power_stype stype)
+{
+ int error;
+
+ if (!ctrlr->ufs_dev.power_mode_supported)
+ return (0);
+
+ /* 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;
+ error = ufshci_sim_send_ssu(ctrlr, /*start*/ false,
+ power_map[stype].ssu_pc, /*immed*/ false);
+ if (error) {
+ ufshci_printf(ctrlr,
+ "Failed to send SSU in resume handler\n");
+ return (error);
+ }
+ }
+
+ 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_pci.c b/sys/dev/ufshci/ufshci_pci.c
--- a/sys/dev/ufshci/ufshci_pci.c
+++ b/sys/dev/ufshci/ufshci_pci.c
@@ -23,6 +23,8 @@
static int ufshci_pci_probe(device_t);
static int ufshci_pci_attach(device_t);
static int ufshci_pci_detach(device_t);
+static int ufshci_pci_suspend(device_t);
+static int ufshci_pci_resume(device_t);
static int ufshci_pci_setup_interrupts(struct ufshci_controller *ctrlr);
@@ -31,8 +33,8 @@
DEVMETHOD(device_probe, ufshci_pci_probe),
DEVMETHOD(device_attach, ufshci_pci_attach),
DEVMETHOD(device_detach, ufshci_pci_detach),
- /* TODO: Implement Suspend, Resume */
- { 0, 0 }
+ DEVMETHOD(device_suspend, ufshci_pci_suspend),
+ DEVMETHOD(device_resume, ufshci_pci_resume), { 0, 0 }
};
static driver_t ufshci_pci_driver = {
@@ -261,3 +263,20 @@
intx:
return (ufshci_pci_setup_shared(ctrlr, ctrlr->msi_count > 0 ? 1 : 0));
}
+
+static int
+ufshci_pci_suspend(device_t dev)
+{
+ struct ufshci_controller *ctrlr = device_get_softc(dev);
+
+ /* Currently, PCI-based ufshci only supports POWER_STYPE_STANDBY */
+ return (ufshci_ctrlr_suspend(ctrlr, POWER_STYPE_STANDBY));
+}
+
+static int
+ufshci_pci_resume(device_t dev)
+{
+ struct ufshci_controller *ctrlr = device_get_softc(dev);
+
+ return (ufshci_ctrlr_resume(ctrlr, POWER_STYPE_AWAKE));
+}
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;
};
/*
@@ -386,12 +413,16 @@
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);
void ufshci_ctrlr_destruct(struct ufshci_controller *ctrlr, device_t dev);
void ufshci_ctrlr_reset(struct ufshci_controller *ctrlr);
+int ufshci_ctrlr_suspend(struct ufshci_controller *ctrlr,
+ enum power_stype stype);
+int ufshci_ctrlr_resume(struct ufshci_controller *ctrlr,
+ enum power_stype stype);
/* ctrlr defined as void * to allow use with config_intrhook. */
void ufshci_ctrlr_start_config_hook(void *arg);
void ufshci_ctrlr_poll(struct ufshci_controller *ctrlr);
@@ -415,6 +446,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
Thu, May 21, 9:48 AM (9 h, 10 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
33385147
Default Alt Text
D54002.id167413.diff (7 KB)
Attached To
Mode
D54002: ufshci: Support suspend/resume
Attached
Detach File
Event Timeline
Log In to Comment