xref: /onnv-gate/usr/src/uts/sun4/io/px/px_util.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate /*
30*0Sstevel@tonic-gate  * PCI nexus utility routines:
31*0Sstevel@tonic-gate  *	property and config routines for attach()
32*0Sstevel@tonic-gate  *	reg/intr/range/assigned-address property routines for bus_map()
33*0Sstevel@tonic-gate  *	init_child()
34*0Sstevel@tonic-gate  *	fault handling
35*0Sstevel@tonic-gate  */
36*0Sstevel@tonic-gate 
37*0Sstevel@tonic-gate #include <sys/types.h>
38*0Sstevel@tonic-gate #include <sys/kmem.h>
39*0Sstevel@tonic-gate #include <sys/async.h>
40*0Sstevel@tonic-gate #include <sys/sysmacros.h>
41*0Sstevel@tonic-gate #include <sys/sunddi.h>
42*0Sstevel@tonic-gate #include <sys/sunndi.h>
43*0Sstevel@tonic-gate #include <sys/ddi_impldefs.h>
44*0Sstevel@tonic-gate #include "px_obj.h"
45*0Sstevel@tonic-gate #include "pcie_pwr.h"
46*0Sstevel@tonic-gate #include <px_regs.h>
47*0Sstevel@tonic-gate #include <px_csr.h>
48*0Sstevel@tonic-gate 
49*0Sstevel@tonic-gate /*LINTLIBRARY*/
50*0Sstevel@tonic-gate 
51*0Sstevel@tonic-gate /*
52*0Sstevel@tonic-gate  * px_get_props
53*0Sstevel@tonic-gate  *
54*0Sstevel@tonic-gate  * This function is called from the attach routine to get the key
55*0Sstevel@tonic-gate  * properties of the pci nodes.
56*0Sstevel@tonic-gate  *
57*0Sstevel@tonic-gate  * used by: px_attach()
58*0Sstevel@tonic-gate  *
59*0Sstevel@tonic-gate  * return value: DDI_FAILURE on failure
60*0Sstevel@tonic-gate  */
61*0Sstevel@tonic-gate int
62*0Sstevel@tonic-gate px_get_props(px_t *px_p, dev_info_t *dip)
63*0Sstevel@tonic-gate {
64*0Sstevel@tonic-gate 	int i, no_of_intrs;
65*0Sstevel@tonic-gate 
66*0Sstevel@tonic-gate 	/*
67*0Sstevel@tonic-gate 	 * Get the bus-ranges property.
68*0Sstevel@tonic-gate 	 */
69*0Sstevel@tonic-gate 	i = sizeof (px_p->px_bus_range);
70*0Sstevel@tonic-gate 	if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
71*0Sstevel@tonic-gate 	    "bus-range", (caddr_t)&px_p->px_bus_range, &i) != DDI_SUCCESS) {
72*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "%s%d: no bus-range property\n",
73*0Sstevel@tonic-gate 		    ddi_driver_name(dip), ddi_get_instance(dip));
74*0Sstevel@tonic-gate 		return (DDI_FAILURE);
75*0Sstevel@tonic-gate 	}
76*0Sstevel@tonic-gate 	DBG(DBG_ATTACH, dip, "get_px_properties: bus-range (%x,%x)\n",
77*0Sstevel@tonic-gate 		px_p->px_bus_range.lo, px_p->px_bus_range.hi);
78*0Sstevel@tonic-gate 
79*0Sstevel@tonic-gate 	/*
80*0Sstevel@tonic-gate 	 * Get the interrupts property.
81*0Sstevel@tonic-gate 	 */
82*0Sstevel@tonic-gate 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
83*0Sstevel@tonic-gate 		"interrupts", (caddr_t)&px_p->px_inos,
84*0Sstevel@tonic-gate 		&px_p->px_inos_len) != DDI_SUCCESS) {
85*0Sstevel@tonic-gate 
86*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "%s%d: no interrupts property\n",
87*0Sstevel@tonic-gate 			ddi_driver_name(dip), ddi_get_instance(dip));
88*0Sstevel@tonic-gate 		return (DDI_FAILURE);
89*0Sstevel@tonic-gate 	}
90*0Sstevel@tonic-gate 
91*0Sstevel@tonic-gate 	/*
92*0Sstevel@tonic-gate 	 * figure out number of interrupts in the "interrupts" property
93*0Sstevel@tonic-gate 	 * and convert them all into ino.
94*0Sstevel@tonic-gate 	 */
95*0Sstevel@tonic-gate 	i = ddi_getprop(DDI_DEV_T_ANY, dip, 0, "#interrupt-cells", 1);
96*0Sstevel@tonic-gate 	i = CELLS_1275_TO_BYTES(i);
97*0Sstevel@tonic-gate 	no_of_intrs = px_p->px_inos_len / i;
98*0Sstevel@tonic-gate 	for (i = 0; i < no_of_intrs; i++)
99*0Sstevel@tonic-gate 		px_p->px_inos[i] = px_p->px_inos[i] & 0x3F;
100*0Sstevel@tonic-gate 
101*0Sstevel@tonic-gate 	/*
102*0Sstevel@tonic-gate 	 * Get the ranges property.
103*0Sstevel@tonic-gate 	 */
104*0Sstevel@tonic-gate 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "ranges",
105*0Sstevel@tonic-gate 		(caddr_t)&px_p->px_ranges_p, &px_p->px_ranges_length) !=
106*0Sstevel@tonic-gate 		DDI_SUCCESS) {
107*0Sstevel@tonic-gate 
108*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "%s%d: no ranges property\n",
109*0Sstevel@tonic-gate 			ddi_driver_name(dip), ddi_get_instance(dip));
110*0Sstevel@tonic-gate 		kmem_free(px_p->px_inos, px_p->px_inos_len);
111*0Sstevel@tonic-gate 		return (DDI_FAILURE);
112*0Sstevel@tonic-gate 	}
113*0Sstevel@tonic-gate 
114*0Sstevel@tonic-gate 	px_p->px_thermal_interrupt =
115*0Sstevel@tonic-gate 		ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
116*0Sstevel@tonic-gate 				"thermal-interrupt", -1);
117*0Sstevel@tonic-gate 	DBG(DBG_ATTACH, dip, "get_px_properties: thermal_interrupt=%d\n",
118*0Sstevel@tonic-gate 	    px_p->px_thermal_interrupt);
119*0Sstevel@tonic-gate 	return (DDI_SUCCESS);
120*0Sstevel@tonic-gate }
121*0Sstevel@tonic-gate 
122*0Sstevel@tonic-gate /*
123*0Sstevel@tonic-gate  * px_free_props:
124*0Sstevel@tonic-gate  *
125*0Sstevel@tonic-gate  * This routine frees the memory used to cache the "interrupts"
126*0Sstevel@tonic-gate  * and "ranges" properties of the pci bus device node.
127*0Sstevel@tonic-gate  *
128*0Sstevel@tonic-gate  * used by: px_detach()
129*0Sstevel@tonic-gate  *
130*0Sstevel@tonic-gate  * return value: none
131*0Sstevel@tonic-gate  */
132*0Sstevel@tonic-gate void
133*0Sstevel@tonic-gate px_free_props(px_t *px_p)
134*0Sstevel@tonic-gate {
135*0Sstevel@tonic-gate 	kmem_free(px_p->px_inos, px_p->px_inos_len);
136*0Sstevel@tonic-gate 	kmem_free(px_p->px_ranges_p, px_p->px_ranges_length);
137*0Sstevel@tonic-gate }
138*0Sstevel@tonic-gate 
139*0Sstevel@tonic-gate /*
140*0Sstevel@tonic-gate  * px_reloc_reg
141*0Sstevel@tonic-gate  *
142*0Sstevel@tonic-gate  * If the "reg" entry (*px_rp) is relocatable, lookup "assigned-addresses"
143*0Sstevel@tonic-gate  * property to fetch corresponding relocated address.
144*0Sstevel@tonic-gate  *
145*0Sstevel@tonic-gate  * used by: px_map()
146*0Sstevel@tonic-gate  *
147*0Sstevel@tonic-gate  * return value:
148*0Sstevel@tonic-gate  *
149*0Sstevel@tonic-gate  *	DDI_SUCCESS		- on success
150*0Sstevel@tonic-gate  *	DDI_ME_INVAL		- regspec is invalid
151*0Sstevel@tonic-gate  */
152*0Sstevel@tonic-gate int
153*0Sstevel@tonic-gate px_reloc_reg(dev_info_t *dip, dev_info_t *rdip, px_t *px_p,
154*0Sstevel@tonic-gate 	pci_regspec_t *rp)
155*0Sstevel@tonic-gate {
156*0Sstevel@tonic-gate 	int assign_len, assign_entries, i;
157*0Sstevel@tonic-gate 	pci_regspec_t *assign_p;
158*0Sstevel@tonic-gate 	uint32_t phys_hi = rp->pci_phys_hi;
159*0Sstevel@tonic-gate 	uint32_t space_type = phys_hi & PCI_REG_ADDR_M;	/* 28-bit */
160*0Sstevel@tonic-gate 
161*0Sstevel@tonic-gate 	DBG(DBG_MAP | DBG_CONT, dip, "\tpx_reloc_reg fr: %x.%x.%x %x.%x\n",
162*0Sstevel@tonic-gate 		rp->pci_phys_hi, rp->pci_phys_mid, rp->pci_phys_low,
163*0Sstevel@tonic-gate 		rp->pci_size_hi, rp->pci_size_low);
164*0Sstevel@tonic-gate 
165*0Sstevel@tonic-gate 	if (space_type == PCI_ADDR_CONFIG || phys_hi & PCI_RELOCAT_B)
166*0Sstevel@tonic-gate 		return (DDI_SUCCESS);
167*0Sstevel@tonic-gate 
168*0Sstevel@tonic-gate 	/*
169*0Sstevel@tonic-gate 	 * Hot plug will be taken care of later
170*0Sstevel@tonic-gate 	 * if (px_p->hotplug_capable == B_FALSE)
171*0Sstevel@tonic-gate 	 */
172*0Sstevel@tonic-gate 	{
173*0Sstevel@tonic-gate 		uint32_t bus = PCI_REG_BUS_G(phys_hi);
174*0Sstevel@tonic-gate 		if (bus < px_p->px_bus_range.lo ||
175*0Sstevel@tonic-gate 		    bus > px_p->px_bus_range.hi) {
176*0Sstevel@tonic-gate 			DBG(DBG_MAP | DBG_CONT, dip, "bad bus# (%x)\n", bus);
177*0Sstevel@tonic-gate 			return (DDI_ME_INVAL);
178*0Sstevel@tonic-gate 		}
179*0Sstevel@tonic-gate 	}
180*0Sstevel@tonic-gate 
181*0Sstevel@tonic-gate 	i = ddi_getlongprop(DDI_DEV_T_ANY, rdip, DDI_PROP_DONTPASS,
182*0Sstevel@tonic-gate 		"assigned-addresses", (caddr_t)&assign_p, &assign_len);
183*0Sstevel@tonic-gate 	if (i) {
184*0Sstevel@tonic-gate 		DBG(DBG_MAP | DBG_CONT, dip, "%s%d: assigned-addresses %d\n",
185*0Sstevel@tonic-gate 			ddi_driver_name(rdip), ddi_get_instance(rdip), i);
186*0Sstevel@tonic-gate 		return (DDI_ME_INVAL);
187*0Sstevel@tonic-gate 	}
188*0Sstevel@tonic-gate 
189*0Sstevel@tonic-gate 	assign_entries = assign_len / sizeof (pci_regspec_t);
190*0Sstevel@tonic-gate 	for (i = 0; i < assign_entries; i++, assign_p++) {
191*0Sstevel@tonic-gate 		uint32_t assign_type = assign_p->pci_phys_hi & PCI_REG_ADDR_M;
192*0Sstevel@tonic-gate 		uint32_t assign_addr = PCI_REG_BDFR_G(assign_p->pci_phys_hi);
193*0Sstevel@tonic-gate 
194*0Sstevel@tonic-gate 		if (PCI_REG_BDFR_G(phys_hi) != assign_addr)
195*0Sstevel@tonic-gate 			continue;
196*0Sstevel@tonic-gate 		if (space_type == assign_type) { /* exact match */
197*0Sstevel@tonic-gate 			rp->pci_phys_low += assign_p->pci_phys_low;
198*0Sstevel@tonic-gate 			break;
199*0Sstevel@tonic-gate 		}
200*0Sstevel@tonic-gate 		if (space_type == PCI_ADDR_MEM64 &&
201*0Sstevel@tonic-gate 			assign_type == PCI_ADDR_MEM32) {
202*0Sstevel@tonic-gate 			rp->pci_phys_low += assign_p->pci_phys_low;
203*0Sstevel@tonic-gate 			rp->pci_phys_hi ^= PCI_ADDR_MEM64 ^ PCI_ADDR_MEM32;
204*0Sstevel@tonic-gate 			break;
205*0Sstevel@tonic-gate 		}
206*0Sstevel@tonic-gate 	}
207*0Sstevel@tonic-gate 	kmem_free(assign_p - i, assign_len);
208*0Sstevel@tonic-gate 	DBG(DBG_MAP | DBG_CONT, dip, "\tpx_reloc_reg to: %x.%x.%x %x.%x <%d>\n",
209*0Sstevel@tonic-gate 		rp->pci_phys_hi, rp->pci_phys_mid, rp->pci_phys_low,
210*0Sstevel@tonic-gate 		rp->pci_size_hi, rp->pci_size_low, i);
211*0Sstevel@tonic-gate 	return (i < assign_entries ? DDI_SUCCESS : DDI_ME_INVAL);
212*0Sstevel@tonic-gate }
213*0Sstevel@tonic-gate 
214*0Sstevel@tonic-gate /*
215*0Sstevel@tonic-gate  * use "ranges" to translate relocated pci regspec into parent space
216*0Sstevel@tonic-gate  */
217*0Sstevel@tonic-gate int
218*0Sstevel@tonic-gate px_xlate_reg(px_t *px_p, pci_regspec_t *px_rp, struct regspec *new_rp)
219*0Sstevel@tonic-gate {
220*0Sstevel@tonic-gate 	int n;
221*0Sstevel@tonic-gate 	px_ranges_t *rng_p = px_p->px_ranges_p;
222*0Sstevel@tonic-gate 	int rng_n = px_p->px_ranges_length / sizeof (px_ranges_t);
223*0Sstevel@tonic-gate 
224*0Sstevel@tonic-gate 	uint32_t space_type = PCI_REG_ADDR_G(px_rp->pci_phys_hi);
225*0Sstevel@tonic-gate 	uint32_t reg_end, reg_begin = px_rp->pci_phys_low;
226*0Sstevel@tonic-gate 	uint32_t sz = px_rp->pci_size_low;
227*0Sstevel@tonic-gate 
228*0Sstevel@tonic-gate 	uint32_t rng_begin, rng_end;
229*0Sstevel@tonic-gate 
230*0Sstevel@tonic-gate 	if (space_type == PCI_REG_ADDR_G(PCI_ADDR_CONFIG)) {
231*0Sstevel@tonic-gate 		if (reg_begin > PCI_CONF_HDR_SIZE)
232*0Sstevel@tonic-gate 			return (DDI_ME_INVAL);
233*0Sstevel@tonic-gate 		sz = sz ? MIN(sz, PCI_CONF_HDR_SIZE) : PCI_CONF_HDR_SIZE;
234*0Sstevel@tonic-gate 		reg_begin += px_rp->pci_phys_hi << 4;
235*0Sstevel@tonic-gate 	}
236*0Sstevel@tonic-gate 	reg_end = reg_begin + sz - 1;
237*0Sstevel@tonic-gate 
238*0Sstevel@tonic-gate 	for (n = 0; n < rng_n; n++, rng_p++) {
239*0Sstevel@tonic-gate 		if (space_type != PCI_REG_ADDR_G(rng_p->child_high))
240*0Sstevel@tonic-gate 			continue;	/* not the same space type */
241*0Sstevel@tonic-gate 
242*0Sstevel@tonic-gate 		rng_begin = rng_p->child_low;
243*0Sstevel@tonic-gate 		if (space_type == PCI_REG_ADDR_G(PCI_ADDR_CONFIG))
244*0Sstevel@tonic-gate 			rng_begin += rng_p->child_high;
245*0Sstevel@tonic-gate 
246*0Sstevel@tonic-gate 		rng_end = rng_begin + rng_p->size_low - 1;
247*0Sstevel@tonic-gate 		if (reg_begin >= rng_begin && reg_end <= rng_end)
248*0Sstevel@tonic-gate 			break;
249*0Sstevel@tonic-gate 	}
250*0Sstevel@tonic-gate 	if (n >= rng_n)
251*0Sstevel@tonic-gate 		return (DDI_ME_REGSPEC_RANGE);
252*0Sstevel@tonic-gate 
253*0Sstevel@tonic-gate 	new_rp->regspec_addr = reg_begin - rng_begin + rng_p->parent_low;
254*0Sstevel@tonic-gate 	new_rp->regspec_bustype = rng_p->parent_high;
255*0Sstevel@tonic-gate 	new_rp->regspec_size = sz;
256*0Sstevel@tonic-gate 	DBG(DBG_MAP | DBG_CONT, px_p->px_dip,
257*0Sstevel@tonic-gate 		"\tpx_xlate_reg: entry %d new_rp %x.%x %x\n",
258*0Sstevel@tonic-gate 		n, new_rp->regspec_bustype, new_rp->regspec_addr, sz);
259*0Sstevel@tonic-gate 
260*0Sstevel@tonic-gate 	return (DDI_SUCCESS);
261*0Sstevel@tonic-gate }
262*0Sstevel@tonic-gate 
263*0Sstevel@tonic-gate /*
264*0Sstevel@tonic-gate  * px_map_registers
265*0Sstevel@tonic-gate  *
266*0Sstevel@tonic-gate  * This function is called from the attach routine to map the registers
267*0Sstevel@tonic-gate  * accessed by this driver.
268*0Sstevel@tonic-gate  *
269*0Sstevel@tonic-gate  * used by: px_attach()
270*0Sstevel@tonic-gate  *
271*0Sstevel@tonic-gate  * return value: DDI_FAILURE on failure
272*0Sstevel@tonic-gate  *
273*0Sstevel@tonic-gate  * Remove px_map_regs() from here and move them to SUN4U library code,
274*0Sstevel@tonic-gate  * after complete virtualization (after porting MSI and Error handling code).
275*0Sstevel@tonic-gate  */
276*0Sstevel@tonic-gate int
277*0Sstevel@tonic-gate px_map_regs(px_t *px_p, dev_info_t *dip)
278*0Sstevel@tonic-gate {
279*0Sstevel@tonic-gate 	ddi_device_acc_attr_t	attr;
280*0Sstevel@tonic-gate 	px_reg_bank_t		reg_bank = PX_REG_CSR;
281*0Sstevel@tonic-gate 
282*0Sstevel@tonic-gate 	attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
283*0Sstevel@tonic-gate 	attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
284*0Sstevel@tonic-gate 	attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC;
285*0Sstevel@tonic-gate 
286*0Sstevel@tonic-gate 	/*
287*0Sstevel@tonic-gate 	 * PCI CSR Base
288*0Sstevel@tonic-gate 	 */
289*0Sstevel@tonic-gate 	if (ddi_regs_map_setup(dip, reg_bank, &px_p->px_address[reg_bank],
290*0Sstevel@tonic-gate 	    0, 0, &attr, &px_p->px_ac[reg_bank]) != DDI_SUCCESS) {
291*0Sstevel@tonic-gate 		goto fail;
292*0Sstevel@tonic-gate 	}
293*0Sstevel@tonic-gate 
294*0Sstevel@tonic-gate 	reg_bank++;
295*0Sstevel@tonic-gate 
296*0Sstevel@tonic-gate 	/*
297*0Sstevel@tonic-gate 	 * XBUS CSR Base
298*0Sstevel@tonic-gate 	 */
299*0Sstevel@tonic-gate 	if (ddi_regs_map_setup(dip, reg_bank, &px_p->px_address[reg_bank],
300*0Sstevel@tonic-gate 	    0, 0, &attr, &px_p->px_ac[reg_bank]) != DDI_SUCCESS) {
301*0Sstevel@tonic-gate 		goto fail;
302*0Sstevel@tonic-gate 	}
303*0Sstevel@tonic-gate 
304*0Sstevel@tonic-gate 	px_p->px_address[reg_bank] -= FIRE_CONTROL_STATUS;
305*0Sstevel@tonic-gate 
306*0Sstevel@tonic-gate done:
307*0Sstevel@tonic-gate 	for (; reg_bank >= PX_REG_CSR; reg_bank--) {
308*0Sstevel@tonic-gate 		DBG(DBG_ATTACH, dip, "reg_bank 0x%x address 0x%p\n",
309*0Sstevel@tonic-gate 		    reg_bank, px_p->px_address[reg_bank]);
310*0Sstevel@tonic-gate 	}
311*0Sstevel@tonic-gate 
312*0Sstevel@tonic-gate 	return (DDI_SUCCESS);
313*0Sstevel@tonic-gate 
314*0Sstevel@tonic-gate fail:
315*0Sstevel@tonic-gate 	cmn_err(CE_WARN, "%s%d: unable to map reg entry %d\n",
316*0Sstevel@tonic-gate 	    ddi_driver_name(dip), ddi_get_instance(dip), reg_bank);
317*0Sstevel@tonic-gate 
318*0Sstevel@tonic-gate 	for (reg_bank--; reg_bank >= PX_REG_CSR; reg_bank--) {
319*0Sstevel@tonic-gate 		px_p->px_address[reg_bank] = NULL;
320*0Sstevel@tonic-gate 		ddi_regs_map_free(&px_p->px_ac[reg_bank]);
321*0Sstevel@tonic-gate 	}
322*0Sstevel@tonic-gate 
323*0Sstevel@tonic-gate 	return (DDI_FAILURE);
324*0Sstevel@tonic-gate }
325*0Sstevel@tonic-gate 
326*0Sstevel@tonic-gate /*
327*0Sstevel@tonic-gate  * px_unmap_regs:
328*0Sstevel@tonic-gate  *
329*0Sstevel@tonic-gate  * This routine unmap the registers mapped by map_px_registers.
330*0Sstevel@tonic-gate  *
331*0Sstevel@tonic-gate  * used by: px_detach(), and error conditions in px_attach()
332*0Sstevel@tonic-gate  *
333*0Sstevel@tonic-gate  * return value: none
334*0Sstevel@tonic-gate  */
335*0Sstevel@tonic-gate void
336*0Sstevel@tonic-gate px_unmap_regs(px_t *px_p)
337*0Sstevel@tonic-gate {
338*0Sstevel@tonic-gate 	int i;
339*0Sstevel@tonic-gate 
340*0Sstevel@tonic-gate 	for (i = 0; i < 4; i++) {
341*0Sstevel@tonic-gate 		if (px_p->px_ac[i])
342*0Sstevel@tonic-gate 			ddi_regs_map_free(&px_p->px_ac[i]);
343*0Sstevel@tonic-gate 	}
344*0Sstevel@tonic-gate }
345*0Sstevel@tonic-gate 
346*0Sstevel@tonic-gate /*
347*0Sstevel@tonic-gate  * px_report_dev
348*0Sstevel@tonic-gate  *
349*0Sstevel@tonic-gate  * This function is called from our control ops routine on a
350*0Sstevel@tonic-gate  * DDI_CTLOPS_REPORTDEV request.
351*0Sstevel@tonic-gate  *
352*0Sstevel@tonic-gate  * The display format is
353*0Sstevel@tonic-gate  *
354*0Sstevel@tonic-gate  *	<name><inst> at <pname><pinst> device <dev> function <func>
355*0Sstevel@tonic-gate  *
356*0Sstevel@tonic-gate  * where
357*0Sstevel@tonic-gate  *
358*0Sstevel@tonic-gate  *	<name>		this device's name property
359*0Sstevel@tonic-gate  *	<inst>		this device's instance number
360*0Sstevel@tonic-gate  *	<name>		parent device's name property
361*0Sstevel@tonic-gate  *	<inst>		parent device's instance number
362*0Sstevel@tonic-gate  *	<dev>		this device's device number
363*0Sstevel@tonic-gate  *	<func>		this device's function number
364*0Sstevel@tonic-gate  */
365*0Sstevel@tonic-gate int
366*0Sstevel@tonic-gate px_report_dev(dev_info_t *dip)
367*0Sstevel@tonic-gate {
368*0Sstevel@tonic-gate 	if (dip == (dev_info_t *)0)
369*0Sstevel@tonic-gate 		return (DDI_FAILURE);
370*0Sstevel@tonic-gate 	cmn_err(CE_CONT, "?PCI Express-device: %s@%s, %s%d\n",
371*0Sstevel@tonic-gate 	    ddi_node_name(dip), ddi_get_name_addr(dip),
372*0Sstevel@tonic-gate 	    ddi_driver_name(dip),
373*0Sstevel@tonic-gate 	    ddi_get_instance(dip));
374*0Sstevel@tonic-gate 	return (DDI_SUCCESS);
375*0Sstevel@tonic-gate }
376*0Sstevel@tonic-gate 
377*0Sstevel@tonic-gate 
378*0Sstevel@tonic-gate /*
379*0Sstevel@tonic-gate  * reg property for pcimem nodes that covers the entire address
380*0Sstevel@tonic-gate  * space for the node:  config, io, or memory.
381*0Sstevel@tonic-gate  */
382*0Sstevel@tonic-gate pci_regspec_t pci_pcimem_reg[3] =
383*0Sstevel@tonic-gate {
384*0Sstevel@tonic-gate 	{PCI_ADDR_CONFIG,			0, 0, 0, 0x800000	},
385*0Sstevel@tonic-gate 	{(uint_t)(PCI_ADDR_IO|PCI_RELOCAT_B),	0, 0, 0, PX_IO_SIZE	},
386*0Sstevel@tonic-gate 	{(uint_t)(PCI_ADDR_MEM32|PCI_RELOCAT_B), 0, 0, 0, PX_MEM_SIZE	}
387*0Sstevel@tonic-gate };
388*0Sstevel@tonic-gate 
389*0Sstevel@tonic-gate /*
390*0Sstevel@tonic-gate  * px_name_child
391*0Sstevel@tonic-gate  *
392*0Sstevel@tonic-gate  * This function is called from init_child to name a node. It is
393*0Sstevel@tonic-gate  * also passed as a callback for node merging functions.
394*0Sstevel@tonic-gate  *
395*0Sstevel@tonic-gate  * return value: DDI_SUCCESS, DDI_FAILURE
396*0Sstevel@tonic-gate  */
397*0Sstevel@tonic-gate static int
398*0Sstevel@tonic-gate px_name_child(dev_info_t *child, char *name, int namelen)
399*0Sstevel@tonic-gate {
400*0Sstevel@tonic-gate 	pci_regspec_t *pci_rp;
401*0Sstevel@tonic-gate 	int reglen;
402*0Sstevel@tonic-gate 	uint_t func;
403*0Sstevel@tonic-gate 	char **unit_addr;
404*0Sstevel@tonic-gate 	uint_t n;
405*0Sstevel@tonic-gate 
406*0Sstevel@tonic-gate 	/*
407*0Sstevel@tonic-gate 	 * Set the address portion of the node name based on
408*0Sstevel@tonic-gate 	 * unit-address property, if it exists.
409*0Sstevel@tonic-gate 	 * The interpretation of the unit-address is DD[,F]
410*0Sstevel@tonic-gate 	 * where DD is the device id and F is the function.
411*0Sstevel@tonic-gate 	 */
412*0Sstevel@tonic-gate 	if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, child,
413*0Sstevel@tonic-gate 	    DDI_PROP_DONTPASS, "unit-address", &unit_addr, &n) ==
414*0Sstevel@tonic-gate 	    DDI_PROP_SUCCESS) {
415*0Sstevel@tonic-gate 		if (n != 1 || *unit_addr == NULL || **unit_addr == 0) {
416*0Sstevel@tonic-gate 			cmn_err(CE_WARN, "unit-address property in %s.conf"
417*0Sstevel@tonic-gate 			    " not well-formed", ddi_driver_name(child));
418*0Sstevel@tonic-gate 			ddi_prop_free(unit_addr);
419*0Sstevel@tonic-gate 			return (DDI_FAILURE);
420*0Sstevel@tonic-gate 		}
421*0Sstevel@tonic-gate 		(void) snprintf(name, namelen, "%s", *unit_addr);
422*0Sstevel@tonic-gate 		ddi_prop_free(unit_addr);
423*0Sstevel@tonic-gate 		return (DDI_SUCCESS);
424*0Sstevel@tonic-gate 	}
425*0Sstevel@tonic-gate 
426*0Sstevel@tonic-gate 	/*
427*0Sstevel@tonic-gate 	 * The unit-address property is does not exist. Set the address
428*0Sstevel@tonic-gate 	 * portion of the node name based on the function and device number.
429*0Sstevel@tonic-gate 	 */
430*0Sstevel@tonic-gate 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
431*0Sstevel@tonic-gate 	    "reg", (int **)&pci_rp, (uint_t *)&reglen) == DDI_SUCCESS) {
432*0Sstevel@tonic-gate 		if (((reglen * sizeof (int)) % sizeof (pci_regspec_t)) != 0) {
433*0Sstevel@tonic-gate 			cmn_err(CE_WARN, "reg property not well-formed");
434*0Sstevel@tonic-gate 			return (DDI_FAILURE);
435*0Sstevel@tonic-gate 		}
436*0Sstevel@tonic-gate 
437*0Sstevel@tonic-gate 		func = PCI_REG_FUNC_G(pci_rp[0].pci_phys_hi);
438*0Sstevel@tonic-gate 		if (func != 0)
439*0Sstevel@tonic-gate 			(void) snprintf(name, namelen, "%x,%x",
440*0Sstevel@tonic-gate 				PCI_REG_DEV_G(pci_rp[0].pci_phys_hi), func);
441*0Sstevel@tonic-gate 		else
442*0Sstevel@tonic-gate 			(void) snprintf(name, namelen, "%x",
443*0Sstevel@tonic-gate 				PCI_REG_DEV_G(pci_rp[0].pci_phys_hi));
444*0Sstevel@tonic-gate 		ddi_prop_free(pci_rp);
445*0Sstevel@tonic-gate 		return (DDI_SUCCESS);
446*0Sstevel@tonic-gate 	}
447*0Sstevel@tonic-gate 
448*0Sstevel@tonic-gate 	cmn_err(CE_WARN, "cannot name pci child '%s'", ddi_node_name(child));
449*0Sstevel@tonic-gate 	return (DDI_FAILURE);
450*0Sstevel@tonic-gate }
451*0Sstevel@tonic-gate 
452*0Sstevel@tonic-gate int
453*0Sstevel@tonic-gate px_uninit_child(px_t *px_p, dev_info_t *child)
454*0Sstevel@tonic-gate {
455*0Sstevel@tonic-gate 	DBG(DBG_INIT_CLD, px_p->px_dip,
456*0Sstevel@tonic-gate 	    "DDI_CTLOPS_UNINITCHILD: arg=%s%d\n",
457*0Sstevel@tonic-gate 	    ddi_driver_name(child), ddi_get_instance(child));
458*0Sstevel@tonic-gate 
459*0Sstevel@tonic-gate 	ddi_set_name_addr(child, NULL);
460*0Sstevel@tonic-gate 	ddi_remove_minor_node(child, NULL);
461*0Sstevel@tonic-gate 	impl_rem_dev_props(child);
462*0Sstevel@tonic-gate 	return (DDI_SUCCESS);
463*0Sstevel@tonic-gate }
464*0Sstevel@tonic-gate 
465*0Sstevel@tonic-gate /*ARGSUSED*/
466*0Sstevel@tonic-gate void
467*0Sstevel@tonic-gate px_post_init_child(px_t *px_p, dev_info_t *child)
468*0Sstevel@tonic-gate {
469*0Sstevel@tonic-gate 	/* Add px specific PEC code */
470*0Sstevel@tonic-gate }
471*0Sstevel@tonic-gate 
472*0Sstevel@tonic-gate /*
473*0Sstevel@tonic-gate  * px_init_child
474*0Sstevel@tonic-gate  *
475*0Sstevel@tonic-gate  * This function is called from our control ops routine on a
476*0Sstevel@tonic-gate  * DDI_CTLOPS_INITCHILD request.  It builds and sets the device's
477*0Sstevel@tonic-gate  * parent private data area.
478*0Sstevel@tonic-gate  *
479*0Sstevel@tonic-gate  * used by: pci_ctlops()
480*0Sstevel@tonic-gate  *
481*0Sstevel@tonic-gate  * return value: none
482*0Sstevel@tonic-gate  */
483*0Sstevel@tonic-gate int
484*0Sstevel@tonic-gate px_init_child(px_t *px_p, dev_info_t *child)
485*0Sstevel@tonic-gate {
486*0Sstevel@tonic-gate 	pci_regspec_t *pci_rp;
487*0Sstevel@tonic-gate 	char name[10];
488*0Sstevel@tonic-gate 	ddi_acc_handle_t config_handle;
489*0Sstevel@tonic-gate 	uint16_t command_preserve, command;
490*0Sstevel@tonic-gate 	uint8_t bcr;
491*0Sstevel@tonic-gate 	uint8_t header_type, min_gnt;
492*0Sstevel@tonic-gate 	uint16_t latency_timer;
493*0Sstevel@tonic-gate 	uint_t n;
494*0Sstevel@tonic-gate 	int i, no_config;
495*0Sstevel@tonic-gate 
496*0Sstevel@tonic-gate 	/*
497*0Sstevel@tonic-gate 	 * The following is a special case for pcimem nodes.
498*0Sstevel@tonic-gate 	 * For these nodes we create a reg property with a
499*0Sstevel@tonic-gate 	 * single entry that covers the entire address space
500*0Sstevel@tonic-gate 	 * for the node (config, io or memory).
501*0Sstevel@tonic-gate 	 */
502*0Sstevel@tonic-gate 	if (strcmp(ddi_driver_name(child), "pcimem") == 0) {
503*0Sstevel@tonic-gate 		(void) ddi_prop_create(DDI_DEV_T_NONE, child,
504*0Sstevel@tonic-gate 		    DDI_PROP_CANSLEEP, "reg", (caddr_t)pci_pcimem_reg,
505*0Sstevel@tonic-gate 		    sizeof (pci_pcimem_reg));
506*0Sstevel@tonic-gate 		ddi_set_name_addr(child, "0");
507*0Sstevel@tonic-gate 		ddi_set_parent_data(child, NULL);
508*0Sstevel@tonic-gate 		return (DDI_SUCCESS);
509*0Sstevel@tonic-gate 	}
510*0Sstevel@tonic-gate 
511*0Sstevel@tonic-gate 	/*
512*0Sstevel@tonic-gate 	 * Check whether the node has config space or is a hard decode
513*0Sstevel@tonic-gate 	 * node (possibly created by a driver.conf file).
514*0Sstevel@tonic-gate 	 */
515*0Sstevel@tonic-gate 	no_config = ddi_prop_get_int(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
516*0Sstevel@tonic-gate 	    "no-config", 0);
517*0Sstevel@tonic-gate 
518*0Sstevel@tonic-gate 	/*
519*0Sstevel@tonic-gate 	 * Pseudo nodes indicate a prototype node with per-instance
520*0Sstevel@tonic-gate 	 * properties to be merged into the real h/w device node.
521*0Sstevel@tonic-gate 	 * However, do not merge if the no-config property is set
522*0Sstevel@tonic-gate 	 * (see PSARC 2000/088).
523*0Sstevel@tonic-gate 	 */
524*0Sstevel@tonic-gate 	if ((ndi_dev_is_persistent_node(child) == 0) && (no_config == 0)) {
525*0Sstevel@tonic-gate 		extern int pci_allow_pseudo_children;
526*0Sstevel@tonic-gate 
527*0Sstevel@tonic-gate 		if (ddi_getlongprop(DDI_DEV_T_ANY, child,
528*0Sstevel@tonic-gate 		    DDI_PROP_DONTPASS, "reg", (caddr_t)&pci_rp, &i) ==
529*0Sstevel@tonic-gate 		    DDI_SUCCESS) {
530*0Sstevel@tonic-gate 			cmn_err(CE_WARN, "cannot merge prototype from %s.conf",
531*0Sstevel@tonic-gate 			    ddi_driver_name(child));
532*0Sstevel@tonic-gate 			kmem_free(pci_rp, i);
533*0Sstevel@tonic-gate 			return (DDI_NOT_WELL_FORMED);
534*0Sstevel@tonic-gate 		}
535*0Sstevel@tonic-gate 		/*
536*0Sstevel@tonic-gate 		 * Name the child
537*0Sstevel@tonic-gate 		 */
538*0Sstevel@tonic-gate 		if (px_name_child(child, name, 10) != DDI_SUCCESS)
539*0Sstevel@tonic-gate 			return (DDI_FAILURE);
540*0Sstevel@tonic-gate 
541*0Sstevel@tonic-gate 		ddi_set_name_addr(child, name);
542*0Sstevel@tonic-gate 		ddi_set_parent_data(child, NULL);
543*0Sstevel@tonic-gate 
544*0Sstevel@tonic-gate 		/*
545*0Sstevel@tonic-gate 		 * Try to merge the properties from this prototype
546*0Sstevel@tonic-gate 		 * node into real h/w nodes.
547*0Sstevel@tonic-gate 		 */
548*0Sstevel@tonic-gate 		if (ndi_merge_node(child, px_name_child) == DDI_SUCCESS) {
549*0Sstevel@tonic-gate 			/*
550*0Sstevel@tonic-gate 			 * Merged ok - return failure to remove the node.
551*0Sstevel@tonic-gate 			 */
552*0Sstevel@tonic-gate 			ddi_set_name_addr(child, NULL);
553*0Sstevel@tonic-gate 			return (DDI_FAILURE);
554*0Sstevel@tonic-gate 		}
555*0Sstevel@tonic-gate 
556*0Sstevel@tonic-gate 		/* workaround for ddivs to run under PCI */
557*0Sstevel@tonic-gate 		if (pci_allow_pseudo_children)
558*0Sstevel@tonic-gate 			return (DDI_SUCCESS);
559*0Sstevel@tonic-gate 
560*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "!%s@%s: %s.conf properties not merged",
561*0Sstevel@tonic-gate 		    ddi_driver_name(child), ddi_get_name_addr(child),
562*0Sstevel@tonic-gate 		    ddi_driver_name(child));
563*0Sstevel@tonic-gate 		ddi_set_name_addr(child, NULL);
564*0Sstevel@tonic-gate 		return (DDI_NOT_WELL_FORMED);
565*0Sstevel@tonic-gate 	}
566*0Sstevel@tonic-gate 
567*0Sstevel@tonic-gate 	if (px_name_child(child, name, 10) != DDI_SUCCESS)
568*0Sstevel@tonic-gate 		return (DDI_FAILURE);
569*0Sstevel@tonic-gate 	ddi_set_name_addr(child, name);
570*0Sstevel@tonic-gate 
571*0Sstevel@tonic-gate 	if (no_config != 0) {
572*0Sstevel@tonic-gate 		/*
573*0Sstevel@tonic-gate 		 * There is no config space so there's nothing more to do.
574*0Sstevel@tonic-gate 		 */
575*0Sstevel@tonic-gate 		return (DDI_SUCCESS);
576*0Sstevel@tonic-gate 	}
577*0Sstevel@tonic-gate 
578*0Sstevel@tonic-gate 	if (pcie_pm_hold(px_p->px_dip) != DDI_SUCCESS) {
579*0Sstevel@tonic-gate 		DBG(DBG_PWR, px_p->px_dip,
580*0Sstevel@tonic-gate 		    "INITCHILD: px_pm_hold failed\n");
581*0Sstevel@tonic-gate 		return (DDI_FAILURE);
582*0Sstevel@tonic-gate 	}
583*0Sstevel@tonic-gate 	/* Any return of DDI_FAILURE after this must call px_pm_release */
584*0Sstevel@tonic-gate 
585*0Sstevel@tonic-gate 	/*
586*0Sstevel@tonic-gate 	 * If configuration registers were previously saved by
587*0Sstevel@tonic-gate 	 * child (before it went to D3), then let the child do the
588*0Sstevel@tonic-gate 	 * restore to set up the config regs as it'll first need to
589*0Sstevel@tonic-gate 	 * power the device out of D3.
590*0Sstevel@tonic-gate 	 */
591*0Sstevel@tonic-gate 	if (ddi_prop_exists(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
592*0Sstevel@tonic-gate 	    "config-regs-saved-by-child") == 1) {
593*0Sstevel@tonic-gate 		DBG(DBG_PWR, child,
594*0Sstevel@tonic-gate 		    "INITCHILD: config regs to be restored by child\n");
595*0Sstevel@tonic-gate 
596*0Sstevel@tonic-gate 		return (DDI_SUCCESS);
597*0Sstevel@tonic-gate 	}
598*0Sstevel@tonic-gate 
599*0Sstevel@tonic-gate 	DBG(DBG_PWR, ddi_get_parent(child),
600*0Sstevel@tonic-gate 	    "INITCHILD: config regs setup for %s@%s\n",
601*0Sstevel@tonic-gate 	    ddi_node_name(child), ddi_get_name_addr(child));
602*0Sstevel@tonic-gate 
603*0Sstevel@tonic-gate 	/*
604*0Sstevel@tonic-gate 	 * Map the child configuration space to for initialization.
605*0Sstevel@tonic-gate 	 * We assume the obp will do the following in the devices
606*0Sstevel@tonic-gate 	 * config space:
607*0Sstevel@tonic-gate 	 *
608*0Sstevel@tonic-gate 	 *	Set the latency-timer register to values appropriate
609*0Sstevel@tonic-gate 	 *	for the devices on the bus (based on other devices
610*0Sstevel@tonic-gate 	 *	MIN_GNT and MAX_LAT registers.
611*0Sstevel@tonic-gate 	 *
612*0Sstevel@tonic-gate 	 *	Set the fast back-to-back enable bit in the command
613*0Sstevel@tonic-gate 	 *	register if it's supported and all devices on the bus
614*0Sstevel@tonic-gate 	 *	have the capability.
615*0Sstevel@tonic-gate 	 *
616*0Sstevel@tonic-gate 	 */
617*0Sstevel@tonic-gate 	if (pci_config_setup(child, &config_handle) != DDI_SUCCESS) {
618*0Sstevel@tonic-gate 		ddi_set_name_addr(child, NULL);
619*0Sstevel@tonic-gate 		pcie_pm_release(px_p->px_dip);
620*0Sstevel@tonic-gate 		return (DDI_FAILURE);
621*0Sstevel@tonic-gate 	}
622*0Sstevel@tonic-gate 
623*0Sstevel@tonic-gate 	/*
624*0Sstevel@tonic-gate 	 * Determine the configuration header type.
625*0Sstevel@tonic-gate 	 */
626*0Sstevel@tonic-gate 	header_type = pci_config_get8(config_handle, PCI_CONF_HEADER);
627*0Sstevel@tonic-gate 	DBG(DBG_INIT_CLD, px_p->px_dip, "%s: header_type=%x\n",
628*0Sstevel@tonic-gate 	    ddi_driver_name(child), header_type);
629*0Sstevel@tonic-gate 
630*0Sstevel@tonic-gate 	/*
631*0Sstevel@tonic-gate 	 * Support for "command-preserve" property.  Note that we
632*0Sstevel@tonic-gate 	 * add PCI_COMM_BACK2BACK_ENAB to the bits to be preserved
633*0Sstevel@tonic-gate 	 * since the obp will set this if the device supports and
634*0Sstevel@tonic-gate 	 * all targets on the same bus support it.  Since psycho
635*0Sstevel@tonic-gate 	 * doesn't support PCI_COMM_BACK2BACK_ENAB, it will never
636*0Sstevel@tonic-gate 	 * be set.  This is just here in case future revs do support
637*0Sstevel@tonic-gate 	 * PCI_COMM_BACK2BACK_ENAB.
638*0Sstevel@tonic-gate 	 */
639*0Sstevel@tonic-gate 	command_preserve =
640*0Sstevel@tonic-gate 	    ddi_prop_get_int(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
641*0Sstevel@tonic-gate 		"command-preserve", 0);
642*0Sstevel@tonic-gate 	DBG(DBG_INIT_CLD, px_p->px_dip, "%s: command-preserve=%x\n",
643*0Sstevel@tonic-gate 	    ddi_driver_name(child), command_preserve);
644*0Sstevel@tonic-gate 	command = pci_config_get16(config_handle, PCI_CONF_COMM);
645*0Sstevel@tonic-gate 	command &= (command_preserve | PCI_COMM_BACK2BACK_ENAB);
646*0Sstevel@tonic-gate 	command |= (px_command_default & ~command_preserve);
647*0Sstevel@tonic-gate 	pci_config_put16(config_handle, PCI_CONF_COMM, command);
648*0Sstevel@tonic-gate 	command = pci_config_get16(config_handle, PCI_CONF_COMM);
649*0Sstevel@tonic-gate 	DBG(DBG_INIT_CLD, px_p->px_dip, "%s: command=%x\n",
650*0Sstevel@tonic-gate 	    ddi_driver_name(child),
651*0Sstevel@tonic-gate 	    pci_config_get16(config_handle, PCI_CONF_COMM));
652*0Sstevel@tonic-gate 
653*0Sstevel@tonic-gate 	/*
654*0Sstevel@tonic-gate 	 * If the device has a bus control register then program it
655*0Sstevel@tonic-gate 	 * based on the settings in the command register.
656*0Sstevel@tonic-gate 	 */
657*0Sstevel@tonic-gate 	if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_ONE) {
658*0Sstevel@tonic-gate 		bcr = pci_config_get8(config_handle, PCI_BCNF_BCNTRL);
659*0Sstevel@tonic-gate 		if (px_command_default & PCI_COMM_PARITY_DETECT)
660*0Sstevel@tonic-gate 			bcr |= PCI_BCNF_BCNTRL_PARITY_ENABLE;
661*0Sstevel@tonic-gate 		if (px_command_default & PCI_COMM_SERR_ENABLE)
662*0Sstevel@tonic-gate 			bcr |= PCI_BCNF_BCNTRL_SERR_ENABLE;
663*0Sstevel@tonic-gate 		bcr |= PCI_BCNF_BCNTRL_MAST_AB_MODE;
664*0Sstevel@tonic-gate 		pci_config_put8(config_handle, PCI_BCNF_BCNTRL, bcr);
665*0Sstevel@tonic-gate 	}
666*0Sstevel@tonic-gate 
667*0Sstevel@tonic-gate 	/*
668*0Sstevel@tonic-gate 	 * Initialize latency timer registers if needed.
669*0Sstevel@tonic-gate 	 */
670*0Sstevel@tonic-gate 	if (px_set_latency_timer_register &&
671*0Sstevel@tonic-gate 	    ddi_getprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
672*0Sstevel@tonic-gate 		"latency-timer", 0) == 0) {
673*0Sstevel@tonic-gate 
674*0Sstevel@tonic-gate 		latency_timer = px_latency_timer;
675*0Sstevel@tonic-gate 		if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_ONE) {
676*0Sstevel@tonic-gate 			pci_config_put8(config_handle, PCI_BCNF_LATENCY_TIMER,
677*0Sstevel@tonic-gate 			    latency_timer);
678*0Sstevel@tonic-gate 		} else {
679*0Sstevel@tonic-gate 			min_gnt = pci_config_get8(config_handle,
680*0Sstevel@tonic-gate 			    PCI_CONF_MIN_G);
681*0Sstevel@tonic-gate 			DBG(DBG_INIT_CLD, px_p->px_dip, "%s: min_gnt=%x\n",
682*0Sstevel@tonic-gate 			    ddi_driver_name(child), min_gnt);
683*0Sstevel@tonic-gate 		}
684*0Sstevel@tonic-gate 		latency_timer = MIN(latency_timer, 0xff);
685*0Sstevel@tonic-gate 		pci_config_put8(config_handle, PCI_CONF_LATENCY_TIMER,
686*0Sstevel@tonic-gate 		    latency_timer);
687*0Sstevel@tonic-gate 		n = pci_config_get8(config_handle, PCI_CONF_LATENCY_TIMER);
688*0Sstevel@tonic-gate 		if (n != 0)
689*0Sstevel@tonic-gate 			(void) ndi_prop_update_int(DDI_DEV_T_NONE, child,
690*0Sstevel@tonic-gate 			    "latency-timer", n);
691*0Sstevel@tonic-gate 	}
692*0Sstevel@tonic-gate 
693*0Sstevel@tonic-gate 	pci_config_teardown(&config_handle);
694*0Sstevel@tonic-gate 
695*0Sstevel@tonic-gate 	/*
696*0Sstevel@tonic-gate 	 * Handle chip specific init-child tasks.
697*0Sstevel@tonic-gate 	 */
698*0Sstevel@tonic-gate 	px_post_init_child(px_p, child);
699*0Sstevel@tonic-gate 	pcie_pm_release(px_p->px_dip);
700*0Sstevel@tonic-gate 
701*0Sstevel@tonic-gate 	return (DDI_SUCCESS);
702*0Sstevel@tonic-gate }
703*0Sstevel@tonic-gate 
704*0Sstevel@tonic-gate /*
705*0Sstevel@tonic-gate  * px_get_reg_set_size
706*0Sstevel@tonic-gate  *
707*0Sstevel@tonic-gate  * Given a dev info pointer to a pci child and a register number, this
708*0Sstevel@tonic-gate  * routine returns the size element of that reg set property.
709*0Sstevel@tonic-gate  *
710*0Sstevel@tonic-gate  * used by: pci_ctlops() - DDI_CTLOPS_REGSIZE
711*0Sstevel@tonic-gate  *
712*0Sstevel@tonic-gate  * return value: size of reg set on success, -1 on error
713*0Sstevel@tonic-gate  */
714*0Sstevel@tonic-gate off_t
715*0Sstevel@tonic-gate px_get_reg_set_size(dev_info_t *child, int rnumber)
716*0Sstevel@tonic-gate {
717*0Sstevel@tonic-gate 	pci_regspec_t *pci_rp;
718*0Sstevel@tonic-gate 	off_t size = -1;
719*0Sstevel@tonic-gate 	int i;
720*0Sstevel@tonic-gate 
721*0Sstevel@tonic-gate 	if (rnumber < 0)
722*0Sstevel@tonic-gate 		return (-1);
723*0Sstevel@tonic-gate 
724*0Sstevel@tonic-gate 	/*
725*0Sstevel@tonic-gate 	 * Get the reg property for the device.
726*0Sstevel@tonic-gate 	 */
727*0Sstevel@tonic-gate 	if (ddi_getlongprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, "reg",
728*0Sstevel@tonic-gate 	    (caddr_t)&pci_rp, &i) != DDI_SUCCESS)
729*0Sstevel@tonic-gate 		return (-1);
730*0Sstevel@tonic-gate 
731*0Sstevel@tonic-gate 	if (rnumber >= (i / (int)sizeof (pci_regspec_t)))
732*0Sstevel@tonic-gate 		goto done;
733*0Sstevel@tonic-gate 
734*0Sstevel@tonic-gate 	size = pci_rp[rnumber].pci_size_low |
735*0Sstevel@tonic-gate 		((uint64_t)pci_rp[rnumber].pci_size_hi << 32);
736*0Sstevel@tonic-gate done:
737*0Sstevel@tonic-gate 	kmem_free(pci_rp, i);
738*0Sstevel@tonic-gate 	return (size);
739*0Sstevel@tonic-gate }
740*0Sstevel@tonic-gate 
741*0Sstevel@tonic-gate 
742*0Sstevel@tonic-gate /*
743*0Sstevel@tonic-gate  * px_get_nreg_set
744*0Sstevel@tonic-gate  *
745*0Sstevel@tonic-gate  * Given a dev info pointer to a pci child, this routine returns the
746*0Sstevel@tonic-gate  * number of sets in its "reg" property.
747*0Sstevel@tonic-gate  *
748*0Sstevel@tonic-gate  * used by: pci_ctlops() - DDI_CTLOPS_NREGS
749*0Sstevel@tonic-gate  *
750*0Sstevel@tonic-gate  * return value: # of reg sets on success, zero on error
751*0Sstevel@tonic-gate  */
752*0Sstevel@tonic-gate uint_t
753*0Sstevel@tonic-gate px_get_nreg_set(dev_info_t *child)
754*0Sstevel@tonic-gate {
755*0Sstevel@tonic-gate 	pci_regspec_t *pci_rp;
756*0Sstevel@tonic-gate 	int i, n;
757*0Sstevel@tonic-gate 
758*0Sstevel@tonic-gate 	/*
759*0Sstevel@tonic-gate 	 * Get the reg property for the device.
760*0Sstevel@tonic-gate 	 */
761*0Sstevel@tonic-gate 	if (ddi_getlongprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, "reg",
762*0Sstevel@tonic-gate 	    (caddr_t)&pci_rp, &i) != DDI_SUCCESS)
763*0Sstevel@tonic-gate 		return (0);
764*0Sstevel@tonic-gate 
765*0Sstevel@tonic-gate 	n = i / (int)sizeof (pci_regspec_t);
766*0Sstevel@tonic-gate 	kmem_free(pci_rp, i);
767*0Sstevel@tonic-gate 	return (n);
768*0Sstevel@tonic-gate }
769*0Sstevel@tonic-gate 
770*0Sstevel@tonic-gate 
771*0Sstevel@tonic-gate /*
772*0Sstevel@tonic-gate  * px_get_nintr
773*0Sstevel@tonic-gate  *
774*0Sstevel@tonic-gate  * Given a dev info pointer to a pci child, this routine returns the
775*0Sstevel@tonic-gate  * number of items in its "interrupts" property.
776*0Sstevel@tonic-gate  *
777*0Sstevel@tonic-gate  * used by: pci_ctlops() - DDI_CTLOPS_NREGS
778*0Sstevel@tonic-gate  *
779*0Sstevel@tonic-gate  * return value: # of interrupts on success, zero on error
780*0Sstevel@tonic-gate  */
781*0Sstevel@tonic-gate uint_t
782*0Sstevel@tonic-gate px_get_nintr(dev_info_t *child)
783*0Sstevel@tonic-gate {
784*0Sstevel@tonic-gate 	int *pci_ip;
785*0Sstevel@tonic-gate 	int i, n;
786*0Sstevel@tonic-gate 
787*0Sstevel@tonic-gate 	if (ddi_getlongprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
788*0Sstevel@tonic-gate 	    "interrupts", (caddr_t)&pci_ip, &i) != DDI_SUCCESS)
789*0Sstevel@tonic-gate 		return (0);
790*0Sstevel@tonic-gate 
791*0Sstevel@tonic-gate 	n = i / (int)sizeof (uint_t);
792*0Sstevel@tonic-gate 	kmem_free(pci_ip, i);
793*0Sstevel@tonic-gate 	return (n);
794*0Sstevel@tonic-gate }
795*0Sstevel@tonic-gate 
796*0Sstevel@tonic-gate uint64_t
797*0Sstevel@tonic-gate px_get_cfg_pabase(px_t *px_p)
798*0Sstevel@tonic-gate {
799*0Sstevel@tonic-gate 	int i;
800*0Sstevel@tonic-gate 	px_ranges_t *rangep = px_p->px_ranges_p;
801*0Sstevel@tonic-gate 	int nrange = px_p->px_ranges_length / sizeof (px_ranges_t);
802*0Sstevel@tonic-gate 	uint32_t cfg_space_type = PCI_REG_ADDR_G(PCI_ADDR_CONFIG);
803*0Sstevel@tonic-gate 
804*0Sstevel@tonic-gate 	ASSERT(cfg_space_type == 0);
805*0Sstevel@tonic-gate 
806*0Sstevel@tonic-gate 	for (i = 0; i < nrange; i++, rangep++) {
807*0Sstevel@tonic-gate 		if (PCI_REG_ADDR_G(rangep->child_high) == cfg_space_type)
808*0Sstevel@tonic-gate 			break;
809*0Sstevel@tonic-gate 	}
810*0Sstevel@tonic-gate 
811*0Sstevel@tonic-gate 	if (i >= nrange)
812*0Sstevel@tonic-gate 		cmn_err(CE_PANIC, "no cfg space in px(%x) ranges prop.\n",
813*0Sstevel@tonic-gate 			(void *)px_p);
814*0Sstevel@tonic-gate 
815*0Sstevel@tonic-gate 	return (((uint64_t)rangep->parent_high << 32) | rangep->parent_low);
816*0Sstevel@tonic-gate }
817*0Sstevel@tonic-gate 
818*0Sstevel@tonic-gate /*
819*0Sstevel@tonic-gate  * decodes standard PCI config space 16bit error status reg
820*0Sstevel@tonic-gate  */
821*0Sstevel@tonic-gate int
822*0Sstevel@tonic-gate px_log_cfg_err(dev_info_t *dip, ushort_t status_reg, char *err_msg)
823*0Sstevel@tonic-gate {
824*0Sstevel@tonic-gate 	int nerr = ddi_get_instance(dip); /* temp for instance */
825*0Sstevel@tonic-gate 	uint64_t perr_fatal = px_perr_fatal & (1 << nerr);
826*0Sstevel@tonic-gate 	uint64_t serr_fatal = px_serr_fatal & (1 << nerr);
827*0Sstevel@tonic-gate 	nerr = 0;
828*0Sstevel@tonic-gate 
829*0Sstevel@tonic-gate 	if ((status_reg & PCI_STAT_PERROR) && perr_fatal)
830*0Sstevel@tonic-gate 		nerr++;
831*0Sstevel@tonic-gate 	if ((status_reg & PCI_STAT_S_SYSERR) && serr_fatal)
832*0Sstevel@tonic-gate 		nerr++;
833*0Sstevel@tonic-gate 	if (status_reg & PCI_STAT_R_MAST_AB)
834*0Sstevel@tonic-gate 		nerr++;
835*0Sstevel@tonic-gate 	if ((status_reg & PCI_STAT_S_PERROR) && perr_fatal)
836*0Sstevel@tonic-gate 		nerr++;
837*0Sstevel@tonic-gate 
838*0Sstevel@tonic-gate 	cmn_err(CE_WARN, "%s%d: %sPCI Express config space CSR=0x%b",
839*0Sstevel@tonic-gate 	    ddi_driver_name(dip), ddi_get_instance(dip), err_msg,
840*0Sstevel@tonic-gate 	    (uint32_t)status_reg, PX_STATUS_BITS);
841*0Sstevel@tonic-gate 
842*0Sstevel@tonic-gate 	return (nerr);
843*0Sstevel@tonic-gate }
844*0Sstevel@tonic-gate 
845*0Sstevel@tonic-gate /*
846*0Sstevel@tonic-gate  * remove the following functions once we port error handling and other
847*0Sstevel@tonic-gate  * misc functionalities based on new VPCI interfaces.
848*0Sstevel@tonic-gate  */
849*0Sstevel@tonic-gate uint64_t
850*0Sstevel@tonic-gate px_get_err_reg(caddr_t csr, uint32_t off)
851*0Sstevel@tonic-gate {
852*0Sstevel@tonic-gate 	return (CSR_XR(csr, off));
853*0Sstevel@tonic-gate }
854*0Sstevel@tonic-gate 
855*0Sstevel@tonic-gate void
856*0Sstevel@tonic-gate px_set_err_reg(caddr_t csr, uint32_t off, uint64_t val)
857*0Sstevel@tonic-gate {
858*0Sstevel@tonic-gate 	CSR_XS(csr, off, val);
859*0Sstevel@tonic-gate }
860