xref: /illumos-gate/usr/src/uts/sun4u/io/pci/pci_util.c (revision 1a220b56b93ff1dc80855691548503117af4cc10)
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  * PCI 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  */
35 
36 #include <sys/types.h>
37 #include <sys/kmem.h>
38 #include <sys/async.h>
39 #include <sys/sysmacros.h>
40 #include <sys/sunddi.h>
41 #include <sys/sunndi.h>
42 #include <sys/fm/protocol.h>
43 #include <sys/fm/io/pci.h>
44 #include <sys/fm/util.h>
45 #include <sys/ddi_impldefs.h>
46 #include <sys/pci/pci_obj.h>
47 
48 /*LINTLIBRARY*/
49 
50 /*
51  * get_pci_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: pci_attach()
57  *
58  * return value: DDI_FAILURE on failure
59  */
60 int
61 get_pci_properties(pci_t *pci_p, dev_info_t *dip)
62 {
63 	int i;
64 
65 	/*
66 	 * Get the device's port id.
67 	 */
68 	if ((pci_p->pci_id = (uint32_t)pci_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 (pci_p->pci_bus_range);
78 	if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
79 	    "bus-range", (caddr_t)&pci_p->pci_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 	DEBUG2(DBG_ATTACH, dip, "get_pci_properties: bus-range (%x,%x)\n",
85 		pci_p->pci_bus_range.lo, pci_p->pci_bus_range.hi);
86 
87 	/*
88 	 * disable streaming cache if necessary, this must be done
89 	 * before PBM is configured.
90 	 */
91 	if (ddi_prop_exists(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
92 			"no-streaming-cache")) {
93 		pci_stream_buf_enable = 0;
94 		pci_stream_buf_exists = 0;
95 	}
96 
97 	/*
98 	 * Get the ranges property.
99 	 */
100 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "ranges",
101 		(caddr_t)&pci_p->pci_ranges, &pci_p->pci_ranges_length) !=
102 		DDI_SUCCESS) {
103 
104 		cmn_err(CE_WARN, "%s%d: no ranges property\n",
105 			ddi_driver_name(dip), ddi_get_instance(dip));
106 		return (DDI_FAILURE);
107 	}
108 	pci_fix_ranges(pci_p->pci_ranges,
109 		pci_p->pci_ranges_length / sizeof (pci_ranges_t));
110 
111 	/*
112 	 * Determine the number upa slot interrupts.
113 	 */
114 	pci_p->pci_numproxy = pci_get_numproxy(pci_p->pci_dip);
115 	DEBUG1(DBG_ATTACH, dip, "get_pci_properties: numproxy=%d\n",
116 	    pci_p->pci_numproxy);
117 
118 	pci_p->pci_thermal_interrupt =
119 		ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
120 				"thermal-interrupt", -1);
121 	DEBUG1(DBG_ATTACH, dip, "get_pci_properties: thermal_interrupt=%d\n",
122 	    pci_p->pci_thermal_interrupt);
123 	return (DDI_SUCCESS);
124 }
125 
126 /*
127  * free_pci_properties:
128  *
129  * This routine frees the memory used to cache the
130  * "ranges" properties of the pci bus device node.
131  *
132  * used by: pci_detach()
133  *
134  * return value: none
135  */
136 void
137 free_pci_properties(pci_t *pci_p)
138 {
139 	kmem_free(pci_p->pci_ranges, pci_p->pci_ranges_length);
140 }
141 
142 /*
143  * pci_reloc_reg
144  *
145  * If the "reg" entry (*pci_rp) is relocatable, lookup "assigned-addresses"
146  * property to fetch corresponding relocated address.
147  *
148  * used by: pci_map()
149  *
150  * return value:
151  *
152  *	DDI_SUCCESS		- on success
153  *	DDI_ME_INVAL		- regspec is invalid
154  */
155 int
156 pci_reloc_reg(dev_info_t *dip, dev_info_t *rdip, pci_t *pci_p,
157 	pci_regspec_t *rp)
158 {
159 	int assign_len, assign_entries, i;
160 	pci_regspec_t *assign_p;
161 	register uint32_t phys_hi = rp->pci_phys_hi;
162 	register uint32_t mask = PCI_REG_ADDR_M | PCI_CONF_ADDR_MASK;
163 	register uint32_t phys_addr = phys_hi & mask;
164 
165 	DEBUG5(DBG_MAP | DBG_CONT, dip, "\tpci_reloc_reg fr: %x.%x.%x %x.%x\n",
166 		rp->pci_phys_hi, rp->pci_phys_mid, rp->pci_phys_low,
167 		rp->pci_size_hi, rp->pci_size_low);
168 
169 	if ((phys_hi & PCI_RELOCAT_B) || !(phys_hi & PCI_ADDR_MASK))
170 		return (DDI_SUCCESS);
171 
172 	if (pci_p->hotplug_capable == B_FALSE) {	/* validate bus # */
173 		uint32_t bus = PCI_REG_BUS_G(phys_hi);
174 		if (bus < pci_p->pci_bus_range.lo ||
175 		    bus > pci_p->pci_bus_range.hi) {
176 			DEBUG1(DBG_MAP | DBG_CONT, dip, "bad bus# (%x)\n", bus);
177 			return (DDI_ME_INVAL);
178 		}
179 	}
180 
181 	/* phys_mid must be 0 regardless space type. */
182 	if (rp->pci_phys_mid != 0 || rp->pci_size_hi != 0) {
183 		DEBUG0(DBG_MAP | DBG_CONT, pci_p->pci_dip,
184 			"phys_mid or size_hi not 0\n");
185 		return (DDI_ME_INVAL);
186 	}
187 
188 	if (ddi_getlongprop(DDI_DEV_T_ANY, rdip, DDI_PROP_DONTPASS,
189 		"assigned-addresses", (caddr_t)&assign_p, &assign_len))
190 		return (DDI_ME_INVAL);
191 
192 	assign_entries = assign_len / sizeof (pci_regspec_t);
193 	for (i = 0; i < assign_entries; i++, assign_p++) {
194 		if ((assign_p->pci_phys_hi & mask) == phys_addr) {
195 			rp->pci_phys_low += assign_p->pci_phys_low;
196 			break;
197 		}
198 	}
199 	kmem_free(assign_p - i, assign_len);
200 	DEBUG5(DBG_MAP | DBG_CONT, dip, "\tpci_reloc_reg to: %x.%x.%x %x.%x\n",
201 		rp->pci_phys_hi, rp->pci_phys_mid, rp->pci_phys_low,
202 		rp->pci_size_hi, rp->pci_size_low);
203 	return (i < assign_entries ? DDI_SUCCESS : DDI_ME_INVAL);
204 }
205 
206 /*
207  * use "ranges" to translate relocated pci regspec into parent space
208  */
209 int
210 pci_xlate_reg(pci_t *pci_p, pci_regspec_t *pci_rp, struct regspec *new_rp)
211 {
212 	int n;
213 	pci_ranges_t *rng_p = pci_p->pci_ranges;
214 	int rng_n = pci_p->pci_ranges_length / sizeof (pci_ranges_t);
215 
216 	uint32_t space_type = PCI_REG_ADDR_G(pci_rp->pci_phys_hi);
217 	uint32_t reg_end, reg_begin = pci_rp->pci_phys_low;
218 	uint32_t sz = pci_rp->pci_size_low;
219 
220 	uint32_t rng_begin, rng_end;
221 
222 	if (space_type == PCI_REG_ADDR_G(PCI_ADDR_CONFIG)) {
223 		if (reg_begin > PCI_CONF_HDR_SIZE)
224 			return (DDI_ME_INVAL);
225 		sz = sz ? MIN(sz, PCI_CONF_HDR_SIZE) : PCI_CONF_HDR_SIZE;
226 		reg_begin += pci_rp->pci_phys_hi;
227 	}
228 	reg_end = reg_begin + sz - 1;
229 
230 	for (n = 0; n < rng_n; n++, rng_p++) {
231 		if (space_type != PCI_REG_ADDR_G(rng_p->child_high))
232 			continue;	/* not the same space type */
233 
234 		rng_begin = rng_p->child_low;
235 		if (space_type == PCI_REG_ADDR_G(PCI_ADDR_CONFIG))
236 			rng_begin += rng_p->child_high;
237 
238 		rng_end = rng_begin + rng_p->size_low - 1;
239 		if (reg_begin >= rng_begin && reg_end <= rng_end)
240 			break;
241 	}
242 	if (n >= rng_n)
243 		return (DDI_ME_REGSPEC_RANGE);
244 
245 	new_rp->regspec_addr = reg_begin - rng_begin + rng_p->parent_low;
246 	new_rp->regspec_bustype = rng_p->parent_high;
247 	new_rp->regspec_size = sz;
248 	DEBUG4(DBG_MAP | DBG_CONT, pci_p->pci_dip,
249 		"\tpci_xlate_reg: entry %d new_rp %x.%x %x\n",
250 		n, new_rp->regspec_bustype, new_rp->regspec_addr, sz);
251 
252 	return (DDI_SUCCESS);
253 }
254 
255 
256 /*
257  * report_dev
258  *
259  * This function is called from our control ops routine on a
260  * DDI_CTLOPS_REPORTDEV request.
261  *
262  * The display format is
263  *
264  *	<name><inst> at <pname><pinst> device <dev> function <func>
265  *
266  * where
267  *
268  *	<name>		this device's name property
269  *	<inst>		this device's instance number
270  *	<name>		parent device's name property
271  *	<inst>		parent device's instance number
272  *	<dev>		this device's device number
273  *	<func>		this device's function number
274  */
275 int
276 report_dev(dev_info_t *dip)
277 {
278 	if (dip == (dev_info_t *)0)
279 		return (DDI_FAILURE);
280 	cmn_err(CE_CONT, "?PCI-device: %s@%s, %s%d\n",
281 	    ddi_node_name(dip), ddi_get_name_addr(dip),
282 	    ddi_driver_name(dip),
283 	    ddi_get_instance(dip));
284 	return (DDI_SUCCESS);
285 }
286 
287 
288 /*
289  * reg property for pcimem nodes that covers the entire address
290  * space for the node:  config, io, or memory.
291  */
292 pci_regspec_t pci_pcimem_reg[3] =
293 {
294 	{PCI_ADDR_CONFIG,			0, 0, 0, 0x800000	},
295 	{(uint_t)(PCI_ADDR_IO|PCI_RELOCAT_B),	0, 0, 0, PCI_IO_SIZE	},
296 	{(uint_t)(PCI_ADDR_MEM32|PCI_RELOCAT_B), 0, 0, 0, PCI_MEM_SIZE	}
297 };
298 
299 /*
300  * name_child
301  *
302  * This function is called from init_child to name a node. It is
303  * also passed as a callback for node merging functions.
304  *
305  * return value: DDI_SUCCESS, DDI_FAILURE
306  */
307 static int
308 name_child(dev_info_t *child, char *name, int namelen)
309 {
310 	pci_regspec_t *pci_rp;
311 	int reglen;
312 	uint_t func;
313 	char **unit_addr;
314 	uint_t n;
315 
316 	/*
317 	 * Set the address portion of the node name based on
318 	 * unit-address property, if it exists.
319 	 * The interpretation of the unit-address is DD[,F]
320 	 * where DD is the device id and F is the function.
321 	 */
322 	if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, child,
323 	    DDI_PROP_DONTPASS, "unit-address", &unit_addr, &n) ==
324 	    DDI_PROP_SUCCESS) {
325 		if (n != 1 || *unit_addr == NULL || **unit_addr == 0) {
326 			cmn_err(CE_WARN, "unit-address property in %s.conf"
327 			    " not well-formed", ddi_driver_name(child));
328 			ddi_prop_free(unit_addr);
329 			return (DDI_FAILURE);
330 		}
331 		(void) snprintf(name, namelen, "%s", *unit_addr);
332 		ddi_prop_free(unit_addr);
333 		return (DDI_SUCCESS);
334 	}
335 
336 	/*
337 	 * The unit-address property is does not exist. Set the address
338 	 * portion of the node name based on the function and device number.
339 	 */
340 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
341 	    "reg", (int **)&pci_rp, (uint_t *)&reglen) == DDI_SUCCESS) {
342 		if (((reglen * sizeof (int)) % sizeof (pci_regspec_t)) != 0) {
343 			cmn_err(CE_WARN, "reg property not well-formed");
344 			return (DDI_FAILURE);
345 		}
346 
347 		func = PCI_REG_FUNC_G(pci_rp[0].pci_phys_hi);
348 		if (func != 0)
349 			(void) snprintf(name, namelen, "%x,%x",
350 				PCI_REG_DEV_G(pci_rp[0].pci_phys_hi), func);
351 		else
352 			(void) snprintf(name, namelen, "%x",
353 				PCI_REG_DEV_G(pci_rp[0].pci_phys_hi));
354 		ddi_prop_free(pci_rp);
355 		return (DDI_SUCCESS);
356 	}
357 
358 	cmn_err(CE_WARN, "cannot name pci child '%s'", ddi_node_name(child));
359 	return (DDI_FAILURE);
360 }
361 
362 int
363 uninit_child(pci_t *pci_p, dev_info_t *child)
364 {
365 	DEBUG2(DBG_CTLOPS, pci_p->pci_dip,
366 	    "DDI_CTLOPS_UNINITCHILD: arg=%s%d\n",
367 	    ddi_driver_name(child), ddi_get_instance(child));
368 
369 
370 	(void) pm_uninit_child(child);
371 
372 	ddi_set_name_addr(child, NULL);
373 	ddi_remove_minor_node(child, NULL);
374 	impl_rem_dev_props(child);
375 
376 	DEBUG0(DBG_PWR, ddi_get_parent(child), "\n\n");
377 
378 	/*
379 	 * Handle chip specific post-uninit-child tasks.
380 	 */
381 	pci_post_uninit_child(pci_p);
382 
383 	return (DDI_SUCCESS);
384 }
385 
386 /*
387  * init_child
388  *
389  * This function is called from our control ops routine on a
390  * DDI_CTLOPS_INITCHILD request.  It builds and sets the device's
391  * parent private data area.
392  *
393  * used by: pci_ctlops()
394  *
395  * return value: none
396  */
397 int
398 init_child(pci_t *pci_p, dev_info_t *child)
399 {
400 	pci_regspec_t *pci_rp;
401 	char name[10];
402 	ddi_acc_handle_t config_handle;
403 	uint16_t command_preserve, command;
404 	uint8_t bcr;
405 	uint8_t header_type, min_gnt;
406 	uint16_t latency_timer;
407 	uint_t n;
408 	int i, no_config;
409 
410 	/*
411 	 * The following is a special case for pcimem nodes.
412 	 * For these nodes we create a reg property with a
413 	 * single entry that covers the entire address space
414 	 * for the node (config, io or memory).
415 	 */
416 	if (strcmp(ddi_driver_name(child), "pcimem") == 0) {
417 		(void) ddi_prop_create(DDI_DEV_T_NONE, child,
418 		    DDI_PROP_CANSLEEP, "reg", (caddr_t)pci_pcimem_reg,
419 		    sizeof (pci_pcimem_reg));
420 		ddi_set_name_addr(child, "0");
421 		ddi_set_parent_data(child, NULL);
422 		return (DDI_SUCCESS);
423 	}
424 
425 	/*
426 	 * Check whether the node has config space or is a hard decode
427 	 * node (possibly created by a driver.conf file).
428 	 */
429 	no_config = ddi_prop_get_int(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
430 	    "no-config", 0);
431 
432 	/*
433 	 * Pseudo nodes indicate a prototype node with per-instance
434 	 * properties to be merged into the real h/w device node.
435 	 * However, do not merge if the no-config property is set
436 	 * (see PSARC 2000/088).
437 	 */
438 	if ((ndi_dev_is_persistent_node(child) == 0) && (no_config == 0)) {
439 		extern int pci_allow_pseudo_children;
440 
441 		if (ddi_getlongprop(DDI_DEV_T_ANY, child,
442 		    DDI_PROP_DONTPASS, "reg", (caddr_t)&pci_rp, &i) ==
443 		    DDI_SUCCESS) {
444 			cmn_err(CE_WARN, "cannot merge prototype from %s.conf",
445 			    ddi_driver_name(child));
446 			kmem_free(pci_rp, i);
447 			return (DDI_NOT_WELL_FORMED);
448 		}
449 		/*
450 		 * Name the child
451 		 */
452 		if (name_child(child, name, 10) != DDI_SUCCESS)
453 			return (DDI_FAILURE);
454 
455 		ddi_set_name_addr(child, name);
456 		ddi_set_parent_data(child, NULL);
457 
458 		/*
459 		 * Try to merge the properties from this prototype
460 		 * node into real h/w nodes.
461 		 */
462 		if (ndi_merge_node(child, name_child) == DDI_SUCCESS) {
463 			/*
464 			 * Merged ok - return failure to remove the node.
465 			 */
466 			ddi_set_name_addr(child, NULL);
467 			return (DDI_FAILURE);
468 		}
469 
470 		/* workaround for ddivs to run under PCI */
471 		if (pci_allow_pseudo_children)
472 			return (DDI_SUCCESS);
473 
474 		cmn_err(CE_WARN, "!%s@%s: %s.conf properties not merged",
475 		    ddi_driver_name(child), ddi_get_name_addr(child),
476 		    ddi_driver_name(child));
477 		ddi_set_name_addr(child, NULL);
478 		return (DDI_NOT_WELL_FORMED);
479 	}
480 
481 	if (name_child(child, name, 10) != DDI_SUCCESS)
482 		return (DDI_FAILURE);
483 	ddi_set_name_addr(child, name);
484 
485 	if (no_config != 0) {
486 		/*
487 		 * There is no config space so there's nothing more to do.
488 		 */
489 		return (DDI_SUCCESS);
490 	}
491 
492 	if (pm_init_child(child) != DDI_SUCCESS)
493 		return (DDI_FAILURE);
494 
495 
496 	/*
497 	 * If configuration registers were previously saved by
498 	 * child (before it went to D3), then let the child do the
499 	 * restore to set up the config regs as it'll first need to
500 	 * power the device out of D3.
501 	 */
502 	if (ddi_prop_exists(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
503 	    "config-regs-saved-by-child") == 1) {
504 		DEBUG0(DBG_PWR, child,
505 		    "INITCHILD: config regs to be restored by child\n");
506 
507 		return (DDI_SUCCESS);
508 	}
509 
510 	DEBUG2(DBG_PWR, ddi_get_parent(child),
511 	    "INITCHILD: config regs setup for %s@%s\n",
512 	    ddi_node_name(child), ddi_get_name_addr(child));
513 
514 	/*
515 	 * Map the child configuration space to for initialization.
516 	 * We assume the obp will do the following in the devices
517 	 * config space:
518 	 *
519 	 *	Set the latency-timer register to values appropriate
520 	 *	for the devices on the bus (based on other devices
521 	 *	MIN_GNT and MAX_LAT registers.
522 	 *
523 	 *	Set the fast back-to-back enable bit in the command
524 	 *	register if it's supported and all devices on the bus
525 	 *	have the capability.
526 	 *
527 	 */
528 	if (pci_config_setup(child, &config_handle) != DDI_SUCCESS) {
529 		(void) pm_uninit_child(child);
530 		ddi_set_name_addr(child, NULL);
531 
532 		return (DDI_FAILURE);
533 	}
534 
535 	/*
536 	 * Determine the configuration header type.
537 	 */
538 	header_type = pci_config_get8(config_handle, PCI_CONF_HEADER);
539 	DEBUG2(DBG_INIT_CLD, pci_p->pci_dip, "%s: header_type=%x\n",
540 	    ddi_driver_name(child), header_type);
541 
542 	/*
543 	 * Support for "command-preserve" property.  Note that we
544 	 * add PCI_COMM_BACK2BACK_ENAB to the bits to be preserved
545 	 * since the obp will set this if the device supports and
546 	 * all targets on the same bus support it.  Since psycho
547 	 * doesn't support PCI_COMM_BACK2BACK_ENAB, it will never
548 	 * be set.  This is just here in case future revs do support
549 	 * PCI_COMM_BACK2BACK_ENAB.
550 	 */
551 	command_preserve =
552 	    ddi_prop_get_int(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
553 		"command-preserve", 0);
554 	DEBUG2(DBG_INIT_CLD, pci_p->pci_dip, "%s: command-preserve=%x\n",
555 	    ddi_driver_name(child), command_preserve);
556 	command = pci_config_get16(config_handle, PCI_CONF_COMM);
557 	command &= (command_preserve | PCI_COMM_BACK2BACK_ENAB);
558 	command |= (pci_command_default & ~command_preserve);
559 	pci_config_put16(config_handle, PCI_CONF_COMM, command);
560 	command = pci_config_get16(config_handle, PCI_CONF_COMM);
561 	DEBUG2(DBG_INIT_CLD, pci_p->pci_dip, "%s: command=%x\n",
562 	    ddi_driver_name(child),
563 	    pci_config_get16(config_handle, PCI_CONF_COMM));
564 
565 	/*
566 	 * If the device has a bus control register then program it
567 	 * based on the settings in the command register.
568 	 */
569 	if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_ONE) {
570 		bcr = pci_config_get8(config_handle, PCI_BCNF_BCNTRL);
571 		if (pci_command_default & PCI_COMM_PARITY_DETECT)
572 			bcr |= PCI_BCNF_BCNTRL_PARITY_ENABLE;
573 		if (pci_command_default & PCI_COMM_SERR_ENABLE)
574 			bcr |= PCI_BCNF_BCNTRL_SERR_ENABLE;
575 		bcr |= PCI_BCNF_BCNTRL_MAST_AB_MODE;
576 		pci_config_put8(config_handle, PCI_BCNF_BCNTRL, bcr);
577 	}
578 
579 	/*
580 	 * Initialize cache-line-size configuration register if needed.
581 	 */
582 	if (pci_set_cache_line_size_register &&
583 	    ddi_getprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
584 		"cache-line-size", 0) == 0) {
585 
586 		pci_config_put8(config_handle, PCI_CONF_CACHE_LINESZ,
587 		    PCI_CACHE_LINE_SIZE);
588 		n = pci_config_get8(config_handle, PCI_CONF_CACHE_LINESZ);
589 		if (n != 0)
590 			(void) ndi_prop_update_int(DDI_DEV_T_NONE, child,
591 			    "cache-line-size", n);
592 	}
593 
594 	/*
595 	 * Initialize latency timer registers if needed.
596 	 */
597 	if (pci_set_latency_timer_register &&
598 	    ddi_getprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
599 		"latency-timer", 0) == 0) {
600 
601 		latency_timer = pci_latency_timer;
602 		if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_ONE) {
603 			pci_config_put8(config_handle, PCI_BCNF_LATENCY_TIMER,
604 			    latency_timer);
605 		} else {
606 			min_gnt = pci_config_get8(config_handle,
607 			    PCI_CONF_MIN_G);
608 			DEBUG2(DBG_INIT_CLD, pci_p->pci_dip, "%s: min_gnt=%x\n",
609 			    ddi_driver_name(child), min_gnt);
610 			if (min_gnt != 0) {
611 				switch (pci_p->pci_pbm_p->pbm_speed) {
612 				case PBM_SPEED_33MHZ:
613 					latency_timer = min_gnt * 8;
614 					break;
615 				case PBM_SPEED_66MHZ:
616 					latency_timer = min_gnt * 4;
617 					break;
618 				}
619 			}
620 		}
621 		latency_timer = MIN(latency_timer, 0xff);
622 		pci_config_put8(config_handle, PCI_CONF_LATENCY_TIMER,
623 		    latency_timer);
624 		n = pci_config_get8(config_handle, PCI_CONF_LATENCY_TIMER);
625 		if (n != 0)
626 			(void) ndi_prop_update_int(DDI_DEV_T_NONE, child,
627 			    "latency-timer", n);
628 	}
629 
630 	pci_config_teardown(&config_handle);
631 
632 	/*
633 	 * Handle chip specific init-child tasks.
634 	 */
635 	pci_post_init_child(pci_p, child);
636 
637 	return (DDI_SUCCESS);
638 }
639 
640 /*
641  * get_nreg_set
642  *
643  * Given a dev info pointer to a pci child, this routine returns the
644  * number of sets in its "reg" property.
645  *
646  * used by: pci_ctlops() - DDI_CTLOPS_NREGS
647  *
648  * return value: # of reg sets on success, zero on error
649  */
650 uint_t
651 get_nreg_set(dev_info_t *child)
652 {
653 	pci_regspec_t *pci_rp;
654 	int i, n;
655 
656 	/*
657 	 * Get the reg property for the device.
658 	 */
659 	if (ddi_getlongprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, "reg",
660 	    (caddr_t)&pci_rp, &i) != DDI_SUCCESS)
661 		return (0);
662 
663 	n = i / (int)sizeof (pci_regspec_t);
664 	kmem_free(pci_rp, i);
665 	return (n);
666 }
667 
668 
669 /*
670  * get_nintr
671  *
672  * Given a dev info pointer to a pci child, this routine returns the
673  * number of items in its "interrupts" property.
674  *
675  * used by: pci_ctlops() - DDI_CTLOPS_NREGS
676  *
677  * return value: # of interrupts on success, zero on error
678  */
679 uint_t
680 get_nintr(dev_info_t *child)
681 {
682 	int *pci_ip;
683 	int i, n;
684 
685 	if (ddi_getlongprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
686 	    "interrupts", (caddr_t)&pci_ip, &i) != DDI_SUCCESS)
687 		return (0);
688 
689 	n = i / (int)sizeof (uint_t);
690 	kmem_free(pci_ip, i);
691 	return (n);
692 }
693 
694 uint64_t
695 pci_get_cfg_pabase(pci_t *pci_p)
696 {
697 	int i;
698 	pci_ranges_t *rangep = pci_p->pci_ranges;
699 	int nrange = pci_p->pci_ranges_length / sizeof (pci_ranges_t);
700 	uint32_t cfg_space_type = PCI_REG_ADDR_G(PCI_ADDR_CONFIG);
701 
702 	ASSERT(cfg_space_type == 0);
703 
704 	for (i = 0; i < nrange; i++, rangep++) {
705 		if (PCI_REG_ADDR_G(rangep->child_high) == cfg_space_type)
706 			break;
707 	}
708 
709 	if (i >= nrange)
710 		cmn_err(CE_PANIC, "no cfg space in pci(%p) ranges prop.\n",
711 			(void *)pci_p);
712 
713 	return (((uint64_t)rangep->parent_high << 32) | rangep->parent_low);
714 }
715 
716 int
717 pci_cfg_report(dev_info_t *dip, ddi_fm_error_t *derr, pci_errstate_t *pci_err_p,
718 	int caller, uint32_t prierr)
719 {
720 	int fatal = 0;
721 	int nonfatal = 0;
722 	int i;
723 
724 	ASSERT(dip);
725 
726 	derr->fme_ena = derr->fme_ena ? derr->fme_ena :
727 	    fm_ena_generate(0, FM_ENA_FMT1);
728 
729 	for (i = 0; pci_err_tbl[i].err_class != NULL; i++) {
730 		if (pci_err_p->pci_cfg_stat & pci_err_tbl[i].reg_bit) {
731 			char buf[FM_MAX_CLASS];
732 
733 			(void) snprintf(buf, FM_MAX_CLASS, "%s.%s",
734 					PCI_ERROR_SUBCLASS,
735 					pci_err_tbl[i].err_class);
736 			ddi_fm_ereport_post(dip, buf, derr->fme_ena,
737 			    DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0,
738 			    PCI_CONFIG_STATUS, DATA_TYPE_UINT16,
739 			    pci_err_p->pci_cfg_stat,
740 			    PCI_CONFIG_COMMAND, DATA_TYPE_UINT16,
741 			    pci_err_p->pci_cfg_comm,
742 			    PCI_PA, DATA_TYPE_UINT64,
743 			    pci_err_p->pci_pa,
744 			    NULL);
745 
746 			switch (pci_err_tbl[i].reg_bit) {
747 			case PCI_STAT_S_SYSERR:
748 				/*
749 				 * address parity error on dma - treat as fatal
750 				 */
751 				fatal++;
752 				break;
753 			case PCI_STAT_R_MAST_AB:
754 			case PCI_STAT_R_TARG_AB:
755 			case PCI_STAT_S_PERROR:
756 				if (prierr) {
757 					/*
758 					 * piow case are already handled in
759 					 * pbm_afsr_report()
760 					 */
761 					break;
762 				}
763 				if (caller != PCI_TRAP_CALL) {
764 					/*
765 					 * if we haven't come from trap handler
766 					 * we won't have an address
767 					 */
768 					fatal++;
769 					break;
770 				}
771 
772 				/*
773 				 * queue target ereport - use return from
774 				 * pci_lookup_handle() to determine if sync
775 				 * or async
776 				 */
777 				nonfatal++;
778 				pci_target_enqueue(derr->fme_ena,
779 				    pci_err_tbl[i].terr_class,
780 				    PCI_ERROR_SUBCLASS,
781 				    (uint64_t)derr->fme_bus_specific);
782 				break;
783 			default:
784 				/*
785 				 * dpe on dma write or ta on dma
786 				 */
787 				nonfatal++;
788 				break;
789 			}
790 		}
791 	}
792 
793 	if (fatal)
794 		return (DDI_FM_FATAL);
795 	else if (nonfatal)
796 		return (DDI_FM_NONFATAL);
797 
798 	return (DDI_FM_OK);
799 }
800 
801 void
802 pci_child_cfg_save(dev_info_t *dip)
803 {
804 	dev_info_t *cdip;
805 	int ret = DDI_SUCCESS;
806 
807 	/*
808 	 * Save the state of the configuration headers of child
809 	 * nodes.
810 	 */
811 
812 	for (cdip = ddi_get_child(dip); cdip != NULL;
813 	    cdip = ddi_get_next_sibling(cdip)) {
814 
815 		/*
816 		 * Not interested in children who are not already
817 		 * init'ed.  They will be set up in init_child().
818 		 */
819 		if (i_ddi_node_state(cdip) < DS_INITIALIZED) {
820 			DEBUG2(DBG_DETACH, dip, "DDI_SUSPEND: skipping "
821 			    "%s%d not in CF1\n", ddi_driver_name(cdip),
822 			    ddi_get_instance(cdip));
823 
824 			continue;
825 		}
826 
827 		/*
828 		 * Only save config registers if not already saved by child.
829 		 */
830 		if (ddi_prop_exists(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS,
831 		    SAVED_CONFIG_REGS) == 1) {
832 
833 			continue;
834 		}
835 
836 		/*
837 		 * The nexus needs to save config registers.  Create a property
838 		 * so it knows to restore on resume.
839 		 */
840 		ret = ndi_prop_create_boolean(DDI_DEV_T_NONE, cdip,
841 		    "nexus-saved-config-regs");
842 
843 		if (ret != DDI_PROP_SUCCESS) {
844 			cmn_err(CE_WARN, "%s%d can't update prop %s",
845 			    ddi_driver_name(cdip), ddi_get_instance(cdip),
846 			    "nexus-saved-config-regs");
847 		}
848 
849 		(void) pci_save_config_regs(cdip);
850 	}
851 }
852 
853 void
854 pci_child_cfg_restore(dev_info_t *dip)
855 {
856 	dev_info_t *cdip;
857 
858 	/*
859 	 * Restore config registers for children that did not save
860 	 * their own registers.  Children pwr states are UNKNOWN after
861 	 * a resume since it is possible for the PM framework to call
862 	 * resume without an actual power cycle. (ie if suspend fails).
863 	 */
864 	for (cdip = ddi_get_child(dip); cdip != NULL;
865 	    cdip = ddi_get_next_sibling(cdip)) {
866 
867 		/*
868 		 * Not interested in children who are not already
869 		 * init'ed.  They will be set up by init_child().
870 		 */
871 		if (i_ddi_node_state(cdip) < DS_INITIALIZED) {
872 			DEBUG2(DBG_DETACH, dip,
873 			    "DDI_RESUME: skipping %s%d not in CF1\n",
874 			    ddi_driver_name(cdip), ddi_get_instance(cdip));
875 			continue;
876 		}
877 
878 		/*
879 		 * Only restore config registers if saved by nexus.
880 		 */
881 		if (ddi_prop_exists(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS,
882 		    "nexus-saved-config-regs") == 1) {
883 			(void) pci_restore_config_regs(cdip);
884 
885 			DEBUG2(DBG_PWR, dip,
886 			    "DDI_RESUME: nexus restoring %s%d config regs\n",
887 			    ddi_driver_name(cdip), ddi_get_instance(cdip));
888 
889 			if (ndi_prop_remove(DDI_DEV_T_NONE, cdip,
890 			    "nexus-saved-config-regs") != DDI_PROP_SUCCESS) {
891 				cmn_err(CE_WARN, "%s%d can't remove prop %s",
892 				    ddi_driver_name(cdip),
893 				    ddi_get_instance(cdip),
894 				    "nexus-saved-config-regs");
895 			}
896 		}
897 	}
898 }
899