summaryrefslogtreecommitdiff
path: root/usr/src/uts/common/cpr/cpr_driver.c
diff options
context:
space:
mode:
authorrandyf <none@none>2007-10-20 16:00:42 -0700
committerrandyf <none@none>2007-10-20 16:00:42 -0700
commit2df1fe9ca32bb227b9158c67f5c00b54c20b10fd (patch)
tree358c576f885c00d42a760d9e35e5b66e77209fe2 /usr/src/uts/common/cpr/cpr_driver.c
parent10b3fbf593a6678eec9b50a01903ef4eb73111e4 (diff)
downloadillumos-gate-2df1fe9ca32bb227b9158c67f5c00b54c20b10fd.tar.gz
PSARC/2005/469 X86 Energy Star compliance
PSARC/2006/632 PSMI extension for state save and restore 6330209 nge needs to support DDI_SUSPEND/DDI_RESUME 6381827 Suspend to RAM on x86 6393154 audio810 needs to support DDI_SUSPEND/DDI_RESUME 6397047 fd, fdc needs to support Suspend/Resume 6401974 cannot enter S3 with ohci PME enable set on Tyan 2865 with Sun or Tyan 2.01 BIOS 6422613 memscrubber doesn't re-acquire lock before CALLB_CPR_EXIT 6455736 ata/dadk/cmdk should support DDI_SUSPEND/DDI_RESUME 6511370 CPR on SPARC regression 6586018 TODOP Macros in i86pc/sys/machclock.h not in sun4u/sun4v equivilent (Sparc only) 6610124 It takes more than 3 minutes after printing "pci_pre_resume nv_sata:0" 6617143 powerd/pmconfig emits a different default message for an existing on or off action. --HG-- rename : usr/src/cmd/power/power.conf => usr/src/cmd/power/power.conf.sparc
Diffstat (limited to 'usr/src/uts/common/cpr/cpr_driver.c')
-rw-r--r--usr/src/uts/common/cpr/cpr_driver.c131
1 files changed, 85 insertions, 46 deletions
diff --git a/usr/src/uts/common/cpr/cpr_driver.c b/usr/src/uts/common/cpr/cpr_driver.c
index a23a9cbf7c..442473c7ca 100644
--- a/usr/src/uts/common/cpr/cpr_driver.c
+++ b/usr/src/uts/common/cpr/cpr_driver.c
@@ -45,6 +45,18 @@ extern int devi_attach(dev_info_t *, int);
static char *devi_string(dev_info_t *, char *);
static int cpr_is_real_device(dev_info_t *);
+/*
+ * Xen uses this code to suspend _all_ drivers quickly and easily.
+ * Suspend and Resume uses it for the same reason, but also has
+ * to contend with some platform specific code that Xen does not.
+ * it is also used as a test entry point for developers/testers to
+ * execute code without going through a complete suspend. So additions
+ * that have platform implications shall need #if[n]def's.
+ */
+#ifndef __xpv
+extern void i_cpr_save_configuration(dev_info_t *);
+extern void i_cpr_restore_configuration(dev_info_t *);
+#endif
/*
* Traverse the dev info tree:
@@ -70,22 +82,52 @@ cpr_suspend_devices(dev_info_t *dip)
devi_string(dip, buf));
ASSERT((DEVI(dip)->devi_cpr_flags & DCF_CPR_SUSPENDED) == 0);
- if (!i_ddi_devi_attached(dip))
+#ifndef __xpv
+ i_cpr_save_configuration(dip);
+#endif
+
+
+ if (!i_ddi_devi_attached(dip)) {
error = DDI_FAILURE;
- else
- error = devi_detach(dip, DDI_SUSPEND);
+ } else {
+#ifndef __xpv
+ if (cpr_test_point != DEVICE_SUSPEND_TO_RAM ||
+ (cpr_test_point == DEVICE_SUSPEND_TO_RAM &&
+ cpr_device == ddi_driver_major(dip))) {
+#endif
+ error = devi_detach(dip, DDI_SUSPEND);
+#ifndef __xpv
+ } else {
+ error = DDI_SUCCESS;
+ }
+#endif
+ }
- if (error == DDI_SUCCESS)
+ if (error == DDI_SUCCESS) {
DEVI(dip)->devi_cpr_flags |= DCF_CPR_SUSPENDED;
+ }
+
else {
CPR_DEBUG(CPR_DEBUG2,
"WARNING: Unable to suspend device %s\n",
devi_string(dip, buf));
cpr_err(CE_WARN, "Unable to suspend device %s.",
- devi_string(dip, buf));
+ devi_string(dip, buf));
cpr_err(CE_WARN, "Device is busy or does not "
- "support suspend/resume.");
- return (ENXIO);
+ "support suspend/resume.");
+#ifndef __xpv
+ /*
+ * the device has failed to suspend however,
+ * if cpr_test_point == FORCE_SUSPEND_TO_RAM
+ * after putting out the warning message above,
+ * we carry on as if suspending the device had
+ * been successful
+ */
+ if (cpr_test_point == FORCE_SUSPEND_TO_RAM)
+ DEVI(dip)->devi_cpr_flags |= DCF_CPR_SUSPENDED;
+ else
+#endif
+ return (ENXIO);
}
}
return (0);
@@ -124,13 +166,27 @@ cpr_resume_devices(dev_info_t *start, int resume_failed)
DEVI(dip)->devi_cpr_flags &= ~DCF_CPR_SUSPENDED;
/*
+ * Always attempt to restore device configuration before
+ * attempting resume
+ */
+#ifndef __xpv
+ i_cpr_restore_configuration(dip);
+#endif
+
+ /*
* There may be background attaches happening on devices
* that were not originally suspended by cpr, so resume
* only devices that were suspended by cpr. Also, stop
* resuming after the first resume failure, but traverse
- * the entire tree to clear the suspend flag.
+ * the entire tree to clear the suspend flag unless the
+ * FORCE_SUSPEND_TO_RAM test point is set.
*/
+#ifndef __xpv
+ if (did_suspend && (!error ||
+ cpr_test_point == FORCE_SUSPEND_TO_RAM)) {
+#else
if (did_suspend && !error) {
+#endif
CPR_DEBUG(CPR_DEBUG2, "Resuming device %s\n",
devi_string(dip, buf));
/*
@@ -146,17 +202,28 @@ cpr_resume_devices(dev_info_t *start, int resume_failed)
cpr_err(CE_WARN, "Skipping %s, device "
"not ready for resume",
devi_string(dip, buf));
- } else if (devi_attach(dip, DDI_RESUME) !=
- DDI_SUCCESS) {
- CPR_DEBUG(CPR_DEBUG2,
- "WARNING: Unable to resume device %s\n",
- devi_string(dip, buf));
- cpr_err(CE_WARN, "Unable to resume device %s",
- devi_string(dip, buf));
- error = ENXIO;
+#ifndef __xpv
+ } else if (cpr_test_point != DEVICE_SUSPEND_TO_RAM ||
+ (cpr_test_point == DEVICE_SUSPEND_TO_RAM &&
+ cpr_device == ddi_driver_major(dip))) {
+#else
+ } else {
+#endif
+ if (devi_attach(dip, DDI_RESUME) !=
+ DDI_SUCCESS) {
+ error = ENXIO;
+ }
}
}
+ if (error == ENXIO) {
+ CPR_DEBUG(CPR_DEBUG2,
+ "WARNING: Unable to resume device %s\n",
+ devi_string(dip, buf));
+ cpr_err(CE_WARN, "Unable to resume device %s",
+ devi_string(dip, buf));
+ }
+
error = cpr_resume_devices(ddi_get_child(dip), error);
last = dip;
}
@@ -176,10 +243,8 @@ devi_string(dev_info_t *devi, char *buf)
name = ddi_node_name(devi);
address = ddi_get_name_addr(devi);
- size = (name == NULL) ?
- strlen("<null name>") : strlen(name);
- size += (address == NULL) ?
- strlen("<null>") : strlen(address);
+ size = (name == NULL) ? strlen("<null name>") : strlen(name);
+ size += (address == NULL) ? strlen("<null>") : strlen(address);
/*
* Make sure that we don't over-run the buffer.
@@ -237,29 +302,3 @@ cpr_is_real_device(dev_info_t *dip)
return (1);
}
}
-
-/*
- * Power down the system.
- */
-void
-cpr_power_down(void)
-{
-#if defined(__sparc)
- /*
- * XXX This platform firmware implementation dependency
- * doesn't belong in common code!
- */
- int is_defined = 0;
- char *wordexists = "p\" power-off\" find nip swap l! ";
- char *req = "power-off";
-
- /*
- * is_defined has value -1 when defined
- */
- prom_interpret(wordexists, (uintptr_t)&is_defined, 0, 0, 0, 0);
- if (is_defined) {
- CPR_DEBUG(CPR_DEBUG1, "\ncpr: %s...\n", req);
- prom_interpret(req, 0, 0, 0, 0, 0);
- }
-#endif
-}