1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #pragma ident "%Z%%M% %I% %E% SMI"
28
29 #include <sys/types.h>
30 #include <sys/kmem.h>
31 #include <sys/async.h>
32 #include <sys/sysmacros.h>
33 #include <sys/sunddi.h>
34 #include <sys/sunndi.h>
35 #include <sys/ddi_impldefs.h>
36 #include <sys/ddi_implfuncs.h>
37 #include <sys/pci/pci_obj.h>
38 #include <sys/pci/pci_pwr.h>
39 #include <sys/pci.h>
40
41 static void pci_pwr_update_comp(pci_pwr_t *pwr_p, pci_pwr_chld_t *p, int comp,
42 int lvl);
43
44 #ifdef DEBUG
45 static char *pci_pwr_bus_label[] = {"PM_LEVEL_B3", "PM_LEVEL_B2", \
46 "PM_LEVEL_B1", "PM_LEVEL_B0"};
47 #endif
48
49 /*LINTLIBRARY*/
50
51 /*
52 * Retreive the pci_pwr_chld_t structure for a given devinfo node.
53 */
54 pci_pwr_chld_t *
pci_pwr_get_info(pci_pwr_t * pwr_p,dev_info_t * dip)55 pci_pwr_get_info(pci_pwr_t *pwr_p, dev_info_t *dip)
56 {
57 pci_pwr_chld_t *p;
58
59 ASSERT(PM_CAPABLE(pwr_p));
60 ASSERT(MUTEX_HELD(&pwr_p->pwr_mutex));
61
62 for (p = pwr_p->pwr_info; p != NULL; p = p->next) {
63 if (p->dip == dip) {
64
65 return (p);
66 }
67 }
68
69 cmn_err(CE_PANIC, "unable to find pwr info data for %s@%s",
70 ddi_node_name(dip), ddi_get_name_addr(dip));
71
72 /*NOTREACHED*/
73 return (NULL);
74 }
75
76 /*
77 * Create a pci_pwr_chld_t structure for a given devinfo node.
78 */
79 void
pci_pwr_create_info(pci_pwr_t * pwr_p,dev_info_t * dip)80 pci_pwr_create_info(pci_pwr_t *pwr_p, dev_info_t *dip)
81 {
82 pci_pwr_chld_t *p;
83
84 ASSERT(PM_CAPABLE(pwr_p));
85
86 DEBUG2(DBG_PWR, ddi_get_parent(dip), "ADDING NEW PWR_INFO %s@%s\n",
87 ddi_node_name(dip), ddi_get_name_addr(dip));
88
89 p = kmem_zalloc(sizeof (struct pci_pwr_chld), KM_SLEEP);
90 p->dip = dip;
91
92 mutex_enter(&pwr_p->pwr_mutex);
93
94 /*
95 * Until components are created for this device, bus
96 * should be at full power since power of child device
97 * is unknown. Increment # children requiring "full power"
98 */
99 p->flags |= PWR_FP_HOLD;
100 pwr_p->pwr_fp++;
101
102 p->next = pwr_p->pwr_info;
103 pwr_p->pwr_info = p;
104
105 pci_pwr_change(pwr_p, pwr_p->current_lvl, pci_pwr_new_lvl(pwr_p));
106
107 mutex_exit(&pwr_p->pwr_mutex);
108 }
109
110 void
pci_pwr_rm_info(pci_pwr_t * pwr_p,dev_info_t * cdip)111 pci_pwr_rm_info(pci_pwr_t *pwr_p, dev_info_t *cdip)
112 {
113 pci_pwr_chld_t **prev_infop;
114 pci_pwr_chld_t *infop = NULL;
115 int i;
116
117 ASSERT(PM_CAPABLE(pwr_p));
118
119 mutex_enter(&pwr_p->pwr_mutex);
120
121 for (prev_infop = &pwr_p->pwr_info; *prev_infop != NULL;
122 prev_infop = &((*prev_infop)->next)) {
123 if ((*prev_infop)->dip == cdip) {
124 infop = *prev_infop;
125 break;
126 }
127 }
128
129 if (infop == NULL) {
130
131 mutex_exit(&pwr_p->pwr_mutex);
132 return;
133 }
134
135 *prev_infop = infop->next;
136
137 /*
138 * Remove any reference counts for this child.
139 */
140 if (infop->comp_pwr != NULL) {
141 for (i = 0; i < infop->num_comps; i++) {
142 pci_pwr_update_comp(pwr_p, infop, i, PM_LEVEL_NOLEVEL);
143 }
144
145 kmem_free(infop->comp_pwr, sizeof (int) * infop->num_comps);
146 }
147
148 if (infop->flags & PWR_FP_HOLD) {
149 pwr_p->pwr_fp--;
150 }
151
152 pci_pwr_change(pwr_p, pwr_p->current_lvl, pci_pwr_new_lvl(pwr_p));
153 mutex_exit(&pwr_p->pwr_mutex);
154 kmem_free(infop, sizeof (struct pci_pwr_chld));
155 }
156
157 /*
158 * Allocate space for component state information in pci_pwr_chld_t
159 */
160 void
pci_pwr_add_components(pci_pwr_t * pwr_p,dev_info_t * cdip,pci_pwr_chld_t * p)161 pci_pwr_add_components(pci_pwr_t *pwr_p, dev_info_t *cdip, pci_pwr_chld_t *p)
162 {
163 int num_comps = PM_NUMCMPTS(cdip);
164 int i;
165
166 ASSERT(MUTEX_HELD(&pwr_p->pwr_mutex));
167 /*
168 * Assume the power level of a component is UNKNOWN until
169 * notified otherwise.
170 */
171 if (num_comps > 0) {
172 p->comp_pwr =
173 kmem_alloc(sizeof (int) * num_comps, KM_SLEEP);
174 p->num_comps = num_comps;
175
176 DEBUG3(DBG_PWR, ddi_get_parent(cdip),
177 "ADDING %d COMPONENTS FOR %s@%s\n", num_comps,
178 ddi_node_name(cdip), ddi_get_name_addr(cdip));
179 } else {
180 cmn_err(CE_WARN, "%s%d device has %d components",
181 ddi_driver_name(cdip), ddi_get_instance(cdip),
182 num_comps);
183
184 return;
185 }
186
187 /*
188 * Release the fp hold that was made when the device
189 * was created.
190 */
191 ASSERT((p->flags & PWR_FP_HOLD) == PWR_FP_HOLD);
192 p->flags &= ~PWR_FP_HOLD;
193 pwr_p->pwr_fp--;
194
195 for (i = 0; i < num_comps; i++) {
196 /*
197 * Initialize the component lvl so that the
198 * state reference counts will be updated correctly.
199 */
200 p->comp_pwr[i] = PM_LEVEL_NOLEVEL;
201 pci_pwr_update_comp(pwr_p, p, i, PM_LEVEL_UNKNOWN);
202 }
203 }
204
205 /*
206 * Update the current power level for component. Then adjust the
207 * bus reference counter for given state.
208 */
209 static void
pci_pwr_update_comp(pci_pwr_t * pwr_p,pci_pwr_chld_t * p,int comp,int lvl)210 pci_pwr_update_comp(pci_pwr_t *pwr_p, pci_pwr_chld_t *p, int comp,
211 int lvl)
212 {
213 ASSERT(MUTEX_HELD(&pwr_p->pwr_mutex));
214
215 /*
216 * Remove old pwr state count for old PM level.
217 */
218 switch (p->comp_pwr[comp]) {
219 case PM_LEVEL_UNKNOWN:
220 pwr_p->pwr_uk--;
221 p->u01--;
222 ASSERT(pwr_p->pwr_uk >= 0);
223 break;
224 case PM_LEVEL_D0:
225 pwr_p->pwr_d0--;
226 p->u01--;
227 ASSERT(pwr_p->pwr_d0 >= 0);
228 break;
229 case PM_LEVEL_D1:
230 pwr_p->pwr_d1--;
231 p->u01--;
232 ASSERT(pwr_p->pwr_d1 >= 0);
233 break;
234 case PM_LEVEL_D2:
235 pwr_p->pwr_d2--;
236 ASSERT(pwr_p->pwr_d2 >= 0);
237 break;
238 case PM_LEVEL_D3:
239 pwr_p->pwr_d3--;
240 ASSERT(pwr_p->pwr_d3 >= 0);
241 break;
242 default:
243 break;
244 }
245
246 p->comp_pwr[comp] = lvl;
247 /*
248 * Add new pwr state count for the new PM level.
249 */
250 switch (lvl) {
251 case PM_LEVEL_UNKNOWN:
252 pwr_p->pwr_uk++;
253 p->u01++;
254 break;
255 case PM_LEVEL_D0:
256 pwr_p->pwr_d0++;
257 p->u01++;
258 break;
259 case PM_LEVEL_D1:
260 pwr_p->pwr_d1++;
261 p->u01++;
262 break;
263 case PM_LEVEL_D2:
264 pwr_p->pwr_d2++;
265 break;
266 case PM_LEVEL_D3:
267 pwr_p->pwr_d3++;
268 break;
269 default:
270 break;
271 }
272
273 }
274
275 /*
276 * Knowing the current state of all devices on the bus, return the
277 * appropriate supported bus speed.
278 */
279 int
pci_pwr_new_lvl(pci_pwr_t * pwr_p)280 pci_pwr_new_lvl(pci_pwr_t *pwr_p)
281 {
282 int b_lvl;
283
284 ASSERT(MUTEX_HELD(&pwr_p->pwr_mutex));
285
286 if (pwr_p->pwr_fp > 0) {
287 DEBUG1(DBG_PWR, pwr_p->pwr_dip, "new_lvl: "
288 "returning PM_LEVEL_B0 pwr_fp = %d\n", pwr_p->pwr_fp);
289
290 return (PM_LEVEL_B0);
291 }
292
293 /*
294 * If any components are at unknown power levels, the
295 * highest power level has to be assumed for the device (D0).
296 */
297 if (pwr_p->pwr_uk > 0) {
298 DEBUG1(DBG_PWR, pwr_p->pwr_dip, "new_lvl: unknown "
299 "count is %d. returning PM_LEVEL_B0\n", pwr_p->pwr_uk);
300
301 return (PM_LEVEL_B0);
302 }
303
304 /*
305 * Find the lowest theoretical level
306 * the bus can operate at.
307 */
308 if (pwr_p->pwr_d0 > 0) {
309 b_lvl = PM_LEVEL_B0;
310 DEBUG1(DBG_PWR, pwr_p->pwr_dip,
311 "new_lvl: PM_LEVEL_B0 d0 count = %d\n",
312 pwr_p->pwr_d0);
313 } else if (pwr_p->pwr_d1 > 0) {
314 b_lvl = PM_LEVEL_B1;
315 DEBUG1(DBG_PWR, pwr_p->pwr_dip,
316 "new_lvl: PM_LEVEL_B1 d1 count = %d\n",
317 pwr_p->pwr_d1);
318 } else if (pwr_p->pwr_d2 > 0) {
319 b_lvl = PM_LEVEL_B2;
320 DEBUG1(DBG_PWR, pwr_p->pwr_dip,
321 "new_lvl: PM_LEVEL_B2 d2 count = %d\n",
322 pwr_p->pwr_d2);
323 } else if (pwr_p->pwr_d3 > 0) {
324 b_lvl = PM_LEVEL_B3;
325 DEBUG1(DBG_PWR, pwr_p->pwr_dip,
326 "new_lvl: PM_LEVEL_B3 d3 count = %d\n",
327 pwr_p->pwr_d3);
328 } else {
329 DEBUG0(DBG_PWR, pwr_p->pwr_dip,
330 "new_lvl: PM_LEVEL_B3: all counts are 0\n");
331 b_lvl = PM_LEVEL_B3;
332 }
333
334 /*
335 * Now find the closest supported level available.
336 * If the level isn't available, have to find the
337 * next highest power level (or lowest in B# terms).
338 */
339 switch (b_lvl) {
340 case PM_LEVEL_B3:
341 if (pwr_p->pwr_flags & PCI_PWR_B3_CAPABLE) {
342 break;
343 }
344 /*FALLTHROUGH*/
345 case PM_LEVEL_B2:
346 if (pwr_p->pwr_flags & PCI_PWR_B2_CAPABLE) {
347 b_lvl = PM_LEVEL_B2;
348 break;
349 }
350 /*FALLTHROUGH*/
351 case PM_LEVEL_B1:
352 if (pwr_p->pwr_flags & PCI_PWR_B1_CAPABLE) {
353 b_lvl = PM_LEVEL_B1;
354 break;
355 }
356 /*FALLTHROUGH*/
357 case PM_LEVEL_B0:
358 /*
359 * This level always supported
360 */
361 b_lvl = PM_LEVEL_B0;
362 break;
363 }
364 DEBUG1(DBG_PWR, pwr_p->pwr_dip,
365 "new_lvl: Adjusted Level is %s\n",
366 pci_pwr_bus_label[b_lvl]);
367
368 return (b_lvl);
369
370 }
371
372 int
pci_raise_power(pci_pwr_t * pwr_p,int current,int new,void * impl_arg,pm_bp_nexus_pwrup_t bpn)373 pci_raise_power(pci_pwr_t *pwr_p, int current, int new, void *impl_arg,
374 pm_bp_nexus_pwrup_t bpn)
375 {
376 int ret = DDI_SUCCESS, pwrup_res;
377
378 ASSERT(MUTEX_HELD(&pwr_p->pwr_mutex));
379
380 pci_pwr_component_busy(pwr_p);
381 mutex_exit(&pwr_p->pwr_mutex);
382 ret = pm_busop_bus_power(pwr_p->pwr_dip, impl_arg,
383 BUS_POWER_NEXUS_PWRUP, (void *) &bpn,
384 (void *) &pwrup_res);
385 if (ret != DDI_SUCCESS || pwrup_res != DDI_SUCCESS) {
386 mutex_enter(&pwr_p->pwr_mutex);
387 pci_pwr_component_idle(pwr_p);
388 mutex_exit(&pwr_p->pwr_mutex);
389 cmn_err(CE_WARN, "%s%d pci_raise_power failed",
390 ddi_driver_name(pwr_p->pwr_dip),
391 ddi_get_instance(pwr_p->pwr_dip));
392 }
393
394 return (ret);
395 }
396
397 int
pci_pwr_ops(pci_pwr_t * pwr_p,dev_info_t * dip,void * impl_arg,pm_bus_power_op_t op,void * arg,void * result)398 pci_pwr_ops(pci_pwr_t *pwr_p, dev_info_t *dip, void *impl_arg,
399 pm_bus_power_op_t op, void *arg, void *result)
400 {
401 pci_pwr_chld_t *p_chld;
402 pm_bp_nexus_pwrup_t bpn;
403 pm_bp_child_pwrchg_t *bpc = (pm_bp_child_pwrchg_t *)arg;
404 dev_info_t *rdip = bpc->bpc_dip;
405 int new_level, *res = (int *)result, ret = DDI_SUCCESS;
406
407 mutex_enter(&pwr_p->pwr_mutex);
408 switch (op) {
409 case BUS_POWER_HAS_CHANGED:
410 p_chld = pci_pwr_get_info(pwr_p, rdip);
411 DEBUG5(DBG_PWR, dip, "%s@%s CHANGED_POWER cmp = %d "
412 "old = %d new = %d\n",
413 ddi_node_name(rdip), ddi_get_name_addr(rdip),
414 bpc->bpc_comp, bpc->bpc_olevel, bpc->bpc_nlevel);
415
416 if (*res == DDI_FAILURE) {
417 DEBUG0(DBG_PWR, rdip, "changed_power_req FAILED\n");
418 break;
419 } else {
420
421 /*
422 * pci_pwr_add_components must be called here if
423 * comp_pwr hasn't been set up yet. It has to be done
424 * here rather than in post-attach, since it is possible
425 * for power() of child to get called before attach
426 * completes.
427 */
428 if (p_chld->comp_pwr == NULL)
429 pci_pwr_add_components(pwr_p, rdip, p_chld);
430
431 pci_pwr_update_comp(pwr_p, p_chld,
432 bpc->bpc_comp, bpc->bpc_nlevel);
433 }
434
435 new_level = pci_pwr_new_lvl(pwr_p);
436 bpn.bpn_dip = pwr_p->pwr_dip;
437 bpn.bpn_comp = PCI_PM_COMP_0;
438 bpn.bpn_level = new_level;
439 bpn.bpn_private = bpc->bpc_private;
440
441 if (new_level > pwr_p->current_lvl)
442 return (pci_raise_power(pwr_p, pwr_p->current_lvl,
443 new_level, impl_arg, bpn));
444 else
445 pci_pwr_change(pwr_p, pwr_p->current_lvl,
446 new_level);
447 break;
448
449 case BUS_POWER_PRE_NOTIFICATION:
450 DEBUG5(DBG_PWR, dip, "PRE %s@%s cmp = %d old = %d "
451 "new = %d. TEMP FULL POWER\n",
452 ddi_node_name(rdip), ddi_get_name_addr(rdip),
453 bpc->bpc_comp, bpc->bpc_olevel, bpc->bpc_nlevel);
454
455 /*
456 * Any state changes require that the bus be at full
457 * power (B0) so that the device configuration
458 * registers can be accessed. Make a fp hold here
459 * so device remains at full power during power
460 * configuration.
461 */
462
463 pwr_p->pwr_fp++;
464 DEBUG1(DBG_PWR, pwr_p->pwr_dip,
465 "incremented fp is %d in PRE_NOTE\n\n", pwr_p->pwr_fp);
466
467 bpn.bpn_dip = pwr_p->pwr_dip;
468 bpn.bpn_comp = PCI_PM_COMP_0;
469 bpn.bpn_level = PM_LEVEL_B0;
470 bpn.bpn_private = bpc->bpc_private;
471
472 if (PM_LEVEL_B0 > pwr_p->current_lvl)
473 return (pci_raise_power(pwr_p, pwr_p->current_lvl,
474 PM_LEVEL_B0, impl_arg, bpn));
475
476 break;
477
478 case BUS_POWER_POST_NOTIFICATION:
479 p_chld = pci_pwr_get_info(pwr_p, rdip);
480 DEBUG5(DBG_PWR, dip, "POST %s@%s cmp = %d old = %d new = %d\n",
481 ddi_node_name(rdip), ddi_get_name_addr(rdip),
482 bpc->bpc_comp, bpc->bpc_olevel, bpc->bpc_nlevel);
483
484 if (*res == DDI_FAILURE) {
485 DEBUG0(DBG_PWR, rdip, "child's power routine FAILED\n");
486 } else {
487
488 /*
489 * pci_pwr_add_components must be called here if
490 * comp_pwr hasen't been set up yet. It has to be done
491 * here rather than in post-attach, since it is possible
492 * for power() of child to get called before attach
493 * completes.
494 */
495 if (p_chld->comp_pwr == NULL)
496 pci_pwr_add_components(pwr_p, rdip, p_chld);
497
498 pci_pwr_update_comp(pwr_p, p_chld,
499 bpc->bpc_comp, bpc->bpc_nlevel);
500
501 }
502
503 pwr_p->pwr_fp--;
504 DEBUG1(DBG_PWR, pwr_p->pwr_dip,
505 "decremented fp is %d in POST_NOTE\n\n", pwr_p->pwr_fp);
506
507 new_level = pci_pwr_new_lvl(pwr_p);
508 bpn.bpn_dip = pwr_p->pwr_dip;
509 bpn.bpn_comp = PCI_PM_COMP_0;
510 bpn.bpn_level = new_level;
511 bpn.bpn_private = bpc->bpc_private;
512
513 if (new_level > pwr_p->current_lvl)
514 return (pci_raise_power(pwr_p, pwr_p->current_lvl,
515 new_level, impl_arg, bpn));
516 else
517 pci_pwr_change(pwr_p, pwr_p->current_lvl,
518 new_level);
519
520 break;
521 default:
522 mutex_exit(&pwr_p->pwr_mutex);
523 return (pm_busop_bus_power(dip, impl_arg, op, arg, result));
524 }
525
526 mutex_exit(&pwr_p->pwr_mutex);
527
528 return (ret);
529 }
530
531 void
pci_pwr_resume(dev_info_t * dip,pci_pwr_t * pwr_p)532 pci_pwr_resume(dev_info_t *dip, pci_pwr_t *pwr_p)
533 {
534 dev_info_t *cdip;
535
536 /*
537 * Inform the PM framework of the current state of the device.
538 * (it is unknown to PM framework at this point).
539 */
540 if (PM_CAPABLE(pwr_p)) {
541 pwr_p->current_lvl = pci_pwr_current_lvl(pwr_p);
542 pm_power_has_changed(dip, PCI_PM_COMP_0,
543 pwr_p->current_lvl);
544 }
545
546 /*
547 * Restore config registers for children that did not save
548 * their own registers. Children pwr states are UNKNOWN after
549 * a resume since it is possible for the PM framework to call
550 * resume without an actual power cycle. (ie if suspend fails).
551 */
552 for (cdip = ddi_get_child(dip); cdip != NULL;
553 cdip = ddi_get_next_sibling(cdip)) {
554
555 /*
556 * Not interested in children who are not already
557 * init'ed. They will be set up by init_child().
558 */
559 if (i_ddi_node_state(cdip) < DS_INITIALIZED) {
560 DEBUG2(DBG_DETACH, dip,
561 "DDI_RESUME: skipping %s%d not in CF1\n",
562 ddi_driver_name(cdip), ddi_get_instance(cdip));
563
564 continue;
565 }
566
567 /*
568 * Only restore config registers if saved by nexus.
569 */
570 if (ddi_prop_exists(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS,
571 NEXUS_SAVED) == 1) {
572 (void) pci_restore_config_regs(cdip);
573
574 DEBUG2(DBG_PWR, dip,
575 "DDI_RESUME: nexus restoring %s%d config regs\n",
576 ddi_driver_name(cdip), ddi_get_instance(cdip));
577
578
579 if (ndi_prop_remove(DDI_DEV_T_NONE, cdip,
580 NEXUS_SAVED) != DDI_PROP_SUCCESS) {
581 cmn_err(CE_WARN, "%s%d can't remove prop %s",
582 ddi_driver_name(cdip),
583 ddi_get_instance(cdip),
584 NEXUS_SAVED);
585 }
586 }
587 }
588 }
589
590 void
pci_pwr_suspend(dev_info_t * dip,pci_pwr_t * pwr_p)591 pci_pwr_suspend(dev_info_t *dip, pci_pwr_t *pwr_p)
592 {
593 dev_info_t *cdip;
594
595 /*
596 * Save the state of the configuration headers of child
597 * nodes.
598 */
599
600 for (cdip = ddi_get_child(dip); cdip != NULL;
601 cdip = ddi_get_next_sibling(cdip)) {
602 pci_pwr_chld_t *p;
603 int i;
604 int num_comps;
605 int ret;
606 /*
607 * Not interested in children who are not already
608 * init'ed. They will be set up in init_child().
609 */
610 if (i_ddi_node_state(cdip) < DS_INITIALIZED) {
611 DEBUG2(DBG_DETACH, dip, "DDI_SUSPEND: skipping "
612 "%s%d not in CF1\n", ddi_driver_name(cdip),
613 ddi_get_instance(cdip));
614
615 continue;
616 }
617
618 /*
619 * Only save config registers if not already saved by child.
620 */
621 if (ddi_prop_exists(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS,
622 SAVED_CONFIG_REGS) == 1) {
623
624 continue;
625 }
626
627 /*
628 * The nexus needs to save config registers. Create a property
629 * so it knows to restore on resume.
630 */
631 ret = ndi_prop_create_boolean(DDI_DEV_T_NONE, cdip,
632 NEXUS_SAVED);
633
634 if (ret != DDI_PROP_SUCCESS) {
635 cmn_err(CE_WARN, "%s%d can't update prop %s",
636 ddi_driver_name(cdip), ddi_get_instance(cdip),
637 NEXUS_SAVED);
638 }
639
640 if (!PM_CAPABLE(pwr_p)) {
641 (void) pci_save_config_regs(cdip);
642
643 continue;
644 }
645
646 mutex_enter(&pwr_p->pwr_mutex);
647 p = pci_pwr_get_info(pwr_p, cdip);
648 num_comps = p->num_comps;
649
650 /*
651 * If a device has components, reset the power level
652 * to unknown. This will ensure that the bus is full
653 * power so that saving register won't panic (if
654 * the device is already powered off, the child should
655 * have already done the save, but an incorrect driver
656 * may have forgotten). If resetting power levels
657 * to unknown isn't done here, it would have to be done
658 * in resume since pci driver has no way of knowing
659 * actual state of HW (power cycle may not have
660 * occurred, and it was decided that poking into a
661 * child's config space should be avoided unless
662 * absolutely necessary).
663 */
664 if (p->comp_pwr == NULL) {
665 (void) pci_save_config_regs(cdip);
666 } else {
667
668 for (i = 0; i < num_comps; i++) {
669 pci_pwr_update_comp(pwr_p, p, i,
670 PM_LEVEL_UNKNOWN);
671 }
672 /*
673 * ensure bus power is on before saving
674 * config regs.
675 */
676 pci_pwr_change(pwr_p, pwr_p->current_lvl,
677 pci_pwr_new_lvl(pwr_p));
678
679 (void) pci_save_config_regs(cdip);
680 }
681 mutex_exit(&pwr_p->pwr_mutex);
682 }
683 }
684
685 void
pci_pwr_component_busy(pci_pwr_t * p)686 pci_pwr_component_busy(pci_pwr_t *p)
687 {
688 ASSERT(MUTEX_HELD(&p->pwr_mutex));
689 if ((p->pwr_flags & PCI_PWR_COMP_BUSY) == 0) {
690 if (pm_busy_component(p->pwr_dip, PCI_PM_COMP_0) ==
691 DDI_FAILURE) {
692 cmn_err(CE_WARN,
693 "%s%d pm_busy_component failed",
694 ddi_driver_name(p->pwr_dip),
695 ddi_get_instance(p->pwr_dip));
696 } else {
697 DEBUG0(DBG_PWR, p->pwr_dip,
698 "called PM_BUSY_COMPONENT(). BUSY BIT SET\n");
699 p->pwr_flags |= PCI_PWR_COMP_BUSY;
700 }
701 } else {
702 DEBUG0(DBG_PWR, p->pwr_dip, "BUSY BIT ALREADY SET\n");
703 }
704 }
705
706 void
pci_pwr_component_idle(pci_pwr_t * p)707 pci_pwr_component_idle(pci_pwr_t *p)
708 {
709 ASSERT(MUTEX_HELD(&p->pwr_mutex));
710 if (p->pwr_flags & PCI_PWR_COMP_BUSY) {
711 if (pm_idle_component(p->pwr_dip, PCI_PM_COMP_0) ==
712 DDI_FAILURE) {
713 cmn_err(CE_WARN,
714 "%s%d pm_idle_component failed",
715 ddi_driver_name(p->pwr_dip),
716 ddi_get_instance(p->pwr_dip));
717 } else {
718 DEBUG0(DBG_PWR, p->pwr_dip,
719 "called PM_IDLE_COMPONENT() BUSY BIT CLEARED\n");
720 p->pwr_flags &= ~PCI_PWR_COMP_BUSY;
721 }
722 } else {
723 DEBUG0(DBG_PWR, p->pwr_dip, "BUSY BIT ALREADY CLEARED\n");
724 }
725 }
726
727 void
pci_pwr_change(pci_pwr_t * pwr_p,int current,int new)728 pci_pwr_change(pci_pwr_t *pwr_p, int current, int new)
729 {
730 ASSERT(MUTEX_HELD(&pwr_p->pwr_mutex));
731 if (current == new) {
732 DEBUG2(DBG_PWR, pwr_p->pwr_dip,
733 "No change in power required. Should be "
734 "busy. (current=%d) == (new=%d)\n",
735 current, new);
736 pci_pwr_component_busy(pwr_p);
737
738 return;
739 }
740
741 if (new < current) {
742 DEBUG2(DBG_PWR, pwr_p->pwr_dip,
743 "should be idle (new=%d) < (current=%d)\n",
744 new, current);
745 pci_pwr_component_idle(pwr_p);
746
747 return;
748 }
749
750 if (new > current) {
751 DEBUG2(DBG_PWR, pwr_p->pwr_dip, "pwr_change: "
752 "pm_raise_power() and should be busy. "
753 "(new=%d) > (current=%d)\n", new, current);
754 pci_pwr_component_busy(pwr_p);
755 mutex_exit(&pwr_p->pwr_mutex);
756 if (pm_raise_power(pwr_p->pwr_dip, PCI_PM_COMP_0,
757 new) == DDI_FAILURE) {
758 cmn_err(CE_WARN, "%s%d pm_raise_power failed",
759 ddi_driver_name(pwr_p->pwr_dip),
760 ddi_get_instance(pwr_p->pwr_dip));
761 }
762 mutex_enter(&pwr_p->pwr_mutex);
763
764 return;
765 }
766 }
767