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