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.
57 extern void i_cpr_save_configuration(dev_info_t
*);
58 extern void i_cpr_restore_configuration(dev_info_t
*);
62 * Traverse the dev info tree:
63 * Call each device driver in the system via a special case
64 * of the detach() entry point to quiesce itself.
65 * Suspend children first.
67 * We only suspend/resume real devices.
71 cpr_suspend_devices(dev_info_t
*dip
)
74 char buf
[CPR_BUFSIZE
];
76 for (; dip
!= NULL
; dip
= ddi_get_next_sibling(dip
)) {
77 if (cpr_suspend_devices(ddi_get_child(dip
)))
79 if (!cpr_is_real_device(dip
))
81 CPR_DEBUG(CPR_DEBUG2
, "Suspending device %s\n",
82 devi_string(dip
, buf
));
83 ASSERT((DEVI(dip
)->devi_cpr_flags
& DCF_CPR_SUSPENDED
) == 0);
86 i_cpr_save_configuration(dip
);
90 if (!i_ddi_devi_attached(dip
)) {
94 if (cpr_test_point
!= DEVICE_SUSPEND_TO_RAM
||
95 (cpr_test_point
== DEVICE_SUSPEND_TO_RAM
&&
96 cpr_device
== ddi_driver_major(dip
))) {
98 error
= devi_detach(dip
, DDI_SUSPEND
);
106 if (error
== DDI_SUCCESS
) {
107 DEVI(dip
)->devi_cpr_flags
|= DCF_CPR_SUSPENDED
;
111 CPR_DEBUG(CPR_DEBUG2
,
112 "WARNING: Unable to suspend device %s\n",
113 devi_string(dip
, buf
));
114 cpr_err(CE_WARN
, "Unable to suspend device %s.",
115 devi_string(dip
, buf
));
116 cpr_err(CE_WARN
, "Device is busy or does not "
117 "support suspend/resume.");
120 * the device has failed to suspend however,
121 * if cpr_test_point == FORCE_SUSPEND_TO_RAM
122 * after putting out the warning message above,
123 * we carry on as if suspending the device had
126 if (cpr_test_point
== FORCE_SUSPEND_TO_RAM
)
127 DEVI(dip
)->devi_cpr_flags
|= DCF_CPR_SUSPENDED
;
137 * Traverse the dev info tree:
138 * Call each device driver in the system via a special case
139 * of the attach() entry point to restore itself.
140 * This is a little tricky because it has to reverse the traversal
141 * order of cpr_suspend_devices().
144 cpr_resume_devices(dev_info_t
*start
, int resume_failed
)
146 dev_info_t
*dip
, *next
, *last
= NULL
;
148 int error
= resume_failed
;
149 char buf
[CPR_BUFSIZE
];
151 while (last
!= start
) {
153 next
= ddi_get_next_sibling(dip
);
154 while (next
!= last
) {
156 next
= ddi_get_next_sibling(dip
);
160 * cpr is the only one that uses this field and the device
161 * itself hasn't resumed yet, there is no need to use a
162 * lock, even though kernel threads are active by now.
164 did_suspend
= DEVI(dip
)->devi_cpr_flags
& DCF_CPR_SUSPENDED
;
166 DEVI(dip
)->devi_cpr_flags
&= ~DCF_CPR_SUSPENDED
;
169 * Always attempt to restore device configuration before
173 i_cpr_restore_configuration(dip
);
177 * There may be background attaches happening on devices
178 * that were not originally suspended by cpr, so resume
179 * only devices that were suspended by cpr. Also, stop
180 * resuming after the first resume failure, but traverse
181 * the entire tree to clear the suspend flag unless the
182 * FORCE_SUSPEND_TO_RAM test point is set.
185 if (did_suspend
&& (!error
||
186 cpr_test_point
== FORCE_SUSPEND_TO_RAM
)) {
188 if (did_suspend
&& !error
) {
190 CPR_DEBUG(CPR_DEBUG2
, "Resuming device %s\n",
191 devi_string(dip
, buf
));
193 * If a device suspended by cpr gets detached during
194 * the resume process (for example, due to hotplugging)
195 * before cpr gets around to issuing it a DDI_RESUME,
196 * we'll have problems.
198 if (!i_ddi_devi_attached(dip
)) {
199 CPR_DEBUG(CPR_DEBUG2
, "WARNING: Skipping "
200 "%s, device not ready for resume\n",
201 devi_string(dip
, buf
));
202 cpr_err(CE_WARN
, "Skipping %s, device "
203 "not ready for resume",
204 devi_string(dip
, buf
));
206 } else if (cpr_test_point
!= DEVICE_SUSPEND_TO_RAM
||
207 (cpr_test_point
== DEVICE_SUSPEND_TO_RAM
&&
208 cpr_device
== ddi_driver_major(dip
))) {
212 if (devi_attach(dip
, DDI_RESUME
) !=
219 if (error
== ENXIO
) {
220 CPR_DEBUG(CPR_DEBUG2
,
221 "WARNING: Unable to resume device %s\n",
222 devi_string(dip
, buf
));
223 cpr_err(CE_WARN
, "Unable to resume device %s",
224 devi_string(dip
, buf
));
227 error
= cpr_resume_devices(ddi_get_child(dip
), error
);
235 * Returns a string which contains device name and address.
238 devi_string(dev_info_t
*devi
, char *buf
)
244 name
= ddi_node_name(devi
);
245 address
= ddi_get_name_addr(devi
);
246 size
= (name
== NULL
) ? strlen("<null name>") : strlen(name
);
247 size
+= (address
== NULL
) ? strlen("<null>") : strlen(address
);
250 * Make sure that we don't over-run the buffer.
251 * There are 2 additional characters in the string.
253 ASSERT((size
+ 2) <= CPR_BUFSIZE
);
256 (void) strcpy(buf
, "<null name>");
258 (void) strcpy(buf
, name
);
260 (void) strcat(buf
, "@");
262 (void) strcat(buf
, "<null>");
264 (void) strcat(buf
, address
);
270 * This function determines whether the given device is real (and should
271 * be suspended) or not (pseudo like). If the device has a "reg" property
272 * then it is presumed to have register state to save/restore.
275 cpr_is_real_device(dev_info_t
*dip
)
277 struct regspec
*regbuf
;
281 if (ddi_get_driver(dip
) == NULL
)
285 * First those devices for which special arrangements have been made
287 if (DEVI(dip
)->devi_pm_flags
& (PMC_NEEDS_SR
|PMC_PARENTAL_SR
))
289 if (DEVI(dip
)->devi_pm_flags
& PMC_NO_SR
)
293 * now the general case
295 rc
= ddi_getlongprop(DDI_DEV_T_ANY
, dip
, DDI_PROP_DONTPASS
, "reg",
296 (caddr_t
)®buf
, &length
);
297 ASSERT(rc
!= DDI_PROP_NO_MEMORY
);
298 if (rc
!= DDI_PROP_SUCCESS
) {
301 kmem_free((caddr_t
)regbuf
, length
);