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