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 (the "License").
6  * You may not use this file except in compliance with the License.
7  *
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.
12  *
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]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 /*
29  * CMU-CH nexus utility routines:
30  *	property and config routines for attach()
31  *	reg/intr/range/assigned-address property routines for bus_map()
32  *	init_child()
33  *	fault handling
34  *	debug functions
35  */
36 
37 #include <sys/types.h>
38 #include <sys/kmem.h>
39 #include <sys/async.h>
40 #include <sys/sysmacros.h>
41 #include <sys/sunddi.h>
42 #include <sys/sunndi.h>
43 #include <sys/fm/protocol.h>
44 #include <sys/fm/io/pci.h>
45 #include <sys/fm/util.h>
46 #include <sys/ddi_impldefs.h>
47 #include <sys/pcicmu/pcicmu.h>
48 #include <sys/promif.h>
49 
50 /*LINTLIBRARY*/
51 
52 /*
53  * get_pcmu_properties
54  *
55  * This function is called from the attach routine to get the key
56  * properties of the pci nodes.
57  *
58  * used by: pcmu_attach()
59  *
60  * return value: DDI_FAILURE on failure
61  */
62 int
63 get_pcmu_properties(pcmu_t *pcmu_p, dev_info_t *dip)
64 {
65 	int i;
66 
67 	/*
68 	 * Get the device's port id.
69 	 */
70 	if ((pcmu_p->pcmu_id = (uint32_t)pcmu_get_portid(dip)) == -1u) {
71 		cmn_err(CE_WARN, "%s%d: no portid property\n",
72 		    ddi_driver_name(dip), ddi_get_instance(dip));
73 		return (DDI_FAILURE);
74 	}
75 
76 	/*
77 	 * Get the bus-ranges property.
78 	 */
79 	i = sizeof (pcmu_p->pcmu_bus_range);
80 	if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
81 	    "bus-range", (caddr_t)&pcmu_p->pcmu_bus_range, &i) != DDI_SUCCESS) {
82 		cmn_err(CE_WARN, "%s%d: no bus-range property\n",
83 		    ddi_driver_name(dip), ddi_get_instance(dip));
84 		return (DDI_FAILURE);
85 	}
86 	PCMU_DBG2(PCMU_DBG_ATTACH, dip,
87 	    "get_pcmu_properties: bus-range (%x,%x)\n",
88 	    pcmu_p->pcmu_bus_range.lo, pcmu_p->pcmu_bus_range.hi);
89 
90 	/*
91 	 * Get the ranges property.
92 	 */
93 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "ranges",
94 	    (caddr_t)&pcmu_p->pcmu_ranges, &pcmu_p->pcmu_ranges_length) !=
95 	    DDI_SUCCESS) {
96 		cmn_err(CE_WARN, "%s%d: no ranges property\n",
97 		    ddi_driver_name(dip), ddi_get_instance(dip));
98 		return (DDI_FAILURE);
99 	}
100 	pcmu_fix_ranges(pcmu_p->pcmu_ranges,
101 	    pcmu_p->pcmu_ranges_length / sizeof (pcmu_ranges_t));
102 
103 	/*
104 	 * Determine the number upa slot interrupts.
105 	 */
106 	pcmu_p->pcmu_numproxy = pcmu_get_numproxy(pcmu_p->pcmu_dip);
107 	PCMU_DBG1(PCMU_DBG_ATTACH, dip, "get_pcmu_properties: numproxy=%d\n",
108 	    pcmu_p->pcmu_numproxy);
109 	return (DDI_SUCCESS);
110 }
111 
112 /*
113  * free_pcmu_properties:
114  *
115  * This routine frees the memory used to cache the
116  * "ranges" properties of the pci bus device node.
117  *
118  * used by: pcmu_detach()
119  *
120  * return value: none
121  */
122 void
123 free_pcmu_properties(pcmu_t *pcmu_p)
124 {
125 	kmem_free(pcmu_p->pcmu_ranges, pcmu_p->pcmu_ranges_length);
126 }
127 
128 /*
129  * pcmu_reloc_reg
130  *
131  * If the "reg" entry (*pcmu_rp) is relocatable, lookup "assigned-addresses"
132  * property to fetch corresponding relocated address.
133  *
134  * used by: pcmu_map()
135  *
136  * return value:
137  *
138  *	DDI_SUCCESS		- on success
139  *	DDI_ME_INVAL		- regspec is invalid
140  */
141 int
142 pcmu_reloc_reg(dev_info_t *dip, dev_info_t *rdip, pcmu_t *pcmu_p,
143 	pci_regspec_t *rp)
144 {
145 	int assign_len, assign_entries, i;
146 	pci_regspec_t *assign_p;
147 	register uint32_t phys_hi = rp->pci_phys_hi;
148 	register uint32_t mask = PCI_REG_ADDR_M | PCI_CONF_ADDR_MASK;
149 	register uint32_t phys_addr = phys_hi & mask;
150 
151 	PCMU_DBG5(PCMU_DBG_MAP | PCMU_DBG_CONT, dip,
152 	    "\tpcmu_reloc_reg fr: %x.%x.%x %x.%x\n",
153 	    rp->pci_phys_hi, rp->pci_phys_mid, rp->pci_phys_low,
154 	    rp->pci_size_hi, rp->pci_size_low);
155 
156 	if ((phys_hi & PCI_RELOCAT_B) || !(phys_hi & PCI_ADDR_MASK)) {
157 		return (DDI_SUCCESS);
158 	}
159 
160 	/* phys_mid must be 0 regardless space type. XXX-64 bit mem space */
161 	if (rp->pci_phys_mid != 0 || rp->pci_size_hi != 0) {
162 		PCMU_DBG0(PCMU_DBG_MAP | PCMU_DBG_CONT, pcmu_p->pcmu_dip,
163 		    "phys_mid or size_hi not 0\n");
164 		return (DDI_ME_INVAL);
165 	}
166 
167 	if (ddi_getlongprop(DDI_DEV_T_ANY, rdip, DDI_PROP_DONTPASS,
168 	    "assigned-addresses", (caddr_t)&assign_p, &assign_len)) {
169 		return (DDI_ME_INVAL);
170 	}
171 
172 	assign_entries = assign_len / sizeof (pci_regspec_t);
173 	for (i = 0; i < assign_entries; i++, assign_p++) {
174 		if ((assign_p->pci_phys_hi & mask) == phys_addr) {
175 			rp->pci_phys_low += assign_p->pci_phys_low;
176 			break;
177 		}
178 	}
179 	kmem_free(assign_p - i, assign_len);
180 	PCMU_DBG5(PCMU_DBG_MAP | PCMU_DBG_CONT, dip,
181 	    "\tpcmu_reloc_reg to: %x.%x.%x %x.%x\n",
182 	    rp->pci_phys_hi, rp->pci_phys_mid, rp->pci_phys_low,
183 	    rp->pci_size_hi, rp->pci_size_low);
184 	return (i < assign_entries ? DDI_SUCCESS : DDI_ME_INVAL);
185 }
186 
187 /*
188  * use "ranges" to translate relocated pci regspec into parent space
189  */
190 int
191 pcmu_xlate_reg(pcmu_t *pcmu_p, pci_regspec_t *pcmu_rp, struct regspec *new_rp)
192 {
193 	int n;
194 	pcmu_ranges_t *rng_p = pcmu_p->pcmu_ranges;
195 	int rng_n = pcmu_p->pcmu_ranges_length / sizeof (pcmu_ranges_t);
196 
197 	uint32_t space_type = PCI_REG_ADDR_G(pcmu_rp->pci_phys_hi);
198 	uint32_t reg_end, reg_begin = pcmu_rp->pci_phys_low;
199 	uint32_t sz = pcmu_rp->pci_size_low;
200 
201 	uint32_t rng_begin, rng_end;
202 
203 	if (space_type == PCI_REG_ADDR_G(PCI_ADDR_CONFIG)) {
204 		if (reg_begin > PCI_CONF_HDR_SIZE) {
205 			return (DDI_ME_INVAL);
206 		}
207 		sz = sz ? MIN(sz, PCI_CONF_HDR_SIZE) : PCI_CONF_HDR_SIZE;
208 		reg_begin += pcmu_rp->pci_phys_hi;
209 	}
210 	reg_end = reg_begin + sz - 1;
211 
212 	for (n = 0; n < rng_n; n++, rng_p++) {
213 		if (space_type != PCI_REG_ADDR_G(rng_p->child_high)) {
214 			continue;	/* not the same space type */
215 		}
216 
217 		rng_begin = rng_p->child_low;
218 		if (space_type == PCI_REG_ADDR_G(PCI_ADDR_CONFIG)) {
219 			rng_begin += rng_p->child_high;
220 		}
221 		rng_end = rng_begin + rng_p->size_low - 1;
222 		if (reg_begin >= rng_begin && reg_end <= rng_end) {
223 			break;
224 		}
225 	}
226 	if (n >= rng_n) {
227 		return (DDI_ME_REGSPEC_RANGE);
228 	}
229 
230 	new_rp->regspec_addr = reg_begin - rng_begin + rng_p->parent_low;
231 	new_rp->regspec_bustype = rng_p->parent_high;
232 	new_rp->regspec_size = sz;
233 	PCMU_DBG4(PCMU_DBG_MAP | PCMU_DBG_CONT, pcmu_p->pcmu_dip,
234 	    "\tpcmu_xlate_reg: entry %d new_rp %x.%x %x\n",
235 	    n, new_rp->regspec_bustype, new_rp->regspec_addr, sz);
236 	return (DDI_SUCCESS);
237 }
238 
239 
240 /*
241  * pcmu_report_dev
242  *
243  * This function is called from our control ops routine on a
244  * DDI_CTLOPS_REPORTDEV request.
245  *
246  * The display format is
247  *
248  *	<name><inst> at <pname><pinst> device <dev> function <func>
249  *
250  * where
251  *
252  *	<name>		this device's name property
253  *	<inst>		this device's instance number
254  *	<name>		parent device's name property
255  *	<inst>		parent device's instance number
256  *	<dev>		this device's device number
257  *	<func>		this device's function number
258  */
259 int
260 pcmu_report_dev(dev_info_t *dip)
261 {
262 	if (dip == (dev_info_t *)0) {
263 		return (DDI_FAILURE);
264 	}
265 	cmn_err(CE_CONT, "?PCI-device: %s@%s, %s%d\n", ddi_node_name(dip),
266 	    ddi_get_name_addr(dip), ddi_driver_name(dip),
267 	    ddi_get_instance(dip));
268 	return (DDI_SUCCESS);
269 }
270 
271 /*
272  * name_child
273  *
274  * This function is called from pcmu_init_child to name a node. It is
275  * also passed as a callback for node merging functions.
276  *
277  * return value: DDI_SUCCESS, DDI_FAILURE
278  */
279 static int
280 name_child(dev_info_t *child, char *name, int namelen)
281 {
282 	pci_regspec_t *pcmu_rp;
283 	int reglen;
284 	uint_t func;
285 	char **unit_addr;
286 	uint_t n;
287 
288 	/*
289 	 * Set the address portion of the node name based on
290 	 * unit-address property, if it exists.
291 	 * The interpretation of the unit-address is DD[,F]
292 	 * where DD is the device id and F is the function.
293 	 */
294 	if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, child,
295 	    DDI_PROP_DONTPASS, "unit-address", &unit_addr, &n) ==
296 	    DDI_PROP_SUCCESS) {
297 		if (n != 1 || *unit_addr == NULL || **unit_addr == 0) {
298 			cmn_err(CE_WARN, "unit-address property in %s.conf"
299 			    " not well-formed", ddi_driver_name(child));
300 			ddi_prop_free(unit_addr);
301 			return (DDI_FAILURE);
302 		}
303 		(void) snprintf(name, namelen, "%s", *unit_addr);
304 		ddi_prop_free(unit_addr);
305 		return (DDI_SUCCESS);
306 	}
307 
308 	/*
309 	 * The unit-address property is does not exist. Set the address
310 	 * portion of the node name based on the function and device number.
311 	 */
312 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
313 	    "reg", (int **)&pcmu_rp, (uint_t *)&reglen) == DDI_SUCCESS) {
314 		if (((reglen * sizeof (int)) % sizeof (pci_regspec_t)) != 0) {
315 			cmn_err(CE_WARN, "reg property not well-formed");
316 			return (DDI_FAILURE);
317 		}
318 
319 		func = PCI_REG_FUNC_G(pcmu_rp[0].pci_phys_hi);
320 		if (func != 0) {
321 			(void) snprintf(name, namelen, "%x,%x",
322 				PCI_REG_DEV_G(pcmu_rp[0].pci_phys_hi), func);
323 		} else {
324 			(void) snprintf(name, namelen, "%x",
325 				PCI_REG_DEV_G(pcmu_rp[0].pci_phys_hi));
326 		}
327 		ddi_prop_free(pcmu_rp);
328 		return (DDI_SUCCESS);
329 	}
330 	cmn_err(CE_WARN, "cannot name pci child '%s'", ddi_node_name(child));
331 	return (DDI_FAILURE);
332 }
333 
334 int
335 pcmu_uninit_child(pcmu_t *pcmu_p, dev_info_t *child)
336 {
337 	PCMU_DBG2(PCMU_DBG_CTLOPS, pcmu_p->pcmu_dip,
338 	    "DDI_CTLOPS_UNINITCHILD: arg=%s%d\n",
339 	    ddi_driver_name(child), ddi_get_instance(child));
340 
341 	ddi_set_name_addr(child, NULL);
342 	ddi_remove_minor_node(child, NULL);
343 	impl_rem_dev_props(child);
344 
345 	PCMU_DBG0(PCMU_DBG_PWR, ddi_get_parent(child), "\n\n");
346 	return (DDI_SUCCESS);
347 }
348 
349 /*
350  * pcmu_init_child
351  *
352  * This function is called from our control ops routine on a
353  * DDI_CTLOPS_INITCHILD request.  It builds and sets the device's
354  * parent private data area.
355  *
356  * used by: pcmu_ctlops()
357  *
358  * return value: none
359  */
360 int
361 pcmu_init_child(pcmu_t *pcmu_p, dev_info_t *child)
362 {
363 	char name[10];
364 	ddi_acc_handle_t config_handle;
365 	uint8_t bcr;
366 	uint8_t header_type;
367 
368 	if (name_child(child, name, 10) != DDI_SUCCESS)
369 		return (DDI_FAILURE);
370 	ddi_set_name_addr(child, name);
371 
372 	PCMU_DBG2(PCMU_DBG_PWR, ddi_get_parent(child),
373 	    "INITCHILD: config regs setup for %s@%s\n",
374 	    ddi_node_name(child), ddi_get_name_addr(child));
375 
376 	/*
377 	 * Map the child configuration space to for initialization.
378 	 * We assume the obp will do the following in the devices
379 	 * config space:
380 	 *
381 	 *	Set the latency-timer register to values appropriate
382 	 *	for the devices on the bus (based on other devices
383 	 *	MIN_GNT and MAX_LAT registers.
384 	 *
385 	 *	Set the fast back-to-back enable bit in the command
386 	 *	register if it's supported and all devices on the bus
387 	 *	have the capability.
388 	 *
389 	 */
390 	if (pci_config_setup(child, &config_handle) != DDI_SUCCESS) {
391 		ddi_set_name_addr(child, NULL);
392 		return (DDI_FAILURE);
393 	}
394 
395 	/*
396 	 * Determine the configuration header type.
397 	 */
398 	header_type = pci_config_get8(config_handle, PCI_CONF_HEADER);
399 	PCMU_DBG2(PCMU_DBG_INIT_CLD, pcmu_p->pcmu_dip, "%s: header_type=%x\n",
400 	    ddi_driver_name(child), header_type);
401 
402 	/*
403 	 * If the device has a bus control register then program it
404 	 * based on the settings in the command register.
405 	 */
406 	if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_ONE) {
407 		bcr = pci_config_get8(config_handle, PCI_BCNF_BCNTRL);
408 		if (pcmu_command_default & PCI_COMM_PARITY_DETECT)
409 			bcr |= PCI_BCNF_BCNTRL_PARITY_ENABLE;
410 		if (pcmu_command_default & PCI_COMM_SERR_ENABLE)
411 			bcr |= PCI_BCNF_BCNTRL_SERR_ENABLE;
412 		bcr |= PCI_BCNF_BCNTRL_MAST_AB_MODE;
413 		pci_config_put8(config_handle, PCI_BCNF_BCNTRL, bcr);
414 	}
415 
416 	pci_config_teardown(&config_handle);
417 	return (DDI_SUCCESS);
418 }
419 
420 /*
421  * pcmu_get_reg_set_size
422  *
423  * Given a dev info pointer to a pci child and a register number, this
424  * routine returns the size element of that reg set property.
425  *
426  * used by: pcmu_ctlops() - DDI_CTLOPS_REGSIZE
427  *
428  * return value: size of reg set on success, zero on error
429  */
430 off_t
431 pcmu_get_reg_set_size(dev_info_t *child, int rnumber)
432 {
433 	pci_regspec_t *pcmu_rp;
434 	off_t size;
435 	int i;
436 
437 	if (rnumber < 0) {
438 		return (0);
439 	}
440 
441 	/*
442 	 * Get the reg property for the device.
443 	 */
444 	if (ddi_getlongprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, "reg",
445 	    (caddr_t)&pcmu_rp, &i) != DDI_SUCCESS) {
446 		return (0);
447 	}
448 
449 	if (rnumber >= (i / (int)sizeof (pci_regspec_t))) {
450 		kmem_free(pcmu_rp, i);
451 		return (0);
452 	}
453 
454 	size = pcmu_rp[rnumber].pci_size_low |
455 		((uint64_t)pcmu_rp[rnumber].pci_size_hi << 32);
456 	kmem_free(pcmu_rp, i);
457 	return (size);
458 }
459 
460 
461 /*
462  * pcmu_get_nreg_set
463  *
464  * Given a dev info pointer to a pci child, this routine returns the
465  * number of sets in its "reg" property.
466  *
467  * used by: pcmu_ctlops() - DDI_CTLOPS_NREGS
468  *
469  * return value: # of reg sets on success, zero on error
470  */
471 uint_t
472 pcmu_get_nreg_set(dev_info_t *child)
473 {
474 	pci_regspec_t *pcmu_rp;
475 	int i, n;
476 
477 	/*
478 	 * Get the reg property for the device.
479 	 */
480 	if (ddi_getlongprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, "reg",
481 	    (caddr_t)&pcmu_rp, &i) != DDI_SUCCESS) {
482 		return (0);
483 	}
484 	n = i / (int)sizeof (pci_regspec_t);
485 	kmem_free(pcmu_rp, i);
486 	return (n);
487 }
488 
489 int
490 pcmu_cfg_report(dev_info_t *dip, ddi_fm_error_t *derr,
491     pcmu_errstate_t *pcmu_err_p, int caller, uint32_t prierr)
492 {
493 	int fatal = 0;
494 	int nonfatal = 0;
495 	int i;
496 	pcmu_t *pcmu_p;
497 	int instance = ddi_get_instance(dip);
498 
499 	ASSERT(dip);
500 
501 	pcmu_p = get_pcmu_soft_state(instance);
502 
503 	derr->fme_ena = derr->fme_ena ? derr->fme_ena :
504 	    fm_ena_generate(0, FM_ENA_FMT1);
505 
506 	for (i = 0; pci_err_tbl[i].err_class != NULL; i++) {
507 		if (pcmu_err_p->pcmu_cfg_stat & pci_err_tbl[i].reg_bit) {
508 			char buf[FM_MAX_CLASS];
509 			char *aux_msg = NULL;
510 
511 			switch (pci_err_tbl[i].reg_bit) {
512 			case PCI_STAT_R_MAST_AB:
513 				aux_msg = "Recieved Master Abort";
514 				/* LINTED fallthrough on case statement */
515 			case PCI_STAT_R_TARG_AB:
516 				if (aux_msg != NULL)
517 					aux_msg = "Recieved Target Abort";
518 				if (prierr) {
519 					/*
520 					 * piow case are already handled in
521 					 * pcmu_pbm_afsr_report()
522 					 */
523 					break;
524 				}
525 				if (caller != PCI_TRAP_CALL) {
526 					/*
527 					 * if we haven't come from trap handler
528 					 * we won't have an address
529 					 */
530 					fatal++;
531 				}
532 				break;
533 			default:
534 				/*
535 				 * dpe on dma write or ta on dma
536 				 */
537 				nonfatal++;
538 				break;
539 			}
540 			(void) snprintf(buf, FM_MAX_CLASS, "%s %s: %s %s",
541 			    (pcmu_p->pcmu_pcbm_p)->pcbm_nameinst_str,
542 			    (pcmu_p->pcmu_pcbm_p)->pcbm_nameaddr_str,
543 			    "PCI config space:", aux_msg);
544 			cmn_err(CE_WARN, "%s %s=0x%p", buf,
545 			    "pbm-csr", (pcmu_p->pcmu_pcbm_p)->pcbm_ctrl_reg);
546 		}
547 	}
548 
549 	if (fatal)
550 		return (DDI_FM_FATAL);
551 	else if (nonfatal)
552 		return (DDI_FM_NONFATAL);
553 
554 	return (DDI_FM_OK);
555 }
556 
557 void
558 pcmu_child_cfg_save(dev_info_t *dip)
559 {
560 	dev_info_t *cdip;
561 	int ret = DDI_SUCCESS;
562 
563 	/*
564 	 * Save the state of the configuration headers of child
565 	 * nodes.
566 	 */
567 
568 	for (cdip = ddi_get_child(dip); cdip != NULL;
569 	    cdip = ddi_get_next_sibling(cdip)) {
570 
571 		/*
572 		 * Not interested in children who are not already
573 		 * init'ed.  They will be set up in pcmu_init_child().
574 		 */
575 		if (i_ddi_node_state(cdip) < DS_INITIALIZED) {
576 			PCMU_DBG2(PCMU_DBG_DETACH, dip, "DDI_SUSPEND: skipping "
577 			    "%s%d not in CF1\n", ddi_driver_name(cdip),
578 			    ddi_get_instance(cdip));
579 
580 			continue;
581 		}
582 
583 		/*
584 		 * Only save config registers if not already saved by child.
585 		 */
586 		if (ddi_prop_exists(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS,
587 		    SAVED_CONFIG_REGS) == 1) {
588 
589 			continue;
590 		}
591 
592 		/*
593 		 * The nexus needs to save config registers.  Create a property
594 		 * so it knows to restore on resume.
595 		 */
596 		ret = ndi_prop_create_boolean(DDI_DEV_T_NONE, cdip,
597 		    "nexus-saved-config-regs");
598 
599 		if (ret != DDI_PROP_SUCCESS) {
600 			cmn_err(CE_WARN, "%s%d can't update prop %s",
601 			    ddi_driver_name(cdip), ddi_get_instance(cdip),
602 			    "nexus-saved-config-regs");
603 		}
604 
605 		(void) pci_save_config_regs(cdip);
606 	}
607 }
608 
609 void
610 pcmu_child_cfg_restore(dev_info_t *dip)
611 {
612 	dev_info_t *cdip;
613 
614 	/*
615 	 * Restore config registers for children that did not save
616 	 * their own registers.  Children pwr states are UNKNOWN after
617 	 * a resume since it is possible for the PM framework to call
618 	 * resume without an actual power cycle. (ie if suspend fails).
619 	 */
620 	for (cdip = ddi_get_child(dip); cdip != NULL;
621 	    cdip = ddi_get_next_sibling(cdip)) {
622 
623 		/*
624 		 * Not interested in children who are not already
625 		 * init'ed.  They will be set up by pcmu_init_child().
626 		 */
627 		if (i_ddi_node_state(cdip) < DS_INITIALIZED) {
628 			PCMU_DBG2(PCMU_DBG_DETACH, dip,
629 			    "DDI_RESUME: skipping %s%d not in CF1\n",
630 			    ddi_driver_name(cdip), ddi_get_instance(cdip));
631 			continue;
632 		}
633 
634 		/*
635 		 * Only restore config registers if saved by nexus.
636 		 */
637 		if (ddi_prop_exists(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS,
638 		    "nexus-saved-config-regs") == 1) {
639 			(void) pci_restore_config_regs(cdip);
640 
641 			PCMU_DBG2(PCMU_DBG_PWR, dip,
642 			    "DDI_RESUME: nexus restoring %s%d config regs\n",
643 			    ddi_driver_name(cdip), ddi_get_instance(cdip));
644 
645 			if (ndi_prop_remove(DDI_DEV_T_NONE, cdip,
646 			    "nexus-saved-config-regs") != DDI_PROP_SUCCESS) {
647 				cmn_err(CE_WARN, "%s%d can't remove prop %s",
648 				    ddi_driver_name(cdip),
649 				    ddi_get_instance(cdip),
650 				    "nexus-saved-config-regs");
651 			}
652 		}
653 	}
654 }
655 
656 #ifdef DEBUG
657 extern uint64_t pcmu_debug_flags;
658 
659 pcmu_dflag_to_str_t pcmu_dflag_strings [] = {
660 	{PCMU_DBG_ATTACH,	"pcmu_attach"},
661 	{PCMU_DBG_DETACH,	"pcmu_detach"},
662 	{PCMU_DBG_MAP,		"pcmu_map"},
663 	{PCMU_DBG_A_INTX,	"pcmu_add_intx"},
664 	{PCMU_DBG_R_INTX,	"pcmu_rem_intx"},
665 	{PCMU_DBG_INIT_CLD,	"pcmu_init_child"},
666 	{PCMU_DBG_CTLOPS,	"pcmu_ctlops"},
667 	{PCMU_DBG_INTR,		"pcmu_intr_wrapper"},
668 	{PCMU_DBG_ERR_INTR,	"pcmu_pbm_error_intr"},
669 	{PCMU_DBG_BUS_FAULT,	"pcmu_fault"},
670 	{PCMU_DBG_IB,		"pcmu_ib"},
671 	{PCMU_DBG_CB,		"pcmu_cb"},
672 	{PCMU_DBG_PBM,		"pcmu_pbm"},
673 	{PCMU_DBG_OPEN,		"pcmu_open"},
674 	{PCMU_DBG_CLOSE,	"pcmu_close"},
675 	{PCMU_DBG_IOCTL,	"pcmu_ioctl"},
676 	{PCMU_DBG_PWR,		"pcmu_pwr"}
677 };
678 
679 void
680 pcmu_debug(uint64_t flag, dev_info_t *dip, char *fmt,
681 	uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4, uintptr_t a5)
682 {
683 	char *s = "pcmu unknown";
684 	uint_t cont = 0;
685 	int i;
686 	int no_rec = (sizeof (pcmu_dflag_strings) /
687 	    sizeof (pcmu_dflag_to_str_t));
688 
689 	if (flag & PCMU_DBG_CONT) {
690 		flag &= ~PCMU_DBG_CONT;
691 		cont = 1;
692 	}
693 	if ((pcmu_debug_flags & flag) == flag) {
694 		for (i = 0; i < no_rec; i++) {
695 			if (pcmu_dflag_strings[i].flag == flag) {
696 				s = pcmu_dflag_strings[i].string;
697 				break;
698 			}
699 		}
700 		if (s && cont == 0) {
701 			prom_printf("%s(%d): %s: ", ddi_driver_name(dip),
702 			    ddi_get_instance(dip), s);
703 		}
704 		prom_printf(fmt, a1, a2, a3, a4, a5);
705 	}
706 }
707 #endif
708