4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #pragma ident "%Z%%M% %I% %E% SMI"
29 * CPR driver support routines
32 #include <sys/types.h>
33 #include <sys/errno.h>
35 #include <sys/systm.h>
36 #include <sys/sunddi.h>
37 #include <sys/ddi_impldefs.h>
41 #define CPR_BUFSIZE 128
43 extern int devi_detach(dev_info_t
*, int);
44 extern int devi_attach(dev_info_t
*, int);
46 static char *devi_string(dev_info_t
*, char *);
47 static int cpr_is_real_device(dev_info_t
*);
49 * Xen uses this code to suspend _all_ drivers quickly and easily.
50 * Suspend and Resume uses it for the same reason, but also has
51 * to contend with some platform specific code that Xen does not.
52 * it is also used as a test entry point for developers/testers to
53 * execute code without going through a complete suspend. So additions
54 * that have platform implications shall need #if[n]def's.
56 extern void i_cpr_save_configuration(dev_info_t
*);
57 extern void i_cpr_restore_configuration(dev_info_t
*);
60 * Traverse the dev info tree:
61 * Call each device driver in the system via a special case
62 * of the detach() entry point to quiesce itself.
63 * Suspend children first.
65 * We only suspend/resume real devices.
69 cpr_suspend_devices(dev_info_t
*dip
)
72 char buf
[CPR_BUFSIZE
];
74 for (; dip
!= NULL
; dip
= ddi_get_next_sibling(dip
)) {
75 if (cpr_suspend_devices(ddi_get_child(dip
)))
77 if (!cpr_is_real_device(dip
))
79 CPR_DEBUG(CPR_DEBUG2
, "Suspending device %s\n",
80 devi_string(dip
, buf
));
81 ASSERT((DEVI(dip
)->devi_cpr_flags
& DCF_CPR_SUSPENDED
) == 0);
83 i_cpr_save_configuration(dip
);
86 if (!i_ddi_devi_attached(dip
)) {
89 if (cpr_test_point
!= DEVICE_SUSPEND_TO_RAM
||
90 (cpr_test_point
== DEVICE_SUSPEND_TO_RAM
&&
91 cpr_device
== ddi_driver_major(dip
))) {
92 error
= devi_detach(dip
, DDI_SUSPEND
);
98 if (error
== DDI_SUCCESS
) {
99 DEVI(dip
)->devi_cpr_flags
|= DCF_CPR_SUSPENDED
;
103 CPR_DEBUG(CPR_DEBUG2
,
104 "WARNING: Unable to suspend device %s\n",
105 devi_string(dip
, buf
));
106 cpr_err(CE_WARN
, "Unable to suspend device %s.",
107 devi_string(dip
, buf
));
108 cpr_err(CE_WARN
, "Device is busy or does not "
109 "support suspend/resume.");
111 * the device has failed to suspend however,
112 * if cpr_test_point == FORCE_SUSPEND_TO_RAM
113 * after putting out the warning message above,
114 * we carry on as if suspending the device had
117 if (cpr_test_point
== FORCE_SUSPEND_TO_RAM
)
118 DEVI(dip
)->devi_cpr_flags
|= DCF_CPR_SUSPENDED
;
127 * Traverse the dev info tree:
128 * Call each device driver in the system via a special case
129 * of the attach() entry point to restore itself.
130 * This is a little tricky because it has to reverse the traversal
131 * order of cpr_suspend_devices().
134 cpr_resume_devices(dev_info_t
*start
, int resume_failed
)
136 dev_info_t
*dip
, *next
, *last
= NULL
;
138 int error
= resume_failed
;
139 char buf
[CPR_BUFSIZE
];
141 while (last
!= start
) {
143 next
= ddi_get_next_sibling(dip
);
144 while (next
!= last
) {
146 next
= ddi_get_next_sibling(dip
);
150 * cpr is the only one that uses this field and the device
151 * itself hasn't resumed yet, there is no need to use a
152 * lock, even though kernel threads are active by now.
154 did_suspend
= DEVI(dip
)->devi_cpr_flags
& DCF_CPR_SUSPENDED
;
156 DEVI(dip
)->devi_cpr_flags
&= ~DCF_CPR_SUSPENDED
;
159 * Always attempt to restore device configuration before
162 i_cpr_restore_configuration(dip
);
165 * There may be background attaches happening on devices
166 * that were not originally suspended by cpr, so resume
167 * only devices that were suspended by cpr. Also, stop
168 * resuming after the first resume failure, but traverse
169 * the entire tree to clear the suspend flag unless the
170 * FORCE_SUSPEND_TO_RAM test point is set.
172 if (did_suspend
&& (!error
||
173 cpr_test_point
== FORCE_SUSPEND_TO_RAM
)) {
174 CPR_DEBUG(CPR_DEBUG2
, "Resuming device %s\n",
175 devi_string(dip
, buf
));
177 * If a device suspended by cpr gets detached during
178 * the resume process (for example, due to hotplugging)
179 * before cpr gets around to issuing it a DDI_RESUME,
180 * we'll have problems.
182 if (!i_ddi_devi_attached(dip
)) {
183 CPR_DEBUG(CPR_DEBUG2
, "WARNING: Skipping "
184 "%s, device not ready for resume\n",
185 devi_string(dip
, buf
));
186 cpr_err(CE_WARN
, "Skipping %s, device "
187 "not ready for resume",
188 devi_string(dip
, buf
));
189 } else if (cpr_test_point
!= DEVICE_SUSPEND_TO_RAM
||
190 (cpr_test_point
== DEVICE_SUSPEND_TO_RAM
&&
191 cpr_device
== ddi_driver_major(dip
))) {
192 if (devi_attach(dip
, DDI_RESUME
) !=
199 if (error
== ENXIO
) {
200 CPR_DEBUG(CPR_DEBUG2
,
201 "WARNING: Unable to resume device %s\n",
202 devi_string(dip
, buf
));
203 cpr_err(CE_WARN
, "Unable to resume device %s",
204 devi_string(dip
, buf
));
207 error
= cpr_resume_devices(ddi_get_child(dip
), error
);
215 * Returns a string which contains device name and address.
218 devi_string(dev_info_t
*devi
, char *buf
)
224 name
= ddi_node_name(devi
);
225 address
= ddi_get_name_addr(devi
);
226 size
= (name
== NULL
) ? strlen("<null name>") : strlen(name
);
227 size
+= (address
== NULL
) ? strlen("<null>") : strlen(address
);
230 * Make sure that we don't over-run the buffer.
231 * There are 2 additional characters in the string.
233 ASSERT((size
+ 2) <= CPR_BUFSIZE
);
236 (void) strcpy(buf
, "<null name>");
238 (void) strcpy(buf
, name
);
240 (void) strcat(buf
, "@");
242 (void) strcat(buf
, "<null>");
244 (void) strcat(buf
, address
);
250 * This function determines whether the given device is real (and should
251 * be suspended) or not (pseudo like). If the device has a "reg" property
252 * then it is presumed to have register state to save/restore.
255 cpr_is_real_device(dev_info_t
*dip
)
257 struct regspec
*regbuf
;
261 if (ddi_get_driver(dip
) == NULL
)
265 * First those devices for which special arrangements have been made
267 if (DEVI(dip
)->devi_pm_flags
& (PMC_NEEDS_SR
|PMC_PARENTAL_SR
))
269 if (DEVI(dip
)->devi_pm_flags
& PMC_NO_SR
)
273 * now the general case
275 rc
= ddi_getlongprop(DDI_DEV_T_ANY
, dip
, DDI_PROP_DONTPASS
, "reg",
276 (caddr_t
)®buf
, &length
);
277 ASSERT(rc
!= DDI_PROP_NO_MEMORY
);
278 if (rc
!= DDI_PROP_SUCCESS
) {
281 kmem_free((caddr_t
)regbuf
, length
);