diff options
author | randyf <none@none> | 2007-10-20 16:00:42 -0700 |
---|---|---|
committer | randyf <none@none> | 2007-10-20 16:00:42 -0700 |
commit | 2df1fe9ca32bb227b9158c67f5c00b54c20b10fd (patch) | |
tree | 358c576f885c00d42a760d9e35e5b66e77209fe2 /usr/src/uts/common/cpr/cpr_driver.c | |
parent | 10b3fbf593a6678eec9b50a01903ef4eb73111e4 (diff) | |
download | illumos-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.c | 131 |
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 -} |