diff options
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 -} |